diff --git a/.devcontainer/wasi/devcontainer.json b/.devcontainer/wasi/devcontainer.json new file mode 100644 index 00000000000..4266144ce47 --- /dev/null +++ b/.devcontainer/wasi/devcontainer.json @@ -0,0 +1,73 @@ +{ + "image": "ghcr.io/python/wasicontainer:latest", + "onCreateCommand": [ + // Install common tooling. + "dnf", + "install", + "-y", + // For umask fix below. + "/usr/bin/setfacl" + ], + "updateContentCommand": { + // Using the shell for `nproc` usage. + "python": "python3 Tools/wasm/wasi build --quiet -- --with-pydebug -C" + }, + "postCreateCommand": { + // https://github.com/orgs/community/discussions/26026 + "umask fix: workspace": ["sudo", "setfacl", "-bnR", "."], + "umask fix: /tmp": ["sudo", "setfacl", "-bnR", "/tmp"] + }, + "customizations": { + "vscode": { + "extensions": [ + // Highlighting for Parser/Python.asdl. + "brettcannon.zephyr-asdl", + // Highlighting for configure.ac. + "maelvalais.autoconf", + // C auto-complete. + "ms-vscode.cpptools", + // Python auto-complete. + "ms-python.python" + ], + "settings": { + "C_Cpp.default.compilerPath": "/usr/bin/clang", + "C_Cpp.default.cStandard": "c11", + "C_Cpp.default.defines": [ + "CONFIG_64", + "Py_BUILD_CORE" + ], + "C_Cpp.default.includePath": [ + "${workspaceFolder}/*", + "${workspaceFolder}/Include/**" + ], + // https://github.com/microsoft/vscode-cpptools/issues/10732 + "C_Cpp.errorSquiggles": "disabled", + "editor.insertSpaces": true, + "editor.rulers": [ + 80 + ], + "editor.tabSize": 4, + "editor.trimAutoWhitespace": true, + "files.associations": { + "*.h": "c" + }, + "files.encoding": "utf8", + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "python.analysis.diagnosticSeverityOverrides": { + // Complains about shadowing the stdlib w/ the stdlib. + "reportShadowedImports": "none", + // Doesn't like _frozen_importlib. + "reportMissingImports": "none" + }, + "python.analysis.extraPaths": [ + "Lib" + ], + "[restructuredtext]": { + "editor.tabSize": 3 + } + } + } + } +} diff --git a/.gitattributes b/.gitattributes index 5682b9150a3..767ec620fba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -68,6 +68,7 @@ PCbuild/readme.txt dos **/clinic/*.cpp.h generated **/clinic/*.h.h generated *_db.h generated +Doc/_static/tachyon-example-*.html generated Doc/c-api/lifecycle.dot.svg generated Doc/data/stable_abi.dat generated Doc/library/token-list.inc generated @@ -83,10 +84,12 @@ Include/opcode_ids.h generated Include/token.h generated Lib/_opcode_metadata.py generated Lib/keyword.py generated +Lib/idlelib/help.html generated Lib/test/certdata/*.pem generated Lib/test/certdata/*.0 generated Lib/test/levenshtein_examples.json generated Lib/test/test_stable_abi_ctypes.py generated +Lib/test/test_zoneinfo/data/*.json generated Lib/token.py generated Misc/sbom.spdx.json generated Objects/typeslots.inc generated @@ -103,3 +106,4 @@ Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated aclocal.m4 generated configure generated +*.min.js generated diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7d26f8b526c..4789cd2c59e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -80,11 +80,16 @@ Tools/patchcheck/ @AA-Turner # ---------------------------------------------------------------------------- # Autotools -configure* @erlend-aasland @corona10 @AA-Turner -Makefile.pre.in @erlend-aasland @AA-Turner -Modules/Setup* @erlend-aasland @AA-Turner +configure* @erlend-aasland @corona10 @AA-Turner @emmatyping +Makefile.pre.in @erlend-aasland @AA-Turner @emmatyping +Modules/makesetup @erlend-aasland @AA-Turner @emmatyping +Modules/Setup* @erlend-aasland @AA-Turner @emmatyping Tools/build/regen-configure.sh @AA-Turner +# generate-build-details +Tools/build/generate-build-details.py @FFY00 +Lib/test/test_build_details.py @FFY00 + # ---------------------------------------------------------------------------- # Documentation @@ -121,6 +126,9 @@ Doc/howto/clinic.rst @erlend-aasland @AA-Turner # C Analyser Tools/c-analyzer/ @ericsnowcurrently +# C API Documentation Checks +Tools/check-c-api-docs/ @ZeroIntensity + # Fuzzing Modules/_xxtestfuzz/ @ammaraskar @@ -149,6 +157,7 @@ Lib/test/test_android.py @mhsmith @freakboy3742 # iOS Doc/using/ios.rst @freakboy3742 Lib/_ios_support.py @freakboy3742 +Apple/ @freakboy3742 iOS/ @freakboy3742 # macOS @@ -157,16 +166,16 @@ Lib/_osx_support.py @python/macos-team Lib/test/test__osx_support.py @python/macos-team # WebAssembly -Tools/wasm/README.md @brettcannon @freakboy3742 +Tools/wasm/README.md @brettcannon @freakboy3742 @emmatyping # WebAssembly (Emscripten) -Tools/wasm/config.site-wasm32-emscripten @freakboy3742 -Tools/wasm/emscripten @freakboy3742 +Tools/wasm/config.site-wasm32-emscripten @freakboy3742 @emmatyping +Tools/wasm/emscripten @freakboy3742 @emmatyping # WebAssembly (WASI) -Tools/wasm/wasi-env @brettcannon -Tools/wasm/wasi.py @brettcannon -Tools/wasm/wasi @brettcannon +Tools/wasm/wasi-env @brettcannon @emmatyping +Tools/wasm/wasi.py @brettcannon @emmatyping +Tools/wasm/wasi @brettcannon @emmatyping # Windows PC/ @python/windows-team @@ -239,10 +248,10 @@ Lib/test/test_getpath.py @FFY00 Modules/getpath* @FFY00 # Hashing / ``hash()`` and related -Include/cpython/pyhash.h @gpshead @picnixz @tiran -Include/internal/pycore_pyhash.h @gpshead @picnixz @tiran -Include/pyhash.h @gpshead @picnixz @tiran -Python/pyhash.c @gpshead @picnixz @tiran +Include/cpython/pyhash.h @gpshead @picnixz +Include/internal/pycore_pyhash.h @gpshead @picnixz +Include/pyhash.h @gpshead @picnixz +Python/pyhash.c @gpshead @picnixz # The import system (including importlib) **/*import* @brettcannon @ericsnowcurrently @ncoghlan @warsaw @@ -280,10 +289,10 @@ Tools/jit/ @brandtbucher @savannahostrowski @diegorusso InternalDocs/jit.md @brandtbucher @savannahostrowski @diegorusso @AA-Turner # Micro-op / μop / Tier 2 Optimiser -Python/optimizer.c @markshannon +Python/optimizer.c @markshannon @Fidget-Spinner Python/optimizer_analysis.c @markshannon @tomasr8 @Fidget-Spinner Python/optimizer_bytecodes.c @markshannon @tomasr8 @Fidget-Spinner -Python/optimizer_symbols.c @markshannon @tomasr8 +Python/optimizer_symbols.c @markshannon @tomasr8 @Fidget-Spinner # Parser, Lexer, and Grammar Grammar/python.gram @pablogsal @lysnikolaou @@ -313,7 +322,7 @@ Tools/build/generate_global_objects.py @ericsnowcurrently # Remote Debugging Python/remote_debug.h @pablogsal Python/remote_debugging.c @pablogsal -Modules/_remote_debugging_module.c @pablogsal @ambv @1st1 +Modules/_remote_debugging/ @pablogsal # Sub-Interpreters **/*crossinterp* @ericsnowcurrently @@ -369,14 +378,14 @@ Lib/calendar.py @AA-Turner Lib/test/test_calendar.py @AA-Turner # Cryptographic Primitives and Applications -**/*hashlib* @gpshead @picnixz @tiran -**/*hashopenssl* @gpshead @picnixz @tiran +**/*hashlib* @gpshead @picnixz +**/*hashopenssl* @gpshead @picnixz **/*hmac* @gpshead @picnixz **/*ssl* @gpshead @picnixz Modules/_hacl/ @gpshead @picnixz -Modules/*blake* @gpshead @picnixz @tiran -Modules/*md5* @gpshead @picnixz @tiran -Modules/*sha* @gpshead @picnixz @tiran +Modules/*blake* @gpshead @picnixz +Modules/*md5* @gpshead @picnixz +Modules/*sha* @gpshead @picnixz # Codecs Modules/cjkcodecs/ @corona10 @@ -405,11 +414,15 @@ Lib/test/test_dataclasses/ @ericvsmith # Dates and times Doc/**/*time.rst @pganssle @abalkin +Doc/library/zoneinfo.rst @pganssle Include/datetime.h @pganssle @abalkin Include/internal/pycore_time.h @pganssle @abalkin +Lib/test/test_zoneinfo/ @pganssle +Lib/zoneinfo/ @pganssle Lib/*time.py @pganssle @abalkin Lib/test/datetimetester.py @pganssle @abalkin Lib/test/test_*time.py @pganssle @abalkin +Modules/*zoneinfo* @pganssle Modules/*time* @pganssle @abalkin Python/pytime.c @pganssle @abalkin @@ -524,6 +537,11 @@ Lib/pydoc.py @AA-Turner Lib/pydoc_data/ @AA-Turner Lib/test/test_pydoc/ @AA-Turner +# Profiling (Sampling) +Doc/library/profiling*.rst @pablogsal +Lib/profiling/ @pablogsal +Lib/test/test_profiling/ @pablogsal + # PyREPL Lib/_pyrepl/ @pablogsal @lysnikolaou @ambv Lib/test/test_pyrepl/ @pablogsal @lysnikolaou @ambv @@ -603,9 +621,9 @@ Lib/test/test_zipfile/_path/ @jaraco Lib/zipfile/_path/ @jaraco # Zstandard -Lib/compression/zstd/ @AA-Turner -Lib/test/test_zstd.py @AA-Turner -Modules/_zstd/ @AA-Turner +Lib/compression/zstd/ @AA-Turner @emmatyping +Lib/test/test_zstd.py @AA-Turner @emmatyping +Modules/_zstd/ @AA-Turner @emmatyping # ---------------------------------------------------------------------------- diff --git a/.github/CONTRIBUTING.rst b/.github/CONTRIBUTING.rst index 5b86302bdd1..94b67ce3dbe 100644 --- a/.github/CONTRIBUTING.rst +++ b/.github/CONTRIBUTING.rst @@ -28,23 +28,23 @@ Please be aware that our workflow does deviate slightly from the typical GitHub project. Details on how to properly submit a pull request are covered in `Lifecycle of a Pull Request `_. We utilize various bots and status checks to help with this, so do follow the -comments they leave and their "Details" links, respectively. The key points of -our workflow that are not covered by a bot or status check are: +comments they leave and their "Details" links, respectively. -- All discussions that are not directly related to the code in the pull request - should happen on `GitHub Issues `_. -- Upon your first non-trivial pull request (which includes documentation changes), - feel free to add yourself to ``Misc/ACKS`` +The final key part of our workflow is that all discussions that are not +directly related to the code in the pull request should happen on +`GitHub Issues `__, generally in the +pull request's parent issue. Setting Expectations -------------------- -Due to the fact that this project is entirely volunteer-run (i.e. no one is paid -to work on Python full-time), we unfortunately can make no guarantees as to if +Due to the fact that this project is run by volunteers, +unfortunately we cannot make any guarantees as to if or when a core developer will get around to reviewing your pull request. If no core developer has done a review or responded to changes made because of a -"changes requested" review, please feel free to email python-dev to ask if -someone could take a look at your pull request. +"changes requested" review within a month, you can ask for someone to +review your pull request via a post in the `Core Development Discourse +category `__. Code of Conduct diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 75d174307ce..de6e8756b03 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -5,3 +5,6 @@ contact_links: - name: "Proposing new features" about: "Submit major feature proposal (e.g. syntax changes) to an ideas forum first." url: "https://discuss.python.org/c/ideas/6" + - name: "Python Install Manager issues" + about: "Report issues with the Python Install Manager (for Windows)" + url: "https://github.com/python/pymanager/issues" diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 68aae196357..267ff6b42a8 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -1,6 +1,7 @@ self-hosted-runner: # Pending https://github.com/rhysd/actionlint/issues/533 - labels: ["windows-11-arm"] + # and https://github.com/rhysd/actionlint/issues/571 + labels: ["windows-11-arm", "macos-15-intel"] config-variables: null diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c8a3165d690..7f3376f8ddb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,6 +12,11 @@ updates: update-types: - "version-update:semver-minor" - "version-update:semver-patch" + cooldown: + # https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns + # Cooldowns protect against supply chain attacks by avoiding the + # highest-risk window immediately after new releases. + default-days: 14 - package-ecosystem: "pip" directory: "/Tools/" schedule: @@ -19,3 +24,5 @@ updates: labels: - "skip issue" - "skip news" + cooldown: + default-days: 14 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83a668fc720..cb2e96d719b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -109,20 +109,10 @@ jobs: python-version: '3.x' - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - # Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }}-${{ env.pythonLocation }} - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Add ccache to PATH run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - name: Configure CPython run: | # Build Python with the libpython dynamic library @@ -152,6 +142,9 @@ jobs: - name: Check for unsupported C global variables if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME run: make check-c-globals + - name: Check for undocumented C APIs + run: make check-c-api-docs + build-windows: name: >- @@ -198,32 +191,23 @@ jobs: macOS ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-macos == 'true' strategy: fail-fast: false matrix: - # Cirrus and macos-14 are M1, macos-13 is default GHA Intel. - # macOS 13 only runs tests against the GIL-enabled CPython. - # Cirrus used for upstream, macos-14 for forks. + # macos-14 is M1, macos-15-intel is Intel. + # macos-15-intel only runs tests against the GIL-enabled CPython. os: - - ghcr.io/cirruslabs/macos-runner:sonoma - macos-14 - - macos-13 - is-fork: # only used for the exclusion trick - - ${{ github.repository_owner != 'python' }} + - macos-15-intel free-threading: - false - true exclude: - - os: ghcr.io/cirruslabs/macos-runner:sonoma - is-fork: true - - os: macos-14 - is-fork: false - - os: macos-13 + - os: macos-15-intel free-threading: true uses: ./.github/workflows/reusable-macos.yml with: - config_hash: ${{ needs.build-context.outputs.config-hash }} free-threading: ${{ matrix.free-threading }} os: ${{ matrix.os }} @@ -233,7 +217,7 @@ jobs: ${{ fromJSON(matrix.free-threading) && '(free-threading)' || '' }} ${{ fromJSON(matrix.bolt) && '(bolt)' || '' }} needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' strategy: fail-fast: false matrix: @@ -255,7 +239,6 @@ jobs: bolt: true uses: ./.github/workflows/reusable-ubuntu.yml with: - config_hash: ${{ needs.build-context.outputs.config-hash }} bolt-optimizations: ${{ matrix.bolt }} free-threading: ${{ matrix.free-threading }} os: ${{ matrix.os }} @@ -265,7 +248,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' strategy: fail-fast: false matrix: @@ -273,7 +256,7 @@ jobs: # Keep 1.1.1w in our list despite it being upstream EOL and otherwise # unsupported as it most resembles other 1.1.1-work-a-like ssl APIs # supported by important vendors such as AWS-LC. - openssl_ver: [1.1.1w, 3.0.17, 3.2.5, 3.3.4, 3.4.2, 3.5.2] + openssl_ver: [1.1.1w, 3.0.18, 3.2.6, 3.3.5, 3.4.3, 3.5.4] # See Tools/ssl/make_ssl_data.py for notes on adding a new version env: OPENSSL_VER: ${{ matrix.openssl_ver }} @@ -286,11 +269,6 @@ jobs: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies @@ -312,10 +290,6 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - name: Configure CPython run: ./configure CFLAGS="-fdiagnostics-format=json" --config-cache --enable-slower-safety --with-pydebug --with-openssl="$OPENSSL_DIR" - name: Build CPython @@ -330,7 +304,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' strategy: fail-fast: false matrix: @@ -347,11 +321,6 @@ jobs: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies @@ -378,10 +347,6 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - name: Configure CPython run: | ./configure CFLAGS="-fdiagnostics-format=json" \ @@ -403,15 +368,14 @@ jobs: build-android: name: Android (${{ matrix.arch }}) needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-android == 'true' timeout-minutes: 60 strategy: fail-fast: false matrix: include: - # Use the same runs-on configuration as build-macos and build-ubuntu. - arch: aarch64 - runs-on: ${{ github.repository_owner == 'python' && 'ghcr.io/cirruslabs/macos-runner:sonoma' || 'macos-14' }} + runs-on: macos-14 - arch: x86_64 runs-on: ubuntu-24.04 @@ -421,24 +385,45 @@ jobs: with: persist-credentials: false - name: Build and test - run: ./Android/android.py ci ${{ matrix.arch }}-linux-android + run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android + + build-ios: + name: iOS + needs: build-context + if: needs.build-context.outputs.run-ios == 'true' + timeout-minutes: 60 + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + # GitHub recommends explicitly selecting the desired Xcode version: + # https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140 + # This became a necessity as a result of + # https://github.com/actions/runner-images/issues/12541 and + # https://github.com/actions/runner-images/issues/12751. + - name: Select Xcode version + run: | + sudo xcode-select --switch /Applications/Xcode_15.4.app + + - name: Build and test + run: python3 Apple ci iOS --fast-ci --simulator 'iPhone SE (3rd generation),OS=17.5' build-wasi: name: 'WASI' needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-wasi == 'true' uses: ./.github/workflows/reusable-wasi.yml - with: - config_hash: ${{ needs.build-context.outputs.config-hash }} test-hypothesis: name: "Hypothesis tests on Ubuntu" runs-on: ubuntu-24.04 timeout-minutes: 60 needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' env: - OPENSSL_VER: 3.0.16 + OPENSSL_VER: 3.0.18 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v4 @@ -465,10 +450,6 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: false - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV" @@ -479,11 +460,6 @@ jobs: run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR" - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: ${{ env.CPYTHON_BUILDDIR }}/config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | @@ -552,13 +528,13 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' strategy: fail-fast: false matrix: os: [ubuntu-24.04] env: - OPENSSL_VER: 3.0.16 + OPENSSL_VER: 3.0.18 PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: @@ -567,11 +543,6 @@ jobs: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install dependencies @@ -597,11 +568,6 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: ${{ github.event_name == 'push' }} - max-size: "200M" - name: Configure CPython run: ./configure --config-cache --with-address-sanitizer --without-pymalloc - name: Build CPython @@ -615,7 +581,7 @@ jobs: # ${{ '' } is a hack to nest jobs under the same sidebar category. name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation] needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' strategy: fail-fast: false matrix: @@ -633,7 +599,6 @@ jobs: uses: ./.github/workflows/reusable-san.yml with: sanitizer: ${{ matrix.sanitizer }} - config_hash: ${{ needs.build-context.outputs.config-hash }} free-threading: ${{ matrix.free-threading }} cross-build-linux: @@ -641,18 +606,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 needs: build-context - if: needs.build-context.outputs.run-tests == 'true' + if: needs.build-context.outputs.run-ubuntu == 'true' steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ needs.build-context.outputs.config-hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Set build dir @@ -732,6 +692,7 @@ jobs: - build-ubuntu-ssltests-awslc - build-ubuntu-ssltests-openssl - build-android + - build-ios - build-wasi - test-hypothesis - build-asan @@ -751,24 +712,24 @@ jobs: test-hypothesis, cifuzz, allowed-skips: >- - ${{ - !fromJSON(needs.build-context.outputs.run-docs) - && ' - check-docs, - ' - || '' - }} + ${{ !fromJSON(needs.build-context.outputs.run-docs) && 'check-docs,' || '' }} ${{ needs.build-context.outputs.run-tests != 'true' && ' check-autoconf-regen, check-generated-files, - build-macos, + ' + || '' + }} + ${{ !fromJSON(needs.build-context.outputs.run-windows-tests) && 'build-windows,' || '' }} + ${{ !fromJSON(needs.build-context.outputs.run-ci-fuzz) && 'cifuzz,' || '' }} + ${{ !fromJSON(needs.build-context.outputs.run-macos) && 'build-macos,' || '' }} + ${{ + !fromJSON(needs.build-context.outputs.run-ubuntu) + && ' build-ubuntu, build-ubuntu-ssltests-awslc, build-ubuntu-ssltests-openssl, - build-android, - build-wasi, test-hypothesis, build-asan, build-san, @@ -776,18 +737,7 @@ jobs: ' || '' }} - ${{ - !fromJSON(needs.build-context.outputs.run-windows-tests) - && ' - build-windows, - ' - || '' - }} - ${{ - !fromJSON(needs.build-context.outputs.run-ci-fuzz) - && ' - cifuzz, - ' - || '' - }} + ${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }} + ${{ !fromJSON(needs.build-context.outputs.run-ios) && 'build-ios,' || '' }} + ${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }} jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/jit.yml b/.github/workflows/jit.yml index 51a069d857f..62325250bd3 100644 --- a/.github/workflows/jit.yml +++ b/.github/workflows/jit.yml @@ -68,20 +68,20 @@ jobs: - true - false llvm: - - 19 + - 21 include: - target: i686-pc-windows-msvc/msvc architecture: Win32 - runner: windows-latest + runner: windows-2022 - target: x86_64-pc-windows-msvc/msvc architecture: x64 - runner: windows-latest + runner: windows-2022 - target: aarch64-pc-windows-msvc/msvc architecture: ARM64 runner: windows-11-arm - target: x86_64-apple-darwin/clang architecture: x86_64 - runner: macos-13 + runner: macos-15-intel - target: aarch64-apple-darwin/clang architecture: aarch64 runner: macos-14 @@ -106,15 +106,10 @@ jobs: ./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} ./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3 - # The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966. - # This is a bug in the macOS runner image where the pre-installed Python is installed in the same - # directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes - # the symlink to the pre-installed Python so that the Homebrew Python is used instead. - name: macOS if: runner.os == 'macOS' run: | brew update - find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete brew install llvm@${{ matrix.llvm }} export SDKROOT="$(xcrun --show-sdk-path)" # Set MACOSX_DEPLOYMENT_TARGET and -Werror=unguarded-availability to @@ -134,30 +129,81 @@ jobs: make all --jobs 4 ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 - # XXX: GH-133171 - # jit-with-disabled-gil: - # name: Free-Threaded (Debug) - # needs: interpreter - # runs-on: ubuntu-24.04 - # timeout-minutes: 90 - # strategy: - # fail-fast: false - # matrix: - # llvm: - # - 19 - # steps: - # - uses: actions/checkout@v4 - # with: - # persist-credentials: false - # - uses: actions/setup-python@v5 - # with: - # python-version: '3.11' - # - name: Build with JIT enabled and GIL disabled - # run: | - # sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} - # export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" - # ./configure --enable-experimental-jit --with-pydebug --disable-gil - # make all --jobs 4 - # - name: Run tests - # run: | - # ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 + jit-with-disabled-gil: + name: Free-Threaded (Debug) + needs: interpreter + runs-on: ubuntu-24.04 + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + llvm: + - 21 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Build with JIT enabled and GIL disabled + run: | + sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} + export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" + ./configure --enable-experimental-jit --with-pydebug --disable-gil + make all --jobs 4 + - name: Run tests + run: | + ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 + continue-on-error: true + + no-opt-jit: + name: JIT without optimizations (Debug) + needs: interpreter + runs-on: ubuntu-24.04 + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + llvm: + - 21 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Build with JIT + run: | + sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} + export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" + ./configure --enable-experimental-jit --with-pydebug + make all --jobs 4 + - name: Run tests without optimizations + run: | + PYTHON_UOPS_OPTIMIZE=0 ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3 + + tail-call-jit: + name: JIT with tail calling interpreter + needs: interpreter + runs-on: ubuntu-24.04 + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + llvm: + - 21 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Build with JIT and tailcall + run: | + sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }} + export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH" + CC=clang-${{ matrix.llvm }} ./configure --enable-experimental-jit --with-tail-call-interp --with-pydebug + make all --jobs 4 diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 5d5d77f29f6..8810730e193 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -16,6 +16,7 @@ on: - "Tools/build/check_extension_modules.py" - "Tools/build/check_warnings.py" - "Tools/build/compute-changes.py" + - "Tools/build/consts_getter.py" - "Tools/build/deepfreeze.py" - "Tools/build/generate-build-details.py" - "Tools/build/generate_sbom.py" @@ -25,6 +26,7 @@ on: - "Tools/build/update_file.py" - "Tools/build/verify_ensurepip_wheels.py" - "Tools/cases_generator/**" + - "Tools/check-c-api-docs/**" - "Tools/clinic/**" - "Tools/jit/**" - "Tools/peg_generator/**" @@ -57,6 +59,7 @@ jobs: "Lib/tomllib", "Tools/build", "Tools/cases_generator", + "Tools/check-c-api-docs", "Tools/clinic", "Tools/jit", "Tools/peg_generator", diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml deleted file mode 100644 index 1d9d637ec84..00000000000 --- a/.github/workflows/project-updater.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Update GH projects - -on: - issues: - types: - - opened - - labeled - -permissions: - contents: read - -jobs: - add-to-project: - name: Add issues to projects - runs-on: ubuntu-latest - timeout-minutes: 10 - strategy: - fail-fast: false - matrix: - include: - # if an issue has any of these labels, it will be added - # to the corresponding project - - { project: 2, label: "release-blocker, deferred-blocker" } - - { project: 32, label: sprint } - - steps: - - uses: actions/add-to-project@v1.0.0 - with: - project-url: https://github.com/orgs/python/projects/${{ matrix.project }} - github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} - labeled: ${{ matrix.label }} diff --git a/.github/workflows/reusable-context.yml b/.github/workflows/reusable-context.yml index d2668ddcac1..ce5562f2d51 100644 --- a/.github/workflows/reusable-context.yml +++ b/.github/workflows/reusable-context.yml @@ -17,24 +17,36 @@ on: # yamllint disable-line rule:truthy # || 'falsy-branch' # }} # - config-hash: - description: Config hash value for use in cache keys - value: ${{ jobs.compute-changes.outputs.config-hash }} # str - run-docs: - description: Whether to build the docs - value: ${{ jobs.compute-changes.outputs.run-docs }} # bool - run-tests: - description: Whether to run the regular tests - value: ${{ jobs.compute-changes.outputs.run-tests }} # bool - run-windows-tests: - description: Whether to run the Windows tests - value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool - run-windows-msi: - description: Whether to run the MSI installer smoke tests - value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool + run-android: + description: Whether to run the Android tests + value: ${{ jobs.compute-changes.outputs.run-android }} # bool run-ci-fuzz: description: Whether to run the CIFuzz job value: ${{ jobs.compute-changes.outputs.run-ci-fuzz }} # bool + run-docs: + description: Whether to build the docs + value: ${{ jobs.compute-changes.outputs.run-docs }} # bool + run-ios: + description: Whether to run the iOS tests + value: ${{ jobs.compute-changes.outputs.run-ios }} # bool + run-macos: + description: Whether to run the macOS tests + value: ${{ jobs.compute-changes.outputs.run-macos }} # bool + run-tests: + description: Whether to run the regular tests + value: ${{ jobs.compute-changes.outputs.run-tests }} # bool + run-ubuntu: + description: Whether to run the Ubuntu tests + value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool + run-wasi: + description: Whether to run the WASI tests + value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool + run-windows-msi: + description: Whether to run the MSI installer smoke tests + value: ${{ jobs.compute-changes.outputs.run-windows-msi }} # bool + run-windows-tests: + description: Whether to run the Windows tests + value: ${{ jobs.compute-changes.outputs.run-windows-tests }} # bool jobs: compute-changes: @@ -42,10 +54,14 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 outputs: - config-hash: ${{ steps.config-hash.outputs.hash }} + run-android: ${{ steps.changes.outputs.run-android }} run-ci-fuzz: ${{ steps.changes.outputs.run-ci-fuzz }} run-docs: ${{ steps.changes.outputs.run-docs }} + run-ios: ${{ steps.changes.outputs.run-ios }} + run-macos: ${{ steps.changes.outputs.run-macos }} run-tests: ${{ steps.changes.outputs.run-tests }} + run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }} + run-wasi: ${{ steps.changes.outputs.run-wasi }} run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }} run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }} steps: @@ -100,8 +116,3 @@ jobs: GITHUB_EVENT_NAME: ${{ github.event_name }} CCF_TARGET_REF: ${{ github.base_ref || github.event.repository.default_branch }} CCF_HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }} - - - name: Compute hash for config cache key - id: config-hash - run: | - echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml index de0c4022136..98d557ba1ea 100644 --- a/.github/workflows/reusable-macos.yml +++ b/.github/workflows/reusable-macos.yml @@ -3,9 +3,6 @@ name: Reusable macOS on: workflow_call: inputs: - config_hash: - required: true - type: string free-threading: required: false type: boolean @@ -36,16 +33,11 @@ jobs: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.config_hash }} - name: Install Homebrew dependencies run: | - brew install pkg-config openssl@3.0 xz gdbm tcl-tk@8 make + brew install pkg-config openssl@3.0 xz gdbm tcl-tk@9 make # Because alternate versions are not symlinked into place by default: - brew link --overwrite tcl-tk@8 + brew link --overwrite tcl-tk@9 - name: Configure CPython run: | MACOSX_DEPLOYMENT_TARGET=10.15 \ @@ -60,15 +52,15 @@ jobs: --prefix=/opt/python-dev \ --with-openssl="$(brew --prefix openssl@3.0)" - name: Build CPython - if : ${{ inputs.free-threading || inputs.os != 'macos-13' }} + if : ${{ inputs.free-threading || inputs.os != 'macos-15-intel' }} run: gmake -j8 - name: Build CPython for compiler warning check - if : ${{ !inputs.free-threading && inputs.os == 'macos-13' }} + if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }} run: set -o pipefail; gmake -j8 --output-sync 2>&1 | tee compiler_output_macos.txt - name: Display build info run: make pythoninfo - name: Check compiler warnings - if : ${{ !inputs.free-threading && inputs.os == 'macos-13' }} + if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }} run: >- python3 Tools/build/check_warnings.py --compiler-output-file-path=compiler_output_macos.txt diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index e6ff02e4838..c601d0b7338 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -6,9 +6,6 @@ on: sanitizer: required: true type: string - config_hash: - required: true - type: string free-threading: description: Whether to use free-threaded mode required: false @@ -34,11 +31,6 @@ jobs: persist-credentials: false - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.sanitizer }}-${{ inputs.config_hash }} - name: Install dependencies run: | sudo ./.github/workflows/posix-deps-apt.sh @@ -77,11 +69,6 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: ${{ github.event_name == 'push' }} - max-size: "200M" - name: Configure CPython run: >- ./configure diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml index 76b19fd5d1a..0c1ebe29ae3 100644 --- a/.github/workflows/reusable-ubuntu.yml +++ b/.github/workflows/reusable-ubuntu.yml @@ -3,9 +3,6 @@ name: Reusable Ubuntu on: workflow_call: inputs: - config_hash: - required: true - type: string bolt-optimizations: description: Whether to enable BOLT optimizations required: false @@ -30,7 +27,7 @@ jobs: runs-on: ${{ inputs.os }} timeout-minutes: 60 env: - OPENSSL_VER: 3.0.15 + OPENSSL_VER: 3.0.18 PYTHONSTRICTEXTENSIONBUILD: 1 TERM: linux steps: @@ -64,11 +61,6 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: ${{ github.event_name == 'push' }} - max-size: "200M" - name: Setup directory envs for out-of-tree builds run: | echo "CPYTHON_RO_SRCDIR=$(realpath -m "${GITHUB_WORKSPACE}"/../cpython-ro-srcdir)" >> "$GITHUB_ENV" @@ -79,11 +71,6 @@ jobs: run: sudo mount --bind -o ro "$GITHUB_WORKSPACE" "$CPYTHON_RO_SRCDIR" - name: Runner image version run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Restore config.cache - uses: actions/cache@v4 - with: - path: ${{ env.CPYTHON_BUILDDIR }}/config.cache - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ inputs.config_hash }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} # `test_unpickle_module_race` writes to the source directory, which is diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml index 6beb91e66d4..91d76fd1b5f 100644 --- a/.github/workflows/reusable-wasi.yml +++ b/.github/workflows/reusable-wasi.yml @@ -2,10 +2,6 @@ name: Reusable WASI on: workflow_call: - inputs: - config_hash: - required: true - type: string env: FORCE_COLOR: 1 @@ -13,11 +9,11 @@ env: jobs: build-wasi-reusable: name: 'build and test' - runs-on: ubuntu-24.04 + runs-on: ubuntu-24.04-arm timeout-minutes: 60 env: - WASMTIME_VERSION: 22.0.0 - WASI_SDK_VERSION: 24 + WASMTIME_VERSION: 38.0.3 + WASI_SDK_VERSION: 29 WASI_SDK_PATH: /opt/wasi-sdk CROSS_BUILD_PYTHON: cross-build/build CROSS_BUILD_WASI: cross-build/wasm32-wasip1 @@ -40,13 +36,8 @@ jobs: if: steps.cache-wasi-sdk.outputs.cache-hit != 'true' run: | mkdir "${WASI_SDK_PATH}" && \ - curl -s -S --location "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.tar.gz" | \ + curl -s -S --location "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-arm64-linux.tar.gz" | \ tar --strip-components 1 --directory "${WASI_SDK_PATH}" --extract --gunzip - - name: "Configure ccache action" - uses: hendrikmuhs/ccache-action@v1.2 - with: - save: ${{ github.event_name == 'push' }} - max-size: "200M" - name: "Add ccache to PATH" run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - name: "Install Python" @@ -55,29 +46,15 @@ jobs: python-version: '3.x' - name: "Runner image version" run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: "Restore Python build config.cache" - uses: actions/cache@v4 - with: - path: ${{ env.CROSS_BUILD_PYTHON }}/config.cache - # Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python. - # Include the hash of `Tools/wasm/wasi.py` as it may change the environment variables. - # (Make sure to keep the key in sync with the other config.cache step below.) - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }} - name: "Configure build Python" - run: python3 Tools/wasm/wasi.py configure-build-python -- --config-cache --with-pydebug + run: python3 Tools/wasm/wasi configure-build-python -- --config-cache --with-pydebug - name: "Make build Python" - run: python3 Tools/wasm/wasi.py make-build-python - - name: "Restore host config.cache" - uses: actions/cache@v4 - with: - path: ${{ env.CROSS_BUILD_WASI }}/config.cache - # Should be kept in sync with the other config.cache step above. - key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }} + run: python3 Tools/wasm/wasi make-build-python - name: "Configure host" # `--with-pydebug` inferred from configure-build-python - run: python3 Tools/wasm/wasi.py configure-host -- --config-cache + run: python3 Tools/wasm/wasi configure-host -- --config-cache - name: "Make host" - run: python3 Tools/wasm/wasi.py make-host + run: python3 Tools/wasm/wasi make-host - name: "Display build info" run: make --directory "${CROSS_BUILD_WASI}" pythoninfo - name: "Test" diff --git a/.github/workflows/reusable-windows-msi.yml b/.github/workflows/reusable-windows-msi.yml index a50de344bba..c95e40a3809 100644 --- a/.github/workflows/reusable-windows-msi.yml +++ b/.github/workflows/reusable-windows-msi.yml @@ -17,7 +17,7 @@ env: jobs: build: name: installer for ${{ inputs.arch }} - runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }} + runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022' }} timeout-minutes: 60 env: ARCH: ${{ inputs.arch }} diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml index 37c802095b0..0648b770753 100644 --- a/.github/workflows/reusable-windows.yml +++ b/.github/workflows/reusable-windows.yml @@ -21,7 +21,7 @@ env: jobs: build: name: Build and test (${{ inputs.arch }}) - runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }} + runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022' }} timeout-minutes: 60 env: ARCH: ${{ inputs.arch }} diff --git a/.github/workflows/tail-call.yml b/.github/workflows/tail-call.yml index 57c92e193a9..e99e317182e 100644 --- a/.github/workflows/tail-call.yml +++ b/.github/workflows/tail-call.yml @@ -49,16 +49,16 @@ jobs: include: # - target: i686-pc-windows-msvc/msvc # architecture: Win32 -# runner: windows-latest +# runner: windows-2022 - target: x86_64-pc-windows-msvc/msvc architecture: x64 - runner: windows-latest + runner: windows-2022 # - target: aarch64-pc-windows-msvc/msvc # architecture: ARM64 -# runner: windows-latest +# runner: windows-2022 - target: x86_64-apple-darwin/clang architecture: x86_64 - runner: macos-13 + runner: macos-15-intel - target: aarch64-apple-darwin/clang architecture: aarch64 runner: macos-14 @@ -101,17 +101,10 @@ jobs: set LLVMInstallDir=C:\Program Files\LLVM ./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }} - # The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966. - # This is a bug in the macOS runner image where the pre-installed Python is installed in the same - # directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes - # the symlink to the pre-installed Python so that the Homebrew Python is used instead. - # Note: when a new LLVM is released, the homebrew installation directory changes, so the builds will fail. - # We either need to upgrade LLVM or change the directory being pointed to. - name: Native macOS (release) if: runner.os == 'macOS' run: | brew update - find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete brew install llvm@${{ matrix.llvm }} export SDKROOT="$(xcrun --show-sdk-path)" export PATH="/usr/local/opt/llvm@${{ matrix.llvm }}/bin:$PATH" diff --git a/.gitignore b/.gitignore index e842676d866..e234d86e8d5 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ gmon.out .pytest_cache/ .ruff_cache/ .DS_Store +.pixi/ *.exe @@ -71,15 +72,15 @@ Lib/test/data/* /Makefile /Makefile.pre /iOSTestbed.* -iOS/Frameworks/ -iOS/Resources/Info.plist -iOS/testbed/build -iOS/testbed/Python.xcframework/ios-*/bin -iOS/testbed/Python.xcframework/ios-*/include -iOS/testbed/Python.xcframework/ios-*/lib -iOS/testbed/Python.xcframework/ios-*/Python.framework -iOS/testbed/iOSTestbed.xcodeproj/project.xcworkspace -iOS/testbed/iOSTestbed.xcodeproj/xcuserdata +Apple/iOS/Frameworks/ +Apple/iOS/Resources/Info.plist +Apple/testbed/build +Apple/testbed/Python.xcframework/*/bin +Apple/testbed/Python.xcframework/*/include +Apple/testbed/Python.xcframework/*/lib +Apple/testbed/Python.xcframework/*/Python.framework +Apple/testbed/*Testbed.xcodeproj/project.xcworkspace +Apple/testbed/*Testbed.xcodeproj/xcuserdata Mac/Makefile Mac/PythonLauncher/Info.plist Mac/PythonLauncher/Makefile @@ -135,7 +136,6 @@ Tools/unicode/data/ /config.log /config.status /config.status.lineno -# hendrikmuhs/ccache-action@v1 /.ccache /cross-build/ /jit_stencils*.h diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d101f5c37e6..c5767ee841e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,23 +1,43 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.8 + rev: v0.13.2 hooks: - - id: ruff + - id: ruff-check + name: Run Ruff (lint) on Apple/ + args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml] + files: ^Apple/ + - id: ruff-check name: Run Ruff (lint) on Doc/ args: [--exit-non-zero-on-fix] files: ^Doc/ - - id: ruff + - id: ruff-check name: Run Ruff (lint) on Lib/test/ args: [--exit-non-zero-on-fix] files: ^Lib/test/ - - id: ruff + - id: ruff-check name: Run Ruff (lint) on Tools/build/ args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml] files: ^Tools/build/ - - id: ruff + - id: ruff-check + name: Run Ruff (lint) on Tools/i18n/ + args: [--exit-non-zero-on-fix, --config=Tools/i18n/.ruff.toml] + files: ^Tools/i18n/ + - id: ruff-check name: Run Ruff (lint) on Argument Clinic args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml] files: ^Tools/clinic/|Lib/test/test_clinic.py + - id: ruff-check + name: Run Ruff (lint) on Tools/peg_generator/ + args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml] + files: ^Tools/peg_generator/ + - id: ruff-check + name: Run Ruff (lint) on Tools/wasm/ + args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml] + files: ^Tools/wasm/ + - id: ruff-format + name: Run Ruff (format) on Apple/ + args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml] + files: ^Apple - id: ruff-format name: Run Ruff (format) on Doc/ args: [--check] @@ -26,9 +46,13 @@ repos: name: Run Ruff (format) on Tools/build/check_warnings.py args: [--check, --config=Tools/build/.ruff.toml] files: ^Tools/build/check_warnings.py + - id: ruff-format + name: Run Ruff (format) on Tools/wasm/ + args: [--check, --config=Tools/wasm/.ruff.toml] + files: ^Tools/wasm/ - repo: https://github.com/psf/black-pre-commit-mirror - rev: 25.1.0 + rev: 25.9.0 hooks: - id: black name: Run Black on Tools/jit/ @@ -39,7 +63,6 @@ repos: hooks: - id: remove-tabs types: [python] - exclude: ^Tools/c-analyzer/cpython/_parser.py - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 @@ -60,7 +83,7 @@ repos: files: '^\.github/CODEOWNERS|\.(gram)$' - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.33.2 + rev: 0.34.0 hooks: - id: check-dependabot - id: check-github-workflows @@ -72,7 +95,7 @@ repos: - id: actionlint - repo: https://github.com/woodruffw/zizmor-pre-commit - rev: v1.11.0 + rev: v1.14.1 hooks: - id: zizmor diff --git a/Android/android.py b/Android/android.py index 85874ad9b60..d1a10be776e 100755 --- a/Android/android.py +++ b/Android/android.py @@ -2,6 +2,7 @@ import asyncio import argparse +import json import os import platform import re @@ -28,6 +29,7 @@ in_source_tree = ( ANDROID_DIR.name == "Android" and (PYTHON_DIR / "pyconfig.h.in").exists() ) +ENV_SCRIPT = ANDROID_DIR / "android-env.sh" TESTBED_DIR = ANDROID_DIR / "testbed" CROSS_BUILD_DIR = PYTHON_DIR / "cross-build" @@ -128,12 +130,11 @@ def android_env(host): sysconfig_filename = next(sysconfig_files).name host = re.fullmatch(r"_sysconfigdata__android_(.+).py", sysconfig_filename)[1] - env_script = ANDROID_DIR / "android-env.sh" env_output = subprocess.run( f"set -eu; " f"HOST={host}; " f"PREFIX={prefix}; " - f". {env_script}; " + f". {ENV_SCRIPT}; " f"export", check=True, shell=True, capture_output=True, encoding='utf-8', ).stdout @@ -150,7 +151,7 @@ def android_env(host): env[key] = value if not env: - raise ValueError(f"Found no variables in {env_script.name} output:\n" + raise ValueError(f"Found no variables in {ENV_SCRIPT.name} output:\n" + env_output) return env @@ -184,10 +185,16 @@ def make_build_python(context): run(["make", "-j", str(os.cpu_count())]) +# To create new builds of these dependencies, usually all that's necessary is to +# push a tag to the cpython-android-source-deps repository, and GitHub Actions +# will do the rest. +# +# If you're a member of the Python core team, and you'd like to be able to push +# these tags yourself, please contact Malcolm Smith or Russell Keith-Magee. def unpack_deps(host, prefix_dir): os.chdir(prefix_dir) deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download" - for name_ver in ["bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.0.15-4", + for name_ver in ["bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.0.18-0", "sqlite-3.50.4-0", "xz-5.4.6-1", "zstd-1.5.7-1"]: filename = f"{name_ver}-{host}.tar.gz" download(f"{deps_url}/{name_ver}/{filename}") @@ -274,15 +281,30 @@ def clean_all(context): def setup_ci(): - # https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/ - if "GITHUB_ACTIONS" in os.environ and platform.system() == "Linux": - run( - ["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"], - input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n', - text=True, - ) - run(["sudo", "udevadm", "control", "--reload-rules"]) - run(["sudo", "udevadm", "trigger", "--name-match=kvm"]) + if "GITHUB_ACTIONS" in os.environ: + # Enable emulator hardware acceleration + # (https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/). + if platform.system() == "Linux": + run( + ["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"], + input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n', + text=True, + ) + run(["sudo", "udevadm", "control", "--reload-rules"]) + run(["sudo", "udevadm", "trigger", "--name-match=kvm"]) + + # Free up disk space by deleting unused versions of the NDK + # (https://github.com/freakboy3742/pyspamsum/pull/108). + for line in ENV_SCRIPT.read_text().splitlines(): + if match := re.fullmatch(r"ndk_version=(.+)", line): + ndk_version = match[1] + break + else: + raise ValueError(f"Failed to find NDK version in {ENV_SCRIPT.name}") + + for item in (android_home / "ndk").iterdir(): + if item.name[0].isdigit() and item.name != ndk_version: + delete_glob(item) def setup_sdk(): @@ -546,27 +568,33 @@ async def gradle_task(context): task_prefix = "connected" env["ANDROID_SERIAL"] = context.connected - if context.command: - mode = "-c" - module = context.command - else: - mode = "-m" - module = context.module or "test" + if context.ci_mode: + context.args[0:0] = [ + # See _add_ci_python_opts in libregrtest/main.py. + "-W", "error", "-bb", "-E", + + # Randomization is disabled because order-dependent failures are + # much less likely to pass on a rerun in single-process mode. + "-m", "test", + f"--{context.ci_mode}-ci", "--single-process", "--no-randomize" + ] + + if not any(arg in context.args for arg in ["-c", "-m"]): + context.args[0:0] = ["-m", "test"] args = [ gradlew, "--console", "plain", f"{task_prefix}DebugAndroidTest", ] + [ - # Build-time properties - f"-Ppython.{name}={value}" + f"-P{name}={value}" for name, value in [ - ("sitePackages", context.site_packages), ("cwd", context.cwd) - ] if value - ] + [ - # Runtime properties - f"-Pandroid.testInstrumentationRunnerArguments.python{name}={value}" - for name, value in [ - ("Mode", mode), ("Module", module), ("Args", join_command(context.args)) - ] if value + ("python.sitePackages", context.site_packages), + ("python.cwd", context.cwd), + ( + "android.testInstrumentationRunnerArguments.pythonArgs", + json.dumps(context.args), + ), + ] + if value ] if context.verbose >= 2: args.append("--info") @@ -734,17 +762,14 @@ def ci(context): else: with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir: print("::group::Tests") + # Prove the package is self-contained by using it to run the tests. shutil.unpack_archive(package_path, temp_dir) - - # Arguments are similar to --fast-ci, but in single-process mode. - launcher_args = ["--managed", "maxVersion", "-v"] - test_args = [ - "--single-process", "--fail-env-changed", "--rerun", "--slowest", - "--verbose3", "-u", "all,-cpu", "--timeout=600" + launcher_args = [ + "--managed", "maxVersion", "-v", f"--{context.ci_mode}-ci" ] run( - ["./android.py", "test", *launcher_args, "--", *test_args], + ["./android.py", "test", *launcher_args], cwd=temp_dir ) print("::endgroup::") @@ -827,18 +852,11 @@ def parse_args(): test.add_argument( "--cwd", metavar="DIR", type=abspath, help="Directory to copy as the app's working directory.") - - mode_group = test.add_mutually_exclusive_group() - mode_group.add_argument( - "-c", dest="command", help="Execute the given Python code.") - mode_group.add_argument( - "-m", dest="module", help="Execute the module with the given name.") - test.epilog = ( - "If neither -c nor -m are passed, the default is '-m test', which will " - "run Python's own test suite.") test.add_argument( - "args", nargs="*", help=f"Arguments to add to sys.argv. " - f"Separate them from {SCRIPT_NAME}'s own arguments with `--`.") + "args", nargs="*", help=f"Python command-line arguments. " + f"Separate them from {SCRIPT_NAME}'s own arguments with `--`. " + f"If neither -c nor -m are included, `-m test` will be prepended, " + f"which will run Python's own test suite.") # Package arguments. for subcommand in [package, ci]: @@ -846,6 +864,16 @@ def parse_args(): "-g", action="store_true", default=False, dest="debug", help="Include debug information in package") + # CI arguments + for subcommand in [test, ci]: + group = subcommand.add_mutually_exclusive_group(required=subcommand is ci) + group.add_argument( + "--fast-ci", action="store_const", dest="ci_mode", const="fast", + help="Add test arguments for GitHub Actions") + group.add_argument( + "--slow-ci", action="store_const", dest="ci_mode", const="slow", + help="Add test arguments for buildbots") + return parser.parse_args() diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts index 92cffd61f86..14d43d8c4d5 100644 --- a/Android/testbed/app/build.gradle.kts +++ b/Android/testbed/app/build.gradle.kts @@ -47,7 +47,7 @@ for ((i, prefix) in prefixes.withIndex()) { val libDir = file("$prefix/lib") val version = run { for (filename in libDir.list()!!) { - """python(\d+\.\d+)""".toRegex().matchEntire(filename)?.let { + """python(\d+\.\d+[a-z]*)""".toRegex().matchEntire(filename)?.let { return@run it.groupValues[1] } } @@ -64,9 +64,10 @@ for ((i, prefix) in prefixes.withIndex()) { val libPythonDir = file("$libDir/python$pythonVersion") val triplet = run { for (filename in libPythonDir.list()!!) { - """_sysconfigdata__android_(.+).py""".toRegex().matchEntire(filename)?.let { - return@run it.groupValues[1] - } + """_sysconfigdata_[a-z]*_android_(.+).py""".toRegex() + .matchEntire(filename)?.let { + return@run it.groupValues[1] + } } throw GradleException("Failed to find Python triplet in $libPythonDir") } @@ -78,7 +79,7 @@ android { val androidEnvFile = file("../../android-env.sh").absoluteFile namespace = "org.python.testbed" - compileSdk = 34 + compileSdk = 35 defaultConfig { applicationId = "org.python.testbed" @@ -91,7 +92,7 @@ android { } throw GradleException("Failed to find API level in $androidEnvFile") } - targetSdk = 34 + targetSdk = 35 versionCode = 1 versionName = "1.0" diff --git a/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt b/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt index 94be52dd2dc..e57243566f9 100644 --- a/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt +++ b/Android/testbed/app/src/androidTest/java/org/python/testbed/PythonSuite.kt @@ -20,7 +20,7 @@ class PythonSuite { val status = PythonTestRunner( InstrumentationRegistry.getInstrumentation().targetContext ).run( - InstrumentationRegistry.getArguments() + InstrumentationRegistry.getArguments().getString("pythonArgs")!!, ) assertEquals(0, status) } finally { diff --git a/Android/testbed/app/src/main/c/main_activity.c b/Android/testbed/app/src/main/c/main_activity.c index ec7f93a3e5e..7f024f0a348 100644 --- a/Android/testbed/app/src/main/c/main_activity.c +++ b/Android/testbed/app/src/main/c/main_activity.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,13 @@ static void throw_runtime_exception(JNIEnv *env, const char *message) { message); } +static void throw_errno(JNIEnv *env, const char *error_prefix) { + char error_message[1024]; + snprintf(error_message, sizeof(error_message), + "%s: %s", error_prefix, strerror(errno)); + throw_runtime_exception(env, error_message); +} + // --- Stdio redirection ------------------------------------------------------ @@ -95,10 +103,7 @@ JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToL for (StreamInfo *si = STREAMS; si->file; si++) { char *error_prefix; if ((error_prefix = redirect_stream(si))) { - char error_message[1024]; - snprintf(error_message, sizeof(error_message), - "%s: %s", error_prefix, strerror(errno)); - throw_runtime_exception(env, error_message); + throw_errno(env, error_prefix); return; } } @@ -107,13 +112,38 @@ JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToL // --- Python initialization --------------------------------------------------- -static PyStatus set_config_string( - JNIEnv *env, PyConfig *config, wchar_t **config_str, jstring value -) { - const char *value_utf8 = (*env)->GetStringUTFChars(env, value, NULL); - PyStatus status = PyConfig_SetBytesString(config, config_str, value_utf8); - (*env)->ReleaseStringUTFChars(env, value, value_utf8); - return status; +static char *init_signals() { + // Some tests use SIGUSR1, but that's blocked by default in an Android app in + // order to make it available to `sigwait` in the Signal Catcher thread. + // (https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:art/runtime/signal_catcher.cc). + // That thread's functionality is only useful for debugging the JVM, so disabling + // it should not weaken the tests. + // + // There's no safe way of stopping the thread completely (#123982), but simply + // unblocking SIGUSR1 is enough to fix most tests. + // + // However, in tests that generate multiple different signals in quick + // succession, it's possible for SIGUSR1 to arrive while the main thread is busy + // running the C-level handler for a different signal. In that case, the SIGUSR1 + // may be sent to the Signal Catcher thread instead, which will generate a log + // message containing the text "reacting to signal". + // + // Such tests may need to be changed in one of the following ways: + // * Use a signal other than SIGUSR1 (e.g. test_stress_delivery_simultaneous in + // test_signal.py). + // * Send the signal to a specific thread rather than the whole process (e.g. + // test_signals in test_threadsignals.py. + sigset_t set; + if (sigemptyset(&set)) { + return "sigemptyset"; + } + if (sigaddset(&set, SIGUSR1)) { + return "sigaddset"; + } + if ((errno = pthread_sigmask(SIG_UNBLOCK, &set, NULL))) { + return "pthread_sigmask"; + } + return NULL; } static void throw_status(JNIEnv *env, PyStatus status) { @@ -121,27 +151,47 @@ static void throw_status(JNIEnv *env, PyStatus status) { } JNIEXPORT int JNICALL Java_org_python_testbed_PythonTestRunner_runPython( - JNIEnv *env, jobject obj, jstring home, jstring runModule + JNIEnv *env, jobject obj, jstring home, jarray args ) { + const char *home_utf8 = (*env)->GetStringUTFChars(env, home, NULL); + char cwd[PATH_MAX]; + snprintf(cwd, sizeof(cwd), "%s/%s", home_utf8, "cwd"); + if (chdir(cwd)) { + throw_errno(env, "chdir"); + return 1; + } + + char *error_prefix; + if ((error_prefix = init_signals())) { + throw_errno(env, error_prefix); + return 1; + } + PyConfig config; PyStatus status; - PyConfig_InitIsolatedConfig(&config); + PyConfig_InitPythonConfig(&config); - status = set_config_string(env, &config, &config.home, home); - if (PyStatus_Exception(status)) { + jsize argc = (*env)->GetArrayLength(env, args); + const char *argv[argc + 1]; + for (int i = 0; i < argc; i++) { + jobject arg = (*env)->GetObjectArrayElement(env, args, i); + argv[i] = (*env)->GetStringUTFChars(env, arg, NULL); + } + argv[argc] = NULL; + + // PyConfig_SetBytesArgv "must be called before other methods, since the + // preinitialization configuration depends on command line arguments" + if (PyStatus_Exception(status = PyConfig_SetBytesArgv(&config, argc, (char**)argv))) { throw_status(env, status); return 1; } - status = set_config_string(env, &config, &config.run_module, runModule); + status = PyConfig_SetBytesString(&config, &config.home, home_utf8); if (PyStatus_Exception(status)) { throw_status(env, status); return 1; } - // Some tests generate SIGPIPE and SIGXFSZ, which should be ignored. - config.install_signal_handlers = 1; - status = Py_InitializeFromConfig(&config); if (PyStatus_Exception(status)) { throw_status(env, status); diff --git a/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt b/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt index ef28948486f..5727b0fe6c3 100644 --- a/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt +++ b/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt @@ -5,6 +5,7 @@ import android.os.* import android.system.Os import android.widget.TextView import androidx.appcompat.app.* +import org.json.JSONArray import java.io.* @@ -15,30 +16,25 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - val status = PythonTestRunner(this).run("-m", "test", "-W -uall") + val status = PythonTestRunner(this).run("""["-m", "test", "-W", "-uall"]""") findViewById(R.id.tvHello).text = "Exit status $status" } } class PythonTestRunner(val context: Context) { - fun run(instrumentationArgs: Bundle) = run( - instrumentationArgs.getString("pythonMode")!!, - instrumentationArgs.getString("pythonModule")!!, - instrumentationArgs.getString("pythonArgs") ?: "", - ) - /** Run Python. * - * @param mode Either "-c" or "-m". - * @param module Python statements for "-c" mode, or a module name for - * "-m" mode. - * @param args Arguments to add to sys.argv. Will be parsed by `shlex.split`. + * @param args Python command-line, encoded as JSON. * @return The Python exit status: zero on success, nonzero on failure. */ - fun run(mode: String, module: String, args: String) : Int { - Os.setenv("PYTHON_MODE", mode, true) - Os.setenv("PYTHON_MODULE", module, true) - Os.setenv("PYTHON_ARGS", args, true) + fun run(args: String) : Int { + // We leave argument 0 as an empty string, which is a placeholder for the + // executable name in embedded mode. + val argsJsonArray = JSONArray(args) + val argsStringArray = Array(argsJsonArray.length() + 1) { it -> ""} + for (i in 0..) : Int } diff --git a/Android/testbed/app/src/main/python/android_testbed_main.py b/Android/testbed/app/src/main/python/android_testbed_main.py deleted file mode 100644 index 31b8e5343a8..00000000000 --- a/Android/testbed/app/src/main/python/android_testbed_main.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import runpy -import shlex -import signal -import sys - -# Some tests use SIGUSR1, but that's blocked by default in an Android app in -# order to make it available to `sigwait` in the Signal Catcher thread. -# (https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:art/runtime/signal_catcher.cc). -# That thread's functionality is only useful for debugging the JVM, so disabling -# it should not weaken the tests. -# -# There's no safe way of stopping the thread completely (#123982), but simply -# unblocking SIGUSR1 is enough to fix most tests. -# -# However, in tests that generate multiple different signals in quick -# succession, it's possible for SIGUSR1 to arrive while the main thread is busy -# running the C-level handler for a different signal. In that case, the SIGUSR1 -# may be sent to the Signal Catcher thread instead, which will generate a log -# message containing the text "reacting to signal". -# -# Such tests may need to be changed in one of the following ways: -# * Use a signal other than SIGUSR1 (e.g. test_stress_delivery_simultaneous in -# test_signal.py). -# * Send the signal to a specific thread rather than the whole process (e.g. -# test_signals in test_threadsignals.py. -signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGUSR1]) - -mode = os.environ["PYTHON_MODE"] -module = os.environ["PYTHON_MODULE"] -sys.argv[1:] = shlex.split(os.environ["PYTHON_ARGS"]) - -cwd = f"{sys.prefix}/cwd" -if not os.path.exists(cwd): - # Empty directories are lost in the asset packing/unpacking process. - os.mkdir(cwd) -os.chdir(cwd) - -if mode == "-c": - # In -c mode, sys.path starts with an empty string, which means whatever the current - # working directory is at the moment of each import. - sys.path.insert(0, "") - exec(module, {}) -elif mode == "-m": - sys.path.insert(0, os.getcwd()) - runpy.run_module(module, run_name="__main__", alter_sys=True) -else: - raise ValueError(f"unknown mode: {mode}") diff --git a/Apple/.ruff.toml b/Apple/.ruff.toml new file mode 100644 index 00000000000..4cdc39ebee4 --- /dev/null +++ b/Apple/.ruff.toml @@ -0,0 +1,22 @@ +extend = "../.ruff.toml" # Inherit the project-wide settings + +[format] +preview = true +docstring-code-format = true + +[lint] +select = [ + "C4", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "ISC", # flake8-implicit-str-concat + "LOG", # flake8-logging + "PGH", # pygrep-hooks + "PT", # flake8-pytest-style + "PYI", # flake8-pyi + "RUF100", # Ban unused `# noqa` comments + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 +] diff --git a/Apple/__main__.py b/Apple/__main__.py new file mode 100644 index 00000000000..256966e76c2 --- /dev/null +++ b/Apple/__main__.py @@ -0,0 +1,1065 @@ +#!/usr/bin/env python3 +########################################################################## +# Apple XCframework build script +# +# This script simplifies the process of configuring, compiling and packaging an +# XCframework for an Apple platform. +# +# At present, it only supports iOS, but it has been constructed so that it +# could be used on any Apple platform. +# +# The simplest entry point is: +# +# $ python Apple ci iOS +# +# which will: +# * Clean any pre-existing build artefacts +# * Configure and make a Python that can be used for the build +# * Configure and make a Python for each supported iOS architecture and ABI +# * Combine the outputs of the builds from the previous step into a single +# XCframework, merging binaries into a "fat" binary if necessary +# * Clone a copy of the testbed, configured to use the XCframework +# * Construct a tarball containing the release artefacts +# * Run the test suite using the generated XCframework. +# +# This is the complete sequence that would be needed in CI to build and test +# a candidate release artefact. +# +# Each individual step can be invoked individually - there are commands to +# clean, configure-build, make-build, configure-host, make-host, package, and +# test. +# +# There is also a build command that can be used to combine the configure and +# make steps for the build Python, an individual host, all hosts, or all +# builds. +########################################################################## +from __future__ import annotations + +import argparse +import os +import platform +import re +import shlex +import shutil +import signal +import subprocess +import sys +import sysconfig +import time +from collections.abc import Callable, Sequence +from contextlib import contextmanager +from datetime import datetime, timezone +from os.path import basename, relpath +from pathlib import Path +from subprocess import CalledProcessError + +EnvironmentT = dict[str, str] +ArgsT = Sequence[str | Path] + +SCRIPT_NAME = Path(__file__).name +PYTHON_DIR = Path(__file__).resolve().parent.parent + +CROSS_BUILD_DIR = PYTHON_DIR / "cross-build" + +HOSTS: dict[str, dict[str, dict[str, str]]] = { + # Structure of this data: + # * Platform identifier + # * an XCframework slice that must exist for that platform + # * a host triple: the multiarch spec for that host + "iOS": { + "ios-arm64": { + "arm64-apple-ios": "arm64-iphoneos", + }, + "ios-arm64_x86_64-simulator": { + "arm64-apple-ios-simulator": "arm64-iphonesimulator", + "x86_64-apple-ios-simulator": "x86_64-iphonesimulator", + }, + }, +} + + +def subdir(name: str, create: bool = False) -> Path: + """Ensure that a cross-build directory for the given name exists.""" + path = CROSS_BUILD_DIR / name + if not path.exists(): + if not create: + sys.exit( + f"{path} does not exist. Create it by running the appropriate " + f"`configure` subcommand of {SCRIPT_NAME}." + ) + else: + path.mkdir(parents=True) + return path + + +def run( + command: ArgsT, + *, + host: str | None = None, + env: EnvironmentT | None = None, + log: bool | None = True, + **kwargs, +) -> subprocess.CompletedProcess: + """Run a command in an Apple development environment. + + Optionally logs the executed command to the console. + """ + kwargs.setdefault("check", True) + if env is None: + env = os.environ.copy() + + if host: + host_env = apple_env(host) + print_env(host_env) + env.update(host_env) + + if log: + print(">", join_command(command)) + return subprocess.run(command, env=env, **kwargs) + + +def join_command(args: str | Path | ArgsT) -> str: + """Format a command so it can be copied into a shell. + + Similar to `shlex.join`, but also accepts arguments which are Paths, or a + single string/Path outside of a list. + """ + if isinstance(args, (str, Path)): + return str(args) + else: + return shlex.join(map(str, args)) + + +def print_env(env: EnvironmentT) -> None: + """Format the environment so it can be pasted into a shell.""" + for key, value in sorted(env.items()): + print(f"export {key}={shlex.quote(value)}") + + +def apple_env(host: str) -> EnvironmentT: + """Construct an Apple development environment for the given host.""" + env = { + "PATH": ":".join([ + str(PYTHON_DIR / "Apple/iOS/Resources/bin"), + str(subdir(host) / "prefix"), + "/usr/bin", + "/bin", + "/usr/sbin", + "/sbin", + "/Library/Apple/usr/bin", + ]), + } + + return env + + +def delete_path(name: str) -> None: + """Delete the named cross-build directory, if it exists.""" + path = CROSS_BUILD_DIR / name + if path.exists(): + print(f"Deleting {path} ...") + shutil.rmtree(path) + + +def all_host_triples(platform: str) -> list[str]: + """Return all host triples for the given platform. + + The host triples are the platform definitions used as input to configure + (e.g., "arm64-apple-ios-simulator"). + """ + triples = [] + for slice_name, slice_parts in HOSTS[platform].items(): + triples.extend(list(slice_parts)) + return triples + + +def clean(context: argparse.Namespace, target: str = "all") -> None: + """The implementation of the "clean" command.""" + # If we're explicitly targeting the build, there's no platform or + # distribution artefacts. If we're cleaning tests, we keep all built + # artefacts. Otherwise, the built artefacts must be dirty, so we remove + # them. + if target not in {"build", "test"}: + paths = ["dist", context.platform] + list(HOSTS[context.platform]) + else: + paths = [] + + if target in {"all", "build"}: + paths.append("build") + + if target in {"all", "hosts"}: + paths.extend(all_host_triples(context.platform)) + elif target not in {"build", "test", "package"}: + paths.append(target) + + if target in {"all", "hosts", "test"}: + paths.extend([ + path.name + for path in CROSS_BUILD_DIR.glob(f"{context.platform}-testbed.*") + ]) + + for path in paths: + delete_path(path) + + +def build_python_path() -> Path: + """The path to the build Python binary.""" + build_dir = subdir("build") + binary = build_dir / "python" + if not binary.is_file(): + binary = binary.with_suffix(".exe") + if not binary.is_file(): + raise FileNotFoundError( + f"Unable to find `python(.exe)` in {build_dir}" + ) + + return binary + + +@contextmanager +def group(text: str): + """A context manager that outputs a log marker around a section of a build. + + If running in a GitHub Actions environment, the GitHub syntax for + collapsible log sections is used. + """ + if "GITHUB_ACTIONS" in os.environ: + print(f"::group::{text}") + else: + print(f"===== {text} " + "=" * (70 - len(text))) + + yield + + if "GITHUB_ACTIONS" in os.environ: + print("::endgroup::") + else: + print() + + +@contextmanager +def cwd(subdir: Path): + """A context manager that sets the current working directory.""" + orig = os.getcwd() + os.chdir(subdir) + yield + os.chdir(orig) + + +def configure_build_python(context: argparse.Namespace) -> None: + """The implementation of the "configure-build" command.""" + if context.clean: + clean(context, "build") + + with ( + group("Configuring build Python"), + cwd(subdir("build", create=True)), + ): + command = [relpath(PYTHON_DIR / "configure")] + if context.args: + command.extend(context.args) + run(command) + + +def make_build_python(context: argparse.Namespace) -> None: + """The implementation of the "make-build" command.""" + with ( + group("Compiling build Python"), + cwd(subdir("build")), + ): + run(["make", "-j", str(os.cpu_count())]) + + +def apple_target(host: str) -> str: + """Return the Apple platform identifier for a given host triple.""" + for _, platform_slices in HOSTS.items(): + for slice_name, slice_parts in platform_slices.items(): + for host_triple, multiarch in slice_parts.items(): + if host == host_triple: + return ".".join(multiarch.split("-")[::-1]) + + raise KeyError(host) + + +def apple_multiarch(host: str) -> str: + """Return the multiarch descriptor for a given host triple.""" + for _, platform_slices in HOSTS.items(): + for slice_name, slice_parts in platform_slices.items(): + for host_triple, multiarch in slice_parts.items(): + if host == host_triple: + return multiarch + + raise KeyError(host) + + +def unpack_deps( + platform: str, + host: str, + prefix_dir: Path, + cache_dir: Path, +) -> None: + """Unpack binary dependencies into a provided directory. + + Downloads binaries if they aren't already present. Downloads will be stored + in provided cache directory. + + On iOS, as a safety mechanism, any dynamic libraries will be purged from + the unpacked dependencies. + """ + # To create new builds of these dependencies, usually all that's necessary + # is to push a tag to the cpython-apple-source-deps repository, and GitHub + # Actions will do the rest. + # + # If you're a member of the Python core team, and you'd like to be able to + # push these tags yourself, please contact Malcolm Smith or Russell + # Keith-Magee. + deps_url = "https://github.com/beeware/cpython-apple-source-deps/releases/download" + for name_ver in [ + "BZip2-1.0.8-2", + "libFFI-3.4.7-2", + "OpenSSL-3.0.18-1", + "XZ-5.6.4-2", + "mpdecimal-4.0.0-2", + "zstd-1.5.7-1", + ]: + filename = f"{name_ver.lower()}-{apple_target(host)}.tar.gz" + archive_path = download( + f"{deps_url}/{name_ver}/{filename}", + target_dir=cache_dir, + ) + shutil.unpack_archive(archive_path, prefix_dir) + + # Dynamic libraries will be preferentially linked over static; + # On iOS, ensure that no dylibs are available in the prefix folder. + if platform == "iOS": + for dylib in prefix_dir.glob("**/*.dylib"): + dylib.unlink() + + +def download(url: str, target_dir: Path) -> Path: + """Download the specified URL into the given directory. + + :return: The path to the downloaded archive. + """ + target_path = Path(target_dir).resolve() + target_path.mkdir(exist_ok=True, parents=True) + + out_path = target_path / basename(url) + if not Path(out_path).is_file(): + run([ + "curl", + "-Lf", + "--retry", + "5", + "--retry-all-errors", + "-o", + out_path, + url, + ]) + else: + print(f"Using cached version of {basename(url)}") + return out_path + + +def configure_host_python( + context: argparse.Namespace, + host: str | None = None, +) -> None: + """The implementation of the "configure-host" command.""" + if host is None: + host = context.host + + if context.clean: + clean(context, host) + + host_dir = subdir(host, create=True) + prefix_dir = host_dir / "prefix" + + with group(f"Downloading dependencies ({host})"): + if not prefix_dir.exists(): + prefix_dir.mkdir() + unpack_deps(context.platform, host, prefix_dir, context.cache_dir) + else: + print("Dependencies already installed") + + with ( + group(f"Configuring host Python ({host})"), + cwd(host_dir), + ): + command = [ + # Basic cross-compiling configuration + relpath(PYTHON_DIR / "configure"), + f"--host={host}", + f"--build={sysconfig.get_config_var('BUILD_GNU_TYPE')}", + f"--with-build-python={build_python_path()}", + "--with-system-libmpdec", + "--enable-framework", + # Dependent libraries. + f"--with-openssl={prefix_dir}", + f"LIBLZMA_CFLAGS=-I{prefix_dir}/include", + f"LIBLZMA_LIBS=-L{prefix_dir}/lib -llzma", + f"LIBFFI_CFLAGS=-I{prefix_dir}/include", + f"LIBFFI_LIBS=-L{prefix_dir}/lib -lffi", + f"LIBMPDEC_CFLAGS=-I{prefix_dir}/include", + f"LIBMPDEC_LIBS=-L{prefix_dir}/lib -lmpdec", + f"LIBZSTD_CFLAGS=-I{prefix_dir}/include", + f"LIBZSTD_LIBS=-L{prefix_dir}/lib -lzstd", + ] + + if context.args: + command.extend(context.args) + run(command, host=host) + + +def make_host_python( + context: argparse.Namespace, + host: str | None = None, +) -> None: + """The implementation of the "make-host" command.""" + if host is None: + host = context.host + + with ( + group(f"Compiling host Python ({host})"), + cwd(subdir(host)), + ): + run(["make", "-j", str(os.cpu_count())], host=host) + run(["make", "install"], host=host) + + +def framework_path(host_triple: str, multiarch: str) -> Path: + """The path to a built single-architecture framework product. + + :param host_triple: The host triple (e.g., arm64-apple-ios-simulator) + :param multiarch: The multiarch identifier (e.g., arm64-simulator) + """ + return CROSS_BUILD_DIR / f"{host_triple}/Apple/iOS/Frameworks/{multiarch}" + + +def package_version(prefix_path: Path) -> str: + """Extract the Python version being built from patchlevel.h.""" + for path in prefix_path.glob("**/patchlevel.h"): + text = path.read_text(encoding="utf-8") + if match := re.search( + r'\n\s*#define\s+PY_VERSION\s+"(.+)"\s*\n', text + ): + version = match[1] + # If not building against a tagged commit, add a timestamp to the + # version. Follow the PyPA version number rules, as this will make + # it easier to process with other tools. The version will have a + # `+` suffix once any official release has been made; a freshly + # forked main branch will have a version of 3.X.0a0. + if version.endswith("a0"): + version += "+" + if version.endswith("+"): + version += datetime.now(timezone.utc).strftime("%Y%m%d.%H%M%S") + + return version + + sys.exit("Unable to determine Python version being packaged.") + + +def lib_platform_files(dirname, names): + """A file filter that ignores platform-specific files in lib.""" + path = Path(dirname) + if ( + path.parts[-3] == "lib" + and path.parts[-2].startswith("python") + and path.parts[-1] == "lib-dynload" + ): + return names + elif path.parts[-2] == "lib" and path.parts[-1].startswith("python"): + ignored_names = { + name + for name in names + if ( + name.startswith("_sysconfigdata_") + or name.startswith("_sysconfig_vars_") + or name == "build-details.json" + ) + } + elif path.parts[-1] == "lib": + ignored_names = { + name + for name in names + if name.startswith("libpython") and name.endswith(".dylib") + } + else: + ignored_names = set() + + return ignored_names + + +def lib_non_platform_files(dirname, names): + """A file filter that ignores anything *except* platform-specific files + in the lib directory. + """ + path = Path(dirname) + if path.parts[-2] == "lib" and path.parts[-1].startswith("python"): + return ( + set(names) - lib_platform_files(dirname, names) - {"lib-dynload"} + ) + else: + return set() + + +def create_xcframework(platform: str) -> str: + """Build an XCframework from the component parts for the platform. + + :return: The version number of the Python version that was packaged. + """ + package_path = CROSS_BUILD_DIR / platform + try: + package_path.mkdir() + except FileExistsError: + raise RuntimeError( + f"{platform} XCframework already exists; do you need to run " + "with --clean?" + ) from None + + frameworks = [] + # Merge Frameworks for each component SDK. If there's only one architecture + # for the SDK, we can use the compiled Python.framework as-is. However, if + # there's more than architecture, we need to merge the individual built + # frameworks into a merged "fat" framework. + for slice_name, slice_parts in HOSTS[platform].items(): + # Some parts are the same across all slices, so we use can any of the + # host frameworks as the source for the merged version. Use the first + # one on the list, as it's as representative as any other. + first_host_triple, first_multiarch = next(iter(slice_parts.items())) + first_framework = ( + framework_path(first_host_triple, first_multiarch) + / "Python.framework" + ) + + if len(slice_parts) == 1: + # The first framework is the only framework, so copy it. + print(f"Copying framework for {slice_name}...") + frameworks.append(first_framework) + else: + print(f"Merging framework for {slice_name}...") + slice_path = CROSS_BUILD_DIR / slice_name + slice_framework = slice_path / "Python.framework" + slice_framework.mkdir(exist_ok=True, parents=True) + + # Copy the Info.plist + shutil.copy( + first_framework / "Info.plist", + slice_framework / "Info.plist", + ) + + # Copy the headers + shutil.copytree( + first_framework / "Headers", + slice_framework / "Headers", + ) + + # Create the "fat" library binary for the slice + run( + ["lipo", "-create", "-output", slice_framework / "Python"] + + [ + ( + framework_path(host_triple, multiarch) + / "Python.framework/Python" + ) + for host_triple, multiarch in slice_parts.items() + ] + ) + + # Add this merged slice to the list to be added to the XCframework + frameworks.append(slice_framework) + + print() + print("Build XCframework...") + cmd = [ + "xcodebuild", + "-create-xcframework", + "-output", + package_path / "Python.xcframework", + ] + for framework in frameworks: + cmd.extend(["-framework", framework]) + + run(cmd) + + # Extract the package version from the merged framework + version = package_version(package_path / "Python.xcframework") + version_tag = ".".join(version.split(".")[:2]) + + # On non-macOS platforms, each framework in XCframework only contains the + # headers, libPython, plus an Info.plist. Other resources like the standard + # library and binary shims aren't allowed to live in framework; they need + # to be copied in separately. + print() + print("Copy additional resources...") + has_common_stdlib = False + for slice_name, slice_parts in HOSTS[platform].items(): + # Some parts are the same across all slices, so we can any of the + # host frameworks as the source for the merged version. + first_host_triple, first_multiarch = next(iter(slice_parts.items())) + first_path = framework_path(first_host_triple, first_multiarch) + first_framework = first_path / "Python.framework" + + slice_path = package_path / f"Python.xcframework/{slice_name}" + slice_framework = slice_path / "Python.framework" + + # Copy the binary helpers + print(f" - {slice_name} binaries") + shutil.copytree(first_path / "bin", slice_path / "bin") + + # Copy the include path (a symlink to the framework headers) + print(f" - {slice_name} include files") + shutil.copytree( + first_path / "include", + slice_path / "include", + symlinks=True, + ) + + # Copy in the cross-architecture pyconfig.h + shutil.copy( + PYTHON_DIR / f"Apple/{platform}/Resources/pyconfig.h", + slice_framework / "Headers/pyconfig.h", + ) + + print(f" - {slice_name} shared library") + # Create a simlink for the fat library + shared_lib = slice_path / f"lib/libpython{version_tag}.dylib" + shared_lib.parent.mkdir() + shared_lib.symlink_to("../Python.framework/Python") + + print(f" - {slice_name} architecture-specific files") + for host_triple, multiarch in slice_parts.items(): + print(f" - {multiarch} standard library") + arch, _ = multiarch.split("-", 1) + + if not has_common_stdlib: + print(" - using this architecture as the common stdlib") + shutil.copytree( + framework_path(host_triple, multiarch) / "lib", + package_path / "Python.xcframework/lib", + ignore=lib_platform_files, + symlinks=True, + ) + has_common_stdlib = True + + shutil.copytree( + framework_path(host_triple, multiarch) / "lib", + slice_path / f"lib-{arch}", + ignore=lib_non_platform_files, + symlinks=True, + ) + + # Copy the host's pyconfig.h to an architecture-specific name. + arch = multiarch.split("-")[0] + host_path = ( + CROSS_BUILD_DIR + / host_triple + / "Apple/iOS/Frameworks" + / multiarch + ) + host_framework = host_path / "Python.framework" + shutil.copy( + host_framework / "Headers/pyconfig.h", + slice_framework / f"Headers/pyconfig-{arch}.h", + ) + + # Apple identifies certain libraries as "security risks"; if you + # statically link those libraries into a Framework, you become + # responsible for providing a privacy manifest for that framework. + xcprivacy_file = { + "OpenSSL": subdir(host_triple) + / "prefix/share/OpenSSL.xcprivacy" + } + print(f" - {multiarch} xcprivacy files") + for module, lib in [ + ("_hashlib", "OpenSSL"), + ("_ssl", "OpenSSL"), + ]: + shutil.copy( + xcprivacy_file[lib], + slice_path + / f"lib-{arch}/python{version_tag}" + / f"lib-dynload/{module}.xcprivacy", + ) + + print(" - build tools") + shutil.copytree( + PYTHON_DIR / "Apple/testbed/Python.xcframework/build", + package_path / "Python.xcframework/build", + ) + + return version + + +def package(context: argparse.Namespace) -> None: + """The implementation of the "package" command.""" + if context.clean: + clean(context, "package") + + with group("Building package"): + # Create an XCframework + version = create_xcframework(context.platform) + + # Clone testbed + print() + run([ + sys.executable, + "Apple/testbed", + "clone", + "--platform", + context.platform, + "--framework", + CROSS_BUILD_DIR / context.platform / "Python.xcframework", + CROSS_BUILD_DIR / context.platform / "testbed", + ]) + + # Build the final archive + archive_name = ( + CROSS_BUILD_DIR + / "dist" + / f"python-{version}-{context.platform}-XCframework" + ) + + print() + print("Create package archive...") + shutil.make_archive( + str(CROSS_BUILD_DIR / archive_name), + format="gztar", + root_dir=CROSS_BUILD_DIR / context.platform, + base_dir=".", + ) + print() + print(f"{archive_name.relative_to(PYTHON_DIR)}.tar.gz created.") + + +def build(context: argparse.Namespace, host: str | None = None) -> None: + """The implementation of the "build" command.""" + if host is None: + host = context.host + + if context.clean: + clean(context, host) + + if host in {"all", "build"}: + for step in [ + configure_build_python, + make_build_python, + ]: + step(context) + + if host == "build": + hosts = [] + elif host in {"all", "hosts"}: + hosts = all_host_triples(context.platform) + else: + hosts = [host] + + for step_host in hosts: + for step in [ + configure_host_python, + make_host_python, + ]: + step(context, host=step_host) + + if host in {"all", "hosts"}: + package(context) + + +def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa: PT028 + """The implementation of the "test" command.""" + if host is None: + host = context.host + + if context.clean: + clean(context, "test") + + with group(f"Test {'XCframework' if host in {'all', 'hosts'} else host}"): + timestamp = str(time.time_ns())[:-6] + testbed_dir = ( + CROSS_BUILD_DIR / f"{context.platform}-testbed.{timestamp}" + ) + if host in {"all", "hosts"}: + framework_path = ( + CROSS_BUILD_DIR / context.platform / "Python.xcframework" + ) + else: + build_arch = platform.machine() + host_arch = host.split("-")[0] + + if not host.endswith("-simulator"): + print("Skipping test suite non-simulator build.") + return + elif build_arch != host_arch: + print( + f"Skipping test suite for an {host_arch} build " + f"on an {build_arch} machine." + ) + return + else: + framework_path = ( + CROSS_BUILD_DIR + / host + / f"Apple/{context.platform}" + / f"Frameworks/{apple_multiarch(host)}" + ) + + run([ + sys.executable, + "Apple/testbed", + "clone", + "--platform", + context.platform, + "--framework", + framework_path, + testbed_dir, + ]) + + run( + [ + sys.executable, + testbed_dir, + "run", + "--verbose", + ] + + ( + ["--simulator", str(context.simulator)] + if context.simulator + else [] + ) + + [ + "--", + "test", + f"--{context.ci_mode}-ci", + "--single-process", + "--no-randomize", + # Timeout handling requires subprocesses; explicitly setting + # the timeout to -1 disables the faulthandler. + "--timeout=-1", + # Adding Python options requires the use of a subprocess to + # start a new Python interpreter. + "--dont-add-python-opts", + ] + ) + + +def apple_sim_host(platform_name: str) -> str: + """Determine the native simulator target for this platform.""" + for _, slice_parts in HOSTS[platform_name].items(): + for host_triple in slice_parts: + parts = host_triple.split("-") + if parts[0] == platform.machine() and parts[-1] == "simulator": + return host_triple + + raise KeyError(platform_name) + + +def ci(context: argparse.Namespace) -> None: + """The implementation of the "ci" command. + + In "Fast" mode, this compiles the build python, and the simulator for the + build machine's architecture; and runs the test suite with `--fast-ci` + configuration. + + In "Slow" mode, it compiles the build python, plus all candidate + architectures (both device and simulator); then runs the test suite with + `--slow-ci` configuration. + """ + clean(context, "all") + if context.ci_mode == "slow": + # In slow mode, build and test the full XCframework + build(context, host="all") + test(context, host="all") + else: + # In fast mode, just build the simulator platform. + sim_host = apple_sim_host(context.platform) + build(context, host="build") + build(context, host=sim_host) + test(context, host=sim_host) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description=( + "A tool for managing the build, package and test process of " + "CPython on Apple platforms." + ), + ) + parser.suggest_on_error = True + subcommands = parser.add_subparsers(dest="subcommand", required=True) + + clean = subcommands.add_parser( + "clean", + help="Delete all build directories", + ) + + configure_build = subcommands.add_parser( + "configure-build", help="Run `configure` for the build Python" + ) + subcommands.add_parser( + "make-build", help="Run `make` for the build Python" + ) + configure_host = subcommands.add_parser( + "configure-host", + help="Run `configure` for a specific platform and target", + ) + make_host = subcommands.add_parser( + "make-host", + help="Run `make` for a specific platform and target", + ) + package = subcommands.add_parser( + "package", + help="Create a release package for the platform", + ) + build = subcommands.add_parser( + "build", + help="Build all platform targets and create the XCframework", + ) + test = subcommands.add_parser( + "test", + help="Run the testbed for a specific platform", + ) + ci = subcommands.add_parser( + "ci", + help="Run build, package, and test", + ) + + # platform argument + for cmd in [clean, configure_host, make_host, package, build, test, ci]: + cmd.add_argument( + "platform", + choices=HOSTS.keys(), + help="The target platform to build", + ) + + # host triple argument + for cmd in [configure_host, make_host]: + cmd.add_argument( + "host", + help="The host triple to build (e.g., arm64-apple-ios-simulator)", + ) + # optional host triple argument + for cmd in [clean, build, test]: + cmd.add_argument( + "host", + nargs="?", + default="all", + help=( + "The host triple to build (e.g., arm64-apple-ios-simulator), " + "or 'build' for just the build platform, or 'hosts' for all " + "host platforms, or 'all' for the build platform and all " + "hosts. Defaults to 'all'" + ), + ) + + # --clean option + for cmd in [configure_build, configure_host, build, package, test, ci]: + cmd.add_argument( + "--clean", + action="store_true", + default=False, + dest="clean", + help="Delete the relevant build directories first", + ) + + # --cache-dir option + for cmd in [configure_host, build, ci]: + cmd.add_argument( + "--cache-dir", + default="./cross-build/downloads", + help="The directory to store cached downloads.", + ) + + # --simulator option + for cmd in [test, ci]: + cmd.add_argument( + "--simulator", + help=( + "The name of the simulator to use (eg: 'iPhone 16e'). " + "Defaults to the most recently released 'entry level' " + "iPhone device. Device architecture and OS version can also " + "be specified; e.g., " + "`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would " + "run on an ARM64 iPhone 16 Pro simulator running iOS 26.0." + ), + ) + group = cmd.add_mutually_exclusive_group() + group.add_argument( + "--fast-ci", + action="store_const", + dest="ci_mode", + const="fast", + help="Add test arguments for GitHub Actions", + ) + group.add_argument( + "--slow-ci", + action="store_const", + dest="ci_mode", + const="slow", + help="Add test arguments for buildbots", + ) + + for subcommand in [configure_build, configure_host, build, ci]: + subcommand.add_argument( + "args", nargs="*", help="Extra arguments to pass to `configure`" + ) + + return parser.parse_args() + + +def print_called_process_error(e: subprocess.CalledProcessError) -> None: + for stream_name in ["stdout", "stderr"]: + content = getattr(e, stream_name) + stream = getattr(sys, stream_name) + if content: + stream.write(content) + if not content.endswith("\n"): + stream.write("\n") + + # shlex uses single quotes, so we surround the command with double quotes. + print( + f'Command "{join_command(e.cmd)}" returned exit status {e.returncode}' + ) + + +def main() -> None: + # Handle SIGTERM the same way as SIGINT. This ensures that if we're + # terminated by the buildbot worker, we'll make an attempt to clean up our + # subprocesses. + def signal_handler(*args): + os.kill(os.getpid(), signal.SIGINT) + + signal.signal(signal.SIGTERM, signal_handler) + + # Process command line arguments + context = parse_args() + dispatch: dict[str, Callable] = { + "clean": clean, + "configure-build": configure_build_python, + "make-build": make_build_python, + "configure-host": configure_host_python, + "make-host": make_host_python, + "package": package, + "build": build, + "test": test, + "ci": ci, + } + + try: + dispatch[context.subcommand](context) + except CalledProcessError as e: + print() + print_called_process_error(e) + sys.exit(1) + except RuntimeError as e: + print() + print(e) + sys.exit(2) + + +if __name__ == "__main__": + # Under the buildbot, stdout is not a TTY, but we must still flush after + # every line to make sure our output appears in the correct order relative + # to the output of our subprocesses. + for stream in [sys.stdout, sys.stderr]: + stream.reconfigure(line_buffering=True) + + main() diff --git a/Apple/iOS/README.md b/Apple/iOS/README.md new file mode 100644 index 00000000000..7ee257b5d64 --- /dev/null +++ b/Apple/iOS/README.md @@ -0,0 +1,339 @@ +# Python on iOS README + +**iOS support is [tier 3](https://peps.python.org/pep-0011/#tier-3).** + +This document provides a quick overview of some iOS specific features in the +Python distribution. + +These instructions are only needed if you're planning to compile Python for iOS +yourself. Most users should *not* need to do this. If you're looking to +experiment with writing an iOS app in Python, tools such as [BeeWare's +Briefcase](https://briefcase.readthedocs.io) and [Kivy's +Buildozer](https://buildozer.readthedocs.io) will provide a much more +approachable user experience. + +## Compilers for building on iOS + +Building for iOS requires the use of Apple's Xcode tooling. It is strongly +recommended that you use the most recent stable release of Xcode. This will +require the use of the most (or second-most) recently released macOS version, +as Apple does not maintain Xcode for older macOS versions. The Xcode Command +Line Tools are not sufficient for iOS development; you need a *full* Xcode +install. + +If you want to run your code on the iOS simulator, you'll also need to install +an iOS Simulator Platform. You should be prompted to select an iOS Simulator +Platform when you first run Xcode. Alternatively, you can add an iOS Simulator +Platform by selecting an open the Platforms tab of the Xcode Settings panel. + +## Building Python on iOS + +### ABIs and Architectures + +iOS apps can be deployed on physical devices, and on the iOS simulator. Although +the API used on these devices is identical, the ABI is different - you need to +link against different libraries for an iOS device build (`iphoneos`) or an +iOS simulator build (`iphonesimulator`). + +Apple uses the `XCframework` format to allow specifying a single dependency +that supports multiple ABIs. An `XCframework` is a wrapper around multiple +ABI-specific frameworks that share a common API. + +iOS can also support different CPU architectures within each ABI. At present, +there is only a single supported architecture on physical devices - ARM64. +However, the *simulator* supports 2 architectures - ARM64 (for running on Apple +Silicon machines), and x86_64 (for running on older Intel-based machines). + +To support multiple CPU architectures on a single platform, Apple uses a "fat +binary" format - a single physical file that contains support for multiple +architectures. It is possible to compile and use a "thin" single architecture +version of a binary for testing purposes; however, the "thin" binary will not be +portable to machines using other architectures. + +### Building a multi-architecture iOS XCframework + +The `Apple` subfolder of the Python repository acts as a build script that +can be used to coordinate the compilation of a complete iOS XCframework. To use +it, run:: + + python Apple build iOS + +This will: + +* Configure and compile a version of Python to run on the build machine +* Download pre-compiled binary dependencies for each platform +* Configure and build a `Python.framework` for each required architecture and + iOS SDK +* Merge the multiple `Python.framework` folders into a single `Python.xcframework` +* Produce a `.tar.gz` archive in the `cross-build/dist` folder containing + the `Python.xcframework`, plus a copy of the Testbed app pre-configured to + use the XCframework. + +The `Apple` build script has other entry points that will perform the +individual parts of the overall `build` target, plus targets to test the +build, clean the `cross-build` folder of iOS build products, and perform a +complete "build and test" CI run. The `--clean` flag can also be used on +individual commands to ensure that a stale build product are removed before +building. + +### Building a single-architecture framework + +If you're using the `Apple` build script, you won't need to build +individual frameworks. However, if you do need to manually configure an iOS +Python build for a single framework, the following options are available. + +#### iOS specific arguments to configure + +* `--enable-framework[=DIR]` + + This argument specifies the location where the Python.framework will be + installed. If `DIR` is not specified, the framework will be installed into + a subdirectory of the `iOS/Frameworks` folder. + + This argument *must* be provided when configuring iOS builds. iOS does not + support non-framework builds. + +* `--with-framework-name=NAME` + + Specify the name for the Python framework; defaults to `Python`. + + > [!NOTE] + > Unless you know what you're doing, changing the name of the Python + > framework on iOS is not advised. If you use this option, you won't be able + > to run the `Apple` build script without making significant manual + > alterations, and you won't be able to use any binary packages unless you + > compile them yourself using your own framework name. + +#### Building Python for iOS + +The Python build system will create a `Python.framework` that supports a +*single* ABI with a *single* architecture. Unlike macOS, iOS does not allow a +framework to contain non-library content, so the iOS build will produce a +`bin` and `lib` folder in the same output folder as `Python.framework`. +The `lib` folder will be needed at runtime to support the Python library. + +If you want to use Python in a real iOS project, you need to produce multiple +`Python.framework` builds, one for each ABI and architecture. iOS builds of +Python *must* be constructed as framework builds. To support this, you must +provide the `--enable-framework` flag when configuring the build. The build +also requires the use of cross-compilation. The minimal commands for building +Python for the ARM64 iOS simulator will look something like: +``` +export PATH="$(pwd)/Apple/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" +./configure \ + --enable-framework \ + --host=arm64-apple-ios-simulator \ + --build=arm64-apple-darwin \ + --with-build-python=/path/to/python.exe +make +make install +``` + +In this invocation: + +* `Apple/iOS/Resources/bin` has been added to the path, providing some shims for the + compilers and linkers needed by the build. Xcode requires the use of `xcrun` + to invoke compiler tooling. However, if `xcrun` is pre-evaluated and the + result passed to `configure`, these results can embed user- and + version-specific paths into the sysconfig data, which limits the portability + of the compiled Python. Alternatively, if `xcrun` is used *as* the compiler, + it requires that compiler variables like `CC` include spaces, which can + cause significant problems with many C configuration systems which assume that + `CC` will be a single executable. + + To work around this problem, the `Apple/iOS/Resources/bin` folder contains some + wrapper scripts that present as simple compilers and linkers, but wrap + underlying calls to `xcrun`. This allows configure to use a `CC` + definition without spaces, and without user- or version-specific paths, while + retaining the ability to adapt to the local Xcode install. These scripts are + included in the `bin` directory of an iOS install. + + These scripts will, by default, use the currently active Xcode installation. + If you want to use a different Xcode installation, you can use + `xcode-select` to set a new default Xcode globally, or you can use the + `DEVELOPER_DIR` environment variable to specify an Xcode install. The + scripts will use the default `iphoneos`/`iphonesimulator` SDK version for + the select Xcode install; if you want to use a different SDK, you can set the + `IOS_SDK_VERSION` environment variable. (e.g, setting + `IOS_SDK_VERSION=17.1` would cause the scripts to use the `iphoneos17.1` + and `iphonesimulator17.1` SDKs, regardless of the Xcode default.) + + The path has also been cleared of any user customizations. A common source of + bugs is for tools like Homebrew to accidentally leak macOS binaries into an iOS + build. Resetting the path to a known "bare bones" value is the easiest way to + avoid these problems. + +* `--host` is the architecture and ABI that you want to build, in GNU compiler + triple format. This will be one of: + + - `arm64-apple-ios` for ARM64 iOS devices. + - `arm64-apple-ios-simulator` for the iOS simulator running on Apple + Silicon devices. + - `x86_64-apple-ios-simulator` for the iOS simulator running on Intel + devices. + +* `--build` is the GNU compiler triple for the machine that will be running + the compiler. This is one of: + + - `arm64-apple-darwin` for Apple Silicon devices. + - `x86_64-apple-darwin` for Intel devices. + +* `/path/to/python.exe` is the path to a Python binary on the machine that + will be running the compiler. This is needed because the Python compilation + process involves running some Python code. On a normal desktop build of + Python, you can compile a python interpreter and then use that interpreter to + run Python code. However, the binaries produced for iOS won't run on macOS, so + you need to provide an external Python interpreter. This interpreter must be + the same version as the Python that is being compiled. To be completely safe, + this should be the *exact* same commit hash. However, the longer a Python + release has been stable, the more likely it is that this constraint can be + relaxed - the same micro version will often be sufficient. + +* The `install` target for iOS builds is slightly different to other + platforms. On most platforms, `make install` will install the build into + the final runtime location. This won't be the case for iOS, as the final + runtime location will be on a physical device. + + However, you still need to run the `install` target for iOS builds, as it + performs some final framework assembly steps. The location specified with + `--enable-framework` will be the location where `make install` will + assemble the complete iOS framework. This completed framework can then + be copied and relocated as required. + +For a full CPython build, you also need to specify the paths to iOS builds of +the binary libraries that CPython depends on (such as XZ, LibFFI and OpenSSL). +This can be done by defining library specific environment variables (such as +`LIBLZMA_CFLAGS`, `LIBLZMA_LIBS`), and the `--with-openssl` configure +option. Versions of these libraries pre-compiled for iOS can be found in [this +repository](https://github.com/beeware/cpython-apple-source-deps/releases). +LibFFI is especially important, as many parts of the standard library +(including the `platform`, `sysconfig` and `webbrowser` modules) require +the use of the `ctypes` module at runtime. + +By default, Python will be compiled with an iOS deployment target (i.e., the +minimum supported iOS version) of 13.0. To specify a different deployment +target, provide the version number as part of the `--host` argument - for +example, `--host=arm64-apple-ios15.4-simulator` would compile an ARM64 +simulator build with a deployment target of 15.4. + +## Testing Python on iOS + +### Testing a multi-architecture framework + +Once you have a built an XCframework, you can test that framework by running: + + $ python Apple test iOS + +This test will attempt to find an "SE-class" simulator (i.e., an iPhone SE, or +iPhone 16e, or similar), and run the test suite on the most recent version of +iOS that is available. You can specify a simulator using the `--simulator` +command line argument, providing the name of the simulator (e.g., `--simulator +'iPhone 16 Pro'`). You can also use this argument to control the OS version used +for testing; `--simulator 'iPhone 16 Pro,OS=18.2'` would attempt to run the +tests on an iPhone 16 Pro running iOS 18.2. + +If the test runner is executed on GitHub Actions, the `GITHUB_ACTIONS` +environment variable will be exposed to the iOS process at runtime. + +### Testing a single-architecture framework + +The `Apple/testbed` folder that contains an Xcode project that is able to run +the Python test suite on Apple platforms. This project converts the Python test +suite into a single test case in Xcode's XCTest framework. The single XCTest +passes if the test suite passes. + +To run the test suite, configure a Python build for an iOS simulator (i.e., +`--host=arm64-apple-ios-simulator` or `--host=x86_64-apple-ios-simulator` +), specifying a framework build (i.e. `--enable-framework`). Ensure that your +`PATH` has been configured to include the `Apple/iOS/Resources/bin` folder and +exclude any non-iOS tools, then run: +``` +make all +make install +make testios +``` + +This will: + +* Build an iOS framework for your chosen architecture; +* Finalize the single-platform framework; +* Make a clean copy of the testbed project; +* Install the Python iOS framework into the copy of the testbed project; and +* Run the test suite on an "entry-level device" simulator (i.e., an iPhone SE, + iPhone 16e, or a similar). + +On success, the test suite will exit and report successful completion of the +test suite. On a 2022 M1 MacBook Pro, the test suite takes approximately 15 +minutes to run; a couple of extra minutes is required to compile the testbed +project, and then boot and prepare the iOS simulator. + +### Debugging test failures + +Running `python Apple test iOS` generates a standalone version of the +`Apple/testbed` project, and runs the full test suite. It does this using +`Apple/testbed` itself - the folder is an executable module that can be used +to create and run a clone of the testbed project. The standalone version of the +testbed will be created in a directory named +`cross-build/iOS-testbed.`. + +You can generate your own standalone testbed instance by running: +``` +python cross-build/iOS/testbed clone my-testbed +``` + +In this invocation, `my-testbed` is the name of the folder for the new +testbed clone. + +If you've built your own XCframework, or you only want to test a single architecture, +you can construct a standalone testbed instance by running: +``` +python Apple/testbed clone --platform iOS --framework my-testbed +``` + +The framework path can be the path path to a `Python.xcframework`, or the +path to a folder that contains a single-platform `Python.framework`. + +You can then use the `my-testbed` folder to run the Python test suite, +passing in any command line arguments you may require. For example, if you're +trying to diagnose a failure in the `os` module, you might run: +``` +python my-testbed run -- test -W test_os +``` + +This is the equivalent of running `python -m test -W test_os` on a desktop +Python build. Any arguments after the `--` will be passed to testbed as if +they were arguments to `python -m` on a desktop machine. + +### Testing in Xcode + +You can also open the testbed project in Xcode by running: +``` +open my-testbed/iOSTestbed.xcodeproj +``` + +This will allow you to use the full Xcode suite of tools for debugging. + +The arguments used to run the test suite are defined as part of the test plan. +To modify the test plan, select the test plan node of the project tree (it +should be the first child of the root node), and select the "Configurations" +tab. Modify the "Arguments Passed On Launch" value to change the testing +arguments. + +The test plan also disables parallel testing, and specifies the use of the +`Testbed.lldbinit` file for providing configuration of the debugger. The +default debugger configuration disables automatic breakpoints on the +`SIGINT`, `SIGUSR1`, `SIGUSR2`, and `SIGXFSZ` signals. + +### Testing on an iOS device + +To test on an iOS device, the app needs to be signed with known developer +credentials. To obtain these credentials, you must have an iOS Developer +account, and your Xcode install will need to be logged into your account (see +the Accounts tab of the Preferences dialog). + +Once the project is open, and you're signed into your Apple Developer account, +select the root node of the project tree (labeled "iOSTestbed"), then the +"Signing & Capabilities" tab in the details page. Select a development team +(this will likely be your own name), and plug in a physical device to your +macOS machine with a USB cable. You should then be able to select your physical +device from the list of targets in the pulldown in the Xcode titlebar. diff --git a/iOS/Resources/Info.plist.in b/Apple/iOS/Resources/Info.plist.in similarity index 100% rename from iOS/Resources/Info.plist.in rename to Apple/iOS/Resources/Info.plist.in diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-ar b/Apple/iOS/Resources/bin/arm64-apple-ios-ar new file mode 100755 index 00000000000..3cf3eb21874 --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-ar @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} ar "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-clang b/Apple/iOS/Resources/bin/arm64-apple-ios-clang new file mode 100755 index 00000000000..f50d5b5142f --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-clang @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET} "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-clang++ b/Apple/iOS/Resources/bin/arm64-apple-ios-clang++ new file mode 100755 index 00000000000..0794731d7dc --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-clang++ @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} clang++ -target arm64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET} "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-cpp b/Apple/iOS/Resources/bin/arm64-apple-ios-cpp new file mode 100755 index 00000000000..24fa1506bab --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-cpp @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET} -E "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-ar b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-ar new file mode 100755 index 00000000000..b836b6db902 --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-clang b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-clang new file mode 100755 index 00000000000..4891a00876e --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET}-simulator "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-clang++ b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-clang++ new file mode 100755 index 00000000000..58b2a5f6f18 --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-clang++ @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang++ -target arm64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET}-simulator "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-cpp b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-cpp new file mode 100755 index 00000000000..c9df94e8b7c --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET}-simulator -E "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-strip b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-strip new file mode 100755 index 00000000000..fd59d309b73 --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-simulator-strip @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} strip -arch arm64 "$@" diff --git a/Apple/iOS/Resources/bin/arm64-apple-ios-strip b/Apple/iOS/Resources/bin/arm64-apple-ios-strip new file mode 100755 index 00000000000..75e823a3d02 --- /dev/null +++ b/Apple/iOS/Resources/bin/arm64-apple-ios-strip @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} strip -arch arm64 "$@" diff --git a/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-ar b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-ar new file mode 100755 index 00000000000..b836b6db902 --- /dev/null +++ b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar "$@" diff --git a/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-clang b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-clang new file mode 100755 index 00000000000..f4739a7b945 --- /dev/null +++ b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET}-simulator "$@" diff --git a/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-clang++ b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-clang++ new file mode 100755 index 00000000000..c348ae4c103 --- /dev/null +++ b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-clang++ @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang++ -target x86_64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET}-simulator "$@" diff --git a/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp new file mode 100755 index 00000000000..6d7f8084c9f --- /dev/null +++ b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios${IPHONEOS_DEPLOYMENT_TARGET}-simulator -E "$@" diff --git a/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-strip b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-strip new file mode 100755 index 00000000000..c5cfb289291 --- /dev/null +++ b/Apple/iOS/Resources/bin/x86_64-apple-ios-simulator-strip @@ -0,0 +1,2 @@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} strip -arch x86_64 "$@" diff --git a/iOS/Resources/pyconfig.h b/Apple/iOS/Resources/pyconfig.h similarity index 100% rename from iOS/Resources/pyconfig.h rename to Apple/iOS/Resources/pyconfig.h diff --git a/iOS/testbed/Python.xcframework/Info.plist b/Apple/testbed/Python.xcframework/Info.plist similarity index 100% rename from iOS/testbed/Python.xcframework/Info.plist rename to Apple/testbed/Python.xcframework/Info.plist diff --git a/iOS/Resources/dylib-Info-template.plist b/Apple/testbed/Python.xcframework/build/iOS-dylib-Info-template.plist similarity index 96% rename from iOS/Resources/dylib-Info-template.plist rename to Apple/testbed/Python.xcframework/build/iOS-dylib-Info-template.plist index f652e272f71..d6caa01c1e4 100644 --- a/iOS/Resources/dylib-Info-template.plist +++ b/Apple/testbed/Python.xcframework/build/iOS-dylib-Info-template.plist @@ -19,7 +19,7 @@ iPhoneOS MinimumOSVersion - 12.0 + 13.0 CFBundleVersion 1 diff --git a/Apple/testbed/Python.xcframework/build/utils.sh b/Apple/testbed/Python.xcframework/build/utils.sh new file mode 100755 index 00000000000..e7155d8b30e --- /dev/null +++ b/Apple/testbed/Python.xcframework/build/utils.sh @@ -0,0 +1,151 @@ +# Utility methods for use in an Xcode project. +# +# An iOS XCframework cannot include any content other than the library binary +# and relevant metadata. However, Python requires a standard library at runtime. +# Therefore, it is necessary to add a build step to an Xcode app target that +# processes the standard library and puts the content into the final app. +# +# In general, these tools will be invoked after bundle resources have been +# copied into the app, but before framework embedding (and signing). +# +# The following is an example script, assuming that: +# * Python.xcframework is in the root of the project +# * There is an `app` folder that contains the app code +# * There is an `app_packages` folder that contains installed Python packages. +# ----- +# set -e +# source $PROJECT_DIR/Python.xcframework/build/build_utils.sh +# install_python Python.xcframework app app_packages +# ----- + +# Copy the standard library from the XCframework into the app bundle. +# +# Accepts one argument: +# 1. The path, relative to the root of the Xcode project, where the Python +# XCframework can be found. +install_stdlib() { + PYTHON_XCFRAMEWORK_PATH=$1 + + mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib" + if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then + echo "Installing Python modules for iOS Simulator" + if [ -d "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/ios-arm64-simulator" ]; then + SLICE_FOLDER="ios-arm64-simulator" + else + SLICE_FOLDER="ios-arm64_x86_64-simulator" + fi + else + echo "Installing Python modules for iOS Device" + SLICE_FOLDER="ios-arm64" + fi + + # If the XCframework has a shared lib folder, then it's a full framework. + # Copy both the common and slice-specific part of the lib directory. + # Otherwise, it's a single-arch framework; use the "full" lib folder. + if [ -d "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/lib" ]; then + rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" + rsync -au "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib-$ARCHS/" "$CODESIGNING_FOLDER_PATH/python/lib/" + else + # A single-arch framework will have a libpython symlink; that can't be included at runtime + rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" --exclude 'libpython*.dylib' + fi +} + +# Convert a single .so library into a framework that iOS can load. +# +# Accepts three arguments: +# 1. The path, relative to the root of the Xcode project, where the Python +# XCframework can be found. +# 2. The base path, relative to the installed location in the app bundle, that +# needs to be processed. Any .so file found in this path (or a subdirectory +# of it) will be processed. +# 2. The full path to a single .so file to process. This path should include +# the base path. +install_dylib () { + PYTHON_XCFRAMEWORK_PATH=$1 + INSTALL_BASE=$2 + FULL_EXT=$3 + + # The name of the extension file + EXT=$(basename "$FULL_EXT") + # The name and location of the module + MODULE_PATH=$(dirname "$FULL_EXT") + MODULE_NAME=$(echo $EXT | cut -d "." -f 1) + # The location of the extension file, relative to the bundle + RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} + # The path to the extension file, relative to the install base + PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/} + # The full dotted name of the extension module, constructed from the file path. + FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d "." -f 1 | tr "/" "."); + # A bundle identifier; not actually used, but required by Xcode framework packaging + FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-") + # The name of the framework folder. + FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework" + + # If the framework folder doesn't exist, create it. + if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then + echo "Creating framework for $RELATIVE_EXT" + mkdir -p "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" + cp "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/build/$PLATFORM_FAMILY_NAME-dylib-Info-template.plist" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" + plutil -replace CFBundleExecutable -string "$FULL_MODULE_NAME" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" + plutil -replace CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" + fi + + echo "Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME" + mv "$FULL_EXT" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME" + # Create a placeholder .fwork file where the .so was + echo "$FRAMEWORK_FOLDER/$FULL_MODULE_NAME" > ${FULL_EXT%.so}.fwork + # Create a back reference to the .so file location in the framework + echo "${RELATIVE_EXT%.so}.fwork" > "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin" + + # If the framework provides an xcprivacy file, install it. + if [ -e "$MODULE_PATH/$MODULE_NAME.xcprivacy" ]; then + echo "Installing XCPrivacy file for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME" + XCPRIVACY_FILE="$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/PrivacyInfo.xcprivacy" + if [ -e "$XCPRIVACY_FILE" ]; then + rm -rf "$XCPRIVACY_FILE" + fi + mv "$MODULE_PATH/$MODULE_NAME.xcprivacy" "$XCPRIVACY_FILE" + fi + + echo "Signing framework as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)..." + /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" +} + +# Process all the dynamic libraries in a path into Framework format. +# +# Accepts two arguments: +# 1. The path, relative to the root of the Xcode project, where the Python +# XCframework can be found. +# 2. The base path, relative to the installed location in the app bundle, that +# needs to be processed. Any .so file found in this path (or a subdirectory +# of it) will be processed. +process_dylibs () { + PYTHON_XCFRAMEWORK_PATH=$1 + LIB_PATH=$2 + find "$CODESIGNING_FOLDER_PATH/$LIB_PATH" -name "*.so" | while read FULL_EXT; do + install_dylib $PYTHON_XCFRAMEWORK_PATH "$LIB_PATH/" "$FULL_EXT" + done +} + +# The entry point for post-processing a Python XCframework. +# +# Accepts 1 or more arguments: +# 1. The path, relative to the root of the Xcode project, where the Python +# XCframework can be found. If the XCframework is in the root of the project, +# 2+. The path of a package, relative to the root of the packaged app, that contains +# library content that should be processed for binary libraries. +install_python() { + PYTHON_XCFRAMEWORK_PATH=$1 + shift + + install_stdlib $PYTHON_XCFRAMEWORK_PATH + PYTHON_VER=$(ls -1 "$CODESIGNING_FOLDER_PATH/python/lib") + echo "Install Python $PYTHON_VER standard library extension modules..." + process_dylibs $PYTHON_XCFRAMEWORK_PATH python/lib/$PYTHON_VER/lib-dynload + + for package_path in $@; do + echo "Installing $package_path extension modules ..." + process_dylibs $PYTHON_XCFRAMEWORK_PATH $package_path + done +} diff --git a/iOS/testbed/Python.xcframework/ios-arm64/README b/Apple/testbed/Python.xcframework/ios-arm64/README similarity index 100% rename from iOS/testbed/Python.xcframework/ios-arm64/README rename to Apple/testbed/Python.xcframework/ios-arm64/README diff --git a/iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README b/Apple/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README similarity index 100% rename from iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README rename to Apple/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README diff --git a/iOS/testbed/iOSTestbed.lldbinit b/Apple/testbed/Testbed.lldbinit similarity index 100% rename from iOS/testbed/iOSTestbed.lldbinit rename to Apple/testbed/Testbed.lldbinit diff --git a/iOS/testbed/iOSTestbedTests/iOSTestbedTests.m b/Apple/testbed/TestbedTests/TestbedTests.m similarity index 96% rename from iOS/testbed/iOSTestbedTests/iOSTestbedTests.m rename to Apple/testbed/TestbedTests/TestbedTests.m index d3159f5c2e1..f7788c47f2c 100644 --- a/iOS/testbed/iOSTestbedTests/iOSTestbedTests.m +++ b/Apple/testbed/TestbedTests/TestbedTests.m @@ -1,11 +1,11 @@ #import #import -@interface iOSTestbedTests : XCTestCase +@interface TestbedTests : XCTestCase @end -@implementation iOSTestbedTests +@implementation TestbedTests - (void)testPython { @@ -35,20 +35,23 @@ setenv("NO_COLOR", "1", true); setenv("PYTHON_COLORS", "0", true); + if (getenv("GITHUB_ACTIONS")) { + NSLog(@"Running in a GitHub Actions environment"); + } // Arguments to pass into the test suite runner. // argv[0] must identify the process; any subsequent arg // will be handled as if it were an argument to `python -m test` // The processInfo arguments contain the binary that is running, // followed by the arguments defined in the test plan. This means: // run_module = test_args[1] - // argv = ["iOSTestbed"] + test_args[2:] + // argv = ["Testbed"] + test_args[2:] test_args = [[NSProcessInfo processInfo] arguments]; if (test_args == NULL) { NSLog(@"Unable to identify test arguments."); } NSLog(@"Test arguments: %@", test_args); argv = malloc(sizeof(char *) * ([test_args count] - 1)); - argv[0] = "iOSTestbed"; + argv[0] = "Testbed"; for (int i = 1; i < [test_args count] - 1; i++) { argv[i] = [[test_args objectAtIndex:i+1] UTF8String]; } diff --git a/iOS/testbed/__main__.py b/Apple/testbed/__main__.py similarity index 54% rename from iOS/testbed/__main__.py rename to Apple/testbed/__main__.py index 6a4d9c76d16..0dd77ab8b82 100644 --- a/iOS/testbed/__main__.py +++ b/Apple/testbed/__main__.py @@ -1,11 +1,16 @@ import argparse import json +import os import re +import shlex import shutil import subprocess import sys from pathlib import Path +TEST_SLICES = { + "iOS": "ios-arm64_x86_64-simulator", +} DECODE_ARGS = ("UTF-8", "backslashreplace") @@ -21,45 +26,49 @@ LOG_PREFIX_REGEX = re.compile( # Select a simulator device to use. -def select_simulator_device(): +def select_simulator_device(platform): # List the testing simulators, in JSON format raw_json = subprocess.check_output(["xcrun", "simctl", "list", "-j"]) json_data = json.loads(raw_json) - # Any device will do; we'll look for "SE" devices - but the name isn't - # consistent over time. Older Xcode versions will use "iPhone SE (Nth - # generation)"; As of 2025, they've started using "iPhone 16e". - # - # When Xcode is updated after a new release, new devices will be available - # and old ones will be dropped from the set available on the latest iOS - # version. Select the one with the highest minimum runtime version - this - # is an indicator of the "newest" released device, which should always be - # supported on the "most recent" iOS version. - se_simulators = sorted( - (devicetype["minRuntimeVersion"], devicetype["name"]) - for devicetype in json_data["devicetypes"] - if devicetype["productFamily"] == "iPhone" - and ( - ( - "iPhone " in devicetype["name"] - and devicetype["name"].endswith("e") + if platform == "iOS": + # Any iOS device will do; we'll look for "SE" devices - but the name + # isn't consistent over time. Older Xcode versions will use "iPhone SE + # (Nth generation)"; As of 2025, they've started using "iPhone 16e". + # + # When Xcode is updated after a new release, new devices will be + # available and old ones will be dropped from the set available on the + # latest iOS version. Select the one with the highest minimum runtime + # version - this is an indicator of the "newest" released device, which + # should always be supported on the "most recent" iOS version. + se_simulators = sorted( + (devicetype["minRuntimeVersion"], devicetype["name"]) + for devicetype in json_data["devicetypes"] + if devicetype["productFamily"] == "iPhone" + and ( + ( + "iPhone " in devicetype["name"] + and devicetype["name"].endswith("e") + ) + or "iPhone SE " in devicetype["name"] ) - or "iPhone SE " in devicetype["name"] ) - ) + simulator = se_simulators[-1][1] + else: + raise ValueError(f"Unknown platform {platform}") - return se_simulators[-1][1] + return simulator -def xcode_test(location, simulator, verbose): +def xcode_test(location: Path, platform: str, simulator: str, verbose: bool): # Build and run the test suite on the named simulator. args = [ "-project", - str(location / "iOSTestbed.xcodeproj"), + str(location / f"{platform}Testbed.xcodeproj"), "-scheme", - "iOSTestbed", + f"{platform}Testbed", "-destination", - f"platform=iOS Simulator,name={simulator}", + f"platform={platform} Simulator,name={simulator}", "-derivedDataPath", str(location / "DerivedData"), ] @@ -71,6 +80,13 @@ def xcode_test(location, simulator, verbose): check=True, ) + # Any environment variable prefixed with TEST_RUNNER_ is exposed into the + # test runner environment. There are some variables (like those identifying + # CI platforms) that can be useful to have access to. + test_env = os.environ.copy() + if "GITHUB_ACTIONS" in os.environ: + test_env["TEST_RUNNER_GITHUB_ACTIONS"] = os.environ["GITHUB_ACTIONS"] + print("Running test project...") # Test execution *can't* be run -quiet; verbose mode # is how we see the output of the test output. @@ -78,6 +94,7 @@ def xcode_test(location, simulator, verbose): ["xcodebuild", "test-without-building"] + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + env=test_env, ) while line := (process.stdout.readline()).decode(*DECODE_ARGS): # Strip the timestamp/process prefix from each log line @@ -89,10 +106,24 @@ def xcode_test(location, simulator, verbose): exit(status) +def copy(src, tgt): + """An all-purpose copy. + + If src is a file, it is copied. If src is a symlink, it is copied *as a + symlink*. If src is a directory, the full tree is duplicated, with symlinks + being preserved. + """ + if src.is_file() or src.is_symlink(): + shutil.copyfile(src, tgt, follow_symlinks=False) + else: + shutil.copytree(src, tgt, symlinks=True) + + def clone_testbed( source: Path, target: Path, framework: Path, + platform: str, apps: list[Path], ) -> None: if target.exists(): @@ -101,11 +132,11 @@ def clone_testbed( if framework is None: if not ( - source / "Python.xcframework/ios-arm64_x86_64-simulator/bin" + source / "Python.xcframework" / TEST_SLICES[platform] / "bin" ).is_dir(): print( f"The testbed being cloned ({source}) does not contain " - f"a simulator framework. Re-run with --framework" + "a framework with slices. Re-run with --framework" ) sys.exit(11) else: @@ -124,33 +155,49 @@ def clone_testbed( print("Cloning testbed project:") print(f" Cloning {source}...", end="") - shutil.copytree(source, target, symlinks=True) + # Only copy the files for the platform being cloned plus the files common + # to all platforms. The XCframework will be copied later, if needed. + target.mkdir(parents=True) + + for name in [ + "__main__.py", + "TestbedTests", + "Testbed.lldbinit", + f"{platform}Testbed", + f"{platform}Testbed.xcodeproj", + f"{platform}Testbed.xctestplan", + ]: + copy(source / name, target / name) + print(" done") + orig_xc_framework_path = source / "Python.xcframework" xc_framework_path = target / "Python.xcframework" - sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" + test_framework_path = xc_framework_path / TEST_SLICES[platform] if framework is not None: if framework.suffix == ".xcframework": print(" Installing XCFramework...", end="") - if xc_framework_path.is_dir(): - shutil.rmtree(xc_framework_path) - else: - xc_framework_path.unlink(missing_ok=True) xc_framework_path.symlink_to( framework.relative_to(xc_framework_path.parent, walk_up=True) ) print(" done") else: print(" Installing simulator framework...", end="") - if sim_framework_path.is_dir(): - shutil.rmtree(sim_framework_path) + # We're only installing a slice of a framework; we need + # to do a full tree copy to make sure we don't damage + # symlinked content. + shutil.copytree(orig_xc_framework_path, xc_framework_path) + if test_framework_path.is_dir(): + shutil.rmtree(test_framework_path) else: - sim_framework_path.unlink(missing_ok=True) - sim_framework_path.symlink_to( - framework.relative_to(sim_framework_path.parent, walk_up=True) + test_framework_path.unlink(missing_ok=True) + test_framework_path.symlink_to( + framework.relative_to(test_framework_path.parent, walk_up=True) ) print(" done") else: + copy(orig_xc_framework_path, xc_framework_path) + if ( xc_framework_path.is_symlink() and not xc_framework_path.readlink().is_absolute() @@ -158,39 +205,39 @@ def clone_testbed( # XCFramework is a relative symlink. Rewrite the symlink relative # to the new location. print(" Rewriting symlink to XCframework...", end="") - orig_xc_framework_path = ( + resolved_xc_framework_path = ( source / xc_framework_path.readlink() ).resolve() xc_framework_path.unlink() xc_framework_path.symlink_to( - orig_xc_framework_path.relative_to( + resolved_xc_framework_path.relative_to( xc_framework_path.parent, walk_up=True ) ) print(" done") elif ( - sim_framework_path.is_symlink() - and not sim_framework_path.readlink().is_absolute() + test_framework_path.is_symlink() + and not test_framework_path.readlink().is_absolute() ): print(" Rewriting symlink to simulator framework...", end="") # Simulator framework is a relative symlink. Rewrite the symlink # relative to the new location. - orig_sim_framework_path = ( - source / "Python.XCframework" / sim_framework_path.readlink() + orig_test_framework_path = ( + source / "Python.XCframework" / test_framework_path.readlink() ).resolve() - sim_framework_path.unlink() - sim_framework_path.symlink_to( - orig_sim_framework_path.relative_to( - sim_framework_path.parent, walk_up=True + test_framework_path.unlink() + test_framework_path.symlink_to( + orig_test_framework_path.relative_to( + test_framework_path.parent, walk_up=True ) ) print(" done") else: - print(" Using pre-existing iOS framework.") + print(" Using pre-existing Python framework.") for app_src in apps: print(f" Installing app {app_src.name!r}...", end="") - app_target = target / f"iOSTestbed/app/{app_src.name}" + app_target = target / f"Testbed/app/{app_src.name}" if app_target.is_dir(): shutil.rmtree(app_target) shutil.copytree(app_src, app_target) @@ -199,46 +246,65 @@ def clone_testbed( print(f"Successfully cloned testbed: {target.resolve()}") -def update_test_plan(testbed_path, args): +def update_test_plan(testbed_path, platform, args): # Modify the test plan to use the requested test arguments. - test_plan_path = testbed_path / "iOSTestbed.xctestplan" + test_plan_path = testbed_path / f"{platform}Testbed.xctestplan" with test_plan_path.open("r", encoding="utf-8") as f: test_plan = json.load(f) test_plan["defaultOptions"]["commandLineArgumentEntries"] = [ - {"argument": arg} for arg in args + {"argument": shlex.quote(arg)} for arg in args ] with test_plan_path.open("w", encoding="utf-8") as f: json.dump(test_plan, f, indent=2) -def run_testbed(simulator: str | None, args: list[str], verbose: bool = False): +def run_testbed( + platform: str, + simulator: str | None, + args: list[str], + verbose: bool = False, +): location = Path(__file__).parent print("Updating test plan...", end="") - update_test_plan(location, args) + update_test_plan(location, platform, args) print(" done.") if simulator is None: - simulator = select_simulator_device() + simulator = select_simulator_device(platform) print(f"Running test on {simulator}") - xcode_test(location, simulator=simulator, verbose=verbose) + xcode_test( + location, + platform=platform, + simulator=simulator, + verbose=verbose, + ) def main(): + # Look for directories like `iOSTestbed` as an indicator of the platforms + # that the testbed folder supports. The original source testbed can support + # many platforms, but when cloned, only one platform is preserved. + available_platforms = [ + platform + for platform in ["iOS"] + if (Path(__file__).parent / f"{platform}Testbed").is_dir() + ] + parser = argparse.ArgumentParser( description=( - "Manages the process of testing a Python project in the iOS simulator." + "Manages the process of testing an Apple Python project " + "through Xcode." ), ) subcommands = parser.add_subparsers(dest="subcommand") - clone = subcommands.add_parser( "clone", description=( - "Clone the testbed project, copying in an iOS Python framework and" + "Clone the testbed project, copying in a Python framework and" "any specified application code." ), help="Clone a testbed project to a new location.", @@ -250,6 +316,13 @@ def main(): "XCFramework) to use when running the testbed" ), ) + clone.add_argument( + "--platform", + dest="platform", + choices=available_platforms, + default=available_platforms[0], + help=f"The platform to target (default: {available_platforms[0]})", + ) clone.add_argument( "--app", dest="apps", @@ -264,7 +337,10 @@ def main(): run = subcommands.add_parser( "run", - usage="%(prog)s [-h] [--simulator SIMULATOR] -- [ ...]", + usage=( + "%(prog)s [-h] [--simulator SIMULATOR] -- " + " [ ...]" + ), description=( "Run a testbed project. The arguments provided after `--` will be " "passed to the running iOS process as if they were arguments to " @@ -272,6 +348,13 @@ def main(): ), help="Run a testbed project", ) + run.add_argument( + "--platform", + dest="platform", + choices=available_platforms, + default=available_platforms[0], + help=f"The platform to target (default: {available_platforms[0]})", + ) run.add_argument( "--simulator", help=( @@ -306,29 +389,34 @@ def main(): framework=Path(context.framework).resolve() if context.framework else None, + platform=context.platform, apps=[Path(app) for app in context.apps], ) elif context.subcommand == "run": if test_args: if not ( Path(__file__).parent - / "Python.xcframework/ios-arm64_x86_64-simulator/bin" + / "Python.xcframework" + / TEST_SLICES[context.platform] + / "bin" ).is_dir(): print( - f"Testbed does not contain a compiled iOS framework. Use " - f"`python {sys.argv[0]} clone ...` to create a runnable " - f"clone of this testbed." + "Testbed does not contain a compiled Python framework. " + f"Use `python {sys.argv[0]} clone ...` to create a " + "runnable clone of this testbed." ) sys.exit(20) run_testbed( + platform=context.platform, simulator=context.simulator, verbose=context.verbose, args=test_args, ) else: print( - f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)" + "Must specify test arguments " + f"(e.g., {sys.argv[0]} run -- test)" ) print() parser.print_help(sys.stderr) @@ -339,4 +427,9 @@ def main(): if __name__ == "__main__": + # Under the buildbot, stdout is not a TTY, but we must still flush after + # every line to make sure our output appears in the correct order relative + # to the output of our subprocesses. + for stream in [sys.stdout, sys.stderr]: + stream.reconfigure(line_buffering=True) main() diff --git a/iOS/testbed/iOSTestbed.xcodeproj/project.pbxproj b/Apple/testbed/iOSTestbed.xcodeproj/project.pbxproj similarity index 79% rename from iOS/testbed/iOSTestbed.xcodeproj/project.pbxproj rename to Apple/testbed/iOSTestbed.xcodeproj/project.pbxproj index 18cdafd8127..f8835a3bc58 100644 --- a/iOS/testbed/iOSTestbed.xcodeproj/project.pbxproj +++ b/Apple/testbed/iOSTestbed.xcodeproj/project.pbxproj @@ -11,12 +11,11 @@ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; }; 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */; }; 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; }; - 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */; }; + 607A66322B0EFA3A0010BFC8 /* TestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* TestbedTests.m */; }; 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */; }; 608619542CB77BA900F46182 /* app_packages in Resources */ = {isa = PBXBuildFile; fileRef = 608619532CB77BA900F46182 /* app_packages */; }; 608619562CB7819B00F46182 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 608619552CB7819B00F46182 /* app */; }; /* End PBXBuildFile section */ @@ -64,9 +63,8 @@ 607A66242B0EFA390010BFC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSTestbedTests.m; sourceTree = ""; }; + 607A66312B0EFA3A0010BFC8 /* TestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestbedTests.m; sourceTree = ""; }; 607A664A2B0EFB310010BFC8 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; }; - 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dylib-Info-template.plist"; sourceTree = ""; }; 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOSTestbed-Info.plist"; sourceTree = ""; }; 608619532CB77BA900F46182 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = ""; }; 608619552CB7819B00F46182 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = ""; }; @@ -99,7 +97,7 @@ 60FE0EFB2E56BB6D00524F87 /* iOSTestbed.xctestplan */, 607A664A2B0EFB310010BFC8 /* Python.xcframework */, 607A66142B0EFA380010BFC8 /* iOSTestbed */, - 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */, + 607A66302B0EFA3A0010BFC8 /* TestbedTests */, 607A66132B0EFA380010BFC8 /* Products */, 607A664F2B0EFFE00010BFC8 /* Frameworks */, ); @@ -120,7 +118,6 @@ 608619552CB7819B00F46182 /* app */, 608619532CB77BA900F46182 /* app_packages */, 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */, - 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */, 607A66152B0EFA380010BFC8 /* AppDelegate.h */, 607A66162B0EFA380010BFC8 /* AppDelegate.m */, 607A66212B0EFA390010BFC8 /* Assets.xcassets */, @@ -130,12 +127,12 @@ path = iOSTestbed; sourceTree = ""; }; - 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */ = { + 607A66302B0EFA3A0010BFC8 /* TestbedTests */ = { isa = PBXGroup; children = ( - 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */, + 607A66312B0EFA3A0010BFC8 /* TestbedTests.m */, ); - path = iOSTestbedTests; + path = TestbedTests; sourceTree = ""; }; 607A664F2B0EFFE00010BFC8 /* Frameworks */ = { @@ -155,8 +152,7 @@ 607A660E2B0EFA380010BFC8 /* Sources */, 607A660F2B0EFA380010BFC8 /* Frameworks */, 607A66102B0EFA380010BFC8 /* Resources */, - 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */, - 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */, + 607A66552B0F061D0010BFC8 /* Process Python libraries */, 607A664E2B0EFC080010BFC8 /* Embed Frameworks */, ); buildRules = ( @@ -230,7 +226,6 @@ buildActionMask = 2147483647; files = ( 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */, - 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */, 608619562CB7819B00F46182 /* app in Resources */, 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */, 608619542CB77BA900F46182 /* app_packages in Resources */, @@ -247,7 +242,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */ = { + 607A66552B0F061D0010BFC8 /* Process Python libraries */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -257,34 +252,14 @@ ); inputPaths = ( ); - name = "Install Target Specific Python Standard Library"; + name = "Process Python libraries"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nfi\n"; - showEnvVarsInLog = 0; - }; - 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Prepare Python Binary Modules"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_EXT=$2\n\n # The name of the extension file\n EXT=$(basename \"$FULL_EXT\")\n # The location of the extension file, relative to the bundle\n RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} \n # The path to the extension file, relative to the install base\n PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}\n # The full dotted name of the extension module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_EXT\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleExecutable -string \"$FULL_MODULE_NAME\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n fi\n \n echo \"Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" \n mv \"$FULL_EXT\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\"\n # Create a placeholder .fwork file where the .so was\n echo \"$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" > ${FULL_EXT%.so}.fwork\n # Create a back reference to the .so file location in the framework\n echo \"${RELATIVE_EXT%.so}.fwork\" > \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin\" \n}\n\nPYTHON_VER=$(ls -1 \"$CODESIGNING_FOLDER_PATH/python/lib\")\necho \"Install Python $PYTHON_VER standard library extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib python/lib/$PYTHON_VER/lib-dynload/ \"$FULL_EXT\"\ndone\necho \"Install app package extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app_packages/ \"$FULL_EXT\"\ndone\necho \"Install app extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app/ \"$FULL_EXT\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; + shellScript = "set -e\nsource $PROJECT_DIR/Python.xcframework/build/utils.sh\ninstall_python Python.xcframework app app_packages\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -303,7 +278,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */, + 607A66322B0EFA3A0010BFC8 /* TestbedTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/iOS/testbed/iOSTestbed.xcodeproj/xcshareddata/xcschemes/iOSTestbed.xcscheme b/Apple/testbed/iOSTestbed.xcodeproj/xcshareddata/xcschemes/iOSTestbed.xcscheme similarity index 97% rename from iOS/testbed/iOSTestbed.xcodeproj/xcshareddata/xcschemes/iOSTestbed.xcscheme rename to Apple/testbed/iOSTestbed.xcodeproj/xcshareddata/xcschemes/iOSTestbed.xcscheme index d093a46f02e..3c330a4152b 100644 --- a/iOS/testbed/iOSTestbed.xcodeproj/xcshareddata/xcschemes/iOSTestbed.xcscheme +++ b/Apple/testbed/iOSTestbed.xcodeproj/xcshareddata/xcschemes/iOSTestbed.xcscheme @@ -27,7 +27,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - customLLDBInitFile = "/Users/rkm/projects/pyspamsum/localtest/iOSTestbed.lldbinit" + customLLDBInitFile = "$(SOURCE_ROOT)/Testbed.lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + Tachyon Profiler - Flamegraph Report + + + + + + + +
+ +
+
+ + Tachyon + + Flamegraph Report +
+
+ + +
+
+ + + + + + + + +
+
+ + +
+ + + + +
+
+
+
+ + +
+ + Tachyon Profiler + + + Python Sampling Profiler + + + + + +
+
+ + + + diff --git a/Doc/_static/tachyon-example-heatmap.html b/Doc/_static/tachyon-example-heatmap.html new file mode 100644 index 00000000000..f725e947500 --- /dev/null +++ b/Doc/_static/tachyon-example-heatmap.html @@ -0,0 +1,3804 @@ + + + + + + /tmp/tachyon_selfcontained.py - Heatmap + + + +
+ +
+
+ + Tachyon + + /tmp/tachyon_selfcontained.py +
+
+ + + + + + + + + + + +
+
+ + +
+
+
+
1,054
+
Self Samples
+
+
+
4,236
+
Cumulative
+
+
+
24
+
Lines Hit
+
+
+
100.00%
+
% of Total
+
+
+
206
+
Max Self
+
+
+
1054
+
Max Total
+
+
+
+ + +
+
+ Intensity: +
+
+ Cold + + Hot +
+ +
+
+ Self Time +
+ Total Time +
+
+ Show All +
+ Hot Only +
+
+ Heat +
+ Specialization +
+ + +
+
+
+ + +
+
+
Line
+
Self
+
Total
+
Code
+
+
+
1
+
+
+
+
"""
+ +
+
+
2
+
+
+
+
Tachyon Demo - Self-contained profiling example.
+ +
+
+
3
+
+
+
+
Pure Python with no external imports for clean heatmap output.
+ +
+
+
4
+
+
+
+
"""
+ +
+
+
5
+
+
+
+
+ +
+
+
6
+
+
+
+
+ +
+
+
7
+
1
+
1
+ +
def fibonacci(n):
+ +
+ +
+
8
+
+
+
+
"""Recursive fibonacci - creates deep call stacks."""
+ +
+
+
9
+
3
+
3
+ +
if n <= 1:
+ +
+ +
+
10
+
17
+
17
+ +
return n
+
+
+ +
+
11
+
206
+
227
+ +
return fibonacci(n - 1) + fibonacci(n - 2)
+
+
+ +
+
12
+
+
+
+
+ +
+
+
13
+
+
+
+
+ +
+
+
14
+
+
+
+
def bubble_sort(arr):
+ +
+
+
15
+
+
+
+
"""Classic bubble sort - O(n^2) comparison sorting."""
+ +
+
+
16
+
+
+
+
n = len(arr)
+ +
+
+
17
+
+
+
+
for i in range(n):
+ +
+
+
18
+
2
+
2
+ +
for j in range(0, n - i - 1):
+ +
+ +
+
19
+
8
+
8
+ +
if arr[j] > arr[j + 1]:
+
+
+ +
+
20
+
2
+
2
+ +
arr[j], arr[j + 1] = arr[j + 1], arr[j]
+ +
+ +
+
21
+
+
+
+
return arr
+ +
+
+
22
+
+
+
+
+ +
+
+
23
+
+
+
+
+ +
+
+
24
+
+
+
+
def matrix_multiply(a, b):
+ +
+
+
25
+
+
+
+
"""Matrix multiplication using nested loops."""
+ +
+
+
26
+
+
+
+
rows_a, cols_a = len(a), len(a[0])
+ +
+
+
27
+
+
+
+
rows_b, cols_b = len(b), len(b[0])
+ +
+
+
28
+
+
+
+
result = [[0] * cols_b for _ in range(rows_a)]
+ +
+
+
29
+
+
+
+
+ +
+
+
30
+
+
+
+
for i in range(rows_a):
+ +
+
+
31
+
+
+
+
for j in range(cols_b):
+ +
+
+
32
+
8
+
8
+ +
for k in range(cols_a):
+ +
+ +
+
33
+
62
+
62
+ +
result[i][j] += a[i][k] * b[k][j]
+
+
+ +
+
34
+
+
+
+
return result
+ +
+
+
35
+
+
+
+
+ +
+
+
36
+
+
+
+
+ +
+
+
37
+
+
+
+
def prime_sieve(limit):
+ +
+
+
38
+
+
+
+
"""Sieve of Eratosthenes - find all primes up to limit."""
+ +
+
+
39
+
+
+
+
is_prime = [True] * (limit + 1)
+ +
+
+
40
+
+
+
+
is_prime[0] = is_prime[1] = False
+ +
+
+
41
+
+
+
+
+ +
+
+
42
+
+
+
+
for num in range(2, int(limit ** 0.5) + 1):
+ +
+
+
43
+
+
+
+
if is_prime[num]:
+ +
+
+
44
+
1
+
1
+ +
for multiple in range(num * num, limit + 1, num):
+
+
+ +
+
45
+
+
+
+
is_prime[multiple] = False
+ +
+
+
46
+
+
+
+
+ +
+
+
47
+
2
+
2
+ +
return [num for num, prime in enumerate(is_prime) if prime]
+ +
+ +
+
48
+
+
+
+
+ +
+
+
49
+
+
+
+
+ +
+
+
50
+
+
+
+
def string_processing(iterations):
+ +
+
+
51
+
+
+
+
"""String operations - concatenation and formatting."""
+ +
+
+
52
+
+
+
+
for _ in range(iterations):
+ +
+
+
53
+
+
+
+
result = ""
+ +
+
+
54
+
+
+
+
for i in range(50):
+ +
+
+
55
+
91
+
91
+ +
result += f"item_{i}_"
+
+
+ +
+
56
+
22
+
22
+ +
parts = result.split("_")
+ +
+ +
+
57
+
10
+
10
+ +
joined = "-".join(parts)
+ +
+ +
+
58
+
+
+
+
+ +
+
+
59
+
+
+
+
+ +
+
+
60
+
+
+
+
def list_operations(iterations):
+ +
+
+
61
+
+
+
+
"""List comprehensions and operations."""
+ +
+
+
62
+
+
+
+
for _ in range(iterations):
+ +
+
+
63
+
118
+
118
+ +
squares = [x ** 2 for x in range(500)]
+ +
+ +
+
64
+
119
+
119
+ +
evens = [x for x in squares if x % 2 == 0]
+
+
+ +
+
65
+
12
+
12
+ +
total = sum(evens)
+ +
+ +
+
66
+
+
+
+
+ +
+
+
67
+
+
+
+
+ +
+
+
68
+
+
+
+
def dict_operations(iterations):
+ +
+
+
69
+
+
+
+
"""Dictionary creation and lookups."""
+ +
+
+
70
+
+
+
+
for _ in range(iterations):
+ +
+
+
71
+
206
+
206
+ +
data = {f"key_{i}": i ** 2 for i in range(200)}
+
+
+ +
+
72
+
158
+
158
+ +
values = [data[f"key_{i}"] for i in range(200)]
+ +
+ +
+
73
+
5
+
5
+ +
total = sum(values)
+ +
+ +
+
74
+
+
+
+
+ +
+
+
75
+
+
+
+
+ +
+
+
76
+
+
+
+
def compute_heavy():
+ +
+
+
77
+
+
+
+
"""CPU-intensive computation section."""
+ +
+
+
78
+
1
+
301
+ +
fibonacci(30)
+
+
+ +
+
79
+
+
+
+
+ +
+
+
80
+
+
+
+
size = 60
+ +
+
+
81
+
+
+
+
a = [[i + j for j in range(size)] for i in range(size)]
+ +
+
+
82
+
+
+
+
b = [[i * j for j in range(size)] for i in range(size)]
+ +
+
+
83
+
+
+
+
matrix_multiply(a, b)
+ +
+
+
84
+
+
+
+
+ +
+
+
85
+
+
+
+
prime_sieve(10000)
+ +
+
+
86
+
+
+
+
+ +
+
+
87
+
+
+
+
+ +
+
+
88
+
+
+
+
def data_processing():
+ +
+
+
89
+
+
+
+
"""Data structure operations."""
+ +
+
+
90
+
+
753
+ +
string_processing(2000)
+
+
+ +
+
91
+
+
+
+
list_operations(1500)
+ +
+
+
92
+
+
+
+
dict_operations(1000)
+ +
+
+
93
+
+
+
+
+ +
+
+
94
+
+
+
+
data = list(range(800))
+ +
+
+
95
+
+
+
+
for _ in range(3):
+ +
+
+
96
+
+
+
+
data = data[::-1]
+ +
+
+
97
+
+
+
+
bubble_sort(data[:200])
+ +
+
+
98
+
+
+
+
+ +
+
+
99
+
+
+
+
+ +
+
+
100
+
+
+
+
def main():
+ +
+
+
101
+
+
+
+
"""Main entry point."""
+ +
+
+
102
+
+
1,054
+ +
compute_heavy()
+
+
+ +
+
103
+
+
+
+
data_processing()
+ +
+
+
104
+
+
+
+
+ +
+
+
105
+
+
+
+
+ +
+
+
106
+
+
+
+
if __name__ == "__main__":
+ +
+
+
107
+
+
1,054
+ +
main()
+
+
+ + +
+
+ + + + diff --git a/Doc/about.rst b/Doc/about.rst index 8f635d7f743..5c1b497ca6b 100644 --- a/Doc/about.rst +++ b/Doc/about.rst @@ -32,8 +32,9 @@ Contributors to the Python documentation ---------------------------------------- Many people have contributed to the Python language, the Python standard -library, and the Python documentation. See :source:`Misc/ACKS` in the Python -source distribution for a partial list of contributors. +library, and the Python documentation. See the `CPython +GitHub repository `__ +for a partial list of contributors. It is only with the input and contributions of the Python community that Python has such wonderful documentation -- Thank You! diff --git a/Doc/bugs.rst b/Doc/bugs.rst index faf13eeb6a7..0683eebbaf6 100644 --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -19,6 +19,12 @@ If you find a bug in this documentation or would like to propose an improvement, please submit a bug report on the :ref:`issue tracker `. If you have a suggestion on how to fix it, include that as well. +.. only:: translation + + If the bug or suggested improvement concerns the translation of this + documentation, submit the report to the + `translation’s repository `_ instead. + You can also open a discussion item on our `Documentation Discourse forum `_. diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst index 59d913a0462..59044d2d88c 100644 --- a/Doc/c-api/allocation.rst +++ b/Doc/c-api/allocation.rst @@ -140,10 +140,6 @@ Allocating Objects on the Heap * :c:member:`~PyTypeObject.tp_alloc` -.. c:function:: void PyObject_Del(void *op) - - Same as :c:func:`PyObject_Free`. - .. c:var:: PyObject _Py_NoneStruct Object which is visible in Python as ``None``. This should only be accessed @@ -156,3 +152,35 @@ Allocating Objects on the Heap :ref:`moduleobjects` To allocate and create extension modules. + +Deprecated aliases +^^^^^^^^^^^^^^^^^^ + +These are :term:`soft deprecated` aliases to existing functions and macros. +They exist solely for backwards compatibility. + + +.. list-table:: + :widths: auto + :header-rows: 1 + + * * Deprecated alias + * Function + * * .. c:macro:: PyObject_NEW(type, typeobj) + * :c:macro:`PyObject_New` + * * .. c:macro:: PyObject_NEW_VAR(type, typeobj, n) + * :c:macro:`PyObject_NewVar` + * * .. c:macro:: PyObject_INIT(op, typeobj) + * :c:func:`PyObject_Init` + * * .. c:macro:: PyObject_INIT_VAR(op, typeobj, n) + * :c:func:`PyObject_InitVar` + * * .. c:macro:: PyObject_MALLOC(n) + * :c:func:`PyObject_Malloc` + * * .. c:macro:: PyObject_REALLOC(p, n) + * :c:func:`PyObject_Realloc` + * * .. c:macro:: PyObject_FREE(p) + * :c:func:`PyObject_Free` + * * .. c:macro:: PyObject_DEL(p) + * :c:func:`PyObject_Free` + * * .. c:macro:: PyObject_Del(p) + * :c:func:`PyObject_Free` diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 3429a4eb652..fd6be6a9b67 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -160,7 +160,7 @@ There are three ways strings and buffers can be converted to C: ``w*`` (read-write :term:`bytes-like object`) [Py_buffer] This format accepts any object which implements the read-write buffer interface. It fills a :c:type:`Py_buffer` structure provided by the caller. - The buffer may contain embedded null bytes. The caller have to call + The buffer may contain embedded null bytes. The caller has to call :c:func:`PyBuffer_Release` when it is done with the buffer. ``es`` (:class:`str`) [const char \*encoding, char \*\*buffer] @@ -305,7 +305,7 @@ the minimal value for the corresponding signed integer type of the same size. ``D`` (:class:`complex`) [Py_complex] Convert a Python complex number to a C :c:type:`Py_complex` structure. -.. deprecated:: next +.. deprecated:: 3.15 For unsigned integer formats ``B``, ``H``, ``I``, ``k`` and ``K``, :exc:`DeprecationWarning` is emitted when the value is larger than diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index d3081894ead..6bb72a2312b 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -261,6 +261,10 @@ readonly, format MUST be consistent for all consumers. For example, :c:expr:`PyBUF_SIMPLE | PyBUF_WRITABLE` can be used to request a simple writable buffer. + .. c:macro:: PyBUF_WRITEABLE + + This is a :term:`soft deprecated` alias to :c:macro:`PyBUF_WRITABLE`. + .. c:macro:: PyBUF_FORMAT Controls the :c:member:`~Py_buffer.format` field. If set, this field MUST diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index d47beee68ea..82c25573683 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -47,6 +47,10 @@ called with a non-bytes parameter. *len* on success, and ``NULL`` on failure. If *v* is ``NULL``, the contents of the bytes object are uninitialized. + .. deprecated:: 3.15 + ``PyBytes_FromStringAndSize(NULL, len)`` is :term:`soft deprecated`, + use the :c:type:`PyBytesWriter` API instead. + .. c:function:: PyObject* PyBytes_FromFormat(const char *format, ...) @@ -219,3 +223,209 @@ called with a non-bytes parameter. reallocation fails, the original bytes object at *\*bytes* is deallocated, *\*bytes* is set to ``NULL``, :exc:`MemoryError` is set, and ``-1`` is returned. + + .. deprecated:: 3.15 + The function is :term:`soft deprecated`, + use the :c:type:`PyBytesWriter` API instead. + + +.. c:function:: PyObject *PyBytes_Repr(PyObject *bytes, int smartquotes) + + Get the string representation of *bytes*. This function is currently used to + implement :meth:`!bytes.__repr__` in Python. + + This function does not do type checking; it is undefined behavior to pass + *bytes* as a non-bytes object or ``NULL``. + + If *smartquotes* is true, the representation will use a double-quoted string + instead of single-quoted string when single-quotes are present in *bytes*. + For example, the byte string ``'Python'`` would be represented as + ``b"'Python'"`` when *smartquotes* is true, or ``b'\'Python\''`` when it is + false. + + On success, this function returns a :term:`strong reference` to a + :class:`str` object containing the representation. On failure, this + returns ``NULL`` with an exception set. + + +.. c:function:: PyObject *PyBytes_DecodeEscape(const char *s, Py_ssize_t len, const char *errors, Py_ssize_t unicode, const char *recode_encoding) + + Unescape a backslash-escaped string *s*. *s* must not be ``NULL``. + *len* must be the size of *s*. + + *errors* must be one of ``"strict"``, ``"replace"``, or ``"ignore"``. If + *errors* is ``NULL``, then ``"strict"`` is used by default. + + On success, this function returns a :term:`strong reference` to a Python + :class:`bytes` object containing the unescaped string. On failure, this + function returns ``NULL`` with an exception set. + + .. versionchanged:: 3.9 + *unicode* and *recode_encoding* are now unused. + + +.. _pybyteswriter: + +PyBytesWriter +------------- + +The :c:type:`PyBytesWriter` API can be used to create a Python :class:`bytes` +object. + +.. versionadded:: 3.15 + +.. c:type:: PyBytesWriter + + A bytes writer instance. + + The API is **not thread safe**: a writer should only be used by a single + thread at the same time. + + The instance must be destroyed by :c:func:`PyBytesWriter_Finish` on + success, or :c:func:`PyBytesWriter_Discard` on error. + + +Create, Finish, Discard +^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: PyBytesWriter* PyBytesWriter_Create(Py_ssize_t size) + + Create a :c:type:`PyBytesWriter` to write *size* bytes. + + If *size* is greater than zero, allocate *size* bytes, and set the + writer size to *size*. The caller is responsible to write *size* + bytes using :c:func:`PyBytesWriter_GetData`. + This function does not overallocate. + + On error, set an exception and return ``NULL``. + + *size* must be positive or zero. + +.. c:function:: PyObject* PyBytesWriter_Finish(PyBytesWriter *writer) + + Finish a :c:type:`PyBytesWriter` created by + :c:func:`PyBytesWriter_Create`. + + On success, return a Python :class:`bytes` object. + On error, set an exception and return ``NULL``. + + The writer instance is invalid after the call in any case. + No API can be called on the writer after :c:func:`PyBytesWriter_Finish`. + +.. c:function:: PyObject* PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size) + + Similar to :c:func:`PyBytesWriter_Finish`, but resize the writer + to *size* bytes before creating the :class:`bytes` object. + +.. c:function:: PyObject* PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf) + + Similar to :c:func:`PyBytesWriter_Finish`, but resize the writer + using *buf* pointer before creating the :class:`bytes` object. + + Set an exception and return ``NULL`` if *buf* pointer is outside the + internal buffer bounds. + + Function pseudo-code:: + + Py_ssize_t size = (char*)buf - (char*)PyBytesWriter_GetData(writer); + return PyBytesWriter_FinishWithSize(writer, size); + +.. c:function:: void PyBytesWriter_Discard(PyBytesWriter *writer) + + Discard a :c:type:`PyBytesWriter` created by :c:func:`PyBytesWriter_Create`. + + Do nothing if *writer* is ``NULL``. + + The writer instance is invalid after the call. + No API can be called on the writer after :c:func:`PyBytesWriter_Discard`. + +High-level API +^^^^^^^^^^^^^^ + +.. c:function:: int PyBytesWriter_WriteBytes(PyBytesWriter *writer, const void *bytes, Py_ssize_t size) + + Grow the *writer* internal buffer by *size* bytes, + write *size* bytes of *bytes* at the *writer* end, + and add *size* to the *writer* size. + + If *size* is equal to ``-1``, call ``strlen(bytes)`` to get the + string length. + + On success, return ``0``. + On error, set an exception and return ``-1``. + +.. c:function:: int PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) + + Similar to :c:func:`PyBytes_FromFormat`, but write the output directly at + the writer end. Grow the writer internal buffer on demand. Then add the + written size to the writer size. + + On success, return ``0``. + On error, set an exception and return ``-1``. + + +Getters +^^^^^^^ + +.. c:function:: Py_ssize_t PyBytesWriter_GetSize(PyBytesWriter *writer) + + Get the writer size. + +.. c:function:: void* PyBytesWriter_GetData(PyBytesWriter *writer) + + Get the writer data: start of the internal buffer. + + The pointer is valid until :c:func:`PyBytesWriter_Finish` or + :c:func:`PyBytesWriter_Discard` is called on *writer*. + + +Low-level API +^^^^^^^^^^^^^ + +.. c:function:: int PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) + + Resize the writer to *size* bytes. It can be used to enlarge or to + shrink the writer. + This function typically overallocates to achieve amortized performance when + resizing multiple times. + + Newly allocated bytes are left uninitialized. + + On success, return ``0``. + On error, set an exception and return ``-1``. + + *size* must be positive or zero. + +.. c:function:: int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t grow) + + Resize the writer by adding *grow* bytes to the current writer size. + This function typically overallocates to achieve amortized performance when + resizing multiple times. + + Newly allocated bytes are left uninitialized. + + On success, return ``0``. + On error, set an exception and return ``-1``. + + *size* can be negative to shrink the writer. + +.. c:function:: void* PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, void *buf) + + Similar to :c:func:`PyBytesWriter_Grow`, but update also the *buf* + pointer. + + The *buf* pointer is moved if the internal buffer is moved in memory. + The *buf* relative position within the internal buffer is left + unchanged. + + On error, set an exception and return ``NULL``. + + *buf* must not be ``NULL``. + + Function pseudo-code:: + + Py_ssize_t pos = (char*)buf - (char*)PyBytesWriter_GetData(writer); + if (PyBytesWriter_Grow(writer, size) < 0) { + return NULL; + } + return (char*)PyBytesWriter_GetData(writer) + pos; diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 64dc4f5275b..03a848d68ed 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -15,13 +15,19 @@ Refer to :ref:`using-capsules` for more information on using these objects. .. c:type:: PyCapsule This subtype of :c:type:`PyObject` represents an opaque value, useful for C - extension modules who need to pass an opaque value (as a :c:expr:`void*` + extension modules which need to pass an opaque value (as a :c:expr:`void*` pointer) through Python code to other C code. It is often used to make a C function pointer defined in one module available to other modules, so the regular import mechanism can be used to access C APIs defined in dynamically loaded modules. +.. c:var:: PyTypeObject PyCapsule_Type + + The type object corresponding to capsule objects. This is the same object + as :class:`types.CapsuleType` in the Python layer. + + .. c:type:: PyCapsule_Destructor The type of a destructor callback for a capsule. Defined as:: diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst index 61eb994c370..2501ed9580d 100644 --- a/Doc/c-api/cell.rst +++ b/Doc/c-api/cell.rst @@ -7,7 +7,7 @@ Cell Objects "Cell" objects are used to implement variables referenced by multiple scopes. For each such variable, a cell object is created to store the value; the local -variables of each stack frame that references the value contains a reference to +variables of each stack frame that references the value contain a reference to the cells from outer scopes which also use that variable. When the value is accessed, the value contained in the cell is used instead of the cell object itself. This de-referencing of the cell object requires support from the diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index 717b0da8f87..45f5e83adc4 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -211,6 +211,17 @@ bound into a function. .. versionadded:: 3.12 +.. c:function:: PyObject *PyCode_Optimize(PyObject *code, PyObject *consts, PyObject *names, PyObject *lnotab_obj) + + This is a :term:`soft deprecated` function that does nothing. + + Prior to Python 3.10, this function would perform basic optimizations to a + code object. + + .. versionchanged:: 3.10 + This function now does nothing. + + .. _c_codeobject_flags: Code Object Flags @@ -289,7 +300,7 @@ may change without deprecation warnings. .. c:function:: Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free) - Return a new an opaque index value used to adding data to code objects. + Return a new opaque index value used to adding data to code objects. You generally call this function once (per interpreter) and use the result with ``PyCode_GetExtra`` and ``PyCode_SetExtra`` to manipulate diff --git a/Doc/c-api/codec.rst b/Doc/c-api/codec.rst index 8ae5c4fecd6..35ee048bd5f 100644 --- a/Doc/c-api/codec.rst +++ b/Doc/c-api/codec.rst @@ -7,7 +7,7 @@ Codec registry and support functions Register a new codec search function. - As side effect, this tries to load the :mod:`!encodings` package, if not yet + As a side effect, this tries to load the :mod:`!encodings` package, if not yet done, to make sure that it is always first in the list of search functions. .. c:function:: int PyCodec_Unregister(PyObject *search_function) @@ -39,7 +39,7 @@ Codec registry and support functions *object* is passed through the decoder function found for the given *encoding* using the error handling method defined by *errors*. *errors* may be ``NULL`` to use the default method defined for the codec. Raises a - :exc:`LookupError` if no encoder can be found. + :exc:`LookupError` if no decoder can be found. Codec lookup API @@ -129,3 +129,13 @@ Registry API for Unicode encoding error handlers Replace the unicode encode error with ``\N{...}`` escapes. .. versionadded:: 3.5 + + +Codec utility variables +----------------------- + +.. c:var:: const char *Py_hexdigits + + A string constant containing the lowercase hexadecimal digits: ``"0123456789abcdef"``. + + .. versionadded:: 3.3 diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index aa91b85d07f..629312bd771 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -16,7 +16,7 @@ Complex Number Objects The complex number value, using the C :c:type:`Py_complex` representation. - .. deprecated-removed:: next 3.20 + .. deprecated-removed:: 3.15 3.20 Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex` to convert a Python complex number to/from the C :c:type:`Py_complex` @@ -82,7 +82,7 @@ Complex Number Objects .. c:type:: Py_complex - This C structure defines export format for a Python complex + This C structure defines an export format for a Python complex number object. .. c:member:: double real diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst index 880f7b15ce6..1746fe95eaa 100644 --- a/Doc/c-api/concrete.rst +++ b/Doc/c-api/concrete.rst @@ -109,11 +109,20 @@ Other Objects descriptor.rst slice.rst memoryview.rst + picklebuffer.rst weakref.rst capsule.rst frame.rst gen.rst coro.rst contextvars.rst - datetime.rst typehints.rst + + +C API for extension modules +=========================== + +.. toctree:: + + curses.rst + datetime.rst diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index c92ef4c653a..96078d22710 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -41,7 +41,7 @@ The return value (*rv*) for these functions should be interpreted as follows: ``rv + 1`` bytes would have been needed to succeed. ``str[size-1]`` is ``'\0'`` in this case. -* When ``rv < 0``, "something bad happened." ``str[size-1]`` is ``'\0'`` in +* When ``rv < 0``, the output conversion failed and ``str[size-1]`` is ``'\0'`` in this case too, but the rest of *str* is undefined. The exact cause of the error depends on the underlying platform. @@ -105,7 +105,7 @@ The following functions provide locale-independent string to number conversions. If ``s`` represents a value that is too large to store in a float (for example, ``"1e500"`` is such a string on many platforms) then - if ``overflow_exception`` is ``NULL`` return ``Py_INFINITY`` (with + if ``overflow_exception`` is ``NULL`` return :c:macro:`!INFINITY` (with an appropriate sign) and don't set any exception. Otherwise, ``overflow_exception`` must point to a Python exception object; raise that exception and return ``-1.0``. In both cases, set @@ -128,18 +128,28 @@ The following functions provide locale-independent string to number conversions. must be 0 and is ignored. The ``'r'`` format code specifies the standard :func:`repr` format. - *flags* can be zero or more of the values ``Py_DTSF_SIGN``, - ``Py_DTSF_ADD_DOT_0``, or ``Py_DTSF_ALT``, or-ed together: + *flags* can be zero or more of the following values or-ed together: - * ``Py_DTSF_SIGN`` means to always precede the returned string with a sign - character, even if *val* is non-negative. + .. c:macro:: Py_DTSF_SIGN - * ``Py_DTSF_ADD_DOT_0`` means to ensure that the returned string will not look - like an integer. + Always precede the returned string with a sign + character, even if *val* is non-negative. - * ``Py_DTSF_ALT`` means to apply "alternate" formatting rules. See the - documentation for the :c:func:`PyOS_snprintf` ``'#'`` specifier for - details. + .. c:macro:: Py_DTSF_ADD_DOT_0 + + Ensure that the returned string will not look like an integer. + + .. c:macro:: Py_DTSF_ALT + + Apply "alternate" formatting rules. + See the documentation for the :c:func:`PyOS_snprintf` ``'#'`` specifier for + details. + + .. c:macro:: Py_DTSF_NO_NEG_0 + + Negative zero is converted to positive zero. + + .. versionadded:: 3.11 If *ptype* is non-``NULL``, then the value it points to will be set to one of ``Py_DTST_FINITE``, ``Py_DTST_INFINITE``, or ``Py_DTST_NAN``, signifying that @@ -152,13 +162,85 @@ The following functions provide locale-independent string to number conversions. .. versionadded:: 3.1 -.. c:function:: int PyOS_stricmp(const char *s1, const char *s2) +.. c:function:: int PyOS_mystricmp(const char *str1, const char *str2) + int PyOS_mystrnicmp(const char *str1, const char *str2, Py_ssize_t size) - Case insensitive comparison of strings. The function works almost - identically to :c:func:`!strcmp` except that it ignores the case. + Case insensitive comparison of strings. These functions work almost + identically to :c:func:`!strcmp` and :c:func:`!strncmp` (respectively), + except that they ignore the case of ASCII characters. + + Return ``0`` if the strings are equal, a negative value if *str1* sorts + lexicographically before *str2*, or a positive value if it sorts after. + + In the *str1* or *str2* arguments, a NUL byte marks the end of the string. + For :c:func:`!PyOS_mystrnicmp`, the *size* argument gives the maximum size + of the string, as if NUL was present at the index given by *size*. + + These functions do not use the locale. -.. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size) +.. c:function:: int PyOS_stricmp(const char *str1, const char *str2) + int PyOS_strnicmp(const char *str1, const char *str2, Py_ssize_t size) - Case insensitive comparison of strings. The function works almost - identically to :c:func:`!strncmp` except that it ignores the case. + Case insensitive comparison of strings. + + On Windows, these are aliases of :c:func:`!stricmp` and :c:func:`!strnicmp`, + respectively. + + On other platforms, they are aliases of :c:func:`PyOS_mystricmp` and + :c:func:`PyOS_mystrnicmp`, respectively. + + +Character classification and conversion +======================================= + +The following macros provide locale-independent (unlike the C standard library +``ctype.h``) character classification and conversion. +The argument must be a signed or unsigned :c:expr:`char`. + + +.. c:macro:: Py_ISALNUM(c) + + Return true if the character *c* is an alphanumeric character. + + +.. c:macro:: Py_ISALPHA(c) + + Return true if the character *c* is an alphabetic character (``a-z`` and ``A-Z``). + + +.. c:macro:: Py_ISDIGIT(c) + + Return true if the character *c* is a decimal digit (``0-9``). + + +.. c:macro:: Py_ISLOWER(c) + + Return true if the character *c* is a lowercase ASCII letter (``a-z``). + + +.. c:macro:: Py_ISUPPER(c) + + Return true if the character *c* is an uppercase ASCII letter (``A-Z``). + + +.. c:macro:: Py_ISSPACE(c) + + Return true if the character *c* is a whitespace character (space, tab, + carriage return, newline, vertical tab, or form feed). + + +.. c:macro:: Py_ISXDIGIT(c) + + Return true if the character *c* is a hexadecimal digit (``0-9``, ``a-f``, and + ``A-F``). + + +.. c:macro:: Py_TOLOWER(c) + + Return the lowercase equivalent of the character *c*. + + +.. c:macro:: Py_TOUPPER(c) + + Return the uppercase equivalent of the character *c*. diff --git a/Doc/c-api/curses.rst b/Doc/c-api/curses.rst new file mode 100644 index 00000000000..5a1697c43cc --- /dev/null +++ b/Doc/c-api/curses.rst @@ -0,0 +1,138 @@ +.. highlight:: c + +Curses C API +------------ + +:mod:`curses` exposes a small C interface for extension modules. +Consumers must include the header file :file:`py_curses.h` (which is not +included by default by :file:`Python.h`) and :c:func:`import_curses` must +be invoked, usually as part of the module initialisation function, to populate +:c:var:`PyCurses_API`. + +.. warning:: + + Neither the C API nor the pure Python :mod:`curses` module are compatible + with subinterpreters. + +.. c:macro:: import_curses() + + Import the curses C API. The macro does not need a semi-colon to be called. + + On success, populate the :c:var:`PyCurses_API` pointer. + + On failure, set :c:var:`PyCurses_API` to NULL and set an exception. + The caller must check if an error occurred via :c:func:`PyErr_Occurred`: + + .. code-block:: + + import_curses(); // semi-colon is optional but recommended + if (PyErr_Occurred()) { /* cleanup */ } + + +.. c:var:: void **PyCurses_API + + Dynamically allocated object containing the curses C API. + This variable is only available once :c:macro:`import_curses` succeeds. + + ``PyCurses_API[0]`` corresponds to :c:data:`PyCursesWindow_Type`. + + ``PyCurses_API[1]``, ``PyCurses_API[2]``, and ``PyCurses_API[3]`` + are pointers to predicate functions of type ``int (*)(void)``. + + When called, these predicates return whether :func:`curses.setupterm`, + :func:`curses.initscr`, and :func:`curses.start_color` have been called + respectively. + + See also the convenience macros :c:macro:`PyCursesSetupTermCalled`, + :c:macro:`PyCursesInitialised`, and :c:macro:`PyCursesInitialisedColor`. + + .. note:: + + The number of entries in this structure is subject to changes. + Consider using :c:macro:`PyCurses_API_pointers` to check if + new fields are available or not. + + +.. c:macro:: PyCurses_API_pointers + + The number of accessible fields (``4``) in :c:var:`PyCurses_API`. + This number is incremented whenever new fields are added. + + +.. c:var:: PyTypeObject PyCursesWindow_Type + + The :ref:`heap type ` corresponding to :class:`curses.window`. + + +.. c:function:: int PyCursesWindow_Check(PyObject *op) + + Return true if *op* is a :class:`curses.window` instance, false otherwise. + + +The following macros are convenience macros expanding into C statements. +In particular, they can only be used as ``macro;`` or ``macro``, but not +``macro()`` or ``macro();``. + +.. c:macro:: PyCursesSetupTermCalled + + Macro checking if :func:`curses.setupterm` has been called. + + The macro expansion is roughly equivalent to: + + .. code-block:: + + { + typedef int (*predicate_t)(void); + predicate_t was_setupterm_called = (predicate_t)PyCurses_API[1]; + if (!was_setupterm_called()) { + return NULL; + } + } + + +.. c:macro:: PyCursesInitialised + + Macro checking if :func:`curses.initscr` has been called. + + The macro expansion is roughly equivalent to: + + .. code-block:: + + { + typedef int (*predicate_t)(void); + predicate_t was_initscr_called = (predicate_t)PyCurses_API[2]; + if (!was_initscr_called()) { + return NULL; + } + } + + +.. c:macro:: PyCursesInitialisedColor + + Macro checking if :func:`curses.start_color` has been called. + + The macro expansion is roughly equivalent to: + + .. code-block:: + + { + typedef int (*predicate_t)(void); + predicate_t was_start_color_called = (predicate_t)PyCurses_API[3]; + if (!was_start_color_called()) { + return NULL; + } + } + + +Internal data +------------- + +The following objects are exposed by the C API but should be considered +internal-only. + +.. c:macro:: PyCurses_CAPSULE_NAME + + Name of the curses capsule to pass to :c:func:`PyCapsule_Import`. + + Internal usage only. Use :c:macro:`import_curses` instead. + diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst index d2d4d5309c7..127d7c9c91a 100644 --- a/Doc/c-api/datetime.rst +++ b/Doc/c-api/datetime.rst @@ -8,11 +8,42 @@ DateTime Objects Various date and time objects are supplied by the :mod:`datetime` module. Before using any of these functions, the header file :file:`datetime.h` must be included in your source (note that this is not included by :file:`Python.h`), -and the macro :c:macro:`!PyDateTime_IMPORT` must be invoked, usually as part of +and the macro :c:macro:`PyDateTime_IMPORT` must be invoked, usually as part of the module initialisation function. The macro puts a pointer to a C structure -into a static variable, :c:data:`!PyDateTimeAPI`, that is used by the following +into a static variable, :c:data:`PyDateTimeAPI`, that is used by the following macros. +.. c:macro:: PyDateTime_IMPORT() + + Import the datetime C API. + + On success, populate the :c:var:`PyDateTimeAPI` pointer. + On failure, set :c:var:`PyDateTimeAPI` to ``NULL`` and set an exception. + The caller must check if an error occurred via :c:func:`PyErr_Occurred`: + + .. code-block:: + + PyDateTime_IMPORT; + if (PyErr_Occurred()) { /* cleanup */ } + + .. warning:: + + This is not compatible with subinterpreters. + +.. c:type:: PyDateTime_CAPI + + Structure containing the fields for the datetime C API. + + The fields of this structure are private and subject to change. + + Do not use this directly; prefer ``PyDateTime_*`` APIs instead. + +.. c:var:: PyDateTime_CAPI *PyDateTimeAPI + + Dynamically allocated object containing the datetime C API. + + This variable is only available once :c:macro:`PyDateTime_IMPORT` succeeds. + .. c:type:: PyDateTime_Date This subtype of :c:type:`PyObject` represents a Python date object. @@ -46,7 +77,7 @@ macros. .. c:var:: PyTypeObject PyDateTime_DeltaType - This instance of :c:type:`PyTypeObject` represents Python type for + This instance of :c:type:`PyTypeObject` represents the Python type for the difference between two datetime values; it is the same object as :class:`datetime.timedelta` in the Python layer. @@ -325,3 +356,16 @@ Macros for the convenience of modules implementing the DB API: Create and return a new :class:`datetime.date` object given an argument tuple suitable for passing to :meth:`datetime.date.fromtimestamp`. + + +Internal data +------------- + +The following symbols are exposed by the C API but should be considered +internal-only. + +.. c:macro:: PyDateTime_CAPSULE_NAME + + Name of the datetime capsule to pass to :c:func:`PyCapsule_Import`. + + Internal usage only. Use :c:macro:`PyDateTime_IMPORT` instead. diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst index b32c113e5f0..313c534545a 100644 --- a/Doc/c-api/descriptor.rst +++ b/Doc/c-api/descriptor.rst @@ -21,20 +21,104 @@ found in the dictionary of type objects. .. c:function:: PyObject* PyDescr_NewMember(PyTypeObject *type, struct PyMemberDef *meth) +.. c:var:: PyTypeObject PyMemberDescr_Type + + The type object for member descriptor objects created from + :c:type:`PyMemberDef` structures. These descriptors expose fields of a + C struct as attributes on a type, and correspond + to :class:`types.MemberDescriptorType` objects in Python. + + + +.. c:var:: PyTypeObject PyGetSetDescr_Type + + The type object for get/set descriptor objects created from + :c:type:`PyGetSetDef` structures. These descriptors implement attributes + whose value is computed by C getter and setter functions, and are used + for many built-in type attributes. + + .. c:function:: PyObject* PyDescr_NewMethod(PyTypeObject *type, struct PyMethodDef *meth) +.. c:var:: PyTypeObject PyMethodDescr_Type + + The type object for method descriptor objects created from + :c:type:`PyMethodDef` structures. These descriptors expose C functions as + methods on a type, and correspond to :class:`types.MemberDescriptorType` + objects in Python. + + .. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *wrapper, void *wrapped) +.. c:var:: PyTypeObject PyWrapperDescr_Type + + The type object for wrapper descriptor objects created by + :c:func:`PyDescr_NewWrapper` and :c:func:`PyWrapper_New`. Wrapper + descriptors are used internally to expose special methods implemented + via wrapper structures, and appear in Python as + :class:`types.WrapperDescriptorType` objects. + + .. c:function:: PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) .. c:function:: int PyDescr_IsData(PyObject *descr) - Return non-zero if the descriptor objects *descr* describes a data attribute, or + Return non-zero if the descriptor object *descr* describes a data attribute, or ``0`` if it describes a method. *descr* must be a descriptor object; there is no error checking. .. c:function:: PyObject* PyWrapper_New(PyObject *, PyObject *) + + +Built-in descriptors +^^^^^^^^^^^^^^^^^^^^ + +.. c:var:: PyTypeObject PySuper_Type + + The type object for super objects. This is the same object as + :class:`super` in the Python layer. + + +.. c:var:: PyTypeObject PyClassMethod_Type + + The type of class method objects. This is the same object as + :class:`classmethod` in the Python layer. + + +.. c:var:: PyTypeObject PyClassMethodDescr_Type + + The type object for C-level class method descriptor objects. + This is the type of the descriptors created for :func:`classmethod` defined in + C extension types, and is the same object as :class:`classmethod` + in Python. + + +.. c:function:: PyObject *PyClassMethod_New(PyObject *callable) + + Create a new :class:`classmethod` object wrapping *callable*. + *callable* must be a callable object and must not be ``NULL``. + + On success, this function returns a :term:`strong reference` to a new class + method descriptor. On failure, this function returns ``NULL`` with an + exception set. + + +.. c:var:: PyTypeObject PyStaticMethod_Type + + The type of static method objects. This is the same object as + :class:`staticmethod` in the Python layer. + + +.. c:function:: PyObject *PyStaticMethod_New(PyObject *callable) + + Create a new :class:`staticmethod` object wrapping *callable*. + *callable* must be a callable object and must not be ``NULL``. + + On success, this function returns a :term:`strong reference` to a new static + method descriptor. On failure, this function returns ``NULL`` with an + exception set. + diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 0fbe26b56c0..9c4428ced41 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -43,6 +43,17 @@ Dictionary Objects prevent modification of the dictionary for non-dynamic class types. +.. c:var:: PyTypeObject PyDictProxy_Type + + The type object for mapping proxy objects created by + :c:func:`PyDictProxy_New` and for the read-only ``__dict__`` attribute + of many built-in types. A :c:type:`PyDictProxy_Type` instance provides a + dynamic, read-only view of an underlying dictionary: changes to the + underlying dictionary are reflected in the proxy, but the proxy itself + does not support mutation operations. This corresponds to + :class:`types.MappingProxyType` in Python. + + .. c:function:: void PyDict_Clear(PyObject *p) Empty an existing dictionary of all key-value pairs. @@ -50,7 +61,7 @@ Dictionary Objects .. c:function:: int PyDict_Contains(PyObject *p, PyObject *key) - Determine if dictionary *p* contains *key*. If an item in *p* is matches + Determine if dictionary *p* contains *key*. If an item in *p* matches *key*, return ``1``, otherwise return ``0``. On error, return ``-1``. This is equivalent to the Python expression ``key in p``. @@ -198,7 +209,7 @@ Dictionary Objects .. c:function:: int PyDict_Pop(PyObject *p, PyObject *key, PyObject **result) Remove *key* from dictionary *p* and optionally return the removed value. - Do not raise :exc:`KeyError` if the key missing. + Do not raise :exc:`KeyError` if the key is missing. - If the key is present, set *\*result* to a new reference to the removed value if *result* is not ``NULL``, and return ``1``. @@ -207,7 +218,7 @@ Dictionary Objects - On error, raise an exception and return ``-1``. Similar to :meth:`dict.pop`, but without the default value and - not raising :exc:`KeyError` if the key missing. + not raising :exc:`KeyError` if the key is missing. .. versionadded:: 3.13 @@ -245,6 +256,11 @@ Dictionary Objects ``len(p)`` on a dictionary. +.. c:function:: Py_ssize_t PyDict_GET_SIZE(PyObject *p) + + Similar to :c:func:`PyDict_Size`, but without error checking. + + .. c:function:: int PyDict_Next(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue) Iterate over all key-value pairs in the dictionary *p*. The @@ -426,3 +442,138 @@ Dictionary Objects it before returning. .. versionadded:: 3.12 + + +Dictionary View Objects +^^^^^^^^^^^^^^^^^^^^^^^ + +.. c:function:: int PyDictViewSet_Check(PyObject *op) + + Return true if *op* is a view of a set inside a dictionary. This is currently + equivalent to :c:expr:`PyDictKeys_Check(op) || PyDictItems_Check(op)`. This + function always succeeds. + + +.. c:var:: PyTypeObject PyDictKeys_Type + + Type object for a view of dictionary keys. In Python, this is the type of + the object returned by :meth:`dict.keys`. + + +.. c:function:: int PyDictKeys_Check(PyObject *op) + + Return true if *op* is an instance of a dictionary keys view. This function + always succeeds. + + +.. c:var:: PyTypeObject PyDictValues_Type + + Type object for a view of dictionary values. In Python, this is the type of + the object returned by :meth:`dict.values`. + + +.. c:function:: int PyDictValues_Check(PyObject *op) + + Return true if *op* is an instance of a dictionary values view. This function + always succeeds. + + +.. c:var:: PyTypeObject PyDictItems_Type + + Type object for a view of dictionary items. In Python, this is the type of + the object returned by :meth:`dict.items`. + + +.. c:function:: int PyDictItems_Check(PyObject *op) + + Return true if *op* is an instance of a dictionary items view. This function + always succeeds. + + +Ordered Dictionaries +^^^^^^^^^^^^^^^^^^^^ + +Python's C API provides interface for :class:`collections.OrderedDict` from C. +Since Python 3.7, dictionaries are ordered by default, so there is usually +little need for these functions; prefer ``PyDict*`` where possible. + + +.. c:var:: PyTypeObject PyODict_Type + + Type object for ordered dictionaries. This is the same object as + :class:`collections.OrderedDict` in the Python layer. + + +.. c:function:: int PyODict_Check(PyObject *od) + + Return true if *od* is an ordered dictionary object or an instance of a + subtype of the :class:`~collections.OrderedDict` type. This function + always succeeds. + + +.. c:function:: int PyODict_CheckExact(PyObject *od) + + Return true if *od* is an ordered dictionary object, but not an instance of + a subtype of the :class:`~collections.OrderedDict` type. + This function always succeeds. + + +.. c:var:: PyTypeObject PyODictKeys_Type + + Analogous to :c:type:`PyDictKeys_Type` for ordered dictionaries. + + +.. c:var:: PyTypeObject PyODictValues_Type + + Analogous to :c:type:`PyDictValues_Type` for ordered dictionaries. + + +.. c:var:: PyTypeObject PyODictItems_Type + + Analogous to :c:type:`PyDictItems_Type` for ordered dictionaries. + + +.. c:function:: PyObject *PyODict_New(void) + + Return a new empty ordered dictionary, or ``NULL`` on failure. + + This is analogous to :c:func:`PyDict_New`. + + +.. c:function:: int PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value) + + Insert *value* into the ordered dictionary *od* with a key of *key*. + Return ``0`` on success or ``-1`` with an exception set on failure. + + This is analogous to :c:func:`PyDict_SetItem`. + + +.. c:function:: int PyODict_DelItem(PyObject *od, PyObject *key) + + Remove the entry in the ordered dictionary *od* with key *key*. + Return ``0`` on success or ``-1`` with an exception set on failure. + + This is analogous to :c:func:`PyDict_DelItem`. + + +These are :term:`soft deprecated` aliases to ``PyDict`` APIs: + + +.. list-table:: + :widths: auto + :header-rows: 1 + + * * ``PyODict`` + * ``PyDict`` + * * .. c:macro:: PyODict_GetItem(od, key) + * :c:func:`PyDict_GetItem` + * * .. c:macro:: PyODict_GetItemWithError(od, key) + * :c:func:`PyDict_GetItemWithError` + * * .. c:macro:: PyODict_GetItemString(od, key) + * :c:func:`PyDict_GetItemString` + * * .. c:macro:: PyODict_Contains(od, key) + * :c:func:`PyDict_Contains` + * * .. c:macro:: PyODict_Size(od) + * :c:func:`PyDict_Size` + * * .. c:macro:: PyODict_SIZE(od) + * :c:func:`PyDict_GET_SIZE` diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 3ff4631a8e5..d7fe9e2c9ec 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -309,6 +309,14 @@ For convenience, some of these functions will always return a .. versionadded:: 3.4 +.. c:function:: void PyErr_RangedSyntaxLocationObject(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset) + + Similar to :c:func:`PyErr_SyntaxLocationObject`, but also sets the + *end_lineno* and *end_col_offset* information for the current exception. + + .. versionadded:: 3.10 + + .. c:function:: void PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset) Like :c:func:`PyErr_SyntaxLocationObject`, but *filename* is a byte string @@ -331,6 +339,23 @@ For convenience, some of these functions will always return a use. +.. c:function:: PyObject *PyErr_ProgramTextObject(PyObject *filename, int lineno) + + Get the source line in *filename* at line *lineno*. *filename* should be a + Python :class:`str` object. + + On success, this function returns a Python string object with the found line. + On failure, this function returns ``NULL`` without an exception set. + + +.. c:function:: PyObject *PyErr_ProgramText(const char *filename, int lineno) + + Similar to :c:func:`PyErr_ProgramTextObject`, but *filename* is a + :c:expr:`const char *`, which is decoded with the + :term:`filesystem encoding and error handler`, instead of a + Python object reference. + + Issuing warnings ================ @@ -394,6 +419,15 @@ an error value). .. versionadded:: 3.2 +.. c:function:: int PyErr_WarnExplicitFormat(PyObject *category, const char *filename, int lineno, const char *module, PyObject *registry, const char *format, ...) + + Similar to :c:func:`PyErr_WarnExplicit`, but uses + :c:func:`PyUnicode_FromFormat` to format the warning message. *format* is + an ASCII-encoded string. + + .. versionadded:: 3.2 + + .. c:function:: int PyErr_ResourceWarning(PyObject *source, Py_ssize_t stack_level, const char *format, ...) Function similar to :c:func:`PyErr_WarnFormat`, but *category* is @@ -762,6 +796,17 @@ Exception Classes Exception Objects ================= +.. c:function:: int PyExceptionInstance_Check(PyObject *op) + + Return true if *op* is an instance of :class:`BaseException`, false + otherwise. This function always succeeds. + + +.. c:macro:: PyExceptionInstance_Class(op) + + Equivalent to :c:func:`Py_TYPE(op) `. + + .. c:function:: PyObject* PyException_GetTraceback(PyObject *ex) Return the traceback associated with the exception as a new reference, as @@ -939,6 +984,9 @@ because the :ref:`call protocol ` takes care of recursion handling. be concatenated to the :exc:`RecursionError` message caused by the recursion depth limit. + .. seealso:: + The :c:func:`PyUnstable_ThreadState_SetStackProtection` function. + .. versionchanged:: 3.9 This function is now also available in the :ref:`limited API `. @@ -979,6 +1027,27 @@ these are the C equivalent to :func:`reprlib.recursive_repr`. Ends a :c:func:`Py_ReprEnter`. Must be called once for each invocation of :c:func:`Py_ReprEnter` that returns zero. +.. c:function:: int Py_GetRecursionLimit(void) + + Get the recursion limit for the current interpreter. It can be set with + :c:func:`Py_SetRecursionLimit`. The recursion limit prevents the + Python interpreter stack from growing infinitely. + + This function cannot fail, and the caller must hold an + :term:`attached thread state`. + + .. seealso:: + :py:func:`sys.getrecursionlimit` + +.. c:function:: void Py_SetRecursionLimit(int new_limit) + + Set the recursion limit for the current interpreter. + + This function cannot fail, and the caller must hold an + :term:`attached thread state`. + + .. seealso:: + :py:func:`sys.setrecursionlimit` .. _standardexceptions: @@ -1207,3 +1276,37 @@ Warning types .. versionadded:: 3.10 :c:data:`PyExc_EncodingWarning`. + + +Tracebacks +========== + +.. c:var:: PyTypeObject PyTraceBack_Type + + Type object for traceback objects. This is available as + :class:`types.TracebackType` in the Python layer. + + +.. c:function:: int PyTraceBack_Check(PyObject *op) + + Return true if *op* is a traceback object, false otherwise. This function + does not account for subtypes. + + +.. c:function:: int PyTraceBack_Here(PyFrameObject *f) + + Replace the :attr:`~BaseException.__traceback__` attribute on the current + exception with a new traceback prepending *f* to the existing chain. + + Calling this function without an exception set is undefined behavior. + + This function returns ``0`` on success, and returns ``-1`` with an + exception set on failure. + + +.. c:function:: int PyTraceBack_Print(PyObject *tb, PyObject *f) + + Write the traceback *tb* into the file *f*. + + This function returns ``0`` on success, and returns ``-1`` with an + exception set on failure. diff --git a/Doc/c-api/extension-modules.rst b/Doc/c-api/extension-modules.rst index 3d331e6ec12..92b531665e1 100644 --- a/Doc/c-api/extension-modules.rst +++ b/Doc/c-api/extension-modules.rst @@ -8,7 +8,8 @@ Defining extension modules A C extension for CPython is a shared library (for example, a ``.so`` file on Linux, ``.pyd`` DLL on Windows), which is loadable into the Python process (for example, it is compiled with compatible compiler settings), and which -exports an :ref:`initialization function `. +exports an :dfn:`export hook` function (or an +old-style :ref:`initialization function `). To be importable by default (that is, by :py:class:`importlib.machinery.ExtensionFileLoader`), @@ -23,25 +24,127 @@ and must be named after the module name plus an extension listed in One suitable tool is Setuptools, whose documentation can be found at https://setuptools.pypa.io/en/latest/setuptools.html. -Normally, the initialization function returns a module definition initialized -using :c:func:`PyModuleDef_Init`. -This allows splitting the creation process into several phases: +.. _extension-export-hook: +Extension export hook +..................... + +.. versionadded:: 3.15 + + Support for the :samp:`PyModExport_{}` export hook was added in Python + 3.15. The older way of defining modules is still available: consult either + the :ref:`extension-pyinit` section or earlier versions of this + documentation if you plan to support earlier Python versions. + +The export hook must be an exported function with the following signature: + +.. c:function:: PyModuleDef_Slot *PyModExport_modulename(void) + +For modules with ASCII-only names, the :ref:`export hook ` +must be named :samp:`PyModExport_{}`, +with ```` replaced by the module's name. + +For non-ASCII module names, the export hook must instead be named +:samp:`PyModExportU_{}` (note the ``U``), with ```` encoded using +Python's *punycode* encoding with hyphens replaced by underscores. In Python: + +.. code-block:: python + + def hook_name(name): + try: + suffix = b'_' + name.encode('ascii') + except UnicodeEncodeError: + suffix = b'U_' + name.encode('punycode').replace(b'-', b'_') + return b'PyModExport' + suffix + +The export hook returns an array of :c:type:`PyModuleDef_Slot` entries, +terminated by an entry with a slot ID of ``0``. +These slots describe how the module should be created and initialized. + +This array must remain valid and constant until interpreter shutdown. +Typically, it should use ``static`` storage. +Prefer using the :c:macro:`Py_mod_create` and :c:macro:`Py_mod_exec` slots +for any dynamic behavior. + +The export hook may return ``NULL`` with an exception set to signal failure. + +It is recommended to define the export hook function using a helper macro: + +.. c:macro:: PyMODEXPORT_FUNC + + Declare an extension module export hook. + This macro: + + * specifies the :c:expr:`PyModuleDef_Slot*` return type, + * adds any special linkage declarations required by the platform, and + * for C++, declares the function as ``extern "C"``. + +For example, a module called ``spam`` would be defined like this:: + + PyABIInfo_VAR(abi_info); + + static PyModuleDef_Slot spam_slots[] = { + {Py_mod_abi, &abi_info}, + {Py_mod_name, "spam"}, + {Py_mod_init, spam_init_function}, + ... + {0, NULL}, + }; + + PyMODEXPORT_FUNC + PyModExport_spam(void) + { + return spam_slots; + } + +The export hook is typically the only non-\ ``static`` +item defined in the module's C source. + +The hook should be kept short -- ideally, one line as above. +If you do need to use Python C API in this function, it is recommended to call +``PyABIInfo_Check(&abi_info, "modulename")`` first to raise an exception, +rather than crash, in common cases of ABI mismatch. + + +.. note:: + + It is possible to export multiple modules from a single shared library by + defining multiple export hooks. + However, importing them requires a custom importer or suitably named + copies/links of the extension file, because Python's import machinery only + finds the function corresponding to the filename. + See the `Multiple modules in one library `__ + section in :pep:`489` for details. + + +.. _multi-phase-initialization: + +Multi-phase initialization +.......................... + +The process of creating an extension module follows several phases: + +- Python finds and calls the export hook to get information on how to + create the module. - Before any substantial code is executed, Python can determine which capabilities the module supports, and it can adjust the environment or refuse loading an incompatible extension. -- By default, Python itself creates the module object -- that is, it does - the equivalent of :py:meth:`object.__new__` for classes. - It also sets initial attributes like :attr:`~module.__package__` and - :attr:`~module.__loader__`. -- Afterwards, the module object is initialized using extension-specific - code -- the equivalent of :py:meth:`~object.__init__` on classes. + Slots like :c:data:`Py_mod_abi`, :c:data:`Py_mod_gil` and + :c:data:`Py_mod_multiple_interpreters` influence this step. +- By default, Python itself then creates the module object -- that is, it does + the equivalent of calling :py:meth:`~object.__new__` when creating an object. + This step can be overridden using the :c:data:`Py_mod_create` slot. +- Python sets initial module attributes like :attr:`~module.__package__` and + :attr:`~module.__loader__`, and inserts the module object into + :py:attr:`sys.modules`. +- Afterwards, the module object is initialized in an extension-specific way + -- the equivalent of :py:meth:`~object.__init__` when creating an object, + or of executing top-level code in a Python-language module. + The behavior is specified using the :c:data:`Py_mod_exec` slot. This is called *multi-phase initialization* to distinguish it from the legacy -(but still supported) *single-phase initialization* scheme, -where the initialization function returns a fully constructed module. -See the :ref:`single-phase-initialization section below ` -for details. +(but still supported) :ref:`single-phase initialization `, +where an initialization function returns a fully constructed module. .. versionchanged:: 3.5 @@ -53,7 +156,7 @@ Multiple module instances By default, extension modules are not singletons. For example, if the :py:attr:`sys.modules` entry is removed and the module -is re-imported, a new module object is created, and typically populated with +is re-imported, a new module object is created and, typically, populated with fresh method and type objects. The old module is subject to normal garbage collection. This mirrors the behavior of pure-Python modules. @@ -83,36 +186,34 @@ A module may also be limited to the main interpreter using the :c:data:`Py_mod_multiple_interpreters` slot. -.. _extension-export-hook: +.. _extension-pyinit: -Initialization function -....................... +``PyInit`` function +................... -The initialization function defined by an extension module has the -following signature: +.. deprecated:: 3.15 + + This functionality is :term:`soft deprecated`. + It will not get new features, but there are no plans to remove it. + +Instead of :c:func:`PyModExport_modulename`, an extension module can define +an older-style :dfn:`initialization function` with the signature: .. c:function:: PyObject* PyInit_modulename(void) Its name should be :samp:`PyInit_{}`, with ```` replaced by the name of the module. +For non-ASCII module names, use :samp:`PyInitU_{}` instead, with +```` encoded in the same way as for the +:ref:`export hook ` (that is, using Punycode +with underscores). -For modules with ASCII-only names, the function must instead be named -:samp:`PyInit_{}`, with ```` replaced by the name of the module. -When using :ref:`multi-phase-initialization`, non-ASCII module names -are allowed. In this case, the initialization function name is -:samp:`PyInitU_{}`, with ```` encoded using Python's -*punycode* encoding with hyphens replaced by underscores. In Python: +If a module exports both :samp:`PyInit_{}` and +:samp:`PyModExport_{}`, the :samp:`PyInit_{}` function +is ignored. -.. code-block:: python - - def initfunc_name(name): - try: - suffix = b'_' + name.encode('ascii') - except UnicodeEncodeError: - suffix = b'U_' + name.encode('punycode').replace(b'-', b'_') - return b'PyInit' + suffix - -It is recommended to define the initialization function using a helper macro: +Like with :c:macro:`PyMODEXPORT_FUNC`, it is recommended to define the +initialization function using a helper macro: .. c:macro:: PyMODINIT_FUNC @@ -123,6 +224,34 @@ It is recommended to define the initialization function using a helper macro: * adds any special linkage declarations required by the platform, and * for C++, declares the function as ``extern "C"``. + +Normally, the initialization function (``PyInit_modulename``) returns +a :c:type:`PyModuleDef` instance with non-``NULL`` +:c:member:`~PyModuleDef.m_slots`. This allows Python to use +:ref:`multi-phase initialization `. + +Before it is returned, the ``PyModuleDef`` instance must be initialized +using the following function: + +.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def) + + Ensure a module definition is a properly initialized Python object that + correctly reports its type and a reference count. + + Return *def* cast to ``PyObject*``, or ``NULL`` if an error occurred. + + Calling this function is required before returning a :c:type:`PyModuleDef` + from a module initialization function. + It should not be used in other contexts. + + Note that Python assumes that ``PyModuleDef`` structures are statically + allocated. + This function may return either a new reference or a borrowed one; + this reference must not be released. + + .. versionadded:: 3.5 + + For example, a module called ``spam`` would be defined like this:: static struct PyModuleDef spam_module = { @@ -137,59 +266,23 @@ For example, a module called ``spam`` would be defined like this:: return PyModuleDef_Init(&spam_module); } -It is possible to export multiple modules from a single shared library by -defining multiple initialization functions. However, importing them requires -using symbolic links or a custom importer, because by default only the -function corresponding to the filename is found. -See the `Multiple modules in one library `__ -section in :pep:`489` for details. - -The initialization function is typically the only non-\ ``static`` -item defined in the module's C source. - - -.. _multi-phase-initialization: - -Multi-phase initialization -.......................... - -Normally, the :ref:`initialization function ` -(``PyInit_modulename``) returns a :c:type:`PyModuleDef` instance with -non-``NULL`` :c:member:`~PyModuleDef.m_slots`. -Before it is returned, the ``PyModuleDef`` instance must be initialized -using the following function: - - -.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def) - - Ensure a module definition is a properly initialized Python object that - correctly reports its type and a reference count. - - Return *def* cast to ``PyObject*``, or ``NULL`` if an error occurred. - - Calling this function is required for :ref:`multi-phase-initialization`. - It should not be used in other contexts. - - Note that Python assumes that ``PyModuleDef`` structures are statically - allocated. - This function may return either a new reference or a borrowed one; - this reference must not be released. - - .. versionadded:: 3.5 - .. _single-phase-initialization: Legacy single-phase initialization -.................................. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. attention:: - Single-phase initialization is a legacy mechanism to initialize extension +.. deprecated:: 3.15 + + Single-phase initialization is :term:`soft deprecated`. + It is a legacy mechanism to initialize extension modules, with known drawbacks and design flaws. Extension module authors are encouraged to use multi-phase initialization instead. -In single-phase initialization, the -:ref:`initialization function ` (``PyInit_modulename``) + However, there are no plans to remove support for it. + +In single-phase initialization, the old-style +:ref:`initialization function ` (``PyInit_modulename``) should create, populate and return a module object. This is typically done using :c:func:`PyModule_Create` and functions like :c:func:`PyModule_AddObjectRef`. @@ -242,6 +335,8 @@ in the following ways: * Single-phase modules support module lookup functions like :c:func:`PyState_FindModule`. +* The module's :c:member:`PyModuleDef.m_slots` must be NULL. + .. [#testsinglephase] ``_testsinglephase`` is an internal module used in CPython's self-test suite; your installation may or may not include it. diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index e9019a0d500..9d01254ddb2 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -93,6 +93,29 @@ the :mod:`io` APIs instead. .. versionadded:: 3.8 +.. c:function:: PyObject *PyFile_OpenCodeObject(PyObject *path) + + Open *path* with the mode ``'rb'``. *path* must be a Python :class:`str` + object. The behavior of this function may be overridden by + :c:func:`PyFile_SetOpenCodeHook` to allow for some preprocessing of the + text. + + This is analogous to :func:`io.open_code` in Python. + + On success, this function returns a :term:`strong reference` to a Python + file object. On failure, this function returns ``NULL`` with an exception + set. + + .. versionadded:: 3.8 + + +.. c:function:: PyObject *PyFile_OpenCode(const char *path) + + Similar to :c:func:`PyFile_OpenCodeObject`, but *path* is a + UTF-8 encoded :c:expr:`const char*`. + + .. versionadded:: 3.8 + .. c:function:: int PyFile_WriteObject(PyObject *obj, PyObject *p, int flags) diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 489676caa3a..b0d440580b9 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -78,6 +78,111 @@ Floating-Point Objects Return the minimum normalized positive float *DBL_MIN* as C :c:expr:`double`. +.. c:macro:: Py_INFINITY + + This macro expands a to constant expression of type :c:expr:`double`, that + represents the positive infinity. + + It is equivalent to the :c:macro:`!INFINITY` macro from the C11 standard + ```` header. + + .. deprecated:: 3.15 + The macro is :term:`soft deprecated`. + + +.. c:macro:: Py_NAN + + This macro expands a to constant expression of type :c:expr:`double`, that + represents a quiet not-a-number (qNaN) value. + + On most platforms, this is equivalent to the :c:macro:`!NAN` macro from + the C11 standard ```` header. + + +.. c:macro:: Py_HUGE_VAL + + Equivalent to :c:macro:`!INFINITY`. + + .. deprecated:: 3.14 + The macro is :term:`soft deprecated`. + + +.. c:macro:: Py_MATH_E + + The definition (accurate for a :c:expr:`double` type) of the :data:`math.e` constant. + + +.. c:macro:: Py_MATH_El + + High precision (long double) definition of :data:`~math.e` constant. + + .. deprecated-removed:: 3.15 3.20 + + +.. c:macro:: Py_MATH_PI + + The definition (accurate for a :c:expr:`double` type) of the :data:`math.pi` constant. + + +.. c:macro:: Py_MATH_PIl + + High precision (long double) definition of :data:`~math.pi` constant. + + .. deprecated-removed:: 3.15 3.20 + + +.. c:macro:: Py_MATH_TAU + + The definition (accurate for a :c:expr:`double` type) of the :data:`math.tau` constant. + + .. versionadded:: 3.6 + + +.. c:macro:: Py_RETURN_NAN + + Return :data:`math.nan` from a function. + + On most platforms, this is equivalent to ``return PyFloat_FromDouble(NAN)``. + + +.. c:macro:: Py_RETURN_INF(sign) + + Return :data:`math.inf` or :data:`-math.inf ` from a function, + depending on the sign of *sign*. + + On most platforms, this is equivalent to the following:: + + return PyFloat_FromDouble(copysign(INFINITY, sign)); + + +.. c:macro:: Py_IS_FINITE(X) + + Return ``1`` if the given floating-point number *X* is finite, + that is, it is normal, subnormal or zero, but not infinite or NaN. + Return ``0`` otherwise. + + .. deprecated:: 3.14 + The macro is :term:`soft deprecated`. Use :c:macro:`!isfinite` instead. + + +.. c:macro:: Py_IS_INFINITY(X) + + Return ``1`` if the given floating-point number *X* is positive or negative + infinity. Return ``0`` otherwise. + + .. deprecated:: 3.14 + The macro is :term:`soft deprecated`. Use :c:macro:`!isinf` instead. + + +.. c:macro:: Py_IS_NAN(X) + + Return ``1`` if the given floating-point number *X* is a not-a-number (NaN) + value. Return ``0`` otherwise. + + .. deprecated:: 3.14 + The macro is :term:`soft deprecated`. Use :c:macro:`!isnan` instead. + + Pack and Unpack functions ------------------------- @@ -96,8 +201,8 @@ NaNs (if such things exist on the platform) isn't handled correctly, and attempting to unpack a bytes string containing an IEEE INF or NaN will raise an exception. -Note that NaNs type may not be preserved on IEEE platforms (silent NaN become -quiet), for example on x86 systems in 32-bit mode. +Note that NaNs type may not be preserved on IEEE platforms (signaling NaN become +quiet NaN), for example on x86 systems in 32-bit mode. On non-IEEE platforms with more precision, or larger dynamic range, than IEEE 754 supports, not all values can be packed; on non-IEEE platforms with less diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst index 1a52e146a69..fb17cf7f1da 100644 --- a/Doc/c-api/frame.rst +++ b/Doc/c-api/frame.rst @@ -29,6 +29,12 @@ See also :ref:`Reflection `. Previously, this type was only available after including ````. +.. c:function:: PyFrameObject *PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, PyObject *locals) + + Create a new frame object. This function returns a :term:`strong reference` + to the new frame object on success, and returns ``NULL`` with an exception + set on failure. + .. c:function:: int PyFrame_Check(PyObject *obj) Return non-zero if *obj* is a frame object. @@ -161,6 +167,57 @@ See :pep:`667` for more information. Return non-zero if *obj* is a frame :func:`locals` proxy. + +Legacy Local Variable APIs +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These APIs are :term:`soft deprecated`. As of Python 3.13, they do nothing. +They exist solely for backwards compatibility. + + +.. c:function:: void PyFrame_LocalsToFast(PyFrameObject *f, int clear) + + This function is :term:`soft deprecated` and does nothing. + + Prior to Python 3.13, this function would copy the :attr:`~frame.f_locals` + attribute of *f* to the internal "fast" array of local variables, allowing + changes in frame objects to be visible to the interpreter. If *clear* was + true, this function would process variables that were unset in the locals + dictionary. + + .. versionchanged:: 3.13 + This function now does nothing. + + +.. c:function:: void PyFrame_FastToLocals(PyFrameObject *f) + + This function is :term:`soft deprecated` and does nothing. + + Prior to Python 3.13, this function would copy the internal "fast" array + of local variables (which is used by the interpreter) to the + :attr:`~frame.f_locals` attribute of *f*, allowing changes in local + variables to be visible to frame objects. + + .. versionchanged:: 3.13 + This function now does nothing. + + +.. c:function:: int PyFrame_FastToLocalsWithError(PyFrameObject *f) + + This function is :term:`soft deprecated` and does nothing. + + Prior to Python 3.13, this function was similar to + :c:func:`PyFrame_FastToLocals`, but would return ``0`` on success, and + ``-1`` with an exception set on failure. + + .. versionchanged:: 3.13 + This function now does nothing. + + +.. seealso:: + :pep:`667` + + Internal Frames ^^^^^^^^^^^^^^^ diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst index 5fb8567ef8c..609b5e885b6 100644 --- a/Doc/c-api/function.rst +++ b/Doc/c-api/function.rst @@ -102,6 +102,15 @@ There are a few functions specific to Python functions. dictionary of arguments or ``NULL``. +.. c:function:: int PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults) + + Set the keyword-only argument default values of the function object *op*. + *defaults* must be a dictionary of keyword-only arguments or ``Py_None``. + + This function returns ``0`` on success, and returns ``-1`` with an exception + set on failure. + + .. c:function:: PyObject* PyFunction_GetClosure(PyObject *op) Return the closure associated with the function object *op*. This can be ``NULL`` @@ -175,6 +184,9 @@ There are a few functions specific to Python functions. .. versionadded:: 3.12 + - ``PyFunction_PYFUNC_EVENT_MODIFY_QUALNAME`` + + .. versionadded:: 3.15 .. c:type:: int (*PyFunction_WatchCallback)(PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value) @@ -197,7 +209,7 @@ There are a few functions specific to Python functions. runtime behavior depending on optimization decisions, it does not change the semantics of the Python code being executed. - If *event* is ``PyFunction_EVENT_DESTROY``, Taking a reference in the + If *event* is ``PyFunction_EVENT_DESTROY``, taking a reference in the callback to the about-to-be-destroyed function will resurrect it, preventing it from being freed at this time. When the resurrected object is destroyed later, any watcher callbacks active at that time will be called again. diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index f6fa52b36c5..fed795b1e8c 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -232,6 +232,10 @@ The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type: object argument. If *visit* returns a non-zero value that value should be returned immediately. + The traversal function must not have any side effects. Implementations + may not modify the reference counts of any Python objects nor create or + destroy any Python objects. + To simplify writing :c:member:`~PyTypeObject.tp_traverse` handlers, a :c:func:`Py_VISIT` macro is provided. In order to use this macro, the :c:member:`~PyTypeObject.tp_traverse` implementation must name its arguments exactly *visit* and *arg*: diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst index 0eb5922f6da..44f3bdbf959 100644 --- a/Doc/c-api/gen.rst +++ b/Doc/c-api/gen.rst @@ -44,3 +44,41 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. with ``__name__`` and ``__qualname__`` set to *name* and *qualname*. A reference to *frame* is stolen by this function. The *frame* argument must not be ``NULL``. + +.. c:function:: PyCodeObject* PyGen_GetCode(PyGenObject *gen) + + Return a new :term:`strong reference` to the code object wrapped by *gen*. + This function always succeeds. + + +Asynchronous Generator Objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. seealso:: + :pep:`525` + +.. c:var:: PyTypeObject PyAsyncGen_Type + + The type object corresponding to asynchronous generator objects. This is + available as :class:`types.AsyncGeneratorType` in the Python layer. + + .. versionadded:: 3.6 + +.. c:function:: PyObject *PyAsyncGen_New(PyFrameObject *frame, PyObject *name, PyObject *qualname) + + Create a new asynchronous generator wrapping *frame*, with ``__name__`` and + ``__qualname__`` set to *name* and *qualname*. *frame* is stolen by this + function and must not be ``NULL``. + + On success, this function returns a :term:`strong reference` to the + new asynchronous generator. On failure, this function returns ``NULL`` + with an exception set. + + .. versionadded:: 3.6 + +.. c:function:: int PyAsyncGen_CheckExact(PyObject *op) + + Return true if *op* is an asynchronous generator object, false otherwise. + This function always succeeds. + + .. versionadded:: 3.6 diff --git a/Doc/c-api/hash.rst b/Doc/c-api/hash.rst index b5fe93573a1..1ad712b0ce4 100644 --- a/Doc/c-api/hash.rst +++ b/Doc/c-api/hash.rst @@ -11,42 +11,98 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`. .. versionadded:: 3.2 + .. c:type:: Py_uhash_t Hash value type: unsigned integer. .. versionadded:: 3.2 + +.. c:macro:: Py_HASH_ALGORITHM + + A numerical value indicating the algorithm for hashing of :class:`str`, + :class:`bytes`, and :class:`memoryview`. + + The algorithm name is exposed by :data:`sys.hash_info.algorithm`. + + .. versionadded:: 3.4 + + +.. c:macro:: Py_HASH_FNV + Py_HASH_SIPHASH24 + Py_HASH_SIPHASH13 + + Numerical values to compare to :c:macro:`Py_HASH_ALGORITHM` to determine + which algorithm is used for hashing. The hash algorithm can be configured + via the configure :option:`--with-hash-algorithm` option. + + .. versionadded:: 3.4 + Add :c:macro:`!Py_HASH_FNV` and :c:macro:`!Py_HASH_SIPHASH24`. + + .. versionadded:: 3.11 + Add :c:macro:`!Py_HASH_SIPHASH13`. + + +.. c:macro:: Py_HASH_CUTOFF + + Buffers of length in range ``[1, Py_HASH_CUTOFF)`` are hashed using DJBX33A + instead of the algorithm described by :c:macro:`Py_HASH_ALGORITHM`. + + - A :c:macro:`!Py_HASH_CUTOFF` of 0 disables the optimization. + - :c:macro:`!Py_HASH_CUTOFF` must be non-negative and less or equal than 7. + + 32-bit platforms should use a cutoff smaller than 64-bit platforms because + it is easier to create colliding strings. A cutoff of 7 on 64-bit platforms + and 5 on 32-bit platforms should provide a decent safety margin. + + This corresponds to the :data:`sys.hash_info.cutoff` constant. + + .. versionadded:: 3.4 + + .. c:macro:: PyHASH_MODULUS - The `Mersenne prime `_ ``P = 2**n -1``, used for numeric hash scheme. + The `Mersenne prime `_ ``P = 2**n -1``, + used for numeric hash scheme. + + This corresponds to the :data:`sys.hash_info.modulus` constant. .. versionadded:: 3.13 + .. c:macro:: PyHASH_BITS The exponent ``n`` of ``P`` in :c:macro:`PyHASH_MODULUS`. .. versionadded:: 3.13 + .. c:macro:: PyHASH_MULTIPLIER Prime multiplier used in string and various other hashes. .. versionadded:: 3.13 + .. c:macro:: PyHASH_INF The hash value returned for a positive infinity. + This corresponds to the :data:`sys.hash_info.inf` constant. + .. versionadded:: 3.13 + .. c:macro:: PyHASH_IMAG The multiplier used for the imaginary part of a complex number. + This corresponds to the :data:`sys.hash_info.imag` constant. + .. versionadded:: 3.13 + .. c:type:: PyHash_FuncDef Hash function definition used by :c:func:`PyHash_GetFuncDef`. @@ -59,14 +115,20 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`. Hash function name (UTF-8 encoded string). + This corresponds to the :data:`sys.hash_info.algorithm` constant. + .. c:member:: const int hash_bits Internal size of the hash value in bits. + This corresponds to the :data:`sys.hash_info.hash_bits` constant. + .. c:member:: const int seed_bits Size of seed input in bits. + This corresponds to the :data:`sys.hash_info.seed_bits` constant. + .. versionadded:: 3.4 diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 8eabc0406b1..a28c0713dd3 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -129,8 +129,7 @@ Importing Modules of :class:`~importlib.machinery.SourceFileLoader` otherwise. The module's :attr:`~module.__file__` attribute will be set to the code - object's :attr:`~codeobject.co_filename`. If applicable, - :attr:`~module.__cached__` will also be set. + object's :attr:`~codeobject.co_filename`. This function will reload the module if it was already imported. See :c:func:`PyImport_ReloadModule` for the intended way to reload a module. @@ -142,10 +141,13 @@ Importing Modules :c:func:`PyImport_ExecCodeModuleWithPathnames`. .. versionchanged:: 3.12 - The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__` + The setting of ``__cached__`` and :attr:`~module.__loader__` is deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + .. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) @@ -157,16 +159,19 @@ Importing Modules .. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname) - Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__` - attribute of the module object is set to *cpathname* if it is - non-``NULL``. Of the three functions, this is the preferred one to use. + Like :c:func:`PyImport_ExecCodeModuleEx`, but the path to any compiled file + via *cpathname* is used appropriately when non-``NULL``. Of the three + functions, this is the preferred one to use. .. versionadded:: 3.3 .. versionchanged:: 3.12 - Setting :attr:`~module.__cached__` is deprecated. See + Setting ``__cached__`` is deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. + .. versionchanged:: 3.15 + ``__cached__`` no longer set. + .. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname) @@ -314,6 +319,13 @@ Importing Modules initialization. +.. c:var:: struct _inittab *PyImport_Inittab + + The table of built-in modules used by Python initialization. Do not use this directly; + use :c:func:`PyImport_AppendInittab` and :c:func:`PyImport_ExtendInittab` + instead. + + .. c:function:: PyObject* PyImport_ImportModuleAttr(PyObject *mod_name, PyObject *attr_name) Import the module *mod_name* and get its attribute *attr_name*. @@ -333,3 +345,24 @@ Importing Modules strings instead of Python :class:`str` objects. .. versionadded:: 3.14 + +.. c:function:: PyObject* PyImport_CreateModuleFromInitfunc(PyObject *spec, PyObject* (*initfunc)(void)) + + This function is a building block that enables embedders to implement + the :py:meth:`~importlib.abc.Loader.create_module` step of custom + static extension importers (e.g. of statically-linked extensions). + + *spec* must be a :class:`~importlib.machinery.ModuleSpec` object. + + *initfunc* must be an :ref:`initialization function `, + the same as for :c:func:`PyImport_AppendInittab`. + + On success, create and return a module object. + This module will not be initialized; call :c:func:`PyModule_Exec` + to initialize it. + (Custom importers should do this in their + :py:meth:`~importlib.abc.Loader.exec_module` method.) + + On error, return NULL with an exception set. + + .. versionadded:: 3.15 diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index b99988f743d..7411644f9e1 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -41,7 +41,6 @@ The following functions can be safely called before Python is initialized: * :c:func:`PyObject_SetArenaAllocator` * :c:func:`Py_SetProgramName` * :c:func:`Py_SetPythonHome` - * :c:func:`PySys_ResetWarnOptions` * the configuration functions covered in :ref:`init-config` * Informative functions: @@ -1020,6 +1019,12 @@ code, or when embedding the Python interpreter: interpreter lock is also shared by all threads, regardless of to which interpreter they belong. + .. versionchanged:: 3.12 + + :pep:`684` introduced the possibility + of a :ref:`per-interpreter GIL `. + See :c:func:`Py_NewInterpreterFromConfig`. + .. c:type:: PyThreadState @@ -1108,7 +1113,7 @@ code, or when embedding the Python interpreter: This function is safe to call without an :term:`attached thread state`; it will simply return ``NULL`` indicating that there was no prior thread state. - .. seealso: + .. seealso:: :c:func:`PyEval_ReleaseThread` .. note:: @@ -1119,6 +1124,19 @@ code, or when embedding the Python interpreter: The following functions use thread-local storage, and are not compatible with sub-interpreters: +.. c:type:: PyGILState_STATE + + The type of the value returned by :c:func:`PyGILState_Ensure` and passed to + :c:func:`PyGILState_Release`. + + .. c:enumerator:: PyGILState_LOCKED + + The GIL was already held when :c:func:`PyGILState_Ensure` was called. + + .. c:enumerator:: PyGILState_UNLOCKED + + The GIL was not held when :c:func:`PyGILState_Ensure` was called. + .. c:function:: PyGILState_STATE PyGILState_Ensure() Ensure that the current thread is ready to call the Python C API regardless @@ -1169,12 +1187,12 @@ with sub-interpreters: made on the main thread. This is mainly a helper/diagnostic function. .. note:: - This function does not account for :term:`thread states ` created - by something other than :c:func:`PyGILState_Ensure` (such as :c:func:`PyThreadState_New`). + This function may return non-``NULL`` even when the :term:`thread state` + is detached. Prefer :c:func:`PyThreadState_Get` or :c:func:`PyThreadState_GetUnchecked` for most cases. - .. seealso: :c:func:`PyThreadState_Get`` + .. seealso:: :c:func:`PyThreadState_Get` .. c:function:: int PyGILState_Check() @@ -1273,11 +1291,11 @@ All of the following functions must be called after :c:func:`Py_Initialize`. must be :term:`attached ` .. versionchanged:: 3.9 - This function now calls the :c:member:`PyThreadState.on_delete` callback. + This function now calls the :c:member:`!PyThreadState.on_delete` callback. Previously, that happened in :c:func:`PyThreadState_Delete`. .. versionchanged:: 3.13 - The :c:member:`PyThreadState.on_delete` callback was removed. + The :c:member:`!PyThreadState.on_delete` callback was removed. .. c:function:: void PyThreadState_Delete(PyThreadState *tstate) @@ -1348,6 +1366,43 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.11 +.. c:function:: int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size) + + Set the stack protection start address and stack protection size + of a Python thread state. + + On success, return ``0``. + On failure, set an exception and return ``-1``. + + CPython implements :ref:`recursion control ` for C code by raising + :py:exc:`RecursionError` when it notices that the machine execution stack is close + to overflow. See for example the :c:func:`Py_EnterRecursiveCall` function. + For this, it needs to know the location of the current thread's stack, which it + normally gets from the operating system. + When the stack is changed, for example using context switching techniques like the + Boost library's ``boost::context``, you must call + :c:func:`~PyUnstable_ThreadState_SetStackProtection` to inform CPython of the change. + + Call :c:func:`~PyUnstable_ThreadState_SetStackProtection` either before + or after changing the stack. + Do not call any other Python C API between the call and the stack + change. + + See :c:func:`PyUnstable_ThreadState_ResetStackProtection` for undoing this operation. + + .. versionadded:: 3.15 + + +.. c:function:: void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate) + + Reset the stack protection start address and stack protection size + of a Python thread state to the operating system defaults. + + See :c:func:`PyUnstable_ThreadState_SetStackProtection` for an explanation. + + .. versionadded:: 3.15 + + .. c:function:: PyInterpreterState* PyInterpreterState_Get(void) Get the current interpreter. @@ -1377,6 +1432,9 @@ All of the following functions must be called after :c:func:`Py_Initialize`. This is not a replacement for :c:func:`PyModule_GetState()`, which extensions should use to store interpreter-specific state information. + The returned dictionary is borrowed from the interpreter and is valid until + interpreter shutdown. + .. versionadded:: 3.8 @@ -1659,7 +1717,8 @@ function. You can create and destroy them using the following functions: Only C-level static and global variables are shared between these module objects. - * For modules using single-phase initialization, + * For modules using legacy + :ref:`single-phase initialization `, e.g. :c:func:`PyModule_Create`, the first time a particular extension is imported, it is initialized normally, and a (shallow) copy of its module's dictionary is squirreled away. @@ -1711,6 +1770,8 @@ function. You can create and destroy them using the following functions: haven't been explicitly destroyed at that point. +.. _per-interpreter-gil: + A Per-Interpreter GIL --------------------- @@ -1722,7 +1783,7 @@ being blocked by other interpreters or blocking any others. Thus a single Python process can truly take advantage of multiple CPU cores when running Python code. The isolation also encourages a different approach to concurrency than that of just using threads. -(See :pep:`554`.) +(See :pep:`554` and :pep:`684`.) Using an isolated interpreter requires vigilance in preserving that isolation. That especially means not sharing any objects or mutable @@ -1827,6 +1888,29 @@ pointer and a void pointer argument. called from the main interpreter. Each subinterpreter now has its own list of scheduled calls. + .. versionchanged:: 3.12 + This function now always schedules *func* to be run in the main + interpreter. + + +.. c:function:: int Py_MakePendingCalls(void) + + Execute all pending calls. This is usually executed automatically by the + interpreter. + + This function returns ``0`` on success, and returns ``-1`` with an exception + set on failure. + + If this is not called in the main thread of the main + interpreter, this function does nothing and returns ``0``. + The caller must hold an :term:`attached thread state`. + + .. versionadded:: 3.1 + + .. versionchanged:: 3.12 + This function only runs pending calls in the main interpreter. + + .. _profiling: Profiling and Tracing @@ -2003,6 +2087,11 @@ Reference tracing is set to :c:data:`PyRefTracer_DESTROY`). The **data** argument is the opaque pointer that was provided when :c:func:`PyRefTracer_SetTracer` was called. + If a new tracing function is registered replacing the current a call to the + trace function will be made with the object set to **NULL** and **event** set to + :c:data:`PyRefTracer_TRACKER_REMOVED`. This will happen just before the new + function is registered. + .. versionadded:: 3.13 .. c:var:: int PyRefTracer_CREATE @@ -2015,6 +2104,13 @@ Reference tracing The value for the *event* parameter to :c:type:`PyRefTracer` functions when a Python object has been destroyed. +.. c:var:: int PyRefTracer_TRACKER_REMOVED + + The value for the *event* parameter to :c:type:`PyRefTracer` functions when the + current tracer is about to be replaced by a new one. + + .. versionadded:: 3.14 + .. c:function:: int PyRefTracer_SetTracer(PyRefTracer tracer, void *data) Register a reference tracer function. The function will be called when a new @@ -2030,6 +2126,10 @@ Reference tracing There must be an :term:`attached thread state` when calling this function. + If another tracer function was already registered, the old function will be + called with **event** set to :c:data:`PyRefTracer_TRACKER_REMOVED` just before + the new function is registered. + .. versionadded:: 3.13 .. c:function:: PyRefTracer PyRefTracer_GetTracer(void** data) @@ -2097,7 +2197,7 @@ use a thread key and functions to associate a :c:expr:`void*` value per thread. A :term:`thread state` does *not* need to be :term:`attached ` -when calling these functions; they suppl their own locking. +when calling these functions; they supply their own locking. Note that :file:`Python.h` does not include the declaration of the TLS APIs, you need to include :file:`pythread.h` to use thread-local storage. @@ -2440,3 +2540,220 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`. In the default build, this macro expands to ``}``. .. versionadded:: 3.13 + + +Legacy Locking APIs +------------------- + +These APIs are obsolete since Python 3.13 with the introduction of +:c:type:`PyMutex`. + +.. versionchanged:: 3.15 + These APIs are now a simple wrapper around ``PyMutex``. + + +.. c:type:: PyThread_type_lock + + A pointer to a mutual exclusion lock. + + +.. c:type:: PyLockStatus + + The result of acquiring a lock with a timeout. + + .. c:namespace:: NULL + + .. c:enumerator:: PY_LOCK_FAILURE + + Failed to acquire the lock. + + .. c:enumerator:: PY_LOCK_ACQUIRED + + The lock was successfully acquired. + + .. c:enumerator:: PY_LOCK_INTR + + The lock was interrupted by a signal. + + +.. c:function:: PyThread_type_lock PyThread_allocate_lock(void) + + Allocate a new lock. + + On success, this function returns a lock; on failure, this + function returns ``0`` without an exception set. + + The caller does not need to hold an :term:`attached thread state`. + + .. versionchanged:: 3.15 + This function now always uses :c:type:`PyMutex`. In prior versions, this + would use a lock provided by the operating system. + + +.. c:function:: void PyThread_free_lock(PyThread_type_lock lock) + + Destroy *lock*. The lock should not be held by any thread when calling + this. + + The caller does not need to hold an :term:`attached thread state`. + + +.. c:function:: PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag) + + Acquire *lock* with a timeout. + + This will wait for *microseconds* microseconds to acquire the lock. If the + timeout expires, this function returns :c:enumerator:`PY_LOCK_FAILURE`. + If *microseconds* is ``-1``, this will wait indefinitely until the lock has + been released. + + If *intr_flag* is ``1``, acquiring the lock may be interrupted by a signal, + in which case this function returns :c:enumerator:`PY_LOCK_INTR`. Upon + interruption, it's generally expected that the caller makes a call to + :c:func:`Py_MakePendingCalls` to propagate an exception to Python code. + + If the lock is successfully acquired, this function returns + :c:enumerator:`PY_LOCK_ACQUIRED`. + + The caller does not need to hold an :term:`attached thread state`. + + +.. c:function:: int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) + + Acquire *lock*. + + If *waitflag* is ``1`` and another thread currently holds the lock, this + function will wait until the lock can be acquired and will always return + ``1``. + + If *waitflag* is ``0`` and another thread holds the lock, this function will + not wait and instead return ``0``. If the lock is not held by any other + thread, then this function will acquire it and return ``1``. + + Unlike :c:func:`PyThread_acquire_lock_timed`, acquiring the lock cannot be + interrupted by a signal. + + The caller does not need to hold an :term:`attached thread state`. + + +.. c:function:: int PyThread_release_lock(PyThread_type_lock lock) + + Release *lock*. If *lock* is not held, then this function issues a + fatal error. + + The caller does not need to hold an :term:`attached thread state`. + + +Operating System Thread APIs +============================ + +.. c:macro:: PYTHREAD_INVALID_THREAD_ID + + Sentinel value for an invalid thread ID. + + This is currently equivalent to ``(unsigned long)-1``. + + +.. c:function:: unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg) + + Start function *func* in a new thread with argument *arg*. + The resulting thread is not intended to be joined. + + *func* must not be ``NULL``, but *arg* may be ``NULL``. + + On success, this function returns the identifier of the new thread; on failure, + this returns :c:macro:`PYTHREAD_INVALID_THREAD_ID`. + + The caller does not need to hold an :term:`attached thread state`. + + +.. c:function:: unsigned long PyThread_get_thread_ident(void) + + Return the identifier of the current thread, which will never be zero. + + This function cannot fail, and the caller does not need to hold an + :term:`attached thread state`. + + .. seealso:: + :py:func:`threading.get_ident` + + +.. c:function:: PyObject *PyThread_GetInfo(void) + + Get general information about the current thread in the form of a + :ref:`struct sequence ` object. This information is + accessible as :py:attr:`sys.thread_info` in Python. + + On success, this returns a new :term:`strong reference` to the thread + information; on failure, this returns ``NULL`` with an exception set. + + The caller must hold an :term:`attached thread state`. + + +.. c:macro:: PY_HAVE_THREAD_NATIVE_ID + + This macro is defined when the system supports native thread IDs. + + +.. c:function:: unsigned long PyThread_get_thread_native_id(void) + + Get the native identifier of the current thread as it was assigned by the operating + system's kernel, which will never be less than zero. + + This function is only available when :c:macro:`PY_HAVE_THREAD_NATIVE_ID` is + defined. + + This function cannot fail, and the caller does not need to hold an + :term:`attached thread state`. + + .. seealso:: + :py:func:`threading.get_native_id` + + +.. c:function:: void PyThread_exit_thread(void) + + Terminate the current thread. This function is generally considered unsafe + and should be avoided. It is kept solely for backwards compatibility. + + This function is only safe to call if all functions in the full call + stack are written to safely allow it. + + .. warning:: + + If the current system uses POSIX threads (also known as "pthreads"), + this calls :manpage:`pthread_exit(3)`, which attempts to unwind the stack + and call C++ destructors on some libc implementations. However, if a + ``noexcept`` function is reached, it may terminate the process. + Other systems, such as macOS, do unwinding. + + On Windows, this function calls ``_endthreadex()``, which kills the thread + without calling C++ destructors. + + In any case, there is a risk of corruption on the thread's stack. + + .. deprecated:: 3.14 + + +.. c:function:: void PyThread_init_thread(void) + + Initialize ``PyThread*`` APIs. Python executes this function automatically, + so there's little need to call it from an extension module. + + +.. c:function:: int PyThread_set_stacksize(size_t size) + + Set the stack size of the current thread to *size* bytes. + + This function returns ``0`` on success, ``-1`` if *size* is invalid, or + ``-2`` if the system does not support changing the stack size. This function + does not set exceptions. + + The caller does not need to hold an :term:`attached thread state`. + + +.. c:function:: size_t PyThread_get_stacksize(void) + + Return the stack size of the current thread in bytes, or ``0`` if the system's + default stack size is in use. + + The caller does not need to hold an :term:`attached thread state`. diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 4f0199838e1..c345029e4ac 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -102,7 +102,7 @@ Error Handling * Set *\*err_msg* and return ``1`` if an error is set. * Set *\*err_msg* to ``NULL`` and return ``0`` otherwise. - An error message is an UTF-8 encoded string. + An error message is a UTF-8 encoded string. If *config* has an exit code, format the exit code as an error message. @@ -1278,6 +1278,11 @@ PyConfig Default: ``0``. + .. deprecated-removed:: 3.15 3.17 + + The :option:`-b` and :option:`!-bb` options will become no-op in 3.17. + :c:member:`~PyConfig.bytes_warning` member will be removed in 3.17. + .. c:member:: int warn_default_encoding If non-zero, emit a :exc:`EncodingWarning` warning when :class:`io.TextIOWrapper` diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index acce3dc215d..bb94bcb86a7 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -121,6 +121,10 @@ complete listing. Return the absolute value of ``x``. + If the result cannot be represented (for example, if ``x`` has + :c:macro:`!INT_MIN` value for :c:expr:`int` type), the behavior is + undefined. + .. versionadded:: 3.3 .. c:macro:: Py_ALWAYS_INLINE @@ -167,6 +171,17 @@ complete listing. Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the command line (see :c:member:`PyConfig.use_environment`). +.. c:macro:: Py_LOCAL(type) + + Declare a function returning the specified *type* using a fast-calling + qualifier for functions that are local to the current file. + Semantically, this is equivalent to ``static type``. + +.. c:macro:: Py_LOCAL_INLINE(type) + + Equivalent to :c:macro:`Py_LOCAL` but additionally requests the function + be inlined. + .. c:macro:: Py_MAX(x, y) Return the maximum value between ``x`` and ``y``. @@ -179,6 +194,14 @@ complete listing. .. versionadded:: 3.6 +.. c:macro:: Py_MEMCPY(dest, src, n) + + This is a :term:`soft deprecated` alias to :c:func:`!memcpy`. + Use :c:func:`!memcpy` directly instead. + + .. deprecated:: 3.14 + The macro is :term:`soft deprecated`. + .. c:macro:: Py_MIN(x, y) Return the minimum value between ``x`` and ``y``. @@ -233,9 +256,32 @@ complete listing. .. versionadded:: 3.4 +.. c:macro:: Py_BUILD_ASSERT(cond) + + Asserts a compile-time condition *cond*, as a statement. + The build will fail if the condition is false or cannot be evaluated at compile time. + + For example:: + + Py_BUILD_ASSERT(sizeof(PyTime_t) == sizeof(int64_t)); + + .. versionadded:: 3.3 + +.. c:macro:: Py_BUILD_ASSERT_EXPR(cond) + + Asserts a compile-time condition *cond*, as an expression that evaluates to ``0``. + The build will fail if the condition is false or cannot be evaluated at compile time. + + For example:: + + #define foo_to_char(foo) \ + ((char *)(foo) + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) + + .. versionadded:: 3.3 + .. c:macro:: PyDoc_STRVAR(name, str) - Creates a variable with name ``name`` that can be used in docstrings. + Creates a variable with name *name* that can be used in docstrings. If Python is built without docstrings, the value will be empty. Use :c:macro:`PyDoc_STRVAR` for docstrings to support building @@ -267,6 +313,28 @@ complete listing. {NULL, NULL} }; +.. c:macro:: PyDoc_VAR(name) + + Declares a static character array variable with the given name *name*. + + For example:: + + PyDoc_VAR(python_doc) = PyDoc_STR("A genus of constricting snakes in the Pythonidae family native " + "to the tropics and subtropics of the Eastern Hemisphere."); + +.. c:macro:: Py_ARRAY_LENGTH(array) + + Compute the length of a statically allocated C array at compile time. + + The *array* argument must be a C array with a size known at compile time. + Passing an array with an unknown size, such as a heap-allocated array, + will result in a compilation error on some compilers, or otherwise produce + incorrect results. + + This is roughly equivalent to:: + + sizeof(array) / sizeof((array)[0]) + .. _api-objects: diff --git a/Doc/c-api/iter.rst b/Doc/c-api/iter.rst index bf9df62c6f1..6cfd24c5ae6 100644 --- a/Doc/c-api/iter.rst +++ b/Doc/c-api/iter.rst @@ -54,6 +54,6 @@ There are two functions specifically for working with iterators. - ``PYGEN_RETURN`` if iterator returns. Return value is returned via *presult*. - ``PYGEN_NEXT`` if iterator yields. Yielded value is returned via *presult*. - - ``PYGEN_ERROR`` if iterator has raised and exception. *presult* is set to ``NULL``. + - ``PYGEN_ERROR`` if iterator has raised an exception. *presult* is set to ``NULL``. .. versionadded:: 3.10 diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst index 6b7ba8c9979..bfbfe3c9279 100644 --- a/Doc/c-api/iterator.rst +++ b/Doc/c-api/iterator.rst @@ -50,3 +50,72 @@ sentinel value is returned. callable object that can be called with no parameters; each call to it should return the next item in the iteration. When *callable* returns a value equal to *sentinel*, the iteration will be terminated. + + +Range Objects +^^^^^^^^^^^^^ + +.. c:var:: PyTypeObject PyRange_Type + + The type object for :class:`range` objects. + + +.. c:function:: int PyRange_Check(PyObject *o) + + Return true if the object *o* is an instance of a :class:`range` object. + This function always succeeds. + + +Builtin Iterator Types +^^^^^^^^^^^^^^^^^^^^^^ + +These are built-in iteration types that are included in Python's C API, but +provide no additional functions. They are here for completeness. + + +.. list-table:: + :widths: auto + :header-rows: 1 + + * * C type + * Python type + * * .. c:var:: PyTypeObject PyEnum_Type + * :py:class:`enumerate` + * * .. c:var:: PyTypeObject PyFilter_Type + * :py:class:`filter` + * * .. c:var:: PyTypeObject PyMap_Type + * :py:class:`map` + * * .. c:var:: PyTypeObject PyReversed_Type + * :py:class:`reversed` + * * .. c:var:: PyTypeObject PyZip_Type + * :py:class:`zip` + + +Other Iterator Objects +^^^^^^^^^^^^^^^^^^^^^^ + +.. c:var:: PyTypeObject PyByteArrayIter_Type +.. c:var:: PyTypeObject PyBytesIter_Type +.. c:var:: PyTypeObject PyListIter_Type +.. c:var:: PyTypeObject PyListRevIter_Type +.. c:var:: PyTypeObject PySetIter_Type +.. c:var:: PyTypeObject PyTupleIter_Type +.. c:var:: PyTypeObject PyRangeIter_Type +.. c:var:: PyTypeObject PyLongRangeIter_Type +.. c:var:: PyTypeObject PyDictIterKey_Type +.. c:var:: PyTypeObject PyDictRevIterKey_Type +.. c:var:: PyTypeObject PyDictIterValue_Type +.. c:var:: PyTypeObject PyDictRevIterValue_Type +.. c:var:: PyTypeObject PyDictIterItem_Type +.. c:var:: PyTypeObject PyDictRevIterItem_Type +.. c:var:: PyTypeObject PyODictIter_Type + + Type objects for iterators of various built-in objects. + + Do not create instances of these directly; prefer calling + :c:func:`PyObject_GetIter` instead. + + Note that there is no guarantee that a given built-in type uses a given iterator + type. For example, iterating over :class:`range` will use one of two iterator + types depending on the size of the range. Other types may start using a + similar scheme in the future, without warning. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 31e2cd57034..ed34efe716d 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -40,9 +40,11 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Return a new :c:type:`PyLongObject` object from *v*, or ``NULL`` on failure. - The current implementation keeps an array of integer objects for all integers - between ``-5`` and ``256``. When you create an int in that range you actually - just get back a reference to the existing object. + .. impl-detail:: + + CPython keeps an array of integer objects for all integers + between ``-5`` and ``1024``. When you create an int in that range + you actually just get back a reference to the existing object. .. c:function:: PyObject* PyLong_FromUnsignedLong(unsigned long v) @@ -159,6 +161,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.13 +.. c:macro:: PyLong_FromPid(pid) + + Macro for creating a Python integer from a process identifier. + + This can be defined as an alias to :c:func:`PyLong_FromLong` or + :c:func:`PyLong_FromLongLong`, depending on the size of the system's + PID type. + + .. versionadded:: 3.2 + + .. c:function:: long PyLong_AsLong(PyObject *obj) .. index:: @@ -573,6 +586,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.13 +.. c:macro:: PyLong_AsPid(pid) + + Macro for converting a Python integer into a process identifier. + + This can be defined as an alias to :c:func:`PyLong_AsLong`, + :c:func:`PyLong_FromLongLong`, or :c:func:`PyLong_AsInt`, depending on the + size of the system's PID type. + + .. versionadded:: 3.2 + + .. c:function:: int PyLong_GetSign(PyObject *obj, int *sign) Get the sign of the integer object *obj*. diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst index 1f55c0aa955..2476ebb9b69 100644 --- a/Doc/c-api/mapping.rst +++ b/Doc/c-api/mapping.rst @@ -102,7 +102,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and .. note:: - Exceptions which occur when this calls :meth:`~object.__getitem__` + Exceptions which occur when this calls the :meth:`~object.__getitem__` method are silently ignored. For proper error handling, use :c:func:`PyMapping_HasKeyWithError`, :c:func:`PyMapping_GetOptionalItem` or :c:func:`PyObject_GetItem()` instead. @@ -116,7 +116,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and .. note:: - Exceptions that occur when this calls :meth:`~object.__getitem__` + Exceptions that occur when this calls the :meth:`~object.__getitem__` method or while creating the temporary :class:`str` object are silently ignored. For proper error handling, use :c:func:`PyMapping_HasKeyStringWithError`, diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 61218a1bf6f..668a163b2df 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -82,7 +82,7 @@ The following functions allow marshalled values to be read back in. assumes that no further objects will be read from the file, allowing it to aggressively load file data into memory so that the de-serialization can operate from data in memory rather than reading a byte at a time from the - file. Only use these variant if you are certain that you won't be reading + file. Only use this variant if you are certain that you won't be reading anything else from the file. On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError` diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index df1bb0ce370..23958980102 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -102,7 +102,7 @@ All allocating functions belong to one of three different "domains" (see also strategies and are optimized for different purposes. The specific details on how every domain allocates memory or what internal functions each domain calls is considered an implementation detail, but for debugging purposes a simplified -table can be found at :ref:`here `. +table can be found at :ref:`default-memory-allocators`. The APIs used to allocate and free a block of memory must be from the same domain. For example, :c:func:`PyMem_Free` must be used to free memory allocated using :c:func:`PyMem_Malloc`. diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index f6038032805..e4ac8b57673 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -13,6 +13,12 @@ A :class:`memoryview` object exposes the C level :ref:`buffer interface any other object. +.. c:var:: PyTypeObject PyMemoryView_Type + + This instance of :c:type:`PyTypeObject` represents the Python memoryview + type. This is the same object as :class:`memoryview` in the Python layer. + + .. c:function:: PyObject *PyMemoryView_FromObject(PyObject *obj) Create a memoryview object from an object that provides the buffer interface. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index c8edcecc5b4..22f8b1309aa 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -3,17 +3,16 @@ .. _moduleobjects: Module Objects --------------- +============== .. index:: pair: object; module - .. c:var:: PyTypeObject PyModule_Type .. index:: single: ModuleType (in module types) This instance of :c:type:`PyTypeObject` represents the Python module type. This - is exposed to Python programs as ``types.ModuleType``. + is exposed to Python programs as :py:class:`types.ModuleType`. .. c:function:: int PyModule_Check(PyObject *p) @@ -71,6 +70,9 @@ Module Objects ``PyObject_*`` functions rather than directly manipulate a module's :attr:`~object.__dict__`. + The returned reference is borrowed from the module; it is valid until + the module is destroyed. + .. c:function:: PyObject* PyModule_GetNameObject(PyObject *module) @@ -90,18 +92,19 @@ Module Objects Similar to :c:func:`PyModule_GetNameObject` but return the name encoded to ``'utf-8'``. -.. c:function:: void* PyModule_GetState(PyObject *module) - - Return the "state" of the module, that is, a pointer to the block of memory - allocated at module creation time, or ``NULL``. See - :c:member:`PyModuleDef.m_size`. - + The returned buffer is only valid until the module is renamed or destroyed. + Note that Python code may rename a module by setting its :py:attr:`~module.__name__` + attribute. .. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module) Return a pointer to the :c:type:`PyModuleDef` struct from which the module was created, or ``NULL`` if the module wasn't created from a definition. + On error, return ``NULL`` with an exception set. + Use :c:func:`PyErr_Occurred` to tell this case apart from a missing + :c:type:`!PyModuleDef`. + .. c:function:: PyObject* PyModule_GetFilenameObject(PyObject *module) @@ -122,215 +125,116 @@ Module Objects Similar to :c:func:`PyModule_GetFilenameObject` but return the filename encoded to 'utf-8'. + The returned buffer is only valid until the module's :py:attr:`~module.__file__` attribute + is reassigned or the module is destroyed. + .. deprecated:: 3.2 :c:func:`PyModule_GetFilename` raises :exc:`UnicodeEncodeError` on unencodable filenames, use :c:func:`PyModule_GetFilenameObject` instead. -.. _pymoduledef: +.. _pymoduledef_slot: -Module definitions ------------------- +Module definition +----------------- -The functions in the previous section work on any module object, including -modules imported from Python code. +Modules created using the C API are typically defined using an +array of :dfn:`slots`. +The slots provide a "description" of how a module should be created. -Modules defined using the C API typically use a *module definition*, -:c:type:`PyModuleDef` -- a statically allocated, constant “description" of -how a module should be created. +.. versionchanged:: 3.15 -The definition is usually used to define an extension's “main” module object -(see :ref:`extension-modules` for details). -It is also used to -:ref:`create extension modules dynamically `. + Previously, a :c:type:`PyModuleDef` struct was necessary to define modules. + The older way of defining modules is still available: consult either the + :ref:`pymoduledef` section or earlier versions of this documentation + if you plan to support earlier Python versions. -Unlike :c:func:`PyModule_New`, the definition allows management of -*module state* -- a piece of memory that is allocated and cleared together -with the module object. -Unlike the module's Python attributes, Python code cannot replace or delete -data stored in module state. +The slots array is usually used to define an extension module's “main” +module object (see :ref:`extension-modules` for details). +It can also be used to +:ref:`create extension modules dynamically `. -.. c:type:: PyModuleDef +Unless specified otherwise, the same slot ID may not be repeated +in an array of slots. - The module definition struct, which holds all information needed to create - a module object. - This structure must be statically allocated (or be otherwise guaranteed - to be valid while any modules created from it exist). - Usually, there is only one variable of this type for each extension module. - - .. c:member:: PyModuleDef_Base m_base - - Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`. - - .. c:member:: const char *m_name - - Name for the new module. - - .. c:member:: const char *m_doc - - Docstring for the module; usually a docstring variable created with - :c:macro:`PyDoc_STRVAR` is used. - - .. c:member:: Py_ssize_t m_size - - Module state may be kept in a per-module memory area that can be - retrieved with :c:func:`PyModule_GetState`, rather than in static globals. - This makes modules safe for use in multiple sub-interpreters. - - This memory area is allocated based on *m_size* on module creation, - and freed when the module object is deallocated, after the - :c:member:`~PyModuleDef.m_free` function has been called, if present. - - Setting it to a non-negative value means that the module can be - re-initialized and specifies the additional amount of memory it requires - for its state. - - Setting ``m_size`` to ``-1`` means that the module does not support - sub-interpreters, because it has global state. - Negative ``m_size`` is only allowed when using - :ref:`legacy single-phase initialization ` - or when :ref:`creating modules dynamically `. - - See :PEP:`3121` for more details. - - .. c:member:: PyMethodDef* m_methods - - A pointer to a table of module-level functions, described by - :c:type:`PyMethodDef` values. Can be ``NULL`` if no functions are present. - - .. c:member:: PyModuleDef_Slot* m_slots - - An array of slot definitions for multi-phase initialization, terminated by - a ``{0, NULL}`` entry. - When using legacy single-phase initialization, *m_slots* must be ``NULL``. - - .. versionchanged:: 3.5 - - Prior to version 3.5, this member was always set to ``NULL``, - and was defined as: - - .. c:member:: inquiry m_reload - - .. c:member:: traverseproc m_traverse - - A traversal function to call during GC traversal of the module object, or - ``NULL`` if not needed. - - This function is not called if the module state was requested but is not - allocated yet. This is the case immediately after the module is created - and before the module is executed (:c:data:`Py_mod_exec` function). More - precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater - than 0 and the module state (as returned by :c:func:`PyModule_GetState`) - is ``NULL``. - - .. versionchanged:: 3.9 - No longer called before the module state is allocated. - - .. c:member:: inquiry m_clear - - A clear function to call during GC clearing of the module object, or - ``NULL`` if not needed. - - This function is not called if the module state was requested but is not - allocated yet. This is the case immediately after the module is created - and before the module is executed (:c:data:`Py_mod_exec` function). More - precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater - than 0 and the module state (as returned by :c:func:`PyModule_GetState`) - is ``NULL``. - - Like :c:member:`PyTypeObject.tp_clear`, this function is not *always* - called before a module is deallocated. For example, when reference - counting is enough to determine that an object is no longer used, - the cyclic garbage collector is not involved and - :c:member:`~PyModuleDef.m_free` is called directly. - - .. versionchanged:: 3.9 - No longer called before the module state is allocated. - - .. c:member:: freefunc m_free - - A function to call during deallocation of the module object, or ``NULL`` - if not needed. - - This function is not called if the module state was requested but is not - allocated yet. This is the case immediately after the module is created - and before the module is executed (:c:data:`Py_mod_exec` function). More - precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater - than 0 and the module state (as returned by :c:func:`PyModule_GetState`) - is ``NULL``. - - .. versionchanged:: 3.9 - No longer called before the module state is allocated. - - -Module slots -............ .. c:type:: PyModuleDef_Slot .. c:member:: int slot - A slot ID, chosen from the available values explained below. + A slot ID, chosen from the available ``Py_mod_*`` values explained below. + + An ID of 0 marks the end of a :c:type:`!PyModuleDef_Slot` array. .. c:member:: void* value Value of the slot, whose meaning depends on the slot ID. + The value may not be NULL. + To leave a slot out, omit the :c:type:`PyModuleDef_Slot` entry entirely. + .. versionadded:: 3.5 -The available slot types are: -.. c:macro:: Py_mod_create +Metadata slots +.............. - Specifies a function that is called to create the module object itself. - The *value* pointer of this slot must point to a function of the signature: +.. c:macro:: Py_mod_name - .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def) - :no-index-entry: - :no-contents-entry: + :c:type:`Slot ID ` for the name of the new module, + as a NUL-terminated UTF8-encoded ``const char *``. - The function receives a :py:class:`~importlib.machinery.ModuleSpec` - instance, as defined in :PEP:`451`, and the module definition. - It should return a new module object, or set an error - and return ``NULL``. + Note that modules are typically created using a + :py:class:`~importlib.machinery.ModuleSpec`, and when they are, the + name from the spec will be used instead of :c:data:`!Py_mod_name`. + However, it is still recommended to include this slot for introspection + and debugging purposes. - This function should be kept minimal. In particular, it should not - call arbitrary Python code, as trying to import the same module again may - result in an infinite loop. + .. versionadded:: 3.15 - Multiple ``Py_mod_create`` slots may not be specified in one module - definition. + Use :c:member:`PyModuleDef.m_name` instead to support previous versions. - If ``Py_mod_create`` is not specified, the import machinery will create - a normal module object using :c:func:`PyModule_New`. The name is taken from - *spec*, not the definition, to allow extension modules to dynamically adjust - to their place in the module hierarchy and be imported under different - names through symlinks, all while sharing a single module definition. +.. c:macro:: Py_mod_doc - There is no requirement for the returned object to be an instance of - :c:type:`PyModule_Type`. Any type can be used, as long as it supports - setting and getting import-related attributes. - However, only ``PyModule_Type`` instances may be returned if the - ``PyModuleDef`` has non-``NULL`` ``m_traverse``, ``m_clear``, - ``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``. + :c:type:`Slot ID ` for the docstring of the new + module, as a NUL-terminated UTF8-encoded ``const char *``. -.. c:macro:: Py_mod_exec + Usually it is set to a variable created with :c:macro:`PyDoc_STRVAR`. - Specifies a function that is called to *execute* the module. - This is equivalent to executing the code of a Python module: typically, - this function adds classes and constants to the module. - The signature of the function is: + .. versionadded:: 3.15 - .. c:function:: int exec_module(PyObject* module) - :no-index-entry: - :no-contents-entry: + Use :c:member:`PyModuleDef.m_doc` instead to support previous versions. - If multiple ``Py_mod_exec`` slots are specified, they are processed in the - order they appear in the *m_slots* array. + +Feature slots +............. + +.. c:macro:: Py_mod_abi + + :c:type:`Slot ID ` whose value points to + a :c:struct:`PyABIInfo` structure describing the ABI that + the extension is using. + + A suitable :c:struct:`!PyABIInfo` variable can be defined using the + :c:macro:`PyABIInfo_VAR` macro, as in: + + .. code-block:: c + + PyABIInfo_VAR(abi_info); + + static PyModuleDef_Slot mymodule_slots[] = { + {Py_mod_abi, &abi_info}, + ... + }; + + When creating a module, Python checks the value of this slot + using :c:func:`PyABIInfo_Check`. + + .. versionadded:: 3.15 .. c:macro:: Py_mod_multiple_interpreters - Specifies one of the following values: + :c:type:`Slot ID ` whose value is one of: .. c:namespace:: NULL @@ -353,9 +257,6 @@ The available slot types are: This slot determines whether or not importing this module in a subinterpreter will fail. - Multiple ``Py_mod_multiple_interpreters`` slots may not be specified - in one module definition. - If ``Py_mod_multiple_interpreters`` is not specified, the import machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``. @@ -363,7 +264,7 @@ The available slot types are: .. c:macro:: Py_mod_gil - Specifies one of the following values: + :c:type:`Slot ID ` whose value is one of: .. c:namespace:: NULL @@ -381,23 +282,482 @@ The available slot types are: this module will cause the GIL to be automatically enabled. See :ref:`whatsnew313-free-threaded-cpython` for more detail. - Multiple ``Py_mod_gil`` slots may not be specified in one module definition. - If ``Py_mod_gil`` is not specified, the import machinery defaults to ``Py_MOD_GIL_USED``. .. versionadded:: 3.13 -.. _moduledef-dynamic: +Creation and initialization slots +................................. + +.. c:macro:: Py_mod_create + + :c:type:`Slot ID ` for a function that creates + the module object itself. + The function must have the signature: + + .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def) + :no-index-entry: + :no-contents-entry: + + The function will be called with: + + - *spec*: a ``ModuleSpec``-like object, meaning that any attributes defined + for :py:class:`importlib.machinery.ModuleSpec` have matching semantics. + However, any of the attributes may be missing. + - *def*: ``NULL``, or the module definition if the module is created from one. + + The function should return a new module object, or set an error + and return ``NULL``. + + This function should be kept minimal. In particular, it should not + call arbitrary Python code, as trying to import the same module again may + result in an infinite loop. + + If ``Py_mod_create`` is not specified, the import machinery will create + a normal module object using :c:func:`PyModule_New`. The name is taken from + *spec*, not the definition, to allow extension modules to dynamically adjust + to their place in the module hierarchy and be imported under different + names through symlinks, all while sharing a single module definition. + + There is no requirement for the returned object to be an instance of + :c:type:`PyModule_Type`. + However, some slots may only be used with + :c:type:`!PyModule_Type` instances; in particular: + + - :c:macro:`Py_mod_exec`, + - :ref:`module state slots ` (``Py_mod_state_*``), + - :c:macro:`Py_mod_token`. + + .. versionadded:: 3.5 + + .. versionchanged:: 3.15 + + The *slots* argument may be a ``ModuleSpec``-like object, rather than + a true :py:class:`~importlib.machinery.ModuleSpec` instance. + Note that previous versions of CPython did not enforce this. + + The *def* argument may now be ``NULL``, since modules are not necessarily + made from definitions. + +.. c:macro:: Py_mod_exec + + :c:type:`Slot ID ` for a function that will + :dfn:`execute`, or initialize, the module. + This function does the equivalent to executing the code of a Python module: + typically, it adds classes and constants to the module. + The signature of the function is: + + .. c:function:: int exec_module(PyObject* module) + :no-index-entry: + :no-contents-entry: + + See the :ref:`capi-module-support-functions` section for some useful + functions to call. + + For backwards compatibility, the :c:type:`PyModuleDef.m_slots` array may + contain multiple :c:macro:`!Py_mod_exec` slots; these are processed in the + order they appear in the array. + Elsewhere (that is, in arguments to :c:func:`PyModule_FromSlotsAndSpec` + and in return values of :samp:`PyModExport_{}`), repeating the slot + is not allowed. + + .. versionadded:: 3.5 + + .. versionchanged:: 3.15 + + Repeated ``Py_mod_exec`` slots are disallowed, except in + :c:type:`PyModuleDef.m_slots`. + +.. c:macro:: Py_mod_methods + + :c:type:`Slot ID ` for a table of module-level + functions, as an array of :c:type:`PyMethodDef` values suitable as the + *functions* argument to :c:func:`PyModule_AddFunctions`. + + Like other slot IDs, a slots array may only contain one + :c:macro:`!Py_mod_methods` entry. + To add functions from multiple :c:type:`PyMethodDef` arrays, call + :c:func:`PyModule_AddFunctions` in the :c:macro:`Py_mod_exec` function. + + The table must be statically allocated (or otherwise guaranteed to outlive + the module object). + + .. versionadded:: 3.15 + + Use :c:member:`PyModuleDef.m_methods` instead to support previous versions. + +.. _ext-module-state: + +Module state +------------ + +Extension modules can have *module state* -- a +piece of memory that is allocated on module creation, +and freed when the module object is deallocated. +The module state is specified using :ref:`dedicated slots `. + +A typical use of module state is storing an exception type -- or indeed *any* +type object defined by the module -- + +Unlike the module's Python attributes, Python code cannot replace or delete +data stored in module state. + +Keeping per-module information in attributes and module state, rather than in +static globals, makes module objects *isolated* and safer for use in +multiple sub-interpreters. +It also helps Python do an orderly clean-up when it shuts down. + +Extensions that keep references to Python objects as part of module state must +implement :c:macro:`Py_mod_state_traverse` and :c:macro:`Py_mod_state_clear` +functions to avoid reference leaks. + +To retrieve the state from a given module, use the following functions: + +.. c:function:: void* PyModule_GetState(PyObject *module) + + Return the "state" of the module, that is, a pointer to the block of memory + allocated at module creation time, or ``NULL``. See + :c:macro:`Py_mod_state_size`. + + On error, return ``NULL`` with an exception set. + Use :c:func:`PyErr_Occurred` to tell this case apart from missing + module state. + + +.. c:function:: int PyModule_GetStateSize(PyObject *, Py_ssize_t *result) + + Set *\*result* to the size of the module's state, as specified using + :c:macro:`Py_mod_state_size` (or :c:member:`PyModuleDef.m_size`), + and return 0. + + On error, set *\*result* to -1, and return -1 with an exception set. + + .. versionadded:: 3.15 + + + +.. _ext-module-state-slots: + +Slots for defining module state +............................... + +The following :c:member:`PyModuleDef_Slot.slot` IDs are available for +defining the module state. + +.. c:macro:: Py_mod_state_size + + :c:type:`Slot ID ` for the size of the module state, + in bytes. + + Setting the value to a non-negative value means that the module can be + re-initialized and specifies the additional amount of memory it requires + for its state. + + See :PEP:`3121` for more details. + + Use :c:func:`PyModule_GetStateSize` to retrieve the size of a given module. + + .. versionadded:: 3.15 + + Use :c:member:`PyModuleDef.m_size` instead to support previous versions. + +.. c:macro:: Py_mod_state_traverse + + :c:type:`Slot ID ` for a traversal function to call + during GC traversal of the module object. + + The signature of the function, and meanings of the arguments, + is similar as for :c:member:`PyTypeObject.tp_traverse`: + + .. c:function:: int traverse_module_state(PyObject *module, visitproc visit, void *arg) + :no-index-entry: + :no-contents-entry: + + This function is not called if the module state was requested but is not + allocated yet. This is the case immediately after the module is created + and before the module is executed (:c:data:`Py_mod_exec` function). More + precisely, this function is not called if the state size + (:c:data:`Py_mod_state_size`) is greater than 0 and the module state + (as returned by :c:func:`PyModule_GetState`) is ``NULL``. + + .. versionadded:: 3.15 + + Use :c:member:`PyModuleDef.m_size` instead to support previous versions. + +.. c:macro:: Py_mod_state_clear + + :c:type:`Slot ID ` for a clear function to call + during GC clearing of the module object. + + The signature of the function is: + + .. c:function:: int clear_module_state(PyObject* module) + :no-index-entry: + :no-contents-entry: + + This function is not called if the module state was requested but is not + allocated yet. This is the case immediately after the module is created + and before the module is executed (:c:data:`Py_mod_exec` function). More + precisely, this function is not called if the state size + (:c:data:`Py_mod_state_size`) is greater than 0 and the module state + (as returned by :c:func:`PyModule_GetState`) is ``NULL``. + + Like :c:member:`PyTypeObject.tp_clear`, this function is not *always* + called before a module is deallocated. For example, when reference + counting is enough to determine that an object is no longer used, + the cyclic garbage collector is not involved and + the :c:macro:`Py_mod_state_free` function is called directly. + + .. versionadded:: 3.15 + + Use :c:member:`PyModuleDef.m_clear` instead to support previous versions. + +.. c:macro:: Py_mod_state_free + + :c:type:`Slot ID ` for a function to call during + deallocation of the module object. + + The signature of the function is: + + .. c:function:: int free_module_state(PyObject* module) + :no-index-entry: + :no-contents-entry: + + This function is not called if the module state was requested but is not + allocated yet. This is the case immediately after the module is created + and before the module is executed (:c:data:`Py_mod_exec` function). More + precisely, this function is not called if the state size + (:c:data:`Py_mod_state_size`) is greater than 0 and the module state + (as returned by :c:func:`PyModule_GetState`) is ``NULL``. + + .. versionadded:: 3.15 + + Use :c:member:`PyModuleDef.m_free` instead to support previous versions. + + +.. _ext-module-token: + +Module token +............ + +Each module may have an associated *token*: a pointer-sized value intended to +identify of the module state's memory layout. +This means that if you have a module object, but you are not sure if it +“belongs” to your extension, you can check using code like this: + +.. code-block:: c + + PyObject *module = + + void *module_token; + if (PyModule_GetToken(module, &module_token) < 0) { + return NULL; + } + if (module_token != your_token) { + PyErr_SetString(PyExc_ValueError, "unexpected module") + return NULL; + } + + // This module's state has the expected memory layout; it's safe to cast + struct my_state state = (struct my_state*)PyModule_GetState(module) + +A module's token -- and the *your_token* value to use in the above code -- is: + +- For modules created with :c:type:`PyModuleDef`: the address of that + :c:type:`PyModuleDef`; +- For modules defined with the :c:macro:`Py_mod_token` slot: the value + of that slot; +- For modules created from an ``PyModExport_*`` + :ref:`export hook `: the slots array that the export + hook returned (unless overriden with :c:macro:`Py_mod_token`). + +.. c:macro:: Py_mod_token + + :c:type:`Slot ID ` for the module token. + + If you use this slot to set the module token (rather than rely on the + default), you must ensure that: + + * The pointer outlives the class, so it's not reused for something else + while the class exists. + * It "belongs" to the extension module where the class lives, so it will not + clash with other extensions. + * If the token points to a :c:type:`PyModuleDef` struct, the module should + behave as if it was created from that :c:type:`PyModuleDef`. + In particular, the module state must have matching layout and semantics. + + Modules created from :c:type:`PyModuleDef` always use the address of + the :c:type:`PyModuleDef` as the token. + This means that :c:macro:`!Py_mod_token` cannot be used in + :c:member:`PyModuleDef.m_slots`. + + .. versionadded:: 3.15 + +.. c:function:: int PyModule_GetToken(PyObject *module, void** result) + + Set *\*result* to the module's token and return 0. + + On error, set *\*result* to NULL, and return -1 with an exception set. + + .. versionadded:: 3.15 + +See also :c:func:`PyType_GetModuleByToken`. + + +.. _module-from-slots: Creating extension modules dynamically -------------------------------------- -The following functions may be used to create a module outside of an -extension's :ref:`initialization function `. -They are also used in -:ref:`single-phase initialization `. +The following functions may be used to create an extension module dynamically, +rather than from an extension's :ref:`export hook `. + +.. c:function:: PyObject *PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots, PyObject *spec) + + Create a new module object, given an array of :ref:`slots ` + and the :py:class:`~importlib.machinery.ModuleSpec` *spec*. + + The *slots* argument must point to an array of :c:type:`PyModuleDef_Slot` + structures, terminated by an entry slot with slot ID of 0 + (typically written as ``{0}`` or ``{0, NULL}`` in C). + The *slots* argument may not be ``NULL``. + + The *spec* argument may be any ``ModuleSpec``-like object, as described + in :c:macro:`Py_mod_create` documentation. + Currently, the *spec* must have a ``name`` attribute. + + On success, return the new module. + On error, return ``NULL`` with an exception set. + + Note that this does not process the module's execution slot + (:c:data:`Py_mod_exec`). + Both :c:func:`!PyModule_FromSlotsAndSpec` and :c:func:`PyModule_Exec` + must be called to fully initialize a module. + (See also :ref:`multi-phase-initialization`.) + + The *slots* array only needs to be valid for the duration of the + :c:func:`!PyModule_FromSlotsAndSpec` call. + In particular, it may be heap-allocated. + + .. versionadded:: 3.15 + +.. c:function:: int PyModule_Exec(PyObject *module) + + Execute the :c:data:`Py_mod_exec` slot(s) of the given *module*. + + On success, return 0. + On error, return -1 with an exception set. + + For clarity: If *module* has no slots, for example if it uses + :ref:`legacy single-phase initialization `, + this function does nothing and returns 0. + + .. versionadded:: 3.15 + + + +.. _pymoduledef: + +Module definition struct +------------------------ + +Traditionally, extension modules were defined using a *module definition* +as the “description" of how a module should be created. +Rather than using an array of :ref:`slots ` directly, +the definition has dedicated members for most common functionality, +and allows additional slots as an extension mechanism. + +This way of defining modules is still available and there are no plans to +remove it. + +.. c:type:: PyModuleDef + + The module definition struct, which holds information needed to create + a module object. + + This structure must be statically allocated (or be otherwise guaranteed + to be valid while any modules created from it exist). + Usually, there is only one variable of this type for each extension module + defined this way. + + .. c:member:: PyModuleDef_Base m_base + + Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`: + + .. c:namespace:: NULL + + .. c:type:: PyModuleDef_Base + + The type of :c:member:`!PyModuleDef.m_base`. + + .. c:macro:: PyModuleDef_HEAD_INIT + + The required initial value for :c:member:`!PyModuleDef.m_base`. + + .. c:member:: const char *m_name + + Corresponds to the :c:macro:`Py_mod_name` slot. + + .. c:member:: const char *m_doc + + These members correspond to the :c:macro:`Py_mod_doc` slot. + Setting this to NULL is equivalent to omitting the slot. + + .. c:member:: Py_ssize_t m_size + + Corresponds to the :c:macro:`Py_mod_state_size` slot. + Setting this to zero is equivalent to omitting the slot. + + When using :ref:`legacy single-phase initialization ` + or when creating modules dynamically using :c:func:`PyModule_Create` + or :c:func:`PyModule_Create2`, :c:member:`!m_size` may be set to -1. + This indicates that the module does not support sub-interpreters, + because it has global state. + + .. c:member:: PyMethodDef *m_methods + + Corresponds to the :c:macro:`Py_mod_methods` slot. + Setting this to NULL is equivalent to omitting the slot. + + .. c:member:: PyModuleDef_Slot* m_slots + + An array of additional slots, terminated by a ``{0, NULL}`` entry. + + This array may not contain slots corresponding to :c:type:`PyModuleDef` + members. + For example, you cannot use :c:macro:`Py_mod_name` in :c:member:`!m_slots`; + the module name must be given as :c:member:`PyModuleDef.m_name`. + + .. versionchanged:: 3.5 + + Prior to version 3.5, this member was always set to ``NULL``, + and was defined as: + + .. c:member:: inquiry m_reload + + .. c:member:: traverseproc m_traverse + inquiry m_clear + freefunc m_free + + These members correspond to the :c:macro:`Py_mod_state_traverse`, + :c:macro:`Py_mod_state_clear`, and :c:macro:`Py_mod_state_free` slots, + respectively. + + Setting these members to NULL is equivalent to omitting the + corresponding slots. + + .. versionchanged:: 3.9 + + :c:member:`m_traverse`, :c:member:`m_clear` and :c:member:`m_free` + functions are longer called before the module state is allocated. + + +.. _moduledef-dynamic: + +The following API can be used to create modules from a :c:type:`!PyModuleDef` +struct: .. c:function:: PyObject* PyModule_Create(PyModuleDef *def) @@ -474,12 +834,13 @@ They are also used in useful for versioning. This may change in the future. +.. _capi-module-support-functions: + Support functions ----------------- -The following functions are provided to help initialize a module -state. -They are intended for a module's execution slots (:c:data:`Py_mod_exec`), +The following functions are provided to help initialize a module object. +They are intended for a module's execution slot (:c:data:`Py_mod_exec`), the initialization function for legacy :ref:`single-phase initialization `, or code that creates modules dynamically. @@ -645,6 +1006,9 @@ or code that creates modules dynamically. :c:type:`PyMethodDef` arrays; in that case they should call this function directly. + The *functions* array must be statically allocated (or otherwise guaranteed + to outlive the module object). + .. versionadded:: 3.5 .. c:function:: int PyModule_SetDocString(PyObject *module, const char *docstring) diff --git a/Doc/c-api/monitoring.rst b/Doc/c-api/monitoring.rst index 7926148302a..b0227c2f4fa 100644 --- a/Doc/c-api/monitoring.rst +++ b/Doc/c-api/monitoring.rst @@ -136,7 +136,7 @@ Managing the Monitoring State ----------------------------- Monitoring states can be managed with the help of monitoring scopes. A scope -would typically correspond to a python function. +would typically correspond to a Python function. .. c:function:: int PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version, const uint8_t *event_types, Py_ssize_t length) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 78599e704b1..3e0cc660317 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -73,7 +73,7 @@ Object Protocol Flag to be used with multiple functions that print the object (like :c:func:`PyObject_Print` and :c:func:`PyFile_WriteObject`). - If passed, these function would use the :func:`str` of the object + If passed, these functions use the :func:`str` of the object instead of the :func:`repr`. @@ -85,6 +85,35 @@ Object Protocol instead of the :func:`repr`. +.. c:function:: void PyUnstable_Object_Dump(PyObject *op) + + Dump an object *op* to ``stderr``. This should only be used for debugging. + + The output is intended to try dumping objects even after memory corruption: + + * Information is written starting with fields that are the least likely to + crash when accessed. + * This function can be called without an :term:`attached thread state`, but + it's not recommended to do so: it can cause deadlocks. + * An object that does not belong to the current interpreter may be dumped, + but this may also cause crashes or unintended behavior. + * Implement a heuristic to detect if the object memory has been freed. Don't + display the object contents in this case, only its memory address. + * The output format may change at any time. + + Example of output: + + .. code-block:: output + + object address : 0x7f80124702c0 + object refcount : 2 + object type : 0x9902e0 + object type name: str + object repr : 'abcdef' + + .. versionadded:: 3.15 + + .. c:function:: int PyObject_HasAttrWithError(PyObject *o, PyObject *attr_name) Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise. @@ -201,7 +230,7 @@ Object Protocol This case can arise from forgetting ``NULL`` checks and would delete the attribute. - .. versionchanged:: next + .. versionchanged:: 3.15 Must not be called with NULL value if an exception is set. @@ -226,7 +255,7 @@ Object Protocol For more details, see :c:func:`PyUnicode_InternFromString`, which may be used internally to create a key object. - .. versionchanged:: next + .. versionchanged:: 3.15 Must not be called with NULL value if an exception is set. @@ -600,7 +629,7 @@ Object Protocol Clear the managed dictionary of *obj*. - This function must only be called in a traverse function of the type which + This function must only be called in a clear function of the type which has the :c:macro:`Py_TPFLAGS_MANAGED_DICT` flag set. .. versionadded:: 3.13 diff --git a/Doc/c-api/picklebuffer.rst b/Doc/c-api/picklebuffer.rst new file mode 100644 index 00000000000..9e2d92341b0 --- /dev/null +++ b/Doc/c-api/picklebuffer.rst @@ -0,0 +1,59 @@ +.. highlight:: c + +.. _picklebuffer-objects: + +.. index:: + pair: object; PickleBuffer + +Pickle buffer objects +--------------------- + +.. versionadded:: 3.8 + +A :class:`pickle.PickleBuffer` object wraps a :ref:`buffer-providing object +` for out-of-band data transfer with the :mod:`pickle` module. + + +.. c:var:: PyTypeObject PyPickleBuffer_Type + + This instance of :c:type:`PyTypeObject` represents the Python pickle buffer type. + This is the same object as :class:`pickle.PickleBuffer` in the Python layer. + + +.. c:function:: int PyPickleBuffer_Check(PyObject *op) + + Return true if *op* is a pickle buffer instance. + This function always succeeds. + + +.. c:function:: PyObject *PyPickleBuffer_FromObject(PyObject *obj) + + Create a pickle buffer from the object *obj*. + + This function will fail if *obj* doesn't support the :ref:`buffer protocol `. + + On success, return a new pickle buffer instance. + On failure, set an exception and return ``NULL``. + + Analogous to calling :class:`pickle.PickleBuffer` with *obj* in Python. + + +.. c:function:: const Py_buffer *PyPickleBuffer_GetBuffer(PyObject *picklebuf) + + Get a pointer to the underlying :c:type:`Py_buffer` that the pickle buffer wraps. + + The returned pointer is valid as long as *picklebuf* is alive and has not been + released. The caller must not modify or free the returned :c:type:`Py_buffer`. + If the pickle buffer has been released, raise :exc:`ValueError`. + + On success, return a pointer to the buffer view. + On failure, set an exception and return ``NULL``. + + +.. c:function:: int PyPickleBuffer_Release(PyObject *picklebuf) + + Release the underlying buffer held by the pickle buffer. + + Return ``0`` on success. On failure, set an exception and return ``-1``. + + Analogous to calling :meth:`pickle.PickleBuffer.release` in Python. diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index cba823aa027..09c0fb6b9c5 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -147,7 +147,7 @@ subtypes but not for instances of :class:`frozenset` or its subtypes. Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a - :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~frozenset.discard` + :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise :exc:`SystemError` if *set* is not an instance of :class:`set` or its subtype. diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index 9b65e0b8d23..f5e6b7ad157 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -2,9 +2,9 @@ .. _stable: -*************** -C API Stability -*************** +*********************** +C API and ABI Stability +*********************** Unless documented otherwise, Python's C API is covered by the Backwards Compatibility Policy, :pep:`387`. @@ -199,6 +199,162 @@ This is the case with Windows and macOS releases from ``python.org`` and many third-party distributors. +ABI Checking +============ + +.. versionadded:: 3.15 + +Python includes a rudimentary check for ABI compatibility. + +This check is not comprehensive. +It only guards against common cases of incompatible modules being +installed for the wrong interpreter. +It also does not take :ref:`platform incompatibilities ` +into account. +It can only be done after an extension is successfully loaded. + +Despite these limitations, it is recommended that extension modules use this +mechanism, so that detectable incompatibilities raise exceptions rather than +crash. + +Most modules can use this check via the :c:data:`Py_mod_abi` +slot and the :c:macro:`PyABIInfo_VAR` macro, for example like this: + +.. code-block:: c + + PyABIInfo_VAR(abi_info); + + static PyModuleDef_Slot mymodule_slots[] = { + {Py_mod_abi, &abi_info}, + ... + }; + + +The full API is described below for advanced use cases. + +.. c:function:: int PyABIInfo_Check(PyABIInfo *info, const char *module_name) + + Verify that the given *info* is compatible with the currently running + interpreter. + + Return 0 on success. On failure, raise an exception and return -1. + + If the ABI is incompatible, the raised exception will be :py:exc:`ImportError`. + + The *module_name* argument can be ``NULL``, or point to a NUL-terminated + UTF-8-encoded string used for error messages. + + Note that if *info* describes the ABI that the current code uses (as defined + by :c:macro:`PyABIInfo_VAR`, for example), using any other Python C API + may lead to crashes. + In particular, it is not safe to examine the raised exception. + + .. versionadded:: 3.15 + +.. c:macro:: PyABIInfo_VAR(NAME) + + Define a static :c:struct:`PyABIInfo` variable with the given *NAME* that + describes the ABI that the current code will use. + This macro expands to: + + .. code-block:: c + + static PyABIInfo NAME = { + 1, 0, + PyABIInfo_DEFAULT_FLAGS, + PY_VERSION_HEX, + PyABIInfo_DEFAULT_ABI_VERSION + } + + .. versionadded:: 3.15 + +.. c:type:: PyABIInfo + + .. c:member:: uint8_t abiinfo_major_version + + The major version of :c:struct:`PyABIInfo`. Can be set to: + + * ``0`` to skip all checking, or + * ``1`` to specify this version of :c:struct:`!PyABIInfo`. + + .. c:member:: uint8_t abiinfo_minor_version + + The minor version of :c:struct:`PyABIInfo`. + Must be set to ``0``; larger values are reserved for backwards-compatible + future versions of :c:struct:`!PyABIInfo`. + + .. c:member:: uint16_t flags + + .. c:namespace:: NULL + + This field is usually set to the following macro: + + .. c:macro:: PyABIInfo_DEFAULT_FLAGS + + Default flags, based on current values of macros such as + :c:macro:`Py_LIMITED_API` and :c:macro:`Py_GIL_DISABLED`. + + Alternately, the field can be set to the following flags, combined + by bitwise OR. + Unused bits must be set to zero. + + ABI variant -- one of: + + .. c:macro:: PyABIInfo_STABLE + + Specifies that the stable ABI is used. + + .. c:macro:: PyABIInfo_INTERNAL + + Specifies ABI specific to a particular build of CPython. + Internal use only. + + Free-threading compatibility -- one of: + + .. c:macro:: PyABIInfo_FREETHREADED + + Specifies ABI compatible with free-threading builds of CPython. + (That is, ones compiled with :option:`--disable-gil`; with ``t`` + in :py:data:`sys.abiflags`) + + .. c:macro:: PyABIInfo_GIL + + Specifies ABI compatible with non-free-threading builds of CPython + (ones compiled *without* :option:`--disable-gil`). + + .. c:member:: uint32_t build_version + + The version of the Python headers used to build the code, in the format + used by :c:macro:`PY_VERSION_HEX`. + + This can be set to ``0`` to skip any checks related to this field. + This option is meant mainly for projects that do not use the CPython + headers directly, and do not emulate a specific version of them. + + .. c:member:: uint32_t abi_version + + The ABI version. + + For the Stable ABI, this field should be the value of + :c:macro:`Py_LIMITED_API` + (except if :c:macro:`Py_LIMITED_API` is ``3``; use + :c:expr:`Py_PACK_VERSION(3, 2)` in that case). + + Otherwise, it should be set to :c:macro:`PY_VERSION_HEX`. + + It can also be set to ``0`` to skip any checks related to this field. + + .. c:namespace:: NULL + + .. c:macro:: PyABIInfo_DEFAULT_ABI_VERSION + + The value that should be used for this field, based on current + values of macros such as :c:macro:`Py_LIMITED_API`, + :c:macro:`PY_VERSION_HEX` and :c:macro:`Py_GIL_DISABLED`. + + .. versionadded:: 3.15 + + .. _limited-api-list: Contents of Limited API diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 58dd915e04f..62f45def04f 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -280,6 +280,8 @@ Implementing functions and methods Name of the method. + A ``NULL`` *ml_name* marks the end of a :c:type:`!PyMethodDef` array. + .. c:member:: PyCFunction ml_meth Pointer to the C implementation. @@ -447,6 +449,25 @@ definition with the same method name. slot. This is helpful because calls to PyCFunctions are optimized more than wrapper object calls. + +.. c:var:: PyTypeObject PyCMethod_Type + + The type object corresponding to Python C method objects. This is + available as :class:`types.BuiltinMethodType` in the Python layer. + + +.. c:function:: int PyCMethod_Check(PyObject *op) + + Return true if *op* is an instance of the :c:type:`PyCMethod_Type` type + or a subtype of it. This function always succeeds. + + +.. c:function:: int PyCMethod_CheckExact(PyObject *op) + + This is the same as :c:func:`PyCMethod_Check`, but does not account for + subtypes. + + .. c:function:: PyObject * PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *cls) Turn *ml* into a Python :term:`callable` object. @@ -472,6 +493,24 @@ definition with the same method name. .. versionadded:: 3.9 +.. c:var:: PyTypeObject PyCFunction_Type + + The type object corresponding to Python C function objects. This is + available as :class:`types.BuiltinFunctionType` in the Python layer. + + +.. c:function:: int PyCFunction_Check(PyObject *op) + + Return true if *op* is an instance of the :c:type:`PyCFunction_Type` type + or a subtype of it. This function always succeeds. + + +.. c:function:: int PyCFunction_CheckExact(PyObject *op) + + This is the same as :c:func:`PyCFunction_Check`, but does not account for + subtypes. + + .. c:function:: PyObject * PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) Equivalent to ``PyCMethod_New(ml, self, module, NULL)``. @@ -482,6 +521,62 @@ definition with the same method name. Equivalent to ``PyCMethod_New(ml, self, NULL, NULL)``. +.. c:function:: int PyCFunction_GetFlags(PyObject *func) + + Get the function's flags on *func* as they were passed to + :c:member:`~PyMethodDef.ml_flags`. + + If *func* is not a C function object, this fails with an exception. + *func* must not be ``NULL``. + + This function returns the function's flags on success, and ``-1`` with an + exception set on failure. + + +.. c:function:: int PyCFunction_GET_FLAGS(PyObject *func) + + This is the same as :c:func:`PyCFunction_GetFlags`, but without error + or type checking. + + +.. c:function:: PyCFunction PyCFunction_GetFunction(PyObject *func) + + Get the function pointer on *func* as it was passed to + :c:member:`~PyMethodDef.ml_meth`. + + If *func* is not a C function object, this fails with an exception. + *func* must not be ``NULL``. + + This function returns the function pointer on success, and ``NULL`` with an + exception set on failure. + + +.. c:function:: int PyCFunction_GET_FUNCTION(PyObject *func) + + This is the same as :c:func:`PyCFunction_GetFunction`, but without error + or type checking. + + +.. c:function:: PyObject *PyCFunction_GetSelf(PyObject *func) + + Get the "self" object on *func*. This is the object that would be passed + to the first argument of a :c:type:`PyCFunction`. For C function objects + created through a :c:type:`PyMethodDef` on a :c:type:`PyModuleDef`, this + is the resulting module object. + + If *func* is not a C function object, this fails with an exception. + *func* must not be ``NULL``. + + This function returns a :term:`borrowed reference` to the "self" object + on success, and ``NULL`` with an exception set on failure. + + +.. c:function:: PyObject *PyCFunction_GET_SELF(PyObject *func) + + This is the same as :c:func:`PyCFunction_GetSelf`, but without error or + type checking. + + Accessing attributes of extension types --------------------------------------- @@ -605,14 +700,12 @@ The following flags can be used with :c:member:`PyMemberDef.flags`: entry indicates an offset from the subclass-specific data, rather than from ``PyObject``. - Can only be used as part of :c:member:`Py_tp_members ` + Can only be used as part of the :c:data:`Py_tp_members` :c:type:`slot ` when creating a class using negative :c:member:`~PyType_Spec.basicsize`. It is mandatory in that case. - - This flag is only used in :c:type:`PyType_Slot`. - When setting :c:member:`~PyTypeObject.tp_members` during - class creation, Python clears it and sets + When setting :c:member:`~PyTypeObject.tp_members` from the slot during + class creation, Python clears the flag and sets :c:member:`PyMemberDef.offset` to the offset from the ``PyObject`` struct. .. index:: diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index b34936dd55e..ee73c1c8ada 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -123,6 +123,24 @@ Operating System Utilities This is a thin wrapper around either :c:func:`!sigaction` or :c:func:`!signal`. Do not call those functions directly! + +.. c:function:: int PyOS_InterruptOccurred(void) + + Check if a :c:macro:`!SIGINT` signal has been received. + + Returns ``1`` if a :c:macro:`!SIGINT` has occurred and clears the signal flag, + or ``0`` otherwise. + + In most cases, you should prefer :c:func:`PyErr_CheckSignals` over this function. + :c:func:`!PyErr_CheckSignals` invokes the appropriate signal handlers + for all pending signals, allowing Python code to handle the signal properly. + This function only detects :c:macro:`!SIGINT` and does not invoke any Python + signal handlers. + + This function is async-signal-safe and this function cannot fail. + The caller must hold an :term:`attached thread state`. + + .. c:function:: wchar_t* Py_DecodeLocale(const char* arg, size_t *size) .. warning:: @@ -268,7 +286,7 @@ accessible to C code. They all work with the current interpreter thread's If the non-existing object should not be treated as a failure, you can use :c:func:`PySys_GetOptionalAttr` instead. - .. versionadded:: next + .. versionadded:: 3.15 .. c:function:: PyObject *PySys_GetAttrString(const char *name) @@ -279,7 +297,7 @@ accessible to C code. They all work with the current interpreter thread's If the non-existing object should not be treated as a failure, you can use :c:func:`PySys_GetOptionalAttrString` instead. - .. versionadded:: next + .. versionadded:: 3.15 .. c:function:: int PySys_GetOptionalAttr(PyObject *name, PyObject **result) @@ -293,7 +311,7 @@ accessible to C code. They all work with the current interpreter thread's * Set an exception, set *\*result* to ``NULL``, and return ``-1``, if an error occurred. - .. versionadded:: next + .. versionadded:: 3.15 .. c:function:: int PySys_GetOptionalAttrString(const char *name, PyObject **result) @@ -301,7 +319,7 @@ accessible to C code. They all work with the current interpreter thread's specified as a :c:expr:`const char*` UTF-8 encoded bytes string, rather than a :c:expr:`PyObject*`. - .. versionadded:: next + .. versionadded:: 3.15 .. c:function:: PyObject *PySys_GetObject(const char *name) @@ -316,14 +334,6 @@ accessible to C code. They all work with the current interpreter thread's case *name* is deleted from the sys module. Returns ``0`` on success, ``-1`` on error. -.. c:function:: void PySys_ResetWarnOptions() - - Reset :data:`sys.warnoptions` to an empty list. This function may be - called prior to :c:func:`Py_Initialize`. - - .. deprecated-removed:: 3.13 3.15 - Clear :data:`sys.warnoptions` and :data:`!warnings.filters` instead. - .. c:function:: void PySys_WriteStdout(const char *format, ...) Write the output string described by *format* to :data:`sys.stdout`. No diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 815afddad19..3e3752696c4 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -37,6 +37,19 @@ Tuple Objects or ``NULL`` with an exception set on failure. +.. c:function:: PyObject* PyTuple_FromArray(PyObject *const *array, Py_ssize_t size) + + Create a tuple of *size* items and copy references from *array* to the new + tuple. + + *array* can be NULL if *size* is ``0``. + + On success, return a new reference. + On error, set an exception and return ``NULL``. + + .. versionadded:: 3.15 + + .. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...) Return a new tuple object of size *n*, @@ -48,7 +61,7 @@ Tuple Objects .. c:function:: Py_ssize_t PyTuple_Size(PyObject *p) Take a pointer to a tuple object, and return the size of that tuple. - On error, return ``-1`` and with an exception set. + On error, return ``-1`` with an exception set. .. c:function:: Py_ssize_t PyTuple_GET_SIZE(PyObject *p) @@ -135,8 +148,11 @@ Tuple Objects Struct Sequence Objects ----------------------- -Struct sequence objects are the C equivalent of :func:`~collections.namedtuple` -objects, i.e. a sequence whose items can also be accessed through attributes. +A struct sequence object is a :term:`named tuple`, that is, a sequence +whose items can also be accessed through attributes. +It is similar to :func:`collections.namedtuple`, but provides a slightly +different interface. + To create a struct sequence, you first have to create a specific struct sequence type. diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 5bdbff4e0ad..8cadf26cee3 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -116,6 +116,20 @@ Type Objects .. versionadded:: 3.12 +.. c:function:: int PyType_Unwatch(int watcher_id, PyObject *type) + + Mark *type* as not watched. This undoes a previous call to + :c:func:`PyType_Watch`. *type* must not be ``NULL``. + + An extension should never call this function with a *watcher_id* that was + not returned to it by a previous call to :c:func:`PyType_AddWatcher`. + + On success, this function returns ``0``. On failure, this function returns + ``-1`` with an exception set. + + .. versionadded:: 3.12 + + .. c:type:: int (*PyType_WatchCallback)(PyObject *type) Type of a type-watcher callback function. @@ -133,6 +147,18 @@ Type Objects Type features are denoted by single bit flags. +.. c:function:: int PyType_FastSubclass(PyTypeObject *type, int flag) + + Return non-zero if the type object *type* sets the subclass flag *flag*. + Subclass flags are denoted by + :c:macro:`Py_TPFLAGS_*_SUBCLASS `. + This function is used by many ``_Check`` functions for common types. + + .. seealso:: + :c:func:`PyObject_TypeCheck`, which is used as a slower alternative in + ``_Check`` functions for types that don't come with subclass flags. + + .. c:function:: int PyType_IS_GC(PyTypeObject *o) Return true if the type object includes support for the cycle detector; this @@ -169,12 +195,14 @@ Type Objects before initialization) and should be paired with :c:func:`PyObject_Free` in :c:member:`~PyTypeObject.tp_free`. + .. c:function:: PyObject* PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds) Generic handler for the :c:member:`~PyTypeObject.tp_new` slot of a type object. Creates a new instance using the type's :c:member:`~PyTypeObject.tp_alloc` slot and returns the resulting object. + .. c:function:: int PyType_Ready(PyTypeObject *type) Finalize a type object. This should be called on all type objects to finish @@ -191,6 +219,7 @@ Type Objects GC protocol itself by at least implementing the :c:member:`~PyTypeObject.tp_traverse` handle. + .. c:function:: PyObject* PyType_GetName(PyTypeObject *type) Return the type's name. Equivalent to getting the type's @@ -198,6 +227,7 @@ Type Objects .. versionadded:: 3.11 + .. c:function:: PyObject* PyType_GetQualName(PyTypeObject *type) Return the type's qualified name. Equivalent to getting the @@ -213,6 +243,7 @@ Type Objects .. versionadded:: 3.13 + .. c:function:: PyObject* PyType_GetModuleName(PyTypeObject *type) Return the type's module name. Equivalent to getting the @@ -220,6 +251,7 @@ Type Objects .. versionadded:: 3.13 + .. c:function:: void* PyType_GetSlot(PyTypeObject *type, int slot) Return the function pointer stored in the given slot. If the @@ -236,6 +268,7 @@ Type Objects :c:func:`PyType_GetSlot` can now accept all types. Previously, it was limited to :ref:`heap types `. + .. c:function:: PyObject* PyType_GetModule(PyTypeObject *type) Return the module object associated with the given type when the type was @@ -250,11 +283,12 @@ Type Objects ``Py_TYPE(self)`` may be a *subclass* of the intended class, and subclasses are not necessarily defined in the same module as their superclass. See :c:type:`PyCMethod` to get the class that defines the method. - See :c:func:`PyType_GetModuleByDef` for cases when :c:type:`!PyCMethod` cannot - be used. + See :c:func:`PyType_GetModuleByToken` for cases when :c:type:`!PyCMethod` + cannot be used. .. versionadded:: 3.9 + .. c:function:: void* PyType_GetModuleState(PyTypeObject *type) Return the state of the module object associated with the given type. @@ -269,10 +303,11 @@ Type Objects .. versionadded:: 3.9 -.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def) - Find the first superclass whose module was created from - the given :c:type:`PyModuleDef` *def*, and return that module. +.. c:function:: PyObject* PyType_GetModuleByToken(PyTypeObject *type, const void *mod_token) + + Find the first superclass whose module has the given + :ref:`module token `, and return that module. If no module is found, raises a :py:class:`TypeError` and returns ``NULL``. @@ -282,16 +317,34 @@ Type Objects and other places where a method's defining class cannot be passed using the :c:type:`PyCMethod` calling convention. + .. versionadded:: 3.15 + + +.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def) + + Find the first superclass whose module was created from the given + :c:type:`PyModuleDef` *def*, or whose :ref:`module token ` + is equal to *def*, and return that module. + + Note that modules created from a :c:type:`PyModuleDef` always have their + token set to the :c:type:`PyModuleDef`'s address. + In other words, this function is equivalent to + :c:func:`PyType_GetModuleByToken`, except that it: + + - returns a borrowed reference, and + - has a non-``void*`` argument type (which is a cosmetic difference in C). + The returned reference is :term:`borrowed ` from *type*, and will be valid as long as you hold a reference to *type*. Do not release it with :c:func:`Py_DECREF` or similar. .. versionadded:: 3.11 -.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result) + +.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *tp_token, PyTypeObject **result) Find the first superclass in *type*'s :term:`method resolution order` whose - :c:macro:`Py_tp_token` token is equal to the given one. + :c:macro:`Py_tp_token` token is equal to *tp_token*. * If found, set *\*result* to a new :term:`strong reference` to it and return ``1``. @@ -302,10 +355,11 @@ Type Objects The *result* argument may be ``NULL``, in which case *\*result* is not set. Use this if you need only the return value. - The *token* argument may not be ``NULL``. + The *tp_token* argument may not be ``NULL``. .. versionadded:: 3.14 + .. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type) Attempt to assign a version tag to the given type. @@ -316,6 +370,16 @@ Type Objects .. versionadded:: 3.12 +.. c:function:: int PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) + + Return true if instances of *type* support creating weak references, false + otherwise. This function always succeeds. *type* must not be ``NULL``. + + .. seealso:: + * :ref:`weakrefobjects` + * :py:mod:`weakref` + + Creating Heap-Allocated Types ............................. @@ -336,8 +400,8 @@ The following functions and structs are used to create The *bases* argument can be used to specify base classes; it can either be only one class or a tuple of classes. - If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead. - If that also is ``NULL``, the *Py_tp_base* slot is used instead. + If *bases* is ``NULL``, the :c:data:`Py_tp_bases` slot is used instead. + If that also is ``NULL``, the :c:data:`Py_tp_base` slot is used instead. If that also is ``NULL``, the new type derives from :class:`object`. The *module* argument can be used to record the module in which the new @@ -364,6 +428,7 @@ The following functions and structs are used to create .. versionadded:: 3.12 + .. c:function:: PyObject* PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) Equivalent to ``PyType_FromMetaclass(NULL, module, spec, bases)``. @@ -390,6 +455,7 @@ The following functions and structs are used to create Creating classes whose metaclass overrides :c:member:`~PyTypeObject.tp_new` is no longer allowed. + .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, bases)``. @@ -411,6 +477,7 @@ The following functions and structs are used to create Creating classes whose metaclass overrides :c:member:`~PyTypeObject.tp_new` is no longer allowed. + .. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec) Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, NULL)``. @@ -431,6 +498,7 @@ The following functions and structs are used to create Creating classes whose metaclass overrides :c:member:`~PyTypeObject.tp_new` is no longer allowed. + .. c:function:: int PyType_Freeze(PyTypeObject *type) Make a type immutable: set the :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag. @@ -539,9 +607,9 @@ The following functions and structs are used to create :c:type:`PyAsyncMethods` with an added ``Py_`` prefix. For example, use: - * ``Py_tp_dealloc`` to set :c:member:`PyTypeObject.tp_dealloc` - * ``Py_nb_add`` to set :c:member:`PyNumberMethods.nb_add` - * ``Py_sq_length`` to set :c:member:`PySequenceMethods.sq_length` + * :c:data:`Py_tp_dealloc` to set :c:member:`PyTypeObject.tp_dealloc` + * :c:data:`Py_nb_add` to set :c:member:`PyNumberMethods.nb_add` + * :c:data:`Py_sq_length` to set :c:member:`PySequenceMethods.sq_length` An additional slot is supported that does not correspond to a :c:type:`!PyTypeObject` struct field: @@ -560,7 +628,7 @@ The following functions and structs are used to create If it is not possible to switch to a ``MANAGED`` flag (for example, for vectorcall or to support Python older than 3.12), specify the - offset in :c:member:`Py_tp_members `. + offset in :c:data:`Py_tp_members`. See :ref:`PyMemberDef documentation ` for details. @@ -587,8 +655,8 @@ The following functions and structs are used to create under the :ref:`limited API `. .. versionchanged:: 3.14 - The field :c:member:`~PyTypeObject.tp_vectorcall` can now set - using ``Py_tp_vectorcall``. See the field's documentation + The field :c:member:`~PyTypeObject.tp_vectorcall` can now be set + using :c:data:`Py_tp_vectorcall`. See the field's documentation for details. .. c:member:: void *pfunc @@ -598,10 +666,11 @@ The following functions and structs are used to create *pfunc* values may not be ``NULL``, except for the following slots: - * ``Py_tp_doc`` + * :c:data:`Py_tp_doc` * :c:data:`Py_tp_token` (for clarity, prefer :c:data:`Py_TP_USE_SPEC` rather than ``NULL``) + .. c:macro:: Py_tp_token A :c:member:`~PyType_Slot.slot` that records a static memory layout ID diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 8bd3144f88a..efac86078f9 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -676,6 +676,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: destructor PyTypeObject.tp_dealloc + .. corresponding-type-slot:: Py_tp_dealloc + A pointer to the instance destructor function. The function signature is:: void tp_dealloc(PyObject *self); @@ -860,6 +862,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: getattrfunc PyTypeObject.tp_getattr + .. corresponding-type-slot:: Py_tp_getattr + An optional pointer to the get-attribute-string function. This field is deprecated. When it is defined, it should point to a function @@ -877,6 +881,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: setattrfunc PyTypeObject.tp_setattr + .. corresponding-type-slot:: Py_tp_setattr + An optional pointer to the function for setting and deleting attributes. This field is deprecated. When it is defined, it should point to a function @@ -909,6 +915,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: reprfunc PyTypeObject.tp_repr + .. corresponding-type-slot:: Py_tp_repr + .. index:: pair: built-in function; repr An optional pointer to a function that implements the built-in function @@ -974,6 +982,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: hashfunc PyTypeObject.tp_hash + .. corresponding-type-slot:: Py_tp_hash + .. index:: pair: built-in function; hash An optional pointer to a function that implements the built-in function @@ -1015,6 +1025,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: ternaryfunc PyTypeObject.tp_call + .. corresponding-type-slot:: Py_tp_call + An optional pointer to a function that implements calling the object. This should be ``NULL`` if the object is not callable. The signature is the same as for :c:func:`PyObject_Call`:: @@ -1028,6 +1040,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: reprfunc PyTypeObject.tp_str + .. corresponding-type-slot:: Py_tp_str + An optional pointer to a function that implements the built-in operation :func:`str`. (Note that :class:`str` is a type now, and :func:`str` calls the constructor for that type. This constructor calls :c:func:`PyObject_Str` to do @@ -1053,6 +1067,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: getattrofunc PyTypeObject.tp_getattro + .. corresponding-type-slot:: Py_tp_getattro + An optional pointer to the get-attribute function. The signature is the same as for :c:func:`PyObject_GetAttr`:: @@ -1077,6 +1093,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: setattrofunc PyTypeObject.tp_setattro + .. corresponding-type-slot:: Py_tp_setattro + An optional pointer to the function for setting and deleting attributes. The signature is the same as for :c:func:`PyObject_SetAttr`:: @@ -1260,7 +1278,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) This bit indicates that instances of the class have a :attr:`~object.__dict__` attribute, and that the space for the dictionary is managed by the VM. - If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set. + If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set. The type traverse function must call :c:func:`PyObject_VisitManagedDict` and its clear function must call :c:func:`PyObject_ClearManagedDict`. @@ -1278,6 +1296,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) This bit indicates that instances of the class should be weakly referenceable. + If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` must also be set. + .. versionadded:: 3.12 **Inheritance:** @@ -1331,8 +1351,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:macro:: Py_TPFLAGS_BASE_EXC_SUBCLASS .. c:macro:: Py_TPFLAGS_TYPE_SUBCLASS - These flags are used by functions such as - :c:func:`PyLong_Check` to quickly determine if a type is a subclass + Functions such as :c:func:`PyLong_Check` will call :c:func:`PyType_FastSubclass` + with one of these flags to quickly determine if a type is a subclass of a built-in type; such specific checks are faster than a generic check, like :c:func:`PyObject_IsInstance`. Custom types that inherit from built-ins should have their :c:member:`~PyTypeObject.tp_flags` @@ -1473,6 +1493,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: const char* PyTypeObject.tp_doc + .. corresponding-type-slot:: Py_tp_doc + An optional pointer to a NUL-terminated C string giving the docstring for this type object. This is exposed as the :attr:`~type.__doc__` attribute on the type and instances of the type. @@ -1484,6 +1506,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: traverseproc PyTypeObject.tp_traverse + .. corresponding-type-slot:: Py_tp_traverse + An optional pointer to a traversal function for the garbage collector. This is only used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is:: @@ -1545,6 +1569,11 @@ and :c:data:`PyType_Type` effectively act as defaults.) but the instance has no strong reference to the elements inside it, as they are allowed to be removed even if the instance is still alive). + .. warning:: + The traversal function must not have any side effects. It must not + modify the reference counts of any Python objects nor create or destroy + any Python objects. + Note that :c:func:`Py_VISIT` requires the *visit* and *arg* parameters to :c:func:`!local_traverse` to have these specific names; don't name them just anything. @@ -1580,6 +1609,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: inquiry PyTypeObject.tp_clear + .. corresponding-type-slot:: Py_tp_clear + An optional pointer to a clear function. The signature is:: int tp_clear(PyObject *); @@ -1704,7 +1735,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) :c:func:`Py_CLEAR` macro performs the operations in a safe order. If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the - :c:member:`~PyTypeObject.tp_flags` field, the traverse function must call + :c:member:`~PyTypeObject.tp_flags` field, the clear function must call :c:func:`PyObject_ClearManagedDict` like this:: PyObject_ClearManagedDict((PyObject*)self); @@ -1728,6 +1759,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: richcmpfunc PyTypeObject.tp_richcompare + .. corresponding-type-slot:: Py_tp_richcompare + An optional pointer to the rich comparison function, whose signature is:: PyObject *tp_richcompare(PyObject *self, PyObject *other, int op); @@ -1830,6 +1863,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: getiterfunc PyTypeObject.tp_iter + .. corresponding-type-slot:: Py_tp_iter + An optional pointer to a function that returns an :term:`iterator` for the object. Its presence normally signals that the instances of this type are :term:`iterable` (although sequences may be iterable without this function). @@ -1845,6 +1880,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: iternextfunc PyTypeObject.tp_iternext + .. corresponding-type-slot:: Py_tp_iternext + An optional pointer to a function that returns the next item in an :term:`iterator`. The signature is:: @@ -1868,6 +1905,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: struct PyMethodDef* PyTypeObject.tp_methods + .. corresponding-type-slot:: Py_tp_methods + An optional pointer to a static ``NULL``-terminated array of :c:type:`PyMethodDef` structures, declaring regular methods of this type. @@ -1882,6 +1921,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: struct PyMemberDef* PyTypeObject.tp_members + .. corresponding-type-slot:: Py_tp_members + An optional pointer to a static ``NULL``-terminated array of :c:type:`PyMemberDef` structures, declaring regular data members (fields or slots) of instances of this type. @@ -1897,6 +1938,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: struct PyGetSetDef* PyTypeObject.tp_getset + .. corresponding-type-slot:: Py_tp_getset + An optional pointer to a static ``NULL``-terminated array of :c:type:`PyGetSetDef` structures, declaring computed attributes of instances of this type. @@ -1911,6 +1954,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: PyTypeObject* PyTypeObject.tp_base + .. corresponding-type-slot:: Py_tp_base + An optional pointer to a base type from which type properties are inherited. At this level, only single inheritance is supported; multiple inheritance require dynamically creating a type object by calling the metatype. @@ -1983,6 +2028,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: descrgetfunc PyTypeObject.tp_descr_get + .. corresponding-type-slot:: Py_tp_descr_get + An optional pointer to a "descriptor get" function. The function signature is:: @@ -1998,6 +2045,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: descrsetfunc PyTypeObject.tp_descr_set + .. corresponding-type-slot:: Py_tp_descr_set + An optional pointer to a function for setting and deleting a descriptor's value. @@ -2058,6 +2107,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: initproc PyTypeObject.tp_init + .. corresponding-type-slot:: Py_tp_init + An optional pointer to an instance initialization function. This function corresponds to the :meth:`~object.__init__` method of classes. Like @@ -2093,6 +2144,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: allocfunc PyTypeObject.tp_alloc + .. corresponding-type-slot:: Py_tp_alloc + An optional pointer to an instance allocation function. The function signature is:: @@ -2116,6 +2169,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: newfunc PyTypeObject.tp_new + .. corresponding-type-slot:: Py_tp_new + An optional pointer to an instance creation function. The function signature is:: @@ -2155,6 +2210,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: freefunc PyTypeObject.tp_free + .. corresponding-type-slot:: Py_tp_free + An optional pointer to an instance deallocation function. Its signature is:: void tp_free(void *self); @@ -2184,6 +2241,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: inquiry PyTypeObject.tp_is_gc + .. corresponding-type-slot:: Py_tp_is_gc + An optional pointer to a function called by the garbage collector. The garbage collector needs to know whether a particular object is collectible @@ -2212,12 +2271,14 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: PyObject* PyTypeObject.tp_bases + .. corresponding-type-slot:: Py_tp_bases + Tuple of base types. This field should be set to ``NULL`` and treated as read-only. Python will fill it in when the type is :c:func:`initialized `. - For dynamically created classes, the ``Py_tp_bases`` + For dynamically created classes, the :c:data:`Py_tp_bases` :c:type:`slot ` can be used instead of the *bases* argument of :c:func:`PyType_FromSpecWithBases`. The argument form is preferred. @@ -2292,6 +2353,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: destructor PyTypeObject.tp_del + .. corresponding-type-slot:: Py_tp_del + This field is deprecated. Use :c:member:`~PyTypeObject.tp_finalize` instead. @@ -2306,6 +2369,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: destructor PyTypeObject.tp_finalize + .. corresponding-type-slot:: Py_tp_finalize + An optional pointer to an instance finalization function. This is the C implementation of the :meth:`~object.__del__` special method. Its signature is:: @@ -2464,6 +2529,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: vectorcallfunc PyTypeObject.tp_vectorcall + .. corresponding-type-slot:: Py_tp_vectorcall + A :ref:`vectorcall function ` to use for calls of this type object (rather than instances). In other words, ``tp_vectorcall`` can be used to optimize ``type.__call__``, @@ -2629,42 +2696,148 @@ Number Object Structures Python 3.0.1. .. c:member:: binaryfunc PyNumberMethods.nb_add + + .. corresponding-type-slot:: Py_nb_add + .. c:member:: binaryfunc PyNumberMethods.nb_subtract + + .. corresponding-type-slot:: Py_nb_subtract + .. c:member:: binaryfunc PyNumberMethods.nb_multiply + + .. corresponding-type-slot:: Py_nb_multiply + .. c:member:: binaryfunc PyNumberMethods.nb_remainder + + .. corresponding-type-slot:: Py_nb_remainder + .. c:member:: binaryfunc PyNumberMethods.nb_divmod + + .. corresponding-type-slot:: Py_nb_divmod + .. c:member:: ternaryfunc PyNumberMethods.nb_power + + .. corresponding-type-slot:: Py_nb_power + .. c:member:: unaryfunc PyNumberMethods.nb_negative + + .. corresponding-type-slot:: Py_nb_negative + .. c:member:: unaryfunc PyNumberMethods.nb_positive + + .. corresponding-type-slot:: Py_nb_positive + .. c:member:: unaryfunc PyNumberMethods.nb_absolute + + .. corresponding-type-slot:: Py_nb_absolute + .. c:member:: inquiry PyNumberMethods.nb_bool + + .. corresponding-type-slot:: Py_nb_bool + .. c:member:: unaryfunc PyNumberMethods.nb_invert + + .. corresponding-type-slot:: Py_nb_invert + .. c:member:: binaryfunc PyNumberMethods.nb_lshift + + .. corresponding-type-slot:: Py_nb_lshift + .. c:member:: binaryfunc PyNumberMethods.nb_rshift + + .. corresponding-type-slot:: Py_nb_rshift + .. c:member:: binaryfunc PyNumberMethods.nb_and + + .. corresponding-type-slot:: Py_nb_and + .. c:member:: binaryfunc PyNumberMethods.nb_xor + + .. corresponding-type-slot:: Py_nb_xor + .. c:member:: binaryfunc PyNumberMethods.nb_or + + .. corresponding-type-slot:: Py_nb_or + .. c:member:: unaryfunc PyNumberMethods.nb_int + + .. corresponding-type-slot:: Py_nb_int + .. c:member:: void *PyNumberMethods.nb_reserved + .. c:member:: unaryfunc PyNumberMethods.nb_float + + .. corresponding-type-slot:: Py_nb_float + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_add + + .. corresponding-type-slot:: Py_nb_inplace_add + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_subtract + + .. corresponding-type-slot:: Py_nb_inplace_subtract + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_multiply + + .. corresponding-type-slot:: Py_nb_inplace_multiply + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_remainder + + .. corresponding-type-slot:: Py_nb_inplace_remainder + .. c:member:: ternaryfunc PyNumberMethods.nb_inplace_power + + .. corresponding-type-slot:: Py_nb_inplace_power + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_lshift + + .. corresponding-type-slot:: Py_nb_inplace_lshift + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_rshift + + .. corresponding-type-slot:: Py_nb_inplace_rshift + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_and + + .. corresponding-type-slot:: Py_nb_inplace_and + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_xor + + .. corresponding-type-slot:: Py_nb_inplace_xor + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_or + + .. corresponding-type-slot:: Py_nb_inplace_or + .. c:member:: binaryfunc PyNumberMethods.nb_floor_divide + + .. corresponding-type-slot:: Py_nb_floor_divide + .. c:member:: binaryfunc PyNumberMethods.nb_true_divide + + .. corresponding-type-slot:: Py_nb_true_divide + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_floor_divide + + .. corresponding-type-slot:: Py_nb_inplace_floor_divide + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_true_divide + + .. corresponding-type-slot:: Py_nb_inplace_true_divide + .. c:member:: unaryfunc PyNumberMethods.nb_index + + .. corresponding-type-slot:: Py_nb_index + .. c:member:: binaryfunc PyNumberMethods.nb_matrix_multiply + + .. corresponding-type-slot:: Py_nb_matrix_multiply + .. c:member:: binaryfunc PyNumberMethods.nb_inplace_matrix_multiply + .. corresponding-type-slot:: Py_nb_inplace_matrix_multiply + + .. _mapping-structs: @@ -2681,12 +2854,16 @@ Mapping Object Structures .. c:member:: lenfunc PyMappingMethods.mp_length + .. corresponding-type-slot:: Py_mp_length + This function is used by :c:func:`PyMapping_Size` and :c:func:`PyObject_Size`, and has the same signature. This slot may be set to ``NULL`` if the object has no defined length. .. c:member:: binaryfunc PyMappingMethods.mp_subscript + .. corresponding-type-slot:: Py_mp_subscript + This function is used by :c:func:`PyObject_GetItem` and :c:func:`PySequence_GetSlice`, and has the same signature as :c:func:`!PyObject_GetItem`. This slot must be filled for the @@ -2695,6 +2872,8 @@ Mapping Object Structures .. c:member:: objobjargproc PyMappingMethods.mp_ass_subscript + .. corresponding-type-slot:: Py_mp_ass_subscript + This function is used by :c:func:`PyObject_SetItem`, :c:func:`PyObject_DelItem`, :c:func:`PySequence_SetSlice` and :c:func:`PySequence_DelSlice`. It has the same signature as @@ -2718,6 +2897,8 @@ Sequence Object Structures .. c:member:: lenfunc PySequenceMethods.sq_length + .. corresponding-type-slot:: Py_sq_length + This function is used by :c:func:`PySequence_Size` and :c:func:`PyObject_Size`, and has the same signature. It is also used for handling negative indices via the :c:member:`~PySequenceMethods.sq_item` @@ -2725,18 +2906,24 @@ Sequence Object Structures .. c:member:: binaryfunc PySequenceMethods.sq_concat + .. corresponding-type-slot:: Py_sq_concat + This function is used by :c:func:`PySequence_Concat` and has the same signature. It is also used by the ``+`` operator, after trying the numeric addition via the :c:member:`~PyNumberMethods.nb_add` slot. .. c:member:: ssizeargfunc PySequenceMethods.sq_repeat + .. corresponding-type-slot:: Py_sq_repeat + This function is used by :c:func:`PySequence_Repeat` and has the same signature. It is also used by the ``*`` operator, after trying numeric multiplication via the :c:member:`~PyNumberMethods.nb_multiply` slot. .. c:member:: ssizeargfunc PySequenceMethods.sq_item + .. corresponding-type-slot:: Py_sq_item + This function is used by :c:func:`PySequence_GetItem` and has the same signature. It is also used by :c:func:`PyObject_GetItem`, after trying the subscription via the :c:member:`~PyMappingMethods.mp_subscript` slot. @@ -2750,6 +2937,8 @@ Sequence Object Structures .. c:member:: ssizeobjargproc PySequenceMethods.sq_ass_item + .. corresponding-type-slot:: Py_sq_ass_item + This function is used by :c:func:`PySequence_SetItem` and has the same signature. It is also used by :c:func:`PyObject_SetItem` and :c:func:`PyObject_DelItem`, after trying the item assignment and deletion @@ -2759,6 +2948,8 @@ Sequence Object Structures .. c:member:: objobjproc PySequenceMethods.sq_contains + .. corresponding-type-slot:: Py_sq_contains + This function may be used by :c:func:`PySequence_Contains` and has the same signature. This slot may be left to ``NULL``, in this case :c:func:`!PySequence_Contains` simply traverses the sequence until it @@ -2766,6 +2957,8 @@ Sequence Object Structures .. c:member:: binaryfunc PySequenceMethods.sq_inplace_concat + .. corresponding-type-slot:: Py_sq_inplace_concat + This function is used by :c:func:`PySequence_InPlaceConcat` and has the same signature. It should modify its first operand, and return it. This slot may be left to ``NULL``, in this case :c:func:`!PySequence_InPlaceConcat` @@ -2775,6 +2968,8 @@ Sequence Object Structures .. c:member:: ssizeargfunc PySequenceMethods.sq_inplace_repeat + .. corresponding-type-slot:: Py_sq_inplace_repeat + This function is used by :c:func:`PySequence_InPlaceRepeat` and has the same signature. It should modify its first operand, and return it. This slot may be left to ``NULL``, in this case :c:func:`!PySequence_InPlaceRepeat` @@ -2800,6 +2995,8 @@ Buffer Object Structures .. c:member:: getbufferproc PyBufferProcs.bf_getbuffer + .. corresponding-type-slot:: Py_bf_getbuffer + The signature of this function is:: int (PyObject *exporter, Py_buffer *view, int flags); @@ -2849,6 +3046,8 @@ Buffer Object Structures .. c:member:: releasebufferproc PyBufferProcs.bf_releasebuffer + .. corresponding-type-slot:: Py_bf_releasebuffer + The signature of this function is:: void (PyObject *exporter, Py_buffer *view); @@ -2903,6 +3102,8 @@ Async Object Structures .. c:member:: unaryfunc PyAsyncMethods.am_await + .. corresponding-type-slot:: Py_am_await + The signature of this function is:: PyObject *am_await(PyObject *self); @@ -2914,6 +3115,8 @@ Async Object Structures .. c:member:: unaryfunc PyAsyncMethods.am_aiter + .. corresponding-type-slot:: Py_am_aiter + The signature of this function is:: PyObject *am_aiter(PyObject *self); @@ -2926,6 +3129,8 @@ Async Object Structures .. c:member:: unaryfunc PyAsyncMethods.am_anext + .. corresponding-type-slot:: Py_am_anext + The signature of this function is:: PyObject *am_anext(PyObject *self); @@ -2936,6 +3141,8 @@ Async Object Structures .. c:member:: sendfunc PyAsyncMethods.am_send + .. corresponding-type-slot:: Py_am_send + The signature of this function is:: PySendResult am_send(PyObject *self, PyObject *arg, PyObject **result); diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 84fee05cb4c..ca7c8bb11a5 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -321,12 +321,22 @@ These APIs can be used to work with surrogates: Check if *ch* is a low surrogate (``0xDC00 <= ch <= 0xDFFF``). +.. c:function:: Py_UCS4 Py_UNICODE_HIGH_SURROGATE(Py_UCS4 ch) + + Return the high UTF-16 surrogate (``0xD800`` to ``0xDBFF``) for a Unicode + code point in the range ``[0x10000; 0x10FFFF]``. + +.. c:function:: Py_UCS4 Py_UNICODE_LOW_SURROGATE(Py_UCS4 ch) + + Return the low UTF-16 surrogate (``0xDC00`` to ``0xDFFF``) for a Unicode + code point in the range ``[0x10000; 0x10FFFF]``. + .. c:function:: Py_UCS4 Py_UNICODE_JOIN_SURROGATES(Py_UCS4 high, Py_UCS4 low) Join two surrogate code points and return a single :c:type:`Py_UCS4` value. *high* and *low* are respectively the leading and trailing surrogates in a - surrogate pair. *high* must be in the range [0xD800; 0xDBFF] and *low* must - be in the range [0xDC00; 0xDFFF]. + surrogate pair. *high* must be in the range ``[0xD800; 0xDBFF]`` and *low* must + be in the range ``[0xDC00; 0xDFFF]``. Creating and accessing Unicode strings @@ -747,7 +757,7 @@ APIs: Return ``0`` on success, ``-1`` on error with an exception set. This function checks that *unicode* is a Unicode object, that the index is - not out of bounds, and that the object's reference count is one). + not out of bounds, and that the object's reference count is one. See :c:func:`PyUnicode_WRITE` for a version that skips these checks, making them your responsibility. diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index fb07fec7eff..7eb9f0b54ab 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -13,8 +13,9 @@ the interpreter. Several of these functions accept a start symbol from the grammar as a parameter. The available start symbols are :c:data:`Py_eval_input`, -:c:data:`Py_file_input`, and :c:data:`Py_single_input`. These are described -following the functions which accept them as parameters. +:c:data:`Py_file_input`, :c:data:`Py_single_input`, and +:c:data:`Py_func_type_input`. These are described following the functions +which accept them as parameters. Note also that several of these functions take :c:expr:`FILE*` parameters. One particular issue which needs to be handled carefully is that the :c:type:`FILE` @@ -99,6 +100,20 @@ the same library that the Python runtime is using. Otherwise, Python may not handle script file with LF line ending correctly. +.. c:function:: int PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) + + Read and execute a single statement from a file associated with an + interactive device according to the *flags* argument. The user will be + prompted using ``sys.ps1`` and ``sys.ps2``. *filename* must be a Python + :class:`str` object. + + Returns ``0`` when the input was + executed successfully, ``-1`` if there was an exception, or an error code + from the :file:`errcode.h` include file distributed as part of Python if + there was a parse error. (Note that :file:`errcode.h` is not included by + :file:`Python.h`, so must be included specifically if needed.) + + .. c:function:: int PyRun_InteractiveOne(FILE *fp, const char *filename) This is a simplified interface to :c:func:`PyRun_InteractiveOneFlags` below, @@ -107,17 +122,10 @@ the same library that the Python runtime is using. .. c:function:: int PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags) - Read and execute a single statement from a file associated with an - interactive device according to the *flags* argument. The user will be - prompted using ``sys.ps1`` and ``sys.ps2``. *filename* is decoded from the + Similar to :c:func:`PyRun_InteractiveOneObject`, but *filename* is a + :c:expr:`const char*`, which is decoded from the :term:`filesystem encoding and error handler`. - Returns ``0`` when the input was - executed successfully, ``-1`` if there was an exception, or an error code - from the :file:`errcode.h` include file distributed as part of Python if - there was a parse error. (Note that :file:`errcode.h` is not included by - :file:`Python.h`, so must be included specifically if needed.) - .. c:function:: int PyRun_InteractiveLoop(FILE *fp, const char *filename) @@ -140,7 +148,7 @@ the same library that the Python runtime is using. interpreter prompt is about to become idle and wait for user input from the terminal. The return value is ignored. Overriding this hook can be used to integrate the interpreter's prompt with other - event loops, as done in the :file:`Modules/_tkinter.c` in the + event loops, as done in :file:`Modules/_tkinter.c` in the Python source code. .. versionchanged:: 3.12 @@ -183,7 +191,7 @@ the same library that the Python runtime is using. objects *globals* and *locals* with the compiler flags specified by *flags*. *globals* must be a dictionary; *locals* can be any object that implements the mapping protocol. The parameter *start* specifies - the start token that should be used to parse the source code. + the start symbol and must one of the :ref:`available start symbols `. Returns the result of executing the code as a Python object, or ``NULL`` if an exception was raised. @@ -231,9 +239,9 @@ the same library that the Python runtime is using. .. c:function:: PyObject* Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize) Parse and compile the Python source code in *str*, returning the resulting code - object. The start token is given by *start*; this can be used to constrain the - code which can be compiled and should be :c:data:`Py_eval_input`, - :c:data:`Py_file_input`, or :c:data:`Py_single_input`. The filename specified by + object. The start symbol is given by *start*; this can be used to constrain the + code which can be compiled and should be :ref:`available start symbols + `. The filename specified by *filename* is used to construct the code object and may appear in tracebacks or :exc:`SyntaxError` exception messages. This returns ``NULL`` if the code cannot be parsed or compiled. @@ -296,32 +304,6 @@ the same library that the Python runtime is using. true on success, false on failure. -.. c:var:: int Py_eval_input - - .. index:: single: Py_CompileString (C function) - - The start symbol from the Python grammar for isolated expressions; for use with - :c:func:`Py_CompileString`. - - -.. c:var:: int Py_file_input - - .. index:: single: Py_CompileString (C function) - - The start symbol from the Python grammar for sequences of statements as read - from a file or other source; for use with :c:func:`Py_CompileString`. This is - the symbol to use when compiling arbitrarily long Python source code. - - -.. c:var:: int Py_single_input - - .. index:: single: Py_CompileString (C function) - - The start symbol from the Python grammar for a single statement; for use with - :c:func:`Py_CompileString`. This is the symbol used for the interactive - interpreter loop. - - .. c:struct:: PyCompilerFlags This is the structure used to hold compiler flags. In cases where code is only @@ -365,3 +347,92 @@ the same library that the Python runtime is using. as :c:macro:`CO_FUTURE_ANNOTATIONS` to enable features normally selectable using :ref:`future statements `. See :ref:`c_codeobject_flags` for a complete list. + + +.. _start-symbols: + +Available start symbols +^^^^^^^^^^^^^^^^^^^^^^^ + + +.. c:var:: int Py_eval_input + + .. index:: single: Py_CompileString (C function) + + The start symbol from the Python grammar for isolated expressions; for use with + :c:func:`Py_CompileString`. + + +.. c:var:: int Py_file_input + + .. index:: single: Py_CompileString (C function) + + The start symbol from the Python grammar for sequences of statements as read + from a file or other source; for use with :c:func:`Py_CompileString`. This is + the symbol to use when compiling arbitrarily long Python source code. + + +.. c:var:: int Py_single_input + + .. index:: single: Py_CompileString (C function) + + The start symbol from the Python grammar for a single statement; for use with + :c:func:`Py_CompileString`. This is the symbol used for the interactive + interpreter loop. + + +.. c:var:: int Py_func_type_input + + .. index:: single: Py_CompileString (C function) + + The start symbol from the Python grammar for a function type; for use with + :c:func:`Py_CompileString`. This is used to parse "signature type comments" + from :pep:`484`. + + This requires the :c:macro:`PyCF_ONLY_AST` flag to be set. + + .. seealso:: + * :py:class:`ast.FunctionType` + * :pep:`484` + + .. versionadded:: 3.8 + + +Stack Effects +^^^^^^^^^^^^^ + +.. seealso:: + :py:func:`dis.stack_effect` + + +.. c:macro:: PY_INVALID_STACK_EFFECT + + Sentinel value representing an invalid stack effect. + + This is currently equivalent to ``INT_MAX``. + + .. versionadded:: 3.8 + + +.. c:function:: int PyCompile_OpcodeStackEffect(int opcode, int oparg) + + Compute the stack effect of *opcode* with argument *oparg*. + + On success, this function returns the stack effect; on failure, this + returns :c:macro:`PY_INVALID_STACK_EFFECT`. + + .. versionadded:: 3.4 + + +.. c:function:: int PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump) + + Similar to :c:func:`PyCompile_OpcodeStackEffect`, but don't include the + stack effect of jumping if *jump* is zero. + + If *jump* is ``0``, this will not include the stack effect of jumping, but + if *jump* is ``1`` or ``-1``, this will include it. + + On success, this function returns the stack effect; on failure, this + returns :c:macro:`PY_INVALID_STACK_EFFECT`. + + .. versionadded:: 3.8 diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index c3c6cf413dc..db6ae0a9d4e 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -19,7 +19,14 @@ as much as it can. .. c:function:: int PyWeakref_CheckRef(PyObject *ob) - Return non-zero if *ob* is a reference object. This function always succeeds. + Return non-zero if *ob* is a reference object or a subclass of the reference + type. This function always succeeds. + + +.. c:function:: int PyWeakref_CheckRefExact(PyObject *ob) + + Return non-zero if *ob* is a reference object, but not a subclass of the + reference type. This function always succeeds. .. c:function:: int PyWeakref_CheckProxy(PyObject *ob) @@ -38,6 +45,10 @@ as much as it can. weakly referenceable object, or if *callback* is not callable, ``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`. + .. seealso:: + :c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly + referenceable. + .. c:function:: PyObject* PyWeakref_NewProxy(PyObject *ob, PyObject *callback) @@ -50,6 +61,10 @@ as much as it can. is not a weakly referenceable object, or if *callback* is not callable, ``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`. + .. seealso:: + :c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly + referenceable. + .. c:function:: int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) @@ -64,30 +79,6 @@ as much as it can. .. versionadded:: 3.13 -.. c:function:: PyObject* PyWeakref_GetObject(PyObject *ref) - - Return a :term:`borrowed reference` to the referenced object from a weak - reference, *ref*. If the referent is no longer live, returns ``Py_None``. - - .. note:: - - This function returns a :term:`borrowed reference` to the referenced object. - This means that you should always call :c:func:`Py_INCREF` on the object - except when it cannot be destroyed before the last usage of the borrowed - reference. - - .. deprecated-removed:: 3.13 3.15 - Use :c:func:`PyWeakref_GetRef` instead. - - -.. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref) - - Similar to :c:func:`PyWeakref_GetObject`, but does no error checking. - - .. deprecated-removed:: 3.13 3.15 - Use :c:func:`PyWeakref_GetRef` instead. - - .. c:function:: int PyWeakref_IsDead(PyObject *ref) Test if the weak reference *ref* is dead. Returns 1 if the reference is diff --git a/Doc/conf.py b/Doc/conf.py index 35e0b3eaeaf..f6efc5ff22a 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -221,31 +221,18 @@ nitpick_ignore = [ ('envvar', 'USER'), ('envvar', 'USERNAME'), ('envvar', 'USERPROFILE'), - # Deprecated function that was never documented: - ('py:func', 'getargspec'), - ('py:func', 'inspect.getargspec'), - # Undocumented modules that users shouldn't have to worry about - # (implementation details of `os.path`): - ('py:mod', 'ntpath'), - ('py:mod', 'posixpath'), ] # Temporary undocumented names. # In future this list must be empty. nitpick_ignore += [ - # Undocumented public C macros - ('c:macro', 'Py_BUILD_ASSERT'), - ('c:macro', 'Py_BUILD_ASSERT_EXPR'), # Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot # be resolved, as the method is currently undocumented. For context, see # https://github.com/python/cpython/pull/103289. ('py:meth', '_SubParsersAction.add_parser'), # Attributes/methods/etc. that definitely should be documented better, # but are deferred for now: - ('py:attr', '__annotations__'), - ('py:meth', '__missing__'), ('py:attr', '__wrapped__'), - ('py:meth', 'index'), # list.index, tuple.index, etc. ] # gh-106948: Copy standard C types declared in the "c:type" domain and C @@ -369,11 +356,12 @@ latex_elements = { 'papersize': 'a4paper', # The font size ('10pt', '11pt' or '12pt'). 'pointsize': '10pt', + 'maxlistdepth': '8', # See https://github.com/python/cpython/issues/139588 } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). -_stdauthor = 'Guido van Rossum and the Python development team' +_stdauthor = 'The Python development team' latex_documents = [ ('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'), ( @@ -448,12 +436,36 @@ latex_appendices = ['glossary', 'about', 'license', 'copyright'] epub_author = 'Python Documentation Authors' epub_publisher = 'Python Software Foundation' -epub_exclude_files = ('index.xhtml', 'download.xhtml') +epub_exclude_files = ( + 'index.xhtml', + 'download.xhtml', + '_static/tachyon-example-flamegraph.html', + '_static/tachyon-example-heatmap.html', +) # index pages are not valid xhtml # https://github.com/sphinx-doc/sphinx/issues/12359 epub_use_index = False +# translation tag +# --------------- + +language_code = None +for arg in sys.argv: + if arg.startswith('language='): + language_code = arg.split('=', 1)[1] + +if language_code: + tags.add('translation') # noqa: F821 + + rst_epilog += f"""\ +.. _TRANSLATION_REPO: https://github.com/python/python-docs-{language_code.replace("_", "-").lower()} +""" # noqa: F821 +else: + rst_epilog += """\ +.. _TRANSLATION_REPO: https://github.com/python +""" + # Options for the coverage checker # -------------------------------- diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 144c5608e07..64399f6ab1f 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -1141,6 +1141,9 @@ PyInterpreterState_Clear:PyInterpreterState*:interp:: PyInterpreterState_Delete:void::: PyInterpreterState_Delete:PyInterpreterState*:interp:: +PyInterpreterState_GetDict:PyObject*::0: +PyInterpreterState_GetDict:PyInterpreterState*:interp:: + PyInterpreterState_GetID:int64_t::: PyInterpreterState_GetID:PyInterpreterState*:interp:: @@ -1469,6 +1472,9 @@ PyModule_Create2:PyObject*::+1: PyModule_Create2:PyModuleDef*:def:: PyModule_Create2:int:module_api_version:: +PyModule_Exec:int::: +PyModule_ExecDef:PyObject*:module:0: + PyModule_ExecDef:int::: PyModule_ExecDef:PyObject*:module:0: PyModule_ExecDef:PyModuleDef*:def:: @@ -1482,6 +1488,10 @@ PyModule_FromDefAndSpec2:PyModuleDef*:def:: PyModule_FromDefAndSpec2:PyObject*:spec:0: PyModule_FromDefAndSpec2:int:module_api_version:: +PyModule_FromSlotsAndSpec:PyObject*::+1: +PyModule_FromSlotsAndSpec:const PyModuleDef_Slot *:slots:: +PyModule_FromSlotsAndSpec:PyObject*:spec:0: + PyModule_GetDef:PyModuleDef*::0: PyModule_GetDef:PyObject*:module:0: @@ -1503,6 +1513,14 @@ PyModule_GetNameObject:PyObject*:module:0: PyModule_GetState:void*::: PyModule_GetState:PyObject*:module:0: +PyModule_GetStateSize:int::: +PyModule_GetStateSize:PyObject*:module:0: +PyModule_GetToken:Py_ssize_t**:result:: + +PyModule_GetToken:int::: +PyModule_GetToken:PyObject*:module:0: +PyModule_GetToken:void**:result:: + PyModule_New:PyObject*::+1: PyModule_New:char*:name:: @@ -2409,6 +2427,10 @@ PyType_GetFlags:PyTypeObject*:type:0: PyType_GetName:PyObject*::+1: PyType_GetName:PyTypeObject*:type:0: +PyType_GetModuleByToken:PyObject*::+1: +PyType_GetModuleByToken:PyTypeObject*:type:0: +PyType_GetModuleByToken:PyModuleDef*:def:: + PyType_GetModuleByDef:PyObject*::0: PyType_GetModuleByDef:PyTypeObject*:type:0: PyType_GetModuleByDef:PyModuleDef*:def:: @@ -2947,12 +2969,6 @@ PyWeakref_CheckProxy:PyObject*:ob:0: PyWeakref_CheckRef:int::: PyWeakref_CheckRef:PyObject*:ob:0: -PyWeakref_GET_OBJECT:PyObject*::0: -PyWeakref_GET_OBJECT:PyObject*:ref:0: - -PyWeakref_GetObject:PyObject*::0: -PyWeakref_GetObject:PyObject*:ref:0: - PyWeakref_GetRef:int::: PyWeakref_GetRef:PyObject*:ref:0: PyWeakref_GetRef:PyObject**:pobj:+1: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 0d0dfb38432..9c5fdcefaf8 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,5 +1,22 @@ role,name,added,ifdef_note,struct_abi_kind +macro,METH_CLASS,3.2,, +macro,METH_COEXIST,3.2,, +macro,METH_FASTCALL,3.7,, +macro,METH_METHOD,3.7,, +macro,METH_NOARGS,3.2,, +macro,METH_O,3.2,, +macro,METH_STATIC,3.2,, +macro,METH_VARARGS,3.2,, macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,, +type,PyABIInfo,3.15,,full-abi +func,PyABIInfo_Check,3.15,, +macro,PyABIInfo_DEFAULT_ABI_VERSION,3.15,, +macro,PyABIInfo_DEFAULT_FLAGS,3.15,, +macro,PyABIInfo_FREETHREADED,3.15,, +macro,PyABIInfo_FREETHREADING_AGNOSTIC,3.15,, +macro,PyABIInfo_GIL,3.15,, +macro,PyABIInfo_STABLE,3.15,, +macro,PyABIInfo_VAR,3.15,, func,PyAIter_Check,3.10,, func,PyArg_Parse,3.2,, func,PyArg_ParseTuple,3.2,, @@ -8,6 +25,26 @@ func,PyArg_UnpackTuple,3.2,, func,PyArg_VaParse,3.2,, func,PyArg_VaParseTupleAndKeywords,3.2,, func,PyArg_ValidateKeywordArguments,3.2,, +macro,PyBUF_ANY_CONTIGUOUS,3.11,, +macro,PyBUF_CONTIG,3.11,, +macro,PyBUF_CONTIG_RO,3.11,, +macro,PyBUF_C_CONTIGUOUS,3.11,, +macro,PyBUF_FORMAT,3.11,, +macro,PyBUF_FULL,3.11,, +macro,PyBUF_FULL_RO,3.11,, +macro,PyBUF_F_CONTIGUOUS,3.11,, +macro,PyBUF_INDIRECT,3.11,, +macro,PyBUF_MAX_NDIM,3.11,, +macro,PyBUF_ND,3.11,, +macro,PyBUF_READ,3.11,, +macro,PyBUF_RECORDS,3.11,, +macro,PyBUF_RECORDS_RO,3.11,, +macro,PyBUF_SIMPLE,3.11,, +macro,PyBUF_STRIDED,3.11,, +macro,PyBUF_STRIDED_RO,3.11,, +macro,PyBUF_STRIDES,3.11,, +macro,PyBUF_WRITABLE,3.11,, +macro,PyBUF_WRITE,3.11,, data,PyBaseObject_Type,3.2,, func,PyBool_FromLong,3.2,, data,PyBool_Type,3.2,, @@ -123,6 +160,7 @@ func,PyDict_Merge,3.2,, func,PyDict_MergeFromSeq2,3.2,, func,PyDict_New,3.2,, func,PyDict_Next,3.2,, +func,PyDict_SetDefaultRef,3.15,, func,PyDict_SetItem,3.2,, func,PyDict_SetItemString,3.2,, func,PyDict_Size,3.2,, @@ -388,6 +426,7 @@ func,PyLong_FromUnsignedNativeBytes,3.14,, func,PyLong_FromVoidPtr,3.2,, func,PyLong_GetInfo,3.2,, data,PyLong_Type,3.2,, +macro,PyMODEXPORT_FUNC,3.15,, data,PyMap_Type,3.2,, func,PyMapping_Check,3.2,, func,PyMapping_GetItemString,3.2,, @@ -425,6 +464,7 @@ data,PyMethodDescr_Type,3.2,, type,PyModuleDef,3.2,,full-abi type,PyModuleDef_Base,3.2,,full-abi func,PyModuleDef_Init,3.5,, +type,PyModuleDef_Slot,3.5,,full-abi data,PyModuleDef_Type,3.5,, func,PyModule_Add,3.13,, func,PyModule_AddFunctions,3.7,, @@ -434,8 +474,10 @@ func,PyModule_AddObjectRef,3.10,, func,PyModule_AddStringConstant,3.2,, func,PyModule_AddType,3.10,, func,PyModule_Create2,3.2,, +func,PyModule_Exec,3.15,, func,PyModule_ExecDef,3.7,, func,PyModule_FromDefAndSpec2,3.7,, +func,PyModule_FromSlotsAndSpec,3.15,, func,PyModule_GetDef,3.2,, func,PyModule_GetDict,3.2,, func,PyModule_GetFilename,3.2,, @@ -443,6 +485,8 @@ func,PyModule_GetFilenameObject,3.2,, func,PyModule_GetName,3.2,, func,PyModule_GetNameObject,3.7,, func,PyModule_GetState,3.2,, +func,PyModule_GetStateSize,3.15,, +func,PyModule_GetToken,3.15,, func,PyModule_New,3.2,, func,PyModule_NewObject,3.7,, func,PyModule_SetDocString,3.7,, @@ -634,7 +678,6 @@ func,PySys_GetObject,3.2,, func,PySys_GetOptionalAttr,3.15,, func,PySys_GetOptionalAttrString,3.15,, func,PySys_GetXOptions,3.7,, -func,PySys_ResetWarnOptions,3.2,, func,PySys_SetArgv,3.2,, func,PySys_SetArgvEx,3.2,, func,PySys_SetObject,3.2,, @@ -702,6 +745,7 @@ func,PyType_GetFlags,3.2,, func,PyType_GetFullyQualifiedName,3.13,, func,PyType_GetModule,3.10,, func,PyType_GetModuleByDef,3.13,, +func,PyType_GetModuleByToken,3.15,, func,PyType_GetModuleName,3.13,, func,PyType_GetModuleState,3.10,, func,PyType_GetName,3.11,, @@ -828,13 +872,20 @@ member,PyVarObject.ob_size,3.2,, func,PyVectorcall_Call,3.12,, func,PyVectorcall_NARGS,3.12,, type,PyWeakReference,3.2,,opaque -func,PyWeakref_GetObject,3.2,, func,PyWeakref_GetRef,3.13,, func,PyWeakref_NewProxy,3.2,, func,PyWeakref_NewRef,3.2,, data,PyWrapperDescr_Type,3.2,, func,PyWrapper_New,3.2,, data,PyZip_Type,3.2,, +macro,Py_ASNATIVEBYTES_ALLOW_INDEX,3.14,, +macro,Py_ASNATIVEBYTES_BIG_ENDIAN,3.14,, +macro,Py_ASNATIVEBYTES_DEFAULTS,3.14,, +macro,Py_ASNATIVEBYTES_LITTLE_ENDIAN,3.14,, +macro,Py_ASNATIVEBYTES_NATIVE_ENDIAN,3.14,, +macro,Py_ASNATIVEBYTES_REJECT_NEGATIVE,3.14,, +macro,Py_ASNATIVEBYTES_UNSIGNED_BUFFER,3.14,, +macro,Py_AUDIT_READ,3.12,, func,Py_AddPendingCall,3.2,, func,Py_AtExit,3.2,, macro,Py_BEGIN_ALLOW_THREADS,3.2,, @@ -865,6 +916,7 @@ func,Py_GetPlatform,3.2,, func,Py_GetRecursionLimit,3.2,, func,Py_GetVersion,3.2,, data,Py_HasFileSystemDefaultEncoding,3.2,, +func,Py_IS_TYPE,3.15,, func,Py_IncRef,3.2,, func,Py_Initialize,3.2,, func,Py_InitializeEx,3.2,, @@ -881,22 +933,147 @@ func,Py_NewInterpreter,3.2,, func,Py_NewRef,3.10,, func,Py_PACK_FULL_VERSION,3.14,, func,Py_PACK_VERSION,3.14,, +macro,Py_READONLY,3.12,, func,Py_REFCNT,3.14,, +macro,Py_RELATIVE_OFFSET,3.12,, func,Py_ReprEnter,3.2,, func,Py_ReprLeave,3.2,, +func,Py_SET_SIZE,3.15,, +func,Py_SIZE,3.15,, func,Py_SetProgramName,3.2,, func,Py_SetPythonHome,3.2,, func,Py_SetRecursionLimit,3.2,, +macro,Py_TPFLAGS_BASETYPE,3.2,, +macro,Py_TPFLAGS_DEFAULT,3.2,, +macro,Py_TPFLAGS_HAVE_GC,3.2,, +macro,Py_TPFLAGS_HAVE_VECTORCALL,3.12,, +macro,Py_TPFLAGS_ITEMS_AT_END,3.12,, +macro,Py_TPFLAGS_METHOD_DESCRIPTOR,3.8,, +macro,Py_TP_USE_SPEC,3.14,, func,Py_TYPE,3.14,, +macro,Py_T_BOOL,3.12,, +macro,Py_T_BYTE,3.12,, +macro,Py_T_CHAR,3.12,, +macro,Py_T_DOUBLE,3.12,, +macro,Py_T_FLOAT,3.12,, +macro,Py_T_INT,3.12,, +macro,Py_T_LONG,3.12,, +macro,Py_T_LONGLONG,3.12,, +macro,Py_T_OBJECT_EX,3.12,, +macro,Py_T_PYSSIZET,3.12,, +macro,Py_T_SHORT,3.12,, +macro,Py_T_STRING,3.12,, +macro,Py_T_STRING_INPLACE,3.12,, +macro,Py_T_UBYTE,3.12,, +macro,Py_T_UINT,3.12,, +macro,Py_T_ULONG,3.12,, +macro,Py_T_ULONGLONG,3.12,, +macro,Py_T_USHORT,3.12,, type,Py_UCS4,3.2,, macro,Py_UNBLOCK_THREADS,3.2,, data,Py_UTF8Mode,3.8,, func,Py_VaBuildValue,3.2,, data,Py_Version,3.11,, func,Py_XNewRef,3.10,, +macro,Py_am_aiter,3.5,, +macro,Py_am_anext,3.5,, +macro,Py_am_await,3.5,, +macro,Py_am_send,3.10,, +macro,Py_bf_getbuffer,3.11,, +macro,Py_bf_releasebuffer,3.11,, type,Py_buffer,3.11,,full-abi type,Py_intptr_t,3.2,, +macro,Py_mod_abi,3.15,, +macro,Py_mod_create,3.5,, +macro,Py_mod_doc,3.15,, +macro,Py_mod_exec,3.5,, +macro,Py_mod_gil,3.13,, +macro,Py_mod_methods,3.15,, +macro,Py_mod_multiple_interpreters,3.12,, +macro,Py_mod_name,3.15,, +macro,Py_mod_state_clear,3.15,, +macro,Py_mod_state_free,3.15,, +macro,Py_mod_state_size,3.15,, +macro,Py_mod_state_traverse,3.15,, +macro,Py_mod_token,3.15,, +macro,Py_mp_ass_subscript,3.2,, +macro,Py_mp_length,3.2,, +macro,Py_mp_subscript,3.2,, +macro,Py_nb_absolute,3.2,, +macro,Py_nb_add,3.2,, +macro,Py_nb_and,3.2,, +macro,Py_nb_bool,3.2,, +macro,Py_nb_divmod,3.2,, +macro,Py_nb_float,3.2,, +macro,Py_nb_floor_divide,3.2,, +macro,Py_nb_index,3.2,, +macro,Py_nb_inplace_add,3.2,, +macro,Py_nb_inplace_and,3.2,, +macro,Py_nb_inplace_floor_divide,3.2,, +macro,Py_nb_inplace_lshift,3.2,, +macro,Py_nb_inplace_matrix_multiply,3.5,, +macro,Py_nb_inplace_multiply,3.2,, +macro,Py_nb_inplace_or,3.2,, +macro,Py_nb_inplace_power,3.2,, +macro,Py_nb_inplace_remainder,3.2,, +macro,Py_nb_inplace_rshift,3.2,, +macro,Py_nb_inplace_subtract,3.2,, +macro,Py_nb_inplace_true_divide,3.2,, +macro,Py_nb_inplace_xor,3.2,, +macro,Py_nb_int,3.2,, +macro,Py_nb_invert,3.2,, +macro,Py_nb_lshift,3.2,, +macro,Py_nb_matrix_multiply,3.5,, +macro,Py_nb_multiply,3.2,, +macro,Py_nb_negative,3.2,, +macro,Py_nb_or,3.2,, +macro,Py_nb_positive,3.2,, +macro,Py_nb_power,3.2,, +macro,Py_nb_remainder,3.2,, +macro,Py_nb_rshift,3.2,, +macro,Py_nb_subtract,3.2,, +macro,Py_nb_true_divide,3.2,, +macro,Py_nb_xor,3.2,, +macro,Py_sq_ass_item,3.2,, +macro,Py_sq_concat,3.2,, +macro,Py_sq_contains,3.2,, +macro,Py_sq_inplace_concat,3.2,, +macro,Py_sq_inplace_repeat,3.2,, +macro,Py_sq_item,3.2,, +macro,Py_sq_length,3.2,, +macro,Py_sq_repeat,3.2,, type,Py_ssize_t,3.2,, +macro,Py_tp_alloc,3.2,, +macro,Py_tp_base,3.2,, +macro,Py_tp_bases,3.2,, +macro,Py_tp_call,3.2,, +macro,Py_tp_clear,3.2,, +macro,Py_tp_dealloc,3.2,, +macro,Py_tp_del,3.2,, +macro,Py_tp_descr_get,3.2,, +macro,Py_tp_descr_set,3.2,, +macro,Py_tp_doc,3.2,, +macro,Py_tp_finalize,3.5,, +macro,Py_tp_free,3.2,, +macro,Py_tp_getattr,3.2,, +macro,Py_tp_getattro,3.2,, +macro,Py_tp_getset,3.2,, +macro,Py_tp_hash,3.2,, +macro,Py_tp_init,3.2,, +macro,Py_tp_is_gc,3.2,, +macro,Py_tp_iter,3.2,, +macro,Py_tp_iternext,3.2,, +macro,Py_tp_members,3.2,, +macro,Py_tp_methods,3.2,, +macro,Py_tp_new,3.2,, +macro,Py_tp_repr,3.2,, +macro,Py_tp_richcompare,3.2,, +macro,Py_tp_setattr,3.2,, +macro,Py_tp_setattro,3.2,, +macro,Py_tp_str,3.2,, +macro,Py_tp_token,3.14,, +macro,Py_tp_traverse,3.2,, +macro,Py_tp_vectorcall,3.14,, type,Py_uintptr_t,3.2,, type,allocfunc,3.2,, type,binaryfunc,3.2,, diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst index a3e335ecaf4..9927b876760 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.15.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst @@ -3,7 +3,7 @@ Pending removal in Python 3.15 * The :c:func:`!PyImport_ImportModuleNoBlock`: Use :c:func:`PyImport_ImportModule` instead. -* :c:func:`PyWeakref_GetObject` and :c:func:`PyWeakref_GET_OBJECT`: +* :c:func:`!PyWeakref_GetObject` and :c:func:`!PyWeakref_GET_OBJECT`: Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project `__ can be used to get :c:func:`PyWeakref_GetRef` on Python 3.12 and older. @@ -59,7 +59,7 @@ Pending removal in Python 3.15 Set :c:member:`PyConfig.program_name` instead. * :c:func:`!Py_SetPythonHome()`: Set :c:member:`PyConfig.home` instead. - * :c:func:`PySys_ResetWarnOptions`: + * :c:func:`!PySys_ResetWarnOptions`: Clear :data:`sys.warnoptions` and :data:`!warnings.filters` instead. The :c:func:`Py_InitializeFromConfig` API should be used with diff --git a/Doc/deprecations/c-api-pending-removal-in-3.18.rst b/Doc/deprecations/c-api-pending-removal-in-3.18.rst index 564cfb79a0b..022aee93aa7 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.18.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.18.rst @@ -1,11 +1,12 @@ Pending removal in Python 3.18 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* Deprecated private functions (:gh:`128863`): +* The following private functions are deprecated + and planned for removal in Python 3.18: * :c:func:`!_PyBytes_Join`: use :c:func:`PyBytes_Join`. * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. - * :c:func:`!_PyDict_Pop()`: :c:func:`PyDict_Pop`. + * :c:func:`!_PyDict_Pop()`: use :c:func:`PyDict_Pop`. * :c:func:`!_PyLong_Sign()`: use :c:func:`PyLong_GetSign`. * :c:func:`!_PyLong_FromDigits` and :c:func:`!_PyLong_New`: use :c:func:`PyLongWriter_Create`. @@ -31,7 +32,7 @@ Pending removal in Python 3.18 :c:func:`PyUnicodeWriter_WriteSubstring(writer, str, start, end) `. * :c:func:`!_PyUnicodeWriter_WriteASCIIString`: replace ``_PyUnicodeWriter_WriteASCIIString(&writer, str)`` with - :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) `. + :c:func:`PyUnicodeWriter_WriteASCII(writer, str) `. * :c:func:`!_PyUnicodeWriter_WriteLatin1String`: replace ``_PyUnicodeWriter_WriteLatin1String(&writer, str)`` with :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) `. @@ -41,5 +42,6 @@ Pending removal in Python 3.18 * :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`. The `pythoncapi-compat project - `__ can be used to get these - new public functions on Python 3.13 and older. + `__ can be used to get + these new public functions on Python 3.13 and older. + (Contributed by Victor Stinner in :gh:`128863`.) diff --git a/Doc/deprecations/c-api-pending-removal-in-3.20.rst b/Doc/deprecations/c-api-pending-removal-in-3.20.rst index 82f975d6ed4..8de55bbe7e6 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.20.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.20.rst @@ -1,7 +1,16 @@ Pending removal in Python 3.20 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* :c:func:`!_PyObject_CallMethodId`, :c:func:`!_PyObject_GetAttrId` and + :c:func:`!_PyUnicode_FromId` are deprecated since 3.15 and will be removed in + 3.20. Instead, use :c:func:`PyUnicode_InternFromString()` and cache the result in + the module state, then call :c:func:`PyObject_CallMethod` or + :c:func:`PyObject_GetAttr`. + (Contributed by Victor Stinner in :gh:`141049`.) + * The ``cval`` field in :c:type:`PyComplexObject` (:gh:`128813`). Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex` to convert a Python complex number to/from the C :c:type:`Py_complex` representation. + +* Macros :c:macro:`!Py_MATH_PIl` and :c:macro:`!Py_MATH_El`. diff --git a/Doc/deprecations/index.rst b/Doc/deprecations/index.rst index c6e05c176b2..f3cecb321d6 100644 --- a/Doc/deprecations/index.rst +++ b/Doc/deprecations/index.rst @@ -9,6 +9,8 @@ Deprecations .. include:: pending-removal-in-3.19.rst +.. include:: pending-removal-in-3.20.rst + .. include:: pending-removal-in-future.rst C API deprecations diff --git a/Doc/deprecations/pending-removal-in-3.13.rst b/Doc/deprecations/pending-removal-in-3.13.rst index 2fd2f12cc6a..d5b8c80e8f9 100644 --- a/Doc/deprecations/pending-removal-in-3.13.rst +++ b/Doc/deprecations/pending-removal-in-3.13.rst @@ -38,15 +38,3 @@ APIs: * :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`) * :class:`!webbrowser.MacOSX` (:gh:`86421`) * :class:`classmethod` descriptor chaining (:gh:`89519`) -* :mod:`importlib.resources` deprecated methods: - - * ``contents()`` - * ``is_resource()`` - * ``open_binary()`` - * ``open_text()`` - * ``path()`` - * ``read_binary()`` - * ``read_text()`` - - Use :func:`importlib.resources.files` instead. Refer to `importlib-resources: Migrating from Legacy - `_ (:gh:`106531`) diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst index 9aac10840a6..171758156ab 100644 --- a/Doc/deprecations/pending-removal-in-3.14.rst +++ b/Doc/deprecations/pending-removal-in-3.14.rst @@ -38,12 +38,6 @@ Pending removal in Python 3.14 is no current event loop set and it decides to create one. (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) -* :mod:`collections.abc`: Deprecated :class:`!collections.abc.ByteString`. - Prefer :class:`!Sequence` or :class:`~collections.abc.Buffer`. - For use in typing, prefer a union, like ``bytes | bytearray``, - or :class:`collections.abc.Buffer`. - (Contributed by Shantanu Jain in :gh:`91896`.) - * :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`. (Contributed by Alan Williams in :gh:`72346`.) @@ -96,9 +90,6 @@ Pending removal in Python 3.14 if :ref:`named placeholders ` are used and *parameters* is a sequence instead of a :class:`dict`. -* :mod:`typing`: :class:`!typing.ByteString`, deprecated since Python 3.9, - now causes a :exc:`DeprecationWarning` to be emitted when it is used. - * :mod:`urllib`: :class:`!urllib.parse.Quoter` is deprecated: it was not intended to be a public API. diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst index 9505bcfa05a..3b9cf892fe9 100644 --- a/Doc/deprecations/pending-removal-in-3.15.rst +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -3,9 +3,9 @@ Pending removal in Python 3.15 * The import system: - * Setting :attr:`~module.__cached__` on a module while + * Setting ``__cached__`` on a module while failing to set :attr:`__spec__.cached ` - is deprecated. In Python 3.15, :attr:`!__cached__` will cease to be set or + is deprecated. In Python 3.15, ``__cached__`` will cease to be set or take into consideration by the import system or standard library. (:gh:`97879`) * Setting :attr:`~module.__package__` on a module while @@ -92,7 +92,7 @@ Pending removal in Python 3.15 Use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})`` to create a TypedDict with zero field. - * The :func:`typing.no_type_check_decorator` decorator function + * The :func:`!typing.no_type_check_decorator` decorator function has been deprecated since Python 3.13. After eight years in the :mod:`typing` module, it has yet to be supported by any major type checker. @@ -107,6 +107,6 @@ Pending removal in Python 3.15 * :mod:`zipimport`: - * :meth:`~zipimport.zipimporter.load_module` has been deprecated since + * :meth:`!zipimport.zipimporter.load_module` has been deprecated since Python 3.10. Use :meth:`~zipimport.zipimporter.exec_module` instead. - (Contributed by Jiahao Li in :gh:`125746`.) + (:gh:`125746`.) diff --git a/Doc/deprecations/pending-removal-in-3.16.rst b/Doc/deprecations/pending-removal-in-3.16.rst index cdd76ee693f..b00c7002b03 100644 --- a/Doc/deprecations/pending-removal-in-3.16.rst +++ b/Doc/deprecations/pending-removal-in-3.16.rst @@ -63,9 +63,9 @@ Pending removal in Python 3.16 * :mod:`logging`: - Support for custom logging handlers with the *strm* argument is deprecated - and scheduled for removal in Python 3.16. Define handlers with the *stream* - argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.) + * Support for custom logging handlers with the *strm* argument is deprecated + and scheduled for removal in Python 3.16. Define handlers with the *stream* + argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.) * :mod:`mimetypes`: diff --git a/Doc/deprecations/pending-removal-in-3.17.rst b/Doc/deprecations/pending-removal-in-3.17.rst index 370b98307e5..e769c9d371e 100644 --- a/Doc/deprecations/pending-removal-in-3.17.rst +++ b/Doc/deprecations/pending-removal-in-3.17.rst @@ -1,6 +1,34 @@ Pending removal in Python 3.17 ------------------------------ +* :mod:`collections.abc`: + + - :class:`collections.abc.ByteString` is scheduled for removal in Python 3.17. + + Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj`` + implements the :ref:`buffer protocol ` at runtime. For use + in type annotations, either use :class:`~collections.abc.Buffer` or a union + that explicitly specifies the types your code supports (e.g., + ``bytes | bytearray | memoryview``). + + :class:`!ByteString` was originally intended to be an abstract class that + would serve as a supertype of both :class:`bytes` and :class:`bytearray`. + However, since the ABC never had any methods, knowing that an object was an + instance of :class:`!ByteString` never actually told you anything useful + about the object. Other common buffer types such as :class:`memoryview` + were also never understood as subtypes of :class:`!ByteString` (either at + runtime or by static type checkers). + + See :pep:`PEP 688 <688#current-options>` for more details. + (Contributed by Shantanu Jain in :gh:`91896`.) + + +* :mod:`encodings`: + + - Passing non-ascii *encoding* names to :func:`encodings.normalize_encoding` + is deprecated and scheduled for removal in Python 3.17. + (Contributed by Stan Ulbrych in :gh:`136702`) + * :mod:`typing`: - Before Python 3.14, old-style unions were implemented using the private class @@ -8,3 +36,22 @@ Pending removal in Python 3.17 but it has been retained for backward compatibility, with removal scheduled for Python 3.17. Users should use documented introspection helpers like :func:`typing.get_origin` and :func:`typing.get_args` instead of relying on private implementation details. + - :class:`typing.ByteString`, deprecated since Python 3.9, is scheduled for removal in + Python 3.17. + + Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj`` + implements the :ref:`buffer protocol ` at runtime. For use + in type annotations, either use :class:`~collections.abc.Buffer` or a union + that explicitly specifies the types your code supports (e.g., + ``bytes | bytearray | memoryview``). + + :class:`!ByteString` was originally intended to be an abstract class that + would serve as a supertype of both :class:`bytes` and :class:`bytearray`. + However, since the ABC never had any methods, knowing that an object was an + instance of :class:`!ByteString` never actually told you anything useful + about the object. Other common buffer types such as :class:`memoryview` + were also never understood as subtypes of :class:`!ByteString` (either at + runtime or by static type checkers). + + See :pep:`PEP 688 <688#current-options>` for more details. + (Contributed by Shantanu Jain in :gh:`91896`.) diff --git a/Doc/deprecations/pending-removal-in-3.20.rst b/Doc/deprecations/pending-removal-in-3.20.rst new file mode 100644 index 00000000000..185f20fbc6d --- /dev/null +++ b/Doc/deprecations/pending-removal-in-3.20.rst @@ -0,0 +1,29 @@ +Pending removal in Python 3.20 +------------------------------ + +* The ``__version__`` attribute has been deprecated in these standard library + modules and will be removed in Python 3.20. + Use :py:data:`sys.version_info` instead. + + - :mod:`argparse` + - :mod:`csv` + - :mod:`ctypes` + - :mod:`!ctypes.macholib` + - :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead) + - :mod:`http.server` + - :mod:`imaplib` + - :mod:`ipaddress` + - :mod:`json` + - :mod:`logging` (``__date__`` also deprecated) + - :mod:`optparse` + - :mod:`pickle` + - :mod:`platform` + - :mod:`re` + - :mod:`socketserver` + - :mod:`tabnanny` + - :mod:`tkinter.font` + - :mod:`tkinter.ttk` + - :mod:`wsgiref.simple_server` + - :mod:`zlib` + + (Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.) diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst index edb672ed8ad..30186741670 100644 --- a/Doc/deprecations/pending-removal-in-future.rst +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -15,7 +15,6 @@ although there is currently no date scheduled for their removal. * :mod:`builtins`: - * ``bool(NotImplemented)``. * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)`` signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead, the single argument signature. @@ -77,7 +76,7 @@ although there is currently no date scheduled for their removal. * :mod:`mailbox`: Use of StringIO input and text mode is deprecated, use BytesIO and binary mode instead. -* :mod:`os`: Calling :func:`os.register_at_fork` in multi-threaded process. +* :mod:`os`: Calling :func:`os.register_at_fork` in a multi-threaded process. * :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is deprecated, use an exception instance. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index e3612f3a187..26085b5cebd 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -560,6 +560,8 @@ For an object to be weakly referenceable, the extension type must set the field. The legacy :c:member:`~PyTypeObject.tp_weaklistoffset` field should be left as zero. +If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set. + Concretely, here is how the statically declared type object would look:: static PyTypeObject TrivialType = { diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index c758c019ca4..ac0aa81e56b 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -591,9 +591,9 @@ exhaustive test suites that exercise every line of code in a module. An appropriate testing discipline can help build large complex applications in Python as well as having interface specifications would. In fact, it can be better because an interface specification cannot test certain properties of a -program. For example, the :meth:`!list.append` method is expected to add new elements +program. For example, the :meth:`list.append` method is expected to add new elements to the end of some internal list; an interface specification cannot test that -your :meth:`!list.append` implementation will actually do this correctly, but it's +your :meth:`list.append` implementation will actually do this correctly, but it's trivial to check this property in a test suite. Writing test suites is very helpful, and you might want to design your code to diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 578777d7f23..698f2117ff5 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -186,7 +186,7 @@ How do I get documentation on Python? ------------------------------------- The standard documentation for the current stable version of Python is available -at https://docs.python.org/3/. PDF, plain text, and downloadable HTML versions are +at https://docs.python.org/3/. EPUB, plain text, and downloadable HTML versions are also available at https://docs.python.org/3/download.html. The documentation is written in reStructuredText and processed by `the Sphinx diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index 9f9e4fab685..6f9dfa8616e 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -454,7 +454,7 @@ There are two factors that produce this result: (the list), and both ``x`` and ``y`` refer to it. 2) Lists are :term:`mutable`, which means that you can change their content. -After the call to :meth:`!append`, the content of the mutable object has +After the call to :meth:`~sequence.append`, the content of the mutable object has changed from ``[]`` to ``[10]``. Since both the variables refer to the same object, using either name accesses the modified value ``[10]``. @@ -1397,9 +1397,9 @@ To see why this happens, you need to know that (a) if an object implements an :meth:`~object.__iadd__` magic method, it gets called when the ``+=`` augmented assignment is executed, and its return value is what gets used in the assignment statement; -and (b) for lists, :meth:`!__iadd__` is equivalent to calling :meth:`!extend` on the list -and returning the list. That's why we say that for lists, ``+=`` is a -"shorthand" for :meth:`!list.extend`:: +and (b) for lists, :meth:`!__iadd__` is equivalent to calling +:meth:`~sequence.extend` on the list and returning the list. +That's why we say that for lists, ``+=`` is a "shorthand" for :meth:`list.extend`:: >>> a_list = [] >>> a_list += [1] diff --git a/Doc/faq/python-video-icon.png b/Doc/faq/python-video-icon.png deleted file mode 100644 index 265da50c7b3..00000000000 Binary files a/Doc/faq/python-video-icon.png and /dev/null differ diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 45344521167..68035c2dfb5 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -21,7 +21,9 @@ Glossary right delimiters (parentheses, square brackets, curly braces or triple quotes), or after specifying a decorator. - * The :const:`Ellipsis` built-in constant. + .. index:: single: ...; ellipsis literal + + * The three dots form of the :ref:`Ellipsis ` object. abstract base class Abstract base classes complement :term:`duck-typing` by @@ -132,6 +134,14 @@ Glossary iterator's :meth:`~object.__anext__` method until it raises a :exc:`StopAsyncIteration` exception. Introduced by :pep:`492`. + atomic operation + An operation that appears to execute as a single, indivisible step: no + other thread can observe it half-done, and its effects become visible all + at once. Python does not guarantee that high-level statements are atomic + (for example, ``x += 1`` performs multiple bytecode operations and is not + atomic). Atomicity is only guaranteed where explicitly documented. See + also :term:`race condition` and :term:`data race`. + attached thread state A :term:`thread state` that is active for the current OS thread. @@ -287,6 +297,22 @@ Glossary advanced mathematical feature. If you're not aware of a need for them, it's almost certain you can safely ignore them. + concurrency + The ability of a computer program to perform multiple tasks at the same + time. Python provides libraries for writing programs that make use of + different forms of concurrency. :mod:`asyncio` is a library for dealing + with asynchronous tasks and coroutines. :mod:`threading` provides + access to operating system threads and :mod:`multiprocessing` to + operating system processes. Multi-core processors can execute threads and + processes on different CPU cores at the same time (see + :term:`parallelism`). + + concurrent modification + When multiple threads modify shared data at the same time. Concurrent + modification without proper synchronization can cause + :term:`race conditions `, and might also trigger a + :term:`data race `, data corruption, or both. + context This term has different meanings depending on where and how it is used. Some common meanings: @@ -361,6 +387,28 @@ Glossary the :term:`cyclic garbage collector ` is to identify these groups and break the reference cycles so that the memory can be reclaimed. + data race + A situation where multiple threads access the same memory location + concurrently, at least one of the accesses is a write, and the threads + do not use any synchronization to control their access. Data races + lead to :term:`non-deterministic` behavior and can cause data corruption. + Proper use of :term:`locks ` and other :term:`synchronization primitives + ` prevents data races. Note that data races + can only happen in native code, but that :term:`native code` might be + exposed in a Python API. See also :term:`race condition` and + :term:`thread-safe`. + + deadlock + A situation in which two or more tasks (threads, processes, or coroutines) + wait indefinitely for each other to release resources or complete actions, + preventing any from making progress. For example, if thread A holds lock + 1 and waits for lock 2, while thread B holds lock 2 and waits for lock 1, + both threads will wait indefinitely. In Python this often arises from + acquiring multiple locks in conflicting orders or from circular + join/await dependencies. Deadlocks can be avoided by always acquiring + multiple :term:`locks ` in a consistent order. See also + :term:`lock` and :term:`reentrant`. + decorator A function returning another function, usually applied as a function transformation using the ``@wrapper`` syntax. Common examples for @@ -660,6 +708,14 @@ Glossary requires the GIL to be held in order to use it. This refers to having an :term:`attached thread state`. + global state + Data that is accessible throughout a program, such as module-level + variables, class variables, or C static variables in :term:`extension modules + `. In multi-threaded programs, global state shared + between threads typically requires synchronization to avoid + :term:`race conditions ` and + :term:`data races `. + hash-based pyc A bytecode cache file that uses the hash rather than the last-modified time of the corresponding source file to determine its validity. See @@ -704,7 +760,9 @@ Glossary tuples. Such an object cannot be altered. A new object has to be created if a different value has to be stored. They play an important role in places where a constant hash value is needed, for example as a key - in a dictionary. + in a dictionary. Immutable objects are inherently :term:`thread-safe` + because their state cannot be modified after creation, eliminating concerns + about improperly synchronized :term:`concurrent modification`. import path A list of locations (or :term:`path entries `) that are @@ -794,8 +852,9 @@ Glossary CPython does not consistently apply the requirement that an iterator define :meth:`~iterator.__iter__`. - And also please note that the free-threading CPython does not guarantee - the thread-safety of iterator operations. + And also please note that :term:`free-threaded ` + CPython does not guarantee :term:`thread-safe` behavior of iterator + operations. key function @@ -811,7 +870,7 @@ Glossary :func:`itertools.groupby`. There are several ways to create a key function. For example. the - :meth:`str.lower` method can serve as a key function for case insensitive + :meth:`str.casefold` method can serve as a key function for case insensitive sorts. Alternatively, a key function can be built from a :keyword:`lambda` expression such as ``lambda r: (r[0], r[2])``. Also, :func:`operator.attrgetter`, :func:`operator.itemgetter`, and @@ -833,10 +892,11 @@ Glossary :keyword:`if` statements. In a multi-threaded environment, the LBYL approach can risk introducing a - race condition between "the looking" and "the leaping". For example, the - code, ``if key in mapping: return mapping[key]`` can fail if another + :term:`race condition` between "the looking" and "the leaping". For example, + the code, ``if key in mapping: return mapping[key]`` can fail if another thread removes *key* from *mapping* after the test, but before the lookup. - This issue can be solved with locks or by using the EAFP approach. + This issue can be solved with :term:`locks ` or by using the + :term:`EAFP` approach. See also :term:`thread-safe`. lexical analyzer @@ -855,6 +915,19 @@ Glossary clause is optional. If omitted, all elements in ``range(256)`` are processed. + lock + A :term:`synchronization primitive` that allows only one thread at a + time to access a shared resource. A thread must acquire a lock before + accessing the protected resource and release it afterward. If a thread + attempts to acquire a lock that is already held by another thread, it + will block until the lock becomes available. Python's :mod:`threading` + module provides :class:`~threading.Lock` (a basic lock) and + :class:`~threading.RLock` (a :term:`reentrant` lock). Locks are used + to prevent :term:`race conditions ` and ensure + :term:`thread-safe` access to shared data. Alternative design patterns + to locks exist such as queues, producer/consumer patterns, and + thread-local state. See also :term:`deadlock`, and :term:`reentrant`. + loader An object that loads a module. It must define the :meth:`!exec_module` and :meth:`!create_module` methods @@ -940,8 +1013,11 @@ Glossary See :term:`method resolution order`. mutable - Mutable objects can change their value but keep their :func:`id`. See - also :term:`immutable`. + An :term:`object` with state that is allowed to change during the course + of the program. In multi-threaded programs, mutable objects that are + shared between threads require careful synchronization to avoid + :term:`race conditions `. See also :term:`immutable`, + :term:`thread-safe`, and :term:`concurrent modification`. named tuple The term "named tuple" applies to any type or class that inherits from @@ -993,6 +1069,13 @@ Glossary See also :term:`module`. + native code + Code that is compiled to machine instructions and runs directly on the + processor, as opposed to code that is interpreted or runs in a virtual + machine. In the context of Python, native code typically refers to + C, C++, Rust or Fortran code in :term:`extension modules ` + that can be called from Python. See also :term:`extension module`. + nested scope The ability to refer to a variable in an enclosing definition. For instance, a function defined inside another function can refer to @@ -1009,6 +1092,15 @@ Glossary properties, :meth:`~object.__getattribute__`, class methods, and static methods. + non-deterministic + Behavior where the outcome of a program can vary between executions with + the same inputs. In multi-threaded programs, non-deterministic behavior + often results from :term:`race conditions ` where the + relative timing or interleaving of threads affects the result. + Proper synchronization using :term:`locks ` and other + :term:`synchronization primitives ` helps + ensure deterministic behavior. + object Any data with state (attributes or value) and defined behavior (methods). Also the ultimate base class of any :term:`new-style @@ -1023,6 +1115,15 @@ Glossary applied to all scopes, only those relying on a known set of local and nonlocal variable names are restricted to optimized scopes. + optional module + An :term:`extension module` that is part of the :term:`standard library`, + but may be absent in some builds of :term:`CPython`, + usually due to missing third-party libraries or because the module + is not available for a given platform. + + See :ref:`optional-module-requirements` for a list of optional modules + that require third-party libraries. + package A Python :term:`module` which can contain submodules or recursively, subpackages. Technically, a package is a Python module with a @@ -1030,6 +1131,16 @@ Glossary See also :term:`regular package` and :term:`namespace package`. + parallelism + Executing multiple operations at the same time (e.g. on multiple CPU + cores). In Python builds with the + :term:`global interpreter lock (GIL) `, only one + thread runs Python bytecode at a time, so taking advantage of multiple + CPU cores typically involves multiple processes + (e.g. :mod:`multiprocessing`) or native extensions that release the GIL. + In :term:`free-threaded ` Python, multiple Python threads + can run Python code simultaneously on different cores. + parameter A named entity in a :term:`function` (or method) definition that specifies an :term:`argument` (or in some cases, arguments) that the @@ -1204,6 +1315,18 @@ Glossary >>> email.mime.text.__name__ 'email.mime.text' + race condition + A condition of a program where the its behavior + depends on the relative timing or ordering of events, particularly in + multi-threaded programs. Race conditions can lead to + :term:`non-deterministic` behavior and bugs that are difficult to + reproduce. A :term:`data race` is a specific type of race condition + involving unsynchronized access to shared memory. The :term:`LBYL` + coding style is particularly susceptible to race conditions in + multi-threaded code. Using :term:`locks ` and other + :term:`synchronization primitives ` + helps prevent race conditions. + reference count The number of references to an object. When the reference count of an object drops to zero, it is deallocated. Some objects are @@ -1225,6 +1348,25 @@ Glossary See also :term:`namespace package`. + reentrant + A property of a function or :term:`lock` that allows it to be called or + acquired multiple times by the same thread without causing errors or a + :term:`deadlock`. + + For functions, reentrancy means the function can be safely called again + before a previous invocation has completed, which is important when + functions may be called recursively or from signal handlers. Thread-unsafe + functions may be :term:`non-deterministic` if they're called reentrantly in a + multithreaded program. + + For locks, Python's :class:`threading.RLock` (reentrant lock) is + reentrant, meaning a thread that already holds the lock can acquire it + again without blocking. In contrast, :class:`threading.Lock` is not + reentrant - attempting to acquire it twice from the same thread will cause + a deadlock. + + See also :term:`lock` and :term:`deadlock`. + REPL An acronym for the "read–eval–print loop", another name for the :term:`interactive` interpreter shell. @@ -1249,8 +1391,9 @@ Glossary The :class:`collections.abc.Sequence` abstract base class defines a much richer interface that goes beyond just :meth:`~object.__getitem__` and :meth:`~object.__len__`, adding - :meth:`!count`, :meth:`!index`, :meth:`~object.__contains__`, and - :meth:`~object.__reversed__`. Types that implement this expanded + :meth:`~sequence.count`, :meth:`~sequence.index`, + :meth:`~object.__contains__`, and :meth:`~object.__reversed__`. + Types that implement this expanded interface can be registered explicitly using :func:`~abc.ABCMeta.register`. For more documentation on sequence methods generally, see @@ -1328,6 +1471,18 @@ Glossary See also :term:`borrowed reference`. + synchronization primitive + A basic building block for coordinating (synchronizing) the execution of + multiple threads to ensure :term:`thread-safe` access to shared resources. + Python's :mod:`threading` module provides several synchronization primitives + including :class:`~threading.Lock`, :class:`~threading.RLock`, + :class:`~threading.Semaphore`, :class:`~threading.Condition`, + :class:`~threading.Event`, and :class:`~threading.Barrier`. Additionally, + the :mod:`queue` module provides multi-producer, multi-consumer queues + that are especially useful in multithreaded programs. These + primitives help prevent :term:`race conditions ` and + coordinate thread execution. See also :term:`lock`. + t-string t-strings String literals prefixed with ``t`` or ``T`` are commonly called @@ -1380,6 +1535,19 @@ Glossary See :ref:`Thread State and the Global Interpreter Lock ` for more information. + thread-safe + A module, function, or class that behaves correctly when used by multiple + threads concurrently. Thread-safe code uses appropriate + :term:`synchronization primitives ` like + :term:`locks ` to protect shared mutable state, or is designed + to avoid shared mutable state entirely. In the + :term:`free-threaded ` build, built-in types like + :class:`dict`, :class:`list`, and :class:`set` use internal locking + to make many operations thread-safe, although thread safety is not + necessarily guaranteed. Code that is not thread-safe may experience + :term:`race conditions ` and :term:`data races ` + when used in multi-threaded programs. + token A small unit of source code, generated by the diff --git a/Doc/howto/a-conceptual-overview-of-asyncio.rst b/Doc/howto/a-conceptual-overview-of-asyncio.rst index d68f7cc6921..3adfedbf410 100644 --- a/Doc/howto/a-conceptual-overview-of-asyncio.rst +++ b/Doc/howto/a-conceptual-overview-of-asyncio.rst @@ -1,7 +1,7 @@ .. _a-conceptual-overview-of-asyncio: **************************************** -A Conceptual Overview of :mod:`!asyncio` +A conceptual overview of :mod:`!asyncio` **************************************** This :ref:`HOWTO ` article seeks to help you build a sturdy mental @@ -9,12 +9,11 @@ model of how :mod:`asyncio` fundamentally works, helping you understand the how and why behind the recommended patterns. You might be curious about some key :mod:`!asyncio` concepts. -You'll be comfortably able to answer these questions by the end of this -article: +By the end of this article, you'll be able to comfortably answer these questions: - What's happening behind the scenes when an object is awaited? - How does :mod:`!asyncio` differentiate between a task which doesn't need - CPU-time (such as a network request or file read) as opposed to a task that + CPU time (such as a network request or file read) as opposed to a task that does (such as computing n-factorial)? - How to write an asynchronous variant of an operation, such as an async sleep or database request. @@ -35,18 +34,18 @@ A conceptual overview part 1: the high-level -------------------------------------------- In part 1, we'll cover the main, high-level building blocks of :mod:`!asyncio`: -the event loop, coroutine functions, coroutine objects, tasks and ``await``. +the event loop, coroutine functions, coroutine objects, tasks, and ``await``. ========== -Event Loop +Event loop ========== Everything in :mod:`!asyncio` happens relative to the event loop. -It's the star of the show. +It's the star of the show, but prefers to work behind the scenes, managing +and coordinating resources. It's like an orchestra conductor. -It's behind the scenes managing resources. Some power is explicitly granted to it, but a lot of its ability to get things -done comes from the respect and cooperation of its worker bees. +done comes from the respect and cooperation of its band members. In more technical terms, the event loop contains a collection of jobs to be run. Some jobs are added directly by you, and some indirectly by :mod:`!asyncio`. @@ -56,11 +55,11 @@ Once it pauses or completes, it returns control to the event loop. The event loop will then select another job from its pool and invoke it. You can *roughly* think of the collection of jobs as a queue: jobs are added and then processed one at a time, generally (but not always) in order. -This process repeats indefinitely with the event loop cycling endlessly +This process repeats indefinitely, with the event loop cycling endlessly onwards. If there are no more jobs pending execution, the event loop is smart enough to rest and avoid needlessly wasting CPU cycles, and will come back when there's -more work to be done. +more work to be done, such as when I/O operations complete or timers expire. Effective execution relies on jobs sharing well and cooperating; a greedy job could hog control and leave the other jobs to starve, rendering the overall @@ -171,14 +170,17 @@ Roughly speaking, :ref:`tasks ` are coroutines (not coroutine functions) tied to an event loop. A task also maintains a list of callback functions whose importance will become clear in a moment when we discuss :keyword:`await`. -The recommended way to create tasks is via :func:`asyncio.create_task`. Creating a task automatically schedules it for execution (by adding a callback to run it in the event loop's to-do list, that is, collection of jobs). +The recommended way to create tasks is via :func:`asyncio.create_task`. -Since there's only one event loop (in each thread), :mod:`!asyncio` takes care of -associating the task with the event loop for you. As such, there's no need -to specify the event loop. +:mod:`!asyncio` automatically associates tasks with the event loop for you. +This automatic association was purposely designed into :mod:`!asyncio` for +the sake of simplicity. +Without it, you'd have to keep track of the event loop object and pass it to +any coroutine function that wants to create tasks, adding redundant clutter +to your code. :: @@ -251,6 +253,10 @@ different ways:: In a crucial way, the behavior of ``await`` depends on the type of object being awaited. +^^^^^^^^^^^^^^ +Awaiting tasks +^^^^^^^^^^^^^^ + Awaiting a task will cede control from the current task or coroutine to the event loop. In the process of relinquishing control, a few important things happen. @@ -276,12 +282,16 @@ in this case, a call to resume ``plant_a_tree()``. Generally speaking, when the awaited task finishes (``dig_the_hole_task``), the original task or coroutine (``plant_a_tree()``) is added back to the event -loops to-do list to be resumed. +loop's to-do list to be resumed. This is a basic, yet reliable mental model. In practice, the control handoffs are slightly more complex, but not by much. In part 2, we'll walk through the details that make this possible. +^^^^^^^^^^^^^^^^^^^ +Awaiting coroutines +^^^^^^^^^^^^^^^^^^^ + **Unlike tasks, awaiting a coroutine does not hand control back to the event loop!** Wrapping a coroutine in a task first, then awaiting that would cede @@ -310,7 +320,7 @@ Consider this program:: The first statement in the coroutine ``main()`` creates ``task_b`` and schedules it for execution via the event loop. Then, ``coro_a()`` is repeatedly awaited. Control never cedes to the -event loop which is why we see the output of all three ``coro_a()`` +event loop, which is why we see the output of all three ``coro_a()`` invocations before ``coro_b()``'s output: .. code-block:: none @@ -338,8 +348,8 @@ This behavior of ``await coroutine`` can trip a lot of people up! That example highlights how using only ``await coroutine`` could unintentionally hog control from other tasks and effectively stall the event loop. -:func:`asyncio.run` can help you detect such occurences via the -``debug=True`` flag which accordingly enables +:func:`asyncio.run` can help you detect such occurrences via the +``debug=True`` flag, which enables :ref:`debug mode `. Among other things, it will log any coroutines that monopolize execution for 100ms or longer. @@ -348,8 +358,10 @@ The design intentionally trades off some conceptual clarity around usage of ``await`` for improved performance. Each time a task is awaited, control needs to be passed all the way up the call stack to the event loop. -That might sound minor, but in a large program with many ``await``'s and a deep -callstack that overhead can add up to a meaningful performance drag. +Then, the event loop needs to manage its internal state and work through +its processing logic to resume the next job. +That might sound minor, but in a large program with many ``await``\ s, that +overhead can add up to a non-negligible performance drag. ------------------------------------------------ A conceptual overview part 2: the nuts and bolts @@ -365,14 +377,15 @@ and how to make your own asynchronous operators. The inner workings of coroutines ================================ -:mod:`!asyncio` leverages four components to pass around control. +:mod:`!asyncio` leverages four components of Python to pass +around control. :meth:`coroutine.send(arg) ` is the method used to start or resume a coroutine. If the coroutine was paused and is now being resumed, the argument ``arg`` will be sent in as the return value of the ``yield`` statement which originally paused it. -If the coroutine is being used for the first time (as opposed to being resumed) +If the coroutine is being used for the first time (as opposed to being resumed), ``arg`` must be ``None``. .. code-block:: @@ -403,14 +416,14 @@ If the coroutine is being used for the first time (as opposed to being resumed) returned_value = e.value print(f"Coroutine main() finished and provided value: {returned_value}.") -:ref:`yield `, like usual, pauses execution and returns control +:ref:`yield `, as usual, pauses execution and returns control to the caller. In the example above, the ``yield``, on line 3, is called by ``... = await rock`` on line 11. More broadly speaking, ``await`` calls the :meth:`~object.__await__` method of the given object. ``await`` also does one more very special thing: it propagates (or "passes -along") any ``yield``\ s it receives up the call-chain. +along") any ``yield``\ s it receives up the call chain. In this case, that's back to ``... = coroutine.send(None)`` on line 16. The coroutine is resumed via the ``coroutine.send(42)`` call on line 21. @@ -449,9 +462,9 @@ That might sound odd to you. You might be thinking: That causes the error: ``SyntaxError: yield from not allowed in a coroutine.`` This was intentionally designed for the sake of simplicity -- mandating only one way of using coroutines. + Despite that, ``yield from`` and ``await`` effectively do the same thing. Initially ``yield`` was barred as well, but was re-accepted to allow for async generators. - Despite that, ``yield from`` and ``await`` effectively do the same thing. ======= Futures @@ -462,12 +475,12 @@ computation's status and result. The term is a nod to the idea of something still to come or not yet happened, and the object is a way to keep an eye on that something. -A future has a few important attributes. One is its state which can be either -"pending", "cancelled" or "done". +A future has a few important attributes. One is its state, which can be either +"pending", "cancelled", or "done". Another is its result, which is set when the state transitions to done. Unlike a coroutine, a future does not represent the actual computation to be done; instead, it represents the status and result of that computation, kind of -like a status light (red, yellow or green) or indicator. +like a status light (red, yellow, or green) or indicator. :class:`asyncio.Task` subclasses :class:`asyncio.Future` in order to gain these various capabilities. @@ -490,8 +503,8 @@ We'll go through an example of how you could leverage a future to create your own variant of asynchronous sleep (``async_sleep``) which mimics :func:`asyncio.sleep`. -This snippet registers a few tasks with the event loop and then awaits a -coroutine wrapped in a task: ``async_sleep(3)``. +This snippet registers a few tasks with the event loop and then awaits the task +created by ``asyncio.create_task``, which wraps the ``async_sleep(3)`` coroutine. We want that task to finish only after three seconds have elapsed, but without preventing other tasks from running. @@ -540,8 +553,8 @@ will monitor how much time has elapsed and, accordingly, call # Block until the future is marked as done. await future -Below, we'll use a rather bare object, ``YieldToEventLoop()``, to ``yield`` -from ``__await__`` in order to cede control to the event loop. +Below, we use a rather bare ``YieldToEventLoop()`` object to ``yield`` +from its ``__await__`` method, ceding control to the event loop. This is effectively the same as calling ``asyncio.sleep(0)``, but this approach offers more clarity, not to mention it's somewhat cheating to use ``asyncio.sleep`` when showcasing how to implement it! @@ -552,13 +565,13 @@ The ``watcher_task``, which runs the coroutine ``_sleep_watcher(...)``, will be invoked once per full cycle of the event loop. On each resumption, it'll check the time and if not enough has elapsed, then it'll pause once again and hand control back to the event loop. -Eventually, enough time will have elapsed, and ``_sleep_watcher(...)`` will -mark the future as done, and then itself finish too by breaking out of the +Once enough time has elapsed, ``_sleep_watcher(...)`` +marks the future as done and completes by exiting its infinite ``while`` loop. Given this helper task is only invoked once per cycle of the event loop, you'd be correct to note that this asynchronous sleep will sleep *at least* three seconds, rather than exactly three seconds. -Note this is also of true of ``asyncio.sleep``. +Note this is also true of ``asyncio.sleep``. :: @@ -601,6 +614,6 @@ For reference, you could implement it without futures, like so:: else: await YieldToEventLoop() -But, that's all for now. Hopefully you're ready to more confidently dive into +But that's all for now. Hopefully you're ready to more confidently dive into some async programming or check out advanced topics in the :mod:`rest of the documentation `. diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index f6c3e473f1c..9d5a9ac8b71 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -420,7 +420,7 @@ Here are three practical data validation utilities: def validate(self, value): if not isinstance(value, str): - raise TypeError(f'Expected {value!r} to be an str') + raise TypeError(f'Expected {value!r} to be a str') if self.minsize is not None and len(value) < self.minsize: raise ValueError( f'Expected {value!r} to be no smaller than {self.minsize!r}' diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst index 577e283bb9c..83eba8cfea3 100644 --- a/Doc/howto/free-threading-extensions.rst +++ b/Doc/howto/free-threading-extensions.rst @@ -45,9 +45,12 @@ single-phase initialization. Multi-Phase Initialization .......................... -Extensions that use multi-phase initialization (i.e., -:c:func:`PyModuleDef_Init`) should add a :c:data:`Py_mod_gil` slot in the -module definition. If your extension supports older versions of CPython, +Extensions that use :ref:`multi-phase initialization ` +(functions like :c:func:`PyModuleDef_Init`, +:c:func:`PyModExport_* ` export hook, +:c:func:`PyModule_FromSlotsAndSpec`) should add a +:c:data:`Py_mod_gil` slot in the module definition. +If your extension supports older versions of CPython, you should guard the slot with a :c:data:`PY_VERSION_HEX` check. :: @@ -60,18 +63,12 @@ you should guard the slot with a :c:data:`PY_VERSION_HEX` check. {0, NULL} }; - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - .m_slots = module_slots, - ... - }; - Single-Phase Initialization ........................... -Extensions that use single-phase initialization (i.e., -:c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to +Extensions that use legacy :ref:`single-phase initialization ` +(that is, :c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to indicate that they support running with the GIL disabled. The function is only defined in the free-threaded build, so you should guard the call with ``#ifdef Py_GIL_DISABLED`` to avoid compilation errors in the regular build. @@ -173,9 +170,9 @@ that return :term:`strong references `. +-----------------------------------+-----------------------------------+ | :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) | +-----------------------------------+-----------------------------------+ -| :c:func:`PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` | +| :c:func:`!PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` | +-----------------------------------+-----------------------------------+ -| :c:func:`PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` | +| :c:func:`!PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` | +-----------------------------------+-----------------------------------+ | :c:func:`PyImport_AddModule` | :c:func:`PyImport_AddModuleRef` | +-----------------------------------+-----------------------------------+ @@ -203,7 +200,7 @@ Memory Allocation APIs Python's memory management C API provides functions in three different :ref:`allocation domains `: "raw", "mem", and "object". For thread-safety, the free-threaded build requires that only Python objects -are allocated using the object domain, and that all Python object are +are allocated using the object domain, and that all Python objects are allocated using that domain. This differs from the prior Python versions, where this was only a best practice and not a hard requirement. @@ -344,12 +341,12 @@ This means you cannot rely on nested critical sections to lock multiple objects at once, as the inner critical section may suspend the outer ones. Instead, use :c:macro:`Py_BEGIN_CRITICAL_SECTION2` to lock two objects simultaneously. -Note that the locks described above are only :c:type:`!PyMutex` based locks. +Note that the locks described above are only :c:type:`PyMutex` based locks. The critical section implementation does not know about or affect other locking mechanisms that might be in use, like POSIX mutexes. Also note that while -blocking on any :c:type:`!PyMutex` causes the critical sections to be +blocking on any :c:type:`PyMutex` causes the critical sections to be suspended, only the mutexes that are part of the critical sections are -released. If :c:type:`!PyMutex` is used without a critical section, it will +released. If :c:type:`PyMutex` is used without a critical section, it will not be released and therefore does not get the same deadlock avoidance. Important Considerations @@ -397,7 +394,8 @@ The wheels, shared libraries, and binaries are indicated by a ``t`` suffix. * `pypa/manylinux `_ supports the free-threaded build, with the ``t`` suffix, such as ``python3.13t``. * `pypa/cibuildwheel `_ supports the - free-threaded build if you set + free-threaded build on Python 3.13 and 3.14. On Python 3.14, free-threaded + wheels will be built by default. On Python 3.13, you will need to set `CIBW_ENABLE to cpython-freethreading `_. Limited C API and Stable ABI diff --git a/Doc/howto/free-threading-python.rst b/Doc/howto/free-threading-python.rst index 24069617c47..380c2be0495 100644 --- a/Doc/howto/free-threading-python.rst +++ b/Doc/howto/free-threading-python.rst @@ -11,9 +11,7 @@ available processing power by running threads in parallel on available CPU cores While not all software will benefit from this automatically, programs designed with threading in mind will run faster on multi-core hardware. -The free-threaded mode is working and continues to be improved, but -there is some additional overhead in single-threaded workloads compared -to the regular build. Additionally, third-party packages, in particular ones +Some third-party packages, in particular ones with an :term:`extension module`, may not be ready for use in a free-threaded build, and will re-enable the :term:`GIL`. @@ -101,60 +99,42 @@ This section describes known limitations of the free-threaded CPython build. Immortalization --------------- -The free-threaded build of the 3.13 release makes some objects :term:`immortal`. +In the free-threaded build, some objects are :term:`immortal`. Immortal objects are not deallocated and have reference counts that are never modified. This is done to avoid reference count contention that would prevent efficient multi-threaded scaling. -An object will be made immortal when a new thread is started for the first time -after the main thread is running. The following objects are immortalized: +As of the 3.14 release, immortalization is limited to: -* :ref:`function ` objects declared at the module level -* :ref:`method ` descriptors -* :ref:`code ` objects -* :term:`module` objects and their dictionaries -* :ref:`classes ` (type objects) - -Because immortal objects are never deallocated, applications that create many -objects of these types may see increased memory usage. This is expected to be -addressed in the 3.14 release. - -Additionally, numeric and string literals in the code as well as strings -returned by :func:`sys.intern` are also immortalized. This behavior is -expected to remain in the 3.14 free-threaded build. +* Code constants: numeric literals, string literals, and tuple literals + composed of other constants. +* Strings interned by :func:`sys.intern`. Frame objects ------------- -It is not safe to access :ref:`frame ` objects from other -threads and doing so may cause your program to crash . This means that -:func:`sys._current_frames` is generally not safe to use in a free-threaded -build. Functions like :func:`inspect.currentframe` and :func:`sys._getframe` -are generally safe as long as the resulting frame object is not passed to -another thread. +It is not safe to access :attr:`frame.f_locals` from a :ref:`frame ` +object if that frame is currently executing in another thread, and doing so may +crash the interpreter. + Iterators --------- -Sharing the same iterator object between multiple threads is generally not -safe and threads may see duplicate or missing elements when iterating or crash -the interpreter. +It is generally not thread-safe to access the same iterator object from +multiple threads concurrently, and threads may see duplicate or missing +elements. Single-threaded performance --------------------------- The free-threaded build has additional overhead when executing Python code -compared to the default GIL-enabled build. In 3.13, this overhead is about -40% on the `pyperformance `_ suite. -Programs that spend most of their time in C extensions or I/O will see -less of an impact. The largest impact is because the specializing adaptive -interpreter (:pep:`659`) is disabled in the free-threaded build. We expect -to re-enable it in a thread-safe way in the 3.14 release. This overhead is -expected to be reduced in upcoming Python release. We are aiming for an -overhead of 10% or less on the pyperformance suite compared to the default -GIL-enabled build. +compared to the default GIL-enabled build. The amount of overhead depends +on the workload and hardware. On the pyperformance benchmark suite, the +average overhead ranges from about 1% on macOS aarch64 to 8% on x86-64 Linux +systems. Behavioral changes diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index 053558e3890..552514063c9 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -4,7 +4,7 @@ Functional Programming HOWTO ******************************** -:Author: A. M. Kuchling +:Author: \A. M. Kuchling :Release: 0.32 In this document, we'll take a tour of Python's features suitable for diff --git a/Doc/howto/gdb_helpers.rst b/Doc/howto/gdb_helpers.rst index 98ce813ca4a..33d1fbf8cd9 100644 --- a/Doc/howto/gdb_helpers.rst +++ b/Doc/howto/gdb_helpers.rst @@ -136,7 +136,7 @@ enabled:: at Objects/unicodeobject.c:551 #7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569 #8 0x0000000000584abd in PyDict_GetItemString (v= - {'Yuck': , '__builtins__': , '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': , 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': , '__doc__': None}, key= + {'Yuck': , '__builtins__': , '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': , 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__name__': '__main__', 'z': , '__doc__': None}, key= 0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171 Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst index 6e03ef20a21..b3db1189e5d 100644 --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -269,6 +269,8 @@ should instead read: (assuming a :ref:`debug build ` of CPython 3.6) +.. _static-markers: + Available static markers ------------------------ diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 7da6dc8a397..6092c75f48f 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -353,7 +353,7 @@ garbage collection protocol. That is, heap types should: - Have the :c:macro:`Py_TPFLAGS_HAVE_GC` flag. -- Define a traverse function using ``Py_tp_traverse``, which +- Define a traverse function using :c:data:`Py_tp_traverse`, which visits the type (e.g. using ``Py_VISIT(Py_TYPE(self))``). Please refer to the documentation of diff --git a/Doc/howto/remote_debugging.rst b/Doc/howto/remote_debugging.rst index b7323803654..78b40bcdf71 100644 --- a/Doc/howto/remote_debugging.rst +++ b/Doc/howto/remote_debugging.rst @@ -3,6 +3,78 @@ Remote debugging attachment protocol ==================================== +This protocol enables external tools to attach to a running CPython process and +execute Python code remotely. + +Most platforms require elevated privileges to attach to another Python process. + +.. _permission-requirements: + +Permission requirements +======================= + +Attaching to a running Python process for remote debugging requires elevated +privileges on most platforms. The specific requirements and troubleshooting +steps depend on your operating system: + +.. rubric:: Linux + +The tracer process must have the ``CAP_SYS_PTRACE`` capability or equivalent +privileges. You can only trace processes you own and can signal. Tracing may +fail if the process is already being traced, or if it is running with +set-user-ID or set-group-ID. Security modules like Yama may further restrict +tracing. + +To temporarily relax ptrace restrictions (until reboot), run: + + ``echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`` + +.. note:: + + Disabling ``ptrace_scope`` reduces system hardening and should only be done + in trusted environments. + +If running inside a container, use ``--cap-add=SYS_PTRACE`` or +``--privileged``, and run as root if needed. + +Try re-running the command with elevated privileges: + + ``sudo -E !!`` + + +.. rubric:: macOS + +To attach to another process, you typically need to run your debugging tool +with elevated privileges. This can be done by using ``sudo`` or running as +root. + +Even when attaching to processes you own, macOS may block debugging unless +the debugger is run with root privileges due to system security restrictions. + + +.. rubric:: Windows + +To attach to another process, you usually need to run your debugging tool +with administrative privileges. Start the command prompt or terminal as +Administrator. + +Some processes may still be inaccessible even with Administrator rights, +unless you have the ``SeDebugPrivilege`` privilege enabled. + +To resolve file or folder access issues, adjust the security permissions: + + 1. Right-click the file or folder and select **Properties**. + 2. Go to the **Security** tab to view users and groups with access. + 3. Click **Edit** to modify permissions. + 4. Select your user account. + 5. In **Permissions**, check **Read** or **Full control** as needed. + 6. Click **Apply**, then **OK** to confirm. + + +.. note:: + + Ensure you've satisfied all :ref:`permission-requirements` before proceeding. + This section describes the low-level protocol that enables external tools to inject and execute a Python script within a running CPython process. diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst index 254fe729355..243cc27bac7 100644 --- a/Doc/howto/unicode.rst +++ b/Doc/howto/unicode.rst @@ -352,6 +352,8 @@ If you don't include such a comment, the default encoding used will be UTF-8 as already mentioned. See also :pep:`263` for more information. +.. _unicode-properties: + Unicode Properties ------------------ diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index d79d1abe8d0..4e77d2cb407 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -15,7 +15,7 @@ Introduction You may also find useful the following article on fetching web resources with Python: - * `Basic Authentication `_ + * `Basic Authentication `__ A tutorial on *Basic Authentication*, with examples in Python. diff --git a/Doc/includes/optional-module.rst b/Doc/includes/optional-module.rst new file mode 100644 index 00000000000..262e73f2eaa --- /dev/null +++ b/Doc/includes/optional-module.rst @@ -0,0 +1,9 @@ +This is an :term:`optional module`. +If it is missing from your copy of CPython, +look for documentation from your distributor (that is, +whoever provided Python to you). +If you are the distributor, see :ref:`optional-module-requirements`. + +.. Similar notes appear in the docs of the modules: + - zipfile + - tarfile diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 1d00d05817e..47f5eabb6f2 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -127,7 +127,7 @@ This module defines the following constants and functions: .. versionchanged:: 3.13 Added support for GNU/kFreeBSD. - .. versionchanged:: next + .. versionchanged:: 3.15 Added support for Solaris. diff --git a/Doc/library/annotationlib.rst b/Doc/library/annotationlib.rst index 981d89be7d5..40f2a6dc304 100644 --- a/Doc/library/annotationlib.rst +++ b/Doc/library/annotationlib.rst @@ -4,6 +4,7 @@ .. module:: annotationlib :synopsis: Functionality for introspecting annotations +.. versionadded:: 3.14 **Source code:** :source:`Lib/annotationlib.py` @@ -45,6 +46,10 @@ and :func:`call_annotate_function`, as well as the :func:`call_evaluate_function` function for working with :term:`evaluate functions `. +.. caution:: + + Most functionality in this module can execute arbitrary code; see + :ref:`the security section ` for more information. .. seealso:: @@ -335,14 +340,29 @@ Functions * VALUE: :attr:`!object.__annotations__` is tried first; if that does not exist, the :attr:`!object.__annotate__` function is called if it exists. + * FORWARDREF: If :attr:`!object.__annotations__` exists and can be evaluated successfully, it is used; otherwise, the :attr:`!object.__annotate__` function is called. If it does not exist either, :attr:`!object.__annotations__` is tried again and any error from accessing it is re-raised. + + * When calling :attr:`!object.__annotate__` it is first called with :attr:`~Format.FORWARDREF`. + If this is not implemented, it will then check if :attr:`~Format.VALUE_WITH_FAKE_GLOBALS` + is supported and use that in the fake globals environment. + If neither of these formats are supported, it will fall back to using :attr:`~Format.VALUE`. + If :attr:`~Format.VALUE` fails, the error from this call will be raised. + * STRING: If :attr:`!object.__annotate__` exists, it is called first; otherwise, :attr:`!object.__annotations__` is used and stringified using :func:`annotations_to_string`. + * When calling :attr:`!object.__annotate__` it is first called with :attr:`~Format.STRING`. + If this is not implemented, it will then check if :attr:`~Format.VALUE_WITH_FAKE_GLOBALS` + is supported and use that in the fake globals environment. + If neither of these formats are supported, it will fall back to using :attr:`~Format.VALUE` + with the result converted using :func:`annotations_to_string`. + If :attr:`~Format.VALUE` fails, the error from this call will be raised. + Returns a dict. :func:`!get_annotations` returns a new dict every time it's called; calling it twice on the same object will return two different but equivalent dicts. @@ -603,3 +623,23 @@ Below are a few examples of the behavior with unsupported expressions: >>> def ifexp(x: 1 if y else 0): ... >>> get_annotations(ifexp, format=Format.STRING) {'x': '1'} + +.. _annotationlib-security: + +Security implications of introspecting annotations +-------------------------------------------------- + +Much of the functionality in this module involves executing code related to annotations, +which can then do arbitrary things. For example, +:func:`get_annotations` may call an arbitrary :term:`annotate function`, and +:meth:`ForwardRef.evaluate` may call :func:`eval` on an arbitrary string. Code contained +in an annotation might make arbitrary system calls, enter an infinite loop, or perform any +other operation. This is also true for any access of the :attr:`~object.__annotations__` attribute, +and for various functions in the :mod:`typing` module that work with annotations, such as +:func:`typing.get_type_hints`. + +Any security issue arising from this also applies immediately after importing +code that may contain untrusted annotations: importing code can always cause arbitrary operations +to be performed. However, it is unsafe to accept strings or other input from an untrusted source and +pass them to any of the APIs for introspecting annotations, for example by editing an +``__annotations__`` dictionary or directly creating a :class:`ForwardRef` object. diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 79e15994491..5cfe047d746 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -74,7 +74,7 @@ ArgumentParser objects prefix_chars='-', fromfile_prefix_chars=None, \ argument_default=None, conflict_handler='error', \ add_help=True, allow_abbrev=True, exit_on_error=True, \ - *, suggest_on_error=False, color=True) + *, suggest_on_error=True, color=True) Create a new :class:`ArgumentParser` object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description @@ -117,7 +117,7 @@ ArgumentParser objects error info when an error occurs. (default: ``True``) * suggest_on_error_ - Enables suggestions for mistyped argument choices - and subparser names (default: ``False``) + and subparser names (default: ``True``) * color_ - Allow color output (default: ``True``) @@ -134,6 +134,9 @@ ArgumentParser objects .. versionchanged:: 3.14 *suggest_on_error* and *color* parameters were added. + .. versionchanged:: 3.15 + *suggest_on_error* default changed to ``True``. + The following sections describe how each of these are used. @@ -596,13 +599,11 @@ suggest_on_error ^^^^^^^^^^^^^^^^ By default, when a user passes an invalid argument choice or subparser name, -:class:`ArgumentParser` will exit with error info and list the permissible -argument choices (if specified) or subparser names as part of the error message. - -If the user would like to enable suggestions for mistyped argument choices and -subparser names, the feature can be enabled by setting ``suggest_on_error`` to -``True``. Note that this only applies for arguments when the choices specified -are strings:: +:class:`ArgumentParser` will exit with error info and provide suggestions for +mistyped arguments. The error message will list the permissible argument +choices (if specified) or subparser names, along with a "maybe you meant" +suggestion if a close match is found. Note that this only applies for arguments +when the choices specified are strings:: >>> parser = argparse.ArgumentParser(description='Process some integers.', suggest_on_error=True) @@ -612,16 +613,14 @@ are strings:: >>> parser.parse_args(['--action', 'sumn', 1, 2, 3]) tester.py: error: argument --action: invalid choice: 'sumn', maybe you meant 'sum'? (choose from 'sum', 'max') -If you're writing code that needs to be compatible with older Python versions -and want to opportunistically use ``suggest_on_error`` when it's available, you -can set it as an attribute after initializing the parser instead of using the -keyword argument:: +You can disable suggestions by setting ``suggest_on_error`` to ``False``:: - >>> parser = argparse.ArgumentParser(description='Process some integers.') - >>> parser.suggest_on_error = True + >>> parser = argparse.ArgumentParser(description='Process some integers.', + suggest_on_error=False) .. versionadded:: 3.14 - +.. versionchanged:: 3.15 + Changed default value of ``suggest_on_error`` from ``False`` to ``True``. color ^^^^^ @@ -639,8 +638,34 @@ by setting ``color`` to ``False``:: ... help='an integer for the accumulator') >>> parser.parse_args(['--help']) +Note that when ``color=True``, colored output depends on both environment +variables and terminal capabilities. However, if ``color=False``, colored +output is always disabled, even if environment variables like ``FORCE_COLOR`` +are set. + .. versionadded:: 3.14 +To highlight inline code in your description or epilog text, you can use +backticks:: + + >>> parser = argparse.ArgumentParser( + ... formatter_class=argparse.RawDescriptionHelpFormatter, + ... epilog='''Examples: + ... `python -m myapp --verbose` + ... `python -m myapp --config settings.json` + ... ''') + +When colors are enabled, the text inside backticks will be displayed in a +distinct color to help examples stand out. When colors are disabled, backticks +are preserved as-is, which is readable in plain text. + +.. note:: + + Backtick markup only applies to description and epilog text. It does not + apply to individual argument ``help`` strings. + +.. versionadded:: 3.15 + The add_argument() method ------------------------- @@ -763,9 +788,9 @@ how the command-line arguments should be handled. The supplied actions are: Namespace(foo=42) * ``'store_true'`` and ``'store_false'`` - These are special cases of - ``'store_const'`` used for storing the values ``True`` and ``False`` - respectively. In addition, they create default values of ``False`` and - ``True`` respectively:: + ``'store_const'`` that respectively store the values ``True`` and ``False`` + with default values of ``False`` and + ``True``:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', action='store_true') @@ -774,19 +799,19 @@ how the command-line arguments should be handled. The supplied actions are: >>> parser.parse_args('--foo --bar'.split()) Namespace(foo=True, bar=False, baz=True) -* ``'append'`` - This stores a list, and appends each argument value to the - list. It is useful to allow an option to be specified multiple times. - If the default value is non-empty, the default elements will be present - in the parsed value for the option, with any values from the - command line appended after those default values. Example usage:: +* ``'append'`` - This appends each argument value to a list. + It is useful for allowing an option to be specified multiple times. + If the default value is a non-empty list, the parsed value will start + with the default list's elements and any values from the command line + will be appended after those default values. Example usage:: >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--foo', action='append') + >>> parser.add_argument('--foo', action='append', default=['0']) >>> parser.parse_args('--foo 1 --foo 2'.split()) - Namespace(foo=['1', '2']) + Namespace(foo=['0', '1', '2']) -* ``'append_const'`` - This stores a list, and appends the value specified by - the const_ keyword argument to the list; note that the const_ keyword +* ``'append_const'`` - This appends the value specified by + the const_ keyword argument to a list; note that the const_ keyword argument defaults to ``None``. The ``'append_const'`` action is typically useful when multiple arguments need to store constants to the same list. For example:: @@ -797,8 +822,8 @@ how the command-line arguments should be handled. The supplied actions are: >>> parser.parse_args('--str --int'.split()) Namespace(types=[, ]) -* ``'extend'`` - This stores a list and appends each item from the multi-value - argument list to it. +* ``'extend'`` - This appends each item from a multi-value + argument to a list. The ``'extend'`` action is typically used with the nargs_ keyword argument value ``'+'`` or ``'*'``. Note that when nargs_ is ``None`` (the default) or ``'?'``, each @@ -812,7 +837,7 @@ how the command-line arguments should be handled. The supplied actions are: .. versionadded:: 3.8 -* ``'count'`` - This counts the number of times a keyword argument occurs. For +* ``'count'`` - This counts the number of times an argument occurs. For example, this is useful for increasing verbosity levels:: >>> parser = argparse.ArgumentParser() @@ -981,8 +1006,8 @@ the various :class:`ArgumentParser` actions. The two most common uses of it are (like ``-f`` or ``--foo``) and ``nargs='?'``. This creates an optional argument that can be followed by zero or one command-line arguments. When parsing the command line, if the option string is encountered with no - command-line argument following it, the value of ``const`` will be assumed to - be ``None`` instead. See the nargs_ description for examples. + command-line argument following it, the value from ``const`` will be used. + See the nargs_ description for examples. .. versionchanged:: 3.11 ``const=None`` by default, including when ``action='append_const'`` or @@ -1142,16 +1167,21 @@ if the argument was not one of the acceptable values:: game.py: error: argument move: invalid choice: 'fire' (choose from 'rock', 'paper', 'scissors') -Note that inclusion in the *choices* sequence is checked after any type_ -conversions have been performed, so the type of the objects in the *choices* -sequence should match the type_ specified. - Any sequence can be passed as the *choices* value, so :class:`list` objects, :class:`tuple` objects, and custom sequences are all supported. Use of :class:`enum.Enum` is not recommended because it is difficult to control its appearance in usage, help, and error messages. +Note that *choices* are checked after any type_ +conversions have been performed, so objects in *choices* +should match the type_ specified. This can make *choices* +appear unfamiliar in usage, help, or error messages. + +To keep *choices* user-friendly, consider a custom type wrapper that +converts and formats values, or omit type_ and handle conversion in +your application code. + Formatted choices override the default *metavar* which is normally derived from *dest*. This is usually what you want because the user never sees the *dest* parameter. If this display isn't desirable (perhaps because there are @@ -1313,8 +1343,12 @@ attribute is determined by the ``dest`` keyword argument of For optional argument actions, the value of ``dest`` is normally inferred from the option strings. :class:`ArgumentParser` generates the value of ``dest`` by -taking the first long option string and stripping away the initial ``--`` -string. If no long option strings were supplied, ``dest`` will be derived from +taking the first double-dash long option string and stripping away the initial +``-`` characters. +If no double-dash long option strings were supplied, ``dest`` will be derived +from the first single-dash long option string by stripping the initial ``-`` +character. +If no long option strings were supplied, ``dest`` will be derived from the first short option string by stripping the initial ``-`` character. Any internal ``-`` characters will be converted to ``_`` characters to make sure the string is a valid attribute name. The examples below illustrate this @@ -1322,11 +1356,12 @@ behavior:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('-f', '--foo-bar', '--foo') + >>> parser.add_argument('-q', '-quz') >>> parser.add_argument('-x', '-y') - >>> parser.parse_args('-f 1 -x 2'.split()) - Namespace(foo_bar='1', x='2') - >>> parser.parse_args('--foo 1 -y 2'.split()) - Namespace(foo_bar='1', x='2') + >>> parser.parse_args('-f 1 -q 2 -x 3'.split()) + Namespace(foo_bar='1', quz='2', x='3') + >>> parser.parse_args('--foo 1 -quz 2 -y 3'.split()) + Namespace(foo_bar='1', quz='2', x='2') ``dest`` allows a custom attribute name to be provided:: @@ -1335,6 +1370,9 @@ behavior:: >>> parser.parse_args('--foo XXX'.split()) Namespace(bar='XXX') +.. versionchanged:: 3.15 + Single-dash long option now takes precedence over short options. + .. _deprecated: @@ -1428,8 +1466,18 @@ this API may be passed as the ``action`` parameter to >>> parser.parse_args(['--no-foo']) Namespace(foo=False) + Single-dash long options are also supported. + For example, negative option ``-nofoo`` is automatically added for + positive option ``-foo``. + But no additional options are added for short options such as ``-f``. + .. versionadded:: 3.9 + .. versionchanged:: 3.15 + Added support for single-dash options. + + Added support for alternate prefix_chars_. + The parse_args() method ----------------------- @@ -1652,7 +1700,7 @@ The Namespace object Other utilities --------------- -Sub-commands +Subcommands ^^^^^^^^^^^^ .. method:: ArgumentParser.add_subparsers(*, [title], [description], [prog], \ @@ -1681,7 +1729,7 @@ Sub-commands * *description* - description for the sub-parser group in help output, by default ``None`` - * *prog* - usage information that will be displayed with sub-command help, + * *prog* - usage information that will be displayed with subcommand help, by default the name of the program and any positional arguments before the subparser argument @@ -1691,7 +1739,7 @@ Sub-commands * action_ - the basic type of action to be taken when this argument is encountered at the command line - * dest_ - name of the attribute under which sub-command name will be + * dest_ - name of the attribute under which subcommand name will be stored; by default ``None`` and no value is stored * required_ - Whether or not a subcommand must be provided, by default @@ -2061,7 +2109,9 @@ Parser defaults >>> parser.parse_args(['736']) Namespace(bar=42, baz='badger', foo=736) - Note that parser-level defaults always override argument-level defaults:: + Note that defaults can be set at both the parser level using :meth:`set_defaults` + and at the argument level using :meth:`add_argument`. If both are called for the + same argument, the last default set for an argument is used:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--foo', default='bar') diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 319b2c81505..bf37540e5fa 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -139,12 +139,13 @@ Node classes The :meth:`~object.__repr__` output of :class:`~ast.AST` nodes includes the values of the node fields. -.. deprecated:: 3.8 +.. deprecated-removed:: 3.8 3.14 - Old classes :class:`!ast.Num`, :class:`!ast.Str`, :class:`!ast.Bytes`, - :class:`!ast.NameConstant` and :class:`!ast.Ellipsis` are still available, - but they will be removed in future Python releases. In the meantime, - instantiating them will return an instance of a different class. + Previous versions of Python provided the AST classes :class:`!ast.Num`, + :class:`!ast.Str`, :class:`!ast.Bytes`, :class:`!ast.NameConstant` and + :class:`!ast.Ellipsis`, which were deprecated in Python 3.8. These classes + were removed in Python 3.14, and their functionality has been replaced with + :class:`ast.Constant`. .. deprecated:: 3.9 @@ -363,6 +364,11 @@ Literals function call). This has the same meaning as ``FormattedValue.value``. * ``str`` is a constant containing the text of the interpolation expression. + + If ``str`` is set to ``None``, then ``value`` is used to generate code + when calling :func:`ast.unparse`. This no longer guarantees that the + generated code is identical to the original and is intended for code + generation. * ``conversion`` is an integer: * -1: no conversion @@ -2200,10 +2206,10 @@ Async and await Apart from the node classes, the :mod:`ast` module defines these utility functions and classes for traversing abstract syntax trees: -.. function:: parse(source, filename='', mode='exec', *, type_comments=False, feature_version=None, optimize=-1) +.. function:: parse(source, filename='', mode='exec', *, type_comments=False, feature_version=None, optimize=-1, module=None) Parse the source into an AST node. Equivalent to ``compile(source, - filename, mode, flags=FLAGS_VALUE, optimize=optimize)``, + filename, mode, flags=FLAGS_VALUE, optimize=optimize, module=module)``, where ``FLAGS_VALUE`` is ``ast.PyCF_ONLY_AST`` if ``optimize <= 0`` and ``ast.PyCF_OPTIMIZED_AST`` otherwise. @@ -2256,6 +2262,9 @@ and classes for traversing abstract syntax trees: The minimum supported version for ``feature_version`` is now ``(3, 7)``. The ``optimize`` argument was added. + .. versionadded:: 3.15 + Added the *module* parameter. + .. function:: unparse(ast_obj) @@ -2411,12 +2420,12 @@ and classes for traversing abstract syntax trees: during traversal. For this a special visitor exists (:class:`NodeTransformer`) that allows modifications. - .. deprecated:: 3.8 + .. deprecated-removed:: 3.8 3.14 Methods :meth:`!visit_Num`, :meth:`!visit_Str`, :meth:`!visit_Bytes`, - :meth:`!visit_NameConstant` and :meth:`!visit_Ellipsis` are deprecated - now and will not be called in future Python versions. Add the - :meth:`visit_Constant` method to handle all constant nodes. + :meth:`!visit_NameConstant` and :meth:`!visit_Ellipsis` will not be called + in Python 3.14+. Add the :meth:`visit_Constant` method instead to handle + all constant nodes. .. class:: NodeTransformer() @@ -2507,7 +2516,7 @@ and classes for traversing abstract syntax trees: .. versionchanged:: 3.13 Added the *show_empty* option. - .. versionchanged:: next + .. versionchanged:: 3.15 Omit optional ``Load()`` values by default. diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 0ccc7a2b448..72f484fd1cb 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1631,6 +1631,9 @@ async/await code consider using the high-level conforms to the :class:`asyncio.SubprocessTransport` base class and *protocol* is an object instantiated by the *protocol_factory*. + If the transport is closed or is garbage collected, the child process + is killed if it is still running. + .. method:: loop.subprocess_shell(protocol_factory, cmd, *, \ stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ stderr=subprocess.PIPE, **kwargs) @@ -1654,6 +1657,9 @@ async/await code consider using the high-level conforms to the :class:`SubprocessTransport` base class and *protocol* is an object instantiated by the *protocol_factory*. + If the transport is closed or is garbage collected, the child process + is killed if it is still running. + .. note:: It is the application's responsibility to ensure that all whitespace and special characters are quoted appropriately to avoid `shell injection diff --git a/Doc/library/asyncio-queue.rst b/Doc/library/asyncio-queue.rst index d481a1921d5..a9735ae8065 100644 --- a/Doc/library/asyncio-queue.rst +++ b/Doc/library/asyncio-queue.rst @@ -107,7 +107,7 @@ Queue The queue can no longer grow. Future calls to :meth:`~Queue.put` raise :exc:`QueueShutDown`. Currently blocked callers of :meth:`~Queue.put` will be unblocked - and will raise :exc:`QueueShutDown` in the formerly blocked thread. + and will raise :exc:`QueueShutDown` in the formerly awaiting task. If *immediate* is false (the default), the queue can be wound down normally with :meth:`~Queue.get` calls to extract tasks diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index e1568ae330b..05445219510 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -316,13 +316,14 @@ StreamWriter If that fails, the data is queued in an internal write buffer until it can be sent. + The *data* buffer should be a bytes, bytearray, or C-contiguous one-dimensional + memoryview object. + The method should be used along with the ``drain()`` method:: stream.write(data) await stream.drain() - .. note:: - The *data* buffer should be a C contiguous one-dimensional :term:`bytes-like object `. .. method:: writelines(data) diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index 03e76bc8689..9416c758e51 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -76,6 +76,9 @@ Creating Subprocesses See the documentation of :meth:`loop.subprocess_exec` for other parameters. + If the process object is garbage collected while the process is still + running, the child process will be killed. + .. versionchanged:: 3.10 Removed the *loop* parameter. @@ -95,6 +98,9 @@ Creating Subprocesses See the documentation of :meth:`loop.subprocess_shell` for other parameters. + If the process object is garbage collected while the process is still + running, the child process will be killed. + .. important:: It is the application's responsibility to ensure that all whitespace and diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index f825ae92ec7..863b3e33657 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1221,8 +1221,8 @@ Task Object To cancel a running Task use the :meth:`cancel` method. Calling it will cause the Task to throw a :exc:`CancelledError` exception into - the wrapped coroutine. If a coroutine is awaiting on a Future - object during cancellation, the Future object will be cancelled. + the wrapped coroutine. If a coroutine is awaiting on a future-like + object during cancellation, the awaited object will be cancelled. :meth:`cancelled` can be used to check if the Task was cancelled. The method returns ``True`` if the wrapped coroutine did not @@ -1411,6 +1411,10 @@ Task Object the cancellation, it needs to call :meth:`Task.uncancel` in addition to catching the exception. + If the Task being cancelled is currently awaiting on a future-like + object, that awaited object will also be cancelled. This cancellation + propagates down the entire chain of awaited objects. + .. versionchanged:: 3.9 Added the *msg* parameter. diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index 444db01390d..0f72e31dee5 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -79,6 +79,10 @@ You can experiment with an ``asyncio`` concurrent context in the :term:`REPL`: >>> await asyncio.sleep(10, result='hello') 'hello' +This REPL provides limited compatibility with :envvar:`PYTHON_BASIC_REPL`. +It is recommended that the default REPL is used +for full functionality and the latest features. + .. audit-event:: cpython.run_stdin "" "" .. versionchanged:: 3.12.5 (also 3.11.10, 3.10.15, 3.9.20, and 3.8.20) diff --git a/Doc/library/bdb.rst b/Doc/library/bdb.rst index c7a3e0c596b..a3c6da7a6d6 100644 --- a/Doc/library/bdb.rst +++ b/Doc/library/bdb.rst @@ -236,7 +236,7 @@ The :mod:`bdb` module also defines two classes: Normally derived classes don't override the following methods, but they may if they want to redefine the definition of stopping and breakpoints. - .. method:: is_skipped_line(module_name) + .. method:: is_skipped_module(module_name) Return ``True`` if *module_name* matches any skip pattern. diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst index d02ffe469ad..d5ec4212c1f 100644 --- a/Doc/library/bisect.rst +++ b/Doc/library/bisect.rst @@ -83,7 +83,7 @@ The following functions are provided: Insert *x* in *a* in sorted order. This function first runs :py:func:`~bisect.bisect_left` to locate an insertion point. - Next, it runs the :meth:`!insert` method on *a* to insert *x* at the + Next, it runs the :meth:`~sequence.insert` method on *a* to insert *x* at the appropriate position to maintain sort order. To support inserting records in a table, the *key* function (if any) is @@ -103,7 +103,7 @@ The following functions are provided: entries of *x*. This function first runs :py:func:`~bisect.bisect_right` to locate an insertion point. - Next, it runs the :meth:`!insert` method on *a* to insert *x* at the + Next, it runs the :meth:`~sequence.insert` method on *a* to insert *x* at the appropriate position to maintain sort order. To support inserting records in a table, the *key* function (if any) is diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index ebe2e43feba..12650861c0f 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -25,6 +25,8 @@ The :mod:`bz2` module contains: * The :func:`compress` and :func:`decompress` functions for one-shot (de)compression. +.. include:: ../includes/optional-module.rst + (De)compression of files ------------------------ diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index fd397547a04..822e627af8d 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -158,6 +158,11 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is :class:`TextCalendar` instances have the following methods: + .. method:: prweek(theweek, width) + + Print a week's calendar as returned by :meth:`formatweek` and without a + final newline. + .. method:: formatday(theday, weekday, width) @@ -533,7 +538,7 @@ The :mod:`calendar` module exports the following data attributes: in the standalone form if the locale provides one. Else it is equivalent to :data:`month_name`. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: standalone_month_abbr @@ -542,7 +547,7 @@ The :mod:`calendar` module exports the following data attributes: locale in the standalone form if the locale provides one. Else it is equivalent to :data:`month_abbr`. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: JANUARY @@ -710,8 +715,7 @@ The following options are accepted: .. option:: month The month of the specified :option:`year` to print the calendar for. - Must be a number between 1 and 12, - and may only be used in text mode. + Must be a number between 1 and 12. Defaults to printing a calendar for the full year. diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 26518a0458f..b6d5dbee21d 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -338,7 +338,7 @@ Constants .. data:: nan A floating-point "not a number" (NaN) value. Equivalent to - ``float('nan')``. + ``float('nan')``. See also :data:`math.nan`. .. versionadded:: 3.6 diff --git a/Doc/library/cmdline.rst b/Doc/library/cmdline.rst index 16c67ddbf7c..6418706269f 100644 --- a/Doc/library/cmdline.rst +++ b/Doc/library/cmdline.rst @@ -12,27 +12,28 @@ The following modules have a command-line interface. * :ref:`calendar ` * :mod:`code` * :ref:`compileall ` -* :mod:`cProfile`: see :ref:`profile ` +* ``cProfile``: see :ref:`profiling.tracing ` * :ref:`dis ` * :ref:`doctest ` * :mod:`!encodings.rot_13` -* :mod:`ensurepip` +* :ref:`ensurepip ` * :mod:`filecmp` * :mod:`fileinput` * :mod:`ftplib` * :ref:`gzip ` * :ref:`http.server ` -* :mod:`!idlelib` +* :ref:`idlelib ` * :ref:`inspect ` * :ref:`json ` * :ref:`mimetypes ` -* :mod:`pdb` +* :ref:`pdb ` * :ref:`pickle ` * :ref:`pickletools ` * :ref:`platform ` * :mod:`poplib` -* :ref:`profile ` -* :mod:`pstats` +* :ref:`profiling.sampling ` +* :ref:`profiling.tracing ` +* :ref:`pstats ` * :ref:`py_compile ` * :mod:`pyclbr` * :mod:`pydoc` @@ -52,8 +53,8 @@ The following modules have a command-line interface. * :mod:`turtledemo` * :ref:`unittest ` * :ref:`uuid ` -* :mod:`venv` -* :mod:`webbrowser` +* :ref:`venv ` +* :ref:`webbrowser ` * :ref:`zipapp ` * :ref:`zipfile ` diff --git a/Doc/library/code.rst b/Doc/library/code.rst index 52587c4dd8f..59c016d2150 100644 --- a/Doc/library/code.rst +++ b/Doc/library/code.rst @@ -29,7 +29,7 @@ build applications which provide an interactive interpreter prompt. module. -.. class:: InteractiveConsole(locals=None, filename="", local_exit=False) +.. class:: InteractiveConsole(locals=None, filename="", *, local_exit=False) Closely emulate the behavior of the interactive Python interpreter. This class builds on :class:`InteractiveInterpreter` and adds prompting using the familiar diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 5932012c535..305e5d07a35 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -68,11 +68,21 @@ The full details for each codec can also be looked up directly: Looks up the codec info in the Python codec registry and returns a :class:`CodecInfo` object as defined below. - Encodings are first looked up in the registry's cache. If not found, the list of + This function first normalizes the *encoding*: all ASCII letters are + converted to lower case, spaces are replaced with hyphens. + Then encoding is looked up in the registry's cache. If not found, the list of registered search functions is scanned. If no :class:`CodecInfo` object is found, a :exc:`LookupError` is raised. Otherwise, the :class:`CodecInfo` object is stored in the cache and returned to the caller. + .. versionchanged:: 3.9 + Any characters except ASCII letters and digits and a dot are converted to underscore. + + .. versionchanged:: 3.15 + No characters are converted to underscore anymore. + Spaces are converted to hyphens. + + .. class:: CodecInfo(encode, decode, streamreader=None, streamwriter=None, incrementalencoder=None, incrementaldecoder=None, name=None) Codec details when looking up the codec registry. The constructor @@ -167,14 +177,11 @@ function: .. function:: register(search_function, /) Register a codec search function. Search functions are expected to take one - argument, being the encoding name in all lower case letters with hyphens - and spaces converted to underscores, and return a :class:`CodecInfo` object. + argument, being the encoding name in all lower case letters with spaces + converted to hyphens, and return a :class:`CodecInfo` object. In case a search function cannot find a given encoding, it should return ``None``. - .. versionchanged:: 3.9 - Hyphens and spaces are converted to underscore. - .. function:: unregister(search_function, /) @@ -982,17 +989,22 @@ defined in Unicode. A simple and straightforward way that can store each Unicode code point, is to store each code point as four consecutive bytes. There are two possibilities: store the bytes in big endian or in little endian order. These two encodings are called ``UTF-32-BE`` and ``UTF-32-LE`` respectively. Their -disadvantage is that if e.g. you use ``UTF-32-BE`` on a little endian machine you -will always have to swap bytes on encoding and decoding. ``UTF-32`` avoids this -problem: bytes will always be in natural endianness. When these bytes are read -by a CPU with a different endianness, then bytes have to be swapped though. To -be able to detect the endianness of a ``UTF-16`` or ``UTF-32`` byte sequence, -there's the so called BOM ("Byte Order Mark"). This is the Unicode character -``U+FEFF``. This character can be prepended to every ``UTF-16`` or ``UTF-32`` -byte sequence. The byte swapped version of this character (``0xFFFE``) is an -illegal character that may not appear in a Unicode text. So when the -first character in a ``UTF-16`` or ``UTF-32`` byte sequence -appears to be a ``U+FFFE`` the bytes have to be swapped on decoding. +disadvantage is that if, for example, you use ``UTF-32-BE`` on a little endian +machine you will always have to swap bytes on encoding and decoding. +Python's ``UTF-16`` and ``UTF-32`` codecs avoid this problem by using the +platform's native byte order when no BOM is present. +Python follows prevailing platform +practice, so native-endian data round-trips without redundant byte swapping, +even though the Unicode Standard defaults to big-endian when the byte order is +unspecified. When these bytes are read by a CPU with a different endianness, +the bytes have to be swapped. To be able to detect the endianness of a +``UTF-16`` or ``UTF-32`` byte sequence, a BOM ("Byte Order Mark") is used. +This is the Unicode character ``U+FEFF``. This character can be prepended to every +``UTF-16`` or ``UTF-32`` byte sequence. The byte swapped version of this character +(``0xFFFE``) is an illegal character that may not appear in a Unicode text. +When the first character of a ``UTF-16`` or ``UTF-32`` byte sequence is +``U+FFFE``, the bytes have to be swapped on decoding. + Unfortunately the character ``U+FEFF`` had a second purpose as a ``ZERO WIDTH NO-BREAK SPACE``: a character that has no width and doesn't allow a word to be split. It can e.g. be used to give hints to a ligature algorithm. @@ -1065,7 +1077,7 @@ or with dictionaries as mapping tables. The following table lists the codecs by name, together with a few common aliases, and the languages for which the encoding is likely used. Neither the list of aliases nor the list of languages is meant to be exhaustive. Notice that spelling alternatives that only differ in -case or use a hyphen instead of an underscore are also valid aliases +case or use a space or a hyphen instead of an underscore are also valid aliases because they are equivalent when normalized by :func:`~encodings.normalize_encoding`. For example, ``'utf-8'`` is a valid alias for the ``'utf_8'`` codec. @@ -1076,7 +1088,7 @@ alias for the ``'utf_8'`` codec. refer to the source :source:`aliases.py ` file. On Windows, ``cpXXX`` codecs are available for all code pages. -But only codecs listed in the following table are guarantead to exist on +But only codecs listed in the following table are guaranteed to exist on other platforms. .. impl-detail:: @@ -1332,7 +1344,7 @@ particular, the following variants typically exist: +-----------------+--------------------------------+--------------------------------+ | utf_8 | U8, UTF, utf8, cp65001 | all languages | +-----------------+--------------------------------+--------------------------------+ -| utf_8_sig | | all languages | +| utf_8_sig | utf8-sig | all languages | +-----------------+--------------------------------+--------------------------------+ .. versionchanged:: 3.4 diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index daa9af6d1dd..e6daccb91f2 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -140,6 +140,9 @@ ABC Inherits from Abstract Methods Mi ``__len__``, ``insert`` +:class:`ByteString` :class:`Sequence` ``__getitem__``, Inherited :class:`Sequence` methods + ``__len__`` + :class:`Set` :class:`Collection` ``__contains__``, ``__le__``, ``__lt__``, ``__eq__``, ``__ne__``, ``__iter__``, ``__gt__``, ``__ge__``, ``__and__``, ``__or__``, ``__len__`` ``__sub__``, ``__rsub__``, ``__xor__``, ``__rxor__`` @@ -260,21 +263,50 @@ Collections Abstract Base Classes -- Detailed Descriptions .. class:: Sequence MutableSequence + ByteString ABCs for read-only and mutable :term:`sequences `. Implementation note: Some of the mixin methods, such as - :meth:`~container.__iter__`, :meth:`~object.__reversed__` and :meth:`index`, make - repeated calls to the underlying :meth:`~object.__getitem__` method. + :meth:`~container.__iter__`, :meth:`~object.__reversed__`, + and :meth:`~sequence.index` make repeated calls to the underlying + :meth:`~object.__getitem__` method. Consequently, if :meth:`~object.__getitem__` is implemented with constant access speed, the mixin methods will have linear performance; however, if the underlying method is linear (as it would be with a linked list), the mixins will have quadratic performance and will likely need to be overridden. - .. versionchanged:: 3.5 - The index() method added support for *stop* and *start* - arguments. + .. method:: index(value, start=0, stop=None) + + Return first index of *value*. + + Raises :exc:`ValueError` if the value is not present. + + Supporting the *start* and *stop* arguments is optional, but recommended. + + .. versionchanged:: 3.5 + The :meth:`~sequence.index` method gained support for + the *stop* and *start* arguments. + + .. deprecated-removed:: 3.12 3.17 + The :class:`ByteString` ABC has been deprecated. + + Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj`` + implements the :ref:`buffer protocol ` at runtime. For use + in type annotations, either use :class:`Buffer` or a union that + explicitly specifies the types your code supports (e.g., + ``bytes | bytearray | memoryview``). + + :class:`!ByteString` was originally intended to be an abstract class that + would serve as a supertype of both :class:`bytes` and :class:`bytearray`. + However, since the ABC never had any methods, knowing that an object was + an instance of :class:`!ByteString` never actually told you anything + useful about the object. Other common buffer types such as + :class:`memoryview` were also never understood as subtypes of + :class:`!ByteString` (either at runtime or by static type checkers). + + See :pep:`PEP 688 <688#current-options>` for more details. .. class:: Set MutableSet @@ -304,7 +336,7 @@ Collections Abstract Base Classes -- Detailed Descriptions .. note:: In CPython, generator-based coroutines (:term:`generators ` - decorated with :func:`@types.coroutine `) are + decorated with :deco:`types.coroutine`) are *awaitables*, even though they do not have an :meth:`~object.__await__` method. Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``. Use :func:`inspect.isawaitable` to detect them. @@ -322,7 +354,7 @@ Collections Abstract Base Classes -- Detailed Descriptions .. note:: In CPython, generator-based coroutines (:term:`generators ` - decorated with :func:`@types.coroutine `) are + decorated with :deco:`types.coroutine`) are *awaitables*, even though they do not have an :meth:`~object.__await__` method. Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``. Use :func:`inspect.isawaitable` to detect them. diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 5fbdb12f40c..4e0db485e06 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -367,9 +367,11 @@ Several mathematical operations are provided for combining :class:`Counter` objects to produce multisets (counters that have counts greater than zero). Addition and subtraction combine counters by adding or subtracting the counts of corresponding elements. Intersection and union return the minimum and -maximum of corresponding counts. Equality and inclusion compare -corresponding counts. Each operation can accept inputs with signed -counts, but the output will exclude results with counts of zero or less. +maximum of corresponding counts. Symmetric difference returns the difference +between the maximum and minimum of the corresponding counts. Equality and +inclusion compare corresponding counts. Each operation can accept inputs +with signed counts, but the output will exclude results with counts of zero +or below. .. doctest:: @@ -383,6 +385,8 @@ counts, but the output will exclude results with counts of zero or less. Counter({'a': 1, 'b': 1}) >>> c | d # union: max(c[x], d[x]) Counter({'a': 3, 'b': 2}) + >>> c ^ d # max(c[x], d[x]) - min(c[x], d[x]) + Counter({'a': 2, 'b': 1}) >>> c == d # equality: c[x] == d[x] False >>> c <= d # inclusion: c[x] <= d[x] @@ -400,6 +404,9 @@ or subtracting from an empty counter. .. versionadded:: 3.3 Added support for unary plus, unary minus, and in-place multiset operations. +.. versionadded:: 3.15 + Added support for the symmetric difference multiset operation, ``c ^ d``. + .. note:: Counters were primarily designed to work with positive integers to represent @@ -758,9 +765,9 @@ stack manipulations such as ``dup``, ``drop``, ``swap``, ``over``, ``pick``, .. attribute:: default_factory - This attribute is used by the :meth:`__missing__` method; it is - initialized from the first argument to the constructor, if present, or to - ``None``, if absent. + This attribute is used by the :meth:`~defaultdict.__missing__` method; + it is initialized from the first argument to the constructor, if present, + or to ``None``, if absent. .. versionchanged:: 3.9 Added merge (``|``) and update (``|=``) operators, specified in @@ -783,10 +790,10 @@ sequence of key-value pairs into a dictionary of lists: When each key is encountered for the first time, it is not already in the mapping; so an entry is automatically created using the :attr:`~defaultdict.default_factory` -function which returns an empty :class:`list`. The :meth:`!list.append` +function which returns an empty :class:`list`. The :meth:`list.append` operation then attaches the value to the new list. When keys are encountered again, the look-up proceeds normally (returning the list for that key) and the -:meth:`!list.append` operation adds another value to the list. This technique is +:meth:`list.append` operation adds another value to the list. This technique is simpler and faster than an equivalent technique using :meth:`dict.setdefault`: >>> d = {} @@ -1202,7 +1209,7 @@ If a new entry overwrites an existing entry, the original insertion position is changed and moved to the end:: class LastUpdatedOrderedDict(OrderedDict): - 'Store items in the order the keys were last added' + 'Store items in the order that the keys were last updated.' def __setitem__(self, key, value): super().__setitem__(key, value) diff --git a/Doc/library/compression.rst b/Doc/library/compression.rst index 618b4a3c2bd..98719be9992 100644 --- a/Doc/library/compression.rst +++ b/Doc/library/compression.rst @@ -1,6 +1,8 @@ The :mod:`!compression` package =============================== +.. module:: compression + .. versionadded:: 3.14 The :mod:`!compression` package contains the canonical compression modules diff --git a/Doc/library/compression.zstd.rst b/Doc/library/compression.zstd.rst index a901403621b..89b6fe540f5 100644 --- a/Doc/library/compression.zstd.rst +++ b/Doc/library/compression.zstd.rst @@ -33,6 +33,8 @@ The :mod:`!compression.zstd` module contains: * The :class:`CompressionParameter`, :class:`DecompressionParameter`, and :class:`Strategy` classes for setting advanced (de)compression parameters. +.. include:: ../includes/optional-module.rst + Exceptions ---------- diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 6f8043e6cf7..c2e2f7f820f 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -239,6 +239,8 @@ ThreadPoolExecutor Example InterpreterPoolExecutor ----------------------- +.. versionadded:: 3.14 + The :class:`InterpreterPoolExecutor` class uses a pool of interpreters to execute calls asynchronously. It is a :class:`ThreadPoolExecutor` subclass, which means each worker is running in its own thread. diff --git a/Doc/library/concurrent.interpreters.rst b/Doc/library/concurrent.interpreters.rst index 41ea6af3b22..55036090e8d 100644 --- a/Doc/library/concurrent.interpreters.rst +++ b/Doc/library/concurrent.interpreters.rst @@ -29,12 +29,12 @@ Actual concurrency is available separately through .. seealso:: :class:`~concurrent.futures.InterpreterPoolExecutor` - combines threads with interpreters in a familiar interface. + Combines threads with interpreters in a familiar interface. - .. XXX Add references to the upcoming HOWTO docs in the seealso block. + .. XXX Add references to the upcoming HOWTO docs in the seealso block. :ref:`isolating-extensions-howto` - how to update an extension module to support multiple interpreters + How to update an extension module to support multiple interpreters. :pep:`554` diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index 04080fd0d86..d058ba206c6 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -65,8 +65,9 @@ A small number of constants live in the built-in namespace. They are: .. index:: single: ...; ellipsis literal .. data:: Ellipsis - The same as the ellipsis literal "``...``". Special value used mostly in conjunction - with extended slicing syntax for user-defined container data types. + The same as the ellipsis literal "``...``", an object frequently used to + indicate that something is omitted. Assignment to ``Ellipsis`` is possible, but + assignment to ``...`` raises a :exc:`SyntaxError`. ``Ellipsis`` is the sole instance of the :data:`types.EllipsisType` type. diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 176be4ff333..d0fa645093a 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -327,10 +327,10 @@ Functions and classes provided: .. function:: redirect_stdout(new_target) Context manager for temporarily redirecting :data:`sys.stdout` to - another file or file-like object. + another :term:`file object`. This tool adds flexibility to existing functions or classes whose output - is hardwired to stdout. + is hardwired to :data:`sys.stdout`. For example, the output of :func:`help` normally is sent to *sys.stdout*. You can capture that output in a string by redirecting the output to an @@ -366,8 +366,8 @@ Functions and classes provided: .. function:: redirect_stderr(new_target) - Similar to :func:`~contextlib.redirect_stdout` but redirecting - :data:`sys.stderr` to another file or file-like object. + Similar to :func:`~contextlib.redirect_stdout` but redirecting the global + :data:`sys.stderr` to another :term:`file object`. This context manager is :ref:`reentrant `. diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 57580ce026e..b218468a084 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -313,7 +313,7 @@ client:: addr = writer.transport.get_extra_info('socket').getpeername() client_addr_var.set(addr) - # In any code that we call is now possible to get + # In any code that we call, it is now possible to get the # client's address by calling 'client_addr_var.get()'. while True: diff --git a/Doc/library/crypt.rst b/Doc/library/crypt.rst index 9ff37196ccf..647cb4925f3 100644 --- a/Doc/library/crypt.rst +++ b/Doc/library/crypt.rst @@ -13,7 +13,7 @@ being deprecated in Python 3.11. The removal was decided in :pep:`594`. Applications can use the :mod:`hashlib` module from the standard library. Other possible replacements are third-party libraries from PyPI: -:pypi:`legacycrypt`, :pypi:`bcrypt`, :pypi:`argon2-cffi`, or :pypi:`passlib`. +:pypi:`legacycrypt`, :pypi:`bcrypt`, or :pypi:`argon2-cffi`. These are not supported or maintained by the Python core team. The last version of Python that provided the :mod:`!crypt` module was diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index c11c9b8b2bf..4a033d823e6 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -295,8 +295,8 @@ The :mod:`csv` module defines the following classes: - the second through n-th rows contain strings where at least one value's length differs from that of the putative header of that column. - Twenty rows after the first row are sampled; if more than half of columns + - rows meet the criteria, :const:`True` is returned. + Twenty-one rows after the header are sampled; if more than half of the + columns + rows meet the criteria, :const:`True` is returned. .. note:: @@ -468,7 +468,8 @@ Dialects support the following attributes: .. attribute:: Dialect.skipinitialspace When :const:`True`, spaces immediately following the *delimiter* are ignored. - The default is :const:`False`. + The default is :const:`False`. When combining ``delimiter=' '`` with + ``skipinitialspace=True``, unquoted empty fields are not allowed. .. attribute:: Dialect.strict @@ -637,7 +638,7 @@ done:: .. rubric:: Footnotes .. [1] If ``newline=''`` is not specified, newlines embedded inside quoted fields - will not be interpreted correctly, and on platforms that use ``\r\n`` linendings + will not be interpreted correctly, and on platforms that use ``\r\n`` line endings on write an extra ``\r`` will be added. It should always be safe to specify ``newline=''``, since the csv module does its own (:term:`universal `) newline handling. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index d8dac24c8ab..6038af99009 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -14,6 +14,8 @@ data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python. +.. include:: ../includes/optional-module.rst + .. _ctypes-ctypes-tutorial: @@ -1386,6 +1388,9 @@ On Linux, :func:`~ctypes.util.find_library` tries to run external programs (``/sbin/ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the library file. It returns the filename of the library file. +Note that if the output of these programs does not correspond to the dynamic +linker used by Python, the result of this function may be misleading. + .. versionchanged:: 3.6 On Linux, the value of the environment variable ``LD_LIBRARY_PATH`` is used when searching for libraries, if a library cannot be found by any other means. @@ -2130,6 +2135,8 @@ Utility functions The exact functionality is system dependent. + See :ref:`ctypes-finding-shared-libraries` for complete documentation. + .. function:: find_msvcrt() :module: ctypes.util diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index fab54ca87ef..057d338edda 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -23,6 +23,8 @@ Linux and the BSD variants of Unix. .. include:: ../includes/wasm-mobile-notavail.rst +.. include:: ../includes/optional-module.rst + .. note:: Whenever the documentation mentions a *character* it can be specified @@ -716,8 +718,10 @@ The module :mod:`curses` defines the following functions: Window Objects -------------- -Window objects, as returned by :func:`initscr` and :func:`newwin` above, have -the following methods and attributes: +.. class:: window + + Window objects, as returned by :func:`initscr` and :func:`newwin` above, have + the following methods and attributes: .. method:: window.addch(ch[, attr]) @@ -1347,7 +1351,6 @@ The :mod:`curses` module defines the following data members: .. data:: version -.. data:: __version__ A bytes object representing the current version of the module. diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 2e4520c823b..cff36e25822 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -317,7 +317,7 @@ Module contents :func:`!field`, then the class attribute for this field will be replaced by the specified *default* value. If *default* is not provided, then the class attribute will be deleted. The intent is - that after the :func:`@dataclass ` decorator runs, the class + that after the :deco:`dataclass` decorator runs, the class attributes will all contain the default values for the fields, just as if the default value itself were specified. For example, after:: @@ -427,7 +427,7 @@ Module contents :data:`typing.Any` is used for ``type``. The values of *init*, *repr*, *eq*, *order*, *unsafe_hash*, *frozen*, *match_args*, *kw_only*, *slots*, and *weakref_slot* have - the same meaning as they do in :func:`@dataclass `. + the same meaning as they do in :deco:`dataclass`. If *module* is defined, the :attr:`!__module__` attribute of the dataclass is set to that value. @@ -435,12 +435,12 @@ Module contents The *decorator* parameter is a callable that will be used to create the dataclass. It should take the class object as a first argument and the same keyword arguments - as :func:`@dataclass `. By default, the :func:`@dataclass ` + as :deco:`dataclass`. By default, the :deco:`dataclass` function is used. This function is not strictly required, because any Python - mechanism for creating a new class with :attr:`!__annotations__` can - then apply the :func:`@dataclass ` function to convert that class to + mechanism for creating a new class with :attr:`~object.__annotations__` can + then apply the :deco:`dataclass` function to convert that class to a dataclass. This function is provided as a convenience. For example:: @@ -569,7 +569,7 @@ Post-init processing def __post_init__(self): self.c = self.a + self.b -The :meth:`~object.__init__` method generated by :func:`@dataclass ` does not call base +The :meth:`~object.__init__` method generated by :deco:`dataclass` does not call base class :meth:`!__init__` methods. If the base class has an :meth:`!__init__` method that has to be called, it is common to call this method in a :meth:`__post_init__` method:: @@ -599,7 +599,7 @@ parameters to :meth:`!__post_init__`. Also see the warning about how Class variables --------------- -One of the few places where :func:`@dataclass ` actually inspects the type +One of the few places where :deco:`dataclass` actually inspects the type of a field is to determine if a field is a class variable as defined in :pep:`526`. It does this by checking if the type of the field is :data:`typing.ClassVar`. If a field is a ``ClassVar``, it is excluded @@ -612,7 +612,7 @@ module-level :func:`fields` function. Init-only variables ------------------- -Another place where :func:`@dataclass ` inspects a type annotation is to +Another place where :deco:`dataclass` inspects a type annotation is to determine if a field is an init-only variable. It does this by seeing if the type of a field is of type :class:`InitVar`. If a field is an :class:`InitVar`, it is considered a pseudo-field called an init-only @@ -646,7 +646,7 @@ Frozen instances ---------------- It is not possible to create truly immutable Python objects. However, -by passing ``frozen=True`` to the :func:`@dataclass ` decorator you can +by passing ``frozen=True`` to the :deco:`dataclass` decorator you can emulate immutability. In that case, dataclasses will add :meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These methods will raise a :exc:`FrozenInstanceError` when invoked. @@ -662,7 +662,7 @@ must use :meth:`!object.__setattr__`. Inheritance ----------- -When the dataclass is being created by the :func:`@dataclass ` decorator, +When the dataclass is being created by the :deco:`dataclass` decorator, it looks through all of the class's base classes in reverse MRO (that is, starting at :class:`object`) and, for each dataclass that it finds, adds the fields from that base class to an ordered mapping of fields. @@ -786,7 +786,7 @@ for :attr:`!x` when creating a class instance will share the same copy of :attr:`!x`. Because dataclasses just use normal Python class creation they also share this behavior. There is no general way for Data Classes to detect this condition. Instead, the -:func:`@dataclass ` decorator will raise a :exc:`ValueError` if it +:deco:`dataclass` decorator will raise a :exc:`ValueError` if it detects an unhashable default parameter. The assumption is that if a value is unhashable, it is mutable. This is a partial solution, but it does protect against many common errors. @@ -820,7 +820,7 @@ default value have the following special behaviors: :meth:`~object.__get__` or :meth:`!__set__` method is called rather than returning or overwriting the descriptor object. -* To determine whether a field contains a default value, :func:`@dataclass ` +* To determine whether a field contains a default value, :deco:`dataclass` will call the descriptor's :meth:`!__get__` method using its class access form: ``descriptor.__get__(obj=None, type=cls)``. If the descriptor returns a value in this case, it will be used as the diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 7010f99c54d..8ae1c1fb9e4 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -535,6 +535,9 @@ Other constructors, all class methods: :c:func:`localtime` function. Raise :exc:`OSError` instead of :exc:`ValueError` on :c:func:`localtime` failure. + .. versionchanged:: 3.15 + Accepts any real number as *timestamp*, not only integer or float. + .. classmethod:: date.fromordinal(ordinal) @@ -1020,6 +1023,10 @@ Other constructors, all class methods: .. versionchanged:: 3.6 :meth:`fromtimestamp` may return instances with :attr:`.fold` set to 1. + .. versionchanged:: 3.15 + Accepts any real number as *timestamp*, not only integer or float. + + .. classmethod:: datetime.utcfromtimestamp(timestamp) Return the UTC :class:`.datetime` corresponding to the POSIX timestamp, with @@ -1060,6 +1067,9 @@ Other constructors, all class methods: Use :meth:`datetime.fromtimestamp` with :const:`UTC` instead. + .. versionchanged:: 3.15 + Accepts any real number as *timestamp*, not only integer or float. + .. classmethod:: datetime.fromordinal(ordinal) @@ -2629,7 +2639,10 @@ differences between platforms in handling of unsupported format specifiers. ``%G``, ``%u`` and ``%V`` were added. .. versionadded:: 3.12 - ``%:z`` was added. + ``%:z`` was added for :meth:`~.datetime.strftime` + +.. versionadded:: 3.15 + ``%:z`` was added for :meth:`~.datetime.strptime` Technical Detail ^^^^^^^^^^^^^^^^ @@ -2724,12 +2737,18 @@ Notes: When the ``%z`` directive is provided to the :meth:`~.datetime.strptime` method, the UTC offsets can have a colon as a separator between hours, minutes and seconds. - For example, ``'+01:00:00'`` will be parsed as an offset of one hour. - In addition, providing ``'Z'`` is identical to ``'+00:00'``. + For example, both ``'+010000'`` and ``'+01:00:00'`` will be parsed as an offset + of one hour. In addition, providing ``'Z'`` is identical to ``'+00:00'``. ``%:z`` - Behaves exactly as ``%z``, but has a colon separator added between - hours, minutes and seconds. + When used with :meth:`~.datetime.strftime`, behaves exactly as ``%z``, + except that a colon separator is added between hours, minutes and seconds. + + When used with :meth:`~.datetime.strptime`, the UTC offset is *required* + to have a colon as a separator between hours, minutes and seconds. + For example, ``'+01:00:00'`` (but *not* ``'+010000'``) will be parsed as + an offset of one hour. In addition, providing ``'Z'`` is identical to + ``'+00:00'``. ``%Z`` In :meth:`~.datetime.strftime`, ``%Z`` is replaced by an empty string if diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst index 140ca5c1e34..02eb68d7b49 100644 --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -217,7 +217,7 @@ or any other SQLite browser, including the SQLite CLI. While reorganizing, as much as two times the size of the original database is required in free disk space. However, be aware that this factor changes for each :mod:`dbm` submodule. - .. versionadded:: next + .. versionadded:: 3.15 :mod:`dbm.gnu` --- GNU database manager @@ -275,9 +275,6 @@ functionality like crash tolerance. * ``'s'``: Synchronized mode. Changes to the database will be written immediately to the file. * ``'u'``: Do not lock database. - * ``'m'``: Do not use :manpage:`mmap(2)`. - This may harm performance, but improve crash tolerance. - .. versionadded:: next Not all flags are valid for all versions of GDBM. See the :data:`open_flags` member for a list of supported flag characters. @@ -522,7 +519,7 @@ The :mod:`!dbm.dumb` module defines the following: While reorganizing, no additional free disk space is required. However, be aware that this factor changes for each :mod:`dbm` submodule. - .. versionadded:: next + .. versionadded:: 3.15 .. method:: dumbdbm.sync() diff --git a/Doc/library/debug.rst b/Doc/library/debug.rst index 60223657a44..f87c2481fb8 100644 --- a/Doc/library/debug.rst +++ b/Doc/library/debug.rst @@ -1,5 +1,5 @@ *********************** -Debugging and Profiling +Debugging and profiling *********************** These libraries help you with Python development: the debugger enables you to @@ -15,7 +15,8 @@ intrusive debugging or patching. bdb.rst faulthandler.rst pdb.rst - profile.rst + profiling.rst + pstats.rst timeit.rst trace.rst tracemalloc.rst diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 0b99a832405..376bcc7aaf9 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -34,10 +34,12 @@ The :mod:`decimal` module provides support for fast correctly rounded decimal floating-point arithmetic. It offers several advantages over the :class:`float` datatype: -* Decimal "is based on a floating-point model which was designed with people - in mind, and necessarily has a paramount guiding principle -- computers must - provide an arithmetic that works in the same way as the arithmetic that - people learn at school." -- excerpt from the decimal arithmetic specification. +* Decimal "is based on a `floating-point model + `__ which was designed + with people in mind, and necessarily has a paramount guiding principle -- + computers must provide an arithmetic that works in the same way as the + arithmetic that people learn at school." -- excerpt from the decimal + arithmetic specification. * Decimal numbers can be represented exactly. In contrast, numbers like ``1.1`` and ``2.2`` do not have exact representations in binary @@ -238,6 +240,26 @@ floating-point flying circus: >>> c % a Decimal('0.77') +Decimals can be formatted (with :func:`format` built-in or :ref:`f-strings`) in +fixed-point or scientific notation, using the same formatting syntax (see +:ref:`formatspec`) as builtin :class:`float` type: + +.. doctest:: + + >>> format(Decimal('2.675'), "f") + '2.675' + >>> format(Decimal('2.675'), ".2f") + '2.68' + >>> f"{Decimal('2.675'):.2f}" + '2.68' + >>> format(Decimal('2.675'), ".2e") + '2.68e+0' + >>> with localcontext() as ctx: + ... ctx.rounding = ROUND_DOWN + ... print(format(Decimal('2.675'), ".2f")) + ... + 2.67 + And some mathematical functions are also available to Decimal: >>> getcontext().prec = 28 @@ -264,7 +286,7 @@ allows the settings to be changed. This approach meets the needs of most applications. For more advanced work, it may be useful to create alternate contexts using the -Context() constructor. To make an alternate active, use the :func:`setcontext` +:meth:`Context` constructor. To make an alternate active, use the :func:`setcontext` function. In accordance with the standard, the :mod:`decimal` module provides two ready to @@ -1569,7 +1591,16 @@ In addition to the three supplied contexts, new contexts can be created with the Constants --------- -The constants in this section are only relevant for the C module. They +.. data:: SPEC_VERSION + + The highest version of the General Decimal Arithmetic + Specification that this implementation complies with. + See https://speleotrove.com/decimal/decarith.html for the specification. + + .. versionadded:: 3.15 + + +The following constants are only relevant for the C module. They are also included in the pure Python version for compatibility. +---------------------------------+---------------------+-------------------------------+ @@ -2100,20 +2131,20 @@ to work with the :class:`Decimal` class:: Decimal FAQ ----------- -Q. It is cumbersome to type ``decimal.Decimal('1234.5')``. Is there a way to +Q: It is cumbersome to type ``decimal.Decimal('1234.5')``. Is there a way to minimize typing when using the interactive interpreter? -A. Some users abbreviate the constructor to just a single letter: +A: Some users abbreviate the constructor to just a single letter: >>> D = decimal.Decimal >>> D('1.23') + D('3.45') Decimal('4.68') -Q. In a fixed-point application with two decimal places, some inputs have many +Q: In a fixed-point application with two decimal places, some inputs have many places and need to be rounded. Others are not supposed to have excess digits and need to be validated. What methods should be used? -A. The :meth:`~Decimal.quantize` method rounds to a fixed number of decimal places. If +A: The :meth:`~Decimal.quantize` method rounds to a fixed number of decimal places. If the :const:`Inexact` trap is set, it is also useful for validation: >>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01') @@ -2131,10 +2162,10 @@ the :const:`Inexact` trap is set, it is also useful for validation: ... Inexact: None -Q. Once I have valid two place inputs, how do I maintain that invariant +Q: Once I have valid two place inputs, how do I maintain that invariant throughout an application? -A. Some operations like addition, subtraction, and multiplication by an integer +A: Some operations like addition, subtraction, and multiplication by an integer will automatically preserve fixed point. Others operations, like division and non-integer multiplication, will change the number of decimal places and need to be followed-up with a :meth:`~Decimal.quantize` step: @@ -2166,21 +2197,21 @@ to handle the :meth:`~Decimal.quantize` step: >>> div(b, a) Decimal('0.03') -Q. There are many ways to express the same value. The numbers ``200``, +Q: There are many ways to express the same value. The numbers ``200``, ``200.000``, ``2E2``, and ``.02E+4`` all have the same value at various precisions. Is there a way to transform them to a single recognizable canonical value? -A. The :meth:`~Decimal.normalize` method maps all equivalent values to a single +A: The :meth:`~Decimal.normalize` method maps all equivalent values to a single representative: >>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split()) >>> [v.normalize() for v in values] [Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')] -Q. When does rounding occur in a computation? +Q: When does rounding occur in a computation? -A. It occurs *after* the computation. The philosophy of the decimal +A: It occurs *after* the computation. The philosophy of the decimal specification is that numbers are considered exact and are created independent of the current context. They can even have greater precision than current context. Computations process with those @@ -2198,10 +2229,10 @@ applied to the *result* of the computation:: >>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded Decimal('3.1416') -Q. Some decimal values always print with exponential notation. Is there a way +Q: Some decimal values always print with exponential notation. Is there a way to get a non-exponential representation? -A. For some values, exponential notation is the only way to express the number +A: For some values, exponential notation is the only way to express the number of significant places in the coefficient. For example, expressing ``5.0E+3`` as ``5000`` keeps the value constant but cannot show the original's two-place significance. @@ -2216,9 +2247,9 @@ value unchanged: >>> remove_exponent(Decimal('5E+3')) Decimal('5000') -Q. Is there a way to convert a regular float to a :class:`Decimal`? +Q: Is there a way to convert a regular float to a :class:`Decimal`? -A. Yes, any binary floating-point number can be exactly expressed as a +A: Yes, any binary floating-point number can be exactly expressed as a Decimal though an exact conversion may take more precision than intuition would suggest: @@ -2227,19 +2258,19 @@ suggest: >>> Decimal(math.pi) Decimal('3.141592653589793115997963468544185161590576171875') -Q. Within a complex calculation, how can I make sure that I haven't gotten a +Q: Within a complex calculation, how can I make sure that I haven't gotten a spurious result because of insufficient precision or rounding anomalies. -A. The decimal module makes it easy to test results. A best practice is to +A: The decimal module makes it easy to test results. A best practice is to re-run calculations using greater precision and with various rounding modes. Widely differing results indicate insufficient precision, rounding mode issues, ill-conditioned inputs, or a numerically unstable algorithm. -Q. I noticed that context precision is applied to the results of operations but +Q: I noticed that context precision is applied to the results of operations but not to the inputs. Is there anything to watch out for when mixing values of different precisions? -A. Yes. The principle is that all values are considered to be exact and so is +A: Yes. The principle is that all values are considered to be exact and so is the arithmetic on those values. Only the results are rounded. The advantage for inputs is that "what you type is what you get". A disadvantage is that the results can look odd if you forget that the inputs haven't been rounded: @@ -2267,9 +2298,9 @@ Alternatively, inputs can be rounded upon creation using the >>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678') Decimal('1.2345') -Q. Is the CPython implementation fast for large numbers? +Q: Is the CPython implementation fast for large numbers? -A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of +A: Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of the decimal module integrate the high speed `libmpdec `_ library for arbitrary precision correctly rounded decimal floating-point arithmetic [#]_. diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index c55ecac3409..9e5a62d8fe5 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -231,7 +231,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. *linejunk*: A function that accepts a single string argument, and returns true if the string is junk, or false if not. The default is ``None``. There is also a module-level function :func:`IS_LINE_JUNK`, which filters out lines - without visible characters, except for at most one pound character (``'#'``) + without visible characters, except for at most one hash character (``'#'``) -- however the underlying :class:`SequenceMatcher` class does a dynamic analysis of which lines are so frequent as to constitute noise, and this usually works better than using this function. @@ -323,7 +323,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. See :ref:`difflib-interface` for a more detailed example. - .. versionchanged:: next + .. versionchanged:: 3.15 Added the *color* parameter. diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 7360f4aa804..a24589fd0a5 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -585,6 +585,22 @@ operations on it as if it was a Python list. The top of the stack corresponds to generate line tracing events. +.. opcode:: NOT_TAKEN + + Do nothing code. + Used by the interpreter to record :monitoring-event:`BRANCH_LEFT` + and :monitoring-event:`BRANCH_RIGHT` events for :mod:`sys.monitoring`. + + .. versionadded:: 3.14 + + +.. opcode:: POP_ITER + + Removes the iterator from the top of the stack. + + .. versionadded:: 3.14 + + .. opcode:: POP_TOP Removes the top-of-stack item:: @@ -1626,7 +1642,7 @@ iterations of the loop. Pushes a ``NULL`` to the stack. Used in the call sequence to match the ``NULL`` pushed by - :opcode:`LOAD_METHOD` for non-method calls. + :opcode:`!LOAD_METHOD` for non-method calls. .. versionadded:: 3.11 @@ -1657,9 +1673,13 @@ iterations of the loop. * ``0x02`` a dictionary of keyword-only parameters' default values * ``0x04`` a tuple of strings containing parameters' annotations * ``0x08`` a tuple containing cells for free variables, making a closure + * ``0x10`` the :term:`annotate function` for the function object .. versionadded:: 3.13 + .. versionchanged:: 3.14 + Added ``0x10`` to indicate the annotate function for the function object. + .. opcode:: BUILD_SLICE (argc) @@ -1947,14 +1967,15 @@ but are replaced by real opcodes or removed before bytecode is generated. Marks the end of the code block associated with the last ``SETUP_FINALLY``, ``SETUP_CLEANUP`` or ``SETUP_WITH``. + .. opcode:: JUMP -.. opcode:: JUMP_NO_INTERRUPT + JUMP_NO_INTERRUPT Undirected relative jump instructions which are replaced by their directed (forward/backward) counterparts by the assembler. .. opcode:: JUMP_IF_TRUE -.. opcode:: JUMP_IF_FALSE + JUMP_IF_FALSE Conditional jumps which do not impact the stack. Replaced by the sequence ``COPY 1``, ``TO_BOOL``, ``POP_JUMP_IF_TRUE/FALSE``. @@ -1970,12 +1991,6 @@ but are replaced by real opcodes or removed before bytecode is generated. This opcode is now a pseudo-instruction. -.. opcode:: LOAD_METHOD - - Optimized unbound method lookup. Emitted as a ``LOAD_ATTR`` opcode - with a flag set in the arg. - - .. _opcode_collections: Opcode collections diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index 02b73ccd3f3..df3de8f622a 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -1123,7 +1123,7 @@ from text files and modules with doctests: The global ``__file__`` is added to the globals provided to doctests loaded from a text file using :func:`DocFileSuite`. - .. versionchanged:: next + .. versionchanged:: 3.15 Run each example as a :ref:`subtest `. @@ -1164,7 +1164,7 @@ from text files and modules with doctests: :func:`DocTestSuite` returns an empty :class:`unittest.TestSuite` if *module* contains no docstrings instead of raising :exc:`ValueError`. - .. versionchanged:: next + .. versionchanged:: 3.15 Run each example as a :ref:`subtest `. Under the covers, :func:`DocTestSuite` creates a :class:`unittest.TestSuite` out @@ -1564,7 +1564,7 @@ DocTestRunner objects containing *example*. *out* is the output function that was passed to :meth:`DocTestRunner.run`. - .. versionadded:: next + .. versionadded:: 3.15 .. method:: report_start(out, test, example) diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index 7f8044932fa..ff8b601fe3d 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -294,7 +294,7 @@ variant, :attr:`~.BaseHeader.max_count` is set to 1. ``inline`` and ``attachment`` are the only valid values in common use. -.. class:: ContentTransferEncoding +.. class:: ContentTransferEncodingHeader Handles the :mailheader:`Content-Transfer-Encoding` header. diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index fa102c4a080..32b92c01570 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -30,6 +30,8 @@ when creating a virtual environment) or after explicitly uninstalling needed to bootstrap ``pip`` are included as internal parts of the package. +.. include:: ../includes/optional-module.rst + .. seealso:: :ref:`installing-index` @@ -40,7 +42,9 @@ when creating a virtual environment) or after explicitly uninstalling .. include:: ../includes/wasm-mobile-notavail.rst -Command line interface +.. _ensurepip-cli: + +Command-line interface ---------------------- .. program:: ensurepip diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 8875669ffcc..a8a7e671aad 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -315,6 +315,7 @@ Data Types Returns ``['__class__', '__doc__', '__module__', 'name', 'value']`` and any public methods defined on *self.__class__*:: + >>> from enum import Enum >>> from datetime import date >>> class Weekday(Enum): ... MONDAY = 1 @@ -341,7 +342,7 @@ Data Types A *staticmethod* that is used to determine the next value returned by :class:`auto`:: - >>> from enum import auto + >>> from enum import auto, Enum >>> class PowersOfThree(Enum): ... @staticmethod ... def _generate_next_value_(name, start, count, last_values): @@ -373,7 +374,7 @@ Data Types A *classmethod* for looking up values not found in *cls*. By default it does nothing, but can be overridden to implement custom search behavior:: - >>> from enum import StrEnum + >>> from enum import auto, StrEnum >>> class Build(StrEnum): ... DEBUG = auto() ... OPTIMIZED = auto() @@ -412,6 +413,7 @@ Data Types Returns the string used for *repr()* calls. By default, returns the *Enum* name, member name, and value, but can be overridden:: + >>> from enum import auto, Enum >>> class OtherStyle(Enum): ... ALTERNATE = auto() ... OTHER = auto() @@ -428,6 +430,7 @@ Data Types Returns the string used for *str()* calls. By default, returns the *Enum* name and member name, but can be overridden:: + >>> from enum import auto, Enum >>> class OtherStyle(Enum): ... ALTERNATE = auto() ... OTHER = auto() @@ -443,6 +446,7 @@ Data Types Returns the string used for *format()* and *f-string* calls. By default, returns :meth:`__str__` return value, but can be overridden:: + >>> from enum import auto, Enum >>> class OtherStyle(Enum): ... ALTERNATE = auto() ... OTHER = auto() diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index a73cc2e8a2d..f3aca1ba492 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -450,7 +450,7 @@ The following exceptions are the exceptions that are usually raised. :meth:`threading.Thread.join` can now raise this exception. - .. versionchanged:: next + .. versionchanged:: 3.15 This exception may be raised when acquiring :meth:`threading.Lock` or :meth:`threading.RLock`. @@ -742,8 +742,8 @@ depending on the system error code. .. attribute:: characters_written - An integer containing the number of characters written to the stream - before it blocked. This attribute is available when using the + An integer containing the number of **bytes** written to the stream + before it blocked. This attribute is available when using the buffered I/O classes from the :mod:`io` module. .. exception:: ChildProcessError @@ -897,6 +897,9 @@ The following exceptions are used as warning categories; see the Base class for warnings about dubious syntax. + This warning is typically emitted when compiling Python source code, and usually won't be reported + when running already compiled code. + .. exception:: RuntimeWarning @@ -975,6 +978,12 @@ their subgroups based on the types of the contained exceptions. raises a :exc:`TypeError` if any contained exception is not an :exc:`Exception` subclass. + .. impl-detail:: + + The ``excs`` parameter may be any sequence, but lists and tuples are + specifically processed more efficiently here. For optimal performance, + pass a tuple as ``excs``. + .. attribute:: message The ``msg`` argument to the constructor. This is a read-only attribute. diff --git a/Doc/library/fcntl.rst b/Doc/library/fcntl.rst index 5c078df44ff..f57fcdf0bcf 100644 --- a/Doc/library/fcntl.rst +++ b/Doc/library/fcntl.rst @@ -125,7 +125,7 @@ The module defines the following functions: Add support of arbitrary :term:`bytes-like objects `, not only :class:`bytes`. - .. versionchanged:: next + .. versionchanged:: 3.15 The size of bytes-like objects is no longer limited to 1024 bytes. @@ -187,7 +187,7 @@ The module defines the following functions: The GIL is always released during a system call. System calls failing with EINTR are automatically retried. - .. versionchanged:: next + .. versionchanged:: 3.15 The size of not mutated bytes-like objects is no longer limited to 1024 bytes. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 61799e303a1..7635e652965 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -292,7 +292,9 @@ are always available. They are listed here in alphabetical order. :func:`property`. -.. function:: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) +.. function:: compile(source, filename, mode, flags=0, \ + dont_inherit=False, optimize=-1, \ + *, module=None) Compile the *source* into a code or AST object. Code objects can be executed by :func:`exec` or :func:`eval`. *source* can either be a normal string, a @@ -334,8 +336,12 @@ are always available. They are listed here in alphabetical order. ``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false) or ``2`` (docstrings are removed too). - This function raises :exc:`SyntaxError` if the compiled source is invalid, - and :exc:`ValueError` if the source contains null bytes. + The optional argument *module* specifies the module name. + It is needed to unambiguous :ref:`filter ` syntax warnings + by module name. + + This function raises :exc:`SyntaxError` or :exc:`ValueError` if the compiled + source is invalid. If you want to parse Python code into its AST representation, see :func:`ast.parse`. @@ -371,6 +377,9 @@ are always available. They are listed here in alphabetical order. ``ast.PyCF_ALLOW_TOP_LEVEL_AWAIT`` can now be passed in flags to enable support for top-level ``await``, ``async for``, and ``async with``. + .. versionadded:: 3.15 + Added the *module* parameter. + .. class:: complex(number=0, /) complex(string, /) @@ -517,7 +526,7 @@ are always available. They are listed here in alphabetical order. >>> dir() # show the names in the module namespace # doctest: +SKIP ['__builtins__', '__name__', 'struct'] >>> dir(struct) # show the names in the struct module # doctest: +SKIP - ['Struct', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', + ['Struct', '__all__', '__builtins__', '__doc__', '__file__', '__initializing__', '__loader__', '__name__', '__package__', '_clearcache', 'calcsize', 'error', 'pack', 'pack_into', 'unpack', 'unpack_from'] @@ -597,16 +606,16 @@ are always available. They are listed here in alphabetical order. This function executes arbitrary code. Calling it with user-supplied input may lead to security vulnerabilities. - The *expression* argument is parsed and evaluated as a Python expression + The *source* argument is parsed and evaluated as a Python expression (technically speaking, a condition list) using the *globals* and *locals* mappings as global and local namespace. If the *globals* dictionary is present and does not contain a value for the key ``__builtins__``, a reference to the dictionary of the built-in module :mod:`builtins` is - inserted under that key before *expression* is parsed. That way you can + inserted under that key before *source* is parsed. That way you can control what builtins are available to the executed code by inserting your own ``__builtins__`` dictionary into *globals* before passing it to :func:`eval`. If the *locals* mapping is omitted it defaults to the - *globals* dictionary. If both mappings are omitted, the expression is + *globals* dictionary. If both mappings are omitted, the source is executed with the *globals* and *locals* in the environment where :func:`eval` is called. Note, *eval()* will only have access to the :term:`nested scopes ` (non-locals) in the enclosing @@ -1859,7 +1868,7 @@ are always available. They are listed here in alphabetical order. the same data with other ordering tools such as :func:`max` that rely on a different underlying method. Implementing all six comparisons also helps avoid confusion for mixed type comparisons which can call - reflected the :meth:`~object.__gt__` method. + the reflected :meth:`~object.__gt__` method. For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index beec9b942af..221c0712c7c 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -42,11 +42,11 @@ The :mod:`functools` module defines the following functions: def factorial(n): return n * factorial(n-1) if n else 1 - >>> factorial(10) # no previously cached result, makes 11 recursive calls + >>> factorial(10) # no previously cached result, makes 11 recursive calls 3628800 - >>> factorial(5) # just looks up cached value result + >>> factorial(5) # no new calls, just returns the cached result 120 - >>> factorial(12) # makes two new recursive calls, the other 10 are cached + >>> factorial(12) # two new recursive calls, factorial(10) is cached 479001600 The cache is threadsafe so that the wrapped function can be used in @@ -57,6 +57,10 @@ The :mod:`functools` module defines the following functions: another thread makes an additional call before the initial call has been completed and cached. + Call-once behavior is not guaranteed because locks are not held during the + function call. Potentially another call with the same arguments could + occur while the first call is still running. + .. versionadded:: 3.9 @@ -190,7 +194,7 @@ The :mod:`functools` module defines the following functions: Note, type specificity applies only to the function's immediate arguments rather than their contents. The scalar arguments, ``Decimal(42)`` and - ``Fraction(42)`` are be treated as distinct calls with distinct results. + ``Fraction(42)`` are treated as distinct calls with distinct results. In contrast, the tuple arguments ``('answer', Decimal(42))`` and ``('answer', Fraction(42))`` are treated as equivalent. @@ -672,7 +676,7 @@ The :mod:`functools` module defines the following functions: dispatch>` :term:`generic function`. To define a generic method, decorate it with the ``@singledispatchmethod`` - decorator. When defining a function using ``@singledispatchmethod``, note + decorator. When defining a method using ``@singledispatchmethod``, note that the dispatch happens on the type of the first non-*self* or non-*cls* argument:: @@ -690,7 +694,7 @@ The :mod:`functools` module defines the following functions: return not arg ``@singledispatchmethod`` supports nesting with other decorators such as - :func:`@classmethod`. Note that to allow for + :deco:`classmethod`. Note that to allow for ``dispatcher.register``, ``singledispatchmethod`` must be the *outer most* decorator. Here is the ``Negator`` class with the ``neg`` methods bound to the class, rather than an instance of the class:: @@ -712,11 +716,13 @@ The :mod:`functools` module defines the following functions: return not arg The same pattern can be used for other similar decorators: - :func:`@staticmethod`, - :func:`@abstractmethod`, and others. + :deco:`staticmethod`, :deco:`~abc.abstractmethod`, and others. .. versionadded:: 3.8 + .. versionchanged:: 3.15 + Added support of non-:term:`descriptor` callables. + .. function:: update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 2ef5c4b35a2..0e041b5395e 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -108,10 +108,19 @@ The :mod:`gc` module provides the following functions: * ``uncollectable`` is the total number of objects which were found to be uncollectable (and were therefore moved to the :data:`garbage` - list) inside this generation. + list) inside this generation; + + * ``candidates`` is the total number of objects in this generation which were + considered for collection and traversed; + + * ``duration`` is the total time in seconds spent in collections for this + generation. .. versionadded:: 3.4 + .. versionchanged:: 3.15 + Add ``duration`` and ``candidates``. + .. function:: set_threshold(threshold0, [threshold1, [threshold2]]) @@ -313,6 +322,12 @@ values but should not rebind them): "uncollectable": When *phase* is "stop", the number of objects that could not be collected and were put in :data:`garbage`. + "candidates": When *phase* is "stop", the total number of objects in this + generation which were considered for collection and traversed. + + "duration": When *phase* is "stop", the time in seconds spent in the + collection. + Applications can add their own callbacks to this list. The primary use cases are: @@ -325,6 +340,9 @@ values but should not rebind them): .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Add "duration" and "candidates". + The following constants are provided for use with :func:`set_debug`: diff --git a/Doc/library/getpass.rst b/Doc/library/getpass.rst index 0fb0fc88683..a0c0c6dee2d 100644 --- a/Doc/library/getpass.rst +++ b/Doc/library/getpass.rst @@ -27,9 +27,9 @@ The :mod:`getpass` module provides two functions: The *echo_char* argument controls how user input is displayed while typing. If *echo_char* is ``None`` (default), input remains hidden. Otherwise, - *echo_char* must be a printable ASCII string and each typed character - is replaced by it. For example, ``echo_char='*'`` will display - asterisks instead of the actual input. + *echo_char* must be a single printable ASCII character and each + typed character is replaced by it. For example, ``echo_char='*'`` will + display asterisks instead of the actual input. If echo free input is unavailable getpass() falls back to printing a warning message to *stream* and reading from ``sys.stdin`` and @@ -39,6 +39,14 @@ The :mod:`getpass` module provides two functions: If you call getpass from within IDLE, the input may be done in the terminal you launched IDLE from rather than the idle window itself. + .. note:: + On Unix systems, when *echo_char* is set, the terminal will be + configured to operate in + :manpage:`noncanonical mode `. + In particular, this means that line editing shortcuts such as + :kbd:`Ctrl+U` will not work and may insert unexpected characters into + the input. + .. versionchanged:: 3.14 Added the *echo_char* parameter for keyboard feedback. diff --git a/Doc/library/glob.rst b/Doc/library/glob.rst index 59ad1b07f27..52c44928153 100644 --- a/Doc/library/glob.rst +++ b/Doc/library/glob.rst @@ -18,23 +18,27 @@ single: - (minus); in glob-style wildcards single: . (dot); in glob-style wildcards -The :mod:`glob` module finds all the pathnames matching a specified pattern -according to the rules used by the Unix shell, although results are returned in -arbitrary order. No tilde expansion is done, but ``*``, ``?``, and character +The :mod:`!glob` module finds pathnames +using pattern matching rules similar to the Unix shell. +No tilde expansion is done, but ``*``, ``?``, and character ranges expressed with ``[]`` will be correctly matched. This is done by using the :func:`os.scandir` and :func:`fnmatch.fnmatch` functions in concert, and not by actually invoking a subshell. -Note that files beginning with a dot (``.``) can only be matched by +.. note:: + The pathnames are returned in no particular order. If you need a specific + order, sort the results. + +Files beginning with a dot (``.``) can only be matched by patterns that also start with a dot, unlike :func:`fnmatch.fnmatch` or :func:`pathlib.Path.glob`. -(For tilde and shell variable expansion, use :func:`os.path.expanduser` and -:func:`os.path.expandvars`.) +For tilde and shell variable expansion, use :func:`os.path.expanduser` and +:func:`os.path.expandvars`. For a literal match, wrap the meta-characters in brackets. For example, ``'[?]'`` matches the character ``'?'``. -The :mod:`glob` module defines the following functions: +The :mod:`!glob` module defines the following functions: .. function:: glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, \ @@ -51,7 +55,7 @@ The :mod:`glob` module defines the following functions: If *root_dir* is not ``None``, it should be a :term:`path-like object` specifying the root directory for searching. It has the same effect on - :func:`glob` as changing the current directory before calling it. If + :func:`!glob` as changing the current directory before calling it. If *pathname* is relative, the result will contain paths relative to *root_dir*. diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index c59014a6f5b..d23c0741ddb 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -11,6 +11,8 @@ This module provides a simple interface to compress and decompress files just like the GNU programs :program:`gzip` and :program:`gunzip` would. +.. include:: ../includes/optional-module.rst + The data compression is provided by the :mod:`zlib` module. The :mod:`gzip` module provides the :class:`GzipFile` class, as well as the @@ -59,7 +61,7 @@ The module defines the following items: .. versionchanged:: 3.6 Accepts a :term:`path-like object`. - .. versionchanged:: next + .. versionchanged:: 3.15 The default compression level was reduced to 6 (down from 9). It is the default level used by most compression tools and a better tradeoff between speed and performance. @@ -186,7 +188,7 @@ The module defines the following items: Remove the ``filename`` attribute, use the :attr:`~GzipFile.name` attribute instead. - .. versionchanged:: next + .. versionchanged:: 3.15 The default compression level was reduced to 6 (down from 9). It is the default level used by most compression tools and a better tradeoff between speed and performance. @@ -216,7 +218,7 @@ The module defines the following items: The *mtime* parameter now defaults to 0 for reproducible output. For the previous behaviour of using the current time, pass ``None`` to *mtime*. - .. versionchanged:: next + .. versionchanged:: 3.15 The default compression level was reduced to 6 (down from 9). It is the default level used by most compression tools and a better tradeoff between speed and performance. @@ -281,7 +283,7 @@ Example of how to GZIP compress a binary string:: .. _gzip-cli: -Command Line Interface +Command-line interface ---------------------- The :mod:`gzip` module provides a simple command line interface to compress or @@ -294,7 +296,7 @@ Once executed the :mod:`gzip` module keeps the input file(s). Add a new command line interface with a usage. By default, when you will execute the CLI, the default compression level is 6. -Command line options +Command-line options ^^^^^^^^^^^^^^^^^^^^ .. option:: file diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 8bba6700930..b21ecdaede6 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -310,7 +310,7 @@ a file or file-like object. .. versionadded:: 3.11 .. versionchanged:: 3.14 - Now raises a :exc:`BlockingIOError` if the file is opened in blocking + Now raises a :exc:`BlockingIOError` if the file is opened in non-blocking mode. Previously, spurious null bytes were added to the digest. diff --git a/Doc/library/heapq.rst b/Doc/library/heapq.rst index 95ef72469b1..5049262306a 100644 --- a/Doc/library/heapq.rst +++ b/Doc/library/heapq.rst @@ -58,6 +58,11 @@ functions, respectively. The following functions are provided for min-heaps: +.. function:: heapify(x) + + Transform list *x* into a min-heap, in-place, in linear time. + + .. function:: heappush(heap, item) Push the value *item* onto the *heap*, maintaining the min-heap invariant. @@ -77,11 +82,6 @@ The following functions are provided for min-heaps: followed by a separate call to :func:`heappop`. -.. function:: heapify(x) - - Transform list *x* into a min-heap, in-place, in linear time. - - .. function:: heapreplace(heap, item) Pop and return the smallest item from the *heap*, and also push the new *item*. diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst index 57076c38086..d5608bd7543 100644 --- a/Doc/library/hmac.rst +++ b/Doc/library/hmac.rst @@ -50,7 +50,9 @@ cannot be used with HMAC. .. versionadded:: 3.7 -An HMAC object has the following methods: +.. class:: HMAC + + An HMAC object has the following methods: .. method:: HMAC.update(msg) diff --git a/Doc/library/html.parser.rst b/Doc/library/html.parser.rst index dd67fc34e85..341a8337ba2 100644 --- a/Doc/library/html.parser.rst +++ b/Doc/library/html.parser.rst @@ -15,14 +15,18 @@ This module defines a class :class:`HTMLParser` which serves as the basis for parsing text files formatted in HTML (HyperText Mark-up Language) and XHTML. -.. class:: HTMLParser(*, convert_charrefs=True) +.. class:: HTMLParser(*, convert_charrefs=True, scripting=False) Create a parser instance able to parse invalid markup. - If *convert_charrefs* is ``True`` (the default), all character - references (except the ones in ``script``/``style`` elements) are + If *convert_charrefs* is true (the default), all character + references (except the ones in elements like ``script`` and ``style``) are automatically converted to the corresponding Unicode characters. + If *scripting* is false (the default), the content of the ``noscript`` + element is parsed normally; if it's true, it's returned as is without + being parsed. + An :class:`.HTMLParser` instance is fed HTML data and calls handler methods when start tags, end tags, text, comments, and other markup elements are encountered. The user should subclass :class:`.HTMLParser` and override its @@ -37,6 +41,9 @@ parsing text files formatted in HTML (HyperText Mark-up Language) and XHTML. .. versionchanged:: 3.5 The default value for argument *convert_charrefs* is now ``True``. + .. versionchanged:: 3.14.1 + Added the *scripting* parameter. + Example HTML Parser Application ------------------------------- @@ -161,15 +168,15 @@ implementations do nothing (except for :meth:`~HTMLParser.handle_startendtag`): .. method:: HTMLParser.handle_data(data) This method is called to process arbitrary data (e.g. text nodes and the - content of ```` and ````). + content of elements like ``script`` and ``style``). .. method:: HTMLParser.handle_entityref(name) This method is called to process a named character reference of the form ``&name;`` (e.g. ``>``), where *name* is a general entity reference - (e.g. ``'gt'``). This method is never called if *convert_charrefs* is - ``True``. + (e.g. ``'gt'``). + This method is only called if *convert_charrefs* is false. .. method:: HTMLParser.handle_charref(name) @@ -177,8 +184,8 @@ implementations do nothing (except for :meth:`~HTMLParser.handle_startendtag`): This method is called to process decimal and hexadecimal numeric character references of the form :samp:`&#{NNN};` and :samp:`&#x{NNN};`. For example, the decimal equivalent for ``>`` is ``>``, whereas the hexadecimal is ``>``; - in this case the method will receive ``'62'`` or ``'x3E'``. This method - is never called if *convert_charrefs* is ``True``. + in this case the method will receive ``'62'`` or ``'x3E'``. + This method is only called if *convert_charrefs* is false. .. method:: HTMLParser.handle_comment(data) @@ -292,8 +299,8 @@ Parsing an element with a few attributes and a title: Data : Python End tag : h1 -The content of ``script`` and ``style`` elements is returned as is, without -further parsing: +The content of elements like ``script`` and ``style`` is returned as is, +without further parsing: .. doctest:: @@ -304,10 +311,10 @@ further parsing: End tag : style >>> parser.feed('') + ... 'alert("hello! ☺");') Start tag: script attr: ('type', 'text/javascript') - Data : alert("hello!"); + Data : alert("hello! ☺"); End tag : script Parsing comments: @@ -336,7 +343,7 @@ correct char (note: these 3 references are all equivalent to ``'>'``): Feeding incomplete chunks to :meth:`~HTMLParser.feed` works, but :meth:`~HTMLParser.handle_data` might be called more than once -(unless *convert_charrefs* is set to ``True``): +if *convert_charrefs* is false: .. doctest:: diff --git a/Doc/library/html.rst b/Doc/library/html.rst index 9aa39ba9a42..65c49a4107a 100644 --- a/Doc/library/html.rst +++ b/Doc/library/html.rst @@ -14,9 +14,12 @@ This module defines utilities to manipulate HTML. Convert the characters ``&``, ``<`` and ``>`` in string *s* to HTML-safe sequences. Use this if you need to display text that might contain such - characters in HTML. If the optional flag *quote* is true, the characters - (``"``) and (``'``) are also translated; this helps for inclusion in an HTML - attribute value delimited by quotes, as in ````. + characters in HTML. If the optional flag *quote* is true (the default), the + characters (``"``) and (``'``) are also translated; this helps for inclusion + in an HTML attribute value delimited by quotes, as in ````. + If *quote* is set to false, the characters (``"``) and (``'``) are not + translated. + .. versionadded:: 3.2 diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 07f5ebf57c9..ddf3d40d221 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -68,7 +68,7 @@ The module provides the following classes: .. versionchanged:: 3.7 *blocksize* parameter was added. - .. versionchanged:: next + .. versionchanged:: 3.15 *max_response_headers* parameter was added. @@ -114,7 +114,7 @@ The module provides the following classes: The deprecated *key_file*, *cert_file* and *check_hostname* parameters have been removed. - .. versionchanged:: next + .. versionchanged:: 3.15 *max_response_headers* parameter was added. @@ -133,7 +133,7 @@ This module provides the following function: Parse the headers from a file pointer *fp* representing a HTTP request/response. The file has to be a :class:`~io.BufferedIOBase` reader - (i.e. not text) and must provide a valid :rfc:`2822` style header. + (i.e. not text) and must provide a valid :rfc:`5322` style header. This function returns an instance of :class:`http.client.HTTPMessage` that holds the header fields, but no payload @@ -319,6 +319,12 @@ HTTPConnection Objects :class:`str` or bytes-like object that is not also a file as the body representation. + .. note:: + + Note that you must have read the whole response or call :meth:`close` + if :meth:`getresponse` raised an non-:exc:`ConnectionError` exception + before you can send a new request to the server. + .. versionchanged:: 3.2 *body* can now be an iterable. @@ -334,16 +340,15 @@ HTTPConnection Objects Should be called after a request is sent to get the response from the server. Returns an :class:`HTTPResponse` instance. - .. note:: - - Note that you must have read the whole response before you can send a new - request to the server. - .. versionchanged:: 3.5 If a :exc:`ConnectionError` or subclass is raised, the :class:`HTTPConnection` object will be ready to reconnect when a new request is sent. + Note that this does not apply to :exc:`OSError`\s raised by the underlying + socket. Instead the caller is responsible to call :meth:`close` on the + existing connection. + .. method:: HTTPConnection.set_debuglevel(level) @@ -429,7 +434,7 @@ HTTPConnection Objects The maximum number of allowed response headers to help prevent denial-of-service attacks. By default, the maximum number of allowed headers is set to 100. - .. versionadded:: next + .. versionadded:: 3.15 As an alternative to using the :meth:`~HTTPConnection.request` method described above, you can diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 251aea891c3..fcb0069b760 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -12,7 +12,7 @@ -------------- The :mod:`http.cookiejar` module defines classes for automatic handling of HTTP -cookies. It is useful for accessing web sites that require small pieces of data +cookies. It is useful for accessing websites that require small pieces of data -- :dfn:`cookies` -- to be set on the client machine by an HTTP response from a web server, and then returned to the server in later HTTP requests. diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst index 9e7648ef6d8..88e978d7f5e 100644 --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -30,7 +30,7 @@ in a cookie name (as :attr:`~Morsel.key`). .. versionchanged:: 3.3 Allowed '``:``' as a valid cookie name character. -.. versionchanged:: next +.. versionchanged:: 3.15 Allowed '``"``' as a valid cookie value character. .. note:: diff --git a/Doc/library/http.rst b/Doc/library/http.rst index ce3fb9f8120..b0bdfc65e45 100644 --- a/Doc/library/http.rst +++ b/Doc/library/http.rst @@ -139,7 +139,8 @@ equal to the constant name (i.e. ``http.HTTPStatus.OK`` is also available as .. versionchanged:: 3.13 Implemented RFC9110 naming for status constants. Old constant names are preserved for - backwards compatibility. + backwards compatibility: ``413 REQUEST_ENTITY_TOO_LARGE``, ``414 REQUEST_URI_TOO_LONG``, + ``416 REQUESTED_RANGE_NOT_SATISFIABLE`` and ``422 UNPROCESSABLE_ENTITY``. HTTP status category -------------------- diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index 063344e0284..58f09634f95 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -154,7 +154,7 @@ instantiation, of which this module provides three different variants: variable. This instance parses and manages the headers in the HTTP request. The :func:`~http.client.parse_headers` function from :mod:`http.client` is used to parse the headers and it requires that the - HTTP request provide a valid :rfc:`2822` style header. + HTTP request provide a valid :rfc:`5322` style header. .. attribute:: rfile diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index fabea611e0e..a16f46ef812 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -13,7 +13,7 @@ IDLE --- Python editor and shell single: Integrated Development Environment .. - Remember to update Lib/idlelib/help.html with idlelib.help.copy_source() when modifying this file. + Remember to update Lib/idlelib/help.html with idlelib.help.copy_strip() when modifying this file. -------------- @@ -37,6 +37,10 @@ IDLE has the following features: * configuration, browsers, and other dialogs +The IDLE application is implemented in the :mod:`idlelib` package. + +.. include:: ../includes/optional-module.rst + Menus ----- @@ -88,7 +92,7 @@ Save Save As... Save the current window with a Save As dialog. The file saved becomes the - new associated file for the window. (If your file namager is set to hide + new associated file for the window. (If your file manager is set to hide extensions, the current extension will be omitted in the file name box. If the new filename has no '.', '.py' and '.txt' will be added for Python and text files, except that on macOS Aqua,'.py' is added for all files.) @@ -204,9 +208,9 @@ New Indent Width Open a dialog to change indent width. The accepted default by the Python community is 4 spaces. -Strip Trailing Chitespace +Strip Trailing Whitespace Remove trailing space and other whitespace characters after the last - non-whitespace character of a line by applying str.rstrip to each line, + non-whitespace character of a line by applying :meth:`str.rstrip` to each line, including lines within multiline strings. Except for Shell windows, remove extra newlines at the end of the file. @@ -657,7 +661,9 @@ looked for in the user's home directory. Statements in this file will be executed in the Tk namespace, so this file is not useful for importing functions to be used from IDLE's Python shell. -Command line usage +.. _idlelib-cli: + +Command-line usage ^^^^^^^^^^^^^^^^^^ .. program:: idle diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 2a12a0ca8e9..0b0537d3bbd 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -413,7 +413,7 @@ An :class:`IMAP4` instance has the following methods: the password. Will only work if the server ``CAPABILITY`` response includes the phrase ``AUTH=CRAM-MD5``. - .. versionchanged:: next + .. versionchanged:: 3.15 An :exc:`IMAP4.error` is raised if MD5 support is not available. diff --git a/Doc/library/importlib.resources.rst b/Doc/library/importlib.resources.rst index 7a11f4fe069..20297f9fe30 100644 --- a/Doc/library/importlib.resources.rst +++ b/Doc/library/importlib.resources.rst @@ -73,12 +73,15 @@ for example, a package and its resources can be imported from a zip file using .. versionadded:: 3.9 .. versionchanged:: 3.12 - *package* parameter was renamed to *anchor*. *anchor* can now - be a non-package module and if omitted will default to the caller's - module. *package* is still accepted for compatibility but will raise - a :exc:`DeprecationWarning`. Consider passing the anchor positionally or - using ``importlib_resources >= 5.10`` for a compatible interface - on older Pythons. + *package* parameter was renamed to *anchor*. + *package* was still accepted, but deprecated. + + .. versionchanged:: 3.15 + *package* parameter was fully removed. *anchor* can now be a + non-package module and if omitted will default to the caller's module. + *package* is no longer accepted since Python 3.15. Consider passing the + anchor positionally or using ``importlib_resources >= 5.10`` for a + compatible interface on older Pythons. .. function:: as_file(traversable) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index ddf503af82d..e4b5b6831fa 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -124,6 +124,10 @@ Functions need to call :func:`invalidate_caches` in order for the new module to be noticed by the import system. + If the module cannot be imported, :func:`import_module` will raise + :exc:`ImportError` or an appropriate subclass like + :exc:`ModuleNotFoundError`. + .. versionchanged:: 3.3 Parent packages are automatically imported. @@ -206,6 +210,12 @@ Functions :exc:`ModuleNotFoundError` is raised when the module being reloaded lacks a :class:`~importlib.machinery.ModuleSpec`. + .. versionchanged:: 3.15 + If *module* is a lazy module that has not yet been materialized (i.e., + loaded via :class:`importlib.util.LazyLoader` and not yet accessed), + calling :func:`reload` is a no-op and returns the module unchanged. + This prevents the reload from unintentionally triggering the lazy load. + .. warning:: This function is not thread-safe. Calling it from multiple threads can result in unexpected behavior. It's recommended to use the :class:`threading.Lock` @@ -316,6 +326,9 @@ ABC hierarchy:: .. versionchanged:: 3.7 Introduced the optional :meth:`get_resource_reader` method. + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. method:: create_module(spec) A method that returns the module object to use when @@ -340,47 +353,6 @@ ABC hierarchy:: .. versionchanged:: 3.6 :meth:`create_module` must also be defined. - .. method:: load_module(fullname) - - A legacy method for loading a module. If the module cannot be - loaded, :exc:`ImportError` is raised, otherwise the loaded module is - returned. - - If the requested module already exists in :data:`sys.modules`, that - module should be used and reloaded. - Otherwise the loader should create a new module and insert it into - :data:`sys.modules` before any loading begins, to prevent recursion - from the import. If the loader inserted a module and the load fails, it - must be removed by the loader from :data:`sys.modules`; modules already - in :data:`sys.modules` before the loader began execution should be left - alone. - - The loader should set several attributes on the module - (note that some of these attributes can change when a module is - reloaded): - - - :attr:`module.__name__` - - :attr:`module.__file__` - - :attr:`module.__cached__` *(deprecated)* - - :attr:`module.__path__` - - :attr:`module.__package__` *(deprecated)* - - :attr:`module.__loader__` *(deprecated)* - - When :meth:`exec_module` is available then backwards-compatible - functionality is provided. - - .. versionchanged:: 3.4 - Raise :exc:`ImportError` when called instead of - :exc:`NotImplementedError`. Functionality provided when - :meth:`exec_module` is available. - - .. deprecated-removed:: 3.4 3.15 - The recommended API for loading a module is :meth:`exec_module` - (and :meth:`create_module`). Loaders should implement it instead of - :meth:`load_module`. The import machinery takes care of all the - other responsibilities of :meth:`load_module` when - :meth:`exec_module` is implemented. - .. class:: ResourceLoader @@ -455,7 +427,7 @@ ABC hierarchy:: .. versionchanged:: 3.4 Raises :exc:`ImportError` instead of :exc:`NotImplementedError`. - .. staticmethod:: source_to_code(data, path='') + .. staticmethod:: source_to_code(data, path='', fullname=None) Create a code object from Python source. @@ -467,24 +439,25 @@ ABC hierarchy:: With the subsequent code object one can execute it in a module by running ``exec(code, module.__dict__)``. + The optional argument *fullname* specifies the module name. + It is needed to unambiguous :ref:`filter ` syntax + warnings by module name. + .. versionadded:: 3.4 .. versionchanged:: 3.5 Made the method static. + .. versionadded:: 3.15 + Added the *fullname* parameter. + + .. method:: exec_module(module) Implementation of :meth:`Loader.exec_module`. .. versionadded:: 3.4 - .. method:: load_module(fullname) - - Implementation of :meth:`Loader.load_module`. - - .. deprecated-removed:: 3.4 3.15 - use :meth:`exec_module` instead. - .. class:: ExecutionLoader @@ -518,6 +491,9 @@ ABC hierarchy:: .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. attribute:: name The name of the module the loader can handle. @@ -526,13 +502,6 @@ ABC hierarchy:: Path to the file of the module. - .. method:: load_module(fullname) - - Calls super's ``load_module()``. - - .. deprecated-removed:: 3.4 3.15 - Use :meth:`Loader.exec_module` instead. - .. method:: get_filename(fullname) :abstractmethod: @@ -564,6 +533,9 @@ ABC hierarchy:: optimization to speed up loading by removing the parsing step of Python's compiler, and so no bytecode-specific API is exposed. + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. method:: path_stats(path) Optional abstract method which returns a :class:`dict` containing @@ -617,13 +589,6 @@ ABC hierarchy:: .. versionadded:: 3.4 - .. method:: load_module(fullname) - - Concrete implementation of :meth:`Loader.load_module`. - - .. deprecated-removed:: 3.4 3.15 - Use :meth:`exec_module` instead. - .. method:: get_source(fullname) Concrete implementation of :meth:`InspectLoader.get_source`. @@ -1009,6 +974,36 @@ find and load modules. :exc:`ImportError` is raised. +.. class:: NamespacePath(name, path, path_finder) + + Represents a :term:`namespace package`'s path (:attr:`module.__path__`). + + When its ``__path__`` value is accessed it will be recomputed if necessary. + This keeps it in-sync with the global state (:attr:`sys.modules`). + + The *name* argument is the name of the namespace module. + + The *path* argument is the initial path value. + + The *path_finder* argument is the callable used to recompute the path value. + The callable has the same signature as :meth:`importlib.abc.MetaPathFinder.find_spec`. + + When the parent's :attr:`module.__path__` attribute is updated, the path + value is recomputed. + + If the parent module is missing from :data:`sys.modules`, then + :exc:`ModuleNotFoundError` will be raised. + + For top-level modules, the parent module's path is :data:`sys.path`. + + .. note:: + + :meth:`PathFinder.invalidate_caches` invalidates :class:`NamespacePath`, + forcing the path value to be recomputed next time it is accessed. + + .. versionadded:: 3.15 + + .. class:: SourceFileLoader(fullname, path) A concrete implementation of :class:`importlib.abc.SourceLoader` by @@ -1017,6 +1012,9 @@ find and load modules. .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. attribute:: name The name of the module that this loader will handle. @@ -1037,15 +1035,6 @@ find and load modules. Concrete implementation of :meth:`importlib.abc.SourceLoader.set_data`. - .. method:: load_module(name=None) - - Concrete implementation of :meth:`importlib.abc.Loader.load_module` where - specifying the name of the module to load is optional. - - .. deprecated-removed:: 3.6 3.15 - - Use :meth:`importlib.abc.Loader.exec_module` instead. - .. class:: SourcelessFileLoader(fullname, path) @@ -1059,6 +1048,9 @@ find and load modules. .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. attribute:: name The name of the module the loader will handle. @@ -1080,15 +1072,6 @@ find and load modules. Returns ``None`` as bytecode files have no source when this loader is used. - .. method:: load_module(name=None) - - Concrete implementation of :meth:`importlib.abc.Loader.load_module` where - specifying the name of the module to load is optional. - - .. deprecated-removed:: 3.6 3.15 - - Use :meth:`importlib.abc.Loader.exec_module` instead. - .. class:: ExtensionFileLoader(fullname, path) @@ -1220,8 +1203,7 @@ find and load modules. .. attribute:: cached - The filename of a compiled version of the module's code - (see :attr:`module.__cached__`). + The filename of a compiled version of the module's code. The :term:`finder` should always set this attribute but it may be ``None`` for modules that do not need compiled code stored. @@ -1253,7 +1235,7 @@ find and load modules. To accommodate this requirement, when running on iOS, extension module binaries are *not* packaged as ``.so`` files on ``sys.path``, but as individual standalone frameworks. To discover those frameworks, this loader - is be registered against the ``.fwork`` file extension, with a ``.fwork`` + is registered against the ``.fwork`` file extension, with a ``.fwork`` file acting as a placeholder in the original location of the binary on ``sys.path``. The ``.fwork`` file contains the path of the actual binary in the ``Frameworks`` folder, relative to the app bundle. To allow for @@ -1323,7 +1305,7 @@ an :term:`importer`. .. versionadded:: 3.4 -.. function:: cache_from_source(path, debug_override=None, *, optimization=None) +.. function:: cache_from_source(path, *, optimization=None) Return the :pep:`3147`/:pep:`488` path to the byte-compiled file associated with the source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return @@ -1342,12 +1324,6 @@ an :term:`importer`. ``/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc``. The string representation of *optimization* can only be alphanumeric, else :exc:`ValueError` is raised. - The *debug_override* parameter is deprecated and can be used to override - the system's value for ``__debug__``. A ``True`` value is the equivalent of - setting *optimization* to the empty string. A ``False`` value is the same as - setting *optimization* to ``1``. If both *debug_override* an *optimization* - are not ``None`` then :exc:`TypeError` is raised. - .. versionadded:: 3.4 .. versionchanged:: 3.5 @@ -1357,6 +1333,9 @@ an :term:`importer`. .. versionchanged:: 3.6 Accepts a :term:`path-like object`. + .. versionchanged:: 3.15 + The *debug_override* parameter was removed. + .. function:: source_from_cache(path) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index e8d1176f477..e5abd68f03b 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -253,6 +253,9 @@ attributes (see :ref:`import-mod-attrs` for module attributes): +-----------------+-------------------+---------------------------+ | | gi_running | is the generator running? | +-----------------+-------------------+---------------------------+ +| | gi_suspended | is the generator | +| | | suspended? | ++-----------------+-------------------+---------------------------+ | | gi_code | code | +-----------------+-------------------+---------------------------+ | | gi_yieldfrom | object being iterated by | @@ -616,17 +619,29 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Retrieving source code ---------------------- -.. function:: getdoc(object) +.. function:: getdoc(object, *, inherit_class_doc=True, fallback_to_class_doc=True) Get the documentation string for an object, cleaned up with :func:`cleandoc`. - If the documentation string for an object is not provided and the object is - a class, a method, a property or a descriptor, retrieve the documentation - string from the inheritance hierarchy. + If the documentation string for an object is not provided: + + * if the object is a class and *inherit_class_doc* is true (by default), + retrieve the documentation string from the inheritance hierarchy; + * if the object is a method, a property or a descriptor, retrieve + the documentation string from the inheritance hierarchy; + * otherwise, if *fallback_to_class_doc* is true (by default), retrieve + the documentation string from the class of the object. + Return ``None`` if the documentation string is invalid or missing. .. versionchanged:: 3.5 Documentation strings are now inherited if not overridden. + .. versionchanged:: 3.15 + Added parameters *inherit_class_doc* and *fallback_to_class_doc*. + + Documentation strings on :class:`~functools.cached_property` + objects are now inherited if not overridden. + .. function:: getcomments(object) @@ -1179,7 +1194,7 @@ Classes and functions :func:`signature` in Python 3.5, but that decision has been reversed in order to restore a clearly supported standard interface for single-source Python 2/3 code migrating away from the legacy - :func:`getargspec` API. + :func:`!getargspec` API. .. versionchanged:: 3.7 Python only explicitly guaranteed that it preserved the declaration @@ -1289,6 +1304,11 @@ Classes and functions This is an alias for :func:`annotationlib.get_annotations`; see the documentation of that function for more information. + .. caution:: + + This function may execute arbitrary code contained in annotations. + See :ref:`annotationlib-security` for more information. + .. versionadded:: 3.10 .. versionchanged:: 3.14 @@ -1768,7 +1788,7 @@ Buffer flags .. _inspect-module-cli: -Command Line Interface +Command-line interface ---------------------- The :mod:`inspect` module also provides a basic introspection capability diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 12a5a96a3c5..8b4217c210d 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -183,8 +183,10 @@ Basic Usage :param bool ensure_ascii: If ``True`` (the default), the output is guaranteed to - have all incoming non-ASCII characters escaped. - If ``False``, these characters will be outputted as-is. + have all incoming non-ASCII and non-printable characters escaped. + If ``False``, all characters will be outputted as-is, except for + the characters that must be escaped: quotation mark, reverse solidus, + and the control characters U+0000 through U+001F. :param bool check_circular: If ``False``, the circular reference check for container types is skipped @@ -495,8 +497,10 @@ Encoders and Decoders :class:`bool` or ``None``. If *skipkeys* is true, such items are simply skipped. If *ensure_ascii* is true (the default), the output is guaranteed to - have all incoming non-ASCII characters escaped. If *ensure_ascii* is - false, these characters will be output as-is. + have all incoming non-ASCII and non-printable characters escaped. + If *ensure_ascii* is false, all characters will be output as-is, except for + the characters that must be escaped: quotation mark, reverse solidus, + and the control characters U+0000 through U+001F. If *check_circular* is true (the default), then lists, dicts, and custom encoded objects will be checked for circular references during encoding to @@ -636,7 +640,7 @@ UTF-32, with UTF-8 being the recommended default for maximum interoperability. As permitted, though not required, by the RFC, this module's serializer sets *ensure_ascii=True* by default, thus escaping the output so that the resulting -strings only contain ASCII characters. +strings only contain printable ASCII characters. Other than the *ensure_ascii* parameter, this module is defined strictly in terms of conversion between Python objects and diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 0800b3e5677..ce025670c92 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -48,8 +48,19 @@ The :mod:`locale` module defines the following exception and functions: If *locale* is omitted or ``None``, the current setting for *category* is returned. + Example:: + + >>> import locale + >>> loc = locale.setlocale(locale.LC_ALL) # get current locale + # use German locale; name and availability varies with platform + >>> locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8') + >>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut + >>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale + >>> locale.setlocale(locale.LC_ALL, 'C') # use default (C) locale + >>> locale.setlocale(locale.LC_ALL, loc) # restore saved locale + :func:`setlocale` is not thread-safe on most systems. Applications typically - start with a call of :: + start with a call of:: import locale locale.setlocale(locale.LC_ALL, '') @@ -58,7 +69,7 @@ The :mod:`locale` module defines the following exception and functions: specified in the :envvar:`LANG` environment variable). If the locale is not changed thereafter, using multithreading should not cause problems. - .. versionchanged:: next + .. versionchanged:: 3.15 Support language codes with ``@``-modifiers. @@ -374,7 +385,7 @@ The :mod:`locale` module defines the following exception and functions: determined. The "C" locale is represented as ``(None, None)``. - .. versionchanged:: next + .. versionchanged:: 3.15 ``@``-modifier are no longer silently removed, but included in the language code. @@ -524,8 +535,8 @@ The :mod:`locale` module defines the following exception and functions: SSH connections. Python doesn't internally use locale-dependent character transformation functions - from ``ctype.h``. Instead, an internal ``pyctype.h`` provides locale-independent - equivalents like :c:macro:`!Py_TOLOWER`. + from ``ctype.h``. Instead, ``pyctype.h`` provides locale-independent + equivalents like :c:macro:`Py_TOLOWER`. .. data:: LC_COLLATE @@ -580,18 +591,6 @@ The :mod:`locale` module defines the following exception and functions: :func:`localeconv`. -Example:: - - >>> import locale - >>> loc = locale.getlocale() # get current locale - # use German locale; name might vary with platform - >>> locale.setlocale(locale.LC_ALL, 'de_DE') - >>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut - >>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale - >>> locale.setlocale(locale.LC_ALL, 'C') # use default (C) locale - >>> locale.setlocale(locale.LC_ALL, loc) # restore saved locale - - Background, details, hints, tips and caveats -------------------------------------------- diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index d74ef73ee28..c9cfbdb4126 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -463,6 +463,7 @@ timed intervals. .. method:: getFilesToDelete() Returns a list of filenames which should be deleted as part of rollover. These + are the absolute paths of the oldest backup log files written by the handler. .. method:: shouldRollover(record) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index b3017c1ec70..0cf5b1c0d9b 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -671,8 +671,7 @@ Formatter Objects which is just the logged message. :type fmt: str - :param datefmt: A format string in the given *style* for - the date/time portion of the logged output. + :param datefmt: A format string for the date/time portion of the logged output. If not specified, the default described in :meth:`formatTime` is used. :type datefmt: str @@ -680,7 +679,7 @@ Formatter Objects how the format string will be merged with its data: using one of :ref:`old-string-formatting` (``%``), :meth:`str.format` (``{``) or :class:`string.Template` (``$``). This only applies to - *fmt* and *datefmt* (e.g. ``'%(message)s'`` versus ``'{message}'``), + *fmt* (e.g. ``'%(message)s'`` versus ``'{message}'``), not to the actual log messages passed to the logging methods. However, there are :ref:`other ways ` to use ``{``- and ``$``-formatting for log messages. @@ -1083,12 +1082,13 @@ LoggerAdapter Objects information into logging calls. For a usage example, see the section on :ref:`adding contextual information to your logging output `. -.. class:: LoggerAdapter(logger, extra, merge_extra=False) +.. class:: LoggerAdapter(logger, extra=None, merge_extra=False) Returns an instance of :class:`LoggerAdapter` initialized with an - underlying :class:`Logger` instance, a dict-like object (*extra*), and a - boolean (*merge_extra*) indicating whether or not the *extra* argument of - individual log calls should be merged with the :class:`LoggerAdapter` extra. + underlying :class:`Logger` instance, an optional dict-like object (*extra*), + and an optional boolean (*merge_extra*) indicating whether or not + the *extra* argument of individual log calls should be merged with + the :class:`LoggerAdapter` extra. The default behavior is to ignore the *extra* argument of individual log calls and only use the one of the :class:`LoggerAdapter` instance @@ -1128,9 +1128,13 @@ information into logging calls. For a usage example, see the section on Attribute :attr:`!manager` and method :meth:`!_log` were added, which delegate to the underlying logger and allow adapters to be nested. + .. versionchanged:: 3.10 + + The *extra* argument is now optional. + .. versionchanged:: 3.13 - The *merge_extra* argument was added. + The *merge_extra* parameter was added. Thread Safety diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 69f7cb8d48d..8a4f68f3502 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -23,6 +23,8 @@ module. Note that :class:`LZMAFile` and :class:`bz2.BZ2File` are *not* thread-safe, so if you need to use a single :class:`LZMAFile` instance from multiple threads, it is necessary to protect it with a lock. +.. include:: ../includes/optional-module.rst + .. exception:: LZMAError diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst index e8a96f29ea1..62e289573c0 100644 --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -917,7 +917,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. copied; furthermore, any format-specific information is converted insofar as possible if *message* is a :class:`!Message` instance. If *message* is a string, a byte string, - or a file, it should contain an :rfc:`2822`\ -compliant message, which is read + or a file, it should contain an :rfc:`5322`\ -compliant message, which is read and parsed. Files should be open in binary mode, but text mode files are accepted for backward compatibility. diff --git a/Doc/library/math.integer.rst b/Doc/library/math.integer.rst new file mode 100644 index 00000000000..0068ae2bdd5 --- /dev/null +++ b/Doc/library/math.integer.rst @@ -0,0 +1,85 @@ +:mod:`math.integer` --- integer-specific mathematics functions +============================================================== + +.. module:: math.integer + :synopsis: Integer-specific mathematics functions. + +.. versionadded:: 3.15 + +-------------- + +This module provides access to the mathematical functions defined for integer arguments. +These functions accept integers and objects that implement the +:meth:`~object.__index__` method which is used to convert the object to an integer +number. + +The following functions are provided by this module. All return values are +computed exactly and are integers. + + +.. function:: comb(n, k, /) + + Return the number of ways to choose *k* items from *n* items without repetition + and without order. + + Evaluates to ``n! / (k! * (n - k)!)`` when ``k <= n`` and evaluates + to zero when ``k > n``. + + Also called the binomial coefficient because it is equivalent + to the coefficient of k-th term in polynomial expansion of + ``(1 + x)ⁿ``. + + Raises :exc:`ValueError` if either of the arguments are negative. + + +.. function:: factorial(n, /) + + Return factorial of the nonnegative integer *n*. + + +.. function:: gcd(*integers) + + Return the greatest common divisor of the specified integer arguments. + If any of the arguments is nonzero, then the returned value is the largest + positive integer that is a divisor of all arguments. If all arguments + are zero, then the returned value is ``0``. ``gcd()`` without arguments + returns ``0``. + + +.. function:: isqrt(n, /) + + Return the integer square root of the nonnegative integer *n*. This is the + floor of the exact square root of *n*, or equivalently the greatest integer + *a* such that *a*\ ² |nbsp| ≤ |nbsp| *n*. + + For some applications, it may be more convenient to have the least integer + *a* such that *n* |nbsp| ≤ |nbsp| *a*\ ², or in other words the ceiling of + the exact square root of *n*. For positive *n*, this can be computed using + ``a = 1 + isqrt(n - 1)``. + + + .. |nbsp| unicode:: 0xA0 + :trim: + + +.. function:: lcm(*integers) + + Return the least common multiple of the specified integer arguments. + If all arguments are nonzero, then the returned value is the smallest + positive integer that is a multiple of all arguments. If any of the arguments + is zero, then the returned value is ``0``. ``lcm()`` without arguments + returns ``1``. + + +.. function:: perm(n, k=None, /) + + Return the number of ways to choose *k* items from *n* items + without repetition and with order. + + Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates + to zero when ``k > n``. + + If *k* is not specified or is ``None``, then *k* defaults to *n* + and the function returns ``n!``. + + Raises :exc:`ValueError` if either of the arguments are negative. diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 55f2de07553..d2ff74822f9 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -27,15 +27,6 @@ noted otherwise, all return values are floats. ==================================================== ============================================ -**Number-theoretic functions** --------------------------------------------------------------------------------------------------- -:func:`comb(n, k) ` Number of ways to choose *k* items from *n* items without repetition and without order -:func:`factorial(n) ` *n* factorial -:func:`gcd(*integers) ` Greatest common divisor of the integer arguments -:func:`isqrt(n) ` Integer square root of a nonnegative integer *n* -:func:`lcm(*integers) ` Least common multiple of the integer arguments -:func:`perm(n, k) ` Number of ways to choose *k* items from *n* items without repetition and with order - **Floating point arithmetic** -------------------------------------------------------------------------------------------------- :func:`ceil(x) ` Ceiling of *x*, the smallest integer greater than or equal to *x* @@ -126,92 +117,6 @@ noted otherwise, all return values are floats. ==================================================== ============================================ -Number-theoretic functions --------------------------- - -.. function:: comb(n, k) - - Return the number of ways to choose *k* items from *n* items without repetition - and without order. - - Evaluates to ``n! / (k! * (n - k)!)`` when ``k <= n`` and evaluates - to zero when ``k > n``. - - Also called the binomial coefficient because it is equivalent - to the coefficient of k-th term in polynomial expansion of - ``(1 + x)ⁿ``. - - Raises :exc:`TypeError` if either of the arguments are not integers. - Raises :exc:`ValueError` if either of the arguments are negative. - - .. versionadded:: 3.8 - - -.. function:: factorial(n) - - Return factorial of the nonnegative integer *n*. - - .. versionchanged:: 3.10 - Floats with integral values (like ``5.0``) are no longer accepted. - - -.. function:: gcd(*integers) - - Return the greatest common divisor of the specified integer arguments. - If any of the arguments is nonzero, then the returned value is the largest - positive integer that is a divisor of all arguments. If all arguments - are zero, then the returned value is ``0``. ``gcd()`` without arguments - returns ``0``. - - .. versionadded:: 3.5 - - .. versionchanged:: 3.9 - Added support for an arbitrary number of arguments. Formerly, only two - arguments were supported. - - -.. function:: isqrt(n) - - Return the integer square root of the nonnegative integer *n*. This is the - floor of the exact square root of *n*, or equivalently the greatest integer - *a* such that *a*\ ² |nbsp| ≤ |nbsp| *n*. - - For some applications, it may be more convenient to have the least integer - *a* such that *n* |nbsp| ≤ |nbsp| *a*\ ², or in other words the ceiling of - the exact square root of *n*. For positive *n*, this can be computed using - ``a = 1 + isqrt(n - 1)``. - - .. versionadded:: 3.8 - - -.. function:: lcm(*integers) - - Return the least common multiple of the specified integer arguments. - If all arguments are nonzero, then the returned value is the smallest - positive integer that is a multiple of all arguments. If any of the arguments - is zero, then the returned value is ``0``. ``lcm()`` without arguments - returns ``1``. - - .. versionadded:: 3.9 - - -.. function:: perm(n, k=None) - - Return the number of ways to choose *k* items from *n* items - without repetition and with order. - - Evaluates to ``n! / (n - k)!`` when ``k <= n`` and evaluates - to zero when ``k > n``. - - If *k* is not specified or is ``None``, then *k* defaults to *n* - and the function returns ``n!``. - - Raises :exc:`TypeError` if either of the arguments are not integers. - Raises :exc:`ValueError` if either of the arguments are negative. - - .. versionadded:: 3.8 - - Floating point arithmetic ------------------------- @@ -259,7 +164,7 @@ Floating point arithmetic is, :func:`!fmax` is not required to be sensitive to the sign of such operands (see Annex F of the C11 standard, §F.10.0.3 and §F.10.9.2). - .. versionadded:: next + .. versionadded:: 3.15 .. function:: fmin(x, y) @@ -271,7 +176,7 @@ Floating point arithmetic is, :func:`!fmin` is not required to be sensitive to the sign of such operands (see Annex F of the C11 standard, §F.10.0.3 and §F.10.9.3). - .. versionadded:: next + .. versionadded:: 3.15 .. function:: fmod(x, y) @@ -408,7 +313,7 @@ Floating point manipulation functions nonzero number that is not a subnormal (see :func:`issubnormal`). Return ``False`` otherwise. - .. versionadded:: next + .. versionadded:: 3.15 .. function:: issubnormal(x) @@ -417,7 +322,7 @@ Floating point manipulation functions nonzero number with a magnitude smaller than :data:`sys.float_info.min`. Return ``False`` otherwise. - .. versionadded:: next + .. versionadded:: 3.15 .. function:: isinf(x) @@ -464,7 +369,7 @@ Floating point manipulation functions This is useful to detect the sign bit of zeroes, infinities and NaNs. - .. versionadded:: next + .. versionadded:: 3.15 .. function:: ulp(x) @@ -601,7 +506,7 @@ Summation and product functions Roughly equivalent to:: - sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q))) + sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q, strict=True))) .. versionadded:: 3.8 @@ -812,6 +717,75 @@ Special functions .. versionadded:: 3.2 +Number-theoretic functions +-------------------------- + +For backward compatibility, the :mod:`math` module provides also aliases of +the following functions from the :mod:`math.integer` module: + +.. list-table:: + + * - .. function:: comb(n, k) + :no-typesetting: + + :func:`comb(n, k) ` + - Number of ways to choose *k* items from *n* items without repetition + and without order + + * - .. function:: factorial(n) + :no-typesetting: + + :func:`factorial(n) ` + - *n* factorial + + * - .. function:: gcd(*integers) + :no-typesetting: + + :func:`gcd(*integers) ` + - Greatest common divisor of the integer arguments + + * - .. function:: isqrt(n) + :no-typesetting: + + :func:`isqrt(n) ` + - Integer square root of a nonnegative integer *n* + + * - .. function:: lcm(*integers) + :no-typesetting: + + :func:`lcm(*integers) ` + - Least common multiple of the integer arguments + + * - .. function:: perm(n, k) + :no-typesetting: + + :func:`perm(n, k) ` + - Number of ways to choose *k* items from *n* items without repetition + and with order + +.. versionadded:: 3.5 + The :func:`gcd` function. + +.. versionadded:: 3.8 + The :func:`comb`, :func:`perm` and :func:`isqrt` functions. + +.. versionadded:: 3.9 + The :func:`lcm` function. + +.. versionchanged:: 3.9 + Added support for an arbitrary number of arguments in the :func:`gcd` + function. + Formerly, only two arguments were supported. + +.. versionchanged:: 3.10 + Floats with integral values (like ``5.0``) are no longer accepted in the + :func:`factorial` function. + +.. deprecated:: 3.15 + These aliases are :term:`soft deprecated` in favor of the + :mod:`math.integer` functions. + + Constants --------- @@ -894,5 +868,5 @@ Constants Module :mod:`cmath` Complex number versions of many of these functions. -.. |nbsp| unicode:: 0xA0 - :trim: + Module :mod:`math.integer` + Integer-specific mathematics functions. diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index 8fca79b23e4..f32aa322c40 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -48,10 +48,11 @@ update the underlying file. To map anonymous memory, -1 should be passed as the fileno along with the length. -.. class:: mmap(fileno, length, tagname=None, access=ACCESS_DEFAULT, offset=0) +.. class:: mmap(fileno, length, tagname=None, \ + access=ACCESS_DEFAULT, offset=0, *, trackfd=True) **(Windows version)** Maps *length* bytes from the file specified by the - file handle *fileno*, and creates a mmap object. If *length* is larger + file descriptor *fileno*, and creates a mmap object. If *length* is larger than the current size of the file, the file is extended to contain *length* bytes. If *length* is ``0``, the maximum length of the map is the current size of the file, except that if the file is empty Windows raises an @@ -69,6 +70,17 @@ To map anonymous memory, -1 should be passed as the fileno along with the length will be relative to the offset from the beginning of the file. *offset* defaults to 0. *offset* must be a multiple of the :const:`ALLOCATIONGRANULARITY`. + If *trackfd* is ``False``, the file handle corresponding to *fileno* will + not be duplicated, and the resulting :class:`!mmap` object will not + be associated with the map's underlying file. + This means that the :meth:`~mmap.mmap.size` and :meth:`~mmap.mmap.resize` + methods will fail. + This mode is useful to limit the number of open file handles. + The original file can be renamed (but not deleted) after closing *fileno*. + + .. versionchanged:: 3.15 + The *trackfd* parameter was added. + .. audit-event:: mmap.__new__ fileno,length,access,offset mmap.mmap .. class:: mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, \ @@ -217,6 +229,12 @@ To map anonymous memory, -1 should be passed as the fileno along with the length on error under Windows. A zero value was returned on success; an exception was raised on error under Unix. + .. versionchanged:: 3.15 + Allow specifying *offset* without *size*. Previously, both *offset* + and *size* parameters were required together. Now *offset* can be + specified alone, and the flush operation will extend from *offset* + to the end of the mmap. + .. method:: madvise(option[, start[, length]]) @@ -277,6 +295,8 @@ To map anonymous memory, -1 should be passed as the fileno along with the length pagefile) will silently create a new map with the original data copied over up to the length of the new size. + Availability: Windows and systems with the ``mremap()`` system call. + .. versionchanged:: 3.11 Correctly fails if attempting to resize when another map is held Allows resize against an anonymous map on Windows @@ -312,6 +332,10 @@ To map anonymous memory, -1 should be passed as the fileno along with the length Return the length of the file, which can be larger than the size of the memory-mapped area. + For an anonymous mapping, return its size. + + .. versionchanged:: 3.15 + Anonymous mappings are now supported on Unix. .. method:: tell() diff --git a/Doc/library/msvcrt.rst b/Doc/library/msvcrt.rst index 327cc3602b1..a2c5e375d2c 100644 --- a/Doc/library/msvcrt.rst +++ b/Doc/library/msvcrt.rst @@ -22,6 +22,8 @@ api. The normal API deals only with ASCII characters and is of limited use for internationalized applications. The wide char API should be used where ever possible. +.. availability:: Windows. + .. versionchanged:: 3.3 Operations in this module now raise :exc:`OSError` where :exc:`IOError` was raised. diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index d18ada3511d..382a0abedfc 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -22,8 +22,7 @@ to this, the :mod:`multiprocessing` module allows the programmer to fully leverage multiple processors on a given machine. It runs on both POSIX and Windows. -The :mod:`multiprocessing` module also introduces APIs which do not have -analogs in the :mod:`threading` module. A prime example of this is the +The :mod:`multiprocessing` module also introduces the :class:`~multiprocessing.pool.Pool` object which offers a convenient means of parallelizing the execution of a function across multiple input values, distributing the input data across processes (data parallelism). The following @@ -44,6 +43,10 @@ will print to standard output :: [1, 4, 9] +The :mod:`multiprocessing` module also introduces APIs which do not have +analogs in the :mod:`threading` module, like the ability to :meth:`terminate +`, :meth:`interrupt ` or :meth:`kill +` a running process. .. seealso:: @@ -518,6 +521,21 @@ Reference The :mod:`multiprocessing` package mostly replicates the API of the :mod:`threading` module. +.. _global-start-method: + +Global start method +^^^^^^^^^^^^^^^^^^^ + +Python supports several ways to create and initialize a process. +The global start method sets the default mechanism for creating a process. + +Several multiprocessing functions and methods that may also instantiate +certain objects will implicitly set the global start method to the system's default, +if it hasn’t been set already. The global start method can only be set once. +If you need to change the start method from the system default, you must +proactively set the global start method before calling functions or methods, +or creating these objects. + :class:`Process` and exceptions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -829,8 +847,8 @@ raising an exception. One difference from other Python queue implementations, is that :mod:`multiprocessing` queues serializes all objects that are put into them using :mod:`pickle`. -The object return by the get method is a re-created object that does not share memory -with the original object. +The object returned by the get method is a re-created object that does not share +memory with the original object. Note that one can also create a shared queue by using a manager object -- see :ref:`multiprocessing-managers`. @@ -887,7 +905,7 @@ For an example of the usage of queues for interprocess communication see :ref:`multiprocessing-examples`. -.. function:: Pipe([duplex]) +.. function:: Pipe(duplex=True) Returns a pair ``(conn1, conn2)`` of :class:`~multiprocessing.connection.Connection` objects representing the @@ -907,6 +925,9 @@ For an example of the usage of queues for interprocess communication see locks/semaphores. When a process first puts an item on the queue a feeder thread is started which transfers objects from a buffer into the pipe. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + The usual :exc:`queue.Empty` and :exc:`queue.Full` exceptions from the standard library's :mod:`queue` module are raised to signal timeouts. @@ -1022,6 +1043,9 @@ For an example of the usage of queues for interprocess communication see It is a simplified :class:`Queue` type, very close to a locked :class:`Pipe`. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + .. method:: close() Close the queue: release internal resources. @@ -1052,6 +1076,9 @@ For an example of the usage of queues for interprocess communication see :class:`JoinableQueue`, a :class:`Queue` subclass, is a queue which additionally has :meth:`task_done` and :meth:`join` methods. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + .. method:: task_done() Indicate that a formerly enqueued task is complete. Used by queue @@ -1164,8 +1191,8 @@ Miscellaneous :mod:`multiprocessing` module. If *method* is ``None`` then the default context is returned. Note that if - the global start method has not been set, this will set it to the - default method. + the global start method has not been set, this will set it to the system default + See :ref:`global-start-method` for more details. Otherwise *method* should be ``'fork'``, ``'spawn'``, ``'forkserver'``. :exc:`ValueError` is raised if the specified start method is not available. See :ref:`multiprocessing-start-methods`. @@ -1176,10 +1203,9 @@ Miscellaneous Return the name of start method used for starting processes. - If the global start method has not been set and *allow_none* is - ``False``, then the start method is set to the default and the name - is returned. If the start method has not been set and *allow_none* is - ``True`` then ``None`` is returned. + If the global start method is not set and *allow_none* is ``False``, the global start + method is set to the default, and its name is returned. See + :ref:`global-start-method` for more details. The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'`` or ``None``. See :ref:`multiprocessing-start-methods`. @@ -1406,6 +1432,9 @@ object -- see :ref:`multiprocessing-managers`. A barrier object: a clone of :class:`threading.Barrier`. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + .. versionadded:: 3.3 .. class:: BoundedSemaphore([value]) @@ -1413,6 +1442,9 @@ object -- see :ref:`multiprocessing-managers`. A bounded semaphore object: a close analog of :class:`threading.BoundedSemaphore`. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + A solitary difference from its close analog exists: its ``acquire`` method's first argument is named *block*, as is consistent with :meth:`Lock.acquire`. @@ -1433,6 +1465,9 @@ object -- see :ref:`multiprocessing-managers`. If *lock* is specified then it should be a :class:`Lock` or :class:`RLock` object from :mod:`multiprocessing`. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + .. versionchanged:: 3.3 The :meth:`~threading.Condition.wait_for` method was added. @@ -1440,6 +1475,8 @@ object -- see :ref:`multiprocessing-managers`. A clone of :class:`threading.Event`. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. .. class:: Lock() @@ -1455,6 +1492,9 @@ object -- see :ref:`multiprocessing-managers`. instance of ``multiprocessing.synchronize.Lock`` initialized with a default context. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + :class:`Lock` supports the :term:`context manager` protocol and thus may be used in :keyword:`with` statements. @@ -1512,6 +1552,9 @@ object -- see :ref:`multiprocessing-managers`. instance of ``multiprocessing.synchronize.RLock`` initialized with a default context. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + :class:`RLock` supports the :term:`context manager` protocol and thus may be used in :keyword:`with` statements. @@ -1571,15 +1614,28 @@ object -- see :ref:`multiprocessing-managers`. A semaphore object: a close analog of :class:`threading.Semaphore`. + Instantiating this class may set the global start method. See + :ref:`global-start-method` for more details. + A solitary difference from its close analog exists: its ``acquire`` method's first argument is named *block*, as is consistent with :meth:`Lock.acquire`. + + .. method:: get_value() + + Return the current value of semaphore. + + Note that this may raise :exc:`NotImplementedError` on platforms like + macOS where ``sem_getvalue()`` is not implemented. + + .. method:: locked() Return a boolean indicating whether this object is locked right now. .. versionadded:: 3.14 + .. note:: On macOS, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with @@ -1705,7 +1761,7 @@ processes. attributes which allow one to use it to store and retrieve strings -- see documentation for :mod:`ctypes`. -.. function:: Array(typecode_or_type, size_or_initializer, *, lock=True) +.. function:: Array(typecode_or_type, size_or_initializer, *, lock=True, ctx=None) The same as :func:`RawArray` except that depending on the value of *lock* a process-safe synchronization wrapper may be returned instead of a raw ctypes @@ -1719,9 +1775,13 @@ processes. automatically protected by a lock, so it will not necessarily be "process-safe". - Note that *lock* is a keyword-only argument. + *ctx* is a context object, or ``None`` (use the current context). If ``None``, + calling this may set the global start method. See + :ref:`global-start-method` for more details. -.. function:: Value(typecode_or_type, *args, lock=True) + Note that *lock* and *ctx* are keyword-only parameters. + +.. function:: Value(typecode_or_type, *args, lock=True, ctx=None) The same as :func:`RawValue` except that depending on the value of *lock* a process-safe synchronization wrapper may be returned instead of a raw ctypes @@ -1734,19 +1794,27 @@ processes. automatically protected by a lock, so it will not necessarily be "process-safe". - Note that *lock* is a keyword-only argument. + *ctx* is a context object, or ``None`` (use the current context). If ``None``, + calling this may set the global start method. See + :ref:`global-start-method` for more details. + + Note that *lock* and *ctx* are keyword-only parameters. .. function:: copy(obj) Return a ctypes object allocated from shared memory which is a copy of the ctypes object *obj*. -.. function:: synchronized(obj[, lock]) +.. function:: synchronized(obj, lock=None, ctx=None) Return a process-safe wrapper object for a ctypes object which uses *lock* to synchronize access. If *lock* is ``None`` (the default) then a :class:`multiprocessing.RLock` object is created automatically. + *ctx* is a context object, or ``None`` (use the current context). If ``None``, + calling this may set the global start method. See + :ref:`global-start-method` for more details. + A synchronized wrapper will have two methods in addition to those of the object it wraps: :meth:`get_obj` returns the wrapped object and :meth:`get_lock` returns the lock object used for synchronization. @@ -1864,8 +1932,9 @@ their parent process exits. The manager classes are defined in the *serializer* must be ``'pickle'`` (use :mod:`pickle` serialization) or ``'xmlrpclib'`` (use :mod:`xmlrpc.client` serialization). - *ctx* is a context object, or ``None`` (use the current context). See the - :func:`get_context` function. + *ctx* is a context object, or ``None`` (use the current context). If ``None``, + calling this may set the global start method. See + :ref:`global-start-method` for more details. *shutdown_timeout* is a timeout in seconds used to wait until the process used by the manager completes in the :meth:`shutdown` method. If the @@ -2358,7 +2427,9 @@ with the :class:`Pool` class. the worker processes. Usually a pool is created using the function :func:`multiprocessing.Pool` or the :meth:`Pool` method of a context object. In both cases *context* is set - appropriately. + appropriately. If ``None``, calling this function will have the side effect + of setting the current global start method if it has not been set already. + See the :func:`get_context` function. Note that the methods of the pool object should only be called by the process which created the pool. diff --git a/Doc/library/numeric.rst b/Doc/library/numeric.rst index 7c76a479d73..a2109a29bfb 100644 --- a/Doc/library/numeric.rst +++ b/Doc/library/numeric.rst @@ -19,6 +19,7 @@ The following modules are documented in this chapter: numbers.rst math.rst + math.integer.rst cmath.rst decimal.rst fractions.rst diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index cb021be4543..3cfe08a1fe1 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -42,8 +42,8 @@ the :mod:`glob` module.) a path that is *always* in one of the different formats. They all have the same interface: - * :mod:`posixpath` for UNIX-style paths - * :mod:`ntpath` for Windows paths + * :mod:`!posixpath` for UNIX-style paths + * :mod:`!ntpath` for Windows paths .. versionchanged:: 3.8 @@ -57,8 +57,9 @@ the :mod:`glob` module.) .. function:: abspath(path) Return a normalized absolutized version of the pathname *path*. On most - platforms, this is equivalent to calling the function :func:`normpath` as - follows: ``normpath(join(os.getcwd(), path))``. + platforms, this is equivalent to calling ``normpath(join(os.getcwd(), path))``. + + .. seealso:: :func:`os.path.join` and :func:`os.path.normpath`. .. versionchanged:: 3.6 Accepts a :term:`path-like object`. @@ -243,6 +244,8 @@ the :mod:`glob` module.) begins with a slash, on Windows that it begins with two (back)slashes, or a drive letter, colon, and (back)slash together. + .. seealso:: :func:`abspath` + .. versionchanged:: 3.6 Accepts a :term:`path-like object`. @@ -357,14 +360,28 @@ the :mod:`glob` module.) concatenation of *path* and all members of *\*paths*, with exactly one directory separator following each non-empty part, except the last. That is, the result will only end in a separator if the last part is either empty or - ends in a separator. If a segment is an absolute path (which on Windows - requires both a drive and a root), then all previous segments are ignored and - joining continues from the absolute path segment. + ends in a separator. + + If a segment is an absolute path (which on Windows requires both a drive and + a root), then all previous segments are ignored and joining continues from the + absolute path segment. On Linux, for example:: + + >>> os.path.join('/home/foo', 'bar') + '/home/foo/bar' + >>> os.path.join('/home/foo', '/home/bar') + '/home/bar' On Windows, the drive is not reset when a rooted path segment (e.g., ``r'\foo'``) is encountered. If a segment is on a different drive or is an - absolute path, all previous segments are ignored and the drive is reset. Note - that since there is a current directory for each drive, + absolute path, all previous segments are ignored and the drive is reset. For + example:: + + >>> os.path.join('c:\\', 'foo') + 'c:\\foo' + >>> os.path.join('c:\\foo', 'd:\\bar') + 'd:\\bar' + + Note that since there is a current directory for each drive, ``os.path.join("c:", "foo")`` represents a path relative to the current directory on drive :file:`C:` (:file:`c:foo`), not :file:`c:\\foo`. @@ -449,7 +466,7 @@ the :mod:`glob` module.) .. versionchanged:: 3.10 The *strict* parameter was added. - .. versionchanged:: next + .. versionchanged:: 3.15 The :data:`ALL_BUT_LAST` and :data:`ALLOW_MISSING` values for the *strict* parameter was added. @@ -457,13 +474,13 @@ the :mod:`glob` module.) Special value used for the *strict* argument in :func:`realpath`. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: ALLOW_MISSING Special value used for the *strict* argument in :func:`realpath`. - .. versionadded:: next + .. versionadded:: 3.15 .. function:: relpath(path, start=os.curdir) @@ -527,8 +544,8 @@ the :mod:`glob` module.) *path* is empty, both *head* and *tail* are empty. Trailing slashes are stripped from *head* unless it is the root (one or more slashes only). In all cases, ``join(head, tail)`` returns a path to the same location as *path* - (but the strings may differ). Also see the functions :func:`dirname` and - :func:`basename`. + (but the strings may differ). Also see the functions :func:`join`, + :func:`dirname` and :func:`basename`. .. versionchanged:: 3.6 Accepts a :term:`path-like object`. diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 45ec6c7a51b..671270d6112 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -108,7 +108,7 @@ Python UTF-8 Mode .. versionadded:: 3.7 See :pep:`540` for more details. -.. versionchanged:: next +.. versionchanged:: 3.15 Python UTF-8 mode is now enabled by default (:pep:`686`). It may be disabled with by setting :envvar:`PYTHONUTF8=0 ` as @@ -216,8 +216,8 @@ process and user. You can delete items in this mapping to unset environment variables. :func:`unsetenv` will be called automatically when an item is deleted from - :data:`os.environ`, and when one of the :meth:`pop` or :meth:`clear` methods is - called. + :data:`os.environ`, and when one of the :meth:`~dict.pop` or + :meth:`~dict.clear` methods is called. .. seealso:: @@ -430,8 +430,8 @@ process and user. associated with the effective user id of the process; the group access list may change over the lifetime of the process, it is not affected by calls to :func:`setgroups`, and its length is not limited to 16. The - deployment target value, :const:`MACOSX_DEPLOYMENT_TARGET`, can be - obtained with :func:`sysconfig.get_config_var`. + deployment target value can be obtained with + :func:`sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') `. .. function:: getlogin() @@ -558,7 +558,7 @@ process and user. .. function:: initgroups(username, gid, /) - Call the system initgroups() to initialize the group access list with all of + Call the system ``initgroups()`` to initialize the group access list with all of the groups of which the specified username is a member, plus the specified group id. @@ -1501,6 +1501,7 @@ or `the MSDN `_ on Windo - :data:`RWF_HIPRI` - :data:`RWF_NOWAIT` + - :data:`RWF_DONTCACHE` Return the total number of bytes actually read which can be less than the total capacity of all the objects. @@ -1546,6 +1547,15 @@ or `the MSDN `_ on Windo .. versionadded:: 3.7 +.. data:: RWF_DONTCACHE + + Use uncached buffered IO. + + .. availability:: Linux >= 6.14 + + .. versionadded:: 3.15 + + .. function:: ptsname(fd, /) Return the name of the slave pseudo-terminal device associated with the @@ -1587,6 +1597,7 @@ or `the MSDN `_ on Windo - :data:`RWF_DSYNC` - :data:`RWF_SYNC` - :data:`RWF_APPEND` + - :data:`RWF_DONTCACHE` Return the total number of bytes actually written. @@ -2006,8 +2017,8 @@ features: must be a string specifying a file path. However, some functions now alternatively accept an open file descriptor for their *path* argument. The function will then operate on the file referred to by the descriptor. - (For POSIX systems, Python will call the variant of the function prefixed - with ``f`` (e.g. call ``fchdir`` instead of ``chdir``).) + For POSIX systems, Python will call the variant of the function prefixed + with ``f`` (e.g. call ``fchdir`` instead of ``chdir``). You can check whether or not *path* can be specified as a file descriptor for a particular function on your platform using :data:`os.supports_fd`. @@ -2022,7 +2033,7 @@ features: * **paths relative to directory descriptors:** If *dir_fd* is not ``None``, it should be a file descriptor referring to a directory, and the path to operate on should be relative; path will then be relative to that directory. If the - path is absolute, *dir_fd* is ignored. (For POSIX systems, Python will call + path is absolute, *dir_fd* is ignored. For POSIX systems, Python will call the variant of the function with an ``at`` suffix and possibly prefixed with ``f`` (e.g. call ``faccessat`` instead of ``access``). @@ -2035,8 +2046,8 @@ features: * **not following symlinks:** If *follow_symlinks* is ``False``, and the last element of the path to operate on is a symbolic link, the function will operate on the symbolic link itself rather than the file - pointed to by the link. (For POSIX systems, Python will call the ``l...`` - variant of the function.) + pointed to by the link. For POSIX systems, Python will call the ``l...`` + variant of the function. You can check whether or not *follow_symlinks* is supported for a particular function on your platform using :data:`os.supports_follow_symlinks`. @@ -2595,10 +2606,10 @@ features: Create a filesystem node (file, device special file or named pipe) named *path*. *mode* specifies both the permissions to use and the type of node - to be created, being combined (bitwise OR) with one of ``stat.S_IFREG``, - ``stat.S_IFCHR``, ``stat.S_IFBLK``, and ``stat.S_IFIFO`` (those constants are - available in :mod:`stat`). For ``stat.S_IFCHR`` and ``stat.S_IFBLK``, - *device* defines the newly created device special file (probably using + to be created, being combined (bitwise OR) with one of :const:`stat.S_IFREG`, + :const:`stat.S_IFCHR`, :const:`stat.S_IFBLK`, and :const:`stat.S_IFIFO`. + For :const:`stat.S_IFCHR` and :const:`stat.S_IFBLK`, *device* defines the + newly created device special file (probably using :func:`os.makedev`), otherwise it is ignored. This function can also support :ref:`paths relative to directory descriptors @@ -2616,13 +2627,13 @@ features: .. function:: major(device, /) Extract the device major number from a raw device number (usually the - :attr:`st_dev` or :attr:`st_rdev` field from :c:struct:`stat`). + :attr:`~stat_result.st_dev` or :attr:`~stat_result.st_rdev` field from :c:struct:`stat`). .. function:: minor(device, /) Extract the device minor number from a raw device number (usually the - :attr:`st_dev` or :attr:`st_rdev` field from :c:struct:`stat`). + :attr:`~stat_result.st_dev` or :attr:`~stat_result.st_rdev` field from :c:struct:`stat`). .. function:: makedev(major, minor, /) @@ -2630,6 +2641,13 @@ features: Compose a raw device number from the major and minor device numbers. +.. data:: NODEV + + Non-existent device. + + .. versionadded:: 3.15 + + .. function:: pathconf(path, name) Return system configuration information relevant to a named file. *name* @@ -3346,8 +3364,8 @@ features: .. versionchanged:: 3.8 On Windows, the :attr:`st_mode` member now identifies special - files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK` - as appropriate. + files as :const:`~stat.S_IFCHR`, :const:`~stat.S_IFIFO` or + :const:`~stat.S_IFBLK` as appropriate. .. versionchanged:: 3.12 On Windows, :attr:`st_ctime` is deprecated. Eventually, it will @@ -3365,6 +3383,359 @@ features: Added the :attr:`st_birthtime` member on Windows. +.. function:: statx(path, mask, *, flags=0, dir_fd=None, follow_symlinks=True) + + Get the status of a file or file descriptor by performing a :c:func:`!statx` + system call on the given path. + + *path* is a :term:`path-like object` or an open file descriptor. *mask* is a + combination of the module-level :const:`STATX_* ` constants + specifying the information to retrieve. *flags* is a combination of the + module-level :const:`AT_STATX_* ` constants and/or + :const:`AT_NO_AUTOMOUNT`. Returns a :class:`statx_result` object whose + :attr:`~os.statx_result.stx_mask` attribute specifies the information + actually retrieved (which may differ from *mask*). + + This function supports :ref:`specifying a file descriptor `, + :ref:`paths relative to directory descriptors `, and + :ref:`not following symlinks `. + + .. seealso:: The :manpage:`statx(2)` man page. + + .. availability:: Linux >= 4.11 with glibc >= 2.28. + + .. versionadded:: 3.15 + + +.. class:: statx_result + + Information about a file returned by :func:`os.statx`. + + :class:`!statx_result` has the following attributes: + + .. attribute:: stx_atime + + Time of most recent access expressed in seconds. + + Equal to ``None`` if :data:`STATX_ATIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_atime_ns + + Time of most recent access expressed in nanoseconds as an integer. + + Equal to ``None`` if :data:`STATX_ATIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_atomic_write_segments_max + + Maximum iovecs for direct I/O with torn-write protection. + + Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.11. + + .. attribute:: stx_atomic_write_unit_max + + Maximum size for direct I/O with torn-write protection. + + Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.11. + + .. attribute:: stx_atomic_write_unit_max_opt + + Maximum optimized size for direct I/O with torn-write protection. + + Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.16. + + .. attribute:: stx_atomic_write_unit_min + + Minimum size for direct I/O with torn-write protection. + + Equal to ``None`` if :data:`STATX_WRITE_ATOMIC` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.11. + + .. attribute:: stx_attributes + + Bitmask of :const:`STATX_ATTR_* ` constants + specifying the attributes of this file. + + .. attribute:: stx_attributes_mask + + A mask indicating which bits in :attr:`stx_attributes` are supported by + the VFS and the filesystem. + + .. attribute:: stx_blksize + + "Preferred" blocksize for efficient file system I/O. Writing to a file in + smaller chunks may cause an inefficient read-modify-rewrite. + + .. attribute:: stx_blocks + + Number of 512-byte blocks allocated for file. + This may be smaller than :attr:`stx_size`/512 when the file has holes. + + Equal to ``None`` if :data:`STATX_BLOCKS` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_btime + + Time of file creation expressed in seconds. + + Equal to ``None`` if :data:`STATX_BTIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_btime_ns + + Time of file creation expressed in nanoseconds as an integer. + + Equal to ``None`` if :data:`STATX_BTIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_ctime + + Time of most recent metadata change expressed in seconds. + + Equal to ``None`` if :data:`STATX_CTIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_ctime_ns + + Time of most recent metadata change expressed in nanoseconds as an + integer. + + Equal to ``None`` if :data:`STATX_CTIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_dev + + Identifier of the device on which this file resides. + + .. attribute:: stx_dev_major + + Major number of the device on which this file resides. + + .. attribute:: stx_dev_minor + + Minor number of the device on which this file resides. + + .. attribute:: stx_dio_mem_align + + Direct I/O memory buffer alignment requirement. + + Equal to ``None`` if :data:`STATX_DIOALIGN` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.1. + + .. attribute:: stx_dio_offset_align + + Direct I/O file offset alignment requirement. + + Equal to ``None`` if :data:`STATX_DIOALIGN` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.1. + + .. attribute:: stx_dio_read_offset_align + + Direct I/O file offset alignment requirement for reads. + + Equal to ``None`` if :data:`STATX_DIO_READ_ALIGN` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.14. + + .. attribute:: stx_gid + + Group identifier of the file owner. + + Equal to ``None`` if :data:`STATX_GID` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_ino + + Inode number. + + Equal to ``None`` if :data:`STATX_INO` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_mask + + Bitmask of :const:`STATX_* ` constants specifying the + information retrieved, which may differ from what was requested. + + .. attribute:: stx_mnt_id + + Mount identifier. + + Equal to ``None`` if :data:`STATX_MNT_ID` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 5.8. + + .. attribute:: stx_mode + + File mode: file type and file mode bits (permissions). + + Equal to ``None`` if :data:`STATX_TYPE | STATX_MODE ` + is missing from :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_mtime + + Time of most recent content modification expressed in seconds. + + Equal to ``None`` if :data:`STATX_MTIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_mtime_ns + + Time of most recent content modification expressed in nanoseconds as an + integer. + + Equal to ``None`` if :data:`STATX_MTIME` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_nlink + + Number of hard links. + + Equal to ``None`` if :data:`STATX_NLINK` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_rdev + + Type of device if an inode device. + + .. attribute:: stx_rdev_major + + Major number of the device this file represents. + + .. attribute:: stx_rdev_minor + + Minor number of the device this file represents. + + .. attribute:: stx_size + + Size of the file in bytes, if it is a regular file or a symbolic link. + The size of a symbolic link is the length of the pathname it contains, + without a terminating null byte. + + Equal to ``None`` if :data:`STATX_SIZE` is missing from + :attr:`~statx_result.stx_mask`. + + .. attribute:: stx_subvol + + Subvolume identifier. + + Equal to ``None`` if :data:`STATX_SUBVOL` is missing from + :attr:`~statx_result.stx_mask`. + + .. availability:: Linux >= 4.11 with glibc >= 2.28 and build-time kernel + userspace API headers >= 6.10. + + .. attribute:: stx_uid + + User identifier of the file owner. + + Equal to ``None`` if :data:`STATX_UID` is missing from + :attr:`~statx_result.stx_mask`. + + .. seealso:: The :manpage:`statx(2)` man page. + + .. availability:: Linux >= 4.11 with glibc >= 2.28. + + .. versionadded:: 3.15 + + +.. data:: STATX_TYPE + STATX_MODE + STATX_NLINK + STATX_UID + STATX_GID + STATX_ATIME + STATX_MTIME + STATX_CTIME + STATX_INO + STATX_SIZE + STATX_BLOCKS + STATX_BASIC_STATS + STATX_BTIME + STATX_MNT_ID + STATX_DIOALIGN + STATX_MNT_ID_UNIQUE + STATX_SUBVOL + STATX_WRITE_ATOMIC + STATX_DIO_READ_ALIGN + + Bitflags for use in the *mask* parameter to :func:`os.statx`. Some of these + flags may be available even when their corresponding members in + :class:`statx_result` are not available. + + .. availability:: Linux >= 4.11 with glibc >= 2.28. + + .. versionadded:: 3.15 + +.. data:: AT_STATX_FORCE_SYNC + + A flag for the :func:`os.statx` function. Requests that the kernel return + up-to-date information even when doing so is expensive (for example, + requiring a round trip to the server for a file on a network filesystem). + + .. availability:: Linux >= 4.11 with glibc >= 2.28. + + .. versionadded:: 3.15 + +.. data:: AT_STATX_DONT_SYNC + + A flag for the :func:`os.statx` function. Requests that the kernel return + cached information if possible. + + .. availability:: Linux >= 4.11 with glibc >= 2.28. + + .. versionadded:: 3.15 + +.. data:: AT_STATX_SYNC_AS_STAT + + A flag for the :func:`os.statx` function. This flag is defined as ``0``, so + it has no effect, but it can be used to explicitly indicate neither + :data:`AT_STATX_FORCE_SYNC` nor :data:`AT_STATX_DONT_SYNC` is being passed. + In the absence of the other two flags, the kernel will generally return + information as fresh as :func:`os.stat` would return. + + .. availability:: Linux >= 4.11 with glibc >= 2.28. + + .. versionadded:: 3.15 + + +.. data:: AT_NO_AUTOMOUNT + + If the final component of a path is an automount point, operate on the + automount point instead of performing the automount. On Linux, + :func:`os.stat`, :func:`os.fstat` and :func:`os.lstat` always behave this + way. + + .. availability:: Linux. + + .. versionadded:: 3.15 + + .. function:: statvfs(path) Perform a :c:func:`!statvfs` system call on the given path. The return value is @@ -3502,6 +3873,9 @@ features: Create a symbolic link pointing to *src* named *dst*. + The *src* parameter refers to the target of the link (the file or directory being linked to), + and *dst* is the name of the link being created. + On Windows, a symlink represents either a file or a directory, and does not morph to the target dynamically. If the target is present, the type of the symlink will be created to match. Otherwise, the symlink will be created @@ -3600,7 +3974,8 @@ features: where each member is an int expressing nanoseconds. - If *times* is not ``None``, it must be a 2-tuple of the form ``(atime, mtime)`` - where each member is an int or float expressing seconds. + where each member is a real number expressing seconds, + rounded down to nanoseconds. - If *times* is ``None`` and *ns* is unspecified, this is equivalent to specifying ``ns=(atime_ns, mtime_ns)`` where both times are the current time. @@ -3627,6 +4002,9 @@ features: .. versionchanged:: 3.6 Accepts a :term:`path-like object`. + .. versionchanged:: 3.15 + Accepts any real numbers as *times*, not only integers or floats. + .. function:: walk(top, topdown=True, onerror=None, followlinks=False) @@ -3757,9 +4135,9 @@ features: import os for root, dirs, files, rootfd in os.fwalk('python/Lib/xml'): - print(root, "consumes", end="") + print(root, "consumes", end=" ") print(sum([os.stat(name, dir_fd=rootfd).st_size for name in files]), - end="") + end=" ") print("bytes in", len(files), "non-directory files") if '__pycache__' in dirs: dirs.remove('__pycache__') # don't visit __pycache__ directories @@ -4032,7 +4410,7 @@ Naturally, they are all only available on Linux. the timer will fire when the timer's clock (set by *clockid* in :func:`timerfd_create`) reaches *initial* seconds. - The timer's interval is set by the *interval* :py:class:`float`. + The timer's interval is set by the *interval* real number. If *interval* is zero, the timer only fires once, on the initial expiration. If *interval* is greater than zero, the timer fires every time *interval* seconds have elapsed since the previous expiration. @@ -4263,10 +4641,10 @@ to be ignored. .. function:: abort() - Generate a :const:`SIGABRT` signal to the current process. On Unix, the default + Generate a :const:`~signal.SIGABRT` signal to the current process. On Unix, the default behavior is to produce a core dump; on Windows, the process immediately returns an exit code of ``3``. Be aware that calling this function will not call the - Python signal handler registered for :const:`SIGABRT` with + Python signal handler registered for :const:`~signal.SIGABRT` with :func:`signal.signal`. @@ -4570,6 +4948,8 @@ written in Python, such as a mail server's external command delivery program. master end of the pseudo-terminal. For a more portable approach, use the :mod:`pty` module. If an error occurs :exc:`OSError` is raised. + The returned file descriptor *fd* is :ref:`non-inheritable `. + .. audit-event:: os.forkpty "" os.forkpty .. warning:: @@ -4586,6 +4966,9 @@ written in Python, such as a mail server's external command delivery program. threads, this now raises a :exc:`DeprecationWarning`. See the longer explanation on :func:`os.fork`. + .. versionchanged:: 3.15 + The returned file descriptor is now made non-inheritable. + .. availability:: Unix, not WASI, not Android, not iOS. diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index ebf5756146d..79e0b7f09ea 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -311,7 +311,7 @@ Pure paths provide the following methods and properties: .. attribute:: PurePath.parser The implementation of the :mod:`os.path` module used for low-level path - parsing and joining: either :mod:`posixpath` or :mod:`ntpath`. + parsing and joining: either :mod:`!posixpath` or :mod:`!ntpath`. .. versionadded:: 3.13 diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 90dc6648045..0bbdc425352 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -76,6 +76,10 @@ The debugger's prompt is ``(Pdb)``, which is the indicator that you are in debug .. _pdb-cli: + +Command-line interface +---------------------- + .. program:: pdb You can also invoke :mod:`pdb` from the command line to debug other scripts. For @@ -334,7 +338,7 @@ access further features, you have to do this yourself: .. _debugger-commands: -Debugger Commands +Debugger commands ----------------- The commands recognized by the debugger are listed below. Most commands can be diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index 007c9fe1b95..3a9b66ec7e7 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -732,8 +732,8 @@ or both. These items will be appended to the object either using ``obj.append(item)`` or, in batch, using ``obj.extend(list_of_items)``. This is primarily used for list subclasses, but may be used by other - classes as long as they have - :ref:`append and extend methods ` with + classes as long as they have :meth:`~sequence.append` + and :meth:`~sequence.extend` methods with the appropriate signature. (Whether :meth:`!append` or :meth:`!extend` is used depends on which pickle protocol version is used as well as the number of items to append, so both must be supported.) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index 37df13f8a1e..d05c6e5a2aa 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -56,6 +56,8 @@ Cross platform Returns the machine type, e.g. ``'AMD64'``. An empty string is returned if the value cannot be determined. + The output is platform-dependent and may differ in casing and naming conventions. + .. function:: node() @@ -187,6 +189,14 @@ Cross platform .. versionchanged:: 3.9 :attr:`processor` is resolved late instead of immediately. +.. function:: invalidate_caches() + + Clear out the internal cache of information, such as the :func:`uname`. + This is typically useful when the platform's :func:`node` is changed + by an external process and one needs to retrieve the updated value. + + .. versionadded:: 3.14 + Windows platform ---------------- @@ -370,14 +380,3 @@ The following options are accepted: You can also pass one or more positional arguments (``terse``, ``nonaliased``) to explicitly control the output format. These behave similarly to their corresponding options. - -Miscellaneous -------------- - -.. function:: invalidate_caches() - - Clear out the internal cache of information, such as the :func:`uname`. - This is typically useful when the platform's :func:`node` is changed - by an external process and one needs to retrieve the updated value. - - .. versionadded:: 3.14 diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 2985f31bacb..f5189245079 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -22,8 +22,6 @@ The formatted representation keeps objects on a single line if it can, and breaks them onto multiple lines if they don't fit within the allowed width, adjustable by the *width* parameter defaulting to 80 characters. -Dictionaries are sorted by key before the display is computed. - .. versionchanged:: 3.9 Added support for pretty-printing :class:`types.SimpleNamespace`. diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 0d96232658b..218aa88bc49 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -1,523 +1,64 @@ .. _profile: -******************** -The Python Profilers -******************** +**************************************** +:mod:`!profile` --- Pure Python profiler +**************************************** -**Source code:** :source:`Lib/profile.py`, :source:`Lib/pstats.py`, and :source:`Lib/profile/sample.py` +.. module:: profile + :synopsis: Pure Python profiler (deprecated). + :deprecated: + +**Source code:** :source:`Lib/profile.py` -------------- -.. _profiler-introduction: +.. deprecated-removed:: 3.15 3.17 -Introduction to the profilers -============================= +The :mod:`profile` module is deprecated and will be removed in Python 3.17. +Use :mod:`profiling.tracing` instead. -.. index:: - single: statistical profiling - single: profiling, statistical - single: deterministic profiling - single: profiling, deterministic +The :mod:`profile` module provides a pure Python implementation of a +deterministic profiler. While useful for understanding profiler internals or +extending profiler behavior through subclassing, its pure Python implementation +introduces significant overhead compared to the C-based :mod:`profiling.tracing` +module. -Python provides both :dfn:`statistical profiling` and :dfn:`deterministic profiling` of -Python programs. A :dfn:`profile` is a set of statistics that describes how -often and for how long various parts of the program executed. These statistics -can be formatted into reports via the :mod:`pstats` module. +For most profiling tasks, use: -The Python standard library provides three different profiling implementations: +- :mod:`profiling.sampling` for production debugging with zero overhead +- :mod:`profiling.tracing` for development and testing -**Statistical Profiler:** -1. :mod:`profile.sample` provides statistical profiling of running Python processes - using periodic stack sampling. It can attach to any running Python process without - requiring code modification or restart, making it ideal for production debugging. +Migration +========= -**Deterministic Profilers:** +Migrating from :mod:`profile` to :mod:`profiling.tracing` is straightforward. +The APIs are compatible:: -2. :mod:`cProfile` is recommended for development and testing; it's a C extension with - reasonable overhead that makes it suitable for profiling long-running - programs. Based on :mod:`lsprof`, contributed by Brett Rosen and Ted - Czotter. + # Old (deprecated) + import profile + profile.run('my_function()') -3. :mod:`profile`, a pure Python module whose interface is imitated by - :mod:`cProfile`, but which adds significant overhead to profiled programs. - If you're trying to extend the profiler in some way, the task might be easier - with this module. Originally designed and written by Jim Roskind. + # New (recommended) + import profiling.tracing + profiling.tracing.run('my_function()') + +For most code, replacing ``import profile`` with ``import profiling.tracing`` +(and using ``profiling.tracing`` instead of ``profile`` throughout) provides +a straightforward migration path. .. note:: - The profiler modules are designed to provide an execution profile for a given - program, not for benchmarking purposes (for that, there is :mod:`timeit` for - reasonably accurate results). This particularly applies to benchmarking - Python code against C code: the profilers introduce overhead for Python code, - but not for C-level functions, and so the C code would seem faster than any - Python one. + The ``cProfile`` module remains available as a backward-compatible alias + to :mod:`profiling.tracing`. Existing code using ``import cProfile`` will + continue to work without modification. -**Profiler Comparison:** -+-------------------+----------------------+----------------------+----------------------+ -| Feature | Statistical | Deterministic | Deterministic | -| | (``profile.sample``) | (``cProfile``) | (``profile``) | -+===================+======================+======================+======================+ -| **Target** | Running process | Code you run | Code you run | -+-------------------+----------------------+----------------------+----------------------+ -| **Overhead** | Virtually none | Moderate | High | -+-------------------+----------------------+----------------------+----------------------+ -| **Accuracy** | Statistical approx. | Exact call counts | Exact call counts | -+-------------------+----------------------+----------------------+----------------------+ -| **Setup** | Attach to any PID | Instrument code | Instrument code | -+-------------------+----------------------+----------------------+----------------------+ -| **Use Case** | Production debugging | Development/testing | Profiler extension | -+-------------------+----------------------+----------------------+----------------------+ -| **Implementation**| C extension | C extension | Pure Python | -+-------------------+----------------------+----------------------+----------------------+ +:mod:`!profile` and :mod:`!profiling.tracing` module reference +============================================================== -.. note:: - - The statistical profiler (:mod:`profile.sample`) is recommended for most production - use cases due to its extremely low overhead and ability to profile running processes - without modification. It can attach to any Python process and collect performance - data with minimal impact on execution speed, making it ideal for debugging - performance issues in live applications. - - -.. _statistical-profiling: - -What Is Statistical Profiling? -============================== - -:dfn:`Statistical profiling` works by periodically interrupting a running -program to capture its current call stack. Rather than monitoring every -function entry and exit like deterministic profilers, it takes snapshots at -regular intervals to build a statistical picture of where the program spends -its time. - -The sampling profiler uses process memory reading (via system calls like -``process_vm_readv`` on Linux, ``vm_read`` on macOS, and ``ReadProcessMemory`` on -Windows) to attach to a running Python process and extract stack trace -information without requiring any code modification or restart of the target -process. This approach provides several key advantages over traditional -profiling methods. - -The fundamental principle is that if a function appears frequently in the -collected stack samples, it is likely consuming significant CPU time. By -analyzing thousands of samples, the profiler can accurately estimate the -relative time spent in different parts of the program. The statistical nature -means that while individual measurements may vary, the aggregate results -converge to represent the true performance characteristics of the application. - -Since statistical profiling operates externally to the target process, it -introduces virtually no overhead to the running program. The profiler process -runs separately and reads the target process memory without interrupting its -execution. This makes it suitable for profiling production systems where -performance impact must be minimized. - -The accuracy of statistical profiling improves with the number of samples -collected. Short-lived functions may be missed or underrepresented, while -long-running functions will be captured proportionally to their execution time. -This characteristic makes statistical profiling particularly effective for -identifying the most significant performance bottlenecks rather than providing -exhaustive coverage of all function calls. - -Statistical profiling excels at answering questions like "which functions -consume the most CPU time?" and "where should I focus optimization efforts?" -rather than "exactly how many times was this function called?" The trade-off -between precision and practicality makes it an invaluable tool for performance -analysis in real-world applications. - -.. _profile-instant: - -Instant User's Manual -===================== - -This section is provided for users that "don't want to read the manual." It -provides a very brief overview, and allows a user to rapidly perform profiling -on an existing application. - -**Statistical Profiling (Recommended for Production):** - -To profile an existing running process:: - - python -m profile.sample 1234 - -To profile with custom settings:: - - python -m profile.sample -i 50 -d 30 1234 - -**Deterministic Profiling (Development/Testing):** - -To profile a function that takes a single argument, you can do:: - - import cProfile - import re - cProfile.run('re.compile("foo|bar")') - -(Use :mod:`profile` instead of :mod:`cProfile` if the latter is not available on -your system.) - -The above action would run :func:`re.compile` and print profile results like -the following:: - - 214 function calls (207 primitive calls) in 0.002 seconds - - Ordered by: cumulative time - - ncalls tottime percall cumtime percall filename:lineno(function) - 1 0.000 0.000 0.002 0.002 {built-in method builtins.exec} - 1 0.000 0.000 0.001 0.001 :1() - 1 0.000 0.000 0.001 0.001 __init__.py:250(compile) - 1 0.000 0.000 0.001 0.001 __init__.py:289(_compile) - 1 0.000 0.000 0.000 0.000 _compiler.py:759(compile) - 1 0.000 0.000 0.000 0.000 _parser.py:937(parse) - 1 0.000 0.000 0.000 0.000 _compiler.py:598(_code) - 1 0.000 0.000 0.000 0.000 _parser.py:435(_parse_sub) - -The first line indicates that 214 calls were monitored. Of those calls, 207 -were :dfn:`primitive`, meaning that the call was not induced via recursion. The -next line: ``Ordered by: cumulative time`` indicates the output is sorted -by the ``cumtime`` values. The column headings include: - -ncalls - for the number of calls. - -tottime - for the total time spent in the given function (and excluding time made in - calls to sub-functions) - -percall - is the quotient of ``tottime`` divided by ``ncalls`` - -cumtime - is the cumulative time spent in this and all subfunctions (from invocation - till exit). This figure is accurate *even* for recursive functions. - -percall - is the quotient of ``cumtime`` divided by primitive calls - -filename:lineno(function) - provides the respective data of each function - -When there are two numbers in the first column (for example ``3/1``), it means -that the function recursed. The second value is the number of primitive calls -and the former is the total number of calls. Note that when the function does -not recurse, these two values are the same, and only the single figure is -printed. - -Instead of printing the output at the end of the profile run, you can save the -results to a file by specifying a filename to the :func:`run` function:: - - import cProfile - import re - cProfile.run('re.compile("foo|bar")', 'restats') - -The :class:`pstats.Stats` class reads profile results from a file and formats -them in various ways. - -.. _sampling-profiler-cli: - -Statistical Profiler Command Line Interface -=========================================== - -.. program:: profile.sample - -The :mod:`profile.sample` module can be invoked as a script to profile running processes:: - - python -m profile.sample [options] PID - -**Basic Usage Examples:** - -Profile process 1234 for 10 seconds with default settings:: - - python -m profile.sample 1234 - -Profile with custom interval and duration, save to file:: - - python -m profile.sample -i 50 -d 30 -o profile.stats 1234 - -Generate collapsed stacks to use with tools like `flamegraph.pl -`_:: - - python -m profile.sample --collapsed 1234 - -Profile all threads, sort by total time:: - - python -m profile.sample -a --sort-tottime 1234 - -Profile with real-time sampling statistics:: - - python -m profile.sample --realtime-stats 1234 - -**Command Line Options:** - -.. option:: PID - - Process ID of the Python process to profile (required) - -.. option:: -i, --interval INTERVAL - - Sampling interval in microseconds (default: 100) - -.. option:: -d, --duration DURATION - - Sampling duration in seconds (default: 10) - -.. option:: -a, --all-threads - - Sample all threads in the process instead of just the main thread - -.. option:: --realtime-stats - - Print real-time sampling statistics during profiling - -.. option:: --pstats - - Generate pstats output (default) - -.. option:: --collapsed - - Generate collapsed stack traces for flamegraphs - -.. option:: -o, --outfile OUTFILE - - Save output to a file - -**Sorting Options (pstats format only):** - -.. option:: --sort-nsamples - - Sort by number of direct samples - -.. option:: --sort-tottime - - Sort by total time - -.. option:: --sort-cumtime - - Sort by cumulative time (default) - -.. option:: --sort-sample-pct - - Sort by sample percentage - -.. option:: --sort-cumul-pct - - Sort by cumulative sample percentage - -.. option:: --sort-nsamples-cumul - - Sort by cumulative samples - -.. option:: --sort-name - - Sort by function name - -.. option:: -l, --limit LIMIT - - Limit the number of rows in the output (default: 15) - -.. option:: --no-summary - - Disable the summary section in the output - -**Understanding Statistical Profile Output:** - -The statistical profiler produces output similar to deterministic profilers but with different column meanings:: - - Profile Stats: - nsamples sample% tottime (ms) cumul% cumtime (ms) filename:lineno(function) - 45/67 12.5 23.450 18.6 56.780 mymodule.py:42(process_data) - 23/23 6.4 15.230 6.4 15.230 :0(len) - -**Column Meanings:** - -- **nsamples**: ``direct/cumulative`` - Times function was directly executing / on call stack -- **sample%**: Percentage of total samples where function was directly executing -- **tottime**: Estimated time spent directly in this function -- **cumul%**: Percentage of samples where function was anywhere on call stack -- **cumtime**: Estimated cumulative time including called functions -- **filename:lineno(function)**: Location and name of the function - -.. _profile-cli: - -:mod:`profile.sample` Module Reference -======================================================= - -.. module:: profile.sample - :synopsis: Python statistical profiler. - -This section documents the programmatic interface for the :mod:`profile.sample` module. -For command-line usage, see :ref:`sampling-profiler-cli`. For conceptual information -about statistical profiling, see :ref:`statistical-profiling` - -.. function:: sample(pid, *, sort=2, sample_interval_usec=100, duration_sec=10, filename=None, all_threads=False, limit=None, show_summary=True, output_format="pstats", realtime_stats=False) - - Sample a Python process and generate profiling data. - - This is the main entry point for statistical profiling. It creates a - :class:`SampleProfiler`, collects stack traces from the target process, and - outputs the results in the specified format. - - :param int pid: Process ID of the target Python process - :param int sort: Sort order for pstats output (default: 2 for cumulative time) - :param int sample_interval_usec: Sampling interval in microseconds (default: 100) - :param int duration_sec: Duration to sample in seconds (default: 10) - :param str filename: Output filename (None for stdout/default naming) - :param bool all_threads: Whether to sample all threads (default: False) - :param int limit: Maximum number of functions to display (default: None) - :param bool show_summary: Whether to show summary statistics (default: True) - :param str output_format: Output format - 'pstats' or 'collapsed' (default: 'pstats') - :param bool realtime_stats: Whether to display real-time statistics (default: False) - - :raises ValueError: If output_format is not 'pstats' or 'collapsed' - - Examples:: - - # Basic usage - profile process 1234 for 10 seconds - import profile.sample - profile.sample.sample(1234) - - # Profile with custom settings - profile.sample.sample(1234, duration_sec=30, sample_interval_usec=50, all_threads=True) - - # Generate collapsed stack traces for flamegraph.pl - profile.sample.sample(1234, output_format='collapsed', filename='profile.collapsed') - -.. class:: SampleProfiler(pid, sample_interval_usec, all_threads) - - Low-level API for the statistical profiler. - - This profiler uses periodic stack sampling to collect performance data - from running Python processes with minimal overhead. It can attach to - any Python process by PID and collect stack traces at regular intervals. - - :param int pid: Process ID of the target Python process - :param int sample_interval_usec: Sampling interval in microseconds - :param bool all_threads: Whether to sample all threads or just the main thread - - .. method:: sample(collector, duration_sec=10) - - Sample the target process for the specified duration. - - Collects stack traces from the target process at regular intervals - and passes them to the provided collector for processing. - - :param collector: Object that implements ``collect()`` method to process stack traces - :param int duration_sec: Duration to sample in seconds (default: 10) - - The method tracks sampling statistics and can display real-time - information if realtime_stats is enabled. - -.. seealso:: - - :ref:`sampling-profiler-cli` - Command-line interface documentation for the statistical profiler. - -Deterministic Profiler Command Line Interface -============================================= - -.. program:: cProfile - -The files :mod:`cProfile` and :mod:`profile` can also be invoked as a script to -profile another script. For example:: - - python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py) - -.. option:: -o - - Writes the profile results to a file instead of to stdout. - -.. option:: -s - - Specifies one of the :func:`~pstats.Stats.sort_stats` sort values - to sort the output by. - This only applies when :option:`-o ` is not supplied. - -.. option:: -m - - Specifies that a module is being profiled instead of a script. - - .. versionadded:: 3.7 - Added the ``-m`` option to :mod:`cProfile`. - - .. versionadded:: 3.8 - Added the ``-m`` option to :mod:`profile`. - -The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods -for manipulating and printing the data saved into a profile results file:: - - import pstats - from pstats import SortKey - p = pstats.Stats('restats') - p.strip_dirs().sort_stats(-1).print_stats() - -The :meth:`~pstats.Stats.strip_dirs` method removed the extraneous path from all -the module names. The :meth:`~pstats.Stats.sort_stats` method sorted all the -entries according to the standard module/line/name string that is printed. The -:meth:`~pstats.Stats.print_stats` method printed out all the statistics. You -might try the following sort calls:: - - p.sort_stats(SortKey.NAME) - p.print_stats() - -The first call will actually sort the list by function name, and the second call -will print out the statistics. The following are some interesting calls to -experiment with:: - - p.sort_stats(SortKey.CUMULATIVE).print_stats(10) - -This sorts the profile by cumulative time in a function, and then only prints -the ten most significant lines. If you want to understand what algorithms are -taking time, the above line is what you would use. - -If you were looking to see what functions were looping a lot, and taking a lot -of time, you would do:: - - p.sort_stats(SortKey.TIME).print_stats(10) - -to sort according to time spent within each function, and then print the -statistics for the top ten functions. - -You might also try:: - - p.sort_stats(SortKey.FILENAME).print_stats('__init__') - -This will sort all the statistics by file name, and then print out statistics -for only the class init methods (since they are spelled with ``__init__`` in -them). As one final example, you could try:: - - p.sort_stats(SortKey.TIME, SortKey.CUMULATIVE).print_stats(.5, 'init') - -This line sorts statistics with a primary key of time, and a secondary key of -cumulative time, and then prints out some of the statistics. To be specific, the -list is first culled down to 50% (re: ``.5``) of its original size, then only -lines containing ``init`` are maintained, and that sub-sub-list is printed. - -If you wondered what functions called the above functions, you could now (``p`` -is still sorted according to the last criteria) do:: - - p.print_callers(.5, 'init') - -and you would get a list of callers for each of the listed functions. - -If you want more functionality, you're going to have to read the manual, or -guess what the following functions do:: - - p.print_callees() - p.add('restats') - -Invoked as a script, the :mod:`pstats` module is a statistics browser for -reading and examining profile dumps. It has a simple line-oriented interface -(implemented using :mod:`cmd`) and interactive help. - -:mod:`profile` and :mod:`cProfile` Module Reference -======================================================= - -.. module:: cProfile -.. module:: profile - :synopsis: Python source profiler. - -Both the :mod:`profile` and :mod:`cProfile` modules provide the following -functions: +Both the :mod:`profile` and :mod:`profiling.tracing` modules provide the +following functions: .. function:: run(command, filename=None, sort=-1) @@ -545,7 +86,7 @@ functions: .. class:: Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True) This class is normally only used if more precise control over profiling is - needed than what the :func:`cProfile.run` function provides. + needed than what the :func:`profiling.tracing.run` function provides. A custom timer can be supplied for measuring how long code takes to run via the *timer* argument. This must be a function that returns a single number @@ -557,9 +98,12 @@ functions: Directly using the :class:`Profile` class allows formatting profile results without writing the profile data to a file:: - import cProfile, pstats, io + import profiling.tracing + import pstats + import io from pstats import SortKey - pr = cProfile.Profile() + + pr = profiling.tracing.Profile() pr.enable() # ... do something ... pr.disable() @@ -570,11 +114,12 @@ functions: print(s.getvalue()) The :class:`Profile` class can also be used as a context manager (supported - only in :mod:`cProfile` module. see :ref:`typecontextmanager`):: + only in :mod:`profiling.tracing`, not in the deprecated :mod:`profile` + module; see :ref:`typecontextmanager`):: - import cProfile + import profiling.tracing - with cProfile.Profile() as pr: + with profiling.tracing.Profile() as pr: # ... do something ... pr.print_stats() @@ -584,11 +129,11 @@ functions: .. method:: enable() - Start collecting profiling data. Only in :mod:`cProfile`. + Start collecting profiling data. Only in :mod:`profiling.tracing`. .. method:: disable() - Stop collecting profiling data. Only in :mod:`cProfile`. + Stop collecting profiling data. Only in :mod:`profiling.tracing`. .. method:: create_stats() @@ -602,7 +147,7 @@ functions: The *sort* parameter specifies the sorting order of the displayed statistics. It accepts a single key or a tuple of keys to enable - multi-level sorting, as in :func:`Stats.sort_stats `. + multi-level sorting, as in :meth:`pstats.Stats.sort_stats`. .. versionadded:: 3.13 :meth:`~Profile.print_stats` now accepts a tuple of keys. @@ -629,237 +174,43 @@ returns. If the interpreter is terminated (e.g. via a :func:`sys.exit` call during the called command/function execution) no profiling results will be printed. -.. _profile-stats: -The :class:`Stats` Class -======================== +Differences from :mod:`!profiling.tracing` +========================================== -Analysis of the profiler data is done using the :class:`~pstats.Stats` class. +The :mod:`profile` module differs from :mod:`profiling.tracing` in several +ways: -.. module:: pstats - :synopsis: Statistics object for use with the profiler. +**Higher overhead.** The pure Python implementation is significantly slower +than the C implementation, making it unsuitable for profiling long-running +programs or performance-sensitive code. -.. class:: Stats(*filenames or profile, stream=sys.stdout) +**Calibration support.** The :mod:`profile` module supports calibration to +compensate for profiling overhead. This is not needed in :mod:`profiling.tracing` +because the C implementation has negligible overhead. - This class constructor creates an instance of a "statistics object" from a - *filename* (or list of filenames) or from a :class:`Profile` instance. Output - will be printed to the stream specified by *stream*. +**Custom timers.** Both modules support custom timers, but :mod:`profile` +accepts timer functions that return tuples (like :func:`os.times`), while +:mod:`profiling.tracing` requires a function returning a single number. - The file selected by the above constructor must have been created by the - corresponding version of :mod:`profile` or :mod:`cProfile`. To be specific, - there is *no* file compatibility guaranteed with future versions of this - profiler, and there is no compatibility with files produced by other - profilers, or the same profiler run on a different operating system. If - several files are provided, all the statistics for identical functions will - be coalesced, so that an overall view of several processes can be considered - in a single report. If additional files need to be combined with data in an - existing :class:`~pstats.Stats` object, the :meth:`~pstats.Stats.add` method - can be used. +**Subclassing.** The pure Python implementation is easier to subclass and +extend for custom profiling behavior. - Instead of reading the profile data from a file, a :class:`cProfile.Profile` - or :class:`profile.Profile` object can be used as the profile data source. - - :class:`Stats` objects have the following methods: - - .. method:: strip_dirs() - - This method for the :class:`Stats` class removes all leading path - information from file names. It is very useful in reducing the size of - the printout to fit within (close to) 80 columns. This method modifies - the object, and the stripped information is lost. After performing a - strip operation, the object is considered to have its entries in a - "random" order, as it was just after object initialization and loading. - If :meth:`~pstats.Stats.strip_dirs` causes two function names to be - indistinguishable (they are on the same line of the same filename, and - have the same function name), then the statistics for these two entries - are accumulated into a single entry. - - - .. method:: add(*filenames) - - This method of the :class:`Stats` class accumulates additional profiling - information into the current profiling object. Its arguments should refer - to filenames created by the corresponding version of :func:`profile.run` - or :func:`cProfile.run`. Statistics for identically named (re: file, line, - name) functions are automatically accumulated into single function - statistics. - - - .. method:: dump_stats(filename) - - Save the data loaded into the :class:`Stats` object to a file named - *filename*. The file is created if it does not exist, and is overwritten - if it already exists. This is equivalent to the method of the same name - on the :class:`profile.Profile` and :class:`cProfile.Profile` classes. - - - .. method:: sort_stats(*keys) - - This method modifies the :class:`Stats` object by sorting it according to - the supplied criteria. The argument can be either a string or a SortKey - enum identifying the basis of a sort (example: ``'time'``, ``'name'``, - ``SortKey.TIME`` or ``SortKey.NAME``). The SortKey enums argument have - advantage over the string argument in that it is more robust and less - error prone. - - When more than one key is provided, then additional keys are used as - secondary criteria when there is equality in all keys selected before - them. For example, ``sort_stats(SortKey.NAME, SortKey.FILE)`` will sort - all the entries according to their function name, and resolve all ties - (identical function names) by sorting by file name. - - For the string argument, abbreviations can be used for any key names, as - long as the abbreviation is unambiguous. - - The following are the valid string and SortKey: - - +------------------+---------------------+----------------------+ - | Valid String Arg | Valid enum Arg | Meaning | - +==================+=====================+======================+ - | ``'calls'`` | SortKey.CALLS | call count | - +------------------+---------------------+----------------------+ - | ``'cumulative'`` | SortKey.CUMULATIVE | cumulative time | - +------------------+---------------------+----------------------+ - | ``'cumtime'`` | N/A | cumulative time | - +------------------+---------------------+----------------------+ - | ``'file'`` | N/A | file name | - +------------------+---------------------+----------------------+ - | ``'filename'`` | SortKey.FILENAME | file name | - +------------------+---------------------+----------------------+ - | ``'module'`` | N/A | file name | - +------------------+---------------------+----------------------+ - | ``'ncalls'`` | N/A | call count | - +------------------+---------------------+----------------------+ - | ``'pcalls'`` | SortKey.PCALLS | primitive call count | - +------------------+---------------------+----------------------+ - | ``'line'`` | SortKey.LINE | line number | - +------------------+---------------------+----------------------+ - | ``'name'`` | SortKey.NAME | function name | - +------------------+---------------------+----------------------+ - | ``'nfl'`` | SortKey.NFL | name/file/line | - +------------------+---------------------+----------------------+ - | ``'stdname'`` | SortKey.STDNAME | standard name | - +------------------+---------------------+----------------------+ - | ``'time'`` | SortKey.TIME | internal time | - +------------------+---------------------+----------------------+ - | ``'tottime'`` | N/A | internal time | - +------------------+---------------------+----------------------+ - - Note that all sorts on statistics are in descending order (placing most - time consuming items first), where as name, file, and line number searches - are in ascending order (alphabetical). The subtle distinction between - ``SortKey.NFL`` and ``SortKey.STDNAME`` is that the standard name is a - sort of the name as printed, which means that the embedded line numbers - get compared in an odd way. For example, lines 3, 20, and 40 would (if - the file names were the same) appear in the string order 20, 3 and 40. - In contrast, ``SortKey.NFL`` does a numeric compare of the line numbers. - In fact, ``sort_stats(SortKey.NFL)`` is the same as - ``sort_stats(SortKey.NAME, SortKey.FILENAME, SortKey.LINE)``. - - For backward-compatibility reasons, the numeric arguments ``-1``, ``0``, - ``1``, and ``2`` are permitted. They are interpreted as ``'stdname'``, - ``'calls'``, ``'time'``, and ``'cumulative'`` respectively. If this old - style format (numeric) is used, only one sort key (the numeric key) will - be used, and additional arguments will be silently ignored. - - .. For compatibility with the old profiler. - - .. versionadded:: 3.7 - Added the SortKey enum. - - .. method:: reverse_order() - - This method for the :class:`Stats` class reverses the ordering of the - basic list within the object. Note that by default ascending vs - descending order is properly selected based on the sort key of choice. - - .. This method is provided primarily for compatibility with the old - profiler. - - - .. method:: print_stats(*restrictions) - - This method for the :class:`Stats` class prints out a report as described - in the :func:`profile.run` definition. - - The order of the printing is based on the last - :meth:`~pstats.Stats.sort_stats` operation done on the object (subject to - caveats in :meth:`~pstats.Stats.add` and - :meth:`~pstats.Stats.strip_dirs`). - - The arguments provided (if any) can be used to limit the list down to the - significant entries. Initially, the list is taken to be the complete set - of profiled functions. Each restriction is either an integer (to select a - count of lines), or a decimal fraction between 0.0 and 1.0 inclusive (to - select a percentage of lines), or a string that will be interpreted as a - regular expression (to pattern match the standard name that is printed). - If several restrictions are provided, then they are applied sequentially. - For example:: - - print_stats(.1, 'foo:') - - would first limit the printing to first 10% of list, and then only print - functions that were part of filename :file:`.\*foo:`. In contrast, the - command:: - - print_stats('foo:', .1) - - would limit the list to all functions having file names :file:`.\*foo:`, - and then proceed to only print the first 10% of them. - - - .. method:: print_callers(*restrictions) - - This method for the :class:`Stats` class prints a list of all functions - that called each function in the profiled database. The ordering is - identical to that provided by :meth:`~pstats.Stats.print_stats`, and the - definition of the restricting argument is also identical. Each caller is - reported on its own line. The format differs slightly depending on the - profiler that produced the stats: - - * With :mod:`profile`, a number is shown in parentheses after each caller - to show how many times this specific call was made. For convenience, a - second non-parenthesized number repeats the cumulative time spent in the - function at the right. - - * With :mod:`cProfile`, each caller is preceded by three numbers: the - number of times this specific call was made, and the total and - cumulative times spent in the current function while it was invoked by - this specific caller. - - - .. method:: print_callees(*restrictions) - - This method for the :class:`Stats` class prints a list of all function - that were called by the indicated function. Aside from this reversal of - direction of calls (re: called vs was called by), the arguments and - ordering are identical to the :meth:`~pstats.Stats.print_callers` method. - - - .. method:: get_stats_profile() - - This method returns an instance of StatsProfile, which contains a mapping - of function names to instances of FunctionProfile. Each FunctionProfile - instance holds information related to the function's profile such as how - long the function took to run, how many times it was called, etc... - - .. versionadded:: 3.9 - Added the following dataclasses: StatsProfile, FunctionProfile. - Added the following function: get_stats_profile. .. _deterministic-profiling: -What Is Deterministic Profiling? +What is deterministic profiling? ================================ :dfn:`Deterministic profiling` is meant to reflect the fact that all *function call*, *function return*, and *exception* events are monitored, and precise timings are made for the intervals between these events (during which time the user's code is executing). In contrast, :dfn:`statistical profiling` (which is -provided by the :mod:`profile.sample` module) periodically samples the effective instruction pointer, and -deduces where time is being spent. The latter technique traditionally involves -less overhead (as the code does not need to be instrumented), but provides only -relative indications of where time is being spent. +provided by the :mod:`profiling.sampling` module) periodically samples the +effective instruction pointer, and deduces where time is being spent. The +latter technique traditionally involves less overhead (as the code does not +need to be instrumented), but provides only relative indications of where time +is being spent. In Python, since there is an interpreter active during execution, the presence of instrumented code is not required in order to do deterministic profiling. @@ -903,15 +254,16 @@ this error. The error that accumulates in this fashion is typically less than the accuracy of the clock (less than one clock tick), but it *can* accumulate and become very significant. -The problem is more important with :mod:`profile` than with the lower-overhead -:mod:`cProfile`. For this reason, :mod:`profile` provides a means of -calibrating itself for a given platform so that this error can be -probabilistically (on the average) removed. After the profiler is calibrated, it -will be more accurate (in a least square sense), but it will sometimes produce -negative numbers (when call counts are exceptionally low, and the gods of -probability work against you :-). ) Do *not* be alarmed by negative numbers in -the profile. They should *only* appear if you have calibrated your profiler, -and the results are actually better than without calibration. +The problem is more important with the deprecated :mod:`profile` module than +with the lower-overhead :mod:`profiling.tracing`. For this reason, +:mod:`profile` provides a means of calibrating itself for a given platform so +that this error can be probabilistically (on the average) removed. After the +profiler is calibrated, it will be more accurate (in a least square sense), but +it will sometimes produce negative numbers (when call counts are exceptionally +low, and the gods of probability work against you :-). ) Do *not* be alarmed +by negative numbers in the profile. They should *only* appear if you have +calibrated your profiler, and the results are actually better than without +calibration. .. _profile-calibration: @@ -957,6 +309,7 @@ When you have a consistent answer, there are three ways you can use it:: If you have a choice, you are better off choosing a smaller constant, and then your results will "less often" show up as negative in profile statistics. + .. _profile-timers: Using a custom timer @@ -969,7 +322,7 @@ to the :class:`Profile` class constructor:: pr = profile.Profile(your_time_func) The resulting profiler will then call ``your_time_func``. Depending on whether -you are using :class:`profile.Profile` or :class:`cProfile.Profile`, +you are using :class:`profile.Profile` or :class:`profiling.tracing.Profile`, ``your_time_func``'s return value will be interpreted differently: :class:`profile.Profile` @@ -988,20 +341,32 @@ you are using :class:`profile.Profile` or :class:`cProfile.Profile`, replacement dispatch method that best handles your timer call, along with the appropriate calibration constant. -:class:`cProfile.Profile` +:class:`profiling.tracing.Profile` ``your_time_func`` should return a single number. If it returns integers, you can also invoke the class constructor with a second argument specifying the real duration of one unit of time. For example, if ``your_integer_time_func`` returns times measured in thousands of seconds, you would construct the :class:`Profile` instance as follows:: - pr = cProfile.Profile(your_integer_time_func, 0.001) + pr = profiling.tracing.Profile(your_integer_time_func, 0.001) - As the :class:`cProfile.Profile` class cannot be calibrated, custom timer - functions should be used with care and should be as fast as possible. For - the best results with a custom timer, it might be necessary to hard-code it - in the C source of the internal :mod:`!_lsprof` module. + As the :class:`profiling.tracing.Profile` class cannot be calibrated, custom + timer functions should be used with care and should be as fast as possible. + For the best results with a custom timer, it might be necessary to hard-code + it in the C source of the internal :mod:`!_lsprof` module. Python 3.3 adds several new functions in :mod:`time` that can be used to make precise measurements of process or wall-clock time. For example, see :func:`time.perf_counter`. + + +.. seealso:: + + :mod:`profiling` + Overview of Python profiling tools. + + :mod:`profiling.tracing` + Recommended replacement for this module. + + :mod:`pstats` + Statistical analysis and formatting for profile data. diff --git a/Doc/library/profiling.rst b/Doc/library/profiling.rst new file mode 100644 index 00000000000..4b56d9c4b7b --- /dev/null +++ b/Doc/library/profiling.rst @@ -0,0 +1,270 @@ +.. highlight:: shell-session + +.. _profiling-module: + +*************************************** +:mod:`profiling` --- Python profilers +*************************************** + +.. module:: profiling + :synopsis: Python profiling tools for performance analysis. + +.. versionadded:: 3.15 + +**Source code:** :source:`Lib/profiling/` + +-------------- + +.. index:: + single: statistical profiling + single: profiling, statistical + single: deterministic profiling + single: profiling, deterministic + + +Introduction to profiling +========================= + +A :dfn:`profile` is a set of statistics that describes how often and for how +long various parts of a program execute. These statistics help identify +performance bottlenecks and guide optimization efforts. Python provides two +fundamentally different approaches to collecting this information: statistical +sampling and deterministic tracing. + +The :mod:`profiling` package organizes Python's built-in profiling tools under +a single namespace. It contains two submodules, each implementing a different +profiling methodology: + +:mod:`profiling.sampling` + A statistical profiler that periodically samples the call stack. Run scripts + directly or attach to running processes by PID. Provides multiple output + formats (flame graphs, heatmaps, Firefox Profiler), GIL analysis, GC tracking, + and multiple profiling modes (wall-clock, CPU, GIL) with virtually no overhead. + +:mod:`profiling.tracing` + A deterministic profiler that traces every function call, return, and + exception event. Provides exact call counts and precise timing information, + capturing every invocation including very fast functions. + +.. note:: + + The profiler modules are designed to provide an execution profile for a + given program, not for benchmarking purposes. For benchmarking, use the + :mod:`timeit` module, which provides reasonably accurate timing + measurements. This distinction is particularly important when comparing + Python code against C code: deterministic profilers introduce overhead for + Python code but not for C-level functions, which can skew comparisons. + + +.. _choosing-a-profiler: + +Choosing a profiler +=================== + +For most performance analysis, use the statistical profiler +(:mod:`profiling.sampling`). It has minimal overhead, works for both development +and production, and provides rich visualization options including flamegraphs, +heatmaps, GIL analysis, and more. + +Use the deterministic profiler (:mod:`profiling.tracing`) when you need **exact +call counts** and cannot afford to miss any function calls. Since it instruments +every function call and return, it will capture even very fast functions that +complete between sampling intervals. The tradeoff is higher overhead. + +The following table summarizes the key differences: + ++--------------------+------------------------------+------------------------------+ +| Feature | Statistical sampling | Deterministic | +| | (:mod:`profiling.sampling`) | (:mod:`profiling.tracing`) | ++====================+==============================+==============================+ +| **Overhead** | Virtually none | Moderate | ++--------------------+------------------------------+------------------------------+ +| **Accuracy** | Statistical estimate | Exact call counts | ++--------------------+------------------------------+------------------------------+ +| **Output formats** | pstats, flamegraph, heatmap, | pstats | +| | gecko, collapsed | | ++--------------------+------------------------------+------------------------------+ +| **Profiling modes**| Wall-clock, CPU, GIL | Wall-clock | ++--------------------+------------------------------+------------------------------+ +| **Special frames** | GC, native (C extensions) | N/A | ++--------------------+------------------------------+------------------------------+ +| **Attach to PID** | Yes | No | ++--------------------+------------------------------+------------------------------+ + + +When to use statistical sampling +-------------------------------- + +The statistical profiler (:mod:`profiling.sampling`) is recommended for most +performance analysis tasks. Use it the same way you would use +:mod:`profiling.tracing`:: + + python -m profiling.sampling run script.py + +One of the main strengths of the sampling profiler is its variety of output +formats. Beyond traditional pstats tables, it can generate interactive +flamegraphs that visualize call hierarchies, line-level source heatmaps that +show exactly where time is spent in your code, and Firefox Profiler output for +timeline-based analysis. + +The profiler also provides insight into Python interpreter behavior that +deterministic profiling cannot capture. Use ``--mode gil`` to identify GIL +contention in multi-threaded code, ``--mode cpu`` to measure actual CPU time +excluding I/O waits, or inspect ```` frames to understand garbage collection +overhead. The ``--native`` option reveals time spent in C extensions, helping +distinguish Python overhead from library performance. + +For multi-threaded applications, the ``-a`` option samples all threads +simultaneously, showing how work is distributed. And for production debugging, +the ``attach`` command connects to any running Python process by PID without +requiring a restart or code changes. + + +When to use deterministic tracing +--------------------------------- + +The deterministic profiler (:mod:`profiling.tracing`) instruments every function +call and return. This approach has higher overhead than sampling, but guarantees +complete coverage of program execution. + +The primary reason to choose deterministic tracing is when you need exact call +counts. Statistical profiling estimates frequency based on sampling, which may +undercount short-lived functions that complete between samples. If you need to +verify that an optimization actually reduced the number of function calls, or +if you want to trace the complete call graph to understand caller-callee +relationships, deterministic tracing is the right choice. + +Deterministic tracing also excels at capturing functions that execute in +microseconds. Such functions may not appear frequently enough in statistical +samples, but deterministic tracing records every invocation regardless of +duration. + + +Quick start +=========== + +This section provides the minimal steps needed to start profiling. For complete +documentation, see the dedicated pages for each profiler. + + +Statistical profiling +--------------------- + +To profile a script, use the :mod:`profiling.sampling` module with the ``run`` +command:: + + python -m profiling.sampling run script.py + python -m profiling.sampling run -m mypackage.module + +This runs the script under the profiler and prints a summary of where time was +spent. For an interactive flamegraph:: + + python -m profiling.sampling run --flamegraph script.py + +To profile an already-running process, use the ``attach`` command with the +process ID:: + + python -m profiling.sampling attach 1234 + +For custom settings, specify the sampling interval (in microseconds) and +duration (in seconds):: + + python -m profiling.sampling run -i 50 -d 30 script.py + + +Deterministic profiling +----------------------- + +To profile a script from the command line:: + + python -m profiling.tracing script.py + +To profile a piece of code programmatically: + +.. code-block:: python + + import profiling.tracing + profiling.tracing.run('my_function()') + +This executes the given code under the profiler and prints a summary showing +exact function call counts and timing. + + +.. _profile-output: + +Understanding profile output +============================ + +Both profilers collect function-level statistics, though they present them in +different formats. The sampling profiler offers multiple visualizations +(flamegraphs, heatmaps, Firefox Profiler, pstats tables), while the +deterministic profiler produces pstats-compatible output. Regardless of format, +the underlying concepts are the same. + +Key profiling concepts: + +**Direct time** (also called *self time* or *tottime*) + Time spent executing code in the function itself, excluding time spent in + functions it called. High direct time indicates the function contains + expensive operations. + +**Cumulative time** (also called *total time* or *cumtime*) + Time spent in the function and all functions it called. This measures the + total cost of calling a function, including its entire call subtree. + +**Call count** (also called *ncalls* or *samples*) + How many times the function was called (deterministic) or sampled + (statistical). In deterministic profiling, this is exact. In statistical + profiling, it represents the number of times the function appeared in a + stack sample. + +**Primitive calls** + Calls that are not induced by recursion. When a function recurses, the total + call count includes recursive invocations, but primitive calls counts only + the initial entry. Displayed as ``total/primitive`` (for example, ``3/1`` + means three total calls, one primitive). + +**Caller/Callee relationships** + Which functions called a given function (callers) and which functions it + called (callees). Flamegraphs visualize this as nested rectangles; pstats + can display it via the :meth:`~pstats.Stats.print_callers` and + :meth:`~pstats.Stats.print_callees` methods. + + +Legacy compatibility +==================== + +For backward compatibility, the ``cProfile`` module remains available as an +alias to :mod:`profiling.tracing`. Existing code using ``import cProfile`` will +continue to work without modification in all future Python versions. + +.. deprecated:: 3.15 + + The pure Python :mod:`profile` module is deprecated and will be removed in + Python 3.17. Use :mod:`profiling.tracing` (or its alias ``cProfile``) + instead. See :mod:`profile` for migration guidance. + + +.. seealso:: + + :mod:`profiling.sampling` + Statistical sampling profiler with flamegraphs, heatmaps, and GIL analysis. + Recommended for most users. + + :mod:`profiling.tracing` + Deterministic tracing profiler for exact call counts. + + :mod:`pstats` + Statistics analysis and formatting for profile data. + + :mod:`timeit` + Module for measuring execution time of small code snippets. + + +.. rubric:: Submodules + +.. toctree:: + :maxdepth: 1 + + profiling.tracing.rst + profiling.sampling.rst diff --git a/Doc/library/profiling.sampling.rst b/Doc/library/profiling.sampling.rst new file mode 100644 index 00000000000..1f60e2cb578 --- /dev/null +++ b/Doc/library/profiling.sampling.rst @@ -0,0 +1,1393 @@ +.. highlight:: shell-session + +.. _profiling-sampling: + +*************************************************** +:mod:`profiling.sampling` --- Statistical profiler +*************************************************** + +.. module:: profiling.sampling + :synopsis: Statistical sampling profiler for Python processes. + +.. versionadded:: 3.15 + +**Source code:** :source:`Lib/profiling/sampling/` + +.. program:: profiling.sampling + +-------------- + +.. image:: tachyon-logo.png + :alt: Tachyon logo + :align: center + :width: 300px + +The :mod:`profiling.sampling` module, named **Tachyon**, provides statistical +profiling of Python programs through periodic stack sampling. Tachyon can +run scripts directly or attach to any running Python process without requiring +code changes or restarts. Because sampling occurs externally to the target +process, overhead is virtually zero, making Tachyon suitable for both +development and production environments. + + +What is statistical profiling? +============================== + +Statistical profiling builds a picture of program behavior by periodically +capturing snapshots of the call stack. Rather than instrumenting every function +call and return as deterministic profilers do, Tachyon reads the call stack at +regular intervals to record what code is currently running. + +This approach rests on a simple principle: functions that consume significant +CPU time will appear frequently in the collected samples. By gathering thousands +of samples over a profiling session, Tachyon constructs an accurate statistical +estimate of where time is spent. The more samples collected, the +more precise this estimate becomes. + + +How time is estimated +--------------------- + +The time values shown in Tachyon's output are **estimates derived from sample +counts**, not direct measurements. Tachyon counts how many times each function +appears in the collected samples, then multiplies by the sampling interval to +estimate time. + +For example, with a 100 microsecond sampling interval over a 10-second profile, +Tachyon collects approximately 100,000 samples. If a function appears in 5,000 +samples (5% of total), Tachyon estimates it consumed 5% of the 10-second +duration, or about 500 milliseconds. This is a statistical estimate, not a +precise measurement. + +The accuracy of these estimates depends on sample count. With 100,000 samples, +a function showing 5% has a margin of error of roughly ±0.5%. With only 1,000 +samples, the same 5% measurement could actually represent anywhere from 3% to +7% of real time. + +This is why longer profiling durations and shorter sampling intervals produce +more reliable results---they collect more samples. For most performance +analysis, the default settings provide sufficient accuracy to identify +bottlenecks and guide optimization efforts. + +Because sampling is statistical, results will vary slightly between runs. A +function showing 12% in one run might show 11% or 13% in the next. This is +normal and expected. Focus on the overall pattern rather than exact percentages, +and don't worry about small variations between runs. + + +When to use a different approach +-------------------------------- + +Statistical sampling is not ideal for every situation. + +For very short scripts that complete in under one second, the profiler may not +collect enough samples for reliable results. Use :mod:`profiling.tracing` +instead, or run the script in a loop to extend profiling time. + +When you need exact call counts, sampling cannot provide them. Sampling +estimates frequency from snapshots, so if you need to know precisely how many +times a function was called, use :mod:`profiling.tracing`. + +When comparing two implementations where the difference might be only 1-2%, +sampling noise can obscure real differences. Use :mod:`timeit` for +micro-benchmarks or :mod:`profiling.tracing` for precise measurements. + + +The key difference from :mod:`profiling.tracing` is how measurement happens. +A tracing profiler instruments your code, recording every function call and +return. This provides exact call counts and precise timing but adds overhead +to every function call. A sampling profiler, by contrast, observes the program +from outside at fixed intervals without modifying its execution. Think of the +difference like this: tracing is like having someone follow you and write down +every step you take, while sampling is like taking photographs every second +and inferring your path from those snapshots. + +This external observation model is what makes sampling profiling practical for +production use. The profiled program runs at full speed because there is no +instrumentation code running inside it, and the target process is never stopped +or paused during sampling---Tachyon reads the call stack directly from the +process's memory while it continues to run. You can attach to a live server, +collect data, and detach without the application ever knowing it was observed. +The trade-off is that very short-lived functions may be missed if they happen +to complete between samples. + +Statistical profiling excels at answering the question, "Where is my program +spending time?" It reveals hotspots and bottlenecks in production code where +deterministic profiling overhead would be unacceptable. For exact call counts +and complete call graphs, use :mod:`profiling.tracing` instead. + + +Quick examples +============== + +Profile a script and see the results immediately:: + + python -m profiling.sampling run script.py + +Profile a module with arguments:: + + python -m profiling.sampling run -m mypackage.module arg1 arg2 + +Generate an interactive flame graph:: + + python -m profiling.sampling run --flamegraph -o profile.html script.py + +Attach to a running process by PID:: + + python -m profiling.sampling attach 12345 + +Use live mode for real-time monitoring (press ``q`` to quit):: + + python -m profiling.sampling run --live script.py + +Profile for 60 seconds with a faster sampling rate:: + + python -m profiling.sampling run -d 60 -i 50 script.py + +Generate a line-by-line heatmap:: + + python -m profiling.sampling run --heatmap script.py + +Enable opcode-level profiling to see which bytecode instructions are executing:: + + python -m profiling.sampling run --opcodes --flamegraph script.py + + +Commands +======== + +Tachyon operates through two subcommands that determine how to obtain the +target process. + + +The ``run`` command +------------------- + +The ``run`` command launches a Python script or module and profiles it from +startup:: + + python -m profiling.sampling run script.py + python -m profiling.sampling run -m mypackage.module + +When profiling a script, the profiler starts the target in a subprocess, waits +for it to initialize, then begins collecting samples. The ``-m`` flag +indicates that the target should be run as a module (equivalent to +``python -m``). Arguments after the target are passed through to the +profiled program:: + + python -m profiling.sampling run script.py --config settings.yaml + + +The ``attach`` command +---------------------- + +The ``attach`` command connects to an already-running Python process by its +process ID:: + + python -m profiling.sampling attach 12345 + +This command is particularly valuable for investigating performance issues in +production systems. The target process requires no modification and need not +be restarted. The profiler attaches, collects samples for the specified +duration, then detaches and produces output. + +:: + + python -m profiling.sampling attach --live 12345 + python -m profiling.sampling attach --flamegraph -d 30 -o profile.html 12345 + +On most systems, attaching to another process requires appropriate permissions. +See :ref:`profiling-permissions` for platform-specific requirements. + + +Profiling in production +----------------------- + +The sampling profiler is designed for production use. It imposes no measurable +overhead on the target process because it reads memory externally rather than +instrumenting code. The target application continues running at full speed and +is unaware it is being profiled. + +When profiling production systems, keep these guidelines in mind: + +Start with shorter durations (10-30 seconds) to get quick results, then extend +if you need more statistical accuracy. The default 10-second duration is usually +sufficient to identify major hotspots. + +If possible, profile during representative load rather than peak traffic. +Profiles collected during normal operation are easier to interpret than those +collected during unusual spikes. + +The profiler itself consumes some CPU on the machine where it runs (not on the +target process). On the same machine, this is typically negligible. When +profiling remote processes, network latency does not affect the target. + +Results from production may differ from development due to different data +sizes, concurrent load, or caching effects. This is expected and is often +exactly what you want to capture. + + +.. _profiling-permissions: + +Platform requirements +--------------------- + +The profiler reads the target process's memory to capture stack traces. This +requires elevated permissions on most operating systems. + +**Linux** + +On Linux, the profiler uses ``ptrace`` or ``process_vm_readv`` to read the +target process's memory. This typically requires one of: + +- Running as root +- Having the ``CAP_SYS_PTRACE`` capability +- Adjusting the Yama ptrace scope: ``/proc/sys/kernel/yama/ptrace_scope`` + +The default ptrace_scope of 1 restricts ptrace to parent processes only. To +allow attaching to any process owned by the same user, set it to 0:: + + echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope + +**macOS** + +On macOS, the profiler uses ``task_for_pid()`` to access the target process. +This requires one of: + +- Running as root +- The profiler binary having the ``com.apple.security.cs.debugger`` entitlement +- System Integrity Protection (SIP) being disabled (not recommended) + +**Windows** + +On Windows, the profiler requires administrative privileges or the +``SeDebugPrivilege`` privilege to read another process's memory. + + +Version compatibility +--------------------- + +The profiler and target process must run the same Python minor version (for +example, both Python 3.15). Attaching from Python 3.14 to a Python 3.15 process +is not supported. + +Additional restrictions apply to pre-release Python versions: if either the +profiler or target is running a pre-release (alpha, beta, or release candidate), +both must run the exact same version. + +On free-threaded Python builds, the profiler cannot attach from a free-threaded +build to a standard build, or vice versa. + + +Sampling configuration +====================== + +Before exploring the various output formats and visualization options, it is +important to understand how to configure the sampling process itself. The +profiler offers several options that control how frequently samples are +collected, how long profiling runs, which threads are observed, and what +additional context is captured in each sample. + +The default configuration works well for most use cases: + +.. list-table:: + :header-rows: 1 + :widths: 25 75 + + * - Option + - Default + * - Default for ``--interval`` / ``-i`` + - 100 µs between samples (~10,000 samples/sec) + * - Default for ``--duration`` / ``-d`` + - 10 seconds + * - Default for ``--all-threads`` / ``-a`` + - Main thread only + * - Default for ``--native`` + - No ```` frames (C code time attributed to caller) + * - Default for ``--no-gc`` + - ```` frames included when garbage collection is active + * - Default for ``--mode`` + - Wall-clock mode (all samples recorded) + * - Default for ``--realtime-stats`` + - Disabled + * - Default for ``--subprocesses`` + - Disabled + + +Sampling interval and duration +------------------------------ + +The two most fundamental parameters are the sampling interval and duration. +Together, these determine how many samples will be collected during a profiling +session. + +The :option:`--interval` option (:option:`-i`) sets the time between samples in +microseconds. The default is 100 microseconds, which produces approximately +10,000 samples per second:: + + python -m profiling.sampling run -i 50 script.py + +Lower intervals capture more samples and provide finer-grained data at the +cost of slightly higher profiler CPU usage. Higher intervals reduce profiler +overhead but may miss short-lived functions. For most applications, the +default interval provides a good balance between accuracy and overhead. + +The :option:`--duration` option (:option:`-d`) sets how long to profile in seconds. The +default is 10 seconds:: + + python -m profiling.sampling run -d 60 script.py + +Longer durations collect more samples and produce more statistically reliable +results, especially for code paths that execute infrequently. When profiling +a program that runs for a fixed time, you may want to set the duration to +match or exceed the expected runtime. + + +Thread selection +---------------- + +Python programs often use multiple threads, whether explicitly through the +:mod:`threading` module or implicitly through libraries that manage thread +pools. + +By default, the profiler samples only the main thread. The :option:`--all-threads` +option (:option:`-a`) enables sampling of all threads in the process:: + + python -m profiling.sampling run -a script.py + +Multi-thread profiling reveals how work is distributed across threads and can +identify threads that are blocked or starved. Each thread's samples are +combined in the output, with the ability to filter by thread in some formats. +This option is particularly useful when investigating concurrency issues or +when work is distributed across a thread pool. + + +Special frames +-------------- + +The profiler can inject artificial frames into the captured stacks to provide +additional context about what the interpreter is doing at the moment each +sample is taken. These synthetic frames help distinguish different types of +execution that would otherwise be invisible. + +The :option:`--native` option adds ```` frames to indicate when Python has +called into C code (extension modules, built-in functions, or the interpreter +itself):: + + python -m profiling.sampling run --native script.py + +These frames help distinguish time spent in Python code versus time spent in +native libraries. Without this option, native code execution appears as time +in the Python function that made the call. This is useful when optimizing +code that makes heavy use of C extensions like NumPy or database drivers. + +By default, the profiler includes ```` frames when garbage collection is +active. The :option:`--no-gc` option suppresses these frames:: + + python -m profiling.sampling run --no-gc script.py + +GC frames help identify programs where garbage collection consumes significant +time, which may indicate memory allocation patterns worth optimizing. If you +see substantial time in ```` frames, consider investigating object +allocation rates or using object pooling. + + +Opcode-aware profiling +---------------------- + +The :option:`--opcodes` option enables instruction-level profiling that captures +which Python bytecode instructions are executing at each sample:: + + python -m profiling.sampling run --opcodes --flamegraph script.py + +This feature provides visibility into Python's bytecode execution, including +adaptive specialization optimizations. When a generic instruction like +``LOAD_ATTR`` is specialized at runtime into a more efficient variant like +``LOAD_ATTR_INSTANCE_VALUE``, the profiler shows both the specialized name +and the base instruction. + +Opcode information appears in several output formats: + +- **Flame graphs**: Hovering over a frame displays a tooltip with a bytecode + instruction breakdown, showing which opcodes consumed time in that function +- **Heatmap**: Expandable bytecode panels per source line show instruction + breakdown with specialization percentages +- **Live mode**: An opcode panel shows instruction-level statistics for the + selected function, accessible via keyboard navigation +- **Gecko format**: Opcode transitions are emitted as interval markers in the + Firefox Profiler timeline + +This level of detail is particularly useful for: + +- Understanding the performance impact of Python's adaptive specialization +- Identifying hot bytecode instructions that might benefit from optimization +- Analyzing the effectiveness of different code patterns at the instruction level +- Debugging performance issues that occur at the bytecode level + +The :option:`--opcodes` option is compatible with :option:`--live`, :option:`--flamegraph`, +:option:`--heatmap`, and :option:`--gecko` formats. It requires additional memory to store +opcode information and may slightly reduce sampling performance, but provides +unprecedented visibility into Python's execution model. + + +Real-time statistics +-------------------- + +The :option:`--realtime-stats` option displays sampling rate statistics during +profiling:: + + python -m profiling.sampling run --realtime-stats script.py + +This shows the actual achieved sampling rate, which may be lower than requested +if the profiler cannot keep up. The statistics help verify that profiling is +working correctly and that sufficient samples are being collected. See +:ref:`sampling-efficiency` for details on interpreting these metrics. + + +Subprocess profiling +-------------------- + +The :option:`--subprocesses` option enables automatic profiling of subprocesses +spawned by the target:: + + python -m profiling.sampling run --subprocesses script.py + python -m profiling.sampling attach --subprocesses 12345 + +When enabled, the profiler monitors the target process for child process +creation. When a new Python child process is detected, a separate profiler +instance is automatically spawned to profile it. This is useful for +applications that use :mod:`multiprocessing`, :mod:`subprocess`, +:mod:`concurrent.futures` with :class:`~concurrent.futures.ProcessPoolExecutor`, +or other process spawning mechanisms. + +.. code-block:: python + :caption: worker_pool.py + + from concurrent.futures import ProcessPoolExecutor + import math + + def compute_factorial(n): + total = 0 + for i in range(50): + total += math.factorial(n) + return total + + if __name__ == "__main__": + numbers = [5000 + i * 100 for i in range(50)] + with ProcessPoolExecutor(max_workers=4) as executor: + results = list(executor.map(compute_factorial, numbers)) + print(f"Computed {len(results)} factorials") + +:: + + python -m profiling.sampling run --subprocesses --flamegraph worker_pool.py + +This produces separate flame graphs for the main process and each worker +process: ``flamegraph_.html``, ``flamegraph_.html``, +and so on. + +Each subprocess receives its own output file. The filename is derived from +the specified output path (or the default) with the subprocess's process ID +appended: + +- If you specify ``-o profile.html``, subprocesses produce ``profile_12345.html``, + ``profile_12346.html``, and so on +- With default output, subprocesses produce files like ``flamegraph_12345.html`` + or directories like ``heatmap_12345`` +- For pstats format (which defaults to stdout), subprocesses produce files like + ``profile_12345.pstats`` + +The subprocess profilers inherit most sampling options from the parent (interval, +duration, thread selection, native frames, GC frames, async-aware mode, and +output format). All Python descendant processes are profiled recursively, +including grandchildren and further descendants. + +Subprocess detection works by periodically scanning for new descendants of +the target process and checking whether each new process is a Python process +by probing the process memory for Python runtime structures. Non-Python +subprocesses (such as shell commands or external tools) are ignored. + +There is a limit of 100 concurrent subprocess profilers to prevent resource +exhaustion in programs that spawn many processes. If this limit is reached, +additional subprocesses are not profiled and a warning is printed. + +The :option:`--subprocesses` option is incompatible with :option:`--live` mode +because live mode uses an interactive terminal interface that cannot +accommodate multiple concurrent profiler displays. + + +.. _sampling-efficiency: + +Sampling efficiency +------------------- + +Sampling efficiency metrics help assess the quality of the collected data. +These metrics appear in the profiler's terminal output and in the flame graph +sidebar. + +**Sampling efficiency** is the percentage of sample attempts that succeeded. +Each sample attempt reads the target process's call stack from memory. An +attempt can fail if the process is in an inconsistent state at the moment of +reading, such as during a context switch or while the interpreter is updating +its internal structures. A low efficiency may indicate that the profiler could +not keep up with the requested sampling rate, often due to system load or an +overly aggressive interval setting. + +**Missed samples** is the percentage of expected samples that were not +collected. Based on the configured interval and duration, the profiler expects +to collect a certain number of samples. Some samples may be missed if the +profiler falls behind schedule, for example when the system is under heavy +load. A small percentage of missed samples is normal and does not significantly +affect the statistical accuracy of the profile. + +Both metrics are informational. Even with some failed attempts or missed +samples, the profile remains statistically valid as long as enough samples +were collected. The profiler reports the actual number of samples captured, +which you can use to judge whether the data is sufficient for your analysis. + + +Profiling modes +=============== + +The sampling profiler supports four modes that control which samples are +recorded. The mode determines what the profile measures: total elapsed time, +CPU execution time, time spent holding the global interpreter lock, or +exception handling. + + +Wall-clock mode +--------------- + +Wall-clock mode (:option:`--mode`\ ``=wall``) captures all samples regardless of what the +thread is doing. This is the default mode and provides a complete picture of +where time passes during program execution:: + + python -m profiling.sampling run --mode=wall script.py + +In wall-clock mode, samples are recorded whether the thread is actively +executing Python code, waiting for I/O, blocked on a lock, or sleeping. +This makes wall-clock profiling ideal for understanding the overall time +distribution in your program, including time spent waiting. + +If your program spends significant time in I/O operations, network calls, or +sleep, wall-clock mode will show these waits as time attributed to the calling +function. This is often exactly what you want when optimizing end-to-end +latency. + + +CPU mode +-------- + +CPU mode (:option:`--mode`\ ``=cpu``) records samples only when the thread is actually +executing on a CPU core:: + + python -m profiling.sampling run --mode=cpu script.py + +Samples taken while the thread is sleeping, blocked on I/O, or waiting for +a lock are discarded. The resulting profile shows where CPU cycles are consumed, +filtering out idle time. + +CPU mode is useful when you want to focus on computational hotspots without +being distracted by I/O waits. If your program alternates between computation +and network calls, CPU mode reveals which computational sections are most +expensive. + + +Comparing wall-clock and CPU profiles +------------------------------------- + +Running both wall-clock and CPU mode profiles can reveal whether a function's +time is spent computing or waiting. + +If a function appears prominently in both profiles, it is a true computational +hotspot---actively using the CPU. Optimization should focus on algorithmic +improvements or more efficient code. + +If a function is high in wall-clock mode but low or absent in CPU mode, it is +I/O-bound or waiting. The function spends most of its time waiting for network, +disk, locks, or sleep. CPU optimization won't help here; consider async I/O, +connection pooling, or reducing wait time instead. + +.. code-block:: python + + import time + + def do_sleep(): + time.sleep(2) + + def do_compute(): + sum(i**2 for i in range(1000000)) + + if __name__ == "__main__": + do_sleep() + do_compute() + +:: + + python -m profiling.sampling run --mode=wall script.py # do_sleep ~98%, do_compute ~1% + python -m profiling.sampling run --mode=cpu script.py # do_sleep absent, do_compute dominates + + +GIL mode +-------- + +GIL mode (:option:`--mode`\ ``=gil``) records samples only when the thread holds Python's +global interpreter lock:: + + python -m profiling.sampling run --mode=gil script.py + +The GIL is held only while executing Python bytecode. When Python calls into +C extensions, performs I/O operations, or executes native code, the GIL is +typically released. This means GIL mode effectively measures time spent +running Python code specifically, filtering out time in native libraries. + +In multi-threaded programs, GIL mode reveals which code is preventing other +threads from running Python bytecode. Since only one thread can hold the GIL +at a time, functions that appear frequently in GIL mode profiles are +monopolizing the interpreter. + +GIL mode helps answer questions like "which functions are monopolizing the +GIL?" and "why are my other threads starving?" It can also be useful in +single-threaded programs to distinguish Python execution time from time spent +in C extensions or I/O. + +.. code-block:: python + + import hashlib + + def hash_work(): + # C extension - releases GIL during computation + for _ in range(200): + hashlib.sha256(b"data" * 250000).hexdigest() + + def python_work(): + # Pure Python - holds GIL during computation + for _ in range(3): + sum(i**2 for i in range(1000000)) + + if __name__ == "__main__": + hash_work() + python_work() + +:: + + python -m profiling.sampling run --mode=cpu script.py # hash_work ~42%, python_work ~38% + python -m profiling.sampling run --mode=gil script.py # hash_work ~5%, python_work ~60% + + +Exception mode +-------------- + +Exception mode (``--mode=exception``) records samples only when a thread has +an active exception:: + + python -m profiling.sampling run --mode=exception script.py + +Samples are recorded in two situations: when an exception is being propagated +up the call stack (after ``raise`` but before being caught), or when code is +executing inside an ``except`` block where exception information is still +present in the thread state. + +The following example illustrates which code regions are captured: + +.. code-block:: python + + def example(): + try: + raise ValueError("error") # Captured: exception being raised + except ValueError: + process_error() # Captured: inside except block + finally: + cleanup() # NOT captured: exception already handled + + def example_propagating(): + try: + try: + raise ValueError("error") + finally: + cleanup() # Captured: exception propagating through + except ValueError: + pass + + def example_no_exception(): + try: + do_work() + finally: + cleanup() # NOT captured: no exception involved + +Note that ``finally`` blocks are only captured when an exception is actively +propagating through them. Once an ``except`` block finishes executing, Python +clears the exception information before running any subsequent ``finally`` +block. Similarly, ``finally`` blocks that run during normal execution (when no +exception was raised) are not captured because no exception state is present. + +This mode is useful for understanding where your program spends time handling +errors. Exception handling can be a significant source of overhead in code +that uses exceptions for flow control (such as ``StopIteration`` in iterators) +or in applications that process many error conditions (such as network servers +handling connection failures). + +Exception mode helps answer questions like "how much time is spent handling +exceptions?" and "which exception handlers are the most expensive?" It can +reveal hidden performance costs in code that catches and processes many +exceptions, even when those exceptions are handled gracefully. For example, +if a parsing library uses exceptions internally to signal format errors, this +mode will capture time spent in those handlers even if the calling code never +sees the exceptions. + + +Output formats +============== + +The profiler produces output in several formats, each suited to different +analysis workflows. The format is selected with a command-line flag, and +output goes to stdout, a file, or a directory depending on the format. + + +pstats format +------------- + +The pstats format (:option:`--pstats`) produces a text table similar to what +deterministic profilers generate. This is the default output format:: + + python -m profiling.sampling run script.py + python -m profiling.sampling run --pstats script.py + +.. figure:: tachyon-pstats.png + :alt: Tachyon pstats terminal output + :align: center + :width: 100% + + The pstats format displays profiling results in a color-coded table showing + function hotspots, sample counts, and timing estimates. + +Output appears on stdout by default:: + + Profile Stats (Mode: wall): + nsamples sample% tottime (ms) cumul% cumtime (ms) filename:lineno(function) + 234/892 11.7% 234.00 44.6% 892.00 server.py:145(handle_request) + 156/156 7.8% 156.00 7.8% 156.00 :0(socket.recv) + 98/421 4.9% 98.00 21.1% 421.00 parser.py:67(parse_message) + +The columns show sampling counts and estimated times: + +- **nsamples**: Displayed as ``direct/cumulative`` (for example, ``10/50``). + Direct samples are when the function was at the top of the stack, actively + executing. Cumulative samples are when the function appeared anywhere on the + stack, including when it was waiting for functions it called. If a function + shows ``10/50``, it was directly executing in 10 samples and was on the call + stack in 50 samples total. + +- **sample%** and **cumul%**: Percentages of total samples for direct and + cumulative counts respectively. + +- **tottime** and **cumtime**: Estimated wall-clock time based on sample counts + and the profiling duration. Time units are selected automatically based on + the magnitude: seconds for large values, milliseconds for moderate values, + or microseconds for small values. + +The output includes a legend explaining each column and a summary of +interesting functions that highlights: + +- **Hot spots**: Functions with high direct/cumulative sample ratio (ratio + close to 1.0). These functions spend most of their time executing their own + code rather than waiting for callees. High ratios indicate where CPU time + is actually consumed. + +- **Indirect calls**: Functions with large differences between cumulative and + direct samples. These are orchestration functions that delegate work to + other functions. They appear frequently on the stack but rarely at the top. + +- **Call magnification**: Functions where cumulative samples far exceed direct + samples (high cumulative/direct multiplier). These are frequently-nested + functions that appear deep in many call chains. + +Use :option:`--no-summary` to suppress both the legend and summary sections. + +To save pstats output to a file instead of stdout:: + + python -m profiling.sampling run -o profile.txt script.py + +The pstats format supports several options for controlling the display. +The :option:`--sort` option determines the column used for ordering results:: + + python -m profiling.sampling run --sort=tottime script.py + python -m profiling.sampling run --sort=cumtime script.py + python -m profiling.sampling run --sort=nsamples script.py + +The :option:`--limit` option restricts output to the top N entries:: + + python -m profiling.sampling run --limit=30 script.py + +The :option:`--no-summary` option suppresses the header summary that precedes the +statistics table. + + +Collapsed stacks format +----------------------- + +Collapsed stacks format (:option:`--collapsed`) produces one line per unique call +stack, with a count of how many times that stack was sampled:: + + python -m profiling.sampling run --collapsed script.py + +The output looks like: + +.. code-block:: text + + main;process_data;parse_json;decode_utf8 42 + main;process_data;parse_json 156 + main;handle_request;send_response 89 + +Each line contains semicolon-separated function names representing the call +stack from bottom to top, followed by a space and the sample count. This +format is designed for compatibility with external flame graph tools, +particularly Brendan Gregg's ``flamegraph.pl`` script. + +To generate a flame graph from collapsed stacks:: + + python -m profiling.sampling run --collapsed script.py > stacks.txt + flamegraph.pl stacks.txt > profile.svg + +The resulting SVG can be viewed in any web browser and provides an interactive +visualization where you can click to zoom into specific call paths. + + +Flame graph format +------------------ + +Flame graph format (:option:`--flamegraph`) produces a self-contained HTML file with +an interactive flame graph visualization:: + + python -m profiling.sampling run --flamegraph script.py + python -m profiling.sampling run --flamegraph -o profile.html script.py + +.. figure:: tachyon-flamegraph.png + :alt: Tachyon interactive flame graph + :align: center + :width: 100% + + The flame graph visualization shows call stacks as nested rectangles, with + width proportional to time spent. The sidebar displays runtime statistics, + GIL metrics, and hotspot functions. + +.. only:: html + + `Try the interactive example <../_static/tachyon-example-flamegraph.html>`__! + +If no output file is specified, the profiler generates a filename based on +the process ID (for example, ``flamegraph.12345.html``). + +The generated HTML file requires no external dependencies and can be opened +directly in a web browser. The visualization displays call stacks as nested +rectangles, with width proportional to time spent. Hovering over a rectangle +shows details about that function including source code context, and clicking +zooms into that portion of the call tree. + +The flame graph interface includes: + +- A sidebar showing profile summary, thread statistics, sampling efficiency + metrics (see :ref:`sampling-efficiency`), and top hotspot functions +- Search functionality supporting both function name matching and + ``file.py:42`` line patterns +- Per-thread filtering via dropdown +- Dark/light theme toggle (preference saved across sessions) +- SVG export for saving the current view + +The thread statistics section shows runtime behavior metrics: + +- **GIL Held**: percentage of samples where a thread held the global interpreter + lock (actively running Python code) +- **GIL Released**: percentage of samples where no thread held the GIL +- **Waiting GIL**: percentage of samples where a thread was waiting to acquire + the GIL +- **GC**: percentage of samples during garbage collection + +These statistics help identify GIL contention and understand how time is +distributed between Python execution, native code, and waiting. + +Flame graphs are particularly effective for identifying deep call stacks and +understanding the hierarchical structure of time consumption. Wide rectangles +at the top indicate functions that consume significant time either directly +or through their callees. + + +Gecko format +------------ + +Gecko format (:option:`--gecko`) produces JSON output compatible with the Firefox +Profiler:: + + python -m profiling.sampling run --gecko script.py + python -m profiling.sampling run --gecko -o profile.json script.py + +The `Firefox Profiler `__ is a sophisticated +web-based tool originally built for profiling Firefox itself. It provides +features beyond basic flame graphs, including a timeline view, call tree +exploration, and marker visualization. See the +`Firefox Profiler documentation `__ for +detailed usage instructions. + +To use the output, open the Firefox Profiler in your browser and load the +JSON file. The profiler runs entirely client-side, so your profiling data +never leaves your machine. + +Gecko format automatically collects additional metadata about GIL state and +CPU activity, enabling analysis features specific to Python's threading model. +The profiler emits interval markers that appear as colored bands in the +Firefox Profiler timeline: + +- **GIL markers**: show when threads hold or release the global interpreter lock +- **CPU markers**: show when threads are executing on CPU versus idle +- **Code type markers**: distinguish Python code from native (C extension) code +- **GC markers**: indicate garbage collection activity + +For this reason, the :option:`--mode` option is not available with Gecko format; +all relevant data is captured automatically. + +.. figure:: tachyon-gecko-calltree.png + :alt: Firefox Profiler Call Tree view + :align: center + :width: 100% + + The Call Tree view shows the complete call hierarchy with sample counts + and percentages. The sidebar displays detailed statistics for the + selected function including running time and sample distribution. + +.. figure:: tachyon-gecko-flamegraph.png + :alt: Firefox Profiler Flame Graph view + :align: center + :width: 100% + + The Flame Graph visualization shows call stacks as nested rectangles. + Functions names are visible in the call hierarchy. + +.. figure:: tachyon-gecko-opcodes.png + :alt: Firefox Profiler Marker Chart with opcodes + :align: center + :width: 100% + + The Marker Chart displays interval markers including CPU state, GIL + status, and opcodes. With ``--opcodes`` enabled, bytecode instructions + like ``BINARY_OP_ADD_FLOAT``, ``CALL_PY_EXACT_ARGS``, and + ``CALL_LIST_APPEND`` appear as markers showing execution over time. + + +Heatmap format +-------------- + +Heatmap format (:option:`--heatmap`) generates an interactive HTML visualization +showing sample counts at the source line level:: + + python -m profiling.sampling run --heatmap script.py + python -m profiling.sampling run --heatmap -o my_heatmap script.py + +.. figure:: tachyon-heatmap.png + :alt: Tachyon heatmap visualization + :align: center + :width: 100% + + The heatmap overlays sample counts directly on your source code. Lines are + color-coded from cool (few samples) to hot (many samples). Navigation + buttons (▲▼) let you jump between callers and callees. + +Unlike other formats that produce a single file, heatmap output creates a +directory containing HTML files for each profiled source file. If no output +path is specified, the directory is named ``heatmap_PID``. + +The heatmap visualization displays your source code with a color gradient +indicating how many samples were collected at each line. Hot lines (many +samples) appear in warm colors, while cold lines (few or no samples) appear +in cool colors. This view helps pinpoint exactly which lines of code are +responsible for time consumption. + +The heatmap interface provides several interactive features: + +- **Coloring modes**: toggle between "Self Time" (direct execution) and + "Total Time" (cumulative, including time in called functions) +- **Cold code filtering**: show all lines or only lines with samples +- **Call graph navigation**: each line shows navigation buttons (▲ for callers, + ▼ for callees) that let you trace execution paths through your code. When + multiple functions called or were called from a line, a menu appears showing + all options with their sample counts. +- **Scroll minimap**: a vertical overview showing the heat distribution across + the entire file +- **Hierarchical index**: files organized by type (stdlib, site-packages, + project) with aggregate sample counts per folder +- **Dark/light theme**: toggle with preference saved across sessions +- **Line linking**: click line numbers to create shareable URLs + +When opcode-level profiling is enabled with :option:`--opcodes`, each hot line +can be expanded to show which bytecode instructions consumed time: + +.. figure:: tachyon-heatmap-with-opcodes.png + :alt: Heatmap with expanded bytecode panel + :align: center + :width: 100% + + Expanding a hot line reveals the bytecode instructions executed, including + specialized variants. The panel shows sample counts per instruction and the + overall specialization percentage for the line. + +.. only:: html + + `Try the interactive example <../_static/tachyon-example-heatmap.html>`__! + +Heatmaps are especially useful when you know which file contains a performance +issue but need to identify the specific lines. Many developers prefer this +format because it maps directly to their source code, making it easy to read +and navigate. For smaller scripts and focused analysis, heatmaps provide an +intuitive view that shows exactly where time is spent without requiring +interpretation of hierarchical visualizations. + + +Live mode +========= + +Live mode (:option:`--live`) provides a terminal-based real-time view of profiling +data, similar to the ``top`` command for system processes:: + + python -m profiling.sampling run --live script.py + python -m profiling.sampling attach --live 12345 + +.. figure:: tachyon-live-mode-2.gif + :alt: Tachyon live mode showing all threads + :align: center + :width: 100% + + Live mode displays real-time profiling statistics, showing combined + data from multiple threads in a multi-threaded application. + +The display updates continuously as new samples arrive, showing the current +hottest functions. This mode requires the :mod:`curses` module, which is +available on Unix-like systems but not on Windows. The terminal must be at +least 60 columns wide and 12 lines tall; larger terminals display more columns. + +The header displays the top 3 hottest functions, sampling efficiency metrics, +and thread status statistics (GIL held percentage, CPU usage, GC time). The +main table shows function statistics with the currently sorted column indicated +by an arrow (▼). + +When :option:`--opcodes` is enabled, an additional opcode panel appears below the +main table, showing instruction-level statistics for the currently selected +function. This panel displays which bytecode instructions are executing most +frequently, including specialized variants and their base opcodes. + +.. figure:: tachyon-live-mode-1.gif + :alt: Tachyon live mode with opcode panel + :align: center + :width: 100% + + Live mode with ``--opcodes`` enabled shows an opcode panel with a bytecode + instruction breakdown for the selected function. + + +Keyboard commands +----------------- + +Within live mode, keyboard commands control the display: + +:kbd:`q` + Quit the profiler and return to the shell. + +:kbd:`s` / :kbd:`S` + Cycle through sort orders forward/backward (sample count, percentage, + total time, cumulative percentage, cumulative time). + +:kbd:`p` + Pause or resume display updates. Sampling continues in the background + while the display is paused, so you can freeze the view to examine results + without stopping data collection. + +:kbd:`r` + Reset all statistics and start fresh. This is disabled after profiling + finishes to prevent accidental data loss. + +:kbd:`/` + Enter filter mode to search for functions by name. The filter uses + case-insensitive substring matching against the filename and function name. + Type a pattern and press Enter to apply, or Escape to cancel. Glob patterns + and regular expressions are not supported. + +:kbd:`c` + Clear the current filter and show all functions again. + +:kbd:`t` + Toggle between viewing all threads combined or per-thread statistics. + In per-thread mode, a thread counter (for example, ``1/4``) appears showing + your position among the available threads. + +:kbd:`←` :kbd:`→` or :kbd:`↑` :kbd:`↓` + In per-thread view, navigate between threads. Navigation wraps around + from the last thread to the first and vice versa. + +:kbd:`+` / :kbd:`-` + Increase or decrease the display refresh rate. The range is 0.05 seconds + (20 Hz, very responsive) to 1.0 second (1 Hz, lower overhead). Faster refresh + rates use more CPU. The default is 0.1 seconds (10 Hz). + +:kbd:`x` + Toggle trend indicators that show whether functions are becoming hotter + or cooler over time. When enabled, increasing metrics appear in green and + decreasing metrics appear in red, comparing each update to the previous one. + +:kbd:`h` or :kbd:`?` + Show the help screen with all available commands. + +:kbd:`j` / :kbd:`k` (or :kbd:`Up` / :kbd:`Down`) + Navigate through opcode entries in the opcode panel (when ``--opcodes`` is + enabled). These keys scroll through the instruction-level statistics for the + currently selected function. + +When profiling finishes (duration expires or target process exits), the display +shows a "PROFILING COMPLETE" banner and freezes the final results. You can +still navigate, sort, and filter the results before pressing :kbd:`q` to exit. + +Live mode is incompatible with output format options (:option:`--collapsed`, +:option:`--flamegraph`, and so on) because it uses an interactive terminal +interface rather than producing file output. + + +Async-aware profiling +===================== + +For programs using :mod:`asyncio`, the profiler offers async-aware mode +(:option:`--async-aware`) that reconstructs call stacks based on the task structure +rather than the raw Python frames:: + + python -m profiling.sampling run --async-aware async_script.py + +Standard profiling of async code can be confusing because the physical call +stack often shows event loop internals rather than the logical flow of your +coroutines. Async-aware mode addresses this by tracking which task is running +and presenting stacks that reflect the ``await`` chain. + +.. code-block:: python + + import asyncio + + async def fetch(url): + await asyncio.sleep(0.1) + return url + + async def main(): + for _ in range(50): + await asyncio.gather(fetch("a"), fetch("b"), fetch("c")) + + if __name__ == "__main__": + asyncio.run(main()) + +:: + + python -m profiling.sampling run --async-aware --flamegraph -o out.html script.py + +.. note:: + + Async-aware profiling requires the target process to have the :mod:`asyncio` + module loaded. If you profile a script before it imports asyncio, async-aware + mode will not be able to capture task information. + + +Async modes +----------- + +The :option:`--async-mode` option controls which tasks appear in the profile:: + + python -m profiling.sampling run --async-aware --async-mode=running async_script.py + python -m profiling.sampling run --async-aware --async-mode=all async_script.py + +With :option:`--async-mode`\ ``=running`` (the default), only the task currently executing +on the CPU is profiled. This shows where your program is actively spending time +and is the typical choice for performance analysis. + +With :option:`--async-mode`\ ``=all``, tasks that are suspended (awaiting I/O, locks, or +other tasks) are also included. This mode is useful for understanding what your +program is waiting on, but produces larger profiles since every suspended task +appears in each sample. + + +Task markers and stack reconstruction +------------------------------------- + +In async-aware profiles, you will see ```` frames that mark boundaries +between asyncio tasks. These are synthetic frames inserted by the profiler to +show the task structure. The task name appears as the function name in these +frames. + +When a task awaits another task, the profiler reconstructs the logical call +chain by following the ``await`` relationships. Only "leaf" tasks (tasks that +no other task is currently awaiting) generate their own stack entries. Tasks +being awaited by other tasks appear as part of their awaiter's stack instead. + +If a task has multiple awaiters (a diamond pattern in the task graph), the +profiler deterministically selects one parent and annotates the task marker +with the number of parents, for example ``MyTask (2 parents)``. This indicates +that alternate execution paths exist but are not shown in this particular stack. + + +Option restrictions +------------------- + +Async-aware mode uses a different stack reconstruction mechanism and is +incompatible with: :option:`--native`, :option:`--no-gc`, :option:`--all-threads`, and +:option:`--mode`\ ``=cpu`` or :option:`--mode`\ ``=gil``. + + +Command-line interface +====================== + +.. program:: profiling.sampling + +The complete command-line interface for reference. + + +Global options +-------------- + +.. option:: run + + Run and profile a Python script or module. + +.. option:: attach + + Attach to and profile a running process by PID. + + +Sampling options +---------------- + +.. option:: -i , --interval + + Sampling interval in microseconds. Default: 100. + +.. option:: -d , --duration + + Profiling duration in seconds. Default: 10. + +.. option:: -a, --all-threads + + Sample all threads, not just the main thread. + +.. option:: --realtime-stats + + Display sampling statistics during profiling. + +.. option:: --native + + Include ```` frames for non-Python code. + +.. option:: --no-gc + + Exclude ```` frames for garbage collection. + +.. option:: --async-aware + + Enable async-aware profiling for asyncio programs. + +.. option:: --opcodes + + Gather bytecode opcode information for instruction-level profiling. Shows + which bytecode instructions are executing, including specializations. + Compatible with ``--live``, ``--flamegraph``, ``--heatmap``, and ``--gecko`` + formats only. + +.. option:: --subprocesses + + Also profile subprocesses. Each subprocess gets its own profiler + instance and output file. Incompatible with ``--live``. + + +Mode options +------------ + +.. option:: --mode + + Sampling mode: ``wall`` (default), ``cpu``, ``gil``, or ``exception``. + The ``cpu``, ``gil``, and ``exception`` modes are incompatible with + ``--async-aware``. + +.. option:: --async-mode + + Async profiling mode: ``running`` (default) or ``all``. + Requires ``--async-aware``. + + +Output options +-------------- + +.. option:: --pstats + + Generate text statistics output. This is the default. + +.. option:: --collapsed + + Generate collapsed stack format for external flame graph tools. + +.. option:: --flamegraph + + Generate self-contained HTML flame graph. + +.. option:: --gecko + + Generate Gecko JSON format for Firefox Profiler. + +.. option:: --heatmap + + Generate HTML heatmap with line-level sample counts. + +.. option:: -o , --output + + Output file or directory path. Default behavior varies by format: + ``--pstats`` writes to stdout, ``--flamegraph`` and ``--gecko`` generate + files like ``flamegraph.PID.html``, and ``--heatmap`` creates a directory + named ``heatmap_PID``. + + +pstats display options +---------------------- + +These options apply only to pstats format output. + +.. option:: --sort + + Sort order: ``nsamples``, ``tottime``, ``cumtime``, ``sample-pct``, + ``cumul-pct``, ``nsamples-cumul``, or ``name``. Default: ``nsamples``. + +.. option:: -l , --limit + + Maximum number of entries to display. Default: 15. + +.. option:: --no-summary + + Omit the Legend and Summary of Interesting Functions sections from output. + + +Run command options +------------------- + +.. option:: -m, --module + + Treat the target as a module name rather than a script path. + +.. option:: --live + + Start interactive terminal interface instead of batch profiling. + + +.. seealso:: + + :mod:`profiling` + Overview of Python profiling tools and guidance on choosing a profiler. + + :mod:`profiling.tracing` + Deterministic tracing profiler for exact call counts and timing. + + :mod:`pstats` + Statistics analysis for profile data. + + `Firefox Profiler `__ + Web-based profiler that accepts Gecko format output. See the + `documentation `__ for usage details. + + `FlameGraph `__ + Tools for generating flame graphs from collapsed stack format. diff --git a/Doc/library/profiling.tracing.rst b/Doc/library/profiling.tracing.rst new file mode 100644 index 00000000000..6e6ba9173a1 --- /dev/null +++ b/Doc/library/profiling.tracing.rst @@ -0,0 +1,331 @@ +.. _profiling-tracing: + +**************************************************** +:mod:`profiling.tracing` --- Deterministic profiler +**************************************************** + +.. module:: profiling.tracing + :synopsis: Deterministic tracing profiler for Python programs. + +.. module:: cProfile + :synopsis: Alias for profiling.tracing (backward compatibility). + :noindex: + +.. versionadded:: 3.15 + +**Source code:** :source:`Lib/profiling/tracing/` + +-------------- + +The :mod:`profiling.tracing` module provides deterministic profiling of Python +programs. It monitors every function call, function return, and exception event, +recording precise timing for each. This approach provides exact call counts and +complete visibility into program execution, making it ideal for development and +testing scenarios. + +.. note:: + + This module is also available as ``cProfile`` for backward compatibility. + The ``cProfile`` name will continue to work in all future Python versions. + Use whichever import style suits your codebase:: + + # Preferred (new style) + import profiling.tracing + profiling.tracing.run('my_function()') + + # Also works (backward compatible) + import cProfile + cProfile.run('my_function()') + + +What is deterministic profiling? +================================ + +:dfn:`Deterministic profiling` captures every function call, function return, +and exception event during program execution. The profiler measures the precise +time intervals between these events, providing exact statistics about how the +program behaves. + +In contrast to :ref:`statistical profiling `, which samples +the call stack periodically to estimate where time is spent, deterministic +profiling records every event. This means you get exact call counts rather than +statistical approximations. The trade-off is that instrumenting every event +introduces overhead that can slow down program execution. + +Python's interpreted nature makes deterministic profiling practical. The +interpreter already dispatches events for function calls and returns, so the +profiler can hook into this mechanism without requiring code modification. The +overhead tends to be moderate relative to the inherent cost of interpretation, +making deterministic profiling suitable for most development workflows. + +Deterministic profiling helps answer questions like: + +- How many times was this function called? +- What is the complete call graph of my program? +- Which functions are called by a particular function? +- Are there unexpected function calls happening? + +Call count statistics can identify bugs (surprising counts) and inline +expansion opportunities (high call counts). Internal time statistics reveal +"hot loops" that warrant optimization. Cumulative time statistics help identify +algorithmic inefficiencies. The handling of cumulative times in this profiler +allows direct comparison of recursive and iterative implementations. + + +.. _profiling-tracing-cli: + +Command-line interface +====================== + +.. program:: profiling.tracing + +The :mod:`profiling.tracing` module can be invoked as a script to profile +another script or module: + +.. code-block:: shell-session + + python -m profiling.tracing [-o output_file] [-s sort_order] (-m module | script.py) + +This runs the specified script or module under the profiler and prints the +results to standard output (or saves them to a file). + +.. option:: -o + + Write the profile results to a file instead of standard output. The output + file can be read by the :mod:`pstats` module for later analysis. + +.. option:: -s + + Sort the output by the specified key. This accepts any of the sort keys + recognized by :meth:`pstats.Stats.sort_stats`, such as ``cumulative``, + ``time``, ``calls``, or ``name``. This option only applies when + :option:`-o ` is not specified. + +.. option:: -m + + Profile a module instead of a script. The module is located using the + standard import mechanism. + + .. versionadded:: 3.7 + The ``-m`` option for ``cProfile``. + + .. versionadded:: 3.8 + The ``-m`` option for :mod:`profile`. + + +Programmatic usage examples +=========================== + +For more control over profiling, use the module's functions and classes +directly. + + +Basic profiling +--------------- + +The simplest approach uses the :func:`!run` function:: + + import profiling.tracing + profiling.tracing.run('my_function()') + +This profiles the given code string and prints a summary to standard output. +To save results for later analysis:: + + profiling.tracing.run('my_function()', 'output.prof') + + +Using the :class:`!Profile` class +--------------------------------- + +The :class:`!Profile` class provides fine-grained control:: + + import profiling.tracing + import pstats + from io import StringIO + + pr = profiling.tracing.Profile() + pr.enable() + # ... code to profile ... + pr.disable() + + # Print results + s = StringIO() + ps = pstats.Stats(pr, stream=s).sort_stats(pstats.SortKey.CUMULATIVE) + ps.print_stats() + print(s.getvalue()) + +The :class:`!Profile` class also works as a context manager:: + + import profiling.tracing + + with profiling.tracing.Profile() as pr: + # ... code to profile ... + + pr.print_stats() + + +Module reference +================ + +.. currentmodule:: profiling.tracing + +.. function:: run(command, filename=None, sort=-1) + + Profile execution of a command and print or save the results. + + This function executes the *command* string using :func:`exec` in the + ``__main__`` module's namespace:: + + exec(command, __main__.__dict__, __main__.__dict__) + + If *filename* is not provided, the function creates a :class:`pstats.Stats` + instance and prints a summary to standard output. If *filename* is + provided, the raw profile data is saved to that file for later analysis + with :mod:`pstats`. + + The *sort* argument specifies the sort order for printed output, accepting + any value recognized by :meth:`pstats.Stats.sort_stats`. + + +.. function:: runctx(command, globals, locals, filename=None, sort=-1) + + Profile execution of a command with explicit namespaces. + + Like :func:`run`, but executes the command with the specified *globals* + and *locals* mappings instead of using the ``__main__`` module's namespace:: + + exec(command, globals, locals) + + +.. class:: Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True) + + A profiler object that collects execution statistics. + + The optional *timer* argument specifies a custom timing function. If not + provided, the profiler uses a platform-appropriate default timer. When + supplying a custom timer, it must return a single number representing the + current time. If the timer returns integers, use *timeunit* to specify the + duration of one time unit (for example, ``0.001`` for milliseconds). + + The *subcalls* argument controls whether the profiler tracks call + relationships between functions. The *builtins* argument controls whether + built-in functions are profiled. + + .. versionchanged:: 3.8 + Added context manager support. + + .. method:: enable() + + Start collecting profiling data. + + .. method:: disable() + + Stop collecting profiling data. + + .. method:: create_stats() + + Stop collecting data and record the results internally as the current + profile. + + .. method:: print_stats(sort=-1) + + Create a :class:`pstats.Stats` object from the current profile and print + the results to standard output. + + The *sort* argument specifies the sorting order. It accepts a single + key or a tuple of keys for multi-level sorting, using the same values + as :meth:`pstats.Stats.sort_stats`. + + .. versionadded:: 3.13 + Support for a tuple of sort keys. + + .. method:: dump_stats(filename) + + Write the current profile data to *filename*. The file can be read by + :class:`pstats.Stats` for later analysis. + + .. method:: run(cmd) + + Profile the command string via :func:`exec`. + + .. method:: runctx(cmd, globals, locals) + + Profile the command string via :func:`exec` with the specified + namespaces. + + .. method:: runcall(func, /, *args, **kwargs) + + Profile a function call. Returns whatever *func* returns:: + + result = pr.runcall(my_function, arg1, arg2, keyword=value) + +.. note:: + + Profiling requires that the profiled code returns normally. If the + interpreter terminates (for example, via :func:`sys.exit`) during + profiling, no results will be available. + + +Using a custom timer +==================== + +The :class:`Profile` class accepts a custom timing function, allowing you to +measure different aspects of execution such as wall-clock time or CPU time. +Pass the timing function to the constructor:: + + pr = profiling.tracing.Profile(my_timer_function) + +The timer function must return a single number representing the current time. +If it returns integers, also specify *timeunit* to indicate the duration of +one unit:: + + # Timer returns time in milliseconds + pr = profiling.tracing.Profile(my_ms_timer, 0.001) + +For best performance, the timer function should be as fast as possible. The +profiler calls it frequently, so timer overhead directly affects profiling +overhead. + +The :mod:`time` module provides several functions suitable for use as custom +timers: + +- :func:`time.perf_counter` for high-resolution wall-clock time +- :func:`time.process_time` for CPU time (excluding sleep) +- :func:`time.monotonic` for monotonic clock time + + +Limitations +=========== + +Deterministic profiling has inherent limitations related to timing accuracy. + +The underlying timer typically has a resolution of about one millisecond. +Measurements cannot be more accurate than this resolution. With enough +measurements, timing errors tend to average out, but individual measurements +may be imprecise. + +There is also latency between when an event occurs and when the profiler +captures the timestamp. Similarly, there is latency after reading the +timestamp before user code resumes. Functions called frequently accumulate +this latency, which can make them appear slower than they actually are. This +error is typically less than one clock tick per call but can become +significant for functions called many times. + +The :mod:`profiling.tracing` module (and its ``cProfile`` alias) is +implemented as a C extension with low overhead, so these timing issues are +less pronounced than with the deprecated pure Python :mod:`profile` module. + + +.. seealso:: + + :mod:`profiling` + Overview of Python profiling tools and guidance on choosing a profiler. + + :mod:`profiling.sampling` + Statistical sampling profiler for production use. + + :mod:`pstats` + Statistics analysis and formatting for profile data. + + :mod:`profile` + Deprecated pure Python profiler (includes calibration documentation). diff --git a/Doc/library/pstats.rst b/Doc/library/pstats.rst new file mode 100644 index 00000000000..ce1cc5c9535 --- /dev/null +++ b/Doc/library/pstats.rst @@ -0,0 +1,362 @@ +.. _pstats-module: + +******************************************** +:mod:`pstats` --- Statistics for profilers +******************************************** + +.. module:: pstats + :synopsis: Statistics object for analyzing profiler output. + +**Source code:** :source:`Lib/pstats.py` + +-------------- + +The :mod:`pstats` module provides tools for reading, manipulating, and +displaying profiling statistics generated by Python's profilers. It reads +output from both :mod:`profiling.tracing` (deterministic profiler) and +:mod:`profiling.sampling` (statistical profiler). + + +Reading and displaying profile data +=================================== + +The :class:`Stats` class is the primary interface for working with profile +data. It can read statistics from files or directly from a +:class:`~profiling.tracing.Profile` object. + +Load statistics from a file and print a basic report:: + + import pstats + + p = pstats.Stats('profile_output.prof') + p.print_stats() + +The :class:`Stats` object provides methods for sorting and filtering the +data before printing. For example, to see the ten functions with the highest +cumulative time:: + + from pstats import SortKey + + p = pstats.Stats('profile_output.prof') + p.sort_stats(SortKey.CUMULATIVE).print_stats(10) + + +Working with statistics +----------------------- + +The :class:`Stats` class supports method chaining, making it convenient to +perform multiple operations:: + + p = pstats.Stats('restats') + p.strip_dirs().sort_stats(-1).print_stats() + +The :meth:`~Stats.strip_dirs` method removes directory paths from filenames, +making the output more compact. The :meth:`~Stats.sort_stats` method accepts +various keys to control the sort order. + +Different sort keys highlight different aspects of performance:: + + from pstats import SortKey + + # Functions that consume the most cumulative time + p.sort_stats(SortKey.CUMULATIVE).print_stats(10) + + # Functions that consume the most time in their own code + p.sort_stats(SortKey.TIME).print_stats(10) + + # Functions sorted by name + p.sort_stats(SortKey.NAME).print_stats() + + +Filtering output +---------------- + +The :meth:`~Stats.print_stats` method accepts restrictions that filter +which functions are displayed. Restrictions can be integers (limiting the +count), floats between 0 and 1 (selecting a percentage), or strings (matching +function names via regular expression). + +Print only the top 10%:: + + p.print_stats(.1) + +Print only functions whose names contain "init":: + + p.print_stats('init') + +Combine restrictions (they apply sequentially):: + + # Top 10%, then only those containing "init" + p.print_stats(.1, 'init') + + # Functions in files matching "foo:", limited to top 50% + p.sort_stats(SortKey.FILENAME).print_stats('foo:', .5) + + +Analyzing call relationships +---------------------------- + +The :meth:`~Stats.print_callers` method shows which functions called each +displayed function:: + + p.print_callers() + +The :meth:`~Stats.print_callees` method shows the opposite relationship, +listing which functions each displayed function called:: + + p.print_callees() + +Both methods accept the same restriction arguments as :meth:`~Stats.print_stats`. + + +Combining multiple profiles +--------------------------- + +Statistics from multiple profiling runs can be combined into a single +:class:`Stats` object:: + + # Load multiple files at once + p = pstats.Stats('run1.prof', 'run2.prof', 'run3.prof') + + # Or add files incrementally + p = pstats.Stats('run1.prof') + p.add('run2.prof') + p.add('run3.prof') + +When files are combined, statistics for identical functions (same file, line, +and name) are accumulated, giving an aggregate view across all profiling runs. + + +The :class:`!Stats` class +========================= + +.. class:: Stats(*filenames_or_profile, stream=sys.stdout) + + Create a statistics object from profile data. + + The arguments can be filenames (strings or path-like objects) or + :class:`~profiling.tracing.Profile` objects. If multiple sources are + provided, their statistics are combined. + + The *stream* argument specifies where output from :meth:`print_stats` and + related methods is written. It defaults to :data:`sys.stdout`. + + The profile data format is specific to the Python version that created it. + There is no compatibility guarantee between Python versions or between + different profilers. + + .. method:: strip_dirs() + + Remove leading path information from all filenames. + + This method modifies the object in place and returns it for method + chaining. After stripping, the statistics are considered to be in + random order. + + If stripping causes two functions to become indistinguishable (same + filename, line number, and function name), their statistics are + combined into a single entry. + + .. method:: add(*filenames) + + Add profiling data from additional files. + + The files must have been created by the same profiler type. Statistics + for identical functions are accumulated. + + .. method:: dump_stats(filename) + + Save the current statistics to a file. + + The file is created if it does not exist and overwritten if it does. + The saved data can be loaded by creating a new :class:`Stats` object. + + .. method:: sort_stats(*keys) + + Sort the statistics according to the specified criteria. + + Each key can be a string or a :class:`SortKey` enum member. When + multiple keys are provided, later keys break ties in earlier keys. + + Using :class:`SortKey` enum members is preferred over strings as it + provides better error checking:: + + from pstats import SortKey + p.sort_stats(SortKey.CUMULATIVE) + + Valid sort keys: + + +------------------+------------------------+----------------------+ + | String | Enum | Meaning | + +==================+========================+======================+ + | ``'calls'`` | ``SortKey.CALLS`` | call count | + +------------------+------------------------+----------------------+ + | ``'cumulative'`` | ``SortKey.CUMULATIVE`` | cumulative time | + +------------------+------------------------+----------------------+ + | ``'cumtime'`` | N/A | cumulative time | + +------------------+------------------------+----------------------+ + | ``'file'`` | N/A | file name | + +------------------+------------------------+----------------------+ + | ``'filename'`` | ``SortKey.FILENAME`` | file name | + +------------------+------------------------+----------------------+ + | ``'module'`` | N/A | file name | + +------------------+------------------------+----------------------+ + | ``'ncalls'`` | N/A | call count | + +------------------+------------------------+----------------------+ + | ``'pcalls'`` | ``SortKey.PCALLS`` | primitive call count | + +------------------+------------------------+----------------------+ + | ``'line'`` | ``SortKey.LINE`` | line number | + +------------------+------------------------+----------------------+ + | ``'name'`` | ``SortKey.NAME`` | function name | + +------------------+------------------------+----------------------+ + | ``'nfl'`` | ``SortKey.NFL`` | name/file/line | + +------------------+------------------------+----------------------+ + | ``'stdname'`` | ``SortKey.STDNAME`` | standard name | + +------------------+------------------------+----------------------+ + | ``'time'`` | ``SortKey.TIME`` | internal time | + +------------------+------------------------+----------------------+ + | ``'tottime'`` | N/A | internal time | + +------------------+------------------------+----------------------+ + + All sorts on statistics are in descending order (most time consuming + first), while name, file, and line number sorts are ascending + (alphabetical). + + The difference between ``SortKey.NFL`` and ``SortKey.STDNAME`` is that + NFL sorts line numbers numerically while STDNAME sorts them as strings. + ``sort_stats(SortKey.NFL)`` is equivalent to + ``sort_stats(SortKey.NAME, SortKey.FILENAME, SortKey.LINE)``. + + For backward compatibility, the numeric arguments ``-1``, ``0``, ``1``, + and ``2`` are also accepted, meaning ``'stdname'``, ``'calls'``, + ``'time'``, and ``'cumulative'`` respectively. + + .. versionadded:: 3.7 + The :class:`SortKey` enum. + + .. method:: reverse_order() + + Reverse the current sort order. + + By default, the sort direction is chosen appropriately for the sort key + (descending for time-based keys, ascending for name-based keys). This + method inverts that choice. + + .. method:: print_stats(*restrictions) + + Print a report of the profiling statistics. + + The output includes a header line summarizing the data, followed by a + table of function statistics sorted according to the last + :meth:`sort_stats` call. + + Restrictions filter the output. Each restriction is either: + + - An integer: limits output to that many entries + - A float between 0.0 and 1.0: selects that fraction of entries + - A string: matches function names via regular expression + + Restrictions are applied sequentially. For example:: + + print_stats(.1, 'foo:') + + First limits to the top 10%, then filters to functions matching 'foo:'. + + .. method:: print_callers(*restrictions) + + Print the callers of each function in the statistics. + + For each function in the filtered results, shows which functions called + it and how often. + + With :mod:`profiling.tracing` (or ``cProfile``), each caller line + shows three numbers: the number of calls from that caller, and the + total and cumulative times for those specific calls. + + Accepts the same restriction arguments as :meth:`print_stats`. + + .. method:: print_callees(*restrictions) + + Print the functions called by each function in the statistics. + + This is the inverse of :meth:`print_callers`, showing which functions + each listed function called. + + Accepts the same restriction arguments as :meth:`print_stats`. + + .. method:: get_stats_profile() + + Return a ``StatsProfile`` object containing the statistics. + + The returned object provides programmatic access to the profile data, + with function names mapped to ``FunctionProfile`` objects + containing timing and call count information. + + .. versionadded:: 3.9 + + +.. class:: SortKey + + An enumeration of valid sort keys for :meth:`Stats.sort_stats`. + + .. attribute:: CALLS + + Sort by call count. + + .. attribute:: CUMULATIVE + + Sort by cumulative time. + + .. attribute:: FILENAME + + Sort by file name. + + .. attribute:: LINE + + Sort by line number. + + .. attribute:: NAME + + Sort by function name. + + .. attribute:: NFL + + Sort by name, then file, then line number (numeric line sort). + + .. attribute:: PCALLS + + Sort by primitive (non-recursive) call count. + + .. attribute:: STDNAME + + Sort by standard name (string-based line sort). + + .. attribute:: TIME + + Sort by internal time (time in function excluding subcalls). + + +.. _pstats-cli: + +Command-line interface +====================== + +The :mod:`pstats` module can be invoked as a script to interactively browse +profile data:: + + python -m pstats profile_output.prof + +This opens a line-oriented interface (built on :mod:`cmd`) for examining the +statistics. Type ``help`` at the prompt for available commands. + + +.. seealso:: + + :mod:`profiling` + Overview of Python profiling tools. + + :mod:`profiling.tracing` + Deterministic tracing profiler. + + :mod:`profiling.sampling` + Statistical sampling profiler. diff --git a/Doc/library/pty.rst b/Doc/library/pty.rst index 1a44bb13a84..2912c9e16c6 100644 --- a/Doc/library/pty.rst +++ b/Doc/library/pty.rst @@ -33,9 +33,14 @@ The :mod:`pty` module defines the following functions: file descriptor connected to the child's controlling terminal (and also to the child's standard input and output). + The returned file descriptor *fd* is :ref:`non-inheritable `. + .. warning:: On macOS the use of this function is unsafe when mixed with using higher-level system APIs, and that includes using :mod:`urllib.request`. + .. versionchanged:: 3.15 + The returned file descriptor is now made non-inheritable. + .. function:: openpty() diff --git a/Doc/library/pyexpat.rst b/Doc/library/pyexpat.rst index 5506ac828e5..2f5db81955c 100644 --- a/Doc/library/pyexpat.rst +++ b/Doc/library/pyexpat.rst @@ -72,6 +72,13 @@ The :mod:`xml.parsers.expat` module contains two functions: *encoding* [1]_ is given it will override the implicit or explicit encoding of the document. + .. _xmlparser-non-root: + + Parsers created through :func:`!ParserCreate` are called "root" parsers, + in the sense that they do not have any parent parser attached. Non-root + parsers are created by :meth:`parser.ExternalEntityParserCreate + `. + Expat can optionally do XML namespace processing for you, enabled by providing a value for *namespace_separator*. The value must be a one-character string; a :exc:`ValueError` will be raised if the string has an illegal length (``None`` @@ -216,10 +223,10 @@ XMLParser Objects Calling ``SetReparseDeferralEnabled(True)`` allows re-enabling reparse deferral. - Note that :meth:`SetReparseDeferralEnabled` has been backported to some - prior releases of CPython as a security fix. Check for availability of - :meth:`SetReparseDeferralEnabled` using :func:`hasattr` if used in code - running across a variety of Python versions. + :meth:`!SetReparseDeferralEnabled` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. .. versionadded:: 3.13 @@ -231,6 +238,131 @@ XMLParser Objects .. versionadded:: 3.13 +:class:`!xmlparser` objects have the following methods to tune protections +against some common XML vulnerabilities. + +.. method:: xmlparser.SetBillionLaughsAttackProtectionActivationThreshold(threshold, /) + + Sets the number of output bytes needed to activate protection against + `billion laughs`_ attacks. + + The number of output bytes includes amplification from entity expansion + and reading DTD files. + + Parser objects usually have a protection activation threshold of 8 MiB, + but the actual default value depends on the underlying Expat library. + + An :exc:`ExpatError` is raised if this method is called on a + |xml-non-root-parser| parser. + The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset` + should not be used as they may have no special meaning. + + :meth:`!SetBillionLaughsAttackProtectionActivationThreshold` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. + + .. note:: + + Activation thresholds below 4 MiB are known to break support for DITA 1.3 + payload and are hence not recommended. + + .. versionadded:: 3.15 + +.. method:: xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification(max_factor, /) + + Sets the maximum tolerated amplification factor for protection against + `billion laughs`_ attacks. + + The amplification factor is calculated as ``(direct + indirect) / direct`` + while parsing, where ``direct`` is the number of bytes read from + the primary document in parsing and ``indirect`` is the number of + bytes added by expanding entities and reading of external DTD files. + + The *max_factor* value must be a non-NaN :class:`float` value greater than + or equal to 1.0. Peak amplifications of factor 15,000 for the entire payload + and of factor 30,000 in the middle of parsing have been observed with small + benign files in practice. In particular, the activation threshold should be + carefully chosen to avoid false positives. + + Parser objects usually have a maximum amplification factor of 100, + but the actual default value depends on the underlying Expat library. + + An :exc:`ExpatError` is raised if this method is called on a + |xml-non-root-parser| parser or if *max_factor* is outside the valid range. + The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset` + should not be used as they may have no special meaning. + + :meth:`!SetBillionLaughsAttackProtectionMaximumAmplification` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. + + .. note:: + + The maximum amplification factor is only considered if the threshold + that can be adjusted by :meth:`.SetBillionLaughsAttackProtectionActivationThreshold` + is exceeded. + + .. versionadded:: 3.15 + +.. method:: xmlparser.SetAllocTrackerActivationThreshold(threshold, /) + + Sets the number of allocated bytes of dynamic memory needed to activate + protection against disproportionate use of RAM. + + Parser objects usually have an allocation activation threshold of 64 MiB, + but the actual default value depends on the underlying Expat library. + + An :exc:`ExpatError` is raised if this method is called on a + |xml-non-root-parser| parser. + The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset` + should not be used as they may have no special meaning. + + :meth:`!SetAllocTrackerActivationThreshold` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. + + .. versionadded:: 3.15 + +.. method:: xmlparser.SetAllocTrackerMaximumAmplification(max_factor, /) + + Sets the maximum amplification factor between direct input and bytes + of dynamic memory allocated. + + The amplification factor is calculated as ``allocated / direct`` + while parsing, where ``direct`` is the number of bytes read from + the primary document in parsing and ``allocated`` is the number + of bytes of dynamic memory allocated in the parser hierarchy. + + The *max_factor* value must be a non-NaN :class:`float` value greater than + or equal to 1.0. Amplification factors greater than 100.0 can be observed + near the start of parsing even with benign files in practice. In particular, + the activation threshold should be carefully chosen to avoid false positives. + + Parser objects usually have a maximum amplification factor of 100, + but the actual default value depends on the underlying Expat library. + + An :exc:`ExpatError` is raised if this method is called on a + |xml-non-root-parser| parser or if *max_factor* is outside the valid range. + The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset` + should not be used as they may have no special meaning. + + :meth:`!SetAllocTrackerMaximumAmplification` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. + + .. note:: + + The maximum amplification factor is only considered if the threshold + that can be adjusted by :meth:`.SetAllocTrackerActivationThreshold` + is exceeded. + + .. versionadded:: 3.15 + + :class:`xmlparser` objects have the following attributes: @@ -502,6 +634,15 @@ otherwise stated. .. method:: xmlparser.ExternalEntityRefHandler(context, base, systemId, publicId) + .. warning:: + + Implementing a handler that accesses local files and/or the network + may create a vulnerability to + `external entity attacks `_ + if :class:`xmlparser` is used with user-provided XML content. + Please reflect on your `threat model `_ + before implementing this handler. + Called for references to external entities. *base* is the current base, as set by a previous call to :meth:`SetBase`. The public and system identifiers, *systemId* and *publicId*, are strings if given; if the public identifier is not @@ -954,3 +1095,6 @@ The ``errors`` module has the following attributes: not. See https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDecl and https://www.iana.org/assignments/character-sets/character-sets.xhtml. + +.. _billion laughs: https://en.wikipedia.org/wiki/Billion_laughs_attack +.. |xml-non-root-parser| replace:: :ref:`non-root ` diff --git a/Doc/library/random.rst b/Doc/library/random.rst index b1120b3a4d8..4e55e301b89 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -630,7 +630,8 @@ Recipes ------- These recipes show how to efficiently make random selections -from the combinatoric iterators in the :mod:`itertools` module: +from the combinatoric iterators in the :mod:`itertools` module +or the :pypi:`more-itertools` project: .. testcode:: import random @@ -661,6 +662,17 @@ from the combinatoric iterators in the :mod:`itertools` module: indices = sorted(random.choices(range(n), k=r)) return tuple(pool[i] for i in indices) + def random_derangement(iterable): + "Choose a permutation where no element is in its original position." + seq = tuple(iterable) + if len(seq) < 2: + raise ValueError('derangements require at least two values') + perm = list(seq) + while True: + random.shuffle(perm) + if all(p != q for p, q in zip(seq, perm)): + return tuple(perm) + The default :func:`.random` returns multiples of 2⁻⁵³ in the range *0.0 ≤ x < 1.0*. All such numbers are evenly spaced and are exactly representable as Python floats. However, many other representable diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst index f649fce5efc..0449682585c 100644 --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -26,6 +26,8 @@ Readline library in general. .. include:: ../includes/wasm-mobile-notavail.rst +.. include:: ../includes/optional-module.rst + .. note:: The underlying Readline library API may be implemented by @@ -244,6 +246,15 @@ Startup hooks if Python was compiled for a version of the library that supports it. +.. function:: get_pre_input_hook() + + Get the current pre-input hook function, or ``None`` if no pre-input hook + function has been set. This function only exists if Python was compiled + for a version of the library that supports it. + + .. versionadded:: 3.15 + + .. _readline-completion: Completion diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst index 5bc68fdeff4..c58dc4243ec 100644 --- a/Doc/library/resource.rst +++ b/Doc/library/resource.rst @@ -51,7 +51,7 @@ this module for those platforms. Constant used to represent the limit for an unlimited resource. - .. versionchanged:: next + .. versionchanged:: 3.15 It is now always positive. Previously, it could be negative, such as -1 or -3. @@ -63,7 +63,7 @@ this module for those platforms. cannot be represented in the ``rlim_t`` value in C. Can be equal to :data:`RLIM_INFINITY`. - .. versionadded:: next + .. versionadded:: 3.15 .. function:: getrlimit(resource) @@ -141,7 +141,7 @@ platform. .. data:: RLIMIT_CPU The maximum amount of processor time (in seconds) that a process can use. If - this limit is exceeded, a :const:`SIGXCPU` signal is sent to the process. (See + this limit is exceeded, a :const:`~signal.SIGXCPU` signal is sent to the process. (See the :mod:`signal` module documentation for information about how to catch this signal and do something useful, e.g. flush open files to disk.) @@ -296,7 +296,7 @@ platform. .. availability:: NetBSD >= 7.0. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: RLIMIT_PIPEBUF @@ -306,7 +306,7 @@ platform. .. availability:: FreeBSD >= 14.2. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: RLIMIT_THREADS @@ -315,7 +315,7 @@ platform. .. availability:: AIX. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: RLIMIT_UMTXP @@ -325,7 +325,7 @@ platform. .. availability:: FreeBSD >= 11. - .. versionadded:: next + .. versionadded:: 3.15 Resource Usage @@ -363,47 +363,47 @@ These functions are used to retrieve resource usage information: For backward compatibility, the return value is also accessible as a tuple of 16 elements. - The fields :attr:`ru_utime` and :attr:`ru_stime` of the return value are + The fields :attr:`!ru_utime` and :attr:`!ru_stime` of the return value are floating-point values representing the amount of time spent executing in user mode and the amount of time spent executing in system mode, respectively. The remaining values are integers. Consult the :manpage:`getrusage(2)` man page for detailed information about these values. A brief summary is presented here: - +--------+---------------------+---------------------------------------+ - | Index | Field | Resource | - +========+=====================+=======================================+ - | ``0`` | :attr:`ru_utime` | time in user mode (float seconds) | - +--------+---------------------+---------------------------------------+ - | ``1`` | :attr:`ru_stime` | time in system mode (float seconds) | - +--------+---------------------+---------------------------------------+ - | ``2`` | :attr:`ru_maxrss` | maximum resident set size | - +--------+---------------------+---------------------------------------+ - | ``3`` | :attr:`ru_ixrss` | shared memory size | - +--------+---------------------+---------------------------------------+ - | ``4`` | :attr:`ru_idrss` | unshared memory size | - +--------+---------------------+---------------------------------------+ - | ``5`` | :attr:`ru_isrss` | unshared stack size | - +--------+---------------------+---------------------------------------+ - | ``6`` | :attr:`ru_minflt` | page faults not requiring I/O | - +--------+---------------------+---------------------------------------+ - | ``7`` | :attr:`ru_majflt` | page faults requiring I/O | - +--------+---------------------+---------------------------------------+ - | ``8`` | :attr:`ru_nswap` | number of swap outs | - +--------+---------------------+---------------------------------------+ - | ``9`` | :attr:`ru_inblock` | block input operations | - +--------+---------------------+---------------------------------------+ - | ``10`` | :attr:`ru_oublock` | block output operations | - +--------+---------------------+---------------------------------------+ - | ``11`` | :attr:`ru_msgsnd` | messages sent | - +--------+---------------------+---------------------------------------+ - | ``12`` | :attr:`ru_msgrcv` | messages received | - +--------+---------------------+---------------------------------------+ - | ``13`` | :attr:`ru_nsignals` | signals received | - +--------+---------------------+---------------------------------------+ - | ``14`` | :attr:`ru_nvcsw` | voluntary context switches | - +--------+---------------------+---------------------------------------+ - | ``15`` | :attr:`ru_nivcsw` | involuntary context switches | - +--------+---------------------+---------------------------------------+ + +--------+----------------------+---------------------------------------+ + | Index | Field | Resource | + +========+======================+=======================================+ + | ``0`` | :attr:`!ru_utime` | time in user mode (float seconds) | + +--------+----------------------+---------------------------------------+ + | ``1`` | :attr:`!ru_stime` | time in system mode (float seconds) | + +--------+----------------------+---------------------------------------+ + | ``2`` | :attr:`!ru_maxrss` | maximum resident set size | + +--------+----------------------+---------------------------------------+ + | ``3`` | :attr:`!ru_ixrss` | shared memory size | + +--------+----------------------+---------------------------------------+ + | ``4`` | :attr:`!ru_idrss` | unshared memory size | + +--------+----------------------+---------------------------------------+ + | ``5`` | :attr:`!ru_isrss` | unshared stack size | + +--------+----------------------+---------------------------------------+ + | ``6`` | :attr:`!ru_minflt` | page faults not requiring I/O | + +--------+----------------------+---------------------------------------+ + | ``7`` | :attr:`!ru_majflt` | page faults requiring I/O | + +--------+----------------------+---------------------------------------+ + | ``8`` | :attr:`!ru_nswap` | number of swap outs | + +--------+----------------------+---------------------------------------+ + | ``9`` | :attr:`!ru_inblock` | block input operations | + +--------+----------------------+---------------------------------------+ + | ``10`` | :attr:`!ru_oublock` | block output operations | + +--------+----------------------+---------------------------------------+ + | ``11`` | :attr:`!ru_msgsnd` | messages sent | + +--------+----------------------+---------------------------------------+ + | ``12`` | :attr:`!ru_msgrcv` | messages received | + +--------+----------------------+---------------------------------------+ + | ``13`` | :attr:`!ru_nsignals` | signals received | + +--------+----------------------+---------------------------------------+ + | ``14`` | :attr:`!ru_nvcsw` | voluntary context switches | + +--------+----------------------+---------------------------------------+ + | ``15`` | :attr:`!ru_nivcsw` | involuntary context switches | + +--------+----------------------+---------------------------------------+ This function will raise a :exc:`ValueError` if an invalid *who* parameter is specified. It may also raise :exc:`error` exception in unusual circumstances. diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index b07ec6e93f8..64735b5a109 100644 --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -50,10 +50,10 @@ The :mod:`runpy` module provides two functions: overridden by :func:`run_module`. The special global variables ``__name__``, ``__spec__``, ``__file__``, - ``__cached__``, ``__loader__`` and ``__package__`` are set in the globals - dictionary before the module code is executed. (Note that this is a - minimal set of variables - other variables may be set implicitly as an - interpreter implementation detail.) + ``__loader__`` and ``__package__`` are set in the globals dictionary before + the module code is executed. (Note that this is a minimal set of variables - + other variables may be set implicitly as an interpreter implementation + detail.) ``__name__`` is set to *run_name* if this optional argument is not :const:`None`, to ``mod_name + '.__main__'`` if the named module is a @@ -63,7 +63,7 @@ The :mod:`runpy` module provides two functions: module (that is, ``__spec__.name`` will always be *mod_name* or ``mod_name + '.__main__'``, never *run_name*). - ``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` are + ``__file__``, ``__loader__`` and ``__package__`` are :ref:`set as normal ` based on the module spec. If the argument *alter_sys* is supplied and evaluates to :const:`True`, @@ -98,6 +98,9 @@ The :mod:`runpy` module provides two functions: ``__package__`` are deprecated. See :class:`~importlib.machinery.ModuleSpec` for alternatives. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + .. function:: run_path(path_name, init_globals=None, run_name=None) .. index:: @@ -125,23 +128,23 @@ The :mod:`runpy` module provides two functions: overridden by :func:`run_path`. The special global variables ``__name__``, ``__spec__``, ``__file__``, - ``__cached__``, ``__loader__`` and ``__package__`` are set in the globals - dictionary before the module code is executed. (Note that this is a - minimal set of variables - other variables may be set implicitly as an - interpreter implementation detail.) + ``__loader__`` and ``__package__`` are set in the globals dictionary before + the module code is executed. (Note that this is a minimal set of variables - + other variables may be set implicitly as an interpreter implementation + detail.) ``__name__`` is set to *run_name* if this optional argument is not :const:`None` and to ``''`` otherwise. If *file_path* directly references a script file (whether as source or as precompiled byte code), then ``__file__`` will be set to - *file_path*, and ``__spec__``, ``__cached__``, ``__loader__`` and + *file_path*, and ``__spec__``, ``__loader__`` and ``__package__`` will all be set to :const:`None`. If *file_path* is a reference to a valid :data:`sys.path` entry, then ``__spec__`` will be set appropriately for the imported :mod:`__main__` module (that is, ``__spec__.name`` will always be ``__main__``). - ``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` will be + ``__file__``, ``__loader__`` and ``__package__`` will be :ref:`set as normal ` based on the module spec. A number of alterations are also made to the :mod:`sys` module. Firstly, @@ -173,6 +176,9 @@ The :mod:`runpy` module provides two functions: The setting of ``__cached__``, ``__loader__``, and ``__package__`` are deprecated. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + .. seealso:: :pep:`338` -- Executing modules as scripts diff --git a/Doc/library/select.rst b/Doc/library/select.rst index d2094283d54..62b5161fb80 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -115,7 +115,7 @@ The module defines the following: :ref:`kevent-objects` below for the methods supported by kevent objects. -.. function:: select(rlist, wlist, xlist[, timeout]) +.. function:: select(rlist, wlist, xlist, timeout=None) This is a straightforward interface to the Unix :c:func:`!select` system call. The first three arguments are iterables of 'waitable objects': either @@ -129,8 +129,9 @@ The module defines the following: Empty iterables are allowed, but acceptance of three empty iterables is platform-dependent. (It is known to work on Unix but not on Windows.) The - optional *timeout* argument specifies a time-out as a floating-point number - in seconds. When the *timeout* argument is omitted the function blocks until + optional *timeout* argument specifies a time-out in seconds; it may be + a non-integer to specify fractions of seconds. + When the *timeout* argument is omitted or ``None``, the function blocks until at least one file descriptor is ready. A time-out value of zero specifies a poll and never blocks. @@ -164,6 +165,9 @@ The module defines the following: :pep:`475` for the rationale), instead of raising :exc:`InterruptedError`. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. data:: PIPE_BUF @@ -270,6 +274,9 @@ object. :pep:`475` for the rationale), instead of raising :exc:`InterruptedError`. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. _epoll-objects: @@ -368,7 +375,9 @@ Edge and Level Trigger Polling (epoll) Objects .. method:: epoll.poll(timeout=None, maxevents=-1) - Wait for events. timeout in seconds (float) + Wait for events. + If *timeout* is given, it specifies the length of time in seconds + (may be non-integer) which the system will wait for events before returning. .. versionchanged:: 3.5 The function is now retried with a recomputed timeout when interrupted by @@ -376,6 +385,9 @@ Edge and Level Trigger Polling (epoll) Objects :pep:`475` for the rationale), instead of raising :exc:`InterruptedError`. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. _poll-objects: @@ -464,6 +476,9 @@ linearly scanned again. :c:func:`!select` is *O*\ (*highest file descriptor*), w :pep:`475` for the rationale), instead of raising :exc:`InterruptedError`. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. _kqueue-objects: @@ -496,7 +511,7 @@ Kqueue Objects - changelist must be an iterable of kevent objects or ``None`` - max_events must be 0 or a positive integer - - timeout in seconds (floats possible); the default is ``None``, + - timeout in seconds (non-integers are possible); the default is ``None``, to wait forever .. versionchanged:: 3.5 @@ -505,6 +520,9 @@ Kqueue Objects :pep:`475` for the rationale), instead of raising :exc:`InterruptedError`. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. _kevent-objects: diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index b88fe4157bd..51bae2fce30 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -64,7 +64,7 @@ lots of shared sub-objects. The keys are ordinary strings. .. versionchanged:: 3.11 Accepts :term:`path-like object` for filename. - .. versionchanged:: next + .. versionchanged:: 3.15 Accepts custom *serializer* and *deserializer* functions in place of :func:`pickle.dumps` and :func:`pickle.loads`. @@ -103,7 +103,7 @@ Two additional methods are supported: Calls :meth:`sync` and attempts to shrink space used on disk by removing empty space resulting from deletions. - .. versionadded:: next + .. versionadded:: 3.15 .. method:: Shelf.close() @@ -185,7 +185,7 @@ Restrictions :const:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle protocol. - .. versionchanged:: next + .. versionchanged:: 3.15 Added the *serializer* and *deserializer* parameters. @@ -204,7 +204,7 @@ Restrictions optional *protocol*, *writeback*, *keyencoding*, *serializer* and *deserializer* parameters have the same interpretation as in :func:`~shelve.open`. - .. versionchanged:: next + .. versionchanged:: 3.15 Added the *serializer* and *deserializer* parameters. @@ -220,7 +220,7 @@ Restrictions and *deserializer* parameters have the same interpretation as in :func:`~shelve.open`. - .. versionchanged:: next + .. versionchanged:: 3.15 Added the *serializer* and *deserializer* parameters. @@ -274,7 +274,7 @@ Exceptions The *deserializer* and *serializer* arguments must be given together. - .. versionadded:: next + .. versionadded:: 3.15 .. seealso:: diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 692f31c8ca6..3a4631e7c65 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -90,6 +90,13 @@ Directory and files operations copy the file more efficiently. See :ref:`shutil-platform-dependent-efficient-copy-operations` section. +.. exception:: SpecialFileError + + This exception is raised when :func:`copyfile` or :func:`copytree` attempt + to copy a named pipe. + + .. versionadded:: 2.7 + .. exception:: SameFileError This exception is raised if source and destination in :func:`copyfile` diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index b0307d3dea1..cdefcd29ef7 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -205,10 +205,26 @@ The variables defined in the :mod:`signal` module are: .. availability:: Unix. +.. data:: SIGPROF + + Profiling timer expired. + + .. availability:: Unix. + +.. data:: SIGQUIT + + Terminal quit signal. + + .. availability:: Unix. + .. data:: SIGSEGV Segmentation fault: invalid memory reference. +.. data:: SIGSTOP + + Stop executing (cannot be caught or ignored). + .. data:: SIGSTKFLT Stack fault on coprocessor. The Linux kernel does not raise this signal: it @@ -237,18 +253,30 @@ The variables defined in the :mod:`signal` module are: .. availability:: Unix. +.. data:: SIGVTALRM + + Virtual timer expired. + + .. availability:: Unix. + .. data:: SIGWINCH Window resize signal. .. availability:: Unix. +.. data:: SIGXCPU + + CPU time limit exceeded. + + .. availability:: Unix. + .. data:: SIG* All the signal numbers are defined symbolically. For example, the hangup signal is defined as :const:`signal.SIGHUP`; the variable names are identical to the names used in C programs, as found in ````. The Unix man page for - ':c:func:`signal`' lists the existing signals (on some systems this is + '``signal``' lists the existing signals (on some systems this is :manpage:`signal(2)`, on others the list is in :manpage:`signal(7)`). Note that not all systems define the same set of signal names; only those names defined by the system are defined by this module. @@ -478,11 +506,11 @@ The :mod:`signal` module defines the following functions: .. versionadded:: 3.3 -.. function:: setitimer(which, seconds, interval=0.0) +.. function:: setitimer(which, seconds, interval=0) Sets given interval timer (one of :const:`signal.ITIMER_REAL`, :const:`signal.ITIMER_VIRTUAL` or :const:`signal.ITIMER_PROF`) specified - by *which* to fire after *seconds* (float is accepted, different from + by *which* to fire after *seconds* (rounded up to microseconds, different from :func:`alarm`) and after that every *interval* seconds (if *interval* is non-zero). The interval timer specified by *which* can be cleared by setting *seconds* to zero. @@ -493,13 +521,18 @@ The :mod:`signal` module defines the following functions: :const:`signal.ITIMER_VIRTUAL` sends :const:`SIGVTALRM`, and :const:`signal.ITIMER_PROF` will deliver :const:`SIGPROF`. - The old values are returned as a tuple: (delay, interval). + The old values are returned as a two-tuple of floats: + (``delay``, ``interval``). Attempting to pass an invalid interval timer will cause an :exc:`ItimerError`. .. availability:: Unix. + .. versionchanged:: 3.15 + Accepts any real numbers as *seconds* and *interval*, not only integers + or floats. + .. function:: getitimer(which) @@ -639,9 +672,8 @@ The :mod:`signal` module defines the following functions: *sigset*. The return value is an object representing the data contained in the - :c:type:`siginfo_t` structure, namely: :attr:`si_signo`, :attr:`si_code`, - :attr:`si_errno`, :attr:`si_pid`, :attr:`si_uid`, :attr:`si_status`, - :attr:`si_band`. + ``siginfo_t`` structure, namely: ``si_signo``, ``si_code``, + ``si_errno``, ``si_pid``, ``si_uid``, ``si_status``, ``si_band``. .. availability:: Unix. @@ -676,6 +708,9 @@ The :mod:`signal` module defines the following functions: by a signal not in *sigset* and the signal handler does not raise an exception (see :pep:`475` for the rationale). + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. _signal-example: diff --git a/Doc/library/site.rst b/Doc/library/site.rst index e98dd83b60e..d93e4dc7c75 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -270,7 +270,7 @@ Module contents .. _site-commandline: -Command Line Interface +Command-line interface ---------------------- .. program:: site diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index c5f8516f768..3bf5ec6099f 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -24,10 +24,13 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). .. class:: SMTP(host='', port=0, local_hostname=None[, timeout], source_address=None) An :class:`SMTP` instance encapsulates an SMTP connection. It has methods - that support a full repertoire of SMTP and ESMTP operations. If the optional - *host* and *port* parameters are given, the SMTP :meth:`connect` method is - called with those parameters during initialization. If specified, - *local_hostname* is used as the FQDN of the local host in the HELO/EHLO + that support a full repertoire of SMTP and ESMTP operations. + + If the host parameter is set to a truthy value, :meth:`SMTP.connect` is called with + host and port automatically when the object is created; otherwise, :meth:`!connect` must + be called manually. + + If specified, *local_hostname* is used as the FQDN of the local host in the HELO/EHLO command. Otherwise, the local hostname is found using :func:`socket.getfqdn`. If the :meth:`connect` call returns anything other than a success code, an :exc:`SMTPConnectError` is raised. The optional @@ -62,6 +65,10 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). ``smtplib.SMTP.send`` with arguments ``self`` and ``data``, where ``data`` is the bytes about to be sent to the remote host. + .. attribute:: SMTP.default_port + + The default port used for SMTP connections (25). + .. versionchanged:: 3.3 Support for the :keyword:`with` statement was added. @@ -80,15 +87,23 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). An :class:`SMTP_SSL` instance behaves exactly the same as instances of :class:`SMTP`. :class:`SMTP_SSL` should be used for situations where SSL is - required from the beginning of the connection and using :meth:`starttls` is - not appropriate. If *host* is not specified, the local host is used. If - *port* is zero, the standard SMTP-over-SSL port (465) is used. The optional - arguments *local_hostname*, *timeout* and *source_address* have the same + required from the beginning of the connection and using :meth:`SMTP.starttls` is + not appropriate. + + If the host parameter is set to a truthy value, :meth:`SMTP.connect` is called with host + and port automatically when the object is created; otherwise, :meth:`!SMTP.connect` must + be called manually. + + The optional arguments *local_hostname*, *timeout* and *source_address* have the same meaning as they do in the :class:`SMTP` class. *context*, also optional, can contain a :class:`~ssl.SSLContext` and allows configuring various aspects of the secure connection. Please read :ref:`ssl-security` for best practices. + .. attribute:: SMTP_SSL.default_port + + The default port used for SMTP-over-SSL connections (465). + .. versionchanged:: 3.3 *context* was added. @@ -112,7 +127,7 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). The LMTP protocol, which is very similar to ESMTP, is heavily based on the standard SMTP client. It's common to use Unix sockets for LMTP, so our - :meth:`connect` method must support that as well as a regular host:port + :meth:`~SMTP.connect` method must support that as well as a regular host:port server. The optional arguments *local_hostname* and *source_address* have the same meaning as they do in the :class:`SMTP` class. To specify a Unix socket, you must use an absolute path for *host*, starting with a '/'. @@ -147,9 +162,15 @@ A nice selection of exceptions is defined as well: .. exception:: SMTPResponseException Base class for all exceptions that include an SMTP error code. These exceptions - are generated in some instances when the SMTP server returns an error code. The - error code is stored in the :attr:`smtp_code` attribute of the error, and the - :attr:`smtp_error` attribute is set to the error message. + are generated in some instances when the SMTP server returns an error code. + + .. attribute:: smtp_code + + The error code. + + .. attribute:: smtp_error + + The error message. .. exception:: SMTPSenderRefused @@ -161,9 +182,13 @@ A nice selection of exceptions is defined as well: .. exception:: SMTPRecipientsRefused - All recipient addresses refused. The errors for each recipient are accessible - through the attribute :attr:`recipients`, which is a dictionary of exactly the - same sort as :meth:`SMTP.sendmail` returns. + All recipient addresses refused. + + .. attribute:: recipients + + A dictionary of exactly the same sort as returned + by :meth:`SMTP.sendmail` containing the errors for + each recipient. .. exception:: SMTPDataError @@ -213,7 +238,6 @@ SMTP Objects An :class:`SMTP` instance has the following methods: - .. method:: SMTP.set_debuglevel(level) Set the debug output level. A value of 1 or ``True`` for *level* results in @@ -250,6 +274,9 @@ An :class:`SMTP` instance has the following methods: 2-tuple of the response code and message sent by the server in its connection response. + If port is not changed from its default value of 0, the value of the :attr:`default_port` + attribute is used. + .. audit-event:: smtplib.connect self,host,port smtplib.SMTP.connect @@ -417,7 +444,7 @@ An :class:`SMTP` instance has the following methods: .. versionchanged:: 3.4 The method now supports hostname check with - :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see + :attr:`ssl.SSLContext.check_hostname` and *Server Name Indicator* (see :const:`~ssl.HAS_SNI`). .. versionchanged:: 3.5 @@ -431,11 +458,13 @@ An :class:`SMTP` instance has the following methods: Send mail. The required arguments are an :rfc:`822` from-address string, a list of :rfc:`822` to-address strings (a bare string will be treated as a list with 1 address), and a message string. The caller may pass a list of ESMTP options - (such as ``8bitmime``) to be used in ``MAIL FROM`` commands as *mail_options*. + (such as ``"8bitmime"``) to be used in ``MAIL FROM`` commands as *mail_options*. ESMTP options (such as ``DSN`` commands) that should be used with all ``RCPT`` - commands can be passed as *rcpt_options*. (If you need to use different ESMTP + commands can be passed as *rcpt_options*. Each option should be passed as a string + containing the full text of the option, including any potential key + (for instance, ``"NOTIFY=SUCCESS,FAILURE"``). (If you need to use different ESMTP options to different recipients you have to use the low-level methods such as - :meth:`mail`, :meth:`rcpt` and :meth:`data` to send the message.) + :meth:`!mail`, :meth:`!rcpt` and :meth:`!data` to send the message.) .. note:: @@ -467,10 +496,7 @@ An :class:`SMTP` instance has the following methods: This method may raise the following exceptions: :exc:`SMTPRecipientsRefused` - All recipients were refused. Nobody got the mail. The :attr:`recipients` - attribute of the exception object is a dictionary with information about the - refused recipients (like the one returned when at least one recipient was - accepted). + All recipients were refused. Nobody got the mail. :exc:`SMTPHeloError` The server didn't reply properly to the ``HELO`` greeting. @@ -546,6 +572,30 @@ Low-level methods corresponding to the standard SMTP/ESMTP commands ``HELP``, Normally these do not need to be called directly, so they are not documented here. For details, consult the module code. +Additionally, an SMTP instance has the following attributes: + + +.. attribute:: SMTP.helo_resp + + The response to the ``HELO`` command, see :meth:`helo`. + + +.. attribute:: SMTP.ehlo_resp + + The response to the ``EHLO`` command, see :meth:`ehlo`. + + +.. attribute:: SMTP.does_esmtp + + A boolean value indicating whether the server supports ESMTP, see + :meth:`ehlo`. + + +.. attribute:: SMTP.esmtp_features + + A dictionary of the names of SMTP service extensions supported by the server, + see :meth:`ehlo`. + .. _smtp-example: diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index bc89a3228f0..743d768bfa1 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -482,6 +482,9 @@ The AF_* and SOCK_* constants are now :class:`AddressFamily` and .. versionchanged:: 3.14 Added support for ``TCP_QUICKACK`` on Windows platforms when available. + .. versionchanged:: 3.15 + ``IPV6_HDRINCL`` was added. + .. data:: AF_CAN PF_CAN @@ -1407,11 +1410,14 @@ The :mod:`socket` module also offers various network-related services: .. function:: setdefaulttimeout(timeout) - Set the default timeout in seconds (float) for new socket objects. When + Set the default timeout in seconds (real number) for new socket objects. When the socket module is first imported, the default is ``None``. See :meth:`~socket.settimeout` for possible values and their respective meanings. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. + .. function:: sethostname(name) @@ -2073,7 +2079,7 @@ to sockets. .. method:: socket.settimeout(value) Set a timeout on blocking socket operations. The *value* argument can be a - nonnegative floating-point number expressing seconds, or ``None``. + nonnegative real number expressing seconds, or ``None``. If a non-zero value is given, subsequent socket operations will raise a :exc:`timeout` exception if the timeout period *value* has elapsed before the operation has completed. If zero is given, the socket is put in @@ -2085,12 +2091,12 @@ to sockets. The method no longer toggles :const:`SOCK_NONBLOCK` flag on :attr:`socket.type`. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. -.. method:: socket.setsockopt(level, optname, value: int) -.. method:: socket.setsockopt(level, optname, value: buffer) - :noindex: -.. method:: socket.setsockopt(level, optname, None, optlen: int) - :noindex: + +.. method:: socket.setsockopt(level, optname, value: int | Buffer) + socket.setsockopt(level, optname, None, optlen: int) .. index:: pair: module; struct diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst index 7fb629f7d2f..491b8769f44 100644 --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -24,7 +24,7 @@ There are four basic concrete server classes: :meth:`~BaseServer.server_activate`. The other parameters are passed to the :class:`BaseServer` base class. - .. versionchanged:: next + .. versionchanged:: 3.15 The default queue size is now ``socket.SOMAXCONN`` for :class:`socketserver.TCPServer`. .. class:: UDPServer(server_address, RequestHandlerClass, bind_and_activate=True) @@ -546,7 +546,7 @@ The difference is that the ``readline()`` call in the second handler will call first handler had to use a ``recv()`` loop to accumulate data until a newline itself. If it had just used a single ``recv()`` without the loop it would just have returned what has been received so far from the client. -TCP is stream based: data arrives in the order it was sent, but there no +TCP is stream based: data arrives in the order it was sent, but there is no correlation between client ``send()`` or ``sendall()`` calls and the number of ``recv()`` calls on the server required to receive it. diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index d317ead66f9..3b1a9c2f6ee 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -31,7 +31,9 @@ PostgreSQL or Oracle. The :mod:`!sqlite3` module was written by Gerhard Häring. It provides an SQL interface compliant with the DB-API 2.0 specification described by :pep:`249`, and -requires SQLite 3.15.2 or newer. +requires the third-party `SQLite `_ library. + +.. include:: ../includes/optional-module.rst This document includes four main sections: @@ -514,7 +516,7 @@ Module constants This constant is only available if Python was compiled with SQLite 3.24.0 or greater. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: threadsafety @@ -620,7 +622,7 @@ Connection objects supplied, this must be a :term:`callable` returning an instance of :class:`Cursor` or its subclasses. - .. method:: blobopen(table, column, row, /, *, readonly=False, name="main") + .. method:: blobopen(table, column, rowid, /, *, readonly=False, name="main") Open a :class:`Blob` handle to an existing :abbr:`BLOB (Binary Large OBject)`. @@ -631,8 +633,8 @@ Connection objects :param str column: The name of the column where the blob is located. - :param str row: - The name of the row where the blob is located. + :param int rowid: + The row id where the blob is located. :param bool readonly: Set to ``True`` if the blob should be opened without write @@ -1611,6 +1613,9 @@ Cursor objects If the *size* parameter is used, then it is best for it to retain the same value from one :meth:`fetchmany` call to the next. + .. versionchanged:: 3.15 + Negative *size* values are rejected by raising :exc:`ValueError`. + .. method:: fetchall() Return all (remaining) rows of a query result as a :class:`list`. @@ -1638,6 +1643,9 @@ Cursor objects Read/write attribute that controls the number of rows returned by :meth:`fetchmany`. The default value is 1 which means a single row would be fetched per call. + .. versionchanged:: 3.15 + Negative values are rejected by raising :exc:`ValueError`. + .. attribute:: connection Read-only attribute that provides the SQLite database :class:`Connection` diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 18985d42349..7d30094963d 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -18,8 +18,9 @@ This module provides access to Transport Layer Security (often known as "Secure Sockets Layer") encryption and peer authentication facilities for network sockets, both client-side and server-side. This module uses the OpenSSL -library. It is available on all modern Unix systems, Windows, macOS, and -probably additional platforms, as long as OpenSSL is installed on that platform. +library. + +.. include:: ../includes/optional-module.rst .. note:: @@ -125,7 +126,8 @@ Context creation A convenience function helps create :class:`SSLContext` objects for common purposes. -.. function:: create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None) +.. function:: create_default_context(purpose=Purpose.SERVER_AUTH, *,\ + cafile=None, capath=None, cadata=None) Return a new :class:`SSLContext` object with default settings for the given *purpose*. The settings are chosen by the :mod:`ssl` module, @@ -215,6 +217,25 @@ purposes. :data:`VERIFY_X509_STRICT` in its default verify flags. +Signature algorithms +^^^^^^^^^^^^^^^^^^^^ + +.. function:: get_sigalgs() + + Return a list of available TLS signature algorithm names used + by servers to complete the TLS handshake or clients requesting + certificate-based authentication. For example:: + + >>> ssl.get_sigalgs() # doctest: +SKIP + ['ecdsa_secp256r1_sha256', 'ecdsa_secp384r1_sha384', ...] + + These names can be used when building string values to pass to the + :meth:`SSLContext.set_client_sigalgs` and + :meth:`SSLContext.set_server_sigalgs` methods. + + .. versionadded:: 3.15 + + Exceptions ^^^^^^^^^^ @@ -314,7 +335,7 @@ Exceptions Random generation ^^^^^^^^^^^^^^^^^ -.. function:: RAND_bytes(num) +.. function:: RAND_bytes(num, /) Return *num* cryptographically strong pseudo-random bytes. Raises an :class:`SSLError` if the PRNG has not been seeded with enough data or if the @@ -334,11 +355,10 @@ Random generation .. function:: RAND_status() Return ``True`` if the SSL pseudo-random number generator has been seeded - with 'enough' randomness, and ``False`` otherwise. You can use - :func:`ssl.RAND_egd` and :func:`ssl.RAND_add` to increase the randomness of - the pseudo-random number generator. + with 'enough' randomness, and ``False`` otherwise. Use :func:`ssl.RAND_add` + to increase the randomness of the pseudo-random number generator. -.. function:: RAND_add(bytes, entropy) +.. function:: RAND_add(bytes, entropy, /) Mix the given *bytes* into the SSL pseudo-random number generator. The parameter *entropy* (a float) is a lower bound on the entropy contained in @@ -406,12 +426,12 @@ Certificate handling .. versionchanged:: 3.10 The *timeout* parameter was added. -.. function:: DER_cert_to_PEM_cert(DER_cert_bytes) +.. function:: DER_cert_to_PEM_cert(der_cert_bytes) Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded string version of the same certificate. -.. function:: PEM_cert_to_DER_cert(PEM_cert_string) +.. function:: PEM_cert_to_DER_cert(pem_cert_string) Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of bytes for that same certificate. @@ -939,7 +959,7 @@ Constants Whether the OpenSSL library has built-in support for External PSKs in TLS 1.3 as described in :rfc:`9258`. - .. versionadded:: next + .. versionadded:: 3.15 .. data:: HAS_PHA @@ -1114,7 +1134,7 @@ SSL Sockets functions support reading and writing of data larger than 2 GB. Writing zero-length data no longer fails with a protocol violation error. - .. versionchanged:: next + .. versionchanged:: 3.15 Python now uses ``SSL_sendfile`` internally when possible. The function sends a file more efficiently because it performs TLS encryption in the kernel to avoid additional context switches. @@ -1141,10 +1161,10 @@ SSL sockets also have the following additional methods and attributes: .. deprecated:: 3.6 Use :meth:`~SSLSocket.recv` instead of :meth:`~SSLSocket.read`. -.. method:: SSLSocket.write(buf) +.. method:: SSLSocket.write(data) - Write *buf* to the SSL socket and return the number of bytes written. The - *buf* argument must be an object supporting the buffer interface. + Write *data* to the SSL socket and return the number of bytes written. The + *data* argument must be an object supporting the buffer interface. Raise :exc:`SSLWantReadError` or :exc:`SSLWantWriteError` if the socket is :ref:`non-blocking ` and the write would block. @@ -1154,7 +1174,7 @@ SSL sockets also have the following additional methods and attributes: .. versionchanged:: 3.5 The socket timeout is no longer reset each time bytes are received or sent. - The socket timeout is now the maximum total duration to write *buf*. + The socket timeout is now the maximum total duration to write *data*. .. deprecated:: 3.6 Use :meth:`~SSLSocket.send` instead of :meth:`~SSLSocket.write`. @@ -1171,12 +1191,15 @@ SSL sockets also have the following additional methods and attributes: :meth:`~socket.socket.recv` and :meth:`~socket.socket.send` instead of these methods. -.. method:: SSLSocket.do_handshake() +.. method:: SSLSocket.do_handshake(block=False) Perform the SSL setup handshake. + If *block* is true and the timeout obtained by :meth:`~socket.socket.gettimeout` + is zero, the socket is set in blocking mode until the handshake is performed. + .. versionchanged:: 3.4 - The handshake method also performs :func:`match_hostname` when the + The handshake method also performs :func:`!match_hostname` when the :attr:`~SSLContext.check_hostname` attribute of the socket's :attr:`~SSLSocket.context` is true. @@ -1186,7 +1209,7 @@ SSL sockets also have the following additional methods and attributes: .. versionchanged:: 3.7 Hostname or IP address is matched by OpenSSL during handshake. The - function :func:`match_hostname` is no longer used. In case OpenSSL + function :func:`!match_hostname` is no longer used. In case OpenSSL refuses a hostname or IP address, the handshake is aborted early and a TLS alert message is sent to the peer. @@ -1295,7 +1318,23 @@ SSL sockets also have the following additional methods and attributes: Return the group used for doing key agreement on this connection. If no connection has been established, returns ``None``. - .. versionadded:: next + .. versionadded:: 3.15 + +.. method:: SSLSocket.client_sigalg() + + Return the signature algorithm used for performing certificate-based client + authentication on this connection, or ``None`` if no connection has been + established or client authentication didn't occur. + + .. versionadded:: 3.15 + +.. method:: SSLSocket.server_sigalg() + + Return the signature algorithm used by the server to complete the TLS + handshake on this connection, or ``None`` if no connection has been + established or the cipher suite has no signature. + + .. versionadded:: 3.15 .. method:: SSLSocket.compression() @@ -1671,7 +1710,7 @@ to speed up repeated connections from the same clients. :const:`True` this method will also return any associated aliases such as the ECDH curve names supported in older versions of OpenSSL. - .. versionadded:: next + .. versionadded:: 3.15 .. method:: SSLContext.set_default_verify_paths() @@ -1682,23 +1721,37 @@ to speed up repeated connections from the same clients. provided as part of the operating system, though, it is likely to be configured properly. -.. method:: SSLContext.set_ciphers(ciphers) +.. method:: SSLContext.set_ciphers(ciphers, /) - Set the available ciphers for sockets created with this context. - It should be a string in the `OpenSSL cipher list format + Set the allowed ciphers for sockets created with this context when + connecting using TLS 1.2 and earlier. The *ciphers* argument should + be a string in the `OpenSSL cipher list format `_. + To set allowed TLS 1.3 ciphers, use :meth:`SSLContext.set_ciphersuites`. + If no cipher can be selected (because compile-time options or other configuration forbids use of all the specified ciphers), an :class:`SSLError` will be raised. .. note:: - when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will - give the currently selected cipher. + When connected, the :meth:`SSLSocket.cipher` method of SSL sockets will + return details about the negotiated cipher. - TLS 1.3 cipher suites cannot be disabled with - :meth:`~SSLContext.set_ciphers`. +.. method:: SSLContext.set_ciphersuites(ciphersuites, /) -.. method:: SSLContext.set_groups(groups) + Set the allowed ciphers for sockets created with this context when + connecting using TLS 1.3. The *ciphersuites* argument should be a + colon-separate string of TLS 1.3 cipher names. If no cipher can be + selected (because compile-time options or other configuration forbids + use of all the specified ciphers), an :class:`SSLError` will be raised. + + .. note:: + When connected, the :meth:`SSLSocket.cipher` method of SSL sockets will + return details about the negotiated cipher. + + .. versionadded:: 3.15 + +.. method:: SSLContext.set_groups(groups, /) Set the groups allowed for key agreement for sockets created with this context. It should be a string in the `OpenSSL group list format @@ -1709,9 +1762,38 @@ to speed up repeated connections from the same clients. When connected, the :meth:`SSLSocket.group` method of SSL sockets will return the group used for key agreement on that connection. - .. versionadded:: next + .. versionadded:: 3.15 -.. method:: SSLContext.set_alpn_protocols(protocols) +.. method:: SSLContext.set_client_sigalgs(sigalgs, /) + + Set the signature algorithms allowed for certificate-based client + authentication. It should be a string in the `OpenSSL client sigalgs + list format + `_. + + .. note:: + + When connected, the :meth:`SSLSocket.client_sigalg` method of SSL + sockets will return the signature algorithm used for performing + certificate-based client authentication on that connection. + + .. versionadded:: 3.15 + +.. method:: SSLContext.set_server_sigalgs(sigalgs, /) + + Set the signature algorithms allowed for the server to complete the TLS + handshake. It should be a string in the `OpenSSL sigalgs list format + `_. + + .. note:: + + When connected, the :meth:`SSLSocket.server_sigalg` method of SSL + sockets will return the signature algorithm used by the server to + complete the TLS handshake on that connection. + + .. versionadded:: 3.15 + +.. method:: SSLContext.set_alpn_protocols(alpn_protocols) Specify which protocols the socket should advertise during the SSL/TLS handshake. It should be a list of ASCII strings, like ``['http/1.1', @@ -1725,7 +1807,7 @@ to speed up repeated connections from the same clients. .. versionadded:: 3.5 -.. method:: SSLContext.set_npn_protocols(protocols) +.. method:: SSLContext.set_npn_protocols(npn_protocols) Specify which protocols the socket should advertise during the SSL/TLS handshake. It should be a list of strings, like ``['http/1.1', 'spdy/2']``, @@ -1792,7 +1874,7 @@ to speed up repeated connections from the same clients. .. versionadded:: 3.7 -.. attribute:: SSLContext.set_servername_callback(server_name_callback) +.. method:: SSLContext.set_servername_callback(server_name_callback) This is a legacy API retained for backwards compatibility. When possible, you should use :attr:`sni_callback` instead. The given *server_name_callback* @@ -1806,7 +1888,7 @@ to speed up repeated connections from the same clients. .. versionadded:: 3.4 -.. method:: SSLContext.load_dh_params(dhfile) +.. method:: SSLContext.load_dh_params(dhfile, /) Load the key generation parameters for Diffie-Hellman (DH) key exchange. Using DH key exchange improves forward secrecy at the expense of @@ -1819,7 +1901,7 @@ to speed up repeated connections from the same clients. .. versionadded:: 3.3 -.. method:: SSLContext.set_ecdh_curve(curve_name) +.. method:: SSLContext.set_ecdh_curve(curve_name, /) Set the curve name for Elliptic Curve-based Diffie-Hellman (ECDH) key exchange. ECDH is significantly faster than regular DH while arguably @@ -2693,12 +2775,12 @@ purpose. It wraps an OpenSSL memory BIO (Basic IO) object: A boolean indicating whether the memory BIO is current at the end-of-file position. - .. method:: MemoryBIO.read(n=-1) + .. method:: MemoryBIO.read(n=-1, /) Read up to *n* bytes from the memory buffer. If *n* is not specified or negative, all bytes are returned. - .. method:: MemoryBIO.write(buf) + .. method:: MemoryBIO.write(buf, /) Write the bytes from *buf* to the memory BIO. The *buf* argument must be an object supporting the buffer protocol. @@ -2781,7 +2863,7 @@ This common check is automatically performed when .. versionchanged:: 3.7 Hostname matchings is now performed by OpenSSL. Python no longer uses - :func:`match_hostname`. + :func:`!match_hostname`. In server mode, if you want to authenticate your clients using the SSL layer (rather than using a higher-level authentication mechanism), you'll also have @@ -2845,10 +2927,15 @@ TLS 1.3 The TLS 1.3 protocol behaves slightly differently than previous version of TLS/SSL. Some new TLS 1.3 features are not yet available. -- TLS 1.3 uses a disjunct set of cipher suites. All AES-GCM and - ChaCha20 cipher suites are enabled by default. The method - :meth:`SSLContext.set_ciphers` cannot enable or disable any TLS 1.3 - ciphers yet, but :meth:`SSLContext.get_ciphers` returns them. +- TLS 1.3 uses a disjunct set of cipher suites. All AES-GCM and ChaCha20 + cipher suites are enabled by default. To restrict which TLS 1.3 ciphers + are allowed, the :meth:`SSLContext.set_ciphersuites` method should be + called instead of :meth:`SSLContext.set_ciphers`, which only affects + ciphers in older TLS versions. The :meth:`SSLContext.get_ciphers` method + returns information about ciphers for both TLS 1.3 and earlier versions + and the method :meth:`SSLSocket.cipher` returns information about the + negotiated cipher for both TLS 1.3 and earlier versions once a connection + is established. - Session tickets are no longer sent as part of the initial handshake and are handled differently. :attr:`SSLSocket.session` and :class:`SSLSession` are not compatible with TLS 1.3. @@ -2857,7 +2944,7 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available. process certificate requests while they send or receive application data from the server. - TLS 1.3 features like early data, deferred TLS client cert request, - signature algorithm configuration, and rekeying are not supported yet. + and rekeying are not supported yet. .. seealso:: @@ -2872,16 +2959,16 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available. Steve Kent :rfc:`RFC 4086: Randomness Requirements for Security <4086>` - Donald E., Jeffrey I. Schiller + Donald E. Eastlake, Jeffrey I. Schiller, Steve Crocker :rfc:`RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile <5280>` - D. Cooper + David Cooper et al. :rfc:`RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 <5246>` - T. Dierks et. al. + Tim Dierks and Eric Rescorla. :rfc:`RFC 6066: Transport Layer Security (TLS) Extensions <6066>` - D. Eastlake + Donald E. Eastlake `IANA TLS: Transport Layer Security (TLS) Parameters `_ IANA diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst index 8434b2e8c75..82012b31a00 100644 --- a/Doc/library/stat.rst +++ b/Doc/library/stat.rst @@ -493,3 +493,22 @@ constants, but are not an exhaustive list. IO_REPARSE_TAG_APPEXECLINK .. versionadded:: 3.8 + +On Linux, the following file attribute constants are available for use when +testing bits in the :attr:`~os.statx_result.stx_attributes` and +:attr:`~os.statx_result.stx_attributes_mask` members returned by +:func:`os.statx`. See the :manpage:`statx(2)` man page for more detail on the +meaning of these constants. + +.. data:: STATX_ATTR_COMPRESSED + STATX_ATTR_IMMUTABLE + STATX_ATTR_APPEND + STATX_ATTR_NODUMP + STATX_ATTR_ENCRYPTED + STATX_ATTR_AUTOMOUNT + STATX_ATTR_MOUNT_ROOT + STATX_ATTR_VERITY + STATX_ATTR_DAX + STATX_ATTR_WRITE_ATOMIC + + .. versionadded:: 3.15 diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 3320f7c3bba..f33b73238ec 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -164,7 +164,7 @@ This table summarizes the comparison operations: pair: object; numeric pair: objects; comparing -Objects of different types, except different numeric types, never compare equal. +Unless stated otherwise, objects of different types never compare equal. The ``==`` operator is always defined but for some object types (for example, class objects) is equivalent to :keyword:`is`. The ``<``, ``<=``, ``>`` and ``>=`` operators are only defined where they make sense; for example, they raise a @@ -1000,8 +1000,6 @@ operations have the same priority as the corresponding numeric operations. [3]_ pair: slice; operation pair: operator; in pair: operator; not in - single: count() (sequence method) - single: index() (sequence method) +--------------------------+--------------------------------+----------+ | Operation | Result | Notes | @@ -1018,7 +1016,7 @@ operations have the same priority as the corresponding numeric operations. [3]_ | ``s * n`` or | equivalent to adding *s* to | (2)(7) | | ``n * s`` | itself *n* times | | +--------------------------+--------------------------------+----------+ -| ``s[i]`` | *i*\ th item of *s*, origin 0 | (3)(9) | +| ``s[i]`` | *i*\ th item of *s*, origin 0 | (3)(8) | +--------------------------+--------------------------------+----------+ | ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) | +--------------------------+--------------------------------+----------+ @@ -1031,13 +1029,6 @@ operations have the same priority as the corresponding numeric operations. [3]_ +--------------------------+--------------------------------+----------+ | ``max(s)`` | largest item of *s* | | +--------------------------+--------------------------------+----------+ -| ``s.index(x[, i[, j]])`` | index of the first occurrence | \(8) | -| | of *x* in *s* (at or after | | -| | index *i* and before index *j*)| | -+--------------------------+--------------------------------+----------+ -| ``s.count(x)`` | total number of occurrences of | | -| | *x* in *s* | | -+--------------------------+--------------------------------+----------+ Sequences of the same type also support comparisons. In particular, tuples and lists are compared lexicographically by comparing corresponding elements. @@ -1143,16 +1134,42 @@ Notes: concatenation or repetition. (8) - ``index`` raises :exc:`ValueError` when *x* is not found in *s*. - Not all implementations support passing the additional arguments *i* and *j*. - These arguments allow efficient searching of subsections of the sequence. Passing - the extra arguments is roughly equivalent to using ``s[i:j].index(x)``, only - without copying any data and with the returned index being relative to - the start of the sequence rather than the start of the slice. - -(9) An :exc:`IndexError` is raised if *i* is outside the sequence range. +.. rubric:: Sequence Methods + +Sequence types also support the following methods: + +.. method:: list.count(value, /) + range.count(value, /) + tuple.count(value, /) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.count(value, /) + + Return the total number of occurrences of *value* in *sequence*. + +.. method:: list.index(value[, start[, stop]) + range.index(value[, start[, stop]) + tuple.index(value[, start[, stop]) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.index(value[, start[, stop]) + + Return the index of the first occurrence of *value* in *sequence*. + + Raises :exc:`ValueError` if *value* is not found in *sequence*. + + The *start* or *stop* arguments allow for efficient searching + of subsections of the sequence, beginning at *start* and ending at *stop*. + This is roughly equivalent to ``start + sequence[start:stop].index(value)``, + only without copying any data. + + .. caution:: + Not all sequence types support passing the *start* and *stop* arguments. + .. _typesseq-immutable: @@ -1202,14 +1219,6 @@ accepts integers that meet the value restriction ``0 <= x <= 255``). pair: subscript; assignment pair: slice; assignment pair: statement; del - single: append() (sequence method) - single: clear() (sequence method) - single: copy() (sequence method) - single: extend() (sequence method) - single: insert() (sequence method) - single: pop() (sequence method) - single: remove() (sequence method) - single: reverse() (sequence method) +------------------------------+--------------------------------+---------------------+ | Operation | Result | Notes | @@ -1233,39 +1242,14 @@ accepts integers that meet the value restriction ``0 <= x <= 255``). | ``del s[i:j:k]`` | removes the elements of | | | | ``s[i:j:k]`` from the list | | +------------------------------+--------------------------------+---------------------+ -| ``s.append(x)`` | appends *x* to the end of the | | -| | sequence (same as | | -| | ``s[len(s):len(s)] = [x]``) | | -+------------------------------+--------------------------------+---------------------+ -| ``s.clear()`` | removes all items from *s* | \(5) | -| | (same as ``del s[:]``) | | -+------------------------------+--------------------------------+---------------------+ -| ``s.copy()`` | creates a shallow copy of *s* | \(5) | -| | (same as ``s[:]``) | | -+------------------------------+--------------------------------+---------------------+ -| ``s.extend(t)`` or | extends *s* with the | | -| ``s += t`` | contents of *t* (for the | | +| ``s += t`` | extends *s* with the | | +| | contents of *t* (for the | | | | most part the same as | | | | ``s[len(s):len(s)] = t``) | | +------------------------------+--------------------------------+---------------------+ -| ``s *= n`` | updates *s* with its contents | \(6) | +| ``s *= n`` | updates *s* with its contents | \(2) | | | repeated *n* times | | +------------------------------+--------------------------------+---------------------+ -| ``s.insert(i, x)`` | inserts *x* into *s* at the | | -| | index given by *i* | | -| | (same as ``s[i:i] = [x]``) | | -+------------------------------+--------------------------------+---------------------+ -| ``s.pop()`` or ``s.pop(i)`` | retrieves the item at *i* and | \(2) | -| | also removes it from *s* | | -+------------------------------+--------------------------------+---------------------+ -| ``s.remove(x)`` | removes the first item from | \(3) | -| | *s* where ``s[i]`` is equal to | | -| | *x* | | -+------------------------------+--------------------------------+---------------------+ -| ``s.reverse()`` | reverses the items of *s* in | \(4) | -| | place | | -+------------------------------+--------------------------------+---------------------+ - Notes: @@ -1273,33 +1257,106 @@ Notes: If *k* is not equal to ``1``, *t* must have the same length as the slice it is replacing. (2) - The optional argument *i* defaults to ``-1``, so that by default the last - item is removed and returned. - -(3) - :meth:`remove` raises :exc:`ValueError` when *x* is not found in *s*. - -(4) - The :meth:`reverse` method modifies the sequence in place for economy of - space when reversing a large sequence. To remind users that it operates by - side effect, it does not return the reversed sequence. - -(5) - :meth:`clear` and :meth:`!copy` are included for consistency with the - interfaces of mutable containers that don't support slicing operations - (such as :class:`dict` and :class:`set`). :meth:`!copy` is not part of the - :class:`collections.abc.MutableSequence` ABC, but most concrete - mutable sequence classes provide it. - - .. versionadded:: 3.3 - :meth:`clear` and :meth:`!copy` methods. - -(6) The value *n* is an integer, or an object implementing :meth:`~object.__index__`. Zero and negative values of *n* clear the sequence. Items in the sequence are not copied; they are referenced multiple times, as explained for ``s * n`` under :ref:`typesseq-common`. +.. rubric:: Mutable Sequence Methods + +Mutable sequence types also support the following methods: + +.. method:: bytearray.append(value, /) + list.append(value, /) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.append(value, /) + + Append *value* to the end of the sequence + This is equivalent to writing ``seq[len(seq):len(seq)] = [value]``. + +.. method:: bytearray.clear() + list.clear() + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.clear() + + .. versionadded:: 3.3 + + Remove all items from *sequence*. + This is equivalent to writing ``del sequence[:]``. + +.. method:: bytearray.copy() + list.copy() + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.copy() + + .. versionadded:: 3.3 + + Create a shallow copy of *sequence*. + This is equivalent to writing ``sequence[:]``. + + .. hint:: The :meth:`!copy` method is not part of the + :class:`~collections.abc.MutableSequence` :class:`~abc.ABC`, + but most concrete mutable sequence types provide it. + +.. method:: bytearray.extend(iterable, /) + list.extend(iterable, /) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.extend(iterable, /) + + Extend *sequence* with the contents of *iterable*. + For the most part, this is the same as writing + ``seq[len(seq):len(seq)] = iterable``. + +.. method:: bytearray.insert(index, value, /) + list.insert(index, value, /) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.insert(index, value, /) + + Insert *value* into *sequence* at the given *index*. + This is equivalent to writing ``sequence[index:index] = [value]``. + +.. method:: bytearray.pop(index=-1, /) + list.pop(index=-1, /) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.pop(index=-1, /) + + Retrieve the item at *index* and also removes it from *sequence*. + By default, the last item in *sequence* is removed and returned. + +.. method:: bytearray.remove(value, /) + list.remove(value, /) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.remove(value, /) + + Remove the first item from *sequence* where ``sequence[i] == value``. + + Raises :exc:`ValueError` if *value* is not found in *sequence*. + +.. method:: bytearray.reverse() + list.reverse() + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. method:: sequence.reverse() + + Reverse the items of *sequence* in place. + This method maintains economy of space when reversing a large sequence. + To remind users that it operates by side-effect, it returns ``None``. + .. _typesseq-list: @@ -1786,9 +1843,9 @@ expression support in the :mod:`re` module). lowercase, :meth:`lower` would do nothing to ``'ß'``; :meth:`casefold` converts it to ``"ss"``. - The casefolding algorithm is - `described in section 3.13 'Default Case Folding' of the Unicode Standard - `__. + The casefolding algorithm is `described in section 3.13.3 'Default Case + Folding' of the Unicode Standard + `__. .. versionadded:: 3.3 @@ -1937,10 +1994,16 @@ expression support in the :mod:`re` module). ``{}``. Each replacement field contains either the numeric index of a positional argument, or the name of a keyword argument. Returns a copy of the string where each replacement field is replaced with the string value of - the corresponding argument. + the corresponding argument. For example: + + .. doctest:: >>> "The sum of 1 + 2 is {0}".format(1+2) 'The sum of 1 + 2 is 3' + >>> "The sum of {a} + {b} is {answer}".format(answer=1+2, a=1, b=2) + 'The sum of 1 + 2 is 3' + >>> "{1} expects the {0} Inquisition!".format("Spanish", "Nobody") + 'Nobody expects the Spanish Inquisition!' See :ref:`formatstrings` for a description of the various formatting options that can be specified in format strings. @@ -1999,14 +2062,33 @@ expression support in the :mod:`re` module). property being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is different from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and Ideographic' of the Unicode Standard - `_. + `__. + For example: + + .. doctest:: + + >>> 'Letters and spaces'.isalpha() + False + >>> 'LettersOnly'.isalpha() + True + >>> 'µ'.isalpha() # non-ASCII characters can be considered alphabetical too + True + + See :ref:`unicode-properties`. .. method:: str.isascii() Return ``True`` if the string is empty or all characters in the string are ASCII, ``False`` otherwise. - ASCII characters have code points in the range U+0000-U+007F. + ASCII characters have code points in the range U+0000-U+007F. For example: + + .. doctest:: + + >>> 'ASCII characters'.isascii() + True + >>> 'µ'.isascii() + False .. versionadded:: 3.7 @@ -2016,9 +2098,18 @@ expression support in the :mod:`re` module). Return ``True`` if all characters in the string are decimal characters and there is at least one character, ``False`` otherwise. Decimal characters are those that can be used to form - numbers in base 10, e.g. U+0660, ARABIC-INDIC DIGIT + numbers in base 10, such as U+0660, ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in the Unicode - General Category "Nd". + General Category "Nd". For example: + + .. doctest:: + + >>> '0123456789'.isdecimal() + True + >>> '٠١٢٣٤٥٦٧٨٩'.isdecimal() # Arabic-Indic digits zero to nine + True + >>> 'alphabetic'.isdecimal() + False .. method:: str.isdigit() @@ -2064,6 +2155,21 @@ expression support in the :mod:`re` module). that have the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric characters are those with the property value Numeric_Type=Digit, Numeric_Type=Decimal or Numeric_Type=Numeric. + For example: + + .. doctest:: + + >>> '0123456789'.isnumeric() + True + >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-indic digit zero to nine + True + >>> '⅕'.isnumeric() # Vulgar fraction one fifth + True + >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric() + (False, True, True) + + See also :meth:`isdecimal` and :meth:`isdigit`. Numeric characters are + a superset of decimal numbers. .. method:: str.isprintable() @@ -2100,6 +2206,19 @@ expression support in the :mod:`re` module). character, for example uppercase characters may only follow uncased characters and lowercase characters only cased ones. Return ``False`` otherwise. + For example: + + .. doctest:: + + >>> 'Spam, Spam, Spam'.istitle() + True + >>> 'spam, spam, spam'.istitle() + False + >>> 'SPAM, SPAM, SPAM'.istitle() + False + + See also :meth:`title`. + .. method:: str.isupper() @@ -2124,7 +2243,16 @@ expression support in the :mod:`re` module). Return a string which is the concatenation of the strings in *iterable*. A :exc:`TypeError` will be raised if there are any non-string values in *iterable*, including :class:`bytes` objects. The separator between - elements is the string providing this method. + elements is the string providing this method. For example: + + .. doctest:: + + >>> ', '.join(['spam', 'spam', 'spam']) + 'spam, spam, spam' + >>> '-'.join('Python') + 'P-y-t-h-o-n' + + See also :meth:`split`. .. method:: str.ljust(width, fillchar=' ', /) @@ -2133,15 +2261,28 @@ expression support in the :mod:`re` module). done using the specified *fillchar* (default is an ASCII space). The original string is returned if *width* is less than or equal to ``len(s)``. + For example: + + .. doctest:: + + >>> 'Python'.ljust(10) + 'Python ' + >>> 'Python'.ljust(10, '.') + 'Python....' + >>> 'Monty Python'.ljust(10, '.') + 'Monty Python' + + See also :meth:`rjust`. + .. method:: str.lower() Return a copy of the string with all the cased characters [4]_ converted to lowercase. - The lowercasing algorithm used is - `described in section 3.13 'Default Case Folding' of the Unicode Standard - `__. + The lowercasing algorithm used is `described in section 3.13.2 'Default Case + Conversion' of the Unicode Standard + `__. .. method:: str.lstrip(chars=None, /) @@ -2338,6 +2479,8 @@ expression support in the :mod:`re` module). >>> " foo ".split(maxsplit=0) ['foo '] + See also :meth:`join`. + .. index:: single: universal newlines; str.splitlines method @@ -2477,6 +2620,8 @@ expression support in the :mod:`re` module). >>> titlecase("they're bill's friends.") "They're Bill's Friends." + See also :meth:`istitle`. + .. method:: str.translate(table, /) @@ -2504,9 +2649,9 @@ expression support in the :mod:`re` module). character(s) is not "Lu" (Letter, uppercase), but e.g. "Lt" (Letter, titlecase). - The uppercasing algorithm used is - `described in section 3.13 'Default Case Folding' of the Unicode Standard - `__. + The uppercasing algorithm used is `described in section 3.13.2 'Default Case + Conversion' of the Unicode Standard + `__. .. method:: str.zfill(width, /) @@ -2539,6 +2684,8 @@ expression support in the :mod:`re` module). single: : (colon); in formatted string literal single: = (equals); for help in debugging using string literals +.. _stdtypes-fstrings: + Formatted String Literals (f-strings) ------------------------------------- @@ -2547,123 +2694,147 @@ Formatted String Literals (f-strings) The :keyword:`await` and :keyword:`async for` can be used in expressions within f-strings. .. versionchanged:: 3.8 - Added the debugging operator (``=``) + Added the debug specifier (``=``) .. versionchanged:: 3.12 Many restrictions on expressions within f-strings have been removed. Notably, nested strings, comments, and backslashes are now permitted. An :dfn:`f-string` (formally a :dfn:`formatted string literal`) is a string literal that is prefixed with ``f`` or ``F``. -This type of string literal allows embedding arbitrary Python expressions -within *replacement fields*, which are delimited by curly brackets (``{}``). -These expressions are evaluated at runtime, similarly to :meth:`str.format`, -and are converted into regular :class:`str` objects. -For example: +This type of string literal allows embedding the results of arbitrary Python +expressions within *replacement fields*, which are delimited by curly +brackets (``{}``). +Each replacement field must contain an expression, optionally followed by: -.. doctest:: +* a *debug specifier* -- an equal sign (``=``); +* a *conversion specifier* -- ``!s``, ``!r`` or ``!a``; and/or +* a *format specifier* prefixed with a colon (``:``). - >>> who = 'nobody' - >>> nationality = 'Spanish' - >>> f'{who.title()} expects the {nationality} Inquisition!' - 'Nobody expects the Spanish Inquisition!' +See the :ref:`Lexical Analysis section on f-strings ` for details +on the syntax of these fields. -It is also possible to use a multi line f-string: +Debug specifier +^^^^^^^^^^^^^^^ -.. doctest:: +.. versionadded:: 3.8 - >>> f'''This is a string - ... on two lines''' - 'This is a string\non two lines' +If a debug specifier -- an equal sign (``=``) -- appears after the replacement +field expression, the resulting f-string will contain the expression's source, +the equal sign, and the value of the expression. +This is often useful for debugging:: -A single opening curly bracket, ``'{'``, marks a *replacement field* that -can contain any Python expression: + >>> number = 14.3 + >>> f'{number=}' + 'number=14.3' -.. doctest:: +Whitespace before, inside and after the expression, as well as whitespace +after the equal sign, is significant --- it is retained in the result:: - >>> nationality = 'Spanish' - >>> f'The {nationality} Inquisition!' - 'The Spanish Inquisition!' + >>> f'{ number - 4 = }' + ' number - 4 = 10.3' -To include a literal ``{`` or ``}``, use a double bracket: -.. doctest:: +Conversion specifier +^^^^^^^^^^^^^^^^^^^^ - >>> x = 42 - >>> f'{{x}} is {x}' - '{x} is 42' - -Functions can also be used, and :ref:`format specifiers `: - -.. doctest:: - - >>> from math import sqrt - >>> f'√2 \N{ALMOST EQUAL TO} {sqrt(2):.5f}' - '√2 ≈ 1.41421' - -Any non-string expression is converted using :func:`str`, by default: - -.. doctest:: +By default, the value of a replacement field expression is converted to +a string using :func:`str`:: >>> from fractions import Fraction - >>> f'{Fraction(1, 3)}' + >>> one_third = Fraction(1, 3) + >>> f'{one_third}' '1/3' -To use an explicit conversion, use the ``!`` (exclamation mark) operator, -followed by any of the valid formats, which are: +When a debug specifier but no format specifier is used, the default conversion +instead uses :func:`repr`:: -========== ============== -Conversion Meaning -========== ============== -``!a`` :func:`ascii` -``!r`` :func:`repr` -``!s`` :func:`str` -========== ============== + >>> f'{one_third = }' + 'one_third = Fraction(1, 3)' -For example: +The conversion can be specified explicitly using one of these specifiers: -.. doctest:: +* ``!s`` for :func:`str` +* ``!r`` for :func:`repr` +* ``!a`` for :func:`ascii` - >>> from fractions import Fraction - >>> f'{Fraction(1, 3)!s}' +For example:: + + >>> str(one_third) '1/3' - >>> f'{Fraction(1, 3)!r}' + >>> repr(one_third) 'Fraction(1, 3)' - >>> question = '¿Dónde está el Presidente?' - >>> print(f'{question!a}') - '\xbfD\xf3nde est\xe1 el Presidente?' -While debugging it may be helpful to see both the expression and its value, -by using the equals sign (``=``) after the expression. -This preserves spaces within the brackets, and can be used with a converter. -By default, the debugging operator uses the :func:`repr` (``!r``) conversion. -For example: + >>> f'{one_third!s} is {one_third!r}' + '1/3 is Fraction(1, 3)' -.. doctest:: + >>> string = "¡kočka 😸!" + >>> ascii(string) + "'\\xa1ko\\u010dka \\U0001f638!'" + + >>> f'{string = !a}' + "string = '\\xa1ko\\u010dka \\U0001f638!'" + + +Format specifier +^^^^^^^^^^^^^^^^ + +After the expression has been evaluated, and possibly converted using an +explicit conversion specifier, it is formatted using the :func:`format` function. +If the replacement field includes a *format specifier* introduced by a colon +(``:``), the specifier is passed to :func:`!format` as the second argument. +The result of :func:`!format` is then used as the final value for the +replacement field. For example:: >>> from fractions import Fraction - >>> calculation = Fraction(1, 3) - >>> f'{calculation=}' - 'calculation=Fraction(1, 3)' - >>> f'{calculation = }' - 'calculation = Fraction(1, 3)' - >>> f'{calculation = !s}' - 'calculation = 1/3' + >>> one_third = Fraction(1, 3) + >>> f'{one_third:.6f}' + '0.333333' + >>> f'{one_third:_^+10}' + '___+1/3___' + >>> >>> f'{one_third!r:_^20}' + '___Fraction(1, 3)___' + >>> f'{one_third = :~>10}~' + 'one_third = ~~~~~~~1/3~' -Once the output has been evaluated, it can be formatted using a -:ref:`format specifier ` following a colon (``':'``). -After the expression has been evaluated, and possibly converted to a string, -the :meth:`!__format__` method of the result is called with the format specifier, -or the empty string if no format specifier is given. -The formatted result is then used as the final value for the replacement field. -For example: +.. _stdtypes-tstrings: -.. doctest:: +Template String Literals (t-strings) +------------------------------------ - >>> from fractions import Fraction - >>> f'{Fraction(1, 7):.6f}' - '0.142857' - >>> f'{Fraction(1, 7):_^+10}' - '___+1/7___' +An :dfn:`t-string` (formally a :dfn:`template string literal`) is +a string literal that is prefixed with ``t`` or ``T``. + +These strings follow the same syntax and evaluation rules as +:ref:`formatted string literals `, +with for the following differences: + +* Rather than evaluating to a ``str`` object, template string literals evaluate + to a :class:`string.templatelib.Template` object. + +* The :func:`format` protocol is not used. + Instead, the format specifier and conversions (if any) are passed to + a new :class:`~string.templatelib.Interpolation` object that is created + for each evaluated expression. + It is up to code that processes the resulting :class:`~string.templatelib.Template` + object to decide how to handle format specifiers and conversions. + +* Format specifiers containing nested replacement fields are evaluated eagerly, + prior to being passed to the :class:`~string.templatelib.Interpolation` object. + For instance, an interpolation of the form ``{amount:.{precision}f}`` will + evaluate the inner expression ``{precision}`` to determine the value of the + ``format_spec`` attribute. + If ``precision`` were to be ``2``, the resulting format specifier + would be ``'.2f'``. + +* When the equals sign ``'='`` is provided in an interpolation expression, + the text of the expression is appended to the literal string that precedes + the relevant interpolation. + This includes the equals sign and any surrounding whitespace. + The :class:`!Interpolation` instance for the expression will be created as + normal, except that :attr:`~string.templatelib.Interpolation.conversion` will + be set to '``r``' (:func:`repr`) by default. + If an explicit conversion or format specifier are provided, + this will override the default behaviour. .. _old-string-formatting: @@ -3101,6 +3272,30 @@ objects. .. versionadded:: 3.14 + .. method:: take_bytes(n=None, /) + + Remove the first *n* bytes from the bytearray and return them as an immutable + :class:`bytes`. + By default (if *n* is ``None``), return all bytes and clear the bytearray. + + If *n* is negative, index from the end and take the first :func:`len` + plus *n* bytes. If *n* is out of bounds, raise :exc:`IndexError`. + + Taking less than the full length will leave remaining bytes in the + :class:`bytearray`, which requires a copy. If the remaining bytes should be + discarded, use :func:`~bytearray.resize` or :keyword:`del` to truncate + then :func:`~bytearray.take_bytes` without a size. + + .. impl-detail:: + + Taking all bytes is a zero-copy operation. + + .. versionadded:: 3.15 + + See the :ref:`What's New ` entry for + common code patterns which can be optimized with + :meth:`bytearray.take_bytes`. + Since bytearray objects are sequences of integers (akin to a list), for a bytearray object *b*, ``b[0]`` will be an integer, while ``b[0:1]`` will be a bytearray object of length 1. (This contrasts with text strings, where @@ -4508,7 +4703,7 @@ copying. .. versionadded:: 3.14 - .. method:: index(value, start=0, stop=sys.maxsize, /) + .. method:: index(value, start=0, stop=sys.maxsize, /) Return the index of the first occurrence of *value* (at or after index *start* and before index *stop*). @@ -4659,11 +4854,12 @@ other sequence-like behavior. There are currently two built-in set types, :class:`set` and :class:`frozenset`. The :class:`set` type is mutable --- the contents can be changed using methods -like :meth:`~set.add` and :meth:`~set.remove`. Since it is mutable, it has no -hash value and cannot be used as either a dictionary key or as an element of -another set. The :class:`frozenset` type is immutable and :term:`hashable` --- -its contents cannot be altered after it is created; it can therefore be used as -a dictionary key or as an element of another set. +like :meth:`~set.add` and :meth:`~set.remove`. +Since it is mutable, it has no hash value and cannot be used as +either a dictionary key or as an element of another set. +The :class:`frozenset` type is immutable and :term:`hashable` --- +its contents cannot be altered after it is created; +it can therefore be used as a dictionary key or as an element of another set. Non-empty sets (not frozensets) can be created by placing a comma-separated list of elements within braces, for example: ``{'jack', 'sjoerd'}``, in addition to the @@ -4680,164 +4876,172 @@ The constructors for both classes work the same: objects. If *iterable* is not specified, a new empty set is returned. - Sets can be created by several means: +Sets can be created by several means: - * Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}`` - * Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}`` - * Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])`` +* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}`` +* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}`` +* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])`` - Instances of :class:`set` and :class:`frozenset` provide the following - operations: +Instances of :class:`set` and :class:`frozenset` provide the following +operations: - .. describe:: len(s) +.. describe:: len(s) - Return the number of elements in set *s* (cardinality of *s*). + Return the number of elements in set *s* (cardinality of *s*). - .. describe:: x in s +.. describe:: x in s - Test *x* for membership in *s*. + Test *x* for membership in *s*. - .. describe:: x not in s +.. describe:: x not in s - Test *x* for non-membership in *s*. + Test *x* for non-membership in *s*. - .. method:: isdisjoint(other, /) +.. method:: frozenset.isdisjoint(other, /) + set.isdisjoint(other, /) - Return ``True`` if the set has no elements in common with *other*. Sets are - disjoint if and only if their intersection is the empty set. + Return ``True`` if the set has no elements in common with *other*. Sets are + disjoint if and only if their intersection is the empty set. - .. method:: issubset(other, /) - set <= other +.. method:: frozenset.issubset(other, /) + set.issubset(other, /) +.. describe:: set <= other - Test whether every element in the set is in *other*. + Test whether every element in the set is in *other*. - .. method:: set < other +.. describe:: set < other - Test whether the set is a proper subset of *other*, that is, - ``set <= other and set != other``. + Test whether the set is a proper subset of *other*, that is, + ``set <= other and set != other``. - .. method:: issuperset(other, /) - set >= other +.. method:: frozenset.issuperset(other, /) + set.issuperset(other, /) +.. describe:: set >= other - Test whether every element in *other* is in the set. + Test whether every element in *other* is in the set. - .. method:: set > other +.. describe:: set > other - Test whether the set is a proper superset of *other*, that is, ``set >= - other and set != other``. + Test whether the set is a proper superset of *other*, that is, ``set >= + other and set != other``. - .. method:: union(*others) - set | other | ... +.. method:: frozenset.union(*others) + set.union(*others) +.. describe:: set | other | ... - Return a new set with elements from the set and all others. + Return a new set with elements from the set and all others. - .. method:: intersection(*others) - set & other & ... +.. method:: frozenset.intersection(*others) + set.intersection(*others) +.. describe:: set & other & ... - Return a new set with elements common to the set and all others. + Return a new set with elements common to the set and all others. - .. method:: difference(*others) - set - other - ... +.. method:: frozenset.difference(*others) + set.difference(*others) +.. describe:: set - other - ... - Return a new set with elements in the set that are not in the others. + Return a new set with elements in the set that are not in the others. - .. method:: symmetric_difference(other, /) - set ^ other +.. method:: frozenset.symmetric_difference(other, /) + set.symmetric_difference(other, /) +.. describe:: set ^ other - Return a new set with elements in either the set or *other* but not both. + Return a new set with elements in either the set or *other* but not both. - .. method:: copy() +.. method:: frozenset.copy() + set.copy() - Return a shallow copy of the set. + Return a shallow copy of the set. - Note, the non-operator versions of :meth:`union`, :meth:`intersection`, - :meth:`difference`, :meth:`symmetric_difference`, :meth:`issubset`, and - :meth:`issuperset` methods will accept any iterable as an argument. In - contrast, their operator based counterparts require their arguments to be - sets. This precludes error-prone constructions like ``set('abc') & 'cbs'`` - in favor of the more readable ``set('abc').intersection('cbs')``. +Note, the non-operator versions of :meth:`~frozenset.union`, +:meth:`~frozenset.intersection`, :meth:`~frozenset.difference`, :meth:`~frozenset.symmetric_difference`, :meth:`~frozenset.issubset`, and +:meth:`~frozenset.issuperset` methods will accept any iterable as an argument. In +contrast, their operator based counterparts require their arguments to be +sets. This precludes error-prone constructions like ``set('abc') & 'cbs'`` +in favor of the more readable ``set('abc').intersection('cbs')``. - Both :class:`set` and :class:`frozenset` support set to set comparisons. Two - sets are equal if and only if every element of each set is contained in the - other (each is a subset of the other). A set is less than another set if and - only if the first set is a proper subset of the second set (is a subset, but - is not equal). A set is greater than another set if and only if the first set - is a proper superset of the second set (is a superset, but is not equal). +Both :class:`set` and :class:`frozenset` support set to set comparisons. Two +sets are equal if and only if every element of each set is contained in the +other (each is a subset of the other). A set is less than another set if and +only if the first set is a proper subset of the second set (is a subset, but +is not equal). A set is greater than another set if and only if the first set +is a proper superset of the second set (is a superset, but is not equal). - Instances of :class:`set` are compared to instances of :class:`frozenset` - based on their members. For example, ``set('abc') == frozenset('abc')`` - returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``. +Instances of :class:`set` are compared to instances of :class:`frozenset` +based on their members. For example, ``set('abc') == frozenset('abc')`` +returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``. - The subset and equality comparisons do not generalize to a total ordering - function. For example, any two nonempty disjoint sets are not equal and are not - subsets of each other, so *all* of the following return ``False``: ``ab``. +The subset and equality comparisons do not generalize to a total ordering +function. For example, any two nonempty disjoint sets are not equal and are not +subsets of each other, so *all* of the following return ``False``: ``ab``. - Since sets only define partial ordering (subset relationships), the output of - the :meth:`list.sort` method is undefined for lists of sets. +Since sets only define partial ordering (subset relationships), the output of +the :meth:`list.sort` method is undefined for lists of sets. - Set elements, like dictionary keys, must be :term:`hashable`. +Set elements, like dictionary keys, must be :term:`hashable`. - Binary operations that mix :class:`set` instances with :class:`frozenset` - return the type of the first operand. For example: ``frozenset('ab') | - set('bc')`` returns an instance of :class:`frozenset`. +Binary operations that mix :class:`set` instances with :class:`frozenset` +return the type of the first operand. For example: ``frozenset('ab') | +set('bc')`` returns an instance of :class:`frozenset`. - The following table lists operations available for :class:`set` that do not - apply to immutable instances of :class:`frozenset`: +The following table lists operations available for :class:`set` that do not +apply to immutable instances of :class:`frozenset`: - .. method:: update(*others) - set |= other | ... +.. method:: set.update(*others) +.. describe:: set |= other | ... - Update the set, adding elements from all others. + Update the set, adding elements from all others. - .. method:: intersection_update(*others) - set &= other & ... +.. method:: set.intersection_update(*others) +.. describe:: set &= other & ... - Update the set, keeping only elements found in it and all others. + Update the set, keeping only elements found in it and all others. - .. method:: difference_update(*others) - set -= other | ... +.. method:: set.difference_update(*others) +.. describe:: set -= other | ... - Update the set, removing elements found in others. + Update the set, removing elements found in others. - .. method:: symmetric_difference_update(other, /) - set ^= other +.. method:: set.symmetric_difference_update(other, /) +.. describe:: set ^= other - Update the set, keeping only elements found in either set, but not in both. + Update the set, keeping only elements found in either set, but not in both. - .. method:: add(elem, /) +.. method:: set.add(elem, /) - Add element *elem* to the set. + Add element *elem* to the set. - .. method:: remove(elem, /) +.. method:: set.remove(elem, /) - Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is - not contained in the set. + Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is + not contained in the set. - .. method:: discard(elem, /) +.. method:: set.discard(elem, /) - Remove element *elem* from the set if it is present. + Remove element *elem* from the set if it is present. - .. method:: pop() +.. method:: set.pop() - Remove and return an arbitrary element from the set. Raises - :exc:`KeyError` if the set is empty. + Remove and return an arbitrary element from the set. Raises + :exc:`KeyError` if the set is empty. - .. method:: clear() +.. method:: set.clear() - Remove all elements from the set. + Remove all elements from the set. - Note, the non-operator versions of the :meth:`update`, - :meth:`intersection_update`, :meth:`difference_update`, and - :meth:`symmetric_difference_update` methods will accept any iterable as an - argument. +Note, the non-operator versions of the :meth:`~set.update`, +:meth:`~set.intersection_update`, :meth:`~set.difference_update`, and +:meth:`~set.symmetric_difference_update` methods will accept any iterable as an +argument. - Note, the *elem* argument to the :meth:`~object.__contains__`, - :meth:`remove`, and - :meth:`discard` methods may be a set. To support searching for an equivalent - frozenset, a temporary one is created from *elem*. +Note, the *elem* argument to the :meth:`~object.__contains__`, +:meth:`~set.remove`, and +:meth:`~set.discard` methods may be a set. To support searching for an equivalent +frozenset, a temporary one is created from *elem*. .. _typesmapping: @@ -4896,9 +5100,6 @@ can be used interchangeably to index the same dictionary entry. being added is already present, the value from the keyword argument replaces the value from the positional argument. - Providing keyword arguments as in the first example only works for keys that - are valid Python identifiers. Otherwise, any valid keys can be used. - Dictionaries compare equal if and only if they have the same ``(key, value)`` pairs (regardless of ordering). Order comparisons ('<', '<=', '>=', '>') raise :exc:`TypeError`. To illustrate dictionary creation and equality, @@ -4957,13 +5158,13 @@ can be used interchangeably to index the same dictionary entry. .. index:: __missing__() - If a subclass of dict defines a method :meth:`__missing__` and *key* + If a subclass of dict defines a method :meth:`~object.__missing__` and *key* is not present, the ``d[key]`` operation calls that method with the key *key* as argument. The ``d[key]`` operation then returns or raises whatever is returned or raised by the ``__missing__(key)`` call. - No other operations or methods invoke :meth:`__missing__`. If - :meth:`__missing__` is not defined, :exc:`KeyError` is raised. - :meth:`__missing__` must be a method; it cannot be an instance variable:: + No other operations or methods invoke :meth:`~object.__missing__`. If + :meth:`~object.__missing__` is not defined, :exc:`KeyError` is raised. + :meth:`~object.__missing__` must be a method; it cannot be an instance variable:: >>> class Counter(dict): ... def __missing__(self, key): @@ -4977,7 +5178,8 @@ can be used interchangeably to index the same dictionary entry. 1 The example above shows part of the implementation of - :class:`collections.Counter`. A different ``__missing__`` method is used + :class:`collections.Counter`. + A different :meth:`!__missing__` method is used by :class:`collections.defaultdict`. .. describe:: d[key] = value @@ -5283,9 +5485,11 @@ before the statement body is executed and exited when the statement ends: Returning a true value from this method will cause the :keyword:`with` statement to suppress the exception and continue execution with the statement immediately following the :keyword:`!with` statement. Otherwise the exception continues - propagating after this method has finished executing. Exceptions that occur - during execution of this method will replace any exception that occurred in the - body of the :keyword:`!with` statement. + propagating after this method has finished executing. + + If this method raises an exception while handling an earlier exception from the + :keyword:`with` block, the new exception is raised, and the original exception + is stored in its :attr:`~BaseException.__context__` attribute. The exception passed in should never be reraised explicitly - instead, this method should return a false value to indicate that the method completed @@ -5486,6 +5690,7 @@ list is non-exhaustive. * :class:`collections.abc.MutableMapping` * :class:`collections.abc.Sequence` * :class:`collections.abc.MutableSequence` +* :class:`collections.abc.ByteString` * :class:`collections.abc.MappingView` * :class:`collections.abc.KeysView` * :class:`collections.abc.ItemsView` @@ -5761,9 +5966,10 @@ Methods .. index:: pair: object; method -Methods are functions that are called using the attribute notation. There are -two flavors: :ref:`built-in methods ` (such as :meth:`append` -on lists) and :ref:`class instance method `. +Methods are functions that are called using the attribute notation. +There are two flavors: :ref:`built-in methods ` +(such as :meth:`~list.append` on lists) +and :ref:`class instance method `. Built-in methods are described with the types that support them. If you access a method (a function defined in a class namespace) through an @@ -5869,13 +6075,34 @@ It is written as ``None``. The Ellipsis Object ------------------- -This object is commonly used by slicing (see :ref:`slicings`). It supports no -special operations. There is exactly one ellipsis object, named +This object is commonly used to indicate that something is omitted. +It supports no special operations. There is exactly one ellipsis object, named :const:`Ellipsis` (a built-in name). ``type(Ellipsis)()`` produces the :const:`Ellipsis` singleton. It is written as ``Ellipsis`` or ``...``. +In typical use, ``...`` as the ``Ellipsis`` object appears in a few different +places, for instance: + +- In type annotations, such as :ref:`callable arguments ` + or :ref:`tuple elements `. + +- As the body of a function instead of a :ref:`pass statement `. + +- In third-party libraries, such as `Numpy's slicing and striding + `_. + +Python also uses three dots in ways that are not ``Ellipsis`` objects, for instance: + +- Doctest's :const:`ELLIPSIS `, as a pattern for missing content. + +- The default Python prompt of the :term:`interactive` shell when partial input is incomplete. + +Lastly, the Python documentation often uses three dots in conventional English +usage to mean omitted content, even in code examples that also use them as the +``Ellipsis``. + .. _bltin-notimplemented-object: diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 6336a0ec47b..e3ad018d1d0 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -4,7 +4,7 @@ .. module:: string :synopsis: Common string operations. -**Source code:** :source:`Lib/string.py` +**Source code:** :source:`Lib/string/__init__.py` -------------- @@ -546,6 +546,9 @@ The available presentation types for :class:`float` and | | :class:`float`, and shows all coefficient digits | | | for :class:`~decimal.Decimal`. If ``p=0``, the decimal | | | point is omitted unless the ``#`` option is used. | + | | | + | | For :class:`float`, the exponent always contains at | + | | least two digits, and is zero if the value is zero. | +---------+----------------------------------------------------------+ | ``'E'`` | Scientific notation. Same as ``'e'`` except it uses | | | an upper case 'E' as the separator character. | diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst index 85d65fa9de1..a5b2d796aaf 100644 --- a/Doc/library/string.templatelib.rst +++ b/Doc/library/string.templatelib.rst @@ -24,7 +24,7 @@ Template strings Template strings are a mechanism for custom string processing. They have the full flexibility of Python's :ref:`f-strings`, but return a :class:`Template` instance that gives access -to the static and interpolated (in curly braces) parts of a string +to the static and interpolated (in curly brackets) parts of a string *before* they are combined. To write a t-string, use a ``'t'`` prefix instead of an ``'f'``, like so: @@ -258,13 +258,16 @@ Types .. attribute:: expression :type: str - The text of a valid Python expression, or an empty string. + For interpolations created by t-string literals, :attr:`!expression` + is the expression text found inside the curly brackets (``{`` & ``}``), + including any whitespace, excluding the curly brackets themselves, + and ending before the first ``!``, ``:``, or ``=`` if any is present. + For manually created interpolations, :attr:`!expression` is the arbitrary + string provided when constructing the interpolation instance. - The :attr:`.expression` is the original text of the - interpolation's Python expression, if the interpolation was created - from a t-string literal. Developers creating interpolations manually - should either set this to an empty string or choose a suitable valid - Python expression. + We recommend using valid Python expressions or the empty string for the + ``expression`` field of manually created :class:`!Interpolation` + instances, although this is not enforced at runtime. >>> t'{1 + 2}'.interpolations[0].expression '1 + 2' diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 028a7861f36..b8dfcc31077 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -649,7 +649,7 @@ functions. If specified, *env* must provide any variables required for the program to execute. On Windows, in order to run a `side-by-side assembly`_ the - specified *env* **must** include a valid :envvar:`SystemRoot`. + specified *env* **must** include a valid ``%SystemRoot%``. .. _side-by-side assembly: https://en.wikipedia.org/wiki/Side-by-Side_Assembly @@ -831,7 +831,9 @@ Instances of the :class:`Popen` class have the following methods: If the process does not terminate after *timeout* seconds, a :exc:`TimeoutExpired` exception will be raised. Catching this exception and - retrying communication will not lose any output. + retrying communication will not lose any output. Supplying *input* to a + subsequent post-timeout :meth:`communicate` call is in undefined behavior + and may become an error in the future. The child process is not killed if the timeout expires, so in order to cleanup properly a well-behaved application should kill the child process and @@ -844,6 +846,11 @@ Instances of the :class:`Popen` class have the following methods: proc.kill() outs, errs = proc.communicate() + After a call to :meth:`~Popen.communicate` raises :exc:`TimeoutExpired`, do + not call :meth:`~Popen.wait`. Use an additional :meth:`~Popen.communicate` + call to finish handling pipes and populate the :attr:`~Popen.returncode` + attribute. + .. note:: The data read is buffered in memory, so do not use this method if the data @@ -1473,7 +1480,7 @@ handling consistency are valid for these functions. Return ``(exitcode, output)`` of executing *cmd* in a shell. - Execute the string *cmd* in a shell with :meth:`Popen.check_output` and + Execute the string *cmd* in a shell with :func:`check_output` and return a 2-tuple ``(exitcode, output)``. *encoding* and *errors* are used to decode output; see the notes on :ref:`frequently-used-arguments` for more details. diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index d120c6acf62..b6b2f28d067 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -1,7 +1,7 @@ .. _superseded: ****************** -Superseded Modules +Superseded modules ****************** The modules described in this chapter have been superseded by other modules @@ -24,3 +24,4 @@ currently no modules in this latter category. :maxdepth: 1 getopt.rst + profile.rst diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index 54e19af4bd6..f5e6f9f8acf 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -21,11 +21,17 @@ tables. Generating Symbol Tables ------------------------ -.. function:: symtable(code, filename, compile_type) +.. function:: symtable(code, filename, compile_type, *, module=None) Return the toplevel :class:`SymbolTable` for the Python source *code*. *filename* is the name of the file containing the code. *compile_type* is like the *mode* argument to :func:`compile`. + The optional argument *module* specifies the module name. + It is needed to unambiguous :ref:`filter ` syntax warnings + by module name. + + .. versionadded:: 3.15 + Added the *module* parameter. Examining Symbol Tables diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 0f986aa580b..303655fb128 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -216,14 +216,17 @@ by another event: The :monitoring-event:`C_RETURN` and :monitoring-event:`C_RAISE` events are controlled by the :monitoring-event:`CALL` event. -:monitoring-event:`C_RETURN` and :monitoring-event:`C_RAISE` events will only be seen if the -corresponding :monitoring-event:`CALL` event is being monitored. +:monitoring-event:`C_RETURN` and :monitoring-event:`C_RAISE` events will only be +seen if the corresponding :monitoring-event:`CALL` event is being monitored. + + +.. _monitoring-event-global: Other events '''''''''''' Other events are not necessarily tied to a specific location in the -program and cannot be individually disabled. +program and cannot be individually disabled via :data:`DISABLE`. The other events that can be monitored are: @@ -289,12 +292,13 @@ in Python (see :ref:`c-api-monitoring`). .. function:: get_local_events(tool_id: int, code: CodeType, /) -> int - Returns all the local events for *code* + Returns all the :ref:`local events ` for *code* .. function:: set_local_events(tool_id: int, code: CodeType, event_set: int, /) -> None - Activates all the local events for *code* which are set in *event_set*. - Raises a :exc:`ValueError` if *tool_id* is not in use. + Activates all the :ref:`local events ` for *code* + which are set in *event_set*. Raises a :exc:`ValueError` if *tool_id* is not + in use. Disabling events @@ -305,15 +309,21 @@ Disabling events A special value that can be returned from a callback function to disable events for the current code location. -Local events can be disabled for a specific code location by returning -:data:`sys.monitoring.DISABLE` from a callback function. This does not change -which events are set, or any other code locations for the same event. +:ref:`Local events ` can be disabled for a specific code +location by returning :data:`sys.monitoring.DISABLE` from a callback function. +This does not change which events are set, or any other code locations for the +same event. Disabling events for specific locations is very important for high performance monitoring. For example, a program can be run under a debugger with no overhead if the debugger disables all monitoring except for a few breakpoints. +If :data:`DISABLE` is returned by a callback for a +:ref:`global event `, :exc:`ValueError` will be raised +by the interpreter in a non-specific location (that is, no traceback will be +provided). + .. function:: restart_events() -> None Enable all the events that were disabled by :data:`sys.monitoring.DISABLE` diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 30fd4db1fd1..a0621d4b0db 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -11,6 +11,51 @@ interpreter and to functions that interact strongly with the interpreter. It is always available. Unless explicitly noted otherwise, all variables are read-only. +.. data:: abi_info + + .. versionadded:: 3.15 + + An object containing information about the ABI of the currently running + Python interpreter. + It should include information that affect the CPython ABI in ways that + require a specific build of the interpreter chosen from variants that can + co-exist on a single machine. + For example, it does not encode the base OS (Linux or Windows), but does + include pointer size since some systems support both 32- and 64-bit builds. + The available entries are the same on all platforms; + e.g. *pointer_size* is available even on 64-bit-only architectures. + + The following attributes are available: + + .. attribute:: abi_info.pointer_bits + + The width of pointers in bits, as an integer, + equivalent to ``8 * sizeof(void *)``. + Usually, this is ``32`` or ``64``. + + .. attribute:: abi_info.free_threaded + + A Boolean indicating whether the interpreter was built with + :term:`free threading` support. + This reflects either the presence of the :option:`--disable-gil` + :file:`configure` option (on Unix) + or setting the ``DisableGil`` property (on Windows). + + .. attribute:: abi_info.debug + + A Boolean indicating whether the interpreter was built in + :ref:`debug mode `. + This reflects either the presence of the :option:`--with-pydebug` + :file:`configure` option (on Unix) + or the ``Debug`` configuration (on Windows). + + .. attribute:: abi_info.byteorder + + A string indicating the native byte order, + either ``'big'`` or ``'little'``. + This is the same as the :data:`byteorder` attribute. + + .. data:: abiflags On POSIX systems where Python was built with the standard ``configure`` @@ -523,8 +568,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only Since :func:`exit` ultimately "only" raises an exception, it will only exit the process when called from the main thread, and the exception is not - intercepted. Cleanup actions specified by finally clauses of :keyword:`try` statements - are honored, and it is possible to intercept the exit attempt at an outer level. + intercepted. Cleanup actions specified by :keyword:`finally` clauses of + :keyword:`try` statements are honored, and it is possible to intercept the + exit attempt at an outer level. .. versionchanged:: 3.6 If an error occurs in the cleanup after the Python interpreter @@ -1130,10 +1176,14 @@ always available. Unless explicitly noted otherwise, all variables are read-only The size of the seed key of the hash algorithm + .. attribute:: hash_info.cutoff + + Cutoff for small string DJBX33A optimization in range ``[1, cutoff)``. + .. versionadded:: 3.2 .. versionchanged:: 3.4 - Added *algorithm*, *hash_bits* and *seed_bits* + Added *algorithm*, *hash_bits*, *seed_bits*, and *cutoff*. .. data:: hexversion @@ -2159,7 +2209,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only :func:`sys.unraisablehook` can be overridden to control how unraisable exceptions are handled. - .. versionchanged:: next + .. versionchanged:: 3.15 Exceptions are now printed with colorful text. .. seealso:: diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index 684d14a74c4..3b0bfb85da7 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -382,22 +382,22 @@ Other functions Examples of returned values: - - linux-i586 - - linux-alpha (?) + - linux-x86_64 + - linux-aarch64 - solaris-2.6-sun4u - Windows will return one of: + Windows: - win-amd64 (64-bit Windows on AMD64, aka x86_64, Intel64, and EM64T) - win-arm64 (64-bit Windows on ARM64, aka AArch64) - win32 (all others - specifically, sys.platform is returned) - macOS can return: + POSIX based OS: - - macosx-10.6-ppc - - macosx-10.4-ppc64 - - macosx-10.3-i386 - - macosx-10.4-fat + - linux-x86_64 + - macosx-15.5-arm64 + - macosx-26.0-universal2 (macOS on Apple Silicon or Intel) + - android-24-arm64_v8a For other non-POSIX platforms, currently just returns :data:`sys.platform`. diff --git a/Doc/library/tachyon-flamegraph.png b/Doc/library/tachyon-flamegraph.png new file mode 100644 index 00000000000..a17cd304f8b Binary files /dev/null and b/Doc/library/tachyon-flamegraph.png differ diff --git a/Doc/library/tachyon-gecko-calltree.png b/Doc/library/tachyon-gecko-calltree.png new file mode 100644 index 00000000000..71b096940e8 Binary files /dev/null and b/Doc/library/tachyon-gecko-calltree.png differ diff --git a/Doc/library/tachyon-gecko-flamegraph.png b/Doc/library/tachyon-gecko-flamegraph.png new file mode 100644 index 00000000000..d427ed85ac0 Binary files /dev/null and b/Doc/library/tachyon-gecko-flamegraph.png differ diff --git a/Doc/library/tachyon-gecko-opcodes.png b/Doc/library/tachyon-gecko-opcodes.png new file mode 100644 index 00000000000..9741eb65912 Binary files /dev/null and b/Doc/library/tachyon-gecko-opcodes.png differ diff --git a/Doc/library/tachyon-heatmap-with-opcodes.png b/Doc/library/tachyon-heatmap-with-opcodes.png new file mode 100644 index 00000000000..5ad67d13154 Binary files /dev/null and b/Doc/library/tachyon-heatmap-with-opcodes.png differ diff --git a/Doc/library/tachyon-heatmap.png b/Doc/library/tachyon-heatmap.png new file mode 100644 index 00000000000..47ac1119f4e Binary files /dev/null and b/Doc/library/tachyon-heatmap.png differ diff --git a/Doc/library/tachyon-live-mode-1.gif b/Doc/library/tachyon-live-mode-1.gif new file mode 100644 index 00000000000..2d58e807d6a Binary files /dev/null and b/Doc/library/tachyon-live-mode-1.gif differ diff --git a/Doc/library/tachyon-live-mode-2.gif b/Doc/library/tachyon-live-mode-2.gif new file mode 100644 index 00000000000..bbc2163fe60 Binary files /dev/null and b/Doc/library/tachyon-live-mode-2.gif differ diff --git a/Doc/library/tachyon-logo.png b/Doc/library/tachyon-logo.png new file mode 100644 index 00000000000..bf0901ec9f3 Binary files /dev/null and b/Doc/library/tachyon-logo.png differ diff --git a/Doc/library/tachyon-pstats.png b/Doc/library/tachyon-pstats.png new file mode 100644 index 00000000000..d0281ade660 Binary files /dev/null and b/Doc/library/tachyon-pstats.png differ diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index acaec5b592b..5ff8502bbe2 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -21,6 +21,14 @@ Some facts and figures: * reads and writes :mod:`gzip`, :mod:`bz2`, :mod:`compression.zstd`, and :mod:`lzma` compressed archives if the respective modules are available. + .. + The following paragraph should be similar to ../includes/optional-module.rst + + If any of these :term:`optional modules ` are missing from + your copy of CPython, look for documentation from your distributor (that is, + whoever provided Python to you). + If you are the distributor, see :ref:`optional-module-requirements`. + * read/write support for the POSIX.1-1988 (ustar) format. * read/write support for the GNU tar format including *longname* and *longlink* @@ -198,7 +206,7 @@ Some facts and figures: .. versionchanged:: 3.14 The *preset* keyword argument also works for streams. - .. versionchanged:: next + .. versionchanged:: 3.15 The default compression level was reduced to 6 (down from 9). It is the default level used by most compression tools and a better tradeoff between speed and performance. @@ -294,7 +302,7 @@ The :mod:`tarfile` module defines the following exceptions: The exception that was raised to reject the replacement member is available as :attr:`!BaseException.__context__`. - .. versionadded:: next + .. versionadded:: 3.15 The following constants are available at the module level: @@ -1146,7 +1154,7 @@ reused in custom filters: Note that this filter does not block *all* dangerous archive features. See :ref:`tarfile-further-verification` for details. - .. versionchanged:: next + .. versionchanged:: 3.15 Link targets are now normalized. diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 9fdb21b8bad..395cde21ccf 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -851,7 +851,7 @@ The :mod:`test.support` module defines the following functions: Decorator for tests that fill the address space. -.. function:: linked_with_musl() +.. function:: linked_to_musl() Return ``False`` if there is no evidence the interpreter was compiled with ``musl``, otherwise return a version triple, either ``(0, 0, 0)`` if the diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index 9a0aeb7c128..19cc4f191df 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -198,7 +198,7 @@ This module defines the following functions: .. versionchanged:: 3.13 Added support for GNU/kFreeBSD. - .. versionchanged:: next + .. versionchanged:: 3.15 Added support for Solaris. @@ -608,7 +608,7 @@ since it is impossible to detect the termination of alien threads. timeout occurs. When the *timeout* argument is present and not ``None``, it should be a - floating-point number specifying a timeout for the operation in seconds + real number specifying a timeout for the operation in seconds (or fractions thereof). As :meth:`~Thread.join` always returns ``None``, you must call :meth:`~Thread.is_alive` after :meth:`~Thread.join` to decide whether a timeout happened -- if the thread is still alive, the @@ -632,6 +632,9 @@ since it is impossible to detect the termination of alien threads. May raise :exc:`PythonFinalizationError`. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. attribute:: name A string used for identification purposes only. It has no semantics. @@ -764,7 +767,7 @@ All methods are executed atomically. If a call with *blocking* set to ``True`` would block, return ``False`` immediately; otherwise, set the lock to locked and return ``True``. - When invoked with the floating-point *timeout* argument set to a positive + When invoked with the *timeout* argument set to a positive value, block for at most the number of seconds specified by *timeout* and as long as the lock cannot be acquired. A *timeout* argument of ``-1`` specifies an unbounded wait. It is forbidden to specify a *timeout* @@ -783,6 +786,9 @@ All methods are executed atomically. .. versionchanged:: 3.14 Lock acquisition can now be interrupted by signals on Windows. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. method:: release() @@ -863,7 +869,7 @@ call release as many times the lock has been acquired can lead to deadlock. * If no thread owns the lock, acquire the lock and return immediately. * If another thread owns the lock, block until we are able to acquire - lock, or *timeout*, if set to a positive float value. + lock, or *timeout*, if set to a positive value. * If the same thread owns the lock, acquire the lock again, and return immediately. This is the difference between :class:`Lock` and @@ -890,6 +896,9 @@ call release as many times the lock has been acquired can lead to deadlock. .. versionchanged:: 3.2 The *timeout* parameter is new. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. method:: release() @@ -1023,7 +1032,7 @@ item to the buffer only needs to wake up one consumer thread. occurs. Once awakened or timed out, it re-acquires the lock and returns. When the *timeout* argument is present and not ``None``, it should be a - floating-point number specifying a timeout for the operation in seconds + real number specifying a timeout for the operation in seconds (or fractions thereof). When the underlying lock is an :class:`RLock`, it is not released using @@ -1150,6 +1159,9 @@ Semaphores also support the :ref:`context management protocol `. .. versionchanged:: 3.2 The *timeout* parameter is new. + .. versionchanged:: 3.15 + Accepts any real number as *timeout*, not only integer or float. + .. method:: release(n=1) Release a semaphore, incrementing the internal counter by *n*. When it @@ -1250,7 +1262,7 @@ method. The :meth:`~Event.wait` method blocks until the flag is true. the internal flag did not become true within the given wait time. When the timeout argument is present and not ``None``, it should be a - floating-point number specifying a timeout for the operation in seconds, + real number specifying a timeout for the operation in seconds, or fractions thereof. .. versionchanged:: 3.1 diff --git a/Doc/library/time.rst b/Doc/library/time.rst index b05c0a312db..a931134331f 100644 --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -189,7 +189,7 @@ Functions .. versionadded:: 3.7 -.. function:: clock_settime(clk_id, time: float) +.. function:: clock_settime(clk_id, time) Set the time of the specified clock *clk_id*. Currently, :data:`CLOCK_REALTIME` is the only accepted value for *clk_id*. @@ -201,6 +201,9 @@ Functions .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Accepts any real number as *time*, not only integer or float. + .. function:: clock_settime_ns(clk_id, time: int) @@ -223,6 +226,9 @@ Functions ``asctime(localtime(secs))``. Locale information is not used by :func:`ctime`. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. + .. function:: get_clock_info(name) @@ -238,8 +244,8 @@ Functions The result has the following attributes: - - *adjustable*: ``True`` if the clock can be changed automatically (e.g. by - a NTP daemon) or manually by the system administrator, ``False`` otherwise + - *adjustable*: ``True`` if the clock can be set to jump forward or backward + in time, ``False`` otherwise. Does not refer to gradual NTP rate adjustments. - *implementation*: The name of the underlying C function used to get the clock value. Refer to :ref:`time-clock-id-constants` for possible values. - *monotonic*: ``True`` if the clock cannot go backward, @@ -258,6 +264,9 @@ Functions :class:`struct_time` object. See :func:`calendar.timegm` for the inverse of this function. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. + .. function:: localtime([secs]) @@ -271,6 +280,9 @@ Functions :c:func:`gmtime` failure. It's common for this to be restricted to years between 1970 and 2038. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. + .. function:: mktime(t) @@ -382,8 +394,7 @@ Functions .. function:: sleep(secs) Suspend execution of the calling thread for the given number of seconds. - The argument may be a floating-point number to indicate a more precise sleep - time. + The argument may be a non-integer to indicate a more precise sleep time. If the sleep is interrupted by a signal and no exception is raised by the signal handler, the sleep is restarted with a recomputed timeout. @@ -396,9 +407,9 @@ Functions On Windows, if *secs* is zero, the thread relinquishes the remainder of its time slice to any other thread that is ready to run. If there are no other threads ready to run, the function returns immediately, and the thread - continues execution. On Windows 8.1 and newer the implementation uses + continues execution. On Windows 10 and newer the implementation uses a `high-resolution timer - `_ + `_ which provides resolution of 100 nanoseconds. If *secs* is zero, ``Sleep(0)`` is used. .. rubric:: Unix implementation @@ -428,6 +439,9 @@ Functions .. versionchanged:: 3.13 Raises an auditing event. + .. versionchanged:: 3.15 + Accepts any real number, not only integer or float. + .. index:: single: % (percent); datetime format @@ -570,7 +584,7 @@ Functions calculations when the day of the week and the year are specified. Here is an example, a format for dates compatible with that specified in the - :rfc:`2822` Internet email standard. [1]_ :: + :rfc:`5322` Internet email standard. [1]_ :: >>> from time import gmtime, strftime >>> strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) @@ -1052,4 +1066,5 @@ Timezone Constants strict reading of the original 1982 :rfc:`822` standard calls for a two-digit year (``%y`` rather than ``%Y``), but practice moved to 4-digit years long before the year 2000. After that, :rfc:`822` became obsolete and the 4-digit year has - been first recommended by :rfc:`1123` and then mandated by :rfc:`2822`. + been first recommended by :rfc:`1123` and then mandated by :rfc:`2822`, + with :rfc:`5322` continuing this requirement. diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index f284988daf2..81177533be8 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -36,6 +36,8 @@ details that are unchanged. Most documentation you will find online still uses the old API and can be woefully outdated. +.. include:: ../includes/optional-module.rst + .. seealso:: * `TkDocs `_ @@ -392,7 +394,7 @@ by spaces. Without getting into too many details, notice the following: * Operations which are implemented as separate *commands* in Tcl (like ``grid`` or ``destroy``) are represented as *methods* on Tkinter widget objects. As you'll see shortly, at other times Tcl uses what appear to be - method calls on widget objects, which more closely mirror what would is + method calls on widget objects, which more closely mirror what is used in Tkinter. @@ -839,8 +841,7 @@ geometry For example: ``fred["geometry"] = "200x100"``. justify - Legal values are the strings: ``"left"``, ``"center"``, ``"right"``, and - ``"fill"``. + Legal values are the strings: ``"left"``, ``"center"``, and ``"right"``. region This is a string with four space-delimited elements, each of which is a legal diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index fea6b57edf0..95a57c57e71 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -29,6 +29,8 @@ introduced in Logo `_, developed by Wally Feurzeig, Seymour Papert and Cynthia Solomon in 1967. +.. include:: ../includes/optional-module.rst + Get started =========== @@ -777,13 +779,17 @@ Turtle motion 180.0 -.. function:: dot(size=None, *color) +.. function:: dot() + dot(size) + dot(color, /) + dot(size, color, /) + dot(size, r, g, b, /) :param size: an integer >= 1 (if given) :param color: a colorstring or a numeric color tuple Draw a circular dot with diameter *size*, using *color*. If *size* is - not given, the maximum of pensize+4 and 2*pensize is used. + not given, the maximum of ``pensize+4`` and ``2*pensize`` is used. .. doctest:: @@ -1152,7 +1158,9 @@ Drawing state Color control ~~~~~~~~~~~~~ -.. function:: pencolor(*args) +.. function:: pencolor() + pencolor(color, /) + pencolor(r, g, b, /) Return or set the pencolor. @@ -1161,7 +1169,7 @@ Color control ``pencolor()`` Return the current pencolor as color specification string or as a tuple (see example). May be used as input to another - color/pencolor/fillcolor call. + color/pencolor/fillcolor/bgcolor call. ``pencolor(colorstring)`` Set pencolor to *colorstring*, which is a Tk color specification string, @@ -1201,7 +1209,9 @@ Color control (50.0, 193.0, 143.0) -.. function:: fillcolor(*args) +.. function:: fillcolor() + fillcolor(color, /) + fillcolor(r, g, b, /) Return or set the fillcolor. @@ -1210,7 +1220,7 @@ Color control ``fillcolor()`` Return the current fillcolor as color specification string, possibly in tuple format (see example). May be used as input to another - color/pencolor/fillcolor call. + color/pencolor/fillcolor/bgcolor call. ``fillcolor(colorstring)`` Set fillcolor to *colorstring*, which is a Tk color specification string, @@ -1244,7 +1254,10 @@ Color control (255.0, 255.0, 255.0) -.. function:: color(*args) +.. function:: color() + color(color, /) + color(r, g, b, /) + color(pencolor, fillcolor, /) Return or set pencolor and fillcolor. @@ -1870,13 +1883,32 @@ Most of the examples in this section refer to a TurtleScreen instance called Window control -------------- -.. function:: bgcolor(*args) +.. function:: bgcolor() + bgcolor(color, /) + bgcolor(r, g, b, /) - :param args: a color string or three numbers in the range 0..colormode or a - 3-tuple of such numbers + Return or set the background color of the TurtleScreen. + Four input formats are allowed: - Set or return background color of the TurtleScreen. + ``bgcolor()`` + Return the current background color as color specification string or + as a tuple (see example). May be used as input to another + color/pencolor/fillcolor/bgcolor call. + + ``bgcolor(colorstring)`` + Set the background color to *colorstring*, which is a Tk color + specification string, such as ``"red"``, ``"yellow"``, or ``"#33cc8c"``. + + ``bgcolor((r, g, b))`` + Set the background color to the RGB color represented by the tuple of + *r*, *g*, and *b*. + Each of *r*, *g*, and *b* must be in the range 0..colormode, where + colormode is either 1.0 or 255 (see :func:`colormode`). + + ``bgcolor(r, g, b)`` + Set the background color to the RGB color represented by *r*, *g*, and *b*. Each of + *r*, *g*, and *b* must be in the range 0..colormode. .. doctest:: :skipif: _tkinter is None @@ -2769,68 +2801,68 @@ The demo scripts are: .. tabularcolumns:: |l|L|L| -+----------------+------------------------------+-----------------------+ -| Name | Description | Features | -+================+==============================+=======================+ -| bytedesign | complex classical | :func:`tracer`, delay,| -| | turtle graphics pattern | :func:`update` | -+----------------+------------------------------+-----------------------+ -| chaos | graphs Verhulst dynamics, | world coordinates | -| | shows that computer's | | -| | computations can generate | | -| | results sometimes against the| | -| | common sense expectations | | -+----------------+------------------------------+-----------------------+ -| clock | analog clock showing time | turtles as clock's | -| | of your computer | hands, ontimer | -+----------------+------------------------------+-----------------------+ -| colormixer | experiment with r, g, b | :func:`ondrag` | -+----------------+------------------------------+-----------------------+ -| forest | 3 breadth-first trees | randomization | -+----------------+------------------------------+-----------------------+ -| fractalcurves | Hilbert & Koch curves | recursion | -+----------------+------------------------------+-----------------------+ -| lindenmayer | ethnomathematics | L-System | -| | (indian kolams) | | -+----------------+------------------------------+-----------------------+ -| minimal_hanoi | Towers of Hanoi | Rectangular Turtles | -| | | as Hanoi discs | -| | | (shape, shapesize) | -+----------------+------------------------------+-----------------------+ -| nim | play the classical nim game | turtles as nimsticks, | -| | with three heaps of sticks | event driven (mouse, | -| | against the computer. | keyboard) | -+----------------+------------------------------+-----------------------+ -| paint | super minimalistic | :func:`onclick` | -| | drawing program | | -+----------------+------------------------------+-----------------------+ -| peace | elementary | turtle: appearance | -| | | and animation | -+----------------+------------------------------+-----------------------+ -| penrose | aperiodic tiling with | :func:`stamp` | -| | kites and darts | | -+----------------+------------------------------+-----------------------+ -| planet_and_moon| simulation of | compound shapes, | -| | gravitational system | :class:`Vec2D` | -+----------------+------------------------------+-----------------------+ -| rosette | a pattern from the wikipedia | :func:`clone`, | -| | article on turtle graphics | :func:`undo` | -+----------------+------------------------------+-----------------------+ -| round_dance | dancing turtles rotating | compound shapes, clone| -| | pairwise in opposite | shapesize, tilt, | -| | direction | get_shapepoly, update | -+----------------+------------------------------+-----------------------+ -| sorting_animate| visual demonstration of | simple alignment, | -| | different sorting methods | randomization | -+----------------+------------------------------+-----------------------+ -| tree | a (graphical) breadth | :func:`clone` | -| | first tree (using generators)| | -+----------------+------------------------------+-----------------------+ -| two_canvases | simple design | turtles on two | -| | | canvases | -+----------------+------------------------------+-----------------------+ -| yinyang | another elementary example | :func:`circle` | -+----------------+------------------------------+-----------------------+ ++------------------------+------------------------------+--------------------------------------+ +| Name | Description | Features | ++========================+==============================+======================================+ +| ``bytedesign`` | complex classical | :func:`tracer`, :func:`delay`, | +| | turtle graphics pattern | :func:`update` | ++------------------------+------------------------------+--------------------------------------+ +| ``chaos`` | graphs Verhulst dynamics, | world coordinates | +| | shows that computer's | | +| | computations can generate | | +| | results sometimes against the| | +| | common sense expectations | | ++------------------------+------------------------------+--------------------------------------+ +| ``clock`` | analog clock showing time | turtles as clock's | +| | of your computer | hands, :func:`ontimer` | ++------------------------+------------------------------+--------------------------------------+ +| ``colormixer`` | experiment with r, g, b | :func:`ondrag` | ++------------------------+------------------------------+--------------------------------------+ +| ``forest`` | 3 breadth-first trees | randomization | ++------------------------+------------------------------+--------------------------------------+ +| ``fractalcurves`` | Hilbert & Koch curves | recursion | ++------------------------+------------------------------+--------------------------------------+ +| ``lindenmayer`` | ethnomathematics | L-System | +| | (indian kolams) | | ++------------------------+------------------------------+--------------------------------------+ +| ``minimal_hanoi`` | Towers of Hanoi | Rectangular Turtles | +| | | as Hanoi discs | +| | | (:func:`shape`, :func:`shapesize`) | ++------------------------+------------------------------+--------------------------------------+ +| ``nim`` | play the classical nim game | turtles as nimsticks, | +| | with three heaps of sticks | event driven (mouse, | +| | against the computer. | keyboard) | ++------------------------+------------------------------+--------------------------------------+ +| ``paint`` | super minimalistic | :func:`onclick` | +| | drawing program | | ++------------------------+------------------------------+--------------------------------------+ +| ``peace`` | elementary | turtle: appearance | +| | | and animation | ++------------------------+------------------------------+--------------------------------------+ +| ``penrose`` | aperiodic tiling with | :func:`stamp` | +| | kites and darts | | ++------------------------+------------------------------+--------------------------------------+ +| ``planet_and_moon`` | simulation of | compound shapes, | +| | gravitational system | :class:`Vec2D` | ++------------------------+------------------------------+--------------------------------------+ +| ``rosette`` | a pattern from the wikipedia | :func:`clone`, | +| | article on turtle graphics | :func:`undo` | ++------------------------+------------------------------+--------------------------------------+ +| ``round_dance`` | dancing turtles rotating | compound shapes, :func:`clone` | +| | pairwise in opposite | :func:`shapesize`, :func:`tilt`, | +| | direction | :func:`get_shapepoly`, :func:`update`| ++------------------------+------------------------------+--------------------------------------+ +| ``sorting_animate`` | visual demonstration of | simple alignment, | +| | different sorting methods | randomization | ++------------------------+------------------------------+--------------------------------------+ +| ``tree`` | a (graphical) breadth | :func:`clone` | +| | first tree (using generators)| | ++------------------------+------------------------------+--------------------------------------+ +| ``two_canvases`` | simple design | turtles on two | +| | | canvases | ++------------------------+------------------------------+--------------------------------------+ +| ``yinyang`` | another elementary example | :func:`circle` | ++------------------------+------------------------------+--------------------------------------+ Have fun! diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 207024a7619..40b5f3db13d 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -338,7 +338,7 @@ Standard names are defined for the following types: The type of frame locals proxy objects, as found on the :attr:`frame.f_locals` attribute. - .. versionadded:: next + .. versionadded:: 3.15 .. seealso:: :pep:`667` diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 9dbac8ce75d..4e9946fd456 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -230,9 +230,11 @@ For example: callback: Callable[[str], Awaitable[None]] = on_update +.. index:: single: ...; ellipsis literal + The subscription syntax must always be used with exactly two values: the argument list and the return type. The argument list must be a list of types, -a :class:`ParamSpec`, :data:`Concatenate`, or an ellipsis. The return type must +a :class:`ParamSpec`, :data:`Concatenate`, or an ellipsis (``...``). The return type must be a single type. If a literal ellipsis ``...`` is given as the argument list, it indicates that @@ -375,8 +377,11 @@ accepts *any number* of type arguments:: # but ``z`` has been assigned to a tuple of length 3 z: tuple[int] = (1, 2, 3) +.. index:: single: ...; ellipsis literal + To denote a tuple which could be of *any* length, and in which all elements are -of the same type ``T``, use ``tuple[T, ...]``. To denote an empty tuple, use +of the same type ``T``, use the literal ellipsis ``...``: ``tuple[T, ...]``. +To denote an empty tuple, use ``tuple[()]``. Using plain ``tuple`` as an annotation is equivalent to using ``tuple[Any, ...]``:: @@ -1162,6 +1167,8 @@ These can be used as types in annotations. They all support subscription using Special form for annotating higher-order functions. + .. index:: single: ...; ellipsis literal + ``Concatenate`` can be used in conjunction with :ref:`Callable ` and :class:`ParamSpec` to annotate a higher-order callable which adds, removes, or transforms parameters of another @@ -1383,7 +1390,7 @@ These can be used as types in annotations. They all support subscription using Using ``Annotated[T, x]`` as an annotation still allows for static typechecking of ``T``, as type checkers will simply ignore the metadata ``x``. In this way, ``Annotated`` differs from the - :func:`@no_type_check ` decorator, which can also be used for + :deco:`no_type_check` decorator, which can also be used for adding annotations outside the scope of the typing system, but completely disables typechecking for a function or class. @@ -2236,7 +2243,7 @@ without the dedicated syntax, as documented below. .. versionadded:: 3.10 -.. class:: TypeAliasType(name, value, *, type_params=()) +.. class:: TypeAliasType(name, value, *, type_params=(), qualname=None) The type of type aliases created through the :keyword:`type` statement. @@ -2260,9 +2267,23 @@ without the dedicated syntax, as documented below. >>> Alias.__name__ 'Alias' + .. attribute:: __qualname__ + + The :term:`qualified name` of the type alias: + + .. doctest:: + + >>> class Class: + ... type Alias = int + ... + >>> Class.Alias.__qualname__ + 'Class.Alias' + + .. versionadded:: 3.15 + .. attribute:: __module__ - The module in which the type alias was defined:: + The name of the module in which the type alias was defined:: >>> type Alias = int >>> Alias.__module__ @@ -2428,19 +2449,6 @@ types. Using :func:`super` (and the ``__class__`` :term:`closure variable`) in methods of ``NamedTuple`` subclasses is unsupported and causes a :class:`TypeError`. - .. deprecated-removed:: 3.13 3.15 - The undocumented keyword argument syntax for creating NamedTuple classes - (``NT = NamedTuple("NT", x=int)``) is deprecated, and will be disallowed - in 3.15. Use the class-based syntax or the functional syntax instead. - - .. deprecated-removed:: 3.13 3.15 - When using the functional syntax to create a NamedTuple class, failing to - pass a value to the 'fields' parameter (``NT = NamedTuple("NT")``) is - deprecated. Passing ``None`` to the 'fields' parameter - (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be - disallowed in Python 3.15. To create a NamedTuple class with 0 fields, - use ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``. - .. class:: NewType(name, tp) Helper class to create low-overhead :ref:`distinct types `. @@ -2455,7 +2463,7 @@ types. .. attribute:: __module__ - The module in which the new type is defined. + The name of the module in which the new type is defined. .. attribute:: __name__ @@ -2816,19 +2824,12 @@ types. .. versionchanged:: 3.13 Support for the :data:`ReadOnly` qualifier was added. - .. deprecated-removed:: 3.13 3.15 - When using the functional syntax to create a TypedDict class, failing to - pass a value to the 'fields' parameter (``TD = TypedDict("TD")``) is - deprecated. Passing ``None`` to the 'fields' parameter - (``TD = TypedDict("TD", None)``) is also deprecated. Both will be - disallowed in Python 3.15. To create a TypedDict class with 0 fields, - use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. Protocols --------- The following protocols are provided by the :mod:`!typing` module. All are decorated -with :func:`@runtime_checkable `. +with :deco:`runtime_checkable`. .. class:: SupportsAbs @@ -2868,8 +2869,8 @@ ABCs and Protocols for working with I/O --------------------------------------- .. class:: IO[AnyStr] - TextIO[AnyStr] - BinaryIO[AnyStr] + TextIO + BinaryIO Generic class ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` and ``BinaryIO(IO[bytes])`` @@ -3009,7 +3010,7 @@ Functions and decorators The presence of ``@dataclass_transform()`` tells a static type checker that the decorated object performs runtime "magic" that transforms a class in a similar way to - :func:`@dataclasses.dataclass `. + :deco:`dataclasses.dataclass`. Example usage with a decorator function: @@ -3047,14 +3048,14 @@ Functions and decorators The ``CustomerModel`` classes defined above will be treated by type checkers similarly to classes created with - :func:`@dataclasses.dataclass `. + :deco:`dataclasses.dataclass`. For example, type checkers will assume these classes have ``__init__`` methods that accept ``id`` and ``name``. The decorated class, metaclass, or function may accept the following bool arguments which type checkers will assume have the same effect as they would have on the - :func:`@dataclasses.dataclass` decorator: ``init``, + :deco:`dataclasses.dataclass` decorator: ``init``, ``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``, ``kw_only``, and ``slots``. It must be possible for the value of these arguments (``True`` or ``False``) to be statically evaluated. @@ -3182,12 +3183,12 @@ Functions and decorators .. function:: get_overloads(func) - Return a sequence of :func:`@overload `-decorated definitions for + Return a sequence of :deco:`overload`-decorated definitions for *func*. *func* is the function object for the implementation of the overloaded function. For example, given the definition of ``process`` in - the documentation for :func:`@overload `, + the documentation for :deco:`overload`, ``get_overloads(process)`` will return a sequence of three function objects for the three defined overloads. If called on a function with no overloads, ``get_overloads()`` returns an empty sequence. @@ -3257,17 +3258,6 @@ Functions and decorators ``@no_type_check`` mutates the decorated object in place. -.. decorator:: no_type_check_decorator - - Decorator to give another decorator the :func:`no_type_check` effect. - - This wraps the decorator with something that wraps the decorated - function in :func:`no_type_check`. - - .. deprecated-removed:: 3.13 3.15 - No type checker ever added support for ``@no_type_check_decorator``. It - is therefore deprecated, and will be removed in Python 3.15. - .. decorator:: override Decorator to indicate that a method in a subclass is intended to override a @@ -3344,7 +3334,7 @@ Introspection helpers If *globalns* or *localns* is not given, appropriate namespace dictionaries are inferred from *obj*. * ``None`` is replaced with :class:`types.NoneType`. - * If :func:`@no_type_check ` has been applied to *obj*, an + * If :deco:`no_type_check` has been applied to *obj*, an empty dictionary is returned. * If *obj* is a class ``C``, the function returns a dictionary that merges annotations from ``C``'s base classes with those on ``C`` directly. This @@ -3353,13 +3343,19 @@ Introspection helpers ``__annotations__`` dictionaries. Annotations on classes appearing earlier in the :term:`method resolution order` always take precedence over annotations on classes appearing later in the method resolution order. - * The function recursively replaces all occurrences of ``Annotated[T, ...]`` + * The function recursively replaces all occurrences of + ``Annotated[T, ...]``, ``Required[T]``, ``NotRequired[T]``, and ``ReadOnly[T]`` with ``T``, unless *include_extras* is set to ``True`` (see :class:`Annotated` for more information). See also :func:`annotationlib.get_annotations`, a lower-level function that returns annotations more directly. + .. caution:: + + This function may execute arbitrary code contained in annotations. + See :ref:`annotationlib-security` for more information. + .. note:: If any forward references in the annotations of *obj* are not resolvable @@ -3506,6 +3502,11 @@ Introspection helpers See the documentation for :meth:`annotationlib.ForwardRef.evaluate` for the meaning of the *owner*, *globals*, *locals*, *type_params*, and *format* parameters. + .. caution:: + + This function may execute arbitrary code contained in annotations. + See :ref:`annotationlib-security` for more information. + .. versionadded:: 3.14 .. data:: NoDefault @@ -3771,6 +3772,28 @@ Aliases to container ABCs in :mod:`collections.abc` :class:`collections.abc.Set` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. class:: ByteString(Sequence[int]) + + Deprecated alias to :class:`collections.abc.ByteString`. + + Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj`` + implements the :ref:`buffer protocol ` at runtime. For use in + type annotations, either use :class:`~collections.abc.Buffer` or a union + that explicitly specifies the types your code supports (e.g., + ``bytes | bytearray | memoryview``). + + :class:`!ByteString` was originally intended to be an abstract class that + would serve as a supertype of both :class:`bytes` and :class:`bytearray`. + However, since the ABC never had any methods, knowing that an object was an + instance of :class:`!ByteString` never actually told you anything useful + about the object. Other common buffer types such as :class:`memoryview` were + also never understood as subtypes of :class:`!ByteString` (either at runtime + or by static type checkers). + + See :pep:`PEP 688 <688#current-options>` for more details. + + .. deprecated-removed:: 3.9 3.17 + .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) Deprecated alias to :class:`collections.abc.Collection`. @@ -4064,6 +4087,10 @@ convenience. This is subject to change, and not all deprecations are listed. - 3.9 - Undecided (see :ref:`deprecated-aliases` for more information) - :pep:`585` + * - :class:`typing.ByteString` + - 3.9 + - 3.17 + - :gh:`91896` * - :data:`typing.Text` - 3.11 - Undecided @@ -4076,10 +4103,6 @@ convenience. This is subject to change, and not all deprecations are listed. - 3.12 - Undecided - :pep:`695` - * - :func:`@typing.no_type_check_decorator ` - - 3.13 - - 3.15 - - :gh:`106309` * - :data:`typing.AnyStr` - 3.13 - 3.18 diff --git a/Doc/library/unicodedata.rst b/Doc/library/unicodedata.rst index 0aef597d064..34f21f49b4b 100644 --- a/Doc/library/unicodedata.rst +++ b/Doc/library/unicodedata.rst @@ -17,91 +17,174 @@ This module provides access to the Unicode Character Database (UCD) which defines character properties for all Unicode characters. The data contained in -this database is compiled from the `UCD version 16.0.0 -`_. +this database is compiled from the `UCD version 17.0.0 +`_. The module uses the same names and symbols as defined by Unicode Standard Annex #44, `"Unicode Character Database" `_. It defines the following functions: +.. seealso:: -.. function:: lookup(name) + The :ref:`unicode-howto` for more information about Unicode and how to use + this module. + + +.. function:: lookup(name, /) Look up character by name. If a character with the given name is found, return the corresponding character. If not found, :exc:`KeyError` is raised. + For example:: + + >>> unicodedata.lookup('LEFT CURLY BRACKET') + '{' + + The characters returned by this function are the same as those produced by + ``\N`` escape sequence in string literals. For example:: + + >>> unicodedata.lookup('MIDDLE DOT') == '\N{MIDDLE DOT}' + True .. versionchanged:: 3.3 Support for name aliases [#]_ and named sequences [#]_ has been added. -.. function:: name(chr[, default]) +.. function:: name(chr, default=None, /) Returns the name assigned to the character *chr* as a string. If no name is defined, *default* is returned, or, if not given, :exc:`ValueError` is - raised. + raised. For example:: + + >>> unicodedata.name('½') + 'VULGAR FRACTION ONE HALF' + >>> unicodedata.name('\uFFFF', 'fallback') + 'fallback' -.. function:: decimal(chr[, default]) +.. function:: decimal(chr, default=None, /) Returns the decimal value assigned to the character *chr* as integer. If no such value is defined, *default* is returned, or, if not given, - :exc:`ValueError` is raised. + :exc:`ValueError` is raised. For example:: + + >>> unicodedata.decimal('\N{ARABIC-INDIC DIGIT NINE}') + 9 + >>> unicodedata.decimal('\N{SUPERSCRIPT NINE}', -1) + -1 -.. function:: digit(chr[, default]) +.. function:: digit(chr, default=None, /) Returns the digit value assigned to the character *chr* as integer. If no such value is defined, *default* is returned, or, if not given, - :exc:`ValueError` is raised. + :exc:`ValueError` is raised:: + + >>> unicodedata.digit('\N{SUPERSCRIPT NINE}') + 9 -.. function:: numeric(chr[, default]) +.. function:: numeric(chr, default=None, /) Returns the numeric value assigned to the character *chr* as float. If no such value is defined, *default* is returned, or, if not given, - :exc:`ValueError` is raised. + :exc:`ValueError` is raised:: + + >>> unicodedata.numeric('½') + 0.5 -.. function:: category(chr) +.. function:: category(chr, /) Returns the general category assigned to the character *chr* as - string. + string. General category names consist of two letters. + See the `General Category Values section of the Unicode Character + Database documentation `_ + for a list of category codes. For example:: + + >>> unicodedata.category('A') # 'L'etter, 'u'ppercase + 'Lu' -.. function:: bidirectional(chr) +.. function:: bidirectional(chr, /) Returns the bidirectional class assigned to the character *chr* as string. If no such value is defined, an empty string is returned. + See the `Bidirectional Class Values section of the Unicode Character + Database `_ + documentation for a list of bidirectional codes. For example:: + + >>> unicodedata.bidirectional('\N{ARABIC-INDIC DIGIT SEVEN}') # 'A'rabic, 'N'umber + 'AN' -.. function:: combining(chr) +.. function:: combining(chr, /) Returns the canonical combining class assigned to the character *chr* as integer. Returns ``0`` if no combining class is defined. + See the `Canonical Combining Class Values section of the Unicode Character + Database `_ + for more information. -.. function:: east_asian_width(chr) +.. function:: east_asian_width(chr, /) Returns the east asian width assigned to the character *chr* as - string. + string. For a list of widths and or more information, see the + `Unicode Standard Annex #11 `_. -.. function:: mirrored(chr) +.. function:: mirrored(chr, /) Returns the mirrored property assigned to the character *chr* as integer. Returns ``1`` if the character has been identified as a "mirrored" - character in bidirectional text, ``0`` otherwise. + character in bidirectional text, ``0`` otherwise. For example:: + + >>> unicodedata.mirrored('>') + 1 -.. function:: decomposition(chr) +.. function:: isxidstart(chr, /) + + Return ``True`` if *chr* is a valid identifier start per the + `Unicode Standard Annex #31 `_, + that is, it has the ``XID_Start`` property. Return ``False`` otherwise. + For example:: + + >>> unicodedata.isxidstart('S') + True + >>> unicodedata.isxidstart('0') + False + + .. versionadded:: 3.15 + + +.. function:: isxidcontinue(chr, /) + + Return ``True`` if *chr* is a valid identifier character per the + `Unicode Standard Annex #31 `_, + that is, it has the ``XID_Continue`` property. Return ``False`` otherwise. + For example:: + + >>> unicodedata.isxidcontinue('S') + True + >>> unicodedata.isxidcontinue(' ') + False + + .. versionadded:: 3.15 + + +.. function:: decomposition(chr, /) Returns the character decomposition mapping assigned to the character *chr* as string. An empty string is returned in case no such mapping is - defined. + defined. For example:: + + >>> unicodedata.decomposition('Ã') + '0041 0303' -.. function:: normalize(form, unistr) +.. function:: normalize(form, unistr, /) Return the normal form *form* for the Unicode string *unistr*. Valid values for *form* are 'NFC', 'NFKC', 'NFD', and 'NFKD'. @@ -122,9 +205,9 @@ following functions: normally would be unified with other characters. For example, U+2160 (ROMAN NUMERAL ONE) is really the same thing as U+0049 (LATIN CAPITAL LETTER I). However, it is supported in Unicode for compatibility with existing character - sets (e.g. gb2312). + sets (for example, gb2312). - The normal form KD (NFKD) will apply the compatibility decomposition, i.e. + The normal form KD (NFKD) will apply the compatibility decomposition, that is, replace all compatibility characters with their equivalents. The normal form KC (NFKC) first applies the compatibility decomposition, followed by the canonical composition. @@ -133,7 +216,8 @@ following functions: a human reader, if one has combining characters and the other doesn't, they may not compare equal. -.. function:: is_normalized(form, unistr) + +.. function:: is_normalized(form, unistr, /) Return whether the Unicode string *unistr* is in the normal form *form*. Valid values for *form* are 'NFC', 'NFKC', 'NFD', and 'NFKD'. @@ -154,27 +238,9 @@ In addition, the module exposes the following constant: Unicode database version 3.2 instead, for applications that require this specific version of the Unicode database (such as IDNA). -Examples: - - >>> import unicodedata - >>> unicodedata.lookup('LEFT CURLY BRACKET') - '{' - >>> unicodedata.name('/') - 'SOLIDUS' - >>> unicodedata.decimal('9') - 9 - >>> unicodedata.decimal('a') - Traceback (most recent call last): - File "", line 1, in - ValueError: not a decimal - >>> unicodedata.category('A') # 'L'etter, 'u'ppercase - 'Lu' - >>> unicodedata.bidirectional('\u0660') # 'A'rabic, 'N'umber - 'AN' - .. rubric:: Footnotes -.. [#] https://www.unicode.org/Public/16.0.0/ucd/NameAliases.txt +.. [#] https://www.unicode.org/Public/17.0.0/ucd/NameAliases.txt -.. [#] https://www.unicode.org/Public/16.0.0/ucd/NamedSequences.txt +.. [#] https://www.unicode.org/Public/17.0.0/ucd/NamedSequences.txt diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 00cc9bfc0a5..61c75b5a03b 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -600,13 +600,13 @@ this list of calls for us:: Partial mocking ~~~~~~~~~~~~~~~ -In some tests I wanted to mock out a call to :meth:`datetime.date.today` -to return a known date, but I didn't want to prevent the code under test from -creating new date objects. Unfortunately :class:`datetime.date` is written in C, and -so I couldn't just monkey-patch out the static :meth:`datetime.date.today` method. +For some tests, you may want to mock out a call to :meth:`datetime.date.today` +to return a known date, but don't want to prevent the code under test from +creating new date objects. Unfortunately :class:`datetime.date` is written in C, +so you cannot just monkey-patch out the static :meth:`datetime.date.today` method. -I found a simple way of doing this that involved effectively wrapping the date -class with a mock, but passing through calls to the constructor to the real +Instead, you can effectively wrap the date +class with a mock, while passing through calls to the constructor to the real class (and returning real instances). The :func:`patch decorator ` is used here to @@ -743,16 +743,15 @@ exception is raised in the setUp then tearDown is not called. Mocking Unbound Methods ~~~~~~~~~~~~~~~~~~~~~~~ -Whilst writing tests today I needed to patch an *unbound method* (patching the -method on the class rather than on the instance). I needed self to be passed -in as the first argument because I want to make asserts about which objects -were calling this particular method. The issue is that you can't patch with a -mock for this, because if you replace an unbound method with a mock it doesn't -become a bound method when fetched from the instance, and so it doesn't get -self passed in. The workaround is to patch the unbound method with a real -function instead. The :func:`patch` decorator makes it so simple to -patch out methods with a mock that having to create a real function becomes a -nuisance. +Sometimes a test needs to patch an *unbound method*, which means patching the +method on the class rather than on the instance. In order to make assertions +about which objects were calling this particular method, you need to pass +``self`` as the first argument. The issue is that you can't patch with a mock for +this, because if you replace an unbound method with a mock it doesn't become +a bound method when fetched from the instance, and so it doesn't get ``self`` +passed in. The workaround is to patch the unbound method with a real function +instead. The :func:`patch` decorator makes it so simple to patch out methods +with a mock that having to create a real function becomes a nuisance. If you pass ``autospec=True`` to patch then it does the patching with a *real* function object. This function object has the same signature as the one @@ -760,8 +759,8 @@ it is replacing, but delegates to a mock under the hood. You still get your mock auto-created in exactly the same way as before. What it means though, is that if you use it to patch out an unbound method on a class the mocked function will be turned into a bound method if it is fetched from an instance. -It will have ``self`` passed in as the first argument, which is exactly what I -wanted: +It will have ``self`` passed in as the first argument, which is exactly what +was needed: >>> class Foo: ... def foo(self): @@ -864,9 +863,9 @@ Here's one solution that uses the :attr:`~Mock.side_effect` functionality. If you provide a ``side_effect`` function for a mock then ``side_effect`` will be called with the same args as the mock. This gives us an opportunity to copy the arguments and store them for later assertions. In this -example I'm using *another* mock to store the arguments so that I can use the +example we're using *another* mock to store the arguments so that we can use the mock methods for doing the assertion. Again a helper function sets this up for -me. :: +us. :: >>> from copy import deepcopy >>> from unittest.mock import Mock, patch, DEFAULT diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index ec96e841612..0bc0a953fd9 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -438,7 +438,7 @@ run whether the test method succeeded or not. Such a working environment for the testing code is called a :dfn:`test fixture`. A new TestCase instance is created as a unique test fixture used to execute each individual test method. Thus -:meth:`~TestCase.setUp`, :meth:`~TestCase.tearDown`, and :meth:`~TestCase.__init__` +:meth:`~TestCase.setUp`, :meth:`~TestCase.tearDown`, and :meth:`!TestCase.__init__` will be called once per test. It is recommended that you use TestCase implementations to group tests together @@ -518,7 +518,7 @@ set-up and tear-down methods:: subclasses will make future test refactorings infinitely easier. In some cases, the existing tests may have been written using the :mod:`doctest` -module. If so, :mod:`doctest` provides a :class:`DocTestSuite` class that can +module. If so, :mod:`doctest` provides a :class:`~doctest.DocTestSuite` class that can automatically build :class:`unittest.TestSuite` instances from the existing :mod:`doctest`\ -based tests. @@ -1023,7 +1023,7 @@ Test cases additional keyword argument *msg*. The context manager will store the caught exception object in its - :attr:`exception` attribute. This can be useful if the intention + :attr:`!exception` attribute. This can be useful if the intention is to perform additional checks on the exception raised:: with self.assertRaises(SomeException) as cm: @@ -1036,7 +1036,7 @@ Test cases Added the ability to use :meth:`assertRaises` as a context manager. .. versionchanged:: 3.2 - Added the :attr:`exception` attribute. + Added the :attr:`!exception` attribute. .. versionchanged:: 3.3 Added the *msg* keyword argument when used as a context manager. @@ -1089,8 +1089,8 @@ Test cases additional keyword argument *msg*. The context manager will store the caught warning object in its - :attr:`warning` attribute, and the source line which triggered the - warnings in the :attr:`filename` and :attr:`lineno` attributes. + :attr:`!warning` attribute, and the source line which triggered the + warnings in the :attr:`!filename` and :attr:`!lineno` attributes. This can be useful if the intention is to perform additional checks on the warning caught:: @@ -1177,7 +1177,7 @@ Test cases .. versionadded:: 3.4 - .. versionchanged:: next + .. versionchanged:: 3.15 Now accepts a *formatter* to control how messages are formatted. .. method:: assertNoLogs(logger=None, level=None) @@ -1437,7 +1437,7 @@ Test cases that lists the differences between the sets. This method is used by default when comparing sets or frozensets with :meth:`assertEqual`. - Fails if either of *first* or *second* does not have a :meth:`set.difference` + Fails if either of *first* or *second* does not have a :meth:`~frozenset.difference` method. .. versionadded:: 3.1 @@ -1645,7 +1645,7 @@ Test cases .. method:: asyncSetUp() :async: - Method called to prepare the test fixture. This is called after :meth:`setUp`. + Method called to prepare the test fixture. This is called after :meth:`TestCase.setUp`. This is called immediately before calling the test method; other than :exc:`AssertionError` or :exc:`SkipTest`, any exception raised by this method will be considered an error rather than a test failure. The default implementation @@ -1655,7 +1655,7 @@ Test cases :async: Method called immediately after the test method has been called and the - result recorded. This is called before :meth:`tearDown`. This is called even if + result recorded. This is called before :meth:`~TestCase.tearDown`. This is called even if the test method raised an exception, so the implementation in subclasses may need to be particularly careful about checking internal state. Any exception, other than :exc:`AssertionError` or :exc:`SkipTest`, raised by this method will be @@ -1684,7 +1684,7 @@ Test cases Sets up a new event loop to run the test, collecting the result into the :class:`TestResult` object passed as *result*. If *result* is omitted or ``None``, a temporary result object is created (by calling - the :meth:`defaultTestResult` method) and used. The result object is + the :meth:`~TestCase.defaultTestResult` method) and used. The result object is returned to :meth:`run`'s caller. At the end of the test all the tasks in the event loop are cancelled. @@ -1805,7 +1805,7 @@ Grouping tests returned by repeated iterations before :meth:`TestSuite.run` must be the same for each call iteration. After :meth:`TestSuite.run`, callers should not rely on the tests returned by this method unless the caller uses a - subclass that overrides :meth:`TestSuite._removeTestAtIndex` to preserve + subclass that overrides :meth:`!TestSuite._removeTestAtIndex` to preserve test references. .. versionchanged:: 3.2 @@ -1816,10 +1816,10 @@ Grouping tests .. versionchanged:: 3.4 In earlier versions the :class:`TestSuite` held references to each :class:`TestCase` after :meth:`TestSuite.run`. Subclasses can restore - that behavior by overriding :meth:`TestSuite._removeTestAtIndex`. + that behavior by overriding :meth:`!TestSuite._removeTestAtIndex`. In the typical usage of a :class:`TestSuite` object, the :meth:`run` method - is invoked by a :class:`TestRunner` rather than by the end-user test harness. + is invoked by a :class:`!TestRunner` rather than by the end-user test harness. Loading and running tests @@ -1853,12 +1853,12 @@ Loading and running tests .. method:: loadTestsFromTestCase(testCaseClass) Return a suite of all test cases contained in the :class:`TestCase`\ -derived - :class:`testCaseClass`. + :class:`!testCaseClass`. A test case instance is created for each method named by :meth:`getTestCaseNames`. By default these are the method names beginning with ``test``. If :meth:`getTestCaseNames` returns no - methods, but the :meth:`runTest` method is implemented, a single test + methods, but the :meth:`!runTest` method is implemented, a single test case is created for that method instead. @@ -1905,13 +1905,13 @@ Loading and running tests case class will be picked up as "a test method within a test case class", rather than "a callable object". - For example, if you have a module :mod:`SampleTests` containing a - :class:`TestCase`\ -derived class :class:`SampleTestCase` with three test - methods (:meth:`test_one`, :meth:`test_two`, and :meth:`test_three`), the + For example, if you have a module :mod:`!SampleTests` containing a + :class:`TestCase`\ -derived class :class:`!SampleTestCase` with three test + methods (:meth:`!test_one`, :meth:`!test_two`, and :meth:`!test_three`), the specifier ``'SampleTests.SampleTestCase'`` would cause this method to return a suite which will run all three test methods. Using the specifier ``'SampleTests.SampleTestCase.test_two'`` would cause it to return a test - suite which will run only the :meth:`test_two` test method. The specifier + suite which will run only the :meth:`!test_two` test method. The specifier can refer to modules and packages which have not been imported; they will be imported as a side-effect. @@ -2058,7 +2058,7 @@ Loading and running tests Testing frameworks built on top of :mod:`unittest` may want access to the :class:`TestResult` object generated by running a set of tests for reporting purposes; a :class:`TestResult` instance is returned by the - :meth:`TestRunner.run` method for this purpose. + :meth:`!TestRunner.run` method for this purpose. :class:`TestResult` instances have the following attributes that will be of interest when inspecting the results of running a set of tests: @@ -2144,12 +2144,12 @@ Loading and running tests This method can be called to signal that the set of tests being run should be aborted by setting the :attr:`shouldStop` attribute to ``True``. - :class:`TestRunner` objects should respect this flag and return without + :class:`!TestRunner` objects should respect this flag and return without running any additional tests. For example, this feature is used by the :class:`TextTestRunner` class to stop the test framework when the user signals an interrupt from the - keyboard. Interactive tools which provide :class:`TestRunner` + keyboard. Interactive tools which provide :class:`!TestRunner` implementations can use this in a similar manner. The following methods of the :class:`TestResult` class are used to maintain @@ -2469,9 +2469,9 @@ Class and Module Fixtures ------------------------- Class and module level fixtures are implemented in :class:`TestSuite`. When -the test suite encounters a test from a new class then :meth:`tearDownClass` -from the previous class (if there is one) is called, followed by -:meth:`setUpClass` from the new class. +the test suite encounters a test from a new class then +:meth:`~TestCase.tearDownClass` from the previous class (if there is one) +is called, followed by :meth:`~TestCase.setUpClass` from the new class. Similarly if a test is from a different module from the previous test then ``tearDownModule`` from the previous module is run, followed by @@ -2532,6 +2532,10 @@ instead of as an error. setUpModule and tearDownModule ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. function:: setUpModule + tearDownModule + :no-typesetting: + These should be implemented as functions:: def setUpModule(): diff --git a/Doc/library/urllib.robotparser.rst b/Doc/library/urllib.robotparser.rst index 016fcdc75da..674f646c633 100644 --- a/Doc/library/urllib.robotparser.rst +++ b/Doc/library/urllib.robotparser.rst @@ -19,7 +19,7 @@ This module provides a single class, :class:`RobotFileParser`, which answers questions about whether or not a particular user agent can fetch a URL on the -web site that published the :file:`robots.txt` file. For more details on the +website that published the :file:`robots.txt` file. For more details on the structure of :file:`robots.txt` files, see http://www.robotstxt.org/orig.html. diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index de427fbafe7..4c000a92e87 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -78,7 +78,7 @@ It also creates a :file:`bin` (or :file:`Scripts` on Windows) subdirectory containing a copy or symlink of the Python executable (as appropriate for the platform or arguments used at environment creation time). It also creates a :file:`lib/pythonX.Y/site-packages` subdirectory -(on Windows, this is :file:`Lib\site-packages`). +(on Windows, this is :file:`Lib\\site-packages`). If an existing directory is specified, it will be re-used. .. versionchanged:: 3.5 @@ -407,6 +407,8 @@ creation according to their needs, the :class:`EnvBuilder` class. * ``lib_path`` - The purelib path for the virtual environment. + * ``platlib_path`` - The platlib path for the virtual environment. + * ``bin_path`` - The script path for the virtual environment. * ``bin_name`` - The name of the script path relative to the virtual @@ -431,6 +433,9 @@ creation according to their needs, the :class:`EnvBuilder` class. The attribute ``lib_path`` was added to the context, and the context object was documented. + .. versionchanged:: 3.15 + The attribute ``platlib_path`` was added to the context. + .. method:: create_configuration(context) Creates the ``pyvenv.cfg`` configuration file in the environment. diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst index 05e061cc697..0de7a90bfcb 100644 --- a/Doc/library/warnings.rst +++ b/Doc/library/warnings.rst @@ -80,7 +80,9 @@ The following warnings category classes are currently defined: | | unless triggered by code in ``__main__``). | +----------------------------------+-----------------------------------------------+ | :exc:`SyntaxWarning` | Base category for warnings about dubious | -| | syntactic features. | +| | syntactic features (typically emitted when | +| | compiling Python source code, and hence | +| | may not be suppressed by runtime filters) | +----------------------------------+-----------------------------------------------+ | :exc:`RuntimeWarning` | Base category for warnings about dubious | | | runtime features. | @@ -157,8 +159,10 @@ the disposition of the match. Each entry is a tuple of the form (*action*, * *message* is a string containing a regular expression that the start of the warning message must match, case-insensitively. In :option:`-W` and - :envvar:`PYTHONWARNINGS`, *message* is a literal string that the start of the - warning message must contain (case-insensitively), ignoring any whitespace at + :envvar:`PYTHONWARNINGS`, if *message* starts and ends with a forward slash + (``/``), it specifies a regular expression as above; + otherwise it is a literal string that the start of the + warning message must match (case-insensitively), ignoring any whitespace at the start or end of *message*. * *category* is a class (a subclass of :exc:`Warning`) of which the warning @@ -166,7 +170,9 @@ the disposition of the match. Each entry is a tuple of the form (*action*, * *module* is a string containing a regular expression that the start of the fully qualified module name must match, case-sensitively. In :option:`-W` and - :envvar:`PYTHONWARNINGS`, *module* is a literal string that the + :envvar:`PYTHONWARNINGS`, if *module* starts and ends with a forward slash + (``/``), it specifies a regular expression as above; + otherwise it is a literal string that the fully qualified module name must be equal to (case-sensitively), ignoring any whitespace at the start or end of *module*. @@ -474,14 +480,28 @@ Available Functions .. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None) This is a low-level interface to the functionality of :func:`warn`, passing in - explicitly the message, category, filename and line number, and optionally the - module name and the registry (which should be the ``__warningregistry__`` - dictionary of the module). The module name defaults to the filename with - ``.py`` stripped; if no registry is passed, the warning is never suppressed. + explicitly the message, category, filename and line number, and optionally + other arguments. *message* must be a string and *category* a subclass of :exc:`Warning` or *message* may be a :exc:`Warning` instance, in which case *category* will be ignored. + *module*, if supplied, should be the module name. + If no module is passed, the module regular expression in + :ref:`warnings filter ` will be tested against the module + names constructed from the path components starting from all parent + directories (with ``/__init__.py``, ``.py`` and, on Windows, ``.pyw`` + stripped) and against the filename with ``.py`` stripped. + For example, when the filename is ``'/path/to/package/module.py'``, it will + be tested against ``'path.to.package.module'``, ``'to.package.module'`` + ``'package.module'``, ``'module'``, and ``'/path/to/package/module'``. + + *registry*, if supplied, should be the ``__warningregistry__`` dictionary + of the module. + If no registry is passed, each warning is treated as the first occurrence, + that is, filter actions ``"default"``, ``"module"`` and ``"once"`` are + handled as ``"always"``. + *module_globals*, if supplied, should be the global namespace in use by the code for which the warning is issued. (This argument is used to support displaying source for modules found in zipfiles or other non-filesystem import @@ -493,6 +513,10 @@ Available Functions .. versionchanged:: 3.6 Add the *source* parameter. + .. versionchanged:: 3.15 + If no module is passed, test the filter regular expression against + module names created from the path, not only the path itself. + .. function:: showwarning(message, category, filename, lineno, file=None, line=None) @@ -584,7 +608,7 @@ Available Functions The deprecation message passed to the decorator is saved in the ``__deprecated__`` attribute on the decorated object. If applied to an overload, the decorator - must be after the :func:`@overload ` decorator + must be after the :deco:`~typing.overload` decorator for the attribute to exist on the overload as returned by :func:`typing.get_overloads`. diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index a3f5bfd5e2f..7ff2c97992c 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -25,8 +25,9 @@ The :mod:`wave` module defines the following function and exception: .. function:: open(file, mode=None) - If *file* is a string, open the file by that name, otherwise treat it as a - file-like object. *mode* can be: + If *file* is a string, a :term:`path-like object` or a + :term:`bytes-like object` open the file by that name, otherwise treat it as + a file-like object. *mode* can be: ``'rb'`` Read only mode. @@ -52,6 +53,10 @@ The :mod:`wave` module defines the following function and exception: .. versionchanged:: 3.4 Added support for unseekable files. + .. versionchanged:: 3.15 + Added support for :term:`path-like objects ` + and :term:`bytes-like objects `. + .. exception:: Error An error raised when something is impossible because it violates the WAV diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst index fd6abc70261..a2103d8fdd8 100644 --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -49,6 +49,11 @@ a new tab, with the browser being brought to the foreground. The use of the :mod:`webbrowser` module on iOS requires the :mod:`ctypes` module. If :mod:`ctypes` isn't available, calls to :func:`.open` will fail. +.. _webbrowser-cli: + +Command-line interface +---------------------- + .. program:: webbrowser The script :program:`webbrowser` can be used as a command-line interface for the @@ -232,7 +237,7 @@ Here are some simple examples:: .. _browser-controllers: -Browser Controller Objects +Browser controller objects -------------------------- Browser controllers provide the :attr:`~controller.name` attribute, diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index b3a824fb69a..89def6e2afe 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -14,6 +14,8 @@ integer as the registry handle, a :ref:`handle object ` is used to ensure that the handles are closed correctly, even if the programmer neglects to explicitly close them. +.. availability:: Windows. + .. _exception-changed: .. versionchanged:: 3.3 @@ -173,6 +175,24 @@ This module offers the following functions: See :ref:`above `. +.. function:: DeleteTree(key, sub_key=None) + + Deletes the specified key and all its subkeys and values recursively. + + *key* is an already open key, or one of the predefined + :ref:`HKEY_* constants `. + + *sub_key* is a string that names the subkey to delete. If ``None``, + deletes all subkeys and values of the specified key. + + This function deletes a key and all its descendants. If *sub_key* is + ``None``, all subkeys and values of the specified key are deleted. + + .. audit-event:: winreg.DeleteTree key,sub_key winreg.DeleteTree + + .. versionadded:: 3.15 + + .. function:: DeleteValue(key, value) Removes a named value from a registry key. @@ -753,8 +773,9 @@ Handle objects provide semantics for :meth:`~object.__bool__` -- thus :: will print ``Yes`` if the handle is currently valid (has not been closed or detached). -The object also support comparison semantics, so handle objects will compare -true if they both reference the same underlying Windows handle value. +The object also support equality comparison semantics, so handle objects will +compare equal if they both reference the same underlying Windows handle value. +Closed handle objects (those with a handle value of zero) always compare equal. Handle objects can be converted to an integer (e.g., using the built-in :func:`int` function), in which case the underlying Windows handle value is @@ -797,3 +818,6 @@ integer handle, and also disconnect the Windows handle from the handle object. will automatically close *key* when control leaves the :keyword:`with` block. +.. versionchanged:: 3.15 + Handle objects are now compared by their underlying Windows handle value + instead of object identity for equality comparisons. diff --git a/Doc/library/winsound.rst b/Doc/library/winsound.rst index 925984c3cdb..93c0c025982 100644 --- a/Doc/library/winsound.rst +++ b/Doc/library/winsound.rst @@ -13,6 +13,8 @@ The :mod:`winsound` module provides access to the basic sound-playing machinery provided by Windows platforms. It includes functions and several constants. +.. availability:: Windows. + .. function:: Beep(frequency, duration) diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst index 8bceeecd463..a21cfaa4645 100644 --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -74,7 +74,7 @@ given point) or to make use of the :func:`DOMEventStream.expandNode` method and switch to DOM-related processing. -.. class:: PullDom(documentFactory=None) +.. class:: PullDOM(documentFactory=None) Subclass of :class:`xml.sax.handler.ContentHandler`. diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index 00075ac2a23..e59759683a6 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -656,6 +656,10 @@ Functions .. versionchanged:: 3.13 Added the :meth:`!close` method. + .. versionchanged:: 3.15 + A :exc:`ResourceWarning` is now emitted if the iterator opened a file + and is not explicitly closed. + .. function:: parse(source, parser=None) @@ -1398,10 +1402,10 @@ XMLParser Objects Disabling reparse deferral has security consequences; please see :meth:`xml.parsers.expat.xmlparser.SetReparseDeferralEnabled` for details. - Note that :meth:`flush` has been backported to some prior releases of - CPython as a security fix. Check for availability of :meth:`flush` - using :func:`hasattr` if used in code running across a variety of Python - versions. + :meth:`!flush` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. .. versionadded:: 3.13 @@ -1476,10 +1480,10 @@ XMLPullParser Objects Disabling reparse deferral has security consequences; please see :meth:`xml.parsers.expat.xmlparser.SetReparseDeferralEnabled` for details. - Note that :meth:`flush` has been backported to some prior releases of - CPython as a security fix. Check for availability of :meth:`flush` - using :func:`hasattr` if used in code running across a variety of Python - versions. + :meth:`!flush` + has been backported to some prior releases of CPython as a security fix. + Check for availability using :func:`hasattr` if used in code running + across a variety of Python versions. .. versionadded:: 3.13 diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst index 28465219a1a..acd8d399fe3 100644 --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -53,11 +53,22 @@ XML security An attacker can abuse XML features to carry out denial of service attacks, access local files, generate network connections to other machines, or -circumvent firewalls. +circumvent firewalls when attacker-controlled XML is being parsed, +in Python or elsewhere. -Expat versions lower that 2.6.0 may be vulnerable to "billion laughs", -"quadratic blowup" and "large tokens". Python may be vulnerable if it uses such -older versions of Expat as a system-provided library. +The built-in XML parsers of Python rely on the library `libexpat`_, commonly +called Expat, for parsing XML. + +By default, Expat itself does not access local files or create network +connections. + +Expat versions lower than 2.7.2 may be vulnerable to the "billion laughs", +"quadratic blowup" and "large tokens" vulnerabilities, or to disproportional +use of dynamic memory. +Python bundles a copy of Expat, and whether Python uses the bundled or a +system-wide Expat, depends on how the Python interpreter +:option:`has been configured <--with-system-expat>` in your environment. +Python may be vulnerable if it uses such older versions of Expat. Check :const:`!pyexpat.EXPAT_VERSION`. :mod:`xmlrpc` is **vulnerable** to the "decompression bomb" attack. @@ -90,5 +101,6 @@ large tokens be used to cause denial of service in the application parsing XML. The issue is known as :cve:`2023-52425`. +.. _libexpat: https://github.com/libexpat/libexpat .. _Billion Laughs: https://en.wikipedia.org/wiki/Billion_laughs .. _ZIP bomb: https://en.wikipedia.org/wiki/Zip_bomb diff --git a/Doc/library/xml.sax.handler.rst b/Doc/library/xml.sax.handler.rst index c2c9d6424b5..f1af7253e43 100644 --- a/Doc/library/xml.sax.handler.rst +++ b/Doc/library/xml.sax.handler.rst @@ -96,6 +96,14 @@ for the feature and property names. .. data:: feature_external_ges + .. warning:: + + Enabling opens a vulnerability to + `external entity attacks `_ + if the parser is used with user-provided XML content. + Please reflect on your `threat model `_ + before enabling this feature. + | value: ``"http://xml.org/sax/features/external-general-entities"`` | true: Include all external general (text) entities. | false: Do not include external general entities. @@ -248,8 +256,7 @@ events in the input document: The *name* parameter contains the raw XML 1.0 name of the element type as a string and the *attrs* parameter holds an object of the - :class:`~xml.sax.xmlreader.Attributes` - interface (see :ref:`attributes-objects`) containing the attributes of + :ref:`Attributes ` interface containing the attributes of the element. The object passed as *attrs* may be re-used by the parser; holding on to a reference to it is not a reliable way to keep a copy of the attributes. To keep a copy of the attributes, use the :meth:`copy` method of the *attrs* @@ -271,8 +278,7 @@ events in the input document: The *name* parameter contains the name of the element type as a ``(uri, localname)`` tuple, the *qname* parameter contains the raw XML 1.0 name used in the source document, and the *attrs* parameter holds an instance of the - :class:`~xml.sax.xmlreader.AttributesNS` interface (see - :ref:`attributes-ns-objects`) + :ref:`AttributesNS ` interface containing the attributes of the element. If no namespace is associated with the element, the *uri* component of *name* will be ``None``. The object passed as *attrs* may be re-used by the parser; holding on to a reference to it is not diff --git a/Doc/library/xml.sax.utils.rst b/Doc/library/xml.sax.utils.rst index 5ee11d58c3d..7731f03d875 100644 --- a/Doc/library/xml.sax.utils.rst +++ b/Doc/library/xml.sax.utils.rst @@ -37,7 +37,7 @@ or as base classes. You can unescape other strings of data by passing a dictionary as the optional *entities* parameter. The keys and values must all be strings; each key will be - replaced with its corresponding value. ``'&'``, ``'<'``, and ``'>'`` + replaced with its corresponding value. ``'&'``, ``'<'``, and ``'>'`` are always unescaped, even if *entities* is provided. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst index 547cb50be78..7e511237a6a 100644 --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -179,9 +179,9 @@ ServerProxy Objects A :class:`ServerProxy` instance has a method corresponding to each remote procedure call accepted by the XML-RPC server. Calling the method performs an RPC, dispatched by both name and argument signature (e.g. the same method name -can be overloaded with multiple argument signatures). The RPC finishes by -returning a value, which may be either returned data in a conformant type or a -:class:`Fault` or :class:`ProtocolError` object indicating an error. +can be overloaded with multiple argument signatures). The RPC finishes either +by returning data in a conformant type or by raising a :class:`Fault` or +:class:`ProtocolError` exception indicating an error. Servers that support the XML introspection API support some common methods grouped under the reserved :attr:`~ServerProxy.system` attribute: @@ -472,7 +472,7 @@ remote server into a single request [#]_. Create an object used to boxcar method calls. *server* is the eventual target of the call. Calls can be made to the result object, but they will immediately - return ``None``, and only store the call name and parameters in the + return ``None``, and only store the call name and arguments in the :class:`MultiCall` object. Calling the object itself causes all stored calls to be transmitted as a single ``system.multicall`` request. The result of this call is a :term:`generator`; iterating over this generator yields the individual @@ -524,7 +524,7 @@ Convenience Functions .. function:: dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False) - Convert *params* into an XML-RPC request. or into a response if *methodresponse* + Convert *params* into an XML-RPC request, or into a response if *methodresponse* is true. *params* can be either a tuple of arguments or an instance of the :exc:`Fault` exception class. If *methodresponse* is true, only a single value can be returned, meaning that *params* must be of length 1. *encoding*, if diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index f6ec33640b6..ae4e25b13b9 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -16,13 +16,23 @@ provides tools to create, read, write, append, and list a ZIP file. Any advanced use of this module will require an understanding of the format, as defined in `PKZIP Application Note`_. -This module does not currently handle multi-disk ZIP files. +This module does not handle multipart ZIP files. It can handle ZIP files that use the ZIP64 extensions (that is ZIP files that are more than 4 GiB in size). It supports -decryption of encrypted files in ZIP archives, but it currently cannot +decryption of encrypted files in ZIP archives, but it cannot create an encrypted file. Decryption is extremely slow as it is implemented in native Python rather than C. +.. + The following paragraph should be similar to ../includes/optional-module.rst + +Handling compressed archives requires :term:`optional modules ` +such as :mod:`zlib`, :mod:`bz2`, :mod:`lzma`, and :mod:`compression.zstd`. +If any of them are missing from your copy of CPython, +look for documentation from your distributor (that is, +whoever provided Python to you). +If you are the distributor, see :ref:`optional-module-requirements`. + The module defines the following items: .. exception:: BadZipFile @@ -165,7 +175,7 @@ The module defines the following items: .. _zipfile-objects: -ZipFile Objects +ZipFile objects --------------- @@ -238,7 +248,7 @@ ZipFile Objects .. note:: *metadata_encoding* is an instance-wide setting for the ZipFile. - It is not currently possible to set this on a per-member basis. + It is not possible to set this on a per-member basis. This attribute is a workaround for legacy implementations which produce archives with names in the current locale encoding or code page (mostly @@ -561,7 +571,7 @@ The following data attributes are also available: .. _path-objects: -Path Objects +Path objects ------------ .. class:: Path(root, at='') @@ -697,7 +707,7 @@ changes. .. _pyzipfile-objects: -PyZipFile Objects +PyZipFile objects ----------------- The :class:`PyZipFile` constructor takes the same parameters as the @@ -774,7 +784,7 @@ The :class:`PyZipFile` constructor takes the same parameters as the .. _zipinfo-objects: -ZipInfo Objects +ZipInfo objects --------------- Instances of the :class:`ZipInfo` class are returned by the :meth:`.getinfo` and @@ -944,7 +954,7 @@ Instances have the following methods and attributes: .. _zipfile-commandline: .. program:: zipfile -Command-Line Interface +Command-line interface ---------------------- The :mod:`zipfile` module provides a simple command-line interface to interact @@ -1019,7 +1029,7 @@ From file itself Decompression may fail due to incorrect password / CRC checksum / ZIP format or unsupported compression method / decryption. -File System limitations +File system limitations ~~~~~~~~~~~~~~~~~~~~~~~ Exceeding limitations on different file systems can cause decompression failed. diff --git a/Doc/library/zipimport.rst b/Doc/library/zipimport.rst index cd76f29a556..444c3d631a4 100644 --- a/Doc/library/zipimport.rst +++ b/Doc/library/zipimport.rst @@ -30,6 +30,9 @@ Any files may be present in the ZIP archive, but importers are only invoked for corresponding :file:`.pyc` file, meaning that if a ZIP archive doesn't contain :file:`.pyc` files, importing may be rather slow. +.. versionchanged:: 3.15 + Zstandard (*zstd*) compressed zip file entries are supported. + .. versionchanged:: 3.13 ZIP64 is supported @@ -142,17 +145,6 @@ zipimporter Objects :exc:`ZipImportError` if the module couldn't be found. - .. method:: load_module(fullname) - - Load the module specified by *fullname*. *fullname* must be the fully - qualified (dotted) module name. Returns the imported module on success, - raises :exc:`ZipImportError` on failure. - - .. deprecated-removed:: 3.10 3.15 - - Use :meth:`exec_module` instead. - - .. method:: invalidate_caches() Clear out the internal cache of information about files found within @@ -188,17 +180,20 @@ Here is an example that imports a module from a ZIP archive - note that the .. code-block:: shell-session - $ unzip -l example.zip - Archive: example.zip + $ unzip -l example_archive.zip + Archive: example_archive.zip Length Date Time Name -------- ---- ---- ---- - 8467 11-26-02 22:30 jwzthreading.py + 8467 01-01-00 12:30 example.py -------- ------- 8467 1 file - $ ./python - Python 2.3 (#1, Aug 1 2003, 19:54:32) + +.. code-block:: pycon + >>> import sys - >>> sys.path.insert(0, 'example.zip') # Add .zip file to front of path - >>> import jwzthreading - >>> jwzthreading.__file__ - 'example.zip/jwzthreading.py' + >>> # Add the archive to the front of the module search path + >>> sys.path.insert(0, 'example_archive.zip') + >>> import example + >>> example.__file__ + 'example_archive.zip/example.py' + diff --git a/Doc/library/zlib.rst b/Doc/library/zlib.rst index 7c5e9b086e1..ce0a22b9456 100644 --- a/Doc/library/zlib.rst +++ b/Doc/library/zlib.rst @@ -8,15 +8,13 @@ -------------- For applications that require data compression, the functions in this module -allow compression and decompression, using the zlib library. The zlib library -has its own home page at https://www.zlib.net. There are known -incompatibilities between the Python module and versions of the zlib library -earlier than 1.1.3; 1.1.3 has a `security vulnerability `_, so we recommend using -1.1.4 or later. +allow compression and decompression, using the `zlib library `_. + +.. include:: ../includes/optional-module.rst zlib's functions have many options and often need to be used in a particular order. This documentation doesn't attempt to cover all of the permutations; -consult the zlib manual at http://www.zlib.net/manual.html for authoritative +consult the `zlib manual `_ for authoritative information. For reading and writing ``.gz`` files see the :mod:`gzip` module. @@ -56,23 +54,22 @@ The available exception and functions in this module are: that were concurrently computed. To compute checksums sequentially, use :func:`adler32` with the running checksum as the ``value`` argument. - .. versionadded:: next + .. versionadded:: 3.15 -.. function:: compress(data, /, level=-1, wbits=MAX_WBITS) +.. function:: compress(data, /, level=Z_DEFAULT_COMPRESSION, wbits=MAX_WBITS) Compresses the bytes in *data*, returning a bytes object containing compressed data. *level* is an integer from ``0`` to ``9`` or ``-1`` controlling the level of compression; - ``1`` (Z_BEST_SPEED) is fastest and produces the least compression, ``9`` (Z_BEST_COMPRESSION) - is slowest and produces the most. ``0`` (Z_NO_COMPRESSION) is no compression. - The default value is ``-1`` (Z_DEFAULT_COMPRESSION). Z_DEFAULT_COMPRESSION represents a default - compromise between speed and compression (currently equivalent to level 6). + See :const:`Z_BEST_SPEED` (``1``), :const:`Z_BEST_COMPRESSION` (``9``), + :const:`Z_NO_COMPRESSION` (``0``), and the default, + :const:`Z_DEFAULT_COMPRESSION` (``-1``) for more information about these values. .. _compress-wbits: The *wbits* argument controls the size of the history buffer (or the "window size") used when compressing data, and whether a header and trailer is included in the output. It can take several ranges of values, - defaulting to ``15`` (MAX_WBITS): + defaulting to ``15`` (:const:`MAX_WBITS`): * +9 to +15: The base-two logarithm of the window size, which therefore ranges between 512 and 32768. Larger values produce @@ -96,17 +93,15 @@ The available exception and functions in this module are: The *wbits* parameter is now available to set window bits and compression type. -.. function:: compressobj(level=-1, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY[, zdict]) +.. function:: compressobj(level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY[, zdict]) Returns a compression object, to be used for compressing data streams that won't fit into memory at once. *level* is the compression level -- an integer from ``0`` to ``9`` or ``-1``. - A value of ``1`` (Z_BEST_SPEED) is fastest and produces the least compression, - while a value of ``9`` (Z_BEST_COMPRESSION) is slowest and produces the most. - ``0`` (Z_NO_COMPRESSION) is no compression. The default value is ``-1`` (Z_DEFAULT_COMPRESSION). - Z_DEFAULT_COMPRESSION represents a default compromise between speed and compression - (currently equivalent to level 6). + See :const:`Z_BEST_SPEED` (``1``), :const:`Z_BEST_COMPRESSION` (``9``), + :const:`Z_NO_COMPRESSION` (``0``), and the default, + :const:`Z_DEFAULT_COMPRESSION` (``-1``) for more information about these values. *method* is the compression algorithm. Currently, the only supported value is :const:`DEFLATED`. @@ -121,7 +116,7 @@ The available exception and functions in this module are: *strategy* is used to tune the compression algorithm. Possible values are :const:`Z_DEFAULT_STRATEGY`, :const:`Z_FILTERED`, :const:`Z_HUFFMAN_ONLY`, - :const:`Z_RLE` (zlib 1.2.0.1) and :const:`Z_FIXED` (zlib 1.2.2.2). + :const:`Z_RLE` and :const:`Z_FIXED`. *zdict* is a predefined compression dictionary. This is a sequence of bytes (such as a :class:`bytes` object) containing subsequences that are expected @@ -162,7 +157,7 @@ The available exception and functions in this module are: that were concurrently computed. To compute checksums sequentially, use :func:`crc32` with the running checksum as the ``value`` argument. - .. versionadded:: next + .. versionadded:: 3.15 .. function:: decompress(data, /, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE) @@ -249,7 +244,7 @@ Compression objects support the following methods: All pending input is processed, and a bytes object containing the remaining compressed output is returned. *mode* can be selected from the constants :const:`Z_NO_FLUSH`, :const:`Z_PARTIAL_FLUSH`, :const:`Z_SYNC_FLUSH`, - :const:`Z_FULL_FLUSH`, :const:`Z_BLOCK` (zlib 1.2.3.4), or :const:`Z_FINISH`, + :const:`Z_FULL_FLUSH`, :const:`Z_BLOCK`, or :const:`Z_FINISH`, defaulting to :const:`Z_FINISH`. Except :const:`Z_FINISH`, all constants allow compressing further bytestrings of data, while :const:`Z_FINISH` finishes the compressed stream and prevents compressing any more data. After calling :meth:`flush` @@ -340,6 +335,137 @@ Decompression objects support the following methods and attributes: objects. +The following constants are available to configure compression and decompression +behavior: + +.. data:: DEFLATED + + The deflate compression method. + + +.. data:: MAX_WBITS + + The maximum window size, expressed as a power of 2. + For example, if :const:`!MAX_WBITS` is ``15`` it results in a window size + of ``32 KiB``. + + +.. data:: DEF_MEM_LEVEL + + The default memory level for compression objects. + + +.. data:: DEF_BUF_SIZE + + The default buffer size for decompression operations. + + +.. data:: Z_NO_COMPRESSION + + Compression level ``0``; no compression. + + .. versionadded:: 3.6 + + +.. data:: Z_BEST_SPEED + + Compression level ``1``; fastest and produces the least compression. + + +.. data:: Z_BEST_COMPRESSION + + Compression level ``9``; slowest and produces the most compression. + + +.. data:: Z_DEFAULT_COMPRESSION + + Default compression level (``-1``); a compromise between speed and + compression. Currently equivalent to compression level ``6``. + + +.. data:: Z_DEFAULT_STRATEGY + + Default compression strategy, for normal data. + + +.. data:: Z_FILTERED + + Compression strategy for data produced by a filter (or predictor). + + +.. data:: Z_HUFFMAN_ONLY + + Compression strategy that forces Huffman coding only. + + +.. data:: Z_RLE + + Compression strategy that limits match distances to one (run-length encoding). + + This constant is only available if Python was compiled with zlib + 1.2.0.1 or greater. + + .. versionadded:: 3.6 + + +.. data:: Z_FIXED + + Compression strategy that prevents the use of dynamic Huffman codes. + + This constant is only available if Python was compiled with zlib + 1.2.2.2 or greater. + + .. versionadded:: 3.6 + + +.. data:: Z_NO_FLUSH + + Flush mode ``0``. No special flushing behavior. + + .. versionadded:: 3.6 + + +.. data:: Z_PARTIAL_FLUSH + + Flush mode ``1``. Flush as much output as possible. + + +.. data:: Z_SYNC_FLUSH + + Flush mode ``2``. All output is flushed and the output is aligned to a byte boundary. + + +.. data:: Z_FULL_FLUSH + + Flush mode ``3``. All output is flushed and the compression state is reset. + + +.. data:: Z_FINISH + + Flush mode ``4``. All pending input is processed, no more input is expected. + + +.. data:: Z_BLOCK + + Flush mode ``5``. A deflate block is completed and emitted. + + This constant is only available if Python was compiled with zlib + 1.2.2.2 or greater. + + .. versionadded:: 3.6 + + +.. data:: Z_TREES + + Flush mode ``6``, for inflate operations. Instructs inflate to return when + it gets to the next deflate block boundary. + + This constant is only available if Python was compiled with zlib + 1.2.3.4 or greater. + + .. versionadded:: 3.6 + + Information about the version of the zlib library in use is available through the following constants: @@ -375,10 +501,10 @@ the following constants: Module :mod:`gzip` Reading and writing :program:`gzip`\ -format files. - http://www.zlib.net + https://www.zlib.net The zlib library home page. - http://www.zlib.net/manual.html + https://www.zlib.net/manual.html The zlib manual explains the semantics and usage of the library's many functions. diff --git a/Doc/library/zoneinfo.rst b/Doc/library/zoneinfo.rst index 53d8e2598ec..8147e58d322 100644 --- a/Doc/library/zoneinfo.rst +++ b/Doc/library/zoneinfo.rst @@ -299,7 +299,7 @@ The behavior of a ``ZoneInfo`` file depends on how it was constructed: 1. ``ZoneInfo(key)``: When constructed with the primary constructor, a ``ZoneInfo`` object is serialized by key, and when deserialized, the deserializing process uses the primary and thus it is expected that these - are expected to be the same object as other references to the same time + are the same object as other references to the same time zone. For example, if ``europe_berlin_pkl`` is a string containing a pickle constructed from ``ZoneInfo("Europe/Berlin")``, one would expect the following behavior: @@ -349,7 +349,7 @@ Functions This function only includes canonical zone names and does not include "special" zones such as those under the ``posix/`` and ``right/`` - directories, or the ``posixrules`` zone. + directories, the ``posixrules`` or the ``localtime`` zone. .. caution:: diff --git a/Doc/license.rst b/Doc/license.rst index 480414bb84c..269d14cefbc 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -1169,3 +1169,33 @@ contributors. The pyzstd code is distributed under the 3-Clause BSD License:: CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Profiling module +---------------- + +The :mod:`!profiling` module includes vendored third-party libraries in +:file:`Lib/profiling/sampling/_vendor/` with the following licenses: + +**d3-flamegraph** + +The d3-flamegraph library is distributed under the Apache License, Version 2.0. +See the OpenSSL section above for the full text of the Apache License Version 2.0. + +**d3.js** + +The d3.js library contains the following notice:: + + Copyright 2010-2021 Mike Bostock + + Permission to use, copy, modify, and/or distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright notice + and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 4e49a49c081..861c221502e 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -335,15 +335,29 @@ stored in the :mod:`sys` module is reset to its previous value:: :keyword:`!except*` clause -------------------------- -The :keyword:`!except*` clause(s) are used for handling -:exc:`ExceptionGroup`\s. The exception type for matching is interpreted as in -the case of :keyword:`except`, but in the case of exception groups we can have -partial matches when the type matches some of the exceptions in the group. -This means that multiple :keyword:`!except*` clauses can execute, -each handling part of the exception group. -Each clause executes at most once and handles an exception group -of all matching exceptions. Each exception in the group is handled by at most -one :keyword:`!except*` clause, the first that matches it. :: +The :keyword:`!except*` clause(s) specify one or more handlers for groups of +exceptions (:exc:`BaseExceptionGroup` instances). A :keyword:`try` statement +can have either :keyword:`except` or :keyword:`!except*` clauses, but not both. +The exception type for matching is mandatory in the case of :keyword:`!except*`, +so ``except*:`` is a syntax error. The type is interpreted as in the case of +:keyword:`!except`, but matching is performed on the exceptions contained in the +group that is being handled. An :exc:`TypeError` is raised if a matching +type is a subclass of :exc:`!BaseExceptionGroup`, because that would have +ambiguous semantics. + +When an exception group is raised in the try block, each :keyword:`!except*` +clause splits (see :meth:`~BaseExceptionGroup.split`) it into the subgroups +of matching and non-matching exceptions. If the matching subgroup is not empty, +it becomes the handled exception (the value returned from :func:`sys.exception`) +and assigned to the target of the :keyword:`!except*` clause (if there is one). +Then, the body of the :keyword:`!except*` clause executes. If the non-matching +subgroup is not empty, it is processed by the next :keyword:`!except*` in the +same manner. This continues until all exceptions in the group have been matched, +or the last :keyword:`!except*` clause has run. + +After all :keyword:`!except*` clauses execute, the group of unhandled exceptions +is merged with any exceptions that were raised or re-raised from within +:keyword:`!except*` clauses. This merged exception group propagates on.:: >>> try: ... raise ExceptionGroup("eg", @@ -356,37 +370,27 @@ one :keyword:`!except*` clause, the first that matches it. :: caught with nested (TypeError(2),) caught with nested (OSError(3), OSError(4)) + Exception Group Traceback (most recent call last): - | File "", line 2, in - | ExceptionGroup: eg + | File "", line 2, in + | raise ExceptionGroup("eg", + | [ValueError(1), TypeError(2), OSError(3), OSError(4)]) + | ExceptionGroup: eg (1 sub-exception) +-+---------------- 1 ---------------- | ValueError: 1 +------------------------------------ - -Any remaining exceptions that were not handled by any :keyword:`!except*` -clause are re-raised at the end, along with all exceptions that were -raised from within the :keyword:`!except*` clauses. If this list contains -more than one exception to reraise, they are combined into an exception -group. - -If the raised exception is not an exception group and its type matches -one of the :keyword:`!except*` clauses, it is caught and wrapped by an -exception group with an empty message string. :: +If the exception raised from the :keyword:`try` block is not an exception group +and its type matches one of the :keyword:`!except*` clauses, it is caught and +wrapped by an exception group with an empty message string. This ensures that the +type of the target ``e`` is consistently :exc:`BaseExceptionGroup`:: >>> try: ... raise BlockingIOError ... except* BlockingIOError as e: ... print(repr(e)) ... - ExceptionGroup('', (BlockingIOError())) + ExceptionGroup('', (BlockingIOError(),)) -An :keyword:`!except*` clause must have a matching expression; it cannot be ``except*:``. -Furthermore, this expression cannot contain exception group types, because that would -have ambiguous semantics. - -It is not possible to mix :keyword:`except` and :keyword:`!except*` -in the same :keyword:`try`. -The :keyword:`break`, :keyword:`continue`, and :keyword:`return` statements +:keyword:`break`, :keyword:`continue` and :keyword:`return` cannot appear in an :keyword:`!except*` clause. @@ -416,12 +420,14 @@ clauses. -------------------------- If :keyword:`!finally` is present, it specifies a 'cleanup' handler. The -:keyword:`try` clause is executed, including any :keyword:`except` and -:keyword:`else` clauses. If an exception occurs in any of the clauses and is -not handled, the exception is temporarily saved. The :keyword:`!finally` clause -is executed. If there is a saved exception it is re-raised at the end of the -:keyword:`!finally` clause. If the :keyword:`!finally` clause raises another -exception, the saved exception is set as the context of the new exception. +:keyword:`try` clause is executed, including any :keyword:`except` +and :keyword:`else ` clauses. +If an exception occurs in any of the clauses and is not handled, +the exception is temporarily saved. +The :keyword:`!finally` clause is executed. If there is a saved exception +it is re-raised at the end of the :keyword:`!finally` clause. +If the :keyword:`!finally` clause raises another exception, the saved exception +is set as the context of the new exception. If the :keyword:`!finally` clause executes a :keyword:`return`, :keyword:`break` or :keyword:`continue` statement, the saved exception is discarded. For example, this function returns 42. @@ -588,6 +594,7 @@ the items are surrounded by parentheses. For example:: statement. .. _match: +.. _case: The :keyword:`!match` statement =============================== @@ -608,9 +615,9 @@ The match statement is used for pattern matching. Syntax: .. productionlist:: python-grammar match_stmt: 'match' `subject_expr` ":" NEWLINE INDENT `case_block`+ DEDENT - subject_expr: `star_named_expression` "," `star_named_expressions`? - : | `named_expression` - case_block: 'case' `patterns` [`guard`] ":" `block` + subject_expr: `!star_named_expression` "," `!star_named_expressions`? + : | `!named_expression` + case_block: 'case' `patterns` [`guard`] ":" `!block` .. note:: This section uses single quotes to denote @@ -699,7 +706,7 @@ Guards .. index:: ! guard .. productionlist:: python-grammar - guard: "if" `named_expression` + guard: "if" `!named_expression` A ``guard`` (which is part of the ``case``) must succeed for code inside the ``case`` block to execute. It takes the form: :keyword:`if` followed by an @@ -1013,8 +1020,8 @@ subject value: items, as for a fixed-length sequence. .. note:: The length of the subject sequence is obtained via - :func:`len` (i.e. via the :meth:`__len__` protocol). This length may be - cached by the interpreter in a similar manner as + :func:`len` (i.e. via the :meth:`~object.__len__` protocol). + This length may be cached by the interpreter in a similar manner as :ref:`value patterns `. @@ -1065,8 +1072,8 @@ subject value: .. note:: Key-value pairs are matched using the two-argument form of the mapping subject's ``get()`` method. Matched key-value pairs must already be present - in the mapping, and not created on-the-fly via :meth:`__missing__` or - :meth:`~object.__getitem__`. + in the mapping, and not created on-the-fly via :meth:`~object.__missing__` + or :meth:`~object.__getitem__`. In simple terms ``{KEY1: P1, KEY2: P2, ... }`` matches only if all the following happens: diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 7af3457070b..d92972117a3 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -16,9 +16,8 @@ Objects, values and types single: data :dfn:`Objects` are Python's abstraction for data. All data in a Python program -is represented by objects or by relations between objects. (In a sense, and in -conformance to Von Neumann's model of a "stored program computer", code is also -represented by objects.) +is represented by objects or by relations between objects. Even code is +represented by objects. .. index:: pair: built-in function; id @@ -29,9 +28,6 @@ represented by objects.) single: mutable object single: immutable object -.. XXX it *is* now possible in some cases to change an object's - type, under certain controlled conditions - Every object has an identity, a type and a value. An object's *identity* never changes once it has been created; you may think of it as the object's address in memory. The :keyword:`is` operator compares the identity of two objects; the @@ -899,7 +895,6 @@ Attribute assignment updates the module's namespace dictionary, e.g., single: __loader__ (module attribute) single: __path__ (module attribute) single: __file__ (module attribute) - single: __cached__ (module attribute) single: __doc__ (module attribute) single: __annotations__ (module attribute) single: __annotate__ (module attribute) @@ -1048,43 +1043,28 @@ this approach. instead of :attr:`!module.__path__`. .. attribute:: module.__file__ -.. attribute:: module.__cached__ - :attr:`!__file__` and :attr:`!__cached__` are both optional attributes that + :attr:`!__file__` is an optional attribute that may or may not be set. Both attributes should be a :class:`str` when they are available. - :attr:`!__file__` indicates the pathname of the file from which the module - was loaded (if loaded from a file), or the pathname of the shared library - file for extension modules loaded dynamically from a shared library. - It might be missing for certain types of modules, such as C modules that are - statically linked into the interpreter, and the + An optional attribute, :attr:`!__file__` indicates the pathname of the file + from which the module was loaded (if loaded from a file), or the pathname of + the shared library file for extension modules loaded dynamically from a + shared library. It might be missing for certain types of modules, such as C + modules that are statically linked into the interpreter, and the :ref:`import system ` may opt to leave it unset if it has no semantic meaning (for example, a module loaded from a database). - If :attr:`!__file__` is set then the :attr:`!__cached__` attribute might - also be set, which is the path to any compiled version of - the code (for example, a byte-compiled file). The file does not need to exist - to set this attribute; the path can simply point to where the - compiled file *would* exist (see :pep:`3147`). - - Note that :attr:`!__cached__` may be set even if :attr:`!__file__` is not - set. However, that scenario is quite atypical. Ultimately, the - :term:`loader` is what makes use of the module spec provided by the - :term:`finder` (from which :attr:`!__file__` and :attr:`!__cached__` are - derived). So if a loader can load from a cached module but otherwise does - not load from a file, that atypical scenario may be appropriate. - - It is **strongly** recommended that you use - :attr:`module.__spec__.cached ` - instead of :attr:`!module.__cached__`. - .. deprecated-removed:: 3.13 3.15 - Setting :attr:`!__cached__` on a module while failing to set + Setting ``__cached__`` on a module while failing to set :attr:`!__spec__.cached` is deprecated. In Python 3.15, - :attr:`!__cached__` will cease to be set or taken into consideration by + ``__cached__`` will cease to be set or taken into consideration by the import system or standard library. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + Other writable attributes on module objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1185,6 +1165,7 @@ Special attributes single: __module__ (class attribute) single: __dict__ (class attribute) single: __bases__ (class attribute) + single: __base__ (class attribute) single: __doc__ (class attribute) single: __annotations__ (class attribute) single: __annotate__ (class attribute) @@ -1219,6 +1200,13 @@ Special attributes In most cases, for a class defined as ``class X(A, B, C)``, ``X.__bases__`` will be exactly equal to ``(A, B, C)``. + * - .. attribute:: type.__base__ + - .. impl-detail:: + + The single base class in the inheritance chain that is responsible + for the memory layout of instances. This attribute corresponds to + :c:member:`~PyTypeObject.tp_base` at the C level. + * - .. attribute:: type.__doc__ - The class's documentation string, or ``None`` if undefined. Not inherited by subclasses. @@ -1272,7 +1260,7 @@ Special attributes * - .. attribute:: type.__firstlineno__ - The line number of the first line of the class definition, including decorators. - Setting the :attr:`__module__` attribute removes the + Setting the :attr:`~type.__module__` attribute removes the :attr:`!__firstlineno__` item from the type's dictionary. .. versionadded:: 3.13 @@ -1638,6 +1626,7 @@ and are also passed to registered trace functions. single: f_locals (frame attribute) single: f_lasti (frame attribute) single: f_builtins (frame attribute) + single: f_generator (frame attribute) Special read-only attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1675,6 +1664,12 @@ Special read-only attributes (this is an index into the :term:`bytecode` string of the :ref:`code object `) + * - .. attribute:: frame.f_generator + - The :term:`generator` or :term:`coroutine` object that owns this frame, + or ``None`` if the frame is a normal function. + + .. versionadded:: 3.14 + .. index:: single: f_trace (frame attribute) single: f_trace_lines (frame attribute) @@ -1896,9 +1891,9 @@ falling back to :meth:`~object.__getitem__`). [#]_ When implementing a class that emulates any built-in type, it is important that the emulation only be implemented to the degree that it makes sense for the object being modelled. For example, some sequences may work well with retrieval -of individual elements, but extracting a slice may not make sense. (One example -of this is the :class:`~xml.dom.NodeList` interface in the W3C's Document -Object Model.) +of individual elements, but extracting a slice may not make sense. +(One example of this is the :ref:`NodeList ` interface +in the W3C's Document Object Model.) .. _customization: @@ -2351,6 +2346,9 @@ Customizing module attribute access single: __dir__ (module attribute) single: __class__ (module attribute) +.. method:: module.__getattr__ + module.__dir__ + Special names ``__getattr__`` and ``__dir__`` can be also used to customize access to module attributes. The ``__getattr__`` function at the module level should accept one argument which is the name of an attribute and return the @@ -2364,6 +2362,8 @@ The ``__dir__`` function should accept no arguments, and return an iterable of strings that represents the names accessible on module. If present, this function overrides the standard :func:`dir` search on a module. +.. attribute:: module.__class__ + For a more fine grained customization of the module behavior (setting attributes, properties, etc.), one can set the ``__class__`` attribute of a module object to a subclass of :class:`types.ModuleType`. For example:: @@ -2546,7 +2546,7 @@ instance dictionary. In contrast, non-data descriptors can be overridden by instances. Python methods (including those decorated with -:func:`@staticmethod ` and :func:`@classmethod `) are +:deco:`staticmethod` and :deco:`classmethod`) are implemented as non-data descriptors. Accordingly, instances can redefine and override methods. This allows individual instances to acquire behaviors that differ from other instances of the same class. @@ -2614,8 +2614,8 @@ Notes on using *__slots__*: descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a - class derived from a +* :exc:`TypeError` will be raised if *__slots__* other than *__dict__* and + *__weakref__* are defined for a class derived from a :c:member:`"variable-length" built-in type ` such as :class:`int`, :class:`bytes`, and :class:`tuple`. @@ -2640,6 +2640,10 @@ Notes on using *__slots__*: of the iterator's values. However, the *__slots__* attribute will be an empty iterator. +.. versionchanged:: 3.15 + Allowed defining the *__dict__* and *__weakref__* *__slots__* for any class. + + .. _class-customization: Customizing class creation @@ -2685,7 +2689,7 @@ class defining the method. .. versionadded:: 3.6 -When a class is created, :meth:`type.__new__` scans the class variables +When a class is created, :meth:`!type.__new__` scans the class variables and makes callbacks to those with a :meth:`~object.__set_name__` hook. .. method:: object.__set_name__(self, owner, name) @@ -2981,7 +2985,7 @@ class method ``__class_getitem__()``. When defined on a class, ``__class_getitem__()`` is automatically a class method. As such, there is no need for it to be decorated with - :func:`@classmethod` when it is defined. + :deco:`classmethod` when it is defined. The purpose of *__class_getitem__* @@ -3130,16 +3134,20 @@ objects. The :mod:`collections.abc` module provides a :term:`abstract base class` to help create those methods from a base set of :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, :meth:`~object.__delitem__`, and :meth:`!keys`. -Mutable sequences should provide methods :meth:`!append`, :meth:`!count`, -:meth:`!index`, :meth:`!extend`, :meth:`!insert`, :meth:`!pop`, :meth:`!remove`, -:meth:`!reverse` and :meth:`!sort`, like Python standard :class:`list` -objects. Finally, -sequence types should implement addition (meaning concatenation) and + +Mutable sequences should provide methods +:meth:`~sequence.append`, :meth:`~sequence.clear`, :meth:`~sequence.count`, +:meth:`~sequence.extend`, :meth:`~sequence.index`, :meth:`~sequence.insert`, +:meth:`~sequence.pop`, :meth:`~sequence.remove`, and :meth:`~sequence.reverse`, +like Python standard :class:`list` objects. +Finally, sequence types should implement addition (meaning concatenation) and multiplication (meaning repetition) by defining the methods :meth:`~object.__add__`, :meth:`~object.__radd__`, :meth:`~object.__iadd__`, :meth:`~object.__mul__`, :meth:`~object.__rmul__` and :meth:`~object.__imul__` described below; they should not define other numerical -operators. It is recommended that both mappings and sequences implement the +operators. + +It is recommended that both mappings and sequences implement the :meth:`~object.__contains__` method to allow efficient use of the ``in`` operator; for mappings, ``in`` should search the mapping's keys; for sequences, it should diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index cb6c524dd97..639c232571e 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -398,6 +398,192 @@ See also the description of the :keyword:`try` statement in section :ref:`try` and :keyword:`raise` statement in section :ref:`raise`. +.. _execcomponents: + +Runtime Components +================== + +General Computing Model +----------------------- + +Python's execution model does not operate in a vacuum. It runs on +a host machine and through that host's runtime environment, including +its operating system (OS), if there is one. When a program runs, +the conceptual layers of how it runs on the host look something +like this: + + | **host machine** + | **process** (global resources) + | **thread** (runs machine code) + +Each process represents a program running on the host. Think of each +process itself as the data part of its program. Think of the process' +threads as the execution part of the program. This distinction will +be important to understand the conceptual Python runtime. + +The process, as the data part, is the execution context in which the +program runs. It mostly consists of the set of resources assigned to +the program by the host, including memory, signals, file handles, +sockets, and environment variables. + +Processes are isolated and independent from one another. (The same +is true for hosts.) The host manages the process' access to its +assigned resources, in addition to coordinating between processes. + +Each thread represents the actual execution of the program's machine +code, running relative to the resources assigned to the program's +process. It's strictly up to the host how and when that execution +takes place. + +From the point of view of Python, a program always starts with exactly +one thread. However, the program may grow to run in multiple +simultaneous threads. Not all hosts support multiple threads per +process, but most do. Unlike processes, threads in a process are not +isolated and independent from one another. Specifically, all threads +in a process share all of the process' resources. + +The fundamental point of threads is that each one does *run* +independently, at the same time as the others. That may be only +conceptually at the same time ("concurrently") or physically +("in parallel"). Either way, the threads effectively run +at a non-synchronized rate. + +.. note:: + + That non-synchronized rate means none of the process' memory is + guaranteed to stay consistent for the code running in any given + thread. Thus multi-threaded programs must take care to coordinate + access to intentionally shared resources. Likewise, they must take + care to be absolutely diligent about not accessing any *other* + resources in multiple threads; otherwise two threads running at the + same time might accidentally interfere with each other's use of some + shared data. All this is true for both Python programs and the + Python runtime. + + The cost of this broad, unstructured requirement is the tradeoff for + the kind of raw concurrency that threads provide. The alternative + to the required discipline generally means dealing with + non-deterministic bugs and data corruption. + +Python Runtime Model +-------------------- + +The same conceptual layers apply to each Python program, with some +extra data layers specific to Python: + + | **host machine** + | **process** (global resources) + | Python global runtime (*state*) + | Python interpreter (*state*) + | **thread** (runs Python bytecode and "C-API") + | Python thread *state* + +At the conceptual level: when a Python program starts, it looks exactly +like that diagram, with one of each. The runtime may grow to include +multiple interpreters, and each interpreter may grow to include +multiple thread states. + +.. note:: + + A Python implementation won't necessarily implement the runtime + layers distinctly or even concretely. The only exception is places + where distinct layers are directly specified or exposed to users, + like through the :mod:`threading` module. + +.. note:: + + The initial interpreter is typically called the "main" interpreter. + Some Python implementations, like CPython, assign special roles + to the main interpreter. + + Likewise, the host thread where the runtime was initialized is known + as the "main" thread. It may be different from the process' initial + thread, though they are often the same. In some cases "main thread" + may be even more specific and refer to the initial thread state. + A Python runtime might assign specific responsibilities + to the main thread, such as handling signals. + +As a whole, the Python runtime consists of the global runtime state, +interpreters, and thread states. The runtime ensures all that state +stays consistent over its lifetime, particularly when used with +multiple host threads. + +The global runtime, at the conceptual level, is just a set of +interpreters. While those interpreters are otherwise isolated and +independent from one another, they may share some data or other +resources. The runtime is responsible for managing these global +resources safely. The actual nature and management of these resources +is implementation-specific. Ultimately, the external utility of the +global runtime is limited to managing interpreters. + +In contrast, an "interpreter" is conceptually what we would normally +think of as the (full-featured) "Python runtime". When machine code +executing in a host thread interacts with the Python runtime, it calls +into Python in the context of a specific interpreter. + +.. note:: + + The term "interpreter" here is not the same as the "bytecode + interpreter", which is what regularly runs in threads, executing + compiled Python code. + + In an ideal world, "Python runtime" would refer to what we currently + call "interpreter". However, it's been called "interpreter" at least + since introduced in 1997 (`CPython:a027efa5b`_). + + .. _CPython:a027efa5b: https://github.com/python/cpython/commit/a027efa5b + +Each interpreter completely encapsulates all of the non-process-global, +non-thread-specific state needed for the Python runtime to work. +Notably, the interpreter's state persists between uses. It includes +fundamental data like :data:`sys.modules`. The runtime ensures +multiple threads using the same interpreter will safely +share it between them. + +A Python implementation may support using multiple interpreters at the +same time in the same process. They are independent and isolated from +one another. For example, each interpreter has its own +:data:`sys.modules`. + +For thread-specific runtime state, each interpreter has a set of thread +states, which it manages, in the same way the global runtime contains +a set of interpreters. It can have thread states for as many host +threads as it needs. It may even have multiple thread states for +the same host thread, though that isn't as common. + +Each thread state, conceptually, has all the thread-specific runtime +data an interpreter needs to operate in one host thread. The thread +state includes the current raised exception and the thread's Python +call stack. It may include other thread-specific resources. + +.. note:: + + The term "Python thread" can sometimes refer to a thread state, but + normally it means a thread created using the :mod:`threading` module. + +Each thread state, over its lifetime, is always tied to exactly one +interpreter and exactly one host thread. It will only ever be used in +that thread and with that interpreter. + +Multiple thread states may be tied to the same host thread, whether for +different interpreters or even the same interpreter. However, for any +given host thread, only one of the thread states tied to it can be used +by the thread at a time. + +Thread states are isolated and independent from one another and don't +share any data, except for possibly sharing an interpreter and objects +or other resources belonging to that interpreter. + +Once a program is running, new Python threads can be created using the +:mod:`threading` module (on platforms and Python implementations that +support threads). Additional processes can be created using the +:mod:`os`, :mod:`subprocess`, and :mod:`multiprocessing` modules. +Interpreters can be created and used with the +:mod:`~concurrent.interpreters` module. Coroutines (async) can +be run using :mod:`asyncio` in each interpreter, typically only +in a single thread (often the main thread). + + .. rubric:: Footnotes .. [#] This limitation occurs because the code that is executed by these operations diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 9aca25e3214..165dfa69f88 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -174,7 +174,7 @@ Formally: .. grammar-snippet:: :group: python-grammar - strings: ( `STRING` | fstring)+ | tstring+ + strings: ( `STRING` | `fstring`)+ | `tstring`+ This feature is defined at the syntactical level, so it only works with literals. To concatenate string expressions at run time, the '+' operator may be used:: @@ -1938,8 +1938,9 @@ Conditional expressions conditional_expression: `or_test` ["if" `or_test` "else" `expression`] expression: `conditional_expression` | `lambda_expr` -Conditional expressions (sometimes called a "ternary operator") have the lowest -priority of all Python operations. +A conditional expression (sometimes called a "ternary operator") is an +alternative to the if-else statement. As it is an expression, it returns a value +and can appear as a sub-expression. The expression ``x if C else y`` first evaluates the condition, *C* rather than *x*. If *C* is true, *x* is evaluated and its value is returned; otherwise, *y* is diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index d772d1f5345..f50d02a0ef0 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -359,21 +359,16 @@ of what happens during the loading portion of import:: if spec.loader is None: # unsupported raise ImportError - if spec.origin is None and spec.submodule_search_locations is not None: - # namespace package - sys.modules[spec.name] = module - elif not hasattr(spec.loader, 'exec_module'): - module = spec.loader.load_module(spec.name) - else: - sys.modules[spec.name] = module + + sys.modules[spec.name] = module + try: + spec.loader.exec_module(module) + except BaseException: try: - spec.loader.exec_module(module) - except BaseException: - try: - del sys.modules[spec.name] - except KeyError: - pass - raise + del sys.modules[spec.name] + except KeyError: + pass + raise return sys.modules[spec.name] Note the following details: @@ -408,7 +403,10 @@ Note the following details: .. versionchanged:: 3.4 The import system has taken over the boilerplate responsibilities of loaders. These were previously performed by the - :meth:`importlib.abc.Loader.load_module` method. + ``importlib.abc.Loader.load_module`` method. + +.. versionchanged:: 3.15 + The ``load_module`` method is no longer used. Loaders ------- @@ -443,7 +441,7 @@ import machinery will create the new module itself. The :meth:`~importlib.abc.Loader.create_module` method of loaders. .. versionchanged:: 3.4 - The :meth:`~importlib.abc.Loader.load_module` method was replaced by + The ``importlib.abc.Loader.load_module`` method was replaced by :meth:`~importlib.abc.Loader.exec_module` and the import machinery assumed all the boilerplate responsibilities of loading. diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index e320eedfa67..046c759854c 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -10,12 +10,76 @@ Lexical analysis A Python program is read by a *parser*. Input to the parser is a stream of :term:`tokens `, generated by the *lexical analyzer* (also known as the *tokenizer*). -This chapter describes how the lexical analyzer breaks a file into tokens. +This chapter describes how the lexical analyzer produces these tokens. -Python reads program text as Unicode code points; the encoding of a source file -can be given by an encoding declaration and defaults to UTF-8, see :pep:`3120` -for details. If the source file cannot be decoded, a :exc:`SyntaxError` is -raised. +The lexical analyzer determines the program text's :ref:`encoding ` +(UTF-8 by default), and decodes the text into +:ref:`source characters `. +If the text cannot be decoded, a :exc:`SyntaxError` is raised. + +Next, the lexical analyzer uses the source characters to generate a stream of tokens. +The type of a generated token generally depends on the next source character to +be processed. Similarly, other special behavior of the analyzer depends on +the first source character that hasn't yet been processed. +The following table gives a quick summary of these source characters, +with links to sections that contain more information. + +.. list-table:: + :header-rows: 1 + + * - Character + - Next token (or other relevant documentation) + + * - * space + * tab + * formfeed + - * :ref:`Whitespace ` + + * - * CR, LF + - * :ref:`New line ` + * :ref:`Indentation ` + + * - * backslash (``\``) + - * :ref:`Explicit line joining ` + * (Also significant in :ref:`string escape sequences `) + + * - * hash (``#``) + - * :ref:`Comment ` + + * - * quote (``'``, ``"``) + - * :ref:`String literal ` + + * - * ASCII letter (``a``-``z``, ``A``-``Z``) + * non-ASCII character + - * :ref:`Name ` + * Prefixed :ref:`string or bytes literal ` + + * - * underscore (``_``) + - * :ref:`Name ` + * (Can also be part of :ref:`numeric literals `) + + * - * number (``0``-``9``) + - * :ref:`Numeric literal ` + + * - * dot (``.``) + - * :ref:`Numeric literal ` + * :ref:`Operator ` + + * - * question mark (``?``) + * dollar (``$``) + * + .. (the following uses zero-width space characters to render + .. a literal backquote) + + backquote (``​`​``) + * control character + - * Error (outside string literals and comments) + + * - * other printing character + - * :ref:`Operator or delimiter ` + + * - * end of file + - * :ref:`End marker ` .. _line-structure: @@ -120,6 +184,8 @@ If an encoding is declared, the encoding name must be recognized by Python encoding is used for all lexical analysis, including string literals, comments and identifiers. +.. _lexical-source-character: + All lexical analysis, including string literals, comments and identifiers, works on Unicode text decoded using the source encoding. Any Unicode code point, except the NUL control character, can appear in @@ -279,7 +345,15 @@ Whitespace between tokens Except at the beginning of a logical line or in string literals, the whitespace characters space, tab and formfeed can be used interchangeably to separate -tokens. Whitespace is needed between two tokens only if their concatenation +tokens: + +.. grammar-snippet:: + :group: python-grammar + + whitespace: ' ' | tab | formfeed + + +Whitespace is needed between two tokens only if their concatenation could otherwise be interpreted as a different token. For example, ``ab`` is one token, but ``a b`` is two tokens. However, ``+a`` and ``+ a`` both produce two tokens, ``+`` and ``a``, as ``+a`` is not a valid token. @@ -320,73 +394,29 @@ Names (identifiers and keywords) :data:`~token.NAME` tokens represent *identifiers*, *keywords*, and *soft keywords*. -Within the ASCII range (U+0001..U+007F), the valid characters for names -include the uppercase and lowercase letters (``A-Z`` and ``a-z``), -the underscore ``_`` and, except for the first character, the digits -``0`` through ``9``. +Names are composed of the following characters: + +* uppercase and lowercase letters (``A-Z`` and ``a-z``), +* the underscore (``_``), +* digits (``0`` through ``9``), which cannot appear as the first character, and +* non-ASCII characters. Valid names may only contain "letter-like" and + "digit-like" characters; see :ref:`lexical-names-nonascii` for details. Names must contain at least one character, but have no upper length limit. Case is significant. -Besides ``A-Z``, ``a-z``, ``_`` and ``0-9``, names can also use "letter-like" -and "number-like" characters from outside the ASCII range, as detailed below. - -All identifiers are converted into the `normalization form`_ NFKC while -parsing; comparison of identifiers is based on NFKC. - -Formally, the first character of a normalized identifier must belong to the -set ``id_start``, which is the union of: - -* Unicode category ```` - uppercase letters (includes ``A`` to ``Z``) -* Unicode category ```` - lowercase letters (includes ``a`` to ``z``) -* Unicode category ```` - titlecase letters -* Unicode category ```` - modifier letters -* Unicode category ```` - other letters -* Unicode category ```` - letter numbers -* {``"_"``} - the underscore -* ```` - an explicit set of characters in `PropList.txt`_ - to support backwards compatibility - -The remaining characters must belong to the set ``id_continue``, which is the -union of: - -* all characters in ``id_start`` -* Unicode category ```` - decimal numbers (includes ``0`` to ``9``) -* Unicode category ```` - connector punctuations -* Unicode category ```` - nonspacing marks -* Unicode category ```` - spacing combining marks -* ```` - another explicit set of characters in - `PropList.txt`_ to support backwards compatibility - -Unicode categories use the version of the Unicode Character Database as -included in the :mod:`unicodedata` module. - -These sets are based on the Unicode standard annex `UAX-31`_. -See also :pep:`3131` for further details. - -Even more formally, names are described by the following lexical definitions: +Formally, names are described by the following lexical definitions: .. grammar-snippet:: :group: python-grammar - NAME: `xid_start` `xid_continue`* - id_start: | | | | | | "_" | - id_continue: `id_start` | | | | | - xid_start: - xid_continue: - identifier: <`NAME`, except keywords> + NAME: `name_start` `name_continue`* + name_start: "a"..."z" | "A"..."Z" | "_" | + name_continue: name_start | "0"..."9" + identifier: <`NAME`, except keywords> -A non-normative listing of all valid identifier characters as defined by -Unicode is available in the `DerivedCoreProperties.txt`_ file in the Unicode -Character Database. - - -.. _UAX-31: https://www.unicode.org/reports/tr31/ -.. _PropList.txt: https://www.unicode.org/Public/16.0.0/ucd/PropList.txt -.. _DerivedCoreProperties.txt: https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt -.. _normalization form: https://www.unicode.org/reports/tr15/#Norm_Forms +Note that not all names matched by this grammar are valid; see +:ref:`lexical-names-nonascii` for details. .. _keywords: @@ -489,6 +519,95 @@ characters: :ref:`atom-identifiers`. +.. _lexical-names-nonascii: + +Non-ASCII characters in names +----------------------------- + +Names that contain non-ASCII characters need additional normalization +and validation beyond the rules and grammar explained +:ref:`above `. +For example, ``ř_1``, ``蛇``, or ``साँप`` are valid names, but ``r〰2``, +``€``, or ``🐍`` are not. + +This section explains the exact rules. + +All names are converted into the `normalization form`_ NFKC while parsing. +This means that, for example, some typographic variants of characters are +converted to their "basic" form. For example, ``fiⁿₐˡᵢᶻₐᵗᵢᵒₙ`` normalizes to +``finalization``, so Python treats them as the same name:: + + >>> fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = 3 + >>> finalization + 3 + +.. note:: + + Normalization is done at the lexical level only. + Run-time functions that take names as *strings* generally do not normalize + their arguments. + For example, the variable defined above is accessible at run time in the + :func:`globals` dictionary as ``globals()["finalization"]`` but not + ``globals()["fiⁿₐˡᵢᶻₐᵗᵢᵒₙ"]``. + +Similarly to how ASCII-only names must contain only letters, digits and +the underscore, and cannot start with a digit, a valid name must +start with a character in the "letter-like" set ``xid_start``, +and the remaining characters must be in the "letter- and digit-like" set +``xid_continue``. + +These sets based on the *XID_Start* and *XID_Continue* sets as defined by the +Unicode standard annex `UAX-31`_. +Python's ``xid_start`` additionally includes the underscore (``_``). +Note that Python does not necessarily conform to `UAX-31`_. + +A non-normative listing of characters in the *XID_Start* and *XID_Continue* +sets as defined by Unicode is available in the `DerivedCoreProperties.txt`_ +file in the Unicode Character Database. +For reference, the construction rules for the ``xid_*`` sets are given below. + +The set ``id_start`` is defined as the union of: + +* Unicode category ```` - uppercase letters (includes ``A`` to ``Z``) +* Unicode category ```` - lowercase letters (includes ``a`` to ``z``) +* Unicode category ```` - titlecase letters +* Unicode category ```` - modifier letters +* Unicode category ```` - other letters +* Unicode category ```` - letter numbers +* {``"_"``} - the underscore +* ```` - an explicit set of characters in `PropList.txt`_ + to support backwards compatibility + +The set ``xid_start`` then closes this set under NFKC normalization, by +removing all characters whose normalization is not of the form +``id_start id_continue*``. + +The set ``id_continue`` is defined as the union of: + +* ``id_start`` (see above) +* Unicode category ```` - decimal numbers (includes ``0`` to ``9``) +* Unicode category ```` - connector punctuations +* Unicode category ```` - nonspacing marks +* Unicode category ```` - spacing combining marks +* ```` - another explicit set of characters in + `PropList.txt`_ to support backwards compatibility + +Again, ``xid_continue`` closes this set under NFKC normalization. + +Unicode categories use the version of the Unicode Character Database as +included in the :mod:`unicodedata` module. + +.. _UAX-31: https://www.unicode.org/reports/tr31/ +.. _PropList.txt: https://www.unicode.org/Public/17.0.0/ucd/PropList.txt +.. _DerivedCoreProperties.txt: https://www.unicode.org/Public/17.0.0/ucd/DerivedCoreProperties.txt +.. _normalization form: https://www.unicode.org/reports/tr15/#Norm_Forms + +.. seealso:: + + * :pep:`3131` -- Supporting Non-ASCII Identifiers + * :pep:`672` -- Unicode-related Security Considerations for Python + + .. _literals: Literals @@ -628,10 +747,10 @@ to indicate that an ending quote ends the literal. STRING: [`stringprefix`] (`stringcontent`) stringprefix: <("r" | "u" | "b" | "br" | "rb"), case-insensitive> stringcontent: - | "'" ( !"'" `stringitem`)* "'" - | '"' ( !'"' `stringitem`)* '"' | "'''" ( !"'''" `longstringitem`)* "'''" | '"""' ( !'"""' `longstringitem`)* '"""' + | "'" ( !"'" `stringitem`)* "'" + | '"' ( !'"' `stringitem`)* '"' stringitem: `stringchar` | `stringescapeseq` stringchar: longstringitem: `stringitem` | newline @@ -793,7 +912,7 @@ with the given *name*:: This sequence cannot appear in :ref:`bytes literals `. .. versionchanged:: 3.3 - Support for `name aliases `__ + Support for `name aliases `__ has been added. .. _string-escape-long-hex: @@ -921,124 +1040,59 @@ f-strings --------- .. versionadded:: 3.6 +.. versionchanged:: 3.7 + The :keyword:`await` and :keyword:`async for` can be used in expressions + within f-strings. +.. versionchanged:: 3.8 + Added the debug specifier (``=``) +.. versionchanged:: 3.12 + Many restrictions on expressions within f-strings have been removed. + Notably, nested strings, comments, and backslashes are now permitted. A :dfn:`formatted string literal` or :dfn:`f-string` is a string literal -that is prefixed with '``f``' or '``F``'. These strings may contain -replacement fields, which are expressions delimited by curly braces ``{}``. -While other string literals always have a constant value, formatted strings -are really expressions evaluated at run time. +that is prefixed with '``f``' or '``F``'. +Unlike other string literals, f-strings do not have a constant value. +They may contain *replacement fields* delimited by curly braces ``{}``. +Replacement fields contain expressions which are evaluated at run time. +For example:: -Escape sequences are decoded like in ordinary string literals (except when -a literal is also marked as a raw string). After decoding, the grammar -for the contents of the string is: + >>> who = 'nobody' + >>> nationality = 'Spanish' + >>> f'{who.title()} expects the {nationality} Inquisition!' + 'Nobody expects the Spanish Inquisition!' -.. productionlist:: python-grammar - f_string: (`literal_char` | "{{" | "}}" | `replacement_field`)* - replacement_field: "{" `f_expression` ["="] ["!" `conversion`] [":" `format_spec`] "}" - f_expression: (`conditional_expression` | "*" `or_expr`) - : ("," `conditional_expression` | "," "*" `or_expr`)* [","] - : | `yield_expression` - conversion: "s" | "r" | "a" - format_spec: (`literal_char` | `replacement_field`)* - literal_char: +Any doubled curly braces (``{{`` or ``}}``) outside replacement fields +are replaced with the corresponding single curly brace:: -The parts of the string outside curly braces are treated literally, -except that any doubled curly braces ``'{{'`` or ``'}}'`` are replaced -with the corresponding single curly brace. A single opening curly -bracket ``'{'`` marks a replacement field, which starts with a -Python expression. To display both the expression text and its value after -evaluation, (useful in debugging), an equal sign ``'='`` may be added after the -expression. A conversion field, introduced by an exclamation point ``'!'`` may -follow. A format specifier may also be appended, introduced by a colon ``':'``. -A replacement field ends with a closing curly bracket ``'}'``. + >>> print(f'{{...}}') + {...} + +Other characters outside replacement fields are treated like in ordinary +string literals. +This means that escape sequences are decoded (except when a literal is +also marked as a raw string), and newlines are possible in triple-quoted +f-strings:: + + >>> name = 'Galahad' + >>> favorite_color = 'blue' + >>> print(f'{name}:\t{favorite_color}') + Galahad: blue + >>> print(rf"C:\Users\{name}") + C:\Users\Galahad + >>> print(f'''Three shall be the number of the counting + ... and the number of the counting shall be three.''') + Three shall be the number of the counting + and the number of the counting shall be three. Expressions in formatted string literals are treated like regular -Python expressions surrounded by parentheses, with a few exceptions. -An empty expression is not allowed, and both :keyword:`lambda` and -assignment expressions ``:=`` must be surrounded by explicit parentheses. +Python expressions. Each expression is evaluated in the context where the formatted string literal -appears, in order from left to right. Replacement expressions can contain -newlines in both single-quoted and triple-quoted f-strings and they can contain -comments. Everything that comes after a ``#`` inside a replacement field -is a comment (even closing braces and quotes). In that case, replacement fields -must be closed in a different line. - -.. code-block:: text - - >>> f"abc{a # This is a comment }" - ... + 3}" - 'abc5' - -.. versionchanged:: 3.7 - Prior to Python 3.7, an :keyword:`await` expression and comprehensions - containing an :keyword:`async for` clause were illegal in the expressions - in formatted string literals due to a problem with the implementation. - -.. versionchanged:: 3.12 - Prior to Python 3.12, comments were not allowed inside f-string replacement - fields. - -When the equal sign ``'='`` is provided, the output will have the expression -text, the ``'='`` and the evaluated value. Spaces after the opening brace -``'{'``, within the expression and after the ``'='`` are all retained in the -output. By default, the ``'='`` causes the :func:`repr` of the expression to be -provided, unless there is a format specified. When a format is specified it -defaults to the :func:`str` of the expression unless a conversion ``'!r'`` is -declared. - -.. versionadded:: 3.8 - The equal sign ``'='``. - -If a conversion is specified, the result of evaluating the expression -is converted before formatting. Conversion ``'!s'`` calls :func:`str` on -the result, ``'!r'`` calls :func:`repr`, and ``'!a'`` calls :func:`ascii`. - -The result is then formatted using the :func:`format` protocol. The -format specifier is passed to the :meth:`~object.__format__` method of the -expression or conversion result. An empty string is passed when the -format specifier is omitted. The formatted result is then included in -the final value of the whole string. - -Top-level format specifiers may include nested replacement fields. These nested -fields may include their own conversion fields and :ref:`format specifiers -`, but may not include more deeply nested replacement fields. The -:ref:`format specifier mini-language ` is the same as that used by -the :meth:`str.format` method. - -Formatted string literals may be concatenated, but replacement fields -cannot be split across literals. - -Some examples of formatted string literals:: - - >>> name = "Fred" - >>> f"He said his name is {name!r}." - "He said his name is 'Fred'." - >>> f"He said his name is {repr(name)}." # repr() is equivalent to !r - "He said his name is 'Fred'." - >>> width = 10 - >>> precision = 4 - >>> value = decimal.Decimal("12.34567") - >>> f"result: {value:{width}.{precision}}" # nested fields - 'result: 12.35' - >>> today = datetime(year=2017, month=1, day=27) - >>> f"{today:%B %d, %Y}" # using date format specifier - 'January 27, 2017' - >>> f"{today=:%B %d, %Y}" # using date format specifier and debugging - 'today=January 27, 2017' - >>> number = 1024 - >>> f"{number:#0x}" # using integer format specifier - '0x400' - >>> foo = "bar" - >>> f"{ foo = }" # preserves whitespace - " foo = 'bar'" - >>> line = "The mill's closed" - >>> f"{line = }" - 'line = "The mill\'s closed"' - >>> f"{line = :20}" - "line = The mill's closed " - >>> f"{line = !r:20}" - 'line = "The mill\'s closed" ' +appears, in order from left to right. +An empty expression is not allowed, and both :keyword:`lambda` and +assignment expressions ``:=`` must be surrounded by explicit parentheses:: + >>> f'{(half := 1/2)}, {half * 42}' + '0.5, 21.0' Reusing the outer f-string quoting type inside a replacement field is permitted:: @@ -1047,10 +1101,6 @@ permitted:: >>> f"abc {a["x"]} def" 'abc 2 def' -.. versionchanged:: 3.12 - Prior to Python 3.12, reuse of the same quoting type of the outer f-string - inside a replacement field was not possible. - Backslashes are also allowed in replacement fields and are evaluated the same way as in any other context:: @@ -1061,23 +1111,84 @@ way as in any other context:: b c -.. versionchanged:: 3.12 - Prior to Python 3.12, backslashes were not permitted inside an f-string - replacement field. +It is possible to nest f-strings:: -Formatted string literals cannot be used as docstrings, even if they do not -include expressions. + >>> name = 'world' + >>> f'Repeated:{f' hello {name}' * 3}' + 'Repeated: hello world hello world hello world' -:: +Portable Python programs should not use more than 5 levels of nesting. + +.. impl-detail:: + + CPython does not limit nesting of f-strings. + +Replacement expressions can contain newlines in both single-quoted and +triple-quoted f-strings and they can contain comments. +Everything that comes after a ``#`` inside a replacement field +is a comment (even closing braces and quotes). +This means that replacement fields with comments must be closed in a +different line: + +.. code-block:: text + + >>> a = 2 + >>> f"abc{a # This comment }" continues until the end of the line + ... + 3}" + 'abc5' + +After the expression, replacement fields may optionally contain: + +* a *debug specifier* -- an equal sign (``=``), optionally surrounded by + whitespace on one or both sides; +* a *conversion specifier* -- ``!s``, ``!r`` or ``!a``; and/or +* a *format specifier* prefixed with a colon (``:``). + +See the :ref:`Standard Library section on f-strings ` +for details on how these fields are evaluated. + +As that section explains, *format specifiers* are passed as the second argument +to the :func:`format` function to format a replacement field value. +For example, they can be used to specify a field width and padding characters +using the :ref:`Format Specification Mini-Language `:: + + >>> number = 14.3 + >>> f'{number:20.7f}' + ' 14.3000000' + +Top-level format specifiers may include nested replacement fields:: + + >>> field_size = 20 + >>> precision = 7 + >>> f'{number:{field_size}.{precision}f}' + ' 14.3000000' + +These nested fields may include their own conversion fields and +:ref:`format specifiers `:: + + >>> number = 3 + >>> f'{number:{field_size}}' + ' 3' + >>> f'{number:{field_size:05}}' + '00000000000000000003' + +However, these nested fields may not include more deeply nested replacement +fields. + +Formatted string literals cannot be used as :term:`docstrings `, +even if they do not include expressions:: >>> def foo(): ... f"Not a docstring" ... - >>> foo.__doc__ is None - True + >>> print(foo.__doc__) + None -See also :pep:`498` for the proposal that added formatted string literals, -and :meth:`str.format`, which uses a related format string mechanism. +.. seealso:: + + * :pep:`498` -- Literal String Interpolation + * :pep:`701` -- Syntactic formalization of f-strings + * :meth:`str.format`, which uses a related format string mechanism. .. _t-strings: @@ -1090,36 +1201,99 @@ t-strings A :dfn:`template string literal` or :dfn:`t-string` is a string literal that is prefixed with '``t``' or '``T``'. -These strings follow the same syntax and evaluation rules as -:ref:`formatted string literals `, with the following differences: +These strings follow the same syntax rules as +:ref:`formatted string literals `. +For differences in evaluation rules, see the +:ref:`Standard Library section on t-strings ` -* Rather than evaluating to a ``str`` object, template string literals evaluate - to a :class:`string.templatelib.Template` object. -* The :func:`format` protocol is not used. - Instead, the format specifier and conversions (if any) are passed to - a new :class:`~string.templatelib.Interpolation` object that is created - for each evaluated expression. - It is up to code that processes the resulting :class:`~string.templatelib.Template` - object to decide how to handle format specifiers and conversions. +Formal grammar for f-strings +---------------------------- -* Format specifiers containing nested replacement fields are evaluated eagerly, - prior to being passed to the :class:`~string.templatelib.Interpolation` object. - For instance, an interpolation of the form ``{amount:.{precision}f}`` will - evaluate the inner expression ``{precision}`` to determine the value of the - ``format_spec`` attribute. - If ``precision`` were to be ``2``, the resulting format specifier - would be ``'.2f'``. +F-strings are handled partly by the :term:`lexical analyzer`, which produces the +tokens :py:data:`~token.FSTRING_START`, :py:data:`~token.FSTRING_MIDDLE` +and :py:data:`~token.FSTRING_END`, and partly by the parser, which handles +expressions in the replacement field. +The exact way the work is split is a CPython implementation detail. -* When the equals sign ``'='`` is provided in an interpolation expression, - the text of the expression is appended to the literal string that precedes - the relevant interpolation. - This includes the equals sign and any surrounding whitespace. - The :class:`!Interpolation` instance for the expression will be created as - normal, except that :attr:`~string.templatelib.Interpolation.conversion` will - be set to '``r``' (:func:`repr`) by default. - If an explicit conversion or format specifier are provided, - this will override the default behaviour. +Correspondingly, the f-string grammar is a mix of +:ref:`lexical and syntactic definitions `. + +Whitespace is significant in these situations: + +* There may be no whitespace in :py:data:`~token.FSTRING_START` (between + the prefix and quote). +* Whitespace in :py:data:`~token.FSTRING_MIDDLE` is part of the literal + string contents. +* In ``fstring_replacement_field``, if ``f_debug_specifier`` is present, + all whitespace after the opening brace until the ``f_debug_specifier``, + as well as whitespace immediately following ``f_debug_specifier``, + is retained as part of the expression. + + .. impl-detail:: + + The expression is not handled in the tokenization phase; it is + retrieved from the source code using locations of the ``{`` token + and the token after ``=``. + + +The ``FSTRING_MIDDLE`` definition uses +:ref:`negative lookaheads ` (``!``) +to indicate special characters (backslash, newline, ``{``, ``}``) and +sequences (``f_quote``). + +.. grammar-snippet:: + :group: python-grammar + + fstring: `FSTRING_START` `fstring_middle`* `FSTRING_END` + + FSTRING_START: `fstringprefix` ("'" | '"' | "'''" | '"""') + FSTRING_END: `f_quote` + fstringprefix: <("f" | "fr" | "rf"), case-insensitive> + f_debug_specifier: '=' + f_quote: + + fstring_middle: + | `fstring_replacement_field` + | `FSTRING_MIDDLE` + FSTRING_MIDDLE: + | (!"\" !`newline` !'{' !'}' !`f_quote`) `source_character` + | `stringescapeseq` + | "{{" + | "}}" + | + fstring_replacement_field: + | '{' `f_expression` [`f_debug_specifier`] [`fstring_conversion`] + [`fstring_full_format_spec`] '}' + fstring_conversion: + | "!" ("s" | "r" | "a") + fstring_full_format_spec: + | ':' `fstring_format_spec`* + fstring_format_spec: + | `FSTRING_MIDDLE` + | `fstring_replacement_field` + f_expression: + | ','.(`conditional_expression` | "*" `or_expr`)+ [","] + | `yield_expression` + +.. note:: + + In the above grammar snippet, the ``f_quote`` and ``FSTRING_MIDDLE`` rules + are context-sensitive -- they depend on the contents of ``FSTRING_START`` + of the nearest enclosing ``fstring``. + + Constructing a more traditional formal grammar from this template is left + as an exercise for the reader. + +The grammar for t-strings is identical to the one for f-strings, with *t* +instead of *f* at the beginning of rule and token names and in the prefix. + +.. grammar-snippet:: + :group: python-grammar + + tstring: TSTRING_START tstring_middle* TSTRING_END + + .. _numbers: @@ -1242,8 +1416,8 @@ The parts are separated by a decimal point, ``.``:: 2.71828 4.0 -Unlike in integer literals, leading zeros are allowed in the numeric parts. -For example, ``077.010`` is legal, and denotes the same number as ``77.10``. +Unlike in integer literals, leading zeros are allowed. +For example, ``077.010`` is legal, and denotes the same number as ``77.01``. As in integer literals, single underscores may occur between digits to help readability:: @@ -1351,67 +1525,62 @@ Formally, imaginary literals are described by the following lexical definition: imagnumber: (`floatnumber` | `digitpart`) ("j" | "J") -.. _operators: - -Operators -========= - -.. index:: single: operators - -The following tokens are operators: - -.. code-block:: none - - - + - * ** / // % @ - << >> & | ^ ~ := - < > <= >= == != - - .. _delimiters: - -Delimiters -========== - -.. index:: single: delimiters - -The following tokens serve as delimiters in the grammar: - -.. code-block:: none - - ( ) [ ] { } - , : ! . ; @ = - -The period can also occur in floating-point and imaginary literals. - +.. _operators: .. _lexical-ellipsis: -A sequence of three periods has a special meaning as an -:py:data:`Ellipsis` literal: +Operators and delimiters +======================== -.. code-block:: none +.. index:: + single: operators + single: delimiters - ... +The following grammar defines :dfn:`operator` and :dfn:`delimiter` tokens, +that is, the generic :data:`~token.OP` token type. +A :ref:`list of these tokens and their names ` +is also available in the :mod:`!token` module documentation. -The following *augmented assignment operators* serve -lexically as delimiters, but also perform an operation: +.. grammar-snippet:: + :group: python-grammar -.. code-block:: none + OP: + | assignment_operator + | bitwise_operator + | comparison_operator + | enclosing_delimiter + | other_delimiter + | arithmetic_operator + | "..." + | other_op - -> += -= *= /= //= %= - @= &= |= ^= >>= <<= **= + assignment_operator: "+=" | "-=" | "*=" | "**=" | "/=" | "//=" | "%=" | + "&=" | "|=" | "^=" | "<<=" | ">>=" | "@=" | ":=" + bitwise_operator: "&" | "|" | "^" | "~" | "<<" | ">>" + comparison_operator: "<=" | ">=" | "<" | ">" | "==" | "!=" + enclosing_delimiter: "(" | ")" | "[" | "]" | "{" | "}" + other_delimiter: "," | ":" | "!" | ";" | "=" | "->" + arithmetic_operator: "+" | "-" | "**" | "*" | "//" | "/" | "%" + other_op: "." | "@" -The following printing ASCII characters have special meaning as part of other -tokens or are otherwise significant to the lexical analyzer: +.. note:: -.. code-block:: none + Generally, *operators* are used to combine :ref:`expressions `, + while *delimiters* serve other purposes. + However, there is no clear, formal distinction between the two categories. - ' " # \ + Some tokens can serve as either operators or delimiters, depending on usage. + For example, ``*`` is both the multiplication operator and a delimiter used + for sequence unpacking, and ``@`` is both the matrix multiplication and + a delimiter that introduces decorators. -The following printing ASCII characters are not used in Python. Their -occurrence outside string literals and comments is an unconditional error: + For some tokens, the distinction is unclear. + For example, some people consider ``.``, ``(``, and ``)`` to be delimiters, while others + see the :py:func:`getattr` operator and the function call operator(s). -.. code-block:: none + Some of Python's operators, like ``and``, ``or``, and ``not in``, use + :ref:`keyword ` tokens rather than "symbols" (operator tokens). - $ ? ` +A sequence of three consecutive periods (``...``) has a special +meaning as an :py:data:`Ellipsis` literal. diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 3f2bcb2a60e..9c022570e7e 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -465,8 +465,8 @@ Deletion of a target list recursively deletes each target, from left to right. Deletion of a name removes the binding of that name from the local or global namespace, depending on whether the name occurs in a :keyword:`global` statement -in the same code block. If the name is unbound, a :exc:`NameError` exception -will be raised. +in the same code block. Trying to delete an unbound name raises a +:exc:`NameError` exception. .. index:: pair: attribute; deletion @@ -831,6 +831,9 @@ where the :keyword:`import` statement occurs. .. index:: single: __all__ (optional module attribute) +.. attribute:: module.__all__ + :no-typesetting: + The *public names* defined by a module are determined by checking the module's namespace for a variable named ``__all__``; if defined, it must be a sequence of strings which are names defined or imported by that module. The names diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 7b7286429a1..716772b7f28 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -7,11 +7,11 @@ # won't suddenly cause build failures. Updating the version is fine as long # as no warnings are raised by doing so. # Keep this version in sync with ``Doc/conf.py``. -sphinx~=8.2.0 +sphinx~=9.0.0 blurb -sphinxext-opengraph~=0.12.0 +sphinxext-opengraph~=0.13.0 sphinx-notfound-page~=1.0.0 # The theme used by the documentation is stored separately, so we need diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 31b2e567f11..54b92f1172e 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -4,14 +4,10 @@ Doc/c-api/descriptor.rst Doc/c-api/float.rst -Doc/c-api/init.rst Doc/c-api/init_config.rst Doc/c-api/intro.rst -Doc/c-api/module.rst Doc/c-api/stable.rst -Doc/c-api/type.rst Doc/c-api/typeobj.rst -Doc/extending/extending.rst Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/email.charset.rst @@ -27,46 +23,26 @@ Doc/library/multiprocessing.rst Doc/library/optparse.rst Doc/library/os.rst Doc/library/pickletools.rst -Doc/library/profile.rst Doc/library/pyexpat.rst -Doc/library/resource.rst Doc/library/select.rst -Doc/library/signal.rst -Doc/library/smtplib.rst Doc/library/socket.rst Doc/library/ssl.rst -Doc/library/stdtypes.rst -Doc/library/subprocess.rst Doc/library/termios.rst Doc/library/test.rst Doc/library/tkinter.rst Doc/library/tkinter.scrolledtext.rst Doc/library/tkinter.ttk.rst Doc/library/unittest.mock.rst -Doc/library/unittest.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst Doc/library/wsgiref.rst Doc/library/xml.dom.minidom.rst Doc/library/xml.dom.pulldom.rst Doc/library/xml.dom.rst -Doc/library/xml.sax.handler.rst Doc/library/xml.sax.reader.rst Doc/library/xml.sax.rst Doc/library/xmlrpc.client.rst Doc/library/xmlrpc.server.rst -Doc/library/zlib.rst -Doc/reference/compound_stmts.rst -Doc/reference/datamodel.rst -Doc/using/windows.rst Doc/whatsnew/2.4.rst Doc/whatsnew/2.5.rst Doc/whatsnew/2.6.rst -Doc/whatsnew/2.7.rst -Doc/whatsnew/3.3.rst -Doc/whatsnew/3.4.rst -Doc/whatsnew/3.5.rst -Doc/whatsnew/3.6.rst -Doc/whatsnew/3.7.rst -Doc/whatsnew/3.8.rst -Doc/whatsnew/3.10.rst diff --git a/Doc/tools/check-warnings.py b/Doc/tools/check-warnings.py index c686eecf8d9..2f2bb9e2dcb 100644 --- a/Doc/tools/check-warnings.py +++ b/Doc/tools/check-warnings.py @@ -15,7 +15,7 @@ from pathlib import Path from typing import TextIO # Fail if NEWS nit found before this line number -NEWS_NIT_THRESHOLD = 1700 +NEWS_NIT_THRESHOLD = 8550 # Exclude these whether they're dirty or clean, # because they trigger a rebuild of dirty files. diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 089614a1f6c..e04a5f144c4 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -154,7 +154,10 @@ def add_annotations(app: Sphinx, doctree: nodes.document) -> None: node.insert(0, annotation) -def _stable_abi_annotation(record: StableABIEntry) -> nodes.emphasis: +def _stable_abi_annotation( + record: StableABIEntry, + is_corresponding_slot: bool = False, +) -> nodes.emphasis: """Create the Stable ABI annotation. These have two forms: @@ -168,9 +171,28 @@ def _stable_abi_annotation(record: StableABIEntry) -> nodes.emphasis: ... all of which can have "since version X.Y" appended. """ stable_added = record.added - message = sphinx_gettext("Part of the") - message = message.center(len(message) + 2) - emph_node = nodes.emphasis(message, message, classes=["stableabi"]) + emph_node = nodes.emphasis('', '', classes=["stableabi"]) + if is_corresponding_slot: + # See "Type slot annotations" in add_annotations + ref_node = addnodes.pending_xref( + "slot ID", + refdomain="c", + reftarget="PyType_Slot", + reftype="type", + refexplicit="True", + ) + ref_node += nodes.Text(sphinx_gettext("slot ID")) + + message = sphinx_gettext("The corresponding") + emph_node += nodes.Text(" " + message + " ") + emph_node += ref_node + emph_node += nodes.Text(" ") + emph_node += nodes.literal(record.name, record.name) + message = sphinx_gettext("is part of the") + emph_node += nodes.Text(" " + message + " ") + else: + message = sphinx_gettext("Part of the") + emph_node += nodes.Text(" " + message + " ") ref_node = addnodes.pending_xref( "Stable ABI", refdomain="std", @@ -265,6 +287,51 @@ class LimitedAPIList(SphinxDirective): return [node] +class CorrespondingTypeSlot(SphinxDirective): + """Type slot annotations + + Docs for these are with the corresponding field, for example, + "Py_tp_repr" is documented under "PyTypeObject.tp_repr", with + only a stable ABI note mentioning "Py_tp_repr" (and linking to + docs on how this works). + + If there is no corresponding field, these should be documented as normal + macros. + """ + + has_content = False + + required_arguments = 1 + optional_arguments = 0 + + def run(self) -> list[nodes.Node]: + name = self.arguments[0] + state = self.env.domaindata["c_annotations"] + stable_abi_data = state["stable_abi_data"] + + try: + record = stable_abi_data[name] + except LookupError as err: + raise LookupError( + f"{name} is not part of stable ABI. " + + "Document it as `c:macro::` rather than " + + "`corresponding-type-slot::`." + ) from err + + annotation = _stable_abi_annotation(record, is_corresponding_slot=True) + + node = nodes.paragraph() + content = [ + ".. c:namespace:: NULL", + "", + ".. c:macro:: " + name, + " :no-typesetting:", + ] + self.state.nested_parse(StringList(content), 0, node) + node.insert(0, annotation) + return [node] + + def init_annotations(app: Sphinx) -> None: # Using domaindata is a bit hack-ish, # but allows storing state without a global variable or closure. @@ -281,6 +348,7 @@ def setup(app: Sphinx) -> ExtensionMetadata: app.add_config_value("refcount_file", "", "env", types={str}) app.add_config_value("stable_abi_file", "", "env", types={str}) app.add_directive("limited-api-list", LimitedAPIList) + app.add_directive("corresponding-type-slot", CorrespondingTypeSlot) app.connect("builder-inited", init_annotations) app.connect("doctree-read", add_annotations) diff --git a/Doc/tools/extensions/glossary_search.py b/Doc/tools/extensions/glossary_search.py index 502b6cd95bc..bcda4b7b435 100644 --- a/Doc/tools/extensions/glossary_search.py +++ b/Doc/tools/extensions/glossary_search.py @@ -38,7 +38,7 @@ def process_glossary_nodes( rendered = app.builder.render_partial(definition) terms[term.lower()] = { 'title': term, - 'body': rendered['html_body'], + 'body': rendered['fragment'], } diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index f5451adb37b..f9bf273e762 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -24,14 +24,6 @@ from sphinx.util.docutils import SphinxDirective # Used in conf.py and updated here by python/release-tools/run_release.py SOURCE_URI = 'https://github.com/python/cpython/tree/main/%s' -# monkey-patch reST parser to disable alphabetic and roman enumerated lists -from docutils.parsers.rst.states import Body -Body.enum.converters['loweralpha'] = \ - Body.enum.converters['upperalpha'] = \ - Body.enum.converters['lowerroman'] = \ - Body.enum.converters['upperroman'] = lambda x: None - - class PyAwaitableMixin(object): def handle_signature(self, sig, signode): ret = super(PyAwaitableMixin, self).handle_signature(sig, signode) diff --git a/Doc/tools/templates/customsourcelink.html b/Doc/tools/templates/customsourcelink.html index 8e271bca1e0..0d83ac9f78a 100644 --- a/Doc/tools/templates/customsourcelink.html +++ b/Doc/tools/templates/customsourcelink.html @@ -8,6 +8,12 @@ rel="nofollow">{{ _('Show source') }} + {% if language != "en" %} +
  • + {{ _('Show translation source') }} +
  • + {% endif %} {%- endif %} diff --git a/Doc/tools/templates/download.html b/Doc/tools/templates/download.html index 47a57eb111b..c78c650b1cb 100644 --- a/Doc/tools/templates/download.html +++ b/Doc/tools/templates/download.html @@ -31,8 +31,7 @@ {% if last_updated %}

    {% trans %}Last updated on: {{ last_updated }}.{% endtrans %}

    {% endif %} -

    {% trans %}To download an archive containing all the documents for this version of -Python in one of various formats, follow one of links in this table.{% endtrans %}

    +

    {% trans %}Download an archive containing all the documentation for this version of Python:{% endtrans %}

    @@ -40,50 +39,41 @@ Python in one of various formats, follow one of links in this table.{% endtrans - - - - - - - + + - - + + - - + + - +
    {% trans %}Packed as .zip{% endtrans %} {% trans %}Packed as .tar.bz2{% endtrans %}
    {% trans %}PDF{% endtrans %}{% trans download_size="17" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="17" %}Download (ca. {{ download_size }} MiB){% endtrans %}
    {% trans %}HTML{% endtrans %}{% trans download_size="13" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="8" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans %}Download{% endtrans %}{% trans %}Download{% endtrans %}
    {% trans %}Plain text{% endtrans %}{% trans download_size="4" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="3" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans %}Download{% endtrans %}{% trans %}Download{% endtrans %}
    {% trans %}Texinfo{% endtrans %}{% trans download_size="9" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans download_size="7" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans %}Download{% endtrans %}{% trans %}Download{% endtrans %}
    {% trans %}EPUB{% endtrans %}{% trans download_size="6" %}Download (ca. {{ download_size }} MiB){% endtrans %}{% trans %}Download{% endtrans %}
    -

    {% trans %}These archives contain all the content in the documentation.{% endtrans %}

    - - -

    {% trans %}Unpacking{% endtrans %}

    - -

    {% trans %}Unix users should download the .tar.bz2 archives; these are bzipped tar -archives and can be handled in the usual way using tar and the bzip2 -program. The Info-ZIP unzip program can be -used to handle the ZIP archives if desired. The .tar.bz2 archives provide the -best compression and fastest download times.{% endtrans %}

    - -

    {% trans %}Windows users can use the ZIP archives since those are customary on that -platform. These are created on Unix using the Info-ZIP zip program.{% endtrans %}

    +

    {% trans %} +We no longer provide pre-built PDFs of the documentation. +To build a PDF archive, follow the instructions in the +Developer's Guide +and run make dist-pdf in the Doc/ directory of a copy of the CPython repository. +{% endtrans %}

    +

    {% trans %} +See the directory listing +for file sizes.{% endtrans %}

    {% trans %}Problems{% endtrans %}

    - -

    {% trans %}If you have comments or suggestions for the Python documentation, please send -email to docs@python.org.{% endtrans %}

    +{% set bugs = pathto('bugs') %} +

    {% trans bugs = bugs %}Open an issue +if you have comments or suggestions for the Python documentation.{% endtrans %}

    {% endblock %} diff --git a/Doc/tools/templates/dummy.html b/Doc/tools/templates/dummy.html index 0fdbe2a5801..75f6607d8f3 100644 --- a/Doc/tools/templates/dummy.html +++ b/Doc/tools/templates/dummy.html @@ -27,8 +27,8 @@ In extensions/implementation_detail.py: In extensions/changes.py: -{% trans %}Deprecated since version {deprecated}, will be removed in version {removed}{% endtrans %} -{% trans %}Deprecated since version {deprecated}, removed in version {removed}{% endtrans %} +{% trans %}Deprecated since version %s, will be removed in version %s{% endtrans %} +{% trans %}Deprecated since version %s, removed in version %s{% endtrans %} In docsbuild-scripts, when rewriting indexsidebar.html with actual versions: diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index 1cb0200822d..54c6eb9b5ef 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -28,7 +28,7 @@ {% block extrahead %} {% if builder == "html" %} {% if enable_analytics %} - + {% endif %} {% if pagename == 'whatsnew/changelog' and not embedded %} diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 5c0e8f34bf8..f3e69756401 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -251,6 +251,7 @@ statements: a ``try`` statement's ``else`` clause runs when no exception occurs, and a loop's ``else`` clause runs when no ``break`` occurs. For more on the ``try`` statement and exceptions, see :ref:`tut-handling`. +.. index:: single: ...; ellipsis literal .. _tut-pass: :keyword:`!pass` Statements @@ -277,6 +278,12 @@ at a more abstract level. The :keyword:`!pass` is silently ignored:: ... pass # Remember to implement this! ... +For this last case, many people use the ellipsis literal :code:`...` instead of +:code:`pass`. This use has no special meaning to Python, and is not part of +the language definition (you could use any constant expression here), but +:code:`...` is used conventionally as a placeholder body as well. +See :ref:`bltin-ellipsis-object`. + .. _tut-match: @@ -561,7 +568,7 @@ This example, as usual, demonstrates some new Python features: Different types define different methods. Methods of different types may have the same name without causing ambiguity. (It is possible to define your own object types and methods, using *classes*, see :ref:`tut-classes`) - The method :meth:`!append` shown in the example is defined for list objects; it + The method :meth:`~list.append` shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent to ``result = result + [a]``, but more efficient. @@ -1032,31 +1039,28 @@ blank, visually separating the summary from the rest of the description. The following lines should be one or more paragraphs describing the object's calling conventions, its side effects, etc. -The Python parser does not strip indentation from multi-line string literals in -Python, so tools that process documentation have to strip indentation if -desired. This is done using the following convention. The first non-blank line -*after* the first line of the string determines the amount of indentation for -the entire documentation string. (We can't use the first line since it is -generally adjacent to the string's opening quotes so its indentation is not -apparent in the string literal.) Whitespace "equivalent" to this indentation is -then stripped from the start of all lines of the string. Lines that are -indented less should not occur, but if they occur all their leading whitespace -should be stripped. Equivalence of whitespace should be tested after expansion -of tabs (to 8 spaces, normally). +The Python parser strips indentation from multi-line string literals when they +serve as module, class, or function docstrings. Here is an example of a multi-line docstring:: >>> def my_function(): ... """Do nothing, but document it. ... - ... No, really, it doesn't do anything. + ... No, really, it doesn't do anything: + ... + ... >>> my_function() + ... >>> ... """ ... pass ... >>> print(my_function.__doc__) Do nothing, but document it. - No, really, it doesn't do anything. + No, really, it doesn't do anything: + + >>> my_function() + >>> .. _tut-annotations: @@ -1074,7 +1078,7 @@ Function Annotations information about the types used by user-defined functions (see :pep:`3107` and :pep:`484` for more information). -:term:`Annotations ` are stored in the :attr:`!__annotations__` +:term:`Annotations ` are stored in the :attr:`~object.__annotations__` attribute of the function as a dictionary and have no effect on any other part of the function. Parameter annotations are defined by a colon after the parameter name, followed by an expression evaluating to the value of the annotation. Return annotations are diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index cbe780e075b..7e02e74177c 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -12,9 +12,8 @@ and adds some new things as well. More on Lists ============= -The list data type has some more methods. Here are all of the methods of list -objects: - +The :ref:`list ` data type has some more methods. Here are all +of the methods of list objects: .. method:: list.append(x) :noindex: @@ -62,7 +61,7 @@ objects: .. method:: list.index(x[, start[, end]]) :noindex: - Return zero-based index in the list of the first item whose value is equal to *x*. + Return zero-based index of the first occurrence of *x* in the list. Raises a :exc:`ValueError` if there is no such item. The optional arguments *start* and *end* are interpreted as in the slice @@ -142,8 +141,8 @@ Using Lists as Stacks The list methods make it very easy to use a list as a stack, where the last element added is the first element retrieved ("last-in, first-out"). To add an -item to the top of the stack, use :meth:`!append`. To retrieve an item from the -top of the stack, use :meth:`!pop` without an explicit index. For example:: +item to the top of the stack, use :meth:`~list.append`. To retrieve an item from the +top of the stack, use :meth:`~list.pop` without an explicit index. For example:: >>> stack = [3, 4, 5] >>> stack.append(6) @@ -340,7 +339,7 @@ The :keyword:`!del` statement ============================= There is a way to remove an item from a list given its index instead of its -value: the :keyword:`del` statement. This differs from the :meth:`!pop` method +value: the :keyword:`del` statement. This differs from the :meth:`~list.pop` method which returns a value. The :keyword:`!del` statement can also be used to remove slices from a list or clear the entire list (which we did earlier by assignment of an empty list to the slice). For example:: @@ -445,10 +444,11 @@ packing and sequence unpacking. Sets ==== -Python also includes a data type for *sets*. A set is an unordered collection -with no duplicate elements. Basic uses include membership testing and -eliminating duplicate entries. Set objects also support mathematical operations -like union, intersection, difference, and symmetric difference. +Python also includes a data type for :ref:`sets `. A set is +an unordered collection with no duplicate elements. Basic uses include +membership testing and eliminating duplicate entries. Set objects also +support mathematical operations like union, intersection, difference, and +symmetric difference. Curly braces or the :func:`set` function can be used to create sets. Note: to create an empty set you have to use ``set()``, not ``{}``; the latter creates an @@ -500,8 +500,8 @@ any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can't use lists as keys, since lists can be modified in place using index -assignments, slice assignments, or methods like :meth:`!append` and -:meth:`!extend`. +assignments, slice assignments, or methods like :meth:`~list.append` and +:meth:`~list.extend`. It is best to think of a dictionary as a set of *key: value* pairs, with the requirement that the keys are unique (within one dictionary). A pair of @@ -512,8 +512,12 @@ dictionary; this is also the way dictionaries are written on output. The main operations on a dictionary are storing a value with some key and extracting the value given the key. It is also possible to delete a key:value pair with ``del``. If you store using a key that is already in use, the old -value associated with that key is forgotten. It is an error to extract a value -using a non-existent key. +value associated with that key is forgotten. + +Extracting a value for a non-existent key by subscripting (``d[key]``) raises a +:exc:`KeyError`. To avoid getting this error when trying to access a possibly +non-existent key, use the :meth:`~dict.get` method instead, which returns +``None`` (or a specified default value) if the key is not in the dictionary. Performing ``list(d)`` on a dictionary returns a list of all the keys used in the dictionary, in insertion order (if you want it sorted, just use @@ -528,6 +532,12 @@ Here is a small example using a dictionary:: {'jack': 4098, 'sape': 4139, 'guido': 4127} >>> tel['jack'] 4098 + >>> tel['irv'] + Traceback (most recent call last): + File "", line 1, in + KeyError: 'irv' + >>> print(tel.get('irv')) + None >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel diff --git a/Doc/tutorial/index.rst b/Doc/tutorial/index.rst index d0bf77dc40d..20fe161be4a 100644 --- a/Doc/tutorial/index.rst +++ b/Doc/tutorial/index.rst @@ -15,7 +15,7 @@ together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms. The Python interpreter and the extensive standard library are freely available -in source or binary form for all major platforms from the Python web site, +in source or binary form for all major platforms from the Python website, https://www.python.org/, and may be freely distributed. The same site also contains distributions of and pointers to many free third party Python modules, programs and tools, and additional documentation. diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 9e06e03991b..deabac52530 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -49,7 +49,7 @@ primary prompt, ``>>>``. (It shouldn't take long.) Numbers ------- -The interpreter acts as a simple calculator: you can type an expression at it +The interpreter acts as a simple calculator: you can type an expression into it and it will write the value. Expression syntax is straightforward: the operators ``+``, ``-``, ``*`` and ``/`` can be used to perform arithmetic; parentheses (``()``) can be used for grouping. @@ -420,7 +420,7 @@ type, i.e. it is possible to change their content:: [1, 8, 27, 64, 125] You can also add new items at the end of the list, by using -the :meth:`!list.append` *method* (we will see more about methods later):: +the :meth:`list.append` *method* (we will see more about methods later):: >>> cubes.append(216) # add the cube of 6 >>> cubes.append(7 ** 3) # and the cube of 7 diff --git a/Doc/tutorial/stdlib.rst b/Doc/tutorial/stdlib.rst index d83ecca270b..342c1a00193 100644 --- a/Doc/tutorial/stdlib.rst +++ b/Doc/tutorial/stdlib.rst @@ -183,13 +183,13 @@ protocols. Two of the simplest are :mod:`urllib.request` for retrieving data from URLs and :mod:`smtplib` for sending mail:: >>> from urllib.request import urlopen - >>> with urlopen('http://worldtimeapi.org/api/timezone/etc/UTC.txt') as response: + >>> with urlopen('https://docs.python.org/3/') as response: ... for line in response: ... line = line.decode() # Convert bytes to a str - ... if line.startswith('datetime'): + ... if 'updated' in line: ... print(line.rstrip()) # Remove trailing newline ... - datetime: 2022-01-01T01:36:47.689215+00:00 + Last updated on Nov 11, 2025 (20:11 UTC). >>> import smtplib >>> server = smtplib.SMTP('localhost') @@ -335,7 +335,7 @@ sophisticated and robust capabilities of its larger packages. For example: names, no direct knowledge or handling of XML is needed. * The :mod:`email` package is a library for managing email messages, including - MIME and other :rfc:`2822`-based message documents. Unlike :mod:`smtplib` and + MIME and other :rfc:`5322`-based message documents. Unlike :mod:`smtplib` and :mod:`poplib` which actually send and receive messages, the email package has a complete toolset for building or decoding complex message structures (including attachments) and for implementing internet encoding and header diff --git a/Doc/tutorial/whatnow.rst b/Doc/tutorial/whatnow.rst index dbe2d7fc099..359cf80a7b2 100644 --- a/Doc/tutorial/whatnow.rst +++ b/Doc/tutorial/whatnow.rst @@ -30,7 +30,7 @@ the set are: More Python resources: -* https://www.python.org: The major Python web site. It contains code, +* https://www.python.org: The major Python website. It contains code, documentation, and pointers to Python-related pages around the web. * https://docs.python.org: Fast access to Python's documentation. diff --git a/Doc/using/android.rst b/Doc/using/android.rst index cb762310328..45345d045dd 100644 --- a/Doc/using/android.rst +++ b/Doc/using/android.rst @@ -40,8 +40,15 @@ If you're sure you want to do all of this manually, read on. You can use the :source:`testbed app ` as a guide; each step below contains a link to the relevant file. -* Build Python by following the instructions in :source:`Android/README.md`. - This will create the directory ``cross-build/HOST/prefix``. +* First, acquire a build of Python for Android: + + * The easiest way is to download an Android release from `python.org + `__. The ``prefix`` directory + mentioned below is at the top level of the package. + + * Or if you want to build it yourself, follow the instructions in + :source:`Android/README.md`. The ``prefix`` directory will be created under + :samp:`cross-build/{HOST}`. * Add code to your :source:`build.gradle ` file to copy the following items into your project. All except your own Python diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index cad49e2deeb..aff165191b7 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -254,6 +254,15 @@ Miscellaneous options .. versionchanged:: 3.5 Affects also comparisons of :class:`bytes` with :class:`int`. + .. deprecated:: 3.15 + + Deprecate :option:`-b` and :option:`!-bb` command line options + and schedule them to become no-op in Python 3.17. + These were primarily helpers for the Python 2 -> 3 transition. + Starting with Python 3.17, no :exc:`BytesWarning` will be raised + for these cases; use a type checker instead. + + .. option:: -B If given, Python won't try to write ``.pyc`` files on the @@ -369,8 +378,8 @@ Miscellaneous options .. option:: -R Turn on hash randomization. This option only has an effect if the - :envvar:`PYTHONHASHSEED` environment variable is set to ``0``, since hash - randomization is enabled by default. + :envvar:`PYTHONHASHSEED` environment variable is set to anything other + than ``random``, since hash randomization is enabled by default. On previous versions of Python, this option turns on hash randomization, so that the :meth:`~object.__hash__` values of str and bytes objects @@ -470,8 +479,10 @@ Miscellaneous options The *action* field is as explained above but only applies to warnings that match the remaining fields. - The *message* field must match the whole warning message; this match is - case-insensitive. + The *message* field must match the start of the warning message; + this match is case-insensitive. + If it starts and ends with a forward slash (``/``), it specifies + a regular expression, otherwise it specifies a literal string. The *category* field matches the warning category (ex: ``DeprecationWarning``). This must be a class name; the match test @@ -480,6 +491,10 @@ Miscellaneous options The *module* field matches the (fully qualified) module name; this match is case-sensitive. + If it starts and ends with a forward slash (``/``), it specifies + a regular expression that the start of the fully qualified module name + must match, otherwise it specifies a literal string that the fully + qualified module name must be equal to. The *lineno* field matches the line number, where zero matches all line numbers and is thus equivalent to an omitted line number. @@ -497,6 +512,9 @@ Miscellaneous options See :ref:`warning-filter` and :ref:`describing-warning-filters` for more details. + .. versionchanged:: 3.15 + Added regular expression support for *message* and *module*. + .. option:: -x @@ -971,6 +989,9 @@ conflict. See :ref:`warning-filter` and :ref:`describing-warning-filters` for more details. + .. versionchanged:: 3.15 + Added regular expression support for *message* and *module*. + .. envvar:: PYTHONFAULTHANDLER @@ -1256,9 +1277,8 @@ conflict. .. envvar:: PYTHON_BASIC_REPL If this variable is set to any value, the interpreter will not attempt to - load the Python-based :term:`REPL` that requires :mod:`curses` and - :mod:`readline`, and will instead use the traditional parser-based - :term:`REPL`. + load the Python-based :term:`REPL` that requires :mod:`readline`, and will + instead use the traditional parser-based :term:`REPL`. .. versionadded:: 3.13 diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 2cda9587975..af055d35290 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -4,10 +4,13 @@ Configure Python .. highlight:: sh + +.. _build-requirements: + Build Requirements ================== -Features and minimum versions required to build CPython: +To build CPython, you will need: * A `C11 `_ compiler. `Optional C11 features @@ -22,52 +25,138 @@ Features and minimum versions required to build CPython: * Support for threads. -* OpenSSL 1.1.1 is the minimum version and OpenSSL 3.0.16 is the recommended - minimum version for the :mod:`ssl` and :mod:`hashlib` extension modules. - -* SQLite 3.15.2 for the :mod:`sqlite3` extension module. - -* Tcl/Tk 8.5.12 for the :mod:`tkinter` module. - -* `libmpdec `_ 2.5.0 - for the :mod:`decimal` module. - -* Autoconf 2.72 and aclocal 1.16.5 are required to regenerate the - :file:`configure` script. - -.. versionchanged:: 3.1 - Tcl/Tk version 8.3.1 is now required. - .. versionchanged:: 3.5 On Windows, Visual Studio 2015 or later is now required. - Tcl/Tk version 8.4 is now required. .. versionchanged:: 3.6 - Selected C99 features are now required, like ```` and ``static - inline`` functions. + Selected C99 features, like ```` and ``static inline`` functions, + are now required. .. versionchanged:: 3.7 - Thread support and OpenSSL 1.0.2 are now required. - -.. versionchanged:: 3.10 - OpenSSL 1.1.1 is now required. - Require SQLite 3.7.15. + Thread support is now required. .. versionchanged:: 3.11 C11 compiler, IEEE 754 and NaN support are now required. On Windows, Visual Studio 2017 or later is required. - Tcl/Tk version 8.5.12 is now required for the :mod:`tkinter` module. - -.. versionchanged:: 3.13 - Autoconf 2.71, aclocal 1.16.5 and SQLite 3.15.2 are now required. - -.. versionchanged:: 3.14 - Autoconf 2.72 is now required. See also :pep:`7` "Style Guide for C Code" and :pep:`11` "CPython platform support". +.. _optional-module-requirements: + +Requirements for optional modules +--------------------------------- + +Some :term:`optional modules ` of the standard library +require third-party libraries installed for development +(for example, header files must be available). + +Missing requirements are reported in the ``configure`` output. +Modules that are missing due to missing dependencies are listed near the end +of the ``make`` output, +sometimes using an internal name, for example, ``_ctypes`` for :mod:`ctypes` +module. + +If you distribute a CPython interpreter without optional modules, +it's best practice to advise users, who generally expect that +standard library modules are available. + +Dependencies to build optional modules are: + +.. list-table:: + :header-rows: 1 + :align: left + + * - Dependency + - Minimum version + - Python module + * - `libbz2 `_ + - + - :mod:`bz2` + * - `libffi `_ + - 3.3.0 recommended + - :mod:`ctypes` + * - `liblzma `_ + - + - :mod:`lzma` + * - `libmpdec `_ + - 2.5.0 + - :mod:`decimal` [1]_ + * - `libreadline `_ or + `libedit `_ [2]_ + - + - :mod:`readline` + * - `libuuid `_ + - + - ``_uuid`` [3]_ + * - `ncurses `_ [4]_ + - + - :mod:`curses` + * - `OpenSSL `_ + - | 3.0.18 recommended + | (1.1.1 minimum) + - :mod:`ssl`, :mod:`hashlib` [5]_ + * - `SQLite `_ + - 3.15.2 + - :mod:`sqlite3` + * - `Tcl/Tk `_ + - 8.5.12 + - :mod:`tkinter`, :ref:`IDLE `, :mod:`turtle` + * - `zlib `_ + - 1.2.2.1 + - :mod:`zlib`, :mod:`gzip`, :mod:`ensurepip` + * - `zstd `_ + - 1.4.5 + - :mod:`compression.zstd` + +.. [1] If *libmpdec* is not available, the :mod:`decimal` module will use + a pure-Python implementation. + See :option:`--with-system-libmpdec` for details. +.. [2] See :option:`--with-readline` for choosing the backend for the + :mod:`readline` module. +.. [3] The :mod:`uuid` module uses ``_uuid`` to generate "safe" UUIDs. + See the module documentation for details. +.. [4] The :mod:`curses` module requires the ``libncurses`` or ``libncursesw`` + library. + The :mod:`curses.panel` module additionally requires the ``libpanel`` or + ``libpanelw`` library. +.. [5] If OpenSSL is not available, the :mod:`hashlib` module will use + bundled implementations of several hash functions. + See :option:`--with-builtin-hashlib-hashes` for *forcing* usage of OpenSSL. + +Note that the table does not include all optional modules; in particular, +platform-specific modules like :mod:`winreg` are not listed here. + +.. seealso:: + + * The `devguide `_ + includes a full list of dependencies required to build all modules and + instructions on how to install them on common platforms. + * :option:`--with-system-expat` allows building with an external + `libexpat `_ library. + * :ref:`configure-options-for-dependencies` + +.. versionchanged:: 3.1 + Tcl/Tk version 8.3.1 is now required for :mod:`tkinter`. + +.. versionchanged:: 3.5 + Tcl/Tk version 8.4 is now required for :mod:`tkinter`. + +.. versionchanged:: 3.7 + OpenSSL 1.0.2 is now required for :mod:`hashlib` and :mod:`ssl`. + +.. versionchanged:: 3.10 + OpenSSL 1.1.1 is now required for :mod:`hashlib` and :mod:`ssl`. + SQLite 3.7.15 is now required for :mod:`sqlite3`. + +.. versionchanged:: 3.11 + Tcl/Tk version 8.5.12 is now required for :mod:`tkinter`. + +.. versionchanged:: 3.13 + SQLite 3.15.2 is now required for :mod:`sqlite3`. + + Generated files =============== @@ -94,8 +183,19 @@ The container is optional, the following command can be run locally:: autoreconf -ivf -Werror -The generated files can change depending on the exact ``autoconf-archive``, -``aclocal`` and ``pkg-config`` versions. +The generated files can change depending on the exact versions of the +tools used. +The container that CPython uses has +`Autoconf `_ 2.72, +``aclocal`` from `Automake `_ 1.16.5, +and `pkg-config `_ 1.8.1. + +.. versionchanged:: 3.13 + Autoconf 2.71 and aclocal 1.16.5 and are now used to regenerate + :file:`configure`. + +.. versionchanged:: 3.14 + Autoconf 2.72 is now used to regenerate :file:`configure`. .. _configure-options: @@ -222,6 +322,30 @@ General Options .. versionadded:: 3.11 +.. option:: --with-missing-stdlib-config=FILE + + Path to a `JSON `_ configuration file + containing custom error messages for missing :term:`standard library` modules. + + This option is intended for Python distributors who wish to provide + distribution-specific guidance when users encounter standard library + modules that are missing or packaged separately. + + The JSON file should map missing module names to custom error message strings. + For example, if your distribution packages :mod:`tkinter` and + :mod:`_tkinter` separately and excludes :mod:`!_gdbm` for legal reasons, + the configuration could contain: + + .. code-block:: json + + { + "_gdbm": "The '_gdbm' module is not available in this distribution", + "tkinter": "Install the python-tk package to use tkinter", + "_tkinter": "Install the python-tk package to use tkinter", + } + + .. versionadded:: 3.15 + .. option:: --enable-pystats Turn on internal Python performance statistics gathering. @@ -293,6 +417,9 @@ General Options .. option:: --disable-gil + .. c:macro:: Py_GIL_DISABLED + :no-typesetting: + Enables support for running Python without the :term:`global interpreter lock` (GIL): free threading build. @@ -373,6 +500,8 @@ Linker options Name for machine-dependent library files. +.. _configure-options-for-dependencies: + Options for third-party dependencies ------------------------------------ @@ -395,12 +524,6 @@ Options for third-party dependencies C compiler and linker flags for ``gdbm``. -.. option:: LIBB2_CFLAGS -.. option:: LIBB2_LIBS - - C compiler and linker flags for ``libb2`` (:ref:`BLAKE2 `), - used by :mod:`hashlib` module, overriding ``pkg-config``. - .. option:: LIBEDIT_CFLAGS .. option:: LIBEDIT_LIBS @@ -866,9 +989,16 @@ Libraries options .. versionchanged:: 3.13 Default to using the installed ``mpdecimal`` library. - .. deprecated-removed:: 3.13 3.15 + .. versionchanged:: 3.15 + + A bundled copy of the library will no longer be selected + implicitly if an installed ``mpdecimal`` library is not found. + In Python 3.15 only, it can still be selected explicitly using + ``--with-system-libmpdec=no`` or ``--without-system-libmpdec``. + + .. deprecated-removed:: 3.13 3.16 A copy of the ``mpdecimal`` library sources will no longer be distributed - with Python 3.15. + with Python 3.16. .. seealso:: :option:`LIBMPDEC_CFLAGS` and :option:`LIBMPDEC_LIBS`. diff --git a/Doc/using/ios.rst b/Doc/using/ios.rst index 91cfed16f0e..5e4033fb6ce 100644 --- a/Doc/using/ios.rst +++ b/Doc/using/ios.rst @@ -170,7 +170,7 @@ helpful. To add Python to an iOS Xcode project: 1. Build or obtain a Python ``XCFramework``. See the instructions in - :source:`iOS/README.rst` (in the CPython source distribution) for details on + :source:`Apple/iOS/README.md` (in the CPython source distribution) for details on how to build a Python ``XCFramework``. At a minimum, you will need a build that supports ``arm64-apple-ios``, plus one of either ``arm64-apple-ios-simulator`` or ``x86_64-apple-ios-simulator``. @@ -180,22 +180,19 @@ To add Python to an iOS Xcode project: of your project; however, you can use any other location that you want by adjusting paths as needed. -3. Drag the ``iOS/Resources/dylib-Info-template.plist`` file into your project, - and ensure it is associated with the app target. - -4. Add your application code as a folder in your Xcode project. In the +3. Add your application code as a folder in your Xcode project. In the following instructions, we'll assume that your user code is in a folder named ``app`` in the root of your project; you can use any other location by adjusting paths as needed. Ensure that this folder is associated with your app target. -5. Select the app target by selecting the root node of your Xcode project, then +4. Select the app target by selecting the root node of your Xcode project, then the target name in the sidebar that appears. -6. In the "General" settings, under "Frameworks, Libraries and Embedded +5. In the "General" settings, under "Frameworks, Libraries and Embedded Content", add ``Python.xcframework``, with "Embed & Sign" selected. -7. In the "Build Settings" tab, modify the following: +6. In the "Build Settings" tab, modify the following: - Build Options @@ -211,86 +208,24 @@ To add Python to an iOS Xcode project: * Quoted Include In Framework Header: No -8. Add a build step that copies the Python standard library into your app. In - the "Build Phases" tab, add a new "Run Script" build step *before* the - "Embed Frameworks" step, but *after* the "Copy Bundle Resources" step. Name - the step "Install Target Specific Python Standard Library", disable the - "Based on dependency analysis" checkbox, and set the script content to: +7. Add a build step that processes the Python standard library, and your own + Python binary dependencies. In the "Build Phases" tab, add a new "Run + Script" build step *before* the "Embed Frameworks" step, but *after* the + "Copy Bundle Resources" step. Name the step "Process Python libraries", + disable the "Based on dependency analysis" checkbox, and set the script + content to: .. code-block:: bash - set -e + set -e + source $PROJECT_DIR/Python.xcframework/build/build_utils.sh + install_python Python.xcframework app - mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib" - if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then - echo "Installing Python modules for iOS Simulator" - rsync -au --delete "$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" - else - echo "Installing Python modules for iOS Device" - rsync -au --delete "$PROJECT_DIR/Python.xcframework/ios-arm64/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" - fi + If you have placed your XCframework somewhere other than the root of your + project, modify the path to the first argument. - Note that the name of the simulator "slice" in the XCframework may be - different, depending the CPU architectures your ``XCFramework`` supports. - -9. Add a second build step that processes the binary extension modules in the - standard library into "Framework" format. Add a "Run Script" build step - *directly after* the one you added in step 8, named "Prepare Python Binary - Modules". It should also have "Based on dependency analysis" unchecked, with - the following script content: - - .. code-block:: bash - - set -e - - install_dylib () { - INSTALL_BASE=$1 - FULL_EXT=$2 - - # The name of the extension file - EXT=$(basename "$FULL_EXT") - # The location of the extension file, relative to the bundle - RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} - # The path to the extension file, relative to the install base - PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/} - # The full dotted name of the extension module, constructed from the file path. - FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d "." -f 1 | tr "/" "."); - # A bundle identifier; not actually used, but required by Xcode framework packaging - FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-") - # The name of the framework folder. - FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework" - - # If the framework folder doesn't exist, create it. - if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then - echo "Creating framework for $RELATIVE_EXT" - mkdir -p "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" - cp "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" - plutil -replace CFBundleExecutable -string "$FULL_MODULE_NAME" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" - plutil -replace CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" - fi - - echo "Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME" - mv "$FULL_EXT" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME" - # Create a placeholder .fwork file where the .so was - echo "$FRAMEWORK_FOLDER/$FULL_MODULE_NAME" > ${FULL_EXT%.so}.fwork - # Create a back reference to the .so file location in the framework - echo "${RELATIVE_EXT%.so}.fwork" > "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin" - } - - PYTHON_VER=$(ls -1 "$CODESIGNING_FOLDER_PATH/python/lib") - echo "Install Python $PYTHON_VER standard library extension modules..." - find "$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload" -name "*.so" | while read FULL_EXT; do - install_dylib python/lib/$PYTHON_VER/lib-dynload/ "$FULL_EXT" - done - - # Clean up dylib template - rm -f "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" - - echo "Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)..." - find "$CODESIGNING_FOLDER_PATH/Frameworks" -name "*.framework" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der "{}" \; - -10. Add Objective C code to initialize and use a Python interpreter in embedded - mode. You should ensure that: +8. Add Objective C code to initialize and use a Python interpreter in embedded + mode. You should ensure that: * UTF-8 mode (:c:member:`PyPreConfig.utf8_mode`) is *enabled*; * Buffered stdio (:c:member:`PyConfig.buffered_stdio`) is *disabled*; @@ -309,22 +244,19 @@ To add Python to an iOS Xcode project: Your app's bundle location can be determined using ``[[NSBundle mainBundle] resourcePath]``. -Steps 8, 9 and 10 of these instructions assume that you have a single folder of +Steps 7 and 8 of these instructions assume that you have a single folder of pure Python application code, named ``app``. If you have third-party binary modules in your app, some additional steps will be required: * You need to ensure that any folders containing third-party binaries are - either associated with the app target, or copied in as part of step 8. Step 8 - should also purge any binaries that are not appropriate for the platform a - specific build is targeting (i.e., delete any device binaries if you're - building an app targeting the simulator). + either associated with the app target, or are explicitly copied as part of + step 7. Step 7 should also purge any binaries that are not appropriate for + the platform a specific build is targeting (i.e., delete any device binaries + if you're building an app targeting the simulator). -* Any folders that contain third-party binaries must be processed into - framework form by step 9. The invocation of ``install_dylib`` that processes - the ``lib-dynload`` folder can be copied and adapted for this purpose. - -* If you're using a separate folder for third-party packages, ensure that folder - is included as part of the :envvar:`PYTHONPATH` configuration in step 10. +* If you're using a separate folder for third-party packages, ensure that + folder is added to the end of the call to ``install_python`` in step 7, and + as part of the :envvar:`PYTHONPATH` configuration in step 8. * If any of the folders that contain third-party packages will contain ``.pth`` files, you should add that folder as a *site directory* (using @@ -334,25 +266,30 @@ modules in your app, some additional steps will be required: Testing a Python package ------------------------ -The CPython source tree contains :source:`a testbed project ` that +The CPython source tree contains :source:`a testbed project ` that is used to run the CPython test suite on the iOS simulator. This testbed can also be used as a testbed project for running your Python library's test suite on iOS. -After building or obtaining an iOS XCFramework (See :source:`iOS/README.rst` -for details), create a clone of the Python iOS testbed project by running: +After building or obtaining an iOS XCFramework (see :source:`Apple/iOS/README.md` +for details), create a clone of the Python iOS testbed project. If you used the +``Apple`` build script to build the XCframework, you can run: .. code-block:: bash - $ python iOS/testbed clone --framework --app --app app-testbed + $ python cross-build/iOS/testbed clone --app --app app-testbed -You will need to modify the ``iOS/testbed`` reference to point to that -directory in the CPython source tree; any folders specified with the ``--app`` -flag will be copied into the cloned testbed project. The resulting testbed will -be created in the ``app-testbed`` folder. In this example, the ``module1`` and -``module2`` would be importable modules at runtime. If your project has -additional dependencies, they can be installed into the -``app-testbed/iOSTestbed/app_packages`` folder (using ``pip install --target -app-testbed/iOSTestbed/app_packages`` or similar). +Or, if you've sourced your own XCframework, by running: + +.. code-block:: bash + + $ python Apple/testbed clone --platform iOS --framework --app --app app-testbed + +Any folders specified with the ``--app`` flag will be copied into the cloned +testbed project. The resulting testbed will be created in the ``app-testbed`` +folder. In this example, the ``module1`` and ``module2`` would be importable +modules at runtime. If your project has additional dependencies, they can be +installed into the ``app-testbed/Testbed/app_packages`` folder (using ``pip +install --target app-testbed/Testbed/app_packages`` or similar). You can then use the ``app-testbed`` folder to run the test suite for your app, For example, if ``module1.tests`` was the entry point to your test suite, you @@ -381,7 +318,7 @@ tab. Modify the "Arguments Passed On Launch" value to change the testing arguments. The test plan also disables parallel testing, and specifies the use of the -``iOSTestbed.lldbinit`` file for providing configuration of the debugger. The +``Testbed.lldbinit`` file for providing configuration of the debugger. The default debugger configuration disables automatic breakpoints on the ``SIGINT``, ``SIGUSR1``, ``SIGUSR2``, and ``SIGXFSZ`` signals. @@ -391,7 +328,12 @@ App Store Compliance The only mechanism for distributing apps to third-party iOS devices is to submit the app to the iOS App Store; apps submitted for distribution must pass Apple's app review process. This process includes a set of automated validation -rules that inspect the submitted application bundle for problematic code. +rules that inspect the submitted application bundle for problematic code. There +are some steps that must be taken to ensure that your app will be able to pass +these validation steps. + +Incompatible code in the standard library +----------------------------------------- The Python standard library contains some code that is known to violate these automated rules. While these violations appear to be false positives, Apple's @@ -402,3 +344,18 @@ The Python source tree contains :source:`a patch file ` that will remove all code that is known to cause issues with the App Store review process. This patch is applied automatically when building for iOS. + +Privacy manifests +----------------- + +In April 2025, Apple introduced a requirement for `certain third-party +libraries to provide a Privacy Manifest +`__. +As a result, if you have a binary module that uses one of the affected +libraries, you must provide an ``.xcprivacy`` file for that library. +OpenSSL is one library affected by this requirement, but there are others. + +If you produce a binary module named ``mymodule.so``, and use you the Xcode +build script described in step 7 above, you can place a ``mymodule.xcprivacy`` +file next to ``mymodule.so``, and the privacy manifest will be installed into +the required location when the binary module is converted into a framework. diff --git a/Doc/using/mac_installer_07_applications.png b/Doc/using/mac_installer_07_applications.png index 940219cad6f..c8b3aa1099a 100644 Binary files a/Doc/using/mac_installer_07_applications.png and b/Doc/using/mac_installer_07_applications.png differ diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 9ec4e341932..a9950ef7525 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -84,11 +84,17 @@ On FreeBSD and OpenBSD Building Python =============== +.. seealso:: + + If you want to contribute to CPython, refer to the + `devguide `_, + which includes build instructions and other tips on setting up environment. + If you want to compile CPython yourself, first thing you should do is get the `source `_. You can download either the -latest release's source or just grab a fresh `clone -`_. (If you want -to contribute patches, you will need a clone.) +latest release's source or grab a fresh `clone +`_. +You will also need to install the :ref:`build requirements `. The build process consists of the usual commands:: diff --git a/Doc/using/win_install_freethreaded.png b/Doc/using/win_install_freethreaded.png index 0aa01c1df6e..12b89c0165d 100644 Binary files a/Doc/using/win_install_freethreaded.png and b/Doc/using/win_install_freethreaded.png differ diff --git a/Doc/using/win_installer.png b/Doc/using/win_installer.png index 03bf2d7b16c..fc9605a79cf 100644 Binary files a/Doc/using/win_installer.png and b/Doc/using/win_installer.png differ diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index c66308e61e8..a4bc336cc92 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -4,6 +4,8 @@ .. _Microsoft Store app: https://apps.microsoft.com/detail/9NQ7512CXL7T +.. _legacy launcher: https://www.python.org/ftp/python/3.14.0/win32/launcher.msi + .. _using-on-windows: ************************* @@ -60,7 +62,7 @@ packages. .. _windows-path-mod: .. _launcher: -Python Install Manager +Python install manager ====================== Installation @@ -103,7 +105,7 @@ Windows Server 2019, please see :ref:`pymanager-advancedinstall` below for more information. -Basic Use +Basic use --------- The recommended command for launching Python is ``python``, which will either @@ -193,7 +195,7 @@ installed if automatic installation is configured (most likely by setting ``pymanager exec`` forms of the command were used. -Command Help +Command help ------------ The ``py help`` command will display the full list of supported commands, along @@ -218,7 +220,7 @@ override multiple settings at once. See :ref:`pymanager-config` below for more information about these files. -Listing Runtimes +Listing runtimes ---------------- .. code:: @@ -259,7 +261,7 @@ For compatibility with the old launcher, the ``--list``, ``--list-paths``, additional options, and will produce legacy formatted output. -Installing Runtimes +Installing runtimes ------------------- .. code:: @@ -288,8 +290,12 @@ Passing ``--dry-run`` will generate output and logs, but will not modify any installs. In addition to the above options, the ``--target`` option will extract the -runtime to the specified directory instead of doing a normal install. This is -useful for embedding runtimes into larger applications. +runtime to the specified directory instead of doing a normal install. +This is useful for embedding runtimes into larger applications. +Unlike a normal install, ``py`` will not be aware of the extracted runtime, +and no Start menu or other shortcuts will be created. +To launch the runtime, directly execute the main executable (typically +``python.exe``) in the target directory. .. code:: @@ -298,7 +304,7 @@ useful for embedding runtimes into larger applications. .. _pymanager-offline: -Offline Installs +Offline installs ---------------- To perform offline installs of Python, you will need to first create an offline @@ -330,7 +336,7 @@ In this way, Python runtimes can be installed and managed on a machine without access to the internet. -Uninstalling Runtimes +Uninstalling runtimes --------------------- .. code:: @@ -376,10 +382,13 @@ overridden installs may resolve settings differently. A global configuration file may be configured by an administrator, and would be read first. The user configuration file is stored at -:file:`%AppData%\\Python\\pymanager.json` (by default) and is read next, +:file:`%AppData%\\Python\\pymanager.json` +(note that this location is under ``Roaming``, not ``Local``) and is read next, overwriting any settings from earlier files. An additional configuration file may be specified as the ``PYTHON_MANAGER_CONFIG`` environment variable or the ``--config`` command line option (but not both). +These locations may be modified by administrative customization options listed +later. The following settings are those that are considered likely to be modified in normal use. Later sections list those that are intended for administrative @@ -398,7 +407,7 @@ customization. - Description * - ``default_tag`` - - ``PYTHON_MANAGER_DEFAULT`` + - .. envvar:: PYTHON_MANAGER_DEFAULT - The preferred default version to launch or install. By default, this is interpreted as the most recent non-prerelease version from the CPython team. @@ -418,8 +427,8 @@ customization. * - ``automatic_install`` - ``PYTHON_MANAGER_AUTOMATIC_INSTALL`` - - True to allow automatic installs when specifying a particular runtime - to launch. + - True to allow automatic installs when using ``py exec`` to launch. + Other commands will not automatically install. By default, true. * - ``include_unmanaged`` @@ -457,6 +466,25 @@ customization. - Specify the default format used by the ``py list`` command. By default, ``table``. + * - ``install_dir`` + - (none) + - Specify the root directory that runtimes will be installed into. + If you change this setting, previously installed runtimes will not be + usable unless you move them to the new location. + + * - ``global_dir`` + - (none) + - Specify the directory where global commands (such as ``python3.14.exe``) + are stored. + This directory should be added to your :envvar:`PATH` to make the + commands available from your terminal. + + * - ``download_dir`` + - (none) + - Specify the directory where downloaded files are stored. + This directory is a temporary cache, and can be cleaned up from time to + time. + Dotted names should be nested inside JSON objects, for example, ``list.format`` would be specified as ``{"list": {"format": "table"}}``. @@ -524,12 +552,9 @@ configuration option. The behaviour of shebangs in the Python install manager is subtly different from the previous ``py.exe`` launcher, and the old configuration options no longer apply. If you are specifically reliant on the old behaviour or - configuration, we recommend keeping the legacy launcher. It may be - `downloaded independently `_ - and installed on its own. The legacy launcher's ``py`` command will override - PyManager's one, and you will need to use ``pymanager`` commands for - installing and uninstalling. - + configuration, we recommend installing the `legacy launcher`_. The legacy + launcher's ``py`` command will override PyManager's one by default, and you + will need to use ``pymanager`` commands for installing and uninstalling. .. _Add-AppxPackage: https://learn.microsoft.com/powershell/module/appx/add-appxpackage @@ -541,7 +566,7 @@ configuration option. .. _pymanager-advancedinstall: -Advanced Installation +Advanced installation --------------------- For situations where an MSIX cannot be installed, such as some older @@ -635,7 +660,7 @@ the Store package in this way. .. _pymanager-admin-config: -Administrative Configuration +Administrative configuration ---------------------------- There are a number of options that may be useful for administrators to override @@ -726,17 +751,12 @@ directory containing the configuration file that specified them. .. _install-freethreaded-windows: -Installing Free-threaded Binaries +Installing free-threaded binaries --------------------------------- -.. versionadded:: 3.13 (Experimental) +.. versionadded:: 3.13 -.. note:: - - Everything described in this section is considered experimental, - and should be expected to change in future releases. - -Pre-built distributions of the experimental free-threaded build are available +Pre-built distributions of the free-threaded build are available by installing tags with the ``t`` suffix. .. code:: @@ -786,6 +806,12 @@ default). * - - Check that the ``py`` and ``pymanager`` commands work. + * - + - Ensure your :envvar:`PATH` variable contains the entry for + ``%UserProfile%\AppData\Local\Microsoft\WindowsApps``. + The operating system includes this entry once by default, after other + user paths. If removed, shortcuts will not be found. + * - ``py`` gives me a "command not found" error when I type it in my terminal. - Did you :ref:`install the Python install manager `? @@ -796,6 +822,12 @@ default). The "Python (default windowed)" and "Python install manager" commands may also need refreshing. + * - + - Ensure your :envvar:`PATH` variable contains the entry for + ``%UserProfile%\AppData\Local\Microsoft\WindowsApps``. + The operating system includes this entry once by default, after other + user paths. If removed, shortcuts will not be found. + * - ``py`` gives me a "can't open file" error when I type commands in my terminal. - This usually means you have the legacy launcher installed and @@ -812,7 +844,7 @@ default). ``python.exe`` alias is set to "Python (default)" * - ``python`` and ``py`` don't launch the runtime I expect - - Check your ``PYTHON_MANAGER_DEFAULT`` environment variable + - Check your :envvar:`PYTHON_MANAGER_DEFAULT` environment variable or ``default_tag`` configuration. The ``py list`` command will show your default based on these settings. @@ -826,7 +858,7 @@ default). - Prerelease and experimental installs that are not managed by the Python install manager may be chosen ahead of stable releases. Configure your default tag or uninstall the prerelease runtime - and reinstall using ``py install``. + and reinstall it using ``py install``. * - ``pythonw`` or ``pyw`` don't launch the same runtime as ``python`` or ``py`` - Click Start, open "Manage app execution aliases", and check that your @@ -845,6 +877,31 @@ default). These scripts are separated for each runtime, and so you may need to add multiple paths. + * - Typing ``script-name.py`` in the terminal opens in a new window. + - This is a known limitation of the operating system. Either specify ``py`` + before the script name, create a batch file containing ``@py "%~dpn0.py" %*`` + with the same name as the script, or install the `legacy launcher`_ + and select it as the association for scripts. + + * - Drag-dropping files onto a script doesn't work + - This is a known limitation of the operating system. It is supported with + the `legacy launcher`_, or with the Python install manager when installed + from the MSI. + + * - I have installed the Python install manager multiple times. + - It is possible to install from the Store or WinGet, from the MSIX on + the Python website, and from the MSI, all at once. + They are all compatible and will share configuration and runtimes. + + * - + - See the earlier :ref:`pymanager-advancedinstall` section for ways to + uninstall the install manager other than the typical Installed Apps + (Add and Remove Programs) settings page. + + * - My old ``py.ini`` settings no longer work. + - The new Python install manager no longer supports this configuration file + or its settings, and so it will be ignored. + See :ref:`pymanager-config` for information about configuration settings. .. _windows-embeddable: @@ -862,7 +919,7 @@ To install an embedded distribution, we recommend using ``py install`` with the .. code:: - $> py install 3.14-embed --target=runtime + $> py install 3.14-embed --target= When extracted, the embedded distribution is (almost) fully isolated from the user's system, including environment variables, system registry settings, and @@ -885,7 +942,7 @@ versions before providing updates to users. The two recommended use cases for this distribution are described below. -Python Application +Python application ------------------ An application written in Python does not necessarily require users to be aware @@ -989,12 +1046,7 @@ for the 64-bit version, `www.nuget.org/packages/pythonx86 Free-threaded packages ---------------------- -.. versionadded:: 3.13 (Experimental) - -.. note:: - - Everything described in this section is considered experimental, - and should be expected to change in future releases. +.. versionadded:: 3.13 Packages containing free-threaded binaries are named `python-freethreaded `_ @@ -1046,7 +1098,7 @@ please install Python 3.12. .. _max-path: -Removing the MAX_PATH Limitation +Removing the MAX_PATH limitation ================================ Windows historically has limited path lengths to 260 characters. This meant that @@ -1070,7 +1122,7 @@ UTF-8 mode ========== .. versionadded:: 3.7 -.. versionchanged:: next +.. versionchanged:: 3.15 Python UTF-8 mode is now enabled by default (:pep:`686`). @@ -1332,7 +1384,7 @@ installation". In this case: * Shortcuts are available for all users -Removing the MAX_PATH Limitation +Removing the MAX_PATH limitation -------------------------------- Windows historically has limited path lengths to 260 characters. This meant that @@ -1355,7 +1407,7 @@ After changing the above option, no further configuration is required. .. _install-quiet-option: -Installing Without UI +Installing without UI --------------------- All of the options available in the installer UI can also be specified from the @@ -1504,7 +1556,7 @@ example file sets the same options as the previous example: .. _install-layout-option: -Installing Without Downloading +Installing without downloading ------------------------------ As some features of Python are not included in the initial installer download, @@ -1545,15 +1597,10 @@ settings and replace any that have been removed or modified. :ref:`launcher`, which has its own entry in Programs and Features. -Installing Free-threaded Binaries +Installing free-threaded binaries --------------------------------- -.. versionadded:: 3.13 (Experimental) - -.. note:: - - Everything described in this section is considered experimental, - and should be expected to change in future releases. +.. versionadded:: 3.13 To install pre-built binaries with free-threading enabled (see :pep:`703`), you should select "Customize installation". The second page of options includes the @@ -1585,7 +1632,7 @@ builds. Free-threaded binaries are also available :ref:`on nuget.org `. -Python Launcher for Windows (Deprecated) +Python launcher for Windows (deprecated) ======================================== .. deprecated:: 3.14 @@ -1737,7 +1784,7 @@ have the script specify the version which should be used. The key benefit of this is that a single launcher can support multiple Python versions at the same time depending on the contents of the first line. -Shebang Lines +Shebang lines ------------- If the first line of a script file starts with ``#!``, it is known as a @@ -1802,7 +1849,7 @@ program, which performs a :envvar:`PATH` search. If an executable matching the first argument after the ``env`` command cannot be found, but the argument starts with ``python``, it will be handled as described for the other virtual commands. -The environment variable :envvar:`PYLAUNCHER_NO_SEARCH_PATH` may be set +The environment variable :envvar:`!PYLAUNCHER_NO_SEARCH_PATH` may be set (to any value) to skip this search of :envvar:`PATH`. Shebang lines that do not match any of these patterns are looked up in the @@ -1869,7 +1916,7 @@ For example, a shebang line of ``#!python`` has no version qualifier, while ``#!python3`` has a version qualifier which specifies only a major version. If no version qualifiers are found in a command, the environment -variable :envvar:`PY_PYTHON` can be set to specify the default version +variable :envvar:`!PY_PYTHON` can be set to specify the default version qualifier. If it is not set, the default is "3". The variable can specify any value that may be passed on the command line, such as "3", "3.7", "3.7-32" or "3.7-64". (Note that the "-64" option is only @@ -1942,17 +1989,17 @@ For example: Diagnostics ----------- -If an environment variable :envvar:`PYLAUNCHER_DEBUG` is set (to any value), the +If an environment variable :envvar:`!PYLAUNCHER_DEBUG` is set (to any value), the launcher will print diagnostic information to stderr (i.e. to the console). While this information manages to be simultaneously verbose *and* terse, it should allow you to see what versions of Python were located, why a particular version was chosen and the exact command-line used to execute the target Python. It is primarily intended for testing and debugging. -Dry Run +Dry run ------- -If an environment variable :envvar:`PYLAUNCHER_DRYRUN` is set (to any value), +If an environment variable :envvar:`!PYLAUNCHER_DRYRUN` is set (to any value), the launcher will output the command it would have run, but will not actually launch Python. This may be useful for tools that want to use the launcher to detect and then launch Python directly. Note that the command written to @@ -1962,14 +2009,14 @@ the console. Install on demand ----------------- -If an environment variable :envvar:`PYLAUNCHER_ALLOW_INSTALL` is set (to any +If an environment variable :envvar:`!PYLAUNCHER_ALLOW_INSTALL` is set (to any value), and the requested Python version is not installed but is available on the Microsoft Store, the launcher will attempt to install it. This may require user interaction to complete, and you may need to run the command again. -An additional :envvar:`PYLAUNCHER_ALWAYS_INSTALL` variable causes the launcher +An additional :envvar:`!PYLAUNCHER_ALWAYS_INSTALL` variable causes the launcher to always try to install Python, even if it is detected. This is mainly intended -for testing (and should be used with :envvar:`PYLAUNCHER_DRYRUN`). +for testing (and should be used with :envvar:`!PYLAUNCHER_DRYRUN`). Return codes ------------ diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index 1a949ec4035..c157c0337a1 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -656,7 +656,8 @@ break. The change which will probably break the most code is tightening up the arguments accepted by some methods. Some methods would take multiple arguments and treat them as a tuple, particularly various list methods such as -:meth:`!append` and :meth:`!insert`. In earlier versions of Python, if ``L`` is +:meth:`~list.append` and :meth:`~list.insert`. +In earlier versions of Python, if ``L`` is a list, ``L.append( 1,2 )`` appends the tuple ``(1,2)`` to the list. In Python 2.0 this causes a :exc:`TypeError` exception to be raised, with the message: 'append requires exactly 1 argument; 2 given'. The fix is to simply add an diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index b7e4e73f4ce..f43692b3dce 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -66,7 +66,7 @@ Here's a simple example:: The union and intersection of sets can be computed with the :meth:`~frozenset.union` and :meth:`~frozenset.intersection` methods; an alternative notation uses the bitwise operators ``&`` and ``|``. Mutable sets also have in-place versions of these methods, -:meth:`!union_update` and :meth:`~frozenset.intersection_update`. :: +:meth:`!union_update` and :meth:`~set.intersection_update`. :: >>> S1 = sets.Set([1,2,3]) >>> S2 = sets.Set([4,5,6]) @@ -87,7 +87,7 @@ It's also possible to take the symmetric difference of two sets. This is the set of all elements in the union that aren't in the intersection. Another way of putting it is that the symmetric difference contains all elements that are in exactly one set. Again, there's an alternative notation (``^``), and an -in-place version with the ungainly name :meth:`~frozenset.symmetric_difference_update`. :: +in-place version with the ungainly name :meth:`~set.symmetric_difference_update`. :: >>> S1 = sets.Set([1,2,3,4]) >>> S2 = sets.Set([3,4,5,6]) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 3430ac8668e..9b8f36862c1 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1277,12 +1277,12 @@ complete list of changes, or look through the SVN logs for all the details. with the new ':keyword:`with`' statement. See section :ref:`contextlibmod` for more about this module. -* New module: The :mod:`cProfile` module is a C implementation of the existing - :mod:`profile` module that has much lower overhead. The module's interface is - the same as :mod:`profile`: you run ``cProfile.run('main()')`` to profile a +* New module: The :mod:`!cProfile` module is a C implementation of the existing + :mod:`!profile` module that has much lower overhead. The module's interface is + the same as :mod:`!profile`: you run ``cProfile.run('main()')`` to profile a function, can save profile data to a file, etc. It's not yet known if the Hotshot profiler, which is also written in C but doesn't match the - :mod:`profile` module's interface, will continue to be maintained in future + :mod:`!profile` module's interface, will continue to be maintained in future versions of Python. (Contributed by Armin Rigo.) Also, the :mod:`pstats` module for analyzing the data measured by the profiler @@ -2169,9 +2169,9 @@ Changes to Python's build process and to the C API include: * Two new macros can be used to indicate C functions that are local to the current file so that a faster calling convention can be used. - ``Py_LOCAL(type)`` declares the function as returning a value of the + :c:macro:`Py_LOCAL` declares the function as returning a value of the specified *type* and uses a fast-calling qualifier. - ``Py_LOCAL_INLINE(type)`` does the same thing and also requests the + :c:macro:`Py_LOCAL_INLINE` does the same thing and also requests the function be inlined. If macro :c:macro:`!PY_LOCAL_AGGRESSIVE` is defined before :file:`python.h` is included, a set of more aggressive optimizations are enabled for the module; you should benchmark the results to find out if these diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 0803eba99e6..f5e3a47037c 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -56,7 +56,7 @@ Python 2.6 incorporates new features and syntax from 3.0 while remaining compatible with existing code by not removing older features or syntax. When it's not possible to do that, Python 2.6 tries to do what it can, adding compatibility functions in a -:mod:`future_builtins` module and a :option:`!-3` switch to warn about +:mod:`!future_builtins` module and a :option:`!-3` switch to warn about usages that will become unsupported in 3.0. Some significant new packages have been added to the standard library, @@ -109,7 +109,7 @@ are: Python 3.0 adds several new built-in functions and changes the semantics of some existing builtins. Functions that are new in 3.0 such as :func:`bin` have simply been added to Python 2.6, but existing -builtins haven't been changed; instead, the :mod:`future_builtins` +builtins haven't been changed; instead, the :mod:`!future_builtins` module has versions with the new 3.0 semantics. Code written to be compatible with 3.0 can do ``from future_builtins import hex, map`` as necessary. @@ -118,7 +118,7 @@ A new command-line switch, :option:`!-3`, enables warnings about features that will be removed in Python 3.0. You can run code with this switch to see how much work will be necessary to port code to 3.0. The value of this switch is available -to Python code as the boolean variable :data:`sys.py3kwarning`, +to Python code as the boolean variable :data:`!sys.py3kwarning`, and to C extension code as :c:data:`!Py_Py3kWarningFlag`. .. seealso:: @@ -307,9 +307,9 @@ The :mod:`threading` module's locks and condition variables also support the The lock is acquired before the block is executed and always released once the block is complete. -The :func:`localcontext` function in the :mod:`decimal` module makes it easy -to save and restore the current decimal context, which encapsulates the desired -precision and rounding characteristics for computations:: +The :func:`~decimal.localcontext` function in the :mod:`decimal` module makes +it easy to save and restore the current decimal context, which encapsulates +the desired precision and rounding characteristics for computations:: from decimal import Decimal, Context, localcontext @@ -337,12 +337,12 @@ underlying implementation and should keep reading. A high-level explanation of the context management protocol is: * The expression is evaluated and should result in an object called a "context - manager". The context manager must have :meth:`~object.__enter__` and :meth:`~object.__exit__` - methods. + manager". The context manager must have :meth:`~object.__enter__` and + :meth:`~object.__exit__` methods. -* The context manager's :meth:`~object.__enter__` method is called. The value returned - is assigned to *VAR*. If no ``as VAR`` clause is present, the value is simply - discarded. +* The context manager's :meth:`~object.__enter__` method is called. The value + returned is assigned to *VAR*. If no ``as VAR`` clause is present, the + value is simply discarded. * The code in *BLOCK* is executed. @@ -378,7 +378,7 @@ be to let the user write code like this:: The transaction should be committed if the code in the block runs flawlessly or rolled back if there's an exception. Here's the basic interface for -:class:`DatabaseConnection` that I'll assume:: +:class:`!DatabaseConnection` that I'll assume:: class DatabaseConnection: # Database interface @@ -431,14 +431,15 @@ The contextlib module The :mod:`contextlib` module provides some functions and a decorator that are useful when writing objects for use with the ':keyword:`with`' statement. -The decorator is called :func:`contextmanager`, and lets you write a single -generator function instead of defining a new class. The generator should yield -exactly one value. The code up to the :keyword:`yield` will be executed as the -:meth:`~object.__enter__` method, and the value yielded will be the method's return -value that will get bound to the variable in the ':keyword:`with`' statement's -:keyword:`!as` clause, if any. The code after the :keyword:`!yield` will be -executed in the :meth:`~object.__exit__` method. Any exception raised in the block will -be raised by the :keyword:`!yield` statement. +The decorator is called :func:`~contextlib.contextmanager`, and lets you write +a single generator function instead of defining a new class. The generator +should yield exactly one value. The code up to the :keyword:`yield` will be +executed as the :meth:`~object.__enter__` method, and the value yielded will +be the method's return value that will get bound to the variable in the +':keyword:`with`' statement's :keyword:`!as` clause, if any. The code after +the :keyword:`!yield` will be executed in the :meth:`~object.__exit__` method. +Any exception raised in the block will be raised by the :keyword:`!yield` +statement. Using this decorator, our database example from the previous section could be written as:: @@ -469,7 +470,7 @@ statement both starts a database transaction and acquires a thread lock:: with nested (db_transaction(db), lock) as (cursor, locked): ... -Finally, the :func:`closing` function returns its argument so that it can be +Finally, the :func:`~contextlib.closing` function returns its argument so that it can be bound to a variable, and calls the argument's ``.close()`` method at the end of the block. :: @@ -538,7 +539,7 @@ If you don't like the default directory, it can be overridden by an environment variable. :envvar:`PYTHONUSERBASE` sets the root directory used for all Python versions supporting this feature. On Windows, the directory for application-specific data can be changed by -setting the :envvar:`APPDATA` environment variable. You can also +setting the :envvar:`!APPDATA` environment variable. You can also modify the :file:`site.py` file for your Python installation. The feature can be disabled entirely by running Python with the @@ -568,11 +569,12 @@ The :mod:`multiprocessing` module started out as an exact emulation of the :mod:`threading` module using processes instead of threads. That goal was discarded along the path to Python 2.6, but the general approach of the module is still similar. The fundamental class -is the :class:`Process`, which is passed a callable object and -a collection of arguments. The :meth:`start` method +is the :class:`~multiprocessing.Process`, which is passed a callable object and +a collection of arguments. The :meth:`~multiprocessing.Process.start` method sets the callable running in a subprocess, after which you can call -the :meth:`is_alive` method to check whether the subprocess is still running -and the :meth:`join` method to wait for the process to exit. +the :meth:`~multiprocessing.Process.is_alive` method to check whether the +subprocess is still running and the :meth:`~multiprocessing.Process.join` +method to wait for the process to exit. Here's a simple example where the subprocess will calculate a factorial. The function doing the calculation is written strangely so @@ -619,13 +621,16 @@ the object to communicate. (If the parent were to change the value of the global variable, the child's value would be unaffected, and vice versa.) -Two other classes, :class:`Pool` and :class:`Manager`, provide -higher-level interfaces. :class:`Pool` will create a fixed number of -worker processes, and requests can then be distributed to the workers -by calling :meth:`apply` or :meth:`apply_async` to add a single request, -and :meth:`map` or :meth:`map_async` to add a number of -requests. The following code uses a :class:`Pool` to spread requests -across 5 worker processes and retrieve a list of results:: +Two other classes, :class:`~multiprocessing.pool.Pool` and +:class:`~multiprocessing.Manager`, provide higher-level interfaces. +:class:`~multiprocessing.pool.Pool` will create a fixed number of worker +processes, and requests can then be distributed to the workers by calling +:meth:`~multiprocessing.pool.Pool.apply` or +:meth:`~multiprocessing.pool.Pool.apply_async` to add a single request, and +:meth:`~multiprocessing.pool.Pool.map` or +:meth:`~multiprocessing.pool.Pool.map_async` to add a number of +requests. The following code uses a :class:`~multiprocessing.pool.Pool` to +spread requests across 5 worker processes and retrieve a list of results:: from multiprocessing import Pool @@ -646,15 +651,18 @@ This produces the following output:: 33452526613163807108170062053440751665152000000000 ... -The other high-level interface, the :class:`Manager` class, creates a -separate server process that can hold master copies of Python data +The other high-level interface, the :class:`~multiprocessing.Manager` class, +creates a separate server process that can hold master copies of Python data structures. Other processes can then access and modify these data structures using proxy objects. The following example creates a shared dictionary by calling the :meth:`dict` method; the worker processes then insert values into the dictionary. (Locking is not done for you automatically, which doesn't matter in this example. -:class:`Manager`'s methods also include :meth:`Lock`, :meth:`RLock`, -and :meth:`Semaphore` to create shared locks.) +:class:`~multiprocessing.Manager`'s methods also include +:meth:`~multiprocessing.managers.SyncManager.Lock`, +:meth:`~multiprocessing.managers.SyncManager.RLock`, +and :meth:`~multiprocessing.managers.SyncManager.Semaphore` to create +shared locks.) :: @@ -824,7 +832,7 @@ documentation for a :ref:`complete list `; here's a sample: format, followed by a percent sign. ===== ======================================================================== -Classes and types can define a :meth:`__format__` method to control how they're +Classes and types can define a :meth:`~object.__format__` method to control how they're formatted. It receives a single argument, the format specifier:: def __format__(self, format_spec): @@ -834,7 +842,7 @@ formatted. It receives a single argument, the format specifier:: return str(self) There's also a :func:`format` builtin that will format a single -value. It calls the type's :meth:`__format__` method with the +value. It calls the type's :meth:`~object.__format__` method with the provided specifier:: >>> format(75.6564, '.2f') @@ -997,9 +1005,10 @@ sequence of bytes:: u'\u31ef \u3244' Byte arrays support most of the methods of string types, such as -:meth:`startswith`/:meth:`endswith`, :meth:`find`/:meth:`rfind`, -and some of the methods of lists, such as :meth:`append`, -:meth:`pop`, and :meth:`reverse`. +:meth:`~bytearray.startswith`/:meth:`~bytearray.endswith`, +:meth:`~bytearray.find`/:meth:`~bytearray.rfind`, +and some of the methods of lists, such as :meth:`~bytearray.append`, +:meth:`~bytearray.pop`, and :meth:`~bytearray.reverse`. :: @@ -1028,56 +1037,58 @@ PEP 3116: New I/O Library Python's built-in file objects support a number of methods, but file-like objects don't necessarily support all of them. Objects that -imitate files usually support :meth:`read` and :meth:`write`, but they -may not support :meth:`readline`, for example. Python 3.0 introduces -a layered I/O library in the :mod:`io` module that separates buffering -and text-handling features from the fundamental read and write -operations. +imitate files usually support :meth:`!read` and +:meth:`!write`, but they may not support :meth:`!readline`, +for example. Python 3.0 introduces a layered I/O library in the :mod:`io` +module that separates buffering and text-handling features from the +fundamental read and write operations. There are three levels of abstract base classes provided by the :mod:`io` module: -* :class:`RawIOBase` defines raw I/O operations: :meth:`read`, - :meth:`readinto`, - :meth:`write`, :meth:`seek`, :meth:`tell`, :meth:`truncate`, - and :meth:`close`. +* :class:`~io.RawIOBase` defines raw I/O operations: :meth:`~io.RawIOBase.read`, + :meth:`~io.RawIOBase.readinto`, :meth:`~io.RawIOBase.write`, + :meth:`~io.IOBase.seek`, :meth:`~io.IOBase.tell`, :meth:`~io.IOBase.truncate`, + and :meth:`~io.IOBase.close`. Most of the methods of this class will often map to a single system call. - There are also :meth:`readable`, :meth:`writable`, and :meth:`seekable` - methods for determining what operations a given object will allow. + There are also :meth:`~io.IOBase.readable`, :meth:`~io.IOBase.writable`, + and :meth:`~io.IOBase.seekable` methods for determining what operations a + given object will allow. Python 3.0 has concrete implementations of this class for files and sockets, but Python 2.6 hasn't restructured its file and socket objects in this way. -* :class:`BufferedIOBase` is an abstract base class that +* :class:`~io.BufferedIOBase` is an abstract base class that buffers data in memory to reduce the number of system calls used, making I/O processing more efficient. - It supports all of the methods of :class:`RawIOBase`, - and adds a :attr:`raw` attribute holding the underlying raw object. + It supports all of the methods of :class:`~io.RawIOBase`, + and adds a :attr:`~io.BufferedIOBase.raw` attribute holding the underlying + raw object. There are five concrete classes implementing this ABC. - :class:`BufferedWriter` and :class:`BufferedReader` are for objects - that support write-only or read-only usage that have a :meth:`seek` - method for random access. :class:`BufferedRandom` objects support + :class:`~io.BufferedWriter` and :class:`~io.BufferedReader` are for objects + that support write-only or read-only usage that have a :meth:`~io.IOBase.seek` + method for random access. :class:`~io.BufferedRandom` objects support read and write access upon the same underlying stream, and - :class:`BufferedRWPair` is for objects such as TTYs that have both + :class:`~io.BufferedRWPair` is for objects such as TTYs that have both read and write operations acting upon unconnected streams of data. - The :class:`BytesIO` class supports reading, writing, and seeking + The :class:`~io.BytesIO` class supports reading, writing, and seeking over an in-memory buffer. .. index:: single: universal newlines; What's new -* :class:`TextIOBase`: Provides functions for reading and writing +* :class:`~io.TextIOBase`: Provides functions for reading and writing strings (remember, strings will be Unicode in Python 3.0), - and supporting :term:`universal newlines`. :class:`TextIOBase` defines + and supporting :term:`universal newlines`. :class:`~io.TextIOBase` defines the :meth:`readline` method and supports iteration upon objects. - There are two concrete implementations. :class:`TextIOWrapper` + There are two concrete implementations. :class:`~io.TextIOWrapper` wraps a buffered I/O object, supporting all of the methods for - text I/O and adding a :attr:`buffer` attribute for access - to the underlying object. :class:`StringIO` simply buffers + text I/O and adding a :attr:`~io.TextIOBase.buffer` attribute for access + to the underlying object. :class:`~io.StringIO` simply buffers everything in memory without ever writing anything to disk. (In Python 2.6, :class:`io.StringIO` is implemented in @@ -1161,7 +1172,7 @@ Some object-oriented languages such as Java support interfaces, declaring that a class has a given set of methods or supports a given access protocol. Abstract Base Classes (or ABCs) are an equivalent feature for Python. The ABC support consists of an :mod:`abc` module -containing a metaclass called :class:`ABCMeta`, special handling of +containing a metaclass called :class:`~abc.ABCMeta`, special handling of this metaclass by the :func:`isinstance` and :func:`issubclass` builtins, and a collection of basic ABCs that the Python developers think will be widely useful. Future versions of Python will probably @@ -1171,17 +1182,17 @@ Let's say you have a particular class and wish to know whether it supports dictionary-style access. The phrase "dictionary-style" is vague, however. It probably means that accessing items with ``obj[1]`` works. Does it imply that setting items with ``obj[2] = value`` works? -Or that the object will have :meth:`keys`, :meth:`values`, and :meth:`items` -methods? What about the iterative variants such as :meth:`iterkeys`? :meth:`copy` -and :meth:`update`? Iterating over the object with :func:`iter`? +Or that the object will have :meth:`!keys`, :meth:`!values`, and :meth:`!items` +methods? What about the iterative variants such as :meth:`!iterkeys`? +:meth:`!copy`and :meth:`!update`? Iterating over the object with :func:`!iter`? The Python 2.6 :mod:`collections` module includes a number of different ABCs that represent these distinctions. :class:`Iterable` -indicates that a class defines :meth:`__iter__`, and -:class:`Container` means the class defines a :meth:`__contains__` +indicates that a class defines :meth:`~object.__iter__`, and +:class:`Container` means the class defines a :meth:`~object.__contains__` method and therefore supports ``x in y`` expressions. The basic dictionary interface of getting items, setting items, and -:meth:`keys`, :meth:`values`, and :meth:`items`, is defined by the +:meth:`!keys`, :meth:`!values`, and :meth:`!items`, is defined by the :class:`MutableMapping` ABC. You can derive your own classes from a particular ABC @@ -1195,7 +1206,7 @@ to indicate they support that ABC's interface:: Alternatively, you could write the class without deriving from the desired ABC and instead register the class by -calling the ABC's :meth:`register` method:: +calling the ABC's :meth:`~abc.ABCMeta.register` method:: import collections @@ -1205,10 +1216,10 @@ calling the ABC's :meth:`register` method:: collections.MutableMapping.register(Storage) For classes that you write, deriving from the ABC is probably clearer. -The :meth:`register` method is useful when you've written a new +The :meth:`~abc.ABCMeta.register` method is useful when you've written a new ABC that can describe an existing type or class, or if you want to declare that some third-party class implements an ABC. -For example, if you defined a :class:`PrintableType` ABC, +For example, if you defined a :class:`!PrintableType` ABC, it's legal to do:: # Register Python's types @@ -1255,16 +1266,16 @@ metaclass in a class definition:: ... -In the :class:`Drawable` ABC above, the :meth:`draw_doubled` method +In the :class:`!Drawable` ABC above, the :meth:`!draw_doubled` method renders the object at twice its size and can be implemented in terms -of other methods described in :class:`Drawable`. Classes implementing +of other methods described in :class:`!Drawable`. Classes implementing this ABC therefore don't need to provide their own implementation -of :meth:`draw_doubled`, though they can do so. An implementation -of :meth:`draw` is necessary, though; the ABC can't provide +of :meth:`!draw_doubled`, though they can do so. An implementation +of :meth:`!draw` is necessary, though; the ABC can't provide a useful generic implementation. -You can apply the ``@abstractmethod`` decorator to methods such as -:meth:`draw` that must be implemented; Python will then raise an +You can apply the :deco:`~abc.abstractmethod` decorator to methods such as +:meth:`!draw` that must be implemented; Python will then raise an exception for classes that don't define the method. Note that the exception is only raised when you actually try to create an instance of a subclass lacking the method:: @@ -1288,7 +1299,7 @@ Abstract data attributes can be declared using the def readonly(self): return self._x -Subclasses must then define a :meth:`readonly` property. +Subclasses must then define a ``readonly`` property. .. seealso:: @@ -1528,8 +1539,8 @@ Some smaller changes made to the core Python language are: the :exc:`StopIteration` exception will be raised. (Backported in :issue:`2719`.) -* Tuples now have :meth:`index` and :meth:`count` methods matching the - list type's :meth:`index` and :meth:`count` methods:: +* Tuples now have :meth:`~tuple.index` and :meth:`~tuple.count` methods + matching the list type's :meth:`~list.index` and :meth:`~list.count` methods:: >>> t = (0,1,2,3,4,0,1,2) >>> t.index(3) @@ -2738,13 +2749,13 @@ numbers. .. ====================================================================== -The :mod:`future_builtins` module +The :mod:`!future_builtins` module -------------------------------------- Python 3.0 makes many changes to the repertoire of built-in functions, and most of the changes can't be introduced in the Python 2.x series because they would break compatibility. -The :mod:`future_builtins` module provides versions +The :mod:`!future_builtins` module provides versions of these built-in functions that can be imported when writing 3.0-compatible code. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index caed3192be8..7296296d144 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -858,8 +858,8 @@ Some smaller changes made to the core Python language are: .. XXX bytearray doesn't seem to be documented -* When using :class:`@classmethod ` and - :class:`@staticmethod ` to wrap +* When using :deco:`classmethod` and + :deco:`staticmethod` to wrap methods as class or static methods, the wrapper object now exposes the wrapped function as their :attr:`~method.__func__` attribute. @@ -1541,7 +1541,7 @@ changes, or look through the Subversion logs for all the details. buffer API, which fixed a test suite failure (fix by Antoine Pitrou; :issue:`7133`) and automatically set OpenSSL's :c:macro:`!SSL_MODE_AUTO_RETRY`, which will prevent an error - code being returned from :meth:`recv` operations that trigger an SSL + code being returned from :meth:`!recv` operations that trigger an SSL renegotiation (fix by Antoine Pitrou; :issue:`8222`). The :func:`~ssl.SSLContext.wrap_socket` constructor function now takes a @@ -2031,7 +2031,7 @@ version 1.3. Some of the new features are: * ElementTree's code for converting trees to a string has been significantly reworked, making it roughly twice as fast in many cases. The :meth:`ElementTree.write() ` - and :meth:`Element.write` methods now have a *method* parameter that can be + and :meth:`!Element.write` methods now have a *method* parameter that can be "xml" (the default), "html", or "text". HTML mode will output empty elements as ```` instead of ````, and text mode will skip over elements and only output the text chunks. If @@ -2044,7 +2044,7 @@ version 1.3. Some of the new features are: Namespace handling has also been improved. All ``xmlns:`` declarations are now output on the root element, not scattered throughout the resulting XML. You can set the default namespace for a tree - by setting the :attr:`default_namespace` attribute and can + by setting the :attr:`!default_namespace` attribute and can register new prefixes with :meth:`~xml.etree.ElementTree.register_namespace`. In XML mode, you can use the true/false *xml_declaration* parameter to suppress the XML declaration. @@ -2196,8 +2196,6 @@ Changes to Python's build process and to the C API include: locale-independent way. (Added by Eric Smith; :issue:`5793`.) - .. XXX these macros don't seem to be described in the c-api docs. - * Removed function: :c:func:`!PyEval_CallObject` is now only available as a macro. A function version was being kept around to preserve ABI linking compatibility, but that was in 1997; it can certainly be @@ -2234,7 +2232,7 @@ Changes to Python's build process and to the C API include: * When using the :c:type:`PyMemberDef` structure to define attributes of a type, Python will no longer let you try to delete or set a - :c:macro:`T_STRING_INPLACE` attribute. + :c:macro:`!T_STRING_INPLACE` attribute. .. rev 79644 @@ -2259,12 +2257,12 @@ Changes to Python's build process and to the C API include: :issue:`6491`.) * The :program:`configure` script now checks for floating-point rounding bugs - on certain 32-bit Intel chips and defines a :c:macro:`X87_DOUBLE_ROUNDING` + on certain 32-bit Intel chips and defines a :c:macro:`!X87_DOUBLE_ROUNDING` preprocessor definition. No code currently uses this definition, but it's available if anyone wishes to use it. (Added by Mark Dickinson; :issue:`2937`.) - :program:`configure` also now sets a :envvar:`LDCXXSHARED` Makefile + :program:`configure` also now sets a :envvar:`!LDCXXSHARED` Makefile variable for supporting C++ linking. (Contributed by Arfrever Frehtes Taifersar Arahesis; :issue:`1222585`.) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 1067601c652..4b092b13959 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -847,8 +847,8 @@ Other Language Changes respectively. (Contributed by Joshua Bronson, Daniel Pope, and Justin Wang in :issue:`31861`.) -* Static methods (:func:`@staticmethod `) and class methods - (:func:`@classmethod `) now inherit the method attributes +* Static methods (:deco:`staticmethod`) and class methods + (:deco:`classmethod`) now inherit the method attributes (``__module__``, ``__name__``, ``__qualname__``, ``__doc__``, ``__annotations__``) and have a new ``__wrapped__`` attribute. Moreover, static methods are now callable as regular functions. @@ -901,7 +901,7 @@ Improved Modules asyncio ------- -Add missing :meth:`~asyncio.events.AbstractEventLoop.connect_accepted_socket` +Add missing :meth:`~asyncio.loop.connect_accepted_socket` method. (Contributed by Alex Grönholm in :issue:`41332`.) @@ -933,7 +933,7 @@ Base32 Encoding with Extended Hex Alphabet. bdb --- -Add :meth:`~bdb.Breakpoint.clearBreakpoints` to reset all set breakpoints. +Add :meth:`!clearBreakpoints` to reset all set breakpoints. (Contributed by Irit Katriel in :issue:`24160`.) bisect @@ -1398,7 +1398,7 @@ A new verify flag :const:`~ssl.VERIFY_X509_PARTIAL_CHAIN` has been added. sqlite3 ------- -Add audit events for :func:`~sqlite3.connect/handle`, +Add audit events for :func:`~sqlite3.connect`, :meth:`~sqlite3.Connection.enable_load_extension`, and :meth:`~sqlite3.Connection.load_extension`. (Contributed by Erlend E. Aasland in :issue:`43762`.) @@ -1622,7 +1622,7 @@ Deprecated compatibility. Specifically, :meth:`!find_loader`/:meth:`!find_module` (superseded by :meth:`~importlib.abc.MetaPathFinder.find_spec`), - :meth:`~importlib.abc.Loader.load_module` + ``importlib.abc.Loader.load_module`` (superseded by :meth:`~importlib.abc.Loader.exec_module`), :meth:`!module_repr` (which the import system takes care of for you), the ``__package__`` attribute @@ -1652,7 +1652,7 @@ Deprecated preference for :meth:`~zipimport.zipimporter.exec_module`. (Contributed by Brett Cannon in :issue:`26131`.) -* The use of :meth:`~importlib.abc.Loader.load_module` by the import +* The use of ``importlib.abc.Loader.load_module`` by the import system now triggers an :exc:`ImportWarning` as :meth:`~importlib.abc.Loader.exec_module` is preferred. (Contributed by Brett Cannon in :issue:`26131`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index abf9677fd9c..a095d887352 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1292,7 +1292,7 @@ This section covers specific optimizations independent of the (Contributed by Stefan Behnel in :gh:`68264`.) * Resizing lists is streamlined for the common case, - speeding up :meth:`!list.append` by ≈15% + speeding up :meth:`list.append` by ≈15% and simple :term:`list comprehension`\s by up to 20-30% (Contributed by Dennis Sweeney in :gh:`91165`.) @@ -2673,7 +2673,7 @@ Removed (Contributed by Victor Stinner in :issue:`45474`.) -* Exclude :c:func:`PyWeakref_GET_OBJECT` from the limited C API. It never +* Exclude :c:func:`!PyWeakref_GET_OBJECT` from the limited C API. It never worked since the :c:type:`!PyWeakReference` structure is opaque in the limited C API. (Contributed by Victor Stinner in :issue:`35134`.) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 7cfdc287b7f..221956f3dd3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1191,9 +1191,23 @@ Deprecated replaced by :data:`calendar.JANUARY` and :data:`calendar.FEBRUARY`. (Contributed by Prince Roshan in :gh:`103636`.) -* :mod:`collections.abc`: Deprecated :class:`!collections.abc.ByteString`. - Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. - For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. +* :mod:`collections.abc`: Deprecated :class:`collections.abc.ByteString`. + + Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj`` implements + the :ref:`buffer protocol ` at runtime. For use in type + annotations, either use :class:`~collections.abc.Buffer` or a union + that explicitly specifies the types your code supports (e.g., + ``bytes | bytearray | memoryview``). + + :class:`!ByteString` was originally intended to be an abstract class that + would serve as a supertype of both :class:`bytes` and :class:`bytearray`. + However, since the ABC never had any methods, knowing that an object was an + instance of :class:`!ByteString` never actually told you anything useful + about the object. Other common buffer types such as :class:`memoryview` were + also never understood as subtypes of :class:`!ByteString` (either at + runtime or by static type checkers). + + See :pep:`PEP 688 <688#current-options>` for more details. (Contributed by Shantanu Jain in :gh:`91896`.) * :mod:`datetime`: :class:`datetime.datetime`'s :meth:`~datetime.datetime.utcnow` and @@ -1301,7 +1315,7 @@ Deprecated :class:`collections.abc.Hashable` and :class:`collections.abc.Sized` respectively, are deprecated. (:gh:`94309`.) - * :class:`!typing.ByteString`, deprecated since Python 3.9, now causes a + * :class:`typing.ByteString`, deprecated since Python 3.9, now causes a :exc:`DeprecationWarning` to be emitted when it is used. (Contributed by Alex Waygood in :gh:`91896`.) @@ -1323,7 +1337,7 @@ Deprecated it was :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) -* Setting :attr:`~module.__package__` or :attr:`~module.__cached__` on a +* Setting :attr:`~module.__package__` or ``__cached__`` on a module is deprecated, and will cease to be set or taken into consideration by the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.) @@ -1349,6 +1363,10 @@ Deprecated .. include:: ../deprecations/pending-removal-in-3.17.rst +.. include:: ../deprecations/pending-removal-in-3.19.rst + +.. include:: ../deprecations/pending-removal-in-3.20.rst + .. include:: ../deprecations/pending-removal-in-future.rst .. _whatsnew312-removed: diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 61f458d24e9..dc105156f33 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -60,7 +60,7 @@ Summary -- Release Highlights .. This section singles out the most important changes in Python 3.13. Brevity is key. -Python 3.13 is the latest stable release of the Python programming +Python 3.13 is a stable release of the Python programming language, with a mix of changes to the language, the implementation and the standard library. The biggest changes include a new `interactive interpreter @@ -1569,8 +1569,6 @@ and are now removed: * :pypi:`bcrypt`: Modern password hashing for your software and your servers. - * :pypi:`passlib`: - Comprehensive password hashing framework supporting over 30 schemes. * :pypi:`argon2-cffi`: The secure Argon2 password hashing algorithm. * :pypi:`legacycrypt`: @@ -1995,7 +1993,7 @@ New Deprecations use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. (Contributed by Alex Waygood in :gh:`105566` and :gh:`105570`.) - * Deprecate the :func:`typing.no_type_check_decorator` decorator function, + * Deprecate the :func:`!typing.no_type_check_decorator` decorator function, to be removed in Python 3.15. After eight years in the :mod:`typing` module, it has yet to be supported by any major type checker. @@ -2026,6 +2024,10 @@ New Deprecations .. include:: ../deprecations/pending-removal-in-3.17.rst +.. include:: ../deprecations/pending-removal-in-3.19.rst + +.. include:: ../deprecations/pending-removal-in-3.20.rst + .. include:: ../deprecations/pending-removal-in-future.rst CPython Bytecode Changes @@ -2176,7 +2178,7 @@ New Features (Contributed by Sam Gross in :gh:`114329`.) * Add the :c:func:`PyList_Extend` and :c:func:`PyList_Clear` functions, - mirroring the Python :meth:`!list.extend` and :meth:`!list.clear` methods. + mirroring the Python :meth:`list.extend` and :meth:`list.clear` methods. (Contributed by Victor Stinner in :gh:`111138`.) * Add the :c:func:`PyLong_AsInt` function. @@ -2246,7 +2248,7 @@ New Features (Contributed by Serhiy Storchaka in :gh:`110289`.) * Add the :c:func:`PyWeakref_GetRef` function - as an alternative to :c:func:`PyWeakref_GetObject` + as an alternative to :c:func:`!PyWeakref_GetObject` that returns a :term:`strong reference` or ``NULL`` if the referent is no longer live. (Contributed by Victor Stinner in :gh:`105927`.) @@ -2490,7 +2492,7 @@ Deprecated C APIs * Deprecate old Python initialization functions: - * :c:func:`PySys_ResetWarnOptions`: + * :c:func:`!PySys_ResetWarnOptions`: Clear :data:`sys.warnoptions` and :data:`!warnings.filters` instead. * :c:func:`!Py_GetExecPrefix`: Get :data:`sys.exec_prefix` instead. @@ -2531,8 +2533,8 @@ Deprecated C APIs are just aliases to :c:type:`!wchar_t`. (Contributed by Victor Stinner in :gh:`105156`.) -* Deprecate the :c:func:`PyWeakref_GetObject` and - :c:func:`PyWeakref_GET_OBJECT` functions, +* Deprecate the :c:func:`!PyWeakref_GetObject` and + :c:func:`!PyWeakref_GET_OBJECT` functions, which return a :term:`borrowed reference`. Replace them with the new :c:func:`PyWeakref_GetRef` function, which returns a :term:`strong reference`. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index aaa3487cb5c..9459b73bcb5 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1,8 +1,9 @@ + **************************** What's new in Python 3.14 **************************** -:Editor: Hugo van Kemenade +:Editors: Adam Turner and Hugo van Kemenade .. Rules for maintenance: @@ -45,458 +46,115 @@ when researching a change. This article explains the new features in Python 3.14, compared to 3.13. - +Python 3.14 was released on 7 October 2025. For full details, see the :ref:`changelog `. .. seealso:: :pep:`745` -- Python 3.14 release schedule -.. note:: - Prerelease users should be aware that this document is currently in draft - form. It will be updated substantially as Python 3.14 moves towards release, - so it's worth checking back even after reading earlier versions. - - -Summary -- release highlights +Summary -- Release highlights ============================= .. This section singles out the most important changes in Python 3.14. Brevity is key. -Python 3.14 will be the latest stable release of the Python -programming language, with a mix of changes to the language, the -implementation and the standard library. +Python 3.14 is the latest stable release of the Python programming +language, with a mix of changes to the language, the implementation, +and the standard library. +The biggest changes include :ref:`template string literals +`, +:ref:`deferred evaluation of annotations `, +and support for :ref:`subinterpreters ` in +the standard library. -The biggest changes to the implementation include template strings (:pep:`750`), -deferred evaluation of annotations (:pep:`649`), -and a new type of interpreter that uses tail calls. - -The library changes include the addition of a new :mod:`!annotationlib` module -for introspecting and wrapping annotations (:pep:`749`), -a new :mod:`!compression.zstd` module for Zstandard support (:pep:`784`), -plus syntax highlighting in the REPL, +The library changes include significantly improved capabilities for +:ref:`introspection in asyncio `, +:ref:`support for Zstandard ` via a new +:mod:`compression.zstd` module, syntax highlighting in the REPL, as well as the usual deprecations and removals, and improvements in user-friendliness and correctness. +This article doesn't attempt to provide a complete specification +of all new features, but instead gives a convenient overview. +For full details refer to the documentation, +such as the :ref:`Library Reference ` +and :ref:`Language Reference `. +To understand the complete implementation and design rationale for a change, +refer to the PEP for a particular new feature; +but note that PEPs usually are not kept up-to-date +once a feature has been fully implemented. +See `Porting to Python 3.14`_ for guidance on upgrading from +earlier versions of Python. + +-------------- + .. PEP-sized items next. -* :ref:`PEP 779: Free-threaded Python is officially supported ` -* :ref:`PEP 649 and 749: deferred evaluation of annotations ` -* :ref:`PEP 734: Multiple interpreters in the stdlib ` -* :ref:`PEP 741: Python configuration C API ` -* :ref:`PEP 750: Template strings ` -* :ref:`PEP 758: Allow except and except* expressions without parentheses ` -* :ref:`PEP 761: Discontinuation of PGP signatures ` -* :ref:`PEP 765: Disallow return/break/continue that exit a finally block ` +Interpreter improvements: + +* :pep:`649` and :pep:`749`: :ref:`Deferred evaluation of annotations + ` +* :pep:`734`: :ref:`Multiple interpreters in the standard library + ` +* :pep:`750`: :ref:`Template strings ` +* :pep:`758`: :ref:`Allow except and except* expressions without brackets + ` +* :pep:`765`: :ref:`Control flow in finally blocks + ` +* :pep:`768`: :ref:`Safe external debugger interface for CPython + ` +* :ref:`A new type of interpreter ` * :ref:`Free-threaded mode improvements ` -* :ref:`PEP 768: Safe external debugger interface for CPython ` -* :ref:`PEP 784: Adding Zstandard to the standard library ` -* :ref:`A new type of interpreter ` -* :ref:`Syntax highlighting in PyREPL `, - and color output in :ref:`unittest `, - :ref:`argparse `, - :ref:`json ` and - :ref:`calendar ` CLIs -* :ref:`Binary releases for the experimental just-in-time compiler ` +* :ref:`Improved error messages ` +* :ref:`Incremental garbage collection ` +Significant improvements in the standard library: -Incompatible changes -==================== +* :pep:`784`: :ref:`Zstandard support in the standard library + ` +* :ref:`whatsnew314-asyncio-introspection` +* :ref:`whatsnew314-concurrent-warnings-control` +* :ref:`Syntax highlighting in the default interactive shell + `, and color output in several + standard library CLIs -On platforms other than macOS and Windows, the default :ref:`start -method ` for :mod:`multiprocessing` -and :class:`~concurrent.futures.ProcessPoolExecutor` switches from -*fork* to *forkserver*. +C API improvements: -See :ref:`(1) ` and -:ref:`(2) ` for details. +* :pep:`741`: :ref:`Python configuration C API ` -If you encounter :exc:`NameError`\s or pickling errors coming out of -:mod:`multiprocessing` or :mod:`concurrent.futures`, see the -:ref:`forkserver restrictions `. +Platform support: + +* :pep:`776`: Emscripten is now an :ref:`officially supported platform + `, at :pep:`tier 3 <11#tier-3>`. + +Release changes: + +* :pep:`779`: :ref:`Free-threaded Python is officially supported + ` +* :pep:`761`: :ref:`PGP signatures have been discontinued for official releases + ` +* :ref:`Windows and macOS binary releases now support the experimental + just-in-time compiler ` +* :ref:`Binary releases for Android are now provided ` -The interpreter avoids some reference count modifications internally when -it's safe to do so. This can lead to different values returned from -:func:`sys.getrefcount` and :c:func:`Py_REFCNT` compared to previous versions -of Python. See :ref:`below ` for details. New features ============ -.. _whatsnew314-pep779: +.. _whatsnew314-deferred-annotations: -PEP 779: Free-threaded Python is officially supported ------------------------------------------------------ - -The free-threaded build of Python is now supported and no longer experimental. -This is the start of phase II where free-threaded Python is officially supported -but still optional. - -We are confident that the project is on the right path, and we appreciate the -continued dedication from everyone working to make free-threading ready for -broader adoption across the Python community. - -With these recommendations and the acceptance of this PEP, we as the Python -developer community should broadly advertise that free-threading is a supported -Python build option now and into the future, and that it will not be removed -without a proper deprecation schedule. - -Any decision to transition to phase III, with free-threading as the default or -sole build of Python is still undecided, and dependent on many factors both -within CPython itself and the community. This decision is for the future. - -.. seealso:: - :pep:`779` and its `acceptance - `__. - -.. _whatsnew314-pep734: - -PEP 734: Multiple interpreters in the stdlib --------------------------------------------- - -The CPython runtime supports running multiple copies of Python in the -same process simultaneously and has done so for over 20 years. -Each of these separate copies is called an "interpreter". -However, the feature had been available only through the C-API. - -That limitation is removed in the 3.14 release, -with the new :mod:`concurrent.interpreters` module. - -There are at least two notable reasons why using multiple interpreters -is worth considering: - -* they support a new (to Python), human-friendly concurrency model -* true multi-core parallelism - -For some use cases, concurrency in software enables efficiency and -can simplify software, at a high level. At the same time, implementing -and maintaining all but the simplest concurrency is often a struggle -for the human brain. That especially applies to plain threads -(for example, :mod:`threading`), where all memory is shared between all threads. - -With multiple isolated interpreters, you can take advantage of a class -of concurrency models, like CSP or the actor model, that have found -success in other programming languages, like Smalltalk, Erlang, -Haskell, and Go. Think of multiple interpreters like threads -but with opt-in sharing. - -Regarding multi-core parallelism: as of the 3.12 release, interpreters -are now sufficiently isolated from one another to be used in parallel. -(See :pep:`684`.) This unlocks a variety of CPU-intensive use cases -for Python that were limited by the :term:`GIL`. - -Using multiple interpreters is similar in many ways to -:mod:`multiprocessing`, in that they both provide isolated logical -"processes" that can run in parallel, with no sharing by default. -However, when using multiple interpreters, an application will use -fewer system resources and will operate more efficiently (since it -stays within the same process). Think of multiple interpreters as -having the isolation of processes with the efficiency of threads. - -.. XXX Add an example or two. -.. XXX Link to the not-yet-added HOWTO doc. - -While the feature has been around for decades, multiple interpreters -have not been used widely, due to low awareness and the lack of a stdlib -module. Consequently, they currently have several notable limitations, -which will improve significantly now that the feature is finally -going mainstream. - -Current limitations: - -* starting each interpreter has not been optimized yet -* each interpreter uses more memory than necessary - (we will be working next on extensive internal sharing between - interpreters) -* there aren't many options *yet* for truly sharing objects or other - data between interpreters (other than :type:`memoryview`) -* many extension modules on PyPI are not compatible with multiple - interpreters yet (stdlib extension modules *are* compatible) -* the approach to writing applications that use multiple isolated - interpreters is mostly unfamiliar to Python users, for now - -The impact of these limitations will depend on future CPython -improvements, how interpreters are used, and what the community solves -through PyPI packages. Depending on the use case, the limitations may -not have much impact, so try it out! - -Furthermore, future CPython releases will reduce or eliminate overhead -and provide utilities that are less appropriate on PyPI. In the -meantime, most of the limitations can also be addressed through -extension modules, meaning PyPI packages can fill any gap for 3.14, and -even back to 3.12 where interpreters were finally properly isolated and -stopped sharing the :term:`GIL`. Likewise, we expect to slowly see -libraries on PyPI for high-level abstractions on top of interpreters. - -Regarding extension modules, work is in progress to update some PyPI -projects, as well as tools like Cython, pybind11, nanobind, and PyO3. -The steps for isolating an extension module are found at -:ref:`isolating-extensions-howto`. Isolating a module has a lot of -overlap with what is required to support -:ref:`free-threading `, -so the ongoing work in the community in that area will help accelerate -support for multiple interpreters. - -Also added in 3.14: :ref:`concurrent.futures.InterpreterPoolExecutor -`. - -.. seealso:: - :pep:`734`. - - -.. _whatsnew314-pep750: - -PEP 750: Template strings -------------------------- - -Template string literals (t-strings) are a generalization of f-strings, -using a ``t`` in place of the ``f`` prefix. Instead of evaluating -to :class:`str`, t-strings evaluate to a new :class:`!string.templatelib.Template` type: - -.. code-block:: python - - from string.templatelib import Template - - name = "World" - template: Template = t"Hello {name}" - -The template can then be combined with functions that operate on the template's -structure to produce a :class:`str` or a string-like result. -For example, sanitizing input: - -.. code-block:: python - - evil = "" - template = t"

    {evil}

    " - assert html(template) == "

    <script>alert('evil')</script>

    " - -As another example, generating HTML attributes from data: - -.. code-block:: python - - attributes = {"src": "shrubbery.jpg", "alt": "looks nice"} - template = t"" - assert html(template) == 'looks nice' - -Compared to using an f-string, the ``html`` function has access to template attributes -containing the original information: static strings, interpolations, and values -from the original scope. Unlike existing templating approaches, t-strings build -from the well-known f-string syntax and rules. Template systems thus benefit -from Python tooling as they are much closer to the Python language, syntax, -scoping, and more. - -Writing template handlers is straightforward: - -.. code-block:: python - - from string.templatelib import Template, Interpolation - - def lower_upper(template: Template) -> str: - """Render static parts lowercased and interpolations uppercased.""" - parts: list[str] = [] - for item in template: - if isinstance(item, Interpolation): - parts.append(str(item.value).upper()) - else: - parts.append(item.lower()) - return "".join(parts) - - name = "world" - assert lower_upper(t"HELLO {name}") == "hello WORLD" - -With this in place, developers can write template systems to sanitize SQL, make -safe shell operations, improve logging, tackle modern ideas in web development -(HTML, CSS, and so on), and implement lightweight, custom business DSLs. - -(Contributed by Jim Baker, Guido van Rossum, Paul Everitt, Koudai Aono, -Lysandros Nikolaou, Dave Peck, Adam Turner, Jelle Zijlstra, Bénédikt Tran, -and Pablo Galindo Salgado in :gh:`132661`.) - -.. seealso:: - :pep:`750`. - - -.. _whatsnew314-pep768: - -PEP 768: Safe external debugger interface for CPython ------------------------------------------------------ - -:pep:`768` introduces a zero-overhead debugging interface that allows debuggers and profilers -to safely attach to running Python processes. This is a significant enhancement to Python's -debugging capabilities allowing debuggers to forego unsafe alternatives. See -:ref:`below ` for how this feature is leveraged to -implement the new :mod:`pdb` module's remote attaching capabilities. - -The new interface provides safe execution points for attaching debugger code without modifying -the interpreter's normal execution path or adding runtime overhead. This enables tools to -inspect and interact with Python applications in real-time without stopping or restarting -them — a crucial capability for high-availability systems and production environments. - -For convenience, CPython implements this interface through the :mod:`sys` module with a -:func:`sys.remote_exec` function:: - - sys.remote_exec(pid, script_path) - -This function allows sending Python code to be executed in a target process at the next safe -execution point. However, tool authors can also implement the protocol directly as described -in the PEP, which details the underlying mechanisms used to safely attach to running processes. - -Here's a simple example that inspects object types in a running Python process: - - .. code-block:: python - - import os - import sys - import tempfile - - # Create a temporary script - with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: - script_path = f.name - f.write(f"import my_debugger; my_debugger.connect({os.getpid()})") - try: - # Execute in process with PID 1234 - print("Behold! An offering:") - sys.remote_exec(1234, script_path) - finally: - os.unlink(script_path) - -The debugging interface has been carefully designed with security in mind and includes several -mechanisms to control access: - -* A :envvar:`PYTHON_DISABLE_REMOTE_DEBUG` environment variable. -* A :option:`-X disable-remote-debug` command-line option. -* A :option:`--without-remote-debug` configure flag to completely disable the feature at build time. - -A key implementation detail is that the interface piggybacks on the interpreter's existing evaluation -loop and safe points, ensuring zero overhead during normal execution while providing a reliable way -for external processes to coordinate debugging operations. - -(Contributed by Pablo Galindo Salgado, Matt Wozniski, and Ivona Stojanovic in :gh:`131591`.) - -.. seealso:: - :pep:`768`. - - -.. _whatsnew314-pep784: - -PEP 784: Adding Zstandard to the standard library -------------------------------------------------- - -The new ``compression`` package contains modules :mod:`!compression.lzma`, -:mod:`!compression.bz2`, :mod:`!compression.gzip` and :mod:`!compression.zlib` -which re-export the :mod:`lzma`, :mod:`bz2`, :mod:`gzip` and :mod:`zlib` -modules respectively. The new import names under ``compression`` are the -canonical names for importing these compression modules going forward. However, -the existing modules names have not been deprecated. Any deprecation or removal -of the existing compression modules will occur no sooner than five years after -the release of 3.14. - -The new :mod:`!compression.zstd` module provides compression and decompression -APIs for the Zstandard format via bindings to `Meta's zstd library -`__. Zstandard is a widely adopted, highly -efficient, and fast compression format. In addition to the APIs introduced in -:mod:`!compression.zstd`, support for reading and writing Zstandard compressed -archives has been added to the :mod:`tarfile`, :mod:`zipfile`, and -:mod:`shutil` modules. - -Here's an example of using the new module to compress some data: - -.. code-block:: python - - from compression import zstd - import math - - data = str(math.pi).encode() * 20 - - compressed = zstd.compress(data) - - ratio = len(compressed) / len(data) - print(f"Achieved compression ratio of {ratio}") - -As can be seen, the API is similar to the APIs of the :mod:`!lzma` and -:mod:`!bz2` modules. - -(Contributed by Emma Harper Smith, Adam Turner, Gregory P. Smith, Tomas Roun, -Victor Stinner, and Rogdham in :gh:`132983`.) - -.. seealso:: - :pep:`784`. - - -.. _whatsnew314-remote-pdb: - -Remote attaching to a running Python process with PDB ------------------------------------------------------ - -The :mod:`pdb` module now supports remote attaching to a running Python process -using a new ``-p PID`` command-line option: - -.. code-block:: sh - - python -m pdb -p 1234 - -This will connect to the Python process with the given PID and allow you to -debug it interactively. Notice that due to how the Python interpreter works -attaching to a remote process that is blocked in a system call or waiting for -I/O will only work once the next bytecode instruction is executed or when the -process receives a signal. - -This feature uses :pep:`768` and the :func:`sys.remote_exec` function -to attach to the remote process and send the PDB commands to it. - - -(Contributed by Matt Wozniski and Pablo Galindo in :gh:`131591`.) - -.. seealso:: - :pep:`768`. - - -.. _whatsnew314-pep758: - -PEP 758 – Allow except and except* expressions without parentheses ------------------------------------------------------------------- - -The :keyword:`except` and :keyword:`except* ` expressions now allow -parentheses to be omitted when there are multiple exception types and the ``as`` clause is not used. -For example the following expressions are now valid: - -.. code-block:: python - - try: - connect_to_server() - except TimeoutError, ConnectionRefusedError: - print("Network issue encountered.") - - # The same applies to except* (for exception groups): - - try: - connect_to_server() - except* TimeoutError, ConnectionRefusedError: - print("Network issue encountered.") - -Check :pep:`758` for more details. - -(Contributed by Pablo Galindo and Brett Cannon in :gh:`131831`.) - -.. seealso:: - :pep:`758`. - - -.. _whatsnew314-pep649: - -PEP 649 and 749: deferred evaluation of annotations ---------------------------------------------------- +:pep:`649` & :pep:`749`: Deferred evaluation of annotations +------------------------------------------------------------ The :term:`annotations ` on functions, classes, and modules are no longer evaluated eagerly. Instead, annotations are stored in special-purpose :term:`annotate functions ` and evaluated only when necessary (except if ``from __future__ import annotations`` is used). -This is specified in :pep:`649` and :pep:`749`. -This change is designed to make annotations in Python more performant and more -usable in most circumstances. The runtime cost for defining annotations is +This change is designed to improve performance and usability of annotations +in Python in most circumstances. The runtime cost for defining annotations is minimized, but it remains possible to introspect annotations at runtime. It is no longer necessary to enclose annotations in strings if they contain forward references. @@ -524,70 +182,344 @@ This example shows how these formats behave: >>> get_annotations(func, format=Format.STRING) {'arg': 'Undefined'} -Implications for annotated code -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The :ref:`porting ` section contains guidance +on changes that may be needed due to these changes, though in the majority of +cases, code will continue working as-is. -If you define annotations in your code (for example, for use with a static type -checker), then this change probably does not affect you: you can keep -writing annotations the same way you did with previous versions of Python. - -You will likely be able to remove quoted strings in annotations, which are frequently -used for forward references. Similarly, if you use ``from __future__ import annotations`` -to avoid having to write strings in annotations, you may well be able to -remove that import once you support only Python 3.14 and newer. -However, if you rely on third-party libraries that read annotations, -those libraries may need changes to support unquoted annotations before they -work as expected. - -Implications for readers of ``__annotations__`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If your code reads the ``__annotations__`` attribute on objects, you may want -to make changes in order to support code that relies on deferred evaluation of -annotations. For example, you may want to use :func:`annotationlib.get_annotations` -with the :attr:`~annotationlib.Format.FORWARDREF` format, as the :mod:`dataclasses` -module now does. - -The external :pypi:`typing_extensions` package provides partial backports of some of the -functionality of the :mod:`annotationlib` module, such as the :class:`~annotationlib.Format` -enum and the :func:`~annotationlib.get_annotations` function. These can be used to -write cross-version code that takes advantage of the new behavior in Python 3.14. - -Related changes -^^^^^^^^^^^^^^^ - -The changes in Python 3.14 are designed to rework how ``__annotations__`` -works at runtime while minimizing breakage to code that contains -annotations in source code and to code that reads ``__annotations__``. However, -if you rely on undocumented details of the annotation behavior or on private -functions in the standard library, there are many ways in which your code may -not work in Python 3.14. To safeguard your code against future changes, -use only the documented functionality of the :mod:`annotationlib` module. - -In particular, do not read annotations directly from the namespace dictionary -attribute of type objects. Use :func:`annotationlib.get_annotate_from_class_namespace` -during class construction and :func:`annotationlib.get_annotations` afterwards. - -In previous releases, it was sometimes possible to access class annotations from -an instance of an annotated class. This behavior was undocumented and accidental, -and will no longer work in Python 3.14. - -``from __future__ import annotations`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In Python 3.7, :pep:`563` introduced the ``from __future__ import annotations`` -directive, which turns all annotations into strings. This directive is now -considered deprecated and it is expected to be removed in a future version of Python. -However, this removal will not happen until after Python 3.13, the last version of -Python without deferred evaluation of annotations, reaches its end of life in 2029. -In Python 3.14, the behavior of code using ``from __future__ import annotations`` -is unchanged. - -(Contributed by Jelle Zijlstra in :gh:`119180`; :pep:`649` was written by Larry Hastings.) +(Contributed by Jelle Zijlstra in :pep:`749` and :gh:`119180`; +:pep:`649` was written by Larry Hastings.) .. seealso:: - :pep:`649` and :pep:`749`. + :pep:`649` + Deferred Evaluation Of Annotations Using Descriptors + :pep:`749` + Implementing PEP 649 + + +.. _whatsnew314-multiple-interpreters: + +:pep:`734`: Multiple interpreters in the standard library +--------------------------------------------------------- + +The CPython runtime supports running multiple copies of Python in the +same process simultaneously and has done so for over 20 years. +Each of these separate copies is called an 'interpreter'. +However, the feature had been available only through +the :ref:`C-API `. + +That limitation is removed in Python 3.14, +with the new :mod:`concurrent.interpreters` module. + +There are at least two notable reasons why using multiple interpreters +has significant benefits: + +* they support a new (to Python), human-friendly concurrency model +* true multi-core parallelism + +For some use cases, concurrency in software improves efficiency and +can simplify design, at a high level. +At the same time, implementing and maintaining all but the simplest concurrency +is often a struggle for the human brain. +That especially applies to plain threads (for example, :mod:`threading`), +where all memory is shared between all threads. + +With multiple isolated interpreters, you can take advantage of a class +of concurrency models, like Communicating Sequential Processes (CSP) +or the actor model, that have found +success in other programming languages, like Smalltalk, Erlang, +Haskell, and Go. Think of multiple interpreters as threads +but with opt-in sharing. + +Regarding multi-core parallelism: as of Python 3.12, interpreters +are now sufficiently isolated from one another to be used in parallel +(see :pep:`684`). This unlocks a variety of CPU-intensive use cases +for Python that were limited by the :term:`GIL`. + +Using multiple interpreters is similar in many ways to +:mod:`multiprocessing`, in that they both provide isolated logical +"processes" that can run in parallel, with no sharing by default. +However, when using multiple interpreters, an application will use +fewer system resources and will operate more efficiently (since it +stays within the same process). Think of multiple interpreters as +having the isolation of processes with the efficiency of threads. + +.. XXX Add an example or two. +.. XXX Link to the not-yet-added HOWTO doc. + +While the feature has been around for decades, multiple interpreters +have not been used widely, due to low awareness and the lack of a +standard library module. Consequently, they currently have several +notable limitations, which are expected to improve significantly now +that the feature is going mainstream. + +Current limitations: + +* starting each interpreter has not been optimized yet +* each interpreter uses more memory than necessary + (work continues on extensive internal sharing between interpreters) +* there aren't many options *yet* for truly sharing objects or other + data between interpreters (other than :type:`memoryview`) +* many third-party extension modules on PyPI are not yet compatible + with multiple interpreters + (all standard library extension modules *are* compatible) +* the approach to writing applications that use multiple isolated + interpreters is mostly unfamiliar to Python users, for now + +The impact of these limitations will depend on future CPython +improvements, how interpreters are used, and what the community solves +through PyPI packages. Depending on the use case, the limitations may +not have much impact, so try it out! + +Furthermore, future CPython releases will reduce or eliminate overhead +and provide utilities that are less appropriate on PyPI. In the +meantime, most of the limitations can also be addressed through +extension modules, meaning PyPI packages can fill any gap for 3.14, and +even back to 3.12 where interpreters were finally properly isolated and +stopped sharing the :term:`GIL`. Likewise, libraries on PyPI are expected +to emerge for high-level abstractions on top of interpreters. + +Regarding extension modules, work is in progress to update some PyPI +projects, as well as tools like Cython, pybind11, nanobind, and PyO3. +The steps for isolating an extension module are found at +:ref:`isolating-extensions-howto`. +Isolating a module has a lot of overlap with what is required to support +:ref:`free-threading `, so the ongoing +work in the community in that area will help accelerate support +for multiple interpreters. + +Also added in 3.14: :ref:`concurrent.futures.InterpreterPoolExecutor +`. + +(Contributed by Eric Snow in :gh:`134939`.) + +.. seealso:: :pep:`734` + + +.. _whatsnew314-template-string-literals: + +:pep:`750`: Template string literals +------------------------------------ + +Template strings are a new mechanism for custom string processing. +They share the familiar syntax of f-strings but, unlike f-strings, +return an object representing the static and interpolated parts of +the string, instead of a simple :class:`str`. + +To write a t-string, use a ``'t'`` prefix instead of an ``'f'``: + +.. doctest:: + + >>> variety = 'Stilton' + >>> template = t'Try some {variety} cheese!' + >>> type(template) + + +:class:`~string.templatelib.Template` objects provide access to the static +and interpolated (in curly braces) parts of a string *before* they are combined. +Iterate over :class:`!Template` instances to access their parts in order: + +.. testsetup:: + + variety = 'Stilton' + template = t'Try some {variety} cheese!' + +.. doctest:: + + >>> list(template) + ['Try some ', Interpolation('Stilton', 'variety', None, ''), ' cheese!'] + +It's easy to write (or call) code to process :class:`!Template` instances. +For example, here's a function that renders static parts lowercase and +:class:`~string.templatelib.Interpolation` instances uppercase: + +.. code-block:: python + + from string.templatelib import Interpolation + + def lower_upper(template): + """Render static parts lowercase and interpolations uppercase.""" + parts = [] + for part in template: + if isinstance(part, Interpolation): + parts.append(str(part.value).upper()) + else: + parts.append(part.lower()) + return ''.join(parts) + + name = 'Wenslydale' + template = t'Mister {name}' + assert lower_upper(template) == 'mister WENSLYDALE' + +Because :class:`!Template` instances distinguish between static strings and +interpolations at runtime, they can be useful for sanitising user input. +Writing a :func:`!html` function that escapes user input in HTML is an exercise +left to the reader! +Template processing code can provide improved flexibility. +For instance, a more advanced :func:`!html` function could accept +a :class:`!dict` of HTML attributes directly in the template: + +.. code-block:: python + + attributes = {'src': 'limburger.jpg', 'alt': 'lovely cheese'} + template = t'' + assert html(template) == 'lovely cheese' + +Of course, template processing code does not need to return a string-like result. +An even *more* advanced :func:`!html` could return a custom type representing +a DOM-like structure. + +With t-strings in place, developers can write systems that sanitise SQL, +make safe shell operations, improve logging, tackle modern ideas in web +development (HTML, CSS, and so on), and implement lightweight custom business DSLs. + +(Contributed by Jim Baker, Guido van Rossum, Paul Everitt, Koudai Aono, +Lysandros Nikolaou, Dave Peck, Adam Turner, Jelle Zijlstra, Bénédikt Tran, +and Pablo Galindo Salgado in :gh:`132661`.) + +.. seealso:: :pep:`750`. + + +.. _whatsnew314-remote-debugging: + +:pep:`768`: Safe external debugger interface +-------------------------------------------- + +Python 3.14 introduces a zero-overhead debugging interface that allows +debuggers and profilers to safely attach to running Python processes +without stopping or restarting them. +This is a significant enhancement to Python's debugging capabilities, +meaning that unsafe alternatives are no longer required. + +The new interface provides safe execution points for attaching debugger code +without modifying the interpreter's normal execution path +or adding any overhead at runtime. +Due to this, tools can now inspect and interact with Python applications +in real-time, which is a crucial capability for high-availability systems +and production environments. + +For convenience, this interface is implemented in the :func:`sys.remote_exec` +function. For example: + +.. code-block:: python + + import sys + from tempfile import NamedTemporaryFile + + with NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: + script_path = f.name + f.write(f'import my_debugger; my_debugger.connect({os.getpid()})') + + # Execute in process with PID 1234 + print('Behold! An offering:') + sys.remote_exec(1234, script_path) + + +This function allows sending Python code to be executed in a target process +at the next safe execution point. +However, tool authors can also implement the protocol directly as described +in the PEP, which details the underlying mechanisms used to safely attach to +running processes. + +The debugging interface has been carefully designed with security in mind +and includes several mechanisms to control access: + +* A :envvar:`PYTHON_DISABLE_REMOTE_DEBUG` environment variable. +* A :option:`-X disable-remote-debug` command-line option. +* A :option:`--without-remote-debug` configure flag to completely disable + the feature at build time. + +(Contributed by Pablo Galindo Salgado, Matt Wozniski, and Ivona Stojanovic +in :gh:`131591`.) + +.. seealso:: :pep:`768`. + + +.. _whatsnew314-tail-call-interpreter: + +A new type of interpreter +------------------------- + +A new type of interpreter has been added to CPython. +It uses tail calls between small C functions that implement individual +Python opcodes, rather than one large C ``case`` statement. +For certain newer compilers, this interpreter provides +significantly better performance. Preliminary benchmarks suggest a geometric +mean of 3-5% faster on the standard ``pyperformance`` benchmark suite, +depending on platform and architecture. +The baseline is Python 3.14 built with Clang 19, without this new interpreter. + +This interpreter currently only works with Clang 19 and newer +on x86-64 and AArch64 architectures. +However, a future release of GCC is expected to support this as well. + +This feature is opt-in for now. Enabling profile-guided optimization is highly +recommendeded when using the new interpreter as it is the only configuration +that has been tested and validated for improved performance. +For further information, see :option:`--with-tail-call-interp`. + +.. note:: + + This is not to be confused with `tail call optimization`__ of Python + functions, which is currently not implemented in CPython. + + This new interpreter type is an internal implementation detail of the CPython + interpreter. It doesn't change the visible behavior of Python programs at + all. It can improve their performance, but doesn't change anything else. + + __ https://en.wikipedia.org/wiki/Tail_call + +(Contributed by Ken Jin in :gh:`128563`, with ideas on how to implement this +in CPython by Mark Shannon, Garrett Gu, Haoran Xu, and Josh Haberman.) + + +.. _whatsnew314-free-threaded-cpython: + +Free-threaded mode improvements +------------------------------- + +CPython's free-threaded mode (:pep:`703`), initially added in 3.13, +has been significantly improved in Python 3.14. +The implementation described in PEP 703 has been finished, including C API +changes, and temporary workarounds in the interpreter were replaced with +more permanent solutions. +The specializing adaptive interpreter (:pep:`659`) is now enabled +in free-threaded mode, which along with many other optimizations +greatly improves its performance. +The performance penalty on single-threaded code in free-threaded mode +is now roughly 5-10%, depending on the platform and C compiler used. + +From Python 3.14, when compiling extension modules for the free-threaded build of +CPython on Windows, the preprocessor variable ``Py_GIL_DISABLED`` now needs to +be specified by the build backend, as it will no longer be determined +automatically by the C compiler. For a running interpreter, the setting that +was used at compile time can be found using :func:`sysconfig.get_config_var`. + +The new :option:`-X context_aware_warnings <-X>` flag controls if +:ref:`concurrent safe warnings control ` +is enabled. The flag defaults to true for the free-threaded build +and false for the GIL-enabled build. + +A new :data:`~sys.flags.thread_inherit_context` flag has been added, +which if enabled means that threads created with :class:`threading.Thread` +start with a copy of the :class:`~contextvars.Context()` of the caller of +:meth:`~threading.Thread.start`. Most significantly, this makes the warning +filtering context established by :class:`~warnings.catch_warnings` be +"inherited" by threads (or asyncio tasks) started within that context. It also +affects other modules that use context variables, such as the :mod:`decimal` +context manager. +This flag defaults to true for the free-threaded build and false for +the GIL-enabled build. + +(Contributed by Sam Gross, Matt Page, Neil Schemenauer, Thomas Wouters, +Donghee Na, Kirill Podoprigora, Ken Jin, Itamar Oren, Brett Simmers, +Dino Viehland, Nathan Goldbaum, Ralf Gommers, Lysandros Nikolaou, Kumar Aditya, +Edgar Margffoy, and many others. +Some of these contributors are employed by Meta, which has continued to provide +significant engineering resources to support this project.) + + +.. _whatsnew314-improved-error-messages: Improved error messages ----------------------- @@ -608,47 +540,12 @@ Improved error messages ^^^^^^ SyntaxError: invalid syntax. Did you mean 'while'? - >>> asynch def fetch_data(): - ... pass - Traceback (most recent call last): - File "", line 1 - asynch def fetch_data(): - ^^^^^^ - SyntaxError: invalid syntax. Did you mean 'async'? - - >>> async def foo(): - ... awaid fetch_data() - Traceback (most recent call last): - File "", line 2 - awaid fetch_data() - ^^^^^ - SyntaxError: invalid syntax. Did you mean 'await'? - - >>> raisee ValueError("Error") - Traceback (most recent call last): - File "", line 1 - raisee ValueError("Error") - ^^^^^^ - SyntaxError: invalid syntax. Did you mean 'raise'? - While the feature focuses on the most common cases, some variations of misspellings may still result in regular syntax errors. (Contributed by Pablo Galindo in :gh:`132449`.) -* When an unpacking assignment fails due to an incorrect number of variables, the - error message prints the received number of values in more cases than before. - (Contributed by Tushar Sadhwani in :gh:`122239`.) - - .. code-block:: pycon - - >>> x, y, z = 1, 2, 3, 4 - Traceback (most recent call last): - File "", line 1, in - x, y, z = 1, 2, 3, 4 - ^^^^^^^ - ValueError: too many values to unpack (expected 3, got 4) - -* :keyword:`elif` statements that follow an :keyword:`else` block now have a specific error message. +* :keyword:`elif` statements that follow an :keyword:`else` block now have + a specific error message. (Contributed by Steele Farnsworth in :gh:`129902`.) .. code-block:: pycon @@ -664,11 +561,9 @@ Improved error messages ^^^^ SyntaxError: 'elif' block follows an 'else' block -* If a statement (:keyword:`pass`, :keyword:`del`, :keyword:`return`, - :keyword:`yield`, :keyword:`raise`, :keyword:`break`, :keyword:`continue`, - :keyword:`assert`, :keyword:`import`, :keyword:`from`) is passed to the - :ref:`if_expr` after :keyword:`else`, or one of :keyword:`pass`, - :keyword:`break`, or :keyword:`continue` is passed before :keyword:`if`, then the +* If a statement is passed to the :ref:`if_expr` after :keyword:`else`, + or one of :keyword:`pass`, :keyword:`break`, or :keyword:`continue` + is passed before :keyword:`if`, then the error message highlights where the :token:`~python-grammar:expression` is required. (Contributed by Sergey Miryanov in :gh:`129515`.) @@ -688,10 +583,9 @@ Improved error messages ^^^^^^^^ SyntaxError: expected expression before 'if', but statement is given - * When incorrectly closed strings are detected, the error message suggests - that the string may be intended to be part of the string. (Contributed by - Pablo Galindo in :gh:`88535`.) + that the string may be intended to be part of the string. + (Contributed by Pablo Galindo in :gh:`88535`.) .. code-block:: pycon @@ -700,8 +594,8 @@ Improved error messages SyntaxError: invalid syntax. Is this intended to be part of the string? * When strings have incompatible prefixes, the error now shows - which prefixes are incompatible. (Contributed by - Nikita Sobolev in :gh:`133197`.) + which prefixes are incompatible. + (Contributed by Nikita Sobolev in :gh:`133197`.) .. code-block:: pycon @@ -718,20 +612,11 @@ Improved error messages - Except handlers: ``except ... as ...`` - Pattern-match cases: ``case ... as ...`` - (Contributed by Nikita Sobolev in :gh:`123539`, - :gh:`123562`, and :gh:`123440`.) - - .. code-block:: pycon - - >>> import ast as arr[0] - File "", line 1 - import ast as arr[0] - ^^^^^^ - SyntaxError: cannot use subscript as import target + (Contributed by Nikita Sobolev in :gh:`123539`, :gh:`123562`, and :gh:`123440`.) * Improved error message when trying to add an instance of an unhashable type to - a :class:`dict` or :class:`set`. (Contributed by CF Bolz-Tereick and Victor Stinner - in :gh:`132828`.) + a :class:`dict` or :class:`set`. + (Contributed by CF Bolz-Tereick and Victor Stinner in :gh:`132828`.) .. code-block:: pycon @@ -751,66 +636,77 @@ Improved error messages ~^^^ TypeError: cannot use 'list' as a dict key (unhashable type: 'list') +* Improved error message when an object supporting the synchronous + context manager protocol is entered using :keyword:`async with` + instead of :keyword:`with`, + and vice versa for the asynchronous context manager protocol. + (Contributed by Bénédikt Tran in :gh:`128398`.) -.. _whatsnew314-pep741: -PEP 741: Python configuration C API ------------------------------------ +.. _whatsnew314-zstandard: -Add a :ref:`PyInitConfig C API ` to configure the Python -initialization without relying on C structures and the ability to make -ABI-compatible changes in the future. +:pep:`784`: Zstandard support in the standard library +----------------------------------------------------- -Complete the :pep:`587` :ref:`PyConfig C API ` by adding -:c:func:`PyInitConfig_AddModule` which can be used to add a built-in extension -module; a feature previously referred to as the “inittab”. +The new :mod:`!compression` package contains modules :mod:`!compression.lzma`, +:mod:`!compression.bz2`, :mod:`!compression.gzip` and :mod:`!compression.zlib` +which re-export the :mod:`lzma`, :mod:`bz2`, :mod:`gzip` and :mod:`zlib` +modules respectively. The new import names under :mod:`!compression` are the +preferred names for importing these compression modules from Python 3.14. However, +the existing modules names have not been deprecated. Any deprecation or removal +of the existing compression modules will occur no sooner than five years after +the release of 3.14. -Add :c:func:`PyConfig_Get` and :c:func:`PyConfig_Set` functions to get and set -the current runtime configuration. +The new :mod:`!compression.zstd` module provides compression and decompression +APIs for the Zstandard format via bindings to `Meta's zstd library +`__. Zstandard is a widely adopted, highly +efficient, and fast compression format. In addition to the APIs introduced in +:mod:`!compression.zstd`, support for reading and writing Zstandard compressed +archives has been added to the :mod:`tarfile`, :mod:`zipfile`, and +:mod:`shutil` modules. -PEP 587 “Python Initialization Configuration” unified all the ways to configure -the Python initialization. This PEP unifies also the configuration of the -Python preinitialization and the Python initialization in a single API. -Moreover, this PEP only provides a single choice to embed Python, instead of -having two “Python” and “Isolated” choices (PEP 587), to simplify the API -further. +Here's an example of using the new module to compress some data: -The lower level PEP 587 PyConfig API remains available for use cases with an -intentionally higher level of coupling to CPython implementation details (such -as emulating the full functionality of CPython’s CLI, including its -configuration mechanisms). +.. code-block:: python -(Contributed by Victor Stinner in :gh:`107954`.) + from compression import zstd + import math + + data = str(math.pi).encode() * 20 + compressed = zstd.compress(data) + ratio = len(compressed) / len(data) + print(f"Achieved compression ratio of {ratio}") + +As can be seen, the API is similar to the APIs of the :mod:`!lzma` and +:mod:`!bz2` modules. + +(Contributed by Emma Harper Smith, Adam Turner, Gregory P. Smith, Tomas Roun, +Victor Stinner, and Rogdham in :gh:`132983`.) + +.. seealso:: :pep:`784`. -.. seealso:: - :pep:`741`. .. _whatsnew314-asyncio-introspection: Asyncio introspection capabilities ---------------------------------- -Added a new command-line interface to inspect running Python processes using -asynchronous tasks, available via: +Added a new command-line interface to inspect running Python processes +using asynchronous tasks, available via ``python -m asyncio ps PID`` +or ``python -m asyncio pstree PID``. -.. code-block:: bash +The ``ps`` subcommand inspects the given process ID (PID) and displays +information about currently running asyncio tasks. +It outputs a task table: a flat listing of all tasks, their names, +their coroutine stacks, and which tasks are awaiting them. - python -m asyncio ps PID -This tool inspects the given process ID (PID) and displays information about -currently running asyncio tasks. It outputs a task table: a flat -listing of all tasks, their names, their coroutine stacks, and which tasks are -awaiting them. - -.. code-block:: bash - - python -m asyncio pstree PID - -This tool fetches the same information, but renders a visual async call tree, -showing coroutine relationships in a hierarchical format. This command is -particularly useful for debugging long-running or stuck asynchronous programs. -It can help developers quickly identify where a program is blocked, what tasks -are pending, and how coroutines are chained together. +The ``pstree`` subcommand fetches the same information, but instead renders a +visual async call tree, showing coroutine relationships in a hierarchical format. +This command is particularly useful for debugging long-running or stuck +asynchronous programs. +It can help developers quickly identify where a program is blocked, +what tasks are pending, and how coroutines are chained together. For example given this code: @@ -818,23 +714,25 @@ For example given this code: import asyncio - async def play(track): + async def play_track(track): await asyncio.sleep(5) - print(f"🎵 Finished: {track}") + print(f'🎵 Finished: {track}') - async def album(name, tracks): + async def play_album(name, tracks): async with asyncio.TaskGroup() as tg: for track in tracks: - tg.create_task(play(track), name=track) + tg.create_task(play_track(track), name=track) async def main(): async with asyncio.TaskGroup() as tg: tg.create_task( - album("Sundowning", ["TNDNBTG", "Levitate"]), name="Sundowning") + play_album('Sundowning', ['TNDNBTG', 'Levitate']), + name='Sundowning') tg.create_task( - album("TMBTE", ["DYWTYLM", "Aqua Regia"]), name="TMBTE") + play_album('TMBTE', ['DYWTYLM', 'Aqua Regia']), + name='TMBTE') - if __name__ == "__main__": + if __name__ == '__main__': asyncio.run(main()) Executing the new tool on the running process will yield a table like this: @@ -899,165 +797,163 @@ prevent tree construction: (Contributed by Pablo Galindo, Łukasz Langa, Yury Selivanov, and Marta Gomez Macias in :gh:`91048`.) -.. _whatsnew314-tail-call: -A new type of interpreter -------------------------- - -A new type of interpreter has been added to CPython. -It uses tail calls between small C functions that implement individual -Python opcodes, rather than one large C case statement. -For certain newer compilers, this interpreter provides -significantly better performance. Preliminary numbers on our machines suggest -anywhere up to 30% faster Python code, and a geometric mean of 3-5% -faster on ``pyperformance`` depending on platform and architecture. The -baseline is Python 3.14 built with Clang 19 without this new interpreter. - -This interpreter currently only works with Clang 19 and newer -on x86-64 and AArch64 architectures. However, we expect -that a future release of GCC will support this as well. - -This feature is opt-in for now. We highly recommend enabling profile-guided -optimization with the new interpreter as it is the only configuration we have -tested and can validate its improved performance. -For further information on how to build Python, see -:option:`--with-tail-call-interp`. - -.. note:: - - This is not to be confused with `tail call optimization`__ of Python - functions, which is currently not implemented in CPython. - - This new interpreter type is an internal implementation detail of the CPython - interpreter. It doesn't change the visible behavior of Python programs at - all. It can improve their performance, but doesn't change anything else. - - __ https://en.wikipedia.org/wiki/Tail_call - -.. attention:: - - This section previously reported a 9-15% geometric mean speedup. This number has since been - cautiously revised down to 3-5%. While we expect performance results to be better - than what we report, our estimates are more conservative due to a - `compiler bug `_ found in - Clang/LLVM 19, which causes the normal interpreter to be slower. We were unaware of this bug, - resulting in inaccurate results. We sincerely apologize for - communicating results that were only accurate for LLVM v19.1.x and v20.1.0. In the meantime, - the bug has been fixed in LLVM v20.1.1 and for the upcoming v21.1, but it will remain - unfixed for LLVM v19.1.x and v20.1.0. Thus - any benchmarks with those versions of LLVM may produce inaccurate numbers. - (Thanks to Nelson Elhage for bringing this to light.) - -(Contributed by Ken Jin in :gh:`128563`, with ideas on how to implement this -in CPython by Mark Shannon, Garrett Gu, Haoran Xu, and Josh Haberman.) - -.. _whatsnew314-free-threaded-cpython: - -Free-threaded mode ------------------- - -Free-threaded mode (:pep:`703`), initially added in 3.13, has been significantly improved. -The implementation described in PEP 703 was finished, including C API changes, -and temporary workarounds in the interpreter were replaced with more permanent solutions. -The specializing adaptive interpreter (:pep:`659`) is now enabled in free-threaded mode, -which along with many other optimizations greatly improves its performance. -The performance penalty on single-threaded code in free-threaded mode is now roughly 5-10%, -depending on platform and C compiler used. - -This work was done by many contributors: Sam Gross, Matt Page, Neil Schemenauer, -Thomas Wouters, Donghee Na, Kirill Podoprigora, Ken Jin, Itamar Oren, -Brett Simmers, Dino Viehland, Nathan Goldbaum, Ralf Gommers, Lysandros Nikolaou, -Kumar Aditya, Edgar Margffoy, and many others. - -Some of these contributors are employed by Meta, which has continued to provide -significant engineering resources to support this project. - -From 3.14, when compiling extension modules for the free-threaded build of -CPython on Windows, the preprocessor variable ``Py_GIL_DISABLED`` now needs to -be specified by the build backend, as it will no longer be determined -automatically by the C compiler. For a running interpreter, the setting that -was used at compile time can be found using :func:`sysconfig.get_config_var`. - -A new flag has been added, :data:`~sys.flags.context_aware_warnings`. This -flag defaults to true for the free-threaded build and false for the GIL-enabled -build. If the flag is true then the :class:`warnings.catch_warnings` context -manager uses a context variable for warning filters. This makes the context -manager behave predictably when used with multiple threads or asynchronous -tasks. - -A new flag has been added, :data:`~sys.flags.thread_inherit_context`. This flag -defaults to true for the free-threaded build and false for the GIL-enabled -build. If the flag is true then threads created with :class:`threading.Thread` -start with a copy of the :class:`~contextvars.Context()` of the caller of -:meth:`~threading.Thread.start`. Most significantly, this makes the warning -filtering context established by :class:`~warnings.catch_warnings` be -"inherited" by threads (or asyncio tasks) started within that context. It also -affects other modules that use context variables, such as the :mod:`decimal` -context manager. - - -.. _whatsnew314-pyrepl-highlighting: - -Syntax highlighting in PyREPL ------------------------------ - -The default :term:`interactive` shell now highlights Python syntax as you -type. The feature is enabled by default unless the -:envvar:`PYTHON_BASIC_REPL` environment is set or any color-disabling -environment variables are used. See :ref:`using-on-controlling-color` for -details. - -The default color theme for syntax highlighting strives for good contrast -and uses exclusively the 4-bit VGA standard ANSI color codes for maximum -compatibility. The theme can be customized using an experimental API -``_colorize.set_theme()``. This can be called interactively, as well as -in the :envvar:`PYTHONSTARTUP` script. - -(Contributed by Łukasz Langa in :gh:`131507`.) - - -.. _whatsnew314-jit-compiler: - -Binary releases for the experimental just-in-time compiler ----------------------------------------------------------- - -The official macOS and Windows release binaries now include an *experimental* -just-in-time (JIT) compiler. Although it is **not** recommended for production -use, it can be tested by setting :envvar:`PYTHON_JIT=1 ` as an -environment variable. Downstream source builds and redistributors can use the -:option:`--enable-experimental-jit=yes-off` configuration option for similar -behavior. - -The JIT is at an early stage and still in active development. As such, the -typical performance impact of enabling it can range from 10% slower to 20% -faster, depending on workload. To aid in testing and evaluation, a set of -introspection functions has been provided in the :data:`sys._jit` namespace. -:func:`sys._jit.is_available` can be used to determine if the current executable -supports JIT compilation, while :func:`sys._jit.is_enabled` can be used to tell -if JIT compilation has been enabled for the current process. - -Currently, the most significant missing functionality is that native debuggers -and profilers like ``gdb`` and ``perf`` are unable to unwind through JIT frames -(Python debuggers and profilers, like :mod:`pdb` or :mod:`profile`, continue to -work without modification). Free-threaded builds do not support JIT compilation. - -Please report any bugs or major performance regressions that you encounter! - -.. seealso:: :pep:`744` +.. _whatsnew314-concurrent-warnings-control: Concurrent safe warnings control -------------------------------- The :class:`warnings.catch_warnings` context manager will now optionally -use a context variable for warning filters. This is enabled by setting +use a context variable for warning filters. This is enabled by setting the :data:`~sys.flags.context_aware_warnings` flag, either with the ``-X`` -command-line option or an environment variable. This gives predictable +command-line option or an environment variable. This gives predictable warnings control when using :class:`~warnings.catch_warnings` combined with multiple threads or asynchronous tasks. The flag defaults to true for the free-threaded build and false for the GIL-enabled build. (Contributed by Neil Schemenauer and Kumar Aditya in :gh:`130010`.) + +Other language changes +====================== + +* All Windows code pages are now supported as 'cpXXX' codecs on Windows. + (Contributed by Serhiy Storchaka in :gh:`123803`.) + +* Implement mixed-mode arithmetic rules combining real and complex numbers + as specified by the C standard since C99. + (Contributed by Sergey B Kirpichev in :gh:`69639`.) + +* More syntax errors are now detected regardless of optimisation and + the :option:`-O` command-line option. + This includes writes to ``__debug__``, incorrect use of :keyword:`await`, + and asynchronous comprehensions outside asynchronous functions. + For example, ``python -O -c 'assert (__debug__ := 1)'`` + or ``python -O -c 'assert await 1'`` now produce :exc:`SyntaxError`\ s. + (Contributed by Irit Katriel and Jelle Zijlstra in :gh:`122245` & :gh:`121637`.) + +* When subclassing a pure C type, the C slots for the new type + are no longer replaced with a wrapped version on class creation + if they are not explicitly overridden in the subclass. + (Contributed by Tomasz Pytel in :gh:`132284`.) + + +Built-ins +--------- + +* The :meth:`bytes.fromhex` and :meth:`bytearray.fromhex` methods now accept + ASCII :class:`bytes` and :term:`bytes-like objects `. + (Contributed by Daniel Pope in :gh:`129349`.) + +* Add class methods :meth:`float.from_number` and :meth:`complex.from_number` + to convert a number to :class:`float` or :class:`complex` type correspondingly. + They raise a :exc:`TypeError` if the argument is not a real number. + (Contributed by Serhiy Storchaka in :gh:`84978`.) + +* Support underscore and comma as thousands separators in the fractional part + for floating-point presentation types of the new-style string formatting + (with :func:`format` or :ref:`f-strings`). + (Contributed by Sergey B Kirpichev in :gh:`87790`.) + +* The :func:`int` function no longer delegates to :meth:`~object.__trunc__`. + Classes that want to support conversion to :func:`!int` must implement + either :meth:`~object.__int__` or :meth:`~object.__index__`. + (Contributed by Mark Dickinson in :gh:`119743`.) + +* The :func:`map` function now has an optional keyword-only *strict* flag + like :func:`zip` to check that all the iterables are of equal length. + (Contributed by Wannes Boeykens in :gh:`119793`.) + +* The :class:`memoryview` type now supports subscription, + making it a :term:`generic type`. + (Contributed by Brian Schubert in :gh:`126012`.) + +* Using :data:`NotImplemented` in a boolean context + will now raise a :exc:`TypeError`. + This has raised a :exc:`DeprecationWarning` since Python 3.9. + (Contributed by Jelle Zijlstra in :gh:`118767`.) + +* Three-argument :func:`pow` now tries calling :meth:`~object.__rpow__` + if necessary. + Previously it was only called in two-argument :func:`!pow` + and the binary power operator. + (Contributed by Serhiy Storchaka in :gh:`130104`.) + +* :class:`super` objects are now :mod:`copyable ` and :mod:`pickleable + `. + (Contributed by Serhiy Storchaka in :gh:`125767`.) + + +Command line and environment +---------------------------- + +* The import time flag can now track modules that are already loaded ('cached'), + via the new :option:`-X importtime=2 <-X>`. + When such a module is imported, the ``self`` and ``cumulative`` times + are replaced by the string ``cached``. + + Values above ``2`` for ``-X importtime`` are now reserved for future use. + + (Contributed by Noah Kim and Adam Turner in :gh:`118655`.) + +* The command-line option :option:`-c` now automatically dedents its code + argument before execution. The auto-dedentation behavior mirrors + :func:`textwrap.dedent`. + (Contributed by Jon Crall and Steven Sun in :gh:`103998`.) + +* :option:`!-J` is no longer a reserved flag for Jython_, + and now has no special meaning. + (Contributed by Adam Turner in :gh:`133336`.) + + .. _Jython: https://www.jython.org/ + + +.. _whatsnew314-bracketless-except: + +PEP 758: Allow ``except`` and ``except*`` expressions without brackets +---------------------------------------------------------------------- + +The :keyword:`except` and :keyword:`except* ` expressions +now allow brackets to be omitted when there are multiple exception types +and the ``as`` clause is not used. +For example: + +.. code-block:: python + + try: + connect_to_server() + except TimeoutError, ConnectionRefusedError: + print('The network has ceased to be!') + +(Contributed by Pablo Galindo and Brett Cannon in :pep:`758` and :gh:`131831`.) + + +.. _whatsnew314-finally-syntaxwarning: + +PEP 765: Control flow in :keyword:`finally` blocks +-------------------------------------------------- + +The compiler now emits a :exc:`SyntaxWarning` when a :keyword:`return`, +:keyword:`break`, or :keyword:`continue` statement have the effect of +leaving a :keyword:`finally` block. +This change is specified in :pep:`765`. + +In situations where this change is inconvenient (such as those where the +warnings are redundant due to code linting), the :ref:`warning filter +` can be used to turn off all syntax warnings by adding +``ignore::SyntaxWarning`` as a filter. This can be specified in combination +with a filter that converts other warnings to errors (for example, passing +``-Werror -Wignore::SyntaxWarning`` as CLI options, or setting +``PYTHONWARNINGS=error,ignore::SyntaxWarning``). + +Note that applying such a filter at runtime using the :mod:`warnings` module +will only suppress the warning in code that is compiled *after* the filter is +adjusted. Code that is compiled prior to the filter adjustment (for example, +when a module is imported) will still emit the syntax warning. + +(Contributed by Irit Katriel in :gh:`130080`.) + + .. _whatsnew314-incremental-gc: Incremental garbage collection @@ -1081,157 +977,62 @@ The behavior of :func:`!gc.collect` changes slightly: (Contributed by Mark Shannon in :gh:`108362`.) -Platform support -================ -* :pep:`776`: Emscripten is now an officially supported platform at - :pep:`tier 3 <11#tier-3>`. As a part of this effort, more than 25 bugs in - `Emscripten libc`__ were fixed. Emscripten now includes support - for :mod:`ctypes`, :mod:`termios`, and :mod:`fcntl`, as well as - experimental support for :ref:`PyREPL `. +Default interactive shell +------------------------- - (Contributed by R. Hood Chatham in :gh:`127146`, :gh:`127683`, and :gh:`136931`.) +.. _whatsnew314-pyrepl-highlighting: - __ https://emscripten.org/docs/porting/emscripten-runtime-environment.html +* The default :term:`interactive` shell now highlights Python syntax. + The feature is enabled by default, save if :envvar:`PYTHON_BASIC_REPL` + or any other environment variable that disables colour is set. + See :ref:`using-on-controlling-color` for details. -Other language changes -====================== + The default color theme for syntax highlighting strives for good contrast + and exclusively uses the 4-bit VGA standard ANSI color codes for maximum + compatibility. The theme can be customized using an experimental API + :func:`!_colorize.set_theme`. + This can be called interactively or in the :envvar:`PYTHONSTARTUP` script. + Note that this function has no stability guarantees, + and may change or be removed. -* The default :term:`interactive` shell now supports import autocompletion. - This means that typing ``import foo`` and pressing ```` will suggest - modules starting with ``foo``. Similarly, typing ``from foo import b`` will - suggest submodules of ``foo`` starting with ``b``. Note that autocompletion - of module attributes is not currently supported. + (Contributed by Łukasz Langa in :gh:`131507`.) + +* The default :term:`interactive` shell now supports import auto-completion. + This means that typing ``import co`` and pressing :kbd:`` will suggest + modules starting with ``co``. Similarly, typing ``from concurrent import i`` + will suggest submodules of ``concurrent`` starting with ``i``. + Note that autocompletion of module attributes is not currently supported. (Contributed by Tomas Roun in :gh:`69605`.) -* The :func:`map` built-in now has an optional keyword-only *strict* flag - like :func:`zip` to check that all the iterables are of equal length. - (Contributed by Wannes Boeykens in :gh:`119793`.) - -* Incorrect usage of :keyword:`await` and asynchronous comprehensions - is now detected even if the code is optimized away by the :option:`-O` - command-line option. For example, ``python -O -c 'assert await 1'`` - now produces a :exc:`SyntaxError`. (Contributed by Jelle Zijlstra in :gh:`121637`.) - -* Writes to ``__debug__`` are now detected even if the code is optimized - away by the :option:`-O` command-line option. For example, - ``python -O -c 'assert (__debug__ := 1)'`` now produces a - :exc:`SyntaxError`. (Contributed by Irit Katriel in :gh:`122245`.) - -* Add class methods :meth:`float.from_number` and :meth:`complex.from_number` - to convert a number to :class:`float` or :class:`complex` type correspondingly. - They raise an error if the argument is a string. - (Contributed by Serhiy Storchaka in :gh:`84978`.) - -* Implement mixed-mode arithmetic rules combining real and complex numbers as - specified by C standards since C99. - (Contributed by Sergey B Kirpichev in :gh:`69639`.) - -* All Windows code pages are now supported as "cpXXX" codecs on Windows. - (Contributed by Serhiy Storchaka in :gh:`123803`.) - -* :class:`super` objects are now :mod:`pickleable ` and - :mod:`copyable `. - (Contributed by Serhiy Storchaka in :gh:`125767`.) - -* The :class:`memoryview` type now supports subscription, - making it a :term:`generic type`. - (Contributed by Brian Schubert in :gh:`126012`.) - -* Support underscore and comma as thousands separators in the fractional part - for floating-point presentation types of the new-style string formatting - (with :func:`format` or :ref:`f-strings`). - (Contributed by Sergey B Kirpichev in :gh:`87790`.) - -* The :func:`bytes.fromhex` and :func:`bytearray.fromhex` methods now accept - ASCII :class:`bytes` and :term:`bytes-like objects `. - (Contributed by Daniel Pope in :gh:`129349`.) - -* Support ``\z`` as a synonym for ``\Z`` in :mod:`regular expressions `. - It is interpreted unambiguously in many other regular expression engines, - unlike ``\Z``, which has subtly different behavior. - (Contributed by Serhiy Storchaka in :gh:`133306`.) - -* ``\B`` in :mod:`regular expression ` now matches the empty input string. - Now it is always the opposite of ``\b``. - (Contributed by Serhiy Storchaka in :gh:`124130`.) - -* iOS and macOS apps can now be configured to redirect ``stdout`` and - ``stderr`` content to the system log. (Contributed by Russell Keith-Magee in - :gh:`127592`.) - -* The iOS testbed is now able to stream test output while the test is running. - The testbed can also be used to run the test suite of projects other than - CPython itself. (Contributed by Russell Keith-Magee in :gh:`127592`.) - -* Three-argument :func:`pow` now tries calling :meth:`~object.__rpow__` if - necessary. Previously it was only called in two-argument :func:`!pow` and the - binary power operator. - (Contributed by Serhiy Storchaka in :gh:`130104`.) - -* Add a built-in implementation for HMAC (:rfc:`2104`) using formally verified - code from the `HACL* `__ project. - This implementation is used as a fallback when the OpenSSL implementation - of HMAC is not available. - (Contributed by Bénédikt Tran in :gh:`99108`.) - -* The import time flag can now track modules that are already loaded ('cached'), - via the new :option:`-X importtime=2 <-X>`. - When such a module is imported, the ``self`` and ``cumulative`` times - are replaced by the string ``cached``. - Values above ``2`` for ``-X importtime`` are now reserved for future use. - (Contributed by Noah Kim and Adam Turner in :gh:`118655`.) - -* When subclassing from a pure C type, the C slots for the new type are no - longer replaced with a wrapped version on class creation if they are not - explicitly overridden in the subclass. - (Contributed by Tomasz Pytel in :gh:`132329`.) - -* The command-line option :option:`-c` now automatically dedents its code - argument before execution. The auto-dedentation behavior mirrors - :func:`textwrap.dedent`. - (Contributed by Jon Crall and Steven Sun in :gh:`103998`.) - -* Improve error message when an object supporting the synchronous - context manager protocol is entered using :keyword:`async - with` instead of :keyword:`with`. - And vice versa with the asynchronous context manager protocol. - (Contributed by Bénédikt Tran in :gh:`128398`.) - -* :option:`!-J` is no longer a reserved flag for Jython_, - and now has no special meaning. - (Contributed by Adam Turner in :gh:`133336`.) - - .. _Jython: https://www.jython.org/ - -* The :func:`int` built-in no longer delegates to :meth:`~object.__trunc__`. - Classes that want to support conversion to :func:`!int` must implement - either :meth:`~object.__int__` or :meth:`~object.__index__`. - (Contributed by Mark Dickinson in :gh:`119743`.) - -* Using :data:`NotImplemented` in a boolean context - will now raise a :exc:`TypeError`. - This has raised a :exc:`DeprecationWarning` since Python 3.9. - (Contributed by Jelle Zijlstra in :gh:`118767`.) - - -.. _whatsnew314-pep765: - -PEP 765: Disallow ``return``/``break``/``continue`` that exit a ``finally`` block ---------------------------------------------------------------------------------- - -The compiler emits a :exc:`SyntaxWarning` when a :keyword:`return`, :keyword:`break` or -:keyword:`continue` statement appears where it exits a :keyword:`finally` block. -This change is specified in :pep:`765`. - New modules =========== -* :mod:`annotationlib`: For introspecting :term:`annotations `. - See :pep:`749` for more details. +* :mod:`annotationlib`: + For introspecting :term:`annotations `. + See :ref:`PEP 749 ` for more details. (Contributed by Jelle Zijlstra in :gh:`119180`.) +* :mod:`compression` (including :mod:`compression.zstd`): + A package for compression-related modules, + including a new module to support the Zstandard compression format. + See :ref:`PEP 784 ` for more details. + (Contributed by Emma Harper Smith, Adam Turner, Gregory P. Smith, Tomas Roun, + Victor Stinner, and Rogdham in :gh:`132983`.) + +* :mod:`concurrent.interpreters`: + Support for multiple interpreters in the standard library. + See :ref:`PEP 734 ` for more details. + (Contributed by Eric Snow in :gh:`134939`.) + +* :mod:`string.templatelib`: + Support for template string literals (t-strings). + See :ref:`PEP 750 ` for more details. + (Contributed by Jim Baker, Guido van Rossum, Paul Everitt, Koudai Aono, + Lysandros Nikolaou, Dave Peck, Adam Turner, Jelle Zijlstra, Bénédikt Tran, + and Pablo Galindo Salgado in :gh:`132661`.) + Improved modules ================ @@ -1249,8 +1050,6 @@ argparse and subparser names if mistyped by the user. (Contributed by Savannah Ostrowski in :gh:`124456`.) - .. _whatsnew314-color-argparse: - * Enable color for help text, which can be disabled with the optional *color* parameter to :class:`argparse.ArgumentParser`. This can also be controlled by :ref:`environment variables @@ -1261,7 +1060,7 @@ argparse ast --- -* Add :func:`ast.compare` for comparing two ASTs. +* Add :func:`~ast.compare`, a function for comparing two ASTs. (Contributed by Batuhan Taskaya and Jeremy Hylton in :gh:`60191`.) * Add support for :func:`copy.replace` for AST nodes. @@ -1270,15 +1069,17 @@ ast * Docstrings are now removed from an optimized AST in optimization level 2. (Contributed by Irit Katriel in :gh:`123958`.) -* The ``repr()`` output for AST nodes now includes more information. +* The :func:`repr` output for AST nodes now includes more information. (Contributed by Tomas Roun in :gh:`116022`.) -* :func:`ast.parse`, when called with an AST as input, now always verifies - that the root node type is appropriate. +* When called with an AST as input, the :func:`~ast.parse` function + now always verifies that the root node type is appropriate. (Contributed by Irit Katriel in :gh:`130139`.) -* Add new ``--feature-version``, ``--optimize``, ``--show-empty`` options to - the command-line interface. +* Add new options to the command-line interface: + :option:`--feature-version `, + :option:`--optimize `, and + :option:`--show-empty `. (Contributed by Semyon Moroz in :gh:`133367`.) @@ -1297,20 +1098,23 @@ asyncio :meth:`asyncio.create_task`, :meth:`asyncio.loop.create_task`, :meth:`asyncio.TaskGroup.create_task`. + (Contributed by Thomas Grainger in :gh:`128307`.) * There are two new utility functions for introspecting and printing a program's call graph: :func:`~asyncio.capture_call_graph` and :func:`~asyncio.print_call_graph`. + See :ref:`Asyncio introspection capabilities + ` for more details. (Contributed by Yury Selivanov, Pablo Galindo Salgado, and Łukasz Langa in :gh:`91048`.) - .. _whatsnew314-color-calendar: - calendar -------- +.. _whatsnew314-color-calendar: + * By default, today's date is highlighted in color in :mod:`calendar`'s :ref:`command-line ` text output. This can be controlled by :ref:`environment variables @@ -1323,19 +1127,25 @@ concurrent.futures .. _whatsnew314-concurrent-futures-interp-pool: -* Add :class:`~concurrent.futures.InterpreterPoolExecutor`, - which exposes "subinterpreters" (multiple Python interpreters in the - same process) to Python code. This is separate from the proposed API - in :pep:`734`. +* Add a new executor class, :class:`~concurrent.futures.InterpreterPoolExecutor`, + which exposes multiple Python interpreters in the same process + ('subinterpreters') to Python code. + This uses a pool of independent Python interpreters to execute calls + asynchronously. + + This is separate from the new :mod:`~concurrent.interpreters` module + introduced by :ref:`PEP 734 `. (Contributed by Eric Snow in :gh:`124548`.) .. _whatsnew314-concurrent-futures-start-method: -* The default :class:`~concurrent.futures.ProcessPoolExecutor` - :ref:`start method ` changed - from :ref:`fork ` to :ref:`forkserver - ` on platforms other than macOS and - Windows where it was already :ref:`spawn `. +* On Unix platforms other than macOS, :ref:`'forkserver' + ` is now the default :ref:`start + method ` for + :class:`~concurrent.futures.ProcessPoolExecutor` + (replacing :ref:`'fork' `). + This change does not affect Windows or macOS, where :ref:`'spawn' + ` remains the default start method. If the threading incompatible *fork* method is required, you must explicitly request it by supplying a multiprocessing context *mp_context* to @@ -1348,31 +1158,36 @@ concurrent.futures (Contributed by Gregory P. Smith in :gh:`84559`.) -* Add :meth:`concurrent.futures.ProcessPoolExecutor.terminate_workers` and - :meth:`concurrent.futures.ProcessPoolExecutor.kill_workers` as - ways to terminate or kill all living worker processes in the given pool. +* Add two new methods to :class:`~concurrent.futures.ProcessPoolExecutor`, + :meth:`~concurrent.futures.ProcessPoolExecutor.terminate_workers` + and :meth:`~concurrent.futures.ProcessPoolExecutor.kill_workers`, + as ways to terminate or kill all living worker processes in the given pool. (Contributed by Charles Machalow in :gh:`130849`.) -* Add the optional ``buffersize`` parameter to - :meth:`concurrent.futures.Executor.map` to limit the number of submitted +* Add the optional *buffersize* parameter to :meth:`Executor.map + ` to limit the number of submitted tasks whose results have not yet been yielded. If the buffer is full, iteration over the *iterables* pauses until a result is yielded from the buffer. (Contributed by Enzo Bonnal and Josh Rosenberg in :gh:`74028`.) + configparser ------------ -* Security fix: will no longer write config files it cannot read. Attempting - to :meth:`configparser.ConfigParser.write` keys containing delimiters or - beginning with the section header pattern will raise a - :class:`configparser.InvalidWriteError`. +* :mod:`!configparser` will no longer write config files it cannot read, + to improve security. + Attempting to :meth:`~configparser.ConfigParser.write` keys containing + delimiters or beginning with the section header pattern will raise an + :class:`~configparser.InvalidWriteError`. (Contributed by Jacob Lincoln in :gh:`129270`.) + contextvars ----------- -* Support context manager protocol by :class:`contextvars.Token`. +* Support the :term:`context manager` protocol + for :class:`~contextvars.Token` objects. (Contributed by Andrew Svetlov in :gh:`129889`.) @@ -1380,8 +1195,8 @@ ctypes ------ * The layout of :ref:`bit fields ` - in :class:`~ctypes.Structure` and :class:`~ctypes.Union` - now matches platform defaults (GCC/Clang or MSVC) more closely. + in :class:`~ctypes.Structure` and :class:`~ctypes.Union` objects + is now a closer match to platform defaults (GCC/Clang or MSVC). In particular, fields no longer overlap. (Contributed by Matthias Görgens in :gh:`97702`.) @@ -1400,7 +1215,7 @@ ctypes * On Windows, the :func:`~ctypes.CopyComPointer` function is now public. (Contributed by Jun Komoda in :gh:`127275`.) -* :func:`ctypes.memoryview_at` now exists to create a +* Add :func:`~ctypes.memoryview_at`, a function to create a :class:`memoryview` object that refers to the supplied pointer and length. This works like :func:`ctypes.string_at` except it avoids a buffer copy, and is typically useful when implementing pure Python @@ -1408,7 +1223,7 @@ ctypes (Contributed by Rian Hunter in :gh:`112018`.) * Complex types, :class:`~ctypes.c_float_complex`, - :class:`~ctypes.c_double_complex` and :class:`~ctypes.c_longdouble_complex`, + :class:`~ctypes.c_double_complex`, and :class:`~ctypes.c_longdouble_complex`, are now available if both the compiler and the ``libffi`` library support complex C types. (Contributed by Sergey B Kirpichev in :gh:`61103`.) @@ -1418,50 +1233,57 @@ ctypes (Contributed by Brian Ward in :gh:`119349`.) * Move :func:`ctypes.POINTER` types cache from a global internal cache - (``_pointer_type_cache``) to the :attr:`ctypes._CData.__pointer_type__` - attribute of the corresponding :mod:`ctypes` types. + (``_pointer_type_cache``) to the :attr:`_CData.__pointer_type__ + ` attribute of the corresponding + :mod:`!ctypes` types. This will stop the cache from growing without limits in some situations. (Contributed by Sergey Miryanov in :gh:`100926`.) -* The :class:`ctypes.py_object` type now supports subscription, +* The :class:`~ctypes.py_object` type now supports subscription, making it a :term:`generic type`. (Contributed by Brian Schubert in :gh:`132168`.) -* :mod:`ctypes` now supports :term:`free-threading builds `. +* :mod:`!ctypes` now supports :term:`free-threading builds `. (Contributed by Kumar Aditya and Peter Bierma in :gh:`127945`.) + curses ------ * Add the :func:`~curses.assume_default_colors` function, a refinement of the :func:`~curses.use_default_colors` function which - allows to change the color pair ``0``. + allows changing the color pair ``0``. (Contributed by Serhiy Storchaka in :gh:`133139`.) + datetime -------- -* Add :meth:`datetime.time.strptime` and :meth:`datetime.date.strptime`. +* Add the :meth:`~datetime.date.strptime` method to the + :class:`datetime.date` and :class:`datetime.time` classes. (Contributed by Wannes Boeykens in :gh:`41431`.) + decimal ------- -* Add alternative :class:`~decimal.Decimal` constructor - :meth:`Decimal.from_number() `. +* Add :meth:`.Decimal.from_number` as an alternative constructor for + :class:`~decimal.Decimal`. (Contributed by Serhiy Storchaka in :gh:`121798`.) -* Expose :func:`decimal.IEEEContext` to support creation of contexts +* Expose :func:`~decimal.IEEEContext` to support creation of contexts corresponding to the IEEE 754 (2008) decimal interchange formats. (Contributed by Sergey B Kirpichev in :gh:`53032`.) + difflib ------- * Comparison pages with highlighted changes generated by the - :class:`difflib.HtmlDiff` class now support dark mode. + :class:`~difflib.HtmlDiff` class now support 'dark mode'. (Contributed by Jiahao Li in :gh:`129939`.) + dis --- @@ -1486,7 +1308,7 @@ dis errno ----- -* Add :data:`errno.EHWPOISON` error code. +* Add the :data:`~errno.EHWPOISON` error code constant. (Contributed by James Roy in :gh:`126585`.) @@ -1494,39 +1316,43 @@ faulthandler ------------ * Add support for printing the C stack trace on systems that - :ref:`support it ` via :func:`faulthandler.dump_c_stack` - or via the *c_stack* argument in :func:`faulthandler.enable`. + :ref:`support it ` via the new + :func:`~faulthandler.dump_c_stack` function or via the *c_stack* argument + in :func:`faulthandler.enable`. (Contributed by Peter Bierma in :gh:`127604`.) fnmatch ------- -* Added :func:`fnmatch.filterfalse` for excluding names matching a pattern. +* Add :func:`~fnmatch.filterfalse`, a function to reject names + matching a given pattern. (Contributed by Bénédikt Tran in :gh:`74598`.) fractions --------- -* Add support for converting any objects that have the - :meth:`!as_integer_ratio` method to a :class:`~fractions.Fraction`. +* A :class:`~fractions.Fraction` object may now be constructed from any + object with the :meth:`!as_integer_ratio` method. (Contributed by Serhiy Storchaka in :gh:`82017`.) -* Add alternative :class:`~fractions.Fraction` constructor - :meth:`Fraction.from_number() `. +* Add :meth:`.Fraction.from_number` as an alternative constructor for + :class:`~fractions.Fraction`. (Contributed by Serhiy Storchaka in :gh:`121797`.) functools --------- -* Add support to :func:`functools.partial` and - :func:`functools.partialmethod` for :data:`functools.Placeholder` sentinels - to reserve a place for positional arguments. +* Add the :data:`~functools.Placeholder` sentinel. + This may be used with the :func:`~functools.partial` + or :func:`~functools.partialmethod` functions to reserve a place + for positional arguments in the returned :ref:`partial object + `. (Contributed by Dominykas Grigonis in :gh:`119127`.) -* Allow the *initial* parameter of :func:`functools.reduce` to be passed +* Allow the *initial* parameter of :func:`~functools.reduce` to be passed as a keyword argument. (Contributed by Sayandip Dutta in :gh:`125916`.) @@ -1544,16 +1370,17 @@ getopt getpass ------- -* Support keyboard feedback by :func:`getpass.getpass` via the keyword-only - optional argument ``echo_char``. Placeholder characters are rendered whenever - a character is entered, and removed when a character is deleted. +* Support keyboard feedback in the :func:`~getpass.getpass` function via + the keyword-only optional argument *echo_char*. + Placeholder characters are rendered whenever a character is entered, + and removed when a character is deleted. (Contributed by Semyon Moroz in :gh:`77065`.) graphlib -------- -* Allow :meth:`graphlib.TopologicalSorter.prepare` to be called more than once +* Allow :meth:`.TopologicalSorter.prepare` to be called more than once as long as sorting has not started. (Contributed by Daniel Pope in :gh:`130914`.) @@ -1561,13 +1388,14 @@ graphlib heapq ----- -* Add functions for working with max-heaps: +* The :mod:`!heapq` module has improved support for working with max-heaps, + via the following new functions: - * :func:`heapq.heapify_max`, - * :func:`heapq.heappush_max`, - * :func:`heapq.heappop_max`, - * :func:`heapq.heapreplace_max` - * :func:`heapq.heappushpop_max` + * :func:`~heapq.heapify_max` + * :func:`~heapq.heappush_max` + * :func:`~heapq.heappop_max` + * :func:`~heapq.heapreplace_max` + * :func:`~heapq.heappushpop_max` hmac @@ -1575,6 +1403,8 @@ hmac * Add a built-in implementation for HMAC (:rfc:`2104`) using formally verified code from the `HACL* `__ project. + This implementation is used as a fallback when the OpenSSL implementation + of HMAC is not available. (Contributed by Bénédikt Tran in :gh:`99108`.) @@ -1590,9 +1420,12 @@ http the command-line interface (``python -m http.server``) through the following options: - * ``--tls-cert ``: Path to the TLS certificate file. - * ``--tls-key ``: Optional path to the private key file. - * ``--tls-password-file ``: Optional path to the password file for the private key. + * :option:`--tls-cert \ `: + Path to the TLS certificate file. + * :option:`--tls-key \ `: + Optional path to the private key file. + * :option:`--tls-password-file \ `: + Optional path to the password file for the private key. (Contributed by Semyon Moroz in :gh:`85162`.) @@ -1600,7 +1433,7 @@ http imaplib ------- -* Add :meth:`IMAP4.idle() `, implementing the IMAP4 +* Add :meth:`.IMAP4.idle`, implementing the IMAP4 ``IDLE`` command as defined in :rfc:`2177`. (Contributed by Forest in :gh:`55454`.) @@ -1608,15 +1441,16 @@ imaplib inspect ------- -* :func:`inspect.signature` takes a new argument *annotation_format* to control +* :func:`~inspect.signature` takes a new argument *annotation_format* to control the :class:`annotationlib.Format` used for representing annotations. (Contributed by Jelle Zijlstra in :gh:`101552`.) -* :meth:`inspect.Signature.format` takes a new argument *unquote_annotations*. - If true, string :term:`annotations ` are displayed without surrounding quotes. +* :meth:`.Signature.format` takes a new argument *unquote_annotations*. + If true, string :term:`annotations ` are displayed without + surrounding quotes. (Contributed by Jelle Zijlstra in :gh:`101552`.) -* Add function :func:`inspect.ispackage` to determine whether an object is a +* Add function :func:`~inspect.ispackage` to determine whether an object is a :term:`package` or not. (Contributed by Zhikang Yan in :gh:`125634`.) @@ -1628,7 +1462,7 @@ io :exc:`BlockingIOError` if the operation cannot immediately return bytes. (Contributed by Giovanni Siragusa in :gh:`109523`.) -* Add protocols :class:`io.Reader` and :class:`io.Writer` as simpler +* Add the :class:`~io.Reader` and :class:`~io.Writer` protocols as simpler alternatives to the pseudo-protocols :class:`typing.IO`, :class:`typing.TextIO`, and :class:`typing.BinaryIO`. (Contributed by Sebastian Rittau in :gh:`127648`.) @@ -1637,35 +1471,36 @@ io json ---- -* Add notes for JSON serialization errors that allow to identify the source - of the error. +* Add exception notes for JSON serialization errors that allow + identifying the source of the error. (Contributed by Serhiy Storchaka in :gh:`122163`.) -* Enable the :mod:`json` module to work as a script using the :option:`-m` - switch: :program:`python -m json`. +* Allow using the :mod:`json` module as a script using the :option:`-m` switch: + :program:`python -m json`. + This is now preferred to :program:`python -m json.tool`, + which is :term:`soft deprecated`. See the :ref:`JSON command-line interface ` documentation. (Contributed by Trey Hunner in :gh:`122873`.) - .. _whatsnew314-color-json: - * By default, the output of the :ref:`JSON command-line interface ` is highlighted in color. This can be controlled by :ref:`environment variables `. (Contributed by Tomas Roun in :gh:`131952`.) + linecache --------- -* :func:`linecache.getline` can retrieve source code for frozen modules. +* :func:`~linecache.getline` can now retrieve source code for frozen modules. (Contributed by Tian Gao in :gh:`131638`.) logging.handlers ---------------- -* :class:`logging.handlers.QueueListener` now implements the context - manager protocol, allowing it to be used in a :keyword:`with` statement. +* :class:`~logging.handlers.QueueListener` objects now support the + :term:`context manager` protocol. (Contributed by Charles Machalow in :gh:`132106`.) * :meth:`QueueListener.start ` now @@ -1683,14 +1518,13 @@ math mimetypes --------- -* Document the command-line for :mod:`mimetypes`. - It now exits with ``1`` on failure instead of ``0`` - and ``2`` on incorrect command-line parameters instead of ``1``. - Also, errors are printed to stderr instead of stdout and their text is made - tighter. +* Add a public :ref:`command-line ` for the module, + invoked via :program:`python -m mimetypes`. (Contributed by Oleg Iarygin and Hugo van Kemenade in :gh:`93096`.) -* Add MS and :rfc:`8081` MIME types for fonts: +* Add several new MIME types based on RFCs and common usage: + + .. rubric:: Microsoft and :rfc:`8081` MIME types for fonts * Embedded OpenType: ``application/vnd.ms-fontobject`` * OpenType Layout (OTF) ``font/otf`` @@ -1698,18 +1532,14 @@ mimetypes * WOFF 1.0 ``font/woff`` * WOFF 2.0 ``font/woff2`` - (Contributed by Sahil Prajapati and Hugo van Kemenade in :gh:`84852`.) - -* Add :rfc:`9559` MIME types for Matroska audiovisual data container - structures, containing: + .. rubric:: :rfc:`9559` MIME types for Matroska audiovisual + data container structures * audio with no video: ``audio/matroska`` (``.mka``) * video: ``video/matroska`` (``.mkv``) * stereoscopic video: ``video/matroska-3d`` (``.mk3d``) - (Contributed by Hugo van Kemenade in :gh:`89416`.) - -* Add MIME types for images with RFCs: + .. rubric:: Images with RFCs * :rfc:`1494`: CCITT Group 3 (``.g3``) * :rfc:`3362`: Real-time Facsimile, T.38 (``.t38``) @@ -1718,9 +1548,7 @@ mimetypes * :rfc:`4047`: Flexible Image Transport System (``.fits``) * :rfc:`7903`: Enhanced Metafile (``.emf``) and Windows Metafile (``.wmf``) - (Contributed by Hugo van Kemenade in :gh:`85957`.) - -* More MIME type changes: + .. rubric:: Other MIME type additions and changes * :rfc:`2361`: Change type for ``.avi`` to ``video/vnd.avi`` and for ``.wav`` to ``audio/vnd.wave`` @@ -1728,6 +1556,8 @@ mimetypes * :rfc:`5334`: Add Ogg media (``.oga``, ``.ogg`` and ``.ogx``) * :rfc:`6713`: Add gzip ``application/gzip`` (``.gz``) * :rfc:`9639`: Add FLAC ``audio/flac`` (``.flac``) + * :rfc:`9512` ``application/yaml`` MIME type for YAML files (``.yaml`` + and ``.yml``) * Add 7z ``application/x-7z-compressed`` (``.7z``) * Add Android Package ``application/vnd.android.package-archive`` (``.apk``) when not strict @@ -1750,11 +1580,9 @@ mimetypes * `W3C `__: Add EPUB ``application/epub+zip`` (``.epub``) - (Contributed by Hugo van Kemenade in :gh:`129965`.) - -* Add :rfc:`9512` ``application/yaml`` MIME type for YAML files (``.yaml`` - and ``.yml``). (Contributed by Sasha "Nelie" Chernykh and Hugo van Kemenade - in :gh:`132056`.) + (Contributed by Sahil Prajapati and Hugo van Kemenade in :gh:`84852`, + by Sasha "Nelie" Chernykh and Hugo van Kemenade in :gh:`132056`, + and by Hugo van Kemenade in :gh:`89416`, :gh:`85957`, and :gh:`129965`.) multiprocessing @@ -1762,14 +1590,16 @@ multiprocessing .. _whatsnew314-multiprocessing-start-method: -* The default :ref:`start method ` changed - from :ref:`fork ` to :ref:`forkserver - ` on platforms other than macOS and - Windows where it was already :ref:`spawn `. +* On Unix platforms other than macOS, :ref:`'forkserver' + ` is now the default :ref:`start + method ` + (replacing :ref:`'fork' `). + This change does not affect Windows or macOS, where :ref:`'spawn' + ` remains the default start method. If the threading incompatible *fork* method is required, you must explicitly - request it via a context from :func:`multiprocessing.get_context` (preferred) - or change the default via :func:`multiprocessing.set_start_method`. + request it via a context from :func:`~multiprocessing.get_context` (preferred) + or change the default via :func:`~multiprocessing.set_start_method`. See :ref:`forkserver restrictions ` for information and differences with the *fork* method and how this change @@ -1778,7 +1608,7 @@ multiprocessing (Contributed by Gregory P. Smith in :gh:`84559`.) -* :mod:`multiprocessing`'s ``"forkserver"`` start method now authenticates +* :mod:`multiprocessing`'s ``'forkserver'`` start method now authenticates its control socket to avoid solely relying on filesystem permissions to restrict what other processes could cause the forkserver to spawn workers and run code. @@ -1794,20 +1624,22 @@ multiprocessing (Contributed by Roy Hyunjin Han for :gh:`103134`.) * Add support for shared :class:`set` objects via - :meth:`SyncManager.set() `. - The :func:`set` in :func:`multiprocessing.Manager` method is now available. + :meth:`.SyncManager.set`. + The :func:`set` in :func:`~multiprocessing.Manager` method is now available. (Contributed by Mingyu Park in :gh:`129949`.) -* Add :func:`multiprocessing.Process.interrupt` which terminates the child +* Add the :meth:`~multiprocessing.Process.interrupt` + to :class:`multiprocessing.Process` objects, which terminates the child process by sending :py:const:`~signal.SIGINT`. This enables :keyword:`finally` clauses to print a stack trace for the terminated process. (Contributed by Artem Pulkin in :gh:`131913`.) + operator -------- -* Two new functions :func:`operator.is_none` and :func:`operator.is_not_none` - have been added, such that ``operator.is_none(obj)`` is equivalent +* Add :func:`~operator.is_none` and :func:`~operator.is_not_none` as a pair + of functions, such that ``operator.is_none(obj)`` is equivalent to ``obj is None`` and ``operator.is_not_none(obj)`` is equivalent to ``obj is not None``. (Contributed by Raymond Hettinger and Nico Mexis in :gh:`115808`.) @@ -1816,17 +1648,17 @@ operator os -- -* Add the :func:`os.reload_environ` function to update :data:`os.environ` and +* Add the :func:`~os.reload_environ` function to update :data:`os.environ` and :data:`os.environb` with changes to the environment made by :func:`os.putenv`, by :func:`os.unsetenv`, or made outside Python in the same process. (Contributed by Victor Stinner in :gh:`120057`.) * Add the :data:`~os.SCHED_DEADLINE` and :data:`~os.SCHED_NORMAL` constants - to the :mod:`os` module. + to the :mod:`!os` module. (Contributed by James Roy in :gh:`127688`.) -* Add the :func:`os.readinto` function to read into a +* Add the :func:`~os.readinto` function to read into a :ref:`buffer object ` from a file descriptor. (Contributed by Cody Maloney in :gh:`129205`.) @@ -1834,8 +1666,8 @@ os os.path ------- -* The *strict* parameter to :func:`os.path.realpath` accepts a new value, - :data:`os.path.ALLOW_MISSING`. +* The *strict* parameter to :func:`~os.path.realpath` accepts a new value, + :data:`~os.path.ALLOW_MISSING`. If used, errors other than :exc:`FileNotFoundError` will be re-raised; the resulting path can be missing but it will be free of symlinks. (Contributed by Petr Viktorin for :cve:`2025-4517`.) @@ -1854,8 +1686,8 @@ pathlib (Contributed by Barney Gale in :gh:`73991`.) -* Add :attr:`pathlib.Path.info` attribute, which stores an object - implementing the :class:`pathlib.types.PathInfo` protocol (also new). The +* Add the :attr:`~pathlib.Path.info` attribute, which stores an object + implementing the new :class:`pathlib.types.PathInfo` protocol. The object supports querying the file type and internally caching :func:`~os.stat` results. Path objects generated by :meth:`~pathlib.Path.iterdir` are initialized with file type information @@ -1866,7 +1698,26 @@ pathlib pdb --- -* Hardcoded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace`) now +* The :mod:`pdb` module now supports remote attaching to a running Python process + using a new :option:`-p PID ` command-line option: + + .. code-block:: sh + + python -m pdb -p 1234 + + This will connect to the Python process with the given PID and allow you to + debug it interactively. Notice that due to how the Python interpreter works + attaching to a remote process that is blocked in a system call or waiting for + I/O will only work once the next bytecode instruction is executed or when the + process receives a signal. + + This feature uses :ref:`PEP 768 ` + and the new :func:`sys.remote_exec` function to attach to the remote process + and send the PDB commands to it. + + (Contributed by Matt Wozniski and Pablo Galindo in :gh:`131591`.) + +* Hardcoded breakpoints (:func:`breakpoint` and :func:`~pdb.set_trace`) now reuse the most recent :class:`~pdb.Pdb` instance that calls :meth:`~pdb.Pdb.set_trace`, instead of creating a new one each time. As a result, all the instance specific data like :pdbcmd:`display` and @@ -1905,8 +1756,8 @@ pdb (Contributed by Tian Gao in :gh:`132576`.) * Source code displayed in :mod:`pdb` will be syntax-highlighted. This feature - can be controlled using the same methods as PyREPL, in addition to the newly - added ``colorize`` argument of :class:`pdb.Pdb`. + can be controlled using the same methods as the default :term:`interactive` + shell, in addition to the newly added ``colorize`` argument of :class:`pdb.Pdb`. (Contributed by Tian Gao and Łukasz Langa in :gh:`133355`.) @@ -1916,15 +1767,16 @@ pickle * Set the default protocol version on the :mod:`pickle` module to 5. For more details, see :ref:`pickle protocols `. -* Add notes for pickle serialization errors that allow to identify the source - of the error. +* Add exception notes for pickle serialization errors that allow + identifying the source of the error. (Contributed by Serhiy Storchaka in :gh:`122213`.) platform -------- -* Add :func:`platform.invalidate_caches` to invalidate the cached results. +* Add :func:`~platform.invalidate_caches`, a function to invalidate + cached results in the :mod:`!platform` module. (Contributed by Bénédikt Tran in :gh:`122549`.) @@ -1936,6 +1788,19 @@ pydoc (Contributed by Jelle Zijlstra in :gh:`101552`.) +re +-- + +* Support ``\z`` as a synonym for ``\Z`` in :mod:`regular expressions `. + It is interpreted unambiguously in many other regular expression engines, + unlike ``\Z``, which has subtly different behavior. + (Contributed by Serhiy Storchaka in :gh:`133306`.) + +* ``\B`` in :mod:`regular expression ` now matches the empty input string, + meaning that it is now always the opposite of ``\b``. + (Contributed by Serhiy Storchaka in :gh:`124130`.) + + socket ------ @@ -1962,11 +1827,12 @@ socket * Add many new constants. (Contributed by Serhiy Storchaka in :gh:`132734`.) + ssl --- -* Indicate through :data:`ssl.HAS_PHA` whether the :mod:`ssl` module supports - TLSv1.3 post-handshake client authentication (PHA). +* Indicate through the :data:`~ssl.HAS_PHA` Boolean whether the :mod:`!ssl` + module supports TLSv1.3 post-handshake client authentication (PHA). (Contributed by Will Childs-Klein in :gh:`128036`.) @@ -1982,7 +1848,7 @@ struct symtable -------- -* Expose the following :class:`symtable.Symbol` methods: +* Expose the following :class:`~symtable.Symbol` methods: * :meth:`~symtable.Symbol.is_comp_cell` * :meth:`~symtable.Symbol.is_comp_iter` @@ -1997,28 +1863,41 @@ sys * The previously undocumented special function :func:`sys.getobjects`, which only exists in specialized builds of Python, may now return objects from other interpreters than the one it's called in. + (Contributed by Eric Snow in :gh:`125286`.) * Add :func:`sys._is_immortal` for determining if an object is :term:`immortal`. (Contributed by Peter Bierma in :gh:`128509`.) -* On FreeBSD, :data:`sys.platform` doesn't contain the major version anymore. +* On FreeBSD, :data:`sys.platform` no longer contains the major version number. It is always ``'freebsd'``, instead of ``'freebsd13'`` or ``'freebsd14'``. + (Contributed by Michael Osipov in :gh:`129393`.) * Raise :exc:`DeprecationWarning` for :func:`sys._clear_type_cache`. This function was deprecated in Python 3.13 but it didn't raise a runtime warning. +* Add :func:`sys.remote_exec` to implement the new external debugger interface. + See :ref:`PEP 768 ` for details. + (Contributed by Pablo Galindo Salgado, Matt Wozniski, and Ivona Stojanovic + in :gh:`131591`.) + +* Add the :data:`sys._jit` namespace, containing utilities for introspecting + just-in-time compilation. + (Contributed by Brandt Bucher in :gh:`133231`.) + sys.monitoring -------------- -* Two new events are added: :monitoring-event:`BRANCH_LEFT` and - :monitoring-event:`BRANCH_RIGHT`. The ``BRANCH`` event is deprecated. +* Add two new monitoring events, :monitoring-event:`BRANCH_LEFT` and + :monitoring-event:`BRANCH_RIGHT`. + These replace and deprecate the :monitoring-event:`!BRANCH` event. + (Contributed by Mark Shannon in :gh:`122548`.) sysconfig --------- -* Add ``ABIFLAGS`` key to :func:`sysconfig.get_config_vars` on Windows. +* Add ``ABIFLAGS`` key to :func:`~sysconfig.get_config_vars` on Windows. (Contributed by Xuehai Pan in :gh:`131799`.) @@ -2028,15 +1907,18 @@ tarfile * :func:`~tarfile.data_filter` now normalizes symbolic link targets in order to avoid path traversal attacks. (Contributed by Petr Viktorin in :gh:`127987` and :cve:`2025-4138`.) + * :func:`~tarfile.TarFile.extractall` now skips fixing up directory attributes when a directory was removed or replaced by another kind of file. (Contributed by Petr Viktorin in :gh:`127987` and :cve:`2024-12718`.) + * :func:`~tarfile.TarFile.extract` and :func:`~tarfile.TarFile.extractall` now (re-)apply the extraction filter when substituting a link (hard or symbolic) with a copy of another archive member, and when fixing up directory attributes. The former raises a new exception, :exc:`~tarfile.LinkFallbackError`. (Contributed by Petr Viktorin for :cve:`2025-4330` and :cve:`2024-12718`.) + * :func:`~tarfile.TarFile.extract` and :func:`~tarfile.TarFile.extractall` no longer extract rejected members when :func:`~tarfile.TarFile.errorlevel` is zero. @@ -2056,17 +1938,18 @@ tkinter ------- * Make :mod:`tkinter` widget methods :meth:`!after` and :meth:`!after_idle` - accept arguments passed by keyword. + accept keyword arguments. (Contributed by Zhikang Yan in :gh:`126899`.) -* Add ability to specify name for :class:`!tkinter.OptionMenu` and +* Add ability to specify a name for :class:`!tkinter.OptionMenu` and :class:`!tkinter.ttk.OptionMenu`. (Contributed by Zhikang Yan in :gh:`130482`.) + turtle ------ -* Add context managers for :func:`turtle.fill`, :func:`turtle.poly` +* Add context managers for :func:`turtle.fill`, :func:`turtle.poly`, and :func:`turtle.no_animation`. (Contributed by Marie Roald and Yngve Mardal Moe in :gh:`126350`.) @@ -2084,44 +1967,59 @@ typing .. _whatsnew314-typing-union: -* :class:`types.UnionType` and :class:`typing.Union` are now aliases for each other, - meaning that both old-style unions (created with ``Union[int, str]``) and new-style - unions (``int | str``) now create instances of the same runtime type. This unifies - the behavior between the two syntaxes, but leads to some differences in behavior that +* The :class:`types.UnionType` and :class:`typing.Union` types are now + aliases for each other, meaning that both old-style unions + (created with ``Union[int, str]``) and new-style unions (``int | str``) + now create instances of the same runtime type. This unifies the behavior + between the two syntaxes, but leads to some differences in behavior that may affect users who introspect types at runtime: - - Both syntaxes for creating a union now produce the same string representation in - ``repr()``. For example, ``repr(Union[int, str])`` - is now ``"int | str"`` instead of ``"typing.Union[int, str]"``. - - Unions created using the old syntax are no longer cached. Previously, running - ``Union[int, str]`` multiple times would return the same object - (``Union[int, str] is Union[int, str]`` would be ``True``), but now it will - return two different objects. Users should use ``==`` to compare unions for equality, not - ``is``. New-style unions have never been cached this way. - This change could increase memory usage for some programs that use a large number of - unions created by subscripting ``typing.Union``. However, several factors offset this cost: - unions used in annotations are no longer evaluated by default in Python 3.14 - because of :pep:`649`; an instance of :class:`types.UnionType` is - itself much smaller than the object returned by ``Union[]`` was on prior Python - versions; and removing the cache also saves some space. It is therefore - unlikely that this change will cause a significant increase in memory usage for most - users. + - Both syntaxes for creating a union now produce the same string + representation in :func:`repr`. + For example, ``repr(Union[int, str])`` is now ``"int | str"`` instead of + ``"typing.Union[int, str]"``. + + - Unions created using the old syntax are no longer cached. + Previously, running ``Union[int, str]`` multiple times would return + the same object (``Union[int, str] is Union[int, str]`` would be ``True``), + but now it will return two different objects. + Use ``==`` to compare unions for equality, not ``is``. + New-style unions have never been cached this way. + This change could increase memory usage for some programs that use + a large number of unions created by subscripting ``typing.Union``. + However, several factors offset this cost: + unions used in annotations are no longer evaluated by default in Python + 3.14 because of :pep:`649`; an instance of :class:`types.UnionType` is + itself much smaller than the object returned by ``Union[]`` was on prior + Python versions; and removing the cache also saves some space. + It is therefore unlikely that this change will cause a significant increase + in memory usage for most users. + - Previously, old-style unions were implemented using the private class - ``typing._UnionGenericAlias``. This class is no longer needed for the implementation, - but it has been retained for backward compatibility, with removal scheduled for Python - 3.17. Users should use documented introspection helpers like :func:`typing.get_origin` - and :func:`typing.get_args` instead of relying on private implementation details. - - It is now possible to use :class:`typing.Union` itself in :func:`isinstance` checks. - For example, ``isinstance(int | str, typing.Union)`` will return ``True``; previously - this raised :exc:`TypeError`. - - The ``__args__`` attribute of :class:`typing.Union` objects is no longer writable. - - It is no longer possible to set any attributes on :class:`typing.Union` objects. + ``typing._UnionGenericAlias``. + This class is no longer needed for the implementation, + but it has been retained for backward compatibility, + with removal scheduled for Python 3.17. + Users should use documented introspection helpers like + :func:`~typing.get_origin` and :func:`typing.get_args` instead of + relying on private implementation details. + + - It is now possible to use :class:`typing.Union` itself in + :func:`isinstance` checks. + For example, ``isinstance(int | str, typing.Union)`` will return ``True``; + previously this raised :exc:`TypeError`. + + - The :attr:`!__args__` attribute of :class:`typing.Union` objects is + no longer writable. + + - It is no longer possible to set any attributes on :class:`~typing.Union` + objects. This only ever worked for dunder attributes on previous versions, was never documented to work, and was subtly broken in many cases. (Contributed by Jelle Zijlstra in :gh:`105499`.) -* :class:`typing.TypeAliasType` now supports star unpacking. +* :class:`~typing.TypeAliasType` now supports star unpacking. unicodedata @@ -2130,11 +2028,11 @@ unicodedata * The Unicode database has been updated to Unicode 16.0.0. -.. _whatsnew314-color-unittest: - unittest -------- +.. _whatsnew314-color-unittest: + * :mod:`unittest` output is now colored by default. This can be controlled by :ref:`environment variables `. @@ -2172,7 +2070,7 @@ urllib * Improve ergonomics and standards compliance when parsing and emitting ``file:`` URLs. - In :func:`urllib.request.url2pathname`: + In :func:`~urllib.request.url2pathname`: - Accept a complete URL when the new *require_scheme* argument is set to true. @@ -2183,7 +2081,7 @@ urllib - Raise :exc:`~urllib.error.URLError` if a URL authority isn't local, except on Windows where we return a UNC path as before. - In :func:`urllib.request.pathname2url`: + In :func:`~urllib.request.pathname2url`: - Return a complete URL when the new *add_scheme* argument is set to true. - Include an empty URL authority when a path begins with a slash. For @@ -2199,16 +2097,17 @@ urllib uuid ---- -* Add support for UUID versions 6, 7, and 8 via :func:`uuid.uuid6`, - :func:`uuid.uuid7`, and :func:`uuid.uuid8` respectively, as specified +* Add support for UUID versions 6, 7, and 8 via :func:`~uuid.uuid6`, + :func:`~uuid.uuid7`, and :func:`~uuid.uuid8` respectively, as specified in :rfc:`9562`. (Contributed by Bénédikt Tran in :gh:`89083`.) -* :const:`uuid.NIL` and :const:`uuid.MAX` are now available to represent the +* :const:`~uuid.NIL` and :const:`~uuid.MAX` are now available to represent the Nil and Max UUID formats as defined by :rfc:`9562`. (Contributed by Nick Pope in :gh:`128427`.) -* Allow to generate multiple UUIDs at once via :option:`python -m uuid --count `. +* Allow generating multiple UUIDs simultaneously on the command-line via + :option:`python -m uuid --count `. (Contributed by Simon Legner in :gh:`131236`.) @@ -2226,14 +2125,13 @@ webbrowser zipfile ------- -* Added :func:`ZipInfo._for_archive ` +* Added :meth:`ZipInfo._for_archive `, a method to resolve suitable defaults for a :class:`~zipfile.ZipInfo` object as used by :func:`ZipFile.writestr `. (Contributed by Bénédikt Tran in :gh:`123424`.) -* :meth:`zipfile.ZipFile.writestr` now respects ``SOURCE_DATE_EPOCH`` that - distributions can set centrally and have build tools consume this in order - to produce reproducible output. +* :meth:`.ZipFile.writestr` now respects the :envvar:`SOURCE_DATE_EPOCH` + environment variable in order to better support reproducible builds. (Contributed by Jiahao Li in :gh:`91279`.) @@ -2253,12 +2151,18 @@ Optimizations (Contributed by Adam Turner, Bénédikt Tran, Chris Markiewicz, Eli Schwartz, Hugo van Kemenade, Jelle Zijlstra, and others in :gh:`118761`.) +* The interpreter now avoids some reference count modifications internally + when it's safe to do so. + This can lead to different values being returned from :func:`sys.getrefcount` + and :c:func:`Py_REFCNT` compared to previous versions of Python. + See :ref:`below ` for details. + asyncio ------- -* Standard benchmark results have improved by 10-20%, following the - implementation of a new per-thread double linked list +* Standard benchmark results have improved by 10-20% following the + implementation of a new per-thread doubly linked list for :class:`native tasks `, also reducing memory usage. This enables external introspection tools such as @@ -2561,14 +2465,6 @@ asyncio runner.run(operation_two()) -collections.abc ---------------- - -* Remove :class:`!ByteString`, which has been deprecated since Python 3.12. - (Contributed by Nikita Sobolev in :gh:`118803`.) - - - email ----- @@ -2647,13 +2543,6 @@ sqlite3 (Contributed by Erlend E. Aasland in :gh:`118928` and :gh:`101693`.) -typing ------- - -* Remove :class:`!ByteString`, which has been deprecated since Python 3.12. - (Contributed by Nikita Sobolev in :gh:`118803`.) - - urllib ------ @@ -2676,25 +2565,34 @@ urllib Deprecated ========== +New deprecations +---------------- + +* Passing a complex number as the *real* or *imag* argument in the + :func:`complex` constructor is now deprecated; + complex numbers should only be passed as a single positional argument. + (Contributed by Serhiy Storchaka in :gh:`109218`.) + * :mod:`argparse`: - * Passing the undocumented keyword argument *prefix_chars* to - :meth:`~argparse.ArgumentParser.add_argument_group` is now - deprecated. + * Passing the undocumented keyword argument *prefix_chars* to the + :meth:`~argparse.ArgumentParser.add_argument_group` method is now deprecated. (Contributed by Savannah Ostrowski in :gh:`125563`.) + * Deprecated the :class:`argparse.FileType` type converter. - Anything with resource management should be done downstream after the - arguments are parsed. + Anything relating to resource management should be handled + downstream, after the arguments have been parsed. (Contributed by Serhiy Storchaka in :gh:`58032`.) * :mod:`asyncio`: - * :func:`!asyncio.iscoroutinefunction` is deprecated + * The :func:`!asyncio.iscoroutinefunction` is now deprecated and will be removed in Python 3.16; use :func:`inspect.iscoroutinefunction` instead. (Contributed by Jiahao Li and Kumar Aditya in :gh:`122875`.) - * :mod:`asyncio` policy system is deprecated and will be removed in Python 3.16. + * The :mod:`asyncio` policy system is deprecated + and will be removed in Python 3.16. In particular, the following classes and functions are deprecated: * :class:`asyncio.AbstractEventLoopPolicy` @@ -2705,99 +2603,102 @@ Deprecated * :func:`asyncio.set_event_loop_policy` Users should use :func:`asyncio.run` or :class:`asyncio.Runner` with - *loop_factory* to use the desired event loop implementation. + the *loop_factory* argument to use the desired event loop implementation. - For example, to use :class:`asyncio.SelectorEventLoop` on Windows:: + For example, to use :class:`asyncio.SelectorEventLoop` on Windows: - import asyncio + .. code-block:: python - async def main(): - ... + import asyncio - asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop) + async def main(): + ... + + asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop) (Contributed by Kumar Aditya in :gh:`127949`.) -* :mod:`builtins`: - Passing a complex number as the *real* or *imag* argument in the - :func:`complex` constructor is now deprecated; it should only be passed - as a single positional argument. - (Contributed by Serhiy Storchaka in :gh:`109218`.) - * :mod:`codecs`: - :func:`codecs.open` is now deprecated. Use :func:`open` instead. + The :func:`codecs.open` function is now deprecated, + and will be removed in a future version of Python. + Use :func:`open` instead. (Contributed by Inada Naoki in :gh:`133036`.) * :mod:`ctypes`: * On non-Windows platforms, setting :attr:`.Structure._pack_` to use a - MSVC-compatible default memory layout is deprecated in favor of setting - :attr:`.Structure._layout_` to ``'ms'``. + MSVC-compatible default memory layout is now deprecated in favor of setting + :attr:`.Structure._layout_` to ``'ms'``, and will be removed in Python 3.19. (Contributed by Petr Viktorin in :gh:`131747`.) - * Calling :func:`ctypes.POINTER` on a string is deprecated. - Use :ref:`ctypes-incomplete-types` for self-referential structures. + * Calling :func:`ctypes.POINTER` on a string is now deprecated. + Use :ref:`incomplete types ` + for self-referential structures. Also, the internal ``ctypes._pointer_type_cache`` is deprecated. See :func:`ctypes.POINTER` for updated implementation details. (Contributed by Sergey Myrianov in :gh:`100926`.) * :mod:`functools`: Calling the Python implementation of :func:`functools.reduce` with *function* - or *sequence* as keyword arguments is now deprecated. + or *sequence* as keyword arguments is now deprecated; + the parameters will be made positional-only in Python 3.16. (Contributed by Kirill Podoprigora in :gh:`121676`.) * :mod:`logging`: - Support for custom logging handlers with the *strm* argument is deprecated - and scheduled for removal in Python 3.16. Define handlers with the *stream* - argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.) + Support for custom logging handlers with the *strm* argument + is now deprecated and scheduled for removal in Python 3.16. + Define handlers with the *stream* argument instead. + (Contributed by Mariusz Felisiak in :gh:`115032`.) * :mod:`mimetypes`: - Valid extensions start with a '.' or are empty for + Valid extensions are either empty or must start with '.' for :meth:`mimetypes.MimeTypes.add_type`. Undotted extensions are deprecated and will raise a :exc:`ValueError` in Python 3.16. (Contributed by Hugo van Kemenade in :gh:`75223`.) -* :mod:`!nturl2path`: This module is now deprecated. Call - :func:`urllib.request.url2pathname` and :func:`~urllib.request.pathname2url` - instead. +* :mod:`!nturl2path`: + This module is now deprecated. Call :func:`urllib.request.url2pathname` + and :func:`~urllib.request.pathname2url` instead. (Contributed by Barney Gale in :gh:`125866`.) * :mod:`os`: - :term:`Soft deprecate ` :func:`os.popen` and - :func:`os.spawn* ` functions. They should no longer be used to - write new code. The :mod:`subprocess` module is recommended instead. + The :func:`os.popen` and :func:`os.spawn* ` functions + are now :term:`soft deprecated`. + They should no longer be used to write new code. + The :mod:`subprocess` module is recommended instead. (Contributed by Victor Stinner in :gh:`120743`.) * :mod:`pathlib`: - :meth:`!pathlib.PurePath.as_uri` is deprecated and will be removed in Python - 3.19. Use :meth:`pathlib.Path.as_uri` instead. + :meth:`!pathlib.PurePath.as_uri` is now deprecated + and scheduled for removal in Python 3.19. + Use :meth:`pathlib.Path.as_uri` instead. (Contributed by Barney Gale in :gh:`123599`.) * :mod:`pdb`: The undocumented ``pdb.Pdb.curframe_locals`` attribute is now a deprecated - read-only property. The low overhead dynamic frame locals access added in - Python 3.13 by PEP 667 means the frame locals cache reference previously - stored in this attribute is no longer needed. Derived debuggers should access + read-only property, which will be removed in a future version of Python. + The low overhead dynamic frame locals access added in Python 3.13 by :pep:`667` + means the frame locals cache reference previously stored in this attribute + is no longer needed. Derived debuggers should access ``pdb.Pdb.curframe.f_locals`` directly in Python 3.13 and later versions. (Contributed by Tian Gao in :gh:`124369` and :gh:`125951`.) * :mod:`symtable`: - Deprecate :meth:`symtable.Class.get_methods` due to the lack of interest. + Deprecate :meth:`symtable.Class.get_methods` due to the lack of interest, + scheduled for removal in Python 3.16. (Contributed by Bénédikt Tran in :gh:`119698`.) * :mod:`tkinter`: The :class:`!tkinter.Variable` methods :meth:`!trace_variable`, :meth:`!trace_vdelete` and :meth:`!trace_vinfo` are now deprecated. - Use :meth:`!trace_add`, :meth:`!trace_remove` and :meth:`!trace_info` - instead. + Use :meth:`!trace_add`, :meth:`!trace_remove` and :meth:`!trace_info` instead. (Contributed by Serhiy Storchaka in :gh:`120220`.) * :mod:`urllib.parse`: Accepting objects with false values (like ``0`` and ``[]``) except empty - strings, byte-like objects and ``None`` in :mod:`urllib.parse` functions - :func:`~urllib.parse.parse_qsl` and :func:`~urllib.parse.parse_qs` is now - deprecated. + strings, bytes-like objects and ``None`` in :func:`~urllib.parse.parse_qsl` + and :func:`~urllib.parse.parse_qs` is now deprecated. (Contributed by Serhiy Storchaka in :gh:`116897`.) .. Add deprecations above alphabetically, not here at the end. @@ -2810,24 +2711,554 @@ Deprecated .. include:: ../deprecations/pending-removal-in-3.19.rst +.. include:: ../deprecations/pending-removal-in-3.20.rst + .. include:: ../deprecations/pending-removal-in-future.rst CPython bytecode changes ======================== -* Replaced the opcode ``BINARY_SUBSCR`` by :opcode:`BINARY_OP` with oparg ``NB_SUBSCR``. +* Replaced the opcode :opcode:`!BINARY_SUBSCR` by the :opcode:`BINARY_OP` + opcode with the ``NB_SUBSCR`` oparg. (Contributed by Irit Katriel in :gh:`100239`.) +* Add the :opcode:`BUILD_INTERPOLATION` and :opcode:`BUILD_TEMPLATE` + opcodes to construct new :class:`~string.templatelib.Interpolation` + and :class:`~string.templatelib.Template` instances, respectively. + (Contributed by Lysandros Nikolaou and others in :gh:`132661`; + see also :ref:`PEP 750: Template strings `). + +* Remove the :opcode:`!BUILD_CONST_KEY_MAP` opcode. + Use :opcode:`BUILD_MAP` instead. + (Contributed by Mark Shannon in :gh:`122160`.) + +* Replace the :opcode:`!LOAD_ASSERTION_ERROR` opcode with + :opcode:`LOAD_COMMON_CONSTANT` and add support for loading + :exc:`NotImplementedError`. + +* Add the :opcode:`LOAD_FAST_BORROW` and :opcode:`LOAD_FAST_BORROW_LOAD_FAST_BORROW` + opcodes to reduce reference counting overhead when the interpreter can prove + that the reference in the frame outlives the reference loaded onto the stack. + (Contributed by Matt Page in :gh:`130704`.) + +* Add the :opcode:`LOAD_SMALL_INT` opcode, which pushes a small integer + equal to the ``oparg`` to the stack. + The :opcode:`!RETURN_CONST` opcode is removed as it is no longer used. + (Contributed by Mark Shannon in :gh:`125837`.) + +* Add the new :opcode:`LOAD_SPECIAL` instruction. + Generate code for :keyword:`with` and :keyword:`async with` statements + using the new instruction. + Removed the :opcode:`!BEFORE_WITH` and :opcode:`!BEFORE_ASYNC_WITH` instructions. + (Contributed by Mark Shannon in :gh:`120507`.) + +* Add the :opcode:`POP_ITER` opcode to support 'virtual' iterators. + (Contributed by Mark Shannon in :gh:`132554`.) + + +Pseudo-instructions +------------------- + +* Add the :opcode:`!ANNOTATIONS_PLACEHOLDER` pseudo instruction + to support partially executed module-level annotations with + :ref:`deferred evaluation of annotations `. + (Contributed by Jelle Zijlstra in :gh:`130907`.) + +* Add the :opcode:`!BINARY_OP_EXTEND` pseudo instruction, + which executes a pair of functions (guard and specialization functions) + accessed from the inline cache. + (Contributed by Irit Katriel in :gh:`100239`.) + +* Add three specializations for :opcode:`CALL_KW`; + :opcode:`!CALL_KW_PY` for calls to Python functions, + :opcode:`!CALL_KW_BOUND_METHOD` for calls to bound methods, and + :opcode:`!CALL_KW_NON_PY` for all other calls. + (Contributed by Mark Shannon in :gh:`118093`.) + +* Add the :opcode:`JUMP_IF_TRUE` and :opcode:`JUMP_IF_FALSE` pseudo instructions, + conditional jumps which do not impact the stack. + Replaced by the sequence ``COPY 1``, ``TO_BOOL``, ``POP_JUMP_IF_TRUE/FALSE``. + (Contributed by Irit Katriel in :gh:`124285`.) + +* Add the :opcode:`!LOAD_CONST_MORTAL` pseudo instruction. + (Contributed by Mark Shannon in :gh:`128685`.) + +* Add the :opcode:`!LOAD_CONST_IMMORTAL` pseudo instruction, + which does the same as :opcode:`!LOAD_CONST`, but is more efficient + for immortal objects. + (Contributed by Mark Shannon in :gh:`125837`.) + +* Add the :opcode:`NOT_TAKEN` pseudo instruction, used by :mod:`sys.monitoring` + to record branch events (such as :monitoring-event:`BRANCH_LEFT`). + (Contributed by Mark Shannon in :gh:`122548`.) + + +C API changes +============= + +.. _whatsnew314-capi-config: + +Python configuration C API +-------------------------- + +Add a :ref:`PyInitConfig C API ` to configure the Python +initialization without relying on C structures and the ability to make +ABI-compatible changes in the future. + +Complete the :pep:`587` :ref:`PyConfig C API ` by adding +:c:func:`PyInitConfig_AddModule` which can be used to add a built-in extension +module; a feature previously referred to as the "inittab". + +Add :c:func:`PyConfig_Get` and :c:func:`PyConfig_Set` functions to get and set +the current runtime configuration. + +:pep:`587` 'Python Initialization Configuration' unified all the ways +to configure Python's initialization. This PEP also unifies the configuration +of Python's preinitialization and initialization in a single API. +Moreover, this PEP only provides a single choice to embed Python, +instead of having two 'Python' and 'Isolated' choices (PEP 587), +to further simplify the API. + +The lower level PEP 587 PyConfig API remains available for use cases +with an intentionally higher level of coupling to CPython implementation details +(such as emulating the full functionality of CPython's CLI, including its +configuration mechanisms). + +(Contributed by Victor Stinner in :gh:`107954`.) + +.. seealso:: :pep:`741` and :pep:`587` + + +New features in the C API +------------------------- + +* Add :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION`, + two new macros for bit-packing Python version numbers. + This is useful for comparisons with :c:var:`Py_Version` + or :c:macro:`PY_VERSION_HEX`. + (Contributed by Petr Viktorin in :gh:`128629`.) + +* Add :c:func:`PyBytes_Join(sep, iterable) ` function, + similar to ``sep.join(iterable)`` in Python. + (Contributed by Victor Stinner in :gh:`121645`.) + +* Add functions to manipulate the configuration of the current + runtime Python interpreter + (:ref:`PEP 741: Python configuration C API `): + + * :c:func:`PyConfig_Get` + * :c:func:`PyConfig_GetInt` + * :c:func:`PyConfig_Set` + * :c:func:`PyConfig_Names` + + (Contributed by Victor Stinner in :gh:`107954`.) + +* Add functions to configure Python initialization + (:ref:`PEP 741: Python configuration C API `): + + * :c:func:`Py_InitializeFromInitConfig` + * :c:func:`PyInitConfig_AddModule` + * :c:func:`PyInitConfig_Create` + * :c:func:`PyInitConfig_Free` + * :c:func:`PyInitConfig_FreeStrList` + * :c:func:`PyInitConfig_GetError` + * :c:func:`PyInitConfig_GetExitCode` + * :c:func:`PyInitConfig_GetInt` + * :c:func:`PyInitConfig_GetStr` + * :c:func:`PyInitConfig_GetStrList` + * :c:func:`PyInitConfig_HasOption` + * :c:func:`PyInitConfig_SetInt` + * :c:func:`PyInitConfig_SetStr` + * :c:func:`PyInitConfig_SetStrList` + + (Contributed by Victor Stinner in :gh:`107954`.) + +* Add :c:func:`Py_fopen` function to open a file. + This works similarly to the standard C :c:func:`!fopen` function, + instead accepting a Python object for the *path* parameter + and setting an exception on error. + The corresponding new :c:func:`Py_fclose` function should be used + to close a file. + (Contributed by Victor Stinner in :gh:`127350`.) + +* Add :c:func:`Py_HashBuffer` to compute and return the hash value of a buffer. + (Contributed by Antoine Pitrou and Victor Stinner in :gh:`122854`.) + +* Add :c:func:`PyImport_ImportModuleAttr` and + :c:func:`PyImport_ImportModuleAttrString` helper functions to import a module + and get an attribute of the module. + (Contributed by Victor Stinner in :gh:`128911`.) + +* Add :c:func:`PyIter_NextItem` to replace :c:func:`PyIter_Next`, + which has an ambiguous return value. + (Contributed by Irit Katriel and Erlend Aasland in :gh:`105201`.) + +* Add :c:func:`PyLong_GetSign` function to get the sign of :class:`int` objects. + (Contributed by Sergey B Kirpichev in :gh:`116560`.) + +* Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` + and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` + is positive, negative, or zero, respectively. + (Contributed by James Roy and Sergey B Kirpichev in :gh:`126061`.) + +* Add new functions to convert C ```` numbers to/from + Python :class:`int` objects: + + * :c:func:`PyLong_AsInt32` + * :c:func:`PyLong_AsInt64` + * :c:func:`PyLong_AsUInt32` + * :c:func:`PyLong_AsUInt64` + * :c:func:`PyLong_FromInt32` + * :c:func:`PyLong_FromInt64` + * :c:func:`PyLong_FromUInt32` + * :c:func:`PyLong_FromUInt64` + + (Contributed by Victor Stinner in :gh:`120389`.) + +* Add a new import and export API for Python :class:`int` objects + (:pep:`757`): + + * :c:func:`PyLong_GetNativeLayout` + * :c:func:`PyLong_Export` + * :c:func:`PyLong_FreeExport` + * :c:func:`PyLongWriter_Create` + * :c:func:`PyLongWriter_Finish` + * :c:func:`PyLongWriter_Discard` + + (Contributed by Sergey B Kirpichev and Victor Stinner in :gh:`102471`.) + +* Add :c:func:`PyMonitoring_FireBranchLeftEvent` and + :c:func:`PyMonitoring_FireBranchRightEvent` for generating + :monitoring-event:`BRANCH_LEFT` and :monitoring-event:`BRANCH_RIGHT` + events, respectively. + (Contributed by Mark Shannon in :gh:`122548`.) + +* Add :c:func:`PyType_Freeze` function to make a type immutable. + (Contributed by Victor Stinner in :gh:`121654`.) + +* Add :c:func:`PyType_GetBaseByToken` and :c:data:`Py_tp_token` slot + for easier superclass identification, which attempts to resolve the + type checking issue mentioned in :pep:`PEP 630 <630#type-checking>`. + (Contributed in :gh:`124153`.) + +* Add a new :c:func:`PyUnicode_Equal` function to test if two + strings are equal. + The function is also added to the Limited C API. + (Contributed by Victor Stinner in :gh:`124502`.) + +* Add a new :c:type:`PyUnicodeWriter` API to create a Python :class:`str` + object, with the following functions: + + * :c:func:`PyUnicodeWriter_Create` + * :c:func:`PyUnicodeWriter_DecodeUTF8Stateful` + * :c:func:`PyUnicodeWriter_Discard` + * :c:func:`PyUnicodeWriter_Finish` + * :c:func:`PyUnicodeWriter_Format` + * :c:func:`PyUnicodeWriter_WriteASCII` + * :c:func:`PyUnicodeWriter_WriteChar` + * :c:func:`PyUnicodeWriter_WriteRepr` + * :c:func:`PyUnicodeWriter_WriteStr` + * :c:func:`PyUnicodeWriter_WriteSubstring` + * :c:func:`PyUnicodeWriter_WriteUCS4` + * :c:func:`PyUnicodeWriter_WriteUTF8` + * :c:func:`PyUnicodeWriter_WriteWideChar` + + (Contributed by Victor Stinner in :gh:`119182`.) + +* The ``k`` and ``K`` formats in :c:func:`PyArg_ParseTuple` and + similar functions now use :meth:`~object.__index__` if available, + like all other integer formats. + (Contributed by Serhiy Storchaka in :gh:`112068`.) + +* Add support for a new ``p`` format unit in :c:func:`Py_BuildValue` + that produces a Python :class:`bool` object from a C integer. + (Contributed by Pablo Galindo in :issue:`45325`.) + +* Add :c:func:`PyUnstable_IsImmortal` for determining if + an object is :term:`immortal`, for debugging purposes. + (Contributed by Peter Bierma in :gh:`128509`.) + +* Add :c:func:`PyUnstable_Object_EnableDeferredRefcount` for enabling + deferred reference counting, as outlined in :pep:`703`. + +* Add :c:func:`PyUnstable_Object_IsUniquelyReferenced` as + a replacement for ``Py_REFCNT(op) == 1`` on :term:`free threaded + ` builds. + (Contributed by Peter Bierma in :gh:`133140`.) + +* Add :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary` to + determine if an object is a unique temporary object on the + interpreter's operand stack. + This can be used in some cases as a replacement for checking + if :c:func:`Py_REFCNT` is ``1`` for Python objects passed + as arguments to C API functions. + (Contributed by Sam Gross in :gh:`133164`.) + + +Limited C API changes +--------------------- + +* In the limited C API version 3.14 and newer, :c:func:`Py_TYPE` and + :c:func:`Py_REFCNT` are now implemented as an opaque function call + to hide implementation details. + (Contributed by Victor Stinner in :gh:`120600` and :gh:`124127`.) + +* Remove the :c:macro:`PySequence_Fast_GET_SIZE`, + :c:macro:`PySequence_Fast_GET_ITEM`, + and :c:macro:`PySequence_Fast_ITEMS` + macros from the limited C API, since they have always been broken + in the limited C API. + (Contributed by Victor Stinner in :gh:`91417`.) + + +.. _whatsnew314-c-api-removed: + +Removed C APIs +-------------- + +* Creating :c:data:`immutable types ` with + mutable bases was deprecated in Python 3.12, + and now raises a :exc:`TypeError`. + (Contributed by Nikita Sobolev in :gh:`119775`.) + +* Remove ``PyDictObject.ma_version_tag`` member, which was deprecated + in Python 3.12. + Use the :c:func:`PyDict_AddWatcher` API instead. + (Contributed by Sam Gross in :gh:`124296`.) + +* Remove the private ``_Py_InitializeMain()`` function. + It was a :term:`provisional API` added to Python 3.8 by :pep:`587`. + (Contributed by Victor Stinner in :gh:`129033`.) + +* Remove the undocumented APIs :c:macro:`!Py_C_RECURSION_LIMIT` + and :c:member:`!PyThreadState.c_recursion_remaining`. + These were added in 3.13 and have been removed without deprecation. + Use :c:func:`Py_EnterRecursiveCall` to guard against runaway + recursion in C code. + (Removed by Petr Viktorin in :gh:`133079`, see also :gh:`130396`.) + + +.. _whatsnew314-c-api-deprecated: + +Deprecated C APIs +----------------- + +* The :c:macro:`!Py_HUGE_VAL` macro is now :term:`soft deprecated`. + Use :c:macro:`!INFINITY` instead. + (Contributed by Sergey B Kirpichev in :gh:`120026`.) + +* The :c:macro:`!Py_IS_NAN`, :c:macro:`!Py_IS_INFINITY`, + and :c:macro:`!Py_IS_FINITE` macros are now :term:`soft deprecated`. + Use :c:macro:`!isnan`, :c:macro:`!isinf` and :c:macro:`!isfinite` + instead, available from :file:`math.h` since C99. + (Contributed by Sergey B Kirpichev in :gh:`119613`.) + +* Non-tuple sequences are now deprecated as argument for the ``(items)`` + format unit in :c:func:`PyArg_ParseTuple` and other :ref:`argument + parsing ` functions if *items* contains format units + which store a :ref:`borrowed buffer ` or a + :term:`borrowed reference`. + (Contributed by Serhiy Storchaka in :gh:`50333`.) + +* The ``_PyMonitoring_FireBranchEvent`` function is now deprecated + and should be replaced with calls to + :c:func:`PyMonitoring_FireBranchLeftEvent` and + :c:func:`PyMonitoring_FireBranchRightEvent`. + +* The previously undocumented function :c:func:`PySequence_In` is + now :term:`soft deprecated`. + Use :c:func:`PySequence_Contains` instead. + (Contributed by Yuki Kobayashi in :gh:`127896`.) + +.. Add C API deprecations above alphabetically, not here at the end. + +.. include:: ../deprecations/c-api-pending-removal-in-3.15.rst + +.. include:: ../deprecations/c-api-pending-removal-in-3.16.rst + +.. include:: ../deprecations/c-api-pending-removal-in-3.18.rst + +.. include:: ../deprecations/c-api-pending-removal-in-future.rst + + +.. _whatsnew314-build-changes: + +Build changes +============= + +* :pep:`776`: Emscripten is now an officially supported platform at + :pep:`tier 3 <11#tier-3>`. As a part of this effort, more than 25 bugs in + `Emscripten libc`__ were fixed. Emscripten now includes support + for :mod:`ctypes`, :mod:`termios`, and :mod:`fcntl`, as well as + experimental support for the new :ref:`default interactive shell + `. + (Contributed by R. Hood Chatham in :gh:`127146`, :gh:`127683`, and :gh:`136931`.) + + __ https://emscripten.org/docs/porting/emscripten-runtime-environment.html + +* Official Android binary releases are now provided on python.org__. + + __ https://www.python.org/downloads/android/ + +* GNU Autoconf 2.72 is now required to generate :file:`configure`. + (Contributed by Erlend Aasland in :gh:`115765`.) + +* ``wasm32-unknown-emscripten`` is now a :pep:`11` tier 3 platform. + (Contributed by R. Hood Chatham in :gh:`127146`, :gh:`127683`, and :gh:`136931`.) + +* ``#pragma``-based linking with ``python3*.lib`` can now be switched off + with :c:expr:`Py_NO_LINK_LIB`. + (Contributed by Jean-Christophe Fillion-Robin in :gh:`82909`.) + +* CPython now enables a set of recommended compiler options by default + for improved security. + Use the :option:`--disable-safety` :file:`configure` option to disable them, + or the :option:`--enable-slower-safety` option for a larger set + of compiler options, albeit with a performance cost. + +* The ``WITH_FREELISTS`` macro and ``--without-freelists`` :file:`configure` + option have been removed. + +* The new :file:`configure` option :option:`--with-tail-call-interp` + may be used to enable the experimental tail call interpreter. + See :ref:`whatsnew314-tail-call-interpreter` for further details. + +* To disable the new remote debugging support, use the + :option:`--without-remote-debug` :file:`configure` option. + This may be useful for security reasons. + +* iOS and macOS apps can now be configured to redirect ``stdout`` and + ``stderr`` content to the system log. + (Contributed by Russell Keith-Magee in :gh:`127592`.) + +* The iOS testbed is now able to stream test output while the test is running. + The testbed can also be used to run the test suite of projects other than + CPython itself. + (Contributed by Russell Keith-Magee in :gh:`127592`.) + + +.. _whatsnew314-build_details: + +:file:`build-details.json` +-------------------------- + +Installations of Python now contain a new file, :file:`build-details.json`. +This is a static JSON document containing build details for CPython, +to allow for introspection without needing to run code. +This is helpful for use-cases such as Python launchers, cross-compilation, +and so on. + +:file:`build-details.json` must be installed in the platform-independent +standard library directory. This corresponds to the :ref:`'stdlib' +` :mod:`sysconfig` installation path, +which can be found by running ``sysconfig.get_path('stdlib')``. + +.. seealso:: + :pep:`739` -- ``build-details.json`` 1.0 -- a static description file + for Python build details + + +.. _whatsnew314-no-more-pgp: + +Discontinuation of PGP signatures +--------------------------------- + +PGP (Pretty Good Privacy) signatures will not be provided +for releases of Python 3.14 or future versions. +To verify CPython artifacts, users must use `Sigstore verification materials +`__. +Releases have been signed using Sigstore_ since Python 3.11. + +This change in release process was specified in :pep:`761`. + +.. _Sigstore: https://www.sigstore.dev/ + + +.. _whatsnew314-free-threaded-now-supported: + +Free-threaded Python is officially supported +-------------------------------------------- + +The free-threaded build of Python is now supported and no longer experimental. +This is the start of `phase II `__ where +free-threaded Python is officially supported but still optional. + +The free-threading team are confident that the project is on the right path, +and appreciate the continued dedication from everyone working to make +free-threading ready for broader adoption across the Python community. + +With these recommendations and the acceptance of this PEP, the Python developer +community should broadly advertise that free-threading is a supported +Python build option now and into the future, and that it will not be removed +without a proper deprecation schedule. + +Any decision to transition to `phase III `__, +with free-threading as the default or sole build of Python is still undecided, +and dependent on many factors both within CPython itself and the community. +This decision is for the future. + +.. seealso:: + + :pep:`779` + + `PEP 779's acceptance `__ + + +.. _whatsnew314-jit-compiler: + +Binary releases for the experimental just-in-time compiler +---------------------------------------------------------- + +The official macOS and Windows release binaries now include an *experimental* +just-in-time (JIT) compiler. Although it is **not** recommended for production +use, it can be tested by setting :envvar:`PYTHON_JIT=1 ` as an +environment variable. Downstream source builds and redistributors can use the +:option:`--enable-experimental-jit=yes-off` configuration option for similar +behavior. + +The JIT is at an early stage and still in active development. As such, the +typical performance impact of enabling it can range from 10% slower to 20% +faster, depending on workload. To aid in testing and evaluation, a set of +introspection functions has been provided in the :data:`sys._jit` namespace. +:func:`sys._jit.is_available` can be used to determine if the current executable +supports JIT compilation, while :func:`sys._jit.is_enabled` can be used to tell +if JIT compilation has been enabled for the current process. + +Currently, the most significant missing functionality is that native debuggers +and profilers like ``gdb`` and ``perf`` are unable to unwind through JIT frames +(Python debuggers and profilers, like :mod:`pdb` or :mod:`profile`, continue to +work without modification). Free-threaded builds do not support JIT compilation. + +Please report any bugs or major performance regressions that you encounter! + +.. seealso:: :pep:`744` + + Porting to Python 3.14 ====================== This section lists previously described changes and other bugfixes that may require changes to your code. + Changes in the Python API ------------------------- +* On Unix platforms other than macOS, *forkserver* is now the default + :ref:`start method ` for :mod:`multiprocessing` + and :class:`~concurrent.futures.ProcessPoolExecutor`, instead of *fork*. + + See :ref:`(1) ` and + :ref:`(2) ` for details. + + If you encounter :exc:`NameError`\s or pickling errors coming out of + :mod:`multiprocessing` or :mod:`concurrent.futures`, see the + :ref:`forkserver restrictions `. + + This change does not affect Windows or macOS, where :ref:`'spawn' + ` remains the default start method. + * :class:`functools.partial` is now a method descriptor. Wrap it in :func:`staticmethod` if you want to preserve the old behavior. (Contributed by Serhiy Storchaka and Dominykas Grigonis in :gh:`121027`.) @@ -2850,209 +3281,112 @@ Changes in the Python API (Contributed by Jelle Zijlstra in :gh:`105499`.) * The runtime behavior of annotations has changed in various ways; see - :ref:`above ` for details. While most code that interacts + :ref:`above ` for details. While most code that interacts with annotations should continue to work, some undocumented details may behave differently. +* As part of making the :mod:`mimetypes` CLI public, + it now exits with ``1`` on failure instead of ``0`` + and ``2`` on incorrect command-line parameters instead of ``1``. + Error messages are now printed to stderr. -Build changes -============= +* The ``\B`` pattern in regular expression now matches the empty string + when given as the entire pattern, which may cause behavioural changes. -* GNU Autoconf 2.72 is now required to generate :file:`configure`. - (Contributed by Erlend Aasland in :gh:`115765`.) - -* ``#pragma``-based linking with ``python3*.lib`` can now be switched off - with :c:expr:`Py_NO_LINK_LIB`. (Contributed by Jean-Christophe - Fillion-Robin in :gh:`82909`.) - -.. _whatsnew314-pep761: - -PEP 761: Discontinuation of PGP signatures ------------------------------------------- - -PGP signatures will not be available for CPython 3.14 and onwards. -Users verifying artifacts must use `Sigstore verification materials`_ for -verifying CPython artifacts. This change in release process is specified -in :pep:`761`. - -.. _Sigstore verification materials: https://www.python.org/downloads/metadata/sigstore/ +* On FreeBSD, :data:`sys.platform` no longer contains the major version number. -C API changes -============= +.. _whatsnew314-porting-annotations: -New features ------------- +Changes in annotations (:pep:`649` and :pep:`749`) +-------------------------------------------------- -* Add :c:func:`PyLong_GetSign` function to get the sign of :class:`int` objects. - (Contributed by Sergey B Kirpichev in :gh:`116560`.) +This section contains guidance on changes that may be needed to annotations +or Python code that interacts with or introspects annotations, +due to the changes related to :ref:`deferred evaluation of annotations +`. -* Add a new :c:type:`PyUnicodeWriter` API to create a Python :class:`str` - object: - - * :c:func:`PyUnicodeWriter_Create` - * :c:func:`PyUnicodeWriter_DecodeUTF8Stateful` - * :c:func:`PyUnicodeWriter_Discard` - * :c:func:`PyUnicodeWriter_Finish` - * :c:func:`PyUnicodeWriter_Format` - * :c:func:`PyUnicodeWriter_WriteASCII` - * :c:func:`PyUnicodeWriter_WriteChar` - * :c:func:`PyUnicodeWriter_WriteRepr` - * :c:func:`PyUnicodeWriter_WriteStr` - * :c:func:`PyUnicodeWriter_WriteSubstring` - * :c:func:`PyUnicodeWriter_WriteUCS4` - * :c:func:`PyUnicodeWriter_WriteUTF8` - * :c:func:`PyUnicodeWriter_WriteWideChar` - - (Contributed by Victor Stinner in :gh:`119182`.) - -* Add :c:func:`PyIter_NextItem` to replace :c:func:`PyIter_Next`, - which has an ambiguous return value. - (Contributed by Irit Katriel and Erlend Aasland in :gh:`105201`.) - -* Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` - and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` - is positive, negative, or zero, respectively. - (Contributed by James Roy and Sergey B Kirpichev in :gh:`126061`.) - -* Add new functions to convert C ```` numbers from/to Python - :class:`int`: - - * :c:func:`PyLong_AsInt32` - * :c:func:`PyLong_AsInt64` - * :c:func:`PyLong_AsUInt32` - * :c:func:`PyLong_AsUInt64` - * :c:func:`PyLong_FromInt32` - * :c:func:`PyLong_FromInt64` - * :c:func:`PyLong_FromUInt32` - * :c:func:`PyLong_FromUInt64` - - (Contributed by Victor Stinner in :gh:`120389`.) - -* Add :c:func:`PyBytes_Join(sep, iterable) ` function, - similar to ``sep.join(iterable)`` in Python. - (Contributed by Victor Stinner in :gh:`121645`.) - -* Add :c:func:`Py_HashBuffer` to compute and return the hash value of a buffer. - (Contributed by Antoine Pitrou and Victor Stinner in :gh:`122854`.) - -* Add functions to get and set the current runtime Python configuration - (:pep:`741`): - - * :c:func:`PyConfig_Get` - * :c:func:`PyConfig_GetInt` - * :c:func:`PyConfig_Set` - * :c:func:`PyConfig_Names` - - (Contributed by Victor Stinner in :gh:`107954`.) - -* Add functions to configure the Python initialization (:pep:`741`): - - * :c:func:`Py_InitializeFromInitConfig` - * :c:func:`PyInitConfig_AddModule` - * :c:func:`PyInitConfig_Create` - * :c:func:`PyInitConfig_Free` - * :c:func:`PyInitConfig_FreeStrList` - * :c:func:`PyInitConfig_GetError` - * :c:func:`PyInitConfig_GetExitCode` - * :c:func:`PyInitConfig_GetInt` - * :c:func:`PyInitConfig_GetStr` - * :c:func:`PyInitConfig_GetStrList` - * :c:func:`PyInitConfig_HasOption` - * :c:func:`PyInitConfig_SetInt` - * :c:func:`PyInitConfig_SetStr` - * :c:func:`PyInitConfig_SetStrList` - - (Contributed by Victor Stinner in :gh:`107954`.) - -* Add a new import and export API for Python :class:`int` objects (:pep:`757`): - - * :c:func:`PyLong_GetNativeLayout` - * :c:func:`PyLong_Export` - * :c:func:`PyLong_FreeExport` - * :c:func:`PyLongWriter_Create` - * :c:func:`PyLongWriter_Finish` - * :c:func:`PyLongWriter_Discard` - - (Contributed by Sergey B Kirpichev and Victor Stinner in :gh:`102471`.) - -* Add :c:func:`PyType_GetBaseByToken` and :c:data:`Py_tp_token` slot for easier - superclass identification, which attempts to resolve the `type checking issue - `__ mentioned in :pep:`630`. - (Contributed in :gh:`124153`.) - -* Add :c:func:`PyUnicode_Equal` function to the limited C API: - test if two strings are equal. - (Contributed by Victor Stinner in :gh:`124502`.) - -* Add :c:func:`PyType_Freeze` function to make a type immutable. - (Contributed by Victor Stinner in :gh:`121654`.) - -* Add :c:func:`PyUnstable_Object_EnableDeferredRefcount` for enabling - deferred reference counting, as outlined in :pep:`703`. - -* Add :c:func:`PyMonitoring_FireBranchLeftEvent` and - :c:func:`PyMonitoring_FireBranchRightEvent` for generating - :monitoring-event:`BRANCH_LEFT` and :monitoring-event:`BRANCH_RIGHT` - events, respectively. - -* Add :c:func:`Py_fopen` function to open a file. Similar to the - :c:func:`!fopen` function, but the *path* parameter is a Python object and an - exception is set on error. Add also :c:func:`Py_fclose` function to close a - file. - (Contributed by Victor Stinner in :gh:`127350`.) - -* The ``k`` and ``K`` formats in :c:func:`PyArg_ParseTuple` and - similar functions now use :meth:`~object.__index__` if available, - like all other integer formats. - (Contributed by Serhiy Storchaka in :gh:`112068`.) - -* Add macros :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION` for - bit-packing Python version numbers. - (Contributed by Petr Viktorin in :gh:`128629`.) - -* Add :c:func:`PyUnstable_IsImmortal` for determining whether an object is :term:`immortal`, - for debugging purposes. - -* Add :c:func:`PyImport_ImportModuleAttr` and - :c:func:`PyImport_ImportModuleAttrString` helper functions to import a module - and get an attribute of the module. - (Contributed by Victor Stinner in :gh:`128911`.) - -* Add support for a new ``p`` format unit in :c:func:`Py_BuildValue` that allows - taking a C integer and produces a Python :class:`bool` object. (Contributed by - Pablo Galindo in :issue:`45325`.) - -* Add :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary` to determine if an object - is a unique temporary object on the interpreter's operand stack. This can - be used in some cases as a replacement for checking if :c:func:`Py_REFCNT` - is ``1`` for Python objects passed as arguments to C API functions. - -* Add :c:func:`PyUnstable_Object_IsUniquelyReferenced` as a replacement for - ``Py_REFCNT(op) == 1`` on :term:`free threaded ` builds. - (Contributed by Peter Bierma in :gh:`133140`.) +In the majority of cases, working code from older versions of Python +will not require any changes. -Limited C API changes ---------------------- +Implications for annotated code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* In the limited C API 3.14 and newer, :c:func:`Py_TYPE` and - :c:func:`Py_REFCNT` are now implemented as an opaque function call to hide - implementation details. - (Contributed by Victor Stinner in :gh:`120600` and :gh:`124127`.) +If you define annotations in your code (for example, for use with a static type +checker), then this change probably does not affect you: you can keep +writing annotations the same way you did with previous versions of Python. -* Remove the :c:macro:`PySequence_Fast_GET_SIZE`, - :c:macro:`PySequence_Fast_GET_ITEM` and :c:macro:`PySequence_Fast_ITEMS` - macros from the limited C API, since these macros never worked in the limited - C API. Keep :c:func:`PySequence_Fast` in the limited C API. - (Contributed by Victor Stinner in :gh:`91417`.) +You will likely be able to remove quoted strings in annotations, which are frequently +used for forward references. Similarly, if you use ``from __future__ import annotations`` +to avoid having to write strings in annotations, you may well be able to +remove that import once you support only Python 3.14 and newer. +However, if you rely on third-party libraries that read annotations, +those libraries may need changes to support unquoted annotations before they +work as expected. -Porting to Python 3.14 ----------------------- +Implications for readers of ``__annotations__`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If your code reads the :attr:`~object.__annotations__` attribute on objects, +you may want to make changes in order to support code that relies on +deferred evaluation of annotations. +For example, you may want to use :func:`annotationlib.get_annotations` with +the :attr:`~annotationlib.Format.FORWARDREF` format, +as the :mod:`dataclasses` module now does. + +The external :pypi:`typing_extensions` package provides partial backports +of some of the functionality of the :mod:`annotationlib` module, +such as the :class:`~annotationlib.Format` enum and +the :func:`~annotationlib.get_annotations` function. +These can be used to write cross-version code that takes advantage of +the new behavior in Python 3.14. + + +Related changes +^^^^^^^^^^^^^^^ + +The changes in Python 3.14 are designed to rework how :attr:`!__annotations__` +works at runtime while minimizing breakage to code that contains +annotations in source code and to code that reads :attr:`!__annotations__`. +However, if you rely on undocumented details of the annotation behavior +or on private functions in the standard library, there are many ways in which +your code may not work in Python 3.14. +To safeguard your code against future changes, only use the documented +functionality of the :mod:`annotationlib` module. + +In particular, do not read annotations directly from the namespace dictionary +attribute of type objects. +Use :func:`annotationlib.get_annotate_from_class_namespace` during class +construction and :func:`annotationlib.get_annotations` afterwards. + +In previous releases, it was sometimes possible to access class annotations +from an instance of an annotated class. This behavior was undocumented +and accidental, and will no longer work in Python 3.14. + + +``from __future__ import annotations`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In Python 3.7, :pep:`563` introduced the ``from __future__ import annotations`` +:ref:`future statement `, which turns all annotations into strings. + +However, this statement is now deprecated and it is expected to be removed +in a future version of Python. +This removal will not happen until after Python 3.13 reaches its end of life +in 2029, being the last version of Python without support for deferred +evaluation of annotations. + +In Python 3.14, the behavior of code using ``from __future__ import annotations`` +is unchanged. + + +Changes in the C API +-------------------- * :c:func:`Py_Finalize` now deletes all interned strings. This - is backwards incompatible to any C-Extension that holds onto an interned + is backwards incompatible to any C extension that holds onto an interned string after a call to :c:func:`Py_Finalize` and is then reused after a call to :c:func:`Py_Initialize`. Any issues arising from this behavior will normally result in crashes during the execution of the subsequent call to @@ -3103,110 +3437,3 @@ Porting to Python 3.14 functions on Python 3.13 and older. .. _pythoncapi-compat project: https://github.com/python/pythoncapi-compat/ - - -.. _whatsnew314-c-api-deprecated: - -Deprecated ----------- - -* The :c:macro:`!Py_HUGE_VAL` macro is :term:`soft deprecated`, - use :c:macro:`!Py_INFINITY` instead. - (Contributed by Sergey B Kirpichev in :gh:`120026`.) - -* Macros :c:macro:`!Py_IS_NAN`, :c:macro:`!Py_IS_INFINITY` - and :c:macro:`!Py_IS_FINITE` are :term:`soft deprecated`, - use instead :c:macro:`!isnan`, :c:macro:`!isinf` and - :c:macro:`!isfinite` available from :file:`math.h` - since C99. (Contributed by Sergey B Kirpichev in :gh:`119613`.) - -* Non-tuple sequences are deprecated as argument for the ``(items)`` - format unit in :c:func:`PyArg_ParseTuple` and other - :ref:`argument parsing ` functions if *items* contains - format units which store a :ref:`borrowed buffer ` - or a :term:`borrowed reference`. - (Contributed by Serhiy Storchaka in :gh:`50333`.) - -* The previously undocumented function :c:func:`PySequence_In` is :term:`soft deprecated`. - Use :c:func:`PySequence_Contains` instead. - (Contributed by Yuki Kobayashi in :gh:`127896`.) - -.. Add C API deprecations above alphabetically, not here at the end. - -* The ``PyMonitoring_FireBranchEvent`` function is deprecated and should - be replaced with calls to :c:func:`PyMonitoring_FireBranchLeftEvent` - and :c:func:`PyMonitoring_FireBranchRightEvent`. - -* The following private functions are deprecated and planned for removal in - Python 3.18: - - * :c:func:`!_PyBytes_Join`: use :c:func:`PyBytes_Join`. - * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. - * :c:func:`!_PyDict_Pop()`: use :c:func:`PyDict_Pop`. - * :c:func:`!_PyLong_Sign()`: use :c:func:`PyLong_GetSign`. - * :c:func:`!_PyLong_FromDigits` and :c:func:`!_PyLong_New`: - use :c:func:`PyLongWriter_Create`. - * :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. - * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. - * :c:func:`!_PyUnicodeWriter_Init`: - replace ``_PyUnicodeWriter_Init(&writer)`` with - :c:func:`writer = PyUnicodeWriter_Create(0) `. - * :c:func:`!_PyUnicodeWriter_Finish`: - replace ``_PyUnicodeWriter_Finish(&writer)`` with - :c:func:`PyUnicodeWriter_Finish(writer) `. - * :c:func:`!_PyUnicodeWriter_Dealloc`: - replace ``_PyUnicodeWriter_Dealloc(&writer)`` with - :c:func:`PyUnicodeWriter_Discard(writer) `. - * :c:func:`!_PyUnicodeWriter_WriteChar`: - replace ``_PyUnicodeWriter_WriteChar(&writer, ch)`` with - :c:func:`PyUnicodeWriter_WriteChar(writer, ch) `. - * :c:func:`!_PyUnicodeWriter_WriteStr`: - replace ``_PyUnicodeWriter_WriteStr(&writer, str)`` with - :c:func:`PyUnicodeWriter_WriteStr(writer, str) `. - * :c:func:`!_PyUnicodeWriter_WriteSubstring`: - replace ``_PyUnicodeWriter_WriteSubstring(&writer, str, start, end)`` with - :c:func:`PyUnicodeWriter_WriteSubstring(writer, str, start, end) `. - * :c:func:`!_PyUnicodeWriter_WriteASCIIString`: - replace ``_PyUnicodeWriter_WriteASCIIString(&writer, str)`` with - :c:func:`PyUnicodeWriter_WriteASCII(writer, str) `. - * :c:func:`!_PyUnicodeWriter_WriteLatin1String`: - replace ``_PyUnicodeWriter_WriteLatin1String(&writer, str)`` with - :c:func:`PyUnicodeWriter_WriteUTF8(writer, str) `. - * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. - * :c:func:`!_Py_fopen_obj`: use :c:func:`Py_fopen`. - - The `pythoncapi-compat project`_ can be used to get these new public - functions on Python 3.13 and older. - (Contributed by Victor Stinner in :gh:`128863`.) - -.. include:: ../deprecations/c-api-pending-removal-in-3.15.rst - -.. include:: ../deprecations/c-api-pending-removal-in-3.16.rst - -.. include:: ../deprecations/c-api-pending-removal-in-3.18.rst - -.. include:: ../deprecations/c-api-pending-removal-in-future.rst - - -.. _whatsnew314-c-api-removed: - -Removed -------- - -* Creating :c:data:`immutable types ` with mutable - bases was deprecated since 3.12 and now raises a :exc:`TypeError`. - -* Remove ``PyDictObject.ma_version_tag`` member which was deprecated since - Python 3.12. Use the :c:func:`PyDict_AddWatcher` API instead. - (Contributed by Sam Gross in :gh:`124296`.) - -* Remove the private ``_Py_InitializeMain()`` function. It was a - :term:`provisional API` added to Python 3.8 by :pep:`587`. - (Contributed by Victor Stinner in :gh:`129033`.) - -* The undocumented APIs :c:macro:`!Py_C_RECURSION_LIMIT` and - :c:member:`!PyThreadState.c_recursion_remaining`, added in 3.13, are removed - without a deprecation period. - Please use :c:func:`Py_EnterRecursiveCall` to guard against runaway recursion - in C code. - (Removed in :gh:`133079`, see also :gh:`130396`.) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 54a7d0f3c57..7e032fe5df2 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -3,7 +3,7 @@ What's new in Python 3.15 **************************** -:Editor: TBD +:Editor: Hugo van Kemenade .. Rules for maintenance: @@ -56,8 +56,8 @@ For full details, see the :ref:`changelog `. so it's worth checking back even after reading earlier versions. -Summary --- release highlights -============================== +Summary -- Release highlights +============================= .. This section singles out the most important changes in Python 3.15. Brevity is key. @@ -65,109 +65,130 @@ Summary --- release highlights .. PEP-sized items next. +* :pep:`799`: :ref:`A dedicated profiling package for organizing Python + profiling tools ` +* :pep:`799`: :ref:`Tachyon: High frequency statistical sampling profiler + profiling tools ` +* :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding + ` +* :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object + ` +* :ref:`The JIT compiler has been significantly upgraded ` +* :ref:`Improved error messages ` New features ============ +.. _whatsnew315-profiling-package: + +:pep:`799`: A dedicated profiling package +----------------------------------------- + +A new :mod:`profiling` module has been added to organize Python's built-in +profiling tools under a single, coherent namespace. This module contains: + +* :mod:`profiling.tracing`: deterministic function-call tracing (relocated from + ``cProfile``). +* :mod:`profiling.sampling`: a new statistical sampling profiler (named Tachyon). + +The ``cProfile`` module remains as an alias for backwards compatibility. +The :mod:`profile` module is deprecated and will be removed in Python 3.17. + +.. seealso:: :pep:`799` for further details. + +(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`138122`.) + + .. _whatsnew315-sampling-profiler: -High frequency statistical sampling profiler --------------------------------------------- +Tachyon: High frequency statistical sampling profiler +----------------------------------------------------- -A new statistical sampling profiler has been added to the :mod:`profile` module as -:mod:`profile.sample`. This profiler enables low-overhead performance analysis of +.. image:: ../library/tachyon-logo.png + :alt: Tachyon profiler logo + :align: center + :width: 200px + +A new statistical sampling profiler (Tachyon) has been added as +:mod:`profiling.sampling`. This profiler enables low-overhead performance analysis of running Python processes without requiring code modification or process restart. -Unlike deterministic profilers (:mod:`cProfile` and :mod:`profile`) that instrument +Unlike deterministic profilers (such as :mod:`profiling.tracing`) that instrument every function call, the sampling profiler periodically captures stack traces from running processes. This approach provides virtually zero overhead while achieving sampling rates of **up to 1,000,000 Hz**, making it the fastest sampling profiler available for Python (at the time of its contribution) and ideal for debugging -performance issues in production environments. +performance issues in production environments. This capability is particularly +valuable for debugging performance issues in production systems where traditional +profiling approaches would be too intrusive. Key features include: * **Zero-overhead profiling**: Attach to any running Python process without - affecting its performance -* **No code modification required**: Profile existing applications without restart -* **Real-time statistics**: Monitor sampling quality during data collection -* **Multiple output formats**: Generate both detailed statistics and flamegraph data -* **Thread-aware profiling**: Option to profile all threads or just the main thread + affecting its performance. Ideal for production debugging where you can't afford + to restart or slow down your application. -Profile process 1234 for 10 seconds with default settings:: +* **No code modification required**: Profile existing applications without restart. + Simply point the profiler at a running process by PID and start collecting data. - python -m profile.sample 1234 +* **Flexible target modes**: -Profile with custom interval and duration, save to file:: + * Profile running processes by PID (``attach``) - attach to already-running applications + * Run and profile scripts directly (``run``) - profile from the very start of execution + * Execute and profile modules (``run -m``) - profile packages run as ``python -m module`` - python -m profile.sample -i 50 -d 30 -o profile.stats 1234 +* **Multiple profiling modes**: Choose what to measure based on your performance investigation: -Generate collapsed stacks for flamegraph:: + * **Wall-clock time** (``--mode wall``, default): Measures real elapsed time including I/O, + network waits, and blocking operations. Use this to understand where your program spends + calendar time, including when waiting for external resources. + * **CPU time** (``--mode cpu``): Measures only active CPU execution time, excluding I/O waits + and blocking. Use this to identify CPU-bound bottlenecks and optimize computational work. + * **GIL-holding time** (``--mode gil``): Measures time spent holding Python's Global Interpreter + Lock. Use this to identify which threads dominate GIL usage in multi-threaded applications. + * **Exception handling time** (``--mode exception``): Captures samples only from threads with + an active exception. Use this to analyze exception handling overhead. - python -m profile.sample --collapsed 1234 +* **Thread-aware profiling**: Option to profile all threads (``-a``) or just the main thread, + essential for understanding multi-threaded application behavior. -Profile all threads and sort by total time:: +* **Multiple output formats**: Choose the visualization that best fits your workflow: - python -m profile.sample -a --sort-tottime 1234 + * ``--pstats``: Detailed tabular statistics compatible with :mod:`pstats`. Shows function-level + timing with direct and cumulative samples. Best for detailed analysis and integration with + existing Python profiling tools. + * ``--collapsed``: Generates collapsed stack traces (one line per stack). This format is + specifically designed for creating flamegraphs with external tools like Brendan Gregg's + FlameGraph scripts or speedscope. + * ``--flamegraph``: Generates a self-contained interactive HTML flamegraph using D3.js. + Opens directly in your browser for immediate visual analysis. Flamegraphs show the call + hierarchy where width represents time spent, making it easy to spot bottlenecks at a glance. + * ``--gecko``: Generates Gecko Profiler format compatible with Firefox Profiler + (https://profiler.firefox.com). Upload the output to Firefox Profiler for advanced + timeline-based analysis with features like stack charts, markers, and network activity. + * ``--heatmap``: Generates an interactive HTML heatmap visualization with line-level sample + counts. Creates a directory with per-file heatmaps showing exactly where time is spent + at the source code level. -The profiler generates statistical estimates of where time is spent:: +* **Live interactive mode**: Real-time TUI profiler with a top-like interface (``--live``). + Monitor performance as your application runs with interactive sorting and filtering. - Real-time sampling stats: Mean: 100261.5Hz (9.97µs) Min: 86333.4Hz (11.58µs) Max: 118807.2Hz (8.42µs) Samples: 400001 - Captured 498841 samples in 5.00 seconds - Sample rate: 99768.04 samples/sec - Error rate: 0.72% - Profile Stats: - nsamples sample% tottime (s) cumul% cumtime (s) filename:lineno(function) - 43/418858 0.0 0.000 87.9 4.189 case.py:667(TestCase.run) - 3293/418812 0.7 0.033 87.9 4.188 case.py:613(TestCase._callTestMethod) - 158562/158562 33.3 1.586 33.3 1.586 test_compile.py:725(TestSpecifics.test_compiler_recursion_limit..check_limit) - 129553/129553 27.2 1.296 27.2 1.296 ast.py:46(parse) - 0/128129 0.0 0.000 26.9 1.281 test_ast.py:884(AST_Tests.test_ast_recursion_limit..check_limit) - 7/67446 0.0 0.000 14.2 0.674 test_compile.py:729(TestSpecifics.test_compiler_recursion_limit) - 6/60380 0.0 0.000 12.7 0.604 test_ast.py:888(AST_Tests.test_ast_recursion_limit) - 3/50020 0.0 0.000 10.5 0.500 test_compile.py:727(TestSpecifics.test_compiler_recursion_limit) - 1/38011 0.0 0.000 8.0 0.380 test_ast.py:886(AST_Tests.test_ast_recursion_limit) - 1/25076 0.0 0.000 5.3 0.251 test_compile.py:728(TestSpecifics.test_compiler_recursion_limit) - 22361/22362 4.7 0.224 4.7 0.224 test_compile.py:1368(TestSpecifics.test_big_dict_literal) - 4/18008 0.0 0.000 3.8 0.180 test_ast.py:889(AST_Tests.test_ast_recursion_limit) - 11/17696 0.0 0.000 3.7 0.177 subprocess.py:1038(Popen.__init__) - 16968/16968 3.6 0.170 3.6 0.170 subprocess.py:1900(Popen._execute_child) - 2/16941 0.0 0.000 3.6 0.169 test_compile.py:730(TestSpecifics.test_compiler_recursion_limit) +* **Async-aware profiling**: Profile async/await code with task-based stack reconstruction + (``--async-aware``). See which coroutines are consuming time, with options to show only + running tasks or all tasks including those waiting. - Legend: - nsamples: Direct/Cumulative samples (direct executing / on call stack) - sample%: Percentage of total samples this function was directly executing - tottime: Estimated total time spent directly in this function - cumul%: Percentage of total samples when this function was on the call stack - cumtime: Estimated cumulative time (including time in called functions) - filename:lineno(function): Function location and name +* **Opcode-level profiling**: Gather bytecode opcode information for instruction-level + profiling (``--opcodes``). Shows which bytecode instructions are executing, including + specializations from the adaptive interpreter. - Summary of Interesting Functions: +See :mod:`profiling.sampling` for the complete documentation, including all +available output formats, profiling modes, and configuration options. - Functions with Highest Direct/Cumulative Ratio (Hot Spots): - 1.000 direct/cumulative ratio, 33.3% direct samples: test_compile.py:(TestSpecifics.test_compiler_recursion_limit..check_limit) - 1.000 direct/cumulative ratio, 27.2% direct samples: ast.py:(parse) - 1.000 direct/cumulative ratio, 3.6% direct samples: subprocess.py:(Popen._execute_child) +(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953` and :gh:`138122`.) - Functions with Highest Call Frequency (Indirect Calls): - 418815 indirect calls, 87.9% total stack presence: case.py:(TestCase.run) - 415519 indirect calls, 87.9% total stack presence: case.py:(TestCase._callTestMethod) - 159470 indirect calls, 33.5% total stack presence: test_compile.py:(TestSpecifics.test_compiler_recursion_limit) - - Functions with Highest Call Magnification (Cumulative/Direct): - 12267.9x call magnification, 159470 indirect calls from 13 direct: test_compile.py:(TestSpecifics.test_compiler_recursion_limit) - 10581.7x call magnification, 116388 indirect calls from 11 direct: test_ast.py:(AST_Tests.test_ast_recursion_limit) - 9740.9x call magnification, 418815 indirect calls from 43 direct: case.py:(TestCase.run) - -The profiler automatically identifies performance bottlenecks through statistical -analysis, highlighting functions with high CPU usage and call frequency patterns. - -This capability is particularly valuable for debugging performance issues in -production systems where traditional profiling approaches would be too intrusive. - -(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953`.) +.. _whatsnew315-improved-error-messages: Improved error messages ----------------------- @@ -211,9 +232,11 @@ Improved error messages Other language changes ====================== +.. _whatsnew315-utf8-default: + * Python now uses UTF-8_ as the default encoding, independent of the system's environment. This means that I/O operations without an explicit encoding, - e.g. ``open('flying-circus.txt')``, will use UTF-8. + for example, ``open('flying-circus.txt')``, will use UTF-8. UTF-8 is a widely-supported Unicode_ character encoding that has become a *de facto* standard for representing text, including nearly every webpage on the internet, many common file formats, programming languages, and more. @@ -227,7 +250,7 @@ Other language changes To retain the previous behaviour, Python's UTF-8 mode may be disabled with the :envvar:`PYTHONUTF8=0 ` environment variable or the - :option:`-X utf8=0 <-X>` command line option. + :option:`-X utf8=0 <-X>` command-line option. .. seealso:: :pep:`686` for further details. @@ -273,16 +296,195 @@ Other language changes This speeds up class creation, and helps avoid reference cycles. (Contributed by Petr Viktorin in :gh:`135228`.) +* The :option:`-W` option and the :envvar:`PYTHONWARNINGS` environment variable + can now specify regular expressions instead of literal strings to match + the warning message and the module name, if the corresponding field starts + and ends with a forward slash (``/``). + (Contributed by Serhiy Storchaka in :gh:`134716`.) + +* Functions that take timestamp or timeout arguments now accept any real + numbers (such as :class:`~decimal.Decimal` and :class:`~fractions.Fraction`), + not only integers or floats, although this does not improve precision. + (Contributed by Serhiy Storchaka in :gh:`67795`.) + +.. _whatsnew315-bytearray-take-bytes: + +* Added :meth:`bytearray.take_bytes(n=None, /) ` to take + bytes out of a :class:`bytearray` without copying. This enables optimizing code + which must return :class:`bytes` after working with a mutable buffer of bytes + such as data buffering, network protocol parsing, encoding, decoding, + and compression. Common code patterns which can be optimized with + :func:`~bytearray.take_bytes` are listed below. + + .. list-table:: Suggested optimizing refactors + :header-rows: 1 + + * - Description + - Old + - New + + * - Return :class:`bytes` after working with :class:`bytearray` + - .. code:: python + + def read() -> bytes: + buffer = bytearray(1024) + ... + return bytes(buffer) + + - .. code:: python + + def read() -> bytes: + buffer = bytearray(1024) + ... + return buffer.take_bytes() + + * - Empty a buffer getting the bytes + - .. code:: python + + buffer = bytearray(1024) + ... + data = bytes(buffer) + buffer.clear() + + - .. code:: python + + buffer = bytearray(1024) + ... + data = buffer.take_bytes() + + * - Split a buffer at a specific separator + - .. code:: python + + buffer = bytearray(b'abc\ndef') + n = buffer.find(b'\n') + data = bytes(buffer[:n + 1]) + del buffer[:n + 1] + assert data == b'abc' + assert buffer == bytearray(b'def') + + - .. code:: python + + buffer = bytearray(b'abc\ndef') + n = buffer.find(b'\n') + data = buffer.take_bytes(n + 1) + + * - Split a buffer at a specific separator; discard after the separator + - .. code:: python + + buffer = bytearray(b'abc\ndef') + n = buffer.find(b'\n') + data = bytes(buffer[:n]) + buffer.clear() + assert data == b'abc' + assert len(buffer) == 0 + + - .. code:: python + + buffer = bytearray(b'abc\ndef') + n = buffer.find(b'\n') + buffer.resize(n) + data = buffer.take_bytes() + + (Contributed by Cody Maloney in :gh:`139871`.) + +* Many functions related to compiling or parsing Python code, such as + :func:`compile`, :func:`ast.parse`, :func:`symtable.symtable`, + and :func:`importlib.abc.InspectLoader.source_to_code`, now allow the module + name to be passed. It is needed to unambiguously :ref:`filter ` + syntax warnings by module name. + (Contributed by Serhiy Storchaka in :gh:`135801`.) + +* Allowed defining the *__dict__* and *__weakref__* :ref:`__slots__ ` + for any class. + (Contributed by Serhiy Storchaka in :gh:`41779`.) + New modules =========== -* None yet. +math.integer +------------ + +This module provides access to the mathematical functions for integer +arguments (:pep:`791`). +(Contributed by Serhiy Storchaka in :gh:`81313`.) Improved modules ================ +argparse +-------- + +* The :class:`~argparse.BooleanOptionalAction` action supports now single-dash + long options and alternate prefix characters. + (Contributed by Serhiy Storchaka in :gh:`138525`.) + +* Changed the *suggest_on_error* parameter of :class:`argparse.ArgumentParser` to + default to ``True``. This enables suggestions for mistyped arguments by default. + (Contributed by Jakob Schluse in :gh:`140450`.) + +* Added backtick markup support in description and epilog text to highlight + inline code when color output is enabled. + (Contributed by Savannah Ostrowski in :gh:`142390`.) + +calendar +-------- + +* Calendar pages generated by the :class:`calendar.HTMLCalendar` class now support + dark mode and have been migrated to the HTML5 standard for improved accessibility. + (Contributed by Jiahao Li and Hugo van Kemenade in :gh:`137634`.) + +* The :mod:`calendar`'s :ref:`command-line ` HTML output now + accepts the year-month option: ``python -m calendar -t html 2009 06``. + (Contributed by Pål Grønås Drange in :gh:`140212`.) + + +collections +----------- + +* Added :meth:`!collections.Counter.__xor__` and + :meth:`!collections.Counter.__ixor__` to compute the symmetric difference + between :class:`~collections.Counter` objects. + (Contributed by Raymond Hettinger in :gh:`138682`.) + +collections.abc +--------------- + +* :class:`collections.abc.ByteString` has been removed from + ``collections.abc.__all__``. :class:`!collections.abc.ByteString` has been + deprecated since Python 3.12, and is scheduled for removal in Python 3.17. + +* The following statements now cause ``DeprecationWarning``\ s to be emitted at + runtime: + + * ``from collections.abc import ByteString`` + * ``import collections.abc; collections.abc.ByteString``. + + ``DeprecationWarning``\ s were already emitted if + :class:`collections.abc.ByteString` was subclassed or used as the second + argument to :func:`isinstance` or :func:`issubclass`, but warnings were not + previously emitted if it was merely imported or accessed from the + :mod:`!collections.abc` module. + + +concurrent.futures +------------------ + +* Improved error reporting when a child process in a + :class:`concurrent.futures.ProcessPoolExecutor` terminates abruptly. + The resulting traceback will now tell you the PID and exit code of the + terminated process. + (Contributed by Jonathan Berg in :gh:`139486`.) + + +dataclasses +----------- + +* Annotations for generated ``__init__`` methods no longer include internal + type names. + + dbm --- @@ -290,10 +492,7 @@ dbm which allow to recover unused free space previously occupied by deleted entries. (Contributed by Andrea Oliveri in :gh:`134004`.) -* Add the ``'m'`` flag for :func:`dbm.gnu.open` which allows to disable - the use of :manpage:`mmap(2)`. - This may harm performance, but improve crash tolerance. - (Contributed by Serhiy Storchaka in :gh:`66234`.) + difflib ------- @@ -311,6 +510,14 @@ difflib (Contributed by Jiahao Li in :gh:`134580`.) +functools +--------- + +* :func:`~functools.singledispatchmethod` now supports non-:term:`descriptor` + callables. + (Contributed by Serhiy Storchaka in :gh:`140873`.) + + hashlib ------- @@ -339,11 +546,19 @@ http.cookies (Contributed by Nick Burns and Senthil Kumaran in :gh:`92936`.) +inspect +------- + +* Add parameters *inherit_class_doc* and *fallback_to_class_doc* + for :func:`~inspect.getdoc`. + (Contributed by Serhiy Storchaka in :gh:`132686`.) + + locale ------ * :func:`~locale.setlocale` now supports language codes with ``@``-modifiers. - ``@``-modifier are no longer silently removed in :func:`~locale.getlocale`, + ``@``-modifiers are no longer silently removed in :func:`~locale.getlocale`, but included in the language code. (Contributed by Serhiy Storchaka in :gh:`137729`.) @@ -358,6 +573,34 @@ math (Contributed by Bénédikt Tran in :gh:`135853`.) +mimetypes +--------- + +* Add ``application/node`` MIME type for ``.cjs`` extension. (Contributed by John Franey in :gh:`140937`.) +* Add ``application/toml``. (Contributed by Gil Forcada in :gh:`139959`.) +* Rename ``application/x-texinfo`` to ``application/texinfo``. + (Contributed by Charlie Lin in :gh:`140165`.) +* Changed the MIME type for ``.ai`` files to ``application/pdf``. + (Contributed by Stan Ulbrych in :gh:`141239`.) + + +mmap +---- + +* :class:`mmap.mmap` now has a *trackfd* parameter on Windows; + if it is ``False``, the file handle corresponding to *fileno* will + not be duplicated. + (Contributed by Serhiy Storchaka in :gh:`78502`.) + + +os +-- + +* Add :func:`os.statx` on Linux kernel versions 4.11 and later with + glibc versions 2.28 and later. + (Contributed by Jeffrey Bosboom and Victor Stinner in :gh:`83714`.) + + os.path ------- @@ -370,6 +613,7 @@ os.path the resulting path can be missing but it will be free of symlinks. (Contributed by Petr Viktorin for :cve:`2025-4517`.) + resource -------- @@ -387,6 +631,13 @@ shelve (Contributed by Andrea Oliveri in :gh:`134004`.) +socket +------ + +* Add constants for the ISO-TP CAN protocol. + (Contributed by Patrick Menschel and Stefan Tatschner in :gh:`86819`.) + + sqlite3 ------- @@ -398,7 +649,10 @@ sqlite3 * Prompts, error messages, and help text are now colored. This is enabled by default, see :ref:`using-on-controlling-color` for details. - (Contributed by Stan Ulbrych and Łukasz Langa in :gh:`133461`) + (Contributed by Stan Ulbrych and Łukasz Langa in :gh:`133461`.) + + * Table, index, trigger, view, column, function, and schema completion on . + (Contributed by Long Tan in :gh:`136101`.) ssl @@ -424,7 +678,38 @@ ssl agreement groups compatible with the minimum and maximum TLS versions currently set in the context. This call requires OpenSSL 3.5 or later. - (Contributed by Ron Frederick in :gh:`136306`) + (Contributed by Ron Frederick in :gh:`136306`.) + +* Added a new method :meth:`ssl.SSLContext.set_ciphersuites` for setting TLS 1.3 + ciphers. For TLS 1.2 or earlier, :meth:`ssl.SSLContext.set_ciphers` should + continue to be used. Both calls can be made on the same context and the + selected cipher suite will depend on the TLS version negotiated when a + connection is made. + (Contributed by Ron Frederick in :gh:`137197`.) + +* Added new methods for managing signature algorithms: + + * :func:`ssl.get_sigalgs` returns a list of all available TLS signature + algorithms. This call requires OpenSSL 3.4 or later. + * :meth:`ssl.SSLContext.set_client_sigalgs` sets the signature algorithms + allowed for certificate-based client authentication. + * :meth:`ssl.SSLContext.set_server_sigalgs` sets the signature algorithms + allowed for the server to complete the TLS handshake. + * :meth:`ssl.SSLSocket.client_sigalg` returns the signature algorithm + selected for client authentication on the current connection. This call + requires OpenSSL 3.5 or later. + * :meth:`ssl.SSLSocket.server_sigalg` returns the signature algorithm + selected for the server to complete the TLS handshake on the current + connection. This call requires OpenSSL 3.5 or later. + + (Contributed by Ron Frederick in :gh:`138252`.) + + +sys +--- + +* Add :data:`sys.abi_info` namespace to improve access to ABI information. + (Contributed by Klaus Zimmermann in :gh:`137476`.) tarfile @@ -447,8 +732,34 @@ tarfile :func:`~tarfile.TarFile.errorlevel` is zero. (Contributed by Matt Prodani and Petr Viktorin in :gh:`112887` and :cve:`2025-4435`.) +* :func:`~tarfile.TarFile.extract` and :func:`~tarfile.TarFile.extractall` + now replace slashes by backslashes in symlink targets on Windows to prevent + creation of corrupted links. + (Contributed by Christoph Walcher in :gh:`57911`.) +timeit +------ + +* The command-line interface now colorizes error tracebacks + by default. This can be controlled with + :ref:`environment variables `. + (Contributed by Yi Hong in :gh:`139374`.) + +tkinter +------- + +* The :meth:`!tkinter.Text.search` method now supports two additional + arguments: *nolinestop* which allows the search to + continue across line boundaries; + and *strictlimits* which restricts the search to within the specified range. + (Contributed by Rihaan Meher in :gh:`130848`) + +* A new method :meth:`!tkinter.Text.search_all` has been introduced. + This method allows for searching for all matches of a pattern + using Tcl's ``-all`` and ``-overlap`` options. + (Contributed by Rihaan Meher in :gh:`130848`) + types ------ @@ -458,6 +769,17 @@ types as described in :pep:`667`. +unicodedata +----------- + +* The Unicode database has been updated to Unicode 17.0.0. + +* Add :func:`unicodedata.isxidstart` and :func:`unicodedata.isxidcontinue` + functions to check whether a character can start or continue a + `Unicode Standard Annex #31 `_ identifier. + (Contributed by Stan Ulbrych in :gh:`129117`.) + + unittest -------- @@ -466,6 +788,47 @@ unittest (Contributed by Garry Cairns in :gh:`134567`.) +venv +---- + +* On POSIX platforms, platlib directories will be created if needed when + creating virtual environments, instead of using ``lib64 -> lib`` symlink. + This means purelib and platlib of virtual environments no longer share the + same ``lib`` directory on platforms where :data:`sys.platlibdir` is not + equal to ``lib``. + (Contributed by Rui Xi in :gh:`133951`.) + + +warnings +-------- + +* Improve filtering by module in :func:`warnings.warn_explicit` if no *module* + argument is passed. + It now tests the module regular expression in the warnings filter not only + against the filename with ``.py`` stripped, but also against module names + constructed starting from different parent directories of the filename + (with ``/__init__.py``, ``.py`` and, on Windows, ``.pyw`` stripped). + (Contributed by Serhiy Storchaka in :gh:`135801`.) + + +xml.parsers.expat +----------------- + +* Add :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerActivationThreshold` + and :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerMaximumAmplification` + to :ref:`xmlparser ` objects to tune protections against + disproportional amounts of dynamic memory usage from within an Expat parser. + (Contributed by Bénédikt Tran in :gh:`90949`.) + +* Add :meth:`~xml.parsers.expat.xmlparser.SetBillionLaughsAttackProtectionActivationThreshold` + and :meth:`~xml.parsers.expat.xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification` + to :ref:`xmlparser ` objects to tune protections against + `billion laughs`_ attacks. + (Contributed by Bénédikt Tran in :gh:`90949`.) + + .. _billion laughs: https://en.wikipedia.org/wiki/Billion_laughs_attack + + zlib ---- @@ -481,33 +844,97 @@ zlib Optimizations ============= -module_name ------------ +csv +--- -* TODO +* :meth:`csv.Sniffer.sniff` delimiter detection is now up to 1.6x faster. + (Contributed by Maurycy Pawłowski-Wieroński in :gh:`137628`.) +.. _whatsnew315-jit: -Deprecated -========== +Upgraded JIT compiler +===================== -hashlib -------- +Results from the `pyperformance `__ +benchmark suite report +`3-4% `__ +geometric mean performance improvement for the JIT over the standard CPython +interpreter built with all optimizations enabled. The speedups for JIT +builds versus no JIT builds range from roughly 20% slowdown to over +100% speedup (ignoring the ``unpack_sequence`` microbenchmark) on +x86-64 Linux and AArch64 macOS systems. -* In hash function constructors such as :func:`~hashlib.new` or the - direct hash-named constructors such as :func:`~hashlib.md5` and - :func:`~hashlib.sha256`, their optional initial data parameter could - also be passed a keyword argument named ``data=`` or ``string=`` in - various :mod:`hashlib` implementations. +.. attention:: + These results are not yet final. - Support for the ``string`` keyword argument name is now deprecated and - is slated for removal in Python 3.19. Prefer passing the initial data as - a positional argument for maximum backwards compatibility. +The major upgrades to the JIT are: - (Contributed by Bénédikt Tran in :gh:`134978`.) +* LLVM 21 build-time dependency +* New tracing frontend +* Basic register allocation in the JIT +* More JIT optimizations +* Better machine code generation +.. rubric:: LLVM 21 build-time dependency + +The JIT compiler now uses LLVM 21 for build-time stencil generation. As +always, LLVM is only needed when building CPython with the JIT enabled; +end users running Python do not need LLVM installed. Instructions for +installing LLVM can be found in the `JIT compiler documentation +`__ +for all supported platforms. + +(Contributed by Savannah Ostrowski in :gh:`140973`.) + +.. rubric:: A new tracing frontend + +The JIT compiler now supports significantly more bytecode operations and +control flow than in Python 3.14, enabling speedups on a wider variety of +code. For example, simple Python object creation is now understood by the +3.15 JIT compiler. Overloaded operations and generators are also partially +supported. This was made possible by an overhauled JIT tracing frontend +that records actual execution paths through code, rather than estimating +them as the previous implementation did. + +(Contributed by Ken Jin in :gh:`139109`. Support for Windows added by +Mark Shannon in :gh:`141703`.) + +.. rubric:: Basic register allocation in the JIT + +A basic form of register allocation has been added to the JIT compiler's +optimizer. This allows the JIT compiler to avoid certain stack operations +altogether and instead operate on registers. This allows the JIT to produce +more efficient traces by avoiding reads and writes to memory. + +(Contributed by Mark Shannon in :gh:`135379`.) + +.. rubric:: More JIT optimizations + +More `constant-propagation `__ +is now performed. This means when the JIT compiler detects that certain user +code results in constants, the code can be simplified by the JIT. + +(Contributed by Ken Jin and Savannah Ostrowski in :gh:`132732`.) + +The JIT avoids :term:`reference count`\ s where possible. This generally +reduces the cost of most operations in Python. + +(Contributed by Ken Jin, Donghee Na, Zheao Li, Savannah Ostrowski, +Noam Cohen, Tomas Roun, PuQing in :gh:`134584`.) + +.. rubric:: Better machine code generation + +The JIT compiler's machine code generator now produces better machine code +for x86-64 and AArch64 macOS and Linux targets. In general, users should +experience lower memory usage for generated machine code and more efficient +machine code versus the old JIT. + +(Contributed by Brandt Bucher in :gh:`136528` and :gh:`136528`. +Implementation for AArch64 contributed by Mark Shannon in :gh:`139855`. +Additional optimizations for AArch64 contributed by Mark Shannon and +Diego Russo in :gh:`140683` and :gh:`142305`.) -.. Add deprecations above alphabetically, not here at the end. Removed ======= @@ -538,6 +965,14 @@ http.server (Contributed by Bénédikt Tran in :gh:`133810`.) +importlib.resources +------------------- + +* Removed deprecated ``package`` parameter + from :func:`importlib.resources.files` function. + (Contributed by Semyon Moroz in :gh:`138044`) + + pathlib ------- @@ -587,7 +1022,7 @@ typing (Contributed by Bénédikt Tran in :gh:`133817`.) * Using ``TD = TypedDict("TD")`` or ``TD = TypedDict("TD", None)`` to - construct a :class:`~typing.TypedDict` type with zero field is no + construct a :class:`~typing.TypedDict` type with zero fields is no longer supported. Use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})`` instead. (Contributed by Bénédikt Tran in :gh:`133823`.) @@ -598,9 +1033,27 @@ typing * Code like ``class B2(A[T2], Protocol[T1, T2]): ...`` now correctly handles type parameters order: it is ``(T1, T2)``, not ``(T2, T1)`` - as it was incorrectly infered in runtime before. + as it was incorrectly inferred in runtime before. (Contributed by Nikita Sobolev in :gh:`137191`.) +* :class:`typing.ByteString` has been removed from ``typing.__all__``. + :class:`!typing.ByteString` has been deprecated since Python 3.9, and is + scheduled for removal in Python 3.17. + +* The following statements now cause ``DeprecationWarning``\ s to be emitted at + runtime: + + * ``from typing import ByteString`` + * ``import typing; typing.ByteString``. + + ``DeprecationWarning``\ s were already emitted if :class:`typing.ByteString` + was subclassed or used as the second argument to :func:`isinstance` or + :func:`issubclass`, but warnings were not previously emitted if it was merely + imported or accessed from the :mod:`!typing` module. + +* Deprecated :func:`!typing.no_type_check_decorator` has been removed. + (Contributed by Nikita Sobolev in :gh:`133601`.) + wave ---- @@ -611,20 +1064,84 @@ wave (Contributed by Bénédikt Tran in :gh:`133873`.) -Porting to Python 3.15 -====================== +zipimport +--------- -This section lists previously described changes and other bugfixes -that may require changes to your code. +* Remove deprecated :meth:`!zipimport.zipimporter.load_module`. + Use :meth:`zipimport.zipimporter.exec_module` instead. + (Contributed by Jiahao Li in :gh:`133656`.) -Build changes -============= +Deprecated +========== -* Removed implicit fallback to the bundled copy of the ``libmpdec`` library. - Now this should be explicitly enabled with :option:`--with-system-libmpdec` - set to ``no`` or with :option:`!--without-system-libmpdec`. - (Contributed by Sergey B Kirpichev in :gh:`115119`.) +New deprecations +---------------- + +* CLI: + + * Deprecate :option:`-b` and :option:`!-bb` command-line options + and schedule them to become no-ops in Python 3.17. + These were primarily helpers for the Python 2 -> 3 transition. + Starting with Python 3.17, no :exc:`BytesWarning` will be raised + for these cases; use a type checker instead. + + (Contributed by Nikita Sobolev in :gh:`136355`.) + +* :mod:`hashlib`: + + * In hash function constructors such as :func:`~hashlib.new` or the + direct hash-named constructors such as :func:`~hashlib.md5` and + :func:`~hashlib.sha256`, the optional initial data parameter could + also be passed as a keyword argument named ``data=`` or ``string=`` in + various :mod:`hashlib` implementations. + + Support for the ``string`` keyword argument name is now deprecated and + is slated for removal in Python 3.19. Prefer passing the initial data as + a positional argument for maximum backwards compatibility. + + (Contributed by Bénédikt Tran in :gh:`134978`.) + +* ``__version__`` + + * The ``__version__`` attribute has been deprecated in these standard library + modules and will be removed in Python 3.20. + Use :py:data:`sys.version_info` instead. + + - :mod:`argparse` + - :mod:`csv` + - :mod:`ctypes` + - :mod:`!ctypes.macholib` + - :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead) + - :mod:`http.server` + - :mod:`imaplib` + - :mod:`ipaddress` + - :mod:`json` + - :mod:`logging` (``__date__`` also deprecated) + - :mod:`optparse` + - :mod:`pickle` + - :mod:`platform` + - :mod:`re` + - :mod:`socketserver` + - :mod:`tabnanny` + - :mod:`tkinter.font` + - :mod:`tkinter.ttk` + - :mod:`wsgiref.simple_server` + - :mod:`zlib` + + (Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.) + +.. Add deprecations above alphabetically, not here at the end. + +.. include:: ../deprecations/pending-removal-in-3.16.rst + +.. include:: ../deprecations/pending-removal-in-3.17.rst + +.. include:: ../deprecations/pending-removal-in-3.19.rst + +.. include:: ../deprecations/pending-removal-in-3.20.rst + +.. include:: ../deprecations/pending-removal-in-future.rst C API changes @@ -640,57 +1157,67 @@ New features * Add :c:type:`PyUnstable_Unicode_GET_CACHED_HASH` to get the cached hash of a string. See the documentation for caveats. - (Contributed by Petr Viktorin in :gh:`131510`) + (Contributed by Petr Viktorin in :gh:`131510`.) + +* Add API for checking an extension module's ABI compatibility: + :c:data:`Py_mod_abi`, :c:func:`PyABIInfo_Check`, :c:macro:`PyABIInfo_VAR` + and :c:data:`Py_mod_abi`. + (Contributed by Petr Viktorin in :gh:`137210`.) + +.. _whatsnew315-pep782: + +* Implement :pep:`782`, the :ref:`PyBytesWriter API `. + Add functions: + + * :c:func:`PyBytesWriter_Create` + * :c:func:`PyBytesWriter_Discard` + * :c:func:`PyBytesWriter_FinishWithPointer` + * :c:func:`PyBytesWriter_FinishWithSize` + * :c:func:`PyBytesWriter_Finish` + * :c:func:`PyBytesWriter_Format` + * :c:func:`PyBytesWriter_GetData` + * :c:func:`PyBytesWriter_GetSize` + * :c:func:`PyBytesWriter_GrowAndUpdatePointer` + * :c:func:`PyBytesWriter_Grow` + * :c:func:`PyBytesWriter_Resize` + * :c:func:`PyBytesWriter_WriteBytes` + + (Contributed by Victor Stinner in :gh:`129813`.) + +* Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C-API for creating + a module from a *spec* and *initfunc*. + (Contributed by Itamar Oren in :gh:`116146`.) + +* Add :c:func:`PyTuple_FromArray` to create a :class:`tuple` from an array. + (Contributed by Victor Stinner in :gh:`111489`.) + +* Add :c:func:`PyUnstable_Object_Dump` to dump an object to ``stderr``. + It should only be used for debugging. + (Contributed by Victor Stinner in :gh:`141070`.) + +* Add :c:func:`PyUnstable_ThreadState_SetStackProtection` and + :c:func:`PyUnstable_ThreadState_ResetStackProtection` functions to set + the stack protection base address and stack protection size of a Python + thread state. + (Contributed by Victor Stinner in :gh:`139653`.) + + +Changed C APIs +-------------- + +* If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` or :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` + flag is set then :c:macro:`Py_TPFLAGS_HAVE_GC` must be set too. + (Contributed by Sergey Miryanov in :gh:`134786`) Porting to Python 3.15 ---------------------- -* :class:`sqlite3.Connection` APIs has been cleaned up. - - * All parameters of :func:`sqlite3.connect` except *database* are now keyword-only. - * The first three parameters of methods :meth:`~sqlite3.Connection.create_function` - and :meth:`~sqlite3.Connection.create_aggregate` are now positional-only. - * The first parameter of methods :meth:`~sqlite3.Connection.set_authorizer`, - :meth:`~sqlite3.Connection.set_progress_handler` and - :meth:`~sqlite3.Connection.set_trace_callback` is now positional-only. - - (Contributed by Serhiy Storchaka in :gh:`133595`.) - * Private functions promoted to public C APIs: The |pythoncapi_compat_project| can be used to get most of these new functions on Python 3.14 and older. -* :data:`resource.RLIM_INFINITY` is now always positive. - Passing a negative integer value that corresponded to its old value - (such as ``-1`` or ``-3``, depending on platform) to - :func:`resource.setrlimit` and :func:`resource.prlimit` is now deprecated. - (Contributed by Serhiy Storchaka in :gh:`137044`.) - - -Deprecated C APIs ------------------ - -* For unsigned integer formats in :c:func:`PyArg_ParseTuple`, - accepting Python integers with value that is larger than the maximal value - for the C type or less than the minimal value for the corresponding - signed integer type of the same size is now deprecated. - (Contributed by Serhiy Storchaka in :gh:`132629`.) - -* Deprecate :c:member:`~PyComplexObject.cval` field of the the - :c:type:`PyComplexObject` type. - Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex` - to convert a Python complex number to/from the C :c:type:`Py_complex` - representation. - (Contributed by Sergey B Kirpichev in :gh:`128813`.) - -* Functions :c:func:`_Py_c_sum`, :c:func:`_Py_c_diff`, :c:func:`_Py_c_neg`, - :c:func:`_Py_c_prod`, :c:func:`_Py_c_quot`, :c:func:`_Py_c_pow` and - :c:func:`_Py_c_abs` are :term:`soft deprecated`. - (Contributed by Sergey B Kirpichev in :gh:`128813`.) - -.. Add C API deprecations above alphabetically, not here at the end. Removed C APIs -------------- @@ -708,12 +1235,22 @@ Removed C APIs Use :c:func:`PyCodec_Encode` instead; Note that some codecs (for example, "base64") may return a type other than :class:`bytes`, such as :class:`str`. - (Contributed by Stan Ulbrych in :gh:`133612`) + (Contributed by Stan Ulbrych in :gh:`133612`.) * :c:func:`!PyImport_ImportModuleNoBlock`: deprecated alias of :c:func:`PyImport_ImportModule`. (Contributed by Bénédikt Tran in :gh:`133644`.) +* :c:func:`!PyWeakref_GetObject` and :c:macro:`!PyWeakref_GET_OBJECT`: + use :c:func:`PyWeakref_GetRef` instead. The |pythoncapi_compat_project| + can be used to get :c:func:`!PyWeakref_GetRef` on Python 3.12 and older. + (Contributed by Bénédikt Tran in :gh:`133644`.) + +* Remove deprecated :c:func:`!PySys_ResetWarnOptions`. + Clear :data:`sys.warnoptions` and :data:`!warnings.filters` instead. + + (Contributed by Nikita Sobolev in :gh:`138886`.) + The following functions are removed in favor of :c:func:`PyConfig_Get`. The |pythoncapi_compat_project| can be used to get :c:func:`!PyConfig_Get` on Python 3.13 and older. @@ -750,3 +1287,113 @@ on Python 3.13 and older. .. |pythoncapi_compat_project| replace:: |pythoncapi_compat_project_link|_ .. |pythoncapi_compat_project_link| replace:: pythoncapi-compat project .. _pythoncapi_compat_project_link: https://github.com/python/pythoncapi-compat + + +Deprecated C APIs +----------------- + +* For unsigned integer formats in :c:func:`PyArg_ParseTuple`, + accepting Python integers with value that is larger than the maximal value + for the C type or less than the minimal value for the corresponding + signed integer type of the same size is now deprecated. + (Contributed by Serhiy Storchaka in :gh:`132629`.) + +* :c:func:`PyBytes_FromStringAndSize(NULL, len) ` + and :c:func:`_PyBytes_Resize` are :term:`soft deprecated`, + use the :c:type:`PyBytesWriter` API instead. + (Contributed by Victor Stinner in :gh:`129813`.) + +* :c:func:`!_PyObject_CallMethodId`, :c:func:`!_PyObject_GetAttrId` and + :c:func:`!_PyUnicode_FromId` are deprecated since 3.15 and will be removed in + 3.20. Instead, use :c:func:`PyUnicode_InternFromString()` and cache the result in + the module state, then call :c:func:`PyObject_CallMethod` or + :c:func:`PyObject_GetAttr`. + (Contributed by Victor Stinner in :gh:`141049`.) + +* Deprecate :c:member:`~PyComplexObject.cval` field of the + :c:type:`PyComplexObject` type. + Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex` + to convert a Python complex number to/from the C :c:type:`Py_complex` + representation. + (Contributed by Sergey B Kirpichev in :gh:`128813`.) + +* Functions :c:func:`_Py_c_sum`, :c:func:`_Py_c_diff`, :c:func:`_Py_c_neg`, + :c:func:`_Py_c_prod`, :c:func:`_Py_c_quot`, :c:func:`_Py_c_pow` and + :c:func:`_Py_c_abs` are :term:`soft deprecated`. + (Contributed by Sergey B Kirpichev in :gh:`128813`.) + +* :c:member:`~PyConfig.bytes_warning` is deprecated + since 3.15 and will be removed in 3.17. + (Contributed by Nikita Sobolev in :gh:`136355`.) + +* :c:macro:`!Py_INFINITY` macro is :term:`soft deprecated`, + use the C11 standard ```` :c:macro:`!INFINITY` instead. + (Contributed by Sergey B Kirpichev in :gh:`141004`.) + +* :c:macro:`!Py_MATH_El` and :c:macro:`!Py_MATH_PIl` are deprecated + since 3.15 and will be removed in 3.20. + (Contributed by Sergey B Kirpichev in :gh:`141004`.) + + +.. Add C API deprecations above alphabetically, not here at the end. + + +Build changes +============= + +* Removed implicit fallback to the bundled copy of the ``libmpdec`` library. + Now this should be explicitly enabled with :option:`--with-system-libmpdec` + set to ``no`` or with :option:`!--without-system-libmpdec`. + (Contributed by Sergey B Kirpichev in :gh:`115119`.) + +* The new configure option :option:`--with-missing-stdlib-config=FILE` allows + distributors to pass a `JSON `_ + configuration file containing custom error messages for :term:`standard library` + modules that are missing or packaged separately. + (Contributed by Stan Ulbrych and Petr Viktorin in :gh:`139707`.) + +* Annotating anonymous mmap usage is now supported if Linux kernel supports + :manpage:`PR_SET_VMA_ANON_NAME ` (Linux 5.17 or newer). + Annotations are visible in ``/proc//maps`` if the kernel supports the feature + and :option:`-X dev <-X>` is passed to the Python or Python is built in :ref:`debug mode `. + (Contributed by Donghee Na in :gh:`141770`) + + +Porting to Python 3.15 +====================== + +This section lists previously described changes and other bugfixes +that may require changes to your code. + +* :class:`sqlite3.Connection` APIs have been cleaned up. + + * All parameters of :func:`sqlite3.connect` except *database* are now keyword-only. + * The first three parameters of methods :meth:`~sqlite3.Connection.create_function` + and :meth:`~sqlite3.Connection.create_aggregate` are now positional-only. + * The first parameter of methods :meth:`~sqlite3.Connection.set_authorizer`, + :meth:`~sqlite3.Connection.set_progress_handler` and + :meth:`~sqlite3.Connection.set_trace_callback` is now positional-only. + + (Contributed by Serhiy Storchaka in :gh:`133595`.) + +* :data:`resource.RLIM_INFINITY` is now always positive. + Passing a negative integer value that corresponded to its old value + (such as ``-1`` or ``-3``, depending on platform) to + :func:`resource.setrlimit` and :func:`resource.prlimit` is now deprecated. + (Contributed by Serhiy Storchaka in :gh:`137044`.) + +* :meth:`~mmap.mmap.resize` has been removed on platforms that don't support the + underlying syscall, instead of raising a :exc:`SystemError`. + +* A resource warning is now emitted for an unclosed + :func:`xml.etree.ElementTree.iterparse` iterator if it opened a file. + Use its :meth:`!close` method or the :func:`contextlib.closing` context + manager to close it. + (Contributed by Osama Abdelkader and Serhiy Storchaka in :gh:`140601`.) + +* If a short option and a single-dash long option are passed to + :meth:`argparse.ArgumentParser.add_argument`, *dest* is now inferred from + the single-dash long option. For example, in ``add_argument('-f', '-foo')``, + *dest* is now ``'foo'`` instead of ``'f'``. + Pass an explicit *dest* argument to preserve the old behavior. + (Contributed by Serhiy Storchaka in :gh:`138697`.) diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 7104904c956..3b13d90f769 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -312,7 +312,7 @@ cluttering source directories, the *pyc* files are now collected in a Aside from the filenames and target directories, the new scheme has a few aspects that are visible to the programmer: -* Imported modules now have a :attr:`~module.__cached__` attribute which stores +* Imported modules now have a ``__cached__`` attribute which stores the name of the actual file that was imported: >>> import collections @@ -458,7 +458,7 @@ Some smaller changes made to the core Python language are: :class:`~collections.defaultdict`, :class:`~shelve.Shelf`, :class:`~configparser.ConfigParser`, or :mod:`dbm`. It is also useful with custom :class:`dict` subclasses that normalize keys before look-up or that - supply a :meth:`__missing__` method for unknown keys:: + supply a :meth:`~object.__missing__` method for unknown keys:: >>> import shelve >>> d = shelve.open('tmp.shl') diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 89fd6868645..1bb79bce2c3 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -331,7 +331,7 @@ simplified and finer-grained. You don't have to worry anymore about choosing the appropriate exception type between :exc:`OSError`, :exc:`IOError`, :exc:`EnvironmentError`, -:exc:`WindowsError`, :exc:`mmap.error`, :exc:`socket.error` or +:exc:`WindowsError`, :exc:`!mmap.error`, :exc:`socket.error` or :exc:`select.error`. All these exception types are now only one: :exc:`OSError`. The other names are kept as aliases for compatibility reasons. @@ -805,7 +805,7 @@ Some smaller changes made to the core Python language are: * New methods have been added to :class:`list` and :class:`bytearray`: ``copy()`` and ``clear()`` (:issue:`10516`). Consequently, :class:`~collections.abc.MutableSequence` now also defines a - :meth:`~collections.abc.MutableSequence.clear` method (:issue:`11388`). + :meth:`!clear` method (:issue:`11388`). * Raw bytes literals can now be written ``rb"..."`` as well as ``br"..."``. @@ -869,10 +869,10 @@ faulthandler This new debug module :mod:`faulthandler` contains functions to dump Python tracebacks explicitly, on a fault (a crash like a segmentation fault), after a timeout, or on a user signal. Call :func:`faulthandler.enable` to install fault handlers for the -:const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGABRT`, :const:`SIGBUS`, and -:const:`SIGILL` signals. You can also enable them at startup by setting the -:envvar:`PYTHONFAULTHANDLER` environment variable or by using :option:`-X` -``faulthandler`` command line option. +:const:`~signal.SIGSEGV`, :const:`~signal.SIGFPE`, :const:`~signal.SIGABRT`, +:const:`~signal.SIGBUS`, and :const:`~signal.SIGILL` signals. +You can also enable them at startup by setting the :envvar:`PYTHONFAULTHANDLER` +environment variable or by using :option:`-X` ``faulthandler`` command line option. Example of a segmentation fault on Linux: @@ -916,7 +916,7 @@ abc Improved support for abstract base classes containing descriptors composed with abstract methods. The recommended approach to declaring abstract descriptors is -now to provide :attr:`__isabstractmethod__` as a dynamically updated +now to provide :attr:`!__isabstractmethod__` as a dynamically updated property. The built-in descriptors have been updated accordingly. * :class:`abc.abstractproperty` has been deprecated, use :class:`property` @@ -979,7 +979,7 @@ new features have been added: (Contributed by Nir Aides in :issue:`1625`.) * :class:`bz2.BZ2File` now implements all of the :class:`io.BufferedIOBase` API, - except for the :meth:`detach` and :meth:`truncate` methods. + except for the :meth:`!detach` and :meth:`!truncate` methods. codecs @@ -1064,7 +1064,7 @@ curses * If the :mod:`curses` module is linked to the ncursesw library, use Unicode functions when Unicode strings or characters are passed (e.g. - :c:func:`waddwstr`), and bytes functions otherwise (e.g. :c:func:`waddstr`). + :c:func:`!waddwstr`), and bytes functions otherwise (e.g. :c:func:`!waddstr`). * Use the locale encoding instead of ``utf-8`` to encode Unicode strings. * :class:`curses.window` has a new :attr:`curses.window.encoding` attribute. * The :class:`curses.window` class has a new :meth:`~curses.window.get_wch` @@ -1137,15 +1137,15 @@ API changes * The C module has the following context limits, depending on the machine architecture: - +-------------------+----------------+-------------------------+ - | | 32-bit | 64-bit | - +===================+================+=========================+ - | :const:`MAX_PREC` | ``425000000`` | ``999999999999999999`` | - +-------------------+----------------+-------------------------+ - | :const:`MAX_EMAX` | ``425000000`` | ``999999999999999999`` | - +-------------------+----------------+-------------------------+ - | :const:`MIN_EMIN` | ``-425000000`` | ``-999999999999999999`` | - +-------------------+----------------+-------------------------+ + +----------------------------+----------------+-------------------------+ + | | 32-bit | 64-bit | + +============================+================+=========================+ + | :const:`~decimal.MAX_PREC` | ``425000000`` | ``999999999999999999`` | + +----------------------------+----------------+-------------------------+ + | :const:`~decimal.MAX_EMAX` | ``425000000`` | ``999999999999999999`` | + +----------------------------+----------------+-------------------------+ + | :const:`~decimal.MIN_EMIN` | ``-425000000`` | ``-999999999999999999`` | + +----------------------------+----------------+-------------------------+ * In the context templates (:const:`~decimal.DefaultContext`, :const:`~decimal.BasicContext` and :const:`~decimal.ExtendedContext`) @@ -1434,7 +1434,7 @@ html :class:`html.parser.HTMLParser` is now able to parse broken markup without raising errors, therefore the *strict* argument of the constructor and the -:exc:`~html.parser.HTMLParseError` exception are now deprecated. +:exc:`!HTMLParseError` exception are now deprecated. The ability to parse broken markup is the result of a number of bug fixes that are also available on the latest bug fix releases of Python 2.7/3.2. (Contributed by Ezio Melotti in :issue:`15114`, and :issue:`14538`, @@ -1486,7 +1486,7 @@ already exists. It is based on the C11 'x' mode to fopen(). The constructor of the :class:`~io.TextIOWrapper` class has a new *write_through* optional argument. If *write_through* is ``True``, calls to -:meth:`~io.TextIOWrapper.write` are guaranteed not to be buffered: any data +:meth:`!write` are guaranteed not to be buffered: any data written on the :class:`~io.TextIOWrapper` object is immediately handled to its underlying binary buffer. @@ -1504,7 +1504,7 @@ logging The :func:`~logging.basicConfig` function now supports an optional ``handlers`` argument taking an iterable of handlers to be added to the root logger. -A class level attribute :attr:`~logging.handlers.SysLogHandler.append_nul` has +A class level attribute :attr:`!append_nul` has been added to :class:`~logging.handlers.SysLogHandler` to allow control of the appending of the ``NUL`` (``\000``) byte to syslog records, since for some daemons it is required while for others it is passed through to the log. @@ -1536,8 +1536,8 @@ The new :func:`multiprocessing.connection.wait` function allows polling multiple objects (such as connections, sockets and pipes) with a timeout. (Contributed by Richard Oudkerk in :issue:`12328`.) -:class:`multiprocessing.Connection` objects can now be transferred over -multiprocessing connections. +:class:`multiprocessing.connection.Connection` objects can now be transferred +over multiprocessing connections. (Contributed by Richard Oudkerk in :issue:`4892`.) :class:`multiprocessing.Process` now accepts a ``daemon`` keyword argument @@ -1611,7 +1611,7 @@ os :func:`~os.rename`, :func:`~os.replace`, :func:`~os.rmdir`, :func:`~os.stat`, :func:`~os.symlink`, :func:`~os.unlink`, :func:`~os.utime`. Platform support for using these parameters can be checked via the sets - :data:`os.supports_dir_fd` and :data:`os.supports_follows_symlinks`. + :data:`os.supports_dir_fd` and :data:`os.supports_follow_symlinks`. - The following functions now support a file descriptor for their path argument: :func:`~os.chdir`, :func:`~os.chmod`, :func:`~os.chown`, @@ -1698,7 +1698,7 @@ os :const:`~os.RTLD_NOLOAD`, and :const:`~os.RTLD_DEEPBIND` are available on platforms that support them. These are for use with the :func:`sys.setdlopenflags` function, and supersede the similar constants - defined in :mod:`ctypes` and :mod:`DLFCN`. (Contributed by Victor Stinner + defined in :mod:`ctypes` and :mod:`!DLFCN`. (Contributed by Victor Stinner in :issue:`13226`.) * :func:`os.symlink` now accepts (and ignores) the ``target_is_directory`` @@ -1728,8 +1728,8 @@ reduction functions to be set. pydoc ----- -The Tk GUI and the :func:`~pydoc.serve` function have been removed from the -:mod:`pydoc` module: ``pydoc -g`` and :func:`~pydoc.serve` have been deprecated +The Tk GUI and the :func:`!serve` function have been removed from the +:mod:`pydoc` module: ``pydoc -g`` and :func:`!serve` have been deprecated in Python 3.2. @@ -1931,7 +1931,7 @@ ssl * :func:`~ssl.RAND_bytes`: generate cryptographically strong pseudo-random bytes. - * :func:`~ssl.RAND_pseudo_bytes`: generate pseudo-random bytes. + * :func:`!RAND_pseudo_bytes`: generate pseudo-random bytes. (Contributed by Victor Stinner in :issue:`12049`.) @@ -2020,8 +2020,7 @@ tarfile tempfile -------- -:class:`tempfile.SpooledTemporaryFile`\'s -:meth:`~tempfile.SpooledTemporaryFile.truncate` method now accepts +:class:`tempfile.SpooledTemporaryFile`\'s :meth:`!truncate` method now accepts a ``size`` parameter. (Contributed by Ryan Kelly in :issue:`9957`.) @@ -2129,7 +2128,7 @@ xml.etree.ElementTree The :mod:`xml.etree.ElementTree` module now imports its C accelerator by default; there is no longer a need to explicitly import -:mod:`xml.etree.cElementTree` (this module stays for backwards compatibility, +:mod:`!xml.etree.cElementTree` (this module stays for backwards compatibility, but is now deprecated). In addition, the ``iter`` family of methods of :class:`~xml.etree.ElementTree.Element` has been optimized (rewritten in C). The module's documentation has also been greatly improved with added examples @@ -2197,7 +2196,7 @@ Changes to Python's build process and to the C API include: * :c:func:`PyUnicode_AsUCS4`, :c:func:`PyUnicode_AsUCS4Copy` * :c:macro:`PyUnicode_DATA`, :c:macro:`PyUnicode_1BYTE_DATA`, :c:macro:`PyUnicode_2BYTE_DATA`, :c:macro:`PyUnicode_4BYTE_DATA` - * :c:macro:`PyUnicode_KIND` with :c:enum:`PyUnicode_Kind` enum: + * :c:macro:`PyUnicode_KIND` with :c:enum:`!PyUnicode_Kind` enum: :c:data:`!PyUnicode_WCHAR_KIND`, :c:data:`PyUnicode_1BYTE_KIND`, :c:data:`PyUnicode_2BYTE_KIND`, :c:data:`PyUnicode_4BYTE_KIND` * :c:macro:`PyUnicode_READ`, :c:macro:`PyUnicode_READ_CHAR`, :c:macro:`PyUnicode_WRITE` @@ -2232,17 +2231,17 @@ Deprecated Python modules, functions and methods (``utf-32-le`` or ``utf-32-be``) * :meth:`ftplib.FTP.nlst` and :meth:`ftplib.FTP.dir`: use :meth:`ftplib.FTP.mlsd` -* :func:`platform.popen`: use the :mod:`subprocess` module. Check especially +* :func:`!platform.popen`: use the :mod:`subprocess` module. Check especially the :ref:`subprocess-replacements` section (:issue:`11377`). * :issue:`13374`: The Windows bytes API has been deprecated in the :mod:`os` module. Use Unicode filenames, instead of bytes filenames, to not depend on the ANSI code page anymore and to support any filename. -* :issue:`13988`: The :mod:`xml.etree.cElementTree` module is deprecated. The +* :issue:`13988`: The :mod:`!xml.etree.cElementTree` module is deprecated. The accelerator is used automatically whenever available. -* The behaviour of :func:`time.clock` depends on the platform: use the new +* The behaviour of :func:`!time.clock` depends on the platform: use the new :func:`time.perf_counter` or :func:`time.process_time` function instead, depending on your requirements, to have a well defined behaviour. -* The :func:`os.stat_float_times` function is deprecated. +* The :func:`!os.stat_float_times` function is deprecated. * :mod:`abc` module: * :class:`abc.abstractproperty` has been deprecated, use :class:`property` @@ -2466,7 +2465,7 @@ Porting C code * In the course of changes to the buffer API the undocumented :c:member:`!smalltable` member of the :c:type:`Py_buffer` structure has been removed and the - layout of the :c:type:`PyMemoryViewObject` has changed. + layout of the :c:type:`!PyMemoryViewObject` has changed. All extensions relying on the relevant parts in ``memoryobject.h`` or ``object.h`` must be rebuilt. diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index e4f602a17ee..a390211ddb5 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2,7 +2,7 @@ What's New In Python 3.4 **************************** -:Author: R. David Murray (Editor) +:Author: \R. David Murray (Editor) .. Rules for maintenance: @@ -122,7 +122,7 @@ Significantly improved library modules: on Unix ` (:issue:`8713`). * :mod:`email` has a new submodule, :mod:`~email.contentmanager`, and a new :mod:`~email.message.Message` subclass - (:class:`~email.contentmanager.EmailMessage`) that :ref:`simplify MIME + (:class:`~email.message.EmailMessage`) that :ref:`simplify MIME handling ` (:issue:`18891`). * The :mod:`inspect` and :mod:`pydoc` modules are now capable of correct introspection of a much wider variety of callable objects, @@ -154,7 +154,7 @@ Security improvements: `. * All modules in the standard library that support SSL now support server certificate verification, including hostname matching - (:func:`ssl.match_hostname`) and CRLs (Certificate Revocation lists, see + (:func:`!ssl.match_hostname`) and CRLs (Certificate Revocation lists, see :func:`ssl.SSLContext.load_verify_locations`). CPython implementation improvements: @@ -739,7 +739,7 @@ these new components. In addition, a new application-friendly class :class:`~dis.Bytecode` provides an object-oriented API for inspecting bytecode in both in human-readable form and for iterating over instructions. The :class:`~dis.Bytecode` constructor -takes the same arguments that :func:`~dis.get_instruction` does (plus an +takes the same arguments that :func:`~dis.get_instructions` does (plus an optional *current_offset*), and the resulting object can be iterated to produce :class:`~dis.Instruction` objects. But it also has a :mod:`~dis.Bytecode.dis` method, equivalent to calling :mod:`~dis.dis` on the constructor argument, but @@ -958,8 +958,9 @@ http optional additional *explain* parameter which can be used to provide an extended error description, overriding the hardcoded default if there is one. This extended error description will be formatted using the -:attr:`~http.server.HTTP.error_message_format` attribute and sent as the body -of the error response. (Contributed by Karl Cow in :issue:`12921`.) +:attr:`~http.server.BaseHTTPRequestHandler.error_message_format` attribute +and sent as the body of the error response. +(Contributed by Karl Cow in :issue:`12921`.) The :mod:`http.server` :ref:`command line interface ` now has a ``-b/--bind`` option that causes the server to listen on a specific address. @@ -1038,7 +1039,7 @@ As part of the implementation of the new :mod:`enum` module, the metaclasses. (Contributed by Ethan Furman in :issue:`18929` and :issue:`19030`.) -:func:`~inspect.getfullargspec` and :func:`~inspect.getargspec` +:func:`~inspect.getfullargspec` and :func:`!getargspec` now use the :func:`~inspect.signature` API. This allows them to support a much broader range of callables, including those with ``__signature__`` attributes, those with metadata provided by argument @@ -1221,7 +1222,7 @@ pickle :mod:`pickle` now supports (but does not use by default) a new pickle protocol, protocol 4. This new protocol addresses a number of issues that were present in previous protocols, such as the serialization of nested classes, very large -strings and containers, and classes whose :meth:`__new__` method takes +strings and containers, and classes whose :meth:`~object.__new__` method takes keyword-only arguments. It also provides some efficiency improvements. .. seealso:: @@ -1299,7 +1300,7 @@ affect the behaviour of :func:`help`. re -- -New :func:`~re.fullmatch` function and :meth:`.regex.fullmatch` method anchor +New :func:`~re.fullmatch` function and :meth:`.Pattern.fullmatch` method anchor the pattern at both ends of the string to match. This provides a way to be explicit about the goal of the match, which avoids a class of subtle bugs where ``$`` characters get lost during code changes or the addition of alternatives @@ -1519,7 +1520,7 @@ subprocess be used to provide the contents of ``stdin`` for the command that is run. (Contributed by Zack Weinberg in :issue:`16624`.) -:func:`~subprocess.getstatus` and :func:`~subprocess.getstatusoutput` now +:func:`~subprocess.getoutput` and :func:`~subprocess.getstatusoutput` now work on Windows. This change was actually inadvertently made in 3.3.4. (Contributed by Tim Golden in :issue:`10197`.) @@ -1535,7 +1536,7 @@ plain tuple. (Contributed by Claudiu Popa in :issue:`18901`.) called automatically at the end of the block. (Contributed by Serhiy Storchaka in :issue:`18878`.) -:meth:`.AU_write.setsampwidth` now supports 24 bit samples, thus adding +:meth:`!AU_write.setsampwidth` now supports 24 bit samples, thus adding support for writing 24 sample using the module. (Contributed by Serhiy Storchaka in :issue:`19261`.) @@ -1615,7 +1616,7 @@ A new :func:`~types.DynamicClassAttribute` descriptor provides a way to define an attribute that acts normally when looked up through an instance object, but which is routed to the *class* ``__getattr__`` when looked up through the class. This allows one to have properties active on a class, and have virtual -attributes on the class with the same name (see :mod:`Enum` for an example). +attributes on the class with the same name (see :mod:`enum` for an example). (Contributed by Ethan Furman in :issue:`19030`.) @@ -1709,7 +1710,7 @@ matching calls, which means an argument can now be matched by either position or name, instead of only by position. (Contributed by Antoine Pitrou in :issue:`17015`.) -:func:`~mock.mock_open` objects now have ``readline`` and ``readlines`` +:func:`~unittest.mock.mock_open` objects now have ``readline`` and ``readlines`` methods. (Contributed by Toshio Kuratomi in :issue:`17467`.) @@ -1729,8 +1730,8 @@ installed in the virtual environment. (Contributed by Nick Coghlan in wave ---- -The :meth:`~wave.getparams` method now returns a namedtuple rather than a -plain tuple. (Contributed by Claudiu Popa in :issue:`17487`.) +The :meth:`~wave.Wave_read.getparams` method now returns a namedtuple rather +than a plain tuple. (Contributed by Claudiu Popa in :issue:`17487`.) :meth:`wave.open` now supports the context management protocol. (Contributed by Claudiu Popa in :issue:`17616`.) @@ -1788,7 +1789,7 @@ example, this could be used to exclude test files from the archive. (Contributed by Christian Tismer in :issue:`19274`.) The *allowZip64* parameter to :class:`~zipfile.ZipFile` and -:class:`~zipfile.PyZipfile` is now ``True`` by default. (Contributed by +:class:`~zipfile.PyZipFile` is now ``True`` by default. (Contributed by William Mallard in :issue:`17201`.) @@ -1817,7 +1818,7 @@ PEP 442: Safe Object Finalization --------------------------------- :pep:`442` removes the current limitations and quirks of object finalization -in CPython. With it, objects with :meth:`__del__` methods, as well as +in CPython. With it, objects with :meth:`~object.__del__` methods, as well as generators with :keyword:`finally` clauses, can be finalized when they are part of a reference cycle. @@ -2043,7 +2044,7 @@ Significant Optimizations strings is now significantly faster. (Contributed by Victor Stinner and Antoine Pitrou in :issue:`15596`.) -* A performance issue in :meth:`io.FileIO.readall` has been solved. This +* A performance issue in :meth:`!io.FileIO.readall` has been solved. This particularly affects Windows, and significantly speeds up the case of piping significant amounts of data through :mod:`subprocess`. (Contributed by Richard Oudkerk in :issue:`15758`.) @@ -2085,10 +2086,10 @@ Deprecations in the Python API :meth:`!importlib.abc.PathEntryFinder.find_loader` and :meth:`!find_module` are replaced by :meth:`importlib.abc.PathEntryFinder.find_spec`; all of the :samp:`{xxx}Loader` ABC - ``load_module`` methods (:meth:`!importlib.abc.Loader.load_module`, - :meth:`!importlib.abc.InspectLoader.load_module`, - :meth:`!importlib.abc.FileLoader.load_module`, - :meth:`!importlib.abc.SourceLoader.load_module`) should no longer be + ``load_module`` methods (``importlib.abc.Loader.load_module``, + ``importlib.abc.InspectLoader.load_module``, + ``importlib.abc.FileLoader.load_module``, + ``importlib.abc.SourceLoader.load_module``) should no longer be implemented, instead loaders should implement an ``exec_module`` method (:meth:`importlib.abc.Loader.exec_module`, @@ -2103,7 +2104,7 @@ Deprecations in the Python API * The :mod:`!imp` module is pending deprecation. To keep compatibility with Python 2/3 code bases, the module's removal is currently not scheduled. -* The :mod:`formatter` module is pending deprecation and is slated for removal +* The :mod:`!formatter` module is pending deprecation and is slated for removal in Python 3.6. * ``MD5`` as the default *digestmod* for the :func:`hmac.new` function is @@ -2120,11 +2121,11 @@ Deprecations in the Python API * The *strict* argument of :class:`~html.parser.HTMLParser` is deprecated. -* The :mod:`plistlib` :func:`~plistlib.readPlist`, - :func:`~plistlib.writePlist`, :func:`~plistlib.readPlistFromBytes`, and - :func:`~plistlib.writePlistToBytes` functions are deprecated in favor of the +* The :mod:`plistlib` :func:`!readPlist`, + :func:`!writePlist`, :func:`!readPlistFromBytes`, and + :func:`!writePlistToBytes` functions are deprecated in favor of the corresponding new functions :func:`~plistlib.load`, :func:`~plistlib.dump`, - :func:`~plistlib.loads`, and :func:`~plistlib.dumps`. :func:`~plistlib.Data` + :func:`~plistlib.loads`, and :func:`~plistlib.dumps`. :func:`!Data` is deprecated in favor of just using the :class:`bytes` constructor. * The :mod:`sysconfig` key ``SO`` is deprecated, it has been replaced by @@ -2212,8 +2213,8 @@ removed: that do not have a __format__ method that handles it. See :issue:`7994` for background. -* :meth:`difflib.SequenceMatcher.isbjunk` and - :meth:`difflib.SequenceMatcher.isbpopular` were deprecated in 3.2, and have +* :meth:`!difflib.SequenceMatcher.isbjunk` and + :meth:`!difflib.SequenceMatcher.isbpopular` were deprecated in 3.2, and have now been removed: use ``x in sm.bjunk`` and ``x in sm.bpopular``, where *sm* is a :class:`~difflib.SequenceMatcher` object (:issue:`13248`). @@ -2280,7 +2281,7 @@ Changes in the Python API * :meth:`!importlib.util.module_for_loader` now sets ``__loader__`` and ``__package__`` unconditionally to properly support reloading. If this is not desired then you will need to set these attributes manually. You can use - :func:`importlib.util.module_to_load` for module management. + :func:`!importlib.util.module_to_load` for module management. * Import now resets relevant attributes (e.g. ``__name__``, ``__loader__``, ``__package__``, ``__file__``, ``__cached__``) unconditionally when reloading. @@ -2428,7 +2429,7 @@ Changes in the Python API disallowed command forms didn't make any sense and are unlikely to be in use. * The :func:`re.split`, :func:`re.findall`, and :func:`re.sub` functions, and - the :meth:`~re.match.group` and :meth:`~re.match.groups` methods of + the :meth:`~re.Match.group` and :meth:`~re.Match.groups` methods of ``match`` objects now always return a *bytes* object when the string to be matched is a :term:`bytes-like object`. Previously the return type matched the input type, so if your code was depending on the return value diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index db3f1db3bd7..6009dd8a71e 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -181,7 +181,7 @@ Coroutine functions are declared using the new :keyword:`async def` syntax:: Inside a coroutine function, the new :keyword:`await` expression can be used to suspend coroutine execution until the result is available. Any object can be *awaited*, as long as it implements the :term:`awaitable` protocol by -defining the :meth:`__await__` method. +defining the :meth:`~object.__await__` method. PEP 492 also adds :keyword:`async for` statement for convenient iteration over asynchronous iterables. @@ -273,9 +273,10 @@ PEP 465 - A dedicated infix operator for matrix multiplication :pep:`465` adds the ``@`` infix operator for matrix multiplication. Currently, no builtin Python types implement the new operator, however, it -can be implemented by defining :meth:`__matmul__`, :meth:`__rmatmul__`, -and :meth:`__imatmul__` for regular, reflected, and in-place matrix -multiplication. The semantics of these methods is similar to that of +can be implemented by defining :meth:`~object.__matmul__`, +:meth:`~object.__rmatmul__`, and :meth:`~object.__imatmul__` for regular, +reflected, and in-place matrix multiplication. +The semantics of these methods is similar to that of methods defining other infix arithmetic operators. Matrix multiplication is a notably common operation in many fields of @@ -800,7 +801,7 @@ Notable changes in the :mod:`asyncio` module since Python 3.4.0: control. (Contributed by Victor Stinner.) -* The :func:`~asyncio.async` function is deprecated in favor of +* The :func:`!async` function is deprecated in favor of :func:`~asyncio.ensure_future`. (Contributed by Yury Selivanov.) @@ -905,10 +906,8 @@ collections The :class:`~collections.OrderedDict` class is now implemented in C, which makes it 4 to 100 times faster. (Contributed by Eric Snow in :issue:`16991`.) -:meth:`OrderedDict.items() `, -:meth:`OrderedDict.keys() `, -:meth:`OrderedDict.values() ` views now support -:func:`reversed` iteration. +:meth:`!OrderedDict.items`, :meth:`!OrderedDict.keys`, +and :meth:`!OrderedDict.values` views now support :func:`reversed` iteration. (Contributed by Serhiy Storchaka in :issue:`19505`.) The :class:`~collections.deque` class now defines @@ -928,7 +927,7 @@ Docstrings produced by :func:`~collections.namedtuple` can now be updated:: (Contributed by Berker Peksag in :issue:`24064`.) The :class:`~collections.UserString` class now implements the -:meth:`__getnewargs__`, :meth:`__rmod__`, :meth:`~str.casefold`, +:meth:`~object.__getnewargs__`, :meth:`~object.__rmod__`, :meth:`~str.casefold`, :meth:`~str.format_map`, :meth:`~str.isprintable`, and :meth:`~str.maketrans` methods to match the corresponding methods of :class:`str`. (Contributed by Joe Jevnik in :issue:`22189`.) @@ -937,7 +936,7 @@ methods to match the corresponding methods of :class:`str`. collections.abc --------------- -The :meth:`Sequence.index() ` method now +The :meth:`!Sequence.index` method now accepts *start* and *stop* arguments to match the corresponding methods of :class:`tuple`, :class:`list`, etc. (Contributed by Devin Jeanpierre in :issue:`23086`.) @@ -1045,8 +1044,8 @@ not just sequences. (Contributed by Serhiy Storchaka in :issue:`23171`.) curses ------ -The new :func:`~curses.update_lines_cols` function updates the :data:`LINES` -and :data:`COLS` module variables. This is useful for detecting +The new :func:`~curses.update_lines_cols` function updates the :data:`~curses.LINES` +and :data:`~curses.COLS` module variables. This is useful for detecting manual screen resizing. (Contributed by Arnon Yaari in :issue:`4254`.) @@ -1347,8 +1346,8 @@ network objects from existing addresses:: (Contributed by Peter Moody and Antoine Pitrou in :issue:`16531`.) -A new :attr:`~ipaddress.IPv4Network.reverse_pointer` attribute for the -:class:`~ipaddress.IPv4Network` and :class:`~ipaddress.IPv6Network` classes +A new :attr:`~ipaddress.IPv4Address.reverse_pointer` attribute for the +:class:`~ipaddress.IPv4Address` and :class:`~ipaddress.IPv6Address` classes returns the name of the reverse DNS PTR record:: >>> import ipaddress @@ -1451,7 +1450,7 @@ and :data:`~math.nan`. (Contributed by Mark Dickinson in :issue:`23185`.) A new function :func:`~math.isclose` provides a way to test for approximate equality. (Contributed by Chris Barker and Tal Einat in :issue:`24270`.) -A new :func:`~math.gcd` function has been added. The :func:`fractions.gcd` +A new :func:`~math.gcd` function has been added. The :func:`!fractions.gcd` function is now deprecated. (Contributed by Mark Dickinson and Serhiy Storchaka in :issue:`22486`.) @@ -1602,10 +1601,10 @@ The :func:`~re.sub` and :func:`~re.subn` functions now replace unmatched groups with empty strings instead of raising an exception. (Contributed by Serhiy Storchaka in :issue:`1519638`.) -The :class:`re.error` exceptions have new attributes, -:attr:`~re.error.msg`, :attr:`~re.error.pattern`, -:attr:`~re.error.pos`, :attr:`~re.error.lineno`, -and :attr:`~re.error.colno`, that provide better context +The :class:`re.error ` exceptions have new attributes, +:attr:`~re.PatternError.msg`, :attr:`~re.PatternError.pattern`, +:attr:`~re.PatternError.pos`, :attr:`~re.PatternError.lineno`, +and :attr:`~re.PatternError.colno`, that provide better context information about the error:: >>> re.compile(""" @@ -1794,10 +1793,10 @@ query the actual protocol version in use. (Contributed by Antoine Pitrou in :issue:`20421`.) The :class:`~ssl.SSLSocket` class now implements -a :meth:`SSLSocket.sendfile() ` method. +a :meth:`!SSLSocket.sendfile` method. (Contributed by Giampaolo Rodola' in :issue:`17552`.) -The :meth:`SSLSocket.send() ` method now raises either +The :meth:`!SSLSocket.send` method now raises either the :exc:`ssl.SSLWantReadError` or :exc:`ssl.SSLWantWriteError` exception on a non-blocking socket if the operation would block. Previously, it would return ``0``. (Contributed by Nikolaus Rath in :issue:`20951`.) @@ -1806,20 +1805,20 @@ The :func:`~ssl.cert_time_to_seconds` function now interprets the input time as UTC and not as local time, per :rfc:`5280`. Additionally, the return value is always an :class:`int`. (Contributed by Akira Li in :issue:`19940`.) -New :meth:`SSLObject.shared_ciphers() ` and +New :meth:`!SSLObject.shared_ciphers` and :meth:`SSLSocket.shared_ciphers() ` methods return the list of ciphers sent by the client during the handshake. (Contributed by Benjamin Peterson in :issue:`23186`.) The :meth:`SSLSocket.do_handshake() `, :meth:`SSLSocket.read() `, -:meth:`SSLSocket.shutdown() `, and +:meth:`!SSLSocket.shutdown`, and :meth:`SSLSocket.write() ` methods of the :class:`~ssl.SSLSocket` class no longer reset the socket timeout every time bytes are received or sent. The socket timeout is now the maximum total duration of the method. (Contributed by Victor Stinner in :issue:`23853`.) -The :func:`~ssl.match_hostname` function now supports matching of IP addresses. +The :func:`!match_hostname` function now supports matching of IP addresses. (Contributed by Antoine Pitrou in :issue:`23239`.) @@ -1863,10 +1862,10 @@ Examples:: sys --- -A new :func:`~sys.set_coroutine_wrapper` function allows setting a global +A new :func:`!set_coroutine_wrapper` function allows setting a global hook that will be called whenever a :term:`coroutine object ` is created by an :keyword:`async def` function. A corresponding -:func:`~sys.get_coroutine_wrapper` can be used to obtain a currently set +:func:`!get_coroutine_wrapper` can be used to obtain a currently set wrapper. Both functions are :term:`provisional `, and are intended for debugging purposes only. (Contributed by Yury Selivanov in :issue:`24017`.) @@ -2014,8 +2013,9 @@ The :class:`~unittest.mock.Mock` class has the following improvements: method to check if the mock object was called. (Contributed by Kushal Das in :issue:`21262`.) -The :class:`~unittest.mock.MagicMock` class now supports :meth:`__truediv__`, -:meth:`__divmod__` and :meth:`__matmul__` operators. +The :class:`~unittest.mock.MagicMock` class now supports +:meth:`~object.__truediv__`, :meth:`~object.__divmod__` +and :meth:`~object.__matmul__` operators. (Contributed by Johannes Baiter in :issue:`20968`, and Håkan Lövdahl in :issue:`23581` and :issue:`23568`.) @@ -2290,10 +2290,10 @@ Windows XP is no longer supported by Microsoft, thus, per :PEP:`11`, CPython Deprecated Python modules, functions and methods ------------------------------------------------ -The :mod:`formatter` module has now graduated to full deprecation and is still +The :mod:`!formatter` module has now graduated to full deprecation and is still slated for removal in Python 3.6. -The :func:`asyncio.async` function is deprecated in favor of +The :func:`!asyncio.async` function is deprecated in favor of :func:`~asyncio.ensure_future`. The :mod:`!smtpd` module has in the past always decoded the DATA portion of @@ -2314,7 +2314,7 @@ Passing a format string as keyword argument *format_string* to the class has been deprecated. (Contributed by Serhiy Storchaka in :issue:`23671`.) -The :func:`platform.dist` and :func:`platform.linux_distribution` functions +The :func:`!platform.dist` and :func:`!platform.linux_distribution` functions are now deprecated. Linux distributions use too many different ways of describing themselves, so the functionality is left to a package. (Contributed by Vajrasky Kok and Berker Peksag in :issue:`1322`.) @@ -2324,11 +2324,11 @@ The previously undocumented ``from_function`` and ``from_builtin`` methods of :meth:`Signature.from_callable() ` method instead. (Contributed by Yury Selivanov in :issue:`24248`.) -The :func:`inspect.getargspec` function is deprecated and scheduled to be +The :func:`!inspect.getargspec` function is deprecated and scheduled to be removed in Python 3.6. (See :issue:`20438` for details.) The :mod:`inspect` :func:`~inspect.getfullargspec`, -:func:`~inspect.getcallargs`, and :func:`~inspect.formatargspec` functions are +:func:`~inspect.getcallargs`, and :func:`!formatargspec` functions are deprecated in favor of the :func:`inspect.signature` API. (Contributed by Yury Selivanov in :issue:`20438`.) @@ -2405,7 +2405,7 @@ Changes in the Python API error-prone and has been removed in Python 3.5. See :issue:`13936` for full details. -* The :meth:`ssl.SSLSocket.send` method now raises either +* The :meth:`!ssl.SSLSocket.send` method now raises either :exc:`ssl.SSLWantReadError` or :exc:`ssl.SSLWantWriteError` on a non-blocking socket if the operation would block. Previously, it would return ``0``. (Contributed by Nikolaus Rath in :issue:`20951`.) @@ -2440,12 +2440,12 @@ Changes in the Python API :mod:`http.client` and :mod:`http.server` remain available for backwards compatibility. (Contributed by Demian Brecht in :issue:`21793`.) -* When an import loader defines :meth:`importlib.machinery.Loader.exec_module` +* When an import loader defines :meth:`~importlib.abc.Loader.exec_module` it is now expected to also define - :meth:`~importlib.machinery.Loader.create_module` (raises a + :meth:`~importlib.abc.Loader.create_module` (raises a :exc:`DeprecationWarning` now, will be an error in Python 3.6). If the loader inherits from :class:`importlib.abc.Loader` then there is nothing to do, else - simply define :meth:`~importlib.machinery.Loader.create_module` to return + simply define :meth:`~importlib.abc.Loader.create_module` to return ``None``. (Contributed by Brett Cannon in :issue:`23014`.) * The :func:`re.split` function always ignored empty pattern matches, so the @@ -2488,7 +2488,7 @@ Changes in the Python API the POT-Creation-Date header. * The :mod:`smtplib` module now uses :data:`sys.stderr` instead of the previous - module-level :data:`stderr` variable for debug output. If your (test) + module-level :data:`!stderr` variable for debug output. If your (test) program depends on patching the module-level variable to capture the debug output, you will need to update it to capture sys.stderr instead. @@ -2514,11 +2514,11 @@ Changes in the C API -------------------- * The undocumented :c:member:`!format` member of the - (non-public) :c:type:`PyMemoryViewObject` structure has been removed. + (non-public) :c:type:`!PyMemoryViewObject` structure has been removed. All extensions relying on the relevant parts in ``memoryobject.h`` must be rebuilt. -* The :c:type:`PyMemAllocator` structure was renamed to +* The :c:type:`!PyMemAllocator` structure was renamed to :c:type:`PyMemAllocatorEx` and a new ``calloc`` field was added. * Removed non-documented macro :c:macro:`!PyObject_REPR()` which leaked references. diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 050c9103b00..9eafc09dbee 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -745,7 +745,7 @@ Some smaller changes made to the core Python language are: * It is now possible to set a :ref:`special method ` to ``None`` to indicate that the corresponding operation is not available. - For example, if a class sets :meth:`__iter__` to ``None``, the class + For example, if a class sets :meth:`~object.__iter__` to ``None``, the class is not iterable. (Contributed by Andrew Barnert and Ivan Levkivskyi in :issue:`25958`.) @@ -871,7 +871,7 @@ Notable changes in the :mod:`asyncio` module since Python 3.5.0 of the last iteration will be discarded. (Contributed by Guido van Rossum in :issue:`25593`.) -* :meth:`Future.set_exception ` +* :meth:`Future.set_exception ` will now raise :exc:`TypeError` when passed an instance of the :exc:`StopIteration` exception. (Contributed by Chris Angelico in :issue:`26221`.) @@ -925,7 +925,7 @@ added to represent sized iterable container classes. (Contributed by Ivan Levkivskyi, docs by Neil Girdhar in :issue:`27598`.) The new :class:`~collections.abc.Reversible` abstract base class represents -iterable classes that also provide the :meth:`__reversed__` method. +iterable classes that also provide the :meth:`~object.__reversed__` method. (Contributed by Ivan Levkivskyi in :issue:`25987`.) The new :class:`~collections.abc.AsyncGenerator` abstract base class represents @@ -971,7 +971,7 @@ datetime -------- The :class:`~datetime.datetime` and :class:`~datetime.time` classes have -the new :attr:`~time.fold` attribute used to disambiguate local time +the new :attr:`~datetime.time.fold` attribute used to disambiguate local time when necessary. Many functions in the :mod:`datetime` have been updated to support local time disambiguation. See :ref:`Local Time Disambiguation ` section for more @@ -1052,12 +1052,12 @@ enum ---- Two new enumeration base classes have been added to the :mod:`enum` module: -:class:`~enum.Flag` and :class:`~enum.IntFlags`. Both are used to define +:class:`~enum.Flag` and :class:`~enum.IntFlag`. Both are used to define constants that can be combined using the bitwise operators. (Contributed by Ethan Furman in :issue:`23591`.) Many standard library modules have been updated to use the -:class:`~enum.IntFlags` class for their constants. +:class:`~enum.IntFlag` class for their constants. The new :class:`enum.auto` value can be used to assign values to enum members automatically:: @@ -1224,7 +1224,7 @@ generator expression scopes as if they were positional-only parameters called ``implicit0``. (Contributed by Jelle Zijlstra in :issue:`19611`.) To reduce code churn when upgrading from Python 2.7 and the legacy -:func:`inspect.getargspec` API, the previously documented deprecation of +:func:`!inspect.getargspec` API, the previously documented deprecation of :func:`inspect.getfullargspec` has been reversed. While this function is convenient for single/source Python 2/3 code bases, the richer :func:`inspect.signature` interface remains the recommended approach for new @@ -1275,7 +1275,7 @@ See the summary of :ref:`PEP 519 ` for details on how the A new :meth:`~os.scandir.close` method allows explicitly closing a :func:`~os.scandir` iterator. The :func:`~os.scandir` iterator now -supports the :term:`context manager` protocol. If a :func:`scandir` +supports the :term:`context manager` protocol. If a :func:`!scandir` iterator is neither exhausted nor explicitly closed a :exc:`ResourceWarning` will be emitted in its destructor. (Contributed by Serhiy Storchaka in :issue:`25994`.) @@ -1434,7 +1434,7 @@ defined in :mod:`http.server`, :mod:`xmlrpc.server` and protocol. (Contributed by Aviv Palivoda in :issue:`26404`.) -The :attr:`~socketserver.StreamRequestHandler.wfile` attribute of +The :attr:`wfile ` attribute of :class:`~socketserver.StreamRequestHandler` classes now implements the :class:`io.BufferedIOBase` writable interface. In particular, calling :meth:`~io.BufferedIOBase.write` is now guaranteed to send the @@ -1465,7 +1465,7 @@ The new :meth:`~ssl.SSLContext.get_ciphers` method can be used to get a list of enabled ciphers in order of cipher priority. All constants and flags have been converted to :class:`~enum.IntEnum` and -:class:`~enum.IntFlags`. +:class:`~enum.IntFlag`. (Contributed by Christian Heimes in :issue:`28025`.) Server and client-side specific TLS protocols for :class:`~ssl.SSLContext` @@ -1531,8 +1531,8 @@ Stéphane Wirtel in :issue:`25485`). time ---- -The :class:`~time.struct_time` attributes :attr:`tm_gmtoff` and -:attr:`tm_zone` are now available on all platforms. +The :class:`~time.struct_time` attributes :attr:`!tm_gmtoff` and +:attr:`!tm_zone` are now available on all platforms. timeit @@ -1551,12 +1551,12 @@ between best and worst times. tkinter ------- -Added methods :meth:`~tkinter.Variable.trace_add`, -:meth:`~tkinter.Variable.trace_remove` and :meth:`~tkinter.Variable.trace_info` -in the :class:`tkinter.Variable` class. They replace old methods -:meth:`~tkinter.Variable.trace_variable`, :meth:`~tkinter.Variable.trace`, -:meth:`~tkinter.Variable.trace_vdelete` and -:meth:`~tkinter.Variable.trace_vinfo` that use obsolete Tcl commands and might +Added methods :meth:`!Variable.trace_add`, +:meth:`!Variable.trace_remove` and :meth:`!trace_info` +in the :class:`!tkinter.Variable` class. They replace old methods +:meth:`!trace_variable`, :meth:`!trace`, +:meth:`!trace_vdelete` and +:meth:`!trace_vinfo` that use obsolete Tcl commands and might not work in future versions of Tcl. (Contributed by Serhiy Storchaka in :issue:`22115`). @@ -1674,8 +1674,8 @@ urllib.request If a HTTP request has a file or iterable body (other than a bytes object) but no ``Content-Length`` header, rather than -throwing an error, :class:`~urllib.request.AbstractHTTPHandler` now -falls back to use chunked transfer encoding. +throwing an error, :class:`AbstractHTTPHandler ` +now falls back to use chunked transfer encoding. (Contributed by Demian Brecht and Rolf Krahl in :issue:`12319`.) @@ -1701,7 +1701,7 @@ warnings A new optional *source* parameter has been added to the :func:`warnings.warn_explicit` function: the destroyed object which emitted a :exc:`ResourceWarning`. A *source* attribute has also been added to -:class:`warnings.WarningMessage` (contributed by Victor Stinner in +:class:`!warnings.WarningMessage` (contributed by Victor Stinner in :issue:`26568` and :issue:`26567`). When a :exc:`ResourceWarning` warning is logged, the :mod:`tracemalloc` module is now @@ -1942,7 +1942,7 @@ Raising the :exc:`StopIteration` exception inside a generator will now generate a :exc:`DeprecationWarning`, and will trigger a :exc:`RuntimeError` in Python 3.7. See :ref:`whatsnew-pep-479` for details. -The :meth:`__aiter__` method is now expected to return an asynchronous +The :meth:`~object.__aiter__` method is now expected to return an asynchronous iterator directly instead of returning an awaitable as previously. Doing the former will trigger a :exc:`DeprecationWarning`. Backward compatibility will be removed in Python 3.7. @@ -2006,10 +2006,10 @@ deprecated. importlib ~~~~~~~~~ -The :meth:`importlib.machinery.SourceFileLoader.load_module` and -:meth:`importlib.machinery.SourcelessFileLoader.load_module` methods +The ``importlib.machinery.SourceFileLoader.load_module`` and +``importlib.machinery.SourcelessFileLoader.load_module`` methods are now deprecated. They were the only remaining implementations of -:meth:`importlib.abc.Loader.load_module` in :mod:`importlib` that had not +``importlib.abc.Loader.load_module`` in :mod:`importlib` that had not been deprecated in previous versions of Python in favour of :meth:`importlib.abc.Loader.exec_module`. @@ -2189,7 +2189,7 @@ Changes in the Python API booleans being a subclass of integers, this should only be an issue if you were doing identity checks for ``1`` or ``0``. See :issue:`25768`. -* Reading the :attr:`~urllib.parse.SplitResult.port` attribute of +* Reading the :attr:`!port` attribute of :func:`urllib.parse.urlsplit` and :func:`~urllib.parse.urlparse` results now raises :exc:`ValueError` for out-of-range values, rather than returning :const:`None`. See :issue:`20059`. @@ -2197,8 +2197,8 @@ Changes in the Python API * The :mod:`!imp` module now raises a :exc:`DeprecationWarning` instead of :exc:`PendingDeprecationWarning`. -* The following modules have had missing APIs added to their :attr:`__all__` - attributes to match the documented APIs: +* The following modules have had missing APIs added to their + :attr:`~module.__all__` attributes to match the documented APIs: :mod:`calendar`, :mod:`!cgi`, :mod:`csv`, :mod:`~xml.etree.ElementTree`, :mod:`enum`, :mod:`fileinput`, :mod:`ftplib`, :mod:`logging`, :mod:`mailbox`, @@ -2253,11 +2253,13 @@ Changes in the Python API * As part of :pep:`487`, the handling of keyword arguments passed to :class:`type` (other than the metaclass hint, ``metaclass``) is now consistently delegated to :meth:`object.__init_subclass__`. This means that - :meth:`type.__new__` and :meth:`type.__init__` both now accept arbitrary - keyword arguments, but :meth:`object.__init_subclass__` (which is called from - :meth:`type.__new__`) will reject them by default. Custom metaclasses - accepting additional keyword arguments will need to adjust their calls to - :meth:`type.__new__` (whether direct or via :class:`super`) accordingly. + :meth:`type.__new__ ` and :meth:`type.__init__ + ` both now accept arbitrary keyword arguments, + but :meth:`object.__init_subclass__` (which is called from + :meth:`type.__new__ `) will reject them by default. + Custom metaclasses accepting additional keyword arguments will need to adjust + their calls to :meth:`type.__new__ ` + (whether direct or via :class:`super`) accordingly. * In ``distutils.command.sdist.sdist``, the ``default_format`` attribute has been removed and is no longer honored. Instead, the @@ -2305,7 +2307,7 @@ Changes in the Python API real-world compatibility. (Contributed by Lita Cho in :issue:`21815`.) -* The :func:`mmap.write() ` function now returns the number +* The :func:`mmap.mmap.write` function now returns the number of bytes written like other write methods. (Contributed by Jakub Stasiak in :issue:`26335`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index f420fa5c044..32ca965b7d0 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -320,9 +320,9 @@ effort will be made to add such support. PEP 562: Customization of Access to Module Attributes ----------------------------------------------------- -Python 3.7 allows defining :meth:`__getattr__` on modules and will call +Python 3.7 allows defining :meth:`~module.__getattr__` on modules and will call it whenever a module attribute is otherwise not found. Defining -:meth:`__dir__` on modules is now also allowed. +:meth:`~module.__dir__` on modules is now also allowed. A typical example of where this may be useful is module attribute deprecation and lazy loading. @@ -409,8 +409,8 @@ PEP 560: Core Support for ``typing`` module and Generic Types Initially :pep:`484` was designed in such way that it would not introduce *any* changes to the core CPython interpreter. Now type hints and the :mod:`typing` module are extensively used by the community, so this restriction is removed. -The PEP introduces two special methods :meth:`__class_getitem__` and -``__mro_entries__``, these methods are now used by most classes and special +The PEP introduces two special methods :meth:`~object.__class_getitem__` and +:meth:`~object.__mro_entries__`, these methods are now used by most classes and special constructs in :mod:`typing`. As a result, the speed of various operations with types increased up to 7 times, the generic types can be used without metaclass conflicts, and several long standing bugs in :mod:`typing` module are @@ -603,7 +603,7 @@ The new :mod:`importlib.resources` module provides several new APIs and one new ABC for access to, opening, and reading *resources* inside packages. Resources are roughly similar to files inside packages, but they needn't be actual files on the physical file system. Module loaders can provide a -:meth:`get_resource_reader` function which returns +:meth:`!get_resource_reader` function which returns a :class:`importlib.abc.ResourceReader` instance to support this new API. Built-in file path loaders and zip file loaders both support this. @@ -841,7 +841,7 @@ and by Alexander Mohr and Ilya Kulakov in :issue:`29302`.) cProfile -------- -The :mod:`cProfile` command line now accepts ``-m module_name`` as an +The :mod:`!cProfile` command line now accepts ``-m module_name`` as an alternative to script path. (Contributed by Sanyam Khurana in :issue:`21862`.) @@ -910,9 +910,9 @@ which allows listing the names of properties which should not become enum members. (Contributed by Ethan Furman in :issue:`31801`.) -In Python 3.8, attempting to check for non-Enum objects in :class:`Enum` +In Python 3.8, attempting to check for non-Enum objects in :class:`~enum.Enum` classes will raise a :exc:`TypeError` (e.g. ``1 in Color``); similarly, -attempting to check for non-Flag objects in a :class:`Flag` member will +attempting to check for non-Flag objects in a :class:`~enum.Flag` member will raise :exc:`TypeError` (e.g. ``1 in Perm.RW``); currently, both operations return :const:`False` instead and are deprecated. (Contributed by Ethan Furman in :issue:`33217`.) @@ -969,7 +969,7 @@ uses the current working directory. (Contributed by Stéphane Wirtel and Julien Palard in :issue:`28707`.) The new :class:`ThreadingHTTPServer ` class -uses threads to handle requests using :class:`~socketserver.ThreadingMixin`. +uses threads to handle requests using :class:`~socketserver.ThreadingMixIn`. It is used when ``http.server`` is run with ``-m``. (Contributed by Julien Palard in :issue:`31639`.) @@ -1052,12 +1052,12 @@ support the loading of resources from packages. See also lacks a spec. (Contributed by Garvit Khatri in :issue:`29851`.) -:func:`importlib.find_spec` now raises :exc:`ModuleNotFoundError` instead of +:func:`importlib.util.find_spec` now raises :exc:`ModuleNotFoundError` instead of :exc:`AttributeError` if the specified parent module is not a package (i.e. lacks a ``__path__`` attribute). (Contributed by Milan Oberkirch in :issue:`30436`.) -The new :func:`importlib.source_hash` can be used to compute the hash of +The new :func:`importlib.util.source_hash` can be used to compute the hash of the passed source. A :ref:`hash-based .pyc file ` embeds the value returned by this function. @@ -1148,7 +1148,7 @@ running. (Contributed by Antoine Pitrou in :issue:`30596`.) The new :meth:`Process.kill() ` method can -be used to terminate the process using the :data:`SIGKILL` signal on Unix. +be used to terminate the process using the :data:`~signal.SIGKILL` signal on Unix. (Contributed by Vitor Pereira in :issue:`30794`.) Non-daemonic threads created by :class:`~multiprocessing.Process` are now @@ -1280,9 +1280,10 @@ This function should be used instead of :func:`os.close` for better compatibility across platforms. (Contributed by Christian Heimes in :issue:`32454`.) -The :mod:`socket` module now exposes the :const:`socket.TCP_CONGESTION` -(Linux 2.6.13), :const:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37), and -:const:`socket.TCP_NOTSENT_LOWAT` (Linux 3.12) constants. +The :mod:`socket` module now exposes the :ref:`socket.TCP_CONGESTION +` (Linux 2.6.13), :ref:`socket.TCP_USER_TIMEOUT +` (Linux 2.6.37), and :ref:`socket.TCP_NOTSENT_LOWAT +` (Linux 3.12) constants. (Contributed by Omar Sandoval in :issue:`26273` and Nathaniel J. Smith in :issue:`29728`.) @@ -1298,11 +1299,14 @@ by default. socketserver ------------ -:meth:`socketserver.ThreadingMixIn.server_close` now waits until all non-daemon -threads complete. :meth:`socketserver.ForkingMixIn.server_close` now waits +:meth:`socketserver.ThreadingMixIn.server_close +` now waits until all non-daemon +threads complete. :meth:`socketserver.ForkingMixIn.server_close +` now waits until all child processes complete. -Add a new :attr:`socketserver.ForkingMixIn.block_on_close` class attribute to +Add a new :attr:`socketserver.ForkingMixIn.block_on_close +` class attribute to :class:`socketserver.ForkingMixIn` and :class:`socketserver.ThreadingMixIn` classes. Set the class attribute to ``False`` to get the pre-3.7 behaviour. @@ -1323,7 +1327,7 @@ ssl --- The :mod:`ssl` module now uses OpenSSL's builtin API instead of -:func:`~ssl.match_hostname` to check a host name or an IP address. Values +:func:`!match_hostname` to check a host name or an IP address. Values are validated during TLS handshake. Any certificate validation error including failing the host name check now raises :exc:`~ssl.SSLCertVerificationError` and aborts the handshake with a proper @@ -1341,7 +1345,7 @@ Host name validation can be customized with The ``ssl`` module no longer sends IP addresses in SNI TLS extension. (Contributed by Christian Heimes in :issue:`32185`.) -:func:`~ssl.match_hostname` no longer supports partial wildcards like +:func:`!match_hostname` no longer supports partial wildcards like ``www*.example.org``. (Contributed by Mandeep Singh in :issue:`23033` and Christian Heimes in :issue:`31399`.) @@ -1438,7 +1442,7 @@ The new :func:`sys.get_coroutine_origin_tracking_depth` function returns the current coroutine origin tracking depth, as set by the new :func:`sys.set_coroutine_origin_tracking_depth`. :mod:`asyncio` has been converted to use this new API instead of -the deprecated :func:`sys.set_coroutine_wrapper`. +the deprecated :func:`!sys.set_coroutine_wrapper`. (Contributed by Nathaniel J. Smith in :issue:`32591`.) @@ -1615,7 +1619,7 @@ external entities by default. xml.etree --------- -:ref:`ElementPath ` predicates in the :meth:`find` +:ref:`ElementPath ` predicates in the :meth:`!find` methods can now compare text of the current node with ``[. = "text"]``, not only text in children. Predicates also allow adding spaces for better readability. (Contributed by Stefan Behnel in :issue:`31648`.) @@ -1624,7 +1628,7 @@ better readability. (Contributed by Stefan Behnel in :issue:`31648`.) xmlrpc.server ------------- -:meth:`SimpleXMLRPCDispatcher.register_function ` +:meth:`!SimpleXMLRPCDispatcher.register_function` can now be used as a decorator. (Contributed by Xiang Zhang in :issue:`7769`.) @@ -1682,15 +1686,15 @@ The :mod:`tracemalloc` now exposes a C API through the new functions. (Contributed by Victor Stinner in :issue:`30054`.) -The new :c:func:`import__find__load__start` and -:c:func:`import__find__load__done` static markers can be used to trace -module imports. +The new :ref:`import__find__load__start ` and +:ref:`import__find__load__done ` static markers can be used +to trace module imports. (Contributed by Christian Heimes in :issue:`31574`.) The fields :c:member:`!name` and :c:member:`!doc` of structures :c:type:`PyMemberDef`, :c:type:`PyGetSetDef`, :c:type:`PyStructSequence_Field`, :c:type:`PyStructSequence_Desc`, -and :c:struct:`wrapperbase` are now of type ``const char *`` rather of +and :c:struct:`!wrapperbase` are now of type ``const char *`` rather of ``char *``. (Contributed by Serhiy Storchaka in :issue:`28761`.) The result of :c:func:`PyUnicode_AsUTF8AndSize` and :c:func:`PyUnicode_AsUTF8` @@ -1719,8 +1723,8 @@ Added C API support for timezones with timezone constructors and access to the UTC singleton with :c:data:`PyDateTime_TimeZone_UTC`. Contributed by Paul Ganssle in :issue:`10381`. -The type of results of :c:func:`PyThread_start_new_thread` and -:c:func:`PyThread_get_thread_ident`, and the *id* parameter of +The type of results of :c:func:`!PyThread_start_new_thread` and +:c:func:`!PyThread_get_thread_ident`, and the *id* parameter of :c:func:`PyThreadState_SetAsyncExc` changed from :c:expr:`long` to :c:expr:`unsigned long`. (Contributed by Serhiy Storchaka in :issue:`6532`.) @@ -1847,8 +1851,8 @@ make the creation of named tuples 4 to 6 times faster. (Contributed by Jelle Zijlstra with further improvements by INADA Naoki, Serhiy Storchaka, and Raymond Hettinger in :issue:`28638`.) -:meth:`date.fromordinal` and :meth:`date.fromtimestamp` are now up to -30% faster in the common case. +:meth:`datetime.date.fromordinal` and :meth:`datetime.date.fromtimestamp` +are now up to 30% faster in the common case. (Contributed by Paul Ganssle in :issue:`32403`.) The :func:`os.fwalk` function is now up to 2 times faster thanks to @@ -1997,9 +2001,9 @@ modes (this will be an error in future Python releases). enum ---- -In Python 3.8, attempting to check for non-Enum objects in :class:`Enum` +In Python 3.8, attempting to check for non-Enum objects in :class:`~enum.Enum` classes will raise a :exc:`TypeError` (e.g. ``1 in Color``); similarly, -attempting to check for non-Flag objects in a :class:`Flag` member will +attempting to check for non-Flag objects in a :class:`~enum.Flag` member will raise :exc:`TypeError` (e.g. ``1 in Perm.RW``); currently, both operations return :const:`False` instead. (Contributed by Ethan Furman in :issue:`33217`.) @@ -2034,14 +2038,14 @@ favour of :class:`importlib.abc.ResourceReader`. locale ------ -:func:`locale.format` has been deprecated, use :meth:`locale.format_string` +:func:`!locale.format` has been deprecated, use :meth:`locale.format_string` instead. (Contributed by Garvit in :issue:`10379`.) macpath ------- -The :mod:`macpath` is now deprecated and will be removed in Python 3.8. +The :mod:`!macpath` is now deprecated and will be removed in Python 3.8. (Contributed by Chi Hsuan Yen in :issue:`9850`.) @@ -2066,7 +2070,7 @@ if the passed argument is larger than 16 bits, an exception will be raised. ssl --- -:func:`ssl.wrap_socket` is deprecated. Use +:func:`!ssl.wrap_socket` is deprecated. Use :meth:`ssl.SSLContext.wrap_socket` instead. (Contributed by Christian Heimes in :issue:`28124`.) @@ -2082,8 +2086,8 @@ Use :func:`!sunau.open` instead. sys --- -Deprecated :func:`sys.set_coroutine_wrapper` and -:func:`sys.get_coroutine_wrapper`. +Deprecated :func:`!sys.set_coroutine_wrapper` and +:func:`!sys.get_coroutine_wrapper`. The undocumented ``sys.callstats()`` function has been deprecated and will be removed in a future Python version. @@ -2093,7 +2097,7 @@ will be removed in a future Python version. wave ---- -:func:`wave.openfp` has been deprecated and will be removed in Python 3.9. +:func:`!wave.openfp` has been deprecated and will be removed in Python 3.9. Use :func:`wave.open` instead. (Contributed by Brian Curtin in :issue:`31985`.) @@ -2173,8 +2177,8 @@ The following features and APIs have been removed from Python 3.7: * Removed previously deprecated in Python 2.4 classes ``Plist``, ``Dict`` and ``_InternalDict`` in the :mod:`plistlib` module. Dict values in the result - of functions :func:`~plistlib.readPlist` and - :func:`~plistlib.readPlistFromBytes` are now normal dicts. You no longer + of functions :func:`!readPlist` and + :func:`!readPlistFromBytes` are now normal dicts. You no longer can use attribute access to access items of these dictionaries. * The ``asyncio.windows_utils.socketpair()`` function has been @@ -2191,7 +2195,7 @@ The following features and APIs have been removed from Python 3.7: * Direct instantiation of :class:`ssl.SSLSocket` and :class:`ssl.SSLObject` objects is now prohibited. The constructors were never documented, tested, or designed as public constructors. Users were supposed to use - :func:`ssl.wrap_socket` or :class:`ssl.SSLContext`. + :func:`!ssl.wrap_socket` or :class:`ssl.SSLContext`. (Contributed by Christian Heimes in :issue:`32951`.) * The unused ``distutils`` ``install_misc`` command has been removed. @@ -2275,15 +2279,18 @@ Changes in Python Behavior Changes in the Python API ------------------------- -* :meth:`socketserver.ThreadingMixIn.server_close` now waits until all +* :meth:`socketserver.ThreadingMixIn.server_close + ` now waits until all non-daemon threads complete. Set the new :attr:`socketserver.ThreadingMixIn.block_on_close` class attribute to ``False`` to get the pre-3.7 behaviour. (Contributed by Victor Stinner in :issue:`31233` and :issue:`33540`.) -* :meth:`socketserver.ForkingMixIn.server_close` now waits until all +* :meth:`socketserver.ForkingMixIn.server_close + ` now waits until all child processes complete. Set the new - :attr:`socketserver.ForkingMixIn.block_on_close` class attribute to ``False`` + :attr:`socketserver.ForkingMixIn.block_on_close + ` class attribute to ``False`` to get the pre-3.7 behaviour. (Contributed by Victor Stinner in :issue:`31151` and :issue:`33540`.) @@ -2476,7 +2483,7 @@ avoiding possible problems use new functions :c:func:`PySlice_Unpack` and CPython bytecode changes ------------------------ -There are two new opcodes: :opcode:`LOAD_METHOD` and :opcode:`!CALL_METHOD`. +There are two new opcodes: :opcode:`!LOAD_METHOD` and :opcode:`!CALL_METHOD`. (Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.) The :opcode:`!STORE_ANNOTATION` opcode has been removed. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index bc2eb1d0e26..545a17aecab 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -536,7 +536,7 @@ Other Language Changes element is a callable with a ``(obj, state)`` signature. This allows the direct control over the state-updating behavior of a specific object. If not *None*, this callable will have priority over the object's - :meth:`~__setstate__` method. + :meth:`~object.__setstate__` method. (Contributed by Pierre Glaser and Olivier Grisel in :issue:`35900`.) New Modules @@ -1035,9 +1035,9 @@ symlinks and directory junctions) has been delegated to the operating system. Specifically, :func:`os.stat` will now traverse anything supported by the operating system, while :func:`os.lstat` will only open reparse points that identify as "name surrogates" while others are opened as for :func:`os.stat`. -In all cases, :attr:`stat_result.st_mode` will only have ``S_IFLNK`` set for +In all cases, :attr:`os.stat_result.st_mode` will only have ``S_IFLNK`` set for symbolic links and not other kinds of reparse points. To identify other kinds -of reparse point, check the new :attr:`stat_result.st_reparse_tag` attribute. +of reparse point, check the new :attr:`os.stat_result.st_reparse_tag` attribute. On Windows, :func:`os.readlink` is now able to read directory junctions. Note that :func:`~os.path.islink` will return ``False`` for directory junctions, @@ -1285,20 +1285,20 @@ now matches what the C tokenizer does internally. tkinter ------- -Added methods :meth:`~tkinter.Spinbox.selection_from`, -:meth:`~tkinter.Spinbox.selection_present`, -:meth:`~tkinter.Spinbox.selection_range` and -:meth:`~tkinter.Spinbox.selection_to` -in the :class:`tkinter.Spinbox` class. +Added methods :meth:`!selection_from`, +:meth:`!selection_present`, +:meth:`!selection_range` and +:meth:`!selection_to` +in the :class:`!tkinter.Spinbox` class. (Contributed by Juliette Monsel in :issue:`34829`.) -Added method :meth:`~tkinter.Canvas.moveto` -in the :class:`tkinter.Canvas` class. +Added method :meth:`!moveto` +in the :class:`!tkinter.Canvas` class. (Contributed by Juliette Monsel in :issue:`23831`.) -The :class:`tkinter.PhotoImage` class now has -:meth:`~tkinter.PhotoImage.transparency_get` and -:meth:`~tkinter.PhotoImage.transparency_set` methods. (Contributed by +The :class:`!tkinter.PhotoImage` class now has +:meth:`!transparency_get` and +:meth:`!transparency_set` methods. (Contributed by Zackery Spytz in :issue:`25451`.) @@ -1432,7 +1432,7 @@ and ``{namespace}*`` which returns all tags in the given namespace. (Contributed by Stefan Behnel in :issue:`28238`.) The :mod:`xml.etree.ElementTree` module provides a new function -:func:`–xml.etree.ElementTree.canonicalize` that implements C14N 2.0. +:func:`~xml.etree.ElementTree.canonicalize` that implements C14N 2.0. (Contributed by Stefan Behnel in :issue:`13611`.) The target object of :class:`xml.etree.ElementTree.XMLParser` can @@ -1573,7 +1573,7 @@ Build and C API Changes * :c:func:`Py_INCREF`, :c:func:`Py_DECREF` * :c:func:`Py_XINCREF`, :c:func:`Py_XDECREF` - * :c:func:`PyObject_INIT`, :c:func:`PyObject_INIT_VAR` + * :c:macro:`!PyObject_INIT`, :c:macro:`!PyObject_INIT_VAR` * Private functions: :c:func:`!_PyObject_GC_TRACK`, :c:func:`!_PyObject_GC_UNTRACK`, :c:func:`!_Py_Dealloc` @@ -1677,7 +1677,7 @@ Deprecated constant nodes. (Contributed by Serhiy Storchaka in :issue:`36917`.) -* The :func:`asyncio.coroutine` :term:`decorator` is deprecated and will be +* The :deco:`!asyncio.coroutine` :term:`decorator` is deprecated and will be removed in version 3.10. Instead of ``@asyncio.coroutine``, use :keyword:`async def` instead. (Contributed by Andrew Svetlov in :issue:`36921`.) @@ -1697,22 +1697,22 @@ Deprecated (Contributed by Yury Selivanov in :issue:`34790`.) * The following functions and methods are deprecated in the :mod:`gettext` - module: :func:`~gettext.lgettext`, :func:`~gettext.ldgettext`, - :func:`~gettext.lngettext` and :func:`~gettext.ldngettext`. + module: :func:`!lgettext`, :func:`!ldgettext`, + :func:`!lngettext` and :func:`!ldngettext`. They return encoded bytes, and it's possible that you will get unexpected Unicode-related exceptions if there are encoding problems with the translated strings. It's much better to use alternatives which return Unicode strings in Python 3. These functions have been broken for a long time. - Function :func:`~gettext.bind_textdomain_codeset`, methods - :meth:`~gettext.NullTranslations.output_charset` and - :meth:`~gettext.NullTranslations.set_output_charset`, and the *codeset* + Function :func:`!bind_textdomain_codeset`, methods + :meth:`!NullTranslations.output_charset` and + :meth:`!NullTranslations.set_output_charset`, and the *codeset* parameter of functions :func:`~gettext.translation` and :func:`~gettext.install` are also deprecated, since they are only used for the ``l*gettext()`` functions. (Contributed by Serhiy Storchaka in :issue:`33710`.) -* The :meth:`~threading.Thread.isAlive` method of :class:`threading.Thread` +* The :meth:`!isAlive` method of :class:`threading.Thread` has been deprecated. (Contributed by Donghee Na in :issue:`35283`.) @@ -1727,7 +1727,7 @@ Deprecated * Deprecated passing the following arguments as keyword arguments: - *func* in :func:`functools.partialmethod`, :func:`weakref.finalize`, - :meth:`profile.Profile.runcall`, :meth:`cProfile.Profile.runcall`, + :meth:`profile.Profile.runcall`, :meth:`!cProfile.Profile.runcall`, :meth:`bdb.Bdb.runcall`, :meth:`trace.Trace.runfunc` and :func:`curses.wrapper`. - *function* in :meth:`unittest.TestCase.addCleanup`. @@ -1735,11 +1735,11 @@ Deprecated :class:`concurrent.futures.ThreadPoolExecutor` and :class:`concurrent.futures.ProcessPoolExecutor`. - *callback* in :meth:`contextlib.ExitStack.callback`, - :meth:`contextlib.AsyncExitStack.callback` and + :meth:`!contextlib.AsyncExitStack.callback` and :meth:`contextlib.AsyncExitStack.push_async_callback`. - - *c* and *typeid* in the :meth:`~multiprocessing.managers.Server.create` - method of :class:`multiprocessing.managers.Server` and - :class:`multiprocessing.managers.SharedMemoryServer`. + - *c* and *typeid* in the :meth:`!create` + method of :class:`!multiprocessing.managers.Server` and + :class:`!multiprocessing.managers.SharedMemoryServer`. - *obj* in :func:`weakref.finalize`. In future releases of Python, they will be :ref:`positional-only @@ -1757,14 +1757,14 @@ The following features and APIs have been removed from Python 3.8: able to import from collections was marked for removal in 3.8, but has been delayed to 3.9. (See :gh:`81134`.) -* The :mod:`macpath` module, deprecated in Python 3.7, has been removed. +* The :mod:`!macpath` module, deprecated in Python 3.7, has been removed. (Contributed by Victor Stinner in :issue:`35471`.) -* The function :func:`platform.popen` has been removed, after having been +* The function :func:`!platform.popen` has been removed, after having been deprecated since Python 3.3: use :func:`os.popen` instead. (Contributed by Victor Stinner in :issue:`35345`.) -* The function :func:`time.clock` has been removed, after having been +* The function :func:`!time.clock` has been removed, after having been deprecated since Python 3.3: use :func:`time.perf_counter` or :func:`time.process_time` instead, depending on your requirements, to have well-defined behavior. @@ -1800,8 +1800,8 @@ The following features and APIs have been removed from Python 3.8: :func:`fileinput.FileInput` which was ignored and deprecated since Python 3.6 has been removed. :issue:`36952` (Contributed by Matthias Bussonnier.) -* The functions :func:`sys.set_coroutine_wrapper` and - :func:`sys.get_coroutine_wrapper` deprecated in Python 3.7 have been removed; +* The functions :func:`!sys.set_coroutine_wrapper` and + :func:`!sys.get_coroutine_wrapper` deprecated in Python 3.7 have been removed; :issue:`36933` (Contributed by Matthias Bussonnier.) @@ -1864,9 +1864,10 @@ Changes in the Python API * :class:`subprocess.Popen` can now use :func:`os.posix_spawn` in some cases for better performance. On Windows Subsystem for Linux and QEMU User - Emulation, the :class:`Popen` constructor using :func:`os.posix_spawn` no longer raises an - exception on errors like "missing program". Instead the child process fails with a - non-zero :attr:`~Popen.returncode`. + Emulation, the :class:`~subprocess.Popen` constructor using + :func:`os.posix_spawn` no longer raises an exception on errors like + "missing program". Instead the child process fails with a + non-zero :attr:`~subprocess.Popen.returncode`. (Contributed by Joannah Nanjekye and Victor Stinner in :issue:`35537`.) * The *preexec_fn* argument of * :class:`subprocess.Popen` is no longer @@ -1875,11 +1876,11 @@ Changes in the Python API (Contributed by Eric Snow in :issue:`34651`, modified by Christian Heimes in :issue:`37951`.) -* The :meth:`imap.IMAP4.logout` method no longer silently ignores arbitrary +* The :meth:`imaplib.IMAP4.logout` method no longer silently ignores arbitrary exceptions. (Contributed by Victor Stinner in :issue:`36348`.) -* The function :func:`platform.popen` has been removed, after having been deprecated since +* The function :func:`!platform.popen` has been removed, after having been deprecated since Python 3.3: use :func:`os.popen` instead. (Contributed by Victor Stinner in :issue:`35345`.) @@ -1894,9 +1895,11 @@ Changes in the Python API specialized methods like :meth:`~tkinter.ttk.Treeview.selection_set` for changing the selection. (Contributed by Serhiy Storchaka in :issue:`31508`.) -* The :meth:`writexml`, :meth:`toxml` and :meth:`toprettyxml` methods of - :mod:`xml.dom.minidom`, and the :meth:`write` method of :mod:`xml.etree`, - now preserve the attribute order specified by the user. +* The :meth:`~xml.dom.minidom.Node.writexml`, :meth:`~xml.dom.minidom.Node.toxml` + and :meth:`~xml.dom.minidom.Node.toprettyxml` methods of + :mod:`xml.dom.minidom` and the :meth:`~xml.etree.ElementTree.ElementTree.write` + method of :mod:`xml.etree.ElementTree` now preserve the attribute order + specified by the user. (Contributed by Diego Rojas and Raymond Hettinger in :issue:`34160`.) * A :mod:`dbm.dumb` database opened with flags ``'r'`` is now read-only. @@ -1916,8 +1919,8 @@ Changes in the Python API ``type.__new__``. A :exc:`DeprecationWarning` was emitted in Python 3.6--3.7. (Contributed by Serhiy Storchaka in :issue:`23722`.) -* The :class:`cProfile.Profile` class can now be used as a context - manager. (Contributed by Scott Sanderson in :issue:`29235`.) +* The :class:`cProfile.Profile ` class can now be used as + a context manager. (Contributed by Scott Sanderson in :issue:`29235`.) * :func:`shutil.copyfile`, :func:`shutil.copy`, :func:`shutil.copy2`, :func:`shutil.copytree` and :func:`shutil.move` use platform-specific @@ -1952,7 +1955,7 @@ Changes in the Python API (Contributed by Christian Heimes in :issue:`17239`.) * Deleting a key from a read-only :mod:`dbm` database (:mod:`dbm.dumb`, - :mod:`dbm.gnu` or :mod:`dbm.ndbm`) raises :attr:`error` (:exc:`dbm.dumb.error`, + :mod:`dbm.gnu` or :mod:`dbm.ndbm`) raises :attr:`!error` (:exc:`dbm.dumb.error`, :exc:`dbm.gnu.error` or :exc:`dbm.ndbm.error`) instead of :exc:`KeyError`. (Contributed by Xiang Zhang in :issue:`33106`.) @@ -2044,7 +2047,7 @@ Changes in the C API :c:func:`PyType_FromSpec`) hold a reference to their type object. Increasing the reference count of these type objects has been moved from :c:func:`PyType_GenericAlloc` to the more low-level functions, - :c:func:`PyObject_Init` and :c:func:`PyObject_INIT`. + :c:func:`PyObject_Init` and :c:macro:`!PyObject_INIT`. This makes types created through :c:func:`PyType_FromSpec` behave like other classes in managed code. @@ -2064,7 +2067,7 @@ Changes in the C API This may happen after calling :c:macro:`PyObject_New`, :c:macro:`PyObject_NewVar`, :c:func:`PyObject_GC_New`, :c:func:`PyObject_GC_NewVar`, or any other custom allocator that uses - :c:func:`PyObject_Init` or :c:func:`PyObject_INIT`. + :c:func:`PyObject_Init` or :c:macro:`!PyObject_INIT`. Example: diff --git a/Grammar/python.gram b/Grammar/python.gram index d36d55183ce..110136af81b 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -212,7 +212,9 @@ del_stmt[stmt_ty]: yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) } -assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) } +assert_stmt[stmt_ty]: + | invalid_assert_stmt + | 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) } import_stmt[stmt_ty]: | invalid_import @@ -624,6 +626,7 @@ mapping_pattern[pattern_ty]: CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, items)), NULL, EXTRA) } + | invalid_mapping_pattern items_pattern[asdl_seq*]: | ','.key_value_pattern+ @@ -1248,8 +1251,7 @@ invalid_expression: # !(NAME STRING) is not matched so we don't show this error with some invalid string prefixes like: kf"dsfsdf" # Soft keywords need to also be ignored because they can be parsed as NAME NAME | !(NAME STRING | SOFT_KEYWORD) a=disjunction b=expression_without_invalid { - _PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL : - RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") } + _PyPegen_raise_error_for_missing_comma(p, a, b) } | a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") } | a=disjunction 'if' b=disjunction 'else' !expression { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("expected expression after 'else', but statement is given") } @@ -1302,6 +1304,25 @@ invalid_raise_stmt: invalid_del_stmt: | 'del' a=star_expressions { RAISE_SYNTAX_ERROR_INVALID_TARGET(DEL_TARGETS, a) } +invalid_assert_stmt: + | 'assert' a=expression '=' b=expression { + RAISE_SYNTAX_ERROR_KNOWN_RANGE( + a, b, + "cannot assign to %s here. Maybe you meant '==' instead of '='?", + _PyPegen_get_expr_name(a)) } + | 'assert' expression ',' a=expression '=' b=expression { + RAISE_SYNTAX_ERROR_KNOWN_RANGE( + a, b, + "cannot assign to %s here. Maybe you meant '==' instead of '='?", + _PyPegen_get_expr_name(a)) } + | 'assert' a=expression ':=' b=expression { + RAISE_SYNTAX_ERROR_KNOWN_RANGE( + a, b, + "cannot use named expression without parentheses here") } + | 'assert' expression ',' a=expression ':=' b=expression { + RAISE_SYNTAX_ERROR_KNOWN_RANGE( + a, b, + "cannot use named expression without parentheses here") } invalid_block: | NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") } invalid_comprehension: @@ -1394,11 +1415,11 @@ invalid_import: | 'import' token=NEWLINE { RAISE_SYNTAX_ERROR_STARTING_FROM(token, "Expected one or more names after 'import'") } invalid_dotted_as_name: - | dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) a=expression { + | dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) a=expression { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use %s as import target", _PyPegen_get_expr_name(a)) } invalid_import_from_as_name: - | NAME 'as' !(NAME (',' | ')' | NEWLINE)) a=expression { + | NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) a=expression { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use %s as import target", _PyPegen_get_expr_name(a)) } @@ -1455,6 +1476,10 @@ invalid_match_stmt: | "match" subject_expr NEWLINE { CHECK_VERSION(void*, 10, "Pattern matching is", RAISE_SYNTAX_ERROR("expected ':'") ) } | a="match" subject=subject_expr ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after 'match' statement on line %d", a->lineno) } + | a="case" patterns guard? b=':' block { + RAISE_SYNTAX_ERROR_KNOWN_RANGE( + a, b, + "case statement must be inside match statement") } invalid_case_block: | "case" patterns guard? NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") } | a="case" patterns guard? ':' NEWLINE !INDENT { @@ -1469,6 +1494,10 @@ invalid_class_pattern: PyPegen_first_item(a, pattern_ty), PyPegen_last_item(a, pattern_ty), "positional patterns follow keyword patterns") } +invalid_mapping_pattern: + | '{' (items_pattern ',')? rest=double_star_pattern ',' items_pattern ','? '}' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION( + rest, + "double star pattern must be the last (right-most) subpattern in the mapping pattern") } invalid_class_argument_pattern[asdl_pattern_seq*]: | [positional_patterns ','] keyword_patterns ',' a=positional_patterns { a } invalid_if_stmt: diff --git a/Include/Python.h b/Include/Python.h index 261b4d316bd..78083bbf31d 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -78,7 +78,7 @@ __pragma(warning(disable: 4201)) #include "pybuffer.h" #include "pystats.h" #include "pyatomic.h" -#include "pylock.h" +#include "cpython/pylock.h" #include "critical_section.h" #include "object.h" #include "refcount.h" @@ -105,7 +105,7 @@ __pragma(warning(disable: 4201)) #include "setobject.h" #include "methodobject.h" #include "moduleobject.h" -#include "monitoring.h" +#include "cpython/monitoring.h" #include "cpython/funcobject.h" #include "cpython/classobject.h" #include "fileobject.h" diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index ffd19ccd350..7490ece52e5 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -6,7 +6,7 @@ /* Like PyObject_CallMethod(), but expect a _Py_Identifier* as the method name. */ -PyAPI_FUNC(PyObject*) _PyObject_CallMethodId( +Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyObject_CallMethodId( PyObject *obj, _Py_Identifier *name, const char *format, ...); diff --git a/Include/cpython/bytearrayobject.h b/Include/cpython/bytearrayobject.h index 4dddef713ce..1edd0820742 100644 --- a/Include/cpython/bytearrayobject.h +++ b/Include/cpython/bytearrayobject.h @@ -5,25 +5,25 @@ /* Object layout */ typedef struct { PyObject_VAR_HEAD - Py_ssize_t ob_alloc; /* How many bytes allocated in ob_bytes */ + /* How many bytes allocated in ob_bytes + + In the current implementation this is equivalent to Py_SIZE(ob_bytes_object). + The value is always loaded and stored atomically for thread safety. + There are API compatibilty concerns with removing so keeping for now. */ + Py_ssize_t ob_alloc; char *ob_bytes; /* Physical backing buffer */ char *ob_start; /* Logical start inside ob_bytes */ Py_ssize_t ob_exports; /* How many buffer exports */ + PyObject *ob_bytes_object; /* PyBytes for zero-copy bytes conversion */ } PyByteArrayObject; -PyAPI_DATA(char) _PyByteArray_empty_string[]; - /* Macros and static inline functions, trading safety for speed */ #define _PyByteArray_CAST(op) \ (assert(PyByteArray_Check(op)), _Py_CAST(PyByteArrayObject*, op)) static inline char* PyByteArray_AS_STRING(PyObject *op) { - PyByteArrayObject *self = _PyByteArray_CAST(op); - if (Py_SIZE(self)) { - return self->ob_start; - } - return _PyByteArray_empty_string; + return _PyByteArray_CAST(op)->ob_start; } #define PyByteArray_AS_STRING(self) PyByteArray_AS_STRING(_PyObject_CAST(self)) diff --git a/Include/cpython/bytesobject.h b/Include/cpython/bytesobject.h index 71c133f173f..85bc2b827df 100644 --- a/Include/cpython/bytesobject.h +++ b/Include/cpython/bytesobject.h @@ -40,3 +40,46 @@ _PyBytes_Join(PyObject *sep, PyObject *iterable) { return PyBytes_Join(sep, iterable); } + + +// --- PyBytesWriter API ----------------------------------------------------- + +typedef struct PyBytesWriter PyBytesWriter; + +PyAPI_FUNC(PyBytesWriter *) PyBytesWriter_Create( + Py_ssize_t size); +PyAPI_FUNC(void) PyBytesWriter_Discard( + PyBytesWriter *writer); +PyAPI_FUNC(PyObject*) PyBytesWriter_Finish( + PyBytesWriter *writer); +PyAPI_FUNC(PyObject*) PyBytesWriter_FinishWithSize( + PyBytesWriter *writer, + Py_ssize_t size); +PyAPI_FUNC(PyObject*) PyBytesWriter_FinishWithPointer( + PyBytesWriter *writer, + void *buf); + +PyAPI_FUNC(void*) PyBytesWriter_GetData( + PyBytesWriter *writer); +PyAPI_FUNC(Py_ssize_t) PyBytesWriter_GetSize( + PyBytesWriter *writer); + +PyAPI_FUNC(int) PyBytesWriter_WriteBytes( + PyBytesWriter *writer, + const void *bytes, + Py_ssize_t size); +PyAPI_FUNC(int) PyBytesWriter_Format( + PyBytesWriter *writer, + const char *format, + ...); + +PyAPI_FUNC(int) PyBytesWriter_Resize( + PyBytesWriter *writer, + Py_ssize_t size); +PyAPI_FUNC(int) PyBytesWriter_Grow( + PyBytesWriter *writer, + Py_ssize_t size); +PyAPI_FUNC(void*) PyBytesWriter_GrowAndUpdatePointer( + PyBytesWriter *writer, + Py_ssize_t size, + void *buf); diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 3f0dce03455..84456a709a6 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -282,15 +282,6 @@ typedef struct _line_offsets { */ PyAPI_FUNC(int) _PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds); -/* Create a comparable key used to compare constants taking in account the - * object type. It is used to make sure types are not coerced (e.g., float and - * complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms - * - * Return (type(obj), obj, ...): a tuple with variable size (at least 2 items) - * depending on the type and the value. The type is the first item to not - * compare bytes and str which can raise a BytesWarning exception. */ -PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj); - PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, PyObject *lnotab); diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h index df9ec7050fc..5f2f7b6d4f5 100644 --- a/Include/cpython/dictobject.h +++ b/Include/cpython/dictobject.h @@ -39,16 +39,6 @@ Py_DEPRECATED(3.14) PyAPI_FUNC(PyObject *) _PyDict_GetItemStringWithError(PyObje PyAPI_FUNC(PyObject *) PyDict_SetDefault( PyObject *mp, PyObject *key, PyObject *defaultobj); -// Inserts `key` with a value `default_value`, if `key` is not already present -// in the dictionary. If `result` is not NULL, then the value associated -// with `key` is returned in `*result` (either the existing value, or the now -// inserted `default_value`). -// Returns: -// -1 on error -// 0 if `key` was not present and `default_value` was inserted -// 1 if `key` was present and `default_value` was not inserted -PyAPI_FUNC(int) PyDict_SetDefaultRef(PyObject *mp, PyObject *key, PyObject *default_value, PyObject **result); - /* Get the number of items of a dictionary. */ static inline Py_ssize_t PyDict_GET_SIZE(PyObject *op) { PyDictObject *mp; diff --git a/Include/cpython/funcobject.h b/Include/cpython/funcobject.h index 598cd330bc9..9e1599a7648 100644 --- a/Include/cpython/funcobject.h +++ b/Include/cpython/funcobject.h @@ -134,7 +134,8 @@ PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *); V(DESTROY) \ V(MODIFY_CODE) \ V(MODIFY_DEFAULTS) \ - V(MODIFY_KWDEFAULTS) + V(MODIFY_KWDEFAULTS) \ + V(MODIFY_QUALNAME) typedef enum { #define PY_DEF_EVENT(EVENT) PyFunction_EVENT_##EVENT, diff --git a/Include/cpython/import.h b/Include/cpython/import.h index 0ce0b1ee6cc..149a20af8b9 100644 --- a/Include/cpython/import.h +++ b/Include/cpython/import.h @@ -10,6 +10,13 @@ struct _inittab { PyAPI_DATA(struct _inittab *) PyImport_Inittab; PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab); +// Custom importers may use this API to initialize statically linked +// extension modules directly from a spec and init function, +// without needing to go through inittab +PyAPI_FUNC(PyObject *) PyImport_CreateModuleFromInitfunc( + PyObject *spec, + PyObject *(*initfunc)(void)); + struct _frozen { const char *name; /* ASCII encoded string */ const unsigned char *code; diff --git a/Include/cpython/marshal.h b/Include/cpython/marshal.h new file mode 100644 index 00000000000..6c1f7f96b6a --- /dev/null +++ b/Include/cpython/marshal.h @@ -0,0 +1,17 @@ +#ifndef _Py_CPYTHON_MARSHAL_H +# error "this header file must not be included directly" +#endif + +PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *, + Py_ssize_t); +PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); + +#define Py_MARSHAL_VERSION 5 + +PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *); +PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *); + +PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int); +PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int); diff --git a/Include/cpython/modsupport.h b/Include/cpython/modsupport.h index d3b88f58c82..61344421064 100644 --- a/Include/cpython/modsupport.h +++ b/Include/cpython/modsupport.h @@ -24,3 +24,15 @@ typedef struct _PyArg_Parser { PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *, struct _PyArg_Parser *, ...); + +#ifdef Py_BUILD_CORE +// Internal; defined here to avoid explicitly including pycore_modsupport.h +#define _Py_INTERNAL_ABI_SLOT \ + {Py_mod_abi, (void*) &(PyABIInfo) { \ + .abiinfo_major_version = 1, \ + .abiinfo_minor_version = 0, \ + .flags = PyABIInfo_INTERNAL, \ + .build_version = PY_VERSION_HEX, \ + .abi_version = PY_VERSION_HEX }} \ + /////////////////////////////////////////////////////// +#endif diff --git a/Include/cpython/monitoring.h b/Include/cpython/monitoring.h index ce92942404c..5094c8c23ae 100644 --- a/Include/cpython/monitoring.h +++ b/Include/cpython/monitoring.h @@ -1,7 +1,13 @@ -#ifndef Py_CPYTHON_MONITORING_H -# error "this header file must not be included directly" +#ifndef Py_MONITORING_H +#define Py_MONITORING_H +#ifndef Py_LIMITED_API +#ifdef __cplusplus +extern "C" { #endif +// There is currently no limited API for monitoring + + /* Local events. * These require bytecode instrumentation */ @@ -267,3 +273,9 @@ PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike } #undef _PYMONITORING_IF_ACTIVE + +#ifdef __cplusplus +} +#endif +#endif // !Py_LIMITED_API +#endif // !Py_MONITORING_H diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 973d358ed8e..85d5edd62e3 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -295,9 +295,12 @@ PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *); PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); PyAPI_FUNC(void) _Py_BreakPoint(void); -PyAPI_FUNC(void) _PyObject_Dump(PyObject *); +PyAPI_FUNC(void) PyUnstable_Object_Dump(PyObject *); -PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *); +// Alias for backward compatibility +#define _PyObject_Dump PyUnstable_Object_Dump + +Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *); PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); @@ -387,10 +390,11 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *); process with a message on stderr if the given condition fails to hold, but compile away to nothing if NDEBUG is defined. - However, before aborting, Python will also try to call _PyObject_Dump() on - the given object. This may be of use when investigating bugs in which a - particular object is corrupt (e.g. buggy a tp_visit method in an extension - module breaking the garbage collector), to help locate the broken objects. + However, before aborting, Python will also try to call + PyUnstable_Object_Dump() on the given object. This may be of use when + investigating bugs in which a particular object is corrupt (e.g. buggy a + tp_visit method in an extension module breaking the garbage collector), to + help locate the broken objects. The WITH_MSG variant allows you to supply an additional message that Python will attempt to print to stderr, after the object dump. */ @@ -432,8 +436,6 @@ PyAPI_FUNC(void) _Py_NO_RETURN _PyObject_AssertFailed( PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op); PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate); -PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count); - /* For backwards compatibility with the old trashcan mechanism */ #define Py_TRASHCAN_BEGIN(op, dealloc) #define Py_TRASHCAN_END @@ -442,7 +444,6 @@ PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int m PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj); PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg); -PyAPI_FUNC(int) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict); PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj); @@ -463,6 +464,7 @@ PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type); typedef enum { PyRefTracer_CREATE = 0, PyRefTracer_DESTROY = 1, + PyRefTracer_TRACKER_REMOVED = 2, } PyRefTracerEvent; typedef int (*PyRefTracer)(PyObject *, PyRefTracerEvent event, void *); diff --git a/Include/cpython/pyatomic.h b/Include/cpython/pyatomic.h index 2a0c11e7b3a..790640309f1 100644 --- a/Include/cpython/pyatomic.h +++ b/Include/cpython/pyatomic.h @@ -591,6 +591,17 @@ static inline void _Py_atomic_fence_release(void); // --- aliases --------------------------------------------------------------- +// Compilers don't really support "consume" semantics, so we fake it. Use +// "acquire" with TSan to support false positives. Use "relaxed" otherwise, +// because CPUs on all platforms we support respect address dependencies without +// extra barriers. +// See 2.6.7 in https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2055r0.pdf +#if defined(_Py_THREAD_SANITIZER) +# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_acquire +#else +# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_relaxed +#endif + #if SIZEOF_LONG == 8 # define _Py_atomic_load_ulong(p) \ _Py_atomic_load_uint64((uint64_t *)p) diff --git a/Include/cpython/pyatomic_std.h b/Include/cpython/pyatomic_std.h index 69a8b9e615e..7176f667a40 100644 --- a/Include/cpython/pyatomic_std.h +++ b/Include/cpython/pyatomic_std.h @@ -948,14 +948,6 @@ _Py_atomic_store_ushort_relaxed(unsigned short *obj, unsigned short value) memory_order_relaxed); } -static inline void -_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value) -{ - _Py_USING_STD; - atomic_store_explicit((_Atomic(unsigned int)*)obj, value, - memory_order_relaxed); -} - static inline void _Py_atomic_store_long_relaxed(long *obj, long value) { @@ -1031,6 +1023,14 @@ _Py_atomic_store_int_release(int *obj, int value) memory_order_release); } +static inline void +_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value) +{ + _Py_USING_STD; + atomic_store_explicit((_Atomic(unsigned int)*)obj, value, + memory_order_release); +} + static inline void _Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value) { diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 6b63d304b0d..be2e3b641c2 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -18,6 +18,7 @@ typedef struct { PyException_HEAD PyObject *msg; PyObject *excs; + PyObject *excs_str; } PyBaseExceptionGroupObject; typedef struct { diff --git a/Include/cpython/pyhash.h b/Include/cpython/pyhash.h index a33ba10b8d3..dac223368db 100644 --- a/Include/cpython/pyhash.h +++ b/Include/cpython/pyhash.h @@ -7,7 +7,7 @@ /* Parameters used for the numeric hash implementation. See notes for _Py_HashDouble in Python/pyhash.c. Numeric hashes are based on - reduction modulo the prime 2**_PyHASH_BITS - 1. */ + reduction modulo the prime 2**PyHASH_BITS - 1. */ #if SIZEOF_VOID_P >= 8 # define PyHASH_BITS 61 @@ -15,7 +15,7 @@ # define PyHASH_BITS 31 #endif -#define PyHASH_MODULUS (((size_t)1 << _PyHASH_BITS) - 1) +#define PyHASH_MODULUS (((size_t)1 << PyHASH_BITS) - 1) #define PyHASH_INF 314159 #define PyHASH_IMAG PyHASH_MULTIPLIER diff --git a/Include/cpython/pylock.h b/Include/cpython/pylock.h index 63886fca28e..460ac2c9f80 100644 --- a/Include/cpython/pylock.h +++ b/Include/cpython/pylock.h @@ -1,7 +1,11 @@ -#ifndef Py_CPYTHON_LOCK_H -# error "this header file must not be included directly" +#ifndef Py_LOCK_H +#define Py_LOCK_H +#ifndef Py_LIMITED_API +#ifdef __cplusplus +extern "C" { #endif + #define _Py_UNLOCKED 0 #define _Py_LOCKED 1 @@ -72,3 +76,10 @@ _PyMutex_IsLocked(PyMutex *m) return (_Py_atomic_load_uint8(&m->_bits) & _Py_LOCKED) != 0; } #define PyMutex_IsLocked _PyMutex_IsLocked + + +#ifdef __cplusplus +} +#endif +#endif // !Py_LIMITED_API +#endif // !Py_LOCK_H diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index e13b2b373c4..22df26bd37a 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -28,10 +28,10 @@ typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *); #define PyTrace_OPCODE 7 /* Remote debugger support */ -#define Py_MAX_SCRIPT_PATH_SIZE 512 +#define _Py_MAX_SCRIPT_PATH_SIZE 512 typedef struct { int32_t debugger_pending_call; - char debugger_script_path[Py_MAX_SCRIPT_PATH_SIZE]; + char debugger_script_path[_Py_MAX_SCRIPT_PATH_SIZE]; } _PyRemoteDebuggerSupport; typedef struct _err_stackitem { @@ -107,11 +107,15 @@ struct _ts { # define _PyThreadState_WHENCE_THREADING 3 # define _PyThreadState_WHENCE_GILSTATE 4 # define _PyThreadState_WHENCE_EXEC 5 +# define _PyThreadState_WHENCE_THREADING_DAEMON 6 #endif /* Currently holds the GIL. Must be its own field to avoid data races */ int holds_gil; + /* Currently requesting the GIL */ + int gil_requested; + int _whence; /* Thread state (_Py_THREAD_ATTACHED, _Py_THREAD_DETACHED, _Py_THREAD_SUSPENDED). @@ -131,6 +135,15 @@ struct _ts { /* Pointer to currently executing frame. */ struct _PyInterpreterFrame *current_frame; + /* Pointer to the base frame (bottommost sentinel frame). + Used by profilers to validate complete stack unwinding. + Points to the embedded base_frame in _PyThreadStateImpl. + The frame is embedded there rather than here because _PyInterpreterFrame + is defined in internal headers that cannot be exposed in the public API. */ + struct _PyInterpreterFrame *base_frame; + + struct _PyInterpreterFrame *last_profiled_frame; + Py_tracefunc c_profilefunc; Py_tracefunc c_tracefunc; PyObject *c_profileobj; @@ -157,6 +170,11 @@ struct _ts { */ unsigned long native_thread_id; + /* List of objects that still need to be cleaned up, singly linked + * via their gc headers' gc_next pointers. The list is populated by + * _PyTrash_thread_deposit_object and cleaned up by + * _PyTrash_thread_destroy_chain. + */ PyObject *delete_later; /* Tagged pointer to top-most critical section, or zero if there is no @@ -211,6 +229,15 @@ struct _ts { */ PyObject *threading_local_sentinel; _PyRemoteDebuggerSupport remote_debugger_support; + +#ifdef Py_STATS + // Pointer to PyStats structure, NULL if recording is off. For the + // free-threaded build, the structure is per-thread (stored as a pointer + // in _PyThreadStateImpl). For the default build, the structure is stored + // in the PyInterpreterState structure (threads do not have their own + // structure and all share the same per-interpreter structure). + PyStats *pystats; +#endif }; /* other API */ @@ -233,6 +260,21 @@ PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate); // function is set, otherwise disable them. PyAPI_FUNC(void) PyThreadState_LeaveTracing(PyThreadState *tstate); +#ifdef Py_STATS +#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE) +extern _Py_thread_local PyThreadState *_Py_tss_tstate; + +static inline PyStats* +_PyThreadState_GetStatsFast(void) +{ + if (_Py_tss_tstate == NULL) { + return NULL; // no attached thread state + } + return _Py_tss_tstate->pystats; +} +#endif +#endif // Py_STATS + /* PyGILState */ /* Helper/diagnostic function - return 1 if the current thread @@ -246,6 +288,18 @@ PyAPI_FUNC(int) PyGILState_Check(void); */ PyAPI_FUNC(PyObject*) _PyThread_CurrentFrames(void); +// Set the stack protection start address and stack protection size +// of a Python thread state +PyAPI_FUNC(int) PyUnstable_ThreadState_SetStackProtection( + PyThreadState *tstate, + void *stack_start_addr, // Stack start address + size_t stack_size); // Stack size (in bytes) + +// Reset the stack protection start address and stack protection size +// of a Python thread state +PyAPI_FUNC(void) PyUnstable_ThreadState_ResetStackProtection( + PyThreadState *tstate); + /* Routines for advanced debuggers, requested by David Beazley. Don't use unless you know what you are doing! */ PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Main(void); diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index cf830b6066f..e473110eca7 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -4,7 +4,7 @@ // // - _Py_INCREF_STAT_INC() and _Py_DECREF_STAT_INC() used by Py_INCREF() // and Py_DECREF(). -// - _Py_stats variable +// - _PyStats_GET() // // Functions of the sys module: // @@ -14,7 +14,7 @@ // - sys._stats_dump() // // Python must be built with ./configure --enable-pystats to define the -// Py_STATS macro. +// _PyStats_GET() macro. // // Define _PY_INTERPRETER macro to increment interpreter_increfs and // interpreter_decrefs. Otherwise, increment increfs and decrefs. @@ -29,7 +29,7 @@ # error "this header file must not be included directly" #endif -#define PYSTATS_MAX_UOP_ID 1024 +#define PYSTATS_MAX_UOP_ID 2000 #define SPECIALIZATION_FAILURE_KINDS 60 @@ -109,6 +109,18 @@ typedef struct _gc_stats { uint64_t objects_not_transitively_reachable; } GCStats; +#ifdef Py_GIL_DISABLED +// stats specific to free-threaded build +typedef struct _ft_stats { + // number of times interpreter had to spin or park when trying to acquire a mutex + uint64_t mutex_sleeps; + // number of times that the QSBR mechanism polled (compute read sequence value) + uint64_t qsbr_polls; + // number of times stop-the-world mechanism was used + uint64_t world_stops; +} FTStats; +#endif + typedef struct _uop_stats { uint64_t execution_count; uint64_t miss; @@ -130,6 +142,7 @@ typedef struct _optimization_stats { uint64_t recursive_call; uint64_t low_confidence; uint64_t unknown_callee; + uint64_t trace_immediately_deopts; uint64_t executors_invalidated; UOpStats opcode[PYSTATS_MAX_UOP_ID + 1]; uint64_t unsupported_opcode[256]; @@ -138,6 +151,8 @@ typedef struct _optimization_stats { uint64_t optimized_trace_length_hist[_Py_UOP_HIST_SIZE]; uint64_t optimizer_attempts; uint64_t optimizer_successes; + uint64_t optimizer_contradiction; + uint64_t optimizer_frame_overflow; uint64_t optimizer_failure_reason_no_memory; uint64_t remove_globals_builtins_changed; uint64_t remove_globals_incorrect_keys; @@ -173,22 +188,48 @@ typedef struct _stats { CallStats call_stats; ObjectStats object_stats; OptimizationStats optimization_stats; +#ifdef Py_GIL_DISABLED + FTStats ft_stats; +#endif RareEventStats rare_event_stats; - GCStats *gc_stats; + GCStats gc_stats[3]; // must match NUM_GENERATIONS } PyStats; +// Export for most shared extensions +PyAPI_FUNC(PyStats *) _PyStats_GetLocal(void); -// Export for shared extensions like 'math' -PyAPI_DATA(PyStats*) _Py_stats; +#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE) +// use inline function version defined in cpython/pystate.h +static inline PyStats *_PyThreadState_GetStatsFast(void); +#define _PyStats_GET _PyThreadState_GetStatsFast +#else +#define _PyStats_GET _PyStats_GetLocal +#endif + +#define _Py_STATS_EXPR(expr) \ + do { \ + PyStats *s = _PyStats_GET(); \ + if (s != NULL) { \ + s->expr; \ + } \ + } while (0) + +#define _Py_STATS_COND_EXPR(cond, expr) \ + do { \ + PyStats *s = _PyStats_GET(); \ + if (s != NULL && (cond)) { \ + s->expr; \ + } \ + } while (0) #ifdef _PY_INTERPRETER -# define _Py_INCREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_increfs++; } while (0) -# define _Py_DECREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_decrefs++; } while (0) -# define _Py_INCREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_immortal_increfs++; } while (0) -# define _Py_DECREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_immortal_decrefs++; } while (0) +# define _Py_INCREF_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_increfs++) +# define _Py_DECREF_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_decrefs++) +# define _Py_INCREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_immortal_increfs++) +# define _Py_DECREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_immortal_decrefs++) #else -# define _Py_INCREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.increfs++; } while (0) -# define _Py_DECREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.decrefs++; } while (0) -# define _Py_INCREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.immortal_increfs++; } while (0) -# define _Py_DECREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.immortal_decrefs++; } while (0) +# define _Py_INCREF_STAT_INC() _Py_STATS_EXPR(object_stats.increfs++) +# define _Py_DECREF_STAT_INC() _Py_STATS_EXPR(object_stats.decrefs++) +# define _Py_INCREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.immortal_increfs++) +# define _Py_DECREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.immortal_decrefs++) #endif diff --git a/Include/cpython/sliceobject.h b/Include/cpython/sliceobject.h new file mode 100644 index 00000000000..4c3ea1faceb --- /dev/null +++ b/Include/cpython/sliceobject.h @@ -0,0 +1,20 @@ +#ifndef Py_CPYTHON_SLICEOBJECT_H +# error "this header file must not be included directly" +#endif + +/* Slice object interface */ + +/* +A slice object containing start, stop, and step data members (the +names are from range). After much talk with Guido, it was decided to +let these be any arbitrary python type. Py_None stands for omitted values. +*/ +typedef struct { + PyObject_HEAD + PyObject *start, *stop, *step; /* not NULL */ +} PySliceObject; + +PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop); +PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, + PyObject **start_ptr, PyObject **stop_ptr, + PyObject **step_ptr); diff --git a/Include/cpython/structseq.h b/Include/cpython/structseq.h new file mode 100644 index 00000000000..328fbe86143 --- /dev/null +++ b/Include/cpython/structseq.h @@ -0,0 +1,12 @@ +#ifndef Py_CPYTHON_STRUCTSEQ_H +# error "this header file must not be included directly" +#endif + +PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, + PyStructSequence_Desc *desc); +PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, + PyStructSequence_Desc *desc); + +typedef PyTupleObject PyStructSequence; +#define PyStructSequence_SET_ITEM PyStructSequence_SetItem +#define PyStructSequence_GET_ITEM PyStructSequence_GetItem diff --git a/Include/cpython/tupleobject.h b/Include/cpython/tupleobject.h index afb98ccbb81..888baaf3358 100644 --- a/Include/cpython/tupleobject.h +++ b/Include/cpython/tupleobject.h @@ -38,3 +38,7 @@ PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) { } #define PyTuple_SET_ITEM(op, index, value) \ PyTuple_SET_ITEM(_PyObject_CAST(op), (index), _PyObject_CAST(value)) + +PyAPI_FUNC(PyObject*) PyTuple_FromArray( + PyObject *const *array, + Py_ssize_t size); diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 73e3bc44d6c..631a6570658 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -301,7 +301,6 @@ static inline Py_ssize_t PyUnicode_GET_LENGTH(PyObject *op) { /* Returns the cached hash, or -1 if not cached yet. */ static inline Py_hash_t PyUnstable_Unicode_GET_CACHED_HASH(PyObject *op) { - assert(PyUnicode_Check(op)); #ifdef Py_GIL_DISABLED return _Py_atomic_load_ssize_relaxed(&_PyASCIIObject_CAST(op)->hash); #else @@ -779,4 +778,4 @@ static inline int Py_UNICODE_ISALNUM(Py_UCS4 ch) { // Return an interned Unicode object for an Identifier; may fail if there is no // memory. -PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); +Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); diff --git a/Include/cpython/warnings.h b/Include/cpython/warnings.h index 8731fd2e96b..4e3eb88e8ff 100644 --- a/Include/cpython/warnings.h +++ b/Include/cpython/warnings.h @@ -18,9 +18,3 @@ PyAPI_FUNC(int) PyErr_WarnExplicitFormat( // DEPRECATED: Use PyErr_WarnEx() instead. #define PyErr_Warn(category, msg) PyErr_WarnEx((category), (msg), 1) - -int _PyErr_WarnExplicitObjectWithContext( - PyObject *category, - PyObject *message, - PyObject *filename, - int lineno); diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h index da8e77cddac..e0711407cee 100644 --- a/Include/cpython/weakrefobject.h +++ b/Include/cpython/weakrefobject.h @@ -47,20 +47,3 @@ PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self); // Test if a weak reference is dead. PyAPI_FUNC(int) PyWeakref_IsDead(PyObject *ref); - -Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj) -{ - PyWeakReference *ref = _PyWeakref_CAST(ref_obj); - PyObject *obj = ref->wr_object; - // Explanation for the Py_REFCNT() check: when a weakref's target is part - // of a long chain of deallocations which triggers the trashcan mechanism, - // clearing the weakrefs can be delayed long after the target's refcount - // has dropped to zero. In the meantime, code accessing the weakref will - // be able to "see" the target object even though it is supposed to be - // unreachable. See issue gh-60806. - if (Py_REFCNT(obj) > 0) { - return obj; - } - return Py_None; -} -#define PyWeakref_GET_OBJECT(ref) PyWeakref_GET_OBJECT(_PyObject_CAST(ref)) diff --git a/Include/datetime.h b/Include/datetime.h index b78cc0e8e2e..ed36e6e48c8 100644 --- a/Include/datetime.h +++ b/Include/datetime.h @@ -1,8 +1,8 @@ /* datetime.h */ #ifndef Py_LIMITED_API -#ifndef DATETIME_H -#define DATETIME_H +#ifndef Py_DATETIME_H +#define Py_DATETIME_H #ifdef __cplusplus extern "C" { #endif @@ -263,5 +263,5 @@ static PyDateTime_CAPI *PyDateTimeAPI = NULL; #ifdef __cplusplus } #endif -#endif +#endif /* !Py_DATETIME_H */ #endif /* !Py_LIMITED_API */ diff --git a/Include/dictobject.h b/Include/dictobject.h index 1bbeec1ab69..0384e3131dc 100644 --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -68,6 +68,18 @@ PyAPI_FUNC(int) PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result PyAPI_FUNC(int) PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result); #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030F0000 +// Inserts `key` with a value `default_value`, if `key` is not already present +// in the dictionary. If `result` is not NULL, then the value associated +// with `key` is returned in `*result` (either the existing value, or the now +// inserted `default_value`). +// Returns: +// -1 on error +// 0 if `key` was not present and `default_value` was inserted +// 1 if `key` was present and `default_value` was not inserted +PyAPI_FUNC(int) PyDict_SetDefaultRef(PyObject *mp, PyObject *key, PyObject *default_value, PyObject **result); +#endif + #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000 PyAPI_FUNC(PyObject *) PyObject_GenericGetDict(PyObject *, void *); #endif diff --git a/Include/exports.h b/Include/exports.h index 0c646d5beb6..62feb09ed2b 100644 --- a/Include/exports.h +++ b/Include/exports.h @@ -9,6 +9,7 @@ inside the Python core, they are private to the core. If in an extension module, it may be declared with external linkage depending on the platform. + PyMODEXPORT_FUNC: Like PyMODINIT_FUNC, but for a slots array As a number of platforms support/require "__declspec(dllimport/dllexport)", we support a HAVE_DECLSPEC_DLL macro to save duplication. @@ -62,9 +63,9 @@ /* module init functions inside the core need no external linkage */ /* except for Cygwin to handle embedding */ # if defined(__CYGWIN__) -# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* +# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL # else /* __CYGWIN__ */ -# define PyMODINIT_FUNC PyObject* +# define _PyINIT_FUNC_DECLSPEC # endif /* __CYGWIN__ */ # else /* Py_BUILD_CORE */ /* Building an extension module, or an embedded situation */ @@ -78,9 +79,9 @@ # define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE /* module init functions outside the core must be exported */ # if defined(__cplusplus) -# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject* +# define _PyINIT_FUNC_DECLSPEC extern "C" Py_EXPORTED_SYMBOL # else /* __cplusplus */ -# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* +# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL # endif /* __cplusplus */ # endif /* Py_BUILD_CORE */ # endif /* HAVE_DECLSPEC_DLL */ @@ -93,13 +94,15 @@ #ifndef PyAPI_DATA # define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE #endif -#ifndef PyMODINIT_FUNC +#ifndef _PyINIT_FUNC_DECLSPEC # if defined(__cplusplus) -# define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject* +# define _PyINIT_FUNC_DECLSPEC extern "C" Py_EXPORTED_SYMBOL # else /* __cplusplus */ -# define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* +# define _PyINIT_FUNC_DECLSPEC Py_EXPORTED_SYMBOL # endif /* __cplusplus */ #endif +#define PyMODINIT_FUNC _PyINIT_FUNC_DECLSPEC PyObject* +#define PyMODEXPORT_FUNC _PyINIT_FUNC_DECLSPEC PyModuleDef_Slot* #endif /* Py_EXPORTS_H */ diff --git a/Include/floatobject.h b/Include/floatobject.h index 4d24a76edd5..814337b070a 100644 --- a/Include/floatobject.h +++ b/Include/floatobject.h @@ -18,14 +18,14 @@ PyAPI_DATA(PyTypeObject) PyFloat_Type; #define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN) -#define Py_RETURN_INF(sign) \ - do { \ - if (copysign(1., sign) == 1.) { \ - return PyFloat_FromDouble(Py_INFINITY); \ - } \ - else { \ - return PyFloat_FromDouble(-Py_INFINITY); \ - } \ +#define Py_RETURN_INF(sign) \ + do { \ + if (copysign(1., sign) == 1.) { \ + return PyFloat_FromDouble(INFINITY); \ + } \ + else { \ + return PyFloat_FromDouble(-INFINITY); \ + } \ } while(0) PyAPI_FUNC(double) PyFloat_GetMax(void); diff --git a/Include/internal/pycore_abstract.h b/Include/internal/pycore_abstract.h index 3cc0afac4bd..30809e09700 100644 --- a/Include/internal/pycore_abstract.h +++ b/Include/internal/pycore_abstract.h @@ -51,6 +51,10 @@ extern int _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); // Export for '_bisect' shared extension. PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *); +// Convert Python int to Py_ssize_t. Do nothing if the argument is None. +// Raises ValueError if argument is negative. +PyAPI_FUNC(int) _Py_convert_optional_to_non_negative_ssize_t(PyObject *, void *); + // Same as PyNumber_Index() but can return an instance of a subclass of int. // Export for 'math' shared extension. PyAPI_FUNC(PyObject*) _PyNumber_Index(PyObject *o); diff --git a/Include/internal/pycore_backoff.h b/Include/internal/pycore_backoff.h index 454c8dde031..23ca7299e0d 100644 --- a/Include/internal/pycore_backoff.h +++ b/Include/internal/pycore_backoff.h @@ -22,33 +22,48 @@ extern "C" { Another use is for the Tier 2 optimizer to decide when to create a new Tier 2 trace (executor). Again, exponential backoff is used. - The 16-bit counter is structured as a 12-bit unsigned 'value' - and a 4-bit 'backoff' field. When resetting the counter, the + The 16-bit counter is structured as a 13-bit unsigned 'value' + and a 3-bit 'backoff' field. When resetting the counter, the backoff field is incremented (until it reaches a limit) and the - value is set to a bit mask representing the value 2**backoff - 1. - The maximum backoff is 12 (the number of bits in the value). + value is set to a bit mask representing some prime value - 1. + New values and backoffs for each backoff are calculated once + at compile time and saved to value_and_backoff_next table. + The maximum backoff is 6, since 7 is an UNREACHABLE_BACKOFF. There is an exceptional value which must not be updated, 0xFFFF. */ -#define BACKOFF_BITS 4 -#define MAX_BACKOFF 12 -#define UNREACHABLE_BACKOFF 15 +#define BACKOFF_BITS 3 +#define BACKOFF_MASK 7 +#define MAX_BACKOFF 6 +#define UNREACHABLE_BACKOFF 7 +#define MAX_VALUE 0x1FFF -static inline bool -is_unreachable_backoff_counter(_Py_BackoffCounter counter) -{ - return counter.value_and_backoff == UNREACHABLE_BACKOFF; -} +#define MAKE_VALUE_AND_BACKOFF(value, backoff) \ + ((uint16_t)(((value) << BACKOFF_BITS) | (backoff))) + +// For previous backoff b we use value x such that +// x + 1 is near to 2**(2*b+1) and x + 1 is prime. +static const uint16_t value_and_backoff_next[] = { + MAKE_VALUE_AND_BACKOFF(1, 1), + MAKE_VALUE_AND_BACKOFF(6, 2), + MAKE_VALUE_AND_BACKOFF(30, 3), + MAKE_VALUE_AND_BACKOFF(126, 4), + MAKE_VALUE_AND_BACKOFF(508, 5), + MAKE_VALUE_AND_BACKOFF(2052, 6), + // We use the same backoff counter for all backoffs >= MAX_BACKOFF. + MAKE_VALUE_AND_BACKOFF(8190, 6), + MAKE_VALUE_AND_BACKOFF(8190, 6), +}; static inline _Py_BackoffCounter make_backoff_counter(uint16_t value, uint16_t backoff) { - assert(backoff <= 15); - assert(value <= 0xFFF); - _Py_BackoffCounter result; - result.value_and_backoff = (value << BACKOFF_BITS) | backoff; - return result; + assert(backoff <= UNREACHABLE_BACKOFF); + assert(value <= MAX_VALUE); + return ((_Py_BackoffCounter){ + .value_and_backoff = MAKE_VALUE_AND_BACKOFF(value, backoff) + }); } static inline _Py_BackoffCounter @@ -62,14 +77,11 @@ forge_backoff_counter(uint16_t counter) static inline _Py_BackoffCounter restart_backoff_counter(_Py_BackoffCounter counter) { - assert(!is_unreachable_backoff_counter(counter)); - int backoff = counter.value_and_backoff & 15; - if (backoff < MAX_BACKOFF) { - return make_backoff_counter((1 << (backoff + 1)) - 1, backoff + 1); - } - else { - return make_backoff_counter((1 << MAX_BACKOFF) - 1, MAX_BACKOFF); - } + uint16_t backoff = counter.value_and_backoff & BACKOFF_MASK; + assert(backoff <= MAX_BACKOFF); + return ((_Py_BackoffCounter){ + .value_and_backoff = value_and_backoff_next[backoff] + }); } static inline _Py_BackoffCounter @@ -95,12 +107,25 @@ backoff_counter_triggers(_Py_BackoffCounter counter) return counter.value_and_backoff < UNREACHABLE_BACKOFF; } +static inline _Py_BackoffCounter +trigger_backoff_counter(void) +{ + _Py_BackoffCounter result; + result.value_and_backoff = 0; + return result; +} + // Initial JUMP_BACKWARD counter. // Must be larger than ADAPTIVE_COOLDOWN_VALUE, otherwise when JIT code is // invalidated we may construct a new trace before the bytecode has properly // re-specialized: -#define JUMP_BACKWARD_INITIAL_VALUE 4095 -#define JUMP_BACKWARD_INITIAL_BACKOFF 12 +// Note: this should be a prime number-1. This increases the likelihood of +// finding a "good" loop iteration to trace. +// For example, 4095 does not work for the nqueens benchmark on pyperformance +// as we always end up tracing the loop iteration's +// exhaustion iteration. Which aborts our current tracer. +#define JUMP_BACKWARD_INITIAL_VALUE 4000 +#define JUMP_BACKWARD_INITIAL_BACKOFF 6 static inline _Py_BackoffCounter initial_jump_backoff_counter(void) { @@ -112,8 +137,8 @@ initial_jump_backoff_counter(void) * Must be larger than ADAPTIVE_COOLDOWN_VALUE, * otherwise when a side exit warms up we may construct * a new trace before the Tier 1 code has properly re-specialized. */ -#define SIDE_EXIT_INITIAL_VALUE 4095 -#define SIDE_EXIT_INITIAL_BACKOFF 12 +#define SIDE_EXIT_INITIAL_VALUE 4000 +#define SIDE_EXIT_INITIAL_BACKOFF 6 static inline _Py_BackoffCounter initial_temperature_backoff_counter(void) diff --git a/Include/internal/pycore_blocks_output_buffer.h b/Include/internal/pycore_blocks_output_buffer.h index 573e10359b7..016e7a18665 100644 --- a/Include/internal/pycore_blocks_output_buffer.h +++ b/Include/internal/pycore_blocks_output_buffer.h @@ -45,12 +45,14 @@ extern "C" { #endif typedef struct { - // List of bytes objects - PyObject *list; + // Bytes writer managing output buffer + PyBytesWriter *writer; // Number of whole allocated size Py_ssize_t allocated; - // Max length of the buffer, negative number means unlimited length. + // Max length of the buffer, negative number means unlimited length Py_ssize_t max_length; + // Number of blocks of bytes. Used to calculate next allocation size + size_t num_blocks; } _BlocksOutputBuffer; static const char unable_allocate_msg[] = "Unable to allocate output buffer."; @@ -107,11 +109,10 @@ _BlocksOutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, const Py_ssize_t max_length, void **next_out) { - PyObject *b; Py_ssize_t block_size; - // ensure .list was set to NULL - assert(buffer->list == NULL); + // ensure .writer was set to NULL + assert(buffer->writer == NULL); // get block size if (0 <= max_length && max_length < BUFFER_BLOCK_SIZE[0]) { @@ -120,25 +121,17 @@ _BlocksOutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, block_size = BUFFER_BLOCK_SIZE[0]; } - // the first block - b = PyBytes_FromStringAndSize(NULL, block_size); - if (b == NULL) { + buffer->writer = PyBytesWriter_Create(block_size); + if (buffer->writer == NULL) { return -1; } - // create the list - buffer->list = PyList_New(1); - if (buffer->list == NULL) { - Py_DECREF(b); - return -1; - } - PyList_SET_ITEM(buffer->list, 0, b); - // set variables buffer->allocated = block_size; buffer->max_length = max_length; + buffer->num_blocks = 1; - *next_out = PyBytes_AS_STRING(b); + *next_out = PyBytesWriter_GetData(buffer->writer); return block_size; } @@ -155,31 +148,21 @@ _BlocksOutputBuffer_InitWithSize(_BlocksOutputBuffer *buffer, const Py_ssize_t init_size, void **next_out) { - PyObject *b; - // ensure .list was set to NULL - assert(buffer->list == NULL); + // ensure .writer was set to NULL + assert(buffer->writer == NULL); - // the first block - b = PyBytes_FromStringAndSize(NULL, init_size); - if (b == NULL) { - PyErr_SetString(PyExc_MemoryError, unable_allocate_msg); + buffer->writer = PyBytesWriter_Create(init_size); + if (buffer->writer == NULL) { return -1; } - // create the list - buffer->list = PyList_New(1); - if (buffer->list == NULL) { - Py_DECREF(b); - return -1; - } - PyList_SET_ITEM(buffer->list, 0, b); - // set variables buffer->allocated = init_size; buffer->max_length = -1; + buffer->num_blocks = 1; - *next_out = PyBytes_AS_STRING(b); + *next_out = PyBytesWriter_GetData(buffer->writer); return init_size; } @@ -193,8 +176,6 @@ _BlocksOutputBuffer_Grow(_BlocksOutputBuffer *buffer, void **next_out, const Py_ssize_t avail_out) { - PyObject *b; - const Py_ssize_t list_len = Py_SIZE(buffer->list); Py_ssize_t block_size; // ensure no gaps in the data @@ -205,11 +186,10 @@ _BlocksOutputBuffer_Grow(_BlocksOutputBuffer *buffer, } // get block size - if (list_len < (Py_ssize_t) Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE)) { - block_size = BUFFER_BLOCK_SIZE[list_len]; - } else { - block_size = BUFFER_BLOCK_SIZE[Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE) - 1]; - } + size_t maxblock = Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE); + assert(maxblock >= 1); + size_t block_index = Py_MIN(buffer->num_blocks, maxblock - 1); + block_size = BUFFER_BLOCK_SIZE[block_index]; // check max_length if (buffer->max_length >= 0) { @@ -229,22 +209,19 @@ _BlocksOutputBuffer_Grow(_BlocksOutputBuffer *buffer, return -1; } - // create the block - b = PyBytes_FromStringAndSize(NULL, block_size); - if (b == NULL) { + if (PyBytesWriter_Grow(buffer->writer, block_size)) { PyErr_SetString(PyExc_MemoryError, unable_allocate_msg); return -1; } - if (PyList_Append(buffer->list, b) < 0) { - Py_DECREF(b); - return -1; - } - Py_DECREF(b); + + Py_ssize_t current_size = buffer->allocated; // set variables buffer->allocated += block_size; + buffer->num_blocks += 1; - *next_out = PyBytes_AS_STRING(b); + char *data = PyBytesWriter_GetData(buffer->writer); + *next_out = data + current_size; return block_size; } @@ -265,54 +242,17 @@ static inline PyObject * _BlocksOutputBuffer_Finish(_BlocksOutputBuffer *buffer, const Py_ssize_t avail_out) { - PyObject *result, *block; - const Py_ssize_t list_len = Py_SIZE(buffer->list); - - // fast path for single block - if ((list_len == 1 && avail_out == 0) || - (list_len == 2 && Py_SIZE(PyList_GET_ITEM(buffer->list, 1)) == avail_out)) - { - block = PyList_GET_ITEM(buffer->list, 0); - Py_INCREF(block); - - Py_CLEAR(buffer->list); - return block; - } - - // final bytes object - result = PyBytes_FromStringAndSize(NULL, buffer->allocated - avail_out); - if (result == NULL) { - PyErr_SetString(PyExc_MemoryError, unable_allocate_msg); - return NULL; - } - - // memory copy - if (list_len > 0) { - char *posi = PyBytes_AS_STRING(result); - - // blocks except the last one - Py_ssize_t i = 0; - for (; i < list_len-1; i++) { - block = PyList_GET_ITEM(buffer->list, i); - memcpy(posi, PyBytes_AS_STRING(block), Py_SIZE(block)); - posi += Py_SIZE(block); - } - // the last block - block = PyList_GET_ITEM(buffer->list, i); - memcpy(posi, PyBytes_AS_STRING(block), Py_SIZE(block) - avail_out); - } else { - assert(Py_SIZE(result) == 0); - } - - Py_CLEAR(buffer->list); - return result; + assert(buffer->writer != NULL); + return PyBytesWriter_FinishWithSize(buffer->writer, + buffer->allocated - avail_out); } /* Clean up the buffer when an error occurred. */ static inline void _BlocksOutputBuffer_OnError(_BlocksOutputBuffer *buffer) { - Py_CLEAR(buffer->list); + PyBytesWriter_Discard(buffer->writer); + buffer->writer = NULL; } #ifdef __cplusplus diff --git a/Include/internal/pycore_bytes_methods.h b/Include/internal/pycore_bytes_methods.h index 059dc2599bb..3e1474c1c01 100644 --- a/Include/internal/pycore_bytes_methods.h +++ b/Include/internal/pycore_bytes_methods.h @@ -47,6 +47,9 @@ extern PyObject *_Py_bytes_endswith(const char *str, Py_ssize_t len, /* The maketrans() static method. */ extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to); +/* Helper for repr(bytes) and repr(bytearray). */ +extern PyObject *_Py_bytes_repr(const char *, Py_ssize_t, int, const char *); + /* Shared __doc__ strings. */ extern const char _Py_isspace__doc__[]; extern const char _Py_isalpha__doc__[]; diff --git a/Include/internal/pycore_bytesobject.h b/Include/internal/pycore_bytesobject.h index 8ea9b3ebb88..8e8fa696ee0 100644 --- a/Include/internal/pycore_bytesobject.h +++ b/Include/internal/pycore_bytesobject.h @@ -60,88 +60,46 @@ PyAPI_FUNC(void) _PyBytes_Repeat(char* dest, Py_ssize_t len_dest, const char* src, Py_ssize_t len_src); -/* --- _PyBytesWriter ----------------------------------------------------- */ +/* _PyBytesObject_SIZE gives the basic size of a bytes object; any memory allocation + for a bytes object of length n should request PyBytesObject_SIZE + n bytes. -/* The _PyBytesWriter structure is big: it contains an embedded "stack buffer". - A _PyBytesWriter variable must be declared at the end of variables in a - function to optimize the memory allocation on the stack. */ -typedef struct { - /* bytes, bytearray or NULL (when the small buffer is used) */ - PyObject *buffer; + Using _PyBytesObject_SIZE instead of sizeof(PyBytesObject) saves + 3 or 7 bytes per bytes object allocation on a typical system. +*/ +#define _PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1) - /* Number of allocated size. */ - Py_ssize_t allocated; +/* --- PyBytesWriter ------------------------------------------------------ */ - /* Minimum number of allocated bytes, - incremented by _PyBytesWriter_Prepare() */ - Py_ssize_t min_size; - - /* If non-zero, use a bytearray instead of a bytes object for buffer. */ +struct PyBytesWriter { + char small_buffer[256]; + PyObject *obj; + Py_ssize_t size; int use_bytearray; - - /* If non-zero, overallocate the buffer (default: 0). - This flag must be zero if use_bytearray is non-zero. */ int overallocate; +}; - /* Stack buffer */ - int use_small_buffer; - char small_buffer[512]; -} _PyBytesWriter; +// Export for '_testcapi' shared extension +PyAPI_FUNC(PyBytesWriter*) _PyBytesWriter_CreateByteArray(Py_ssize_t size); -/* Initialize a bytes writer +static inline Py_ssize_t +_PyBytesWriter_GetSize(PyBytesWriter *writer) +{ + return writer->size; +} - By default, the overallocation is disabled. Set the overallocate attribute - to control the allocation of the buffer. - - Export _PyBytesWriter API for '_pickle' shared extension. */ -PyAPI_FUNC(void) _PyBytesWriter_Init(_PyBytesWriter *writer); - -/* Get the buffer content and reset the writer. - Return a bytes object, or a bytearray object if use_bytearray is non-zero. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(PyObject *) _PyBytesWriter_Finish(_PyBytesWriter *writer, - void *str); - -/* Deallocate memory of a writer (clear its internal buffer). */ -PyAPI_FUNC(void) _PyBytesWriter_Dealloc(_PyBytesWriter *writer); - -/* Allocate the buffer to write size bytes. - Return the pointer to the beginning of buffer data. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_Alloc(_PyBytesWriter *writer, - Py_ssize_t size); - -/* Ensure that the buffer is large enough to write *size* bytes. - Add size to the writer minimum size (min_size attribute). - - str is the current pointer inside the buffer. - Return the updated current pointer inside the buffer. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_Prepare(_PyBytesWriter *writer, - void *str, - Py_ssize_t size); - -/* Resize the buffer to make it larger. - The new buffer may be larger than size bytes because of overallocation. - Return the updated current pointer inside the buffer. - Raise an exception and return NULL on error. - - Note: size must be greater than the number of allocated bytes in the writer. - - This function doesn't use the writer minimum size (min_size attribute). - - See also _PyBytesWriter_Prepare(). - */ -PyAPI_FUNC(void*) _PyBytesWriter_Resize(_PyBytesWriter *writer, - void *str, - Py_ssize_t size); - -/* Write bytes. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_WriteBytes(_PyBytesWriter *writer, - void *str, - const void *bytes, - Py_ssize_t size); +static inline char* +_PyBytesWriter_GetData(PyBytesWriter *writer) +{ + if (writer->obj == NULL) { + return writer->small_buffer; + } + else if (writer->use_bytearray) { + return PyByteArray_AS_STRING(writer->obj); + } + else { + return PyBytes_AS_STRING(writer->obj); + } +} #ifdef __cplusplus } diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 32ac3d17f22..4f4cf02f64b 100644 --- a/Include/internal/pycore_call.h +++ b/Include/internal/pycore_call.h @@ -64,39 +64,6 @@ PyAPI_FUNC(PyObject*) _PyObject_CallMethod( PyObject *name, const char *format, ...); -extern PyObject* _PyObject_CallMethodIdObjArgs( - PyObject *obj, - _Py_Identifier *name, - ...); - -static inline PyObject * -_PyObject_VectorcallMethodId( - _Py_Identifier *name, PyObject *const *args, - size_t nargsf, PyObject *kwnames) -{ - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - return _Py_NULL; - } - return PyObject_VectorcallMethod(oname, args, nargsf, kwnames); -} - -static inline PyObject * -_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name) -{ - size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET; - return _PyObject_VectorcallMethodId(name, &self, nargsf, _Py_NULL); -} - -static inline PyObject * -_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg) -{ - PyObject *args[2] = {self, arg}; - size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET; - assert(arg != NULL); - return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL); -} - /* === Vectorcall protocol (PEP 590) ============================= */ @@ -186,7 +153,7 @@ _PyObject_CallNoArgs(PyObject *func) { } -extern PyObject *const * +PyAPI_FUNC(PyObject *const *) _PyStack_UnpackDict(PyThreadState *tstate, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject **p_kwnames); @@ -196,7 +163,7 @@ extern void _PyStack_UnpackDict_Free( Py_ssize_t nargs, PyObject *kwnames); -extern void _PyStack_UnpackDict_FreeNoDecRef( +PyAPI_FUNC(void) _PyStack_UnpackDict_FreeNoDecRef( PyObject *const *stack, PyObject *kwnames); diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index a03fe42668f..af53f2e7d6f 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -33,8 +33,6 @@ extern int _PyEval_SetOpcodeTrace(PyFrameObject *f, bool enable); // Export for 'array' shared extension PyAPI_FUNC(PyObject*) _PyEval_GetBuiltin(PyObject *); -extern PyObject* _PyEval_GetBuiltinId(_Py_Identifier *); - extern void _PyEval_SetSwitchInterval(unsigned long microseconds); extern unsigned long _PyEval_GetSwitchInterval(void); @@ -217,7 +215,14 @@ extern void _PyEval_DeactivateOpCache(void); static inline int _Py_MakeRecCheck(PyThreadState *tstate) { uintptr_t here_addr = _Py_get_machine_stack_pointer(); _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; - return here_addr < _tstate->c_stack_soft_limit; + // Overflow if stack pointer is between soft limit and the base of the hardware stack. + // If it is below the hardware stack base, assume that we have the wrong stack limits, and do nothing. + // We could have the wrong stack limits because of limited platform support, or user-space threads. +#if _Py_STACK_GROWS_DOWN + return here_addr < _tstate->c_stack_soft_limit && here_addr >= _tstate->c_stack_soft_limit - 2 * _PyOS_STACK_MARGIN_BYTES; +#else + return here_addr > _tstate->c_stack_soft_limit && here_addr <= _tstate->c_stack_soft_limit + 2 * _PyOS_STACK_MARGIN_BYTES; +#endif } // Export for '_json' shared extension, used via _Py_EnterRecursiveCall() @@ -226,7 +231,7 @@ PyAPI_FUNC(int) _Py_CheckRecursiveCall( PyThreadState *tstate, const char *where); -int _Py_CheckRecursiveCallPy( +PyAPI_FUNC(int) _Py_CheckRecursiveCallPy( PyThreadState *tstate); static inline int _Py_EnterRecursiveCallTstate(PyThreadState *tstate, @@ -249,9 +254,18 @@ static inline int _Py_ReachedRecursionLimit(PyThreadState *tstate) { uintptr_t here_addr = _Py_get_machine_stack_pointer(); _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; assert(_tstate->c_stack_hard_limit != 0); +#if _Py_STACK_GROWS_DOWN return here_addr <= _tstate->c_stack_soft_limit; +#else + return here_addr >= _tstate->c_stack_soft_limit; +#endif } +// Export for test_peg_generator +PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin( + PyThreadState *tstate, + int margin_count); + static inline void _Py_LeaveRecursiveCall(void) { } @@ -301,6 +315,7 @@ PyAPI_FUNC(PyObject *) _PyEval_ImportName(PyThreadState *, _PyInterpreterFrame * PyAPI_FUNC(PyObject *)_PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs); PyAPI_FUNC(PyObject *)_PyEval_MatchKeys(PyThreadState *tstate, PyObject *map, PyObject *keys); PyAPI_FUNC(void) _PyEval_MonitorRaise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); +PyAPI_FUNC(bool) _PyEval_NoToolsForUnwind(PyThreadState *tstate); PyAPI_FUNC(int) _PyEval_UnpackIterableStackRef(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, _PyStackRef *sp); PyAPI_FUNC(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject **scratch); @@ -362,8 +377,6 @@ _Py_eval_breaker_bit_is_set(PyThreadState *tstate, uintptr_t bit) void _Py_set_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit); void _Py_unset_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit); -PyAPI_FUNC(_PyStackRef) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value); - #ifndef Py_SUPPORTS_REMOTE_DEBUG #if defined(__APPLE__) #include @@ -391,6 +404,66 @@ _PyForIter_VirtualIteratorNext(PyThreadState* tstate, struct _PyInterpreterFrame #define SPECIAL___AEXIT__ 3 #define SPECIAL_MAX 3 +PyAPI_DATA(const _Py_CODEUNIT *) _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR; + +/* Helper functions for large uops */ + +PyAPI_FUNC(PyObject *) +_Py_VectorCall_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args, + _PyStackRef kwnames); + +PyAPI_FUNC(PyObject *) +_Py_BuiltinCallFast_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args); + +PyAPI_FUNC(PyObject *) +_Py_BuiltinCallFastWithKeywords_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args); + +PyAPI_FUNC(PyObject *) +_PyCallMethodDescriptorFast_StackRefSteal( + _PyStackRef callable, + PyMethodDef *meth, + PyObject *self, + _PyStackRef *arguments, + int total_args); + +PyAPI_FUNC(PyObject *) +_PyCallMethodDescriptorFastWithKeywords_StackRefSteal( + _PyStackRef callable, + PyMethodDef *meth, + PyObject *self, + _PyStackRef *arguments, + int total_args); + +PyAPI_FUNC(PyObject *) +_Py_CallBuiltinClass_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args); + +PyAPI_FUNC(PyObject *) +_Py_BuildString_StackRefSteal( + _PyStackRef *arguments, + int total_args); + +PyAPI_FUNC(PyObject *) +_Py_BuildMap_StackRefSteal( + _PyStackRef *arguments, + int half_args); + +PyAPI_FUNC(void) +_Py_assert_within_stack_bounds( + _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, + const char *filename, int lineno); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 8e1415f27b6..cb9c0aa27a1 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -262,7 +262,7 @@ extern PyObject* _PyCode_GetFreevars(PyCodeObject *); extern PyObject* _PyCode_GetCode(PyCodeObject *); /** API for initializing the line number tables. */ -extern int _PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds); +PyAPI_FUNC(int) _PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds); /** Out of process API for initializing the location table. */ extern void _PyLineTable_InitAddressRange( @@ -272,9 +272,16 @@ extern void _PyLineTable_InitAddressRange( PyCodeAddressRange *range); /** API for traversing the line number table. */ -extern int _PyLineTable_NextAddressRange(PyCodeAddressRange *range); +PyAPI_FUNC(int) _PyLineTable_NextAddressRange(PyCodeAddressRange *range); extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range); +// Similar to PyCode_Addr2Line(), but return -1 if the code object is invalid +// and can be called without an attached tstate. Used by dump_frame() in +// Python/traceback.c. The function uses heuristics to detect freed memory, +// it's not 100% reliable. +extern int _PyCode_SafeAddr2Line(PyCodeObject *co, int addr); + + /** API for executors */ extern void _PyCode_Clear_Executors(PyCodeObject *code); @@ -291,33 +298,34 @@ extern void _PyCode_Clear_Executors(PyCodeObject *code); #define ENABLE_SPECIALIZATION_FT ENABLE_SPECIALIZATION #endif -/* Specialization functions */ +/* Specialization functions, these are exported only for other re-generated + * interpreters to call */ -extern void _Py_Specialize_LoadSuperAttr(_PyStackRef global_super, _PyStackRef cls, +PyAPI_FUNC(void) _Py_Specialize_LoadSuperAttr(_PyStackRef global_super, _PyStackRef cls, _Py_CODEUNIT *instr, int load_method); -extern void _Py_Specialize_LoadAttr(_PyStackRef owner, _Py_CODEUNIT *instr, +PyAPI_FUNC(void) _Py_Specialize_LoadAttr(_PyStackRef owner, _Py_CODEUNIT *instr, PyObject *name); -extern void _Py_Specialize_StoreAttr(_PyStackRef owner, _Py_CODEUNIT *instr, +PyAPI_FUNC(void) _Py_Specialize_StoreAttr(_PyStackRef owner, _Py_CODEUNIT *instr, PyObject *name); -extern void _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, +PyAPI_FUNC(void) _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name); -extern void _Py_Specialize_StoreSubscr(_PyStackRef container, _PyStackRef sub, +PyAPI_FUNC(void) _Py_Specialize_StoreSubscr(_PyStackRef container, _PyStackRef sub, _Py_CODEUNIT *instr); -extern void _Py_Specialize_Call(_PyStackRef callable, _Py_CODEUNIT *instr, - int nargs); -extern void _Py_Specialize_CallKw(_PyStackRef callable, _Py_CODEUNIT *instr, +PyAPI_FUNC(void) _Py_Specialize_Call(_PyStackRef callable, _PyStackRef self_or_null, + _Py_CODEUNIT *instr, int nargs); +PyAPI_FUNC(void) _Py_Specialize_CallKw(_PyStackRef callable, _Py_CODEUNIT *instr, int nargs); -extern void _Py_Specialize_BinaryOp(_PyStackRef lhs, _PyStackRef rhs, _Py_CODEUNIT *instr, +PyAPI_FUNC(void) _Py_Specialize_BinaryOp(_PyStackRef lhs, _PyStackRef rhs, _Py_CODEUNIT *instr, int oparg, _PyStackRef *locals); -extern void _Py_Specialize_CompareOp(_PyStackRef lhs, _PyStackRef rhs, +PyAPI_FUNC(void) _Py_Specialize_CompareOp(_PyStackRef lhs, _PyStackRef rhs, _Py_CODEUNIT *instr, int oparg); -extern void _Py_Specialize_UnpackSequence(_PyStackRef seq, _Py_CODEUNIT *instr, +PyAPI_FUNC(void) _Py_Specialize_UnpackSequence(_PyStackRef seq, _Py_CODEUNIT *instr, int oparg); -extern void _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT *instr, int oparg); -extern void _Py_Specialize_Send(_PyStackRef receiver, _Py_CODEUNIT *instr); -extern void _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr); -extern void _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr); -extern void _Py_GatherStats_GetIter(_PyStackRef iterable); +PyAPI_FUNC(void) _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT *instr, int oparg); +PyAPI_FUNC(void) _Py_Specialize_Send(_PyStackRef receiver, _Py_CODEUNIT *instr); +PyAPI_FUNC(void) _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr); +PyAPI_FUNC(void) _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr); +PyAPI_FUNC(void) _Py_GatherStats_GetIter(_PyStackRef iterable); // Utility functions for reading/writing 32/64-bit values in the inline caches. // Great care should be taken to ensure that these functions remain correct and @@ -512,7 +520,7 @@ typedef struct { #define COMPARISON_NOT_EQUALS (COMPARISON_UNORDERED | COMPARISON_LESS_THAN | COMPARISON_GREATER_THAN) -extern int _Py_Instrument(PyCodeObject *co, PyInterpreterState *interp); +PyAPI_FUNC(int) _Py_Instrument(PyCodeObject *co, PyInterpreterState *interp); extern _Py_CODEUNIT _Py_GetBaseCodeUnit(PyCodeObject *code, int offset); @@ -660,6 +668,15 @@ PyAPI_FUNC(int) _PyCode_VerifyStateless( PyAPI_FUNC(int) _PyCode_CheckPureFunction(PyCodeObject *, const char **); PyAPI_FUNC(int) _PyCode_ReturnsOnlyNone(PyCodeObject *); +/* Create a comparable key used to compare constants taking in account the + * object type. It is used to make sure types are not coerced (e.g., float and + * complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms + * + * Return (type(obj), obj, ...): a tuple with variable size (at least 2 items) + * depending on the type and the value. The type is the first item to not + * compare bytes and str which can raise a BytesWarning exception. */ +extern PyObject* _PyCode_ConstantKey(PyObject *obj); + #ifdef __cplusplus } diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index c18e04bf67a..527141b54d0 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -32,7 +32,8 @@ PyAPI_FUNC(PyCodeObject*) _PyAST_Compile( PyObject *filename, PyCompilerFlags *flags, int optimize, - struct _arena *arena); + struct _arena *arena, + PyObject *module); /* AST preprocessing */ extern int _PyCompile_AstPreprocess( @@ -41,7 +42,8 @@ extern int _PyCompile_AstPreprocess( PyCompilerFlags *flags, int optimize, struct _arena *arena, - int syntax_check_only); + int syntax_check_only, + PyObject *module); extern int _PyAST_Preprocess( struct _mod *, @@ -49,7 +51,9 @@ extern int _PyAST_Preprocess( PyObject *filename, int optimize, int ff_features, - int syntax_check_only); + int syntax_check_only, + int enable_warnings, + PyObject *module); typedef struct { diff --git a/Include/internal/pycore_context.h b/Include/internal/pycore_context.h index c77ef7910c0..a833f790a62 100644 --- a/Include/internal/pycore_context.h +++ b/Include/internal/pycore_context.h @@ -55,5 +55,8 @@ struct _pycontexttokenobject { // Export for '_testcapi' shared extension PyAPI_FUNC(PyObject*) _PyContext_NewHamtForTests(void); +PyAPI_FUNC(int) _PyContext_Enter(PyThreadState *ts, PyObject *octx); +PyAPI_FUNC(int) _PyContext_Exit(PyThreadState *ts, PyObject *octx); + #endif /* !Py_INTERNAL_CONTEXT_H */ diff --git a/Include/internal/pycore_critical_section.h b/Include/internal/pycore_critical_section.h index 2601de40737..60b6fc4a72e 100644 --- a/Include/internal/pycore_critical_section.h +++ b/Include/internal/pycore_critical_section.h @@ -32,7 +32,7 @@ extern "C" { const bool _should_lock_cs = PyList_CheckExact(_orig_seq); \ PyCriticalSection _cs; \ if (_should_lock_cs) { \ - _PyCriticalSection_Begin(&_cs, _orig_seq); \ + PyCriticalSection_Begin(&_cs, _orig_seq); \ } # define Py_END_CRITICAL_SECTION_SEQUENCE_FAST() \ @@ -77,10 +77,10 @@ _PyCriticalSection_Resume(PyThreadState *tstate); // (private) slow path for locking the mutex PyAPI_FUNC(void) -_PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m); +_PyCriticalSection_BeginSlow(PyThreadState *tstate, PyCriticalSection *c, PyMutex *m); PyAPI_FUNC(void) -_PyCriticalSection2_BeginSlow(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2, +_PyCriticalSection2_BeginSlow(PyThreadState *tstate, PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2, int is_m1_locked); PyAPI_FUNC(void) @@ -95,34 +95,30 @@ _PyCriticalSection_IsActive(uintptr_t tag) } static inline void -_PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m) +_PyCriticalSection_BeginMutex(PyThreadState *tstate, PyCriticalSection *c, PyMutex *m) { if (PyMutex_LockFast(m)) { - PyThreadState *tstate = _PyThreadState_GET(); c->_cs_mutex = m; c->_cs_prev = tstate->critical_section; tstate->critical_section = (uintptr_t)c; } else { - _PyCriticalSection_BeginSlow(c, m); + _PyCriticalSection_BeginSlow(tstate, c, m); } } -#define PyCriticalSection_BeginMutex _PyCriticalSection_BeginMutex static inline void -_PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op) +_PyCriticalSection_Begin(PyThreadState *tstate, PyCriticalSection *c, PyObject *op) { - _PyCriticalSection_BeginMutex(c, &op->ob_mutex); + _PyCriticalSection_BeginMutex(tstate, c, &op->ob_mutex); } -#define PyCriticalSection_Begin _PyCriticalSection_Begin // Removes the top-most critical section from the thread's stack of critical // sections. If the new top-most critical section is inactive, then it is // resumed. static inline void -_PyCriticalSection_Pop(PyCriticalSection *c) +_PyCriticalSection_Pop(PyThreadState *tstate, PyCriticalSection *c) { - PyThreadState *tstate = _PyThreadState_GET(); uintptr_t prev = c->_cs_prev; tstate->critical_section = prev; @@ -132,7 +128,7 @@ _PyCriticalSection_Pop(PyCriticalSection *c) } static inline void -_PyCriticalSection_End(PyCriticalSection *c) +_PyCriticalSection_End(PyThreadState *tstate, PyCriticalSection *c) { // If the mutex is NULL, we used the fast path in // _PyCriticalSection_BeginSlow for locks already held in the top-most @@ -141,18 +137,17 @@ _PyCriticalSection_End(PyCriticalSection *c) return; } PyMutex_Unlock(c->_cs_mutex); - _PyCriticalSection_Pop(c); + _PyCriticalSection_Pop(tstate, c); } -#define PyCriticalSection_End _PyCriticalSection_End static inline void -_PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2) +_PyCriticalSection2_BeginMutex(PyThreadState *tstate, PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2) { if (m1 == m2) { // If the two mutex arguments are the same, treat this as a critical // section with a single mutex. c->_cs_mutex2 = NULL; - _PyCriticalSection_BeginMutex(&c->_cs_base, m1); + _PyCriticalSection_BeginMutex(tstate, &c->_cs_base, m1); return; } @@ -167,7 +162,6 @@ _PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2) if (PyMutex_LockFast(m1)) { if (PyMutex_LockFast(m2)) { - PyThreadState *tstate = _PyThreadState_GET(); c->_cs_base._cs_mutex = m1; c->_cs_mutex2 = m2; c->_cs_base._cs_prev = tstate->critical_section; @@ -176,24 +170,22 @@ _PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2) tstate->critical_section = p; } else { - _PyCriticalSection2_BeginSlow(c, m1, m2, 1); + _PyCriticalSection2_BeginSlow(tstate, c, m1, m2, 1); } } else { - _PyCriticalSection2_BeginSlow(c, m1, m2, 0); + _PyCriticalSection2_BeginSlow(tstate, c, m1, m2, 0); } } -#define PyCriticalSection2_BeginMutex _PyCriticalSection2_BeginMutex static inline void -_PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b) +_PyCriticalSection2_Begin(PyThreadState *tstate, PyCriticalSection2 *c, PyObject *a, PyObject *b) { - _PyCriticalSection2_BeginMutex(c, &a->ob_mutex, &b->ob_mutex); + _PyCriticalSection2_BeginMutex(tstate, c, &a->ob_mutex, &b->ob_mutex); } -#define PyCriticalSection2_Begin _PyCriticalSection2_Begin static inline void -_PyCriticalSection2_End(PyCriticalSection2 *c) +_PyCriticalSection2_End(PyThreadState *tstate, PyCriticalSection2 *c) { // if mutex1 is NULL, we used the fast path in // _PyCriticalSection_BeginSlow for mutexes that are already held, @@ -207,9 +199,8 @@ _PyCriticalSection2_End(PyCriticalSection2 *c) PyMutex_Unlock(c->_cs_mutex2); } PyMutex_Unlock(c->_cs_base._cs_mutex); - _PyCriticalSection_Pop(&c->_cs_base); + _PyCriticalSection_Pop(tstate, &c->_cs_base); } -#define PyCriticalSection2_End _PyCriticalSection2_End static inline void _PyCriticalSection_AssertHeld(PyMutex *mutex) @@ -251,6 +242,45 @@ _PyCriticalSection_AssertHeldObj(PyObject *op) #endif } + +#undef Py_BEGIN_CRITICAL_SECTION +# define Py_BEGIN_CRITICAL_SECTION(op) \ + { \ + PyCriticalSection _py_cs; \ + PyThreadState *_cs_tstate = _PyThreadState_GET(); \ + _PyCriticalSection_Begin(_cs_tstate, &_py_cs, _PyObject_CAST(op)) + +#undef Py_BEGIN_CRITICAL_SECTION_MUTEX +# define Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex) \ + { \ + PyCriticalSection _py_cs; \ + PyThreadState *_cs_tstate = _PyThreadState_GET(); \ + _PyCriticalSection_BeginMutex(_cs_tstate, &_py_cs, mutex) + +#undef Py_END_CRITICAL_SECTION +# define Py_END_CRITICAL_SECTION() \ + _PyCriticalSection_End(_cs_tstate, &_py_cs); \ + } + +#undef Py_BEGIN_CRITICAL_SECTION2 +# define Py_BEGIN_CRITICAL_SECTION2(a, b) \ + { \ + PyCriticalSection2 _py_cs2; \ + PyThreadState *_cs_tstate = _PyThreadState_GET(); \ + _PyCriticalSection2_Begin(_cs_tstate, &_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b)) + +#undef Py_BEGIN_CRITICAL_SECTION2_MUTEX +# define Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2) \ + { \ + PyCriticalSection2 _py_cs2; \ + PyThreadState *_cs_tstate = _PyThreadState_GET(); \ + _PyCriticalSection2_BeginMutex(_cs_tstate, &_py_cs2, m1, m2) + +#undef Py_END_CRITICAL_SECTION2 +# define Py_END_CRITICAL_SECTION2() \ + _PyCriticalSection2_End(_cs_tstate, &_py_cs2); \ + } + #endif /* Py_GIL_DISABLED */ #ifdef __cplusplus diff --git a/Include/internal/pycore_debug_offsets.h b/Include/internal/pycore_debug_offsets.h index 1b59fa2ef60..66f14e69f33 100644 --- a/Include/internal/pycore_debug_offsets.h +++ b/Include/internal/pycore_debug_offsets.h @@ -102,12 +102,23 @@ typedef struct _Py_DebugOffsets { uint64_t next; uint64_t interp; uint64_t current_frame; + uint64_t base_frame; + uint64_t last_profiled_frame; uint64_t thread_id; uint64_t native_thread_id; uint64_t datastack_chunk; uint64_t status; + uint64_t holds_gil; + uint64_t gil_requested; + uint64_t current_exception; + uint64_t exc_state; } thread_state; + // Exception stack item offset + struct { + uint64_t exc_value; + } err_stackitem; + // InterpreterFrame offset; struct _interpreter_frame { uint64_t size; @@ -210,6 +221,7 @@ typedef struct _Py_DebugOffsets { struct _gc { uint64_t size; uint64_t collecting; + uint64_t frame; } gc; // Generator object offset; @@ -269,10 +281,19 @@ typedef struct _Py_DebugOffsets { .next = offsetof(PyThreadState, next), \ .interp = offsetof(PyThreadState, interp), \ .current_frame = offsetof(PyThreadState, current_frame), \ + .base_frame = offsetof(PyThreadState, base_frame), \ + .last_profiled_frame = offsetof(PyThreadState, last_profiled_frame), \ .thread_id = offsetof(PyThreadState, thread_id), \ .native_thread_id = offsetof(PyThreadState, native_thread_id), \ .datastack_chunk = offsetof(PyThreadState, datastack_chunk), \ .status = offsetof(PyThreadState, _status), \ + .holds_gil = offsetof(PyThreadState, holds_gil), \ + .gil_requested = offsetof(PyThreadState, gil_requested), \ + .current_exception = offsetof(PyThreadState, current_exception), \ + .exc_state = offsetof(PyThreadState, exc_state), \ + }, \ + .err_stackitem = { \ + .exc_value = offsetof(_PyErr_StackItem, exc_value), \ }, \ .interpreter_frame = { \ .size = sizeof(_PyInterpreterFrame), \ @@ -351,6 +372,7 @@ typedef struct _Py_DebugOffsets { .gc = { \ .size = sizeof(struct _gc_runtime_state), \ .collecting = offsetof(struct _gc_runtime_state, collecting), \ + .frame = offsetof(struct _gc_runtime_state, frame), \ }, \ .gen_object = { \ .size = sizeof(PyGenObject), \ @@ -368,7 +390,7 @@ typedef struct _Py_DebugOffsets { .remote_debugging_enabled = offsetof(PyInterpreterState, config.remote_debug), \ .debugger_pending_call = offsetof(_PyRemoteDebuggerSupport, debugger_pending_call), \ .debugger_script_path = offsetof(_PyRemoteDebuggerSupport, debugger_script_path), \ - .debugger_script_path_size = Py_MAX_SCRIPT_PATH_SIZE, \ + .debugger_script_path_size = _Py_MAX_SCRIPT_PATH_SIZE, \ }, \ } diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 6ab569393e5..1193f496da1 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -30,14 +30,11 @@ PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key, // Export for '_asyncio' shared extension PyAPI_FUNC(int) _PyDict_DelItem_KnownHash(PyObject *mp, PyObject *key, Py_hash_t hash); -extern int _PyDict_Contains_KnownHash(PyObject *, PyObject *, Py_hash_t); -// "Id" variants -extern PyObject* _PyDict_GetItemIdWithError(PyObject *dp, - _Py_Identifier *key); -extern int _PyDict_ContainsId(PyObject *, _Py_Identifier *); -extern int _PyDict_SetItemId(PyObject *dp, _Py_Identifier *key, PyObject *item); -extern int _PyDict_DelItemId(PyObject *mp, _Py_Identifier *key); +extern int _PyDict_DelItem_KnownHash_LockHeld(PyObject *mp, PyObject *key, + Py_hash_t hash); + +extern int _PyDict_Contains_KnownHash(PyObject *, PyObject *, Py_hash_t); extern int _PyDict_Next( PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, Py_hash_t *hash); @@ -47,6 +44,8 @@ extern int _PyDict_HasOnlyStringKeys(PyObject *mp); // Export for '_ctypes' shared extension PyAPI_FUNC(Py_ssize_t) _PyDict_SizeOf(PyDictObject *); +extern Py_ssize_t _PyDict_SizeOf_LockHeld(PyDictObject *); + #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) /* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0, @@ -144,7 +143,7 @@ PyAPI_FUNC(int) _PyDict_SetItem_KnownHash_LockHeld(PyDictObject *mp, PyObject *k PyAPI_FUNC(int) _PyDict_GetItemRef_KnownHash_LockHeld(PyDictObject *op, PyObject *key, Py_hash_t hash, PyObject **result); extern int _PyDict_GetItemRef_KnownHash(PyDictObject *op, PyObject *key, Py_hash_t hash, PyObject **result); extern int _PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **result); -extern int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr, PyObject *name, PyObject *value); +PyAPI_FUNC(int) _PyObjectDict_SetItem(PyTypeObject *tp, PyObject *obj, PyObject **dictptr, PyObject *name, PyObject *value); extern int _PyDict_Pop_KnownHash( PyDictObject *dict, diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index f3c9a669ad3..3a41ec4b54b 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -17,15 +17,16 @@ extern "C" { static inline struct _Py_freelists * _Py_freelists_GET(void) { - PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG - _Py_EnsureTstateNotNULL(tstate); + _Py_AssertHoldsTstate(); #endif #ifdef Py_GIL_DISABLED + PyThreadState *tstate = _PyThreadState_GET(); return &((_PyThreadStateImpl*)tstate)->freelists; #else - return &tstate->interp->object_state.freelists; + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->object_state.freelists; #endif } diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 59beb92f3f7..46e2a82ea03 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -27,6 +27,7 @@ extern "C" { # define Py_futureiters_MAXFREELIST 255 # define Py_object_stack_chunks_MAXFREELIST 4 # define Py_unicode_writers_MAXFREELIST 1 +# define Py_bytes_writers_MAXFREELIST 1 # define Py_pycfunctionobject_MAXFREELIST 16 # define Py_pycmethodobject_MAXFREELIST 16 # define Py_pymethodobjects_MAXFREELIST 20 @@ -61,6 +62,7 @@ struct _Py_freelists { struct _Py_freelist futureiters; struct _Py_freelist object_stack_chunks; struct _Py_freelist unicode_writers; + struct _Py_freelist bytes_writers; struct _Py_freelist pycfunctionobject; struct _Py_freelist pycmethodobject; struct _Py_freelist pymethodobjects; diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 6e120965956..e89f4b5c8a4 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -extern PyObject* _PyFunction_Vectorcall( +PyAPI_FUNC(PyObject *) _PyFunction_Vectorcall( PyObject *func, PyObject *const *stack, size_t nargsf, diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index a6519aa0863..fd284d0e4ec 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -205,6 +205,12 @@ static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) { #endif } +extern void _Py_ScheduleGC(PyThreadState *tstate); + +#ifndef Py_GIL_DISABLED +extern void _Py_TriggerGC(struct _gc_runtime_state *gcstate); +#endif + /* Tell the GC to track this object. * @@ -238,14 +244,19 @@ static inline void _PyObject_GC_TRACK( "object is in generation which is garbage collected", filename, lineno, __func__); - PyInterpreterState *interp = _PyInterpreterState_GET(); - PyGC_Head *generation0 = &interp->gc.young.head; + struct _gc_runtime_state *gcstate = &_PyInterpreterState_GET()->gc; + PyGC_Head *generation0 = &gcstate->young.head; PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); _PyGCHead_SET_NEXT(last, gc); _PyGCHead_SET_PREV(gc, last); - uintptr_t not_visited = 1 ^ interp->gc.visited_space; + uintptr_t not_visited = 1 ^ gcstate->visited_space; gc->_gc_next = ((uintptr_t)generation0) | not_visited; generation0->_gc_prev = (uintptr_t)gc; + gcstate->young.count++; /* number of tracked GC objects */ + gcstate->heap_size++; + if (gcstate->young.count > gcstate->young.threshold) { + _Py_TriggerGC(gcstate); + } #endif } @@ -280,6 +291,11 @@ static inline void _PyObject_GC_UNTRACK( _PyGCHead_SET_PREV(next, prev); gc->_gc_next = 0; gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; + struct _gc_runtime_state *gcstate = &_PyInterpreterState_GET()->gc; + if (gcstate->young.count > 0) { + gcstate->young.count--; + } + gcstate->heap_size--; #endif } @@ -343,7 +359,6 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); // Functions to clear types free lists extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); -extern void _Py_ScheduleGC(PyThreadState *tstate); extern void _Py_RunGC(PyThreadState *tstate); union _PyStackRef; diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index c1fc3511f84..b08c8c52221 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -31,7 +31,7 @@ PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *); PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); PyAPI_FUNC(PyObject *)_PyCoro_GetAwaitableIter(PyObject *o); -extern PyObject *_PyAsyncGenValueWrapperNew(PyThreadState *state, PyObject *); +PyAPI_FUNC(PyObject *)_PyAsyncGenValueWrapperNew(PyThreadState *state, PyObject *); extern PyTypeObject _PyCoroWrapper_Type; extern PyTypeObject _PyAsyncGenWrappedValue_Type; diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 2078c201b45..56bc003ac3e 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -13,7 +13,7 @@ static inline void _PyStaticObject_CheckRefcnt(PyObject *obj) { if (!_Py_IsImmortal(obj)) { fprintf(stderr, "Immortal Object has less refcnt than expected.\n"); - _PyObject_Dump(obj); + PyUnstable_Object_Dump(obj); } } #endif @@ -286,6 +286,774 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 254]); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 255]); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 256]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 257]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 258]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 259]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 260]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 261]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 262]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 263]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 264]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 265]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 266]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 267]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 268]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 269]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 270]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 271]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 272]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 273]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 274]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 275]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 276]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 277]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 278]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 279]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 280]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 281]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 282]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 283]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 284]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 285]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 286]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 287]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 288]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 289]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 290]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 291]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 292]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 293]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 294]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 295]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 296]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 297]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 298]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 299]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 300]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 301]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 302]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 303]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 304]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 305]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 306]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 307]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 308]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 309]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 310]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 311]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 312]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 313]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 314]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 315]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 316]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 317]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 318]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 319]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 320]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 321]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 322]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 323]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 324]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 325]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 326]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 327]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 328]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 329]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 330]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 331]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 332]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 333]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 334]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 335]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 336]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 337]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 338]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 339]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 340]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 341]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 342]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 343]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 344]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 345]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 346]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 347]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 348]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 349]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 350]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 351]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 352]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 353]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 354]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 355]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 356]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 357]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 358]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 359]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 360]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 361]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 362]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 363]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 364]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 365]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 366]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 367]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 368]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 369]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 370]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 371]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 372]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 373]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 374]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 375]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 376]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 377]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 378]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 379]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 380]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 381]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 382]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 383]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 384]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 385]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 386]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 387]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 388]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 389]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 390]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 391]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 392]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 393]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 394]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 395]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 396]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 397]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 398]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 399]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 400]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 401]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 402]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 403]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 404]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 405]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 406]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 407]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 408]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 409]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 410]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 411]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 412]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 413]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 414]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 415]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 416]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 417]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 418]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 419]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 420]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 421]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 422]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 423]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 424]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 425]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 426]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 427]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 428]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 429]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 430]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 431]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 432]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 433]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 434]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 435]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 436]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 437]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 438]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 439]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 440]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 441]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 442]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 443]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 444]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 445]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 446]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 447]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 448]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 449]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 450]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 451]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 452]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 453]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 454]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 455]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 456]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 457]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 458]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 459]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 460]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 461]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 462]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 463]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 464]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 465]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 466]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 467]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 468]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 469]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 470]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 471]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 472]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 473]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 474]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 475]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 476]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 477]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 478]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 479]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 480]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 481]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 482]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 483]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 484]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 485]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 486]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 487]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 488]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 489]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 490]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 491]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 492]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 493]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 494]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 495]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 496]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 497]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 498]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 499]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 500]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 501]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 502]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 503]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 504]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 505]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 506]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 507]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 508]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 509]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 510]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 511]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 512]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 513]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 514]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 515]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 516]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 517]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 518]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 519]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 520]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 521]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 522]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 523]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 524]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 525]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 526]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 527]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 528]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 529]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 530]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 531]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 532]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 533]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 534]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 535]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 536]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 537]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 538]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 539]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 540]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 541]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 542]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 543]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 544]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 545]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 546]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 547]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 548]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 549]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 550]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 551]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 552]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 553]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 554]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 555]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 556]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 557]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 558]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 559]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 560]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 561]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 562]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 563]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 564]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 565]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 566]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 567]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 568]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 569]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 570]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 571]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 572]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 573]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 574]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 575]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 576]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 577]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 578]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 579]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 580]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 581]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 582]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 583]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 584]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 585]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 586]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 587]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 588]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 589]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 590]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 591]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 592]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 593]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 594]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 595]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 596]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 597]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 598]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 599]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 600]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 601]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 602]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 603]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 604]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 605]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 606]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 607]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 608]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 609]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 610]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 611]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 612]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 613]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 614]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 615]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 616]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 617]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 618]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 619]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 620]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 621]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 622]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 623]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 624]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 625]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 626]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 627]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 628]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 629]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 630]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 631]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 632]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 633]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 634]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 635]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 636]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 637]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 638]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 639]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 640]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 641]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 642]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 643]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 644]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 645]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 646]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 647]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 648]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 649]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 650]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 651]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 652]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 653]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 654]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 655]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 656]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 657]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 658]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 659]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 660]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 661]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 662]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 663]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 664]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 665]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 666]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 667]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 668]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 669]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 670]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 671]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 672]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 673]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 674]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 675]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 676]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 677]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 678]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 679]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 680]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 681]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 682]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 683]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 684]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 685]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 686]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 687]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 688]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 689]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 690]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 691]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 692]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 693]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 694]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 695]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 696]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 697]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 698]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 699]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 700]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 701]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 702]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 703]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 704]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 705]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 706]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 707]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 708]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 709]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 710]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 711]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 712]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 713]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 714]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 715]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 716]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 717]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 718]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 719]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 720]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 721]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 722]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 723]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 724]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 725]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 726]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 727]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 728]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 729]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 730]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 731]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 732]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 733]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 734]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 735]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 736]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 737]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 738]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 739]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 740]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 741]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 742]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 743]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 744]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 745]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 746]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 747]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 748]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 749]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 750]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 751]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 752]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 753]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 754]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 755]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 756]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 757]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 758]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 759]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 760]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 761]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 762]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 763]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 764]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 765]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 766]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 767]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 768]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 769]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 770]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 771]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 772]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 773]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 774]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 775]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 776]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 777]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 778]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 779]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 780]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 781]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 782]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 783]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 784]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 785]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 786]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 787]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 788]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 789]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 790]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 791]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 792]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 793]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 794]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 795]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 796]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 797]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 798]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 799]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 800]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 801]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 802]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 803]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 804]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 805]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 806]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 807]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 808]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 809]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 810]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 811]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 812]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 813]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 814]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 815]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 816]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 817]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 818]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 819]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 820]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 821]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 822]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 823]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 824]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 825]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 826]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 827]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 828]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 829]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 830]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 831]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 832]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 833]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 834]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 835]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 836]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 837]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 838]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 839]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 840]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 841]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 842]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 843]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 844]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 845]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 846]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 847]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 848]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 849]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 850]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 851]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 852]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 853]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 854]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 855]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 856]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 857]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 858]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 859]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 860]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 861]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 862]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 863]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 864]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 865]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 866]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 867]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 868]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 869]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 870]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 871]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 872]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 873]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 874]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 875]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 876]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 877]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 878]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 879]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 880]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 881]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 882]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 883]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 884]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 885]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 886]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 887]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 888]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 889]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 890]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 891]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 892]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 893]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 894]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 895]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 896]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 897]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 898]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 899]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 900]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 901]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 902]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 903]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 904]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 905]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 906]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 907]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 908]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 909]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 910]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 911]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 912]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 913]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 914]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 915]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 916]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 917]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 918]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 919]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 920]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 921]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 922]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 923]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 924]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 925]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 926]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 927]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 928]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 929]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 930]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 931]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 932]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 933]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 934]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 935]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 936]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 937]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 938]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 939]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 940]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 941]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 942]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 943]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 944]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 945]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 946]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 947]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 948]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 949]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 950]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 951]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 952]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 953]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 954]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 955]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 956]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 957]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 958]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 959]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 960]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 961]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 962]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 963]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 964]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 965]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 966]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 967]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 968]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 969]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 970]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 971]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 972]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 973]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 974]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 975]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 976]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 977]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 978]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 979]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 980]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 981]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 982]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 983]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 984]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 985]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 986]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 987]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 988]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 989]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 990]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 991]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 992]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 993]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 994]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 995]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 996]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 997]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 998]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 999]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1000]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1001]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1002]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1003]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1004]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1005]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1006]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1007]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1008]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1009]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1010]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1011]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1012]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1013]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1014]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1015]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1016]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1017]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1018]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1019]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1020]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1021]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1022]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1023]); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(small_ints)[_PY_NSMALLNEGINTS + 1024]); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(bytes_characters)[0]); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(bytes_characters)[1]); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_SINGLETON(bytes_characters)[2]); @@ -558,10 +1326,12 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot_locals)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(empty)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(format)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(gc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(generic_base)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(list_err)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(native)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(str_replace_inf)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8)); @@ -839,6 +1609,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_parameter_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_stack)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cache_frames)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_datetime_module)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_statements)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cadata)); @@ -933,6 +1704,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eager_start)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(effective_ids)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(element_factory)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(emptyerror)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encoding)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end)); @@ -958,6 +1730,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extra_tokens)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(facility)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(factory)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fallback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(false)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(family)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fanout)); @@ -984,13 +1757,16 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(format_spec)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(frame_buffer)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(free_threaded)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(from_param)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromlist)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromtimestamp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fromutc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fset)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fullerror)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(func)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(future)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(generation)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get_debug)); @@ -1079,6 +1855,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_value)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(latin1)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(leaf_size)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(legacy)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(len)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(length)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(level)); @@ -1094,12 +1871,14 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(loop)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(manual_reset)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mapping)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mask)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(match)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(max_length)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxdigits)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxevents)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxlen)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxmem)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxsize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxsplit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(maxvalue)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(memLevel)); @@ -1131,6 +1910,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(name_from)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(namespace_separator)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(namespaces)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(native)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ndigits)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(nested)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(new_file_name)); @@ -1157,6 +1937,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(only_keys)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(oparg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(opcode)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(opcodes)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(open)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(opener)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(operation)); @@ -1182,6 +1963,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(person)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pi_factory)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pid)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pointer_bits)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(policy)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos1)); @@ -1197,7 +1979,10 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(protocol)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps1)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps2)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(qid)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(qualname)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(query)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(queuetype)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(quotetabs)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(raw)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read)); @@ -1209,6 +1994,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readonly)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(real)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(recursive)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reducer_override)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(registry)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol)); @@ -1251,12 +2037,14 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(setstate)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(shape)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(shared)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(short)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(show_cmd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signed)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signum)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(size)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sizehint)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(skip_file_prefixes)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(skip_non_matching_threads)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sleep)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sock)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sort)); @@ -1268,6 +2056,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stacklevel)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(start)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(statement)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stats)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(status)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stderr)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stdin)); @@ -1285,6 +2074,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tabsize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tag)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(take_bytes)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(target)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(target_is_directory)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(task)); @@ -1322,6 +2112,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzinfo)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzname)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(uid)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unboundop)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unlink)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unraisablehook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(updates)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index a7ebaf76c90..8be948b92ec 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -46,10 +46,12 @@ struct _Py_global_strings { STRUCT_FOR_STR(dot_locals, ".") STRUCT_FOR_STR(empty, "") STRUCT_FOR_STR(format, ".format") + STRUCT_FOR_STR(gc, "") STRUCT_FOR_STR(generic_base, ".generic_base") STRUCT_FOR_STR(json_decoder, "json.decoder") STRUCT_FOR_STR(kwdefaults, ".kwdefaults") STRUCT_FOR_STR(list_err, "list index out of range") + STRUCT_FOR_STR(native, "") STRUCT_FOR_STR(str_replace_inf, "1e309") STRUCT_FOR_STR(type_params, ".type_params") STRUCT_FOR_STR(utf_8, "utf-8") @@ -330,6 +332,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(c_parameter_type) STRUCT_FOR_ID(c_return) STRUCT_FOR_ID(c_stack) + STRUCT_FOR_ID(cache_frames) STRUCT_FOR_ID(cached_datetime_module) STRUCT_FOR_ID(cached_statements) STRUCT_FOR_ID(cadata) @@ -424,6 +427,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(eager_start) STRUCT_FOR_ID(effective_ids) STRUCT_FOR_ID(element_factory) + STRUCT_FOR_ID(emptyerror) STRUCT_FOR_ID(encode) STRUCT_FOR_ID(encoding) STRUCT_FOR_ID(end) @@ -449,6 +453,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(extra_tokens) STRUCT_FOR_ID(facility) STRUCT_FOR_ID(factory) + STRUCT_FOR_ID(fallback) STRUCT_FOR_ID(false) STRUCT_FOR_ID(family) STRUCT_FOR_ID(fanout) @@ -475,13 +480,16 @@ struct _Py_global_strings { STRUCT_FOR_ID(format) STRUCT_FOR_ID(format_spec) STRUCT_FOR_ID(frame_buffer) + STRUCT_FOR_ID(free_threaded) STRUCT_FOR_ID(from_param) STRUCT_FOR_ID(fromlist) STRUCT_FOR_ID(fromtimestamp) STRUCT_FOR_ID(fromutc) STRUCT_FOR_ID(fset) + STRUCT_FOR_ID(fullerror) STRUCT_FOR_ID(func) STRUCT_FOR_ID(future) + STRUCT_FOR_ID(gc) STRUCT_FOR_ID(generation) STRUCT_FOR_ID(get) STRUCT_FOR_ID(get_debug) @@ -570,6 +578,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(last_value) STRUCT_FOR_ID(latin1) STRUCT_FOR_ID(leaf_size) + STRUCT_FOR_ID(legacy) STRUCT_FOR_ID(len) STRUCT_FOR_ID(length) STRUCT_FOR_ID(level) @@ -585,12 +594,14 @@ struct _Py_global_strings { STRUCT_FOR_ID(loop) STRUCT_FOR_ID(manual_reset) STRUCT_FOR_ID(mapping) + STRUCT_FOR_ID(mask) STRUCT_FOR_ID(match) STRUCT_FOR_ID(max_length) STRUCT_FOR_ID(maxdigits) STRUCT_FOR_ID(maxevents) STRUCT_FOR_ID(maxlen) STRUCT_FOR_ID(maxmem) + STRUCT_FOR_ID(maxsize) STRUCT_FOR_ID(maxsplit) STRUCT_FOR_ID(maxvalue) STRUCT_FOR_ID(memLevel) @@ -622,6 +633,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(name_from) STRUCT_FOR_ID(namespace_separator) STRUCT_FOR_ID(namespaces) + STRUCT_FOR_ID(native) STRUCT_FOR_ID(ndigits) STRUCT_FOR_ID(nested) STRUCT_FOR_ID(new_file_name) @@ -648,6 +660,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(only_keys) STRUCT_FOR_ID(oparg) STRUCT_FOR_ID(opcode) + STRUCT_FOR_ID(opcodes) STRUCT_FOR_ID(open) STRUCT_FOR_ID(opener) STRUCT_FOR_ID(operation) @@ -673,6 +686,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(person) STRUCT_FOR_ID(pi_factory) STRUCT_FOR_ID(pid) + STRUCT_FOR_ID(pointer_bits) STRUCT_FOR_ID(policy) STRUCT_FOR_ID(pos) STRUCT_FOR_ID(pos1) @@ -688,7 +702,10 @@ struct _Py_global_strings { STRUCT_FOR_ID(protocol) STRUCT_FOR_ID(ps1) STRUCT_FOR_ID(ps2) + STRUCT_FOR_ID(qid) + STRUCT_FOR_ID(qualname) STRUCT_FOR_ID(query) + STRUCT_FOR_ID(queuetype) STRUCT_FOR_ID(quotetabs) STRUCT_FOR_ID(raw) STRUCT_FOR_ID(read) @@ -700,6 +717,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(readline) STRUCT_FOR_ID(readonly) STRUCT_FOR_ID(real) + STRUCT_FOR_ID(recursive) STRUCT_FOR_ID(reducer_override) STRUCT_FOR_ID(registry) STRUCT_FOR_ID(rel_tol) @@ -742,12 +760,14 @@ struct _Py_global_strings { STRUCT_FOR_ID(setstate) STRUCT_FOR_ID(shape) STRUCT_FOR_ID(shared) + STRUCT_FOR_ID(short) STRUCT_FOR_ID(show_cmd) STRUCT_FOR_ID(signed) STRUCT_FOR_ID(signum) STRUCT_FOR_ID(size) STRUCT_FOR_ID(sizehint) STRUCT_FOR_ID(skip_file_prefixes) + STRUCT_FOR_ID(skip_non_matching_threads) STRUCT_FOR_ID(sleep) STRUCT_FOR_ID(sock) STRUCT_FOR_ID(sort) @@ -759,6 +779,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(stacklevel) STRUCT_FOR_ID(start) STRUCT_FOR_ID(statement) + STRUCT_FOR_ID(stats) STRUCT_FOR_ID(status) STRUCT_FOR_ID(stderr) STRUCT_FOR_ID(stdin) @@ -776,6 +797,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(symmetric_difference_update) STRUCT_FOR_ID(tabsize) STRUCT_FOR_ID(tag) + STRUCT_FOR_ID(take_bytes) STRUCT_FOR_ID(target) STRUCT_FOR_ID(target_is_directory) STRUCT_FOR_ID(task) @@ -813,6 +835,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(tzinfo) STRUCT_FOR_ID(tzname) STRUCT_FOR_ID(uid) + STRUCT_FOR_ID(unboundop) STRUCT_FOR_ID(unlink) STRUCT_FOR_ID(unraisablehook) STRUCT_FOR_ID(updates) diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 13fbff4eb65..4c8b8c0ed86 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -17,7 +17,8 @@ extern int _PyImport_IsInitialized(PyInterpreterState *); // Export for 'pyexpat' shared extension PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module); -extern int _PyImport_SetModuleString(const char *name, PyObject* module); +// Export for 'math' shared extension +PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module); extern void _PyImport_AcquireLock(PyInterpreterState *interp); extern void _PyImport_ReleaseLock(PyInterpreterState *interp); @@ -127,11 +128,18 @@ PyAPI_FUNC(int) _PyImport_ClearExtension(PyObject *name, PyObject *filename); // state of the module argument: // - If module is NULL or a PyModuleObject with md_gil == Py_MOD_GIL_NOT_USED, // call _PyEval_DisableGIL(). -// - Otherwise, call _PyEval_EnableGILPermanent(). If the GIL was not already -// enabled permanently, issue a warning referencing the module's name. +// - Otherwise, call _PyImport_EnableGILAndWarn // // This function may raise an exception. extern int _PyImport_CheckGILForModule(PyObject *module, PyObject *module_name); +// Assuming that the GIL is enabled from a call to +// _PyEval_EnableGILTransient(), call _PyEval_EnableGILPermanent(). +// If the GIL was not already enabled permanently, issue a warning referencing +// the module's name. +// Leave a message in verbose mode. +// +// This function may raise an exception. +extern int _PyImport_EnableGILAndWarn(PyThreadState *, PyObject *module_name); #endif #ifdef __cplusplus diff --git a/Include/internal/pycore_importdl.h b/Include/internal/pycore_importdl.h index 3ba9229cc21..f60c5510d20 100644 --- a/Include/internal/pycore_importdl.h +++ b/Include/internal/pycore_importdl.h @@ -14,6 +14,34 @@ extern "C" { extern const char *_PyImport_DynLoadFiletab[]; +#ifdef HAVE_DYNAMIC_LOADING +/* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is + supported on this platform. configure will then compile and link in one + of the dynload_*.c files, as appropriate. We will call a function in + those modules to get a function pointer to the module's init function. + + The function should return: + - The function pointer on success + - NULL with exception set if the library cannot be loaded + - NULL *without* an extension set if the library could be loaded but the + function cannot be found in it. +*/ +#ifdef MS_WINDOWS +#include +typedef FARPROC dl_funcptr; +extern dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, + const char *shortname, + PyObject *pathname, + FILE *fp); +#else +typedef void (*dl_funcptr)(void); +extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, + const char *shortname, + const char *pathname, FILE *fp); +#endif + +#endif /* HAVE_DYNAMIC_LOADING */ + typedef enum ext_module_kind { _Py_ext_module_kind_UNKNOWN = 0, @@ -28,6 +56,11 @@ typedef enum ext_module_origin { _Py_ext_module_origin_DYNAMIC = 3, } _Py_ext_module_origin; +struct hook_prefixes { + const char *const init_prefix; + const char *const export_prefix; +}; + /* Input for loading an extension module. */ struct _Py_ext_module_loader_info { PyObject *filename; @@ -40,7 +73,7 @@ struct _Py_ext_module_loader_info { * depending on if it's builtin or not. */ PyObject *path; _Py_ext_module_origin origin; - const char *hook_prefix; + const struct hook_prefixes *hook_prefixes; const char *newcontext; }; extern void _Py_ext_module_loader_info_clear( @@ -62,7 +95,9 @@ extern int _Py_ext_module_loader_info_init_from_spec( PyObject *spec); #endif -/* The result from running an extension module's init function. */ +/* The result from running an extension module's init function. + * Not used for modules defined via PyModExport (slots array). + */ struct _Py_ext_module_loader_result { PyModuleDef *def; PyObject *module; @@ -89,10 +124,11 @@ extern void _Py_ext_module_loader_result_apply_error( /* The module init function. */ typedef PyObject *(*PyModInitFunction)(void); +typedef PyModuleDef_Slot *(*PyModExportFunction)(void); #ifdef HAVE_DYNAMIC_LOADING -extern PyModInitFunction _PyImport_GetModInitFunc( +extern int _PyImport_GetModuleExportHooks( struct _Py_ext_module_loader_info *info, - FILE *fp); + FILE *fp, PyModInitFunction *modinit, PyModExportFunction *modexport); #endif extern int _PyImport_RunModInitFunc( PyModInitFunction p0, @@ -104,8 +140,6 @@ extern int _PyImport_RunModInitFunc( #define MAXSUFFIXSIZE 12 #ifdef MS_WINDOWS -#include -typedef FARPROC dl_funcptr; #ifdef Py_DEBUG # define PYD_DEBUG_SUFFIX "_d" @@ -128,8 +162,6 @@ typedef FARPROC dl_funcptr; #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX "." PYD_SOABI ".pyd" #define PYD_UNTAGGED_SUFFIX PYD_DEBUG_SUFFIX ".pyd" -#else -typedef void (*dl_funcptr)(void); #endif diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 368dafb9063..183b2d45c5e 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -153,10 +153,8 @@ typedef enum { } _PyConfigInitEnum; typedef enum { - /* For now, this means the GIL is enabled. - - gh-116329: This will eventually change to "the GIL is disabled but can - be re-enabled by loading an incompatible extension module." */ + /* In free threaded builds, this means that the GIL is disabled at startup, + but may be enabled by loading an incompatible extension module. */ _PyConfig_GIL_DEFAULT = -1, /* The GIL has been forced off or on, and will not be affected by module loading. */ diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index 7658adca719..ebc5622912f 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -33,32 +33,34 @@ int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events); int _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events); int _PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet *events); -extern int + +// these are exported only for other re-generated interpreters to call +PyAPI_FUNC(int) _Py_call_instrumentation(PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); -extern int +PyAPI_FUNC(int) _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev); -extern int +PyAPI_FUNC(int) _Py_call_instrumentation_instruction( PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr); -_Py_CODEUNIT * +PyAPI_FUNC(_Py_CODEUNIT *) _Py_call_instrumentation_jump( _Py_CODEUNIT *instr, PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest); -extern int +PyAPI_FUNC(int) _Py_call_instrumentation_arg(PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg); -extern int +PyAPI_FUNC(int) _Py_call_instrumentation_2args(PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); -extern void +PyAPI_FUNC(void) _Py_call_instrumentation_exc2(PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index fa9568ab4d0..6b3d5711b92 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -15,7 +15,6 @@ extern "C" { #include "pycore_tstate.h" // _PyThreadStateImpl #include "pycore_typedefs.h" // _PyRuntimeState - #define CODE_MAX_WATCHERS 8 #define CONTEXT_MAX_WATCHERS 8 #define FUNC_MAX_WATCHERS 8 @@ -180,6 +179,10 @@ struct gc_collection_stats { Py_ssize_t collected; /* total number of uncollectable objects (put into gc.garbage) */ Py_ssize_t uncollectable; + // Total number of objects considered for collection and traversed: + Py_ssize_t candidates; + // Duration of the collection in seconds: + double duration; }; /* Running stats per generation */ @@ -190,6 +193,10 @@ struct gc_generation_stats { Py_ssize_t collected; /* total number of uncollectable objects (put into gc.garbage) */ Py_ssize_t uncollectable; + // Total number of objects considered for collection and traversed: + Py_ssize_t candidates; + // Duration of the collection in seconds: + double duration; }; enum _GCPhase { @@ -198,16 +205,10 @@ enum _GCPhase { }; /* If we change this, we need to change the default value in the - signature of gc.collect. */ + signature of gc.collect and change the size of PyStats.gc_stats */ #define NUM_GENERATIONS 3 struct _gc_runtime_state { - /* List of objects that still need to be cleaned up, singly linked - * via their gc headers' gc_prev pointers. */ - PyObject *trash_delete_later; - /* Current call-stack depth of tp_dealloc calls. */ - int trash_delete_nesting; - /* Is automatic collection enabled? */ int enabled; int debug; @@ -219,6 +220,9 @@ struct _gc_runtime_state { struct gc_generation_stats generation_stats[NUM_GENERATIONS]; /* true if we are currently running the collector */ int collecting; + // The frame that started the current collection. It might be NULL even when + // collecting (if no Python frame is running): + _PyInterpreterFrame *frame; /* list of uncollectable objects */ PyObject *garbage; /* a list of callbacks to be invoked when collection is performed */ @@ -677,11 +681,6 @@ struct _Py_interp_cached_objects { /* object.__reduce__ */ PyObject *objreduce; -#ifndef Py_GIL_DISABLED - /* resolve_slotdups() */ - PyObject *type_slots_pname; - pytype_slotdef *type_slots_ptrs[MAX_EQUIV]; -#endif /* TypeVar and related types */ PyTypeObject *generic_type; @@ -779,12 +778,6 @@ struct _is { * and should be placed at the beginning. */ struct _ceval_state ceval; - /* This structure is carefully allocated so that it's correctly aligned - * to avoid undefined behaviors during LOAD and STORE. The '_malloced' - * field stores the allocated pointer address that will later be freed. - */ - void *_malloced; - PyInterpreterState *next; int64_t id; @@ -949,11 +942,13 @@ struct _is { struct callable_cache callable_cache; PyObject *common_consts[NUM_COMMON_CONSTANTS]; bool jit; + bool compiling; struct _PyExecutorObject *executor_list_head; struct _PyExecutorObject *executor_deletion_list_head; struct _PyExecutorObject *cold_executor; + struct _PyExecutorObject *cold_dynamic_executor; int executor_deletion_list_remaining_capacity; - size_t trace_run_counter; + size_t executor_creation_counter; _rare_events rare_events; PyDict_WatchCallback builtins_dict_watcher; @@ -977,6 +972,18 @@ struct _is { # ifdef Py_STACKREF_CLOSE_DEBUG _Py_hashtable_t *closed_stackrefs_table; # endif +#endif + +#ifdef Py_STATS + // true if recording of pystats is on, this is used when new threads + // are created to decide if recording should be on for them + int pystats_enabled; + // allocated when (and if) stats are first enabled + PyStats *pystats_struct; +#ifdef Py_GIL_DISABLED + // held when pystats related interpreter state is being updated + PyMutex pystats_mutex; +#endif #endif /* the initial PyInterpreterState.threads.head */ diff --git a/Include/internal/pycore_interpframe.h b/Include/internal/pycore_interpframe.h index 2ee3696317c..8949d6cc2fc 100644 --- a/Include/internal/pycore_interpframe.h +++ b/Include/internal/pycore_interpframe.h @@ -24,6 +24,36 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { return (PyCodeObject *)executable; } +// Similar to _PyFrame_GetCode(), but return NULL if the frame is invalid or +// freed. Used by dump_frame() in Python/traceback.c. The function uses +// heuristics to detect freed memory, it's not 100% reliable. +static inline PyCodeObject* +_PyFrame_SafeGetCode(_PyInterpreterFrame *f) +{ + // globals and builtins may be NULL on a legit frame, but it's unlikely. + // It's more likely that it's a sign of an invalid frame. + if (f->f_globals == NULL || f->f_builtins == NULL) { + return NULL; + } + + if (PyStackRef_IsNull(f->f_executable)) { + return NULL; + } + void *ptr; + memcpy(&ptr, &f->f_executable, sizeof(f->f_executable)); + if (_PyMem_IsPtrFreed(ptr)) { + return NULL; + } + PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); + if (_PyObject_IsFreed(executable)) { + return NULL; + } + if (!PyCode_Check(executable)) { + return NULL; + } + return (PyCodeObject *)executable; +} + static inline _Py_CODEUNIT * _PyFrame_GetBytecode(_PyInterpreterFrame *f) { @@ -37,6 +67,31 @@ _PyFrame_GetBytecode(_PyInterpreterFrame *f) #endif } +// Similar to PyUnstable_InterpreterFrame_GetLasti(), but return NULL if the +// frame is invalid or freed. Used by dump_frame() in Python/traceback.c. The +// function uses heuristics to detect freed memory, it's not 100% reliable. +static inline int +_PyFrame_SafeGetLasti(struct _PyInterpreterFrame *f) +{ + // Code based on _PyFrame_GetBytecode() but replace _PyFrame_GetCode() + // with _PyFrame_SafeGetCode(). + PyCodeObject *co = _PyFrame_SafeGetCode(f); + if (co == NULL) { + return -1; + } + + _Py_CODEUNIT *bytecode; +#ifdef Py_GIL_DISABLED + _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); + assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); + bytecode = (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; +#else + bytecode = _PyCode_CODE(co); +#endif + + return (int)(f->instr_ptr - bytecode) * sizeof(_Py_CODEUNIT); +} + static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) { PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj); assert(PyFunction_Check(func)); diff --git a/Include/internal/pycore_interpframe_structs.h b/Include/internal/pycore_interpframe_structs.h index 835b8e58194..38510685f40 100644 --- a/Include/internal/pycore_interpframe_structs.h +++ b/Include/internal/pycore_interpframe_structs.h @@ -24,7 +24,6 @@ enum _frameowner { FRAME_OWNED_BY_GENERATOR = 1, FRAME_OWNED_BY_FRAME_OBJECT = 2, FRAME_OWNED_BY_INTERPRETER = 3, - FRAME_OWNED_BY_CSTACK = 4, }; struct _PyInterpreterFrame { diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 8a88cbf607b..a7041ef8d4b 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -13,9 +13,15 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +/* To be able to reason about code layout and branches, keep code size below 1 MB */ +#define PY_MAX_JIT_CODE_SIZE ((1 << 20)-1) + #ifdef _Py_JIT -typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); +typedef _Py_CODEUNIT *(*jit_func)( + _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, + _PyStackRef _tos_cache0, _PyStackRef _tos_cache1, _PyStackRef _tos_cache2 +); int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 3c213783cd4..d545ba0c3ab 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -135,7 +135,7 @@ extern int _PyLong_FormatWriter( int alternate); extern char* _PyLong_FormatBytesWriter( - _PyBytesWriter *writer, + PyBytesWriter *writer, char *str, PyObject *obj, int base, diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 81bfd162c7e..2fb46a6df50 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -279,11 +279,14 @@ Known values: Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST) Python 3.14b3 3625 (Fix handling of opcodes that may leave operands on the stack when optimizing LOAD_FAST) Python 3.14rc2 3626 (Fix missing exception handlers in logical expression) + Python 3.14rc3 3627 (Fix miscompilation of some module-level annotations) Python 3.15a0 3650 (Initial version) Python 3.15a1 3651 (Simplify LOAD_CONST) Python 3.15a1 3652 (Virtual iterators) Python 3.15a1 3653 (Fix handling of opcodes that may leave operands on the stack when optimizing LOAD_FAST) Python 3.15a1 3654 (Fix missing exception handlers in logical expression) + Python 3.15a1 3655 (Fix miscompilation of some module-level annotations) + Python 3.15a1 3656 (Add TRACE_RECORD instruction, for platforms with switch based interpreter) Python 3.16 will start with 3700 @@ -297,7 +300,7 @@ PC/launcher.c must also be updated. */ -#define PYC_MAGIC_NUMBER 3654 +#define PYC_MAGIC_NUMBER 3656 /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes (little-endian) and then appending b'\r\n'. */ #define PYC_MAGIC_NUMBER_TOKEN \ diff --git a/Include/internal/pycore_mmap.h b/Include/internal/pycore_mmap.h new file mode 100644 index 00000000000..214fd4362a5 --- /dev/null +++ b/Include/internal/pycore_mmap.h @@ -0,0 +1,45 @@ +#ifndef Py_INTERNAL_MMAP_H +#define Py_INTERNAL_MMAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_pystate.h" + +#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) +# include +# include +#endif + +#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) +static inline void +_PyAnnotateMemoryMap(void *addr, size_t size, const char *name) +{ +#ifndef Py_DEBUG + if (!_Py_GetConfig()->dev_mode) { + return; + } +#endif + assert(strlen(name) < 80); + int old_errno = errno; + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name); + /* Ignore errno from prctl */ + /* See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746 */ + errno = old_errno; +} +#else +static inline void +_PyAnnotateMemoryMap(void *Py_UNUSED(addr), size_t Py_UNUSED(size), const char *Py_UNUSED(name)) +{ +} +#endif + +#ifdef __cplusplus +} +#endif +#endif // !Py_INTERNAL_MMAP_H diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h index b170d7bce70..9a62daf6621 100644 --- a/Include/internal/pycore_moduleobject.h +++ b/Include/internal/pycore_moduleobject.h @@ -1,5 +1,8 @@ #ifndef Py_INTERNAL_MODULEOBJECT_H #define Py_INTERNAL_MODULEOBJECT_H + +#include + #ifdef __cplusplus extern "C" { #endif @@ -16,32 +19,49 @@ extern int _PyModule_IsPossiblyShadowing(PyObject *); extern int _PyModule_IsExtension(PyObject *obj); +typedef int (*_Py_modexecfunc)(PyObject *); + typedef struct { PyObject_HEAD PyObject *md_dict; - PyModuleDef *md_def; void *md_state; PyObject *md_weaklist; // for logging purposes after md_dict is cleared PyObject *md_name; + bool md_token_is_def; /* if true, `md_token` is the PyModuleDef */ #ifdef Py_GIL_DISABLED - void *md_gil; + bool md_requires_gil; #endif + Py_ssize_t md_state_size; + traverseproc md_state_traverse; + inquiry md_state_clear; + freefunc md_state_free; + void *md_token; + _Py_modexecfunc md_exec; /* only set if md_token_is_def is true */ } PyModuleObject; -static inline PyModuleDef* _PyModule_GetDef(PyObject *mod) { - assert(PyModule_Check(mod)); - return ((PyModuleObject *)mod)->md_def; +#define _PyModule_CAST(op) \ + (assert(PyModule_Check(op)), _Py_CAST(PyModuleObject*, (op))) + +static inline PyModuleDef *_PyModule_GetDefOrNull(PyObject *arg) { + PyModuleObject *mod = _PyModule_CAST(arg); + if (mod->md_token_is_def) { + return (PyModuleDef *)mod->md_token; + } + return NULL; +} + +static inline PyModuleDef *_PyModule_GetToken(PyObject *arg) { + PyModuleObject *mod = _PyModule_CAST(arg); + return (PyModuleDef *)mod->md_token; } static inline void* _PyModule_GetState(PyObject* mod) { - assert(PyModule_Check(mod)); - return ((PyModuleObject *)mod)->md_state; + return _PyModule_CAST(mod)->md_state; } static inline PyObject* _PyModule_GetDict(PyObject *mod) { - assert(PyModule_Check(mod)); - PyObject *dict = ((PyModuleObject *)mod) -> md_dict; + PyObject *dict = _PyModule_CAST(mod)->md_dict; // _PyModule_GetDict(mod) must not be used after calling module_clear(mod) assert(dict != NULL); return dict; // borrowed reference diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 40f8ca68c00..6b91e4334b1 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -496,6 +496,9 @@ static inline void Py_DECREF_MORTAL_SPECIALIZED(PyObject *op, destructor destruc #define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) Py_DECREF_MORTAL_SPECIALIZED(_PyObject_CAST(op), destruct) #endif +#else // Py_GIL_DISABLED +# define Py_DECREF_MORTAL(op) Py_DECREF(op) +# define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) Py_DECREF(op) #endif /* Inline functions trading binary compatibility for speed: @@ -863,8 +866,7 @@ static inline Py_hash_t _PyObject_HashFast(PyObject *op) { if (PyUnicode_CheckExact(op)) { - Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED( - _PyASCIIObject_CAST(op)->hash); + Py_hash_t hash = PyUnstable_Unicode_GET_CACHED_HASH(op); if (hash != -1) { return hash; } @@ -1031,7 +1033,8 @@ enum _PyAnnotateFormat { _Py_ANNOTATE_FORMAT_STRING = 4, }; -int _PyObject_SetDict(PyObject *obj, PyObject *value); +extern int _PyObject_SetDict(PyObject *obj, PyObject *value); +extern int _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict); #ifndef Py_GIL_DISABLED static inline Py_ALWAYS_INLINE void _Py_INCREF_MORTAL(PyObject *op) @@ -1045,8 +1048,14 @@ static inline Py_ALWAYS_INLINE void _Py_INCREF_MORTAL(PyObject *op) } #endif } +#else +# define _Py_INCREF_MORTAL(op) Py_INCREF(op) #endif +/* Utility for the tp_traverse slot of mutable heap types that have no other + * references. */ +PyAPI_FUNC(int) _PyObject_VisitType(PyObject *op, visitproc visit, void *arg); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index bd6b84ec7fd..906ea0db0a5 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -488,6 +488,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 1; case TO_BOOL_STR: return 1; + case TRACE_RECORD: + return 0; case UNARY_INVERT: return 1; case UNARY_NEGATIVE: @@ -971,6 +973,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case TO_BOOL_STR: return 1; + case TRACE_RECORD: + return 0; case UNARY_INVERT: return 1; case UNARY_NEGATIVE: @@ -1028,9 +1032,12 @@ enum InstructionFormat { #define HAS_ESCAPES_FLAG (512) #define HAS_EXIT_FLAG (1024) #define HAS_PURE_FLAG (2048) -#define HAS_ERROR_NO_POP_FLAG (4096) -#define HAS_NO_SAVE_IP_FLAG (8192) -#define HAS_PERIODIC_FLAG (16384) +#define HAS_SYNC_SP_FLAG (4096) +#define HAS_ERROR_NO_POP_FLAG (8192) +#define HAS_NO_SAVE_IP_FLAG (16384) +#define HAS_PERIODIC_FLAG (32768) +#define HAS_UNPREDICTABLE_JUMP_FLAG (65536) +#define HAS_NEEDS_GUARD_IP_FLAG (131072) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) @@ -1043,9 +1050,12 @@ enum InstructionFormat { #define OPCODE_HAS_ESCAPES(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ESCAPES_FLAG)) #define OPCODE_HAS_EXIT(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_EXIT_FLAG)) #define OPCODE_HAS_PURE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PURE_FLAG)) +#define OPCODE_HAS_SYNC_SP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_SYNC_SP_FLAG)) #define OPCODE_HAS_ERROR_NO_POP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ERROR_NO_POP_FLAG)) #define OPCODE_HAS_NO_SAVE_IP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NO_SAVE_IP_FLAG)) #define OPCODE_HAS_PERIODIC(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PERIODIC_FLAG)) +#define OPCODE_HAS_UNPREDICTABLE_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_UNPREDICTABLE_JUMP_FLAG)) +#define OPCODE_HAS_NEEDS_GUARD_IP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NEEDS_GUARD_IP_FLAG)) #define OPARG_SIMPLE 0 #define OPARG_CACHE_1 1 @@ -1062,27 +1072,27 @@ enum InstructionFormat { struct opcode_metadata { uint8_t valid_entry; uint8_t instr_format; - uint16_t flags; + uint32_t flags; }; extern const struct opcode_metadata _PyOpcode_opcode_metadata[267]; #ifdef NEED_OPCODE_METADATA const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, - [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG }, + [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_LIST_SLICE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, [BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BUILD_INTERPOLATION] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1094,33 +1104,33 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [BUILD_TEMPLATE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [CACHE] = { true, INSTR_FMT_IX, 0 }, - [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_ISINSTANCE] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_KW_BOUND_METHOD] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_KW_BOUND_METHOD] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [CALL_KW_NON_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_KW_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_KW_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [CALL_LEN] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [CHECK_EG_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, @@ -1143,7 +1153,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [DELETE_SUBSCR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [END_ASYNC_FOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [END_ASYNC_FOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [END_FOR] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, [END_SEND] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_PURE_FLAG }, [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1151,11 +1161,11 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, - [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG }, + [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, + [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [GET_AITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_ANEXT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1164,17 +1174,17 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_END_ASYNC_FOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [INSTRUMENTED_END_ASYNC_FOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, + [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG }, [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_NOT_TAKEN] = { true, INSTR_FMT_IX, 0 }, [INSTRUMENTED_POP_ITER] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, @@ -1183,8 +1193,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1197,7 +1207,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, @@ -1205,7 +1215,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1253,10 +1263,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [RESERVED] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, - [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, - [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1283,6 +1293,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [TO_BOOL_LIST] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [TO_BOOL_NONE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [TRACE_RECORD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_INVERT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, @@ -1292,7 +1303,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [ANNOTATIONS_PLACEHOLDER] = { true, -1, HAS_PURE_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1318,21 +1329,21 @@ extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 } } }, - [BINARY_OP_ADD_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_FLOAT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_ADD_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_INT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_ADD_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_ADD_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_ADD_UNICODE] = { .nuops = 5, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } }, [BINARY_OP_EXTEND] = { .nuops = 2, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 } } }, [BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_MULTIPLY_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_DICT] = { .nuops = 2, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 3, .uops = { { _GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_TUPLE_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_TUPLE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_TUPLE_INT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_SUBTRACT_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_INT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_SUBTRACT_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, [BINARY_SLICE] = { .nuops = 1, .uops = { { _BINARY_SLICE, OPARG_SIMPLE, 0 } } }, [BUILD_INTERPOLATION] = { .nuops = 1, .uops = { { _BUILD_INTERPOLATION, OPARG_SIMPLE, 0 } } }, [BUILD_LIST] = { .nuops = 1, .uops = { { _BUILD_LIST, OPARG_SIMPLE, 0 } } }, @@ -1348,15 +1359,15 @@ _PyOpcode_macro_expansion[256] = { [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_BUILTIN_O] = { .nuops = 2, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_BUILTIN_O] = { .nuops = 4, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_1, OPARG_SIMPLE, 0 } } }, [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_2, OPARG_SIMPLE, 0 } } }, [CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, [CALL_KW_BOUND_METHOD] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION_KW, 2, 1 }, { _EXPAND_METHOD_KW, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_KW_NON_PY] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_KW, OPARG_SIMPLE, 3 }, { _CALL_KW_NON_PY, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_KW_PY] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_LEN] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 } } }, - [CALL_LIST_APPEND] = { .nuops = 4, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } }, + [CALL_LEN] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, + [CALL_LIST_APPEND] = { .nuops = 6, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, @@ -1364,14 +1375,14 @@ _PyOpcode_macro_expansion[256] = { [CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_PY_GENERAL] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_STR_1] = { .nuops = 4, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_STR_1, OPARG_SIMPLE, 3 }, { _CALL_STR_1, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_TUPLE_1] = { .nuops = 4, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TUPLE_1, OPARG_SIMPLE, 3 }, { _CALL_TUPLE_1, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_STR_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_STR_1, OPARG_SIMPLE, 3 }, { _CALL_STR_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_TUPLE_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TUPLE_1, OPARG_SIMPLE, 3 }, { _CALL_TUPLE_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_TYPE_1] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TYPE_1, OPARG_SIMPLE, 3 }, { _CALL_TYPE_1, OPARG_SIMPLE, 3 } } }, [CHECK_EG_MATCH] = { .nuops = 1, .uops = { { _CHECK_EG_MATCH, OPARG_SIMPLE, 0 } } }, [CHECK_EXC_MATCH] = { .nuops = 1, .uops = { { _CHECK_EXC_MATCH, OPARG_SIMPLE, 0 } } }, [COMPARE_OP] = { .nuops = 1, .uops = { { _COMPARE_OP, OPARG_SIMPLE, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _COMPARE_OP_FLOAT, OPARG_SIMPLE, 1 } } }, - [COMPARE_OP_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _COMPARE_OP_INT, OPARG_SIMPLE, 1 } } }, + [COMPARE_OP_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _COMPARE_OP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 } } }, [COMPARE_OP_STR] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _COMPARE_OP_STR, OPARG_SIMPLE, 1 } } }, [CONTAINS_OP] = { .nuops = 1, .uops = { { _CONTAINS_OP, OPARG_SIMPLE, 0 } } }, [CONTAINS_OP_DICT] = { .nuops = 2, .uops = { { _GUARD_TOS_DICT, OPARG_SIMPLE, 0 }, { _CONTAINS_OP_DICT, OPARG_SIMPLE, 1 } } }, @@ -1406,12 +1417,15 @@ _PyOpcode_macro_expansion[256] = { [IMPORT_FROM] = { .nuops = 1, .uops = { { _IMPORT_FROM, OPARG_SIMPLE, 0 } } }, [IMPORT_NAME] = { .nuops = 1, .uops = { { _IMPORT_NAME, OPARG_SIMPLE, 0 } } }, [IS_OP] = { .nuops = 1, .uops = { { _IS_OP, OPARG_SIMPLE, 0 } } }, + [JUMP_BACKWARD] = { .nuops = 2, .uops = { { _CHECK_PERIODIC, OPARG_SIMPLE, 1 }, { _JUMP_BACKWARD_NO_INTERRUPT, OPARG_REPLACED, 1 } } }, + [JUMP_BACKWARD_NO_INTERRUPT] = { .nuops = 1, .uops = { { _JUMP_BACKWARD_NO_INTERRUPT, OPARG_REPLACED, 0 } } }, + [JUMP_BACKWARD_NO_JIT] = { .nuops = 2, .uops = { { _CHECK_PERIODIC, OPARG_SIMPLE, 1 }, { _JUMP_BACKWARD_NO_INTERRUPT, OPARG_REPLACED, 1 } } }, [LIST_APPEND] = { .nuops = 1, .uops = { { _LIST_APPEND, OPARG_SIMPLE, 0 } } }, [LIST_EXTEND] = { .nuops = 1, .uops = { { _LIST_EXTEND, OPARG_SIMPLE, 0 } } }, [LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, OPARG_SIMPLE, 8 } } }, [LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 4, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 5, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, @@ -1468,9 +1482,9 @@ _PyOpcode_macro_expansion[256] = { [SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, OPARG_SIMPLE, 0 } } }, [SET_UPDATE] = { .nuops = 1, .uops = { { _SET_UPDATE, OPARG_SIMPLE, 0 } } }, [STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, OPARG_SIMPLE, 3 } } }, - [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, OPARG_SIMPLE, 3 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } }, - [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } }, - [STORE_ATTR_WITH_HINT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 } } }, + [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, OPARG_SIMPLE, 3 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, + [STORE_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, + [STORE_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, [STORE_DEREF] = { .nuops = 1, .uops = { { _STORE_DEREF, OPARG_SIMPLE, 0 } } }, [STORE_FAST] = { .nuops = 1, .uops = { { _STORE_FAST, OPARG_SIMPLE, 0 } } }, [STORE_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _STORE_FAST, OPARG_TOP, 0 }, { _LOAD_FAST, OPARG_BOTTOM, 0 } } }, @@ -1479,8 +1493,8 @@ _PyOpcode_macro_expansion[256] = { [STORE_NAME] = { .nuops = 1, .uops = { { _STORE_NAME, OPARG_SIMPLE, 0 } } }, [STORE_SLICE] = { .nuops = 1, .uops = { { _STORE_SLICE, OPARG_SIMPLE, 0 } } }, [STORE_SUBSCR] = { .nuops = 1, .uops = { { _STORE_SUBSCR, OPARG_SIMPLE, 0 } } }, - [STORE_SUBSCR_DICT] = { .nuops = 2, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_DICT, OPARG_SIMPLE, 1 } } }, - [STORE_SUBSCR_LIST_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 } } }, + [STORE_SUBSCR_DICT] = { .nuops = 3, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_DICT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } }, + [STORE_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } }, [SWAP] = { .nuops = 1, .uops = { { _SWAP, OPARG_SIMPLE, 0 } } }, [TO_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL, OPARG_SIMPLE, 2 } } }, [TO_BOOL_ALWAYS_TRUE] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _REPLACE_WITH_TRUE, OPARG_SIMPLE, 3 } } }, @@ -1731,6 +1745,7 @@ const char *_PyOpcode_OpName[267] = { [TO_BOOL_LIST] = "TO_BOOL_LIST", [TO_BOOL_NONE] = "TO_BOOL_NONE", [TO_BOOL_STR] = "TO_BOOL_STR", + [TRACE_RECORD] = "TRACE_RECORD", [UNARY_INVERT] = "UNARY_INVERT", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", @@ -1802,7 +1817,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [230] = 230, [231] = 231, [232] = 232, - [233] = 233, [BINARY_OP] = BINARY_OP, [BINARY_OP_ADD_FLOAT] = BINARY_OP, [BINARY_OP_ADD_INT] = BINARY_OP, @@ -2018,6 +2032,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [TO_BOOL_LIST] = TO_BOOL, [TO_BOOL_NONE] = TO_BOOL, [TO_BOOL_STR] = TO_BOOL, + [TRACE_RECORD] = TRACE_RECORD, [UNARY_INVERT] = UNARY_INVERT, [UNARY_NEGATIVE] = UNARY_NEGATIVE, [UNARY_NOT] = UNARY_NOT, @@ -2063,7 +2078,6 @@ const uint8_t _PyOpcode_Deopt[256] = { case 230: \ case 231: \ case 232: \ - case 233: \ ; struct pseudo_targets { uint8_t as_sequence; diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 9f930f2107e..295d4909e14 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_typedefs.h" // _PyInterpreterFrame +#include "pycore_uop.h" // _PyUOpInstruction #include "pycore_uop_ids.h" #include "pycore_stackref.h" // _PyStackRef #include @@ -20,56 +21,25 @@ typedef struct _PyExecutorLinkListNode { } _PyExecutorLinkListNode; -/* Bloom filter with m = 256 - * https://en.wikipedia.org/wiki/Bloom_filter */ -#define _Py_BLOOM_FILTER_WORDS 8 - -typedef struct { - uint32_t bits[_Py_BLOOM_FILTER_WORDS]; -} _PyBloomFilter; - typedef struct { uint8_t opcode; uint8_t oparg; - uint8_t valid:1; - uint8_t linked:1; - uint8_t chain_depth:6; // Must be big enough for MAX_CHAIN_DEPTH - 1. + uint8_t valid; + uint8_t linked; + uint8_t chain_depth; // Must be big enough for MAX_CHAIN_DEPTH - 1. bool warm; - int index; // Index of ENTER_EXECUTOR (if code isn't NULL, below). + int32_t index; // Index of ENTER_EXECUTOR (if code isn't NULL, below). _PyBloomFilter bloom; _PyExecutorLinkListNode links; PyCodeObject *code; // Weak (NULL if no corresponding ENTER_EXECUTOR). } _PyVMData; -/* Depending on the format, - * the 32 bits between the oparg and operand are: - * UOP_FORMAT_TARGET: - * uint32_t target; - * UOP_FORMAT_JUMP - * uint16_t jump_target; - * uint16_t error_target; - */ -typedef struct { - uint16_t opcode:15; - uint16_t format:1; - uint16_t oparg; - union { - uint32_t target; - struct { - uint16_t jump_target; - uint16_t error_target; - }; - }; - uint64_t operand0; // A cache entry - uint64_t operand1; -#ifdef Py_STATS - uint64_t execution_count; -#endif -} _PyUOpInstruction; - typedef struct _PyExitData { uint32_t target; - uint16_t index; + uint16_t index:12; + uint16_t stack_cache:2; + uint16_t is_dynamic:1; + uint16_t is_control_flow:1; _Py_BackoffCounter temperature; struct _PyExecutorObject *executor; } _PyExitData; @@ -115,15 +85,12 @@ PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp); #endif // Used as the threshold to trigger executor invalidation when -// trace_run_counter is greater than this value. -#define JIT_CLEANUP_THRESHOLD 100000 +// executor_creation_counter is greater than this value. +// This value is arbitrary and was not optimized. +#define JIT_CLEANUP_THRESHOLD 1000 -// This is the length of the trace we project initially. -#define UOP_MAX_TRACE_LENGTH 800 - -#define TRACE_STACK_SIZE 5 - -int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame, +int _Py_uop_analyze_and_optimize( + PyFunctionObject *func, _PyUOpInstruction *trace, int trace_len, int curr_stackentries, _PyBloomFilter *dependencies); @@ -157,7 +124,7 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst) #define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5) // Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) -#define MAX_ABSTRACT_FRAME_DEPTH (TRACE_STACK_SIZE + 2) +#define MAX_ABSTRACT_FRAME_DEPTH (16) // The maximum number of side exits that we can take before requiring forward // progress (and inserting a new ENTER_EXECUTOR instruction). In practice, this @@ -251,6 +218,12 @@ PyJitRef_Wrap(JitOptSymbol *sym) return (JitOptRef){.bits=(uintptr_t)sym}; } +static inline JitOptRef +PyJitRef_StripReferenceInfo(JitOptRef ref) +{ + return PyJitRef_Wrap(PyJitRef_Unwrap(ref)); +} + static inline JitOptRef PyJitRef_Borrow(JitOptRef ref) { @@ -272,9 +245,14 @@ PyJitRef_IsBorrowed(JitOptRef ref) } struct _Py_UOpsAbstractFrame { + bool globals_watched; + // The version number of the globals dicts, once checked. 0 if unchecked. + uint32_t globals_checked_version; // Max stacklen int stack_len; int locals_len; + PyFunctionObject *func; + PyCodeObject *code; JitOptRef *stack_pointer; JitOptRef *stack; @@ -293,6 +271,8 @@ typedef struct _JitOptContext { char done; char out_of_space; bool contradiction; + // Has the builtins dict been watched? + bool builtins_watched; // The current "executing" frame. _Py_UOpsAbstractFrame *frame; _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH]; @@ -332,8 +312,8 @@ extern bool _Py_uop_sym_is_bottom(JitOptRef sym); extern int _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef sym); extern PyTypeObject *_Py_uop_sym_get_type(JitOptRef sym); extern JitOptRef _Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptRef *args); -extern JitOptRef _Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptRef sym, int item); -extern int _Py_uop_sym_tuple_length(JitOptRef sym); +extern JitOptRef _Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptRef sym, Py_ssize_t item); +extern Py_ssize_t _Py_uop_sym_tuple_length(JitOptRef sym); extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value, bool truthy); extern bool _Py_uop_sym_is_compact_int(JitOptRef sym); extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx); @@ -348,11 +328,11 @@ extern _Py_UOpsAbstractFrame *_Py_uop_frame_new( int curr_stackentries, JitOptRef *args, int arg_len); -extern int _Py_uop_frame_pop(JitOptContext *ctx); +extern int _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries); PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); -PyAPI_FUNC(int) _PyOptimizer_Optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyExecutorObject **exec_ptr, int chain_depth); +PyAPI_FUNC(int) _PyOptimizer_Optimize(_PyInterpreterFrame *frame, PyThreadState *tstate); static inline _PyExecutorObject *_PyExecutor_FromExit(_PyExitData *exit) { @@ -361,18 +341,10 @@ static inline _PyExecutorObject *_PyExecutor_FromExit(_PyExitData *exit) } extern _PyExecutorObject *_PyExecutor_GetColdExecutor(void); +extern _PyExecutorObject *_PyExecutor_GetColdDynamicExecutor(void); PyAPI_FUNC(void) _PyExecutor_ClearExit(_PyExitData *exit); -static inline int is_terminator(const _PyUOpInstruction *uop) -{ - int opcode = uop->opcode; - return ( - opcode == _EXIT_TRACE || - opcode == _JUMP_TO_TOP - ); -} - extern void _PyExecutor_Free(_PyExecutorObject *self); PyAPI_FUNC(int) _PyDumpExecutors(FILE *out); @@ -380,6 +352,18 @@ PyAPI_FUNC(int) _PyDumpExecutors(FILE *out); extern void _Py_ClearExecutorDeletionList(PyInterpreterState *interp); #endif +int _PyJit_translate_single_bytecode_to_trace(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr, int stop_tracing_opcode); + +PyAPI_FUNC(int) +_PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, + _Py_CODEUNIT *curr_instr, _Py_CODEUNIT *start_instr, + _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit, + int oparg); + +void _PyJit_FinalizeTracing(PyThreadState *tstate); + +void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_parser.h b/Include/internal/pycore_parser.h index 2885dee63dc..2c46f59ab7d 100644 --- a/Include/internal/pycore_parser.h +++ b/Include/internal/pycore_parser.h @@ -48,7 +48,8 @@ extern struct _mod* _PyParser_ASTFromString( PyObject* filename, int mode, PyCompilerFlags *flags, - PyArena *arena); + PyArena *arena, + PyObject *module); extern struct _mod* _PyParser_ASTFromFile( FILE *fp, diff --git a/Include/internal/pycore_pyatomic_ft_wrappers.h b/Include/internal/pycore_pyatomic_ft_wrappers.h index c31c3365700..1a6d5075361 100644 --- a/Include/internal/pycore_pyatomic_ft_wrappers.h +++ b/Include/internal/pycore_pyatomic_ft_wrappers.h @@ -31,6 +31,8 @@ extern "C" { _Py_atomic_store_ptr(&value, new_value) #define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) \ _Py_atomic_load_ptr_acquire(&value) +#define FT_ATOMIC_LOAD_PTR_CONSUME(value) \ + _Py_atomic_load_ptr_consume(&value) #define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) \ _Py_atomic_load_uintptr_acquire(&value) #define FT_ATOMIC_LOAD_PTR_RELAXED(value) \ @@ -55,6 +57,8 @@ extern "C" { _Py_atomic_store_uintptr_release(&value, new_value) #define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \ _Py_atomic_store_ssize_relaxed(&value, new_value) +#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \ + _Py_atomic_store_ssize_release(&value, new_value) #define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) \ _Py_atomic_store_uint8_relaxed(&value, new_value) #define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) \ @@ -77,6 +81,10 @@ extern "C" { _Py_atomic_store_ushort_relaxed(&value, new_value) #define FT_ATOMIC_LOAD_USHORT_RELAXED(value) \ _Py_atomic_load_ushort_relaxed(&value) +#define FT_ATOMIC_LOAD_INT(value) \ + _Py_atomic_load_int(&value) +#define FT_ATOMIC_STORE_INT(value, new_value) \ + _Py_atomic_store_int(&value, new_value) #define FT_ATOMIC_STORE_INT_RELAXED(value, new_value) \ _Py_atomic_store_int_relaxed(&value, new_value) #define FT_ATOMIC_LOAD_INT_RELAXED(value) \ @@ -121,6 +129,7 @@ extern "C" { #define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) value #define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) value #define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) value +#define FT_ATOMIC_LOAD_PTR_CONSUME(value) value #define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) value #define FT_ATOMIC_LOAD_PTR_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT8(value) value @@ -133,6 +142,7 @@ extern "C" { #define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value +#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) value = new_value @@ -144,6 +154,8 @@ extern "C" { #define FT_ATOMIC_STORE_SHORT_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_LOAD_USHORT_RELAXED(value) value #define FT_ATOMIC_STORE_USHORT_RELAXED(value, new_value) value = new_value +#define FT_ATOMIC_LOAD_INT(value) value +#define FT_ATOMIC_STORE_INT(value, new_value) value = new_value #define FT_ATOMIC_LOAD_INT_RELAXED(value) value #define FT_ATOMIC_STORE_INT_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_LOAD_UINT_RELAXED(value) value diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index 2c2048f7e12..f80808fcc8c 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -123,7 +123,8 @@ extern void _PyErr_SetNone(PyThreadState *tstate, PyObject *exception); extern PyObject* _PyErr_NoMemory(PyThreadState *tstate); extern int _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset, - int end_lineno, int end_col_offset); + int end_lineno, int end_col_offset, + PyObject *module); extern void _PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset); diff --git a/Include/internal/pycore_pymath.h b/Include/internal/pycore_pymath.h index eea8996ba68..f66325aa59c 100644 --- a/Include/internal/pycore_pymath.h +++ b/Include/internal/pycore_pymath.h @@ -33,7 +33,7 @@ extern "C" { static inline void _Py_ADJUST_ERANGE1(double x) { if (errno == 0) { - if (x == Py_INFINITY || x == -Py_INFINITY) { + if (x == INFINITY || x == -INFINITY) { errno = ERANGE; } } @@ -44,8 +44,8 @@ static inline void _Py_ADJUST_ERANGE1(double x) static inline void _Py_ADJUST_ERANGE2(double x, double y) { - if (x == Py_INFINITY || x == -Py_INFINITY || - y == Py_INFINITY || y == -Py_INFINITY) + if (x == INFINITY || x == -INFINITY || + y == INFINITY || y == -INFINITY) { if (errno == 0) { errno = ERANGE; @@ -146,17 +146,17 @@ extern void _Py_set_387controlword(unsigned short); unsigned int old_fpcr, new_fpcr #define _Py_SET_53BIT_PRECISION_START \ do { \ - __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr)); \ + __asm__ ("fmove.l %%fpcr,%0" : "=dm" (old_fpcr)); \ /* Set double precision / round to nearest. */ \ new_fpcr = (old_fpcr & ~0xf0) | 0x80; \ if (new_fpcr != old_fpcr) { \ - __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr));\ + __asm__ volatile ("fmove.l %0,%%fpcr" : : "dm" (new_fpcr)); \ } \ } while (0) #define _Py_SET_53BIT_PRECISION_END \ do { \ if (new_fpcr != old_fpcr) { \ - __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr)); \ + __asm__ volatile ("fmove.l %0,%%fpcr" : : "dm" (old_fpcr)); \ } \ } while (0) #endif diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h index f3f2ae0a140..05484e847f1 100644 --- a/Include/internal/pycore_pymem.h +++ b/Include/internal/pycore_pymem.h @@ -54,20 +54,43 @@ static inline int _PyMem_IsPtrFreed(const void *ptr) { uintptr_t value = (uintptr_t)ptr; #if SIZEOF_VOID_P == 8 - return (value == 0 + return (value <= 0xff // NULL, 0x1, 0x2, ..., 0xff || value == (uintptr_t)0xCDCDCDCDCDCDCDCD || value == (uintptr_t)0xDDDDDDDDDDDDDDDD - || value == (uintptr_t)0xFDFDFDFDFDFDFDFD); + || value == (uintptr_t)0xFDFDFDFDFDFDFDFD + || value >= (uintptr_t)0xFFFFFFFFFFFFFF00); // -0xff, ..., -2, -1 #elif SIZEOF_VOID_P == 4 - return (value == 0 + return (value <= 0xff || value == (uintptr_t)0xCDCDCDCD || value == (uintptr_t)0xDDDDDDDD - || value == (uintptr_t)0xFDFDFDFD); + || value == (uintptr_t)0xFDFDFDFD + || value >= (uintptr_t)0xFFFFFF00); #else # error "unknown pointer size" #endif } +// Similar to _PyMem_IsPtrFreed() but expects an 'unsigned long' instead of a +// pointer. +static inline int _PyMem_IsULongFreed(unsigned long value) +{ +#if SIZEOF_LONG == 8 + return (value == 0 + || value == (unsigned long)0xCDCDCDCDCDCDCDCD + || value == (unsigned long)0xDDDDDDDDDDDDDDDD + || value == (unsigned long)0xFDFDFDFDFDFDFDFD + || value == (unsigned long)0xFFFFFFFFFFFFFFFF); +#elif SIZEOF_LONG == 4 + return (value == 0 + || value == (unsigned long)0xCDCDCDCD + || value == (unsigned long)0xDDDDDDDD + || value == (unsigned long)0xFDFDFDFD + || value == (unsigned long)0xFFFFFFFF); +#else +# error "unknown long size" +#endif +} + extern int _PyMem_GetAllocatorName( const char *name, PyMemAllocatorName *allocator); diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index ea3dfbd2eef..189a8dde9f0 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -89,8 +89,9 @@ _Py_ThreadCanHandleSignals(PyInterpreterState *interp) /* Variable and static inline functions for in-line access to current thread and interpreter state */ -#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE) +#if !defined(Py_BUILD_CORE_MODULE) extern _Py_thread_local PyThreadState *_Py_tss_tstate; +extern _Py_thread_local PyInterpreterState *_Py_tss_interp; #endif #ifndef NDEBUG @@ -114,7 +115,7 @@ PyAPI_FUNC(PyThreadState *) _PyThreadState_GetCurrent(void); static inline PyThreadState* _PyThreadState_GET(void) { -#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE) +#if !defined(Py_BUILD_CORE_MODULE) return _Py_tss_tstate; #else return _PyThreadState_GetCurrent(); @@ -204,11 +205,15 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) See also PyInterpreterState_Get() and _PyGILState_GetInterpreterStateUnsafe(). */ static inline PyInterpreterState* _PyInterpreterState_GET(void) { - PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG + PyThreadState *tstate = _PyThreadState_GET(); _Py_EnsureTstateNotNULL(tstate); #endif - return tstate->interp; +#if !defined(Py_BUILD_CORE_MODULE) + return _Py_tss_interp; +#else + return _PyThreadState_GET()->interp; +#endif } @@ -326,7 +331,11 @@ _Py_RecursionLimit_GetMargin(PyThreadState *tstate) _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; assert(_tstate->c_stack_hard_limit != 0); intptr_t here_addr = _Py_get_machine_stack_pointer(); +#if _Py_STACK_GROWS_DOWN return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, here_addr - (intptr_t)_tstate->c_stack_soft_limit, _PyOS_STACK_MARGIN_SHIFT); +#else + return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (intptr_t)_tstate->c_stack_soft_limit - here_addr, _PyOS_STACK_MARGIN_SHIFT); +#endif } #ifdef __cplusplus diff --git a/Include/internal/pycore_pystats.h b/Include/internal/pycore_pystats.h index f8af398a560..50ab21aa0f1 100644 --- a/Include/internal/pycore_pystats.h +++ b/Include/internal/pycore_pystats.h @@ -9,7 +9,7 @@ extern "C" { #endif #ifdef Py_STATS -extern void _Py_StatsOn(void); +extern int _Py_StatsOn(void); extern void _Py_StatsOff(void); extern void _Py_StatsClear(void); extern int _Py_PrintSpecializationStats(int to_file); diff --git a/Include/internal/pycore_pythonrun.h b/Include/internal/pycore_pythonrun.h index c2832098ddb..2a544edc431 100644 --- a/Include/internal/pycore_pythonrun.h +++ b/Include/internal/pycore_pythonrun.h @@ -33,14 +33,20 @@ extern const char* _Py_SourceAsString( PyCompilerFlags *cf, PyObject **cmd_copy); +extern PyObject * _Py_CompileStringObjectWithModule( + const char *str, + PyObject *filename, int start, + PyCompilerFlags *flags, int optimize, + PyObject *module); + /* Stack size, in "pointers". This must be large enough, so * no two calls to check recursion depth are more than this far * apart. In practice, that means it must be larger than the C * stack consumption of PyEval_EvalDefault */ -#if defined(_Py_ADDRESS_SANITIZER) || defined(_Py_THREAD_SANITIZER) -# define _PyOS_LOG2_STACK_MARGIN 12 -#elif defined(Py_DEBUG) && defined(WIN32) +#if (defined(Py_DEBUG) \ + || defined(_Py_ADDRESS_SANITIZER) \ + || defined(_Py_THREAD_SANITIZER)) # define _PyOS_LOG2_STACK_MARGIN 12 #else # define _PyOS_LOG2_STACK_MARGIN 11 @@ -54,6 +60,12 @@ extern const char* _Py_SourceAsString( # define _PyOS_STACK_MARGIN_SHIFT (_PyOS_LOG2_STACK_MARGIN + 2) #endif +#ifdef _Py_THREAD_SANITIZER +# define _PyOS_MIN_STACK_SIZE (_PyOS_STACK_MARGIN_BYTES * 6) +#else +# define _PyOS_MIN_STACK_SIZE (_PyOS_STACK_MARGIN_BYTES * 3) +#endif + #ifdef __cplusplus } diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 27669c50cd6..d381fb9d2d4 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -275,6 +275,774 @@ extern "C" { _PyLong_DIGIT_INIT(254), \ _PyLong_DIGIT_INIT(255), \ _PyLong_DIGIT_INIT(256), \ + _PyLong_DIGIT_INIT(257), \ + _PyLong_DIGIT_INIT(258), \ + _PyLong_DIGIT_INIT(259), \ + _PyLong_DIGIT_INIT(260), \ + _PyLong_DIGIT_INIT(261), \ + _PyLong_DIGIT_INIT(262), \ + _PyLong_DIGIT_INIT(263), \ + _PyLong_DIGIT_INIT(264), \ + _PyLong_DIGIT_INIT(265), \ + _PyLong_DIGIT_INIT(266), \ + _PyLong_DIGIT_INIT(267), \ + _PyLong_DIGIT_INIT(268), \ + _PyLong_DIGIT_INIT(269), \ + _PyLong_DIGIT_INIT(270), \ + _PyLong_DIGIT_INIT(271), \ + _PyLong_DIGIT_INIT(272), \ + _PyLong_DIGIT_INIT(273), \ + _PyLong_DIGIT_INIT(274), \ + _PyLong_DIGIT_INIT(275), \ + _PyLong_DIGIT_INIT(276), \ + _PyLong_DIGIT_INIT(277), \ + _PyLong_DIGIT_INIT(278), \ + _PyLong_DIGIT_INIT(279), \ + _PyLong_DIGIT_INIT(280), \ + _PyLong_DIGIT_INIT(281), \ + _PyLong_DIGIT_INIT(282), \ + _PyLong_DIGIT_INIT(283), \ + _PyLong_DIGIT_INIT(284), \ + _PyLong_DIGIT_INIT(285), \ + _PyLong_DIGIT_INIT(286), \ + _PyLong_DIGIT_INIT(287), \ + _PyLong_DIGIT_INIT(288), \ + _PyLong_DIGIT_INIT(289), \ + _PyLong_DIGIT_INIT(290), \ + _PyLong_DIGIT_INIT(291), \ + _PyLong_DIGIT_INIT(292), \ + _PyLong_DIGIT_INIT(293), \ + _PyLong_DIGIT_INIT(294), \ + _PyLong_DIGIT_INIT(295), \ + _PyLong_DIGIT_INIT(296), \ + _PyLong_DIGIT_INIT(297), \ + _PyLong_DIGIT_INIT(298), \ + _PyLong_DIGIT_INIT(299), \ + _PyLong_DIGIT_INIT(300), \ + _PyLong_DIGIT_INIT(301), \ + _PyLong_DIGIT_INIT(302), \ + _PyLong_DIGIT_INIT(303), \ + _PyLong_DIGIT_INIT(304), \ + _PyLong_DIGIT_INIT(305), \ + _PyLong_DIGIT_INIT(306), \ + _PyLong_DIGIT_INIT(307), \ + _PyLong_DIGIT_INIT(308), \ + _PyLong_DIGIT_INIT(309), \ + _PyLong_DIGIT_INIT(310), \ + _PyLong_DIGIT_INIT(311), \ + _PyLong_DIGIT_INIT(312), \ + _PyLong_DIGIT_INIT(313), \ + _PyLong_DIGIT_INIT(314), \ + _PyLong_DIGIT_INIT(315), \ + _PyLong_DIGIT_INIT(316), \ + _PyLong_DIGIT_INIT(317), \ + _PyLong_DIGIT_INIT(318), \ + _PyLong_DIGIT_INIT(319), \ + _PyLong_DIGIT_INIT(320), \ + _PyLong_DIGIT_INIT(321), \ + _PyLong_DIGIT_INIT(322), \ + _PyLong_DIGIT_INIT(323), \ + _PyLong_DIGIT_INIT(324), \ + _PyLong_DIGIT_INIT(325), \ + _PyLong_DIGIT_INIT(326), \ + _PyLong_DIGIT_INIT(327), \ + _PyLong_DIGIT_INIT(328), \ + _PyLong_DIGIT_INIT(329), \ + _PyLong_DIGIT_INIT(330), \ + _PyLong_DIGIT_INIT(331), \ + _PyLong_DIGIT_INIT(332), \ + _PyLong_DIGIT_INIT(333), \ + _PyLong_DIGIT_INIT(334), \ + _PyLong_DIGIT_INIT(335), \ + _PyLong_DIGIT_INIT(336), \ + _PyLong_DIGIT_INIT(337), \ + _PyLong_DIGIT_INIT(338), \ + _PyLong_DIGIT_INIT(339), \ + _PyLong_DIGIT_INIT(340), \ + _PyLong_DIGIT_INIT(341), \ + _PyLong_DIGIT_INIT(342), \ + _PyLong_DIGIT_INIT(343), \ + _PyLong_DIGIT_INIT(344), \ + _PyLong_DIGIT_INIT(345), \ + _PyLong_DIGIT_INIT(346), \ + _PyLong_DIGIT_INIT(347), \ + _PyLong_DIGIT_INIT(348), \ + _PyLong_DIGIT_INIT(349), \ + _PyLong_DIGIT_INIT(350), \ + _PyLong_DIGIT_INIT(351), \ + _PyLong_DIGIT_INIT(352), \ + _PyLong_DIGIT_INIT(353), \ + _PyLong_DIGIT_INIT(354), \ + _PyLong_DIGIT_INIT(355), \ + _PyLong_DIGIT_INIT(356), \ + _PyLong_DIGIT_INIT(357), \ + _PyLong_DIGIT_INIT(358), \ + _PyLong_DIGIT_INIT(359), \ + _PyLong_DIGIT_INIT(360), \ + _PyLong_DIGIT_INIT(361), \ + _PyLong_DIGIT_INIT(362), \ + _PyLong_DIGIT_INIT(363), \ + _PyLong_DIGIT_INIT(364), \ + _PyLong_DIGIT_INIT(365), \ + _PyLong_DIGIT_INIT(366), \ + _PyLong_DIGIT_INIT(367), \ + _PyLong_DIGIT_INIT(368), \ + _PyLong_DIGIT_INIT(369), \ + _PyLong_DIGIT_INIT(370), \ + _PyLong_DIGIT_INIT(371), \ + _PyLong_DIGIT_INIT(372), \ + _PyLong_DIGIT_INIT(373), \ + _PyLong_DIGIT_INIT(374), \ + _PyLong_DIGIT_INIT(375), \ + _PyLong_DIGIT_INIT(376), \ + _PyLong_DIGIT_INIT(377), \ + _PyLong_DIGIT_INIT(378), \ + _PyLong_DIGIT_INIT(379), \ + _PyLong_DIGIT_INIT(380), \ + _PyLong_DIGIT_INIT(381), \ + _PyLong_DIGIT_INIT(382), \ + _PyLong_DIGIT_INIT(383), \ + _PyLong_DIGIT_INIT(384), \ + _PyLong_DIGIT_INIT(385), \ + _PyLong_DIGIT_INIT(386), \ + _PyLong_DIGIT_INIT(387), \ + _PyLong_DIGIT_INIT(388), \ + _PyLong_DIGIT_INIT(389), \ + _PyLong_DIGIT_INIT(390), \ + _PyLong_DIGIT_INIT(391), \ + _PyLong_DIGIT_INIT(392), \ + _PyLong_DIGIT_INIT(393), \ + _PyLong_DIGIT_INIT(394), \ + _PyLong_DIGIT_INIT(395), \ + _PyLong_DIGIT_INIT(396), \ + _PyLong_DIGIT_INIT(397), \ + _PyLong_DIGIT_INIT(398), \ + _PyLong_DIGIT_INIT(399), \ + _PyLong_DIGIT_INIT(400), \ + _PyLong_DIGIT_INIT(401), \ + _PyLong_DIGIT_INIT(402), \ + _PyLong_DIGIT_INIT(403), \ + _PyLong_DIGIT_INIT(404), \ + _PyLong_DIGIT_INIT(405), \ + _PyLong_DIGIT_INIT(406), \ + _PyLong_DIGIT_INIT(407), \ + _PyLong_DIGIT_INIT(408), \ + _PyLong_DIGIT_INIT(409), \ + _PyLong_DIGIT_INIT(410), \ + _PyLong_DIGIT_INIT(411), \ + _PyLong_DIGIT_INIT(412), \ + _PyLong_DIGIT_INIT(413), \ + _PyLong_DIGIT_INIT(414), \ + _PyLong_DIGIT_INIT(415), \ + _PyLong_DIGIT_INIT(416), \ + _PyLong_DIGIT_INIT(417), \ + _PyLong_DIGIT_INIT(418), \ + _PyLong_DIGIT_INIT(419), \ + _PyLong_DIGIT_INIT(420), \ + _PyLong_DIGIT_INIT(421), \ + _PyLong_DIGIT_INIT(422), \ + _PyLong_DIGIT_INIT(423), \ + _PyLong_DIGIT_INIT(424), \ + _PyLong_DIGIT_INIT(425), \ + _PyLong_DIGIT_INIT(426), \ + _PyLong_DIGIT_INIT(427), \ + _PyLong_DIGIT_INIT(428), \ + _PyLong_DIGIT_INIT(429), \ + _PyLong_DIGIT_INIT(430), \ + _PyLong_DIGIT_INIT(431), \ + _PyLong_DIGIT_INIT(432), \ + _PyLong_DIGIT_INIT(433), \ + _PyLong_DIGIT_INIT(434), \ + _PyLong_DIGIT_INIT(435), \ + _PyLong_DIGIT_INIT(436), \ + _PyLong_DIGIT_INIT(437), \ + _PyLong_DIGIT_INIT(438), \ + _PyLong_DIGIT_INIT(439), \ + _PyLong_DIGIT_INIT(440), \ + _PyLong_DIGIT_INIT(441), \ + _PyLong_DIGIT_INIT(442), \ + _PyLong_DIGIT_INIT(443), \ + _PyLong_DIGIT_INIT(444), \ + _PyLong_DIGIT_INIT(445), \ + _PyLong_DIGIT_INIT(446), \ + _PyLong_DIGIT_INIT(447), \ + _PyLong_DIGIT_INIT(448), \ + _PyLong_DIGIT_INIT(449), \ + _PyLong_DIGIT_INIT(450), \ + _PyLong_DIGIT_INIT(451), \ + _PyLong_DIGIT_INIT(452), \ + _PyLong_DIGIT_INIT(453), \ + _PyLong_DIGIT_INIT(454), \ + _PyLong_DIGIT_INIT(455), \ + _PyLong_DIGIT_INIT(456), \ + _PyLong_DIGIT_INIT(457), \ + _PyLong_DIGIT_INIT(458), \ + _PyLong_DIGIT_INIT(459), \ + _PyLong_DIGIT_INIT(460), \ + _PyLong_DIGIT_INIT(461), \ + _PyLong_DIGIT_INIT(462), \ + _PyLong_DIGIT_INIT(463), \ + _PyLong_DIGIT_INIT(464), \ + _PyLong_DIGIT_INIT(465), \ + _PyLong_DIGIT_INIT(466), \ + _PyLong_DIGIT_INIT(467), \ + _PyLong_DIGIT_INIT(468), \ + _PyLong_DIGIT_INIT(469), \ + _PyLong_DIGIT_INIT(470), \ + _PyLong_DIGIT_INIT(471), \ + _PyLong_DIGIT_INIT(472), \ + _PyLong_DIGIT_INIT(473), \ + _PyLong_DIGIT_INIT(474), \ + _PyLong_DIGIT_INIT(475), \ + _PyLong_DIGIT_INIT(476), \ + _PyLong_DIGIT_INIT(477), \ + _PyLong_DIGIT_INIT(478), \ + _PyLong_DIGIT_INIT(479), \ + _PyLong_DIGIT_INIT(480), \ + _PyLong_DIGIT_INIT(481), \ + _PyLong_DIGIT_INIT(482), \ + _PyLong_DIGIT_INIT(483), \ + _PyLong_DIGIT_INIT(484), \ + _PyLong_DIGIT_INIT(485), \ + _PyLong_DIGIT_INIT(486), \ + _PyLong_DIGIT_INIT(487), \ + _PyLong_DIGIT_INIT(488), \ + _PyLong_DIGIT_INIT(489), \ + _PyLong_DIGIT_INIT(490), \ + _PyLong_DIGIT_INIT(491), \ + _PyLong_DIGIT_INIT(492), \ + _PyLong_DIGIT_INIT(493), \ + _PyLong_DIGIT_INIT(494), \ + _PyLong_DIGIT_INIT(495), \ + _PyLong_DIGIT_INIT(496), \ + _PyLong_DIGIT_INIT(497), \ + _PyLong_DIGIT_INIT(498), \ + _PyLong_DIGIT_INIT(499), \ + _PyLong_DIGIT_INIT(500), \ + _PyLong_DIGIT_INIT(501), \ + _PyLong_DIGIT_INIT(502), \ + _PyLong_DIGIT_INIT(503), \ + _PyLong_DIGIT_INIT(504), \ + _PyLong_DIGIT_INIT(505), \ + _PyLong_DIGIT_INIT(506), \ + _PyLong_DIGIT_INIT(507), \ + _PyLong_DIGIT_INIT(508), \ + _PyLong_DIGIT_INIT(509), \ + _PyLong_DIGIT_INIT(510), \ + _PyLong_DIGIT_INIT(511), \ + _PyLong_DIGIT_INIT(512), \ + _PyLong_DIGIT_INIT(513), \ + _PyLong_DIGIT_INIT(514), \ + _PyLong_DIGIT_INIT(515), \ + _PyLong_DIGIT_INIT(516), \ + _PyLong_DIGIT_INIT(517), \ + _PyLong_DIGIT_INIT(518), \ + _PyLong_DIGIT_INIT(519), \ + _PyLong_DIGIT_INIT(520), \ + _PyLong_DIGIT_INIT(521), \ + _PyLong_DIGIT_INIT(522), \ + _PyLong_DIGIT_INIT(523), \ + _PyLong_DIGIT_INIT(524), \ + _PyLong_DIGIT_INIT(525), \ + _PyLong_DIGIT_INIT(526), \ + _PyLong_DIGIT_INIT(527), \ + _PyLong_DIGIT_INIT(528), \ + _PyLong_DIGIT_INIT(529), \ + _PyLong_DIGIT_INIT(530), \ + _PyLong_DIGIT_INIT(531), \ + _PyLong_DIGIT_INIT(532), \ + _PyLong_DIGIT_INIT(533), \ + _PyLong_DIGIT_INIT(534), \ + _PyLong_DIGIT_INIT(535), \ + _PyLong_DIGIT_INIT(536), \ + _PyLong_DIGIT_INIT(537), \ + _PyLong_DIGIT_INIT(538), \ + _PyLong_DIGIT_INIT(539), \ + _PyLong_DIGIT_INIT(540), \ + _PyLong_DIGIT_INIT(541), \ + _PyLong_DIGIT_INIT(542), \ + _PyLong_DIGIT_INIT(543), \ + _PyLong_DIGIT_INIT(544), \ + _PyLong_DIGIT_INIT(545), \ + _PyLong_DIGIT_INIT(546), \ + _PyLong_DIGIT_INIT(547), \ + _PyLong_DIGIT_INIT(548), \ + _PyLong_DIGIT_INIT(549), \ + _PyLong_DIGIT_INIT(550), \ + _PyLong_DIGIT_INIT(551), \ + _PyLong_DIGIT_INIT(552), \ + _PyLong_DIGIT_INIT(553), \ + _PyLong_DIGIT_INIT(554), \ + _PyLong_DIGIT_INIT(555), \ + _PyLong_DIGIT_INIT(556), \ + _PyLong_DIGIT_INIT(557), \ + _PyLong_DIGIT_INIT(558), \ + _PyLong_DIGIT_INIT(559), \ + _PyLong_DIGIT_INIT(560), \ + _PyLong_DIGIT_INIT(561), \ + _PyLong_DIGIT_INIT(562), \ + _PyLong_DIGIT_INIT(563), \ + _PyLong_DIGIT_INIT(564), \ + _PyLong_DIGIT_INIT(565), \ + _PyLong_DIGIT_INIT(566), \ + _PyLong_DIGIT_INIT(567), \ + _PyLong_DIGIT_INIT(568), \ + _PyLong_DIGIT_INIT(569), \ + _PyLong_DIGIT_INIT(570), \ + _PyLong_DIGIT_INIT(571), \ + _PyLong_DIGIT_INIT(572), \ + _PyLong_DIGIT_INIT(573), \ + _PyLong_DIGIT_INIT(574), \ + _PyLong_DIGIT_INIT(575), \ + _PyLong_DIGIT_INIT(576), \ + _PyLong_DIGIT_INIT(577), \ + _PyLong_DIGIT_INIT(578), \ + _PyLong_DIGIT_INIT(579), \ + _PyLong_DIGIT_INIT(580), \ + _PyLong_DIGIT_INIT(581), \ + _PyLong_DIGIT_INIT(582), \ + _PyLong_DIGIT_INIT(583), \ + _PyLong_DIGIT_INIT(584), \ + _PyLong_DIGIT_INIT(585), \ + _PyLong_DIGIT_INIT(586), \ + _PyLong_DIGIT_INIT(587), \ + _PyLong_DIGIT_INIT(588), \ + _PyLong_DIGIT_INIT(589), \ + _PyLong_DIGIT_INIT(590), \ + _PyLong_DIGIT_INIT(591), \ + _PyLong_DIGIT_INIT(592), \ + _PyLong_DIGIT_INIT(593), \ + _PyLong_DIGIT_INIT(594), \ + _PyLong_DIGIT_INIT(595), \ + _PyLong_DIGIT_INIT(596), \ + _PyLong_DIGIT_INIT(597), \ + _PyLong_DIGIT_INIT(598), \ + _PyLong_DIGIT_INIT(599), \ + _PyLong_DIGIT_INIT(600), \ + _PyLong_DIGIT_INIT(601), \ + _PyLong_DIGIT_INIT(602), \ + _PyLong_DIGIT_INIT(603), \ + _PyLong_DIGIT_INIT(604), \ + _PyLong_DIGIT_INIT(605), \ + _PyLong_DIGIT_INIT(606), \ + _PyLong_DIGIT_INIT(607), \ + _PyLong_DIGIT_INIT(608), \ + _PyLong_DIGIT_INIT(609), \ + _PyLong_DIGIT_INIT(610), \ + _PyLong_DIGIT_INIT(611), \ + _PyLong_DIGIT_INIT(612), \ + _PyLong_DIGIT_INIT(613), \ + _PyLong_DIGIT_INIT(614), \ + _PyLong_DIGIT_INIT(615), \ + _PyLong_DIGIT_INIT(616), \ + _PyLong_DIGIT_INIT(617), \ + _PyLong_DIGIT_INIT(618), \ + _PyLong_DIGIT_INIT(619), \ + _PyLong_DIGIT_INIT(620), \ + _PyLong_DIGIT_INIT(621), \ + _PyLong_DIGIT_INIT(622), \ + _PyLong_DIGIT_INIT(623), \ + _PyLong_DIGIT_INIT(624), \ + _PyLong_DIGIT_INIT(625), \ + _PyLong_DIGIT_INIT(626), \ + _PyLong_DIGIT_INIT(627), \ + _PyLong_DIGIT_INIT(628), \ + _PyLong_DIGIT_INIT(629), \ + _PyLong_DIGIT_INIT(630), \ + _PyLong_DIGIT_INIT(631), \ + _PyLong_DIGIT_INIT(632), \ + _PyLong_DIGIT_INIT(633), \ + _PyLong_DIGIT_INIT(634), \ + _PyLong_DIGIT_INIT(635), \ + _PyLong_DIGIT_INIT(636), \ + _PyLong_DIGIT_INIT(637), \ + _PyLong_DIGIT_INIT(638), \ + _PyLong_DIGIT_INIT(639), \ + _PyLong_DIGIT_INIT(640), \ + _PyLong_DIGIT_INIT(641), \ + _PyLong_DIGIT_INIT(642), \ + _PyLong_DIGIT_INIT(643), \ + _PyLong_DIGIT_INIT(644), \ + _PyLong_DIGIT_INIT(645), \ + _PyLong_DIGIT_INIT(646), \ + _PyLong_DIGIT_INIT(647), \ + _PyLong_DIGIT_INIT(648), \ + _PyLong_DIGIT_INIT(649), \ + _PyLong_DIGIT_INIT(650), \ + _PyLong_DIGIT_INIT(651), \ + _PyLong_DIGIT_INIT(652), \ + _PyLong_DIGIT_INIT(653), \ + _PyLong_DIGIT_INIT(654), \ + _PyLong_DIGIT_INIT(655), \ + _PyLong_DIGIT_INIT(656), \ + _PyLong_DIGIT_INIT(657), \ + _PyLong_DIGIT_INIT(658), \ + _PyLong_DIGIT_INIT(659), \ + _PyLong_DIGIT_INIT(660), \ + _PyLong_DIGIT_INIT(661), \ + _PyLong_DIGIT_INIT(662), \ + _PyLong_DIGIT_INIT(663), \ + _PyLong_DIGIT_INIT(664), \ + _PyLong_DIGIT_INIT(665), \ + _PyLong_DIGIT_INIT(666), \ + _PyLong_DIGIT_INIT(667), \ + _PyLong_DIGIT_INIT(668), \ + _PyLong_DIGIT_INIT(669), \ + _PyLong_DIGIT_INIT(670), \ + _PyLong_DIGIT_INIT(671), \ + _PyLong_DIGIT_INIT(672), \ + _PyLong_DIGIT_INIT(673), \ + _PyLong_DIGIT_INIT(674), \ + _PyLong_DIGIT_INIT(675), \ + _PyLong_DIGIT_INIT(676), \ + _PyLong_DIGIT_INIT(677), \ + _PyLong_DIGIT_INIT(678), \ + _PyLong_DIGIT_INIT(679), \ + _PyLong_DIGIT_INIT(680), \ + _PyLong_DIGIT_INIT(681), \ + _PyLong_DIGIT_INIT(682), \ + _PyLong_DIGIT_INIT(683), \ + _PyLong_DIGIT_INIT(684), \ + _PyLong_DIGIT_INIT(685), \ + _PyLong_DIGIT_INIT(686), \ + _PyLong_DIGIT_INIT(687), \ + _PyLong_DIGIT_INIT(688), \ + _PyLong_DIGIT_INIT(689), \ + _PyLong_DIGIT_INIT(690), \ + _PyLong_DIGIT_INIT(691), \ + _PyLong_DIGIT_INIT(692), \ + _PyLong_DIGIT_INIT(693), \ + _PyLong_DIGIT_INIT(694), \ + _PyLong_DIGIT_INIT(695), \ + _PyLong_DIGIT_INIT(696), \ + _PyLong_DIGIT_INIT(697), \ + _PyLong_DIGIT_INIT(698), \ + _PyLong_DIGIT_INIT(699), \ + _PyLong_DIGIT_INIT(700), \ + _PyLong_DIGIT_INIT(701), \ + _PyLong_DIGIT_INIT(702), \ + _PyLong_DIGIT_INIT(703), \ + _PyLong_DIGIT_INIT(704), \ + _PyLong_DIGIT_INIT(705), \ + _PyLong_DIGIT_INIT(706), \ + _PyLong_DIGIT_INIT(707), \ + _PyLong_DIGIT_INIT(708), \ + _PyLong_DIGIT_INIT(709), \ + _PyLong_DIGIT_INIT(710), \ + _PyLong_DIGIT_INIT(711), \ + _PyLong_DIGIT_INIT(712), \ + _PyLong_DIGIT_INIT(713), \ + _PyLong_DIGIT_INIT(714), \ + _PyLong_DIGIT_INIT(715), \ + _PyLong_DIGIT_INIT(716), \ + _PyLong_DIGIT_INIT(717), \ + _PyLong_DIGIT_INIT(718), \ + _PyLong_DIGIT_INIT(719), \ + _PyLong_DIGIT_INIT(720), \ + _PyLong_DIGIT_INIT(721), \ + _PyLong_DIGIT_INIT(722), \ + _PyLong_DIGIT_INIT(723), \ + _PyLong_DIGIT_INIT(724), \ + _PyLong_DIGIT_INIT(725), \ + _PyLong_DIGIT_INIT(726), \ + _PyLong_DIGIT_INIT(727), \ + _PyLong_DIGIT_INIT(728), \ + _PyLong_DIGIT_INIT(729), \ + _PyLong_DIGIT_INIT(730), \ + _PyLong_DIGIT_INIT(731), \ + _PyLong_DIGIT_INIT(732), \ + _PyLong_DIGIT_INIT(733), \ + _PyLong_DIGIT_INIT(734), \ + _PyLong_DIGIT_INIT(735), \ + _PyLong_DIGIT_INIT(736), \ + _PyLong_DIGIT_INIT(737), \ + _PyLong_DIGIT_INIT(738), \ + _PyLong_DIGIT_INIT(739), \ + _PyLong_DIGIT_INIT(740), \ + _PyLong_DIGIT_INIT(741), \ + _PyLong_DIGIT_INIT(742), \ + _PyLong_DIGIT_INIT(743), \ + _PyLong_DIGIT_INIT(744), \ + _PyLong_DIGIT_INIT(745), \ + _PyLong_DIGIT_INIT(746), \ + _PyLong_DIGIT_INIT(747), \ + _PyLong_DIGIT_INIT(748), \ + _PyLong_DIGIT_INIT(749), \ + _PyLong_DIGIT_INIT(750), \ + _PyLong_DIGIT_INIT(751), \ + _PyLong_DIGIT_INIT(752), \ + _PyLong_DIGIT_INIT(753), \ + _PyLong_DIGIT_INIT(754), \ + _PyLong_DIGIT_INIT(755), \ + _PyLong_DIGIT_INIT(756), \ + _PyLong_DIGIT_INIT(757), \ + _PyLong_DIGIT_INIT(758), \ + _PyLong_DIGIT_INIT(759), \ + _PyLong_DIGIT_INIT(760), \ + _PyLong_DIGIT_INIT(761), \ + _PyLong_DIGIT_INIT(762), \ + _PyLong_DIGIT_INIT(763), \ + _PyLong_DIGIT_INIT(764), \ + _PyLong_DIGIT_INIT(765), \ + _PyLong_DIGIT_INIT(766), \ + _PyLong_DIGIT_INIT(767), \ + _PyLong_DIGIT_INIT(768), \ + _PyLong_DIGIT_INIT(769), \ + _PyLong_DIGIT_INIT(770), \ + _PyLong_DIGIT_INIT(771), \ + _PyLong_DIGIT_INIT(772), \ + _PyLong_DIGIT_INIT(773), \ + _PyLong_DIGIT_INIT(774), \ + _PyLong_DIGIT_INIT(775), \ + _PyLong_DIGIT_INIT(776), \ + _PyLong_DIGIT_INIT(777), \ + _PyLong_DIGIT_INIT(778), \ + _PyLong_DIGIT_INIT(779), \ + _PyLong_DIGIT_INIT(780), \ + _PyLong_DIGIT_INIT(781), \ + _PyLong_DIGIT_INIT(782), \ + _PyLong_DIGIT_INIT(783), \ + _PyLong_DIGIT_INIT(784), \ + _PyLong_DIGIT_INIT(785), \ + _PyLong_DIGIT_INIT(786), \ + _PyLong_DIGIT_INIT(787), \ + _PyLong_DIGIT_INIT(788), \ + _PyLong_DIGIT_INIT(789), \ + _PyLong_DIGIT_INIT(790), \ + _PyLong_DIGIT_INIT(791), \ + _PyLong_DIGIT_INIT(792), \ + _PyLong_DIGIT_INIT(793), \ + _PyLong_DIGIT_INIT(794), \ + _PyLong_DIGIT_INIT(795), \ + _PyLong_DIGIT_INIT(796), \ + _PyLong_DIGIT_INIT(797), \ + _PyLong_DIGIT_INIT(798), \ + _PyLong_DIGIT_INIT(799), \ + _PyLong_DIGIT_INIT(800), \ + _PyLong_DIGIT_INIT(801), \ + _PyLong_DIGIT_INIT(802), \ + _PyLong_DIGIT_INIT(803), \ + _PyLong_DIGIT_INIT(804), \ + _PyLong_DIGIT_INIT(805), \ + _PyLong_DIGIT_INIT(806), \ + _PyLong_DIGIT_INIT(807), \ + _PyLong_DIGIT_INIT(808), \ + _PyLong_DIGIT_INIT(809), \ + _PyLong_DIGIT_INIT(810), \ + _PyLong_DIGIT_INIT(811), \ + _PyLong_DIGIT_INIT(812), \ + _PyLong_DIGIT_INIT(813), \ + _PyLong_DIGIT_INIT(814), \ + _PyLong_DIGIT_INIT(815), \ + _PyLong_DIGIT_INIT(816), \ + _PyLong_DIGIT_INIT(817), \ + _PyLong_DIGIT_INIT(818), \ + _PyLong_DIGIT_INIT(819), \ + _PyLong_DIGIT_INIT(820), \ + _PyLong_DIGIT_INIT(821), \ + _PyLong_DIGIT_INIT(822), \ + _PyLong_DIGIT_INIT(823), \ + _PyLong_DIGIT_INIT(824), \ + _PyLong_DIGIT_INIT(825), \ + _PyLong_DIGIT_INIT(826), \ + _PyLong_DIGIT_INIT(827), \ + _PyLong_DIGIT_INIT(828), \ + _PyLong_DIGIT_INIT(829), \ + _PyLong_DIGIT_INIT(830), \ + _PyLong_DIGIT_INIT(831), \ + _PyLong_DIGIT_INIT(832), \ + _PyLong_DIGIT_INIT(833), \ + _PyLong_DIGIT_INIT(834), \ + _PyLong_DIGIT_INIT(835), \ + _PyLong_DIGIT_INIT(836), \ + _PyLong_DIGIT_INIT(837), \ + _PyLong_DIGIT_INIT(838), \ + _PyLong_DIGIT_INIT(839), \ + _PyLong_DIGIT_INIT(840), \ + _PyLong_DIGIT_INIT(841), \ + _PyLong_DIGIT_INIT(842), \ + _PyLong_DIGIT_INIT(843), \ + _PyLong_DIGIT_INIT(844), \ + _PyLong_DIGIT_INIT(845), \ + _PyLong_DIGIT_INIT(846), \ + _PyLong_DIGIT_INIT(847), \ + _PyLong_DIGIT_INIT(848), \ + _PyLong_DIGIT_INIT(849), \ + _PyLong_DIGIT_INIT(850), \ + _PyLong_DIGIT_INIT(851), \ + _PyLong_DIGIT_INIT(852), \ + _PyLong_DIGIT_INIT(853), \ + _PyLong_DIGIT_INIT(854), \ + _PyLong_DIGIT_INIT(855), \ + _PyLong_DIGIT_INIT(856), \ + _PyLong_DIGIT_INIT(857), \ + _PyLong_DIGIT_INIT(858), \ + _PyLong_DIGIT_INIT(859), \ + _PyLong_DIGIT_INIT(860), \ + _PyLong_DIGIT_INIT(861), \ + _PyLong_DIGIT_INIT(862), \ + _PyLong_DIGIT_INIT(863), \ + _PyLong_DIGIT_INIT(864), \ + _PyLong_DIGIT_INIT(865), \ + _PyLong_DIGIT_INIT(866), \ + _PyLong_DIGIT_INIT(867), \ + _PyLong_DIGIT_INIT(868), \ + _PyLong_DIGIT_INIT(869), \ + _PyLong_DIGIT_INIT(870), \ + _PyLong_DIGIT_INIT(871), \ + _PyLong_DIGIT_INIT(872), \ + _PyLong_DIGIT_INIT(873), \ + _PyLong_DIGIT_INIT(874), \ + _PyLong_DIGIT_INIT(875), \ + _PyLong_DIGIT_INIT(876), \ + _PyLong_DIGIT_INIT(877), \ + _PyLong_DIGIT_INIT(878), \ + _PyLong_DIGIT_INIT(879), \ + _PyLong_DIGIT_INIT(880), \ + _PyLong_DIGIT_INIT(881), \ + _PyLong_DIGIT_INIT(882), \ + _PyLong_DIGIT_INIT(883), \ + _PyLong_DIGIT_INIT(884), \ + _PyLong_DIGIT_INIT(885), \ + _PyLong_DIGIT_INIT(886), \ + _PyLong_DIGIT_INIT(887), \ + _PyLong_DIGIT_INIT(888), \ + _PyLong_DIGIT_INIT(889), \ + _PyLong_DIGIT_INIT(890), \ + _PyLong_DIGIT_INIT(891), \ + _PyLong_DIGIT_INIT(892), \ + _PyLong_DIGIT_INIT(893), \ + _PyLong_DIGIT_INIT(894), \ + _PyLong_DIGIT_INIT(895), \ + _PyLong_DIGIT_INIT(896), \ + _PyLong_DIGIT_INIT(897), \ + _PyLong_DIGIT_INIT(898), \ + _PyLong_DIGIT_INIT(899), \ + _PyLong_DIGIT_INIT(900), \ + _PyLong_DIGIT_INIT(901), \ + _PyLong_DIGIT_INIT(902), \ + _PyLong_DIGIT_INIT(903), \ + _PyLong_DIGIT_INIT(904), \ + _PyLong_DIGIT_INIT(905), \ + _PyLong_DIGIT_INIT(906), \ + _PyLong_DIGIT_INIT(907), \ + _PyLong_DIGIT_INIT(908), \ + _PyLong_DIGIT_INIT(909), \ + _PyLong_DIGIT_INIT(910), \ + _PyLong_DIGIT_INIT(911), \ + _PyLong_DIGIT_INIT(912), \ + _PyLong_DIGIT_INIT(913), \ + _PyLong_DIGIT_INIT(914), \ + _PyLong_DIGIT_INIT(915), \ + _PyLong_DIGIT_INIT(916), \ + _PyLong_DIGIT_INIT(917), \ + _PyLong_DIGIT_INIT(918), \ + _PyLong_DIGIT_INIT(919), \ + _PyLong_DIGIT_INIT(920), \ + _PyLong_DIGIT_INIT(921), \ + _PyLong_DIGIT_INIT(922), \ + _PyLong_DIGIT_INIT(923), \ + _PyLong_DIGIT_INIT(924), \ + _PyLong_DIGIT_INIT(925), \ + _PyLong_DIGIT_INIT(926), \ + _PyLong_DIGIT_INIT(927), \ + _PyLong_DIGIT_INIT(928), \ + _PyLong_DIGIT_INIT(929), \ + _PyLong_DIGIT_INIT(930), \ + _PyLong_DIGIT_INIT(931), \ + _PyLong_DIGIT_INIT(932), \ + _PyLong_DIGIT_INIT(933), \ + _PyLong_DIGIT_INIT(934), \ + _PyLong_DIGIT_INIT(935), \ + _PyLong_DIGIT_INIT(936), \ + _PyLong_DIGIT_INIT(937), \ + _PyLong_DIGIT_INIT(938), \ + _PyLong_DIGIT_INIT(939), \ + _PyLong_DIGIT_INIT(940), \ + _PyLong_DIGIT_INIT(941), \ + _PyLong_DIGIT_INIT(942), \ + _PyLong_DIGIT_INIT(943), \ + _PyLong_DIGIT_INIT(944), \ + _PyLong_DIGIT_INIT(945), \ + _PyLong_DIGIT_INIT(946), \ + _PyLong_DIGIT_INIT(947), \ + _PyLong_DIGIT_INIT(948), \ + _PyLong_DIGIT_INIT(949), \ + _PyLong_DIGIT_INIT(950), \ + _PyLong_DIGIT_INIT(951), \ + _PyLong_DIGIT_INIT(952), \ + _PyLong_DIGIT_INIT(953), \ + _PyLong_DIGIT_INIT(954), \ + _PyLong_DIGIT_INIT(955), \ + _PyLong_DIGIT_INIT(956), \ + _PyLong_DIGIT_INIT(957), \ + _PyLong_DIGIT_INIT(958), \ + _PyLong_DIGIT_INIT(959), \ + _PyLong_DIGIT_INIT(960), \ + _PyLong_DIGIT_INIT(961), \ + _PyLong_DIGIT_INIT(962), \ + _PyLong_DIGIT_INIT(963), \ + _PyLong_DIGIT_INIT(964), \ + _PyLong_DIGIT_INIT(965), \ + _PyLong_DIGIT_INIT(966), \ + _PyLong_DIGIT_INIT(967), \ + _PyLong_DIGIT_INIT(968), \ + _PyLong_DIGIT_INIT(969), \ + _PyLong_DIGIT_INIT(970), \ + _PyLong_DIGIT_INIT(971), \ + _PyLong_DIGIT_INIT(972), \ + _PyLong_DIGIT_INIT(973), \ + _PyLong_DIGIT_INIT(974), \ + _PyLong_DIGIT_INIT(975), \ + _PyLong_DIGIT_INIT(976), \ + _PyLong_DIGIT_INIT(977), \ + _PyLong_DIGIT_INIT(978), \ + _PyLong_DIGIT_INIT(979), \ + _PyLong_DIGIT_INIT(980), \ + _PyLong_DIGIT_INIT(981), \ + _PyLong_DIGIT_INIT(982), \ + _PyLong_DIGIT_INIT(983), \ + _PyLong_DIGIT_INIT(984), \ + _PyLong_DIGIT_INIT(985), \ + _PyLong_DIGIT_INIT(986), \ + _PyLong_DIGIT_INIT(987), \ + _PyLong_DIGIT_INIT(988), \ + _PyLong_DIGIT_INIT(989), \ + _PyLong_DIGIT_INIT(990), \ + _PyLong_DIGIT_INIT(991), \ + _PyLong_DIGIT_INIT(992), \ + _PyLong_DIGIT_INIT(993), \ + _PyLong_DIGIT_INIT(994), \ + _PyLong_DIGIT_INIT(995), \ + _PyLong_DIGIT_INIT(996), \ + _PyLong_DIGIT_INIT(997), \ + _PyLong_DIGIT_INIT(998), \ + _PyLong_DIGIT_INIT(999), \ + _PyLong_DIGIT_INIT(1000), \ + _PyLong_DIGIT_INIT(1001), \ + _PyLong_DIGIT_INIT(1002), \ + _PyLong_DIGIT_INIT(1003), \ + _PyLong_DIGIT_INIT(1004), \ + _PyLong_DIGIT_INIT(1005), \ + _PyLong_DIGIT_INIT(1006), \ + _PyLong_DIGIT_INIT(1007), \ + _PyLong_DIGIT_INIT(1008), \ + _PyLong_DIGIT_INIT(1009), \ + _PyLong_DIGIT_INIT(1010), \ + _PyLong_DIGIT_INIT(1011), \ + _PyLong_DIGIT_INIT(1012), \ + _PyLong_DIGIT_INIT(1013), \ + _PyLong_DIGIT_INIT(1014), \ + _PyLong_DIGIT_INIT(1015), \ + _PyLong_DIGIT_INIT(1016), \ + _PyLong_DIGIT_INIT(1017), \ + _PyLong_DIGIT_INIT(1018), \ + _PyLong_DIGIT_INIT(1019), \ + _PyLong_DIGIT_INIT(1020), \ + _PyLong_DIGIT_INIT(1021), \ + _PyLong_DIGIT_INIT(1022), \ + _PyLong_DIGIT_INIT(1023), \ + _PyLong_DIGIT_INIT(1024), \ } #define _Py_bytes_characters_INIT { \ @@ -553,10 +1321,12 @@ extern "C" { INIT_STR(dot_locals, "."), \ INIT_STR(empty, ""), \ INIT_STR(format, ".format"), \ + INIT_STR(gc, ""), \ INIT_STR(generic_base, ".generic_base"), \ INIT_STR(json_decoder, "json.decoder"), \ INIT_STR(kwdefaults, ".kwdefaults"), \ INIT_STR(list_err, "list index out of range"), \ + INIT_STR(native, ""), \ INIT_STR(str_replace_inf, "1e309"), \ INIT_STR(type_params, ".type_params"), \ INIT_STR(utf_8, "utf-8"), \ @@ -837,6 +1607,7 @@ extern "C" { INIT_ID(c_parameter_type), \ INIT_ID(c_return), \ INIT_ID(c_stack), \ + INIT_ID(cache_frames), \ INIT_ID(cached_datetime_module), \ INIT_ID(cached_statements), \ INIT_ID(cadata), \ @@ -931,6 +1702,7 @@ extern "C" { INIT_ID(eager_start), \ INIT_ID(effective_ids), \ INIT_ID(element_factory), \ + INIT_ID(emptyerror), \ INIT_ID(encode), \ INIT_ID(encoding), \ INIT_ID(end), \ @@ -956,6 +1728,7 @@ extern "C" { INIT_ID(extra_tokens), \ INIT_ID(facility), \ INIT_ID(factory), \ + INIT_ID(fallback), \ INIT_ID(false), \ INIT_ID(family), \ INIT_ID(fanout), \ @@ -982,13 +1755,16 @@ extern "C" { INIT_ID(format), \ INIT_ID(format_spec), \ INIT_ID(frame_buffer), \ + INIT_ID(free_threaded), \ INIT_ID(from_param), \ INIT_ID(fromlist), \ INIT_ID(fromtimestamp), \ INIT_ID(fromutc), \ INIT_ID(fset), \ + INIT_ID(fullerror), \ INIT_ID(func), \ INIT_ID(future), \ + INIT_ID(gc), \ INIT_ID(generation), \ INIT_ID(get), \ INIT_ID(get_debug), \ @@ -1077,6 +1853,7 @@ extern "C" { INIT_ID(last_value), \ INIT_ID(latin1), \ INIT_ID(leaf_size), \ + INIT_ID(legacy), \ INIT_ID(len), \ INIT_ID(length), \ INIT_ID(level), \ @@ -1092,12 +1869,14 @@ extern "C" { INIT_ID(loop), \ INIT_ID(manual_reset), \ INIT_ID(mapping), \ + INIT_ID(mask), \ INIT_ID(match), \ INIT_ID(max_length), \ INIT_ID(maxdigits), \ INIT_ID(maxevents), \ INIT_ID(maxlen), \ INIT_ID(maxmem), \ + INIT_ID(maxsize), \ INIT_ID(maxsplit), \ INIT_ID(maxvalue), \ INIT_ID(memLevel), \ @@ -1129,6 +1908,7 @@ extern "C" { INIT_ID(name_from), \ INIT_ID(namespace_separator), \ INIT_ID(namespaces), \ + INIT_ID(native), \ INIT_ID(ndigits), \ INIT_ID(nested), \ INIT_ID(new_file_name), \ @@ -1155,6 +1935,7 @@ extern "C" { INIT_ID(only_keys), \ INIT_ID(oparg), \ INIT_ID(opcode), \ + INIT_ID(opcodes), \ INIT_ID(open), \ INIT_ID(opener), \ INIT_ID(operation), \ @@ -1180,6 +1961,7 @@ extern "C" { INIT_ID(person), \ INIT_ID(pi_factory), \ INIT_ID(pid), \ + INIT_ID(pointer_bits), \ INIT_ID(policy), \ INIT_ID(pos), \ INIT_ID(pos1), \ @@ -1195,7 +1977,10 @@ extern "C" { INIT_ID(protocol), \ INIT_ID(ps1), \ INIT_ID(ps2), \ + INIT_ID(qid), \ + INIT_ID(qualname), \ INIT_ID(query), \ + INIT_ID(queuetype), \ INIT_ID(quotetabs), \ INIT_ID(raw), \ INIT_ID(read), \ @@ -1207,6 +1992,7 @@ extern "C" { INIT_ID(readline), \ INIT_ID(readonly), \ INIT_ID(real), \ + INIT_ID(recursive), \ INIT_ID(reducer_override), \ INIT_ID(registry), \ INIT_ID(rel_tol), \ @@ -1249,12 +2035,14 @@ extern "C" { INIT_ID(setstate), \ INIT_ID(shape), \ INIT_ID(shared), \ + INIT_ID(short), \ INIT_ID(show_cmd), \ INIT_ID(signed), \ INIT_ID(signum), \ INIT_ID(size), \ INIT_ID(sizehint), \ INIT_ID(skip_file_prefixes), \ + INIT_ID(skip_non_matching_threads), \ INIT_ID(sleep), \ INIT_ID(sock), \ INIT_ID(sort), \ @@ -1266,6 +2054,7 @@ extern "C" { INIT_ID(stacklevel), \ INIT_ID(start), \ INIT_ID(statement), \ + INIT_ID(stats), \ INIT_ID(status), \ INIT_ID(stderr), \ INIT_ID(stdin), \ @@ -1283,6 +2072,7 @@ extern "C" { INIT_ID(symmetric_difference_update), \ INIT_ID(tabsize), \ INIT_ID(tag), \ + INIT_ID(take_bytes), \ INIT_ID(target), \ INIT_ID(target_is_directory), \ INIT_ID(task), \ @@ -1320,6 +2110,7 @@ extern "C" { INIT_ID(tzinfo), \ INIT_ID(tzname), \ INIT_ID(uid), \ + INIT_ID(unboundop), \ INIT_ID(unlink), \ INIT_ID(unraisablehook), \ INIT_ID(updates), \ diff --git a/Include/internal/pycore_runtime_structs.h b/Include/internal/pycore_runtime_structs.h index 12164c7fdd9..995f49e78dc 100644 --- a/Include/internal/pycore_runtime_structs.h +++ b/Include/internal/pycore_runtime_structs.h @@ -106,7 +106,7 @@ struct _Py_cached_objects { }; // These would be in pycore_long.h if it weren't for an include cycle. -#define _PY_NSMALLPOSINTS 257 +#define _PY_NSMALLPOSINTS 1025 #define _PY_NSMALLNEGINTS 5 #include "pycore_global_strings.h" // struct _Py_global_strings @@ -276,12 +276,6 @@ struct pyruntimestate { struct _types_runtime_state types; struct _Py_time_runtime_state time; -#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) - // Used in "Python/emscripten_trampoline.c" to choose between type - // reflection trampoline and EM_JS trampoline. - int (*emscripten_count_args_function)(PyCFunctionWithKeywords func); -#endif - /* All the objects that are shared by the runtime's interpreters. */ struct _Py_cached_objects cached_objects; struct _Py_static_objects static_objects; diff --git a/Include/internal/pycore_semaphore.h b/Include/internal/pycore_semaphore.h index 26953838460..66b4939dcac 100644 --- a/Include/internal/pycore_semaphore.h +++ b/Include/internal/pycore_semaphore.h @@ -46,10 +46,8 @@ typedef struct _PySemaphore { } _PySemaphore; // Puts the current thread to sleep until _PySemaphore_Wakeup() is called. -// If `detach` is true, then the thread will detach/release the GIL while -// sleeping. PyAPI_FUNC(int) -_PySemaphore_Wait(_PySemaphore *sema, PyTime_t timeout_ns, int detach); +_PySemaphore_Wait(_PySemaphore *sema, PyTime_t timeout_ns); // Wakes up a single thread waiting on sema. Note that _PySemaphore_Wakeup() // can be called before _PySemaphore_Wait(). diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index c4e8f10fe05..69d667b4be4 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -50,27 +50,62 @@ extern "C" { CPython refcounting operations on it! */ +#define Py_INT_TAG 3 +#define Py_TAG_INVALID 2 +#define Py_TAG_REFCNT 1 +#define Py_TAG_BITS 3 + +#define Py_TAGGED_SHIFT 2 #if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -#define Py_TAG_BITS 0 - PyAPI_FUNC(PyObject *) _Py_stackref_get_object(_PyStackRef ref); PyAPI_FUNC(PyObject *) _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber); -PyAPI_FUNC(_PyStackRef) _Py_stackref_create(PyObject *obj, const char *filename, int linenumber); +PyAPI_FUNC(_PyStackRef) _Py_stackref_create(PyObject *obj, uint16_t flags, const char *filename, int linenumber); PyAPI_FUNC(void) _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber); +PyAPI_FUNC(_PyStackRef) _Py_stackref_get_borrowed_from(_PyStackRef ref, const char *filename, int linenumber); +PyAPI_FUNC(void) _Py_stackref_set_borrowed_from(_PyStackRef ref, _PyStackRef borrowed_from, const char *filename, int linenumber); extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref); static const _PyStackRef PyStackRef_NULL = { .index = 0 }; -static const _PyStackRef PyStackRef_ERROR = { .index = 2 }; +static const _PyStackRef PyStackRef_ERROR = { .index = (1 << Py_TAGGED_SHIFT) }; -// Use the first 3 even numbers for None, True and False. -// Odd numbers are reserved for (tagged) integers -#define PyStackRef_None ((_PyStackRef){ .index = 4 } ) -#define PyStackRef_False ((_PyStackRef){ .index = 6 }) -#define PyStackRef_True ((_PyStackRef){ .index = 8 }) +#define PyStackRef_None ((_PyStackRef){ .index = (2 << Py_TAGGED_SHIFT) } ) +#define PyStackRef_False ((_PyStackRef){ .index = (3 << Py_TAGGED_SHIFT) }) +#define PyStackRef_True ((_PyStackRef){ .index = (4 << Py_TAGGED_SHIFT) }) -#define INITIAL_STACKREF_INDEX 10 +#define INITIAL_STACKREF_INDEX (5 << Py_TAGGED_SHIFT) + +#define PyStackRef_ZERO_BITS PyStackRef_NULL + +static inline _PyStackRef +PyStackRef_Wrap(void *ptr) +{ + assert(ptr != NULL); +#ifdef Py_DEBUG + assert(((uint64_t)ptr & Py_TAG_BITS) == 0); + return (_PyStackRef){ .index = ((uint64_t)ptr) | Py_TAG_INVALID }; +#else + return (_PyStackRef){ .index = (uint64_t)ptr }; +#endif +} + +static inline void * +PyStackRef_Unwrap(_PyStackRef ref) +{ +#ifdef Py_DEBUG + assert ((ref.index & Py_TAG_BITS) == Py_TAG_INVALID); + return (void *)(ref.index & ~Py_TAG_BITS); +#else + return (void *)(ref.index); +#endif +} + +static inline int +PyStackRef_RefcountOnObject(_PyStackRef ref) +{ + return (ref.index & Py_TAG_REFCNT) == 0; +} static inline int PyStackRef_IsNull(_PyStackRef ref) @@ -81,7 +116,13 @@ PyStackRef_IsNull(_PyStackRef ref) static inline bool PyStackRef_IsError(_PyStackRef ref) { - return ref.index == 2; + return ref.index == (1 << Py_TAGGED_SHIFT); +} + +static inline bool +PyStackRef_IsMalformed(_PyStackRef ref) +{ + return (ref.index & Py_TAG_BITS) == Py_TAG_INVALID; } static inline bool @@ -112,7 +153,7 @@ PyStackRef_IsNone(_PyStackRef ref) static inline bool PyStackRef_IsTaggedInt(_PyStackRef ref) { - return (ref.index & 1) == 1; + return (ref.index & Py_TAG_BITS) == Py_INT_TAG; } static inline PyObject * @@ -123,50 +164,68 @@ _PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumb _Py_stackref_record_borrow(ref, filename, linenumber); return _Py_stackref_get_object(ref); } - #define PyStackRef_AsPyObjectBorrow(REF) _PyStackRef_AsPyObjectBorrow((REF), __FILE__, __LINE__) static inline PyObject * _PyStackRef_AsPyObjectSteal(_PyStackRef ref, const char *filename, int linenumber) { - return _Py_stackref_close(ref, filename, linenumber); + PyObject *obj = _Py_stackref_close(ref, filename, linenumber); + if (PyStackRef_RefcountOnObject(ref)) { + return obj; + } + return Py_NewRef(obj); } #define PyStackRef_AsPyObjectSteal(REF) _PyStackRef_AsPyObjectSteal((REF), __FILE__, __LINE__) static inline _PyStackRef _PyStackRef_FromPyObjectNew(PyObject *obj, const char *filename, int linenumber) { - Py_INCREF(obj); - return _Py_stackref_create(obj, filename, linenumber); + assert(obj != NULL); + uint16_t flags = 0; + if (!_Py_IsImmortal(obj)) { + _Py_INCREF_MORTAL(obj); + } else { + flags = Py_TAG_REFCNT; + } + return _Py_stackref_create(obj, flags, filename, linenumber); } #define PyStackRef_FromPyObjectNew(obj) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj), __FILE__, __LINE__) static inline _PyStackRef _PyStackRef_FromPyObjectSteal(PyObject *obj, const char *filename, int linenumber) { - return _Py_stackref_create(obj, filename, linenumber); + assert(obj != NULL); + uint16_t flags = 0; + if (_Py_IsImmortal(obj)) { + flags = Py_TAG_REFCNT; + } + return _Py_stackref_create(obj, flags, filename, linenumber); } #define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj), __FILE__, __LINE__) static inline _PyStackRef _PyStackRef_FromPyObjectBorrow(PyObject *obj, const char *filename, int linenumber) { - return _Py_stackref_create(obj, filename, linenumber); + return _Py_stackref_create(obj, Py_TAG_REFCNT, filename, linenumber); } #define PyStackRef_FromPyObjectBorrow(obj) _PyStackRef_FromPyObjectBorrow(_PyObject_CAST(obj), __FILE__, __LINE__) static inline void _PyStackRef_CLOSE(_PyStackRef ref, const char *filename, int linenumber) { + assert(!PyStackRef_IsError(ref)); + assert(!PyStackRef_IsNull(ref)); if (PyStackRef_IsTaggedInt(ref)) { return; } PyObject *obj = _Py_stackref_close(ref, filename, linenumber); - Py_DECREF(obj); + assert(Py_REFCNT(obj) > 0); + if (PyStackRef_RefcountOnObject(ref)) { + Py_DECREF(obj); + } } #define PyStackRef_CLOSE(REF) _PyStackRef_CLOSE((REF), __FILE__, __LINE__) - static inline void _PyStackRef_XCLOSE(_PyStackRef ref, const char *filename, int linenumber) { @@ -182,31 +241,56 @@ static inline _PyStackRef _PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber) { assert(!PyStackRef_IsError(ref)); + assert(!PyStackRef_IsNull(ref)); if (PyStackRef_IsTaggedInt(ref)) { return ref; } - else { - PyObject *obj = _Py_stackref_get_object(ref); + PyObject *obj = _Py_stackref_get_object(ref); + uint16_t flags = 0; + if (PyStackRef_RefcountOnObject(ref)) { Py_INCREF(obj); - return _Py_stackref_create(obj, filename, linenumber); + } else { + flags = Py_TAG_REFCNT; } + _PyStackRef new_ref = _Py_stackref_create(obj, flags, filename, linenumber); + if (flags == Py_TAG_REFCNT && !_Py_IsImmortal(obj)) { + _PyStackRef borrowed_from = _Py_stackref_get_borrowed_from(ref, filename, linenumber); + _Py_stackref_set_borrowed_from(new_ref, borrowed_from, filename, linenumber); + } + return new_ref; } #define PyStackRef_DUP(REF) _PyStackRef_DUP(REF, __FILE__, __LINE__) -extern void _PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct, const char *filename, int linenumber); +static inline void +_PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct, const char *filename, int linenumber) +{ + assert(!PyStackRef_IsError(ref)); + assert(!PyStackRef_IsNull(ref)); + assert(!PyStackRef_IsTaggedInt(ref)); + PyObject *obj = _Py_stackref_close(ref, filename, linenumber); + assert(Py_REFCNT(obj) > 0); + if (PyStackRef_RefcountOnObject(ref)) { + _Py_DECREF_SPECIALIZED(obj, destruct); + } +} #define PyStackRef_CLOSE_SPECIALIZED(REF, DESTRUCT) _PyStackRef_CLOSE_SPECIALIZED(REF, DESTRUCT, __FILE__, __LINE__) static inline _PyStackRef -PyStackRef_MakeHeapSafe(_PyStackRef ref) +_PyStackRef_Borrow(_PyStackRef ref, const char *filename, int linenumber) { - return ref; -} - -static inline _PyStackRef -PyStackRef_Borrow(_PyStackRef ref) -{ - return PyStackRef_DUP(ref); + assert(!PyStackRef_IsError(ref)); + assert(!PyStackRef_IsNull(ref)); + if (PyStackRef_IsTaggedInt(ref)) { + return ref; + } + PyObject *obj = _Py_stackref_get_object(ref); + _PyStackRef new_ref = _Py_stackref_create(obj, Py_TAG_REFCNT, filename, linenumber); + if (!_Py_IsImmortal(obj)) { + _Py_stackref_set_borrowed_from(new_ref, ref, filename, linenumber); + } + return new_ref; } +#define PyStackRef_Borrow(REF) _PyStackRef_Borrow((REF), __FILE__, __LINE__) #define PyStackRef_CLEAR(REF) \ do { \ @@ -219,28 +303,56 @@ PyStackRef_Borrow(_PyStackRef ref) static inline _PyStackRef _PyStackRef_FromPyObjectStealMortal(PyObject *obj, const char *filename, int linenumber) { + assert(obj != NULL); assert(!_Py_IsImmortal(obj)); - return _Py_stackref_create(obj, filename, linenumber); + return _Py_stackref_create(obj, 0, filename, linenumber); } #define PyStackRef_FromPyObjectStealMortal(obj) _PyStackRef_FromPyObjectStealMortal(_PyObject_CAST(obj), __FILE__, __LINE__) static inline bool PyStackRef_IsHeapSafe(_PyStackRef ref) { - return true; + if ((ref.index & Py_TAG_BITS) != Py_TAG_REFCNT || PyStackRef_IsNull(ref)) { + // Tagged ints and ERROR are included. + return true; + } + + PyObject *obj = _Py_stackref_get_object(ref); + return _Py_IsImmortal(obj); } +static inline _PyStackRef +_PyStackRef_MakeHeapSafe(_PyStackRef ref, const char *filename, int linenumber) +{ + // Special references that can't be closed. + if (ref.index < INITIAL_STACKREF_INDEX) { + return ref; + } + + bool heap_safe = PyStackRef_IsHeapSafe(ref); + PyObject *obj = _Py_stackref_close(ref, filename, linenumber); + uint16_t flags = 0; + if (heap_safe) { + // Close old ref and create a new one with the same flags. + // This is necessary for correct borrow checking. + flags = ref.index & Py_TAG_BITS; + } else { + Py_INCREF(obj); + } + return _Py_stackref_create(obj, flags, filename, linenumber); +} +#define PyStackRef_MakeHeapSafe(REF) _PyStackRef_MakeHeapSafe(REF, __FILE__, __LINE__) + static inline _PyStackRef _PyStackRef_FromPyObjectNewMortal(PyObject *obj, const char *filename, int linenumber) { + assert(obj != NULL); assert(!_Py_IsStaticImmortal(obj)); Py_INCREF(obj); - return _Py_stackref_create(obj, filename, linenumber); + return _Py_stackref_create(obj, 0, filename, linenumber); } #define PyStackRef_FromPyObjectNewMortal(obj) _PyStackRef_FromPyObjectNewMortal(_PyObject_CAST(obj), __FILE__, __LINE__) -#define PyStackRef_RefcountOnObject(REF) 1 - extern int PyStackRef_Is(_PyStackRef a, _PyStackRef b); extern bool PyStackRef_IsTaggedInt(_PyStackRef ref); @@ -257,13 +369,12 @@ PyStackRef_IsNullOrInt(_PyStackRef ref); #else -#define Py_INT_TAG 3 -#define Py_TAG_INVALID 2 -#define Py_TAG_REFCNT 1 -#define Py_TAG_BITS 3 - static const _PyStackRef PyStackRef_ERROR = { .bits = Py_TAG_INVALID }; +/* For use in the JIT to clear an unused value. + * PyStackRef_ZERO_BITS has no meaning and should not be used other than by the JIT. */ +static const _PyStackRef PyStackRef_ZERO_BITS = { .bits = 0 }; + /* Wrap a pointer in a stack ref. * The resulting stack reference is not safe and should only be used * in the interpreter to pass values from one uop to another. @@ -273,6 +384,7 @@ PyStackRef_Wrap(void *ptr) { assert(ptr != NULL); #ifdef Py_DEBUG + assert(((uintptr_t)ptr & Py_TAG_BITS) == 0); return (_PyStackRef){ .bits = ((uintptr_t)ptr) | Py_TAG_INVALID }; #else return (_PyStackRef){ .bits = (uintptr_t)ptr }; @@ -296,6 +408,12 @@ PyStackRef_IsError(_PyStackRef ref) return ref.bits == Py_TAG_INVALID; } +static inline bool +PyStackRef_IsMalformed(_PyStackRef ref) +{ + return (ref.bits & Py_TAG_BITS) == Py_TAG_INVALID; +} + static inline bool PyStackRef_IsValid(_PyStackRef ref) { @@ -312,8 +430,9 @@ PyStackRef_IsTaggedInt(_PyStackRef i) static inline _PyStackRef PyStackRef_TagInt(intptr_t i) { - assert(Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (i << 2), 2) == i); - return (_PyStackRef){ .bits = ((((uintptr_t)i) << 2) | Py_INT_TAG) }; + assert(Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (intptr_t)(((uintptr_t)i) << Py_TAGGED_SHIFT), + Py_TAGGED_SHIFT) == i); + return (_PyStackRef){ .bits = ((((uintptr_t)i) << Py_TAGGED_SHIFT) | Py_INT_TAG) }; } static inline intptr_t @@ -321,7 +440,7 @@ PyStackRef_UntagInt(_PyStackRef i) { assert(PyStackRef_IsTaggedInt(i)); intptr_t val = (intptr_t)i.bits; - return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 2); + return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, Py_TAGGED_SHIFT); } @@ -329,189 +448,10 @@ static inline _PyStackRef PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref) { assert((ref.bits & Py_TAG_BITS) == Py_INT_TAG); // Is tagged int - assert((ref.bits & (~Py_TAG_BITS)) != (INT_MAX & (~Py_TAG_BITS))); // Isn't about to overflow - return (_PyStackRef){ .bits = ref.bits + 4 }; + assert((ref.bits & (~Py_TAG_BITS)) != (INTPTR_MAX & (~Py_TAG_BITS))); // Isn't about to overflow + return (_PyStackRef){ .bits = ref.bits + (1 << Py_TAGGED_SHIFT) }; } -#define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0) - -#ifdef Py_GIL_DISABLED - -#define Py_TAG_DEFERRED Py_TAG_REFCNT - -#define Py_TAG_PTR ((uintptr_t)0) - - -static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED}; - -#define PyStackRef_IsNull(stackref) ((stackref).bits == PyStackRef_NULL.bits) -#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_DEFERRED }) -#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_DEFERRED }) -#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_DEFERRED }) - -// Checks that mask out the deferred bit in the free threading build. -#define PyStackRef_IsNone(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_None) -#define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True) -#define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False) - -#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref)) - -static inline PyObject * -PyStackRef_AsPyObjectBorrow(_PyStackRef stackref) -{ - assert(!PyStackRef_IsTaggedInt(stackref)); - PyObject *cleared = ((PyObject *)((stackref).bits & (~Py_TAG_BITS))); - return cleared; -} - -#define PyStackRef_IsDeferred(ref) (((ref).bits & Py_TAG_BITS) == Py_TAG_DEFERRED) - -static inline PyObject * -PyStackRef_NotDeferred_AsPyObject(_PyStackRef stackref) -{ - assert(!PyStackRef_IsDeferred(stackref)); - return (PyObject *)stackref.bits; -} - -static inline PyObject * -PyStackRef_AsPyObjectSteal(_PyStackRef stackref) -{ - assert(!PyStackRef_IsNull(stackref)); - if (PyStackRef_IsDeferred(stackref)) { - return Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)); - } - return PyStackRef_AsPyObjectBorrow(stackref); -} - -static inline _PyStackRef -_PyStackRef_FromPyObjectSteal(PyObject *obj) -{ - assert(obj != NULL); - // Make sure we don't take an already tagged value. - assert(((uintptr_t)obj & Py_TAG_BITS) == 0); - return (_PyStackRef){ .bits = (uintptr_t)obj }; -} -# define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj)) - -static inline bool -PyStackRef_IsHeapSafe(_PyStackRef stackref) -{ - if (PyStackRef_IsDeferred(stackref)) { - PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); - return obj == NULL || _Py_IsImmortal(obj) || _PyObject_HasDeferredRefcount(obj); - } - return true; -} - -static inline _PyStackRef -PyStackRef_MakeHeapSafe(_PyStackRef stackref) -{ - if (PyStackRef_IsHeapSafe(stackref)) { - return stackref; - } - PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); - return (_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) | Py_TAG_PTR }; -} - -static inline _PyStackRef -PyStackRef_FromPyObjectStealMortal(PyObject *obj) -{ - assert(obj != NULL); - assert(!_Py_IsImmortal(obj)); - // Make sure we don't take an already tagged value. - assert(((uintptr_t)obj & Py_TAG_BITS) == 0); - return (_PyStackRef){ .bits = (uintptr_t)obj }; -} - -static inline _PyStackRef -PyStackRef_FromPyObjectNew(PyObject *obj) -{ - // Make sure we don't take an already tagged value. - assert(((uintptr_t)obj & Py_TAG_BITS) == 0); - assert(obj != NULL); - if (_PyObject_HasDeferredRefcount(obj)) { - return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED }; - } - else { - return (_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) | Py_TAG_PTR }; - } -} -#define PyStackRef_FromPyObjectNew(obj) PyStackRef_FromPyObjectNew(_PyObject_CAST(obj)) - -static inline _PyStackRef -PyStackRef_FromPyObjectBorrow(PyObject *obj) -{ - // Make sure we don't take an already tagged value. - assert(((uintptr_t)obj & Py_TAG_BITS) == 0); - assert(obj != NULL); - return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED }; -} -#define PyStackRef_FromPyObjectBorrow(obj) PyStackRef_FromPyObjectBorrow(_PyObject_CAST(obj)) - -#define PyStackRef_CLOSE(REF) \ - do { \ - _PyStackRef _close_tmp = (REF); \ - assert(!PyStackRef_IsNull(_close_tmp)); \ - if (!PyStackRef_IsDeferredOrTaggedInt(_close_tmp)) { \ - Py_DECREF(PyStackRef_AsPyObjectBorrow(_close_tmp)); \ - } \ - } while (0) - -static inline void -PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct) -{ - (void)destruct; - PyStackRef_CLOSE(ref); -} - -static inline _PyStackRef -PyStackRef_DUP(_PyStackRef stackref) -{ - assert(!PyStackRef_IsNull(stackref)); - if (PyStackRef_IsDeferredOrTaggedInt(stackref)) { - return stackref; - } - Py_INCREF(PyStackRef_AsPyObjectBorrow(stackref)); - return stackref; -} - -static inline _PyStackRef -PyStackRef_Borrow(_PyStackRef stackref) -{ - return (_PyStackRef){ .bits = stackref.bits | Py_TAG_DEFERRED }; -} - -// Convert a possibly deferred reference to a strong reference. -static inline _PyStackRef -PyStackRef_AsStrongReference(_PyStackRef stackref) -{ - return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref)); -} - -#define PyStackRef_XCLOSE(stackref) \ - do { \ - _PyStackRef _tmp = (stackref); \ - if (!PyStackRef_IsNull(_tmp)) { \ - PyStackRef_CLOSE(_tmp); \ - } \ - } while (0); - -#define PyStackRef_CLEAR(op) \ - do { \ - _PyStackRef *_tmp_op_ptr = &(op); \ - _PyStackRef _tmp_old_op = (*_tmp_op_ptr); \ - if (!PyStackRef_IsNull(_tmp_old_op)) { \ - *_tmp_op_ptr = PyStackRef_NULL; \ - PyStackRef_CLOSE(_tmp_old_op); \ - } \ - } while (0) - -#define PyStackRef_FromPyObjectNewMortal PyStackRef_FromPyObjectNew - -#else // Py_GIL_DISABLED - -// With GIL - /* References to immortal objects always have their tag bit set to Py_TAG_REFCNT * as they can (must) have their reclamation deferred */ @@ -530,13 +470,24 @@ static const _PyStackRef PyStackRef_NULL = { .bits = PyStackRef_NULL_BITS }; #define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_REFCNT }) #define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_REFCNT }) +#ifdef Py_GIL_DISABLED +// Checks that mask out the deferred bit in the free threading build. +#define PyStackRef_IsNone(REF) (((REF).bits & ~Py_TAG_REFCNT) == (uintptr_t)&_Py_NoneStruct) +#define PyStackRef_IsTrue(REF) (((REF).bits & ~Py_TAG_REFCNT) == (uintptr_t)&_Py_TrueStruct) +#define PyStackRef_IsFalse(REF) (((REF).bits & ~Py_TAG_REFCNT) == (uintptr_t)&_Py_FalseStruct) +#else #define PyStackRef_IsTrue(REF) ((REF).bits == (((uintptr_t)&_Py_TrueStruct) | Py_TAG_REFCNT)) #define PyStackRef_IsFalse(REF) ((REF).bits == (((uintptr_t)&_Py_FalseStruct) | Py_TAG_REFCNT)) #define PyStackRef_IsNone(REF) ((REF).bits == (((uintptr_t)&_Py_NoneStruct) | Py_TAG_REFCNT)) +#endif -#ifdef Py_DEBUG +#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref)) -static inline void PyStackRef_CheckValid(_PyStackRef ref) { +#if defined(Py_DEBUG) && !defined(Py_GIL_DISABLED) + +static inline void +PyStackRef_CheckValid(_PyStackRef ref) +{ assert(ref.bits != 0); int tag = ref.bits & Py_TAG_BITS; PyObject *obj = BITS_TO_PTR_MASKED(ref); @@ -587,6 +538,8 @@ PyStackRef_Borrow(_PyStackRef ref) static inline PyObject * PyStackRef_AsPyObjectSteal(_PyStackRef ref) { + assert(!PyStackRef_IsNull(ref)); + assert(!PyStackRef_IsTaggedInt(ref)); if (PyStackRef_RefcountOnObject(ref)) { return BITS_TO_PTR(ref); } @@ -599,14 +552,18 @@ static inline _PyStackRef PyStackRef_FromPyObjectSteal(PyObject *obj) { assert(obj != NULL); -#if SIZEOF_VOID_P > 4 - unsigned int tag = obj->ob_flags & Py_TAG_REFCNT; +#ifdef Py_GIL_DISABLED + return (_PyStackRef){ .bits = (uintptr_t)obj }; #else +# if SIZEOF_VOID_P > 4 + unsigned int tag = obj->ob_flags & Py_TAG_REFCNT; +# else unsigned int tag = _Py_IsImmortal(obj) ? Py_TAG_REFCNT : 0; -#endif +# endif _PyStackRef ref = ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag}); PyStackRef_CheckValid(ref); return ref; +#endif } static inline _PyStackRef @@ -614,7 +571,7 @@ PyStackRef_FromPyObjectStealMortal(PyObject *obj) { assert(obj != NULL); assert(!_Py_IsImmortal(obj)); - _PyStackRef ref = ((_PyStackRef){.bits = ((uintptr_t)(obj)) }); + _PyStackRef ref = (_PyStackRef){ .bits = (uintptr_t)obj }; PyStackRef_CheckValid(ref); return ref; } @@ -623,9 +580,15 @@ static inline _PyStackRef _PyStackRef_FromPyObjectNew(PyObject *obj) { assert(obj != NULL); - if (_Py_IsImmortal(obj)) { - return (_PyStackRef){ .bits = ((uintptr_t)obj) | Py_TAG_REFCNT}; +#ifdef Py_GIL_DISABLED + if (_PyObject_HasDeferredRefcount(obj)) { + return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_REFCNT }; } +#else + if (_Py_IsImmortal(obj)) { + return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_REFCNT }; + } +#endif _Py_INCREF_MORTAL(obj); _PyStackRef ref = (_PyStackRef){ .bits = (uintptr_t)obj }; PyStackRef_CheckValid(ref); @@ -648,6 +611,7 @@ _PyStackRef_FromPyObjectNewMortal(PyObject *obj) static inline _PyStackRef PyStackRef_FromPyObjectBorrow(PyObject *obj) { + assert(obj != NULL); return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_REFCNT}; } @@ -670,7 +634,15 @@ PyStackRef_DUP(_PyStackRef ref) static inline bool PyStackRef_IsHeapSafe(_PyStackRef ref) { - return (ref.bits & Py_TAG_BITS) != Py_TAG_REFCNT || ref.bits == PyStackRef_NULL_BITS || _Py_IsImmortal(BITS_TO_PTR_MASKED(ref)); +#ifdef Py_GIL_DISABLED + if ((ref.bits & Py_TAG_BITS) != Py_TAG_REFCNT) { + return true; + } + PyObject *obj = BITS_TO_PTR_MASKED(ref); + return obj == NULL || _PyObject_HasDeferredRefcount(obj); +#else + return (ref.bits & Py_TAG_BITS) != Py_TAG_REFCNT || ref.bits == PyStackRef_NULL_BITS || _Py_IsImmortal(BITS_TO_PTR_MASKED(ref)); +#endif } static inline _PyStackRef @@ -686,6 +658,13 @@ PyStackRef_MakeHeapSafe(_PyStackRef ref) return ref; } +// Convert a possibly deferred reference to a strong reference. +static inline _PyStackRef +PyStackRef_AsStrongReference(_PyStackRef stackref) +{ + return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref)); +} + #ifdef _WIN32 #define PyStackRef_CLOSE(REF) \ do { \ @@ -703,12 +682,6 @@ PyStackRef_CLOSE(_PyStackRef ref) } #endif -static inline bool -PyStackRef_IsNullOrInt(_PyStackRef ref) -{ - return PyStackRef_IsNull(ref) || PyStackRef_IsTaggedInt(ref); -} - static inline void PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct) { @@ -741,8 +714,6 @@ PyStackRef_XCLOSE(_PyStackRef ref) } while (0) -#endif // Py_GIL_DISABLED - // Note: this is a macro because MSVC (Windows) has trouble inlining it. #define PyStackRef_Is(a, b) (((a).bits & (~Py_TAG_REFCNT)) == ((b).bits & (~Py_TAG_REFCNT))) @@ -810,13 +781,24 @@ _PyThreadState_PopCStackRef(PyThreadState *tstate, _PyCStackRef *ref) PyStackRef_XCLOSE(ref->ref); } +static inline _PyStackRef +_PyThreadState_PopCStackRefSteal(PyThreadState *tstate, _PyCStackRef *ref) +{ +#ifdef Py_GIL_DISABLED + _PyThreadStateImpl *tstate_impl = (_PyThreadStateImpl *)tstate; + assert(tstate_impl->c_stack_refs == ref); + tstate_impl->c_stack_refs = ref->next; +#endif + return ref->ref; +} + #ifdef Py_GIL_DISABLED static inline int _Py_TryIncrefCompareStackRef(PyObject **src, PyObject *op, _PyStackRef *out) { if (_PyObject_HasDeferredRefcount(op)) { - *out = (_PyStackRef){ .bits = (uintptr_t)op | Py_TAG_DEFERRED }; + *out = (_PyStackRef){ .bits = (uintptr_t)op | Py_TAG_REFCNT }; return 1; } if (_Py_TryIncrefCompare(src, op)) { diff --git a/Include/internal/pycore_stats.h b/Include/internal/pycore_stats.h index ab649574f33..850e6ea4552 100644 --- a/Include/internal/pycore_stats.h +++ b/Include/internal/pycore_stats.h @@ -15,39 +15,56 @@ extern "C" { #include "pycore_bitutils.h" // _Py_bit_length -#define STAT_INC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name++; } while (0) -#define STAT_DEC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name--; } while (0) -#define OPCODE_EXE_INC(opname) do { if (_Py_stats) _Py_stats->opcode_stats[opname].execution_count++; } while (0) -#define CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.name++; } while (0) -#define OBJECT_STAT_INC(name) do { if (_Py_stats) _Py_stats->object_stats.name++; } while (0) -#define OBJECT_STAT_INC_COND(name, cond) \ - do { if (_Py_stats && cond) _Py_stats->object_stats.name++; } while (0) -#define EVAL_CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.eval_calls[name]++; } while (0) -#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) \ - do { if (_Py_stats && PyFunction_Check(callable)) _Py_stats->call_stats.eval_calls[name]++; } while (0) -#define GC_STAT_ADD(gen, name, n) do { if (_Py_stats) _Py_stats->gc_stats[(gen)].name += (n); } while (0) -#define OPT_STAT_INC(name) do { if (_Py_stats) _Py_stats->optimization_stats.name++; } while (0) -#define OPT_STAT_ADD(name, n) do { if (_Py_stats) _Py_stats->optimization_stats.name += (n); } while (0) -#define UOP_STAT_INC(opname, name) do { if (_Py_stats) { assert(opname < 512); _Py_stats->optimization_stats.opcode[opname].name++; } } while (0) -#define UOP_PAIR_INC(uopcode, lastuop) \ - do { \ - if (lastuop && _Py_stats) { \ - _Py_stats->optimization_stats.opcode[lastuop].pair_count[uopcode]++; \ - } \ - lastuop = uopcode; \ - } while (0) -#define OPT_UNSUPPORTED_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.unsupported_opcode[opname]++; } while (0) -#define OPT_ERROR_IN_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.error_in_opcode[opname]++; } while (0) -#define OPT_HIST(length, name) \ +#define STAT_INC(opname, name) _Py_STATS_EXPR(opcode_stats[opname].specialization.name++) +#define STAT_DEC(opname, name) _Py_STATS_EXPR(opcode_stats[opname].specialization.name--) +#define OPCODE_EXE_INC(opname) _Py_STATS_EXPR(opcode_stats[opname].execution_count++) +#define CALL_STAT_INC(name) _Py_STATS_EXPR(call_stats.name++) +#define OBJECT_STAT_INC(name) _Py_STATS_EXPR(object_stats.name++) +#define OBJECT_STAT_INC_COND(name, cond) _Py_STATS_COND_EXPR(cond, object_stats.name++) +#define EVAL_CALL_STAT_INC(name) _Py_STATS_EXPR(call_stats.eval_calls[name]++) +#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) _Py_STATS_COND_EXPR(PyFunction_Check(callable), call_stats.eval_calls[name]++) +#define GC_STAT_ADD(gen, name, n) _Py_STATS_EXPR(gc_stats[(gen)].name += (n)) +#define OPT_STAT_INC(name) _Py_STATS_EXPR(optimization_stats.name++) +#define OPT_STAT_ADD(name, n) _Py_STATS_EXPR(optimization_stats.name += (n)) +#define UOP_STAT_INC(opname, name) \ do { \ - if (_Py_stats) { \ - int bucket = _Py_bit_length(length >= 1 ? length - 1 : 0); \ - bucket = (bucket >= _Py_UOP_HIST_SIZE) ? _Py_UOP_HIST_SIZE - 1 : bucket; \ - _Py_stats->optimization_stats.name[bucket]++; \ + PyStats *s = _PyStats_GET(); \ + if (s) { \ + assert(opname < 512); \ + s->optimization_stats.opcode[opname].name++; \ } \ } while (0) -#define RARE_EVENT_STAT_INC(name) do { if (_Py_stats) _Py_stats->rare_event_stats.name++; } while (0) -#define OPCODE_DEFERRED_INC(opname) do { if (_Py_stats && opcode == opname) _Py_stats->opcode_stats[opname].specialization.deferred++; } while (0) +#define UOP_PAIR_INC(uopcode, lastuop) \ + do { \ + PyStats *s = _PyStats_GET(); \ + if (lastuop && s) { \ + s->optimization_stats.opcode[lastuop].pair_count[uopcode]++; \ + } \ + lastuop = uopcode; \ + } while (0) +#define OPT_UNSUPPORTED_OPCODE(opname) _Py_STATS_EXPR(optimization_stats.unsupported_opcode[opname]++) +#define OPT_ERROR_IN_OPCODE(opname) _Py_STATS_EXPR(optimization_stats.error_in_opcode[opname]++) +#define OPT_HIST(length, name) \ + do { \ + PyStats *s = _PyStats_GET(); \ + if (s) { \ + int bucket = _Py_bit_length(length >= 1 ? length - 1 : 0); \ + bucket = (bucket >= _Py_UOP_HIST_SIZE) ? _Py_UOP_HIST_SIZE - 1 : bucket; \ + s->optimization_stats.name[bucket]++; \ + } \ + } while (0) +#define RARE_EVENT_STAT_INC(name) _Py_STATS_EXPR(rare_event_stats.name++) +#define OPCODE_DEFERRED_INC(opname) _Py_STATS_COND_EXPR(opcode==opname, opcode_stats[opname].specialization.deferred++) + +#ifdef Py_GIL_DISABLED +#define FT_STAT_MUTEX_SLEEP_INC() _Py_STATS_EXPR(ft_stats.mutex_sleeps++) +#define FT_STAT_QSBR_POLL_INC() _Py_STATS_EXPR(ft_stats.qsbr_polls++) +#define FT_STAT_WORLD_STOP_INC() _Py_STATS_EXPR(ft_stats.world_stops++) +#else +#define FT_STAT_MUTEX_SLEEP_INC() +#define FT_STAT_QSBR_POLL_INC() +#define FT_STAT_WORLD_STOP_INC() +#endif // Export for '_opcode' shared extension PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); @@ -71,13 +88,16 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); #define OPT_HIST(length, name) ((void)0) #define RARE_EVENT_STAT_INC(name) ((void)0) #define OPCODE_DEFERRED_INC(opname) ((void)0) +#define FT_STAT_MUTEX_SLEEP_INC() +#define FT_STAT_QSBR_POLL_INC() +#define FT_STAT_WORLD_STOP_INC() #endif // !Py_STATS #define RARE_EVENT_INTERP_INC(interp, name) \ do { \ /* saturating add */ \ - int val = FT_ATOMIC_LOAD_UINT8_RELAXED(interp->rare_events.name); \ + uint8_t val = FT_ATOMIC_LOAD_UINT8_RELAXED(interp->rare_events.name); \ if (val < UINT8_MAX) { \ FT_ATOMIC_STORE_UINT8(interp->rare_events.name, val + 1); \ } \ @@ -90,6 +110,11 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); RARE_EVENT_INTERP_INC(interp, name); \ } while (0); \ +PyStatus _PyStats_InterpInit(PyInterpreterState *); +bool _PyStats_ThreadInit(PyInterpreterState *, _PyThreadStateImpl *); +void _PyStats_ThreadFini(_PyThreadStateImpl *); +void _PyStats_Attach(_PyThreadStateImpl *); +void _PyStats_Detach(_PyThreadStateImpl *); #ifdef __cplusplus } diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 98099b4a497..9dbfa913219 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -188,7 +188,8 @@ extern struct symtable* _Py_SymtableStringObjectFlags( const char *str, PyObject *filename, int start, - PyCompilerFlags *flags); + PyCompilerFlags *flags, + PyObject *module); int _PyFuture_FromAST( struct _mod * mod, diff --git a/Include/internal/pycore_time.h b/Include/internal/pycore_time.h index 23312471c65..b671225ca6e 100644 --- a/Include/internal/pycore_time.h +++ b/Include/internal/pycore_time.h @@ -147,11 +147,6 @@ extern int _PyTime_FromSecondsDouble( // Clamp to [PyTime_MIN; PyTime_MAX] on overflow. extern PyTime_t _PyTime_FromMicrosecondsClamp(PyTime_t us); -// Create a timestamp from a Python int object (number of nanoseconds). -// Export for '_lsprof' shared extension. -PyAPI_FUNC(int) _PyTime_FromLong(PyTime_t *t, - PyObject *obj); - // Convert a number of seconds (Python float or int) to a timestamp. // Raise an exception and return -1 on error, return 0 on success. // Export for '_socket' shared extension. @@ -182,10 +177,6 @@ extern PyTime_t _PyTime_As100Nanoseconds(PyTime_t t, _PyTime_round_t round); #endif -// Convert a timestamp (number of nanoseconds) as a Python int object. -// Export for '_testinternalcapi' shared extension. -PyAPI_FUNC(PyObject*) _PyTime_AsLong(PyTime_t t); - #ifndef MS_WINDOWS // Create a timestamp from a timeval structure. // Raise an exception and return -1 on overflow, return 0 on success. diff --git a/Include/internal/pycore_traceback.h b/Include/internal/pycore_traceback.h index a4f125e073d..8357cce9d89 100644 --- a/Include/internal/pycore_traceback.h +++ b/Include/internal/pycore_traceback.h @@ -103,6 +103,8 @@ extern int _Py_WriteIndent(int, PyObject *); PyAPI_FUNC(void) _Py_InitDumpStack(void); PyAPI_FUNC(void) _Py_DumpStack(int fd); +extern void _Py_DumpTraceback_Init(void); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index 572e8025876..693385f9a46 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -30,8 +30,8 @@ struct _PyTraceMalloc_Config { }; -/* Pack the frame_t structure to reduce the memory footprint on 64-bit - architectures: 12 bytes instead of 16. */ +/* Pack the tracemalloc_frame and tracemalloc_traceback structures to reduce + the memory footprint on 64-bit architectures: 12 bytes instead of 16. */ #if defined(_MSC_VER) #pragma pack(push, 4) #endif @@ -46,18 +46,22 @@ tracemalloc_frame { PyObject *filename; unsigned int lineno; }; -#ifdef _MSC_VER -#pragma pack(pop) -#endif -struct tracemalloc_traceback { +struct +#ifdef __GNUC__ +__attribute__((packed)) +#endif +tracemalloc_traceback { Py_uhash_t hash; /* Number of frames stored */ uint16_t nframe; /* Total number of frames the traceback had */ uint16_t total_nframe; - struct tracemalloc_frame frames[1]; + struct tracemalloc_frame frames[]; }; +#ifdef _MSC_VER +#pragma pack(pop) +#endif struct _tracemalloc_runtime_state { @@ -95,7 +99,7 @@ struct _tracemalloc_runtime_state { Protected by TABLES_LOCK(). */ _Py_hashtable_t *domains; - struct tracemalloc_traceback empty_traceback; + struct tracemalloc_traceback *empty_traceback; Py_tss_t reentrant_key; }; diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index bad968428c7..c4f723ac8ab 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -10,9 +10,11 @@ extern "C" { #include "pycore_brc.h" // struct _brc_thread_state #include "pycore_freelist_state.h" // struct _Py_freelists +#include "pycore_interpframe_structs.h" // _PyInterpreterFrame #include "pycore_mimalloc.h" // struct _mimalloc_thread_state #include "pycore_qsbr.h" // struct qsbr - +#include "pycore_uop.h" // struct _PyUOpInstruction +#include "pycore_structs.h" #ifdef Py_GIL_DISABLED struct _gc_thread_state { @@ -21,6 +23,38 @@ struct _gc_thread_state { }; #endif +#if _Py_TIER2 +typedef struct _PyJitTracerInitialState { + int stack_depth; + int chain_depth; + struct _PyExitData *exit; + PyCodeObject *code; // Strong + PyFunctionObject *func; // Strong + _Py_CODEUNIT *start_instr; + _Py_CODEUNIT *close_loop_instr; + _Py_CODEUNIT *jump_backward_instr; +} _PyJitTracerInitialState; + +typedef struct _PyJitTracerPreviousState { + bool dependencies_still_valid; + bool instr_is_super; + int code_max_size; + int code_curr_size; + int instr_oparg; + int instr_stacklevel; + _Py_CODEUNIT *instr; + PyCodeObject *instr_code; // Strong + struct _PyInterpreterFrame *instr_frame; + _PyBloomFilter dependencies; +} _PyJitTracerPreviousState; + +typedef struct _PyJitTracerState { + _PyUOpInstruction *code_buffer; + _PyJitTracerInitialState initial_state; + _PyJitTracerPreviousState prev_state; +} _PyJitTracerState; +#endif + // Every PyThreadState is actually allocated as a _PyThreadStateImpl. The // PyThreadState fields are exposed as part of the C API, although most fields // are intended to be private. The _PyThreadStateImpl fields not exposed. @@ -28,6 +62,10 @@ typedef struct _PyThreadStateImpl { // semi-public fields are in PyThreadState. PyThreadState base; + // Embedded base frame - sentinel at the bottom of the frame stack. + // Used by profiling/sampling to detect incomplete stack traces. + _PyInterpreterFrame base_frame; + // The reference count field is used to synchronize deallocation of the // thread state during runtime finalization. Py_ssize_t refcount; @@ -37,6 +75,10 @@ typedef struct _PyThreadStateImpl { uintptr_t c_stack_soft_limit; uintptr_t c_stack_hard_limit; + // PyUnstable_ThreadState_ResetStackProtection() values + uintptr_t c_stack_init_base; + uintptr_t c_stack_init_top; + PyObject *asyncio_running_loop; // Strong reference PyObject *asyncio_running_task; // Strong reference @@ -70,12 +112,20 @@ typedef struct _PyThreadStateImpl { // When >1, code objects do not immortalize their non-string constants. int suppress_co_const_immortalization; + +#ifdef Py_STATS + // per-thread stats, will be merged into interp->pystats_struct + PyStats *pystats_struct; // allocated by _PyStats_ThreadInit() #endif +#endif // Py_GIL_DISABLED + #if defined(Py_REF_DEBUG) && defined(Py_GIL_DISABLED) Py_ssize_t reftotal; // this thread's total refcount operations #endif - +#if _Py_TIER2 + _PyJitTracerState jit_tracer_state; +#endif } _PyThreadStateImpl; #ifdef __cplusplus diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h index acf1bec4602..46db02593ad 100644 --- a/Include/internal/pycore_tuple.h +++ b/Include/internal/pycore_tuple.h @@ -23,7 +23,6 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *); #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) -PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 24df69aa93f..abaa60890b5 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -90,6 +90,9 @@ _PyType_GetModuleState(PyTypeObject *type) // function PyAPI_FUNC(PyObject *) _PyType_GetDict(PyTypeObject *); +PyAPI_FUNC(PyObject *) _PyType_LookupSubclasses(PyTypeObject *); +PyAPI_FUNC(PyObject *) _PyType_InitSubclasses(PyTypeObject *); + extern PyObject * _PyType_GetBases(PyTypeObject *type); extern PyObject * _PyType_GetMRO(PyTypeObject *type); extern PyObject* _PyType_GetSubclasses(PyTypeObject *); @@ -149,6 +152,14 @@ typedef int (*_py_validate_type)(PyTypeObject *); extern int _PyType_Validate(PyTypeObject *ty, _py_validate_type validate, unsigned int *tp_version); extern int _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version); +// Precalculates count of non-unique slots and fills wrapperbase.name_count. +extern int _PyType_InitSlotDefs(PyInterpreterState *interp); + +// Like PyType_GetBaseByToken, but does not modify refcounts. +// Cannot fail; arguments must be valid. +PyAPI_FUNC(int) +_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject **result); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_unicodectype.h b/Include/internal/pycore_unicodectype.h new file mode 100644 index 00000000000..523bdb56b09 --- /dev/null +++ b/Include/internal/pycore_unicodectype.h @@ -0,0 +1,25 @@ +#ifndef Py_INTERNAL_UNICODECTYPE_H +#define Py_INTERNAL_UNICODECTYPE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +extern int _PyUnicode_ToLowerFull(Py_UCS4 ch, Py_UCS4 *res); +extern int _PyUnicode_ToTitleFull(Py_UCS4 ch, Py_UCS4 *res); +extern int _PyUnicode_ToUpperFull(Py_UCS4 ch, Py_UCS4 *res); +extern int _PyUnicode_ToFoldedFull(Py_UCS4 ch, Py_UCS4 *res); +extern int _PyUnicode_IsCaseIgnorable(Py_UCS4 ch); +extern int _PyUnicode_IsCased(Py_UCS4 ch); + +// Export for 'unicodedata' shared extension. +PyAPI_FUNC(int) _PyUnicode_IsXidStart(Py_UCS4 ch); +PyAPI_FUNC(int) _PyUnicode_IsXidContinue(Py_UCS4 ch); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_UNICODECTYPE_H */ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 3791b913c17..97dda73f9b5 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -11,16 +11,108 @@ extern "C" { #include "pycore_fileutils.h" // _Py_error_handler #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI -/* --- Characters Type APIs ----------------------------------------------- */ -extern int _PyUnicode_IsXidStart(Py_UCS4 ch); -extern int _PyUnicode_IsXidContinue(Py_UCS4 ch); -extern int _PyUnicode_ToLowerFull(Py_UCS4 ch, Py_UCS4 *res); -extern int _PyUnicode_ToTitleFull(Py_UCS4 ch, Py_UCS4 *res); -extern int _PyUnicode_ToUpperFull(Py_UCS4 ch, Py_UCS4 *res); -extern int _PyUnicode_ToFoldedFull(Py_UCS4 ch, Py_UCS4 *res); -extern int _PyUnicode_IsCaseIgnorable(Py_UCS4 ch); -extern int _PyUnicode_IsCased(Py_UCS4 ch); +// Maximum code point of Unicode 6.0: 0x10ffff (1,114,111). +#define _Py_MAX_UNICODE 0x10ffff + + +extern int _PyUnicode_IsModifiable(PyObject *unicode); +extern void _PyUnicodeWriter_InitWithBuffer( + _PyUnicodeWriter *writer, + PyObject *buffer); +extern PyObject* _PyUnicode_Result(PyObject *unicode); +extern int _PyUnicode_DecodeUTF8Writer( + _PyUnicodeWriter *writer, + const char *s, + Py_ssize_t size, + _Py_error_handler error_handler, + const char *errors, + Py_ssize_t *consumed); +extern PyObject* _PyUnicode_ResizeCompact( + PyObject *unicode, + Py_ssize_t length); +extern PyObject* _PyUnicode_GetEmpty(void); + + +/* Generic helper macro to convert characters of different types. + from_type and to_type have to be valid type names, begin and end + are pointers to the source characters which should be of type + "from_type *". to is a pointer of type "to_type *" and points to the + buffer where the result characters are written to. */ +#define _PyUnicode_CONVERT_BYTES(from_type, to_type, begin, end, to) \ + do { \ + to_type *_to = (to_type *)(to); \ + const from_type *_iter = (const from_type *)(begin);\ + const from_type *_end = (const from_type *)(end);\ + Py_ssize_t n = (_end) - (_iter); \ + const from_type *_unrolled_end = \ + _iter + _Py_SIZE_ROUND_DOWN(n, 4); \ + while (_iter < (_unrolled_end)) { \ + _to[0] = (to_type) _iter[0]; \ + _to[1] = (to_type) _iter[1]; \ + _to[2] = (to_type) _iter[2]; \ + _to[3] = (to_type) _iter[3]; \ + _iter += 4; _to += 4; \ + } \ + while (_iter < (_end)) \ + *_to++ = (to_type) *_iter++; \ + } while (0) + + +static inline void +_PyUnicode_Fill(int kind, void *data, Py_UCS4 value, + Py_ssize_t start, Py_ssize_t length) +{ + assert(0 <= start); + switch (kind) { + case PyUnicode_1BYTE_KIND: { + assert(value <= 0xff); + Py_UCS1 ch = (unsigned char)value; + Py_UCS1 *to = (Py_UCS1 *)data + start; + memset(to, ch, length); + break; + } + case PyUnicode_2BYTE_KIND: { + assert(value <= 0xffff); + Py_UCS2 ch = (Py_UCS2)value; + Py_UCS2 *to = (Py_UCS2 *)data + start; + const Py_UCS2 *end = to + length; + for (; to < end; ++to) *to = ch; + break; + } + case PyUnicode_4BYTE_KIND: { + assert(value <= _Py_MAX_UNICODE); + Py_UCS4 ch = value; + Py_UCS4 * to = (Py_UCS4 *)data + start; + const Py_UCS4 *end = to + length; + for (; to < end; ++to) *to = ch; + break; + } + default: Py_UNREACHABLE(); + } +} + +static inline int +_PyUnicode_EnsureUnicode(PyObject *obj) +{ + if (!PyUnicode_Check(obj)) { + PyErr_Format(PyExc_TypeError, + "must be str, not %T", obj); + return -1; + } + return 0; +} + +static inline int +_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch) +{ + assert(ch <= _Py_MAX_UNICODE); + if (_PyUnicodeWriter_Prepare(writer, 1, ch) < 0) + return -1; + PyUnicode_WRITE(writer->kind, writer->data, writer->pos, ch); + writer->pos++; + return 0; +} /* --- Unicode API -------------------------------------------------------- */ @@ -82,12 +174,16 @@ extern int _PyUnicode_FormatAdvancedWriter( Py_ssize_t start, Py_ssize_t end); +/* PyUnicodeWriter_Format, with va_list instead of `...` */ +extern int _PyUnicodeWriter_FormatV( + PyUnicodeWriter *writer, + const char *format, + va_list vargs); + /* --- UTF-7 Codecs ------------------------------------------------------- */ extern PyObject* _PyUnicode_EncodeUTF7( PyObject *unicode, /* Unicode object */ - int base64SetO, /* Encode RFC2152 Set O characters in base64 */ - int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ const char *errors); /* error handling */ /* --- UTF-8 Codecs ------------------------------------------------------- */ @@ -211,14 +307,6 @@ PyAPI_FUNC(PyObject*) _PyUnicode_JoinArray( Py_ssize_t seqlen ); -/* Test whether a unicode is equal to ASCII identifier. Return 1 if true, - 0 otherwise. The right argument must be ASCII identifier. - Any error occurs inside will be cleared before return. */ -extern int _PyUnicode_EqualToASCIIId( - PyObject *left, /* Left string */ - _Py_Identifier *right /* Right identifier */ - ); - // Test whether a unicode is equal to ASCII string. Return 1 if true, // 0 otherwise. The right argument must be ASCII-encoded string. // Any error occurs inside will be cleared before return. @@ -236,21 +324,6 @@ extern PyObject* _PyUnicode_XStrip( ); -/* Using explicit passed-in values, insert the thousands grouping - into the string pointed to by buffer. For the argument descriptions, - see Objects/stringlib/localeutil.h */ -extern Py_ssize_t _PyUnicode_InsertThousandsGrouping( - _PyUnicodeWriter *writer, - Py_ssize_t n_buffer, - PyObject *digits, - Py_ssize_t d_pos, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - PyObject *thousands_sep, - Py_UCS4 *maxchar, - int forward); - /* Dedent a string. Behaviour is expected to be an exact match of `textwrap.dedent`. Return a new reference on success, NULL with exception set on error. diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index c9b8a8b5051..24e50828935 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1108,6 +1108,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(cache_frames); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cached_datetime_module); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1484,6 +1488,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(emptyerror); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(encode); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1584,6 +1592,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(fallback); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(false); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1688,6 +1700,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(free_threaded); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(from_param); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1708,6 +1724,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(fullerror); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(func); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1716,6 +1736,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(gc); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(generation); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2068,6 +2092,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(legacy); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(len); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2128,6 +2156,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(mask); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(match); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2152,6 +2184,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(maxsize); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(maxsplit); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2276,6 +2312,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(native); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ndigits); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2380,6 +2420,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(opcodes); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(open); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2480,6 +2524,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(pointer_bits); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(policy); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2540,10 +2588,22 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(qid); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(qualname); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(query); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(queuetype); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(quotetabs); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2588,6 +2648,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(recursive); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(reducer_override); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2756,6 +2820,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(short); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(show_cmd); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2780,6 +2848,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(skip_non_matching_threads); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sleep); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2824,6 +2896,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(stats); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(status); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2892,6 +2968,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(take_bytes); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(target); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -3040,6 +3120,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(unboundop); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(unlink); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -3180,6 +3264,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(gc); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_STR(anon_null); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -3204,6 +3292,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_STR(native); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_STR(anon_setcomp); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Include/internal/pycore_uop.h b/Include/internal/pycore_uop.h new file mode 100644 index 00000000000..e828a1cc5a5 --- /dev/null +++ b/Include/internal/pycore_uop.h @@ -0,0 +1,58 @@ +#ifndef Py_CORE_UOP_H +#define Py_CORE_UOP_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include +/* Depending on the format, + * the 32 bits between the oparg and operand are: + * UOP_FORMAT_TARGET: + * uint32_t target; + * UOP_FORMAT_JUMP + * uint16_t jump_target; + * uint16_t error_target; + */ +typedef struct _PyUOpInstruction{ + uint16_t opcode:15; + uint16_t format:1; + uint16_t oparg; + union { + uint32_t target; + struct { + uint16_t jump_target; + uint16_t error_target; + }; + }; + uint64_t operand0; // A cache entry + uint64_t operand1; +#ifdef Py_STATS + uint64_t execution_count; +#endif +} _PyUOpInstruction; + +// This is the length of the trace we translate initially. +#ifdef Py_DEBUG + // With asserts, the stencils are a lot larger +#define UOP_MAX_TRACE_LENGTH 2000 +#else +#define UOP_MAX_TRACE_LENGTH 5000 +#endif +#define UOP_BUFFER_SIZE (UOP_MAX_TRACE_LENGTH * sizeof(_PyUOpInstruction)) + +/* Bloom filter with m = 256 + * https://en.wikipedia.org/wiki/Bloom_filter */ +#define _Py_BLOOM_FILTER_WORDS 8 + +typedef struct { + uint32_t bits[_Py_BLOOM_FILTER_WORDS]; +} _PyBloomFilter; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_UOP_H */ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 749369a40ae..f73aad9de1c 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -13,25 +13,22 @@ extern "C" { #define _SET_IP 301 #define _BINARY_OP 302 #define _BINARY_OP_ADD_FLOAT 303 -#define _BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS 304 -#define _BINARY_OP_ADD_INT 305 -#define _BINARY_OP_ADD_UNICODE 306 -#define _BINARY_OP_EXTEND 307 -#define _BINARY_OP_INPLACE_ADD_UNICODE 308 -#define _BINARY_OP_MULTIPLY_FLOAT 309 -#define _BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS 310 -#define _BINARY_OP_MULTIPLY_INT 311 -#define _BINARY_OP_SUBSCR_CHECK_FUNC 312 -#define _BINARY_OP_SUBSCR_DICT 313 -#define _BINARY_OP_SUBSCR_INIT_CALL 314 -#define _BINARY_OP_SUBSCR_LIST_INT 315 -#define _BINARY_OP_SUBSCR_LIST_SLICE 316 -#define _BINARY_OP_SUBSCR_STR_INT 317 -#define _BINARY_OP_SUBSCR_TUPLE_INT 318 -#define _BINARY_OP_SUBTRACT_FLOAT 319 -#define _BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS 320 -#define _BINARY_OP_SUBTRACT_INT 321 -#define _BINARY_SLICE 322 +#define _BINARY_OP_ADD_INT 304 +#define _BINARY_OP_ADD_UNICODE 305 +#define _BINARY_OP_EXTEND 306 +#define _BINARY_OP_INPLACE_ADD_UNICODE 307 +#define _BINARY_OP_MULTIPLY_FLOAT 308 +#define _BINARY_OP_MULTIPLY_INT 309 +#define _BINARY_OP_SUBSCR_CHECK_FUNC 310 +#define _BINARY_OP_SUBSCR_DICT 311 +#define _BINARY_OP_SUBSCR_INIT_CALL 312 +#define _BINARY_OP_SUBSCR_LIST_INT 313 +#define _BINARY_OP_SUBSCR_LIST_SLICE 314 +#define _BINARY_OP_SUBSCR_STR_INT 315 +#define _BINARY_OP_SUBSCR_TUPLE_INT 316 +#define _BINARY_OP_SUBTRACT_FLOAT 317 +#define _BINARY_OP_SUBTRACT_INT 318 +#define _BINARY_SLICE 319 #define _BUILD_INTERPOLATION BUILD_INTERPOLATION #define _BUILD_LIST BUILD_LIST #define _BUILD_MAP BUILD_MAP @@ -40,143 +37,148 @@ extern "C" { #define _BUILD_STRING BUILD_STRING #define _BUILD_TEMPLATE BUILD_TEMPLATE #define _BUILD_TUPLE BUILD_TUPLE -#define _CALL_BUILTIN_CLASS 323 -#define _CALL_BUILTIN_FAST 324 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS 325 -#define _CALL_BUILTIN_O 326 +#define _CALL_BUILTIN_CLASS 320 +#define _CALL_BUILTIN_FAST 321 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS 322 +#define _CALL_BUILTIN_O 323 #define _CALL_INTRINSIC_1 CALL_INTRINSIC_1 #define _CALL_INTRINSIC_2 CALL_INTRINSIC_2 -#define _CALL_ISINSTANCE 327 -#define _CALL_KW_NON_PY 328 -#define _CALL_LEN 329 -#define _CALL_LIST_APPEND 330 -#define _CALL_METHOD_DESCRIPTOR_FAST 331 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 332 -#define _CALL_METHOD_DESCRIPTOR_NOARGS 333 -#define _CALL_METHOD_DESCRIPTOR_O 334 -#define _CALL_NON_PY_GENERAL 335 -#define _CALL_STR_1 336 -#define _CALL_TUPLE_1 337 -#define _CALL_TYPE_1 338 -#define _CHECK_AND_ALLOCATE_OBJECT 339 -#define _CHECK_ATTR_CLASS 340 -#define _CHECK_ATTR_METHOD_LAZY_DICT 341 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 342 +#define _CALL_ISINSTANCE 324 +#define _CALL_KW_NON_PY 325 +#define _CALL_LEN 326 +#define _CALL_LIST_APPEND 327 +#define _CALL_METHOD_DESCRIPTOR_FAST 328 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 329 +#define _CALL_METHOD_DESCRIPTOR_NOARGS 330 +#define _CALL_METHOD_DESCRIPTOR_O 331 +#define _CALL_NON_PY_GENERAL 332 +#define _CALL_STR_1 333 +#define _CALL_TUPLE_1 334 +#define _CALL_TYPE_1 335 +#define _CHECK_AND_ALLOCATE_OBJECT 336 +#define _CHECK_ATTR_CLASS 337 +#define _CHECK_ATTR_METHOD_LAZY_DICT 338 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 339 #define _CHECK_EG_MATCH CHECK_EG_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _CHECK_FUNCTION 343 -#define _CHECK_FUNCTION_EXACT_ARGS 344 -#define _CHECK_FUNCTION_VERSION 345 -#define _CHECK_FUNCTION_VERSION_INLINE 346 -#define _CHECK_FUNCTION_VERSION_KW 347 -#define _CHECK_IS_NOT_PY_CALLABLE 348 -#define _CHECK_IS_NOT_PY_CALLABLE_KW 349 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 350 -#define _CHECK_METHOD_VERSION 351 -#define _CHECK_METHOD_VERSION_KW 352 -#define _CHECK_PEP_523 353 -#define _CHECK_PERIODIC 354 -#define _CHECK_PERIODIC_AT_END 355 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 356 -#define _CHECK_RECURSION_REMAINING 357 -#define _CHECK_STACK_SPACE 358 -#define _CHECK_STACK_SPACE_OPERAND 359 -#define _CHECK_VALIDITY 360 -#define _COLD_EXIT 361 -#define _COMPARE_OP 362 -#define _COMPARE_OP_FLOAT 363 -#define _COMPARE_OP_INT 364 -#define _COMPARE_OP_STR 365 -#define _CONTAINS_OP 366 -#define _CONTAINS_OP_DICT 367 -#define _CONTAINS_OP_SET 368 +#define _CHECK_FUNCTION_EXACT_ARGS 340 +#define _CHECK_FUNCTION_VERSION 341 +#define _CHECK_FUNCTION_VERSION_INLINE 342 +#define _CHECK_FUNCTION_VERSION_KW 343 +#define _CHECK_IS_NOT_PY_CALLABLE 344 +#define _CHECK_IS_NOT_PY_CALLABLE_KW 345 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 346 +#define _CHECK_METHOD_VERSION 347 +#define _CHECK_METHOD_VERSION_KW 348 +#define _CHECK_PEP_523 349 +#define _CHECK_PERIODIC 350 +#define _CHECK_PERIODIC_AT_END 351 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 352 +#define _CHECK_RECURSION_REMAINING 353 +#define _CHECK_STACK_SPACE 354 +#define _CHECK_STACK_SPACE_OPERAND 355 +#define _CHECK_VALIDITY 356 +#define _COLD_DYNAMIC_EXIT 357 +#define _COLD_EXIT 358 +#define _COMPARE_OP 359 +#define _COMPARE_OP_FLOAT 360 +#define _COMPARE_OP_INT 361 +#define _COMPARE_OP_STR 362 +#define _CONTAINS_OP 363 +#define _CONTAINS_OP_DICT 364 +#define _CONTAINS_OP_SET 365 #define _CONVERT_VALUE CONVERT_VALUE -#define _COPY 369 -#define _COPY_1 370 -#define _COPY_2 371 -#define _COPY_3 372 +#define _COPY 366 +#define _COPY_1 367 +#define _COPY_2 368 +#define _COPY_3 369 #define _COPY_FREE_VARS COPY_FREE_VARS -#define _CREATE_INIT_FRAME 373 +#define _CREATE_INIT_FRAME 370 #define _DELETE_ATTR DELETE_ATTR #define _DELETE_DEREF DELETE_DEREF #define _DELETE_FAST DELETE_FAST #define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_NAME DELETE_NAME #define _DELETE_SUBSCR DELETE_SUBSCR -#define _DEOPT 374 +#define _DEOPT 371 #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE -#define _DO_CALL 375 -#define _DO_CALL_FUNCTION_EX 376 -#define _DO_CALL_KW 377 +#define _DO_CALL 372 +#define _DO_CALL_FUNCTION_EX 373 +#define _DO_CALL_KW 374 +#define _DYNAMIC_EXIT 375 #define _END_FOR END_FOR #define _END_SEND END_SEND -#define _ERROR_POP_N 378 +#define _ERROR_POP_N 376 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _EXPAND_METHOD 379 -#define _EXPAND_METHOD_KW 380 -#define _FATAL_ERROR 381 +#define _EXPAND_METHOD 377 +#define _EXPAND_METHOD_KW 378 +#define _FATAL_ERROR 379 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 382 -#define _FOR_ITER_GEN_FRAME 383 -#define _FOR_ITER_TIER_TWO 384 +#define _FOR_ITER 380 +#define _FOR_ITER_GEN_FRAME 381 +#define _FOR_ITER_TIER_TWO 382 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BINARY_OP_EXTEND 385 -#define _GUARD_CALLABLE_ISINSTANCE 386 -#define _GUARD_CALLABLE_LEN 387 -#define _GUARD_CALLABLE_LIST_APPEND 388 -#define _GUARD_CALLABLE_STR_1 389 -#define _GUARD_CALLABLE_TUPLE_1 390 -#define _GUARD_CALLABLE_TYPE_1 391 -#define _GUARD_DORV_NO_DICT 392 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 393 -#define _GUARD_GLOBALS_VERSION 394 -#define _GUARD_IS_FALSE_POP 395 -#define _GUARD_IS_NONE_POP 396 -#define _GUARD_IS_NOT_NONE_POP 397 -#define _GUARD_IS_TRUE_POP 398 -#define _GUARD_KEYS_VERSION 399 -#define _GUARD_NOS_DICT 400 -#define _GUARD_NOS_FLOAT 401 -#define _GUARD_NOS_INT 402 -#define _GUARD_NOS_LIST 403 -#define _GUARD_NOS_NOT_NULL 404 -#define _GUARD_NOS_NULL 405 -#define _GUARD_NOS_OVERFLOWED 406 -#define _GUARD_NOS_TUPLE 407 -#define _GUARD_NOS_UNICODE 408 -#define _GUARD_NOT_EXHAUSTED_LIST 409 -#define _GUARD_NOT_EXHAUSTED_RANGE 410 -#define _GUARD_NOT_EXHAUSTED_TUPLE 411 -#define _GUARD_THIRD_NULL 412 -#define _GUARD_TOS_ANY_SET 413 -#define _GUARD_TOS_DICT 414 -#define _GUARD_TOS_FLOAT 415 -#define _GUARD_TOS_INT 416 -#define _GUARD_TOS_LIST 417 -#define _GUARD_TOS_OVERFLOWED 418 -#define _GUARD_TOS_SLICE 419 -#define _GUARD_TOS_TUPLE 420 -#define _GUARD_TOS_UNICODE 421 -#define _GUARD_TYPE_VERSION 422 -#define _GUARD_TYPE_VERSION_AND_LOCK 423 -#define _HANDLE_PENDING_AND_DEOPT 424 +#define _GUARD_BINARY_OP_EXTEND 383 +#define _GUARD_CALLABLE_ISINSTANCE 384 +#define _GUARD_CALLABLE_LEN 385 +#define _GUARD_CALLABLE_LIST_APPEND 386 +#define _GUARD_CALLABLE_STR_1 387 +#define _GUARD_CALLABLE_TUPLE_1 388 +#define _GUARD_CALLABLE_TYPE_1 389 +#define _GUARD_DORV_NO_DICT 390 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 391 +#define _GUARD_GLOBALS_VERSION 392 +#define _GUARD_IP_RETURN_GENERATOR 393 +#define _GUARD_IP_RETURN_VALUE 394 +#define _GUARD_IP_YIELD_VALUE 395 +#define _GUARD_IP__PUSH_FRAME 396 +#define _GUARD_IS_FALSE_POP 397 +#define _GUARD_IS_NONE_POP 398 +#define _GUARD_IS_NOT_NONE_POP 399 +#define _GUARD_IS_TRUE_POP 400 +#define _GUARD_KEYS_VERSION 401 +#define _GUARD_NOS_DICT 402 +#define _GUARD_NOS_FLOAT 403 +#define _GUARD_NOS_INT 404 +#define _GUARD_NOS_LIST 405 +#define _GUARD_NOS_NOT_NULL 406 +#define _GUARD_NOS_NULL 407 +#define _GUARD_NOS_OVERFLOWED 408 +#define _GUARD_NOS_TUPLE 409 +#define _GUARD_NOS_UNICODE 410 +#define _GUARD_NOT_EXHAUSTED_LIST 411 +#define _GUARD_NOT_EXHAUSTED_RANGE 412 +#define _GUARD_NOT_EXHAUSTED_TUPLE 413 +#define _GUARD_THIRD_NULL 414 +#define _GUARD_TOS_ANY_SET 415 +#define _GUARD_TOS_DICT 416 +#define _GUARD_TOS_FLOAT 417 +#define _GUARD_TOS_INT 418 +#define _GUARD_TOS_LIST 419 +#define _GUARD_TOS_OVERFLOWED 420 +#define _GUARD_TOS_SLICE 421 +#define _GUARD_TOS_TUPLE 422 +#define _GUARD_TOS_UNICODE 423 +#define _GUARD_TYPE_VERSION 424 +#define _GUARD_TYPE_VERSION_AND_LOCK 425 +#define _HANDLE_PENDING_AND_DEOPT 426 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 425 -#define _INIT_CALL_PY_EXACT_ARGS 426 -#define _INIT_CALL_PY_EXACT_ARGS_0 427 -#define _INIT_CALL_PY_EXACT_ARGS_1 428 -#define _INIT_CALL_PY_EXACT_ARGS_2 429 -#define _INIT_CALL_PY_EXACT_ARGS_3 430 -#define _INIT_CALL_PY_EXACT_ARGS_4 431 -#define _INSERT_NULL 432 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 427 +#define _INIT_CALL_PY_EXACT_ARGS 428 +#define _INIT_CALL_PY_EXACT_ARGS_0 429 +#define _INIT_CALL_PY_EXACT_ARGS_1 430 +#define _INIT_CALL_PY_EXACT_ARGS_2 431 +#define _INIT_CALL_PY_EXACT_ARGS_3 432 +#define _INIT_CALL_PY_EXACT_ARGS_4 433 +#define _INSERT_NULL 434 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -186,177 +188,914 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 433 +#define _IS_NONE 435 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 434 -#define _ITER_CHECK_RANGE 435 -#define _ITER_CHECK_TUPLE 436 -#define _ITER_JUMP_LIST 437 -#define _ITER_JUMP_RANGE 438 -#define _ITER_JUMP_TUPLE 439 -#define _ITER_NEXT_LIST 440 -#define _ITER_NEXT_LIST_TIER_TWO 441 -#define _ITER_NEXT_RANGE 442 -#define _ITER_NEXT_TUPLE 443 -#define _JUMP_TO_TOP 444 +#define _ITER_CHECK_LIST 436 +#define _ITER_CHECK_RANGE 437 +#define _ITER_CHECK_TUPLE 438 +#define _ITER_JUMP_LIST 439 +#define _ITER_JUMP_RANGE 440 +#define _ITER_JUMP_TUPLE 441 +#define _ITER_NEXT_LIST 442 +#define _ITER_NEXT_LIST_TIER_TWO 443 +#define _ITER_NEXT_RANGE 444 +#define _ITER_NEXT_TUPLE 445 +#define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT +#define _JUMP_TO_TOP 446 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 445 -#define _LOAD_ATTR_CLASS 446 +#define _LOAD_ATTR 447 +#define _LOAD_ATTR_CLASS 448 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 447 -#define _LOAD_ATTR_METHOD_LAZY_DICT 448 -#define _LOAD_ATTR_METHOD_NO_DICT 449 -#define _LOAD_ATTR_METHOD_WITH_VALUES 450 -#define _LOAD_ATTR_MODULE 451 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 452 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 453 -#define _LOAD_ATTR_PROPERTY_FRAME 454 -#define _LOAD_ATTR_SLOT 455 -#define _LOAD_ATTR_WITH_HINT 456 +#define _LOAD_ATTR_INSTANCE_VALUE 449 +#define _LOAD_ATTR_METHOD_LAZY_DICT 450 +#define _LOAD_ATTR_METHOD_NO_DICT 451 +#define _LOAD_ATTR_METHOD_WITH_VALUES 452 +#define _LOAD_ATTR_MODULE 453 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 454 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 455 +#define _LOAD_ATTR_PROPERTY_FRAME 456 +#define _LOAD_ATTR_SLOT 457 +#define _LOAD_ATTR_WITH_HINT 458 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 457 +#define _LOAD_BYTECODE 459 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 458 -#define _LOAD_CONST_INLINE_BORROW 459 -#define _LOAD_CONST_UNDER_INLINE 460 -#define _LOAD_CONST_UNDER_INLINE_BORROW 461 +#define _LOAD_CONST_INLINE 460 +#define _LOAD_CONST_INLINE_BORROW 461 +#define _LOAD_CONST_UNDER_INLINE 462 +#define _LOAD_CONST_UNDER_INLINE_BORROW 463 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 462 -#define _LOAD_FAST_0 463 -#define _LOAD_FAST_1 464 -#define _LOAD_FAST_2 465 -#define _LOAD_FAST_3 466 -#define _LOAD_FAST_4 467 -#define _LOAD_FAST_5 468 -#define _LOAD_FAST_6 469 -#define _LOAD_FAST_7 470 +#define _LOAD_FAST 464 +#define _LOAD_FAST_0 465 +#define _LOAD_FAST_1 466 +#define _LOAD_FAST_2 467 +#define _LOAD_FAST_3 468 +#define _LOAD_FAST_4 469 +#define _LOAD_FAST_5 470 +#define _LOAD_FAST_6 471 +#define _LOAD_FAST_7 472 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 471 -#define _LOAD_FAST_BORROW_0 472 -#define _LOAD_FAST_BORROW_1 473 -#define _LOAD_FAST_BORROW_2 474 -#define _LOAD_FAST_BORROW_3 475 -#define _LOAD_FAST_BORROW_4 476 -#define _LOAD_FAST_BORROW_5 477 -#define _LOAD_FAST_BORROW_6 478 -#define _LOAD_FAST_BORROW_7 479 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW LOAD_FAST_BORROW_LOAD_FAST_BORROW +#define _LOAD_FAST_BORROW 473 +#define _LOAD_FAST_BORROW_0 474 +#define _LOAD_FAST_BORROW_1 475 +#define _LOAD_FAST_BORROW_2 476 +#define _LOAD_FAST_BORROW_3 477 +#define _LOAD_FAST_BORROW_4 478 +#define _LOAD_FAST_BORROW_5 479 +#define _LOAD_FAST_BORROW_6 480 +#define _LOAD_FAST_BORROW_7 481 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK -#define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 480 -#define _LOAD_GLOBAL_BUILTINS 481 -#define _LOAD_GLOBAL_MODULE 482 +#define _LOAD_GLOBAL 482 +#define _LOAD_GLOBAL_BUILTINS 483 +#define _LOAD_GLOBAL_MODULE 484 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 483 -#define _LOAD_SMALL_INT_0 484 -#define _LOAD_SMALL_INT_1 485 -#define _LOAD_SMALL_INT_2 486 -#define _LOAD_SMALL_INT_3 487 -#define _LOAD_SPECIAL 488 +#define _LOAD_SMALL_INT 485 +#define _LOAD_SMALL_INT_0 486 +#define _LOAD_SMALL_INT_1 487 +#define _LOAD_SMALL_INT_2 488 +#define _LOAD_SMALL_INT_3 489 +#define _LOAD_SPECIAL 490 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 489 +#define _MAKE_CALLARGS_A_TUPLE 491 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 490 +#define _MAKE_WARM 492 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 491 -#define _MAYBE_EXPAND_METHOD_KW 492 -#define _MONITOR_CALL 493 -#define _MONITOR_CALL_KW 494 -#define _MONITOR_JUMP_BACKWARD 495 -#define _MONITOR_RESUME 496 +#define _MAYBE_EXPAND_METHOD 493 +#define _MAYBE_EXPAND_METHOD_KW 494 +#define _MONITOR_CALL 495 +#define _MONITOR_CALL_KW 496 +#define _MONITOR_JUMP_BACKWARD 497 +#define _MONITOR_RESUME 498 #define _NOP NOP -#define _POP_CALL 497 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW 498 -#define _POP_CALL_ONE 499 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 500 -#define _POP_CALL_TWO 501 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 502 +#define _POP_CALL 499 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW 500 +#define _POP_CALL_ONE 501 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 502 +#define _POP_CALL_TWO 503 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 504 #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 503 -#define _POP_JUMP_IF_TRUE 504 +#define _POP_JUMP_IF_FALSE 505 +#define _POP_JUMP_IF_TRUE 506 #define _POP_TOP POP_TOP -#define _POP_TOP_FLOAT 505 -#define _POP_TOP_INT 506 -#define _POP_TOP_LOAD_CONST_INLINE 507 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 508 -#define _POP_TOP_NOP 509 -#define _POP_TOP_UNICODE 510 -#define _POP_TWO 511 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 512 +#define _POP_TOP_FLOAT 507 +#define _POP_TOP_INT 508 +#define _POP_TOP_LOAD_CONST_INLINE 509 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 510 +#define _POP_TOP_NOP 511 +#define _POP_TOP_UNICODE 512 +#define _POP_TWO 513 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 514 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 513 +#define _PUSH_FRAME 515 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 514 -#define _PY_FRAME_GENERAL 515 -#define _PY_FRAME_KW 516 -#define _QUICKEN_RESUME 517 -#define _REPLACE_WITH_TRUE 518 +#define _PUSH_NULL_CONDITIONAL 516 +#define _PY_FRAME_GENERAL 517 +#define _PY_FRAME_KW 518 +#define _QUICKEN_RESUME 519 +#define _REPLACE_WITH_TRUE 520 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 519 -#define _SEND 520 -#define _SEND_GEN_FRAME 521 +#define _SAVE_RETURN_OFFSET 521 +#define _SEND 522 +#define _SEND_GEN_FRAME 523 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 522 -#define _STORE_ATTR 523 -#define _STORE_ATTR_INSTANCE_VALUE 524 -#define _STORE_ATTR_SLOT 525 -#define _STORE_ATTR_WITH_HINT 526 +#define _SPILL_OR_RELOAD 524 +#define _START_EXECUTOR 525 +#define _STORE_ATTR 526 +#define _STORE_ATTR_INSTANCE_VALUE 527 +#define _STORE_ATTR_SLOT 528 +#define _STORE_ATTR_WITH_HINT 529 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 527 -#define _STORE_FAST_0 528 -#define _STORE_FAST_1 529 -#define _STORE_FAST_2 530 -#define _STORE_FAST_3 531 -#define _STORE_FAST_4 532 -#define _STORE_FAST_5 533 -#define _STORE_FAST_6 534 -#define _STORE_FAST_7 535 -#define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST -#define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST +#define _STORE_FAST 530 +#define _STORE_FAST_0 531 +#define _STORE_FAST_1 532 +#define _STORE_FAST_2 533 +#define _STORE_FAST_3 534 +#define _STORE_FAST_4 535 +#define _STORE_FAST_5 536 +#define _STORE_FAST_6 537 +#define _STORE_FAST_7 538 #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 536 -#define _STORE_SUBSCR 537 -#define _STORE_SUBSCR_DICT 538 -#define _STORE_SUBSCR_LIST_INT 539 -#define _SWAP 540 -#define _SWAP_2 541 -#define _SWAP_3 542 -#define _TIER2_RESUME_CHECK 543 -#define _TO_BOOL 544 +#define _STORE_SLICE 539 +#define _STORE_SUBSCR 540 +#define _STORE_SUBSCR_DICT 541 +#define _STORE_SUBSCR_LIST_INT 542 +#define _SWAP 543 +#define _SWAP_2 544 +#define _SWAP_3 545 +#define _TIER2_RESUME_CHECK 546 +#define _TO_BOOL 547 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST 545 +#define _TO_BOOL_LIST 548 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 546 +#define _TO_BOOL_STR 549 +#define _TRACE_RECORD TRACE_RECORD #define _UNARY_INVERT UNARY_INVERT #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 547 -#define _UNPACK_SEQUENCE_LIST 548 -#define _UNPACK_SEQUENCE_TUPLE 549 -#define _UNPACK_SEQUENCE_TWO_TUPLE 550 +#define _UNPACK_SEQUENCE 550 +#define _UNPACK_SEQUENCE_LIST 551 +#define _UNPACK_SEQUENCE_TUPLE 552 +#define _UNPACK_SEQUENCE_TWO_TUPLE 553 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 550 +#define MAX_UOP_ID 553 +#define _BINARY_OP_r21 554 +#define _BINARY_OP_ADD_FLOAT_r03 555 +#define _BINARY_OP_ADD_FLOAT_r13 556 +#define _BINARY_OP_ADD_FLOAT_r23 557 +#define _BINARY_OP_ADD_INT_r03 558 +#define _BINARY_OP_ADD_INT_r13 559 +#define _BINARY_OP_ADD_INT_r23 560 +#define _BINARY_OP_ADD_UNICODE_r03 561 +#define _BINARY_OP_ADD_UNICODE_r13 562 +#define _BINARY_OP_ADD_UNICODE_r23 563 +#define _BINARY_OP_EXTEND_r21 564 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r20 565 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 566 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 567 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 568 +#define _BINARY_OP_MULTIPLY_INT_r03 569 +#define _BINARY_OP_MULTIPLY_INT_r13 570 +#define _BINARY_OP_MULTIPLY_INT_r23 571 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 572 +#define _BINARY_OP_SUBSCR_DICT_r21 573 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 574 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 575 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 576 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 577 +#define _BINARY_OP_SUBSCR_LIST_INT_r21 578 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 579 +#define _BINARY_OP_SUBSCR_STR_INT_r21 580 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r21 581 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 582 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 583 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 584 +#define _BINARY_OP_SUBTRACT_INT_r03 585 +#define _BINARY_OP_SUBTRACT_INT_r13 586 +#define _BINARY_OP_SUBTRACT_INT_r23 587 +#define _BINARY_SLICE_r31 588 +#define _BUILD_INTERPOLATION_r01 589 +#define _BUILD_LIST_r01 590 +#define _BUILD_MAP_r01 591 +#define _BUILD_SET_r01 592 +#define _BUILD_SLICE_r01 593 +#define _BUILD_STRING_r01 594 +#define _BUILD_TEMPLATE_r21 595 +#define _BUILD_TUPLE_r01 596 +#define _CALL_BUILTIN_CLASS_r01 597 +#define _CALL_BUILTIN_FAST_r01 598 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 599 +#define _CALL_BUILTIN_O_r03 600 +#define _CALL_INTRINSIC_1_r11 601 +#define _CALL_INTRINSIC_2_r21 602 +#define _CALL_ISINSTANCE_r31 603 +#define _CALL_KW_NON_PY_r11 604 +#define _CALL_LEN_r33 605 +#define _CALL_LIST_APPEND_r02 606 +#define _CALL_LIST_APPEND_r12 607 +#define _CALL_LIST_APPEND_r22 608 +#define _CALL_LIST_APPEND_r32 609 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 610 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 611 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 612 +#define _CALL_METHOD_DESCRIPTOR_O_r01 613 +#define _CALL_NON_PY_GENERAL_r01 614 +#define _CALL_STR_1_r32 615 +#define _CALL_TUPLE_1_r32 616 +#define _CALL_TYPE_1_r31 617 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 618 +#define _CHECK_ATTR_CLASS_r01 619 +#define _CHECK_ATTR_CLASS_r11 620 +#define _CHECK_ATTR_CLASS_r22 621 +#define _CHECK_ATTR_CLASS_r33 622 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 623 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 624 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 625 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 626 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 627 +#define _CHECK_EG_MATCH_r22 628 +#define _CHECK_EXC_MATCH_r22 629 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 630 +#define _CHECK_FUNCTION_VERSION_r00 631 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 632 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 633 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 634 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 635 +#define _CHECK_FUNCTION_VERSION_KW_r11 636 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 637 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 638 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 639 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 640 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 641 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 642 +#define _CHECK_METHOD_VERSION_r00 643 +#define _CHECK_METHOD_VERSION_KW_r11 644 +#define _CHECK_PEP_523_r00 645 +#define _CHECK_PEP_523_r11 646 +#define _CHECK_PEP_523_r22 647 +#define _CHECK_PEP_523_r33 648 +#define _CHECK_PERIODIC_r00 649 +#define _CHECK_PERIODIC_AT_END_r00 650 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 651 +#define _CHECK_RECURSION_REMAINING_r00 652 +#define _CHECK_RECURSION_REMAINING_r11 653 +#define _CHECK_RECURSION_REMAINING_r22 654 +#define _CHECK_RECURSION_REMAINING_r33 655 +#define _CHECK_STACK_SPACE_r00 656 +#define _CHECK_STACK_SPACE_OPERAND_r00 657 +#define _CHECK_STACK_SPACE_OPERAND_r11 658 +#define _CHECK_STACK_SPACE_OPERAND_r22 659 +#define _CHECK_STACK_SPACE_OPERAND_r33 660 +#define _CHECK_VALIDITY_r00 661 +#define _CHECK_VALIDITY_r11 662 +#define _CHECK_VALIDITY_r22 663 +#define _CHECK_VALIDITY_r33 664 +#define _COLD_DYNAMIC_EXIT_r00 665 +#define _COLD_EXIT_r00 666 +#define _COMPARE_OP_r21 667 +#define _COMPARE_OP_FLOAT_r01 668 +#define _COMPARE_OP_FLOAT_r11 669 +#define _COMPARE_OP_FLOAT_r21 670 +#define _COMPARE_OP_FLOAT_r32 671 +#define _COMPARE_OP_INT_r23 672 +#define _COMPARE_OP_STR_r21 673 +#define _CONTAINS_OP_r21 674 +#define _CONTAINS_OP_DICT_r21 675 +#define _CONTAINS_OP_SET_r21 676 +#define _CONVERT_VALUE_r11 677 +#define _COPY_r01 678 +#define _COPY_1_r02 679 +#define _COPY_1_r12 680 +#define _COPY_1_r23 681 +#define _COPY_2_r03 682 +#define _COPY_2_r13 683 +#define _COPY_2_r23 684 +#define _COPY_3_r03 685 +#define _COPY_3_r13 686 +#define _COPY_3_r23 687 +#define _COPY_3_r33 688 +#define _COPY_FREE_VARS_r00 689 +#define _COPY_FREE_VARS_r11 690 +#define _COPY_FREE_VARS_r22 691 +#define _COPY_FREE_VARS_r33 692 +#define _CREATE_INIT_FRAME_r01 693 +#define _DELETE_ATTR_r10 694 +#define _DELETE_DEREF_r00 695 +#define _DELETE_FAST_r00 696 +#define _DELETE_GLOBAL_r00 697 +#define _DELETE_NAME_r00 698 +#define _DELETE_SUBSCR_r20 699 +#define _DEOPT_r00 700 +#define _DEOPT_r10 701 +#define _DEOPT_r20 702 +#define _DEOPT_r30 703 +#define _DICT_MERGE_r10 704 +#define _DICT_UPDATE_r10 705 +#define _DO_CALL_r01 706 +#define _DO_CALL_FUNCTION_EX_r31 707 +#define _DO_CALL_KW_r11 708 +#define _DYNAMIC_EXIT_r00 709 +#define _DYNAMIC_EXIT_r10 710 +#define _DYNAMIC_EXIT_r20 711 +#define _DYNAMIC_EXIT_r30 712 +#define _END_FOR_r10 713 +#define _END_SEND_r21 714 +#define _ERROR_POP_N_r00 715 +#define _EXIT_INIT_CHECK_r10 716 +#define _EXIT_TRACE_r00 717 +#define _EXIT_TRACE_r10 718 +#define _EXIT_TRACE_r20 719 +#define _EXIT_TRACE_r30 720 +#define _EXPAND_METHOD_r00 721 +#define _EXPAND_METHOD_KW_r11 722 +#define _FATAL_ERROR_r00 723 +#define _FATAL_ERROR_r11 724 +#define _FATAL_ERROR_r22 725 +#define _FATAL_ERROR_r33 726 +#define _FORMAT_SIMPLE_r11 727 +#define _FORMAT_WITH_SPEC_r21 728 +#define _FOR_ITER_r23 729 +#define _FOR_ITER_GEN_FRAME_r23 730 +#define _FOR_ITER_TIER_TWO_r23 731 +#define _GET_AITER_r11 732 +#define _GET_ANEXT_r12 733 +#define _GET_AWAITABLE_r11 734 +#define _GET_ITER_r12 735 +#define _GET_LEN_r12 736 +#define _GET_YIELD_FROM_ITER_r11 737 +#define _GUARD_BINARY_OP_EXTEND_r22 738 +#define _GUARD_CALLABLE_ISINSTANCE_r03 739 +#define _GUARD_CALLABLE_ISINSTANCE_r13 740 +#define _GUARD_CALLABLE_ISINSTANCE_r23 741 +#define _GUARD_CALLABLE_ISINSTANCE_r33 742 +#define _GUARD_CALLABLE_LEN_r03 743 +#define _GUARD_CALLABLE_LEN_r13 744 +#define _GUARD_CALLABLE_LEN_r23 745 +#define _GUARD_CALLABLE_LEN_r33 746 +#define _GUARD_CALLABLE_LIST_APPEND_r03 747 +#define _GUARD_CALLABLE_LIST_APPEND_r13 748 +#define _GUARD_CALLABLE_LIST_APPEND_r23 749 +#define _GUARD_CALLABLE_LIST_APPEND_r33 750 +#define _GUARD_CALLABLE_STR_1_r03 751 +#define _GUARD_CALLABLE_STR_1_r13 752 +#define _GUARD_CALLABLE_STR_1_r23 753 +#define _GUARD_CALLABLE_STR_1_r33 754 +#define _GUARD_CALLABLE_TUPLE_1_r03 755 +#define _GUARD_CALLABLE_TUPLE_1_r13 756 +#define _GUARD_CALLABLE_TUPLE_1_r23 757 +#define _GUARD_CALLABLE_TUPLE_1_r33 758 +#define _GUARD_CALLABLE_TYPE_1_r03 759 +#define _GUARD_CALLABLE_TYPE_1_r13 760 +#define _GUARD_CALLABLE_TYPE_1_r23 761 +#define _GUARD_CALLABLE_TYPE_1_r33 762 +#define _GUARD_DORV_NO_DICT_r01 763 +#define _GUARD_DORV_NO_DICT_r11 764 +#define _GUARD_DORV_NO_DICT_r22 765 +#define _GUARD_DORV_NO_DICT_r33 766 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 767 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 768 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 769 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 770 +#define _GUARD_GLOBALS_VERSION_r00 771 +#define _GUARD_GLOBALS_VERSION_r11 772 +#define _GUARD_GLOBALS_VERSION_r22 773 +#define _GUARD_GLOBALS_VERSION_r33 774 +#define _GUARD_IP_RETURN_GENERATOR_r00 775 +#define _GUARD_IP_RETURN_GENERATOR_r11 776 +#define _GUARD_IP_RETURN_GENERATOR_r22 777 +#define _GUARD_IP_RETURN_GENERATOR_r33 778 +#define _GUARD_IP_RETURN_VALUE_r00 779 +#define _GUARD_IP_RETURN_VALUE_r11 780 +#define _GUARD_IP_RETURN_VALUE_r22 781 +#define _GUARD_IP_RETURN_VALUE_r33 782 +#define _GUARD_IP_YIELD_VALUE_r00 783 +#define _GUARD_IP_YIELD_VALUE_r11 784 +#define _GUARD_IP_YIELD_VALUE_r22 785 +#define _GUARD_IP_YIELD_VALUE_r33 786 +#define _GUARD_IP__PUSH_FRAME_r00 787 +#define _GUARD_IP__PUSH_FRAME_r11 788 +#define _GUARD_IP__PUSH_FRAME_r22 789 +#define _GUARD_IP__PUSH_FRAME_r33 790 +#define _GUARD_IS_FALSE_POP_r00 791 +#define _GUARD_IS_FALSE_POP_r10 792 +#define _GUARD_IS_FALSE_POP_r21 793 +#define _GUARD_IS_FALSE_POP_r32 794 +#define _GUARD_IS_NONE_POP_r00 795 +#define _GUARD_IS_NONE_POP_r10 796 +#define _GUARD_IS_NONE_POP_r21 797 +#define _GUARD_IS_NONE_POP_r32 798 +#define _GUARD_IS_NOT_NONE_POP_r10 799 +#define _GUARD_IS_TRUE_POP_r00 800 +#define _GUARD_IS_TRUE_POP_r10 801 +#define _GUARD_IS_TRUE_POP_r21 802 +#define _GUARD_IS_TRUE_POP_r32 803 +#define _GUARD_KEYS_VERSION_r01 804 +#define _GUARD_KEYS_VERSION_r11 805 +#define _GUARD_KEYS_VERSION_r22 806 +#define _GUARD_KEYS_VERSION_r33 807 +#define _GUARD_NOS_DICT_r02 808 +#define _GUARD_NOS_DICT_r12 809 +#define _GUARD_NOS_DICT_r22 810 +#define _GUARD_NOS_DICT_r33 811 +#define _GUARD_NOS_FLOAT_r02 812 +#define _GUARD_NOS_FLOAT_r12 813 +#define _GUARD_NOS_FLOAT_r22 814 +#define _GUARD_NOS_FLOAT_r33 815 +#define _GUARD_NOS_INT_r02 816 +#define _GUARD_NOS_INT_r12 817 +#define _GUARD_NOS_INT_r22 818 +#define _GUARD_NOS_INT_r33 819 +#define _GUARD_NOS_LIST_r02 820 +#define _GUARD_NOS_LIST_r12 821 +#define _GUARD_NOS_LIST_r22 822 +#define _GUARD_NOS_LIST_r33 823 +#define _GUARD_NOS_NOT_NULL_r02 824 +#define _GUARD_NOS_NOT_NULL_r12 825 +#define _GUARD_NOS_NOT_NULL_r22 826 +#define _GUARD_NOS_NOT_NULL_r33 827 +#define _GUARD_NOS_NULL_r02 828 +#define _GUARD_NOS_NULL_r12 829 +#define _GUARD_NOS_NULL_r22 830 +#define _GUARD_NOS_NULL_r33 831 +#define _GUARD_NOS_OVERFLOWED_r02 832 +#define _GUARD_NOS_OVERFLOWED_r12 833 +#define _GUARD_NOS_OVERFLOWED_r22 834 +#define _GUARD_NOS_OVERFLOWED_r33 835 +#define _GUARD_NOS_TUPLE_r02 836 +#define _GUARD_NOS_TUPLE_r12 837 +#define _GUARD_NOS_TUPLE_r22 838 +#define _GUARD_NOS_TUPLE_r33 839 +#define _GUARD_NOS_UNICODE_r02 840 +#define _GUARD_NOS_UNICODE_r12 841 +#define _GUARD_NOS_UNICODE_r22 842 +#define _GUARD_NOS_UNICODE_r33 843 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 844 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 845 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 846 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 847 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 848 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 849 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 850 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 851 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 852 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 853 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 854 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 855 +#define _GUARD_THIRD_NULL_r03 856 +#define _GUARD_THIRD_NULL_r13 857 +#define _GUARD_THIRD_NULL_r23 858 +#define _GUARD_THIRD_NULL_r33 859 +#define _GUARD_TOS_ANY_SET_r01 860 +#define _GUARD_TOS_ANY_SET_r11 861 +#define _GUARD_TOS_ANY_SET_r22 862 +#define _GUARD_TOS_ANY_SET_r33 863 +#define _GUARD_TOS_DICT_r01 864 +#define _GUARD_TOS_DICT_r11 865 +#define _GUARD_TOS_DICT_r22 866 +#define _GUARD_TOS_DICT_r33 867 +#define _GUARD_TOS_FLOAT_r01 868 +#define _GUARD_TOS_FLOAT_r11 869 +#define _GUARD_TOS_FLOAT_r22 870 +#define _GUARD_TOS_FLOAT_r33 871 +#define _GUARD_TOS_INT_r01 872 +#define _GUARD_TOS_INT_r11 873 +#define _GUARD_TOS_INT_r22 874 +#define _GUARD_TOS_INT_r33 875 +#define _GUARD_TOS_LIST_r01 876 +#define _GUARD_TOS_LIST_r11 877 +#define _GUARD_TOS_LIST_r22 878 +#define _GUARD_TOS_LIST_r33 879 +#define _GUARD_TOS_OVERFLOWED_r01 880 +#define _GUARD_TOS_OVERFLOWED_r11 881 +#define _GUARD_TOS_OVERFLOWED_r22 882 +#define _GUARD_TOS_OVERFLOWED_r33 883 +#define _GUARD_TOS_SLICE_r01 884 +#define _GUARD_TOS_SLICE_r11 885 +#define _GUARD_TOS_SLICE_r22 886 +#define _GUARD_TOS_SLICE_r33 887 +#define _GUARD_TOS_TUPLE_r01 888 +#define _GUARD_TOS_TUPLE_r11 889 +#define _GUARD_TOS_TUPLE_r22 890 +#define _GUARD_TOS_TUPLE_r33 891 +#define _GUARD_TOS_UNICODE_r01 892 +#define _GUARD_TOS_UNICODE_r11 893 +#define _GUARD_TOS_UNICODE_r22 894 +#define _GUARD_TOS_UNICODE_r33 895 +#define _GUARD_TYPE_VERSION_r01 896 +#define _GUARD_TYPE_VERSION_r11 897 +#define _GUARD_TYPE_VERSION_r22 898 +#define _GUARD_TYPE_VERSION_r33 899 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 900 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 901 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 902 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 903 +#define _HANDLE_PENDING_AND_DEOPT_r00 904 +#define _HANDLE_PENDING_AND_DEOPT_r10 905 +#define _HANDLE_PENDING_AND_DEOPT_r20 906 +#define _HANDLE_PENDING_AND_DEOPT_r30 907 +#define _IMPORT_FROM_r12 908 +#define _IMPORT_NAME_r21 909 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 910 +#define _INIT_CALL_PY_EXACT_ARGS_r01 911 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 912 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 913 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 914 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 915 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 916 +#define _INSERT_NULL_r10 917 +#define _INSTRUMENTED_FOR_ITER_r23 918 +#define _INSTRUMENTED_INSTRUCTION_r00 919 +#define _INSTRUMENTED_JUMP_FORWARD_r00 920 +#define _INSTRUMENTED_JUMP_FORWARD_r11 921 +#define _INSTRUMENTED_JUMP_FORWARD_r22 922 +#define _INSTRUMENTED_JUMP_FORWARD_r33 923 +#define _INSTRUMENTED_LINE_r00 924 +#define _INSTRUMENTED_NOT_TAKEN_r00 925 +#define _INSTRUMENTED_NOT_TAKEN_r11 926 +#define _INSTRUMENTED_NOT_TAKEN_r22 927 +#define _INSTRUMENTED_NOT_TAKEN_r33 928 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 929 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 930 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 931 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 932 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 933 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 934 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 935 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 936 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 937 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 938 +#define _IS_NONE_r11 939 +#define _IS_OP_r21 940 +#define _ITER_CHECK_LIST_r02 941 +#define _ITER_CHECK_LIST_r12 942 +#define _ITER_CHECK_LIST_r22 943 +#define _ITER_CHECK_LIST_r33 944 +#define _ITER_CHECK_RANGE_r02 945 +#define _ITER_CHECK_RANGE_r12 946 +#define _ITER_CHECK_RANGE_r22 947 +#define _ITER_CHECK_RANGE_r33 948 +#define _ITER_CHECK_TUPLE_r02 949 +#define _ITER_CHECK_TUPLE_r12 950 +#define _ITER_CHECK_TUPLE_r22 951 +#define _ITER_CHECK_TUPLE_r33 952 +#define _ITER_JUMP_LIST_r02 953 +#define _ITER_JUMP_LIST_r12 954 +#define _ITER_JUMP_LIST_r22 955 +#define _ITER_JUMP_LIST_r33 956 +#define _ITER_JUMP_RANGE_r02 957 +#define _ITER_JUMP_RANGE_r12 958 +#define _ITER_JUMP_RANGE_r22 959 +#define _ITER_JUMP_RANGE_r33 960 +#define _ITER_JUMP_TUPLE_r02 961 +#define _ITER_JUMP_TUPLE_r12 962 +#define _ITER_JUMP_TUPLE_r22 963 +#define _ITER_JUMP_TUPLE_r33 964 +#define _ITER_NEXT_LIST_r23 965 +#define _ITER_NEXT_LIST_TIER_TWO_r23 966 +#define _ITER_NEXT_RANGE_r03 967 +#define _ITER_NEXT_RANGE_r13 968 +#define _ITER_NEXT_RANGE_r23 969 +#define _ITER_NEXT_TUPLE_r03 970 +#define _ITER_NEXT_TUPLE_r13 971 +#define _ITER_NEXT_TUPLE_r23 972 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 973 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 974 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 975 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 976 +#define _JUMP_TO_TOP_r00 977 +#define _LIST_APPEND_r10 978 +#define _LIST_EXTEND_r10 979 +#define _LOAD_ATTR_r10 980 +#define _LOAD_ATTR_CLASS_r11 981 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 982 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 983 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 984 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 985 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 986 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 987 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 988 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 989 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 990 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 991 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 992 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 993 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 994 +#define _LOAD_ATTR_MODULE_r11 995 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 996 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 997 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 998 +#define _LOAD_ATTR_SLOT_r11 999 +#define _LOAD_ATTR_WITH_HINT_r11 1000 +#define _LOAD_BUILD_CLASS_r01 1001 +#define _LOAD_BYTECODE_r00 1002 +#define _LOAD_COMMON_CONSTANT_r01 1003 +#define _LOAD_COMMON_CONSTANT_r12 1004 +#define _LOAD_COMMON_CONSTANT_r23 1005 +#define _LOAD_CONST_r01 1006 +#define _LOAD_CONST_r12 1007 +#define _LOAD_CONST_r23 1008 +#define _LOAD_CONST_INLINE_r01 1009 +#define _LOAD_CONST_INLINE_r12 1010 +#define _LOAD_CONST_INLINE_r23 1011 +#define _LOAD_CONST_INLINE_BORROW_r01 1012 +#define _LOAD_CONST_INLINE_BORROW_r12 1013 +#define _LOAD_CONST_INLINE_BORROW_r23 1014 +#define _LOAD_CONST_UNDER_INLINE_r02 1015 +#define _LOAD_CONST_UNDER_INLINE_r12 1016 +#define _LOAD_CONST_UNDER_INLINE_r23 1017 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1018 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1019 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1020 +#define _LOAD_DEREF_r01 1021 +#define _LOAD_FAST_r01 1022 +#define _LOAD_FAST_r12 1023 +#define _LOAD_FAST_r23 1024 +#define _LOAD_FAST_0_r01 1025 +#define _LOAD_FAST_0_r12 1026 +#define _LOAD_FAST_0_r23 1027 +#define _LOAD_FAST_1_r01 1028 +#define _LOAD_FAST_1_r12 1029 +#define _LOAD_FAST_1_r23 1030 +#define _LOAD_FAST_2_r01 1031 +#define _LOAD_FAST_2_r12 1032 +#define _LOAD_FAST_2_r23 1033 +#define _LOAD_FAST_3_r01 1034 +#define _LOAD_FAST_3_r12 1035 +#define _LOAD_FAST_3_r23 1036 +#define _LOAD_FAST_4_r01 1037 +#define _LOAD_FAST_4_r12 1038 +#define _LOAD_FAST_4_r23 1039 +#define _LOAD_FAST_5_r01 1040 +#define _LOAD_FAST_5_r12 1041 +#define _LOAD_FAST_5_r23 1042 +#define _LOAD_FAST_6_r01 1043 +#define _LOAD_FAST_6_r12 1044 +#define _LOAD_FAST_6_r23 1045 +#define _LOAD_FAST_7_r01 1046 +#define _LOAD_FAST_7_r12 1047 +#define _LOAD_FAST_7_r23 1048 +#define _LOAD_FAST_AND_CLEAR_r01 1049 +#define _LOAD_FAST_AND_CLEAR_r12 1050 +#define _LOAD_FAST_AND_CLEAR_r23 1051 +#define _LOAD_FAST_BORROW_r01 1052 +#define _LOAD_FAST_BORROW_r12 1053 +#define _LOAD_FAST_BORROW_r23 1054 +#define _LOAD_FAST_BORROW_0_r01 1055 +#define _LOAD_FAST_BORROW_0_r12 1056 +#define _LOAD_FAST_BORROW_0_r23 1057 +#define _LOAD_FAST_BORROW_1_r01 1058 +#define _LOAD_FAST_BORROW_1_r12 1059 +#define _LOAD_FAST_BORROW_1_r23 1060 +#define _LOAD_FAST_BORROW_2_r01 1061 +#define _LOAD_FAST_BORROW_2_r12 1062 +#define _LOAD_FAST_BORROW_2_r23 1063 +#define _LOAD_FAST_BORROW_3_r01 1064 +#define _LOAD_FAST_BORROW_3_r12 1065 +#define _LOAD_FAST_BORROW_3_r23 1066 +#define _LOAD_FAST_BORROW_4_r01 1067 +#define _LOAD_FAST_BORROW_4_r12 1068 +#define _LOAD_FAST_BORROW_4_r23 1069 +#define _LOAD_FAST_BORROW_5_r01 1070 +#define _LOAD_FAST_BORROW_5_r12 1071 +#define _LOAD_FAST_BORROW_5_r23 1072 +#define _LOAD_FAST_BORROW_6_r01 1073 +#define _LOAD_FAST_BORROW_6_r12 1074 +#define _LOAD_FAST_BORROW_6_r23 1075 +#define _LOAD_FAST_BORROW_7_r01 1076 +#define _LOAD_FAST_BORROW_7_r12 1077 +#define _LOAD_FAST_BORROW_7_r23 1078 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1079 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1080 +#define _LOAD_FAST_CHECK_r01 1081 +#define _LOAD_FAST_CHECK_r12 1082 +#define _LOAD_FAST_CHECK_r23 1083 +#define _LOAD_FAST_LOAD_FAST_r02 1084 +#define _LOAD_FAST_LOAD_FAST_r13 1085 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1086 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1087 +#define _LOAD_GLOBAL_r00 1088 +#define _LOAD_GLOBAL_BUILTINS_r01 1089 +#define _LOAD_GLOBAL_MODULE_r01 1090 +#define _LOAD_LOCALS_r01 1091 +#define _LOAD_LOCALS_r12 1092 +#define _LOAD_LOCALS_r23 1093 +#define _LOAD_NAME_r01 1094 +#define _LOAD_SMALL_INT_r01 1095 +#define _LOAD_SMALL_INT_r12 1096 +#define _LOAD_SMALL_INT_r23 1097 +#define _LOAD_SMALL_INT_0_r01 1098 +#define _LOAD_SMALL_INT_0_r12 1099 +#define _LOAD_SMALL_INT_0_r23 1100 +#define _LOAD_SMALL_INT_1_r01 1101 +#define _LOAD_SMALL_INT_1_r12 1102 +#define _LOAD_SMALL_INT_1_r23 1103 +#define _LOAD_SMALL_INT_2_r01 1104 +#define _LOAD_SMALL_INT_2_r12 1105 +#define _LOAD_SMALL_INT_2_r23 1106 +#define _LOAD_SMALL_INT_3_r01 1107 +#define _LOAD_SMALL_INT_3_r12 1108 +#define _LOAD_SMALL_INT_3_r23 1109 +#define _LOAD_SPECIAL_r00 1110 +#define _LOAD_SUPER_ATTR_ATTR_r31 1111 +#define _LOAD_SUPER_ATTR_METHOD_r32 1112 +#define _MAKE_CALLARGS_A_TUPLE_r33 1113 +#define _MAKE_CELL_r00 1114 +#define _MAKE_FUNCTION_r11 1115 +#define _MAKE_WARM_r00 1116 +#define _MAKE_WARM_r11 1117 +#define _MAKE_WARM_r22 1118 +#define _MAKE_WARM_r33 1119 +#define _MAP_ADD_r20 1120 +#define _MATCH_CLASS_r31 1121 +#define _MATCH_KEYS_r23 1122 +#define _MATCH_MAPPING_r02 1123 +#define _MATCH_MAPPING_r12 1124 +#define _MATCH_MAPPING_r23 1125 +#define _MATCH_SEQUENCE_r02 1126 +#define _MATCH_SEQUENCE_r12 1127 +#define _MATCH_SEQUENCE_r23 1128 +#define _MAYBE_EXPAND_METHOD_r00 1129 +#define _MAYBE_EXPAND_METHOD_KW_r11 1130 +#define _MONITOR_CALL_r00 1131 +#define _MONITOR_CALL_KW_r11 1132 +#define _MONITOR_JUMP_BACKWARD_r00 1133 +#define _MONITOR_JUMP_BACKWARD_r11 1134 +#define _MONITOR_JUMP_BACKWARD_r22 1135 +#define _MONITOR_JUMP_BACKWARD_r33 1136 +#define _MONITOR_RESUME_r00 1137 +#define _NOP_r00 1138 +#define _NOP_r11 1139 +#define _NOP_r22 1140 +#define _NOP_r33 1141 +#define _POP_CALL_r20 1142 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1143 +#define _POP_CALL_ONE_r30 1144 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1145 +#define _POP_CALL_TWO_r30 1146 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1147 +#define _POP_EXCEPT_r10 1148 +#define _POP_ITER_r20 1149 +#define _POP_JUMP_IF_FALSE_r00 1150 +#define _POP_JUMP_IF_FALSE_r10 1151 +#define _POP_JUMP_IF_FALSE_r21 1152 +#define _POP_JUMP_IF_FALSE_r32 1153 +#define _POP_JUMP_IF_TRUE_r00 1154 +#define _POP_JUMP_IF_TRUE_r10 1155 +#define _POP_JUMP_IF_TRUE_r21 1156 +#define _POP_JUMP_IF_TRUE_r32 1157 +#define _POP_TOP_r10 1158 +#define _POP_TOP_FLOAT_r00 1159 +#define _POP_TOP_FLOAT_r10 1160 +#define _POP_TOP_FLOAT_r21 1161 +#define _POP_TOP_FLOAT_r32 1162 +#define _POP_TOP_INT_r00 1163 +#define _POP_TOP_INT_r10 1164 +#define _POP_TOP_INT_r21 1165 +#define _POP_TOP_INT_r32 1166 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1167 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1168 +#define _POP_TOP_NOP_r00 1169 +#define _POP_TOP_NOP_r10 1170 +#define _POP_TOP_NOP_r21 1171 +#define _POP_TOP_NOP_r32 1172 +#define _POP_TOP_UNICODE_r00 1173 +#define _POP_TOP_UNICODE_r10 1174 +#define _POP_TOP_UNICODE_r21 1175 +#define _POP_TOP_UNICODE_r32 1176 +#define _POP_TWO_r20 1177 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1178 +#define _PUSH_EXC_INFO_r02 1179 +#define _PUSH_EXC_INFO_r12 1180 +#define _PUSH_EXC_INFO_r23 1181 +#define _PUSH_FRAME_r10 1182 +#define _PUSH_NULL_r01 1183 +#define _PUSH_NULL_r12 1184 +#define _PUSH_NULL_r23 1185 +#define _PUSH_NULL_CONDITIONAL_r00 1186 +#define _PY_FRAME_GENERAL_r01 1187 +#define _PY_FRAME_KW_r11 1188 +#define _QUICKEN_RESUME_r00 1189 +#define _QUICKEN_RESUME_r11 1190 +#define _QUICKEN_RESUME_r22 1191 +#define _QUICKEN_RESUME_r33 1192 +#define _REPLACE_WITH_TRUE_r11 1193 +#define _RESUME_CHECK_r00 1194 +#define _RESUME_CHECK_r11 1195 +#define _RESUME_CHECK_r22 1196 +#define _RESUME_CHECK_r33 1197 +#define _RETURN_GENERATOR_r01 1198 +#define _RETURN_VALUE_r11 1199 +#define _SAVE_RETURN_OFFSET_r00 1200 +#define _SAVE_RETURN_OFFSET_r11 1201 +#define _SAVE_RETURN_OFFSET_r22 1202 +#define _SAVE_RETURN_OFFSET_r33 1203 +#define _SEND_r22 1204 +#define _SEND_GEN_FRAME_r22 1205 +#define _SETUP_ANNOTATIONS_r00 1206 +#define _SET_ADD_r10 1207 +#define _SET_FUNCTION_ATTRIBUTE_r01 1208 +#define _SET_FUNCTION_ATTRIBUTE_r11 1209 +#define _SET_FUNCTION_ATTRIBUTE_r21 1210 +#define _SET_FUNCTION_ATTRIBUTE_r32 1211 +#define _SET_IP_r00 1212 +#define _SET_IP_r11 1213 +#define _SET_IP_r22 1214 +#define _SET_IP_r33 1215 +#define _SET_UPDATE_r10 1216 +#define _SPILL_OR_RELOAD_r01 1217 +#define _SPILL_OR_RELOAD_r02 1218 +#define _SPILL_OR_RELOAD_r03 1219 +#define _SPILL_OR_RELOAD_r10 1220 +#define _SPILL_OR_RELOAD_r12 1221 +#define _SPILL_OR_RELOAD_r13 1222 +#define _SPILL_OR_RELOAD_r20 1223 +#define _SPILL_OR_RELOAD_r21 1224 +#define _SPILL_OR_RELOAD_r23 1225 +#define _SPILL_OR_RELOAD_r30 1226 +#define _SPILL_OR_RELOAD_r31 1227 +#define _SPILL_OR_RELOAD_r32 1228 +#define _START_EXECUTOR_r00 1229 +#define _STORE_ATTR_r20 1230 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1231 +#define _STORE_ATTR_SLOT_r21 1232 +#define _STORE_ATTR_WITH_HINT_r21 1233 +#define _STORE_DEREF_r10 1234 +#define _STORE_FAST_r10 1235 +#define _STORE_FAST_0_r10 1236 +#define _STORE_FAST_1_r10 1237 +#define _STORE_FAST_2_r10 1238 +#define _STORE_FAST_3_r10 1239 +#define _STORE_FAST_4_r10 1240 +#define _STORE_FAST_5_r10 1241 +#define _STORE_FAST_6_r10 1242 +#define _STORE_FAST_7_r10 1243 +#define _STORE_FAST_LOAD_FAST_r11 1244 +#define _STORE_FAST_STORE_FAST_r20 1245 +#define _STORE_GLOBAL_r10 1246 +#define _STORE_NAME_r10 1247 +#define _STORE_SLICE_r30 1248 +#define _STORE_SUBSCR_r30 1249 +#define _STORE_SUBSCR_DICT_r31 1250 +#define _STORE_SUBSCR_LIST_INT_r32 1251 +#define _SWAP_r11 1252 +#define _SWAP_2_r02 1253 +#define _SWAP_2_r12 1254 +#define _SWAP_2_r22 1255 +#define _SWAP_2_r33 1256 +#define _SWAP_3_r03 1257 +#define _SWAP_3_r13 1258 +#define _SWAP_3_r23 1259 +#define _SWAP_3_r33 1260 +#define _TIER2_RESUME_CHECK_r00 1261 +#define _TIER2_RESUME_CHECK_r11 1262 +#define _TIER2_RESUME_CHECK_r22 1263 +#define _TIER2_RESUME_CHECK_r33 1264 +#define _TO_BOOL_r11 1265 +#define _TO_BOOL_BOOL_r01 1266 +#define _TO_BOOL_BOOL_r11 1267 +#define _TO_BOOL_BOOL_r22 1268 +#define _TO_BOOL_BOOL_r33 1269 +#define _TO_BOOL_INT_r11 1270 +#define _TO_BOOL_LIST_r11 1271 +#define _TO_BOOL_NONE_r01 1272 +#define _TO_BOOL_NONE_r11 1273 +#define _TO_BOOL_NONE_r22 1274 +#define _TO_BOOL_NONE_r33 1275 +#define _TO_BOOL_STR_r11 1276 +#define _TRACE_RECORD_r00 1277 +#define _UNARY_INVERT_r11 1278 +#define _UNARY_NEGATIVE_r11 1279 +#define _UNARY_NOT_r01 1280 +#define _UNARY_NOT_r11 1281 +#define _UNARY_NOT_r22 1282 +#define _UNARY_NOT_r33 1283 +#define _UNPACK_EX_r10 1284 +#define _UNPACK_SEQUENCE_r10 1285 +#define _UNPACK_SEQUENCE_LIST_r10 1286 +#define _UNPACK_SEQUENCE_TUPLE_r10 1287 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1288 +#define _WITH_EXCEPT_START_r33 1289 +#define _YIELD_VALUE_r11 1290 +#define MAX_UOP_REGS_ID 1290 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index bf361233560..0cc38919565 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -11,15 +11,30 @@ extern "C" { #include #include "pycore_uop_ids.h" -extern const uint16_t _PyUop_Flags[MAX_UOP_ID+1]; +#define MAX_CACHED_REGISTER 3 +extern const uint32_t _PyUop_Flags[MAX_UOP_ID+1]; typedef struct _rep_range { uint8_t start; uint8_t stop; } ReplicationRange; extern const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1]; -extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1]; +extern const char * const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1]; extern int _PyUop_num_popped(int opcode, int oparg); +typedef struct _pyuop_tos_cache_entry { + /* input depth is implicit in position */ + int8_t output; + int8_t exit; + int16_t opcode; +} _PyUopTOSentry; +typedef struct _PyUopCachingInfo { + uint8_t best[MAX_CACHED_REGISTER + 1]; + _PyUopTOSentry entries[MAX_CACHED_REGISTER + 1]; +} _PyUopCachingInfo; +extern const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1]; +extern const uint16_t _PyUop_SpillsAndReloads[4][4]; +extern const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1]; + #ifdef NEED_OPCODE_METADATA -const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { +const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_NOP] = HAS_PURE_FLAG, [_CHECK_PERIODIC] = HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CHECK_PERIODIC_IF_NOT_YIELD_FROM] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -44,8 +59,6 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_FAST_BORROW_7] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, [_LOAD_FAST_BORROW] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG, [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_FAST_BORROW_LOAD_FAST_BORROW] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG, [_LOAD_SMALL_INT_0] = 0, [_LOAD_SMALL_INT_1] = 0, @@ -61,8 +74,6 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_STORE_FAST_6] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, [_STORE_FAST_7] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, - [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, - [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, [_POP_TOP] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_POP_TOP_NOP] = 0, [_POP_TOP_INT] = 0, @@ -97,13 +108,10 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_BINARY_OP_SUBTRACT_INT] = HAS_EXIT_FLAG | HAS_PURE_FLAG, [_GUARD_NOS_FLOAT] = HAS_EXIT_FLAG, [_GUARD_TOS_FLOAT] = HAS_EXIT_FLAG, - [_BINARY_OP_MULTIPLY_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_ADD_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_MULTIPLY_FLOAT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_ADD_FLOAT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_SUBTRACT_FLOAT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG, @@ -128,12 +136,12 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_DELETE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_INTRINSIC_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_INTRINSIC_2] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_RETURN_VALUE] = HAS_ESCAPES_FLAG, + [_RETURN_VALUE] = HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG, [_GET_AITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GET_AWAITABLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_SEND_GEN_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_YIELD_VALUE] = HAS_ARG_FLAG, + [_YIELD_VALUE] = HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG, [_POP_EXCEPT] = HAS_ESCAPES_FLAG, [_LOAD_COMMON_CONSTANT] = HAS_ARG_FLAG, [_LOAD_BUILD_CLASS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -181,7 +189,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_TYPE_VERSION] = HAS_EXIT_FLAG, [_GUARD_TYPE_VERSION_AND_LOCK] = HAS_EXIT_FLAG, [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG, - [_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG, [_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_LOAD_ATTR_SLOT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, @@ -237,7 +245,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG, [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, [_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_PY_FRAME_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_PY_FRAME_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG, [_CHECK_FUNCTION_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CHECK_FUNCTION_VERSION_INLINE] = HAS_EXIT_FLAG, [_CHECK_METHOD_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, @@ -256,21 +264,21 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_INIT_CALL_PY_EXACT_ARGS_3] = HAS_PURE_FLAG, [_INIT_CALL_PY_EXACT_ARGS_4] = HAS_PURE_FLAG, [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_PURE_FLAG, - [_PUSH_FRAME] = 0, + [_PUSH_FRAME] = HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG, [_GUARD_NOS_NULL] = HAS_DEOPT_FLAG, [_GUARD_NOS_NOT_NULL] = HAS_EXIT_FLAG, [_GUARD_THIRD_NULL] = HAS_DEOPT_FLAG, [_GUARD_CALLABLE_TYPE_1] = HAS_DEOPT_FLAG, [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_STR_1] = HAS_DEOPT_FLAG, - [_CALL_STR_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_STR_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_TUPLE_1] = HAS_DEOPT_FLAG, - [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG, [_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_BUILTIN_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_BUILTIN_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CALL_BUILTIN_FAST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_BUILTIN_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_LEN] = HAS_DEOPT_FLAG, @@ -278,13 +286,13 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_CALLABLE_ISINSTANCE] = HAS_DEOPT_FLAG, [_CALL_ISINSTANCE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_LIST_APPEND] = HAS_DEOPT_FLAG, - [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, [_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_NOARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_MAYBE_EXPAND_METHOD_KW] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_PY_FRAME_KW] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_PY_FRAME_KW] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG, [_CHECK_FUNCTION_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CHECK_METHOD_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_EXPAND_METHOD_KW] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, @@ -293,7 +301,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_MAKE_CALLARGS_A_TUPLE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG, - [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG, [_BUILD_SLICE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CONVERT_VALUE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_FORMAT_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -315,6 +323,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_STACK_SPACE_OPERAND] = HAS_DEOPT_FLAG, [_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG, [_EXIT_TRACE] = HAS_ESCAPES_FLAG, + [_DYNAMIC_EXIT] = HAS_ESCAPES_FLAG, [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, [_POP_TOP_LOAD_CONST_INLINE] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, @@ -329,15 +338,20 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG, [_LOAD_CONST_UNDER_INLINE] = 0, [_LOAD_CONST_UNDER_INLINE_BORROW] = 0, - [_CHECK_FUNCTION] = HAS_DEOPT_FLAG, [_START_EXECUTOR] = HAS_DEOPT_FLAG, [_MAKE_WARM] = 0, [_FATAL_ERROR] = 0, - [_DEOPT] = 0, - [_HANDLE_PENDING_AND_DEOPT] = HAS_ESCAPES_FLAG, - [_ERROR_POP_N] = HAS_ARG_FLAG, + [_DEOPT] = HAS_SYNC_SP_FLAG, + [_HANDLE_PENDING_AND_DEOPT] = HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG, + [_ERROR_POP_N] = HAS_ARG_FLAG | HAS_SYNC_SP_FLAG, + [_SPILL_OR_RELOAD] = 0, [_TIER2_RESUME_CHECK] = HAS_PERIODIC_FLAG, - [_COLD_EXIT] = HAS_ESCAPES_FLAG, + [_COLD_EXIT] = HAS_SYNC_SP_FLAG, + [_COLD_DYNAMIC_EXIT] = HAS_SYNC_SP_FLAG, + [_GUARD_IP__PUSH_FRAME] = HAS_EXIT_FLAG, + [_GUARD_IP_YIELD_VALUE] = HAS_EXIT_FLAG, + [_GUARD_IP_RETURN_VALUE] = HAS_EXIT_FLAG, + [_GUARD_IP_RETURN_GENERATOR] = HAS_EXIT_FLAG, }; const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = { @@ -350,325 +364,4517 @@ const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = { [_SWAP] = { 2, 4 }, }; -const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { +const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { + [_NOP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _NOP_r00 }, + { 1, 1, _NOP_r11 }, + { 2, 2, _NOP_r22 }, + { 3, 3, _NOP_r33 }, + }, + }, + [_CHECK_PERIODIC] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_PERIODIC_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_PERIODIC_IF_NOT_YIELD_FROM] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_RESUME_CHECK] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _RESUME_CHECK_r00 }, + { 1, 1, _RESUME_CHECK_r11 }, + { 2, 2, _RESUME_CHECK_r22 }, + { 3, 3, _RESUME_CHECK_r33 }, + }, + }, + [_LOAD_FAST_CHECK] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_CHECK_r01 }, + { 2, 1, _LOAD_FAST_CHECK_r12 }, + { 3, 2, _LOAD_FAST_CHECK_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_0] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_0_r01 }, + { 2, 1, _LOAD_FAST_0_r12 }, + { 3, 2, _LOAD_FAST_0_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_1] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_1_r01 }, + { 2, 1, _LOAD_FAST_1_r12 }, + { 3, 2, _LOAD_FAST_1_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_2] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_2_r01 }, + { 2, 1, _LOAD_FAST_2_r12 }, + { 3, 2, _LOAD_FAST_2_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_3] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_3_r01 }, + { 2, 1, _LOAD_FAST_3_r12 }, + { 3, 2, _LOAD_FAST_3_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_4] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_4_r01 }, + { 2, 1, _LOAD_FAST_4_r12 }, + { 3, 2, _LOAD_FAST_4_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_5] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_5_r01 }, + { 2, 1, _LOAD_FAST_5_r12 }, + { 3, 2, _LOAD_FAST_5_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_6] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_6_r01 }, + { 2, 1, _LOAD_FAST_6_r12 }, + { 3, 2, _LOAD_FAST_6_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_7] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_7_r01 }, + { 2, 1, _LOAD_FAST_7_r12 }, + { 3, 2, _LOAD_FAST_7_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_r01 }, + { 2, 1, _LOAD_FAST_r12 }, + { 3, 2, _LOAD_FAST_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_0] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_0_r01 }, + { 2, 1, _LOAD_FAST_BORROW_0_r12 }, + { 3, 2, _LOAD_FAST_BORROW_0_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_1] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_1_r01 }, + { 2, 1, _LOAD_FAST_BORROW_1_r12 }, + { 3, 2, _LOAD_FAST_BORROW_1_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_2] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_2_r01 }, + { 2, 1, _LOAD_FAST_BORROW_2_r12 }, + { 3, 2, _LOAD_FAST_BORROW_2_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_3] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_3_r01 }, + { 2, 1, _LOAD_FAST_BORROW_3_r12 }, + { 3, 2, _LOAD_FAST_BORROW_3_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_4] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_4_r01 }, + { 2, 1, _LOAD_FAST_BORROW_4_r12 }, + { 3, 2, _LOAD_FAST_BORROW_4_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_5] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_5_r01 }, + { 2, 1, _LOAD_FAST_BORROW_5_r12 }, + { 3, 2, _LOAD_FAST_BORROW_5_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_6] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_6_r01 }, + { 2, 1, _LOAD_FAST_BORROW_6_r12 }, + { 3, 2, _LOAD_FAST_BORROW_6_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW_7] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_7_r01 }, + { 2, 1, _LOAD_FAST_BORROW_7_r12 }, + { 3, 2, _LOAD_FAST_BORROW_7_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_BORROW] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_BORROW_r01 }, + { 2, 1, _LOAD_FAST_BORROW_r12 }, + { 3, 2, _LOAD_FAST_BORROW_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FAST_AND_CLEAR] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_FAST_AND_CLEAR_r01 }, + { 2, 1, _LOAD_FAST_AND_CLEAR_r12 }, + { 3, 2, _LOAD_FAST_AND_CLEAR_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_CONST] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_CONST_r01 }, + { 2, 1, _LOAD_CONST_r12 }, + { 3, 2, _LOAD_CONST_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SMALL_INT_0] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_SMALL_INT_0_r01 }, + { 2, 1, _LOAD_SMALL_INT_0_r12 }, + { 3, 2, _LOAD_SMALL_INT_0_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SMALL_INT_1] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_SMALL_INT_1_r01 }, + { 2, 1, _LOAD_SMALL_INT_1_r12 }, + { 3, 2, _LOAD_SMALL_INT_1_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SMALL_INT_2] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_SMALL_INT_2_r01 }, + { 2, 1, _LOAD_SMALL_INT_2_r12 }, + { 3, 2, _LOAD_SMALL_INT_2_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SMALL_INT_3] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_SMALL_INT_3_r01 }, + { 2, 1, _LOAD_SMALL_INT_3_r12 }, + { 3, 2, _LOAD_SMALL_INT_3_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SMALL_INT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_SMALL_INT_r01 }, + { 2, 1, _LOAD_SMALL_INT_r12 }, + { 3, 2, _LOAD_SMALL_INT_r23 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_0] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_0_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_1] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_1_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_2] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_2_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_3] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_3_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_4] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_4_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_5] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_5_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_6] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_6_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST_7] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_7_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_FAST] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_FAST_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_POP_TOP] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _POP_TOP_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_POP_TOP_NOP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _POP_TOP_NOP_r00 }, + { 0, 1, _POP_TOP_NOP_r10 }, + { 1, 2, _POP_TOP_NOP_r21 }, + { 2, 3, _POP_TOP_NOP_r32 }, + }, + }, + [_POP_TOP_INT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _POP_TOP_INT_r00 }, + { 0, 1, _POP_TOP_INT_r10 }, + { 1, 2, _POP_TOP_INT_r21 }, + { 2, 3, _POP_TOP_INT_r32 }, + }, + }, + [_POP_TOP_FLOAT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _POP_TOP_FLOAT_r00 }, + { 0, 1, _POP_TOP_FLOAT_r10 }, + { 1, 2, _POP_TOP_FLOAT_r21 }, + { 2, 3, _POP_TOP_FLOAT_r32 }, + }, + }, + [_POP_TOP_UNICODE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _POP_TOP_UNICODE_r00 }, + { 0, 1, _POP_TOP_UNICODE_r10 }, + { 1, 2, _POP_TOP_UNICODE_r21 }, + { 2, 3, _POP_TOP_UNICODE_r32 }, + }, + }, + [_POP_TWO] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _POP_TWO_r20 }, + { -1, -1, -1 }, + }, + }, + [_PUSH_NULL] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _PUSH_NULL_r01 }, + { 2, 1, _PUSH_NULL_r12 }, + { 3, 2, _PUSH_NULL_r23 }, + { -1, -1, -1 }, + }, + }, + [_END_FOR] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _END_FOR_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_POP_ITER] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _POP_ITER_r20 }, + { -1, -1, -1 }, + }, + }, + [_END_SEND] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _END_SEND_r21 }, + { -1, -1, -1 }, + }, + }, + [_UNARY_NEGATIVE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _UNARY_NEGATIVE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNARY_NOT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _UNARY_NOT_r01 }, + { 1, 1, _UNARY_NOT_r11 }, + { 2, 2, _UNARY_NOT_r22 }, + { 3, 3, _UNARY_NOT_r33 }, + }, + }, + [_TO_BOOL] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _TO_BOOL_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_TO_BOOL_BOOL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _TO_BOOL_BOOL_r01 }, + { 1, 1, _TO_BOOL_BOOL_r11 }, + { 2, 2, _TO_BOOL_BOOL_r22 }, + { 3, 3, _TO_BOOL_BOOL_r33 }, + }, + }, + [_TO_BOOL_INT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _TO_BOOL_INT_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_NOS_LIST] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_LIST_r02 }, + { 2, 1, _GUARD_NOS_LIST_r12 }, + { 2, 2, _GUARD_NOS_LIST_r22 }, + { 3, 3, _GUARD_NOS_LIST_r33 }, + }, + }, + [_GUARD_TOS_LIST] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_LIST_r01 }, + { 1, 1, _GUARD_TOS_LIST_r11 }, + { 2, 2, _GUARD_TOS_LIST_r22 }, + { 3, 3, _GUARD_TOS_LIST_r33 }, + }, + }, + [_GUARD_TOS_SLICE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_SLICE_r01 }, + { 1, 1, _GUARD_TOS_SLICE_r11 }, + { 2, 2, _GUARD_TOS_SLICE_r22 }, + { 3, 3, _GUARD_TOS_SLICE_r33 }, + }, + }, + [_TO_BOOL_LIST] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _TO_BOOL_LIST_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_TO_BOOL_NONE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _TO_BOOL_NONE_r01 }, + { 1, 1, _TO_BOOL_NONE_r11 }, + { 2, 2, _TO_BOOL_NONE_r22 }, + { 3, 3, _TO_BOOL_NONE_r33 }, + }, + }, + [_GUARD_NOS_UNICODE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_UNICODE_r02 }, + { 2, 1, _GUARD_NOS_UNICODE_r12 }, + { 2, 2, _GUARD_NOS_UNICODE_r22 }, + { 3, 3, _GUARD_NOS_UNICODE_r33 }, + }, + }, + [_GUARD_TOS_UNICODE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_UNICODE_r01 }, + { 1, 1, _GUARD_TOS_UNICODE_r11 }, + { 2, 2, _GUARD_TOS_UNICODE_r22 }, + { 3, 3, _GUARD_TOS_UNICODE_r33 }, + }, + }, + [_TO_BOOL_STR] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _TO_BOOL_STR_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_REPLACE_WITH_TRUE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _REPLACE_WITH_TRUE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNARY_INVERT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _UNARY_INVERT_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_NOS_INT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_INT_r02 }, + { 2, 1, _GUARD_NOS_INT_r12 }, + { 2, 2, _GUARD_NOS_INT_r22 }, + { 3, 3, _GUARD_NOS_INT_r33 }, + }, + }, + [_GUARD_TOS_INT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_INT_r01 }, + { 1, 1, _GUARD_TOS_INT_r11 }, + { 2, 2, _GUARD_TOS_INT_r22 }, + { 3, 3, _GUARD_TOS_INT_r33 }, + }, + }, + [_GUARD_NOS_OVERFLOWED] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_OVERFLOWED_r02 }, + { 2, 1, _GUARD_NOS_OVERFLOWED_r12 }, + { 2, 2, _GUARD_NOS_OVERFLOWED_r22 }, + { 3, 3, _GUARD_NOS_OVERFLOWED_r33 }, + }, + }, + [_GUARD_TOS_OVERFLOWED] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_OVERFLOWED_r01 }, + { 1, 1, _GUARD_TOS_OVERFLOWED_r11 }, + { 2, 2, _GUARD_TOS_OVERFLOWED_r22 }, + { 3, 3, _GUARD_TOS_OVERFLOWED_r33 }, + }, + }, + [_BINARY_OP_MULTIPLY_INT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_MULTIPLY_INT_r03 }, + { 3, 1, _BINARY_OP_MULTIPLY_INT_r13 }, + { 3, 2, _BINARY_OP_MULTIPLY_INT_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_ADD_INT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_ADD_INT_r03 }, + { 3, 1, _BINARY_OP_ADD_INT_r13 }, + { 3, 2, _BINARY_OP_ADD_INT_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_SUBTRACT_INT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_SUBTRACT_INT_r03 }, + { 3, 1, _BINARY_OP_SUBTRACT_INT_r13 }, + { 3, 2, _BINARY_OP_SUBTRACT_INT_r23 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_NOS_FLOAT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_FLOAT_r02 }, + { 2, 1, _GUARD_NOS_FLOAT_r12 }, + { 2, 2, _GUARD_NOS_FLOAT_r22 }, + { 3, 3, _GUARD_NOS_FLOAT_r33 }, + }, + }, + [_GUARD_TOS_FLOAT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_FLOAT_r01 }, + { 1, 1, _GUARD_TOS_FLOAT_r11 }, + { 2, 2, _GUARD_TOS_FLOAT_r22 }, + { 3, 3, _GUARD_TOS_FLOAT_r33 }, + }, + }, + [_BINARY_OP_MULTIPLY_FLOAT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_MULTIPLY_FLOAT_r03 }, + { 3, 1, _BINARY_OP_MULTIPLY_FLOAT_r13 }, + { 3, 2, _BINARY_OP_MULTIPLY_FLOAT_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_ADD_FLOAT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_ADD_FLOAT_r03 }, + { 3, 1, _BINARY_OP_ADD_FLOAT_r13 }, + { 3, 2, _BINARY_OP_ADD_FLOAT_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_SUBTRACT_FLOAT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_SUBTRACT_FLOAT_r03 }, + { 3, 1, _BINARY_OP_SUBTRACT_FLOAT_r13 }, + { 3, 2, _BINARY_OP_SUBTRACT_FLOAT_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_ADD_UNICODE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _BINARY_OP_ADD_UNICODE_r03 }, + { 3, 1, _BINARY_OP_ADD_UNICODE_r13 }, + { 3, 2, _BINARY_OP_ADD_UNICODE_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_INPLACE_ADD_UNICODE] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _BINARY_OP_INPLACE_ADD_UNICODE_r20 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_BINARY_OP_EXTEND] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 2, _GUARD_BINARY_OP_EXTEND_r22 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_EXTEND] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_EXTEND_r21 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_SLICE] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _BINARY_SLICE_r31 }, + }, + }, + [_STORE_SLICE] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 3, _STORE_SLICE_r30 }, + }, + }, + [_BINARY_OP_SUBSCR_LIST_INT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_SUBSCR_LIST_INT_r21 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_SUBSCR_LIST_SLICE] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_SUBSCR_LIST_SLICE_r21 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_SUBSCR_STR_INT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_SUBSCR_STR_INT_r21 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_NOS_TUPLE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_TUPLE_r02 }, + { 2, 1, _GUARD_NOS_TUPLE_r12 }, + { 2, 2, _GUARD_NOS_TUPLE_r22 }, + { 3, 3, _GUARD_NOS_TUPLE_r33 }, + }, + }, + [_GUARD_TOS_TUPLE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_TUPLE_r01 }, + { 1, 1, _GUARD_TOS_TUPLE_r11 }, + { 2, 2, _GUARD_TOS_TUPLE_r22 }, + { 3, 3, _GUARD_TOS_TUPLE_r33 }, + }, + }, + [_BINARY_OP_SUBSCR_TUPLE_INT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_SUBSCR_TUPLE_INT_r21 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_NOS_DICT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_DICT_r02 }, + { 2, 1, _GUARD_NOS_DICT_r12 }, + { 2, 2, _GUARD_NOS_DICT_r22 }, + { 3, 3, _GUARD_NOS_DICT_r33 }, + }, + }, + [_GUARD_TOS_DICT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_DICT_r01 }, + { 1, 1, _GUARD_TOS_DICT_r11 }, + { 2, 2, _GUARD_TOS_DICT_r22 }, + { 3, 3, _GUARD_TOS_DICT_r33 }, + }, + }, + [_BINARY_OP_SUBSCR_DICT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_SUBSCR_DICT_r21 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_SUBSCR_CHECK_FUNC] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _BINARY_OP_SUBSCR_CHECK_FUNC_r23 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP_SUBSCR_INIT_CALL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _BINARY_OP_SUBSCR_INIT_CALL_r01 }, + { 1, 1, _BINARY_OP_SUBSCR_INIT_CALL_r11 }, + { 1, 2, _BINARY_OP_SUBSCR_INIT_CALL_r21 }, + { 1, 3, _BINARY_OP_SUBSCR_INIT_CALL_r31 }, + }, + }, + [_LIST_APPEND] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _LIST_APPEND_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_SET_ADD] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _SET_ADD_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_SUBSCR] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 3, _STORE_SUBSCR_r30 }, + }, + }, + [_STORE_SUBSCR_LIST_INT] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 3, _STORE_SUBSCR_LIST_INT_r32 }, + }, + }, + [_STORE_SUBSCR_DICT] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _STORE_SUBSCR_DICT_r31 }, + }, + }, + [_DELETE_SUBSCR] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _DELETE_SUBSCR_r20 }, + { -1, -1, -1 }, + }, + }, + [_CALL_INTRINSIC_1] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _CALL_INTRINSIC_1_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_INTRINSIC_2] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _CALL_INTRINSIC_2_r21 }, + { -1, -1, -1 }, + }, + }, + [_RETURN_VALUE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _RETURN_VALUE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GET_AITER] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _GET_AITER_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GET_ANEXT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 2, 1, _GET_ANEXT_r12 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GET_AWAITABLE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _GET_AWAITABLE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_SEND_GEN_FRAME] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 2, _SEND_GEN_FRAME_r22 }, + { -1, -1, -1 }, + }, + }, + [_YIELD_VALUE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _YIELD_VALUE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_POP_EXCEPT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _POP_EXCEPT_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_COMMON_CONSTANT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_COMMON_CONSTANT_r01 }, + { 2, 1, _LOAD_COMMON_CONSTANT_r12 }, + { 3, 2, _LOAD_COMMON_CONSTANT_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_BUILD_CLASS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _LOAD_BUILD_CLASS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_NAME] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_NAME_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_DELETE_NAME] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _DELETE_NAME_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNPACK_SEQUENCE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _UNPACK_SEQUENCE_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNPACK_SEQUENCE_TWO_TUPLE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 2, 1, _UNPACK_SEQUENCE_TWO_TUPLE_r12 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNPACK_SEQUENCE_TUPLE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _UNPACK_SEQUENCE_TUPLE_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNPACK_SEQUENCE_LIST] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _UNPACK_SEQUENCE_LIST_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_UNPACK_EX] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _UNPACK_EX_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_ATTR] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _STORE_ATTR_r20 }, + { -1, -1, -1 }, + }, + }, + [_DELETE_ATTR] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _DELETE_ATTR_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_GLOBAL] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_GLOBAL_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_DELETE_GLOBAL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _DELETE_GLOBAL_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_LOCALS] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_LOCALS_r01 }, + { 2, 1, _LOAD_LOCALS_r12 }, + { 3, 2, _LOAD_LOCALS_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_NAME] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _LOAD_NAME_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_GLOBAL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _LOAD_GLOBAL_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_PUSH_NULL_CONDITIONAL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _PUSH_NULL_CONDITIONAL_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_GLOBALS_VERSION] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_GLOBALS_VERSION_r00 }, + { 1, 1, _GUARD_GLOBALS_VERSION_r11 }, + { 2, 2, _GUARD_GLOBALS_VERSION_r22 }, + { 3, 3, _GUARD_GLOBALS_VERSION_r33 }, + }, + }, + [_LOAD_GLOBAL_MODULE] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _LOAD_GLOBAL_MODULE_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_GLOBAL_BUILTINS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _LOAD_GLOBAL_BUILTINS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_DELETE_FAST] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _DELETE_FAST_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_MAKE_CELL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _MAKE_CELL_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_DELETE_DEREF] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _DELETE_DEREF_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_FROM_DICT_OR_DEREF] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_FROM_DICT_OR_DEREF_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_DEREF] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _LOAD_DEREF_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_STORE_DEREF] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _STORE_DEREF_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_COPY_FREE_VARS] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _COPY_FREE_VARS_r00 }, + { 1, 1, _COPY_FREE_VARS_r11 }, + { 2, 2, _COPY_FREE_VARS_r22 }, + { 3, 3, _COPY_FREE_VARS_r33 }, + }, + }, + [_BUILD_STRING] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_STRING_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_INTERPOLATION] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_INTERPOLATION_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_TEMPLATE] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BUILD_TEMPLATE_r21 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_TUPLE] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_TUPLE_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_LIST] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_LIST_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LIST_EXTEND] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _LIST_EXTEND_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_SET_UPDATE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _SET_UPDATE_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_SET] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_SET_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_MAP] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_MAP_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_SETUP_ANNOTATIONS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _SETUP_ANNOTATIONS_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_DICT_UPDATE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _DICT_UPDATE_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_DICT_MERGE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _DICT_MERGE_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_MAP_ADD] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _MAP_ADD_r20 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SUPER_ATTR_ATTR] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _LOAD_SUPER_ATTR_ATTR_r31 }, + }, + }, + [_LOAD_SUPER_ATTR_METHOD] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 3, _LOAD_SUPER_ATTR_METHOD_r32 }, + }, + }, + [_LOAD_ATTR] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _LOAD_ATTR_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_TYPE_VERSION] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TYPE_VERSION_r01 }, + { 1, 1, _GUARD_TYPE_VERSION_r11 }, + { 2, 2, _GUARD_TYPE_VERSION_r22 }, + { 3, 3, _GUARD_TYPE_VERSION_r33 }, + }, + }, + [_GUARD_TYPE_VERSION_AND_LOCK] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TYPE_VERSION_AND_LOCK_r01 }, + { 1, 1, _GUARD_TYPE_VERSION_AND_LOCK_r11 }, + { 2, 2, _GUARD_TYPE_VERSION_AND_LOCK_r22 }, + { 3, 3, _GUARD_TYPE_VERSION_AND_LOCK_r33 }, + }, + }, + [_CHECK_MANAGED_OBJECT_HAS_VALUES] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 }, + { 1, 1, _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 }, + { 2, 2, _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 }, + { 3, 3, _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 }, + }, + }, + [_LOAD_ATTR_INSTANCE_VALUE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _LOAD_ATTR_INSTANCE_VALUE_r02 }, + { 2, 1, _LOAD_ATTR_INSTANCE_VALUE_r12 }, + { 3, 2, _LOAD_ATTR_INSTANCE_VALUE_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_MODULE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_MODULE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_WITH_HINT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_WITH_HINT_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_SLOT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_SLOT_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_ATTR_CLASS] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _CHECK_ATTR_CLASS_r01 }, + { 1, 1, _CHECK_ATTR_CLASS_r11 }, + { 2, 2, _CHECK_ATTR_CLASS_r22 }, + { 3, 3, _CHECK_ATTR_CLASS_r33 }, + }, + }, + [_LOAD_ATTR_CLASS] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_CLASS_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_PROPERTY_FRAME] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_PROPERTY_FRAME_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_DORV_NO_DICT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_DORV_NO_DICT_r01 }, + { 1, 1, _GUARD_DORV_NO_DICT_r11 }, + { 2, 2, _GUARD_DORV_NO_DICT_r22 }, + { 3, 3, _GUARD_DORV_NO_DICT_r33 }, + }, + }, + [_STORE_ATTR_INSTANCE_VALUE] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _STORE_ATTR_INSTANCE_VALUE_r21 }, + { -1, -1, -1 }, + }, + }, + [_STORE_ATTR_WITH_HINT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _STORE_ATTR_WITH_HINT_r21 }, + { -1, -1, -1 }, + }, + }, + [_STORE_ATTR_SLOT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _STORE_ATTR_SLOT_r21 }, + { -1, -1, -1 }, + }, + }, + [_COMPARE_OP] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _COMPARE_OP_r21 }, + { -1, -1, -1 }, + }, + }, + [_COMPARE_OP_FLOAT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _COMPARE_OP_FLOAT_r01 }, + { 1, 1, _COMPARE_OP_FLOAT_r11 }, + { 1, 2, _COMPARE_OP_FLOAT_r21 }, + { 2, 3, _COMPARE_OP_FLOAT_r32 }, + }, + }, + [_COMPARE_OP_INT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _COMPARE_OP_INT_r23 }, + { -1, -1, -1 }, + }, + }, + [_COMPARE_OP_STR] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _COMPARE_OP_STR_r21 }, + { -1, -1, -1 }, + }, + }, + [_IS_OP] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _IS_OP_r21 }, + { -1, -1, -1 }, + }, + }, + [_CONTAINS_OP] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _CONTAINS_OP_r21 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_TOS_ANY_SET] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_TOS_ANY_SET_r01 }, + { 1, 1, _GUARD_TOS_ANY_SET_r11 }, + { 2, 2, _GUARD_TOS_ANY_SET_r22 }, + { 3, 3, _GUARD_TOS_ANY_SET_r33 }, + }, + }, + [_CONTAINS_OP_SET] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _CONTAINS_OP_SET_r21 }, + { -1, -1, -1 }, + }, + }, + [_CONTAINS_OP_DICT] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _CONTAINS_OP_DICT_r21 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_EG_MATCH] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 2, _CHECK_EG_MATCH_r22 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_EXC_MATCH] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 2, _CHECK_EXC_MATCH_r22 }, + { -1, -1, -1 }, + }, + }, + [_IMPORT_NAME] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _IMPORT_NAME_r21 }, + { -1, -1, -1 }, + }, + }, + [_IMPORT_FROM] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 2, 1, _IMPORT_FROM_r12 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_IS_NONE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _IS_NONE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GET_LEN] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 2, 1, _GET_LEN_r12 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_MATCH_CLASS] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _MATCH_CLASS_r31 }, + }, + }, + [_MATCH_MAPPING] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _MATCH_MAPPING_r02 }, + { 2, 1, _MATCH_MAPPING_r12 }, + { 3, 2, _MATCH_MAPPING_r23 }, + { -1, -1, -1 }, + }, + }, + [_MATCH_SEQUENCE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _MATCH_SEQUENCE_r02 }, + { 2, 1, _MATCH_SEQUENCE_r12 }, + { 3, 2, _MATCH_SEQUENCE_r23 }, + { -1, -1, -1 }, + }, + }, + [_MATCH_KEYS] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _MATCH_KEYS_r23 }, + { -1, -1, -1 }, + }, + }, + [_GET_ITER] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 2, 1, _GET_ITER_r12 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GET_YIELD_FROM_ITER] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _GET_YIELD_FROM_ITER_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_FOR_ITER_TIER_TWO] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _FOR_ITER_TIER_TWO_r23 }, + { -1, -1, -1 }, + }, + }, + [_ITER_CHECK_LIST] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _ITER_CHECK_LIST_r02 }, + { 2, 1, _ITER_CHECK_LIST_r12 }, + { 2, 2, _ITER_CHECK_LIST_r22 }, + { 3, 3, _ITER_CHECK_LIST_r33 }, + }, + }, + [_GUARD_NOT_EXHAUSTED_LIST] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOT_EXHAUSTED_LIST_r02 }, + { 2, 1, _GUARD_NOT_EXHAUSTED_LIST_r12 }, + { 2, 2, _GUARD_NOT_EXHAUSTED_LIST_r22 }, + { 3, 3, _GUARD_NOT_EXHAUSTED_LIST_r33 }, + }, + }, + [_ITER_NEXT_LIST_TIER_TWO] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _ITER_NEXT_LIST_TIER_TWO_r23 }, + { -1, -1, -1 }, + }, + }, + [_ITER_CHECK_TUPLE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _ITER_CHECK_TUPLE_r02 }, + { 2, 1, _ITER_CHECK_TUPLE_r12 }, + { 2, 2, _ITER_CHECK_TUPLE_r22 }, + { 3, 3, _ITER_CHECK_TUPLE_r33 }, + }, + }, + [_GUARD_NOT_EXHAUSTED_TUPLE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOT_EXHAUSTED_TUPLE_r02 }, + { 2, 1, _GUARD_NOT_EXHAUSTED_TUPLE_r12 }, + { 2, 2, _GUARD_NOT_EXHAUSTED_TUPLE_r22 }, + { 3, 3, _GUARD_NOT_EXHAUSTED_TUPLE_r33 }, + }, + }, + [_ITER_NEXT_TUPLE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _ITER_NEXT_TUPLE_r03 }, + { 3, 1, _ITER_NEXT_TUPLE_r13 }, + { 3, 2, _ITER_NEXT_TUPLE_r23 }, + { -1, -1, -1 }, + }, + }, + [_ITER_CHECK_RANGE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _ITER_CHECK_RANGE_r02 }, + { 2, 1, _ITER_CHECK_RANGE_r12 }, + { 2, 2, _ITER_CHECK_RANGE_r22 }, + { 3, 3, _ITER_CHECK_RANGE_r33 }, + }, + }, + [_GUARD_NOT_EXHAUSTED_RANGE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOT_EXHAUSTED_RANGE_r02 }, + { 2, 1, _GUARD_NOT_EXHAUSTED_RANGE_r12 }, + { 2, 2, _GUARD_NOT_EXHAUSTED_RANGE_r22 }, + { 3, 3, _GUARD_NOT_EXHAUSTED_RANGE_r33 }, + }, + }, + [_ITER_NEXT_RANGE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _ITER_NEXT_RANGE_r03 }, + { 3, 1, _ITER_NEXT_RANGE_r13 }, + { 3, 2, _ITER_NEXT_RANGE_r23 }, + { -1, -1, -1 }, + }, + }, + [_FOR_ITER_GEN_FRAME] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _FOR_ITER_GEN_FRAME_r23 }, + { -1, -1, -1 }, + }, + }, + [_INSERT_NULL] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _INSERT_NULL_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_SPECIAL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _LOAD_SPECIAL_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_WITH_EXCEPT_START] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 3, _WITH_EXCEPT_START_r33 }, + }, + }, + [_PUSH_EXC_INFO] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _PUSH_EXC_INFO_r02 }, + { 2, 1, _PUSH_EXC_INFO_r12 }, + { 3, 2, _PUSH_EXC_INFO_r23 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 }, + { 1, 1, _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 }, + { 2, 2, _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 }, + { 3, 3, _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 }, + }, + }, + [_GUARD_KEYS_VERSION] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _GUARD_KEYS_VERSION_r01 }, + { 1, 1, _GUARD_KEYS_VERSION_r11 }, + { 2, 2, _GUARD_KEYS_VERSION_r22 }, + { 3, 3, _GUARD_KEYS_VERSION_r33 }, + }, + }, + [_LOAD_ATTR_METHOD_WITH_VALUES] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _LOAD_ATTR_METHOD_WITH_VALUES_r02 }, + { 2, 1, _LOAD_ATTR_METHOD_WITH_VALUES_r12 }, + { 3, 2, _LOAD_ATTR_METHOD_WITH_VALUES_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_METHOD_NO_DICT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _LOAD_ATTR_METHOD_NO_DICT_r02 }, + { 2, 1, _LOAD_ATTR_METHOD_NO_DICT_r12 }, + { 3, 2, _LOAD_ATTR_METHOD_NO_DICT_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_ATTR_METHOD_LAZY_DICT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _CHECK_ATTR_METHOD_LAZY_DICT_r01 }, + { 1, 1, _CHECK_ATTR_METHOD_LAZY_DICT_r11 }, + { 2, 2, _CHECK_ATTR_METHOD_LAZY_DICT_r22 }, + { 3, 3, _CHECK_ATTR_METHOD_LAZY_DICT_r33 }, + }, + }, + [_LOAD_ATTR_METHOD_LAZY_DICT] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _LOAD_ATTR_METHOD_LAZY_DICT_r02 }, + { 2, 1, _LOAD_ATTR_METHOD_LAZY_DICT_r12 }, + { 3, 2, _LOAD_ATTR_METHOD_LAZY_DICT_r23 }, + { -1, -1, -1 }, + }, + }, + [_MAYBE_EXPAND_METHOD] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _MAYBE_EXPAND_METHOD_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_PY_FRAME_GENERAL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 1, _PY_FRAME_GENERAL_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_FUNCTION_VERSION] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_FUNCTION_VERSION_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_FUNCTION_VERSION_INLINE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _CHECK_FUNCTION_VERSION_INLINE_r00 }, + { 1, 1, _CHECK_FUNCTION_VERSION_INLINE_r11 }, + { 2, 2, _CHECK_FUNCTION_VERSION_INLINE_r22 }, + { 3, 3, _CHECK_FUNCTION_VERSION_INLINE_r33 }, + }, + }, + [_CHECK_METHOD_VERSION] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_METHOD_VERSION_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_EXPAND_METHOD] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _EXPAND_METHOD_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_IS_NOT_PY_CALLABLE] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_IS_NOT_PY_CALLABLE_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_NON_PY_GENERAL] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_NON_PY_GENERAL_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_PEP_523] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _CHECK_PEP_523_r00 }, + { 1, 1, _CHECK_PEP_523_r11 }, + { 2, 2, _CHECK_PEP_523_r22 }, + { 3, 3, _CHECK_PEP_523_r33 }, + }, + }, + [_CHECK_FUNCTION_EXACT_ARGS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_FUNCTION_EXACT_ARGS_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_STACK_SPACE] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_STACK_SPACE_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_RECURSION_REMAINING] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _CHECK_RECURSION_REMAINING_r00 }, + { 1, 1, _CHECK_RECURSION_REMAINING_r11 }, + { 2, 2, _CHECK_RECURSION_REMAINING_r22 }, + { 3, 3, _CHECK_RECURSION_REMAINING_r33 }, + }, + }, + [_INIT_CALL_PY_EXACT_ARGS_0] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _INIT_CALL_PY_EXACT_ARGS_0_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_INIT_CALL_PY_EXACT_ARGS_1] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _INIT_CALL_PY_EXACT_ARGS_1_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_INIT_CALL_PY_EXACT_ARGS_2] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _INIT_CALL_PY_EXACT_ARGS_2_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_INIT_CALL_PY_EXACT_ARGS_3] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _INIT_CALL_PY_EXACT_ARGS_3_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_INIT_CALL_PY_EXACT_ARGS_4] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _INIT_CALL_PY_EXACT_ARGS_4_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_INIT_CALL_PY_EXACT_ARGS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _INIT_CALL_PY_EXACT_ARGS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_PUSH_FRAME] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 0, _PUSH_FRAME_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_NOS_NULL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_NULL_r02 }, + { 2, 1, _GUARD_NOS_NULL_r12 }, + { 2, 2, _GUARD_NOS_NULL_r22 }, + { 3, 3, _GUARD_NOS_NULL_r33 }, + }, + }, + [_GUARD_NOS_NOT_NULL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_NOT_NULL_r02 }, + { 2, 1, _GUARD_NOS_NOT_NULL_r12 }, + { 2, 2, _GUARD_NOS_NOT_NULL_r22 }, + { 3, 3, _GUARD_NOS_NOT_NULL_r33 }, + }, + }, + [_GUARD_THIRD_NULL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_THIRD_NULL_r03 }, + { 3, 1, _GUARD_THIRD_NULL_r13 }, + { 3, 2, _GUARD_THIRD_NULL_r23 }, + { 3, 3, _GUARD_THIRD_NULL_r33 }, + }, + }, + [_GUARD_CALLABLE_TYPE_1] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_CALLABLE_TYPE_1_r03 }, + { 3, 1, _GUARD_CALLABLE_TYPE_1_r13 }, + { 3, 2, _GUARD_CALLABLE_TYPE_1_r23 }, + { 3, 3, _GUARD_CALLABLE_TYPE_1_r33 }, + }, + }, + [_CALL_TYPE_1] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _CALL_TYPE_1_r31 }, + }, + }, + [_GUARD_CALLABLE_STR_1] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_CALLABLE_STR_1_r03 }, + { 3, 1, _GUARD_CALLABLE_STR_1_r13 }, + { 3, 2, _GUARD_CALLABLE_STR_1_r23 }, + { 3, 3, _GUARD_CALLABLE_STR_1_r33 }, + }, + }, + [_CALL_STR_1] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 3, _CALL_STR_1_r32 }, + }, + }, + [_GUARD_CALLABLE_TUPLE_1] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_CALLABLE_TUPLE_1_r03 }, + { 3, 1, _GUARD_CALLABLE_TUPLE_1_r13 }, + { 3, 2, _GUARD_CALLABLE_TUPLE_1_r23 }, + { 3, 3, _GUARD_CALLABLE_TUPLE_1_r33 }, + }, + }, + [_CALL_TUPLE_1] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 3, _CALL_TUPLE_1_r32 }, + }, + }, + [_CHECK_AND_ALLOCATE_OBJECT] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _CHECK_AND_ALLOCATE_OBJECT_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CREATE_INIT_FRAME] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 1, _CREATE_INIT_FRAME_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_EXIT_INIT_CHECK] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 1, _EXIT_INIT_CHECK_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_BUILTIN_CLASS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_BUILTIN_CLASS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_BUILTIN_O] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 3, 0, _CALL_BUILTIN_O_r03 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_BUILTIN_FAST] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_BUILTIN_FAST_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_BUILTIN_FAST_WITH_KEYWORDS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_CALLABLE_LEN] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_CALLABLE_LEN_r03 }, + { 3, 1, _GUARD_CALLABLE_LEN_r13 }, + { 3, 2, _GUARD_CALLABLE_LEN_r23 }, + { 3, 3, _GUARD_CALLABLE_LEN_r33 }, + }, + }, + [_CALL_LEN] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 3, _CALL_LEN_r33 }, + }, + }, + [_GUARD_CALLABLE_ISINSTANCE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_CALLABLE_ISINSTANCE_r03 }, + { 3, 1, _GUARD_CALLABLE_ISINSTANCE_r13 }, + { 3, 2, _GUARD_CALLABLE_ISINSTANCE_r23 }, + { 3, 3, _GUARD_CALLABLE_ISINSTANCE_r33 }, + }, + }, + [_CALL_ISINSTANCE] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _CALL_ISINSTANCE_r31 }, + }, + }, + [_GUARD_CALLABLE_LIST_APPEND] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _GUARD_CALLABLE_LIST_APPEND_r03 }, + { 3, 1, _GUARD_CALLABLE_LIST_APPEND_r13 }, + { 3, 2, _GUARD_CALLABLE_LIST_APPEND_r23 }, + { 3, 3, _GUARD_CALLABLE_LIST_APPEND_r33 }, + }, + }, + [_CALL_LIST_APPEND] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _CALL_LIST_APPEND_r02 }, + { 2, 1, _CALL_LIST_APPEND_r12 }, + { 2, 2, _CALL_LIST_APPEND_r22 }, + { 2, 3, _CALL_LIST_APPEND_r32 }, + }, + }, + [_CALL_METHOD_DESCRIPTOR_O] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_METHOD_DESCRIPTOR_O_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_METHOD_DESCRIPTOR_NOARGS] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_METHOD_DESCRIPTOR_NOARGS_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_METHOD_DESCRIPTOR_FAST] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _CALL_METHOD_DESCRIPTOR_FAST_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_MAYBE_EXPAND_METHOD_KW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _MAYBE_EXPAND_METHOD_KW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_PY_FRAME_KW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _PY_FRAME_KW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_FUNCTION_VERSION_KW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _CHECK_FUNCTION_VERSION_KW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_METHOD_VERSION_KW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _CHECK_METHOD_VERSION_KW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_EXPAND_METHOD_KW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _EXPAND_METHOD_KW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CHECK_IS_NOT_PY_CALLABLE_KW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _CHECK_IS_NOT_PY_CALLABLE_KW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CALL_KW_NON_PY] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _CALL_KW_NON_PY_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_MAKE_CALLARGS_A_TUPLE] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 3, _MAKE_CALLARGS_A_TUPLE_r33 }, + }, + }, + [_MAKE_FUNCTION] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _MAKE_FUNCTION_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_SET_FUNCTION_ATTRIBUTE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _SET_FUNCTION_ATTRIBUTE_r01 }, + { 1, 1, _SET_FUNCTION_ATTRIBUTE_r11 }, + { 1, 2, _SET_FUNCTION_ATTRIBUTE_r21 }, + { 2, 3, _SET_FUNCTION_ATTRIBUTE_r32 }, + }, + }, + [_RETURN_GENERATOR] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _RETURN_GENERATOR_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BUILD_SLICE] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _BUILD_SLICE_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_CONVERT_VALUE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _CONVERT_VALUE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_FORMAT_SIMPLE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _FORMAT_SIMPLE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_FORMAT_WITH_SPEC] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _FORMAT_WITH_SPEC_r21 }, + { -1, -1, -1 }, + }, + }, + [_COPY_1] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _COPY_1_r02 }, + { 2, 1, _COPY_1_r12 }, + { 3, 2, _COPY_1_r23 }, + { -1, -1, -1 }, + }, + }, + [_COPY_2] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 3, 0, _COPY_2_r03 }, + { 3, 1, _COPY_2_r13 }, + { 3, 2, _COPY_2_r23 }, + { -1, -1, -1 }, + }, + }, + [_COPY_3] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _COPY_3_r03 }, + { 3, 1, _COPY_3_r13 }, + { 3, 2, _COPY_3_r23 }, + { 3, 3, _COPY_3_r33 }, + }, + }, + [_COPY] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 1, 0, _COPY_r01 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_BINARY_OP] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _BINARY_OP_r21 }, + { -1, -1, -1 }, + }, + }, + [_SWAP_2] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _SWAP_2_r02 }, + { 2, 1, _SWAP_2_r12 }, + { 2, 2, _SWAP_2_r22 }, + { 3, 3, _SWAP_2_r33 }, + }, + }, + [_SWAP_3] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _SWAP_3_r03 }, + { 3, 1, _SWAP_3_r13 }, + { 3, 2, _SWAP_3_r23 }, + { 3, 3, _SWAP_3_r33 }, + }, + }, + [_SWAP] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _SWAP_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_IS_TRUE_POP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IS_TRUE_POP_r00 }, + { 0, 0, _GUARD_IS_TRUE_POP_r10 }, + { 1, 1, _GUARD_IS_TRUE_POP_r21 }, + { 2, 2, _GUARD_IS_TRUE_POP_r32 }, + }, + }, + [_GUARD_IS_FALSE_POP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IS_FALSE_POP_r00 }, + { 0, 0, _GUARD_IS_FALSE_POP_r10 }, + { 1, 1, _GUARD_IS_FALSE_POP_r21 }, + { 2, 2, _GUARD_IS_FALSE_POP_r32 }, + }, + }, + [_GUARD_IS_NONE_POP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IS_NONE_POP_r00 }, + { 0, 0, _GUARD_IS_NONE_POP_r10 }, + { 1, 1, _GUARD_IS_NONE_POP_r21 }, + { 2, 2, _GUARD_IS_NONE_POP_r32 }, + }, + }, + [_GUARD_IS_NOT_NONE_POP] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 0, 0, _GUARD_IS_NOT_NONE_POP_r10 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_JUMP_TO_TOP] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _JUMP_TO_TOP_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_SET_IP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _SET_IP_r00 }, + { 1, 1, _SET_IP_r11 }, + { 2, 2, _SET_IP_r22 }, + { 3, 3, _SET_IP_r33 }, + }, + }, + [_CHECK_STACK_SPACE_OPERAND] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _CHECK_STACK_SPACE_OPERAND_r00 }, + { 1, 1, _CHECK_STACK_SPACE_OPERAND_r11 }, + { 2, 2, _CHECK_STACK_SPACE_OPERAND_r22 }, + { 3, 3, _CHECK_STACK_SPACE_OPERAND_r33 }, + }, + }, + [_SAVE_RETURN_OFFSET] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _SAVE_RETURN_OFFSET_r00 }, + { 1, 1, _SAVE_RETURN_OFFSET_r11 }, + { 2, 2, _SAVE_RETURN_OFFSET_r22 }, + { 3, 3, _SAVE_RETURN_OFFSET_r33 }, + }, + }, + [_EXIT_TRACE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _EXIT_TRACE_r00 }, + { 0, 0, _EXIT_TRACE_r10 }, + { 0, 0, _EXIT_TRACE_r20 }, + { 0, 0, _EXIT_TRACE_r30 }, + }, + }, + [_DYNAMIC_EXIT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _DYNAMIC_EXIT_r00 }, + { 0, 0, _DYNAMIC_EXIT_r10 }, + { 0, 0, _DYNAMIC_EXIT_r20 }, + { 0, 0, _DYNAMIC_EXIT_r30 }, + }, + }, + [_CHECK_VALIDITY] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _CHECK_VALIDITY_r00 }, + { 1, 1, _CHECK_VALIDITY_r11 }, + { 2, 2, _CHECK_VALIDITY_r22 }, + { 3, 3, _CHECK_VALIDITY_r33 }, + }, + }, + [_LOAD_CONST_INLINE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_CONST_INLINE_r01 }, + { 2, 1, _LOAD_CONST_INLINE_r12 }, + { 3, 2, _LOAD_CONST_INLINE_r23 }, + { -1, -1, -1 }, + }, + }, + [_POP_TOP_LOAD_CONST_INLINE] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _POP_TOP_LOAD_CONST_INLINE_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_CONST_INLINE_BORROW] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 1, 0, _LOAD_CONST_INLINE_BORROW_r01 }, + { 2, 1, _LOAD_CONST_INLINE_BORROW_r12 }, + { 3, 2, _LOAD_CONST_INLINE_BORROW_r23 }, + { -1, -1, -1 }, + }, + }, + [_POP_CALL] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 2, _POP_CALL_r20 }, + { -1, -1, -1 }, + }, + }, + [_POP_CALL_ONE] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 3, _POP_CALL_ONE_r30 }, + }, + }, + [_POP_CALL_TWO] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 0, 3, _POP_CALL_TWO_r30 }, + }, + }, + [_POP_TOP_LOAD_CONST_INLINE_BORROW] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 1, 1, _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_POP_TWO_LOAD_CONST_INLINE_BORROW] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 }, + { -1, -1, -1 }, + }, + }, + [_POP_CALL_LOAD_CONST_INLINE_BORROW] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 2, _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 }, + { -1, -1, -1 }, + }, + }, + [_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 }, + }, + }, + [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW] = { + .best = { 3, 3, 3, 3 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { 1, 3, _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 }, + }, + }, + [_LOAD_CONST_UNDER_INLINE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _LOAD_CONST_UNDER_INLINE_r02 }, + { 2, 1, _LOAD_CONST_UNDER_INLINE_r12 }, + { 3, 2, _LOAD_CONST_UNDER_INLINE_r23 }, + { -1, -1, -1 }, + }, + }, + [_LOAD_CONST_UNDER_INLINE_BORROW] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _LOAD_CONST_UNDER_INLINE_BORROW_r02 }, + { 2, 1, _LOAD_CONST_UNDER_INLINE_BORROW_r12 }, + { 3, 2, _LOAD_CONST_UNDER_INLINE_BORROW_r23 }, + { -1, -1, -1 }, + }, + }, + [_START_EXECUTOR] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _START_EXECUTOR_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_MAKE_WARM] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _MAKE_WARM_r00 }, + { 1, 1, _MAKE_WARM_r11 }, + { 2, 2, _MAKE_WARM_r22 }, + { 3, 3, _MAKE_WARM_r33 }, + }, + }, + [_FATAL_ERROR] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _FATAL_ERROR_r00 }, + { 1, 1, _FATAL_ERROR_r11 }, + { 2, 2, _FATAL_ERROR_r22 }, + { 3, 3, _FATAL_ERROR_r33 }, + }, + }, + [_DEOPT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _DEOPT_r00 }, + { 0, 0, _DEOPT_r10 }, + { 0, 0, _DEOPT_r20 }, + { 0, 0, _DEOPT_r30 }, + }, + }, + [_HANDLE_PENDING_AND_DEOPT] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _HANDLE_PENDING_AND_DEOPT_r00 }, + { 0, 0, _HANDLE_PENDING_AND_DEOPT_r10 }, + { 0, 0, _HANDLE_PENDING_AND_DEOPT_r20 }, + { 0, 0, _HANDLE_PENDING_AND_DEOPT_r30 }, + }, + }, + [_ERROR_POP_N] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _ERROR_POP_N_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_TIER2_RESUME_CHECK] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _TIER2_RESUME_CHECK_r00 }, + { 1, 1, _TIER2_RESUME_CHECK_r11 }, + { 2, 2, _TIER2_RESUME_CHECK_r22 }, + { 3, 3, _TIER2_RESUME_CHECK_r33 }, + }, + }, + [_COLD_EXIT] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _COLD_EXIT_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_COLD_DYNAMIC_EXIT] = { + .best = { 0, 0, 0, 0 }, + .entries = { + { 0, 0, _COLD_DYNAMIC_EXIT_r00 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, + [_GUARD_IP__PUSH_FRAME] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IP__PUSH_FRAME_r00 }, + { 1, 1, _GUARD_IP__PUSH_FRAME_r11 }, + { 2, 2, _GUARD_IP__PUSH_FRAME_r22 }, + { 3, 3, _GUARD_IP__PUSH_FRAME_r33 }, + }, + }, + [_GUARD_IP_YIELD_VALUE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IP_YIELD_VALUE_r00 }, + { 1, 1, _GUARD_IP_YIELD_VALUE_r11 }, + { 2, 2, _GUARD_IP_YIELD_VALUE_r22 }, + { 3, 3, _GUARD_IP_YIELD_VALUE_r33 }, + }, + }, + [_GUARD_IP_RETURN_VALUE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IP_RETURN_VALUE_r00 }, + { 1, 1, _GUARD_IP_RETURN_VALUE_r11 }, + { 2, 2, _GUARD_IP_RETURN_VALUE_r22 }, + { 3, 3, _GUARD_IP_RETURN_VALUE_r33 }, + }, + }, + [_GUARD_IP_RETURN_GENERATOR] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_IP_RETURN_GENERATOR_r00 }, + { 1, 1, _GUARD_IP_RETURN_GENERATOR_r11 }, + { 2, 2, _GUARD_IP_RETURN_GENERATOR_r22 }, + { 3, 3, _GUARD_IP_RETURN_GENERATOR_r33 }, + }, + }, +}; + +const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { + [_NOP_r00] = _NOP, + [_NOP_r11] = _NOP, + [_NOP_r22] = _NOP, + [_NOP_r33] = _NOP, + [_CHECK_PERIODIC_r00] = _CHECK_PERIODIC, + [_CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00] = _CHECK_PERIODIC_IF_NOT_YIELD_FROM, + [_RESUME_CHECK_r00] = _RESUME_CHECK, + [_RESUME_CHECK_r11] = _RESUME_CHECK, + [_RESUME_CHECK_r22] = _RESUME_CHECK, + [_RESUME_CHECK_r33] = _RESUME_CHECK, + [_LOAD_FAST_CHECK_r01] = _LOAD_FAST_CHECK, + [_LOAD_FAST_CHECK_r12] = _LOAD_FAST_CHECK, + [_LOAD_FAST_CHECK_r23] = _LOAD_FAST_CHECK, + [_LOAD_FAST_0_r01] = _LOAD_FAST_0, + [_LOAD_FAST_0_r12] = _LOAD_FAST_0, + [_LOAD_FAST_0_r23] = _LOAD_FAST_0, + [_LOAD_FAST_1_r01] = _LOAD_FAST_1, + [_LOAD_FAST_1_r12] = _LOAD_FAST_1, + [_LOAD_FAST_1_r23] = _LOAD_FAST_1, + [_LOAD_FAST_2_r01] = _LOAD_FAST_2, + [_LOAD_FAST_2_r12] = _LOAD_FAST_2, + [_LOAD_FAST_2_r23] = _LOAD_FAST_2, + [_LOAD_FAST_3_r01] = _LOAD_FAST_3, + [_LOAD_FAST_3_r12] = _LOAD_FAST_3, + [_LOAD_FAST_3_r23] = _LOAD_FAST_3, + [_LOAD_FAST_4_r01] = _LOAD_FAST_4, + [_LOAD_FAST_4_r12] = _LOAD_FAST_4, + [_LOAD_FAST_4_r23] = _LOAD_FAST_4, + [_LOAD_FAST_5_r01] = _LOAD_FAST_5, + [_LOAD_FAST_5_r12] = _LOAD_FAST_5, + [_LOAD_FAST_5_r23] = _LOAD_FAST_5, + [_LOAD_FAST_6_r01] = _LOAD_FAST_6, + [_LOAD_FAST_6_r12] = _LOAD_FAST_6, + [_LOAD_FAST_6_r23] = _LOAD_FAST_6, + [_LOAD_FAST_7_r01] = _LOAD_FAST_7, + [_LOAD_FAST_7_r12] = _LOAD_FAST_7, + [_LOAD_FAST_7_r23] = _LOAD_FAST_7, + [_LOAD_FAST_r01] = _LOAD_FAST, + [_LOAD_FAST_r12] = _LOAD_FAST, + [_LOAD_FAST_r23] = _LOAD_FAST, + [_LOAD_FAST_BORROW_0_r01] = _LOAD_FAST_BORROW_0, + [_LOAD_FAST_BORROW_0_r12] = _LOAD_FAST_BORROW_0, + [_LOAD_FAST_BORROW_0_r23] = _LOAD_FAST_BORROW_0, + [_LOAD_FAST_BORROW_1_r01] = _LOAD_FAST_BORROW_1, + [_LOAD_FAST_BORROW_1_r12] = _LOAD_FAST_BORROW_1, + [_LOAD_FAST_BORROW_1_r23] = _LOAD_FAST_BORROW_1, + [_LOAD_FAST_BORROW_2_r01] = _LOAD_FAST_BORROW_2, + [_LOAD_FAST_BORROW_2_r12] = _LOAD_FAST_BORROW_2, + [_LOAD_FAST_BORROW_2_r23] = _LOAD_FAST_BORROW_2, + [_LOAD_FAST_BORROW_3_r01] = _LOAD_FAST_BORROW_3, + [_LOAD_FAST_BORROW_3_r12] = _LOAD_FAST_BORROW_3, + [_LOAD_FAST_BORROW_3_r23] = _LOAD_FAST_BORROW_3, + [_LOAD_FAST_BORROW_4_r01] = _LOAD_FAST_BORROW_4, + [_LOAD_FAST_BORROW_4_r12] = _LOAD_FAST_BORROW_4, + [_LOAD_FAST_BORROW_4_r23] = _LOAD_FAST_BORROW_4, + [_LOAD_FAST_BORROW_5_r01] = _LOAD_FAST_BORROW_5, + [_LOAD_FAST_BORROW_5_r12] = _LOAD_FAST_BORROW_5, + [_LOAD_FAST_BORROW_5_r23] = _LOAD_FAST_BORROW_5, + [_LOAD_FAST_BORROW_6_r01] = _LOAD_FAST_BORROW_6, + [_LOAD_FAST_BORROW_6_r12] = _LOAD_FAST_BORROW_6, + [_LOAD_FAST_BORROW_6_r23] = _LOAD_FAST_BORROW_6, + [_LOAD_FAST_BORROW_7_r01] = _LOAD_FAST_BORROW_7, + [_LOAD_FAST_BORROW_7_r12] = _LOAD_FAST_BORROW_7, + [_LOAD_FAST_BORROW_7_r23] = _LOAD_FAST_BORROW_7, + [_LOAD_FAST_BORROW_r01] = _LOAD_FAST_BORROW, + [_LOAD_FAST_BORROW_r12] = _LOAD_FAST_BORROW, + [_LOAD_FAST_BORROW_r23] = _LOAD_FAST_BORROW, + [_LOAD_FAST_AND_CLEAR_r01] = _LOAD_FAST_AND_CLEAR, + [_LOAD_FAST_AND_CLEAR_r12] = _LOAD_FAST_AND_CLEAR, + [_LOAD_FAST_AND_CLEAR_r23] = _LOAD_FAST_AND_CLEAR, + [_LOAD_CONST_r01] = _LOAD_CONST, + [_LOAD_CONST_r12] = _LOAD_CONST, + [_LOAD_CONST_r23] = _LOAD_CONST, + [_LOAD_SMALL_INT_0_r01] = _LOAD_SMALL_INT_0, + [_LOAD_SMALL_INT_0_r12] = _LOAD_SMALL_INT_0, + [_LOAD_SMALL_INT_0_r23] = _LOAD_SMALL_INT_0, + [_LOAD_SMALL_INT_1_r01] = _LOAD_SMALL_INT_1, + [_LOAD_SMALL_INT_1_r12] = _LOAD_SMALL_INT_1, + [_LOAD_SMALL_INT_1_r23] = _LOAD_SMALL_INT_1, + [_LOAD_SMALL_INT_2_r01] = _LOAD_SMALL_INT_2, + [_LOAD_SMALL_INT_2_r12] = _LOAD_SMALL_INT_2, + [_LOAD_SMALL_INT_2_r23] = _LOAD_SMALL_INT_2, + [_LOAD_SMALL_INT_3_r01] = _LOAD_SMALL_INT_3, + [_LOAD_SMALL_INT_3_r12] = _LOAD_SMALL_INT_3, + [_LOAD_SMALL_INT_3_r23] = _LOAD_SMALL_INT_3, + [_LOAD_SMALL_INT_r01] = _LOAD_SMALL_INT, + [_LOAD_SMALL_INT_r12] = _LOAD_SMALL_INT, + [_LOAD_SMALL_INT_r23] = _LOAD_SMALL_INT, + [_STORE_FAST_0_r10] = _STORE_FAST_0, + [_STORE_FAST_1_r10] = _STORE_FAST_1, + [_STORE_FAST_2_r10] = _STORE_FAST_2, + [_STORE_FAST_3_r10] = _STORE_FAST_3, + [_STORE_FAST_4_r10] = _STORE_FAST_4, + [_STORE_FAST_5_r10] = _STORE_FAST_5, + [_STORE_FAST_6_r10] = _STORE_FAST_6, + [_STORE_FAST_7_r10] = _STORE_FAST_7, + [_STORE_FAST_r10] = _STORE_FAST, + [_POP_TOP_r10] = _POP_TOP, + [_POP_TOP_NOP_r00] = _POP_TOP_NOP, + [_POP_TOP_NOP_r10] = _POP_TOP_NOP, + [_POP_TOP_NOP_r21] = _POP_TOP_NOP, + [_POP_TOP_NOP_r32] = _POP_TOP_NOP, + [_POP_TOP_INT_r00] = _POP_TOP_INT, + [_POP_TOP_INT_r10] = _POP_TOP_INT, + [_POP_TOP_INT_r21] = _POP_TOP_INT, + [_POP_TOP_INT_r32] = _POP_TOP_INT, + [_POP_TOP_FLOAT_r00] = _POP_TOP_FLOAT, + [_POP_TOP_FLOAT_r10] = _POP_TOP_FLOAT, + [_POP_TOP_FLOAT_r21] = _POP_TOP_FLOAT, + [_POP_TOP_FLOAT_r32] = _POP_TOP_FLOAT, + [_POP_TOP_UNICODE_r00] = _POP_TOP_UNICODE, + [_POP_TOP_UNICODE_r10] = _POP_TOP_UNICODE, + [_POP_TOP_UNICODE_r21] = _POP_TOP_UNICODE, + [_POP_TOP_UNICODE_r32] = _POP_TOP_UNICODE, + [_POP_TWO_r20] = _POP_TWO, + [_PUSH_NULL_r01] = _PUSH_NULL, + [_PUSH_NULL_r12] = _PUSH_NULL, + [_PUSH_NULL_r23] = _PUSH_NULL, + [_END_FOR_r10] = _END_FOR, + [_POP_ITER_r20] = _POP_ITER, + [_END_SEND_r21] = _END_SEND, + [_UNARY_NEGATIVE_r11] = _UNARY_NEGATIVE, + [_UNARY_NOT_r01] = _UNARY_NOT, + [_UNARY_NOT_r11] = _UNARY_NOT, + [_UNARY_NOT_r22] = _UNARY_NOT, + [_UNARY_NOT_r33] = _UNARY_NOT, + [_TO_BOOL_r11] = _TO_BOOL, + [_TO_BOOL_BOOL_r01] = _TO_BOOL_BOOL, + [_TO_BOOL_BOOL_r11] = _TO_BOOL_BOOL, + [_TO_BOOL_BOOL_r22] = _TO_BOOL_BOOL, + [_TO_BOOL_BOOL_r33] = _TO_BOOL_BOOL, + [_TO_BOOL_INT_r11] = _TO_BOOL_INT, + [_GUARD_NOS_LIST_r02] = _GUARD_NOS_LIST, + [_GUARD_NOS_LIST_r12] = _GUARD_NOS_LIST, + [_GUARD_NOS_LIST_r22] = _GUARD_NOS_LIST, + [_GUARD_NOS_LIST_r33] = _GUARD_NOS_LIST, + [_GUARD_TOS_LIST_r01] = _GUARD_TOS_LIST, + [_GUARD_TOS_LIST_r11] = _GUARD_TOS_LIST, + [_GUARD_TOS_LIST_r22] = _GUARD_TOS_LIST, + [_GUARD_TOS_LIST_r33] = _GUARD_TOS_LIST, + [_GUARD_TOS_SLICE_r01] = _GUARD_TOS_SLICE, + [_GUARD_TOS_SLICE_r11] = _GUARD_TOS_SLICE, + [_GUARD_TOS_SLICE_r22] = _GUARD_TOS_SLICE, + [_GUARD_TOS_SLICE_r33] = _GUARD_TOS_SLICE, + [_TO_BOOL_LIST_r11] = _TO_BOOL_LIST, + [_TO_BOOL_NONE_r01] = _TO_BOOL_NONE, + [_TO_BOOL_NONE_r11] = _TO_BOOL_NONE, + [_TO_BOOL_NONE_r22] = _TO_BOOL_NONE, + [_TO_BOOL_NONE_r33] = _TO_BOOL_NONE, + [_GUARD_NOS_UNICODE_r02] = _GUARD_NOS_UNICODE, + [_GUARD_NOS_UNICODE_r12] = _GUARD_NOS_UNICODE, + [_GUARD_NOS_UNICODE_r22] = _GUARD_NOS_UNICODE, + [_GUARD_NOS_UNICODE_r33] = _GUARD_NOS_UNICODE, + [_GUARD_TOS_UNICODE_r01] = _GUARD_TOS_UNICODE, + [_GUARD_TOS_UNICODE_r11] = _GUARD_TOS_UNICODE, + [_GUARD_TOS_UNICODE_r22] = _GUARD_TOS_UNICODE, + [_GUARD_TOS_UNICODE_r33] = _GUARD_TOS_UNICODE, + [_TO_BOOL_STR_r11] = _TO_BOOL_STR, + [_REPLACE_WITH_TRUE_r11] = _REPLACE_WITH_TRUE, + [_UNARY_INVERT_r11] = _UNARY_INVERT, + [_GUARD_NOS_INT_r02] = _GUARD_NOS_INT, + [_GUARD_NOS_INT_r12] = _GUARD_NOS_INT, + [_GUARD_NOS_INT_r22] = _GUARD_NOS_INT, + [_GUARD_NOS_INT_r33] = _GUARD_NOS_INT, + [_GUARD_TOS_INT_r01] = _GUARD_TOS_INT, + [_GUARD_TOS_INT_r11] = _GUARD_TOS_INT, + [_GUARD_TOS_INT_r22] = _GUARD_TOS_INT, + [_GUARD_TOS_INT_r33] = _GUARD_TOS_INT, + [_GUARD_NOS_OVERFLOWED_r02] = _GUARD_NOS_OVERFLOWED, + [_GUARD_NOS_OVERFLOWED_r12] = _GUARD_NOS_OVERFLOWED, + [_GUARD_NOS_OVERFLOWED_r22] = _GUARD_NOS_OVERFLOWED, + [_GUARD_NOS_OVERFLOWED_r33] = _GUARD_NOS_OVERFLOWED, + [_GUARD_TOS_OVERFLOWED_r01] = _GUARD_TOS_OVERFLOWED, + [_GUARD_TOS_OVERFLOWED_r11] = _GUARD_TOS_OVERFLOWED, + [_GUARD_TOS_OVERFLOWED_r22] = _GUARD_TOS_OVERFLOWED, + [_GUARD_TOS_OVERFLOWED_r33] = _GUARD_TOS_OVERFLOWED, + [_BINARY_OP_MULTIPLY_INT_r03] = _BINARY_OP_MULTIPLY_INT, + [_BINARY_OP_MULTIPLY_INT_r13] = _BINARY_OP_MULTIPLY_INT, + [_BINARY_OP_MULTIPLY_INT_r23] = _BINARY_OP_MULTIPLY_INT, + [_BINARY_OP_ADD_INT_r03] = _BINARY_OP_ADD_INT, + [_BINARY_OP_ADD_INT_r13] = _BINARY_OP_ADD_INT, + [_BINARY_OP_ADD_INT_r23] = _BINARY_OP_ADD_INT, + [_BINARY_OP_SUBTRACT_INT_r03] = _BINARY_OP_SUBTRACT_INT, + [_BINARY_OP_SUBTRACT_INT_r13] = _BINARY_OP_SUBTRACT_INT, + [_BINARY_OP_SUBTRACT_INT_r23] = _BINARY_OP_SUBTRACT_INT, + [_GUARD_NOS_FLOAT_r02] = _GUARD_NOS_FLOAT, + [_GUARD_NOS_FLOAT_r12] = _GUARD_NOS_FLOAT, + [_GUARD_NOS_FLOAT_r22] = _GUARD_NOS_FLOAT, + [_GUARD_NOS_FLOAT_r33] = _GUARD_NOS_FLOAT, + [_GUARD_TOS_FLOAT_r01] = _GUARD_TOS_FLOAT, + [_GUARD_TOS_FLOAT_r11] = _GUARD_TOS_FLOAT, + [_GUARD_TOS_FLOAT_r22] = _GUARD_TOS_FLOAT, + [_GUARD_TOS_FLOAT_r33] = _GUARD_TOS_FLOAT, + [_BINARY_OP_MULTIPLY_FLOAT_r03] = _BINARY_OP_MULTIPLY_FLOAT, + [_BINARY_OP_MULTIPLY_FLOAT_r13] = _BINARY_OP_MULTIPLY_FLOAT, + [_BINARY_OP_MULTIPLY_FLOAT_r23] = _BINARY_OP_MULTIPLY_FLOAT, + [_BINARY_OP_ADD_FLOAT_r03] = _BINARY_OP_ADD_FLOAT, + [_BINARY_OP_ADD_FLOAT_r13] = _BINARY_OP_ADD_FLOAT, + [_BINARY_OP_ADD_FLOAT_r23] = _BINARY_OP_ADD_FLOAT, + [_BINARY_OP_SUBTRACT_FLOAT_r03] = _BINARY_OP_SUBTRACT_FLOAT, + [_BINARY_OP_SUBTRACT_FLOAT_r13] = _BINARY_OP_SUBTRACT_FLOAT, + [_BINARY_OP_SUBTRACT_FLOAT_r23] = _BINARY_OP_SUBTRACT_FLOAT, + [_BINARY_OP_ADD_UNICODE_r03] = _BINARY_OP_ADD_UNICODE, + [_BINARY_OP_ADD_UNICODE_r13] = _BINARY_OP_ADD_UNICODE, + [_BINARY_OP_ADD_UNICODE_r23] = _BINARY_OP_ADD_UNICODE, + [_BINARY_OP_INPLACE_ADD_UNICODE_r20] = _BINARY_OP_INPLACE_ADD_UNICODE, + [_GUARD_BINARY_OP_EXTEND_r22] = _GUARD_BINARY_OP_EXTEND, + [_BINARY_OP_EXTEND_r21] = _BINARY_OP_EXTEND, + [_BINARY_SLICE_r31] = _BINARY_SLICE, + [_STORE_SLICE_r30] = _STORE_SLICE, + [_BINARY_OP_SUBSCR_LIST_INT_r21] = _BINARY_OP_SUBSCR_LIST_INT, + [_BINARY_OP_SUBSCR_LIST_SLICE_r21] = _BINARY_OP_SUBSCR_LIST_SLICE, + [_BINARY_OP_SUBSCR_STR_INT_r21] = _BINARY_OP_SUBSCR_STR_INT, + [_GUARD_NOS_TUPLE_r02] = _GUARD_NOS_TUPLE, + [_GUARD_NOS_TUPLE_r12] = _GUARD_NOS_TUPLE, + [_GUARD_NOS_TUPLE_r22] = _GUARD_NOS_TUPLE, + [_GUARD_NOS_TUPLE_r33] = _GUARD_NOS_TUPLE, + [_GUARD_TOS_TUPLE_r01] = _GUARD_TOS_TUPLE, + [_GUARD_TOS_TUPLE_r11] = _GUARD_TOS_TUPLE, + [_GUARD_TOS_TUPLE_r22] = _GUARD_TOS_TUPLE, + [_GUARD_TOS_TUPLE_r33] = _GUARD_TOS_TUPLE, + [_BINARY_OP_SUBSCR_TUPLE_INT_r21] = _BINARY_OP_SUBSCR_TUPLE_INT, + [_GUARD_NOS_DICT_r02] = _GUARD_NOS_DICT, + [_GUARD_NOS_DICT_r12] = _GUARD_NOS_DICT, + [_GUARD_NOS_DICT_r22] = _GUARD_NOS_DICT, + [_GUARD_NOS_DICT_r33] = _GUARD_NOS_DICT, + [_GUARD_TOS_DICT_r01] = _GUARD_TOS_DICT, + [_GUARD_TOS_DICT_r11] = _GUARD_TOS_DICT, + [_GUARD_TOS_DICT_r22] = _GUARD_TOS_DICT, + [_GUARD_TOS_DICT_r33] = _GUARD_TOS_DICT, + [_BINARY_OP_SUBSCR_DICT_r21] = _BINARY_OP_SUBSCR_DICT, + [_BINARY_OP_SUBSCR_CHECK_FUNC_r23] = _BINARY_OP_SUBSCR_CHECK_FUNC, + [_BINARY_OP_SUBSCR_INIT_CALL_r01] = _BINARY_OP_SUBSCR_INIT_CALL, + [_BINARY_OP_SUBSCR_INIT_CALL_r11] = _BINARY_OP_SUBSCR_INIT_CALL, + [_BINARY_OP_SUBSCR_INIT_CALL_r21] = _BINARY_OP_SUBSCR_INIT_CALL, + [_BINARY_OP_SUBSCR_INIT_CALL_r31] = _BINARY_OP_SUBSCR_INIT_CALL, + [_LIST_APPEND_r10] = _LIST_APPEND, + [_SET_ADD_r10] = _SET_ADD, + [_STORE_SUBSCR_r30] = _STORE_SUBSCR, + [_STORE_SUBSCR_LIST_INT_r32] = _STORE_SUBSCR_LIST_INT, + [_STORE_SUBSCR_DICT_r31] = _STORE_SUBSCR_DICT, + [_DELETE_SUBSCR_r20] = _DELETE_SUBSCR, + [_CALL_INTRINSIC_1_r11] = _CALL_INTRINSIC_1, + [_CALL_INTRINSIC_2_r21] = _CALL_INTRINSIC_2, + [_RETURN_VALUE_r11] = _RETURN_VALUE, + [_GET_AITER_r11] = _GET_AITER, + [_GET_ANEXT_r12] = _GET_ANEXT, + [_GET_AWAITABLE_r11] = _GET_AWAITABLE, + [_SEND_GEN_FRAME_r22] = _SEND_GEN_FRAME, + [_YIELD_VALUE_r11] = _YIELD_VALUE, + [_POP_EXCEPT_r10] = _POP_EXCEPT, + [_LOAD_COMMON_CONSTANT_r01] = _LOAD_COMMON_CONSTANT, + [_LOAD_COMMON_CONSTANT_r12] = _LOAD_COMMON_CONSTANT, + [_LOAD_COMMON_CONSTANT_r23] = _LOAD_COMMON_CONSTANT, + [_LOAD_BUILD_CLASS_r01] = _LOAD_BUILD_CLASS, + [_STORE_NAME_r10] = _STORE_NAME, + [_DELETE_NAME_r00] = _DELETE_NAME, + [_UNPACK_SEQUENCE_r10] = _UNPACK_SEQUENCE, + [_UNPACK_SEQUENCE_TWO_TUPLE_r12] = _UNPACK_SEQUENCE_TWO_TUPLE, + [_UNPACK_SEQUENCE_TUPLE_r10] = _UNPACK_SEQUENCE_TUPLE, + [_UNPACK_SEQUENCE_LIST_r10] = _UNPACK_SEQUENCE_LIST, + [_UNPACK_EX_r10] = _UNPACK_EX, + [_STORE_ATTR_r20] = _STORE_ATTR, + [_DELETE_ATTR_r10] = _DELETE_ATTR, + [_STORE_GLOBAL_r10] = _STORE_GLOBAL, + [_DELETE_GLOBAL_r00] = _DELETE_GLOBAL, + [_LOAD_LOCALS_r01] = _LOAD_LOCALS, + [_LOAD_LOCALS_r12] = _LOAD_LOCALS, + [_LOAD_LOCALS_r23] = _LOAD_LOCALS, + [_LOAD_NAME_r01] = _LOAD_NAME, + [_LOAD_GLOBAL_r00] = _LOAD_GLOBAL, + [_PUSH_NULL_CONDITIONAL_r00] = _PUSH_NULL_CONDITIONAL, + [_GUARD_GLOBALS_VERSION_r00] = _GUARD_GLOBALS_VERSION, + [_GUARD_GLOBALS_VERSION_r11] = _GUARD_GLOBALS_VERSION, + [_GUARD_GLOBALS_VERSION_r22] = _GUARD_GLOBALS_VERSION, + [_GUARD_GLOBALS_VERSION_r33] = _GUARD_GLOBALS_VERSION, + [_LOAD_GLOBAL_MODULE_r01] = _LOAD_GLOBAL_MODULE, + [_LOAD_GLOBAL_BUILTINS_r01] = _LOAD_GLOBAL_BUILTINS, + [_DELETE_FAST_r00] = _DELETE_FAST, + [_MAKE_CELL_r00] = _MAKE_CELL, + [_DELETE_DEREF_r00] = _DELETE_DEREF, + [_LOAD_FROM_DICT_OR_DEREF_r11] = _LOAD_FROM_DICT_OR_DEREF, + [_LOAD_DEREF_r01] = _LOAD_DEREF, + [_STORE_DEREF_r10] = _STORE_DEREF, + [_COPY_FREE_VARS_r00] = _COPY_FREE_VARS, + [_COPY_FREE_VARS_r11] = _COPY_FREE_VARS, + [_COPY_FREE_VARS_r22] = _COPY_FREE_VARS, + [_COPY_FREE_VARS_r33] = _COPY_FREE_VARS, + [_BUILD_STRING_r01] = _BUILD_STRING, + [_BUILD_INTERPOLATION_r01] = _BUILD_INTERPOLATION, + [_BUILD_TEMPLATE_r21] = _BUILD_TEMPLATE, + [_BUILD_TUPLE_r01] = _BUILD_TUPLE, + [_BUILD_LIST_r01] = _BUILD_LIST, + [_LIST_EXTEND_r10] = _LIST_EXTEND, + [_SET_UPDATE_r10] = _SET_UPDATE, + [_BUILD_SET_r01] = _BUILD_SET, + [_BUILD_MAP_r01] = _BUILD_MAP, + [_SETUP_ANNOTATIONS_r00] = _SETUP_ANNOTATIONS, + [_DICT_UPDATE_r10] = _DICT_UPDATE, + [_DICT_MERGE_r10] = _DICT_MERGE, + [_MAP_ADD_r20] = _MAP_ADD, + [_LOAD_SUPER_ATTR_ATTR_r31] = _LOAD_SUPER_ATTR_ATTR, + [_LOAD_SUPER_ATTR_METHOD_r32] = _LOAD_SUPER_ATTR_METHOD, + [_LOAD_ATTR_r10] = _LOAD_ATTR, + [_GUARD_TYPE_VERSION_r01] = _GUARD_TYPE_VERSION, + [_GUARD_TYPE_VERSION_r11] = _GUARD_TYPE_VERSION, + [_GUARD_TYPE_VERSION_r22] = _GUARD_TYPE_VERSION, + [_GUARD_TYPE_VERSION_r33] = _GUARD_TYPE_VERSION, + [_GUARD_TYPE_VERSION_AND_LOCK_r01] = _GUARD_TYPE_VERSION_AND_LOCK, + [_GUARD_TYPE_VERSION_AND_LOCK_r11] = _GUARD_TYPE_VERSION_AND_LOCK, + [_GUARD_TYPE_VERSION_AND_LOCK_r22] = _GUARD_TYPE_VERSION_AND_LOCK, + [_GUARD_TYPE_VERSION_AND_LOCK_r33] = _GUARD_TYPE_VERSION_AND_LOCK, + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r01] = _CHECK_MANAGED_OBJECT_HAS_VALUES, + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r11] = _CHECK_MANAGED_OBJECT_HAS_VALUES, + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r22] = _CHECK_MANAGED_OBJECT_HAS_VALUES, + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r33] = _CHECK_MANAGED_OBJECT_HAS_VALUES, + [_LOAD_ATTR_INSTANCE_VALUE_r02] = _LOAD_ATTR_INSTANCE_VALUE, + [_LOAD_ATTR_INSTANCE_VALUE_r12] = _LOAD_ATTR_INSTANCE_VALUE, + [_LOAD_ATTR_INSTANCE_VALUE_r23] = _LOAD_ATTR_INSTANCE_VALUE, + [_LOAD_ATTR_MODULE_r11] = _LOAD_ATTR_MODULE, + [_LOAD_ATTR_WITH_HINT_r11] = _LOAD_ATTR_WITH_HINT, + [_LOAD_ATTR_SLOT_r11] = _LOAD_ATTR_SLOT, + [_CHECK_ATTR_CLASS_r01] = _CHECK_ATTR_CLASS, + [_CHECK_ATTR_CLASS_r11] = _CHECK_ATTR_CLASS, + [_CHECK_ATTR_CLASS_r22] = _CHECK_ATTR_CLASS, + [_CHECK_ATTR_CLASS_r33] = _CHECK_ATTR_CLASS, + [_LOAD_ATTR_CLASS_r11] = _LOAD_ATTR_CLASS, + [_LOAD_ATTR_PROPERTY_FRAME_r11] = _LOAD_ATTR_PROPERTY_FRAME, + [_GUARD_DORV_NO_DICT_r01] = _GUARD_DORV_NO_DICT, + [_GUARD_DORV_NO_DICT_r11] = _GUARD_DORV_NO_DICT, + [_GUARD_DORV_NO_DICT_r22] = _GUARD_DORV_NO_DICT, + [_GUARD_DORV_NO_DICT_r33] = _GUARD_DORV_NO_DICT, + [_STORE_ATTR_INSTANCE_VALUE_r21] = _STORE_ATTR_INSTANCE_VALUE, + [_STORE_ATTR_WITH_HINT_r21] = _STORE_ATTR_WITH_HINT, + [_STORE_ATTR_SLOT_r21] = _STORE_ATTR_SLOT, + [_COMPARE_OP_r21] = _COMPARE_OP, + [_COMPARE_OP_FLOAT_r01] = _COMPARE_OP_FLOAT, + [_COMPARE_OP_FLOAT_r11] = _COMPARE_OP_FLOAT, + [_COMPARE_OP_FLOAT_r21] = _COMPARE_OP_FLOAT, + [_COMPARE_OP_FLOAT_r32] = _COMPARE_OP_FLOAT, + [_COMPARE_OP_INT_r23] = _COMPARE_OP_INT, + [_COMPARE_OP_STR_r21] = _COMPARE_OP_STR, + [_IS_OP_r21] = _IS_OP, + [_CONTAINS_OP_r21] = _CONTAINS_OP, + [_GUARD_TOS_ANY_SET_r01] = _GUARD_TOS_ANY_SET, + [_GUARD_TOS_ANY_SET_r11] = _GUARD_TOS_ANY_SET, + [_GUARD_TOS_ANY_SET_r22] = _GUARD_TOS_ANY_SET, + [_GUARD_TOS_ANY_SET_r33] = _GUARD_TOS_ANY_SET, + [_CONTAINS_OP_SET_r21] = _CONTAINS_OP_SET, + [_CONTAINS_OP_DICT_r21] = _CONTAINS_OP_DICT, + [_CHECK_EG_MATCH_r22] = _CHECK_EG_MATCH, + [_CHECK_EXC_MATCH_r22] = _CHECK_EXC_MATCH, + [_IMPORT_NAME_r21] = _IMPORT_NAME, + [_IMPORT_FROM_r12] = _IMPORT_FROM, + [_IS_NONE_r11] = _IS_NONE, + [_GET_LEN_r12] = _GET_LEN, + [_MATCH_CLASS_r31] = _MATCH_CLASS, + [_MATCH_MAPPING_r02] = _MATCH_MAPPING, + [_MATCH_MAPPING_r12] = _MATCH_MAPPING, + [_MATCH_MAPPING_r23] = _MATCH_MAPPING, + [_MATCH_SEQUENCE_r02] = _MATCH_SEQUENCE, + [_MATCH_SEQUENCE_r12] = _MATCH_SEQUENCE, + [_MATCH_SEQUENCE_r23] = _MATCH_SEQUENCE, + [_MATCH_KEYS_r23] = _MATCH_KEYS, + [_GET_ITER_r12] = _GET_ITER, + [_GET_YIELD_FROM_ITER_r11] = _GET_YIELD_FROM_ITER, + [_FOR_ITER_TIER_TWO_r23] = _FOR_ITER_TIER_TWO, + [_ITER_CHECK_LIST_r02] = _ITER_CHECK_LIST, + [_ITER_CHECK_LIST_r12] = _ITER_CHECK_LIST, + [_ITER_CHECK_LIST_r22] = _ITER_CHECK_LIST, + [_ITER_CHECK_LIST_r33] = _ITER_CHECK_LIST, + [_GUARD_NOT_EXHAUSTED_LIST_r02] = _GUARD_NOT_EXHAUSTED_LIST, + [_GUARD_NOT_EXHAUSTED_LIST_r12] = _GUARD_NOT_EXHAUSTED_LIST, + [_GUARD_NOT_EXHAUSTED_LIST_r22] = _GUARD_NOT_EXHAUSTED_LIST, + [_GUARD_NOT_EXHAUSTED_LIST_r33] = _GUARD_NOT_EXHAUSTED_LIST, + [_ITER_NEXT_LIST_TIER_TWO_r23] = _ITER_NEXT_LIST_TIER_TWO, + [_ITER_CHECK_TUPLE_r02] = _ITER_CHECK_TUPLE, + [_ITER_CHECK_TUPLE_r12] = _ITER_CHECK_TUPLE, + [_ITER_CHECK_TUPLE_r22] = _ITER_CHECK_TUPLE, + [_ITER_CHECK_TUPLE_r33] = _ITER_CHECK_TUPLE, + [_GUARD_NOT_EXHAUSTED_TUPLE_r02] = _GUARD_NOT_EXHAUSTED_TUPLE, + [_GUARD_NOT_EXHAUSTED_TUPLE_r12] = _GUARD_NOT_EXHAUSTED_TUPLE, + [_GUARD_NOT_EXHAUSTED_TUPLE_r22] = _GUARD_NOT_EXHAUSTED_TUPLE, + [_GUARD_NOT_EXHAUSTED_TUPLE_r33] = _GUARD_NOT_EXHAUSTED_TUPLE, + [_ITER_NEXT_TUPLE_r03] = _ITER_NEXT_TUPLE, + [_ITER_NEXT_TUPLE_r13] = _ITER_NEXT_TUPLE, + [_ITER_NEXT_TUPLE_r23] = _ITER_NEXT_TUPLE, + [_ITER_CHECK_RANGE_r02] = _ITER_CHECK_RANGE, + [_ITER_CHECK_RANGE_r12] = _ITER_CHECK_RANGE, + [_ITER_CHECK_RANGE_r22] = _ITER_CHECK_RANGE, + [_ITER_CHECK_RANGE_r33] = _ITER_CHECK_RANGE, + [_GUARD_NOT_EXHAUSTED_RANGE_r02] = _GUARD_NOT_EXHAUSTED_RANGE, + [_GUARD_NOT_EXHAUSTED_RANGE_r12] = _GUARD_NOT_EXHAUSTED_RANGE, + [_GUARD_NOT_EXHAUSTED_RANGE_r22] = _GUARD_NOT_EXHAUSTED_RANGE, + [_GUARD_NOT_EXHAUSTED_RANGE_r33] = _GUARD_NOT_EXHAUSTED_RANGE, + [_ITER_NEXT_RANGE_r03] = _ITER_NEXT_RANGE, + [_ITER_NEXT_RANGE_r13] = _ITER_NEXT_RANGE, + [_ITER_NEXT_RANGE_r23] = _ITER_NEXT_RANGE, + [_FOR_ITER_GEN_FRAME_r23] = _FOR_ITER_GEN_FRAME, + [_INSERT_NULL_r10] = _INSERT_NULL, + [_LOAD_SPECIAL_r00] = _LOAD_SPECIAL, + [_WITH_EXCEPT_START_r33] = _WITH_EXCEPT_START, + [_PUSH_EXC_INFO_r02] = _PUSH_EXC_INFO, + [_PUSH_EXC_INFO_r12] = _PUSH_EXC_INFO, + [_PUSH_EXC_INFO_r23] = _PUSH_EXC_INFO, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, + [_GUARD_KEYS_VERSION_r01] = _GUARD_KEYS_VERSION, + [_GUARD_KEYS_VERSION_r11] = _GUARD_KEYS_VERSION, + [_GUARD_KEYS_VERSION_r22] = _GUARD_KEYS_VERSION, + [_GUARD_KEYS_VERSION_r33] = _GUARD_KEYS_VERSION, + [_LOAD_ATTR_METHOD_WITH_VALUES_r02] = _LOAD_ATTR_METHOD_WITH_VALUES, + [_LOAD_ATTR_METHOD_WITH_VALUES_r12] = _LOAD_ATTR_METHOD_WITH_VALUES, + [_LOAD_ATTR_METHOD_WITH_VALUES_r23] = _LOAD_ATTR_METHOD_WITH_VALUES, + [_LOAD_ATTR_METHOD_NO_DICT_r02] = _LOAD_ATTR_METHOD_NO_DICT, + [_LOAD_ATTR_METHOD_NO_DICT_r12] = _LOAD_ATTR_METHOD_NO_DICT, + [_LOAD_ATTR_METHOD_NO_DICT_r23] = _LOAD_ATTR_METHOD_NO_DICT, + [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11] = _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, + [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11] = _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, + [_CHECK_ATTR_METHOD_LAZY_DICT_r01] = _CHECK_ATTR_METHOD_LAZY_DICT, + [_CHECK_ATTR_METHOD_LAZY_DICT_r11] = _CHECK_ATTR_METHOD_LAZY_DICT, + [_CHECK_ATTR_METHOD_LAZY_DICT_r22] = _CHECK_ATTR_METHOD_LAZY_DICT, + [_CHECK_ATTR_METHOD_LAZY_DICT_r33] = _CHECK_ATTR_METHOD_LAZY_DICT, + [_LOAD_ATTR_METHOD_LAZY_DICT_r02] = _LOAD_ATTR_METHOD_LAZY_DICT, + [_LOAD_ATTR_METHOD_LAZY_DICT_r12] = _LOAD_ATTR_METHOD_LAZY_DICT, + [_LOAD_ATTR_METHOD_LAZY_DICT_r23] = _LOAD_ATTR_METHOD_LAZY_DICT, + [_MAYBE_EXPAND_METHOD_r00] = _MAYBE_EXPAND_METHOD, + [_PY_FRAME_GENERAL_r01] = _PY_FRAME_GENERAL, + [_CHECK_FUNCTION_VERSION_r00] = _CHECK_FUNCTION_VERSION, + [_CHECK_FUNCTION_VERSION_INLINE_r00] = _CHECK_FUNCTION_VERSION_INLINE, + [_CHECK_FUNCTION_VERSION_INLINE_r11] = _CHECK_FUNCTION_VERSION_INLINE, + [_CHECK_FUNCTION_VERSION_INLINE_r22] = _CHECK_FUNCTION_VERSION_INLINE, + [_CHECK_FUNCTION_VERSION_INLINE_r33] = _CHECK_FUNCTION_VERSION_INLINE, + [_CHECK_METHOD_VERSION_r00] = _CHECK_METHOD_VERSION, + [_EXPAND_METHOD_r00] = _EXPAND_METHOD, + [_CHECK_IS_NOT_PY_CALLABLE_r00] = _CHECK_IS_NOT_PY_CALLABLE, + [_CALL_NON_PY_GENERAL_r01] = _CALL_NON_PY_GENERAL, + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00] = _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, + [_INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00] = _INIT_CALL_BOUND_METHOD_EXACT_ARGS, + [_CHECK_PEP_523_r00] = _CHECK_PEP_523, + [_CHECK_PEP_523_r11] = _CHECK_PEP_523, + [_CHECK_PEP_523_r22] = _CHECK_PEP_523, + [_CHECK_PEP_523_r33] = _CHECK_PEP_523, + [_CHECK_FUNCTION_EXACT_ARGS_r00] = _CHECK_FUNCTION_EXACT_ARGS, + [_CHECK_STACK_SPACE_r00] = _CHECK_STACK_SPACE, + [_CHECK_RECURSION_REMAINING_r00] = _CHECK_RECURSION_REMAINING, + [_CHECK_RECURSION_REMAINING_r11] = _CHECK_RECURSION_REMAINING, + [_CHECK_RECURSION_REMAINING_r22] = _CHECK_RECURSION_REMAINING, + [_CHECK_RECURSION_REMAINING_r33] = _CHECK_RECURSION_REMAINING, + [_INIT_CALL_PY_EXACT_ARGS_0_r01] = _INIT_CALL_PY_EXACT_ARGS_0, + [_INIT_CALL_PY_EXACT_ARGS_1_r01] = _INIT_CALL_PY_EXACT_ARGS_1, + [_INIT_CALL_PY_EXACT_ARGS_2_r01] = _INIT_CALL_PY_EXACT_ARGS_2, + [_INIT_CALL_PY_EXACT_ARGS_3_r01] = _INIT_CALL_PY_EXACT_ARGS_3, + [_INIT_CALL_PY_EXACT_ARGS_4_r01] = _INIT_CALL_PY_EXACT_ARGS_4, + [_INIT_CALL_PY_EXACT_ARGS_r01] = _INIT_CALL_PY_EXACT_ARGS, + [_PUSH_FRAME_r10] = _PUSH_FRAME, + [_GUARD_NOS_NULL_r02] = _GUARD_NOS_NULL, + [_GUARD_NOS_NULL_r12] = _GUARD_NOS_NULL, + [_GUARD_NOS_NULL_r22] = _GUARD_NOS_NULL, + [_GUARD_NOS_NULL_r33] = _GUARD_NOS_NULL, + [_GUARD_NOS_NOT_NULL_r02] = _GUARD_NOS_NOT_NULL, + [_GUARD_NOS_NOT_NULL_r12] = _GUARD_NOS_NOT_NULL, + [_GUARD_NOS_NOT_NULL_r22] = _GUARD_NOS_NOT_NULL, + [_GUARD_NOS_NOT_NULL_r33] = _GUARD_NOS_NOT_NULL, + [_GUARD_THIRD_NULL_r03] = _GUARD_THIRD_NULL, + [_GUARD_THIRD_NULL_r13] = _GUARD_THIRD_NULL, + [_GUARD_THIRD_NULL_r23] = _GUARD_THIRD_NULL, + [_GUARD_THIRD_NULL_r33] = _GUARD_THIRD_NULL, + [_GUARD_CALLABLE_TYPE_1_r03] = _GUARD_CALLABLE_TYPE_1, + [_GUARD_CALLABLE_TYPE_1_r13] = _GUARD_CALLABLE_TYPE_1, + [_GUARD_CALLABLE_TYPE_1_r23] = _GUARD_CALLABLE_TYPE_1, + [_GUARD_CALLABLE_TYPE_1_r33] = _GUARD_CALLABLE_TYPE_1, + [_CALL_TYPE_1_r31] = _CALL_TYPE_1, + [_GUARD_CALLABLE_STR_1_r03] = _GUARD_CALLABLE_STR_1, + [_GUARD_CALLABLE_STR_1_r13] = _GUARD_CALLABLE_STR_1, + [_GUARD_CALLABLE_STR_1_r23] = _GUARD_CALLABLE_STR_1, + [_GUARD_CALLABLE_STR_1_r33] = _GUARD_CALLABLE_STR_1, + [_CALL_STR_1_r32] = _CALL_STR_1, + [_GUARD_CALLABLE_TUPLE_1_r03] = _GUARD_CALLABLE_TUPLE_1, + [_GUARD_CALLABLE_TUPLE_1_r13] = _GUARD_CALLABLE_TUPLE_1, + [_GUARD_CALLABLE_TUPLE_1_r23] = _GUARD_CALLABLE_TUPLE_1, + [_GUARD_CALLABLE_TUPLE_1_r33] = _GUARD_CALLABLE_TUPLE_1, + [_CALL_TUPLE_1_r32] = _CALL_TUPLE_1, + [_CHECK_AND_ALLOCATE_OBJECT_r00] = _CHECK_AND_ALLOCATE_OBJECT, + [_CREATE_INIT_FRAME_r01] = _CREATE_INIT_FRAME, + [_EXIT_INIT_CHECK_r10] = _EXIT_INIT_CHECK, + [_CALL_BUILTIN_CLASS_r01] = _CALL_BUILTIN_CLASS, + [_CALL_BUILTIN_O_r03] = _CALL_BUILTIN_O, + [_CALL_BUILTIN_FAST_r01] = _CALL_BUILTIN_FAST, + [_CALL_BUILTIN_FAST_WITH_KEYWORDS_r01] = _CALL_BUILTIN_FAST_WITH_KEYWORDS, + [_GUARD_CALLABLE_LEN_r03] = _GUARD_CALLABLE_LEN, + [_GUARD_CALLABLE_LEN_r13] = _GUARD_CALLABLE_LEN, + [_GUARD_CALLABLE_LEN_r23] = _GUARD_CALLABLE_LEN, + [_GUARD_CALLABLE_LEN_r33] = _GUARD_CALLABLE_LEN, + [_CALL_LEN_r33] = _CALL_LEN, + [_GUARD_CALLABLE_ISINSTANCE_r03] = _GUARD_CALLABLE_ISINSTANCE, + [_GUARD_CALLABLE_ISINSTANCE_r13] = _GUARD_CALLABLE_ISINSTANCE, + [_GUARD_CALLABLE_ISINSTANCE_r23] = _GUARD_CALLABLE_ISINSTANCE, + [_GUARD_CALLABLE_ISINSTANCE_r33] = _GUARD_CALLABLE_ISINSTANCE, + [_CALL_ISINSTANCE_r31] = _CALL_ISINSTANCE, + [_GUARD_CALLABLE_LIST_APPEND_r03] = _GUARD_CALLABLE_LIST_APPEND, + [_GUARD_CALLABLE_LIST_APPEND_r13] = _GUARD_CALLABLE_LIST_APPEND, + [_GUARD_CALLABLE_LIST_APPEND_r23] = _GUARD_CALLABLE_LIST_APPEND, + [_GUARD_CALLABLE_LIST_APPEND_r33] = _GUARD_CALLABLE_LIST_APPEND, + [_CALL_LIST_APPEND_r02] = _CALL_LIST_APPEND, + [_CALL_LIST_APPEND_r12] = _CALL_LIST_APPEND, + [_CALL_LIST_APPEND_r22] = _CALL_LIST_APPEND, + [_CALL_LIST_APPEND_r32] = _CALL_LIST_APPEND, + [_CALL_METHOD_DESCRIPTOR_O_r01] = _CALL_METHOD_DESCRIPTOR_O, + [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01] = _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + [_CALL_METHOD_DESCRIPTOR_NOARGS_r01] = _CALL_METHOD_DESCRIPTOR_NOARGS, + [_CALL_METHOD_DESCRIPTOR_FAST_r01] = _CALL_METHOD_DESCRIPTOR_FAST, + [_MAYBE_EXPAND_METHOD_KW_r11] = _MAYBE_EXPAND_METHOD_KW, + [_PY_FRAME_KW_r11] = _PY_FRAME_KW, + [_CHECK_FUNCTION_VERSION_KW_r11] = _CHECK_FUNCTION_VERSION_KW, + [_CHECK_METHOD_VERSION_KW_r11] = _CHECK_METHOD_VERSION_KW, + [_EXPAND_METHOD_KW_r11] = _EXPAND_METHOD_KW, + [_CHECK_IS_NOT_PY_CALLABLE_KW_r11] = _CHECK_IS_NOT_PY_CALLABLE_KW, + [_CALL_KW_NON_PY_r11] = _CALL_KW_NON_PY, + [_MAKE_CALLARGS_A_TUPLE_r33] = _MAKE_CALLARGS_A_TUPLE, + [_MAKE_FUNCTION_r11] = _MAKE_FUNCTION, + [_SET_FUNCTION_ATTRIBUTE_r01] = _SET_FUNCTION_ATTRIBUTE, + [_SET_FUNCTION_ATTRIBUTE_r11] = _SET_FUNCTION_ATTRIBUTE, + [_SET_FUNCTION_ATTRIBUTE_r21] = _SET_FUNCTION_ATTRIBUTE, + [_SET_FUNCTION_ATTRIBUTE_r32] = _SET_FUNCTION_ATTRIBUTE, + [_RETURN_GENERATOR_r01] = _RETURN_GENERATOR, + [_BUILD_SLICE_r01] = _BUILD_SLICE, + [_CONVERT_VALUE_r11] = _CONVERT_VALUE, + [_FORMAT_SIMPLE_r11] = _FORMAT_SIMPLE, + [_FORMAT_WITH_SPEC_r21] = _FORMAT_WITH_SPEC, + [_COPY_1_r02] = _COPY_1, + [_COPY_1_r12] = _COPY_1, + [_COPY_1_r23] = _COPY_1, + [_COPY_2_r03] = _COPY_2, + [_COPY_2_r13] = _COPY_2, + [_COPY_2_r23] = _COPY_2, + [_COPY_3_r03] = _COPY_3, + [_COPY_3_r13] = _COPY_3, + [_COPY_3_r23] = _COPY_3, + [_COPY_3_r33] = _COPY_3, + [_COPY_r01] = _COPY, + [_BINARY_OP_r21] = _BINARY_OP, + [_SWAP_2_r02] = _SWAP_2, + [_SWAP_2_r12] = _SWAP_2, + [_SWAP_2_r22] = _SWAP_2, + [_SWAP_2_r33] = _SWAP_2, + [_SWAP_3_r03] = _SWAP_3, + [_SWAP_3_r13] = _SWAP_3, + [_SWAP_3_r23] = _SWAP_3, + [_SWAP_3_r33] = _SWAP_3, + [_SWAP_r11] = _SWAP, + [_GUARD_IS_TRUE_POP_r00] = _GUARD_IS_TRUE_POP, + [_GUARD_IS_TRUE_POP_r10] = _GUARD_IS_TRUE_POP, + [_GUARD_IS_TRUE_POP_r21] = _GUARD_IS_TRUE_POP, + [_GUARD_IS_TRUE_POP_r32] = _GUARD_IS_TRUE_POP, + [_GUARD_IS_FALSE_POP_r00] = _GUARD_IS_FALSE_POP, + [_GUARD_IS_FALSE_POP_r10] = _GUARD_IS_FALSE_POP, + [_GUARD_IS_FALSE_POP_r21] = _GUARD_IS_FALSE_POP, + [_GUARD_IS_FALSE_POP_r32] = _GUARD_IS_FALSE_POP, + [_GUARD_IS_NONE_POP_r00] = _GUARD_IS_NONE_POP, + [_GUARD_IS_NONE_POP_r10] = _GUARD_IS_NONE_POP, + [_GUARD_IS_NONE_POP_r21] = _GUARD_IS_NONE_POP, + [_GUARD_IS_NONE_POP_r32] = _GUARD_IS_NONE_POP, + [_GUARD_IS_NOT_NONE_POP_r10] = _GUARD_IS_NOT_NONE_POP, + [_JUMP_TO_TOP_r00] = _JUMP_TO_TOP, + [_SET_IP_r00] = _SET_IP, + [_SET_IP_r11] = _SET_IP, + [_SET_IP_r22] = _SET_IP, + [_SET_IP_r33] = _SET_IP, + [_CHECK_STACK_SPACE_OPERAND_r00] = _CHECK_STACK_SPACE_OPERAND, + [_CHECK_STACK_SPACE_OPERAND_r11] = _CHECK_STACK_SPACE_OPERAND, + [_CHECK_STACK_SPACE_OPERAND_r22] = _CHECK_STACK_SPACE_OPERAND, + [_CHECK_STACK_SPACE_OPERAND_r33] = _CHECK_STACK_SPACE_OPERAND, + [_SAVE_RETURN_OFFSET_r00] = _SAVE_RETURN_OFFSET, + [_SAVE_RETURN_OFFSET_r11] = _SAVE_RETURN_OFFSET, + [_SAVE_RETURN_OFFSET_r22] = _SAVE_RETURN_OFFSET, + [_SAVE_RETURN_OFFSET_r33] = _SAVE_RETURN_OFFSET, + [_EXIT_TRACE_r00] = _EXIT_TRACE, + [_EXIT_TRACE_r10] = _EXIT_TRACE, + [_EXIT_TRACE_r20] = _EXIT_TRACE, + [_EXIT_TRACE_r30] = _EXIT_TRACE, + [_DYNAMIC_EXIT_r00] = _DYNAMIC_EXIT, + [_DYNAMIC_EXIT_r10] = _DYNAMIC_EXIT, + [_DYNAMIC_EXIT_r20] = _DYNAMIC_EXIT, + [_DYNAMIC_EXIT_r30] = _DYNAMIC_EXIT, + [_CHECK_VALIDITY_r00] = _CHECK_VALIDITY, + [_CHECK_VALIDITY_r11] = _CHECK_VALIDITY, + [_CHECK_VALIDITY_r22] = _CHECK_VALIDITY, + [_CHECK_VALIDITY_r33] = _CHECK_VALIDITY, + [_LOAD_CONST_INLINE_r01] = _LOAD_CONST_INLINE, + [_LOAD_CONST_INLINE_r12] = _LOAD_CONST_INLINE, + [_LOAD_CONST_INLINE_r23] = _LOAD_CONST_INLINE, + [_POP_TOP_LOAD_CONST_INLINE_r11] = _POP_TOP_LOAD_CONST_INLINE, + [_LOAD_CONST_INLINE_BORROW_r01] = _LOAD_CONST_INLINE_BORROW, + [_LOAD_CONST_INLINE_BORROW_r12] = _LOAD_CONST_INLINE_BORROW, + [_LOAD_CONST_INLINE_BORROW_r23] = _LOAD_CONST_INLINE_BORROW, + [_POP_CALL_r20] = _POP_CALL, + [_POP_CALL_ONE_r30] = _POP_CALL_ONE, + [_POP_CALL_TWO_r30] = _POP_CALL_TWO, + [_POP_TOP_LOAD_CONST_INLINE_BORROW_r11] = _POP_TOP_LOAD_CONST_INLINE_BORROW, + [_POP_TWO_LOAD_CONST_INLINE_BORROW_r21] = _POP_TWO_LOAD_CONST_INLINE_BORROW, + [_POP_CALL_LOAD_CONST_INLINE_BORROW_r21] = _POP_CALL_LOAD_CONST_INLINE_BORROW, + [_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31] = _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW, + [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31] = _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, + [_LOAD_CONST_UNDER_INLINE_r02] = _LOAD_CONST_UNDER_INLINE, + [_LOAD_CONST_UNDER_INLINE_r12] = _LOAD_CONST_UNDER_INLINE, + [_LOAD_CONST_UNDER_INLINE_r23] = _LOAD_CONST_UNDER_INLINE, + [_LOAD_CONST_UNDER_INLINE_BORROW_r02] = _LOAD_CONST_UNDER_INLINE_BORROW, + [_LOAD_CONST_UNDER_INLINE_BORROW_r12] = _LOAD_CONST_UNDER_INLINE_BORROW, + [_LOAD_CONST_UNDER_INLINE_BORROW_r23] = _LOAD_CONST_UNDER_INLINE_BORROW, + [_START_EXECUTOR_r00] = _START_EXECUTOR, + [_MAKE_WARM_r00] = _MAKE_WARM, + [_MAKE_WARM_r11] = _MAKE_WARM, + [_MAKE_WARM_r22] = _MAKE_WARM, + [_MAKE_WARM_r33] = _MAKE_WARM, + [_FATAL_ERROR_r00] = _FATAL_ERROR, + [_FATAL_ERROR_r11] = _FATAL_ERROR, + [_FATAL_ERROR_r22] = _FATAL_ERROR, + [_FATAL_ERROR_r33] = _FATAL_ERROR, + [_DEOPT_r00] = _DEOPT, + [_DEOPT_r10] = _DEOPT, + [_DEOPT_r20] = _DEOPT, + [_DEOPT_r30] = _DEOPT, + [_HANDLE_PENDING_AND_DEOPT_r00] = _HANDLE_PENDING_AND_DEOPT, + [_HANDLE_PENDING_AND_DEOPT_r10] = _HANDLE_PENDING_AND_DEOPT, + [_HANDLE_PENDING_AND_DEOPT_r20] = _HANDLE_PENDING_AND_DEOPT, + [_HANDLE_PENDING_AND_DEOPT_r30] = _HANDLE_PENDING_AND_DEOPT, + [_ERROR_POP_N_r00] = _ERROR_POP_N, + [_SPILL_OR_RELOAD_r01] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r02] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r03] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r10] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r12] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r13] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r20] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r21] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r23] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r30] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r31] = _SPILL_OR_RELOAD, + [_SPILL_OR_RELOAD_r32] = _SPILL_OR_RELOAD, + [_TIER2_RESUME_CHECK_r00] = _TIER2_RESUME_CHECK, + [_TIER2_RESUME_CHECK_r11] = _TIER2_RESUME_CHECK, + [_TIER2_RESUME_CHECK_r22] = _TIER2_RESUME_CHECK, + [_TIER2_RESUME_CHECK_r33] = _TIER2_RESUME_CHECK, + [_COLD_EXIT_r00] = _COLD_EXIT, + [_COLD_DYNAMIC_EXIT_r00] = _COLD_DYNAMIC_EXIT, + [_GUARD_IP__PUSH_FRAME_r00] = _GUARD_IP__PUSH_FRAME, + [_GUARD_IP__PUSH_FRAME_r11] = _GUARD_IP__PUSH_FRAME, + [_GUARD_IP__PUSH_FRAME_r22] = _GUARD_IP__PUSH_FRAME, + [_GUARD_IP__PUSH_FRAME_r33] = _GUARD_IP__PUSH_FRAME, + [_GUARD_IP_YIELD_VALUE_r00] = _GUARD_IP_YIELD_VALUE, + [_GUARD_IP_YIELD_VALUE_r11] = _GUARD_IP_YIELD_VALUE, + [_GUARD_IP_YIELD_VALUE_r22] = _GUARD_IP_YIELD_VALUE, + [_GUARD_IP_YIELD_VALUE_r33] = _GUARD_IP_YIELD_VALUE, + [_GUARD_IP_RETURN_VALUE_r00] = _GUARD_IP_RETURN_VALUE, + [_GUARD_IP_RETURN_VALUE_r11] = _GUARD_IP_RETURN_VALUE, + [_GUARD_IP_RETURN_VALUE_r22] = _GUARD_IP_RETURN_VALUE, + [_GUARD_IP_RETURN_VALUE_r33] = _GUARD_IP_RETURN_VALUE, + [_GUARD_IP_RETURN_GENERATOR_r00] = _GUARD_IP_RETURN_GENERATOR, + [_GUARD_IP_RETURN_GENERATOR_r11] = _GUARD_IP_RETURN_GENERATOR, + [_GUARD_IP_RETURN_GENERATOR_r22] = _GUARD_IP_RETURN_GENERATOR, + [_GUARD_IP_RETURN_GENERATOR_r33] = _GUARD_IP_RETURN_GENERATOR, +}; + +const uint16_t _PyUop_SpillsAndReloads[4][4] = { + [0][1] = _SPILL_OR_RELOAD_r01, + [0][2] = _SPILL_OR_RELOAD_r02, + [0][3] = _SPILL_OR_RELOAD_r03, + [1][0] = _SPILL_OR_RELOAD_r10, + [1][2] = _SPILL_OR_RELOAD_r12, + [1][3] = _SPILL_OR_RELOAD_r13, + [2][0] = _SPILL_OR_RELOAD_r20, + [2][1] = _SPILL_OR_RELOAD_r21, + [2][3] = _SPILL_OR_RELOAD_r23, + [3][0] = _SPILL_OR_RELOAD_r30, + [3][1] = _SPILL_OR_RELOAD_r31, + [3][2] = _SPILL_OR_RELOAD_r32, +}; + +const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_BINARY_OP] = "_BINARY_OP", + [_BINARY_OP_r21] = "_BINARY_OP_r21", [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT", - [_BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS] = "_BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS", + [_BINARY_OP_ADD_FLOAT_r03] = "_BINARY_OP_ADD_FLOAT_r03", + [_BINARY_OP_ADD_FLOAT_r13] = "_BINARY_OP_ADD_FLOAT_r13", + [_BINARY_OP_ADD_FLOAT_r23] = "_BINARY_OP_ADD_FLOAT_r23", [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT", + [_BINARY_OP_ADD_INT_r03] = "_BINARY_OP_ADD_INT_r03", + [_BINARY_OP_ADD_INT_r13] = "_BINARY_OP_ADD_INT_r13", + [_BINARY_OP_ADD_INT_r23] = "_BINARY_OP_ADD_INT_r23", [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE", + [_BINARY_OP_ADD_UNICODE_r03] = "_BINARY_OP_ADD_UNICODE_r03", + [_BINARY_OP_ADD_UNICODE_r13] = "_BINARY_OP_ADD_UNICODE_r13", + [_BINARY_OP_ADD_UNICODE_r23] = "_BINARY_OP_ADD_UNICODE_r23", [_BINARY_OP_EXTEND] = "_BINARY_OP_EXTEND", + [_BINARY_OP_EXTEND_r21] = "_BINARY_OP_EXTEND_r21", [_BINARY_OP_INPLACE_ADD_UNICODE] = "_BINARY_OP_INPLACE_ADD_UNICODE", + [_BINARY_OP_INPLACE_ADD_UNICODE_r20] = "_BINARY_OP_INPLACE_ADD_UNICODE_r20", [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT", - [_BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS] = "_BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS", + [_BINARY_OP_MULTIPLY_FLOAT_r03] = "_BINARY_OP_MULTIPLY_FLOAT_r03", + [_BINARY_OP_MULTIPLY_FLOAT_r13] = "_BINARY_OP_MULTIPLY_FLOAT_r13", + [_BINARY_OP_MULTIPLY_FLOAT_r23] = "_BINARY_OP_MULTIPLY_FLOAT_r23", [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT", + [_BINARY_OP_MULTIPLY_INT_r03] = "_BINARY_OP_MULTIPLY_INT_r03", + [_BINARY_OP_MULTIPLY_INT_r13] = "_BINARY_OP_MULTIPLY_INT_r13", + [_BINARY_OP_MULTIPLY_INT_r23] = "_BINARY_OP_MULTIPLY_INT_r23", [_BINARY_OP_SUBSCR_CHECK_FUNC] = "_BINARY_OP_SUBSCR_CHECK_FUNC", + [_BINARY_OP_SUBSCR_CHECK_FUNC_r23] = "_BINARY_OP_SUBSCR_CHECK_FUNC_r23", [_BINARY_OP_SUBSCR_DICT] = "_BINARY_OP_SUBSCR_DICT", + [_BINARY_OP_SUBSCR_DICT_r21] = "_BINARY_OP_SUBSCR_DICT_r21", [_BINARY_OP_SUBSCR_INIT_CALL] = "_BINARY_OP_SUBSCR_INIT_CALL", + [_BINARY_OP_SUBSCR_INIT_CALL_r01] = "_BINARY_OP_SUBSCR_INIT_CALL_r01", + [_BINARY_OP_SUBSCR_INIT_CALL_r11] = "_BINARY_OP_SUBSCR_INIT_CALL_r11", + [_BINARY_OP_SUBSCR_INIT_CALL_r21] = "_BINARY_OP_SUBSCR_INIT_CALL_r21", + [_BINARY_OP_SUBSCR_INIT_CALL_r31] = "_BINARY_OP_SUBSCR_INIT_CALL_r31", [_BINARY_OP_SUBSCR_LIST_INT] = "_BINARY_OP_SUBSCR_LIST_INT", + [_BINARY_OP_SUBSCR_LIST_INT_r21] = "_BINARY_OP_SUBSCR_LIST_INT_r21", [_BINARY_OP_SUBSCR_LIST_SLICE] = "_BINARY_OP_SUBSCR_LIST_SLICE", + [_BINARY_OP_SUBSCR_LIST_SLICE_r21] = "_BINARY_OP_SUBSCR_LIST_SLICE_r21", [_BINARY_OP_SUBSCR_STR_INT] = "_BINARY_OP_SUBSCR_STR_INT", + [_BINARY_OP_SUBSCR_STR_INT_r21] = "_BINARY_OP_SUBSCR_STR_INT_r21", [_BINARY_OP_SUBSCR_TUPLE_INT] = "_BINARY_OP_SUBSCR_TUPLE_INT", + [_BINARY_OP_SUBSCR_TUPLE_INT_r21] = "_BINARY_OP_SUBSCR_TUPLE_INT_r21", [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT", - [_BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS] = "_BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS", + [_BINARY_OP_SUBTRACT_FLOAT_r03] = "_BINARY_OP_SUBTRACT_FLOAT_r03", + [_BINARY_OP_SUBTRACT_FLOAT_r13] = "_BINARY_OP_SUBTRACT_FLOAT_r13", + [_BINARY_OP_SUBTRACT_FLOAT_r23] = "_BINARY_OP_SUBTRACT_FLOAT_r23", [_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT", + [_BINARY_OP_SUBTRACT_INT_r03] = "_BINARY_OP_SUBTRACT_INT_r03", + [_BINARY_OP_SUBTRACT_INT_r13] = "_BINARY_OP_SUBTRACT_INT_r13", + [_BINARY_OP_SUBTRACT_INT_r23] = "_BINARY_OP_SUBTRACT_INT_r23", [_BINARY_SLICE] = "_BINARY_SLICE", + [_BINARY_SLICE_r31] = "_BINARY_SLICE_r31", [_BUILD_INTERPOLATION] = "_BUILD_INTERPOLATION", + [_BUILD_INTERPOLATION_r01] = "_BUILD_INTERPOLATION_r01", [_BUILD_LIST] = "_BUILD_LIST", + [_BUILD_LIST_r01] = "_BUILD_LIST_r01", [_BUILD_MAP] = "_BUILD_MAP", + [_BUILD_MAP_r01] = "_BUILD_MAP_r01", [_BUILD_SET] = "_BUILD_SET", + [_BUILD_SET_r01] = "_BUILD_SET_r01", [_BUILD_SLICE] = "_BUILD_SLICE", + [_BUILD_SLICE_r01] = "_BUILD_SLICE_r01", [_BUILD_STRING] = "_BUILD_STRING", + [_BUILD_STRING_r01] = "_BUILD_STRING_r01", [_BUILD_TEMPLATE] = "_BUILD_TEMPLATE", + [_BUILD_TEMPLATE_r21] = "_BUILD_TEMPLATE_r21", [_BUILD_TUPLE] = "_BUILD_TUPLE", + [_BUILD_TUPLE_r01] = "_BUILD_TUPLE_r01", [_CALL_BUILTIN_CLASS] = "_CALL_BUILTIN_CLASS", + [_CALL_BUILTIN_CLASS_r01] = "_CALL_BUILTIN_CLASS_r01", [_CALL_BUILTIN_FAST] = "_CALL_BUILTIN_FAST", + [_CALL_BUILTIN_FAST_r01] = "_CALL_BUILTIN_FAST_r01", [_CALL_BUILTIN_FAST_WITH_KEYWORDS] = "_CALL_BUILTIN_FAST_WITH_KEYWORDS", + [_CALL_BUILTIN_FAST_WITH_KEYWORDS_r01] = "_CALL_BUILTIN_FAST_WITH_KEYWORDS_r01", [_CALL_BUILTIN_O] = "_CALL_BUILTIN_O", + [_CALL_BUILTIN_O_r03] = "_CALL_BUILTIN_O_r03", [_CALL_INTRINSIC_1] = "_CALL_INTRINSIC_1", + [_CALL_INTRINSIC_1_r11] = "_CALL_INTRINSIC_1_r11", [_CALL_INTRINSIC_2] = "_CALL_INTRINSIC_2", + [_CALL_INTRINSIC_2_r21] = "_CALL_INTRINSIC_2_r21", [_CALL_ISINSTANCE] = "_CALL_ISINSTANCE", + [_CALL_ISINSTANCE_r31] = "_CALL_ISINSTANCE_r31", [_CALL_KW_NON_PY] = "_CALL_KW_NON_PY", + [_CALL_KW_NON_PY_r11] = "_CALL_KW_NON_PY_r11", [_CALL_LEN] = "_CALL_LEN", + [_CALL_LEN_r33] = "_CALL_LEN_r33", [_CALL_LIST_APPEND] = "_CALL_LIST_APPEND", + [_CALL_LIST_APPEND_r02] = "_CALL_LIST_APPEND_r02", + [_CALL_LIST_APPEND_r12] = "_CALL_LIST_APPEND_r12", + [_CALL_LIST_APPEND_r22] = "_CALL_LIST_APPEND_r22", + [_CALL_LIST_APPEND_r32] = "_CALL_LIST_APPEND_r32", [_CALL_METHOD_DESCRIPTOR_FAST] = "_CALL_METHOD_DESCRIPTOR_FAST", + [_CALL_METHOD_DESCRIPTOR_FAST_r01] = "_CALL_METHOD_DESCRIPTOR_FAST_r01", [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01] = "_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01", [_CALL_METHOD_DESCRIPTOR_NOARGS] = "_CALL_METHOD_DESCRIPTOR_NOARGS", + [_CALL_METHOD_DESCRIPTOR_NOARGS_r01] = "_CALL_METHOD_DESCRIPTOR_NOARGS_r01", [_CALL_METHOD_DESCRIPTOR_O] = "_CALL_METHOD_DESCRIPTOR_O", + [_CALL_METHOD_DESCRIPTOR_O_r01] = "_CALL_METHOD_DESCRIPTOR_O_r01", [_CALL_NON_PY_GENERAL] = "_CALL_NON_PY_GENERAL", + [_CALL_NON_PY_GENERAL_r01] = "_CALL_NON_PY_GENERAL_r01", [_CALL_STR_1] = "_CALL_STR_1", + [_CALL_STR_1_r32] = "_CALL_STR_1_r32", [_CALL_TUPLE_1] = "_CALL_TUPLE_1", + [_CALL_TUPLE_1_r32] = "_CALL_TUPLE_1_r32", [_CALL_TYPE_1] = "_CALL_TYPE_1", + [_CALL_TYPE_1_r31] = "_CALL_TYPE_1_r31", [_CHECK_AND_ALLOCATE_OBJECT] = "_CHECK_AND_ALLOCATE_OBJECT", + [_CHECK_AND_ALLOCATE_OBJECT_r00] = "_CHECK_AND_ALLOCATE_OBJECT_r00", [_CHECK_ATTR_CLASS] = "_CHECK_ATTR_CLASS", + [_CHECK_ATTR_CLASS_r01] = "_CHECK_ATTR_CLASS_r01", + [_CHECK_ATTR_CLASS_r11] = "_CHECK_ATTR_CLASS_r11", + [_CHECK_ATTR_CLASS_r22] = "_CHECK_ATTR_CLASS_r22", + [_CHECK_ATTR_CLASS_r33] = "_CHECK_ATTR_CLASS_r33", [_CHECK_ATTR_METHOD_LAZY_DICT] = "_CHECK_ATTR_METHOD_LAZY_DICT", + [_CHECK_ATTR_METHOD_LAZY_DICT_r01] = "_CHECK_ATTR_METHOD_LAZY_DICT_r01", + [_CHECK_ATTR_METHOD_LAZY_DICT_r11] = "_CHECK_ATTR_METHOD_LAZY_DICT_r11", + [_CHECK_ATTR_METHOD_LAZY_DICT_r22] = "_CHECK_ATTR_METHOD_LAZY_DICT_r22", + [_CHECK_ATTR_METHOD_LAZY_DICT_r33] = "_CHECK_ATTR_METHOD_LAZY_DICT_r33", [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = "_CHECK_CALL_BOUND_METHOD_EXACT_ARGS", + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00] = "_CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00", [_CHECK_EG_MATCH] = "_CHECK_EG_MATCH", + [_CHECK_EG_MATCH_r22] = "_CHECK_EG_MATCH_r22", [_CHECK_EXC_MATCH] = "_CHECK_EXC_MATCH", - [_CHECK_FUNCTION] = "_CHECK_FUNCTION", + [_CHECK_EXC_MATCH_r22] = "_CHECK_EXC_MATCH_r22", [_CHECK_FUNCTION_EXACT_ARGS] = "_CHECK_FUNCTION_EXACT_ARGS", + [_CHECK_FUNCTION_EXACT_ARGS_r00] = "_CHECK_FUNCTION_EXACT_ARGS_r00", [_CHECK_FUNCTION_VERSION] = "_CHECK_FUNCTION_VERSION", + [_CHECK_FUNCTION_VERSION_r00] = "_CHECK_FUNCTION_VERSION_r00", [_CHECK_FUNCTION_VERSION_INLINE] = "_CHECK_FUNCTION_VERSION_INLINE", + [_CHECK_FUNCTION_VERSION_INLINE_r00] = "_CHECK_FUNCTION_VERSION_INLINE_r00", + [_CHECK_FUNCTION_VERSION_INLINE_r11] = "_CHECK_FUNCTION_VERSION_INLINE_r11", + [_CHECK_FUNCTION_VERSION_INLINE_r22] = "_CHECK_FUNCTION_VERSION_INLINE_r22", + [_CHECK_FUNCTION_VERSION_INLINE_r33] = "_CHECK_FUNCTION_VERSION_INLINE_r33", [_CHECK_FUNCTION_VERSION_KW] = "_CHECK_FUNCTION_VERSION_KW", + [_CHECK_FUNCTION_VERSION_KW_r11] = "_CHECK_FUNCTION_VERSION_KW_r11", [_CHECK_IS_NOT_PY_CALLABLE] = "_CHECK_IS_NOT_PY_CALLABLE", + [_CHECK_IS_NOT_PY_CALLABLE_r00] = "_CHECK_IS_NOT_PY_CALLABLE_r00", [_CHECK_IS_NOT_PY_CALLABLE_KW] = "_CHECK_IS_NOT_PY_CALLABLE_KW", + [_CHECK_IS_NOT_PY_CALLABLE_KW_r11] = "_CHECK_IS_NOT_PY_CALLABLE_KW_r11", [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r01] = "_CHECK_MANAGED_OBJECT_HAS_VALUES_r01", + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r11] = "_CHECK_MANAGED_OBJECT_HAS_VALUES_r11", + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r22] = "_CHECK_MANAGED_OBJECT_HAS_VALUES_r22", + [_CHECK_MANAGED_OBJECT_HAS_VALUES_r33] = "_CHECK_MANAGED_OBJECT_HAS_VALUES_r33", [_CHECK_METHOD_VERSION] = "_CHECK_METHOD_VERSION", + [_CHECK_METHOD_VERSION_r00] = "_CHECK_METHOD_VERSION_r00", [_CHECK_METHOD_VERSION_KW] = "_CHECK_METHOD_VERSION_KW", + [_CHECK_METHOD_VERSION_KW_r11] = "_CHECK_METHOD_VERSION_KW_r11", [_CHECK_PEP_523] = "_CHECK_PEP_523", + [_CHECK_PEP_523_r00] = "_CHECK_PEP_523_r00", + [_CHECK_PEP_523_r11] = "_CHECK_PEP_523_r11", + [_CHECK_PEP_523_r22] = "_CHECK_PEP_523_r22", + [_CHECK_PEP_523_r33] = "_CHECK_PEP_523_r33", [_CHECK_PERIODIC] = "_CHECK_PERIODIC", + [_CHECK_PERIODIC_r00] = "_CHECK_PERIODIC_r00", [_CHECK_PERIODIC_IF_NOT_YIELD_FROM] = "_CHECK_PERIODIC_IF_NOT_YIELD_FROM", + [_CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00] = "_CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00", [_CHECK_RECURSION_REMAINING] = "_CHECK_RECURSION_REMAINING", + [_CHECK_RECURSION_REMAINING_r00] = "_CHECK_RECURSION_REMAINING_r00", + [_CHECK_RECURSION_REMAINING_r11] = "_CHECK_RECURSION_REMAINING_r11", + [_CHECK_RECURSION_REMAINING_r22] = "_CHECK_RECURSION_REMAINING_r22", + [_CHECK_RECURSION_REMAINING_r33] = "_CHECK_RECURSION_REMAINING_r33", [_CHECK_STACK_SPACE] = "_CHECK_STACK_SPACE", + [_CHECK_STACK_SPACE_r00] = "_CHECK_STACK_SPACE_r00", [_CHECK_STACK_SPACE_OPERAND] = "_CHECK_STACK_SPACE_OPERAND", + [_CHECK_STACK_SPACE_OPERAND_r00] = "_CHECK_STACK_SPACE_OPERAND_r00", + [_CHECK_STACK_SPACE_OPERAND_r11] = "_CHECK_STACK_SPACE_OPERAND_r11", + [_CHECK_STACK_SPACE_OPERAND_r22] = "_CHECK_STACK_SPACE_OPERAND_r22", + [_CHECK_STACK_SPACE_OPERAND_r33] = "_CHECK_STACK_SPACE_OPERAND_r33", [_CHECK_VALIDITY] = "_CHECK_VALIDITY", + [_CHECK_VALIDITY_r00] = "_CHECK_VALIDITY_r00", + [_CHECK_VALIDITY_r11] = "_CHECK_VALIDITY_r11", + [_CHECK_VALIDITY_r22] = "_CHECK_VALIDITY_r22", + [_CHECK_VALIDITY_r33] = "_CHECK_VALIDITY_r33", + [_COLD_DYNAMIC_EXIT] = "_COLD_DYNAMIC_EXIT", + [_COLD_DYNAMIC_EXIT_r00] = "_COLD_DYNAMIC_EXIT_r00", [_COLD_EXIT] = "_COLD_EXIT", + [_COLD_EXIT_r00] = "_COLD_EXIT_r00", [_COMPARE_OP] = "_COMPARE_OP", + [_COMPARE_OP_r21] = "_COMPARE_OP_r21", [_COMPARE_OP_FLOAT] = "_COMPARE_OP_FLOAT", + [_COMPARE_OP_FLOAT_r01] = "_COMPARE_OP_FLOAT_r01", + [_COMPARE_OP_FLOAT_r11] = "_COMPARE_OP_FLOAT_r11", + [_COMPARE_OP_FLOAT_r21] = "_COMPARE_OP_FLOAT_r21", + [_COMPARE_OP_FLOAT_r32] = "_COMPARE_OP_FLOAT_r32", [_COMPARE_OP_INT] = "_COMPARE_OP_INT", + [_COMPARE_OP_INT_r23] = "_COMPARE_OP_INT_r23", [_COMPARE_OP_STR] = "_COMPARE_OP_STR", + [_COMPARE_OP_STR_r21] = "_COMPARE_OP_STR_r21", [_CONTAINS_OP] = "_CONTAINS_OP", + [_CONTAINS_OP_r21] = "_CONTAINS_OP_r21", [_CONTAINS_OP_DICT] = "_CONTAINS_OP_DICT", + [_CONTAINS_OP_DICT_r21] = "_CONTAINS_OP_DICT_r21", [_CONTAINS_OP_SET] = "_CONTAINS_OP_SET", + [_CONTAINS_OP_SET_r21] = "_CONTAINS_OP_SET_r21", [_CONVERT_VALUE] = "_CONVERT_VALUE", + [_CONVERT_VALUE_r11] = "_CONVERT_VALUE_r11", [_COPY] = "_COPY", + [_COPY_r01] = "_COPY_r01", [_COPY_1] = "_COPY_1", + [_COPY_1_r02] = "_COPY_1_r02", + [_COPY_1_r12] = "_COPY_1_r12", + [_COPY_1_r23] = "_COPY_1_r23", [_COPY_2] = "_COPY_2", + [_COPY_2_r03] = "_COPY_2_r03", + [_COPY_2_r13] = "_COPY_2_r13", + [_COPY_2_r23] = "_COPY_2_r23", [_COPY_3] = "_COPY_3", + [_COPY_3_r03] = "_COPY_3_r03", + [_COPY_3_r13] = "_COPY_3_r13", + [_COPY_3_r23] = "_COPY_3_r23", + [_COPY_3_r33] = "_COPY_3_r33", [_COPY_FREE_VARS] = "_COPY_FREE_VARS", + [_COPY_FREE_VARS_r00] = "_COPY_FREE_VARS_r00", + [_COPY_FREE_VARS_r11] = "_COPY_FREE_VARS_r11", + [_COPY_FREE_VARS_r22] = "_COPY_FREE_VARS_r22", + [_COPY_FREE_VARS_r33] = "_COPY_FREE_VARS_r33", [_CREATE_INIT_FRAME] = "_CREATE_INIT_FRAME", + [_CREATE_INIT_FRAME_r01] = "_CREATE_INIT_FRAME_r01", [_DELETE_ATTR] = "_DELETE_ATTR", + [_DELETE_ATTR_r10] = "_DELETE_ATTR_r10", [_DELETE_DEREF] = "_DELETE_DEREF", + [_DELETE_DEREF_r00] = "_DELETE_DEREF_r00", [_DELETE_FAST] = "_DELETE_FAST", + [_DELETE_FAST_r00] = "_DELETE_FAST_r00", [_DELETE_GLOBAL] = "_DELETE_GLOBAL", + [_DELETE_GLOBAL_r00] = "_DELETE_GLOBAL_r00", [_DELETE_NAME] = "_DELETE_NAME", + [_DELETE_NAME_r00] = "_DELETE_NAME_r00", [_DELETE_SUBSCR] = "_DELETE_SUBSCR", + [_DELETE_SUBSCR_r20] = "_DELETE_SUBSCR_r20", [_DEOPT] = "_DEOPT", + [_DEOPT_r00] = "_DEOPT_r00", + [_DEOPT_r10] = "_DEOPT_r10", + [_DEOPT_r20] = "_DEOPT_r20", + [_DEOPT_r30] = "_DEOPT_r30", [_DICT_MERGE] = "_DICT_MERGE", + [_DICT_MERGE_r10] = "_DICT_MERGE_r10", [_DICT_UPDATE] = "_DICT_UPDATE", + [_DICT_UPDATE_r10] = "_DICT_UPDATE_r10", + [_DYNAMIC_EXIT] = "_DYNAMIC_EXIT", + [_DYNAMIC_EXIT_r00] = "_DYNAMIC_EXIT_r00", + [_DYNAMIC_EXIT_r10] = "_DYNAMIC_EXIT_r10", + [_DYNAMIC_EXIT_r20] = "_DYNAMIC_EXIT_r20", + [_DYNAMIC_EXIT_r30] = "_DYNAMIC_EXIT_r30", [_END_FOR] = "_END_FOR", + [_END_FOR_r10] = "_END_FOR_r10", [_END_SEND] = "_END_SEND", + [_END_SEND_r21] = "_END_SEND_r21", [_ERROR_POP_N] = "_ERROR_POP_N", + [_ERROR_POP_N_r00] = "_ERROR_POP_N_r00", [_EXIT_INIT_CHECK] = "_EXIT_INIT_CHECK", + [_EXIT_INIT_CHECK_r10] = "_EXIT_INIT_CHECK_r10", [_EXIT_TRACE] = "_EXIT_TRACE", + [_EXIT_TRACE_r00] = "_EXIT_TRACE_r00", + [_EXIT_TRACE_r10] = "_EXIT_TRACE_r10", + [_EXIT_TRACE_r20] = "_EXIT_TRACE_r20", + [_EXIT_TRACE_r30] = "_EXIT_TRACE_r30", [_EXPAND_METHOD] = "_EXPAND_METHOD", + [_EXPAND_METHOD_r00] = "_EXPAND_METHOD_r00", [_EXPAND_METHOD_KW] = "_EXPAND_METHOD_KW", + [_EXPAND_METHOD_KW_r11] = "_EXPAND_METHOD_KW_r11", [_FATAL_ERROR] = "_FATAL_ERROR", + [_FATAL_ERROR_r00] = "_FATAL_ERROR_r00", + [_FATAL_ERROR_r11] = "_FATAL_ERROR_r11", + [_FATAL_ERROR_r22] = "_FATAL_ERROR_r22", + [_FATAL_ERROR_r33] = "_FATAL_ERROR_r33", [_FORMAT_SIMPLE] = "_FORMAT_SIMPLE", + [_FORMAT_SIMPLE_r11] = "_FORMAT_SIMPLE_r11", [_FORMAT_WITH_SPEC] = "_FORMAT_WITH_SPEC", + [_FORMAT_WITH_SPEC_r21] = "_FORMAT_WITH_SPEC_r21", [_FOR_ITER_GEN_FRAME] = "_FOR_ITER_GEN_FRAME", + [_FOR_ITER_GEN_FRAME_r23] = "_FOR_ITER_GEN_FRAME_r23", [_FOR_ITER_TIER_TWO] = "_FOR_ITER_TIER_TWO", + [_FOR_ITER_TIER_TWO_r23] = "_FOR_ITER_TIER_TWO_r23", [_GET_AITER] = "_GET_AITER", + [_GET_AITER_r11] = "_GET_AITER_r11", [_GET_ANEXT] = "_GET_ANEXT", + [_GET_ANEXT_r12] = "_GET_ANEXT_r12", [_GET_AWAITABLE] = "_GET_AWAITABLE", + [_GET_AWAITABLE_r11] = "_GET_AWAITABLE_r11", [_GET_ITER] = "_GET_ITER", + [_GET_ITER_r12] = "_GET_ITER_r12", [_GET_LEN] = "_GET_LEN", + [_GET_LEN_r12] = "_GET_LEN_r12", [_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER", + [_GET_YIELD_FROM_ITER_r11] = "_GET_YIELD_FROM_ITER_r11", [_GUARD_BINARY_OP_EXTEND] = "_GUARD_BINARY_OP_EXTEND", + [_GUARD_BINARY_OP_EXTEND_r22] = "_GUARD_BINARY_OP_EXTEND_r22", [_GUARD_CALLABLE_ISINSTANCE] = "_GUARD_CALLABLE_ISINSTANCE", + [_GUARD_CALLABLE_ISINSTANCE_r03] = "_GUARD_CALLABLE_ISINSTANCE_r03", + [_GUARD_CALLABLE_ISINSTANCE_r13] = "_GUARD_CALLABLE_ISINSTANCE_r13", + [_GUARD_CALLABLE_ISINSTANCE_r23] = "_GUARD_CALLABLE_ISINSTANCE_r23", + [_GUARD_CALLABLE_ISINSTANCE_r33] = "_GUARD_CALLABLE_ISINSTANCE_r33", [_GUARD_CALLABLE_LEN] = "_GUARD_CALLABLE_LEN", + [_GUARD_CALLABLE_LEN_r03] = "_GUARD_CALLABLE_LEN_r03", + [_GUARD_CALLABLE_LEN_r13] = "_GUARD_CALLABLE_LEN_r13", + [_GUARD_CALLABLE_LEN_r23] = "_GUARD_CALLABLE_LEN_r23", + [_GUARD_CALLABLE_LEN_r33] = "_GUARD_CALLABLE_LEN_r33", [_GUARD_CALLABLE_LIST_APPEND] = "_GUARD_CALLABLE_LIST_APPEND", + [_GUARD_CALLABLE_LIST_APPEND_r03] = "_GUARD_CALLABLE_LIST_APPEND_r03", + [_GUARD_CALLABLE_LIST_APPEND_r13] = "_GUARD_CALLABLE_LIST_APPEND_r13", + [_GUARD_CALLABLE_LIST_APPEND_r23] = "_GUARD_CALLABLE_LIST_APPEND_r23", + [_GUARD_CALLABLE_LIST_APPEND_r33] = "_GUARD_CALLABLE_LIST_APPEND_r33", [_GUARD_CALLABLE_STR_1] = "_GUARD_CALLABLE_STR_1", + [_GUARD_CALLABLE_STR_1_r03] = "_GUARD_CALLABLE_STR_1_r03", + [_GUARD_CALLABLE_STR_1_r13] = "_GUARD_CALLABLE_STR_1_r13", + [_GUARD_CALLABLE_STR_1_r23] = "_GUARD_CALLABLE_STR_1_r23", + [_GUARD_CALLABLE_STR_1_r33] = "_GUARD_CALLABLE_STR_1_r33", [_GUARD_CALLABLE_TUPLE_1] = "_GUARD_CALLABLE_TUPLE_1", + [_GUARD_CALLABLE_TUPLE_1_r03] = "_GUARD_CALLABLE_TUPLE_1_r03", + [_GUARD_CALLABLE_TUPLE_1_r13] = "_GUARD_CALLABLE_TUPLE_1_r13", + [_GUARD_CALLABLE_TUPLE_1_r23] = "_GUARD_CALLABLE_TUPLE_1_r23", + [_GUARD_CALLABLE_TUPLE_1_r33] = "_GUARD_CALLABLE_TUPLE_1_r33", [_GUARD_CALLABLE_TYPE_1] = "_GUARD_CALLABLE_TYPE_1", + [_GUARD_CALLABLE_TYPE_1_r03] = "_GUARD_CALLABLE_TYPE_1_r03", + [_GUARD_CALLABLE_TYPE_1_r13] = "_GUARD_CALLABLE_TYPE_1_r13", + [_GUARD_CALLABLE_TYPE_1_r23] = "_GUARD_CALLABLE_TYPE_1_r23", + [_GUARD_CALLABLE_TYPE_1_r33] = "_GUARD_CALLABLE_TYPE_1_r33", [_GUARD_DORV_NO_DICT] = "_GUARD_DORV_NO_DICT", + [_GUARD_DORV_NO_DICT_r01] = "_GUARD_DORV_NO_DICT_r01", + [_GUARD_DORV_NO_DICT_r11] = "_GUARD_DORV_NO_DICT_r11", + [_GUARD_DORV_NO_DICT_r22] = "_GUARD_DORV_NO_DICT_r22", + [_GUARD_DORV_NO_DICT_r33] = "_GUARD_DORV_NO_DICT_r33", [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT", + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01", + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11", + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22", + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33", [_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION", + [_GUARD_GLOBALS_VERSION_r00] = "_GUARD_GLOBALS_VERSION_r00", + [_GUARD_GLOBALS_VERSION_r11] = "_GUARD_GLOBALS_VERSION_r11", + [_GUARD_GLOBALS_VERSION_r22] = "_GUARD_GLOBALS_VERSION_r22", + [_GUARD_GLOBALS_VERSION_r33] = "_GUARD_GLOBALS_VERSION_r33", + [_GUARD_IP_RETURN_GENERATOR] = "_GUARD_IP_RETURN_GENERATOR", + [_GUARD_IP_RETURN_GENERATOR_r00] = "_GUARD_IP_RETURN_GENERATOR_r00", + [_GUARD_IP_RETURN_GENERATOR_r11] = "_GUARD_IP_RETURN_GENERATOR_r11", + [_GUARD_IP_RETURN_GENERATOR_r22] = "_GUARD_IP_RETURN_GENERATOR_r22", + [_GUARD_IP_RETURN_GENERATOR_r33] = "_GUARD_IP_RETURN_GENERATOR_r33", + [_GUARD_IP_RETURN_VALUE] = "_GUARD_IP_RETURN_VALUE", + [_GUARD_IP_RETURN_VALUE_r00] = "_GUARD_IP_RETURN_VALUE_r00", + [_GUARD_IP_RETURN_VALUE_r11] = "_GUARD_IP_RETURN_VALUE_r11", + [_GUARD_IP_RETURN_VALUE_r22] = "_GUARD_IP_RETURN_VALUE_r22", + [_GUARD_IP_RETURN_VALUE_r33] = "_GUARD_IP_RETURN_VALUE_r33", + [_GUARD_IP_YIELD_VALUE] = "_GUARD_IP_YIELD_VALUE", + [_GUARD_IP_YIELD_VALUE_r00] = "_GUARD_IP_YIELD_VALUE_r00", + [_GUARD_IP_YIELD_VALUE_r11] = "_GUARD_IP_YIELD_VALUE_r11", + [_GUARD_IP_YIELD_VALUE_r22] = "_GUARD_IP_YIELD_VALUE_r22", + [_GUARD_IP_YIELD_VALUE_r33] = "_GUARD_IP_YIELD_VALUE_r33", + [_GUARD_IP__PUSH_FRAME] = "_GUARD_IP__PUSH_FRAME", + [_GUARD_IP__PUSH_FRAME_r00] = "_GUARD_IP__PUSH_FRAME_r00", + [_GUARD_IP__PUSH_FRAME_r11] = "_GUARD_IP__PUSH_FRAME_r11", + [_GUARD_IP__PUSH_FRAME_r22] = "_GUARD_IP__PUSH_FRAME_r22", + [_GUARD_IP__PUSH_FRAME_r33] = "_GUARD_IP__PUSH_FRAME_r33", [_GUARD_IS_FALSE_POP] = "_GUARD_IS_FALSE_POP", + [_GUARD_IS_FALSE_POP_r00] = "_GUARD_IS_FALSE_POP_r00", + [_GUARD_IS_FALSE_POP_r10] = "_GUARD_IS_FALSE_POP_r10", + [_GUARD_IS_FALSE_POP_r21] = "_GUARD_IS_FALSE_POP_r21", + [_GUARD_IS_FALSE_POP_r32] = "_GUARD_IS_FALSE_POP_r32", [_GUARD_IS_NONE_POP] = "_GUARD_IS_NONE_POP", + [_GUARD_IS_NONE_POP_r00] = "_GUARD_IS_NONE_POP_r00", + [_GUARD_IS_NONE_POP_r10] = "_GUARD_IS_NONE_POP_r10", + [_GUARD_IS_NONE_POP_r21] = "_GUARD_IS_NONE_POP_r21", + [_GUARD_IS_NONE_POP_r32] = "_GUARD_IS_NONE_POP_r32", [_GUARD_IS_NOT_NONE_POP] = "_GUARD_IS_NOT_NONE_POP", + [_GUARD_IS_NOT_NONE_POP_r10] = "_GUARD_IS_NOT_NONE_POP_r10", [_GUARD_IS_TRUE_POP] = "_GUARD_IS_TRUE_POP", + [_GUARD_IS_TRUE_POP_r00] = "_GUARD_IS_TRUE_POP_r00", + [_GUARD_IS_TRUE_POP_r10] = "_GUARD_IS_TRUE_POP_r10", + [_GUARD_IS_TRUE_POP_r21] = "_GUARD_IS_TRUE_POP_r21", + [_GUARD_IS_TRUE_POP_r32] = "_GUARD_IS_TRUE_POP_r32", [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", + [_GUARD_KEYS_VERSION_r01] = "_GUARD_KEYS_VERSION_r01", + [_GUARD_KEYS_VERSION_r11] = "_GUARD_KEYS_VERSION_r11", + [_GUARD_KEYS_VERSION_r22] = "_GUARD_KEYS_VERSION_r22", + [_GUARD_KEYS_VERSION_r33] = "_GUARD_KEYS_VERSION_r33", [_GUARD_NOS_DICT] = "_GUARD_NOS_DICT", + [_GUARD_NOS_DICT_r02] = "_GUARD_NOS_DICT_r02", + [_GUARD_NOS_DICT_r12] = "_GUARD_NOS_DICT_r12", + [_GUARD_NOS_DICT_r22] = "_GUARD_NOS_DICT_r22", + [_GUARD_NOS_DICT_r33] = "_GUARD_NOS_DICT_r33", [_GUARD_NOS_FLOAT] = "_GUARD_NOS_FLOAT", + [_GUARD_NOS_FLOAT_r02] = "_GUARD_NOS_FLOAT_r02", + [_GUARD_NOS_FLOAT_r12] = "_GUARD_NOS_FLOAT_r12", + [_GUARD_NOS_FLOAT_r22] = "_GUARD_NOS_FLOAT_r22", + [_GUARD_NOS_FLOAT_r33] = "_GUARD_NOS_FLOAT_r33", [_GUARD_NOS_INT] = "_GUARD_NOS_INT", + [_GUARD_NOS_INT_r02] = "_GUARD_NOS_INT_r02", + [_GUARD_NOS_INT_r12] = "_GUARD_NOS_INT_r12", + [_GUARD_NOS_INT_r22] = "_GUARD_NOS_INT_r22", + [_GUARD_NOS_INT_r33] = "_GUARD_NOS_INT_r33", [_GUARD_NOS_LIST] = "_GUARD_NOS_LIST", + [_GUARD_NOS_LIST_r02] = "_GUARD_NOS_LIST_r02", + [_GUARD_NOS_LIST_r12] = "_GUARD_NOS_LIST_r12", + [_GUARD_NOS_LIST_r22] = "_GUARD_NOS_LIST_r22", + [_GUARD_NOS_LIST_r33] = "_GUARD_NOS_LIST_r33", [_GUARD_NOS_NOT_NULL] = "_GUARD_NOS_NOT_NULL", + [_GUARD_NOS_NOT_NULL_r02] = "_GUARD_NOS_NOT_NULL_r02", + [_GUARD_NOS_NOT_NULL_r12] = "_GUARD_NOS_NOT_NULL_r12", + [_GUARD_NOS_NOT_NULL_r22] = "_GUARD_NOS_NOT_NULL_r22", + [_GUARD_NOS_NOT_NULL_r33] = "_GUARD_NOS_NOT_NULL_r33", [_GUARD_NOS_NULL] = "_GUARD_NOS_NULL", + [_GUARD_NOS_NULL_r02] = "_GUARD_NOS_NULL_r02", + [_GUARD_NOS_NULL_r12] = "_GUARD_NOS_NULL_r12", + [_GUARD_NOS_NULL_r22] = "_GUARD_NOS_NULL_r22", + [_GUARD_NOS_NULL_r33] = "_GUARD_NOS_NULL_r33", [_GUARD_NOS_OVERFLOWED] = "_GUARD_NOS_OVERFLOWED", + [_GUARD_NOS_OVERFLOWED_r02] = "_GUARD_NOS_OVERFLOWED_r02", + [_GUARD_NOS_OVERFLOWED_r12] = "_GUARD_NOS_OVERFLOWED_r12", + [_GUARD_NOS_OVERFLOWED_r22] = "_GUARD_NOS_OVERFLOWED_r22", + [_GUARD_NOS_OVERFLOWED_r33] = "_GUARD_NOS_OVERFLOWED_r33", [_GUARD_NOS_TUPLE] = "_GUARD_NOS_TUPLE", + [_GUARD_NOS_TUPLE_r02] = "_GUARD_NOS_TUPLE_r02", + [_GUARD_NOS_TUPLE_r12] = "_GUARD_NOS_TUPLE_r12", + [_GUARD_NOS_TUPLE_r22] = "_GUARD_NOS_TUPLE_r22", + [_GUARD_NOS_TUPLE_r33] = "_GUARD_NOS_TUPLE_r33", [_GUARD_NOS_UNICODE] = "_GUARD_NOS_UNICODE", + [_GUARD_NOS_UNICODE_r02] = "_GUARD_NOS_UNICODE_r02", + [_GUARD_NOS_UNICODE_r12] = "_GUARD_NOS_UNICODE_r12", + [_GUARD_NOS_UNICODE_r22] = "_GUARD_NOS_UNICODE_r22", + [_GUARD_NOS_UNICODE_r33] = "_GUARD_NOS_UNICODE_r33", [_GUARD_NOT_EXHAUSTED_LIST] = "_GUARD_NOT_EXHAUSTED_LIST", + [_GUARD_NOT_EXHAUSTED_LIST_r02] = "_GUARD_NOT_EXHAUSTED_LIST_r02", + [_GUARD_NOT_EXHAUSTED_LIST_r12] = "_GUARD_NOT_EXHAUSTED_LIST_r12", + [_GUARD_NOT_EXHAUSTED_LIST_r22] = "_GUARD_NOT_EXHAUSTED_LIST_r22", + [_GUARD_NOT_EXHAUSTED_LIST_r33] = "_GUARD_NOT_EXHAUSTED_LIST_r33", [_GUARD_NOT_EXHAUSTED_RANGE] = "_GUARD_NOT_EXHAUSTED_RANGE", + [_GUARD_NOT_EXHAUSTED_RANGE_r02] = "_GUARD_NOT_EXHAUSTED_RANGE_r02", + [_GUARD_NOT_EXHAUSTED_RANGE_r12] = "_GUARD_NOT_EXHAUSTED_RANGE_r12", + [_GUARD_NOT_EXHAUSTED_RANGE_r22] = "_GUARD_NOT_EXHAUSTED_RANGE_r22", + [_GUARD_NOT_EXHAUSTED_RANGE_r33] = "_GUARD_NOT_EXHAUSTED_RANGE_r33", [_GUARD_NOT_EXHAUSTED_TUPLE] = "_GUARD_NOT_EXHAUSTED_TUPLE", + [_GUARD_NOT_EXHAUSTED_TUPLE_r02] = "_GUARD_NOT_EXHAUSTED_TUPLE_r02", + [_GUARD_NOT_EXHAUSTED_TUPLE_r12] = "_GUARD_NOT_EXHAUSTED_TUPLE_r12", + [_GUARD_NOT_EXHAUSTED_TUPLE_r22] = "_GUARD_NOT_EXHAUSTED_TUPLE_r22", + [_GUARD_NOT_EXHAUSTED_TUPLE_r33] = "_GUARD_NOT_EXHAUSTED_TUPLE_r33", [_GUARD_THIRD_NULL] = "_GUARD_THIRD_NULL", + [_GUARD_THIRD_NULL_r03] = "_GUARD_THIRD_NULL_r03", + [_GUARD_THIRD_NULL_r13] = "_GUARD_THIRD_NULL_r13", + [_GUARD_THIRD_NULL_r23] = "_GUARD_THIRD_NULL_r23", + [_GUARD_THIRD_NULL_r33] = "_GUARD_THIRD_NULL_r33", [_GUARD_TOS_ANY_SET] = "_GUARD_TOS_ANY_SET", + [_GUARD_TOS_ANY_SET_r01] = "_GUARD_TOS_ANY_SET_r01", + [_GUARD_TOS_ANY_SET_r11] = "_GUARD_TOS_ANY_SET_r11", + [_GUARD_TOS_ANY_SET_r22] = "_GUARD_TOS_ANY_SET_r22", + [_GUARD_TOS_ANY_SET_r33] = "_GUARD_TOS_ANY_SET_r33", [_GUARD_TOS_DICT] = "_GUARD_TOS_DICT", + [_GUARD_TOS_DICT_r01] = "_GUARD_TOS_DICT_r01", + [_GUARD_TOS_DICT_r11] = "_GUARD_TOS_DICT_r11", + [_GUARD_TOS_DICT_r22] = "_GUARD_TOS_DICT_r22", + [_GUARD_TOS_DICT_r33] = "_GUARD_TOS_DICT_r33", [_GUARD_TOS_FLOAT] = "_GUARD_TOS_FLOAT", + [_GUARD_TOS_FLOAT_r01] = "_GUARD_TOS_FLOAT_r01", + [_GUARD_TOS_FLOAT_r11] = "_GUARD_TOS_FLOAT_r11", + [_GUARD_TOS_FLOAT_r22] = "_GUARD_TOS_FLOAT_r22", + [_GUARD_TOS_FLOAT_r33] = "_GUARD_TOS_FLOAT_r33", [_GUARD_TOS_INT] = "_GUARD_TOS_INT", + [_GUARD_TOS_INT_r01] = "_GUARD_TOS_INT_r01", + [_GUARD_TOS_INT_r11] = "_GUARD_TOS_INT_r11", + [_GUARD_TOS_INT_r22] = "_GUARD_TOS_INT_r22", + [_GUARD_TOS_INT_r33] = "_GUARD_TOS_INT_r33", [_GUARD_TOS_LIST] = "_GUARD_TOS_LIST", + [_GUARD_TOS_LIST_r01] = "_GUARD_TOS_LIST_r01", + [_GUARD_TOS_LIST_r11] = "_GUARD_TOS_LIST_r11", + [_GUARD_TOS_LIST_r22] = "_GUARD_TOS_LIST_r22", + [_GUARD_TOS_LIST_r33] = "_GUARD_TOS_LIST_r33", [_GUARD_TOS_OVERFLOWED] = "_GUARD_TOS_OVERFLOWED", + [_GUARD_TOS_OVERFLOWED_r01] = "_GUARD_TOS_OVERFLOWED_r01", + [_GUARD_TOS_OVERFLOWED_r11] = "_GUARD_TOS_OVERFLOWED_r11", + [_GUARD_TOS_OVERFLOWED_r22] = "_GUARD_TOS_OVERFLOWED_r22", + [_GUARD_TOS_OVERFLOWED_r33] = "_GUARD_TOS_OVERFLOWED_r33", [_GUARD_TOS_SLICE] = "_GUARD_TOS_SLICE", + [_GUARD_TOS_SLICE_r01] = "_GUARD_TOS_SLICE_r01", + [_GUARD_TOS_SLICE_r11] = "_GUARD_TOS_SLICE_r11", + [_GUARD_TOS_SLICE_r22] = "_GUARD_TOS_SLICE_r22", + [_GUARD_TOS_SLICE_r33] = "_GUARD_TOS_SLICE_r33", [_GUARD_TOS_TUPLE] = "_GUARD_TOS_TUPLE", + [_GUARD_TOS_TUPLE_r01] = "_GUARD_TOS_TUPLE_r01", + [_GUARD_TOS_TUPLE_r11] = "_GUARD_TOS_TUPLE_r11", + [_GUARD_TOS_TUPLE_r22] = "_GUARD_TOS_TUPLE_r22", + [_GUARD_TOS_TUPLE_r33] = "_GUARD_TOS_TUPLE_r33", [_GUARD_TOS_UNICODE] = "_GUARD_TOS_UNICODE", + [_GUARD_TOS_UNICODE_r01] = "_GUARD_TOS_UNICODE_r01", + [_GUARD_TOS_UNICODE_r11] = "_GUARD_TOS_UNICODE_r11", + [_GUARD_TOS_UNICODE_r22] = "_GUARD_TOS_UNICODE_r22", + [_GUARD_TOS_UNICODE_r33] = "_GUARD_TOS_UNICODE_r33", [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", + [_GUARD_TYPE_VERSION_r01] = "_GUARD_TYPE_VERSION_r01", + [_GUARD_TYPE_VERSION_r11] = "_GUARD_TYPE_VERSION_r11", + [_GUARD_TYPE_VERSION_r22] = "_GUARD_TYPE_VERSION_r22", + [_GUARD_TYPE_VERSION_r33] = "_GUARD_TYPE_VERSION_r33", [_GUARD_TYPE_VERSION_AND_LOCK] = "_GUARD_TYPE_VERSION_AND_LOCK", + [_GUARD_TYPE_VERSION_AND_LOCK_r01] = "_GUARD_TYPE_VERSION_AND_LOCK_r01", + [_GUARD_TYPE_VERSION_AND_LOCK_r11] = "_GUARD_TYPE_VERSION_AND_LOCK_r11", + [_GUARD_TYPE_VERSION_AND_LOCK_r22] = "_GUARD_TYPE_VERSION_AND_LOCK_r22", + [_GUARD_TYPE_VERSION_AND_LOCK_r33] = "_GUARD_TYPE_VERSION_AND_LOCK_r33", [_HANDLE_PENDING_AND_DEOPT] = "_HANDLE_PENDING_AND_DEOPT", + [_HANDLE_PENDING_AND_DEOPT_r00] = "_HANDLE_PENDING_AND_DEOPT_r00", + [_HANDLE_PENDING_AND_DEOPT_r10] = "_HANDLE_PENDING_AND_DEOPT_r10", + [_HANDLE_PENDING_AND_DEOPT_r20] = "_HANDLE_PENDING_AND_DEOPT_r20", + [_HANDLE_PENDING_AND_DEOPT_r30] = "_HANDLE_PENDING_AND_DEOPT_r30", [_IMPORT_FROM] = "_IMPORT_FROM", + [_IMPORT_FROM_r12] = "_IMPORT_FROM_r12", [_IMPORT_NAME] = "_IMPORT_NAME", + [_IMPORT_NAME_r21] = "_IMPORT_NAME_r21", [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", + [_INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00", [_INIT_CALL_PY_EXACT_ARGS] = "_INIT_CALL_PY_EXACT_ARGS", + [_INIT_CALL_PY_EXACT_ARGS_r01] = "_INIT_CALL_PY_EXACT_ARGS_r01", [_INIT_CALL_PY_EXACT_ARGS_0] = "_INIT_CALL_PY_EXACT_ARGS_0", + [_INIT_CALL_PY_EXACT_ARGS_0_r01] = "_INIT_CALL_PY_EXACT_ARGS_0_r01", [_INIT_CALL_PY_EXACT_ARGS_1] = "_INIT_CALL_PY_EXACT_ARGS_1", + [_INIT_CALL_PY_EXACT_ARGS_1_r01] = "_INIT_CALL_PY_EXACT_ARGS_1_r01", [_INIT_CALL_PY_EXACT_ARGS_2] = "_INIT_CALL_PY_EXACT_ARGS_2", + [_INIT_CALL_PY_EXACT_ARGS_2_r01] = "_INIT_CALL_PY_EXACT_ARGS_2_r01", [_INIT_CALL_PY_EXACT_ARGS_3] = "_INIT_CALL_PY_EXACT_ARGS_3", + [_INIT_CALL_PY_EXACT_ARGS_3_r01] = "_INIT_CALL_PY_EXACT_ARGS_3_r01", [_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4", + [_INIT_CALL_PY_EXACT_ARGS_4_r01] = "_INIT_CALL_PY_EXACT_ARGS_4_r01", [_INSERT_NULL] = "_INSERT_NULL", + [_INSERT_NULL_r10] = "_INSERT_NULL_r10", [_IS_NONE] = "_IS_NONE", + [_IS_NONE_r11] = "_IS_NONE_r11", [_IS_OP] = "_IS_OP", + [_IS_OP_r21] = "_IS_OP_r21", [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", + [_ITER_CHECK_LIST_r02] = "_ITER_CHECK_LIST_r02", + [_ITER_CHECK_LIST_r12] = "_ITER_CHECK_LIST_r12", + [_ITER_CHECK_LIST_r22] = "_ITER_CHECK_LIST_r22", + [_ITER_CHECK_LIST_r33] = "_ITER_CHECK_LIST_r33", [_ITER_CHECK_RANGE] = "_ITER_CHECK_RANGE", + [_ITER_CHECK_RANGE_r02] = "_ITER_CHECK_RANGE_r02", + [_ITER_CHECK_RANGE_r12] = "_ITER_CHECK_RANGE_r12", + [_ITER_CHECK_RANGE_r22] = "_ITER_CHECK_RANGE_r22", + [_ITER_CHECK_RANGE_r33] = "_ITER_CHECK_RANGE_r33", [_ITER_CHECK_TUPLE] = "_ITER_CHECK_TUPLE", + [_ITER_CHECK_TUPLE_r02] = "_ITER_CHECK_TUPLE_r02", + [_ITER_CHECK_TUPLE_r12] = "_ITER_CHECK_TUPLE_r12", + [_ITER_CHECK_TUPLE_r22] = "_ITER_CHECK_TUPLE_r22", + [_ITER_CHECK_TUPLE_r33] = "_ITER_CHECK_TUPLE_r33", [_ITER_NEXT_LIST_TIER_TWO] = "_ITER_NEXT_LIST_TIER_TWO", + [_ITER_NEXT_LIST_TIER_TWO_r23] = "_ITER_NEXT_LIST_TIER_TWO_r23", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", + [_ITER_NEXT_RANGE_r03] = "_ITER_NEXT_RANGE_r03", + [_ITER_NEXT_RANGE_r13] = "_ITER_NEXT_RANGE_r13", + [_ITER_NEXT_RANGE_r23] = "_ITER_NEXT_RANGE_r23", [_ITER_NEXT_TUPLE] = "_ITER_NEXT_TUPLE", + [_ITER_NEXT_TUPLE_r03] = "_ITER_NEXT_TUPLE_r03", + [_ITER_NEXT_TUPLE_r13] = "_ITER_NEXT_TUPLE_r13", + [_ITER_NEXT_TUPLE_r23] = "_ITER_NEXT_TUPLE_r23", [_JUMP_TO_TOP] = "_JUMP_TO_TOP", + [_JUMP_TO_TOP_r00] = "_JUMP_TO_TOP_r00", [_LIST_APPEND] = "_LIST_APPEND", + [_LIST_APPEND_r10] = "_LIST_APPEND_r10", [_LIST_EXTEND] = "_LIST_EXTEND", + [_LIST_EXTEND_r10] = "_LIST_EXTEND_r10", [_LOAD_ATTR] = "_LOAD_ATTR", + [_LOAD_ATTR_r10] = "_LOAD_ATTR_r10", [_LOAD_ATTR_CLASS] = "_LOAD_ATTR_CLASS", + [_LOAD_ATTR_CLASS_r11] = "_LOAD_ATTR_CLASS_r11", [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", + [_LOAD_ATTR_INSTANCE_VALUE_r02] = "_LOAD_ATTR_INSTANCE_VALUE_r02", + [_LOAD_ATTR_INSTANCE_VALUE_r12] = "_LOAD_ATTR_INSTANCE_VALUE_r12", + [_LOAD_ATTR_INSTANCE_VALUE_r23] = "_LOAD_ATTR_INSTANCE_VALUE_r23", [_LOAD_ATTR_METHOD_LAZY_DICT] = "_LOAD_ATTR_METHOD_LAZY_DICT", + [_LOAD_ATTR_METHOD_LAZY_DICT_r02] = "_LOAD_ATTR_METHOD_LAZY_DICT_r02", + [_LOAD_ATTR_METHOD_LAZY_DICT_r12] = "_LOAD_ATTR_METHOD_LAZY_DICT_r12", + [_LOAD_ATTR_METHOD_LAZY_DICT_r23] = "_LOAD_ATTR_METHOD_LAZY_DICT_r23", [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", + [_LOAD_ATTR_METHOD_NO_DICT_r02] = "_LOAD_ATTR_METHOD_NO_DICT_r02", + [_LOAD_ATTR_METHOD_NO_DICT_r12] = "_LOAD_ATTR_METHOD_NO_DICT_r12", + [_LOAD_ATTR_METHOD_NO_DICT_r23] = "_LOAD_ATTR_METHOD_NO_DICT_r23", [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", + [_LOAD_ATTR_METHOD_WITH_VALUES_r02] = "_LOAD_ATTR_METHOD_WITH_VALUES_r02", + [_LOAD_ATTR_METHOD_WITH_VALUES_r12] = "_LOAD_ATTR_METHOD_WITH_VALUES_r12", + [_LOAD_ATTR_METHOD_WITH_VALUES_r23] = "_LOAD_ATTR_METHOD_WITH_VALUES_r23", [_LOAD_ATTR_MODULE] = "_LOAD_ATTR_MODULE", + [_LOAD_ATTR_MODULE_r11] = "_LOAD_ATTR_MODULE_r11", [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT", + [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11", [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", + [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11", [_LOAD_ATTR_PROPERTY_FRAME] = "_LOAD_ATTR_PROPERTY_FRAME", + [_LOAD_ATTR_PROPERTY_FRAME_r11] = "_LOAD_ATTR_PROPERTY_FRAME_r11", [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", + [_LOAD_ATTR_SLOT_r11] = "_LOAD_ATTR_SLOT_r11", [_LOAD_ATTR_WITH_HINT] = "_LOAD_ATTR_WITH_HINT", + [_LOAD_ATTR_WITH_HINT_r11] = "_LOAD_ATTR_WITH_HINT_r11", [_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS", + [_LOAD_BUILD_CLASS_r01] = "_LOAD_BUILD_CLASS_r01", [_LOAD_COMMON_CONSTANT] = "_LOAD_COMMON_CONSTANT", + [_LOAD_COMMON_CONSTANT_r01] = "_LOAD_COMMON_CONSTANT_r01", + [_LOAD_COMMON_CONSTANT_r12] = "_LOAD_COMMON_CONSTANT_r12", + [_LOAD_COMMON_CONSTANT_r23] = "_LOAD_COMMON_CONSTANT_r23", [_LOAD_CONST] = "_LOAD_CONST", + [_LOAD_CONST_r01] = "_LOAD_CONST_r01", + [_LOAD_CONST_r12] = "_LOAD_CONST_r12", + [_LOAD_CONST_r23] = "_LOAD_CONST_r23", [_LOAD_CONST_INLINE] = "_LOAD_CONST_INLINE", + [_LOAD_CONST_INLINE_r01] = "_LOAD_CONST_INLINE_r01", + [_LOAD_CONST_INLINE_r12] = "_LOAD_CONST_INLINE_r12", + [_LOAD_CONST_INLINE_r23] = "_LOAD_CONST_INLINE_r23", [_LOAD_CONST_INLINE_BORROW] = "_LOAD_CONST_INLINE_BORROW", + [_LOAD_CONST_INLINE_BORROW_r01] = "_LOAD_CONST_INLINE_BORROW_r01", + [_LOAD_CONST_INLINE_BORROW_r12] = "_LOAD_CONST_INLINE_BORROW_r12", + [_LOAD_CONST_INLINE_BORROW_r23] = "_LOAD_CONST_INLINE_BORROW_r23", [_LOAD_CONST_UNDER_INLINE] = "_LOAD_CONST_UNDER_INLINE", + [_LOAD_CONST_UNDER_INLINE_r02] = "_LOAD_CONST_UNDER_INLINE_r02", + [_LOAD_CONST_UNDER_INLINE_r12] = "_LOAD_CONST_UNDER_INLINE_r12", + [_LOAD_CONST_UNDER_INLINE_r23] = "_LOAD_CONST_UNDER_INLINE_r23", [_LOAD_CONST_UNDER_INLINE_BORROW] = "_LOAD_CONST_UNDER_INLINE_BORROW", + [_LOAD_CONST_UNDER_INLINE_BORROW_r02] = "_LOAD_CONST_UNDER_INLINE_BORROW_r02", + [_LOAD_CONST_UNDER_INLINE_BORROW_r12] = "_LOAD_CONST_UNDER_INLINE_BORROW_r12", + [_LOAD_CONST_UNDER_INLINE_BORROW_r23] = "_LOAD_CONST_UNDER_INLINE_BORROW_r23", [_LOAD_DEREF] = "_LOAD_DEREF", + [_LOAD_DEREF_r01] = "_LOAD_DEREF_r01", [_LOAD_FAST] = "_LOAD_FAST", + [_LOAD_FAST_r01] = "_LOAD_FAST_r01", + [_LOAD_FAST_r12] = "_LOAD_FAST_r12", + [_LOAD_FAST_r23] = "_LOAD_FAST_r23", [_LOAD_FAST_0] = "_LOAD_FAST_0", + [_LOAD_FAST_0_r01] = "_LOAD_FAST_0_r01", + [_LOAD_FAST_0_r12] = "_LOAD_FAST_0_r12", + [_LOAD_FAST_0_r23] = "_LOAD_FAST_0_r23", [_LOAD_FAST_1] = "_LOAD_FAST_1", + [_LOAD_FAST_1_r01] = "_LOAD_FAST_1_r01", + [_LOAD_FAST_1_r12] = "_LOAD_FAST_1_r12", + [_LOAD_FAST_1_r23] = "_LOAD_FAST_1_r23", [_LOAD_FAST_2] = "_LOAD_FAST_2", + [_LOAD_FAST_2_r01] = "_LOAD_FAST_2_r01", + [_LOAD_FAST_2_r12] = "_LOAD_FAST_2_r12", + [_LOAD_FAST_2_r23] = "_LOAD_FAST_2_r23", [_LOAD_FAST_3] = "_LOAD_FAST_3", + [_LOAD_FAST_3_r01] = "_LOAD_FAST_3_r01", + [_LOAD_FAST_3_r12] = "_LOAD_FAST_3_r12", + [_LOAD_FAST_3_r23] = "_LOAD_FAST_3_r23", [_LOAD_FAST_4] = "_LOAD_FAST_4", + [_LOAD_FAST_4_r01] = "_LOAD_FAST_4_r01", + [_LOAD_FAST_4_r12] = "_LOAD_FAST_4_r12", + [_LOAD_FAST_4_r23] = "_LOAD_FAST_4_r23", [_LOAD_FAST_5] = "_LOAD_FAST_5", + [_LOAD_FAST_5_r01] = "_LOAD_FAST_5_r01", + [_LOAD_FAST_5_r12] = "_LOAD_FAST_5_r12", + [_LOAD_FAST_5_r23] = "_LOAD_FAST_5_r23", [_LOAD_FAST_6] = "_LOAD_FAST_6", + [_LOAD_FAST_6_r01] = "_LOAD_FAST_6_r01", + [_LOAD_FAST_6_r12] = "_LOAD_FAST_6_r12", + [_LOAD_FAST_6_r23] = "_LOAD_FAST_6_r23", [_LOAD_FAST_7] = "_LOAD_FAST_7", + [_LOAD_FAST_7_r01] = "_LOAD_FAST_7_r01", + [_LOAD_FAST_7_r12] = "_LOAD_FAST_7_r12", + [_LOAD_FAST_7_r23] = "_LOAD_FAST_7_r23", [_LOAD_FAST_AND_CLEAR] = "_LOAD_FAST_AND_CLEAR", + [_LOAD_FAST_AND_CLEAR_r01] = "_LOAD_FAST_AND_CLEAR_r01", + [_LOAD_FAST_AND_CLEAR_r12] = "_LOAD_FAST_AND_CLEAR_r12", + [_LOAD_FAST_AND_CLEAR_r23] = "_LOAD_FAST_AND_CLEAR_r23", [_LOAD_FAST_BORROW] = "_LOAD_FAST_BORROW", + [_LOAD_FAST_BORROW_r01] = "_LOAD_FAST_BORROW_r01", + [_LOAD_FAST_BORROW_r12] = "_LOAD_FAST_BORROW_r12", + [_LOAD_FAST_BORROW_r23] = "_LOAD_FAST_BORROW_r23", [_LOAD_FAST_BORROW_0] = "_LOAD_FAST_BORROW_0", + [_LOAD_FAST_BORROW_0_r01] = "_LOAD_FAST_BORROW_0_r01", + [_LOAD_FAST_BORROW_0_r12] = "_LOAD_FAST_BORROW_0_r12", + [_LOAD_FAST_BORROW_0_r23] = "_LOAD_FAST_BORROW_0_r23", [_LOAD_FAST_BORROW_1] = "_LOAD_FAST_BORROW_1", + [_LOAD_FAST_BORROW_1_r01] = "_LOAD_FAST_BORROW_1_r01", + [_LOAD_FAST_BORROW_1_r12] = "_LOAD_FAST_BORROW_1_r12", + [_LOAD_FAST_BORROW_1_r23] = "_LOAD_FAST_BORROW_1_r23", [_LOAD_FAST_BORROW_2] = "_LOAD_FAST_BORROW_2", + [_LOAD_FAST_BORROW_2_r01] = "_LOAD_FAST_BORROW_2_r01", + [_LOAD_FAST_BORROW_2_r12] = "_LOAD_FAST_BORROW_2_r12", + [_LOAD_FAST_BORROW_2_r23] = "_LOAD_FAST_BORROW_2_r23", [_LOAD_FAST_BORROW_3] = "_LOAD_FAST_BORROW_3", + [_LOAD_FAST_BORROW_3_r01] = "_LOAD_FAST_BORROW_3_r01", + [_LOAD_FAST_BORROW_3_r12] = "_LOAD_FAST_BORROW_3_r12", + [_LOAD_FAST_BORROW_3_r23] = "_LOAD_FAST_BORROW_3_r23", [_LOAD_FAST_BORROW_4] = "_LOAD_FAST_BORROW_4", + [_LOAD_FAST_BORROW_4_r01] = "_LOAD_FAST_BORROW_4_r01", + [_LOAD_FAST_BORROW_4_r12] = "_LOAD_FAST_BORROW_4_r12", + [_LOAD_FAST_BORROW_4_r23] = "_LOAD_FAST_BORROW_4_r23", [_LOAD_FAST_BORROW_5] = "_LOAD_FAST_BORROW_5", + [_LOAD_FAST_BORROW_5_r01] = "_LOAD_FAST_BORROW_5_r01", + [_LOAD_FAST_BORROW_5_r12] = "_LOAD_FAST_BORROW_5_r12", + [_LOAD_FAST_BORROW_5_r23] = "_LOAD_FAST_BORROW_5_r23", [_LOAD_FAST_BORROW_6] = "_LOAD_FAST_BORROW_6", + [_LOAD_FAST_BORROW_6_r01] = "_LOAD_FAST_BORROW_6_r01", + [_LOAD_FAST_BORROW_6_r12] = "_LOAD_FAST_BORROW_6_r12", + [_LOAD_FAST_BORROW_6_r23] = "_LOAD_FAST_BORROW_6_r23", [_LOAD_FAST_BORROW_7] = "_LOAD_FAST_BORROW_7", - [_LOAD_FAST_BORROW_LOAD_FAST_BORROW] = "_LOAD_FAST_BORROW_LOAD_FAST_BORROW", + [_LOAD_FAST_BORROW_7_r01] = "_LOAD_FAST_BORROW_7_r01", + [_LOAD_FAST_BORROW_7_r12] = "_LOAD_FAST_BORROW_7_r12", + [_LOAD_FAST_BORROW_7_r23] = "_LOAD_FAST_BORROW_7_r23", [_LOAD_FAST_CHECK] = "_LOAD_FAST_CHECK", - [_LOAD_FAST_LOAD_FAST] = "_LOAD_FAST_LOAD_FAST", + [_LOAD_FAST_CHECK_r01] = "_LOAD_FAST_CHECK_r01", + [_LOAD_FAST_CHECK_r12] = "_LOAD_FAST_CHECK_r12", + [_LOAD_FAST_CHECK_r23] = "_LOAD_FAST_CHECK_r23", [_LOAD_FROM_DICT_OR_DEREF] = "_LOAD_FROM_DICT_OR_DEREF", + [_LOAD_FROM_DICT_OR_DEREF_r11] = "_LOAD_FROM_DICT_OR_DEREF_r11", [_LOAD_GLOBAL] = "_LOAD_GLOBAL", + [_LOAD_GLOBAL_r00] = "_LOAD_GLOBAL_r00", [_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS", + [_LOAD_GLOBAL_BUILTINS_r01] = "_LOAD_GLOBAL_BUILTINS_r01", [_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE", + [_LOAD_GLOBAL_MODULE_r01] = "_LOAD_GLOBAL_MODULE_r01", [_LOAD_LOCALS] = "_LOAD_LOCALS", + [_LOAD_LOCALS_r01] = "_LOAD_LOCALS_r01", + [_LOAD_LOCALS_r12] = "_LOAD_LOCALS_r12", + [_LOAD_LOCALS_r23] = "_LOAD_LOCALS_r23", [_LOAD_NAME] = "_LOAD_NAME", + [_LOAD_NAME_r01] = "_LOAD_NAME_r01", [_LOAD_SMALL_INT] = "_LOAD_SMALL_INT", + [_LOAD_SMALL_INT_r01] = "_LOAD_SMALL_INT_r01", + [_LOAD_SMALL_INT_r12] = "_LOAD_SMALL_INT_r12", + [_LOAD_SMALL_INT_r23] = "_LOAD_SMALL_INT_r23", [_LOAD_SMALL_INT_0] = "_LOAD_SMALL_INT_0", + [_LOAD_SMALL_INT_0_r01] = "_LOAD_SMALL_INT_0_r01", + [_LOAD_SMALL_INT_0_r12] = "_LOAD_SMALL_INT_0_r12", + [_LOAD_SMALL_INT_0_r23] = "_LOAD_SMALL_INT_0_r23", [_LOAD_SMALL_INT_1] = "_LOAD_SMALL_INT_1", + [_LOAD_SMALL_INT_1_r01] = "_LOAD_SMALL_INT_1_r01", + [_LOAD_SMALL_INT_1_r12] = "_LOAD_SMALL_INT_1_r12", + [_LOAD_SMALL_INT_1_r23] = "_LOAD_SMALL_INT_1_r23", [_LOAD_SMALL_INT_2] = "_LOAD_SMALL_INT_2", + [_LOAD_SMALL_INT_2_r01] = "_LOAD_SMALL_INT_2_r01", + [_LOAD_SMALL_INT_2_r12] = "_LOAD_SMALL_INT_2_r12", + [_LOAD_SMALL_INT_2_r23] = "_LOAD_SMALL_INT_2_r23", [_LOAD_SMALL_INT_3] = "_LOAD_SMALL_INT_3", + [_LOAD_SMALL_INT_3_r01] = "_LOAD_SMALL_INT_3_r01", + [_LOAD_SMALL_INT_3_r12] = "_LOAD_SMALL_INT_3_r12", + [_LOAD_SMALL_INT_3_r23] = "_LOAD_SMALL_INT_3_r23", [_LOAD_SPECIAL] = "_LOAD_SPECIAL", + [_LOAD_SPECIAL_r00] = "_LOAD_SPECIAL_r00", [_LOAD_SUPER_ATTR_ATTR] = "_LOAD_SUPER_ATTR_ATTR", + [_LOAD_SUPER_ATTR_ATTR_r31] = "_LOAD_SUPER_ATTR_ATTR_r31", [_LOAD_SUPER_ATTR_METHOD] = "_LOAD_SUPER_ATTR_METHOD", + [_LOAD_SUPER_ATTR_METHOD_r32] = "_LOAD_SUPER_ATTR_METHOD_r32", [_MAKE_CALLARGS_A_TUPLE] = "_MAKE_CALLARGS_A_TUPLE", + [_MAKE_CALLARGS_A_TUPLE_r33] = "_MAKE_CALLARGS_A_TUPLE_r33", [_MAKE_CELL] = "_MAKE_CELL", + [_MAKE_CELL_r00] = "_MAKE_CELL_r00", [_MAKE_FUNCTION] = "_MAKE_FUNCTION", + [_MAKE_FUNCTION_r11] = "_MAKE_FUNCTION_r11", [_MAKE_WARM] = "_MAKE_WARM", + [_MAKE_WARM_r00] = "_MAKE_WARM_r00", + [_MAKE_WARM_r11] = "_MAKE_WARM_r11", + [_MAKE_WARM_r22] = "_MAKE_WARM_r22", + [_MAKE_WARM_r33] = "_MAKE_WARM_r33", [_MAP_ADD] = "_MAP_ADD", + [_MAP_ADD_r20] = "_MAP_ADD_r20", [_MATCH_CLASS] = "_MATCH_CLASS", + [_MATCH_CLASS_r31] = "_MATCH_CLASS_r31", [_MATCH_KEYS] = "_MATCH_KEYS", + [_MATCH_KEYS_r23] = "_MATCH_KEYS_r23", [_MATCH_MAPPING] = "_MATCH_MAPPING", + [_MATCH_MAPPING_r02] = "_MATCH_MAPPING_r02", + [_MATCH_MAPPING_r12] = "_MATCH_MAPPING_r12", + [_MATCH_MAPPING_r23] = "_MATCH_MAPPING_r23", [_MATCH_SEQUENCE] = "_MATCH_SEQUENCE", + [_MATCH_SEQUENCE_r02] = "_MATCH_SEQUENCE_r02", + [_MATCH_SEQUENCE_r12] = "_MATCH_SEQUENCE_r12", + [_MATCH_SEQUENCE_r23] = "_MATCH_SEQUENCE_r23", [_MAYBE_EXPAND_METHOD] = "_MAYBE_EXPAND_METHOD", + [_MAYBE_EXPAND_METHOD_r00] = "_MAYBE_EXPAND_METHOD_r00", [_MAYBE_EXPAND_METHOD_KW] = "_MAYBE_EXPAND_METHOD_KW", + [_MAYBE_EXPAND_METHOD_KW_r11] = "_MAYBE_EXPAND_METHOD_KW_r11", [_NOP] = "_NOP", + [_NOP_r00] = "_NOP_r00", + [_NOP_r11] = "_NOP_r11", + [_NOP_r22] = "_NOP_r22", + [_NOP_r33] = "_NOP_r33", [_POP_CALL] = "_POP_CALL", + [_POP_CALL_r20] = "_POP_CALL_r20", [_POP_CALL_LOAD_CONST_INLINE_BORROW] = "_POP_CALL_LOAD_CONST_INLINE_BORROW", + [_POP_CALL_LOAD_CONST_INLINE_BORROW_r21] = "_POP_CALL_LOAD_CONST_INLINE_BORROW_r21", [_POP_CALL_ONE] = "_POP_CALL_ONE", + [_POP_CALL_ONE_r30] = "_POP_CALL_ONE_r30", [_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW] = "_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW", + [_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31] = "_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31", [_POP_CALL_TWO] = "_POP_CALL_TWO", + [_POP_CALL_TWO_r30] = "_POP_CALL_TWO_r30", [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW] = "_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW", + [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31] = "_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31", [_POP_EXCEPT] = "_POP_EXCEPT", + [_POP_EXCEPT_r10] = "_POP_EXCEPT_r10", [_POP_ITER] = "_POP_ITER", + [_POP_ITER_r20] = "_POP_ITER_r20", [_POP_TOP] = "_POP_TOP", + [_POP_TOP_r10] = "_POP_TOP_r10", [_POP_TOP_FLOAT] = "_POP_TOP_FLOAT", + [_POP_TOP_FLOAT_r00] = "_POP_TOP_FLOAT_r00", + [_POP_TOP_FLOAT_r10] = "_POP_TOP_FLOAT_r10", + [_POP_TOP_FLOAT_r21] = "_POP_TOP_FLOAT_r21", + [_POP_TOP_FLOAT_r32] = "_POP_TOP_FLOAT_r32", [_POP_TOP_INT] = "_POP_TOP_INT", + [_POP_TOP_INT_r00] = "_POP_TOP_INT_r00", + [_POP_TOP_INT_r10] = "_POP_TOP_INT_r10", + [_POP_TOP_INT_r21] = "_POP_TOP_INT_r21", + [_POP_TOP_INT_r32] = "_POP_TOP_INT_r32", [_POP_TOP_LOAD_CONST_INLINE] = "_POP_TOP_LOAD_CONST_INLINE", + [_POP_TOP_LOAD_CONST_INLINE_r11] = "_POP_TOP_LOAD_CONST_INLINE_r11", [_POP_TOP_LOAD_CONST_INLINE_BORROW] = "_POP_TOP_LOAD_CONST_INLINE_BORROW", + [_POP_TOP_LOAD_CONST_INLINE_BORROW_r11] = "_POP_TOP_LOAD_CONST_INLINE_BORROW_r11", [_POP_TOP_NOP] = "_POP_TOP_NOP", + [_POP_TOP_NOP_r00] = "_POP_TOP_NOP_r00", + [_POP_TOP_NOP_r10] = "_POP_TOP_NOP_r10", + [_POP_TOP_NOP_r21] = "_POP_TOP_NOP_r21", + [_POP_TOP_NOP_r32] = "_POP_TOP_NOP_r32", [_POP_TOP_UNICODE] = "_POP_TOP_UNICODE", + [_POP_TOP_UNICODE_r00] = "_POP_TOP_UNICODE_r00", + [_POP_TOP_UNICODE_r10] = "_POP_TOP_UNICODE_r10", + [_POP_TOP_UNICODE_r21] = "_POP_TOP_UNICODE_r21", + [_POP_TOP_UNICODE_r32] = "_POP_TOP_UNICODE_r32", [_POP_TWO] = "_POP_TWO", + [_POP_TWO_r20] = "_POP_TWO_r20", [_POP_TWO_LOAD_CONST_INLINE_BORROW] = "_POP_TWO_LOAD_CONST_INLINE_BORROW", + [_POP_TWO_LOAD_CONST_INLINE_BORROW_r21] = "_POP_TWO_LOAD_CONST_INLINE_BORROW_r21", [_PUSH_EXC_INFO] = "_PUSH_EXC_INFO", + [_PUSH_EXC_INFO_r02] = "_PUSH_EXC_INFO_r02", + [_PUSH_EXC_INFO_r12] = "_PUSH_EXC_INFO_r12", + [_PUSH_EXC_INFO_r23] = "_PUSH_EXC_INFO_r23", [_PUSH_FRAME] = "_PUSH_FRAME", + [_PUSH_FRAME_r10] = "_PUSH_FRAME_r10", [_PUSH_NULL] = "_PUSH_NULL", + [_PUSH_NULL_r01] = "_PUSH_NULL_r01", + [_PUSH_NULL_r12] = "_PUSH_NULL_r12", + [_PUSH_NULL_r23] = "_PUSH_NULL_r23", [_PUSH_NULL_CONDITIONAL] = "_PUSH_NULL_CONDITIONAL", + [_PUSH_NULL_CONDITIONAL_r00] = "_PUSH_NULL_CONDITIONAL_r00", [_PY_FRAME_GENERAL] = "_PY_FRAME_GENERAL", + [_PY_FRAME_GENERAL_r01] = "_PY_FRAME_GENERAL_r01", [_PY_FRAME_KW] = "_PY_FRAME_KW", + [_PY_FRAME_KW_r11] = "_PY_FRAME_KW_r11", [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", + [_REPLACE_WITH_TRUE_r11] = "_REPLACE_WITH_TRUE_r11", [_RESUME_CHECK] = "_RESUME_CHECK", + [_RESUME_CHECK_r00] = "_RESUME_CHECK_r00", + [_RESUME_CHECK_r11] = "_RESUME_CHECK_r11", + [_RESUME_CHECK_r22] = "_RESUME_CHECK_r22", + [_RESUME_CHECK_r33] = "_RESUME_CHECK_r33", [_RETURN_GENERATOR] = "_RETURN_GENERATOR", + [_RETURN_GENERATOR_r01] = "_RETURN_GENERATOR_r01", [_RETURN_VALUE] = "_RETURN_VALUE", + [_RETURN_VALUE_r11] = "_RETURN_VALUE_r11", [_SAVE_RETURN_OFFSET] = "_SAVE_RETURN_OFFSET", + [_SAVE_RETURN_OFFSET_r00] = "_SAVE_RETURN_OFFSET_r00", + [_SAVE_RETURN_OFFSET_r11] = "_SAVE_RETURN_OFFSET_r11", + [_SAVE_RETURN_OFFSET_r22] = "_SAVE_RETURN_OFFSET_r22", + [_SAVE_RETURN_OFFSET_r33] = "_SAVE_RETURN_OFFSET_r33", [_SEND_GEN_FRAME] = "_SEND_GEN_FRAME", + [_SEND_GEN_FRAME_r22] = "_SEND_GEN_FRAME_r22", [_SETUP_ANNOTATIONS] = "_SETUP_ANNOTATIONS", + [_SETUP_ANNOTATIONS_r00] = "_SETUP_ANNOTATIONS_r00", [_SET_ADD] = "_SET_ADD", + [_SET_ADD_r10] = "_SET_ADD_r10", [_SET_FUNCTION_ATTRIBUTE] = "_SET_FUNCTION_ATTRIBUTE", + [_SET_FUNCTION_ATTRIBUTE_r01] = "_SET_FUNCTION_ATTRIBUTE_r01", + [_SET_FUNCTION_ATTRIBUTE_r11] = "_SET_FUNCTION_ATTRIBUTE_r11", + [_SET_FUNCTION_ATTRIBUTE_r21] = "_SET_FUNCTION_ATTRIBUTE_r21", + [_SET_FUNCTION_ATTRIBUTE_r32] = "_SET_FUNCTION_ATTRIBUTE_r32", [_SET_IP] = "_SET_IP", + [_SET_IP_r00] = "_SET_IP_r00", + [_SET_IP_r11] = "_SET_IP_r11", + [_SET_IP_r22] = "_SET_IP_r22", + [_SET_IP_r33] = "_SET_IP_r33", [_SET_UPDATE] = "_SET_UPDATE", + [_SET_UPDATE_r10] = "_SET_UPDATE_r10", + [_SPILL_OR_RELOAD] = "_SPILL_OR_RELOAD", + [_SPILL_OR_RELOAD_r01] = "_SPILL_OR_RELOAD_r01", + [_SPILL_OR_RELOAD_r02] = "_SPILL_OR_RELOAD_r02", + [_SPILL_OR_RELOAD_r03] = "_SPILL_OR_RELOAD_r03", + [_SPILL_OR_RELOAD_r10] = "_SPILL_OR_RELOAD_r10", + [_SPILL_OR_RELOAD_r12] = "_SPILL_OR_RELOAD_r12", + [_SPILL_OR_RELOAD_r13] = "_SPILL_OR_RELOAD_r13", + [_SPILL_OR_RELOAD_r20] = "_SPILL_OR_RELOAD_r20", + [_SPILL_OR_RELOAD_r21] = "_SPILL_OR_RELOAD_r21", + [_SPILL_OR_RELOAD_r23] = "_SPILL_OR_RELOAD_r23", + [_SPILL_OR_RELOAD_r30] = "_SPILL_OR_RELOAD_r30", + [_SPILL_OR_RELOAD_r31] = "_SPILL_OR_RELOAD_r31", + [_SPILL_OR_RELOAD_r32] = "_SPILL_OR_RELOAD_r32", [_START_EXECUTOR] = "_START_EXECUTOR", + [_START_EXECUTOR_r00] = "_START_EXECUTOR_r00", [_STORE_ATTR] = "_STORE_ATTR", + [_STORE_ATTR_r20] = "_STORE_ATTR_r20", [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE", + [_STORE_ATTR_INSTANCE_VALUE_r21] = "_STORE_ATTR_INSTANCE_VALUE_r21", [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", + [_STORE_ATTR_SLOT_r21] = "_STORE_ATTR_SLOT_r21", [_STORE_ATTR_WITH_HINT] = "_STORE_ATTR_WITH_HINT", + [_STORE_ATTR_WITH_HINT_r21] = "_STORE_ATTR_WITH_HINT_r21", [_STORE_DEREF] = "_STORE_DEREF", + [_STORE_DEREF_r10] = "_STORE_DEREF_r10", [_STORE_FAST] = "_STORE_FAST", + [_STORE_FAST_r10] = "_STORE_FAST_r10", [_STORE_FAST_0] = "_STORE_FAST_0", + [_STORE_FAST_0_r10] = "_STORE_FAST_0_r10", [_STORE_FAST_1] = "_STORE_FAST_1", + [_STORE_FAST_1_r10] = "_STORE_FAST_1_r10", [_STORE_FAST_2] = "_STORE_FAST_2", + [_STORE_FAST_2_r10] = "_STORE_FAST_2_r10", [_STORE_FAST_3] = "_STORE_FAST_3", + [_STORE_FAST_3_r10] = "_STORE_FAST_3_r10", [_STORE_FAST_4] = "_STORE_FAST_4", + [_STORE_FAST_4_r10] = "_STORE_FAST_4_r10", [_STORE_FAST_5] = "_STORE_FAST_5", + [_STORE_FAST_5_r10] = "_STORE_FAST_5_r10", [_STORE_FAST_6] = "_STORE_FAST_6", + [_STORE_FAST_6_r10] = "_STORE_FAST_6_r10", [_STORE_FAST_7] = "_STORE_FAST_7", - [_STORE_FAST_LOAD_FAST] = "_STORE_FAST_LOAD_FAST", - [_STORE_FAST_STORE_FAST] = "_STORE_FAST_STORE_FAST", + [_STORE_FAST_7_r10] = "_STORE_FAST_7_r10", [_STORE_GLOBAL] = "_STORE_GLOBAL", + [_STORE_GLOBAL_r10] = "_STORE_GLOBAL_r10", [_STORE_NAME] = "_STORE_NAME", + [_STORE_NAME_r10] = "_STORE_NAME_r10", [_STORE_SLICE] = "_STORE_SLICE", + [_STORE_SLICE_r30] = "_STORE_SLICE_r30", [_STORE_SUBSCR] = "_STORE_SUBSCR", + [_STORE_SUBSCR_r30] = "_STORE_SUBSCR_r30", [_STORE_SUBSCR_DICT] = "_STORE_SUBSCR_DICT", + [_STORE_SUBSCR_DICT_r31] = "_STORE_SUBSCR_DICT_r31", [_STORE_SUBSCR_LIST_INT] = "_STORE_SUBSCR_LIST_INT", + [_STORE_SUBSCR_LIST_INT_r32] = "_STORE_SUBSCR_LIST_INT_r32", [_SWAP] = "_SWAP", + [_SWAP_r11] = "_SWAP_r11", [_SWAP_2] = "_SWAP_2", + [_SWAP_2_r02] = "_SWAP_2_r02", + [_SWAP_2_r12] = "_SWAP_2_r12", + [_SWAP_2_r22] = "_SWAP_2_r22", + [_SWAP_2_r33] = "_SWAP_2_r33", [_SWAP_3] = "_SWAP_3", + [_SWAP_3_r03] = "_SWAP_3_r03", + [_SWAP_3_r13] = "_SWAP_3_r13", + [_SWAP_3_r23] = "_SWAP_3_r23", + [_SWAP_3_r33] = "_SWAP_3_r33", [_TIER2_RESUME_CHECK] = "_TIER2_RESUME_CHECK", + [_TIER2_RESUME_CHECK_r00] = "_TIER2_RESUME_CHECK_r00", + [_TIER2_RESUME_CHECK_r11] = "_TIER2_RESUME_CHECK_r11", + [_TIER2_RESUME_CHECK_r22] = "_TIER2_RESUME_CHECK_r22", + [_TIER2_RESUME_CHECK_r33] = "_TIER2_RESUME_CHECK_r33", [_TO_BOOL] = "_TO_BOOL", + [_TO_BOOL_r11] = "_TO_BOOL_r11", [_TO_BOOL_BOOL] = "_TO_BOOL_BOOL", + [_TO_BOOL_BOOL_r01] = "_TO_BOOL_BOOL_r01", + [_TO_BOOL_BOOL_r11] = "_TO_BOOL_BOOL_r11", + [_TO_BOOL_BOOL_r22] = "_TO_BOOL_BOOL_r22", + [_TO_BOOL_BOOL_r33] = "_TO_BOOL_BOOL_r33", [_TO_BOOL_INT] = "_TO_BOOL_INT", + [_TO_BOOL_INT_r11] = "_TO_BOOL_INT_r11", [_TO_BOOL_LIST] = "_TO_BOOL_LIST", + [_TO_BOOL_LIST_r11] = "_TO_BOOL_LIST_r11", [_TO_BOOL_NONE] = "_TO_BOOL_NONE", + [_TO_BOOL_NONE_r01] = "_TO_BOOL_NONE_r01", + [_TO_BOOL_NONE_r11] = "_TO_BOOL_NONE_r11", + [_TO_BOOL_NONE_r22] = "_TO_BOOL_NONE_r22", + [_TO_BOOL_NONE_r33] = "_TO_BOOL_NONE_r33", [_TO_BOOL_STR] = "_TO_BOOL_STR", + [_TO_BOOL_STR_r11] = "_TO_BOOL_STR_r11", [_UNARY_INVERT] = "_UNARY_INVERT", + [_UNARY_INVERT_r11] = "_UNARY_INVERT_r11", [_UNARY_NEGATIVE] = "_UNARY_NEGATIVE", + [_UNARY_NEGATIVE_r11] = "_UNARY_NEGATIVE_r11", [_UNARY_NOT] = "_UNARY_NOT", + [_UNARY_NOT_r01] = "_UNARY_NOT_r01", + [_UNARY_NOT_r11] = "_UNARY_NOT_r11", + [_UNARY_NOT_r22] = "_UNARY_NOT_r22", + [_UNARY_NOT_r33] = "_UNARY_NOT_r33", [_UNPACK_EX] = "_UNPACK_EX", + [_UNPACK_EX_r10] = "_UNPACK_EX_r10", [_UNPACK_SEQUENCE] = "_UNPACK_SEQUENCE", + [_UNPACK_SEQUENCE_r10] = "_UNPACK_SEQUENCE_r10", [_UNPACK_SEQUENCE_LIST] = "_UNPACK_SEQUENCE_LIST", + [_UNPACK_SEQUENCE_LIST_r10] = "_UNPACK_SEQUENCE_LIST_r10", [_UNPACK_SEQUENCE_TUPLE] = "_UNPACK_SEQUENCE_TUPLE", + [_UNPACK_SEQUENCE_TUPLE_r10] = "_UNPACK_SEQUENCE_TUPLE_r10", [_UNPACK_SEQUENCE_TWO_TUPLE] = "_UNPACK_SEQUENCE_TWO_TUPLE", + [_UNPACK_SEQUENCE_TWO_TUPLE_r12] = "_UNPACK_SEQUENCE_TWO_TUPLE_r12", [_WITH_EXCEPT_START] = "_WITH_EXCEPT_START", + [_WITH_EXCEPT_START_r33] = "_WITH_EXCEPT_START_r33", [_YIELD_VALUE] = "_YIELD_VALUE", + [_YIELD_VALUE_r11] = "_YIELD_VALUE_r11", }; int _PyUop_num_popped(int opcode, int oparg) { @@ -721,10 +4927,6 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _LOAD_FAST_AND_CLEAR: return 0; - case _LOAD_FAST_LOAD_FAST: - return 0; - case _LOAD_FAST_BORROW_LOAD_FAST_BORROW: - return 0; case _LOAD_CONST: return 0; case _LOAD_SMALL_INT_0: @@ -755,10 +4957,6 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _STORE_FAST: return 1; - case _STORE_FAST_LOAD_FAST: - return 1; - case _STORE_FAST_STORE_FAST: - return 2; case _POP_TOP: return 1; case _POP_TOP_NOP: @@ -833,12 +5031,6 @@ int _PyUop_num_popped(int opcode, int oparg) return 2; case _BINARY_OP_SUBTRACT_FLOAT: return 2; - case _BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS: - return 2; - case _BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS: - return 2; - case _BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS: - return 2; case _BINARY_OP_ADD_UNICODE: return 2; case _BINARY_OP_INPLACE_ADD_UNICODE: @@ -1263,6 +5455,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _EXIT_TRACE: return 0; + case _DYNAMIC_EXIT: + return 0; case _CHECK_VALIDITY: return 0; case _LOAD_CONST_INLINE: @@ -1291,8 +5485,6 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _LOAD_CONST_UNDER_INLINE_BORROW: return 1; - case _CHECK_FUNCTION: - return 0; case _START_EXECUTOR: return 0; case _MAKE_WARM: @@ -1305,10 +5497,22 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _ERROR_POP_N: return 0; + case _SPILL_OR_RELOAD: + return 0; case _TIER2_RESUME_CHECK: return 0; case _COLD_EXIT: return 0; + case _COLD_DYNAMIC_EXIT: + return 0; + case _GUARD_IP__PUSH_FRAME: + return 0; + case _GUARD_IP_YIELD_VALUE: + return 0; + case _GUARD_IP_RETURN_VALUE: + return 0; + case _GUARD_IP_RETURN_GENERATOR: + return 0; default: return -1; } diff --git a/Include/marshal.h b/Include/marshal.h index f773587bdd0..2ccb112b40c 100644 --- a/Include/marshal.h +++ b/Include/marshal.h @@ -1,31 +1,18 @@ - /* Interface for marshal.c */ #ifndef Py_MARSHAL_H #define Py_MARSHAL_H -#ifndef Py_LIMITED_API - #ifdef __cplusplus extern "C" { #endif -PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *, - Py_ssize_t); -PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); - -#define Py_MARSHAL_VERSION 5 - -PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *); -PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *); -PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *); -PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *); - -PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int); -PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int); +#ifndef Py_LIMITED_API +# define _Py_CPYTHON_MARSHAL_H +# include "cpython/marshal.h" +# undef _Py_CPYTHON_MARSHAL_H +#endif #ifdef __cplusplus } #endif - -#endif /* Py_LIMITED_API */ #endif /* !Py_MARSHAL_H */ diff --git a/Include/modsupport.h b/Include/modsupport.h index af995f567b0..cb47ad8cd27 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -56,58 +56,6 @@ PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def); #define Py_CLEANUP_SUPPORTED 0x20000 -#define PYTHON_API_VERSION 1013 -#define PYTHON_API_STRING "1013" -/* The API version is maintained (independently from the Python version) - so we can detect mismatches between the interpreter and dynamically - loaded modules. These are diagnosed by an error message but - the module is still loaded (because the mismatch can only be tested - after loading the module). The error message is intended to - explain the core dump a few seconds later. - - The symbol PYTHON_API_STRING defines the same value as a string - literal. *** PLEASE MAKE SURE THE DEFINITIONS MATCH. *** - - Please add a line or two to the top of this log for each API - version change: - - 22-Feb-2006 MvL 1013 PEP 353 - long indices for sequence lengths - - 19-Aug-2002 GvR 1012 Changes to string object struct for - interning changes, saving 3 bytes. - - 17-Jul-2001 GvR 1011 Descr-branch, just to be on the safe side - - 25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and - PyFrame_New(); Python 2.1a2 - - 14-Mar-2000 GvR 1009 Unicode API added - - 3-Jan-1999 GvR 1007 Decided to change back! (Don't reuse 1008!) - - 3-Dec-1998 GvR 1008 Python 1.5.2b1 - - 18-Jan-1997 GvR 1007 string interning and other speedups - - 11-Oct-1996 GvR renamed Py_Ellipses to Py_Ellipsis :-( - - 30-Jul-1996 GvR Slice and ellipses syntax added - - 23-Jul-1996 GvR For 1.4 -- better safe than sorry this time :-) - - 7-Nov-1995 GvR Keyword arguments (should've been done at 1.3 :-( ) - - 10-Jan-1995 GvR Renamed globals to new naming scheme - - 9-Jan-1995 GvR Initial version (incompatible with older API) -*/ - -/* The PYTHON_ABI_VERSION is introduced in PEP 384. For the lifetime of - Python 3, it will stay at the value of 3; changes to the limited API - must be performed in a strictly backwards-compatible manner. */ -#define PYTHON_ABI_VERSION 3 -#define PYTHON_ABI_STRING "3" - PyAPI_FUNC(PyObject *) PyModule_Create2(PyModuleDef*, int apiver); #ifdef Py_LIMITED_API @@ -134,6 +82,72 @@ PyAPI_FUNC(PyObject *) PyModule_FromDefAndSpec2(PyModuleDef *def, #endif /* New in 3.5 */ +/* ABI info & checking (new in 3.15) */ +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) +typedef struct PyABIInfo { + uint8_t abiinfo_major_version; + uint8_t abiinfo_minor_version; + uint16_t flags; + uint32_t build_version; + uint32_t abi_version; +} PyABIInfo; +#define PyABIInfo_STABLE 0x0001 +#define PyABIInfo_GIL 0x0002 +#define PyABIInfo_FREETHREADED 0x0004 +#define PyABIInfo_INTERNAL 0x0008 + +#define PyABIInfo_FREETHREADING_AGNOSTIC (PyABIInfo_GIL|PyABIInfo_FREETHREADED) + +PyAPI_FUNC(int) PyABIInfo_Check(PyABIInfo *info, const char *module_name); + +// Define the defaults +#ifdef Py_LIMITED_API + #define _PyABIInfo_DEFAULT_FLAG_STABLE PyABIInfo_STABLE + #if Py_LIMITED_API == 3 + #define PyABIInfo_DEFAULT_ABI_VERSION _Py_PACK_VERSION(3, 2) + #else + #define PyABIInfo_DEFAULT_ABI_VERSION Py_LIMITED_API + #endif +#else + #define _PyABIInfo_DEFAULT_FLAG_STABLE 0 + #define PyABIInfo_DEFAULT_ABI_VERSION PY_VERSION_HEX +#endif +#if defined(Py_LIMITED_API) && defined(_Py_OPAQUE_PYOBJECT) + #define _PyABIInfo_DEFAULT_FLAG_FT PyABIInfo_FREETHREADING_AGNOSTIC +#elif defined(Py_GIL_DISABLED) + #define _PyABIInfo_DEFAULT_FLAG_FT PyABIInfo_FREETHREADED +#else + #define _PyABIInfo_DEFAULT_FLAG_FT PyABIInfo_GIL +#endif +#if defined(Py_BUILD_CORE) + #define _PyABIInfo_DEFAULT_FLAG_INTERNAL PyABIInfo_INTERNAL +#else + #define _PyABIInfo_DEFAULT_FLAG_INTERNAL 0 +#endif + +#define PyABIInfo_DEFAULT_FLAGS ( \ + _PyABIInfo_DEFAULT_FLAG_STABLE \ + | _PyABIInfo_DEFAULT_FLAG_FT \ + | _PyABIInfo_DEFAULT_FLAG_INTERNAL \ + ) \ + ///////////////////////////////////////////////////////// + +#define _PyABIInfo_DEFAULT { \ + 1, 0, \ + PyABIInfo_DEFAULT_FLAGS, \ + PY_VERSION_HEX, \ + PyABIInfo_DEFAULT_ABI_VERSION } \ + ///////////////////////////////////////////////////////// + +#define PyABIInfo_VAR(NAME) \ + static PyABIInfo NAME = _PyABIInfo_DEFAULT; + +#undef _PyABIInfo_DEFAULT_STABLE +#undef _PyABIInfo_DEFAULT_FT +#undef _PyABIInfo_DEFAULT_INTERNAL + +#endif /* ABI info (new in 3.15) */ + #ifndef Py_LIMITED_API # define Py_CPYTHON_MODSUPPORT_H # include "cpython/modsupport.h" diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 17634a93f8f..e83bc395aa4 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -81,10 +81,21 @@ struct PyModuleDef_Slot { #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 # define Py_mod_gil 4 #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) +# define Py_mod_abi 5 +# define Py_mod_name 6 +# define Py_mod_doc 7 +# define Py_mod_state_size 8 +# define Py_mod_methods 9 +# define Py_mod_state_traverse 10 +# define Py_mod_state_clear 11 +# define Py_mod_state_free 12 +# define Py_mod_token 13 +#endif #ifndef Py_LIMITED_API -#define _Py_mod_LAST_SLOT 4 +#define _Py_mod_LAST_SLOT 13 #endif #endif /* New in 3.5 */ @@ -106,6 +117,13 @@ struct PyModuleDef_Slot { PyAPI_FUNC(int) PyUnstable_Module_SetGIL(PyObject *module, void *gil); #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) +PyAPI_FUNC(PyObject *) PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *, + PyObject *spec); +PyAPI_FUNC(int) PyModule_Exec(PyObject *mod); +PyAPI_FUNC(int) PyModule_GetStateSize(PyObject *mod, Py_ssize_t *result); +PyAPI_FUNC(int) PyModule_GetToken(PyObject *, void **result); +#endif #ifndef _Py_OPAQUE_PYOBJECT struct PyModuleDef { diff --git a/Include/monitoring.h b/Include/monitoring.h deleted file mode 100644 index 985f7f230e4..00000000000 --- a/Include/monitoring.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef Py_MONITORING_H -#define Py_MONITORING_H -#ifdef __cplusplus -extern "C" { -#endif - -// There is currently no limited API for monitoring - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_MONITORING_H -# include "cpython/monitoring.h" -# undef Py_CPYTHON_MONITORING_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MONITORING_H */ diff --git a/Include/object.h b/Include/object.h index 064904b733d..ad452be8405 100644 --- a/Include/object.h +++ b/Include/object.h @@ -71,6 +71,8 @@ whose size is determined when the object is allocated. * * Statically allocated objects might be shared between * interpreters, so must be marked as immortal. + * + * Before changing this, see the check in PyModuleDef_Init(). */ #if defined(Py_GIL_DISABLED) #define PyObject_HEAD_INIT(type) \ @@ -138,12 +140,12 @@ struct _object { # endif }; #else - Py_ssize_t ob_refcnt; + Py_ssize_t ob_refcnt; // part of stable ABI; do not change #endif _Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, char) _aligner; }; - PyTypeObject *ob_type; + PyTypeObject *ob_type; // part of stable ABI; do not change }; #else // Objects that are not owned by any thread use a thread id (tid) of zero. @@ -171,7 +173,7 @@ struct _object { #ifndef _Py_OPAQUE_PYOBJECT struct PyVarObject { PyObject ob_base; - Py_ssize_t ob_size; /* Number of items in variable part */ + Py_ssize_t ob_size; // Number of items in variable part. Part of stable ABI }; #endif typedef struct PyVarObject PyVarObject; @@ -263,56 +265,72 @@ _Py_IsOwnedByCurrentThread(PyObject *ob) } #endif -// Py_TYPE() implementation for the stable ABI -PyAPI_FUNC(PyTypeObject*) Py_TYPE(PyObject *ob); - -#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030e0000 - // Stable ABI implements Py_TYPE() as a function call - // on limited C API version 3.14 and newer. -#else - static inline PyTypeObject* _Py_TYPE(PyObject *ob) - { - return ob->ob_type; - } - #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 - # define Py_TYPE(ob) _Py_TYPE(_PyObject_CAST(ob)) - #else - # define Py_TYPE(ob) _Py_TYPE(ob) - #endif -#endif - PyAPI_DATA(PyTypeObject) PyLong_Type; PyAPI_DATA(PyTypeObject) PyBool_Type; +/* Definitions for the stable ABI */ +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 14) +PyAPI_FUNC(PyTypeObject*) Py_TYPE(PyObject *ob); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) +PyAPI_FUNC(Py_ssize_t) Py_SIZE(PyObject *ob); +PyAPI_FUNC(int) Py_IS_TYPE(PyObject *ob, PyTypeObject *type); +PyAPI_FUNC(void) Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size); +#endif + #ifndef _Py_OPAQUE_PYOBJECT + +static inline void +Py_SET_TYPE(PyObject *ob, PyTypeObject *type) +{ + ob->ob_type = type; +} + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < _Py_PACK_VERSION(3, 11) +// Non-limited API & limited API 3.11 & below: use static inline functions and +// use _PyObject_CAST so that users don't need their own casts +# define Py_TYPE(ob) _Py_TYPE_impl(_PyObject_CAST(ob)) +# define Py_SIZE(ob) _Py_SIZE_impl(_PyObject_CAST(ob)) +# define Py_IS_TYPE(ob, type) _Py_IS_TYPE_impl(_PyObject_CAST(ob), (type)) +# define Py_SET_SIZE(ob, size) _Py_SET_SIZE_impl(_PyVarObject_CAST(ob), (size)) +# define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) +#elif Py_LIMITED_API+0 < _Py_PACK_VERSION(3, 15) +// Limited API 3.11-3.14: use static inline functions, without casts +# define Py_SIZE(ob) _Py_SIZE_impl(ob) +# define Py_IS_TYPE(ob, type) _Py_IS_TYPE_impl((ob), (type)) +# define Py_SET_SIZE(ob, size) _Py_SET_SIZE_impl((ob), (size)) +# if Py_LIMITED_API+0 < _Py_PACK_VERSION(3, 14) +// Py_TYPE() is static inline only on Limited API 3.13 and below +# define Py_TYPE(ob) _Py_TYPE_impl(ob) +# endif +#else +// Limited API 3.15+: use function calls +#endif + +static inline +PyTypeObject* _Py_TYPE_impl(PyObject *ob) +{ + return ob->ob_type; +} + // bpo-39573: The Py_SET_SIZE() function must be used to set an object size. -static inline Py_ssize_t Py_SIZE(PyObject *ob) { +static inline Py_ssize_t +_Py_SIZE_impl(PyObject *ob) +{ assert(Py_TYPE(ob) != &PyLong_Type); assert(Py_TYPE(ob) != &PyBool_Type); return _PyVarObject_CAST(ob)->ob_size; } -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 -# define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob)) -#endif -#endif // !defined(_Py_OPAQUE_PYOBJECT) -static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { +static inline int +_Py_IS_TYPE_impl(PyObject *ob, PyTypeObject *type) +{ return Py_TYPE(ob) == type; } -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 -# define Py_IS_TYPE(ob, type) Py_IS_TYPE(_PyObject_CAST(ob), (type)) -#endif - -#ifndef _Py_OPAQUE_PYOBJECT -static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { - ob->ob_type = type; -} -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 -# define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) -#endif - -static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { +static inline void +_Py_SET_SIZE_impl(PyVarObject *ob, Py_ssize_t size) +{ assert(Py_TYPE(_PyObject_CAST(ob)) != &PyLong_Type); assert(Py_TYPE(_PyObject_CAST(ob)) != &PyBool_Type); #ifdef Py_GIL_DISABLED @@ -321,9 +339,7 @@ static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { ob->ob_size = size; #endif } -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 -# define Py_SET_SIZE(ob, size) Py_SET_SIZE(_PyVarObject_CAST(ob), (size)) -#endif + #endif // !defined(_Py_OPAQUE_PYOBJECT) @@ -527,7 +543,7 @@ given type object has a specified feature. #define Py_TPFLAGS_INLINE_VALUES (1 << 2) /* Placement of weakref pointers are managed by the VM, not by the type. - * The VM will automatically set tp_weaklistoffset. + * The VM will automatically set tp_weaklistoffset. Implies Py_TPFLAGS_HAVE_GC. */ #define Py_TPFLAGS_MANAGED_WEAKREF (1 << 3) @@ -634,6 +650,7 @@ given type object has a specified feature. // Flag values for ob_flags (16 bits available, if SIZEOF_VOID_P > 4). #define _Py_IMMORTAL_FLAGS (1 << 0) +#define _Py_LEGACY_ABI_CHECK_FLAG (1 << 1) /* see PyModuleDef_Init() */ #define _Py_STATICALLY_ALLOCATED_FLAG (1 << 2) #if defined(Py_GIL_DISABLED) && defined(Py_DEBUG) #define _Py_TYPE_REVEALED_FLAG (1 << 3) @@ -692,8 +709,13 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ # define Py_NotImplemented (&_Py_NotImplementedStruct) #endif -/* Macro for returning Py_NotImplemented from a function */ -#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented +/* Macro for returning Py_NotImplemented from a function. Only treat + * Py_NotImplemented as immortal in the limited C API 3.12 and newer. */ +#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030c0000 +# define Py_RETURN_NOTIMPLEMENTED return Py_NewRef(Py_NotImplemented) +#else +# define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented +#endif /* Rich comparison opcodes */ #define Py_LT 0 @@ -831,6 +853,11 @@ PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *); PyAPI_FUNC(int) PyType_Freeze(PyTypeObject *type); #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) +PyAPI_FUNC(PyObject *) PyType_GetModuleByToken(PyTypeObject *type, + const void *token); +#endif + #ifdef __cplusplus } #endif diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 1d5c74adefc..0d066c16901 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -213,28 +213,29 @@ extern "C" { #define UNPACK_SEQUENCE_LIST 207 #define UNPACK_SEQUENCE_TUPLE 208 #define UNPACK_SEQUENCE_TWO_TUPLE 209 -#define INSTRUMENTED_END_FOR 234 -#define INSTRUMENTED_POP_ITER 235 -#define INSTRUMENTED_END_SEND 236 -#define INSTRUMENTED_FOR_ITER 237 -#define INSTRUMENTED_INSTRUCTION 238 -#define INSTRUMENTED_JUMP_FORWARD 239 -#define INSTRUMENTED_NOT_TAKEN 240 -#define INSTRUMENTED_POP_JUMP_IF_TRUE 241 -#define INSTRUMENTED_POP_JUMP_IF_FALSE 242 -#define INSTRUMENTED_POP_JUMP_IF_NONE 243 -#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 244 -#define INSTRUMENTED_RESUME 245 -#define INSTRUMENTED_RETURN_VALUE 246 -#define INSTRUMENTED_YIELD_VALUE 247 -#define INSTRUMENTED_END_ASYNC_FOR 248 -#define INSTRUMENTED_LOAD_SUPER_ATTR 249 -#define INSTRUMENTED_CALL 250 -#define INSTRUMENTED_CALL_KW 251 -#define INSTRUMENTED_CALL_FUNCTION_EX 252 -#define INSTRUMENTED_JUMP_BACKWARD 253 -#define INSTRUMENTED_LINE 254 -#define ENTER_EXECUTOR 255 +#define INSTRUMENTED_END_FOR 233 +#define INSTRUMENTED_POP_ITER 234 +#define INSTRUMENTED_END_SEND 235 +#define INSTRUMENTED_FOR_ITER 236 +#define INSTRUMENTED_INSTRUCTION 237 +#define INSTRUMENTED_JUMP_FORWARD 238 +#define INSTRUMENTED_NOT_TAKEN 239 +#define INSTRUMENTED_POP_JUMP_IF_TRUE 240 +#define INSTRUMENTED_POP_JUMP_IF_FALSE 241 +#define INSTRUMENTED_POP_JUMP_IF_NONE 242 +#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 243 +#define INSTRUMENTED_RESUME 244 +#define INSTRUMENTED_RETURN_VALUE 245 +#define INSTRUMENTED_YIELD_VALUE 246 +#define INSTRUMENTED_END_ASYNC_FOR 247 +#define INSTRUMENTED_LOAD_SUPER_ATTR 248 +#define INSTRUMENTED_CALL 249 +#define INSTRUMENTED_CALL_KW 250 +#define INSTRUMENTED_CALL_FUNCTION_EX 251 +#define INSTRUMENTED_JUMP_BACKWARD 252 +#define INSTRUMENTED_LINE 253 +#define ENTER_EXECUTOR 254 +#define TRACE_RECORD 255 #define ANNOTATIONS_PLACEHOLDER 256 #define JUMP 257 #define JUMP_IF_FALSE 258 @@ -249,7 +250,7 @@ extern "C" { #define HAVE_ARGUMENT 43 #define MIN_SPECIALIZED_OPCODE 129 -#define MIN_INSTRUMENTED_OPCODE 234 +#define MIN_INSTRUMENTED_OPCODE 233 #ifdef __cplusplus } diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 532873b51e6..90a73c8f2b1 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -6,6 +6,9 @@ configure.ac must also be changed. There is also (independent) API version information in modsupport.h. + + This header should self-contained; PC/python_ver_rc.h includes it + without the rest of Python.h. */ /* Values for PY_RELEASE_LEVEL */ @@ -21,10 +24,10 @@ #define PY_MINOR_VERSION 15 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.15.0a0" +#define PY_VERSION "3.15.0a3+" /*--end constants--*/ @@ -46,4 +49,16 @@ // Public Py_PACK_VERSION is declared in pymacro.h; it needs . + +/* The API and ABI versions are left for backwards compatibility. + They've not been updated since 2006 and 2010, respectively. + API/ABI versioning is now tied to the CPython version. + The *_VERSION and *_STRING symbols should define the same value; as + number and string literal respectively. Make sure the definitions match. +*/ +#define PYTHON_API_VERSION 1013 +#define PYTHON_API_STRING "1013" +#define PYTHON_ABI_VERSION 3 +#define PYTHON_ABI_STRING "3" + #endif //_Py_PATCHLEVEL_H diff --git a/Include/pyexpat.h b/Include/pyexpat.h index 9824d099c3d..f523f8bb273 100644 --- a/Include/pyexpat.h +++ b/Include/pyexpat.h @@ -52,6 +52,16 @@ struct PyExpat_CAPI int (*SetHashSalt)(XML_Parser parser, unsigned long hash_salt); /* might be NULL for expat < 2.6.0 */ XML_Bool (*SetReparseDeferralEnabled)(XML_Parser parser, XML_Bool enabled); + /* might be NULL for expat < 2.7.2 */ + XML_Bool (*SetAllocTrackerActivationThreshold)( + XML_Parser parser, unsigned long long activationThresholdBytes); + XML_Bool (*SetAllocTrackerMaximumAmplification)( + XML_Parser parser, float maxAmplificationFactor); + /* might be NULL for expat < 2.4.0 */ + XML_Bool (*SetBillionLaughsAttackProtectionActivationThreshold)( + XML_Parser parser, unsigned long long activationThresholdBytes); + XML_Bool (*SetBillionLaughsAttackProtectionMaximumAmplification)( + XML_Parser parser, float maxAmplificationFactor); /* always add new stuff to the end! */ }; diff --git a/Include/pylock.h b/Include/pylock.h deleted file mode 100644 index 1939ef269d3..00000000000 --- a/Include/pylock.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef Py_LOCK_H -#define Py_LOCK_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -# define Py_CPYTHON_LOCK_H -# include "cpython/pylock.h" -# undef Py_CPYTHON_LOCK_H -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LOCK_H */ diff --git a/Include/pymacro.h b/Include/pymacro.h index 857cdf12db9..7ecce44a0d2 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -116,6 +116,12 @@ /* Absolute value of the number x */ #define Py_ABS(x) ((x) < 0 ? -(x) : (x)) +/* Safer implementation that avoids an undefined behavior for the minimal + value of the signed integer type if its absolute value is larger than + the maximal value of the signed integer type (in the two's complement + representations, which is common). + */ +#define _Py_ABS_CAST(T, x) ((x) >= 0 ? ((T) (x)) : ((T) (((T) -((x) + 1)) + 1u))) #define _Py_XSTRINGIFY(x) #x diff --git a/Include/pymath.h b/Include/pymath.h index 0ead1f95670..7cfe441365d 100644 --- a/Include/pymath.h +++ b/Include/pymath.h @@ -7,6 +7,7 @@ /* High precision definition of pi and e (Euler) * The values are taken from libc6's math.h. */ +// Deprecated since Python 3.15. #ifndef Py_MATH_PIl #define Py_MATH_PIl 3.1415926535897932384626433832795029L #endif @@ -14,6 +15,7 @@ #define Py_MATH_PI 3.14159265358979323846 #endif +// Deprecated since Python 3.15. #ifndef Py_MATH_El #define Py_MATH_El 2.7182818284590452353602874713526625L #endif @@ -43,13 +45,14 @@ #define Py_IS_FINITE(X) isfinite(X) // Py_INFINITY: Value that evaluates to a positive double infinity. +// Soft deprecated since Python 3.15, use INFINITY instead. #ifndef Py_INFINITY # define Py_INFINITY ((double)INFINITY) #endif /* Py_HUGE_VAL should always be the same as Py_INFINITY. But historically * this was not reliable and Python did not require IEEE floats and C99 - * conformity. The macro was soft deprecated in Python 3.14, use Py_INFINITY instead. + * conformity. The macro was soft deprecated in Python 3.14, use INFINITY instead. */ #ifndef Py_HUGE_VAL # define Py_HUGE_VAL HUGE_VAL @@ -57,9 +60,24 @@ /* Py_NAN: Value that evaluates to a quiet Not-a-Number (NaN). The sign is * undefined and normally not relevant, but e.g. fixed for float("nan"). + * + * Note: On Solaris, NAN is a function address, hence arithmetic is impossible. + * For that reason, we instead use the built-in call if available or fallback + * to a generic NaN computed from strtod() as a last resort. + * + * See https://github.com/python/cpython/issues/136006 for details. */ #if !defined(Py_NAN) -# define Py_NAN ((double)NAN) +# if defined(__sun) +# if _Py__has_builtin(__builtin_nanf) +# define Py_NAN ((double)__builtin_nanf("")) +# else +# include +# define Py_NAN (strtod("NAN", NULL)) +# endif +# else +# define Py_NAN ((double)NAN) +# endif #endif #endif /* Py_PYMATH_H */ diff --git a/Include/pyport.h b/Include/pyport.h index 62db8d07701..61e2317976e 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -504,28 +504,30 @@ extern "C" { * Thread support is stubbed and any attempt to create a new thread fails. */ #if (!defined(HAVE_PTHREAD_STUBS) && \ + !defined(__wasi__) && \ (!defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__))) # define Py_CAN_START_THREADS 1 #endif + +/* gh-142163: Some libraries rely on HAVE_THREAD_LOCAL being undefined, so + * we can only define it only when Py_BUILD_CORE is set.*/ +#ifdef Py_BUILD_CORE +// This is no longer coupled to _Py_thread_local. +# define HAVE_THREAD_LOCAL 1 +#endif + #ifdef WITH_THREAD -# ifdef Py_BUILD_CORE -# ifdef HAVE_THREAD_LOCAL -# error "HAVE_THREAD_LOCAL is already defined" -# endif -# define HAVE_THREAD_LOCAL 1 -# ifdef thread_local -# define _Py_thread_local thread_local -# elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) -# define _Py_thread_local _Thread_local -# elif defined(_MSC_VER) /* AKA NT_THREADS */ -# define _Py_thread_local __declspec(thread) -# elif defined(__GNUC__) /* includes clang */ -# define _Py_thread_local __thread -# else - // fall back to the PyThread_tss_*() API, or ignore. -# undef HAVE_THREAD_LOCAL -# endif +# ifdef thread_local +# define _Py_thread_local thread_local +# elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) +# define _Py_thread_local _Thread_local +# elif defined(_MSC_VER) /* AKA NT_THREADS */ +# define _Py_thread_local __declspec(thread) +# elif defined(__GNUC__) /* includes clang */ +# define _Py_thread_local __thread +# else +# error "no supported thread-local variable storage classifier" # endif #endif @@ -682,4 +684,10 @@ extern "C" { #endif +// Assume the stack grows down unless specified otherwise +#ifndef _Py_STACK_GROWS_DOWN +# define _Py_STACK_GROWS_DOWN 1 +#endif + + #endif /* Py_PYPORT_H */ diff --git a/Include/refcount.h b/Include/refcount.h index ba34461fefc..51346c7e519 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -114,6 +114,8 @@ PyAPI_FUNC(Py_ssize_t) Py_REFCNT(PyObject *ob); } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 # define Py_REFCNT(ob) _Py_REFCNT(_PyObject_CAST(ob)) + #else + # define Py_REFCNT(ob) _Py_REFCNT(ob) #endif #endif diff --git a/Include/sliceobject.h b/Include/sliceobject.h index 35e2ea254ca..00c70a6e911 100644 --- a/Include/sliceobject.h +++ b/Include/sliceobject.h @@ -16,19 +16,6 @@ PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */ /* Slice object interface */ -/* - -A slice object containing start, stop, and step data members (the -names are from range). After much talk with Guido, it was decided to -let these be any arbitrary python type. Py_None stands for omitted values. -*/ -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - PyObject *start, *stop, *step; /* not NULL */ -} PySliceObject; -#endif - PyAPI_DATA(PyTypeObject) PySlice_Type; PyAPI_DATA(PyTypeObject) PyEllipsis_Type; @@ -36,12 +23,6 @@ PyAPI_DATA(PyTypeObject) PyEllipsis_Type; PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop, PyObject* step); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop); -PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, - PyObject **start_ptr, PyObject **stop_ptr, - PyObject **step_ptr); -#endif PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); Py_DEPRECATED(3.7) @@ -63,6 +44,12 @@ PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length, Py_ssize_t step); #endif +#ifndef Py_LIMITED_API +# define Py_CPYTHON_SLICEOBJECT_H +# include "cpython/sliceobject.h" +# undef Py_CPYTHON_SLICEOBJECT_H +#endif + #ifdef __cplusplus } #endif diff --git a/Include/structseq.h b/Include/structseq.h index 29e24fee54e..e52d6188030 100644 --- a/Include/structseq.h +++ b/Include/structseq.h @@ -21,12 +21,6 @@ typedef struct PyStructSequence_Desc { PyAPI_DATA(const char * const) PyStructSequence_UnnamedField; -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, - PyStructSequence_Desc *desc); -PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, - PyStructSequence_Desc *desc); -#endif PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); @@ -35,9 +29,9 @@ PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); #ifndef Py_LIMITED_API -typedef PyTupleObject PyStructSequence; -#define PyStructSequence_SET_ITEM PyStructSequence_SetItem -#define PyStructSequence_GET_ITEM PyStructSequence_GetItem +# define Py_CPYTHON_STRUCTSEQ_H +# include "cpython/structseq.h" +# undef Py_CPYTHON_STRUCTSEQ_H #endif #ifdef __cplusplus diff --git a/Include/sysmodule.h b/Include/sysmodule.h index 2f362791797..b7d800c5e5d 100644 --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -23,8 +23,6 @@ PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) PyAPI_FUNC(void) PySys_FormatStdout(const char *format, ...); PyAPI_FUNC(void) PySys_FormatStderr(const char *format, ...); -Py_DEPRECATED(3.13) PyAPI_FUNC(void) PySys_ResetWarnOptions(void); - PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); #ifdef __cplusplus diff --git a/Include/weakrefobject.h b/Include/weakrefobject.h index a6e71eb178b..17fac62961c 100644 --- a/Include/weakrefobject.h +++ b/Include/weakrefobject.h @@ -27,7 +27,6 @@ PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, PyObject *callback); PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, PyObject *callback); -Py_DEPRECATED(3.13) PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000 PyAPI_FUNC(int) PyWeakref_GetRef(PyObject *ref, PyObject **pobj); diff --git a/InternalDocs/README.md b/InternalDocs/README.md index a6e2df5ae4a..3e8ab442315 100644 --- a/InternalDocs/README.md +++ b/InternalDocs/README.md @@ -11,6 +11,11 @@ it is not, please report that through the [issue tracker](https://github.com/python/cpython/issues). +General Resources +--- + +- [Source Code Structure](structure.md) + Compiling Python Source Code --- @@ -29,13 +34,13 @@ Runtime Objects - [Frames](frames.md) -- [String Interning](string_interning.md) - Program Execution --- - [The Bytecode Interpreter](interpreter.md) +- [Stack references (_PyStackRef)](stackrefs.md) + - [The JIT](jit.md) - [Garbage Collector Design](garbage_collector.md) @@ -46,6 +51,14 @@ Program Execution - [Stack protection](stack_protection.md) +Built-in Types +--- + +- [String Interning](string_interning.md) + +- [List sort algorithm](../Objects/listsort.txt) + + Modules --- diff --git a/InternalDocs/asyncio.md b/InternalDocs/asyncio.md index 22159852ca5..ca7e8a92dec 100644 --- a/InternalDocs/asyncio.md +++ b/InternalDocs/asyncio.md @@ -205,7 +205,7 @@ the current task is found and returned. If no matching thread state is found, `None` is returned. In free-threading, it avoids contention on a global dictionary as -threads can access the current task of thier running loop without any +threads can access the current task of their running loop without any locking. --- diff --git a/InternalDocs/compiler.md b/InternalDocs/compiler.md index 02bbdf6071f..742af5efcf5 100644 --- a/InternalDocs/compiler.md +++ b/InternalDocs/compiler.md @@ -604,4 +604,4 @@ References pp. 213--227, 1997. [^2]: The Zephyr Abstract Syntax Description Language.: - https://www.cs.princeton.edu/research/techreps/TR-554-97 + https://www.cs.princeton.edu/research/techreps/254 diff --git a/InternalDocs/frames.md b/InternalDocs/frames.md index 804d7436018..60ab2055afa 100644 --- a/InternalDocs/frames.md +++ b/InternalDocs/frames.md @@ -111,6 +111,55 @@ The shim frame points to a special code object containing the `INTERPRETER_EXIT` instruction which cleans up the shim frame and returns. +### Base frame + +Each thread state contains an embedded `_PyInterpreterFrame` called the "base frame" +that serves as a sentinel at the bottom of the frame stack. This frame is allocated +in `_PyThreadStateImpl` (the internal extension of `PyThreadState`) and initialized +when the thread state is created. The `owner` field is set to `FRAME_OWNED_BY_INTERPRETER`. + +External profilers and sampling tools can validate that they have successfully unwound +the complete call stack by checking that the frame chain terminates at the base frame. +The `PyThreadState.base_frame` pointer provides the expected address to compare against. +If a stack walk doesn't reach this frame, the sample is incomplete (possibly due to a +race condition) and should be discarded. + +The base frame is embedded in `_PyThreadStateImpl` rather than `PyThreadState` because +`_PyInterpreterFrame` is defined in internal headers that cannot be exposed in the +public API. A pointer (`PyThreadState.base_frame`) is provided for profilers to access +the address without needing internal headers. + +See the initialization in `new_threadstate()` in [Python/pystate.c](../Python/pystate.c). + +#### How profilers should use the base frame + +External profilers should read `tstate->base_frame` before walking the stack, then +walk from `tstate->current_frame` following `frame->previous` pointers until reaching +a frame with `owner == FRAME_OWNED_BY_INTERPRETER`. After the walk, verify that the +last frame address matches `base_frame`. If not, discard the sample as incomplete +since the frame chain may have been in an inconsistent state due to concurrent updates. + + +### Remote Profiling Frame Cache + +The `last_profiled_frame` field in `PyThreadState` supports an optimization for +remote profilers that sample call stacks from external processes. When a remote +profiler reads the call stack, it writes the current frame address to this field. +The eval loop then keeps this pointer valid by updating it to the parent frame +whenever a frame returns (in `_PyEval_FrameClearAndPop`). + +This creates a "high-water mark" that always points to a frame still on the stack. +On subsequent samples, the profiler can walk from `current_frame` until it reaches +`last_profiled_frame`, knowing that frames from that point downward are unchanged +and can be retrieved from a cache. This significantly reduces the amount of remote +memory reads needed when call stacks are deep and stable at their base. + +The update in `_PyEval_FrameClearAndPop` is guarded: it only writes when +`last_profiled_frame` is non-NULL AND matches the frame being popped. This +prevents transient frames (called and returned between profiler samples) from +corrupting the cache pointer, while avoiding any overhead when profiling is inactive. + + ### The Instruction Pointer `_PyInterpreterFrame` has two fields which are used to maintain the instruction diff --git a/InternalDocs/generators.md b/InternalDocs/generators.md index 979a5b51521..fa652cd231c 100644 --- a/InternalDocs/generators.md +++ b/InternalDocs/generators.md @@ -64,7 +64,7 @@ Iteration The [`FOR_ITER`](https://docs.python.org/dev/library/dis.html#opcode-FOR_ITER) instruction calls `__next__` on the iterator which is on the top of the stack, -and pushes the result to the stack. It has [`specializations`](adaptive.md) +and pushes the result to the stack. It has [`specializations`](interpreter.md) for a few common iterator types, including `FOR_ITER_GEN`, for iterating over a generator. `FOR_ITER_GEN` bypasses the call to `__next__`, and instead directly pushes the generator stack and resumes its execution from the diff --git a/InternalDocs/interpreter.md b/InternalDocs/interpreter.md index 38e9f6fced6..75acdf596a7 100644 --- a/InternalDocs/interpreter.md +++ b/InternalDocs/interpreter.md @@ -226,10 +226,11 @@ Up through 3.10, the call stack was implemented as a singly-linked list of heap allocation for the stack frame. Since 3.11, frames are no longer fully-fledged objects. Instead, a leaner internal -`_PyInterpreterFrame` structure is used, which is allocated using a custom allocator -function (`_PyThreadState_BumpFramePointer()`), which allocates and initializes a -frame structure. Usually a frame allocation is just a pointer bump, which improves -memory locality. +`_PyInterpreterFrame` structure is used. Most frames are allocated contiguously in a +per-thread stack (see `_PyThreadState_PushFrame` in [Python/pystate.c](../Python/pystate.c)), +which improves memory locality and reduces overhead. +If the current `datastack_chunk` has enough space (`_PyThreadState_HasStackSpace`) +then the lightweight `_PyFrame_PushUnchecked` can be used instead of `_PyThreadState_PushFrame`. Sometimes an actual `PyFrameObject` is needed, such as when Python code calls `sys._getframe()` or an extension module calls diff --git a/InternalDocs/jit.md b/InternalDocs/jit.md index c98ccb3ace8..1740b22b85f 100644 --- a/InternalDocs/jit.md +++ b/InternalDocs/jit.md @@ -53,7 +53,7 @@ and an instance of `_PyUOpExecutor_Type` is created to contain it. ## The JIT interpreter After a `JUMP_BACKWARD` instruction invokes the uop optimizer to create a uop -executor, it transfers control to this executor via the `GOTO_TIER_TWO` macro. +executor, it transfers control to this executor via the `TIER1_TO_TIER2` macro. CPython implements two executors. Here we describe the JIT interpreter, which is the simpler of them and is therefore useful for debugging and analyzing @@ -89,7 +89,7 @@ When the full jit is enabled (python was configured with [`--enable-experimental-jit`](https://docs.python.org/dev/using/configure.html#cmdoption-enable-experimental-jit), the uop executor's `jit_code` field is populated with a pointer to a compiled C function that implements the executor logic. This function's signature is -defined by `jit_func` in [`pycore_jit.h`](Include/internal/pycore_jit.h). +defined by `jit_func` in [`pycore_jit.h`](../Include/internal/pycore_jit.h). When the executor is invoked by `ENTER_EXECUTOR`, instead of jumping to the uop interpreter at `tier2_dispatch`, the executor runs the function that `jit_code` points to. This function returns the instruction pointer diff --git a/InternalDocs/stack_protection.md b/InternalDocs/stack_protection.md index 5e35b2d8195..14802e57d09 100644 --- a/InternalDocs/stack_protection.md +++ b/InternalDocs/stack_protection.md @@ -4,7 +4,7 @@ CPython protects against stack overflow in the form of runaway, or just very dee Protection against pure Python stack recursion has existed since very early, but in 3.12 we added protection against stack overflow in C code. This was initially implemented using a counter and later improved in 3.14 to use the actual stack depth. For those platforms that support it (Windows, Mac, and most Linuxes) we query the operating system to find the stack bounds. -For other platforms we use conserative estimates. +For other platforms we use conservative estimates. The C stack looks like this: @@ -38,12 +38,19 @@ Recursion checks are performed by `_Py_EnterRecursiveCall()` or `_Py_EnterRecurs ```python kb_used = (stack_top - stack_pointer)>>10 -if stack_pointer < hard_limit: +if stack_pointer < bottom_of_machine_stack: + pass # Our stack limits could be wrong so it is safest to do nothing. +elif stack_pointer < hard_limit: FatalError(f"Unrecoverable stack overflow (used {kb_used} kB)") elif stack_pointer < soft_limit: raise RecursionError(f"Stack overflow (used {kb_used} kB)") ``` +### User space threads and other oddities + +Some libraries provide user-space threads. These will change the C stack at runtime. +To guard against this we only raise if the stack pointer is in the window between the expected stack base and the soft limit. + ### Diagnosing and fixing stack overflows For stack protection to work correctly the amount of stack consumed between calls to `_Py_EnterRecursiveCall()` must be less than `_PyOS_STACK_MARGIN_BYTES`. diff --git a/InternalDocs/stackrefs.md b/InternalDocs/stackrefs.md new file mode 100644 index 00000000000..5774be9c56d --- /dev/null +++ b/InternalDocs/stackrefs.md @@ -0,0 +1,79 @@ +# Stack references (`_PyStackRef`) + +Stack references are the interpreter's tagged representation of values on the evaluation stack. +They carry metadata to track ownership and support optimizations such as tagged small ints. + +## Shape and tagging + +- A `_PyStackRef` is a tagged pointer-sized value (see `Include/internal/pycore_stackref.h`). +- Tag bits distinguish three cases: + - `Py_TAG_REFCNT` unset - reference count lives on the pointed-to object. + - `Py_TAG_REFCNT` set - ownership is "borrowed" (no refcount to drop on close) or the object is immortal. + - `Py_INT_TAG` set - tagged small integer stored directly in the stackref (no heap allocation). +- Special constants: `PyStackRef_NULL`, `PyStackRef_ERROR`, and embedded `None`/`True`/`False`. + +In GIL builds, most objects carry their refcount; tagged borrowed refs skip decref on close. In free +threading builds, the tag is also used to mark deferred refcounted objects so the GC can see them and +to avoid refcount contention on commonly shared objects. + +## Converting to and from PyObject* + +Three conversions control ownership: + +- `PyStackRef_FromPyObjectNew(obj)` - create a new reference (INCREF if mortal). +- `PyStackRef_FromPyObjectSteal(obj)` - take over ownership without changing the count unless the + object is immortal. +- `PyStackRef_FromPyObjectBorrow(obj)` - create a borrowed stackref (never decref on close). + +The `obj` argument must not be `NULL`. + +Going back to `PyObject*` mirrors this: + +- `PyStackRef_AsPyObjectBorrow(ref)` - borrow the underlying pointer +- `PyStackRef_AsPyObjectSteal(ref)` - transfer ownership from the stackref; if ref is borrowed or + deferred, this creates a new owning `PyObject*` reference. +- `PyStackRef_AsPyObjectNew(ref)` - create a new owning reference + +Only `PyStackRef_AsPyObjectBorrow` allows ref to be `PyStackRef_NULL`. + +## Operations on stackrefs + +The interpreter treats `_PyStackRef` as the unit of stack storage. Ownership must be managed with +the stackref primitives: + +- `PyStackRef_DUP` - like `Py_NewRef` for stackrefs; preserves the original. +- `PyStackRef_Borrow` - create a borrowed stackref from another stackref. +- `PyStackRef_CLOSE` / `PyStackRef_XCLOSE` - like `Py_DECREF`; invalidates the stackref. +- `PyStackRef_CLEAR` - like `Py_CLEAR`; closes and sets the stackref to `PyStackRef_NULL` +- `PyStackRef_MakeHeapSafe` - converts borrowed reference to owning reference + +Borrow tracking (for debug builds with `Py_STACKREF_DEBUG`) records who you borrowed from and reports +double-close, leaked borrows, or use-after-close via fatal errors. + +## Borrow-friendly opcodes + +The interpreter can push borrowed references directly. For example, `LOAD_FAST_BORROW` loads a local +variable as a borrowed `_PyStackRef`, avoiding both INCREF and DECREF for the temporary lifetime on +the evaluation stack. + +## Tagged integers on the stack + +Small ints can be stored inline with `Py_INT_TAG`, so no heap object is involved. Helpers like +`PyStackRef_TagInt`, `PyStackRef_UntagInt`, and `PyStackRef_IncrementTaggedIntNoOverflow` operate on +these values. Type checks use `PyStackRef_IsTaggedInt` and `PyStackRef_LongCheck`. + +## Free threading considerations + +Objects that support deferred reference counting can be pushed to the evaluation +stack and stored in local variables without directly incrementing the reference +count because they are only freed during cyclic garbage collection. This avoids +reference count contention on commonly shared objects such as methods and types. The GC +scans each thread's locals and evaluation stack to keep objects that use +deferred reference counting alive. + +## Debugging support + +`Py_STACKREF_DEBUG` builds replace the inline tags with table-backed IDs so the runtime can track +creation sites, borrows, closes, and leaks. Enabling `Py_STACKREF_CLOSE_DEBUG` additionally records +double closes. The tables live on `PyInterpreterState` and are initialized in `pystate.c`; helper +routines reside in `Python/stackrefs.c`. diff --git a/InternalDocs/structure.md b/InternalDocs/structure.md new file mode 100644 index 00000000000..75c8476aa0a --- /dev/null +++ b/InternalDocs/structure.md @@ -0,0 +1,40 @@ +# CPython source code + +This section gives an overview of CPython's code structure and provides +a summary of file locations for modules and built-ins. + + +## Source code layout + +For a Python module, the typical layout is: + +* `Lib/.py` +* `Modules/_.c` (if there's also a C accelerator module) +* `Lib/test/test_.py` +* `Doc/library/.rst` + +For an extension module, the typical layout is: + +* `Modules/module.c` +* `Lib/test/test_.py` +* `Doc/library/.rst` + +For builtin types, the typical layout is: + +* `Objects/object.c` +* `Lib/test/test_.py` +* [`Doc/library/stdtypes.rst`](../Doc/library/stdtypes.rst) + +For builtin functions, the typical layout is: + +* [`Python/bltinmodule.c`](../Python/bltinmodule.c) +* [`Lib/test/test_builtin.py`](../Lib/test/test_builtin.py) +* [`Doc/library/functions.rst`](../Doc/library/functions.rst) + +Some exceptions to these layouts are: + +* built-in type `int` is at [`Objects/longobject.c`](../Objects/longobject.c) +* built-in type `str` is at [`Objects/unicodeobject.c`](../Objects/unicodeobject.c) +* built-in module `sys` is at [`Python/sysmodule.c`](../Python/sysmodule.c) +* built-in module `marshal` is at [`Python/marshal.c`](../Python/marshal.c) +* Windows-only module `winreg` is at [`PC/winreg.c`](../PC/winreg.c) diff --git a/Lib/_android_support.py b/Lib/_android_support.py index ae506f6a4b5..a439d03a144 100644 --- a/Lib/_android_support.py +++ b/Lib/_android_support.py @@ -29,15 +29,19 @@ def init_streams(android_log_write, stdout_prio, stderr_prio): global logcat logcat = Logcat(android_log_write) - - sys.stdout = TextLogStream( - stdout_prio, "python.stdout", sys.stdout.fileno()) - sys.stderr = TextLogStream( - stderr_prio, "python.stderr", sys.stderr.fileno()) + sys.stdout = TextLogStream(stdout_prio, "python.stdout", sys.stdout) + sys.stderr = TextLogStream(stderr_prio, "python.stderr", sys.stderr) class TextLogStream(io.TextIOWrapper): - def __init__(self, prio, tag, fileno=None, **kwargs): + def __init__(self, prio, tag, original=None, **kwargs): + # Respect the -u option. + if original: + kwargs.setdefault("write_through", original.write_through) + fileno = original.fileno() + else: + fileno = None + # The default is surrogateescape for stdout and backslashreplace for # stderr, but in the context of an Android log, readability is more # important than reversibility. diff --git a/Lib/_ast_unparse.py b/Lib/_ast_unparse.py index 16cf56f62cc..1c8741b5a55 100644 --- a/Lib/_ast_unparse.py +++ b/Lib/_ast_unparse.py @@ -658,9 +658,9 @@ class Unparser(NodeVisitor): unparser.set_precedence(_Precedence.TEST.next(), inner) return unparser.visit(inner) - def _write_interpolation(self, node, is_interpolation=False): + def _write_interpolation(self, node, use_str_attr=False): with self.delimit("{", "}"): - if is_interpolation: + if use_str_attr: expr = node.str else: expr = self._unparse_interpolation_value(node.value) @@ -678,7 +678,8 @@ class Unparser(NodeVisitor): self._write_interpolation(node) def visit_Interpolation(self, node): - self._write_interpolation(node, is_interpolation=True) + # If `str` is set to `None`, use the `value` to generate the source code. + self._write_interpolation(node, use_str_attr=node.str is not None) def visit_Name(self, node): self.write(node.id) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 51263d696a1..60b471317ce 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -1061,6 +1061,41 @@ Sequence.register(bytes) Sequence.register(range) Sequence.register(memoryview) +class _DeprecateByteStringMeta(ABCMeta): + def __new__(cls, name, bases, namespace, **kwargs): + if name != "ByteString": + import warnings + + warnings._deprecated( + "collections.abc.ByteString", + remove=(3, 17), + ) + return super().__new__(cls, name, bases, namespace, **kwargs) + + def __instancecheck__(cls, instance): + import warnings + + warnings._deprecated( + "collections.abc.ByteString", + remove=(3, 17), + ) + return super().__instancecheck__(instance) + +class ByteString(Sequence, metaclass=_DeprecateByteStringMeta): + """Deprecated ABC serving as a common supertype of ``bytes`` and ``bytearray``. + + This ABC is scheduled for removal in Python 3.17. + Use ``isinstance(obj, collections.abc.Buffer)`` to test if ``obj`` + implements the buffer protocol at runtime. For use in type annotations, + either use ``Buffer`` or a union that explicitly specifies the types your + code supports (e.g., ``bytes | bytearray | memoryview``). + """ + + __slots__ = () + +ByteString.register(bytes) +ByteString.register(bytearray) + class MutableSequence(Sequence): """All the operations on a read-write sequence. @@ -1130,3 +1165,13 @@ class MutableSequence(Sequence): MutableSequence.register(list) MutableSequence.register(bytearray) + +_deprecated_ByteString = globals().pop("ByteString") + +def __getattr__(attr): + if attr == "ByteString": + import warnings + warnings._deprecated("collections.abc.ByteString", remove=(3, 17)) + globals()["ByteString"] = _deprecated_ByteString + return _deprecated_ByteString + raise AttributeError(f"module 'collections.abc' has no attribute {attr!r}") diff --git a/Lib/_colorize.py b/Lib/_colorize.py index 325efed274a..0b7047620b4 100644 --- a/Lib/_colorize.py +++ b/Lib/_colorize.py @@ -1,4 +1,3 @@ -import io import os import sys @@ -155,7 +154,7 @@ class ThemeSection(Mapping[str, str]): return iter(self.__dataclass_fields__) -@dataclass(frozen=True) +@dataclass(frozen=True, kw_only=True) class Argparse(ThemeSection): usage: str = ANSIColors.BOLD_BLUE prog: str = ANSIColors.BOLD_MAGENTA @@ -169,7 +168,12 @@ class Argparse(ThemeSection): short_option: str = ANSIColors.BOLD_GREEN label: str = ANSIColors.BOLD_YELLOW action: str = ANSIColors.BOLD_GREEN + default: str = ANSIColors.GREY + interpolated_value: str = ANSIColors.YELLOW reset: str = ANSIColors.RESET + error: str = ANSIColors.BOLD_MAGENTA + warning: str = ANSIColors.BOLD_YELLOW + message: str = ANSIColors.MAGENTA @dataclass(frozen=True, kw_only=True) @@ -187,6 +191,7 @@ class Difflib(ThemeSection): class Syntax(ThemeSection): prompt: str = ANSIColors.BOLD_MAGENTA keyword: str = ANSIColors.BOLD_BLUE + keyword_constant: str = ANSIColors.BOLD_BLUE builtin: str = ANSIColors.CYAN comment: str = ANSIColors.RED string: str = ANSIColors.GREEN @@ -287,21 +292,29 @@ def decolor(text: str) -> str: def can_colorize(*, file: IO[str] | IO[bytes] | None = None) -> bool: + + def _safe_getenv(k: str, fallback: str | None = None) -> str | None: + """Exception-safe environment retrieval. See gh-128636.""" + try: + return os.environ.get(k, fallback) + except Exception: + return fallback + if file is None: file = sys.stdout if not sys.flags.ignore_environment: - if os.environ.get("PYTHON_COLORS") == "0": + if _safe_getenv("PYTHON_COLORS") == "0": return False - if os.environ.get("PYTHON_COLORS") == "1": + if _safe_getenv("PYTHON_COLORS") == "1": return True - if os.environ.get("NO_COLOR"): + if _safe_getenv("NO_COLOR"): return False if not COLORIZE: return False - if os.environ.get("FORCE_COLOR"): + if _safe_getenv("FORCE_COLOR"): return True - if os.environ.get("TERM") == "dumb": + if _safe_getenv("TERM") == "dumb": return False if not hasattr(file, "fileno"): @@ -318,7 +331,7 @@ def can_colorize(*, file: IO[str] | IO[bytes] | None = None) -> bool: try: return os.isatty(file.fileno()) - except io.UnsupportedOperation: + except OSError: return hasattr(file, "isatty") and file.isatty() @@ -344,7 +357,8 @@ def get_theme( environment (including environment variable state and console configuration on Windows) can also change in the course of the application life cycle. """ - if force_color or (not force_no_color and can_colorize(file=tty_file)): + if force_color or (not force_no_color and + can_colorize(file=tty_file)): return _theme return theme_no_color diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index f168d169a32..e681cb17e43 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -208,8 +208,9 @@ opmap = { 'CACHE': 0, 'RESERVED': 17, 'RESUME': 128, - 'INSTRUMENTED_LINE': 254, - 'ENTER_EXECUTOR': 255, + 'INSTRUMENTED_LINE': 253, + 'ENTER_EXECUTOR': 254, + 'TRACE_RECORD': 255, 'BINARY_SLICE': 1, 'BUILD_TEMPLATE': 2, 'CALL_FUNCTION_EX': 4, @@ -328,26 +329,26 @@ opmap = { 'UNPACK_EX': 118, 'UNPACK_SEQUENCE': 119, 'YIELD_VALUE': 120, - 'INSTRUMENTED_END_FOR': 234, - 'INSTRUMENTED_POP_ITER': 235, - 'INSTRUMENTED_END_SEND': 236, - 'INSTRUMENTED_FOR_ITER': 237, - 'INSTRUMENTED_INSTRUCTION': 238, - 'INSTRUMENTED_JUMP_FORWARD': 239, - 'INSTRUMENTED_NOT_TAKEN': 240, - 'INSTRUMENTED_POP_JUMP_IF_TRUE': 241, - 'INSTRUMENTED_POP_JUMP_IF_FALSE': 242, - 'INSTRUMENTED_POP_JUMP_IF_NONE': 243, - 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 244, - 'INSTRUMENTED_RESUME': 245, - 'INSTRUMENTED_RETURN_VALUE': 246, - 'INSTRUMENTED_YIELD_VALUE': 247, - 'INSTRUMENTED_END_ASYNC_FOR': 248, - 'INSTRUMENTED_LOAD_SUPER_ATTR': 249, - 'INSTRUMENTED_CALL': 250, - 'INSTRUMENTED_CALL_KW': 251, - 'INSTRUMENTED_CALL_FUNCTION_EX': 252, - 'INSTRUMENTED_JUMP_BACKWARD': 253, + 'INSTRUMENTED_END_FOR': 233, + 'INSTRUMENTED_POP_ITER': 234, + 'INSTRUMENTED_END_SEND': 235, + 'INSTRUMENTED_FOR_ITER': 236, + 'INSTRUMENTED_INSTRUCTION': 237, + 'INSTRUMENTED_JUMP_FORWARD': 238, + 'INSTRUMENTED_NOT_TAKEN': 239, + 'INSTRUMENTED_POP_JUMP_IF_TRUE': 240, + 'INSTRUMENTED_POP_JUMP_IF_FALSE': 241, + 'INSTRUMENTED_POP_JUMP_IF_NONE': 242, + 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 243, + 'INSTRUMENTED_RESUME': 244, + 'INSTRUMENTED_RETURN_VALUE': 245, + 'INSTRUMENTED_YIELD_VALUE': 246, + 'INSTRUMENTED_END_ASYNC_FOR': 247, + 'INSTRUMENTED_LOAD_SUPER_ATTR': 248, + 'INSTRUMENTED_CALL': 249, + 'INSTRUMENTED_CALL_KW': 250, + 'INSTRUMENTED_CALL_FUNCTION_EX': 251, + 'INSTRUMENTED_JUMP_BACKWARD': 252, 'ANNOTATIONS_PLACEHOLDER': 256, 'JUMP': 257, 'JUMP_IF_FALSE': 258, @@ -362,4 +363,4 @@ opmap = { } HAVE_ARGUMENT = 43 -MIN_INSTRUMENTED_OPCODE = 234 +MIN_INSTRUMENTED_OPCODE = 233 diff --git a/Lib/_py_warnings.py b/Lib/_py_warnings.py index 5070caea6bb..d5a9cec86f3 100644 --- a/Lib/_py_warnings.py +++ b/Lib/_py_warnings.py @@ -369,9 +369,15 @@ def _setoption(arg): if message or module: import re if message: - message = re.escape(message) + if len(message) >= 2 and message[0] == message[-1] == '/': + message = message[1:-1] + else: + message = re.escape(message) if module: - module = re.escape(module) + r'\z' + if len(module) >= 2 and module[0] == module[-1] == '/': + module = module[1:-1] + else: + module = re.escape(module) + r'\z' if lineno: try: lineno = int(lineno) @@ -381,7 +387,23 @@ def _setoption(arg): raise _wm._OptionError("invalid lineno %r" % (lineno,)) from None else: lineno = 0 - _wm.filterwarnings(action, message, category, module, lineno) + try: + _wm.filterwarnings(action, message, category, module, lineno) + except re.PatternError if message or module else (): + if message: + try: + re.compile(message) + except re.PatternError: + raise _wm._OptionError(f"invalid regular expression for " + f"message: {message!r}") from None + if module: + try: + re.compile(module) + except re.PatternError: + raise _wm._OptionError(f"invalid regular expression for " + f"module: {module!r}") from None + # Should never happen. + raise # Helper for _setoption() @@ -498,14 +520,43 @@ def warn(message, category=None, stacklevel=1, source=None, ) +def _match_filename(pattern, filename, *, MS_WINDOWS=(sys.platform == 'win32')): + if not filename: + return pattern.match('') is not None + if filename[0] == '<' and filename[-1] == '>': + return pattern.match(filename) is not None + + is_py = (filename[-3:].lower() == '.py' + if MS_WINDOWS else + filename.endswith('.py')) + if is_py: + filename = filename[:-3] + if pattern.match(filename): # for backward compatibility + return True + if MS_WINDOWS: + if not is_py and filename[-4:].lower() == '.pyw': + filename = filename[:-4] + is_py = True + if is_py and filename[-9:].lower() in (r'\__init__', '/__init__'): + filename = filename[:-9] + filename = filename.replace('\\', '/') + else: + if is_py and filename.endswith('/__init__'): + filename = filename[:-9] + filename = filename.replace('/', '.') + i = 0 + while True: + if pattern.match(filename, i): + return True + i = filename.find('.', i) + 1 + if not i: + return False + + def warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None): lineno = int(lineno) - if module is None: - module = filename or "" - if module[-3:].lower() == ".py": - module = module[:-3] # XXX What about leading pathname? if isinstance(message, Warning): text = str(message) category = message.__class__ @@ -527,9 +578,11 @@ def warn_explicit(message, category, filename, lineno, action, msg, cat, mod, ln = item if ((msg is None or msg.match(text)) and issubclass(category, cat) and - (mod is None or mod.match(module)) and - (ln == 0 or lineno == ln)): - break + (ln == 0 or lineno == ln) and + (mod is None or (_match_filename(mod, filename) + if module is None else + mod.match(module)))): + break else: action = _wm.defaultaction # Early exit actions @@ -592,6 +645,9 @@ class WarningMessage(object): "line : %r}" % (self.message, self._category_name, self.filename, self.lineno, self.line)) + def __repr__(self): + return f'<{type(self).__qualname__} {self}>' + class catch_warnings(object): @@ -765,27 +821,27 @@ class deprecated: arg.__new__ = staticmethod(__new__) - original_init_subclass = arg.__init_subclass__ - # We need slightly different behavior if __init_subclass__ - # is a bound method (likely if it was implemented in Python) - if isinstance(original_init_subclass, MethodType): - original_init_subclass = original_init_subclass.__func__ + if "__init_subclass__" in arg.__dict__: + # __init_subclass__ is directly present on the decorated class. + # Synthesize a wrapper that calls this method directly. + original_init_subclass = arg.__init_subclass__ + # We need slightly different behavior if __init_subclass__ + # is a bound method (likely if it was implemented in Python). + # Otherwise, it likely means it's a builtin such as + # object's implementation of __init_subclass__. + if isinstance(original_init_subclass, MethodType): + original_init_subclass = original_init_subclass.__func__ @functools.wraps(original_init_subclass) def __init_subclass__(*args, **kwargs): _wm.warn(msg, category=category, stacklevel=stacklevel + 1) return original_init_subclass(*args, **kwargs) - - arg.__init_subclass__ = classmethod(__init_subclass__) - # Or otherwise, which likely means it's a builtin such as - # object's implementation of __init_subclass__. else: - @functools.wraps(original_init_subclass) - def __init_subclass__(*args, **kwargs): + def __init_subclass__(cls, *args, **kwargs): _wm.warn(msg, category=category, stacklevel=stacklevel + 1) - return original_init_subclass(*args, **kwargs) + return super(arg, cls).__init_subclass__(*args, **kwargs) - arg.__init_subclass__ = __init_subclass__ + arg.__init_subclass__ = classmethod(__init_subclass__) arg.__deprecated__ = __new__.__deprecated__ = msg __init_subclass__.__deprecated__ = msg diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index ab1b1722b7c..b6d68f23728 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1072,7 +1072,11 @@ class date: @classmethod def strptime(cls, date_string, format): - """Parse string according to the given date format (like time.strptime()).""" + """Parse string according to the given date format (like time.strptime()). + + For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes + """ import _strptime return _strptime._strptime_datetime_date(cls, date_string, format) @@ -1109,6 +1113,8 @@ class date: Format using strftime(). Example: "%d/%m/%Y, %H:%M:%S" + For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes """ return _wrap_strftime(self, format, self.timetuple()) @@ -1456,8 +1462,13 @@ class time: return self @classmethod + def strptime(cls, date_string, format): - """Parse string according to the given time format (like time.strptime()).""" + """Parse string according to the given time format (like time.strptime()). + + For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes + """ import _strptime return _strptime._strptime_datetime_time(cls, date_string, format) @@ -1650,6 +1661,9 @@ class time: def strftime(self, format): """Format using strftime(). The date part of the timestamp passed to underlying strftime should not be used. + + For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes """ # The year must be >= 1000 else Python's strftime implementation # can raise a bogus exception. @@ -2198,7 +2212,11 @@ class datetime(date): @classmethod def strptime(cls, date_string, format): - """Parse string according to the given date and time format (like time.strptime()).""" + """Parse string according to the given time format (like time.strptime()). + + For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes + """ import _strptime return _strptime._strptime_datetime_datetime(cls, date_string, format) diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index 9b8e42a2342..ef889ea0cc8 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -47,13 +47,16 @@ __all__ = [ 'HAVE_THREADS', # C version: compile time choice that enables the coroutine local context - 'HAVE_CONTEXTVAR' + 'HAVE_CONTEXTVAR', + + # Highest version of the spec this module complies with + 'SPEC_VERSION', ] __xname__ = __name__ # sys.modules lookup (--without-threads) __name__ = 'decimal' # For pickling -__version__ = '1.70' # Highest version of the spec this complies with - # See http://speleotrove.com/decimal/ +SPEC_VERSION = '1.70' # Highest version of the spec this complies with + # See https://speleotrove.com/decimal/decarith.html __libmpdec_version__ = "2.4.2" # compatible libmpdec version import math as _math @@ -3340,7 +3343,10 @@ class Decimal(object): return opa, opb def logical_and(self, other, context=None): - """Applies an 'and' operation between self and other's digits.""" + """Applies an 'and' operation between self and other's digits. + + Both self and other must be logical numbers. + """ if context is None: context = getcontext() @@ -3357,14 +3363,20 @@ class Decimal(object): return _dec_from_triple(0, result.lstrip('0') or '0', 0) def logical_invert(self, context=None): - """Invert all its digits.""" + """Invert all its digits. + + The self must be logical number. + """ if context is None: context = getcontext() return self.logical_xor(_dec_from_triple(0,'1'*context.prec,0), context) def logical_or(self, other, context=None): - """Applies an 'or' operation between self and other's digits.""" + """Applies an 'or' operation between self and other's digits. + + Both self and other must be logical numbers. + """ if context is None: context = getcontext() @@ -3381,7 +3393,10 @@ class Decimal(object): return _dec_from_triple(0, result.lstrip('0') or '0', 0) def logical_xor(self, other, context=None): - """Applies an 'xor' operation between self and other's digits.""" + """Applies an 'xor' operation between self and other's digits. + + Both self and other must be logical numbers. + """ if context is None: context = getcontext() @@ -6387,3 +6402,11 @@ _PyHASH_NAN = sys.hash_info.nan # _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS _PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) del sys + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return SPEC_VERSION + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 5db8ce9244b..69a088df8fc 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -546,7 +546,7 @@ class IOBase(metaclass=abc.ABCMeta): res += b if res.endswith(b"\n"): break - return bytes(res) + return res.take_bytes() def __iter__(self): self._checkClosed() @@ -617,8 +617,10 @@ class RawIOBase(IOBase): n = self.readinto(b) if n is None: return None + if n < 0 or n > len(b): + raise ValueError(f"readinto returned {n} outside buffer size {len(b)}") del b[n:] - return bytes(b) + return b.take_bytes() def readall(self): """Read until EOF, using multiple read() call.""" @@ -626,7 +628,7 @@ class RawIOBase(IOBase): while data := self.read(DEFAULT_BUFFER_SIZE): res += data if res: - return bytes(res) + return res.take_bytes() else: # b'' or None return data @@ -1498,6 +1500,7 @@ class FileIO(RawIOBase): _writable = False _appending = False _seekable = None + _truncate = False _closefd = True def __init__(self, file, mode='r', closefd=True, opener=None): @@ -1553,6 +1556,7 @@ class FileIO(RawIOBase): flags = 0 elif 'w' in mode: self._writable = True + self._truncate = True flags = os.O_CREAT | os.O_TRUNC elif 'a' in mode: self._writable = True @@ -1734,7 +1738,7 @@ class FileIO(RawIOBase): assert len(result) - bytes_read >= 1, \ "os.readinto buffer size 0 will result in erroneous EOF / returns 0" result.resize(bytes_read) - return bytes(result) + return result.take_bytes() def readinto(self, buffer): """Same as RawIOBase.readinto().""" @@ -1877,7 +1881,10 @@ class FileIO(RawIOBase): return 'ab' elif self._readable: if self._writable: - return 'rb+' + if self._truncate: + return 'wb+' + else: + return 'rb+' else: return 'rb' else: diff --git a/Lib/_pyrepl/_module_completer.py b/Lib/_pyrepl/_module_completer.py index 1e9462a4215..cf59e007f4d 100644 --- a/Lib/_pyrepl/_module_completer.py +++ b/Lib/_pyrepl/_module_completer.py @@ -1,9 +1,12 @@ from __future__ import annotations +import importlib +import os import pkgutil import sys import token import tokenize +from importlib.machinery import FileFinder from io import StringIO from contextlib import contextmanager from dataclasses import dataclass @@ -16,6 +19,15 @@ if TYPE_CHECKING: from typing import Any, Iterable, Iterator, Mapping +HARDCODED_SUBMODULES = { + # Standard library submodules that are not detected by pkgutil.iter_modules + # but can be imported, so should be proposed in completion + "collections": ["abc"], + "os": ["path"], + "xml.parsers.expat": ["errors", "model"], +} + + def make_default_module_completer() -> ModuleCompleter: # Inside pyrepl, __package__ is set to None by default return ModuleCompleter(namespace={'__package__': None}) @@ -41,6 +53,7 @@ class ModuleCompleter: self.namespace = namespace or {} self._global_cache: list[pkgutil.ModuleInfo] = [] self._curr_sys_path: list[str] = sys.path[:] + self._stdlib_path = os.path.dirname(importlib.__path__[0]) def get_completions(self, line: str) -> list[str] | None: """Return the next possible import completions for 'line'.""" @@ -95,12 +108,26 @@ class ModuleCompleter: return [] modules: Iterable[pkgutil.ModuleInfo] = self.global_cache + is_stdlib_import: bool | None = None for segment in path.split('.'): modules = [mod_info for mod_info in modules if mod_info.ispkg and mod_info.name == segment] + if is_stdlib_import is None: + # Top-level import decide if we import from stdlib or not + is_stdlib_import = all( + self._is_stdlib_module(mod_info) for mod_info in modules + ) modules = self.iter_submodules(modules) - return [module.name for module in modules - if self.is_suggestion_match(module.name, prefix)] + + module_names = [module.name for module in modules] + if is_stdlib_import: + module_names.extend(HARDCODED_SUBMODULES.get(path, ())) + return [module_name for module_name in module_names + if self.is_suggestion_match(module_name, prefix)] + + def _is_stdlib_module(self, module_info: pkgutil.ModuleInfo) -> bool: + return (isinstance(module_info.module_finder, FileFinder) + and module_info.module_finder.path == self._stdlib_path) def is_suggestion_match(self, module_name: str, prefix: str) -> bool: if prefix: diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py index 50c824995d8..10127e58897 100644 --- a/Lib/_pyrepl/commands.py +++ b/Lib/_pyrepl/commands.py @@ -420,14 +420,17 @@ class delete(EditCommand): def do(self) -> None: r = self.reader b = r.buffer - if ( - r.pos == 0 - and len(b) == 0 # this is something of a hack - and self.event[-1] == "\004" - ): - r.update_screen() - r.console.finish() - raise EOFError + if self.event[-1] == "\004": + if b and b[-1].endswith("\n"): + self.finish = True + elif ( + r.pos == 0 + and len(b) == 0 # this is something of a hack + ): + r.update_screen() + r.console.finish() + raise EOFError + for i in range(r.get_arg()): if r.pos != len(b): del b[r.pos] diff --git a/Lib/_pyrepl/fancy_termios.py b/Lib/_pyrepl/fancy_termios.py index 0468b9a2670..8d5bd183f21 100644 --- a/Lib/_pyrepl/fancy_termios.py +++ b/Lib/_pyrepl/fancy_termios.py @@ -20,19 +20,25 @@ import termios -class TermState: - def __init__(self, tuples): - ( - self.iflag, - self.oflag, - self.cflag, - self.lflag, - self.ispeed, - self.ospeed, - self.cc, - ) = tuples +TYPE_CHECKING = False - def as_list(self): +if TYPE_CHECKING: + from typing import cast +else: + cast = lambda typ, val: val + + +class TermState: + def __init__(self, attrs: list[int | list[bytes]]) -> None: + self.iflag = cast(int, attrs[0]) + self.oflag = cast(int, attrs[1]) + self.cflag = cast(int, attrs[2]) + self.lflag = cast(int, attrs[3]) + self.ispeed = cast(int, attrs[4]) + self.ospeed = cast(int, attrs[5]) + self.cc = cast(list[bytes], attrs[6]) + + def as_list(self) -> list[int | list[bytes]]: return [ self.iflag, self.oflag, @@ -45,32 +51,32 @@ class TermState: self.cc[:], ] - def copy(self): + def copy(self) -> "TermState": return self.__class__(self.as_list()) -def tcgetattr(fd): +def tcgetattr(fd: int) -> TermState: return TermState(termios.tcgetattr(fd)) -def tcsetattr(fd, when, attrs): +def tcsetattr(fd: int, when: int, attrs: TermState) -> None: termios.tcsetattr(fd, when, attrs.as_list()) class Term(TermState): TS__init__ = TermState.__init__ - def __init__(self, fd=0): + def __init__(self, fd: int = 0) -> None: self.TS__init__(termios.tcgetattr(fd)) self.fd = fd - self.stack = [] + self.stack: list[list[int | list[bytes]]] = [] - def save(self): + def save(self) -> None: self.stack.append(self.as_list()) - def set(self, when=termios.TCSANOW): + def set(self, when: int = termios.TCSANOW) -> None: termios.tcsetattr(self.fd, when, self.as_list()) - def restore(self): + def restore(self) -> None: self.TS__init__(self.stack.pop()) self.set() diff --git a/Lib/_pyrepl/simple_interact.py b/Lib/_pyrepl/simple_interact.py index ff1bdab9fea..3b0debf2ba0 100644 --- a/Lib/_pyrepl/simple_interact.py +++ b/Lib/_pyrepl/simple_interact.py @@ -31,7 +31,6 @@ import os import sys import code import warnings -import errno from .readline import _get_reader, multiline_input, append_history_file diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py index a7e49923191..09247de748e 100644 --- a/Lib/_pyrepl/unix_console.py +++ b/Lib/_pyrepl/unix_console.py @@ -35,7 +35,7 @@ from fcntl import ioctl from . import terminfo from .console import Console, Event -from .fancy_termios import tcgetattr, tcsetattr +from .fancy_termios import tcgetattr, tcsetattr, TermState from .trace import trace from .unix_eventqueue import EventQueue from .utils import wlen @@ -51,16 +51,19 @@ TYPE_CHECKING = False # types if TYPE_CHECKING: - from typing import IO, Literal, overload + from typing import AbstractSet, IO, Literal, overload, cast else: overload = lambda func: None + cast = lambda typ, val: val class InvalidTerminal(RuntimeError): - pass + def __init__(self, message: str) -> None: + super().__init__(errno.EIO, message) _error = (termios.error, InvalidTerminal) +_error_codes_to_ignore = frozenset([errno.EIO, errno.ENXIO, errno.EPERM]) SIGWINCH_EVENT = "repaint" @@ -125,12 +128,13 @@ except AttributeError: def register(self, fd, flag): self.fd = fd + # note: The 'timeout' argument is received as *milliseconds* def poll(self, timeout: float | None = None) -> list[int]: if timeout is None: r, w, e = select.select([self.fd], [], []) else: - r, w, e = select.select([self.fd], [], [], timeout/1000) + r, w, e = select.select([self.fd], [], [], timeout / 1000) return r poll = MinimalPoll # type: ignore[assignment] @@ -159,9 +163,20 @@ class UnixConsole(Console): self.pollob.register(self.input_fd, select.POLLIN) self.terminfo = terminfo.TermInfo(term or None) self.term = term + self.is_apple_terminal = ( + platform.system() == "Darwin" + and os.getenv("TERM_PROGRAM") == "Apple_Terminal" + ) + + try: + self.__input_fd_set(tcgetattr(self.input_fd), ignore=frozenset()) + except _error as e: + raise RuntimeError(f"termios failure ({e.args[1]})") @overload - def _my_getstr(cap: str, optional: Literal[False] = False) -> bytes: ... + def _my_getstr( + cap: str, optional: Literal[False] = False + ) -> bytes: ... @overload def _my_getstr(cap: str, optional: bool) -> bytes | None: ... @@ -201,7 +216,9 @@ class UnixConsole(Console): self.__setup_movement() - self.event_queue = EventQueue(self.input_fd, self.encoding, self.terminfo) + self.event_queue = EventQueue( + self.input_fd, self.encoding, self.terminfo + ) self.cursor_visible = 1 signal.signal(signal.SIGCONT, self._sigcont_handler) @@ -213,7 +230,6 @@ class UnixConsole(Console): def __read(self, n: int) -> bytes: return os.read(self.input_fd, n) - def change_encoding(self, encoding: str) -> None: """ Change the encoding used for I/O operations. @@ -325,6 +341,8 @@ class UnixConsole(Console): """ Prepare the console for input/output operations. """ + self.__buffer = [] + self.__svtermstate = tcgetattr(self.input_fd) raw = self.__svtermstate.copy() raw.iflag &= ~(termios.INPCK | termios.ISTRIP | termios.IXON) @@ -336,17 +354,15 @@ class UnixConsole(Console): raw.lflag |= termios.ISIG raw.cc[termios.VMIN] = 1 raw.cc[termios.VTIME] = 0 - tcsetattr(self.input_fd, termios.TCSADRAIN, raw) + self.__input_fd_set(raw) # In macOS terminal we need to deactivate line wrap via ANSI escape code - if platform.system() == "Darwin" and os.getenv("TERM_PROGRAM") == "Apple_Terminal": + if self.is_apple_terminal: os.write(self.output_fd, b"\033[?7l") self.screen = [] self.height, self.width = self.getheightwidth() - self.__buffer = [] - self.posxy = 0, 0 self.__gone_tall = 0 self.__move = self.__move_short @@ -368,13 +384,18 @@ class UnixConsole(Console): self.__disable_bracketed_paste() self.__maybe_write_code(self._rmkx) self.flushoutput() - tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate) + self.__input_fd_set(self.__svtermstate) - if platform.system() == "Darwin" and os.getenv("TERM_PROGRAM") == "Apple_Terminal": + if self.is_apple_terminal: os.write(self.output_fd, b"\033[?7h") if hasattr(self, "old_sigwinch"): - signal.signal(signal.SIGWINCH, self.old_sigwinch) + try: + signal.signal(signal.SIGWINCH, self.old_sigwinch) + except ValueError as e: + import threading + if threading.current_thread() is threading.main_thread(): + raise e del self.old_sigwinch def push_char(self, char: int | bytes) -> None: @@ -407,6 +428,8 @@ class UnixConsole(Console): return self.event_queue.get() else: continue + elif err.errno == errno.EIO: + raise SystemExit(errno.EIO) else: raise else: @@ -803,3 +826,17 @@ class UnixConsole(Console): os.write(self.output_fd, self._pad * nchars) else: time.sleep(float(delay) / 1000.0) + + def __input_fd_set( + self, + state: TermState, + ignore: AbstractSet[int] = _error_codes_to_ignore, + ) -> bool: + try: + tcsetattr(self.input_fd, termios.TCSADRAIN, state) + except termios.error as te: + if te.args[0] not in ignore: + raise + return False + else: + return True diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index fd788c8429e..06cddef851b 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -20,6 +20,7 @@ ANSI_ESCAPE_SEQUENCE = re.compile(r"\x1b\[[ -@]*[A-~]") ZERO_WIDTH_BRACKET = re.compile(r"\x01.*?\x02") ZERO_WIDTH_TRANS = str.maketrans({"\x01": "", "\x02": ""}) IDENTIFIERS_AFTER = {"def", "class"} +KEYWORD_CONSTANTS = {"True", "False", "None"} BUILTINS = {str(name) for name in dir(builtins) if not name.startswith('_')} @@ -62,6 +63,12 @@ class ColorSpan(NamedTuple): def str_width(c: str) -> int: if ord(c) < 128: return 1 + # gh-139246 for zero-width joiner and combining characters + if unicodedata.combining(c): + return 0 + category = unicodedata.category(c) + if category == "Cf" and c != "\u00ad": + return 0 w = unicodedata.east_asian_width(c) if w in ("N", "Na", "H", "A"): return 1 @@ -197,8 +204,11 @@ def gen_colors_from_token_stream( span = Span.from_token(token, line_lengths) yield ColorSpan(span, "definition") elif keyword.iskeyword(token.string): + span_cls = "keyword" + if token.string in KEYWORD_CONSTANTS: + span_cls = "keyword_constant" span = Span.from_token(token, line_lengths) - yield ColorSpan(span, "keyword") + yield ColorSpan(span, span_cls) if token.string in IDENTIFIERS_AFTER: is_def_name = True elif ( @@ -208,7 +218,10 @@ def gen_colors_from_token_stream( ): span = Span.from_token(token, line_lengths) yield ColorSpan(span, "soft_keyword") - elif token.string in BUILTINS: + elif ( + token.string in BUILTINS + and not (prev_token and prev_token.exact_type == T.DOT) + ): span = Span.from_token(token, line_lengths) yield ColorSpan(span, "builtin") @@ -257,6 +270,12 @@ def is_soft_keyword_used(*tokens: TI | None) -> bool: return True case (TI(string="case"), TI(string="_"), TI(string=":")): return True + case ( + None | TI(T.NEWLINE) | TI(T.INDENT) | TI(T.DEDENT) | TI(string=":"), + TI(string="type"), + TI(T.NAME, string=s) + ): + return not keyword.iskeyword(s) case _: return False diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index c56dcd6d7dd..f9f5988af0b 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -249,22 +249,10 @@ class WindowsConsole(Console): def __write_changed_line( self, y: int, oldline: str, newline: str, px_coord: int ) -> None: - # this is frustrating; there's no reason to test (say) - # self.dch1 inside the loop -- but alternative ways of - # structuring this function are equally painful (I'm trying to - # avoid writing code generators these days...) minlen = min(wlen(oldline), wlen(newline)) x_pos = 0 x_coord = 0 - px_pos = 0 - j = 0 - for c in oldline: - if j >= px_coord: - break - j += wlen(c) - px_pos += 1 - # reuse the oldline as much as possible, but stop as soon as we # encounter an ESCAPE, because it might be the start of an escape # sequence @@ -358,7 +346,6 @@ class WindowsConsole(Console): self.height, self.width = self.getheightwidth() self.posxy = 0, 0 - self.__gone_tall = 0 self.__offset = 0 if self.__vt_support: diff --git a/Lib/_strptime.py b/Lib/_strptime.py index cdc55e8daaf..d011ddf8b18 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -371,7 +371,9 @@ class TimeRE(dict): # W is set below by using 'U' 'y': r"(?P\d\d)", 'Y': r"(?P\d\d\d\d)", + # See gh-121237: "z" must support colons for backwards compatibility. 'z': r"(?P([+-]\d\d:?[0-5]\d(:?[0-5]\d(\.\d{1,6})?)?)|(?-i:Z))?", + ':z': r"(?P([+-]\d\d:[0-5]\d(:[0-5]\d(\.\d{1,6})?)?)|(?-i:Z))?", 'A': self.__seqToRE(self.locale_time.f_weekday, 'A'), 'a': self.__seqToRE(self.locale_time.a_weekday, 'a'), 'B': self.__seqToRE(_fixmonths(self.locale_time.f_month[1:]), 'B'), @@ -459,16 +461,16 @@ class TimeRE(dict): year_in_format = False day_of_month_in_format = False def repl(m): - format_char = m[1] - match format_char: + directive = m.group()[1:] # exclude `%` symbol + match directive: case 'Y' | 'y' | 'G': nonlocal year_in_format year_in_format = True case 'd': nonlocal day_of_month_in_format day_of_month_in_format = True - return self[format_char] - format = re_sub(r'%[-_0^#]*[0-9]*([OE]?\\?.?)', repl, format) + return self[directive] + format = re_sub(r'%[-_0^#]*[0-9]*([OE]?[:\\]?.?)', repl, format) if day_of_month_in_format and not year_in_format: import warnings warnings.warn("""\ @@ -555,8 +557,17 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): raise ValueError("time data %r does not match format %r" % (data_string, format)) if len(data_string) != found.end(): - raise ValueError("unconverted data remains: %s" % - data_string[found.end():]) + rest = data_string[found.end():] + # Specific check for '%:z' directive + if ( + "colon_z" in found.re.groupindex + and found.group("colon_z") is not None + and rest[0] != ":" + ): + raise ValueError( + f"Missing colon in %:z before '{rest}', got '{data_string}'" + ) + raise ValueError("unconverted data remains: %s" % rest) iso_year = year = None month = day = 1 @@ -616,18 +627,18 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): hour = parse_int(found_dict['I']) ampm = found_dict.get('p', '').lower() # If there was no AM/PM indicator, we'll treat this like AM - if ampm in ('', locale_time.am_pm[0]): - # We're in AM so the hour is correct unless we're - # looking at 12 midnight. - # 12 midnight == 12 AM == hour 0 - if hour == 12: - hour = 0 - elif ampm == locale_time.am_pm[1]: + if ampm == locale_time.am_pm[1]: # We're in PM so we need to add 12 to the hour unless # we're looking at 12 noon. # 12 noon == 12 PM == hour 12 if hour != 12: hour += 12 + else: + # We're in AM so the hour is correct unless we're + # looking at 12 midnight. + # 12 midnight == 12 AM == hour 0 + if hour == 12: + hour = 0 elif group_key == 'M': minute = parse_int(found_dict['M']) elif group_key == 'S': @@ -662,8 +673,8 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): week_of_year_start = 0 elif group_key == 'V': iso_week = int(found_dict['V']) - elif group_key == 'z': - z = found_dict['z'] + elif group_key in ('z', 'colon_z'): + z = found_dict[group_key] if z: if z == 'Z': gmtoff = 0 @@ -672,7 +683,7 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"): z = z[:3] + z[4:] if len(z) > 5: if z[5] != ':': - msg = f"Inconsistent use of : in {found_dict['z']}" + msg = f"Inconsistent use of : in {found_dict[group_key]}" raise ValueError(msg) z = z[:5] + z[6:] hours = int(z[1:3]) diff --git a/Lib/_threading_local.py b/Lib/_threading_local.py index 0b9e5d3bbf6..2af3885458b 100644 --- a/Lib/_threading_local.py +++ b/Lib/_threading_local.py @@ -57,7 +57,7 @@ class _localimpl: # as soon as the OS-level thread ends instead. local = wrlocal() if local is not None: - dct = local.dicts.pop(idt) + local.dicts.pop(idt) wrlocal = ref(self, local_deleted) wrthread = ref(thread, thread_deleted) thread.__dict__[key] = wrlocal diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py index bee019cd515..a5788cdbfae 100644 --- a/Lib/annotationlib.py +++ b/Lib/annotationlib.py @@ -85,6 +85,9 @@ class ForwardRef: # These are always set to None here but may be non-None if a ForwardRef # is created through __class__ assignment on a _Stringifier object. self.__globals__ = None + # This may be either a cell object (for a ForwardRef referring to a single name) + # or a dict mapping cell names to cell objects (for a ForwardRef containing references + # to multiple names). self.__cell__ = None self.__extra_names__ = None # These are initially None but serve as a cache and may be set to a non-None @@ -117,7 +120,7 @@ class ForwardRef: is_forwardref_format = True case _: raise NotImplementedError(format) - if self.__cell__ is not None: + if isinstance(self.__cell__, types.CellType): try: return self.__cell__.cell_contents except ValueError: @@ -147,26 +150,42 @@ class ForwardRef: if globals is None: globals = {} + if type_params is None and owner is not None: + type_params = getattr(owner, "__type_params__", None) + if locals is None: locals = {} if isinstance(owner, type): locals.update(vars(owner)) + elif ( + type_params is not None + or isinstance(self.__cell__, dict) + or self.__extra_names__ + ): + # Create a new locals dict if necessary, + # to avoid mutating the argument. + locals = dict(locals) - if type_params is None and owner is not None: - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - type_params = getattr(owner, "__type_params__", None) - - # Type parameters exist in their own scope, which is logically - # between the locals and the globals. We simulate this by adding - # them to the globals. + # "Inject" type parameters into the local namespace + # (unless they are shadowed by assignments *in* the local namespace), + # as a way of emulating annotation scopes when calling `eval()` if type_params is not None: - globals = dict(globals) for param in type_params: - globals[param.__name__] = param + locals.setdefault(param.__name__, param) + + # Similar logic can be used for nonlocals, which should not + # override locals. + if isinstance(self.__cell__, dict): + for cell_name, cell in self.__cell__.items(): + try: + cell_value = cell.cell_contents + except ValueError: + pass + else: + locals.setdefault(cell_name, cell_value) + if self.__extra_names__: - locals = {**locals, **self.__extra_names__} + locals.update(self.__extra_names__) arg = self.__forward_arg__ if arg.isidentifier() and not keyword.iskeyword(arg): @@ -187,8 +206,11 @@ class ForwardRef: except Exception: if not is_forwardref_format: raise + + # All variables, in scoping order, should be checked before + # triggering __missing__ to create a _Stringifier. new_locals = _StringifierDict( - {**builtins.__dict__, **locals}, + {**builtins.__dict__, **globals, **locals}, globals=globals, owner=owner, is_class=self.__forward_is_class__, @@ -199,7 +221,7 @@ class ForwardRef: except Exception: return self else: - new_locals.transmogrify() + new_locals.transmogrify(self.__cell__) return result def _evaluate(self, globalns, localns, type_params=_sentinel, *, recursive_guard): @@ -241,15 +263,8 @@ class ForwardRef: if self.__code__ is not None: return self.__code__ arg = self.__forward_arg__ - # If we do `def f(*args: *Ts)`, then we'll have `arg = '*Ts'`. - # Unfortunately, this isn't a valid expression on its own, so we - # do the unpacking manually. - if arg.startswith("*"): - arg_to_compile = f"({arg},)[0]" # E.g. (*Ts,)[0] or (*tuple[int, int],)[0] - else: - arg_to_compile = arg try: - self.__code__ = compile(arg_to_compile, "", "eval") + self.__code__ = compile(_rewrite_star_unpack(arg), "", "eval") except SyntaxError: raise SyntaxError(f"Forward reference must be an expression -- got {arg!r}") return self.__code__ @@ -278,7 +293,7 @@ class ForwardRef: self.__forward_module__, id(self.__globals__), # dictionaries are not hashable, so hash by identity self.__forward_is_class__, - self.__cell__, + tuple(sorted(self.__cell__.items())) if isinstance(self.__cell__, dict) else self.__cell__, self.__owner__, tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None, )) @@ -560,32 +575,70 @@ class _Stringifier: del _make_unary_op -def _template_to_ast(template): +def _template_to_ast_constructor(template): + """Convert a `template` instance to a non-literal AST.""" + args = [] + for part in template: + match part: + case str(): + args.append(ast.Constant(value=part)) + case _: + interp = ast.Call( + func=ast.Name(id="Interpolation"), + args=[ + ast.Constant(value=part.value), + ast.Constant(value=part.expression), + ast.Constant(value=part.conversion), + ast.Constant(value=part.format_spec), + ] + ) + args.append(interp) + return ast.Call(func=ast.Name(id="Template"), args=args, keywords=[]) + + +def _template_to_ast_literal(template, parsed): + """Convert a `template` instance to a t-string literal AST.""" values = [] + interp_count = 0 for part in template: match part: case str(): values.append(ast.Constant(value=part)) - # Interpolation, but we don't want to import the string module case _: interp = ast.Interpolation( str=part.expression, - value=ast.parse(part.expression), - conversion=( - ord(part.conversion) - if part.conversion is not None - else -1 - ), - format_spec=( - ast.Constant(value=part.format_spec) - if part.format_spec != "" - else None - ), + value=parsed[interp_count], + conversion=ord(part.conversion) if part.conversion else -1, + format_spec=ast.Constant(value=part.format_spec) + if part.format_spec + else None, ) values.append(interp) + interp_count += 1 return ast.TemplateStr(values=values) +def _template_to_ast(template): + """Make a best-effort conversion of a `template` instance to an AST.""" + # gh-138558: Not all Template instances can be represented as t-string + # literals. Return the most accurate AST we can. See issue for details. + + # If any expr is empty or whitespace only, we cannot convert to a literal. + if any(part.expression.strip() == "" for part in template.interpolations): + return _template_to_ast_constructor(template) + + try: + # Wrap in parens to allow whitespace inside interpolation curly braces + parsed = tuple( + ast.parse(f"({part.expression})", mode="eval").body + for part in template.interpolations + ) + except SyntaxError: + return _template_to_ast_constructor(template) + + return _template_to_ast_literal(template, parsed) + + class _StringifierDict(dict): def __init__(self, namespace, *, globals=None, owner=None, is_class=False, format): super().__init__(namespace) @@ -608,13 +661,15 @@ class _StringifierDict(dict): self.stringifiers.append(fwdref) return fwdref - def transmogrify(self): + def transmogrify(self, cell_dict): for obj in self.stringifiers: obj.__class__ = ForwardRef obj.__stringifier_dict__ = None # not needed for ForwardRef if isinstance(obj.__ast_node__, str): obj.__arg__ = obj.__ast_node__ obj.__ast_node__ = None + if cell_dict is not None and obj.__cell__ is None: + obj.__cell__ = cell_dict def create_unique_name(self): name = f"__annotationlib_name_{self.next_id}__" @@ -664,9 +719,21 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False): # possibly constants if the annotate function uses them directly). We then # convert each of those into a string to get an approximation of the # original source. + + # Attempt to call with VALUE_WITH_FAKE_GLOBALS to check if it is implemented + # See: https://github.com/python/cpython/issues/138764 + # Only fail on NotImplementedError + try: + annotate(Format.VALUE_WITH_FAKE_GLOBALS) + except NotImplementedError: + # Both STRING and VALUE_WITH_FAKE_GLOBALS are not implemented: fallback to VALUE + return annotations_to_string(annotate(Format.VALUE)) + except Exception: + pass + globals = _StringifierDict({}, format=format) is_class = isinstance(owner, type) - closure = _build_closure( + closure, _ = _build_closure( annotate, owner, is_class, globals, allow_evaluation=False ) func = types.FunctionType( @@ -710,7 +777,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False): is_class=is_class, format=format, ) - closure = _build_closure( + closure, cell_dict = _build_closure( annotate, owner, is_class, globals, allow_evaluation=True ) func = types.FunctionType( @@ -722,10 +789,13 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False): ) try: result = func(Format.VALUE_WITH_FAKE_GLOBALS) + except NotImplementedError: + # FORWARDREF and VALUE_WITH_FAKE_GLOBALS not supported, fall back to VALUE + return annotate(Format.VALUE) except Exception: pass else: - globals.transmogrify() + globals.transmogrify(cell_dict) return result # Try again, but do not provide any globals. This allows us to return @@ -737,7 +807,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False): is_class=is_class, format=format, ) - closure = _build_closure( + closure, cell_dict = _build_closure( annotate, owner, is_class, globals, allow_evaluation=False ) func = types.FunctionType( @@ -748,7 +818,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False): kwdefaults=annotate.__kwdefaults__, ) result = func(Format.VALUE_WITH_FAKE_GLOBALS) - globals.transmogrify() + globals.transmogrify(cell_dict) if _is_evaluate: if isinstance(result, ForwardRef): return result.evaluate(format=Format.FORWARDREF) @@ -773,14 +843,11 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False): def _build_closure(annotate, owner, is_class, stringifier_dict, *, allow_evaluation): if not annotate.__closure__: - return None - freevars = annotate.__code__.co_freevars + return None, None new_closure = [] - for i, cell in enumerate(annotate.__closure__): - if i < len(freevars): - name = freevars[i] - else: - name = "__cell__" + cell_dict = {} + for name, cell in zip(annotate.__code__.co_freevars, annotate.__closure__, strict=True): + cell_dict[name] = cell new_cell = None if allow_evaluation: try: @@ -801,7 +868,7 @@ def _build_closure(annotate, owner, is_class, stringifier_dict, *, allow_evaluat stringifier_dict.stringifiers.append(fwdref) new_cell = types.CellType(fwdref) new_closure.append(new_cell) - return tuple(new_closure) + return tuple(new_closure), cell_dict def _stringify_single(anno): @@ -987,7 +1054,8 @@ def get_annotations( locals = {param.__name__: param for param in type_params} | locals return_value = { - key: value if not isinstance(value, str) else eval(value, globals, locals) + key: value if not isinstance(value, str) + else eval(_rewrite_star_unpack(value), globals, locals) for key, value in ann.items() } return return_value @@ -1024,6 +1092,16 @@ def annotations_to_string(annotations): } +def _rewrite_star_unpack(arg): + """If the given argument annotation expression is a star unpack e.g. `'*Ts'` + rewrite it to a valid expression. + """ + if arg.startswith("*"): + return f"({arg},)[0]" # E.g. (*Ts,)[0] or (*tuple[int, int],)[0] + else: + return arg + + def _get_and_call_annotate(obj, format): """Get the __annotate__ function and call it. diff --git a/Lib/argparse.py b/Lib/argparse.py index 2144c81886a..633fec69ea4 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -64,7 +64,6 @@ considered public as object names -- the API of the formatter objects is still considered an implementation detail.) """ -__version__ = '1.1' __all__ = [ 'ArgumentParser', 'ArgumentError', @@ -90,8 +89,8 @@ __all__ = [ import os as _os import re as _re import sys as _sys - -from gettext import gettext as _, ngettext +from gettext import gettext as _ +from gettext import ngettext SUPPRESS = '==SUPPRESS==' @@ -167,7 +166,6 @@ class HelpFormatter(object): indent_increment=2, max_help_position=24, width=None, - color=True, ): # default setting for width if width is None: @@ -175,7 +173,6 @@ class HelpFormatter(object): width = shutil.get_terminal_size().columns width -= 2 - self._set_color(color) self._prog = prog self._indent_increment = indent_increment self._max_help_position = min(max_help_position, @@ -192,10 +189,12 @@ class HelpFormatter(object): self._whitespace_matcher = _re.compile(r'\s+', _re.ASCII) self._long_break_matcher = _re.compile(r'\n\n\n+') - def _set_color(self, color): + self._set_color(False) + + def _set_color(self, color, *, file=None): from _colorize import can_colorize, decolor, get_theme - if color and can_colorize(): + if color and can_colorize(file=file): self._theme = get_theme(force_color=True).argparse self._decolor = decolor else: @@ -281,7 +280,7 @@ class HelpFormatter(object): if action.help is not SUPPRESS: # find all invocations - get_invocation = self._format_action_invocation + get_invocation = lambda x: self._decolor(self._format_action_invocation(x)) invocation_lengths = [len(get_invocation(action)) + self._current_indent] for subaction in self._iter_indented_subactions(action): invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent) @@ -337,27 +336,17 @@ class HelpFormatter(object): elif usage is None: prog = '%(prog)s' % dict(prog=self._prog) - # split optionals from positionals - optionals = [] - positionals = [] - for action in actions: - if action.option_strings: - optionals.append(action) - else: - positionals.append(action) - + parts, pos_start = self._get_actions_usage_parts(actions, groups) # build full usage string - format = self._format_actions_usage - action_usage = format(optionals + positionals, groups) - usage = ' '.join([s for s in [prog, action_usage] if s]) + usage = ' '.join(filter(None, [prog, *parts])) # wrap the usage parts if it's too long text_width = self._width - self._current_indent if len(prefix) + len(self._decolor(usage)) > text_width: # break usage into wrappable parts - opt_parts = self._get_actions_usage_parts(optionals, groups) - pos_parts = self._get_actions_usage_parts(positionals, groups) + opt_parts = parts[:pos_start] + pos_parts = parts[pos_start:] # helper for wrapping lines def get_lines(parts, indent, prefix=None): @@ -414,117 +403,141 @@ class HelpFormatter(object): # prefix with 'usage:' return f'{t.usage}{prefix}{t.reset}{usage}\n\n' - def _format_actions_usage(self, actions, groups): - return ' '.join(self._get_actions_usage_parts(actions, groups)) - def _is_long_option(self, string): return len(string) > 2 def _get_actions_usage_parts(self, actions, groups): - # find group indices and identify actions in groups - group_actions = set() - inserts = {} + """Get usage parts with split index for optionals/positionals. + + Returns (parts, pos_start) where pos_start is the index in parts + where positionals begin. + This preserves mutually exclusive group formatting across the + optionals/positionals boundary (gh-75949). + """ + actions = [action for action in actions if action.help is not SUPPRESS] + # group actions by mutually exclusive groups + action_groups = dict.fromkeys(actions) for group in groups: - if not group._group_actions: - raise ValueError(f'empty group {group}') - - if all(action.help is SUPPRESS for action in group._group_actions): - continue - - try: - start = min(actions.index(item) for item in group._group_actions) - except ValueError: - continue - else: - end = start + len(group._group_actions) - if set(actions[start:end]) == set(group._group_actions): - group_actions.update(group._group_actions) - inserts[start, end] = group + for action in group._group_actions: + if action in action_groups: + action_groups[action] = group + # positional arguments keep their position + positionals = [] + for action in actions: + if not action.option_strings: + group = action_groups.pop(action) + if group: + group_actions = [ + action2 for action2 in group._group_actions + if action2.option_strings and + action_groups.pop(action2, None) + ] + [action] + positionals.append((group.required, group_actions)) + else: + positionals.append((None, [action])) + # the remaining optional arguments are sorted by the position of + # the first option in the group + optionals = [] + for action in actions: + if action.option_strings and action in action_groups: + group = action_groups.pop(action) + if group: + group_actions = [action] + [ + action2 for action2 in group._group_actions + if action2.option_strings and + action_groups.pop(action2, None) + ] + optionals.append((group.required, group_actions)) + else: + optionals.append((None, [action])) # collect all actions format strings parts = [] t = self._theme - for action in actions: + pos_start = None + for i, (required, group) in enumerate(optionals + positionals): + start = len(parts) + if i == len(optionals): + pos_start = start + in_group = len(group) > 1 + for action in group: + # produce all arg strings + if not action.option_strings: + default = self._get_default_metavar_for_positional(action) + part = self._format_args(action, default) + # if it's in a group, strip the outer [] + if in_group: + if part[0] == '[' and part[-1] == ']': + part = part[1:-1] + part = t.summary_action + part + t.reset - # suppressed arguments are marked with None - if action.help is SUPPRESS: - part = None - - # produce all arg strings - elif not action.option_strings: - default = self._get_default_metavar_for_positional(action) - part = ( - t.summary_action - + self._format_args(action, default) - + t.reset - ) - - # if it's in a group, strip the outer [] - if action in group_actions: - if part[0] == '[' and part[-1] == ']': - part = part[1:-1] - - # produce the first way to invoke the option in brackets - else: - option_string = action.option_strings[0] - if self._is_long_option(option_string): - option_color = t.summary_long_option + # produce the first way to invoke the option in brackets else: - option_color = t.summary_short_option + option_string = action.option_strings[0] + if self._is_long_option(option_string): + option_color = t.summary_long_option + else: + option_color = t.summary_short_option - # if the Optional doesn't take a value, format is: - # -s or --long - if action.nargs == 0: - part = action.format_usage() - part = f"{option_color}{part}{t.reset}" + # if the Optional doesn't take a value, format is: + # -s or --long + if action.nargs == 0: + part = action.format_usage() + part = f"{option_color}{part}{t.reset}" - # if the Optional takes a value, format is: - # -s ARGS or --long ARGS - else: - default = self._get_default_metavar_for_optional(action) - args_string = self._format_args(action, default) - part = ( - f"{option_color}{option_string} " - f"{t.summary_label}{args_string}{t.reset}" - ) + # if the Optional takes a value, format is: + # -s ARGS or --long ARGS + else: + default = self._get_default_metavar_for_optional(action) + args_string = self._format_args(action, default) + part = ( + f"{option_color}{option_string} " + f"{t.summary_label}{args_string}{t.reset}" + ) - # make it look optional if it's not required or in a group - if not action.required and action not in group_actions: - part = '[%s]' % part + # make it look optional if it's not required or in a group + if not (action.required or required or in_group): + part = '[%s]' % part - # add the action string to the list - parts.append(part) + # add the action string to the list + parts.append(part) - # group mutually exclusive actions - inserted_separators_indices = set() - for start, end in sorted(inserts, reverse=True): - group = inserts[start, end] - group_parts = [item for item in parts[start:end] if item is not None] - group_size = len(group_parts) - if group.required: - open, close = "()" if group_size > 1 else ("", "") - else: - open, close = "[]" - group_parts[0] = open + group_parts[0] - group_parts[-1] = group_parts[-1] + close - for i, part in enumerate(group_parts[:-1], start=start): - # insert a separator if not already done in a nested group - if i not in inserted_separators_indices: - parts[i] = part + ' |' - inserted_separators_indices.add(i) - parts[start + group_size - 1] = group_parts[-1] - for i in range(start + group_size, end): - parts[i] = None + if in_group: + parts[start] = ('(' if required else '[') + parts[start] + for i in range(start, len(parts) - 1): + parts[i] += ' |' + parts[-1] += ')' if required else ']' - # return the usage parts - return [item for item in parts if item is not None] + if pos_start is None: + pos_start = len(parts) + return parts, pos_start def _format_text(self, text): if '%(prog)' in text: text = text % dict(prog=self._prog) text_width = max(self._width - self._current_indent, 11) indent = ' ' * self._current_indent - return self._fill_text(text, text_width, indent) + '\n\n' + text = self._fill_text(text, text_width, indent) + text = self._apply_text_markup(text) + return text + '\n\n' + + def _apply_text_markup(self, text): + """Apply color markup to text. + + Supported markup: + `...` - inline code (rendered with prog_extra color) + + When colors are disabled, backticks are preserved as-is. + """ + t = self._theme + if not t.reset: + return text + text = _re.sub( + r'`([^`]+)`', + rf'{t.prog_extra}\1{t.reset}', + text, + ) + return text def _format_action(self, action): # determine the required width and the entry label @@ -675,6 +688,10 @@ class HelpFormatter(object): params[name] = value.__name__ if params.get('choices') is not None: params['choices'] = ', '.join(map(str, params['choices'])) + # Before interpolating, wrap the values with color codes + t = self._theme + for name, value in params.items(): + params[name] = f"{t.interpolated_value}{value}{t.reset}" return help_string % params def _iter_indented_subactions(self, action): @@ -745,11 +762,21 @@ class ArgumentDefaultsHelpFormatter(HelpFormatter): if help is None: help = '' - if '%(default)' not in help: - if action.default is not SUPPRESS: - defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] - if action.option_strings or action.nargs in defaulting_nargs: - help += _(' (default: %(default)s)') + if ( + '%(default)' not in help + and action.default is not SUPPRESS + and not action.required + ): + defaulting_nargs = (OPTIONAL, ZERO_OR_MORE) + if action.option_strings or action.nargs in defaulting_nargs: + t = self._theme + default_str = _(" (default: %(default)s)") + prefix, suffix = default_str.split("%(default)s") + help += ( + f" {t.default}{prefix.lstrip()}{t.reset}" + f"%(default)s" + f"{t.default}{suffix}{t.reset}" + ) return help @@ -933,15 +960,26 @@ class BooleanOptionalAction(Action): deprecated=False): _option_strings = [] + neg_option_strings = [] for option_string in option_strings: _option_strings.append(option_string) - if option_string.startswith('--'): - if option_string.startswith('--no-'): + if len(option_string) > 2 and option_string[0] == option_string[1]: + # two-dash long option: '--foo' -> '--no-foo' + if option_string.startswith('no-', 2): raise ValueError(f'invalid option name {option_string!r} ' f'for BooleanOptionalAction') - option_string = '--no-' + option_string[2:] + option_string = option_string[:2] + 'no-' + option_string[2:] _option_strings.append(option_string) + neg_option_strings.append(option_string) + elif len(option_string) > 2 and option_string[0] != option_string[1]: + # single-dash long option: '-foo' -> '-nofoo' + if option_string.startswith('no', 1): + raise ValueError(f'invalid option name {option_string!r} ' + f'for BooleanOptionalAction') + option_string = option_string[:1] + 'no' + option_string[1:] + _option_strings.append(option_string) + neg_option_strings.append(option_string) super().__init__( option_strings=_option_strings, @@ -951,11 +989,12 @@ class BooleanOptionalAction(Action): required=required, help=help, deprecated=deprecated) + self.neg_option_strings = neg_option_strings def __call__(self, parser, namespace, values, option_string=None): if option_string in self.option_strings: - setattr(namespace, self.dest, not option_string.startswith('--no-')) + setattr(namespace, self.dest, option_string not in self.neg_option_strings) def format_usage(self): return ' | '.join(self.option_strings) @@ -1552,8 +1591,8 @@ class _ActionsContainer(object): f'instance of it must be passed') # raise an error if the metavar does not match the type - if hasattr(self, "_get_formatter"): - formatter = self._get_formatter() + if hasattr(self, "_get_validation_formatter"): + formatter = self._get_validation_formatter() try: formatter._format_args(action, None) except TypeError: @@ -1661,29 +1700,35 @@ class _ActionsContainer(object): def _get_optional_kwargs(self, *args, **kwargs): # determine short and long option strings option_strings = [] - long_option_strings = [] for option_string in args: # error on strings that don't start with an appropriate prefix - if not option_string[0] in self.prefix_chars: + if option_string[0] not in self.prefix_chars: raise ValueError( f'invalid option string {option_string!r}: ' f'must start with a character {self.prefix_chars!r}') - - # strings starting with two prefix characters are long options option_strings.append(option_string) - if len(option_string) > 1 and option_string[1] in self.prefix_chars: - long_option_strings.append(option_string) # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' dest = kwargs.pop('dest', None) if dest is None: - if long_option_strings: - dest_option_string = long_option_strings[0] - else: - dest_option_string = option_strings[0] - dest = dest_option_string.lstrip(self.prefix_chars) + priority = 0 + for option_string in option_strings: + if len(option_string) <= 2: + # short option: '-x' -> 'x' + if priority < 1: + dest = option_string.lstrip(self.prefix_chars) + priority = 1 + elif option_string[1] not in self.prefix_chars: + # single-dash long option: '-foo' -> 'foo' + if priority < 2: + dest = option_string.lstrip(self.prefix_chars) + priority = 2 + else: + # two-dash long option: '--foo' -> 'foo' + dest = option_string.lstrip(self.prefix_chars) + break if not dest: - msg = f'dest= is required for options like {option_string!r}' + msg = f'dest= is required for options like {repr(option_strings)[1:-1]}' raise TypeError(msg) dest = dest.replace('-', '_') @@ -1741,8 +1786,8 @@ class _ActionsContainer(object): action.container._remove_action(action) def _check_help(self, action): - if action.help and hasattr(self, "_get_formatter"): - formatter = self._get_formatter() + if action.help and hasattr(self, "_get_validation_formatter"): + formatter = self._get_validation_formatter() try: formatter._expand_help(action) except (ValueError, TypeError, KeyError) as exc: @@ -1858,7 +1903,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - exit_on_error -- Determines whether or not ArgumentParser exits with error info when an error occurs - suggest_on_error - Enables suggestions for mistyped argument choices - and subparser names (default: ``False``) + and subparser names (default: ``True``) - color - Allow color output in help messages (default: ``False``) """ @@ -1877,7 +1922,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): allow_abbrev=True, exit_on_error=True, *, - suggest_on_error=False, + suggest_on_error=True, color=True, ): superinit = super(ArgumentParser, self).__init__ @@ -1897,6 +1942,9 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): self.suggest_on_error = suggest_on_error self.color = color + # Cached formatter for validation (avoids repeated _set_color calls) + self._cached_formatter = None + add_group = self.add_argument_group self._positionals = add_group(_('positional arguments')) self._optionals = add_group(_('options')) @@ -1958,12 +2006,16 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): self._subparsers = self._positionals # prog defaults to the usage message of this parser, skipping - # optional arguments and with no "usage:" prefix + # non-required optional arguments and with no "usage:" prefix if kwargs.get('prog') is None: - formatter = self._get_formatter() + # Create formatter without color to avoid storing ANSI codes in prog + formatter = self.formatter_class(prog=self.prog) + formatter._set_color(False) positionals = self._get_positional_actions() + required_optionals = [action for action in self._get_optional_actions() + if action.required] groups = self._mutually_exclusive_groups - formatter.add_usage(None, positionals, groups, '') + formatter.add_usage(None, required_optionals + positionals, groups, '') kwargs['prog'] = formatter.format_help().strip() # create the parsers action and add it to the positionals list @@ -2430,7 +2482,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): return None # if it doesn't start with a prefix, it was meant to be positional - if not arg_string[0] in self.prefix_chars: + if arg_string[0] not in self.prefix_chars: return None # if the option string is present in the parser, return the action @@ -2692,14 +2744,16 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # Help-formatting methods # ======================= - def format_usage(self): - formatter = self._get_formatter() + def format_usage(self, formatter=None): + if formatter is None: + formatter = self._get_formatter() formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups) return formatter.format_help() - def format_help(self): - formatter = self._get_formatter() + def format_help(self, formatter=None): + if formatter is None: + formatter = self._get_formatter() # usage formatter.add_usage(self.usage, self._actions, @@ -2721,11 +2775,18 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # determine help from format above return formatter.format_help() - def _get_formatter(self): + def _get_formatter(self, file=None): formatter = self.formatter_class(prog=self.prog) - formatter._set_color(self.color) + formatter._set_color(self.color, file=file) return formatter + def _get_validation_formatter(self): + # Return cached formatter for read-only validation operations + # (_expand_help and _format_args). Avoids repeated slow _set_color calls. + if self._cached_formatter is None: + self._cached_formatter = self._get_formatter() + return self._cached_formatter + # ===================== # Help-printing methods # ===================== @@ -2733,12 +2794,26 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def print_usage(self, file=None): if file is None: file = _sys.stdout - self._print_message(self.format_usage(), file) + formatter = self._get_formatter(file=file) + try: + usage_text = self.format_usage(formatter=formatter) + except TypeError: + # Backward compatibility for formatter classes that + # do not accept the 'formatter' keyword argument. + usage_text = self.format_usage() + self._print_message(usage_text, file) def print_help(self, file=None): if file is None: file = _sys.stdout - self._print_message(self.format_help(), file) + formatter = self._get_formatter(file=file) + try: + help_text = self.format_help(formatter=formatter) + except TypeError: + # Backward compatibility for formatter classes that + # do not accept the 'formatter' keyword argument. + help_text = self.format_help() + self._print_message(help_text, file) def _print_message(self, message, file=None): if message: @@ -2748,6 +2823,14 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): except (AttributeError, OSError): pass + def _get_theme(self, file=None): + from _colorize import can_colorize, get_theme + + if self.color and can_colorize(file=file): + return get_theme(force_color=True).argparse + else: + return get_theme(force_no_color=True).argparse + # =============== # Exiting methods # =============== @@ -2767,9 +2850,26 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): should either exit or raise an exception. """ self.print_usage(_sys.stderr) + theme = self._get_theme(file=_sys.stderr) + fmt = _('%(prog)s: error: %(message)s\n') + fmt = fmt.replace('error: %(message)s', + f'{theme.error}error:{theme.reset} {theme.message}%(message)s{theme.reset}') + args = {'prog': self.prog, 'message': message} - self.exit(2, _('%(prog)s: error: %(message)s\n') % args) + self.exit(2, fmt % args) def _warning(self, message): + theme = self._get_theme(file=_sys.stderr) + fmt = _('%(prog)s: warning: %(message)s\n') + fmt = fmt.replace('warning: %(message)s', + f'{theme.warning}warning:{theme.reset} {theme.message}%(message)s{theme.reset}') args = {'prog': self.prog, 'message': message} - self._print_message(_('%(prog)s: warning: %(message)s\n') % args, _sys.stderr) + self._print_message(fmt % args, _sys.stderr) + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.1" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/ast.py b/Lib/ast.py index 983ac1710d0..d9743ba7ab4 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -24,7 +24,7 @@ from _ast import * def parse(source, filename='', mode='exec', *, - type_comments=False, feature_version=None, optimize=-1): + type_comments=False, feature_version=None, optimize=-1, module=None): """ Parse the source into an AST node. Equivalent to compile(source, filename, mode, PyCF_ONLY_AST). @@ -44,7 +44,8 @@ def parse(source, filename='', mode='exec', *, feature_version = minor # Else it should be an int giving the minor version for 3.x. return compile(source, filename, mode, flags, - _feature_version=feature_version, optimize=optimize) + _feature_version=feature_version, optimize=optimize, + module=module) def literal_eval(node_or_string): diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 5ef2e1f9efc..89d456b6858 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -1,6 +1,7 @@ import argparse import ast import asyncio +import asyncio.tools import concurrent.futures import contextvars import inspect @@ -10,9 +11,6 @@ import sys import threading import types import warnings -from asyncio.tools import (TaskTableOutputFormat, - display_awaited_by_tasks_table, - display_awaited_by_tasks_tree) from _colorize import get_theme from _pyrepl.console import InteractiveColoredConsole @@ -76,7 +74,8 @@ class AsyncIOInteractiveConsole(InteractiveColoredConsole): return except BaseException: if keyboard_interrupted: - self.write("\nKeyboardInterrupt\n") + if not CAN_USE_PYREPL: + self.write("\nKeyboardInterrupt\n") else: self.showtraceback() return self.STATEMENT_FAILED @@ -108,13 +107,17 @@ class REPLThread(threading.Thread): if CAN_USE_PYREPL: theme = get_theme().syntax ps1 = f"{theme.prompt}{ps1}{theme.reset}" - console.write(f"{ps1}import asyncio\n") + import_line = f'{theme.keyword}import{theme.reset} asyncio' + else: + import_line = "import asyncio" + console.write(f"{ps1}{import_line}\n") if CAN_USE_PYREPL: from _pyrepl.simple_interact import ( run_multiline_interactive_console, ) try: + sys.ps1 = ps1 run_multiline_interactive_console(console) except SystemExit: # expected via the `exit` and `quit` commands @@ -155,11 +158,6 @@ if __name__ == '__main__': "ps", help="Display a table of all pending tasks in a process" ) ps.add_argument("pid", type=int, help="Process ID to inspect") - formats = [fmt.value for fmt in TaskTableOutputFormat] - formats_to_show = [fmt for fmt in formats - if fmt != TaskTableOutputFormat.bsv.value] - ps.add_argument("--format", choices=formats, default="table", - metavar=f"{{{','.join(formats_to_show)}}}") pstree = subparsers.add_parser( "pstree", help="Display a tree of all pending tasks in a process" ) @@ -167,10 +165,10 @@ if __name__ == '__main__': args = parser.parse_args() match args.command: case "ps": - display_awaited_by_tasks_table(args.pid, format=args.format) + asyncio.tools.display_awaited_by_tasks_table(args.pid) sys.exit(0) case "pstree": - display_awaited_by_tasks_tree(args.pid) + asyncio.tools.display_awaited_by_tasks_tree(args.pid) sys.exit(0) case None: pass # continue to the interactive shell @@ -242,4 +240,5 @@ if __name__ == '__main__': break console.write('exiting asyncio REPL...\n') + loop.close() sys.exit(return_code) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 8cbb71f7085..6619c87bcf5 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -949,7 +949,7 @@ class BaseEventLoop(events.AbstractEventLoop): try: return await self._sock_sendfile_native(sock, file, offset, count) - except exceptions.SendfileNotAvailableError as exc: + except exceptions.SendfileNotAvailableError: if not fallback: raise return await self._sock_sendfile_fallback(sock, file, @@ -1270,7 +1270,7 @@ class BaseEventLoop(events.AbstractEventLoop): try: return await self._sendfile_native(transport, file, offset, count) - except exceptions.SendfileNotAvailableError as exc: + except exceptions.SendfileNotAvailableError: if not fallback: raise diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index d40af422e61..321a4e5d5d1 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -26,6 +26,7 @@ class BaseSubprocessTransport(transports.SubprocessTransport): self._pending_calls = collections.deque() self._pipes = {} self._finished = False + self._pipes_connected = False if stdin == subprocess.PIPE: self._pipes[0] = None @@ -213,6 +214,7 @@ class BaseSubprocessTransport(transports.SubprocessTransport): else: if waiter is not None and not waiter.cancelled(): waiter.set_result(None) + self._pipes_connected = True def _call(self, cb, *data): if self._pending_calls is not None: @@ -256,6 +258,15 @@ class BaseSubprocessTransport(transports.SubprocessTransport): assert not self._finished if self._returncode is None: return + if not self._pipes_connected: + # self._pipes_connected can be False if not all pipes were connected + # because either the process failed to start or the self._connect_pipes task + # got cancelled. In this broken state we consider all pipes disconnected and + # to avoid hanging forever in self._wait as otherwise _exit_waiters + # would never be woken up, we wake them up here. + for waiter in self._exit_waiters: + if not waiter.cancelled(): + waiter.set_result(self._returncode) if all(p is not None and p.disconnected for p in self._pipes.values()): self._finished = True diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 6bd00a64478..29652295218 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -389,7 +389,7 @@ def _chain_future(source, destination): def _call_check_cancel(destination): if destination.cancelled(): - if source_loop is None or source_loop is dest_loop: + if source_loop is None or source_loop is events._get_running_loop(): source.cancel() else: source_loop.call_soon_threadsafe(source.cancel) @@ -398,7 +398,7 @@ def _chain_future(source, destination): if (destination.cancelled() and dest_loop is not None and dest_loop.is_closed()): return - if dest_loop is None or dest_loop is source_loop: + if dest_loop is None or dest_loop is events._get_running_loop(): _set_state(destination, source) else: if dest_loop.is_closed(): diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index f404273c3ae..3fa93b14a67 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -733,7 +733,7 @@ class BaseProactorEventLoop(base_events.BaseEventLoop): async def _sock_sendfile_native(self, sock, file, offset, count): try: fileno = file.fileno() - except (AttributeError, io.UnsupportedOperation) as err: + except (AttributeError, io.UnsupportedOperation): raise exceptions.SendfileNotAvailableError("not a regular file") try: fsize = os.fstat(fileno).st_size diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index 3505d4bb6bd..ff7e16df3c6 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1050,8 +1050,8 @@ class _SelectorSocketTransport(_SelectorTransport): def write(self, data): if not isinstance(data, (bytes, bytearray, memoryview)): - raise TypeError(f'data argument must be a bytes-like object, ' - f'not {type(data).__name__!r}') + raise TypeError(f'data argument must be a bytes, bytearray, or memoryview ' + f'object, not {type(data).__name__!r}') if self._eof: raise RuntimeError('Cannot call write() after write_eof()') if self._empty_waiter is not None: @@ -1174,6 +1174,13 @@ class _SelectorSocketTransport(_SelectorTransport): raise RuntimeError('unable to writelines; sendfile is in progress') if not list_of_data: return + + if self._conn_lost: + if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES: + logger.warning('socket.send() raised exception.') + self._conn_lost += 1 + return + self._buffer.extend([memoryview(data) for data in list_of_data]) self._write_ready() # If the entire buffer couldn't be written, register a write handler diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index c8c01f36474..d2db1a930c2 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -214,7 +214,6 @@ class StreamReaderProtocol(FlowControlMixin, protocols.Protocol): return self._stream_reader_wr() def _replace_transport(self, transport): - loop = self._loop self._transport = transport self._over_ssl = transport.get_extra_info('sslcontext') is not None @@ -668,8 +667,7 @@ class StreamReader: # adds data which makes separator be found. That's why we check for # EOF *after* inspecting the buffer. if self._eof: - chunk = bytes(self._buffer) - self._buffer.clear() + chunk = self._buffer.take_bytes() raise exceptions.IncompleteReadError(chunk, None) # _wait_for_data() will resume reading if stream was paused. @@ -679,10 +677,9 @@ class StreamReader: raise exceptions.LimitOverrunError( 'Separator is found, but chunk is longer than limit', match_start) - chunk = self._buffer[:match_end] - del self._buffer[:match_end] + chunk = self._buffer.take_bytes(match_end) self._maybe_resume_transport() - return bytes(chunk) + return chunk async def read(self, n=-1): """Read up to `n` bytes from the stream. @@ -717,20 +714,16 @@ class StreamReader: # collect everything in self._buffer, but that would # deadlock if the subprocess sends more than self.limit # bytes. So just call self.read(self._limit) until EOF. - blocks = [] - while True: - block = await self.read(self._limit) - if not block: - break - blocks.append(block) - return b''.join(blocks) + joined = bytearray() + while block := await self.read(self._limit): + joined += block + return joined.take_bytes() if not self._buffer and not self._eof: await self._wait_for_data('read') # This will work right even if buffer is less than n bytes - data = bytes(memoryview(self._buffer)[:n]) - del self._buffer[:n] + data = self._buffer.take_bytes(min(len(self._buffer), n)) self._maybe_resume_transport() return data @@ -761,18 +754,12 @@ class StreamReader: while len(self._buffer) < n: if self._eof: - incomplete = bytes(self._buffer) - self._buffer.clear() + incomplete = self._buffer.take_bytes() raise exceptions.IncompleteReadError(incomplete, n) await self._wait_for_data('readexactly') - if len(self._buffer) == n: - data = bytes(self._buffer) - self._buffer.clear() - else: - data = bytes(memoryview(self._buffer)[:n]) - del self._buffer[:n] + data = self._buffer.take_bytes(n) self._maybe_resume_transport() return data diff --git a/Lib/asyncio/tools.py b/Lib/asyncio/tools.py index 3887fb8ab5b..f9b8a4ee56c 100644 --- a/Lib/asyncio/tools.py +++ b/Lib/asyncio/tools.py @@ -1,9 +1,8 @@ """Tools to analyze tasks running in asyncio programs.""" from collections import defaultdict -import csv from itertools import count -from enum import Enum, StrEnum, auto +from enum import Enum import sys from _remote_debugging import RemoteUnwinder, FrameInfo @@ -223,6 +222,20 @@ def _print_cycle_exception(exception: CycleFoundException): print(f"cycle: {inames}", file=sys.stderr) +def exit_with_permission_help_text(): + """ + Prints a message pointing to platform-specific permission help text and exits the program. + This function is called when a PermissionError is encountered while trying + to attach to a process. + """ + print( + "Error: The specified process cannot be attached to due to insufficient permissions.\n" + "See the Python documentation for details on required privileges and troubleshooting:\n" + "https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n" + ) + sys.exit(1) + + def _get_awaited_by_tasks(pid: int) -> list: try: return get_all_awaited_by(pid) @@ -231,58 +244,22 @@ def _get_awaited_by_tasks(pid: int) -> list: e = e.__context__ print(f"Error retrieving tasks: {e}") sys.exit(1) + except PermissionError: + exit_with_permission_help_text() -class TaskTableOutputFormat(StrEnum): - table = auto() - csv = auto() - bsv = auto() - # 🍌SV is not just a format. It's a lifestyle. A philosophy. - # https://www.youtube.com/watch?v=RrsVi1P6n0w - - -def display_awaited_by_tasks_table(pid, *, format=TaskTableOutputFormat.table): +def display_awaited_by_tasks_table(pid: int) -> None: """Build and print a table of all pending tasks under `pid`.""" tasks = _get_awaited_by_tasks(pid) table = build_task_table(tasks) - format = TaskTableOutputFormat(format) - if format == TaskTableOutputFormat.table: - _display_awaited_by_tasks_table(table) - else: - _display_awaited_by_tasks_csv(table, format=format) - - -_row_header = ('tid', 'task id', 'task name', 'coroutine stack', - 'awaiter chain', 'awaiter name', 'awaiter id') - - -def _display_awaited_by_tasks_table(table): - """Print the table in a simple tabular format.""" - print(_fmt_table_row(*_row_header)) - print('-' * 180) + # Print the table in a simple tabular format + print( + f"{'tid':<10} {'task id':<20} {'task name':<20} {'coroutine stack':<50} {'awaiter chain':<50} {'awaiter name':<15} {'awaiter id':<15}" + ) + print("-" * 180) for row in table: - print(_fmt_table_row(*row)) - - -def _fmt_table_row(tid, task_id, task_name, coro_stack, - awaiter_chain, awaiter_name, awaiter_id): - # Format a single row for the table format - return (f'{tid:<10} {task_id:<20} {task_name:<20} {coro_stack:<50} ' - f'{awaiter_chain:<50} {awaiter_name:<15} {awaiter_id:<15}') - - -def _display_awaited_by_tasks_csv(table, *, format): - """Print the table in CSV format""" - if format == TaskTableOutputFormat.csv: - delimiter = ',' - elif format == TaskTableOutputFormat.bsv: - delimiter = '\N{BANANA}' - else: - raise ValueError(f"Unknown output format: {format}") - csv_writer = csv.writer(sys.stdout, delimiter=delimiter) - csv_writer.writerow(_row_header) - csv_writer.writerows(table) + print(f"{row[0]:<10} {row[1]:<20} {row[2]:<20} {row[3]:<50} {row[4]:<50} {row[5]:<15} {row[6]:<15}") def display_awaited_by_tasks_tree(pid: int) -> None: diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 1c1458127db..49e8067ee7b 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -359,7 +359,7 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop): "os.sendfile() is not available") try: fileno = file.fileno() - except (AttributeError, io.UnsupportedOperation) as err: + except (AttributeError, io.UnsupportedOperation): raise exceptions.SendfileNotAvailableError("not a regular file") try: fsize = os.fstat(fileno).st_size diff --git a/Lib/base64.py b/Lib/base64.py index 5d78cc09f40..341bf8eaf18 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -193,7 +193,7 @@ def _b32encode(alphabet, s): encoded[-3:] = b'===' elif leftover == 4: encoded[-1:] = b'=' - return bytes(encoded) + return encoded.take_bytes() def _b32decode(alphabet, s, casefold=False, map01=None): # Delay the initialization of the table to not waste memory @@ -238,7 +238,7 @@ def _b32decode(alphabet, s, casefold=False, map01=None): last = acc.to_bytes(5) # big endian leftover = (43 - 5 * padchars) // 8 # 1: 4, 3: 3, 4: 2, 6: 1 decoded[-5:] = last[:leftover] - return bytes(decoded) + return decoded.take_bytes() def b32encode(s): @@ -462,9 +462,12 @@ def b85decode(b): # Delay the initialization of tables to not waste memory # if the function is never called if _b85dec is None: - _b85dec = [None] * 256 + # we don't assign to _b85dec directly to avoid issues when + # multiple threads call this function simultaneously + b85dec_tmp = [None] * 256 for i, c in enumerate(_b85alphabet): - _b85dec[c] = i + b85dec_tmp[c] = i + _b85dec = b85dec_tmp b = _bytes_from_decode_data(b) padding = (-len(b)) % 5 @@ -601,7 +604,14 @@ def main(): with open(args[0], 'rb') as f: func(f, sys.stdout.buffer) else: - func(sys.stdin.buffer, sys.stdout.buffer) + if sys.stdin.isatty(): + # gh-138775: read terminal input data all at once to detect EOF + import io + data = sys.stdin.buffer.read() + buffer = io.BytesIO(data) + else: + buffer = sys.stdin.buffer + func(buffer, sys.stdout.buffer) if __name__ == '__main__': diff --git a/Lib/bdb.py b/Lib/bdb.py index efc3e0a235a..50cf2b3f5b3 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -199,6 +199,8 @@ class Bdb: self.frame_returning = None self.trace_opcodes = False self.enterframe = None + self.cmdframe = None + self.cmdlineno = None self.code_linenos = weakref.WeakKeyDictionary() self.backend = backend if backend == 'monitoring': @@ -297,7 +299,12 @@ class Bdb: self.user_line(). Raise BdbQuit if self.quitting is set. Return self.trace_dispatch to continue tracing in this scope. """ - if self.stop_here(frame) or self.break_here(frame): + # GH-136057 + # For line events, we don't want to stop at the same line where + # the latest next/step command was issued. + if (self.stop_here(frame) or self.break_here(frame)) and not ( + self.cmdframe == frame and self.cmdlineno == frame.f_lineno + ): self.user_line(frame) self.restart_events() if self.quitting: raise BdbQuit @@ -526,7 +533,8 @@ class Bdb: if self.monitoring_tracer: self.monitoring_tracer.update_local_events() - def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False): + def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False, + cmdframe=None, cmdlineno=None): """Set the attributes for stopping. If stoplineno is greater than or equal to 0, then stop at line @@ -539,6 +547,10 @@ class Bdb: # stoplineno >= 0 means: stop at line >= the stoplineno # stoplineno -1 means: don't stop at all self.stoplineno = stoplineno + # cmdframe/cmdlineno is the frame/line number when the user issued + # step/next commands. + self.cmdframe = cmdframe + self.cmdlineno = cmdlineno self._set_trace_opcodes(opcode) def _set_caller_tracefunc(self, current_frame): @@ -564,7 +576,9 @@ class Bdb: def set_step(self): """Stop after one line of code.""" - self._set_stopinfo(None, None) + # set_step() could be called from signal handler so enterframe might be None + self._set_stopinfo(None, None, cmdframe=self.enterframe, + cmdlineno=getattr(self.enterframe, 'f_lineno', None)) def set_stepinstr(self): """Stop before the next instruction.""" @@ -572,7 +586,7 @@ class Bdb: def set_next(self, frame): """Stop on the next line in or below the given frame.""" - self._set_stopinfo(frame, None) + self._set_stopinfo(frame, None, cmdframe=frame, cmdlineno=frame.f_lineno) def set_return(self, frame): """Stop when returning from the given frame.""" diff --git a/Lib/cProfile.py b/Lib/cProfile.py index 4af82f2cb8c..cc6255f61ae 100644 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -9,6 +9,5 @@ from profiling.tracing import run, runctx, Profile __all__ = ["run", "runctx", "Profile"] if __name__ == "__main__": - import sys from profiling.tracing.__main__ import main main() diff --git a/Lib/calendar.py b/Lib/calendar.py index 678c7be5aac..d80c3fd9524 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -498,30 +498,29 @@ class HTMLCalendar(Calendar): """ if day == 0: # day outside month - return ' ' % self.cssclass_noday + return f' ' else: - return '%d' % (self.cssclasses[weekday], day) + return f'{day}' def formatweek(self, theweek): """ Return a complete week as a table row. """ s = ''.join(self.formatday(d, wd) for (d, wd) in theweek) - return '%s' % s + return f'{s}' def formatweekday(self, day): """ Return a weekday name as a table header. """ - return '%s' % ( - self.cssclasses_weekday_head[day], day_abbr[day]) + return f'{day_abbr[day]}' def formatweekheader(self): """ Return a header for a week as a table row. """ s = ''.join(self.formatweekday(i) for i in self.iterweekdays()) - return '%s' % s + return f'{s}' def formatmonthname(self, theyear, themonth, withyear=True): """ @@ -529,11 +528,10 @@ class HTMLCalendar(Calendar): """ _validate_month(themonth) if withyear: - s = '%s %s' % (standalone_month_name[themonth], theyear) + s = f'{standalone_month_name[themonth]} {theyear}' else: s = standalone_month_name[themonth] - return '%s' % ( - self.cssclass_month_head, s) + return f'{s}' def formatmonth(self, theyear, themonth, withyear=True): """ @@ -541,8 +539,7 @@ class HTMLCalendar(Calendar): """ v = [] a = v.append - a('' % ( - self.cssclass_month)) + a(f'
    ') a('\n') a(self.formatmonthname(theyear, themonth, withyear=withyear)) a('\n') @@ -562,11 +559,9 @@ class HTMLCalendar(Calendar): v = [] a = v.append width = max(width, 1) - a('
    ' % - self.cssclass_year) + a(f'
    ') a('\n') - a('' % ( - width, self.cssclass_year_head, theyear)) + a(f'') for i in range(JANUARY, JANUARY+12, width): # months in this row months = range(i, min(i+width, 13)) @@ -579,29 +574,48 @@ class HTMLCalendar(Calendar): a('
    %s
    {theyear}
    ') return ''.join(v) - def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None): + def _format_html_page(self, theyear, content, css, encoding): """ - Return a formatted year as a complete HTML page. + Return a complete HTML page with the given content. """ if encoding is None: encoding = 'utf-8' v = [] a = v.append - a('\n' % encoding) - a('\n') - a('\n') + a('\n') + a('\n') a('\n') - a('\n' % encoding) + a(f'\n') + a('\n') + a(f'Calendar for {theyear}\n') + a('\n') if css is not None: - a('\n' % css) - a('Calendar for %d\n' % theyear) + a(f'\n') a('\n') a('\n') - a(self.formatyear(theyear, width)) + a(content) a('\n') a('\n') return ''.join(v).encode(encoding, "xmlcharrefreplace") + def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None): + """ + Return a formatted year as a complete HTML page. + """ + content = self.formatyear(theyear, width) + return self._format_html_page(theyear, content, css, encoding) + + def formatmonthpage(self, theyear, themonth, width=3, css='calendar.css', encoding=None): + """ + Return a formatted month as a complete HTML page. + """ + content = self.formatmonth(theyear, themonth, width) + return self._format_html_page(theyear, content, css, encoding) + class different_locale: def __init__(self, locale): @@ -886,7 +900,7 @@ def main(args=None): parser.add_argument( "month", nargs='?', type=int, - help="month number (1-12, text only)" + help="month number (1-12)" ) options = parser.parse_args(args) @@ -899,9 +913,6 @@ def main(args=None): today = datetime.date.today() if options.type == "html": - if options.month: - parser.error("incorrect number of arguments") - sys.exit(1) if options.locale: cal = LocaleHTMLCalendar(locale=locale) else: @@ -912,10 +923,14 @@ def main(args=None): encoding = 'utf-8' optdict = dict(encoding=encoding, css=options.css) write = sys.stdout.buffer.write + if options.year is None: write(cal.formatyearpage(today.year, **optdict)) else: - write(cal.formatyearpage(options.year, **optdict)) + if options.month: + write(cal.formatmonthpage(options.year, options.month, **optdict)) + else: + write(cal.formatyearpage(options.year, **optdict)) else: if options.locale: cal = _CLIDemoLocaleCalendar(highlight_day=today, locale=locale) diff --git a/Lib/codeop.py b/Lib/codeop.py index 8cac00442d9..40e88423119 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -66,9 +66,9 @@ def _maybe_compile(compiler, source, filename, symbol, flags): try: compiler(source + "\n", filename, symbol, flags=flags) return None - except _IncompleteInputError as e: + except _IncompleteInputError: return None - except SyntaxError as e: + except SyntaxError: pass # fallthrough diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index b8653f40a94..55ffc36ea5b 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -796,6 +796,7 @@ class Counter(dict): # set(cp - cq) == sp - sq # set(cp | cq) == sp | sq # set(cp & cq) == sp & sq + # set(cp ^ cq) == sp ^ sq def __eq__(self, other): 'True if all counts agree. Missing counts are treated as zero.' @@ -908,6 +909,33 @@ class Counter(dict): result[elem] = newcount return result + def __xor__(self, other): + '''Symmetric difference. Absolute value of count differences. + + The symmetric difference p ^ q is equivalent to: + + (p - q) | (q - p). + + For each element, symmetric difference gives the same result as: + + max(p[elem], q[elem]) - min(p[elem], q[elem]) + + >>> Counter(a=5, b=3, c=2, d=2) ^ Counter(a=1, b=3, c=5, e=1) + Counter({'a': 4, 'c': 3, 'd': 2, 'e': 1}) + + ''' + if not isinstance(other, Counter): + return NotImplemented + result = Counter() + for elem, count in self.items(): + newcount = abs(count - other[elem]) + if newcount: + result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count: + result[elem] = abs(count) + return result + def __pos__(self): 'Adds an empty counter, effectively stripping negative and zero counts' result = Counter() @@ -990,6 +1018,22 @@ class Counter(dict): self[elem] = other_count return self._keep_positive() + def __ixor__(self, other): + '''Inplace symmetric difference. Absolute value of count differences. + + >>> c = Counter(a=5, b=3, c=2, d=2) + >>> c ^= Counter(a=1, b=3, c=5, e=1) + >>> c + Counter({'a': 4, 'c': 3, 'd': 2, 'e': 1}) + + ''' + for elem, count in self.items(): + self[elem] = abs(count - other[elem]) + for elem, count in other.items(): + if elem not in self: + self[elem] = abs(count) + return self._keep_positive() + ######################################################################## ### ChainMap @@ -1498,6 +1542,8 @@ class UserString(_collections_abc.Sequence): return self.data.format_map(mapping) def index(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, UserString): + sub = sub.data return self.data.index(sub, start, end) def isalpha(self): @@ -1566,6 +1612,8 @@ class UserString(_collections_abc.Sequence): return self.data.rfind(sub, start, end) def rindex(self, sub, start=0, end=_sys.maxsize): + if isinstance(sub, UserString): + sub = sub.data return self.data.rindex(sub, start, end) def rjust(self, width, *args): diff --git a/Lib/compileall.py b/Lib/compileall.py index 67fe370451e..9519a5ac16f 100644 --- a/Lib/compileall.py +++ b/Lib/compileall.py @@ -223,7 +223,7 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, cfile = importlib.util.cache_from_source(fullname) opt_cfiles[opt_level] = cfile - head, tail = name[:-3], name[-3:] + tail = name[-3:] if tail == '.py': if not force: try: diff --git a/Lib/concurrent/futures/interpreter.py b/Lib/concurrent/futures/interpreter.py index 53c6e757ded..85c1da2c722 100644 --- a/Lib/concurrent/futures/interpreter.py +++ b/Lib/concurrent/futures/interpreter.py @@ -2,7 +2,6 @@ from concurrent import interpreters import sys -import textwrap from . import thread as _thread import traceback diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index a14650bf5fa..a42afa68efc 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -474,9 +474,23 @@ class _ExecutorManagerThread(threading.Thread): bpe = BrokenProcessPool("A process in the process pool was " "terminated abruptly while the future was " "running or pending.") + cause_str = None if cause is not None: - bpe.__cause__ = _RemoteTraceback( - f"\n'''\n{''.join(cause)}'''") + cause_str = ''.join(cause) + else: + # No cause known, so report any processes that have + # terminated with nonzero exit codes, e.g. from a + # segfault. Multiple may terminate simultaneously, + # so include all of them in the traceback. + errors = [] + for p in self.processes.values(): + if p.exitcode is not None and p.exitcode != 0: + errors.append(f"Process {p.pid} terminated abruptly " + f"with exit code {p.exitcode}") + if errors: + cause_str = "\n".join(errors) + if cause_str: + bpe.__cause__ = _RemoteTraceback(f"\n'''\n{cause_str}'''") # Mark pending tasks as failed. for work_id, work_item in self.pending_work_items.items(): diff --git a/Lib/concurrent/interpreters/__init__.py b/Lib/concurrent/interpreters/__init__.py index aa46a2b37a4..ea4147ee9a2 100644 --- a/Lib/concurrent/interpreters/__init__.py +++ b/Lib/concurrent/interpreters/__init__.py @@ -149,12 +149,17 @@ class Interpreter: def __reduce__(self): return (type(self), (self._id,)) - def _decref(self): + # gh-135729: Globals might be destroyed by the time this is called, so we + # need to keep references ourself + def _decref(self, *, + InterpreterNotFoundError=InterpreterNotFoundError, + _interp_decref=_interpreters.decref, + ): if not self._ownsref: return self._ownsref = False try: - _interpreters.decref(self._id) + _interp_decref(self._id) except InterpreterNotFoundError: pass diff --git a/Lib/concurrent/interpreters/_queues.py b/Lib/concurrent/interpreters/_queues.py index 9c12b2c8c24..ee159d7de63 100644 --- a/Lib/concurrent/interpreters/_queues.py +++ b/Lib/concurrent/interpreters/_queues.py @@ -170,13 +170,13 @@ class Queue: def qsize(self): return _queues.get_count(self._id) - def put(self, obj, timeout=None, *, + def put(self, obj, block=True, timeout=None, *, unbounditems=None, _delay=10 / 1000, # 10 milliseconds ): """Add the object to the queue. - This blocks while the queue is full. + If "block" is true, this blocks while the queue is full. For most objects, the object received through Queue.get() will be a new one, equivalent to the original and not sharing any @@ -209,6 +209,8 @@ class Queue: If "unbounditems" is UNBOUND then it is returned by get() in place of the unbound item. """ + if not block: + return self.put_nowait(obj, unbounditems=unbounditems) if unbounditems is None: unboundop = -1 else: @@ -221,7 +223,7 @@ class Queue: while True: try: _queues.put(self._id, obj, unboundop) - except QueueFull as exc: + except QueueFull: if timeout is not None and time.time() >= end: raise # re-raise time.sleep(_delay) @@ -235,17 +237,19 @@ class Queue: unboundop, = _serialize_unbound(unbounditems) _queues.put(self._id, obj, unboundop) - def get(self, timeout=None, *, + def get(self, block=True, timeout=None, *, _delay=10 / 1000, # 10 milliseconds ): """Return the next object from the queue. - This blocks while the queue is empty. + If "block" is true, this blocks while the queue is empty. If the next item's original interpreter has been destroyed then the "next object" is determined by the value of the "unbounditems" argument to put(). """ + if not block: + return self.get_nowait() if timeout is not None: timeout = int(timeout) if timeout < 0: @@ -254,7 +258,7 @@ class Queue: while True: try: obj, unboundop = _queues.get(self._id) - except QueueEmpty as exc: + except QueueEmpty: if timeout is not None and time.time() >= end: raise # re-raise time.sleep(_delay) @@ -273,7 +277,7 @@ class Queue: """ try: obj, unboundop = _queues.get(self._id) - except QueueEmpty as exc: + except QueueEmpty: raise # re-raise if unboundop is not None: assert obj is None, repr(obj) diff --git a/Lib/copy.py b/Lib/copy.py index c64fc076179..fff7e93c2a1 100644 --- a/Lib/copy.py +++ b/Lib/copy.py @@ -100,14 +100,14 @@ def copy(x): return _reconstruct(x, None, *rv) -_copy_atomic_types = {types.NoneType, int, float, bool, complex, str, tuple, +_copy_atomic_types = frozenset({types.NoneType, int, float, bool, complex, str, tuple, bytes, frozenset, type, range, slice, property, types.BuiltinFunctionType, types.EllipsisType, types.NotImplementedType, types.FunctionType, types.CodeType, - weakref.ref, super} -_copy_builtin_containers = {list, dict, set, bytearray} + weakref.ref, super}) +_copy_builtin_containers = frozenset({list, dict, set, bytearray}) -def deepcopy(x, memo=None, _nil=[]): +def deepcopy(x, memo=None): """Deep copy operation on arbitrary Python objects. See the module's __doc__ string for more info. @@ -122,8 +122,8 @@ def deepcopy(x, memo=None, _nil=[]): if memo is None: memo = {} else: - y = memo.get(d, _nil) - if y is not _nil: + y = memo.get(d, None) + if y is not None: return y copier = _deepcopy_dispatch.get(cls) @@ -162,9 +162,9 @@ def deepcopy(x, memo=None, _nil=[]): _keep_alive(x, memo) # Make sure x lives at least as long as d return y -_atomic_types = {types.NoneType, types.EllipsisType, types.NotImplementedType, +_atomic_types = frozenset({types.NoneType, types.EllipsisType, types.NotImplementedType, int, float, bool, complex, bytes, str, types.CodeType, type, range, - types.BuiltinFunctionType, types.FunctionType, weakref.ref, property} + types.BuiltinFunctionType, types.FunctionType, weakref.ref, property}) _deepcopy_dispatch = d = {} diff --git a/Lib/csv.py b/Lib/csv.py index 0a627ba7a51..b2aaf5fd9fa 100644 --- a/Lib/csv.py +++ b/Lib/csv.py @@ -81,8 +81,6 @@ __all__ = ["QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE", "unregister_dialect", "DictReader", "DictWriter", "unix_dialect"] -__version__ = "1.0" - class Dialect: """Describe a CSV dialect. @@ -364,31 +362,33 @@ class Sniffer: try and evaluate the smallest portion of the data possible, evaluating additional chunks as necessary. """ + from collections import Counter, defaultdict data = list(filter(None, data.split('\n'))) - ascii = [chr(c) for c in range(127)] # 7-bit ASCII - # build frequency tables chunkLength = min(10, len(data)) iteration = 0 - charFrequency = {} + num_lines = 0 + # {char -> {count_per_line -> num_lines_with_that_count}} + char_frequency = defaultdict(Counter) modes = {} delims = {} start, end = 0, chunkLength while start < len(data): iteration += 1 for line in data[start:end]: - for char in ascii: - metaFrequency = charFrequency.get(char, {}) - # must count even if frequency is 0 - freq = line.count(char) - # value is the mode - metaFrequency[freq] = metaFrequency.get(freq, 0) + 1 - charFrequency[char] = metaFrequency + num_lines += 1 + for char, count in Counter(line).items(): + if char.isascii(): + char_frequency[char][count] += 1 - for char in charFrequency.keys(): - items = list(charFrequency[char].items()) + for char, counts in char_frequency.items(): + items = list(counts.items()) + missed_lines = num_lines - sum(counts.values()) + if missed_lines: + # Store the number of lines 'char' was missing from. + items.append((0, missed_lines)) if len(items) == 1 and items[0][0] == 0: continue # get the mode of the frequencies @@ -511,3 +511,12 @@ class Sniffer: hasHeader -= 1 return hasHeader > 0 + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.0" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index d6d07a13f75..aec92f3aee2 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -1,14 +1,13 @@ """create and manipulate C data types in Python""" -import os as _os, sys as _sys +import os as _os +import sys as _sys +import sysconfig as _sysconfig import types as _types -__version__ = "1.1.0" - from _ctypes import Union, Structure, Array from _ctypes import _Pointer from _ctypes import CFuncPtr as _CFuncPtr -from _ctypes import __version__ as _ctypes_version from _ctypes import RTLD_LOCAL, RTLD_GLOBAL from _ctypes import ArgumentError from _ctypes import SIZEOF_TIME_T @@ -16,9 +15,6 @@ from _ctypes import CField from struct import calcsize as _calcsize -if __version__ != _ctypes_version: - raise Exception("Version number mismatch", __version__, _ctypes_version) - if _os.name == "nt": from _ctypes import COMError, CopyComPointer, FormatError @@ -108,7 +104,7 @@ def CFUNCTYPE(restype, *argtypes, **kw): return CFunctionType if _os.name == "nt": - from _ctypes import LoadLibrary as _dlopen + from _ctypes import LoadLibrary as _LoadLibrary from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL _win_functype_cache = {} @@ -410,52 +406,59 @@ class CDLL(object): use_errno=False, use_last_error=False, winmode=None): + class _FuncPtr(_CFuncPtr): + _flags_ = self._func_flags_ + _restype_ = self._func_restype_ + if use_errno: + _flags_ |= _FUNCFLAG_USE_ERRNO + if use_last_error: + _flags_ |= _FUNCFLAG_USE_LASTERROR + + self._FuncPtr = _FuncPtr if name: name = _os.fspath(name) + self._handle = self._load_library(name, mode, handle, winmode) + + if _os.name == "nt": + def _load_library(self, name, mode, handle, winmode): + if winmode is None: + import nt as _nt + winmode = _nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS + # WINAPI LoadLibrary searches for a DLL if the given name + # is not fully qualified with an explicit drive. For POSIX + # compatibility, and because the DLL search path no longer + # contains the working directory, begin by fully resolving + # any name that contains a path separator. + if name is not None and ('/' in name or '\\' in name): + name = _nt._getfullpathname(name) + winmode |= _nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR + self._name = name + if handle is not None: + return handle + return _LoadLibrary(self._name, winmode) + + else: + def _load_library(self, name, mode, handle, winmode): # If the filename that has been provided is an iOS/tvOS/watchOS # .fwork file, dereference the location to the true origin of the # binary. - if name.endswith(".fwork"): + if name and name.endswith(".fwork"): with open(name) as f: name = _os.path.join( _os.path.dirname(_sys.executable), f.read().strip() ) - - self._name = name - flags = self._func_flags_ - if use_errno: - flags |= _FUNCFLAG_USE_ERRNO - if use_last_error: - flags |= _FUNCFLAG_USE_LASTERROR - if _sys.platform.startswith("aix"): - """When the name contains ".a(" and ends with ")", - e.g., "libFOO.a(libFOO.so)" - this is taken to be an - archive(member) syntax for dlopen(), and the mode is adjusted. - Otherwise, name is presented to dlopen() as a file argument. - """ - if name and name.endswith(")") and ".a(" in name: - mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW ) - if _os.name == "nt": - if winmode is not None: - mode = winmode - else: - import nt - mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS - if '/' in name or '\\' in name: - self._name = nt._getfullpathname(self._name) - mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR - - class _FuncPtr(_CFuncPtr): - _flags_ = flags - _restype_ = self._func_restype_ - self._FuncPtr = _FuncPtr - - if handle is None: - self._handle = _dlopen(self._name, mode) - else: - self._handle = handle + if _sys.platform.startswith("aix"): + """When the name contains ".a(" and ends with ")", + e.g., "libFOO.a(libFOO.so)" - this is taken to be an + archive(member) syntax for dlopen(), and the mode is adjusted. + Otherwise, name is presented to dlopen() as a file argument. + """ + if name and name.endswith(")") and ".a(" in name: + mode |= _os.RTLD_MEMBER | _os.RTLD_NOW + self._name = name + return _dlopen(name, mode) def __repr__(self): return "<%s '%s', handle %x at %#x>" % \ @@ -543,10 +546,9 @@ pydll = LibraryLoader(PyDLL) if _os.name == "nt": pythonapi = PyDLL("python dll", None, _sys.dllhandle) -elif _sys.platform == "android": - pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2]) -elif _sys.platform == "cygwin": - pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2]) +elif _sys.platform in ["android", "cygwin"]: + # These are Unix-like platforms which use a dynamically-linked libpython. + pythonapi = PyDLL(_sysconfig.get_config_var("LDLIBRARY")) else: pythonapi = PyDLL(None) @@ -665,3 +667,12 @@ else: raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}") _reset_cache() + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.1.0" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/ctypes/macholib/__init__.py b/Lib/ctypes/macholib/__init__.py index 5621defccd6..f00e55f8131 100644 --- a/Lib/ctypes/macholib/__init__.py +++ b/Lib/ctypes/macholib/__init__.py @@ -6,4 +6,10 @@ See the relevant header files in /usr/include/mach-o And also Apple's documentation. """ -__version__ = '1.0' +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.0" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 99504911a3d..378f12167c6 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -173,6 +173,25 @@ elif sys.platform == "android": fname = f"{directory}/lib{name}.so" return fname if os.path.isfile(fname) else None +elif sys.platform == "emscripten": + def _is_wasm(filename): + # Return True if the given file is an WASM module + wasm_header = b"\x00asm" + with open(filename, 'br') as thefile: + return thefile.read(4) == wasm_header + + def find_library(name): + candidates = [f"lib{name}.so", f"lib{name}.wasm"] + paths = os.environ.get("LD_LIBRARY_PATH", "") + for libdir in paths.split(":"): + for name in candidates: + libfile = os.path.join(libdir, name) + + if os.path.isfile(libfile) and _is_wasm(libfile): + return libfile + + return None + elif os.name == "posix": # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump import re, tempfile diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index b98f21dcbe9..730ced72998 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -441,9 +441,11 @@ class _FuncBuilder: self.locals = {} self.overwrite_errors = {} self.unconditional_adds = {} + self.method_annotations = {} def add_fn(self, name, args, body, *, locals=None, return_type=MISSING, - overwrite_error=False, unconditional_add=False, decorator=None): + overwrite_error=False, unconditional_add=False, decorator=None, + annotation_fields=None): if locals is not None: self.locals.update(locals) @@ -464,16 +466,14 @@ class _FuncBuilder: self.names.append(name) - if return_type is not MISSING: - self.locals[f'__dataclass_{name}_return_type__'] = return_type - return_annotation = f'->__dataclass_{name}_return_type__' - else: - return_annotation = '' + if annotation_fields is not None: + self.method_annotations[name] = (annotation_fields, return_type) + args = ','.join(args) body = '\n'.join(body) # Compute the text of the entire function, add it to the text we're generating. - self.src.append(f'{f' {decorator}\n' if decorator else ''} def {name}({args}){return_annotation}:\n{body}') + self.src.append(f'{f' {decorator}\n' if decorator else ''} def {name}({args}):\n{body}') def add_fns_to_class(self, cls): # The source to all of the functions we're generating. @@ -509,6 +509,15 @@ class _FuncBuilder: # Now that we've generated the functions, assign them into cls. for name, fn in zip(self.names, fns): fn.__qualname__ = f"{cls.__qualname__}.{fn.__name__}" + + try: + annotation_fields, return_type = self.method_annotations[name] + except KeyError: + pass + else: + annotate_fn = _make_annotate_function(cls, name, annotation_fields, return_type) + fn.__annotate__ = annotate_fn + if self.unconditional_adds.get(name, False): setattr(cls, name, fn) else: @@ -524,6 +533,49 @@ class _FuncBuilder: raise TypeError(error_msg) +def _make_annotate_function(__class__, method_name, annotation_fields, return_type): + # Create an __annotate__ function for a dataclass + # Try to return annotations in the same format as they would be + # from a regular __init__ function + + def __annotate__(format, /): + Format = annotationlib.Format + match format: + case Format.VALUE | Format.FORWARDREF | Format.STRING: + cls_annotations = {} + for base in reversed(__class__.__mro__): + cls_annotations.update( + annotationlib.get_annotations(base, format=format) + ) + + new_annotations = {} + for k in annotation_fields: + # gh-142214: The annotation may be missing in unusual dynamic cases. + # If so, just skip it. + try: + new_annotations[k] = cls_annotations[k] + except KeyError: + pass + + if return_type is not MISSING: + if format == Format.STRING: + new_annotations["return"] = annotationlib.type_repr(return_type) + else: + new_annotations["return"] = return_type + + return new_annotations + + case _: + raise NotImplementedError(format) + + # This is a flag for _add_slots to know it needs to regenerate this method + # In order to remove references to the original class when it is replaced + __annotate__.__generated_by_dataclasses__ = True + __annotate__.__qualname__ = f"{__class__.__qualname__}.{method_name}.__annotate__" + + return __annotate__ + + def _field_assign(frozen, name, value, self_name): # If we're a frozen class, then assign to our fields in __init__ # via object.__setattr__. Otherwise, just use a simple @@ -612,7 +664,7 @@ def _init_param(f): elif f.default_factory is not MISSING: # There's a factory function. Set a marker. default = '=__dataclass_HAS_DEFAULT_FACTORY__' - return f'{f.name}:__dataclass_type_{f.name}__{default}' + return f'{f.name}{default}' def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, @@ -635,11 +687,10 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, raise TypeError(f'non-default argument {f.name!r} ' f'follows default argument {seen_default.name!r}') - locals = {**{f'__dataclass_type_{f.name}__': f.type for f in fields}, - **{'__dataclass_HAS_DEFAULT_FACTORY__': _HAS_DEFAULT_FACTORY, - '__dataclass_builtins_object__': object, - } - } + annotation_fields = [f.name for f in fields if f.init] + + locals = {'__dataclass_HAS_DEFAULT_FACTORY__': _HAS_DEFAULT_FACTORY, + '__dataclass_builtins_object__': object} body_lines = [] for f in fields: @@ -670,7 +721,8 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, [self_name] + _init_params, body_lines, locals=locals, - return_type=None) + return_type=None, + annotation_fields=annotation_fields) def _frozen_get_del_attr(cls, fields, func_builder): @@ -1337,6 +1389,26 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields): or _update_func_cell_for__class__(member.fdel, cls, newcls)): break + # Get new annotations to remove references to the original class + # in forward references + newcls_ann = annotationlib.get_annotations( + newcls, format=annotationlib.Format.FORWARDREF) + + # Fix references in dataclass Fields + for f in getattr(newcls, _FIELDS).values(): + try: + ann = newcls_ann[f.name] + except KeyError: + pass + else: + f.type = ann + + # Fix the class reference in the __annotate__ method + init = newcls.__init__ + if init_annotate := getattr(init, "__annotate__", None): + if getattr(init_annotate, "__generated_by_dataclasses__", False): + _update_func_cell_for__class__(init_annotate, cls, newcls) + return newcls diff --git a/Lib/decimal.py b/Lib/decimal.py index 530bdfb3895..cf13050bfef 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -100,8 +100,8 @@ NaN try: from _decimal import * - from _decimal import __version__ # noqa: F401 from _decimal import __libmpdec_version__ # noqa: F401 + from _decimal import __getattr__ # noqa: F401 except ImportError: import _pydecimal import sys diff --git a/Lib/difflib.py b/Lib/difflib.py index fedc85009aa..4a0600e4ebb 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1924,8 +1924,11 @@ class HtmlDiff(object): # make space non-breakable so they don't get compressed or line wrapped text = text.replace(' ',' ').rstrip() - return '%s%s' \ - % (id,linenum,text) + # add a class to the td tag if there is a difference on the line + css_class = ' class="diff_changed" ' if flag else ' ' + + return f'{linenum}' \ + + f'{text}' def _make_prefix(self): """Create unique anchor prefixes""" diff --git a/Lib/dis.py b/Lib/dis.py index d6d2c1386dd..8c257d118fb 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -530,7 +530,6 @@ class Formatter: fields.append(instr.opname.ljust(_OPNAME_WIDTH)) # Column: Opcode argument if instr.arg is not None: - arg = repr(instr.arg) # If opname is longer than _OPNAME_WIDTH, we allow it to overflow into # the space reserved for oparg. This results in fewer misaligned opargs # in the disassembly output. diff --git a/Lib/doctest.py b/Lib/doctest.py index 92a2ab4f7e6..0fcfa1e3e97 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -104,7 +104,7 @@ import sys import traceback import types import unittest -from io import StringIO, IncrementalNewlineDecoder +from io import StringIO, TextIOWrapper, BytesIO from collections import namedtuple import _colorize # Used in doctests from _colorize import ANSIColors, can_colorize @@ -237,10 +237,6 @@ def _normalize_module(module, depth=2): else: raise TypeError("Expected a module, string, or None") -def _newline_convert(data): - # The IO module provides a handy decoder for universal newline conversion - return IncrementalNewlineDecoder(None, True).decode(data, True) - def _load_testfile(filename, package, module_relative, encoding): if module_relative: package = _normalize_module(package, 3) @@ -252,10 +248,9 @@ def _load_testfile(filename, package, module_relative, encoding): pass if hasattr(loader, 'get_data'): file_contents = loader.get_data(filename) - file_contents = file_contents.decode(encoding) # get_data() opens files as 'rb', so one must do the equivalent # conversion as universal newlines would do. - return _newline_convert(file_contents), filename + return TextIOWrapper(BytesIO(file_contents), encoding=encoding, newline=None).read(), filename with open(filename, encoding=encoding) as f: return f.read(), filename @@ -1172,6 +1167,32 @@ class DocTestFinder: if pat.match(source_lines[lineno]): return lineno + # Handle __test__ string doctests formatted as triple-quoted + # strings. Find a non-blank line in the test string and match it + # in the source, verifying subsequent lines also match to handle + # duplicate lines. + if isinstance(obj, str) and source_lines is not None: + obj_lines = obj.splitlines(keepends=True) + # Skip the first line (may be on same line as opening quotes) + # and any blank lines to find a meaningful line to match. + start_index = 1 + while (start_index < len(obj_lines) + and not obj_lines[start_index].strip()): + start_index += 1 + if start_index < len(obj_lines): + target_line = obj_lines[start_index] + for lineno, source_line in enumerate(source_lines): + if source_line == target_line: + # Verify subsequent lines also match + for i in range(start_index + 1, len(obj_lines) - 1): + source_idx = lineno + i - start_index + if source_idx >= len(source_lines): + break + if obj_lines[i] != source_lines[source_idx]: + break + else: + return lineno - start_index + # We couldn't find the line number. return None diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 91243378dc0..46fef2048ba 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -796,6 +796,10 @@ class MimeParameters(TokenList): value = urllib.parse.unquote(value, encoding='latin-1') else: try: + # Explicitly look up the codec for warning generation, see gh-140030 + # Can be removed in 3.17 + import codecs + codecs.lookup(charset) value = value.decode(charset, 'surrogateescape') except (LookupError, UnicodeEncodeError): # XXX: there should really be a custom defect for @@ -874,6 +878,12 @@ class MessageID(MsgID): class InvalidMessageID(MessageID): token_type = 'invalid-message-id' +class MessageIDList(TokenList): + token_type = 'message-id-list' + + @property + def message_ids(self): + return [x for x in self if x.token_type=='msg-id'] class Header(TokenList): token_type = 'header' @@ -2171,6 +2181,32 @@ def parse_message_id(value): return message_id +def parse_message_ids(value): + """in-reply-to = "In-Reply-To:" 1*msg-id CRLF + references = "References:" 1*msg-id CRLF + """ + message_id_list = MessageIDList() + while value: + if value[0] == ',': + # message id list separated with commas - this is invalid, + # but happens rather frequently in the wild + message_id_list.defects.append( + errors.InvalidHeaderDefect("comma in msg-id list")) + message_id_list.append( + WhiteSpaceTerminal(' ', 'invalid-comma-replacement')) + value = value[1:] + continue + try: + token, value = get_msg_id(value) + message_id_list.append(token) + except errors.HeaderParseError as ex: + token = get_unstructured(value) + message_id_list.append(InvalidMessageID(token)) + message_id_list.defects.append( + errors.InvalidHeaderDefect("Invalid msg-id: {!r}".format(ex))) + break + return message_id_list + # # XXX: As I begin to add additional header parsers, I'm realizing we probably # have two level of parser routines: the get_XXX methods that get a token in @@ -2788,6 +2824,9 @@ def _steal_trailing_WSP_if_exists(lines): if lines and lines[-1] and lines[-1][-1] in WSP: wsp = lines[-1][-1] lines[-1] = lines[-1][:-1] + # gh-142006: if the line is now empty, remove it entirely. + if not lines[-1]: + lines.pop() return wsp def _refold_parse_tree(parse_tree, *, policy): diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py index 84917038874..6a7c5fa06d2 100644 --- a/Lib/email/_parseaddr.py +++ b/Lib/email/_parseaddr.py @@ -146,8 +146,9 @@ def _parsedate_tz(data): return None # Check for a yy specified in two-digit format, then convert it to the # appropriate four-digit format, according to the POSIX standard. RFC 822 - # calls for a two-digit yy, but RFC 2822 (which obsoletes RFC 822) - # mandates a 4-digit yy. For more information, see the documentation for + # calls for a two-digit yy, but RFC 2822 (which obsoletes RFC 822) already + # mandated a 4-digit yy, and RFC 5322 (which obsoletes RFC 2822) continues + # this requirement. For more information, see the documentation for # the time module. if yy < 100: # The year is between 1969 and 1999 (inclusive). @@ -233,9 +234,11 @@ class AddrlistClass: self.CR = '\r\n' self.FWS = self.LWS + self.CR self.atomends = self.specials + self.LWS + self.CR - # Note that RFC 2822 now specifies '.' as obs-phrase, meaning that it - # is obsolete syntax. RFC 2822 requires that we recognize obsolete - # syntax, so allow dots in phrases. + # Note that RFC 2822 section 4.1 introduced '.' as obs-phrase to handle + # existing practice (periods in display names), even though it was not + # allowed in RFC 822. RFC 5322 section 4.1 (which obsoletes RFC 2822) + # continues this requirement. We must recognize obsolete syntax, so + # allow dots in phrases. self.phraseends = self.atomends.replace('.', '') self.field = field self.commentlist = [] diff --git a/Lib/email/_policybase.py b/Lib/email/_policybase.py index 95e79b8938b..e23843df448 100644 --- a/Lib/email/_policybase.py +++ b/Lib/email/_policybase.py @@ -380,7 +380,7 @@ class Compat32(Policy): h = value if h is not None: # The Header class interprets a value of None for maxlinelen as the - # default value of 78, as recommended by RFC 2822. + # default value of 78, as recommended by RFC 5322 section 2.1.1. maxlinelen = 0 if self.max_line_length is not None: maxlinelen = self.max_line_length diff --git a/Lib/email/contentmanager.py b/Lib/email/contentmanager.py index b4f5830bead..11d1536db27 100644 --- a/Lib/email/contentmanager.py +++ b/Lib/email/contentmanager.py @@ -2,6 +2,7 @@ import binascii import email.charset import email.message import email.errors +import sys from email import quoprimime class ContentManager: @@ -142,13 +143,15 @@ def _encode_base64(data, max_line_length): def _encode_text(string, charset, cte, policy): + # If max_line_length is 0 or None, there is no limit. + maxlen = policy.max_line_length or sys.maxsize lines = string.encode(charset).splitlines() linesep = policy.linesep.encode('ascii') def embedded_body(lines): return linesep.join(lines) + linesep def normal_body(lines): return b'\n'.join(lines) + b'\n' if cte is None: # Use heuristics to decide on the "best" encoding. - if max((len(x) for x in lines), default=0) <= policy.max_line_length: + if max(map(len, lines), default=0) <= maxlen: try: return '7bit', normal_body(lines).decode('ascii') except UnicodeDecodeError: @@ -156,8 +159,7 @@ def _encode_text(string, charset, cte, policy): if policy.cte_type == '8bit': return '8bit', normal_body(lines).decode('ascii', 'surrogateescape') sniff = embedded_body(lines[:10]) - sniff_qp = quoprimime.body_encode(sniff.decode('latin-1'), - policy.max_line_length) + sniff_qp = quoprimime.body_encode(sniff.decode('latin-1'), maxlen) sniff_base64 = binascii.b2a_base64(sniff) # This is a little unfair to qp; it includes lineseps, base64 doesn't. if len(sniff_qp) > len(sniff_base64): @@ -172,9 +174,9 @@ def _encode_text(string, charset, cte, policy): data = normal_body(lines).decode('ascii', 'surrogateescape') elif cte == 'quoted-printable': data = quoprimime.body_encode(normal_body(lines).decode('latin-1'), - policy.max_line_length) + maxlen) elif cte == 'base64': - data = _encode_base64(embedded_body(lines), policy.max_line_length) + data = _encode_base64(embedded_body(lines), maxlen) else: raise ValueError("Unknown content transfer encoding {}".format(cte)) return cte, data diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index 9d80a5822af..ae8ef32792b 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -32,7 +32,7 @@ NLCRE = re.compile(r'\r\n|\r|\n') NLCRE_bol = re.compile(r'(\r\n|\r|\n)') NLCRE_eol = re.compile(r'(\r\n|\r|\n)\z') NLCRE_crack = re.compile(r'(\r\n|\r|\n)') -# RFC 2822 $3.6.8 Optional fields. ftext is %d33-57 / %d59-126, Any character +# RFC 5322 section 3.6.8 Optional fields. ftext is %d33-57 / %d59-126, Any character # except controls, SP, and ":". headerRE = re.compile(r'^(From |[\041-\071\073-\176]*:|[\t ])') EMPTYSTRING = '' @@ -294,7 +294,7 @@ class FeedParser: return if self._cur.get_content_maintype() == 'message': # The message claims to be a message/* type, then what follows is - # another RFC 2822 message. + # another RFC 5322 message. for retval in self._parsegen(): if retval is NeedMoreData: yield NeedMoreData @@ -504,10 +504,9 @@ class FeedParser: self._input.unreadline(line) return else: - # Weirdly placed unix-from line. Note this as a defect - # and ignore it. + # Weirdly placed unix-from line. defect = errors.MisplacedEnvelopeHeaderDefect(line) - self._cur.defects.append(defect) + self.policy.handle_defect(self._cur, defect) continue # Split the line on the colon separating field name from value. # There will always be a colon, because if there wasn't the part of @@ -519,7 +518,7 @@ class FeedParser: # message. Track the error but keep going. if i == 0: defect = errors.InvalidHeaderDefect("Missing header name.") - self._cur.defects.append(defect) + self.policy.handle_defect(self._cur, defect) continue assert i>0, "_parse_headers fed line with no : and no leading WS" diff --git a/Lib/email/generator.py b/Lib/email/generator.py index ab5bd0653e4..03524c96559 100644 --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -50,7 +50,7 @@ class Generator: expanded to 8 spaces) than maxheaderlen, the header will split as defined in the Header class. Set maxheaderlen to zero to disable header wrapping. The default is 78, as recommended (but not required) - by RFC 2822. + by RFC 5322 section 2.1.1. The policy keyword specifies a policy object that controls a number of aspects of the generator's operation. If no policy is specified, diff --git a/Lib/email/headerregistry.py b/Lib/email/headerregistry.py index 543141dc427..0e8698efc0b 100644 --- a/Lib/email/headerregistry.py +++ b/Lib/email/headerregistry.py @@ -534,6 +534,18 @@ class MessageIDHeader: kwds['defects'].extend(parse_tree.all_defects) +class ReferencesHeader: + + max_count = 1 + value_parser = staticmethod(parser.parse_message_ids) + + @classmethod + def parse(cls, value, kwds): + kwds['parse_tree'] = parse_tree = cls.value_parser(value) + kwds['decoded'] = str(parse_tree) + kwds['defects'].extend(parse_tree.all_defects) + + # The header factory # _default_header_map = { @@ -557,6 +569,8 @@ _default_header_map = { 'content-disposition': ContentDispositionHeader, 'content-transfer-encoding': ContentTransferEncodingHeader, 'message-id': MessageIDHeader, + 'in-reply-to': ReferencesHeader, + 'references': ReferencesHeader, } class HeaderRegistry: diff --git a/Lib/email/message.py b/Lib/email/message.py index 36e4b4a9f0b..641fb2e944d 100644 --- a/Lib/email/message.py +++ b/Lib/email/message.py @@ -74,19 +74,25 @@ def _parseparam(s): # RDM This might be a Header, so for now stringify it. s = ';' + str(s) plist = [] - while s[:1] == ';': - s = s[1:] - end = s.find(';') - while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: - end = s.find(';', end + 1) + start = 0 + while s.find(';', start) == start: + start += 1 + end = s.find(';', start) + ind, diff = start, 0 + while end > 0: + diff += s.count('"', ind, end) - s.count('\\"', ind, end) + if diff % 2 == 0: + break + end, ind = ind, s.find(';', end + 1) if end < 0: end = len(s) - f = s[:end] - if '=' in f: - i = f.index('=') - f = f[:i].strip().lower() + '=' + f[i+1:].strip() + i = s.find('=', start, end) + if i == -1: + f = s[start:end] + else: + f = s[start:i].rstrip().lower() + '=' + s[i+1:end].lstrip() plist.append(f.strip()) - s = s[end:] + start = end return plist @@ -135,7 +141,7 @@ def _decode_uu(encoded): class Message: """Basic message object. - A message object is defined as something that has a bunch of RFC 2822 + A message object is defined as something that has a bunch of RFC 5322 headers and a payload. It may optionally have an envelope header (a.k.a. Unix-From or From_ header). If the message is a container (i.e. a multipart or a message/rfc822), then the payload is a list of Message diff --git a/Lib/email/parser.py b/Lib/email/parser.py index 039f03cba74..c6a51dd8e37 100644 --- a/Lib/email/parser.py +++ b/Lib/email/parser.py @@ -2,7 +2,7 @@ # Author: Barry Warsaw, Thomas Wouters, Anthony Baxter # Contact: email-sig@python.org -"""A parser of RFC 2822 and MIME email messages.""" +"""A parser of RFC 5322 and MIME email messages.""" __all__ = ['Parser', 'HeaderParser', 'BytesParser', 'BytesHeaderParser', 'FeedParser', 'BytesFeedParser'] @@ -15,13 +15,13 @@ from email._policybase import compat32 class Parser: def __init__(self, _class=None, *, policy=compat32): - """Parser of RFC 2822 and MIME email messages. + """Parser of RFC 5322 and MIME email messages. Creates an in-memory object tree representing the email message, which can then be manipulated and turned over to a Generator to return the textual representation of the message. - The string must be formatted as a block of RFC 2822 headers and header + The string must be formatted as a block of RFC 5322 headers and header continuation lines, optionally preceded by a 'Unix-from' header. The header block is terminated either by the end of the string or by a blank line. @@ -75,13 +75,13 @@ class HeaderParser(Parser): class BytesParser: def __init__(self, *args, **kw): - """Parser of binary RFC 2822 and MIME email messages. + """Parser of binary RFC 5322 and MIME email messages. Creates an in-memory object tree representing the email message, which can then be manipulated and turned over to a Generator to return the textual representation of the message. - The input must be formatted as a block of RFC 2822 headers and header + The input must be formatted as a block of RFC 5322 headers and header continuation lines, optionally preceded by a 'Unix-from' header. The header block is terminated either by the end of the input or by a blank line. diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 3de1f0d24a1..d4824dc3601 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -460,6 +460,10 @@ def collapse_rfc2231_value(value, errors='replace', charset = fallback_charset rawbytes = bytes(text, 'raw-unicode-escape') try: + # Explicitly look up the codec for warning generation, see gh-140030 + # Can be removed in 3.17 + import codecs + codecs.lookup(charset) return str(rawbytes, charset, errors) except LookupError: # charset is not a known codec. diff --git a/Lib/encodings/__init__.py b/Lib/encodings/__init__.py index 298177eb800..e205ec32637 100644 --- a/Lib/encodings/__init__.py +++ b/Lib/encodings/__init__.py @@ -26,10 +26,11 @@ Written by Marc-Andre Lemburg (mal@lemburg.com). (c) Copyright CNRI, All Rights Reserved. NO WARRANTY. -"""#" +""" import codecs import sys +from _codecs import _normalize_encoding from . import aliases _cache = {} @@ -55,18 +56,13 @@ def normalize_encoding(encoding): if isinstance(encoding, bytes): encoding = str(encoding, "ascii") - chars = [] - punct = False - for c in encoding: - if c.isalnum() or c == '.': - if punct and chars: - chars.append('_') - if c.isascii(): - chars.append(c) - punct = False - else: - punct = True - return ''.join(chars) + if not encoding.isascii(): + import warnings + warnings.warn( + "Support for non-ascii encoding names will be removed in 3.17", + DeprecationWarning, stacklevel=2) + + return _normalize_encoding(encoding) def search_function(encoding): diff --git a/Lib/encodings/aliases.py b/Lib/encodings/aliases.py index 4ecb6b6e297..f4b1b8dd43f 100644 --- a/Lib/encodings/aliases.py +++ b/Lib/encodings/aliases.py @@ -17,7 +17,7 @@ """ aliases = { - # Please keep this list sorted alphabetically by value ! + # Please keep this list sorted alphabetically by value! # ascii codec '646' : 'ascii', @@ -318,6 +318,7 @@ aliases = { 'iso_ir_157' : 'iso8859_10', 'l6' : 'iso8859_10', 'latin6' : 'iso8859_10', + 'latin_6' : 'iso8859_10', # iso8859_11 codec 'thai' : 'iso8859_11', @@ -328,6 +329,7 @@ aliases = { 'iso_8859_13' : 'iso8859_13', 'l7' : 'iso8859_13', 'latin7' : 'iso8859_13', + 'latin_7' : 'iso8859_13', # iso8859_14 codec 'iso_8859_14' : 'iso8859_14', @@ -336,11 +338,13 @@ aliases = { 'iso_ir_199' : 'iso8859_14', 'l8' : 'iso8859_14', 'latin8' : 'iso8859_14', + 'latin_8' : 'iso8859_14', # iso8859_15 codec 'iso_8859_15' : 'iso8859_15', 'l9' : 'iso8859_15', 'latin9' : 'iso8859_15', + 'latin_9' : 'iso8859_15', # iso8859_16 codec 'iso_8859_16' : 'iso8859_16', @@ -348,6 +352,7 @@ aliases = { 'iso_ir_226' : 'iso8859_16', 'l10' : 'iso8859_16', 'latin10' : 'iso8859_16', + 'latin_10' : 'iso8859_16', # iso8859_2 codec 'csisolatin2' : 'iso8859_2', @@ -356,6 +361,7 @@ aliases = { 'iso_ir_101' : 'iso8859_2', 'l2' : 'iso8859_2', 'latin2' : 'iso8859_2', + 'latin_2' : 'iso8859_2', # iso8859_3 codec 'csisolatin3' : 'iso8859_3', @@ -364,6 +370,7 @@ aliases = { 'iso_ir_109' : 'iso8859_3', 'l3' : 'iso8859_3', 'latin3' : 'iso8859_3', + 'latin_3' : 'iso8859_3', # iso8859_4 codec 'csisolatin4' : 'iso8859_4', @@ -372,6 +379,7 @@ aliases = { 'iso_ir_110' : 'iso8859_4', 'l4' : 'iso8859_4', 'latin4' : 'iso8859_4', + 'latin_4' : 'iso8859_4', # iso8859_5 codec 'csisolatincyrillic' : 'iso8859_5', @@ -415,6 +423,7 @@ aliases = { 'iso_ir_148' : 'iso8859_9', 'l5' : 'iso8859_9', 'latin5' : 'iso8859_9', + 'latin_5' : 'iso8859_9', # johab codec 'cp1361' : 'johab', @@ -545,6 +554,9 @@ aliases = { 'utf8_ucs4' : 'utf_8', 'cp65001' : 'utf_8', + # utf_8_sig codec + 'utf8_sig' : 'utf_8_sig', + # uu_codec codec 'uu' : 'uu_codec', diff --git a/Lib/encodings/idna.py b/Lib/encodings/idna.py index 0c90b4c9fe1..d31ee07ab45 100644 --- a/Lib/encodings/idna.py +++ b/Lib/encodings/idna.py @@ -226,7 +226,8 @@ class Codec(codecs.Codec): offset + exc.end, exc.reason, ) - return bytes(result+trailing_dot), len(input) + result += trailing_dot + return result.take_bytes(), len(input) def decode(self, input, errors='strict'): @@ -311,7 +312,7 @@ class IncrementalEncoder(codecs.BufferedIncrementalEncoder): result += trailing_dot size += len(trailing_dot) - return (bytes(result), size) + return (result.take_bytes(), size) class IncrementalDecoder(codecs.BufferedIncrementalDecoder): def _buffer_decode(self, input, errors, final): diff --git a/Lib/encodings/punycode.py b/Lib/encodings/punycode.py index 4622fc8c920..268fccbd539 100644 --- a/Lib/encodings/punycode.py +++ b/Lib/encodings/punycode.py @@ -17,7 +17,7 @@ def segregate(str): else: extended.add(c) extended = sorted(extended) - return bytes(base), extended + return base.take_bytes(), extended def selective_len(str, max): """Return the length of str, considering only characters below max.""" @@ -83,7 +83,7 @@ def generate_generalized_integer(N, bias): t = T(j, bias) if N < t: result.append(digits[N]) - return bytes(result) + return result.take_bytes() result.append(digits[t + ((N - t) % (36 - t))]) N = (N - t) // (36 - t) j += 1 @@ -112,7 +112,7 @@ def generate_integers(baselen, deltas): s = generate_generalized_integer(delta, bias) result.extend(s) bias = adapt(delta, points==0, baselen+points+1) - return bytes(result) + return result.take_bytes() def punycode_encode(text): base, extended = segregate(text) diff --git a/Lib/encodings/uu_codec.py b/Lib/encodings/uu_codec.py index 4e58c62fe9e..4f8704016e2 100644 --- a/Lib/encodings/uu_codec.py +++ b/Lib/encodings/uu_codec.py @@ -56,7 +56,7 @@ def uu_decode(input, errors='strict'): break try: data = binascii.a2b_uu(s) - except binascii.Error as v: + except binascii.Error: # Workaround for broken uuencoders by /Fredrik Lundh nbytes = (((s[0]-32) & 63) * 4 + 5) // 3 data = binascii.a2b_uu(s[:nbytes]) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 4bd85990e86..f9f905f46ff 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ from shutil import copy2 __all__ = ["version", "bootstrap"] -_PIP_VERSION = "25.2" +_PIP_VERSION = "25.3" # Directory of system wheel packages. Some Linux distribution packaging # policies recommend against bundling dependencies. For example, Fedora @@ -130,6 +130,15 @@ def _bootstrap(*, root=None, upgrade=False, user=False, Note that calling this function will alter both sys.path and os.environ. """ + + try: + import zlib + except ImportError: + raise ModuleNotFoundError( + "ensurepip requires the standard library module 'zlib' " + "to install pip." + ) from None + if altinstall and default_pip: raise ValueError("Cannot use altinstall and default_pip together") diff --git a/Lib/ensurepip/_bundled/pip-25.2-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-25.3-py3-none-any.whl similarity index 79% rename from Lib/ensurepip/_bundled/pip-25.2-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-25.3-py3-none-any.whl index e14bb3f37c0..755e1aa0c3d 100644 Binary files a/Lib/ensurepip/_bundled/pip-25.2-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-25.3-py3-none-any.whl differ diff --git a/Lib/enum.py b/Lib/enum.py index c00ae85d2f8..15dddf6de69 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -10,14 +10,15 @@ __all__ = [ 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP', 'global_flag_repr', 'global_enum_repr', 'global_str', 'global_enum', 'EnumCheck', 'CONTINUOUS', 'NAMED_FLAGS', 'UNIQUE', - 'pickle_by_global_name', 'pickle_by_enum_name', + 'pickle_by_global_name', 'pickle_by_enum_name', 'show_flag_values', + 'bin', ] # Dummy value for Enum and Flag as there are explicit checks for them # before they have been created. # This is also why there are checks in EnumType like `if Enum is not None` -Enum = Flag = EJECT = _stdlib_enums = ReprEnum = None +Enum = Flag = EJECT = ReprEnum = None class nonmember(object): """ @@ -773,12 +774,16 @@ class EnumType(type): super().__delattr__(attr) def __dir__(cls): + if issubclass(cls, Flag): + members = list(cls._member_map_.keys()) + else: + members = cls._member_names_ interesting = set([ '__class__', '__contains__', '__doc__', '__getitem__', '__iter__', '__len__', '__members__', '__module__', '__name__', '__qualname__', ] - + cls._member_names_ + + members ) if cls._new_member_ is not object.__new__: interesting.add('__new__') @@ -2189,5 +2194,3 @@ def _old_convert_(etype, name, module, filter, source=None, *, boundary=None): members.sort(key=lambda t: t[0]) cls = etype(name, members, module=module, boundary=boundary or KEEP) return cls - -_stdlib_enums = IntEnum, StrEnum, IntFlag diff --git a/Lib/ftplib.py b/Lib/ftplib.py index 50771e8c17c..640acc64f62 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -314,9 +314,9 @@ class FTP: port = sock.getsockname()[1] # Get proper port host = self.sock.getsockname()[0] # Get proper host if self.af == socket.AF_INET: - resp = self.sendport(host, port) + self.sendport(host, port) else: - resp = self.sendeprt(host, port) + self.sendeprt(host, port) if self.timeout is not _GLOBAL_DEFAULT_TIMEOUT: sock.settimeout(self.timeout) return sock @@ -455,7 +455,7 @@ class FTP: """ if callback is None: callback = print_line - resp = self.sendcmd('TYPE A') + self.sendcmd('TYPE A') with self.transfercmd(cmd) as conn, \ conn.makefile('r', encoding=self.encoding) as fp: while 1: @@ -951,7 +951,7 @@ def test(): elif file[:2] == '-d': cmd = 'CWD' if file[2:]: cmd = cmd + ' ' + file[2:] - resp = ftp.sendcmd(cmd) + ftp.sendcmd(cmd) elif file == '-p': ftp.set_pasv(not ftp.passiveserver) else: diff --git a/Lib/functools.py b/Lib/functools.py index a92844ba722..836eb680ccd 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -687,7 +687,7 @@ def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo): # still adjusting the links. root = oldroot[NEXT] oldkey = root[KEY] - oldresult = root[RESULT] + oldresult = root[RESULT] # noqa: F841 root[KEY] = root[RESULT] = None # Now update the cache dictionary. @@ -1083,7 +1083,10 @@ class _singledispatchmethod_get: 'singledispatchmethod method') raise TypeError(f'{funcname} requires at least ' '1 positional argument') - return self._dispatch(args[0].__class__).__get__(self._obj, self._cls)(*args, **kwargs) + method = self._dispatch(args[0].__class__) + if hasattr(method, "__get__"): + method = method.__get__(self._obj, self._cls) + return method(*args, **kwargs) def __getattr__(self, name): # Resolve these attributes lazily to speed up creation of diff --git a/Lib/getpass.py b/Lib/getpass.py index 1dd40e25e09..3d9bb1f0d14 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -33,8 +33,8 @@ def unix_getpass(prompt='Password: ', stream=None, *, echo_char=None): prompt: Written on stream to ask for the input. Default: 'Password: ' stream: A writable file object to display the prompt. Defaults to the tty. If no tty is available defaults to sys.stderr. - echo_char: A string used to mask input (e.g., '*'). If None, input is - hidden. + echo_char: A single ASCII character to mask input (e.g., '*'). + If None, input is hidden. Returns: The seKr3t input. Raises: @@ -144,10 +144,19 @@ def fallback_getpass(prompt='Password: ', stream=None, *, echo_char=None): def _check_echo_char(echo_char): - # ASCII excluding control characters - if echo_char and not (echo_char.isprintable() and echo_char.isascii()): - raise ValueError("'echo_char' must be a printable ASCII string, " - f"got: {echo_char!r}") + # Single-character ASCII excluding control characters + if echo_char is None: + return + if not isinstance(echo_char, str): + raise TypeError("'echo_char' must be a str or None, not " + f"{type(echo_char).__name__}") + if not ( + len(echo_char) == 1 + and echo_char.isprintable() + and echo_char.isascii() + ): + raise ValueError("'echo_char' must be a single printable ASCII " + f"character, got: {echo_char!r}") def _raw_input(prompt="", stream=None, input=None, echo_char=None): diff --git a/Lib/glob.py b/Lib/glob.py index 5d42077003a..c2f8ce279ab 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -22,6 +22,9 @@ def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, dot are special cases that are not matched by '*' and '?' patterns by default. + The order of the returned list is undefined. Sort it if you need a + particular order. + If `include_hidden` is true, the patterns '*', '?', '**' will match hidden directories. @@ -40,6 +43,9 @@ def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False, dot are special cases that are not matched by '*' and '?' patterns. + The order of the returned paths is undefined. Sort them if you need a + particular order. + If recursive is true, the pattern '**' will match any files and zero or more directories and subdirectories. """ diff --git a/Lib/heapq.py b/Lib/heapq.py index 17f62dd2d58..f944376bcd2 100644 --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -494,7 +494,7 @@ def nsmallest(n, iterable, key=None): pass else: if n >= size: - return sorted(iterable, key=key)[:n] + return sorted(iterable, key=key) # When key is none, use simpler decoration if key is None: @@ -554,7 +554,7 @@ def nlargest(n, iterable, key=None): pass else: if n >= size: - return sorted(iterable, key=key, reverse=True)[:n] + return sorted(iterable, key=key, reverse=True) # When key is none, use simpler decoration if key is None: diff --git a/Lib/hmac.py b/Lib/hmac.py index 9d3fae8b1b1..e0c040bcd5f 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -171,6 +171,7 @@ class HMAC: # Call __new__ directly to avoid the expensive __init__. other = self.__class__.__new__(self.__class__) other.digest_size = self.digest_size + other.block_size = self.block_size if self._hmac: other._hmac = self._hmac.copy() other._inner = other._outer = None diff --git a/Lib/html/parser.py b/Lib/html/parser.py index 5d7050dad23..80fb8c3f929 100644 --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -24,6 +24,7 @@ incomplete = re.compile('&[a-zA-Z#]') entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]') charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]') +incomplete_charref = re.compile('&#(?:[0-9]|[xX][0-9a-fA-F])') attr_charref = re.compile(r'&(#[0-9]+|#[xX][0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*)[;=]?') starttagopen = re.compile('<[a-zA-Z]') @@ -127,17 +128,25 @@ class HTMLParser(_markupbase.ParserBase): argument. """ - CDATA_CONTENT_ELEMENTS = ("script", "style") + # See the HTML5 specs section "13.4 Parsing HTML fragments". + # https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-fragments + # CDATA_CONTENT_ELEMENTS are parsed in RAWTEXT mode + CDATA_CONTENT_ELEMENTS = ("script", "style", "xmp", "iframe", "noembed", "noframes") RCDATA_CONTENT_ELEMENTS = ("textarea", "title") - def __init__(self, *, convert_charrefs=True): + def __init__(self, *, convert_charrefs=True, scripting=False): """Initialize and reset this instance. - If convert_charrefs is True (the default), all character references + If convert_charrefs is true (the default), all character references are automatically converted to the corresponding Unicode characters. + + If *scripting* is false (the default), the content of the + ``noscript`` element is parsed normally; if it's true, + it's returned as is without being parsed. """ super().__init__() self.convert_charrefs = convert_charrefs + self.scripting = scripting self.reset() def reset(self): @@ -172,7 +181,9 @@ class HTMLParser(_markupbase.ParserBase): def set_cdata_mode(self, elem, *, escapable=False): self.cdata_elem = elem.lower() self._escapable = escapable - if escapable and not self.convert_charrefs: + if self.cdata_elem == 'plaintext': + self.interesting = re.compile(r'\z') + elif escapable and not self.convert_charrefs: self.interesting = re.compile(r'&|])' % self.cdata_elem, re.IGNORECASE|re.ASCII) else: @@ -294,10 +305,20 @@ class HTMLParser(_markupbase.ParserBase): k = k - 1 i = self.updatepos(i, k) continue + match = incomplete_charref.match(rawdata, i) + if match: + if end: + self.handle_charref(rawdata[i+2:]) + i = self.updatepos(i, n) + break + # incomplete + break + elif i + 3 < n: # larger than "&#x" + # not the end of the buffer, and can't be confused + # with some other construct + self.handle_data("&#") + i = self.updatepos(i, i + 2) else: - if ";" in rawdata[i:]: # bail by consuming &# - self.handle_data(rawdata[i:i+2]) - i = self.updatepos(i, i+2) break elif startswith('&', i): match = entityref.match(rawdata, i) @@ -311,15 +332,13 @@ class HTMLParser(_markupbase.ParserBase): continue match = incomplete.match(rawdata, i) if match: - # match.group() will contain at least 2 chars - if end and match.group() == rawdata[i:]: - k = match.end() - if k <= i: - k = n - i = self.updatepos(i, i + 1) + if end: + self.handle_entityref(rawdata[i+1:]) + i = self.updatepos(i, n) + break # incomplete break - elif (i + 1) < n: + elif i + 1 < n: # not the end of the buffer, and can't be confused # with some other construct self.handle_data("&") @@ -444,8 +463,10 @@ class HTMLParser(_markupbase.ParserBase): self.handle_startendtag(tag, attrs) else: self.handle_starttag(tag, attrs) - if tag in self.CDATA_CONTENT_ELEMENTS: - self.set_cdata_mode(tag) + if (tag in self.CDATA_CONTENT_ELEMENTS or + (self.scripting and tag == "noscript") or + tag == "plaintext"): + self.set_cdata_mode(tag, escapable=False) elif tag in self.RCDATA_CONTENT_ELEMENTS: self.set_cdata_mode(tag, escapable=True) return endpos diff --git a/Lib/http/client.py b/Lib/http/client.py index 0cce49cadc0..73c3256734a 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -111,6 +111,11 @@ responses = {v: v.phrase for v in http.HTTPStatus.__members__.values()} _MAXLINE = 65536 _MAXHEADERS = 100 +# Data larger than this will be read in chunks, to prevent extreme +# overallocation. +_MIN_READ_BUF_SIZE = 1 << 20 + + # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) # # VCHAR = %x21-7E @@ -231,7 +236,7 @@ def _read_headers(fp, max_headers): def _parse_header_lines(header_lines, _class=HTTPMessage): """ - Parses only RFC2822 headers from header lines. + Parses only RFC 5322 headers from header lines. email Parser wants to see strings rather than bytes. But a TextIOWrapper around self.rfile would buffer too many bytes @@ -244,7 +249,7 @@ def _parse_header_lines(header_lines, _class=HTTPMessage): return email.parser.Parser(_class=_class).parsestr(hstring) def parse_headers(fp, _class=HTTPMessage, *, _max_headers=None): - """Parses only RFC2822 headers from a file pointer.""" + """Parses only RFC 5322 headers from a file pointer.""" headers = _read_headers(fp, _max_headers) return _parse_header_lines(headers, _class) @@ -642,10 +647,25 @@ class HTTPResponse(io.BufferedIOBase): reading. If the bytes are truly not available (due to EOF), then the IncompleteRead exception can be used to detect the problem. """ - data = self.fp.read(amt) - if len(data) < amt: - raise IncompleteRead(data, amt-len(data)) - return data + cursize = min(amt, _MIN_READ_BUF_SIZE) + data = self.fp.read(cursize) + if len(data) >= amt: + return data + if len(data) < cursize: + raise IncompleteRead(data, amt - len(data)) + + data = io.BytesIO(data) + data.seek(0, 2) + while True: + # This is a geometric increase in read size (never more than + # doubling out the current length of data per loop iteration). + delta = min(cursize, amt - cursize) + data.write(self.fp.read(delta)) + if data.tell() >= amt: + return data.getvalue() + cursize += delta + if data.tell() < cursize: + raise IncompleteRead(data.getvalue(), amt - data.tell()) def _safe_readinto(self, b): """Same as _safe_read, but for reading into a buffer.""" @@ -1391,8 +1411,7 @@ class HTTPConnection: """Get the response from the server. If the HTTPConnection is in the correct state, returns an - instance of HTTPResponse or of whatever object is returned by - the response_class variable. + instance of HTTPResponse. If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP diff --git a/Lib/http/server.py b/Lib/http/server.py index a2ffbe2e44d..9c9cfbce421 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -61,8 +61,6 @@ XXX To do: # (Actually, the latter is only true if you know the server configuration # at the time the request was made!) -__version__ = "0.6" - __all__ = [ "HTTPServer", "ThreadingHTTPServer", "HTTPSServer", "ThreadingHTTPSServer", @@ -280,7 +278,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): # The server software version. You may want to override this. # The format is multiple whitespace-separated strings, # where each string is of the form name[/version]. - server_version = "BaseHTTP/" + __version__ + server_version = "BaseHTTP" error_message_format = DEFAULT_ERROR_MESSAGE error_content_type = DEFAULT_ERROR_CONTENT_TYPE @@ -302,6 +300,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): error response has already been sent back. """ + is_http_0_9 = False self.command = None # set in case of error on the first line self.request_version = version = self.default_request_version self.close_connection = True @@ -359,6 +358,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): HTTPStatus.BAD_REQUEST, "Bad HTTP/0.9 request type (%r)" % command) return False + is_http_0_9 = True self.command, self.path = command, path # gh-87389: The purpose of replacing '//' with '/' is to protect @@ -368,6 +368,11 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): if self.path.startswith('//'): self.path = '/' + self.path.lstrip('/') # Reduce to a single / + # For HTTP/0.9, headers are not expected at all. + if is_http_0_9: + self.headers = {} + return True + # Examine the headers and look for a Connection directive. try: self.headers = http.client.parse_headers(self.rfile, @@ -683,7 +688,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): """ - server_version = "SimpleHTTP/" + __version__ + server_version = "SimpleHTTP" index_pages = ("index.html", "index.htm") extensions_map = _encodings_map_default = { '.gz': 'application/gzip', @@ -1073,5 +1078,14 @@ def _main(args=None): ) +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "0.6" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + if __name__ == '__main__': _main() diff --git a/Lib/idlelib/CREDITS.txt b/Lib/idlelib/CREDITS.txt index bea3ba7c20d..1b853e8cc1c 100644 --- a/Lib/idlelib/CREDITS.txt +++ b/Lib/idlelib/CREDITS.txt @@ -37,6 +37,7 @@ Major contributors since 2005: - 2014: Saimadhav Heblikar - 2015: Mark Roseman - 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka +- 2025: Stan Ulbrych For additional details refer to NEWS.txt and Changelog. diff --git a/Lib/idlelib/Icons/idle_256.png b/Lib/idlelib/Icons/idle_256.png index 64f276b40d2..84ffdfddc6f 100644 Binary files a/Lib/idlelib/Icons/idle_256.png and b/Lib/idlelib/Icons/idle_256.png differ diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index 30784578cc6..53d83762f99 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,6 +4,9 @@ Released on 2025-10-07 ========================= +gh-129873: Simplify displaying the IDLE doc by only copying the text +section of idle.html to idlelib/help.html. Patch by Stan Ulbrych. + gh-112936: IDLE - Include Shell menu in single-process mode, though with Restart Shell and View Last Restart disabled. Patch by Zhikang Yan. @@ -26,9 +29,6 @@ Released on 2024-10-07 gh-120104: Fix padding in config and search dialog windows in IDLE. -gh-129873: Simplify displaying the IDLE doc by only copying the text -section of idle.html to idlelib/help.html. Patch by Stan Ulbrych. - gh-120083: Add explicit black IDLE Hovertip foreground color needed for recent macOS. Fixes Sonoma showing unreadable white on pale yellow. Patch by John Riggles. diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index b4df353012b..bffa2ddd3cd 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -47,7 +47,7 @@ def make_pat(): name not in keyword.kwlist] builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b" comment = any("COMMENT", [r"#[^\n]*"]) - stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb)?" + stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb|t|rt|tr)?" sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?" dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?' sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" diff --git a/Lib/idlelib/config-main.def b/Lib/idlelib/config-main.def index 28ae94161d5..54bdce34af3 100644 --- a/Lib/idlelib/config-main.def +++ b/Lib/idlelib/config-main.def @@ -34,9 +34,8 @@ # relevant settings from the default file. # # Additional help sources are listed in the [HelpFiles] section below -# and should be viewable by a web browser (or the Windows Help viewer in -# the case of .chm files). These sources will be listed on the Help -# menu. The pattern, and two examples, are: +# and should be viewable by a web browser. These sources will be listed +# on the Help menu. The pattern, and two examples, are: # # # 1 = IDLE;C:/Programs/Python36/Lib/idlelib/help.html diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 17b498f63ba..3128934763a 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -29,25 +29,12 @@ from idlelib import search from idlelib.tree import wheel_event from idlelib.util import py_extensions from idlelib import window +from idlelib.help import _get_dochome # The default tab setting for a Text widget, in average-width characters. TK_TABWIDTH_DEFAULT = 8 -_py_version = ' (%s)' % platform.python_version() darwin = sys.platform == 'darwin' -def _sphinx_version(): - "Format sys.version_info to produce the Sphinx version string used to install the chm docs" - major, minor, micro, level, serial = sys.version_info - # TODO remove unneeded function since .chm no longer installed - release = f'{major}{minor}' - release += f'{micro}' - if level == 'candidate': - release += f'rc{serial}' - elif level != 'final': - release += f'{level[0]}{serial}' - return release - - class EditorWindow: from idlelib.percolator import Percolator from idlelib.colorizer import ColorDelegator, color_config @@ -76,44 +63,7 @@ class EditorWindow: from idlelib.runscript import ScriptBinding if EditorWindow.help_url is None: - dochome = os.path.join(sys.base_prefix, 'Doc', 'index.html') - if sys.platform.count('linux'): - # look for html docs in a couple of standard places - pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3] - if os.path.isdir('/var/www/html/python/'): # "python2" rpm - dochome = '/var/www/html/python/index.html' - else: - basepath = '/usr/share/doc/' # standard location - dochome = os.path.join(basepath, pyver, - 'Doc', 'index.html') - elif sys.platform[:3] == 'win': - import winreg # Windows only, block only executed once. - docfile = '' - KEY = (rf"Software\Python\PythonCore\{sys.winver}" - r"\Help\Main Python Documentation") - try: - docfile = winreg.QueryValue(winreg.HKEY_CURRENT_USER, KEY) - except FileNotFoundError: - try: - docfile = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, - KEY) - except FileNotFoundError: - pass - if os.path.isfile(docfile): - dochome = docfile - elif sys.platform == 'darwin': - # documentation may be stored inside a python framework - dochome = os.path.join(sys.base_prefix, - 'Resources/English.lproj/Documentation/index.html') - dochome = os.path.normpath(dochome) - if os.path.isfile(dochome): - EditorWindow.help_url = dochome - if sys.platform == 'darwin': - # Safari requires real file:-URLs - EditorWindow.help_url = 'file://' + EditorWindow.help_url - else: - EditorWindow.help_url = ("https://docs.python.org/%d.%d/" - % sys.version_info[:2]) + EditorWindow.help_url = _get_dochome() self.flist = flist root = root or flist.root self.root = root @@ -1044,12 +994,16 @@ class EditorWindow: def saved_change_hook(self): short = self.short_title() long = self.long_title() + _py_version = ' (%s)' % platform.python_version() if short and long and not macosx.isCocoaTk(): # Don't use both values on macOS because # that doesn't match platform conventions. title = short + " - " + long + _py_version elif short: - title = short + if short == "IDLE Shell": + title = short + " " + platform.python_version() + else: + title = short + _py_version elif long: title = long else: diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index ebff9a309d9..fc618ab727d 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -53,7 +53,7 @@ and after the window title. If there is no associated file, do Save As instead.

    Save As…

    Save the current window with a Save As dialog. The file saved becomes the -new associated file for the window. (If your file namager is set to hide +new associated file for the window. (If your file manager is set to hide extensions, the current extension will be omitted in the file name box. If the new filename has no ‘.’, ‘.py’ and ‘.txt’ will be added for Python and text files, except that on macOS Aqua,’.py’ is added for all files.)

    @@ -143,8 +143,8 @@ paragraph will be formatted to less than N columns, where N defaults to 72.

    New Indent Width

    Open a dialog to change indent width. The accepted default by the Python community is 4 spaces.

    -
    Strip Trailing Chitespace

    Remove trailing space and other whitespace characters after the last -non-whitespace character of a line by applying str.rstrip to each line, +

    Strip Trailing Whitespace

    Remove trailing space and other whitespace characters after the last +non-whitespace character of a line by applying str.rstrip() to each line, including lines within multiline strings. Except for Shell windows, remove extra newlines at the end of the file.

    @@ -337,16 +337,16 @@ Unix and the Command key on assume that the keys have not been re-bound to something else.)

    • Arrow keys move the cursor one character or line.

    • -
    • C-LeftArrow and C-RightArrow moves left or right one word.

    • +
    • C-LeftArrow and C-RightArrow moves left or right one word.

    • Home and End go to the beginning or end of the line.

    • Page Up and Page Down go up or down one screen.

    • -
    • C-Home and C-End go to beginning or end of the file.

    • -
    • Backspace and Del (or C-d) delete the previous +

    • C-Home and C-End go to beginning or end of the file.

    • +
    • Backspace and Del (or C-d) delete the previous or next character.

    • -
    • C-Backspace and C-Del delete one word left or right.

    • -
    • C-k deletes (‘kills’) everything to the right.

    • +
    • C-Backspace and C-Del delete one word left or right.

    • +
    • C-k deletes (‘kills’) everything to the right.

    -

    Standard keybindings (like C-c to copy and C-v to paste) +

    Standard keybindings (like C-c to copy and C-v to paste) may work. Keybindings are selected in the Configure IDLE dialog.

    @@ -390,7 +390,7 @@ one can specify a drive first.) Move into subdirectories by typing a directory name and a separator.

    Instead of waiting, or after a box is closed, open a completion box immediately with Show Completions on the Edit menu. The default hot -key is C-space. If one types a prefix for the desired name +key is C-space. If one types a prefix for the desired name before opening the box, the first match or near miss is made visible. The result is the same as if one enters a prefix after the box is displayed. Show Completions after a quote completes @@ -473,9 +473,9 @@ in an editor window.

    The editing features described in previous subsections work when entering code interactively. IDLE’s Shell window also responds to the following:

      -
    • C-c attempts to interrupt statement execution (but may fail).

    • -
    • C-d closes Shell if typed at a >>> prompt.

    • -
    • Alt-p and Alt-n (C-p and C-n on macOS) +

    • C-c attempts to interrupt statement execution (but may fail).

    • +
    • C-d closes Shell if typed at a >>> prompt.

    • +
    • Alt-p and Alt-n (C-p and C-n on macOS) retrieve to the current prompt the previous or next previously entered statement that matches anything already typed.

    • Return while the cursor is on any previous statement @@ -517,27 +517,73 @@ executed in the Tk namespace, so this file is not useful for importing functions to be used from IDLE’s Python shell.

      Command line usage

      -
      idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
      -
      --c command  run command in the shell window
      --d          enable debugger and open shell window
      --e          open editor window
      --h          print help message with legal combinations and exit
      --i          open shell window
      --r file     run file in shell window
      --s          run $IDLESTARTUP or $PYTHONSTARTUP first, in shell window
      --t title    set title of shell window
      --           run stdin in shell (- must be last option before args)
      +

      IDLE can be invoked from the command line with various options. The general syntax is:

      +
      python -m idlelib [options] [file ...]
       
      -

      If there are arguments:

      +

      The following options are available:

      +
      +
      +-c <command>
      +

      Run the specified Python command in the shell window. +For example, pass -c "print('Hello, World!')". +On Windows, the outer quotes must be double quotes as shown.

      +
      + +
      +
      +-d
      +

      Enable the debugger and open the shell window.

      +
      + +
      +
      +-e
      +

      Open an editor window.

      +
      + +
      +
      +-h
      +

      Print a help message with legal combinations of options and exit.

      +
      + +
      +
      +-i
      +

      Open a shell window.

      +
      + +
      +
      +-r <file>
      +

      Run the specified file in the shell window.

      +
      + +
      +
      +-s
      +

      Run the startup file (as defined by the environment variables IDLESTARTUP or PYTHONSTARTUP) before opening the shell window.

      +
      + +
      +
      +-t <title>
      +

      Set the title of the shell window.

      +
      + +
      +
      +-
      +

      Read and execute standard input in the shell window. This option must be the last one before any arguments.

      +
      + +

      If arguments are provided:

        -
      • If -, -c, or r is used, all arguments are placed in -sys.argv[1:...] and sys.argv[0] is set to '', '-c', -or '-r'. No editor window is opened, even if that is the default -set in the Options dialog.

      • -
      • Otherwise, arguments are files opened for editing and -sys.argv reflects the arguments passed to IDLE itself.

      • +
      • If -, -c, or -r is used, all arguments are placed in sys.argv[1:], +and sys.argv[0] is set to '', '-c', or '-r' respectively. +No editor window is opened, even if that is the default set in the Options dialog.

      • +
      • Otherwise, arguments are treated as files to be opened for editing, and sys.argv reflects the arguments passed to IDLE itself.

      @@ -798,7 +844,7 @@ of this page for how to use IDLE.

      either in idlelib or click Help => About IDLE on the IDLE menu. This file also maps IDLE menu items to the code that implements the item. Except for files listed under ‘Startup’, the idlelib code is ‘private’ in -sense that feature changes can be backported (see PEP 434).

      +sense that feature changes can be backported (see PEP 434).

    diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py index 063a749df54..48e7eca280e 100644 --- a/Lib/idlelib/help.py +++ b/Lib/idlelib/help.py @@ -23,7 +23,12 @@ HelpWindow - Display HelpFrame in a standalone window. copy_strip - Copy the text part of idle.html to help.html while rstripping each line. show_idlehelp - Create HelpWindow. Called in EditorWindow.help_dialog. + +_get_dochome() - Return path to docs on user's system if present, +otherwise return link to docs.python.org. """ +import os +import sys from html.parser import HTMLParser from os.path import abspath, dirname, isfile, join from platform import python_version @@ -289,6 +294,47 @@ def show_idlehelp(parent): return HelpWindow(parent, filename, 'IDLE Doc (%s)' % python_version()) +def _get_dochome(): + "Return path to local docs if present, otherwise link to docs.python.org." + + dochome = os.path.join(sys.base_prefix, 'Doc', 'index.html') + if sys.platform.count('linux'): + # look for html docs in a couple of standard places + pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3] + if os.path.isdir('/var/www/html/python/'): # rpm package manager + dochome = '/var/www/html/python/index.html' + else: + basepath = '/usr/share/doc/' # dnf/apt package managers + dochome = os.path.join(basepath, pyver, 'Doc', 'index.html') + + elif sys.platform[:3] == 'win': + import winreg # Windows only, block only executed once. + docfile = '' + KEY = (rf"Software\Python\PythonCore\{sys.winver}" + r"\Help\Main Python Documentation") + try: + docfile = winreg.QueryValue(winreg.HKEY_CURRENT_USER, KEY) + except FileNotFoundError: + try: + docfile = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, KEY) + except FileNotFoundError: + pass + if os.path.isfile(docfile): + dochome = docfile + elif sys.platform == 'darwin': + # documentation may be stored inside a python framework + dochome = os.path.join(sys.base_prefix, + 'Resources/English.lproj/Documentation/index.html') + dochome = os.path.normpath(dochome) + if os.path.isfile(dochome): + if sys.platform == 'darwin': + # Safari requires real file:-URLs + return 'file://' + dochome + return dochome + else: + return "https://docs.python.org/%d.%d/" % sys.version_info[:2] + + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_help', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py index 79b5d102dd7..8eed2699c41 100644 --- a/Lib/idlelib/idle_test/__init__.py +++ b/Lib/idlelib/idle_test/__init__.py @@ -20,8 +20,4 @@ def load_tests(loader, standard_tests, pattern): pattern='test_*.py', # Insert here. top_level_dir=top_dir) standard_tests.addTests(module_tests) -## module_tests = loader.discover(start_dir=this_dir, -## pattern='test_*.py', # Insert here. -## top_level_dir=top_dir) -## standard_tests.addTests(module_tests) return standard_tests diff --git a/Lib/idlelib/idle_test/test_colorizer.py b/Lib/idlelib/idle_test/test_colorizer.py index 308bc389384..40800df97b0 100644 --- a/Lib/idlelib/idle_test/test_colorizer.py +++ b/Lib/idlelib/idle_test/test_colorizer.py @@ -36,6 +36,7 @@ source = textwrap.dedent("""\ # All valid prefixes for unicode and byte strings should be colored. r'x', u'x', R'x', U'x', f'x', F'x' fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x' + tr'x', Tr'x', tR'x', TR'x', rt'x', rT'x', Rt'x', RT'x' b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x', rB'x',Rb'x',RB'x' # Invalid combinations of legal characters should be half colored. ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x' @@ -390,19 +391,19 @@ class ColorDelegatorTest(unittest.TestCase): ('6.0', ('KEYWORD',)), ('6.10', ('DEFINITION',)), ('6.11', ()), ('8.0', ('STRING',)), ('8.4', ()), ('8.5', ('STRING',)), ('8.12', ()), ('8.14', ('STRING',)), - ('19.0', ('KEYWORD',)), - ('20.4', ('KEYWORD',)), ('20.16', ('KEYWORD',)),# ('20.19', ('KEYWORD',)), - #('22.4', ('KEYWORD',)), ('22.10', ('KEYWORD',)), ('22.14', ('KEYWORD',)), ('22.19', ('STRING',)), - #('23.12', ('KEYWORD',)), - ('24.8', ('KEYWORD',)), - ('25.4', ('KEYWORD',)), ('25.9', ('KEYWORD',)), - ('25.11', ('KEYWORD',)), ('25.15', ('STRING',)), - ('25.19', ('KEYWORD',)), ('25.22', ()), - ('25.24', ('KEYWORD',)), ('25.29', ('BUILTIN',)), ('25.37', ('KEYWORD',)), - ('26.4', ('KEYWORD',)), ('26.9', ('KEYWORD',)),# ('26.11', ('KEYWORD',)), ('26.14', (),), - ('27.25', ('STRING',)), ('27.38', ('STRING',)), - ('29.0', ('STRING',)), - ('30.1', ('STRING',)), + ('20.0', ('KEYWORD',)), + ('21.4', ('KEYWORD',)), ('21.16', ('KEYWORD',)),# ('21.19', ('KEYWORD',)), + #('23.4', ('KEYWORD',)), ('23.10', ('KEYWORD',)), ('23.14', ('KEYWORD',)), ('23.19', ('STRING',)), + #('24.12', ('KEYWORD',)), + ('25.8', ('KEYWORD',)), + ('26.4', ('KEYWORD',)), ('26.9', ('KEYWORD',)), + ('26.11', ('KEYWORD',)), ('26.15', ('STRING',)), + ('26.19', ('KEYWORD',)), ('26.22', ()), + ('26.24', ('KEYWORD',)), ('26.29', ('BUILTIN',)), ('26.37', ('KEYWORD',)), + ('27.4', ('KEYWORD',)), ('27.9', ('KEYWORD',)),# ('27.11', ('KEYWORD',)), ('27.14', (),), + ('28.25', ('STRING',)), ('28.38', ('STRING',)), + ('30.0', ('STRING',)), + ('31.1', ('STRING',)), # SYNC at the end of every line. ('1.55', ('SYNC',)), ('2.50', ('SYNC',)), ('3.34', ('SYNC',)), ) @@ -433,7 +434,7 @@ class ColorDelegatorTest(unittest.TestCase): eq(text.tag_nextrange('STRING', '8.12'), ('8.14', '8.17')) eq(text.tag_nextrange('STRING', '8.17'), ('8.19', '8.26')) eq(text.tag_nextrange('SYNC', '8.0'), ('8.26', '9.0')) - eq(text.tag_nextrange('SYNC', '30.0'), ('30.10', '32.0')) + eq(text.tag_nextrange('SYNC', '31.0'), ('31.10', '33.0')) def _assert_highlighting(self, source, tag_ranges): """Check highlighting of a given piece of code. diff --git a/Lib/idlelib/idle_test/test_outwin.py b/Lib/idlelib/idle_test/test_outwin.py index 81f4aad7e95..0f13363f84f 100644 --- a/Lib/idlelib/idle_test/test_outwin.py +++ b/Lib/idlelib/idle_test/test_outwin.py @@ -1,6 +1,7 @@ "Test outwin, coverage 76%." from idlelib import outwin +import platform import sys import unittest from test.support import requires @@ -41,7 +42,7 @@ class OutputWindowTest(unittest.TestCase): self.assertFalse(w.ispythonsource(__file__)) def test_window_title(self): - self.assertEqual(self.window.top.title(), 'Output') + self.assertEqual(self.window.top.title(), 'Output' + ' (%s)' % platform.python_version()) def test_maybesave(self): w = self.window diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 74a0e03994f..b80c8e56c92 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -22,7 +22,6 @@ import itertools import linecache import os import os.path -from platform import python_version import re import socket import subprocess @@ -499,7 +498,6 @@ class ModifiedInterpreter(InteractiveInterpreter): self.rpcclt.close() self.terminate_subprocess() console = self.tkconsole - was_executing = console.executing console.executing = False self.spawn_subprocess() try: @@ -841,7 +839,7 @@ class ModifiedInterpreter(InteractiveInterpreter): class PyShell(OutputWindow): from idlelib.squeezer import Squeezer - shell_title = "IDLE Shell " + python_version() + shell_title = "IDLE Shell" # Override classes ColorDelegator = ModifiedColorDelegator diff --git a/Lib/idlelib/query.py b/Lib/idlelib/query.py index 57230e2aaca..5f9bdc031e5 100644 --- a/Lib/idlelib/query.py +++ b/Lib/idlelib/query.py @@ -289,8 +289,6 @@ class HelpSource(Query): def browse_file(self): filetypes = [ ("HTML Files", "*.htm *.html", "TEXT"), - ("PDF Files", "*.pdf", "TEXT"), - ("Windows Help Files", "*.chm"), ("Text Files", "*.txt", "TEXT"), ("All Files", "*")] path = self.pathvar.get() diff --git a/Lib/idlelib/textview.py b/Lib/idlelib/textview.py index 23f0f4cb502..0f719a06883 100644 --- a/Lib/idlelib/textview.py +++ b/Lib/idlelib/textview.py @@ -129,8 +129,8 @@ class ViewWindow(Toplevel): self.title(title) self.viewframe = ViewFrame(self, contents, wrap=wrap) self.protocol("WM_DELETE_WINDOW", self.ok) - self.button_ok = button_ok = Button(self, text='Close', - command=self.ok, takefocus=False) + self.button_ok = Button(self, text='Close', + command=self.ok, takefocus=False) self.viewframe.pack(side='top', expand=True, fill='both') self.is_modal = modal diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 362d6a2dcf2..22a0afcd981 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -21,8 +21,6 @@ Public functions: Internaldate2tuple # GET/SETANNOTATION contributed by Tomas Lindroos June 2005. # IDLE contributed by Forest August 2024. -__version__ = "2.60" - import binascii, errno, random, re, socket, subprocess, sys, time, calendar from datetime import datetime, timezone, timedelta from io import DEFAULT_BUFFER_SIZE @@ -247,7 +245,6 @@ class IMAP4: self._cmd_log_idx = 0 self._cmd_log = {} # Last '_cmd_log_len' interactions if self.debug >= 1: - self._mesg('imaplib version %s' % __version__) self._mesg('new IMAP4 connection, tag=%s' % self.tagpre) self.welcome = self._get_response() @@ -497,8 +494,6 @@ class IMAP4: else: date_time = None literal = MapCRLF.sub(CRLF, message) - if self.utf8_enabled: - literal = b'UTF8 (' + literal + b')' self.literal = literal return self._simple_command(name, mailbox, flags, date_time) @@ -813,7 +808,7 @@ class IMAP4: """ name = 'PROXYAUTH' - return self._simple_command('PROXYAUTH', user) + return self._simple_command(name, user) def rename(self, oldmailbox, newmailbox): @@ -1119,7 +1114,11 @@ class IMAP4: literator = literal else: literator = None - data = data + bytes(' {%s}' % len(literal), self._encoding) + if self.utf8_enabled: + data = data + bytes(' UTF8 (~{%s}' % len(literal), self._encoding) + literal = literal + b')' + else: + data = data + bytes(' {%s}' % len(literal), self._encoding) if __debug__: if self.debug >= 4: @@ -1311,7 +1310,7 @@ class IMAP4: try: self._get_response() - except self.abort as val: + except self.abort: if __debug__: if self.debug >= 1: self.print_log() @@ -1868,7 +1867,7 @@ if __name__ == '__main__': try: optlist, args = getopt.getopt(sys.argv[1:], 'd:s:') - except getopt.error as val: + except getopt.error: optlist, args = (), () stream_command = None @@ -1963,3 +1962,12 @@ try: %s -d5 ''' % sys.argv[0]) raise + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "2.60" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index a7d57561ead..694fea806f7 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -97,6 +97,11 @@ def reload(module): The module must have been successfully imported before. """ + # If a LazyModule has not yet been materialized, reload is a no-op. + if importlib_util := sys.modules.get('importlib.util'): + if lazy_module_type := getattr(importlib_util, '_LazyModule', None): + if isinstance(module, lazy_module_type): + return module try: name = module.__spec__.name except AttributeError: diff --git a/Lib/importlib/_abc.py b/Lib/importlib/_abc.py index 693b4661126..2598036dac4 100644 --- a/Lib/importlib/_abc.py +++ b/Lib/importlib/_abc.py @@ -19,21 +19,3 @@ class Loader(metaclass=abc.ABCMeta): # We don't define exec_module() here since that would break # hasattr checks we do to support backward compatibility. - - def load_module(self, fullname): - """Return the loaded module. - - The module must be added to sys.modules and have import-related - attributes set properly. The fullname is a str. - - ImportError is raised on failure. - - This method is deprecated in favor of loader.exec_module(). If - exec_module() exists then it is used to provide a backwards-compatible - functionality for this method. - - """ - if not hasattr(self, 'exec_module'): - raise ImportError - # Warning implemented in _load_module_shim(). - return _bootstrap._load_module_shim(self, fullname) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 499da1e04ef..07d938b18fe 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -521,24 +521,6 @@ def _requires_frozen(fxn): return _requires_frozen_wrapper -# Typically used by loader classes as a method replacement. -def _load_module_shim(self, fullname): - """Load the specified module into sys.modules and return it. - - This method is deprecated. Use loader.exec_module() instead. - - """ - msg = ("the load_module() method is deprecated and slated for removal in " - "Python 3.15; use exec_module() instead") - _warnings.warn(msg, DeprecationWarning) - spec = spec_from_loader(fullname, self) - if fullname in sys.modules: - module = sys.modules[fullname] - _exec(spec, module) - return sys.modules[fullname] - else: - return _load(spec) - # Module specifications ####################################################### def _module_repr(module): @@ -583,8 +565,7 @@ class ModuleSpec: `has_location` indicates that a spec's "origin" reflects a location. When this is True, `__file__` attribute of the module is set. - `cached` is the location of the cached bytecode file, if any. It - corresponds to the `__cached__` attribute. + `cached` is the location of the cached bytecode file, if any. `submodule_search_locations` is the sequence of path entries to search when importing submodules. If set, is_package should be @@ -717,10 +698,6 @@ def _spec_from_module(module, loader=None, origin=None): origin = getattr(loader, '_ORIGIN', None) if not origin and location is not None: origin = location - try: - cached = module.__cached__ - except AttributeError: - cached = None try: submodule_search_locations = list(module.__path__) except AttributeError: @@ -728,7 +705,7 @@ def _spec_from_module(module, loader=None, origin=None): spec = ModuleSpec(name, loader, origin=origin) spec._set_fileattr = False if location is None else (origin == location) - spec.cached = cached + spec.cached = None spec.submodule_search_locations = submodule_search_locations return spec @@ -763,8 +740,7 @@ def _init_module_attrs(spec, module, *, override=False): # should also be None for consistency. While a bit of a hack, # this is the best place to ensure this consistency. # - # See # https://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module - # and bpo-32305 + # See bpo-32305 module.__file__ = None try: module.__loader__ = loader @@ -789,7 +765,7 @@ def _init_module_attrs(spec, module, *, override=False): module.__path__ = spec.submodule_search_locations except AttributeError: pass - # __file__/__cached__ + # __file__ if spec.has_location: if override or getattr(module, '__file__', None) is None: try: @@ -797,12 +773,6 @@ def _init_module_attrs(spec, module, *, override=False): except AttributeError: pass - if override or getattr(module, '__cached__', None) is None: - if spec.cached is not None: - try: - module.__cached__ = spec.cached - except AttributeError: - pass return module @@ -844,7 +814,7 @@ def _module_repr_from_spec(spec): return f'' -# Used by importlib.reload() and _load_module_shim(). +# Used by importlib.reload(). def _exec(spec, module): """Execute the spec's specified module in an existing module's namespace.""" name = spec.name @@ -860,13 +830,7 @@ def _exec(spec, module): _init_module_attrs(spec, module, override=True) else: _init_module_attrs(spec, module, override=True) - if not hasattr(spec.loader, 'exec_module'): - msg = (f"{_object_name(spec.loader)}.exec_module() not found; " - "falling back to load_module()") - _warnings.warn(msg, ImportWarning) - spec.loader.load_module(name) - else: - spec.loader.exec_module(module) + spec.loader.exec_module(module) finally: # Update the order of insertion into sys.modules for module # clean-up at shutdown. @@ -874,53 +838,8 @@ def _exec(spec, module): sys.modules[spec.name] = module return module - -def _load_backward_compatible(spec): - # It is assumed that all callers have been warned about using load_module() - # appropriately before calling this function. - try: - spec.loader.load_module(spec.name) - except: - if spec.name in sys.modules: - module = sys.modules.pop(spec.name) - sys.modules[spec.name] = module - raise - # The module must be in sys.modules at this point! - # Move it to the end of sys.modules. - module = sys.modules.pop(spec.name) - sys.modules[spec.name] = module - if getattr(module, '__loader__', None) is None: - try: - module.__loader__ = spec.loader - except AttributeError: - pass - if getattr(module, '__package__', None) is None: - try: - # Since module.__path__ may not line up with - # spec.submodule_search_paths, we can't necessarily rely - # on spec.parent here. - module.__package__ = module.__name__ - if not hasattr(module, '__path__'): - module.__package__ = spec.name.rpartition('.')[0] - except AttributeError: - pass - if getattr(module, '__spec__', None) is None: - try: - module.__spec__ = spec - except AttributeError: - pass - return module - def _load_unlocked(spec): # A helper for direct use by the import system. - if spec.loader is not None: - # Not a namespace package. - if not hasattr(spec.loader, 'exec_module'): - msg = (f"{_object_name(spec.loader)}.exec_module() not found; " - "falling back to load_module()") - _warnings.warn(msg, ImportWarning) - return _load_backward_compatible(spec) - module = module_from_spec(spec) # This must be done before putting the module in sys.modules @@ -954,8 +873,7 @@ def _load_unlocked(spec): return module -# A method used during testing of _load_unlocked() and by -# _load_module_shim(). +# A method used during testing of _load_unlocked(). def _load(spec): """Return a new module object, loaded by the spec's loader. @@ -1020,8 +938,6 @@ class BuiltinImporter: """Return False as built-in modules are never packages.""" return False - load_module = classmethod(_load_module_shim) - class FrozenImporter: @@ -1178,25 +1094,6 @@ class FrozenImporter: code = _call_with_frames_removed(_imp.get_frozen_object, name) exec(code, module.__dict__) - @classmethod - def load_module(cls, fullname): - """Load a frozen module. - - This method is deprecated. Use exec_module() instead. - - """ - # Warning about deprecation implemented in _load_module_shim(). - module = _load_module_shim(cls, fullname) - info = _imp.find_frozen(fullname) - assert info is not None - _, ispkg, origname = info - module.__origname__ = origname - vars(module).pop('__file__', None) - if ispkg: - module.__path__ = [] - cls._fix_up_module(module) - return module - @classmethod @_requires_frozen def get_code(cls, fullname): @@ -1307,6 +1204,14 @@ _ERR_MSG_PREFIX = 'No module named ' def _find_and_load_unlocked(name, import_): path = None + sys.audit( + "import", + name, + path, + getattr(sys, "path", None), + getattr(sys, "meta_path", None), + getattr(sys, "path_hooks", None) + ) parent = name.rpartition('.')[0] parent_spec = None if parent: diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 8a1437a2cc5..b576ceb1ce9 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -208,12 +208,8 @@ def _write_atomic(path, data, mode=0o666): try: # We first write data to a temporary file, and then use os.replace() to # perform an atomic rename. - with _io.FileIO(fd, 'wb') as file: - bytes_written = file.write(data) - if bytes_written != len(data): - # Raise an OSError so the 'except' below cleans up the partially - # written file. - raise OSError("os.write() didn't write the full pyc file") + with _io.open(fd, 'wb') as file: + file.write(data) _os.replace(path_tmp, path) except OSError: try: @@ -240,7 +236,7 @@ BYTECODE_SUFFIXES = ['.pyc'] # Deprecated. DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES -def cache_from_source(path, debug_override=None, *, optimization=None): +def cache_from_source(path, *, optimization=None): """Given the path to a .py file, return the path to its .pyc file. The .py file does not need to exist; this simply returns the path to the @@ -251,20 +247,9 @@ def cache_from_source(path, debug_override=None, *, optimization=None): of the argument is taken and verified to be alphanumeric (else ValueError is raised). - The debug_override parameter is deprecated. If debug_override is not None, - a True value is the same as setting 'optimization' to the empty string - while a False value is equivalent to setting 'optimization' to '1'. - If sys.implementation.cache_tag is None then NotImplementedError is raised. """ - if debug_override is not None: - _warnings.warn('the debug_override parameter is deprecated; use ' - "'optimization' instead", DeprecationWarning) - if optimization is not None: - message = 'debug_override or optimization must be set to None' - raise TypeError(message) - optimization = '' if debug_override else 1 path = _os.fspath(path) head, tail = _path_split(path) base, sep, rest = tail.rpartition('.') @@ -552,8 +537,7 @@ def decode_source(source_bytes): import tokenize # To avoid bootstrap issues. source_bytes_readline = _io.BytesIO(source_bytes).readline encoding = tokenize.detect_encoding(source_bytes_readline) - newline_decoder = _io.IncrementalNewlineDecoder(None, True) - return newline_decoder.decode(source_bytes.decode(encoding[0])) + return _io.TextIOWrapper(_io.BytesIO(source_bytes), encoding=encoding[0], newline=None).read() # Module specifications ####################################################### @@ -762,11 +746,6 @@ class _LoaderBasics: 'get_code() returns None') _bootstrap._call_with_frames_removed(exec, code, module.__dict__) - def load_module(self, fullname): - """This method is deprecated.""" - # Warning implemented in _load_module_shim(). - return _bootstrap._load_module_shim(self, fullname) - class SourceLoader(_LoaderBasics): @@ -819,13 +798,14 @@ class SourceLoader(_LoaderBasics): name=fullname) from exc return decode_source(source_bytes) - def source_to_code(self, data, path, *, _optimize=-1): + def source_to_code(self, data, path, fullname=None, *, _optimize=-1): """Return the code object compiled from source. The 'data' argument can be any object type that compile() supports. """ return _bootstrap._call_with_frames_removed(compile, data, path, 'exec', - dont_inherit=True, optimize=_optimize) + dont_inherit=True, optimize=_optimize, + module=fullname) def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. @@ -894,7 +874,7 @@ class SourceLoader(_LoaderBasics): source_path=source_path) if source_bytes is None: source_bytes = self.get_data(source_path) - code_object = self.source_to_code(source_bytes, source_path) + code_object = self.source_to_code(source_bytes, source_path, fullname) _bootstrap._verbose_message('code object from {}', source_path) if (not sys.dont_write_bytecode and bytecode_path is not None and source_mtime is not None): @@ -931,18 +911,6 @@ class FileLoader: def __hash__(self): return hash(self.name) ^ hash(self.path) - @_check_name - def load_module(self, fullname): - """Load a module from a file. - - This method is deprecated. Use exec_module() instead. - - """ - # The only reason for this method is for the name check. - # Issue #14857: Avoid the zero-argument form of super so the implementation - # of that form can be updated without breaking the frozen module. - return super(FileLoader, self).load_module(fullname) - @_check_name def get_filename(self, fullname): """Return the path to the source file as found by the finder.""" @@ -1086,12 +1054,18 @@ class ExtensionFileLoader(FileLoader, _LoaderBasics): return self.path -class _NamespacePath: - """Represents a namespace package's path. It uses the module name - to find its parent module, and from there it looks up the parent's - __path__. When this changes, the module's own path is recomputed, - using path_finder. For top-level modules, the parent module's path - is sys.path.""" +class NamespacePath: + """Represents a namespace package's path. + + It uses the module *name* to find its parent module, and from there it looks + up the parent's __path__. When this changes, the module's own path is + recomputed, using *path_finder*. The initial value is set to *path*. + + For top-level modules, the parent module's path is sys.path. + + *path_finder* should be a callable with the same signature as + MetaPathFinder.find_spec((fullname, path, target=None) -> spec). + """ # When invalidate_caches() is called, this epoch is incremented # https://bugs.python.org/issue45703 @@ -1116,7 +1090,15 @@ class _NamespacePath: def _get_parent_path(self): parent_module_name, path_attr_name = self._find_parent_path_names() - return getattr(sys.modules[parent_module_name], path_attr_name) + try: + module = sys.modules[parent_module_name] + except KeyError as e: + raise ModuleNotFoundError( + f"{parent_module_name!r} must be imported before finding {self._name!r}.", + name=parent_module_name, + ) from e + else: + return getattr(module, path_attr_name) def _recalculate(self): # If the parent's path has changed, recalculate _path @@ -1145,7 +1127,7 @@ class _NamespacePath: return len(self._recalculate()) def __repr__(self): - return f'_NamespacePath({self._path!r})' + return f'NamespacePath({self._path!r})' def __contains__(self, item): return item in self._recalculate() @@ -1154,12 +1136,16 @@ class _NamespacePath: self._path.append(item) +# For backwards-compatibility for anyone desperate enough to get at the class back in the day. +_NamespacePath = NamespacePath + + # This class is actually exposed publicly in a namespace package's __loader__ # attribute, so it should be available through a non-private name. # https://github.com/python/cpython/issues/92054 class NamespaceLoader: def __init__(self, name, path, path_finder): - self._path = _NamespacePath(name, path, path_finder) + self._path = NamespacePath(name, path, path_finder) def is_package(self, fullname): return True @@ -1168,7 +1154,7 @@ class NamespaceLoader: return '' def get_code(self, fullname): - return compile('', '', 'exec', dont_inherit=True) + return compile('', '', 'exec', dont_inherit=True, module=fullname) def create_module(self, spec): """Use default semantics for module creation.""" @@ -1176,18 +1162,6 @@ class NamespaceLoader: def exec_module(self, module): pass - def load_module(self, fullname): - """Load a namespace module. - - This method is deprecated. Use exec_module() instead. - - """ - # The import system never calls this method. - _bootstrap._verbose_message('namespace module loaded with path {!r}', - self._path) - # Warning implemented in _load_module_shim(). - return _bootstrap._load_module_shim(self, fullname) - def get_resource_reader(self, module): from importlib.readers import NamespaceReader return NamespaceReader(self._path) @@ -1214,9 +1188,9 @@ class PathFinder: del sys.path_importer_cache[name] elif hasattr(finder, 'invalidate_caches'): finder.invalidate_caches() - # Also invalidate the caches of _NamespacePaths + # Also invalidate the caches of NamespacePaths # https://bugs.python.org/issue45703 - _NamespacePath._epoch += 1 + NamespacePath._epoch += 1 from importlib.metadata import MetadataPathFinder MetadataPathFinder.invalidate_caches() @@ -1302,7 +1276,7 @@ class PathFinder: # We found at least one namespace path. Return a spec which # can create the namespace package. spec.origin = None - spec.submodule_search_locations = _NamespacePath(fullname, namespace_path, cls._get_spec) + spec.submodule_search_locations = NamespacePath(fullname, namespace_path, cls._get_spec) return spec else: return None @@ -1498,7 +1472,13 @@ class AppleFrameworkLoader(ExtensionFileLoader): ) # Ensure that the __file__ points at the .fwork location - module.__file__ = path + try: + module.__file__ = path + except AttributeError: + # Not important enough to report. + # (The error is also ignored in _bootstrap._init_module_attrs or + # import_run_extension in import.c) + pass return module @@ -1523,7 +1503,6 @@ def _fix_up_module(ns, name, pathname, cpathname=None): ns['__spec__'] = spec ns['__loader__'] = loader ns['__file__'] = pathname - ns['__cached__'] = cpathname except Exception: # Not important enough to report. pass diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py index 1e47495f65f..87922f32d11 100644 --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -108,7 +108,7 @@ class InspectLoader(Loader): source = self.get_source(fullname) if source is None: return None - return self.source_to_code(source) + return self.source_to_code(source, '', fullname) @abc.abstractmethod def get_source(self, fullname): @@ -120,15 +120,14 @@ class InspectLoader(Loader): raise ImportError @staticmethod - def source_to_code(data, path=''): + def source_to_code(data, path='', fullname=None): """Compile 'data' into a code object. The 'data' argument can be anything that compile() can handle. The'path' argument should be where the data was retrieved (when applicable).""" - return compile(data, path, 'exec', dont_inherit=True) + return compile(data, path, 'exec', dont_inherit=True, module=fullname) exec_module = _bootstrap_external._LoaderBasics.exec_module - load_module = _bootstrap_external._LoaderBasics.load_module _register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.NamespaceLoader) @@ -163,9 +162,8 @@ class ExecutionLoader(InspectLoader): try: path = self.get_filename(fullname) except ImportError: - return self.source_to_code(source) - else: - return self.source_to_code(source, path) + path = '' + return self.source_to_code(source, path, fullname) _register( ExecutionLoader, diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py index 63d726445c3..023f77d750f 100644 --- a/Lib/importlib/machinery.py +++ b/Lib/importlib/machinery.py @@ -16,6 +16,7 @@ from ._bootstrap_external import SourcelessFileLoader from ._bootstrap_external import ExtensionFileLoader from ._bootstrap_external import AppleFrameworkLoader from ._bootstrap_external import NamespaceLoader +from ._bootstrap_external import NamespacePath def all_suffixes(): diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index b59587e8016..b010bb8525e 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -1,33 +1,40 @@ +""" +APIs exposing metadata from third-party Python packages. + +This codebase is shared between importlib.metadata in the stdlib +and importlib_metadata in PyPI. See +https://github.com/python/importlib_metadata/wiki/Development-Methodology +for more detail. +""" + from __future__ import annotations -import os -import re import abc -import sys -import json +import collections import email -import types -import inspect -import pathlib -import zipfile -import operator -import textwrap import functools import itertools +import operator +import os +import pathlib import posixpath -import collections +import re +import sys +import textwrap +import types +from collections.abc import Iterable, Mapping +from contextlib import suppress +from importlib import import_module +from importlib.abc import MetaPathFinder +from itertools import starmap +from typing import Any from . import _meta from ._collections import FreezableDefaultDict, Pair from ._functools import method_cache, pass_none from ._itertools import always_iterable, bucket, unique_everseen from ._meta import PackageMetadata, SimplePath - -from contextlib import suppress -from importlib import import_module -from importlib.abc import MetaPathFinder -from itertools import starmap -from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast +from ._typing import md_none __all__ = [ 'Distribution', @@ -53,7 +60,7 @@ class PackageNotFoundError(ModuleNotFoundError): return f"No package metadata was found for {self.name}" @property - def name(self) -> str: # type: ignore[override] + def name(self) -> str: # type: ignore[override] # make readonly (name,) = self.args return name @@ -123,6 +130,12 @@ class Sectioned: return line and not line.startswith('#') +class _EntryPointMatch(types.SimpleNamespace): + module: str + attr: str + extras: str + + class EntryPoint: """An entry point as defined by Python packaging conventions. @@ -138,6 +151,30 @@ class EntryPoint: 'attr' >>> ep.extras ['extra1', 'extra2'] + + If the value package or module are not valid identifiers, a + ValueError is raised on access. + + >>> EntryPoint(name=None, group=None, value='invalid-name').module + Traceback (most recent call last): + ... + ValueError: ('Invalid object reference...invalid-name... + >>> EntryPoint(name=None, group=None, value='invalid-name').attr + Traceback (most recent call last): + ... + ValueError: ('Invalid object reference...invalid-name... + >>> EntryPoint(name=None, group=None, value='invalid-name').extras + Traceback (most recent call last): + ... + ValueError: ('Invalid object reference...invalid-name... + + The same thing happens on construction. + + >>> EntryPoint(name=None, group=None, value='invalid-name') + Traceback (most recent call last): + ... + ValueError: ('Invalid object reference...invalid-name... + """ pattern = re.compile( @@ -165,38 +202,44 @@ class EntryPoint: value: str group: str - dist: Optional[Distribution] = None + dist: Distribution | None = None def __init__(self, name: str, value: str, group: str) -> None: vars(self).update(name=name, value=value, group=group) + self.module def load(self) -> Any: """Load the entry point from its definition. If only a module is indicated by the value, return that module. Otherwise, return the named object. """ - match = cast(Match, self.pattern.match(self.value)) - module = import_module(match.group('module')) - attrs = filter(None, (match.group('attr') or '').split('.')) + module = import_module(self.module) + attrs = filter(None, (self.attr or '').split('.')) return functools.reduce(getattr, attrs, module) @property def module(self) -> str: - match = self.pattern.match(self.value) - assert match is not None - return match.group('module') + return self._match.module @property def attr(self) -> str: - match = self.pattern.match(self.value) - assert match is not None - return match.group('attr') + return self._match.attr @property - def extras(self) -> List[str]: + def extras(self) -> list[str]: + return re.findall(r'\w+', self._match.extras or '') + + @functools.cached_property + def _match(self) -> _EntryPointMatch: match = self.pattern.match(self.value) - assert match is not None - return re.findall(r'\w+', match.group('extras') or '') + if not match: + raise ValueError( + 'Invalid object reference. ' + 'See https://packaging.python.org' + '/en/latest/specifications/entry-points/#data-model', + self.value, + ) + return _EntryPointMatch(**match.groupdict()) def _for(self, dist): vars(self).update(dist=dist) @@ -222,9 +265,26 @@ class EntryPoint: >>> ep.matches(attr='bong') True """ + self._disallow_dist(params) attrs = (getattr(self, param) for param in params) return all(map(operator.eq, params.values(), attrs)) + @staticmethod + def _disallow_dist(params): + """ + Querying by dist is not allowed (dist objects are not comparable). + >>> EntryPoint(name='fan', value='fav', group='fag').matches(dist='foo') + Traceback (most recent call last): + ... + ValueError: "dist" is not suitable for matching... + """ + if "dist" in params: + raise ValueError( + '"dist" is not suitable for matching. ' + "Instead, use Distribution.entry_points.select() on a " + "located distribution." + ) + def _key(self): return self.name, self.value, self.group @@ -254,7 +314,7 @@ class EntryPoints(tuple): __slots__ = () - def __getitem__(self, name: str) -> EntryPoint: # type: ignore[override] + def __getitem__(self, name: str) -> EntryPoint: # type: ignore[override] # Work with str instead of int """ Get the EntryPoint in self matching name. """ @@ -278,14 +338,14 @@ class EntryPoints(tuple): return EntryPoints(ep for ep in self if ep.matches(**params)) @property - def names(self) -> Set[str]: + def names(self) -> set[str]: """ Return the set of all names of all entry points. """ return {ep.name for ep in self} @property - def groups(self) -> Set[str]: + def groups(self) -> set[str]: """ Return the set of all groups of all entry points. """ @@ -306,11 +366,11 @@ class EntryPoints(tuple): class PackagePath(pathlib.PurePosixPath): """A reference to a path in a package""" - hash: Optional[FileHash] + hash: FileHash | None size: int dist: Distribution - def read_text(self, encoding: str = 'utf-8') -> str: # type: ignore[override] + def read_text(self, encoding: str = 'utf-8') -> str: return self.locate().read_text(encoding=encoding) def read_binary(self) -> bytes: @@ -341,7 +401,7 @@ class Distribution(metaclass=abc.ABCMeta): """ @abc.abstractmethod - def read_text(self, filename) -> Optional[str]: + def read_text(self, filename) -> str | None: """Attempt to load metadata file given by the name. Python distribution metadata is organized by blobs of text @@ -368,6 +428,17 @@ class Distribution(metaclass=abc.ABCMeta): """ Given a path to a file in this distribution, return a SimplePath to it. + + This method is used by callers of ``Distribution.files()`` to + locate files within the distribution. If it's possible for a + Distribution to represent files in the distribution as + ``SimplePath`` objects, it should implement this method + to resolve such objects. + + Some Distribution providers may elect not to resolve SimplePath + objects within the distribution by raising a + NotImplementedError, but consumers of such a Distribution would + be unable to invoke ``Distribution.files()``. """ @classmethod @@ -386,11 +457,11 @@ class Distribution(metaclass=abc.ABCMeta): try: return next(iter(cls._prefer_valid(cls.discover(name=name)))) except StopIteration: - raise PackageNotFoundError(name) + raise PackageNotFoundError(name) from None @classmethod def discover( - cls, *, context: Optional[DistributionFinder.Context] = None, **kwargs + cls, *, context: DistributionFinder.Context | None = None, **kwargs ) -> Iterable[Distribution]: """Return an iterable of Distribution objects for all packages. @@ -436,7 +507,7 @@ class Distribution(metaclass=abc.ABCMeta): return filter(None, declared) @property - def metadata(self) -> _meta.PackageMetadata: + def metadata(self) -> _meta.PackageMetadata | None: """Return the parsed metadata for this Distribution. The returned object will have keys that name the various bits of @@ -446,10 +517,8 @@ class Distribution(metaclass=abc.ABCMeta): Custom providers may provide the METADATA file or override this property. """ - # deferred for performance (python/cpython#109829) - from . import _adapters - opt_text = ( + text = ( self.read_text('METADATA') or self.read_text('PKG-INFO') # This last clause is here to support old egg-info files. Its @@ -457,13 +526,20 @@ class Distribution(metaclass=abc.ABCMeta): # (which points to the egg-info file) attribute unchanged. or self.read_text('') ) - text = cast(str, opt_text) + return self._assemble_message(text) + + @staticmethod + @pass_none + def _assemble_message(text: str) -> _meta.PackageMetadata: + # deferred for performance (python/cpython#109829) + from . import _adapters + return _adapters.Message(email.message_from_string(text)) @property def name(self) -> str: """Return the 'Name' metadata for the distribution package.""" - return self.metadata['Name'] + return md_none(self.metadata)['Name'] @property def _normalized_name(self): @@ -473,7 +549,7 @@ class Distribution(metaclass=abc.ABCMeta): @property def version(self) -> str: """Return the 'Version' metadata for the distribution package.""" - return self.metadata['Version'] + return md_none(self.metadata)['Version'] @property def entry_points(self) -> EntryPoints: @@ -486,7 +562,7 @@ class Distribution(metaclass=abc.ABCMeta): return EntryPoints._from_text_for(self.read_text('entry_points.txt'), self) @property - def files(self) -> Optional[List[PackagePath]]: + def files(self) -> list[PackagePath] | None: """Files in this distribution. :return: List of PackagePath for this distribution or None @@ -579,7 +655,7 @@ class Distribution(metaclass=abc.ABCMeta): return text and map('"{}"'.format, text.splitlines()) @property - def requires(self) -> Optional[List[str]]: + def requires(self) -> list[str] | None: """Generated requirements specified for this Distribution""" reqs = self._read_dist_info_reqs() or self._read_egg_info_reqs() return reqs and list(reqs) @@ -635,6 +711,9 @@ class Distribution(metaclass=abc.ABCMeta): return self._load_json('direct_url.json') def _load_json(self, filename): + # Deferred for performance (python/importlib_metadata#503) + import json + return pass_none(json.loads)( self.read_text(filename), object_hook=lambda data: types.SimpleNamespace(**data), @@ -682,7 +761,7 @@ class DistributionFinder(MetaPathFinder): vars(self).update(kwargs) @property - def path(self) -> List[str]: + def path(self) -> list[str]: """ The sequence of directory path that a distribution finder should search. @@ -719,7 +798,7 @@ class FastPath: True """ - @functools.lru_cache() # type: ignore + @functools.lru_cache() # type: ignore[misc] def __new__(cls, root): return super().__new__(cls) @@ -737,6 +816,9 @@ class FastPath: return [] def zip_children(self): + # deferred for performance (python/importlib_metadata#502) + import zipfile + zip_path = zipfile.Path(self.root) names = zip_path.root.namelist() self.joinpath = zip_path.joinpath @@ -831,7 +913,7 @@ class Prepared: normalized = None legacy_normalized = None - def __init__(self, name: Optional[str]): + def __init__(self, name: str | None): self.name = name if name is None: return @@ -894,7 +976,7 @@ class PathDistribution(Distribution): """ self._path = path - def read_text(self, filename: str | os.PathLike[str]) -> Optional[str]: + def read_text(self, filename: str | os.PathLike[str]) -> str | None: with suppress( FileNotFoundError, IsADirectoryError, @@ -958,7 +1040,7 @@ def distributions(**kwargs) -> Iterable[Distribution]: return Distribution.discover(**kwargs) -def metadata(distribution_name: str) -> _meta.PackageMetadata: +def metadata(distribution_name: str) -> _meta.PackageMetadata | None: """Get the metadata for the named package. :param distribution_name: The name of the distribution package to query. @@ -1001,7 +1083,7 @@ def entry_points(**params) -> EntryPoints: return EntryPoints(eps).select(**params) -def files(distribution_name: str) -> Optional[List[PackagePath]]: +def files(distribution_name: str) -> list[PackagePath] | None: """Return a list of files for the named package. :param distribution_name: The name of the distribution package to query. @@ -1010,7 +1092,7 @@ def files(distribution_name: str) -> Optional[List[PackagePath]]: return distribution(distribution_name).files -def requires(distribution_name: str) -> Optional[List[str]]: +def requires(distribution_name: str) -> list[str] | None: """ Return a list of requirements for the named package. @@ -1020,7 +1102,7 @@ def requires(distribution_name: str) -> Optional[List[str]]: return distribution(distribution_name).requires -def packages_distributions() -> Mapping[str, List[str]]: +def packages_distributions() -> Mapping[str, list[str]]: """ Return a mapping of top-level packages to their distributions. @@ -1033,7 +1115,7 @@ def packages_distributions() -> Mapping[str, List[str]]: pkg_to_dist = collections.defaultdict(list) for dist in distributions(): for pkg in _top_level_declared(dist) or _top_level_inferred(dist): - pkg_to_dist[pkg].append(dist.metadata['Name']) + pkg_to_dist[pkg].append(md_none(dist.metadata)['Name']) return dict(pkg_to_dist) @@ -1041,7 +1123,7 @@ def _top_level_declared(dist): return (dist.read_text('top_level.txt') or '').split() -def _topmost(name: PackagePath) -> Optional[str]: +def _topmost(name: PackagePath) -> str | None: """ Return the top-most parent as long as there is a parent. """ @@ -1067,11 +1149,10 @@ def _get_toplevel_name(name: PackagePath) -> str: >>> _get_toplevel_name(PackagePath('foo.dist-info')) 'foo.dist-info' """ - return _topmost(name) or ( - # python/typeshed#10328 - inspect.getmodulename(name) # type: ignore - or str(name) - ) + # Defer import of inspect for performance (python/cpython#118761) + import inspect + + return _topmost(name) or inspect.getmodulename(name) or str(name) def _top_level_inferred(dist): diff --git a/Lib/importlib/metadata/_adapters.py b/Lib/importlib/metadata/_adapters.py index 6223263ed53..f5b30dd92cd 100644 --- a/Lib/importlib/metadata/_adapters.py +++ b/Lib/importlib/metadata/_adapters.py @@ -1,11 +1,58 @@ +import email.message +import email.policy import re import textwrap -import email.message from ._text import FoldedCase +class RawPolicy(email.policy.EmailPolicy): + def fold(self, name, value): + folded = self.linesep.join( + textwrap.indent(value, prefix=' ' * 8, predicate=lambda line: True) + .lstrip() + .splitlines() + ) + return f'{name}: {folded}{self.linesep}' + + class Message(email.message.Message): + r""" + Specialized Message subclass to handle metadata naturally. + + Reads values that may have newlines in them and converts the + payload to the Description. + + >>> msg_text = textwrap.dedent(''' + ... Name: Foo + ... Version: 3.0 + ... License: blah + ... de-blah + ... + ... First line of description. + ... Second line of description. + ... + ... Fourth line! + ... ''').lstrip().replace('', '') + >>> msg = Message(email.message_from_string(msg_text)) + >>> msg['Description'] + 'First line of description.\nSecond line of description.\n\nFourth line!\n' + + Message should render even if values contain newlines. + + >>> print(msg) + Name: Foo + Version: 3.0 + License: blah + de-blah + Description: First line of description. + Second line of description. + + Fourth line! + + + """ + multiple_use_keys = set( map( FoldedCase, @@ -57,15 +104,20 @@ class Message(email.message.Message): def _repair_headers(self): def redent(value): "Correct for RFC822 indentation" - if not value or '\n' not in value: + indent = ' ' * 8 + if not value or '\n' + indent not in value: return value - return textwrap.dedent(' ' * 8 + value) + return textwrap.dedent(indent + value) headers = [(key, redent(value)) for key, value in vars(self)['_headers']] if self._payload: headers.append(('Description', self.get_payload())) + self.set_payload('') return headers + def as_string(self): + return super().as_string(policy=RawPolicy()) + @property def json(self): """ diff --git a/Lib/importlib/metadata/_collections.py b/Lib/importlib/metadata/_collections.py index cf0954e1a30..fc5045d36be 100644 --- a/Lib/importlib/metadata/_collections.py +++ b/Lib/importlib/metadata/_collections.py @@ -1,4 +1,5 @@ import collections +import typing # from jaraco.collections 3.3 @@ -24,7 +25,10 @@ class FreezableDefaultDict(collections.defaultdict): self._frozen = lambda key: self.default_factory() -class Pair(collections.namedtuple('Pair', 'name value')): +class Pair(typing.NamedTuple): + name: str + value: str + @classmethod def parse(cls, text): return cls(*map(str.strip, text.split("=", 1))) diff --git a/Lib/importlib/metadata/_functools.py b/Lib/importlib/metadata/_functools.py index 71f66bd03cb..5dda6a2199a 100644 --- a/Lib/importlib/metadata/_functools.py +++ b/Lib/importlib/metadata/_functools.py @@ -1,5 +1,5 @@ -import types import functools +import types # from jaraco.functools 3.3 diff --git a/Lib/importlib/metadata/_meta.py b/Lib/importlib/metadata/_meta.py index 1927d0f624d..0c20eff3da7 100644 --- a/Lib/importlib/metadata/_meta.py +++ b/Lib/importlib/metadata/_meta.py @@ -1,9 +1,13 @@ from __future__ import annotations import os -from typing import Protocol -from typing import Any, Dict, Iterator, List, Optional, TypeVar, Union, overload - +from collections.abc import Iterator +from typing import ( + Any, + Protocol, + TypeVar, + overload, +) _T = TypeVar("_T") @@ -20,25 +24,25 @@ class PackageMetadata(Protocol): @overload def get( self, name: str, failobj: None = None - ) -> Optional[str]: ... # pragma: no cover + ) -> str | None: ... # pragma: no cover @overload - def get(self, name: str, failobj: _T) -> Union[str, _T]: ... # pragma: no cover + def get(self, name: str, failobj: _T) -> str | _T: ... # pragma: no cover # overload per python/importlib_metadata#435 @overload def get_all( self, name: str, failobj: None = None - ) -> Optional[List[Any]]: ... # pragma: no cover + ) -> list[Any] | None: ... # pragma: no cover @overload - def get_all(self, name: str, failobj: _T) -> Union[List[Any], _T]: + def get_all(self, name: str, failobj: _T) -> list[Any] | _T: """ Return all values associated with a possibly multi-valued key. """ @property - def json(self) -> Dict[str, Union[str, List[str]]]: + def json(self) -> dict[str, str | list[str]]: """ A JSON-compatible form of the metadata. """ @@ -50,11 +54,11 @@ class SimplePath(Protocol): """ def joinpath( - self, other: Union[str, os.PathLike[str]] + self, other: str | os.PathLike[str] ) -> SimplePath: ... # pragma: no cover def __truediv__( - self, other: Union[str, os.PathLike[str]] + self, other: str | os.PathLike[str] ) -> SimplePath: ... # pragma: no cover @property diff --git a/Lib/importlib/metadata/_typing.py b/Lib/importlib/metadata/_typing.py new file mode 100644 index 00000000000..32b1d2b98ac --- /dev/null +++ b/Lib/importlib/metadata/_typing.py @@ -0,0 +1,15 @@ +import functools +import typing + +from ._meta import PackageMetadata + +md_none = functools.partial(typing.cast, PackageMetadata) +""" +Suppress type errors for optional metadata. + +Although Distribution.metadata can return None when metadata is corrupt +and thus None, allow callers to assume it's not None and crash if +that's the case. + +# python/importlib_metadata#493 +""" diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py index 4e9014c45a0..d16ebe4520f 100644 --- a/Lib/importlib/resources/_common.py +++ b/Lib/importlib/resources/_common.py @@ -6,7 +6,6 @@ import contextlib import types import importlib import inspect -import warnings import itertools from typing import Union, Optional, cast @@ -16,39 +15,6 @@ Package = Union[types.ModuleType, str] Anchor = Package -def package_to_anchor(func): - """ - Replace 'package' parameter as 'anchor' and warn about the change. - - Other errors should fall through. - - >>> files('a', 'b') - Traceback (most recent call last): - TypeError: files() takes from 0 to 1 positional arguments but 2 were given - - Remove this compatibility in Python 3.14. - """ - undefined = object() - - @functools.wraps(func) - def wrapper(anchor=undefined, package=undefined): - if package is not undefined: - if anchor is not undefined: - return func(anchor, package) - warnings.warn( - "First parameter to files is renamed to 'anchor'", - DeprecationWarning, - stacklevel=2, - ) - return func(package) - elif anchor is undefined: - return func() - return func(anchor) - - return wrapper - - -@package_to_anchor def files(anchor: Optional[Anchor] = None) -> Traversable: """ Get a Traversable resource for an anchor. diff --git a/Lib/inspect.py b/Lib/inspect.py index 5a46987b78b..07c4e28f0d9 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -706,8 +706,8 @@ def _findclass(func): return None return cls -def _finddoc(obj): - if isclass(obj): +def _finddoc(obj, *, search_in_class=True): + if search_in_class and isclass(obj): for base in obj.__mro__: if base is not object: try: @@ -747,6 +747,12 @@ def _finddoc(obj): cls = _findclass(obj.fget) if cls is None or getattr(cls, name) is not obj: return None + # Should be tested before ismethoddescriptor() + elif isinstance(obj, functools.cached_property): + name = obj.attrname + cls = _findclass(obj.func) + if cls is None or getattr(cls, name) is not obj: + return None elif ismethoddescriptor(obj) or isdatadescriptor(obj): name = obj.__name__ cls = obj.__objclass__ @@ -767,19 +773,37 @@ def _finddoc(obj): return doc return None -def getdoc(object): +def _getowndoc(obj): + """Get the documentation string for an object if it is not + inherited from its class.""" + try: + doc = object.__getattribute__(obj, '__doc__') + if doc is None: + return None + if obj is not type: + typedoc = type(obj).__doc__ + if isinstance(typedoc, str) and typedoc == doc: + return None + return doc + except AttributeError: + return None + +def getdoc(object, *, fallback_to_class_doc=True, inherit_class_doc=True): """Get the documentation string for an object. All tabs are expanded to spaces. To clean up docstrings that are indented to line up with blocks of code, any whitespace than can be uniformly removed from the second line onwards is removed.""" - try: - doc = object.__doc__ - except AttributeError: - return None + if fallback_to_class_doc: + try: + doc = object.__doc__ + except AttributeError: + return None + else: + doc = _getowndoc(object) if doc is None: try: - doc = _finddoc(object) + doc = _finddoc(object, search_in_class=inherit_class_doc) except (AttributeError, TypeError): return None if not isinstance(doc, str): @@ -1065,7 +1089,9 @@ class BlockFinder: def tokeneater(self, type, token, srowcol, erowcol, line): if not self.started and not self.indecorator: - if type == tokenize.INDENT or token == "async": + if type in (tokenize.INDENT, tokenize.COMMENT, tokenize.NL): + pass + elif token == "async": pass # skip any decorators elif token == "@": @@ -2114,7 +2140,6 @@ def _signature_strip_non_python_syntax(signature): current_parameter = 0 OP = token.OP - ERRORTOKEN = token.ERRORTOKEN # token stream always starts with ENCODING token, skip it t = next(token_stream) @@ -3382,22 +3407,22 @@ def _main(): sys.exit(1) if args.details: - print('Target: {}'.format(target)) - print('Origin: {}'.format(getsourcefile(module))) - print('Cached: {}'.format(module.__cached__)) + print(f'Target: {target}') + print(f'Origin: {getsourcefile(module)}') + print(f'Cached: {module.__spec__.cached}') if obj is module: - print('Loader: {}'.format(repr(module.__loader__))) + print(f'Loader: {module.__loader__!r}') if hasattr(module, '__path__'): - print('Submodule search path: {}'.format(module.__path__)) + print(f'Submodule search path: {module.__path__}') else: try: __, lineno = findsource(obj) except Exception: pass else: - print('Line: {}'.format(lineno)) + print(f'Line: {lineno}') - print('\n') + print() else: print(getsource(obj)) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 7470dc6c52d..f1062a8cd05 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -8,9 +8,6 @@ and networks. """ -__version__ = '1.0' - - import functools IPV4LENGTH = 32 @@ -1549,7 +1546,7 @@ class IPv4Network(_BaseV4, _BaseNetwork): if self._prefixlen == (self.max_prefixlen - 1): self.hosts = self.__iter__ elif self._prefixlen == (self.max_prefixlen): - self.hosts = lambda: [IPv4Address(addr)] + self.hosts = lambda: iter((IPv4Address(addr),)) @property @functools.lru_cache() @@ -2340,7 +2337,7 @@ class IPv6Network(_BaseV6, _BaseNetwork): if self._prefixlen == (self.max_prefixlen - 1): self.hosts = self.__iter__ elif self._prefixlen == self.max_prefixlen: - self.hosts = lambda: [IPv6Address(addr)] + self.hosts = lambda: iter((IPv6Address(addr),)) def hosts(self): """Generate Iterator over usable hosts in a network. @@ -2419,3 +2416,12 @@ class _IPv6Constants: IPv6Address._constants = _IPv6Constants IPv6Network._constants = _IPv6Constants + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.0" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 1d972d22ded..89396b25a2c 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -95,7 +95,6 @@ Using json from the shell to validate and pretty-print:: $ echo '{ 1.2:3.4}' | python -m json Expecting property name enclosed in double quotes: line 1 column 3 (char 2) """ -__version__ = '2.0.9' __all__ = [ 'dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', @@ -128,8 +127,9 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, instead of raising a ``TypeError``. If ``ensure_ascii`` is false, then the strings written to ``fp`` can - contain non-ASCII characters if they appear in strings contained in - ``obj``. Otherwise, all such characters are escaped in JSON strings. + contain non-ASCII and non-printable characters if they appear in strings + contained in ``obj``. Otherwise, all such characters are escaped in JSON + strings. If ``check_circular`` is false, then the circular reference check for container types will be skipped and a circular reference will @@ -145,10 +145,11 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, level of 0 will only insert newlines. ``None`` is the most compact representation. - If specified, ``separators`` should be an ``(item_separator, key_separator)`` - tuple. The default is ``(', ', ': ')`` if *indent* is ``None`` and - ``(',', ': ')`` otherwise. To get the most compact JSON representation, - you should specify ``(',', ':')`` to eliminate whitespace. + If specified, ``separators`` should be an ``(item_separator, + key_separator)`` tuple. The default is ``(', ', ': ')`` if *indent* is + ``None`` and ``(',', ': ')`` otherwise. To get the most compact JSON + representation, you should specify ``(',', ':')`` to eliminate + whitespace. ``default(obj)`` is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. @@ -189,9 +190,10 @@ def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped instead of raising a ``TypeError``. - If ``ensure_ascii`` is false, then the return value can contain non-ASCII - characters if they appear in strings contained in ``obj``. Otherwise, all - such characters are escaped in JSON strings. + If ``ensure_ascii`` is false, then the return value can contain + non-ASCII and non-printable characters if they appear in strings + contained in ``obj``. Otherwise, all such characters are escaped in + JSON strings. If ``check_circular`` is false, then the circular reference check for container types will be skipped and a circular reference will @@ -207,10 +209,11 @@ def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, level of 0 will only insert newlines. ``None`` is the most compact representation. - If specified, ``separators`` should be an ``(item_separator, key_separator)`` - tuple. The default is ``(', ', ': ')`` if *indent* is ``None`` and - ``(',', ': ')`` otherwise. To get the most compact JSON representation, - you should specify ``(',', ':')`` to eliminate whitespace. + If specified, ``separators`` should be an ``(item_separator, + key_separator)`` tuple. The default is ``(', ', ': ')`` if *indent* is + ``None`` and ``(',', ': ')`` otherwise. To get the most compact JSON + representation, you should specify ``(',', ':')`` to eliminate + whitespace. ``default(obj)`` is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. @@ -281,11 +284,12 @@ def load(fp, *, cls=None, object_hook=None, parse_float=None, ``object_hook`` will be used instead of the ``dict``. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting). - ``object_pairs_hook`` is an optional function that will be called with the - result of any object literal decoded with an ordered list of pairs. The - return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders. If ``object_hook`` - is also defined, the ``object_pairs_hook`` takes priority. + ``object_pairs_hook`` is an optional function that will be called with + the result of any object literal decoded with an ordered list of pairs. + The return value of ``object_pairs_hook`` will be used instead of the + ``dict``. This feature can be used to implement custom decoders. If + ``object_hook`` is also defined, the ``object_pairs_hook`` takes + priority. To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` kwarg; otherwise ``JSONDecoder`` is used. @@ -306,11 +310,12 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None, ``object_hook`` will be used instead of the ``dict``. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting). - ``object_pairs_hook`` is an optional function that will be called with the - result of any object literal decoded with an ordered list of pairs. The - return value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders. If ``object_hook`` - is also defined, the ``object_pairs_hook`` takes priority. + ``object_pairs_hook`` is an optional function that will be called with + the result of any object literal decoded with an ordered list of pairs. + The return value of ``object_pairs_hook`` will be used instead of the + ``dict``. This feature can be used to implement custom decoders. If + ``object_hook`` is also defined, the ``object_pairs_hook`` takes + priority. ``parse_float``, if specified, will be called with the string of every JSON float to be decoded. By default this is equivalent to @@ -357,3 +362,12 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None, if parse_constant is not None: kw['parse_constant'] = parse_constant return cls(**kw).decode(s) + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "2.0.9" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py index ff4bfcdcc40..92ad6352557 100644 --- a/Lib/json/decoder.py +++ b/Lib/json/decoder.py @@ -297,10 +297,10 @@ class JSONDecoder(object): place of the given ``dict``. This can be used to provide custom deserializations (e.g. to support JSON-RPC class hinting). - ``object_pairs_hook``, if specified will be called with the result of - every JSON object decoded with an ordered list of pairs. The return - value of ``object_pairs_hook`` will be used instead of the ``dict``. - This feature can be used to implement custom decoders. + ``object_pairs_hook``, if specified will be called with the result + of every JSON object decoded with an ordered list of pairs. The + return value of ``object_pairs_hook`` will be used instead of the + ``dict``. This feature can be used to implement custom decoders. If ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority. diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py index bc446e0f377..4c70e8b75ed 100644 --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -111,9 +111,10 @@ class JSONEncoder(object): encoding of keys that are not str, int, float, bool or None. If skipkeys is True, such items are simply skipped. - If ensure_ascii is true, the output is guaranteed to be str - objects with all incoming non-ASCII characters escaped. If - ensure_ascii is false, the output can contain non-ASCII characters. + If ensure_ascii is true, the output is guaranteed to be str objects + with all incoming non-ASCII and non-printable characters escaped. + If ensure_ascii is false, the output can contain non-ASCII and + non-printable characters. If check_circular is true, then lists, dicts, and custom encoded objects will be checked for circular references during encoding to @@ -134,14 +135,15 @@ class JSONEncoder(object): indent level. An indent level of 0 will only insert newlines. None is the most compact representation. - If specified, separators should be an (item_separator, key_separator) - tuple. The default is (', ', ': ') if *indent* is ``None`` and - (',', ': ') otherwise. To get the most compact JSON representation, - you should specify (',', ':') to eliminate whitespace. + If specified, separators should be an (item_separator, + key_separator) tuple. The default is (', ', ': ') if *indent* is + ``None`` and (',', ': ') otherwise. To get the most compact JSON + representation, you should specify (',', ':') to eliminate + whitespace. If specified, default is a function that gets called for objects - that can't otherwise be serialized. It should return a JSON encodable - version of the object or raise a ``TypeError``. + that can't otherwise be serialized. It should return a JSON + encodable version of the object or raise a ``TypeError``. """ @@ -262,17 +264,6 @@ class JSONEncoder(object): def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, - ## HACK: hand-optimized bytecode; turn globals into locals - ValueError=ValueError, - dict=dict, - float=float, - id=id, - int=int, - isinstance=isinstance, - list=list, - str=str, - tuple=tuple, - _intstr=int.__repr__, ): def _iterencode_list(lst, _current_indent_level): @@ -309,7 +300,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, # Subclasses of int/float may override __repr__, but we still # want to encode them as integers/floats in JSON. One example # within the standard library is IntEnum. - yield buf + _intstr(value) + yield buf + int.__repr__(value) elif isinstance(value, float): # see comment above for int yield buf + _floatstr(value) @@ -372,7 +363,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, key = 'null' elif isinstance(key, int): # see comment for int/float in _make_iterencode - key = _intstr(key) + key = int.__repr__(key) elif _skipkeys: continue else: @@ -397,7 +388,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, yield 'false' elif isinstance(value, int): # see comment for int/float in _make_iterencode - yield _intstr(value) + yield int.__repr__(value) elif isinstance(value, float): # see comment for int/float in _make_iterencode yield _floatstr(value) @@ -432,7 +423,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, yield 'false' elif isinstance(o, int): # see comment for int/float in _make_iterencode - yield _intstr(o) + yield int.__repr__(o) elif isinstance(o, float): # see comment for int/float in _make_iterencode yield _floatstr(o) @@ -456,4 +447,13 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, raise if markers is not None: del markers[markerid] - return _iterencode + + def _iterencode_once(o, _current_indent_level): + nonlocal _iterencode, _iterencode_dict, _iterencode_list + try: + yield from _iterencode(o, _current_indent_level) + finally: + # Break reference cycles due to mutually recursive closures: + del _iterencode, _iterencode_dict, _iterencode_list + + return _iterencode_once diff --git a/Lib/linecache.py b/Lib/linecache.py index ef73d1aa997..b5bf9dbdd3c 100644 --- a/Lib/linecache.py +++ b/Lib/linecache.py @@ -123,9 +123,12 @@ def updatecache(filename, module_globals=None): if _source_unavailable(filename): return [] - if filename.startswith('')): return None - # Try for a __loader__, if available - if module_globals and '__name__' in module_globals: - spec = module_globals.get('__spec__') - name = getattr(spec, 'name', None) or module_globals['__name__'] - loader = getattr(spec, 'loader', None) - if loader is None: - loader = module_globals.get('__loader__') - get_source = getattr(loader, 'get_source', None) - if name and get_source: - def get_lines(name=name, *args, **kwargs): - return get_source(name, *args, **kwargs) - return (get_lines,) - return None + if module_globals is not None and not isinstance(module_globals, dict): + raise TypeError(f'module_globals must be a dict, not {type(module_globals).__qualname__}') + if not module_globals or '__name__' not in module_globals: + return None + spec = module_globals.get('__spec__') + name = getattr(spec, 'name', None) or module_globals['__name__'] + if name is None: + return None + + loader = _bless_my_loader(module_globals) + if loader is None: + return None + + get_source = getattr(loader, 'get_source', None) + if get_source is None: + return None + + def get_lines(name=name, *args, **kwargs): + return get_source(name, *args, **kwargs) + return (get_lines,) + +def _bless_my_loader(module_globals): + # Similar to _bless_my_loader() in importlib._bootstrap_external, + # but always emits warnings instead of errors. + loader = module_globals.get('__loader__') + if loader is None and '__spec__' not in module_globals: + return None + spec = module_globals.get('__spec__') + + # The __main__ module has __spec__ = None. + if spec is None and module_globals.get('__name__') == '__main__': + return loader + + spec_loader = getattr(spec, 'loader', None) + if spec_loader is None: + import warnings + warnings.warn( + 'Module globals is missing a __spec__.loader', + DeprecationWarning) + return loader + + assert spec_loader is not None + if loader is not None and loader != spec_loader: + import warnings + warnings.warn( + 'Module globals; __loader__ != __spec__.loader', + DeprecationWarning) + return loader + + return spec_loader def _register_code(code, string, name): diff --git a/Lib/locale.py b/Lib/locale.py index 37cafb4a601..0f1b429ea41 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -214,7 +214,7 @@ def format_string(f, val, grouping=False, monetary=False): Grouping is applied if the third parameter is true. Conversion uses monetary thousands separator and grouping strings if - forth parameter monetary is true.""" + fourth parameter monetary is true.""" global _percent_re if _percent_re is None: import re diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index c5860d53b1b..39689a57e6e 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -45,9 +45,6 @@ import threading __author__ = "Vinay Sajip " __status__ = "production" -# The following module attributes are no longer updated. -__version__ = "0.5.1.2" -__date__ = "07 February 2010" #--------------------------------------------------------------------------- # Miscellaneous module data @@ -1852,9 +1849,9 @@ class LoggerAdapter(object): def __init__(self, logger, extra=None, merge_extra=False): """ - Initialize the adapter with a logger and a dict-like object which - provides contextual information. This constructor signature allows - easy stacking of LoggerAdapters, if so desired. + Initialize the adapter with a logger and an optional dict-like object + which provides contextual information. This constructor signature + allows easy stacking of LoggerAdapters, if so desired. You can effectively pass keyword arguments as shown in the following example: @@ -1885,8 +1882,9 @@ class LoggerAdapter(object): Normally, you'll only need to override this one method in a LoggerAdapter subclass for your specific needs. """ - if self.merge_extra and "extra" in kwargs: - kwargs["extra"] = {**self.extra, **kwargs["extra"]} + if self.merge_extra and kwargs.get("extra") is not None: + if self.extra is not None: + kwargs["extra"] = {**self.extra, **kwargs["extra"]} else: kwargs["extra"] = self.extra return msg, kwargs @@ -2341,3 +2339,16 @@ def captureWarnings(capture): if _warnings_showwarning is not None: warnings.showwarning = _warnings_showwarning _warnings_showwarning = None + + +def __getattr__(name): + if name in ("__version__", "__date__"): + from warnings import _deprecated + + _deprecated(name, remove=(3, 20)) + return { # Do not change + "__version__": "0.5.1.2", + "__date__": "07 February 2010", + }[name] + + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/mailbox.py b/Lib/mailbox.py index b00d9e8634c..4a44642765c 100644 --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -2090,8 +2090,6 @@ class _ProxyFile: return False return self._file.closed - __class_getitem__ = classmethod(GenericAlias) - class _PartialFile(_ProxyFile): """A read-only wrapper of part of a file.""" diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index 7d0f4c1fd40..07ac079186f 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -486,23 +486,28 @@ def _default_mime_types(): '.wiz' : 'application/msword', '.nq' : 'application/n-quads', '.nt' : 'application/n-triples', + '.cjs' : 'application/node', '.bin' : 'application/octet-stream', '.a' : 'application/octet-stream', - '.dll' : 'application/octet-stream', - '.exe' : 'application/octet-stream', '.o' : 'application/octet-stream', '.obj' : 'application/octet-stream', '.so' : 'application/octet-stream', '.oda' : 'application/oda', '.ogx' : 'application/ogg', '.pdf' : 'application/pdf', + '.ai' : 'application/pdf', '.p7c' : 'application/pkcs7-mime', '.ps' : 'application/postscript', - '.ai' : 'application/postscript', '.eps' : 'application/postscript', + '.rtf' : 'application/rtf', + '.texi' : 'application/texinfo', + '.texinfo': 'application/texinfo', + '.toml' : 'application/toml', '.trig' : 'application/trig', '.m3u' : 'application/vnd.apple.mpegurl', '.m3u8' : 'application/vnd.apple.mpegurl', + '.dll' : 'application/vnd.microsoft.portable-executable', + '.exe' : 'application/vnd.microsoft.portable-executable', '.xls' : 'application/vnd.ms-excel', '.xlb' : 'application/vnd.ms-excel', '.eot' : 'application/vnd.ms-fontobject', @@ -548,8 +553,6 @@ def _default_mime_types(): '.tar' : 'application/x-tar', '.tcl' : 'application/x-tcl', '.tex' : 'application/x-tex', - '.texi' : 'application/x-texinfo', - '.texinfo': 'application/x-texinfo', '.roff' : 'application/x-troff', '.t' : 'application/x-troff', '.tr' : 'application/x-troff', @@ -587,9 +590,9 @@ def _default_mime_types(): '.aiff' : 'audio/x-aiff', '.ra' : 'audio/x-pn-realaudio', '.wav' : 'audio/vnd.wave', + '.weba' : 'audio/webm', '.otf' : 'font/otf', '.ttf' : 'font/ttf', - '.weba' : 'audio/webm', '.woff' : 'font/woff', '.woff2' : 'font/woff2', '.avif' : 'image/avif', @@ -647,7 +650,6 @@ def _default_mime_types(): '.pl' : 'text/plain', '.srt' : 'text/plain', '.rtx' : 'text/richtext', - '.rtf' : 'text/rtf', '.tsv' : 'text/tab-separated-values', '.vtt' : 'text/vtt', '.py' : 'text/x-python', @@ -680,11 +682,9 @@ def _default_mime_types(): # Please sort these too common_types = _common_types_default = { - '.rtf' : 'application/rtf', '.apk' : 'application/vnd.android.package-archive', '.midi': 'audio/midi', '.mid' : 'audio/midi', - '.jpg' : 'image/jpg', '.pict': 'image/pict', '.pct' : 'image/pict', '.pic' : 'image/pict', diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py index ac478ee7f51..b8dccc2dd33 100644 --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -66,7 +66,12 @@ def _find_module(name, path=None): file_path = spec.origin - if spec.loader.is_package(name): + # On namespace packages, spec.loader might be None, but + # spec.submodule_search_locations should always be set — check it instead. + if isinstance(spec.submodule_search_locations, importlib.machinery.NamespacePath): + return None, spec.submodule_search_locations, ("", "", _PKG_DIRECTORY) + + if spec.loader.is_package(name): # non-namespace package return None, os.path.dirname(file_path), ("", "", _PKG_DIRECTORY) if isinstance(spec.loader, importlib.machinery.SourceFileLoader): @@ -334,7 +339,7 @@ class ModuleFinder: self.msgout(2, "load_module ->", m) return m if type == _PY_SOURCE: - co = compile(fp.read(), pathname, 'exec') + co = compile(fp.read(), pathname, 'exec', module=fqname) elif type == _PY_COMPILED: try: data = fp.read() @@ -400,7 +405,6 @@ class ModuleFinder: yield "relative_import", (level, fromlist, name) def scan_code(self, co, m): - code = co.co_code scanner = self.scan_opcodes for what, args in scanner(co): if what == "store": @@ -454,6 +458,11 @@ class ModuleFinder: if newname: fqname = newname m = self.add_module(fqname) + + if isinstance(pathname, importlib.machinery.NamespacePath): + m.__path__ = pathname + return m + m.__file__ = pathname m.__path__ = [pathname] diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index fc00d286126..64ec53884ae 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -709,8 +709,7 @@ if sys.platform == 'win32': # written data and then disconnected -- see Issue 14725. else: try: - res = _winapi.WaitForMultipleObjects( - [ov.event], False, INFINITE) + _winapi.WaitForMultipleObjects([ov.event], False, INFINITE) except: ov.cancel() _winapi.CloseHandle(handle) diff --git a/Lib/multiprocessing/dummy/__init__.py b/Lib/multiprocessing/dummy/__init__.py index 6a1468609e3..7dc5d1c8dde 100644 --- a/Lib/multiprocessing/dummy/__init__.py +++ b/Lib/multiprocessing/dummy/__init__.py @@ -33,7 +33,7 @@ from queue import Queue class DummyProcess(threading.Thread): - def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): + def __init__(self, group=None, target=None, name=None, args=(), kwargs=None): threading.Thread.__init__(self, group, target, name, args, kwargs) self._pid = None self._children = weakref.WeakKeyDictionary() diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py index c91891ff162..cc8947c5e04 100644 --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -145,12 +145,13 @@ class ForkServer(object): cmd = ('from multiprocessing.forkserver import main; ' + 'main(%d, %d, %r, **%r)') + main_kws = {} if self._preload_modules: - desired_keys = {'main_path', 'sys_path'} data = spawn.get_preparation_data('ignore') - main_kws = {x: y for x, y in data.items() if x in desired_keys} - else: - main_kws = {} + if 'sys_path' in data: + main_kws['sys_path'] = data['sys_path'] + if 'init_main_from_path' in data: + main_kws['main_path'] = data['init_main_from_path'] with socket.socket(socket.AF_UNIX) as listener: address = connection.arbitrary_address('AF_UNIX') diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py index 6217dfe1268..5c835648395 100644 --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -324,10 +324,6 @@ class BufferWrapper(object): _heap = Heap() def __init__(self, size): - if size < 0: - raise ValueError("Size {0:n} out of range".format(size)) - if sys.maxsize <= size: - raise OverflowError("Size {0:n} too large".format(size)) block = BufferWrapper._heap.malloc(size) self._state = (block, size) util.Finalize(self, BufferWrapper._heap.free, args=(block,)) diff --git a/Lib/multiprocessing/popen_spawn_posix.py b/Lib/multiprocessing/popen_spawn_posix.py index 24b8634523e..cccd659ae77 100644 --- a/Lib/multiprocessing/popen_spawn_posix.py +++ b/Lib/multiprocessing/popen_spawn_posix.py @@ -57,6 +57,10 @@ class Popen(popen_fork.Popen): self._fds.extend([child_r, child_w]) self.pid = util.spawnv_passfds(spawn.get_executable(), cmd, self._fds) + os.close(child_r) + child_r = None + os.close(child_w) + child_w = None self.sentinel = parent_r with open(parent_w, 'wb', closefd=False) as f: f.write(fp.getbuffer()) diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index 9db322be1aa..262513f295f 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -77,7 +77,7 @@ class BaseProcess(object): def _Popen(self): raise NotImplementedError - def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, + def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None): assert group is None, 'group argument must be None for now' count = next(_process_counter) @@ -89,7 +89,7 @@ class BaseProcess(object): self._closed = False self._target = target self._args = tuple(args) - self._kwargs = dict(kwargs) + self._kwargs = dict(kwargs) if kwargs else {} self._name = name or type(self).__name__ + '-' + \ ':'.join(str(i) for i in self._identity) if daemon is not None: diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py index 925f0439000..981599acf5e 100644 --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -121,7 +121,7 @@ class Queue(object): def qsize(self): # Raises NotImplementedError on Mac OSX because of broken sem_getvalue() - return self._maxsize - self._sem._semlock._get_value() + return self._maxsize - self._sem.get_value() def empty(self): return not self._poll() diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py index c53092f6e34..3606d1effb4 100644 --- a/Lib/multiprocessing/resource_tracker.py +++ b/Lib/multiprocessing/resource_tracker.py @@ -15,6 +15,7 @@ # this resource tracker process, "killall python" would probably leave unlinked # resources. +import base64 import os import signal import sys @@ -22,6 +23,8 @@ import threading import warnings from collections import deque +import json + from . import spawn from . import util @@ -65,6 +68,13 @@ class ResourceTracker(object): self._exitcode = None self._reentrant_messages = deque() + # True to use colon-separated lines, rather than JSON lines, + # for internal communication. (Mainly for testing). + # Filenames not supported by the simple format will always be sent + # using JSON. + # The reader should understand all formats. + self._use_simple_format = False + def _reentrant_call_error(self): # gh-109629: this happens if an explicit call to the ResourceTracker # gets interrupted by a garbage collection, invoking a finalizer (*) @@ -111,7 +121,12 @@ class ResourceTracker(object): close(self._fd) self._fd = None - _, status = waitpid(self._pid, 0) + try: + _, status = waitpid(self._pid, 0) + except ChildProcessError: + self._pid = None + self._exitcode = None + return self._pid = None @@ -191,6 +206,19 @@ class ResourceTracker(object): finally: os.close(r) + def _make_probe_message(self): + """Return a probe message.""" + if self._use_simple_format: + return b'PROBE:0:noop\n' + return ( + json.dumps( + {"cmd": "PROBE", "rtype": "noop"}, + ensure_ascii=True, + separators=(",", ":"), + ) + + "\n" + ).encode("ascii") + def _ensure_running_and_write(self, msg=None): with self._lock: if self._lock._recursion_count() > 1: @@ -202,7 +230,7 @@ class ResourceTracker(object): if self._fd is not None: # resource tracker was launched before, is it still running? if msg is None: - to_send = b'PROBE:0:noop\n' + to_send = self._make_probe_message() else: to_send = msg try: @@ -229,7 +257,7 @@ class ResourceTracker(object): try: # We cannot use send here as it calls ensure_running, creating # a cycle. - os.write(self._fd, b'PROBE:0:noop\n') + os.write(self._fd, self._make_probe_message()) except OSError: return False else: @@ -248,11 +276,35 @@ class ResourceTracker(object): assert nbytes == len(msg), f"{nbytes=} != {len(msg)=}" def _send(self, cmd, name, rtype): - msg = f"{cmd}:{name}:{rtype}\n".encode("ascii") - if len(msg) > 512: - # posix guarantees that writes to a pipe of less than PIPE_BUF - # bytes are atomic, and that PIPE_BUF >= 512 - raise ValueError('msg too long') + if self._use_simple_format and '\n' not in name: + msg = f"{cmd}:{name}:{rtype}\n".encode("ascii") + if len(msg) > 512: + # posix guarantees that writes to a pipe of less than PIPE_BUF + # bytes are atomic, and that PIPE_BUF >= 512 + raise ValueError('msg too long') + self._ensure_running_and_write(msg) + return + + # POSIX guarantees that writes to a pipe of less than PIPE_BUF (512 on Linux) + # bytes are atomic. Therefore, we want the message to be shorter than 512 bytes. + # POSIX shm_open() and sem_open() require the name, including its leading slash, + # to be at most NAME_MAX bytes (255 on Linux) + # With json.dump(..., ensure_ascii=True) every non-ASCII byte becomes a 6-char + # escape like \uDC80. + # As we want the overall message to be kept atomic and therefore smaller than 512, + # we encode encode the raw name bytes with URL-safe Base64 - so a 255 long name + # will not exceed 340 bytes. + b = name.encode('utf-8', 'surrogateescape') + if len(b) > 255: + raise ValueError('shared memory name too long (max 255 bytes)') + b64 = base64.urlsafe_b64encode(b).decode('ascii') + + payload = {"cmd": cmd, "rtype": rtype, "base64_name": b64} + msg = (json.dumps(payload, ensure_ascii=True, separators=(",", ":")) + "\n").encode("ascii") + + # The entire JSON message is guaranteed < PIPE_BUF (512 bytes) by construction. + assert len(msg) <= 512, f"internal error: message too long ({len(msg)} bytes)" + assert msg.startswith(b'{') self._ensure_running_and_write(msg) @@ -263,6 +315,30 @@ unregister = _resource_tracker.unregister getfd = _resource_tracker.getfd +def _decode_message(line): + if line.startswith(b'{'): + try: + obj = json.loads(line.decode('ascii')) + except Exception as e: + raise ValueError("malformed resource_tracker message: %r" % (line,)) from e + + cmd = obj["cmd"] + rtype = obj["rtype"] + b64 = obj.get("base64_name", "") + + if not isinstance(cmd, str) or not isinstance(rtype, str) or not isinstance(b64, str): + raise ValueError("malformed resource_tracker fields: %r" % (obj,)) + + try: + name = base64.urlsafe_b64decode(b64).decode('utf-8', 'surrogateescape') + except ValueError as e: + raise ValueError("malformed resource_tracker base64_name: %r" % (b64,)) from e + else: + cmd, rest = line.strip().decode('ascii').split(':', maxsplit=1) + name, rtype = rest.rsplit(':', maxsplit=1) + return cmd, rtype, name + + def main(fd): '''Run resource tracker.''' # protect the process from ^C and "killall python" etc @@ -285,7 +361,7 @@ def main(fd): with open(fd, 'rb') as f: for line in f: try: - cmd, name, rtype = line.strip().decode('ascii').split(':') + cmd, rtype, name = _decode_message(line) cleanup_func = _CLEANUP_FUNCS.get(rtype, None) if cleanup_func is None: raise ValueError( diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py index 30425047e98..9188114ae28 100644 --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -135,11 +135,16 @@ class Semaphore(SemLock): SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx) def get_value(self): + '''Returns current value of Semaphore. + + Raises NotImplementedError on Mac OSX + because of broken sem_getvalue(). + ''' return self._semlock._get_value() def __repr__(self): try: - value = self._semlock._get_value() + value = self.get_value() except Exception: value = 'unknown' return '<%s(value=%s)>' % (self.__class__.__name__, value) @@ -155,7 +160,7 @@ class BoundedSemaphore(Semaphore): def __repr__(self): try: - value = self._semlock._get_value() + value = self.get_value() except Exception: value = 'unknown' return '<%s(value=%s, maxvalue=%s)>' % \ @@ -247,8 +252,8 @@ class Condition(object): def __repr__(self): try: - num_waiters = (self._sleeping_count._semlock._get_value() - - self._woken_count._semlock._get_value()) + num_waiters = (self._sleeping_count.get_value() - + self._woken_count.get_value()) except Exception: num_waiters = 'unknown' return '<%s(%s, %s)>' % (self.__class__.__name__, self._lock, num_waiters) diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py index a1a537dd48d..549fb07c275 100644 --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -126,12 +126,14 @@ abstract_sockets_supported = _platform_supports_abstract_sockets() # Function returning a temp directory which will be removed on exit # -# Maximum length of a socket file path is usually between 92 and 108 [1], -# but Linux is known to use a size of 108 [2]. BSD-based systems usually -# use a size of 104 or 108 and Windows does not create AF_UNIX sockets. +# Maximum length of a NULL-terminated [1] socket file path is usually +# between 92 and 108 [2], but Linux is known to use a size of 108 [3]. +# BSD-based systems usually use a size of 104 or 108 and Windows does +# not create AF_UNIX sockets. # -# [1]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_un.h.html -# [2]: https://man7.org/linux/man-pages/man7/unix.7.html. +# [1]: https://github.com/python/cpython/issues/140734 +# [2]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_un.h.html +# [3]: https://man7.org/linux/man-pages/man7/unix.7.html if sys.platform == 'linux': _SUN_PATH_MAX = 108 @@ -171,11 +173,13 @@ def _get_base_temp_dir(tempfile): # generated by tempfile._RandomNameSequence, which, by design, # is 8 characters long. # - # Thus, the length of socket filename will be: + # Thus, the socket file path length (without NULL terminator) will be: # # len(base_tempdir + '/pymp-XXXXXXXX' + '/sock-XXXXXXXX') sun_path_len = len(base_tempdir) + 14 + 14 - if sun_path_len <= _SUN_PATH_MAX: + # Strict inequality to account for the NULL terminator. + # See https://github.com/python/cpython/issues/140734. + if sun_path_len < _SUN_PATH_MAX: return base_tempdir # Fallback to the default system-wide temporary directory. # This ignores user-defined environment variables. @@ -201,7 +205,7 @@ def _get_base_temp_dir(tempfile): return base_tempdir warn("Ignoring user-defined temporary directory: %s", base_tempdir) # at most max(map(len, dirlist)) + 14 + 14 = 36 characters - assert len(base_system_tempdir) + 14 + 14 <= _SUN_PATH_MAX + assert len(base_system_tempdir) + 14 + 14 < _SUN_PATH_MAX return base_system_tempdir def get_temp_dir(): diff --git a/Lib/netrc.py b/Lib/netrc.py index 2f502c1d533..750b5071e3c 100644 --- a/Lib/netrc.py +++ b/Lib/netrc.py @@ -95,7 +95,7 @@ class netrc: while 1: # Look for a machine, default, or macdef top-level keyword saved_lineno = lexer.lineno - toplevel = tt = lexer.get_token() + tt = lexer.get_token() if not tt: break elif tt[0] == '#': diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 08c529c5963..7d637325240 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -400,17 +400,23 @@ def expanduser(path): # XXX With COMMAND.COM you can use any characters in a variable name, # XXX except '^|<>='. +_varpattern = r"'[^']*'?|%(%|[^%]*%?)|\$(\$|[-\w]+|\{[^}]*\}?)" +_varsub = None +_varsubb = None + def expandvars(path): """Expand shell variables of the forms $var, ${var} and %var%. Unknown variables are left unchanged.""" path = os.fspath(path) + global _varsub, _varsubb if isinstance(path, bytes): if b'$' not in path and b'%' not in path: return path - import string - varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii') - quote = b'\'' + if not _varsubb: + import re + _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub + sub = _varsubb percent = b'%' brace = b'{' rbrace = b'}' @@ -419,94 +425,44 @@ def expandvars(path): else: if '$' not in path and '%' not in path: return path - import string - varchars = string.ascii_letters + string.digits + '_-' - quote = '\'' + if not _varsub: + import re + _varsub = re.compile(_varpattern, re.ASCII).sub + sub = _varsub percent = '%' brace = '{' rbrace = '}' dollar = '$' environ = os.environ - res = path[:0] - index = 0 - pathlen = len(path) - while index < pathlen: - c = path[index:index+1] - if c == quote: # no expansion within single quotes - path = path[index + 1:] - pathlen = len(path) - try: - index = path.index(c) - res += c + path[:index + 1] - except ValueError: - res += c + path - index = pathlen - 1 - elif c == percent: # variable or '%' - if path[index + 1:index + 2] == percent: - res += c - index += 1 - else: - path = path[index+1:] - pathlen = len(path) - try: - index = path.index(percent) - except ValueError: - res += percent + path - index = pathlen - 1 - else: - var = path[:index] - try: - if environ is None: - value = os.fsencode(os.environ[os.fsdecode(var)]) - else: - value = environ[var] - except KeyError: - value = percent + var + percent - res += value - elif c == dollar: # variable or '$$' - if path[index + 1:index + 2] == dollar: - res += c - index += 1 - elif path[index + 1:index + 2] == brace: - path = path[index+2:] - pathlen = len(path) - try: - index = path.index(rbrace) - except ValueError: - res += dollar + brace + path - index = pathlen - 1 - else: - var = path[:index] - try: - if environ is None: - value = os.fsencode(os.environ[os.fsdecode(var)]) - else: - value = environ[var] - except KeyError: - value = dollar + brace + var + rbrace - res += value - else: - var = path[:0] - index += 1 - c = path[index:index + 1] - while c and c in varchars: - var += c - index += 1 - c = path[index:index + 1] - try: - if environ is None: - value = os.fsencode(os.environ[os.fsdecode(var)]) - else: - value = environ[var] - except KeyError: - value = dollar + var - res += value - if c: - index -= 1 + + def repl(m): + lastindex = m.lastindex + if lastindex is None: + return m[0] + name = m[lastindex] + if lastindex == 1: + if name == percent: + return name + if not name.endswith(percent): + return m[0] + name = name[:-1] else: - res += c - index += 1 - return res + if name == dollar: + return name + if name.startswith(brace): + if not name.endswith(rbrace): + return m[0] + name = name[1:-1] + + try: + if environ is None: + return os.fsencode(os.environ[os.fsdecode(name)]) + else: + return environ[name] + except KeyError: + return m[0] + + return sub(repl, path) # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B. @@ -770,7 +726,7 @@ else: try: if _getfinalpathname(spath) == path: path = spath - except ValueError as ex: + except ValueError: # Unexpected, as an invalid path should not have gained a prefix # at any point, but we ignore this error just in case. pass diff --git a/Lib/optparse.py b/Lib/optparse.py index 38cf16d21ef..5ff7f74754f 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -21,8 +21,6 @@ Simple usage example: (options, args) = parser.parse_args() """ -__version__ = "1.5.3" - __all__ = ['Option', 'make_option', 'SUPPRESS_HELP', @@ -1374,7 +1372,7 @@ class OptionParser (OptionContainer): self.values = values try: - stop = self._process_args(largs, rargs, values) + self._process_args(largs, rargs, values) except (BadOptionError, OptionValueError) as err: self.error(str(err)) @@ -1669,3 +1667,12 @@ def _match_abbrev(s, wordmap): # which will become a factory function when there are many Option # classes. make_option = Option + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.5.3" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/os.py b/Lib/os.py index 12926c832f5..52cbc5bc858 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -58,6 +58,11 @@ if 'posix' in _names: __all__.append('_exit') except ImportError: pass + try: + from posix import _clearenv + __all__.append('_clearenv') + except ImportError: + pass import posixpath as path try: @@ -131,6 +136,8 @@ if _exists("_have_functions"): _add("HAVE_UNLINKAT", "unlink") _add("HAVE_UNLINKAT", "rmdir") _add("HAVE_UTIMENSAT", "utime") + if _exists("statx"): + _set.add(statx) supports_dir_fd = _set _set = set() @@ -152,6 +159,8 @@ if _exists("_have_functions"): _add("HAVE_FPATHCONF", "pathconf") if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3 _add("HAVE_FSTATVFS", "statvfs") + if _exists("statx"): + _set.add(statx) supports_fd = _set _set = set() @@ -190,6 +199,8 @@ if _exists("_have_functions"): _add("HAVE_FSTATAT", "stat") _add("HAVE_UTIMENSAT", "utime") _add("MS_WINDOWS", "stat") + if _exists("statx"): + _set.add(statx) supports_follow_symlinks = _set del _set @@ -417,14 +428,16 @@ def walk(top, topdown=True, onerror=None, followlinks=False): # Yield before sub-directory traversal if going top down yield top, dirs, nondirs # Traverse into sub-directories - for dirname in reversed(dirs): - new_path = join(top, dirname) - # bpo-23605: os.path.islink() is used instead of caching - # entry.is_symlink() result during the loop on os.scandir() because - # the caller can replace the directory entry during the "yield" - # above. - if followlinks or not islink(new_path): - stack.append(new_path) + if dirs: + prefix = join(top, top[:0]) # Add trailing slash + for dirname in reversed(dirs): + new_path = prefix + dirname + # bpo-23605: os.path.islink() is used instead of caching + # entry.is_symlink() result during the loop on os.scandir() because + # the caller can replace the directory entry during the "yield" + # above. + if followlinks or not islink(new_path): + stack.append(new_path) else: # Yield after sub-directory traversal if going bottom up stack.append((top, dirs, nondirs)) @@ -766,6 +779,12 @@ class _Environ(MutableMapping): new.update(self) return new + if _exists("_clearenv"): + def clear(self): + _clearenv() + self._data.clear() + + def _create_environ_mapping(): if name == 'nt': # Where Env Var Names Must Be UPPERCASE @@ -813,6 +832,7 @@ if _exists("_create_environ"): env_data.clear() env_data.update(data) + __all__.append("reload_environ") def getenv(key, default=None): """Get an environment variable, return None if it doesn't exist. diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index cea1a9fe57e..44f967eb12d 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -14,7 +14,9 @@ import sys from errno import * from glob import _StringGlobber, _no_recurse_symlinks from itertools import chain -from stat import S_ISDIR, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO +from stat import ( + S_IMODE, S_ISDIR, S_ISREG, S_ISLNK, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO, +) from _collections_abc import Sequence try: @@ -27,10 +29,9 @@ except ImportError: grp = None from pathlib._os import ( - PathInfo, DirEntryInfo, - magic_open, vfspath, + vfsopen, vfspath, ensure_different_files, ensure_distinct_paths, - copyfile2, copyfileobj, copy_info, + copyfile2, copyfileobj, ) @@ -335,13 +336,8 @@ class PurePath: return paths[0] elif paths: # Join path segments from the initializer. - path = self.parser.join(*paths) - # Cache the joined path. - paths.clear() - paths.append(path) - return path + return self.parser.join(*paths) else: - paths.append('') return '' @property @@ -489,16 +485,19 @@ class PurePath: """ if not hasattr(other, 'with_segments'): other = self.with_segments(other) - for step, path in enumerate(chain([other], other.parents)): + parts = [] + for path in chain([other], other.parents): if path == self or path in self.parents: break elif not walk_up: raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") elif path.name == '..': raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") + else: + parts.append('..') else: raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") - parts = ['..'] * step + self._tail[len(path._tail):] + parts.extend(self._tail[len(path._tail):]) return self._from_parsed_parts('', '', parts) def is_relative_to(self, other): @@ -612,6 +611,211 @@ class PureWindowsPath(PurePath): __slots__ = () +_STAT_RESULT_ERROR = [] # falsy sentinel indicating stat() failed. + + +class _Info: + """Implementation of pathlib.types.PathInfo that provides status + information by querying a wrapped os.stat_result object. Don't try to + construct it yourself.""" + __slots__ = ('_path', '_entry', '_stat_result', '_lstat_result') + + def __init__(self, path, entry=None): + self._path = path + self._entry = entry + self._stat_result = None + self._lstat_result = None + + def __repr__(self): + path_type = "WindowsPath" if os.name == "nt" else "PosixPath" + return f"<{path_type}.info>" + + def _stat(self, *, follow_symlinks=True): + """Return the status as an os.stat_result.""" + if self._entry: + return self._entry.stat(follow_symlinks=follow_symlinks) + if follow_symlinks: + if not self._stat_result: + try: + self._stat_result = os.stat(self._path) + except (OSError, ValueError): + self._stat_result = _STAT_RESULT_ERROR + raise + return self._stat_result + else: + if not self._lstat_result: + try: + self._lstat_result = os.lstat(self._path) + except (OSError, ValueError): + self._lstat_result = _STAT_RESULT_ERROR + raise + return self._lstat_result + + def exists(self, *, follow_symlinks=True): + """Whether this path exists.""" + if self._entry: + if not follow_symlinks: + return True + if follow_symlinks: + if self._stat_result is _STAT_RESULT_ERROR: + return False + else: + if self._lstat_result is _STAT_RESULT_ERROR: + return False + try: + self._stat(follow_symlinks=follow_symlinks) + except (OSError, ValueError): + return False + return True + + def is_dir(self, *, follow_symlinks=True): + """Whether this path is a directory.""" + if self._entry: + try: + return self._entry.is_dir(follow_symlinks=follow_symlinks) + except OSError: + return False + if follow_symlinks: + if self._stat_result is _STAT_RESULT_ERROR: + return False + else: + if self._lstat_result is _STAT_RESULT_ERROR: + return False + try: + st = self._stat(follow_symlinks=follow_symlinks) + except (OSError, ValueError): + return False + return S_ISDIR(st.st_mode) + + def is_file(self, *, follow_symlinks=True): + """Whether this path is a regular file.""" + if self._entry: + try: + return self._entry.is_file(follow_symlinks=follow_symlinks) + except OSError: + return False + if follow_symlinks: + if self._stat_result is _STAT_RESULT_ERROR: + return False + else: + if self._lstat_result is _STAT_RESULT_ERROR: + return False + try: + st = self._stat(follow_symlinks=follow_symlinks) + except (OSError, ValueError): + return False + return S_ISREG(st.st_mode) + + def is_symlink(self): + """Whether this path is a symbolic link.""" + if self._entry: + try: + return self._entry.is_symlink() + except OSError: + return False + if self._lstat_result is _STAT_RESULT_ERROR: + return False + try: + st = self._stat(follow_symlinks=False) + except (OSError, ValueError): + return False + return S_ISLNK(st.st_mode) + + def _posix_permissions(self, *, follow_symlinks=True): + """Return the POSIX file permissions.""" + return S_IMODE(self._stat(follow_symlinks=follow_symlinks).st_mode) + + def _file_id(self, *, follow_symlinks=True): + """Returns the identifier of the file.""" + st = self._stat(follow_symlinks=follow_symlinks) + return st.st_dev, st.st_ino + + def _access_time_ns(self, *, follow_symlinks=True): + """Return the access time in nanoseconds.""" + return self._stat(follow_symlinks=follow_symlinks).st_atime_ns + + def _mod_time_ns(self, *, follow_symlinks=True): + """Return the modify time in nanoseconds.""" + return self._stat(follow_symlinks=follow_symlinks).st_mtime_ns + + if hasattr(os.stat_result, 'st_flags'): + def _bsd_flags(self, *, follow_symlinks=True): + """Return the flags.""" + return self._stat(follow_symlinks=follow_symlinks).st_flags + + if hasattr(os, 'listxattr'): + def _xattrs(self, *, follow_symlinks=True): + """Return the xattrs as a list of (attr, value) pairs, or an empty + list if extended attributes aren't supported.""" + try: + return [ + (attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks)) + for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)] + except OSError as err: + if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): + raise + return [] + + +def _copy_info(info, target, follow_symlinks=True): + """Copy metadata from the given PathInfo to the given local path.""" + copy_times_ns = ( + hasattr(info, '_access_time_ns') and + hasattr(info, '_mod_time_ns') and + (follow_symlinks or os.utime in os.supports_follow_symlinks)) + if copy_times_ns: + t0 = info._access_time_ns(follow_symlinks=follow_symlinks) + t1 = info._mod_time_ns(follow_symlinks=follow_symlinks) + os.utime(target, ns=(t0, t1), follow_symlinks=follow_symlinks) + + # We must copy extended attributes before the file is (potentially) + # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. + copy_xattrs = ( + hasattr(info, '_xattrs') and + hasattr(os, 'setxattr') and + (follow_symlinks or os.setxattr in os.supports_follow_symlinks)) + if copy_xattrs: + xattrs = info._xattrs(follow_symlinks=follow_symlinks) + for attr, value in xattrs: + try: + os.setxattr(target, attr, value, follow_symlinks=follow_symlinks) + except OSError as e: + if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): + raise + + copy_posix_permissions = ( + hasattr(info, '_posix_permissions') and + (follow_symlinks or os.chmod in os.supports_follow_symlinks)) + if copy_posix_permissions: + posix_permissions = info._posix_permissions(follow_symlinks=follow_symlinks) + try: + os.chmod(target, posix_permissions, follow_symlinks=follow_symlinks) + except NotImplementedError: + # if we got a NotImplementedError, it's because + # * follow_symlinks=False, + # * lchown() is unavailable, and + # * either + # * fchownat() is unavailable or + # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. + # (it returned ENOSUP.) + # therefore we're out of options--we simply cannot chown the + # symlink. give up, suppress the error. + # (which is what shutil always did in this circumstance.) + pass + + copy_bsd_flags = ( + hasattr(info, '_bsd_flags') and + hasattr(os, 'chflags') and + (follow_symlinks or os.chflags in os.supports_follow_symlinks)) + if copy_bsd_flags: + bsd_flags = info._bsd_flags(follow_symlinks=follow_symlinks) + try: + os.chflags(target, bsd_flags, follow_symlinks=follow_symlinks) + except OSError as why: + if why.errno not in (EOPNOTSUPP, ENOTSUP): + raise + + class Path(PurePath): """PurePath subclass that can make system calls. @@ -637,7 +841,7 @@ class Path(PurePath): try: return self._info except AttributeError: - self._info = PathInfo(self) + self._info = _Info(str(self)) return self._info def stat(self, *, follow_symlinks=True): @@ -817,7 +1021,7 @@ class Path(PurePath): def _from_dir_entry(self, dir_entry, path_str): path = self.with_segments(path_str) path._str = path_str - path._info = DirEntryInfo(dir_entry) + path._info = _Info(dir_entry.path, dir_entry) return path def iterdir(self): @@ -1123,17 +1327,17 @@ class Path(PurePath): self.joinpath(child.name)._copy_from( child, follow_symlinks, preserve_metadata) if preserve_metadata: - copy_info(source.info, self) + _copy_info(source.info, self) else: self._copy_from_file(source, preserve_metadata) def _copy_from_file(self, source, preserve_metadata=False): ensure_different_files(source, self) - with magic_open(source, 'rb') as source_f: + with vfsopen(source, 'rb') as source_f: with open(self, 'wb') as target_f: copyfileobj(source_f, target_f) if preserve_metadata: - copy_info(source.info, self) + _copy_info(source.info, self) if copyfile2: # Use fast OS routine for local file copying where available. @@ -1155,12 +1359,12 @@ class Path(PurePath): def _copy_from_symlink(self, source, preserve_metadata=False): os.symlink(vfspath(source.readlink()), self, source.info.is_dir()) if preserve_metadata: - copy_info(source.info, self, follow_symlinks=False) + _copy_info(source.info, self, follow_symlinks=False) else: def _copy_from_symlink(self, source, preserve_metadata=False): os.symlink(vfspath(source.readlink()), self) if preserve_metadata: - copy_info(source.info, self, follow_symlinks=False) + _copy_info(source.info, self, follow_symlinks=False) def move(self, target): """ diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py new file mode 100644 index 00000000000..58e137f2a92 --- /dev/null +++ b/Lib/pathlib/_local.py @@ -0,0 +1,12 @@ +""" +This module exists so that pathlib objects pickled under Python 3.13 can be +unpickled in 3.14+. +""" + +from pathlib import * + +__all__ = [ + "UnsupportedOperation", + "PurePath", "PurePosixPath", "PureWindowsPath", + "Path", "PosixPath", "WindowsPath", +] diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py index fbcbfb979d1..79a1969d5f8 100644 --- a/Lib/pathlib/_os.py +++ b/Lib/pathlib/_os.py @@ -4,7 +4,6 @@ Low-level OS functionality wrappers used by pathlib. from errno import * from io import TextIOWrapper, text_encoding -from stat import S_ISDIR, S_ISREG, S_ISLNK, S_IMODE import os import sys try: @@ -166,48 +165,86 @@ def copyfileobj(source_f, target_f): write_target(buf) -def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, - newline=None): +def _open_reader(obj): + cls = type(obj) + try: + open_reader = cls.__open_reader__ + except AttributeError: + cls_name = cls.__name__ + raise TypeError(f"{cls_name} can't be opened for reading") from None + else: + return open_reader(obj) + + +def _open_writer(obj, mode): + cls = type(obj) + try: + open_writer = cls.__open_writer__ + except AttributeError: + cls_name = cls.__name__ + raise TypeError(f"{cls_name} can't be opened for writing") from None + else: + return open_writer(obj, mode) + + +def _open_updater(obj, mode): + cls = type(obj) + try: + open_updater = cls.__open_updater__ + except AttributeError: + cls_name = cls.__name__ + raise TypeError(f"{cls_name} can't be opened for updating") from None + else: + return open_updater(obj, mode) + + +def vfsopen(obj, mode='r', buffering=-1, encoding=None, errors=None, + newline=None): """ Open the file pointed to by this path and return a file object, as the built-in open() function does. + + Unlike the built-in open() function, this function additionally accepts + 'openable' objects, which are objects with any of these special methods: + + __open_reader__() + __open_writer__(mode) + __open_updater__(mode) + + '__open_reader__' is called for 'r' mode; '__open_writer__' for 'a', 'w' + and 'x' modes; and '__open_updater__' for 'r+' and 'w+' modes. If text + mode is requested, the result is wrapped in an io.TextIOWrapper object. """ + if buffering != -1: + raise ValueError("buffer size can't be customized") text = 'b' not in mode if text: # Call io.text_encoding() here to ensure any warning is raised at an # appropriate stack level. encoding = text_encoding(encoding) try: - return open(path, mode, buffering, encoding, errors, newline) + return open(obj, mode, buffering, encoding, errors, newline) except TypeError: pass - cls = type(path) + if not text: + if encoding is not None: + raise ValueError("binary mode doesn't take an encoding argument") + if errors is not None: + raise ValueError("binary mode doesn't take an errors argument") + if newline is not None: + raise ValueError("binary mode doesn't take a newline argument") mode = ''.join(sorted(c for c in mode if c not in 'bt')) - if text: - try: - attr = getattr(cls, f'__open_{mode}__') - except AttributeError: - pass - else: - return attr(path, buffering, encoding, errors, newline) - elif encoding is not None: - raise ValueError("binary mode doesn't take an encoding argument") - elif errors is not None: - raise ValueError("binary mode doesn't take an errors argument") - elif newline is not None: - raise ValueError("binary mode doesn't take a newline argument") - - try: - attr = getattr(cls, f'__open_{mode}b__') - except AttributeError: - pass + if mode == 'r': + stream = _open_reader(obj) + elif mode in ('a', 'w', 'x'): + stream = _open_writer(obj, mode) + elif mode in ('+r', '+w'): + stream = _open_updater(obj, mode[1]) else: - stream = attr(path, buffering) - if text: - stream = TextIOWrapper(stream, encoding, errors, newline) - return stream - - raise TypeError(f"{cls.__name__} can't be opened with mode {mode!r}") + raise ValueError(f'invalid mode: {mode}') + if text: + stream = TextIOWrapper(stream, encoding, errors, newline) + return stream def vfspath(obj): @@ -264,281 +301,3 @@ def ensure_different_files(source, target): err.filename = vfspath(source) err.filename2 = vfspath(target) raise err - - -def copy_info(info, target, follow_symlinks=True): - """Copy metadata from the given PathInfo to the given local path.""" - copy_times_ns = ( - hasattr(info, '_access_time_ns') and - hasattr(info, '_mod_time_ns') and - (follow_symlinks or os.utime in os.supports_follow_symlinks)) - if copy_times_ns: - t0 = info._access_time_ns(follow_symlinks=follow_symlinks) - t1 = info._mod_time_ns(follow_symlinks=follow_symlinks) - os.utime(target, ns=(t0, t1), follow_symlinks=follow_symlinks) - - # We must copy extended attributes before the file is (potentially) - # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. - copy_xattrs = ( - hasattr(info, '_xattrs') and - hasattr(os, 'setxattr') and - (follow_symlinks or os.setxattr in os.supports_follow_symlinks)) - if copy_xattrs: - xattrs = info._xattrs(follow_symlinks=follow_symlinks) - for attr, value in xattrs: - try: - os.setxattr(target, attr, value, follow_symlinks=follow_symlinks) - except OSError as e: - if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): - raise - - copy_posix_permissions = ( - hasattr(info, '_posix_permissions') and - (follow_symlinks or os.chmod in os.supports_follow_symlinks)) - if copy_posix_permissions: - posix_permissions = info._posix_permissions(follow_symlinks=follow_symlinks) - try: - os.chmod(target, posix_permissions, follow_symlinks=follow_symlinks) - except NotImplementedError: - # if we got a NotImplementedError, it's because - # * follow_symlinks=False, - # * lchown() is unavailable, and - # * either - # * fchownat() is unavailable or - # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. - # (it returned ENOSUP.) - # therefore we're out of options--we simply cannot chown the - # symlink. give up, suppress the error. - # (which is what shutil always did in this circumstance.) - pass - - copy_bsd_flags = ( - hasattr(info, '_bsd_flags') and - hasattr(os, 'chflags') and - (follow_symlinks or os.chflags in os.supports_follow_symlinks)) - if copy_bsd_flags: - bsd_flags = info._bsd_flags(follow_symlinks=follow_symlinks) - try: - os.chflags(target, bsd_flags, follow_symlinks=follow_symlinks) - except OSError as why: - if why.errno not in (EOPNOTSUPP, ENOTSUP): - raise - - -class _PathInfoBase: - __slots__ = ('_path', '_stat_result', '_lstat_result') - - def __init__(self, path): - self._path = str(path) - - def __repr__(self): - path_type = "WindowsPath" if os.name == "nt" else "PosixPath" - return f"<{path_type}.info>" - - def _stat(self, *, follow_symlinks=True, ignore_errors=False): - """Return the status as an os.stat_result, or None if stat() fails and - ignore_errors is true.""" - if follow_symlinks: - try: - result = self._stat_result - except AttributeError: - pass - else: - if ignore_errors or result is not None: - return result - try: - self._stat_result = os.stat(self._path) - except (OSError, ValueError): - self._stat_result = None - if not ignore_errors: - raise - return self._stat_result - else: - try: - result = self._lstat_result - except AttributeError: - pass - else: - if ignore_errors or result is not None: - return result - try: - self._lstat_result = os.lstat(self._path) - except (OSError, ValueError): - self._lstat_result = None - if not ignore_errors: - raise - return self._lstat_result - - def _posix_permissions(self, *, follow_symlinks=True): - """Return the POSIX file permissions.""" - return S_IMODE(self._stat(follow_symlinks=follow_symlinks).st_mode) - - def _file_id(self, *, follow_symlinks=True): - """Returns the identifier of the file.""" - st = self._stat(follow_symlinks=follow_symlinks) - return st.st_dev, st.st_ino - - def _access_time_ns(self, *, follow_symlinks=True): - """Return the access time in nanoseconds.""" - return self._stat(follow_symlinks=follow_symlinks).st_atime_ns - - def _mod_time_ns(self, *, follow_symlinks=True): - """Return the modify time in nanoseconds.""" - return self._stat(follow_symlinks=follow_symlinks).st_mtime_ns - - if hasattr(os.stat_result, 'st_flags'): - def _bsd_flags(self, *, follow_symlinks=True): - """Return the flags.""" - return self._stat(follow_symlinks=follow_symlinks).st_flags - - if hasattr(os, 'listxattr'): - def _xattrs(self, *, follow_symlinks=True): - """Return the xattrs as a list of (attr, value) pairs, or an empty - list if extended attributes aren't supported.""" - try: - return [ - (attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks)) - for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)] - except OSError as err: - if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): - raise - return [] - - -class _WindowsPathInfo(_PathInfoBase): - """Implementation of pathlib.types.PathInfo that provides status - information for Windows paths. Don't try to construct it yourself.""" - __slots__ = ('_exists', '_is_dir', '_is_file', '_is_symlink') - - def exists(self, *, follow_symlinks=True): - """Whether this path exists.""" - if not follow_symlinks and self.is_symlink(): - return True - try: - return self._exists - except AttributeError: - if os.path.exists(self._path): - self._exists = True - return True - else: - self._exists = self._is_dir = self._is_file = False - return False - - def is_dir(self, *, follow_symlinks=True): - """Whether this path is a directory.""" - if not follow_symlinks and self.is_symlink(): - return False - try: - return self._is_dir - except AttributeError: - if os.path.isdir(self._path): - self._is_dir = self._exists = True - return True - else: - self._is_dir = False - return False - - def is_file(self, *, follow_symlinks=True): - """Whether this path is a regular file.""" - if not follow_symlinks and self.is_symlink(): - return False - try: - return self._is_file - except AttributeError: - if os.path.isfile(self._path): - self._is_file = self._exists = True - return True - else: - self._is_file = False - return False - - def is_symlink(self): - """Whether this path is a symbolic link.""" - try: - return self._is_symlink - except AttributeError: - self._is_symlink = os.path.islink(self._path) - return self._is_symlink - - -class _PosixPathInfo(_PathInfoBase): - """Implementation of pathlib.types.PathInfo that provides status - information for POSIX paths. Don't try to construct it yourself.""" - __slots__ = () - - def exists(self, *, follow_symlinks=True): - """Whether this path exists.""" - st = self._stat(follow_symlinks=follow_symlinks, ignore_errors=True) - if st is None: - return False - return True - - def is_dir(self, *, follow_symlinks=True): - """Whether this path is a directory.""" - st = self._stat(follow_symlinks=follow_symlinks, ignore_errors=True) - if st is None: - return False - return S_ISDIR(st.st_mode) - - def is_file(self, *, follow_symlinks=True): - """Whether this path is a regular file.""" - st = self._stat(follow_symlinks=follow_symlinks, ignore_errors=True) - if st is None: - return False - return S_ISREG(st.st_mode) - - def is_symlink(self): - """Whether this path is a symbolic link.""" - st = self._stat(follow_symlinks=False, ignore_errors=True) - if st is None: - return False - return S_ISLNK(st.st_mode) - - -PathInfo = _WindowsPathInfo if os.name == 'nt' else _PosixPathInfo - - -class DirEntryInfo(_PathInfoBase): - """Implementation of pathlib.types.PathInfo that provides status - information by querying a wrapped os.DirEntry object. Don't try to - construct it yourself.""" - __slots__ = ('_entry',) - - def __init__(self, entry): - super().__init__(entry.path) - self._entry = entry - - def _stat(self, *, follow_symlinks=True, ignore_errors=False): - try: - return self._entry.stat(follow_symlinks=follow_symlinks) - except OSError: - if not ignore_errors: - raise - return None - - def exists(self, *, follow_symlinks=True): - """Whether this path exists.""" - if not follow_symlinks: - return True - return self._stat(ignore_errors=True) is not None - - def is_dir(self, *, follow_symlinks=True): - """Whether this path is a directory.""" - try: - return self._entry.is_dir(follow_symlinks=follow_symlinks) - except OSError: - return False - - def is_file(self, *, follow_symlinks=True): - """Whether this path is a regular file.""" - try: - return self._entry.is_file(follow_symlinks=follow_symlinks) - except OSError: - return False - - def is_symlink(self): - """Whether this path is a symbolic link.""" - try: - return self._entry.is_symlink() - except OSError: - return False diff --git a/Lib/pathlib/types.py b/Lib/pathlib/types.py index 42b80221608..f21ce077454 100644 --- a/Lib/pathlib/types.py +++ b/Lib/pathlib/types.py @@ -13,7 +13,7 @@ Protocols for supporting classes in pathlib. from abc import ABC, abstractmethod from glob import _GlobberBase from io import text_encoding -from pathlib._os import (magic_open, vfspath, ensure_distinct_paths, +from pathlib._os import (vfsopen, vfspath, ensure_distinct_paths, ensure_different_files, copyfileobj) from pathlib import PurePath, Path from typing import Optional, Protocol, runtime_checkable @@ -234,6 +234,33 @@ class _JoinablePath(ABC): parent = split(path)[0] return tuple(parents) + def relative_to(self, other, *, walk_up=False): + """Return the relative path to another path identified by the passed + arguments. If the operation is not possible (because this is not + related to the other path), raise ValueError. + + The *walk_up* parameter controls whether `..` may be used to resolve + the path. + """ + parts = [] + for path in (other,) + other.parents: + if self.is_relative_to(path): + break + elif not walk_up: + raise ValueError(f"{self!r} is not in the subpath of {other!r}") + elif path.name == '..': + raise ValueError(f"'..' segment in {other!r} cannot be walked") + else: + parts.append('..') + else: + raise ValueError(f"{self!r} and {other!r} have different anchors") + return self.with_segments(*parts, *self.parts[len(path.parts):]) + + def is_relative_to(self, other): + """Return True if the path is relative to another path or False. + """ + return other == self or other in self.parents + def full_match(self, pattern): """ Return True if this path matches the given glob-style pattern. The @@ -264,10 +291,10 @@ class _ReadablePath(_JoinablePath): raise NotImplementedError @abstractmethod - def __open_rb__(self, buffering=-1): + def __open_reader__(self): """ Open the file pointed to by this path for reading in binary mode and - return a file object, like open(mode='rb'). + return a file object. """ raise NotImplementedError @@ -275,7 +302,7 @@ class _ReadablePath(_JoinablePath): """ Open the file in bytes mode, read it, and close the file. """ - with magic_open(self, mode='rb', buffering=0) as f: + with vfsopen(self, mode='rb') as f: return f.read() def read_text(self, encoding=None, errors=None, newline=None): @@ -285,7 +312,7 @@ class _ReadablePath(_JoinablePath): # Call io.text_encoding() here to ensure any warning is raised at an # appropriate stack level. encoding = text_encoding(encoding) - with magic_open(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f: + with vfsopen(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f: return f.read() @abstractmethod @@ -394,10 +421,10 @@ class _WritablePath(_JoinablePath): raise NotImplementedError @abstractmethod - def __open_wb__(self, buffering=-1): + def __open_writer__(self, mode): """ Open the file pointed to by this path for writing in binary mode and - return a file object, like open(mode='wb'). + return a file object. """ raise NotImplementedError @@ -407,7 +434,7 @@ class _WritablePath(_JoinablePath): """ # type-check for the buffer interface before truncating the file view = memoryview(data) - with magic_open(self, mode='wb') as f: + with vfsopen(self, mode='wb') as f: return f.write(view) def write_text(self, data, encoding=None, errors=None, newline=None): @@ -420,7 +447,7 @@ class _WritablePath(_JoinablePath): if not isinstance(data, str): raise TypeError('data must be str, not %s' % data.__class__.__name__) - with magic_open(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f: + with vfsopen(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f: return f.write(data) def _copy_from(self, source, follow_symlinks=True): @@ -439,8 +466,8 @@ class _WritablePath(_JoinablePath): stack.append((child, dst.joinpath(child.name))) else: ensure_different_files(src, dst) - with magic_open(src, 'rb') as source_f: - with magic_open(dst, 'wb') as target_f: + with vfsopen(src, 'rb') as source_f: + with vfsopen(dst, 'wb') as target_f: copyfileobj(source_f, target_f) diff --git a/Lib/pdb.py b/Lib/pdb.py index fc83728fb6d..c1a5db080dc 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -100,7 +100,6 @@ import _colorize import _pyrepl.utils from contextlib import ExitStack, closing, contextmanager -from rlcompleter import Completer from types import CodeType from warnings import deprecated @@ -131,7 +130,7 @@ def find_first_executable_line(code): return code.co_firstlineno def find_function(funcname, filename): - cre = re.compile(r'def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname)) + cre = re.compile(r'(?:async\s+)?def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname)) try: fp = tokenize.open(filename) except OSError: @@ -184,20 +183,38 @@ class _ExecutableTarget: class _ScriptTarget(_ExecutableTarget): def __init__(self, target): - self._target = os.path.realpath(target) + self._check(target) + self._target = self._safe_realpath(target) - if not os.path.exists(self._target): - print(f'Error: {target} does not exist') - sys.exit(1) - if os.path.isdir(self._target): - print(f'Error: {target} is a directory') - sys.exit(1) - - # If safe_path(-P) is not set, sys.path[0] is the directory + # If PYTHONSAFEPATH (-P) is not set, sys.path[0] is the directory # of pdb, and we should replace it with the directory of the script if not sys.flags.safe_path: sys.path[0] = os.path.dirname(self._target) + @staticmethod + def _check(target): + """ + Check that target is plausibly a script. + """ + if not os.path.exists(target): + print(f'Error: {target} does not exist') + sys.exit(1) + if os.path.isdir(target): + print(f'Error: {target} is a directory') + sys.exit(1) + + @staticmethod + def _safe_realpath(path): + """ + Return the canonical path (realpath) if it is accessible from the userspace. + Otherwise (for example, if the path is a symlink to an anonymous pipe), + return the original path. + + See GH-142315. + """ + realpath = os.path.realpath(path) + return realpath if os.path.exists(realpath) else path + def __repr__(self): return self._target @@ -347,8 +364,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): bdb.Bdb.__init__(self, skip=skip, backend=backend if backend else get_default_backend()) cmd.Cmd.__init__(self, completekey, stdin, stdout) sys.audit("pdb.Pdb") - if stdout: - self.use_rawinput = 0 + if stdin: + self.use_rawinput = False self.prompt = '(Pdb) ' self.aliases = {} self.displaying = {} @@ -364,6 +381,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): readline.set_completer_delims(' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') except ImportError: pass + self.allow_kbdint = False self.nosigint = nosigint # Consider these characters as part of the command so when the users type @@ -398,6 +416,12 @@ class Pdb(bdb.Bdb, cmd.Cmd): self._current_task = None + self.lineno = None + self.stack = [] + self.curindex = 0 + self.curframe = None + self._user_requested_quit = False + def set_trace(self, frame=None, *, commands=None): Pdb._last_pdb_instance = self if frame is None: @@ -474,7 +498,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): self.lineno = None self.stack = [] self.curindex = 0 - if hasattr(self, 'curframe') and self.curframe: + if self.curframe: self.curframe.f_globals.pop('__pdb_convenience_variables', None) self.curframe = None self.tb_lineno.clear() @@ -648,7 +672,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): def _get_tb_and_exceptions(self, tb_or_exc): """ - Given a tracecack or an exception, return a tuple of chained exceptions + Given a traceback or an exception, return a tuple of chained exceptions and current traceback to inspect. This will deal with selecting the right ``__cause__`` or ``__context__`` @@ -1092,6 +1116,31 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Generic completion functions. Individual complete_foo methods can be # assigned below to one of these functions. + @property + def rlcompleter(self): + """Return the `Completer` class from `rlcompleter`, while avoiding the + side effects of changing the completer from `import rlcompleter`. + + This is a compromise between GH-138860 and GH-139289. If GH-139289 is + fixed, then we don't need this and we can just `import rlcompleter` in + `Pdb.__init__`. + """ + if not hasattr(self, "_rlcompleter"): + try: + import readline + except ImportError: + # readline is not available, just get the Completer + from rlcompleter import Completer + self._rlcompleter = Completer + else: + # importing rlcompleter could have side effect of changing + # the current completer, we need to restore it + prev_completer = readline.get_completer() + from rlcompleter import Completer + self._rlcompleter = Completer + readline.set_completer(prev_completer) + return self._rlcompleter + def completenames(self, text, line, begidx, endidx): # Overwrite completenames() of cmd so for the command completion, # if no current command matches, check for expressions as well @@ -1186,10 +1235,9 @@ class Pdb(bdb.Bdb, cmd.Cmd): conv_vars = self.curframe.f_globals.get('__pdb_convenience_variables', {}) return [f"${name}" for name in conv_vars if name.startswith(text[1:])] - # Use rlcompleter to do the completion state = 0 matches = [] - completer = Completer(self.curframe.f_globals | self.curframe.f_locals) + completer = self.rlcompleter(self.curframe.f_globals | self.curframe.f_locals) while (match := completer.complete(text, state)) is not None: matches.append(match) state += 1 @@ -1204,8 +1252,8 @@ class Pdb(bdb.Bdb, cmd.Cmd): return try: + completer = self.rlcompleter(ns) old_completer = readline.get_completer() - completer = Completer(ns) readline.set_completer(completer.complete) yield finally: @@ -1457,7 +1505,9 @@ class Pdb(bdb.Bdb, cmd.Cmd): f = self.lookupmodule(parts[0]) if f: fname = f - item = parts[1] + item = parts[1] + else: + return failed answer = find_function(item, self.canonic(fname)) return answer or failed @@ -1469,7 +1519,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): """ # this method should be callable before starting debugging, so default # to "no globals" if there is no current frame - frame = getattr(self, 'curframe', None) + frame = self.curframe if module_globals is None: module_globals = frame.f_globals if frame else None line = linecache.getline(filename, lineno, module_globals) @@ -2399,7 +2449,9 @@ class Pdb(bdb.Bdb, cmd.Cmd): except KeyboardInterrupt: pass - def print_stack_entry(self, frame_lineno, prompt_prefix=line_prefix): + def print_stack_entry(self, frame_lineno, prompt_prefix=None): + if prompt_prefix is None: + prompt_prefix = line_prefix frame, lineno = frame_lineno if frame is self.curframe: prefix = '> ' @@ -3504,7 +3556,29 @@ To let the script run up to a given line X in the debugged file, use "-c 'until X'".""" -def main(): +def exit_with_permission_help_text(): + """ + Prints a message pointing to platform-specific permission help text and exits the program. + This function is called when a PermissionError is encountered while trying + to attach to a process. + """ + print( + "Error: The specified process cannot be attached to due to insufficient permissions.\n" + "See the Python documentation for details on required privileges and troubleshooting:\n" + "https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n" + ) + sys.exit(1) + + +def parse_args(): + # We want pdb to be as intuitive as possible to users, so we need to do some + # heuristic parsing to deal with ambiguity. + # For example: + # "python -m pdb -m foo -p 1" should pass "-p 1" to "foo". + # "python -m pdb foo.py -m bar" should pass "-m bar" to "foo.py". + # "python -m pdb -m foo -m bar" should pass "-m bar" to "foo". + # This require some customized parsing logic to find the actual debug target. + import argparse parser = argparse.ArgumentParser( @@ -3515,55 +3589,63 @@ def main(): color=True, ) - # We need to maunally get the script from args, because the first positional - # arguments could be either the script we need to debug, or the argument - # to the -m module + # Get all the commands out first. For backwards compatibility, we allow + # -c commands to be after the target. parser.add_argument('-c', '--command', action='append', default=[], metavar='command', dest='commands', help='pdb commands to execute as if given in a .pdbrc file') - parser.add_argument('-m', metavar='module', dest='module') - parser.add_argument('-p', '--pid', type=int, help="attach to the specified PID", default=None) - - if len(sys.argv) == 1: - # If no arguments were given (python -m pdb), print the whole help message. - # Without this check, argparse would only complain about missing required arguments. - parser.print_help() - sys.exit(2) opts, args = parser.parse_known_args() - if opts.pid: - # If attaching to a remote pid, unrecognized arguments are not allowed. - # This will raise an error if there are extra unrecognized arguments. - opts = parser.parse_args() - if opts.module: - parser.error("argument -m: not allowed with argument --pid") - attach(opts.pid, opts.commands) - return - elif opts.module: - # If a module is being debugged, we consider the arguments after "-m module" to - # be potential arguments to the module itself. We need to parse the arguments - # before "-m" to check if there is any invalid argument. - # e.g. "python -m pdb -m foo --spam" means passing "--spam" to "foo" - # "python -m pdb --spam -m foo" means passing "--spam" to "pdb" and is invalid - idx = sys.argv.index('-m') - args_to_pdb = sys.argv[1:idx] - # This will raise an error if there are invalid arguments - parser.parse_args(args_to_pdb) - else: - # If a script is being debugged, then pdb expects the script name as the first argument. - # Anything before the script is considered an argument to pdb itself, which would - # be invalid because it's not parsed by argparse. + if not args: + # If no arguments were given (python -m pdb), print the whole help message. + # Without this check, argparse would only complain about missing required arguments. + # We need to add the arguments definitions here to get a proper help message. + parser.add_argument('-m', metavar='module', dest='module') + parser.add_argument('-p', '--pid', type=int, help="attach to the specified PID", default=None) + parser.print_help() + sys.exit(2) + elif args[0] == '-p' or args[0] == '--pid': + # Attach to a pid + parser.add_argument('-p', '--pid', type=int, help="attach to the specified PID", default=None) + opts, args = parser.parse_known_args() + if args: + # For --pid, any extra arguments are invalid. + parser.error(f"unrecognized arguments: {' '.join(args)}") + elif args[0] == '-m': + # Debug a module, we only need the first -m module argument. + # The rest is passed to the module itself. + parser.add_argument('-m', metavar='module', dest='module') + opt_module = parser.parse_args(args[:2]) + opts.module = opt_module.module + args = args[2:] + elif args[0].startswith('-'): + # Invalid argument before the script name. invalid_args = list(itertools.takewhile(lambda a: a.startswith('-'), args)) - if invalid_args: - parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") - sys.exit(2) + parser.error(f"unrecognized arguments: {' '.join(invalid_args)}") - if opts.module: + # Otherwise it's debugging a script and we already parsed all -c commands. + + return opts, args + +def main(): + opts, args = parse_args() + + if getattr(opts, 'pid', None) is not None: + try: + attach(opts.pid, opts.commands) + except RuntimeError: + print( + f"Cannot attach to pid {opts.pid}, please make sure that the process exists " + "and is using the same Python version." + ) + sys.exit(1) + except PermissionError: + exit_with_permission_help_text() + return + elif getattr(opts, 'module', None) is not None: file = opts.module target = _ModuleTarget(file) else: - if not args: - parser.error("no module or script to run") file = args.pop(0) if file.endswith('.pyz'): target = _ZipTarget(file) diff --git a/Lib/pickle.py b/Lib/pickle.py index beaefae0479..71c12c50f7f 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -17,7 +17,6 @@ Functions: Misc variables: - __version__ format_version compatible_formats @@ -190,6 +189,11 @@ READONLY_BUFFER = b'\x98' # make top of stack readonly __all__.extend(x for x in dir() if x.isupper() and not x.startswith('_')) +# Data larger than this will be read in chunks, to prevent extreme +# overallocation. +_MIN_READ_BUF_SIZE = (1 << 20) + + class _Framer: _FRAME_SIZE_MIN = 4 @@ -288,7 +292,7 @@ class _Unframer: "pickle exhausted before end of frame") return data else: - return self.file_read(n) + return self._chunked_file_read(n) def readline(self): if self.current_frame: @@ -303,11 +307,23 @@ class _Unframer: else: return self.file_readline() + def _chunked_file_read(self, size): + cursize = min(size, _MIN_READ_BUF_SIZE) + b = self.file_read(cursize) + while cursize < size and len(b) == cursize: + delta = min(cursize, size - cursize) + b += self.file_read(delta) + cursize += delta + return b + def load_frame(self, frame_size): if self.current_frame and self.current_frame.read() != b'': raise UnpicklingError( "beginning of a new frame before end of current frame") - self.current_frame = io.BytesIO(self.file_read(frame_size)) + data = self._chunked_file_read(frame_size) + if len(data) < frame_size: + raise EOFError + self.current_frame = io.BytesIO(data) # Tools used for pickling. @@ -1153,7 +1169,6 @@ class _Pickler: def save_global(self, obj, name=None): write = self.write - memo = self.memo if name is None: name = getattr(obj, '__qualname__', None) @@ -1497,12 +1512,17 @@ class _Unpickler: dispatch[BINBYTES8[0]] = load_binbytes8 def load_bytearray8(self): - len, = unpack(' maxsize: + size, = unpack(' maxsize: raise UnpicklingError("BYTEARRAY8 exceeds system's maximum size " "of %d bytes" % maxsize) - b = bytearray(len) - self.readinto(b) + cursize = min(size, _MIN_READ_BUF_SIZE) + b = bytearray(cursize) + if self.readinto(b) == cursize: + while cursize < size and len(b) == cursize: + delta = min(cursize, size - cursize) + b += self.read(delta) + cursize += delta self.append(b) dispatch[BYTEARRAY8[0]] = load_bytearray8 @@ -1735,7 +1755,7 @@ class _Unpickler: i = self.read(1)[0] try: self.append(self.memo[i]) - except KeyError as exc: + except KeyError: msg = f'Memo value not found at index {i}' raise UnpicklingError(msg) from None dispatch[BINGET[0]] = load_binget @@ -1744,7 +1764,7 @@ class _Unpickler: i, = unpack(' V(ver): ver = glibcversion elif so: - if lib != 'glibc': + if lib not in ('glibc', 'musl'): lib = 'libc' if soversion and (not ver or V(soversion) > V(ver)): ver = soversion @@ -241,6 +246,10 @@ def libc_ver(executable=None, lib='', version='', chunksize=16384): lib = 'musl' if not ver or V(muslversion) > V(ver): ver = muslversion + elif musl_so: + lib = 'musl' + if musl_sover and (not ver or V(musl_sover) > V(ver)): + ver = musl_sover pos = m.end() return lib, version if ver is None else ver @@ -296,8 +305,7 @@ def _syscmd_ver(system='', release='', version='', text=True, encoding="locale", shell=True) - except (OSError, subprocess.CalledProcessError) as why: - #print('Command %s failed: %s' % (cmd, why)) + except (OSError, subprocess.CalledProcessError): continue else: break @@ -1425,5 +1433,14 @@ def _main(args: list[str] | None = None): print(platform(aliased, terse)) +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "1.1.0" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + if __name__ == "__main__": _main() diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 67e832db217..655c51eea3d 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -73,6 +73,9 @@ from xml.parsers.expat import ParserCreate PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__) globals().update(PlistFormat.__members__) +# Data larger than this will be read in chunks, to prevent extreme +# overallocation. +_MIN_READ_BUF_SIZE = 1 << 20 class UID: def __init__(self, data): @@ -508,12 +511,24 @@ class _BinaryPlistParser: return tokenL + def _read(self, size): + cursize = min(size, _MIN_READ_BUF_SIZE) + data = self._fp.read(cursize) + while True: + if len(data) != cursize: + raise InvalidFileException + if cursize == size: + return data + delta = min(cursize, size - cursize) + data += self._fp.read(delta) + cursize += delta + def _read_ints(self, n, size): - data = self._fp.read(size * n) + data = self._read(size * n) if size in _BINARY_FORMAT: return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data) else: - if not size or len(data) != size * n: + if not size: raise InvalidFileException() return tuple(int.from_bytes(data[i: i + size], 'big') for i in range(0, size * n, size)) @@ -573,22 +588,16 @@ class _BinaryPlistParser: elif tokenH == 0x40: # data s = self._get_size(tokenL) - result = self._fp.read(s) - if len(result) != s: - raise InvalidFileException() + result = self._read(s) elif tokenH == 0x50: # ascii string s = self._get_size(tokenL) - data = self._fp.read(s) - if len(data) != s: - raise InvalidFileException() + data = self._read(s) result = data.decode('ascii') elif tokenH == 0x60: # unicode string s = self._get_size(tokenL) * 2 - data = self._fp.read(s) - if len(data) != s: - raise InvalidFileException() + data = self._read(s) result = data.decode('utf-16be') elif tokenH == 0x80: # UID diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 7aaf9ff4faa..1ee27de3206 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -285,42 +285,41 @@ def expanduser(path): # This expands the forms $variable and ${variable} only. # Non-existent variables are left unchanged. -_varprog = None -_varprogb = None +_varpattern = r'\$(\w+|\{[^}]*\}?)' +_varsub = None +_varsubb = None def expandvars(path): """Expand shell variables of form $var and ${var}. Unknown variables are left unchanged.""" path = os.fspath(path) - global _varprog, _varprogb + global _varsub, _varsubb if isinstance(path, bytes): if b'$' not in path: return path - if not _varprogb: + if not _varsubb: import re - _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII) - search = _varprogb.search + _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub + sub = _varsubb start = b'{' end = b'}' environ = getattr(os, 'environb', None) else: if '$' not in path: return path - if not _varprog: + if not _varsub: import re - _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII) - search = _varprog.search + _varsub = re.compile(_varpattern, re.ASCII).sub + sub = _varsub start = '{' end = '}' environ = os.environ - i = 0 - while True: - m = search(path, i) - if not m: - break - i, j = m.span(0) - name = m.group(1) - if name.startswith(start) and name.endswith(end): + + def repl(m): + name = m[1] + if name.startswith(start): + if not name.endswith(end): + return m[0] name = name[1:-1] try: if environ is None: @@ -328,13 +327,11 @@ def expandvars(path): else: value = environ[name] except KeyError: - i = j + return m[0] else: - tail = path[j:] - path = path[:i] + value - i = len(path) - path += tail - return path + return value + + return sub(repl, path) # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. diff --git a/Lib/profile.py b/Lib/profile.py index 20c500d28bc..304284da421 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -607,7 +607,6 @@ def main(): '__file__': spec.origin, '__name__': spec.name, '__package__': None, - '__cached__': None, } try: runctx(code, globs, None, options.outfile, options.sort) diff --git a/Lib/profiling/sampling/__init__.py b/Lib/profiling/sampling/__init__.py index 1745067bbb7..6a0bb5e5c2f 100644 --- a/Lib/profiling/sampling/__init__.py +++ b/Lib/profiling/sampling/__init__.py @@ -7,5 +7,8 @@ call stack rather than tracing every function call. from .collector import Collector from .pstats_collector import PstatsCollector from .stack_collector import CollapsedStackCollector +from .heatmap_collector import HeatmapCollector +from .gecko_collector import GeckoCollector +from .string_table import StringTable -__all__ = ("Collector", "PstatsCollector", "CollapsedStackCollector") +__all__ = ("Collector", "PstatsCollector", "CollapsedStackCollector", "HeatmapCollector", "GeckoCollector", "StringTable") diff --git a/Lib/profiling/sampling/__main__.py b/Lib/profiling/sampling/__main__.py index 3f04ba85042..a45b645eae0 100644 --- a/Lib/profiling/sampling/__main__.py +++ b/Lib/profiling/sampling/__main__.py @@ -1,6 +1,73 @@ """Run the sampling profiler from the command line.""" -from .sample import main +import sys + +MACOS_PERMISSION_ERROR = """\ +🔒 Permission Error: Unable to access process memory on macOS + +Tachyon needs elevated permissions to profile processes. Try one of these solutions: + +1. Try running again with elevated permissions by running 'sudo -E !!'. + +2. If targeting system Python processes: + Note: Apple's System Integrity Protection (SIP) may block access to system + Python binaries. Consider using a user-installed Python instead. +""" + +LINUX_PERMISSION_ERROR = """ +🔒 Tachyon was unable to access process memory. This could be because tachyon +has insufficient privileges (the required capability is CAP_SYS_PTRACE). +Unprivileged processes cannot trace processes that they cannot send signals +to or those running set-user-ID/set-group-ID programs, for security reasons. + +If your uid matches the uid of the target process you want to analyze, you +can do one of the following to get 'ptrace' scope permissions: + +* If you are running inside a Docker container, you need to make sure you + start the container using the '--cap-add=SYS_PTRACE' or '--privileged' + command line arguments. Notice that this may not be enough if you are not + running as 'root' inside the Docker container as you may need to disable + hardening (see next points). + +* Try running again with elevated permissions by running 'sudo -E !!'. + +* You can disable kernel hardening for the current session temporarily (until + a reboot happens) by running 'echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope'. +""" + +WINDOWS_PERMISSION_ERROR = """ +🔒 Tachyon requires administrator rights to access process memory on Windows. +Please run your command prompt as Administrator and try again. +""" + +GENERIC_PERMISSION_ERROR = """ +🔒 Tachyon was unable to access the target process due to operating +system restrictions or missing privileges. +""" + +from .cli import main +from .errors import SamplingUnknownProcessError, SamplingModuleNotFoundError, SamplingScriptNotFoundError + +def handle_permission_error(): + """Handle PermissionError by displaying appropriate error message.""" + if sys.platform == "darwin": + print(MACOS_PERMISSION_ERROR, file=sys.stderr) + elif sys.platform.startswith("linux"): + print(LINUX_PERMISSION_ERROR, file=sys.stderr) + elif sys.platform.startswith("win"): + print(WINDOWS_PERMISSION_ERROR, file=sys.stderr) + else: + print(GENERIC_PERMISSION_ERROR, file=sys.stderr) + sys.exit(1) if __name__ == '__main__': - main() + try: + main() + except PermissionError: + handle_permission_error() + except SamplingUnknownProcessError as err: + print(f"Tachyon cannot find the process: {err}", file=sys.stderr) + sys.exit(1) + except (SamplingModuleNotFoundError, SamplingScriptNotFoundError) as err: + print(f"Tachyon cannot find the target: {err}", file=sys.stderr) + sys.exit(1) diff --git a/Lib/profiling/sampling/_assets/python-logo-only.png b/Lib/profiling/sampling/_assets/python-logo-only.png new file mode 100644 index 00000000000..e590b5c6480 Binary files /dev/null and b/Lib/profiling/sampling/_assets/python-logo-only.png differ diff --git a/Lib/profiling/sampling/_assets/tachyon-logo.png b/Lib/profiling/sampling/_assets/tachyon-logo.png new file mode 100644 index 00000000000..f87e006b14f Binary files /dev/null and b/Lib/profiling/sampling/_assets/tachyon-logo.png differ diff --git a/Lib/profiling/sampling/_child_monitor.py b/Lib/profiling/sampling/_child_monitor.py new file mode 100644 index 00000000000..e06c550d938 --- /dev/null +++ b/Lib/profiling/sampling/_child_monitor.py @@ -0,0 +1,279 @@ +""" +Child process monitoring for the sampling profiler. + +This module monitors a target process for child process creation and spawns +separate profiler instances for each discovered child. +""" + +import subprocess +import sys +import threading +import time + +import _remote_debugging + +# Polling interval for child process discovery +_CHILD_POLL_INTERVAL_SEC = 0.1 + +# Default timeout for waiting on child profilers +_DEFAULT_WAIT_TIMEOUT = 30.0 + +# Maximum number of child profilers to spawn (prevents resource exhaustion) +_MAX_CHILD_PROFILERS = 100 + +# Interval for cleaning up completed profilers (in polling cycles) +_CLEANUP_INTERVAL_CYCLES = 10 + + +def get_child_pids(pid, recursive=True): + """ + Get all child process IDs of the given process. + + Args: + pid: Process ID of the parent process + recursive: If True, return all descendants (children, grandchildren, etc.) + + Returns: + List of child PIDs + """ + return _remote_debugging.get_child_pids(pid, recursive=recursive) + + +def is_python_process(pid): + """ + Check if a process is a Python process. + + Args: + pid: Process ID to check + + Returns: + bool: True if the process appears to be a Python process, False otherwise + """ + return _remote_debugging.is_python_process(pid) + + +class ChildProcessMonitor: + """ + Monitors a target process for child processes and spawns profilers for them. + + Use as a context manager: + with ChildProcessMonitor(pid, cli_args, output_pattern) as monitor: + # monitoring runs here + monitor.wait_for_profilers() # optional: wait before cleanup + # cleanup happens automatically + """ + + def __init__(self, pid, cli_args, output_pattern): + """ + Initialize the child process monitor. + + Args: + pid: Parent process ID to monitor + cli_args: CLI arguments to pass to child profilers + output_pattern: Pattern for output files (format string with {pid}) + """ + self.parent_pid = pid + self.cli_args = cli_args + self.output_pattern = output_pattern + + self._known_children = set() + self._spawned_profilers = [] + self._lock = threading.Lock() + self._stop_event = threading.Event() + self._monitor_thread = None + self._poll_count = 0 + + def __enter__(self): + self._monitor_thread = threading.Thread( + target=self._monitor_loop, + daemon=True, + name=f"child-monitor-{self.parent_pid}", + ) + self._monitor_thread.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self._stop_event.set() + if self._monitor_thread is not None: + self._monitor_thread.join(timeout=2.0) + if self._monitor_thread.is_alive(): + print( + "Warning: Monitor thread did not stop cleanly", + file=sys.stderr, + ) + + # Wait for child profilers to complete naturally + self.wait_for_profilers() + + # Terminate any remaining profilers + with self._lock: + profilers_to_cleanup = list(self._spawned_profilers) + self._spawned_profilers.clear() + + for proc in profilers_to_cleanup: + self._cleanup_process(proc) + return False + + def _cleanup_process(self, proc, terminate_timeout=2.0, kill_timeout=1.0): + if proc.poll() is not None: + return # Already terminated + + proc.terminate() + try: + proc.wait(timeout=terminate_timeout) + except subprocess.TimeoutExpired: + proc.kill() + try: + proc.wait(timeout=kill_timeout) + except subprocess.TimeoutExpired: + # Last resort: wait indefinitely to avoid zombie + # SIGKILL should always work, but we must reap the process + try: + proc.wait() + except Exception: + pass + + @property + def spawned_profilers(self): + with self._lock: + return list(self._spawned_profilers) + + def wait_for_profilers(self, timeout=_DEFAULT_WAIT_TIMEOUT): + """ + Wait for all spawned child profilers to complete. + + Call this before exiting the context if you want profilers to finish + their work naturally rather than being terminated. + + Args: + timeout: Maximum time to wait in seconds + """ + profilers = self.spawned_profilers + if not profilers: + return + + print( + f"Waiting for {len(profilers)} child profiler(s) to complete...", + file=sys.stderr, + ) + + deadline = time.monotonic() + timeout + for proc in profilers: + remaining = deadline - time.monotonic() + if remaining <= 0: + break + try: + proc.wait(timeout=max(0.1, remaining)) + except subprocess.TimeoutExpired: + pass + + def _monitor_loop(self): + # Note: There is an inherent TOCTOU race between discovering a child + # process and checking if it's Python. This is expected for process monitoring. + while not self._stop_event.is_set(): + try: + self._poll_count += 1 + + # Periodically clean up completed profilers to avoid memory buildup + if self._poll_count % _CLEANUP_INTERVAL_CYCLES == 0: + self._cleanup_completed_profilers() + + children = set(get_child_pids(self.parent_pid, recursive=True)) + + with self._lock: + new_children = children - self._known_children + self._known_children.update(new_children) + + for child_pid in new_children: + # Only spawn profiler if this is actually a Python process + if is_python_process(child_pid): + self._spawn_profiler_for_child(child_pid) + + except ProcessLookupError: + # Parent process exited, stop monitoring + break + except Exception as e: + # Log error but continue monitoring + print( + f"Warning: Error in child monitor loop: {e}", + file=sys.stderr, + ) + + self._stop_event.wait(timeout=_CHILD_POLL_INTERVAL_SEC) + + def _cleanup_completed_profilers(self): + with self._lock: + # Keep only profilers that are still running + self._spawned_profilers = [ + p for p in self._spawned_profilers if p.poll() is None + ] + + def _spawn_profiler_for_child(self, child_pid): + if self._stop_event.is_set(): + return + + # Check if we've reached the maximum number of child profilers + with self._lock: + if len(self._spawned_profilers) >= _MAX_CHILD_PROFILERS: + print( + f"Warning: Max child profilers ({_MAX_CHILD_PROFILERS}) reached, " + f"skipping PID {child_pid}", + file=sys.stderr, + ) + return + + cmd = [ + sys.executable, + "-m", + "profiling.sampling", + "attach", + str(child_pid), + ] + cmd.extend(self._build_child_cli_args(child_pid)) + + proc = None + try: + proc = subprocess.Popen( + cmd, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + with self._lock: + if self._stop_event.is_set(): + self._cleanup_process( + proc, terminate_timeout=1.0, kill_timeout=1.0 + ) + return + self._spawned_profilers.append(proc) + + print( + f"Started profiler for child process {child_pid}", + file=sys.stderr, + ) + except Exception as e: + if proc is not None: + self._cleanup_process( + proc, terminate_timeout=1.0, kill_timeout=1.0 + ) + print( + f"Warning: Failed to start profiler for child {child_pid}: {e}", + file=sys.stderr, + ) + + def _build_child_cli_args(self, child_pid): + args = list(self.cli_args) + + if self.output_pattern: + # Use replace() instead of format() to handle user filenames with braces + output_file = self.output_pattern.replace("{pid}", str(child_pid)) + found_output = False + for i, arg in enumerate(args): + if arg in ("-o", "--output") and i + 1 < len(args): + args[i + 1] = output_file + found_output = True + break + if not found_output: + args.extend(["-o", output_file]) + + return args diff --git a/Lib/profiling/sampling/_css_utils.py b/Lib/profiling/sampling/_css_utils.py new file mode 100644 index 00000000000..40912e9b352 --- /dev/null +++ b/Lib/profiling/sampling/_css_utils.py @@ -0,0 +1,22 @@ +import importlib.resources + + +def get_combined_css(component: str) -> str: + template_dir = importlib.resources.files(__package__) + + base_css = (template_dir / "_shared_assets" / "base.css").read_text(encoding="utf-8") + + if component == "flamegraph": + component_css = ( + template_dir / "_flamegraph_assets" / "flamegraph.css" + ).read_text(encoding="utf-8") + elif component == "heatmap": + component_css = (template_dir / "_heatmap_assets" / "heatmap.css").read_text( + encoding="utf-8" + ) + else: + raise ValueError( + f"Unknown component: {component}. Expected 'flamegraph' or 'heatmap'." + ) + + return f"{base_css}\n\n{component_css}" diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css new file mode 100644 index 00000000000..03eb2274d23 --- /dev/null +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css @@ -0,0 +1,1019 @@ +/* ========================================================================== + Flamegraph Viewer - Component-Specific CSS + + DEPENDENCY: Requires _shared_assets/base.css to be loaded first + This file extends the shared foundation with flamegraph-specific styles. + ========================================================================== */ + +/* -------------------------------------------------------------------------- + Layout Overrides (Flamegraph-specific) + -------------------------------------------------------------------------- */ + +html, body { + height: 100%; + overflow: hidden; +} + +.app-layout { + height: 100vh; +} + +.main-content { + display: flex; + flex: 1; + min-height: 0; +} + +/* -------------------------------------------------------------------------- + Search Input (Flamegraph-specific) + -------------------------------------------------------------------------- */ + +.search-wrapper { + flex: 1; + max-width: 360px; + position: relative; +} + +.search-input { + width: 100%; + padding: 8px 36px 8px 14px; + font-family: var(--font-sans); + font-size: 13px; + color: #2e3338; + background: rgba(255, 255, 255, 0.95); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 20px; + outline: none; + transition: all var(--transition-fast); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +.search-input::placeholder { + color: #6c757d; +} + +.search-input:focus { + border-color: rgba(255, 255, 255, 0.8); + background: white; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); +} + +/* Dark theme search input */ +[data-theme="dark"] .search-input { + color: #e6edf3; + background: rgba(33, 38, 45, 0.95); + border: 2px solid rgba(88, 166, 255, 0.3); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); +} + +[data-theme="dark"] .search-input::placeholder { + color: #8b949e; +} + +[data-theme="dark"] .search-input:focus { + border-color: rgba(88, 166, 255, 0.6); + background: rgba(33, 38, 45, 1); + box-shadow: 0 4px 16px rgba(88, 166, 255, 0.2); +} + +.search-input.has-matches { + border-color: rgba(40, 167, 69, 0.8); + box-shadow: 0 4px 16px rgba(40, 167, 69, 0.2); +} + +.search-input.no-matches { + border-color: rgba(220, 53, 69, 0.8); + box-shadow: 0 4px 16px rgba(220, 53, 69, 0.2); +} + +.search-clear { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 20px; + padding: 0; + display: none; + align-items: center; + justify-content: center; + font-size: 14px; + line-height: 1; + color: #6c757d; + background: transparent; + border: none; + border-radius: 50%; + cursor: pointer; + transition: color var(--transition-fast); +} + +.search-clear:hover { + color: #2e3338; +} + +[data-theme="dark"] .search-clear { + color: #8b949e; +} + +[data-theme="dark"] .search-clear:hover { + color: #e6edf3; +} + +.search-wrapper.has-value .search-clear { + display: flex; +} + +/* -------------------------------------------------------------------------- + Sidebar + -------------------------------------------------------------------------- */ + +.sidebar { + width: var(--sidebar-width); + background: var(--bg-secondary); + border-right: 1px solid var(--border); + display: flex; + flex-direction: column; + flex-shrink: 0; + overflow: hidden; + position: relative; +} + +.sidebar.collapsed { + width: var(--sidebar-collapsed) !important; + transition: width var(--transition-normal); +} + +.sidebar-toggle { + position: absolute; + top: 12px; + right: 10px; + width: 26px; + height: 26px; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-muted); + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 6px; + cursor: pointer; + transition: all var(--transition-fast); + z-index: 10; +} + +.sidebar-toggle svg { + transition: transform var(--transition-fast); +} + +.sidebar-toggle:hover { + color: var(--accent); + border-color: var(--accent); + background: var(--accent-glow); +} + +.sidebar.collapsed .sidebar-toggle { + right: 9px; +} + +.sidebar.collapsed .sidebar-toggle svg { + transform: rotate(180deg); +} + +.sidebar-content { + flex: 1; + overflow-y: auto; + padding: 44px 14px 14px; +} + +.sidebar.collapsed .sidebar-content { + display: none; +} + +.sidebar-resize-handle { + position: absolute; + top: 0; + right: 0; + width: 6px; + height: 100%; + cursor: col-resize; + background: transparent; + transition: background var(--transition-fast); + z-index: 11; +} + +.sidebar-resize-handle:hover, +.sidebar-resize-handle.resizing { + background: var(--python-gold); +} + +.sidebar-resize-handle::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 2px; + height: 40px; + background: var(--border); + border-radius: 1px; + opacity: 0; + transition: opacity var(--transition-fast); +} + +.sidebar-resize-handle:hover::before { + opacity: 1; +} + +.sidebar.collapsed .sidebar-resize-handle { + display: none; +} + +body.resizing-sidebar { + cursor: col-resize; + user-select: none; +} + +/* Sidebar Logo */ +.sidebar-logo { + display: flex; + justify-content: center; + margin-bottom: 16px; +} + +.sidebar-logo-img { + width: 220px; + height: 180px; + display: flex; + align-items: center; + justify-content: center; +} + +.sidebar-logo-img svg, +.sidebar-logo-img img { + width: 100%; + height: 100%; + object-fit: contain; +} + +/* Sidebar sections */ +.sidebar-section { + margin-bottom: 20px; +} + +.sidebar-section:last-child { + margin-bottom: 0; +} + +.section-title { + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + color: var(--accent); + margin: 0; + flex: 1; +} + +/* View Mode Section */ +.view-mode-section .section-content { + display: flex; + justify-content: center; +} + +/* Collapsible sections */ +.collapsible .section-header { + display: flex; + align-items: center; + width: 100%; + padding: 0 0 8px 0; + margin-bottom: 10px; + background: none; + border: none; + border-bottom: 2px solid var(--python-gold); + cursor: pointer; + transition: all var(--transition-fast); +} + +.collapsible .section-header:hover { + opacity: 0.8; +} + +.section-chevron { + color: var(--text-muted); + transition: transform var(--transition-fast); +} + +.collapsible.collapsed .section-chevron { + transform: rotate(-90deg); +} + +.section-content { + transition: max-height var(--transition-slow) ease-out, opacity var(--transition-normal) ease-out, padding var(--transition-normal) ease-out; + max-height: 1000px; + opacity: 1; +} + +.collapsible.collapsed .section-content { + max-height: 0; + opacity: 0; + padding-top: 0; + pointer-events: none; + transition: max-height var(--transition-slow) ease-in, opacity var(--transition-normal) ease-in, padding var(--transition-normal) ease-in; +} + +/* -------------------------------------------------------------------------- + Profile Summary Cards + -------------------------------------------------------------------------- */ + +.summary-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; +} + +.summary-card { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 10px; + background: var(--bg-primary); + border: 2px solid var(--border); + border-radius: 8px; + transition: all var(--transition-fast); + animation: slideUp 0.4s ease-out backwards; + animation-delay: calc(var(--i, 0) * 0.08s); + overflow: hidden; + position: relative; +} + +.summary-card:nth-child(1) { --i: 0; --card-color: 55, 118, 171; } +.summary-card:nth-child(2) { --i: 1; --card-color: 40, 167, 69; } +.summary-card:nth-child(3) { --i: 2; --card-color: 255, 193, 7; } +.summary-card:nth-child(4) { --i: 3; --card-color: 111, 66, 193; } + +.summary-card:hover { + border-color: rgba(var(--card-color), 0.6); + background: linear-gradient(135deg, rgba(var(--card-color), 0.08) 0%, var(--bg-primary) 100%); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(var(--card-color), 0.15); +} + +.summary-icon { + font-size: 14px; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, rgba(var(--card-color), 0.15) 0%, rgba(var(--card-color), 0.05) 100%); + border: 1px solid rgba(var(--card-color), 0.2); + border-radius: 6px; + flex-shrink: 0; + transition: all var(--transition-fast); +} + +.summary-card:hover .summary-icon { + transform: scale(1.05); + background: linear-gradient(135deg, rgba(var(--card-color), 0.25) 0%, rgba(var(--card-color), 0.1) 100%); +} + +.summary-data { + min-width: 0; + flex: 1; + overflow: hidden; +} + +.summary-value { + font-family: var(--font-mono); + font-size: 13px; + font-weight: 800; + color: rgb(var(--card-color)); + line-height: 1.2; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.summary-label { + font-size: 8px; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Efficiency Bar */ +.efficiency-section { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--border); +} + +.efficiency-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 5px; +} + +.efficiency-label { + font-size: 9px; + font-weight: 600; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.2px; +} + +.efficiency-value { + font-family: var(--font-mono); + font-size: 11px; + font-weight: 700; + color: var(--accent); +} + +.efficiency-bar { + height: 6px; + background: var(--bg-tertiary); + border-radius: 3px; + overflow: hidden; +} + +.efficiency-fill { + height: 100%; + background: linear-gradient(90deg, #28a745 0%, #20c997 50%, #17a2b8 100%); + border-radius: 3px; + transition: width 0.6s ease-out; + position: relative; + overflow: hidden; +} + +.efficiency-fill::after { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 255, 255, 0.4) 50%, + transparent 100% + ); + animation: shimmer 2s ease-in-out infinite; +} + +/* -------------------------------------------------------------------------- + Thread Stats Grid (in Sidebar) + -------------------------------------------------------------------------- */ + +.thread-stats-section { + display: block; +} + +.stats-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; +} + +.stat-tile { + background: var(--bg-primary); + border-radius: 8px; + padding: 10px; + text-align: center; + border: 2px solid var(--border); + transition: all var(--transition-fast); + animation: fadeIn 0.4s ease-out backwards; + animation-delay: calc(var(--i, 0) * 0.05s); +} + +.stat-tile:nth-child(1) { --i: 0; } +.stat-tile:nth-child(2) { --i: 1; } +.stat-tile:nth-child(3) { --i: 2; } +.stat-tile:nth-child(4) { --i: 3; } + +.stat-tile:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-sm); +} + +.stat-tile-value { + font-family: var(--font-mono); + font-size: 16px; + font-weight: 700; + color: var(--text-primary); + line-height: 1.2; +} + +.stat-tile-label { + font-size: 9px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.3px; + color: var(--text-muted); + margin-top: 2px; +} + +/* Stat tile color variants */ +.stat-tile--green { --tile-color: 40, 167, 69; --tile-text: #28a745; } +.stat-tile--red { --tile-color: 220, 53, 69; --tile-text: #dc3545; } +.stat-tile--yellow { --tile-color: 255, 193, 7; --tile-text: #d39e00; } +.stat-tile--purple { --tile-color: 111, 66, 193; --tile-text: #6f42c1; } + +.stat-tile[class*="--"] { + border-color: rgba(var(--tile-color), 0.4); + background: linear-gradient(135deg, rgba(var(--tile-color), 0.08) 0%, var(--bg-primary) 100%); +} +.stat-tile[class*="--"] .stat-tile-value { color: var(--tile-text); } + +/* -------------------------------------------------------------------------- + Hotspot Cards + -------------------------------------------------------------------------- */ + +.hotspot { + display: flex; + align-items: flex-start; + gap: 10px; + padding: 10px; + margin-bottom: 8px; + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px; + cursor: pointer; + transition: all var(--transition-fast); + opacity: 0; + transform: translateY(8px); + box-shadow: var(--shadow-sm); +} + +.hotspot.visible { + opacity: 1; + transform: translateY(0); +} + +.hotspot:hover { + border-color: var(--accent); + box-shadow: var(--shadow-md); + transform: translateY(-2px); +} + +.hotspot.active { + border-color: var(--python-gold); + background: var(--accent-glow); + box-shadow: 0 0 0 3px var(--accent-glow); +} + +.hotspot:last-child { + margin-bottom: 0; +} + +.hotspot-rank { + width: 26px; + height: 26px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 12px; + flex-shrink: 0; + background: linear-gradient(135deg, var(--python-blue) 0%, var(--python-blue-light) 100%); + color: white; + box-shadow: 0 2px 4px rgba(55, 118, 171, 0.3); +} + +.hotspot-rank--1 { background: linear-gradient(135deg, #d4af37, #f4d03f); color: #5a4a00; } +.hotspot-rank--2 { background: linear-gradient(135deg, #a8a8a8, #c0c0c0); color: #4a4a4a; } +.hotspot-rank--3 { background: linear-gradient(135deg, #cd7f32, #e6a55a); color: #5a3d00; } + +.hotspot-info { + flex: 1; + min-width: 0; +} + +.hotspot-func { + font-family: var(--font-mono); + font-size: 11px; + font-weight: 600; + color: var(--text-primary); + line-height: 1.3; + word-break: break-word; + margin-bottom: 2px; +} + +.hotspot-file { + font-family: var(--font-mono); + font-size: 10px; + color: var(--text-muted); + margin-bottom: 3px; + word-break: break-all; +} + +.hotspot-stats { + font-family: var(--font-mono); + font-size: 10px; + color: var(--text-secondary); +} + +.hotspot-percent { + color: var(--accent); + font-weight: 600; +} + +/* -------------------------------------------------------------------------- + Legend + -------------------------------------------------------------------------- */ + + +.legend { + display: flex; + flex-direction: column; + gap: 4px; +} + +.legend-item { + display: flex; + align-items: center; + gap: 8px; + padding: 5px 8px; + background: var(--bg-primary); + border-radius: 4px; + border: 1px solid var(--border-subtle); + font-size: 11px; +} + +.legend-color { + width: 20px; + height: 10px; + border-radius: 2px; + flex-shrink: 0; + border: 1px solid rgba(0, 0, 0, 0.08); +} + +.legend-label { + color: var(--text-primary); + font-weight: 500; + flex: 1; +} + +.legend-range { + font-family: var(--font-mono); + font-size: 9px; + color: var(--text-muted); +} + +/* -------------------------------------------------------------------------- + Thread Filter + -------------------------------------------------------------------------- */ + +.filter-section { + padding-top: 12px; + border-top: 1px solid var(--border); +} + +.filter-label { + display: block; + font-size: 10px; + font-weight: 600; + color: var(--text-muted); + margin-bottom: 6px; +} + +.filter-select { + width: 100%; + padding: 7px 28px 7px 10px; + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-primary); + background: var(--bg-primary); + border: 2px solid var(--accent); + border-radius: 6px; + cursor: pointer; + outline: none; + appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233776ab' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 6px center; + background-size: 14px; + transition: all var(--transition-fast); +} + +.filter-select:hover { + border-color: var(--accent-hover); + box-shadow: 0 2px 6px var(--accent-glow); +} + +.filter-select:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-glow); +} + +/* -------------------------------------------------------------------------- + Chart Area + -------------------------------------------------------------------------- */ + +.chart-area { + flex: 1; + min-width: 0; + overflow: hidden; + background: var(--bg-primary); + position: relative; +} + +#chart { + width: 100%; + height: 100%; + padding: 16px; + overflow: auto; +} + +/* D3 Flamegraph overrides */ +.d3-flame-graph rect { + stroke: rgba(55, 118, 171, 0.3); + stroke-width: 1px; + cursor: pointer; + transition: filter 0.1s ease; +} + +.d3-flame-graph rect:hover { + stroke: var(--python-blue); + stroke-width: 2px; + filter: brightness(1.08); +} + +.d3-flame-graph text { + font-family: var(--font-sans); + font-size: 12px; + font-weight: 500; + fill: var(--text-primary); + pointer-events: none; +} + +/* Search highlight */ +.d3-flame-graph rect.search-match { + stroke: #ff6b35 !important; + stroke-width: 2px !important; + stroke-dasharray: 4 2; +} + +.d3-flame-graph rect.search-dim { + opacity: 0.25; +} + +/* -------------------------------------------------------------------------- + Tooltip + -------------------------------------------------------------------------- */ + +.python-tooltip { + position: absolute; + z-index: 1000; + pointer-events: none; + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px; + padding: 14px; + max-width: 480px; + box-shadow: var(--shadow-lg); + font-family: var(--font-sans); + font-size: 13px; + color: var(--text-primary); + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; +} + +.tooltip-header { + margin-bottom: 10px; +} + +.tooltip-title { + font-size: 14px; + font-weight: 600; + color: var(--accent); + line-height: 1.3; + word-break: break-word; + margin-bottom: 4px; +} + +.tooltip-location { + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-secondary); + background: var(--bg-tertiary); + padding: 4px 8px; + border-radius: 4px; + word-break: break-all; +} + +.tooltip-stats { + display: grid; + grid-template-columns: auto 1fr; + gap: 4px 14px; + font-size: 12px; +} + +.tooltip-stat-label { + color: var(--text-secondary); + font-weight: 500; +} + +.tooltip-stat-value { + color: var(--text-primary); + font-weight: 600; +} + +.tooltip-stat-value.accent { + color: var(--accent); +} + +.tooltip-source { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--border); +} + +.tooltip-source-title { + font-size: 11px; + font-weight: 600; + color: var(--accent); + margin-bottom: 6px; +} + +.tooltip-source-code { + font-family: var(--font-mono); + font-size: 10px; + line-height: 1.5; + background: var(--bg-tertiary); + border: 1px solid var(--border); + border-radius: 6px; + padding: 8px; + max-height: 140px; + overflow-y: auto; + white-space: pre-wrap; + word-break: break-all; +} + +.tooltip-source-line { + color: var(--text-secondary); + padding: 1px 0; +} + +.tooltip-source-line.current { + color: var(--accent); + font-weight: 600; +} + +.tooltip-hint { + margin-top: 10px; + padding-top: 8px; + border-top: 1px solid var(--border); + font-size: 11px; + color: var(--text-muted); + text-align: center; +} + +/* -------------------------------------------------------------------------- + Tooltip Bytecode/Opcode Section + -------------------------------------------------------------------------- */ + +.tooltip-opcodes { + margin-top: 16px; + padding-top: 12px; + border-top: 1px solid var(--border); +} + +.tooltip-opcodes-title { + color: var(--accent); + font-size: 13px; + margin-bottom: 8px; + font-weight: 600; +} + +.tooltip-opcodes-list { + background: var(--bg-tertiary); + border: 1px solid var(--border); + border-radius: 6px; + padding: 10px; +} + +.tooltip-opcode-row { + display: grid; + grid-template-columns: 1fr 60px 60px; + gap: 8px; + align-items: center; + padding: 3px 0; +} + +.tooltip-opcode-name { + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tooltip-opcode-name.specialized { + color: var(--spec-high-text); +} + +.tooltip-opcode-base-hint { + color: var(--text-muted); + font-size: 11px; + margin-left: 4px; +} + +.tooltip-opcode-badge { + background: var(--spec-high); + color: white; + font-size: 9px; + padding: 1px 4px; + border-radius: 3px; + margin-left: 4px; +} + +.tooltip-opcode-count { + text-align: right; + font-size: 11px; + color: var(--text-secondary); +} + +.tooltip-opcode-bar { + background: var(--bg-secondary); + border-radius: 2px; + height: 8px; + overflow: hidden; +} + +.tooltip-opcode-bar-fill { + background: linear-gradient(90deg, var(--python-blue), var(--python-blue-light)); + height: 100%; +} + +/* -------------------------------------------------------------------------- + Responsive (Flamegraph-specific) + -------------------------------------------------------------------------- */ + +@media (max-width: 900px) { + .sidebar { + position: fixed; + left: 0; + top: var(--topbar-height); + bottom: var(--statusbar-height); + z-index: 100; + box-shadow: var(--shadow-lg); + } + + .sidebar.collapsed { + width: var(--sidebar-collapsed); + } + + .search-wrapper { + max-width: 220px; + } +} + +@media (max-width: 600px) { + .search-wrapper { + max-width: 160px; + } + + .brand-info { + display: none; + } + + .stats-grid { + grid-template-columns: 1fr; + } +} + +/* -------------------------------------------------------------------------- + Flamegraph Root Node Styling + -------------------------------------------------------------------------- */ + +/* Style the root node - no border, themed text */ +.d3-flame-graph g:first-of-type rect { + stroke: none; +} + +.d3-flame-graph g:first-of-type .d3-flame-graph-label { + color: var(--text-muted); +} + +/* -------------------------------------------------------------------------- + Flamegraph-Specific Toggle Override + -------------------------------------------------------------------------- */ + +#toggle-invert .toggle-track.on { + background: #8e44ad; + border-color: #8e44ad; + box-shadow: 0 0 8px rgba(142, 68, 173, 0.3); +} + +.toggle-switch:focus-visible { + border-radius: 4px; +} diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js new file mode 100644 index 00000000000..17fd95af859 --- /dev/null +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -0,0 +1,1320 @@ +const EMBEDDED_DATA = {{FLAMEGRAPH_DATA}}; + +// Global string table for resolving string indices +let stringTable = []; +let normalData = null; +let invertedData = null; +let currentThreadFilter = 'all'; +let isInverted = false; + +// Heat colors are now defined in CSS variables (--heat-1 through --heat-8) +// and automatically switch with theme changes - no JS color arrays needed! + +// Opcode mappings - loaded from embedded data (generated by Python) +let OPCODE_NAMES = {}; +let DEOPT_MAP = {}; + +// Initialize opcode mappings from embedded data +function initOpcodeMapping(data) { + if (data && data.opcode_mapping) { + OPCODE_NAMES = data.opcode_mapping.names || {}; + DEOPT_MAP = data.opcode_mapping.deopt || {}; + } +} + +// Get opcode info from opcode number +function getOpcodeInfo(opcode) { + const opname = OPCODE_NAMES[opcode] || `<${opcode}>`; + const baseOpcode = DEOPT_MAP[opcode]; + const isSpecialized = baseOpcode !== undefined; + const baseOpname = isSpecialized ? (OPCODE_NAMES[baseOpcode] || `<${baseOpcode}>`) : opname; + + return { + opname: opname, + baseOpname: baseOpname, + isSpecialized: isSpecialized + }; +} + +// ============================================================================ +// String Resolution +// ============================================================================ + +function resolveString(index) { + if (index === null || index === undefined) { + return null; + } + if (typeof index === 'number' && index >= 0 && index < stringTable.length) { + return stringTable[index]; + } + return String(index); +} + +function resolveStringIndices(node) { + if (!node) return node; + + const resolved = { ...node }; + + if (typeof resolved.name === 'number') { + resolved.name = resolveString(resolved.name); + } + if (typeof resolved.filename === 'number') { + resolved.filename = resolveString(resolved.filename); + } + if (typeof resolved.funcname === 'number') { + resolved.funcname = resolveString(resolved.funcname); + } + + if (Array.isArray(resolved.source)) { + resolved.source = resolved.source.map(index => + typeof index === 'number' ? resolveString(index) : index + ); + } + + if (Array.isArray(resolved.children)) { + resolved.children = resolved.children.map(child => resolveStringIndices(child)); + } + + return resolved; +} + +// ============================================================================ +// Theme & UI Controls +// ============================================================================ + +function toggleTheme() { + const html = document.documentElement; + const current = html.getAttribute('data-theme') || 'light'; + const next = current === 'light' ? 'dark' : 'light'; + html.setAttribute('data-theme', next); + localStorage.setItem('flamegraph-theme', next); + + // Update theme button icon + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = next === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = next === 'dark' ? '' : 'none'; + } + + // Re-render flamegraph with new theme colors + if (window.flamegraphData && normalData) { + const currentData = isInverted ? invertedData : normalData; + const tooltip = createPythonTooltip(currentData); + const chart = createFlamegraph(tooltip, currentData.value); + renderFlamegraph(chart, window.flamegraphData); + } +} + +function toggleSidebar() { + const sidebar = document.getElementById('sidebar'); + if (sidebar) { + const isCollapsing = !sidebar.classList.contains('collapsed'); + + if (isCollapsing) { + // Save current width before collapsing + const currentWidth = sidebar.offsetWidth; + sidebar.dataset.expandedWidth = currentWidth; + localStorage.setItem('flamegraph-sidebar-width', currentWidth); + } else { + // Restore width when expanding + const savedWidth = sidebar.dataset.expandedWidth || localStorage.getItem('flamegraph-sidebar-width'); + if (savedWidth) { + sidebar.style.width = savedWidth + 'px'; + } + } + + sidebar.classList.toggle('collapsed'); + localStorage.setItem('flamegraph-sidebar', sidebar.classList.contains('collapsed') ? 'collapsed' : 'expanded'); + + // Resize chart after sidebar animation + setTimeout(() => { + resizeChart(); + }, 300); + } +} + +function resizeChart() { + if (window.flamegraphChart && window.flamegraphData) { + const chartArea = document.querySelector('.chart-area'); + if (chartArea) { + window.flamegraphChart.width(chartArea.clientWidth - 32); + d3.select("#chart").datum(window.flamegraphData).call(window.flamegraphChart); + } + } +} + +function toggleSection(sectionId) { + const section = document.getElementById(sectionId); + if (section) { + section.classList.toggle('collapsed'); + // Save state + const collapsedSections = JSON.parse(localStorage.getItem('flamegraph-collapsed-sections') || '{}'); + collapsedSections[sectionId] = section.classList.contains('collapsed'); + localStorage.setItem('flamegraph-collapsed-sections', JSON.stringify(collapsedSections)); + } +} + +function restoreUIState() { + // Restore theme + const savedTheme = localStorage.getItem('flamegraph-theme'); + if (savedTheme) { + document.documentElement.setAttribute('data-theme', savedTheme); + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = savedTheme === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = savedTheme === 'dark' ? '' : 'none'; + } + } + + // Restore sidebar state + const savedSidebar = localStorage.getItem('flamegraph-sidebar'); + if (savedSidebar === 'collapsed') { + const sidebar = document.getElementById('sidebar'); + if (sidebar) sidebar.classList.add('collapsed'); + } + + // Restore sidebar width + const savedWidth = localStorage.getItem('flamegraph-sidebar-width'); + if (savedWidth) { + const sidebar = document.getElementById('sidebar'); + if (sidebar) { + sidebar.style.width = savedWidth + 'px'; + } + } + + // Restore collapsed sections + const collapsedSections = JSON.parse(localStorage.getItem('flamegraph-collapsed-sections') || '{}'); + for (const [sectionId, isCollapsed] of Object.entries(collapsedSections)) { + if (isCollapsed) { + const section = document.getElementById(sectionId); + if (section) section.classList.add('collapsed'); + } + } +} + +// ============================================================================ +// Logo/Favicon Setup +// ============================================================================ + +function setupLogos() { + const logo = document.querySelector('.sidebar-logo-img img'); + if (!logo) return; + + const navbarLogoContainer = document.getElementById('navbar-logo'); + if (navbarLogoContainer) { + const navbarLogo = logo.cloneNode(true); + navbarLogoContainer.appendChild(navbarLogo); + } + + const favicon = document.createElement('link'); + favicon.rel = 'icon'; + favicon.type = 'image/png'; + favicon.href = logo.src; + document.head.appendChild(favicon); +} + +// ============================================================================ +// Status Bar +// ============================================================================ + +function updateStatusBar(nodeData, rootValue) { + const funcname = resolveString(nodeData.funcname) || resolveString(nodeData.name) || "--"; + const filename = resolveString(nodeData.filename) || ""; + const lineno = nodeData.lineno; + const timeMs = (nodeData.value / 1000).toFixed(2); + const percent = rootValue > 0 ? ((nodeData.value / rootValue) * 100).toFixed(1) : "0.0"; + + const brandEl = document.getElementById('status-brand'); + const taglineEl = document.getElementById('status-tagline'); + if (brandEl) brandEl.style.display = 'none'; + if (taglineEl) taglineEl.style.display = 'none'; + + const locationEl = document.getElementById('status-location'); + const funcItem = document.getElementById('status-func-item'); + const timeItem = document.getElementById('status-time-item'); + const percentItem = document.getElementById('status-percent-item'); + + if (locationEl) locationEl.style.display = filename && filename !== "~" ? 'flex' : 'none'; + if (funcItem) funcItem.style.display = 'flex'; + if (timeItem) timeItem.style.display = 'flex'; + if (percentItem) percentItem.style.display = 'flex'; + + const fileEl = document.getElementById('status-file'); + if (fileEl && filename && filename !== "~") { + const basename = filename.split('/').pop(); + fileEl.textContent = lineno ? `${basename}:${lineno}` : basename; + } + + const funcEl = document.getElementById('status-func'); + if (funcEl) funcEl.textContent = funcname.length > 40 ? funcname.substring(0, 37) + '...' : funcname; + + const timeEl = document.getElementById('status-time'); + if (timeEl) timeEl.textContent = `${timeMs} ms`; + + const percentEl = document.getElementById('status-percent'); + if (percentEl) percentEl.textContent = `${percent}%`; +} + +function clearStatusBar() { + const ids = ['status-location', 'status-func-item', 'status-time-item', 'status-percent-item']; + ids.forEach(id => { + const el = document.getElementById(id); + if (el) el.style.display = 'none'; + }); + + const brandEl = document.getElementById('status-brand'); + const taglineEl = document.getElementById('status-tagline'); + if (brandEl) brandEl.style.display = 'flex'; + if (taglineEl) taglineEl.style.display = 'flex'; +} + +// ============================================================================ +// Tooltip +// ============================================================================ + +function createPythonTooltip(data) { + const pythonTooltip = flamegraph.tooltip.defaultFlamegraphTooltip(); + + pythonTooltip.show = function (d, element) { + if (!this._tooltip) { + this._tooltip = d3.select("body") + .append("div") + .attr("class", "python-tooltip") + .style("opacity", 0); + } + + const timeMs = (d.data.value / 1000).toFixed(2); + const percentage = ((d.data.value / data.value) * 100).toFixed(2); + const calls = d.data.calls || 0; + const childCount = d.children ? d.children.length : 0; + const source = d.data.source; + + const funcname = resolveString(d.data.funcname) || resolveString(d.data.name); + const filename = resolveString(d.data.filename) || ""; + const isSpecialFrame = filename === "~"; + + // Build source section + let sourceSection = ""; + if (source && Array.isArray(source) && source.length > 0) { + const sourceLines = source + .map((line) => { + const isCurrent = line.startsWith("→"); + const escaped = line.replace(/&/g, "&").replace(//g, ">"); + return `
    ${escaped}
    `; + }) + .join(""); + + sourceSection = ` +
    +
    Source Code:
    +
    ${sourceLines}
    +
    `; + } + + // Create bytecode/opcode section if available + let opcodeSection = ""; + const opcodes = d.data.opcodes; + if (opcodes && typeof opcodes === 'object' && Object.keys(opcodes).length > 0) { + // Sort opcodes by sample count (descending) + const sortedOpcodes = Object.entries(opcodes) + .sort((a, b) => b[1] - a[1]) + .slice(0, 8); // Limit to top 8 + + const totalOpcodeSamples = sortedOpcodes.reduce((sum, [, count]) => sum + count, 0); + const maxCount = sortedOpcodes[0][1] || 1; + + const opcodeLines = sortedOpcodes.map(([opcode, count]) => { + const opcodeInfo = getOpcodeInfo(parseInt(opcode, 10)); + const pct = ((count / totalOpcodeSamples) * 100).toFixed(1); + const barWidth = (count / maxCount) * 100; + const specializedBadge = opcodeInfo.isSpecialized + ? 'SPECIALIZED' + : ''; + const baseOpHint = opcodeInfo.isSpecialized + ? `(${opcodeInfo.baseOpname})` + : ''; + const nameClass = opcodeInfo.isSpecialized + ? 'tooltip-opcode-name specialized' + : 'tooltip-opcode-name'; + + return ` +
    +
    + ${opcodeInfo.opname}${baseOpHint}${specializedBadge} +
    +
    ${count.toLocaleString()} (${pct}%)
    +
    +
    +
    +
    `; + }).join(''); + + opcodeSection = ` +
    +
    Bytecode Instructions:
    +
    + ${opcodeLines} +
    +
    `; + } + + const fileLocationHTML = isSpecialFrame ? "" : ` +
    ${filename}${d.data.lineno ? ":" + d.data.lineno : ""}
    `; + + const tooltipHTML = ` +
    +
    ${funcname}
    + ${fileLocationHTML} +
    +
    + Execution Time: + ${timeMs} ms + + Percentage: + ${percentage}% + + ${calls > 0 ? ` + Function Calls: + ${calls.toLocaleString()} + ` : ''} + + ${childCount > 0 ? ` + Child Functions: + ${childCount} + ` : ''} +
    + ${sourceSection} + ${opcodeSection} +
    + ${childCount > 0 ? "Click to zoom into this function" : "Leaf function - no children"} +
    + `; + + // Position tooltip + const event = d3.event || window.event; + const mouseX = event.pageX || event.clientX; + const mouseY = event.pageY || event.clientY; + const padding = 12; + + this._tooltip.html(tooltipHTML); + + // Measure tooltip + const node = this._tooltip.style("display", "block").style("opacity", 0).node(); + const tooltipWidth = node.offsetWidth || 320; + const tooltipHeight = node.offsetHeight || 200; + + // Calculate position + let left = mouseX + padding; + let top = mouseY + padding; + + if (left + tooltipWidth > window.innerWidth) { + left = mouseX - tooltipWidth - padding; + if (left < 0) left = padding; + } + + if (top + tooltipHeight > window.innerHeight) { + top = mouseY - tooltipHeight - padding; + if (top < 0) top = padding; + } + + this._tooltip + .style("left", left + "px") + .style("top", top + "px") + .transition() + .duration(150) + .style("opacity", 1); + + // Update status bar + updateStatusBar(d.data, data.value); + }; + + pythonTooltip.hide = function () { + if (this._tooltip) { + this._tooltip.transition().duration(150).style("opacity", 0); + } + clearStatusBar(); + }; + + return pythonTooltip; +} + +// ============================================================================ +// Flamegraph Creation +// ============================================================================ + +function ensureLibraryLoaded() { + if (typeof flamegraph === "undefined") { + console.error("d3-flame-graph library not loaded"); + document.getElementById("chart").innerHTML = + '
    Error: d3-flame-graph library failed to load
    '; + throw new Error("d3-flame-graph library failed to load"); + } +} + +const HEAT_THRESHOLDS = [ + [0.6, 8], + [0.35, 7], + [0.18, 6], + [0.12, 5], + [0.06, 4], + [0.03, 3], + [0.01, 2], +]; + +function getHeatLevel(percentage) { + for (const [threshold, level] of HEAT_THRESHOLDS) { + if (percentage >= threshold) return level; + } + return 1; +} + +function getHeatColors() { + const style = getComputedStyle(document.documentElement); + const colors = {}; + for (let i = 1; i <= 8; i++) { + colors[i] = style.getPropertyValue(`--heat-${i}`).trim(); + } + return colors; +} + +function createFlamegraph(tooltip, rootValue) { + const chartArea = document.querySelector('.chart-area'); + const width = chartArea ? chartArea.clientWidth - 32 : window.innerWidth - 320; + const heatColors = getHeatColors(); + + let chart = flamegraph() + .width(width) + .cellHeight(20) + .transitionDuration(300) + .minFrameSize(1) + .tooltip(tooltip) + .inverted(true) + .setColorMapper(function (d) { + // Root node should be transparent + if (d.depth === 0) return 'transparent'; + + const percentage = d.data.value / rootValue; + const level = getHeatLevel(percentage); + return heatColors[level]; + }); + + return chart; +} + +function renderFlamegraph(chart, data) { + d3.select("#chart").datum(data).call(chart); + window.flamegraphChart = chart; + window.flamegraphData = data; + populateStats(data); +} + +// ============================================================================ +// Search +// ============================================================================ + +function updateSearchHighlight(searchTerm, searchInput) { + d3.selectAll("#chart rect") + .classed("search-match", false) + .classed("search-dim", false); + + // Clear active state from all hotspots + document.querySelectorAll('.hotspot').forEach(h => h.classList.remove('active')); + + if (searchTerm && searchTerm.length > 0) { + let matchCount = 0; + + d3.selectAll("#chart rect").each(function (d) { + if (d && d.data) { + const name = resolveString(d.data.name) || ""; + const funcname = resolveString(d.data.funcname) || ""; + const filename = resolveString(d.data.filename) || ""; + const lineno = d.data.lineno; + const term = searchTerm.toLowerCase(); + + // Check if search term looks like file:line pattern + const fileLineMatch = term.match(/^(.+):(\d+)$/); + let matches = false; + + if (fileLineMatch) { + // Exact file:line matching + const searchFile = fileLineMatch[1]; + const searchLine = parseInt(fileLineMatch[2], 10); + const basename = filename.split('/').pop().toLowerCase(); + matches = basename.includes(searchFile) && lineno === searchLine; + } else { + // Regular substring search + matches = + name.toLowerCase().includes(term) || + funcname.toLowerCase().includes(term) || + filename.toLowerCase().includes(term); + } + + if (matches) { + matchCount++; + d3.select(this).classed("search-match", true); + } else { + d3.select(this).classed("search-dim", true); + } + } + }); + + if (searchInput) { + searchInput.classList.remove("has-matches", "no-matches"); + searchInput.classList.add(matchCount > 0 ? "has-matches" : "no-matches"); + } + + // Mark matching hotspot as active + document.querySelectorAll('.hotspot').forEach(h => { + if (h.dataset.searchterm && h.dataset.searchterm.toLowerCase() === searchTerm.toLowerCase()) { + h.classList.add('active'); + } + }); + } else if (searchInput) { + searchInput.classList.remove("has-matches", "no-matches"); + } +} + +function searchForHotspot(funcname) { + const searchInput = document.getElementById('search-input'); + const searchWrapper = document.querySelector('.search-wrapper'); + if (searchInput) { + // Toggle: if already searching for this term, clear it + if (searchInput.value.trim() === funcname) { + clearSearch(); + } else { + searchInput.value = funcname; + if (searchWrapper) { + searchWrapper.classList.add('has-value'); + } + performSearch(); + } + } +} + +function initSearchHandlers() { + const searchInput = document.getElementById("search-input"); + const searchWrapper = document.querySelector(".search-wrapper"); + if (!searchInput) return; + + let searchTimeout; + function performSearch() { + const term = searchInput.value.trim(); + updateSearchHighlight(term, searchInput); + // Toggle has-value class for clear button visibility + if (searchWrapper) { + searchWrapper.classList.toggle("has-value", term.length > 0); + } + } + + searchInput.addEventListener("input", function () { + clearTimeout(searchTimeout); + searchTimeout = setTimeout(performSearch, 150); + }); + + window.performSearch = performSearch; +} + +function clearSearch() { + const searchInput = document.getElementById("search-input"); + const searchWrapper = document.querySelector(".search-wrapper"); + if (searchInput) { + searchInput.value = ""; + searchInput.classList.remove("has-matches", "no-matches"); + if (searchWrapper) { + searchWrapper.classList.remove("has-value"); + } + // Clear highlights + d3.selectAll("#chart rect") + .classed("search-match", false) + .classed("search-dim", false); + // Clear active hotspot + document.querySelectorAll('.hotspot').forEach(h => h.classList.remove('active')); + } +} + +// ============================================================================ +// Resize Handler +// ============================================================================ + +function handleResize() { + let resizeTimeout; + window.addEventListener("resize", function () { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(resizeChart, 100); + }); +} + +function initSidebarResize() { + const sidebar = document.getElementById('sidebar'); + const resizeHandle = document.getElementById('sidebar-resize-handle'); + if (!sidebar || !resizeHandle) return; + + let isResizing = false; + let startX = 0; + let startWidth = 0; + const minWidth = 200; + const maxWidth = 600; + + resizeHandle.addEventListener('mousedown', function(e) { + isResizing = true; + startX = e.clientX; + startWidth = sidebar.offsetWidth; + resizeHandle.classList.add('resizing'); + document.body.classList.add('resizing-sidebar'); + e.preventDefault(); + }); + + document.addEventListener('mousemove', function(e) { + if (!isResizing) return; + + const deltaX = e.clientX - startX; + const newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth); + sidebar.style.width = newWidth + 'px'; + e.preventDefault(); + }); + + document.addEventListener('mouseup', function() { + if (isResizing) { + isResizing = false; + resizeHandle.classList.remove('resizing'); + document.body.classList.remove('resizing-sidebar'); + + // Save the new width + const width = sidebar.offsetWidth; + localStorage.setItem('flamegraph-sidebar-width', width); + + // Resize chart after sidebar resize + setTimeout(() => { + resizeChart(); + }, 10); + } + }); +} + +// ============================================================================ +// Thread Stats +// ============================================================================ + +// Mode constants (must match constants.py) +const PROFILING_MODE_WALL = 0; +const PROFILING_MODE_CPU = 1; +const PROFILING_MODE_GIL = 2; +const PROFILING_MODE_ALL = 3; + +function populateThreadStats(data, selectedThreadId = null) { + const stats = data?.stats; + if (!stats || !stats.thread_stats) { + return; + } + + const mode = stats.mode !== undefined ? stats.mode : PROFILING_MODE_WALL; + let threadStats; + + if (selectedThreadId !== null && stats.per_thread_stats && stats.per_thread_stats[selectedThreadId]) { + threadStats = stats.per_thread_stats[selectedThreadId]; + } else { + threadStats = stats.thread_stats; + } + + if (!threadStats || typeof threadStats.total !== 'number' || threadStats.total <= 0) { + return; + } + + const section = document.getElementById('thread-stats-bar'); + if (!section) { + return; + } + + section.style.display = 'block'; + + const gilHeldStat = document.getElementById('gil-held-stat'); + const gilReleasedStat = document.getElementById('gil-released-stat'); + const gilWaitingStat = document.getElementById('gil-waiting-stat'); + + if (mode === PROFILING_MODE_GIL) { + // In GIL mode, hide GIL-related stats + if (gilHeldStat) gilHeldStat.style.display = 'none'; + if (gilReleasedStat) gilReleasedStat.style.display = 'none'; + if (gilWaitingStat) gilWaitingStat.style.display = 'none'; + } else { + // Show all stats + if (gilHeldStat) gilHeldStat.style.display = 'block'; + if (gilReleasedStat) gilReleasedStat.style.display = 'block'; + if (gilWaitingStat) gilWaitingStat.style.display = 'block'; + + const gilHeldPctElem = document.getElementById('gil-held-pct'); + if (gilHeldPctElem) gilHeldPctElem.textContent = `${(threadStats.has_gil_pct || 0).toFixed(1)}%`; + + const gilReleasedPctElem = document.getElementById('gil-released-pct'); + // GIL Released = not holding GIL and not waiting for it + const gilReleasedPct = Math.max(0, 100 - (threadStats.has_gil_pct || 0) - (threadStats.gil_requested_pct || 0)); + if (gilReleasedPctElem) gilReleasedPctElem.textContent = `${gilReleasedPct.toFixed(1)}%`; + + const gilWaitingPctElem = document.getElementById('gil-waiting-pct'); + if (gilWaitingPctElem) gilWaitingPctElem.textContent = `${(threadStats.gil_requested_pct || 0).toFixed(1)}%`; + } + + const gcPctElem = document.getElementById('gc-pct'); + if (gcPctElem) gcPctElem.textContent = `${(threadStats.gc_pct || 0).toFixed(1)}%`; + + // Exception stats + const excPctElem = document.getElementById('exc-pct'); + if (excPctElem) excPctElem.textContent = `${(threadStats.has_exception_pct || 0).toFixed(1)}%`; +} + +// ============================================================================ +// Profile Summary Stats +// ============================================================================ + +function formatNumber(num) { + if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; + if (num >= 1000) return (num / 1000).toFixed(1) + 'K'; + return num.toLocaleString(); +} + +function formatDuration(seconds) { + if (seconds >= 3600) { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + return `${h}h ${m}m`; + } + if (seconds >= 60) { + const m = Math.floor(seconds / 60); + const s = Math.floor(seconds % 60); + return `${m}m ${s}s`; + } + return seconds.toFixed(2) + 's'; +} + +function populateProfileSummary(data) { + const stats = data.stats || {}; + const totalSamples = stats.total_samples || data.value || 0; + const duration = stats.duration_sec || 0; + const sampleRate = stats.sample_rate || (duration > 0 ? totalSamples / duration : 0); + const errorRate = stats.error_rate || 0; + const missedSamples= stats.missed_samples || 0; + + const samplesEl = document.getElementById('stat-total-samples'); + if (samplesEl) samplesEl.textContent = formatNumber(totalSamples); + + const durationEl = document.getElementById('stat-duration'); + if (durationEl) durationEl.textContent = duration > 0 ? formatDuration(duration) : '--'; + + const rateEl = document.getElementById('stat-sample-rate'); + if (rateEl) rateEl.textContent = sampleRate > 0 ? formatNumber(Math.round(sampleRate)) : '--'; + + // Count unique functions + // Use normal (non-inverted) tree structure, but respect thread filtering + const uniqueFunctions = new Set(); + function collectUniqueFunctions(node) { + if (!node) return; + const filename = resolveString(node.filename) || 'unknown'; + const funcname = resolveString(node.funcname) || resolveString(node.name) || 'unknown'; + const lineno = node.lineno || 0; + const key = `${filename}|${lineno}|${funcname}`; + uniqueFunctions.add(key); + if (node.children) node.children.forEach(collectUniqueFunctions); + } + // In inverted mode, use normalData (with thread filter if active) + // In normal mode, use the passed data (already has thread filter applied if any) + let functionCountSource; + if (!normalData) { + functionCountSource = data; + } else if (isInverted) { + if (currentThreadFilter !== 'all') { + functionCountSource = filterDataByThread(normalData, parseInt(currentThreadFilter)); + } else { + functionCountSource = normalData; + } + } else { + functionCountSource = data; + } + collectUniqueFunctions(functionCountSource); + + const functionsEl = document.getElementById('stat-functions'); + if (functionsEl) functionsEl.textContent = formatNumber(uniqueFunctions.size); + + // Efficiency bar + if (errorRate !== undefined && errorRate !== null) { + const efficiency = Math.max(0, Math.min(100, (100 - errorRate))); + + const efficiencySection = document.getElementById('efficiency-section'); + if (efficiencySection) efficiencySection.style.display = 'block'; + + const efficiencyValue = document.getElementById('stat-efficiency'); + if (efficiencyValue) efficiencyValue.textContent = efficiency.toFixed(1) + '%'; + + const efficiencyFill = document.getElementById('efficiency-fill'); + if (efficiencyFill) efficiencyFill.style.width = efficiency + '%'; + } + // MissedSamples bar + if (missedSamples !== undefined && missedSamples !== null) { + const sampleEfficiency = Math.max(0, missedSamples); + + const efficiencySection = document.getElementById('efficiency-section'); + if (efficiencySection) efficiencySection.style.display = 'block'; + + const sampleEfficiencyValue = document.getElementById('stat-missed-samples'); + if (sampleEfficiencyValue) sampleEfficiencyValue.textContent = sampleEfficiency.toFixed(1) + '%'; + + const sampleEfficiencyFill = document.getElementById('missed-samples-fill'); + if (sampleEfficiencyFill) sampleEfficiencyFill.style.width = sampleEfficiency + '%'; + } +} + +// ============================================================================ +// Hotspot Stats +// ============================================================================ + +function populateStats(data) { + // Populate profile summary + populateProfileSummary(data); + + // Populate thread statistics if available + populateThreadStats(data); + + // For hotspots: use normal (non-inverted) tree structure, but respect thread filtering. + // In inverted view, the tree structure changes but the hottest functions remain the same. + // However, if a thread filter is active, we need to show that thread's hotspots. + let hotspotSource; + if (!normalData) { + hotspotSource = data; + } else if (isInverted) { + // In inverted mode, use normalData (with thread filter if active) + if (currentThreadFilter !== 'all') { + hotspotSource = filterDataByThread(normalData, parseInt(currentThreadFilter)); + } else { + hotspotSource = normalData; + } + } else { + // In normal mode, use the passed data (already has thread filter applied if any) + hotspotSource = data; + } + const totalSamples = hotspotSource.value || 0; + + const functionMap = new Map(); + + function collectFunctions(node) { + if (!node) return; + + let filename = resolveString(node.filename); + let funcname = resolveString(node.funcname); + + if (!filename || !funcname) { + const nameStr = resolveString(node.name); + if (nameStr?.includes('(')) { + const match = nameStr.match(/^(.+?)\s*\((.+?):(\d+)\)$/); + if (match) { + funcname = funcname || match[1]; + filename = filename || match[2]; + } + } + } + + filename = filename || 'unknown'; + funcname = funcname || 'unknown'; + + if (filename !== 'unknown' && funcname !== 'unknown' && node.value > 0) { + let childrenValue = 0; + if (node.children) { + childrenValue = node.children.reduce((sum, child) => sum + child.value, 0); + } + const directSamples = Math.max(0, node.value - childrenValue); + + const funcKey = `${filename}:${node.lineno || '?'}:${funcname}`; + + if (functionMap.has(funcKey)) { + const existing = functionMap.get(funcKey); + existing.directSamples += directSamples; + existing.directPercent = (existing.directSamples / totalSamples) * 100; + if (directSamples > existing.maxSingleSamples) { + existing.filename = filename; + existing.lineno = node.lineno || '?'; + existing.maxSingleSamples = directSamples; + } + } else { + functionMap.set(funcKey, { + filename: filename, + lineno: node.lineno || '?', + funcname: funcname, + directSamples, + directPercent: (directSamples / totalSamples) * 100, + maxSingleSamples: directSamples + }); + } + } + + if (node.children) { + node.children.forEach(child => collectFunctions(child)); + } + } + + collectFunctions(hotspotSource); + + const hotSpots = Array.from(functionMap.values()) + .filter(f => f.directPercent > 0.5) + .sort((a, b) => b.directPercent - a.directPercent) + .slice(0, 3); + + // Populate and animate hotspot cards + for (let i = 0; i < 3; i++) { + const num = i + 1; + const card = document.getElementById(`hotspot-${num}`); + const funcEl = document.getElementById(`hotspot-func-${num}`); + const fileEl = document.getElementById(`hotspot-file-${num}`); + const percentEl = document.getElementById(`hotspot-percent-${num}`); + const samplesEl = document.getElementById(`hotspot-samples-${num}`); + + if (i < hotSpots.length && hotSpots[i]) { + const h = hotSpots[i]; + const filename = h.filename || 'unknown'; + const lineno = h.lineno ?? '?'; + const isSpecialFrame = filename === '~' && (lineno === 0 || lineno === '?'); + + let funcDisplay = h.funcname || 'unknown'; + if (funcDisplay.length > 28) funcDisplay = funcDisplay.substring(0, 25) + '...'; + + if (funcEl) funcEl.textContent = funcDisplay; + if (fileEl) { + if (isSpecialFrame) { + fileEl.textContent = '--'; + } else { + const basename = filename !== 'unknown' ? filename.split('/').pop() : 'unknown'; + fileEl.textContent = `${basename}:${lineno}`; + } + } + if (percentEl) percentEl.textContent = `${h.directPercent.toFixed(1)}%`; + if (samplesEl) samplesEl.textContent = ` (${h.directSamples.toLocaleString()})`; + } else { + if (funcEl) funcEl.textContent = '--'; + if (fileEl) fileEl.textContent = '--'; + if (percentEl) percentEl.textContent = '--'; + if (samplesEl) samplesEl.textContent = ''; + } + + // Add click handler and animate entrance + if (card) { + if (i < hotSpots.length && hotSpots[i]) { + const h = hotSpots[i]; + const basename = h.filename !== 'unknown' ? h.filename.split('/').pop() : ''; + const searchTerm = basename && h.lineno !== '?' ? `${basename}:${h.lineno}` : h.funcname; + card.dataset.searchterm = searchTerm; + card.onclick = () => searchForHotspot(searchTerm); + card.style.cursor = 'pointer'; + } else { + card.onclick = null; + delete card.dataset.searchterm; + card.style.cursor = 'default'; + } + + setTimeout(() => { + card.classList.add('visible'); + }, 100 + i * 80); + } + } +} + +// ============================================================================ +// Thread Filter +// ============================================================================ + +function initThreadFilter(data) { + const threadFilter = document.getElementById('thread-filter'); + const threadSection = document.getElementById('thread-section'); + + if (!threadFilter || !data.threads) return; + + threadFilter.innerHTML = ''; + + const threads = data.threads || []; + threads.forEach(threadId => { + const option = document.createElement('option'); + option.value = threadId; + option.textContent = `Thread ${threadId}`; + threadFilter.appendChild(option); + }); + + if (threads.length > 1 && threadSection) { + threadSection.style.display = 'block'; + } +} + +function filterByThread() { + const threadFilter = document.getElementById('thread-filter'); + if (!threadFilter || !normalData) return; + + const selectedThread = threadFilter.value; + currentThreadFilter = selectedThread; + const baseData = isInverted ? invertedData : normalData; + + let filteredData; + let selectedThreadId = null; + + if (selectedThread === 'all') { + filteredData = baseData; + } else { + selectedThreadId = parseInt(selectedThread, 10); + filteredData = filterDataByThread(baseData, selectedThreadId); + + if (filteredData.strings) { + stringTable = filteredData.strings; + filteredData = resolveStringIndices(filteredData); + } + } + + const tooltip = createPythonTooltip(filteredData); + const chart = createFlamegraph(tooltip, filteredData.value); + renderFlamegraph(chart, filteredData); + + populateThreadStats(baseData, selectedThreadId); +} + +function filterDataByThread(data, threadId) { + function filterNode(node) { + if (!node.threads || !node.threads.includes(threadId)) { + return null; + } + + const filteredNode = { ...node, children: [] }; + + if (node.children && Array.isArray(node.children)) { + filteredNode.children = node.children + .map(child => filterNode(child)) + .filter(child => child !== null); + } + + return filteredNode; + } + + function recalculateValue(node) { + if (!node.children || node.children.length === 0) { + return node.value || 0; + } + const childrenValue = node.children.reduce((sum, child) => sum + recalculateValue(child), 0); + node.value = Math.max(node.value || 0, childrenValue); + return node.value; + } + + const filteredRoot = { ...data, children: [] }; + + if (data.children && Array.isArray(data.children)) { + filteredRoot.children = data.children + .map(child => filterNode(child)) + .filter(child => child !== null); + } + + recalculateValue(filteredRoot); + return filteredRoot; +} + +// ============================================================================ +// Control Functions +// ============================================================================ + +function resetZoom() { + if (window.flamegraphChart) { + window.flamegraphChart.resetZoom(); + } +} + +function exportSVG() { + const svgElement = document.querySelector("#chart svg"); + if (!svgElement) { + console.warn("Cannot export: No flamegraph SVG found"); + return; + } + const serializer = new XMLSerializer(); + const svgString = serializer.serializeToString(svgElement); + const blob = new Blob([svgString], { type: "image/svg+xml" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "python-performance-flamegraph.svg"; + a.click(); + URL.revokeObjectURL(url); +} + +// ============================================================================ +// Inverted Flamegraph +// ============================================================================ + +// Example: "file.py|10|foo" or "~|0|" for special frames +function getInvertNodeKey(node) { + return `${node.filename || '~'}|${node.lineno || 0}|${node.funcname || node.name}`; +} + +function accumulateInvertedNode(parent, stackFrame, leaf) { + const key = getInvertNodeKey(stackFrame); + + if (!parent.children[key]) { + parent.children[key] = { + name: stackFrame.name, + value: 0, + children: {}, + filename: stackFrame.filename, + lineno: stackFrame.lineno, + funcname: stackFrame.funcname, + source: stackFrame.source, + threads: new Set() + }; + } + + const node = parent.children[key]; + node.value += leaf.value; + if (leaf.threads) { + leaf.threads.forEach(t => node.threads.add(t)); + } + + return node; +} + +function processLeaf(invertedRoot, path, leafNode) { + if (!path || path.length === 0) { + return; + } + + let invertedParent = accumulateInvertedNode(invertedRoot, leafNode, leafNode); + + // Walk backwards through the call stack + for (let i = path.length - 2; i >= 0; i--) { + invertedParent = accumulateInvertedNode(invertedParent, path[i], leafNode); + } +} + +function traverseInvert(path, currentNode, invertedRoot) { + const children = currentNode.children || []; + const childThreads = new Set(children.flatMap(c => c.threads || [])); + const selfThreads = (currentNode.threads || []).filter(t => !childThreads.has(t)); + + if (selfThreads.length > 0) { + processLeaf(invertedRoot, path, { ...currentNode, threads: selfThreads }); + } + + children.forEach(child => traverseInvert(path.concat([child]), child, invertedRoot)); +} + +function convertInvertDictToArray(node) { + if (node.threads instanceof Set) { + node.threads = Array.from(node.threads).sort((a, b) => a - b); + } + + const children = node.children; + if (children && typeof children === 'object' && !Array.isArray(children)) { + node.children = Object.values(children); + node.children.sort((a, b) => b.value - a.value || a.name.localeCompare(b.name)); + node.children.forEach(convertInvertDictToArray); + } + return node; +} + +function generateInvertedFlamegraph(data) { + const invertedRoot = { + name: data.name, + value: data.value, + children: {}, + stats: data.stats, + threads: data.threads + }; + + const children = data.children || []; + if (children.length === 0) { + // Single-frame tree: the root is its own leaf + processLeaf(invertedRoot, [data], data); + } else { + children.forEach(child => traverseInvert([child], child, invertedRoot)); + } + + convertInvertDictToArray(invertedRoot); + return invertedRoot; +} + +function updateToggleUI(toggleId, isOn) { + const toggle = document.getElementById(toggleId); + if (toggle) { + const track = toggle.querySelector('.toggle-track'); + const labels = toggle.querySelectorAll('.toggle-label'); + if (isOn) { + track.classList.add('on'); + labels[0].classList.remove('active'); + labels[1].classList.add('active'); + } else { + track.classList.remove('on'); + labels[0].classList.add('active'); + labels[1].classList.remove('active'); + } + } +} + +function toggleInvert() { + isInverted = !isInverted; + updateToggleUI('toggle-invert', isInverted); + + // Build inverted data on first use + if (isInverted && !invertedData) { + invertedData = generateInvertedFlamegraph(normalData); + } + + let dataToRender = isInverted ? invertedData : normalData; + + if (currentThreadFilter !== 'all') { + dataToRender = filterDataByThread(dataToRender, parseInt(currentThreadFilter)); + } + + const tooltip = createPythonTooltip(dataToRender); + const chart = createFlamegraph(tooltip, dataToRender.value); + renderFlamegraph(chart, dataToRender); +} + +// ============================================================================ +// Initialization +// ============================================================================ + +function initFlamegraph() { + ensureLibraryLoaded(); + restoreUIState(); + setupLogos(); + + if (EMBEDDED_DATA.strings) { + stringTable = EMBEDDED_DATA.strings; + normalData = resolveStringIndices(EMBEDDED_DATA); + } else { + normalData = EMBEDDED_DATA; + } + + // Initialize opcode mapping from embedded data + initOpcodeMapping(EMBEDDED_DATA); + + // Inverted data will be built on first toggle + invertedData = null; + + initThreadFilter(normalData); + + const tooltip = createPythonTooltip(normalData); + const chart = createFlamegraph(tooltip, normalData.value); + renderFlamegraph(chart, normalData); + initSearchHandlers(); + initSidebarResize(); + handleResize(); + + const toggleInvertBtn = document.getElementById('toggle-invert'); + if (toggleInvertBtn) { + toggleInvertBtn.addEventListener('click', toggleInvert); + } +} + +// Keyboard shortcut: Enter/Space activates toggle switches +document.addEventListener('keydown', function(e) { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + return; + } + if ((e.key === 'Enter' || e.key === ' ') && e.target.classList.contains('toggle-switch')) { + e.preventDefault(); + e.target.click(); + } +}); + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", initFlamegraph); +} else { + initFlamegraph(); +} diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html b/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html new file mode 100644 index 00000000000..936c9adfc8c --- /dev/null +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html @@ -0,0 +1,362 @@ + + + + + + Tachyon Profiler - Flamegraph Report + + + + + + + +
    + +
    +
    + + Tachyon + + Flamegraph Report +
    +
    + + +
    +
    + + + + + + + + +
    +
    + + +
    + + + + +
    +
    +
    +
    + + +
    + + Tachyon Profiler + + + Python Sampling Profiler + + + + + +
    +
    + + + + diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.css b/Lib/profiling/sampling/_heatmap_assets/heatmap.css new file mode 100644 index 00000000000..9999cd6760f --- /dev/null +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.css @@ -0,0 +1,1557 @@ +/* ========================================================================== + Heatmap Viewer - Component-Specific CSS + + DEPENDENCY: Requires _shared_assets/base.css to be loaded first + This file extends the shared foundation with heatmap-specific styles. + ========================================================================== */ + +/* Heatmap heat colors - using base.css colors with 60% opacity */ +[data-theme="dark"] { + --heat-1: rgba(90, 123, 167, 0.60); + --heat-2: rgba(106, 148, 168, 0.60); + --heat-3: rgba(122, 172, 172, 0.60); + --heat-4: rgba(142, 196, 152, 0.60); + --heat-5: rgba(168, 216, 136, 0.60); + --heat-6: rgba(200, 222, 122, 0.60); + --heat-7: rgba(244, 212, 93, 0.60); + --heat-8: rgba(255, 122, 69, 0.60); +} + +/* -------------------------------------------------------------------------- + Layout Overrides (Heatmap-specific) + -------------------------------------------------------------------------- */ + +.app-layout { + min-height: 100vh; +} + +/* Sticky top bar for heatmap views */ +.top-bar { + position: sticky; + top: 0; + z-index: 100; +} + +/* -------------------------------------------------------------------------- + Main Content Area + -------------------------------------------------------------------------- */ + +.main-content { + flex: 1; + padding: 24px 3%; + width: 100%; + max-width: 100%; +} + +/* -------------------------------------------------------------------------- + Stats Summary Cards - Enhanced with Icons & Animations + -------------------------------------------------------------------------- */ + +.stats-summary { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 12px; + margin-bottom: 24px; +} + +.stat-card { + display: flex; + align-items: center; + gap: 12px; + background: var(--bg-primary); + border: 2px solid var(--border); + border-radius: 10px; + padding: 14px 16px; + transition: all var(--transition-fast); + animation: slideUp 0.5s ease-out backwards; + animation-delay: calc(var(--i, 0) * 0.08s); + position: relative; + overflow: hidden; +} + +.stat-card:nth-child(1) { --i: 0; --card-color: 55, 118, 171; } +.stat-card:nth-child(2) { --i: 1; --card-color: 40, 167, 69; } +.stat-card:nth-child(3) { --i: 2; --card-color: 255, 193, 7; } +.stat-card:nth-child(4) { --i: 3; --card-color: 111, 66, 193; } +.stat-card:nth-child(5) { --i: 4; --card-color: 220, 53, 69; } +.stat-card:nth-child(6) { --i: 5; --card-color: 23, 162, 184; } + +.stat-card:hover { + border-color: rgba(var(--card-color), 0.6); + background: linear-gradient(135deg, rgba(var(--card-color), 0.08) 0%, var(--bg-primary) 100%); + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(var(--card-color), 0.15); +} + +.stat-icon { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + background: linear-gradient(135deg, rgba(var(--card-color), 0.15) 0%, rgba(var(--card-color), 0.05) 100%); + border: 1px solid rgba(var(--card-color), 0.2); + border-radius: 10px; + flex-shrink: 0; + transition: all var(--transition-fast); +} + +.stat-card:hover .stat-icon { + transform: scale(1.05) rotate(-2deg); + background: linear-gradient(135deg, rgba(var(--card-color), 0.25) 0%, rgba(var(--card-color), 0.1) 100%); +} + +.stat-data { + flex: 1; + min-width: 0; +} + +.stat-value { + font-family: var(--font-mono); + font-size: 1.35em; + font-weight: 800; + color: rgb(var(--card-color)); + display: block; + line-height: 1.1; + letter-spacing: -0.3px; +} + +.stat-label { + font-size: 10px; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.3px; + margin-top: 2px; +} + +/* Sparkline decoration for stats */ +.stat-sparkline { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 30px; + opacity: 0.1; + background: linear-gradient(180deg, + transparent 0%, + rgba(var(--card-color), 0.3) 100% + ); + pointer-events: none; +} + +/* -------------------------------------------------------------------------- + Rate Cards (Error Rate, Missed Samples) with Progress Bars + -------------------------------------------------------------------------- */ + +.rate-card { + display: flex; + flex-direction: column; + gap: 12px; + background: var(--bg-primary); + border: 2px solid var(--border); + border-radius: 12px; + padding: 18px 20px; + transition: all var(--transition-fast); + animation: slideUp 0.5s ease-out backwards; + position: relative; + overflow: hidden; +} + +.rate-card:nth-child(5) { animation-delay: 0.32s; --rate-color: 220, 53, 69; } +.rate-card:nth-child(6) { animation-delay: 0.40s; --rate-color: 255, 152, 0; } + +.rate-card:hover { + border-color: rgba(var(--rate-color), 0.5); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(var(--rate-color), 0.15); +} + +.rate-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.rate-info { + display: flex; + align-items: center; + gap: 10px; +} + +.rate-icon { + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + background: linear-gradient(135deg, rgba(var(--rate-color), 0.15) 0%, rgba(var(--rate-color), 0.05) 100%); + border: 1px solid rgba(var(--rate-color), 0.2); + border-radius: 10px; + flex-shrink: 0; +} + +.rate-label { + font-size: 12px; + font-weight: 600; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.3px; +} + +.rate-value { + font-family: var(--font-mono); + font-size: 1.4em; + font-weight: 800; + color: rgb(var(--rate-color)); +} + +.rate-bar { + height: 8px; + background: var(--bg-tertiary); + border-radius: 4px; + overflow: hidden; + position: relative; +} + +.rate-fill { + height: 100%; + border-radius: 4px; + transition: width 0.8s ease-out; + position: relative; + overflow: hidden; +} + +.rate-fill.error { + background: linear-gradient(90deg, #dc3545 0%, #ff6b6b 100%); +} + +.rate-fill.warning { + background: linear-gradient(90deg, #ff9800 0%, #ffc107 100%); +} + +.rate-fill.good { + background: linear-gradient(90deg, #28a745 0%, #20c997 100%); +} + +/* Shimmer animation on rate bars */ +.rate-fill::after { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 255, 255, 0.4) 50%, + transparent 100% + ); + animation: shimmer 2.5s ease-in-out infinite; +} + +/* -------------------------------------------------------------------------- + Section Headers + -------------------------------------------------------------------------- */ + +.section-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 16px; + padding-bottom: 12px; + border-bottom: 2px solid var(--python-gold); +} + +.section-title { + font-size: 18px; + font-weight: 700; + color: var(--text-primary); + margin: 0; + flex: 1; +} + +/* -------------------------------------------------------------------------- + Filter Controls + -------------------------------------------------------------------------- */ + +.filter-controls { + display: flex; + gap: 8px; + flex-wrap: wrap; + align-items: center; + margin-bottom: 16px; +} + +.control-btn { + padding: 8px 16px; + background: var(--bg-secondary); + color: var(--text-primary); + border: 1px solid var(--border); + border-radius: 6px; + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: all var(--transition-fast); +} + +.control-btn:hover { + background: var(--accent); + color: white; + border-color: var(--accent); +} + +/* -------------------------------------------------------------------------- + Type Sections (stdlib, project, etc) + -------------------------------------------------------------------------- */ + +.type-section { + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px; + overflow: hidden; + margin-bottom: 12px; +} + +.type-header { + padding: 12px 16px; + background: var(--header-gradient); + color: white; + cursor: pointer; + display: flex; + align-items: center; + gap: 10px; + user-select: none; + transition: all var(--transition-fast); + font-weight: 600; +} + +.type-header:hover { + opacity: 0.95; +} + +.type-icon { + font-size: 12px; + transition: transform var(--transition-fast); + min-width: 12px; +} + +.type-title { + font-size: 14px; + flex: 1; +} + +.type-stats { + font-size: 12px; + opacity: 0.9; + background: rgba(255, 255, 255, 0.15); + padding: 4px 10px; + border-radius: 4px; + font-family: var(--font-mono); +} + +.type-content { + padding: 12px; +} + +/* -------------------------------------------------------------------------- + Folder Nodes (hierarchical structure) + -------------------------------------------------------------------------- */ + +.folder-node { + margin-bottom: 6px; +} + +.folder-header { + padding: 8px 12px; + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + user-select: none; + transition: all var(--transition-fast); +} + +.folder-header:hover { + background: var(--accent-glow); + border-color: var(--accent); +} + +.folder-icon { + font-size: 10px; + color: var(--accent); + transition: transform var(--transition-fast); + min-width: 12px; +} + +.folder-name { + flex: 1; + font-weight: 500; + color: var(--text-primary); + font-size: 13px; +} + +.folder-stats { + font-size: 11px; + color: var(--text-secondary); + background: var(--bg-tertiary); + padding: 2px 8px; + border-radius: 4px; + font-family: var(--font-mono); +} + +.folder-content { + padding-left: 20px; + margin-top: 6px; +} + +/* -------------------------------------------------------------------------- + File Items + -------------------------------------------------------------------------- */ + +.files-list { + display: flex; + flex-direction: column; + gap: 4px; + margin-top: 8px; +} + +.file-item { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 12px; + background: var(--bg-primary); + border: 1px solid var(--border-subtle); + border-radius: 6px; + transition: all var(--transition-fast); +} + +.file-item:hover { + background: var(--bg-secondary); + border-color: var(--border); +} + +.file-item .file-link { + flex: 1; + min-width: 0; + font-size: 13px; +} + +.file-samples { + font-size: 12px; + color: var(--text-secondary); + font-weight: 600; + white-space: nowrap; + width: 130px; + flex-shrink: 0; + text-align: right; + font-family: var(--font-mono); +} + +.heatmap-bar-container { + width: 120px; + flex-shrink: 0; + display: flex; + align-items: center; +} + +.heatmap-bar { + flex-shrink: 0; + border-radius: 2px; +} + +/* Links */ +.file-link { + color: var(--accent); + text-decoration: none; + font-weight: 500; + transition: color var(--transition-fast); +} + +.file-link:hover { + color: var(--accent-hover); + text-decoration: underline; +} + +/* -------------------------------------------------------------------------- + Module Badges + -------------------------------------------------------------------------- */ + +.module-badge { + display: inline-block; + padding: 3px 8px; + border-radius: 4px; + font-size: 11px; + font-weight: 600; +} + +.badge-stdlib { + background: rgba(40, 167, 69, 0.15); + color: #28a745; +} + +.badge-site-packages { + background: rgba(0, 123, 255, 0.15); + color: #007bff; +} + +.badge-project { + background: rgba(255, 193, 7, 0.2); + color: #d39e00; +} + +.badge-other { + background: var(--bg-tertiary); + color: var(--text-secondary); +} + +[data-theme="dark"] .badge-stdlib { + background: rgba(40, 167, 69, 0.25); + color: #5dd879; +} + +[data-theme="dark"] .badge-site-packages { + background: rgba(88, 166, 255, 0.25); + color: #79b8ff; +} + +[data-theme="dark"] .badge-project { + background: rgba(255, 212, 59, 0.25); + color: #ffd43b; +} + +/* ========================================================================== + FILE VIEW STYLES (Code Display) + ========================================================================== */ + +.code-view { + font-family: var(--font-mono); + min-height: 100vh; +} + +/* Code Header (Top Bar for file view) */ +.code-header { + height: var(--topbar-height); + background: var(--header-gradient); + display: flex; + align-items: center; + padding: 0 16px; + gap: 16px; + box-shadow: 0 2px 10px rgba(55, 118, 171, 0.25); + border-bottom: 2px solid var(--python-gold); + position: sticky; + top: 0; + z-index: 100; +} + +.code-header-content { + display: flex; + align-items: center; + justify-content: space-between; + width: 94%; + max-width: 100%; + margin: 0 auto; +} + +.code-header h1 { + font-size: 14px; + font-weight: 600; + color: white; + margin: 0; + font-family: var(--font-mono); + display: flex; + align-items: center; + gap: 8px; +} + +/* File Stats Bar */ +.file-stats { + background: var(--bg-secondary); + padding: 16px 24px; + border-bottom: 1px solid var(--border); +} + +.file-stats .stats-grid { + width: 94%; + max-width: 100%; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 12px; +} + +.stat-item { + background: var(--bg-primary); + padding: 12px; + border-radius: 8px; + box-shadow: var(--shadow-sm); + text-align: center; + border: 1px solid var(--border); + transition: all var(--transition-fast); +} + +.stat-item:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-md); + border-color: var(--accent); +} + +.stat-item .stat-value { + font-size: 1.4em; + font-weight: 700; + color: var(--accent); +} + +.stat-item .stat-label { + color: var(--text-muted); + font-size: 10px; + margin-top: 2px; +} + +/* Legend */ +.legend { + background: var(--bg-secondary); + padding: 12px 24px; + border-bottom: 1px solid var(--border); +} + +.legend-content { + width: 100%; + display: flex; + align-items: center; + gap: 20px; + flex-wrap: nowrap; +} + +.legend-separator { + width: 1px; + height: 24px; + background: var(--border); + flex-shrink: 0; +} + +.legend-title { + font-weight: 600; + color: var(--text-primary); + font-size: 13px; + font-family: var(--font-sans); + flex-shrink: 0; +} + +.legend-gradient { + width: 150px; + flex-shrink: 0; + height: 20px; + background: linear-gradient(90deg, + var(--bg-tertiary) 0%, + var(--heat-2) 25%, + var(--heat-4) 50%, + var(--heat-6) 75%, + var(--heat-8) 100% + ); + border-radius: 4px; + border: 1px solid var(--border); +} + +.legend-labels { + display: flex; + gap: 12px; + font-size: 11px; + color: var(--text-muted); + font-family: var(--font-sans); + flex-shrink: 0; +} + +/* Legend Controls Group - wraps toggles and bytecode button together */ +.legend-controls { + display: flex; + align-items: center; + gap: 20px; + flex-shrink: 0; + margin-left: auto; +} + +/* Heatmap-Specific Toggle Overrides */ +#toggle-color-mode .toggle-track.on { + background: #8e44ad; + border-color: #8e44ad; + box-shadow: 0 0 8px rgba(142, 68, 173, 0.3); +} + +#toggle-cold .toggle-track.on { + background: #e67e22; + border-color: #e67e22; + box-shadow: 0 0 8px rgba(230, 126, 34, 0.3); +} + +/* Code Container */ +.code-container { + width: 94%; + max-width: 100%; + margin: 16px auto; + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px 8px 8px 8px; + box-shadow: var(--shadow-sm); + /* Allow horizontal scroll for long lines, but don't clip sticky header */ +} + +/* Code Header Row */ +.code-header-row { + position: sticky; + top: var(--topbar-height); + z-index: 50; + display: flex; + background: var(--bg-secondary); + border-bottom: 2px solid var(--border); + font-weight: 700; + font-size: 11px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + border-radius: 8px 8px 0 0; +} + +.header-line-number { + flex-shrink: 0; + width: 60px; + padding: 8px 10px; + text-align: right; + border-right: 1px solid var(--border); +} + +.header-samples-self, +.header-samples-cumulative { + flex-shrink: 0; + width: 90px; + padding: 8px 10px; + text-align: right; + border-right: 1px solid var(--border); +} + +.header-samples-self { + color: var(--heat-8); +} + +.header-samples-cumulative { + color: var(--accent); +} + +.header-content { + flex: 1; + padding: 8px 15px; +} + +/* Code Lines */ +.code-line { + position: relative; + display: flex; + min-height: 20px; + line-height: 20px; + font-size: 13px; + transition: background var(--transition-fast); + scroll-margin-top: calc(var(--topbar-height) + 50px); +} + +.code-line:hover { + filter: brightness(0.97); +} + +[data-theme="dark"] .code-line:hover { + filter: brightness(1.1); +} + +.line-number { + flex-shrink: 0; + width: 60px; + padding: 0 10px; + text-align: right; + color: var(--text-muted); + background: var(--bg-secondary); + border-right: 1px solid var(--border); + user-select: none; + transition: all var(--transition-fast); +} + +.line-number:hover { + background: var(--accent); + color: white; + cursor: pointer; +} + +.line-samples-self, +.line-samples-cumulative { + flex-shrink: 0; + width: 90px; + padding: 0 10px; + text-align: right; + background: var(--bg-secondary); + border-right: 1px solid var(--border); + font-weight: 600; + user-select: none; + font-size: 12px; +} + +.line-samples-self { + color: var(--heat-8); +} + +.line-samples-cumulative { + color: var(--accent); +} + +.line-content { + flex: 1; + padding: 0 15px; + white-space: pre; + overflow-x: auto; +} + +/* Scrollbar Styling */ +.line-content::-webkit-scrollbar { + height: 6px; +} + +.line-content::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; +} + +.line-content::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} + +/* Navigation Buttons */ +.line-nav-buttons { + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + display: flex; + gap: 4px; + align-items: center; +} + +.nav-btn { + padding: 2px 6px; + font-size: 12px; + font-weight: 500; + border: 1px solid var(--accent); + border-radius: 4px; + background: var(--bg-primary); + color: var(--accent); + cursor: pointer; + transition: all var(--transition-fast); + user-select: none; + line-height: 1; +} + +.nav-btn:hover:not(:disabled) { + background: var(--accent); + color: white; + transform: translateY(-1px); + box-shadow: var(--shadow-sm); +} + +.nav-btn:active:not(:disabled) { + transform: translateY(0); +} + +.nav-btn:disabled { + opacity: 0.3; + cursor: not-allowed; + color: var(--text-muted); + background: var(--bg-secondary); + border-color: var(--border); +} + +.nav-btn.caller { + color: var(--nav-caller); + border-color: var(--nav-caller); +} + +.nav-btn.callee { + color: var(--nav-callee); + border-color: var(--nav-callee); +} + +.nav-btn.caller:hover:not(:disabled) { + background: var(--nav-caller-hover); + color: white; +} + +.nav-btn.callee:hover:not(:disabled) { + background: var(--nav-callee-hover); + color: white; +} + +/* Highlighted target line */ +.code-line:target { + animation: highlight-line 2s ease-out; +} + +@keyframes highlight-line { + 0% { + background: rgba(255, 212, 59, 0.6) !important; + outline: 3px solid var(--python-gold); + outline-offset: -3px; + } + 50% { + background: rgba(255, 212, 59, 0.5) !important; + outline: 3px solid var(--python-gold); + outline-offset: -3px; + } + 100% { + outline: 3px solid transparent; + outline-offset: -3px; + } +} + +/* Popup menu for multiple callees */ +.callee-menu { + position: absolute; + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: var(--shadow-lg); + padding: 8px; + z-index: 1000; + min-width: 250px; + max-width: 400px; + max-height: 300px; + overflow-y: auto; +} + +.callee-menu-header { + font-weight: 600; + color: var(--text-primary); + margin-bottom: 8px; + padding-bottom: 8px; + border-bottom: 1px solid var(--border); + font-size: 13px; + font-family: var(--font-sans); +} + +.callee-menu-item { + padding: 8px; + margin: 4px 0; + border-radius: 6px; + cursor: pointer; + transition: background var(--transition-fast); + display: flex; + flex-direction: column; + gap: 4px; +} + +.callee-menu-item:hover { + background: var(--bg-secondary); +} + +.callee-menu-func { + font-weight: 500; + color: var(--accent); + font-size: 12px; +} + +.callee-menu-file { + font-size: 11px; + color: var(--text-muted); +} + +.count-badge { + display: inline-block; + background: var(--accent); + color: white; + font-size: 10px; + padding: 2px 6px; + border-radius: 4px; + font-weight: 600; + margin-left: 6px; +} + +/* Callee menu scrollbar */ +.callee-menu::-webkit-scrollbar { + width: 6px; +} + +.callee-menu::-webkit-scrollbar-track { + background: var(--bg-secondary); + border-radius: 3px; +} + +.callee-menu::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; +} + +/* -------------------------------------------------------------------------- + Scroll Minimap Marker + -------------------------------------------------------------------------- */ + +#scroll_marker { + position: fixed; + z-index: 1000; + right: 0; + top: 0; + width: 12px; + height: 100%; + background: var(--bg-secondary); + border-left: 1px solid var(--border); + pointer-events: none; +} + +#scroll_marker .marker { + position: absolute; + min-height: 3px; + width: 100%; + pointer-events: none; +} + +#scroll_marker .marker.cold { + background: var(--heat-1); +} + +#scroll_marker .marker.cool { + background: var(--heat-2); +} + +#scroll_marker .marker.mild { + background: var(--heat-3); +} + +#scroll_marker .marker.warm { + background: var(--heat-4); +} + +#scroll_marker .marker.hot { + background: var(--heat-5); +} + +#scroll_marker .marker.very-hot { + background: var(--heat-6); +} + +#scroll_marker .marker.intense { + background: var(--heat-7); +} + +#scroll_marker .marker.extreme { + background: var(--heat-8); +} + +/* -------------------------------------------------------------------------- + Responsive (Heatmap-specific) + -------------------------------------------------------------------------- */ + +@media (max-width: 1100px) { + .stats-summary { + grid-template-columns: repeat(2, 1fr); + } + + .legend-content { + flex-wrap: wrap; + justify-content: center; + } + + .legend-controls { + margin-left: 0; + } +} + +@media (max-width: 900px) { + .main-content { + padding: 16px; + } +} + +@media (max-width: 600px) { + .stats-summary { + grid-template-columns: 1fr; + } + + .file-stats .stats-grid { + grid-template-columns: repeat(2, 1fr); + } + + .legend-content { + flex-direction: column; + align-items: center; + gap: 12px; + } + + .legend-gradient { + width: 100%; + max-width: none; + } + + .legend-separator { + width: 80%; + height: 1px; + } + + .legend-controls { + flex-direction: column; + gap: 12px; + } + + .legend-controls .toggle-switch { + justify-content: center; + } + + .legend-controls .toggle-switch .toggle-label:first-child { + width: 70px; + text-align: right; + } + + .legend-controls .toggle-switch .toggle-label:last-child { + width: 90px; + text-align: left; + } + + /* Compact code columns on small screens */ + .header-line-number, + .line-number { + width: 40px; + } + + .header-samples-self, + .header-samples-cumulative, + .line-samples-self, + .line-samples-cumulative { + width: 55px; + font-size: 10px; + } + + /* Adjust padding - headers need vertical, data rows don't */ + .header-line-number, + .header-samples-self, + .header-samples-cumulative { + padding: 8px 4px; + } + + .line-number, + .line-samples-self, + .line-samples-cumulative { + padding: 0 4px; + } + + .bytecode-panel { + margin: 8px 10px 8px 160px; + } +} + +.bytecode-toggle { + flex-shrink: 0; + width: 20px; + height: 20px; + padding: 0; + margin: 0 4px; + border: none; + background: transparent; + color: var(--code-accent); + cursor: pointer; + font-size: 10px; + transition: transform var(--transition-fast), color var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; +} + +.bytecode-toggle:hover { + color: var(--accent); +} + +.bytecode-spacer { + flex-shrink: 0; + width: 20px; + height: 20px; + margin: 0 4px; +} + +.bytecode-panel { + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: var(--shadow-md); + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-primary); + line-height: 1.5; + word-wrap: break-word; + overflow-wrap: break-word; + padding: 0; + margin: 8px 10px 8px 250px; + position: relative; + z-index: 1; + overflow-y: auto; + max-height: 500px; + flex: 1; + transition: padding 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.bytecode-panel.expanded { + padding: 14px; +} + +.bytecode-wrapper { + position: relative; + display: flex; + overflow: visible; + max-height: 0; + opacity: 0; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease-in-out; +} + +.bytecode-wrapper.expanded { + max-height: 600px; + opacity: 1; + transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease-in-out; +} + +/* Column backdrop matching table header columns (line/self/total) */ +.bytecode-columns { + display: none; + position: absolute; + left: 0; + overflow: hidden; + pointer-events: none; + z-index: 0; +} + +.bytecode-wrapper.expanded .bytecode-columns { + display: flex; + top: 0; + bottom: 0; +} + +.bytecode-panel::-webkit-scrollbar { + width: 8px; +} + +.bytecode-panel::-webkit-scrollbar-track { + background: var(--bg-secondary); + border-radius: 4px; +} + +.bytecode-panel::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; +} + +.bytecode-panel::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} + +/* Specialization summary bar */ +.bytecode-spec-summary { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + margin-bottom: 10px; + border-radius: var(--radius-sm); + background: rgba(100, 100, 100, 0.1); +} + +.bytecode-spec-summary .spec-pct { + font-size: 1.4em; + font-weight: 700; +} + +.bytecode-spec-summary .spec-label { + font-weight: 500; + text-transform: uppercase; + font-size: 0.85em; + letter-spacing: 0.5px; +} + +.bytecode-spec-summary .spec-detail { + color: var(--text-secondary); + font-size: 0.9em; + margin-left: auto; +} + +.bytecode-spec-summary.high { + background: var(--spec-high-bg); + border-left: 3px solid var(--spec-high); +} +.bytecode-spec-summary.high .spec-pct, +.bytecode-spec-summary.high .spec-label { + color: var(--spec-high-text); +} + +.bytecode-spec-summary.medium { + background: var(--spec-medium-bg); + border-left: 3px solid var(--spec-medium); +} +.bytecode-spec-summary.medium .spec-pct, +.bytecode-spec-summary.medium .spec-label { + color: var(--spec-medium-text); +} + +.bytecode-spec-summary.low { + background: var(--spec-low-bg); + border-left: 3px solid var(--spec-low); +} +.bytecode-spec-summary.low .spec-pct, +.bytecode-spec-summary.low .spec-label { + color: var(--spec-low-text); +} + +.bytecode-header { + display: grid; + grid-template-columns: 1fr 80px 80px; + gap: 12px; + padding: 4px 8px; + font-weight: 600; + color: var(--text-secondary); + border-bottom: 1px solid var(--code-border); + margin-bottom: 4px; +} + +.bytecode-expand-all { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + background: var(--bg-secondary); + border: 1px solid var(--code-border); + border-radius: var(--radius-sm); + color: var(--text-secondary); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: all var(--transition-fast); + flex-shrink: 0; +} + +.bytecode-expand-all:hover, +.bytecode-expand-all.expanded { + background: var(--accent); + color: white; + border-color: var(--accent); +} + +.bytecode-expand-all .expand-icon { + font-size: 10px; + transition: transform var(--transition-fast); +} + +.bytecode-expand-all.expanded .expand-icon { + transform: rotate(90deg); +} + +/* ======================================== + INSTRUCTION SPAN HIGHLIGHTING + (triggered only from bytecode panel hover) + ======================================== */ + +/* Highlight from bytecode panel hover */ +.instr-span.highlight-from-bytecode { + outline: 3px solid #ff6b6b !important; + background-color: rgba(255, 107, 107, 0.4) !important; + border-radius: 2px; +} + +/* Bytecode instruction row */ +.bytecode-instruction { + display: grid; + grid-template-columns: 1fr 80px 80px; + gap: 12px; + align-items: center; + padding: 4px 8px; + margin: 2px 0; + border-radius: var(--radius-sm); + cursor: pointer; + transition: background-color var(--transition-fast); +} + +.bytecode-instruction:hover, +.bytecode-instruction.highlight { + background-color: rgba(55, 118, 171, 0.15); +} + +.bytecode-instruction[data-locations] { + cursor: pointer; +} + +.bytecode-instruction[data-locations]:hover { + background-color: rgba(255, 107, 107, 0.2); +} + +.bytecode-opname { + font-weight: 600; + font-family: var(--font-mono); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bytecode-opname.specialized { + color: #2e7d32; +} + +[data-theme="dark"] .bytecode-opname.specialized { + color: #81c784; +} + +.bytecode-opname .base-op { + color: var(--code-text-muted); + font-weight: normal; + font-size: 0.9em; + margin-left: 4px; +} + +.bytecode-samples { + text-align: right; + font-weight: 600; + color: var(--accent); + font-family: var(--font-mono); +} + +.bytecode-samples.hot { + color: #ff6b6b; +} + +.bytecode-heatbar { + width: 60px; + height: 12px; + background: var(--bg-secondary); + border-radius: 2px; + overflow: hidden; + border: 1px solid var(--code-border); +} + +.bytecode-heatbar-fill { + height: 100%; + background: linear-gradient(90deg, #00d4ff 0%, #ff6b00 100%); +} + +.specialization-badge { + display: inline-block; + padding: 1px 6px; + font-size: 0.75em; + background: #e8f5e9; + color: #2e7d32; + border-radius: 3px; + margin-left: 6px; + font-weight: 600; +} + +[data-theme="dark"] .specialization-badge { + background: rgba(129, 199, 132, 0.2); + color: #81c784; +} + +.bytecode-empty { + color: var(--code-text-muted); + font-style: italic; + padding: 8px; +} + +.bytecode-error { + color: #d32f2f; + font-style: italic; + padding: 8px; +} + +/* ======================================== + SPAN TOOLTIPS + ======================================== */ + +.span-tooltip { + position: absolute; + z-index: 10000; + background: var(--bg-primary); + color: var(--text-primary); + padding: 10px 14px; + border-radius: var(--radius-md); + border: 1px solid var(--border); + font-family: var(--font-sans); + font-size: 12px; + box-shadow: var(--shadow-lg); + pointer-events: none; + min-width: 160px; + max-width: 300px; +} + +.span-tooltip::after { + content: ''; + position: absolute; + bottom: -7px; + left: 50%; + transform: translateX(-50%); + border-width: 7px 7px 0; + border-style: solid; + border-color: var(--bg-primary) transparent transparent; + filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.1)); +} + +.span-tooltip-header { + font-weight: 600; + margin-bottom: 8px; + padding-bottom: 6px; + border-bottom: 1px solid var(--border); + color: var(--text-primary); +} + +.span-tooltip-header.hot { + color: #e65100; +} + +.span-tooltip-header.warm { + color: #f59e0b; +} + +.span-tooltip-header.cold { + color: var(--text-muted); +} + +.span-tooltip-row { + display: flex; + justify-content: space-between; + margin: 4px 0; + gap: 16px; +} + +.span-tooltip-label { + color: var(--text-secondary); +} + +.span-tooltip-value { + font-weight: 600; + text-align: right; + color: var(--text-primary); +} + +.span-tooltip-value.highlight { + color: var(--accent); +} + +.span-tooltip-section { + font-weight: 600; + color: var(--text-secondary); + font-size: 11px; + margin-top: 8px; + margin-bottom: 4px; + padding-top: 6px; + border-top: 1px solid var(--border); +} + +.span-tooltip-opcode { + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-primary); + background: var(--bg-secondary); + padding: 3px 8px; + margin: 2px 0; + border-radius: var(--radius-sm); + border-left: 2px solid var(--accent); +} diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js b/Lib/profiling/sampling/_heatmap_assets/heatmap.js new file mode 100644 index 00000000000..d6a91ef2903 --- /dev/null +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js @@ -0,0 +1,759 @@ +// Tachyon Profiler - Heatmap JavaScript +// Interactive features for the heatmap visualization +// Aligned with Flamegraph viewer design patterns + +// ============================================================================ +// State Management +// ============================================================================ + +let currentMenu = null; +let colorMode = 'self'; // 'self' or 'cumulative' - default to self +let coldCodeHidden = false; + +// ============================================================================ +// Theme Support +// ============================================================================ + +function toggleTheme() { + const html = document.documentElement; + const current = html.getAttribute('data-theme') || 'light'; + const next = current === 'light' ? 'dark' : 'light'; + html.setAttribute('data-theme', next); + localStorage.setItem('heatmap-theme', next); + + // Update theme button icon + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = next === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = next === 'dark' ? '' : 'none'; + } + applyLineColors(); + + // Rebuild scroll marker with new theme colors + buildScrollMarker(); +} + +function restoreUIState() { + // Restore theme + const savedTheme = localStorage.getItem('heatmap-theme'); + if (savedTheme) { + document.documentElement.setAttribute('data-theme', savedTheme); + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = savedTheme === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = savedTheme === 'dark' ? '' : 'none'; + } + } +} + +// ============================================================================ +// Utility Functions +// ============================================================================ + +function createElement(tag, className, textContent = '') { + const el = document.createElement(tag); + if (className) el.className = className; + if (textContent) el.textContent = textContent; + return el; +} + +function calculateMenuPosition(buttonRect, menuWidth, menuHeight) { + const viewport = { width: window.innerWidth, height: window.innerHeight }; + const scroll = { + x: window.pageXOffset || document.documentElement.scrollLeft, + y: window.pageYOffset || document.documentElement.scrollTop + }; + + const left = buttonRect.right + menuWidth + 10 < viewport.width + ? buttonRect.right + scroll.x + 10 + : Math.max(scroll.x + 10, buttonRect.left + scroll.x - menuWidth - 10); + + const top = buttonRect.bottom + menuHeight + 10 < viewport.height + ? buttonRect.bottom + scroll.y + 5 + : Math.max(scroll.y + 10, buttonRect.top + scroll.y - menuHeight - 10); + + return { left, top }; +} + +// ============================================================================ +// Menu Management +// ============================================================================ + +function closeMenu() { + if (currentMenu) { + currentMenu.remove(); + currentMenu = null; + } +} + +function showNavigationMenu(button, items, title) { + closeMenu(); + + const menu = createElement('div', 'callee-menu'); + menu.appendChild(createElement('div', 'callee-menu-header', title)); + + items.forEach(linkData => { + const item = createElement('div', 'callee-menu-item'); + + const funcDiv = createElement('div', 'callee-menu-func'); + funcDiv.textContent = linkData.func; + + if (linkData.count !== undefined && linkData.count > 0) { + const countBadge = createElement('span', 'count-badge'); + countBadge.textContent = linkData.count.toLocaleString(); + countBadge.title = `${linkData.count.toLocaleString()} samples`; + funcDiv.appendChild(document.createTextNode(' ')); + funcDiv.appendChild(countBadge); + } + + item.appendChild(funcDiv); + item.appendChild(createElement('div', 'callee-menu-file', linkData.file)); + item.addEventListener('click', () => window.location.href = linkData.link); + menu.appendChild(item); + }); + + const pos = calculateMenuPosition(button.getBoundingClientRect(), 350, 300); + menu.style.left = `${pos.left}px`; + menu.style.top = `${pos.top}px`; + + document.body.appendChild(menu); + currentMenu = menu; +} + +// ============================================================================ +// Navigation +// ============================================================================ + +function handleNavigationClick(button, e) { + e.stopPropagation(); + + const navData = button.getAttribute('data-nav'); + if (navData) { + window.location.href = JSON.parse(navData).link; + return; + } + + const navMulti = button.getAttribute('data-nav-multi'); + if (navMulti) { + const items = JSON.parse(navMulti); + const title = button.classList.contains('caller') ? 'Choose a caller:' : 'Choose a callee:'; + showNavigationMenu(button, items, title); + } +} + +function scrollToTargetLine() { + if (!window.location.hash) return; + const target = document.querySelector(window.location.hash); + if (target) { + target.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } +} + +// ============================================================================ +// Sample Count & Intensity +// ============================================================================ + +function getSampleCount(line) { + let text; + if (colorMode === 'self') { + text = line.querySelector('.line-samples-self')?.textContent.trim().replace(/,/g, ''); + } else { + text = line.querySelector('.line-samples-cumulative')?.textContent.trim().replace(/,/g, ''); + } + return parseInt(text) || 0; +} + +// ============================================================================ +// Scroll Minimap +// ============================================================================ + +function buildScrollMarker() { + const existing = document.getElementById('scroll_marker'); + if (existing) existing.remove(); + + if (document.body.scrollHeight <= window.innerHeight) return; + + const allLines = document.querySelectorAll('.code-line'); + const lines = Array.from(allLines).filter(line => line.style.display !== 'none'); + const markerScale = window.innerHeight / document.body.scrollHeight; + const lineHeight = Math.min(Math.max(3, window.innerHeight / lines.length), 10); + const maxSamples = Math.max(...Array.from(lines, getSampleCount)); + + const scrollMarker = createElement('div', ''); + scrollMarker.id = 'scroll_marker'; + + let prevLine = -99, lastMark, lastTop; + + lines.forEach((line, index) => { + const samples = getSampleCount(line); + if (samples === 0) return; + + const lineTop = Math.floor(line.offsetTop * markerScale); + const lineNumber = index + 1; + const intensityClass = maxSamples > 0 ? (intensityToClass(samples / maxSamples) || 'cold') : 'cold'; + + if (lineNumber === prevLine + 1 && lastMark?.classList.contains(intensityClass)) { + lastMark.style.height = `${lineTop + lineHeight - lastTop}px`; + } else { + lastMark = createElement('div', `marker ${intensityClass}`); + lastMark.style.height = `${lineHeight}px`; + lastMark.style.top = `${lineTop}px`; + scrollMarker.appendChild(lastMark); + lastTop = lineTop; + } + + prevLine = lineNumber; + }); + + document.body.appendChild(scrollMarker); +} + +function applyLineColors() { + const lines = document.querySelectorAll('.code-line'); + lines.forEach(line => { + let intensity; + if (colorMode === 'self') { + intensity = parseFloat(line.getAttribute('data-self-intensity')) || 0; + } else { + intensity = parseFloat(line.getAttribute('data-cumulative-intensity')) || 0; + } + + const color = intensityToColor(intensity); + line.style.background = color; + }); +} + +// ============================================================================ +// Toggle Controls +// ============================================================================ + +function updateToggleUI(toggleId, isOn) { + const toggle = document.getElementById(toggleId); + if (toggle) { + const track = toggle.querySelector('.toggle-track'); + const labels = toggle.querySelectorAll('.toggle-label'); + if (isOn) { + track.classList.add('on'); + labels[0].classList.remove('active'); + labels[1].classList.add('active'); + } else { + track.classList.remove('on'); + labels[0].classList.add('active'); + labels[1].classList.remove('active'); + } + } +} + +function toggleColdCode() { + coldCodeHidden = !coldCodeHidden; + applyHotFilter(); + updateToggleUI('toggle-cold', coldCodeHidden); + buildScrollMarker(); +} + +function applyHotFilter() { + const lines = document.querySelectorAll('.code-line'); + + lines.forEach(line => { + const selfSamples = line.querySelector('.line-samples-self')?.textContent.trim(); + const cumulativeSamples = line.querySelector('.line-samples-cumulative')?.textContent.trim(); + + let isCold; + if (colorMode === 'self') { + isCold = !selfSamples || selfSamples === ''; + } else { + isCold = !cumulativeSamples || cumulativeSamples === ''; + } + + if (isCold) { + line.style.display = coldCodeHidden ? 'none' : 'flex'; + } else { + line.style.display = 'flex'; + } + }); +} + +function toggleColorMode() { + colorMode = colorMode === 'self' ? 'cumulative' : 'self'; + applyLineColors(); + + updateToggleUI('toggle-color-mode', colorMode === 'cumulative'); + + if (coldCodeHidden) { + applyHotFilter(); + } + + buildScrollMarker(); +} + +// ============================================================================ +// Initialization +// ============================================================================ + +document.addEventListener('DOMContentLoaded', function() { + restoreUIState(); + applyLineColors(); + + // Initialize navigation buttons + document.querySelectorAll('.nav-btn').forEach(button => { + button.addEventListener('click', e => handleNavigationClick(button, e)); + }); + + // Initialize line number permalink handlers + document.querySelectorAll('.line-number').forEach(lineNum => { + lineNum.style.cursor = 'pointer'; + lineNum.addEventListener('click', e => { + window.location.hash = `line-${e.target.textContent.trim()}`; + }); + }); + + // Initialize toggle buttons + const toggleColdBtn = document.getElementById('toggle-cold'); + if (toggleColdBtn) toggleColdBtn.addEventListener('click', toggleColdCode); + + const colorModeBtn = document.getElementById('toggle-color-mode'); + if (colorModeBtn) colorModeBtn.addEventListener('click', toggleColorMode); + + // Initialize specialization view toggle (hide if no bytecode data) + const hasBytecode = document.querySelectorAll('.bytecode-toggle').length > 0; + + const specViewBtn = document.getElementById('toggle-spec-view'); + if (specViewBtn) { + if (hasBytecode) { + specViewBtn.addEventListener('click', toggleSpecView); + } else { + specViewBtn.style.display = 'none'; + } + } + + // Initialize expand-all bytecode button + const expandAllBtn = document.getElementById('toggle-all-bytecode'); + if (expandAllBtn) { + if (hasBytecode) { + expandAllBtn.addEventListener('click', toggleAllBytecode); + } else { + expandAllBtn.style.display = 'none'; + } + } + + // Initialize span tooltips + initSpanTooltips(); + + // Build scroll marker and scroll to target + setTimeout(buildScrollMarker, 200); + setTimeout(scrollToTargetLine, 100); +}); + +// Close menu when clicking outside +document.addEventListener('click', e => { + if (currentMenu && !currentMenu.contains(e.target) && !e.target.classList.contains('nav-btn')) { + closeMenu(); + } +}); + +// ======================================== +// SPECIALIZATION VIEW TOGGLE +// ======================================== + +let specViewEnabled = false; + +/** + * Calculate heat color for given intensity (0-1) + * Hot spans (>30%) get warm orange, cold spans get dimmed gray + * @param {number} intensity - Value between 0 and 1 + * @returns {string} rgba color string + */ +function calculateHeatColor(intensity) { + // Hot threshold: only spans with >30% of max samples get color + if (intensity > 0.3) { + // Normalize intensity above threshold to 0-1 + const normalizedIntensity = (intensity - 0.3) / 0.7; + // Warm orange-red with increasing opacity for hotter spans + const alpha = 0.25 + normalizedIntensity * 0.35; // 0.25 to 0.6 + const hotColor = getComputedStyle(document.documentElement).getPropertyValue('--span-hot-base').trim(); + return `rgba(${hotColor}, ${alpha})`; + } else if (intensity > 0) { + // Cold spans: very subtle gray, almost invisible + const coldColor = getComputedStyle(document.documentElement).getPropertyValue('--span-cold-base').trim(); + return `rgba(${coldColor}, 0.1)`; + } + return 'transparent'; +} + +/** + * Apply intensity-based heat colors to source spans + * Hot spans get orange highlight, cold spans get dimmed + * @param {boolean} enable - Whether to enable or disable span coloring + */ +function applySpanHeatColors(enable) { + document.querySelectorAll('.instr-span').forEach(span => { + const samples = enable ? (parseInt(span.dataset.samples) || 0) : 0; + if (samples > 0) { + const intensity = samples / (parseInt(span.dataset.maxSamples) || 1); + span.style.backgroundColor = calculateHeatColor(intensity); + span.style.borderRadius = '2px'; + span.style.padding = '0 1px'; + span.style.cursor = 'pointer'; + } else { + span.style.cssText = ''; + } + }); +} + +// ======================================== +// SPAN TOOLTIPS +// ======================================== + +let activeTooltip = null; + +/** + * Create and show tooltip for a span + */ +function showSpanTooltip(span) { + hideSpanTooltip(); + + const samples = parseInt(span.dataset.samples) || 0; + const maxSamples = parseInt(span.dataset.maxSamples) || 1; + const pct = span.dataset.pct || '0'; + const opcodes = span.dataset.opcodes || ''; + + if (samples === 0) return; + + const intensity = samples / maxSamples; + const isHot = intensity > 0.7; + const isWarm = intensity > 0.3; + const hotnessText = isHot ? 'Hot' : isWarm ? 'Warm' : 'Cold'; + const hotnessClass = isHot ? 'hot' : isWarm ? 'warm' : 'cold'; + + // Build opcodes rows - each opcode on its own row + let opcodesHtml = ''; + if (opcodes) { + const opcodeList = opcodes.split(',').map(op => op.trim()).filter(op => op); + if (opcodeList.length > 0) { + opcodesHtml = ` +
    Opcodes:
    + ${opcodeList.map(op => `
    ${op}
    `).join('')} + `; + } + } + + const tooltip = document.createElement('div'); + tooltip.className = 'span-tooltip'; + tooltip.innerHTML = ` +
    ${hotnessText}
    +
    + Samples: + ${samples.toLocaleString()} +
    +
    + % of line: + ${pct}% +
    + ${opcodesHtml} + `; + + document.body.appendChild(tooltip); + activeTooltip = tooltip; + + // Position tooltip above the span + const rect = span.getBoundingClientRect(); + const tooltipRect = tooltip.getBoundingClientRect(); + + let left = rect.left + (rect.width / 2) - (tooltipRect.width / 2); + let top = rect.top - tooltipRect.height - 8; + + // Keep tooltip in viewport + if (left < 5) left = 5; + if (left + tooltipRect.width > window.innerWidth - 5) { + left = window.innerWidth - tooltipRect.width - 5; + } + if (top < 5) { + top = rect.bottom + 8; // Show below if no room above + } + + tooltip.style.left = `${left + window.scrollX}px`; + tooltip.style.top = `${top + window.scrollY}px`; +} + +/** + * Hide active tooltip + */ +function hideSpanTooltip() { + if (activeTooltip) { + activeTooltip.remove(); + activeTooltip = null; + } +} + +/** + * Initialize span tooltip handlers + */ +function initSpanTooltips() { + document.addEventListener('mouseover', (e) => { + const span = e.target.closest('.instr-span'); + if (span && specViewEnabled) { + showSpanTooltip(span); + } + }); + + document.addEventListener('mouseout', (e) => { + const span = e.target.closest('.instr-span'); + if (span) { + hideSpanTooltip(); + } + }); +} + +function toggleSpecView() { + specViewEnabled = !specViewEnabled; + const lines = document.querySelectorAll('.code-line'); + + if (specViewEnabled) { + lines.forEach(line => { + const specColor = line.getAttribute('data-spec-color'); + line.style.background = specColor || 'transparent'; + }); + } else { + applyLineColors(); + } + + applySpanHeatColors(specViewEnabled); + updateToggleUI('toggle-spec-view', specViewEnabled); + + // Disable/enable color mode toggle based on spec view state + const colorModeToggle = document.getElementById('toggle-color-mode'); + if (colorModeToggle) { + colorModeToggle.classList.toggle('disabled', specViewEnabled); + } + + buildScrollMarker(); +} + +// ======================================== +// BYTECODE PANEL TOGGLE +// ======================================== + +/** + * Toggle bytecode panel visibility for a source line + * @param {HTMLElement} button - The toggle button that was clicked + */ +function toggleBytecode(button) { + const lineDiv = button.closest('.code-line'); + const lineId = lineDiv.id; + const lineNum = lineId.replace('line-', ''); + const panel = document.getElementById(`bytecode-${lineNum}`); + const wrapper = document.getElementById(`bytecode-wrapper-${lineNum}`); + + if (!panel || !wrapper) return; + + const isExpanded = panel.classList.contains('expanded'); + + if (isExpanded) { + panel.classList.remove('expanded'); + wrapper.classList.remove('expanded'); + button.classList.remove('expanded'); + button.innerHTML = '▶'; // Right arrow + } else { + if (!panel.dataset.populated) { + populateBytecodePanel(panel, button); + } + panel.classList.add('expanded'); + wrapper.classList.add('expanded'); + button.classList.add('expanded'); + button.innerHTML = '▼'; // Down arrow + } +} + +/** + * Populate bytecode panel with instruction data + * @param {HTMLElement} panel - The panel element to populate + * @param {HTMLElement} button - The button containing the bytecode data + */ +function populateBytecodePanel(panel, button) { + const bytecodeJson = button.getAttribute('data-bytecode'); + if (!bytecodeJson) return; + + // Get line number from parent + const lineDiv = button.closest('.code-line'); + const lineNum = lineDiv ? lineDiv.id.replace('line-', '') : null; + + try { + const instructions = JSON.parse(bytecodeJson); + if (!instructions.length) { + panel.innerHTML = '
    No bytecode data
    '; + panel.dataset.populated = 'true'; + return; + } + + const maxSamples = Math.max(...instructions.map(i => i.samples), 1); + + // Calculate specialization stats + const totalSamples = instructions.reduce((sum, i) => sum + i.samples, 0); + const specializedSamples = instructions + .filter(i => i.is_specialized) + .reduce((sum, i) => sum + i.samples, 0); + const specPct = totalSamples > 0 ? Math.round(100 * specializedSamples / totalSamples) : 0; + const specializedCount = instructions.filter(i => i.is_specialized).length; + + // Determine specialization level class + let specClass = 'low'; + if (specPct >= 67) specClass = 'high'; + else if (specPct >= 33) specClass = 'medium'; + + // Build specialization summary + let html = `
    + ${specPct}% + specialized + (${specializedCount}/${instructions.length} instructions, ${specializedSamples.toLocaleString()}/${totalSamples.toLocaleString()} samples) +
    `; + + html += '
    ' + + 'Instruction' + + 'Samples' + + 'Heat
    '; + + for (const instr of instructions) { + const heatPct = (instr.samples / maxSamples) * 100; + const isHot = heatPct > 50; + const specializedClass = instr.is_specialized ? ' specialized' : ''; + const baseOpHtml = instr.is_specialized + ? `(${escapeHtml(instr.base_opname)})` : ''; + const badge = instr.is_specialized + ? 'SPECIALIZED' : ''; + + // Build location data attributes for cross-referencing with source spans + const hasLocations = instr.locations && instr.locations.length > 0; + const locationData = hasLocations + ? `data-locations='${JSON.stringify(instr.locations)}' data-line="${lineNum}" data-opcode="${instr.opcode}"` + : ''; + + html += `
    + ${escapeHtml(instr.opname)}${baseOpHtml}${badge} + ${instr.samples.toLocaleString()} +
    +
    `; + } + + panel.innerHTML = html; + panel.dataset.populated = 'true'; + + // Add hover handlers for bytecode instructions to highlight source spans + panel.querySelectorAll('.bytecode-instruction[data-locations]').forEach(instrEl => { + instrEl.addEventListener('mouseenter', highlightSourceFromBytecode); + instrEl.addEventListener('mouseleave', unhighlightSourceFromBytecode); + }); + } catch (e) { + panel.innerHTML = '
    Error loading bytecode
    '; + console.error('Error parsing bytecode data:', e); + } +} + +/** + * Highlight source spans when hovering over bytecode instruction + */ +function highlightSourceFromBytecode(e) { + const instrEl = e.currentTarget; + const lineNum = instrEl.dataset.line; + const locationsStr = instrEl.dataset.locations; + + if (!lineNum) return; + + const lineDiv = document.getElementById(`line-${lineNum}`); + if (!lineDiv) return; + + // Parse locations and highlight matching spans by column range + try { + const locations = JSON.parse(locationsStr || '[]'); + const spans = lineDiv.querySelectorAll('.instr-span'); + spans.forEach(span => { + const spanStart = parseInt(span.dataset.colStart); + const spanEnd = parseInt(span.dataset.colEnd); + for (const loc of locations) { + // Match if span's range matches instruction's location + if (spanStart === loc.col_offset && spanEnd === loc.end_col_offset) { + span.classList.add('highlight-from-bytecode'); + break; + } + } + }); + } catch (err) { + console.error('Error parsing locations:', err); + } + + // Also highlight the instruction row itself + instrEl.classList.add('highlight'); +} + +/** + * Remove highlighting from source spans + */ +function unhighlightSourceFromBytecode(e) { + const instrEl = e.currentTarget; + const lineNum = instrEl.dataset.line; + + if (!lineNum) return; + + const lineDiv = document.getElementById(`line-${lineNum}`); + if (!lineDiv) return; + + const spans = lineDiv.querySelectorAll('.instr-span.highlight-from-bytecode'); + spans.forEach(span => { + span.classList.remove('highlight-from-bytecode'); + }); + + instrEl.classList.remove('highlight'); +} + +/** + * Escape HTML special characters + * @param {string} text - Text to escape + * @returns {string} Escaped HTML + */ +function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; +} + +/** + * Toggle all bytecode panels at once + */ +function toggleAllBytecode() { + const buttons = document.querySelectorAll('.bytecode-toggle'); + if (buttons.length === 0) return; + + const someExpanded = Array.from(buttons).some(b => b.classList.contains('expanded')); + const expandAllBtn = document.getElementById('toggle-all-bytecode'); + + buttons.forEach(button => { + const isExpanded = button.classList.contains('expanded'); + if (someExpanded ? isExpanded : !isExpanded) { + toggleBytecode(button); + } + }); + + // Update the expand-all button state + if (expandAllBtn) { + expandAllBtn.classList.toggle('expanded', !someExpanded); + } +} + +// Keyboard shortcut: 'b' toggles all bytecode panels, Enter/Space activates toggle switches +document.addEventListener('keydown', function(e) { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { + return; + } + if (e.key === 'b' && !e.ctrlKey && !e.altKey && !e.metaKey) { + toggleAllBytecode(); + } + if ((e.key === 'Enter' || e.key === ' ') && e.target.classList.contains('toggle-switch')) { + e.preventDefault(); + e.target.click(); + } +}); + +// Handle hash changes +window.addEventListener('hashchange', () => setTimeout(scrollToTargetLine, 50)); + +// Rebuild scroll marker on resize +window.addEventListener('resize', buildScrollMarker); diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js b/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js new file mode 100644 index 00000000000..8eb6af0db53 --- /dev/null +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js @@ -0,0 +1,129 @@ +// Tachyon Profiler - Heatmap Index JavaScript +// Index page specific functionality + +// ============================================================================ +// Heatmap Bar Coloring +// ============================================================================ + +function applyHeatmapBarColors() { + const bars = document.querySelectorAll('.heatmap-bar[data-intensity]'); + bars.forEach(bar => { + const intensity = parseFloat(bar.getAttribute('data-intensity')) || 0; + const color = intensityToColor(intensity); + bar.style.backgroundColor = color; + }); +} + +// ============================================================================ +// Theme Support +// ============================================================================ + +function toggleTheme() { + const html = document.documentElement; + const current = html.getAttribute('data-theme') || 'light'; + const next = current === 'light' ? 'dark' : 'light'; + html.setAttribute('data-theme', next); + localStorage.setItem('heatmap-theme', next); + + // Update theme button icon + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = next === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = next === 'dark' ? '' : 'none'; + } + + applyHeatmapBarColors(); +} + +function restoreUIState() { + // Restore theme + const savedTheme = localStorage.getItem('heatmap-theme'); + if (savedTheme) { + document.documentElement.setAttribute('data-theme', savedTheme); + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = savedTheme === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = savedTheme === 'dark' ? '' : 'none'; + } + } +} + +// ============================================================================ +// Type Section Toggle (stdlib, project, etc) +// ============================================================================ + +function toggleTypeSection(header) { + const section = header.parentElement; + const content = section.querySelector('.type-content'); + const icon = header.querySelector('.type-icon'); + + if (content.style.display === 'none') { + content.style.display = 'block'; + icon.textContent = '\u25BC'; + } else { + content.style.display = 'none'; + icon.textContent = '\u25B6'; + } +} + +// ============================================================================ +// Folder Toggle +// ============================================================================ + +function toggleFolder(header) { + const folder = header.parentElement; + const content = folder.querySelector('.folder-content'); + const icon = header.querySelector('.folder-icon'); + + if (content.style.display === 'none') { + content.style.display = 'block'; + icon.textContent = '\u25BC'; + folder.classList.remove('collapsed'); + } else { + content.style.display = 'none'; + icon.textContent = '\u25B6'; + folder.classList.add('collapsed'); + } +} + +// ============================================================================ +// Expand/Collapse All +// ============================================================================ + +function expandAll() { + // Expand all type sections + document.querySelectorAll('.type-section').forEach(section => { + const content = section.querySelector('.type-content'); + const icon = section.querySelector('.type-icon'); + content.style.display = 'block'; + icon.textContent = '\u25BC'; + }); + + // Expand all folders + document.querySelectorAll('.folder-node').forEach(folder => { + const content = folder.querySelector('.folder-content'); + const icon = folder.querySelector('.folder-icon'); + content.style.display = 'block'; + icon.textContent = '\u25BC'; + folder.classList.remove('collapsed'); + }); +} + +function collapseAll() { + document.querySelectorAll('.folder-node').forEach(folder => { + const content = folder.querySelector('.folder-content'); + const icon = folder.querySelector('.folder-icon'); + content.style.display = 'none'; + icon.textContent = '\u25B6'; + folder.classList.add('collapsed'); + }); +} + +// ============================================================================ +// Initialization +// ============================================================================ + +document.addEventListener('DOMContentLoaded', function() { + restoreUIState(); + applyHeatmapBarColors(); +}); diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html b/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html new file mode 100644 index 00000000000..3620f8efb80 --- /dev/null +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html @@ -0,0 +1,136 @@ + + + + + + Tachyon Profiler - Heatmap Report + + + +
    + +
    +
    + + Tachyon + + Heatmap Report +
    +
    + + + + + + +
    +
    + + +
    + +
    +
    +
    📄
    +
    + + Files Profiled +
    +
    +
    +
    +
    📊
    +
    + + Total Snapshots +
    +
    +
    +
    +
    +
    + + Duration +
    +
    +
    +
    +
    +
    + + Samples/sec +
    +
    +
    +
    +
    +
    +
    + Error Rate +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    💥
    + Missed Samples +
    + +
    +
    +
    +
    +
    +
    + + +
    +

    Profiled Files

    +
    + +
    + + +
    + +
    + +
    +
    + + +
    + + Tachyon Profiler + + + Python Sampling Profiler + +
    +
    + + + + diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html b/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html new file mode 100644 index 00000000000..91b629b2628 --- /dev/null +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html @@ -0,0 +1,131 @@ + + + + + + <!-- FILENAME --> - Heatmap + + + +
    + +
    +
    + + Tachyon + + +
    +
    + + + + + + + + + + + +
    +
    + + +
    +
    +
    +
    +
    Self Samples
    +
    +
    +
    +
    Cumulative
    +
    +
    +
    +
    Lines Hit
    +
    +
    +
    %
    +
    % of Total
    +
    +
    +
    +
    Max Self
    +
    +
    +
    +
    Max Total
    +
    +
    +
    + + +
    +
    + Intensity: +
    +
    + Cold + + Hot +
    + +
    +
    + Self Time +
    + Total Time +
    +
    + Show All +
    + Hot Only +
    +
    + Heat +
    + Specialization +
    + + +
    +
    +
    + + +
    +
    +
    Line
    +
    Self
    +
    Total
    +
    Code
    +
    + +
    +
    + + + + diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js b/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js new file mode 100644 index 00000000000..7fcd720d45d --- /dev/null +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js @@ -0,0 +1,55 @@ +// Tachyon Profiler - Shared Heatmap JavaScript +// Common utilities shared between index and file views + +// ============================================================================ +// Heat Level Mapping (Single source of truth for intensity thresholds) +// ============================================================================ + +// Maps intensity (0-1) to heat level (0-8). Level 0 = no heat, 1-8 = heat levels. +function intensityToHeatLevel(intensity) { + if (intensity <= 0) return 0; + if (intensity <= 0.125) return 1; + if (intensity <= 0.25) return 2; + if (intensity <= 0.375) return 3; + if (intensity <= 0.5) return 4; + if (intensity <= 0.625) return 5; + if (intensity <= 0.75) return 6; + if (intensity <= 0.875) return 7; + return 8; +} + +// Class names corresponding to heat levels 1-8 (used by scroll marker) +const HEAT_CLASS_NAMES = ['cold', 'cool', 'mild', 'warm', 'hot', 'very-hot', 'intense', 'extreme']; + +function intensityToClass(intensity) { + const level = intensityToHeatLevel(intensity); + return level === 0 ? null : HEAT_CLASS_NAMES[level - 1]; +} + +// ============================================================================ +// Color Mapping (Intensity to Heat Color) +// ============================================================================ + +function intensityToColor(intensity) { + const level = intensityToHeatLevel(intensity); + if (level === 0) { + return 'transparent'; + } + const rootStyle = getComputedStyle(document.documentElement); + return rootStyle.getPropertyValue(`--heat-${level}`).trim(); +} + +// ============================================================================ +// Favicon (Reuse logo image as favicon) +// ============================================================================ + +(function() { + const logo = document.querySelector('.brand-logo img'); + if (logo) { + const favicon = document.createElement('link'); + favicon.rel = 'icon'; + favicon.type = 'image/png'; + favicon.href = logo.src; + document.head.appendChild(favicon); + } +})(); diff --git a/Lib/profiling/sampling/_shared_assets/base.css b/Lib/profiling/sampling/_shared_assets/base.css new file mode 100644 index 00000000000..cb59a0f77c5 --- /dev/null +++ b/Lib/profiling/sampling/_shared_assets/base.css @@ -0,0 +1,498 @@ +/* ========================================================================== + Python Profiler - Shared CSS Foundation + Design system shared between Flamegraph and Heatmap viewers + ========================================================================== */ + +/* -------------------------------------------------------------------------- + CSS Variables & Theme System + -------------------------------------------------------------------------- */ + +:root { + /* Typography */ + --font-sans: "Source Sans Pro", "Lucida Grande", "Lucida Sans Unicode", + "Geneva", "Verdana", sans-serif; + --font-mono: 'SF Mono', 'Monaco', 'Consolas', 'Liberation Mono', monospace; + + /* Python brand colors (theme-independent) */ + --python-blue: #3776ab; + --python-blue-light: #4584bb; + --python-blue-lighter: #5592cc; + --python-gold: #ffd43b; + --python-gold-dark: #ffcd02; + --python-gold-light: #ffdc5c; + + /* Heat palette - defined per theme below */ + + /* Layout */ + --sidebar-width: 280px; + --sidebar-collapsed: 44px; + --topbar-height: 56px; + --statusbar-height: 32px; + + /* Border radius */ + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + + /* Transitions */ + --transition-fast: 0.15s ease; + --transition-normal: 0.25s ease; + --transition-slow: 0.3s ease; +} + +/* Light theme (default) */ +:root, [data-theme="light"] { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-tertiary: #e9ecef; + --border: #e9ecef; + --border-subtle: #f0f2f5; + + --text-primary: #2e3338; + --text-secondary: #5a6c7d; + --text-muted: #6f767e; + + --accent: #3776ab; + --accent-hover: #2d5aa0; + --accent-glow: rgba(55, 118, 171, 0.15); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15); + + --header-gradient: linear-gradient(135deg, #3776ab 0%, #4584bb 100%); + + /* Light mode heat palette - blue to yellow to orange to red (cold to hot) */ + --heat-1: #7ba3d1; + --heat-2: #a8d0ef; + --heat-3: #d6e9f8; + --heat-4: #ffe6a8; + --heat-5: #ffd43b; + --heat-6: #ffb84d; + --heat-7: #ff9966; + --heat-8: #ff6347; + + /* Code view specific */ + --code-bg: #ffffff; + --code-bg-line: #f8f9fa; + --code-border: #e9ecef; + --code-text: #2e3338; + --code-text-muted: #8b949e; + --code-accent: #3776ab; + + /* Navigation colors */ + --nav-caller: #2563eb; + --nav-caller-hover: #1d4ed8; + --nav-callee: #dc2626; + --nav-callee-hover: #b91c1c; + + /* Specialization status colors */ + --spec-high: #4caf50; + --spec-high-text: #2e7d32; + --spec-high-bg: rgba(76, 175, 80, 0.15); + --spec-medium: #ff9800; + --spec-medium-text: #e65100; + --spec-medium-bg: rgba(255, 152, 0, 0.15); + --spec-low: #9e9e9e; + --spec-low-text: #616161; + --spec-low-bg: rgba(158, 158, 158, 0.15); + + /* Heatmap span highlighting colors */ + --span-hot-base: 255, 100, 50; + --span-cold-base: 150, 150, 150; +} + +/* Dark theme */ +[data-theme="dark"] { + --bg-primary: #0d1117; + --bg-secondary: #161b22; + --bg-tertiary: #21262d; + --border: #30363d; + --border-subtle: #21262d; + + --text-primary: #e6edf3; + --text-secondary: #8b949e; + --text-muted: #757e8a; + + --accent: #58a6ff; + --accent-hover: #79b8ff; + --accent-glow: rgba(88, 166, 255, 0.15); + + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5); + + --header-gradient: linear-gradient(135deg, #21262d 0%, #30363d 100%); + + /* Dark mode heat palette - cool to warm gradient for visualization */ + --heat-1: rgba(90, 123, 167, 1); + --heat-2: rgba(106, 148, 168, 1); + --heat-3: rgba(122, 172, 172, 1); + --heat-4: rgba(142, 196, 152, 1); + --heat-5: rgba(168, 216, 136, 1); + --heat-6: rgba(200, 222, 122, 1); + --heat-7: rgba(244, 212, 93, 1); + --heat-8: rgba(255, 122, 69, 1); + + /* Code view specific - dark mode */ + --code-bg: #0d1117; + --code-bg-line: #161b22; + --code-border: #30363d; + --code-text: #e6edf3; + --code-text-muted: #6e7681; + --code-accent: #58a6ff; + + /* Navigation colors - dark theme friendly */ + --nav-caller: #58a6ff; + --nav-caller-hover: #4184e4; + --nav-callee: #f87171; + --nav-callee-hover: #e53e3e; + + /* Specialization status colors - dark theme */ + --spec-high: #81c784; + --spec-high-text: #81c784; + --spec-high-bg: rgba(129, 199, 132, 0.2); + --spec-medium: #ffb74d; + --spec-medium-text: #ffb74d; + --spec-medium-bg: rgba(255, 183, 77, 0.2); + --spec-low: #bdbdbd; + --spec-low-text: #9e9e9e; + --spec-low-bg: rgba(189, 189, 189, 0.15); + + /* Heatmap span highlighting colors - dark theme */ + --span-hot-base: 255, 107, 53; + --span-cold-base: 189, 189, 189; +} + +/* -------------------------------------------------------------------------- + Base Styles + -------------------------------------------------------------------------- */ + +*, *::before, *::after { + box-sizing: border-box; +} + +html, body { + margin: 0; + padding: 0; +} + +body { + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.6; + color: var(--text-primary); + background: var(--bg-primary); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + transition: background var(--transition-normal), color var(--transition-normal); +} + +/* -------------------------------------------------------------------------- + Layout Structure + -------------------------------------------------------------------------- */ + +.app-layout { + display: flex; + flex-direction: column; +} + +/* -------------------------------------------------------------------------- + Top Bar + -------------------------------------------------------------------------- */ + +.top-bar { + height: var(--topbar-height); + background: var(--header-gradient); + display: flex; + align-items: center; + padding: 0 16px; + gap: 16px; + flex-shrink: 0; + box-shadow: 0 2px 10px rgba(55, 118, 171, 0.25); + border-bottom: 2px solid var(--python-gold); +} + +/* Brand / Logo */ +.brand { + display: flex; + align-items: center; + gap: 12px; + color: white; + text-decoration: none; + flex-shrink: 0; +} + +.brand-logo { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 40px; + flex-shrink: 0; +} + +/* Style the inlined SVG/img inside brand-logo */ +.brand-logo svg, +.brand-logo img { + width: 48px; + height: 40px; + display: block; + object-fit: contain; + filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2)); +} + +.brand-info { + display: flex; + flex-direction: column; + line-height: 1.15; +} + +.brand-text { + font-family: var(--font-sans); + font-weight: 700; + font-size: 16px; + letter-spacing: -0.3px; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); + color: inherit; + text-decoration: none; +} + +.brand-subtitle { + font-weight: 500; + font-size: 10px; + opacity: 0.9; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.brand-divider { + width: 1px; + height: 16px; + background: rgba(255, 255, 255, 0.3); +} + +/* Toolbar */ +.toolbar { + display: flex; + align-items: center; + gap: 6px; + margin-left: auto; +} + +.toolbar-btn { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + font-size: 15px; + color: white; + background: rgba(255, 255, 255, 0.12); + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 6px; + cursor: pointer; + text-decoration: none; + transition: all var(--transition-fast); +} + +.toolbar-btn:hover { + background: rgba(255, 255, 255, 0.22); + border-color: rgba(255, 255, 255, 0.35); +} + +.toolbar-btn:active { + transform: scale(0.95); +} + +/* -------------------------------------------------------------------------- + Status Bar + -------------------------------------------------------------------------- */ + +.status-bar { + height: var(--statusbar-height); + background: var(--bg-secondary); + border-top: 1px solid var(--border); + display: flex; + align-items: center; + padding: 0 16px; + gap: 16px; + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-secondary); + flex-shrink: 0; +} + +.status-item { + display: flex; + align-items: center; + gap: 5px; +} + +.status-item::before { + content: ''; + width: 4px; + height: 4px; + background: var(--python-gold); + border-radius: 50%; +} + +.status-item:first-child::before { + display: none; +} + +.status-label { + color: var(--text-muted); +} + +.status-value { + color: var(--text-primary); + font-weight: 500; +} + +.status-value.accent { + color: var(--accent); + font-weight: 600; +} + +/* -------------------------------------------------------------------------- + Animations + -------------------------------------------------------------------------- */ + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(12px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes shimmer { + 0% { left: -100%; } + 100% { left: 100%; } +} + +/* -------------------------------------------------------------------------- + Focus States (Accessibility) + -------------------------------------------------------------------------- */ + +button:focus-visible, +select:focus-visible, +input:focus-visible, +.toggle-switch:focus-visible, +a.toolbar-btn:focus-visible { + outline: 2px solid var(--python-gold); + outline-offset: 2px; +} + +/* -------------------------------------------------------------------------- + Shared Responsive + -------------------------------------------------------------------------- */ + +@media (max-width: 900px) { + .brand-subtitle { + display: none; + } +} + +@media (max-width: 600px) { + .toolbar-btn:not(.theme-toggle) { + display: none; + } +} + +/* -------------------------------------------------------------------------- + Toggle Switch + -------------------------------------------------------------------------- */ + +.toggle-switch { + display: inline-flex; + align-items: center; + gap: 8px; + cursor: pointer; + user-select: none; + font-family: var(--font-sans); + transition: opacity var(--transition-fast); + flex-shrink: 0; +} + +.toggle-switch:hover { + opacity: 0.85; +} + +.toggle-switch .toggle-label { + font-size: 11px; + font-weight: 500; + color: var(--text-muted); + transition: color var(--transition-fast); + white-space: nowrap; + display: inline-flex; + flex-direction: column; +} + +.toggle-switch .toggle-label.active { + color: var(--text-primary); + font-weight: 600; +} + +/* Reserve space for bold text to prevent layout shift on toggle */ +.toggle-switch .toggle-label::after { + content: attr(data-text); + font-weight: 600; + height: 0; + visibility: hidden; +} + +.toggle-switch.disabled { + opacity: 0.4; + pointer-events: none; + cursor: not-allowed; +} + +.toggle-track { + position: relative; + width: 36px; + height: 20px; + background: var(--bg-tertiary); + border: 2px solid var(--border); + border-radius: 12px; + transition: all var(--transition-fast); + box-shadow: inset var(--shadow-sm); +} + +.toggle-track:hover { + border-color: var(--text-muted); +} + +.toggle-track.on { + background: var(--accent); + border-color: var(--accent); + box-shadow: 0 0 8px var(--accent-glow); +} + +.toggle-track::after { + content: ''; + position: absolute; + top: 1px; + left: 1px; + width: 14px; + height: 14px; + background: white; + border-radius: 50%; + box-shadow: var(--shadow-sm); + transition: all var(--transition-fast); +} + +.toggle-track.on::after { + transform: translateX(16px); + box-shadow: var(--shadow-md); +} diff --git a/Lib/profiling/sampling/_sync_coordinator.py b/Lib/profiling/sampling/_sync_coordinator.py index 79e8858ca17..1a4af42588a 100644 --- a/Lib/profiling/sampling/_sync_coordinator.py +++ b/Lib/profiling/sampling/_sync_coordinator.py @@ -5,11 +5,13 @@ This module is used internally by the sample profiler to coordinate the startup of target processes. It should not be called directly by users. """ +import importlib.util import os import sys import socket import runpy import time +import types from typing import List, NoReturn @@ -137,7 +139,7 @@ def _execute_module(module_name: str, module_args: List[str]) -> None: """ # Replace sys.argv to match how Python normally runs modules # When running 'python -m module args', sys.argv is ["__main__.py", "args"] - sys.argv = [f"__main__.py"] + module_args + sys.argv = ["__main__.py"] + module_args try: runpy.run_module(module_name, run_name="__main__", alter_sys=True) @@ -176,13 +178,20 @@ def _execute_script(script_path: str, script_args: List[str], cwd: str) -> None: with open(script_path, 'rb') as f: source_code = f.read() - # Compile and execute the script - code = compile(source_code, script_path, 'exec') - exec(code, {'__name__': '__main__', '__file__': script_path}) except FileNotFoundError as e: raise TargetError(f"Script file not found: {script_path}") from e except PermissionError as e: raise TargetError(f"Permission denied reading script: {script_path}") from e + + try: + main_module = types.ModuleType("__main__") + main_module.__file__ = script_path + main_module.__builtins__ = __builtins__ + # gh-140729: Create a __mp_main__ module to allow pickling + sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module + + code = compile(source_code, script_path, 'exec', module='__main__') + exec(code, main_module.__dict__) except SyntaxError as e: raise TargetError(f"Syntax error in script {script_path}: {e}") from e except SystemExit: @@ -207,22 +216,31 @@ def main() -> NoReturn: # Set up execution environment _setup_environment(cwd) + # Determine execution type and validate target exists + is_module = target_args[0] == "-m" + if is_module: + if len(target_args) < 2: + raise ArgumentError("Module name required after -m") + module_name = target_args[1] + module_args = target_args[2:] + + if importlib.util.find_spec(module_name) is None: + raise TargetError(f"Module not found: {module_name}") + else: + script_path = target_args[0] + script_args = target_args[1:] + # Match the path resolution logic in _execute_script + check_path = script_path if os.path.isabs(script_path) else os.path.join(cwd, script_path) + if not os.path.isfile(check_path): + raise TargetError(f"Script not found: {script_path}") + # Signal readiness to profiler _signal_readiness(sync_port) # Execute the target - if target_args[0] == "-m": - # Module execution - if len(target_args) < 2: - raise ArgumentError("Module name required after -m") - - module_name = target_args[1] - module_args = target_args[2:] + if is_module: _execute_module(module_name, module_args) else: - # Script execution - script_path = target_args[0] - script_args = target_args[1:] _execute_script(script_path, script_args, cwd) except CoordinatorError as e: diff --git a/Lib/profiling/sampling/_vendor/d3-flame-graph/4.1.3/d3-flamegraph-tooltip.min.js b/Lib/profiling/sampling/_vendor/d3-flame-graph/4.1.3/d3-flamegraph-tooltip.min.js new file mode 100644 index 00000000000..7468437093b --- /dev/null +++ b/Lib/profiling/sampling/_vendor/d3-flame-graph/4.1.3/d3-flamegraph-tooltip.min.js @@ -0,0 +1 @@ +!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.flamegraph=n():(t.flamegraph=t.flamegraph||{},t.flamegraph.tooltip=n())}(self,(function(){return(()=>{"use strict";var t={d:(n,e)=>{for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},o:(t,n)=>Object.prototype.hasOwnProperty.call(t,n),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},n={};function e(){}function r(t){return null==t?e:function(){return this.querySelector(t)}}function i(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function o(){return[]}function u(t){return null==t?o:function(){return this.querySelectorAll(t)}}function a(t){return function(){return this.matches(t)}}function s(t){return function(n){return n.matches(t)}}t.r(n),t.d(n,{defaultFlamegraphTooltip:()=>Ae});var l=Array.prototype.find;function c(){return this.firstElementChild}var f=Array.prototype.filter;function h(){return Array.from(this.children)}function p(t){return new Array(t.length)}function d(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function y(t){return function(){return t}}function v(t,n,e,r,i,o){for(var u,a=0,s=n.length,l=o.length;an?1:t>=n?0:NaN}d.prototype={constructor:d,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var b="http://www.w3.org/1999/xhtml";const x={svg:"http://www.w3.org/2000/svg",xhtml:b,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function A(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),x.hasOwnProperty(n)?{space:x[n],local:t}:t}function N(t){return function(){this.removeAttribute(t)}}function k(t){return function(){this.removeAttributeNS(t.space,t.local)}}function M(t,n){return function(){this.setAttribute(t,n)}}function E(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function S(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function C(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function P(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function O(t){return function(){this.style.removeProperty(t)}}function q(t,n,e){return function(){this.style.setProperty(t,n,e)}}function j(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function T(t,n){return t.style.getPropertyValue(n)||P(t).getComputedStyle(t,null).getPropertyValue(n)}function X(t){return function(){delete this[t]}}function R(t,n){return function(){this[t]=n}}function I(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function L(t){return t.trim().split(/^|\s+/)}function D(t){return t.classList||new H(t)}function H(t){this._node=t,this._names=L(t.getAttribute("class")||"")}function Y(t,n){for(var e=D(t),r=-1,i=n.length;++r=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}function st(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var pt=[null];function dt(t,n){this._groups=t,this._parents=n}function yt(){return new dt([[document.documentElement]],pt)}dt.prototype=yt.prototype={constructor:dt,select:function(t){"function"!=typeof t&&(t=r(t));for(var n=this._groups,e=n.length,i=new Array(e),o=0;o=M&&(M=k+1);!(N=b[M])&&++M=0;)(r=i[o])&&(u&&4^r.compareDocumentPosition(u)&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=w);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?O:"function"==typeof n?j:q)(t,n,null==e?"":e)):T(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?X:"function"==typeof n?I:R)(t,n)):this.node()[t]},classed:function(t,n){var e=L(t+"");if(arguments.length<2){for(var r=D(this.node()),i=-1,o=e.length;++i{}};function _t(){for(var t,n=0,e=arguments.length,r={};n=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}}))}function bt(t,n){for(var e,r=0,i=t.length;r0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(void 0,t),n=n._next;--Mt}()}finally{Mt=0,function(){var t,n,e=Nt,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Nt=n);kt=t,Ht(r)}(),Pt=0}}function Dt(){var t=qt.now(),n=t-Ct;n>1e3&&(Ot-=n,Ct=t)}function Ht(t){Mt||(Et&&(Et=clearTimeout(Et)),t-Pt>24?(t<1/0&&(Et=setTimeout(Lt,t-qt.now()-Ot)),St&&(St=clearInterval(St))):(St||(Ct=qt.now(),St=setInterval(Dt,1e3)),Mt=1,jt(Lt)))}function Yt(t,n,e){var r=new Rt;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Rt.prototype=It.prototype={constructor:Rt,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Tt():+e)+(null==n?0:+n),this._next||kt===this||(kt?kt._next=this:Nt=this,kt=this),this._call=t,this._time=e,Ht()},stop:function(){this._call&&(this._call=null,this._time=1/0,Ht())}};var Bt=At("start","end","cancel","interrupt"),$t=[];function Vt(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=1,e.timer.restart(u,e.delay,e.time),e.delay<=t&&u(t-e.delay)}function u(o){var l,c,f,h;if(1!==e.state)return s();for(l in i)if((h=i[l]).name===e.name){if(3===h.state)return Yt(u);4===h.state?(h.state=6,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+l0)throw new Error("too late; already scheduled");return e}function Ut(t,n){var e=Ft(t,n);if(e.state>3)throw new Error("too late; already running");return e}function Ft(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Kt(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}var Wt,Gt=180/Math.PI,Jt={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Qt(t,n,e,r,i,o){var u,a,s;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(s=t*e+n*r)&&(e-=t*s,r-=n*s),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,s/=a),t*r180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Kt(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,s),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Kt(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,s),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:Kt(t,e)},{i:a-2,x:Kt(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,s),o=u=null,function(t){for(var n,e=-1,r=s.length;++e>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?Mn(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?Mn(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=yn.exec(t))?new Cn(n[1],n[2],n[3],1):(n=vn.exec(t))?new Cn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=gn.exec(t))?Mn(n[1],n[2],n[3],n[4]):(n=_n.exec(t))?Mn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=mn.exec(t))?jn(n[1],n[2]/100,n[3]/100,1):(n=wn.exec(t))?jn(n[1],n[2]/100,n[3]/100,n[4]):bn.hasOwnProperty(t)?kn(bn[t]):"transparent"===t?new Cn(NaN,NaN,NaN,0):null}function kn(t){return new Cn(t>>16&255,t>>8&255,255&t,1)}function Mn(t,n,e,r){return r<=0&&(t=n=e=NaN),new Cn(t,n,e,r)}function En(t){return t instanceof sn||(t=Nn(t)),t?new Cn((t=t.rgb()).r,t.g,t.b,t.opacity):new Cn}function Sn(t,n,e,r){return 1===arguments.length?En(t):new Cn(t,n,e,null==r?1:r)}function Cn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Pn(){return"#"+qn(this.r)+qn(this.g)+qn(this.b)}function On(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function qn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function jn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Xn(t,n,e,r)}function Tn(t){if(t instanceof Xn)return new Xn(t.h,t.s,t.l,t.opacity);if(t instanceof sn||(t=Nn(t)),!t)return new Xn;if(t instanceof Xn)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,s=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&s<1?0:u,new Xn(u,a,s,t.opacity)}function Xn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Rn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function In(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}un(sn,Nn,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:xn,formatHex:xn,formatHsl:function(){return Tn(this).formatHsl()},formatRgb:An,toString:An}),un(Cn,Sn,an(sn,{brighter:function(t){return t=null==t?cn:Math.pow(cn,t),new Cn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?ln:Math.pow(ln,t),new Cn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Pn,formatHex:Pn,formatRgb:On,toString:On})),un(Xn,(function(t,n,e,r){return 1===arguments.length?Tn(t):new Xn(t,n,e,null==r?1:r)}),an(sn,{brighter:function(t){return t=null==t?cn:Math.pow(cn,t),new Xn(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?ln:Math.pow(ln,t),new Xn(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Cn(Rn(t>=240?t-240:t+120,i,r),Rn(t,i,r),Rn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const Ln=t=>()=>t;function Dn(t,n){return function(e){return t+e*n}}function Hn(t){return 1==(t=+t)?Yn:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):Ln(isNaN(n)?e:n)}}function Yn(t,n){var e=n-t;return e?Dn(t,e):Ln(isNaN(t)?n:t)}const Bn=function t(n){var e=Hn(n);function r(t,n){var r=e((t=Sn(t)).r,(n=Sn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=Yn(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function $n(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,s.push({i:u,x:Kt(e,r)})),o=zn.lastIndex;return o=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?zt:Ut;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}var ce=vt.prototype.constructor;function fe(t){return function(){this.style.removeProperty(t)}}function he(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}function pe(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&he(t,o,e)),r}return o._value=n,o}function de(t){return function(n){this.textContent=t.call(this,n)}}function ye(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&de(r)),n}return r._value=t,r}var ve=0;function ge(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function _e(){return++ve}var me=vt.prototype;ge.prototype=function(t){return vt().transition(t)}.prototype={constructor:ge,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=r(t));for(var i=this._groups,o=i.length,u=new Array(o),a=0;a2&&e.state<5,e.state=6,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}}(this,t)}))},vt.prototype.transition=function(t){var n,e;t instanceof ge?(n=t._id,t=t._name):(n=_e(),(e=we).time=Tt(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o{"use strict";var t={d:(n,e)=>{for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},o:(t,n)=>Object.prototype.hasOwnProperty.call(t,n)},n={};function e(){}function r(t){return null==t?e:function(){return this.querySelector(t)}}function i(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function o(){return[]}function u(t){return null==t?o:function(){return this.querySelectorAll(t)}}function a(t){return function(){return this.matches(t)}}function l(t){return function(n){return n.matches(t)}}t.d(n,{default:()=>xr});var s=Array.prototype.find;function c(){return this.firstElementChild}var h=Array.prototype.filter;function f(){return Array.from(this.children)}function p(t){return new Array(t.length)}function d(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function g(t){return function(){return t}}function v(t,n,e,r,i,o){for(var u,a=0,l=n.length,s=o.length;an?1:t>=n?0:NaN}d.prototype={constructor:d,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var b="http://www.w3.org/1999/xhtml";const x={svg:"http://www.w3.org/2000/svg",xhtml:b,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function M(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),x.hasOwnProperty(n)?{space:x[n],local:t}:t}function A(t){return function(){this.removeAttribute(t)}}function N(t){return function(){this.removeAttributeNS(t.space,t.local)}}function k(t,n){return function(){this.setAttribute(t,n)}}function E(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function S(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function C(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function j(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function q(t){return function(){this.style.removeProperty(t)}}function O(t,n,e){return function(){this.style.setProperty(t,n,e)}}function P(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function H(t,n){return t.style.getPropertyValue(n)||j(t).getComputedStyle(t,null).getPropertyValue(n)}function L(t){return function(){delete this[t]}}function T(t,n){return function(){this[t]=n}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function B(t){return t.trim().split(/^|\s+/)}function X(t){return t.classList||new z(t)}function z(t){this._node=t,this._names=B(t.getAttribute("class")||"")}function R(t,n){for(var e=X(t),r=-1,i=n.length;++r=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}function lt(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var pt=[null];function dt(t,n){this._groups=t,this._parents=n}function gt(){return new dt([[document.documentElement]],pt)}dt.prototype=gt.prototype={constructor:dt,select:function(t){"function"!=typeof t&&(t=r(t));for(var n=this._groups,e=n.length,i=new Array(e),o=0;o=k&&(k=N+1);!(A=b[k])&&++k=0;)(r=i[o])&&(u&&4^r.compareDocumentPosition(u)&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=_);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?q:"function"==typeof n?P:O)(t,n,null==e?"":e)):H(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?L:"function"==typeof n?D:T)(t,n)):this.node()[t]},classed:function(t,n){var e=B(t+"");if(arguments.length<2){for(var r=X(this.node()),i=-1,o=e.length;++i1?r[0]+r.slice(2):r,+t.slice(e+1)]}function wt(t){return(t=mt(Math.abs(t)))?t[1]:NaN}var _t,bt=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function xt(t){if(!(n=bt.exec(t)))throw new Error("invalid format: "+t);var n;return new Mt({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Mt(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function At(t,n){var e=mt(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}xt.prototype=Mt.prototype,Mt.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const Nt={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>At(100*t,n),r:At,s:function(t,n){var e=mt(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(_t=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+mt(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function kt(t){return t}var Et,St,Ct,jt=Array.prototype.map,qt=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Ot(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?kt:(n=jt.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],u=0,a=n[0],l=0;i>0&&a>0&&(l+a+1>r&&(a=Math.max(1,r-l)),o.push(t.substring(i-=a,i+a)),!((l+=a+1)>r));)a=n[u=(u+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",u=void 0===t.decimal?".":t.decimal+"",a=void 0===t.numerals?kt:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(jt.call(t.numerals,String)),l=void 0===t.percent?"%":t.percent+"",s=void 0===t.minus?"−":t.minus+"",c=void 0===t.nan?"NaN":t.nan+"";function h(t){var n=(t=xt(t)).fill,e=t.align,h=t.sign,f=t.symbol,p=t.zero,d=t.width,g=t.comma,v=t.precision,y=t.trim,m=t.type;"n"===m?(g=!0,m="g"):Nt[m]||(void 0===v&&(v=12),y=!0,m="g"),(p||"0"===n&&"="===e)&&(p=!0,n="0",e="=");var w="$"===f?i:"#"===f&&/[boxX]/.test(m)?"0"+m.toLowerCase():"",_="$"===f?o:/[%p]/.test(m)?l:"",b=Nt[m],x=/[defgprs%]/.test(m);function M(t){var i,o,l,f=w,M=_;if("c"===m)M=b(t)+M,t="";else{var A=(t=+t)<0||1/t<0;if(t=isNaN(t)?c:b(Math.abs(t),v),y&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),A&&0==+t&&"+"!==h&&(A=!1),f=(A?"("===h?h:s:"-"===h||"("===h?"":h)+f,M=("s"===m?qt[8+_t/3]:"")+M+(A&&"("===h?")":""),x)for(i=-1,o=t.length;++i(l=t.charCodeAt(i))||l>57){M=(46===l?u+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!p&&(t=r(t,1/0));var N=f.length+t.length+M.length,k=N>1)+f+t+M+k.slice(N);break;default:t=k+f+t+M}return a(t)}return v=void 0===v?6:/[gprs]/.test(m)?Math.max(1,Math.min(21,v)):Math.max(0,Math.min(20,v)),M.toString=function(){return t+""},M}return{format:h,formatPrefix:function(t,n){var e=h(((t=xt(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(wt(n)/3))),i=Math.pow(10,-r),o=qt[8+r/3];return function(t){return e(i*t)+o}}}}function Pt(t,n){return null==t||null==n?NaN:tn?1:t>=n?0:NaN}function Ht(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Lt(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&function(t,n,e,r,i){for(var o,u=t.children,a=-1,l=u.length,s=t.value&&(r-n)/t.value;++a=0;)n+=e[r].value;else n=1;t.value=n}function Dt(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Xt)):void 0===n&&(n=Bt);for(var e,r,i,o,u,a=new It(t),l=[a];e=l.pop();)if((i=n(e.data))&&(u=(i=Array.from(i)).length))for(e.children=i,o=u-1;o>=0;--o)l.push(r=i[o]=new It(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Rt)}function Bt(t){return t.children}function Xt(t){return Array.isArray(t)?t[1]:null}function zt(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Rt(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function It(t){this.data=t,this.depth=this.height=0,this.parent=null}Et=Ot({thousands:",",grouping:[3],currency:["$",""]}),St=Et.format,Ct=Et.formatPrefix,It.prototype=Dt.prototype={constructor:It,count:function(){return this.eachAfter(Tt)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,u=[o],a=[],l=-1;o=u.pop();)if(a.push(o),e=o.children)for(r=0,i=e.length;r=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Dt(this).eachBefore(zt)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e=0?(o>=$t?10:o>=Vt?5:o>=Yt?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=$t?10:o>=Vt?5:o>=Yt?2:1)}function Ut(t){let n=t,e=t,r=t;function i(t,n,i=0,o=t.length){if(i>>1;r(t[e],n)<0?i=e+1:o=e}while(it(n)-e,e=Pt,r=(n,e)=>Pt(t(n),e)),{left:i,center:function(t,e,r=0,o=t.length){const u=i(t,e,r,o-1);return u>r&&n(t[u-1],e)>-n(t[u],e)?u-1:u},right:function(t,n,i=0,o=t.length){if(i>>1;r(t[e],n)<=0?i=e+1:o=e}while(i>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?mn(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?mn(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=an.exec(t))?new bn(n[1],n[2],n[3],1):(n=ln.exec(t))?new bn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=sn.exec(t))?mn(n[1],n[2],n[3],n[4]):(n=cn.exec(t))?mn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=hn.exec(t))?Nn(n[1],n[2]/100,n[3]/100,1):(n=fn.exec(t))?Nn(n[1],n[2]/100,n[3]/100,n[4]):pn.hasOwnProperty(t)?yn(pn[t]):"transparent"===t?new bn(NaN,NaN,NaN,0):null}function yn(t){return new bn(t>>16&255,t>>8&255,255&t,1)}function mn(t,n,e,r){return r<=0&&(t=n=e=NaN),new bn(t,n,e,r)}function wn(t){return t instanceof Qt||(t=vn(t)),t?new bn((t=t.rgb()).r,t.g,t.b,t.opacity):new bn}function _n(t,n,e,r){return 1===arguments.length?wn(t):new bn(t,n,e,null==r?1:r)}function bn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function xn(){return"#"+An(this.r)+An(this.g)+An(this.b)}function Mn(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function An(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Nn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new En(t,n,e,r)}function kn(t){if(t instanceof En)return new En(t.h,t.s,t.l,t.opacity);if(t instanceof Qt||(t=vn(t)),!t)return new En;if(t instanceof En)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,l=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&l<1?0:u,new En(u,a,l,t.opacity)}function En(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Sn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function Cn(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}Wt(Qt,vn,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:dn,formatHex:dn,formatHsl:function(){return kn(this).formatHsl()},formatRgb:gn,toString:gn}),Wt(bn,_n,Jt(Qt,{brighter:function(t){return t=null==t?nn:Math.pow(nn,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?tn:Math.pow(tn,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:xn,formatHex:xn,formatRgb:Mn,toString:Mn})),Wt(En,(function(t,n,e,r){return 1===arguments.length?kn(t):new En(t,n,e,null==r?1:r)}),Jt(Qt,{brighter:function(t){return t=null==t?nn:Math.pow(nn,t),new En(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?tn:Math.pow(tn,t),new En(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new bn(Sn(t>=240?t-240:t+120,i,r),Sn(t,i,r),Sn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const jn=t=>()=>t;function qn(t,n){return function(e){return t+e*n}}function On(t){return 1==(t=+t)?Pn:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):jn(isNaN(n)?e:n)}}function Pn(t,n){var e=n-t;return e?qn(t,e):jn(isNaN(t)?n:t)}const Hn=function t(n){var e=On(n);function r(t,n){var r=e((t=_n(t)).r,(n=_n(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=Pn(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function Ln(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,l.push({i:u,x:Bn(e,r)})),o=Rn.lastIndex;return on&&(e=t,t=n,n=e),s=function(e){return Math.max(t,Math.min(n,e))}),r=l>2?Wn:Kn,i=o=null,h}function h(n){return null==n||isNaN(n=+n)?e:(i||(i=r(u.map(t),a,l)))(t(s(n)))}return h.invert=function(e){return s(n((o||(o=r(a,u.map(t),Bn)))(e)))},h.domain=function(t){return arguments.length?(u=Array.from(t,Fn),c()):u.slice()},h.range=function(t){return arguments.length?(a=Array.from(t),c()):a.slice()},h.rangeRound=function(t){return a=Array.from(t),l=Yn,c()},h.clamp=function(t){return arguments.length?(s=!!t||Zn,c()):s!==Zn},h.interpolate=function(t){return arguments.length?(l=t,c()):l},h.unknown=function(t){return arguments.length?(e=t,h):e},function(e,r){return t=e,n=r,c()}}function te(){return Qn()(Zn,Zn)}function ne(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function ee(t,n,e,r){var i,o=function(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=$t?i*=10:o>=Vt?i*=5:o>=Yt&&(i*=2),n0)return[t];if((r=n0){let e=Math.round(t/u),r=Math.round(n/u);for(e*un&&--r,o=new Array(i=r-e+1);++an&&--r,o=new Array(i=r-e+1);++a0;){if((i=Ft(l,s,e))===r)return o[u]=l,o[a]=s,n(o);if(i>0)l=Math.floor(l/i)*i,s=Math.ceil(s/i)*i;else{if(!(i<0))break;l=Math.ceil(l*i)/i,s=Math.floor(s*i)/i}r=i}return t},t}function ie(){var t=te();return t.copy=function(){return Jn(t,ie())},ne.apply(t,arguments),re(t)}function oe(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var ue={value:()=>{}};function ae(){for(var t,n=0,e=arguments.length,r={};n=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}}))}function ce(t,n){for(var e,r=0,i=t.length;r0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(void 0,t),n=n._next;--ge}()}finally{ge=0,function(){var t,n,e=pe,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pe=n);de=t,Ce(r)}(),we=0}}function Se(){var t=be.now(),n=t-me;n>1e3&&(_e-=n,me=t)}function Ce(t){ge||(ve&&(ve=clearTimeout(ve)),t-we>24?(t<1/0&&(ve=setTimeout(Ee,t-be.now()-_e)),ye&&(ye=clearInterval(ye))):(ye||(me=be.now(),ye=setInterval(Se,1e3)),ge=1,xe(Ee)))}function je(t,n,e){var r=new Ne;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ne.prototype=ke.prototype={constructor:Ne,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Me():+e)+(null==n?0:+n),this._next||de===this||(de?de._next=this:pe=this,de=this),this._call=t,this._time=e,Ce()},stop:function(){this._call&&(this._call=null,this._time=1/0,Ce())}};var qe=fe("start","end","cancel","interrupt"),Oe=[];function Pe(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=1,e.timer.restart(u,e.delay,e.time),e.delay<=t&&u(t-e.delay)}function u(o){var s,c,h,f;if(1!==e.state)return l();for(s in i)if((f=i[s]).name===e.name){if(3===f.state)return je(u);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[s]):+s0)throw new Error("too late; already scheduled");return e}function Le(t,n){var e=Te(t,n);if(e.state>3)throw new Error("too late; already running");return e}function Te(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var De,Be=180/Math.PI,Xe={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function ze(t,n,e,r,i,o){var u,a,l;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(l=t*e+n*r)&&(e-=t*l,r-=n*l),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,l/=a),t*r180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Bn(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,l),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Bn(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,l),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:Bn(t,e)},{i:a-2,x:Bn(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,l),o=u=null,function(t){for(var n,e=-1,r=l.length;++e=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?He:Le;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}var cr=vt.prototype.constructor;function hr(t){return function(){this.style.removeProperty(t)}}function fr(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}function pr(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&fr(t,o,e)),r}return o._value=n,o}function dr(t){return function(n){this.textContent=t.call(this,n)}}function gr(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&dr(r)),n}return r._value=t,r}var vr=0;function yr(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function mr(){return++vr}var wr=vt.prototype;yr.prototype=function(t){return vt().transition(t)}.prototype={constructor:yr,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=r(t));for(var i=this._groups,o=i.length,u=new Array(o),a=0;a{p&&(p.textContent="search: "+n+" of "+e+" total samples ( "+St(".3f")(n/e*100,3)+"%)")},d()};const E=k;let S=(t,n,e=!1)=>{if(!n)return!1;let r=b(t);e&&(n=n.toLowerCase(),r=r.toLowerCase());const i=new RegExp(n);return void 0!==r&&r&&r.match(i)};const C=S;let j=function(t){p&&(t?p.textContent=t:"function"==typeof d?d():p.textContent="")};const q=j;let O=function(t){return b(t)+" ("+St(".3f")(100*(t.x1-t.x0),3)+"%, "+x(t)+" samples)"},P=function(t){return t.highlight?"#E600E6":function(t,n){let e=_||"warm";_||void 0===n||""===n||(e="red",void 0!==t&&t&&t.match(/::/)&&(e="yellow"),"kernel"===n?e="orange":"jit"===n?e="green":"inlined"===n&&(e="aqua"));const r=function(t){let n=0;if(t){const e=t.split("`");e.length>1&&(t=e[e.length-1]),n=function(t){let n=0,e=0,r=1;if(t){for(let i=0;i6);i++)n+=r*(t.charCodeAt(i)%10),e+=9*r,r*=.7;e>0&&(n/=e)}return n}(t=t.split("(")[0])}return n}(t);return function(t,n){let e,r,i;return"red"===t?(e=200+Math.round(55*n),r=50+Math.round(80*n),i=r):"orange"===t?(e=190+Math.round(65*n),r=90+Math.round(65*n),i=0):"yellow"===t?(e=175+Math.round(55*n),r=e,i=50+Math.round(20*n)):"green"===t?(e=50+Math.round(60*n),r=200+Math.round(55*n),i=e):"pastelgreen"===t?(e=163+Math.round(75*n),r=195+Math.round(49*n),i=72+Math.round(149*n)):"blue"===t?(e=91+Math.round(126*n),r=156+Math.round(76*n),i=221+Math.round(26*n)):"aqua"===t?(e=50+Math.round(60*n),r=165+Math.round(55*n),i=r):"cold"===t?(e=0+Math.round(55*(1-n)),r=0+Math.round(230*(1-n)),i=200+Math.round(55*n)):(e=200+Math.round(55*n),r=0+Math.round(230*(1-n)),i=0+Math.round(55*(1-n))),"rgb("+e+","+r+","+i+")"}(e,r)}(b(t),A(t))};const H=P;function L(t){t.data.fade=!1,t.data.hide=!1,t.children&&t.children.forEach(L)}function T(t){t.parent&&(t.parent.data.fade=!0,T(t.parent))}function D(t){if(i&&i.hide(),function(t){let n,e,r,i=t,o=i.parent;for(;o;){for(n=o.children,e=n.length;e--;)r=n[e],r!==i&&(r.data.hide=!0);i=o,o=i.parent}}(t),L(t),T(t),I(),y){const n=yt(this).select("svg")._groups[0][0].parentNode.offsetTop,r=(window.innerHeight-n)/e,i=(t.height-r+10)*e;window.scrollTo({top:n+i,left:0,behavior:"smooth"})}"function"==typeof c&&c(t)}function B(t,n){if(t.id===n)return t;{const e=M(t);if(e)for(let t=0;t0){const r=t/(n.x1-n.x0);e=e.filter((function(t){return(t.x1-t.x0)*r>f}))}return e}(r),y=yt(this).select("svg");y.attr("width",t);let w=y.selectAll("g").data(g,(function(t){return t.id}));if(!n||v){const t=Math.max.apply(null,g.map((function(t){return t.depth})));n=(t+3)*e,n{D(n)})),w.exit().remove(),w.on("mouseover",(function(t,n){i&&i.show(n,this),j(O(n)),"function"==typeof h&&h(n)})).on("mouseout",(function(){i&&i.hide(),j(null)}))}))}function $(t,n){n.forEach((function(n){const e=t.find((function(t){return t.name===n.name}));e?(e.value+=n.value,n.children&&(e.children||(e.children=[]),$(e.children,n.children))):t.push(n)}))}function V(t){let n,e,r,i,o,u,a,l;const s=[],c=[],h=[],f=!g;let p=t.data;for(p.hide?(t.value=0,e=t.children,e&&h.push(e)):(t.value=p.fade?0:x(p),s.push(t));n=s.pop();)if(e=n.children,e&&(o=e.length)){for(i=0;o--;)a=e[o],p=a.data,p.hide?(a.value=0,r=a.children,r&&h.push(r)):(p.fade?a.value=0:(l=x(p),a.value=l,i+=l),s.push(a));f&&n.value&&(n.value-=i),c.push(e)}for(o=c.length;o--;){for(e=c[o],i=0,u=e.length;u--;)i+=e[u].value;e[0].parent.value+=i}for(;h.length;)for(e=h.pop(),u=e.length;u--;)a=e[u],a.value=0,r=a.children,r&&h.push(r)}function Y(){r.datum((t=>{if("Node"!==t.constructor.name){const n=Dt(t,M);return function(t){let n=0;!function(t,n){n(t);let e=t.children;if(e){const t=[e];let r,i,o;for(;t.length;)for(e=t.pop(),r=e.length;r--;)i=e[r],n(i),o=i.children,o&&t.push(o)}}(t,(function(t){t.id=n++}))}(n),V(n),n.originalValue=n.value,w&&n.eachAfter((t=>{let n=N(t);const e=t.children;let r=e&&e.length;for(;--r>=0;)n+=e[r].delta;t.delta=n})),n}}))}function F(e){if(!arguments.length)return F;r=e,Y(),r.each((function(e){if(0===yt(this).select("svg").size()){const e=yt(this).append("svg:svg").attr("width",t).attr("class","partition d3-flame-graph");n&&(n($([n.data],[t]),n.data))),Y(),I(),F):F},F.update=function(t){return r?(t&&(r.datum(t),Y()),I(),F):F},F.destroy=function(){return r?(i&&(i.hide(),"function"==typeof i.destroy&&i.destroy()),r.selectAll("svg").remove(),F):F},F.setColorMapper=function(t){return arguments.length?(P=n=>{const e=H(n);return t(n,e)},F):(P=H,F)},F.color=F.setColorMapper,F.setColorHue=function(t){return arguments.length?(_=t,F):(_=null,F)},F.minFrameSize=function(t){return arguments.length?(f=t,F):f},F.setDetailsElement=function(t){return arguments.length?(p=t,F):p},F.details=F.setDetailsElement,F.selfValue=function(t){return arguments.length?(g=t,F):g},F.resetHeightOnZoom=function(t){return arguments.length?(v=t,F):v},F.scrollOnZoom=function(t){return arguments.length?(y=t,F):y},F.getName=function(t){return arguments.length?(b=t,F):b},F.getValue=function(t){return arguments.length?(x=t,F):x},F.getChildren=function(t){return arguments.length?(M=t,F):M},F.getLibtype=function(t){return arguments.length?(A=t,F):A},F.getDelta=function(t){return arguments.length?(N=t,F):N},F.setSearchHandler=function(t){return arguments.length?(k=t,F):(k=E,F)},F.setDetailsHandler=function(t){return arguments.length?(j=t,F):(j=q,F)},F.setSearchMatch=function(t){return arguments.length?(S=t,F):(S=C,F)},F}return vt.prototype.interrupt=function(t){return this.each((function(){!function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>2&&e.state<5,e.state=6,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}}(this,t)}))},vt.prototype.transition=function(t){var n,e;t instanceof yr?(n=t._id,t=t._name):(n=mr(),(e=_r).time=Me(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;on?1:t>=n?0:NaN}function e(t,n){return null==t||null==n?NaN:nt?1:n>=t?0:NaN}function r(t){let r,o,a;function u(t,n,e=0,i=t.length){if(e>>1;o(t[r],n)<0?e=r+1:i=r}while(en(t(e),r),a=(n,e)=>t(n)-e):(r=t===n||t===e?t:i,o=t,a=t),{left:u,center:function(t,n,e=0,r=t.length){const i=u(t,n,e,r-1);return i>e&&a(t[i-1],n)>-a(t[i],n)?i-1:i},right:function(t,n,e=0,i=t.length){if(e>>1;o(t[r],n)<=0?e=r+1:i=r}while(e{n(t,e,(r<<=2)+0,(i<<=2)+0,o<<=2),n(t,e,r+1,i+1,o),n(t,e,r+2,i+2,o),n(t,e,r+3,i+3,o)}}));function d(t){return function(n,e,r=e){if(!((e=+e)>=0))throw new RangeError("invalid rx");if(!((r=+r)>=0))throw new RangeError("invalid ry");let{data:i,width:o,height:a}=n;if(!((o=Math.floor(o))>=0))throw new RangeError("invalid width");if(!((a=Math.floor(void 0!==a?a:i.length/o))>=0))throw new RangeError("invalid height");if(!o||!a||!e&&!r)return n;const u=e&&t(e),c=r&&t(r),f=i.slice();return u&&c?(p(u,f,i,o,a),p(u,i,f,o,a),p(u,f,i,o,a),g(c,i,f,o,a),g(c,f,i,o,a),g(c,i,f,o,a)):u?(p(u,i,f,o,a),p(u,f,i,o,a),p(u,i,f,o,a)):c&&(g(c,i,f,o,a),g(c,f,i,o,a),g(c,i,f,o,a)),n}}function p(t,n,e,r,i){for(let o=0,a=r*i;o{if(!((o-=a)>=i))return;let u=t*r[i];const c=a*t;for(let t=i,n=i+c;t{if(!((a-=u)>=o))return;let c=n*i[o];const f=u*n,s=f+u;for(let t=o,n=o+f;t=n&&++e;else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(i=+i)>=i&&++e}return e}function _(t){return 0|t.length}function b(t){return!(t>0)}function m(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function x(t,n){let e,r=0,i=0,o=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(e=n-i,i+=e/++r,o+=e*(n-i));else{let a=-1;for(let u of t)null!=(u=n(u,++a,t))&&(u=+u)>=u&&(e=u-i,i+=e/++r,o+=e*(u-i))}if(r>1)return o/(r-1)}function w(t,n){const e=x(t,n);return e?Math.sqrt(e):e}function M(t,n){let e,r;if(void 0===n)for(const n of t)null!=n&&(void 0===e?n>=n&&(e=r=n):(e>n&&(e=n),r=o&&(e=r=o):(e>o&&(e=o),r0){for(o=t[--i];i>0&&(n=o,e=t[--i],o=n+e,r=e-(o-n),!r););i>0&&(r<0&&t[i-1]<0||r>0&&t[i-1]>0)&&(e=2*r,n=o+e,e==n-o&&(o=n))}return o}}class InternMap extends Map{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const[n,e]of t)this.set(n,e)}get(t){return super.get(A(this,t))}has(t){return super.has(A(this,t))}set(t,n){return super.set(S(this,t),n)}delete(t){return super.delete(E(this,t))}}class InternSet extends Set{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const n of t)this.add(n)}has(t){return super.has(A(this,t))}add(t){return super.add(S(this,t))}delete(t){return super.delete(E(this,t))}}function A({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):e}function S({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):(t.set(r,e),e)}function E({_intern:t,_key:n},e){const r=n(e);return t.has(r)&&(e=t.get(r),t.delete(r)),e}function N(t){return null!==t&&"object"==typeof t?t.valueOf():t}function k(t){return t}function C(t,...n){return F(t,k,k,n)}function P(t,...n){return F(t,Array.from,k,n)}function z(t,n){for(let e=1,r=n.length;et.pop().map((([n,e])=>[...t,n,e]))));return t}function $(t,n,...e){return F(t,k,n,e)}function D(t,n,...e){return F(t,Array.from,n,e)}function R(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function F(t,n,e,r){return function t(i,o){if(o>=r.length)return e(i);const a=new InternMap,u=r[o++];let c=-1;for(const t of i){const n=u(t,++c,i),e=a.get(n);e?e.push(t):a.set(n,[t])}for(const[n,e]of a)a.set(n,t(e,o));return n(a)}(t,0)}function q(t,n){return Array.from(n,(n=>t[n]))}function U(t,...n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");t=Array.from(t);let[e]=n;if(e&&2!==e.length||n.length>1){const r=Uint32Array.from(t,((t,n)=>n));return n.length>1?(n=n.map((n=>t.map(n))),r.sort(((t,e)=>{for(const r of n){const n=O(r[t],r[e]);if(n)return n}}))):(e=t.map(e),r.sort(((t,n)=>O(e[t],e[n])))),q(t,r)}return t.sort(I(e))}function I(t=n){if(t===n)return O;if("function"!=typeof t)throw new TypeError("compare is not a function");return(n,e)=>{const r=t(n,e);return r||0===r?r:(0===t(e,e))-(0===t(n,n))}}function O(t,n){return(null==t||!(t>=t))-(null==n||!(n>=n))||(tn?1:0)}var B=Array.prototype.slice;function Y(t){return()=>t}const L=Math.sqrt(50),j=Math.sqrt(10),H=Math.sqrt(2);function X(t,n,e){const r=(n-t)/Math.max(0,e),i=Math.floor(Math.log10(r)),o=r/Math.pow(10,i),a=o>=L?10:o>=j?5:o>=H?2:1;let u,c,f;return i<0?(f=Math.pow(10,-i)/a,u=Math.round(t*f),c=Math.round(n*f),u/fn&&--c,f=-f):(f=Math.pow(10,i)*a,u=Math.round(t/f),c=Math.round(n/f),u*fn&&--c),c0))return[];if((t=+t)===(n=+n))return[t];const r=n=i))return[];const u=o-i+1,c=new Array(u);if(r)if(a<0)for(let t=0;t0?(t=Math.floor(t/i)*i,n=Math.ceil(n/i)*i):i<0&&(t=Math.ceil(t*i)/i,n=Math.floor(n*i)/i),r=i}}function K(t){return Math.max(1,Math.ceil(Math.log(v(t))/Math.LN2)+1)}function Q(){var t=k,n=M,e=K;function r(r){Array.isArray(r)||(r=Array.from(r));var i,o,a,u=r.length,c=new Array(u);for(i=0;i=h)if(t>=h&&n===M){const t=V(l,h,e);isFinite(t)&&(t>0?h=(Math.floor(h/t)+1)*t:t<0&&(h=(Math.ceil(h*-t)+1)/-t))}else d.pop()}for(var p=d.length,g=0,y=p;d[g]<=l;)++g;for(;d[y-1]>h;)--y;(g||y0?d[i-1]:l,v.x1=i0)for(i=0;i=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e=i)&&(e=i)}return e}function tt(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e=o)&&(e=o,r=i);return r}function nt(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}function et(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e>n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e>o||void 0===e&&o>=o)&&(e=o,r=i);return r}function rt(t,n,e=0,r=1/0,i){if(n=Math.floor(n),e=Math.floor(Math.max(0,e)),r=Math.floor(Math.min(t.length-1,r)),!(e<=n&&n<=r))return t;for(i=void 0===i?O:I(i);r>e;){if(r-e>600){const o=r-e+1,a=n-e+1,u=Math.log(o),c=.5*Math.exp(2*u/3),f=.5*Math.sqrt(u*c*(o-c)/o)*(a-o/2<0?-1:1);rt(t,n,Math.max(e,Math.floor(n-a*c/o+f)),Math.min(r,Math.floor(n+(o-a)*c/o+f)),i)}const o=t[n];let a=e,u=r;for(it(t,e,n),i(t[r],o)>0&&it(t,e,r);a0;)--u}0===i(t[e],o)?it(t,e,u):(++u,it(t,u,r)),u<=n&&(e=u+1),n<=u&&(r=u-1)}return t}function it(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function ot(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)>0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)>0:0===e(n,n))&&(r=n,i=!0);return r}function at(t,n,e){if(t=Float64Array.from(function*(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let e=-1;for(let r of t)null!=(r=n(r,++e,t))&&(r=+r)>=r&&(yield r)}}(t,e)),(r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return nt(t);if(n>=1)return J(t);var r,i=(r-1)*n,o=Math.floor(i),a=J(rt(t,o).subarray(0,o+1));return a+(nt(t.subarray(o+1))-a)*(i-o)}}function ut(t,n,e=o){if((r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,a=Math.floor(i),u=+e(t[a],a,t);return u+(+e(t[a+1],a+1,t)-u)*(i-a)}}function ct(t,n,e=o){if(!isNaN(n=+n)){if(r=Float64Array.from(t,((n,r)=>o(e(t[r],r,t)))),n<=0)return et(r);if(n>=1)return tt(r);var r,i=Uint32Array.from(t,((t,n)=>n)),a=r.length-1,u=Math.floor(a*n);return rt(i,u,0,a,((t,n)=>O(r[t],r[n]))),(u=ot(i.subarray(0,u+1),(t=>r[t])))>=0?u:-1}}function ft(t){return Array.from(function*(t){for(const n of t)yield*n}(t))}function st(t,n){return[t,n]}function lt(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r+t(n)}function kt(t,n){return n=Math.max(0,t.bandwidth()-2*n)/2,t.round()&&(n=Math.round(n)),e=>+t(e)+n}function Ct(){return!this.__axis}function Pt(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,f=t===xt||t===Tt?-1:1,s=t===Tt||t===wt?"x":"y",l=t===xt||t===Mt?St:Et;function h(h){var d=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,p=null==i?n.tickFormat?n.tickFormat.apply(n,e):mt:i,g=Math.max(o,0)+u,y=n.range(),v=+y[0]+c,_=+y[y.length-1]+c,b=(n.bandwidth?kt:Nt)(n.copy(),c),m=h.selection?h.selection():h,x=m.selectAll(".domain").data([null]),w=m.selectAll(".tick").data(d,n).order(),M=w.exit(),T=w.enter().append("g").attr("class","tick"),A=w.select("line"),S=w.select("text");x=x.merge(x.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),w=w.merge(T),A=A.merge(T.append("line").attr("stroke","currentColor").attr(s+"2",f*o)),S=S.merge(T.append("text").attr("fill","currentColor").attr(s,f*g).attr("dy",t===xt?"0em":t===Mt?"0.71em":"0.32em")),h!==m&&(x=x.transition(h),w=w.transition(h),A=A.transition(h),S=S.transition(h),M=M.transition(h).attr("opacity",At).attr("transform",(function(t){return isFinite(t=b(t))?l(t+c):this.getAttribute("transform")})),T.attr("opacity",At).attr("transform",(function(t){var n=this.parentNode.__axis;return l((n&&isFinite(n=n(t))?n:b(t))+c)}))),M.remove(),x.attr("d",t===Tt||t===wt?a?"M"+f*a+","+v+"H"+c+"V"+_+"H"+f*a:"M"+c+","+v+"V"+_:a?"M"+v+","+f*a+"V"+c+"H"+_+"V"+f*a:"M"+v+","+c+"H"+_),w.attr("opacity",1).attr("transform",(function(t){return l(b(t)+c)})),A.attr(s+"2",f*o),S.attr(s,f*g).text(p),m.filter(Ct).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===wt?"start":t===Tt?"end":"middle"),m.each((function(){this.__axis=b}))}return h.scale=function(t){return arguments.length?(n=t,h):n},h.ticks=function(){return e=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(e=null==t?[]:Array.from(t),h):e.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(c=+t,h):c},h}var zt={value:()=>{}};function $t(){for(var t,n=0,e=arguments.length,r={};n=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ut.hasOwnProperty(n)?{space:Ut[n],local:t}:t}function Ot(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===qt&&n.documentElement.namespaceURI===qt?n.createElement(t):n.createElementNS(e,t)}}function Bt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Yt(t){var n=It(t);return(n.local?Bt:Ot)(n)}function Lt(){}function jt(t){return null==t?Lt:function(){return this.querySelector(t)}}function Ht(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function Xt(){return[]}function Gt(t){return null==t?Xt:function(){return this.querySelectorAll(t)}}function Vt(t){return function(){return this.matches(t)}}function Wt(t){return function(n){return n.matches(t)}}var Zt=Array.prototype.find;function Kt(){return this.firstElementChild}var Qt=Array.prototype.filter;function Jt(){return Array.from(this.children)}function tn(t){return new Array(t.length)}function nn(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function en(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;un?1:t>=n?0:NaN}function cn(t){return function(){this.removeAttribute(t)}}function fn(t){return function(){this.removeAttributeNS(t.space,t.local)}}function sn(t,n){return function(){this.setAttribute(t,n)}}function ln(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function hn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function dn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function pn(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function gn(t){return function(){this.style.removeProperty(t)}}function yn(t,n,e){return function(){this.style.setProperty(t,n,e)}}function vn(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function _n(t,n){return t.style.getPropertyValue(n)||pn(t).getComputedStyle(t,null).getPropertyValue(n)}function bn(t){return function(){delete this[t]}}function mn(t,n){return function(){this[t]=n}}function xn(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function wn(t){return t.trim().split(/^|\s+/)}function Mn(t){return t.classList||new Tn(t)}function Tn(t){this._node=t,this._names=wn(t.getAttribute("class")||"")}function An(t,n){for(var e=Mn(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Gn=[null];function Vn(t,n){this._groups=t,this._parents=n}function Wn(){return new Vn([[document.documentElement]],Gn)}function Zn(t){return"string"==typeof t?new Vn([[document.querySelector(t)]],[document.documentElement]):new Vn([[t]],Gn)}Vn.prototype=Wn.prototype={constructor:Vn,select:function(t){"function"!=typeof t&&(t=jt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i=m&&(m=b+1);!(_=y[m])&&++m=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=un);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?gn:"function"==typeof n?vn:yn)(t,n,null==e?"":e)):_n(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?bn:"function"==typeof n?xn:mn)(t,n)):this.node()[t]},classed:function(t,n){var e=wn(t+"");if(arguments.length<2){for(var r=Mn(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?Ln:Yn,r=0;r()=>t;function fe(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:c,dy:f,dispatch:s}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:s}})}function se(t){return!t.ctrlKey&&!t.button}function le(){return this.parentNode}function he(t,n){return null==n?{x:t.x,y:t.y}:n}function de(){return navigator.maxTouchPoints||"ontouchstart"in this}function pe(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function ge(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function ye(){}fe.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var ve=.7,_e=1/ve,be="\\s*([+-]?\\d+)\\s*",me="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",xe="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",we=/^#([0-9a-f]{3,8})$/,Me=new RegExp(`^rgb\\(${be},${be},${be}\\)$`),Te=new RegExp(`^rgb\\(${xe},${xe},${xe}\\)$`),Ae=new RegExp(`^rgba\\(${be},${be},${be},${me}\\)$`),Se=new RegExp(`^rgba\\(${xe},${xe},${xe},${me}\\)$`),Ee=new RegExp(`^hsl\\(${me},${xe},${xe}\\)$`),Ne=new RegExp(`^hsla\\(${me},${xe},${xe},${me}\\)$`),ke={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function Ce(){return this.rgb().formatHex()}function Pe(){return this.rgb().formatRgb()}function ze(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=we.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?$e(n):3===e?new qe(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?De(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?De(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=Me.exec(t))?new qe(n[1],n[2],n[3],1):(n=Te.exec(t))?new qe(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ae.exec(t))?De(n[1],n[2],n[3],n[4]):(n=Se.exec(t))?De(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ee.exec(t))?Le(n[1],n[2]/100,n[3]/100,1):(n=Ne.exec(t))?Le(n[1],n[2]/100,n[3]/100,n[4]):ke.hasOwnProperty(t)?$e(ke[t]):"transparent"===t?new qe(NaN,NaN,NaN,0):null}function $e(t){return new qe(t>>16&255,t>>8&255,255&t,1)}function De(t,n,e,r){return r<=0&&(t=n=e=NaN),new qe(t,n,e,r)}function Re(t){return t instanceof ye||(t=ze(t)),t?new qe((t=t.rgb()).r,t.g,t.b,t.opacity):new qe}function Fe(t,n,e,r){return 1===arguments.length?Re(t):new qe(t,n,e,null==r?1:r)}function qe(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ue(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}`}function Ie(){const t=Oe(this.opacity);return`${1===t?"rgb(":"rgba("}${Be(this.r)}, ${Be(this.g)}, ${Be(this.b)}${1===t?")":`, ${t})`}`}function Oe(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Be(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Ye(t){return((t=Be(t))<16?"0":"")+t.toString(16)}function Le(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Xe(t,n,e,r)}function je(t){if(t instanceof Xe)return new Xe(t.h,t.s,t.l,t.opacity);if(t instanceof ye||(t=ze(t)),!t)return new Xe;if(t instanceof Xe)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e0&&c<1?0:a,new Xe(a,u,c,t.opacity)}function He(t,n,e,r){return 1===arguments.length?je(t):new Xe(t,n,e,null==r?1:r)}function Xe(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ge(t){return(t=(t||0)%360)<0?t+360:t}function Ve(t){return Math.max(0,Math.min(1,t||0))}function We(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}pe(ye,ze,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Ce,formatHex:Ce,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return je(this).formatHsl()},formatRgb:Pe,toString:Pe}),pe(qe,Fe,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new qe(Be(this.r),Be(this.g),Be(this.b),Oe(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ue,formatHex:Ue,formatHex8:function(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}${Ye(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:Ie,toString:Ie})),pe(Xe,He,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new Xe(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new Xe(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new qe(We(t>=240?t-240:t+120,i,r),We(t,i,r),We(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new Xe(Ge(this.h),Ve(this.s),Ve(this.l),Oe(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Oe(this.opacity);return`${1===t?"hsl(":"hsla("}${Ge(this.h)}, ${100*Ve(this.s)}%, ${100*Ve(this.l)}%${1===t?")":`, ${t})`}`}}));const Ze=Math.PI/180,Ke=180/Math.PI,Qe=.96422,Je=1,tr=.82521,nr=4/29,er=6/29,rr=3*er*er,ir=er*er*er;function or(t){if(t instanceof ur)return new ur(t.l,t.a,t.b,t.opacity);if(t instanceof pr)return gr(t);t instanceof qe||(t=Re(t));var n,e,r=lr(t.r),i=lr(t.g),o=lr(t.b),a=cr((.2225045*r+.7168786*i+.0606169*o)/Je);return r===i&&i===o?n=e=a:(n=cr((.4360747*r+.3850649*i+.1430804*o)/Qe),e=cr((.0139322*r+.0971045*i+.7141733*o)/tr)),new ur(116*a-16,500*(n-a),200*(a-e),t.opacity)}function ar(t,n,e,r){return 1===arguments.length?or(t):new ur(t,n,e,null==r?1:r)}function ur(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function cr(t){return t>ir?Math.pow(t,1/3):t/rr+nr}function fr(t){return t>er?t*t*t:rr*(t-nr)}function sr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function lr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function hr(t){if(t instanceof pr)return new pr(t.h,t.c,t.l,t.opacity);if(t instanceof ur||(t=or(t)),0===t.a&&0===t.b)return new pr(NaN,0=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r()=>t;function Cr(t,n){return function(e){return t+e*n}}function Pr(t,n){var e=n-t;return e?Cr(t,e>180||e<-180?e-360*Math.round(e/360):e):kr(isNaN(t)?n:t)}function zr(t){return 1==(t=+t)?$r:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):kr(isNaN(n)?e:n)}}function $r(t,n){var e=n-t;return e?Cr(t,e):kr(isNaN(t)?n:t)}var Dr=function t(n){var e=zr(n);function r(t,n){var r=e((t=Fe(t)).r,(n=Fe(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=$r(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function Rr(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;eo&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:Yr(e,r)})),o=Hr.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Yr(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Yr(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:Yr(t,e)},{i:u-2,x:Yr(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e=0&&n._call.call(void 0,t),n=n._next;--yi}function Ci(){xi=(mi=Mi.now())+wi,yi=vi=0;try{ki()}finally{yi=0,function(){var t,n,e=pi,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pi=n);gi=t,zi(r)}(),xi=0}}function Pi(){var t=Mi.now(),n=t-mi;n>bi&&(wi-=n,mi=t)}function zi(t){yi||(vi&&(vi=clearTimeout(vi)),t-xi>24?(t<1/0&&(vi=setTimeout(Ci,t-Mi.now()-wi)),_i&&(_i=clearInterval(_i))):(_i||(mi=Mi.now(),_i=setInterval(Pi,bi)),yi=1,Ti(Ci)))}function $i(t,n,e){var r=new Ei;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ei.prototype=Ni.prototype={constructor:Ei,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Ai():+e)+(null==n?0:+n),this._next||gi===this||(gi?gi._next=this:pi=this,gi=this),this._call=t,this._time=e,zi()},stop:function(){this._call&&(this._call=null,this._time=1/0,zi())}};var Di=$t("start","end","cancel","interrupt"),Ri=[],Fi=0,qi=1,Ui=2,Ii=3,Oi=4,Bi=5,Yi=6;function Li(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=qi,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var f,s,l,h;if(e.state!==qi)return c();for(f in i)if((h=i[f]).name===e.name){if(h.state===Ii)return $i(a);h.state===Oi?(h.state=Yi,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+fFi)throw new Error("too late; already scheduled");return e}function Hi(t,n){var e=Xi(t,n);if(e.state>Ii)throw new Error("too late; already running");return e}function Xi(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Gi(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>Ui&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?ji:Hi;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=It(t),r="transform"===e?ni:Ki;return this.attrTween(t,"function"==typeof n?(e.local?ro:eo)(e,r,Zi(this,"attr."+t,n)):null==n?(e.local?Ji:Qi)(e):(e.local?no:to)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=It(t);return this.tween(e,(r.local?io:oo)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?ti:Ki;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=_n(this,t),a=(this.style.removeProperty(t),_n(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,lo(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=_n(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=_n(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,Zi(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Hi(this,t),f=c.on,s=null==c.value[a]?o||(o=lo(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=_n(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Zi(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Xi(this.node(),e).tween,o=0,a=i.length;o()=>t;function Qo(t,{sourceEvent:n,target:e,selection:r,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},selection:{value:r,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function Jo(t){t.preventDefault(),t.stopImmediatePropagation()}var ta={name:"drag"},na={name:"space"},ea={name:"handle"},ra={name:"center"};const{abs:ia,max:oa,min:aa}=Math;function ua(t){return[+t[0],+t[1]]}function ca(t){return[ua(t[0]),ua(t[1])]}var fa={name:"x",handles:["w","e"].map(va),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},sa={name:"y",handles:["n","s"].map(va),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},la={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(va),input:function(t){return null==t?null:ca(t)},output:function(t){return t}},ha={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},da={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},pa={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},ga={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},ya={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function va(t){return{type:t}}function _a(t){return!t.ctrlKey&&!t.button}function ba(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function ma(){return navigator.maxTouchPoints||"ontouchstart"in this}function xa(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function wa(t){var n,e=ba,r=_a,i=ma,o=!0,a=$t("start","brush","end"),u=6;function c(n){var e=n.property("__brush",g).selectAll(".overlay").data([va("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",ha.overlay).merge(e).each((function(){var t=xa(this).extent;Zn(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),n.selectAll(".selection").data([va("selection")]).enter().append("rect").attr("class","selection").attr("cursor",ha.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=n.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return ha[t.type]})),n.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",h).filter(i).on("touchstart.brush",h).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function f(){var t=Zn(this),n=xa(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?n[1][0]-u/2:n[0][0]-u/2})).attr("y",(function(t){return"s"===t.type[0]?n[1][1]-u/2:n[0][1]-u/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+u:u})).attr("height",(function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+u:u}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function s(t,n,e){var r=t.__brush.emitter;return!r||e&&r.clean?new l(t,n,e):r}function l(t,n,e){this.that=t,this.args=n,this.state=t.__brush,this.active=0,this.clean=e}function h(e){if((!n||e.touches)&&r.apply(this,arguments)){var i,a,u,c,l,h,d,p,g,y,v,_=this,b=e.target.__data__.type,m="selection"===(o&&e.metaKey?b="overlay":b)?ta:o&&e.altKey?ra:ea,x=t===sa?null:ga[b],w=t===fa?null:ya[b],M=xa(_),T=M.extent,A=M.selection,S=T[0][0],E=T[0][1],N=T[1][0],k=T[1][1],C=0,P=0,z=x&&w&&o&&e.shiftKey,$=Array.from(e.touches||[e],(t=>{const n=t.identifier;return(t=ne(t,_)).point0=t.slice(),t.identifier=n,t}));Gi(_);var D=s(_,arguments,!0).beforestart();if("overlay"===b){A&&(g=!0);const n=[$[0],$[1]||$[0]];M.selection=A=[[i=t===sa?S:aa(n[0][0],n[1][0]),u=t===fa?E:aa(n[0][1],n[1][1])],[l=t===sa?N:oa(n[0][0],n[1][0]),d=t===fa?k:oa(n[0][1],n[1][1])]],$.length>1&&I(e)}else i=A[0][0],u=A[0][1],l=A[1][0],d=A[1][1];a=i,c=u,h=l,p=d;var R=Zn(_).attr("pointer-events","none"),F=R.selectAll(".overlay").attr("cursor",ha[b]);if(e.touches)D.moved=U,D.ended=O;else{var q=Zn(e.view).on("mousemove.brush",U,!0).on("mouseup.brush",O,!0);o&&q.on("keydown.brush",(function(t){switch(t.keyCode){case 16:z=x&&w;break;case 18:m===ea&&(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ra,I(t));break;case 32:m!==ea&&m!==ra||(x<0?l=h-C:x>0&&(i=a-C),w<0?d=p-P:w>0&&(u=c-P),m=na,F.attr("cursor",ha.selection),I(t));break;default:return}Jo(t)}),!0).on("keyup.brush",(function(t){switch(t.keyCode){case 16:z&&(y=v=z=!1,I(t));break;case 18:m===ra&&(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ea,I(t));break;case 32:m===na&&(t.altKey?(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ra):(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ea),F.attr("cursor",ha[b]),I(t));break;default:return}Jo(t)}),!0),ae(e.view)}f.call(_),D.start(e,m.name)}function U(t){for(const n of t.changedTouches||[t])for(const t of $)t.identifier===n.identifier&&(t.cur=ne(n,_));if(z&&!y&&!v&&1===$.length){const t=$[0];ia(t.cur[0]-t[0])>ia(t.cur[1]-t[1])?v=!0:y=!0}for(const t of $)t.cur&&(t[0]=t.cur[0],t[1]=t.cur[1]);g=!0,Jo(t),I(t)}function I(t){const n=$[0],e=n.point0;var r;switch(C=n[0]-e[0],P=n[1]-e[1],m){case na:case ta:x&&(C=oa(S-i,aa(N-l,C)),a=i+C,h=l+C),w&&(P=oa(E-u,aa(k-d,P)),c=u+P,p=d+P);break;case ea:$[1]?(x&&(a=oa(S,aa(N,$[0][0])),h=oa(S,aa(N,$[1][0])),x=1),w&&(c=oa(E,aa(k,$[0][1])),p=oa(E,aa(k,$[1][1])),w=1)):(x<0?(C=oa(S-i,aa(N-i,C)),a=i+C,h=l):x>0&&(C=oa(S-l,aa(N-l,C)),a=i,h=l+C),w<0?(P=oa(E-u,aa(k-u,P)),c=u+P,p=d):w>0&&(P=oa(E-d,aa(k-d,P)),c=u,p=d+P));break;case ra:x&&(a=oa(S,aa(N,i-C*x)),h=oa(S,aa(N,l+C*x))),w&&(c=oa(E,aa(k,u-P*w)),p=oa(E,aa(k,d+P*w)))}ht+e))}function za(t,n){var e=0,r=null,i=null,o=null;function a(a){var u,c=a.length,f=new Array(c),s=Pa(0,c),l=new Array(c*c),h=new Array(c),d=0;a=Float64Array.from({length:c*c},n?(t,n)=>a[n%c][n/c|0]:(t,n)=>a[n/c|0][n%c]);for(let n=0;nr(f[t],f[n])));for(const e of s){const r=n;if(t){const t=Pa(1+~c,c).filter((t=>t<0?a[~t*c+e]:a[e*c+t]));i&&t.sort(((t,n)=>i(t<0?-a[~t*c+e]:a[e*c+t],n<0?-a[~n*c+e]:a[e*c+n])));for(const r of t)if(r<0){(l[~r*c+e]||(l[~r*c+e]={source:null,target:null})).target={index:e,startAngle:n,endAngle:n+=a[~r*c+e]*d,value:a[~r*c+e]}}else{(l[e*c+r]||(l[e*c+r]={source:null,target:null})).source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}else{const t=Pa(0,c).filter((t=>a[e*c+t]||a[t*c+e]));i&&t.sort(((t,n)=>i(a[e*c+t],a[e*c+n])));for(const r of t){let t;if(e=0))throw new Error(`invalid digits: ${t}`);if(n>15)return qa;const e=10**n;return function(t){this._+=t[0];for(let n=1,r=t.length;nRa)if(Math.abs(s*u-c*f)>Ra&&i){let h=e-o,d=r-a,p=u*u+c*c,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(l),_=i*Math.tan(($a-Math.acos((p+l-g)/(2*y*v)))/2),b=_/v,m=_/y;Math.abs(b-1)>Ra&&this._append`L${t+b*f},${n+b*s}`,this._append`A${i},${i},0,0,${+(s*h>f*d)},${this._x1=t+m*u},${this._y1=n+m*c}`}else this._append`L${this._x1=t},${this._y1=n}`;else;}arc(t,n,e,r,i,o){if(t=+t,n=+n,o=!!o,(e=+e)<0)throw new Error(`negative radius: ${e}`);let a=e*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;null===this._x1?this._append`M${c},${f}`:(Math.abs(this._x1-c)>Ra||Math.abs(this._y1-f)>Ra)&&this._append`L${c},${f}`,e&&(l<0&&(l=l%Da+Da),l>Fa?this._append`A${e},${e},0,1,${s},${t-a},${n-u}A${e},${e},0,1,${s},${this._x1=c},${this._y1=f}`:l>Ra&&this._append`A${e},${e},0,${+(l>=$a)},${s},${this._x1=t+e*Math.cos(i)},${this._y1=n+e*Math.sin(i)}`)}rect(t,n,e,r){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${e=+e}v${+r}h${-e}Z`}toString(){return this._}};function Ia(){return new Ua}Ia.prototype=Ua.prototype;var Oa=Array.prototype.slice;function Ba(t){return function(){return t}}function Ya(t){return t.source}function La(t){return t.target}function ja(t){return t.radius}function Ha(t){return t.startAngle}function Xa(t){return t.endAngle}function Ga(){return 0}function Va(){return 10}function Wa(t){var n=Ya,e=La,r=ja,i=ja,o=Ha,a=Xa,u=Ga,c=null;function f(){var f,s=n.apply(this,arguments),l=e.apply(this,arguments),h=u.apply(this,arguments)/2,d=Oa.call(arguments),p=+r.apply(this,(d[0]=s,d)),g=o.apply(this,d)-Ea,y=a.apply(this,d)-Ea,v=+i.apply(this,(d[0]=l,d)),_=o.apply(this,d)-Ea,b=a.apply(this,d)-Ea;if(c||(c=f=Ia()),h>Ca&&(Ma(y-g)>2*h+Ca?y>g?(g+=h,y-=h):(g-=h,y+=h):g=y=(g+y)/2,Ma(b-_)>2*h+Ca?b>_?(_+=h,b-=h):(_-=h,b+=h):_=b=(_+b)/2),c.moveTo(p*Ta(g),p*Aa(g)),c.arc(0,0,p,g,y),g!==_||y!==b)if(t){var m=v-+t.apply(this,arguments),x=(_+b)/2;c.quadraticCurveTo(0,0,m*Ta(_),m*Aa(_)),c.lineTo(v*Ta(x),v*Aa(x)),c.lineTo(m*Ta(b),m*Aa(b))}else c.quadraticCurveTo(0,0,v*Ta(_),v*Aa(_)),c.arc(0,0,v,_,b);if(c.quadraticCurveTo(0,0,p*Ta(g),p*Aa(g)),c.closePath(),f)return c=null,f+""||null}return t&&(f.headRadius=function(n){return arguments.length?(t="function"==typeof n?n:Ba(+n),f):t}),f.radius=function(t){return arguments.length?(r=i="function"==typeof t?t:Ba(+t),f):r},f.sourceRadius=function(t){return arguments.length?(r="function"==typeof t?t:Ba(+t),f):r},f.targetRadius=function(t){return arguments.length?(i="function"==typeof t?t:Ba(+t),f):i},f.startAngle=function(t){return arguments.length?(o="function"==typeof t?t:Ba(+t),f):o},f.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:Ba(+t),f):a},f.padAngle=function(t){return arguments.length?(u="function"==typeof t?t:Ba(+t),f):u},f.source=function(t){return arguments.length?(n=t,f):n},f.target=function(t){return arguments.length?(e=t,f):e},f.context=function(t){return arguments.length?(c=null==t?null:t,f):c},f}var Za=Array.prototype.slice;function Ka(t,n){return t-n}var Qa=t=>()=>t;function Ja(t,n){for(var e,r=-1,i=n.length;++rr!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function nu(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function eu(){}var ru=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function iu(){var t=1,n=1,e=K,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(Ka);else{const e=M(t,ou);for(n=G(...Z(e[0],e[1],n),n);n[n.length-1]>=e[1];)n.pop();for(;n[1]o(t,n)))}function o(e,i){const o=null==i?NaN:+i;if(isNaN(o))throw new Error(`invalid value: ${i}`);var u=[],c=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=au(e[0],r),ru[f<<1].forEach(p);for(;++o=r,ru[s<<2].forEach(p);for(;++o0?u.push([t]):c.push(t)})),c.forEach((function(t){for(var n,e=0,r=u.length;e0&&o0&&a=0&&o>=0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?Qa(Za.call(t)):Qa(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:eu,i):r===u},i}function ou(t){return isFinite(t)?t:NaN}function au(t,n){return null!=t&&+t>=n}function uu(t){return null==t||isNaN(t=+t)?-1/0:t}function cu(t,n,e,r){const i=r-n,o=e-n,a=isFinite(i)||isFinite(o)?i/o:Math.sign(i)/Math.sign(o);return isNaN(a)?t:t+a-.5}function fu(t){return t[0]}function su(t){return t[1]}function lu(){return 1}const hu=134217729,du=33306690738754706e-32;function pu(t,n,e,r,i){let o,a,u,c,f=n[0],s=r[0],l=0,h=0;s>f==s>-f?(o=f,f=n[++l]):(o=s,s=r[++h]);let d=0;if(lf==s>-f?(a=f+o,u=o-(a-f),f=n[++l]):(a=s+o,u=o-(a-s),s=r[++h]),o=a,0!==u&&(i[d++]=u);lf==s>-f?(a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l]):(a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h]),o=a,0!==u&&(i[d++]=u);for(;l=33306690738754716e-32*f?c:-function(t,n,e,r,i,o,a){let u,c,f,s,l,h,d,p,g,y,v,_,b,m,x,w,M,T;const A=t-i,S=e-i,E=n-o,N=r-o;m=A*N,h=hu*A,d=h-(h-A),p=A-d,h=hu*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=E*S,h=hu*E,d=h-(h-E),p=E-d,h=hu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,_u[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,_u[1]=b-(v+l)+(l-w),T=_+v,l=T-_,_u[2]=_-(T-l)+(v-l),_u[3]=T;let k=function(t,n){let e=n[0];for(let r=1;r=C||-k>=C)return k;if(l=t-A,u=t-(A+l)+(l-i),l=e-S,f=e-(S+l)+(l-i),l=n-E,c=n-(E+l)+(l-o),l=r-N,s=r-(N+l)+(l-o),0===u&&0===c&&0===f&&0===s)return k;if(C=vu*a+du*Math.abs(k),k+=A*s+N*u-(E*f+S*c),k>=C||-k>=C)return k;m=u*N,h=hu*u,d=h-(h-u),p=u-d,h=hu*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=c*S,h=hu*c,d=h-(h-c),p=c-d,h=hu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const P=pu(4,_u,4,wu,bu);m=A*s,h=hu*A,d=h-(h-A),p=A-d,h=hu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=E*f,h=hu*E,d=h-(h-E),p=E-d,h=hu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const z=pu(P,bu,4,wu,mu);m=u*s,h=hu*u,d=h-(h-u),p=u-d,h=hu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=c*f,h=hu*c,d=h-(h-c),p=c-d,h=hu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const $=pu(z,mu,4,wu,xu);return xu[$-1]}(t,n,e,r,i,o,f)}const Tu=Math.pow(2,-52),Au=new Uint32Array(512);class Su{static from(t,n=zu,e=$u){const r=t.length,i=new Float64Array(2*r);for(let o=0;o>1;if(n>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*n-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(n)),this._hullPrev=new Uint32Array(n),this._hullNext=new Uint32Array(n),this._hullTri=new Uint32Array(n),this._hullHash=new Int32Array(this._hashSize).fill(-1),this._ids=new Uint32Array(n),this._dists=new Float64Array(n),this.update()}update(){const{coords:t,_hullPrev:n,_hullNext:e,_hullTri:r,_hullHash:i}=this,o=t.length>>1;let a=1/0,u=1/0,c=-1/0,f=-1/0;for(let n=0;nc&&(c=e),r>f&&(f=r),this._ids[n]=n}const s=(a+c)/2,l=(u+f)/2;let h,d,p,g=1/0;for(let n=0;n0&&(d=n,g=e)}let _=t[2*d],b=t[2*d+1],m=1/0;for(let n=0;nr&&(n[e++]=i,r=this._dists[i])}return this.hull=n.subarray(0,e),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(Mu(y,v,_,b,x,w)<0){const t=d,n=_,e=b;d=p,_=x,b=w,p=t,x=n,w=e}const M=function(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=t+(f*s-u*l)*h,p=n+(a*l-c*s)*h;return{x:d,y:p}}(y,v,_,b,x,w);this._cx=M.x,this._cy=M.y;for(let n=0;n0&&Math.abs(f-o)<=Tu&&Math.abs(s-a)<=Tu)continue;if(o=f,a=s,c===h||c===d||c===p)continue;let l=0;for(let t=0,n=this._hashKey(f,s);t=0;)if(y=g,y===l){y=-1;break}if(-1===y)continue;let v=this._addTriangle(y,c,e[y],-1,-1,r[y]);r[c]=this._legalize(v+2),r[y]=v,T++;let _=e[y];for(;g=e[_],Mu(f,s,t[2*_],t[2*_+1],t[2*g],t[2*g+1])<0;)v=this._addTriangle(_,c,g,r[c],-1,r[_]),r[c]=this._legalize(v+2),e[_]=_,T--,_=g;if(y===l)for(;g=n[y],Mu(f,s,t[2*g],t[2*g+1],t[2*y],t[2*y+1])<0;)v=this._addTriangle(g,c,y,-1,r[y],r[g]),this._legalize(v+2),r[g]=v,e[y]=y,T--,y=g;this._hullStart=n[c]=y,e[y]=n[_]=c,e[c]=_,i[this._hashKey(f,s)]=c,i[this._hashKey(t[2*y],t[2*y+1])]=y}this.hull=new Uint32Array(T);for(let t=0,n=this._hullStart;t0?3-e:1+e)/4}(t-this._cx,n-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:n,_halfedges:e,coords:r}=this;let i=0,o=0;for(;;){const a=e[t],u=t-t%3;if(o=u+(t+2)%3,-1===a){if(0===i)break;t=Au[--i];continue}const c=a-a%3,f=u+(t+1)%3,s=c+(a+2)%3,l=n[o],h=n[t],d=n[f],p=n[s];if(Nu(r[2*l],r[2*l+1],r[2*h],r[2*h+1],r[2*d],r[2*d+1],r[2*p],r[2*p+1])){n[t]=p,n[a]=l;const r=e[s];if(-1===r){let n=this._hullStart;do{if(this._hullTri[n]===s){this._hullTri[n]=t;break}n=this._hullPrev[n]}while(n!==this._hullStart)}this._link(t,r),this._link(a,e[o]),this._link(o,s);const u=c+(a+1)%3;i=e&&n[t[a]]>o;)t[a+1]=t[a--];t[a+1]=r}else{let i=e+1,o=r;Pu(t,e+r>>1,i),n[t[e]]>n[t[r]]&&Pu(t,e,r),n[t[i]]>n[t[r]]&&Pu(t,i,r),n[t[e]]>n[t[i]]&&Pu(t,e,i);const a=t[i],u=n[a];for(;;){do{i++}while(n[t[i]]u);if(o=o-e?(Cu(t,n,i,r),Cu(t,n,e,o-1)):(Cu(t,n,e,o-1),Cu(t,n,i,r))}}function Pu(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function zu(t){return t[0]}function $u(t){return t[1]}const Du=1e-6;class Ru{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,n,e){const r=(t=+t)+(e=+e),i=n=+n;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${r},${i}`:(Math.abs(this._x1-r)>Du||Math.abs(this._y1-i)>Du)&&(this._+="L"+r+","+i),e&&(this._+=`A${e},${e},0,1,1,${t-e},${n}A${e},${e},0,1,1,${this._x1=r},${this._y1=i}`)}rect(t,n,e,r){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+r}h${-e}Z`}value(){return this._||null}}class Fu{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class qu{constructor(t,[n,e,r,i]=[0,0,960,500]){if(!((r=+r)>=(n=+n)&&(i=+i)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=r,this.xmin=n,this.ymax=i,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:r}=this;let i,o;const a=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let r,u,c=0,f=0,s=e.length;c1;)i-=2;for(let t=2;t0){if(n>=this.ymax)return null;(i=(this.ymax-n)/r)0){if(t>=this.xmax)return null;(i=(this.xmax-t)/e)this.xmax?2:0)|(nthis.ymax?8:0)}_simplify(t){if(t&&t.length>4){for(let n=0;n2&&function(t){const{triangles:n,coords:e}=t;for(let t=0;t1e-10)return!1}return!0}(t)){this.collinear=Int32Array.from({length:n.length/2},((t,n)=>n)).sort(((t,e)=>n[2*t]-n[2*e]||n[2*t+1]-n[2*e+1]));const t=this.collinear[0],e=this.collinear[this.collinear.length-1],r=[n[2*t],n[2*t+1],n[2*e],n[2*e+1]],i=1e-8*Math.hypot(r[3]-r[1],r[2]-r[0]);for(let t=0,e=n.length/2;t0&&(this.triangles=new Int32Array(3).fill(-1),this.halfedges=new Int32Array(3).fill(-1),this.triangles[0]=r[0],o[r[0]]=1,2===r.length&&(o[r[1]]=0,this.triangles[1]=r[1],this.triangles[2]=r[1]))}voronoi(t){return new qu(this,t)}*neighbors(t){const{inedges:n,hull:e,_hullIndex:r,halfedges:i,triangles:o,collinear:a}=this;if(a){const n=a.indexOf(t);return n>0&&(yield a[n-1]),void(n=0&&i!==e&&i!==r;)e=i;return i}_step(t,n,e){const{inedges:r,hull:i,_hullIndex:o,halfedges:a,triangles:u,points:c}=this;if(-1===r[t]||!c.length)return(t+1)%(c.length>>1);let f=t,s=Iu(n-c[2*t],2)+Iu(e-c[2*t+1],2);const l=r[t];let h=l;do{let r=u[h];const l=Iu(n-c[2*r],2)+Iu(e-c[2*r+1],2);if(l9999?"+"+Ku(n,6):Ku(n,4))+"-"+Ku(t.getUTCMonth()+1,2)+"-"+Ku(t.getUTCDate(),2)+(o?"T"+Ku(e,2)+":"+Ku(r,2)+":"+Ku(i,2)+"."+Ku(o,3)+"Z":i?"T"+Ku(e,2)+":"+Ku(r,2)+":"+Ku(i,2)+"Z":r||e?"T"+Ku(e,2)+":"+Ku(r,2)+"Z":"")}function Ju(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return Hu;if(f)return f=!1,ju;var n,r,i=a;if(t.charCodeAt(i)===Xu){for(;a++=o?c=!0:(r=t.charCodeAt(a++))===Gu?f=!0:r===Vu&&(f=!0,t.charCodeAt(a)===Gu&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;amc(n,e).then((n=>(new DOMParser).parseFromString(n,t)))}var Sc=Ac("application/xml"),Ec=Ac("text/html"),Nc=Ac("image/svg+xml");function kc(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function Cc(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function Pc(t){return t[0]}function zc(t){return t[1]}function $c(t,n,e){var r=new Dc(null==n?Pc:n,null==e?zc:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Dc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Rc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Fc=$c.prototype=Dc.prototype;function qc(t){return function(){return t}}function Uc(t){return 1e-6*(t()-.5)}function Ic(t){return t.x+t.vx}function Oc(t){return t.y+t.vy}function Bc(t){return t.index}function Yc(t,n){var e=t.get(n);if(!e)throw new Error("node not found: "+n);return e}Fc.copy=function(){var t,n,e=new Dc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Rc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Rc(n));return e},Fc.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return kc(this.cover(n,e),n,e,t)},Fc.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;es&&(s=r),il&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;et||t>=i||r>n||n>=o;)switch(u=(nh||(o=c.y0)>d||(a=c.x1)=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,g.data),b=n-+this._y.call(null,g.data),m=_*_+b*b;if(m=(u=(p+y)/2))?p=u:y=u,(s=a>=(c=(g+v)/2))?g=c:v=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},Fc.removeAll=function(t){for(var n=0,e=t.length;n1?r[0]+r.slice(2):r,+t.slice(e+1)]}function Zc(t){return(t=Wc(Math.abs(t)))?t[1]:NaN}var Kc,Qc=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Jc(t){if(!(n=Qc.exec(t)))throw new Error("invalid format: "+t);var n;return new tf({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function tf(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function nf(t,n){var e=Wc(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Jc.prototype=tf.prototype,tf.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var ef={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>nf(100*t,n),r:nf,s:function(t,n){var e=Wc(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Kc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Wc(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function rf(t){return t}var of,af=Array.prototype.map,uf=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function cf(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?rf:(n=af.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?rf:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(af.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"−":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Jc(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,_=t.type;"n"===_?(g=!0,_="g"):ef[_]||(void 0===y&&(y=12),v=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=ef[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),y),v&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),T&&0==+t&&"+"!==l&&(T=!1),h=(T?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?uf[8+Kc/3]:"")+M+(T&&"("===l?")":""),w)for(i=-1,o=t.length;++i(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,S=A>1)+h+t+M+S.slice(A);break;default:t=S+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Jc(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Zc(n)/3))),i=Math.pow(10,-r),o=uf[8+r/3];return function(t){return e(i*t)+o}}}}function ff(n){return of=cf(n),t.format=of.format,t.formatPrefix=of.formatPrefix,of}function sf(t){return Math.max(0,-Zc(Math.abs(t)))}function lf(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Zc(n)/3)))-Zc(Math.abs(t)))}function hf(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Zc(n)-Zc(t))+1}t.format=void 0,t.formatPrefix=void 0,ff({thousands:",",grouping:[3],currency:["$",""]});var df=1e-6,pf=1e-12,gf=Math.PI,yf=gf/2,vf=gf/4,_f=2*gf,bf=180/gf,mf=gf/180,xf=Math.abs,wf=Math.atan,Mf=Math.atan2,Tf=Math.cos,Af=Math.ceil,Sf=Math.exp,Ef=Math.hypot,Nf=Math.log,kf=Math.pow,Cf=Math.sin,Pf=Math.sign||function(t){return t>0?1:t<0?-1:0},zf=Math.sqrt,$f=Math.tan;function Df(t){return t>1?0:t<-1?gf:Math.acos(t)}function Rf(t){return t>1?yf:t<-1?-yf:Math.asin(t)}function Ff(t){return(t=Cf(t/2))*t}function qf(){}function Uf(t,n){t&&Of.hasOwnProperty(t.type)&&Of[t.type](t,n)}var If={Feature:function(t,n){Uf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r=0?1:-1,i=r*e,o=Tf(n=(n*=mf)/2+vf),a=Cf(n),u=Vf*a,c=Gf*o+u*Tf(i),f=u*r*Cf(i);as.add(Mf(f,c)),Xf=t,Gf=o,Vf=a}function ds(t){return[Mf(t[1],t[0]),Rf(t[2])]}function ps(t){var n=t[0],e=t[1],r=Tf(e);return[r*Tf(n),r*Cf(n),Cf(e)]}function gs(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function ys(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function vs(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function _s(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function bs(t){var n=zf(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var ms,xs,ws,Ms,Ts,As,Ss,Es,Ns,ks,Cs,Ps,zs,$s,Ds,Rs,Fs={point:qs,lineStart:Is,lineEnd:Os,polygonStart:function(){Fs.point=Bs,Fs.lineStart=Ys,Fs.lineEnd=Ls,rs=new T,cs.polygonStart()},polygonEnd:function(){cs.polygonEnd(),Fs.point=qs,Fs.lineStart=Is,Fs.lineEnd=Os,as<0?(Wf=-(Kf=180),Zf=-(Qf=90)):rs>df?Qf=90:rs<-df&&(Zf=-90),os[0]=Wf,os[1]=Kf},sphere:function(){Wf=-(Kf=180),Zf=-(Qf=90)}};function qs(t,n){is.push(os=[Wf=t,Kf=t]),nQf&&(Qf=n)}function Us(t,n){var e=ps([t*mf,n*mf]);if(es){var r=ys(es,e),i=ys([r[1],-r[0],0],r);bs(i),i=ds(i);var o,a=t-Jf,u=a>0?1:-1,c=i[0]*bf*u,f=xf(a)>180;f^(u*JfQf&&(Qf=o):f^(u*Jf<(c=(c+360)%360-180)&&cQf&&(Qf=n)),f?tjs(Wf,Kf)&&(Kf=t):js(t,Kf)>js(Wf,Kf)&&(Wf=t):Kf>=Wf?(tKf&&(Kf=t)):t>Jf?js(Wf,t)>js(Wf,Kf)&&(Kf=t):js(t,Kf)>js(Wf,Kf)&&(Wf=t)}else is.push(os=[Wf=t,Kf=t]);nQf&&(Qf=n),es=e,Jf=t}function Is(){Fs.point=Us}function Os(){os[0]=Wf,os[1]=Kf,Fs.point=qs,es=null}function Bs(t,n){if(es){var e=t-Jf;rs.add(xf(e)>180?e+(e>0?360:-360):e)}else ts=t,ns=n;cs.point(t,n),Us(t,n)}function Ys(){cs.lineStart()}function Ls(){Bs(ts,ns),cs.lineEnd(),xf(rs)>df&&(Wf=-(Kf=180)),os[0]=Wf,os[1]=Kf,es=null}function js(t,n){return(n-=t)<0?n+360:n}function Hs(t,n){return t[0]-n[0]}function Xs(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:ngf&&(t-=Math.round(t/_f)*_f),[t,n]}function ul(t,n,e){return(t%=_f)?n||e?ol(fl(t),sl(n,e)):fl(t):n||e?sl(n,e):al}function cl(t){return function(n,e){return xf(n+=t)>gf&&(n-=Math.round(n/_f)*_f),[n,e]}}function fl(t){var n=cl(t);return n.invert=cl(-t),n}function sl(t,n){var e=Tf(t),r=Cf(t),i=Tf(n),o=Cf(n);function a(t,n){var a=Tf(n),u=Tf(t)*a,c=Cf(t)*a,f=Cf(n),s=f*e+u*r;return[Mf(c*i-s*o,u*e-f*r),Rf(s*i+c*o)]}return a.invert=function(t,n){var a=Tf(n),u=Tf(t)*a,c=Cf(t)*a,f=Cf(n),s=f*i-c*o;return[Mf(c*i+f*o,u*e+s*r),Rf(s*e-u*r)]},a}function ll(t){function n(n){return(n=t(n[0]*mf,n[1]*mf))[0]*=bf,n[1]*=bf,n}return t=ul(t[0]*mf,t[1]*mf,t.length>2?t[2]*mf:0),n.invert=function(n){return(n=t.invert(n[0]*mf,n[1]*mf))[0]*=bf,n[1]*=bf,n},n}function hl(t,n,e,r,i,o){if(e){var a=Tf(n),u=Cf(n),c=r*e;null==i?(i=n+r*_f,o=n-c/2):(i=dl(a,i),o=dl(a,o),(r>0?io)&&(i+=r*_f));for(var f,s=i;r>0?s>o:s1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function gl(t,n){return xf(t[0]-n[0])=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function _l(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r=0?1:-1,E=S*A,N=E>gf,k=y*w;if(c.add(Mf(k*S*Cf(E),v*M+k*Tf(E))),a+=N?A+S*_f:A,N^p>=e^m>=e){var C=ys(ps(d),ps(b));bs(C);var P=ys(o,C);bs(P);var z=(N^A>=0?-1:1)*Rf(P[2]);(r>z||r===z&&(C[0]||C[1]))&&(u+=N^A>=0?1:-1)}}return(a<-df||a0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(wl))}return h}}function wl(t){return t.length>1}function Ml(t,n){return((t=t.x)[0]<0?t[1]-yf-df:yf-t[1])-((n=n.x)[0]<0?n[1]-yf-df:yf-n[1])}al.invert=al;var Tl=xl((function(){return!0}),(function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?gf:-gf,c=xf(o-e);xf(c-gf)0?yf:-yf),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=gf&&(xf(e-i)df?wf((Cf(n)*(o=Tf(r))*Cf(e)-Cf(r)*(i=Tf(n))*Cf(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}),(function(t,n,e,r){var i;if(null==t)i=e*yf,r.point(-gf,i),r.point(0,i),r.point(gf,i),r.point(gf,0),r.point(gf,-i),r.point(0,-i),r.point(-gf,-i),r.point(-gf,0),r.point(-gf,i);else if(xf(t[0]-n[0])>df){var o=t[0]0,i=xf(n)>df;function o(t,e){return Tf(t)*Tf(e)>n}function a(t,e,r){var i=[1,0,0],o=ys(ps(t),ps(e)),a=gs(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=ys(i,o),h=_s(i,f);vs(h,_s(o,s));var d=l,p=gs(h,d),g=gs(d,d),y=p*p-g*(gs(h,h)-1);if(!(y<0)){var v=zf(y),_=_s(d,(-p-v)/g);if(vs(_,h),_=ds(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x0^_[1]<(xf(_[0]-m)gf^(m<=_[0]&&_[0]<=x)){var S=_s(d,(-p+v)/g);return vs(S,h),[_,ds(S)]}}}function u(n,e){var i=r?t:gf-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return xl(o,(function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],g=o(l,h),y=r?g?0:u(l,h):g?u(l+(l<0?gf:-gf),h):0;if(!n&&(f=c=g)&&t.lineStart(),g!==c&&(!(d=a(n,p))||gl(n,d)||gl(p,d))&&(p[2]=1),g!==c)s=0,g?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1],2),t.lineEnd()),n=d;else if(i&&n&&r^g){var v;y&e||!(v=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1],3)))}!g||n&&gl(n,p)||t.point(p[0],p[1]),n=p,c=g,e=y},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}}),(function(n,r,i,o){hl(o,t,e,i,n,r)}),r?[0,-t]:[-gf,t-gf])}var Sl,El,Nl,kl,Cl=1e9,Pl=-Cl;function zl(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return xf(r[0]-t)0?0:3:xf(r[0]-e)0?2:1:xf(r[1]-n)0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,g,y,v,_,b=a,m=pl(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(M(l,h),d&&y&&m.rejoin(),c.push(m.result()));x.point=w,y&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;er&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=ft(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&vl(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),v)l=o,h=a,d=u,v=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&y)b.point(o,a);else{var c=[p=Math.max(Pl,Math.min(Cl,p)),g=Math.max(Pl,Math.min(Cl,g))],m=[o=Math.max(Pl,Math.min(Cl,o)),a=Math.max(Pl,Math.min(Cl,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a0)){if(a/=h,h<0){if(a0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,g=a,y=u}return x}}var $l={sphere:qf,point:qf,lineStart:function(){$l.point=Rl,$l.lineEnd=Dl},lineEnd:qf,polygonStart:qf,polygonEnd:qf};function Dl(){$l.point=$l.lineEnd=qf}function Rl(t,n){El=t*=mf,Nl=Cf(n*=mf),kl=Tf(n),$l.point=Fl}function Fl(t,n){t*=mf;var e=Cf(n*=mf),r=Tf(n),i=xf(t-El),o=Tf(i),a=r*Cf(i),u=kl*e-Nl*r*o,c=Nl*e+kl*r*o;Sl.add(Mf(zf(a*a+u*u),c)),El=t,Nl=e,kl=r}function ql(t){return Sl=new T,Lf(t,$l),+Sl}var Ul=[null,null],Il={type:"LineString",coordinates:Ul};function Ol(t,n){return Ul[0]=t,Ul[1]=n,ql(Il)}var Bl={Feature:function(t,n){return Ll(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r0&&(i=Ol(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))df})).map(c)).concat(lt(Af(o/d)*d,i,d).filter((function(t){return xf(t%g)>df})).map(f))}return v.lines=function(){return _().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),v.precision(y)):[[r,u],[e,a]]},v.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),v.precision(y)):[[n,o],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],v):[h,d]},v.precision=function(h){return arguments.length?(y=+h,c=Wl(o,i,90),f=Zl(n,t,y),s=Wl(u,a,90),l=Zl(r,e,y),v):y},v.extentMajor([[-180,-90+df],[180,90-df]]).extentMinor([[-180,-80-df],[180,80+df]])}var Ql,Jl,th,nh,eh=t=>t,rh=new T,ih=new T,oh={point:qf,lineStart:qf,lineEnd:qf,polygonStart:function(){oh.lineStart=ah,oh.lineEnd=fh},polygonEnd:function(){oh.lineStart=oh.lineEnd=oh.point=qf,rh.add(xf(ih)),ih=new T},result:function(){var t=rh/2;return rh=new T,t}};function ah(){oh.point=uh}function uh(t,n){oh.point=ch,Ql=th=t,Jl=nh=n}function ch(t,n){ih.add(nh*t-th*n),th=t,nh=n}function fh(){ch(Ql,Jl)}var sh=oh,lh=1/0,hh=lh,dh=-lh,ph=dh,gh={point:function(t,n){tdh&&(dh=t);nph&&(ph=n)},lineStart:qf,lineEnd:qf,polygonStart:qf,polygonEnd:qf,result:function(){var t=[[lh,hh],[dh,ph]];return dh=ph=-(hh=lh=1/0),t}};var yh,vh,_h,bh,mh=gh,xh=0,wh=0,Mh=0,Th=0,Ah=0,Sh=0,Eh=0,Nh=0,kh=0,Ch={point:Ph,lineStart:zh,lineEnd:Rh,polygonStart:function(){Ch.lineStart=Fh,Ch.lineEnd=qh},polygonEnd:function(){Ch.point=Ph,Ch.lineStart=zh,Ch.lineEnd=Rh},result:function(){var t=kh?[Eh/kh,Nh/kh]:Sh?[Th/Sh,Ah/Sh]:Mh?[xh/Mh,wh/Mh]:[NaN,NaN];return xh=wh=Mh=Th=Ah=Sh=Eh=Nh=kh=0,t}};function Ph(t,n){xh+=t,wh+=n,++Mh}function zh(){Ch.point=$h}function $h(t,n){Ch.point=Dh,Ph(_h=t,bh=n)}function Dh(t,n){var e=t-_h,r=n-bh,i=zf(e*e+r*r);Th+=i*(_h+t)/2,Ah+=i*(bh+n)/2,Sh+=i,Ph(_h=t,bh=n)}function Rh(){Ch.point=Ph}function Fh(){Ch.point=Uh}function qh(){Ih(yh,vh)}function Uh(t,n){Ch.point=Ih,Ph(yh=_h=t,vh=bh=n)}function Ih(t,n){var e=t-_h,r=n-bh,i=zf(e*e+r*r);Th+=i*(_h+t)/2,Ah+=i*(bh+n)/2,Sh+=i,Eh+=(i=bh*t-_h*n)*(_h+t),Nh+=i*(bh+n),kh+=3*i,Ph(_h=t,bh=n)}var Oh=Ch;function Bh(t){this._context=t}Bh.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,_f)}},result:qf};var Yh,Lh,jh,Hh,Xh,Gh=new T,Vh={point:qf,lineStart:function(){Vh.point=Wh},lineEnd:function(){Yh&&Zh(Lh,jh),Vh.point=qf},polygonStart:function(){Yh=!0},polygonEnd:function(){Yh=null},result:function(){var t=+Gh;return Gh=new T,t}};function Wh(t,n){Vh.point=Zh,Lh=Hh=t,jh=Xh=n}function Zh(t,n){Hh-=t,Xh-=n,Gh.add(zf(Hh*Hh+Xh*Xh)),Hh=t,Xh=n}var Kh=Vh;let Qh,Jh,td,nd;class ed{constructor(t){this._append=null==t?rd:function(t){const n=Math.floor(t);if(!(n>=0))throw new RangeError(`invalid digits: ${t}`);if(n>15)return rd;if(n!==Qh){const t=10**n;Qh=n,Jh=function(n){let e=1;this._+=n[0];for(const r=n.length;e4*n&&g--){var m=a+h,x=u+d,w=c+p,M=zf(m*m+x*x+w*w),T=Rf(w/=M),A=xf(xf(w)-1)n||xf((v*k+_*C)/b-.5)>.3||a*h+u*d+c*p2?t[2]%360*mf:0,k()):[y*bf,v*bf,_*bf]},E.angle=function(t){return arguments.length?(b=t%360*mf,k()):b*bf},E.reflectX=function(t){return arguments.length?(m=t?-1:1,k()):m<0},E.reflectY=function(t){return arguments.length?(x=t?-1:1,k()):x<0},E.precision=function(t){return arguments.length?(a=dd(u,S=t*t),C()):zf(S)},E.fitExtent=function(t,n){return ud(E,t,n)},E.fitSize=function(t,n){return cd(E,t,n)},E.fitWidth=function(t,n){return fd(E,t,n)},E.fitHeight=function(t,n){return sd(E,t,n)},function(){return n=t.apply(this,arguments),E.invert=n.invert&&N,k()}}function _d(t){var n=0,e=gf/3,r=vd(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*mf,e=t[1]*mf):[n*bf,e*bf]},i}function bd(t,n){var e=Cf(t),r=(e+Cf(n))/2;if(xf(r)0?n<-yf+df&&(n=-yf+df):n>yf-df&&(n=yf-df);var e=i/kf(Nd(n),r);return[e*Cf(r*t),i-e*Tf(r*t)]}return o.invert=function(t,n){var e=i-n,o=Pf(r)*zf(t*t+e*e),a=Mf(t,xf(e))*Pf(e);return e*r<0&&(a-=gf*Pf(t)*Pf(e)),[a/r,2*wf(kf(i/o,1/r))-yf]},o}function Cd(t,n){return[t,n]}function Pd(t,n){var e=Tf(t),r=t===n?Cf(t):(e-Tf(n))/(n-t),i=e/r+t;if(xf(r)=0;)n+=e[r].value;else n=1;t.value=n}function Gd(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Wd)):void 0===n&&(n=Vd);for(var e,r,i,o,a,u=new Qd(t),c=[u];e=c.pop();)if((i=n(e.data))&&(a=(i=Array.from(i)).length))for(e.children=i,o=a-1;o>=0;--o)c.push(r=i[o]=new Qd(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Kd)}function Vd(t){return t.children}function Wd(t){return Array.isArray(t)?t[1]:null}function Zd(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Kd(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Qd(t){this.data=t,this.depth=this.height=0,this.parent=null}function Jd(t){return null==t?null:tp(t)}function tp(t){if("function"!=typeof t)throw new Error;return t}function np(){return 0}function ep(t){return function(){return t}}qd.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(zd+$d*i+o*(Dd+Rd*i))-n)/(zd+3*$d*i+o*(7*Dd+9*Rd*i)))*r)*i*i,!(xf(e)df&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},Od.invert=Md(Rf),Bd.invert=Md((function(t){return 2*wf(t)})),Yd.invert=function(t,n){return[-n,2*wf(Sf(t))-yf]},Qd.prototype=Gd.prototype={constructor:Qd,count:function(){return this.eachAfter(Xd)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,a=[o],u=[],c=-1;o=a.pop();)if(u.push(o),e=o.children)for(r=0,i=e.length;r=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Gd(this).eachBefore(Zd)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e(t=(rp*t+ip)%op)/op}function up(t,n){for(var e,r,i=0,o=(t=function(t,n){let e,r,i=t.length;for(;i;)r=n()*i--|0,e=t[i],t[i]=t[r],t[r]=e;return t}(Array.from(t),n)).length,a=[];i0&&e*e>r*r+i*i}function lp(t,n){for(var e=0;e1e-6?(E+Math.sqrt(E*E-4*S*N))/(2*S):N/E);return{x:r+w+M*k,y:i+T+A*k,r:k}}function gp(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function yp(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function vp(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function _p(t){this._=t,this.next=null,this.previous=null}function bp(t,n){if(!(o=(t=function(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}(t)).length))return 0;var e,r,i,o,a,u,c,f,s,l,h;if((e=t[0]).x=0,e.y=0,!(o>1))return e.r;if(r=t[1],e.x=-r.r,r.x=e.r,r.y=0,!(o>2))return e.r+r.r;gp(r,e,i=t[2]),e=new _p(e),r=new _p(r),i=new _p(i),e.next=i.previous=r,r.next=e.previous=i,i.next=r.previous=e;t:for(c=3;c1&&!zp(t,n););return t.slice(0,n)}function zp(t,n){if("/"===t[n]){let e=0;for(;n>0&&"\\"===t[--n];)++e;if(0==(1&e))return!0}return!1}function $p(t,n){return t.parent===n.parent?1:2}function Dp(t){var n=t.children;return n?n[0]:t.t}function Rp(t){var n=t.children;return n?n[n.length-1]:t.t}function Fp(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qp(t,n,e){return t.a.parent===n.parent?t.a:e}function Up(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Ip(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++uh&&(h=u),y=s*s*g,(d=Math.max(h/y,y/l))>p){s-=u;break}p=d}v.push(a={value:s,dice:c1?n:1)},e}(Op);var Lp=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l1?n:1)},e}(Op);function jp(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function Hp(t,n){return t[0]-n[0]||t[1]-n[1]}function Xp(t){const n=t.length,e=[0,1];let r,i=2;for(r=2;r1&&jp(t[e[i-2]],t[e[i-1]],t[r])<=0;)--i;e[i++]=r}return e.slice(0,i)}var Gp=Math.random,Vp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Gp),Wp=function t(n){function e(t,e){return arguments.length<2&&(e=t,t=0),t=Math.floor(t),e=Math.floor(e)-t,function(){return Math.floor(n()*e+t)}}return e.source=t,e}(Gp),Zp=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Gp),Kp=function t(n){var e=Zp.source(n);function r(){var t=e.apply(this,arguments);return function(){return Math.exp(t())}}return r.source=t,r}(Gp),Qp=function t(n){function e(t){return(t=+t)<=0?()=>0:function(){for(var e=0,r=t;r>1;--r)e+=n();return e+r*n()}}return e.source=t,e}(Gp),Jp=function t(n){var e=Qp.source(n);function r(t){if(0==(t=+t))return n;var r=e(t);return function(){return r()/t}}return r.source=t,r}(Gp),tg=function t(n){function e(t){return function(){return-Math.log1p(-n())/t}}return e.source=t,e}(Gp),ng=function t(n){function e(t){if((t=+t)<0)throw new RangeError("invalid alpha");return t=1/-t,function(){return Math.pow(1-n(),t)}}return e.source=t,e}(Gp),eg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return function(){return Math.floor(n()+t)}}return e.source=t,e}(Gp),rg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return 0===t?()=>1/0:1===t?()=>1:(t=Math.log1p(-t),function(){return 1+Math.floor(Math.log1p(-n())/t)})}return e.source=t,e}(Gp),ig=function t(n){var e=Zp.source(n)();function r(t,r){if((t=+t)<0)throw new RangeError("invalid k");if(0===t)return()=>0;if(r=null==r?1:+r,1===t)return()=>-Math.log1p(-n())*r;var i=(t<1?t+1:t)-1/3,o=1/(3*Math.sqrt(i)),a=t<1?()=>Math.pow(n(),1/t):()=>1;return function(){do{do{var t=e(),u=1+o*t}while(u<=0);u*=u*u;var c=1-n()}while(c>=1-.0331*t*t*t*t&&Math.log(c)>=.5*t*t+i*(1-u+Math.log(u)));return i*u*a()*r}}return r.source=t,r}(Gp),og=function t(n){var e=ig.source(n);function r(t,n){var r=e(t),i=e(n);return function(){var t=r();return 0===t?0:t/(t+i())}}return r.source=t,r}(Gp),ag=function t(n){var e=rg.source(n),r=og.source(n);function i(t,n){return t=+t,(n=+n)>=1?()=>t:n<=0?()=>0:function(){for(var i=0,o=t,a=n;o*a>16&&o*(1-a)>16;){var u=Math.floor((o+1)*a),c=r(u,o-u+1)();c<=a?(i+=u,o-=u,a=(a-c)/(1-c)):(o=u-1,a/=c)}for(var f=a<.5,s=e(f?a:1-a),l=s(),h=0;l<=o;++h)l+=s();return i+(f?h:o-h)}}return i.source=t,i}(Gp),ug=function t(n){function e(t,e,r){var i;return 0==(t=+t)?i=t=>-Math.log(t):(t=1/t,i=n=>Math.pow(n,t)),e=null==e?0:+e,r=null==r?1:+r,function(){return e+r*i(-Math.log1p(-n()))}}return e.source=t,e}(Gp),cg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){return t+e*Math.tan(Math.PI*n())}}return e.source=t,e}(Gp),fg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){var r=n();return t+e*Math.log(r/(1-r))}}return e.source=t,e}(Gp),sg=function t(n){var e=ig.source(n),r=ag.source(n);function i(t){return function(){for(var i=0,o=t;o>16;){var a=Math.floor(.875*o),u=e(a)();if(u>o)return i+r(a-1,o/u)();i+=a,o-=u}for(var c=-Math.log1p(-n()),f=0;c<=o;++f)c-=Math.log1p(-n());return i+f}}return i.source=t,i}(Gp);const lg=1/4294967296;function hg(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function dg(t,n){switch(arguments.length){case 0:break;case 1:"function"==typeof t?this.interpolator(t):this.range(t);break;default:this.domain(t),"function"==typeof n?this.interpolator(n):this.range(n)}return this}const pg=Symbol("implicit");function gg(){var t=new InternMap,n=[],e=[],r=pg;function i(i){let o=t.get(i);if(void 0===o){if(r!==pg)return r;t.set(i,o=n.push(i)-1)}return e[o%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=new InternMap;for(const r of e)t.has(r)||t.set(r,n.push(r)-1);return i},i.range=function(t){return arguments.length?(e=Array.from(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return gg(n,e).unknown(r)},hg.apply(i,arguments),i}function yg(){var t,n,e=gg().unknown(void 0),r=e.domain,i=e.range,o=0,a=1,u=!1,c=0,f=0,s=.5;function l(){var e=r().length,l=an&&(e=t,t=n,n=e),function(e){return Math.max(t,Math.min(n,e))}}(a[0],a[t-1])),r=t>2?Mg:wg,i=o=null,l}function l(n){return null==n||isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),Yr)))(e)))},l.domain=function(t){return arguments.length?(a=Array.from(t,_g),s()):a.slice()},l.range=function(t){return arguments.length?(u=Array.from(t),s()):u.slice()},l.rangeRound=function(t){return u=Array.from(t),c=Vr,s()},l.clamp=function(t){return arguments.length?(f=!!t||mg,s()):f!==mg},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Sg(){return Ag()(mg,mg)}function Eg(n,e,r,i){var o,a=W(n,e,r);switch((i=Jc(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=lf(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=hf(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=sf(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function Ng(t){var n=t.domain;return t.ticks=function(t){var e=n();return G(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Eg(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i,o=n(),a=0,u=o.length-1,c=o[a],f=o[u],s=10;for(f0;){if((i=V(c,f,e))===r)return o[a]=c,o[u]=f,n(o);if(i>0)c=Math.floor(c/i)*i,f=Math.ceil(f/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,f=Math.floor(f*i)/i}r=i}return t},t}function kg(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a-t(-n,e)}function Fg(n){const e=n(Cg,Pg),r=e.domain;let i,o,a=10;function u(){return i=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),n=>Math.log(n)/t)}(a),o=function(t){return 10===t?Dg:t===Math.E?Math.exp:n=>Math.pow(t,n)}(a),r()[0]<0?(i=Rg(i),o=Rg(o),n(zg,$g)):n(Cg,Pg),e}return e.base=function(t){return arguments.length?(a=+t,u()):a},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=t=>{const n=r();let e=n[0],u=n[n.length-1];const c=u0){for(;l<=h;++l)for(f=1;fu)break;p.push(s)}}else for(;l<=h;++l)for(f=a-1;f>=1;--f)if(s=l>0?f/o(-l):f*o(l),!(su)break;p.push(s)}2*p.length{if(null==n&&(n=10),null==r&&(r=10===a?"s":","),"function"!=typeof r&&(a%1||null!=(r=Jc(r)).precision||(r.trim=!0),r=t.format(r)),n===1/0)return r;const u=Math.max(1,a*n/e.ticks().length);return t=>{let n=t/o(Math.round(i(t)));return n*ar(kg(r(),{floor:t=>o(Math.floor(i(t))),ceil:t=>o(Math.ceil(i(t)))})),e}function qg(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function Ug(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function Ig(t){var n=1,e=t(qg(n),Ug(n));return e.constant=function(e){return arguments.length?t(qg(n=+e),Ug(n)):n},Ng(e)}function Og(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function Bg(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function Yg(t){return t<0?-t*t:t*t}function Lg(t){var n=t(mg,mg),e=1;return n.exponent=function(n){return arguments.length?1===(e=+n)?t(mg,mg):.5===e?t(Bg,Yg):t(Og(e),Og(1/e)):e},Ng(n)}function jg(){var t=Lg(Ag());return t.copy=function(){return Tg(t,jg()).exponent(t.exponent())},hg.apply(t,arguments),t}function Hg(t){return Math.sign(t)*t*t}const Xg=new Date,Gg=new Date;function Vg(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=n=>(t(n=new Date(+n)),n),i.ceil=e=>(t(e=new Date(e-1)),n(e,1),t(e),e),i.round=t=>{const n=i(t),e=i.ceil(t);return t-n(n(t=new Date(+t),null==e?1:Math.floor(e)),t),i.range=(e,r,o)=>{const a=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e0))return a;let u;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(uVg((n=>{if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)}),((t,r)=>{if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})),e&&(i.count=(n,r)=>(Xg.setTime(+n),Gg.setTime(+r),t(Xg),t(Gg),Math.floor(e(Xg,Gg))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?n=>r(n)%t==0:n=>i.count(0,n)%t==0):i:null)),i}const Wg=Vg((()=>{}),((t,n)=>{t.setTime(+t+n)}),((t,n)=>n-t));Wg.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?Vg((n=>{n.setTime(Math.floor(n/t)*t)}),((n,e)=>{n.setTime(+n+e*t)}),((n,e)=>(e-n)/t)):Wg:null);const Zg=Wg.range,Kg=1e3,Qg=6e4,Jg=36e5,ty=864e5,ny=6048e5,ey=2592e6,ry=31536e6,iy=Vg((t=>{t.setTime(t-t.getMilliseconds())}),((t,n)=>{t.setTime(+t+n*Kg)}),((t,n)=>(n-t)/Kg),(t=>t.getUTCSeconds())),oy=iy.range,ay=Vg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Kg)}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getMinutes())),uy=ay.range,cy=Vg((t=>{t.setUTCSeconds(0,0)}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getUTCMinutes())),fy=cy.range,sy=Vg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Kg-t.getMinutes()*Qg)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getHours())),ly=sy.range,hy=Vg((t=>{t.setUTCMinutes(0,0,0)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getUTCHours())),dy=hy.range,py=Vg((t=>t.setHours(0,0,0,0)),((t,n)=>t.setDate(t.getDate()+n)),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Qg)/ty),(t=>t.getDate()-1)),gy=py.range,yy=Vg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ty),(t=>t.getUTCDate()-1)),vy=yy.range,_y=Vg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ty),(t=>Math.floor(t/ty))),by=_y.range;function my(t){return Vg((n=>{n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)}),((t,n)=>{t.setDate(t.getDate()+7*n)}),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Qg)/ny))}const xy=my(0),wy=my(1),My=my(2),Ty=my(3),Ay=my(4),Sy=my(5),Ey=my(6),Ny=xy.range,ky=wy.range,Cy=My.range,Py=Ty.range,zy=Ay.range,$y=Sy.range,Dy=Ey.range;function Ry(t){return Vg((n=>{n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+7*n)}),((t,n)=>(n-t)/ny))}const Fy=Ry(0),qy=Ry(1),Uy=Ry(2),Iy=Ry(3),Oy=Ry(4),By=Ry(5),Yy=Ry(6),Ly=Fy.range,jy=qy.range,Hy=Uy.range,Xy=Iy.range,Gy=Oy.range,Vy=By.range,Wy=Yy.range,Zy=Vg((t=>{t.setDate(1),t.setHours(0,0,0,0)}),((t,n)=>{t.setMonth(t.getMonth()+n)}),((t,n)=>n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())),(t=>t.getMonth())),Ky=Zy.range,Qy=Vg((t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCMonth(t.getUTCMonth()+n)}),((t,n)=>n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())),(t=>t.getUTCMonth())),Jy=Qy.range,tv=Vg((t=>{t.setMonth(0,1),t.setHours(0,0,0,0)}),((t,n)=>{t.setFullYear(t.getFullYear()+n)}),((t,n)=>n.getFullYear()-t.getFullYear()),(t=>t.getFullYear()));tv.every=t=>isFinite(t=Math.floor(t))&&t>0?Vg((n=>{n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)}),((n,e)=>{n.setFullYear(n.getFullYear()+e*t)})):null;const nv=tv.range,ev=Vg((t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCFullYear(t.getUTCFullYear()+n)}),((t,n)=>n.getUTCFullYear()-t.getUTCFullYear()),(t=>t.getUTCFullYear()));ev.every=t=>isFinite(t=Math.floor(t))&&t>0?Vg((n=>{n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)}),((n,e)=>{n.setUTCFullYear(n.getUTCFullYear()+e*t)})):null;const rv=ev.range;function iv(t,n,e,i,o,a){const u=[[iy,1,Kg],[iy,5,5e3],[iy,15,15e3],[iy,30,3e4],[a,1,Qg],[a,5,3e5],[a,15,9e5],[a,30,18e5],[o,1,Jg],[o,3,108e5],[o,6,216e5],[o,12,432e5],[i,1,ty],[i,2,1728e5],[e,1,ny],[n,1,ey],[n,3,7776e6],[t,1,ry]];function c(n,e,i){const o=Math.abs(e-n)/i,a=r((([,,t])=>t)).right(u,o);if(a===u.length)return t.every(W(n/ry,e/ry,i));if(0===a)return Wg.every(Math.max(W(n,e,i),1));const[c,f]=u[o/u[a-1][2]=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:k_,s:C_,S:Zv,u:Kv,U:Qv,V:t_,w:n_,W:e_,x:null,X:null,y:r_,Y:o_,Z:u_,"%":N_},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:c_,e:c_,f:d_,g:T_,G:S_,H:f_,I:s_,j:l_,L:h_,m:p_,M:g_,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:k_,s:C_,S:y_,u:v_,U:__,V:m_,w:x_,W:w_,x:null,X:null,y:M_,Y:A_,Z:E_,"%":N_},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p.get(r[0].toLowerCase()),e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h.get(r[0].toLowerCase()),e+r[0].length):-1},b:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=y.get(r[0].toLowerCase()),e+r[0].length):-1},c:function(t,e,r){return T(t,n,e,r)},d:zv,e:zv,f:Uv,g:Nv,G:Ev,H:Dv,I:Dv,j:$v,L:qv,m:Pv,M:Rv,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s.get(r[0].toLowerCase()),e+r[0].length):-1},q:Cv,Q:Ov,s:Bv,S:Fv,u:Mv,U:Tv,V:Av,w:wv,W:Sv,x:function(t,n,r){return T(t,e,n,r)},X:function(t,n,e){return T(t,r,n,e)},y:Nv,Y:Ev,Z:kv,"%":Iv};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=sv(lv(o.y,0,1))).getUTCDay(),r=i>4||0===i?qy.ceil(r):qy(r),r=yy.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=fv(lv(o.y,0,1))).getDay(),r=i>4||0===i?wy.ceil(r):wy(r),r=py.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?sv(lv(o.y,0,1)).getUTCDay():fv(lv(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,sv(o)):fv(o)}}function T(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in pv?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var dv,pv={"-":"",_:" ",0:"0"},gv=/^\s*\d+/,yv=/^%/,vv=/[\\^$*+?|[\]().{}]/g;function _v(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o[t.toLowerCase(),n])))}function wv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Mv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Tv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Av(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Sv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Ev(t,n,e){var r=gv.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Nv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function kv(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Cv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function Pv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function zv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function $v(t,n,e){var r=gv.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function Dv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Rv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Fv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function qv(t,n,e){var r=gv.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Uv(t,n,e){var r=gv.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Iv(t,n,e){var r=yv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Ov(t,n,e){var r=gv.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function Bv(t,n,e){var r=gv.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Yv(t,n){return _v(t.getDate(),n,2)}function Lv(t,n){return _v(t.getHours(),n,2)}function jv(t,n){return _v(t.getHours()%12||12,n,2)}function Hv(t,n){return _v(1+py.count(tv(t),t),n,3)}function Xv(t,n){return _v(t.getMilliseconds(),n,3)}function Gv(t,n){return Xv(t,n)+"000"}function Vv(t,n){return _v(t.getMonth()+1,n,2)}function Wv(t,n){return _v(t.getMinutes(),n,2)}function Zv(t,n){return _v(t.getSeconds(),n,2)}function Kv(t){var n=t.getDay();return 0===n?7:n}function Qv(t,n){return _v(xy.count(tv(t)-1,t),n,2)}function Jv(t){var n=t.getDay();return n>=4||0===n?Ay(t):Ay.ceil(t)}function t_(t,n){return t=Jv(t),_v(Ay.count(tv(t),t)+(4===tv(t).getDay()),n,2)}function n_(t){return t.getDay()}function e_(t,n){return _v(wy.count(tv(t)-1,t),n,2)}function r_(t,n){return _v(t.getFullYear()%100,n,2)}function i_(t,n){return _v((t=Jv(t)).getFullYear()%100,n,2)}function o_(t,n){return _v(t.getFullYear()%1e4,n,4)}function a_(t,n){var e=t.getDay();return _v((t=e>=4||0===e?Ay(t):Ay.ceil(t)).getFullYear()%1e4,n,4)}function u_(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+_v(n/60|0,"0",2)+_v(n%60,"0",2)}function c_(t,n){return _v(t.getUTCDate(),n,2)}function f_(t,n){return _v(t.getUTCHours(),n,2)}function s_(t,n){return _v(t.getUTCHours()%12||12,n,2)}function l_(t,n){return _v(1+yy.count(ev(t),t),n,3)}function h_(t,n){return _v(t.getUTCMilliseconds(),n,3)}function d_(t,n){return h_(t,n)+"000"}function p_(t,n){return _v(t.getUTCMonth()+1,n,2)}function g_(t,n){return _v(t.getUTCMinutes(),n,2)}function y_(t,n){return _v(t.getUTCSeconds(),n,2)}function v_(t){var n=t.getUTCDay();return 0===n?7:n}function __(t,n){return _v(Fy.count(ev(t)-1,t),n,2)}function b_(t){var n=t.getUTCDay();return n>=4||0===n?Oy(t):Oy.ceil(t)}function m_(t,n){return t=b_(t),_v(Oy.count(ev(t),t)+(4===ev(t).getUTCDay()),n,2)}function x_(t){return t.getUTCDay()}function w_(t,n){return _v(qy.count(ev(t)-1,t),n,2)}function M_(t,n){return _v(t.getUTCFullYear()%100,n,2)}function T_(t,n){return _v((t=b_(t)).getUTCFullYear()%100,n,2)}function A_(t,n){return _v(t.getUTCFullYear()%1e4,n,4)}function S_(t,n){var e=t.getUTCDay();return _v((t=e>=4||0===e?Oy(t):Oy.ceil(t)).getUTCFullYear()%1e4,n,4)}function E_(){return"+0000"}function N_(){return"%"}function k_(t){return+t}function C_(t){return Math.floor(+t/1e3)}function P_(n){return dv=hv(n),t.timeFormat=dv.format,t.timeParse=dv.parse,t.utcFormat=dv.utcFormat,t.utcParse=dv.utcParse,dv}t.timeFormat=void 0,t.timeParse=void 0,t.utcFormat=void 0,t.utcParse=void 0,P_({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var z_="%Y-%m-%dT%H:%M:%S.%LZ";var $_=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat(z_),D_=$_;var R_=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse(z_),F_=R_;function q_(t){return new Date(t)}function U_(t){return t instanceof Date?+t:+new Date(+t)}function I_(t,n,e,r,i,o,a,u,c,f){var s=Sg(),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),g=f("%I:%M"),y=f("%I %p"),v=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y");function x(t){return(c(t)Fr(t[t.length-1]),rb=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(H_),ib=eb(rb),ob=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(H_),ab=eb(ob),ub=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(H_),cb=eb(ub),fb=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(H_),sb=eb(fb),lb=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(H_),hb=eb(lb),db=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(H_),pb=eb(db),gb=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(H_),yb=eb(gb),vb=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(H_),_b=eb(vb),bb=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(H_),mb=eb(bb),xb=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(H_),wb=eb(xb),Mb=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(H_),Tb=eb(Mb),Ab=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(H_),Sb=eb(Ab),Eb=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(H_),Nb=eb(Eb),kb=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(H_),Cb=eb(kb),Pb=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(H_),zb=eb(Pb),$b=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(H_),Db=eb($b),Rb=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(H_),Fb=eb(Rb),qb=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(H_),Ub=eb(qb),Ib=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(H_),Ob=eb(Ib),Bb=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(H_),Yb=eb(Bb),Lb=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(H_),jb=eb(Lb),Hb=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(H_),Xb=eb(Hb),Gb=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(H_),Vb=eb(Gb),Wb=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(H_),Zb=eb(Wb),Kb=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(H_),Qb=eb(Kb),Jb=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(H_),tm=eb(Jb),nm=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(H_),em=eb(nm);var rm=hi(Tr(300,.5,0),Tr(-240,.5,1)),im=hi(Tr(-100,.75,.35),Tr(80,1.5,.8)),om=hi(Tr(260,.75,.35),Tr(80,1.5,.8)),am=Tr();var um=Fe(),cm=Math.PI/3,fm=2*Math.PI/3;function sm(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var lm=sm(H_("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),hm=sm(H_("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),dm=sm(H_("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),pm=sm(H_("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function gm(t){return function(){return t}}const ym=Math.abs,vm=Math.atan2,_m=Math.cos,bm=Math.max,mm=Math.min,xm=Math.sin,wm=Math.sqrt,Mm=1e-12,Tm=Math.PI,Am=Tm/2,Sm=2*Tm;function Em(t){return t>=1?Am:t<=-1?-Am:Math.asin(t)}function Nm(t){let n=3;return t.digits=function(e){if(!arguments.length)return n;if(null==e)n=null;else{const t=Math.floor(e);if(!(t>=0))throw new RangeError(`invalid digits: ${e}`);n=t}return t},()=>new Ua(n)}function km(t){return t.innerRadius}function Cm(t){return t.outerRadius}function Pm(t){return t.startAngle}function zm(t){return t.endAngle}function $m(t){return t&&t.padAngle}function Dm(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/wm(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,g=r+l,y=(h+p)/2,v=(d+g)/2,_=p-h,b=g-d,m=_*_+b*b,x=i-o,w=h*g-p*d,M=(b<0?-1:1)*wm(bm(0,x*x*m-w*w)),T=(w*b-_*M)/m,A=(-w*_-b*M)/m,S=(w*b+_*M)/m,E=(-w*_+b*M)/m,N=T-y,k=A-v,C=S-y,P=E-v;return N*N+k*k>C*C+P*P&&(T=S,A=E),{cx:T,cy:A,x01:-s,y01:-l,x11:T*(i/x-1),y11:A*(i/x-1)}}var Rm=Array.prototype.slice;function Fm(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function qm(t){this._context=t}function Um(t){return new qm(t)}function Im(t){return t[0]}function Om(t){return t[1]}function Bm(t,n){var e=gm(!0),r=null,i=Um,o=null,a=Nm(u);function u(u){var c,f,s,l=(u=Fm(u)).length,h=!1;for(null==r&&(o=i(s=a())),c=0;c<=l;++c)!(c=l;--h)u.point(v[h],_[h]);u.lineEnd(),u.areaEnd()}y&&(v[s]=+t(d,s,f),_[s]=+n(d,s,f),u.point(r?+r(d,s,f):v[s],e?+e(d,s,f):_[s]))}if(p)return u=null,p+""||null}function s(){return Bm().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?Im:gm(+t),n="function"==typeof n?n:gm(void 0===n?0:+n),e="function"==typeof e?e:void 0===e?Om:gm(+e),f.x=function(n){return arguments.length?(t="function"==typeof n?n:gm(+n),r=null,f):t},f.x0=function(n){return arguments.length?(t="function"==typeof n?n:gm(+n),f):t},f.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:gm(+t),f):r},f.y=function(t){return arguments.length?(n="function"==typeof t?t:gm(+t),e=null,f):n},f.y0=function(t){return arguments.length?(n="function"==typeof t?t:gm(+t),f):n},f.y1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:gm(+t),f):e},f.lineX0=f.lineY0=function(){return s().x(t).y(n)},f.lineY1=function(){return s().x(t).y(e)},f.lineX1=function(){return s().x(r).y(n)},f.defined=function(t){return arguments.length?(i="function"==typeof t?t:gm(!!t),f):i},f.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),f):a},f.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),f):o},f}function Lm(t,n){return nt?1:n>=t?0:NaN}function jm(t){return t}qm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Hm=Gm(Um);function Xm(t){this._curve=t}function Gm(t){function n(n){return new Xm(t(n))}return n._curve=t,n}function Vm(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Gm(t)):n()._curve},t}function Wm(){return Vm(Bm().curve(Hm))}function Zm(){var t=Ym().curve(Hm),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Vm(e())},delete t.lineX0,t.lineEndAngle=function(){return Vm(r())},delete t.lineX1,t.lineInnerRadius=function(){return Vm(i())},delete t.lineY0,t.lineOuterRadius=function(){return Vm(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Gm(t)):n()._curve},t}function Km(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}Xm.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};class Qm{constructor(t,n){this._context=t,this._x=n}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,n,t,n):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+n)/2,t,this._y0,t,n)}this._x0=t,this._y0=n}}class Jm{constructor(t){this._context=t}lineStart(){this._point=0}lineEnd(){}point(t,n){if(t=+t,n=+n,0===this._point)this._point=1;else{const e=Km(this._x0,this._y0),r=Km(this._x0,this._y0=(this._y0+n)/2),i=Km(t,this._y0),o=Km(t,n);this._context.moveTo(...e),this._context.bezierCurveTo(...r,...i,...o)}this._x0=t,this._y0=n}}function tx(t){return new Qm(t,!0)}function nx(t){return new Qm(t,!1)}function ex(t){return new Jm(t)}function rx(t){return t.source}function ix(t){return t.target}function ox(t){let n=rx,e=ix,r=Im,i=Om,o=null,a=null,u=Nm(c);function c(){let c;const f=Rm.call(arguments),s=n.apply(this,f),l=e.apply(this,f);if(null==o&&(a=t(c=u())),a.lineStart(),f[0]=s,a.point(+r.apply(this,f),+i.apply(this,f)),f[0]=l,a.point(+r.apply(this,f),+i.apply(this,f)),a.lineEnd(),c)return a=null,c+""||null}return c.source=function(t){return arguments.length?(n=t,c):n},c.target=function(t){return arguments.length?(e=t,c):e},c.x=function(t){return arguments.length?(r="function"==typeof t?t:gm(+t),c):r},c.y=function(t){return arguments.length?(i="function"==typeof t?t:gm(+t),c):i},c.context=function(n){return arguments.length?(null==n?o=a=null:a=t(o=n),c):o},c}const ax=wm(3);var ux={draw(t,n){const e=.59436*wm(n+mm(n/28,.75)),r=e/2,i=r*ax;t.moveTo(0,e),t.lineTo(0,-e),t.moveTo(-i,-r),t.lineTo(i,r),t.moveTo(-i,r),t.lineTo(i,-r)}},cx={draw(t,n){const e=wm(n/Tm);t.moveTo(e,0),t.arc(0,0,e,0,Sm)}},fx={draw(t,n){const e=wm(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}};const sx=wm(1/3),lx=2*sx;var hx={draw(t,n){const e=wm(n/lx),r=e*sx;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},dx={draw(t,n){const e=.62625*wm(n);t.moveTo(0,-e),t.lineTo(e,0),t.lineTo(0,e),t.lineTo(-e,0),t.closePath()}},px={draw(t,n){const e=.87559*wm(n-mm(n/7,2));t.moveTo(-e,0),t.lineTo(e,0),t.moveTo(0,e),t.lineTo(0,-e)}},gx={draw(t,n){const e=wm(n),r=-e/2;t.rect(r,r,e,e)}},yx={draw(t,n){const e=.4431*wm(n);t.moveTo(e,e),t.lineTo(e,-e),t.lineTo(-e,-e),t.lineTo(-e,e),t.closePath()}};const vx=xm(Tm/10)/xm(7*Tm/10),_x=xm(Sm/10)*vx,bx=-_m(Sm/10)*vx;var mx={draw(t,n){const e=wm(.8908130915292852*n),r=_x*e,i=bx*e;t.moveTo(0,-e),t.lineTo(r,i);for(let n=1;n<5;++n){const o=Sm*n/5,a=_m(o),u=xm(o);t.lineTo(u*e,-a*e),t.lineTo(a*r-u*i,u*r+a*i)}t.closePath()}};const xx=wm(3);var wx={draw(t,n){const e=-wm(n/(3*xx));t.moveTo(0,2*e),t.lineTo(-xx*e,-e),t.lineTo(xx*e,-e),t.closePath()}};const Mx=wm(3);var Tx={draw(t,n){const e=.6824*wm(n),r=e/2,i=e*Mx/2;t.moveTo(0,-e),t.lineTo(i,r),t.lineTo(-i,r),t.closePath()}};const Ax=-.5,Sx=wm(3)/2,Ex=1/wm(12),Nx=3*(Ex/2+1);var kx={draw(t,n){const e=wm(n/Nx),r=e/2,i=e*Ex,o=r,a=e*Ex+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(Ax*r-Sx*i,Sx*r+Ax*i),t.lineTo(Ax*o-Sx*a,Sx*o+Ax*a),t.lineTo(Ax*u-Sx*c,Sx*u+Ax*c),t.lineTo(Ax*r+Sx*i,Ax*i-Sx*r),t.lineTo(Ax*o+Sx*a,Ax*a-Sx*o),t.lineTo(Ax*u+Sx*c,Ax*c-Sx*u),t.closePath()}},Cx={draw(t,n){const e=.6189*wm(n-mm(n/6,1.7));t.moveTo(-e,-e),t.lineTo(e,e),t.moveTo(-e,e),t.lineTo(e,-e)}};const Px=[cx,fx,hx,gx,mx,wx,kx],zx=[cx,px,Cx,Tx,ux,yx,dx];function $x(){}function Dx(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Rx(t){this._context=t}function Fx(t){this._context=t}function qx(t){this._context=t}function Ux(t,n){this._basis=new Rx(t),this._beta=n}Rx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Dx(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Dx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Fx.prototype={areaStart:$x,areaEnd:$x,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Dx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},qx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Dx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ux.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Ix=function t(n){function e(t){return 1===n?new Rx(t):new Ux(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function Ox(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Bx(t,n){this._context=t,this._k=(1-n)/6}Bx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Ox(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:Ox(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Yx=function t(n){function e(t){return new Bx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Lx(t,n){this._context=t,this._k=(1-n)/6}Lx.prototype={areaStart:$x,areaEnd:$x,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Ox(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var jx=function t(n){function e(t){return new Lx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Hx(t,n){this._context=t,this._k=(1-n)/6}Hx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Ox(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Xx=function t(n){function e(t){return new Hx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Gx(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>Mm){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>Mm){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Vx(t,n){this._context=t,this._alpha=n}Vx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Gx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Wx=function t(n){function e(t){return n?new Vx(t,n):new Bx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Zx(t,n){this._context=t,this._alpha=n}Zx.prototype={areaStart:$x,areaEnd:$x,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Gx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Kx=function t(n){function e(t){return n?new Zx(t,n):new Lx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Qx(t,n){this._context=t,this._alpha=n}Qx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Gx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Jx=function t(n){function e(t){return n?new Qx(t,n):new Hx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function tw(t){this._context=t}function nw(t){return t<0?-1:1}function ew(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(nw(o)+nw(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function rw(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function iw(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function ow(t){this._context=t}function aw(t){this._context=new uw(t)}function uw(t){this._context=t}function cw(t){this._context=t}function fw(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o=0;)e[n]=n;return e}function dw(t,n){return t[n]}function pw(t){const n=[];return n.key=t,n}function gw(t){var n=t.map(yw);return hw(t).sort((function(t,e){return n[t]-n[e]}))}function yw(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++eo&&(o=n,r=e);return r}function vw(t){var n=t.map(_w);return hw(t).sort((function(t,e){return n[t]-n[e]}))}function _w(t){for(var n,e=0,r=-1,i=t.length;++r=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var bw=t=>()=>t;function mw(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function xw(t,n,e){this.k=t,this.x=n,this.y=e}xw.prototype={constructor:xw,scale:function(t){return 1===t?this:new xw(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new xw(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var ww=new xw(1,0,0);function Mw(t){for(;!t.__zoom;)if(!(t=t.parentNode))return ww;return t.__zoom}function Tw(t){t.stopImmediatePropagation()}function Aw(t){t.preventDefault(),t.stopImmediatePropagation()}function Sw(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function Ew(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function Nw(){return this.__zoom||ww}function kw(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Cw(){return navigator.maxTouchPoints||"ontouchstart"in this}function Pw(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Mw.prototype=xw.prototype,t.Adder=T,t.Delaunay=Lu,t.FormatSpecifier=tf,t.InternMap=InternMap,t.InternSet=InternSet,t.Node=Qd,t.Path=Ua,t.Voronoi=qu,t.ZoomTransform=xw,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>qi&&e.name===n)return new po([[t]],Zo,n,+r);return null},t.arc=function(){var t=km,n=Cm,e=gm(0),r=null,i=Pm,o=zm,a=$m,u=null,c=Nm(f);function f(){var f,s,l=+t.apply(this,arguments),h=+n.apply(this,arguments),d=i.apply(this,arguments)-Am,p=o.apply(this,arguments)-Am,g=ym(p-d),y=p>d;if(u||(u=f=c()),hMm)if(g>Sm-Mm)u.moveTo(h*_m(d),h*xm(d)),u.arc(0,0,h,d,p,!y),l>Mm&&(u.moveTo(l*_m(p),l*xm(p)),u.arc(0,0,l,p,d,y));else{var v,_,b=d,m=p,x=d,w=p,M=g,T=g,A=a.apply(this,arguments)/2,S=A>Mm&&(r?+r.apply(this,arguments):wm(l*l+h*h)),E=mm(ym(h-l)/2,+e.apply(this,arguments)),N=E,k=E;if(S>Mm){var C=Em(S/l*xm(A)),P=Em(S/h*xm(A));(M-=2*C)>Mm?(x+=C*=y?1:-1,w-=C):(M=0,x=w=(d+p)/2),(T-=2*P)>Mm?(b+=P*=y?1:-1,m-=P):(T=0,b=m=(d+p)/2)}var z=h*_m(b),$=h*xm(b),D=l*_m(w),R=l*xm(w);if(E>Mm){var F,q=h*_m(m),U=h*xm(m),I=l*_m(x),O=l*xm(x);if(g1?0:t<-1?Tm:Math.acos(t)}((B*L+Y*j)/(wm(B*B+Y*Y)*wm(L*L+j*j)))/2),X=wm(F[0]*F[0]+F[1]*F[1]);N=mm(E,(l-X)/(H-1)),k=mm(E,(h-X)/(H+1))}else N=k=0}T>Mm?k>Mm?(v=Dm(I,O,z,$,h,k,y),_=Dm(q,U,D,R,h,k,y),u.moveTo(v.cx+v.x01,v.cy+v.y01),kMm&&M>Mm?N>Mm?(v=Dm(D,R,q,U,l,-N,y),_=Dm(z,$,I,O,l,-N,y),u.lineTo(v.cx+v.x01,v.cy+v.y01),N=0))throw new RangeError("invalid r");let e=t.length;if(!((e=Math.floor(e))>=0))throw new RangeError("invalid length");if(!e||!n)return t;const r=y(n),i=t.slice();return r(t,i,0,e,1),r(i,t,0,e,1),r(t,i,0,e,1),t},t.blur2=l,t.blurImage=h,t.brush=function(){return wa(la)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return wa(fa)},t.brushY=function(){return wa(sa)},t.buffer=function(t,n){return fetch(t,n).then(_c)},t.chord=function(){return za(!1,!1)},t.chordDirected=function(){return za(!0,!1)},t.chordTranspose=function(){return za(!1,!0)},t.cluster=function(){var t=Ld,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter((function(n){var e=n.children;e?(n.x=function(t){return t.reduce(jd,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Hd,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)}));var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=ze,t.contourDensity=function(){var t=fu,n=su,e=lu,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=Qa(20);function h(r){var i=new Float32Array(c*f),s=Math.pow(2,-a),h=-1;for(const o of r){var d=(t(o,++h,r)+u)*s,p=(n(o,h,r)+u)*s,g=+e(o,h,r);if(g&&d>=0&&d=0&&pt*r)))(n).map(((t,n)=>(t.value=+e[n],p(t))))}function p(t){return t.coordinates.forEach(g),t}function g(t){t.forEach(y)}function y(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function _(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,d}return d.contours=function(t){var n=h(t),e=iu().size([c,f]),r=Math.pow(2,2*a),i=t=>{t=+t;var i=p(e.contour(n,t*r));return i.value=t,i};return Object.defineProperty(i,"max",{get:()=>J(n)/r}),i},d.x=function(n){return arguments.length?(t="function"==typeof n?n:Qa(+n),d):t},d.y=function(t){return arguments.length?(n="function"==typeof t?t:Qa(+t),d):n},d.weight=function(t){return arguments.length?(e="function"==typeof t?t:Qa(+t),d):e},d.size=function(t){if(!arguments.length)return[r,i];var n=+t[0],e=+t[1];if(!(n>=0&&e>=0))throw new Error("invalid size");return r=n,i=e,_()},d.cellSize=function(t){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),_()},d.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?Qa(Za.call(t)):Qa(t),d):s},d.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=(Math.sqrt(4*t*t+1)-1)/2,_()},d},t.contours=iu,t.count=v,t.create=function(t){return Zn(Yt(t).call(document.documentElement))},t.creator=Yt,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),e=(t=t.map(m)).map(_),r=t.length-1,i=new Array(r+1).fill(0),o=[];if(r<0||e.some(b))return o;for(;;){o.push(i.map(((n,e)=>t[e][n])));let a=r;for(;++i[a]===e[a];){if(0===a)return n?o.map(n):o;i[a--]=0}}},t.csv=wc,t.csvFormat=rc,t.csvFormatBody=ic,t.csvFormatRow=ac,t.csvFormatRows=oc,t.csvFormatValue=uc,t.csvParse=nc,t.csvParseRows=ec,t.cubehelix=Tr,t.cumsum=function(t,n){var e=0,r=0;return Float64Array.from(t,void 0===n?t=>e+=+t||0:i=>e+=+n(i,r++,t)||0)},t.curveBasis=function(t){return new Rx(t)},t.curveBasisClosed=function(t){return new Fx(t)},t.curveBasisOpen=function(t){return new qx(t)},t.curveBumpX=tx,t.curveBumpY=nx,t.curveBundle=Ix,t.curveCardinal=Yx,t.curveCardinalClosed=jx,t.curveCardinalOpen=Xx,t.curveCatmullRom=Wx,t.curveCatmullRomClosed=Kx,t.curveCatmullRomOpen=Jx,t.curveLinear=Um,t.curveLinearClosed=function(t){return new tw(t)},t.curveMonotoneX=function(t){return new ow(t)},t.curveMonotoneY=function(t){return new aw(t)},t.curveNatural=function(t){return new cw(t)},t.curveStep=function(t){return new sw(t,.5)},t.curveStepAfter=function(t){return new sw(t,1)},t.curveStepBefore=function(t){return new sw(t,0)},t.descending=e,t.deviation=w,t.difference=function(t,...n){t=new InternSet(t);for(const e of n)for(const n of e)t.delete(n);return t},t.disjoint=function(t,n){const e=n[Symbol.iterator](),r=new InternSet;for(const n of t){if(r.has(n))return!1;let t,i;for(;({value:t,done:i}=e.next())&&!i;){if(Object.is(n,t))return!1;r.add(t)}}return!0},t.dispatch=$t,t.drag=function(){var t,n,e,r,i=se,o=le,a=he,u=de,c={},f=$t("start","drag","end"),s=0,l=0;function h(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v,ee).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var c=b(this,o.call(this,a,u),a,u,"mouse");c&&(Zn(a.view).on("mousemove.drag",p,re).on("mouseup.drag",g,re),ae(a.view),ie(a),e=!1,t=a.clientX,n=a.clientY,c("start",a))}}function p(r){if(oe(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>l}c.mouse("drag",r)}function g(t){Zn(t.view).on("mousemove.drag mouseup.drag",null),ue(t.view,e),oe(t),c.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),c=a.length;for(e=0;e+t,t.easePoly=wo,t.easePolyIn=mo,t.easePolyInOut=wo,t.easePolyOut=xo,t.easeQuad=_o,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=_o,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=Ao,t.easeSinIn=function(t){return 1==+t?1:1-Math.cos(t*To)},t.easeSinInOut=Ao,t.easeSinOut=function(t){return Math.sin(t*To)},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(!n(r,++e,t))return!1;return!0},t.extent=M,t.fcumsum=function(t,n){const e=new T;let r=-1;return Float64Array.from(t,void 0===n?t=>e.add(+t||0):i=>e.add(+n(i,++r,t)||0))},t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const e=[];let r=-1;for(const i of t)n(i,++r,t)&&e.push(i);return e},t.flatGroup=function(t,...n){return z(P(t,...n),n)},t.flatRollup=function(t,n,...e){return z(D(t,n,...e),e)},t.forceCenter=function(t,n){var e,r=1;function i(){var i,o,a=e.length,u=0,c=0;for(i=0;if+p||os+p||ac.index){var g=f-u.x-u.vx,y=s-u.y-u.vy,v=g*g+y*y;vt.r&&(t.r=t[n].r)}function c(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r[u(t,n,r),t])));for(a=0,i=new Array(f);a=u)){(t.data!==n||t.next)&&(0===l&&(p+=(l=Uc(e))*l),0===h&&(p+=(h=Uc(e))*h),p(t=(Lc*t+jc)%Hc)/Hc}();function l(){h(),f.call("tick",n),e1?(null==e?u.delete(t):u.set(t,p(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=qc(.1);function o(t){for(var i,o=0,a=n.length;o=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++ejs(r[0],r[1])&&(r[1]=i[1]),js(i[0],r[1])>js(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=js(r[1],i[0]))>a&&(a=u,Wf=i[0],Kf=r[1])}return is=os=null,Wf===1/0||Zf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Wf,Zf],[Kf,Qf]]},t.geoCentroid=function(t){ms=xs=ws=Ms=Ts=As=Ss=Es=0,Ns=new T,ks=new T,Cs=new T,Lf(t,Gs);var n=+Ns,e=+ks,r=+Cs,i=Ef(n,e,r);return i=0))throw new RangeError(`invalid digits: ${t}`);i=n}return null===n&&(r=new ed(i)),a},a.projection(t).digits(i).context(n)},t.geoProjection=yd,t.geoProjectionMutator=vd,t.geoRotation=ll,t.geoStereographic=function(){return yd(Bd).scale(250).clipAngle(142)},t.geoStereographicRaw=Bd,t.geoStream=Lf,t.geoTransform=function(t){return{stream:id(t)}},t.geoTransverseMercator=function(){var t=Ed(Yd),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Yd,t.gray=function(t,n){return new ur(t,0,0,null==n?1:n)},t.greatest=ot,t.greatestIndex=function(t,e=n){if(1===e.length)return tt(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)>0)&&(r=n,i=o);return i},t.group=C,t.groupSort=function(t,e,r){return(2!==e.length?U($(t,e,r),(([t,e],[r,i])=>n(e,i)||n(t,r))):U(C(t,r),(([t,r],[i,o])=>e(r,o)||n(t,i)))).map((([t])=>t))},t.groups=P,t.hcl=dr,t.hierarchy=Gd,t.histogram=Q,t.hsl=He,t.html=Ec,t.image=function(t,n){return new Promise((function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t}))},t.index=function(t,...n){return F(t,k,R,n)},t.indexes=function(t,...n){return F(t,Array.from,R,n)},t.interpolate=Gr,t.interpolateArray=function(t,n){return(Ir(n)?Ur:Or)(t,n)},t.interpolateBasis=Er,t.interpolateBasisClosed=Nr,t.interpolateBlues=Xb,t.interpolateBrBG=ib,t.interpolateBuGn=wb,t.interpolateBuPu=Tb,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=om,t.interpolateCubehelix=li,t.interpolateCubehelixDefault=rm,t.interpolateCubehelixLong=hi,t.interpolateDate=Br,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Sb,t.interpolateGreens=Vb,t.interpolateGreys=Zb,t.interpolateHcl=ci,t.interpolateHclLong=fi,t.interpolateHsl=oi,t.interpolateHslLong=ai,t.interpolateHue=function(t,n){var e=Pr(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=dm,t.interpolateLab=function(t,n){var e=$r((t=ar(t)).l,(n=ar(n)).l),r=$r(t.a,n.a),i=$r(t.b,n.b),o=$r(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=hm,t.interpolateNumber=Yr,t.interpolateNumberArray=Ur,t.interpolateObject=Lr,t.interpolateOrRd=Nb,t.interpolateOranges=em,t.interpolatePRGn=ab,t.interpolatePiYG=cb,t.interpolatePlasma=pm,t.interpolatePuBu=zb,t.interpolatePuBuGn=Cb,t.interpolatePuOr=sb,t.interpolatePuRd=Db,t.interpolatePurples=Qb,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return am.h=360*t-100,am.s=1.5-1.5*n,am.l=.8-.9*n,am+""},t.interpolateRdBu=hb,t.interpolateRdGy=pb,t.interpolateRdPu=Fb,t.interpolateRdYlBu=yb,t.interpolateRdYlGn=_b,t.interpolateReds=tm,t.interpolateRgb=Dr,t.interpolateRgbBasis=Fr,t.interpolateRgbBasisClosed=qr,t.interpolateRound=Vr,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,um.r=255*(n=Math.sin(t))*n,um.g=255*(n=Math.sin(t+cm))*n,um.b=255*(n=Math.sin(t+fm))*n,um+""},t.interpolateSpectral=mb,t.interpolateString=Xr,t.interpolateTransformCss=ti,t.interpolateTransformSvg=ni,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=lm,t.interpolateWarm=im,t.interpolateYlGn=Ob,t.interpolateYlGnBu=Ub,t.interpolateYlOrBr=Yb,t.interpolateYlOrRd=jb,t.interpolateZoom=ri,t.interrupt=Gi,t.intersection=function(t,...n){t=new InternSet(t),n=n.map(vt);t:for(const e of t)for(const r of n)if(!r.has(e)){t.delete(e);continue t}return t},t.interval=function(t,n,e){var r=new Ei,i=n;return null==n?(r.restart(t,n,e),r):(r._restart=r.restart,r.restart=function(t,n,e){n=+n,e=null==e?Ai():+e,r._restart((function o(a){a+=i,r._restart(o,i+=n,e),t(a)}),n,e)},r.restart(t,n,e),r)},t.isoFormat=D_,t.isoParse=F_,t.json=function(t,n){return fetch(t,n).then(Tc)},t.lab=ar,t.lch=function(t,n,e,r){return 1===arguments.length?hr(t):new pr(e,n,t,null==r?1:r)},t.least=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)<0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)<0:0===e(n,n))&&(r=n,i=!0);return r},t.leastIndex=ht,t.line=Bm,t.lineRadial=Wm,t.link=ox,t.linkHorizontal=function(){return ox(tx)},t.linkRadial=function(){const t=ox(ex);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return ox(nx)},t.local=Qn,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,((e,r)=>n(e,r,t)))},t.matcher=Vt,t.max=J,t.maxIndex=tt,t.mean=function(t,n){let e=0,r=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++e,r+=n);else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(o=+o)>=o&&(++e,r+=o)}if(e)return r/e},t.median=function(t,n){return at(t,.5,n)},t.medianIndex=function(t,n){return ct(t,.5,n)},t.merge=ft,t.min=nt,t.minIndex=et,t.mode=function(t,n){const e=new InternMap;if(void 0===n)for(let n of t)null!=n&&n>=n&&e.set(n,(e.get(n)||0)+1);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&i>=i&&e.set(i,(e.get(i)||0)+1)}let r,i=0;for(const[t,n]of e)n>i&&(i=n,r=t);return r},t.namespace=It,t.namespaces=Ut,t.nice=Z,t.now=Ai,t.pack=function(){var t=null,n=1,e=1,r=np;function i(i){const o=ap();return i.x=n/2,i.y=e/2,t?i.eachBefore(xp(t)).eachAfter(wp(r,.5,o)).eachBefore(Mp(1)):i.eachBefore(xp(mp)).eachAfter(wp(np,1,o)).eachAfter(wp(r,i.r/Math.min(n,e),o)).eachBefore(Mp(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=Jd(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:ep(+t),i):r},i},t.packEnclose=function(t){return up(t,ap())},t.packSiblings=function(t){return bp(t,ap()),t},t.pairs=function(t,n=st){const e=[];let r,i=!1;for(const o of t)i&&e.push(n(r,o)),r=o,i=!0;return e},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Ap(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a0&&(d+=l);for(null!=n?p.sort((function(t,e){return n(g[t],g[e])})):null!=e&&p.sort((function(t,n){return e(a[t],a[n])})),u=0,f=d?(v-h*b)/d:0;u0?l*f:0)+b,g[c]={data:a[c],index:u,value:l,startAngle:y,endAngle:s,padAngle:_};return g}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:gm(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:gm(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:gm(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:gm(+t),a):o},a},t.piecewise=di,t.pointRadial=Km,t.pointer=ne,t.pointers=function(t,n){return t.target&&(t=te(t),void 0===n&&(n=t.currentTarget),t=t.touches||[t]),Array.from(t,(t=>ne(t,n)))},t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++eu!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n(n=1664525*n+1013904223|0,lg*(n>>>0))},t.randomLogNormal=Kp,t.randomLogistic=fg,t.randomNormal=Zp,t.randomPareto=ng,t.randomPoisson=sg,t.randomUniform=Vp,t.randomWeibull=ug,t.range=lt,t.rank=function(t,e=n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");let r=Array.from(t);const i=new Float64Array(r.length);2!==e.length&&(r=r.map(e),e=n);const o=(t,n)=>e(r[t],r[n]);let a,u;return(t=Uint32Array.from(r,((t,n)=>n))).sort(e===n?(t,n)=>O(r[t],r[n]):I(o)),t.forEach(((t,n)=>{const e=o(t,void 0===a?t:a);e>=0?((void 0===a||e>0)&&(a=t,u=n),i[t]=u):i[t]=NaN})),i},t.reduce=function(t,n,e){if("function"!=typeof n)throw new TypeError("reducer is not a function");const r=t[Symbol.iterator]();let i,o,a=-1;if(arguments.length<3){if(({done:i,value:e}=r.next()),i)return;++a}for(;({done:i,value:o}=r.next()),!i;)e=n(e,o,++a,t);return e},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rgb=Fe,t.ribbon=function(){return Wa()},t.ribbonArrow=function(){return Wa(Va)},t.rollup=$,t.rollups=D,t.scaleBand=yg,t.scaleDiverging=function t(){var n=Ng(L_()(mg));return n.copy=function(){return B_(n,t())},dg.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=Fg(L_()).domain([.1,1,10]);return n.copy=function(){return B_(n,t()).base(n.base())},dg.apply(n,arguments)},t.scaleDivergingPow=j_,t.scaleDivergingSqrt=function(){return j_.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=Ig(L_());return n.copy=function(){return B_(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return null==t||isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Array.from(t,_g),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Array.from(n,_g):[0,1],Ng(r)},t.scaleImplicit=pg,t.scaleLinear=function t(){var n=Sg();return n.copy=function(){return Tg(n,t())},hg.apply(n,arguments),Ng(n)},t.scaleLog=function t(){const n=Fg(Ag()).domain([1,10]);return n.copy=()=>Tg(n,t()).base(n.base()),hg.apply(n,arguments),n},t.scaleOrdinal=gg,t.scalePoint=function(){return vg(yg.apply(null,arguments).paddingInner(1))},t.scalePow=jg,t.scaleQuantile=function t(){var e,r=[],i=[],o=[];function a(){var t=0,n=Math.max(1,i.length);for(o=new Array(n-1);++t0?o[n-1]:r[0],n=i?[o[i-1],r]:[o[n-1],o[n]]},u.unknown=function(t){return arguments.length?(n=t,u):u},u.thresholds=function(){return o.slice()},u.copy=function(){return t().domain([e,r]).range(a).unknown(n)},hg.apply(Ng(u),arguments)},t.scaleRadial=function t(){var n,e=Sg(),r=[0,1],i=!1;function o(t){var r=function(t){return Math.sign(t)*Math.sqrt(Math.abs(t))}(e(t));return isNaN(r)?n:i?Math.round(r):r}return o.invert=function(t){return e.invert(Hg(t))},o.domain=function(t){return arguments.length?(e.domain(t),o):e.domain()},o.range=function(t){return arguments.length?(e.range((r=Array.from(t,_g)).map(Hg)),o):r.slice()},o.rangeRound=function(t){return o.range(t).round(!0)},o.round=function(t){return arguments.length?(i=!!t,o):i},o.clamp=function(t){return arguments.length?(e.clamp(t),o):e.clamp()},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t(e.domain(),r).round(i).clamp(e.clamp()).unknown(n)},hg.apply(o,arguments),Ng(o)},t.scaleSequential=function t(){var n=Ng(O_()(mg));return n.copy=function(){return B_(n,t())},dg.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=Fg(O_()).domain([1,10]);return n.copy=function(){return B_(n,t()).base(n.base())},dg.apply(n,arguments)},t.scaleSequentialPow=Y_,t.scaleSequentialQuantile=function t(){var e=[],r=mg;function i(t){if(null!=t&&!isNaN(t=+t))return r((s(e,t,1)-1)/(e.length-1))}return i.domain=function(t){if(!arguments.length)return e.slice();e=[];for(let n of t)null==n||isNaN(n=+n)||e.push(n);return e.sort(n),i},i.interpolator=function(t){return arguments.length?(r=t,i):r},i.range=function(){return e.map(((t,n)=>r(n/(e.length-1))))},i.quantiles=function(t){return Array.from({length:t+1},((n,r)=>at(e,r/t)))},i.copy=function(){return t(r).domain(e)},dg.apply(i,arguments)},t.scaleSequentialSqrt=function(){return Y_.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=Ig(O_());return n.copy=function(){return B_(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleSqrt=function(){return jg.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=Ig(Ag());return n.copy=function(){return Tg(n,t()).constant(n.constant())},hg.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],i=1;function o(t){return null!=t&&t<=t?r[s(e,t,0,i)]:n}return o.domain=function(t){return arguments.length?(e=Array.from(t),i=Math.min(e.length,r.length-1),o):e.slice()},o.range=function(t){return arguments.length?(r=Array.from(t),i=Math.min(e.length,r.length-1),o):r.slice()},o.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t().domain(e).range(r).unknown(n)},hg.apply(o,arguments)},t.scaleTime=function(){return hg.apply(I_(uv,cv,tv,Zy,xy,py,sy,ay,iy,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return hg.apply(I_(ov,av,ev,Qy,Fy,yy,hy,cy,iy,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,n){const e=ht(t,n);return e<0?void 0:e},t.schemeAccent=G_,t.schemeBlues=Hb,t.schemeBrBG=rb,t.schemeBuGn=xb,t.schemeBuPu=Mb,t.schemeCategory10=X_,t.schemeDark2=V_,t.schemeGnBu=Ab,t.schemeGreens=Gb,t.schemeGreys=Wb,t.schemeOrRd=Eb,t.schemeOranges=nm,t.schemePRGn=ob,t.schemePaired=W_,t.schemePastel1=Z_,t.schemePastel2=K_,t.schemePiYG=ub,t.schemePuBu=Pb,t.schemePuBuGn=kb,t.schemePuOr=fb,t.schemePuRd=$b,t.schemePurples=Kb,t.schemeRdBu=lb,t.schemeRdGy=db,t.schemeRdPu=Rb,t.schemeRdYlBu=gb,t.schemeRdYlGn=vb,t.schemeReds=Jb,t.schemeSet1=Q_,t.schemeSet2=J_,t.schemeSet3=tb,t.schemeSpectral=bb,t.schemeTableau10=nb,t.schemeYlGn=Ib,t.schemeYlGnBu=qb,t.schemeYlOrBr=Bb,t.schemeYlOrRd=Lb,t.select=Zn,t.selectAll=function(t){return"string"==typeof t?new Vn([document.querySelectorAll(t)],[document.documentElement]):new Vn([Ht(t)],Gn)},t.selection=Wn,t.selector=jt,t.selectorAll=Gt,t.shuffle=dt,t.shuffler=pt,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(n(r,++e,t))return!0;return!1},t.sort=U,t.stack=function(){var t=gm([]),n=hw,e=lw,r=dw;function i(i){var o,a,u=Array.from(t.apply(this,arguments),pw),c=u.length,f=-1;for(const t of i)for(o=0,++f;o0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o0){for(var e,r=0,i=t[n[0]],o=i.length;r0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;afunction(t){t=`${t}`;let n=t.length;zp(t,n-1)&&!zp(t,n-2)&&(t=t.slice(0,-1));return"/"===t[0]?t:`/${t}`}(t(n,e,r)))),e=n.map(Pp),i=new Set(n).add("");for(const t of e)i.has(t)||(i.add(t),n.push(t),e.push(Pp(t)),h.push(Np));d=(t,e)=>n[e],p=(t,n)=>e[n]}for(a=0,i=h.length;a=0&&(f=h[t]).data===Np;--t)f.data=null}if(u.parent=Sp,u.eachBefore((function(t){t.depth=t.parent.depth+1,--i})).eachBefore(Kd),u.parent=null,i>0)throw new Error("cycle");return u}return r.id=function(t){return arguments.length?(n=Jd(t),r):n},r.parentId=function(t){return arguments.length?(e=Jd(t),r):e},r.path=function(n){return arguments.length?(t=Jd(n),r):t},r},t.style=_n,t.subset=function(t,n){return _t(n,t)},t.sum=function(t,n){let e=0;if(void 0===n)for(let n of t)(n=+n)&&(e+=n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&(e+=i)}return e},t.superset=_t,t.svg=Nc,t.symbol=function(t,n){let e=null,r=Nm(i);function i(){let i;if(e||(e=i=r()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),i)return e=null,i+""||null}return t="function"==typeof t?t:gm(t||cx),n="function"==typeof n?n:gm(void 0===n?64:+n),i.type=function(n){return arguments.length?(t="function"==typeof n?n:gm(n),i):t},i.size=function(t){return arguments.length?(n="function"==typeof t?t:gm(+t),i):n},i.context=function(t){return arguments.length?(e=null==t?null:t,i):e},i},t.symbolAsterisk=ux,t.symbolCircle=cx,t.symbolCross=fx,t.symbolDiamond=hx,t.symbolDiamond2=dx,t.symbolPlus=px,t.symbolSquare=gx,t.symbolSquare2=yx,t.symbolStar=mx,t.symbolTimes=Cx,t.symbolTriangle=wx,t.symbolTriangle2=Tx,t.symbolWye=kx,t.symbolX=Cx,t.symbols=Px,t.symbolsFill=Px,t.symbolsStroke=zx,t.text=mc,t.thresholdFreedmanDiaconis=function(t,n,e){const r=v(t),i=at(t,.75)-at(t,.25);return r&&i?Math.ceil((e-n)/(2*i*Math.pow(r,-1/3))):1},t.thresholdScott=function(t,n,e){const r=v(t),i=w(t);return r&&i?Math.ceil((e-n)*Math.cbrt(r)/(3.49*i)):1},t.thresholdSturges=K,t.tickFormat=Eg,t.tickIncrement=V,t.tickStep=W,t.ticks=G,t.timeDay=py,t.timeDays=gy,t.timeFormatDefaultLocale=P_,t.timeFormatLocale=hv,t.timeFriday=Sy,t.timeFridays=$y,t.timeHour=sy,t.timeHours=ly,t.timeInterval=Vg,t.timeMillisecond=Wg,t.timeMilliseconds=Zg,t.timeMinute=ay,t.timeMinutes=uy,t.timeMonday=wy,t.timeMondays=ky,t.timeMonth=Zy,t.timeMonths=Ky,t.timeSaturday=Ey,t.timeSaturdays=Dy,t.timeSecond=iy,t.timeSeconds=oy,t.timeSunday=xy,t.timeSundays=Ny,t.timeThursday=Ay,t.timeThursdays=zy,t.timeTickInterval=cv,t.timeTicks=uv,t.timeTuesday=My,t.timeTuesdays=Cy,t.timeWednesday=Ty,t.timeWednesdays=Py,t.timeWeek=xy,t.timeWeeks=Ny,t.timeYear=tv,t.timeYears=nv,t.timeout=$i,t.timer=Ni,t.timerFlush=ki,t.transition=go,t.transpose=gt,t.tree=function(){var t=$p,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new Up(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new Up(r[i],i)),e.parent=n;return(a.parent=new Up(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore((function(t){t.xs.x&&(s=t),t.depth>l.depth&&(l=t)}));var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),g=e/(l.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=Rp(u),o=Dp(o),u&&o;)c=Dp(c),(a=Rp(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(Fp(qp(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!Rp(a)&&(a.t=u,a.m+=l-s),o&&!Dp(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Yp,n=!1,e=1,r=1,i=[0],o=np,a=np,u=np,c=np,f=np;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Tp),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}var l=f[n],h=r/2+l,d=n+1,p=e-1;for(;d>>1;f[g]c-o){var _=r?(i*v+a*y)/r:a;t(n,d,y,i,o,_,c),t(d,e,v,_,o,a,c)}else{var b=r?(o*v+c*y)/r:c;t(n,d,y,i,o,a,b),t(d,e,v,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=Ap,t.treemapResquarify=Lp,t.treemapSlice=Ip,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Ip:Ap)(t,n,e,r,i)},t.treemapSquarify=Yp,t.tsv=Mc,t.tsvFormat=lc,t.tsvFormatBody=hc,t.tsvFormatRow=pc,t.tsvFormatRows=dc,t.tsvFormatValue=gc,t.tsvParse=fc,t.tsvParseRows=sc,t.union=function(...t){const n=new InternSet;for(const e of t)for(const t of e)n.add(t);return n},t.unixDay=_y,t.unixDays=by,t.utcDay=yy,t.utcDays=vy,t.utcFriday=By,t.utcFridays=Vy,t.utcHour=hy,t.utcHours=dy,t.utcMillisecond=Wg,t.utcMilliseconds=Zg,t.utcMinute=cy,t.utcMinutes=fy,t.utcMonday=qy,t.utcMondays=jy,t.utcMonth=Qy,t.utcMonths=Jy,t.utcSaturday=Yy,t.utcSaturdays=Wy,t.utcSecond=iy,t.utcSeconds=oy,t.utcSunday=Fy,t.utcSundays=Ly,t.utcThursday=Oy,t.utcThursdays=Gy,t.utcTickInterval=av,t.utcTicks=ov,t.utcTuesday=Uy,t.utcTuesdays=Hy,t.utcWednesday=Iy,t.utcWednesdays=Xy,t.utcWeek=Fy,t.utcWeeks=Ly,t.utcYear=ev,t.utcYears=rv,t.variance=x,t.version="7.8.5",t.window=pn,t.xml=Sc,t.zip=function(){return gt(arguments)},t.zoom=function(){var t,n,e,r=Sw,i=Ew,o=Pw,a=kw,u=Cw,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=ri,h=$t("start","zoom","end"),d=500,p=150,g=0,y=10;function v(t){t.property("__zoom",Nw).on("wheel.zoom",T,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",S).filter(u).on("touchstart.zoom",E).on("touchmove.zoom",N).on("touchend.zoom touchcancel.zoom",k).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new xw(n,t.x,t.y)}function b(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new xw(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function x(t,n,e,r){t.on("start.zoom",(function(){w(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){w(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=w(t,o).event(r),u=i.apply(t,o),c=null==e?m(u):"function"==typeof e?e.apply(t,o):e,f=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),s=t.__zoom,h="function"==typeof n?n.apply(t,o):n,d=l(s.invert(c).concat(f/s.k),h.invert(c).concat(f/h.k));return function(t){if(1===t)t=h;else{var n=d(t),e=f/n[2];t=new xw(e,c[0]-n[0]*e,c[1]-n[1]*e)}a.zoom(null,t)}}))}function w(t,n,e){return!e&&t.__zooming||new M(t,n)}function M(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function T(t,...n){if(r.apply(this,arguments)){var e=w(this,n).event(t),i=this.__zoom,u=Math.max(c[0],Math.min(c[1],i.k*Math.pow(2,a.apply(this,arguments)))),s=ne(t);if(e.wheel)e.mouse[0][0]===s[0]&&e.mouse[0][1]===s[1]||(e.mouse[1]=i.invert(e.mouse[0]=s)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[s,i.invert(s)],Gi(this),e.start()}Aw(t),e.wheel=setTimeout((function(){e.wheel=null,e.end()}),p),e.zoom("mouse",o(b(_(i,u),e.mouse[0],e.mouse[1]),e.extent,f))}}function A(t,...n){if(!e&&r.apply(this,arguments)){var i=t.currentTarget,a=w(this,n,!0).event(t),u=Zn(t.view).on("mousemove.zoom",(function(t){if(Aw(t),!a.moved){var n=t.clientX-s,e=t.clientY-l;a.moved=n*n+e*e>g}a.event(t).zoom("mouse",o(b(a.that.__zoom,a.mouse[0]=ne(t,i),a.mouse[1]),a.extent,f))}),!0).on("mouseup.zoom",(function(t){u.on("mousemove.zoom mouseup.zoom",null),ue(t.view,a.moved),Aw(t),a.event(t).end()}),!0),c=ne(t,i),s=t.clientX,l=t.clientY;ae(t.view),Tw(t),a.mouse=[c,this.__zoom.invert(c)],Gi(this),a.start()}}function S(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=ne(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),c=e.k*(t.shiftKey?.5:2),l=o(b(_(e,c),a,u),i.apply(this,n),f);Aw(t),s>0?Zn(this).transition().duration(s).call(x,l,a,t):Zn(this).call(v.transform,l,a,t)}}function E(e,...i){if(r.apply(this,arguments)){var o,a,u,c,f=e.touches,s=f.length,l=w(this,i,e.changedTouches.length===s).event(e);for(Tw(e),a=0;a --help` for command-specific help.""" + + +# Constants for socket synchronization +_SYNC_TIMEOUT = 5.0 +_PROCESS_KILL_TIMEOUT = 2.0 +_READY_MESSAGE = b"ready" +_RECV_BUFFER_SIZE = 1024 + +# Format configuration +FORMAT_EXTENSIONS = { + "pstats": "pstats", + "collapsed": "txt", + "flamegraph": "html", + "gecko": "json", + "heatmap": "html", +} + +COLLECTOR_MAP = { + "pstats": PstatsCollector, + "collapsed": CollapsedStackCollector, + "flamegraph": FlamegraphCollector, + "gecko": GeckoCollector, + "heatmap": HeatmapCollector, +} + +def _setup_child_monitor(args, parent_pid): + from ._child_monitor import ChildProcessMonitor + + # Build CLI args for child profilers (excluding --subprocesses to avoid recursion) + child_cli_args = _build_child_profiler_args(args) + + # Build output pattern + output_pattern = _build_output_pattern(args) + + return ChildProcessMonitor( + pid=parent_pid, + cli_args=child_cli_args, + output_pattern=output_pattern, + ) + + +def _get_child_monitor_context(args, pid): + if getattr(args, 'subprocesses', False): + return _setup_child_monitor(args, pid) + return nullcontext() + + +def _build_child_profiler_args(args): + child_args = [] + + # Sampling options + child_args.extend(["-i", str(args.interval)]) + child_args.extend(["-d", str(args.duration)]) + + if args.all_threads: + child_args.append("-a") + if args.realtime_stats: + child_args.append("--realtime-stats") + if args.native: + child_args.append("--native") + if not args.gc: + child_args.append("--no-gc") + if args.opcodes: + child_args.append("--opcodes") + if args.async_aware: + child_args.append("--async-aware") + async_mode = getattr(args, 'async_mode', 'running') + if async_mode != "running": + child_args.extend(["--async-mode", async_mode]) + + # Mode options + mode = getattr(args, 'mode', 'wall') + if mode != "wall": + child_args.extend(["--mode", mode]) + + # Format options (skip pstats as it's the default) + if args.format != "pstats": + child_args.append(f"--{args.format}") + + return child_args + + +def _build_output_pattern(args): + """Build output filename pattern for child profilers. + + The pattern uses {pid} as a placeholder which will be replaced with the + actual child PID using str.replace(), so user filenames with braces are safe. + """ + if args.outfile: + # User specified output - add PID to filename + base, ext = os.path.splitext(args.outfile) + if ext: + return f"{base}_{{pid}}{ext}" + else: + return f"{args.outfile}_{{pid}}" + else: + # Use default pattern based on format (consistent _ separator) + extension = FORMAT_EXTENSIONS.get(args.format, "txt") + if args.format == "heatmap": + return "heatmap_{pid}" + if args.format == "pstats": + # pstats defaults to stdout, but for subprocesses we need files + return "profile_{pid}.pstats" + return f"{args.format}_{{pid}}.{extension}" + + +def _parse_mode(mode_string): + """Convert mode string to mode constant.""" + mode_map = { + "wall": PROFILING_MODE_WALL, + "cpu": PROFILING_MODE_CPU, + "gil": PROFILING_MODE_GIL, + "exception": PROFILING_MODE_EXCEPTION, + } + return mode_map[mode_string] + + +def _check_process_died(process): + """Check if process died and raise an error with stderr if available.""" + if process.poll() is None: + return # Process still running + + # Process died - try to get stderr for error message + stderr_msg = "" + if process.stderr: + try: + stderr_msg = process.stderr.read().decode().strip() + except (OSError, UnicodeDecodeError): + pass + + if stderr_msg: + raise RuntimeError(stderr_msg) + raise RuntimeError(f"Process exited with code {process.returncode}") + + +def _wait_for_ready_signal(sync_sock, process, timeout): + """Wait for the ready signal from the subprocess, checking for early death.""" + deadline = time.monotonic() + timeout + sel = selectors.DefaultSelector() + sel.register(sync_sock, selectors.EVENT_READ) + + try: + while True: + _check_process_died(process) + + remaining = deadline - time.monotonic() + if remaining <= 0: + raise socket.timeout("timed out") + + if not sel.select(timeout=min(0.1, remaining)): + continue + + conn, _ = sync_sock.accept() + try: + ready_signal = conn.recv(_RECV_BUFFER_SIZE) + finally: + conn.close() + + if ready_signal != _READY_MESSAGE: + raise RuntimeError(f"Invalid ready signal received: {ready_signal!r}") + return + finally: + sel.close() + + +def _run_with_sync(original_cmd, suppress_output=False): + """Run a command with socket-based synchronization and return the process.""" + # Create a TCP socket for synchronization with better socket options + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sync_sock: + # Set SO_REUSEADDR to avoid "Address already in use" errors + sync_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sync_sock.bind(("127.0.0.1", 0)) # Let OS choose a free port + sync_port = sync_sock.getsockname()[1] + sync_sock.listen(1) + sync_sock.settimeout(_SYNC_TIMEOUT) + + # Get current working directory to preserve it + cwd = os.getcwd() + + # Build command using the sync coordinator + target_args = original_cmd[1:] # Remove python executable + cmd = ( + sys.executable, + "-m", + "profiling.sampling._sync_coordinator", + str(sync_port), + cwd, + ) + tuple(target_args) + + # Start the process with coordinator + # When suppress_output=True (live mode), capture stderr so we can + # report errors if the process dies before signaling ready. + # When suppress_output=False (normal mode), let stderr inherit so + # script errors print to the terminal. + popen_kwargs = {} + if suppress_output: + popen_kwargs["stdin"] = subprocess.DEVNULL + popen_kwargs["stdout"] = subprocess.DEVNULL + popen_kwargs["stderr"] = subprocess.PIPE + + process = subprocess.Popen(cmd, **popen_kwargs) + + try: + _wait_for_ready_signal(sync_sock, process, _SYNC_TIMEOUT) + + # Close stderr pipe if we were capturing it + if process.stderr: + process.stderr.close() + + except socket.timeout: + # If we timeout, kill the process and raise an error + if process.poll() is None: + process.terminate() + try: + process.wait(timeout=_PROCESS_KILL_TIMEOUT) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + raise RuntimeError( + "Process failed to signal readiness within timeout" + ) + + return process + + +def _add_sampling_options(parser): + """Add sampling configuration options to a parser.""" + sampling_group = parser.add_argument_group("Sampling configuration") + sampling_group.add_argument( + "-i", + "--interval", + type=int, + default=100, + metavar="MICROSECONDS", + help="sampling interval", + ) + sampling_group.add_argument( + "-d", + "--duration", + type=int, + default=10, + metavar="SECONDS", + help="Sampling duration", + ) + sampling_group.add_argument( + "-a", + "--all-threads", + action="store_true", + help="Sample all threads in the process instead of just the main thread", + ) + sampling_group.add_argument( + "--realtime-stats", + action="store_true", + help="Print real-time sampling statistics (Hz, mean, min, max) during profiling", + ) + sampling_group.add_argument( + "--native", + action="store_true", + help='Include artificial "" frames to denote calls to non-Python code', + ) + sampling_group.add_argument( + "--no-gc", + action="store_false", + dest="gc", + help='Don\'t include artificial "" frames to denote active garbage collection', + ) + sampling_group.add_argument( + "--opcodes", + action="store_true", + help="Gather bytecode opcode information for instruction-level profiling " + "(shows which bytecode instructions are executing, including specializations).", + ) + sampling_group.add_argument( + "--async-aware", + action="store_true", + help="Enable async-aware profiling (uses task-based stack reconstruction)", + ) + sampling_group.add_argument( + "--subprocesses", + action="store_true", + help="Also profile subprocesses. Each subprocess gets its own profiler and output file.", + ) + + +def _add_mode_options(parser): + """Add mode options to a parser.""" + mode_group = parser.add_argument_group("Mode options") + mode_group.add_argument( + "--mode", + choices=["wall", "cpu", "gil", "exception"], + default="wall", + help="Sampling mode: wall (all samples), cpu (only samples when thread is on CPU), " + "gil (only samples when thread holds the GIL), " + "exception (only samples when thread has an active exception). " + "Incompatible with --async-aware", + ) + mode_group.add_argument( + "--async-mode", + choices=["running", "all"], + default="running", + help='Async profiling mode: "running" (only running task) ' + 'or "all" (all tasks including waiting). Requires --async-aware', + ) + + +def _add_format_options(parser): + """Add output format options to a parser.""" + output_group = parser.add_argument_group("Output options") + format_group = output_group.add_mutually_exclusive_group() + format_group.add_argument( + "--pstats", + action="store_const", + const="pstats", + dest="format", + help="Generate pstats output (default)", + ) + format_group.add_argument( + "--collapsed", + action="store_const", + const="collapsed", + dest="format", + help="Generate collapsed stack traces for flamegraphs", + ) + format_group.add_argument( + "--flamegraph", + action="store_const", + const="flamegraph", + dest="format", + help="Generate interactive HTML flamegraph visualization", + ) + format_group.add_argument( + "--gecko", + action="store_const", + const="gecko", + dest="format", + help="Generate Gecko format for Firefox Profiler", + ) + format_group.add_argument( + "--heatmap", + action="store_const", + const="heatmap", + dest="format", + help="Generate interactive HTML heatmap visualization with line-level sample counts", + ) + parser.set_defaults(format="pstats") + + output_group.add_argument( + "-o", + "--output", + dest="outfile", + help="Output path (default: stdout for pstats, auto-generated for others). " + "For heatmap: directory name (default: heatmap_PID)", + ) + + +def _add_pstats_options(parser): + """Add pstats-specific display options to a parser.""" + pstats_group = parser.add_argument_group("pstats format options") + pstats_group.add_argument( + "--sort", + choices=[ + "nsamples", + "tottime", + "cumtime", + "sample-pct", + "cumul-pct", + "nsamples-cumul", + "name", + ], + default=None, + help="Sort order for pstats output (default: nsamples)", + ) + pstats_group.add_argument( + "-l", + "--limit", + type=int, + default=None, + help="Limit the number of rows in the output (default: 15)", + ) + pstats_group.add_argument( + "--no-summary", + action="store_true", + help="Disable the summary section in the pstats output", + ) + + +def _sort_to_mode(sort_choice): + """Convert sort choice string to SORT_MODE constant.""" + sort_map = { + "nsamples": SORT_MODE_NSAMPLES, + "tottime": SORT_MODE_TOTTIME, + "cumtime": SORT_MODE_CUMTIME, + "sample-pct": SORT_MODE_SAMPLE_PCT, + "cumul-pct": SORT_MODE_CUMUL_PCT, + "nsamples-cumul": SORT_MODE_NSAMPLES_CUMUL, + "name": -1, + } + return sort_map.get(sort_choice, SORT_MODE_NSAMPLES) + + +def _create_collector(format_type, interval, skip_idle, opcodes=False): + """Create the appropriate collector based on format type. + + Args: + format_type: The output format ('pstats', 'collapsed', 'flamegraph', 'gecko', 'heatmap') + interval: Sampling interval in microseconds + skip_idle: Whether to skip idle samples + opcodes: Whether to collect opcode information (only used by gecko format + for creating interval markers in Firefox Profiler) + + Returns: + A collector instance of the appropriate type + """ + collector_class = COLLECTOR_MAP.get(format_type) + if collector_class is None: + raise ValueError(f"Unknown format: {format_type}") + + # Gecko format never skips idle (it needs both GIL and CPU data) + # and is the only format that uses opcodes for interval markers + if format_type == "gecko": + skip_idle = False + return collector_class(interval, skip_idle=skip_idle, opcodes=opcodes) + + return collector_class(interval, skip_idle=skip_idle) + + +def _generate_output_filename(format_type, pid): + """Generate output filename based on format and PID. + + Args: + format_type: The output format + pid: Process ID + + Returns: + Generated filename + """ + extension = FORMAT_EXTENSIONS.get(format_type, "txt") + # For heatmap, use cleaner directory name without extension + if format_type == "heatmap": + return f"heatmap_{pid}" + return f"{format_type}_{pid}.{extension}" + + +def _handle_output(collector, args, pid, mode): + """Handle output for the collector based on format and arguments. + + Args: + collector: The collector instance with profiling data + args: Parsed command-line arguments + pid: Process ID (for generating filenames) + mode: Profiling mode used + """ + if args.format == "pstats": + if args.outfile: + # If outfile is a directory, generate filename inside it + if os.path.isdir(args.outfile): + filename = os.path.join(args.outfile, _generate_output_filename(args.format, pid)) + collector.export(filename) + else: + collector.export(args.outfile) + else: + # Print to stdout with defaults applied + sort_choice = args.sort if args.sort is not None else "nsamples" + limit = args.limit if args.limit is not None else 15 + sort_mode = _sort_to_mode(sort_choice) + collector.print_stats( + sort_mode, limit, not args.no_summary, mode + ) + else: + # Export to file + if args.outfile and os.path.isdir(args.outfile): + # If outfile is a directory, generate filename inside it + filename = os.path.join(args.outfile, _generate_output_filename(args.format, pid)) + else: + filename = args.outfile or _generate_output_filename(args.format, pid) + collector.export(filename) + + +def _validate_args(args, parser): + """Validate format-specific options and live mode requirements. + + Args: + args: Parsed command-line arguments + parser: ArgumentParser instance for error reporting + """ + # Check if live mode is available + if hasattr(args, 'live') and args.live and LiveStatsCollector is None: + parser.error( + "Live mode requires the curses module, which is not available." + ) + + # --subprocesses is incompatible with --live + if hasattr(args, 'subprocesses') and args.subprocesses: + if hasattr(args, 'live') and args.live: + parser.error("--subprocesses is incompatible with --live mode.") + + # Async-aware mode is incompatible with --native, --no-gc, --mode, and --all-threads + if args.async_aware: + issues = [] + if args.native: + issues.append("--native") + if not args.gc: + issues.append("--no-gc") + if hasattr(args, 'mode') and args.mode != "wall": + issues.append(f"--mode={args.mode}") + if hasattr(args, 'all_threads') and args.all_threads: + issues.append("--all-threads") + if issues: + parser.error( + f"Options {', '.join(issues)} are incompatible with --async-aware. " + "Async-aware profiling uses task-based stack reconstruction." + ) + + # --async-mode requires --async-aware + if hasattr(args, 'async_mode') and args.async_mode != "running" and not args.async_aware: + parser.error("--async-mode requires --async-aware to be enabled.") + + # Live mode is incompatible with format options + if hasattr(args, 'live') and args.live: + if args.format != "pstats": + format_flag = f"--{args.format}" + parser.error( + f"--live is incompatible with {format_flag}. Live mode uses a TUI interface." + ) + + # Live mode is also incompatible with pstats-specific options + issues = [] + if args.sort is not None: + issues.append("--sort") + if args.limit is not None: + issues.append("--limit") + if args.no_summary: + issues.append("--no-summary") + + if issues: + parser.error( + f"Options {', '.join(issues)} are incompatible with --live. " + "Live mode uses a TUI interface with its own controls." + ) + return + + # Validate gecko mode doesn't use non-wall mode + if args.format == "gecko" and args.mode != "wall": + parser.error( + "--mode option is incompatible with --gecko. " + "Gecko format automatically includes both GIL-holding and CPU status analysis." + ) + + # Validate --opcodes is only used with compatible formats + opcodes_compatible_formats = ("live", "gecko", "flamegraph", "heatmap") + if args.opcodes and args.format not in opcodes_compatible_formats: + parser.error( + f"--opcodes is only compatible with {', '.join('--' + f for f in opcodes_compatible_formats)}." + ) + + # Validate pstats-specific options are only used with pstats format + if args.format != "pstats": + issues = [] + if args.sort is not None: + issues.append("--sort") + if args.limit is not None: + issues.append("--limit") + if args.no_summary: + issues.append("--no-summary") + + if issues: + format_flag = f"--{args.format}" + parser.error( + f"Options {', '.join(issues)} are only valid with --pstats, not {format_flag}" + ) + + +def main(): + """Main entry point for the CLI.""" + # Create the main parser + parser = argparse.ArgumentParser( + description=_HELP_DESCRIPTION, + formatter_class=CustomFormatter, + ) + + # Create subparsers for commands + subparsers = parser.add_subparsers( + dest="command", required=True, help="Command to run" + ) + + # === RUN COMMAND === + run_parser = subparsers.add_parser( + "run", + help="Run and profile a script or module", + formatter_class=CustomFormatter, + description="""Run and profile a Python script or module + +Examples: + # Run and profile a module + `python -m profiling.sampling run -m mymodule arg1 arg2` + + # Generate flamegraph from a script + `python -m profiling.sampling run --flamegraph -o output.html script.py` + + # Profile with custom interval and duration + `python -m profiling.sampling run -i 50 -d 30 script.py` + + # Save collapsed stacks to file + `python -m profiling.sampling run --collapsed -o stacks.txt script.py` + + # Live interactive mode for a script + `python -m profiling.sampling run --live script.py`""", + ) + run_parser.add_argument( + "-m", + "--module", + action="store_true", + help="Run target as a module (like python -m)", + ) + run_parser.add_argument( + "target", + help="Script file or module name to profile", + ) + run_parser.add_argument( + "args", + nargs=argparse.REMAINDER, + help="Arguments to pass to the script or module", + ) + run_parser.add_argument( + "--live", + action="store_true", + help="Interactive TUI profiler (top-like interface, press 'q' to quit, 's' to cycle sort)", + ) + _add_sampling_options(run_parser) + _add_mode_options(run_parser) + _add_format_options(run_parser) + _add_pstats_options(run_parser) + + # === ATTACH COMMAND === + attach_parser = subparsers.add_parser( + "attach", + help="Attach to and profile a running process", + formatter_class=CustomFormatter, + description="""Attach to a running process and profile it + +Examples: + # Profile all threads, sort by total time + `python -m profiling.sampling attach -a --sort tottime 1234` + + # Live interactive mode for a running process + `python -m profiling.sampling attach --live 1234`""", + ) + attach_parser.add_argument( + "pid", + type=int, + help="Process ID to attach to", + ) + attach_parser.add_argument( + "--live", + action="store_true", + help="Interactive TUI profiler (top-like interface, press 'q' to quit, 's' to cycle sort)", + ) + _add_sampling_options(attach_parser) + _add_mode_options(attach_parser) + _add_format_options(attach_parser) + _add_pstats_options(attach_parser) + + # Parse arguments + args = parser.parse_args() + + # Validate arguments + _validate_args(args, parser) + + # Command dispatch table + command_handlers = { + "run": _handle_run, + "attach": _handle_attach, + } + + # Execute the appropriate command + handler = command_handlers.get(args.command) + if handler: + handler(args) + else: + parser.error(f"Unknown command: {args.command}") + + +def _handle_attach(args): + """Handle the 'attach' command.""" + if not _is_process_running(args.pid): + raise SamplingUnknownProcessError(args.pid) + # Check if live mode is requested + if args.live: + _handle_live_attach(args, args.pid) + return + + # Use PROFILING_MODE_ALL for gecko format + mode = ( + PROFILING_MODE_ALL + if args.format == "gecko" + else _parse_mode(args.mode) + ) + + # Determine skip_idle based on mode + skip_idle = ( + mode != PROFILING_MODE_WALL if mode != PROFILING_MODE_ALL else False + ) + + # Create the appropriate collector + collector = _create_collector(args.format, args.interval, skip_idle, args.opcodes) + + with _get_child_monitor_context(args, args.pid): + collector = sample( + args.pid, + collector, + duration_sec=args.duration, + all_threads=args.all_threads, + realtime_stats=args.realtime_stats, + mode=mode, + async_aware=args.async_mode if args.async_aware else None, + native=args.native, + gc=args.gc, + opcodes=args.opcodes, + ) + _handle_output(collector, args, args.pid, mode) + + +def _handle_run(args): + """Handle the 'run' command.""" + # Validate target exists before launching subprocess + if args.module: + # Temporarily add cwd to sys.path so we can find modules in the + # current directory, matching the coordinator's behavior + cwd = os.getcwd() + added_cwd = False + if cwd not in sys.path: + sys.path.insert(0, cwd) + added_cwd = True + try: + if importlib.util.find_spec(args.target) is None: + raise SamplingModuleNotFoundError(args.target) + finally: + if added_cwd: + sys.path.remove(cwd) + else: + if not os.path.exists(args.target): + raise SamplingScriptNotFoundError(args.target) + + # Check if live mode is requested + if args.live: + _handle_live_run(args) + return + + # Build the command to run + if args.module: + cmd = (sys.executable, "-m", args.target, *args.args) + else: + cmd = (sys.executable, args.target, *args.args) + + # Run with synchronization + try: + process = _run_with_sync(cmd, suppress_output=False) + except RuntimeError as e: + sys.exit(f"Error: {e}") + + # Use PROFILING_MODE_ALL for gecko format + mode = ( + PROFILING_MODE_ALL + if args.format == "gecko" + else _parse_mode(args.mode) + ) + + # Determine skip_idle based on mode + skip_idle = ( + mode != PROFILING_MODE_WALL if mode != PROFILING_MODE_ALL else False + ) + + # Create the appropriate collector + collector = _create_collector(args.format, args.interval, skip_idle, args.opcodes) + + with _get_child_monitor_context(args, process.pid): + try: + collector = sample( + process.pid, + collector, + duration_sec=args.duration, + all_threads=args.all_threads, + realtime_stats=args.realtime_stats, + mode=mode, + async_aware=args.async_mode if args.async_aware else None, + native=args.native, + gc=args.gc, + opcodes=args.opcodes, + ) + _handle_output(collector, args, process.pid, mode) + finally: + # Terminate the main subprocess - child profilers finish when their + # target processes exit + if process.poll() is None: + process.terminate() + try: + process.wait(timeout=_PROCESS_KILL_TIMEOUT) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + + +def _handle_live_attach(args, pid): + """Handle live mode for an existing process.""" + mode = _parse_mode(args.mode) + + # Determine skip_idle based on mode + skip_idle = mode != PROFILING_MODE_WALL + + # Create live collector with default settings + collector = LiveStatsCollector( + args.interval, + skip_idle=skip_idle, + sort_by="tottime", # Default initial sort + limit=20, # Default limit + pid=pid, + mode=mode, + opcodes=args.opcodes, + async_aware=args.async_mode if args.async_aware else None, + ) + + # Sample in live mode + sample_live( + pid, + collector, + duration_sec=args.duration, + all_threads=args.all_threads, + realtime_stats=args.realtime_stats, + mode=mode, + async_aware=args.async_mode if args.async_aware else None, + native=args.native, + gc=args.gc, + opcodes=args.opcodes, + ) + + +def _handle_live_run(args): + """Handle live mode for running a script/module.""" + # Build the command to run + if args.module: + cmd = (sys.executable, "-m", args.target, *args.args) + else: + cmd = (sys.executable, args.target, *args.args) + + # Run with synchronization, suppressing output for live mode + try: + process = _run_with_sync(cmd, suppress_output=True) + except RuntimeError as e: + sys.exit(f"Error: {e}") + + mode = _parse_mode(args.mode) + + # Determine skip_idle based on mode + skip_idle = mode != PROFILING_MODE_WALL + + # Create live collector with default settings + collector = LiveStatsCollector( + args.interval, + skip_idle=skip_idle, + sort_by="tottime", # Default initial sort + limit=20, # Default limit + pid=process.pid, + mode=mode, + opcodes=args.opcodes, + async_aware=args.async_mode if args.async_aware else None, + ) + + # Profile the subprocess in live mode + try: + sample_live( + process.pid, + collector, + duration_sec=args.duration, + all_threads=args.all_threads, + realtime_stats=args.realtime_stats, + mode=mode, + async_aware=args.async_mode if args.async_aware else None, + native=args.native, + gc=args.gc, + opcodes=args.opcodes, + ) + finally: + # Clean up the subprocess + if process.poll() is None: + process.terminate() + try: + process.wait(timeout=_PROCESS_KILL_TIMEOUT) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + + +if __name__ == "__main__": + main() diff --git a/Lib/profiling/sampling/collector.py b/Lib/profiling/sampling/collector.py index 28286120aef..a1f6ec190f6 100644 --- a/Lib/profiling/sampling/collector.py +++ b/Lib/profiling/sampling/collector.py @@ -1,11 +1,245 @@ from abc import ABC, abstractmethod +from .constants import ( + DEFAULT_LOCATION, + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, + THREAD_STATUS_GIL_REQUESTED, + THREAD_STATUS_UNKNOWN, + THREAD_STATUS_HAS_EXCEPTION, +) +try: + from _remote_debugging import FrameInfo +except ImportError: + # Fallback definition if _remote_debugging is not available + FrameInfo = None + + +def normalize_location(location): + """Normalize location to a 4-tuple format. + + Args: + location: tuple (lineno, end_lineno, col_offset, end_col_offset) or None + + Returns: + tuple: (lineno, end_lineno, col_offset, end_col_offset) + """ + if location is None: + return DEFAULT_LOCATION + return location + + +def extract_lineno(location): + """Extract lineno from location. + + Args: + location: tuple (lineno, end_lineno, col_offset, end_col_offset) or None + + Returns: + int: The line number (0 for synthetic frames) + """ + if location is None: + return 0 + return location[0] class Collector(ABC): @abstractmethod def collect(self, stack_frames): """Collect profiling data from stack frames.""" + def collect_failed_sample(self): + """Collect data about a failed sample attempt.""" + @abstractmethod def export(self, filename): """Export collected data to a file.""" + + def _iter_all_frames(self, stack_frames, skip_idle=False): + for interpreter_info in stack_frames: + for thread_info in interpreter_info.threads: + # skip_idle now means: skip if thread is not actively running + # A thread is "active" if it has the GIL OR is on CPU + if skip_idle: + status_flags = thread_info.status + has_gil = bool(status_flags & THREAD_STATUS_HAS_GIL) + on_cpu = bool(status_flags & THREAD_STATUS_ON_CPU) + if not (has_gil or on_cpu): + continue + frames = thread_info.frame_info + if frames: + yield frames, thread_info.thread_id + + def _iter_async_frames(self, awaited_info_list): + # Phase 1: Index tasks and build parent relationships with pre-computed selection + task_map, child_to_parent, all_task_ids, all_parent_ids = self._build_task_graph(awaited_info_list) + + # Phase 2: Find leaf tasks (tasks not awaited by anyone) + leaf_task_ids = self._find_leaf_tasks(all_task_ids, all_parent_ids) + + # Phase 3: Build linear stacks from each leaf to root (optimized - no sorting!) + yield from self._build_linear_stacks(leaf_task_ids, task_map, child_to_parent) + + def _build_task_graph(self, awaited_info_list): + task_map = {} + child_to_parent = {} # Maps child_id -> (selected_parent_id, parent_count) + all_task_ids = set() + all_parent_ids = set() # Track ALL parent IDs for leaf detection + + for awaited_info in awaited_info_list: + thread_id = awaited_info.thread_id + for task_info in awaited_info.awaited_by: + task_id = task_info.task_id + task_map[task_id] = (task_info, thread_id) + all_task_ids.add(task_id) + + # Pre-compute selected parent and count for optimization + if task_info.awaited_by: + parent_ids = [p.task_name for p in task_info.awaited_by] + parent_count = len(parent_ids) + # Track ALL parents for leaf detection + all_parent_ids.update(parent_ids) + # Use min() for O(n) instead of sorted()[0] which is O(n log n) + selected_parent = min(parent_ids) if parent_count > 1 else parent_ids[0] + child_to_parent[task_id] = (selected_parent, parent_count) + + return task_map, child_to_parent, all_task_ids, all_parent_ids + + def _find_leaf_tasks(self, all_task_ids, all_parent_ids): + # Leaves are tasks that are not parents of any other task + return all_task_ids - all_parent_ids + + def _build_linear_stacks(self, leaf_task_ids, task_map, child_to_parent): + for leaf_id in leaf_task_ids: + frames = [] + visited = set() + current_id = leaf_id + thread_id = None + + # Follow the single parent chain from leaf to root + while current_id is not None: + # Cycle detection + if current_id in visited: + break + visited.add(current_id) + + # Check if task exists in task_map + if current_id not in task_map: + break + + task_info, tid = task_map[current_id] + + # Set thread_id from first task + if thread_id is None: + thread_id = tid + + # Add all frames from all coroutines in this task + if task_info.coroutine_stack: + for coro_info in task_info.coroutine_stack: + for frame in coro_info.call_stack: + frames.append(frame) + + # Get pre-computed parent info (no sorting needed!) + parent_info = child_to_parent.get(current_id) + + # Add task boundary marker with parent count annotation if multiple parents + task_name = task_info.task_name or "Task-" + str(task_info.task_id) + if parent_info: + selected_parent, parent_count = parent_info + if parent_count > 1: + task_name = f"{task_name} ({parent_count} parents)" + frames.append(FrameInfo(("", None, task_name, None))) + current_id = selected_parent + else: + # Root task - no parent + frames.append(FrameInfo(("", None, task_name, None))) + current_id = None + + # Yield the complete stack if we collected any frames + if frames and thread_id is not None: + yield frames, thread_id, leaf_id + + def _is_gc_frame(self, frame): + if isinstance(frame, tuple): + funcname = frame[2] if len(frame) >= 3 else "" + else: + funcname = getattr(frame, "funcname", "") + + return "" in funcname or "gc_collect" in funcname + + def _collect_thread_status_stats(self, stack_frames): + """Collect aggregate and per-thread status statistics from a sample. + + Returns: + tuple: (aggregate_status_counts, has_gc_frame, per_thread_stats) + - aggregate_status_counts: dict with has_gil, on_cpu, has_exception, etc. + - has_gc_frame: bool indicating if any thread has GC frames + - per_thread_stats: dict mapping thread_id to per-thread counts + """ + status_counts = { + "has_gil": 0, + "on_cpu": 0, + "gil_requested": 0, + "unknown": 0, + "has_exception": 0, + "total": 0, + } + has_gc_frame = False + per_thread_stats = {} + + for interpreter_info in stack_frames: + threads = getattr(interpreter_info, "threads", []) + for thread_info in threads: + status_counts["total"] += 1 + + # Track thread status using bit flags + status_flags = getattr(thread_info, "status", 0) + + if status_flags & THREAD_STATUS_HAS_GIL: + status_counts["has_gil"] += 1 + if status_flags & THREAD_STATUS_ON_CPU: + status_counts["on_cpu"] += 1 + if status_flags & THREAD_STATUS_GIL_REQUESTED: + status_counts["gil_requested"] += 1 + if status_flags & THREAD_STATUS_UNKNOWN: + status_counts["unknown"] += 1 + if status_flags & THREAD_STATUS_HAS_EXCEPTION: + status_counts["has_exception"] += 1 + + # Track per-thread statistics + thread_id = getattr(thread_info, "thread_id", None) + if thread_id is not None: + if thread_id not in per_thread_stats: + per_thread_stats[thread_id] = { + "has_gil": 0, + "on_cpu": 0, + "gil_requested": 0, + "unknown": 0, + "has_exception": 0, + "total": 0, + "gc_samples": 0, + } + + thread_stats = per_thread_stats[thread_id] + thread_stats["total"] += 1 + + if status_flags & THREAD_STATUS_HAS_GIL: + thread_stats["has_gil"] += 1 + if status_flags & THREAD_STATUS_ON_CPU: + thread_stats["on_cpu"] += 1 + if status_flags & THREAD_STATUS_GIL_REQUESTED: + thread_stats["gil_requested"] += 1 + if status_flags & THREAD_STATUS_UNKNOWN: + thread_stats["unknown"] += 1 + if status_flags & THREAD_STATUS_HAS_EXCEPTION: + thread_stats["has_exception"] += 1 + + # Check for GC frames in this thread + frames = getattr(thread_info, "frame_info", None) + if frames: + for frame in frames: + if self._is_gc_frame(frame): + thread_stats["gc_samples"] += 1 + has_gc_frame = True + break + + return status_counts, has_gc_frame, per_thread_stats diff --git a/Lib/profiling/sampling/constants.py b/Lib/profiling/sampling/constants.py new file mode 100644 index 00000000000..34b85ba4b3c --- /dev/null +++ b/Lib/profiling/sampling/constants.py @@ -0,0 +1,37 @@ +"""Constants for the sampling profiler.""" + +# Profiling mode constants +PROFILING_MODE_WALL = 0 +PROFILING_MODE_CPU = 1 +PROFILING_MODE_GIL = 2 +PROFILING_MODE_ALL = 3 # Combines GIL + CPU checks +PROFILING_MODE_EXCEPTION = 4 # Only samples when thread has an active exception + +# Sort mode constants +SORT_MODE_NSAMPLES = 0 +SORT_MODE_TOTTIME = 1 +SORT_MODE_CUMTIME = 2 +SORT_MODE_SAMPLE_PCT = 3 +SORT_MODE_CUMUL_PCT = 4 +SORT_MODE_NSAMPLES_CUMUL = 5 + +# Default location for synthetic frames (native, GC) that have no source location +# Format: (lineno, end_lineno, col_offset, end_col_offset) +DEFAULT_LOCATION = (0, 0, -1, -1) + +# Thread status flags +try: + from _remote_debugging import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, + THREAD_STATUS_UNKNOWN, + THREAD_STATUS_GIL_REQUESTED, + THREAD_STATUS_HAS_EXCEPTION, + ) +except ImportError: + # Fallback for tests or when module is not available + THREAD_STATUS_HAS_GIL = (1 << 0) + THREAD_STATUS_ON_CPU = (1 << 1) + THREAD_STATUS_UNKNOWN = (1 << 2) + THREAD_STATUS_GIL_REQUESTED = (1 << 3) + THREAD_STATUS_HAS_EXCEPTION = (1 << 4) diff --git a/Lib/profiling/sampling/errors.py b/Lib/profiling/sampling/errors.py new file mode 100644 index 00000000000..0832ad2d438 --- /dev/null +++ b/Lib/profiling/sampling/errors.py @@ -0,0 +1,19 @@ +"""Custom exceptions for the sampling profiler.""" + +class SamplingProfilerError(Exception): + """Base exception for sampling profiler errors.""" + +class SamplingUnknownProcessError(SamplingProfilerError): + def __init__(self, pid): + self.pid = pid + super().__init__(f"Process with PID '{pid}' does not exist.") + +class SamplingScriptNotFoundError(SamplingProfilerError): + def __init__(self, script_path): + self.script_path = script_path + super().__init__(f"Script '{script_path}' not found.") + +class SamplingModuleNotFoundError(SamplingProfilerError): + def __init__(self, module_name): + self.module_name = module_name + super().__init__(f"Module '{module_name}' not found.") diff --git a/Lib/profiling/sampling/gecko_collector.py b/Lib/profiling/sampling/gecko_collector.py new file mode 100644 index 00000000000..608a15da483 --- /dev/null +++ b/Lib/profiling/sampling/gecko_collector.py @@ -0,0 +1,786 @@ +import itertools +import json +import os +import platform +import sys +import threading +import time + +from .collector import Collector +from .opcode_utils import get_opcode_info, format_opcode +try: + from _remote_debugging import THREAD_STATUS_HAS_GIL, THREAD_STATUS_ON_CPU, THREAD_STATUS_UNKNOWN, THREAD_STATUS_GIL_REQUESTED, THREAD_STATUS_HAS_EXCEPTION +except ImportError: + # Fallback if module not available (shouldn't happen in normal use) + THREAD_STATUS_HAS_GIL = (1 << 0) + THREAD_STATUS_ON_CPU = (1 << 1) + THREAD_STATUS_UNKNOWN = (1 << 2) + THREAD_STATUS_GIL_REQUESTED = (1 << 3) + THREAD_STATUS_HAS_EXCEPTION = (1 << 4) + + +# Categories matching Firefox Profiler expectations +GECKO_CATEGORIES = [ + {"name": "Other", "color": "grey", "subcategories": ["Other"]}, + {"name": "Python", "color": "yellow", "subcategories": ["Other"]}, + {"name": "Native", "color": "blue", "subcategories": ["Other"]}, + {"name": "GC", "color": "orange", "subcategories": ["Other"]}, + {"name": "GIL", "color": "green", "subcategories": ["Other"]}, + {"name": "CPU", "color": "purple", "subcategories": ["Other"]}, + {"name": "Code Type", "color": "red", "subcategories": ["Other"]}, + {"name": "Opcodes", "color": "magenta", "subcategories": ["Other"]}, + {"name": "Exception", "color": "lightblue", "subcategories": ["Other"]}, +] + +# Category indices +CATEGORY_OTHER = 0 +CATEGORY_PYTHON = 1 +CATEGORY_NATIVE = 2 +CATEGORY_GC = 3 +CATEGORY_GIL = 4 +CATEGORY_CPU = 5 +CATEGORY_CODE_TYPE = 6 +CATEGORY_OPCODES = 7 +CATEGORY_EXCEPTION = 8 + +# Subcategory indices +DEFAULT_SUBCATEGORY = 0 + +GECKO_FORMAT_VERSION = 32 +GECKO_PREPROCESSED_VERSION = 57 + +# Resource type constants +RESOURCE_TYPE_LIBRARY = 1 + +# Frame constants +FRAME_ADDRESS_NONE = -1 +FRAME_INLINE_DEPTH_ROOT = 0 + +# Process constants +PROCESS_TYPE_MAIN = 0 +STACKWALK_DISABLED = 0 + + +class GeckoCollector(Collector): + def __init__(self, sample_interval_usec, *, skip_idle=False, opcodes=False): + self.sample_interval_usec = sample_interval_usec + self.skip_idle = skip_idle + self.opcodes_enabled = opcodes + self.start_time = time.time() * 1000 # milliseconds since epoch + + # Global string table (shared across all threads) + self.global_strings = ["(root)"] # Start with root + self.global_string_map = {"(root)": 0} + + # Per-thread data structures + self.threads = {} # tid -> thread data + + # Global tables + self.libs = [] + + # Sampling interval tracking + self.sample_count = 0 + self.last_sample_time = 0 + self.interval = 1.0 # Will be calculated from actual sampling + + # State tracking for interval markers (tid -> start_time) + self.has_gil_start = {} # Thread has the GIL + self.no_gil_start = {} # Thread doesn't have the GIL + self.on_cpu_start = {} # Thread is running on CPU + self.off_cpu_start = {} # Thread is off CPU + self.python_code_start = {} # Thread running Python code (has GIL) + self.native_code_start = {} # Thread running native code (on CPU without GIL) + self.gil_wait_start = {} # Thread waiting for GIL + self.exception_start = {} # Thread has an exception set + self.no_exception_start = {} # Thread has no exception set + + # GC event tracking: track GC start time per thread + self.gc_start_per_thread = {} # tid -> start_time + + # Track which threads have been initialized for state tracking + self.initialized_threads = set() + + # Opcode state tracking per thread: tid -> (opcode, lineno, col_offset, funcname, filename, start_time) + self.opcode_state = {} + + def _track_state_transition(self, tid, condition, active_dict, inactive_dict, + active_name, inactive_name, category, current_time): + """Track binary state transitions and emit markers. + + Args: + tid: Thread ID + condition: Whether the active state is true + active_dict: Dict tracking start time of active state + inactive_dict: Dict tracking start time of inactive state + active_name: Name for active state marker + inactive_name: Name for inactive state marker + category: Gecko category for the markers + current_time: Current timestamp + """ + # On first observation of a thread, just record the current state + # without creating a marker (we don't know what the previous state was) + if tid not in self.initialized_threads: + if condition: + active_dict[tid] = current_time + else: + inactive_dict[tid] = current_time + return + + # For already-initialized threads, track transitions + if condition: + active_dict.setdefault(tid, current_time) + if tid in inactive_dict: + self._add_marker(tid, inactive_name, inactive_dict.pop(tid), + current_time, category) + else: + inactive_dict.setdefault(tid, current_time) + if tid in active_dict: + self._add_marker(tid, active_name, active_dict.pop(tid), + current_time, category) + + def collect(self, stack_frames): + """Collect a sample from stack frames.""" + current_time = (time.time() * 1000) - self.start_time + + # Update interval calculation + if self.sample_count > 0 and self.last_sample_time > 0: + self.interval = ( + current_time - self.last_sample_time + ) / self.sample_count + self.last_sample_time = current_time + + # Process threads and track GC per thread + for interpreter_info in stack_frames: + for thread_info in interpreter_info.threads: + frames = thread_info.frame_info + tid = thread_info.thread_id + + # Initialize thread if needed + if tid not in self.threads: + self.threads[tid] = self._create_thread(tid) + + thread_data = self.threads[tid] + + # Decode status flags + status_flags = thread_info.status + has_gil = bool(status_flags & THREAD_STATUS_HAS_GIL) + on_cpu = bool(status_flags & THREAD_STATUS_ON_CPU) + gil_requested = bool(status_flags & THREAD_STATUS_GIL_REQUESTED) + + # Track GIL possession (Has GIL / No GIL) + self._track_state_transition( + tid, has_gil, self.has_gil_start, self.no_gil_start, + "Has GIL", "No GIL", CATEGORY_GIL, current_time + ) + + # Track CPU state (On CPU / Off CPU) + self._track_state_transition( + tid, on_cpu, self.on_cpu_start, self.off_cpu_start, + "On CPU", "Off CPU", CATEGORY_CPU, current_time + ) + + # Track code type (Python Code / Native Code) + # This is tri-state: Python (has_gil), Native (on_cpu without gil), or Neither + if has_gil: + self._track_state_transition( + tid, True, self.python_code_start, self.native_code_start, + "Python Code", "Native Code", CATEGORY_CODE_TYPE, current_time + ) + elif on_cpu: + self._track_state_transition( + tid, True, self.native_code_start, self.python_code_start, + "Native Code", "Python Code", CATEGORY_CODE_TYPE, current_time + ) + else: + # Thread is idle (neither has GIL nor on CPU) - close any open code markers + # This handles the third state that _track_state_transition doesn't cover + if tid in self.initialized_threads: + if tid in self.python_code_start: + self._add_marker(tid, "Python Code", self.python_code_start.pop(tid), + current_time, CATEGORY_CODE_TYPE) + if tid in self.native_code_start: + self._add_marker(tid, "Native Code", self.native_code_start.pop(tid), + current_time, CATEGORY_CODE_TYPE) + + # Track "Waiting for GIL" intervals (one-sided tracking) + if gil_requested: + self.gil_wait_start.setdefault(tid, current_time) + elif tid in self.gil_wait_start: + self._add_marker(tid, "Waiting for GIL", self.gil_wait_start.pop(tid), + current_time, CATEGORY_GIL) + + # Track exception state (Has Exception / No Exception) + has_exception = bool(status_flags & THREAD_STATUS_HAS_EXCEPTION) + self._track_state_transition( + tid, has_exception, self.exception_start, self.no_exception_start, + "Has Exception", "No Exception", CATEGORY_EXCEPTION, current_time + ) + + # Track GC events by detecting frames in the stack trace + # This leverages the improved GC frame tracking from commit 336366fd7ca + # which precisely identifies the thread that initiated GC collection + has_gc_frame = any(frame[2] == "" for frame in frames) + if has_gc_frame: + # This thread initiated GC collection + if tid not in self.gc_start_per_thread: + self.gc_start_per_thread[tid] = current_time + elif tid in self.gc_start_per_thread: + # End GC marker when no more GC frames are detected + self._add_marker(tid, "GC Collecting", self.gc_start_per_thread.pop(tid), + current_time, CATEGORY_GC) + + # Mark thread as initialized after processing all state transitions + self.initialized_threads.add(tid) + + # Categorize: idle if neither has GIL nor on CPU + is_idle = not has_gil and not on_cpu + + # Skip idle threads if skip_idle is enabled + if self.skip_idle and is_idle: + continue + + if not frames: + continue + + # Process the stack + stack_index = self._process_stack(thread_data, frames) + + # Add sample - cache references to avoid dictionary lookups + samples = thread_data["samples"] + samples["stack"].append(stack_index) + samples["time"].append(current_time) + samples["eventDelay"].append(None) + + # Track opcode state changes for interval markers (leaf frame only) + if self.opcodes_enabled: + leaf_frame = frames[0] + filename, location, funcname, opcode = leaf_frame + if isinstance(location, tuple): + lineno, _, col_offset, _ = location + else: + lineno = location + col_offset = -1 + + current_state = (opcode, lineno, col_offset, funcname, filename) + + if tid not in self.opcode_state: + # First observation - start tracking + self.opcode_state[tid] = (*current_state, current_time) + elif self.opcode_state[tid][:5] != current_state: + # State changed - emit marker for previous state + prev_opcode, prev_lineno, prev_col, prev_funcname, prev_filename, prev_start = self.opcode_state[tid] + self._add_opcode_interval_marker( + tid, prev_opcode, prev_lineno, prev_col, prev_funcname, prev_start, current_time + ) + # Start tracking new state + self.opcode_state[tid] = (*current_state, current_time) + + self.sample_count += 1 + + def _create_thread(self, tid): + """Create a new thread structure with processed profile format.""" + + # Determine if this is the main thread + try: + is_main = tid == threading.main_thread().ident + except (RuntimeError, AttributeError): + is_main = False + + thread = { + "name": f"Thread-{tid}", + "isMainThread": is_main, + "processStartupTime": 0, + "processShutdownTime": None, + "registerTime": 0, + "unregisterTime": None, + "pausedRanges": [], + "pid": str(os.getpid()), + "tid": tid, + "processType": "default", + "processName": "Python Process", + # Sample data - processed format with direct arrays + "samples": { + "stack": [], + "time": [], + "eventDelay": [], + "weight": None, + "weightType": "samples", + "length": 0, # Will be updated on export + }, + # Stack table - processed format + "stackTable": { + "frame": [], + "category": [], + "subcategory": [], + "prefix": [], + "length": 0, # Will be updated on export + }, + # Frame table - processed format + "frameTable": { + "address": [], + "category": [], + "subcategory": [], + "func": [], + "innerWindowID": [], + "implementation": [], + "optimizations": [], + "line": [], + "column": [], + "inlineDepth": [], + "nativeSymbol": [], + "length": 0, # Will be updated on export + }, + # Function table - processed format + "funcTable": { + "name": [], + "isJS": [], + "relevantForJS": [], + "resource": [], + "fileName": [], + "lineNumber": [], + "columnNumber": [], + "length": 0, # Will be updated on export + }, + # Resource table - processed format + "resourceTable": { + "lib": [], + "name": [], + "host": [], + "type": [], + "length": 0, # Will be updated on export + }, + # Native symbols table (empty for Python) + "nativeSymbols": { + "libIndex": [], + "address": [], + "name": [], + "functionSize": [], + "length": 0, + }, + # Markers - processed format (arrays) + "markers": { + "data": [], + "name": [], + "startTime": [], + "endTime": [], + "phase": [], + "category": [], + "length": 0, + }, + # Caches for deduplication + "_stackCache": {}, + "_frameCache": {}, + "_funcCache": {}, + "_resourceCache": {}, + } + + return thread + + def _is_python(self, filename: str) -> bool: + return not filename.startswith("<") or filename in ["", ""] + + def _get_category(self, filename: str) -> int: + return CATEGORY_PYTHON if self._is_python(filename) else CATEGORY_NATIVE + + def _intern_string(self, s): + """Intern a string in the global string table.""" + if s in self.global_string_map: + return self.global_string_map[s] + idx = len(self.global_strings) + self.global_strings.append(s) + self.global_string_map[s] = idx + return idx + + def _add_marker(self, tid, name, start_time, end_time, category): + """Add an interval marker for a specific thread.""" + if tid not in self.threads: + return + + thread_data = self.threads[tid] + duration = end_time - start_time + + name_idx = self._intern_string(name) + markers = thread_data["markers"] + markers["name"].append(name_idx) + markers["startTime"].append(start_time) + markers["endTime"].append(end_time) + markers["phase"].append(1) # 1 = interval marker + markers["category"].append(category) + markers["data"].append({ + "type": name.replace(" ", ""), + "duration": duration, + "tid": tid + }) + + def _add_opcode_interval_marker(self, tid, opcode, lineno, col_offset, funcname, start_time, end_time): + """Add an interval marker for opcode execution span.""" + if tid not in self.threads or opcode is None: + return + + thread_data = self.threads[tid] + opcode_info = get_opcode_info(opcode) + # Use formatted opcode name (with base opcode for specialized ones) + formatted_opname = format_opcode(opcode) + + name_idx = self._intern_string(formatted_opname) + + markers = thread_data["markers"] + markers["name"].append(name_idx) + markers["startTime"].append(start_time) + markers["endTime"].append(end_time) + markers["phase"].append(1) # 1 = interval marker + markers["category"].append(CATEGORY_OPCODES) + markers["data"].append({ + "type": "Opcode", + "opcode": opcode, + "opname": formatted_opname, + "base_opname": opcode_info["base_opname"], + "is_specialized": opcode_info["is_specialized"], + "line": lineno, + "column": col_offset if col_offset >= 0 else None, + "function": funcname, + "duration": end_time - start_time, + }) + + def _process_stack(self, thread_data, frames): + """Process a stack and return the stack index.""" + if not frames: + return None + + # Cache references to avoid repeated dictionary lookups + stack_cache = thread_data["_stackCache"] + stack_table = thread_data["stackTable"] + stack_frames = stack_table["frame"] + stack_prefix = stack_table["prefix"] + stack_category = stack_table["category"] + stack_subcategory = stack_table["subcategory"] + + # Build stack bottom-up (from root to leaf) + prefix_stack_idx = None + + for frame_tuple in reversed(frames): + # frame_tuple is (filename, location, funcname, opcode) + # location is (lineno, end_lineno, col_offset, end_col_offset) or just lineno + filename, location, funcname, opcode = frame_tuple + if isinstance(location, tuple): + lineno, end_lineno, col_offset, end_col_offset = location + else: + # Legacy format: location is just lineno + lineno = location + col_offset = -1 + end_col_offset = -1 + + # Get or create function + func_idx = self._get_or_create_func( + thread_data, filename, funcname, lineno + ) + + # Get or create frame (include column for precise source location) + frame_idx = self._get_or_create_frame( + thread_data, func_idx, lineno, col_offset + ) + + # Check stack cache + stack_key = (frame_idx, prefix_stack_idx) + if stack_key in stack_cache: + prefix_stack_idx = stack_cache[stack_key] + else: + # Create new stack entry + stack_idx = len(stack_frames) + stack_frames.append(frame_idx) + stack_prefix.append(prefix_stack_idx) + + # Determine category + category = self._get_category(filename) + stack_category.append(category) + stack_subcategory.append(DEFAULT_SUBCATEGORY) + + stack_cache[stack_key] = stack_idx + prefix_stack_idx = stack_idx + + return prefix_stack_idx + + def _get_or_create_func(self, thread_data, filename, funcname, lineno): + """Get or create a function entry.""" + func_cache = thread_data["_funcCache"] + func_key = (filename, funcname) + + if func_key in func_cache: + return func_cache[func_key] + + # Cache references for func table + func_table = thread_data["funcTable"] + func_names = func_table["name"] + func_is_js = func_table["isJS"] + func_relevant = func_table["relevantForJS"] + func_resources = func_table["resource"] + func_filenames = func_table["fileName"] + func_line_numbers = func_table["lineNumber"] + func_column_numbers = func_table["columnNumber"] + + func_idx = len(func_names) + + # Intern strings in global table + name_idx = self._intern_string(funcname) + + # Determine if Python + is_python = self._is_python(filename) + + # Create resource + resource_idx = self._get_or_create_resource(thread_data, filename) + + # Add function + func_names.append(name_idx) + func_is_js.append(is_python) + func_relevant.append(is_python) + func_resources.append(resource_idx) + + if is_python: + filename_idx = self._intern_string(os.path.basename(filename)) + func_filenames.append(filename_idx) + func_line_numbers.append(lineno) + else: + func_filenames.append(None) + func_line_numbers.append(None) + func_column_numbers.append(None) + + func_cache[func_key] = func_idx + return func_idx + + def _get_or_create_resource(self, thread_data, filename): + """Get or create a resource entry.""" + resource_cache = thread_data["_resourceCache"] + + if filename in resource_cache: + return resource_cache[filename] + + # Cache references for resource table + resource_table = thread_data["resourceTable"] + resource_libs = resource_table["lib"] + resource_names = resource_table["name"] + resource_hosts = resource_table["host"] + resource_types = resource_table["type"] + + resource_idx = len(resource_names) + resource_name = ( + os.path.basename(filename) if "/" in filename else filename + ) + name_idx = self._intern_string(resource_name) + + resource_libs.append(None) + resource_names.append(name_idx) + resource_hosts.append(None) + resource_types.append(RESOURCE_TYPE_LIBRARY) + + resource_cache[filename] = resource_idx + return resource_idx + + def _get_or_create_frame(self, thread_data, func_idx, lineno, col_offset=-1): + """Get or create a frame entry.""" + frame_cache = thread_data["_frameCache"] + # Include column in cache key for precise frame identification + frame_key = (func_idx, lineno, col_offset if col_offset >= 0 else None) + + if frame_key in frame_cache: + return frame_cache[frame_key] + + # Cache references for frame table + frame_table = thread_data["frameTable"] + frame_addresses = frame_table["address"] + frame_inline_depths = frame_table["inlineDepth"] + frame_categories = frame_table["category"] + frame_subcategories = frame_table["subcategory"] + frame_funcs = frame_table["func"] + frame_native_symbols = frame_table["nativeSymbol"] + frame_inner_window_ids = frame_table["innerWindowID"] + frame_implementations = frame_table["implementation"] + frame_lines = frame_table["line"] + frame_columns = frame_table["column"] + frame_optimizations = frame_table["optimizations"] + + frame_idx = len(frame_funcs) + + # Determine category based on function - use cached func table reference + is_python = thread_data["funcTable"]["isJS"][func_idx] + category = CATEGORY_PYTHON if is_python else CATEGORY_NATIVE + + frame_addresses.append(FRAME_ADDRESS_NONE) + frame_inline_depths.append(FRAME_INLINE_DEPTH_ROOT) + frame_categories.append(category) + frame_subcategories.append(DEFAULT_SUBCATEGORY) + frame_funcs.append(func_idx) + frame_native_symbols.append(None) + frame_inner_window_ids.append(None) + frame_implementations.append(None) + frame_lines.append(lineno if lineno else None) + # Store column offset if available (>= 0), otherwise None + frame_columns.append(col_offset if col_offset >= 0 else None) + frame_optimizations.append(None) + + frame_cache[frame_key] = frame_idx + return frame_idx + + def _finalize_markers(self): + """Close any open markers at the end of profiling.""" + end_time = self.last_sample_time + + # Close all open markers for each thread using a generic approach + marker_states = [ + (self.has_gil_start, "Has GIL", CATEGORY_GIL), + (self.no_gil_start, "No GIL", CATEGORY_GIL), + (self.on_cpu_start, "On CPU", CATEGORY_CPU), + (self.off_cpu_start, "Off CPU", CATEGORY_CPU), + (self.python_code_start, "Python Code", CATEGORY_CODE_TYPE), + (self.native_code_start, "Native Code", CATEGORY_CODE_TYPE), + (self.gil_wait_start, "Waiting for GIL", CATEGORY_GIL), + (self.gc_start_per_thread, "GC Collecting", CATEGORY_GC), + (self.exception_start, "Has Exception", CATEGORY_EXCEPTION), + (self.no_exception_start, "No Exception", CATEGORY_EXCEPTION), + ] + + for state_dict, marker_name, category in marker_states: + for tid in list(state_dict.keys()): + self._add_marker(tid, marker_name, state_dict[tid], end_time, category) + del state_dict[tid] + + # Close any open opcode markers + for tid, state in list(self.opcode_state.items()): + opcode, lineno, col_offset, funcname, filename, start_time = state + self._add_opcode_interval_marker(tid, opcode, lineno, col_offset, funcname, start_time, end_time) + self.opcode_state.clear() + + def export(self, filename): + """Export the profile to a Gecko JSON file.""" + + if self.sample_count > 0 and self.last_sample_time > 0: + self.interval = self.last_sample_time / self.sample_count + + # Spinner for progress indication + spinner = itertools.cycle(['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']) + stop_spinner = threading.Event() + + def spin(): + message = 'Building Gecko profile...' + while not stop_spinner.is_set(): + sys.stderr.write(f'\r{next(spinner)} {message}') + sys.stderr.flush() + time.sleep(0.1) + # Clear the spinner line + sys.stderr.write('\r' + ' ' * (len(message) + 3) + '\r') + sys.stderr.flush() + + spinner_thread = threading.Thread(target=spin, daemon=True) + spinner_thread.start() + + try: + # Finalize any open markers before building profile + self._finalize_markers() + + profile = self._build_profile() + + with open(filename, "w") as f: + json.dump(profile, f, separators=(",", ":")) + finally: + stop_spinner.set() + spinner_thread.join(timeout=1.0) + # Small delay to ensure the clear happens + time.sleep(0.01) + + print(f"Gecko profile written to {filename}") + print( + f"Open in Firefox Profiler: https://profiler.firefox.com/" + ) + + def _build_marker_schema(self): + """Build marker schema definitions for Firefox Profiler.""" + schema = [] + + # Opcode marker schema (only if opcodes enabled) + if self.opcodes_enabled: + schema.append({ + "name": "Opcode", + "display": ["marker-table", "marker-chart"], + "tooltipLabel": "{marker.data.opname}", + "tableLabel": "{marker.data.opname} at line {marker.data.line}", + "chartLabel": "{marker.data.opname}", + "fields": [ + {"key": "opname", "label": "Opcode", "format": "string", "searchable": True}, + {"key": "base_opname", "label": "Base Opcode", "format": "string"}, + {"key": "is_specialized", "label": "Specialized", "format": "string"}, + {"key": "line", "label": "Line", "format": "integer"}, + {"key": "column", "label": "Column", "format": "integer"}, + {"key": "function", "label": "Function", "format": "string"}, + {"key": "duration", "label": "Duration", "format": "duration"}, + ], + }) + + return schema + + def _build_profile(self): + """Build the complete profile structure in processed format.""" + # Convert thread data to final format + threads = [] + + for tid, thread_data in self.threads.items(): + # Update lengths + samples = thread_data["samples"] + stack_table = thread_data["stackTable"] + frame_table = thread_data["frameTable"] + func_table = thread_data["funcTable"] + resource_table = thread_data["resourceTable"] + + samples["length"] = len(samples["stack"]) + stack_table["length"] = len(stack_table["frame"]) + frame_table["length"] = len(frame_table["func"]) + func_table["length"] = len(func_table["name"]) + resource_table["length"] = len(resource_table["name"]) + thread_data["markers"]["length"] = len(thread_data["markers"]["name"]) + + # Clean up internal caches + del thread_data["_stackCache"] + del thread_data["_frameCache"] + del thread_data["_funcCache"] + del thread_data["_resourceCache"] + + threads.append(thread_data) + + # Main profile structure in processed format + profile = { + "meta": { + "interval": self.interval, + "startTime": self.start_time, + "abi": platform.machine(), + "misc": "Python profiler", + "oscpu": platform.machine(), + "platform": platform.system(), + "processType": PROCESS_TYPE_MAIN, + "categories": GECKO_CATEGORIES, + "stackwalk": STACKWALK_DISABLED, + "toolkit": "", + "version": GECKO_FORMAT_VERSION, + "preprocessedProfileVersion": GECKO_PREPROCESSED_VERSION, + "appBuildID": "", + "physicalCPUs": os.cpu_count() or 0, + "logicalCPUs": os.cpu_count() or 0, + "CPUName": "", + "product": "Python", + "symbolicated": True, + "markerSchema": self._build_marker_schema(), + "importedFrom": "Tachyon Sampling Profiler", + "extensions": { + "id": [], + "name": [], + "baseURL": [], + "length": 0, + }, + }, + "libs": self.libs, + "threads": threads, + "pages": [], + "shared": { + "stringArray": self.global_strings, + "sources": {"length": 0, "uuid": [], "filename": []}, + }, + } + + return profile diff --git a/Lib/profiling/sampling/heatmap_collector.py b/Lib/profiling/sampling/heatmap_collector.py new file mode 100644 index 00000000000..e6701901aa3 --- /dev/null +++ b/Lib/profiling/sampling/heatmap_collector.py @@ -0,0 +1,1224 @@ +"""Heatmap collector for Python profiling with line-level execution heat visualization.""" + +import base64 +import collections +import html +import importlib.resources +import json +import math +import os +import platform +import site +import sys +from dataclasses import dataclass, field +from pathlib import Path +from typing import Dict, List, Tuple + +from ._css_utils import get_combined_css +from .collector import normalize_location, extract_lineno +from .stack_collector import StackTraceCollector + + +# ============================================================================ +# Data Classes +# ============================================================================ + +@dataclass +class FileStats: + """Statistics for a single profiled file.""" + filename: str + module_name: str + module_type: str + total_samples: int + total_self_samples: int + num_lines: int + max_samples: int + max_self_samples: int + percentage: float = 0.0 + + +@dataclass +class TreeNode: + """Node in the hierarchical file tree structure.""" + files: List[FileStats] = field(default_factory=list) + samples: int = 0 + count: int = 0 + children: Dict[str, 'TreeNode'] = field(default_factory=dict) + + +# ============================================================================ +# Module Path Analysis +# ============================================================================ + +def get_python_path_info(): + """Get information about Python installation paths for module extraction. + + Returns: + dict: Dictionary containing stdlib path, site-packages paths, and sys.path entries. + """ + info = { + 'stdlib': None, + 'site_packages': [], + 'sys_path': [] + } + + # Get standard library path from os module location + try: + if hasattr(os, '__file__') and os.__file__: + info['stdlib'] = Path(os.__file__).parent + except (AttributeError, OSError): + pass # Silently continue if we can't determine stdlib path + + # Get site-packages directories + site_packages = [] + try: + site_packages.extend(Path(p) for p in site.getsitepackages()) + except (AttributeError, OSError): + pass # Continue without site packages if unavailable + + # Get user site-packages + try: + user_site = site.getusersitepackages() + if user_site and Path(user_site).exists(): + site_packages.append(Path(user_site)) + except (AttributeError, OSError): + pass # Continue without user site packages + + info['site_packages'] = site_packages + info['sys_path'] = [Path(p) for p in sys.path if p] + + return info + + +def extract_module_name(filename, path_info): + """Extract Python module name and type from file path. + + Args: + filename: Path to the Python file + path_info: Dictionary from get_python_path_info() + + Returns: + tuple: (module_name, module_type) where module_type is one of: + 'stdlib', 'site-packages', 'project', or 'other' + """ + if not filename: + return ('unknown', 'other') + + try: + file_path = Path(filename) + except (ValueError, OSError): + return (str(filename), 'other') + + # Check if it's in stdlib + if path_info['stdlib'] and _is_subpath(file_path, path_info['stdlib']): + try: + rel_path = file_path.relative_to(path_info['stdlib']) + return (_path_to_module(rel_path), 'stdlib') + except ValueError: + pass + + # Check site-packages + for site_pkg in path_info['site_packages']: + if _is_subpath(file_path, site_pkg): + try: + rel_path = file_path.relative_to(site_pkg) + return (_path_to_module(rel_path), 'site-packages') + except ValueError: + continue + + # Check other sys.path entries (project files) + if not str(file_path).startswith(('<', '[')): # Skip special files + for path_entry in path_info['sys_path']: + if _is_subpath(file_path, path_entry): + try: + rel_path = file_path.relative_to(path_entry) + return (_path_to_module(rel_path), 'project') + except ValueError: + continue + + # Fallback: just use the filename + return (_path_to_module(file_path), 'other') + + +def _is_subpath(file_path, parent_path): + try: + file_path.relative_to(parent_path) + return True + except (ValueError, OSError): + return False + + +def _path_to_module(path): + if isinstance(path, str): + path = Path(path) + + # Remove .py extension + if path.suffix == '.py': + path = path.with_suffix('') + + # Convert path separators to dots + parts = path.parts + + # Handle __init__ files - they represent the package itself + if parts and parts[-1] == '__init__': + parts = parts[:-1] + + return '.'.join(parts) if parts else path.stem + + +# ============================================================================ +# Helper Classes +# ============================================================================ + +class _TemplateLoader: + """Loads and caches HTML/CSS/JS templates for heatmap generation.""" + + def __init__(self): + """Load all templates and assets once.""" + self.index_template = None + self.file_template = None + self.index_css = None + self.index_js = None + self.file_css = None + self.file_js = None + self.logo_html = None + + self._load_templates() + + def _load_templates(self): + """Load all template files from _heatmap_assets.""" + try: + template_dir = importlib.resources.files(__package__) + assets_dir = template_dir / "_heatmap_assets" + + # Load HTML templates + self.index_template = (assets_dir / "heatmap_index_template.html").read_text(encoding="utf-8") + self.file_template = (assets_dir / "heatmap_pyfile_template.html").read_text(encoding="utf-8") + + # Load CSS (same file used for both index and file pages) + css_content = get_combined_css("heatmap") + self.index_css = css_content + self.file_css = css_content + + # Load JS + shared_js = (assets_dir / "heatmap_shared.js").read_text(encoding="utf-8") + self.index_js = f"{shared_js}\n{(assets_dir / 'heatmap_index.js').read_text(encoding='utf-8')}" + self.file_js = f"{shared_js}\n{(assets_dir / 'heatmap.js').read_text(encoding='utf-8')}" + + # Load Tachyon logo + logo_dir = template_dir / "_assets" + try: + png_path = logo_dir / "tachyon-logo.png" + b64_logo = base64.b64encode(png_path.read_bytes()).decode("ascii") + self.logo_html = f'' + except (FileNotFoundError, IOError) as e: + self.logo_html = '
    ' + print(f"Warning: Could not load Tachyon logo: {e}") + + except (FileNotFoundError, IOError) as e: + raise RuntimeError(f"Failed to load heatmap template files: {e}") from e + + +class _TreeBuilder: + """Builds hierarchical tree structure from file statistics.""" + + @staticmethod + def build_file_tree(file_stats: List[FileStats]) -> Dict[str, TreeNode]: + """Build hierarchical tree grouped by module type, then by module structure. + + Args: + file_stats: List of FileStats objects + + Returns: + Dictionary mapping module types to their tree roots + """ + # Group by module type first + type_groups = {'stdlib': [], 'site-packages': [], 'project': [], 'other': []} + for stat in file_stats: + type_groups[stat.module_type].append(stat) + + # Build tree for each type + trees = {} + for module_type, stats in type_groups.items(): + if not stats: + continue + + root_node = TreeNode() + + for stat in stats: + module_name = stat.module_name + parts = module_name.split('.') + + # Navigate/create tree structure + current_node = root_node + for i, part in enumerate(parts): + if i == len(parts) - 1: + # Last part - store the file + current_node.files.append(stat) + else: + # Intermediate part - create or navigate + if part not in current_node.children: + current_node.children[part] = TreeNode() + current_node = current_node.children[part] + + # Calculate aggregate stats for this type's tree + _TreeBuilder._calculate_node_stats(root_node) + trees[module_type] = root_node + + return trees + + @staticmethod + def _calculate_node_stats(node: TreeNode) -> Tuple[int, int]: + """Recursively calculate aggregate statistics for tree nodes. + + Args: + node: TreeNode to calculate stats for + + Returns: + Tuple of (total_samples, file_count) + """ + total_samples = 0 + file_count = 0 + + # Count files at this level + for file_stat in node.files: + total_samples += file_stat.total_samples + file_count += 1 + + # Recursively process children + for child in node.children.values(): + child_samples, child_count = _TreeBuilder._calculate_node_stats(child) + total_samples += child_samples + file_count += child_count + + node.samples = total_samples + node.count = file_count + return total_samples, file_count + + +class _HtmlRenderer: + """Renders hierarchical tree structures as HTML.""" + + def __init__(self, file_index: Dict[str, str]): + """Initialize renderer with file index. + + Args: + file_index: Mapping from filenames to HTML file names + """ + self.file_index = file_index + self.heatmap_bar_height = 16 + + def render_hierarchical_html(self, trees: Dict[str, TreeNode]) -> str: + """Build hierarchical HTML with type sections and collapsible module folders. + + Args: + trees: Dictionary mapping module types to tree roots + + Returns: + Complete HTML string for all sections + """ + type_names = { + 'stdlib': '📚 Standard Library', + 'site-packages': '📦 Site Packages', + 'project': '🏗️ Project Files', + 'other': '📄 Other Files' + } + + sections = [] + for module_type in ['project', 'stdlib', 'site-packages', 'other']: + if module_type not in trees: + continue + + tree = trees[module_type] + + # Project starts expanded, others start collapsed + is_collapsed = module_type in {'stdlib', 'site-packages', 'other'} + icon = '▶' if is_collapsed else '▼' + content_style = ' style="display: none;"' if is_collapsed else '' + + file_word = "file" if tree.count == 1 else "files" + sample_word = "sample" if tree.samples == 1 else "samples" + section_html = f''' +
    +
    + {icon} + {type_names[module_type]} + ({tree.count} {file_word}, {tree.samples:,} {sample_word}) +
    +
    +''' + + # Render root folders + root_folders = sorted(tree.children.items(), + key=lambda x: x[1].samples, reverse=True) + + for folder_name, folder_node in root_folders: + section_html += self._render_folder(folder_node, folder_name, level=1) + + # Render root files (files not in any module) + if tree.files: + sorted_files = sorted(tree.files, key=lambda x: x.total_samples, reverse=True) + section_html += '
    \n' + for stat in sorted_files: + section_html += self._render_file_item(stat, indent=' ') + section_html += '
    \n' + + section_html += '
    \n
    \n' + sections.append(section_html) + + return '\n'.join(sections) + + def _render_folder(self, node: TreeNode, name: str, level: int = 1) -> str: + """Render a single folder node recursively. + + Args: + node: TreeNode to render + name: Display name for the folder + level: Nesting level for indentation + + Returns: + HTML string for this folder and its contents + """ + indent = ' ' * level + parts = [] + + # Render folder header (collapsed by default) + file_word = "file" if node.count == 1 else "files" + sample_word = "sample" if node.samples == 1 else "samples" + parts.append(f'{indent}') + + return '\n'.join(parts) + + def _render_file_item(self, stat: FileStats, indent: str = '') -> str: + """Render a single file item with heatmap bar. + + Args: + stat: FileStats object + indent: Indentation string + + Returns: + HTML string for file item + """ + full_path = html.escape(stat.filename) + module_name = html.escape(stat.module_name) + + intensity = stat.percentage / 100.0 + bar_width = min(stat.percentage, 100) + + html_file = self.file_index[stat.filename] + + return (f'{indent}
    \n' + f'{indent} 📄 {module_name}\n' + f'{indent} {stat.total_samples:,} samples\n' + f'{indent}
    \n' + f'{indent}
    \n') + + +# ============================================================================ +# Main Collector Class +# ============================================================================ + +class HeatmapCollector(StackTraceCollector): + """Collector that generates coverage.py-style heatmap HTML output with line intensity. + + This collector creates detailed HTML reports showing which lines of code + were executed most frequently during profiling, similar to coverage.py + but showing execution "heat" rather than just coverage. + """ + + # File naming and formatting constants + FILE_INDEX_FORMAT = "file_{:04d}.html" + + def __init__(self, *args, **kwargs): + """Initialize the heatmap collector with data structures for analysis.""" + super().__init__(*args, **kwargs) + + # Sample counting data structures + self.line_samples = collections.Counter() + self.file_samples = collections.defaultdict(collections.Counter) + self.line_self_samples = collections.Counter() + self.file_self_samples = collections.defaultdict(collections.Counter) + + # Call graph data structures for navigation (sets for O(1) deduplication) + self.call_graph = collections.defaultdict(set) + self.callers_graph = collections.defaultdict(set) + self.function_definitions = {} + + # Edge counting for call path analysis + self.edge_samples = collections.Counter() + + # Bytecode-level tracking data structures + # Track samples per (file, lineno) -> {opcode: {'count': N, 'locations': set()}} + # Locations are deduplicated via set to minimize memory usage + self.line_opcodes = collections.defaultdict(dict) + + # Statistics and metadata + self._total_samples = 0 + self._path_info = get_python_path_info() + self.stats = {} + + # Opcode collection flag + self.opcodes_enabled = False + + # Template loader (loads all templates once) + self._template_loader = _TemplateLoader() + + # File index (populated during export) + self.file_index = {} + + # Reusable set for deduplicating line locations within a single sample. + # This avoids over-counting recursive functions in cumulative stats. + self._seen_lines = set() + + def set_stats(self, sample_interval_usec, duration_sec, sample_rate, error_rate=None, missed_samples=None, **kwargs): + """Set profiling statistics to include in heatmap output. + + Args: + sample_interval_usec: Sampling interval in microseconds + duration_sec: Total profiling duration in seconds + sample_rate: Effective sampling rate + error_rate: Optional error rate during profiling + missed_samples: Optional percentage of missed samples + **kwargs: Additional statistics to include + """ + self.stats = { + "sample_interval_usec": sample_interval_usec, + "duration_sec": duration_sec, + "sample_rate": sample_rate, + "error_rate": error_rate, + "missed_samples": missed_samples, + "python_version": sys.version, + "python_implementation": platform.python_implementation(), + "platform": platform.platform(), + } + self.stats.update(kwargs) + + def process_frames(self, frames, thread_id): + """Process stack frames and count samples per line. + + Args: + frames: List of (filename, location, funcname, opcode) tuples in + leaf-to-root order. location is (lineno, end_lineno, col_offset, end_col_offset). + opcode is None if not gathered. + thread_id: Thread ID for this stack trace + """ + self._total_samples += 1 + self._seen_lines.clear() + + for i, (filename, location, funcname, opcode) in enumerate(frames): + # Normalize location to 4-tuple format + lineno, end_lineno, col_offset, end_col_offset = normalize_location(location) + + if not self._is_valid_frame(filename, lineno): + continue + + # frames[0] is the leaf - where execution is actually happening + is_leaf = (i == 0) + line_key = (filename, lineno) + count_cumulative = line_key not in self._seen_lines + if count_cumulative: + self._seen_lines.add(line_key) + + self._record_line_sample(filename, lineno, funcname, is_leaf=is_leaf, + count_cumulative=count_cumulative) + + if opcode is not None: + # Set opcodes_enabled flag when we first encounter opcode data + self.opcodes_enabled = True + self._record_bytecode_sample(filename, lineno, opcode, + end_lineno, col_offset, end_col_offset) + + # Build call graph for adjacent frames + if i + 1 < len(frames): + next_frame = frames[i + 1] + next_lineno = extract_lineno(next_frame[1]) + self._record_call_relationship( + (filename, lineno, funcname), + (next_frame[0], next_lineno, next_frame[2]) + ) + + def _is_valid_frame(self, filename, lineno): + """Check if a frame should be included in the heatmap.""" + # Skip internal or invalid files + if not filename or filename.startswith('<') or filename.startswith('['): + return False + + # Skip invalid frames with corrupted filename data + if filename == "__init__" and lineno == 0: + return False + + return True + + def _record_line_sample(self, filename, lineno, funcname, is_leaf=False, + count_cumulative=True): + """Record a sample for a specific line.""" + # Track cumulative samples (all occurrences in stack) + if count_cumulative: + self.line_samples[(filename, lineno)] += 1 + self.file_samples[filename][lineno] += 1 + + # Track self/leaf samples (only when at top of stack) + if is_leaf: + self.line_self_samples[(filename, lineno)] += 1 + self.file_self_samples[filename][lineno] += 1 + + # Record function definition location + if funcname and (filename, funcname) not in self.function_definitions: + self.function_definitions[(filename, funcname)] = lineno + + def _record_bytecode_sample(self, filename, lineno, opcode, + end_lineno=None, col_offset=None, end_col_offset=None): + """Record a sample for a specific bytecode instruction. + + Args: + filename: Source filename + lineno: Line number + opcode: Opcode number being executed + end_lineno: End line number (may be -1 if not available) + col_offset: Column offset in UTF-8 bytes (may be -1 if not available) + end_col_offset: End column offset in UTF-8 bytes (may be -1 if not available) + """ + key = (filename, lineno) + + # Initialize opcode entry if needed - use set for location deduplication + if opcode not in self.line_opcodes[key]: + self.line_opcodes[key][opcode] = {'count': 0, 'locations': set()} + + self.line_opcodes[key][opcode]['count'] += 1 + + # Store unique location info if column offset is available (not -1) + if col_offset is not None and col_offset >= 0: + # Use tuple as set key for deduplication + loc_key = (end_lineno, col_offset, end_col_offset) + self.line_opcodes[key][opcode]['locations'].add(loc_key) + + def _get_bytecode_data_for_line(self, filename, lineno): + """Get bytecode disassembly data for instructions on a specific line. + + Args: + filename: Source filename + lineno: Line number + + Returns: + List of dicts with instruction info, sorted by samples descending + """ + from .opcode_utils import get_opcode_info, format_opcode + + key = (filename, lineno) + opcode_data = self.line_opcodes.get(key, {}) + + result = [] + for opcode, data in opcode_data.items(): + info = get_opcode_info(opcode) + # Handle both old format (int count) and new format (dict with count/locations) + if isinstance(data, dict): + count = data.get('count', 0) + raw_locations = data.get('locations', set()) + # Convert set of tuples to list of dicts for JSON serialization + if isinstance(raw_locations, set): + locations = [ + {'end_lineno': loc[0], 'col_offset': loc[1], 'end_col_offset': loc[2]} + for loc in raw_locations + ] + else: + locations = raw_locations + else: + count = data + locations = [] + + result.append({ + 'opcode': opcode, + 'opname': format_opcode(opcode), + 'base_opname': info['base_opname'], + 'is_specialized': info['is_specialized'], + 'samples': count, + 'locations': locations, + }) + + # Sort by samples descending, then by opcode number + result.sort(key=lambda x: (-x['samples'], x['opcode'])) + return result + + def _record_call_relationship(self, callee_frame, caller_frame): + """Record caller/callee relationship between adjacent frames.""" + callee_filename, callee_lineno, callee_funcname = callee_frame + caller_filename, caller_lineno, caller_funcname = caller_frame + + # Skip internal files for call graph + if callee_filename.startswith('<') or callee_filename.startswith('['): + return + + # Get the callee's function definition line + callee_def_line = self.function_definitions.get( + (callee_filename, callee_funcname), callee_lineno + ) + + # Record caller -> callee relationship (set handles deduplication) + caller_key = (caller_filename, caller_lineno) + callee_info = (callee_filename, callee_def_line, callee_funcname) + self.call_graph[caller_key].add(callee_info) + + # Record callee <- caller relationship (set handles deduplication) + callee_key = (callee_filename, callee_def_line) + caller_info = (caller_filename, caller_lineno, caller_funcname) + self.callers_graph[callee_key].add(caller_info) + + # Count this call edge for path analysis + edge_key = (caller_key, callee_key) + self.edge_samples[edge_key] += 1 + + def export(self, output_path): + """Export heatmap data as HTML files in a directory. + + Args: + output_path: Path where to create the heatmap output directory + """ + if not self.file_samples: + print("Warning: No heatmap data to export") + return + + try: + output_dir = self._prepare_output_directory(output_path) + file_stats = self._calculate_file_stats() + self._create_file_index(file_stats) + + # Generate individual file reports + self._generate_file_reports(output_dir, file_stats) + + # Generate index page + self._generate_index_html(output_dir / 'index.html', file_stats) + + self._print_export_summary(output_dir, file_stats) + + except Exception as e: + print(f"Error: Failed to export heatmap: {e}") + raise + + def _prepare_output_directory(self, output_path): + """Create output directory for heatmap files.""" + output_dir = Path(output_path) + if output_dir.suffix == '.html': + output_dir = output_dir.with_suffix('') + + try: + output_dir.mkdir(exist_ok=True, parents=True) + except (IOError, OSError) as e: + raise RuntimeError(f"Failed to create output directory {output_dir}: {e}") from e + + return output_dir + + def _create_file_index(self, file_stats: List[FileStats]): + """Create mapping from filenames to HTML file names.""" + self.file_index = { + stat.filename: self.FILE_INDEX_FORMAT.format(i) + for i, stat in enumerate(file_stats) + } + + def _generate_file_reports(self, output_dir, file_stats: List[FileStats]): + """Generate HTML report for each source file.""" + for stat in file_stats: + file_path = output_dir / self.file_index[stat.filename] + line_counts = self.file_samples[stat.filename] + valid_line_counts = {line: count for line, count in line_counts.items() if line >= 0} + + self_counts = self.file_self_samples.get(stat.filename, {}) + valid_self_counts = {line: count for line, count in self_counts.items() if line >= 0} + + self._generate_file_html( + file_path, + stat.filename, + valid_line_counts, + valid_self_counts, + stat + ) + + def _print_export_summary(self, output_dir, file_stats: List[FileStats]): + """Print summary of exported heatmap.""" + print(f"Heatmap output written to {output_dir}/") + print(f" - Index: {output_dir / 'index.html'}") + print(f" - {len(file_stats)} source file(s) analyzed") + + def _calculate_file_stats(self) -> List[FileStats]: + """Calculate statistics for each file. + + Returns: + List of FileStats objects sorted by total samples + """ + file_stats = [] + for filename, line_counts in self.file_samples.items(): + # Skip special frames + if filename in ('~', '...', '.') or filename.startswith('<') or filename.startswith('['): + continue + + # Filter out lines with -1 (special frames) + valid_line_counts = {line: count for line, count in line_counts.items() if line >= 0} + if not valid_line_counts: + continue + + # Get self samples for this file + self_line_counts = self.file_self_samples.get(filename, {}) + valid_self_counts = {line: count for line, count in self_line_counts.items() if line >= 0} + + total_samples = sum(valid_line_counts.values()) + total_self_samples = sum(valid_self_counts.values()) + num_lines = len(valid_line_counts) + max_samples = max(valid_line_counts.values()) + max_self_samples = max(valid_self_counts.values()) if valid_self_counts else 0 + module_name, module_type = extract_module_name(filename, self._path_info) + + file_stats.append(FileStats( + filename=filename, + module_name=module_name, + module_type=module_type, + total_samples=total_samples, + total_self_samples=total_self_samples, + num_lines=num_lines, + max_samples=max_samples, + max_self_samples=max_self_samples, + percentage=0.0 + )) + + # Sort by total samples and calculate percentages + file_stats.sort(key=lambda x: x.total_samples, reverse=True) + if file_stats: + max_total = file_stats[0].total_samples + for stat in file_stats: + stat.percentage = (stat.total_samples / max_total * 100) if max_total > 0 else 0 + + return file_stats + + def _generate_index_html(self, index_path: Path, file_stats: List[FileStats]): + """Generate index.html with list of all profiled files.""" + # Build hierarchical tree + tree = _TreeBuilder.build_file_tree(file_stats) + + # Render tree as HTML + renderer = _HtmlRenderer(self.file_index) + sections_html = renderer.render_hierarchical_html(tree) + + # Format error rate and missed samples with bar classes + error_rate = self.stats.get('error_rate') + if error_rate is not None: + error_rate_str = f"{error_rate:.1f}%" + error_rate_width = min(error_rate, 100) + # Determine bar color class based on rate + if error_rate < 5: + error_rate_class = "good" + elif error_rate < 15: + error_rate_class = "warning" + else: + error_rate_class = "error" + else: + error_rate_str = "N/A" + error_rate_width = 0 + error_rate_class = "good" + + missed_samples = self.stats.get('missed_samples') + if missed_samples is not None: + missed_samples_str = f"{missed_samples:.1f}%" + missed_samples_width = min(missed_samples, 100) + if missed_samples < 5: + missed_samples_class = "good" + elif missed_samples < 15: + missed_samples_class = "warning" + else: + missed_samples_class = "error" + else: + missed_samples_str = "N/A" + missed_samples_width = 0 + missed_samples_class = "good" + + # Populate template + replacements = { + "": f"", + "": f"", + "": self._template_loader.logo_html, + "": f"{sys.version_info.major}.{sys.version_info.minor}", + "": str(len(file_stats)), + "": f"{self._total_samples:,}", + "": f"{self.stats.get('duration_sec', 0):.1f}s", + "": f"{self.stats.get('sample_rate', 0):.1f}", + "": error_rate_str, + "": str(error_rate_width), + "": error_rate_class, + "": missed_samples_str, + "": str(missed_samples_width), + "": missed_samples_class, + "": sections_html, + } + + html_content = self._template_loader.index_template + for placeholder, value in replacements.items(): + html_content = html_content.replace(placeholder, value) + + try: + index_path.write_text(html_content, encoding='utf-8') + except (IOError, OSError) as e: + raise RuntimeError(f"Failed to write index file {index_path}: {e}") from e + + def _generate_file_html(self, output_path: Path, filename: str, + line_counts: Dict[int, int], self_counts: Dict[int, int], + file_stat: FileStats): + """Generate HTML for a single source file with heatmap coloring.""" + # Read source file + try: + source_lines = Path(filename).read_text(encoding='utf-8', errors='replace').splitlines() + except (IOError, OSError) as e: + if not (filename.startswith('<') or filename.startswith('[') or + filename in ('~', '...', '.') or len(filename) < 2): + print(f"Warning: Could not read source file {filename}: {e}") + source_lines = [f"# Source file not available: {filename}"] + + # Generate HTML for each line + max_samples = max(line_counts.values()) if line_counts else 1 + max_self_samples = max(self_counts.values()) if self_counts else 1 + code_lines_html = [ + self._build_line_html(line_num, line_content, line_counts, self_counts, + max_samples, max_self_samples, filename) + for line_num, line_content in enumerate(source_lines, start=1) + ] + + # Populate template + replacements = { + "": html.escape(filename), + "": f"{file_stat.total_samples:,}", + "": f"{file_stat.total_self_samples:,}", + "": str(file_stat.num_lines), + "": f"{file_stat.percentage:.2f}", + "": str(file_stat.max_samples), + "": str(file_stat.max_self_samples), + "": ''.join(code_lines_html), + "": f"", + "": f"", + "": self._template_loader.logo_html, + "": f"{sys.version_info.major}.{sys.version_info.minor}", + } + + html_content = self._template_loader.file_template + for placeholder, value in replacements.items(): + html_content = html_content.replace(placeholder, value) + + try: + output_path.write_text(html_content, encoding='utf-8') + except (IOError, OSError) as e: + raise RuntimeError(f"Failed to write file {output_path}: {e}") from e + + def _build_line_html(self, line_num: int, line_content: str, + line_counts: Dict[int, int], self_counts: Dict[int, int], + max_samples: int, max_self_samples: int, filename: str) -> str: + """Build HTML for a single line of source code.""" + cumulative_samples = line_counts.get(line_num, 0) + self_samples = self_counts.get(line_num, 0) + + # Calculate colors for both self and cumulative modes + if cumulative_samples > 0: + log_cumulative = math.log(cumulative_samples + 1) + log_max = math.log(max_samples + 1) + cumulative_intensity = log_cumulative / log_max if log_max > 0 else 0 + + if self_samples > 0 and max_self_samples > 0: + log_self = math.log(self_samples + 1) + log_max_self = math.log(max_self_samples + 1) + self_intensity = log_self / log_max_self if log_max_self > 0 else 0 + else: + self_intensity = 0 + + self_display = f"{self_samples:,}" if self_samples > 0 else "" + cumulative_display = f"{cumulative_samples:,}" + tooltip = f"Self: {self_samples:,}, Total: {cumulative_samples:,}" + else: + cumulative_intensity = 0 + self_intensity = 0 + self_display = "" + cumulative_display = "" + tooltip = "" + + # Get bytecode data for this line (if any) + bytecode_data = self._get_bytecode_data_for_line(filename, line_num) + has_bytecode = len(bytecode_data) > 0 and cumulative_samples > 0 + + # Build bytecode toggle button if data is available + bytecode_btn_html = '' + bytecode_panel_html = '' + if has_bytecode: + bytecode_json = html.escape(json.dumps(bytecode_data)) + + # Calculate specialization percentage + total_samples = sum(d['samples'] for d in bytecode_data) + specialized_samples = sum(d['samples'] for d in bytecode_data if d['is_specialized']) + spec_pct = int(100 * specialized_samples / total_samples) if total_samples > 0 else 0 + + bytecode_btn_html = ( + f'' + ) + # Wrapper contains columns + content panel + bytecode_panel_html = ( + f'
    \n' + f'
    ' + f'
    ' + f'
    ' + f'
    ' + f'
    \n' + f'
    \n' + f'
    \n' + ) + elif self.opcodes_enabled: + # Add invisible spacer to maintain consistent indentation when opcodes are enabled + bytecode_btn_html = '
    ' + + # Get navigation buttons + nav_buttons_html = self._build_navigation_buttons(filename, line_num) + + # Build line HTML with instruction highlights if available + line_html = self._render_source_with_highlights(line_content, line_num, + filename, bytecode_data) + title_attr = f' title="{html.escape(tooltip)}"' if tooltip else "" + + # Specialization color for toggle mode (green gradient based on spec %) + spec_color_attr = '' + if has_bytecode: + spec_color = self._format_specialization_color(spec_pct) + spec_color_attr = f'data-spec-color="{spec_color}" ' + + return ( + f'
    \n' + f'
    {line_num}
    \n' + f'
    {self_display}
    \n' + f'
    {cumulative_display}
    \n' + f' {bytecode_btn_html}\n' + f'
    {line_html}
    \n' + f' {nav_buttons_html}\n' + f'
    \n' + f'{bytecode_panel_html}' + ) + + def _render_source_with_highlights(self, line_content: str, line_num: int, + filename: str, bytecode_data: list) -> str: + """Render source line with instruction highlight spans. + + Simple: collect ranges with sample counts, assign each byte position to + smallest covering range, then emit spans for contiguous runs with sample data. + """ + import html as html_module + + content = line_content.rstrip('\n') + if not content: + return '' + + # Collect all (start, end) -> {samples, opcodes} mapping from instructions + # Multiple instructions may share the same range, so we sum samples and collect opcodes + range_data = {} + for instr in bytecode_data: + samples = instr.get('samples', 0) + opname = instr.get('opname', '') + for loc in instr.get('locations', []): + if loc.get('end_lineno', line_num) == line_num: + start, end = loc.get('col_offset', -1), loc.get('end_col_offset', -1) + if start >= 0 and end >= 0: + key = (start, end) + if key not in range_data: + range_data[key] = {'samples': 0, 'opcodes': []} + range_data[key]['samples'] += samples + if opname and opname not in range_data[key]['opcodes']: + range_data[key]['opcodes'].append(opname) + + if not range_data: + return html_module.escape(content) + + # For each byte position, find the smallest covering range + byte_to_range = {} + for (start, end) in range_data.keys(): + for pos in range(start, end): + if pos not in byte_to_range: + byte_to_range[pos] = (start, end) + else: + # Keep smaller range + old_start, old_end = byte_to_range[pos] + if (end - start) < (old_end - old_start): + byte_to_range[pos] = (start, end) + + # Calculate totals for percentage and intensity + total_line_samples = sum(d['samples'] for d in range_data.values()) + max_range_samples = max(d['samples'] for d in range_data.values()) if range_data else 1 + + # Render character by character + result = [] + byte_offset = 0 + char_idx = 0 + current_range = None + span_chars = [] + + def flush_span(): + nonlocal span_chars, current_range + if span_chars: + text = html_module.escape(''.join(span_chars)) + if current_range: + data = range_data.get(current_range, {'samples': 0, 'opcodes': []}) + samples = data['samples'] + opcodes = ', '.join(data['opcodes'][:3]) # Top 3 opcodes + if len(data['opcodes']) > 3: + opcodes += f" +{len(data['opcodes']) - 3} more" + pct = int(100 * samples / total_line_samples) if total_line_samples > 0 else 0 + result.append(f'{text}') + else: + result.append(text) + span_chars = [] + + while char_idx < len(content): + char = content[char_idx] + char_bytes = len(char.encode('utf-8')) + char_range = byte_to_range.get(byte_offset) + + if char_range != current_range: + flush_span() + current_range = char_range + + span_chars.append(char) + byte_offset += char_bytes + char_idx += 1 + + flush_span() + return ''.join(result) + + def _format_specialization_color(self, spec_pct: int) -> str: + """Format specialization color based on percentage. + + Uses a gradient from gray (0%) through orange (50%) to green (100%). + """ + # Normalize to 0-1 + ratio = spec_pct / 100.0 + + if ratio >= 0.5: + # Orange to green (50-100%) + t = (ratio - 0.5) * 2 # 0 to 1 + r = int(255 * (1 - t)) # 255 -> 0 + g = int(180 + 75 * t) # 180 -> 255 + b = int(50 * (1 - t)) # 50 -> 0 + else: + # Gray to orange (0-50%) + t = ratio * 2 # 0 to 1 + r = int(158 + 97 * t) # 158 -> 255 + g = int(158 + 22 * t) # 158 -> 180 + b = int(158 - 108 * t) # 158 -> 50 + + alpha = 0.15 + 0.25 * ratio # 0.15 to 0.4 + return f"rgba({r}, {g}, {b}, {alpha})" + + def _build_navigation_buttons(self, filename: str, line_num: int) -> str: + """Build navigation buttons for callers/callees.""" + line_key = (filename, line_num) + caller_list = self._deduplicate_by_function(self.callers_graph.get(line_key, set())) + callee_list = self._deduplicate_by_function(self.call_graph.get(line_key, set())) + + # Get edge counts for each caller/callee + callers_with_counts = self._get_edge_counts(line_key, caller_list, is_caller=True) + callees_with_counts = self._get_edge_counts(line_key, callee_list, is_caller=False) + + # Build navigation buttons with counts + caller_btn = self._create_navigation_button(callers_with_counts, 'caller', '▲') + callee_btn = self._create_navigation_button(callees_with_counts, 'callee', '▼') + + if caller_btn or callee_btn: + return f'
    {caller_btn}{callee_btn}
    ' + return '' + + def _get_edge_counts(self, line_key: Tuple[str, int], + items: List[Tuple[str, int, str]], + is_caller: bool) -> List[Tuple[str, int, str, int]]: + """Get sample counts for each caller/callee edge.""" + result = [] + for file, line, func in items: + edge_line_key = (file, line) + if is_caller: + edge_key = (edge_line_key, line_key) + else: + edge_key = (line_key, edge_line_key) + + count = self.edge_samples.get(edge_key, 0) + result.append((file, line, func, count)) + + result.sort(key=lambda x: x[3], reverse=True) + return result + + def _deduplicate_by_function(self, items) -> List[Tuple[str, int, str]]: + """Remove duplicate entries based on (file, function) key. + + Args: + items: Iterable of (file, line, func) tuples (set or list) + """ + seen = {} + result = [] + for file, line, func in items: + key = (file, func) + if key not in seen: + seen[key] = True + result.append((file, line, func)) + return result + + def _create_navigation_button(self, items_with_counts: List[Tuple[str, int, str, int]], + btn_class: str, arrow: str) -> str: + """Create HTML for a navigation button with sample counts.""" + # Filter valid items + valid_items = [(f, l, fn, cnt) for f, l, fn, cnt in items_with_counts + if f in self.file_index and l > 0] + if not valid_items: + return "" + + if len(valid_items) == 1: + file, line, func, count = valid_items[0] + target_html = self.file_index[file] + nav_data = json.dumps({'link': f"{target_html}#line-{line}", 'func': func}) + title = f"Go to {btn_class}: {html.escape(func)} ({count:,} samples)" + return f'' + + # Multiple items - create menu + total_samples = sum(cnt for _, _, _, cnt in valid_items) + items_data = [ + { + 'file': os.path.basename(file), + 'func': func, + 'count': count, + 'link': f"{self.file_index[file]}#line-{line}" + } + for file, line, func, count in valid_items + ] + items_json = html.escape(json.dumps(items_data)) + title = f"{len(items_data)} {btn_class}s ({total_samples:,} samples)" + return f'' diff --git a/Lib/profiling/sampling/live_collector/__init__.py b/Lib/profiling/sampling/live_collector/__init__.py new file mode 100644 index 00000000000..175e4610d23 --- /dev/null +++ b/Lib/profiling/sampling/live_collector/__init__.py @@ -0,0 +1,200 @@ +"""Live profiling collector that displays top-like statistics using curses. + + ┌─────────────────────────────┐ + │ Target Python Process │ + │ (being profiled) │ + └──────────────┬──────────────┘ + │ Stack sampling at + │ configured interval + │ (e.g., 10000µs) + ▼ + ┌─────────────────────────────┐ + │ LiveStatsCollector │ + │ ┌───────────────────────┐ │ + │ │ collect() │ │ Aggregates samples + │ │ - Iterates frames │ │ into statistics + │ │ - Updates counters │ │ + │ └───────────┬───────────┘ │ + │ │ │ + │ ▼ │ + │ ┌───────────────────────┐ │ + │ │ Data Storage │ │ + │ │ - result dict │ │ Tracks per-function: + │ │ - direct_calls │ │ • Direct samples + │ │ - cumulative_calls │ │ • Cumulative samples + │ └───────────┬───────────┘ │ • Derived time stats + │ │ │ + │ ▼ │ + │ ┌───────────────────────┐ │ + │ │ Display Update │ │ + │ │ (10Hz by default) │ │ Rate-limited refresh + │ └───────────┬───────────┘ │ + └──────────────┼──────────────┘ + │ + ▼ + ┌─────────────────────────────┐ + │ DisplayInterface │ + │ (Abstract layer) │ + └──────────────┬──────────────┘ + ┌───────┴────────┐ + │ │ + ┌──────────▼────────┐ ┌───▼──────────┐ + │ CursesDisplay │ │ MockDisplay │ + │ - Real terminal │ │ - Testing │ + │ - ncurses backend │ │ - No UI │ + └─────────┬─────────┘ └──────────────┘ + │ + ▼ + ┌─────────────────────────────────────┐ + │ Widget-Based Rendering │ + │ ┌─────────────────────────────────┐ │ + │ │ HeaderWidget │ │ + │ │ • PID, uptime, time, interval │ │ + │ │ • Sample stats & progress bar │ │ + │ │ • Efficiency bar │ │ + │ │ • Thread status & GC stats │ │ + │ │ • Function summary │ │ + │ │ • Top 3 hottest functions │ │ + │ ├─────────────────────────────────┤ │ + │ │ TableWidget │ │ + │ │ • Column headers (sortable) │ │ Interactive display + │ │ • Stats rows (scrolling) │ │ with keyboard controls: + │ │ - nsamples % time │ │ s: sort, p: pause + │ │ - function file:line │ │ r: reset, /: filter + │ ├─────────────────────────────────┤ │ q: quit, h: help + │ │ FooterWidget │ │ + │ │ • Legend and status │ │ + │ │ • Filter input prompt │ │ + │ └─────────────────────────────────┘ │ + └─────────────────────────────────────┘ + +Architecture: + +The live collector is organized into four layers. The data collection layer +(LiveStatsCollector) aggregates stack samples into per-function statistics without +any knowledge of how they will be presented. The display abstraction layer +(DisplayInterface) defines rendering operations without coupling to curses or any +specific UI framework. The widget layer (Widget, HeaderWidget, TableWidget, +FooterWidget, HelpWidget, ProgressBarWidget) encapsulates individual UI components +with their own rendering logic, promoting modularity and reusability. The +presentation layer (CursesDisplay/MockDisplay) implements the actual rendering for +terminal output and testing. + +The system runs two independent update loops. The sampling loop is driven by the +profiler at the configured interval (e.g., 10000µs) and continuously collects +stack frames and updates statistics. The display loop runs at a fixed refresh rate +(default 10Hz) and updates the terminal independently of sampling frequency. This +separation allows high-frequency sampling without overwhelming the terminal with +constant redraws. + +Statistics are computed incrementally as samples arrive. The collector maintains +running counters (direct calls and cumulative calls) in a dictionary keyed by +function location. Derived metrics like time estimates and percentages are computed +on-demand during display updates rather than being stored, which minimizes memory +overhead as the number of tracked functions grows. + +User input is processed asynchronously during display updates using non-blocking I/O. +This allows interactive controls (sorting, filtering, pausing) without interrupting +the data collection pipeline. The collector maintains mode flags (paused, +filter_input_mode) that affect what gets displayed but not what gets collected. + +""" + +# Re-export all public classes and constants for backward compatibility +from .collector import LiveStatsCollector +from .display import DisplayInterface, CursesDisplay, MockDisplay +from .widgets import ( + Widget, + ProgressBarWidget, + HeaderWidget, + TableWidget, + FooterWidget, + HelpWidget, +) +from .constants import ( + MICROSECONDS_PER_SECOND, + DISPLAY_UPDATE_HZ, + DISPLAY_UPDATE_INTERVAL, + MIN_TERMINAL_WIDTH, + MIN_TERMINAL_HEIGHT, + WIDTH_THRESHOLD_SAMPLE_PCT, + WIDTH_THRESHOLD_TOTTIME, + WIDTH_THRESHOLD_CUMUL_PCT, + WIDTH_THRESHOLD_CUMTIME, + HEADER_LINES, + FOOTER_LINES, + SAFETY_MARGIN, + TOP_FUNCTIONS_DISPLAY_COUNT, + COL_WIDTH_NSAMPLES, + COL_SPACING, + COL_WIDTH_SAMPLE_PCT, + COL_WIDTH_TIME, + MIN_FUNC_NAME_WIDTH, + MAX_FUNC_NAME_WIDTH, + MIN_AVAILABLE_SPACE, + MIN_BAR_WIDTH, + MAX_SAMPLE_RATE_BAR_WIDTH, + MAX_EFFICIENCY_BAR_WIDTH, + MIN_SAMPLE_RATE_FOR_SCALING, + FINISHED_BANNER_EXTRA_LINES, + COLOR_PAIR_HEADER_BG, + COLOR_PAIR_CYAN, + COLOR_PAIR_YELLOW, + COLOR_PAIR_GREEN, + COLOR_PAIR_MAGENTA, + COLOR_PAIR_RED, + COLOR_PAIR_SORTED_HEADER, + DEFAULT_SORT_BY, + DEFAULT_DISPLAY_LIMIT, +) + +__all__ = [ + # Main collector + "LiveStatsCollector", + # Display interfaces + "DisplayInterface", + "CursesDisplay", + "MockDisplay", + # Widgets + "Widget", + "ProgressBarWidget", + "HeaderWidget", + "TableWidget", + "FooterWidget", + "HelpWidget", + # Constants + "MICROSECONDS_PER_SECOND", + "DISPLAY_UPDATE_HZ", + "DISPLAY_UPDATE_INTERVAL", + "MIN_TERMINAL_WIDTH", + "MIN_TERMINAL_HEIGHT", + "WIDTH_THRESHOLD_SAMPLE_PCT", + "WIDTH_THRESHOLD_TOTTIME", + "WIDTH_THRESHOLD_CUMUL_PCT", + "WIDTH_THRESHOLD_CUMTIME", + "HEADER_LINES", + "FOOTER_LINES", + "SAFETY_MARGIN", + "TOP_FUNCTIONS_DISPLAY_COUNT", + "COL_WIDTH_NSAMPLES", + "COL_SPACING", + "COL_WIDTH_SAMPLE_PCT", + "COL_WIDTH_TIME", + "MIN_FUNC_NAME_WIDTH", + "MAX_FUNC_NAME_WIDTH", + "MIN_AVAILABLE_SPACE", + "MIN_BAR_WIDTH", + "MAX_SAMPLE_RATE_BAR_WIDTH", + "MAX_EFFICIENCY_BAR_WIDTH", + "MIN_SAMPLE_RATE_FOR_SCALING", + "FINISHED_BANNER_EXTRA_LINES", + "COLOR_PAIR_HEADER_BG", + "COLOR_PAIR_CYAN", + "COLOR_PAIR_YELLOW", + "COLOR_PAIR_GREEN", + "COLOR_PAIR_MAGENTA", + "COLOR_PAIR_RED", + "COLOR_PAIR_SORTED_HEADER", + "DEFAULT_SORT_BY", + "DEFAULT_DISPLAY_LIMIT", +] diff --git a/Lib/profiling/sampling/live_collector/collector.py b/Lib/profiling/sampling/live_collector/collector.py new file mode 100644 index 00000000000..28af2e97445 --- /dev/null +++ b/Lib/profiling/sampling/live_collector/collector.py @@ -0,0 +1,1126 @@ +"""LiveStatsCollector - Main collector class for live profiling.""" + +import collections +import contextlib +import curses +from dataclasses import dataclass, field +import os +import site +import sys +import sysconfig +import time +import _colorize + +from ..collector import Collector, extract_lineno +from ..constants import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, + THREAD_STATUS_UNKNOWN, + THREAD_STATUS_GIL_REQUESTED, + THREAD_STATUS_HAS_EXCEPTION, + PROFILING_MODE_CPU, + PROFILING_MODE_GIL, + PROFILING_MODE_WALL, +) +from .constants import ( + MICROSECONDS_PER_SECOND, + DISPLAY_UPDATE_INTERVAL, + MIN_TERMINAL_WIDTH, + MIN_TERMINAL_HEIGHT, + HEADER_LINES, + FOOTER_LINES, + SAFETY_MARGIN, + FINISHED_BANNER_EXTRA_LINES, + DEFAULT_SORT_BY, + DEFAULT_DISPLAY_LIMIT, + COLOR_PAIR_HEADER_BG, + COLOR_PAIR_CYAN, + COLOR_PAIR_YELLOW, + COLOR_PAIR_GREEN, + COLOR_PAIR_MAGENTA, + COLOR_PAIR_RED, + COLOR_PAIR_SORTED_HEADER, +) +from .display import CursesDisplay +from .widgets import HeaderWidget, TableWidget, FooterWidget, HelpWidget, OpcodePanel +from .trend_tracker import TrendTracker + + +@dataclass +class ThreadData: + """Encapsulates all profiling data for a single thread.""" + + thread_id: int + + # Function call statistics: {location: {direct_calls: int, cumulative_calls: int}} + result: dict = field(default_factory=lambda: collections.defaultdict( + lambda: dict(direct_calls=0, cumulative_calls=0) + )) + + # Thread status statistics + has_gil: int = 0 + on_cpu: int = 0 + gil_requested: int = 0 + unknown: int = 0 + has_exception: int = 0 + total: int = 0 # Total status samples for this thread + + # Sample counts + sample_count: int = 0 + gc_frame_samples: int = 0 + + # Opcode statistics: {location: {opcode: count}} + opcode_stats: dict = field(default_factory=lambda: collections.defaultdict( + lambda: collections.defaultdict(int) + )) + + def increment_status_flag(self, status_flags): + """Update status counts based on status bit flags.""" + if status_flags & THREAD_STATUS_HAS_GIL: + self.has_gil += 1 + if status_flags & THREAD_STATUS_ON_CPU: + self.on_cpu += 1 + if status_flags & THREAD_STATUS_GIL_REQUESTED: + self.gil_requested += 1 + if status_flags & THREAD_STATUS_UNKNOWN: + self.unknown += 1 + if status_flags & THREAD_STATUS_HAS_EXCEPTION: + self.has_exception += 1 + self.total += 1 + + def as_status_dict(self): + """Return status counts as a dict for compatibility.""" + return { + "has_gil": self.has_gil, + "on_cpu": self.on_cpu, + "gil_requested": self.gil_requested, + "unknown": self.unknown, + "has_exception": self.has_exception, + "total": self.total, + } + + +class LiveStatsCollector(Collector): + """Collector that displays live top-like statistics using ncurses.""" + + def __init__( + self, + sample_interval_usec, + *, + skip_idle=False, + sort_by=DEFAULT_SORT_BY, + limit=DEFAULT_DISPLAY_LIMIT, + pid=None, + display=None, + mode=None, + opcodes=False, + async_aware=None, + ): + """ + Initialize the live stats collector. + + Args: + sample_interval_usec: Sampling interval in microseconds + skip_idle: Whether to skip idle threads + sort_by: Sort key ('tottime', 'nsamples', 'cumtime', 'sample_pct', 'cumul_pct') + limit: Maximum number of functions to display + pid: Process ID being profiled + display: DisplayInterface implementation (None means curses will be used) + mode: Profiling mode ('cpu', 'gil', etc.) - affects what stats are shown + opcodes: Whether to show opcode panel (requires --opcodes flag) + async_aware: Async tracing mode - None (sync only), "all" or "running" + """ + self.result = collections.defaultdict( + lambda: dict(total_rec_calls=0, direct_calls=0, cumulative_calls=0) + ) + self.sample_interval_usec = sample_interval_usec + self.sample_interval_sec = ( + sample_interval_usec / MICROSECONDS_PER_SECOND + ) + self.skip_idle = skip_idle + self.sort_by = sort_by + self.limit = limit + self.total_samples = 0 + self.start_time = None + self.stdscr = None + self.display = display # DisplayInterface implementation + self.running = True + self.pid = pid + self.mode = mode # Profiling mode + self.async_aware = async_aware # Async tracing mode + # Pre-select frame iterator method to avoid per-call dispatch overhead + self._get_frame_iterator = self._get_async_frame_iterator if async_aware else self._get_sync_frame_iterator + self._saved_stdout = None + self._saved_stderr = None + self._devnull = None + self._last_display_update = None + self.max_sample_rate = 0 # Track maximum sample rate seen + self.successful_samples = 0 # Track samples that captured frames + self.failed_samples = 0 # Track samples that failed to capture frames + self.display_update_interval = DISPLAY_UPDATE_INTERVAL # Instance variable for display refresh rate + + # Thread status statistics (bit flags) + self.thread_status_counts = { + "has_gil": 0, + "on_cpu": 0, + "gil_requested": 0, + "unknown": 0, + "has_exception": 0, + "total": 0, # Total thread count across all samples + } + self.gc_frame_samples = 0 # Track samples with GC frames + + # Opcode statistics: {location: {opcode: count}} + self.opcode_stats = collections.defaultdict(lambda: collections.defaultdict(int)) + self.show_opcodes = opcodes # Show opcode panel when --opcodes flag is passed + self.selected_row = 0 # Currently selected row in table for opcode view + self.scroll_offset = 0 # Scroll offset for table when in opcode mode + + # Interactive controls state + self.paused = False # Pause UI updates (profiling continues) + self.show_help = False # Show help screen + self.filter_pattern = None # Glob pattern to filter functions + self.filter_input_mode = False # Currently entering filter text + self.filter_input_buffer = "" # Buffer for filter input + self.finished = False # Program has finished, showing final state + self.finish_timestamp = None # When profiling finished (for time freezing) + self.finish_wall_time = None # Wall clock time when profiling finished + + # Thread tracking state + self.thread_ids = [] # List of thread IDs seen + self.view_mode = "ALL" # "ALL" or "PER_THREAD" + self.current_thread_index = ( + 0 # Index into thread_ids when in PER_THREAD mode + ) + self.per_thread_data = {} # {thread_id: ThreadData} + + # Calculate common path prefixes to strip + self._path_prefixes = self._get_common_path_prefixes() + + # Widgets (initialized when display is available) + self.header_widget = None + self.table_widget = None + self.footer_widget = None + self.help_widget = None + self.opcode_panel = None + + # Color mode + self._can_colorize = _colorize.can_colorize() + + # Trend tracking (initialized after colors are set up) + self._trend_tracker = None + + self._seen_locations = set() + + @property + def elapsed_time(self): + """Get the elapsed time, frozen when finished.""" + if self.finished and self.finish_timestamp is not None: + return self.finish_timestamp - self.start_time + return time.perf_counter() - self.start_time if self.start_time else 0 + + @property + def current_time_display(self): + """Get the current time for display, frozen when finished.""" + if self.finished and self.finish_wall_time is not None: + return time.strftime("%H:%M:%S", time.localtime(self.finish_wall_time)) + return time.strftime("%H:%M:%S") + + def _get_or_create_thread_data(self, thread_id): + """Get or create ThreadData for a thread ID.""" + if thread_id not in self.per_thread_data: + self.per_thread_data[thread_id] = ThreadData(thread_id=thread_id) + return self.per_thread_data[thread_id] + + def _get_current_thread_data(self): + """Get ThreadData for currently selected thread in PER_THREAD mode.""" + if self.view_mode == "PER_THREAD" and self.current_thread_index < len(self.thread_ids): + thread_id = self.thread_ids[self.current_thread_index] + return self.per_thread_data.get(thread_id) + return None + + def _get_current_result_source(self): + """Get result dict for current view mode (aggregated or per-thread).""" + if self.view_mode == "ALL": + return self.result + thread_data = self._get_current_thread_data() + return thread_data.result if thread_data else {} + + def _get_common_path_prefixes(self): + """Get common path prefixes to strip from file paths.""" + prefixes = [] + + # Get the actual stdlib location from the os module + # This works for both installed Python and development builds + os_module_file = os.__file__ + if os_module_file: + # os.__file__ points to os.py, get its directory + stdlib_dir = os.path.dirname(os.path.abspath(os_module_file)) + prefixes.append(stdlib_dir) + + # Get stdlib location from sysconfig (may be different or same) + stdlib_path = sysconfig.get_path("stdlib") + if stdlib_path: + prefixes.append(stdlib_path) + + # Get platstdlib location (platform-specific stdlib) + platstdlib_path = sysconfig.get_path("platstdlib") + if platstdlib_path: + prefixes.append(platstdlib_path) + + # Get site-packages locations + for site_path in site.getsitepackages(): + prefixes.append(site_path) + + # Also check user site-packages + user_site = site.getusersitepackages() + if user_site: + prefixes.append(user_site) + + # Remove duplicates and sort by length (longest first) to match most specific paths first + prefixes = list(set(prefixes)) + prefixes.sort(key=lambda x: len(x), reverse=True) + + return prefixes + + def simplify_path(self, filepath): + """Simplify a file path by removing common prefixes.""" + # Try to match against known prefixes + for prefix_path in self._path_prefixes: + if filepath.startswith(prefix_path): + # Remove the prefix completely + relative = filepath[len(prefix_path) :].lstrip(os.sep) + return relative + + # If no match, return the original path + return filepath + + def process_frames(self, frames, thread_id=None): + """Process a single thread's frame stack. + + Args: + frames: List of frame information + thread_id: Thread ID for per-thread tracking (optional) + """ + if not frames: + return + + # Get per-thread data if tracking per-thread + thread_data = self._get_or_create_thread_data(thread_id) if thread_id is not None else None + self._seen_locations.clear() + + # Process each frame in the stack to track cumulative calls + # frame.location is (lineno, end_lineno, col_offset, end_col_offset), int, or None + for frame in frames: + lineno = extract_lineno(frame.location) + location = (frame.filename, lineno, frame.funcname) + if location not in self._seen_locations: + self._seen_locations.add(location) + self.result[location]["cumulative_calls"] += 1 + if thread_data: + thread_data.result[location]["cumulative_calls"] += 1 + + # The top frame gets counted as an inline call (directly executing) + top_frame = frames[0] + top_lineno = extract_lineno(top_frame.location) + top_location = (top_frame.filename, top_lineno, top_frame.funcname) + self.result[top_location]["direct_calls"] += 1 + if thread_data: + thread_data.result[top_location]["direct_calls"] += 1 + + # Track opcode for top frame (the actively executing instruction) + opcode = getattr(top_frame, 'opcode', None) + if opcode is not None: + self.opcode_stats[top_location][opcode] += 1 + if thread_data: + thread_data.opcode_stats[top_location][opcode] += 1 + + def _get_sync_frame_iterator(self, stack_frames): + """Iterator for sync frames.""" + return self._iter_all_frames(stack_frames, skip_idle=self.skip_idle) + + def _get_async_frame_iterator(self, stack_frames): + """Iterator for async frames, yielding (frames, thread_id) tuples.""" + for frames, thread_id, task_id in self._iter_async_frames(stack_frames): + yield frames, thread_id + + def collect_failed_sample(self): + self.failed_samples += 1 + self.total_samples += 1 + + def collect(self, stack_frames): + """Collect and display profiling data.""" + if self.start_time is None: + self.start_time = time.perf_counter() + self._last_display_update = self.start_time + + has_gc_frame = False + + # Collect thread status stats (only available in sync mode) + if not self.async_aware: + status_counts, sample_has_gc, per_thread_stats = self._collect_thread_status_stats(stack_frames) + for key, count in status_counts.items(): + self.thread_status_counts[key] += count + if sample_has_gc: + has_gc_frame = True + + for thread_id, stats in per_thread_stats.items(): + thread_data = self._get_or_create_thread_data(thread_id) + thread_data.has_gil += stats.get("has_gil", 0) + thread_data.on_cpu += stats.get("on_cpu", 0) + thread_data.gil_requested += stats.get("gil_requested", 0) + thread_data.unknown += stats.get("unknown", 0) + thread_data.has_exception += stats.get("has_exception", 0) + thread_data.total += stats.get("total", 0) + if stats.get("gc_samples", 0): + thread_data.gc_frame_samples += stats["gc_samples"] + + # Process frames using pre-selected iterator + frames_processed = False + for frames, thread_id in self._get_frame_iterator(stack_frames): + if not frames: + continue + + self.process_frames(frames, thread_id=thread_id) + frames_processed = True + + # Track thread IDs + if thread_id is not None and thread_id not in self.thread_ids: + self.thread_ids.append(thread_id) + + if thread_id is not None: + thread_data = self._get_or_create_thread_data(thread_id) + thread_data.sample_count += 1 + + if has_gc_frame: + self.gc_frame_samples += 1 + + # Count as successful - the sample worked even if no frames matched the filter + # (e.g., in --mode exception when no thread has an active exception) + self.successful_samples += 1 + self.total_samples += 1 + + # Handle input on every sample for instant responsiveness + if self.display is not None: + self._handle_input() + + # Update display at configured rate if display is initialized and not paused + if self.display is not None and not self.paused: + current_time = time.perf_counter() + if ( + self._last_display_update is None + or (current_time - self._last_display_update) + >= self.display_update_interval + ): + self._update_display() + self._last_display_update = current_time + + def _prepare_display_data(self, height): + """Prepare data for display rendering.""" + elapsed = self.elapsed_time + stats_list = self.build_stats_list() + + # Calculate available space for stats + # Add extra lines for finished banner when in finished state + extra_header_lines = ( + FINISHED_BANNER_EXTRA_LINES if self.finished else 0 + ) + max_stats_lines = max( + 0, + height + - HEADER_LINES + - extra_header_lines + - FOOTER_LINES + - SAFETY_MARGIN, + ) + stats_list = stats_list[:max_stats_lines] + + return elapsed, stats_list + + def _initialize_widgets(self, colors): + """Initialize widgets with display and colors.""" + if self.header_widget is None: + # Initialize trend tracker with colors + if self._trend_tracker is None: + self._trend_tracker = TrendTracker(colors, enabled=True) + + self.header_widget = HeaderWidget(self.display, colors, self) + self.table_widget = TableWidget(self.display, colors, self) + self.footer_widget = FooterWidget(self.display, colors, self) + self.help_widget = HelpWidget(self.display, colors) + self.opcode_panel = OpcodePanel(self.display, colors, self) + + def _render_display_sections( + self, height, width, elapsed, stats_list, colors + ): + """Render all display sections to the screen.""" + line = 0 + try: + # Initialize widgets if not already done + self._initialize_widgets(colors) + + # Render header + line = self.header_widget.render( + line, width, elapsed=elapsed, stats_list=stats_list + ) + + # Render table + line = self.table_widget.render( + line, width, height=height, stats_list=stats_list + ) + + # Render opcode panel if enabled + if self.show_opcodes: + line = self.opcode_panel.render( + line, width, height=height, stats_list=stats_list + ) + + except curses.error: + pass + + def _update_display(self): + """Update the display with current stats.""" + try: + # Clear screen and get dimensions + self.display.clear() + height, width = self.display.get_dimensions() + + # Check terminal size + if width < MIN_TERMINAL_WIDTH or height < MIN_TERMINAL_HEIGHT: + self._show_terminal_too_small(height, width) + self.display.refresh() + return + + # Setup colors and initialize widgets (needed for both help and normal display) + colors = self._setup_colors() + self._initialize_widgets(colors) + + # Show help screen if requested + if self.show_help: + self.help_widget.render(0, width, height=height) + self.display.refresh() + return + + # Prepare data + elapsed, stats_list = self._prepare_display_data(height) + + # Render all sections + self._render_display_sections( + height, width, elapsed, stats_list, colors + ) + + # Footer + self.footer_widget.render(height - 2, width) + + # Show filter input prompt if in filter input mode + if self.filter_input_mode: + self.footer_widget.render_filter_input_prompt( + height - 1, width + ) + + # Refresh display + self.display.redraw() + self.display.refresh() + + except Exception: + pass + + def _cycle_sort(self, reverse=False): + """Cycle through different sort modes in column order. + + Args: + reverse: If True, cycle backwards (right to left), otherwise forward (left to right) + """ + sort_modes = [ + "nsamples", + "sample_pct", + "tottime", + "cumul_pct", + "cumtime", + ] + try: + current_idx = sort_modes.index(self.sort_by) + if reverse: + self.sort_by = sort_modes[(current_idx - 1) % len(sort_modes)] + else: + self.sort_by = sort_modes[(current_idx + 1) % len(sort_modes)] + except ValueError: + self.sort_by = "nsamples" + + def _setup_colors(self): + """Set up color pairs and return color attributes.""" + + A_BOLD = self.display.get_attr("A_BOLD") + A_REVERSE = self.display.get_attr("A_REVERSE") + A_UNDERLINE = self.display.get_attr("A_UNDERLINE") + A_NORMAL = self.display.get_attr("A_NORMAL") + + # Check both curses color support and _colorize.can_colorize() + if self.display.has_colors() and self._can_colorize: + with contextlib.suppress(Exception): + # Color constants (using curses values for compatibility) + COLOR_CYAN = 6 + COLOR_GREEN = 2 + COLOR_YELLOW = 3 + COLOR_BLACK = 0 + COLOR_MAGENTA = 5 + COLOR_RED = 1 + + # Initialize all color pairs used throughout the UI + self.display.init_color_pair( + 1, COLOR_CYAN, -1 + ) # Data colors for stats rows + self.display.init_color_pair(2, COLOR_GREEN, -1) + self.display.init_color_pair(3, COLOR_YELLOW, -1) + self.display.init_color_pair( + COLOR_PAIR_HEADER_BG, COLOR_BLACK, COLOR_GREEN + ) + self.display.init_color_pair( + COLOR_PAIR_CYAN, COLOR_CYAN, COLOR_BLACK + ) + self.display.init_color_pair( + COLOR_PAIR_YELLOW, COLOR_YELLOW, COLOR_BLACK + ) + self.display.init_color_pair( + COLOR_PAIR_GREEN, COLOR_GREEN, COLOR_BLACK + ) + self.display.init_color_pair( + COLOR_PAIR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK + ) + self.display.init_color_pair( + COLOR_PAIR_RED, COLOR_RED, COLOR_BLACK + ) + self.display.init_color_pair( + COLOR_PAIR_SORTED_HEADER, COLOR_BLACK, COLOR_YELLOW + ) + + return { + "header": self.display.get_color_pair(COLOR_PAIR_HEADER_BG) + | A_BOLD, + "cyan": self.display.get_color_pair(COLOR_PAIR_CYAN) + | A_BOLD, + "yellow": self.display.get_color_pair(COLOR_PAIR_YELLOW) + | A_BOLD, + "green": self.display.get_color_pair(COLOR_PAIR_GREEN) + | A_BOLD, + "magenta": self.display.get_color_pair(COLOR_PAIR_MAGENTA) + | A_BOLD, + "red": self.display.get_color_pair(COLOR_PAIR_RED) + | A_BOLD, + "sorted_header": self.display.get_color_pair( + COLOR_PAIR_SORTED_HEADER + ) + | A_BOLD, + "normal_header": A_REVERSE | A_BOLD, + "color_samples": self.display.get_color_pair(1), + "color_file": self.display.get_color_pair(2), + "color_func": self.display.get_color_pair(3), + # Trend colors (stock-like indicators) + "trend_up": self.display.get_color_pair(COLOR_PAIR_GREEN) | A_BOLD, + "trend_down": self.display.get_color_pair(COLOR_PAIR_RED) | A_BOLD, + "trend_stable": A_NORMAL, + } + + # Fallback to non-color attributes + return { + "header": A_REVERSE | A_BOLD, + "cyan": A_BOLD, + "yellow": A_BOLD, + "green": A_BOLD, + "magenta": A_BOLD, + "red": A_BOLD, + "sorted_header": A_REVERSE | A_BOLD | A_UNDERLINE, + "normal_header": A_REVERSE | A_BOLD, + "color_samples": A_NORMAL, + "color_file": A_NORMAL, + "color_func": A_NORMAL, + # Trend colors (fallback to bold/normal for monochrome) + "trend_up": A_BOLD, + "trend_down": A_BOLD, + "trend_stable": A_NORMAL, + } + + def build_stats_list(self): + """Build and sort the statistics list.""" + stats_list = [] + result_source = self._get_current_result_source() + + for func, call_counts in result_source.items(): + # Apply filter if set (using substring matching) + if self.filter_pattern: + filename, lineno, funcname = func + # Simple substring match (case-insensitive) + pattern_lower = self.filter_pattern.lower() + filename_lower = filename.lower() + funcname_lower = funcname.lower() + + # Match if pattern is substring of filename, funcname, or combined + matched = ( + pattern_lower in filename_lower + or pattern_lower in funcname_lower + or pattern_lower in f"{filename_lower}:{funcname_lower}" + ) + if not matched: + continue + + direct_calls = call_counts.get("direct_calls", 0) + cumulative_calls = call_counts.get("cumulative_calls", 0) + total_time = direct_calls * self.sample_interval_sec + cumulative_time = cumulative_calls * self.sample_interval_sec + + # Calculate sample percentages using successful_samples as denominator + # This ensures percentages are relative to samples that actually had data, + # not all sampling attempts (important for filtered modes like --mode exception) + sample_pct = (direct_calls / self.successful_samples * 100) if self.successful_samples > 0 else 0 + cumul_pct = (cumulative_calls / self.successful_samples * 100) if self.successful_samples > 0 else 0 + + # Calculate trends for all columns using TrendTracker + trends = {} + if self._trend_tracker is not None: + trends = self._trend_tracker.update_metrics( + func, + { + 'nsamples': direct_calls, + 'tottime': total_time, + 'cumtime': cumulative_time, + 'sample_pct': sample_pct, + 'cumul_pct': cumul_pct, + } + ) + + stats_list.append( + { + "func": func, + "direct_calls": direct_calls, + "cumulative_calls": cumulative_calls, + "total_time": total_time, + "cumulative_time": cumulative_time, + "sample_pct": sample_pct, + "cumul_pct": cumul_pct, + "trends": trends, + } + ) + + # Sort the stats + if self.sort_by == "nsamples": + stats_list.sort(key=lambda x: x["direct_calls"], reverse=True) + elif self.sort_by == "tottime": + stats_list.sort(key=lambda x: x["total_time"], reverse=True) + elif self.sort_by == "cumtime": + stats_list.sort(key=lambda x: x["cumulative_time"], reverse=True) + elif self.sort_by == "sample_pct": + stats_list.sort(key=lambda x: x["sample_pct"], reverse=True) + elif self.sort_by == "cumul_pct": + stats_list.sort(key=lambda x: x["cumul_pct"], reverse=True) + + return stats_list + + def reset_stats(self): + """Reset all collected statistics.""" + self.result.clear() + self.per_thread_data.clear() + self.thread_ids.clear() + self.view_mode = "ALL" + self.current_thread_index = 0 + self.total_samples = 0 + self.successful_samples = 0 + self.failed_samples = 0 + self.max_sample_rate = 0 + self.thread_status_counts = { + "has_gil": 0, + "on_cpu": 0, + "gil_requested": 0, + "unknown": 0, + "has_exception": 0, + "total": 0, + } + self.gc_frame_samples = 0 + # Clear trend tracking + if self._trend_tracker is not None: + self._trend_tracker.clear() + # Reset finished state and finish timestamp + self.finished = False + self.finish_timestamp = None + self.finish_wall_time = None + self.start_time = time.perf_counter() + self._last_display_update = self.start_time + + def mark_finished(self): + """Mark the profiling session as finished.""" + self.finished = True + # Capture the finish timestamp to freeze all timing displays + self.finish_timestamp = time.perf_counter() + self.finish_wall_time = time.time() # Wall clock time for display + # Force a final display update to show the finished message + if self.display is not None: + self._update_display() + + def _handle_finished_input_update(self, had_input): + """Update display after input when program is finished.""" + if self.finished and had_input and self.display is not None: + self._update_display() + + def _get_visible_rows_info(self): + """Calculate visible rows and stats list for opcode navigation.""" + stats_list = self.build_stats_list() + if self.display: + height, _ = self.display.get_dimensions() + extra_header = FINISHED_BANNER_EXTRA_LINES if self.finished else 0 + max_stats = max(0, height - HEADER_LINES - extra_header - FOOTER_LINES - SAFETY_MARGIN) + stats_list = stats_list[:max_stats] + visible_rows = max(1, height - 8 - 2 - 12) + else: + visible_rows = self.limit + total_rows = len(stats_list) + return stats_list, visible_rows, total_rows + + def _move_selection_down(self): + """Move selection down in opcode mode with scrolling.""" + if not self.show_opcodes: + return + + stats_list, visible_rows, total_rows = self._get_visible_rows_info() + if total_rows == 0: + return + + # Max scroll is when last item is at bottom + max_scroll = max(0, total_rows - visible_rows) + # Current absolute position + abs_pos = self.scroll_offset + self.selected_row + + # Only move if not at the last item + if abs_pos < total_rows - 1: + # Try to move selection within visible area first + if self.selected_row < visible_rows - 1: + self.selected_row += 1 + elif self.scroll_offset < max_scroll: + # Scroll down + self.scroll_offset += 1 + + # Clamp to valid range + self.scroll_offset = min(self.scroll_offset, max_scroll) + max_selected = min(visible_rows - 1, total_rows - self.scroll_offset - 1) + self.selected_row = min(self.selected_row, max(0, max_selected)) + + def _move_selection_up(self): + """Move selection up in opcode mode with scrolling.""" + if not self.show_opcodes: + return + + if self.selected_row > 0: + self.selected_row -= 1 + elif self.scroll_offset > 0: + self.scroll_offset -= 1 + + # Clamp to valid range based on actual stats_list + stats_list, visible_rows, total_rows = self._get_visible_rows_info() + if total_rows > 0: + max_scroll = max(0, total_rows - visible_rows) + self.scroll_offset = min(self.scroll_offset, max_scroll) + max_selected = min(visible_rows - 1, total_rows - self.scroll_offset - 1) + self.selected_row = min(self.selected_row, max(0, max_selected)) + + def _navigate_to_previous_thread(self): + """Navigate to previous thread in PER_THREAD mode, or switch from ALL to PER_THREAD.""" + if len(self.thread_ids) > 0: + if self.view_mode == "ALL": + self.view_mode = "PER_THREAD" + self.current_thread_index = len(self.thread_ids) - 1 + else: + self.current_thread_index = ( + self.current_thread_index - 1 + ) % len(self.thread_ids) + + def _navigate_to_next_thread(self): + """Navigate to next thread in PER_THREAD mode, or switch from ALL to PER_THREAD.""" + if len(self.thread_ids) > 0: + if self.view_mode == "ALL": + self.view_mode = "PER_THREAD" + self.current_thread_index = 0 + else: + self.current_thread_index = ( + self.current_thread_index + 1 + ) % len(self.thread_ids) + + def _show_terminal_too_small(self, height, width): + """Display a message when terminal is too small.""" + A_BOLD = self.display.get_attr("A_BOLD") + msg1 = "Terminal too small!" + msg2 = f"Need: {MIN_TERMINAL_WIDTH}x{MIN_TERMINAL_HEIGHT}" + msg3 = f"Have: {width}x{height}" + msg4 = "Please resize" + + # Center the messages + if height >= 4: + self.display.add_str( + height // 2 - 2, + max(0, (width - len(msg1)) // 2), + msg1[: width - 1], + A_BOLD, + ) + self.display.add_str( + height // 2 - 1, + max(0, (width - len(msg2)) // 2), + msg2[: width - 1], + ) + self.display.add_str( + height // 2, + max(0, (width - len(msg3)) // 2), + msg3[: width - 1], + ) + self.display.add_str( + height // 2 + 1, + max(0, (width - len(msg4)) // 2), + msg4[: width - 1], + ) + elif height >= 1: + self.display.add_str(0, 0, msg1[: width - 1], A_BOLD) + + def _show_terminal_size_warning_and_wait(self, height, width): + """Show terminal size warning during initialization and wait for user acknowledgment.""" + A_BOLD = self.display.get_attr("A_BOLD") + A_DIM = self.display.get_attr("A_DIM") + + self.display.clear() + msg1 = "WARNING: Terminal too small!" + msg2 = f"Required: {MIN_TERMINAL_WIDTH}x{MIN_TERMINAL_HEIGHT}" + msg3 = f"Current: {width}x{height}" + msg4 = "Please resize your terminal for best experience" + msg5 = "Press any key to continue..." + + # Center the messages + if height >= 5: + self.display.add_str( + height // 2 - 2, + max(0, (width - len(msg1)) // 2), + msg1[: width - 1], + A_BOLD, + ) + self.display.add_str( + height // 2 - 1, + max(0, (width - len(msg2)) // 2), + msg2[: width - 1], + ) + self.display.add_str( + height // 2, + max(0, (width - len(msg3)) // 2), + msg3[: width - 1], + ) + self.display.add_str( + height // 2 + 1, + max(0, (width - len(msg4)) // 2), + msg4[: width - 1], + ) + self.display.add_str( + height // 2 + 3, + max(0, (width - len(msg5)) // 2), + msg5[: width - 1], + A_DIM, + ) + elif height >= 1: + self.display.add_str(0, 0, msg1[: width - 1], A_BOLD) + + self.display.refresh() + # Wait for user acknowledgment (2 seconds timeout) + self.display.set_nodelay(False) + # Note: timeout is curses-specific, skipping for now + self.display.get_input() + self.display.set_nodelay(True) + + def _handle_input(self): + """Handle keyboard input (non-blocking).""" + from . import constants + + self.display.set_nodelay(True) + ch = self.display.get_input() + + # Handle filter input mode FIRST - takes precedence over all commands + if self.filter_input_mode: + if ch == 27: # ESC key + self.filter_input_mode = False + self.filter_input_buffer = "" + elif ch == 10 or ch == 13: # Enter key + self.filter_pattern = ( + self.filter_input_buffer + if self.filter_input_buffer + else None + ) + self.filter_input_mode = False + self.filter_input_buffer = "" + elif ch == 127 or ch == 263: # Backspace + if self.filter_input_buffer: + self.filter_input_buffer = self.filter_input_buffer[:-1] + elif ch >= 32 and ch < 127: # Printable characters + self.filter_input_buffer += chr(ch) + + # Update display if input was processed while finished + self._handle_finished_input_update(ch != -1) + return + + # Handle help toggle keys + if ch == ord("h") or ch == ord("H") or ch == ord("?"): + self.show_help = not self.show_help + return + + # If showing help, any other key closes it + if self.show_help and ch != -1: + self.show_help = False + return + + # Handle regular commands + if ch == ord("q") or ch == ord("Q"): + self.running = False + + elif ch == ord("s"): + self._cycle_sort(reverse=False) + + elif ch == ord("S"): + self._cycle_sort(reverse=True) + + elif ch == ord("p") or ch == ord("P"): + self.paused = not self.paused + + elif ch == ord("r") or ch == ord("R"): + # Don't allow reset when profiling is finished + if not self.finished: + self.reset_stats() + + elif ch == ord("+") or ch == ord("="): + # Decrease update interval (faster refresh) + self.display_update_interval = max( + 0.05, self.display_update_interval - 0.05 + ) # Min 20Hz + + elif ch == ord("-") or ch == ord("_"): + # Increase update interval (slower refresh) + self.display_update_interval = min( + 1.0, self.display_update_interval + 0.05 + ) # Max 1Hz + + elif ch == ord("c") or ch == ord("C"): + if self.filter_pattern: + self.filter_pattern = None + + elif ch == ord("/"): + self.filter_input_mode = True + self.filter_input_buffer = self.filter_pattern or "" + + elif ch == ord("t") or ch == ord("T"): + # Toggle between ALL and PER_THREAD modes + if self.view_mode == "ALL": + if len(self.thread_ids) > 0: + self.view_mode = "PER_THREAD" + self.current_thread_index = 0 + else: + self.view_mode = "ALL" + + elif ch == ord("x") or ch == ord("X"): + # Toggle trend colors on/off + if self._trend_tracker is not None: + self._trend_tracker.toggle() + + elif ch == ord("j") or ch == ord("J"): + # Move selection down in opcode mode (with scrolling) + self._move_selection_down() + + elif ch == ord("k") or ch == ord("K"): + # Move selection up in opcode mode (with scrolling) + self._move_selection_up() + + elif ch == curses.KEY_UP: + # Move selection up (same as 'k') when in opcode mode + if self.show_opcodes: + self._move_selection_up() + else: + # Navigate to previous thread (same as KEY_LEFT) + self._navigate_to_previous_thread() + + elif ch == curses.KEY_DOWN: + # Move selection down (same as 'j') when in opcode mode + if self.show_opcodes: + self._move_selection_down() + else: + # Navigate to next thread (same as KEY_RIGHT) + self._navigate_to_next_thread() + + elif ch == curses.KEY_LEFT: + # Navigate to previous thread + self._navigate_to_previous_thread() + + elif ch == curses.KEY_RIGHT: + # Navigate to next thread + self._navigate_to_next_thread() + + # Update display if input was processed while finished + self._handle_finished_input_update(ch != -1) + + def init_curses(self, stdscr): + """Initialize curses display and suppress stdout/stderr.""" + self.stdscr = stdscr + self.display = CursesDisplay(stdscr) + + # Check terminal size upfront and warn if too small + height, width = self.display.get_dimensions() + + if width < MIN_TERMINAL_WIDTH or height < MIN_TERMINAL_HEIGHT: + # Show warning and wait briefly for user to see it + self._show_terminal_size_warning_and_wait(height, width) + + curses.curs_set(0) # Hide cursor + stdscr.nodelay(True) # Non-blocking input + stdscr.scrollok(False) # Disable scrolling + stdscr.idlok(False) # Disable hardware insert/delete + stdscr.leaveok(True) # Don't care about cursor position + + if curses.has_colors(): + curses.start_color() + curses.use_default_colors() + + # Suppress stdout and stderr to prevent interfering with curses display + # Use contextlib.redirect_stdout/stderr for better resource management + self._saved_stdout = sys.stdout + self._saved_stderr = sys.stderr + # Open devnull and ensure it's cleaned up even if an exception occurs + try: + self._devnull = open(os.devnull, "w") + sys.stdout = self._devnull + sys.stderr = self._devnull + except Exception: + # If redirection fails, restore original streams + sys.stdout = self._saved_stdout + sys.stderr = self._saved_stderr + raise + + # Initial clear + self.display.clear() + self.display.refresh() + + def cleanup_curses(self): + """Clean up curses display and restore stdout/stderr.""" + # Restore stdout and stderr in reverse order + # Use try-finally to ensure cleanup even if restoration fails + try: + if self._saved_stdout is not None: + sys.stdout = self._saved_stdout + self._saved_stdout = None + if self._saved_stderr is not None: + sys.stderr = self._saved_stderr + self._saved_stderr = None + finally: + # Always close devnull, even if stdout/stderr restoration fails + if self._devnull is not None: + with contextlib.suppress(Exception): + self._devnull.close() + self._devnull = None + + if self.display is not None and self.stdscr is not None: + with contextlib.suppress(Exception): + curses.curs_set(1) # Show cursor + self.display.set_nodelay(False) + + def export(self, filename): + """Export is not supported in live mode.""" + raise NotImplementedError( + "Export to file is not supported in live mode. " + "Use the live TUI to view statistics in real-time." + ) diff --git a/Lib/profiling/sampling/live_collector/constants.py b/Lib/profiling/sampling/live_collector/constants.py new file mode 100644 index 00000000000..8462c0de3fd --- /dev/null +++ b/Lib/profiling/sampling/live_collector/constants.py @@ -0,0 +1,62 @@ +"""Constants for the live profiling collector.""" + +# Time conversion constants +MICROSECONDS_PER_SECOND = 1_000_000 + +# Display update constants +DISPLAY_UPDATE_HZ = 10 +DISPLAY_UPDATE_INTERVAL = 1.0 / DISPLAY_UPDATE_HZ # 0.1 seconds + +# Terminal size constraints +MIN_TERMINAL_WIDTH = 60 +MIN_TERMINAL_HEIGHT = 12 + +# Column width thresholds +WIDTH_THRESHOLD_SAMPLE_PCT = 80 +WIDTH_THRESHOLD_TOTTIME = 100 +WIDTH_THRESHOLD_CUMUL_PCT = 120 +WIDTH_THRESHOLD_CUMTIME = 140 + +# Display layout constants +HEADER_LINES = 10 # Increased to include thread status line +FOOTER_LINES = 2 +SAFETY_MARGIN = 1 +TOP_FUNCTIONS_DISPLAY_COUNT = 3 + +# Column widths for data display +COL_WIDTH_NSAMPLES = 13 +COL_SPACING = 2 +COL_WIDTH_SAMPLE_PCT = 5 +COL_WIDTH_TIME = 10 + +# Function name display +MIN_FUNC_NAME_WIDTH = 10 +MAX_FUNC_NAME_WIDTH = 40 +MIN_AVAILABLE_SPACE = 10 + +# Progress bar display +MIN_BAR_WIDTH = 10 +MAX_SAMPLE_RATE_BAR_WIDTH = 30 +MAX_EFFICIENCY_BAR_WIDTH = 60 + +# Sample rate scaling +MIN_SAMPLE_RATE_FOR_SCALING = 100 + +# Finished banner display +FINISHED_BANNER_EXTRA_LINES = 3 # Blank line + banner + blank line + +# Opcode panel display +OPCODE_PANEL_HEIGHT = 12 # Height reserved for opcode statistics panel + +# Color pair IDs +COLOR_PAIR_HEADER_BG = 4 +COLOR_PAIR_CYAN = 5 +COLOR_PAIR_YELLOW = 6 +COLOR_PAIR_GREEN = 7 +COLOR_PAIR_MAGENTA = 8 +COLOR_PAIR_RED = 9 +COLOR_PAIR_SORTED_HEADER = 10 + +# Default display settings +DEFAULT_SORT_BY = "nsamples" # Number of samples in leaf (self time) +DEFAULT_DISPLAY_LIMIT = 20 diff --git a/Lib/profiling/sampling/live_collector/display.py b/Lib/profiling/sampling/live_collector/display.py new file mode 100644 index 00000000000..d7f65ad73fd --- /dev/null +++ b/Lib/profiling/sampling/live_collector/display.py @@ -0,0 +1,236 @@ +"""Display interface abstractions for the live profiling collector.""" + +import contextlib +import curses +from abc import ABC, abstractmethod + + +class DisplayInterface(ABC): + """Abstract interface for display operations to enable testing.""" + + @abstractmethod + def get_dimensions(self): + """Get terminal dimensions as (height, width).""" + pass + + @abstractmethod + def clear(self): + """Clear the screen.""" + pass + + @abstractmethod + def refresh(self): + """Refresh the screen to show changes.""" + pass + + @abstractmethod + def redraw(self): + """Redraw the entire window.""" + pass + + @abstractmethod + def add_str(self, line, col, text, attr=0): + """Add a string at the specified position.""" + pass + + @abstractmethod + def get_input(self): + """Get a character from input (non-blocking). Returns -1 if no input.""" + pass + + @abstractmethod + def set_nodelay(self, flag): + """Set non-blocking mode for input.""" + pass + + @abstractmethod + def has_colors(self): + """Check if terminal supports colors.""" + pass + + @abstractmethod + def init_color_pair(self, pair_id, fg, bg): + """Initialize a color pair.""" + pass + + @abstractmethod + def get_color_pair(self, pair_id): + """Get a color pair attribute.""" + pass + + @abstractmethod + def get_attr(self, name): + """Get a display attribute by name (e.g., 'A_BOLD', 'A_REVERSE').""" + pass + + +class CursesDisplay(DisplayInterface): + """Real curses display implementation.""" + + def __init__(self, stdscr): + self.stdscr = stdscr + + def get_dimensions(self): + return self.stdscr.getmaxyx() + + def clear(self): + self.stdscr.clear() + + def refresh(self): + self.stdscr.refresh() + + def redraw(self): + self.stdscr.redrawwin() + + def add_str(self, line, col, text, attr=0): + try: + height, width = self.get_dimensions() + if 0 <= line < height and 0 <= col < width: + max_len = width - col - 1 + if len(text) > max_len: + text = text[:max_len] + self.stdscr.addstr(line, col, text, attr) + except curses.error: + pass + + def get_input(self): + try: + return self.stdscr.getch() + except (KeyError, curses.error): + return -1 + + def set_nodelay(self, flag): + self.stdscr.nodelay(flag) + + def has_colors(self): + return curses.has_colors() + + def init_color_pair(self, pair_id, fg, bg): + try: + curses.init_pair(pair_id, fg, bg) + except curses.error: + pass + + def get_color_pair(self, pair_id): + return curses.color_pair(pair_id) + + def get_attr(self, name): + return getattr(curses, name, 0) + + +class MockDisplay(DisplayInterface): + """Mock display for testing.""" + + def __init__(self, height=40, width=160): + self.height = height + self.width = width + self.buffer = {} + self.cleared = False + self.refreshed = False + self.redrawn = False + self.input_queue = [] + self.nodelay_flag = True + self.colors_supported = True + self.color_pairs = {} + + def get_dimensions(self): + return (self.height, self.width) + + def clear(self): + self.buffer.clear() + self.cleared = True + + def refresh(self): + self.refreshed = True + + def redraw(self): + self.redrawn = True + + def add_str(self, line, col, text, attr=0): + if 0 <= line < self.height and 0 <= col < self.width: + max_len = self.width - col - 1 + if len(text) > max_len: + text = text[:max_len] + self.buffer[(line, col)] = (text, attr) + + def get_input(self): + if self.input_queue: + return self.input_queue.pop(0) + return -1 + + def set_nodelay(self, flag): + self.nodelay_flag = flag + + def has_colors(self): + return self.colors_supported + + def init_color_pair(self, pair_id, fg, bg): + self.color_pairs[pair_id] = (fg, bg) + + def get_color_pair(self, pair_id): + return pair_id << 8 + + def get_attr(self, name): + attrs = { + "A_NORMAL": 0, + "A_BOLD": 1 << 16, + "A_REVERSE": 1 << 17, + "A_UNDERLINE": 1 << 18, + "A_DIM": 1 << 19, + } + return attrs.get(name, 0) + + def simulate_input(self, char): + """Helper method for tests to simulate keyboard input.""" + self.input_queue.append(char) + + def get_text_at(self, line, col): + """Helper method for tests to inspect buffer content.""" + if (line, col) in self.buffer: + return self.buffer[(line, col)][0] + return None + + def get_all_lines(self): + """Get all display content as a list of lines (for testing).""" + if not self.buffer: + return [] + + max_line = max(pos[0] for pos in self.buffer.keys()) + lines = [] + for line_num in range(max_line + 1): + line_parts = [] + for col in range(self.width): + if (line_num, col) in self.buffer: + text, _ = self.buffer[(line_num, col)] + line_parts.append((col, text)) + + # Reconstruct line from parts + if line_parts: + line_parts.sort(key=lambda x: x[0]) + line = "" + last_col = 0 + for col, text in line_parts: + if col > last_col: + line += " " * (col - last_col) + line += text + last_col = col + len(text) + lines.append(line.rstrip()) + else: + lines.append("") + + # Remove trailing empty lines + while lines and not lines[-1]: + lines.pop() + + return lines + + def find_text(self, pattern): + """Find text matching pattern in buffer (for testing). Returns (line, col) or None.""" + for (line, col), (text, _) in self.buffer.items(): + if pattern in text: + return (line, col) + return None + + def contains_text(self, text): + """Check if display contains the given text anywhere (for testing).""" + return self.find_text(text) is not None diff --git a/Lib/profiling/sampling/live_collector/trend_tracker.py b/Lib/profiling/sampling/live_collector/trend_tracker.py new file mode 100644 index 00000000000..c025b83a134 --- /dev/null +++ b/Lib/profiling/sampling/live_collector/trend_tracker.py @@ -0,0 +1,157 @@ +"""TrendTracker - Encapsulated trend tracking for live profiling metrics. + +This module provides trend tracking functionality for profiling metrics, +calculating direction indicators (up/down/stable) and managing associated +visual attributes like colors. +""" + +import curses +from typing import Dict, Literal, Any + +TrendDirection = Literal["up", "down", "stable"] + + +class TrendTracker: + """ + Tracks metric trends over time and provides visual indicators. + + This class encapsulates all logic for: + - Tracking previous values of metrics + - Calculating trend directions (up/down/stable) + - Determining visual attributes (colors) for trends + - Managing enable/disable state + + Example: + tracker = TrendTracker(colors_dict) + tracker.update("func1", "nsamples", 10) + trend = tracker.get_trend("func1", "nsamples") + color = tracker.get_color("func1", "nsamples") + """ + + # Threshold for determining if a value has changed significantly + CHANGE_THRESHOLD = 0.001 + + def __init__(self, colors: Dict[str, int], enabled: bool = True): + """ + Initialize the trend tracker. + + Args: + colors: Dictionary containing color attributes including + 'trend_up', 'trend_down', 'trend_stable' + enabled: Whether trend tracking is initially enabled + """ + self._previous_values: Dict[Any, Dict[str, float]] = {} + self._enabled = enabled + self._colors = colors + + @property + def enabled(self) -> bool: + """Whether trend tracking is enabled.""" + return self._enabled + + def toggle(self) -> bool: + """ + Toggle trend tracking on/off. + + Returns: + New enabled state + """ + self._enabled = not self._enabled + return self._enabled + + def set_enabled(self, enabled: bool) -> None: + """Set trend tracking enabled state.""" + self._enabled = enabled + + def update(self, key: Any, metric: str, value: float) -> TrendDirection: + """ + Update a metric value and calculate its trend. + + Args: + key: Identifier for the entity (e.g., function) + metric: Name of the metric (e.g., 'nsamples', 'tottime') + value: Current value of the metric + + Returns: + Trend direction: 'up', 'down', or 'stable' + """ + # Initialize storage for this key if needed + if key not in self._previous_values: + self._previous_values[key] = {} + + # Get previous value, defaulting to current if not tracked yet + prev_value = self._previous_values[key].get(metric, value) + + # Calculate trend + if value > prev_value + self.CHANGE_THRESHOLD: + trend = "up" + elif value < prev_value - self.CHANGE_THRESHOLD: + trend = "down" + else: + trend = "stable" + + # Update previous value for next iteration + self._previous_values[key][metric] = value + + return trend + + def get_trend(self, key: Any, metric: str) -> TrendDirection: + """ + Get the current trend for a metric without updating. + + Args: + key: Identifier for the entity + metric: Name of the metric + + Returns: + Trend direction, or 'stable' if not tracked + """ + # This would require storing trends separately, which we don't do + # For now, return stable if not found + return "stable" + + def get_color(self, trend: TrendDirection) -> int: + """ + Get the color attribute for a trend direction. + + Args: + trend: The trend direction + + Returns: + Curses color attribute (or A_NORMAL if disabled) + """ + if not self._enabled: + return curses.A_NORMAL + + if trend == "up": + return self._colors.get("trend_up", curses.A_BOLD) + elif trend == "down": + return self._colors.get("trend_down", curses.A_BOLD) + else: # stable + return self._colors.get("trend_stable", curses.A_NORMAL) + + def update_metrics(self, key: Any, metrics: Dict[str, float]) -> Dict[str, TrendDirection]: + """ + Update multiple metrics at once and get their trends. + + Args: + key: Identifier for the entity + metrics: Dictionary of metric_name -> value + + Returns: + Dictionary of metric_name -> trend_direction + """ + trends = {} + for metric, value in metrics.items(): + trends[metric] = self.update(key, metric, value) + return trends + + def clear(self) -> None: + """Clear all tracked values (useful on stats reset).""" + self._previous_values.clear() + + def __repr__(self) -> str: + """String representation for debugging.""" + status = "enabled" if self._enabled else "disabled" + tracked = len(self._previous_values) + return f"TrendTracker({status}, tracking {tracked} entities)" diff --git a/Lib/profiling/sampling/live_collector/widgets.py b/Lib/profiling/sampling/live_collector/widgets.py new file mode 100644 index 00000000000..314f3796a09 --- /dev/null +++ b/Lib/profiling/sampling/live_collector/widgets.py @@ -0,0 +1,1085 @@ +"""Widget classes for the live profiling collector UI.""" + +import curses +import time +from abc import ABC, abstractmethod + +from .constants import ( + TOP_FUNCTIONS_DISPLAY_COUNT, + MIN_FUNC_NAME_WIDTH, + MAX_FUNC_NAME_WIDTH, + WIDTH_THRESHOLD_SAMPLE_PCT, + WIDTH_THRESHOLD_TOTTIME, + WIDTH_THRESHOLD_CUMUL_PCT, + WIDTH_THRESHOLD_CUMTIME, + MICROSECONDS_PER_SECOND, + DISPLAY_UPDATE_INTERVAL, + MIN_BAR_WIDTH, + MAX_SAMPLE_RATE_BAR_WIDTH, + MAX_EFFICIENCY_BAR_WIDTH, + MIN_SAMPLE_RATE_FOR_SCALING, + FOOTER_LINES, + FINISHED_BANNER_EXTRA_LINES, + OPCODE_PANEL_HEIGHT, +) +from ..constants import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, + THREAD_STATUS_UNKNOWN, + THREAD_STATUS_GIL_REQUESTED, + PROFILING_MODE_CPU, + PROFILING_MODE_GIL, + PROFILING_MODE_WALL, +) + + +class Widget(ABC): + """Base class for UI widgets.""" + + def __init__(self, display, colors): + """ + Initialize widget. + + Args: + display: DisplayInterface implementation + colors: Dictionary of color attributes + """ + self.display = display + self.colors = colors + + @abstractmethod + def render(self, line, width, **kwargs): + """ + Render the widget starting at the given line. + + Args: + line: Starting line number + width: Available width + **kwargs: Additional rendering parameters + + Returns: + Next available line number after rendering + """ + pass + + def add_str(self, line, col, text, attr=0): + """Add a string to the display at the specified position.""" + self.display.add_str(line, col, text, attr) + + +class ProgressBarWidget(Widget): + """Reusable progress bar widget.""" + + def render(self, line, width, **kwargs): + """Render is not used for progress bars - use render_bar instead.""" + raise NotImplementedError("Use render_bar method instead") + + def render_bar( + self, filled, total, max_width, fill_char="█", empty_char="░" + ): + """ + Render a progress bar and return the bar string and its length. + + Args: + filled: Current filled amount + total: Total amount (max value) + max_width: Maximum width for the bar + fill_char: Character to use for filled portion + empty_char: Character to use for empty portion + + Returns: + Tuple of (bar_string, bar_length) + """ + bar_width = min(max_width, max_width) + normalized = min(filled / max(total, 1), 1.0) + bar_fill = int(normalized * bar_width) + + bar = "[" + for i in range(bar_width): + if i < bar_fill: + bar += fill_char + else: + bar += empty_char + bar += "]" + return bar, len(bar) + + +class HeaderWidget(Widget): + """Widget for rendering the header section (lines 0-8).""" + + def __init__(self, display, colors, collector): + """ + Initialize header widget. + + Args: + display: DisplayInterface implementation + colors: Dictionary of color attributes + collector: Reference to LiveStatsCollector for accessing stats + """ + super().__init__(display, colors) + self.collector = collector + self.progress_bar = ProgressBarWidget(display, colors) + + def render(self, line, width, **kwargs): + """ + Render the complete header section. + + Args: + line: Starting line number + width: Available width + kwargs: Must contain 'elapsed' key + + Returns: + Next available line number + """ + elapsed = kwargs["elapsed"] + + line = self.draw_header_info(line, width, elapsed) + line = self.draw_sample_stats(line, width, elapsed) + line = self.draw_efficiency_bar(line, width) + line = self.draw_thread_status(line, width) + line = self.draw_function_stats( + line, width, kwargs.get("stats_list", []) + ) + line = self.draw_top_functions( + line, width, kwargs.get("stats_list", []) + ) + + # Show prominent finished banner if profiling is complete + if self.collector.finished: + line = self.draw_finished_banner(line, width) + + # Separator + A_DIM = self.display.get_attr("A_DIM") + separator = "─" * (width - 1) + self.add_str(line, 0, separator[: width - 1], A_DIM) + line += 1 + + return line + + def format_uptime(self, elapsed): + """Format elapsed time as uptime string.""" + uptime_sec = int(elapsed) + hours = uptime_sec // 3600 + minutes = (uptime_sec % 3600) // 60 + seconds = uptime_sec % 60 + if hours > 0: + return f"{hours}h{minutes:02d}m{seconds:02d}s" + else: + return f"{minutes}m{seconds:02d}s" + + def draw_header_info(self, line, width, elapsed): + """Draw the header information line with PID, uptime, time, and interval.""" + # Draw title + A_BOLD = self.display.get_attr("A_BOLD") + title = "Tachyon Profiler" + self.add_str(line, 0, title, A_BOLD | self.colors["cyan"]) + line += 1 + + current_time = self.collector.current_time_display + uptime = self.format_uptime(elapsed) + + # Calculate display refresh rate + refresh_hz = ( + 1.0 / self.collector.display_update_interval if self.collector.display_update_interval > 0 else 0 + ) + + # Get current view mode and thread display + if self.collector.view_mode == "ALL": + thread_name = "ALL" + thread_color = self.colors["green"] + else: + # PER_THREAD mode + if self.collector.current_thread_index < len( + self.collector.thread_ids + ): + thread_id = self.collector.thread_ids[ + self.collector.current_thread_index + ] + num_threads = len(self.collector.thread_ids) + thread_name = f"{thread_id} ({self.collector.current_thread_index + 1}/{num_threads})" + thread_color = self.colors["magenta"] + else: + thread_name = "ALL" + thread_color = self.colors["green"] + + header_parts = [ + ("PID: ", curses.A_BOLD), + (f"{self.collector.pid}", self.colors["cyan"]), + (" │ ", curses.A_DIM), + ("Thread: ", curses.A_BOLD), + (thread_name, thread_color), + (" │ ", curses.A_DIM), + ("Uptime: ", curses.A_BOLD), + (uptime, self.colors["green"]), + (" │ ", curses.A_DIM), + ("Time: ", curses.A_BOLD), + (current_time, self.colors["yellow"]), + (" │ ", curses.A_DIM), + ("Interval: ", curses.A_BOLD), + ( + f"{self.collector.sample_interval_usec}µs", + self.colors["magenta"], + ), + (" │ ", curses.A_DIM), + ("Display: ", curses.A_BOLD), + (f"{refresh_hz:.1f}Hz", self.colors["cyan"]), + ] + + col = 0 + for text, attr in header_parts: + if col < width - 1: + self.add_str(line, col, text, attr) + col += len(text) + return line + 1 + + def format_rate_with_units(self, rate_hz): + """Format a rate in Hz with appropriate units (Hz, KHz, MHz).""" + if rate_hz >= 1_000_000: + return f"{rate_hz / 1_000_000:.1f}MHz" + elif rate_hz >= 1_000: + return f"{rate_hz / 1_000:.1f}KHz" + else: + return f"{rate_hz:.1f}Hz" + + def draw_sample_stats(self, line, width, elapsed): + """Draw sample statistics with visual progress bar.""" + sample_rate = ( + self.collector.total_samples / elapsed if elapsed > 0 else 0 + ) + + # Update max sample rate + if sample_rate > self.collector.max_sample_rate: + self.collector.max_sample_rate = sample_rate + + col = 0 + self.add_str(line, col, "Samples: ", curses.A_BOLD) + col += 9 + self.add_str( + line, + col, + f"{self.collector.total_samples:>8}", + self.colors["cyan"], + ) + col += 8 + self.add_str( + line, col, f" total ({sample_rate:>7.1f}/s) ", curses.A_NORMAL + ) + col += 23 + + # Draw sample rate bar + target_rate = ( + MICROSECONDS_PER_SECOND / self.collector.sample_interval_usec + ) + + # Show current/target ratio with percentage + if sample_rate > 0 and target_rate > 0: + percentage = min((sample_rate / target_rate) * 100, 100) + current_formatted = self.format_rate_with_units(sample_rate) + target_formatted = self.format_rate_with_units(target_rate) + + if percentage >= 99.5: # Show 100% when very close + rate_label = f" {current_formatted}/{target_formatted} (100%)" + else: + rate_label = f" {current_formatted}/{target_formatted} ({percentage:>4.1f}%)" + else: + target_formatted = self.format_rate_with_units(target_rate) + rate_label = f" target: {target_formatted}" + + available_width = width - col - len(rate_label) - 3 + + if available_width >= MIN_BAR_WIDTH: + bar_width = min(MAX_SAMPLE_RATE_BAR_WIDTH, available_width) + # Use target rate as the reference, with a minimum for scaling + reference_rate = max(target_rate, MIN_SAMPLE_RATE_FOR_SCALING) + normalized_rate = min(sample_rate / reference_rate, 1.0) + bar_fill = int(normalized_rate * bar_width) + + bar = "[" + for i in range(bar_width): + bar += "█" if i < bar_fill else "░" + bar += "]" + self.add_str(line, col, bar, self.colors["green"]) + col += len(bar) + + if col + len(rate_label) < width - 1: + self.add_str(line, col + 1, rate_label, curses.A_DIM) + return line + 1 + + def draw_efficiency_bar(self, line, width): + """Draw sample efficiency bar showing success/failure rates.""" + # total_samples = successful_samples + failed_samples, so percentages add to 100% + total = max(1, self.collector.total_samples) + success_pct = (self.collector.successful_samples / total) * 100 + failed_pct = (self.collector.failed_samples / total) * 100 + + col = 0 + self.add_str(line, col, "Efficiency:", curses.A_BOLD) + col += 11 + + label = f" {success_pct:>5.2f}% good, {failed_pct:>5.2f}% failed" + available_width = width - col - len(label) - 3 + + if available_width >= MIN_BAR_WIDTH: + bar_width = min(MAX_EFFICIENCY_BAR_WIDTH, available_width) + success_fill = int((self.collector.successful_samples / total) * bar_width) + failed_fill = bar_width - success_fill + + self.add_str(line, col, "[", curses.A_NORMAL) + col += 1 + if success_fill > 0: + self.add_str( + line, col, "█" * success_fill, self.colors["green"] + ) + col += success_fill + if failed_fill > 0: + self.add_str(line, col, "█" * failed_fill, self.colors["red"]) + col += failed_fill + self.add_str(line, col, "]", curses.A_NORMAL) + col += 1 + + self.add_str(line, col + 1, label, curses.A_NORMAL) + return line + 1 + + def _add_percentage_stat( + self, line, col, value, label, color, add_separator=False + ): + """Add a percentage stat to the display. + + Args: + line: Line number + col: Starting column + value: Percentage value + label: Label text + color: Color attribute + add_separator: Whether to add separator before the stat + + Returns: + Updated column position + """ + if add_separator: + self.add_str(line, col, " │ ", curses.A_DIM) + col += 3 + + self.add_str(line, col, f"{value:>4.1f}", color) + col += 4 + self.add_str(line, col, f"% {label}", curses.A_NORMAL) + col += len(label) + 2 + + return col + + def draw_thread_status(self, line, width): + """Draw thread status statistics and GC information.""" + # Get status counts for current view mode + thread_data = self.collector._get_current_thread_data() + status_counts = thread_data.as_status_dict() if thread_data else self.collector.thread_status_counts + + # Calculate percentages + total_threads = max(1, status_counts["total"]) + pct_on_gil = (status_counts["has_gil"] / total_threads) * 100 + pct_off_gil = 100.0 - pct_on_gil + pct_gil_requested = (status_counts["gil_requested"] / total_threads) * 100 + pct_exception = (status_counts.get("has_exception", 0) / total_threads) * 100 + + # Get GC percentage based on view mode + if thread_data: + total_samples = max(1, thread_data.sample_count) + pct_gc = (thread_data.gc_frame_samples / total_samples) * 100 + else: + # Use total_samples for GC percentage since gc_frame_samples is tracked + # across ALL samples (via thread status), not just successful ones + total_samples = max(1, self.collector.total_samples) + pct_gc = (self.collector.gc_frame_samples / total_samples) * 100 + + col = 0 + self.add_str(line, col, "Threads: ", curses.A_BOLD) + col += 11 + + # Show GIL stats only if mode is not GIL (GIL mode filters to only GIL holders) + if self.collector.mode != PROFILING_MODE_GIL: + col = self._add_percentage_stat( + line, col, pct_on_gil, "on gil", self.colors["green"] + ) + col = self._add_percentage_stat( + line, + col, + pct_off_gil, + "off gil", + self.colors["red"], + add_separator=True, + ) + + # Show "waiting for gil" only if mode is not GIL + if self.collector.mode != PROFILING_MODE_GIL and col < width - 30: + col = self._add_percentage_stat( + line, + col, + pct_gil_requested, + "waiting for gil", + self.colors["yellow"], + add_separator=True, + ) + + # Show exception stats + if col < width - 15: + col = self._add_percentage_stat( + line, + col, + pct_exception, + "exc", + self.colors["red"], + add_separator=(col > 11), + ) + + # Always show GC stats + if col < width - 15: + col = self._add_percentage_stat( + line, + col, + pct_gc, + "GC", + self.colors["magenta"], + add_separator=(col > 11), + ) + + return line + 1 + + def draw_function_stats(self, line, width, stats_list): + """Draw function statistics summary.""" + result_set = self.collector._get_current_result_source() + total_funcs = len(result_set) + funcs_shown = len(stats_list) + executing_funcs = sum( + 1 for f in result_set.values() if f.get("direct_calls", 0) > 0 + ) + stack_only = total_funcs - executing_funcs + + col = 0 + self.add_str(line, col, "Functions: ", curses.A_BOLD) + col += 11 + self.add_str(line, col, f"{total_funcs:>5}", self.colors["cyan"]) + col += 5 + self.add_str(line, col, " total", curses.A_NORMAL) + col += 6 + + if col < width - 25: + self.add_str(line, col, " │ ", curses.A_DIM) + col += 3 + self.add_str( + line, col, f"{executing_funcs:>5}", self.colors["green"] + ) + col += 5 + self.add_str(line, col, " exec", curses.A_NORMAL) + col += 5 + + if col < width - 25: + self.add_str(line, col, " │ ", curses.A_DIM) + col += 3 + self.add_str(line, col, f"{stack_only:>5}", self.colors["yellow"]) + col += 5 + self.add_str(line, col, " stack", curses.A_NORMAL) + col += 6 + + if col < width - 20: + self.add_str(line, col, " │ ", curses.A_DIM) + col += 3 + self.add_str( + line, col, f"{funcs_shown:>5}", self.colors["magenta"] + ) + col += 5 + self.add_str(line, col, " shown", curses.A_NORMAL) + return line + 1 + + def draw_top_functions(self, line, width, stats_list): + """Draw top N hottest functions.""" + col = 0 + self.add_str( + line, + col, + f"Top {TOP_FUNCTIONS_DISPLAY_COUNT}: ", + curses.A_BOLD, + ) + col += 11 + + top_by_samples = sorted( + stats_list, key=lambda x: x["direct_calls"], reverse=True + ) + emojis = ["🥇", "🥈", "🥉"] + medal_colors = [ + self.colors["red"], + self.colors["yellow"], + self.colors["green"], + ] + + displayed = 0 + for func_data in top_by_samples: + if displayed >= TOP_FUNCTIONS_DISPLAY_COUNT: + break + if col >= width - 20: + break + if func_data["direct_calls"] == 0: + continue + + func_name = func_data["func"][2] + func_pct = func_data["sample_pct"] + + # Medal emoji + if col + 3 < width - 15: + self.add_str( + line, col, emojis[displayed] + " ", medal_colors[displayed] + ) + col += 3 + + # Function name (truncate to fit) + available_for_name = width - col - 15 + max_name_len = min(25, max(5, available_for_name)) + if len(func_name) > max_name_len: + func_name = func_name[: max_name_len - 3] + "..." + + if col + len(func_name) < width - 10: + self.add_str(line, col, func_name, medal_colors[displayed]) + col += len(func_name) + + pct_str = ( + f" ({func_pct:.1f}%)" + if func_pct >= 0.1 + else f" ({func_data['direct_calls']})" + ) + self.add_str(line, col, pct_str, curses.A_DIM) + col += len(pct_str) + + displayed += 1 + + if displayed < 3 and col < width - 30: + self.add_str(line, col, " │ ", curses.A_DIM) + col += 3 + + if displayed == 0 and col < width - 25: + self.add_str(line, col, "(collecting samples...)", curses.A_DIM) + + return line + 1 + + def draw_finished_banner(self, line, width): + """Draw a prominent banner when profiling is finished.""" + A_REVERSE = self.display.get_attr("A_REVERSE") + A_BOLD = self.display.get_attr("A_BOLD") + + # Add blank line for separation + line += 1 + + # Create the banner message + message = " ✓ PROFILING COMPLETE - Final Results Below - Press 'q' to Quit " + + # Center the message and fill the width with reverse video + if len(message) < width - 1: + padding_total = width - len(message) - 1 + padding_left = padding_total // 2 + padding_right = padding_total - padding_left + full_message = " " * padding_left + message + " " * padding_right + else: + full_message = message[: width - 1] + + # Draw the banner with reverse video and bold + self.add_str( + line, 0, full_message, A_REVERSE | A_BOLD | self.colors["green"] + ) + line += 1 + + # Add blank line for separation + line += 1 + + return line + + +class TableWidget(Widget): + """Widget for rendering column headers and data rows.""" + + def __init__(self, display, colors, collector): + """ + Initialize table widget. + + Args: + display: DisplayInterface implementation + colors: Dictionary of color attributes + collector: Reference to LiveStatsCollector for accessing stats + """ + super().__init__(display, colors) + self.collector = collector + + def render(self, line, width, **kwargs): + """ + Render column headers and data rows. + + Args: + line: Starting line number + width: Available width + kwargs: Must contain 'height' and 'stats_list' keys + + Returns: + Next available line number + """ + height = kwargs["height"] + stats_list = kwargs["stats_list"] + + # Draw column headers + line, show_sample_pct, show_tottime, show_cumul_pct, show_cumtime = ( + self.draw_column_headers(line, width) + ) + column_flags = ( + show_sample_pct, + show_tottime, + show_cumul_pct, + show_cumtime, + ) + + # Draw data rows + line = self.draw_stats_rows( + line, height, width, stats_list, column_flags + ) + + return line + + def draw_column_headers(self, line, width): + """Draw column headers with sort indicators.""" + col = 0 + + # Determine which columns to show based on width + show_sample_pct = width >= WIDTH_THRESHOLD_SAMPLE_PCT + show_tottime = width >= WIDTH_THRESHOLD_TOTTIME + show_cumul_pct = width >= WIDTH_THRESHOLD_CUMUL_PCT + show_cumtime = width >= WIDTH_THRESHOLD_CUMTIME + + sorted_header = self.colors["sorted_header"] + normal_header = self.colors["normal_header"] + + # Determine which column is sorted + sort_col = { + "nsamples": 0, + "sample_pct": 1, + "tottime": 2, + "cumul_pct": 3, + "cumtime": 4, + }.get(self.collector.sort_by, -1) + + # Column 0: nsamples + attr = sorted_header if sort_col == 0 else normal_header + text = f"{'▼nsamples' if sort_col == 0 else 'nsamples':>13}" + self.add_str(line, col, text, attr) + col += 15 + + # Column 1: sample % + if show_sample_pct: + attr = sorted_header if sort_col == 1 else normal_header + text = f"{'▼%' if sort_col == 1 else '%':>5}" + self.add_str(line, col, text, attr) + col += 7 + + # Column 2: tottime + if show_tottime: + attr = sorted_header if sort_col == 2 else normal_header + text = f"{'▼tottime' if sort_col == 2 else 'tottime':>10}" + self.add_str(line, col, text, attr) + col += 12 + + # Column 3: cumul % + if show_cumul_pct: + attr = sorted_header if sort_col == 3 else normal_header + text = f"{'▼%' if sort_col == 3 else '%':>5}" + self.add_str(line, col, text, attr) + col += 7 + + # Column 4: cumtime + if show_cumtime: + attr = sorted_header if sort_col == 4 else normal_header + text = f"{'▼cumtime' if sort_col == 4 else 'cumtime':>10}" + self.add_str(line, col, text, attr) + col += 12 + + # Remaining headers + if col < width - 15: + remaining_space = width - col - 1 + func_width = min( + MAX_FUNC_NAME_WIDTH, + max(MIN_FUNC_NAME_WIDTH, remaining_space // 2), + ) + self.add_str( + line, col, f"{'function':<{func_width}}", normal_header + ) + col += func_width + 2 + + if col < width - 10: + self.add_str(line, col, "file:line", normal_header) + + return ( + line + 1, + show_sample_pct, + show_tottime, + show_cumul_pct, + show_cumtime, + ) + + def draw_stats_rows(self, line, height, width, stats_list, column_flags): + """Draw the statistics data rows.""" + show_sample_pct, show_tottime, show_cumul_pct, show_cumtime = ( + column_flags + ) + + # Get color attributes from the colors dict (already initialized) + color_samples = self.colors.get("color_samples", curses.A_NORMAL) + color_file = self.colors.get("color_file", curses.A_NORMAL) + color_func = self.colors.get("color_func", curses.A_NORMAL) + + # Get trend tracker for color decisions + trend_tracker = self.collector._trend_tracker + + # Check if opcode mode is enabled for row selection highlighting + show_opcodes = getattr(self.collector, 'show_opcodes', False) + selected_row = getattr(self.collector, 'selected_row', 0) + scroll_offset = getattr(self.collector, 'scroll_offset', 0) if show_opcodes else 0 + A_REVERSE = self.display.get_attr("A_REVERSE") + A_BOLD = self.display.get_attr("A_BOLD") + + # Reserve space for opcode panel when enabled + opcode_panel_height = OPCODE_PANEL_HEIGHT if show_opcodes else 0 + + # Apply scroll offset when in opcode mode + display_stats = stats_list[scroll_offset:] if show_opcodes else stats_list + + for row_idx, stat in enumerate(display_stats): + if line >= height - FOOTER_LINES - opcode_panel_height: + break + + func = stat["func"] + direct_calls = stat["direct_calls"] + cumulative_calls = stat["cumulative_calls"] + total_time = stat["total_time"] + cumulative_time = stat["cumulative_time"] + sample_pct = stat["sample_pct"] + cum_pct = stat["cumul_pct"] + trends = stat.get("trends", {}) + + # Check if this row is selected + is_selected = show_opcodes and row_idx == selected_row + + # Helper function to get trend color for a specific column + def get_trend_color(column_name): + if is_selected: + return A_REVERSE | A_BOLD + trend = trends.get(column_name, "stable") + if trend_tracker is not None: + return trend_tracker.get_color(trend) + return curses.A_NORMAL + + filename, lineno, funcname = func[0], func[1], func[2] + samples_str = f"{direct_calls}/{cumulative_calls}" + col = 0 + + # Fill entire row with reverse video background for selected row + if is_selected: + self.add_str(line, 0, " " * (width - 1), A_REVERSE | A_BOLD) + + # Show selection indicator when opcode panel is enabled + if show_opcodes: + if is_selected: + self.add_str(line, col, "►", A_REVERSE | A_BOLD) + else: + self.add_str(line, col, " ", curses.A_NORMAL) + col += 2 + + # Samples column - apply trend color based on nsamples trend + nsamples_color = get_trend_color("nsamples") + self.add_str(line, col, f"{samples_str:>13} ", nsamples_color) + col += 15 + + # Sample % column + if show_sample_pct: + sample_pct_color = get_trend_color("sample_pct") + self.add_str(line, col, f"{sample_pct:>5.1f} ", sample_pct_color) + col += 7 + + # Total time column + if show_tottime: + tottime_color = get_trend_color("tottime") + self.add_str(line, col, f"{total_time:>10.3f} ", tottime_color) + col += 12 + + # Cumul % column + if show_cumul_pct: + cumul_pct_color = get_trend_color("cumul_pct") + self.add_str(line, col, f"{cum_pct:>5.1f} ", cumul_pct_color) + col += 7 + + # Cumul time column + if show_cumtime: + cumtime_color = get_trend_color("cumtime") + self.add_str(line, col, f"{cumulative_time:>10.3f} ", cumtime_color) + col += 12 + + # Function name column + if col < width - 15: + remaining_space = width - col - 1 + func_width = min( + MAX_FUNC_NAME_WIDTH, + max(MIN_FUNC_NAME_WIDTH, remaining_space // 2), + ) + + func_display = funcname + if len(funcname) > func_width: + func_display = funcname[: func_width - 3] + "..." + func_display = f"{func_display:<{func_width}}" + func_color = A_REVERSE | A_BOLD if is_selected else color_func + self.add_str(line, col, func_display, func_color) + col += func_width + 2 + + # File:line column + if col < width - 10: + simplified_path = self.collector.simplify_path(filename) + file_line = f"{simplified_path}:{lineno}" + remaining_width = width - col - 1 + file_color = A_REVERSE | A_BOLD if is_selected else color_file + self.add_str( + line, col, file_line[:remaining_width], file_color + ) + + line += 1 + + return line + + +class FooterWidget(Widget): + """Widget for rendering the footer section (legend and controls).""" + + def __init__(self, display, colors, collector): + """ + Initialize footer widget. + + Args: + display: DisplayInterface implementation + colors: Dictionary of color attributes + collector: Reference to LiveStatsCollector for accessing state + """ + super().__init__(display, colors) + self.collector = collector + + def render(self, line, width, **kwargs): + """ + Render the footer at the specified position. + + Args: + line: Starting line number (should be height - 2) + width: Available width + + Returns: + Next available line number + """ + A_DIM = self.display.get_attr("A_DIM") + A_BOLD = self.display.get_attr("A_BOLD") + + # Legend line + legend = "nsamples: direct/cumulative (direct=executing, cumulative=on stack)" + self.add_str(line, 0, legend[: width - 1], A_DIM) + line += 1 + + # Controls line with status + sort_names = { + "tottime": "Total Time", + "nsamples": "Direct Samples", + "cumtime": "Cumulative Time", + "sample_pct": "Sample %", + "cumul_pct": "Cumulative %", + } + sort_display = sort_names.get( + self.collector.sort_by, self.collector.sort_by + ) + + # Build status indicators + status = [] + if self.collector.finished: + status.append("[PROFILING FINISHED - Press 'q' to quit]") + elif self.collector.paused: + status.append("[PAUSED]") + if self.collector.filter_pattern: + status.append( + f"[Filter: {self.collector.filter_pattern} (c to clear)]" + ) + # Show trend colors status if disabled + if self.collector._trend_tracker is not None and not self.collector._trend_tracker.enabled: + status.append("[Trend colors: OFF]") + status_str = " ".join(status) + " " if status else "" + + if self.collector.finished: + footer = f"{status_str}" + else: + footer = f"{status_str}Sort: {sort_display} | 't':mode 'x':trends ←→:thread 'h':help 'q':quit" + self.add_str( + line, + 0, + footer[: width - 1], + A_BOLD + if (self.collector.paused or self.collector.finished) + else A_DIM, + ) + + return line + 1 + + def render_filter_input_prompt(self, line, width): + """Draw the filter input prompt at the bottom of the screen.""" + A_BOLD = self.display.get_attr("A_BOLD") + A_REVERSE = self.display.get_attr("A_REVERSE") + + # Draw prompt on last line + prompt = f"Function filter: {self.collector.filter_input_buffer}_" + self.add_str(line, 0, prompt[: width - 1], A_REVERSE | A_BOLD) + + +class HelpWidget(Widget): + """Widget for rendering the help screen overlay.""" + + def render(self, line, width, **kwargs): + """ + Render the help screen. + + Args: + line: Starting line number (ignored, help is centered) + width: Available width + kwargs: Must contain 'height' key + + Returns: + Next available line number (not used for overlays) + """ + height = kwargs["height"] + A_BOLD = self.display.get_attr("A_BOLD") + A_NORMAL = self.display.get_attr("A_NORMAL") + + help_lines = [ + ("Tachyon Profiler - Interactive Commands", A_BOLD), + ("", A_NORMAL), + ("Navigation & Display:", A_BOLD), + (" s - Cycle through sort modes (forward)", A_NORMAL), + (" S - Cycle through sort modes (backward)", A_NORMAL), + (" t - Toggle view mode (ALL / per-thread)", A_NORMAL), + (" x - Toggle trend colors (on/off)", A_NORMAL), + (" j/k or ↑/↓ - Select next/previous function (--opcodes)", A_NORMAL), + (" ← / → - Cycle through threads", A_NORMAL), + (" + - Faster display refresh rate", A_NORMAL), + (" - - Slower display refresh rate", A_NORMAL), + ("", A_NORMAL), + ("Control:", A_BOLD), + (" p - Freeze display (snapshot)", A_NORMAL), + (" r - Reset all statistics", A_NORMAL), + ("", A_NORMAL), + ("Filtering:", A_BOLD), + (" / - Enter function filter (substring)", A_NORMAL), + (" c - Clear filter", A_NORMAL), + (" ESC - Cancel filter input", A_NORMAL), + ("", A_NORMAL), + ("Other:", A_BOLD), + (" h or ? - Show/hide this help", A_NORMAL), + (" q - Quit profiler", A_NORMAL), + ("", A_NORMAL), + ("Press any key to close this help screen", A_BOLD), + ] + + start_line = (height - len(help_lines)) // 2 + for i, (text, attr) in enumerate(help_lines): + if start_line + i < height - 1: + col = 2 # Left-align with small margin + self.add_str(start_line + i, col, text[: width - 3], attr) + + return line # Not used for overlays + + +class OpcodePanel(Widget): + """Widget for displaying opcode statistics for a selected function.""" + + def __init__(self, display, colors, collector): + super().__init__(display, colors) + self.collector = collector + + def render(self, line, width, **kwargs): + """Render opcode statistics panel. + + Args: + line: Starting line number + width: Available width + kwargs: Must contain 'stats_list', 'height' + + Returns: + Next available line number + """ + from ..opcode_utils import get_opcode_info, format_opcode + + stats_list = kwargs.get("stats_list", []) + height = kwargs.get("height", 24) + selected_row = self.collector.selected_row + scroll_offset = getattr(self.collector, 'scroll_offset', 0) + + A_BOLD = self.display.get_attr("A_BOLD") + A_NORMAL = self.display.get_attr("A_NORMAL") + color_cyan = self.colors.get("color_cyan", A_NORMAL) + color_yellow = self.colors.get("color_yellow", A_NORMAL) + color_magenta = self.colors.get("color_magenta", A_NORMAL) + + # Get the selected function from stats_list (accounting for scroll) + actual_index = scroll_offset + selected_row + if not stats_list or actual_index >= len(stats_list): + self.add_str(line, 0, "No function selected (use j/k to select)", A_NORMAL) + return line + 1 + + selected_stat = stats_list[actual_index] + func = selected_stat["func"] + filename, lineno, funcname = func + + # Get opcode stats for this function + opcode_stats = self.collector.opcode_stats.get(func, {}) + + if not opcode_stats: + self.add_str(line, 0, f"No opcode data for {funcname}() (requires --opcodes)", A_NORMAL) + return line + 1 + + # Sort opcodes by count + sorted_opcodes = sorted(opcode_stats.items(), key=lambda x: -x[1]) + total_opcode_samples = sum(opcode_stats.values()) + + # Draw header + header = f"─── Opcodes for {funcname}() " + header += "─" * max(0, width - len(header) - 1) + self.add_str(line, 0, header[:width-1], color_cyan | A_BOLD) + line += 1 + + # Calculate max samples for bar scaling + max_count = sorted_opcodes[0][1] if sorted_opcodes else 1 + + # Draw opcode rows (limit to available space) + max_rows = min(8, height - line - 3) # Leave room for footer + bar_width = 20 + + for i, (opcode_num, count) in enumerate(sorted_opcodes[:max_rows]): + if line >= height - 3: + break + + opcode_info = get_opcode_info(opcode_num) + is_specialized = opcode_info["is_specialized"] + name_display = format_opcode(opcode_num) + + pct = (count / total_opcode_samples * 100) if total_opcode_samples > 0 else 0 + + # Draw bar + bar_fill = int((count / max_count) * bar_width) if max_count > 0 else 0 + bar = "█" * bar_fill + "░" * (bar_width - bar_fill) + + # Format: [████████░░░░] LOAD_ATTR 45.2% (1234) + # Specialized opcodes shown in magenta, base opcodes in yellow + name_color = color_magenta if is_specialized else color_yellow + + row_text = f"[{bar}] {name_display:<35} {pct:>5.1f}% ({count:>6})" + self.add_str(line, 2, row_text[:width-3], name_color) + line += 1 + + # Show "..." if more opcodes exist + if len(sorted_opcodes) > max_rows: + remaining = len(sorted_opcodes) - max_rows + self.add_str(line, 2, f"... and {remaining} more opcodes", A_NORMAL) + line += 1 + + return line diff --git a/Lib/profiling/sampling/opcode_utils.py b/Lib/profiling/sampling/opcode_utils.py new file mode 100644 index 00000000000..71b35383da1 --- /dev/null +++ b/Lib/profiling/sampling/opcode_utils.py @@ -0,0 +1,94 @@ +"""Opcode utilities for bytecode-level profiler visualization. + +This module provides utilities to get opcode names and detect specialization +status using the opcode module's metadata. Used by heatmap and flamegraph +collectors to display which bytecode instructions are executing at each +source line, including Python's adaptive specialization optimizations. +""" + +import opcode + +# Build opcode name mapping: opcode number -> opcode name +# This includes both standard opcodes and specialized variants (Python 3.11+) +_OPCODE_NAMES = dict(enumerate(opcode.opname)) +if hasattr(opcode, "_specialized_opmap"): + for name, op in opcode._specialized_opmap.items(): + _OPCODE_NAMES[op] = name + +# Build deopt mapping: specialized opcode number -> base opcode number +# Python 3.11+ uses adaptive specialization where generic opcodes like +# LOAD_ATTR can be replaced at runtime with specialized variants like +# LOAD_ATTR_INSTANCE_VALUE. This mapping lets us show both forms. +_DEOPT_MAP = {} +if hasattr(opcode, "_specializations") and hasattr( + opcode, "_specialized_opmap" +): + for base_name, variant_names in opcode._specializations.items(): + base_opcode = opcode.opmap.get(base_name) + if base_opcode is not None: + for variant_name in variant_names: + variant_opcode = opcode._specialized_opmap.get(variant_name) + if variant_opcode is not None: + _DEOPT_MAP[variant_opcode] = base_opcode + + +def get_opcode_info(opcode_num): + """Get opcode name and specialization info from an opcode number. + + Args: + opcode_num: The opcode number (0-255 or higher for specialized) + + Returns: + A dict with keys: + - 'opname': The opcode name (e.g., 'LOAD_ATTR_INSTANCE_VALUE') + - 'base_opname': The base opcode name (e.g., 'LOAD_ATTR') + - 'is_specialized': True if this is a specialized instruction + """ + opname = _OPCODE_NAMES.get(opcode_num) + if opname is None: + return { + "opname": f"<{opcode_num}>", + "base_opname": f"<{opcode_num}>", + "is_specialized": False, + } + + base_opcode = _DEOPT_MAP.get(opcode_num) + if base_opcode is not None: + base_opname = _OPCODE_NAMES.get(base_opcode, f"<{base_opcode}>") + return { + "opname": opname, + "base_opname": base_opname, + "is_specialized": True, + } + + return { + "opname": opname, + "base_opname": opname, + "is_specialized": False, + } + + +def format_opcode(opcode_num): + """Format an opcode for display, showing base opcode for specialized ones. + + Args: + opcode_num: The opcode number (0-255 or higher for specialized) + + Returns: + A formatted string like 'LOAD_ATTR' or 'LOAD_ATTR_INSTANCE_VALUE (LOAD_ATTR)' + """ + info = get_opcode_info(opcode_num) + if info["is_specialized"]: + return f"{info['opname']} ({info['base_opname']})" + return info["opname"] + + +def get_opcode_mapping(): + """Get opcode name and deopt mappings for JavaScript consumption. + + Returns: + A dict with keys: + - 'names': Dict mapping opcode numbers to opcode names + - 'deopt': Dict mapping specialized opcode numbers to base opcode numbers + """ + return {"names": _OPCODE_NAMES, "deopt": _DEOPT_MAP} diff --git a/Lib/profiling/sampling/pstats_collector.py b/Lib/profiling/sampling/pstats_collector.py index f58da1159c2..7c154e25828 100644 --- a/Lib/profiling/sampling/pstats_collector.py +++ b/Lib/profiling/sampling/pstats_collector.py @@ -1,11 +1,12 @@ import collections import marshal -from .collector import Collector +from _colorize import ANSIColors +from .collector import Collector, extract_lineno class PstatsCollector(Collector): - def __init__(self, sample_interval_usec): + def __init__(self, sample_interval_usec, *, skip_idle=False): self.result = collections.defaultdict( lambda: dict(total_rec_calls=0, direct_calls=0, cumulative_calls=0) ) @@ -14,44 +15,51 @@ class PstatsCollector(Collector): self.callers = collections.defaultdict( lambda: collections.defaultdict(int) ) + self.skip_idle = skip_idle + self._seen_locations = set() - def collect(self, stack_frames): - for thread_id, frames in stack_frames: - if not frames: - continue + def _process_frames(self, frames): + """Process a single thread's frame stack.""" + if not frames: + return - # Process each frame in the stack to track cumulative calls - for frame in frames: - location = (frame.filename, frame.lineno, frame.funcname) + self._seen_locations.clear() + + # Process each frame in the stack to track cumulative calls + # frame.location is int, tuple (lineno, end_lineno, col_offset, end_col_offset), or None + for frame in frames: + lineno = extract_lineno(frame.location) + location = (frame.filename, lineno, frame.funcname) + if location not in self._seen_locations: + self._seen_locations.add(location) self.result[location]["cumulative_calls"] += 1 - # The top frame gets counted as an inline call (directly executing) - top_frame = frames[0] - top_location = ( - top_frame.filename, - top_frame.lineno, - top_frame.funcname, - ) + # The top frame gets counted as an inline call (directly executing) + top_lineno = extract_lineno(frames[0].location) + top_location = (frames[0].filename, top_lineno, frames[0].funcname) + self.result[top_location]["direct_calls"] += 1 - self.result[top_location]["direct_calls"] += 1 + # Track caller-callee relationships for call graph + for i in range(1, len(frames)): + callee_frame = frames[i - 1] + caller_frame = frames[i] - # Track caller-callee relationships for call graph - for i in range(1, len(frames)): - callee_frame = frames[i - 1] - caller_frame = frames[i] + callee_lineno = extract_lineno(callee_frame.location) + caller_lineno = extract_lineno(caller_frame.location) + callee = (callee_frame.filename, callee_lineno, callee_frame.funcname) + caller = (caller_frame.filename, caller_lineno, caller_frame.funcname) - callee = ( - callee_frame.filename, - callee_frame.lineno, - callee_frame.funcname, - ) - caller = ( - caller_frame.filename, - caller_frame.lineno, - caller_frame.funcname, - ) + self.callers[callee][caller] += 1 - self.callers[callee][caller] += 1 + def collect(self, stack_frames): + if stack_frames and hasattr(stack_frames[0], "awaited_by"): + # Async frame processing + for frames, thread_id, task_id in self._iter_async_frames(stack_frames): + self._process_frames(frames) + else: + # Regular frame processing + for frames, thread_id in self._iter_all_frames(stack_frames, skip_idle=self.skip_idle): + self._process_frames(frames) def export(self, filename): self.create_stats() @@ -79,3 +87,342 @@ class PstatsCollector(Collector): cumulative, callers, ) + + def print_stats(self, sort=-1, limit=None, show_summary=True, mode=None): + """Print formatted statistics to stdout.""" + import pstats + from .constants import PROFILING_MODE_CPU + + # Create stats object + stats = pstats.SampledStats(self).strip_dirs() + if not stats.stats: + print("No samples were collected.") + if mode == PROFILING_MODE_CPU: + print("This can happen in CPU mode when all threads are idle.") + return + + # Get the stats data + stats_list = [] + for func, ( + direct_calls, + cumulative_calls, + total_time, + cumulative_time, + callers, + ) in stats.stats.items(): + stats_list.append( + ( + func, + direct_calls, + cumulative_calls, + total_time, + cumulative_time, + callers, + ) + ) + + # Calculate total samples for percentage calculations (using direct_calls) + total_samples = sum( + direct_calls for _, direct_calls, _, _, _, _ in stats_list + ) + + # Sort based on the requested field + sort_field = sort + if sort_field == -1: # stdname + stats_list.sort(key=lambda x: str(x[0])) + elif sort_field == 0: # nsamples (direct samples) + stats_list.sort(key=lambda x: x[1], reverse=True) # direct_calls + elif sort_field == 1: # tottime + stats_list.sort(key=lambda x: x[3], reverse=True) # total_time + elif sort_field == 2: # cumtime + stats_list.sort(key=lambda x: x[4], reverse=True) # cumulative_time + elif sort_field == 3: # sample% + stats_list.sort( + key=lambda x: (x[1] / total_samples * 100) + if total_samples > 0 + else 0, + reverse=True, # direct_calls percentage + ) + elif sort_field == 4: # cumul% + stats_list.sort( + key=lambda x: (x[2] / total_samples * 100) + if total_samples > 0 + else 0, + reverse=True, # cumulative_calls percentage + ) + elif sort_field == 5: # nsamples (cumulative samples) + stats_list.sort(key=lambda x: x[2], reverse=True) # cumulative_calls + + # Apply limit if specified + if limit is not None: + stats_list = stats_list[:limit] + + # Determine the best unit for time columns based on maximum values + max_total_time = max( + (total_time for _, _, _, total_time, _, _ in stats_list), default=0 + ) + max_cumulative_time = max( + (cumulative_time for _, _, _, _, cumulative_time, _ in stats_list), + default=0, + ) + + total_time_unit, total_time_scale = self._determine_best_unit(max_total_time) + cumulative_time_unit, cumulative_time_scale = self._determine_best_unit( + max_cumulative_time + ) + + # Define column widths for consistent alignment + col_widths = { + "nsamples": 15, # "nsamples" column (inline/cumulative format) + "sample_pct": 8, # "sample%" column + "tottime": max(12, len(f"tottime ({total_time_unit})")), + "cum_pct": 8, # "cumul%" column + "cumtime": max(12, len(f"cumtime ({cumulative_time_unit})")), + } + + # Print header with colors and proper alignment + print(f"{ANSIColors.BOLD_BLUE}Profile Stats:{ANSIColors.RESET}") + + header_nsamples = f"{ANSIColors.BOLD_BLUE}{'nsamples':>{col_widths['nsamples']}}{ANSIColors.RESET}" + header_sample_pct = f"{ANSIColors.BOLD_BLUE}{'sample%':>{col_widths['sample_pct']}}{ANSIColors.RESET}" + header_tottime = f"{ANSIColors.BOLD_BLUE}{f'tottime ({total_time_unit})':>{col_widths['tottime']}}{ANSIColors.RESET}" + header_cum_pct = f"{ANSIColors.BOLD_BLUE}{'cumul%':>{col_widths['cum_pct']}}{ANSIColors.RESET}" + header_cumtime = f"{ANSIColors.BOLD_BLUE}{f'cumtime ({cumulative_time_unit})':>{col_widths['cumtime']}}{ANSIColors.RESET}" + header_filename = ( + f"{ANSIColors.BOLD_BLUE}filename:lineno(function){ANSIColors.RESET}" + ) + + print( + f"{header_nsamples} {header_sample_pct} {header_tottime} {header_cum_pct} {header_cumtime} {header_filename}" + ) + + # Print each line with proper alignment + for ( + func, + direct_calls, + cumulative_calls, + total_time, + cumulative_time, + callers, + ) in stats_list: + # Calculate percentages + sample_pct = ( + (direct_calls / total_samples * 100) if total_samples > 0 else 0 + ) + cum_pct = ( + (cumulative_calls / total_samples * 100) + if total_samples > 0 + else 0 + ) + + # Format values with proper alignment - always use A/B format + nsamples_str = f"{direct_calls}/{cumulative_calls}" + nsamples_str = f"{nsamples_str:>{col_widths['nsamples']}}" + sample_pct_str = f"{sample_pct:{col_widths['sample_pct']}.1f}" + tottime = f"{total_time * total_time_scale:{col_widths['tottime']}.3f}" + cum_pct_str = f"{cum_pct:{col_widths['cum_pct']}.1f}" + cumtime = f"{cumulative_time * cumulative_time_scale:{col_widths['cumtime']}.3f}" + + # Format the function name with colors + func_name = ( + f"{ANSIColors.GREEN}{func[0]}{ANSIColors.RESET}:" + f"{ANSIColors.YELLOW}{func[1]}{ANSIColors.RESET}(" + f"{ANSIColors.CYAN}{func[2]}{ANSIColors.RESET})" + ) + + # Print the formatted line with consistent spacing + print( + f"{nsamples_str} {sample_pct_str} {tottime} {cum_pct_str} {cumtime} {func_name}" + ) + + # Print legend + print(f"\n{ANSIColors.BOLD_BLUE}Legend:{ANSIColors.RESET}") + print( + f" {ANSIColors.YELLOW}nsamples{ANSIColors.RESET}: Direct/Cumulative samples (direct executing / on call stack)" + ) + print( + f" {ANSIColors.YELLOW}sample%{ANSIColors.RESET}: Percentage of total samples this function was directly executing" + ) + print( + f" {ANSIColors.YELLOW}tottime{ANSIColors.RESET}: Estimated total time spent directly in this function" + ) + print( + f" {ANSIColors.YELLOW}cumul%{ANSIColors.RESET}: Percentage of total samples when this function was on the call stack" + ) + print( + f" {ANSIColors.YELLOW}cumtime{ANSIColors.RESET}: Estimated cumulative time (including time in called functions)" + ) + print( + f" {ANSIColors.YELLOW}filename:lineno(function){ANSIColors.RESET}: Function location and name" + ) + + # Print summary of interesting functions if enabled + if show_summary and stats_list: + self._print_summary(stats_list, total_samples) + + @staticmethod + def _determine_best_unit(max_value): + """Determine the best unit (s, ms, μs) and scale factor for a maximum value.""" + if max_value >= 1.0: + return "s", 1.0 + elif max_value >= 0.001: + return "ms", 1000.0 + else: + return "μs", 1000000.0 + + def _print_summary(self, stats_list, total_samples): + """Print summary of interesting functions.""" + print( + f"\n{ANSIColors.BOLD_BLUE}Summary of Interesting Functions:{ANSIColors.RESET}" + ) + + # Aggregate stats by fully qualified function name (ignoring line numbers) + func_aggregated = {} + for ( + func, + direct_calls, + cumulative_calls, + total_time, + cumulative_time, + callers, + ) in stats_list: + # Use filename:function_name as the key to get fully qualified name + qualified_name = f"{func[0]}:{func[2]}" + if qualified_name not in func_aggregated: + func_aggregated[qualified_name] = [ + 0, + 0, + 0, + 0, + ] # direct_calls, cumulative_calls, total_time, cumulative_time + func_aggregated[qualified_name][0] += direct_calls + func_aggregated[qualified_name][1] += cumulative_calls + func_aggregated[qualified_name][2] += total_time + func_aggregated[qualified_name][3] += cumulative_time + + # Convert aggregated data back to list format for processing + aggregated_stats = [] + for qualified_name, ( + prim_calls, + total_calls, + total_time, + cumulative_time, + ) in func_aggregated.items(): + # Parse the qualified name back to filename and function name + if ":" in qualified_name: + filename, func_name = qualified_name.rsplit(":", 1) + else: + filename, func_name = "", qualified_name + # Create a dummy func tuple with filename and function name for display + dummy_func = (filename, "", func_name) + aggregated_stats.append( + ( + dummy_func, + prim_calls, + total_calls, + total_time, + cumulative_time, + {}, + ) + ) + + # Determine best units for summary metrics + max_total_time = max( + (total_time for _, _, _, total_time, _, _ in aggregated_stats), + default=0, + ) + max_cumulative_time = max( + ( + cumulative_time + for _, _, _, _, cumulative_time, _ in aggregated_stats + ), + default=0, + ) + + total_unit, total_scale = self._determine_best_unit(max_total_time) + cumulative_unit, cumulative_scale = self._determine_best_unit( + max_cumulative_time + ) + + def _format_func_name(func): + """Format function name with colors.""" + return ( + f"{ANSIColors.GREEN}{func[0]}{ANSIColors.RESET}:" + f"{ANSIColors.YELLOW}{func[1]}{ANSIColors.RESET}(" + f"{ANSIColors.CYAN}{func[2]}{ANSIColors.RESET})" + ) + + def _print_top_functions(stats_list, title, key_func, format_line, n=3): + """Print top N functions sorted by key_func with formatted output.""" + print(f"\n{ANSIColors.BOLD_BLUE}{title}:{ANSIColors.RESET}") + sorted_stats = sorted(stats_list, key=key_func, reverse=True) + for stat in sorted_stats[:n]: + if line := format_line(stat): + print(f" {line}") + + # Functions with highest direct/cumulative ratio (hot spots) + def format_hotspots(stat): + func, direct_calls, cumulative_calls, total_time, _, _ = stat + if direct_calls > 0 and cumulative_calls > 0: + ratio = direct_calls / cumulative_calls + direct_pct = ( + (direct_calls / total_samples * 100) + if total_samples > 0 + else 0 + ) + return ( + f"{ratio:.3f} direct/cumulative ratio, " + f"{direct_pct:.1f}% direct samples: {_format_func_name(func)}" + ) + return None + + _print_top_functions( + aggregated_stats, + "Functions with Highest Direct/Cumulative Ratio (Hot Spots)", + key_func=lambda x: (x[1] / x[2]) if x[2] > 0 else 0, + format_line=format_hotspots, + ) + + # Functions with highest call frequency (cumulative/direct difference) + def format_call_frequency(stat): + func, direct_calls, cumulative_calls, total_time, _, _ = stat + if cumulative_calls > direct_calls: + call_frequency = cumulative_calls - direct_calls + cum_pct = ( + (cumulative_calls / total_samples * 100) + if total_samples > 0 + else 0 + ) + return ( + f"{call_frequency:d} indirect calls, " + f"{cum_pct:.1f}% total stack presence: {_format_func_name(func)}" + ) + return None + + _print_top_functions( + aggregated_stats, + "Functions with Highest Call Frequency (Indirect Calls)", + key_func=lambda x: x[2] - x[1], # Sort by (cumulative - direct) + format_line=format_call_frequency, + ) + + # Functions with highest cumulative-to-direct multiplier (call magnification) + def format_call_magnification(stat): + func, direct_calls, cumulative_calls, total_time, _, _ = stat + if direct_calls > 0 and cumulative_calls > direct_calls: + multiplier = cumulative_calls / direct_calls + indirect_calls = cumulative_calls - direct_calls + return ( + f"{multiplier:.1f}x call magnification, " + f"{indirect_calls:d} indirect calls from {direct_calls:d} direct: {_format_func_name(func)}" + ) + return None + + _print_top_functions( + aggregated_stats, + "Functions with Highest Call Magnification (Cumulative/Direct)", + key_func=lambda x: (x[2] / x[1]) + if x[1] > 0 + else 0, # Sort by cumulative/direct ratio + format_line=format_call_magnification, + ) diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index 929a92e1dda..d4c3b577a17 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -1,9 +1,6 @@ -import argparse import _remote_debugging import os import pstats -import socket -import subprocess import statistics import sys import sysconfig @@ -12,127 +9,56 @@ from collections import deque from _colorize import ANSIColors from .pstats_collector import PstatsCollector -from .stack_collector import CollapsedStackCollector +from .stack_collector import CollapsedStackCollector, FlamegraphCollector +from .heatmap_collector import HeatmapCollector +from .gecko_collector import GeckoCollector +from .constants import ( + PROFILING_MODE_WALL, + PROFILING_MODE_CPU, + PROFILING_MODE_GIL, + PROFILING_MODE_ALL, + PROFILING_MODE_EXCEPTION, +) +try: + from .live_collector import LiveStatsCollector +except ImportError: + LiveStatsCollector = None _FREE_THREADED_BUILD = sysconfig.get_config_var("Py_GIL_DISABLED") is not None -_MAX_STARTUP_ATTEMPTS = 5 -_STARTUP_RETRY_DELAY_SECONDS = 0.1 -_HELP_DESCRIPTION = """Sample a process's stack frames and generate profiling data. -Supports the following target modes: - - -p PID: Profile an existing process by PID - - -m MODULE [ARGS...]: Profile a module as python -m module ... - - filename [ARGS...]: Profile the specified script by running it in a subprocess - -Examples: - # Profile process 1234 for 10 seconds with default settings - python -m profiling.sampling -p 1234 - - # Profile a script by running it in a subprocess - python -m profiling.sampling myscript.py arg1 arg2 - - # Profile a module by running it as python -m module in a subprocess - python -m profiling.sampling -m mymodule arg1 arg2 - - # Profile with custom interval and duration, save to file - python -m profiling.sampling -i 50 -d 30 -o profile.stats -p 1234 - - # Generate collapsed stacks for flamegraph - python -m profiling.sampling --collapsed -p 1234 - - # Profile all threads, sort by total time - python -m profiling.sampling -a --sort-tottime -p 1234 - - # Profile for 1 minute with 1ms sampling interval - python -m profiling.sampling -i 1000 -d 60 -p 1234 - - # Show only top 20 functions sorted by direct samples - python -m profiling.sampling --sort-nsamples -l 20 -p 1234 - - # Profile all threads and save collapsed stacks - python -m profiling.sampling -a --collapsed -o stacks.txt -p 1234 - - # Profile with real-time sampling statistics - python -m profiling.sampling --realtime-stats -p 1234 - - # Sort by sample percentage to find most sampled functions - python -m profiling.sampling --sort-sample-pct -p 1234 - - # Sort by cumulative samples to find functions most on call stack - python -m profiling.sampling --sort-nsamples-cumul -p 1234""" - - -# Constants for socket synchronization -_SYNC_TIMEOUT = 5.0 -_PROCESS_KILL_TIMEOUT = 2.0 -_READY_MESSAGE = b"ready" -_RECV_BUFFER_SIZE = 1024 - - -def _run_with_sync(original_cmd): - """Run a command with socket-based synchronization and return the process.""" - # Create a TCP socket for synchronization with better socket options - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sync_sock: - # Set SO_REUSEADDR to avoid "Address already in use" errors - sync_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sync_sock.bind(("127.0.0.1", 0)) # Let OS choose a free port - sync_port = sync_sock.getsockname()[1] - sync_sock.listen(1) - sync_sock.settimeout(_SYNC_TIMEOUT) - - # Get current working directory to preserve it - cwd = os.getcwd() - - # Build command using the sync coordinator - target_args = original_cmd[1:] # Remove python executable - cmd = (sys.executable, "-m", "profiling.sampling._sync_coordinator", str(sync_port), cwd) + tuple(target_args) - - # Start the process with coordinator - process = subprocess.Popen(cmd) - - try: - # Wait for ready signal with timeout - with sync_sock.accept()[0] as conn: - ready_signal = conn.recv(_RECV_BUFFER_SIZE) - - if ready_signal != _READY_MESSAGE: - raise RuntimeError(f"Invalid ready signal received: {ready_signal!r}") - - except socket.timeout: - # If we timeout, kill the process and raise an error - if process.poll() is None: - process.terminate() - try: - process.wait(timeout=_PROCESS_KILL_TIMEOUT) - except subprocess.TimeoutExpired: - process.kill() - process.wait() - raise RuntimeError("Process failed to signal readiness within timeout") - - return process - - class SampleProfiler: - def __init__(self, pid, sample_interval_usec, all_threads): + def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MODE_WALL, native=False, gc=True, opcodes=False, skip_non_matching_threads=True, collect_stats=False): self.pid = pid self.sample_interval_usec = sample_interval_usec self.all_threads = all_threads - if _FREE_THREADED_BUILD: - self.unwinder = _remote_debugging.RemoteUnwinder( - self.pid, all_threads=self.all_threads - ) - else: - only_active_threads = bool(self.all_threads) - self.unwinder = _remote_debugging.RemoteUnwinder( - self.pid, only_active_thread=only_active_threads - ) + self.mode = mode # Store mode for later use + self.collect_stats = collect_stats + try: + self.unwinder = self._new_unwinder(native, gc, opcodes, skip_non_matching_threads) + except RuntimeError as err: + raise SystemExit(err) from err # Track sample intervals and total sample count self.sample_intervals = deque(maxlen=100) self.total_samples = 0 self.realtime_stats = False - def sample(self, collector, duration_sec=10): + def _new_unwinder(self, native, gc, opcodes, skip_non_matching_threads): + if _FREE_THREADED_BUILD: + unwinder = _remote_debugging.RemoteUnwinder( + self.pid, all_threads=self.all_threads, mode=self.mode, native=native, gc=gc, + opcodes=opcodes, skip_non_matching_threads=skip_non_matching_threads, + cache_frames=True, stats=self.collect_stats + ) + else: + unwinder = _remote_debugging.RemoteUnwinder( + self.pid, only_active_thread=bool(self.all_threads), mode=self.mode, native=native, gc=gc, + opcodes=opcodes, skip_non_matching_threads=skip_non_matching_threads, + cache_frames=True, stats=self.collect_stats + ) + return unwinder + + def sample(self, collector, duration_sec=10, *, async_aware=False): sample_interval_sec = self.sample_interval_usec / 1_000_000 running_time = 0 num_samples = 0 @@ -141,78 +67,93 @@ class SampleProfiler: last_sample_time = start_time realtime_update_interval = 1.0 # Update every second last_realtime_update = start_time + interrupted = False - while running_time < duration_sec: - current_time = time.perf_counter() - if next_time < current_time: - try: - stack_frames = self.unwinder.get_stack_trace() - collector.collect(stack_frames) - except ProcessLookupError: - duration_sec = current_time - start_time + try: + while running_time < duration_sec: + # Check if live collector wants to stop + if hasattr(collector, 'running') and not collector.running: break - except (RuntimeError, UnicodeDecodeError, MemoryError, OSError): - errors += 1 - except Exception as e: - if not self._is_process_running(): + + current_time = time.perf_counter() + if next_time < current_time: + try: + if async_aware == "all": + stack_frames = self.unwinder.get_all_awaited_by() + elif async_aware == "running": + stack_frames = self.unwinder.get_async_stack_trace() + else: + stack_frames = self.unwinder.get_stack_trace() + collector.collect(stack_frames) + except ProcessLookupError: + duration_sec = current_time - start_time break - raise e from None + except (RuntimeError, UnicodeDecodeError, MemoryError, OSError): + collector.collect_failed_sample() + errors += 1 + except Exception as e: + if not _is_process_running(self.pid): + break + raise e from None - # Track actual sampling intervals for real-time stats - if num_samples > 0: - actual_interval = current_time - last_sample_time - self.sample_intervals.append( - 1.0 / actual_interval - ) # Convert to Hz - self.total_samples += 1 + # Track actual sampling intervals for real-time stats + if num_samples > 0: + actual_interval = current_time - last_sample_time + self.sample_intervals.append( + 1.0 / actual_interval + ) # Convert to Hz + self.total_samples += 1 - # Print real-time statistics if enabled - if ( - self.realtime_stats - and (current_time - last_realtime_update) - >= realtime_update_interval - ): - self._print_realtime_stats() - last_realtime_update = current_time + # Print real-time statistics if enabled + if ( + self.realtime_stats + and (current_time - last_realtime_update) + >= realtime_update_interval + ): + self._print_realtime_stats() + last_realtime_update = current_time - last_sample_time = current_time - num_samples += 1 - next_time += sample_interval_sec + last_sample_time = current_time + num_samples += 1 + next_time += sample_interval_sec + running_time = time.perf_counter() - start_time + except KeyboardInterrupt: + interrupted = True running_time = time.perf_counter() - start_time + print("Interrupted by user.") # Clear real-time stats line if it was being displayed if self.realtime_stats and len(self.sample_intervals) > 0: print() # Add newline after real-time stats - print(f"Captured {num_samples} samples in {running_time:.2f} seconds") - print(f"Sample rate: {num_samples / running_time:.2f} samples/sec") - print(f"Error rate: {(errors / num_samples) * 100:.2f}%") - + sample_rate = num_samples / running_time if running_time > 0 else 0 + error_rate = (errors / num_samples) * 100 if num_samples > 0 else 0 expected_samples = int(duration_sec / sample_interval_sec) - if num_samples < expected_samples: + missed_samples = (expected_samples - num_samples) / expected_samples * 100 if expected_samples > 0 else 0 + + # Don't print stats for live mode (curses is handling display) + is_live_mode = LiveStatsCollector is not None and isinstance(collector, LiveStatsCollector) + if not is_live_mode: + print(f"Captured {num_samples} samples in {running_time:.2f} seconds") + print(f"Sample rate: {sample_rate:.2f} samples/sec") + print(f"Error rate: {error_rate:.2f}%") + + # Print unwinder stats if stats collection is enabled + if self.collect_stats: + self._print_unwinder_stats() + + # Pass stats to flamegraph collector if it's the right type + if hasattr(collector, 'set_stats'): + collector.set_stats(self.sample_interval_usec, running_time, sample_rate, error_rate, missed_samples, mode=self.mode) + + if num_samples < expected_samples and not is_live_mode and not interrupted: print( f"Warning: missed {expected_samples - num_samples} samples " f"from the expected total of {expected_samples} " f"({(expected_samples - num_samples) / expected_samples * 100:.2f}%)" ) - def _is_process_running(self): - if sys.platform == "linux" or sys.platform == "darwin": - try: - os.kill(self.pid, 0) - return True - except ProcessLookupError: - return False - elif sys.platform == "win32": - try: - _remote_debugging.RemoteUnwinder(self.pid) - except Exception: - return False - return True - else: - raise ValueError(f"Unsupported platform: {sys.platform}") - def _print_realtime_stats(self): """Print real-time sampling statistics.""" if len(self.sample_intervals) < 2: @@ -233,632 +174,255 @@ class SampleProfiler: (1.0 / min_hz) * 1_000_000 if min_hz > 0 else 0 ) # Max time = Min Hz + # Build cache stats string if stats collection is enabled + cache_stats_str = "" + if self.collect_stats: + try: + stats = self.unwinder.get_stats() + hits = stats.get('frame_cache_hits', 0) + partial = stats.get('frame_cache_partial_hits', 0) + misses = stats.get('frame_cache_misses', 0) + total = hits + partial + misses + if total > 0: + hit_pct = (hits + partial) / total * 100 + cache_stats_str = f" {ANSIColors.MAGENTA}Cache: {hit_pct:.1f}% ({hits}+{partial}/{misses}){ANSIColors.RESET}" + except RuntimeError: + pass + # Clear line and print stats print( - f"\r\033[K{ANSIColors.BOLD_BLUE}Real-time sampling stats:{ANSIColors.RESET} " - f"{ANSIColors.YELLOW}Mean: {mean_hz:.1f}Hz ({mean_us_per_sample:.2f}µs){ANSIColors.RESET} " - f"{ANSIColors.GREEN}Min: {min_hz:.1f}Hz ({max_us_per_sample:.2f}µs){ANSIColors.RESET} " - f"{ANSIColors.RED}Max: {max_hz:.1f}Hz ({min_us_per_sample:.2f}µs){ANSIColors.RESET} " - f"{ANSIColors.CYAN}Samples: {self.total_samples}{ANSIColors.RESET}", + f"\r\033[K{ANSIColors.BOLD_BLUE}Stats:{ANSIColors.RESET} " + f"{ANSIColors.YELLOW}{mean_hz:.1f}Hz ({mean_us_per_sample:.1f}µs){ANSIColors.RESET} " + f"{ANSIColors.GREEN}Min: {min_hz:.1f}Hz{ANSIColors.RESET} " + f"{ANSIColors.RED}Max: {max_hz:.1f}Hz{ANSIColors.RESET} " + f"{ANSIColors.CYAN}N={self.total_samples}{ANSIColors.RESET}" + f"{cache_stats_str}", end="", flush=True, ) + def _print_unwinder_stats(self): + """Print unwinder statistics including cache performance.""" + try: + stats = self.unwinder.get_stats() + except RuntimeError: + return # Stats not enabled -def _determine_best_unit(max_value): - """Determine the best unit (s, ms, μs) and scale factor for a maximum value.""" - if max_value >= 1.0: - return "s", 1.0 - elif max_value >= 0.001: - return "ms", 1000.0 - else: - return "μs", 1000000.0 + print(f"\n{ANSIColors.BOLD_BLUE}{'='*50}{ANSIColors.RESET}") + print(f"{ANSIColors.BOLD_BLUE}Unwinder Statistics:{ANSIColors.RESET}") + # Frame cache stats + total_samples = stats.get('total_samples', 0) + frame_cache_hits = stats.get('frame_cache_hits', 0) + frame_cache_partial_hits = stats.get('frame_cache_partial_hits', 0) + frame_cache_misses = stats.get('frame_cache_misses', 0) + total_lookups = frame_cache_hits + frame_cache_partial_hits + frame_cache_misses -def print_sampled_stats( - stats, sort=-1, limit=None, show_summary=True, sample_interval_usec=100 -): - # Get the stats data - stats_list = [] - for func, ( - direct_calls, - cumulative_calls, - total_time, - cumulative_time, - callers, - ) in stats.stats.items(): - stats_list.append( - ( - func, - direct_calls, - cumulative_calls, - total_time, - cumulative_time, - callers, - ) - ) - - # Calculate total samples for percentage calculations (using direct_calls) - total_samples = sum( - direct_calls for _, direct_calls, _, _, _, _ in stats_list - ) - - # Sort based on the requested field - sort_field = sort - if sort_field == -1: # stdname - stats_list.sort(key=lambda x: str(x[0])) - elif sort_field == 0: # nsamples (direct samples) - stats_list.sort(key=lambda x: x[1], reverse=True) # direct_calls - elif sort_field == 1: # tottime - stats_list.sort(key=lambda x: x[3], reverse=True) # total_time - elif sort_field == 2: # cumtime - stats_list.sort(key=lambda x: x[4], reverse=True) # cumulative_time - elif sort_field == 3: # sample% - stats_list.sort( - key=lambda x: (x[1] / total_samples * 100) - if total_samples > 0 - else 0, - reverse=True, # direct_calls percentage - ) - elif sort_field == 4: # cumul% - stats_list.sort( - key=lambda x: (x[2] / total_samples * 100) - if total_samples > 0 - else 0, - reverse=True, # cumulative_calls percentage - ) - elif sort_field == 5: # nsamples (cumulative samples) - stats_list.sort(key=lambda x: x[2], reverse=True) # cumulative_calls - - # Apply limit if specified - if limit is not None: - stats_list = stats_list[:limit] - - # Determine the best unit for time columns based on maximum values - max_total_time = max( - (total_time for _, _, _, total_time, _, _ in stats_list), default=0 - ) - max_cumulative_time = max( - (cumulative_time for _, _, _, _, cumulative_time, _ in stats_list), - default=0, - ) - - total_time_unit, total_time_scale = _determine_best_unit(max_total_time) - cumulative_time_unit, cumulative_time_scale = _determine_best_unit( - max_cumulative_time - ) - - # Define column widths for consistent alignment - col_widths = { - "nsamples": 15, # "nsamples" column (inline/cumulative format) - "sample_pct": 8, # "sample%" column - "tottime": max(12, len(f"tottime ({total_time_unit})")), - "cum_pct": 8, # "cumul%" column - "cumtime": max(12, len(f"cumtime ({cumulative_time_unit})")), - } - - # Print header with colors and proper alignment - print(f"{ANSIColors.BOLD_BLUE}Profile Stats:{ANSIColors.RESET}") - - header_nsamples = f"{ANSIColors.BOLD_BLUE}{'nsamples':>{col_widths['nsamples']}}{ANSIColors.RESET}" - header_sample_pct = f"{ANSIColors.BOLD_BLUE}{'sample%':>{col_widths['sample_pct']}}{ANSIColors.RESET}" - header_tottime = f"{ANSIColors.BOLD_BLUE}{f'tottime ({total_time_unit})':>{col_widths['tottime']}}{ANSIColors.RESET}" - header_cum_pct = f"{ANSIColors.BOLD_BLUE}{'cumul%':>{col_widths['cum_pct']}}{ANSIColors.RESET}" - header_cumtime = f"{ANSIColors.BOLD_BLUE}{f'cumtime ({cumulative_time_unit})':>{col_widths['cumtime']}}{ANSIColors.RESET}" - header_filename = ( - f"{ANSIColors.BOLD_BLUE}filename:lineno(function){ANSIColors.RESET}" - ) - - print( - f"{header_nsamples} {header_sample_pct} {header_tottime} {header_cum_pct} {header_cumtime} {header_filename}" - ) - - # Print each line with proper alignment - for ( - func, - direct_calls, - cumulative_calls, - total_time, - cumulative_time, - callers, - ) in stats_list: # Calculate percentages - sample_pct = ( - (direct_calls / total_samples * 100) if total_samples > 0 else 0 - ) - cum_pct = ( - (cumulative_calls / total_samples * 100) - if total_samples > 0 - else 0 - ) + hits_pct = (frame_cache_hits / total_lookups * 100) if total_lookups > 0 else 0 + partial_pct = (frame_cache_partial_hits / total_lookups * 100) if total_lookups > 0 else 0 + misses_pct = (frame_cache_misses / total_lookups * 100) if total_lookups > 0 else 0 - # Format values with proper alignment - always use A/B format - nsamples_str = f"{direct_calls}/{cumulative_calls}" - nsamples_str = f"{nsamples_str:>{col_widths['nsamples']}}" - sample_pct_str = f"{sample_pct:{col_widths['sample_pct']}.1f}" - tottime = f"{total_time * total_time_scale:{col_widths['tottime']}.3f}" - cum_pct_str = f"{cum_pct:{col_widths['cum_pct']}.1f}" - cumtime = f"{cumulative_time * cumulative_time_scale:{col_widths['cumtime']}.3f}" + print(f" {ANSIColors.CYAN}Frame Cache:{ANSIColors.RESET}") + print(f" Total samples: {total_samples:,}") + print(f" Full hits: {frame_cache_hits:,} ({ANSIColors.GREEN}{hits_pct:.1f}%{ANSIColors.RESET})") + print(f" Partial hits: {frame_cache_partial_hits:,} ({ANSIColors.YELLOW}{partial_pct:.1f}%{ANSIColors.RESET})") + print(f" Misses: {frame_cache_misses:,} ({ANSIColors.RED}{misses_pct:.1f}%{ANSIColors.RESET})") - # Format the function name with colors - func_name = ( - f"{ANSIColors.GREEN}{func[0]}{ANSIColors.RESET}:" - f"{ANSIColors.YELLOW}{func[1]}{ANSIColors.RESET}(" - f"{ANSIColors.CYAN}{func[2]}{ANSIColors.RESET})" - ) + # Frame read stats + frames_from_cache = stats.get('frames_read_from_cache', 0) + frames_from_memory = stats.get('frames_read_from_memory', 0) + total_frames = frames_from_cache + frames_from_memory + cache_frame_pct = (frames_from_cache / total_frames * 100) if total_frames > 0 else 0 + memory_frame_pct = (frames_from_memory / total_frames * 100) if total_frames > 0 else 0 - # Print the formatted line with consistent spacing - print( - f"{nsamples_str} {sample_pct_str} {tottime} {cum_pct_str} {cumtime} {func_name}" - ) + print(f" {ANSIColors.CYAN}Frame Reads:{ANSIColors.RESET}") + print(f" From cache: {frames_from_cache:,} ({ANSIColors.GREEN}{cache_frame_pct:.1f}%{ANSIColors.RESET})") + print(f" From memory: {frames_from_memory:,} ({ANSIColors.RED}{memory_frame_pct:.1f}%{ANSIColors.RESET})") - # Print legend - print(f"\n{ANSIColors.BOLD_BLUE}Legend:{ANSIColors.RESET}") - print( - f" {ANSIColors.YELLOW}nsamples{ANSIColors.RESET}: Direct/Cumulative samples (direct executing / on call stack)" - ) - print( - f" {ANSIColors.YELLOW}sample%{ANSIColors.RESET}: Percentage of total samples this function was directly executing" - ) - print( - f" {ANSIColors.YELLOW}tottime{ANSIColors.RESET}: Estimated total time spent directly in this function" - ) - print( - f" {ANSIColors.YELLOW}cumul%{ANSIColors.RESET}: Percentage of total samples when this function was on the call stack" - ) - print( - f" {ANSIColors.YELLOW}cumtime{ANSIColors.RESET}: Estimated cumulative time (including time in called functions)" - ) - print( - f" {ANSIColors.YELLOW}filename:lineno(function){ANSIColors.RESET}: Function location and name" - ) + # Code object cache stats + code_hits = stats.get('code_object_cache_hits', 0) + code_misses = stats.get('code_object_cache_misses', 0) + total_code = code_hits + code_misses + code_hits_pct = (code_hits / total_code * 100) if total_code > 0 else 0 + code_misses_pct = (code_misses / total_code * 100) if total_code > 0 else 0 - def _format_func_name(func): - """Format function name with colors.""" - return ( - f"{ANSIColors.GREEN}{func[0]}{ANSIColors.RESET}:" - f"{ANSIColors.YELLOW}{func[1]}{ANSIColors.RESET}(" - f"{ANSIColors.CYAN}{func[2]}{ANSIColors.RESET})" - ) + print(f" {ANSIColors.CYAN}Code Object Cache:{ANSIColors.RESET}") + print(f" Hits: {code_hits:,} ({ANSIColors.GREEN}{code_hits_pct:.1f}%{ANSIColors.RESET})") + print(f" Misses: {code_misses:,} ({ANSIColors.RED}{code_misses_pct:.1f}%{ANSIColors.RESET})") - def _print_top_functions(stats_list, title, key_func, format_line, n=3): - """Print top N functions sorted by key_func with formatted output.""" - print(f"\n{ANSIColors.BOLD_BLUE}{title}:{ANSIColors.RESET}") - sorted_stats = sorted(stats_list, key=key_func, reverse=True) - for stat in sorted_stats[:n]: - if line := format_line(stat): - print(f" {line}") + # Memory operations + memory_reads = stats.get('memory_reads', 0) + memory_bytes = stats.get('memory_bytes_read', 0) + if memory_bytes >= 1024 * 1024: + memory_str = f"{memory_bytes / (1024 * 1024):.1f} MB" + elif memory_bytes >= 1024: + memory_str = f"{memory_bytes / 1024:.1f} KB" + else: + memory_str = f"{memory_bytes} B" + print(f" {ANSIColors.CYAN}Memory:{ANSIColors.RESET}") + print(f" Read operations: {memory_reads:,} ({memory_str})") - # Print summary of interesting functions if enabled - if show_summary and stats_list: - print( - f"\n{ANSIColors.BOLD_BLUE}Summary of Interesting Functions:{ANSIColors.RESET}" - ) + # Stale invalidations + stale_invalidations = stats.get('stale_cache_invalidations', 0) + if stale_invalidations > 0: + print(f" {ANSIColors.YELLOW}Stale cache invalidations: {stale_invalidations}{ANSIColors.RESET}") - # Aggregate stats by fully qualified function name (ignoring line numbers) - func_aggregated = {} - for ( - func, - direct_calls, - cumulative_calls, - total_time, - cumulative_time, - callers, - ) in stats_list: - # Use filename:function_name as the key to get fully qualified name - qualified_name = f"{func[0]}:{func[2]}" - if qualified_name not in func_aggregated: - func_aggregated[qualified_name] = [ - 0, - 0, - 0, - 0, - ] # direct_calls, cumulative_calls, total_time, cumulative_time - func_aggregated[qualified_name][0] += direct_calls - func_aggregated[qualified_name][1] += cumulative_calls - func_aggregated[qualified_name][2] += total_time - func_aggregated[qualified_name][3] += cumulative_time - # Convert aggregated data back to list format for processing - aggregated_stats = [] - for qualified_name, ( - prim_calls, - total_calls, - total_time, - cumulative_time, - ) in func_aggregated.items(): - # Parse the qualified name back to filename and function name - if ":" in qualified_name: - filename, func_name = qualified_name.rsplit(":", 1) - else: - filename, func_name = "", qualified_name - # Create a dummy func tuple with filename and function name for display - dummy_func = (filename, "", func_name) - aggregated_stats.append( - ( - dummy_func, - prim_calls, - total_calls, - total_time, - cumulative_time, - {}, - ) - ) - - # Determine best units for summary metrics - max_total_time = max( - (total_time for _, _, _, total_time, _, _ in aggregated_stats), - default=0, - ) - max_cumulative_time = max( - ( - cumulative_time - for _, _, _, _, cumulative_time, _ in aggregated_stats - ), - default=0, - ) - - total_unit, total_scale = _determine_best_unit(max_total_time) - cumulative_unit, cumulative_scale = _determine_best_unit( - max_cumulative_time - ) - - # Functions with highest direct/cumulative ratio (hot spots) - def format_hotspots(stat): - func, direct_calls, cumulative_calls, total_time, _, _ = stat - if direct_calls > 0 and cumulative_calls > 0: - ratio = direct_calls / cumulative_calls - direct_pct = ( - (direct_calls / total_samples * 100) - if total_samples > 0 - else 0 - ) - return ( - f"{ratio:.3f} direct/cumulative ratio, " - f"{direct_pct:.1f}% direct samples: {_format_func_name(func)}" - ) - return None - - _print_top_functions( - aggregated_stats, - "Functions with Highest Direct/Cumulative Ratio (Hot Spots)", - key_func=lambda x: (x[1] / x[2]) if x[2] > 0 else 0, - format_line=format_hotspots, - ) - - # Functions with highest call frequency (cumulative/direct difference) - def format_call_frequency(stat): - func, direct_calls, cumulative_calls, total_time, _, _ = stat - if cumulative_calls > direct_calls: - call_frequency = cumulative_calls - direct_calls - cum_pct = ( - (cumulative_calls / total_samples * 100) - if total_samples > 0 - else 0 - ) - return ( - f"{call_frequency:d} indirect calls, " - f"{cum_pct:.1f}% total stack presence: {_format_func_name(func)}" - ) - return None - - _print_top_functions( - aggregated_stats, - "Functions with Highest Call Frequency (Indirect Calls)", - key_func=lambda x: x[2] - x[1], # Sort by (cumulative - direct) - format_line=format_call_frequency, - ) - - # Functions with highest cumulative-to-direct multiplier (call magnification) - def format_call_magnification(stat): - func, direct_calls, cumulative_calls, total_time, _, _ = stat - if direct_calls > 0 and cumulative_calls > direct_calls: - multiplier = cumulative_calls / direct_calls - indirect_calls = cumulative_calls - direct_calls - return ( - f"{multiplier:.1f}x call magnification, " - f"{indirect_calls:d} indirect calls from {direct_calls:d} direct: {_format_func_name(func)}" - ) - return None - - _print_top_functions( - aggregated_stats, - "Functions with Highest Call Magnification (Cumulative/Direct)", - key_func=lambda x: (x[2] / x[1]) - if x[1] > 0 - else 0, # Sort by cumulative/direct ratio - format_line=format_call_magnification, - ) +def _is_process_running(pid): + if pid <= 0: + return False + if os.name == "posix": + try: + os.kill(pid, 0) + return True + except ProcessLookupError: + return False + except PermissionError: + # EPERM means process exists but we can't signal it + return True + elif sys.platform == "win32": + try: + _remote_debugging.RemoteUnwinder(pid) + except Exception: + return False + return True + else: + raise ValueError(f"Unsupported platform: {sys.platform}") def sample( pid, + collector, *, - sort=2, - sample_interval_usec=100, duration_sec=10, - filename=None, all_threads=False, - limit=None, - show_summary=True, - output_format="pstats", realtime_stats=False, + mode=PROFILING_MODE_WALL, + async_aware=None, + native=False, + gc=True, + opcodes=False, ): + """Sample a process using the provided collector. + + Args: + pid: Process ID to sample + collector: Collector instance to use for gathering samples + duration_sec: How long to sample for (seconds) + all_threads: Whether to sample all threads + realtime_stats: Whether to print real-time sampling statistics + mode: Profiling mode - WALL (all samples), CPU (only when on CPU), + GIL (only when holding GIL), ALL (includes GIL and CPU status), + EXCEPTION (only when thread has an active exception) + native: Whether to include native frames + gc: Whether to include GC frames + opcodes: Whether to include opcode information + + Returns: + The collector with collected samples + """ + # Get sample interval from collector + sample_interval_usec = collector.sample_interval_usec + + # PROFILING_MODE_ALL implies no skipping at all + if mode == PROFILING_MODE_ALL: + skip_non_matching_threads = False + else: + # For most modes, skip non-matching threads + # Gecko collector overrides this by setting skip_idle=False + skip_non_matching_threads = True + profiler = SampleProfiler( - pid, sample_interval_usec, all_threads=all_threads + pid, + sample_interval_usec, + all_threads=all_threads, + mode=mode, + native=native, + gc=gc, + opcodes=opcodes, + skip_non_matching_threads=skip_non_matching_threads, + collect_stats=realtime_stats, ) profiler.realtime_stats = realtime_stats - collector = None - match output_format: - case "pstats": - collector = PstatsCollector(sample_interval_usec) - case "collapsed": - collector = CollapsedStackCollector() - filename = filename or f"collapsed.{pid}.txt" - case _: - raise ValueError(f"Invalid output format: {output_format}") + # Run the sampling + profiler.sample(collector, duration_sec, async_aware=async_aware) - profiler.sample(collector, duration_sec) + return collector - if output_format == "pstats" and not filename: - stats = pstats.SampledStats(collector).strip_dirs() - print_sampled_stats( - stats, sort, limit, show_summary, sample_interval_usec - ) + +def sample_live( + pid, + collector, + *, + duration_sec=10, + all_threads=False, + realtime_stats=False, + mode=PROFILING_MODE_WALL, + async_aware=None, + native=False, + gc=True, + opcodes=False, +): + """Sample a process in live/interactive mode with curses TUI. + + Args: + pid: Process ID to sample + collector: LiveStatsCollector instance + duration_sec: How long to sample for (seconds) + all_threads: Whether to sample all threads + realtime_stats: Whether to print real-time sampling statistics + mode: Profiling mode - WALL (all samples), CPU (only when on CPU), + GIL (only when holding GIL), ALL (includes GIL and CPU status), + EXCEPTION (only when thread has an active exception) + native: Whether to include native frames + gc: Whether to include GC frames + opcodes: Whether to include opcode information + + Returns: + The collector with collected samples + """ + import curses + + # Get sample interval from collector + sample_interval_usec = collector.sample_interval_usec + + # PROFILING_MODE_ALL implies no skipping at all + if mode == PROFILING_MODE_ALL: + skip_non_matching_threads = False else: - collector.export(filename) + skip_non_matching_threads = True - -def _validate_collapsed_format_args(args, parser): - # Check for incompatible pstats options - invalid_opts = [] - - # Get list of pstats-specific options - pstats_options = {"sort": None, "limit": None, "no_summary": False} - - # Find the default values from the argument definitions - for action in parser._actions: - if action.dest in pstats_options and hasattr(action, "default"): - pstats_options[action.dest] = action.default - - # Check if any pstats-specific options were provided by comparing with defaults - for opt, default in pstats_options.items(): - if getattr(args, opt) != default: - invalid_opts.append(opt.replace("no_", "")) - - if invalid_opts: - parser.error( - f"The following options are only valid with --pstats format: {', '.join(invalid_opts)}" - ) - - # Set default output filename for collapsed format only if we have a PID - # For module/script execution, this will be set later with the subprocess PID - if not args.outfile and args.pid is not None: - args.outfile = f"collapsed.{args.pid}.txt" - - -def wait_for_process_and_sample(pid, sort_value, args): - """Sample the process immediately since it has already signaled readiness.""" - # Set default collapsed filename with subprocess PID if not already set - filename = args.outfile - if not filename and args.format == "collapsed": - filename = f"collapsed.{pid}.txt" - - sample( + profiler = SampleProfiler( pid, - sort=sort_value, - sample_interval_usec=args.interval, - duration_sec=args.duration, - filename=filename, - all_threads=args.all_threads, - limit=args.limit, - show_summary=not args.no_summary, - output_format=args.format, - realtime_stats=args.realtime_stats, + sample_interval_usec, + all_threads=all_threads, + mode=mode, + native=native, + gc=gc, + opcodes=opcodes, + skip_non_matching_threads=skip_non_matching_threads, + collect_stats=realtime_stats, ) + profiler.realtime_stats = realtime_stats - -def main(): - # Create the main parser - parser = argparse.ArgumentParser( - description=_HELP_DESCRIPTION, - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - - # Target selection - target_group = parser.add_mutually_exclusive_group(required=False) - target_group.add_argument( - "-p", "--pid", type=int, help="Process ID to sample" - ) - target_group.add_argument( - "-m", "--module", - help="Run and profile a module as python -m module [ARGS...]" - ) - parser.add_argument( - "args", - nargs=argparse.REMAINDER, - help="Script to run and profile, with optional arguments" - ) - - # Sampling options - sampling_group = parser.add_argument_group("Sampling configuration") - sampling_group.add_argument( - "-i", - "--interval", - type=int, - default=100, - help="Sampling interval in microseconds (default: 100)", - ) - sampling_group.add_argument( - "-d", - "--duration", - type=int, - default=10, - help="Sampling duration in seconds (default: 10)", - ) - sampling_group.add_argument( - "-a", - "--all-threads", - action="store_true", - help="Sample all threads in the process instead of just the main thread", - ) - sampling_group.add_argument( - "--realtime-stats", - action="store_true", - default=False, - help="Print real-time sampling statistics (Hz, mean, min, max, stdev) during profiling", - ) - - # Output format selection - output_group = parser.add_argument_group("Output options") - output_format = output_group.add_mutually_exclusive_group() - output_format.add_argument( - "--pstats", - action="store_const", - const="pstats", - dest="format", - default="pstats", - help="Generate pstats output (default)", - ) - output_format.add_argument( - "--collapsed", - action="store_const", - const="collapsed", - dest="format", - help="Generate collapsed stack traces for flamegraphs", - ) - - output_group.add_argument( - "-o", - "--outfile", - help="Save output to a file (if omitted, prints to stdout for pstats, " - "or saves to collapsed..txt for collapsed format)", - ) - - # pstats-specific options - pstats_group = parser.add_argument_group("pstats format options") - sort_group = pstats_group.add_mutually_exclusive_group() - sort_group.add_argument( - "--sort-nsamples", - action="store_const", - const=0, - dest="sort", - help="Sort by number of direct samples (nsamples column)", - ) - sort_group.add_argument( - "--sort-tottime", - action="store_const", - const=1, - dest="sort", - help="Sort by total time (tottime column)", - ) - sort_group.add_argument( - "--sort-cumtime", - action="store_const", - const=2, - dest="sort", - help="Sort by cumulative time (cumtime column, default)", - ) - sort_group.add_argument( - "--sort-sample-pct", - action="store_const", - const=3, - dest="sort", - help="Sort by sample percentage (sample%% column)", - ) - sort_group.add_argument( - "--sort-cumul-pct", - action="store_const", - const=4, - dest="sort", - help="Sort by cumulative sample percentage (cumul%% column)", - ) - sort_group.add_argument( - "--sort-nsamples-cumul", - action="store_const", - const=5, - dest="sort", - help="Sort by cumulative samples (nsamples column, cumulative part)", - ) - sort_group.add_argument( - "--sort-name", - action="store_const", - const=-1, - dest="sort", - help="Sort by function name", - ) - - pstats_group.add_argument( - "-l", - "--limit", - type=int, - help="Limit the number of rows in the output", - default=15, - ) - pstats_group.add_argument( - "--no-summary", - action="store_true", - help="Disable the summary section in the output", - ) - - args = parser.parse_args() - - # Validate format-specific arguments - if args.format == "collapsed": - _validate_collapsed_format_args(args, parser) - - sort_value = args.sort if args.sort is not None else 2 - - if args.module is not None and not args.module: - parser.error("argument -m/--module: expected one argument") - - # Validate that we have exactly one target type - # Note: args can be present with -m (module arguments) but not as standalone script - has_pid = args.pid is not None - has_module = args.module is not None - has_script = bool(args.args) and args.module is None - - target_count = sum([has_pid, has_module, has_script]) - - if target_count == 0: - parser.error("one of the arguments -p/--pid -m/--module or script name is required") - elif target_count > 1: - parser.error("only one target type can be specified: -p/--pid, -m/--module, or script") - - if args.pid: - sample( - args.pid, - sample_interval_usec=args.interval, - duration_sec=args.duration, - filename=args.outfile, - all_threads=args.all_threads, - limit=args.limit, - sort=sort_value, - show_summary=not args.no_summary, - output_format=args.format, - realtime_stats=args.realtime_stats, - ) - elif args.module or args.args: - if args.module: - cmd = (sys.executable, "-m", args.module, *args.args) - else: - cmd = (sys.executable, *args.args) - - # Use synchronized process startup - process = _run_with_sync(cmd) - - # Process has already signaled readiness, start sampling immediately + def curses_wrapper_func(stdscr): + collector.init_curses(stdscr) try: - wait_for_process_and_sample(process.pid, sort_value, args) + profiler.sample(collector, duration_sec, async_aware=async_aware) + # Mark as finished and keep the TUI running until user presses 'q' + collector.mark_finished() + # Keep processing input until user quits + while collector.running: + collector._handle_input() + time.sleep(0.05) # Small sleep to avoid busy waiting finally: - if process.poll() is None: - process.terminate() - try: - process.wait(timeout=2) - except subprocess.TimeoutExpired: - process.kill() - process.wait() + collector.cleanup_curses() -if __name__ == "__main__": - main() + try: + curses.wrapper(curses_wrapper_func) + except KeyboardInterrupt: + pass + + return collector diff --git a/Lib/profiling/sampling/stack_collector.py b/Lib/profiling/sampling/stack_collector.py index 97dbcb5b2fb..e437facd8bb 100644 --- a/Lib/profiling/sampling/stack_collector.py +++ b/Lib/profiling/sampling/stack_collector.py @@ -1,37 +1,428 @@ +import base64 import collections +import functools +import importlib.resources +import json +import linecache import os +import sys -from .collector import Collector +from ._css_utils import get_combined_css +from .collector import Collector, extract_lineno +from .opcode_utils import get_opcode_mapping +from .string_table import StringTable class StackTraceCollector(Collector): - def __init__(self): - self.call_trees = [] - self.function_samples = collections.defaultdict(int) + def __init__(self, sample_interval_usec, *, skip_idle=False): + self.sample_interval_usec = sample_interval_usec + self.skip_idle = skip_idle - def collect(self, stack_frames): - for thread_id, frames in stack_frames: - if frames: - # Store the complete call stack (reverse order - root first) - call_tree = list(reversed(frames)) - self.call_trees.append(call_tree) + def collect(self, stack_frames, skip_idle=False): + if stack_frames and hasattr(stack_frames[0], "awaited_by"): + # Async-aware mode: process async task frames + for frames, thread_id, task_id in self._iter_async_frames(stack_frames): + if not frames: + continue + self.process_frames(frames, thread_id) + else: + # Sync-only mode + for frames, thread_id in self._iter_all_frames(stack_frames, skip_idle=skip_idle): + if not frames: + continue + self.process_frames(frames, thread_id) - # Count samples per function - for frame in frames: - self.function_samples[frame] += 1 + def process_frames(self, frames, thread_id): + pass class CollapsedStackCollector(StackTraceCollector): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.stack_counter = collections.Counter() + + def process_frames(self, frames, thread_id): + # Extract only (filename, lineno, funcname) - opcode not needed for collapsed stacks + # frame is (filename, location, funcname, opcode) + call_tree = tuple( + (f[0], extract_lineno(f[1]), f[2]) for f in reversed(frames) + ) + self.stack_counter[(call_tree, thread_id)] += 1 + def export(self, filename): - stack_counter = collections.Counter() - for call_tree in self.call_trees: - # Call tree is already in root->leaf order - stack_str = ";".join( - f"{os.path.basename(f[0])}:{f[2]}:{f[1]}" for f in call_tree - ) - stack_counter[stack_str] += 1 + lines = [] + for (call_tree, thread_id), count in self.stack_counter.items(): + parts = [f"tid:{thread_id}"] + for file, line, func in call_tree: + # This is what pstats does for "special" frames: + if file == "~" and line == 0: + part = func + else: + part = f"{os.path.basename(file)}:{func}:{line}" + parts.append(part) + stack_str = ";".join(parts) + lines.append((stack_str, count)) + + lines.sort(key=lambda x: (-x[1], x[0])) with open(filename, "w") as f: - for stack, count in stack_counter.items(): + for stack, count in lines: f.write(f"{stack} {count}\n") print(f"Collapsed stack output written to {filename}") + + +class FlamegraphCollector(StackTraceCollector): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.stats = {} + self._root = {"samples": 0, "children": {}, "threads": set()} + self._total_samples = 0 + self._sample_count = 0 # Track actual number of samples (not thread traces) + self._func_intern = {} + self._string_table = StringTable() + self._all_threads = set() + + # Thread status statistics (similar to LiveStatsCollector) + self.thread_status_counts = { + "has_gil": 0, + "on_cpu": 0, + "gil_requested": 0, + "unknown": 0, + "has_exception": 0, + "total": 0, + } + self.samples_with_gc_frames = 0 + + # Per-thread statistics + self.per_thread_stats = {} # {thread_id: {has_gil, on_cpu, gil_requested, unknown, has_exception, total, gc_samples}} + + def collect(self, stack_frames, skip_idle=False): + """Override to track thread status statistics before processing frames.""" + # Increment sample count once per sample + self._sample_count += 1 + + # Collect both aggregate and per-thread statistics using base method + status_counts, has_gc_frame, per_thread_stats = self._collect_thread_status_stats(stack_frames) + + # Merge aggregate status counts + for key in status_counts: + self.thread_status_counts[key] += status_counts[key] + + # Update aggregate GC frame count + if has_gc_frame: + self.samples_with_gc_frames += 1 + + # Merge per-thread statistics + for thread_id, stats in per_thread_stats.items(): + if thread_id not in self.per_thread_stats: + self.per_thread_stats[thread_id] = { + "has_gil": 0, + "on_cpu": 0, + "gil_requested": 0, + "unknown": 0, + "has_exception": 0, + "total": 0, + "gc_samples": 0, + } + for key, value in stats.items(): + self.per_thread_stats[thread_id][key] += value + + # Call parent collect to process frames + super().collect(stack_frames, skip_idle=skip_idle) + + def set_stats(self, sample_interval_usec, duration_sec, sample_rate, + error_rate=None, missed_samples=None, mode=None): + """Set profiling statistics to include in flamegraph data.""" + self.stats = { + "sample_interval_usec": sample_interval_usec, + "duration_sec": duration_sec, + "sample_rate": sample_rate, + "error_rate": error_rate, + "missed_samples": missed_samples, + "mode": mode + } + + def export(self, filename): + flamegraph_data = self._convert_to_flamegraph_format() + + # Debug output with string table statistics + num_functions = len(flamegraph_data.get("children", [])) + total_time = flamegraph_data.get("value", 0) + string_count = len(self._string_table) + print( + f"Flamegraph data: {num_functions} root functions, total samples: {total_time}, " + f"{string_count} unique strings" + ) + + if num_functions == 0: + print( + "Warning: No functions found in profiling data. Check if sampling captured any data." + ) + return + + html_content = self._create_flamegraph_html(flamegraph_data) + + with open(filename, "w", encoding="utf-8") as f: + f.write(html_content) + + print(f"Flamegraph saved to: {filename}") + + @staticmethod + @functools.lru_cache(maxsize=None) + def _format_function_name(func): + filename, lineno, funcname = func + + # Special frames like and should not show file:line + if filename == "~" and lineno == 0: + return funcname + + if len(filename) > 50: + parts = filename.split("/") + if len(parts) > 2: + filename = f".../{'/'.join(parts[-2:])}" + + return f"{funcname} ({filename}:{lineno})" + + def _convert_to_flamegraph_format(self): + if self._total_samples == 0: + return { + "name": self._string_table.intern("No Data"), + "value": 0, + "children": [], + "threads": [], + "strings": self._string_table.get_strings() + } + + def convert_children(children, min_samples): + out = [] + for func, node in children.items(): + samples = node["samples"] + if samples < min_samples: + continue + + # Intern all string components for maximum efficiency + filename_idx = self._string_table.intern(func[0]) + funcname_idx = self._string_table.intern(func[2]) + name_idx = self._string_table.intern(self._format_function_name(func)) + + child_entry = { + "name": name_idx, + "value": samples, + "children": [], + "filename": filename_idx, + "lineno": func[1], + "funcname": funcname_idx, + "threads": sorted(list(node.get("threads", set()))), + } + + source = self._get_source_lines(func) + if source: + # Intern source lines for memory efficiency + source_indices = [self._string_table.intern(line) for line in source] + child_entry["source"] = source_indices + + # Include opcode data if available + opcodes = node.get("opcodes", {}) + if opcodes: + child_entry["opcodes"] = dict(opcodes) + + # Recurse + child_entry["children"] = convert_children( + node["children"], min_samples + ) + out.append(child_entry) + + # Sort by value (descending) then by name index for consistent ordering + out.sort(key=lambda x: (-x["value"], x["name"])) + return out + + # Filter out very small functions (less than 0.1% of total samples) + total_samples = self._total_samples + min_samples = max(1, int(total_samples * 0.001)) + + root_children = convert_children(self._root["children"], min_samples) + if not root_children: + return { + "name": self._string_table.intern("No significant data"), + "value": 0, + "children": [], + "strings": self._string_table.get_strings() + } + + # Calculate thread status percentages for display + import sysconfig + is_free_threaded = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) + total_threads = max(1, self.thread_status_counts["total"]) + thread_stats = { + "has_gil_pct": (self.thread_status_counts["has_gil"] / total_threads) * 100, + "on_cpu_pct": (self.thread_status_counts["on_cpu"] / total_threads) * 100, + "gil_requested_pct": (self.thread_status_counts["gil_requested"] / total_threads) * 100, + "has_exception_pct": (self.thread_status_counts["has_exception"] / total_threads) * 100, + "gc_pct": (self.samples_with_gc_frames / max(1, self._sample_count)) * 100, + "free_threaded": is_free_threaded, + **self.thread_status_counts + } + + # Calculate per-thread statistics with percentages + per_thread_stats_with_pct = {} + total_samples_denominator = max(1, self._sample_count) + for thread_id, stats in self.per_thread_stats.items(): + total = max(1, stats["total"]) + per_thread_stats_with_pct[thread_id] = { + "has_gil_pct": (stats["has_gil"] / total) * 100, + "on_cpu_pct": (stats["on_cpu"] / total) * 100, + "gil_requested_pct": (stats["gil_requested"] / total) * 100, + "has_exception_pct": (stats["has_exception"] / total) * 100, + "gc_pct": (stats["gc_samples"] / total_samples_denominator) * 100, + **stats + } + + # Build opcode mapping for JS + opcode_mapping = get_opcode_mapping() + + # If we only have one root child, make it the root to avoid redundant level + if len(root_children) == 1: + main_child = root_children[0] + # Update the name to indicate it's the program root + old_name = self._string_table.get_string(main_child["name"]) + new_name = f"Program Root: {old_name}" + main_child["name"] = self._string_table.intern(new_name) + main_child["stats"] = { + **self.stats, + "thread_stats": thread_stats, + "per_thread_stats": per_thread_stats_with_pct + } + main_child["threads"] = sorted(list(self._all_threads)) + main_child["strings"] = self._string_table.get_strings() + main_child["opcode_mapping"] = opcode_mapping + return main_child + + return { + "name": self._string_table.intern("Program Root"), + "value": total_samples, + "children": root_children, + "stats": { + **self.stats, + "thread_stats": thread_stats, + "per_thread_stats": per_thread_stats_with_pct + }, + "threads": sorted(list(self._all_threads)), + "strings": self._string_table.get_strings(), + "opcode_mapping": opcode_mapping + } + + def process_frames(self, frames, thread_id): + """Process stack frames into flamegraph tree structure. + + Args: + frames: List of (filename, location, funcname, opcode) tuples in + leaf-to-root order. location is (lineno, end_lineno, col_offset, end_col_offset). + opcode is None if not gathered. + thread_id: Thread ID for this stack trace + """ + # Reverse to root->leaf order for tree building + self._root["samples"] += 1 + self._total_samples += 1 + self._root["threads"].add(thread_id) + self._all_threads.add(thread_id) + + current = self._root + for filename, location, funcname, opcode in reversed(frames): + lineno = extract_lineno(location) + func = (filename, lineno, funcname) + func = self._func_intern.setdefault(func, func) + + node = current["children"].get(func) + if node is None: + node = {"samples": 0, "children": {}, "threads": set(), "opcodes": collections.Counter()} + current["children"][func] = node + node["samples"] += 1 + node["threads"].add(thread_id) + + if opcode is not None: + node["opcodes"][opcode] += 1 + + current = node + + def _get_source_lines(self, func): + filename, lineno, _ = func + + try: + lines = [] + start_line = max(1, lineno - 2) + end_line = lineno + 3 + + for line_num in range(start_line, end_line): + line = linecache.getline(filename, line_num) + if line.strip(): + marker = "→ " if line_num == lineno else " " + lines.append(f"{marker}{line_num}: {line.rstrip()}") + + return lines if lines else None + + except Exception: + return None + + def _create_flamegraph_html(self, data): + data_json = json.dumps(data) + + template_dir = importlib.resources.files(__package__) + vendor_dir = template_dir / "_vendor" + assets_dir = template_dir / "_assets" + + d3_path = vendor_dir / "d3" / "7.8.5" / "d3.min.js" + d3_flame_graph_dir = vendor_dir / "d3-flame-graph" / "4.1.3" + fg_css_path = d3_flame_graph_dir / "d3-flamegraph.css" + fg_js_path = d3_flame_graph_dir / "d3-flamegraph.min.js" + fg_tooltip_js_path = d3_flame_graph_dir / "d3-flamegraph-tooltip.min.js" + + html_template = (template_dir / "_flamegraph_assets" / "flamegraph_template.html").read_text(encoding="utf-8") + css_content = get_combined_css("flamegraph") + js_content = (template_dir / "_flamegraph_assets" / "flamegraph.js").read_text(encoding="utf-8") + + # Inline first-party CSS/JS + html_template = html_template.replace( + "", f"" + ) + html_template = html_template.replace( + "", f"" + ) + + png_path = assets_dir / "tachyon-logo.png" + b64_logo = base64.b64encode(png_path.read_bytes()).decode("ascii") + + # Let CSS control size; keep markup simple + logo_html = f'Tachyon logo' + html_template = html_template.replace("", logo_html) + html_template = html_template.replace( + "", f"{sys.version_info.major}.{sys.version_info.minor}" + ) + + d3_js = d3_path.read_text(encoding="utf-8") + fg_css = fg_css_path.read_text(encoding="utf-8") + fg_js = fg_js_path.read_text(encoding="utf-8") + fg_tooltip_js = fg_tooltip_js_path.read_text(encoding="utf-8") + + html_template = html_template.replace( + "", + f"", + ) + html_template = html_template.replace( + "", + f"", + ) + html_template = html_template.replace( + "", + f"", + ) + html_template = html_template.replace( + "", + f"", + ) + + # Replace the placeholder with actual data + html_content = html_template.replace( + "{{FLAMEGRAPH_DATA}}", data_json + ) + + return html_content diff --git a/Lib/profiling/sampling/string_table.py b/Lib/profiling/sampling/string_table.py new file mode 100644 index 00000000000..25c347f7ff1 --- /dev/null +++ b/Lib/profiling/sampling/string_table.py @@ -0,0 +1,53 @@ +"""String table implementation for memory-efficient string storage in profiling data.""" + +class StringTable: + """A string table for interning strings and reducing memory usage.""" + + def __init__(self): + self._strings = [] + self._string_to_index = {} + + def intern(self, string): + """Intern a string and return its index. + + Args: + string: The string to intern + + Returns: + int: The index of the string in the table + """ + if not isinstance(string, str): + string = str(string) + + if string in self._string_to_index: + return self._string_to_index[string] + + index = len(self._strings) + self._strings.append(string) + self._string_to_index[string] = index + return index + + def get_string(self, index): + """Get a string by its index. + + Args: + index: The index of the string + + Returns: + str: The string at the given index, or empty string if invalid + """ + if 0 <= index < len(self._strings): + return self._strings[index] + return "" + + def get_strings(self): + """Get the list of all strings in the table. + + Returns: + list: A copy of the strings list + """ + return self._strings.copy() + + def __len__(self): + """Return the number of strings in the table.""" + return len(self._strings) diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index 2dc7ea92c8c..bd3cbf299aa 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -185,7 +185,7 @@ def main(): progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with io.open_code(progname) as fp: - code = compile(fp.read(), progname, 'exec') + code = compile(fp.read(), progname, 'exec', module='__main__') spec = importlib.machinery.ModuleSpec(name='__main__', loader=None, origin=progname) module = importlib.util.module_from_spec(spec) @@ -201,7 +201,6 @@ def main(): '__file__': spec.origin, '__name__': spec.name, '__package__': None, - '__cached__': None, }) try: diff --git a/Lib/pstats.py b/Lib/pstats.py index 079abd2c1b8..07ecda07796 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -154,6 +154,7 @@ class Stats: arg.create_stats() self.stats = arg.stats arg.stats = {} + return if not self.stats: raise TypeError("Cannot create or construct a %r object from %r" % (self.__class__, arg)) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 37f86995d6c..35772cc01d0 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -158,7 +158,6 @@ def _readmodule(module, path, inpackage=None): return _readmodule(submodule, parent['__path__'], package) # Search the path for the module. - f = None if inpackage is not None: search_path = path else: diff --git a/Lib/pydoc.py b/Lib/pydoc.py index d508fb70ea4..c8d4aa7a883 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -108,96 +108,10 @@ def pathdirs(): normdirs.append(normdir) return dirs -def _findclass(func): - cls = sys.modules.get(func.__module__) - if cls is None: - return None - for name in func.__qualname__.split('.')[:-1]: - cls = getattr(cls, name) - if not inspect.isclass(cls): - return None - return cls - -def _finddoc(obj): - if inspect.ismethod(obj): - name = obj.__func__.__name__ - self = obj.__self__ - if (inspect.isclass(self) and - getattr(getattr(self, name, None), '__func__') is obj.__func__): - # classmethod - cls = self - else: - cls = self.__class__ - elif inspect.isfunction(obj): - name = obj.__name__ - cls = _findclass(obj) - if cls is None or getattr(cls, name) is not obj: - return None - elif inspect.isbuiltin(obj): - name = obj.__name__ - self = obj.__self__ - if (inspect.isclass(self) and - self.__qualname__ + '.' + name == obj.__qualname__): - # classmethod - cls = self - else: - cls = self.__class__ - # Should be tested before isdatadescriptor(). - elif isinstance(obj, property): - name = obj.__name__ - cls = _findclass(obj.fget) - if cls is None or getattr(cls, name) is not obj: - return None - elif inspect.ismethoddescriptor(obj) or inspect.isdatadescriptor(obj): - name = obj.__name__ - cls = obj.__objclass__ - if getattr(cls, name) is not obj: - return None - if inspect.ismemberdescriptor(obj): - slots = getattr(cls, '__slots__', None) - if isinstance(slots, dict) and name in slots: - return slots[name] - else: - return None - for base in cls.__mro__: - try: - doc = _getowndoc(getattr(base, name)) - except AttributeError: - continue - if doc is not None: - return doc - return None - -def _getowndoc(obj): - """Get the documentation string for an object if it is not - inherited from its class.""" - try: - doc = object.__getattribute__(obj, '__doc__') - if doc is None: - return None - if obj is not type: - typedoc = type(obj).__doc__ - if isinstance(typedoc, str) and typedoc == doc: - return None - return doc - except AttributeError: - return None - def _getdoc(object): - """Get the documentation string for an object. - - All tabs are expanded to spaces. To clean up docstrings that are - indented to line up with blocks of code, any whitespace than can be - uniformly removed from the second line onwards is removed.""" - doc = _getowndoc(object) - if doc is None: - try: - doc = _finddoc(object) - except (AttributeError, TypeError): - return None - if not isinstance(doc, str): - return None - return inspect.cleandoc(doc) + return inspect.getdoc(object, + fallback_to_class_doc=False, + inherit_class_doc=False) def getdoc(object): """Get the doc string or comments for an object.""" @@ -327,12 +241,12 @@ def visiblename(name, all=None, obj=None): """Decide whether to show documentation on a variable.""" # Certain special names are redundant or internal. # XXX Remove __initializing__? - if name in {'__author__', '__builtins__', '__cached__', '__credits__', - '__date__', '__doc__', '__file__', '__spec__', - '__loader__', '__module__', '__name__', '__package__', - '__path__', '__qualname__', '__slots__', '__version__', - '__static_attributes__', '__firstlineno__', - '__annotate_func__', '__annotations_cache__'}: + if name in {'__author__', '__builtins__', '__credits__', '__date__', + '__doc__', '__file__', '__spec__', '__loader__', '__module__', + '__name__', '__package__', '__path__', '__qualname__', + '__slots__', '__version__', '__static_attributes__', + '__firstlineno__', '__annotate_func__', + '__annotations_cache__'}: return 0 # Private names are hidden, but special names are displayed. if name.startswith('__') and name.endswith('__'): return 1 @@ -536,6 +450,7 @@ class Doc: PYTHONDOCS = os.environ.get("PYTHONDOCS", "https://docs.python.org/%d.%d/library" % sys.version_info[:2]) + STDLIB_DIR = sysconfig.get_path('stdlib') def document(self, object, name=None, *args): """Generate documentation for an object.""" @@ -561,23 +476,12 @@ class Doc: docmodule = docclass = docroutine = docother = docproperty = docdata = fail - def getdocloc(self, object, basedir=sysconfig.get_path('stdlib')): + def getdocloc(self, object, basedir=None): """Return the location of module docs or None""" - - try: - file = inspect.getabsfile(object) - except TypeError: - file = '(built-in)' - + basedir = self.STDLIB_DIR if basedir is None else basedir docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS) - basedir = os.path.normcase(basedir) - if (isinstance(object, type(os)) and - (object.__name__ in ('errno', 'exceptions', 'gc', - 'marshal', 'posix', 'signal', 'sys', - '_thread', 'zipimport') or - (file.startswith(basedir) and - not file.startswith(os.path.join(basedir, 'site-packages')))) and + if (self._is_stdlib_module(object, basedir) and object.__name__ not in ('xml.etree', 'test.test_pydoc.pydoc_mod')): if docloc.startswith(("http://", "https://")): docloc = "{}/{}.html".format(docloc.rstrip("/"), object.__name__.lower()) @@ -587,6 +491,36 @@ class Doc: docloc = None return docloc + def _get_version(self, object): + if self._is_stdlib_module(object): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + version = getattr(object, '__version__', None) + else: + version = getattr(object, '__version__', None) + return '' if version is None else str(version) + + def _is_stdlib_module(self, object, basedir=None): + basedir = self.STDLIB_DIR if basedir is None else basedir + + try: + file = inspect.getabsfile(object) + except TypeError: + file = '(built-in)' + + if sysconfig.is_python_build(): + srcdir = sysconfig.get_config_var('srcdir') + if srcdir: + basedir = os.path.join(srcdir, 'Lib') + + basedir = os.path.normcase(basedir) + return (isinstance(object, type(os)) and + (object.__name__ in ('errno', 'exceptions', 'gc', + 'marshal', 'posix', 'signal', 'sys', + '_thread', 'zipimport') + or (file.startswith(basedir) and + not file.startswith(os.path.join(basedir, 'site-packages'))))) + # -------------------------------------------- HTML documentation generator class HTMLRepr(Repr): @@ -846,8 +780,8 @@ class HTMLDoc(Doc): except TypeError: filelink = '(built-in)' info = [] - if hasattr(object, '__version__'): - version = str(object.__version__) + + if version := self._get_version(object): if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': version = version[11:-1].strip() info.append('version %s' % self.escape(version)) @@ -884,6 +818,7 @@ class HTMLDoc(Doc): for key, value in inspect.getmembers(object, inspect.isroutine): # if __all__ exists, believe it. Otherwise use a heuristic. if (all is not None + or inspect.isbuiltin(value) or (inspect.getmodule(value) or object) is object): if visiblename(key, all, object): funcs.append((key, value)) @@ -1328,6 +1263,7 @@ location listed above. for key, value in inspect.getmembers(object, inspect.isroutine): # if __all__ exists, believe it. Otherwise use a heuristic. if (all is not None + or inspect.isbuiltin(value) or (inspect.getmodule(value) or object) is object): if visiblename(key, all, object): funcs.append((key, value)) @@ -1380,8 +1316,7 @@ location listed above. contents.append(self.docother(value, key, name, maxlen=70)) result = result + self.section('DATA', '\n'.join(contents)) - if hasattr(object, '__version__'): - version = str(object.__version__) + if version := self._get_version(object): if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': version = version[11:-1].strip() result = result + self.section('VERSION', version) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 5f7e14a79d3..2f19e84d2e4 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Tue May 6 18:33:44 2025 +# Autogenerated by Sphinx on Tue Dec 16 14:26:04 2025 # as part of the release process. topics = { @@ -435,9 +435,9 @@ See also: 'atom-identifiers': r'''Identifiers (Names) ******************* -An identifier occurring as an atom is a name. See section Identifiers -and keywords for lexical definition and section Naming and binding for -documentation of naming and binding. +An identifier occurring as an atom is a name. See section Names +(identifiers and keywords) for lexical definition and section Naming +and binding for documentation of naming and binding. When the name is bound to an object, evaluation of the atom yields that object. When a name is not bound, an attempt to evaluate it @@ -492,19 +492,65 @@ The transformation rule is defined as follows: Python supports string and bytes literals and various numeric literals: - literal: stringliteral | bytesliteral - | integer | floatnumber | imagnumber + literal: strings | NUMBER Evaluation of a literal yields an object of the given type (string, bytes, integer, floating-point number, complex number) with the given value. The value may be approximated in the case of floating-point -and imaginary (complex) literals. See section Literals for details. +and imaginary (complex) literals. See section Literals for details. +See section String literal concatenation for details on "strings". All literals correspond to immutable data types, and hence the object’s identity is less important than its value. Multiple evaluations of literals with the same value (either the same occurrence in the program text or a different occurrence) may obtain the same object or a different object with the same value. + + +String literal concatenation +============================ + +Multiple adjacent string or bytes literals (delimited by whitespace), +possibly using different quoting conventions, are allowed, and their +meaning is the same as their concatenation: + + >>> "hello" 'world' + "helloworld" + +Formally: + + strings: ( STRING | fstring)+ | tstring+ + +This feature is defined at the syntactical level, so it only works +with literals. To concatenate string expressions at run time, the ‘+’ +operator may be used: + + >>> greeting = "Hello" + >>> space = " " + >>> name = "Blaise" + >>> print(greeting + space + name) # not: print(greeting space name) + Hello Blaise + +Literal concatenation can freely mix raw strings, triple-quoted +strings, and formatted string literals. For example: + + >>> "Hello" r', ' f"{name}!" + "Hello, Blaise!" + +This feature can be used to reduce the number of backslashes needed, +to split long strings conveniently across long lines, or even to add +comments to parts of strings. For example: + + re.compile("[A-Za-z_]" # letter or underscore + "[A-Za-z0-9_]*" # letter, digit or underscore + ) + +However, bytes literals may only be combined with other byte literals; +not with string literals of any kind. Also, template string literals +may only be combined with other template string literals: + + >>> t"Hello" t"{name}!" + Template(strings=('Hello', '!'), interpolations=(...)) ''', 'attribute-access': r'''Customizing attribute access **************************** @@ -588,6 +634,9 @@ object.__dir__(self) Customizing module attribute access =================================== +module.__getattr__() +module.__dir__() + Special names "__getattr__" and "__dir__" can be also used to customize access to module attributes. The "__getattr__" function at the module level should accept one argument which is the name of an @@ -603,6 +652,8 @@ iterable of strings that represents the names accessible on module. If present, this function overrides the standard "dir()" search on a module. +module.__class__ + For a more fine grained customization of the module behavior (setting attributes, properties, etc.), one can set the "__class__" attribute of a module object to a subclass of "types.ModuleType". For example: @@ -814,9 +865,9 @@ Notes on using *__slots__*: renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* "TypeError" will be raised if nonempty *__slots__* are defined for a - class derived from a ""variable-length" built-in type" such as - "int", "bytes", and "tuple". +* "TypeError" will be raised if *__slots__* other than *__dict__* and + *__weakref__* are defined for a class derived from a ""variable- + length" built-in type" such as "int", "bytes", and "tuple". * Any non-string *iterable* may be assigned to *__slots__*. @@ -836,6 +887,9 @@ Notes on using *__slots__*: * If an *iterator* is used for *__slots__* then a *descriptor* is created for each of the iterator’s values. However, the *__slots__* attribute will be an empty iterator. + +Changed in version 3.15.0a2 (unreleased): Allowed defining the +*__dict__* and *__weakref__* *__slots__* for any class. ''', 'attribute-references': r'''Attribute references ******************** @@ -1047,12 +1101,33 @@ See The standard type hierarchy for more information. 'bltin-ellipsis-object': r'''The Ellipsis Object ******************* -This object is commonly used by slicing (see Slicings). It supports -no special operations. There is exactly one ellipsis object, named -"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the +This object is commonly used to indicate that something is omitted. It +supports no special operations. There is exactly one ellipsis object, +named "Ellipsis" (a built-in name). "type(Ellipsis)()" produces the "Ellipsis" singleton. It is written as "Ellipsis" or "...". + +In typical use, "..." as the "Ellipsis" object appears in a few +different places, for instance: + +* In type annotations, such as callable arguments or tuple elements. + +* As the body of a function instead of a pass statement. + +* In third-party libraries, such as Numpy’s slicing and striding. + +Python also uses three dots in ways that are not "Ellipsis" objects, +for instance: + +* Doctest’s "ELLIPSIS", as a pattern for missing content. + +* The default Python prompt of the *interactive* shell when partial + input is incomplete. + +Lastly, the Python documentation often uses three dots in conventional +English usage to mean omitted content, even in code examples that also +use them as the "Ellipsis". ''', 'bltin-null-object': r'''The Null Object *************** @@ -1314,6 +1389,9 @@ is equivalent to class Foo(object): pass +There may be one or more base classes; see Multiple inheritance below +for more information. + The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly @@ -1377,6 +1455,115 @@ See also: **PEP 3129** - Class Decorators The proposal that added class decorators. Function and method decorators were introduced in **PEP 318**. + + +Multiple inheritance +==================== + +Python classes may have multiple base classes, a technique known as +*multiple inheritance*. The base classes are specified in the class +definition by listing them in parentheses after the class name, +separated by commas. For example, the following class definition: + + >>> class A: pass + >>> class B: pass + >>> class C(A, B): pass + +defines a class "C" that inherits from classes "A" and "B". + +The *method resolution order* (MRO) is the order in which base classes +are searched when looking up an attribute on a class. See The Python +2.3 Method Resolution Order for a description of how Python determines +the MRO for a class. + +Multiple inheritance is not always allowed. Attempting to define a +class with multiple inheritance will raise an error if one of the +bases does not allow subclassing, if a consistent MRO cannot be +created, if no valid metaclass can be determined, or if there is an +instance layout conflict. We’ll discuss each of these in turn. + +First, all base classes must allow subclassing. While most classes +allow subclassing, some built-in classes do not, such as "bool": + + >>> class SubBool(bool): # TypeError + ... pass + Traceback (most recent call last): + ... + TypeError: type 'bool' is not an acceptable base type + +In the resolved MRO of a class, the class’s bases appear in the order +they were specified in the class’s bases list. Additionally, the MRO +always lists a child class before any of its bases. A class definition +will fail if it is impossible to resolve a consistent MRO that +satisfies these rules from the list of bases provided: + + >>> class Base: pass + >>> class Child(Base): pass + >>> class Grandchild(Base, Child): pass # TypeError + Traceback (most recent call last): + ... + TypeError: Cannot create a consistent method resolution order (MRO) for bases Base, Child + +In the MRO of "Grandchild", "Base" must appear before "Child" because +it is first in the base class list, but it must also appear after +"Child" because it is a parent of "Child". This is a contradiction, so +the class cannot be defined. + +If some of the bases have a custom *metaclass*, the metaclass of the +resulting class is chosen among the metaclasses of the bases and the +explicitly specified metaclass of the child class. It must be a +metaclass that is a subclass of all other candidate metaclasses. If no +such metaclass exists among the candidates, the class cannot be +created, as explained in Determining the appropriate metaclass. + +Finally, the instance layouts of the bases must be compatible. This +means that it must be possible to compute a *solid base* for the +class. Exactly which classes are solid bases depends on the Python +implementation. + +**CPython implementation detail:** In CPython, a class is a solid base +if it has a nonempty "__slots__" definition. Many but not all classes +defined in C are also solid bases, including most builtins (such as +"int" or "BaseException") but excluding most concrete "Exception" +classes. Generally, a C class is a solid base if its underlying struct +is different in size from its base class. + +Every class has a solid base. "object", the base class, has itself as +its solid base. If there is a single base, the child class’s solid +base is that class if it is a solid base, or else the base class’s +solid base. If there are multiple bases, we first find the solid base +for each base class to produce a list of candidate solid bases. If +there is a unique solid base that is a subclass of all others, then +that class is the solid base. Otherwise, class creation fails. + +Example: + + >>> class Solid1: + ... __slots__ = ("solid1",) + >>> + >>> class Solid2: + ... __slots__ = ("solid2",) + >>> + >>> class SolidChild(Solid1): + ... __slots__ = ("solid_child",) + >>> + >>> class C1: # solid base is `object` + ... pass + >>> + >>> # OK: solid bases are `Solid1` and `object`, and `Solid1` is a subclass of `object`. + >>> class C2(Solid1, C1): # solid base is `Solid1` + ... pass + >>> + >>> # OK: solid bases are `SolidChild` and `Solid1`, and `SolidChild` is a subclass of `Solid1`. + >>> class C3(SolidChild, Solid1): # solid base is `SolidChild` + ... pass + >>> + >>> # Error: solid bases are `Solid1` and `Solid2`, but neither is a subclass of the other. + >>> class C4(Solid1, Solid2): # error: no single solid base + ... pass + Traceback (most recent call last): + ... + TypeError: multiple bases have instance lay-out conflict ''', 'comparisons': r'''Comparisons *********** @@ -1724,16 +1911,16 @@ The "for" statement The "for" statement is used to iterate over the elements of a sequence (such as a string, tuple or list) or other iterable object: - for_stmt: "for" target_list "in" starred_list ":" suite + for_stmt: "for" target_list "in" starred_expression_list ":" suite ["else" ":" suite] -The "starred_list" expression is evaluated once; it should yield an -*iterable* object. An *iterator* is created for that iterable. The -first item provided by the iterator is then assigned to the target -list using the standard rules for assignments (see Assignment -statements), and the suite is executed. This repeats for each item -provided by the iterator. When the iterator is exhausted, the suite -in the "else" clause, if present, is executed, and the loop +The "starred_expression_list" expression is evaluated once; it should +yield an *iterable* object. An *iterator* is created for that +iterable. The first item provided by the iterator is then assigned to +the target list using the standard rules for assignments (see +Assignment statements), and the suite is executed. This repeats for +each item provided by the iterator. When the iterator is exhausted, +the suite in the "else" clause, if present, is executed, and the loop terminates. A "break" statement executed in the first suite terminates the loop @@ -1874,15 +2061,29 @@ to its previous value: "except*" clause ---------------- -The "except*" clause(s) are used for handling "ExceptionGroup"s. The -exception type for matching is interpreted as in the case of "except", -but in the case of exception groups we can have partial matches when -the type matches some of the exceptions in the group. This means that -multiple "except*" clauses can execute, each handling part of the -exception group. Each clause executes at most once and handles an -exception group of all matching exceptions. Each exception in the -group is handled by at most one "except*" clause, the first that -matches it. +The "except*" clause(s) specify one or more handlers for groups of +exceptions ("BaseExceptionGroup" instances). A "try" statement can +have either "except" or "except*" clauses, but not both. The exception +type for matching is mandatory in the case of "except*", so "except*:" +is a syntax error. The type is interpreted as in the case of "except", +but matching is performed on the exceptions contained in the group +that is being handled. An "TypeError" is raised if a matching type is +a subclass of "BaseExceptionGroup", because that would have ambiguous +semantics. + +When an exception group is raised in the try block, each "except*" +clause splits (see "split()") it into the subgroups of matching and +non-matching exceptions. If the matching subgroup is not empty, it +becomes the handled exception (the value returned from +"sys.exception()") and assigned to the target of the "except*" clause +(if there is one). Then, the body of the "except*" clause executes. If +the non-matching subgroup is not empty, it is processed by the next +"except*" in the same manner. This continues until all exceptions in +the group have been matched, or the last "except*" clause has run. + +After all "except*" clauses execute, the group of unhandled exceptions +is merged with any exceptions that were raised or re-raised from +within "except*" clauses. This merged exception group propagates on.: >>> try: ... raise ExceptionGroup("eg", @@ -1895,33 +2096,27 @@ matches it. caught with nested (TypeError(2),) caught with nested (OSError(3), OSError(4)) + Exception Group Traceback (most recent call last): - | File "", line 2, in - | ExceptionGroup: eg + | File "", line 2, in + | raise ExceptionGroup("eg", + | [ValueError(1), TypeError(2), OSError(3), OSError(4)]) + | ExceptionGroup: eg (1 sub-exception) +-+---------------- 1 ---------------- | ValueError: 1 +------------------------------------ -Any remaining exceptions that were not handled by any "except*" clause -are re-raised at the end, along with all exceptions that were raised -from within the "except*" clauses. If this list contains more than one -exception to reraise, they are combined into an exception group. - -If the raised exception is not an exception group and its type matches -one of the "except*" clauses, it is caught and wrapped by an exception -group with an empty message string. +If the exception raised from the "try" block is not an exception group +and its type matches one of the "except*" clauses, it is caught and +wrapped by an exception group with an empty message string. This +ensures that the type of the target "e" is consistently +"BaseExceptionGroup": >>> try: ... raise BlockingIOError ... except* BlockingIOError as e: ... print(repr(e)) ... - ExceptionGroup('', (BlockingIOError())) + ExceptionGroup('', (BlockingIOError(),)) -An "except*" clause must have a matching expression; it cannot be -"except*:". Furthermore, this expression cannot contain exception -group types, because that would have ambiguous semantics. - -It is not possible to mix "except" and "except*" in the same "try". "break", "continue" and "return" cannot appear in an "except*" clause. @@ -1938,11 +2133,11 @@ not handled by the preceding "except" clauses. ---------------- If "finally" is present, it specifies a ‘cleanup’ handler. The "try" -clause is executed, including any "except" and "else" clauses. If an +clause is executed, including any "except" and "else" clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The "finally" clause is executed. If there is a saved exception it is re-raised at the end of the "finally" -clause. If the "finally" clause raises another exception, the saved +clause. If the "finally" clause raises another exception, the saved exception is set as the context of the new exception. If the "finally" clause executes a "return", "break" or "continue" statement, the saved exception is discarded. For example, this function returns 42. @@ -2097,9 +2292,9 @@ Added in version 3.10. The match statement is used for pattern matching. Syntax: match_stmt: 'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT - subject_expr: star_named_expression "," star_named_expressions? - | named_expression - case_block: 'case' patterns [guard] ":" block + subject_expr: `!star_named_expression` "," `!star_named_expressions`? + | `!named_expression` + case_block: 'case' patterns [guard] ":" `!block` Note: @@ -2190,7 +2385,7 @@ section. Guards ------ - guard: "if" named_expression + guard: "if" `!named_expression` A "guard" (which is part of the "case") must succeed for code inside the "case" block to execute. It takes the form: "if" followed by an @@ -2329,7 +2524,8 @@ A literal pattern corresponds to most literals in Python. Syntax: The rule "strings" and the token "NUMBER" are defined in the standard Python grammar. Triple-quoted strings are supported. Raw strings and -byte strings are supported. f-strings are not supported. +byte strings are supported. f-strings and t-strings are not +supported. The forms "signed_number '+' NUMBER" and "signed_number '-' NUMBER" are for expressing complex numbers; they require a real number on the @@ -2483,7 +2679,7 @@ against a subject value: Note: The length of the subject sequence is obtained via "len()" (i.e. - via the "__len__()" protocol). This length may be cached by the + via the "__len__()" protocol). This length may be cached by the interpreter in a similar manner as value patterns. In simple terms "[P1, P2, P3," … ", P]" matches only if all the @@ -2591,7 +2787,7 @@ a subject value: If only keyword patterns are present, they are processed as follows, one by one: - I. The keyword is looked up as an attribute on the subject. + 1. The keyword is looked up as an attribute on the subject. * If this raises an exception other than "AttributeError", the exception bubbles up. @@ -2603,14 +2799,14 @@ a subject value: the class pattern fails; if this succeeds, the match proceeds to the next keyword. - II. If all keyword patterns succeed, the class pattern succeeds. + 2. If all keyword patterns succeed, the class pattern succeeds. If any positional patterns are present, they are converted to keyword patterns using the "__match_args__" attribute on the class "name_or_attr" before matching: - I. The equivalent of "getattr(cls, "__match_args__", ())" is - called. + 1. The equivalent of "getattr(cls, "__match_args__", ())" is + called. * If this raises an exception, the exception bubbles up. @@ -2631,9 +2827,9 @@ a subject value: Customizing positional arguments in class pattern matching - II. Once all positional patterns have been converted to keyword - patterns, - the match proceeds as if there were only keyword patterns. + 2. Once all positional patterns have been converted to keyword + patterns, the match proceeds as if there were only keyword + patterns. For the following built-in types the handling of positional subpatterns is different: @@ -2866,6 +3062,9 @@ is equivalent to class Foo(object): pass +There may be one or more base classes; see Multiple inheritance below +for more information. + The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly @@ -2931,6 +3130,115 @@ See also: decorators were introduced in **PEP 318**. +Multiple inheritance +-------------------- + +Python classes may have multiple base classes, a technique known as +*multiple inheritance*. The base classes are specified in the class +definition by listing them in parentheses after the class name, +separated by commas. For example, the following class definition: + + >>> class A: pass + >>> class B: pass + >>> class C(A, B): pass + +defines a class "C" that inherits from classes "A" and "B". + +The *method resolution order* (MRO) is the order in which base classes +are searched when looking up an attribute on a class. See The Python +2.3 Method Resolution Order for a description of how Python determines +the MRO for a class. + +Multiple inheritance is not always allowed. Attempting to define a +class with multiple inheritance will raise an error if one of the +bases does not allow subclassing, if a consistent MRO cannot be +created, if no valid metaclass can be determined, or if there is an +instance layout conflict. We’ll discuss each of these in turn. + +First, all base classes must allow subclassing. While most classes +allow subclassing, some built-in classes do not, such as "bool": + + >>> class SubBool(bool): # TypeError + ... pass + Traceback (most recent call last): + ... + TypeError: type 'bool' is not an acceptable base type + +In the resolved MRO of a class, the class’s bases appear in the order +they were specified in the class’s bases list. Additionally, the MRO +always lists a child class before any of its bases. A class definition +will fail if it is impossible to resolve a consistent MRO that +satisfies these rules from the list of bases provided: + + >>> class Base: pass + >>> class Child(Base): pass + >>> class Grandchild(Base, Child): pass # TypeError + Traceback (most recent call last): + ... + TypeError: Cannot create a consistent method resolution order (MRO) for bases Base, Child + +In the MRO of "Grandchild", "Base" must appear before "Child" because +it is first in the base class list, but it must also appear after +"Child" because it is a parent of "Child". This is a contradiction, so +the class cannot be defined. + +If some of the bases have a custom *metaclass*, the metaclass of the +resulting class is chosen among the metaclasses of the bases and the +explicitly specified metaclass of the child class. It must be a +metaclass that is a subclass of all other candidate metaclasses. If no +such metaclass exists among the candidates, the class cannot be +created, as explained in Determining the appropriate metaclass. + +Finally, the instance layouts of the bases must be compatible. This +means that it must be possible to compute a *solid base* for the +class. Exactly which classes are solid bases depends on the Python +implementation. + +**CPython implementation detail:** In CPython, a class is a solid base +if it has a nonempty "__slots__" definition. Many but not all classes +defined in C are also solid bases, including most builtins (such as +"int" or "BaseException") but excluding most concrete "Exception" +classes. Generally, a C class is a solid base if its underlying struct +is different in size from its base class. + +Every class has a solid base. "object", the base class, has itself as +its solid base. If there is a single base, the child class’s solid +base is that class if it is a solid base, or else the base class’s +solid base. If there are multiple bases, we first find the solid base +for each base class to produce a list of candidate solid bases. If +there is a unique solid base that is a subclass of all others, then +that class is the solid base. Otherwise, class creation fails. + +Example: + + >>> class Solid1: + ... __slots__ = ("solid1",) + >>> + >>> class Solid2: + ... __slots__ = ("solid2",) + >>> + >>> class SolidChild(Solid1): + ... __slots__ = ("solid_child",) + >>> + >>> class C1: # solid base is `object` + ... pass + >>> + >>> # OK: solid bases are `Solid1` and `object`, and `Solid1` is a subclass of `object`. + >>> class C2(Solid1, C1): # solid base is `Solid1` + ... pass + >>> + >>> # OK: solid bases are `SolidChild` and `Solid1`, and `SolidChild` is a subclass of `Solid1`. + >>> class C3(SolidChild, Solid1): # solid base is `SolidChild` + ... pass + >>> + >>> # Error: solid bases are `Solid1` and `Solid2`, but neither is a subclass of the other. + >>> class C4(Solid1, Solid2): # error: no single solid base + ... pass + Traceback (most recent call last): + ... + TypeError: multiple bases have instance lay-out conflict + + Coroutines ========== @@ -3304,7 +3612,7 @@ runtime semantics of the code, except if some mechanism is used that introspects and uses the annotations (such as "dataclasses" or "functools.singledispatch()"). -By default, annotations are lazily evaluated in a annotation scope. +By default, annotations are lazily evaluated in an annotation scope. This means that they are not evaluated when the code containing the annotation is evaluated. Instead, the interpreter saves information that can be used to evaluate the annotation later if requested. The @@ -3318,6 +3626,12 @@ present, all annotations are instead stored as strings: >>> f.__annotations__ {'param': 'annotation'} +This future statement will be deprecated and removed in a future +version of Python, but not before Python 3.13 reaches its end of life +(see **PEP 749**). When it is used, introspection tools like +"annotationlib.get_annotations()" and "typing.get_type_hints()" are +less likely to be able to resolve annotations at runtime. + -[ Footnotes ]- [1] The exception is propagated to the invocation stack unless there @@ -3829,10 +4143,14 @@ Changed in version 3.3: Tab-completion via the "readline" module is available for commands and command arguments, e.g. the current global and local names are offered as arguments of the "p" command. + +Command-line interface +====================== + You can also invoke "pdb" from the command line to debug other scripts. For example: - python -m pdb [-c command] (-m module | pyfile) [args ...] + python -m pdb [-c command] (-m module | -p pid | pyfile) [args ...] When invoked as a module, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post- @@ -3844,7 +4162,7 @@ debugger upon program’s exit. -c, --command To execute commands as if given in a ".pdbrc" file; see Debugger - Commands. + commands. Changed in version 3.2: Added the "-c" option. @@ -3856,6 +4174,23 @@ debugger upon program’s exit. Changed in version 3.7: Added the "-m" option. +-p, --pid + + Attach to the process with the specified PID. + + Added in version 3.14. + +To attach to a running Python process for remote debugging, use the +"-p" or "--pid" option with the target process’s PID: + + python -m pdb -p 1234 + +Note: + + Attaching to a process that is blocked in a system call or waiting + for I/O will only work once the next bytecode instruction is + executed or when the process receives a signal. + Typical usage to execute a statement under control of the debugger is: >>> import pdb @@ -4048,7 +4383,7 @@ class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=Fa See the documentation for the functions explained above. -Debugger Commands +Debugger commands ================= The commands recognized by the debugger are listed below. Most @@ -4574,8 +4909,8 @@ to right. Deletion of a name removes the binding of that name from the local or global namespace, depending on whether the name occurs in a "global" -statement in the same code block. If the name is unbound, a -"NameError" exception will be raised. +statement in the same code block. Trying to delete an unbound name +raises a "NameError" exception. Deletion of attribute references, subscriptions and slicings is passed to the primary object involved; deletion of a slicing is in general @@ -4711,11 +5046,6 @@ Note: See also the description of the "try" statement in section The try statement and "raise" statement in section The raise statement. - --[ Footnotes ]- - -[1] This limitation occurs because the code that is executed by these - operations is not available at the time the module is compiled. ''', 'execmodel': r'''Execution model *************** @@ -5069,6 +5399,181 @@ Note: See also the description of the "try" statement in section The try statement and "raise" statement in section The raise statement. + +Runtime Components +================== + + +General Computing Model +----------------------- + +Python’s execution model does not operate in a vacuum. It runs on a +host machine and through that host’s runtime environment, including +its operating system (OS), if there is one. When a program runs, the +conceptual layers of how it runs on the host look something like this: + + **host machine** + **process** (global resources) + **thread** (runs machine code) + +Each process represents a program running on the host. Think of each +process itself as the data part of its program. Think of the process’ +threads as the execution part of the program. This distinction will +be important to understand the conceptual Python runtime. + +The process, as the data part, is the execution context in which the +program runs. It mostly consists of the set of resources assigned to +the program by the host, including memory, signals, file handles, +sockets, and environment variables. + +Processes are isolated and independent from one another. (The same is +true for hosts.) The host manages the process’ access to its assigned +resources, in addition to coordinating between processes. + +Each thread represents the actual execution of the program’s machine +code, running relative to the resources assigned to the program’s +process. It’s strictly up to the host how and when that execution +takes place. + +From the point of view of Python, a program always starts with exactly +one thread. However, the program may grow to run in multiple +simultaneous threads. Not all hosts support multiple threads per +process, but most do. Unlike processes, threads in a process are not +isolated and independent from one another. Specifically, all threads +in a process share all of the process’ resources. + +The fundamental point of threads is that each one does *run* +independently, at the same time as the others. That may be only +conceptually at the same time (“concurrently”) or physically (“in +parallel”). Either way, the threads effectively run at a non- +synchronized rate. + +Note: + + That non-synchronized rate means none of the process’ memory is + guaranteed to stay consistent for the code running in any given + thread. Thus multi-threaded programs must take care to coordinate + access to intentionally shared resources. Likewise, they must take + care to be absolutely diligent about not accessing any *other* + resources in multiple threads; otherwise two threads running at the + same time might accidentally interfere with each other’s use of some + shared data. All this is true for both Python programs and the + Python runtime.The cost of this broad, unstructured requirement is + the tradeoff for the kind of raw concurrency that threads provide. + The alternative to the required discipline generally means dealing + with non-deterministic bugs and data corruption. + + +Python Runtime Model +-------------------- + +The same conceptual layers apply to each Python program, with some +extra data layers specific to Python: + + **host machine** + **process** (global resources) + Python global runtime (*state*) + Python interpreter (*state*) + **thread** (runs Python bytecode and “C-API”) + Python thread *state* + +At the conceptual level: when a Python program starts, it looks +exactly like that diagram, with one of each. The runtime may grow to +include multiple interpreters, and each interpreter may grow to +include multiple thread states. + +Note: + + A Python implementation won’t necessarily implement the runtime + layers distinctly or even concretely. The only exception is places + where distinct layers are directly specified or exposed to users, + like through the "threading" module. + +Note: + + The initial interpreter is typically called the “main” interpreter. + Some Python implementations, like CPython, assign special roles to + the main interpreter.Likewise, the host thread where the runtime was + initialized is known as the “main” thread. It may be different from + the process’ initial thread, though they are often the same. In + some cases “main thread” may be even more specific and refer to the + initial thread state. A Python runtime might assign specific + responsibilities to the main thread, such as handling signals. + +As a whole, the Python runtime consists of the global runtime state, +interpreters, and thread states. The runtime ensures all that state +stays consistent over its lifetime, particularly when used with +multiple host threads. + +The global runtime, at the conceptual level, is just a set of +interpreters. While those interpreters are otherwise isolated and +independent from one another, they may share some data or other +resources. The runtime is responsible for managing these global +resources safely. The actual nature and management of these resources +is implementation-specific. Ultimately, the external utility of the +global runtime is limited to managing interpreters. + +In contrast, an “interpreter” is conceptually what we would normally +think of as the (full-featured) “Python runtime”. When machine code +executing in a host thread interacts with the Python runtime, it calls +into Python in the context of a specific interpreter. + +Note: + + The term “interpreter” here is not the same as the “bytecode + interpreter”, which is what regularly runs in threads, executing + compiled Python code.In an ideal world, “Python runtime” would refer + to what we currently call “interpreter”. However, it’s been called + “interpreter” at least since introduced in 1997 (CPython:a027efa5b). + +Each interpreter completely encapsulates all of the non-process- +global, non-thread-specific state needed for the Python runtime to +work. Notably, the interpreter’s state persists between uses. It +includes fundamental data like "sys.modules". The runtime ensures +multiple threads using the same interpreter will safely share it +between them. + +A Python implementation may support using multiple interpreters at the +same time in the same process. They are independent and isolated from +one another. For example, each interpreter has its own "sys.modules". + +For thread-specific runtime state, each interpreter has a set of +thread states, which it manages, in the same way the global runtime +contains a set of interpreters. It can have thread states for as many +host threads as it needs. It may even have multiple thread states for +the same host thread, though that isn’t as common. + +Each thread state, conceptually, has all the thread-specific runtime +data an interpreter needs to operate in one host thread. The thread +state includes the current raised exception and the thread’s Python +call stack. It may include other thread-specific resources. + +Note: + + The term “Python thread” can sometimes refer to a thread state, but + normally it means a thread created using the "threading" module. + +Each thread state, over its lifetime, is always tied to exactly one +interpreter and exactly one host thread. It will only ever be used in +that thread and with that interpreter. + +Multiple thread states may be tied to the same host thread, whether +for different interpreters or even the same interpreter. However, for +any given host thread, only one of the thread states tied to it can be +used by the thread at a time. + +Thread states are isolated and independent from one another and don’t +share any data, except for possibly sharing an interpreter and objects +or other resources belonging to that interpreter. + +Once a program is running, new Python threads can be created using the +"threading" module (on platforms and Python implementations that +support threads). Additional processes can be created using the "os", +"subprocess", and "multiprocessing" modules. Interpreters can be +created and used with the "interpreters" module. Coroutines (async) +can be run using "asyncio" in each interpreter, typically only in a +single thread (often the main thread). + -[ Footnotes ]- [1] This limitation occurs because the code that is executed by these @@ -5077,7 +5582,7 @@ statement and "raise" statement in section The raise statement. 'exprlists': r'''Expression lists **************** - starred_expression: ["*"] or_expr + starred_expression: "*" or_expr | expression flexible_expression: assignment_expression | starred_expression flexible_expression_list: flexible_expression ("," flexible_expression)* [","] starred_expression_list: starred_expression ("," starred_expression)* [","] @@ -5109,25 +5614,53 @@ parentheses: "()".) 'floating': r'''Floating-point literals *********************** -Floating-point literals are described by the following lexical -definitions: +Floating-point (float) literals, such as "3.14" or "1.5", denote +approximations of real numbers. - floatnumber: pointfloat | exponentfloat - pointfloat: [digitpart] fraction | digitpart "." - exponentfloat: (digitpart | pointfloat) exponent - digitpart: digit (["_"] digit)* - fraction: "." digitpart - exponent: ("e" | "E") ["+" | "-"] digitpart +They consist of *integer* and *fraction* parts, each composed of +decimal digits. The parts are separated by a decimal point, ".": -Note that the integer and exponent parts are always interpreted using -radix 10. For example, "077e010" is legal, and denotes the same number -as "77e10". The allowed range of floating-point literals is -implementation-dependent. As in integer literals, underscores are -supported for digit grouping. + 2.71828 + 4.0 -Some examples of floating-point literals: +Unlike in integer literals, leading zeros are allowed. For example, +"077.010" is legal, and denotes the same number as "77.01". - 3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93 +As in integer literals, single underscores may occur between digits to +help readability: + + 96_485.332_123 + 3.14_15_93 + +Either of these parts, but not both, can be empty. For example: + + 10. # (equivalent to 10.0) + .001 # (equivalent to 0.001) + +Optionally, the integer and fraction may be followed by an *exponent*: +the letter "e" or "E", followed by an optional sign, "+" or "-", and a +number in the same format as the integer and fraction parts. The "e" +or "E" represents “times ten raised to the power of”: + + 1.0e3 # (represents 1.0×10³, or 1000.0) + 1.166e-5 # (represents 1.166×10⁻⁵, or 0.00001166) + 6.02214076e+23 # (represents 6.02214076×10²³, or 602214076000000000000000.) + +In floats with only integer and exponent parts, the decimal point may +be omitted: + + 1e3 # (equivalent to 1.e3 and 1.0e3) + 0e0 # (equivalent to 0.) + +Formally, floating-point literals are described by the following +lexical definitions: + + floatnumber: + | digitpart "." [digitpart] [exponent] + | "." digitpart [exponent] + | digitpart exponent + digitpart: digit (["_"] digit)* + exponent: ("e" | "E") ["+" | "-"] digitpart Changed in version 3.6: Underscores are now allowed for grouping purposes in literals. @@ -5138,16 +5671,16 @@ purposes in literals. The "for" statement is used to iterate over the elements of a sequence (such as a string, tuple or list) or other iterable object: - for_stmt: "for" target_list "in" starred_list ":" suite + for_stmt: "for" target_list "in" starred_expression_list ":" suite ["else" ":" suite] -The "starred_list" expression is evaluated once; it should yield an -*iterable* object. An *iterator* is created for that iterable. The -first item provided by the iterator is then assigned to the target -list using the standard rules for assignments (see Assignment -statements), and the suite is executed. This repeats for each item -provided by the iterator. When the iterator is exhausted, the suite -in the "else" clause, if present, is executed, and the loop +The "starred_expression_list" expression is evaluated once; it should +yield an *iterable* object. An *iterator* is created for that +iterable. The first item provided by the iterator is then assigned to +the target list using the standard rules for assignments (see +Assignment statements), and the suite is executed. This repeats for +each item provided by the iterator. When the iterator is exhausted, +the suite in the "else" clause, if present, is executed, and the loop terminates. A "break" statement executed in the first suite terminates the loop @@ -5181,9 +5714,9 @@ expression list. The "str.format()" method and the "Formatter" class share the same syntax for format strings (although in the case of "Formatter", subclasses can define their own format string syntax). The syntax is -related to that of formatted string literals, but it is less -sophisticated and, in particular, does not support arbitrary -expressions. +related to that of formatted string literals and template string +literals, but it is less sophisticated and, in particular, does not +support arbitrary expressions in interpolations. Format strings contain “replacement fields” surrounded by curly braces "{}". Anything that is not contained in braces is considered literal @@ -5283,9 +5816,9 @@ Format Specification Mini-Language “Format specifications” are used within replacement fields contained within a format string to define how individual values are presented -(see Format String Syntax and f-strings). They can also be passed -directly to the built-in "format()" function. Each formattable type -may define how the format specification is to be interpreted. +(see Format String Syntax, f-strings, and t-strings). They can also be +passed directly to the built-in "format()" function. Each formattable +type may define how the format specification is to be interpreted. Most built-in types implement the following options for format specifications, although some of the formatting options are only @@ -5304,7 +5837,7 @@ The general form of a *standard format specifier* is: sign: "+" | "-" | " " width_and_precision: [width_with_grouping][precision_with_grouping] width_with_grouping: [width][grouping] - precision_with_grouping: "." [precision][grouping] + precision_with_grouping: "." [precision][grouping] | "." grouping width: digit+ precision: digit+ grouping: "," | "_" @@ -5490,7 +6023,9 @@ The available presentation types for "float" and "Decimal" values are: | | With no precision given, uses a precision of "6" digits | | | after the decimal point for "float", and shows all | | | coefficient digits for "Decimal". If "p=0", the decimal | - | | point is omitted unless the "#" option is used. | + | | point is omitted unless the "#" option is used. For | + | | "float", the exponent always contains at least two digits, | + | | and is zero if the value is zero. | +-----------+------------------------------------------------------------+ | "'E'" | Scientific notation. Same as "'e'" except it uses an upper | | | case ‘E’ as the separator character. | @@ -5886,9 +6421,15 @@ as globals. It would be impossible to assign to a global variable without "global", although free variables may refer to globals without being declared global. -The "global" statement applies to the entire scope of a function or -class body. A "SyntaxError" is raised if a variable is used or -assigned to prior to its global declaration in the scope. +The "global" statement applies to the entire current scope (module, +function body or class definition). A "SyntaxError" is raised if a +variable is used or assigned to prior to its global declaration in the +scope. + +At the module level, all variables are global, so a "global" statement +has no effect. However, variables must still not be used or assigned +to prior to their "global" declaration. This requirement is relaxed in +the interactive prompt (*REPL*). **Programmer’s note:** "global" is a directive to the parser. It applies only to code parsed at the same time as the "global" @@ -5942,73 +6483,45 @@ trailing underscore characters: to help avoid name clashes between “private” attributes of base and derived classes. See section Identifiers (Names). ''', - 'identifiers': r'''Identifiers and keywords -************************ + 'identifiers': r'''Names (identifiers and keywords) +******************************** -Identifiers (also referred to as *names*) are described by the -following lexical definitions. +"NAME" tokens represent *identifiers*, *keywords*, and *soft +keywords*. -The syntax of identifiers in Python is based on the Unicode standard -annex UAX-31, with elaboration and changes as defined below; see also -**PEP 3131** for further details. +Names are composed of the following characters: -Within the ASCII range (U+0001..U+007F), the valid characters for -identifiers include the uppercase and lowercase letters "A" through -"Z", the underscore "_" and, except for the first character, the -digits "0" through "9". Python 3.0 introduced additional characters -from outside the ASCII range (see **PEP 3131**). For these -characters, the classification uses the version of the Unicode -Character Database as included in the "unicodedata" module. +* uppercase and lowercase letters ("A-Z" and "a-z"), -Identifiers are unlimited in length. Case is significant. +* the underscore ("_"), - identifier: xid_start xid_continue* - id_start: - id_continue: - xid_start: - xid_continue: +* digits ("0" through "9"), which cannot appear as the first + character, and -The Unicode category codes mentioned above stand for: +* non-ASCII characters. Valid names may only contain “letter-like” and + “digit-like” characters; see Non-ASCII characters in names for + details. -* *Lu* - uppercase letters +Names must contain at least one character, but have no upper length +limit. Case is significant. -* *Ll* - lowercase letters +Formally, names are described by the following lexical definitions: -* *Lt* - titlecase letters + NAME: name_start name_continue* + name_start: "a"..."z" | "A"..."Z" | "_" | + name_continue: name_start | "0"..."9" + identifier: -* *Lm* - modifier letters - -* *Lo* - other letters - -* *Nl* - letter numbers - -* *Mn* - nonspacing marks - -* *Mc* - spacing combining marks - -* *Nd* - decimal numbers - -* *Pc* - connector punctuations - -* *Other_ID_Start* - explicit list of characters in PropList.txt to - support backwards compatibility - -* *Other_ID_Continue* - likewise - -All identifiers are converted into the normal form NFKC while parsing; -comparison of identifiers is based on NFKC. - -A non-normative HTML file listing all valid identifier characters for -Unicode 16.0.0 can be found at -https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt +Note that not all names matched by this grammar are valid; see Non- +ASCII characters in names for details. Keywords ======== -The following identifiers are used as reserved words, or *keywords* of -the language, and cannot be used as ordinary identifiers. They must -be spelled exactly as written here: +The following names are used as reserved words, or *keywords* of the +language, and cannot be used as ordinary identifiers. They must be +spelled exactly as written here: False await else import pass None break except in raise @@ -6024,18 +6537,20 @@ Soft Keywords Added in version 3.10. -Some identifiers are only reserved under specific contexts. These are -known as *soft keywords*. The identifiers "match", "case", "type" and -"_" can syntactically act as keywords in certain contexts, but this -distinction is done at the parser level, not when tokenizing. +Some names are only reserved under specific contexts. These are known +as *soft keywords*: + +* "match", "case", and "_", when used in the "match" statement. + +* "type", when used in the "type" statement. + +These syntactically act as keywords in their specific contexts, but +this distinction is done at the parser level, not when tokenizing. As soft keywords, their use in the grammar is possible while still preserving compatibility with existing code that uses these names as identifier names. -"match", "case", and "_" are used in the "match" statement. "type" is -used in the "type" statement. - Changed in version 3.12: "type" is now a soft keyword. @@ -6081,6 +6596,101 @@ trailing underscore characters: context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes. See section Identifiers (Names). + + +Non-ASCII characters in names +============================= + +Names that contain non-ASCII characters need additional normalization +and validation beyond the rules and grammar explained above. For +example, "ř_1", "蛇", or "साँप" are valid names, but "r〰2", "€", or +"🐍" are not. + +This section explains the exact rules. + +All names are converted into the normalization form NFKC while +parsing. This means that, for example, some typographic variants of +characters are converted to their “basic” form. For example, +"fiⁿₐˡᵢᶻₐᵗᵢᵒₙ" normalizes to "finalization", so Python treats them as +the same name: + + >>> fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = 3 + >>> finalization + 3 + +Note: + + Normalization is done at the lexical level only. Run-time functions + that take names as *strings* generally do not normalize their + arguments. For example, the variable defined above is accessible at + run time in the "globals()" dictionary as + "globals()["finalization"]" but not "globals()["fiⁿₐˡᵢᶻₐᵗᵢᵒₙ"]". + +Similarly to how ASCII-only names must contain only letters, digits +and the underscore, and cannot start with a digit, a valid name must +start with a character in the “letter-like” set "xid_start", and the +remaining characters must be in the “letter- and digit-like” set +"xid_continue". + +These sets based on the *XID_Start* and *XID_Continue* sets as defined +by the Unicode standard annex UAX-31. Python’s "xid_start" +additionally includes the underscore ("_"). Note that Python does not +necessarily conform to UAX-31. + +A non-normative listing of characters in the *XID_Start* and +*XID_Continue* sets as defined by Unicode is available in the +DerivedCoreProperties.txt file in the Unicode Character Database. For +reference, the construction rules for the "xid_*" sets are given +below. + +The set "id_start" is defined as the union of: + +* Unicode category "" - uppercase letters (includes "A" to "Z") + +* Unicode category "" - lowercase letters (includes "a" to "z") + +* Unicode category "" - titlecase letters + +* Unicode category "" - modifier letters + +* Unicode category "" - other letters + +* Unicode category "" - letter numbers + +* {""_""} - the underscore + +* "" - an explicit set of characters in PropList.txt + to support backwards compatibility + +The set "xid_start" then closes this set under NFKC normalization, by +removing all characters whose normalization is not of the form +"id_start id_continue*". + +The set "id_continue" is defined as the union of: + +* "id_start" (see above) + +* Unicode category "" - decimal numbers (includes "0" to "9") + +* Unicode category "" - connector punctuations + +* Unicode category "" - nonspacing marks + +* Unicode category "" - spacing combining marks + +* "" - another explicit set of characters in + PropList.txt to support backwards compatibility + +Again, "xid_continue" closes this set under NFKC normalization. + +Unicode categories use the version of the Unicode Character Database +as included in the "unicodedata" module. + +See also: + + * **PEP 3131** – Supporting Non-ASCII Identifiers + + * **PEP 672** – Unicode-related Security Considerations for Python ''', 'if': r'''The "if" statement ****************** @@ -6101,17 +6711,53 @@ present, is executed. 'imaginary': r'''Imaginary literals ****************** -Imaginary literals are described by the following lexical definitions: +Python has complex number objects, but no complex literals. Instead, +*imaginary literals* denote complex numbers with a zero real part. + +For example, in math, the complex number 3+4.2*i* is written as the +real number 3 added to the imaginary number 4.2*i*. Python uses a +similar syntax, except the imaginary unit is written as "j" rather +than *i*: + + 3+4.2j + +This is an expression composed of the integer literal "3", the +operator ‘"+"’, and the imaginary literal "4.2j". Since these are +three separate tokens, whitespace is allowed between them: + + 3 + 4.2j + +No whitespace is allowed *within* each token. In particular, the "j" +suffix, may not be separated from the number before it. + +The number before the "j" has the same syntax as a floating-point +literal. Thus, the following are valid imaginary literals: + + 4.2j + 3.14j + 10.j + .001j + 1e100j + 3.14e-10j + 3.14_15_93j + +Unlike in a floating-point literal the decimal point can be omitted if +the imaginary number only has an integer part. The number is still +evaluated as a floating-point number, not an integer: + + 10j + 0j + 1000000000000000000000000j # equivalent to 1e+24j + +The "j" suffix is case-insensitive. That means you can use "J" +instead: + + 3.14J # equivalent to 3.14j + +Formally, imaginary literals are described by the following lexical +definition: imagnumber: (floatnumber | digitpart) ("j" | "J") - -An imaginary literal yields a complex number with a real part of 0.0. -Complex numbers are represented as a pair of floating-point numbers -and have the same restrictions on their range. To create a complex -number with a nonzero real part, add a floating-point number to it, -e.g., "(3+4j)". Some examples of imaginary literals: - - 3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j ''', 'import': r'''The "import" statement ********************** @@ -6353,37 +6999,62 @@ The operator "not in" is defined to have the inverse truth value of 'integers': r'''Integer literals **************** -Integer literals are described by the following lexical definitions: +Integer literals denote whole numbers. For example: - integer: decinteger | bininteger | octinteger | hexinteger - decinteger: nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")* + 7 + 3 + 2147483647 + +There is no limit for the length of integer literals apart from what +can be stored in available memory: + + 7922816251426433759354395033679228162514264337593543950336 + +Underscores can be used to group digits for enhanced readability, and +are ignored for determining the numeric value of the literal. For +example, the following literals are equivalent: + + 100_000_000_000 + 100000000000 + 1_00_00_00_00_000 + +Underscores can only occur between digits. For example, "_123", +"321_", and "123__321" are *not* valid literals. + +Integers can be specified in binary (base 2), octal (base 8), or +hexadecimal (base 16) using the prefixes "0b", "0o" and "0x", +respectively. Hexadecimal digits 10 through 15 are represented by +letters "A"-"F", case-insensitive. For example: + + 0b100110111 + 0b_1110_0101 + 0o177 + 0o377 + 0xdeadbeef + 0xDead_Beef + +An underscore can follow the base specifier. For example, "0x_1f" is a +valid literal, but "0_x1f" and "0x__1f" are not. + +Leading zeros in a non-zero decimal number are not allowed. For +example, "0123" is not a valid literal. This is for disambiguation +with C-style octal literals, which Python used before version 3.0. + +Formally, integer literals are described by the following lexical +definitions: + + integer: decinteger | bininteger | octinteger | hexinteger | zerointeger + decinteger: nonzerodigit (["_"] digit)* bininteger: "0" ("b" | "B") (["_"] bindigit)+ octinteger: "0" ("o" | "O") (["_"] octdigit)+ hexinteger: "0" ("x" | "X") (["_"] hexdigit)+ + zerointeger: "0"+ (["_"] "0")* nonzerodigit: "1"..."9" digit: "0"..."9" bindigit: "0" | "1" octdigit: "0"..."7" hexdigit: digit | "a"..."f" | "A"..."F" -There is no limit for the length of integer literals apart from what -can be stored in available memory. - -Underscores are ignored for determining the numeric value of the -literal. They can be used to group digits for enhanced readability. -One underscore can occur between digits, and after base specifiers -like "0x". - -Note that leading zeros in a non-zero decimal number are not allowed. -This is for disambiguation with C-style octal literals, which Python -used before version 3.0. - -Some examples of integer literals: - - 7 2147483647 0o177 0b100110111 - 3 79228162514264337593543950336 0o377 0xdeadbeef - 100_000_000_000 0b_1110_0101 - Changed in version 3.6: Underscores are now allowed for grouping purposes in literals. ''', @@ -6730,14 +7401,189 @@ applies only to code parsed along with it. See the note for the 'numbers': r'''Numeric literals **************** -There are three types of numeric literals: integers, floating-point -numbers, and imaginary numbers. There are no complex literals -(complex numbers can be formed by adding a real number and an -imaginary number). +"NUMBER" tokens represent numeric literals, of which there are three +types: integers, floating-point numbers, and imaginary numbers. -Note that numeric literals do not include a sign; a phrase like "-1" -is actually an expression composed of the unary operator ‘"-"’ and the -literal "1". + NUMBER: integer | floatnumber | imagnumber + +The numeric value of a numeric literal is the same as if it were +passed as a string to the "int", "float" or "complex" class +constructor, respectively. Note that not all valid inputs for those +constructors are also valid literals. + +Numeric literals do not include a sign; a phrase like "-1" is actually +an expression composed of the unary operator ‘"-"’ and the literal +"1". + + +Integer literals +================ + +Integer literals denote whole numbers. For example: + + 7 + 3 + 2147483647 + +There is no limit for the length of integer literals apart from what +can be stored in available memory: + + 7922816251426433759354395033679228162514264337593543950336 + +Underscores can be used to group digits for enhanced readability, and +are ignored for determining the numeric value of the literal. For +example, the following literals are equivalent: + + 100_000_000_000 + 100000000000 + 1_00_00_00_00_000 + +Underscores can only occur between digits. For example, "_123", +"321_", and "123__321" are *not* valid literals. + +Integers can be specified in binary (base 2), octal (base 8), or +hexadecimal (base 16) using the prefixes "0b", "0o" and "0x", +respectively. Hexadecimal digits 10 through 15 are represented by +letters "A"-"F", case-insensitive. For example: + + 0b100110111 + 0b_1110_0101 + 0o177 + 0o377 + 0xdeadbeef + 0xDead_Beef + +An underscore can follow the base specifier. For example, "0x_1f" is a +valid literal, but "0_x1f" and "0x__1f" are not. + +Leading zeros in a non-zero decimal number are not allowed. For +example, "0123" is not a valid literal. This is for disambiguation +with C-style octal literals, which Python used before version 3.0. + +Formally, integer literals are described by the following lexical +definitions: + + integer: decinteger | bininteger | octinteger | hexinteger | zerointeger + decinteger: nonzerodigit (["_"] digit)* + bininteger: "0" ("b" | "B") (["_"] bindigit)+ + octinteger: "0" ("o" | "O") (["_"] octdigit)+ + hexinteger: "0" ("x" | "X") (["_"] hexdigit)+ + zerointeger: "0"+ (["_"] "0")* + nonzerodigit: "1"..."9" + digit: "0"..."9" + bindigit: "0" | "1" + octdigit: "0"..."7" + hexdigit: digit | "a"..."f" | "A"..."F" + +Changed in version 3.6: Underscores are now allowed for grouping +purposes in literals. + + +Floating-point literals +======================= + +Floating-point (float) literals, such as "3.14" or "1.5", denote +approximations of real numbers. + +They consist of *integer* and *fraction* parts, each composed of +decimal digits. The parts are separated by a decimal point, ".": + + 2.71828 + 4.0 + +Unlike in integer literals, leading zeros are allowed. For example, +"077.010" is legal, and denotes the same number as "77.01". + +As in integer literals, single underscores may occur between digits to +help readability: + + 96_485.332_123 + 3.14_15_93 + +Either of these parts, but not both, can be empty. For example: + + 10. # (equivalent to 10.0) + .001 # (equivalent to 0.001) + +Optionally, the integer and fraction may be followed by an *exponent*: +the letter "e" or "E", followed by an optional sign, "+" or "-", and a +number in the same format as the integer and fraction parts. The "e" +or "E" represents “times ten raised to the power of”: + + 1.0e3 # (represents 1.0×10³, or 1000.0) + 1.166e-5 # (represents 1.166×10⁻⁵, or 0.00001166) + 6.02214076e+23 # (represents 6.02214076×10²³, or 602214076000000000000000.) + +In floats with only integer and exponent parts, the decimal point may +be omitted: + + 1e3 # (equivalent to 1.e3 and 1.0e3) + 0e0 # (equivalent to 0.) + +Formally, floating-point literals are described by the following +lexical definitions: + + floatnumber: + | digitpart "." [digitpart] [exponent] + | "." digitpart [exponent] + | digitpart exponent + digitpart: digit (["_"] digit)* + exponent: ("e" | "E") ["+" | "-"] digitpart + +Changed in version 3.6: Underscores are now allowed for grouping +purposes in literals. + + +Imaginary literals +================== + +Python has complex number objects, but no complex literals. Instead, +*imaginary literals* denote complex numbers with a zero real part. + +For example, in math, the complex number 3+4.2*i* is written as the +real number 3 added to the imaginary number 4.2*i*. Python uses a +similar syntax, except the imaginary unit is written as "j" rather +than *i*: + + 3+4.2j + +This is an expression composed of the integer literal "3", the +operator ‘"+"’, and the imaginary literal "4.2j". Since these are +three separate tokens, whitespace is allowed between them: + + 3 + 4.2j + +No whitespace is allowed *within* each token. In particular, the "j" +suffix, may not be separated from the number before it. + +The number before the "j" has the same syntax as a floating-point +literal. Thus, the following are valid imaginary literals: + + 4.2j + 3.14j + 10.j + .001j + 1e100j + 3.14e-10j + 3.14_15_93j + +Unlike in a floating-point literal the decimal point can be omitted if +the imaginary number only has an integer part. The number is still +evaluated as a floating-point number, not an integer: + + 10j + 0j + 1000000000000000000000000j # equivalent to 1e+24j + +The "j" suffix is case-insensitive. That means you can use "J" +instead: + + 3.14J # equivalent to 3.14j + +Formally, imaginary literals are described by the following lexical +definition: + + imagnumber: (floatnumber | digitpart) ("j" | "J") ''', 'numeric-types': r'''Emulating numeric types *********************** @@ -6807,9 +7653,9 @@ object.__ror__(self, other) third argument if the three-argument version of the built-in "pow()" function is to be supported. - Changed in version 3.14.0a7 (unreleased): Three-argument "pow()" - now try calling "__rpow__()" if necessary. Previously it was only - called in two-argument "pow()" and the binary power operator. + Changed in version 3.14: Three-argument "pow()" now try calling + "__rpow__()" if necessary. Previously it was only called in two- + argument "pow()" and the binary power operator. Note: @@ -6894,9 +7740,8 @@ object.__ceil__(self) ************************* *Objects* are Python’s abstraction for data. All data in a Python -program is represented by objects or by relations between objects. (In -a sense, and in conformance to Von Neumann’s model of a “stored -program computer”, code is also represented by objects.) +program is represented by objects or by relations between objects. +Even code is represented by objects. Every object has an identity, a type and a value. An object’s *identity* never changes once it has been created; you may think of it @@ -7283,21 +8128,24 @@ behaving similar to those for Python’s standard "dictionary" objects. The "collections.abc" module provides a "MutableMapping" *abstract base class* to help create those methods from a base set of "__getitem__()", "__setitem__()", "__delitem__()", and "keys()". -Mutable sequences should provide methods "append()", "count()", -"index()", "extend()", "insert()", "pop()", "remove()", "reverse()" -and "sort()", like Python standard "list" objects. Finally, sequence + +Mutable sequences should provide methods "append()", "clear()", +"count()", "extend()", "index()", "insert()", "pop()", "remove()", and +"reverse()", like Python standard "list" objects. Finally, sequence types should implement addition (meaning concatenation) and multiplication (meaning repetition) by defining the methods "__add__()", "__radd__()", "__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described below; they should not define other numerical -operators. It is recommended that both mappings and sequences -implement the "__contains__()" method to allow efficient use of the -"in" operator; for mappings, "in" should search the mapping’s keys; -for sequences, it should search through the values. It is further -recommended that both mappings and sequences implement the -"__iter__()" method to allow efficient iteration through the -container; for mappings, "__iter__()" should iterate through the -object’s keys; for sequences, it should iterate through the values. +operators. + +It is recommended that both mappings and sequences implement the +"__contains__()" method to allow efficient use of the "in" operator; +for mappings, "in" should search the mapping’s keys; for sequences, it +should search through the values. It is further recommended that both +mappings and sequences implement the "__iter__()" method to allow +efficient iteration through the container; for mappings, "__iter__()" +should iterate through the object’s keys; for sequences, it should +iterate through the values. object.__len__(self) @@ -7534,8 +8382,8 @@ When implementing a class that emulates any built-in type, it is important that the emulation only be implemented to the degree that it makes sense for the object being modelled. For example, some sequences may work well with retrieval of individual elements, but -extracting a slice may not make sense. (One example of this is the -"NodeList" interface in the W3C’s Document Object Model.) +extracting a slice may not make sense. (One example of this is the +NodeList interface in the W3C’s Document Object Model.) Basic customization @@ -7930,6 +8778,9 @@ object.__dir__(self) Customizing module attribute access ----------------------------------- +module.__getattr__() +module.__dir__() + Special names "__getattr__" and "__dir__" can be also used to customize access to module attributes. The "__getattr__" function at the module level should accept one argument which is the name of an @@ -7945,6 +8796,8 @@ iterable of strings that represents the names accessible on module. If present, this function overrides the standard "dir()" search on a module. +module.__class__ + For a more fine grained customization of the module behavior (setting attributes, properties, etc.), one can set the "__class__" attribute of a module object to a subclass of "types.ModuleType". For example: @@ -8156,9 +9009,9 @@ Notes on using *__slots__*: renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* "TypeError" will be raised if nonempty *__slots__* are defined for a - class derived from a ""variable-length" built-in type" such as - "int", "bytes", and "tuple". +* "TypeError" will be raised if *__slots__* other than *__dict__* and + *__weakref__* are defined for a class derived from a ""variable- + length" built-in type" such as "int", "bytes", and "tuple". * Any non-string *iterable* may be assigned to *__slots__*. @@ -8179,6 +9032,9 @@ Notes on using *__slots__*: created for each of the iterator’s values. However, the *__slots__* attribute will be an empty iterator. +Changed in version 3.15.0a2 (unreleased): Allowed defining the +*__dict__* and *__weakref__* *__slots__* for any class. + Customizing class creation ========================== @@ -8640,21 +9496,24 @@ behaving similar to those for Python’s standard "dictionary" objects. The "collections.abc" module provides a "MutableMapping" *abstract base class* to help create those methods from a base set of "__getitem__()", "__setitem__()", "__delitem__()", and "keys()". -Mutable sequences should provide methods "append()", "count()", -"index()", "extend()", "insert()", "pop()", "remove()", "reverse()" -and "sort()", like Python standard "list" objects. Finally, sequence + +Mutable sequences should provide methods "append()", "clear()", +"count()", "extend()", "index()", "insert()", "pop()", "remove()", and +"reverse()", like Python standard "list" objects. Finally, sequence types should implement addition (meaning concatenation) and multiplication (meaning repetition) by defining the methods "__add__()", "__radd__()", "__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described below; they should not define other numerical -operators. It is recommended that both mappings and sequences -implement the "__contains__()" method to allow efficient use of the -"in" operator; for mappings, "in" should search the mapping’s keys; -for sequences, it should search through the values. It is further -recommended that both mappings and sequences implement the -"__iter__()" method to allow efficient iteration through the -container; for mappings, "__iter__()" should iterate through the -object’s keys; for sequences, it should iterate through the values. +operators. + +It is recommended that both mappings and sequences implement the +"__contains__()" method to allow efficient use of the "in" operator; +for mappings, "in" should search the mapping’s keys; for sequences, it +should search through the values. It is further recommended that both +mappings and sequences implement the "__iter__()" method to allow +efficient iteration through the container; for mappings, "__iter__()" +should iterate through the object’s keys; for sequences, it should +iterate through the values. object.__len__(self) @@ -8845,9 +9704,9 @@ object.__ror__(self, other) third argument if the three-argument version of the built-in "pow()" function is to be supported. - Changed in version 3.14.0a7 (unreleased): Three-argument "pow()" - now try calling "__rpow__()" if necessary. Previously it was only - called in two-argument "pow()" and the binary power operator. + Changed in version 3.14: Three-argument "pow()" now try calling + "__rpow__()" if necessary. Previously it was only called in two- + argument "pow()" and the binary power operator. Note: @@ -9205,17 +10064,24 @@ str.casefold() Since it is already lowercase, "lower()" would do nothing to "'ß'"; "casefold()" converts it to ""ss"". - The casefolding algorithm is described in section 3.13 ‘Default + The casefolding algorithm is described in section 3.13.3 ‘Default Case Folding’ of the Unicode Standard. Added in version 3.3. -str.center(width[, fillchar]) +str.center(width, fillchar=' ', /) Return centered in a string of length *width*. Padding is done using the specified *fillchar* (default is an ASCII space). The original string is returned if *width* is less than or equal to - "len(s)". + "len(s)". For example: + + >>> 'Python'.center(10) + ' Python ' + >>> 'Python'.center(10, '-') + '--Python--' + >>> 'Python'.center(4) + 'Python' str.count(sub[, start[, end]]) @@ -9224,7 +10090,18 @@ str.count(sub[, start[, end]]) *end* are interpreted as in slice notation. If *sub* is empty, returns the number of empty strings between - characters which is the length of the string plus one. + characters which is the length of the string plus one. For example: + + >>> 'spam, spam, spam'.count('spam') + 3 + >>> 'spam, spam, spam'.count('spam', 5) + 2 + >>> 'spam, spam, spam'.count('spam', 5, 10) + 1 + >>> 'spam, spam, spam'.count('eggs') + 0 + >>> 'spam, spam, spam'.count('') + 17 str.encode(encoding='utf-8', errors='strict') @@ -9241,7 +10118,13 @@ str.encode(encoding='utf-8', errors='strict') For performance reasons, the value of *errors* is not checked for validity unless an encoding error actually occurs, Python - Development Mode is enabled or a debug build is used. + Development Mode is enabled or a debug build is used. For example: + + >>> encoded_str_to_bytes = 'Python'.encode() + >>> type(encoded_str_to_bytes) + + >>> encoded_str_to_bytes + b'Python' Changed in version 3.1: Added support for keyword arguments. @@ -9254,6 +10137,19 @@ str.endswith(suffix[, start[, end]]) otherwise return "False". *suffix* can also be a tuple of suffixes to look for. With optional *start*, test beginning at that position. With optional *end*, stop comparing at that position. + Using *start* and *end* is equivalent to + "str[start:end].endswith(suffix)". For example: + + >>> 'Python'.endswith('on') + True + >>> 'a tuple of suffixes'.endswith(('at', 'in')) + False + >>> 'a tuple of suffixes'.endswith(('at', 'es')) + True + >>> 'Python is amazing'.endswith('is', 0, 9) + True + + See also "startswith()" and "removesuffix()". str.expandtabs(tabsize=8) @@ -9269,19 +10165,29 @@ str.expandtabs(tabsize=8) ("\n") or return ("\r"), it is copied and the current column is reset to zero. Any other character is copied unchanged and the current column is incremented by one regardless of how the - character is represented when printed. + character is represented when printed. For example: - >>> '01\t012\t0123\t01234'.expandtabs() - '01 012 0123 01234' - >>> '01\t012\t0123\t01234'.expandtabs(4) - '01 012 0123 01234' + >>> '01\t012\t0123\t01234'.expandtabs() + '01 012 0123 01234' + >>> '01\t012\t0123\t01234'.expandtabs(4) + '01 012 0123 01234' + >>> print('01\t012\n0123\t01234'.expandtabs(4)) + 01 012 + 0123 01234 str.find(sub[, start[, end]]) Return the lowest index in the string where substring *sub* is found within the slice "s[start:end]". Optional arguments *start* and *end* are interpreted as in slice notation. Return "-1" if - *sub* is not found. + *sub* is not found. For example: + + >>> 'spam, spam, spam'.find('sp') + 0 + >>> 'spam, spam, spam'.find('sp', 5) + 6 + + See also "rfind()" and "index()". Note: @@ -9300,10 +10206,14 @@ str.format(*args, **kwargs) the numeric index of a positional argument, or the name of a keyword argument. Returns a copy of the string where each replacement field is replaced with the string value of the - corresponding argument. + corresponding argument. For example: - >>> "The sum of 1 + 2 is {0}".format(1+2) - 'The sum of 1 + 2 is 3' + >>> "The sum of 1 + 2 is {0}".format(1+2) + 'The sum of 1 + 2 is 3' + >>> "The sum of {a} + {b} is {answer}".format(answer=1+2, a=1, b=2) + 'The sum of 1 + 2 is 3' + >>> "{1} expects the {0} Inquisition!".format("Spanish", "Nobody") + 'Nobody expects the Spanish Inquisition!' See Format String Syntax for a description of the various formatting options that can be specified in format strings. @@ -9358,13 +10268,28 @@ str.isalpha() database as “Letter”, i.e., those with general category property being one of “Lm”, “Lt”, “Lu”, “Ll”, or “Lo”. Note that this is different from the Alphabetic property defined in the section 4.10 - ‘Letters, Alphabetic, and Ideographic’ of the Unicode Standard. + ‘Letters, Alphabetic, and Ideographic’ of the Unicode Standard. For + example: + + >>> 'Letters and spaces'.isalpha() + False + >>> 'LettersOnly'.isalpha() + True + >>> 'µ'.isalpha() # non-ASCII characters can be considered alphabetical too + True + + See Unicode Properties. str.isascii() Return "True" if the string is empty or all characters in the string are ASCII, "False" otherwise. ASCII characters have code - points in the range U+0000-U+007F. + points in the range U+0000-U+007F. For example: + + >>> 'ASCII characters'.isascii() + True + >>> 'µ'.isascii() + False Added in version 3.7. @@ -9373,8 +10298,16 @@ str.isdecimal() Return "True" if all characters in the string are decimal characters and there is at least one character, "False" otherwise. Decimal characters are those that can be used to form numbers in - base 10, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. Formally a decimal - character is a character in the Unicode General Category “Nd”. + base 10, such as U+0660, ARABIC-INDIC DIGIT ZERO. Formally a + decimal character is a character in the Unicode General Category + “Nd”. For example: + + >>> '0123456789'.isdecimal() + True + >>> '٠١٢٣٤٥٦٧٨٩'.isdecimal() # Arabic-Indic digits zero to nine + True + >>> 'alphabetic'.isdecimal() + False str.isdigit() @@ -9389,7 +10322,7 @@ str.isdigit() str.isidentifier() Return "True" if the string is a valid identifier according to the - language definition, section Identifiers and keywords. + language definition, section Names (identifiers and keywords). "keyword.iskeyword()" can be used to test whether string "s" is a reserved identifier, such as "def" and "class". @@ -9417,12 +10350,24 @@ str.isnumeric() that have the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric characters are those with the property value Numeric_Type=Digit, Numeric_Type=Decimal or - Numeric_Type=Numeric. + Numeric_Type=Numeric. For example: + + >>> '0123456789'.isnumeric() + True + >>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-indic digit zero to nine + True + >>> '⅕'.isnumeric() # Vulgar fraction one fifth + True + >>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric() + (False, True, True) + + See also "isdecimal()" and "isdigit()". Numeric characters are a + superset of decimal numbers. str.isprintable() - Return true if all characters in the string are printable, false if - it contains at least one non-printable character. + Return "True" if all characters in the string are printable, + "False" if it contains at least one non-printable character. Here “printable” means the character is suitable for "repr()" to use in its output; “non-printable” means that "repr()" on built-in @@ -9452,6 +10397,17 @@ str.istitle() follow uncased characters and lowercase characters only cased ones. Return "False" otherwise. + For example: + + >>> 'Spam, Spam, Spam'.istitle() + True + >>> 'spam, spam, spam'.istitle() + False + >>> 'SPAM, SPAM, SPAM'.istitle() + False + + See also "title()". + str.isupper() Return "True" if all cased characters [4] in the string are @@ -9467,29 +10423,48 @@ str.isupper() >>> ' '.isupper() False -str.join(iterable) +str.join(iterable, /) Return a string which is the concatenation of the strings in *iterable*. A "TypeError" will be raised if there are any non- string values in *iterable*, including "bytes" objects. The - separator between elements is the string providing this method. + separator between elements is the string providing this method. For + example: -str.ljust(width[, fillchar]) + >>> ', '.join(['spam', 'spam', 'spam']) + 'spam, spam, spam' + >>> '-'.join('Python') + 'P-y-t-h-o-n' + + See also "split()". + +str.ljust(width, fillchar=' ', /) Return the string left justified in a string of length *width*. Padding is done using the specified *fillchar* (default is an ASCII space). The original string is returned if *width* is less than or equal to "len(s)". + For example: + + >>> 'Python'.ljust(10) + 'Python ' + >>> 'Python'.ljust(10, '.') + 'Python....' + >>> 'Monty Python'.ljust(10, '.') + 'Monty Python' + + See also "rjust()". + str.lower() Return a copy of the string with all the cased characters [4] converted to lowercase. - The lowercasing algorithm used is described in section 3.13 - ‘Default Case Folding’ of the Unicode Standard. + The lowercasing algorithm used is described in section 3.13.2 + ‘Default Case Conversion’ of the Unicode Standard. -str.lstrip([chars]) +str.lstrip(chars=None, /) Return a copy of the string with leading characters removed. The *chars* argument is a string specifying the set of characters to be @@ -9510,7 +10485,8 @@ str.lstrip([chars]) >>> 'Arthur: three!'.removeprefix('Arthur: ') 'three!' -static str.maketrans(x[, y[, z]]) +static str.maketrans(dict, /) +static str.maketrans(from, to, remove='', /) This static method returns a translation table usable for "str.translate()". @@ -9521,12 +10497,12 @@ static str.maketrans(x[, y[, z]]) Character keys will then be converted to ordinals. If there are two arguments, they must be strings of equal length, - and in the resulting dictionary, each character in x will be mapped - to the character at the same position in y. If there is a third - argument, it must be a string, whose characters will be mapped to - "None" in the result. + and in the resulting dictionary, each character in *from* will be + mapped to the character at the same position in *to*. If there is + a third argument, it must be a string, whose characters will be + mapped to "None" in the result. -str.partition(sep) +str.partition(sep, /) Split the string at the first occurrence of *sep*, and return a 3-tuple containing the part before the separator, the separator @@ -9560,7 +10536,7 @@ str.removesuffix(suffix, /) Added in version 3.9. -str.replace(old, new, count=-1) +str.replace(old, new, /, count=-1) Return a copy of the string with all occurrences of substring *old* replaced by *new*. If *count* is given, only the first *count* @@ -9582,14 +10558,14 @@ str.rindex(sub[, start[, end]]) Like "rfind()" but raises "ValueError" when the substring *sub* is not found. -str.rjust(width[, fillchar]) +str.rjust(width, fillchar=' ', /) Return the string right justified in a string of length *width*. Padding is done using the specified *fillchar* (default is an ASCII space). The original string is returned if *width* is less than or equal to "len(s)". -str.rpartition(sep) +str.rpartition(sep, /) Split the string at the last occurrence of *sep*, and return a 3-tuple containing the part before the separator, the separator @@ -9606,7 +10582,7 @@ str.rsplit(sep=None, maxsplit=-1) from the right, "rsplit()" behaves like "split()" which is described in detail below. -str.rstrip([chars]) +str.rstrip(chars=None, /) Return a copy of the string with trailing characters removed. The *chars* argument is a string specifying the set of characters to be @@ -9669,6 +10645,20 @@ str.split(sep=None, maxsplit=-1) >>> ' 1 2 3 '.split() ['1', '2', '3'] + If *sep* is not specified or is "None" and *maxsplit* is "0", only + leading runs of consecutive whitespace are considered. + + For example: + + >>> "".split(None, 0) + [] + >>> " ".split(None, 0) + [] + >>> " foo ".split(maxsplit=0) + ['foo '] + + See also "join()". + str.splitlines(keepends=False) Return a list of the lines in the string, breaking at line @@ -9737,7 +10727,7 @@ str.startswith(prefix[, start[, end]]) With optional *start*, test string beginning at that position. With optional *end*, stop comparing string at that position. -str.strip([chars]) +str.strip(chars=None, /) Return a copy of the string with the leading and trailing characters removed. The *chars* argument is a string specifying the @@ -9801,7 +10791,9 @@ str.title() >>> titlecase("they're bill's friends.") "They're Bill's Friends." -str.translate(table) + See also "istitle()". + +str.translate(table, /) Return a copy of the string in which each character has been mapped through the given translation table. The table must be an object @@ -9826,10 +10818,10 @@ str.upper() category of the resulting character(s) is not “Lu” (Letter, uppercase), but e.g. “Lt” (Letter, titlecase). - The uppercasing algorithm used is described in section 3.13 - ‘Default Case Folding’ of the Unicode Standard. + The uppercasing algorithm used is described in section 3.13.2 + ‘Default Case Conversion’ of the Unicode Standard. -str.zfill(width) +str.zfill(width, /) Return a copy of the string left filled with ASCII "'0'" digits to make a string of length *width*. A leading sign prefix @@ -9847,174 +10839,313 @@ str.zfill(width) 'strings': '''String and Bytes literals ************************* -String literals are described by the following lexical definitions: +String literals are text enclosed in single quotes ("'") or double +quotes ("""). For example: - stringliteral: [stringprefix](shortstring | longstring) - stringprefix: "r" | "u" | "R" | "U" | "f" | "F" - | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF" - shortstring: "'" shortstringitem* "'" | '"' shortstringitem* '"' - longstring: "\'\'\'" longstringitem* "\'\'\'" | '"""' longstringitem* '"""' - shortstringitem: shortstringchar | stringescapeseq - longstringitem: longstringchar | stringescapeseq - shortstringchar: - longstringchar: - stringescapeseq: "\\" + "spam" + 'eggs' - bytesliteral: bytesprefix(shortbytes | longbytes) - bytesprefix: "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB" - shortbytes: "'" shortbytesitem* "'" | '"' shortbytesitem* '"' - longbytes: "\'\'\'" longbytesitem* "\'\'\'" | '"""' longbytesitem* '"""' - shortbytesitem: shortbyteschar | bytesescapeseq - longbytesitem: longbyteschar | bytesescapeseq - shortbyteschar: - longbyteschar: - bytesescapeseq: "\\" +The quote used to start the literal also terminates it, so a string +literal can only contain the other quote (except with escape +sequences, see below). For example: -One syntactic restriction not indicated by these productions is that -whitespace is not allowed between the "stringprefix" or "bytesprefix" -and the rest of the literal. The source character set is defined by -the encoding declaration; it is UTF-8 if no encoding declaration is -given in the source file; see section Encoding declarations. + 'Say "Hello", please.' + "Don't do that!" -In plain English: Both types of literals can be enclosed in matching -single quotes ("'") or double quotes ("""). They can also be enclosed -in matching groups of three single or double quotes (these are -generally referred to as *triple-quoted strings*). The backslash ("\\") -character is used to give special meaning to otherwise ordinary -characters like "n", which means ‘newline’ when escaped ("\\n"). It can -also be used to escape characters that otherwise have a special -meaning, such as newline, backslash itself, or the quote character. -See escape sequences below for examples. +Except for this limitation, the choice of quote character ("'" or """) +does not affect how the literal is parsed. -Bytes literals are always prefixed with "'b'" or "'B'"; they produce -an instance of the "bytes" type instead of the "str" type. They may -only contain ASCII characters; bytes with a numeric value of 128 or -greater must be expressed with escapes. +Inside a string literal, the backslash ("\\") character introduces an +*escape sequence*, which has special meaning depending on the +character after the backslash. For example, "\\"" denotes the double +quote character, and does *not* end the string: -Both string and bytes literals may optionally be prefixed with a -letter "'r'" or "'R'"; such constructs are called *raw string -literals* and *raw bytes literals* respectively and treat backslashes -as literal characters. As a result, in raw string literals, "'\\U'" -and "'\\u'" escapes are not treated specially. + >>> print("Say \\"Hello\\" to everyone!") + Say "Hello" to everyone! + +See escape sequences below for a full list of such sequences, and more +details. + + +Triple-quoted strings +===================== + +Strings can also be enclosed in matching groups of three single or +double quotes. These are generally referred to as *triple-quoted +strings*: + + """This is a triple-quoted string.""" + +In triple-quoted literals, unescaped quotes are allowed (and are +retained), except that three unescaped quotes in a row terminate the +literal, if they are of the same kind ("'" or """) used at the start: + + """This string has "quotes" inside.""" + +Unescaped newlines are also allowed and retained: + + \'\'\'This triple-quoted string + continues on the next line.\'\'\' + + +String prefixes +=============== + +String literals can have an optional *prefix* that influences how the +content of the literal is parsed, for example: + + b"data" + f'{result=}' + +The allowed prefixes are: + +* "b": Bytes literal + +* "r": Raw string + +* "f": Formatted string literal (“f-string”) + +* "t": Template string literal (“t-string”) + +* "u": No effect (allowed for backwards compatibility) + +See the linked sections for details on each type. + +Prefixes are case-insensitive (for example, ‘"B"’ works the same as +‘"b"’). The ‘"r"’ prefix can be combined with ‘"f"’, ‘"t"’ or ‘"b"’, +so ‘"fr"’, ‘"rf"’, ‘"tr"’, ‘"rt"’, ‘"br"’, and ‘"rb"’ are also valid +prefixes. Added in version 3.3: The "'rb'" prefix of raw bytes literals has been added as a synonym of "'br'".Support for the unicode legacy literal ("u'value'") was reintroduced to simplify the maintenance of dual Python 2.x and 3.x codebases. See **PEP 414** for more information. -A string literal with "'f'" or "'F'" in its prefix is a *formatted -string literal*; see f-strings. The "'f'" may be combined with "'r'", -but not with "'b'" or "'u'", therefore raw formatted strings are -possible, but formatted bytes literals are not. -In triple-quoted literals, unescaped newlines and quotes are allowed -(and are retained), except that three unescaped quotes in a row -terminate the literal. (A “quote” is the character used to open the -literal, i.e. either "'" or """.) +Formal grammar +============== + +String literals, except “f-strings” and “t-strings”, are described by +the following lexical definitions. + +These definitions use negative lookaheads ("!") to indicate that an +ending quote ends the literal. + + STRING: [stringprefix] (stringcontent) + stringprefix: <("r" | "u" | "b" | "br" | "rb"), case-insensitive> + stringcontent: + | "\'\'\'" ( !"\'\'\'" longstringitem)* "\'\'\'" + | '"""' ( !'"""' longstringitem)* '"""' + | "'" ( !"'" stringitem)* "'" + | '"' ( !'"' stringitem)* '"' + stringitem: stringchar | stringescapeseq + stringchar: + longstringitem: stringitem | newline + stringescapeseq: "\\" + +Note that as in all lexical definitions, whitespace is significant. In +particular, the prefix (if any) must be immediately followed by the +starting quote. Escape sequences ================ -Unless an "'r'" or "'R'" prefix is present, escape sequences in string +Unless an ‘"r"’ or ‘"R"’ prefix is present, escape sequences in string and bytes literals are interpreted according to rules similar to those used by Standard C. The recognized escape sequences are: -+---------------------------+-----------------------------------+---------+ -| Escape Sequence | Meaning | Notes | -|===========================|===================================|=========| -| "\\" | Backslash and newline ignored | (1) | -+---------------------------+-----------------------------------+---------+ -| "\\\\" | Backslash ("\\") | | -+---------------------------+-----------------------------------+---------+ -| "\\'" | Single quote ("'") | | -+---------------------------+-----------------------------------+---------+ -| "\\"" | Double quote (""") | | -+---------------------------+-----------------------------------+---------+ -| "\\a" | ASCII Bell (BEL) | | -+---------------------------+-----------------------------------+---------+ -| "\\b" | ASCII Backspace (BS) | | -+---------------------------+-----------------------------------+---------+ -| "\\f" | ASCII Formfeed (FF) | | -+---------------------------+-----------------------------------+---------+ -| "\\n" | ASCII Linefeed (LF) | | -+---------------------------+-----------------------------------+---------+ -| "\\r" | ASCII Carriage Return (CR) | | -+---------------------------+-----------------------------------+---------+ -| "\\t" | ASCII Horizontal Tab (TAB) | | -+---------------------------+-----------------------------------+---------+ -| "\\v" | ASCII Vertical Tab (VT) | | -+---------------------------+-----------------------------------+---------+ -| "\\*ooo*" | Character with octal value *ooo* | (2,4) | -+---------------------------+-----------------------------------+---------+ -| "\\x*hh*" | Character with hex value *hh* | (3,4) | -+---------------------------+-----------------------------------+---------+ ++----------------------------------------------------+----------------------------------------------------+ +| Escape Sequence | Meaning | +|====================================================|====================================================| +| "\\" | Ignored end of line | ++----------------------------------------------------+----------------------------------------------------+ +| "\\\\" | Backslash | ++----------------------------------------------------+----------------------------------------------------+ +| "\\'" | Single quote | ++----------------------------------------------------+----------------------------------------------------+ +| "\\"" | Double quote | ++----------------------------------------------------+----------------------------------------------------+ +| "\\a" | ASCII Bell (BEL) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\b" | ASCII Backspace (BS) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\f" | ASCII Formfeed (FF) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\n" | ASCII Linefeed (LF) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\r" | ASCII Carriage Return (CR) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\t" | ASCII Horizontal Tab (TAB) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\v" | ASCII Vertical Tab (VT) | ++----------------------------------------------------+----------------------------------------------------+ +| "\\*ooo*" | Octal character | ++----------------------------------------------------+----------------------------------------------------+ +| "\\x*hh*" | Hexadecimal character | ++----------------------------------------------------+----------------------------------------------------+ +| "\\N{*name*}" | Named Unicode character | ++----------------------------------------------------+----------------------------------------------------+ +| "\\u*xxxx*" | Hexadecimal Unicode character | ++----------------------------------------------------+----------------------------------------------------+ +| "\\U*xxxxxxxx*" | Hexadecimal Unicode character | ++----------------------------------------------------+----------------------------------------------------+ -Escape sequences only recognized in string literals are: -+---------------------------+-----------------------------------+---------+ -| Escape Sequence | Meaning | Notes | -|===========================|===================================|=========| -| "\\N{*name*}" | Character named *name* in the | (5) | -| | Unicode database | | -+---------------------------+-----------------------------------+---------+ -| "\\u*xxxx*" | Character with 16-bit hex value | (6) | -| | *xxxx* | | -+---------------------------+-----------------------------------+---------+ -| "\\U*xxxxxxxx*" | Character with 32-bit hex value | (7) | -| | *xxxxxxxx* | | -+---------------------------+-----------------------------------+---------+ +Ignored end of line +------------------- -Notes: +A backslash can be added at the end of a line to ignore the newline: -1. A backslash can be added at the end of a line to ignore the - newline: + >>> 'This string will not include \\ + ... backslashes or newline characters.' + 'This string will not include backslashes or newline characters.' - >>> 'This string will not include \\ - ... backslashes or newline characters.' - 'This string will not include backslashes or newline characters.' +The same result can be achieved using triple-quoted strings, or +parentheses and string literal concatenation. - The same result can be achieved using triple-quoted strings, or - parentheses and string literal concatenation. -2. As in Standard C, up to three octal digits are accepted. +Escaped characters +------------------ - Changed in version 3.11: Octal escapes with value larger than - "0o377" produce a "DeprecationWarning". +To include a backslash in a non-raw Python string literal, it must be +doubled. The "\\\\" escape sequence denotes a single backslash +character: - Changed in version 3.12: Octal escapes with value larger than - "0o377" produce a "SyntaxWarning". In a future Python version they - will be eventually a "SyntaxError". + >>> print('C:\\\\Program Files') + C:\\Program Files -3. Unlike in Standard C, exactly two hex digits are required. +Similarly, the "\\'" and "\\"" sequences denote the single and double +quote character, respectively: -4. In a bytes literal, hexadecimal and octal escapes denote the byte - with the given value. In a string literal, these escapes denote a - Unicode character with the given value. + >>> print('\\' and \\"') + ' and " -5. Changed in version 3.3: Support for name aliases [1] has been - added. -6. Exactly four hex digits are required. +Octal character +--------------- -7. Any Unicode character can be encoded this way. Exactly eight hex - digits are required. +The sequence "\\*ooo*" denotes a *character* with the octal (base 8) +value *ooo*: -Unlike Standard C, all unrecognized escape sequences are left in the -string unchanged, i.e., *the backslash is left in the result*. (This -behavior is useful when debugging: if an escape sequence is mistyped, -the resulting output is more easily recognized as broken.) It is also -important to note that the escape sequences only recognized in string -literals fall into the category of unrecognized escapes for bytes -literals. + >>> '\\120' + 'P' + +Up to three octal digits (0 through 7) are accepted. + +In a bytes literal, *character* means a *byte* with the given value. +In a string literal, it means a Unicode character with the given +value. + +Changed in version 3.11: Octal escapes with value larger than "0o377" +(255) produce a "DeprecationWarning". + +Changed in version 3.12: Octal escapes with value larger than "0o377" +(255) produce a "SyntaxWarning". In a future Python version they will +raise a "SyntaxError". + + +Hexadecimal character +--------------------- + +The sequence "\\x*hh*" denotes a *character* with the hex (base 16) +value *hh*: + + >>> '\\x50' + 'P' + +Unlike in Standard C, exactly two hex digits are required. + +In a bytes literal, *character* means a *byte* with the given value. +In a string literal, it means a Unicode character with the given +value. + + +Named Unicode character +----------------------- + +The sequence "\\N{*name*}" denotes a Unicode character with the given +*name*: + + >>> '\\N{LATIN CAPITAL LETTER P}' + 'P' + >>> '\\N{SNAKE}' + '🐍' + +This sequence cannot appear in bytes literals. + +Changed in version 3.3: Support for name aliases has been added. + + +Hexadecimal Unicode characters +------------------------------ + +These sequences "\\u*xxxx*" and "\\U*xxxxxxxx*" denote the Unicode +character with the given hex (base 16) value. Exactly four digits are +required for "\\u"; exactly eight digits are required for "\\U". The +latter can encode any Unicode character. + + >>> '\\u1234' + 'ሴ' + >>> '\\U0001f40d' + '🐍' + +These sequences cannot appear in bytes literals. + + +Unrecognized escape sequences +----------------------------- + +Unlike in Standard C, all unrecognized escape sequences are left in +the string unchanged, that is, *the backslash is left in the result*: + + >>> print('\\q') + \\q + >>> list('\\q') + ['\\\\', 'q'] + +Note that for bytes literals, the escape sequences only recognized in +string literals ("\\N...", "\\u...", "\\U...") fall into the category of +unrecognized escapes. Changed in version 3.6: Unrecognized escape sequences produce a "DeprecationWarning". Changed in version 3.12: Unrecognized escape sequences produce a -"SyntaxWarning". In a future Python version they will be eventually a +"SyntaxWarning". In a future Python version they will raise a "SyntaxError". + +Bytes literals +============== + +*Bytes literals* are always prefixed with ‘"b"’ or ‘"B"’; they produce +an instance of the "bytes" type instead of the "str" type. They may +only contain ASCII characters; bytes with a numeric value of 128 or +greater must be expressed with escape sequences (typically Hexadecimal +character or Octal character): + + >>> b'\\x89PNG\\r\\n\\x1a\\n' + b'\\x89PNG\\r\\n\\x1a\\n' + >>> list(b'\\x89PNG\\r\\n\\x1a\\n') + [137, 80, 78, 71, 13, 10, 26, 10] + +Similarly, a zero byte must be expressed using an escape sequence +(typically "\\0" or "\\x00"). + + +Raw string literals +=================== + +Both string and bytes literals may optionally be prefixed with a +letter ‘"r"’ or ‘"R"’; such constructs are called *raw string +literals* and *raw bytes literals* respectively and treat backslashes +as literal characters. As a result, in raw string literals, escape +sequences are not treated specially: + + >>> r'\\d{4}-\\d{2}-\\d{2}' + '\\\\d{4}-\\\\d{2}-\\\\d{2}' + Even in a raw literal, quotes can be escaped with a backslash, but the backslash remains in the result; for example, "r"\\""" is a valid string literal consisting of two characters: a backslash and a double @@ -10024,6 +11155,251 @@ cannot end in a single backslash* (since the backslash would escape the following quote character). Note also that a single backslash followed by a newline is interpreted as those two characters as part of the literal, *not* as a line continuation. + + +f-strings +========= + +Added in version 3.6. + +Changed in version 3.7: The "await" and "async for" can be used in +expressions within f-strings. + +Changed in version 3.8: Added the debug specifier ("=") + +Changed in version 3.12: Many restrictions on expressions within +f-strings have been removed. Notably, nested strings, comments, and +backslashes are now permitted. + +A *formatted string literal* or *f-string* is a string literal that is +prefixed with ‘"f"’ or ‘"F"’. Unlike other string literals, f-strings +do not have a constant value. They may contain *replacement fields* +delimited by curly braces "{}". Replacement fields contain expressions +which are evaluated at run time. For example: + + >>> who = 'nobody' + >>> nationality = 'Spanish' + >>> f'{who.title()} expects the {nationality} Inquisition!' + 'Nobody expects the Spanish Inquisition!' + +Any doubled curly braces ("{{" or "}}") outside replacement fields are +replaced with the corresponding single curly brace: + + >>> print(f'{{...}}') + {...} + +Other characters outside replacement fields are treated like in +ordinary string literals. This means that escape sequences are decoded +(except when a literal is also marked as a raw string), and newlines +are possible in triple-quoted f-strings: + + >>> name = 'Galahad' + >>> favorite_color = 'blue' + >>> print(f'{name}:\\t{favorite_color}') + Galahad: blue + >>> print(rf"C:\\Users\\{name}") + C:\\Users\\Galahad + >>> print(f\'\'\'Three shall be the number of the counting + ... and the number of the counting shall be three.\'\'\') + Three shall be the number of the counting + and the number of the counting shall be three. + +Expressions in formatted string literals are treated like regular +Python expressions. Each expression is evaluated in the context where +the formatted string literal appears, in order from left to right. An +empty expression is not allowed, and both "lambda" and assignment +expressions ":=" must be surrounded by explicit parentheses: + + >>> f'{(half := 1/2)}, {half * 42}' + '0.5, 21.0' + +Reusing the outer f-string quoting type inside a replacement field is +permitted: + + >>> a = dict(x=2) + >>> f"abc {a["x"]} def" + 'abc 2 def' + +Backslashes are also allowed in replacement fields and are evaluated +the same way as in any other context: + + >>> a = ["a", "b", "c"] + >>> print(f"List a contains:\\n{"\\n".join(a)}") + List a contains: + a + b + c + +It is possible to nest f-strings: + + >>> name = 'world' + >>> f'Repeated:{f' hello {name}' * 3}' + 'Repeated: hello world hello world hello world' + +Portable Python programs should not use more than 5 levels of nesting. + +**CPython implementation detail:** CPython does not limit nesting of +f-strings. + +Replacement expressions can contain newlines in both single-quoted and +triple-quoted f-strings and they can contain comments. Everything that +comes after a "#" inside a replacement field is a comment (even +closing braces and quotes). This means that replacement fields with +comments must be closed in a different line: + + >>> a = 2 + >>> f"abc{a # This comment }" continues until the end of the line + ... + 3}" + 'abc5' + +After the expression, replacement fields may optionally contain: + +* a *debug specifier* – an equal sign ("="), optionally surrounded by + whitespace on one or both sides; + +* a *conversion specifier* – "!s", "!r" or "!a"; and/or + +* a *format specifier* prefixed with a colon (":"). + +See the Standard Library section on f-strings for details on how these +fields are evaluated. + +As that section explains, *format specifiers* are passed as the second +argument to the "format()" function to format a replacement field +value. For example, they can be used to specify a field width and +padding characters using the Format Specification Mini-Language: + + >>> number = 14.3 + >>> f'{number:20.7f}' + ' 14.3000000' + +Top-level format specifiers may include nested replacement fields: + + >>> field_size = 20 + >>> precision = 7 + >>> f'{number:{field_size}.{precision}f}' + ' 14.3000000' + +These nested fields may include their own conversion fields and format +specifiers: + + >>> number = 3 + >>> f'{number:{field_size}}' + ' 3' + >>> f'{number:{field_size:05}}' + '00000000000000000003' + +However, these nested fields may not include more deeply nested +replacement fields. + +Formatted string literals cannot be used as *docstrings*, even if they +do not include expressions: + + >>> def foo(): + ... f"Not a docstring" + ... + >>> print(foo.__doc__) + None + +See also: + + * **PEP 498** – Literal String Interpolation + + * **PEP 701** – Syntactic formalization of f-strings + + * "str.format()", which uses a related format string mechanism. + + +t-strings +========= + +Added in version 3.14. + +A *template string literal* or *t-string* is a string literal that is +prefixed with ‘"t"’ or ‘"T"’. These strings follow the same syntax +rules as formatted string literals. For differences in evaluation +rules, see the Standard Library section on t-strings + + +Formal grammar for f-strings +============================ + +F-strings are handled partly by the *lexical analyzer*, which produces +the tokens "FSTRING_START", "FSTRING_MIDDLE" and "FSTRING_END", and +partly by the parser, which handles expressions in the replacement +field. The exact way the work is split is a CPython implementation +detail. + +Correspondingly, the f-string grammar is a mix of lexical and +syntactic definitions. + +Whitespace is significant in these situations: + +* There may be no whitespace in "FSTRING_START" (between the prefix + and quote). + +* Whitespace in "FSTRING_MIDDLE" is part of the literal string + contents. + +* In "fstring_replacement_field", if "f_debug_specifier" is present, + all whitespace after the opening brace until the + "f_debug_specifier", as well as whitespace immediately following + "f_debug_specifier", is retained as part of the expression. + + **CPython implementation detail:** The expression is not handled in + the tokenization phase; it is retrieved from the source code using + locations of the "{" token and the token after "=". + +The "FSTRING_MIDDLE" definition uses negative lookaheads ("!") to +indicate special characters (backslash, newline, "{", "}") and +sequences ("f_quote"). + + fstring: FSTRING_START fstring_middle* FSTRING_END + + FSTRING_START: fstringprefix ("'" | '"' | "\'\'\'" | '"""') + FSTRING_END: f_quote + fstringprefix: <("f" | "fr" | "rf"), case-insensitive> + f_debug_specifier: '=' + f_quote: + + fstring_middle: + | fstring_replacement_field + | FSTRING_MIDDLE + FSTRING_MIDDLE: + | (!"\\" !newline !'{' !'}' !f_quote) source_character + | stringescapeseq + | "{{" + | "}}" + | + fstring_replacement_field: + | '{' f_expression [f_debug_specifier] [fstring_conversion] + [fstring_full_format_spec] '}' + fstring_conversion: + | "!" ("s" | "r" | "a") + fstring_full_format_spec: + | ':' fstring_format_spec* + fstring_format_spec: + | FSTRING_MIDDLE + | fstring_replacement_field + f_expression: + | ','.(conditional_expression | "*" or_expr)+ [","] + | yield_expression + +Note: + + In the above grammar snippet, the "f_quote" and "FSTRING_MIDDLE" + rules are context-sensitive – they depend on the contents of + "FSTRING_START" of the nearest enclosing "fstring".Constructing a + more traditional formal grammar from this template is left as an + exercise for the reader. + +The grammar for t-strings is identical to the one for f-strings, with +*t* instead of *f* at the beginning of rule and token names and in the +prefix. + + tstring: TSTRING_START tstring_middle* TSTRING_END + + ''', 'subscriptions': r'''Subscriptions ************* @@ -10218,15 +11594,29 @@ to its previous value: "except*" clause ================ -The "except*" clause(s) are used for handling "ExceptionGroup"s. The -exception type for matching is interpreted as in the case of "except", -but in the case of exception groups we can have partial matches when -the type matches some of the exceptions in the group. This means that -multiple "except*" clauses can execute, each handling part of the -exception group. Each clause executes at most once and handles an -exception group of all matching exceptions. Each exception in the -group is handled by at most one "except*" clause, the first that -matches it. +The "except*" clause(s) specify one or more handlers for groups of +exceptions ("BaseExceptionGroup" instances). A "try" statement can +have either "except" or "except*" clauses, but not both. The exception +type for matching is mandatory in the case of "except*", so "except*:" +is a syntax error. The type is interpreted as in the case of "except", +but matching is performed on the exceptions contained in the group +that is being handled. An "TypeError" is raised if a matching type is +a subclass of "BaseExceptionGroup", because that would have ambiguous +semantics. + +When an exception group is raised in the try block, each "except*" +clause splits (see "split()") it into the subgroups of matching and +non-matching exceptions. If the matching subgroup is not empty, it +becomes the handled exception (the value returned from +"sys.exception()") and assigned to the target of the "except*" clause +(if there is one). Then, the body of the "except*" clause executes. If +the non-matching subgroup is not empty, it is processed by the next +"except*" in the same manner. This continues until all exceptions in +the group have been matched, or the last "except*" clause has run. + +After all "except*" clauses execute, the group of unhandled exceptions +is merged with any exceptions that were raised or re-raised from +within "except*" clauses. This merged exception group propagates on.: >>> try: ... raise ExceptionGroup("eg", @@ -10239,33 +11629,27 @@ matches it. caught with nested (TypeError(2),) caught with nested (OSError(3), OSError(4)) + Exception Group Traceback (most recent call last): - | File "", line 2, in - | ExceptionGroup: eg + | File "", line 2, in + | raise ExceptionGroup("eg", + | [ValueError(1), TypeError(2), OSError(3), OSError(4)]) + | ExceptionGroup: eg (1 sub-exception) +-+---------------- 1 ---------------- | ValueError: 1 +------------------------------------ -Any remaining exceptions that were not handled by any "except*" clause -are re-raised at the end, along with all exceptions that were raised -from within the "except*" clauses. If this list contains more than one -exception to reraise, they are combined into an exception group. - -If the raised exception is not an exception group and its type matches -one of the "except*" clauses, it is caught and wrapped by an exception -group with an empty message string. +If the exception raised from the "try" block is not an exception group +and its type matches one of the "except*" clauses, it is caught and +wrapped by an exception group with an empty message string. This +ensures that the type of the target "e" is consistently +"BaseExceptionGroup": >>> try: ... raise BlockingIOError ... except* BlockingIOError as e: ... print(repr(e)) ... - ExceptionGroup('', (BlockingIOError())) + ExceptionGroup('', (BlockingIOError(),)) -An "except*" clause must have a matching expression; it cannot be -"except*:". Furthermore, this expression cannot contain exception -group types, because that would have ambiguous semantics. - -It is not possible to mix "except" and "except*" in the same "try". "break", "continue" and "return" cannot appear in an "except*" clause. @@ -10282,11 +11666,11 @@ not handled by the preceding "except" clauses. ================ If "finally" is present, it specifies a ‘cleanup’ handler. The "try" -clause is executed, including any "except" and "else" clauses. If an +clause is executed, including any "except" and "else" clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The "finally" clause is executed. If there is a saved exception it is re-raised at the end of the "finally" -clause. If the "finally" clause raises another exception, the saved +clause. If the "finally" clause raises another exception, the saved exception is set as the context of the new exception. If the "finally" clause executes a "return", "break" or "continue" statement, the saved exception is discarded. For example, this function returns 42. @@ -10979,7 +12363,7 @@ module.__package__ "ImportWarning" when falling back to "__package__" during import resolution. - Deprecated since version 3.13, will be removed in version 3.15: + Deprecated since version 3.13, removed in version 3.15: "__package__" will cease to be set or taken into consideration by the import system or standard library. @@ -11023,41 +12407,24 @@ module.__path__ module.__file__ -module.__cached__ + "__file__" is an optional attribute that may or may not be set. + Both attributes should be a "str" when they are available. - "__file__" and "__cached__" are both optional attributes that may - or may not be set. Both attributes should be a "str" when they are - available. + An optional attribute, "__file__" indicates the pathname of the + file from which the module was loaded (if loaded from a file), or + the pathname of the shared library file for extension modules + loaded dynamically from a shared library. It might be missing for + certain types of modules, such as C modules that are statically + linked into the interpreter, and the import system may opt to leave + it unset if it has no semantic meaning (for example, a module + loaded from a database). - "__file__" indicates the pathname of the file from which the module - was loaded (if loaded from a file), or the pathname of the shared - library file for extension modules loaded dynamically from a shared - library. It might be missing for certain types of modules, such as - C modules that are statically linked into the interpreter, and the - import system may opt to leave it unset if it has no semantic - meaning (for example, a module loaded from a database). + Deprecated since version 3.13, removed in version 3.15: Setting + "__cached__" on a module while failing to set "__spec__.cached" is + deprecated. In Python 3.15, "__cached__" will cease to be set or + taken into consideration by the import system or standard library. - If "__file__" is set then the "__cached__" attribute might also be - set, which is the path to any compiled version of the code (for - example, a byte-compiled file). The file does not need to exist to - set this attribute; the path can simply point to where the compiled - file *would* exist (see **PEP 3147**). - - Note that "__cached__" may be set even if "__file__" is not set. - However, that scenario is quite atypical. Ultimately, the *loader* - is what makes use of the module spec provided by the *finder* (from - which "__file__" and "__cached__" are derived). So if a loader can - load from a cached module but otherwise does not load from a file, - that atypical scenario may be appropriate. - - It is **strongly** recommended that you use - "module.__spec__.cached" instead of "module.__cached__". - - Deprecated since version 3.13, will be removed in version 3.15: - Setting "__cached__" on a module while failing to set - "__spec__.cached" is deprecated. In Python 3.15, "__cached__" will - cease to be set or taken into consideration by the import system or - standard library. + Changed in version 3.15: "__cached__" is no longer set. Other writable attributes on module objects @@ -11161,6 +12528,11 @@ Special attributes | | "X.__bases__" will be exactly equal to "(A, B, | | | C)". | +----------------------------------------------------+----------------------------------------------------+ +| type.__base__ | **CPython implementation detail:** The single base | +| | class in the inheritance chain that is responsible | +| | for the memory layout of instances. This attribute | +| | corresponds to "tp_base" at the C level. | ++----------------------------------------------------+----------------------------------------------------+ | type.__doc__ | The class’s documentation string, or "None" if | | | undefined. Not inherited by subclasses. | +----------------------------------------------------+----------------------------------------------------+ @@ -11168,11 +12540,20 @@ Special attributes | | collected during class body execution. See also: | | | "__annotations__ attributes". For best practices | | | on working with "__annotations__", please see | -| | "annotationlib". Where possible, use | +| | "annotationlib". Use | | | "annotationlib.get_annotations()" instead of | -| | accessing this attribute directly. Changed in | -| | version 3.14: Annotations are now lazily | -| | evaluated. See **PEP 649**. | +| | accessing this attribute directly. Warning: | +| | Accessing the "__annotations__" attribute directly | +| | on a class object may return annotations for the | +| | wrong class, specifically in certain cases where | +| | the class, its base class, or a metaclass is | +| | defined under "from __future__ import | +| | annotations". See **749** for details.This | +| | attribute does not exist on certain builtin | +| | classes. On user-defined classes without | +| | "__annotations__", it is an empty dictionary. | +| | Changed in version 3.14: Annotations are now | +| | lazily evaluated. See **PEP 649**. | +----------------------------------------------------+----------------------------------------------------+ | type.__annotate__() | The *annotate function* for this class, or "None" | | | if the class has no annotations. See also: | @@ -11510,6 +12891,10 @@ Special read-only attributes | | (this is an index into the *bytecode* string of | | | the code object) | +----------------------------------------------------+----------------------------------------------------+ +| frame.f_generator | The *generator* or *coroutine* object that owns | +| | this frame, or "None" if the frame is a normal | +| | function. Added in version 3.14. | ++----------------------------------------------------+----------------------------------------------------+ Special writable attributes @@ -11690,8 +13075,8 @@ identity) may not be used as keys. Values that compare equal (such as dictionary entry. class dict(**kwargs) -class dict(mapping, **kwargs) -class dict(iterable, **kwargs) +class dict(mapping, /, **kwargs) +class dict(iterable, /, **kwargs) Return a new dictionary initialized from an optional positional argument and a possibly empty set of keyword arguments. @@ -11724,8 +13109,11 @@ class dict(iterable, **kwargs) the keyword argument replaces the value from the positional argument. - To illustrate, the following examples all return a dictionary equal - to "{"one": 1, "two": 2, "three": 3}": + Dictionaries compare equal if and only if they have the same "(key, + value)" pairs (regardless of ordering). Order comparisons (‘<’, + ‘<=’, ‘>=’, ‘>’) raise "TypeError". To illustrate dictionary + creation and equality, the following examples all return a + dictionary equal to "{"one": 1, "two": 2, "three": 3}": >>> a = dict(one=1, two=2, three=3) >>> b = {'one': 1, 'two': 2, 'three': 3} @@ -11740,6 +13128,29 @@ class dict(iterable, **kwargs) keys that are valid Python identifiers. Otherwise, any valid keys can be used. + Dictionaries preserve insertion order. Note that updating a key + does not affect the order. Keys added after deletion are inserted + at the end. + + >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} + >>> d + {'one': 1, 'two': 2, 'three': 3, 'four': 4} + >>> list(d) + ['one', 'two', 'three', 'four'] + >>> list(d.values()) + [1, 2, 3, 4] + >>> d["one"] = 42 + >>> d + {'one': 42, 'two': 2, 'three': 3, 'four': 4} + >>> del d["two"] + >>> d["two"] = None + >>> d + {'one': 42, 'three': 3, 'four': 4, 'two': None} + + Changed in version 3.7: Dictionary order is guaranteed to be + insertion order. This behavior was an implementation detail of + CPython from 3.6. + These are the operations that dictionaries support (and therefore, custom mapping types should support too): @@ -11777,8 +13188,8 @@ class dict(iterable, **kwargs) 1 The example above shows part of the implementation of - "collections.Counter". A different "__missing__" method is used - by "collections.defaultdict". + "collections.Counter". A different "__missing__()" method is + used by "collections.defaultdict". d[key] = value @@ -11837,7 +13248,8 @@ class dict(iterable, **kwargs) Return a new view of the dictionary’s keys. See the documentation of view objects. - pop(key[, default]) + pop(key, /) + pop(key, default, /) If *key* is in the dictionary, remove it and return its value, else return *default*. If *default* is not given and *key* is @@ -11868,10 +13280,13 @@ class dict(iterable, **kwargs) *key* with a value of *default* and return *default*. *default* defaults to "None". - update([other]) + update(**kwargs) + update(mapping, /, **kwargs) + update(iterable, /, **kwargs) - Update the dictionary with the key/value pairs from *other*, - overwriting existing keys. Return "None". + Update the dictionary with the key/value pairs from *mapping* or + *iterable* and *kwargs*, overwriting existing keys. Return + "None". "update()" accepts either another object with a "keys()" method (in which case "__getitem__()" is called with every key returned @@ -11910,33 +13325,6 @@ class dict(iterable, **kwargs) Added in version 3.9. - Dictionaries compare equal if and only if they have the same "(key, - value)" pairs (regardless of ordering). Order comparisons (‘<’, - ‘<=’, ‘>=’, ‘>’) raise "TypeError". - - Dictionaries preserve insertion order. Note that updating a key - does not affect the order. Keys added after deletion are inserted - at the end. - - >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} - >>> d - {'one': 1, 'two': 2, 'three': 3, 'four': 4} - >>> list(d) - ['one', 'two', 'three', 'four'] - >>> list(d.values()) - [1, 2, 3, 4] - >>> d["one"] = 42 - >>> d - {'one': 42, 'two': 2, 'three': 3, 'four': 4} - >>> del d["two"] - >>> d["two"] = None - >>> d - {'one': 42, 'three': 3, 'four': 4, 'two': None} - - Changed in version 3.7: Dictionary order is guaranteed to be - insertion order. This behavior was an implementation detail of - CPython from 3.6. - Dictionaries and dictionary views are reversible. >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} @@ -12163,7 +13551,7 @@ operations. [3] | "s * n" or "n * s" | equivalent to adding *s* to | (2)(7) | | | itself *n* times | | +----------------------------+----------------------------------+------------+ -| "s[i]" | *i*th item of *s*, origin 0 | (3) | +| "s[i]" | *i*th item of *s*, origin 0 | (3)(8) | +----------------------------+----------------------------------+------------+ | "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) | +----------------------------+----------------------------------+------------+ @@ -12176,13 +13564,6 @@ operations. [3] +----------------------------+----------------------------------+------------+ | "max(s)" | largest item of *s* | | +----------------------------+----------------------------------+------------+ -| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) | -| | *x* in *s* (at or after index | | -| | *i* and before index *j*) | | -+----------------------------+----------------------------------+------------+ -| "s.count(x)" | total number of occurrences of | | -| | *x* in *s* | | -+----------------------------+----------------------------------+------------+ Sequences of the same type also support comparisons. In particular, tuples and lists are compared lexicographically by comparing @@ -12279,13 +13660,31 @@ Notes: that follow specific patterns, and hence don’t support sequence concatenation or repetition. -8. "index" raises "ValueError" when *x* is not found in *s*. Not all - implementations support passing the additional arguments *i* and - *j*. These arguments allow efficient searching of subsections of - the sequence. Passing the extra arguments is roughly equivalent to - using "s[i:j].index(x)", only without copying any data and with the - returned index being relative to the start of the sequence rather - than the start of the slice. +8. An "IndexError" is raised if *i* is outside the sequence range. + +-[ Sequence Methods ]- + +Sequence types also support the following methods: + +sequence.count(value, /) + + Return the total number of occurrences of *value* in *sequence*. + +sequence.index(value[, start[, stop]) + + Return the index of the first occurrence of *value* in *sequence*. + + Raises "ValueError" if *value* is not found in *sequence*. + + The *start* or *stop* arguments allow for efficient searching of + subsections of the sequence, beginning at *start* and ending at + *stop*. This is roughly equivalent to "start + + sequence[start:stop].index(value)", only without copying any data. + + Caution: + + Not all sequence types support passing the *start* and *stop* + arguments. Immutable Sequence Types @@ -12321,11 +13720,15 @@ accepts integers that meet the value restriction "0 <= x <= 255"). | "s[i] = x" | item *i* of *s* is replaced by | | | | *x* | | +--------------------------------+----------------------------------+-----------------------+ +| "del s[i]" | removes item *i* of *s* | | ++--------------------------------+----------------------------------+-----------------------+ | "s[i:j] = t" | slice of *s* from *i* to *j* is | | | | replaced by the contents of the | | | | iterable *t* | | +--------------------------------+----------------------------------+-----------------------+ -| "del s[i:j]" | same as "s[i:j] = []" | | +| "del s[i:j]" | removes the elements of "s[i:j]" | | +| | from the list (same as "s[i:j] = | | +| | []") | | +--------------------------------+----------------------------------+-----------------------+ | "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) | | | replaced by those of *t* | | @@ -12333,64 +13736,80 @@ accepts integers that meet the value restriction "0 <= x <= 255"). | "del s[i:j:k]" | removes the elements of | | | | "s[i:j:k]" from the list | | +--------------------------------+----------------------------------+-----------------------+ -| "s.append(x)" | appends *x* to the end of the | | -| | sequence (same as | | -| | "s[len(s):len(s)] = [x]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.clear()" | removes all items from *s* (same | (5) | -| | as "del s[:]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.copy()" | creates a shallow copy of *s* | (5) | -| | (same as "s[:]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.extend(t)" or "s += t" | extends *s* with the contents of | | +| "s += t" | extends *s* with the contents of | | | | *t* (for the most part the same | | | | as "s[len(s):len(s)] = t") | | +--------------------------------+----------------------------------+-----------------------+ -| "s *= n" | updates *s* with its contents | (6) | +| "s *= n" | updates *s* with its contents | (2) | | | repeated *n* times | | +--------------------------------+----------------------------------+-----------------------+ -| "s.insert(i, x)" | inserts *x* into *s* at the | | -| | index given by *i* (same as | | -| | "s[i:i] = [x]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.pop()" or "s.pop(i)" | retrieves the item at *i* and | (2) | -| | also removes it from *s* | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.remove(x)" | removes the first item from *s* | (3) | -| | where "s[i]" is equal to *x* | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.reverse()" | reverses the items of *s* in | (4) | -| | place | | -+--------------------------------+----------------------------------+-----------------------+ Notes: 1. If *k* is not equal to "1", *t* must have the same length as the slice it is replacing. -2. The optional argument *i* defaults to "-1", so that by default the - last item is removed and returned. - -3. "remove()" raises "ValueError" when *x* is not found in *s*. - -4. The "reverse()" method modifies the sequence in place for economy - of space when reversing a large sequence. To remind users that it - operates by side effect, it does not return the reversed sequence. - -5. "clear()" and "copy()" are included for consistency with the - interfaces of mutable containers that don’t support slicing - operations (such as "dict" and "set"). "copy()" is not part of the - "collections.abc.MutableSequence" ABC, but most concrete mutable - sequence classes provide it. - - Added in version 3.3: "clear()" and "copy()" methods. - -6. The value *n* is an integer, or an object implementing +2. The value *n* is an integer, or an object implementing "__index__()". Zero and negative values of *n* clear the sequence. Items in the sequence are not copied; they are referenced multiple times, as explained for "s * n" under Common Sequence Operations. +-[ Mutable Sequence Methods ]- + +Mutable sequence types also support the following methods: + +sequence.append(value, /) + + Append *value* to the end of the sequence This is equivalent to + writing "seq[len(seq):len(seq)] = [value]". + +sequence.clear() + + Added in version 3.3. + + Remove all items from *sequence*. This is equivalent to writing + "del sequence[:]". + +sequence.copy() + + Added in version 3.3. + + Create a shallow copy of *sequence*. This is equivalent to writing + "sequence[:]". + + Hint: + + The "copy()" method is not part of the "MutableSequence" "ABC", + but most concrete mutable sequence types provide it. + +sequence.extend(iterable, /) + + Extend *sequence* with the contents of *iterable*. For the most + part, this is the same as writing "seq[len(seq):len(seq)] = + iterable". + +sequence.insert(index, value, /) + + Insert *value* into *sequence* at the given *index*. This is + equivalent to writing "sequence[index:index] = [value]". + +sequence.pop(index=-1, /) + + Retrieve the item at *index* and also removes it from *sequence*. + By default, the last item in *sequence* is removed and returned. + +sequence.remove(value, /) + + Remove the first item from *sequence* where "sequence[i] == value". + + Raises "ValueError" if *value* is not found in *sequence*. + +sequence.reverse() + + Reverse the items of *sequence* in place. This method maintains + economy of space when reversing a large sequence. To remind users + that it operates by side-effect, it returns "None". + Lists ===== @@ -12399,7 +13818,7 @@ Lists are mutable sequences, typically used to store collections of homogeneous items (where the precise degree of similarity will vary by application). -class list([iterable]) +class list(iterable=(), /) Lists may be constructed in several ways: @@ -12480,7 +13899,7 @@ built-in). Tuples are also used for cases where an immutable sequence of homogeneous data is needed (such as allowing storage in a "set" or "dict" instance). -class tuple([iterable]) +class tuple(iterable=(), /) Tuples may be constructed in a number of ways: @@ -12520,8 +13939,8 @@ Ranges The "range" type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in "for" loops. -class range(stop) -class range(start, stop[, step]) +class range(stop, /) +class range(start, stop, step=1, /) The arguments to the range constructor must be integers (either built-in "int" or any object that implements the "__index__()" @@ -12649,11 +14068,15 @@ accepts integers that meet the value restriction "0 <= x <= 255"). | "s[i] = x" | item *i* of *s* is replaced by | | | | *x* | | +--------------------------------+----------------------------------+-----------------------+ +| "del s[i]" | removes item *i* of *s* | | ++--------------------------------+----------------------------------+-----------------------+ | "s[i:j] = t" | slice of *s* from *i* to *j* is | | | | replaced by the contents of the | | | | iterable *t* | | +--------------------------------+----------------------------------+-----------------------+ -| "del s[i:j]" | same as "s[i:j] = []" | | +| "del s[i:j]" | removes the elements of "s[i:j]" | | +| | from the list (same as "s[i:j] = | | +| | []") | | +--------------------------------+----------------------------------+-----------------------+ | "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) | | | replaced by those of *t* | | @@ -12661,63 +14084,79 @@ accepts integers that meet the value restriction "0 <= x <= 255"). | "del s[i:j:k]" | removes the elements of | | | | "s[i:j:k]" from the list | | +--------------------------------+----------------------------------+-----------------------+ -| "s.append(x)" | appends *x* to the end of the | | -| | sequence (same as | | -| | "s[len(s):len(s)] = [x]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.clear()" | removes all items from *s* (same | (5) | -| | as "del s[:]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.copy()" | creates a shallow copy of *s* | (5) | -| | (same as "s[:]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.extend(t)" or "s += t" | extends *s* with the contents of | | +| "s += t" | extends *s* with the contents of | | | | *t* (for the most part the same | | | | as "s[len(s):len(s)] = t") | | +--------------------------------+----------------------------------+-----------------------+ -| "s *= n" | updates *s* with its contents | (6) | +| "s *= n" | updates *s* with its contents | (2) | | | repeated *n* times | | +--------------------------------+----------------------------------+-----------------------+ -| "s.insert(i, x)" | inserts *x* into *s* at the | | -| | index given by *i* (same as | | -| | "s[i:i] = [x]") | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.pop()" or "s.pop(i)" | retrieves the item at *i* and | (2) | -| | also removes it from *s* | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.remove(x)" | removes the first item from *s* | (3) | -| | where "s[i]" is equal to *x* | | -+--------------------------------+----------------------------------+-----------------------+ -| "s.reverse()" | reverses the items of *s* in | (4) | -| | place | | -+--------------------------------+----------------------------------+-----------------------+ Notes: 1. If *k* is not equal to "1", *t* must have the same length as the slice it is replacing. -2. The optional argument *i* defaults to "-1", so that by default the - last item is removed and returned. - -3. "remove()" raises "ValueError" when *x* is not found in *s*. - -4. The "reverse()" method modifies the sequence in place for economy - of space when reversing a large sequence. To remind users that it - operates by side effect, it does not return the reversed sequence. - -5. "clear()" and "copy()" are included for consistency with the - interfaces of mutable containers that don’t support slicing - operations (such as "dict" and "set"). "copy()" is not part of the - "collections.abc.MutableSequence" ABC, but most concrete mutable - sequence classes provide it. - - Added in version 3.3: "clear()" and "copy()" methods. - -6. The value *n* is an integer, or an object implementing +2. The value *n* is an integer, or an object implementing "__index__()". Zero and negative values of *n* clear the sequence. Items in the sequence are not copied; they are referenced multiple times, as explained for "s * n" under Common Sequence Operations. + +-[ Mutable Sequence Methods ]- + +Mutable sequence types also support the following methods: + +sequence.append(value, /) + + Append *value* to the end of the sequence This is equivalent to + writing "seq[len(seq):len(seq)] = [value]". + +sequence.clear() + + Added in version 3.3. + + Remove all items from *sequence*. This is equivalent to writing + "del sequence[:]". + +sequence.copy() + + Added in version 3.3. + + Create a shallow copy of *sequence*. This is equivalent to writing + "sequence[:]". + + Hint: + + The "copy()" method is not part of the "MutableSequence" "ABC", + but most concrete mutable sequence types provide it. + +sequence.extend(iterable, /) + + Extend *sequence* with the contents of *iterable*. For the most + part, this is the same as writing "seq[len(seq):len(seq)] = + iterable". + +sequence.insert(index, value, /) + + Insert *value* into *sequence* at the given *index*. This is + equivalent to writing "sequence[index:index] = [value]". + +sequence.pop(index=-1, /) + + Retrieve the item at *index* and also removes it from *sequence*. + By default, the last item in *sequence* is removed and returned. + +sequence.remove(value, /) + + Remove the first item from *sequence* where "sequence[i] == value". + + Raises "ValueError" if *value* is not found in *sequence*. + +sequence.reverse() + + Reverse the items of *sequence* in place. This method maintains + economy of space when reversing a large sequence. To remind users + that it operates by side-effect, it returns "None". ''', 'unary': r'''Unary arithmetic and bitwise operations *************************************** diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index af2808a77da..ecec16e9005 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -137,8 +137,6 @@ __all__ = [ "UNICODE", "NOFLAG", "RegexFlag", "PatternError" ] -__version__ = "2.2.1" - @enum.global_enum @enum._simple_enum(enum.IntFlag, boundary=enum.KEEP) class RegexFlag: @@ -399,9 +397,12 @@ class Scanner: s = _parser.State() s.flags = flags for phrase, action in lexicon: + sub_pattern = _parser.parse(phrase, flags) + if sub_pattern.state.groups != 1: + raise ValueError("Cannot use capturing groups in re.Scanner") gid = s.opengroup() p.append(_parser.SubPattern(s, [ - (SUBPATTERN, (gid, 0, 0, _parser.parse(phrase, flags))), + (SUBPATTERN, (gid, 0, 0, sub_pattern)), ])) s.closegroup(gid, p[-1]) p = _parser.SubPattern(s, [(BRANCH, (None, p))]) @@ -426,3 +427,12 @@ class Scanner: append(action) i = j return result, string[i:] + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "2.2.1" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index 20dd561d1c1..c2ca8e25abe 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -375,7 +375,7 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): # less significant byte is a bit index in the chunk (just like the # CHARSET matching). - charmap = bytes(charmap) # should be hashable + charmap = charmap.take_bytes() # should be hashable comps = {} mapping = bytearray(256) block = 0 diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index 35ab7ede2a7..bd189fe0695 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -455,7 +455,6 @@ def _parse_sub(source, state, verbose, nested): items = [] itemsappend = items.append sourcematch = source.match - start = source.tell() while True: itemsappend(_parse(source, state, verbose, nested + 1, not nested and not items)) diff --git a/Lib/runpy.py b/Lib/runpy.py index ef54d3282ee..9f62d20e9a2 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -80,7 +80,6 @@ def _run_code(code, run_globals, init_globals=None, pkg_name = mod_spec.parent run_globals.update(__name__ = mod_name, __file__ = fname, - __cached__ = cached, __doc__ = None, __loader__ = loader, __package__ = pkg_name, @@ -180,7 +179,6 @@ def _run_module_as_main(mod_name, alter_argv=True): At the very least, these variables in __main__ will be overwritten: __name__ __file__ - __cached__ __loader__ __package__ """ @@ -247,7 +245,7 @@ def _get_main_module_details(error=ImportError): sys.modules[main_name] = saved_main -def _get_code_from_file(fname): +def _get_code_from_file(fname, module): # Check for a compiled file first from pkgutil import read_code code_path = os.path.abspath(fname) @@ -256,7 +254,7 @@ def _get_code_from_file(fname): if code is None: # That didn't work, so try it as normal source code with io.open_code(code_path) as f: - code = compile(f.read(), fname, 'exec') + code = compile(f.read(), fname, 'exec', module=module) return code def run_path(path_name, init_globals=None, run_name=None): @@ -283,7 +281,7 @@ def run_path(path_name, init_globals=None, run_name=None): if isinstance(importer, type(None)): # Not a valid sys.path entry, so run the code directly # execfile() doesn't help as we want to allow compiled files - code = _get_code_from_file(path_name) + code = _get_code_from_file(path_name, run_name) return _run_module_code(code, init_globals, run_name, pkg_name=pkg_name, script_name=path_name) else: diff --git a/Lib/shelve.py b/Lib/shelve.py index 1010be1e09d..9f6296667fd 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -57,7 +57,6 @@ the persistent dictionary on disk, if feasible). """ from pickle import DEFAULT_PROTOCOL, dumps, loads -from io import BytesIO import collections.abc diff --git a/Lib/shlex.py b/Lib/shlex.py index 5bf6e0d70e0..5959f52dd12 100644 --- a/Lib/shlex.py +++ b/Lib/shlex.py @@ -322,6 +322,9 @@ def quote(s): if not s: return "''" + if not isinstance(s, str): + raise TypeError(f"expected string object, got {type(s).__name__!r}") + # Use bytes.translate() for performance safe_chars = (b'%+,-./0123456789:=@' b'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' diff --git a/Lib/site.py b/Lib/site.py index f9327197159..1b7a656551b 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -111,7 +111,7 @@ def makepath(*paths): def abs_paths(): - """Set all module __file__ and __cached__ attributes to an absolute path""" + """Set __file__ to an absolute path.""" for m in set(sys.modules.values()): loader_module = None try: @@ -127,10 +127,6 @@ def abs_paths(): m.__file__ = os.path.abspath(m.__file__) except (AttributeError, OSError, TypeError): pass - try: - m.__cached__ = os.path.abspath(m.__cached__) - except (AttributeError, OSError, TypeError): - pass def removeduppaths(): @@ -333,7 +329,7 @@ def _get_path(userbase): if sys.platform == 'darwin' and sys._framework: return f'{userbase}/lib/{implementation_lower}/site-packages' - return f'{userbase}/lib/python{version[0]}.{version[1]}{abi_thread}/site-packages' + return f'{userbase}/lib/{implementation_lower}{version[0]}.{version[1]}{abi_thread}/site-packages' def getuserbase(): @@ -449,9 +445,9 @@ def setcopyright(): """Set 'copyright' and 'credits' in builtins""" builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright) builtins.credits = _sitebuiltins._Printer("credits", """\ - Thanks to CWI, CNRI, BeOpen, Zope Corporation, the Python Software - Foundation, and a cast of thousands for supporting Python - development. See www.python.org for more information.""") +Thanks to CWI, CNRI, BeOpen, Zope Corporation, the Python Software +Foundation, and a cast of thousands for supporting Python +development. See www.python.org for more information.""") files, dirs = [], [] # Not all modules are required to have a __file__ attribute. See # PEP 420 for more details. @@ -699,7 +695,7 @@ def main(): known_paths = removeduppaths() if orig_path != sys.path: # removeduppaths() might make sys.path absolute. - # fix __file__ and __cached__ of already imported modules too. + # Fix __file__ of already imported modules too. abs_paths() known_paths = venv(known_paths) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 808f0fd47e8..72093f7f8b0 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -917,7 +917,7 @@ class SMTP: The arguments are as for sendmail, except that msg is an email.message.Message object. If from_addr is None or to_addrs is None, these arguments are taken from the headers of the Message as - described in RFC 2822 (a ValueError is raised if there is more than + described in RFC 5322 (a ValueError is raised if there is more than one set of 'Resent-' headers). Regardless of the values of from_addr and to_addr, any Bcc field (or Resent-Bcc field, when the Message is a resent) of the Message object won't be transmitted. The Message @@ -931,7 +931,7 @@ class SMTP: policy. """ - # 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822 + # 'Resent-Date' is a mandatory field if the Message is resent (RFC 5322 # Section 3.6.6). In such a case, we use the 'Resent-*' fields. However, # if there is more than one 'Resent-' block there's no way to # unambiguously determine which one is the most recent in all cases, @@ -950,7 +950,7 @@ class SMTP: else: raise ValueError("message has more than one 'Resent-' header block") if from_addr is None: - # Prefer the sender field per RFC 2822:3.6.2. + # Prefer the sender field per RFC 5322 section 3.6.2. from_addr = (msg[header_prefix + 'Sender'] if (header_prefix + 'Sender') in msg else msg[header_prefix + 'From']) diff --git a/Lib/socketserver.py b/Lib/socketserver.py index 93b0a23be27..ec389457ef5 100644 --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -120,9 +120,6 @@ BaseServer: # Author of the BaseServer patch: Luke Kenneth Casson Leighton -__version__ = "0.4" - - import socket import selectors import os @@ -861,3 +858,12 @@ class DatagramRequestHandler(BaseRequestHandler): def finish(self): self.socket.sendto(self.wfile.getvalue(), self.client_address) + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "0.4" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 093b38c0001..b3746ed7573 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -143,7 +143,7 @@ def main(*args): execute(con, args.sql, suppress_errors=False, theme=theme) else: # No SQL provided; start the REPL. - with completer(): + with completer(con): console = SqliteInteractiveConsole(con, use_color=True) console.interact(banner, exitmsg="") finally: diff --git a/Lib/sqlite3/_completer.py b/Lib/sqlite3/_completer.py index b3e8c0e5f36..ba580f968bf 100644 --- a/Lib/sqlite3/_completer.py +++ b/Lib/sqlite3/_completer.py @@ -1,3 +1,4 @@ +from _sqlite3 import OperationalError from contextlib import contextmanager try: @@ -10,23 +11,84 @@ CLI_COMMANDS = ('.quit', '.help', '.version') _completion_matches = [] -def _complete(text, state): +def _complete(con, text, state): global _completion_matches if state == 0: - if text.startswith('.'): - _completion_matches = [c for c in CLI_COMMANDS if c.startswith(text)] + if text.startswith("."): + _completion_matches = [ + c + " " for c in CLI_COMMANDS if c.startswith(text) + ] else: text_upper = text.upper() - _completion_matches = [c for c in SQLITE_KEYWORDS if c.startswith(text_upper)] + _completion_matches = [ + c + " " for c in SQLITE_KEYWORDS if c.startswith(text_upper) + ] + + cursor = con.cursor() + schemata = tuple(row[1] for row + in cursor.execute("PRAGMA database_list")) + # tables, indexes, triggers, and views + # escape '_' which can appear in attached database names + select_clauses = ( + f"""\ + SELECT name || ' ' FROM \"{schema}\".sqlite_master + WHERE name LIKE REPLACE(:text, '_', '^_') || '%' ESCAPE '^'""" + for schema in schemata + ) + _completion_matches.extend( + row[0] + for row in cursor.execute( + " UNION ".join(select_clauses), {"text": text} + ) + ) + # columns + try: + select_clauses = ( + f"""\ + SELECT pti.name || ' ' FROM "{schema}".sqlite_master AS sm + JOIN pragma_table_xinfo(sm.name,'{schema}') AS pti + WHERE sm.type='table' AND + pti.name LIKE REPLACE(:text, '_', '^_') || '%' ESCAPE '^'""" + for schema in schemata + ) + _completion_matches.extend( + row[0] + for row in cursor.execute( + " UNION ".join(select_clauses), {"text": text} + ) + ) + except OperationalError: + # skip on SQLite<3.16.0 where pragma table-valued function is + # not supported yet + pass + # functions + try: + _completion_matches.extend( + row[0] for row in cursor.execute("""\ + SELECT DISTINCT UPPER(name) || '(' + FROM pragma_function_list() + WHERE name NOT IN ('->', '->>') AND + name LIKE REPLACE(:text, '_', '^_') || '%' ESCAPE '^'""", + {"text": text}, + ) + ) + except OperationalError: + # skip on SQLite<3.30.0 where function_list is not supported yet + pass + # schemata + text_lower = text.lower() + _completion_matches.extend(c for c in schemata + if c.lower().startswith(text_lower)) + _completion_matches = sorted(set(_completion_matches)) try: - return _completion_matches[state] + " " + return _completion_matches[state] except IndexError: return None @contextmanager -def completer(): +def completer(con): try: import readline except ImportError: @@ -34,8 +96,10 @@ def completer(): return old_completer = readline.get_completer() + def complete(text, state): + return _complete(con, text, state) try: - readline.set_completer(_complete) + readline.set_completer(complete) if readline.backend == "editline": # libedit uses "^I" instead of "tab" command_string = "bind ^I rl_complete" diff --git a/Lib/ssl.py b/Lib/ssl.py index 5b8762bcdc2..67a2990b281 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -13,6 +13,9 @@ Exceptions: Functions: + get_sigalgs -- return a list of all available TLS signature + algorithms (requires OpenSSL 3.4 or later) + cert_time_to_seconds -- convert time string used for certificate notBefore and notAfter functions to integer seconds past the Epoch (the time values @@ -107,11 +110,7 @@ from _ssl import ( ) from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj from _ssl import RAND_status, RAND_add, RAND_bytes -try: - from _ssl import RAND_egd -except ImportError: - # RAND_egd is not supported on some platforms - pass +from _ssl import get_sigalgs from _ssl import ( @@ -186,7 +185,7 @@ class _TLSContentType: class _TLSAlertType: """Alert types for TLSContentType.ALERT messages - See RFC 8466, section B.2 + See RFC 8446, section B.2 """ CLOSE_NOTIFY = 0 UNEXPECTED_MESSAGE = 10 @@ -935,6 +934,14 @@ class SSLObject: """Return the currently selected key agreement group name.""" return self._sslobj.group() + def client_sigalg(self): + """Return the selected client authentication signature algorithm.""" + return self._sslobj.client_sigalg() + + def server_sigalg(self): + """Return the selected server handshake signature algorithm.""" + return self._sslobj.server_sigalg() + def shared_ciphers(self): """Return a list of ciphers shared by the client during the handshake or None if this is not a valid server connection. @@ -1222,6 +1229,22 @@ class SSLSocket(socket): else: return self._sslobj.group() + @_sslcopydoc + def client_sigalg(self): + self._checkClosed() + if self._sslobj is None: + return None + else: + return self._sslobj.client_sigalg() + + @_sslcopydoc + def server_sigalg(self): + self._checkClosed() + if self._sslobj is None: + return None + else: + return self._sslobj.server_sigalg() + @_sslcopydoc def shared_ciphers(self): self._checkClosed() diff --git a/Lib/stat.py b/Lib/stat.py index 1b4ed1ebc94..ab1b25b9d63 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -200,6 +200,21 @@ FILE_ATTRIBUTE_TEMPORARY = 256 FILE_ATTRIBUTE_VIRTUAL = 65536 +# Linux STATX_ATTR constants for interpreting os.statx()'s +# "stx_attributes" and "stx_attributes_mask" members + +STATX_ATTR_COMPRESSED = 0x00000004 +STATX_ATTR_IMMUTABLE = 0x00000010 +STATX_ATTR_APPEND = 0x00000020 +STATX_ATTR_NODUMP = 0x00000040 +STATX_ATTR_ENCRYPTED = 0x00000800 +STATX_ATTR_AUTOMOUNT = 0x00001000 +STATX_ATTR_MOUNT_ROOT = 0x00002000 +STATX_ATTR_VERITY = 0x00100000 +STATX_ATTR_DAX = 0x00200000 +STATX_ATTR_WRITE_ATOMIC = 0x00400000 + + # If available, use C implementation try: from _stat import * diff --git a/Lib/statistics.py b/Lib/statistics.py index 3d805cb0739..26cf925529e 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -619,9 +619,14 @@ def stdev(data, xbar=None): if n < 2: raise StatisticsError('stdev requires at least two data points') mss = ss / (n - 1) + try: + mss_numerator = mss.numerator + mss_denominator = mss.denominator + except AttributeError: + raise ValueError('inf or nan encountered in data') if issubclass(T, Decimal): - return _decimal_sqrt_of_frac(mss.numerator, mss.denominator) - return _float_sqrt_of_frac(mss.numerator, mss.denominator) + return _decimal_sqrt_of_frac(mss_numerator, mss_denominator) + return _float_sqrt_of_frac(mss_numerator, mss_denominator) def pstdev(data, mu=None): @@ -637,9 +642,14 @@ def pstdev(data, mu=None): if n < 1: raise StatisticsError('pstdev requires at least one data point') mss = ss / n + try: + mss_numerator = mss.numerator + mss_denominator = mss.denominator + except AttributeError: + raise ValueError('inf or nan encountered in data') if issubclass(T, Decimal): - return _decimal_sqrt_of_frac(mss.numerator, mss.denominator) - return _float_sqrt_of_frac(mss.numerator, mss.denominator) + return _decimal_sqrt_of_frac(mss_numerator, mss_denominator) + return _float_sqrt_of_frac(mss_numerator, mss_denominator) ## Statistics for relations between two inputs ############################# diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 79251bd5310..17333d8c022 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1235,7 +1235,7 @@ class Popen: finally: self._communication_started = True try: - sts = self.wait(timeout=self._remaining_time(endtime)) + self.wait(timeout=self._remaining_time(endtime)) except TimeoutExpired as exc: exc.timeout = timeout raise @@ -1613,6 +1613,10 @@ class Popen: fh.close() + def _writerthread(self, input): + self._stdin_write(input) + + def _communicate(self, input, endtime, orig_timeout): # Start reader threads feeding into a list hanging off of this # object, unless they've already been started. @@ -1631,8 +1635,23 @@ class Popen: self.stderr_thread.daemon = True self.stderr_thread.start() - if self.stdin: - self._stdin_write(input) + # Start writer thread to send input to stdin, unless already + # started. The thread writes input and closes stdin when done, + # or continues in the background on timeout. + if self.stdin and not hasattr(self, "_stdin_thread"): + self._stdin_thread = \ + threading.Thread(target=self._writerthread, + args=(input,)) + self._stdin_thread.daemon = True + self._stdin_thread.start() + + # Wait for the writer thread, or time out. If we time out, the + # thread remains writing and the fd left open in case the user + # calls communicate again. + if hasattr(self, "_stdin_thread"): + self._stdin_thread.join(self._remaining_time(endtime)) + if self._stdin_thread.is_alive(): + raise TimeoutExpired(self.args, orig_timeout) # Wait for the reader threads, or time out. If we time out, the # threads remain reading and the fds left open in case the user @@ -2077,6 +2096,10 @@ class Popen: self.stdin.flush() except BrokenPipeError: pass # communicate() must ignore BrokenPipeError. + except ValueError: + # ignore ValueError: I/O operation on closed file. + if not self.stdin.closed: + raise if not input: try: self.stdin.close() @@ -2102,10 +2125,13 @@ class Popen: self._save_input(input) if self._input: - input_view = memoryview(self._input) + if not isinstance(self._input, memoryview): + input_view = memoryview(self._input) + else: + input_view = self._input.cast("b") # byte input required with _PopenSelector() as selector: - if self.stdin and input: + if self.stdin and not self.stdin.closed and self._input: selector.register(self.stdin, selectors.EVENT_WRITE) if self.stdout and not self.stdout.closed: selector.register(self.stdout, selectors.EVENT_READ) @@ -2138,7 +2164,7 @@ class Popen: selector.unregister(key.fileobj) key.fileobj.close() else: - if self._input_offset >= len(self._input): + if self._input_offset >= len(input_view): selector.unregister(key.fileobj) key.fileobj.close() elif key.fileobj in (self.stdout, self.stderr): diff --git a/Lib/symtable.py b/Lib/symtable.py index 77475c3ffd9..4c832e68f94 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -17,13 +17,13 @@ from enum import StrEnum __all__ = ["symtable", "SymbolTableType", "SymbolTable", "Class", "Function", "Symbol"] -def symtable(code, filename, compile_type): +def symtable(code, filename, compile_type, *, module=None): """ Return the toplevel *SymbolTable* for the source code. *filename* is the name of the file with the code and *compile_type* is the *compile()* mode argument. """ - top = _symtable.symtable(code, filename, compile_type) + top = _symtable.symtable(code, filename, compile_type, module=module) return _newSymbolTable(top, filename) class SymbolTableFactory: diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py index c583b74ce54..8ff9c99435b 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py @@ -645,18 +645,25 @@ def get_platform(): isn't particularly important. Examples of returned values: - linux-i586 - linux-alpha (?) + linux-x86_64 + linux-aarch64 solaris-2.6-sun4u - Windows will return one of: - win-amd64 (64-bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win-arm64 (64-bit Windows on ARM64 (aka AArch64) - win32 (all others - specifically, sys.platform is returned) - For other non-POSIX platforms, currently just returns 'sys.platform'. + Windows: - """ + - win-amd64 (64-bit Windows on AMD64, aka x86_64, Intel64, and EM64T) + - win-arm64 (64-bit Windows on ARM64, aka AArch64) + - win32 (all others - specifically, sys.platform is returned) + + POSIX based OS: + + - linux-x86_64 + - macosx-15.5-arm64 + - macosx-26.0-universal2 (macOS on Apple Silicon or Intel) + - android-24-arm64_v8a + + For other non-POSIX platforms, currently just returns :data:`sys.platform`.""" if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' diff --git a/Lib/sysconfig/__main__.py b/Lib/sysconfig/__main__.py index bc2197cfe79..0cf0cf4dbb9 100644 --- a/Lib/sysconfig/__main__.py +++ b/Lib/sysconfig/__main__.py @@ -21,8 +21,9 @@ from sysconfig import ( # Regexes needed for parsing Makefile (and similar syntaxes, # like old-style Setup files). _variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)" -_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)" -_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}" +_findvar_rx = (r"\$(\([A-Za-z][A-Za-z0-9_]*\)" + r"|\{[A-Za-z][A-Za-z0-9_]*\}" + r"|\$?)") def _parse_makefile(filename, vars=None, keep_unresolved=True): @@ -49,26 +50,7 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True): m = re.match(_variable_rx, line) if m: n, v = m.group(1, 2) - v = v.strip() - # `$$' is a literal `$' in make - tmpv = v.replace('$$', '') - - if "$" in tmpv: - notdone[n] = v - else: - try: - if n in _ALWAYS_STR: - raise ValueError - - v = int(v) - except ValueError: - # insert literal `$' - done[n] = v.replace('$$', '$') - else: - done[n] = v - - # do variable interpolation here - variables = list(notdone.keys()) + notdone[n] = v.strip() # Variables with a 'PY_' prefix in the makefile. These need to # be made available without that prefix through sysconfig. @@ -76,72 +58,64 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True): # if the expansion uses the name without a prefix. renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') - while len(variables) > 0: - for name in tuple(variables): - value = notdone[name] - m1 = re.search(_findvar1_rx, value) - m2 = re.search(_findvar2_rx, value) - if m1 and m2: - m = m1 if m1.start() < m2.start() else m2 - else: - m = m1 if m1 else m2 - if m is not None: - n = m.group(1) - found = True - if n in done: - item = str(done[n]) - elif n in notdone: - # get it on a subsequent round - found = False - elif n in os.environ: - # do it like make: fall back to environment - item = os.environ[n] - - elif n in renamed_variables: - if (name.startswith('PY_') and - name[3:] in renamed_variables): - item = "" - - elif 'PY_' + n in notdone: - found = False - - else: - item = str(done['PY_' + n]) - - else: - done[n] = item = "" - - if found: - after = value[m.end():] - value = value[:m.start()] + item + after - if "$" in after: - notdone[name] = value - else: - try: - if name in _ALWAYS_STR: - raise ValueError - value = int(value) - except ValueError: - done[name] = value.strip() - else: - done[name] = value - variables.remove(name) - - if name.startswith('PY_') \ - and name[3:] in renamed_variables: - - name = name[3:] - if name not in done: - done[name] = value - - else: - # Adds unresolved variables to the done dict. - # This is disabled when called from distutils.sysconfig + def resolve_var(name): + def repl(m): + n = m[1] + if n == '$': + return '$' + elif n == '': + # bogus variable reference (e.g. "prefix=$/opt/python") if keep_unresolved: - done[name] = value - # bogus variable reference (e.g. "prefix=$/opt/python"); - # just drop it since we can't deal - variables.remove(name) + return m[0] + raise ValueError + elif n[0] == '(' and n[-1] == ')': + n = n[1:-1] + elif n[0] == '{' and n[-1] == '}': + n = n[1:-1] + + if n in done: + return str(done[n]) + elif n in notdone: + return str(resolve_var(n)) + elif n in os.environ: + # do it like make: fall back to environment + return os.environ[n] + elif n in renamed_variables: + if name.startswith('PY_') and name[3:] in renamed_variables: + return "" + n = 'PY_' + n + if n in notdone: + return str(resolve_var(n)) + else: + assert n not in done + return "" + else: + done[n] = "" + return "" + + assert name not in done + done[name] = "" + try: + value = re.sub(_findvar_rx, repl, notdone[name]) + except ValueError: + del done[name] + return "" + value = value.strip() + if name not in _ALWAYS_STR: + try: + value = int(value) + except ValueError: + pass + done[name] = value + if name.startswith('PY_') and name[3:] in renamed_variables: + name = name[3:] + if name not in done: + done[name] = value + return value + + for n in notdone: + if n not in done: + resolve_var(n) # strip spurious spaces for k, v in done.items(): diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index c0097351b26..272e8e33e0c 100644 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -16,8 +16,6 @@ releases; such changes may not be backward compatible. # XXX The API needs to undergo changes however; the current code is too # XXX script-like. This will be addressed later. -__version__ = "6" - import os import sys import tokenize @@ -334,5 +332,14 @@ def _process_tokens(tokens): raise NannyNag(start[0], msg, line) +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "6" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + if __name__ == '__main__': main() diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 7aa4a032b63..7db3a40c9b3 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2718,7 +2718,13 @@ class TarFile(object): if os.path.lexists(targetpath): # Avoid FileExistsError on following os.symlink. os.unlink(targetpath) - os.symlink(tarinfo.linkname, targetpath) + link_target = tarinfo.linkname + if os.name == "nt": + # gh-57911: Posix-flavoured forward-slash path separators in + # symlink targets aren't acknowledged by Windows, resulting + # in corrupted links. + link_target = link_target.replace("/", os.path.sep) + os.symlink(link_target, targetpath) return else: if os.path.exists(tarinfo._link_target): diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 53d14ff5c67..2bc61662459 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -691,7 +691,7 @@ else: fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type) try: _os.unlink(name) - except BaseException as e: + except BaseException: _os.close(fd) raise return fd diff --git a/Lib/test/_test_atexit.py b/Lib/test/_test_atexit.py index f618c1fcbca..490b0686a0c 100644 --- a/Lib/test/_test_atexit.py +++ b/Lib/test/_test_atexit.py @@ -135,6 +135,19 @@ class GeneralTest(unittest.TestCase): finally: atexit.unregister(func) + def test_eq_unregister_clear(self): + # Issue #112127: callback's __eq__ may call unregister or _clear + class Evil: + def __eq__(self, other): + action(other) + return NotImplemented + + for action in atexit.unregister, lambda o: atexit._clear(): + with self.subTest(action=action): + atexit.register(lambda: None) + atexit.unregister(Evil()) + atexit._clear() + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index a1c30bcfd51..d03eb1dfb25 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -39,6 +39,7 @@ from test.support import script_helper from test.support import socket_helper from test.support import threading_helper from test.support import warnings_helper +from test.support import subTests from test.support.script_helper import assert_python_failure, assert_python_ok # Skip tests if _multiprocessing wasn't built. @@ -1204,7 +1205,7 @@ class _TestQueue(BaseTestCase): @classmethod def _test_get(cls, queue, child_can_start, parent_can_continue): child_can_start.wait() - #queue.put(1) + queue.put(1) queue.put(2) queue.put(3) queue.put(4) @@ -1229,15 +1230,16 @@ class _TestQueue(BaseTestCase): child_can_start.set() parent_can_continue.wait() - time.sleep(DELTA) + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if not queue_empty(queue): + break self.assertEqual(queue_empty(queue), False) - # Hangs unexpectedly, remove for now - #self.assertEqual(queue.get(), 1) + self.assertEqual(queue.get_nowait(), 1) self.assertEqual(queue.get(True, None), 2) self.assertEqual(queue.get(True), 3) self.assertEqual(queue.get(timeout=1), 4) - self.assertEqual(queue.get_nowait(), 5) + self.assertEqual(queue.get(), 5) self.assertEqual(queue_empty(queue), True) @@ -4382,6 +4384,19 @@ class _TestSharedCTypes(BaseTestCase): self.assertEqual(bar.z, 2 ** 33) +def resource_tracker_format_subtests(func): + """Run given test using both resource tracker communication formats""" + def _inner(self, *args, **kwargs): + tracker = resource_tracker._resource_tracker + for use_simple_format in False, True: + with ( + self.subTest(use_simple_format=use_simple_format), + unittest.mock.patch.object( + tracker, '_use_simple_format', use_simple_format) + ): + func(self, *args, **kwargs) + return _inner + @unittest.skipUnless(HAS_SHMEM, "requires multiprocessing.shared_memory") @hashlib_helper.requires_hashdigest('sha256') class _TestSharedMemory(BaseTestCase): @@ -4661,6 +4676,7 @@ class _TestSharedMemory(BaseTestCase): smm.shutdown() @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") + @resource_tracker_format_subtests def test_shared_memory_SharedMemoryManager_reuses_resource_tracker(self): # bpo-36867: test that a SharedMemoryManager uses the # same resource_tracker process as its parent. @@ -4912,6 +4928,7 @@ class _TestSharedMemory(BaseTestCase): "shared_memory objects to clean up at shutdown", err) @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") + @resource_tracker_format_subtests def test_shared_memory_untracking(self): # gh-82300: When a separate Python process accesses shared memory # with track=False, it must not cause the memory to be deleted @@ -4939,6 +4956,7 @@ class _TestSharedMemory(BaseTestCase): mem.close() @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") + @resource_tracker_format_subtests def test_shared_memory_tracking(self): # gh-82300: When a separate Python process accesses shared memory # with track=True, it must cause the memory to be deleted when @@ -5278,6 +5296,23 @@ class TestInvalidHandle(unittest.TestCase): multiprocessing.connection.Connection, -1) +# +# Regression tests for BaseProcess kwargs handling +# + +class TestBaseProcessKwargs(unittest.TestCase): + def test_default_kwargs_not_shared_between_instances(self): + # Creating multiple Process instances without passing kwargs + # must create independent empty dicts (no shared state). + p1 = multiprocessing.Process(target=lambda: None) + p2 = multiprocessing.Process(target=lambda: None) + self.assertIsInstance(p1._kwargs, dict) + self.assertIsInstance(p2._kwargs, dict) + self.assertIsNot(p1._kwargs, p2._kwargs) + # Mutating one should not affect the other + p1._kwargs['x'] = 1 + self.assertNotIn('x', p2._kwargs) + @hashlib_helper.requires_hashdigest('sha256') class OtherTest(unittest.TestCase): @@ -6939,28 +6974,13 @@ class _TestSpawnedSysPath(BaseTestCase): if multiprocessing.get_start_method() != "forkserver": self.skipTest("forkserver specific test") - # Create a test module in the temporary directory on the child's path - # TODO: This can all be simplified once gh-126631 is fixed and we can - # use __main__ instead of a module. - dirname = os.path.join(self._temp_dir, 'preloaded_module') - init_name = os.path.join(dirname, '__init__.py') - os.mkdir(dirname) - with open(init_name, "w") as f: - cmd = '''if 1: - import sys - print('stderr', end='', file=sys.stderr) - print('stdout', end='', file=sys.stdout) - ''' - f.write(cmd) - name = os.path.join(os.path.dirname(__file__), 'mp_preload_flush.py') - env = {'PYTHONPATH': self._temp_dir} - _, out, err = test.support.script_helper.assert_python_ok(name, **env) + _, out, err = test.support.script_helper.assert_python_ok(name) # Check stderr first, as it is more likely to be useful to see in the # event of a failure. - self.assertEqual(err.decode().rstrip(), 'stderr') - self.assertEqual(out.decode().rstrip(), 'stdout') + self.assertEqual(err.decode().rstrip(), '__main____mp_main__') + self.assertEqual(out.decode().rstrip(), '__main____mp_main__') class MiscTestCase(unittest.TestCase): @@ -7028,6 +7048,18 @@ class MiscTestCase(unittest.TestCase): self.assertEqual(q.get_nowait(), "done") close_queue(q) + def test_preload_main(self): + # gh-126631: Check that __main__ can be pre-loaded + if multiprocessing.get_start_method() != "forkserver": + self.skipTest("forkserver specific test") + + name = os.path.join(os.path.dirname(__file__), 'mp_preload_main.py') + _, out, err = test.support.script_helper.assert_python_ok(name) + self.assertEqual(err, b'') + + # The trailing empty string comes from split() on output ending with \n + out = out.decode().split("\n") + self.assertEqual(out, ['__main__', '__mp_main__', 'f', 'f', '']) # # Mixins @@ -7335,3 +7367,51 @@ class ForkInThreads(unittest.TestCase): res = assert_python_failure("-c", code, PYTHONWARNINGS='error') self.assertIn(b'DeprecationWarning', res.err) self.assertIn(b'is multi-threaded, use of forkpty() may lead to deadlocks in the child', res.err) + +@unittest.skipUnless(HAS_SHMEM, "requires multiprocessing.shared_memory") +class TestSharedMemoryNames(unittest.TestCase): + @subTests('use_simple_format', (True, False)) + def test_that_shared_memory_name_with_colons_has_no_resource_tracker_errors( + self, use_simple_format): + # Test script that creates and cleans up shared memory with colon in name + test_script = textwrap.dedent(""" + import sys + from multiprocessing import shared_memory + from multiprocessing import resource_tracker + import time + + resource_tracker._resource_tracker._use_simple_format = %s + + # Test various patterns of colons in names + test_names = [ + "a:b", + "a:b:c", + "test:name:with:many:colons", + ":starts:with:colon", + "ends:with:colon:", + "::double::colons::", + "name\\nwithnewline", + "name-with-trailing-newline\\n", + "\\nname-starts-with-newline", + "colons:and\\nnewlines:mix", + "multi\\nline\\nname", + ] + + for name in test_names: + try: + shm = shared_memory.SharedMemory(create=True, size=100, name=name) + shm.buf[:5] = b'hello' # Write something to the shared memory + shm.close() + shm.unlink() + + except Exception as e: + print(f"Error with name '{name}': {e}", file=sys.stderr) + sys.exit(1) + + print("SUCCESS") + """ % use_simple_format) + + rc, out, err = assert_python_ok("-c", test_script) + self.assertIn(b"SUCCESS", out) + self.assertNotIn(b"traceback", err.lower(), err) + self.assertNotIn(b"resource_tracker.py", err, err) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 6884ac0dbe6..a893932169a 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -8,6 +8,8 @@ module with arguments identifying each test. import contextlib import os import sys +import unittest.mock +from test.support import swap_item class TestHook: @@ -672,6 +674,84 @@ def test_sys_remote_exec(): assertEqual(event_script_path, tmp_file.name) assertEqual(remote_event_script_path, tmp_file.name) +def test_import_module(): + import importlib + + with TestHook() as hook: + importlib.import_module("importlib") # already imported, won't get logged + importlib.import_module("email") # standard library module + importlib.import_module("pythoninfo") # random module + importlib.import_module(".audit_test_data.submodule", "test") # relative import + importlib.import_module("test.audit_test_data.submodule2") # absolute import + importlib.import_module("_testcapi") # extension module + + actual = [a for e, a in hook.seen if e == "import"] + assertSequenceEqual( + [ + ("email", None, sys.path, sys.meta_path, sys.path_hooks), + ("pythoninfo", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data.submodule", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data.submodule2", None, sys.path, sys.meta_path, sys.path_hooks), + ("_testcapi", None, sys.path, sys.meta_path, sys.path_hooks), + ("_testcapi", unittest.mock.ANY, None, None, None) + ], + actual, + ) + +def test_builtin__import__(): + import importlib # noqa: F401 + + with TestHook() as hook: + __import__("importlib") + __import__("email") + __import__("pythoninfo") + __import__("audit_test_data.submodule", level=1, globals={"__package__": "test"}) + __import__("test.audit_test_data.submodule2") + __import__("_testcapi") + + actual = [a for e, a in hook.seen if e == "import"] + assertSequenceEqual( + [ + ("email", None, sys.path, sys.meta_path, sys.path_hooks), + ("pythoninfo", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data.submodule", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data.submodule2", None, sys.path, sys.meta_path, sys.path_hooks), + ("_testcapi", None, sys.path, sys.meta_path, sys.path_hooks), + ("_testcapi", unittest.mock.ANY, None, None, None) + ], + actual, + ) + +def test_import_statement(): + import importlib # noqa: F401 + # Set __package__ so relative imports work + with swap_item(globals(), "__package__", "test"): + with TestHook() as hook: + import importlib # noqa: F401 + import email # noqa: F401 + import pythoninfo # noqa: F401 + from .audit_test_data import submodule # noqa: F401 + import test.audit_test_data.submodule2 # noqa: F401 + import _testcapi # noqa: F401 + + actual = [a for e, a in hook.seen if e == "import"] + # Import statement ordering is different because the package is + # loaded first and then the submodule + assertSequenceEqual( + [ + ("email", None, sys.path, sys.meta_path, sys.path_hooks), + ("pythoninfo", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data.submodule", None, sys.path, sys.meta_path, sys.path_hooks), + ("test.audit_test_data.submodule2", None, sys.path, sys.meta_path, sys.path_hooks), + ("_testcapi", None, sys.path, sys.meta_path, sys.path_hooks), + ("_testcapi", unittest.mock.ANY, None, None, None) + ], + actual, + ) + if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/audit_test_data/__init__.py b/Lib/test/audit_test_data/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Lib/test/audit_test_data/submodule.py b/Lib/test/audit_test_data/submodule.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Lib/test/audit_test_data/submodule2.py b/Lib/test/audit_test_data/submodule2.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index f28b6a24569..4729708efd3 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1612,12 +1612,17 @@ test_Py_ssize_t_converter a: Py_ssize_t = 12 b: Py_ssize_t(accept={int}) = 34 c: Py_ssize_t(accept={int, NoneType}) = 56 + d: Py_ssize_t(accept={int}, allow_negative=False) = 78 + e: Py_ssize_t(accept={int, NoneType}, allow_negative=False) = 90 + f: Py_ssize_t(accept={int}, allow_negative=True) = -12 + g: Py_ssize_t(accept={int, NoneType}, allow_negative=True) = -34 / [clinic start generated code]*/ PyDoc_STRVAR(test_Py_ssize_t_converter__doc__, -"test_Py_ssize_t_converter($module, a=12, b=34, c=56, /)\n" +"test_Py_ssize_t_converter($module, a=12, b=34, c=56, d=78, e=90, f=-12,\n" +" g=-34, /)\n" "--\n" "\n"); @@ -1626,7 +1631,8 @@ PyDoc_STRVAR(test_Py_ssize_t_converter__doc__, static PyObject * test_Py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b, - Py_ssize_t c); + Py_ssize_t c, Py_ssize_t d, Py_ssize_t e, + Py_ssize_t f, Py_ssize_t g); static PyObject * test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) @@ -1635,8 +1641,12 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na Py_ssize_t a = 12; Py_ssize_t b = 34; Py_ssize_t c = 56; + Py_ssize_t d = 78; + Py_ssize_t e = 90; + Py_ssize_t f = -12; + Py_ssize_t g = -34; - if (!_PyArg_CheckPositional("test_Py_ssize_t_converter", nargs, 0, 3)) { + if (!_PyArg_CheckPositional("test_Py_ssize_t_converter", nargs, 0, 7)) { goto exit; } if (nargs < 1) { @@ -1675,8 +1685,55 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na if (!_Py_convert_optional_to_ssize_t(args[2], &c)) { goto exit; } + if (nargs < 4) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[3]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + d = ival; + if (d < 0) { + PyErr_SetString(PyExc_ValueError, + "d cannot be negative"); + goto exit; + } + } + if (nargs < 5) { + goto skip_optional; + } + if (!_Py_convert_optional_to_non_negative_ssize_t(args[4], &e)) { + goto exit; + } + if (nargs < 6) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[5]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + f = ival; + } + if (nargs < 7) { + goto skip_optional; + } + if (!_Py_convert_optional_to_ssize_t(args[6], &g)) { + goto exit; + } skip_optional: - return_value = test_Py_ssize_t_converter_impl(module, a, b, c); + return_value = test_Py_ssize_t_converter_impl(module, a, b, c, d, e, f, g); exit: return return_value; @@ -1684,8 +1741,9 @@ exit: static PyObject * test_Py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b, - Py_ssize_t c) -/*[clinic end generated code: output=48214bc3d01f4dd7 input=3855f184bb3f299d]*/ + Py_ssize_t c, Py_ssize_t d, Py_ssize_t e, + Py_ssize_t f, Py_ssize_t g) +/*[clinic end generated code: output=4ae0a56a1447fba9 input=a25bac8ecf2890aa]*/ /*[clinic input] @@ -4283,7 +4341,7 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg goto exit; } a = args[0]; - __clinic_args = _PyTuple_FromArray(args + 1, nargs - 1); + __clinic_args = PyTuple_FromArray(args + 1, nargs - 1); if (__clinic_args == NULL) { goto exit; } @@ -4298,7 +4356,7 @@ exit: static PyObject * test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args) -/*[clinic end generated code: output=0c11c475e240869e input=2c49a482f68545c0]*/ +/*[clinic end generated code: output=83cbe9554d04add2 input=2c49a482f68545c0]*/ /*[clinic input] test_vararg @@ -4363,7 +4421,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject } a = fastargs[0]; __clinic_args = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -4379,7 +4437,7 @@ exit: static PyObject * test_vararg_impl(PyObject *module, PyObject *a, PyObject *args) -/*[clinic end generated code: output=17ba625cdd0369c1 input=7448995636d9186a]*/ +/*[clinic end generated code: output=d773f7b54e61f73a input=7448995636d9186a]*/ /*[clinic input] test_vararg_with_default @@ -4456,7 +4514,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar } skip_optional_kwonly: __clinic_args = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -4473,7 +4531,7 @@ exit: static PyObject * test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args, int b) -/*[clinic end generated code: output=3f2b06ab08d5d0be input=3a0f9f557ce1f712]*/ +/*[clinic end generated code: output=d25e56802c197344 input=3a0f9f557ce1f712]*/ /*[clinic input] test_vararg_with_only_defaults @@ -4554,7 +4612,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize } c = fastargs[1]; skip_optional_kwonly: - __clinic_args = _PyTuple_FromArray(args, nargs); + __clinic_args = PyTuple_FromArray(args, nargs); if (__clinic_args == NULL) { goto exit; } @@ -4570,7 +4628,7 @@ exit: static PyObject * test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b, PyObject *c) -/*[clinic end generated code: output=f46666f0b1bf86b9 input=6983e66817f82924]*/ +/*[clinic end generated code: output=7366943a7df42e05 input=6983e66817f82924]*/ /*[clinic input] test_paramname_module diff --git a/Lib/test/data/NormalizationTest-3.2.0.txt b/Lib/test/data/NormalizationTest-3.2.0.txt new file mode 100644 index 00000000000..d1c7b5165e3 --- /dev/null +++ b/Lib/test/data/NormalizationTest-3.2.0.txt @@ -0,0 +1,17035 @@ +# NormalizationTest-3.2.0.txt +# Date: 2002-03-19,23:31:18 GMT [MD] +# +# Normalization Test Suite +# Format: +# +# Columns (c1, c2,...) are separated by semicolons +# Comments are indicated with hash marks +# +# CONFORMANCE: +# 1. The following invariants must be true for all conformant implementations +# +# NFC +# c2 == NFC(c1) == NFC(c2) == NFC(c3) +# c4 == NFC(c4) == NFC(c5) +# +# NFD +# c3 == NFD(c1) == NFD(c2) == NFD(c3) +# c5 == NFD(c4) == NFD(c5) +# +# NFKC +# c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) +# +# NFKD +# c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) +# +# 2. For every assigned Unicode 3.1.0 code point X that is not specifically +# listed in Part 1, the following invariants must be true for all conformant +# implementations: +# +# X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X) +# +@Part0 # Specific cases +# +1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +1E0A 0323;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (Ḋ◌̣; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING DOT BELOW +1E0C 0307;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (Ḍ◌̇; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING DOT ABOVE +0044 0307 0323;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (D◌̇◌̣; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING DOT ABOVE, COMBINING DOT BELOW +0044 0323 0307;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING DOT BELOW, COMBINING DOT ABOVE +1E0A 031B;1E0A 031B;0044 031B 0307;1E0A 031B;0044 031B 0307; # (Ḋ◌̛; Ḋ◌̛; D◌̛◌̇; Ḋ◌̛; D◌̛◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING HORN +1E0C 031B;1E0C 031B;0044 031B 0323;1E0C 031B;0044 031B 0323; # (Ḍ◌̛; Ḍ◌̛; D◌̛◌̣; Ḍ◌̛; D◌̛◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING HORN +1E0A 031B 0323;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (Ḋ◌̛◌̣; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING HORN, COMBINING DOT BELOW +1E0C 031B 0307;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (Ḍ◌̛◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING HORN, COMBINING DOT ABOVE +0044 031B 0307 0323;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (D◌̛◌̇◌̣; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT ABOVE, COMBINING DOT BELOW +0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE +00C8;00C8;0045 0300;00C8;0045 0300; # (È; È; E◌̀; È; E◌̀; ) LATIN CAPITAL LETTER E WITH GRAVE +0112;0112;0045 0304;0112;0045 0304; # (Ē; Ē; E◌̄; Ē; E◌̄; ) LATIN CAPITAL LETTER E WITH MACRON +0045 0300;00C8;0045 0300;00C8;0045 0300; # (E◌̀; È; E◌̀; È; E◌̀; ) LATIN CAPITAL LETTER E, COMBINING GRAVE ACCENT +0045 0304;0112;0045 0304;0112;0045 0304; # (E◌̄; Ē; E◌̄; Ē; E◌̄; ) LATIN CAPITAL LETTER E, COMBINING MACRON +1E14;1E14;0045 0304 0300;1E14;0045 0304 0300; # (Ḕ; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +0112 0300;1E14;0045 0304 0300;1E14;0045 0304 0300; # (Ē◌̀; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E WITH MACRON, COMBINING GRAVE ACCENT +1E14 0304;1E14 0304;0045 0304 0300 0304;1E14 0304;0045 0304 0300 0304; # (Ḕ◌̄; Ḕ◌̄; E◌̄◌̀◌̄; Ḕ◌̄; E◌̄◌̀◌̄; ) LATIN CAPITAL LETTER E WITH MACRON AND GRAVE, COMBINING MACRON +0045 0304 0300;1E14;0045 0304 0300;1E14;0045 0304 0300; # (E◌̄◌̀; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E, COMBINING MACRON, COMBINING GRAVE ACCENT +0045 0300 0304;00C8 0304;0045 0300 0304;00C8 0304;0045 0300 0304; # (E◌̀◌̄; È◌̄; E◌̀◌̄; È◌̄; E◌̀◌̄; ) LATIN CAPITAL LETTER E, COMBINING GRAVE ACCENT, COMBINING MACRON +05B8 05B9 05B1 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F; # (◌ָ◌ֹ◌ֱ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ) HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL, HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA, HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA +0592 05B7 05BC 05A5 05B0 05C0 05C4 05AD;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4; # (◌֒◌ַ◌ּ◌֥◌ְ׀◌ׄ◌֭; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ) HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ, HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ, HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI +# +@Part1 # Character by character test +# All characters not explicitly occurring in c1 of Part 1 have identical NFC, D, KC, KD forms. +# +00A0;00A0;00A0;0020;0020; # ( ;  ;  ; ; ; ) NO-BREAK SPACE +00A8;00A8;00A8;0020 0308;0020 0308; # (¨; ¨; ¨; ◌̈; ◌̈; ) DIAERESIS +00AA;00AA;00AA;0061;0061; # (ª; ª; ª; a; a; ) FEMININE ORDINAL INDICATOR +00AF;00AF;00AF;0020 0304;0020 0304; # (¯; ¯; ¯; ◌̄; ◌̄; ) MACRON +00B2;00B2;00B2;0032;0032; # (²; ²; ²; 2; 2; ) SUPERSCRIPT TWO +00B3;00B3;00B3;0033;0033; # (³; ³; ³; 3; 3; ) SUPERSCRIPT THREE +00B4;00B4;00B4;0020 0301;0020 0301; # (´; ´; ´; ◌́; ◌́; ) ACUTE ACCENT +00B5;00B5;00B5;03BC;03BC; # (µ; µ; µ; μ; μ; ) MICRO SIGN +00B8;00B8;00B8;0020 0327;0020 0327; # (¸; ¸; ¸; ◌̧; ◌̧; ) CEDILLA +00B9;00B9;00B9;0031;0031; # (¹; ¹; ¹; 1; 1; ) SUPERSCRIPT ONE +00BA;00BA;00BA;006F;006F; # (º; º; º; o; o; ) MASCULINE ORDINAL INDICATOR +00BC;00BC;00BC;0031 2044 0034;0031 2044 0034; # (¼; ¼; ¼; 1⁄4; 1⁄4; ) VULGAR FRACTION ONE QUARTER +00BD;00BD;00BD;0031 2044 0032;0031 2044 0032; # (½; ½; ½; 1⁄2; 1⁄2; ) VULGAR FRACTION ONE HALF +00BE;00BE;00BE;0033 2044 0034;0033 2044 0034; # (¾; ¾; ¾; 3⁄4; 3⁄4; ) VULGAR FRACTION THREE QUARTERS +00C0;00C0;0041 0300;00C0;0041 0300; # (À; À; A◌̀; À; A◌̀; ) LATIN CAPITAL LETTER A WITH GRAVE +00C1;00C1;0041 0301;00C1;0041 0301; # (Á; Á; A◌́; Á; A◌́; ) LATIN CAPITAL LETTER A WITH ACUTE +00C2;00C2;0041 0302;00C2;0041 0302; # (Â; Â; A◌̂; Â; A◌̂; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C3;00C3;0041 0303;00C3;0041 0303; # (Ã; Ã; A◌̃; Ã; A◌̃; ) LATIN CAPITAL LETTER A WITH TILDE +00C4;00C4;0041 0308;00C4;0041 0308; # (Ä; Ä; A◌̈; Ä; A◌̈; ) LATIN CAPITAL LETTER A WITH DIAERESIS +00C5;00C5;0041 030A;00C5;0041 030A; # (Å; Å; A◌̊; Å; A◌̊; ) LATIN CAPITAL LETTER A WITH RING ABOVE +00C7;00C7;0043 0327;00C7;0043 0327; # (Ç; Ç; C◌̧; Ç; C◌̧; ) LATIN CAPITAL LETTER C WITH CEDILLA +00C8;00C8;0045 0300;00C8;0045 0300; # (È; È; E◌̀; È; E◌̀; ) LATIN CAPITAL LETTER E WITH GRAVE +00C9;00C9;0045 0301;00C9;0045 0301; # (É; É; E◌́; É; E◌́; ) LATIN CAPITAL LETTER E WITH ACUTE +00CA;00CA;0045 0302;00CA;0045 0302; # (Ê; Ê; E◌̂; Ê; E◌̂; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB;00CB;0045 0308;00CB;0045 0308; # (Ë; Ë; E◌̈; Ë; E◌̈; ) LATIN CAPITAL LETTER E WITH DIAERESIS +00CC;00CC;0049 0300;00CC;0049 0300; # (Ì; Ì; I◌̀; Ì; I◌̀; ) LATIN CAPITAL LETTER I WITH GRAVE +00CD;00CD;0049 0301;00CD;0049 0301; # (Í; Í; I◌́; Í; I◌́; ) LATIN CAPITAL LETTER I WITH ACUTE +00CE;00CE;0049 0302;00CE;0049 0302; # (Î; Î; I◌̂; Î; I◌̂; ) LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF;00CF;0049 0308;00CF;0049 0308; # (Ï; Ï; I◌̈; Ï; I◌̈; ) LATIN CAPITAL LETTER I WITH DIAERESIS +00D1;00D1;004E 0303;00D1;004E 0303; # (Ñ; Ñ; N◌̃; Ñ; N◌̃; ) LATIN CAPITAL LETTER N WITH TILDE +00D2;00D2;004F 0300;00D2;004F 0300; # (Ò; Ò; O◌̀; Ò; O◌̀; ) LATIN CAPITAL LETTER O WITH GRAVE +00D3;00D3;004F 0301;00D3;004F 0301; # (Ó; Ó; O◌́; Ó; O◌́; ) LATIN CAPITAL LETTER O WITH ACUTE +00D4;00D4;004F 0302;00D4;004F 0302; # (Ô; Ô; O◌̂; Ô; O◌̂; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D5;00D5;004F 0303;00D5;004F 0303; # (Õ; Õ; O◌̃; Õ; O◌̃; ) LATIN CAPITAL LETTER O WITH TILDE +00D6;00D6;004F 0308;00D6;004F 0308; # (Ö; Ö; O◌̈; Ö; O◌̈; ) LATIN CAPITAL LETTER O WITH DIAERESIS +00D9;00D9;0055 0300;00D9;0055 0300; # (Ù; Ù; U◌̀; Ù; U◌̀; ) LATIN CAPITAL LETTER U WITH GRAVE +00DA;00DA;0055 0301;00DA;0055 0301; # (Ú; Ú; U◌́; Ú; U◌́; ) LATIN CAPITAL LETTER U WITH ACUTE +00DB;00DB;0055 0302;00DB;0055 0302; # (Û; Û; U◌̂; Û; U◌̂; ) LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC;00DC;0055 0308;00DC;0055 0308; # (Ü; Ü; U◌̈; Ü; U◌̈; ) LATIN CAPITAL LETTER U WITH DIAERESIS +00DD;00DD;0059 0301;00DD;0059 0301; # (Ý; Ý; Y◌́; Ý; Y◌́; ) LATIN CAPITAL LETTER Y WITH ACUTE +00E0;00E0;0061 0300;00E0;0061 0300; # (à; à; a◌̀; à; a◌̀; ) LATIN SMALL LETTER A WITH GRAVE +00E1;00E1;0061 0301;00E1;0061 0301; # (á; á; a◌́; á; a◌́; ) LATIN SMALL LETTER A WITH ACUTE +00E2;00E2;0061 0302;00E2;0061 0302; # (â; â; a◌̂; â; a◌̂; ) LATIN SMALL LETTER A WITH CIRCUMFLEX +00E3;00E3;0061 0303;00E3;0061 0303; # (ã; ã; a◌̃; ã; a◌̃; ) LATIN SMALL LETTER A WITH TILDE +00E4;00E4;0061 0308;00E4;0061 0308; # (ä; ä; a◌̈; ä; a◌̈; ) LATIN SMALL LETTER A WITH DIAERESIS +00E5;00E5;0061 030A;00E5;0061 030A; # (å; å; a◌̊; å; a◌̊; ) LATIN SMALL LETTER A WITH RING ABOVE +00E7;00E7;0063 0327;00E7;0063 0327; # (ç; ç; c◌̧; ç; c◌̧; ) LATIN SMALL LETTER C WITH CEDILLA +00E8;00E8;0065 0300;00E8;0065 0300; # (è; è; e◌̀; è; e◌̀; ) LATIN SMALL LETTER E WITH GRAVE +00E9;00E9;0065 0301;00E9;0065 0301; # (é; é; e◌́; é; e◌́; ) LATIN SMALL LETTER E WITH ACUTE +00EA;00EA;0065 0302;00EA;0065 0302; # (ê; ê; e◌̂; ê; e◌̂; ) LATIN SMALL LETTER E WITH CIRCUMFLEX +00EB;00EB;0065 0308;00EB;0065 0308; # (ë; ë; e◌̈; ë; e◌̈; ) LATIN SMALL LETTER E WITH DIAERESIS +00EC;00EC;0069 0300;00EC;0069 0300; # (ì; ì; i◌̀; ì; i◌̀; ) LATIN SMALL LETTER I WITH GRAVE +00ED;00ED;0069 0301;00ED;0069 0301; # (í; í; i◌́; í; i◌́; ) LATIN SMALL LETTER I WITH ACUTE +00EE;00EE;0069 0302;00EE;0069 0302; # (î; î; i◌̂; î; i◌̂; ) LATIN SMALL LETTER I WITH CIRCUMFLEX +00EF;00EF;0069 0308;00EF;0069 0308; # (ï; ï; i◌̈; ï; i◌̈; ) LATIN SMALL LETTER I WITH DIAERESIS +00F1;00F1;006E 0303;00F1;006E 0303; # (ñ; ñ; n◌̃; ñ; n◌̃; ) LATIN SMALL LETTER N WITH TILDE +00F2;00F2;006F 0300;00F2;006F 0300; # (ò; ò; o◌̀; ò; o◌̀; ) LATIN SMALL LETTER O WITH GRAVE +00F3;00F3;006F 0301;00F3;006F 0301; # (ó; ó; o◌́; ó; o◌́; ) LATIN SMALL LETTER O WITH ACUTE +00F4;00F4;006F 0302;00F4;006F 0302; # (ô; ô; o◌̂; ô; o◌̂; ) LATIN SMALL LETTER O WITH CIRCUMFLEX +00F5;00F5;006F 0303;00F5;006F 0303; # (õ; õ; o◌̃; õ; o◌̃; ) LATIN SMALL LETTER O WITH TILDE +00F6;00F6;006F 0308;00F6;006F 0308; # (ö; ö; o◌̈; ö; o◌̈; ) LATIN SMALL LETTER O WITH DIAERESIS +00F9;00F9;0075 0300;00F9;0075 0300; # (ù; ù; u◌̀; ù; u◌̀; ) LATIN SMALL LETTER U WITH GRAVE +00FA;00FA;0075 0301;00FA;0075 0301; # (ú; ú; u◌́; ú; u◌́; ) LATIN SMALL LETTER U WITH ACUTE +00FB;00FB;0075 0302;00FB;0075 0302; # (û; û; u◌̂; û; u◌̂; ) LATIN SMALL LETTER U WITH CIRCUMFLEX +00FC;00FC;0075 0308;00FC;0075 0308; # (ü; ü; u◌̈; ü; u◌̈; ) LATIN SMALL LETTER U WITH DIAERESIS +00FD;00FD;0079 0301;00FD;0079 0301; # (ý; ý; y◌́; ý; y◌́; ) LATIN SMALL LETTER Y WITH ACUTE +00FF;00FF;0079 0308;00FF;0079 0308; # (ÿ; ÿ; y◌̈; ÿ; y◌̈; ) LATIN SMALL LETTER Y WITH DIAERESIS +0100;0100;0041 0304;0100;0041 0304; # (Ā; Ā; A◌̄; Ā; A◌̄; ) LATIN CAPITAL LETTER A WITH MACRON +0101;0101;0061 0304;0101;0061 0304; # (ā; ā; a◌̄; ā; a◌̄; ) LATIN SMALL LETTER A WITH MACRON +0102;0102;0041 0306;0102;0041 0306; # (Ă; Ă; A◌̆; Ă; A◌̆; ) LATIN CAPITAL LETTER A WITH BREVE +0103;0103;0061 0306;0103;0061 0306; # (ă; ă; a◌̆; ă; a◌̆; ) LATIN SMALL LETTER A WITH BREVE +0104;0104;0041 0328;0104;0041 0328; # (Ą; Ą; A◌̨; Ą; A◌̨; ) LATIN CAPITAL LETTER A WITH OGONEK +0105;0105;0061 0328;0105;0061 0328; # (ą; ą; a◌̨; ą; a◌̨; ) LATIN SMALL LETTER A WITH OGONEK +0106;0106;0043 0301;0106;0043 0301; # (Ć; Ć; C◌́; Ć; C◌́; ) LATIN CAPITAL LETTER C WITH ACUTE +0107;0107;0063 0301;0107;0063 0301; # (ć; ć; c◌́; ć; c◌́; ) LATIN SMALL LETTER C WITH ACUTE +0108;0108;0043 0302;0108;0043 0302; # (Ĉ; Ĉ; C◌̂; Ĉ; C◌̂; ) LATIN CAPITAL LETTER C WITH CIRCUMFLEX +0109;0109;0063 0302;0109;0063 0302; # (ĉ; ĉ; c◌̂; ĉ; c◌̂; ) LATIN SMALL LETTER C WITH CIRCUMFLEX +010A;010A;0043 0307;010A;0043 0307; # (Ċ; Ċ; C◌̇; Ċ; C◌̇; ) LATIN CAPITAL LETTER C WITH DOT ABOVE +010B;010B;0063 0307;010B;0063 0307; # (ċ; ċ; c◌̇; ċ; c◌̇; ) LATIN SMALL LETTER C WITH DOT ABOVE +010C;010C;0043 030C;010C;0043 030C; # (Č; Č; C◌̌; Č; C◌̌; ) LATIN CAPITAL LETTER C WITH CARON +010D;010D;0063 030C;010D;0063 030C; # (č; č; c◌̌; č; c◌̌; ) LATIN SMALL LETTER C WITH CARON +010E;010E;0044 030C;010E;0044 030C; # (Ď; Ď; D◌̌; Ď; D◌̌; ) LATIN CAPITAL LETTER D WITH CARON +010F;010F;0064 030C;010F;0064 030C; # (ď; ď; d◌̌; ď; d◌̌; ) LATIN SMALL LETTER D WITH CARON +0112;0112;0045 0304;0112;0045 0304; # (Ē; Ē; E◌̄; Ē; E◌̄; ) LATIN CAPITAL LETTER E WITH MACRON +0113;0113;0065 0304;0113;0065 0304; # (ē; ē; e◌̄; ē; e◌̄; ) LATIN SMALL LETTER E WITH MACRON +0114;0114;0045 0306;0114;0045 0306; # (Ĕ; Ĕ; E◌̆; Ĕ; E◌̆; ) LATIN CAPITAL LETTER E WITH BREVE +0115;0115;0065 0306;0115;0065 0306; # (ĕ; ĕ; e◌̆; ĕ; e◌̆; ) LATIN SMALL LETTER E WITH BREVE +0116;0116;0045 0307;0116;0045 0307; # (Ė; Ė; E◌̇; Ė; E◌̇; ) LATIN CAPITAL LETTER E WITH DOT ABOVE +0117;0117;0065 0307;0117;0065 0307; # (ė; ė; e◌̇; ė; e◌̇; ) LATIN SMALL LETTER E WITH DOT ABOVE +0118;0118;0045 0328;0118;0045 0328; # (Ę; Ę; E◌̨; Ę; E◌̨; ) LATIN CAPITAL LETTER E WITH OGONEK +0119;0119;0065 0328;0119;0065 0328; # (ę; ę; e◌̨; ę; e◌̨; ) LATIN SMALL LETTER E WITH OGONEK +011A;011A;0045 030C;011A;0045 030C; # (Ě; Ě; E◌̌; Ě; E◌̌; ) LATIN CAPITAL LETTER E WITH CARON +011B;011B;0065 030C;011B;0065 030C; # (ě; ě; e◌̌; ě; e◌̌; ) LATIN SMALL LETTER E WITH CARON +011C;011C;0047 0302;011C;0047 0302; # (Ĝ; Ĝ; G◌̂; Ĝ; G◌̂; ) LATIN CAPITAL LETTER G WITH CIRCUMFLEX +011D;011D;0067 0302;011D;0067 0302; # (ĝ; ĝ; g◌̂; ĝ; g◌̂; ) LATIN SMALL LETTER G WITH CIRCUMFLEX +011E;011E;0047 0306;011E;0047 0306; # (Ğ; Ğ; G◌̆; Ğ; G◌̆; ) LATIN CAPITAL LETTER G WITH BREVE +011F;011F;0067 0306;011F;0067 0306; # (ğ; ğ; g◌̆; ğ; g◌̆; ) LATIN SMALL LETTER G WITH BREVE +0120;0120;0047 0307;0120;0047 0307; # (Ġ; Ġ; G◌̇; Ġ; G◌̇; ) LATIN CAPITAL LETTER G WITH DOT ABOVE +0121;0121;0067 0307;0121;0067 0307; # (ġ; ġ; g◌̇; ġ; g◌̇; ) LATIN SMALL LETTER G WITH DOT ABOVE +0122;0122;0047 0327;0122;0047 0327; # (Ģ; Ģ; G◌̧; Ģ; G◌̧; ) LATIN CAPITAL LETTER G WITH CEDILLA +0123;0123;0067 0327;0123;0067 0327; # (ģ; ģ; g◌̧; ģ; g◌̧; ) LATIN SMALL LETTER G WITH CEDILLA +0124;0124;0048 0302;0124;0048 0302; # (Ĥ; Ĥ; H◌̂; Ĥ; H◌̂; ) LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0125;0125;0068 0302;0125;0068 0302; # (ĥ; ĥ; h◌̂; ĥ; h◌̂; ) LATIN SMALL LETTER H WITH CIRCUMFLEX +0128;0128;0049 0303;0128;0049 0303; # (Ĩ; Ĩ; I◌̃; Ĩ; I◌̃; ) LATIN CAPITAL LETTER I WITH TILDE +0129;0129;0069 0303;0129;0069 0303; # (ĩ; ĩ; i◌̃; ĩ; i◌̃; ) LATIN SMALL LETTER I WITH TILDE +012A;012A;0049 0304;012A;0049 0304; # (Ī; Ī; I◌̄; Ī; I◌̄; ) LATIN CAPITAL LETTER I WITH MACRON +012B;012B;0069 0304;012B;0069 0304; # (ī; ī; i◌̄; ī; i◌̄; ) LATIN SMALL LETTER I WITH MACRON +012C;012C;0049 0306;012C;0049 0306; # (Ĭ; Ĭ; I◌̆; Ĭ; I◌̆; ) LATIN CAPITAL LETTER I WITH BREVE +012D;012D;0069 0306;012D;0069 0306; # (ĭ; ĭ; i◌̆; ĭ; i◌̆; ) LATIN SMALL LETTER I WITH BREVE +012E;012E;0049 0328;012E;0049 0328; # (Į; Į; I◌̨; Į; I◌̨; ) LATIN CAPITAL LETTER I WITH OGONEK +012F;012F;0069 0328;012F;0069 0328; # (į; į; i◌̨; į; i◌̨; ) LATIN SMALL LETTER I WITH OGONEK +0130;0130;0049 0307;0130;0049 0307; # (İ; İ; I◌̇; İ; I◌̇; ) LATIN CAPITAL LETTER I WITH DOT ABOVE +0132;0132;0132;0049 004A;0049 004A; # (IJ; IJ; IJ; IJ; IJ; ) LATIN CAPITAL LIGATURE IJ +0133;0133;0133;0069 006A;0069 006A; # (ij; ij; ij; ij; ij; ) LATIN SMALL LIGATURE IJ +0134;0134;004A 0302;0134;004A 0302; # (Ĵ; Ĵ; J◌̂; Ĵ; J◌̂; ) LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0135;0135;006A 0302;0135;006A 0302; # (ĵ; ĵ; j◌̂; ĵ; j◌̂; ) LATIN SMALL LETTER J WITH CIRCUMFLEX +0136;0136;004B 0327;0136;004B 0327; # (Ķ; Ķ; K◌̧; Ķ; K◌̧; ) LATIN CAPITAL LETTER K WITH CEDILLA +0137;0137;006B 0327;0137;006B 0327; # (ķ; ķ; k◌̧; ķ; k◌̧; ) LATIN SMALL LETTER K WITH CEDILLA +0139;0139;004C 0301;0139;004C 0301; # (Ĺ; Ĺ; L◌́; Ĺ; L◌́; ) LATIN CAPITAL LETTER L WITH ACUTE +013A;013A;006C 0301;013A;006C 0301; # (ĺ; ĺ; l◌́; ĺ; l◌́; ) LATIN SMALL LETTER L WITH ACUTE +013B;013B;004C 0327;013B;004C 0327; # (Ļ; Ļ; L◌̧; Ļ; L◌̧; ) LATIN CAPITAL LETTER L WITH CEDILLA +013C;013C;006C 0327;013C;006C 0327; # (ļ; ļ; l◌̧; ļ; l◌̧; ) LATIN SMALL LETTER L WITH CEDILLA +013D;013D;004C 030C;013D;004C 030C; # (Ľ; Ľ; L◌̌; Ľ; L◌̌; ) LATIN CAPITAL LETTER L WITH CARON +013E;013E;006C 030C;013E;006C 030C; # (ľ; ľ; l◌̌; ľ; l◌̌; ) LATIN SMALL LETTER L WITH CARON +013F;013F;013F;004C 00B7;004C 00B7; # (Ŀ; Ŀ; Ŀ; L·; L·; ) LATIN CAPITAL LETTER L WITH MIDDLE DOT +0140;0140;0140;006C 00B7;006C 00B7; # (ŀ; ŀ; ŀ; l·; l·; ) LATIN SMALL LETTER L WITH MIDDLE DOT +0143;0143;004E 0301;0143;004E 0301; # (Ń; Ń; N◌́; Ń; N◌́; ) LATIN CAPITAL LETTER N WITH ACUTE +0144;0144;006E 0301;0144;006E 0301; # (ń; ń; n◌́; ń; n◌́; ) LATIN SMALL LETTER N WITH ACUTE +0145;0145;004E 0327;0145;004E 0327; # (Ņ; Ņ; N◌̧; Ņ; N◌̧; ) LATIN CAPITAL LETTER N WITH CEDILLA +0146;0146;006E 0327;0146;006E 0327; # (ņ; ņ; n◌̧; ņ; n◌̧; ) LATIN SMALL LETTER N WITH CEDILLA +0147;0147;004E 030C;0147;004E 030C; # (Ň; Ň; N◌̌; Ň; N◌̌; ) LATIN CAPITAL LETTER N WITH CARON +0148;0148;006E 030C;0148;006E 030C; # (ň; ň; n◌̌; ň; n◌̌; ) LATIN SMALL LETTER N WITH CARON +0149;0149;0149;02BC 006E;02BC 006E; # (ʼn; ʼn; ʼn; ʼn; ʼn; ) LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +014C;014C;004F 0304;014C;004F 0304; # (Ō; Ō; O◌̄; Ō; O◌̄; ) LATIN CAPITAL LETTER O WITH MACRON +014D;014D;006F 0304;014D;006F 0304; # (ō; ō; o◌̄; ō; o◌̄; ) LATIN SMALL LETTER O WITH MACRON +014E;014E;004F 0306;014E;004F 0306; # (Ŏ; Ŏ; O◌̆; Ŏ; O◌̆; ) LATIN CAPITAL LETTER O WITH BREVE +014F;014F;006F 0306;014F;006F 0306; # (ŏ; ŏ; o◌̆; ŏ; o◌̆; ) LATIN SMALL LETTER O WITH BREVE +0150;0150;004F 030B;0150;004F 030B; # (Ő; Ő; O◌̋; Ő; O◌̋; ) LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0151;0151;006F 030B;0151;006F 030B; # (ő; ő; o◌̋; ő; o◌̋; ) LATIN SMALL LETTER O WITH DOUBLE ACUTE +0154;0154;0052 0301;0154;0052 0301; # (Ŕ; Ŕ; R◌́; Ŕ; R◌́; ) LATIN CAPITAL LETTER R WITH ACUTE +0155;0155;0072 0301;0155;0072 0301; # (ŕ; ŕ; r◌́; ŕ; r◌́; ) LATIN SMALL LETTER R WITH ACUTE +0156;0156;0052 0327;0156;0052 0327; # (Ŗ; Ŗ; R◌̧; Ŗ; R◌̧; ) LATIN CAPITAL LETTER R WITH CEDILLA +0157;0157;0072 0327;0157;0072 0327; # (ŗ; ŗ; r◌̧; ŗ; r◌̧; ) LATIN SMALL LETTER R WITH CEDILLA +0158;0158;0052 030C;0158;0052 030C; # (Ř; Ř; R◌̌; Ř; R◌̌; ) LATIN CAPITAL LETTER R WITH CARON +0159;0159;0072 030C;0159;0072 030C; # (ř; ř; r◌̌; ř; r◌̌; ) LATIN SMALL LETTER R WITH CARON +015A;015A;0053 0301;015A;0053 0301; # (Ś; Ś; S◌́; Ś; S◌́; ) LATIN CAPITAL LETTER S WITH ACUTE +015B;015B;0073 0301;015B;0073 0301; # (ś; ś; s◌́; ś; s◌́; ) LATIN SMALL LETTER S WITH ACUTE +015C;015C;0053 0302;015C;0053 0302; # (Ŝ; Ŝ; S◌̂; Ŝ; S◌̂; ) LATIN CAPITAL LETTER S WITH CIRCUMFLEX +015D;015D;0073 0302;015D;0073 0302; # (ŝ; ŝ; s◌̂; ŝ; s◌̂; ) LATIN SMALL LETTER S WITH CIRCUMFLEX +015E;015E;0053 0327;015E;0053 0327; # (Ş; Ş; S◌̧; Ş; S◌̧; ) LATIN CAPITAL LETTER S WITH CEDILLA +015F;015F;0073 0327;015F;0073 0327; # (ş; ş; s◌̧; ş; s◌̧; ) LATIN SMALL LETTER S WITH CEDILLA +0160;0160;0053 030C;0160;0053 030C; # (Š; Š; S◌̌; Š; S◌̌; ) LATIN CAPITAL LETTER S WITH CARON +0161;0161;0073 030C;0161;0073 030C; # (š; š; s◌̌; š; s◌̌; ) LATIN SMALL LETTER S WITH CARON +0162;0162;0054 0327;0162;0054 0327; # (Ţ; Ţ; T◌̧; Ţ; T◌̧; ) LATIN CAPITAL LETTER T WITH CEDILLA +0163;0163;0074 0327;0163;0074 0327; # (ţ; ţ; t◌̧; ţ; t◌̧; ) LATIN SMALL LETTER T WITH CEDILLA +0164;0164;0054 030C;0164;0054 030C; # (Ť; Ť; T◌̌; Ť; T◌̌; ) LATIN CAPITAL LETTER T WITH CARON +0165;0165;0074 030C;0165;0074 030C; # (ť; ť; t◌̌; ť; t◌̌; ) LATIN SMALL LETTER T WITH CARON +0168;0168;0055 0303;0168;0055 0303; # (Ũ; Ũ; U◌̃; Ũ; U◌̃; ) LATIN CAPITAL LETTER U WITH TILDE +0169;0169;0075 0303;0169;0075 0303; # (ũ; ũ; u◌̃; ũ; u◌̃; ) LATIN SMALL LETTER U WITH TILDE +016A;016A;0055 0304;016A;0055 0304; # (Ū; Ū; U◌̄; Ū; U◌̄; ) LATIN CAPITAL LETTER U WITH MACRON +016B;016B;0075 0304;016B;0075 0304; # (ū; ū; u◌̄; ū; u◌̄; ) LATIN SMALL LETTER U WITH MACRON +016C;016C;0055 0306;016C;0055 0306; # (Ŭ; Ŭ; U◌̆; Ŭ; U◌̆; ) LATIN CAPITAL LETTER U WITH BREVE +016D;016D;0075 0306;016D;0075 0306; # (ŭ; ŭ; u◌̆; ŭ; u◌̆; ) LATIN SMALL LETTER U WITH BREVE +016E;016E;0055 030A;016E;0055 030A; # (Ů; Ů; U◌̊; Ů; U◌̊; ) LATIN CAPITAL LETTER U WITH RING ABOVE +016F;016F;0075 030A;016F;0075 030A; # (ů; ů; u◌̊; ů; u◌̊; ) LATIN SMALL LETTER U WITH RING ABOVE +0170;0170;0055 030B;0170;0055 030B; # (Ű; Ű; U◌̋; Ű; U◌̋; ) LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0171;0171;0075 030B;0171;0075 030B; # (ű; ű; u◌̋; ű; u◌̋; ) LATIN SMALL LETTER U WITH DOUBLE ACUTE +0172;0172;0055 0328;0172;0055 0328; # (Ų; Ų; U◌̨; Ų; U◌̨; ) LATIN CAPITAL LETTER U WITH OGONEK +0173;0173;0075 0328;0173;0075 0328; # (ų; ų; u◌̨; ų; u◌̨; ) LATIN SMALL LETTER U WITH OGONEK +0174;0174;0057 0302;0174;0057 0302; # (Ŵ; Ŵ; W◌̂; Ŵ; W◌̂; ) LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0175;0175;0077 0302;0175;0077 0302; # (ŵ; ŵ; w◌̂; ŵ; w◌̂; ) LATIN SMALL LETTER W WITH CIRCUMFLEX +0176;0176;0059 0302;0176;0059 0302; # (Ŷ; Ŷ; Y◌̂; Ŷ; Y◌̂; ) LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0177;0177;0079 0302;0177;0079 0302; # (ŷ; ŷ; y◌̂; ŷ; y◌̂; ) LATIN SMALL LETTER Y WITH CIRCUMFLEX +0178;0178;0059 0308;0178;0059 0308; # (Ÿ; Ÿ; Y◌̈; Ÿ; Y◌̈; ) LATIN CAPITAL LETTER Y WITH DIAERESIS +0179;0179;005A 0301;0179;005A 0301; # (Ź; Ź; Z◌́; Ź; Z◌́; ) LATIN CAPITAL LETTER Z WITH ACUTE +017A;017A;007A 0301;017A;007A 0301; # (ź; ź; z◌́; ź; z◌́; ) LATIN SMALL LETTER Z WITH ACUTE +017B;017B;005A 0307;017B;005A 0307; # (Ż; Ż; Z◌̇; Ż; Z◌̇; ) LATIN CAPITAL LETTER Z WITH DOT ABOVE +017C;017C;007A 0307;017C;007A 0307; # (ż; ż; z◌̇; ż; z◌̇; ) LATIN SMALL LETTER Z WITH DOT ABOVE +017D;017D;005A 030C;017D;005A 030C; # (Ž; Ž; Z◌̌; Ž; Z◌̌; ) LATIN CAPITAL LETTER Z WITH CARON +017E;017E;007A 030C;017E;007A 030C; # (ž; ž; z◌̌; ž; z◌̌; ) LATIN SMALL LETTER Z WITH CARON +017F;017F;017F;0073;0073; # (ſ; ſ; ſ; s; s; ) LATIN SMALL LETTER LONG S +01A0;01A0;004F 031B;01A0;004F 031B; # (Ơ; Ơ; O◌̛; Ơ; O◌̛; ) LATIN CAPITAL LETTER O WITH HORN +01A1;01A1;006F 031B;01A1;006F 031B; # (ơ; ơ; o◌̛; ơ; o◌̛; ) LATIN SMALL LETTER O WITH HORN +01AF;01AF;0055 031B;01AF;0055 031B; # (Ư; Ư; U◌̛; Ư; U◌̛; ) LATIN CAPITAL LETTER U WITH HORN +01B0;01B0;0075 031B;01B0;0075 031B; # (ư; ư; u◌̛; ư; u◌̛; ) LATIN SMALL LETTER U WITH HORN +01C4;01C4;01C4;0044 017D;0044 005A 030C; # (DŽ; DŽ; DŽ; DŽ; DZ◌̌; ) LATIN CAPITAL LETTER DZ WITH CARON +01C5;01C5;01C5;0044 017E;0044 007A 030C; # (Dž; Dž; Dž; Dž; Dz◌̌; ) LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +01C6;01C6;01C6;0064 017E;0064 007A 030C; # (dž; dž; dž; dž; dz◌̌; ) LATIN SMALL LETTER DZ WITH CARON +01C7;01C7;01C7;004C 004A;004C 004A; # (LJ; LJ; LJ; LJ; LJ; ) LATIN CAPITAL LETTER LJ +01C8;01C8;01C8;004C 006A;004C 006A; # (Lj; Lj; Lj; Lj; Lj; ) LATIN CAPITAL LETTER L WITH SMALL LETTER J +01C9;01C9;01C9;006C 006A;006C 006A; # (lj; lj; lj; lj; lj; ) LATIN SMALL LETTER LJ +01CA;01CA;01CA;004E 004A;004E 004A; # (NJ; NJ; NJ; NJ; NJ; ) LATIN CAPITAL LETTER NJ +01CB;01CB;01CB;004E 006A;004E 006A; # (Nj; Nj; Nj; Nj; Nj; ) LATIN CAPITAL LETTER N WITH SMALL LETTER J +01CC;01CC;01CC;006E 006A;006E 006A; # (nj; nj; nj; nj; nj; ) LATIN SMALL LETTER NJ +01CD;01CD;0041 030C;01CD;0041 030C; # (Ǎ; Ǎ; A◌̌; Ǎ; A◌̌; ) LATIN CAPITAL LETTER A WITH CARON +01CE;01CE;0061 030C;01CE;0061 030C; # (ǎ; ǎ; a◌̌; ǎ; a◌̌; ) LATIN SMALL LETTER A WITH CARON +01CF;01CF;0049 030C;01CF;0049 030C; # (Ǐ; Ǐ; I◌̌; Ǐ; I◌̌; ) LATIN CAPITAL LETTER I WITH CARON +01D0;01D0;0069 030C;01D0;0069 030C; # (ǐ; ǐ; i◌̌; ǐ; i◌̌; ) LATIN SMALL LETTER I WITH CARON +01D1;01D1;004F 030C;01D1;004F 030C; # (Ǒ; Ǒ; O◌̌; Ǒ; O◌̌; ) LATIN CAPITAL LETTER O WITH CARON +01D2;01D2;006F 030C;01D2;006F 030C; # (ǒ; ǒ; o◌̌; ǒ; o◌̌; ) LATIN SMALL LETTER O WITH CARON +01D3;01D3;0055 030C;01D3;0055 030C; # (Ǔ; Ǔ; U◌̌; Ǔ; U◌̌; ) LATIN CAPITAL LETTER U WITH CARON +01D4;01D4;0075 030C;01D4;0075 030C; # (ǔ; ǔ; u◌̌; ǔ; u◌̌; ) LATIN SMALL LETTER U WITH CARON +01D5;01D5;0055 0308 0304;01D5;0055 0308 0304; # (Ǖ; Ǖ; U◌̈◌̄; Ǖ; U◌̈◌̄; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D6;01D6;0075 0308 0304;01D6;0075 0308 0304; # (ǖ; ǖ; u◌̈◌̄; ǖ; u◌̈◌̄; ) LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D7;01D7;0055 0308 0301;01D7;0055 0308 0301; # (Ǘ; Ǘ; U◌̈◌́; Ǘ; U◌̈◌́; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D8;01D8;0075 0308 0301;01D8;0075 0308 0301; # (ǘ; ǘ; u◌̈◌́; ǘ; u◌̈◌́; ) LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01D9;01D9;0055 0308 030C;01D9;0055 0308 030C; # (Ǚ; Ǚ; U◌̈◌̌; Ǚ; U◌̈◌̌; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DA;01DA;0075 0308 030C;01DA;0075 0308 030C; # (ǚ; ǚ; u◌̈◌̌; ǚ; u◌̈◌̌; ) LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01DB;01DB;0055 0308 0300;01DB;0055 0308 0300; # (Ǜ; Ǜ; U◌̈◌̀; Ǜ; U◌̈◌̀; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DC;01DC;0075 0308 0300;01DC;0075 0308 0300; # (ǜ; ǜ; u◌̈◌̀; ǜ; u◌̈◌̀; ) LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE +01DE;01DE;0041 0308 0304;01DE;0041 0308 0304; # (Ǟ; Ǟ; A◌̈◌̄; Ǟ; A◌̈◌̄; ) LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +01DF;01DF;0061 0308 0304;01DF;0061 0308 0304; # (ǟ; ǟ; a◌̈◌̄; ǟ; a◌̈◌̄; ) LATIN SMALL LETTER A WITH DIAERESIS AND MACRON +01E0;01E0;0041 0307 0304;01E0;0041 0307 0304; # (Ǡ; Ǡ; A◌̇◌̄; Ǡ; A◌̇◌̄; ) LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +01E1;01E1;0061 0307 0304;01E1;0061 0307 0304; # (ǡ; ǡ; a◌̇◌̄; ǡ; a◌̇◌̄; ) LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON +01E2;01E2;00C6 0304;01E2;00C6 0304; # (Ǣ; Ǣ; Æ◌̄; Ǣ; Æ◌̄; ) LATIN CAPITAL LETTER AE WITH MACRON +01E3;01E3;00E6 0304;01E3;00E6 0304; # (ǣ; ǣ; æ◌̄; ǣ; æ◌̄; ) LATIN SMALL LETTER AE WITH MACRON +01E6;01E6;0047 030C;01E6;0047 030C; # (Ǧ; Ǧ; G◌̌; Ǧ; G◌̌; ) LATIN CAPITAL LETTER G WITH CARON +01E7;01E7;0067 030C;01E7;0067 030C; # (ǧ; ǧ; g◌̌; ǧ; g◌̌; ) LATIN SMALL LETTER G WITH CARON +01E8;01E8;004B 030C;01E8;004B 030C; # (Ǩ; Ǩ; K◌̌; Ǩ; K◌̌; ) LATIN CAPITAL LETTER K WITH CARON +01E9;01E9;006B 030C;01E9;006B 030C; # (ǩ; ǩ; k◌̌; ǩ; k◌̌; ) LATIN SMALL LETTER K WITH CARON +01EA;01EA;004F 0328;01EA;004F 0328; # (Ǫ; Ǫ; O◌̨; Ǫ; O◌̨; ) LATIN CAPITAL LETTER O WITH OGONEK +01EB;01EB;006F 0328;01EB;006F 0328; # (ǫ; ǫ; o◌̨; ǫ; o◌̨; ) LATIN SMALL LETTER O WITH OGONEK +01EC;01EC;004F 0328 0304;01EC;004F 0328 0304; # (Ǭ; Ǭ; O◌̨◌̄; Ǭ; O◌̨◌̄; ) LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +01ED;01ED;006F 0328 0304;01ED;006F 0328 0304; # (ǭ; ǭ; o◌̨◌̄; ǭ; o◌̨◌̄; ) LATIN SMALL LETTER O WITH OGONEK AND MACRON +01EE;01EE;01B7 030C;01EE;01B7 030C; # (Ǯ; Ǯ; Ʒ◌̌; Ǯ; Ʒ◌̌; ) LATIN CAPITAL LETTER EZH WITH CARON +01EF;01EF;0292 030C;01EF;0292 030C; # (ǯ; ǯ; ʒ◌̌; ǯ; ʒ◌̌; ) LATIN SMALL LETTER EZH WITH CARON +01F0;01F0;006A 030C;01F0;006A 030C; # (ǰ; ǰ; j◌̌; ǰ; j◌̌; ) LATIN SMALL LETTER J WITH CARON +01F1;01F1;01F1;0044 005A;0044 005A; # (DZ; DZ; DZ; DZ; DZ; ) LATIN CAPITAL LETTER DZ +01F2;01F2;01F2;0044 007A;0044 007A; # (Dz; Dz; Dz; Dz; Dz; ) LATIN CAPITAL LETTER D WITH SMALL LETTER Z +01F3;01F3;01F3;0064 007A;0064 007A; # (dz; dz; dz; dz; dz; ) LATIN SMALL LETTER DZ +01F4;01F4;0047 0301;01F4;0047 0301; # (Ǵ; Ǵ; G◌́; Ǵ; G◌́; ) LATIN CAPITAL LETTER G WITH ACUTE +01F5;01F5;0067 0301;01F5;0067 0301; # (ǵ; ǵ; g◌́; ǵ; g◌́; ) LATIN SMALL LETTER G WITH ACUTE +01F8;01F8;004E 0300;01F8;004E 0300; # (Ǹ; Ǹ; N◌̀; Ǹ; N◌̀; ) LATIN CAPITAL LETTER N WITH GRAVE +01F9;01F9;006E 0300;01F9;006E 0300; # (ǹ; ǹ; n◌̀; ǹ; n◌̀; ) LATIN SMALL LETTER N WITH GRAVE +01FA;01FA;0041 030A 0301;01FA;0041 030A 0301; # (Ǻ; Ǻ; A◌̊◌́; Ǻ; A◌̊◌́; ) LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +01FB;01FB;0061 030A 0301;01FB;0061 030A 0301; # (ǻ; ǻ; a◌̊◌́; ǻ; a◌̊◌́; ) LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +01FC;01FC;00C6 0301;01FC;00C6 0301; # (Ǽ; Ǽ; Æ◌́; Ǽ; Æ◌́; ) LATIN CAPITAL LETTER AE WITH ACUTE +01FD;01FD;00E6 0301;01FD;00E6 0301; # (ǽ; ǽ; æ◌́; ǽ; æ◌́; ) LATIN SMALL LETTER AE WITH ACUTE +01FE;01FE;00D8 0301;01FE;00D8 0301; # (Ǿ; Ǿ; Ø◌́; Ǿ; Ø◌́; ) LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +01FF;01FF;00F8 0301;01FF;00F8 0301; # (ǿ; ǿ; ø◌́; ǿ; ø◌́; ) LATIN SMALL LETTER O WITH STROKE AND ACUTE +0200;0200;0041 030F;0200;0041 030F; # (Ȁ; Ȁ; A◌̏; Ȁ; A◌̏; ) LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0201;0201;0061 030F;0201;0061 030F; # (ȁ; ȁ; a◌̏; ȁ; a◌̏; ) LATIN SMALL LETTER A WITH DOUBLE GRAVE +0202;0202;0041 0311;0202;0041 0311; # (Ȃ; Ȃ; A◌̑; Ȃ; A◌̑; ) LATIN CAPITAL LETTER A WITH INVERTED BREVE +0203;0203;0061 0311;0203;0061 0311; # (ȃ; ȃ; a◌̑; ȃ; a◌̑; ) LATIN SMALL LETTER A WITH INVERTED BREVE +0204;0204;0045 030F;0204;0045 030F; # (Ȅ; Ȅ; E◌̏; Ȅ; E◌̏; ) LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0205;0205;0065 030F;0205;0065 030F; # (ȅ; ȅ; e◌̏; ȅ; e◌̏; ) LATIN SMALL LETTER E WITH DOUBLE GRAVE +0206;0206;0045 0311;0206;0045 0311; # (Ȇ; Ȇ; E◌̑; Ȇ; E◌̑; ) LATIN CAPITAL LETTER E WITH INVERTED BREVE +0207;0207;0065 0311;0207;0065 0311; # (ȇ; ȇ; e◌̑; ȇ; e◌̑; ) LATIN SMALL LETTER E WITH INVERTED BREVE +0208;0208;0049 030F;0208;0049 030F; # (Ȉ; Ȉ; I◌̏; Ȉ; I◌̏; ) LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +0209;0209;0069 030F;0209;0069 030F; # (ȉ; ȉ; i◌̏; ȉ; i◌̏; ) LATIN SMALL LETTER I WITH DOUBLE GRAVE +020A;020A;0049 0311;020A;0049 0311; # (Ȋ; Ȋ; I◌̑; Ȋ; I◌̑; ) LATIN CAPITAL LETTER I WITH INVERTED BREVE +020B;020B;0069 0311;020B;0069 0311; # (ȋ; ȋ; i◌̑; ȋ; i◌̑; ) LATIN SMALL LETTER I WITH INVERTED BREVE +020C;020C;004F 030F;020C;004F 030F; # (Ȍ; Ȍ; O◌̏; Ȍ; O◌̏; ) LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020D;020D;006F 030F;020D;006F 030F; # (ȍ; ȍ; o◌̏; ȍ; o◌̏; ) LATIN SMALL LETTER O WITH DOUBLE GRAVE +020E;020E;004F 0311;020E;004F 0311; # (Ȏ; Ȏ; O◌̑; Ȏ; O◌̑; ) LATIN CAPITAL LETTER O WITH INVERTED BREVE +020F;020F;006F 0311;020F;006F 0311; # (ȏ; ȏ; o◌̑; ȏ; o◌̑; ) LATIN SMALL LETTER O WITH INVERTED BREVE +0210;0210;0052 030F;0210;0052 030F; # (Ȑ; Ȑ; R◌̏; Ȑ; R◌̏; ) LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0211;0211;0072 030F;0211;0072 030F; # (ȑ; ȑ; r◌̏; ȑ; r◌̏; ) LATIN SMALL LETTER R WITH DOUBLE GRAVE +0212;0212;0052 0311;0212;0052 0311; # (Ȓ; Ȓ; R◌̑; Ȓ; R◌̑; ) LATIN CAPITAL LETTER R WITH INVERTED BREVE +0213;0213;0072 0311;0213;0072 0311; # (ȓ; ȓ; r◌̑; ȓ; r◌̑; ) LATIN SMALL LETTER R WITH INVERTED BREVE +0214;0214;0055 030F;0214;0055 030F; # (Ȕ; Ȕ; U◌̏; Ȕ; U◌̏; ) LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0215;0215;0075 030F;0215;0075 030F; # (ȕ; ȕ; u◌̏; ȕ; u◌̏; ) LATIN SMALL LETTER U WITH DOUBLE GRAVE +0216;0216;0055 0311;0216;0055 0311; # (Ȗ; Ȗ; U◌̑; Ȗ; U◌̑; ) LATIN CAPITAL LETTER U WITH INVERTED BREVE +0217;0217;0075 0311;0217;0075 0311; # (ȗ; ȗ; u◌̑; ȗ; u◌̑; ) LATIN SMALL LETTER U WITH INVERTED BREVE +0218;0218;0053 0326;0218;0053 0326; # (Ș; Ș; S◌̦; Ș; S◌̦; ) LATIN CAPITAL LETTER S WITH COMMA BELOW +0219;0219;0073 0326;0219;0073 0326; # (ș; ș; s◌̦; ș; s◌̦; ) LATIN SMALL LETTER S WITH COMMA BELOW +021A;021A;0054 0326;021A;0054 0326; # (Ț; Ț; T◌̦; Ț; T◌̦; ) LATIN CAPITAL LETTER T WITH COMMA BELOW +021B;021B;0074 0326;021B;0074 0326; # (ț; ț; t◌̦; ț; t◌̦; ) LATIN SMALL LETTER T WITH COMMA BELOW +021E;021E;0048 030C;021E;0048 030C; # (Ȟ; Ȟ; H◌̌; Ȟ; H◌̌; ) LATIN CAPITAL LETTER H WITH CARON +021F;021F;0068 030C;021F;0068 030C; # (ȟ; ȟ; h◌̌; ȟ; h◌̌; ) LATIN SMALL LETTER H WITH CARON +0226;0226;0041 0307;0226;0041 0307; # (Ȧ; Ȧ; A◌̇; Ȧ; A◌̇; ) LATIN CAPITAL LETTER A WITH DOT ABOVE +0227;0227;0061 0307;0227;0061 0307; # (ȧ; ȧ; a◌̇; ȧ; a◌̇; ) LATIN SMALL LETTER A WITH DOT ABOVE +0228;0228;0045 0327;0228;0045 0327; # (Ȩ; Ȩ; E◌̧; Ȩ; E◌̧; ) LATIN CAPITAL LETTER E WITH CEDILLA +0229;0229;0065 0327;0229;0065 0327; # (ȩ; ȩ; e◌̧; ȩ; e◌̧; ) LATIN SMALL LETTER E WITH CEDILLA +022A;022A;004F 0308 0304;022A;004F 0308 0304; # (Ȫ; Ȫ; O◌̈◌̄; Ȫ; O◌̈◌̄; ) LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +022B;022B;006F 0308 0304;022B;006F 0308 0304; # (ȫ; ȫ; o◌̈◌̄; ȫ; o◌̈◌̄; ) LATIN SMALL LETTER O WITH DIAERESIS AND MACRON +022C;022C;004F 0303 0304;022C;004F 0303 0304; # (Ȭ; Ȭ; O◌̃◌̄; Ȭ; O◌̃◌̄; ) LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022D;022D;006F 0303 0304;022D;006F 0303 0304; # (ȭ; ȭ; o◌̃◌̄; ȭ; o◌̃◌̄; ) LATIN SMALL LETTER O WITH TILDE AND MACRON +022E;022E;004F 0307;022E;004F 0307; # (Ȯ; Ȯ; O◌̇; Ȯ; O◌̇; ) LATIN CAPITAL LETTER O WITH DOT ABOVE +022F;022F;006F 0307;022F;006F 0307; # (ȯ; ȯ; o◌̇; ȯ; o◌̇; ) LATIN SMALL LETTER O WITH DOT ABOVE +0230;0230;004F 0307 0304;0230;004F 0307 0304; # (Ȱ; Ȱ; O◌̇◌̄; Ȱ; O◌̇◌̄; ) LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +0231;0231;006F 0307 0304;0231;006F 0307 0304; # (ȱ; ȱ; o◌̇◌̄; ȱ; o◌̇◌̄; ) LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON +0232;0232;0059 0304;0232;0059 0304; # (Ȳ; Ȳ; Y◌̄; Ȳ; Y◌̄; ) LATIN CAPITAL LETTER Y WITH MACRON +0233;0233;0079 0304;0233;0079 0304; # (ȳ; ȳ; y◌̄; ȳ; y◌̄; ) LATIN SMALL LETTER Y WITH MACRON +02B0;02B0;02B0;0068;0068; # (ʰ; ʰ; ʰ; h; h; ) MODIFIER LETTER SMALL H +02B1;02B1;02B1;0266;0266; # (ʱ; ʱ; ʱ; ɦ; ɦ; ) MODIFIER LETTER SMALL H WITH HOOK +02B2;02B2;02B2;006A;006A; # (ʲ; ʲ; ʲ; j; j; ) MODIFIER LETTER SMALL J +02B3;02B3;02B3;0072;0072; # (ʳ; ʳ; ʳ; r; r; ) MODIFIER LETTER SMALL R +02B4;02B4;02B4;0279;0279; # (ʴ; ʴ; ʴ; ɹ; ɹ; ) MODIFIER LETTER SMALL TURNED R +02B5;02B5;02B5;027B;027B; # (ʵ; ʵ; ʵ; ɻ; ɻ; ) MODIFIER LETTER SMALL TURNED R WITH HOOK +02B6;02B6;02B6;0281;0281; # (ʶ; ʶ; ʶ; ʁ; ʁ; ) MODIFIER LETTER SMALL CAPITAL INVERTED R +02B7;02B7;02B7;0077;0077; # (ʷ; ʷ; ʷ; w; w; ) MODIFIER LETTER SMALL W +02B8;02B8;02B8;0079;0079; # (ʸ; ʸ; ʸ; y; y; ) MODIFIER LETTER SMALL Y +02D8;02D8;02D8;0020 0306;0020 0306; # (˘; ˘; ˘; ◌̆; ◌̆; ) BREVE +02D9;02D9;02D9;0020 0307;0020 0307; # (˙; ˙; ˙; ◌̇; ◌̇; ) DOT ABOVE +02DA;02DA;02DA;0020 030A;0020 030A; # (˚; ˚; ˚; ◌̊; ◌̊; ) RING ABOVE +02DB;02DB;02DB;0020 0328;0020 0328; # (˛; ˛; ˛; ◌̨; ◌̨; ) OGONEK +02DC;02DC;02DC;0020 0303;0020 0303; # (˜; ˜; ˜; ◌̃; ◌̃; ) SMALL TILDE +02DD;02DD;02DD;0020 030B;0020 030B; # (˝; ˝; ˝; ◌̋; ◌̋; ) DOUBLE ACUTE ACCENT +02E0;02E0;02E0;0263;0263; # (ˠ; ˠ; ˠ; ɣ; ɣ; ) MODIFIER LETTER SMALL GAMMA +02E1;02E1;02E1;006C;006C; # (ˡ; ˡ; ˡ; l; l; ) MODIFIER LETTER SMALL L +02E2;02E2;02E2;0073;0073; # (ˢ; ˢ; ˢ; s; s; ) MODIFIER LETTER SMALL S +02E3;02E3;02E3;0078;0078; # (ˣ; ˣ; ˣ; x; x; ) MODIFIER LETTER SMALL X +02E4;02E4;02E4;0295;0295; # (ˤ; ˤ; ˤ; ʕ; ʕ; ) MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +0340;0300;0300;0300;0300; # (◌̀; ◌̀; ◌̀; ◌̀; ◌̀; ) COMBINING GRAVE TONE MARK +0341;0301;0301;0301;0301; # (◌́; ◌́; ◌́; ◌́; ◌́; ) COMBINING ACUTE TONE MARK +0343;0313;0313;0313;0313; # (◌̓; ◌̓; ◌̓; ◌̓; ◌̓; ) COMBINING GREEK KORONIS +0344;0308 0301;0308 0301;0308 0301;0308 0301; # (◌̈́; ◌̈◌́; ◌̈◌́; ◌̈◌́; ◌̈◌́; ) COMBINING GREEK DIALYTIKA TONOS +0374;02B9;02B9;02B9;02B9; # (ʹ; ʹ; ʹ; ʹ; ʹ; ) GREEK NUMERAL SIGN +037A;037A;037A;0020 0345;0020 0345; # (ͺ; ͺ; ͺ; ◌ͅ; ◌ͅ; ) GREEK YPOGEGRAMMENI +037E;003B;003B;003B;003B; # (;; ;; ;; ;; ;; ) GREEK QUESTION MARK +0384;0384;0384;0020 0301;0020 0301; # (΄; ΄; ΄; ◌́; ◌́; ) GREEK TONOS +0385;0385;00A8 0301;0020 0308 0301;0020 0308 0301; # (΅; ΅; ¨◌́; ◌̈◌́; ◌̈◌́; ) GREEK DIALYTIKA TONOS +0386;0386;0391 0301;0386;0391 0301; # (Ά; Ά; Α◌́; Ά; Α◌́; ) GREEK CAPITAL LETTER ALPHA WITH TONOS +0387;00B7;00B7;00B7;00B7; # (·; ·; ·; ·; ·; ) GREEK ANO TELEIA +0388;0388;0395 0301;0388;0395 0301; # (Έ; Έ; Ε◌́; Έ; Ε◌́; ) GREEK CAPITAL LETTER EPSILON WITH TONOS +0389;0389;0397 0301;0389;0397 0301; # (Ή; Ή; Η◌́; Ή; Η◌́; ) GREEK CAPITAL LETTER ETA WITH TONOS +038A;038A;0399 0301;038A;0399 0301; # (Ί; Ί; Ι◌́; Ί; Ι◌́; ) GREEK CAPITAL LETTER IOTA WITH TONOS +038C;038C;039F 0301;038C;039F 0301; # (Ό; Ό; Ο◌́; Ό; Ο◌́; ) GREEK CAPITAL LETTER OMICRON WITH TONOS +038E;038E;03A5 0301;038E;03A5 0301; # (Ύ; Ύ; Υ◌́; Ύ; Υ◌́; ) GREEK CAPITAL LETTER UPSILON WITH TONOS +038F;038F;03A9 0301;038F;03A9 0301; # (Ώ; Ώ; Ω◌́; Ώ; Ω◌́; ) GREEK CAPITAL LETTER OMEGA WITH TONOS +0390;0390;03B9 0308 0301;0390;03B9 0308 0301; # (ΐ; ΐ; ι◌̈◌́; ΐ; ι◌̈◌́; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03AA;03AA;0399 0308;03AA;0399 0308; # (Ϊ; Ϊ; Ι◌̈; Ϊ; Ι◌̈; ) GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +03AB;03AB;03A5 0308;03AB;03A5 0308; # (Ϋ; Ϋ; Υ◌̈; Ϋ; Υ◌̈; ) GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03AC;03AC;03B1 0301;03AC;03B1 0301; # (ά; ά; α◌́; ά; α◌́; ) GREEK SMALL LETTER ALPHA WITH TONOS +03AD;03AD;03B5 0301;03AD;03B5 0301; # (έ; έ; ε◌́; έ; ε◌́; ) GREEK SMALL LETTER EPSILON WITH TONOS +03AE;03AE;03B7 0301;03AE;03B7 0301; # (ή; ή; η◌́; ή; η◌́; ) GREEK SMALL LETTER ETA WITH TONOS +03AF;03AF;03B9 0301;03AF;03B9 0301; # (ί; ί; ι◌́; ί; ι◌́; ) GREEK SMALL LETTER IOTA WITH TONOS +03B0;03B0;03C5 0308 0301;03B0;03C5 0308 0301; # (ΰ; ΰ; υ◌̈◌́; ΰ; υ◌̈◌́; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03CA;03CA;03B9 0308;03CA;03B9 0308; # (ϊ; ϊ; ι◌̈; ϊ; ι◌̈; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA +03CB;03CB;03C5 0308;03CB;03C5 0308; # (ϋ; ϋ; υ◌̈; ϋ; υ◌̈; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA +03CC;03CC;03BF 0301;03CC;03BF 0301; # (ό; ό; ο◌́; ό; ο◌́; ) GREEK SMALL LETTER OMICRON WITH TONOS +03CD;03CD;03C5 0301;03CD;03C5 0301; # (ύ; ύ; υ◌́; ύ; υ◌́; ) GREEK SMALL LETTER UPSILON WITH TONOS +03CE;03CE;03C9 0301;03CE;03C9 0301; # (ώ; ώ; ω◌́; ώ; ω◌́; ) GREEK SMALL LETTER OMEGA WITH TONOS +03D0;03D0;03D0;03B2;03B2; # (ϐ; ϐ; ϐ; β; β; ) GREEK BETA SYMBOL +03D1;03D1;03D1;03B8;03B8; # (ϑ; ϑ; ϑ; θ; θ; ) GREEK THETA SYMBOL +03D2;03D2;03D2;03A5;03A5; # (ϒ; ϒ; ϒ; Υ; Υ; ) GREEK UPSILON WITH HOOK SYMBOL +03D3;03D3;03D2 0301;038E;03A5 0301; # (ϓ; ϓ; ϒ◌́; Ύ; Υ◌́; ) GREEK UPSILON WITH ACUTE AND HOOK SYMBOL +03D4;03D4;03D2 0308;03AB;03A5 0308; # (ϔ; ϔ; ϒ◌̈; Ϋ; Υ◌̈; ) GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL +03D5;03D5;03D5;03C6;03C6; # (ϕ; ϕ; ϕ; φ; φ; ) GREEK PHI SYMBOL +03D6;03D6;03D6;03C0;03C0; # (ϖ; ϖ; ϖ; π; π; ) GREEK PI SYMBOL +03F0;03F0;03F0;03BA;03BA; # (ϰ; ϰ; ϰ; κ; κ; ) GREEK KAPPA SYMBOL +03F1;03F1;03F1;03C1;03C1; # (ϱ; ϱ; ϱ; ρ; ρ; ) GREEK RHO SYMBOL +03F2;03F2;03F2;03C2;03C2; # (ϲ; ϲ; ϲ; ς; ς; ) GREEK LUNATE SIGMA SYMBOL +03F4;03F4;03F4;0398;0398; # (ϴ; ϴ; ϴ; Θ; Θ; ) GREEK CAPITAL THETA SYMBOL +03F5;03F5;03F5;03B5;03B5; # (ϵ; ϵ; ϵ; ε; ε; ) GREEK LUNATE EPSILON SYMBOL +0400;0400;0415 0300;0400;0415 0300; # (Ѐ; Ѐ; Е◌̀; Ѐ; Е◌̀; ) CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401;0401;0415 0308;0401;0415 0308; # (Ё; Ё; Е◌̈; Ё; Е◌̈; ) CYRILLIC CAPITAL LETTER IO +0403;0403;0413 0301;0403;0413 0301; # (Ѓ; Ѓ; Г◌́; Ѓ; Г◌́; ) CYRILLIC CAPITAL LETTER GJE +0407;0407;0406 0308;0407;0406 0308; # (Ї; Ї; І◌̈; Ї; І◌̈; ) CYRILLIC CAPITAL LETTER YI +040C;040C;041A 0301;040C;041A 0301; # (Ќ; Ќ; К◌́; Ќ; К◌́; ) CYRILLIC CAPITAL LETTER KJE +040D;040D;0418 0300;040D;0418 0300; # (Ѝ; Ѝ; И◌̀; Ѝ; И◌̀; ) CYRILLIC CAPITAL LETTER I WITH GRAVE +040E;040E;0423 0306;040E;0423 0306; # (Ў; Ў; У◌̆; Ў; У◌̆; ) CYRILLIC CAPITAL LETTER SHORT U +0419;0419;0418 0306;0419;0418 0306; # (Й; Й; И◌̆; Й; И◌̆; ) CYRILLIC CAPITAL LETTER SHORT I +0439;0439;0438 0306;0439;0438 0306; # (й; й; и◌̆; й; и◌̆; ) CYRILLIC SMALL LETTER SHORT I +0450;0450;0435 0300;0450;0435 0300; # (ѐ; ѐ; е◌̀; ѐ; е◌̀; ) CYRILLIC SMALL LETTER IE WITH GRAVE +0451;0451;0435 0308;0451;0435 0308; # (ё; ё; е◌̈; ё; е◌̈; ) CYRILLIC SMALL LETTER IO +0453;0453;0433 0301;0453;0433 0301; # (ѓ; ѓ; г◌́; ѓ; г◌́; ) CYRILLIC SMALL LETTER GJE +0457;0457;0456 0308;0457;0456 0308; # (ї; ї; і◌̈; ї; і◌̈; ) CYRILLIC SMALL LETTER YI +045C;045C;043A 0301;045C;043A 0301; # (ќ; ќ; к◌́; ќ; к◌́; ) CYRILLIC SMALL LETTER KJE +045D;045D;0438 0300;045D;0438 0300; # (ѝ; ѝ; и◌̀; ѝ; и◌̀; ) CYRILLIC SMALL LETTER I WITH GRAVE +045E;045E;0443 0306;045E;0443 0306; # (ў; ў; у◌̆; ў; у◌̆; ) CYRILLIC SMALL LETTER SHORT U +0476;0476;0474 030F;0476;0474 030F; # (Ѷ; Ѷ; Ѵ◌̏; Ѷ; Ѵ◌̏; ) CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0477;0477;0475 030F;0477;0475 030F; # (ѷ; ѷ; ѵ◌̏; ѷ; ѵ◌̏; ) CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +04C1;04C1;0416 0306;04C1;0416 0306; # (Ӂ; Ӂ; Ж◌̆; Ӂ; Ж◌̆; ) CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04C2;04C2;0436 0306;04C2;0436 0306; # (ӂ; ӂ; ж◌̆; ӂ; ж◌̆; ) CYRILLIC SMALL LETTER ZHE WITH BREVE +04D0;04D0;0410 0306;04D0;0410 0306; # (Ӑ; Ӑ; А◌̆; Ӑ; А◌̆; ) CYRILLIC CAPITAL LETTER A WITH BREVE +04D1;04D1;0430 0306;04D1;0430 0306; # (ӑ; ӑ; а◌̆; ӑ; а◌̆; ) CYRILLIC SMALL LETTER A WITH BREVE +04D2;04D2;0410 0308;04D2;0410 0308; # (Ӓ; Ӓ; А◌̈; Ӓ; А◌̈; ) CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D3;04D3;0430 0308;04D3;0430 0308; # (ӓ; ӓ; а◌̈; ӓ; а◌̈; ) CYRILLIC SMALL LETTER A WITH DIAERESIS +04D6;04D6;0415 0306;04D6;0415 0306; # (Ӗ; Ӗ; Е◌̆; Ӗ; Е◌̆; ) CYRILLIC CAPITAL LETTER IE WITH BREVE +04D7;04D7;0435 0306;04D7;0435 0306; # (ӗ; ӗ; е◌̆; ӗ; е◌̆; ) CYRILLIC SMALL LETTER IE WITH BREVE +04DA;04DA;04D8 0308;04DA;04D8 0308; # (Ӛ; Ӛ; Ә◌̈; Ӛ; Ә◌̈; ) CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04DB;04DB;04D9 0308;04DB;04D9 0308; # (ӛ; ӛ; ә◌̈; ӛ; ә◌̈; ) CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04DC;04DC;0416 0308;04DC;0416 0308; # (Ӝ; Ӝ; Ж◌̈; Ӝ; Ж◌̈; ) CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +04DD;04DD;0436 0308;04DD;0436 0308; # (ӝ; ӝ; ж◌̈; ӝ; ж◌̈; ) CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +04DE;04DE;0417 0308;04DE;0417 0308; # (Ӟ; Ӟ; З◌̈; Ӟ; З◌̈; ) CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +04DF;04DF;0437 0308;04DF;0437 0308; # (ӟ; ӟ; з◌̈; ӟ; з◌̈; ) CYRILLIC SMALL LETTER ZE WITH DIAERESIS +04E2;04E2;0418 0304;04E2;0418 0304; # (Ӣ; Ӣ; И◌̄; Ӣ; И◌̄; ) CYRILLIC CAPITAL LETTER I WITH MACRON +04E3;04E3;0438 0304;04E3;0438 0304; # (ӣ; ӣ; и◌̄; ӣ; и◌̄; ) CYRILLIC SMALL LETTER I WITH MACRON +04E4;04E4;0418 0308;04E4;0418 0308; # (Ӥ; Ӥ; И◌̈; Ӥ; И◌̈; ) CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E5;04E5;0438 0308;04E5;0438 0308; # (ӥ; ӥ; и◌̈; ӥ; и◌̈; ) CYRILLIC SMALL LETTER I WITH DIAERESIS +04E6;04E6;041E 0308;04E6;041E 0308; # (Ӧ; Ӧ; О◌̈; Ӧ; О◌̈; ) CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E7;04E7;043E 0308;04E7;043E 0308; # (ӧ; ӧ; о◌̈; ӧ; о◌̈; ) CYRILLIC SMALL LETTER O WITH DIAERESIS +04EA;04EA;04E8 0308;04EA;04E8 0308; # (Ӫ; Ӫ; Ө◌̈; Ӫ; Ө◌̈; ) CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04EB;04EB;04E9 0308;04EB;04E9 0308; # (ӫ; ӫ; ө◌̈; ӫ; ө◌̈; ) CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04EC;04EC;042D 0308;04EC;042D 0308; # (Ӭ; Ӭ; Э◌̈; Ӭ; Э◌̈; ) CYRILLIC CAPITAL LETTER E WITH DIAERESIS +04ED;04ED;044D 0308;04ED;044D 0308; # (ӭ; ӭ; э◌̈; ӭ; э◌̈; ) CYRILLIC SMALL LETTER E WITH DIAERESIS +04EE;04EE;0423 0304;04EE;0423 0304; # (Ӯ; Ӯ; У◌̄; Ӯ; У◌̄; ) CYRILLIC CAPITAL LETTER U WITH MACRON +04EF;04EF;0443 0304;04EF;0443 0304; # (ӯ; ӯ; у◌̄; ӯ; у◌̄; ) CYRILLIC SMALL LETTER U WITH MACRON +04F0;04F0;0423 0308;04F0;0423 0308; # (Ӱ; Ӱ; У◌̈; Ӱ; У◌̈; ) CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F1;04F1;0443 0308;04F1;0443 0308; # (ӱ; ӱ; у◌̈; ӱ; у◌̈; ) CYRILLIC SMALL LETTER U WITH DIAERESIS +04F2;04F2;0423 030B;04F2;0423 030B; # (Ӳ; Ӳ; У◌̋; Ӳ; У◌̋; ) CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04F3;04F3;0443 030B;04F3;0443 030B; # (ӳ; ӳ; у◌̋; ӳ; у◌̋; ) CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +04F4;04F4;0427 0308;04F4;0427 0308; # (Ӵ; Ӵ; Ч◌̈; Ӵ; Ч◌̈; ) CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04F5;04F5;0447 0308;04F5;0447 0308; # (ӵ; ӵ; ч◌̈; ӵ; ч◌̈; ) CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F8;04F8;042B 0308;04F8;042B 0308; # (Ӹ; Ӹ; Ы◌̈; Ӹ; Ы◌̈; ) CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +04F9;04F9;044B 0308;04F9;044B 0308; # (ӹ; ӹ; ы◌̈; ӹ; ы◌̈; ) CYRILLIC SMALL LETTER YERU WITH DIAERESIS +0587;0587;0587;0565 0582;0565 0582; # (և; և; և; եւ; եւ; ) ARMENIAN SMALL LIGATURE ECH YIWN +0622;0622;0627 0653;0622;0627 0653; # (آ; آ; ا◌ٓ; آ; ا◌ٓ; ) ARABIC LETTER ALEF WITH MADDA ABOVE +0623;0623;0627 0654;0623;0627 0654; # (أ; أ; ا◌ٔ; أ; ا◌ٔ; ) ARABIC LETTER ALEF WITH HAMZA ABOVE +0624;0624;0648 0654;0624;0648 0654; # (ؤ; ؤ; و◌ٔ; ؤ; و◌ٔ; ) ARABIC LETTER WAW WITH HAMZA ABOVE +0625;0625;0627 0655;0625;0627 0655; # (إ; إ; ا◌ٕ; إ; ا◌ٕ; ) ARABIC LETTER ALEF WITH HAMZA BELOW +0626;0626;064A 0654;0626;064A 0654; # (ئ; ئ; ي◌ٔ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE +0675;0675;0675;0627 0674;0627 0674; # (ٵ; ٵ; ٵ; اٴ; اٴ; ) ARABIC LETTER HIGH HAMZA ALEF +0676;0676;0676;0648 0674;0648 0674; # (ٶ; ٶ; ٶ; وٴ; وٴ; ) ARABIC LETTER HIGH HAMZA WAW +0677;0677;0677;06C7 0674;06C7 0674; # (ٷ; ٷ; ٷ; ۇٴ; ۇٴ; ) ARABIC LETTER U WITH HAMZA ABOVE +0678;0678;0678;064A 0674;064A 0674; # (ٸ; ٸ; ٸ; يٴ; يٴ; ) ARABIC LETTER HIGH HAMZA YEH +06C0;06C0;06D5 0654;06C0;06D5 0654; # (ۀ; ۀ; ە◌ٔ; ۀ; ە◌ٔ; ) ARABIC LETTER HEH WITH YEH ABOVE +06C2;06C2;06C1 0654;06C2;06C1 0654; # (ۂ; ۂ; ہ◌ٔ; ۂ; ہ◌ٔ; ) ARABIC LETTER HEH GOAL WITH HAMZA ABOVE +06D3;06D3;06D2 0654;06D3;06D2 0654; # (ۓ; ۓ; ے◌ٔ; ۓ; ے◌ٔ; ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +0929;0929;0928 093C;0929;0928 093C; # (ऩ; ऩ; न◌़; ऩ; न◌़; ) DEVANAGARI LETTER NNNA +0931;0931;0930 093C;0931;0930 093C; # (ऱ; ऱ; र◌़; ऱ; र◌़; ) DEVANAGARI LETTER RRA +0934;0934;0933 093C;0934;0933 093C; # (ऴ; ऴ; ळ◌़; ऴ; ळ◌़; ) DEVANAGARI LETTER LLLA +0958;0915 093C;0915 093C;0915 093C;0915 093C; # (क़; क◌़; क◌़; क◌़; क◌़; ) DEVANAGARI LETTER QA +0959;0916 093C;0916 093C;0916 093C;0916 093C; # (ख़; ख◌़; ख◌़; ख◌़; ख◌़; ) DEVANAGARI LETTER KHHA +095A;0917 093C;0917 093C;0917 093C;0917 093C; # (ग़; ग◌़; ग◌़; ग◌़; ग◌़; ) DEVANAGARI LETTER GHHA +095B;091C 093C;091C 093C;091C 093C;091C 093C; # (ज़; ज◌़; ज◌़; ज◌़; ज◌़; ) DEVANAGARI LETTER ZA +095C;0921 093C;0921 093C;0921 093C;0921 093C; # (ड़; ड◌़; ड◌़; ड◌़; ड◌़; ) DEVANAGARI LETTER DDDHA +095D;0922 093C;0922 093C;0922 093C;0922 093C; # (ढ़; ढ◌़; ढ◌़; ढ◌़; ढ◌़; ) DEVANAGARI LETTER RHA +095E;092B 093C;092B 093C;092B 093C;092B 093C; # (फ़; फ◌़; फ◌़; फ◌़; फ◌़; ) DEVANAGARI LETTER FA +095F;092F 093C;092F 093C;092F 093C;092F 093C; # (य़; य◌़; य◌़; य◌़; य◌़; ) DEVANAGARI LETTER YYA +09CB;09CB;09C7 09BE;09CB;09C7 09BE; # (ো; ো; ো; ো; ো; ) BENGALI VOWEL SIGN O +09CC;09CC;09C7 09D7;09CC;09C7 09D7; # (ৌ; ৌ; ৌ; ৌ; ৌ; ) BENGALI VOWEL SIGN AU +09DC;09A1 09BC;09A1 09BC;09A1 09BC;09A1 09BC; # (ড়; ড◌়; ড◌়; ড◌়; ড◌়; ) BENGALI LETTER RRA +09DD;09A2 09BC;09A2 09BC;09A2 09BC;09A2 09BC; # (ঢ়; ঢ◌়; ঢ◌়; ঢ◌়; ঢ◌়; ) BENGALI LETTER RHA +09DF;09AF 09BC;09AF 09BC;09AF 09BC;09AF 09BC; # (য়; য◌়; য◌়; য◌়; য◌়; ) BENGALI LETTER YYA +0A33;0A32 0A3C;0A32 0A3C;0A32 0A3C;0A32 0A3C; # (ਲ਼; ਲ◌਼; ਲ◌਼; ਲ◌਼; ਲ◌਼; ) GURMUKHI LETTER LLA +0A36;0A38 0A3C;0A38 0A3C;0A38 0A3C;0A38 0A3C; # (ਸ਼; ਸ◌਼; ਸ◌਼; ਸ◌਼; ਸ◌਼; ) GURMUKHI LETTER SHA +0A59;0A16 0A3C;0A16 0A3C;0A16 0A3C;0A16 0A3C; # (ਖ਼; ਖ◌਼; ਖ◌਼; ਖ◌਼; ਖ◌਼; ) GURMUKHI LETTER KHHA +0A5A;0A17 0A3C;0A17 0A3C;0A17 0A3C;0A17 0A3C; # (ਗ਼; ਗ◌਼; ਗ◌਼; ਗ◌਼; ਗ◌਼; ) GURMUKHI LETTER GHHA +0A5B;0A1C 0A3C;0A1C 0A3C;0A1C 0A3C;0A1C 0A3C; # (ਜ਼; ਜ◌਼; ਜ◌਼; ਜ◌਼; ਜ◌਼; ) GURMUKHI LETTER ZA +0A5E;0A2B 0A3C;0A2B 0A3C;0A2B 0A3C;0A2B 0A3C; # (ਫ਼; ਫ◌਼; ਫ◌਼; ਫ◌਼; ਫ◌਼; ) GURMUKHI LETTER FA +0B48;0B48;0B47 0B56;0B48;0B47 0B56; # (ୈ; ୈ; େ◌ୖ; ୈ; େ◌ୖ; ) ORIYA VOWEL SIGN AI +0B4B;0B4B;0B47 0B3E;0B4B;0B47 0B3E; # (ୋ; ୋ; ୋ; ୋ; ୋ; ) ORIYA VOWEL SIGN O +0B4C;0B4C;0B47 0B57;0B4C;0B47 0B57; # (ୌ; ୌ; ୌ; ୌ; ୌ; ) ORIYA VOWEL SIGN AU +0B5C;0B21 0B3C;0B21 0B3C;0B21 0B3C;0B21 0B3C; # (ଡ଼; ଡ◌଼; ଡ◌଼; ଡ◌଼; ଡ◌଼; ) ORIYA LETTER RRA +0B5D;0B22 0B3C;0B22 0B3C;0B22 0B3C;0B22 0B3C; # (ଢ଼; ଢ◌଼; ଢ◌଼; ଢ◌଼; ଢ◌଼; ) ORIYA LETTER RHA +0B94;0B94;0B92 0BD7;0B94;0B92 0BD7; # (ஔ; ஔ; ஔ; ஔ; ஔ; ) TAMIL LETTER AU +0BCA;0BCA;0BC6 0BBE;0BCA;0BC6 0BBE; # (ொ; ொ; ொ; ொ; ொ; ) TAMIL VOWEL SIGN O +0BCB;0BCB;0BC7 0BBE;0BCB;0BC7 0BBE; # (ோ; ோ; ோ; ோ; ோ; ) TAMIL VOWEL SIGN OO +0BCC;0BCC;0BC6 0BD7;0BCC;0BC6 0BD7; # (ௌ; ௌ; ௌ; ௌ; ௌ; ) TAMIL VOWEL SIGN AU +0C48;0C48;0C46 0C56;0C48;0C46 0C56; # (◌ై; ◌ై; ◌ె◌ౖ; ◌ై; ◌ె◌ౖ; ) TELUGU VOWEL SIGN AI +0CC0;0CC0;0CBF 0CD5;0CC0;0CBF 0CD5; # (ೀ; ೀ; ◌ೀ; ೀ; ◌ೀ; ) KANNADA VOWEL SIGN II +0CC7;0CC7;0CC6 0CD5;0CC7;0CC6 0CD5; # (ೇ; ೇ; ◌ೇ; ೇ; ◌ೇ; ) KANNADA VOWEL SIGN EE +0CC8;0CC8;0CC6 0CD6;0CC8;0CC6 0CD6; # (ೈ; ೈ; ◌ೈ; ೈ; ◌ೈ; ) KANNADA VOWEL SIGN AI +0CCA;0CCA;0CC6 0CC2;0CCA;0CC6 0CC2; # (ೊ; ೊ; ◌ೊ; ೊ; ◌ೊ; ) KANNADA VOWEL SIGN O +0CCB;0CCB;0CC6 0CC2 0CD5;0CCB;0CC6 0CC2 0CD5; # (ೋ; ೋ; ◌ೋ; ೋ; ◌ೋ; ) KANNADA VOWEL SIGN OO +0D4A;0D4A;0D46 0D3E;0D4A;0D46 0D3E; # (ൊ; ൊ; ൊ; ൊ; ൊ; ) MALAYALAM VOWEL SIGN O +0D4B;0D4B;0D47 0D3E;0D4B;0D47 0D3E; # (ോ; ോ; ോ; ോ; ോ; ) MALAYALAM VOWEL SIGN OO +0D4C;0D4C;0D46 0D57;0D4C;0D46 0D57; # (ൌ; ൌ; ൌ; ൌ; ൌ; ) MALAYALAM VOWEL SIGN AU +0DDA;0DDA;0DD9 0DCA;0DDA;0DD9 0DCA; # (ේ; ේ; ෙ◌්; ේ; ෙ◌්; ) SINHALA VOWEL SIGN DIGA KOMBUVA +0DDC;0DDC;0DD9 0DCF;0DDC;0DD9 0DCF; # (ො; ො; ො; ො; ො; ) SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA +0DDD;0DDD;0DD9 0DCF 0DCA;0DDD;0DD9 0DCF 0DCA; # (ෝ; ෝ; ො◌්; ෝ; ො◌්; ) SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DDE;0DDE;0DD9 0DDF;0DDE;0DD9 0DDF; # (ෞ; ෞ; ෞ; ෞ; ෞ; ) SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA +0E33;0E33;0E33;0E4D 0E32;0E4D 0E32; # (ำ; ำ; ำ; ◌ํา; ◌ํา; ) THAI CHARACTER SARA AM +0EB3;0EB3;0EB3;0ECD 0EB2;0ECD 0EB2; # (ຳ; ຳ; ຳ; ◌ໍາ; ◌ໍາ; ) LAO VOWEL SIGN AM +0EDC;0EDC;0EDC;0EAB 0E99;0EAB 0E99; # (ໜ; ໜ; ໜ; ຫນ; ຫນ; ) LAO HO NO +0EDD;0EDD;0EDD;0EAB 0EA1;0EAB 0EA1; # (ໝ; ໝ; ໝ; ຫມ; ຫມ; ) LAO HO MO +0F0C;0F0C;0F0C;0F0B;0F0B; # (༌; ༌; ༌; ་; ་; ) TIBETAN MARK DELIMITER TSHEG BSTAR +0F43;0F42 0FB7;0F42 0FB7;0F42 0FB7;0F42 0FB7; # (གྷ; ག◌ྷ; ག◌ྷ; ག◌ྷ; ག◌ྷ; ) TIBETAN LETTER GHA +0F4D;0F4C 0FB7;0F4C 0FB7;0F4C 0FB7;0F4C 0FB7; # (ཌྷ; ཌ◌ྷ; ཌ◌ྷ; ཌ◌ྷ; ཌ◌ྷ; ) TIBETAN LETTER DDHA +0F52;0F51 0FB7;0F51 0FB7;0F51 0FB7;0F51 0FB7; # (དྷ; ད◌ྷ; ད◌ྷ; ད◌ྷ; ད◌ྷ; ) TIBETAN LETTER DHA +0F57;0F56 0FB7;0F56 0FB7;0F56 0FB7;0F56 0FB7; # (བྷ; བ◌ྷ; བ◌ྷ; བ◌ྷ; བ◌ྷ; ) TIBETAN LETTER BHA +0F5C;0F5B 0FB7;0F5B 0FB7;0F5B 0FB7;0F5B 0FB7; # (ཛྷ; ཛ◌ྷ; ཛ◌ྷ; ཛ◌ྷ; ཛ◌ྷ; ) TIBETAN LETTER DZHA +0F69;0F40 0FB5;0F40 0FB5;0F40 0FB5;0F40 0FB5; # (ཀྵ; ཀ◌ྵ; ཀ◌ྵ; ཀ◌ྵ; ཀ◌ྵ; ) TIBETAN LETTER KSSA +0F73;0F71 0F72;0F71 0F72;0F71 0F72;0F71 0F72; # (◌ཱི; ◌ཱ◌ི; ◌ཱ◌ི; ◌ཱ◌ི; ◌ཱ◌ི; ) TIBETAN VOWEL SIGN II +0F75;0F71 0F74;0F71 0F74;0F71 0F74;0F71 0F74; # (◌ཱུ; ◌ཱ◌ུ; ◌ཱ◌ུ; ◌ཱ◌ུ; ◌ཱ◌ུ; ) TIBETAN VOWEL SIGN UU +0F76;0FB2 0F80;0FB2 0F80;0FB2 0F80;0FB2 0F80; # (◌ྲྀ; ◌ྲ◌ྀ; ◌ྲ◌ྀ; ◌ྲ◌ྀ; ◌ྲ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC R +0F77;0F77;0F77;0FB2 0F71 0F80;0FB2 0F71 0F80; # (◌ཷ; ◌ཷ; ◌ཷ; ◌ྲ◌ཱ◌ྀ; ◌ྲ◌ཱ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC RR +0F78;0FB3 0F80;0FB3 0F80;0FB3 0F80;0FB3 0F80; # (◌ླྀ; ◌ླ◌ྀ; ◌ླ◌ྀ; ◌ླ◌ྀ; ◌ླ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC L +0F79;0F79;0F79;0FB3 0F71 0F80;0FB3 0F71 0F80; # (◌ཹ; ◌ཹ; ◌ཹ; ◌ླ◌ཱ◌ྀ; ◌ླ◌ཱ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC LL +0F81;0F71 0F80;0F71 0F80;0F71 0F80;0F71 0F80; # (◌ཱྀ; ◌ཱ◌ྀ; ◌ཱ◌ྀ; ◌ཱ◌ྀ; ◌ཱ◌ྀ; ) TIBETAN VOWEL SIGN REVERSED II +0F93;0F92 0FB7;0F92 0FB7;0F92 0FB7;0F92 0FB7; # (◌ྒྷ; ◌ྒ◌ྷ; ◌ྒ◌ྷ; ◌ྒ◌ྷ; ◌ྒ◌ྷ; ) TIBETAN SUBJOINED LETTER GHA +0F9D;0F9C 0FB7;0F9C 0FB7;0F9C 0FB7;0F9C 0FB7; # (◌ྜྷ; ◌ྜ◌ྷ; ◌ྜ◌ྷ; ◌ྜ◌ྷ; ◌ྜ◌ྷ; ) TIBETAN SUBJOINED LETTER DDHA +0FA2;0FA1 0FB7;0FA1 0FB7;0FA1 0FB7;0FA1 0FB7; # (◌ྡྷ; ◌ྡ◌ྷ; ◌ྡ◌ྷ; ◌ྡ◌ྷ; ◌ྡ◌ྷ; ) TIBETAN SUBJOINED LETTER DHA +0FA7;0FA6 0FB7;0FA6 0FB7;0FA6 0FB7;0FA6 0FB7; # (◌ྦྷ; ◌ྦ◌ྷ; ◌ྦ◌ྷ; ◌ྦ◌ྷ; ◌ྦ◌ྷ; ) TIBETAN SUBJOINED LETTER BHA +0FAC;0FAB 0FB7;0FAB 0FB7;0FAB 0FB7;0FAB 0FB7; # (◌ྫྷ; ◌ྫ◌ྷ; ◌ྫ◌ྷ; ◌ྫ◌ྷ; ◌ྫ◌ྷ; ) TIBETAN SUBJOINED LETTER DZHA +0FB9;0F90 0FB5;0F90 0FB5;0F90 0FB5;0F90 0FB5; # (◌ྐྵ; ◌ྐ◌ྵ; ◌ྐ◌ྵ; ◌ྐ◌ྵ; ◌ྐ◌ྵ; ) TIBETAN SUBJOINED LETTER KSSA +1026;1026;1025 102E;1026;1025 102E; # (ဦ; ဦ; ဥ◌ီ; ဦ; ဥ◌ီ; ) MYANMAR LETTER UU +1E00;1E00;0041 0325;1E00;0041 0325; # (Ḁ; Ḁ; A◌̥; Ḁ; A◌̥; ) LATIN CAPITAL LETTER A WITH RING BELOW +1E01;1E01;0061 0325;1E01;0061 0325; # (ḁ; ḁ; a◌̥; ḁ; a◌̥; ) LATIN SMALL LETTER A WITH RING BELOW +1E02;1E02;0042 0307;1E02;0042 0307; # (Ḃ; Ḃ; B◌̇; Ḃ; B◌̇; ) LATIN CAPITAL LETTER B WITH DOT ABOVE +1E03;1E03;0062 0307;1E03;0062 0307; # (ḃ; ḃ; b◌̇; ḃ; b◌̇; ) LATIN SMALL LETTER B WITH DOT ABOVE +1E04;1E04;0042 0323;1E04;0042 0323; # (Ḅ; Ḅ; B◌̣; Ḅ; B◌̣; ) LATIN CAPITAL LETTER B WITH DOT BELOW +1E05;1E05;0062 0323;1E05;0062 0323; # (ḅ; ḅ; b◌̣; ḅ; b◌̣; ) LATIN SMALL LETTER B WITH DOT BELOW +1E06;1E06;0042 0331;1E06;0042 0331; # (Ḇ; Ḇ; B◌̱; Ḇ; B◌̱; ) LATIN CAPITAL LETTER B WITH LINE BELOW +1E07;1E07;0062 0331;1E07;0062 0331; # (ḇ; ḇ; b◌̱; ḇ; b◌̱; ) LATIN SMALL LETTER B WITH LINE BELOW +1E08;1E08;0043 0327 0301;1E08;0043 0327 0301; # (Ḉ; Ḉ; C◌̧◌́; Ḉ; C◌̧◌́; ) LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +1E09;1E09;0063 0327 0301;1E09;0063 0327 0301; # (ḉ; ḉ; c◌̧◌́; ḉ; c◌̧◌́; ) LATIN SMALL LETTER C WITH CEDILLA AND ACUTE +1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0B;1E0B;0064 0307;1E0B;0064 0307; # (ḋ; ḋ; d◌̇; ḋ; d◌̇; ) LATIN SMALL LETTER D WITH DOT ABOVE +1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +1E0D;1E0D;0064 0323;1E0D;0064 0323; # (ḍ; ḍ; d◌̣; ḍ; d◌̣; ) LATIN SMALL LETTER D WITH DOT BELOW +1E0E;1E0E;0044 0331;1E0E;0044 0331; # (Ḏ; Ḏ; D◌̱; Ḏ; D◌̱; ) LATIN CAPITAL LETTER D WITH LINE BELOW +1E0F;1E0F;0064 0331;1E0F;0064 0331; # (ḏ; ḏ; d◌̱; ḏ; d◌̱; ) LATIN SMALL LETTER D WITH LINE BELOW +1E10;1E10;0044 0327;1E10;0044 0327; # (Ḑ; Ḑ; D◌̧; Ḑ; D◌̧; ) LATIN CAPITAL LETTER D WITH CEDILLA +1E11;1E11;0064 0327;1E11;0064 0327; # (ḑ; ḑ; d◌̧; ḑ; d◌̧; ) LATIN SMALL LETTER D WITH CEDILLA +1E12;1E12;0044 032D;1E12;0044 032D; # (Ḓ; Ḓ; D◌̭; Ḓ; D◌̭; ) LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E13;1E13;0064 032D;1E13;0064 032D; # (ḓ; ḓ; d◌̭; ḓ; d◌̭; ) LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW +1E14;1E14;0045 0304 0300;1E14;0045 0304 0300; # (Ḕ; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1E15;1E15;0065 0304 0300;1E15;0065 0304 0300; # (ḕ; ḕ; e◌̄◌̀; ḕ; e◌̄◌̀; ) LATIN SMALL LETTER E WITH MACRON AND GRAVE +1E16;1E16;0045 0304 0301;1E16;0045 0304 0301; # (Ḗ; Ḗ; E◌̄◌́; Ḗ; E◌̄◌́; ) LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E17;1E17;0065 0304 0301;1E17;0065 0304 0301; # (ḗ; ḗ; e◌̄◌́; ḗ; e◌̄◌́; ) LATIN SMALL LETTER E WITH MACRON AND ACUTE +1E18;1E18;0045 032D;1E18;0045 032D; # (Ḙ; Ḙ; E◌̭; Ḙ; E◌̭; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E19;1E19;0065 032D;1E19;0065 032D; # (ḙ; ḙ; e◌̭; ḙ; e◌̭; ) LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW +1E1A;1E1A;0045 0330;1E1A;0045 0330; # (Ḛ; Ḛ; E◌̰; Ḛ; E◌̰; ) LATIN CAPITAL LETTER E WITH TILDE BELOW +1E1B;1E1B;0065 0330;1E1B;0065 0330; # (ḛ; ḛ; e◌̰; ḛ; e◌̰; ) LATIN SMALL LETTER E WITH TILDE BELOW +1E1C;1E1C;0045 0327 0306;1E1C;0045 0327 0306; # (Ḝ; Ḝ; E◌̧◌̆; Ḝ; E◌̧◌̆; ) LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +1E1D;1E1D;0065 0327 0306;1E1D;0065 0327 0306; # (ḝ; ḝ; e◌̧◌̆; ḝ; e◌̧◌̆; ) LATIN SMALL LETTER E WITH CEDILLA AND BREVE +1E1E;1E1E;0046 0307;1E1E;0046 0307; # (Ḟ; Ḟ; F◌̇; Ḟ; F◌̇; ) LATIN CAPITAL LETTER F WITH DOT ABOVE +1E1F;1E1F;0066 0307;1E1F;0066 0307; # (ḟ; ḟ; f◌̇; ḟ; f◌̇; ) LATIN SMALL LETTER F WITH DOT ABOVE +1E20;1E20;0047 0304;1E20;0047 0304; # (Ḡ; Ḡ; G◌̄; Ḡ; G◌̄; ) LATIN CAPITAL LETTER G WITH MACRON +1E21;1E21;0067 0304;1E21;0067 0304; # (ḡ; ḡ; g◌̄; ḡ; g◌̄; ) LATIN SMALL LETTER G WITH MACRON +1E22;1E22;0048 0307;1E22;0048 0307; # (Ḣ; Ḣ; H◌̇; Ḣ; H◌̇; ) LATIN CAPITAL LETTER H WITH DOT ABOVE +1E23;1E23;0068 0307;1E23;0068 0307; # (ḣ; ḣ; h◌̇; ḣ; h◌̇; ) LATIN SMALL LETTER H WITH DOT ABOVE +1E24;1E24;0048 0323;1E24;0048 0323; # (Ḥ; Ḥ; H◌̣; Ḥ; H◌̣; ) LATIN CAPITAL LETTER H WITH DOT BELOW +1E25;1E25;0068 0323;1E25;0068 0323; # (ḥ; ḥ; h◌̣; ḥ; h◌̣; ) LATIN SMALL LETTER H WITH DOT BELOW +1E26;1E26;0048 0308;1E26;0048 0308; # (Ḧ; Ḧ; H◌̈; Ḧ; H◌̈; ) LATIN CAPITAL LETTER H WITH DIAERESIS +1E27;1E27;0068 0308;1E27;0068 0308; # (ḧ; ḧ; h◌̈; ḧ; h◌̈; ) LATIN SMALL LETTER H WITH DIAERESIS +1E28;1E28;0048 0327;1E28;0048 0327; # (Ḩ; Ḩ; H◌̧; Ḩ; H◌̧; ) LATIN CAPITAL LETTER H WITH CEDILLA +1E29;1E29;0068 0327;1E29;0068 0327; # (ḩ; ḩ; h◌̧; ḩ; h◌̧; ) LATIN SMALL LETTER H WITH CEDILLA +1E2A;1E2A;0048 032E;1E2A;0048 032E; # (Ḫ; Ḫ; H◌̮; Ḫ; H◌̮; ) LATIN CAPITAL LETTER H WITH BREVE BELOW +1E2B;1E2B;0068 032E;1E2B;0068 032E; # (ḫ; ḫ; h◌̮; ḫ; h◌̮; ) LATIN SMALL LETTER H WITH BREVE BELOW +1E2C;1E2C;0049 0330;1E2C;0049 0330; # (Ḭ; Ḭ; I◌̰; Ḭ; I◌̰; ) LATIN CAPITAL LETTER I WITH TILDE BELOW +1E2D;1E2D;0069 0330;1E2D;0069 0330; # (ḭ; ḭ; i◌̰; ḭ; i◌̰; ) LATIN SMALL LETTER I WITH TILDE BELOW +1E2E;1E2E;0049 0308 0301;1E2E;0049 0308 0301; # (Ḯ; Ḯ; I◌̈◌́; Ḯ; I◌̈◌́; ) LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +1E2F;1E2F;0069 0308 0301;1E2F;0069 0308 0301; # (ḯ; ḯ; i◌̈◌́; ḯ; i◌̈◌́; ) LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE +1E30;1E30;004B 0301;1E30;004B 0301; # (Ḱ; Ḱ; K◌́; Ḱ; K◌́; ) LATIN CAPITAL LETTER K WITH ACUTE +1E31;1E31;006B 0301;1E31;006B 0301; # (ḱ; ḱ; k◌́; ḱ; k◌́; ) LATIN SMALL LETTER K WITH ACUTE +1E32;1E32;004B 0323;1E32;004B 0323; # (Ḳ; Ḳ; K◌̣; Ḳ; K◌̣; ) LATIN CAPITAL LETTER K WITH DOT BELOW +1E33;1E33;006B 0323;1E33;006B 0323; # (ḳ; ḳ; k◌̣; ḳ; k◌̣; ) LATIN SMALL LETTER K WITH DOT BELOW +1E34;1E34;004B 0331;1E34;004B 0331; # (Ḵ; Ḵ; K◌̱; Ḵ; K◌̱; ) LATIN CAPITAL LETTER K WITH LINE BELOW +1E35;1E35;006B 0331;1E35;006B 0331; # (ḵ; ḵ; k◌̱; ḵ; k◌̱; ) LATIN SMALL LETTER K WITH LINE BELOW +1E36;1E36;004C 0323;1E36;004C 0323; # (Ḷ; Ḷ; L◌̣; Ḷ; L◌̣; ) LATIN CAPITAL LETTER L WITH DOT BELOW +1E37;1E37;006C 0323;1E37;006C 0323; # (ḷ; ḷ; l◌̣; ḷ; l◌̣; ) LATIN SMALL LETTER L WITH DOT BELOW +1E38;1E38;004C 0323 0304;1E38;004C 0323 0304; # (Ḹ; Ḹ; L◌̣◌̄; Ḹ; L◌̣◌̄; ) LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E39;1E39;006C 0323 0304;1E39;006C 0323 0304; # (ḹ; ḹ; l◌̣◌̄; ḹ; l◌̣◌̄; ) LATIN SMALL LETTER L WITH DOT BELOW AND MACRON +1E3A;1E3A;004C 0331;1E3A;004C 0331; # (Ḻ; Ḻ; L◌̱; Ḻ; L◌̱; ) LATIN CAPITAL LETTER L WITH LINE BELOW +1E3B;1E3B;006C 0331;1E3B;006C 0331; # (ḻ; ḻ; l◌̱; ḻ; l◌̱; ) LATIN SMALL LETTER L WITH LINE BELOW +1E3C;1E3C;004C 032D;1E3C;004C 032D; # (Ḽ; Ḽ; L◌̭; Ḽ; L◌̭; ) LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3D;1E3D;006C 032D;1E3D;006C 032D; # (ḽ; ḽ; l◌̭; ḽ; l◌̭; ) LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW +1E3E;1E3E;004D 0301;1E3E;004D 0301; # (Ḿ; Ḿ; M◌́; Ḿ; M◌́; ) LATIN CAPITAL LETTER M WITH ACUTE +1E3F;1E3F;006D 0301;1E3F;006D 0301; # (ḿ; ḿ; m◌́; ḿ; m◌́; ) LATIN SMALL LETTER M WITH ACUTE +1E40;1E40;004D 0307;1E40;004D 0307; # (Ṁ; Ṁ; M◌̇; Ṁ; M◌̇; ) LATIN CAPITAL LETTER M WITH DOT ABOVE +1E41;1E41;006D 0307;1E41;006D 0307; # (ṁ; ṁ; m◌̇; ṁ; m◌̇; ) LATIN SMALL LETTER M WITH DOT ABOVE +1E42;1E42;004D 0323;1E42;004D 0323; # (Ṃ; Ṃ; M◌̣; Ṃ; M◌̣; ) LATIN CAPITAL LETTER M WITH DOT BELOW +1E43;1E43;006D 0323;1E43;006D 0323; # (ṃ; ṃ; m◌̣; ṃ; m◌̣; ) LATIN SMALL LETTER M WITH DOT BELOW +1E44;1E44;004E 0307;1E44;004E 0307; # (Ṅ; Ṅ; N◌̇; Ṅ; N◌̇; ) LATIN CAPITAL LETTER N WITH DOT ABOVE +1E45;1E45;006E 0307;1E45;006E 0307; # (ṅ; ṅ; n◌̇; ṅ; n◌̇; ) LATIN SMALL LETTER N WITH DOT ABOVE +1E46;1E46;004E 0323;1E46;004E 0323; # (Ṇ; Ṇ; N◌̣; Ṇ; N◌̣; ) LATIN CAPITAL LETTER N WITH DOT BELOW +1E47;1E47;006E 0323;1E47;006E 0323; # (ṇ; ṇ; n◌̣; ṇ; n◌̣; ) LATIN SMALL LETTER N WITH DOT BELOW +1E48;1E48;004E 0331;1E48;004E 0331; # (Ṉ; Ṉ; N◌̱; Ṉ; N◌̱; ) LATIN CAPITAL LETTER N WITH LINE BELOW +1E49;1E49;006E 0331;1E49;006E 0331; # (ṉ; ṉ; n◌̱; ṉ; n◌̱; ) LATIN SMALL LETTER N WITH LINE BELOW +1E4A;1E4A;004E 032D;1E4A;004E 032D; # (Ṋ; Ṋ; N◌̭; Ṋ; N◌̭; ) LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E4B;1E4B;006E 032D;1E4B;006E 032D; # (ṋ; ṋ; n◌̭; ṋ; n◌̭; ) LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW +1E4C;1E4C;004F 0303 0301;1E4C;004F 0303 0301; # (Ṍ; Ṍ; O◌̃◌́; Ṍ; O◌̃◌́; ) LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4D;1E4D;006F 0303 0301;1E4D;006F 0303 0301; # (ṍ; ṍ; o◌̃◌́; ṍ; o◌̃◌́; ) LATIN SMALL LETTER O WITH TILDE AND ACUTE +1E4E;1E4E;004F 0303 0308;1E4E;004F 0303 0308; # (Ṏ; Ṏ; O◌̃◌̈; Ṏ; O◌̃◌̈; ) LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +1E4F;1E4F;006F 0303 0308;1E4F;006F 0303 0308; # (ṏ; ṏ; o◌̃◌̈; ṏ; o◌̃◌̈; ) LATIN SMALL LETTER O WITH TILDE AND DIAERESIS +1E50;1E50;004F 0304 0300;1E50;004F 0304 0300; # (Ṑ; Ṑ; O◌̄◌̀; Ṑ; O◌̄◌̀; ) LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1E51;1E51;006F 0304 0300;1E51;006F 0304 0300; # (ṑ; ṑ; o◌̄◌̀; ṑ; o◌̄◌̀; ) LATIN SMALL LETTER O WITH MACRON AND GRAVE +1E52;1E52;004F 0304 0301;1E52;004F 0304 0301; # (Ṓ; Ṓ; O◌̄◌́; Ṓ; O◌̄◌́; ) LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E53;1E53;006F 0304 0301;1E53;006F 0304 0301; # (ṓ; ṓ; o◌̄◌́; ṓ; o◌̄◌́; ) LATIN SMALL LETTER O WITH MACRON AND ACUTE +1E54;1E54;0050 0301;1E54;0050 0301; # (Ṕ; Ṕ; P◌́; Ṕ; P◌́; ) LATIN CAPITAL LETTER P WITH ACUTE +1E55;1E55;0070 0301;1E55;0070 0301; # (ṕ; ṕ; p◌́; ṕ; p◌́; ) LATIN SMALL LETTER P WITH ACUTE +1E56;1E56;0050 0307;1E56;0050 0307; # (Ṗ; Ṗ; P◌̇; Ṗ; P◌̇; ) LATIN CAPITAL LETTER P WITH DOT ABOVE +1E57;1E57;0070 0307;1E57;0070 0307; # (ṗ; ṗ; p◌̇; ṗ; p◌̇; ) LATIN SMALL LETTER P WITH DOT ABOVE +1E58;1E58;0052 0307;1E58;0052 0307; # (Ṙ; Ṙ; R◌̇; Ṙ; R◌̇; ) LATIN CAPITAL LETTER R WITH DOT ABOVE +1E59;1E59;0072 0307;1E59;0072 0307; # (ṙ; ṙ; r◌̇; ṙ; r◌̇; ) LATIN SMALL LETTER R WITH DOT ABOVE +1E5A;1E5A;0052 0323;1E5A;0052 0323; # (Ṛ; Ṛ; R◌̣; Ṛ; R◌̣; ) LATIN CAPITAL LETTER R WITH DOT BELOW +1E5B;1E5B;0072 0323;1E5B;0072 0323; # (ṛ; ṛ; r◌̣; ṛ; r◌̣; ) LATIN SMALL LETTER R WITH DOT BELOW +1E5C;1E5C;0052 0323 0304;1E5C;0052 0323 0304; # (Ṝ; Ṝ; R◌̣◌̄; Ṝ; R◌̣◌̄; ) LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5D;1E5D;0072 0323 0304;1E5D;0072 0323 0304; # (ṝ; ṝ; r◌̣◌̄; ṝ; r◌̣◌̄; ) LATIN SMALL LETTER R WITH DOT BELOW AND MACRON +1E5E;1E5E;0052 0331;1E5E;0052 0331; # (Ṟ; Ṟ; R◌̱; Ṟ; R◌̱; ) LATIN CAPITAL LETTER R WITH LINE BELOW +1E5F;1E5F;0072 0331;1E5F;0072 0331; # (ṟ; ṟ; r◌̱; ṟ; r◌̱; ) LATIN SMALL LETTER R WITH LINE BELOW +1E60;1E60;0053 0307;1E60;0053 0307; # (Ṡ; Ṡ; S◌̇; Ṡ; S◌̇; ) LATIN CAPITAL LETTER S WITH DOT ABOVE +1E61;1E61;0073 0307;1E61;0073 0307; # (ṡ; ṡ; s◌̇; ṡ; s◌̇; ) LATIN SMALL LETTER S WITH DOT ABOVE +1E62;1E62;0053 0323;1E62;0053 0323; # (Ṣ; Ṣ; S◌̣; Ṣ; S◌̣; ) LATIN CAPITAL LETTER S WITH DOT BELOW +1E63;1E63;0073 0323;1E63;0073 0323; # (ṣ; ṣ; s◌̣; ṣ; s◌̣; ) LATIN SMALL LETTER S WITH DOT BELOW +1E64;1E64;0053 0301 0307;1E64;0053 0301 0307; # (Ṥ; Ṥ; S◌́◌̇; Ṥ; S◌́◌̇; ) LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +1E65;1E65;0073 0301 0307;1E65;0073 0301 0307; # (ṥ; ṥ; s◌́◌̇; ṥ; s◌́◌̇; ) LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE +1E66;1E66;0053 030C 0307;1E66;0053 030C 0307; # (Ṧ; Ṧ; S◌̌◌̇; Ṧ; S◌̌◌̇; ) LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E67;1E67;0073 030C 0307;1E67;0073 030C 0307; # (ṧ; ṧ; s◌̌◌̇; ṧ; s◌̌◌̇; ) LATIN SMALL LETTER S WITH CARON AND DOT ABOVE +1E68;1E68;0053 0323 0307;1E68;0053 0323 0307; # (Ṩ; Ṩ; S◌̣◌̇; Ṩ; S◌̣◌̇; ) LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +1E69;1E69;0073 0323 0307;1E69;0073 0323 0307; # (ṩ; ṩ; s◌̣◌̇; ṩ; s◌̣◌̇; ) LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6A;1E6A;0054 0307;1E6A;0054 0307; # (Ṫ; Ṫ; T◌̇; Ṫ; T◌̇; ) LATIN CAPITAL LETTER T WITH DOT ABOVE +1E6B;1E6B;0074 0307;1E6B;0074 0307; # (ṫ; ṫ; t◌̇; ṫ; t◌̇; ) LATIN SMALL LETTER T WITH DOT ABOVE +1E6C;1E6C;0054 0323;1E6C;0054 0323; # (Ṭ; Ṭ; T◌̣; Ṭ; T◌̣; ) LATIN CAPITAL LETTER T WITH DOT BELOW +1E6D;1E6D;0074 0323;1E6D;0074 0323; # (ṭ; ṭ; t◌̣; ṭ; t◌̣; ) LATIN SMALL LETTER T WITH DOT BELOW +1E6E;1E6E;0054 0331;1E6E;0054 0331; # (Ṯ; Ṯ; T◌̱; Ṯ; T◌̱; ) LATIN CAPITAL LETTER T WITH LINE BELOW +1E6F;1E6F;0074 0331;1E6F;0074 0331; # (ṯ; ṯ; t◌̱; ṯ; t◌̱; ) LATIN SMALL LETTER T WITH LINE BELOW +1E70;1E70;0054 032D;1E70;0054 032D; # (Ṱ; Ṱ; T◌̭; Ṱ; T◌̭; ) LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E71;1E71;0074 032D;1E71;0074 032D; # (ṱ; ṱ; t◌̭; ṱ; t◌̭; ) LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW +1E72;1E72;0055 0324;1E72;0055 0324; # (Ṳ; Ṳ; U◌̤; Ṳ; U◌̤; ) LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E73;1E73;0075 0324;1E73;0075 0324; # (ṳ; ṳ; u◌̤; ṳ; u◌̤; ) LATIN SMALL LETTER U WITH DIAERESIS BELOW +1E74;1E74;0055 0330;1E74;0055 0330; # (Ṵ; Ṵ; U◌̰; Ṵ; U◌̰; ) LATIN CAPITAL LETTER U WITH TILDE BELOW +1E75;1E75;0075 0330;1E75;0075 0330; # (ṵ; ṵ; u◌̰; ṵ; u◌̰; ) LATIN SMALL LETTER U WITH TILDE BELOW +1E76;1E76;0055 032D;1E76;0055 032D; # (Ṷ; Ṷ; U◌̭; Ṷ; U◌̭; ) LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E77;1E77;0075 032D;1E77;0075 032D; # (ṷ; ṷ; u◌̭; ṷ; u◌̭; ) LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW +1E78;1E78;0055 0303 0301;1E78;0055 0303 0301; # (Ṹ; Ṹ; U◌̃◌́; Ṹ; U◌̃◌́; ) LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +1E79;1E79;0075 0303 0301;1E79;0075 0303 0301; # (ṹ; ṹ; u◌̃◌́; ṹ; u◌̃◌́; ) LATIN SMALL LETTER U WITH TILDE AND ACUTE +1E7A;1E7A;0055 0304 0308;1E7A;0055 0304 0308; # (Ṻ; Ṻ; U◌̄◌̈; Ṻ; U◌̄◌̈; ) LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1E7B;1E7B;0075 0304 0308;1E7B;0075 0304 0308; # (ṻ; ṻ; u◌̄◌̈; ṻ; u◌̄◌̈; ) LATIN SMALL LETTER U WITH MACRON AND DIAERESIS +1E7C;1E7C;0056 0303;1E7C;0056 0303; # (Ṽ; Ṽ; V◌̃; Ṽ; V◌̃; ) LATIN CAPITAL LETTER V WITH TILDE +1E7D;1E7D;0076 0303;1E7D;0076 0303; # (ṽ; ṽ; v◌̃; ṽ; v◌̃; ) LATIN SMALL LETTER V WITH TILDE +1E7E;1E7E;0056 0323;1E7E;0056 0323; # (Ṿ; Ṿ; V◌̣; Ṿ; V◌̣; ) LATIN CAPITAL LETTER V WITH DOT BELOW +1E7F;1E7F;0076 0323;1E7F;0076 0323; # (ṿ; ṿ; v◌̣; ṿ; v◌̣; ) LATIN SMALL LETTER V WITH DOT BELOW +1E80;1E80;0057 0300;1E80;0057 0300; # (Ẁ; Ẁ; W◌̀; Ẁ; W◌̀; ) LATIN CAPITAL LETTER W WITH GRAVE +1E81;1E81;0077 0300;1E81;0077 0300; # (ẁ; ẁ; w◌̀; ẁ; w◌̀; ) LATIN SMALL LETTER W WITH GRAVE +1E82;1E82;0057 0301;1E82;0057 0301; # (Ẃ; Ẃ; W◌́; Ẃ; W◌́; ) LATIN CAPITAL LETTER W WITH ACUTE +1E83;1E83;0077 0301;1E83;0077 0301; # (ẃ; ẃ; w◌́; ẃ; w◌́; ) LATIN SMALL LETTER W WITH ACUTE +1E84;1E84;0057 0308;1E84;0057 0308; # (Ẅ; Ẅ; W◌̈; Ẅ; W◌̈; ) LATIN CAPITAL LETTER W WITH DIAERESIS +1E85;1E85;0077 0308;1E85;0077 0308; # (ẅ; ẅ; w◌̈; ẅ; w◌̈; ) LATIN SMALL LETTER W WITH DIAERESIS +1E86;1E86;0057 0307;1E86;0057 0307; # (Ẇ; Ẇ; W◌̇; Ẇ; W◌̇; ) LATIN CAPITAL LETTER W WITH DOT ABOVE +1E87;1E87;0077 0307;1E87;0077 0307; # (ẇ; ẇ; w◌̇; ẇ; w◌̇; ) LATIN SMALL LETTER W WITH DOT ABOVE +1E88;1E88;0057 0323;1E88;0057 0323; # (Ẉ; Ẉ; W◌̣; Ẉ; W◌̣; ) LATIN CAPITAL LETTER W WITH DOT BELOW +1E89;1E89;0077 0323;1E89;0077 0323; # (ẉ; ẉ; w◌̣; ẉ; w◌̣; ) LATIN SMALL LETTER W WITH DOT BELOW +1E8A;1E8A;0058 0307;1E8A;0058 0307; # (Ẋ; Ẋ; X◌̇; Ẋ; X◌̇; ) LATIN CAPITAL LETTER X WITH DOT ABOVE +1E8B;1E8B;0078 0307;1E8B;0078 0307; # (ẋ; ẋ; x◌̇; ẋ; x◌̇; ) LATIN SMALL LETTER X WITH DOT ABOVE +1E8C;1E8C;0058 0308;1E8C;0058 0308; # (Ẍ; Ẍ; X◌̈; Ẍ; X◌̈; ) LATIN CAPITAL LETTER X WITH DIAERESIS +1E8D;1E8D;0078 0308;1E8D;0078 0308; # (ẍ; ẍ; x◌̈; ẍ; x◌̈; ) LATIN SMALL LETTER X WITH DIAERESIS +1E8E;1E8E;0059 0307;1E8E;0059 0307; # (Ẏ; Ẏ; Y◌̇; Ẏ; Y◌̇; ) LATIN CAPITAL LETTER Y WITH DOT ABOVE +1E8F;1E8F;0079 0307;1E8F;0079 0307; # (ẏ; ẏ; y◌̇; ẏ; y◌̇; ) LATIN SMALL LETTER Y WITH DOT ABOVE +1E90;1E90;005A 0302;1E90;005A 0302; # (Ẑ; Ẑ; Z◌̂; Ẑ; Z◌̂; ) LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +1E91;1E91;007A 0302;1E91;007A 0302; # (ẑ; ẑ; z◌̂; ẑ; z◌̂; ) LATIN SMALL LETTER Z WITH CIRCUMFLEX +1E92;1E92;005A 0323;1E92;005A 0323; # (Ẓ; Ẓ; Z◌̣; Ẓ; Z◌̣; ) LATIN CAPITAL LETTER Z WITH DOT BELOW +1E93;1E93;007A 0323;1E93;007A 0323; # (ẓ; ẓ; z◌̣; ẓ; z◌̣; ) LATIN SMALL LETTER Z WITH DOT BELOW +1E94;1E94;005A 0331;1E94;005A 0331; # (Ẕ; Ẕ; Z◌̱; Ẕ; Z◌̱; ) LATIN CAPITAL LETTER Z WITH LINE BELOW +1E95;1E95;007A 0331;1E95;007A 0331; # (ẕ; ẕ; z◌̱; ẕ; z◌̱; ) LATIN SMALL LETTER Z WITH LINE BELOW +1E96;1E96;0068 0331;1E96;0068 0331; # (ẖ; ẖ; h◌̱; ẖ; h◌̱; ) LATIN SMALL LETTER H WITH LINE BELOW +1E97;1E97;0074 0308;1E97;0074 0308; # (ẗ; ẗ; t◌̈; ẗ; t◌̈; ) LATIN SMALL LETTER T WITH DIAERESIS +1E98;1E98;0077 030A;1E98;0077 030A; # (ẘ; ẘ; w◌̊; ẘ; w◌̊; ) LATIN SMALL LETTER W WITH RING ABOVE +1E99;1E99;0079 030A;1E99;0079 030A; # (ẙ; ẙ; y◌̊; ẙ; y◌̊; ) LATIN SMALL LETTER Y WITH RING ABOVE +1E9A;1E9A;1E9A;0061 02BE;0061 02BE; # (ẚ; ẚ; ẚ; aʾ; aʾ; ) LATIN SMALL LETTER A WITH RIGHT HALF RING +1E9B;1E9B;017F 0307;1E61;0073 0307; # (ẛ; ẛ; ſ◌̇; ṡ; s◌̇; ) LATIN SMALL LETTER LONG S WITH DOT ABOVE +1EA0;1EA0;0041 0323;1EA0;0041 0323; # (Ạ; Ạ; A◌̣; Ạ; A◌̣; ) LATIN CAPITAL LETTER A WITH DOT BELOW +1EA1;1EA1;0061 0323;1EA1;0061 0323; # (ạ; ạ; a◌̣; ạ; a◌̣; ) LATIN SMALL LETTER A WITH DOT BELOW +1EA2;1EA2;0041 0309;1EA2;0041 0309; # (Ả; Ả; A◌̉; Ả; A◌̉; ) LATIN CAPITAL LETTER A WITH HOOK ABOVE +1EA3;1EA3;0061 0309;1EA3;0061 0309; # (ả; ả; a◌̉; ả; a◌̉; ) LATIN SMALL LETTER A WITH HOOK ABOVE +1EA4;1EA4;0041 0302 0301;1EA4;0041 0302 0301; # (Ấ; Ấ; A◌̂◌́; Ấ; A◌̂◌́; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA5;1EA5;0061 0302 0301;1EA5;0061 0302 0301; # (ấ; ấ; a◌̂◌́; ấ; a◌̂◌́; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA6;1EA6;0041 0302 0300;1EA6;0041 0302 0300; # (Ầ; Ầ; A◌̂◌̀; Ầ; A◌̂◌̀; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA7;1EA7;0061 0302 0300;1EA7;0061 0302 0300; # (ầ; ầ; a◌̂◌̀; ầ; a◌̂◌̀; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA8;1EA8;0041 0302 0309;1EA8;0041 0302 0309; # (Ẩ; Ẩ; A◌̂◌̉; Ẩ; A◌̂◌̉; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EA9;1EA9;0061 0302 0309;1EA9;0061 0302 0309; # (ẩ; ẩ; a◌̂◌̉; ẩ; a◌̂◌̉; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAA;1EAA;0041 0302 0303;1EAA;0041 0302 0303; # (Ẫ; Ẫ; A◌̂◌̃; Ẫ; A◌̂◌̃; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EAB;1EAB;0061 0302 0303;1EAB;0061 0302 0303; # (ẫ; ẫ; a◌̂◌̃; ẫ; a◌̂◌̃; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE +1EAC;1EAC;0041 0323 0302;1EAC;0041 0323 0302; # (Ậ; Ậ; A◌̣◌̂; Ậ; A◌̣◌̂; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAD;1EAD;0061 0323 0302;1EAD;0061 0323 0302; # (ậ; ậ; a◌̣◌̂; ậ; a◌̣◌̂; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAE;1EAE;0041 0306 0301;1EAE;0041 0306 0301; # (Ắ; Ắ; A◌̆◌́; Ắ; A◌̆◌́; ) LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EAF;1EAF;0061 0306 0301;1EAF;0061 0306 0301; # (ắ; ắ; a◌̆◌́; ắ; a◌̆◌́; ) LATIN SMALL LETTER A WITH BREVE AND ACUTE +1EB0;1EB0;0041 0306 0300;1EB0;0041 0306 0300; # (Ằ; Ằ; A◌̆◌̀; Ằ; A◌̆◌̀; ) LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB1;1EB1;0061 0306 0300;1EB1;0061 0306 0300; # (ằ; ằ; a◌̆◌̀; ằ; a◌̆◌̀; ) LATIN SMALL LETTER A WITH BREVE AND GRAVE +1EB2;1EB2;0041 0306 0309;1EB2;0041 0306 0309; # (Ẳ; Ẳ; A◌̆◌̉; Ẳ; A◌̆◌̉; ) LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +1EB3;1EB3;0061 0306 0309;1EB3;0061 0306 0309; # (ẳ; ẳ; a◌̆◌̉; ẳ; a◌̆◌̉; ) LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE +1EB4;1EB4;0041 0306 0303;1EB4;0041 0306 0303; # (Ẵ; Ẵ; A◌̆◌̃; Ẵ; A◌̆◌̃; ) LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB5;1EB5;0061 0306 0303;1EB5;0061 0306 0303; # (ẵ; ẵ; a◌̆◌̃; ẵ; a◌̆◌̃; ) LATIN SMALL LETTER A WITH BREVE AND TILDE +1EB6;1EB6;0041 0323 0306;1EB6;0041 0323 0306; # (Ặ; Ặ; A◌̣◌̆; Ặ; A◌̣◌̆; ) LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EB7;1EB7;0061 0323 0306;1EB7;0061 0323 0306; # (ặ; ặ; a◌̣◌̆; ặ; a◌̣◌̆; ) LATIN SMALL LETTER A WITH BREVE AND DOT BELOW +1EB8;1EB8;0045 0323;1EB8;0045 0323; # (Ẹ; Ẹ; E◌̣; Ẹ; E◌̣; ) LATIN CAPITAL LETTER E WITH DOT BELOW +1EB9;1EB9;0065 0323;1EB9;0065 0323; # (ẹ; ẹ; e◌̣; ẹ; e◌̣; ) LATIN SMALL LETTER E WITH DOT BELOW +1EBA;1EBA;0045 0309;1EBA;0045 0309; # (Ẻ; Ẻ; E◌̉; Ẻ; E◌̉; ) LATIN CAPITAL LETTER E WITH HOOK ABOVE +1EBB;1EBB;0065 0309;1EBB;0065 0309; # (ẻ; ẻ; e◌̉; ẻ; e◌̉; ) LATIN SMALL LETTER E WITH HOOK ABOVE +1EBC;1EBC;0045 0303;1EBC;0045 0303; # (Ẽ; Ẽ; E◌̃; Ẽ; E◌̃; ) LATIN CAPITAL LETTER E WITH TILDE +1EBD;1EBD;0065 0303;1EBD;0065 0303; # (ẽ; ẽ; e◌̃; ẽ; e◌̃; ) LATIN SMALL LETTER E WITH TILDE +1EBE;1EBE;0045 0302 0301;1EBE;0045 0302 0301; # (Ế; Ế; E◌̂◌́; Ế; E◌̂◌́; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EBF;1EBF;0065 0302 0301;1EBF;0065 0302 0301; # (ế; ế; e◌̂◌́; ế; e◌̂◌́; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC0;1EC0;0045 0302 0300;1EC0;0045 0302 0300; # (Ề; Ề; E◌̂◌̀; Ề; E◌̂◌̀; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC1;1EC1;0065 0302 0300;1EC1;0065 0302 0300; # (ề; ề; e◌̂◌̀; ề; e◌̂◌̀; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC2;1EC2;0045 0302 0309;1EC2;0045 0302 0309; # (Ể; Ể; E◌̂◌̉; Ể; E◌̂◌̉; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC3;1EC3;0065 0302 0309;1EC3;0065 0302 0309; # (ể; ể; e◌̂◌̉; ể; e◌̂◌̉; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC4;1EC4;0045 0302 0303;1EC4;0045 0302 0303; # (Ễ; Ễ; E◌̂◌̃; Ễ; E◌̂◌̃; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC5;1EC5;0065 0302 0303;1EC5;0065 0302 0303; # (ễ; ễ; e◌̂◌̃; ễ; e◌̂◌̃; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE +1EC6;1EC6;0045 0323 0302;1EC6;0045 0323 0302; # (Ệ; Ệ; E◌̣◌̂; Ệ; E◌̣◌̂; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC7;1EC7;0065 0323 0302;1EC7;0065 0323 0302; # (ệ; ệ; e◌̣◌̂; ệ; e◌̣◌̂; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC8;1EC8;0049 0309;1EC8;0049 0309; # (Ỉ; Ỉ; I◌̉; Ỉ; I◌̉; ) LATIN CAPITAL LETTER I WITH HOOK ABOVE +1EC9;1EC9;0069 0309;1EC9;0069 0309; # (ỉ; ỉ; i◌̉; ỉ; i◌̉; ) LATIN SMALL LETTER I WITH HOOK ABOVE +1ECA;1ECA;0049 0323;1ECA;0049 0323; # (Ị; Ị; I◌̣; Ị; I◌̣; ) LATIN CAPITAL LETTER I WITH DOT BELOW +1ECB;1ECB;0069 0323;1ECB;0069 0323; # (ị; ị; i◌̣; ị; i◌̣; ) LATIN SMALL LETTER I WITH DOT BELOW +1ECC;1ECC;004F 0323;1ECC;004F 0323; # (Ọ; Ọ; O◌̣; Ọ; O◌̣; ) LATIN CAPITAL LETTER O WITH DOT BELOW +1ECD;1ECD;006F 0323;1ECD;006F 0323; # (ọ; ọ; o◌̣; ọ; o◌̣; ) LATIN SMALL LETTER O WITH DOT BELOW +1ECE;1ECE;004F 0309;1ECE;004F 0309; # (Ỏ; Ỏ; O◌̉; Ỏ; O◌̉; ) LATIN CAPITAL LETTER O WITH HOOK ABOVE +1ECF;1ECF;006F 0309;1ECF;006F 0309; # (ỏ; ỏ; o◌̉; ỏ; o◌̉; ) LATIN SMALL LETTER O WITH HOOK ABOVE +1ED0;1ED0;004F 0302 0301;1ED0;004F 0302 0301; # (Ố; Ố; O◌̂◌́; Ố; O◌̂◌́; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED1;1ED1;006F 0302 0301;1ED1;006F 0302 0301; # (ố; ố; o◌̂◌́; ố; o◌̂◌́; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED2;1ED2;004F 0302 0300;1ED2;004F 0302 0300; # (Ồ; Ồ; O◌̂◌̀; Ồ; O◌̂◌̀; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED3;1ED3;006F 0302 0300;1ED3;006F 0302 0300; # (ồ; ồ; o◌̂◌̀; ồ; o◌̂◌̀; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED4;1ED4;004F 0302 0309;1ED4;004F 0302 0309; # (Ổ; Ổ; O◌̂◌̉; Ổ; O◌̂◌̉; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED5;1ED5;006F 0302 0309;1ED5;006F 0302 0309; # (ổ; ổ; o◌̂◌̉; ổ; o◌̂◌̉; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED6;1ED6;004F 0302 0303;1ED6;004F 0302 0303; # (Ỗ; Ỗ; O◌̂◌̃; Ỗ; O◌̂◌̃; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED7;1ED7;006F 0302 0303;1ED7;006F 0302 0303; # (ỗ; ỗ; o◌̂◌̃; ỗ; o◌̂◌̃; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE +1ED8;1ED8;004F 0323 0302;1ED8;004F 0323 0302; # (Ộ; Ộ; O◌̣◌̂; Ộ; O◌̣◌̂; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1ED9;1ED9;006F 0323 0302;1ED9;006F 0323 0302; # (ộ; ộ; o◌̣◌̂; ộ; o◌̣◌̂; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDA;1EDA;004F 031B 0301;1EDA;004F 031B 0301; # (Ớ; Ớ; O◌̛◌́; Ớ; O◌̛◌́; ) LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDB;1EDB;006F 031B 0301;1EDB;006F 031B 0301; # (ớ; ớ; o◌̛◌́; ớ; o◌̛◌́; ) LATIN SMALL LETTER O WITH HORN AND ACUTE +1EDC;1EDC;004F 031B 0300;1EDC;004F 031B 0300; # (Ờ; Ờ; O◌̛◌̀; Ờ; O◌̛◌̀; ) LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EDD;1EDD;006F 031B 0300;1EDD;006F 031B 0300; # (ờ; ờ; o◌̛◌̀; ờ; o◌̛◌̀; ) LATIN SMALL LETTER O WITH HORN AND GRAVE +1EDE;1EDE;004F 031B 0309;1EDE;004F 031B 0309; # (Ở; Ở; O◌̛◌̉; Ở; O◌̛◌̉; ) LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EDF;1EDF;006F 031B 0309;1EDF;006F 031B 0309; # (ở; ở; o◌̛◌̉; ở; o◌̛◌̉; ) LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE +1EE0;1EE0;004F 031B 0303;1EE0;004F 031B 0303; # (Ỡ; Ỡ; O◌̛◌̃; Ỡ; O◌̛◌̃; ) LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EE1;1EE1;006F 031B 0303;1EE1;006F 031B 0303; # (ỡ; ỡ; o◌̛◌̃; ỡ; o◌̛◌̃; ) LATIN SMALL LETTER O WITH HORN AND TILDE +1EE2;1EE2;004F 031B 0323;1EE2;004F 031B 0323; # (Ợ; Ợ; O◌̛◌̣; Ợ; O◌̛◌̣; ) LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1EE3;1EE3;006F 031B 0323;1EE3;006F 031B 0323; # (ợ; ợ; o◌̛◌̣; ợ; o◌̛◌̣; ) LATIN SMALL LETTER O WITH HORN AND DOT BELOW +1EE4;1EE4;0055 0323;1EE4;0055 0323; # (Ụ; Ụ; U◌̣; Ụ; U◌̣; ) LATIN CAPITAL LETTER U WITH DOT BELOW +1EE5;1EE5;0075 0323;1EE5;0075 0323; # (ụ; ụ; u◌̣; ụ; u◌̣; ) LATIN SMALL LETTER U WITH DOT BELOW +1EE6;1EE6;0055 0309;1EE6;0055 0309; # (Ủ; Ủ; U◌̉; Ủ; U◌̉; ) LATIN CAPITAL LETTER U WITH HOOK ABOVE +1EE7;1EE7;0075 0309;1EE7;0075 0309; # (ủ; ủ; u◌̉; ủ; u◌̉; ) LATIN SMALL LETTER U WITH HOOK ABOVE +1EE8;1EE8;0055 031B 0301;1EE8;0055 031B 0301; # (Ứ; Ứ; U◌̛◌́; Ứ; U◌̛◌́; ) LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EE9;1EE9;0075 031B 0301;1EE9;0075 031B 0301; # (ứ; ứ; u◌̛◌́; ứ; u◌̛◌́; ) LATIN SMALL LETTER U WITH HORN AND ACUTE +1EEA;1EEA;0055 031B 0300;1EEA;0055 031B 0300; # (Ừ; Ừ; U◌̛◌̀; Ừ; U◌̛◌̀; ) LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEB;1EEB;0075 031B 0300;1EEB;0075 031B 0300; # (ừ; ừ; u◌̛◌̀; ừ; u◌̛◌̀; ) LATIN SMALL LETTER U WITH HORN AND GRAVE +1EEC;1EEC;0055 031B 0309;1EEC;0055 031B 0309; # (Ử; Ử; U◌̛◌̉; Ử; U◌̛◌̉; ) LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EED;1EED;0075 031B 0309;1EED;0075 031B 0309; # (ử; ử; u◌̛◌̉; ử; u◌̛◌̉; ) LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE +1EEE;1EEE;0055 031B 0303;1EEE;0055 031B 0303; # (Ữ; Ữ; U◌̛◌̃; Ữ; U◌̛◌̃; ) LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EEF;1EEF;0075 031B 0303;1EEF;0075 031B 0303; # (ữ; ữ; u◌̛◌̃; ữ; u◌̛◌̃; ) LATIN SMALL LETTER U WITH HORN AND TILDE +1EF0;1EF0;0055 031B 0323;1EF0;0055 031B 0323; # (Ự; Ự; U◌̛◌̣; Ự; U◌̛◌̣; ) LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EF1;1EF1;0075 031B 0323;1EF1;0075 031B 0323; # (ự; ự; u◌̛◌̣; ự; u◌̛◌̣; ) LATIN SMALL LETTER U WITH HORN AND DOT BELOW +1EF2;1EF2;0059 0300;1EF2;0059 0300; # (Ỳ; Ỳ; Y◌̀; Ỳ; Y◌̀; ) LATIN CAPITAL LETTER Y WITH GRAVE +1EF3;1EF3;0079 0300;1EF3;0079 0300; # (ỳ; ỳ; y◌̀; ỳ; y◌̀; ) LATIN SMALL LETTER Y WITH GRAVE +1EF4;1EF4;0059 0323;1EF4;0059 0323; # (Ỵ; Ỵ; Y◌̣; Ỵ; Y◌̣; ) LATIN CAPITAL LETTER Y WITH DOT BELOW +1EF5;1EF5;0079 0323;1EF5;0079 0323; # (ỵ; ỵ; y◌̣; ỵ; y◌̣; ) LATIN SMALL LETTER Y WITH DOT BELOW +1EF6;1EF6;0059 0309;1EF6;0059 0309; # (Ỷ; Ỷ; Y◌̉; Ỷ; Y◌̉; ) LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF7;1EF7;0079 0309;1EF7;0079 0309; # (ỷ; ỷ; y◌̉; ỷ; y◌̉; ) LATIN SMALL LETTER Y WITH HOOK ABOVE +1EF8;1EF8;0059 0303;1EF8;0059 0303; # (Ỹ; Ỹ; Y◌̃; Ỹ; Y◌̃; ) LATIN CAPITAL LETTER Y WITH TILDE +1EF9;1EF9;0079 0303;1EF9;0079 0303; # (ỹ; ỹ; y◌̃; ỹ; y◌̃; ) LATIN SMALL LETTER Y WITH TILDE +1F00;1F00;03B1 0313;1F00;03B1 0313; # (ἀ; ἀ; α◌̓; ἀ; α◌̓; ) GREEK SMALL LETTER ALPHA WITH PSILI +1F01;1F01;03B1 0314;1F01;03B1 0314; # (ἁ; ἁ; α◌̔; ἁ; α◌̔; ) GREEK SMALL LETTER ALPHA WITH DASIA +1F02;1F02;03B1 0313 0300;1F02;03B1 0313 0300; # (ἂ; ἂ; α◌̓◌̀; ἂ; α◌̓◌̀; ) GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA +1F03;1F03;03B1 0314 0300;1F03;03B1 0314 0300; # (ἃ; ἃ; α◌̔◌̀; ἃ; α◌̔◌̀; ) GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA +1F04;1F04;03B1 0313 0301;1F04;03B1 0313 0301; # (ἄ; ἄ; α◌̓◌́; ἄ; α◌̓◌́; ) GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA +1F05;1F05;03B1 0314 0301;1F05;03B1 0314 0301; # (ἅ; ἅ; α◌̔◌́; ἅ; α◌̔◌́; ) GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA +1F06;1F06;03B1 0313 0342;1F06;03B1 0313 0342; # (ἆ; ἆ; α◌̓◌͂; ἆ; α◌̓◌͂; ) GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F07;1F07;03B1 0314 0342;1F07;03B1 0314 0342; # (ἇ; ἇ; α◌̔◌͂; ἇ; α◌̔◌͂; ) GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F08;1F08;0391 0313;1F08;0391 0313; # (Ἀ; Ἀ; Α◌̓; Ἀ; Α◌̓; ) GREEK CAPITAL LETTER ALPHA WITH PSILI +1F09;1F09;0391 0314;1F09;0391 0314; # (Ἁ; Ἁ; Α◌̔; Ἁ; Α◌̔; ) GREEK CAPITAL LETTER ALPHA WITH DASIA +1F0A;1F0A;0391 0313 0300;1F0A;0391 0313 0300; # (Ἂ; Ἂ; Α◌̓◌̀; Ἂ; Α◌̓◌̀; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F0B;1F0B;0391 0314 0300;1F0B;0391 0314 0300; # (Ἃ; Ἃ; Α◌̔◌̀; Ἃ; Α◌̔◌̀; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F0C;1F0C;0391 0313 0301;1F0C;0391 0313 0301; # (Ἄ; Ἄ; Α◌̓◌́; Ἄ; Α◌̓◌́; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F0D;1F0D;0391 0314 0301;1F0D;0391 0314 0301; # (Ἅ; Ἅ; Α◌̔◌́; Ἅ; Α◌̔◌́; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F0E;1F0E;0391 0313 0342;1F0E;0391 0313 0342; # (Ἆ; Ἆ; Α◌̓◌͂; Ἆ; Α◌̓◌͂; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0F;1F0F;0391 0314 0342;1F0F;0391 0314 0342; # (Ἇ; Ἇ; Α◌̔◌͂; Ἇ; Α◌̔◌͂; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F10;1F10;03B5 0313;1F10;03B5 0313; # (ἐ; ἐ; ε◌̓; ἐ; ε◌̓; ) GREEK SMALL LETTER EPSILON WITH PSILI +1F11;1F11;03B5 0314;1F11;03B5 0314; # (ἑ; ἑ; ε◌̔; ἑ; ε◌̔; ) GREEK SMALL LETTER EPSILON WITH DASIA +1F12;1F12;03B5 0313 0300;1F12;03B5 0313 0300; # (ἒ; ἒ; ε◌̓◌̀; ἒ; ε◌̓◌̀; ) GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA +1F13;1F13;03B5 0314 0300;1F13;03B5 0314 0300; # (ἓ; ἓ; ε◌̔◌̀; ἓ; ε◌̔◌̀; ) GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA +1F14;1F14;03B5 0313 0301;1F14;03B5 0313 0301; # (ἔ; ἔ; ε◌̓◌́; ἔ; ε◌̓◌́; ) GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA +1F15;1F15;03B5 0314 0301;1F15;03B5 0314 0301; # (ἕ; ἕ; ε◌̔◌́; ἕ; ε◌̔◌́; ) GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F18;1F18;0395 0313;1F18;0395 0313; # (Ἐ; Ἐ; Ε◌̓; Ἐ; Ε◌̓; ) GREEK CAPITAL LETTER EPSILON WITH PSILI +1F19;1F19;0395 0314;1F19;0395 0314; # (Ἑ; Ἑ; Ε◌̔; Ἑ; Ε◌̔; ) GREEK CAPITAL LETTER EPSILON WITH DASIA +1F1A;1F1A;0395 0313 0300;1F1A;0395 0313 0300; # (Ἒ; Ἒ; Ε◌̓◌̀; Ἒ; Ε◌̓◌̀; ) GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F1B;1F1B;0395 0314 0300;1F1B;0395 0314 0300; # (Ἓ; Ἓ; Ε◌̔◌̀; Ἓ; Ε◌̔◌̀; ) GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +1F1C;1F1C;0395 0313 0301;1F1C;0395 0313 0301; # (Ἔ; Ἔ; Ε◌̓◌́; Ἔ; Ε◌̓◌́; ) GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F1D;1F1D;0395 0314 0301;1F1D;0395 0314 0301; # (Ἕ; Ἕ; Ε◌̔◌́; Ἕ; Ε◌̔◌́; ) GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F20;1F20;03B7 0313;1F20;03B7 0313; # (ἠ; ἠ; η◌̓; ἠ; η◌̓; ) GREEK SMALL LETTER ETA WITH PSILI +1F21;1F21;03B7 0314;1F21;03B7 0314; # (ἡ; ἡ; η◌̔; ἡ; η◌̔; ) GREEK SMALL LETTER ETA WITH DASIA +1F22;1F22;03B7 0313 0300;1F22;03B7 0313 0300; # (ἢ; ἢ; η◌̓◌̀; ἢ; η◌̓◌̀; ) GREEK SMALL LETTER ETA WITH PSILI AND VARIA +1F23;1F23;03B7 0314 0300;1F23;03B7 0314 0300; # (ἣ; ἣ; η◌̔◌̀; ἣ; η◌̔◌̀; ) GREEK SMALL LETTER ETA WITH DASIA AND VARIA +1F24;1F24;03B7 0313 0301;1F24;03B7 0313 0301; # (ἤ; ἤ; η◌̓◌́; ἤ; η◌̓◌́; ) GREEK SMALL LETTER ETA WITH PSILI AND OXIA +1F25;1F25;03B7 0314 0301;1F25;03B7 0314 0301; # (ἥ; ἥ; η◌̔◌́; ἥ; η◌̔◌́; ) GREEK SMALL LETTER ETA WITH DASIA AND OXIA +1F26;1F26;03B7 0313 0342;1F26;03B7 0313 0342; # (ἦ; ἦ; η◌̓◌͂; ἦ; η◌̓◌͂; ) GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI +1F27;1F27;03B7 0314 0342;1F27;03B7 0314 0342; # (ἧ; ἧ; η◌̔◌͂; ἧ; η◌̔◌͂; ) GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI +1F28;1F28;0397 0313;1F28;0397 0313; # (Ἠ; Ἠ; Η◌̓; Ἠ; Η◌̓; ) GREEK CAPITAL LETTER ETA WITH PSILI +1F29;1F29;0397 0314;1F29;0397 0314; # (Ἡ; Ἡ; Η◌̔; Ἡ; Η◌̔; ) GREEK CAPITAL LETTER ETA WITH DASIA +1F2A;1F2A;0397 0313 0300;1F2A;0397 0313 0300; # (Ἢ; Ἢ; Η◌̓◌̀; Ἢ; Η◌̓◌̀; ) GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F2B;1F2B;0397 0314 0300;1F2B;0397 0314 0300; # (Ἣ; Ἣ; Η◌̔◌̀; Ἣ; Η◌̔◌̀; ) GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F2C;1F2C;0397 0313 0301;1F2C;0397 0313 0301; # (Ἤ; Ἤ; Η◌̓◌́; Ἤ; Η◌̓◌́; ) GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F2D;1F2D;0397 0314 0301;1F2D;0397 0314 0301; # (Ἥ; Ἥ; Η◌̔◌́; Ἥ; Η◌̔◌́; ) GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F2E;1F2E;0397 0313 0342;1F2E;0397 0313 0342; # (Ἦ; Ἦ; Η◌̓◌͂; Ἦ; Η◌̓◌͂; ) GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F2F;1F2F;0397 0314 0342;1F2F;0397 0314 0342; # (Ἧ; Ἧ; Η◌̔◌͂; Ἧ; Η◌̔◌͂; ) GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F30;1F30;03B9 0313;1F30;03B9 0313; # (ἰ; ἰ; ι◌̓; ἰ; ι◌̓; ) GREEK SMALL LETTER IOTA WITH PSILI +1F31;1F31;03B9 0314;1F31;03B9 0314; # (ἱ; ἱ; ι◌̔; ἱ; ι◌̔; ) GREEK SMALL LETTER IOTA WITH DASIA +1F32;1F32;03B9 0313 0300;1F32;03B9 0313 0300; # (ἲ; ἲ; ι◌̓◌̀; ἲ; ι◌̓◌̀; ) GREEK SMALL LETTER IOTA WITH PSILI AND VARIA +1F33;1F33;03B9 0314 0300;1F33;03B9 0314 0300; # (ἳ; ἳ; ι◌̔◌̀; ἳ; ι◌̔◌̀; ) GREEK SMALL LETTER IOTA WITH DASIA AND VARIA +1F34;1F34;03B9 0313 0301;1F34;03B9 0313 0301; # (ἴ; ἴ; ι◌̓◌́; ἴ; ι◌̓◌́; ) GREEK SMALL LETTER IOTA WITH PSILI AND OXIA +1F35;1F35;03B9 0314 0301;1F35;03B9 0314 0301; # (ἵ; ἵ; ι◌̔◌́; ἵ; ι◌̔◌́; ) GREEK SMALL LETTER IOTA WITH DASIA AND OXIA +1F36;1F36;03B9 0313 0342;1F36;03B9 0313 0342; # (ἶ; ἶ; ι◌̓◌͂; ἶ; ι◌̓◌͂; ) GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI +1F37;1F37;03B9 0314 0342;1F37;03B9 0314 0342; # (ἷ; ἷ; ι◌̔◌͂; ἷ; ι◌̔◌͂; ) GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI +1F38;1F38;0399 0313;1F38;0399 0313; # (Ἰ; Ἰ; Ι◌̓; Ἰ; Ι◌̓; ) GREEK CAPITAL LETTER IOTA WITH PSILI +1F39;1F39;0399 0314;1F39;0399 0314; # (Ἱ; Ἱ; Ι◌̔; Ἱ; Ι◌̔; ) GREEK CAPITAL LETTER IOTA WITH DASIA +1F3A;1F3A;0399 0313 0300;1F3A;0399 0313 0300; # (Ἲ; Ἲ; Ι◌̓◌̀; Ἲ; Ι◌̓◌̀; ) GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F3B;1F3B;0399 0314 0300;1F3B;0399 0314 0300; # (Ἳ; Ἳ; Ι◌̔◌̀; Ἳ; Ι◌̔◌̀; ) GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F3C;1F3C;0399 0313 0301;1F3C;0399 0313 0301; # (Ἴ; Ἴ; Ι◌̓◌́; Ἴ; Ι◌̓◌́; ) GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F3D;1F3D;0399 0314 0301;1F3D;0399 0314 0301; # (Ἵ; Ἵ; Ι◌̔◌́; Ἵ; Ι◌̔◌́; ) GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F3E;1F3E;0399 0313 0342;1F3E;0399 0313 0342; # (Ἶ; Ἶ; Ι◌̓◌͂; Ἶ; Ι◌̓◌͂; ) GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3F;1F3F;0399 0314 0342;1F3F;0399 0314 0342; # (Ἷ; Ἷ; Ι◌̔◌͂; Ἷ; Ι◌̔◌͂; ) GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +1F40;1F40;03BF 0313;1F40;03BF 0313; # (ὀ; ὀ; ο◌̓; ὀ; ο◌̓; ) GREEK SMALL LETTER OMICRON WITH PSILI +1F41;1F41;03BF 0314;1F41;03BF 0314; # (ὁ; ὁ; ο◌̔; ὁ; ο◌̔; ) GREEK SMALL LETTER OMICRON WITH DASIA +1F42;1F42;03BF 0313 0300;1F42;03BF 0313 0300; # (ὂ; ὂ; ο◌̓◌̀; ὂ; ο◌̓◌̀; ) GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA +1F43;1F43;03BF 0314 0300;1F43;03BF 0314 0300; # (ὃ; ὃ; ο◌̔◌̀; ὃ; ο◌̔◌̀; ) GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA +1F44;1F44;03BF 0313 0301;1F44;03BF 0313 0301; # (ὄ; ὄ; ο◌̓◌́; ὄ; ο◌̓◌́; ) GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA +1F45;1F45;03BF 0314 0301;1F45;03BF 0314 0301; # (ὅ; ὅ; ο◌̔◌́; ὅ; ο◌̔◌́; ) GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F48;1F48;039F 0313;1F48;039F 0313; # (Ὀ; Ὀ; Ο◌̓; Ὀ; Ο◌̓; ) GREEK CAPITAL LETTER OMICRON WITH PSILI +1F49;1F49;039F 0314;1F49;039F 0314; # (Ὁ; Ὁ; Ο◌̔; Ὁ; Ο◌̔; ) GREEK CAPITAL LETTER OMICRON WITH DASIA +1F4A;1F4A;039F 0313 0300;1F4A;039F 0313 0300; # (Ὂ; Ὂ; Ο◌̓◌̀; Ὂ; Ο◌̓◌̀; ) GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F4B;1F4B;039F 0314 0300;1F4B;039F 0314 0300; # (Ὃ; Ὃ; Ο◌̔◌̀; Ὃ; Ο◌̔◌̀; ) GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +1F4C;1F4C;039F 0313 0301;1F4C;039F 0313 0301; # (Ὄ; Ὄ; Ο◌̓◌́; Ὄ; Ο◌̓◌́; ) GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F4D;1F4D;039F 0314 0301;1F4D;039F 0314 0301; # (Ὅ; Ὅ; Ο◌̔◌́; Ὅ; Ο◌̔◌́; ) GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50;1F50;03C5 0313;1F50;03C5 0313; # (ὐ; ὐ; υ◌̓; ὐ; υ◌̓; ) GREEK SMALL LETTER UPSILON WITH PSILI +1F51;1F51;03C5 0314;1F51;03C5 0314; # (ὑ; ὑ; υ◌̔; ὑ; υ◌̔; ) GREEK SMALL LETTER UPSILON WITH DASIA +1F52;1F52;03C5 0313 0300;1F52;03C5 0313 0300; # (ὒ; ὒ; υ◌̓◌̀; ὒ; υ◌̓◌̀; ) GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F53;1F53;03C5 0314 0300;1F53;03C5 0314 0300; # (ὓ; ὓ; υ◌̔◌̀; ὓ; υ◌̔◌̀; ) GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA +1F54;1F54;03C5 0313 0301;1F54;03C5 0313 0301; # (ὔ; ὔ; υ◌̓◌́; ὔ; υ◌̓◌́; ) GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F55;1F55;03C5 0314 0301;1F55;03C5 0314 0301; # (ὕ; ὕ; υ◌̔◌́; ὕ; υ◌̔◌́; ) GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA +1F56;1F56;03C5 0313 0342;1F56;03C5 0313 0342; # (ὖ; ὖ; υ◌̓◌͂; ὖ; υ◌̓◌͂; ) GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1F57;1F57;03C5 0314 0342;1F57;03C5 0314 0342; # (ὗ; ὗ; υ◌̔◌͂; ὗ; υ◌̔◌͂; ) GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F59;1F59;03A5 0314;1F59;03A5 0314; # (Ὑ; Ὑ; Υ◌̔; Ὑ; Υ◌̔; ) GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B;1F5B;03A5 0314 0300;1F5B;03A5 0314 0300; # (Ὓ; Ὓ; Υ◌̔◌̀; Ὓ; Υ◌̔◌̀; ) GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D;1F5D;03A5 0314 0301;1F5D;03A5 0314 0301; # (Ὕ; Ὕ; Υ◌̔◌́; Ὕ; Υ◌̔◌́; ) GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F;1F5F;03A5 0314 0342;1F5F;03A5 0314 0342; # (Ὗ; Ὗ; Υ◌̔◌͂; Ὗ; Υ◌̔◌͂; ) GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F60;1F60;03C9 0313;1F60;03C9 0313; # (ὠ; ὠ; ω◌̓; ὠ; ω◌̓; ) GREEK SMALL LETTER OMEGA WITH PSILI +1F61;1F61;03C9 0314;1F61;03C9 0314; # (ὡ; ὡ; ω◌̔; ὡ; ω◌̔; ) GREEK SMALL LETTER OMEGA WITH DASIA +1F62;1F62;03C9 0313 0300;1F62;03C9 0313 0300; # (ὢ; ὢ; ω◌̓◌̀; ὢ; ω◌̓◌̀; ) GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA +1F63;1F63;03C9 0314 0300;1F63;03C9 0314 0300; # (ὣ; ὣ; ω◌̔◌̀; ὣ; ω◌̔◌̀; ) GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA +1F64;1F64;03C9 0313 0301;1F64;03C9 0313 0301; # (ὤ; ὤ; ω◌̓◌́; ὤ; ω◌̓◌́; ) GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA +1F65;1F65;03C9 0314 0301;1F65;03C9 0314 0301; # (ὥ; ὥ; ω◌̔◌́; ὥ; ω◌̔◌́; ) GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA +1F66;1F66;03C9 0313 0342;1F66;03C9 0313 0342; # (ὦ; ὦ; ω◌̓◌͂; ὦ; ω◌̓◌͂; ) GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F67;1F67;03C9 0314 0342;1F67;03C9 0314 0342; # (ὧ; ὧ; ω◌̔◌͂; ὧ; ω◌̔◌͂; ) GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F68;1F68;03A9 0313;1F68;03A9 0313; # (Ὠ; Ὠ; Ω◌̓; Ὠ; Ω◌̓; ) GREEK CAPITAL LETTER OMEGA WITH PSILI +1F69;1F69;03A9 0314;1F69;03A9 0314; # (Ὡ; Ὡ; Ω◌̔; Ὡ; Ω◌̔; ) GREEK CAPITAL LETTER OMEGA WITH DASIA +1F6A;1F6A;03A9 0313 0300;1F6A;03A9 0313 0300; # (Ὢ; Ὢ; Ω◌̓◌̀; Ὢ; Ω◌̓◌̀; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1F6B;1F6B;03A9 0314 0300;1F6B;03A9 0314 0300; # (Ὣ; Ὣ; Ω◌̔◌̀; Ὣ; Ω◌̔◌̀; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1F6C;1F6C;03A9 0313 0301;1F6C;03A9 0313 0301; # (Ὤ; Ὤ; Ω◌̓◌́; Ὤ; Ω◌̓◌́; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1F6D;1F6D;03A9 0314 0301;1F6D;03A9 0314 0301; # (Ὥ; Ὥ; Ω◌̔◌́; Ὥ; Ω◌̔◌́; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1F6E;1F6E;03A9 0313 0342;1F6E;03A9 0313 0342; # (Ὦ; Ὦ; Ω◌̓◌͂; Ὦ; Ω◌̓◌͂; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6F;1F6F;03A9 0314 0342;1F6F;03A9 0314 0342; # (Ὧ; Ὧ; Ω◌̔◌͂; Ὧ; Ω◌̔◌͂; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F70;1F70;03B1 0300;1F70;03B1 0300; # (ὰ; ὰ; α◌̀; ὰ; α◌̀; ) GREEK SMALL LETTER ALPHA WITH VARIA +1F71;03AC;03B1 0301;03AC;03B1 0301; # (ά; ά; α◌́; ά; α◌́; ) GREEK SMALL LETTER ALPHA WITH OXIA +1F72;1F72;03B5 0300;1F72;03B5 0300; # (ὲ; ὲ; ε◌̀; ὲ; ε◌̀; ) GREEK SMALL LETTER EPSILON WITH VARIA +1F73;03AD;03B5 0301;03AD;03B5 0301; # (έ; έ; ε◌́; έ; ε◌́; ) GREEK SMALL LETTER EPSILON WITH OXIA +1F74;1F74;03B7 0300;1F74;03B7 0300; # (ὴ; ὴ; η◌̀; ὴ; η◌̀; ) GREEK SMALL LETTER ETA WITH VARIA +1F75;03AE;03B7 0301;03AE;03B7 0301; # (ή; ή; η◌́; ή; η◌́; ) GREEK SMALL LETTER ETA WITH OXIA +1F76;1F76;03B9 0300;1F76;03B9 0300; # (ὶ; ὶ; ι◌̀; ὶ; ι◌̀; ) GREEK SMALL LETTER IOTA WITH VARIA +1F77;03AF;03B9 0301;03AF;03B9 0301; # (ί; ί; ι◌́; ί; ι◌́; ) GREEK SMALL LETTER IOTA WITH OXIA +1F78;1F78;03BF 0300;1F78;03BF 0300; # (ὸ; ὸ; ο◌̀; ὸ; ο◌̀; ) GREEK SMALL LETTER OMICRON WITH VARIA +1F79;03CC;03BF 0301;03CC;03BF 0301; # (ό; ό; ο◌́; ό; ο◌́; ) GREEK SMALL LETTER OMICRON WITH OXIA +1F7A;1F7A;03C5 0300;1F7A;03C5 0300; # (ὺ; ὺ; υ◌̀; ὺ; υ◌̀; ) GREEK SMALL LETTER UPSILON WITH VARIA +1F7B;03CD;03C5 0301;03CD;03C5 0301; # (ύ; ύ; υ◌́; ύ; υ◌́; ) GREEK SMALL LETTER UPSILON WITH OXIA +1F7C;1F7C;03C9 0300;1F7C;03C9 0300; # (ὼ; ὼ; ω◌̀; ὼ; ω◌̀; ) GREEK SMALL LETTER OMEGA WITH VARIA +1F7D;03CE;03C9 0301;03CE;03C9 0301; # (ώ; ώ; ω◌́; ώ; ω◌́; ) GREEK SMALL LETTER OMEGA WITH OXIA +1F80;1F80;03B1 0313 0345;1F80;03B1 0313 0345; # (ᾀ; ᾀ; α◌̓◌ͅ; ᾀ; α◌̓◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81;1F81;03B1 0314 0345;1F81;03B1 0314 0345; # (ᾁ; ᾁ; α◌̔◌ͅ; ᾁ; α◌̔◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82;1F82;03B1 0313 0300 0345;1F82;03B1 0313 0300 0345; # (ᾂ; ᾂ; α◌̓◌̀◌ͅ; ᾂ; α◌̓◌̀◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83;1F83;03B1 0314 0300 0345;1F83;03B1 0314 0300 0345; # (ᾃ; ᾃ; α◌̔◌̀◌ͅ; ᾃ; α◌̔◌̀◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84;1F84;03B1 0313 0301 0345;1F84;03B1 0313 0301 0345; # (ᾄ; ᾄ; α◌̓◌́◌ͅ; ᾄ; α◌̓◌́◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85;1F85;03B1 0314 0301 0345;1F85;03B1 0314 0301 0345; # (ᾅ; ᾅ; α◌̔◌́◌ͅ; ᾅ; α◌̔◌́◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86;1F86;03B1 0313 0342 0345;1F86;03B1 0313 0342 0345; # (ᾆ; ᾆ; α◌̓◌͂◌ͅ; ᾆ; α◌̓◌͂◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87;1F87;03B1 0314 0342 0345;1F87;03B1 0314 0342 0345; # (ᾇ; ᾇ; α◌̔◌͂◌ͅ; ᾇ; α◌̔◌͂◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88;1F88;0391 0313 0345;1F88;0391 0313 0345; # (ᾈ; ᾈ; Α◌̓◌ͅ; ᾈ; Α◌̓◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89;1F89;0391 0314 0345;1F89;0391 0314 0345; # (ᾉ; ᾉ; Α◌̔◌ͅ; ᾉ; Α◌̔◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A;1F8A;0391 0313 0300 0345;1F8A;0391 0313 0300 0345; # (ᾊ; ᾊ; Α◌̓◌̀◌ͅ; ᾊ; Α◌̓◌̀◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B;1F8B;0391 0314 0300 0345;1F8B;0391 0314 0300 0345; # (ᾋ; ᾋ; Α◌̔◌̀◌ͅ; ᾋ; Α◌̔◌̀◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C;1F8C;0391 0313 0301 0345;1F8C;0391 0313 0301 0345; # (ᾌ; ᾌ; Α◌̓◌́◌ͅ; ᾌ; Α◌̓◌́◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D;1F8D;0391 0314 0301 0345;1F8D;0391 0314 0301 0345; # (ᾍ; ᾍ; Α◌̔◌́◌ͅ; ᾍ; Α◌̔◌́◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E;1F8E;0391 0313 0342 0345;1F8E;0391 0313 0342 0345; # (ᾎ; ᾎ; Α◌̓◌͂◌ͅ; ᾎ; Α◌̓◌͂◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F;1F8F;0391 0314 0342 0345;1F8F;0391 0314 0342 0345; # (ᾏ; ᾏ; Α◌̔◌͂◌ͅ; ᾏ; Α◌̔◌͂◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90;1F90;03B7 0313 0345;1F90;03B7 0313 0345; # (ᾐ; ᾐ; η◌̓◌ͅ; ᾐ; η◌̓◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91;1F91;03B7 0314 0345;1F91;03B7 0314 0345; # (ᾑ; ᾑ; η◌̔◌ͅ; ᾑ; η◌̔◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92;1F92;03B7 0313 0300 0345;1F92;03B7 0313 0300 0345; # (ᾒ; ᾒ; η◌̓◌̀◌ͅ; ᾒ; η◌̓◌̀◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93;1F93;03B7 0314 0300 0345;1F93;03B7 0314 0300 0345; # (ᾓ; ᾓ; η◌̔◌̀◌ͅ; ᾓ; η◌̔◌̀◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94;1F94;03B7 0313 0301 0345;1F94;03B7 0313 0301 0345; # (ᾔ; ᾔ; η◌̓◌́◌ͅ; ᾔ; η◌̓◌́◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95;1F95;03B7 0314 0301 0345;1F95;03B7 0314 0301 0345; # (ᾕ; ᾕ; η◌̔◌́◌ͅ; ᾕ; η◌̔◌́◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96;1F96;03B7 0313 0342 0345;1F96;03B7 0313 0342 0345; # (ᾖ; ᾖ; η◌̓◌͂◌ͅ; ᾖ; η◌̓◌͂◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97;1F97;03B7 0314 0342 0345;1F97;03B7 0314 0342 0345; # (ᾗ; ᾗ; η◌̔◌͂◌ͅ; ᾗ; η◌̔◌͂◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98;1F98;0397 0313 0345;1F98;0397 0313 0345; # (ᾘ; ᾘ; Η◌̓◌ͅ; ᾘ; Η◌̓◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99;1F99;0397 0314 0345;1F99;0397 0314 0345; # (ᾙ; ᾙ; Η◌̔◌ͅ; ᾙ; Η◌̔◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A;1F9A;0397 0313 0300 0345;1F9A;0397 0313 0300 0345; # (ᾚ; ᾚ; Η◌̓◌̀◌ͅ; ᾚ; Η◌̓◌̀◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B;1F9B;0397 0314 0300 0345;1F9B;0397 0314 0300 0345; # (ᾛ; ᾛ; Η◌̔◌̀◌ͅ; ᾛ; Η◌̔◌̀◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C;1F9C;0397 0313 0301 0345;1F9C;0397 0313 0301 0345; # (ᾜ; ᾜ; Η◌̓◌́◌ͅ; ᾜ; Η◌̓◌́◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D;1F9D;0397 0314 0301 0345;1F9D;0397 0314 0301 0345; # (ᾝ; ᾝ; Η◌̔◌́◌ͅ; ᾝ; Η◌̔◌́◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E;1F9E;0397 0313 0342 0345;1F9E;0397 0313 0342 0345; # (ᾞ; ᾞ; Η◌̓◌͂◌ͅ; ᾞ; Η◌̓◌͂◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F;1F9F;0397 0314 0342 0345;1F9F;0397 0314 0342 0345; # (ᾟ; ᾟ; Η◌̔◌͂◌ͅ; ᾟ; Η◌̔◌͂◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0;1FA0;03C9 0313 0345;1FA0;03C9 0313 0345; # (ᾠ; ᾠ; ω◌̓◌ͅ; ᾠ; ω◌̓◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1;1FA1;03C9 0314 0345;1FA1;03C9 0314 0345; # (ᾡ; ᾡ; ω◌̔◌ͅ; ᾡ; ω◌̔◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2;1FA2;03C9 0313 0300 0345;1FA2;03C9 0313 0300 0345; # (ᾢ; ᾢ; ω◌̓◌̀◌ͅ; ᾢ; ω◌̓◌̀◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3;1FA3;03C9 0314 0300 0345;1FA3;03C9 0314 0300 0345; # (ᾣ; ᾣ; ω◌̔◌̀◌ͅ; ᾣ; ω◌̔◌̀◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4;1FA4;03C9 0313 0301 0345;1FA4;03C9 0313 0301 0345; # (ᾤ; ᾤ; ω◌̓◌́◌ͅ; ᾤ; ω◌̓◌́◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5;1FA5;03C9 0314 0301 0345;1FA5;03C9 0314 0301 0345; # (ᾥ; ᾥ; ω◌̔◌́◌ͅ; ᾥ; ω◌̔◌́◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6;1FA6;03C9 0313 0342 0345;1FA6;03C9 0313 0342 0345; # (ᾦ; ᾦ; ω◌̓◌͂◌ͅ; ᾦ; ω◌̓◌͂◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7;1FA7;03C9 0314 0342 0345;1FA7;03C9 0314 0342 0345; # (ᾧ; ᾧ; ω◌̔◌͂◌ͅ; ᾧ; ω◌̔◌͂◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8;1FA8;03A9 0313 0345;1FA8;03A9 0313 0345; # (ᾨ; ᾨ; Ω◌̓◌ͅ; ᾨ; Ω◌̓◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9;1FA9;03A9 0314 0345;1FA9;03A9 0314 0345; # (ᾩ; ᾩ; Ω◌̔◌ͅ; ᾩ; Ω◌̔◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA;1FAA;03A9 0313 0300 0345;1FAA;03A9 0313 0300 0345; # (ᾪ; ᾪ; Ω◌̓◌̀◌ͅ; ᾪ; Ω◌̓◌̀◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB;1FAB;03A9 0314 0300 0345;1FAB;03A9 0314 0300 0345; # (ᾫ; ᾫ; Ω◌̔◌̀◌ͅ; ᾫ; Ω◌̔◌̀◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC;1FAC;03A9 0313 0301 0345;1FAC;03A9 0313 0301 0345; # (ᾬ; ᾬ; Ω◌̓◌́◌ͅ; ᾬ; Ω◌̓◌́◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD;1FAD;03A9 0314 0301 0345;1FAD;03A9 0314 0301 0345; # (ᾭ; ᾭ; Ω◌̔◌́◌ͅ; ᾭ; Ω◌̔◌́◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE;1FAE;03A9 0313 0342 0345;1FAE;03A9 0313 0342 0345; # (ᾮ; ᾮ; Ω◌̓◌͂◌ͅ; ᾮ; Ω◌̓◌͂◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF;1FAF;03A9 0314 0342 0345;1FAF;03A9 0314 0342 0345; # (ᾯ; ᾯ; Ω◌̔◌͂◌ͅ; ᾯ; Ω◌̔◌͂◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB0;1FB0;03B1 0306;1FB0;03B1 0306; # (ᾰ; ᾰ; α◌̆; ᾰ; α◌̆; ) GREEK SMALL LETTER ALPHA WITH VRACHY +1FB1;1FB1;03B1 0304;1FB1;03B1 0304; # (ᾱ; ᾱ; α◌̄; ᾱ; α◌̄; ) GREEK SMALL LETTER ALPHA WITH MACRON +1FB2;1FB2;03B1 0300 0345;1FB2;03B1 0300 0345; # (ᾲ; ᾲ; α◌̀◌ͅ; ᾲ; α◌̀◌ͅ; ) GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB3;1FB3;03B1 0345;1FB3;03B1 0345; # (ᾳ; ᾳ; α◌ͅ; ᾳ; α◌ͅ; ) GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FB4;1FB4;03B1 0301 0345;1FB4;03B1 0301 0345; # (ᾴ; ᾴ; α◌́◌ͅ; ᾴ; α◌́◌ͅ; ) GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6;1FB6;03B1 0342;1FB6;03B1 0342; # (ᾶ; ᾶ; α◌͂; ᾶ; α◌͂; ) GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7;1FB7;03B1 0342 0345;1FB7;03B1 0342 0345; # (ᾷ; ᾷ; α◌͂◌ͅ; ᾷ; α◌͂◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB8;1FB8;0391 0306;1FB8;0391 0306; # (Ᾰ; Ᾰ; Α◌̆; Ᾰ; Α◌̆; ) GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB9;1FB9;0391 0304;1FB9;0391 0304; # (Ᾱ; Ᾱ; Α◌̄; Ᾱ; Α◌̄; ) GREEK CAPITAL LETTER ALPHA WITH MACRON +1FBA;1FBA;0391 0300;1FBA;0391 0300; # (Ὰ; Ὰ; Α◌̀; Ὰ; Α◌̀; ) GREEK CAPITAL LETTER ALPHA WITH VARIA +1FBB;0386;0391 0301;0386;0391 0301; # (Ά; Ά; Α◌́; Ά; Α◌́; ) GREEK CAPITAL LETTER ALPHA WITH OXIA +1FBC;1FBC;0391 0345;1FBC;0391 0345; # (ᾼ; ᾼ; Α◌ͅ; ᾼ; Α◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBD;1FBD;1FBD;0020 0313;0020 0313; # (᾽; ᾽; ᾽; ◌̓; ◌̓; ) GREEK KORONIS +1FBE;03B9;03B9;03B9;03B9; # (ι; ι; ι; ι; ι; ) GREEK PROSGEGRAMMENI +1FBF;1FBF;1FBF;0020 0313;0020 0313; # (᾿; ᾿; ᾿; ◌̓; ◌̓; ) GREEK PSILI +1FC0;1FC0;1FC0;0020 0342;0020 0342; # (῀; ῀; ῀; ◌͂; ◌͂; ) GREEK PERISPOMENI +1FC1;1FC1;00A8 0342;0020 0308 0342;0020 0308 0342; # (῁; ῁; ¨◌͂; ◌̈◌͂; ◌̈◌͂; ) GREEK DIALYTIKA AND PERISPOMENI +1FC2;1FC2;03B7 0300 0345;1FC2;03B7 0300 0345; # (ῂ; ῂ; η◌̀◌ͅ; ῂ; η◌̀◌ͅ; ) GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC3;1FC3;03B7 0345;1FC3;03B7 0345; # (ῃ; ῃ; η◌ͅ; ῃ; η◌ͅ; ) GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FC4;1FC4;03B7 0301 0345;1FC4;03B7 0301 0345; # (ῄ; ῄ; η◌́◌ͅ; ῄ; η◌́◌ͅ; ) GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6;1FC6;03B7 0342;1FC6;03B7 0342; # (ῆ; ῆ; η◌͂; ῆ; η◌͂; ) GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7;1FC7;03B7 0342 0345;1FC7;03B7 0342 0345; # (ῇ; ῇ; η◌͂◌ͅ; ῇ; η◌͂◌ͅ; ) GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC8;1FC8;0395 0300;1FC8;0395 0300; # (Ὲ; Ὲ; Ε◌̀; Ὲ; Ε◌̀; ) GREEK CAPITAL LETTER EPSILON WITH VARIA +1FC9;0388;0395 0301;0388;0395 0301; # (Έ; Έ; Ε◌́; Έ; Ε◌́; ) GREEK CAPITAL LETTER EPSILON WITH OXIA +1FCA;1FCA;0397 0300;1FCA;0397 0300; # (Ὴ; Ὴ; Η◌̀; Ὴ; Η◌̀; ) GREEK CAPITAL LETTER ETA WITH VARIA +1FCB;0389;0397 0301;0389;0397 0301; # (Ή; Ή; Η◌́; Ή; Η◌́; ) GREEK CAPITAL LETTER ETA WITH OXIA +1FCC;1FCC;0397 0345;1FCC;0397 0345; # (ῌ; ῌ; Η◌ͅ; ῌ; Η◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCD;1FCD;1FBF 0300;0020 0313 0300;0020 0313 0300; # (῍; ῍; ᾿◌̀; ◌̓◌̀; ◌̓◌̀; ) GREEK PSILI AND VARIA +1FCE;1FCE;1FBF 0301;0020 0313 0301;0020 0313 0301; # (῎; ῎; ᾿◌́; ◌̓◌́; ◌̓◌́; ) GREEK PSILI AND OXIA +1FCF;1FCF;1FBF 0342;0020 0313 0342;0020 0313 0342; # (῏; ῏; ᾿◌͂; ◌̓◌͂; ◌̓◌͂; ) GREEK PSILI AND PERISPOMENI +1FD0;1FD0;03B9 0306;1FD0;03B9 0306; # (ῐ; ῐ; ι◌̆; ῐ; ι◌̆; ) GREEK SMALL LETTER IOTA WITH VRACHY +1FD1;1FD1;03B9 0304;1FD1;03B9 0304; # (ῑ; ῑ; ι◌̄; ῑ; ι◌̄; ) GREEK SMALL LETTER IOTA WITH MACRON +1FD2;1FD2;03B9 0308 0300;1FD2;03B9 0308 0300; # (ῒ; ῒ; ι◌̈◌̀; ῒ; ι◌̈◌̀; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3;0390;03B9 0308 0301;0390;03B9 0308 0301; # (ΐ; ΐ; ι◌̈◌́; ΐ; ι◌̈◌́; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6;1FD6;03B9 0342;1FD6;03B9 0342; # (ῖ; ῖ; ι◌͂; ῖ; ι◌͂; ) GREEK SMALL LETTER IOTA WITH PERISPOMENI +1FD7;1FD7;03B9 0308 0342;1FD7;03B9 0308 0342; # (ῗ; ῗ; ι◌̈◌͂; ῗ; ι◌̈◌͂; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD8;1FD8;0399 0306;1FD8;0399 0306; # (Ῐ; Ῐ; Ι◌̆; Ῐ; Ι◌̆; ) GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD9;1FD9;0399 0304;1FD9;0399 0304; # (Ῑ; Ῑ; Ι◌̄; Ῑ; Ι◌̄; ) GREEK CAPITAL LETTER IOTA WITH MACRON +1FDA;1FDA;0399 0300;1FDA;0399 0300; # (Ὶ; Ὶ; Ι◌̀; Ὶ; Ι◌̀; ) GREEK CAPITAL LETTER IOTA WITH VARIA +1FDB;038A;0399 0301;038A;0399 0301; # (Ί; Ί; Ι◌́; Ί; Ι◌́; ) GREEK CAPITAL LETTER IOTA WITH OXIA +1FDD;1FDD;1FFE 0300;0020 0314 0300;0020 0314 0300; # (῝; ῝; ῾◌̀; ◌̔◌̀; ◌̔◌̀; ) GREEK DASIA AND VARIA +1FDE;1FDE;1FFE 0301;0020 0314 0301;0020 0314 0301; # (῞; ῞; ῾◌́; ◌̔◌́; ◌̔◌́; ) GREEK DASIA AND OXIA +1FDF;1FDF;1FFE 0342;0020 0314 0342;0020 0314 0342; # (῟; ῟; ῾◌͂; ◌̔◌͂; ◌̔◌͂; ) GREEK DASIA AND PERISPOMENI +1FE0;1FE0;03C5 0306;1FE0;03C5 0306; # (ῠ; ῠ; υ◌̆; ῠ; υ◌̆; ) GREEK SMALL LETTER UPSILON WITH VRACHY +1FE1;1FE1;03C5 0304;1FE1;03C5 0304; # (ῡ; ῡ; υ◌̄; ῡ; υ◌̄; ) GREEK SMALL LETTER UPSILON WITH MACRON +1FE2;1FE2;03C5 0308 0300;1FE2;03C5 0308 0300; # (ῢ; ῢ; υ◌̈◌̀; ῢ; υ◌̈◌̀; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3;03B0;03C5 0308 0301;03B0;03C5 0308 0301; # (ΰ; ΰ; υ◌̈◌́; ΰ; υ◌̈◌́; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4;1FE4;03C1 0313;1FE4;03C1 0313; # (ῤ; ῤ; ρ◌̓; ῤ; ρ◌̓; ) GREEK SMALL LETTER RHO WITH PSILI +1FE5;1FE5;03C1 0314;1FE5;03C1 0314; # (ῥ; ῥ; ρ◌̔; ῥ; ρ◌̔; ) GREEK SMALL LETTER RHO WITH DASIA +1FE6;1FE6;03C5 0342;1FE6;03C5 0342; # (ῦ; ῦ; υ◌͂; ῦ; υ◌͂; ) GREEK SMALL LETTER UPSILON WITH PERISPOMENI +1FE7;1FE7;03C5 0308 0342;1FE7;03C5 0308 0342; # (ῧ; ῧ; υ◌̈◌͂; ῧ; υ◌̈◌͂; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE8;1FE8;03A5 0306;1FE8;03A5 0306; # (Ῠ; Ῠ; Υ◌̆; Ῠ; Υ◌̆; ) GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE9;1FE9;03A5 0304;1FE9;03A5 0304; # (Ῡ; Ῡ; Υ◌̄; Ῡ; Υ◌̄; ) GREEK CAPITAL LETTER UPSILON WITH MACRON +1FEA;1FEA;03A5 0300;1FEA;03A5 0300; # (Ὺ; Ὺ; Υ◌̀; Ὺ; Υ◌̀; ) GREEK CAPITAL LETTER UPSILON WITH VARIA +1FEB;038E;03A5 0301;038E;03A5 0301; # (Ύ; Ύ; Υ◌́; Ύ; Υ◌́; ) GREEK CAPITAL LETTER UPSILON WITH OXIA +1FEC;1FEC;03A1 0314;1FEC;03A1 0314; # (Ῥ; Ῥ; Ρ◌̔; Ῥ; Ρ◌̔; ) GREEK CAPITAL LETTER RHO WITH DASIA +1FED;1FED;00A8 0300;0020 0308 0300;0020 0308 0300; # (῭; ῭; ¨◌̀; ◌̈◌̀; ◌̈◌̀; ) GREEK DIALYTIKA AND VARIA +1FEE;0385;00A8 0301;0020 0308 0301;0020 0308 0301; # (΅; ΅; ¨◌́; ◌̈◌́; ◌̈◌́; ) GREEK DIALYTIKA AND OXIA +1FEF;0060;0060;0060;0060; # (`; `; `; `; `; ) GREEK VARIA +1FF2;1FF2;03C9 0300 0345;1FF2;03C9 0300 0345; # (ῲ; ῲ; ω◌̀◌ͅ; ῲ; ω◌̀◌ͅ; ) GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF3;1FF3;03C9 0345;1FF3;03C9 0345; # (ῳ; ῳ; ω◌ͅ; ῳ; ω◌ͅ; ) GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FF4;1FF4;03C9 0301 0345;1FF4;03C9 0301 0345; # (ῴ; ῴ; ω◌́◌ͅ; ῴ; ω◌́◌ͅ; ) GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6;1FF6;03C9 0342;1FF6;03C9 0342; # (ῶ; ῶ; ω◌͂; ῶ; ω◌͂; ) GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7;1FF7;03C9 0342 0345;1FF7;03C9 0342 0345; # (ῷ; ῷ; ω◌͂◌ͅ; ῷ; ω◌͂◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF8;1FF8;039F 0300;1FF8;039F 0300; # (Ὸ; Ὸ; Ο◌̀; Ὸ; Ο◌̀; ) GREEK CAPITAL LETTER OMICRON WITH VARIA +1FF9;038C;039F 0301;038C;039F 0301; # (Ό; Ό; Ο◌́; Ό; Ο◌́; ) GREEK CAPITAL LETTER OMICRON WITH OXIA +1FFA;1FFA;03A9 0300;1FFA;03A9 0300; # (Ὼ; Ὼ; Ω◌̀; Ὼ; Ω◌̀; ) GREEK CAPITAL LETTER OMEGA WITH VARIA +1FFB;038F;03A9 0301;038F;03A9 0301; # (Ώ; Ώ; Ω◌́; Ώ; Ω◌́; ) GREEK CAPITAL LETTER OMEGA WITH OXIA +1FFC;1FFC;03A9 0345;1FFC;03A9 0345; # (ῼ; ῼ; Ω◌ͅ; ῼ; Ω◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFD;00B4;00B4;0020 0301;0020 0301; # (´; ´; ´; ◌́; ◌́; ) GREEK OXIA +1FFE;1FFE;1FFE;0020 0314;0020 0314; # (῾; ῾; ῾; ◌̔; ◌̔; ) GREEK DASIA +2000;2002;2002;0020;0020; # ( ;  ;  ; ; ; ) EN QUAD +2001;2003;2003;0020;0020; # ( ;  ;  ; ; ; ) EM QUAD +2002;2002;2002;0020;0020; # ( ;  ;  ; ; ; ) EN SPACE +2003;2003;2003;0020;0020; # ( ;  ;  ; ; ; ) EM SPACE +2004;2004;2004;0020;0020; # ( ;  ;  ; ; ; ) THREE-PER-EM SPACE +2005;2005;2005;0020;0020; # ( ;  ;  ; ; ; ) FOUR-PER-EM SPACE +2006;2006;2006;0020;0020; # ( ;  ;  ; ; ; ) SIX-PER-EM SPACE +2007;2007;2007;0020;0020; # ( ;  ;  ; ; ; ) FIGURE SPACE +2008;2008;2008;0020;0020; # ( ;  ;  ; ; ; ) PUNCTUATION SPACE +2009;2009;2009;0020;0020; # ( ;  ;  ; ; ; ) THIN SPACE +200A;200A;200A;0020;0020; # ( ;  ;  ; ; ; ) HAIR SPACE +2011;2011;2011;2010;2010; # (‑; ‑; ‑; ‐; ‐; ) NON-BREAKING HYPHEN +2017;2017;2017;0020 0333;0020 0333; # (‗; ‗; ‗; ◌̳; ◌̳; ) DOUBLE LOW LINE +2024;2024;2024;002E;002E; # (․; ․; ․; .; .; ) ONE DOT LEADER +2025;2025;2025;002E 002E;002E 002E; # (‥; ‥; ‥; ..; ..; ) TWO DOT LEADER +2026;2026;2026;002E 002E 002E;002E 002E 002E; # (…; …; …; ...; ...; ) HORIZONTAL ELLIPSIS +202F;202F;202F;0020;0020; # ( ;  ;  ; ; ; ) NARROW NO-BREAK SPACE +2033;2033;2033;2032 2032;2032 2032; # (″; ″; ″; ′′; ′′; ) DOUBLE PRIME +2034;2034;2034;2032 2032 2032;2032 2032 2032; # (‴; ‴; ‴; ′′′; ′′′; ) TRIPLE PRIME +2036;2036;2036;2035 2035;2035 2035; # (‶; ‶; ‶; ‵‵; ‵‵; ) REVERSED DOUBLE PRIME +2037;2037;2037;2035 2035 2035;2035 2035 2035; # (‷; ‷; ‷; ‵‵‵; ‵‵‵; ) REVERSED TRIPLE PRIME +203C;203C;203C;0021 0021;0021 0021; # (‼; ‼; ‼; !!; !!; ) DOUBLE EXCLAMATION MARK +203E;203E;203E;0020 0305;0020 0305; # (‾; ‾; ‾; ◌̅; ◌̅; ) OVERLINE +2047;2047;2047;003F 003F;003F 003F; # (⁇; ⁇; ⁇; ??; ??; ) DOUBLE QUESTION MARK +2048;2048;2048;003F 0021;003F 0021; # (⁈; ⁈; ⁈; ?!; ?!; ) QUESTION EXCLAMATION MARK +2049;2049;2049;0021 003F;0021 003F; # (⁉; ⁉; ⁉; !?; !?; ) EXCLAMATION QUESTION MARK +2057;2057;2057;2032 2032 2032 2032;2032 2032 2032 2032; # (⁗; ⁗; ⁗; ′′′′; ′′′′; ) QUADRUPLE PRIME +205F;205F;205F;0020;0020; # ( ;  ;  ; ; ; ) MEDIUM MATHEMATICAL SPACE +2070;2070;2070;0030;0030; # (⁰; ⁰; ⁰; 0; 0; ) SUPERSCRIPT ZERO +2071;2071;2071;0069;0069; # (ⁱ; ⁱ; ⁱ; i; i; ) SUPERSCRIPT LATIN SMALL LETTER I +2074;2074;2074;0034;0034; # (⁴; ⁴; ⁴; 4; 4; ) SUPERSCRIPT FOUR +2075;2075;2075;0035;0035; # (⁵; ⁵; ⁵; 5; 5; ) SUPERSCRIPT FIVE +2076;2076;2076;0036;0036; # (⁶; ⁶; ⁶; 6; 6; ) SUPERSCRIPT SIX +2077;2077;2077;0037;0037; # (⁷; ⁷; ⁷; 7; 7; ) SUPERSCRIPT SEVEN +2078;2078;2078;0038;0038; # (⁸; ⁸; ⁸; 8; 8; ) SUPERSCRIPT EIGHT +2079;2079;2079;0039;0039; # (⁹; ⁹; ⁹; 9; 9; ) SUPERSCRIPT NINE +207A;207A;207A;002B;002B; # (⁺; ⁺; ⁺; +; +; ) SUPERSCRIPT PLUS SIGN +207B;207B;207B;2212;2212; # (⁻; ⁻; ⁻; −; −; ) SUPERSCRIPT MINUS +207C;207C;207C;003D;003D; # (⁼; ⁼; ⁼; =; =; ) SUPERSCRIPT EQUALS SIGN +207D;207D;207D;0028;0028; # (⁽; ⁽; ⁽; (; (; ) SUPERSCRIPT LEFT PARENTHESIS +207E;207E;207E;0029;0029; # (⁾; ⁾; ⁾; ); ); ) SUPERSCRIPT RIGHT PARENTHESIS +207F;207F;207F;006E;006E; # (ⁿ; ⁿ; ⁿ; n; n; ) SUPERSCRIPT LATIN SMALL LETTER N +2080;2080;2080;0030;0030; # (₀; ₀; ₀; 0; 0; ) SUBSCRIPT ZERO +2081;2081;2081;0031;0031; # (₁; ₁; ₁; 1; 1; ) SUBSCRIPT ONE +2082;2082;2082;0032;0032; # (₂; ₂; ₂; 2; 2; ) SUBSCRIPT TWO +2083;2083;2083;0033;0033; # (₃; ₃; ₃; 3; 3; ) SUBSCRIPT THREE +2084;2084;2084;0034;0034; # (₄; ₄; ₄; 4; 4; ) SUBSCRIPT FOUR +2085;2085;2085;0035;0035; # (₅; ₅; ₅; 5; 5; ) SUBSCRIPT FIVE +2086;2086;2086;0036;0036; # (₆; ₆; ₆; 6; 6; ) SUBSCRIPT SIX +2087;2087;2087;0037;0037; # (₇; ₇; ₇; 7; 7; ) SUBSCRIPT SEVEN +2088;2088;2088;0038;0038; # (₈; ₈; ₈; 8; 8; ) SUBSCRIPT EIGHT +2089;2089;2089;0039;0039; # (₉; ₉; ₉; 9; 9; ) SUBSCRIPT NINE +208A;208A;208A;002B;002B; # (₊; ₊; ₊; +; +; ) SUBSCRIPT PLUS SIGN +208B;208B;208B;2212;2212; # (₋; ₋; ₋; −; −; ) SUBSCRIPT MINUS +208C;208C;208C;003D;003D; # (₌; ₌; ₌; =; =; ) SUBSCRIPT EQUALS SIGN +208D;208D;208D;0028;0028; # (₍; ₍; ₍; (; (; ) SUBSCRIPT LEFT PARENTHESIS +208E;208E;208E;0029;0029; # (₎; ₎; ₎; ); ); ) SUBSCRIPT RIGHT PARENTHESIS +20A8;20A8;20A8;0052 0073;0052 0073; # (₨; ₨; ₨; Rs; Rs; ) RUPEE SIGN +2100;2100;2100;0061 002F 0063;0061 002F 0063; # (℀; ℀; ℀; a/c; a/c; ) ACCOUNT OF +2101;2101;2101;0061 002F 0073;0061 002F 0073; # (℁; ℁; ℁; a/s; a/s; ) ADDRESSED TO THE SUBJECT +2102;2102;2102;0043;0043; # (ℂ; ℂ; ℂ; C; C; ) DOUBLE-STRUCK CAPITAL C +2103;2103;2103;00B0 0043;00B0 0043; # (℃; ℃; ℃; °C; °C; ) DEGREE CELSIUS +2105;2105;2105;0063 002F 006F;0063 002F 006F; # (℅; ℅; ℅; c/o; c/o; ) CARE OF +2106;2106;2106;0063 002F 0075;0063 002F 0075; # (℆; ℆; ℆; c/u; c/u; ) CADA UNA +2107;2107;2107;0190;0190; # (ℇ; ℇ; ℇ; Ɛ; Ɛ; ) EULER CONSTANT +2109;2109;2109;00B0 0046;00B0 0046; # (℉; ℉; ℉; °F; °F; ) DEGREE FAHRENHEIT +210A;210A;210A;0067;0067; # (ℊ; ℊ; ℊ; g; g; ) SCRIPT SMALL G +210B;210B;210B;0048;0048; # (ℋ; ℋ; ℋ; H; H; ) SCRIPT CAPITAL H +210C;210C;210C;0048;0048; # (ℌ; ℌ; ℌ; H; H; ) BLACK-LETTER CAPITAL H +210D;210D;210D;0048;0048; # (ℍ; ℍ; ℍ; H; H; ) DOUBLE-STRUCK CAPITAL H +210E;210E;210E;0068;0068; # (ℎ; ℎ; ℎ; h; h; ) PLANCK CONSTANT +210F;210F;210F;0127;0127; # (ℏ; ℏ; ℏ; ħ; ħ; ) PLANCK CONSTANT OVER TWO PI +2110;2110;2110;0049;0049; # (ℐ; ℐ; ℐ; I; I; ) SCRIPT CAPITAL I +2111;2111;2111;0049;0049; # (ℑ; ℑ; ℑ; I; I; ) BLACK-LETTER CAPITAL I +2112;2112;2112;004C;004C; # (ℒ; ℒ; ℒ; L; L; ) SCRIPT CAPITAL L +2113;2113;2113;006C;006C; # (ℓ; ℓ; ℓ; l; l; ) SCRIPT SMALL L +2115;2115;2115;004E;004E; # (ℕ; ℕ; ℕ; N; N; ) DOUBLE-STRUCK CAPITAL N +2116;2116;2116;004E 006F;004E 006F; # (№; №; №; No; No; ) NUMERO SIGN +2119;2119;2119;0050;0050; # (ℙ; ℙ; ℙ; P; P; ) DOUBLE-STRUCK CAPITAL P +211A;211A;211A;0051;0051; # (ℚ; ℚ; ℚ; Q; Q; ) DOUBLE-STRUCK CAPITAL Q +211B;211B;211B;0052;0052; # (ℛ; ℛ; ℛ; R; R; ) SCRIPT CAPITAL R +211C;211C;211C;0052;0052; # (ℜ; ℜ; ℜ; R; R; ) BLACK-LETTER CAPITAL R +211D;211D;211D;0052;0052; # (ℝ; ℝ; ℝ; R; R; ) DOUBLE-STRUCK CAPITAL R +2120;2120;2120;0053 004D;0053 004D; # (℠; ℠; ℠; SM; SM; ) SERVICE MARK +2121;2121;2121;0054 0045 004C;0054 0045 004C; # (℡; ℡; ℡; TEL; TEL; ) TELEPHONE SIGN +2122;2122;2122;0054 004D;0054 004D; # (™; ™; ™; TM; TM; ) TRADE MARK SIGN +2124;2124;2124;005A;005A; # (ℤ; ℤ; ℤ; Z; Z; ) DOUBLE-STRUCK CAPITAL Z +2126;03A9;03A9;03A9;03A9; # (Ω; Ω; Ω; Ω; Ω; ) OHM SIGN +2128;2128;2128;005A;005A; # (ℨ; ℨ; ℨ; Z; Z; ) BLACK-LETTER CAPITAL Z +212A;004B;004B;004B;004B; # (K; K; K; K; K; ) KELVIN SIGN +212B;00C5;0041 030A;00C5;0041 030A; # (Å; Å; A◌̊; Å; A◌̊; ) ANGSTROM SIGN +212C;212C;212C;0042;0042; # (ℬ; ℬ; ℬ; B; B; ) SCRIPT CAPITAL B +212D;212D;212D;0043;0043; # (ℭ; ℭ; ℭ; C; C; ) BLACK-LETTER CAPITAL C +212F;212F;212F;0065;0065; # (ℯ; ℯ; ℯ; e; e; ) SCRIPT SMALL E +2130;2130;2130;0045;0045; # (ℰ; ℰ; ℰ; E; E; ) SCRIPT CAPITAL E +2131;2131;2131;0046;0046; # (ℱ; ℱ; ℱ; F; F; ) SCRIPT CAPITAL F +2133;2133;2133;004D;004D; # (ℳ; ℳ; ℳ; M; M; ) SCRIPT CAPITAL M +2134;2134;2134;006F;006F; # (ℴ; ℴ; ℴ; o; o; ) SCRIPT SMALL O +2135;2135;2135;05D0;05D0; # (ℵ; ℵ; ℵ; א; א; ) ALEF SYMBOL +2136;2136;2136;05D1;05D1; # (ℶ; ℶ; ℶ; ב; ב; ) BET SYMBOL +2137;2137;2137;05D2;05D2; # (ℷ; ℷ; ℷ; ג; ג; ) GIMEL SYMBOL +2138;2138;2138;05D3;05D3; # (ℸ; ℸ; ℸ; ד; ד; ) DALET SYMBOL +2139;2139;2139;0069;0069; # (ℹ; ℹ; ℹ; i; i; ) INFORMATION SOURCE +213D;213D;213D;03B3;03B3; # (ℽ; ℽ; ℽ; γ; γ; ) DOUBLE-STRUCK SMALL GAMMA +213E;213E;213E;0393;0393; # (ℾ; ℾ; ℾ; Γ; Γ; ) DOUBLE-STRUCK CAPITAL GAMMA +213F;213F;213F;03A0;03A0; # (ℿ; ℿ; ℿ; Π; Π; ) DOUBLE-STRUCK CAPITAL PI +2140;2140;2140;2211;2211; # (⅀; ⅀; ⅀; ∑; ∑; ) DOUBLE-STRUCK N-ARY SUMMATION +2145;2145;2145;0044;0044; # (ⅅ; ⅅ; ⅅ; D; D; ) DOUBLE-STRUCK ITALIC CAPITAL D +2146;2146;2146;0064;0064; # (ⅆ; ⅆ; ⅆ; d; d; ) DOUBLE-STRUCK ITALIC SMALL D +2147;2147;2147;0065;0065; # (ⅇ; ⅇ; ⅇ; e; e; ) DOUBLE-STRUCK ITALIC SMALL E +2148;2148;2148;0069;0069; # (ⅈ; ⅈ; ⅈ; i; i; ) DOUBLE-STRUCK ITALIC SMALL I +2149;2149;2149;006A;006A; # (ⅉ; ⅉ; ⅉ; j; j; ) DOUBLE-STRUCK ITALIC SMALL J +2153;2153;2153;0031 2044 0033;0031 2044 0033; # (⅓; ⅓; ⅓; 1⁄3; 1⁄3; ) VULGAR FRACTION ONE THIRD +2154;2154;2154;0032 2044 0033;0032 2044 0033; # (⅔; ⅔; ⅔; 2⁄3; 2⁄3; ) VULGAR FRACTION TWO THIRDS +2155;2155;2155;0031 2044 0035;0031 2044 0035; # (⅕; ⅕; ⅕; 1⁄5; 1⁄5; ) VULGAR FRACTION ONE FIFTH +2156;2156;2156;0032 2044 0035;0032 2044 0035; # (⅖; ⅖; ⅖; 2⁄5; 2⁄5; ) VULGAR FRACTION TWO FIFTHS +2157;2157;2157;0033 2044 0035;0033 2044 0035; # (⅗; ⅗; ⅗; 3⁄5; 3⁄5; ) VULGAR FRACTION THREE FIFTHS +2158;2158;2158;0034 2044 0035;0034 2044 0035; # (⅘; ⅘; ⅘; 4⁄5; 4⁄5; ) VULGAR FRACTION FOUR FIFTHS +2159;2159;2159;0031 2044 0036;0031 2044 0036; # (⅙; ⅙; ⅙; 1⁄6; 1⁄6; ) VULGAR FRACTION ONE SIXTH +215A;215A;215A;0035 2044 0036;0035 2044 0036; # (⅚; ⅚; ⅚; 5⁄6; 5⁄6; ) VULGAR FRACTION FIVE SIXTHS +215B;215B;215B;0031 2044 0038;0031 2044 0038; # (⅛; ⅛; ⅛; 1⁄8; 1⁄8; ) VULGAR FRACTION ONE EIGHTH +215C;215C;215C;0033 2044 0038;0033 2044 0038; # (⅜; ⅜; ⅜; 3⁄8; 3⁄8; ) VULGAR FRACTION THREE EIGHTHS +215D;215D;215D;0035 2044 0038;0035 2044 0038; # (⅝; ⅝; ⅝; 5⁄8; 5⁄8; ) VULGAR FRACTION FIVE EIGHTHS +215E;215E;215E;0037 2044 0038;0037 2044 0038; # (⅞; ⅞; ⅞; 7⁄8; 7⁄8; ) VULGAR FRACTION SEVEN EIGHTHS +215F;215F;215F;0031 2044;0031 2044; # (⅟; ⅟; ⅟; 1⁄; 1⁄; ) FRACTION NUMERATOR ONE +2160;2160;2160;0049;0049; # (Ⅰ; Ⅰ; Ⅰ; I; I; ) ROMAN NUMERAL ONE +2161;2161;2161;0049 0049;0049 0049; # (Ⅱ; Ⅱ; Ⅱ; II; II; ) ROMAN NUMERAL TWO +2162;2162;2162;0049 0049 0049;0049 0049 0049; # (Ⅲ; Ⅲ; Ⅲ; III; III; ) ROMAN NUMERAL THREE +2163;2163;2163;0049 0056;0049 0056; # (Ⅳ; Ⅳ; Ⅳ; IV; IV; ) ROMAN NUMERAL FOUR +2164;2164;2164;0056;0056; # (Ⅴ; Ⅴ; Ⅴ; V; V; ) ROMAN NUMERAL FIVE +2165;2165;2165;0056 0049;0056 0049; # (Ⅵ; Ⅵ; Ⅵ; VI; VI; ) ROMAN NUMERAL SIX +2166;2166;2166;0056 0049 0049;0056 0049 0049; # (Ⅶ; Ⅶ; Ⅶ; VII; VII; ) ROMAN NUMERAL SEVEN +2167;2167;2167;0056 0049 0049 0049;0056 0049 0049 0049; # (Ⅷ; Ⅷ; Ⅷ; VIII; VIII; ) ROMAN NUMERAL EIGHT +2168;2168;2168;0049 0058;0049 0058; # (Ⅸ; Ⅸ; Ⅸ; IX; IX; ) ROMAN NUMERAL NINE +2169;2169;2169;0058;0058; # (Ⅹ; Ⅹ; Ⅹ; X; X; ) ROMAN NUMERAL TEN +216A;216A;216A;0058 0049;0058 0049; # (Ⅺ; Ⅺ; Ⅺ; XI; XI; ) ROMAN NUMERAL ELEVEN +216B;216B;216B;0058 0049 0049;0058 0049 0049; # (Ⅻ; Ⅻ; Ⅻ; XII; XII; ) ROMAN NUMERAL TWELVE +216C;216C;216C;004C;004C; # (Ⅼ; Ⅼ; Ⅼ; L; L; ) ROMAN NUMERAL FIFTY +216D;216D;216D;0043;0043; # (Ⅽ; Ⅽ; Ⅽ; C; C; ) ROMAN NUMERAL ONE HUNDRED +216E;216E;216E;0044;0044; # (Ⅾ; Ⅾ; Ⅾ; D; D; ) ROMAN NUMERAL FIVE HUNDRED +216F;216F;216F;004D;004D; # (Ⅿ; Ⅿ; Ⅿ; M; M; ) ROMAN NUMERAL ONE THOUSAND +2170;2170;2170;0069;0069; # (ⅰ; ⅰ; ⅰ; i; i; ) SMALL ROMAN NUMERAL ONE +2171;2171;2171;0069 0069;0069 0069; # (ⅱ; ⅱ; ⅱ; ii; ii; ) SMALL ROMAN NUMERAL TWO +2172;2172;2172;0069 0069 0069;0069 0069 0069; # (ⅲ; ⅲ; ⅲ; iii; iii; ) SMALL ROMAN NUMERAL THREE +2173;2173;2173;0069 0076;0069 0076; # (ⅳ; ⅳ; ⅳ; iv; iv; ) SMALL ROMAN NUMERAL FOUR +2174;2174;2174;0076;0076; # (ⅴ; ⅴ; ⅴ; v; v; ) SMALL ROMAN NUMERAL FIVE +2175;2175;2175;0076 0069;0076 0069; # (ⅵ; ⅵ; ⅵ; vi; vi; ) SMALL ROMAN NUMERAL SIX +2176;2176;2176;0076 0069 0069;0076 0069 0069; # (ⅶ; ⅶ; ⅶ; vii; vii; ) SMALL ROMAN NUMERAL SEVEN +2177;2177;2177;0076 0069 0069 0069;0076 0069 0069 0069; # (ⅷ; ⅷ; ⅷ; viii; viii; ) SMALL ROMAN NUMERAL EIGHT +2178;2178;2178;0069 0078;0069 0078; # (ⅸ; ⅸ; ⅸ; ix; ix; ) SMALL ROMAN NUMERAL NINE +2179;2179;2179;0078;0078; # (ⅹ; ⅹ; ⅹ; x; x; ) SMALL ROMAN NUMERAL TEN +217A;217A;217A;0078 0069;0078 0069; # (ⅺ; ⅺ; ⅺ; xi; xi; ) SMALL ROMAN NUMERAL ELEVEN +217B;217B;217B;0078 0069 0069;0078 0069 0069; # (ⅻ; ⅻ; ⅻ; xii; xii; ) SMALL ROMAN NUMERAL TWELVE +217C;217C;217C;006C;006C; # (ⅼ; ⅼ; ⅼ; l; l; ) SMALL ROMAN NUMERAL FIFTY +217D;217D;217D;0063;0063; # (ⅽ; ⅽ; ⅽ; c; c; ) SMALL ROMAN NUMERAL ONE HUNDRED +217E;217E;217E;0064;0064; # (ⅾ; ⅾ; ⅾ; d; d; ) SMALL ROMAN NUMERAL FIVE HUNDRED +217F;217F;217F;006D;006D; # (ⅿ; ⅿ; ⅿ; m; m; ) SMALL ROMAN NUMERAL ONE THOUSAND +219A;219A;2190 0338;219A;2190 0338; # (↚; ↚; ←◌̸; ↚; ←◌̸; ) LEFTWARDS ARROW WITH STROKE +219B;219B;2192 0338;219B;2192 0338; # (↛; ↛; →◌̸; ↛; →◌̸; ) RIGHTWARDS ARROW WITH STROKE +21AE;21AE;2194 0338;21AE;2194 0338; # (↮; ↮; ↔◌̸; ↮; ↔◌̸; ) LEFT RIGHT ARROW WITH STROKE +21CD;21CD;21D0 0338;21CD;21D0 0338; # (⇍; ⇍; ⇐◌̸; ⇍; ⇐◌̸; ) LEFTWARDS DOUBLE ARROW WITH STROKE +21CE;21CE;21D4 0338;21CE;21D4 0338; # (⇎; ⇎; ⇔◌̸; ⇎; ⇔◌̸; ) LEFT RIGHT DOUBLE ARROW WITH STROKE +21CF;21CF;21D2 0338;21CF;21D2 0338; # (⇏; ⇏; ⇒◌̸; ⇏; ⇒◌̸; ) RIGHTWARDS DOUBLE ARROW WITH STROKE +2204;2204;2203 0338;2204;2203 0338; # (∄; ∄; ∃◌̸; ∄; ∃◌̸; ) THERE DOES NOT EXIST +2209;2209;2208 0338;2209;2208 0338; # (∉; ∉; ∈◌̸; ∉; ∈◌̸; ) NOT AN ELEMENT OF +220C;220C;220B 0338;220C;220B 0338; # (∌; ∌; ∋◌̸; ∌; ∋◌̸; ) DOES NOT CONTAIN AS MEMBER +2224;2224;2223 0338;2224;2223 0338; # (∤; ∤; ∣◌̸; ∤; ∣◌̸; ) DOES NOT DIVIDE +2226;2226;2225 0338;2226;2225 0338; # (∦; ∦; ∥◌̸; ∦; ∥◌̸; ) NOT PARALLEL TO +222C;222C;222C;222B 222B;222B 222B; # (∬; ∬; ∬; ∫∫; ∫∫; ) DOUBLE INTEGRAL +222D;222D;222D;222B 222B 222B;222B 222B 222B; # (∭; ∭; ∭; ∫∫∫; ∫∫∫; ) TRIPLE INTEGRAL +222F;222F;222F;222E 222E;222E 222E; # (∯; ∯; ∯; ∮∮; ∮∮; ) SURFACE INTEGRAL +2230;2230;2230;222E 222E 222E;222E 222E 222E; # (∰; ∰; ∰; ∮∮∮; ∮∮∮; ) VOLUME INTEGRAL +2241;2241;223C 0338;2241;223C 0338; # (≁; ≁; ∼◌̸; ≁; ∼◌̸; ) NOT TILDE +2244;2244;2243 0338;2244;2243 0338; # (≄; ≄; ≃◌̸; ≄; ≃◌̸; ) NOT ASYMPTOTICALLY EQUAL TO +2247;2247;2245 0338;2247;2245 0338; # (≇; ≇; ≅◌̸; ≇; ≅◌̸; ) NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO +2249;2249;2248 0338;2249;2248 0338; # (≉; ≉; ≈◌̸; ≉; ≈◌̸; ) NOT ALMOST EQUAL TO +2260;2260;003D 0338;2260;003D 0338; # (≠; ≠; =◌̸; ≠; =◌̸; ) NOT EQUAL TO +2262;2262;2261 0338;2262;2261 0338; # (≢; ≢; ≡◌̸; ≢; ≡◌̸; ) NOT IDENTICAL TO +226D;226D;224D 0338;226D;224D 0338; # (≭; ≭; ≍◌̸; ≭; ≍◌̸; ) NOT EQUIVALENT TO +226E;226E;003C 0338;226E;003C 0338; # (≮; ≮; <◌̸; ≮; <◌̸; ) NOT LESS-THAN +226F;226F;003E 0338;226F;003E 0338; # (≯; ≯; >◌̸; ≯; >◌̸; ) NOT GREATER-THAN +2270;2270;2264 0338;2270;2264 0338; # (≰; ≰; ≤◌̸; ≰; ≤◌̸; ) NEITHER LESS-THAN NOR EQUAL TO +2271;2271;2265 0338;2271;2265 0338; # (≱; ≱; ≥◌̸; ≱; ≥◌̸; ) NEITHER GREATER-THAN NOR EQUAL TO +2274;2274;2272 0338;2274;2272 0338; # (≴; ≴; ≲◌̸; ≴; ≲◌̸; ) NEITHER LESS-THAN NOR EQUIVALENT TO +2275;2275;2273 0338;2275;2273 0338; # (≵; ≵; ≳◌̸; ≵; ≳◌̸; ) NEITHER GREATER-THAN NOR EQUIVALENT TO +2278;2278;2276 0338;2278;2276 0338; # (≸; ≸; ≶◌̸; ≸; ≶◌̸; ) NEITHER LESS-THAN NOR GREATER-THAN +2279;2279;2277 0338;2279;2277 0338; # (≹; ≹; ≷◌̸; ≹; ≷◌̸; ) NEITHER GREATER-THAN NOR LESS-THAN +2280;2280;227A 0338;2280;227A 0338; # (⊀; ⊀; ≺◌̸; ⊀; ≺◌̸; ) DOES NOT PRECEDE +2281;2281;227B 0338;2281;227B 0338; # (⊁; ⊁; ≻◌̸; ⊁; ≻◌̸; ) DOES NOT SUCCEED +2284;2284;2282 0338;2284;2282 0338; # (⊄; ⊄; ⊂◌̸; ⊄; ⊂◌̸; ) NOT A SUBSET OF +2285;2285;2283 0338;2285;2283 0338; # (⊅; ⊅; ⊃◌̸; ⊅; ⊃◌̸; ) NOT A SUPERSET OF +2288;2288;2286 0338;2288;2286 0338; # (⊈; ⊈; ⊆◌̸; ⊈; ⊆◌̸; ) NEITHER A SUBSET OF NOR EQUAL TO +2289;2289;2287 0338;2289;2287 0338; # (⊉; ⊉; ⊇◌̸; ⊉; ⊇◌̸; ) NEITHER A SUPERSET OF NOR EQUAL TO +22AC;22AC;22A2 0338;22AC;22A2 0338; # (⊬; ⊬; ⊢◌̸; ⊬; ⊢◌̸; ) DOES NOT PROVE +22AD;22AD;22A8 0338;22AD;22A8 0338; # (⊭; ⊭; ⊨◌̸; ⊭; ⊨◌̸; ) NOT TRUE +22AE;22AE;22A9 0338;22AE;22A9 0338; # (⊮; ⊮; ⊩◌̸; ⊮; ⊩◌̸; ) DOES NOT FORCE +22AF;22AF;22AB 0338;22AF;22AB 0338; # (⊯; ⊯; ⊫◌̸; ⊯; ⊫◌̸; ) NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE +22E0;22E0;227C 0338;22E0;227C 0338; # (⋠; ⋠; ≼◌̸; ⋠; ≼◌̸; ) DOES NOT PRECEDE OR EQUAL +22E1;22E1;227D 0338;22E1;227D 0338; # (⋡; ⋡; ≽◌̸; ⋡; ≽◌̸; ) DOES NOT SUCCEED OR EQUAL +22E2;22E2;2291 0338;22E2;2291 0338; # (⋢; ⋢; ⊑◌̸; ⋢; ⊑◌̸; ) NOT SQUARE IMAGE OF OR EQUAL TO +22E3;22E3;2292 0338;22E3;2292 0338; # (⋣; ⋣; ⊒◌̸; ⋣; ⊒◌̸; ) NOT SQUARE ORIGINAL OF OR EQUAL TO +22EA;22EA;22B2 0338;22EA;22B2 0338; # (⋪; ⋪; ⊲◌̸; ⋪; ⊲◌̸; ) NOT NORMAL SUBGROUP OF +22EB;22EB;22B3 0338;22EB;22B3 0338; # (⋫; ⋫; ⊳◌̸; ⋫; ⊳◌̸; ) DOES NOT CONTAIN AS NORMAL SUBGROUP +22EC;22EC;22B4 0338;22EC;22B4 0338; # (⋬; ⋬; ⊴◌̸; ⋬; ⊴◌̸; ) NOT NORMAL SUBGROUP OF OR EQUAL TO +22ED;22ED;22B5 0338;22ED;22B5 0338; # (⋭; ⋭; ⊵◌̸; ⋭; ⊵◌̸; ) DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL +2329;3008;3008;3008;3008; # (〈; 〈; 〈; 〈; 〈; ) LEFT-POINTING ANGLE BRACKET +232A;3009;3009;3009;3009; # (〉; 〉; 〉; 〉; 〉; ) RIGHT-POINTING ANGLE BRACKET +2460;2460;2460;0031;0031; # (①; ①; ①; 1; 1; ) CIRCLED DIGIT ONE +2461;2461;2461;0032;0032; # (②; ②; ②; 2; 2; ) CIRCLED DIGIT TWO +2462;2462;2462;0033;0033; # (③; ③; ③; 3; 3; ) CIRCLED DIGIT THREE +2463;2463;2463;0034;0034; # (④; ④; ④; 4; 4; ) CIRCLED DIGIT FOUR +2464;2464;2464;0035;0035; # (⑤; ⑤; ⑤; 5; 5; ) CIRCLED DIGIT FIVE +2465;2465;2465;0036;0036; # (⑥; ⑥; ⑥; 6; 6; ) CIRCLED DIGIT SIX +2466;2466;2466;0037;0037; # (⑦; ⑦; ⑦; 7; 7; ) CIRCLED DIGIT SEVEN +2467;2467;2467;0038;0038; # (⑧; ⑧; ⑧; 8; 8; ) CIRCLED DIGIT EIGHT +2468;2468;2468;0039;0039; # (⑨; ⑨; ⑨; 9; 9; ) CIRCLED DIGIT NINE +2469;2469;2469;0031 0030;0031 0030; # (⑩; ⑩; ⑩; 10; 10; ) CIRCLED NUMBER TEN +246A;246A;246A;0031 0031;0031 0031; # (⑪; ⑪; ⑪; 11; 11; ) CIRCLED NUMBER ELEVEN +246B;246B;246B;0031 0032;0031 0032; # (⑫; ⑫; ⑫; 12; 12; ) CIRCLED NUMBER TWELVE +246C;246C;246C;0031 0033;0031 0033; # (⑬; ⑬; ⑬; 13; 13; ) CIRCLED NUMBER THIRTEEN +246D;246D;246D;0031 0034;0031 0034; # (⑭; ⑭; ⑭; 14; 14; ) CIRCLED NUMBER FOURTEEN +246E;246E;246E;0031 0035;0031 0035; # (⑮; ⑮; ⑮; 15; 15; ) CIRCLED NUMBER FIFTEEN +246F;246F;246F;0031 0036;0031 0036; # (⑯; ⑯; ⑯; 16; 16; ) CIRCLED NUMBER SIXTEEN +2470;2470;2470;0031 0037;0031 0037; # (⑰; ⑰; ⑰; 17; 17; ) CIRCLED NUMBER SEVENTEEN +2471;2471;2471;0031 0038;0031 0038; # (⑱; ⑱; ⑱; 18; 18; ) CIRCLED NUMBER EIGHTEEN +2472;2472;2472;0031 0039;0031 0039; # (⑲; ⑲; ⑲; 19; 19; ) CIRCLED NUMBER NINETEEN +2473;2473;2473;0032 0030;0032 0030; # (⑳; ⑳; ⑳; 20; 20; ) CIRCLED NUMBER TWENTY +2474;2474;2474;0028 0031 0029;0028 0031 0029; # (⑴; ⑴; ⑴; (1); (1); ) PARENTHESIZED DIGIT ONE +2475;2475;2475;0028 0032 0029;0028 0032 0029; # (⑵; ⑵; ⑵; (2); (2); ) PARENTHESIZED DIGIT TWO +2476;2476;2476;0028 0033 0029;0028 0033 0029; # (⑶; ⑶; ⑶; (3); (3); ) PARENTHESIZED DIGIT THREE +2477;2477;2477;0028 0034 0029;0028 0034 0029; # (⑷; ⑷; ⑷; (4); (4); ) PARENTHESIZED DIGIT FOUR +2478;2478;2478;0028 0035 0029;0028 0035 0029; # (⑸; ⑸; ⑸; (5); (5); ) PARENTHESIZED DIGIT FIVE +2479;2479;2479;0028 0036 0029;0028 0036 0029; # (⑹; ⑹; ⑹; (6); (6); ) PARENTHESIZED DIGIT SIX +247A;247A;247A;0028 0037 0029;0028 0037 0029; # (⑺; ⑺; ⑺; (7); (7); ) PARENTHESIZED DIGIT SEVEN +247B;247B;247B;0028 0038 0029;0028 0038 0029; # (⑻; ⑻; ⑻; (8); (8); ) PARENTHESIZED DIGIT EIGHT +247C;247C;247C;0028 0039 0029;0028 0039 0029; # (⑼; ⑼; ⑼; (9); (9); ) PARENTHESIZED DIGIT NINE +247D;247D;247D;0028 0031 0030 0029;0028 0031 0030 0029; # (⑽; ⑽; ⑽; (10); (10); ) PARENTHESIZED NUMBER TEN +247E;247E;247E;0028 0031 0031 0029;0028 0031 0031 0029; # (⑾; ⑾; ⑾; (11); (11); ) PARENTHESIZED NUMBER ELEVEN +247F;247F;247F;0028 0031 0032 0029;0028 0031 0032 0029; # (⑿; ⑿; ⑿; (12); (12); ) PARENTHESIZED NUMBER TWELVE +2480;2480;2480;0028 0031 0033 0029;0028 0031 0033 0029; # (⒀; ⒀; ⒀; (13); (13); ) PARENTHESIZED NUMBER THIRTEEN +2481;2481;2481;0028 0031 0034 0029;0028 0031 0034 0029; # (⒁; ⒁; ⒁; (14); (14); ) PARENTHESIZED NUMBER FOURTEEN +2482;2482;2482;0028 0031 0035 0029;0028 0031 0035 0029; # (⒂; ⒂; ⒂; (15); (15); ) PARENTHESIZED NUMBER FIFTEEN +2483;2483;2483;0028 0031 0036 0029;0028 0031 0036 0029; # (⒃; ⒃; ⒃; (16); (16); ) PARENTHESIZED NUMBER SIXTEEN +2484;2484;2484;0028 0031 0037 0029;0028 0031 0037 0029; # (⒄; ⒄; ⒄; (17); (17); ) PARENTHESIZED NUMBER SEVENTEEN +2485;2485;2485;0028 0031 0038 0029;0028 0031 0038 0029; # (⒅; ⒅; ⒅; (18); (18); ) PARENTHESIZED NUMBER EIGHTEEN +2486;2486;2486;0028 0031 0039 0029;0028 0031 0039 0029; # (⒆; ⒆; ⒆; (19); (19); ) PARENTHESIZED NUMBER NINETEEN +2487;2487;2487;0028 0032 0030 0029;0028 0032 0030 0029; # (⒇; ⒇; ⒇; (20); (20); ) PARENTHESIZED NUMBER TWENTY +2488;2488;2488;0031 002E;0031 002E; # (⒈; ⒈; ⒈; 1.; 1.; ) DIGIT ONE FULL STOP +2489;2489;2489;0032 002E;0032 002E; # (⒉; ⒉; ⒉; 2.; 2.; ) DIGIT TWO FULL STOP +248A;248A;248A;0033 002E;0033 002E; # (⒊; ⒊; ⒊; 3.; 3.; ) DIGIT THREE FULL STOP +248B;248B;248B;0034 002E;0034 002E; # (⒋; ⒋; ⒋; 4.; 4.; ) DIGIT FOUR FULL STOP +248C;248C;248C;0035 002E;0035 002E; # (⒌; ⒌; ⒌; 5.; 5.; ) DIGIT FIVE FULL STOP +248D;248D;248D;0036 002E;0036 002E; # (⒍; ⒍; ⒍; 6.; 6.; ) DIGIT SIX FULL STOP +248E;248E;248E;0037 002E;0037 002E; # (⒎; ⒎; ⒎; 7.; 7.; ) DIGIT SEVEN FULL STOP +248F;248F;248F;0038 002E;0038 002E; # (⒏; ⒏; ⒏; 8.; 8.; ) DIGIT EIGHT FULL STOP +2490;2490;2490;0039 002E;0039 002E; # (⒐; ⒐; ⒐; 9.; 9.; ) DIGIT NINE FULL STOP +2491;2491;2491;0031 0030 002E;0031 0030 002E; # (⒑; ⒑; ⒑; 10.; 10.; ) NUMBER TEN FULL STOP +2492;2492;2492;0031 0031 002E;0031 0031 002E; # (⒒; ⒒; ⒒; 11.; 11.; ) NUMBER ELEVEN FULL STOP +2493;2493;2493;0031 0032 002E;0031 0032 002E; # (⒓; ⒓; ⒓; 12.; 12.; ) NUMBER TWELVE FULL STOP +2494;2494;2494;0031 0033 002E;0031 0033 002E; # (⒔; ⒔; ⒔; 13.; 13.; ) NUMBER THIRTEEN FULL STOP +2495;2495;2495;0031 0034 002E;0031 0034 002E; # (⒕; ⒕; ⒕; 14.; 14.; ) NUMBER FOURTEEN FULL STOP +2496;2496;2496;0031 0035 002E;0031 0035 002E; # (⒖; ⒖; ⒖; 15.; 15.; ) NUMBER FIFTEEN FULL STOP +2497;2497;2497;0031 0036 002E;0031 0036 002E; # (⒗; ⒗; ⒗; 16.; 16.; ) NUMBER SIXTEEN FULL STOP +2498;2498;2498;0031 0037 002E;0031 0037 002E; # (⒘; ⒘; ⒘; 17.; 17.; ) NUMBER SEVENTEEN FULL STOP +2499;2499;2499;0031 0038 002E;0031 0038 002E; # (⒙; ⒙; ⒙; 18.; 18.; ) NUMBER EIGHTEEN FULL STOP +249A;249A;249A;0031 0039 002E;0031 0039 002E; # (⒚; ⒚; ⒚; 19.; 19.; ) NUMBER NINETEEN FULL STOP +249B;249B;249B;0032 0030 002E;0032 0030 002E; # (⒛; ⒛; ⒛; 20.; 20.; ) NUMBER TWENTY FULL STOP +249C;249C;249C;0028 0061 0029;0028 0061 0029; # (⒜; ⒜; ⒜; (a); (a); ) PARENTHESIZED LATIN SMALL LETTER A +249D;249D;249D;0028 0062 0029;0028 0062 0029; # (⒝; ⒝; ⒝; (b); (b); ) PARENTHESIZED LATIN SMALL LETTER B +249E;249E;249E;0028 0063 0029;0028 0063 0029; # (⒞; ⒞; ⒞; (c); (c); ) PARENTHESIZED LATIN SMALL LETTER C +249F;249F;249F;0028 0064 0029;0028 0064 0029; # (⒟; ⒟; ⒟; (d); (d); ) PARENTHESIZED LATIN SMALL LETTER D +24A0;24A0;24A0;0028 0065 0029;0028 0065 0029; # (⒠; ⒠; ⒠; (e); (e); ) PARENTHESIZED LATIN SMALL LETTER E +24A1;24A1;24A1;0028 0066 0029;0028 0066 0029; # (⒡; ⒡; ⒡; (f); (f); ) PARENTHESIZED LATIN SMALL LETTER F +24A2;24A2;24A2;0028 0067 0029;0028 0067 0029; # (⒢; ⒢; ⒢; (g); (g); ) PARENTHESIZED LATIN SMALL LETTER G +24A3;24A3;24A3;0028 0068 0029;0028 0068 0029; # (⒣; ⒣; ⒣; (h); (h); ) PARENTHESIZED LATIN SMALL LETTER H +24A4;24A4;24A4;0028 0069 0029;0028 0069 0029; # (⒤; ⒤; ⒤; (i); (i); ) PARENTHESIZED LATIN SMALL LETTER I +24A5;24A5;24A5;0028 006A 0029;0028 006A 0029; # (⒥; ⒥; ⒥; (j); (j); ) PARENTHESIZED LATIN SMALL LETTER J +24A6;24A6;24A6;0028 006B 0029;0028 006B 0029; # (⒦; ⒦; ⒦; (k); (k); ) PARENTHESIZED LATIN SMALL LETTER K +24A7;24A7;24A7;0028 006C 0029;0028 006C 0029; # (⒧; ⒧; ⒧; (l); (l); ) PARENTHESIZED LATIN SMALL LETTER L +24A8;24A8;24A8;0028 006D 0029;0028 006D 0029; # (⒨; ⒨; ⒨; (m); (m); ) PARENTHESIZED LATIN SMALL LETTER M +24A9;24A9;24A9;0028 006E 0029;0028 006E 0029; # (⒩; ⒩; ⒩; (n); (n); ) PARENTHESIZED LATIN SMALL LETTER N +24AA;24AA;24AA;0028 006F 0029;0028 006F 0029; # (⒪; ⒪; ⒪; (o); (o); ) PARENTHESIZED LATIN SMALL LETTER O +24AB;24AB;24AB;0028 0070 0029;0028 0070 0029; # (⒫; ⒫; ⒫; (p); (p); ) PARENTHESIZED LATIN SMALL LETTER P +24AC;24AC;24AC;0028 0071 0029;0028 0071 0029; # (⒬; ⒬; ⒬; (q); (q); ) PARENTHESIZED LATIN SMALL LETTER Q +24AD;24AD;24AD;0028 0072 0029;0028 0072 0029; # (⒭; ⒭; ⒭; (r); (r); ) PARENTHESIZED LATIN SMALL LETTER R +24AE;24AE;24AE;0028 0073 0029;0028 0073 0029; # (⒮; ⒮; ⒮; (s); (s); ) PARENTHESIZED LATIN SMALL LETTER S +24AF;24AF;24AF;0028 0074 0029;0028 0074 0029; # (⒯; ⒯; ⒯; (t); (t); ) PARENTHESIZED LATIN SMALL LETTER T +24B0;24B0;24B0;0028 0075 0029;0028 0075 0029; # (⒰; ⒰; ⒰; (u); (u); ) PARENTHESIZED LATIN SMALL LETTER U +24B1;24B1;24B1;0028 0076 0029;0028 0076 0029; # (⒱; ⒱; ⒱; (v); (v); ) PARENTHESIZED LATIN SMALL LETTER V +24B2;24B2;24B2;0028 0077 0029;0028 0077 0029; # (⒲; ⒲; ⒲; (w); (w); ) PARENTHESIZED LATIN SMALL LETTER W +24B3;24B3;24B3;0028 0078 0029;0028 0078 0029; # (⒳; ⒳; ⒳; (x); (x); ) PARENTHESIZED LATIN SMALL LETTER X +24B4;24B4;24B4;0028 0079 0029;0028 0079 0029; # (⒴; ⒴; ⒴; (y); (y); ) PARENTHESIZED LATIN SMALL LETTER Y +24B5;24B5;24B5;0028 007A 0029;0028 007A 0029; # (⒵; ⒵; ⒵; (z); (z); ) PARENTHESIZED LATIN SMALL LETTER Z +24B6;24B6;24B6;0041;0041; # (Ⓐ; Ⓐ; Ⓐ; A; A; ) CIRCLED LATIN CAPITAL LETTER A +24B7;24B7;24B7;0042;0042; # (Ⓑ; Ⓑ; Ⓑ; B; B; ) CIRCLED LATIN CAPITAL LETTER B +24B8;24B8;24B8;0043;0043; # (Ⓒ; Ⓒ; Ⓒ; C; C; ) CIRCLED LATIN CAPITAL LETTER C +24B9;24B9;24B9;0044;0044; # (Ⓓ; Ⓓ; Ⓓ; D; D; ) CIRCLED LATIN CAPITAL LETTER D +24BA;24BA;24BA;0045;0045; # (Ⓔ; Ⓔ; Ⓔ; E; E; ) CIRCLED LATIN CAPITAL LETTER E +24BB;24BB;24BB;0046;0046; # (Ⓕ; Ⓕ; Ⓕ; F; F; ) CIRCLED LATIN CAPITAL LETTER F +24BC;24BC;24BC;0047;0047; # (Ⓖ; Ⓖ; Ⓖ; G; G; ) CIRCLED LATIN CAPITAL LETTER G +24BD;24BD;24BD;0048;0048; # (Ⓗ; Ⓗ; Ⓗ; H; H; ) CIRCLED LATIN CAPITAL LETTER H +24BE;24BE;24BE;0049;0049; # (Ⓘ; Ⓘ; Ⓘ; I; I; ) CIRCLED LATIN CAPITAL LETTER I +24BF;24BF;24BF;004A;004A; # (Ⓙ; Ⓙ; Ⓙ; J; J; ) CIRCLED LATIN CAPITAL LETTER J +24C0;24C0;24C0;004B;004B; # (Ⓚ; Ⓚ; Ⓚ; K; K; ) CIRCLED LATIN CAPITAL LETTER K +24C1;24C1;24C1;004C;004C; # (Ⓛ; Ⓛ; Ⓛ; L; L; ) CIRCLED LATIN CAPITAL LETTER L +24C2;24C2;24C2;004D;004D; # (Ⓜ; Ⓜ; Ⓜ; M; M; ) CIRCLED LATIN CAPITAL LETTER M +24C3;24C3;24C3;004E;004E; # (Ⓝ; Ⓝ; Ⓝ; N; N; ) CIRCLED LATIN CAPITAL LETTER N +24C4;24C4;24C4;004F;004F; # (Ⓞ; Ⓞ; Ⓞ; O; O; ) CIRCLED LATIN CAPITAL LETTER O +24C5;24C5;24C5;0050;0050; # (Ⓟ; Ⓟ; Ⓟ; P; P; ) CIRCLED LATIN CAPITAL LETTER P +24C6;24C6;24C6;0051;0051; # (Ⓠ; Ⓠ; Ⓠ; Q; Q; ) CIRCLED LATIN CAPITAL LETTER Q +24C7;24C7;24C7;0052;0052; # (Ⓡ; Ⓡ; Ⓡ; R; R; ) CIRCLED LATIN CAPITAL LETTER R +24C8;24C8;24C8;0053;0053; # (Ⓢ; Ⓢ; Ⓢ; S; S; ) CIRCLED LATIN CAPITAL LETTER S +24C9;24C9;24C9;0054;0054; # (Ⓣ; Ⓣ; Ⓣ; T; T; ) CIRCLED LATIN CAPITAL LETTER T +24CA;24CA;24CA;0055;0055; # (Ⓤ; Ⓤ; Ⓤ; U; U; ) CIRCLED LATIN CAPITAL LETTER U +24CB;24CB;24CB;0056;0056; # (Ⓥ; Ⓥ; Ⓥ; V; V; ) CIRCLED LATIN CAPITAL LETTER V +24CC;24CC;24CC;0057;0057; # (Ⓦ; Ⓦ; Ⓦ; W; W; ) CIRCLED LATIN CAPITAL LETTER W +24CD;24CD;24CD;0058;0058; # (Ⓧ; Ⓧ; Ⓧ; X; X; ) CIRCLED LATIN CAPITAL LETTER X +24CE;24CE;24CE;0059;0059; # (Ⓨ; Ⓨ; Ⓨ; Y; Y; ) CIRCLED LATIN CAPITAL LETTER Y +24CF;24CF;24CF;005A;005A; # (Ⓩ; Ⓩ; Ⓩ; Z; Z; ) CIRCLED LATIN CAPITAL LETTER Z +24D0;24D0;24D0;0061;0061; # (ⓐ; ⓐ; ⓐ; a; a; ) CIRCLED LATIN SMALL LETTER A +24D1;24D1;24D1;0062;0062; # (ⓑ; ⓑ; ⓑ; b; b; ) CIRCLED LATIN SMALL LETTER B +24D2;24D2;24D2;0063;0063; # (ⓒ; ⓒ; ⓒ; c; c; ) CIRCLED LATIN SMALL LETTER C +24D3;24D3;24D3;0064;0064; # (ⓓ; ⓓ; ⓓ; d; d; ) CIRCLED LATIN SMALL LETTER D +24D4;24D4;24D4;0065;0065; # (ⓔ; ⓔ; ⓔ; e; e; ) CIRCLED LATIN SMALL LETTER E +24D5;24D5;24D5;0066;0066; # (ⓕ; ⓕ; ⓕ; f; f; ) CIRCLED LATIN SMALL LETTER F +24D6;24D6;24D6;0067;0067; # (ⓖ; ⓖ; ⓖ; g; g; ) CIRCLED LATIN SMALL LETTER G +24D7;24D7;24D7;0068;0068; # (ⓗ; ⓗ; ⓗ; h; h; ) CIRCLED LATIN SMALL LETTER H +24D8;24D8;24D8;0069;0069; # (ⓘ; ⓘ; ⓘ; i; i; ) CIRCLED LATIN SMALL LETTER I +24D9;24D9;24D9;006A;006A; # (ⓙ; ⓙ; ⓙ; j; j; ) CIRCLED LATIN SMALL LETTER J +24DA;24DA;24DA;006B;006B; # (ⓚ; ⓚ; ⓚ; k; k; ) CIRCLED LATIN SMALL LETTER K +24DB;24DB;24DB;006C;006C; # (ⓛ; ⓛ; ⓛ; l; l; ) CIRCLED LATIN SMALL LETTER L +24DC;24DC;24DC;006D;006D; # (ⓜ; ⓜ; ⓜ; m; m; ) CIRCLED LATIN SMALL LETTER M +24DD;24DD;24DD;006E;006E; # (ⓝ; ⓝ; ⓝ; n; n; ) CIRCLED LATIN SMALL LETTER N +24DE;24DE;24DE;006F;006F; # (ⓞ; ⓞ; ⓞ; o; o; ) CIRCLED LATIN SMALL LETTER O +24DF;24DF;24DF;0070;0070; # (ⓟ; ⓟ; ⓟ; p; p; ) CIRCLED LATIN SMALL LETTER P +24E0;24E0;24E0;0071;0071; # (ⓠ; ⓠ; ⓠ; q; q; ) CIRCLED LATIN SMALL LETTER Q +24E1;24E1;24E1;0072;0072; # (ⓡ; ⓡ; ⓡ; r; r; ) CIRCLED LATIN SMALL LETTER R +24E2;24E2;24E2;0073;0073; # (ⓢ; ⓢ; ⓢ; s; s; ) CIRCLED LATIN SMALL LETTER S +24E3;24E3;24E3;0074;0074; # (ⓣ; ⓣ; ⓣ; t; t; ) CIRCLED LATIN SMALL LETTER T +24E4;24E4;24E4;0075;0075; # (ⓤ; ⓤ; ⓤ; u; u; ) CIRCLED LATIN SMALL LETTER U +24E5;24E5;24E5;0076;0076; # (ⓥ; ⓥ; ⓥ; v; v; ) CIRCLED LATIN SMALL LETTER V +24E6;24E6;24E6;0077;0077; # (ⓦ; ⓦ; ⓦ; w; w; ) CIRCLED LATIN SMALL LETTER W +24E7;24E7;24E7;0078;0078; # (ⓧ; ⓧ; ⓧ; x; x; ) CIRCLED LATIN SMALL LETTER X +24E8;24E8;24E8;0079;0079; # (ⓨ; ⓨ; ⓨ; y; y; ) CIRCLED LATIN SMALL LETTER Y +24E9;24E9;24E9;007A;007A; # (ⓩ; ⓩ; ⓩ; z; z; ) CIRCLED LATIN SMALL LETTER Z +24EA;24EA;24EA;0030;0030; # (⓪; ⓪; ⓪; 0; 0; ) CIRCLED DIGIT ZERO +2A0C;2A0C;2A0C;222B 222B 222B 222B;222B 222B 222B 222B; # (⨌; ⨌; ⨌; ∫∫∫∫; ∫∫∫∫; ) QUADRUPLE INTEGRAL OPERATOR +2A74;2A74;2A74;003A 003A 003D;003A 003A 003D; # (⩴; ⩴; ⩴; ::=; ::=; ) DOUBLE COLON EQUAL +2A75;2A75;2A75;003D 003D;003D 003D; # (⩵; ⩵; ⩵; ==; ==; ) TWO CONSECUTIVE EQUALS SIGNS +2A76;2A76;2A76;003D 003D 003D;003D 003D 003D; # (⩶; ⩶; ⩶; ===; ===; ) THREE CONSECUTIVE EQUALS SIGNS +2ADC;2ADD 0338;2ADD 0338;2ADD 0338;2ADD 0338; # (⫝̸; ⫝◌̸; ⫝◌̸; ⫝◌̸; ⫝◌̸; ) FORKING +2E9F;2E9F;2E9F;6BCD;6BCD; # (⺟; ⺟; ⺟; 母; 母; ) CJK RADICAL MOTHER +2EF3;2EF3;2EF3;9F9F;9F9F; # (⻳; ⻳; ⻳; 龟; 龟; ) CJK RADICAL C-SIMPLIFIED TURTLE +2F00;2F00;2F00;4E00;4E00; # (⼀; ⼀; ⼀; 一; 一; ) KANGXI RADICAL ONE +2F01;2F01;2F01;4E28;4E28; # (⼁; ⼁; ⼁; 丨; 丨; ) KANGXI RADICAL LINE +2F02;2F02;2F02;4E36;4E36; # (⼂; ⼂; ⼂; 丶; 丶; ) KANGXI RADICAL DOT +2F03;2F03;2F03;4E3F;4E3F; # (⼃; ⼃; ⼃; 丿; 丿; ) KANGXI RADICAL SLASH +2F04;2F04;2F04;4E59;4E59; # (⼄; ⼄; ⼄; 乙; 乙; ) KANGXI RADICAL SECOND +2F05;2F05;2F05;4E85;4E85; # (⼅; ⼅; ⼅; 亅; 亅; ) KANGXI RADICAL HOOK +2F06;2F06;2F06;4E8C;4E8C; # (⼆; ⼆; ⼆; 二; 二; ) KANGXI RADICAL TWO +2F07;2F07;2F07;4EA0;4EA0; # (⼇; ⼇; ⼇; 亠; 亠; ) KANGXI RADICAL LID +2F08;2F08;2F08;4EBA;4EBA; # (⼈; ⼈; ⼈; 人; 人; ) KANGXI RADICAL MAN +2F09;2F09;2F09;513F;513F; # (⼉; ⼉; ⼉; 儿; 儿; ) KANGXI RADICAL LEGS +2F0A;2F0A;2F0A;5165;5165; # (⼊; ⼊; ⼊; 入; 入; ) KANGXI RADICAL ENTER +2F0B;2F0B;2F0B;516B;516B; # (⼋; ⼋; ⼋; 八; 八; ) KANGXI RADICAL EIGHT +2F0C;2F0C;2F0C;5182;5182; # (⼌; ⼌; ⼌; 冂; 冂; ) KANGXI RADICAL DOWN BOX +2F0D;2F0D;2F0D;5196;5196; # (⼍; ⼍; ⼍; 冖; 冖; ) KANGXI RADICAL COVER +2F0E;2F0E;2F0E;51AB;51AB; # (⼎; ⼎; ⼎; 冫; 冫; ) KANGXI RADICAL ICE +2F0F;2F0F;2F0F;51E0;51E0; # (⼏; ⼏; ⼏; 几; 几; ) KANGXI RADICAL TABLE +2F10;2F10;2F10;51F5;51F5; # (⼐; ⼐; ⼐; 凵; 凵; ) KANGXI RADICAL OPEN BOX +2F11;2F11;2F11;5200;5200; # (⼑; ⼑; ⼑; 刀; 刀; ) KANGXI RADICAL KNIFE +2F12;2F12;2F12;529B;529B; # (⼒; ⼒; ⼒; 力; 力; ) KANGXI RADICAL POWER +2F13;2F13;2F13;52F9;52F9; # (⼓; ⼓; ⼓; 勹; 勹; ) KANGXI RADICAL WRAP +2F14;2F14;2F14;5315;5315; # (⼔; ⼔; ⼔; 匕; 匕; ) KANGXI RADICAL SPOON +2F15;2F15;2F15;531A;531A; # (⼕; ⼕; ⼕; 匚; 匚; ) KANGXI RADICAL RIGHT OPEN BOX +2F16;2F16;2F16;5338;5338; # (⼖; ⼖; ⼖; 匸; 匸; ) KANGXI RADICAL HIDING ENCLOSURE +2F17;2F17;2F17;5341;5341; # (⼗; ⼗; ⼗; 十; 十; ) KANGXI RADICAL TEN +2F18;2F18;2F18;535C;535C; # (⼘; ⼘; ⼘; 卜; 卜; ) KANGXI RADICAL DIVINATION +2F19;2F19;2F19;5369;5369; # (⼙; ⼙; ⼙; 卩; 卩; ) KANGXI RADICAL SEAL +2F1A;2F1A;2F1A;5382;5382; # (⼚; ⼚; ⼚; 厂; 厂; ) KANGXI RADICAL CLIFF +2F1B;2F1B;2F1B;53B6;53B6; # (⼛; ⼛; ⼛; 厶; 厶; ) KANGXI RADICAL PRIVATE +2F1C;2F1C;2F1C;53C8;53C8; # (⼜; ⼜; ⼜; 又; 又; ) KANGXI RADICAL AGAIN +2F1D;2F1D;2F1D;53E3;53E3; # (⼝; ⼝; ⼝; 口; 口; ) KANGXI RADICAL MOUTH +2F1E;2F1E;2F1E;56D7;56D7; # (⼞; ⼞; ⼞; 囗; 囗; ) KANGXI RADICAL ENCLOSURE +2F1F;2F1F;2F1F;571F;571F; # (⼟; ⼟; ⼟; 土; 土; ) KANGXI RADICAL EARTH +2F20;2F20;2F20;58EB;58EB; # (⼠; ⼠; ⼠; 士; 士; ) KANGXI RADICAL SCHOLAR +2F21;2F21;2F21;5902;5902; # (⼡; ⼡; ⼡; 夂; 夂; ) KANGXI RADICAL GO +2F22;2F22;2F22;590A;590A; # (⼢; ⼢; ⼢; 夊; 夊; ) KANGXI RADICAL GO SLOWLY +2F23;2F23;2F23;5915;5915; # (⼣; ⼣; ⼣; 夕; 夕; ) KANGXI RADICAL EVENING +2F24;2F24;2F24;5927;5927; # (⼤; ⼤; ⼤; 大; 大; ) KANGXI RADICAL BIG +2F25;2F25;2F25;5973;5973; # (⼥; ⼥; ⼥; 女; 女; ) KANGXI RADICAL WOMAN +2F26;2F26;2F26;5B50;5B50; # (⼦; ⼦; ⼦; 子; 子; ) KANGXI RADICAL CHILD +2F27;2F27;2F27;5B80;5B80; # (⼧; ⼧; ⼧; 宀; 宀; ) KANGXI RADICAL ROOF +2F28;2F28;2F28;5BF8;5BF8; # (⼨; ⼨; ⼨; 寸; 寸; ) KANGXI RADICAL INCH +2F29;2F29;2F29;5C0F;5C0F; # (⼩; ⼩; ⼩; 小; 小; ) KANGXI RADICAL SMALL +2F2A;2F2A;2F2A;5C22;5C22; # (⼪; ⼪; ⼪; 尢; 尢; ) KANGXI RADICAL LAME +2F2B;2F2B;2F2B;5C38;5C38; # (⼫; ⼫; ⼫; 尸; 尸; ) KANGXI RADICAL CORPSE +2F2C;2F2C;2F2C;5C6E;5C6E; # (⼬; ⼬; ⼬; 屮; 屮; ) KANGXI RADICAL SPROUT +2F2D;2F2D;2F2D;5C71;5C71; # (⼭; ⼭; ⼭; 山; 山; ) KANGXI RADICAL MOUNTAIN +2F2E;2F2E;2F2E;5DDB;5DDB; # (⼮; ⼮; ⼮; 巛; 巛; ) KANGXI RADICAL RIVER +2F2F;2F2F;2F2F;5DE5;5DE5; # (⼯; ⼯; ⼯; 工; 工; ) KANGXI RADICAL WORK +2F30;2F30;2F30;5DF1;5DF1; # (⼰; ⼰; ⼰; 己; 己; ) KANGXI RADICAL ONESELF +2F31;2F31;2F31;5DFE;5DFE; # (⼱; ⼱; ⼱; 巾; 巾; ) KANGXI RADICAL TURBAN +2F32;2F32;2F32;5E72;5E72; # (⼲; ⼲; ⼲; 干; 干; ) KANGXI RADICAL DRY +2F33;2F33;2F33;5E7A;5E7A; # (⼳; ⼳; ⼳; 幺; 幺; ) KANGXI RADICAL SHORT THREAD +2F34;2F34;2F34;5E7F;5E7F; # (⼴; ⼴; ⼴; 广; 广; ) KANGXI RADICAL DOTTED CLIFF +2F35;2F35;2F35;5EF4;5EF4; # (⼵; ⼵; ⼵; 廴; 廴; ) KANGXI RADICAL LONG STRIDE +2F36;2F36;2F36;5EFE;5EFE; # (⼶; ⼶; ⼶; 廾; 廾; ) KANGXI RADICAL TWO HANDS +2F37;2F37;2F37;5F0B;5F0B; # (⼷; ⼷; ⼷; 弋; 弋; ) KANGXI RADICAL SHOOT +2F38;2F38;2F38;5F13;5F13; # (⼸; ⼸; ⼸; 弓; 弓; ) KANGXI RADICAL BOW +2F39;2F39;2F39;5F50;5F50; # (⼹; ⼹; ⼹; 彐; 彐; ) KANGXI RADICAL SNOUT +2F3A;2F3A;2F3A;5F61;5F61; # (⼺; ⼺; ⼺; 彡; 彡; ) KANGXI RADICAL BRISTLE +2F3B;2F3B;2F3B;5F73;5F73; # (⼻; ⼻; ⼻; 彳; 彳; ) KANGXI RADICAL STEP +2F3C;2F3C;2F3C;5FC3;5FC3; # (⼼; ⼼; ⼼; 心; 心; ) KANGXI RADICAL HEART +2F3D;2F3D;2F3D;6208;6208; # (⼽; ⼽; ⼽; 戈; 戈; ) KANGXI RADICAL HALBERD +2F3E;2F3E;2F3E;6236;6236; # (⼾; ⼾; ⼾; 戶; 戶; ) KANGXI RADICAL DOOR +2F3F;2F3F;2F3F;624B;624B; # (⼿; ⼿; ⼿; 手; 手; ) KANGXI RADICAL HAND +2F40;2F40;2F40;652F;652F; # (⽀; ⽀; ⽀; 支; 支; ) KANGXI RADICAL BRANCH +2F41;2F41;2F41;6534;6534; # (⽁; ⽁; ⽁; 攴; 攴; ) KANGXI RADICAL RAP +2F42;2F42;2F42;6587;6587; # (⽂; ⽂; ⽂; 文; 文; ) KANGXI RADICAL SCRIPT +2F43;2F43;2F43;6597;6597; # (⽃; ⽃; ⽃; 斗; 斗; ) KANGXI RADICAL DIPPER +2F44;2F44;2F44;65A4;65A4; # (⽄; ⽄; ⽄; 斤; 斤; ) KANGXI RADICAL AXE +2F45;2F45;2F45;65B9;65B9; # (⽅; ⽅; ⽅; 方; 方; ) KANGXI RADICAL SQUARE +2F46;2F46;2F46;65E0;65E0; # (⽆; ⽆; ⽆; 无; 无; ) KANGXI RADICAL NOT +2F47;2F47;2F47;65E5;65E5; # (⽇; ⽇; ⽇; 日; 日; ) KANGXI RADICAL SUN +2F48;2F48;2F48;66F0;66F0; # (⽈; ⽈; ⽈; 曰; 曰; ) KANGXI RADICAL SAY +2F49;2F49;2F49;6708;6708; # (⽉; ⽉; ⽉; 月; 月; ) KANGXI RADICAL MOON +2F4A;2F4A;2F4A;6728;6728; # (⽊; ⽊; ⽊; 木; 木; ) KANGXI RADICAL TREE +2F4B;2F4B;2F4B;6B20;6B20; # (⽋; ⽋; ⽋; 欠; 欠; ) KANGXI RADICAL LACK +2F4C;2F4C;2F4C;6B62;6B62; # (⽌; ⽌; ⽌; 止; 止; ) KANGXI RADICAL STOP +2F4D;2F4D;2F4D;6B79;6B79; # (⽍; ⽍; ⽍; 歹; 歹; ) KANGXI RADICAL DEATH +2F4E;2F4E;2F4E;6BB3;6BB3; # (⽎; ⽎; ⽎; 殳; 殳; ) KANGXI RADICAL WEAPON +2F4F;2F4F;2F4F;6BCB;6BCB; # (⽏; ⽏; ⽏; 毋; 毋; ) KANGXI RADICAL DO NOT +2F50;2F50;2F50;6BD4;6BD4; # (⽐; ⽐; ⽐; 比; 比; ) KANGXI RADICAL COMPARE +2F51;2F51;2F51;6BDB;6BDB; # (⽑; ⽑; ⽑; 毛; 毛; ) KANGXI RADICAL FUR +2F52;2F52;2F52;6C0F;6C0F; # (⽒; ⽒; ⽒; 氏; 氏; ) KANGXI RADICAL CLAN +2F53;2F53;2F53;6C14;6C14; # (⽓; ⽓; ⽓; 气; 气; ) KANGXI RADICAL STEAM +2F54;2F54;2F54;6C34;6C34; # (⽔; ⽔; ⽔; 水; 水; ) KANGXI RADICAL WATER +2F55;2F55;2F55;706B;706B; # (⽕; ⽕; ⽕; 火; 火; ) KANGXI RADICAL FIRE +2F56;2F56;2F56;722A;722A; # (⽖; ⽖; ⽖; 爪; 爪; ) KANGXI RADICAL CLAW +2F57;2F57;2F57;7236;7236; # (⽗; ⽗; ⽗; 父; 父; ) KANGXI RADICAL FATHER +2F58;2F58;2F58;723B;723B; # (⽘; ⽘; ⽘; 爻; 爻; ) KANGXI RADICAL DOUBLE X +2F59;2F59;2F59;723F;723F; # (⽙; ⽙; ⽙; 爿; 爿; ) KANGXI RADICAL HALF TREE TRUNK +2F5A;2F5A;2F5A;7247;7247; # (⽚; ⽚; ⽚; 片; 片; ) KANGXI RADICAL SLICE +2F5B;2F5B;2F5B;7259;7259; # (⽛; ⽛; ⽛; 牙; 牙; ) KANGXI RADICAL FANG +2F5C;2F5C;2F5C;725B;725B; # (⽜; ⽜; ⽜; 牛; 牛; ) KANGXI RADICAL COW +2F5D;2F5D;2F5D;72AC;72AC; # (⽝; ⽝; ⽝; 犬; 犬; ) KANGXI RADICAL DOG +2F5E;2F5E;2F5E;7384;7384; # (⽞; ⽞; ⽞; 玄; 玄; ) KANGXI RADICAL PROFOUND +2F5F;2F5F;2F5F;7389;7389; # (⽟; ⽟; ⽟; 玉; 玉; ) KANGXI RADICAL JADE +2F60;2F60;2F60;74DC;74DC; # (⽠; ⽠; ⽠; 瓜; 瓜; ) KANGXI RADICAL MELON +2F61;2F61;2F61;74E6;74E6; # (⽡; ⽡; ⽡; 瓦; 瓦; ) KANGXI RADICAL TILE +2F62;2F62;2F62;7518;7518; # (⽢; ⽢; ⽢; 甘; 甘; ) KANGXI RADICAL SWEET +2F63;2F63;2F63;751F;751F; # (⽣; ⽣; ⽣; 生; 生; ) KANGXI RADICAL LIFE +2F64;2F64;2F64;7528;7528; # (⽤; ⽤; ⽤; 用; 用; ) KANGXI RADICAL USE +2F65;2F65;2F65;7530;7530; # (⽥; ⽥; ⽥; 田; 田; ) KANGXI RADICAL FIELD +2F66;2F66;2F66;758B;758B; # (⽦; ⽦; ⽦; 疋; 疋; ) KANGXI RADICAL BOLT OF CLOTH +2F67;2F67;2F67;7592;7592; # (⽧; ⽧; ⽧; 疒; 疒; ) KANGXI RADICAL SICKNESS +2F68;2F68;2F68;7676;7676; # (⽨; ⽨; ⽨; 癶; 癶; ) KANGXI RADICAL DOTTED TENT +2F69;2F69;2F69;767D;767D; # (⽩; ⽩; ⽩; 白; 白; ) KANGXI RADICAL WHITE +2F6A;2F6A;2F6A;76AE;76AE; # (⽪; ⽪; ⽪; 皮; 皮; ) KANGXI RADICAL SKIN +2F6B;2F6B;2F6B;76BF;76BF; # (⽫; ⽫; ⽫; 皿; 皿; ) KANGXI RADICAL DISH +2F6C;2F6C;2F6C;76EE;76EE; # (⽬; ⽬; ⽬; 目; 目; ) KANGXI RADICAL EYE +2F6D;2F6D;2F6D;77DB;77DB; # (⽭; ⽭; ⽭; 矛; 矛; ) KANGXI RADICAL SPEAR +2F6E;2F6E;2F6E;77E2;77E2; # (⽮; ⽮; ⽮; 矢; 矢; ) KANGXI RADICAL ARROW +2F6F;2F6F;2F6F;77F3;77F3; # (⽯; ⽯; ⽯; 石; 石; ) KANGXI RADICAL STONE +2F70;2F70;2F70;793A;793A; # (⽰; ⽰; ⽰; 示; 示; ) KANGXI RADICAL SPIRIT +2F71;2F71;2F71;79B8;79B8; # (⽱; ⽱; ⽱; 禸; 禸; ) KANGXI RADICAL TRACK +2F72;2F72;2F72;79BE;79BE; # (⽲; ⽲; ⽲; 禾; 禾; ) KANGXI RADICAL GRAIN +2F73;2F73;2F73;7A74;7A74; # (⽳; ⽳; ⽳; 穴; 穴; ) KANGXI RADICAL CAVE +2F74;2F74;2F74;7ACB;7ACB; # (⽴; ⽴; ⽴; 立; 立; ) KANGXI RADICAL STAND +2F75;2F75;2F75;7AF9;7AF9; # (⽵; ⽵; ⽵; 竹; 竹; ) KANGXI RADICAL BAMBOO +2F76;2F76;2F76;7C73;7C73; # (⽶; ⽶; ⽶; 米; 米; ) KANGXI RADICAL RICE +2F77;2F77;2F77;7CF8;7CF8; # (⽷; ⽷; ⽷; 糸; 糸; ) KANGXI RADICAL SILK +2F78;2F78;2F78;7F36;7F36; # (⽸; ⽸; ⽸; 缶; 缶; ) KANGXI RADICAL JAR +2F79;2F79;2F79;7F51;7F51; # (⽹; ⽹; ⽹; 网; 网; ) KANGXI RADICAL NET +2F7A;2F7A;2F7A;7F8A;7F8A; # (⽺; ⽺; ⽺; 羊; 羊; ) KANGXI RADICAL SHEEP +2F7B;2F7B;2F7B;7FBD;7FBD; # (⽻; ⽻; ⽻; 羽; 羽; ) KANGXI RADICAL FEATHER +2F7C;2F7C;2F7C;8001;8001; # (⽼; ⽼; ⽼; 老; 老; ) KANGXI RADICAL OLD +2F7D;2F7D;2F7D;800C;800C; # (⽽; ⽽; ⽽; 而; 而; ) KANGXI RADICAL AND +2F7E;2F7E;2F7E;8012;8012; # (⽾; ⽾; ⽾; 耒; 耒; ) KANGXI RADICAL PLOW +2F7F;2F7F;2F7F;8033;8033; # (⽿; ⽿; ⽿; 耳; 耳; ) KANGXI RADICAL EAR +2F80;2F80;2F80;807F;807F; # (⾀; ⾀; ⾀; 聿; 聿; ) KANGXI RADICAL BRUSH +2F81;2F81;2F81;8089;8089; # (⾁; ⾁; ⾁; 肉; 肉; ) KANGXI RADICAL MEAT +2F82;2F82;2F82;81E3;81E3; # (⾂; ⾂; ⾂; 臣; 臣; ) KANGXI RADICAL MINISTER +2F83;2F83;2F83;81EA;81EA; # (⾃; ⾃; ⾃; 自; 自; ) KANGXI RADICAL SELF +2F84;2F84;2F84;81F3;81F3; # (⾄; ⾄; ⾄; 至; 至; ) KANGXI RADICAL ARRIVE +2F85;2F85;2F85;81FC;81FC; # (⾅; ⾅; ⾅; 臼; 臼; ) KANGXI RADICAL MORTAR +2F86;2F86;2F86;820C;820C; # (⾆; ⾆; ⾆; 舌; 舌; ) KANGXI RADICAL TONGUE +2F87;2F87;2F87;821B;821B; # (⾇; ⾇; ⾇; 舛; 舛; ) KANGXI RADICAL OPPOSE +2F88;2F88;2F88;821F;821F; # (⾈; ⾈; ⾈; 舟; 舟; ) KANGXI RADICAL BOAT +2F89;2F89;2F89;826E;826E; # (⾉; ⾉; ⾉; 艮; 艮; ) KANGXI RADICAL STOPPING +2F8A;2F8A;2F8A;8272;8272; # (⾊; ⾊; ⾊; 色; 色; ) KANGXI RADICAL COLOR +2F8B;2F8B;2F8B;8278;8278; # (⾋; ⾋; ⾋; 艸; 艸; ) KANGXI RADICAL GRASS +2F8C;2F8C;2F8C;864D;864D; # (⾌; ⾌; ⾌; 虍; 虍; ) KANGXI RADICAL TIGER +2F8D;2F8D;2F8D;866B;866B; # (⾍; ⾍; ⾍; 虫; 虫; ) KANGXI RADICAL INSECT +2F8E;2F8E;2F8E;8840;8840; # (⾎; ⾎; ⾎; 血; 血; ) KANGXI RADICAL BLOOD +2F8F;2F8F;2F8F;884C;884C; # (⾏; ⾏; ⾏; 行; 行; ) KANGXI RADICAL WALK ENCLOSURE +2F90;2F90;2F90;8863;8863; # (⾐; ⾐; ⾐; 衣; 衣; ) KANGXI RADICAL CLOTHES +2F91;2F91;2F91;897E;897E; # (⾑; ⾑; ⾑; 襾; 襾; ) KANGXI RADICAL WEST +2F92;2F92;2F92;898B;898B; # (⾒; ⾒; ⾒; 見; 見; ) KANGXI RADICAL SEE +2F93;2F93;2F93;89D2;89D2; # (⾓; ⾓; ⾓; 角; 角; ) KANGXI RADICAL HORN +2F94;2F94;2F94;8A00;8A00; # (⾔; ⾔; ⾔; 言; 言; ) KANGXI RADICAL SPEECH +2F95;2F95;2F95;8C37;8C37; # (⾕; ⾕; ⾕; 谷; 谷; ) KANGXI RADICAL VALLEY +2F96;2F96;2F96;8C46;8C46; # (⾖; ⾖; ⾖; 豆; 豆; ) KANGXI RADICAL BEAN +2F97;2F97;2F97;8C55;8C55; # (⾗; ⾗; ⾗; 豕; 豕; ) KANGXI RADICAL PIG +2F98;2F98;2F98;8C78;8C78; # (⾘; ⾘; ⾘; 豸; 豸; ) KANGXI RADICAL BADGER +2F99;2F99;2F99;8C9D;8C9D; # (⾙; ⾙; ⾙; 貝; 貝; ) KANGXI RADICAL SHELL +2F9A;2F9A;2F9A;8D64;8D64; # (⾚; ⾚; ⾚; 赤; 赤; ) KANGXI RADICAL RED +2F9B;2F9B;2F9B;8D70;8D70; # (⾛; ⾛; ⾛; 走; 走; ) KANGXI RADICAL RUN +2F9C;2F9C;2F9C;8DB3;8DB3; # (⾜; ⾜; ⾜; 足; 足; ) KANGXI RADICAL FOOT +2F9D;2F9D;2F9D;8EAB;8EAB; # (⾝; ⾝; ⾝; 身; 身; ) KANGXI RADICAL BODY +2F9E;2F9E;2F9E;8ECA;8ECA; # (⾞; ⾞; ⾞; 車; 車; ) KANGXI RADICAL CART +2F9F;2F9F;2F9F;8F9B;8F9B; # (⾟; ⾟; ⾟; 辛; 辛; ) KANGXI RADICAL BITTER +2FA0;2FA0;2FA0;8FB0;8FB0; # (⾠; ⾠; ⾠; 辰; 辰; ) KANGXI RADICAL MORNING +2FA1;2FA1;2FA1;8FB5;8FB5; # (⾡; ⾡; ⾡; 辵; 辵; ) KANGXI RADICAL WALK +2FA2;2FA2;2FA2;9091;9091; # (⾢; ⾢; ⾢; 邑; 邑; ) KANGXI RADICAL CITY +2FA3;2FA3;2FA3;9149;9149; # (⾣; ⾣; ⾣; 酉; 酉; ) KANGXI RADICAL WINE +2FA4;2FA4;2FA4;91C6;91C6; # (⾤; ⾤; ⾤; 釆; 釆; ) KANGXI RADICAL DISTINGUISH +2FA5;2FA5;2FA5;91CC;91CC; # (⾥; ⾥; ⾥; 里; 里; ) KANGXI RADICAL VILLAGE +2FA6;2FA6;2FA6;91D1;91D1; # (⾦; ⾦; ⾦; 金; 金; ) KANGXI RADICAL GOLD +2FA7;2FA7;2FA7;9577;9577; # (⾧; ⾧; ⾧; 長; 長; ) KANGXI RADICAL LONG +2FA8;2FA8;2FA8;9580;9580; # (⾨; ⾨; ⾨; 門; 門; ) KANGXI RADICAL GATE +2FA9;2FA9;2FA9;961C;961C; # (⾩; ⾩; ⾩; 阜; 阜; ) KANGXI RADICAL MOUND +2FAA;2FAA;2FAA;96B6;96B6; # (⾪; ⾪; ⾪; 隶; 隶; ) KANGXI RADICAL SLAVE +2FAB;2FAB;2FAB;96B9;96B9; # (⾫; ⾫; ⾫; 隹; 隹; ) KANGXI RADICAL SHORT TAILED BIRD +2FAC;2FAC;2FAC;96E8;96E8; # (⾬; ⾬; ⾬; 雨; 雨; ) KANGXI RADICAL RAIN +2FAD;2FAD;2FAD;9751;9751; # (⾭; ⾭; ⾭; 靑; 靑; ) KANGXI RADICAL BLUE +2FAE;2FAE;2FAE;975E;975E; # (⾮; ⾮; ⾮; 非; 非; ) KANGXI RADICAL WRONG +2FAF;2FAF;2FAF;9762;9762; # (⾯; ⾯; ⾯; 面; 面; ) KANGXI RADICAL FACE +2FB0;2FB0;2FB0;9769;9769; # (⾰; ⾰; ⾰; 革; 革; ) KANGXI RADICAL LEATHER +2FB1;2FB1;2FB1;97CB;97CB; # (⾱; ⾱; ⾱; 韋; 韋; ) KANGXI RADICAL TANNED LEATHER +2FB2;2FB2;2FB2;97ED;97ED; # (⾲; ⾲; ⾲; 韭; 韭; ) KANGXI RADICAL LEEK +2FB3;2FB3;2FB3;97F3;97F3; # (⾳; ⾳; ⾳; 音; 音; ) KANGXI RADICAL SOUND +2FB4;2FB4;2FB4;9801;9801; # (⾴; ⾴; ⾴; 頁; 頁; ) KANGXI RADICAL LEAF +2FB5;2FB5;2FB5;98A8;98A8; # (⾵; ⾵; ⾵; 風; 風; ) KANGXI RADICAL WIND +2FB6;2FB6;2FB6;98DB;98DB; # (⾶; ⾶; ⾶; 飛; 飛; ) KANGXI RADICAL FLY +2FB7;2FB7;2FB7;98DF;98DF; # (⾷; ⾷; ⾷; 食; 食; ) KANGXI RADICAL EAT +2FB8;2FB8;2FB8;9996;9996; # (⾸; ⾸; ⾸; 首; 首; ) KANGXI RADICAL HEAD +2FB9;2FB9;2FB9;9999;9999; # (⾹; ⾹; ⾹; 香; 香; ) KANGXI RADICAL FRAGRANT +2FBA;2FBA;2FBA;99AC;99AC; # (⾺; ⾺; ⾺; 馬; 馬; ) KANGXI RADICAL HORSE +2FBB;2FBB;2FBB;9AA8;9AA8; # (⾻; ⾻; ⾻; 骨; 骨; ) KANGXI RADICAL BONE +2FBC;2FBC;2FBC;9AD8;9AD8; # (⾼; ⾼; ⾼; 高; 高; ) KANGXI RADICAL TALL +2FBD;2FBD;2FBD;9ADF;9ADF; # (⾽; ⾽; ⾽; 髟; 髟; ) KANGXI RADICAL HAIR +2FBE;2FBE;2FBE;9B25;9B25; # (⾾; ⾾; ⾾; 鬥; 鬥; ) KANGXI RADICAL FIGHT +2FBF;2FBF;2FBF;9B2F;9B2F; # (⾿; ⾿; ⾿; 鬯; 鬯; ) KANGXI RADICAL SACRIFICIAL WINE +2FC0;2FC0;2FC0;9B32;9B32; # (⿀; ⿀; ⿀; 鬲; 鬲; ) KANGXI RADICAL CAULDRON +2FC1;2FC1;2FC1;9B3C;9B3C; # (⿁; ⿁; ⿁; 鬼; 鬼; ) KANGXI RADICAL GHOST +2FC2;2FC2;2FC2;9B5A;9B5A; # (⿂; ⿂; ⿂; 魚; 魚; ) KANGXI RADICAL FISH +2FC3;2FC3;2FC3;9CE5;9CE5; # (⿃; ⿃; ⿃; 鳥; 鳥; ) KANGXI RADICAL BIRD +2FC4;2FC4;2FC4;9E75;9E75; # (⿄; ⿄; ⿄; 鹵; 鹵; ) KANGXI RADICAL SALT +2FC5;2FC5;2FC5;9E7F;9E7F; # (⿅; ⿅; ⿅; 鹿; 鹿; ) KANGXI RADICAL DEER +2FC6;2FC6;2FC6;9EA5;9EA5; # (⿆; ⿆; ⿆; 麥; 麥; ) KANGXI RADICAL WHEAT +2FC7;2FC7;2FC7;9EBB;9EBB; # (⿇; ⿇; ⿇; 麻; 麻; ) KANGXI RADICAL HEMP +2FC8;2FC8;2FC8;9EC3;9EC3; # (⿈; ⿈; ⿈; 黃; 黃; ) KANGXI RADICAL YELLOW +2FC9;2FC9;2FC9;9ECD;9ECD; # (⿉; ⿉; ⿉; 黍; 黍; ) KANGXI RADICAL MILLET +2FCA;2FCA;2FCA;9ED1;9ED1; # (⿊; ⿊; ⿊; 黑; 黑; ) KANGXI RADICAL BLACK +2FCB;2FCB;2FCB;9EF9;9EF9; # (⿋; ⿋; ⿋; 黹; 黹; ) KANGXI RADICAL EMBROIDERY +2FCC;2FCC;2FCC;9EFD;9EFD; # (⿌; ⿌; ⿌; 黽; 黽; ) KANGXI RADICAL FROG +2FCD;2FCD;2FCD;9F0E;9F0E; # (⿍; ⿍; ⿍; 鼎; 鼎; ) KANGXI RADICAL TRIPOD +2FCE;2FCE;2FCE;9F13;9F13; # (⿎; ⿎; ⿎; 鼓; 鼓; ) KANGXI RADICAL DRUM +2FCF;2FCF;2FCF;9F20;9F20; # (⿏; ⿏; ⿏; 鼠; 鼠; ) KANGXI RADICAL RAT +2FD0;2FD0;2FD0;9F3B;9F3B; # (⿐; ⿐; ⿐; 鼻; 鼻; ) KANGXI RADICAL NOSE +2FD1;2FD1;2FD1;9F4A;9F4A; # (⿑; ⿑; ⿑; 齊; 齊; ) KANGXI RADICAL EVEN +2FD2;2FD2;2FD2;9F52;9F52; # (⿒; ⿒; ⿒; 齒; 齒; ) KANGXI RADICAL TOOTH +2FD3;2FD3;2FD3;9F8D;9F8D; # (⿓; ⿓; ⿓; 龍; 龍; ) KANGXI RADICAL DRAGON +2FD4;2FD4;2FD4;9F9C;9F9C; # (⿔; ⿔; ⿔; 龜; 龜; ) KANGXI RADICAL TURTLE +2FD5;2FD5;2FD5;9FA0;9FA0; # (⿕; ⿕; ⿕; 龠; 龠; ) KANGXI RADICAL FLUTE +3000;3000;3000;0020;0020; # ( ;  ;  ; ; ; ) IDEOGRAPHIC SPACE +3036;3036;3036;3012;3012; # (〶; 〶; 〶; 〒; 〒; ) CIRCLED POSTAL MARK +3038;3038;3038;5341;5341; # (〸; 〸; 〸; 十; 十; ) HANGZHOU NUMERAL TEN +3039;3039;3039;5344;5344; # (〹; 〹; 〹; 卄; 卄; ) HANGZHOU NUMERAL TWENTY +303A;303A;303A;5345;5345; # (〺; 〺; 〺; 卅; 卅; ) HANGZHOU NUMERAL THIRTY +304C;304C;304B 3099;304C;304B 3099; # (が; が; か◌゙; が; か◌゙; ) HIRAGANA LETTER GA +304E;304E;304D 3099;304E;304D 3099; # (ぎ; ぎ; き◌゙; ぎ; き◌゙; ) HIRAGANA LETTER GI +3050;3050;304F 3099;3050;304F 3099; # (ぐ; ぐ; く◌゙; ぐ; く◌゙; ) HIRAGANA LETTER GU +3052;3052;3051 3099;3052;3051 3099; # (げ; げ; け◌゙; げ; け◌゙; ) HIRAGANA LETTER GE +3054;3054;3053 3099;3054;3053 3099; # (ご; ご; こ◌゙; ご; こ◌゙; ) HIRAGANA LETTER GO +3056;3056;3055 3099;3056;3055 3099; # (ざ; ざ; さ◌゙; ざ; さ◌゙; ) HIRAGANA LETTER ZA +3058;3058;3057 3099;3058;3057 3099; # (じ; じ; し◌゙; じ; し◌゙; ) HIRAGANA LETTER ZI +305A;305A;3059 3099;305A;3059 3099; # (ず; ず; す◌゙; ず; す◌゙; ) HIRAGANA LETTER ZU +305C;305C;305B 3099;305C;305B 3099; # (ぜ; ぜ; せ◌゙; ぜ; せ◌゙; ) HIRAGANA LETTER ZE +305E;305E;305D 3099;305E;305D 3099; # (ぞ; ぞ; そ◌゙; ぞ; そ◌゙; ) HIRAGANA LETTER ZO +3060;3060;305F 3099;3060;305F 3099; # (だ; だ; た◌゙; だ; た◌゙; ) HIRAGANA LETTER DA +3062;3062;3061 3099;3062;3061 3099; # (ぢ; ぢ; ち◌゙; ぢ; ち◌゙; ) HIRAGANA LETTER DI +3065;3065;3064 3099;3065;3064 3099; # (づ; づ; つ◌゙; づ; つ◌゙; ) HIRAGANA LETTER DU +3067;3067;3066 3099;3067;3066 3099; # (で; で; て◌゙; で; て◌゙; ) HIRAGANA LETTER DE +3069;3069;3068 3099;3069;3068 3099; # (ど; ど; と◌゙; ど; と◌゙; ) HIRAGANA LETTER DO +3070;3070;306F 3099;3070;306F 3099; # (ば; ば; は◌゙; ば; は◌゙; ) HIRAGANA LETTER BA +3071;3071;306F 309A;3071;306F 309A; # (ぱ; ぱ; は◌゚; ぱ; は◌゚; ) HIRAGANA LETTER PA +3073;3073;3072 3099;3073;3072 3099; # (び; び; ひ◌゙; び; ひ◌゙; ) HIRAGANA LETTER BI +3074;3074;3072 309A;3074;3072 309A; # (ぴ; ぴ; ひ◌゚; ぴ; ひ◌゚; ) HIRAGANA LETTER PI +3076;3076;3075 3099;3076;3075 3099; # (ぶ; ぶ; ふ◌゙; ぶ; ふ◌゙; ) HIRAGANA LETTER BU +3077;3077;3075 309A;3077;3075 309A; # (ぷ; ぷ; ふ◌゚; ぷ; ふ◌゚; ) HIRAGANA LETTER PU +3079;3079;3078 3099;3079;3078 3099; # (べ; べ; へ◌゙; べ; へ◌゙; ) HIRAGANA LETTER BE +307A;307A;3078 309A;307A;3078 309A; # (ぺ; ぺ; へ◌゚; ぺ; へ◌゚; ) HIRAGANA LETTER PE +307C;307C;307B 3099;307C;307B 3099; # (ぼ; ぼ; ほ◌゙; ぼ; ほ◌゙; ) HIRAGANA LETTER BO +307D;307D;307B 309A;307D;307B 309A; # (ぽ; ぽ; ほ◌゚; ぽ; ほ◌゚; ) HIRAGANA LETTER PO +3094;3094;3046 3099;3094;3046 3099; # (ゔ; ゔ; う◌゙; ゔ; う◌゙; ) HIRAGANA LETTER VU +309B;309B;309B;0020 3099;0020 3099; # (゛; ゛; ゛; ◌゙; ◌゙; ) KATAKANA-HIRAGANA VOICED SOUND MARK +309C;309C;309C;0020 309A;0020 309A; # (゜; ゜; ゜; ◌゚; ◌゚; ) KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309E;309E;309D 3099;309E;309D 3099; # (ゞ; ゞ; ゝ◌゙; ゞ; ゝ◌゙; ) HIRAGANA VOICED ITERATION MARK +309F;309F;309F;3088 308A;3088 308A; # (ゟ; ゟ; ゟ; より; より; ) HIRAGANA DIGRAPH YORI +30AC;30AC;30AB 3099;30AC;30AB 3099; # (ガ; ガ; カ◌゙; ガ; カ◌゙; ) KATAKANA LETTER GA +30AE;30AE;30AD 3099;30AE;30AD 3099; # (ギ; ギ; キ◌゙; ギ; キ◌゙; ) KATAKANA LETTER GI +30B0;30B0;30AF 3099;30B0;30AF 3099; # (グ; グ; ク◌゙; グ; ク◌゙; ) KATAKANA LETTER GU +30B2;30B2;30B1 3099;30B2;30B1 3099; # (ゲ; ゲ; ケ◌゙; ゲ; ケ◌゙; ) KATAKANA LETTER GE +30B4;30B4;30B3 3099;30B4;30B3 3099; # (ゴ; ゴ; コ◌゙; ゴ; コ◌゙; ) KATAKANA LETTER GO +30B6;30B6;30B5 3099;30B6;30B5 3099; # (ザ; ザ; サ◌゙; ザ; サ◌゙; ) KATAKANA LETTER ZA +30B8;30B8;30B7 3099;30B8;30B7 3099; # (ジ; ジ; シ◌゙; ジ; シ◌゙; ) KATAKANA LETTER ZI +30BA;30BA;30B9 3099;30BA;30B9 3099; # (ズ; ズ; ス◌゙; ズ; ス◌゙; ) KATAKANA LETTER ZU +30BC;30BC;30BB 3099;30BC;30BB 3099; # (ゼ; ゼ; セ◌゙; ゼ; セ◌゙; ) KATAKANA LETTER ZE +30BE;30BE;30BD 3099;30BE;30BD 3099; # (ゾ; ゾ; ソ◌゙; ゾ; ソ◌゙; ) KATAKANA LETTER ZO +30C0;30C0;30BF 3099;30C0;30BF 3099; # (ダ; ダ; タ◌゙; ダ; タ◌゙; ) KATAKANA LETTER DA +30C2;30C2;30C1 3099;30C2;30C1 3099; # (ヂ; ヂ; チ◌゙; ヂ; チ◌゙; ) KATAKANA LETTER DI +30C5;30C5;30C4 3099;30C5;30C4 3099; # (ヅ; ヅ; ツ◌゙; ヅ; ツ◌゙; ) KATAKANA LETTER DU +30C7;30C7;30C6 3099;30C7;30C6 3099; # (デ; デ; テ◌゙; デ; テ◌゙; ) KATAKANA LETTER DE +30C9;30C9;30C8 3099;30C9;30C8 3099; # (ド; ド; ト◌゙; ド; ト◌゙; ) KATAKANA LETTER DO +30D0;30D0;30CF 3099;30D0;30CF 3099; # (バ; バ; ハ◌゙; バ; ハ◌゙; ) KATAKANA LETTER BA +30D1;30D1;30CF 309A;30D1;30CF 309A; # (パ; パ; ハ◌゚; パ; ハ◌゚; ) KATAKANA LETTER PA +30D3;30D3;30D2 3099;30D3;30D2 3099; # (ビ; ビ; ヒ◌゙; ビ; ヒ◌゙; ) KATAKANA LETTER BI +30D4;30D4;30D2 309A;30D4;30D2 309A; # (ピ; ピ; ヒ◌゚; ピ; ヒ◌゚; ) KATAKANA LETTER PI +30D6;30D6;30D5 3099;30D6;30D5 3099; # (ブ; ブ; フ◌゙; ブ; フ◌゙; ) KATAKANA LETTER BU +30D7;30D7;30D5 309A;30D7;30D5 309A; # (プ; プ; フ◌゚; プ; フ◌゚; ) KATAKANA LETTER PU +30D9;30D9;30D8 3099;30D9;30D8 3099; # (ベ; ベ; ヘ◌゙; ベ; ヘ◌゙; ) KATAKANA LETTER BE +30DA;30DA;30D8 309A;30DA;30D8 309A; # (ペ; ペ; ヘ◌゚; ペ; ヘ◌゚; ) KATAKANA LETTER PE +30DC;30DC;30DB 3099;30DC;30DB 3099; # (ボ; ボ; ホ◌゙; ボ; ホ◌゙; ) KATAKANA LETTER BO +30DD;30DD;30DB 309A;30DD;30DB 309A; # (ポ; ポ; ホ◌゚; ポ; ホ◌゚; ) KATAKANA LETTER PO +30F4;30F4;30A6 3099;30F4;30A6 3099; # (ヴ; ヴ; ウ◌゙; ヴ; ウ◌゙; ) KATAKANA LETTER VU +30F7;30F7;30EF 3099;30F7;30EF 3099; # (ヷ; ヷ; ワ◌゙; ヷ; ワ◌゙; ) KATAKANA LETTER VA +30F8;30F8;30F0 3099;30F8;30F0 3099; # (ヸ; ヸ; ヰ◌゙; ヸ; ヰ◌゙; ) KATAKANA LETTER VI +30F9;30F9;30F1 3099;30F9;30F1 3099; # (ヹ; ヹ; ヱ◌゙; ヹ; ヱ◌゙; ) KATAKANA LETTER VE +30FA;30FA;30F2 3099;30FA;30F2 3099; # (ヺ; ヺ; ヲ◌゙; ヺ; ヲ◌゙; ) KATAKANA LETTER VO +30FE;30FE;30FD 3099;30FE;30FD 3099; # (ヾ; ヾ; ヽ◌゙; ヾ; ヽ◌゙; ) KATAKANA VOICED ITERATION MARK +30FF;30FF;30FF;30B3 30C8;30B3 30C8; # (ヿ; ヿ; ヿ; コト; コト; ) KATAKANA DIGRAPH KOTO +3131;3131;3131;1100;1100; # (ㄱ; ㄱ; ㄱ; ᄀ; ᄀ; ) HANGUL LETTER KIYEOK +3132;3132;3132;1101;1101; # (ㄲ; ㄲ; ㄲ; ᄁ; ᄁ; ) HANGUL LETTER SSANGKIYEOK +3133;3133;3133;11AA;11AA; # (ㄳ; ㄳ; ㄳ; ᆪ; ᆪ; ) HANGUL LETTER KIYEOK-SIOS +3134;3134;3134;1102;1102; # (ㄴ; ㄴ; ㄴ; ᄂ; ᄂ; ) HANGUL LETTER NIEUN +3135;3135;3135;11AC;11AC; # (ㄵ; ㄵ; ㄵ; ᆬ; ᆬ; ) HANGUL LETTER NIEUN-CIEUC +3136;3136;3136;11AD;11AD; # (ㄶ; ㄶ; ㄶ; ᆭ; ᆭ; ) HANGUL LETTER NIEUN-HIEUH +3137;3137;3137;1103;1103; # (ㄷ; ㄷ; ㄷ; ᄃ; ᄃ; ) HANGUL LETTER TIKEUT +3138;3138;3138;1104;1104; # (ㄸ; ㄸ; ㄸ; ᄄ; ᄄ; ) HANGUL LETTER SSANGTIKEUT +3139;3139;3139;1105;1105; # (ㄹ; ㄹ; ㄹ; ᄅ; ᄅ; ) HANGUL LETTER RIEUL +313A;313A;313A;11B0;11B0; # (ㄺ; ㄺ; ㄺ; ᆰ; ᆰ; ) HANGUL LETTER RIEUL-KIYEOK +313B;313B;313B;11B1;11B1; # (ㄻ; ㄻ; ㄻ; ᆱ; ᆱ; ) HANGUL LETTER RIEUL-MIEUM +313C;313C;313C;11B2;11B2; # (ㄼ; ㄼ; ㄼ; ᆲ; ᆲ; ) HANGUL LETTER RIEUL-PIEUP +313D;313D;313D;11B3;11B3; # (ㄽ; ㄽ; ㄽ; ᆳ; ᆳ; ) HANGUL LETTER RIEUL-SIOS +313E;313E;313E;11B4;11B4; # (ㄾ; ㄾ; ㄾ; ᆴ; ᆴ; ) HANGUL LETTER RIEUL-THIEUTH +313F;313F;313F;11B5;11B5; # (ㄿ; ㄿ; ㄿ; ᆵ; ᆵ; ) HANGUL LETTER RIEUL-PHIEUPH +3140;3140;3140;111A;111A; # (ㅀ; ㅀ; ㅀ; ᄚ; ᄚ; ) HANGUL LETTER RIEUL-HIEUH +3141;3141;3141;1106;1106; # (ㅁ; ㅁ; ㅁ; ᄆ; ᄆ; ) HANGUL LETTER MIEUM +3142;3142;3142;1107;1107; # (ㅂ; ㅂ; ㅂ; ᄇ; ᄇ; ) HANGUL LETTER PIEUP +3143;3143;3143;1108;1108; # (ㅃ; ㅃ; ㅃ; ᄈ; ᄈ; ) HANGUL LETTER SSANGPIEUP +3144;3144;3144;1121;1121; # (ㅄ; ㅄ; ㅄ; ᄡ; ᄡ; ) HANGUL LETTER PIEUP-SIOS +3145;3145;3145;1109;1109; # (ㅅ; ㅅ; ㅅ; ᄉ; ᄉ; ) HANGUL LETTER SIOS +3146;3146;3146;110A;110A; # (ㅆ; ㅆ; ㅆ; ᄊ; ᄊ; ) HANGUL LETTER SSANGSIOS +3147;3147;3147;110B;110B; # (ㅇ; ㅇ; ㅇ; ᄋ; ᄋ; ) HANGUL LETTER IEUNG +3148;3148;3148;110C;110C; # (ㅈ; ㅈ; ㅈ; ᄌ; ᄌ; ) HANGUL LETTER CIEUC +3149;3149;3149;110D;110D; # (ㅉ; ㅉ; ㅉ; ᄍ; ᄍ; ) HANGUL LETTER SSANGCIEUC +314A;314A;314A;110E;110E; # (ㅊ; ㅊ; ㅊ; ᄎ; ᄎ; ) HANGUL LETTER CHIEUCH +314B;314B;314B;110F;110F; # (ㅋ; ㅋ; ㅋ; ᄏ; ᄏ; ) HANGUL LETTER KHIEUKH +314C;314C;314C;1110;1110; # (ㅌ; ㅌ; ㅌ; ᄐ; ᄐ; ) HANGUL LETTER THIEUTH +314D;314D;314D;1111;1111; # (ㅍ; ㅍ; ㅍ; ᄑ; ᄑ; ) HANGUL LETTER PHIEUPH +314E;314E;314E;1112;1112; # (ㅎ; ㅎ; ㅎ; ᄒ; ᄒ; ) HANGUL LETTER HIEUH +314F;314F;314F;1161;1161; # (ㅏ; ㅏ; ㅏ; ᅡ; ᅡ; ) HANGUL LETTER A +3150;3150;3150;1162;1162; # (ㅐ; ㅐ; ㅐ; ᅢ; ᅢ; ) HANGUL LETTER AE +3151;3151;3151;1163;1163; # (ㅑ; ㅑ; ㅑ; ᅣ; ᅣ; ) HANGUL LETTER YA +3152;3152;3152;1164;1164; # (ㅒ; ㅒ; ㅒ; ᅤ; ᅤ; ) HANGUL LETTER YAE +3153;3153;3153;1165;1165; # (ㅓ; ㅓ; ㅓ; ᅥ; ᅥ; ) HANGUL LETTER EO +3154;3154;3154;1166;1166; # (ㅔ; ㅔ; ㅔ; ᅦ; ᅦ; ) HANGUL LETTER E +3155;3155;3155;1167;1167; # (ㅕ; ㅕ; ㅕ; ᅧ; ᅧ; ) HANGUL LETTER YEO +3156;3156;3156;1168;1168; # (ㅖ; ㅖ; ㅖ; ᅨ; ᅨ; ) HANGUL LETTER YE +3157;3157;3157;1169;1169; # (ㅗ; ㅗ; ㅗ; ᅩ; ᅩ; ) HANGUL LETTER O +3158;3158;3158;116A;116A; # (ㅘ; ㅘ; ㅘ; ᅪ; ᅪ; ) HANGUL LETTER WA +3159;3159;3159;116B;116B; # (ㅙ; ㅙ; ㅙ; ᅫ; ᅫ; ) HANGUL LETTER WAE +315A;315A;315A;116C;116C; # (ㅚ; ㅚ; ㅚ; ᅬ; ᅬ; ) HANGUL LETTER OE +315B;315B;315B;116D;116D; # (ㅛ; ㅛ; ㅛ; ᅭ; ᅭ; ) HANGUL LETTER YO +315C;315C;315C;116E;116E; # (ㅜ; ㅜ; ㅜ; ᅮ; ᅮ; ) HANGUL LETTER U +315D;315D;315D;116F;116F; # (ㅝ; ㅝ; ㅝ; ᅯ; ᅯ; ) HANGUL LETTER WEO +315E;315E;315E;1170;1170; # (ㅞ; ㅞ; ㅞ; ᅰ; ᅰ; ) HANGUL LETTER WE +315F;315F;315F;1171;1171; # (ㅟ; ㅟ; ㅟ; ᅱ; ᅱ; ) HANGUL LETTER WI +3160;3160;3160;1172;1172; # (ㅠ; ㅠ; ㅠ; ᅲ; ᅲ; ) HANGUL LETTER YU +3161;3161;3161;1173;1173; # (ㅡ; ㅡ; ㅡ; ᅳ; ᅳ; ) HANGUL LETTER EU +3162;3162;3162;1174;1174; # (ㅢ; ㅢ; ㅢ; ᅴ; ᅴ; ) HANGUL LETTER YI +3163;3163;3163;1175;1175; # (ㅣ; ㅣ; ㅣ; ᅵ; ᅵ; ) HANGUL LETTER I +3164;3164;3164;1160;1160; # (ㅤ; ㅤ; ㅤ; ᅠ; ᅠ; ) HANGUL FILLER +3165;3165;3165;1114;1114; # (ㅥ; ㅥ; ㅥ; ᄔ; ᄔ; ) HANGUL LETTER SSANGNIEUN +3166;3166;3166;1115;1115; # (ㅦ; ㅦ; ㅦ; ᄕ; ᄕ; ) HANGUL LETTER NIEUN-TIKEUT +3167;3167;3167;11C7;11C7; # (ㅧ; ㅧ; ㅧ; ᇇ; ᇇ; ) HANGUL LETTER NIEUN-SIOS +3168;3168;3168;11C8;11C8; # (ㅨ; ㅨ; ㅨ; ᇈ; ᇈ; ) HANGUL LETTER NIEUN-PANSIOS +3169;3169;3169;11CC;11CC; # (ㅩ; ㅩ; ㅩ; ᇌ; ᇌ; ) HANGUL LETTER RIEUL-KIYEOK-SIOS +316A;316A;316A;11CE;11CE; # (ㅪ; ㅪ; ㅪ; ᇎ; ᇎ; ) HANGUL LETTER RIEUL-TIKEUT +316B;316B;316B;11D3;11D3; # (ㅫ; ㅫ; ㅫ; ᇓ; ᇓ; ) HANGUL LETTER RIEUL-PIEUP-SIOS +316C;316C;316C;11D7;11D7; # (ㅬ; ㅬ; ㅬ; ᇗ; ᇗ; ) HANGUL LETTER RIEUL-PANSIOS +316D;316D;316D;11D9;11D9; # (ㅭ; ㅭ; ㅭ; ᇙ; ᇙ; ) HANGUL LETTER RIEUL-YEORINHIEUH +316E;316E;316E;111C;111C; # (ㅮ; ㅮ; ㅮ; ᄜ; ᄜ; ) HANGUL LETTER MIEUM-PIEUP +316F;316F;316F;11DD;11DD; # (ㅯ; ㅯ; ㅯ; ᇝ; ᇝ; ) HANGUL LETTER MIEUM-SIOS +3170;3170;3170;11DF;11DF; # (ㅰ; ㅰ; ㅰ; ᇟ; ᇟ; ) HANGUL LETTER MIEUM-PANSIOS +3171;3171;3171;111D;111D; # (ㅱ; ㅱ; ㅱ; ᄝ; ᄝ; ) HANGUL LETTER KAPYEOUNMIEUM +3172;3172;3172;111E;111E; # (ㅲ; ㅲ; ㅲ; ᄞ; ᄞ; ) HANGUL LETTER PIEUP-KIYEOK +3173;3173;3173;1120;1120; # (ㅳ; ㅳ; ㅳ; ᄠ; ᄠ; ) HANGUL LETTER PIEUP-TIKEUT +3174;3174;3174;1122;1122; # (ㅴ; ㅴ; ㅴ; ᄢ; ᄢ; ) HANGUL LETTER PIEUP-SIOS-KIYEOK +3175;3175;3175;1123;1123; # (ㅵ; ㅵ; ㅵ; ᄣ; ᄣ; ) HANGUL LETTER PIEUP-SIOS-TIKEUT +3176;3176;3176;1127;1127; # (ㅶ; ㅶ; ㅶ; ᄧ; ᄧ; ) HANGUL LETTER PIEUP-CIEUC +3177;3177;3177;1129;1129; # (ㅷ; ㅷ; ㅷ; ᄩ; ᄩ; ) HANGUL LETTER PIEUP-THIEUTH +3178;3178;3178;112B;112B; # (ㅸ; ㅸ; ㅸ; ᄫ; ᄫ; ) HANGUL LETTER KAPYEOUNPIEUP +3179;3179;3179;112C;112C; # (ㅹ; ㅹ; ㅹ; ᄬ; ᄬ; ) HANGUL LETTER KAPYEOUNSSANGPIEUP +317A;317A;317A;112D;112D; # (ㅺ; ㅺ; ㅺ; ᄭ; ᄭ; ) HANGUL LETTER SIOS-KIYEOK +317B;317B;317B;112E;112E; # (ㅻ; ㅻ; ㅻ; ᄮ; ᄮ; ) HANGUL LETTER SIOS-NIEUN +317C;317C;317C;112F;112F; # (ㅼ; ㅼ; ㅼ; ᄯ; ᄯ; ) HANGUL LETTER SIOS-TIKEUT +317D;317D;317D;1132;1132; # (ㅽ; ㅽ; ㅽ; ᄲ; ᄲ; ) HANGUL LETTER SIOS-PIEUP +317E;317E;317E;1136;1136; # (ㅾ; ㅾ; ㅾ; ᄶ; ᄶ; ) HANGUL LETTER SIOS-CIEUC +317F;317F;317F;1140;1140; # (ㅿ; ㅿ; ㅿ; ᅀ; ᅀ; ) HANGUL LETTER PANSIOS +3180;3180;3180;1147;1147; # (ㆀ; ㆀ; ㆀ; ᅇ; ᅇ; ) HANGUL LETTER SSANGIEUNG +3181;3181;3181;114C;114C; # (ㆁ; ㆁ; ㆁ; ᅌ; ᅌ; ) HANGUL LETTER YESIEUNG +3182;3182;3182;11F1;11F1; # (ㆂ; ㆂ; ㆂ; ᇱ; ᇱ; ) HANGUL LETTER YESIEUNG-SIOS +3183;3183;3183;11F2;11F2; # (ㆃ; ㆃ; ㆃ; ᇲ; ᇲ; ) HANGUL LETTER YESIEUNG-PANSIOS +3184;3184;3184;1157;1157; # (ㆄ; ㆄ; ㆄ; ᅗ; ᅗ; ) HANGUL LETTER KAPYEOUNPHIEUPH +3185;3185;3185;1158;1158; # (ㆅ; ㆅ; ㆅ; ᅘ; ᅘ; ) HANGUL LETTER SSANGHIEUH +3186;3186;3186;1159;1159; # (ㆆ; ㆆ; ㆆ; ᅙ; ᅙ; ) HANGUL LETTER YEORINHIEUH +3187;3187;3187;1184;1184; # (ㆇ; ㆇ; ㆇ; ᆄ; ᆄ; ) HANGUL LETTER YO-YA +3188;3188;3188;1185;1185; # (ㆈ; ㆈ; ㆈ; ᆅ; ᆅ; ) HANGUL LETTER YO-YAE +3189;3189;3189;1188;1188; # (ㆉ; ㆉ; ㆉ; ᆈ; ᆈ; ) HANGUL LETTER YO-I +318A;318A;318A;1191;1191; # (ㆊ; ㆊ; ㆊ; ᆑ; ᆑ; ) HANGUL LETTER YU-YEO +318B;318B;318B;1192;1192; # (ㆋ; ㆋ; ㆋ; ᆒ; ᆒ; ) HANGUL LETTER YU-YE +318C;318C;318C;1194;1194; # (ㆌ; ㆌ; ㆌ; ᆔ; ᆔ; ) HANGUL LETTER YU-I +318D;318D;318D;119E;119E; # (ㆍ; ㆍ; ㆍ; ᆞ; ᆞ; ) HANGUL LETTER ARAEA +318E;318E;318E;11A1;11A1; # (ㆎ; ㆎ; ㆎ; ᆡ; ᆡ; ) HANGUL LETTER ARAEAE +3192;3192;3192;4E00;4E00; # (㆒; ㆒; ㆒; 一; 一; ) IDEOGRAPHIC ANNOTATION ONE MARK +3193;3193;3193;4E8C;4E8C; # (㆓; ㆓; ㆓; 二; 二; ) IDEOGRAPHIC ANNOTATION TWO MARK +3194;3194;3194;4E09;4E09; # (㆔; ㆔; ㆔; 三; 三; ) IDEOGRAPHIC ANNOTATION THREE MARK +3195;3195;3195;56DB;56DB; # (㆕; ㆕; ㆕; 四; 四; ) IDEOGRAPHIC ANNOTATION FOUR MARK +3196;3196;3196;4E0A;4E0A; # (㆖; ㆖; ㆖; 上; 上; ) IDEOGRAPHIC ANNOTATION TOP MARK +3197;3197;3197;4E2D;4E2D; # (㆗; ㆗; ㆗; 中; 中; ) IDEOGRAPHIC ANNOTATION MIDDLE MARK +3198;3198;3198;4E0B;4E0B; # (㆘; ㆘; ㆘; 下; 下; ) IDEOGRAPHIC ANNOTATION BOTTOM MARK +3199;3199;3199;7532;7532; # (㆙; ㆙; ㆙; 甲; 甲; ) IDEOGRAPHIC ANNOTATION FIRST MARK +319A;319A;319A;4E59;4E59; # (㆚; ㆚; ㆚; 乙; 乙; ) IDEOGRAPHIC ANNOTATION SECOND MARK +319B;319B;319B;4E19;4E19; # (㆛; ㆛; ㆛; 丙; 丙; ) IDEOGRAPHIC ANNOTATION THIRD MARK +319C;319C;319C;4E01;4E01; # (㆜; ㆜; ㆜; 丁; 丁; ) IDEOGRAPHIC ANNOTATION FOURTH MARK +319D;319D;319D;5929;5929; # (㆝; ㆝; ㆝; 天; 天; ) IDEOGRAPHIC ANNOTATION HEAVEN MARK +319E;319E;319E;5730;5730; # (㆞; ㆞; ㆞; 地; 地; ) IDEOGRAPHIC ANNOTATION EARTH MARK +319F;319F;319F;4EBA;4EBA; # (㆟; ㆟; ㆟; 人; 人; ) IDEOGRAPHIC ANNOTATION MAN MARK +3200;3200;3200;0028 1100 0029;0028 1100 0029; # (㈀; ㈀; ㈀; (ᄀ); (ᄀ); ) PARENTHESIZED HANGUL KIYEOK +3201;3201;3201;0028 1102 0029;0028 1102 0029; # (㈁; ㈁; ㈁; (ᄂ); (ᄂ); ) PARENTHESIZED HANGUL NIEUN +3202;3202;3202;0028 1103 0029;0028 1103 0029; # (㈂; ㈂; ㈂; (ᄃ); (ᄃ); ) PARENTHESIZED HANGUL TIKEUT +3203;3203;3203;0028 1105 0029;0028 1105 0029; # (㈃; ㈃; ㈃; (ᄅ); (ᄅ); ) PARENTHESIZED HANGUL RIEUL +3204;3204;3204;0028 1106 0029;0028 1106 0029; # (㈄; ㈄; ㈄; (ᄆ); (ᄆ); ) PARENTHESIZED HANGUL MIEUM +3205;3205;3205;0028 1107 0029;0028 1107 0029; # (㈅; ㈅; ㈅; (ᄇ); (ᄇ); ) PARENTHESIZED HANGUL PIEUP +3206;3206;3206;0028 1109 0029;0028 1109 0029; # (㈆; ㈆; ㈆; (ᄉ); (ᄉ); ) PARENTHESIZED HANGUL SIOS +3207;3207;3207;0028 110B 0029;0028 110B 0029; # (㈇; ㈇; ㈇; (ᄋ); (ᄋ); ) PARENTHESIZED HANGUL IEUNG +3208;3208;3208;0028 110C 0029;0028 110C 0029; # (㈈; ㈈; ㈈; (ᄌ); (ᄌ); ) PARENTHESIZED HANGUL CIEUC +3209;3209;3209;0028 110E 0029;0028 110E 0029; # (㈉; ㈉; ㈉; (ᄎ); (ᄎ); ) PARENTHESIZED HANGUL CHIEUCH +320A;320A;320A;0028 110F 0029;0028 110F 0029; # (㈊; ㈊; ㈊; (ᄏ); (ᄏ); ) PARENTHESIZED HANGUL KHIEUKH +320B;320B;320B;0028 1110 0029;0028 1110 0029; # (㈋; ㈋; ㈋; (ᄐ); (ᄐ); ) PARENTHESIZED HANGUL THIEUTH +320C;320C;320C;0028 1111 0029;0028 1111 0029; # (㈌; ㈌; ㈌; (ᄑ); (ᄑ); ) PARENTHESIZED HANGUL PHIEUPH +320D;320D;320D;0028 1112 0029;0028 1112 0029; # (㈍; ㈍; ㈍; (ᄒ); (ᄒ); ) PARENTHESIZED HANGUL HIEUH +320E;320E;320E;0028 AC00 0029;0028 1100 1161 0029; # (㈎; ㈎; ㈎; (가); (가); ) PARENTHESIZED HANGUL KIYEOK A +320F;320F;320F;0028 B098 0029;0028 1102 1161 0029; # (㈏; ㈏; ㈏; (나); (나); ) PARENTHESIZED HANGUL NIEUN A +3210;3210;3210;0028 B2E4 0029;0028 1103 1161 0029; # (㈐; ㈐; ㈐; (다); (다); ) PARENTHESIZED HANGUL TIKEUT A +3211;3211;3211;0028 B77C 0029;0028 1105 1161 0029; # (㈑; ㈑; ㈑; (라); (라); ) PARENTHESIZED HANGUL RIEUL A +3212;3212;3212;0028 B9C8 0029;0028 1106 1161 0029; # (㈒; ㈒; ㈒; (마); (마); ) PARENTHESIZED HANGUL MIEUM A +3213;3213;3213;0028 BC14 0029;0028 1107 1161 0029; # (㈓; ㈓; ㈓; (바); (바); ) PARENTHESIZED HANGUL PIEUP A +3214;3214;3214;0028 C0AC 0029;0028 1109 1161 0029; # (㈔; ㈔; ㈔; (사); (사); ) PARENTHESIZED HANGUL SIOS A +3215;3215;3215;0028 C544 0029;0028 110B 1161 0029; # (㈕; ㈕; ㈕; (아); (아); ) PARENTHESIZED HANGUL IEUNG A +3216;3216;3216;0028 C790 0029;0028 110C 1161 0029; # (㈖; ㈖; ㈖; (자); (자); ) PARENTHESIZED HANGUL CIEUC A +3217;3217;3217;0028 CC28 0029;0028 110E 1161 0029; # (㈗; ㈗; ㈗; (차); (차); ) PARENTHESIZED HANGUL CHIEUCH A +3218;3218;3218;0028 CE74 0029;0028 110F 1161 0029; # (㈘; ㈘; ㈘; (카); (카); ) PARENTHESIZED HANGUL KHIEUKH A +3219;3219;3219;0028 D0C0 0029;0028 1110 1161 0029; # (㈙; ㈙; ㈙; (타); (타); ) PARENTHESIZED HANGUL THIEUTH A +321A;321A;321A;0028 D30C 0029;0028 1111 1161 0029; # (㈚; ㈚; ㈚; (파); (파); ) PARENTHESIZED HANGUL PHIEUPH A +321B;321B;321B;0028 D558 0029;0028 1112 1161 0029; # (㈛; ㈛; ㈛; (하); (하); ) PARENTHESIZED HANGUL HIEUH A +321C;321C;321C;0028 C8FC 0029;0028 110C 116E 0029; # (㈜; ㈜; ㈜; (주); (주); ) PARENTHESIZED HANGUL CIEUC U +3220;3220;3220;0028 4E00 0029;0028 4E00 0029; # (㈠; ㈠; ㈠; (一); (一); ) PARENTHESIZED IDEOGRAPH ONE +3221;3221;3221;0028 4E8C 0029;0028 4E8C 0029; # (㈡; ㈡; ㈡; (二); (二); ) PARENTHESIZED IDEOGRAPH TWO +3222;3222;3222;0028 4E09 0029;0028 4E09 0029; # (㈢; ㈢; ㈢; (三); (三); ) PARENTHESIZED IDEOGRAPH THREE +3223;3223;3223;0028 56DB 0029;0028 56DB 0029; # (㈣; ㈣; ㈣; (四); (四); ) PARENTHESIZED IDEOGRAPH FOUR +3224;3224;3224;0028 4E94 0029;0028 4E94 0029; # (㈤; ㈤; ㈤; (五); (五); ) PARENTHESIZED IDEOGRAPH FIVE +3225;3225;3225;0028 516D 0029;0028 516D 0029; # (㈥; ㈥; ㈥; (六); (六); ) PARENTHESIZED IDEOGRAPH SIX +3226;3226;3226;0028 4E03 0029;0028 4E03 0029; # (㈦; ㈦; ㈦; (七); (七); ) PARENTHESIZED IDEOGRAPH SEVEN +3227;3227;3227;0028 516B 0029;0028 516B 0029; # (㈧; ㈧; ㈧; (八); (八); ) PARENTHESIZED IDEOGRAPH EIGHT +3228;3228;3228;0028 4E5D 0029;0028 4E5D 0029; # (㈨; ㈨; ㈨; (九); (九); ) PARENTHESIZED IDEOGRAPH NINE +3229;3229;3229;0028 5341 0029;0028 5341 0029; # (㈩; ㈩; ㈩; (十); (十); ) PARENTHESIZED IDEOGRAPH TEN +322A;322A;322A;0028 6708 0029;0028 6708 0029; # (㈪; ㈪; ㈪; (月); (月); ) PARENTHESIZED IDEOGRAPH MOON +322B;322B;322B;0028 706B 0029;0028 706B 0029; # (㈫; ㈫; ㈫; (火); (火); ) PARENTHESIZED IDEOGRAPH FIRE +322C;322C;322C;0028 6C34 0029;0028 6C34 0029; # (㈬; ㈬; ㈬; (水); (水); ) PARENTHESIZED IDEOGRAPH WATER +322D;322D;322D;0028 6728 0029;0028 6728 0029; # (㈭; ㈭; ㈭; (木); (木); ) PARENTHESIZED IDEOGRAPH WOOD +322E;322E;322E;0028 91D1 0029;0028 91D1 0029; # (㈮; ㈮; ㈮; (金); (金); ) PARENTHESIZED IDEOGRAPH METAL +322F;322F;322F;0028 571F 0029;0028 571F 0029; # (㈯; ㈯; ㈯; (土); (土); ) PARENTHESIZED IDEOGRAPH EARTH +3230;3230;3230;0028 65E5 0029;0028 65E5 0029; # (㈰; ㈰; ㈰; (日); (日); ) PARENTHESIZED IDEOGRAPH SUN +3231;3231;3231;0028 682A 0029;0028 682A 0029; # (㈱; ㈱; ㈱; (株); (株); ) PARENTHESIZED IDEOGRAPH STOCK +3232;3232;3232;0028 6709 0029;0028 6709 0029; # (㈲; ㈲; ㈲; (有); (有); ) PARENTHESIZED IDEOGRAPH HAVE +3233;3233;3233;0028 793E 0029;0028 793E 0029; # (㈳; ㈳; ㈳; (社); (社); ) PARENTHESIZED IDEOGRAPH SOCIETY +3234;3234;3234;0028 540D 0029;0028 540D 0029; # (㈴; ㈴; ㈴; (名); (名); ) PARENTHESIZED IDEOGRAPH NAME +3235;3235;3235;0028 7279 0029;0028 7279 0029; # (㈵; ㈵; ㈵; (特); (特); ) PARENTHESIZED IDEOGRAPH SPECIAL +3236;3236;3236;0028 8CA1 0029;0028 8CA1 0029; # (㈶; ㈶; ㈶; (財); (財); ) PARENTHESIZED IDEOGRAPH FINANCIAL +3237;3237;3237;0028 795D 0029;0028 795D 0029; # (㈷; ㈷; ㈷; (祝); (祝); ) PARENTHESIZED IDEOGRAPH CONGRATULATION +3238;3238;3238;0028 52B4 0029;0028 52B4 0029; # (㈸; ㈸; ㈸; (労); (労); ) PARENTHESIZED IDEOGRAPH LABOR +3239;3239;3239;0028 4EE3 0029;0028 4EE3 0029; # (㈹; ㈹; ㈹; (代); (代); ) PARENTHESIZED IDEOGRAPH REPRESENT +323A;323A;323A;0028 547C 0029;0028 547C 0029; # (㈺; ㈺; ㈺; (呼); (呼); ) PARENTHESIZED IDEOGRAPH CALL +323B;323B;323B;0028 5B66 0029;0028 5B66 0029; # (㈻; ㈻; ㈻; (学); (学); ) PARENTHESIZED IDEOGRAPH STUDY +323C;323C;323C;0028 76E3 0029;0028 76E3 0029; # (㈼; ㈼; ㈼; (監); (監); ) PARENTHESIZED IDEOGRAPH SUPERVISE +323D;323D;323D;0028 4F01 0029;0028 4F01 0029; # (㈽; ㈽; ㈽; (企); (企); ) PARENTHESIZED IDEOGRAPH ENTERPRISE +323E;323E;323E;0028 8CC7 0029;0028 8CC7 0029; # (㈾; ㈾; ㈾; (資); (資); ) PARENTHESIZED IDEOGRAPH RESOURCE +323F;323F;323F;0028 5354 0029;0028 5354 0029; # (㈿; ㈿; ㈿; (協); (協); ) PARENTHESIZED IDEOGRAPH ALLIANCE +3240;3240;3240;0028 796D 0029;0028 796D 0029; # (㉀; ㉀; ㉀; (祭); (祭); ) PARENTHESIZED IDEOGRAPH FESTIVAL +3241;3241;3241;0028 4F11 0029;0028 4F11 0029; # (㉁; ㉁; ㉁; (休); (休); ) PARENTHESIZED IDEOGRAPH REST +3242;3242;3242;0028 81EA 0029;0028 81EA 0029; # (㉂; ㉂; ㉂; (自); (自); ) PARENTHESIZED IDEOGRAPH SELF +3243;3243;3243;0028 81F3 0029;0028 81F3 0029; # (㉃; ㉃; ㉃; (至); (至); ) PARENTHESIZED IDEOGRAPH REACH +3251;3251;3251;0032 0031;0032 0031; # (㉑; ㉑; ㉑; 21; 21; ) CIRCLED NUMBER TWENTY ONE +3252;3252;3252;0032 0032;0032 0032; # (㉒; ㉒; ㉒; 22; 22; ) CIRCLED NUMBER TWENTY TWO +3253;3253;3253;0032 0033;0032 0033; # (㉓; ㉓; ㉓; 23; 23; ) CIRCLED NUMBER TWENTY THREE +3254;3254;3254;0032 0034;0032 0034; # (㉔; ㉔; ㉔; 24; 24; ) CIRCLED NUMBER TWENTY FOUR +3255;3255;3255;0032 0035;0032 0035; # (㉕; ㉕; ㉕; 25; 25; ) CIRCLED NUMBER TWENTY FIVE +3256;3256;3256;0032 0036;0032 0036; # (㉖; ㉖; ㉖; 26; 26; ) CIRCLED NUMBER TWENTY SIX +3257;3257;3257;0032 0037;0032 0037; # (㉗; ㉗; ㉗; 27; 27; ) CIRCLED NUMBER TWENTY SEVEN +3258;3258;3258;0032 0038;0032 0038; # (㉘; ㉘; ㉘; 28; 28; ) CIRCLED NUMBER TWENTY EIGHT +3259;3259;3259;0032 0039;0032 0039; # (㉙; ㉙; ㉙; 29; 29; ) CIRCLED NUMBER TWENTY NINE +325A;325A;325A;0033 0030;0033 0030; # (㉚; ㉚; ㉚; 30; 30; ) CIRCLED NUMBER THIRTY +325B;325B;325B;0033 0031;0033 0031; # (㉛; ㉛; ㉛; 31; 31; ) CIRCLED NUMBER THIRTY ONE +325C;325C;325C;0033 0032;0033 0032; # (㉜; ㉜; ㉜; 32; 32; ) CIRCLED NUMBER THIRTY TWO +325D;325D;325D;0033 0033;0033 0033; # (㉝; ㉝; ㉝; 33; 33; ) CIRCLED NUMBER THIRTY THREE +325E;325E;325E;0033 0034;0033 0034; # (㉞; ㉞; ㉞; 34; 34; ) CIRCLED NUMBER THIRTY FOUR +325F;325F;325F;0033 0035;0033 0035; # (㉟; ㉟; ㉟; 35; 35; ) CIRCLED NUMBER THIRTY FIVE +3260;3260;3260;1100;1100; # (㉠; ㉠; ㉠; ᄀ; ᄀ; ) CIRCLED HANGUL KIYEOK +3261;3261;3261;1102;1102; # (㉡; ㉡; ㉡; ᄂ; ᄂ; ) CIRCLED HANGUL NIEUN +3262;3262;3262;1103;1103; # (㉢; ㉢; ㉢; ᄃ; ᄃ; ) CIRCLED HANGUL TIKEUT +3263;3263;3263;1105;1105; # (㉣; ㉣; ㉣; ᄅ; ᄅ; ) CIRCLED HANGUL RIEUL +3264;3264;3264;1106;1106; # (㉤; ㉤; ㉤; ᄆ; ᄆ; ) CIRCLED HANGUL MIEUM +3265;3265;3265;1107;1107; # (㉥; ㉥; ㉥; ᄇ; ᄇ; ) CIRCLED HANGUL PIEUP +3266;3266;3266;1109;1109; # (㉦; ㉦; ㉦; ᄉ; ᄉ; ) CIRCLED HANGUL SIOS +3267;3267;3267;110B;110B; # (㉧; ㉧; ㉧; ᄋ; ᄋ; ) CIRCLED HANGUL IEUNG +3268;3268;3268;110C;110C; # (㉨; ㉨; ㉨; ᄌ; ᄌ; ) CIRCLED HANGUL CIEUC +3269;3269;3269;110E;110E; # (㉩; ㉩; ㉩; ᄎ; ᄎ; ) CIRCLED HANGUL CHIEUCH +326A;326A;326A;110F;110F; # (㉪; ㉪; ㉪; ᄏ; ᄏ; ) CIRCLED HANGUL KHIEUKH +326B;326B;326B;1110;1110; # (㉫; ㉫; ㉫; ᄐ; ᄐ; ) CIRCLED HANGUL THIEUTH +326C;326C;326C;1111;1111; # (㉬; ㉬; ㉬; ᄑ; ᄑ; ) CIRCLED HANGUL PHIEUPH +326D;326D;326D;1112;1112; # (㉭; ㉭; ㉭; ᄒ; ᄒ; ) CIRCLED HANGUL HIEUH +326E;326E;326E;AC00;1100 1161; # (㉮; ㉮; ㉮; 가; 가; ) CIRCLED HANGUL KIYEOK A +326F;326F;326F;B098;1102 1161; # (㉯; ㉯; ㉯; 나; 나; ) CIRCLED HANGUL NIEUN A +3270;3270;3270;B2E4;1103 1161; # (㉰; ㉰; ㉰; 다; 다; ) CIRCLED HANGUL TIKEUT A +3271;3271;3271;B77C;1105 1161; # (㉱; ㉱; ㉱; 라; 라; ) CIRCLED HANGUL RIEUL A +3272;3272;3272;B9C8;1106 1161; # (㉲; ㉲; ㉲; 마; 마; ) CIRCLED HANGUL MIEUM A +3273;3273;3273;BC14;1107 1161; # (㉳; ㉳; ㉳; 바; 바; ) CIRCLED HANGUL PIEUP A +3274;3274;3274;C0AC;1109 1161; # (㉴; ㉴; ㉴; 사; 사; ) CIRCLED HANGUL SIOS A +3275;3275;3275;C544;110B 1161; # (㉵; ㉵; ㉵; 아; 아; ) CIRCLED HANGUL IEUNG A +3276;3276;3276;C790;110C 1161; # (㉶; ㉶; ㉶; 자; 자; ) CIRCLED HANGUL CIEUC A +3277;3277;3277;CC28;110E 1161; # (㉷; ㉷; ㉷; 차; 차; ) CIRCLED HANGUL CHIEUCH A +3278;3278;3278;CE74;110F 1161; # (㉸; ㉸; ㉸; 카; 카; ) CIRCLED HANGUL KHIEUKH A +3279;3279;3279;D0C0;1110 1161; # (㉹; ㉹; ㉹; 타; 타; ) CIRCLED HANGUL THIEUTH A +327A;327A;327A;D30C;1111 1161; # (㉺; ㉺; ㉺; 파; 파; ) CIRCLED HANGUL PHIEUPH A +327B;327B;327B;D558;1112 1161; # (㉻; ㉻; ㉻; 하; 하; ) CIRCLED HANGUL HIEUH A +3280;3280;3280;4E00;4E00; # (㊀; ㊀; ㊀; 一; 一; ) CIRCLED IDEOGRAPH ONE +3281;3281;3281;4E8C;4E8C; # (㊁; ㊁; ㊁; 二; 二; ) CIRCLED IDEOGRAPH TWO +3282;3282;3282;4E09;4E09; # (㊂; ㊂; ㊂; 三; 三; ) CIRCLED IDEOGRAPH THREE +3283;3283;3283;56DB;56DB; # (㊃; ㊃; ㊃; 四; 四; ) CIRCLED IDEOGRAPH FOUR +3284;3284;3284;4E94;4E94; # (㊄; ㊄; ㊄; 五; 五; ) CIRCLED IDEOGRAPH FIVE +3285;3285;3285;516D;516D; # (㊅; ㊅; ㊅; 六; 六; ) CIRCLED IDEOGRAPH SIX +3286;3286;3286;4E03;4E03; # (㊆; ㊆; ㊆; 七; 七; ) CIRCLED IDEOGRAPH SEVEN +3287;3287;3287;516B;516B; # (㊇; ㊇; ㊇; 八; 八; ) CIRCLED IDEOGRAPH EIGHT +3288;3288;3288;4E5D;4E5D; # (㊈; ㊈; ㊈; 九; 九; ) CIRCLED IDEOGRAPH NINE +3289;3289;3289;5341;5341; # (㊉; ㊉; ㊉; 十; 十; ) CIRCLED IDEOGRAPH TEN +328A;328A;328A;6708;6708; # (㊊; ㊊; ㊊; 月; 月; ) CIRCLED IDEOGRAPH MOON +328B;328B;328B;706B;706B; # (㊋; ㊋; ㊋; 火; 火; ) CIRCLED IDEOGRAPH FIRE +328C;328C;328C;6C34;6C34; # (㊌; ㊌; ㊌; 水; 水; ) CIRCLED IDEOGRAPH WATER +328D;328D;328D;6728;6728; # (㊍; ㊍; ㊍; 木; 木; ) CIRCLED IDEOGRAPH WOOD +328E;328E;328E;91D1;91D1; # (㊎; ㊎; ㊎; 金; 金; ) CIRCLED IDEOGRAPH METAL +328F;328F;328F;571F;571F; # (㊏; ㊏; ㊏; 土; 土; ) CIRCLED IDEOGRAPH EARTH +3290;3290;3290;65E5;65E5; # (㊐; ㊐; ㊐; 日; 日; ) CIRCLED IDEOGRAPH SUN +3291;3291;3291;682A;682A; # (㊑; ㊑; ㊑; 株; 株; ) CIRCLED IDEOGRAPH STOCK +3292;3292;3292;6709;6709; # (㊒; ㊒; ㊒; 有; 有; ) CIRCLED IDEOGRAPH HAVE +3293;3293;3293;793E;793E; # (㊓; ㊓; ㊓; 社; 社; ) CIRCLED IDEOGRAPH SOCIETY +3294;3294;3294;540D;540D; # (㊔; ㊔; ㊔; 名; 名; ) CIRCLED IDEOGRAPH NAME +3295;3295;3295;7279;7279; # (㊕; ㊕; ㊕; 特; 特; ) CIRCLED IDEOGRAPH SPECIAL +3296;3296;3296;8CA1;8CA1; # (㊖; ㊖; ㊖; 財; 財; ) CIRCLED IDEOGRAPH FINANCIAL +3297;3297;3297;795D;795D; # (㊗; ㊗; ㊗; 祝; 祝; ) CIRCLED IDEOGRAPH CONGRATULATION +3298;3298;3298;52B4;52B4; # (㊘; ㊘; ㊘; 労; 労; ) CIRCLED IDEOGRAPH LABOR +3299;3299;3299;79D8;79D8; # (㊙; ㊙; ㊙; 秘; 秘; ) CIRCLED IDEOGRAPH SECRET +329A;329A;329A;7537;7537; # (㊚; ㊚; ㊚; 男; 男; ) CIRCLED IDEOGRAPH MALE +329B;329B;329B;5973;5973; # (㊛; ㊛; ㊛; 女; 女; ) CIRCLED IDEOGRAPH FEMALE +329C;329C;329C;9069;9069; # (㊜; ㊜; ㊜; 適; 適; ) CIRCLED IDEOGRAPH SUITABLE +329D;329D;329D;512A;512A; # (㊝; ㊝; ㊝; 優; 優; ) CIRCLED IDEOGRAPH EXCELLENT +329E;329E;329E;5370;5370; # (㊞; ㊞; ㊞; 印; 印; ) CIRCLED IDEOGRAPH PRINT +329F;329F;329F;6CE8;6CE8; # (㊟; ㊟; ㊟; 注; 注; ) CIRCLED IDEOGRAPH ATTENTION +32A0;32A0;32A0;9805;9805; # (㊠; ㊠; ㊠; 項; 項; ) CIRCLED IDEOGRAPH ITEM +32A1;32A1;32A1;4F11;4F11; # (㊡; ㊡; ㊡; 休; 休; ) CIRCLED IDEOGRAPH REST +32A2;32A2;32A2;5199;5199; # (㊢; ㊢; ㊢; 写; 写; ) CIRCLED IDEOGRAPH COPY +32A3;32A3;32A3;6B63;6B63; # (㊣; ㊣; ㊣; 正; 正; ) CIRCLED IDEOGRAPH CORRECT +32A4;32A4;32A4;4E0A;4E0A; # (㊤; ㊤; ㊤; 上; 上; ) CIRCLED IDEOGRAPH HIGH +32A5;32A5;32A5;4E2D;4E2D; # (㊥; ㊥; ㊥; 中; 中; ) CIRCLED IDEOGRAPH CENTRE +32A6;32A6;32A6;4E0B;4E0B; # (㊦; ㊦; ㊦; 下; 下; ) CIRCLED IDEOGRAPH LOW +32A7;32A7;32A7;5DE6;5DE6; # (㊧; ㊧; ㊧; 左; 左; ) CIRCLED IDEOGRAPH LEFT +32A8;32A8;32A8;53F3;53F3; # (㊨; ㊨; ㊨; 右; 右; ) CIRCLED IDEOGRAPH RIGHT +32A9;32A9;32A9;533B;533B; # (㊩; ㊩; ㊩; 医; 医; ) CIRCLED IDEOGRAPH MEDICINE +32AA;32AA;32AA;5B97;5B97; # (㊪; ㊪; ㊪; 宗; 宗; ) CIRCLED IDEOGRAPH RELIGION +32AB;32AB;32AB;5B66;5B66; # (㊫; ㊫; ㊫; 学; 学; ) CIRCLED IDEOGRAPH STUDY +32AC;32AC;32AC;76E3;76E3; # (㊬; ㊬; ㊬; 監; 監; ) CIRCLED IDEOGRAPH SUPERVISE +32AD;32AD;32AD;4F01;4F01; # (㊭; ㊭; ㊭; 企; 企; ) CIRCLED IDEOGRAPH ENTERPRISE +32AE;32AE;32AE;8CC7;8CC7; # (㊮; ㊮; ㊮; 資; 資; ) CIRCLED IDEOGRAPH RESOURCE +32AF;32AF;32AF;5354;5354; # (㊯; ㊯; ㊯; 協; 協; ) CIRCLED IDEOGRAPH ALLIANCE +32B0;32B0;32B0;591C;591C; # (㊰; ㊰; ㊰; 夜; 夜; ) CIRCLED IDEOGRAPH NIGHT +32B1;32B1;32B1;0033 0036;0033 0036; # (㊱; ㊱; ㊱; 36; 36; ) CIRCLED NUMBER THIRTY SIX +32B2;32B2;32B2;0033 0037;0033 0037; # (㊲; ㊲; ㊲; 37; 37; ) CIRCLED NUMBER THIRTY SEVEN +32B3;32B3;32B3;0033 0038;0033 0038; # (㊳; ㊳; ㊳; 38; 38; ) CIRCLED NUMBER THIRTY EIGHT +32B4;32B4;32B4;0033 0039;0033 0039; # (㊴; ㊴; ㊴; 39; 39; ) CIRCLED NUMBER THIRTY NINE +32B5;32B5;32B5;0034 0030;0034 0030; # (㊵; ㊵; ㊵; 40; 40; ) CIRCLED NUMBER FORTY +32B6;32B6;32B6;0034 0031;0034 0031; # (㊶; ㊶; ㊶; 41; 41; ) CIRCLED NUMBER FORTY ONE +32B7;32B7;32B7;0034 0032;0034 0032; # (㊷; ㊷; ㊷; 42; 42; ) CIRCLED NUMBER FORTY TWO +32B8;32B8;32B8;0034 0033;0034 0033; # (㊸; ㊸; ㊸; 43; 43; ) CIRCLED NUMBER FORTY THREE +32B9;32B9;32B9;0034 0034;0034 0034; # (㊹; ㊹; ㊹; 44; 44; ) CIRCLED NUMBER FORTY FOUR +32BA;32BA;32BA;0034 0035;0034 0035; # (㊺; ㊺; ㊺; 45; 45; ) CIRCLED NUMBER FORTY FIVE +32BB;32BB;32BB;0034 0036;0034 0036; # (㊻; ㊻; ㊻; 46; 46; ) CIRCLED NUMBER FORTY SIX +32BC;32BC;32BC;0034 0037;0034 0037; # (㊼; ㊼; ㊼; 47; 47; ) CIRCLED NUMBER FORTY SEVEN +32BD;32BD;32BD;0034 0038;0034 0038; # (㊽; ㊽; ㊽; 48; 48; ) CIRCLED NUMBER FORTY EIGHT +32BE;32BE;32BE;0034 0039;0034 0039; # (㊾; ㊾; ㊾; 49; 49; ) CIRCLED NUMBER FORTY NINE +32BF;32BF;32BF;0035 0030;0035 0030; # (㊿; ㊿; ㊿; 50; 50; ) CIRCLED NUMBER FIFTY +32C0;32C0;32C0;0031 6708;0031 6708; # (㋀; ㋀; ㋀; 1月; 1月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY +32C1;32C1;32C1;0032 6708;0032 6708; # (㋁; ㋁; ㋁; 2月; 2月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY +32C2;32C2;32C2;0033 6708;0033 6708; # (㋂; ㋂; ㋂; 3月; 3月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH +32C3;32C3;32C3;0034 6708;0034 6708; # (㋃; ㋃; ㋃; 4月; 4月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL +32C4;32C4;32C4;0035 6708;0035 6708; # (㋄; ㋄; ㋄; 5月; 5月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY +32C5;32C5;32C5;0036 6708;0036 6708; # (㋅; ㋅; ㋅; 6月; 6月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE +32C6;32C6;32C6;0037 6708;0037 6708; # (㋆; ㋆; ㋆; 7月; 7月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY +32C7;32C7;32C7;0038 6708;0038 6708; # (㋇; ㋇; ㋇; 8月; 8月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST +32C8;32C8;32C8;0039 6708;0039 6708; # (㋈; ㋈; ㋈; 9月; 9月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER +32C9;32C9;32C9;0031 0030 6708;0031 0030 6708; # (㋉; ㋉; ㋉; 10月; 10月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER +32CA;32CA;32CA;0031 0031 6708;0031 0031 6708; # (㋊; ㋊; ㋊; 11月; 11月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER +32CB;32CB;32CB;0031 0032 6708;0031 0032 6708; # (㋋; ㋋; ㋋; 12月; 12月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER +32D0;32D0;32D0;30A2;30A2; # (㋐; ㋐; ㋐; ア; ア; ) CIRCLED KATAKANA A +32D1;32D1;32D1;30A4;30A4; # (㋑; ㋑; ㋑; イ; イ; ) CIRCLED KATAKANA I +32D2;32D2;32D2;30A6;30A6; # (㋒; ㋒; ㋒; ウ; ウ; ) CIRCLED KATAKANA U +32D3;32D3;32D3;30A8;30A8; # (㋓; ㋓; ㋓; エ; エ; ) CIRCLED KATAKANA E +32D4;32D4;32D4;30AA;30AA; # (㋔; ㋔; ㋔; オ; オ; ) CIRCLED KATAKANA O +32D5;32D5;32D5;30AB;30AB; # (㋕; ㋕; ㋕; カ; カ; ) CIRCLED KATAKANA KA +32D6;32D6;32D6;30AD;30AD; # (㋖; ㋖; ㋖; キ; キ; ) CIRCLED KATAKANA KI +32D7;32D7;32D7;30AF;30AF; # (㋗; ㋗; ㋗; ク; ク; ) CIRCLED KATAKANA KU +32D8;32D8;32D8;30B1;30B1; # (㋘; ㋘; ㋘; ケ; ケ; ) CIRCLED KATAKANA KE +32D9;32D9;32D9;30B3;30B3; # (㋙; ㋙; ㋙; コ; コ; ) CIRCLED KATAKANA KO +32DA;32DA;32DA;30B5;30B5; # (㋚; ㋚; ㋚; サ; サ; ) CIRCLED KATAKANA SA +32DB;32DB;32DB;30B7;30B7; # (㋛; ㋛; ㋛; シ; シ; ) CIRCLED KATAKANA SI +32DC;32DC;32DC;30B9;30B9; # (㋜; ㋜; ㋜; ス; ス; ) CIRCLED KATAKANA SU +32DD;32DD;32DD;30BB;30BB; # (㋝; ㋝; ㋝; セ; セ; ) CIRCLED KATAKANA SE +32DE;32DE;32DE;30BD;30BD; # (㋞; ㋞; ㋞; ソ; ソ; ) CIRCLED KATAKANA SO +32DF;32DF;32DF;30BF;30BF; # (㋟; ㋟; ㋟; タ; タ; ) CIRCLED KATAKANA TA +32E0;32E0;32E0;30C1;30C1; # (㋠; ㋠; ㋠; チ; チ; ) CIRCLED KATAKANA TI +32E1;32E1;32E1;30C4;30C4; # (㋡; ㋡; ㋡; ツ; ツ; ) CIRCLED KATAKANA TU +32E2;32E2;32E2;30C6;30C6; # (㋢; ㋢; ㋢; テ; テ; ) CIRCLED KATAKANA TE +32E3;32E3;32E3;30C8;30C8; # (㋣; ㋣; ㋣; ト; ト; ) CIRCLED KATAKANA TO +32E4;32E4;32E4;30CA;30CA; # (㋤; ㋤; ㋤; ナ; ナ; ) CIRCLED KATAKANA NA +32E5;32E5;32E5;30CB;30CB; # (㋥; ㋥; ㋥; ニ; ニ; ) CIRCLED KATAKANA NI +32E6;32E6;32E6;30CC;30CC; # (㋦; ㋦; ㋦; ヌ; ヌ; ) CIRCLED KATAKANA NU +32E7;32E7;32E7;30CD;30CD; # (㋧; ㋧; ㋧; ネ; ネ; ) CIRCLED KATAKANA NE +32E8;32E8;32E8;30CE;30CE; # (㋨; ㋨; ㋨; ノ; ノ; ) CIRCLED KATAKANA NO +32E9;32E9;32E9;30CF;30CF; # (㋩; ㋩; ㋩; ハ; ハ; ) CIRCLED KATAKANA HA +32EA;32EA;32EA;30D2;30D2; # (㋪; ㋪; ㋪; ヒ; ヒ; ) CIRCLED KATAKANA HI +32EB;32EB;32EB;30D5;30D5; # (㋫; ㋫; ㋫; フ; フ; ) CIRCLED KATAKANA HU +32EC;32EC;32EC;30D8;30D8; # (㋬; ㋬; ㋬; ヘ; ヘ; ) CIRCLED KATAKANA HE +32ED;32ED;32ED;30DB;30DB; # (㋭; ㋭; ㋭; ホ; ホ; ) CIRCLED KATAKANA HO +32EE;32EE;32EE;30DE;30DE; # (㋮; ㋮; ㋮; マ; マ; ) CIRCLED KATAKANA MA +32EF;32EF;32EF;30DF;30DF; # (㋯; ㋯; ㋯; ミ; ミ; ) CIRCLED KATAKANA MI +32F0;32F0;32F0;30E0;30E0; # (㋰; ㋰; ㋰; ム; ム; ) CIRCLED KATAKANA MU +32F1;32F1;32F1;30E1;30E1; # (㋱; ㋱; ㋱; メ; メ; ) CIRCLED KATAKANA ME +32F2;32F2;32F2;30E2;30E2; # (㋲; ㋲; ㋲; モ; モ; ) CIRCLED KATAKANA MO +32F3;32F3;32F3;30E4;30E4; # (㋳; ㋳; ㋳; ヤ; ヤ; ) CIRCLED KATAKANA YA +32F4;32F4;32F4;30E6;30E6; # (㋴; ㋴; ㋴; ユ; ユ; ) CIRCLED KATAKANA YU +32F5;32F5;32F5;30E8;30E8; # (㋵; ㋵; ㋵; ヨ; ヨ; ) CIRCLED KATAKANA YO +32F6;32F6;32F6;30E9;30E9; # (㋶; ㋶; ㋶; ラ; ラ; ) CIRCLED KATAKANA RA +32F7;32F7;32F7;30EA;30EA; # (㋷; ㋷; ㋷; リ; リ; ) CIRCLED KATAKANA RI +32F8;32F8;32F8;30EB;30EB; # (㋸; ㋸; ㋸; ル; ル; ) CIRCLED KATAKANA RU +32F9;32F9;32F9;30EC;30EC; # (㋹; ㋹; ㋹; レ; レ; ) CIRCLED KATAKANA RE +32FA;32FA;32FA;30ED;30ED; # (㋺; ㋺; ㋺; ロ; ロ; ) CIRCLED KATAKANA RO +32FB;32FB;32FB;30EF;30EF; # (㋻; ㋻; ㋻; ワ; ワ; ) CIRCLED KATAKANA WA +32FC;32FC;32FC;30F0;30F0; # (㋼; ㋼; ㋼; ヰ; ヰ; ) CIRCLED KATAKANA WI +32FD;32FD;32FD;30F1;30F1; # (㋽; ㋽; ㋽; ヱ; ヱ; ) CIRCLED KATAKANA WE +32FE;32FE;32FE;30F2;30F2; # (㋾; ㋾; ㋾; ヲ; ヲ; ) CIRCLED KATAKANA WO +3300;3300;3300;30A2 30D1 30FC 30C8;30A2 30CF 309A 30FC 30C8; # (㌀; ㌀; ㌀; アパート; アハ◌゚ート; ) SQUARE APAATO +3301;3301;3301;30A2 30EB 30D5 30A1;30A2 30EB 30D5 30A1; # (㌁; ㌁; ㌁; アルファ; アルファ; ) SQUARE ARUHUA +3302;3302;3302;30A2 30F3 30DA 30A2;30A2 30F3 30D8 309A 30A2; # (㌂; ㌂; ㌂; アンペア; アンヘ◌゚ア; ) SQUARE ANPEA +3303;3303;3303;30A2 30FC 30EB;30A2 30FC 30EB; # (㌃; ㌃; ㌃; アール; アール; ) SQUARE AARU +3304;3304;3304;30A4 30CB 30F3 30B0;30A4 30CB 30F3 30AF 3099; # (㌄; ㌄; ㌄; イニング; イニンク◌゙; ) SQUARE ININGU +3305;3305;3305;30A4 30F3 30C1;30A4 30F3 30C1; # (㌅; ㌅; ㌅; インチ; インチ; ) SQUARE INTI +3306;3306;3306;30A6 30A9 30F3;30A6 30A9 30F3; # (㌆; ㌆; ㌆; ウォン; ウォン; ) SQUARE UON +3307;3307;3307;30A8 30B9 30AF 30FC 30C9;30A8 30B9 30AF 30FC 30C8 3099; # (㌇; ㌇; ㌇; エスクード; エスクート◌゙; ) SQUARE ESUKUUDO +3308;3308;3308;30A8 30FC 30AB 30FC;30A8 30FC 30AB 30FC; # (㌈; ㌈; ㌈; エーカー; エーカー; ) SQUARE EEKAA +3309;3309;3309;30AA 30F3 30B9;30AA 30F3 30B9; # (㌉; ㌉; ㌉; オンス; オンス; ) SQUARE ONSU +330A;330A;330A;30AA 30FC 30E0;30AA 30FC 30E0; # (㌊; ㌊; ㌊; オーム; オーム; ) SQUARE OOMU +330B;330B;330B;30AB 30A4 30EA;30AB 30A4 30EA; # (㌋; ㌋; ㌋; カイリ; カイリ; ) SQUARE KAIRI +330C;330C;330C;30AB 30E9 30C3 30C8;30AB 30E9 30C3 30C8; # (㌌; ㌌; ㌌; カラット; カラット; ) SQUARE KARATTO +330D;330D;330D;30AB 30ED 30EA 30FC;30AB 30ED 30EA 30FC; # (㌍; ㌍; ㌍; カロリー; カロリー; ) SQUARE KARORII +330E;330E;330E;30AC 30ED 30F3;30AB 3099 30ED 30F3; # (㌎; ㌎; ㌎; ガロン; カ◌゙ロン; ) SQUARE GARON +330F;330F;330F;30AC 30F3 30DE;30AB 3099 30F3 30DE; # (㌏; ㌏; ㌏; ガンマ; カ◌゙ンマ; ) SQUARE GANMA +3310;3310;3310;30AE 30AC;30AD 3099 30AB 3099; # (㌐; ㌐; ㌐; ギガ; キ◌゙カ◌゙; ) SQUARE GIGA +3311;3311;3311;30AE 30CB 30FC;30AD 3099 30CB 30FC; # (㌑; ㌑; ㌑; ギニー; キ◌゙ニー; ) SQUARE GINII +3312;3312;3312;30AD 30E5 30EA 30FC;30AD 30E5 30EA 30FC; # (㌒; ㌒; ㌒; キュリー; キュリー; ) SQUARE KYURII +3313;3313;3313;30AE 30EB 30C0 30FC;30AD 3099 30EB 30BF 3099 30FC; # (㌓; ㌓; ㌓; ギルダー; キ◌゙ルタ◌゙ー; ) SQUARE GIRUDAA +3314;3314;3314;30AD 30ED;30AD 30ED; # (㌔; ㌔; ㌔; キロ; キロ; ) SQUARE KIRO +3315;3315;3315;30AD 30ED 30B0 30E9 30E0;30AD 30ED 30AF 3099 30E9 30E0; # (㌕; ㌕; ㌕; キログラム; キロク◌゙ラム; ) SQUARE KIROGURAMU +3316;3316;3316;30AD 30ED 30E1 30FC 30C8 30EB;30AD 30ED 30E1 30FC 30C8 30EB; # (㌖; ㌖; ㌖; キロメートル; キロメートル; ) SQUARE KIROMEETORU +3317;3317;3317;30AD 30ED 30EF 30C3 30C8;30AD 30ED 30EF 30C3 30C8; # (㌗; ㌗; ㌗; キロワット; キロワット; ) SQUARE KIROWATTO +3318;3318;3318;30B0 30E9 30E0;30AF 3099 30E9 30E0; # (㌘; ㌘; ㌘; グラム; ク◌゙ラム; ) SQUARE GURAMU +3319;3319;3319;30B0 30E9 30E0 30C8 30F3;30AF 3099 30E9 30E0 30C8 30F3; # (㌙; ㌙; ㌙; グラムトン; ク◌゙ラムトン; ) SQUARE GURAMUTON +331A;331A;331A;30AF 30EB 30BC 30A4 30ED;30AF 30EB 30BB 3099 30A4 30ED; # (㌚; ㌚; ㌚; クルゼイロ; クルセ◌゙イロ; ) SQUARE KURUZEIRO +331B;331B;331B;30AF 30ED 30FC 30CD;30AF 30ED 30FC 30CD; # (㌛; ㌛; ㌛; クローネ; クローネ; ) SQUARE KUROONE +331C;331C;331C;30B1 30FC 30B9;30B1 30FC 30B9; # (㌜; ㌜; ㌜; ケース; ケース; ) SQUARE KEESU +331D;331D;331D;30B3 30EB 30CA;30B3 30EB 30CA; # (㌝; ㌝; ㌝; コルナ; コルナ; ) SQUARE KORUNA +331E;331E;331E;30B3 30FC 30DD;30B3 30FC 30DB 309A; # (㌞; ㌞; ㌞; コーポ; コーホ◌゚; ) SQUARE KOOPO +331F;331F;331F;30B5 30A4 30AF 30EB;30B5 30A4 30AF 30EB; # (㌟; ㌟; ㌟; サイクル; サイクル; ) SQUARE SAIKURU +3320;3320;3320;30B5 30F3 30C1 30FC 30E0;30B5 30F3 30C1 30FC 30E0; # (㌠; ㌠; ㌠; サンチーム; サンチーム; ) SQUARE SANTIIMU +3321;3321;3321;30B7 30EA 30F3 30B0;30B7 30EA 30F3 30AF 3099; # (㌡; ㌡; ㌡; シリング; シリンク◌゙; ) SQUARE SIRINGU +3322;3322;3322;30BB 30F3 30C1;30BB 30F3 30C1; # (㌢; ㌢; ㌢; センチ; センチ; ) SQUARE SENTI +3323;3323;3323;30BB 30F3 30C8;30BB 30F3 30C8; # (㌣; ㌣; ㌣; セント; セント; ) SQUARE SENTO +3324;3324;3324;30C0 30FC 30B9;30BF 3099 30FC 30B9; # (㌤; ㌤; ㌤; ダース; タ◌゙ース; ) SQUARE DAASU +3325;3325;3325;30C7 30B7;30C6 3099 30B7; # (㌥; ㌥; ㌥; デシ; テ◌゙シ; ) SQUARE DESI +3326;3326;3326;30C9 30EB;30C8 3099 30EB; # (㌦; ㌦; ㌦; ドル; ト◌゙ル; ) SQUARE DORU +3327;3327;3327;30C8 30F3;30C8 30F3; # (㌧; ㌧; ㌧; トン; トン; ) SQUARE TON +3328;3328;3328;30CA 30CE;30CA 30CE; # (㌨; ㌨; ㌨; ナノ; ナノ; ) SQUARE NANO +3329;3329;3329;30CE 30C3 30C8;30CE 30C3 30C8; # (㌩; ㌩; ㌩; ノット; ノット; ) SQUARE NOTTO +332A;332A;332A;30CF 30A4 30C4;30CF 30A4 30C4; # (㌪; ㌪; ㌪; ハイツ; ハイツ; ) SQUARE HAITU +332B;332B;332B;30D1 30FC 30BB 30F3 30C8;30CF 309A 30FC 30BB 30F3 30C8; # (㌫; ㌫; ㌫; パーセント; ハ◌゚ーセント; ) SQUARE PAASENTO +332C;332C;332C;30D1 30FC 30C4;30CF 309A 30FC 30C4; # (㌬; ㌬; ㌬; パーツ; ハ◌゚ーツ; ) SQUARE PAATU +332D;332D;332D;30D0 30FC 30EC 30EB;30CF 3099 30FC 30EC 30EB; # (㌭; ㌭; ㌭; バーレル; ハ◌゙ーレル; ) SQUARE BAARERU +332E;332E;332E;30D4 30A2 30B9 30C8 30EB;30D2 309A 30A2 30B9 30C8 30EB; # (㌮; ㌮; ㌮; ピアストル; ヒ◌゚アストル; ) SQUARE PIASUTORU +332F;332F;332F;30D4 30AF 30EB;30D2 309A 30AF 30EB; # (㌯; ㌯; ㌯; ピクル; ヒ◌゚クル; ) SQUARE PIKURU +3330;3330;3330;30D4 30B3;30D2 309A 30B3; # (㌰; ㌰; ㌰; ピコ; ヒ◌゚コ; ) SQUARE PIKO +3331;3331;3331;30D3 30EB;30D2 3099 30EB; # (㌱; ㌱; ㌱; ビル; ヒ◌゙ル; ) SQUARE BIRU +3332;3332;3332;30D5 30A1 30E9 30C3 30C9;30D5 30A1 30E9 30C3 30C8 3099; # (㌲; ㌲; ㌲; ファラッド; ファラット◌゙; ) SQUARE HUARADDO +3333;3333;3333;30D5 30A3 30FC 30C8;30D5 30A3 30FC 30C8; # (㌳; ㌳; ㌳; フィート; フィート; ) SQUARE HUIITO +3334;3334;3334;30D6 30C3 30B7 30A7 30EB;30D5 3099 30C3 30B7 30A7 30EB; # (㌴; ㌴; ㌴; ブッシェル; フ◌゙ッシェル; ) SQUARE BUSSYERU +3335;3335;3335;30D5 30E9 30F3;30D5 30E9 30F3; # (㌵; ㌵; ㌵; フラン; フラン; ) SQUARE HURAN +3336;3336;3336;30D8 30AF 30BF 30FC 30EB;30D8 30AF 30BF 30FC 30EB; # (㌶; ㌶; ㌶; ヘクタール; ヘクタール; ) SQUARE HEKUTAARU +3337;3337;3337;30DA 30BD;30D8 309A 30BD; # (㌷; ㌷; ㌷; ペソ; ヘ◌゚ソ; ) SQUARE PESO +3338;3338;3338;30DA 30CB 30D2;30D8 309A 30CB 30D2; # (㌸; ㌸; ㌸; ペニヒ; ヘ◌゚ニヒ; ) SQUARE PENIHI +3339;3339;3339;30D8 30EB 30C4;30D8 30EB 30C4; # (㌹; ㌹; ㌹; ヘルツ; ヘルツ; ) SQUARE HERUTU +333A;333A;333A;30DA 30F3 30B9;30D8 309A 30F3 30B9; # (㌺; ㌺; ㌺; ペンス; ヘ◌゚ンス; ) SQUARE PENSU +333B;333B;333B;30DA 30FC 30B8;30D8 309A 30FC 30B7 3099; # (㌻; ㌻; ㌻; ページ; ヘ◌゚ーシ◌゙; ) SQUARE PEEZI +333C;333C;333C;30D9 30FC 30BF;30D8 3099 30FC 30BF; # (㌼; ㌼; ㌼; ベータ; ヘ◌゙ータ; ) SQUARE BEETA +333D;333D;333D;30DD 30A4 30F3 30C8;30DB 309A 30A4 30F3 30C8; # (㌽; ㌽; ㌽; ポイント; ホ◌゚イント; ) SQUARE POINTO +333E;333E;333E;30DC 30EB 30C8;30DB 3099 30EB 30C8; # (㌾; ㌾; ㌾; ボルト; ホ◌゙ルト; ) SQUARE BORUTO +333F;333F;333F;30DB 30F3;30DB 30F3; # (㌿; ㌿; ㌿; ホン; ホン; ) SQUARE HON +3340;3340;3340;30DD 30F3 30C9;30DB 309A 30F3 30C8 3099; # (㍀; ㍀; ㍀; ポンド; ホ◌゚ント◌゙; ) SQUARE PONDO +3341;3341;3341;30DB 30FC 30EB;30DB 30FC 30EB; # (㍁; ㍁; ㍁; ホール; ホール; ) SQUARE HOORU +3342;3342;3342;30DB 30FC 30F3;30DB 30FC 30F3; # (㍂; ㍂; ㍂; ホーン; ホーン; ) SQUARE HOON +3343;3343;3343;30DE 30A4 30AF 30ED;30DE 30A4 30AF 30ED; # (㍃; ㍃; ㍃; マイクロ; マイクロ; ) SQUARE MAIKURO +3344;3344;3344;30DE 30A4 30EB;30DE 30A4 30EB; # (㍄; ㍄; ㍄; マイル; マイル; ) SQUARE MAIRU +3345;3345;3345;30DE 30C3 30CF;30DE 30C3 30CF; # (㍅; ㍅; ㍅; マッハ; マッハ; ) SQUARE MAHHA +3346;3346;3346;30DE 30EB 30AF;30DE 30EB 30AF; # (㍆; ㍆; ㍆; マルク; マルク; ) SQUARE MARUKU +3347;3347;3347;30DE 30F3 30B7 30E7 30F3;30DE 30F3 30B7 30E7 30F3; # (㍇; ㍇; ㍇; マンション; マンション; ) SQUARE MANSYON +3348;3348;3348;30DF 30AF 30ED 30F3;30DF 30AF 30ED 30F3; # (㍈; ㍈; ㍈; ミクロン; ミクロン; ) SQUARE MIKURON +3349;3349;3349;30DF 30EA;30DF 30EA; # (㍉; ㍉; ㍉; ミリ; ミリ; ) SQUARE MIRI +334A;334A;334A;30DF 30EA 30D0 30FC 30EB;30DF 30EA 30CF 3099 30FC 30EB; # (㍊; ㍊; ㍊; ミリバール; ミリハ◌゙ール; ) SQUARE MIRIBAARU +334B;334B;334B;30E1 30AC;30E1 30AB 3099; # (㍋; ㍋; ㍋; メガ; メカ◌゙; ) SQUARE MEGA +334C;334C;334C;30E1 30AC 30C8 30F3;30E1 30AB 3099 30C8 30F3; # (㍌; ㍌; ㍌; メガトン; メカ◌゙トン; ) SQUARE MEGATON +334D;334D;334D;30E1 30FC 30C8 30EB;30E1 30FC 30C8 30EB; # (㍍; ㍍; ㍍; メートル; メートル; ) SQUARE MEETORU +334E;334E;334E;30E4 30FC 30C9;30E4 30FC 30C8 3099; # (㍎; ㍎; ㍎; ヤード; ヤート◌゙; ) SQUARE YAADO +334F;334F;334F;30E4 30FC 30EB;30E4 30FC 30EB; # (㍏; ㍏; ㍏; ヤール; ヤール; ) SQUARE YAARU +3350;3350;3350;30E6 30A2 30F3;30E6 30A2 30F3; # (㍐; ㍐; ㍐; ユアン; ユアン; ) SQUARE YUAN +3351;3351;3351;30EA 30C3 30C8 30EB;30EA 30C3 30C8 30EB; # (㍑; ㍑; ㍑; リットル; リットル; ) SQUARE RITTORU +3352;3352;3352;30EA 30E9;30EA 30E9; # (㍒; ㍒; ㍒; リラ; リラ; ) SQUARE RIRA +3353;3353;3353;30EB 30D4 30FC;30EB 30D2 309A 30FC; # (㍓; ㍓; ㍓; ルピー; ルヒ◌゚ー; ) SQUARE RUPII +3354;3354;3354;30EB 30FC 30D6 30EB;30EB 30FC 30D5 3099 30EB; # (㍔; ㍔; ㍔; ルーブル; ルーフ◌゙ル; ) SQUARE RUUBURU +3355;3355;3355;30EC 30E0;30EC 30E0; # (㍕; ㍕; ㍕; レム; レム; ) SQUARE REMU +3356;3356;3356;30EC 30F3 30C8 30B2 30F3;30EC 30F3 30C8 30B1 3099 30F3; # (㍖; ㍖; ㍖; レントゲン; レントケ◌゙ン; ) SQUARE RENTOGEN +3357;3357;3357;30EF 30C3 30C8;30EF 30C3 30C8; # (㍗; ㍗; ㍗; ワット; ワット; ) SQUARE WATTO +3358;3358;3358;0030 70B9;0030 70B9; # (㍘; ㍘; ㍘; 0点; 0点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO +3359;3359;3359;0031 70B9;0031 70B9; # (㍙; ㍙; ㍙; 1点; 1点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE +335A;335A;335A;0032 70B9;0032 70B9; # (㍚; ㍚; ㍚; 2点; 2点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO +335B;335B;335B;0033 70B9;0033 70B9; # (㍛; ㍛; ㍛; 3点; 3点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE +335C;335C;335C;0034 70B9;0034 70B9; # (㍜; ㍜; ㍜; 4点; 4点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR +335D;335D;335D;0035 70B9;0035 70B9; # (㍝; ㍝; ㍝; 5点; 5点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE +335E;335E;335E;0036 70B9;0036 70B9; # (㍞; ㍞; ㍞; 6点; 6点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX +335F;335F;335F;0037 70B9;0037 70B9; # (㍟; ㍟; ㍟; 7点; 7点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN +3360;3360;3360;0038 70B9;0038 70B9; # (㍠; ㍠; ㍠; 8点; 8点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT +3361;3361;3361;0039 70B9;0039 70B9; # (㍡; ㍡; ㍡; 9点; 9点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE +3362;3362;3362;0031 0030 70B9;0031 0030 70B9; # (㍢; ㍢; ㍢; 10点; 10点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN +3363;3363;3363;0031 0031 70B9;0031 0031 70B9; # (㍣; ㍣; ㍣; 11点; 11点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN +3364;3364;3364;0031 0032 70B9;0031 0032 70B9; # (㍤; ㍤; ㍤; 12点; 12点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE +3365;3365;3365;0031 0033 70B9;0031 0033 70B9; # (㍥; ㍥; ㍥; 13点; 13点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN +3366;3366;3366;0031 0034 70B9;0031 0034 70B9; # (㍦; ㍦; ㍦; 14点; 14点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN +3367;3367;3367;0031 0035 70B9;0031 0035 70B9; # (㍧; ㍧; ㍧; 15点; 15点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN +3368;3368;3368;0031 0036 70B9;0031 0036 70B9; # (㍨; ㍨; ㍨; 16点; 16点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN +3369;3369;3369;0031 0037 70B9;0031 0037 70B9; # (㍩; ㍩; ㍩; 17点; 17点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN +336A;336A;336A;0031 0038 70B9;0031 0038 70B9; # (㍪; ㍪; ㍪; 18点; 18点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN +336B;336B;336B;0031 0039 70B9;0031 0039 70B9; # (㍫; ㍫; ㍫; 19点; 19点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN +336C;336C;336C;0032 0030 70B9;0032 0030 70B9; # (㍬; ㍬; ㍬; 20点; 20点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY +336D;336D;336D;0032 0031 70B9;0032 0031 70B9; # (㍭; ㍭; ㍭; 21点; 21点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE +336E;336E;336E;0032 0032 70B9;0032 0032 70B9; # (㍮; ㍮; ㍮; 22点; 22点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO +336F;336F;336F;0032 0033 70B9;0032 0033 70B9; # (㍯; ㍯; ㍯; 23点; 23点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE +3370;3370;3370;0032 0034 70B9;0032 0034 70B9; # (㍰; ㍰; ㍰; 24点; 24点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR +3371;3371;3371;0068 0050 0061;0068 0050 0061; # (㍱; ㍱; ㍱; hPa; hPa; ) SQUARE HPA +3372;3372;3372;0064 0061;0064 0061; # (㍲; ㍲; ㍲; da; da; ) SQUARE DA +3373;3373;3373;0041 0055;0041 0055; # (㍳; ㍳; ㍳; AU; AU; ) SQUARE AU +3374;3374;3374;0062 0061 0072;0062 0061 0072; # (㍴; ㍴; ㍴; bar; bar; ) SQUARE BAR +3375;3375;3375;006F 0056;006F 0056; # (㍵; ㍵; ㍵; oV; oV; ) SQUARE OV +3376;3376;3376;0070 0063;0070 0063; # (㍶; ㍶; ㍶; pc; pc; ) SQUARE PC +337B;337B;337B;5E73 6210;5E73 6210; # (㍻; ㍻; ㍻; 平成; 平成; ) SQUARE ERA NAME HEISEI +337C;337C;337C;662D 548C;662D 548C; # (㍼; ㍼; ㍼; 昭和; 昭和; ) SQUARE ERA NAME SYOUWA +337D;337D;337D;5927 6B63;5927 6B63; # (㍽; ㍽; ㍽; 大正; 大正; ) SQUARE ERA NAME TAISYOU +337E;337E;337E;660E 6CBB;660E 6CBB; # (㍾; ㍾; ㍾; 明治; 明治; ) SQUARE ERA NAME MEIZI +337F;337F;337F;682A 5F0F 4F1A 793E;682A 5F0F 4F1A 793E; # (㍿; ㍿; ㍿; 株式会社; 株式会社; ) SQUARE CORPORATION +3380;3380;3380;0070 0041;0070 0041; # (㎀; ㎀; ㎀; pA; pA; ) SQUARE PA AMPS +3381;3381;3381;006E 0041;006E 0041; # (㎁; ㎁; ㎁; nA; nA; ) SQUARE NA +3382;3382;3382;03BC 0041;03BC 0041; # (㎂; ㎂; ㎂; μA; μA; ) SQUARE MU A +3383;3383;3383;006D 0041;006D 0041; # (㎃; ㎃; ㎃; mA; mA; ) SQUARE MA +3384;3384;3384;006B 0041;006B 0041; # (㎄; ㎄; ㎄; kA; kA; ) SQUARE KA +3385;3385;3385;004B 0042;004B 0042; # (㎅; ㎅; ㎅; KB; KB; ) SQUARE KB +3386;3386;3386;004D 0042;004D 0042; # (㎆; ㎆; ㎆; MB; MB; ) SQUARE MB +3387;3387;3387;0047 0042;0047 0042; # (㎇; ㎇; ㎇; GB; GB; ) SQUARE GB +3388;3388;3388;0063 0061 006C;0063 0061 006C; # (㎈; ㎈; ㎈; cal; cal; ) SQUARE CAL +3389;3389;3389;006B 0063 0061 006C;006B 0063 0061 006C; # (㎉; ㎉; ㎉; kcal; kcal; ) SQUARE KCAL +338A;338A;338A;0070 0046;0070 0046; # (㎊; ㎊; ㎊; pF; pF; ) SQUARE PF +338B;338B;338B;006E 0046;006E 0046; # (㎋; ㎋; ㎋; nF; nF; ) SQUARE NF +338C;338C;338C;03BC 0046;03BC 0046; # (㎌; ㎌; ㎌; μF; μF; ) SQUARE MU F +338D;338D;338D;03BC 0067;03BC 0067; # (㎍; ㎍; ㎍; μg; μg; ) SQUARE MU G +338E;338E;338E;006D 0067;006D 0067; # (㎎; ㎎; ㎎; mg; mg; ) SQUARE MG +338F;338F;338F;006B 0067;006B 0067; # (㎏; ㎏; ㎏; kg; kg; ) SQUARE KG +3390;3390;3390;0048 007A;0048 007A; # (㎐; ㎐; ㎐; Hz; Hz; ) SQUARE HZ +3391;3391;3391;006B 0048 007A;006B 0048 007A; # (㎑; ㎑; ㎑; kHz; kHz; ) SQUARE KHZ +3392;3392;3392;004D 0048 007A;004D 0048 007A; # (㎒; ㎒; ㎒; MHz; MHz; ) SQUARE MHZ +3393;3393;3393;0047 0048 007A;0047 0048 007A; # (㎓; ㎓; ㎓; GHz; GHz; ) SQUARE GHZ +3394;3394;3394;0054 0048 007A;0054 0048 007A; # (㎔; ㎔; ㎔; THz; THz; ) SQUARE THZ +3395;3395;3395;03BC 006C;03BC 006C; # (㎕; ㎕; ㎕; μl; μl; ) SQUARE MU L +3396;3396;3396;006D 006C;006D 006C; # (㎖; ㎖; ㎖; ml; ml; ) SQUARE ML +3397;3397;3397;0064 006C;0064 006C; # (㎗; ㎗; ㎗; dl; dl; ) SQUARE DL +3398;3398;3398;006B 006C;006B 006C; # (㎘; ㎘; ㎘; kl; kl; ) SQUARE KL +3399;3399;3399;0066 006D;0066 006D; # (㎙; ㎙; ㎙; fm; fm; ) SQUARE FM +339A;339A;339A;006E 006D;006E 006D; # (㎚; ㎚; ㎚; nm; nm; ) SQUARE NM +339B;339B;339B;03BC 006D;03BC 006D; # (㎛; ㎛; ㎛; μm; μm; ) SQUARE MU M +339C;339C;339C;006D 006D;006D 006D; # (㎜; ㎜; ㎜; mm; mm; ) SQUARE MM +339D;339D;339D;0063 006D;0063 006D; # (㎝; ㎝; ㎝; cm; cm; ) SQUARE CM +339E;339E;339E;006B 006D;006B 006D; # (㎞; ㎞; ㎞; km; km; ) SQUARE KM +339F;339F;339F;006D 006D 0032;006D 006D 0032; # (㎟; ㎟; ㎟; mm2; mm2; ) SQUARE MM SQUARED +33A0;33A0;33A0;0063 006D 0032;0063 006D 0032; # (㎠; ㎠; ㎠; cm2; cm2; ) SQUARE CM SQUARED +33A1;33A1;33A1;006D 0032;006D 0032; # (㎡; ㎡; ㎡; m2; m2; ) SQUARE M SQUARED +33A2;33A2;33A2;006B 006D 0032;006B 006D 0032; # (㎢; ㎢; ㎢; km2; km2; ) SQUARE KM SQUARED +33A3;33A3;33A3;006D 006D 0033;006D 006D 0033; # (㎣; ㎣; ㎣; mm3; mm3; ) SQUARE MM CUBED +33A4;33A4;33A4;0063 006D 0033;0063 006D 0033; # (㎤; ㎤; ㎤; cm3; cm3; ) SQUARE CM CUBED +33A5;33A5;33A5;006D 0033;006D 0033; # (㎥; ㎥; ㎥; m3; m3; ) SQUARE M CUBED +33A6;33A6;33A6;006B 006D 0033;006B 006D 0033; # (㎦; ㎦; ㎦; km3; km3; ) SQUARE KM CUBED +33A7;33A7;33A7;006D 2215 0073;006D 2215 0073; # (㎧; ㎧; ㎧; m∕s; m∕s; ) SQUARE M OVER S +33A8;33A8;33A8;006D 2215 0073 0032;006D 2215 0073 0032; # (㎨; ㎨; ㎨; m∕s2; m∕s2; ) SQUARE M OVER S SQUARED +33A9;33A9;33A9;0050 0061;0050 0061; # (㎩; ㎩; ㎩; Pa; Pa; ) SQUARE PA +33AA;33AA;33AA;006B 0050 0061;006B 0050 0061; # (㎪; ㎪; ㎪; kPa; kPa; ) SQUARE KPA +33AB;33AB;33AB;004D 0050 0061;004D 0050 0061; # (㎫; ㎫; ㎫; MPa; MPa; ) SQUARE MPA +33AC;33AC;33AC;0047 0050 0061;0047 0050 0061; # (㎬; ㎬; ㎬; GPa; GPa; ) SQUARE GPA +33AD;33AD;33AD;0072 0061 0064;0072 0061 0064; # (㎭; ㎭; ㎭; rad; rad; ) SQUARE RAD +33AE;33AE;33AE;0072 0061 0064 2215 0073;0072 0061 0064 2215 0073; # (㎮; ㎮; ㎮; rad∕s; rad∕s; ) SQUARE RAD OVER S +33AF;33AF;33AF;0072 0061 0064 2215 0073 0032;0072 0061 0064 2215 0073 0032; # (㎯; ㎯; ㎯; rad∕s2; rad∕s2; ) SQUARE RAD OVER S SQUARED +33B0;33B0;33B0;0070 0073;0070 0073; # (㎰; ㎰; ㎰; ps; ps; ) SQUARE PS +33B1;33B1;33B1;006E 0073;006E 0073; # (㎱; ㎱; ㎱; ns; ns; ) SQUARE NS +33B2;33B2;33B2;03BC 0073;03BC 0073; # (㎲; ㎲; ㎲; μs; μs; ) SQUARE MU S +33B3;33B3;33B3;006D 0073;006D 0073; # (㎳; ㎳; ㎳; ms; ms; ) SQUARE MS +33B4;33B4;33B4;0070 0056;0070 0056; # (㎴; ㎴; ㎴; pV; pV; ) SQUARE PV +33B5;33B5;33B5;006E 0056;006E 0056; # (㎵; ㎵; ㎵; nV; nV; ) SQUARE NV +33B6;33B6;33B6;03BC 0056;03BC 0056; # (㎶; ㎶; ㎶; μV; μV; ) SQUARE MU V +33B7;33B7;33B7;006D 0056;006D 0056; # (㎷; ㎷; ㎷; mV; mV; ) SQUARE MV +33B8;33B8;33B8;006B 0056;006B 0056; # (㎸; ㎸; ㎸; kV; kV; ) SQUARE KV +33B9;33B9;33B9;004D 0056;004D 0056; # (㎹; ㎹; ㎹; MV; MV; ) SQUARE MV MEGA +33BA;33BA;33BA;0070 0057;0070 0057; # (㎺; ㎺; ㎺; pW; pW; ) SQUARE PW +33BB;33BB;33BB;006E 0057;006E 0057; # (㎻; ㎻; ㎻; nW; nW; ) SQUARE NW +33BC;33BC;33BC;03BC 0057;03BC 0057; # (㎼; ㎼; ㎼; μW; μW; ) SQUARE MU W +33BD;33BD;33BD;006D 0057;006D 0057; # (㎽; ㎽; ㎽; mW; mW; ) SQUARE MW +33BE;33BE;33BE;006B 0057;006B 0057; # (㎾; ㎾; ㎾; kW; kW; ) SQUARE KW +33BF;33BF;33BF;004D 0057;004D 0057; # (㎿; ㎿; ㎿; MW; MW; ) SQUARE MW MEGA +33C0;33C0;33C0;006B 03A9;006B 03A9; # (㏀; ㏀; ㏀; kΩ; kΩ; ) SQUARE K OHM +33C1;33C1;33C1;004D 03A9;004D 03A9; # (㏁; ㏁; ㏁; MΩ; MΩ; ) SQUARE M OHM +33C2;33C2;33C2;0061 002E 006D 002E;0061 002E 006D 002E; # (㏂; ㏂; ㏂; a.m.; a.m.; ) SQUARE AM +33C3;33C3;33C3;0042 0071;0042 0071; # (㏃; ㏃; ㏃; Bq; Bq; ) SQUARE BQ +33C4;33C4;33C4;0063 0063;0063 0063; # (㏄; ㏄; ㏄; cc; cc; ) SQUARE CC +33C5;33C5;33C5;0063 0064;0063 0064; # (㏅; ㏅; ㏅; cd; cd; ) SQUARE CD +33C6;33C6;33C6;0043 2215 006B 0067;0043 2215 006B 0067; # (㏆; ㏆; ㏆; C∕kg; C∕kg; ) SQUARE C OVER KG +33C7;33C7;33C7;0043 006F 002E;0043 006F 002E; # (㏇; ㏇; ㏇; Co.; Co.; ) SQUARE CO +33C8;33C8;33C8;0064 0042;0064 0042; # (㏈; ㏈; ㏈; dB; dB; ) SQUARE DB +33C9;33C9;33C9;0047 0079;0047 0079; # (㏉; ㏉; ㏉; Gy; Gy; ) SQUARE GY +33CA;33CA;33CA;0068 0061;0068 0061; # (㏊; ㏊; ㏊; ha; ha; ) SQUARE HA +33CB;33CB;33CB;0048 0050;0048 0050; # (㏋; ㏋; ㏋; HP; HP; ) SQUARE HP +33CC;33CC;33CC;0069 006E;0069 006E; # (㏌; ㏌; ㏌; in; in; ) SQUARE IN +33CD;33CD;33CD;004B 004B;004B 004B; # (㏍; ㏍; ㏍; KK; KK; ) SQUARE KK +33CE;33CE;33CE;004B 004D;004B 004D; # (㏎; ㏎; ㏎; KM; KM; ) SQUARE KM CAPITAL +33CF;33CF;33CF;006B 0074;006B 0074; # (㏏; ㏏; ㏏; kt; kt; ) SQUARE KT +33D0;33D0;33D0;006C 006D;006C 006D; # (㏐; ㏐; ㏐; lm; lm; ) SQUARE LM +33D1;33D1;33D1;006C 006E;006C 006E; # (㏑; ㏑; ㏑; ln; ln; ) SQUARE LN +33D2;33D2;33D2;006C 006F 0067;006C 006F 0067; # (㏒; ㏒; ㏒; log; log; ) SQUARE LOG +33D3;33D3;33D3;006C 0078;006C 0078; # (㏓; ㏓; ㏓; lx; lx; ) SQUARE LX +33D4;33D4;33D4;006D 0062;006D 0062; # (㏔; ㏔; ㏔; mb; mb; ) SQUARE MB SMALL +33D5;33D5;33D5;006D 0069 006C;006D 0069 006C; # (㏕; ㏕; ㏕; mil; mil; ) SQUARE MIL +33D6;33D6;33D6;006D 006F 006C;006D 006F 006C; # (㏖; ㏖; ㏖; mol; mol; ) SQUARE MOL +33D7;33D7;33D7;0050 0048;0050 0048; # (㏗; ㏗; ㏗; PH; PH; ) SQUARE PH +33D8;33D8;33D8;0070 002E 006D 002E;0070 002E 006D 002E; # (㏘; ㏘; ㏘; p.m.; p.m.; ) SQUARE PM +33D9;33D9;33D9;0050 0050 004D;0050 0050 004D; # (㏙; ㏙; ㏙; PPM; PPM; ) SQUARE PPM +33DA;33DA;33DA;0050 0052;0050 0052; # (㏚; ㏚; ㏚; PR; PR; ) SQUARE PR +33DB;33DB;33DB;0073 0072;0073 0072; # (㏛; ㏛; ㏛; sr; sr; ) SQUARE SR +33DC;33DC;33DC;0053 0076;0053 0076; # (㏜; ㏜; ㏜; Sv; Sv; ) SQUARE SV +33DD;33DD;33DD;0057 0062;0057 0062; # (㏝; ㏝; ㏝; Wb; Wb; ) SQUARE WB +33E0;33E0;33E0;0031 65E5;0031 65E5; # (㏠; ㏠; ㏠; 1日; 1日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE +33E1;33E1;33E1;0032 65E5;0032 65E5; # (㏡; ㏡; ㏡; 2日; 2日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO +33E2;33E2;33E2;0033 65E5;0033 65E5; # (㏢; ㏢; ㏢; 3日; 3日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE +33E3;33E3;33E3;0034 65E5;0034 65E5; # (㏣; ㏣; ㏣; 4日; 4日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR +33E4;33E4;33E4;0035 65E5;0035 65E5; # (㏤; ㏤; ㏤; 5日; 5日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE +33E5;33E5;33E5;0036 65E5;0036 65E5; # (㏥; ㏥; ㏥; 6日; 6日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX +33E6;33E6;33E6;0037 65E5;0037 65E5; # (㏦; ㏦; ㏦; 7日; 7日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN +33E7;33E7;33E7;0038 65E5;0038 65E5; # (㏧; ㏧; ㏧; 8日; 8日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT +33E8;33E8;33E8;0039 65E5;0039 65E5; # (㏨; ㏨; ㏨; 9日; 9日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE +33E9;33E9;33E9;0031 0030 65E5;0031 0030 65E5; # (㏩; ㏩; ㏩; 10日; 10日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN +33EA;33EA;33EA;0031 0031 65E5;0031 0031 65E5; # (㏪; ㏪; ㏪; 11日; 11日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN +33EB;33EB;33EB;0031 0032 65E5;0031 0032 65E5; # (㏫; ㏫; ㏫; 12日; 12日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE +33EC;33EC;33EC;0031 0033 65E5;0031 0033 65E5; # (㏬; ㏬; ㏬; 13日; 13日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN +33ED;33ED;33ED;0031 0034 65E5;0031 0034 65E5; # (㏭; ㏭; ㏭; 14日; 14日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN +33EE;33EE;33EE;0031 0035 65E5;0031 0035 65E5; # (㏮; ㏮; ㏮; 15日; 15日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN +33EF;33EF;33EF;0031 0036 65E5;0031 0036 65E5; # (㏯; ㏯; ㏯; 16日; 16日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN +33F0;33F0;33F0;0031 0037 65E5;0031 0037 65E5; # (㏰; ㏰; ㏰; 17日; 17日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN +33F1;33F1;33F1;0031 0038 65E5;0031 0038 65E5; # (㏱; ㏱; ㏱; 18日; 18日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN +33F2;33F2;33F2;0031 0039 65E5;0031 0039 65E5; # (㏲; ㏲; ㏲; 19日; 19日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN +33F3;33F3;33F3;0032 0030 65E5;0032 0030 65E5; # (㏳; ㏳; ㏳; 20日; 20日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY +33F4;33F4;33F4;0032 0031 65E5;0032 0031 65E5; # (㏴; ㏴; ㏴; 21日; 21日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE +33F5;33F5;33F5;0032 0032 65E5;0032 0032 65E5; # (㏵; ㏵; ㏵; 22日; 22日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO +33F6;33F6;33F6;0032 0033 65E5;0032 0033 65E5; # (㏶; ㏶; ㏶; 23日; 23日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE +33F7;33F7;33F7;0032 0034 65E5;0032 0034 65E5; # (㏷; ㏷; ㏷; 24日; 24日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR +33F8;33F8;33F8;0032 0035 65E5;0032 0035 65E5; # (㏸; ㏸; ㏸; 25日; 25日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE +33F9;33F9;33F9;0032 0036 65E5;0032 0036 65E5; # (㏹; ㏹; ㏹; 26日; 26日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX +33FA;33FA;33FA;0032 0037 65E5;0032 0037 65E5; # (㏺; ㏺; ㏺; 27日; 27日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN +33FB;33FB;33FB;0032 0038 65E5;0032 0038 65E5; # (㏻; ㏻; ㏻; 28日; 28日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT +33FC;33FC;33FC;0032 0039 65E5;0032 0039 65E5; # (㏼; ㏼; ㏼; 29日; 29日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE +33FD;33FD;33FD;0033 0030 65E5;0033 0030 65E5; # (㏽; ㏽; ㏽; 30日; 30日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY +33FE;33FE;33FE;0033 0031 65E5;0033 0031 65E5; # (㏾; ㏾; ㏾; 31日; 31日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE +AC00;AC00;1100 1161;AC00;1100 1161; # (가; 가; 가; 가; 가; ) HANGUL SYLLABLE GA +AC01;AC01;1100 1161 11A8;AC01;1100 1161 11A8; # (각; 각; 각; 각; 각; ) HANGUL SYLLABLE GAG +AC02;AC02;1100 1161 11A9;AC02;1100 1161 11A9; # (갂; 갂; 갂; 갂; 갂; ) HANGUL SYLLABLE GAGG +AC03;AC03;1100 1161 11AA;AC03;1100 1161 11AA; # (갃; 갃; 갃; 갃; 갃; ) HANGUL SYLLABLE GAGS +AC04;AC04;1100 1161 11AB;AC04;1100 1161 11AB; # (간; 간; 간; 간; 간; ) HANGUL SYLLABLE GAN +AC05;AC05;1100 1161 11AC;AC05;1100 1161 11AC; # (갅; 갅; 갅; 갅; 갅; ) HANGUL SYLLABLE GANJ +AC06;AC06;1100 1161 11AD;AC06;1100 1161 11AD; # (갆; 갆; 갆; 갆; 갆; ) HANGUL SYLLABLE GANH +AC07;AC07;1100 1161 11AE;AC07;1100 1161 11AE; # (갇; 갇; 갇; 갇; 갇; ) HANGUL SYLLABLE GAD +AC08;AC08;1100 1161 11AF;AC08;1100 1161 11AF; # (갈; 갈; 갈; 갈; 갈; ) HANGUL SYLLABLE GAL +AC09;AC09;1100 1161 11B0;AC09;1100 1161 11B0; # (갉; 갉; 갉; 갉; 갉; ) HANGUL SYLLABLE GALG +AC0A;AC0A;1100 1161 11B1;AC0A;1100 1161 11B1; # (갊; 갊; 갊; 갊; 갊; ) HANGUL SYLLABLE GALM +AC0B;AC0B;1100 1161 11B2;AC0B;1100 1161 11B2; # (갋; 갋; 갋; 갋; 갋; ) HANGUL SYLLABLE GALB +AC0C;AC0C;1100 1161 11B3;AC0C;1100 1161 11B3; # (갌; 갌; 갌; 갌; 갌; ) HANGUL SYLLABLE GALS +AC0D;AC0D;1100 1161 11B4;AC0D;1100 1161 11B4; # (갍; 갍; 갍; 갍; 갍; ) HANGUL SYLLABLE GALT +AC0E;AC0E;1100 1161 11B5;AC0E;1100 1161 11B5; # (갎; 갎; 갎; 갎; 갎; ) HANGUL SYLLABLE GALP +AC0F;AC0F;1100 1161 11B6;AC0F;1100 1161 11B6; # (갏; 갏; 갏; 갏; 갏; ) HANGUL SYLLABLE GALH +AC10;AC10;1100 1161 11B7;AC10;1100 1161 11B7; # (감; 감; 감; 감; 감; ) HANGUL SYLLABLE GAM +AC11;AC11;1100 1161 11B8;AC11;1100 1161 11B8; # (갑; 갑; 갑; 갑; 갑; ) HANGUL SYLLABLE GAB +AC12;AC12;1100 1161 11B9;AC12;1100 1161 11B9; # (값; 값; 값; 값; 값; ) HANGUL SYLLABLE GABS +AC13;AC13;1100 1161 11BA;AC13;1100 1161 11BA; # (갓; 갓; 갓; 갓; 갓; ) HANGUL SYLLABLE GAS +AC14;AC14;1100 1161 11BB;AC14;1100 1161 11BB; # (갔; 갔; 갔; 갔; 갔; ) HANGUL SYLLABLE GASS +AC15;AC15;1100 1161 11BC;AC15;1100 1161 11BC; # (강; 강; 강; 강; 강; ) HANGUL SYLLABLE GANG +AC16;AC16;1100 1161 11BD;AC16;1100 1161 11BD; # (갖; 갖; 갖; 갖; 갖; ) HANGUL SYLLABLE GAJ +AC17;AC17;1100 1161 11BE;AC17;1100 1161 11BE; # (갗; 갗; 갗; 갗; 갗; ) HANGUL SYLLABLE GAC +AC18;AC18;1100 1161 11BF;AC18;1100 1161 11BF; # (갘; 갘; 갘; 갘; 갘; ) HANGUL SYLLABLE GAK +AC19;AC19;1100 1161 11C0;AC19;1100 1161 11C0; # (같; 같; 같; 같; 같; ) HANGUL SYLLABLE GAT +AC1A;AC1A;1100 1161 11C1;AC1A;1100 1161 11C1; # (갚; 갚; 갚; 갚; 갚; ) HANGUL SYLLABLE GAP +AC1B;AC1B;1100 1161 11C2;AC1B;1100 1161 11C2; # (갛; 갛; 갛; 갛; 갛; ) HANGUL SYLLABLE GAH +AC1C;AC1C;1100 1162;AC1C;1100 1162; # (개; 개; 개; 개; 개; ) HANGUL SYLLABLE GAE +AC1D;AC1D;1100 1162 11A8;AC1D;1100 1162 11A8; # (객; 객; 객; 객; 객; ) HANGUL SYLLABLE GAEG +AC1E;AC1E;1100 1162 11A9;AC1E;1100 1162 11A9; # (갞; 갞; 갞; 갞; 갞; ) HANGUL SYLLABLE GAEGG +AC1F;AC1F;1100 1162 11AA;AC1F;1100 1162 11AA; # (갟; 갟; 갟; 갟; 갟; ) HANGUL SYLLABLE GAEGS +AC20;AC20;1100 1162 11AB;AC20;1100 1162 11AB; # (갠; 갠; 갠; 갠; 갠; ) HANGUL SYLLABLE GAEN +AC21;AC21;1100 1162 11AC;AC21;1100 1162 11AC; # (갡; 갡; 갡; 갡; 갡; ) HANGUL SYLLABLE GAENJ +AC22;AC22;1100 1162 11AD;AC22;1100 1162 11AD; # (갢; 갢; 갢; 갢; 갢; ) HANGUL SYLLABLE GAENH +AC23;AC23;1100 1162 11AE;AC23;1100 1162 11AE; # (갣; 갣; 갣; 갣; 갣; ) HANGUL SYLLABLE GAED +AC24;AC24;1100 1162 11AF;AC24;1100 1162 11AF; # (갤; 갤; 갤; 갤; 갤; ) HANGUL SYLLABLE GAEL +AC25;AC25;1100 1162 11B0;AC25;1100 1162 11B0; # (갥; 갥; 갥; 갥; 갥; ) HANGUL SYLLABLE GAELG +AC26;AC26;1100 1162 11B1;AC26;1100 1162 11B1; # (갦; 갦; 갦; 갦; 갦; ) HANGUL SYLLABLE GAELM +AC27;AC27;1100 1162 11B2;AC27;1100 1162 11B2; # (갧; 갧; 갧; 갧; 갧; ) HANGUL SYLLABLE GAELB +AC28;AC28;1100 1162 11B3;AC28;1100 1162 11B3; # (갨; 갨; 갨; 갨; 갨; ) HANGUL SYLLABLE GAELS +AC29;AC29;1100 1162 11B4;AC29;1100 1162 11B4; # (갩; 갩; 갩; 갩; 갩; ) HANGUL SYLLABLE GAELT +AC2A;AC2A;1100 1162 11B5;AC2A;1100 1162 11B5; # (갪; 갪; 갪; 갪; 갪; ) HANGUL SYLLABLE GAELP +AC2B;AC2B;1100 1162 11B6;AC2B;1100 1162 11B6; # (갫; 갫; 갫; 갫; 갫; ) HANGUL SYLLABLE GAELH +AC2C;AC2C;1100 1162 11B7;AC2C;1100 1162 11B7; # (갬; 갬; 갬; 갬; 갬; ) HANGUL SYLLABLE GAEM +AC2D;AC2D;1100 1162 11B8;AC2D;1100 1162 11B8; # (갭; 갭; 갭; 갭; 갭; ) HANGUL SYLLABLE GAEB +AC2E;AC2E;1100 1162 11B9;AC2E;1100 1162 11B9; # (갮; 갮; 갮; 갮; 갮; ) HANGUL SYLLABLE GAEBS +AC2F;AC2F;1100 1162 11BA;AC2F;1100 1162 11BA; # (갯; 갯; 갯; 갯; 갯; ) HANGUL SYLLABLE GAES +AC30;AC30;1100 1162 11BB;AC30;1100 1162 11BB; # (갰; 갰; 갰; 갰; 갰; ) HANGUL SYLLABLE GAESS +AC31;AC31;1100 1162 11BC;AC31;1100 1162 11BC; # (갱; 갱; 갱; 갱; 갱; ) HANGUL SYLLABLE GAENG +AC32;AC32;1100 1162 11BD;AC32;1100 1162 11BD; # (갲; 갲; 갲; 갲; 갲; ) HANGUL SYLLABLE GAEJ +AC33;AC33;1100 1162 11BE;AC33;1100 1162 11BE; # (갳; 갳; 갳; 갳; 갳; ) HANGUL SYLLABLE GAEC +AC34;AC34;1100 1162 11BF;AC34;1100 1162 11BF; # (갴; 갴; 갴; 갴; 갴; ) HANGUL SYLLABLE GAEK +AC35;AC35;1100 1162 11C0;AC35;1100 1162 11C0; # (갵; 갵; 갵; 갵; 갵; ) HANGUL SYLLABLE GAET +AC36;AC36;1100 1162 11C1;AC36;1100 1162 11C1; # (갶; 갶; 갶; 갶; 갶; ) HANGUL SYLLABLE GAEP +AC37;AC37;1100 1162 11C2;AC37;1100 1162 11C2; # (갷; 갷; 갷; 갷; 갷; ) HANGUL SYLLABLE GAEH +AC38;AC38;1100 1163;AC38;1100 1163; # (갸; 갸; 갸; 갸; 갸; ) HANGUL SYLLABLE GYA +AC39;AC39;1100 1163 11A8;AC39;1100 1163 11A8; # (갹; 갹; 갹; 갹; 갹; ) HANGUL SYLLABLE GYAG +AC3A;AC3A;1100 1163 11A9;AC3A;1100 1163 11A9; # (갺; 갺; 갺; 갺; 갺; ) HANGUL SYLLABLE GYAGG +AC3B;AC3B;1100 1163 11AA;AC3B;1100 1163 11AA; # (갻; 갻; 갻; 갻; 갻; ) HANGUL SYLLABLE GYAGS +AC3C;AC3C;1100 1163 11AB;AC3C;1100 1163 11AB; # (갼; 갼; 갼; 갼; 갼; ) HANGUL SYLLABLE GYAN +AC3D;AC3D;1100 1163 11AC;AC3D;1100 1163 11AC; # (갽; 갽; 갽; 갽; 갽; ) HANGUL SYLLABLE GYANJ +AC3E;AC3E;1100 1163 11AD;AC3E;1100 1163 11AD; # (갾; 갾; 갾; 갾; 갾; ) HANGUL SYLLABLE GYANH +AC3F;AC3F;1100 1163 11AE;AC3F;1100 1163 11AE; # (갿; 갿; 갿; 갿; 갿; ) HANGUL SYLLABLE GYAD +AC40;AC40;1100 1163 11AF;AC40;1100 1163 11AF; # (걀; 걀; 걀; 걀; 걀; ) HANGUL SYLLABLE GYAL +AC41;AC41;1100 1163 11B0;AC41;1100 1163 11B0; # (걁; 걁; 걁; 걁; 걁; ) HANGUL SYLLABLE GYALG +AC42;AC42;1100 1163 11B1;AC42;1100 1163 11B1; # (걂; 걂; 걂; 걂; 걂; ) HANGUL SYLLABLE GYALM +AC43;AC43;1100 1163 11B2;AC43;1100 1163 11B2; # (걃; 걃; 걃; 걃; 걃; ) HANGUL SYLLABLE GYALB +AC44;AC44;1100 1163 11B3;AC44;1100 1163 11B3; # (걄; 걄; 걄; 걄; 걄; ) HANGUL SYLLABLE GYALS +AC45;AC45;1100 1163 11B4;AC45;1100 1163 11B4; # (걅; 걅; 걅; 걅; 걅; ) HANGUL SYLLABLE GYALT +AC46;AC46;1100 1163 11B5;AC46;1100 1163 11B5; # (걆; 걆; 걆; 걆; 걆; ) HANGUL SYLLABLE GYALP +AC47;AC47;1100 1163 11B6;AC47;1100 1163 11B6; # (걇; 걇; 걇; 걇; 걇; ) HANGUL SYLLABLE GYALH +AC48;AC48;1100 1163 11B7;AC48;1100 1163 11B7; # (걈; 걈; 걈; 걈; 걈; ) HANGUL SYLLABLE GYAM +AC49;AC49;1100 1163 11B8;AC49;1100 1163 11B8; # (걉; 걉; 걉; 걉; 걉; ) HANGUL SYLLABLE GYAB +AC4A;AC4A;1100 1163 11B9;AC4A;1100 1163 11B9; # (걊; 걊; 걊; 걊; 걊; ) HANGUL SYLLABLE GYABS +AC4B;AC4B;1100 1163 11BA;AC4B;1100 1163 11BA; # (걋; 걋; 걋; 걋; 걋; ) HANGUL SYLLABLE GYAS +AC4C;AC4C;1100 1163 11BB;AC4C;1100 1163 11BB; # (걌; 걌; 걌; 걌; 걌; ) HANGUL SYLLABLE GYASS +AC4D;AC4D;1100 1163 11BC;AC4D;1100 1163 11BC; # (걍; 걍; 걍; 걍; 걍; ) HANGUL SYLLABLE GYANG +AC4E;AC4E;1100 1163 11BD;AC4E;1100 1163 11BD; # (걎; 걎; 걎; 걎; 걎; ) HANGUL SYLLABLE GYAJ +AC4F;AC4F;1100 1163 11BE;AC4F;1100 1163 11BE; # (걏; 걏; 걏; 걏; 걏; ) HANGUL SYLLABLE GYAC +AC50;AC50;1100 1163 11BF;AC50;1100 1163 11BF; # (걐; 걐; 걐; 걐; 걐; ) HANGUL SYLLABLE GYAK +AC51;AC51;1100 1163 11C0;AC51;1100 1163 11C0; # (걑; 걑; 걑; 걑; 걑; ) HANGUL SYLLABLE GYAT +AC52;AC52;1100 1163 11C1;AC52;1100 1163 11C1; # (걒; 걒; 걒; 걒; 걒; ) HANGUL SYLLABLE GYAP +AC53;AC53;1100 1163 11C2;AC53;1100 1163 11C2; # (걓; 걓; 걓; 걓; 걓; ) HANGUL SYLLABLE GYAH +AC54;AC54;1100 1164;AC54;1100 1164; # (걔; 걔; 걔; 걔; 걔; ) HANGUL SYLLABLE GYAE +AC55;AC55;1100 1164 11A8;AC55;1100 1164 11A8; # (걕; 걕; 걕; 걕; 걕; ) HANGUL SYLLABLE GYAEG +AC56;AC56;1100 1164 11A9;AC56;1100 1164 11A9; # (걖; 걖; 걖; 걖; 걖; ) HANGUL SYLLABLE GYAEGG +AC57;AC57;1100 1164 11AA;AC57;1100 1164 11AA; # (걗; 걗; 걗; 걗; 걗; ) HANGUL SYLLABLE GYAEGS +AC58;AC58;1100 1164 11AB;AC58;1100 1164 11AB; # (걘; 걘; 걘; 걘; 걘; ) HANGUL SYLLABLE GYAEN +AC59;AC59;1100 1164 11AC;AC59;1100 1164 11AC; # (걙; 걙; 걙; 걙; 걙; ) HANGUL SYLLABLE GYAENJ +AC5A;AC5A;1100 1164 11AD;AC5A;1100 1164 11AD; # (걚; 걚; 걚; 걚; 걚; ) HANGUL SYLLABLE GYAENH +AC5B;AC5B;1100 1164 11AE;AC5B;1100 1164 11AE; # (걛; 걛; 걛; 걛; 걛; ) HANGUL SYLLABLE GYAED +AC5C;AC5C;1100 1164 11AF;AC5C;1100 1164 11AF; # (걜; 걜; 걜; 걜; 걜; ) HANGUL SYLLABLE GYAEL +AC5D;AC5D;1100 1164 11B0;AC5D;1100 1164 11B0; # (걝; 걝; 걝; 걝; 걝; ) HANGUL SYLLABLE GYAELG +AC5E;AC5E;1100 1164 11B1;AC5E;1100 1164 11B1; # (걞; 걞; 걞; 걞; 걞; ) HANGUL SYLLABLE GYAELM +AC5F;AC5F;1100 1164 11B2;AC5F;1100 1164 11B2; # (걟; 걟; 걟; 걟; 걟; ) HANGUL SYLLABLE GYAELB +AC60;AC60;1100 1164 11B3;AC60;1100 1164 11B3; # (걠; 걠; 걠; 걠; 걠; ) HANGUL SYLLABLE GYAELS +AC61;AC61;1100 1164 11B4;AC61;1100 1164 11B4; # (걡; 걡; 걡; 걡; 걡; ) HANGUL SYLLABLE GYAELT +AC62;AC62;1100 1164 11B5;AC62;1100 1164 11B5; # (걢; 걢; 걢; 걢; 걢; ) HANGUL SYLLABLE GYAELP +AC63;AC63;1100 1164 11B6;AC63;1100 1164 11B6; # (걣; 걣; 걣; 걣; 걣; ) HANGUL SYLLABLE GYAELH +AC64;AC64;1100 1164 11B7;AC64;1100 1164 11B7; # (걤; 걤; 걤; 걤; 걤; ) HANGUL SYLLABLE GYAEM +AC65;AC65;1100 1164 11B8;AC65;1100 1164 11B8; # (걥; 걥; 걥; 걥; 걥; ) HANGUL SYLLABLE GYAEB +AC66;AC66;1100 1164 11B9;AC66;1100 1164 11B9; # (걦; 걦; 걦; 걦; 걦; ) HANGUL SYLLABLE GYAEBS +AC67;AC67;1100 1164 11BA;AC67;1100 1164 11BA; # (걧; 걧; 걧; 걧; 걧; ) HANGUL SYLLABLE GYAES +AC68;AC68;1100 1164 11BB;AC68;1100 1164 11BB; # (걨; 걨; 걨; 걨; 걨; ) HANGUL SYLLABLE GYAESS +AC69;AC69;1100 1164 11BC;AC69;1100 1164 11BC; # (걩; 걩; 걩; 걩; 걩; ) HANGUL SYLLABLE GYAENG +AC6A;AC6A;1100 1164 11BD;AC6A;1100 1164 11BD; # (걪; 걪; 걪; 걪; 걪; ) HANGUL SYLLABLE GYAEJ +AC6B;AC6B;1100 1164 11BE;AC6B;1100 1164 11BE; # (걫; 걫; 걫; 걫; 걫; ) HANGUL SYLLABLE GYAEC +AC6C;AC6C;1100 1164 11BF;AC6C;1100 1164 11BF; # (걬; 걬; 걬; 걬; 걬; ) HANGUL SYLLABLE GYAEK +AC6D;AC6D;1100 1164 11C0;AC6D;1100 1164 11C0; # (걭; 걭; 걭; 걭; 걭; ) HANGUL SYLLABLE GYAET +AC6E;AC6E;1100 1164 11C1;AC6E;1100 1164 11C1; # (걮; 걮; 걮; 걮; 걮; ) HANGUL SYLLABLE GYAEP +AC6F;AC6F;1100 1164 11C2;AC6F;1100 1164 11C2; # (걯; 걯; 걯; 걯; 걯; ) HANGUL SYLLABLE GYAEH +AC70;AC70;1100 1165;AC70;1100 1165; # (거; 거; 거; 거; 거; ) HANGUL SYLLABLE GEO +AC71;AC71;1100 1165 11A8;AC71;1100 1165 11A8; # (걱; 걱; 걱; 걱; 걱; ) HANGUL SYLLABLE GEOG +AC72;AC72;1100 1165 11A9;AC72;1100 1165 11A9; # (걲; 걲; 걲; 걲; 걲; ) HANGUL SYLLABLE GEOGG +AC73;AC73;1100 1165 11AA;AC73;1100 1165 11AA; # (걳; 걳; 걳; 걳; 걳; ) HANGUL SYLLABLE GEOGS +AC74;AC74;1100 1165 11AB;AC74;1100 1165 11AB; # (건; 건; 건; 건; 건; ) HANGUL SYLLABLE GEON +AC75;AC75;1100 1165 11AC;AC75;1100 1165 11AC; # (걵; 걵; 걵; 걵; 걵; ) HANGUL SYLLABLE GEONJ +AC76;AC76;1100 1165 11AD;AC76;1100 1165 11AD; # (걶; 걶; 걶; 걶; 걶; ) HANGUL SYLLABLE GEONH +AC77;AC77;1100 1165 11AE;AC77;1100 1165 11AE; # (걷; 걷; 걷; 걷; 걷; ) HANGUL SYLLABLE GEOD +AC78;AC78;1100 1165 11AF;AC78;1100 1165 11AF; # (걸; 걸; 걸; 걸; 걸; ) HANGUL SYLLABLE GEOL +AC79;AC79;1100 1165 11B0;AC79;1100 1165 11B0; # (걹; 걹; 걹; 걹; 걹; ) HANGUL SYLLABLE GEOLG +AC7A;AC7A;1100 1165 11B1;AC7A;1100 1165 11B1; # (걺; 걺; 걺; 걺; 걺; ) HANGUL SYLLABLE GEOLM +AC7B;AC7B;1100 1165 11B2;AC7B;1100 1165 11B2; # (걻; 걻; 걻; 걻; 걻; ) HANGUL SYLLABLE GEOLB +AC7C;AC7C;1100 1165 11B3;AC7C;1100 1165 11B3; # (걼; 걼; 걼; 걼; 걼; ) HANGUL SYLLABLE GEOLS +AC7D;AC7D;1100 1165 11B4;AC7D;1100 1165 11B4; # (걽; 걽; 걽; 걽; 걽; ) HANGUL SYLLABLE GEOLT +AC7E;AC7E;1100 1165 11B5;AC7E;1100 1165 11B5; # (걾; 걾; 걾; 걾; 걾; ) HANGUL SYLLABLE GEOLP +AC7F;AC7F;1100 1165 11B6;AC7F;1100 1165 11B6; # (걿; 걿; 걿; 걿; 걿; ) HANGUL SYLLABLE GEOLH +AC80;AC80;1100 1165 11B7;AC80;1100 1165 11B7; # (검; 검; 검; 검; 검; ) HANGUL SYLLABLE GEOM +AC81;AC81;1100 1165 11B8;AC81;1100 1165 11B8; # (겁; 겁; 겁; 겁; 겁; ) HANGUL SYLLABLE GEOB +AC82;AC82;1100 1165 11B9;AC82;1100 1165 11B9; # (겂; 겂; 겂; 겂; 겂; ) HANGUL SYLLABLE GEOBS +AC83;AC83;1100 1165 11BA;AC83;1100 1165 11BA; # (것; 것; 것; 것; 것; ) HANGUL SYLLABLE GEOS +AC84;AC84;1100 1165 11BB;AC84;1100 1165 11BB; # (겄; 겄; 겄; 겄; 겄; ) HANGUL SYLLABLE GEOSS +AC85;AC85;1100 1165 11BC;AC85;1100 1165 11BC; # (겅; 겅; 겅; 겅; 겅; ) HANGUL SYLLABLE GEONG +AC86;AC86;1100 1165 11BD;AC86;1100 1165 11BD; # (겆; 겆; 겆; 겆; 겆; ) HANGUL SYLLABLE GEOJ +AC87;AC87;1100 1165 11BE;AC87;1100 1165 11BE; # (겇; 겇; 겇; 겇; 겇; ) HANGUL SYLLABLE GEOC +AC88;AC88;1100 1165 11BF;AC88;1100 1165 11BF; # (겈; 겈; 겈; 겈; 겈; ) HANGUL SYLLABLE GEOK +AC89;AC89;1100 1165 11C0;AC89;1100 1165 11C0; # (겉; 겉; 겉; 겉; 겉; ) HANGUL SYLLABLE GEOT +AC8A;AC8A;1100 1165 11C1;AC8A;1100 1165 11C1; # (겊; 겊; 겊; 겊; 겊; ) HANGUL SYLLABLE GEOP +AC8B;AC8B;1100 1165 11C2;AC8B;1100 1165 11C2; # (겋; 겋; 겋; 겋; 겋; ) HANGUL SYLLABLE GEOH +AC8C;AC8C;1100 1166;AC8C;1100 1166; # (게; 게; 게; 게; 게; ) HANGUL SYLLABLE GE +AC8D;AC8D;1100 1166 11A8;AC8D;1100 1166 11A8; # (겍; 겍; 겍; 겍; 겍; ) HANGUL SYLLABLE GEG +AC8E;AC8E;1100 1166 11A9;AC8E;1100 1166 11A9; # (겎; 겎; 겎; 겎; 겎; ) HANGUL SYLLABLE GEGG +AC8F;AC8F;1100 1166 11AA;AC8F;1100 1166 11AA; # (겏; 겏; 겏; 겏; 겏; ) HANGUL SYLLABLE GEGS +AC90;AC90;1100 1166 11AB;AC90;1100 1166 11AB; # (겐; 겐; 겐; 겐; 겐; ) HANGUL SYLLABLE GEN +AC91;AC91;1100 1166 11AC;AC91;1100 1166 11AC; # (겑; 겑; 겑; 겑; 겑; ) HANGUL SYLLABLE GENJ +AC92;AC92;1100 1166 11AD;AC92;1100 1166 11AD; # (겒; 겒; 겒; 겒; 겒; ) HANGUL SYLLABLE GENH +AC93;AC93;1100 1166 11AE;AC93;1100 1166 11AE; # (겓; 겓; 겓; 겓; 겓; ) HANGUL SYLLABLE GED +AC94;AC94;1100 1166 11AF;AC94;1100 1166 11AF; # (겔; 겔; 겔; 겔; 겔; ) HANGUL SYLLABLE GEL +AC95;AC95;1100 1166 11B0;AC95;1100 1166 11B0; # (겕; 겕; 겕; 겕; 겕; ) HANGUL SYLLABLE GELG +AC96;AC96;1100 1166 11B1;AC96;1100 1166 11B1; # (겖; 겖; 겖; 겖; 겖; ) HANGUL SYLLABLE GELM +AC97;AC97;1100 1166 11B2;AC97;1100 1166 11B2; # (겗; 겗; 겗; 겗; 겗; ) HANGUL SYLLABLE GELB +AC98;AC98;1100 1166 11B3;AC98;1100 1166 11B3; # (겘; 겘; 겘; 겘; 겘; ) HANGUL SYLLABLE GELS +AC99;AC99;1100 1166 11B4;AC99;1100 1166 11B4; # (겙; 겙; 겙; 겙; 겙; ) HANGUL SYLLABLE GELT +AC9A;AC9A;1100 1166 11B5;AC9A;1100 1166 11B5; # (겚; 겚; 겚; 겚; 겚; ) HANGUL SYLLABLE GELP +AC9B;AC9B;1100 1166 11B6;AC9B;1100 1166 11B6; # (겛; 겛; 겛; 겛; 겛; ) HANGUL SYLLABLE GELH +AC9C;AC9C;1100 1166 11B7;AC9C;1100 1166 11B7; # (겜; 겜; 겜; 겜; 겜; ) HANGUL SYLLABLE GEM +AC9D;AC9D;1100 1166 11B8;AC9D;1100 1166 11B8; # (겝; 겝; 겝; 겝; 겝; ) HANGUL SYLLABLE GEB +AC9E;AC9E;1100 1166 11B9;AC9E;1100 1166 11B9; # (겞; 겞; 겞; 겞; 겞; ) HANGUL SYLLABLE GEBS +AC9F;AC9F;1100 1166 11BA;AC9F;1100 1166 11BA; # (겟; 겟; 겟; 겟; 겟; ) HANGUL SYLLABLE GES +ACA0;ACA0;1100 1166 11BB;ACA0;1100 1166 11BB; # (겠; 겠; 겠; 겠; 겠; ) HANGUL SYLLABLE GESS +ACA1;ACA1;1100 1166 11BC;ACA1;1100 1166 11BC; # (겡; 겡; 겡; 겡; 겡; ) HANGUL SYLLABLE GENG +ACA2;ACA2;1100 1166 11BD;ACA2;1100 1166 11BD; # (겢; 겢; 겢; 겢; 겢; ) HANGUL SYLLABLE GEJ +ACA3;ACA3;1100 1166 11BE;ACA3;1100 1166 11BE; # (겣; 겣; 겣; 겣; 겣; ) HANGUL SYLLABLE GEC +ACA4;ACA4;1100 1166 11BF;ACA4;1100 1166 11BF; # (겤; 겤; 겤; 겤; 겤; ) HANGUL SYLLABLE GEK +ACA5;ACA5;1100 1166 11C0;ACA5;1100 1166 11C0; # (겥; 겥; 겥; 겥; 겥; ) HANGUL SYLLABLE GET +ACA6;ACA6;1100 1166 11C1;ACA6;1100 1166 11C1; # (겦; 겦; 겦; 겦; 겦; ) HANGUL SYLLABLE GEP +ACA7;ACA7;1100 1166 11C2;ACA7;1100 1166 11C2; # (겧; 겧; 겧; 겧; 겧; ) HANGUL SYLLABLE GEH +ACA8;ACA8;1100 1167;ACA8;1100 1167; # (겨; 겨; 겨; 겨; 겨; ) HANGUL SYLLABLE GYEO +ACA9;ACA9;1100 1167 11A8;ACA9;1100 1167 11A8; # (격; 격; 격; 격; 격; ) HANGUL SYLLABLE GYEOG +ACAA;ACAA;1100 1167 11A9;ACAA;1100 1167 11A9; # (겪; 겪; 겪; 겪; 겪; ) HANGUL SYLLABLE GYEOGG +ACAB;ACAB;1100 1167 11AA;ACAB;1100 1167 11AA; # (겫; 겫; 겫; 겫; 겫; ) HANGUL SYLLABLE GYEOGS +ACAC;ACAC;1100 1167 11AB;ACAC;1100 1167 11AB; # (견; 견; 견; 견; 견; ) HANGUL SYLLABLE GYEON +ACAD;ACAD;1100 1167 11AC;ACAD;1100 1167 11AC; # (겭; 겭; 겭; 겭; 겭; ) HANGUL SYLLABLE GYEONJ +ACAE;ACAE;1100 1167 11AD;ACAE;1100 1167 11AD; # (겮; 겮; 겮; 겮; 겮; ) HANGUL SYLLABLE GYEONH +ACAF;ACAF;1100 1167 11AE;ACAF;1100 1167 11AE; # (겯; 겯; 겯; 겯; 겯; ) HANGUL SYLLABLE GYEOD +ACB0;ACB0;1100 1167 11AF;ACB0;1100 1167 11AF; # (결; 결; 결; 결; 결; ) HANGUL SYLLABLE GYEOL +ACB1;ACB1;1100 1167 11B0;ACB1;1100 1167 11B0; # (겱; 겱; 겱; 겱; 겱; ) HANGUL SYLLABLE GYEOLG +ACB2;ACB2;1100 1167 11B1;ACB2;1100 1167 11B1; # (겲; 겲; 겲; 겲; 겲; ) HANGUL SYLLABLE GYEOLM +ACB3;ACB3;1100 1167 11B2;ACB3;1100 1167 11B2; # (겳; 겳; 겳; 겳; 겳; ) HANGUL SYLLABLE GYEOLB +ACB4;ACB4;1100 1167 11B3;ACB4;1100 1167 11B3; # (겴; 겴; 겴; 겴; 겴; ) HANGUL SYLLABLE GYEOLS +ACB5;ACB5;1100 1167 11B4;ACB5;1100 1167 11B4; # (겵; 겵; 겵; 겵; 겵; ) HANGUL SYLLABLE GYEOLT +ACB6;ACB6;1100 1167 11B5;ACB6;1100 1167 11B5; # (겶; 겶; 겶; 겶; 겶; ) HANGUL SYLLABLE GYEOLP +ACB7;ACB7;1100 1167 11B6;ACB7;1100 1167 11B6; # (겷; 겷; 겷; 겷; 겷; ) HANGUL SYLLABLE GYEOLH +ACB8;ACB8;1100 1167 11B7;ACB8;1100 1167 11B7; # (겸; 겸; 겸; 겸; 겸; ) HANGUL SYLLABLE GYEOM +ACB9;ACB9;1100 1167 11B8;ACB9;1100 1167 11B8; # (겹; 겹; 겹; 겹; 겹; ) HANGUL SYLLABLE GYEOB +ACBA;ACBA;1100 1167 11B9;ACBA;1100 1167 11B9; # (겺; 겺; 겺; 겺; 겺; ) HANGUL SYLLABLE GYEOBS +ACBB;ACBB;1100 1167 11BA;ACBB;1100 1167 11BA; # (겻; 겻; 겻; 겻; 겻; ) HANGUL SYLLABLE GYEOS +ACBC;ACBC;1100 1167 11BB;ACBC;1100 1167 11BB; # (겼; 겼; 겼; 겼; 겼; ) HANGUL SYLLABLE GYEOSS +ACBD;ACBD;1100 1167 11BC;ACBD;1100 1167 11BC; # (경; 경; 경; 경; 경; ) HANGUL SYLLABLE GYEONG +ACBE;ACBE;1100 1167 11BD;ACBE;1100 1167 11BD; # (겾; 겾; 겾; 겾; 겾; ) HANGUL SYLLABLE GYEOJ +ACBF;ACBF;1100 1167 11BE;ACBF;1100 1167 11BE; # (겿; 겿; 겿; 겿; 겿; ) HANGUL SYLLABLE GYEOC +ACC0;ACC0;1100 1167 11BF;ACC0;1100 1167 11BF; # (곀; 곀; 곀; 곀; 곀; ) HANGUL SYLLABLE GYEOK +ACC1;ACC1;1100 1167 11C0;ACC1;1100 1167 11C0; # (곁; 곁; 곁; 곁; 곁; ) HANGUL SYLLABLE GYEOT +ACC2;ACC2;1100 1167 11C1;ACC2;1100 1167 11C1; # (곂; 곂; 곂; 곂; 곂; ) HANGUL SYLLABLE GYEOP +ACC3;ACC3;1100 1167 11C2;ACC3;1100 1167 11C2; # (곃; 곃; 곃; 곃; 곃; ) HANGUL SYLLABLE GYEOH +ACC4;ACC4;1100 1168;ACC4;1100 1168; # (계; 계; 계; 계; 계; ) HANGUL SYLLABLE GYE +ACC5;ACC5;1100 1168 11A8;ACC5;1100 1168 11A8; # (곅; 곅; 곅; 곅; 곅; ) HANGUL SYLLABLE GYEG +ACC6;ACC6;1100 1168 11A9;ACC6;1100 1168 11A9; # (곆; 곆; 곆; 곆; 곆; ) HANGUL SYLLABLE GYEGG +ACC7;ACC7;1100 1168 11AA;ACC7;1100 1168 11AA; # (곇; 곇; 곇; 곇; 곇; ) HANGUL SYLLABLE GYEGS +ACC8;ACC8;1100 1168 11AB;ACC8;1100 1168 11AB; # (곈; 곈; 곈; 곈; 곈; ) HANGUL SYLLABLE GYEN +ACC9;ACC9;1100 1168 11AC;ACC9;1100 1168 11AC; # (곉; 곉; 곉; 곉; 곉; ) HANGUL SYLLABLE GYENJ +ACCA;ACCA;1100 1168 11AD;ACCA;1100 1168 11AD; # (곊; 곊; 곊; 곊; 곊; ) HANGUL SYLLABLE GYENH +ACCB;ACCB;1100 1168 11AE;ACCB;1100 1168 11AE; # (곋; 곋; 곋; 곋; 곋; ) HANGUL SYLLABLE GYED +ACCC;ACCC;1100 1168 11AF;ACCC;1100 1168 11AF; # (곌; 곌; 곌; 곌; 곌; ) HANGUL SYLLABLE GYEL +ACCD;ACCD;1100 1168 11B0;ACCD;1100 1168 11B0; # (곍; 곍; 곍; 곍; 곍; ) HANGUL SYLLABLE GYELG +ACCE;ACCE;1100 1168 11B1;ACCE;1100 1168 11B1; # (곎; 곎; 곎; 곎; 곎; ) HANGUL SYLLABLE GYELM +ACCF;ACCF;1100 1168 11B2;ACCF;1100 1168 11B2; # (곏; 곏; 곏; 곏; 곏; ) HANGUL SYLLABLE GYELB +ACD0;ACD0;1100 1168 11B3;ACD0;1100 1168 11B3; # (곐; 곐; 곐; 곐; 곐; ) HANGUL SYLLABLE GYELS +ACD1;ACD1;1100 1168 11B4;ACD1;1100 1168 11B4; # (곑; 곑; 곑; 곑; 곑; ) HANGUL SYLLABLE GYELT +ACD2;ACD2;1100 1168 11B5;ACD2;1100 1168 11B5; # (곒; 곒; 곒; 곒; 곒; ) HANGUL SYLLABLE GYELP +ACD3;ACD3;1100 1168 11B6;ACD3;1100 1168 11B6; # (곓; 곓; 곓; 곓; 곓; ) HANGUL SYLLABLE GYELH +ACD4;ACD4;1100 1168 11B7;ACD4;1100 1168 11B7; # (곔; 곔; 곔; 곔; 곔; ) HANGUL SYLLABLE GYEM +ACD5;ACD5;1100 1168 11B8;ACD5;1100 1168 11B8; # (곕; 곕; 곕; 곕; 곕; ) HANGUL SYLLABLE GYEB +ACD6;ACD6;1100 1168 11B9;ACD6;1100 1168 11B9; # (곖; 곖; 곖; 곖; 곖; ) HANGUL SYLLABLE GYEBS +ACD7;ACD7;1100 1168 11BA;ACD7;1100 1168 11BA; # (곗; 곗; 곗; 곗; 곗; ) HANGUL SYLLABLE GYES +ACD8;ACD8;1100 1168 11BB;ACD8;1100 1168 11BB; # (곘; 곘; 곘; 곘; 곘; ) HANGUL SYLLABLE GYESS +ACD9;ACD9;1100 1168 11BC;ACD9;1100 1168 11BC; # (곙; 곙; 곙; 곙; 곙; ) HANGUL SYLLABLE GYENG +ACDA;ACDA;1100 1168 11BD;ACDA;1100 1168 11BD; # (곚; 곚; 곚; 곚; 곚; ) HANGUL SYLLABLE GYEJ +ACDB;ACDB;1100 1168 11BE;ACDB;1100 1168 11BE; # (곛; 곛; 곛; 곛; 곛; ) HANGUL SYLLABLE GYEC +ACDC;ACDC;1100 1168 11BF;ACDC;1100 1168 11BF; # (곜; 곜; 곜; 곜; 곜; ) HANGUL SYLLABLE GYEK +ACDD;ACDD;1100 1168 11C0;ACDD;1100 1168 11C0; # (곝; 곝; 곝; 곝; 곝; ) HANGUL SYLLABLE GYET +ACDE;ACDE;1100 1168 11C1;ACDE;1100 1168 11C1; # (곞; 곞; 곞; 곞; 곞; ) HANGUL SYLLABLE GYEP +ACDF;ACDF;1100 1168 11C2;ACDF;1100 1168 11C2; # (곟; 곟; 곟; 곟; 곟; ) HANGUL SYLLABLE GYEH +ACE0;ACE0;1100 1169;ACE0;1100 1169; # (고; 고; 고; 고; 고; ) HANGUL SYLLABLE GO +ACE1;ACE1;1100 1169 11A8;ACE1;1100 1169 11A8; # (곡; 곡; 곡; 곡; 곡; ) HANGUL SYLLABLE GOG +ACE2;ACE2;1100 1169 11A9;ACE2;1100 1169 11A9; # (곢; 곢; 곢; 곢; 곢; ) HANGUL SYLLABLE GOGG +ACE3;ACE3;1100 1169 11AA;ACE3;1100 1169 11AA; # (곣; 곣; 곣; 곣; 곣; ) HANGUL SYLLABLE GOGS +ACE4;ACE4;1100 1169 11AB;ACE4;1100 1169 11AB; # (곤; 곤; 곤; 곤; 곤; ) HANGUL SYLLABLE GON +ACE5;ACE5;1100 1169 11AC;ACE5;1100 1169 11AC; # (곥; 곥; 곥; 곥; 곥; ) HANGUL SYLLABLE GONJ +ACE6;ACE6;1100 1169 11AD;ACE6;1100 1169 11AD; # (곦; 곦; 곦; 곦; 곦; ) HANGUL SYLLABLE GONH +ACE7;ACE7;1100 1169 11AE;ACE7;1100 1169 11AE; # (곧; 곧; 곧; 곧; 곧; ) HANGUL SYLLABLE GOD +ACE8;ACE8;1100 1169 11AF;ACE8;1100 1169 11AF; # (골; 골; 골; 골; 골; ) HANGUL SYLLABLE GOL +ACE9;ACE9;1100 1169 11B0;ACE9;1100 1169 11B0; # (곩; 곩; 곩; 곩; 곩; ) HANGUL SYLLABLE GOLG +ACEA;ACEA;1100 1169 11B1;ACEA;1100 1169 11B1; # (곪; 곪; 곪; 곪; 곪; ) HANGUL SYLLABLE GOLM +ACEB;ACEB;1100 1169 11B2;ACEB;1100 1169 11B2; # (곫; 곫; 곫; 곫; 곫; ) HANGUL SYLLABLE GOLB +ACEC;ACEC;1100 1169 11B3;ACEC;1100 1169 11B3; # (곬; 곬; 곬; 곬; 곬; ) HANGUL SYLLABLE GOLS +ACED;ACED;1100 1169 11B4;ACED;1100 1169 11B4; # (곭; 곭; 곭; 곭; 곭; ) HANGUL SYLLABLE GOLT +ACEE;ACEE;1100 1169 11B5;ACEE;1100 1169 11B5; # (곮; 곮; 곮; 곮; 곮; ) HANGUL SYLLABLE GOLP +ACEF;ACEF;1100 1169 11B6;ACEF;1100 1169 11B6; # (곯; 곯; 곯; 곯; 곯; ) HANGUL SYLLABLE GOLH +ACF0;ACF0;1100 1169 11B7;ACF0;1100 1169 11B7; # (곰; 곰; 곰; 곰; 곰; ) HANGUL SYLLABLE GOM +ACF1;ACF1;1100 1169 11B8;ACF1;1100 1169 11B8; # (곱; 곱; 곱; 곱; 곱; ) HANGUL SYLLABLE GOB +ACF2;ACF2;1100 1169 11B9;ACF2;1100 1169 11B9; # (곲; 곲; 곲; 곲; 곲; ) HANGUL SYLLABLE GOBS +ACF3;ACF3;1100 1169 11BA;ACF3;1100 1169 11BA; # (곳; 곳; 곳; 곳; 곳; ) HANGUL SYLLABLE GOS +ACF4;ACF4;1100 1169 11BB;ACF4;1100 1169 11BB; # (곴; 곴; 곴; 곴; 곴; ) HANGUL SYLLABLE GOSS +ACF5;ACF5;1100 1169 11BC;ACF5;1100 1169 11BC; # (공; 공; 공; 공; 공; ) HANGUL SYLLABLE GONG +ACF6;ACF6;1100 1169 11BD;ACF6;1100 1169 11BD; # (곶; 곶; 곶; 곶; 곶; ) HANGUL SYLLABLE GOJ +ACF7;ACF7;1100 1169 11BE;ACF7;1100 1169 11BE; # (곷; 곷; 곷; 곷; 곷; ) HANGUL SYLLABLE GOC +ACF8;ACF8;1100 1169 11BF;ACF8;1100 1169 11BF; # (곸; 곸; 곸; 곸; 곸; ) HANGUL SYLLABLE GOK +ACF9;ACF9;1100 1169 11C0;ACF9;1100 1169 11C0; # (곹; 곹; 곹; 곹; 곹; ) HANGUL SYLLABLE GOT +ACFA;ACFA;1100 1169 11C1;ACFA;1100 1169 11C1; # (곺; 곺; 곺; 곺; 곺; ) HANGUL SYLLABLE GOP +ACFB;ACFB;1100 1169 11C2;ACFB;1100 1169 11C2; # (곻; 곻; 곻; 곻; 곻; ) HANGUL SYLLABLE GOH +ACFC;ACFC;1100 116A;ACFC;1100 116A; # (과; 과; 과; 과; 과; ) HANGUL SYLLABLE GWA +ACFD;ACFD;1100 116A 11A8;ACFD;1100 116A 11A8; # (곽; 곽; 곽; 곽; 곽; ) HANGUL SYLLABLE GWAG +ACFE;ACFE;1100 116A 11A9;ACFE;1100 116A 11A9; # (곾; 곾; 곾; 곾; 곾; ) HANGUL SYLLABLE GWAGG +ACFF;ACFF;1100 116A 11AA;ACFF;1100 116A 11AA; # (곿; 곿; 곿; 곿; 곿; ) HANGUL SYLLABLE GWAGS +AD00;AD00;1100 116A 11AB;AD00;1100 116A 11AB; # (관; 관; 관; 관; 관; ) HANGUL SYLLABLE GWAN +AD01;AD01;1100 116A 11AC;AD01;1100 116A 11AC; # (괁; 괁; 괁; 괁; 괁; ) HANGUL SYLLABLE GWANJ +AD02;AD02;1100 116A 11AD;AD02;1100 116A 11AD; # (괂; 괂; 괂; 괂; 괂; ) HANGUL SYLLABLE GWANH +AD03;AD03;1100 116A 11AE;AD03;1100 116A 11AE; # (괃; 괃; 괃; 괃; 괃; ) HANGUL SYLLABLE GWAD +AD04;AD04;1100 116A 11AF;AD04;1100 116A 11AF; # (괄; 괄; 괄; 괄; 괄; ) HANGUL SYLLABLE GWAL +AD05;AD05;1100 116A 11B0;AD05;1100 116A 11B0; # (괅; 괅; 괅; 괅; 괅; ) HANGUL SYLLABLE GWALG +AD06;AD06;1100 116A 11B1;AD06;1100 116A 11B1; # (괆; 괆; 괆; 괆; 괆; ) HANGUL SYLLABLE GWALM +AD07;AD07;1100 116A 11B2;AD07;1100 116A 11B2; # (괇; 괇; 괇; 괇; 괇; ) HANGUL SYLLABLE GWALB +AD08;AD08;1100 116A 11B3;AD08;1100 116A 11B3; # (괈; 괈; 괈; 괈; 괈; ) HANGUL SYLLABLE GWALS +AD09;AD09;1100 116A 11B4;AD09;1100 116A 11B4; # (괉; 괉; 괉; 괉; 괉; ) HANGUL SYLLABLE GWALT +AD0A;AD0A;1100 116A 11B5;AD0A;1100 116A 11B5; # (괊; 괊; 괊; 괊; 괊; ) HANGUL SYLLABLE GWALP +AD0B;AD0B;1100 116A 11B6;AD0B;1100 116A 11B6; # (괋; 괋; 괋; 괋; 괋; ) HANGUL SYLLABLE GWALH +AD0C;AD0C;1100 116A 11B7;AD0C;1100 116A 11B7; # (괌; 괌; 괌; 괌; 괌; ) HANGUL SYLLABLE GWAM +AD0D;AD0D;1100 116A 11B8;AD0D;1100 116A 11B8; # (괍; 괍; 괍; 괍; 괍; ) HANGUL SYLLABLE GWAB +AD0E;AD0E;1100 116A 11B9;AD0E;1100 116A 11B9; # (괎; 괎; 괎; 괎; 괎; ) HANGUL SYLLABLE GWABS +AD0F;AD0F;1100 116A 11BA;AD0F;1100 116A 11BA; # (괏; 괏; 괏; 괏; 괏; ) HANGUL SYLLABLE GWAS +AD10;AD10;1100 116A 11BB;AD10;1100 116A 11BB; # (괐; 괐; 괐; 괐; 괐; ) HANGUL SYLLABLE GWASS +AD11;AD11;1100 116A 11BC;AD11;1100 116A 11BC; # (광; 광; 광; 광; 광; ) HANGUL SYLLABLE GWANG +AD12;AD12;1100 116A 11BD;AD12;1100 116A 11BD; # (괒; 괒; 괒; 괒; 괒; ) HANGUL SYLLABLE GWAJ +AD13;AD13;1100 116A 11BE;AD13;1100 116A 11BE; # (괓; 괓; 괓; 괓; 괓; ) HANGUL SYLLABLE GWAC +AD14;AD14;1100 116A 11BF;AD14;1100 116A 11BF; # (괔; 괔; 괔; 괔; 괔; ) HANGUL SYLLABLE GWAK +AD15;AD15;1100 116A 11C0;AD15;1100 116A 11C0; # (괕; 괕; 괕; 괕; 괕; ) HANGUL SYLLABLE GWAT +AD16;AD16;1100 116A 11C1;AD16;1100 116A 11C1; # (괖; 괖; 괖; 괖; 괖; ) HANGUL SYLLABLE GWAP +AD17;AD17;1100 116A 11C2;AD17;1100 116A 11C2; # (괗; 괗; 괗; 괗; 괗; ) HANGUL SYLLABLE GWAH +AD18;AD18;1100 116B;AD18;1100 116B; # (괘; 괘; 괘; 괘; 괘; ) HANGUL SYLLABLE GWAE +AD19;AD19;1100 116B 11A8;AD19;1100 116B 11A8; # (괙; 괙; 괙; 괙; 괙; ) HANGUL SYLLABLE GWAEG +AD1A;AD1A;1100 116B 11A9;AD1A;1100 116B 11A9; # (괚; 괚; 괚; 괚; 괚; ) HANGUL SYLLABLE GWAEGG +AD1B;AD1B;1100 116B 11AA;AD1B;1100 116B 11AA; # (괛; 괛; 괛; 괛; 괛; ) HANGUL SYLLABLE GWAEGS +AD1C;AD1C;1100 116B 11AB;AD1C;1100 116B 11AB; # (괜; 괜; 괜; 괜; 괜; ) HANGUL SYLLABLE GWAEN +AD1D;AD1D;1100 116B 11AC;AD1D;1100 116B 11AC; # (괝; 괝; 괝; 괝; 괝; ) HANGUL SYLLABLE GWAENJ +AD1E;AD1E;1100 116B 11AD;AD1E;1100 116B 11AD; # (괞; 괞; 괞; 괞; 괞; ) HANGUL SYLLABLE GWAENH +AD1F;AD1F;1100 116B 11AE;AD1F;1100 116B 11AE; # (괟; 괟; 괟; 괟; 괟; ) HANGUL SYLLABLE GWAED +AD20;AD20;1100 116B 11AF;AD20;1100 116B 11AF; # (괠; 괠; 괠; 괠; 괠; ) HANGUL SYLLABLE GWAEL +AD21;AD21;1100 116B 11B0;AD21;1100 116B 11B0; # (괡; 괡; 괡; 괡; 괡; ) HANGUL SYLLABLE GWAELG +AD22;AD22;1100 116B 11B1;AD22;1100 116B 11B1; # (괢; 괢; 괢; 괢; 괢; ) HANGUL SYLLABLE GWAELM +AD23;AD23;1100 116B 11B2;AD23;1100 116B 11B2; # (괣; 괣; 괣; 괣; 괣; ) HANGUL SYLLABLE GWAELB +AD24;AD24;1100 116B 11B3;AD24;1100 116B 11B3; # (괤; 괤; 괤; 괤; 괤; ) HANGUL SYLLABLE GWAELS +AD25;AD25;1100 116B 11B4;AD25;1100 116B 11B4; # (괥; 괥; 괥; 괥; 괥; ) HANGUL SYLLABLE GWAELT +AD26;AD26;1100 116B 11B5;AD26;1100 116B 11B5; # (괦; 괦; 괦; 괦; 괦; ) HANGUL SYLLABLE GWAELP +AD27;AD27;1100 116B 11B6;AD27;1100 116B 11B6; # (괧; 괧; 괧; 괧; 괧; ) HANGUL SYLLABLE GWAELH +AD28;AD28;1100 116B 11B7;AD28;1100 116B 11B7; # (괨; 괨; 괨; 괨; 괨; ) HANGUL SYLLABLE GWAEM +AD29;AD29;1100 116B 11B8;AD29;1100 116B 11B8; # (괩; 괩; 괩; 괩; 괩; ) HANGUL SYLLABLE GWAEB +AD2A;AD2A;1100 116B 11B9;AD2A;1100 116B 11B9; # (괪; 괪; 괪; 괪; 괪; ) HANGUL SYLLABLE GWAEBS +AD2B;AD2B;1100 116B 11BA;AD2B;1100 116B 11BA; # (괫; 괫; 괫; 괫; 괫; ) HANGUL SYLLABLE GWAES +AD2C;AD2C;1100 116B 11BB;AD2C;1100 116B 11BB; # (괬; 괬; 괬; 괬; 괬; ) HANGUL SYLLABLE GWAESS +AD2D;AD2D;1100 116B 11BC;AD2D;1100 116B 11BC; # (괭; 괭; 괭; 괭; 괭; ) HANGUL SYLLABLE GWAENG +AD2E;AD2E;1100 116B 11BD;AD2E;1100 116B 11BD; # (괮; 괮; 괮; 괮; 괮; ) HANGUL SYLLABLE GWAEJ +AD2F;AD2F;1100 116B 11BE;AD2F;1100 116B 11BE; # (괯; 괯; 괯; 괯; 괯; ) HANGUL SYLLABLE GWAEC +AD30;AD30;1100 116B 11BF;AD30;1100 116B 11BF; # (괰; 괰; 괰; 괰; 괰; ) HANGUL SYLLABLE GWAEK +AD31;AD31;1100 116B 11C0;AD31;1100 116B 11C0; # (괱; 괱; 괱; 괱; 괱; ) HANGUL SYLLABLE GWAET +AD32;AD32;1100 116B 11C1;AD32;1100 116B 11C1; # (괲; 괲; 괲; 괲; 괲; ) HANGUL SYLLABLE GWAEP +AD33;AD33;1100 116B 11C2;AD33;1100 116B 11C2; # (괳; 괳; 괳; 괳; 괳; ) HANGUL SYLLABLE GWAEH +AD34;AD34;1100 116C;AD34;1100 116C; # (괴; 괴; 괴; 괴; 괴; ) HANGUL SYLLABLE GOE +AD35;AD35;1100 116C 11A8;AD35;1100 116C 11A8; # (괵; 괵; 괵; 괵; 괵; ) HANGUL SYLLABLE GOEG +AD36;AD36;1100 116C 11A9;AD36;1100 116C 11A9; # (괶; 괶; 괶; 괶; 괶; ) HANGUL SYLLABLE GOEGG +AD37;AD37;1100 116C 11AA;AD37;1100 116C 11AA; # (괷; 괷; 괷; 괷; 괷; ) HANGUL SYLLABLE GOEGS +AD38;AD38;1100 116C 11AB;AD38;1100 116C 11AB; # (괸; 괸; 괸; 괸; 괸; ) HANGUL SYLLABLE GOEN +AD39;AD39;1100 116C 11AC;AD39;1100 116C 11AC; # (괹; 괹; 괹; 괹; 괹; ) HANGUL SYLLABLE GOENJ +AD3A;AD3A;1100 116C 11AD;AD3A;1100 116C 11AD; # (괺; 괺; 괺; 괺; 괺; ) HANGUL SYLLABLE GOENH +AD3B;AD3B;1100 116C 11AE;AD3B;1100 116C 11AE; # (괻; 괻; 괻; 괻; 괻; ) HANGUL SYLLABLE GOED +AD3C;AD3C;1100 116C 11AF;AD3C;1100 116C 11AF; # (괼; 괼; 괼; 괼; 괼; ) HANGUL SYLLABLE GOEL +AD3D;AD3D;1100 116C 11B0;AD3D;1100 116C 11B0; # (괽; 괽; 괽; 괽; 괽; ) HANGUL SYLLABLE GOELG +AD3E;AD3E;1100 116C 11B1;AD3E;1100 116C 11B1; # (괾; 괾; 괾; 괾; 괾; ) HANGUL SYLLABLE GOELM +AD3F;AD3F;1100 116C 11B2;AD3F;1100 116C 11B2; # (괿; 괿; 괿; 괿; 괿; ) HANGUL SYLLABLE GOELB +AD40;AD40;1100 116C 11B3;AD40;1100 116C 11B3; # (굀; 굀; 굀; 굀; 굀; ) HANGUL SYLLABLE GOELS +AD41;AD41;1100 116C 11B4;AD41;1100 116C 11B4; # (굁; 굁; 굁; 굁; 굁; ) HANGUL SYLLABLE GOELT +AD42;AD42;1100 116C 11B5;AD42;1100 116C 11B5; # (굂; 굂; 굂; 굂; 굂; ) HANGUL SYLLABLE GOELP +AD43;AD43;1100 116C 11B6;AD43;1100 116C 11B6; # (굃; 굃; 굃; 굃; 굃; ) HANGUL SYLLABLE GOELH +AD44;AD44;1100 116C 11B7;AD44;1100 116C 11B7; # (굄; 굄; 굄; 굄; 굄; ) HANGUL SYLLABLE GOEM +AD45;AD45;1100 116C 11B8;AD45;1100 116C 11B8; # (굅; 굅; 굅; 굅; 굅; ) HANGUL SYLLABLE GOEB +AD46;AD46;1100 116C 11B9;AD46;1100 116C 11B9; # (굆; 굆; 굆; 굆; 굆; ) HANGUL SYLLABLE GOEBS +AD47;AD47;1100 116C 11BA;AD47;1100 116C 11BA; # (굇; 굇; 굇; 굇; 굇; ) HANGUL SYLLABLE GOES +AD48;AD48;1100 116C 11BB;AD48;1100 116C 11BB; # (굈; 굈; 굈; 굈; 굈; ) HANGUL SYLLABLE GOESS +AD49;AD49;1100 116C 11BC;AD49;1100 116C 11BC; # (굉; 굉; 굉; 굉; 굉; ) HANGUL SYLLABLE GOENG +AD4A;AD4A;1100 116C 11BD;AD4A;1100 116C 11BD; # (굊; 굊; 굊; 굊; 굊; ) HANGUL SYLLABLE GOEJ +AD4B;AD4B;1100 116C 11BE;AD4B;1100 116C 11BE; # (굋; 굋; 굋; 굋; 굋; ) HANGUL SYLLABLE GOEC +AD4C;AD4C;1100 116C 11BF;AD4C;1100 116C 11BF; # (굌; 굌; 굌; 굌; 굌; ) HANGUL SYLLABLE GOEK +AD4D;AD4D;1100 116C 11C0;AD4D;1100 116C 11C0; # (굍; 굍; 굍; 굍; 굍; ) HANGUL SYLLABLE GOET +AD4E;AD4E;1100 116C 11C1;AD4E;1100 116C 11C1; # (굎; 굎; 굎; 굎; 굎; ) HANGUL SYLLABLE GOEP +AD4F;AD4F;1100 116C 11C2;AD4F;1100 116C 11C2; # (굏; 굏; 굏; 굏; 굏; ) HANGUL SYLLABLE GOEH +AD50;AD50;1100 116D;AD50;1100 116D; # (교; 교; 교; 교; 교; ) HANGUL SYLLABLE GYO +AD51;AD51;1100 116D 11A8;AD51;1100 116D 11A8; # (굑; 굑; 굑; 굑; 굑; ) HANGUL SYLLABLE GYOG +AD52;AD52;1100 116D 11A9;AD52;1100 116D 11A9; # (굒; 굒; 굒; 굒; 굒; ) HANGUL SYLLABLE GYOGG +AD53;AD53;1100 116D 11AA;AD53;1100 116D 11AA; # (굓; 굓; 굓; 굓; 굓; ) HANGUL SYLLABLE GYOGS +AD54;AD54;1100 116D 11AB;AD54;1100 116D 11AB; # (굔; 굔; 굔; 굔; 굔; ) HANGUL SYLLABLE GYON +AD55;AD55;1100 116D 11AC;AD55;1100 116D 11AC; # (굕; 굕; 굕; 굕; 굕; ) HANGUL SYLLABLE GYONJ +AD56;AD56;1100 116D 11AD;AD56;1100 116D 11AD; # (굖; 굖; 굖; 굖; 굖; ) HANGUL SYLLABLE GYONH +AD57;AD57;1100 116D 11AE;AD57;1100 116D 11AE; # (굗; 굗; 굗; 굗; 굗; ) HANGUL SYLLABLE GYOD +AD58;AD58;1100 116D 11AF;AD58;1100 116D 11AF; # (굘; 굘; 굘; 굘; 굘; ) HANGUL SYLLABLE GYOL +AD59;AD59;1100 116D 11B0;AD59;1100 116D 11B0; # (굙; 굙; 굙; 굙; 굙; ) HANGUL SYLLABLE GYOLG +AD5A;AD5A;1100 116D 11B1;AD5A;1100 116D 11B1; # (굚; 굚; 굚; 굚; 굚; ) HANGUL SYLLABLE GYOLM +AD5B;AD5B;1100 116D 11B2;AD5B;1100 116D 11B2; # (굛; 굛; 굛; 굛; 굛; ) HANGUL SYLLABLE GYOLB +AD5C;AD5C;1100 116D 11B3;AD5C;1100 116D 11B3; # (굜; 굜; 굜; 굜; 굜; ) HANGUL SYLLABLE GYOLS +AD5D;AD5D;1100 116D 11B4;AD5D;1100 116D 11B4; # (굝; 굝; 굝; 굝; 굝; ) HANGUL SYLLABLE GYOLT +AD5E;AD5E;1100 116D 11B5;AD5E;1100 116D 11B5; # (굞; 굞; 굞; 굞; 굞; ) HANGUL SYLLABLE GYOLP +AD5F;AD5F;1100 116D 11B6;AD5F;1100 116D 11B6; # (굟; 굟; 굟; 굟; 굟; ) HANGUL SYLLABLE GYOLH +AD60;AD60;1100 116D 11B7;AD60;1100 116D 11B7; # (굠; 굠; 굠; 굠; 굠; ) HANGUL SYLLABLE GYOM +AD61;AD61;1100 116D 11B8;AD61;1100 116D 11B8; # (굡; 굡; 굡; 굡; 굡; ) HANGUL SYLLABLE GYOB +AD62;AD62;1100 116D 11B9;AD62;1100 116D 11B9; # (굢; 굢; 굢; 굢; 굢; ) HANGUL SYLLABLE GYOBS +AD63;AD63;1100 116D 11BA;AD63;1100 116D 11BA; # (굣; 굣; 굣; 굣; 굣; ) HANGUL SYLLABLE GYOS +AD64;AD64;1100 116D 11BB;AD64;1100 116D 11BB; # (굤; 굤; 굤; 굤; 굤; ) HANGUL SYLLABLE GYOSS +AD65;AD65;1100 116D 11BC;AD65;1100 116D 11BC; # (굥; 굥; 굥; 굥; 굥; ) HANGUL SYLLABLE GYONG +AD66;AD66;1100 116D 11BD;AD66;1100 116D 11BD; # (굦; 굦; 굦; 굦; 굦; ) HANGUL SYLLABLE GYOJ +AD67;AD67;1100 116D 11BE;AD67;1100 116D 11BE; # (굧; 굧; 굧; 굧; 굧; ) HANGUL SYLLABLE GYOC +AD68;AD68;1100 116D 11BF;AD68;1100 116D 11BF; # (굨; 굨; 굨; 굨; 굨; ) HANGUL SYLLABLE GYOK +AD69;AD69;1100 116D 11C0;AD69;1100 116D 11C0; # (굩; 굩; 굩; 굩; 굩; ) HANGUL SYLLABLE GYOT +AD6A;AD6A;1100 116D 11C1;AD6A;1100 116D 11C1; # (굪; 굪; 굪; 굪; 굪; ) HANGUL SYLLABLE GYOP +AD6B;AD6B;1100 116D 11C2;AD6B;1100 116D 11C2; # (굫; 굫; 굫; 굫; 굫; ) HANGUL SYLLABLE GYOH +AD6C;AD6C;1100 116E;AD6C;1100 116E; # (구; 구; 구; 구; 구; ) HANGUL SYLLABLE GU +AD6D;AD6D;1100 116E 11A8;AD6D;1100 116E 11A8; # (국; 국; 국; 국; 국; ) HANGUL SYLLABLE GUG +AD6E;AD6E;1100 116E 11A9;AD6E;1100 116E 11A9; # (굮; 굮; 굮; 굮; 굮; ) HANGUL SYLLABLE GUGG +AD6F;AD6F;1100 116E 11AA;AD6F;1100 116E 11AA; # (굯; 굯; 굯; 굯; 굯; ) HANGUL SYLLABLE GUGS +AD70;AD70;1100 116E 11AB;AD70;1100 116E 11AB; # (군; 군; 군; 군; 군; ) HANGUL SYLLABLE GUN +AD71;AD71;1100 116E 11AC;AD71;1100 116E 11AC; # (굱; 굱; 굱; 굱; 굱; ) HANGUL SYLLABLE GUNJ +AD72;AD72;1100 116E 11AD;AD72;1100 116E 11AD; # (굲; 굲; 굲; 굲; 굲; ) HANGUL SYLLABLE GUNH +AD73;AD73;1100 116E 11AE;AD73;1100 116E 11AE; # (굳; 굳; 굳; 굳; 굳; ) HANGUL SYLLABLE GUD +AD74;AD74;1100 116E 11AF;AD74;1100 116E 11AF; # (굴; 굴; 굴; 굴; 굴; ) HANGUL SYLLABLE GUL +AD75;AD75;1100 116E 11B0;AD75;1100 116E 11B0; # (굵; 굵; 굵; 굵; 굵; ) HANGUL SYLLABLE GULG +AD76;AD76;1100 116E 11B1;AD76;1100 116E 11B1; # (굶; 굶; 굶; 굶; 굶; ) HANGUL SYLLABLE GULM +AD77;AD77;1100 116E 11B2;AD77;1100 116E 11B2; # (굷; 굷; 굷; 굷; 굷; ) HANGUL SYLLABLE GULB +AD78;AD78;1100 116E 11B3;AD78;1100 116E 11B3; # (굸; 굸; 굸; 굸; 굸; ) HANGUL SYLLABLE GULS +AD79;AD79;1100 116E 11B4;AD79;1100 116E 11B4; # (굹; 굹; 굹; 굹; 굹; ) HANGUL SYLLABLE GULT +AD7A;AD7A;1100 116E 11B5;AD7A;1100 116E 11B5; # (굺; 굺; 굺; 굺; 굺; ) HANGUL SYLLABLE GULP +AD7B;AD7B;1100 116E 11B6;AD7B;1100 116E 11B6; # (굻; 굻; 굻; 굻; 굻; ) HANGUL SYLLABLE GULH +AD7C;AD7C;1100 116E 11B7;AD7C;1100 116E 11B7; # (굼; 굼; 굼; 굼; 굼; ) HANGUL SYLLABLE GUM +AD7D;AD7D;1100 116E 11B8;AD7D;1100 116E 11B8; # (굽; 굽; 굽; 굽; 굽; ) HANGUL SYLLABLE GUB +AD7E;AD7E;1100 116E 11B9;AD7E;1100 116E 11B9; # (굾; 굾; 굾; 굾; 굾; ) HANGUL SYLLABLE GUBS +AD7F;AD7F;1100 116E 11BA;AD7F;1100 116E 11BA; # (굿; 굿; 굿; 굿; 굿; ) HANGUL SYLLABLE GUS +AD80;AD80;1100 116E 11BB;AD80;1100 116E 11BB; # (궀; 궀; 궀; 궀; 궀; ) HANGUL SYLLABLE GUSS +AD81;AD81;1100 116E 11BC;AD81;1100 116E 11BC; # (궁; 궁; 궁; 궁; 궁; ) HANGUL SYLLABLE GUNG +AD82;AD82;1100 116E 11BD;AD82;1100 116E 11BD; # (궂; 궂; 궂; 궂; 궂; ) HANGUL SYLLABLE GUJ +AD83;AD83;1100 116E 11BE;AD83;1100 116E 11BE; # (궃; 궃; 궃; 궃; 궃; ) HANGUL SYLLABLE GUC +AD84;AD84;1100 116E 11BF;AD84;1100 116E 11BF; # (궄; 궄; 궄; 궄; 궄; ) HANGUL SYLLABLE GUK +AD85;AD85;1100 116E 11C0;AD85;1100 116E 11C0; # (궅; 궅; 궅; 궅; 궅; ) HANGUL SYLLABLE GUT +AD86;AD86;1100 116E 11C1;AD86;1100 116E 11C1; # (궆; 궆; 궆; 궆; 궆; ) HANGUL SYLLABLE GUP +AD87;AD87;1100 116E 11C2;AD87;1100 116E 11C2; # (궇; 궇; 궇; 궇; 궇; ) HANGUL SYLLABLE GUH +AD88;AD88;1100 116F;AD88;1100 116F; # (궈; 궈; 궈; 궈; 궈; ) HANGUL SYLLABLE GWEO +AD89;AD89;1100 116F 11A8;AD89;1100 116F 11A8; # (궉; 궉; 궉; 궉; 궉; ) HANGUL SYLLABLE GWEOG +AD8A;AD8A;1100 116F 11A9;AD8A;1100 116F 11A9; # (궊; 궊; 궊; 궊; 궊; ) HANGUL SYLLABLE GWEOGG +AD8B;AD8B;1100 116F 11AA;AD8B;1100 116F 11AA; # (궋; 궋; 궋; 궋; 궋; ) HANGUL SYLLABLE GWEOGS +AD8C;AD8C;1100 116F 11AB;AD8C;1100 116F 11AB; # (권; 권; 권; 권; 권; ) HANGUL SYLLABLE GWEON +AD8D;AD8D;1100 116F 11AC;AD8D;1100 116F 11AC; # (궍; 궍; 궍; 궍; 궍; ) HANGUL SYLLABLE GWEONJ +AD8E;AD8E;1100 116F 11AD;AD8E;1100 116F 11AD; # (궎; 궎; 궎; 궎; 궎; ) HANGUL SYLLABLE GWEONH +AD8F;AD8F;1100 116F 11AE;AD8F;1100 116F 11AE; # (궏; 궏; 궏; 궏; 궏; ) HANGUL SYLLABLE GWEOD +AD90;AD90;1100 116F 11AF;AD90;1100 116F 11AF; # (궐; 궐; 궐; 궐; 궐; ) HANGUL SYLLABLE GWEOL +AD91;AD91;1100 116F 11B0;AD91;1100 116F 11B0; # (궑; 궑; 궑; 궑; 궑; ) HANGUL SYLLABLE GWEOLG +AD92;AD92;1100 116F 11B1;AD92;1100 116F 11B1; # (궒; 궒; 궒; 궒; 궒; ) HANGUL SYLLABLE GWEOLM +AD93;AD93;1100 116F 11B2;AD93;1100 116F 11B2; # (궓; 궓; 궓; 궓; 궓; ) HANGUL SYLLABLE GWEOLB +AD94;AD94;1100 116F 11B3;AD94;1100 116F 11B3; # (궔; 궔; 궔; 궔; 궔; ) HANGUL SYLLABLE GWEOLS +AD95;AD95;1100 116F 11B4;AD95;1100 116F 11B4; # (궕; 궕; 궕; 궕; 궕; ) HANGUL SYLLABLE GWEOLT +AD96;AD96;1100 116F 11B5;AD96;1100 116F 11B5; # (궖; 궖; 궖; 궖; 궖; ) HANGUL SYLLABLE GWEOLP +AD97;AD97;1100 116F 11B6;AD97;1100 116F 11B6; # (궗; 궗; 궗; 궗; 궗; ) HANGUL SYLLABLE GWEOLH +AD98;AD98;1100 116F 11B7;AD98;1100 116F 11B7; # (궘; 궘; 궘; 궘; 궘; ) HANGUL SYLLABLE GWEOM +AD99;AD99;1100 116F 11B8;AD99;1100 116F 11B8; # (궙; 궙; 궙; 궙; 궙; ) HANGUL SYLLABLE GWEOB +AD9A;AD9A;1100 116F 11B9;AD9A;1100 116F 11B9; # (궚; 궚; 궚; 궚; 궚; ) HANGUL SYLLABLE GWEOBS +AD9B;AD9B;1100 116F 11BA;AD9B;1100 116F 11BA; # (궛; 궛; 궛; 궛; 궛; ) HANGUL SYLLABLE GWEOS +AD9C;AD9C;1100 116F 11BB;AD9C;1100 116F 11BB; # (궜; 궜; 궜; 궜; 궜; ) HANGUL SYLLABLE GWEOSS +AD9D;AD9D;1100 116F 11BC;AD9D;1100 116F 11BC; # (궝; 궝; 궝; 궝; 궝; ) HANGUL SYLLABLE GWEONG +AD9E;AD9E;1100 116F 11BD;AD9E;1100 116F 11BD; # (궞; 궞; 궞; 궞; 궞; ) HANGUL SYLLABLE GWEOJ +AD9F;AD9F;1100 116F 11BE;AD9F;1100 116F 11BE; # (궟; 궟; 궟; 궟; 궟; ) HANGUL SYLLABLE GWEOC +ADA0;ADA0;1100 116F 11BF;ADA0;1100 116F 11BF; # (궠; 궠; 궠; 궠; 궠; ) HANGUL SYLLABLE GWEOK +ADA1;ADA1;1100 116F 11C0;ADA1;1100 116F 11C0; # (궡; 궡; 궡; 궡; 궡; ) HANGUL SYLLABLE GWEOT +ADA2;ADA2;1100 116F 11C1;ADA2;1100 116F 11C1; # (궢; 궢; 궢; 궢; 궢; ) HANGUL SYLLABLE GWEOP +ADA3;ADA3;1100 116F 11C2;ADA3;1100 116F 11C2; # (궣; 궣; 궣; 궣; 궣; ) HANGUL SYLLABLE GWEOH +ADA4;ADA4;1100 1170;ADA4;1100 1170; # (궤; 궤; 궤; 궤; 궤; ) HANGUL SYLLABLE GWE +ADA5;ADA5;1100 1170 11A8;ADA5;1100 1170 11A8; # (궥; 궥; 궥; 궥; 궥; ) HANGUL SYLLABLE GWEG +ADA6;ADA6;1100 1170 11A9;ADA6;1100 1170 11A9; # (궦; 궦; 궦; 궦; 궦; ) HANGUL SYLLABLE GWEGG +ADA7;ADA7;1100 1170 11AA;ADA7;1100 1170 11AA; # (궧; 궧; 궧; 궧; 궧; ) HANGUL SYLLABLE GWEGS +ADA8;ADA8;1100 1170 11AB;ADA8;1100 1170 11AB; # (궨; 궨; 궨; 궨; 궨; ) HANGUL SYLLABLE GWEN +ADA9;ADA9;1100 1170 11AC;ADA9;1100 1170 11AC; # (궩; 궩; 궩; 궩; 궩; ) HANGUL SYLLABLE GWENJ +ADAA;ADAA;1100 1170 11AD;ADAA;1100 1170 11AD; # (궪; 궪; 궪; 궪; 궪; ) HANGUL SYLLABLE GWENH +ADAB;ADAB;1100 1170 11AE;ADAB;1100 1170 11AE; # (궫; 궫; 궫; 궫; 궫; ) HANGUL SYLLABLE GWED +ADAC;ADAC;1100 1170 11AF;ADAC;1100 1170 11AF; # (궬; 궬; 궬; 궬; 궬; ) HANGUL SYLLABLE GWEL +ADAD;ADAD;1100 1170 11B0;ADAD;1100 1170 11B0; # (궭; 궭; 궭; 궭; 궭; ) HANGUL SYLLABLE GWELG +ADAE;ADAE;1100 1170 11B1;ADAE;1100 1170 11B1; # (궮; 궮; 궮; 궮; 궮; ) HANGUL SYLLABLE GWELM +ADAF;ADAF;1100 1170 11B2;ADAF;1100 1170 11B2; # (궯; 궯; 궯; 궯; 궯; ) HANGUL SYLLABLE GWELB +ADB0;ADB0;1100 1170 11B3;ADB0;1100 1170 11B3; # (궰; 궰; 궰; 궰; 궰; ) HANGUL SYLLABLE GWELS +ADB1;ADB1;1100 1170 11B4;ADB1;1100 1170 11B4; # (궱; 궱; 궱; 궱; 궱; ) HANGUL SYLLABLE GWELT +ADB2;ADB2;1100 1170 11B5;ADB2;1100 1170 11B5; # (궲; 궲; 궲; 궲; 궲; ) HANGUL SYLLABLE GWELP +ADB3;ADB3;1100 1170 11B6;ADB3;1100 1170 11B6; # (궳; 궳; 궳; 궳; 궳; ) HANGUL SYLLABLE GWELH +ADB4;ADB4;1100 1170 11B7;ADB4;1100 1170 11B7; # (궴; 궴; 궴; 궴; 궴; ) HANGUL SYLLABLE GWEM +ADB5;ADB5;1100 1170 11B8;ADB5;1100 1170 11B8; # (궵; 궵; 궵; 궵; 궵; ) HANGUL SYLLABLE GWEB +ADB6;ADB6;1100 1170 11B9;ADB6;1100 1170 11B9; # (궶; 궶; 궶; 궶; 궶; ) HANGUL SYLLABLE GWEBS +ADB7;ADB7;1100 1170 11BA;ADB7;1100 1170 11BA; # (궷; 궷; 궷; 궷; 궷; ) HANGUL SYLLABLE GWES +ADB8;ADB8;1100 1170 11BB;ADB8;1100 1170 11BB; # (궸; 궸; 궸; 궸; 궸; ) HANGUL SYLLABLE GWESS +ADB9;ADB9;1100 1170 11BC;ADB9;1100 1170 11BC; # (궹; 궹; 궹; 궹; 궹; ) HANGUL SYLLABLE GWENG +ADBA;ADBA;1100 1170 11BD;ADBA;1100 1170 11BD; # (궺; 궺; 궺; 궺; 궺; ) HANGUL SYLLABLE GWEJ +ADBB;ADBB;1100 1170 11BE;ADBB;1100 1170 11BE; # (궻; 궻; 궻; 궻; 궻; ) HANGUL SYLLABLE GWEC +ADBC;ADBC;1100 1170 11BF;ADBC;1100 1170 11BF; # (궼; 궼; 궼; 궼; 궼; ) HANGUL SYLLABLE GWEK +ADBD;ADBD;1100 1170 11C0;ADBD;1100 1170 11C0; # (궽; 궽; 궽; 궽; 궽; ) HANGUL SYLLABLE GWET +ADBE;ADBE;1100 1170 11C1;ADBE;1100 1170 11C1; # (궾; 궾; 궾; 궾; 궾; ) HANGUL SYLLABLE GWEP +ADBF;ADBF;1100 1170 11C2;ADBF;1100 1170 11C2; # (궿; 궿; 궿; 궿; 궿; ) HANGUL SYLLABLE GWEH +ADC0;ADC0;1100 1171;ADC0;1100 1171; # (귀; 귀; 귀; 귀; 귀; ) HANGUL SYLLABLE GWI +ADC1;ADC1;1100 1171 11A8;ADC1;1100 1171 11A8; # (귁; 귁; 귁; 귁; 귁; ) HANGUL SYLLABLE GWIG +ADC2;ADC2;1100 1171 11A9;ADC2;1100 1171 11A9; # (귂; 귂; 귂; 귂; 귂; ) HANGUL SYLLABLE GWIGG +ADC3;ADC3;1100 1171 11AA;ADC3;1100 1171 11AA; # (귃; 귃; 귃; 귃; 귃; ) HANGUL SYLLABLE GWIGS +ADC4;ADC4;1100 1171 11AB;ADC4;1100 1171 11AB; # (귄; 귄; 귄; 귄; 귄; ) HANGUL SYLLABLE GWIN +ADC5;ADC5;1100 1171 11AC;ADC5;1100 1171 11AC; # (귅; 귅; 귅; 귅; 귅; ) HANGUL SYLLABLE GWINJ +ADC6;ADC6;1100 1171 11AD;ADC6;1100 1171 11AD; # (귆; 귆; 귆; 귆; 귆; ) HANGUL SYLLABLE GWINH +ADC7;ADC7;1100 1171 11AE;ADC7;1100 1171 11AE; # (귇; 귇; 귇; 귇; 귇; ) HANGUL SYLLABLE GWID +ADC8;ADC8;1100 1171 11AF;ADC8;1100 1171 11AF; # (귈; 귈; 귈; 귈; 귈; ) HANGUL SYLLABLE GWIL +ADC9;ADC9;1100 1171 11B0;ADC9;1100 1171 11B0; # (귉; 귉; 귉; 귉; 귉; ) HANGUL SYLLABLE GWILG +ADCA;ADCA;1100 1171 11B1;ADCA;1100 1171 11B1; # (귊; 귊; 귊; 귊; 귊; ) HANGUL SYLLABLE GWILM +ADCB;ADCB;1100 1171 11B2;ADCB;1100 1171 11B2; # (귋; 귋; 귋; 귋; 귋; ) HANGUL SYLLABLE GWILB +ADCC;ADCC;1100 1171 11B3;ADCC;1100 1171 11B3; # (귌; 귌; 귌; 귌; 귌; ) HANGUL SYLLABLE GWILS +ADCD;ADCD;1100 1171 11B4;ADCD;1100 1171 11B4; # (귍; 귍; 귍; 귍; 귍; ) HANGUL SYLLABLE GWILT +ADCE;ADCE;1100 1171 11B5;ADCE;1100 1171 11B5; # (귎; 귎; 귎; 귎; 귎; ) HANGUL SYLLABLE GWILP +ADCF;ADCF;1100 1171 11B6;ADCF;1100 1171 11B6; # (귏; 귏; 귏; 귏; 귏; ) HANGUL SYLLABLE GWILH +ADD0;ADD0;1100 1171 11B7;ADD0;1100 1171 11B7; # (귐; 귐; 귐; 귐; 귐; ) HANGUL SYLLABLE GWIM +ADD1;ADD1;1100 1171 11B8;ADD1;1100 1171 11B8; # (귑; 귑; 귑; 귑; 귑; ) HANGUL SYLLABLE GWIB +ADD2;ADD2;1100 1171 11B9;ADD2;1100 1171 11B9; # (귒; 귒; 귒; 귒; 귒; ) HANGUL SYLLABLE GWIBS +ADD3;ADD3;1100 1171 11BA;ADD3;1100 1171 11BA; # (귓; 귓; 귓; 귓; 귓; ) HANGUL SYLLABLE GWIS +ADD4;ADD4;1100 1171 11BB;ADD4;1100 1171 11BB; # (귔; 귔; 귔; 귔; 귔; ) HANGUL SYLLABLE GWISS +ADD5;ADD5;1100 1171 11BC;ADD5;1100 1171 11BC; # (귕; 귕; 귕; 귕; 귕; ) HANGUL SYLLABLE GWING +ADD6;ADD6;1100 1171 11BD;ADD6;1100 1171 11BD; # (귖; 귖; 귖; 귖; 귖; ) HANGUL SYLLABLE GWIJ +ADD7;ADD7;1100 1171 11BE;ADD7;1100 1171 11BE; # (귗; 귗; 귗; 귗; 귗; ) HANGUL SYLLABLE GWIC +ADD8;ADD8;1100 1171 11BF;ADD8;1100 1171 11BF; # (귘; 귘; 귘; 귘; 귘; ) HANGUL SYLLABLE GWIK +ADD9;ADD9;1100 1171 11C0;ADD9;1100 1171 11C0; # (귙; 귙; 귙; 귙; 귙; ) HANGUL SYLLABLE GWIT +ADDA;ADDA;1100 1171 11C1;ADDA;1100 1171 11C1; # (귚; 귚; 귚; 귚; 귚; ) HANGUL SYLLABLE GWIP +ADDB;ADDB;1100 1171 11C2;ADDB;1100 1171 11C2; # (귛; 귛; 귛; 귛; 귛; ) HANGUL SYLLABLE GWIH +ADDC;ADDC;1100 1172;ADDC;1100 1172; # (규; 규; 규; 규; 규; ) HANGUL SYLLABLE GYU +ADDD;ADDD;1100 1172 11A8;ADDD;1100 1172 11A8; # (귝; 귝; 귝; 귝; 귝; ) HANGUL SYLLABLE GYUG +ADDE;ADDE;1100 1172 11A9;ADDE;1100 1172 11A9; # (귞; 귞; 귞; 귞; 귞; ) HANGUL SYLLABLE GYUGG +ADDF;ADDF;1100 1172 11AA;ADDF;1100 1172 11AA; # (귟; 귟; 귟; 귟; 귟; ) HANGUL SYLLABLE GYUGS +ADE0;ADE0;1100 1172 11AB;ADE0;1100 1172 11AB; # (균; 균; 균; 균; 균; ) HANGUL SYLLABLE GYUN +ADE1;ADE1;1100 1172 11AC;ADE1;1100 1172 11AC; # (귡; 귡; 귡; 귡; 귡; ) HANGUL SYLLABLE GYUNJ +ADE2;ADE2;1100 1172 11AD;ADE2;1100 1172 11AD; # (귢; 귢; 귢; 귢; 귢; ) HANGUL SYLLABLE GYUNH +ADE3;ADE3;1100 1172 11AE;ADE3;1100 1172 11AE; # (귣; 귣; 귣; 귣; 귣; ) HANGUL SYLLABLE GYUD +ADE4;ADE4;1100 1172 11AF;ADE4;1100 1172 11AF; # (귤; 귤; 귤; 귤; 귤; ) HANGUL SYLLABLE GYUL +ADE5;ADE5;1100 1172 11B0;ADE5;1100 1172 11B0; # (귥; 귥; 귥; 귥; 귥; ) HANGUL SYLLABLE GYULG +ADE6;ADE6;1100 1172 11B1;ADE6;1100 1172 11B1; # (귦; 귦; 귦; 귦; 귦; ) HANGUL SYLLABLE GYULM +ADE7;ADE7;1100 1172 11B2;ADE7;1100 1172 11B2; # (귧; 귧; 귧; 귧; 귧; ) HANGUL SYLLABLE GYULB +ADE8;ADE8;1100 1172 11B3;ADE8;1100 1172 11B3; # (귨; 귨; 귨; 귨; 귨; ) HANGUL SYLLABLE GYULS +ADE9;ADE9;1100 1172 11B4;ADE9;1100 1172 11B4; # (귩; 귩; 귩; 귩; 귩; ) HANGUL SYLLABLE GYULT +ADEA;ADEA;1100 1172 11B5;ADEA;1100 1172 11B5; # (귪; 귪; 귪; 귪; 귪; ) HANGUL SYLLABLE GYULP +ADEB;ADEB;1100 1172 11B6;ADEB;1100 1172 11B6; # (귫; 귫; 귫; 귫; 귫; ) HANGUL SYLLABLE GYULH +ADEC;ADEC;1100 1172 11B7;ADEC;1100 1172 11B7; # (귬; 귬; 귬; 귬; 귬; ) HANGUL SYLLABLE GYUM +ADED;ADED;1100 1172 11B8;ADED;1100 1172 11B8; # (귭; 귭; 귭; 귭; 귭; ) HANGUL SYLLABLE GYUB +ADEE;ADEE;1100 1172 11B9;ADEE;1100 1172 11B9; # (귮; 귮; 귮; 귮; 귮; ) HANGUL SYLLABLE GYUBS +ADEF;ADEF;1100 1172 11BA;ADEF;1100 1172 11BA; # (귯; 귯; 귯; 귯; 귯; ) HANGUL SYLLABLE GYUS +ADF0;ADF0;1100 1172 11BB;ADF0;1100 1172 11BB; # (귰; 귰; 귰; 귰; 귰; ) HANGUL SYLLABLE GYUSS +ADF1;ADF1;1100 1172 11BC;ADF1;1100 1172 11BC; # (귱; 귱; 귱; 귱; 귱; ) HANGUL SYLLABLE GYUNG +ADF2;ADF2;1100 1172 11BD;ADF2;1100 1172 11BD; # (귲; 귲; 귲; 귲; 귲; ) HANGUL SYLLABLE GYUJ +ADF3;ADF3;1100 1172 11BE;ADF3;1100 1172 11BE; # (귳; 귳; 귳; 귳; 귳; ) HANGUL SYLLABLE GYUC +ADF4;ADF4;1100 1172 11BF;ADF4;1100 1172 11BF; # (귴; 귴; 귴; 귴; 귴; ) HANGUL SYLLABLE GYUK +ADF5;ADF5;1100 1172 11C0;ADF5;1100 1172 11C0; # (귵; 귵; 귵; 귵; 귵; ) HANGUL SYLLABLE GYUT +ADF6;ADF6;1100 1172 11C1;ADF6;1100 1172 11C1; # (귶; 귶; 귶; 귶; 귶; ) HANGUL SYLLABLE GYUP +ADF7;ADF7;1100 1172 11C2;ADF7;1100 1172 11C2; # (귷; 귷; 귷; 귷; 귷; ) HANGUL SYLLABLE GYUH +ADF8;ADF8;1100 1173;ADF8;1100 1173; # (그; 그; 그; 그; 그; ) HANGUL SYLLABLE GEU +ADF9;ADF9;1100 1173 11A8;ADF9;1100 1173 11A8; # (극; 극; 극; 극; 극; ) HANGUL SYLLABLE GEUG +ADFA;ADFA;1100 1173 11A9;ADFA;1100 1173 11A9; # (귺; 귺; 귺; 귺; 귺; ) HANGUL SYLLABLE GEUGG +ADFB;ADFB;1100 1173 11AA;ADFB;1100 1173 11AA; # (귻; 귻; 귻; 귻; 귻; ) HANGUL SYLLABLE GEUGS +ADFC;ADFC;1100 1173 11AB;ADFC;1100 1173 11AB; # (근; 근; 근; 근; 근; ) HANGUL SYLLABLE GEUN +ADFD;ADFD;1100 1173 11AC;ADFD;1100 1173 11AC; # (귽; 귽; 귽; 귽; 귽; ) HANGUL SYLLABLE GEUNJ +ADFE;ADFE;1100 1173 11AD;ADFE;1100 1173 11AD; # (귾; 귾; 귾; 귾; 귾; ) HANGUL SYLLABLE GEUNH +ADFF;ADFF;1100 1173 11AE;ADFF;1100 1173 11AE; # (귿; 귿; 귿; 귿; 귿; ) HANGUL SYLLABLE GEUD +AE00;AE00;1100 1173 11AF;AE00;1100 1173 11AF; # (글; 글; 글; 글; 글; ) HANGUL SYLLABLE GEUL +AE01;AE01;1100 1173 11B0;AE01;1100 1173 11B0; # (긁; 긁; 긁; 긁; 긁; ) HANGUL SYLLABLE GEULG +AE02;AE02;1100 1173 11B1;AE02;1100 1173 11B1; # (긂; 긂; 긂; 긂; 긂; ) HANGUL SYLLABLE GEULM +AE03;AE03;1100 1173 11B2;AE03;1100 1173 11B2; # (긃; 긃; 긃; 긃; 긃; ) HANGUL SYLLABLE GEULB +AE04;AE04;1100 1173 11B3;AE04;1100 1173 11B3; # (긄; 긄; 긄; 긄; 긄; ) HANGUL SYLLABLE GEULS +AE05;AE05;1100 1173 11B4;AE05;1100 1173 11B4; # (긅; 긅; 긅; 긅; 긅; ) HANGUL SYLLABLE GEULT +AE06;AE06;1100 1173 11B5;AE06;1100 1173 11B5; # (긆; 긆; 긆; 긆; 긆; ) HANGUL SYLLABLE GEULP +AE07;AE07;1100 1173 11B6;AE07;1100 1173 11B6; # (긇; 긇; 긇; 긇; 긇; ) HANGUL SYLLABLE GEULH +AE08;AE08;1100 1173 11B7;AE08;1100 1173 11B7; # (금; 금; 금; 금; 금; ) HANGUL SYLLABLE GEUM +AE09;AE09;1100 1173 11B8;AE09;1100 1173 11B8; # (급; 급; 급; 급; 급; ) HANGUL SYLLABLE GEUB +AE0A;AE0A;1100 1173 11B9;AE0A;1100 1173 11B9; # (긊; 긊; 긊; 긊; 긊; ) HANGUL SYLLABLE GEUBS +AE0B;AE0B;1100 1173 11BA;AE0B;1100 1173 11BA; # (긋; 긋; 긋; 긋; 긋; ) HANGUL SYLLABLE GEUS +AE0C;AE0C;1100 1173 11BB;AE0C;1100 1173 11BB; # (긌; 긌; 긌; 긌; 긌; ) HANGUL SYLLABLE GEUSS +AE0D;AE0D;1100 1173 11BC;AE0D;1100 1173 11BC; # (긍; 긍; 긍; 긍; 긍; ) HANGUL SYLLABLE GEUNG +AE0E;AE0E;1100 1173 11BD;AE0E;1100 1173 11BD; # (긎; 긎; 긎; 긎; 긎; ) HANGUL SYLLABLE GEUJ +AE0F;AE0F;1100 1173 11BE;AE0F;1100 1173 11BE; # (긏; 긏; 긏; 긏; 긏; ) HANGUL SYLLABLE GEUC +AE10;AE10;1100 1173 11BF;AE10;1100 1173 11BF; # (긐; 긐; 긐; 긐; 긐; ) HANGUL SYLLABLE GEUK +AE11;AE11;1100 1173 11C0;AE11;1100 1173 11C0; # (긑; 긑; 긑; 긑; 긑; ) HANGUL SYLLABLE GEUT +AE12;AE12;1100 1173 11C1;AE12;1100 1173 11C1; # (긒; 긒; 긒; 긒; 긒; ) HANGUL SYLLABLE GEUP +AE13;AE13;1100 1173 11C2;AE13;1100 1173 11C2; # (긓; 긓; 긓; 긓; 긓; ) HANGUL SYLLABLE GEUH +AE14;AE14;1100 1174;AE14;1100 1174; # (긔; 긔; 긔; 긔; 긔; ) HANGUL SYLLABLE GYI +AE15;AE15;1100 1174 11A8;AE15;1100 1174 11A8; # (긕; 긕; 긕; 긕; 긕; ) HANGUL SYLLABLE GYIG +AE16;AE16;1100 1174 11A9;AE16;1100 1174 11A9; # (긖; 긖; 긖; 긖; 긖; ) HANGUL SYLLABLE GYIGG +AE17;AE17;1100 1174 11AA;AE17;1100 1174 11AA; # (긗; 긗; 긗; 긗; 긗; ) HANGUL SYLLABLE GYIGS +AE18;AE18;1100 1174 11AB;AE18;1100 1174 11AB; # (긘; 긘; 긘; 긘; 긘; ) HANGUL SYLLABLE GYIN +AE19;AE19;1100 1174 11AC;AE19;1100 1174 11AC; # (긙; 긙; 긙; 긙; 긙; ) HANGUL SYLLABLE GYINJ +AE1A;AE1A;1100 1174 11AD;AE1A;1100 1174 11AD; # (긚; 긚; 긚; 긚; 긚; ) HANGUL SYLLABLE GYINH +AE1B;AE1B;1100 1174 11AE;AE1B;1100 1174 11AE; # (긛; 긛; 긛; 긛; 긛; ) HANGUL SYLLABLE GYID +AE1C;AE1C;1100 1174 11AF;AE1C;1100 1174 11AF; # (긜; 긜; 긜; 긜; 긜; ) HANGUL SYLLABLE GYIL +AE1D;AE1D;1100 1174 11B0;AE1D;1100 1174 11B0; # (긝; 긝; 긝; 긝; 긝; ) HANGUL SYLLABLE GYILG +AE1E;AE1E;1100 1174 11B1;AE1E;1100 1174 11B1; # (긞; 긞; 긞; 긞; 긞; ) HANGUL SYLLABLE GYILM +AE1F;AE1F;1100 1174 11B2;AE1F;1100 1174 11B2; # (긟; 긟; 긟; 긟; 긟; ) HANGUL SYLLABLE GYILB +AE20;AE20;1100 1174 11B3;AE20;1100 1174 11B3; # (긠; 긠; 긠; 긠; 긠; ) HANGUL SYLLABLE GYILS +AE21;AE21;1100 1174 11B4;AE21;1100 1174 11B4; # (긡; 긡; 긡; 긡; 긡; ) HANGUL SYLLABLE GYILT +AE22;AE22;1100 1174 11B5;AE22;1100 1174 11B5; # (긢; 긢; 긢; 긢; 긢; ) HANGUL SYLLABLE GYILP +AE23;AE23;1100 1174 11B6;AE23;1100 1174 11B6; # (긣; 긣; 긣; 긣; 긣; ) HANGUL SYLLABLE GYILH +AE24;AE24;1100 1174 11B7;AE24;1100 1174 11B7; # (긤; 긤; 긤; 긤; 긤; ) HANGUL SYLLABLE GYIM +AE25;AE25;1100 1174 11B8;AE25;1100 1174 11B8; # (긥; 긥; 긥; 긥; 긥; ) HANGUL SYLLABLE GYIB +AE26;AE26;1100 1174 11B9;AE26;1100 1174 11B9; # (긦; 긦; 긦; 긦; 긦; ) HANGUL SYLLABLE GYIBS +AE27;AE27;1100 1174 11BA;AE27;1100 1174 11BA; # (긧; 긧; 긧; 긧; 긧; ) HANGUL SYLLABLE GYIS +AE28;AE28;1100 1174 11BB;AE28;1100 1174 11BB; # (긨; 긨; 긨; 긨; 긨; ) HANGUL SYLLABLE GYISS +AE29;AE29;1100 1174 11BC;AE29;1100 1174 11BC; # (긩; 긩; 긩; 긩; 긩; ) HANGUL SYLLABLE GYING +AE2A;AE2A;1100 1174 11BD;AE2A;1100 1174 11BD; # (긪; 긪; 긪; 긪; 긪; ) HANGUL SYLLABLE GYIJ +AE2B;AE2B;1100 1174 11BE;AE2B;1100 1174 11BE; # (긫; 긫; 긫; 긫; 긫; ) HANGUL SYLLABLE GYIC +AE2C;AE2C;1100 1174 11BF;AE2C;1100 1174 11BF; # (긬; 긬; 긬; 긬; 긬; ) HANGUL SYLLABLE GYIK +AE2D;AE2D;1100 1174 11C0;AE2D;1100 1174 11C0; # (긭; 긭; 긭; 긭; 긭; ) HANGUL SYLLABLE GYIT +AE2E;AE2E;1100 1174 11C1;AE2E;1100 1174 11C1; # (긮; 긮; 긮; 긮; 긮; ) HANGUL SYLLABLE GYIP +AE2F;AE2F;1100 1174 11C2;AE2F;1100 1174 11C2; # (긯; 긯; 긯; 긯; 긯; ) HANGUL SYLLABLE GYIH +AE30;AE30;1100 1175;AE30;1100 1175; # (기; 기; 기; 기; 기; ) HANGUL SYLLABLE GI +AE31;AE31;1100 1175 11A8;AE31;1100 1175 11A8; # (긱; 긱; 긱; 긱; 긱; ) HANGUL SYLLABLE GIG +AE32;AE32;1100 1175 11A9;AE32;1100 1175 11A9; # (긲; 긲; 긲; 긲; 긲; ) HANGUL SYLLABLE GIGG +AE33;AE33;1100 1175 11AA;AE33;1100 1175 11AA; # (긳; 긳; 긳; 긳; 긳; ) HANGUL SYLLABLE GIGS +AE34;AE34;1100 1175 11AB;AE34;1100 1175 11AB; # (긴; 긴; 긴; 긴; 긴; ) HANGUL SYLLABLE GIN +AE35;AE35;1100 1175 11AC;AE35;1100 1175 11AC; # (긵; 긵; 긵; 긵; 긵; ) HANGUL SYLLABLE GINJ +AE36;AE36;1100 1175 11AD;AE36;1100 1175 11AD; # (긶; 긶; 긶; 긶; 긶; ) HANGUL SYLLABLE GINH +AE37;AE37;1100 1175 11AE;AE37;1100 1175 11AE; # (긷; 긷; 긷; 긷; 긷; ) HANGUL SYLLABLE GID +AE38;AE38;1100 1175 11AF;AE38;1100 1175 11AF; # (길; 길; 길; 길; 길; ) HANGUL SYLLABLE GIL +AE39;AE39;1100 1175 11B0;AE39;1100 1175 11B0; # (긹; 긹; 긹; 긹; 긹; ) HANGUL SYLLABLE GILG +AE3A;AE3A;1100 1175 11B1;AE3A;1100 1175 11B1; # (긺; 긺; 긺; 긺; 긺; ) HANGUL SYLLABLE GILM +AE3B;AE3B;1100 1175 11B2;AE3B;1100 1175 11B2; # (긻; 긻; 긻; 긻; 긻; ) HANGUL SYLLABLE GILB +AE3C;AE3C;1100 1175 11B3;AE3C;1100 1175 11B3; # (긼; 긼; 긼; 긼; 긼; ) HANGUL SYLLABLE GILS +AE3D;AE3D;1100 1175 11B4;AE3D;1100 1175 11B4; # (긽; 긽; 긽; 긽; 긽; ) HANGUL SYLLABLE GILT +AE3E;AE3E;1100 1175 11B5;AE3E;1100 1175 11B5; # (긾; 긾; 긾; 긾; 긾; ) HANGUL SYLLABLE GILP +AE3F;AE3F;1100 1175 11B6;AE3F;1100 1175 11B6; # (긿; 긿; 긿; 긿; 긿; ) HANGUL SYLLABLE GILH +AE40;AE40;1100 1175 11B7;AE40;1100 1175 11B7; # (김; 김; 김; 김; 김; ) HANGUL SYLLABLE GIM +AE41;AE41;1100 1175 11B8;AE41;1100 1175 11B8; # (깁; 깁; 깁; 깁; 깁; ) HANGUL SYLLABLE GIB +AE42;AE42;1100 1175 11B9;AE42;1100 1175 11B9; # (깂; 깂; 깂; 깂; 깂; ) HANGUL SYLLABLE GIBS +AE43;AE43;1100 1175 11BA;AE43;1100 1175 11BA; # (깃; 깃; 깃; 깃; 깃; ) HANGUL SYLLABLE GIS +AE44;AE44;1100 1175 11BB;AE44;1100 1175 11BB; # (깄; 깄; 깄; 깄; 깄; ) HANGUL SYLLABLE GISS +AE45;AE45;1100 1175 11BC;AE45;1100 1175 11BC; # (깅; 깅; 깅; 깅; 깅; ) HANGUL SYLLABLE GING +AE46;AE46;1100 1175 11BD;AE46;1100 1175 11BD; # (깆; 깆; 깆; 깆; 깆; ) HANGUL SYLLABLE GIJ +AE47;AE47;1100 1175 11BE;AE47;1100 1175 11BE; # (깇; 깇; 깇; 깇; 깇; ) HANGUL SYLLABLE GIC +AE48;AE48;1100 1175 11BF;AE48;1100 1175 11BF; # (깈; 깈; 깈; 깈; 깈; ) HANGUL SYLLABLE GIK +AE49;AE49;1100 1175 11C0;AE49;1100 1175 11C0; # (깉; 깉; 깉; 깉; 깉; ) HANGUL SYLLABLE GIT +AE4A;AE4A;1100 1175 11C1;AE4A;1100 1175 11C1; # (깊; 깊; 깊; 깊; 깊; ) HANGUL SYLLABLE GIP +AE4B;AE4B;1100 1175 11C2;AE4B;1100 1175 11C2; # (깋; 깋; 깋; 깋; 깋; ) HANGUL SYLLABLE GIH +AE4C;AE4C;1101 1161;AE4C;1101 1161; # (까; 까; 까; 까; 까; ) HANGUL SYLLABLE GGA +AE4D;AE4D;1101 1161 11A8;AE4D;1101 1161 11A8; # (깍; 깍; 깍; 깍; 깍; ) HANGUL SYLLABLE GGAG +AE4E;AE4E;1101 1161 11A9;AE4E;1101 1161 11A9; # (깎; 깎; 깎; 깎; 깎; ) HANGUL SYLLABLE GGAGG +AE4F;AE4F;1101 1161 11AA;AE4F;1101 1161 11AA; # (깏; 깏; 깏; 깏; 깏; ) HANGUL SYLLABLE GGAGS +AE50;AE50;1101 1161 11AB;AE50;1101 1161 11AB; # (깐; 깐; 깐; 깐; 깐; ) HANGUL SYLLABLE GGAN +AE51;AE51;1101 1161 11AC;AE51;1101 1161 11AC; # (깑; 깑; 깑; 깑; 깑; ) HANGUL SYLLABLE GGANJ +AE52;AE52;1101 1161 11AD;AE52;1101 1161 11AD; # (깒; 깒; 깒; 깒; 깒; ) HANGUL SYLLABLE GGANH +AE53;AE53;1101 1161 11AE;AE53;1101 1161 11AE; # (깓; 깓; 깓; 깓; 깓; ) HANGUL SYLLABLE GGAD +AE54;AE54;1101 1161 11AF;AE54;1101 1161 11AF; # (깔; 깔; 깔; 깔; 깔; ) HANGUL SYLLABLE GGAL +AE55;AE55;1101 1161 11B0;AE55;1101 1161 11B0; # (깕; 깕; 깕; 깕; 깕; ) HANGUL SYLLABLE GGALG +AE56;AE56;1101 1161 11B1;AE56;1101 1161 11B1; # (깖; 깖; 깖; 깖; 깖; ) HANGUL SYLLABLE GGALM +AE57;AE57;1101 1161 11B2;AE57;1101 1161 11B2; # (깗; 깗; 깗; 깗; 깗; ) HANGUL SYLLABLE GGALB +AE58;AE58;1101 1161 11B3;AE58;1101 1161 11B3; # (깘; 깘; 깘; 깘; 깘; ) HANGUL SYLLABLE GGALS +AE59;AE59;1101 1161 11B4;AE59;1101 1161 11B4; # (깙; 깙; 깙; 깙; 깙; ) HANGUL SYLLABLE GGALT +AE5A;AE5A;1101 1161 11B5;AE5A;1101 1161 11B5; # (깚; 깚; 깚; 깚; 깚; ) HANGUL SYLLABLE GGALP +AE5B;AE5B;1101 1161 11B6;AE5B;1101 1161 11B6; # (깛; 깛; 깛; 깛; 깛; ) HANGUL SYLLABLE GGALH +AE5C;AE5C;1101 1161 11B7;AE5C;1101 1161 11B7; # (깜; 깜; 깜; 깜; 깜; ) HANGUL SYLLABLE GGAM +AE5D;AE5D;1101 1161 11B8;AE5D;1101 1161 11B8; # (깝; 깝; 깝; 깝; 깝; ) HANGUL SYLLABLE GGAB +AE5E;AE5E;1101 1161 11B9;AE5E;1101 1161 11B9; # (깞; 깞; 깞; 깞; 깞; ) HANGUL SYLLABLE GGABS +AE5F;AE5F;1101 1161 11BA;AE5F;1101 1161 11BA; # (깟; 깟; 깟; 깟; 깟; ) HANGUL SYLLABLE GGAS +AE60;AE60;1101 1161 11BB;AE60;1101 1161 11BB; # (깠; 깠; 깠; 깠; 깠; ) HANGUL SYLLABLE GGASS +AE61;AE61;1101 1161 11BC;AE61;1101 1161 11BC; # (깡; 깡; 깡; 깡; 깡; ) HANGUL SYLLABLE GGANG +AE62;AE62;1101 1161 11BD;AE62;1101 1161 11BD; # (깢; 깢; 깢; 깢; 깢; ) HANGUL SYLLABLE GGAJ +AE63;AE63;1101 1161 11BE;AE63;1101 1161 11BE; # (깣; 깣; 깣; 깣; 깣; ) HANGUL SYLLABLE GGAC +AE64;AE64;1101 1161 11BF;AE64;1101 1161 11BF; # (깤; 깤; 깤; 깤; 깤; ) HANGUL SYLLABLE GGAK +AE65;AE65;1101 1161 11C0;AE65;1101 1161 11C0; # (깥; 깥; 깥; 깥; 깥; ) HANGUL SYLLABLE GGAT +AE66;AE66;1101 1161 11C1;AE66;1101 1161 11C1; # (깦; 깦; 깦; 깦; 깦; ) HANGUL SYLLABLE GGAP +AE67;AE67;1101 1161 11C2;AE67;1101 1161 11C2; # (깧; 깧; 깧; 깧; 깧; ) HANGUL SYLLABLE GGAH +AE68;AE68;1101 1162;AE68;1101 1162; # (깨; 깨; 깨; 깨; 깨; ) HANGUL SYLLABLE GGAE +AE69;AE69;1101 1162 11A8;AE69;1101 1162 11A8; # (깩; 깩; 깩; 깩; 깩; ) HANGUL SYLLABLE GGAEG +AE6A;AE6A;1101 1162 11A9;AE6A;1101 1162 11A9; # (깪; 깪; 깪; 깪; 깪; ) HANGUL SYLLABLE GGAEGG +AE6B;AE6B;1101 1162 11AA;AE6B;1101 1162 11AA; # (깫; 깫; 깫; 깫; 깫; ) HANGUL SYLLABLE GGAEGS +AE6C;AE6C;1101 1162 11AB;AE6C;1101 1162 11AB; # (깬; 깬; 깬; 깬; 깬; ) HANGUL SYLLABLE GGAEN +AE6D;AE6D;1101 1162 11AC;AE6D;1101 1162 11AC; # (깭; 깭; 깭; 깭; 깭; ) HANGUL SYLLABLE GGAENJ +AE6E;AE6E;1101 1162 11AD;AE6E;1101 1162 11AD; # (깮; 깮; 깮; 깮; 깮; ) HANGUL SYLLABLE GGAENH +AE6F;AE6F;1101 1162 11AE;AE6F;1101 1162 11AE; # (깯; 깯; 깯; 깯; 깯; ) HANGUL SYLLABLE GGAED +AE70;AE70;1101 1162 11AF;AE70;1101 1162 11AF; # (깰; 깰; 깰; 깰; 깰; ) HANGUL SYLLABLE GGAEL +AE71;AE71;1101 1162 11B0;AE71;1101 1162 11B0; # (깱; 깱; 깱; 깱; 깱; ) HANGUL SYLLABLE GGAELG +AE72;AE72;1101 1162 11B1;AE72;1101 1162 11B1; # (깲; 깲; 깲; 깲; 깲; ) HANGUL SYLLABLE GGAELM +AE73;AE73;1101 1162 11B2;AE73;1101 1162 11B2; # (깳; 깳; 깳; 깳; 깳; ) HANGUL SYLLABLE GGAELB +AE74;AE74;1101 1162 11B3;AE74;1101 1162 11B3; # (깴; 깴; 깴; 깴; 깴; ) HANGUL SYLLABLE GGAELS +AE75;AE75;1101 1162 11B4;AE75;1101 1162 11B4; # (깵; 깵; 깵; 깵; 깵; ) HANGUL SYLLABLE GGAELT +AE76;AE76;1101 1162 11B5;AE76;1101 1162 11B5; # (깶; 깶; 깶; 깶; 깶; ) HANGUL SYLLABLE GGAELP +AE77;AE77;1101 1162 11B6;AE77;1101 1162 11B6; # (깷; 깷; 깷; 깷; 깷; ) HANGUL SYLLABLE GGAELH +AE78;AE78;1101 1162 11B7;AE78;1101 1162 11B7; # (깸; 깸; 깸; 깸; 깸; ) HANGUL SYLLABLE GGAEM +AE79;AE79;1101 1162 11B8;AE79;1101 1162 11B8; # (깹; 깹; 깹; 깹; 깹; ) HANGUL SYLLABLE GGAEB +AE7A;AE7A;1101 1162 11B9;AE7A;1101 1162 11B9; # (깺; 깺; 깺; 깺; 깺; ) HANGUL SYLLABLE GGAEBS +AE7B;AE7B;1101 1162 11BA;AE7B;1101 1162 11BA; # (깻; 깻; 깻; 깻; 깻; ) HANGUL SYLLABLE GGAES +AE7C;AE7C;1101 1162 11BB;AE7C;1101 1162 11BB; # (깼; 깼; 깼; 깼; 깼; ) HANGUL SYLLABLE GGAESS +AE7D;AE7D;1101 1162 11BC;AE7D;1101 1162 11BC; # (깽; 깽; 깽; 깽; 깽; ) HANGUL SYLLABLE GGAENG +AE7E;AE7E;1101 1162 11BD;AE7E;1101 1162 11BD; # (깾; 깾; 깾; 깾; 깾; ) HANGUL SYLLABLE GGAEJ +AE7F;AE7F;1101 1162 11BE;AE7F;1101 1162 11BE; # (깿; 깿; 깿; 깿; 깿; ) HANGUL SYLLABLE GGAEC +AE80;AE80;1101 1162 11BF;AE80;1101 1162 11BF; # (꺀; 꺀; 꺀; 꺀; 꺀; ) HANGUL SYLLABLE GGAEK +AE81;AE81;1101 1162 11C0;AE81;1101 1162 11C0; # (꺁; 꺁; 꺁; 꺁; 꺁; ) HANGUL SYLLABLE GGAET +AE82;AE82;1101 1162 11C1;AE82;1101 1162 11C1; # (꺂; 꺂; 꺂; 꺂; 꺂; ) HANGUL SYLLABLE GGAEP +AE83;AE83;1101 1162 11C2;AE83;1101 1162 11C2; # (꺃; 꺃; 꺃; 꺃; 꺃; ) HANGUL SYLLABLE GGAEH +AE84;AE84;1101 1163;AE84;1101 1163; # (꺄; 꺄; 꺄; 꺄; 꺄; ) HANGUL SYLLABLE GGYA +AE85;AE85;1101 1163 11A8;AE85;1101 1163 11A8; # (꺅; 꺅; 꺅; 꺅; 꺅; ) HANGUL SYLLABLE GGYAG +AE86;AE86;1101 1163 11A9;AE86;1101 1163 11A9; # (꺆; 꺆; 꺆; 꺆; 꺆; ) HANGUL SYLLABLE GGYAGG +AE87;AE87;1101 1163 11AA;AE87;1101 1163 11AA; # (꺇; 꺇; 꺇; 꺇; 꺇; ) HANGUL SYLLABLE GGYAGS +AE88;AE88;1101 1163 11AB;AE88;1101 1163 11AB; # (꺈; 꺈; 꺈; 꺈; 꺈; ) HANGUL SYLLABLE GGYAN +AE89;AE89;1101 1163 11AC;AE89;1101 1163 11AC; # (꺉; 꺉; 꺉; 꺉; 꺉; ) HANGUL SYLLABLE GGYANJ +AE8A;AE8A;1101 1163 11AD;AE8A;1101 1163 11AD; # (꺊; 꺊; 꺊; 꺊; 꺊; ) HANGUL SYLLABLE GGYANH +AE8B;AE8B;1101 1163 11AE;AE8B;1101 1163 11AE; # (꺋; 꺋; 꺋; 꺋; 꺋; ) HANGUL SYLLABLE GGYAD +AE8C;AE8C;1101 1163 11AF;AE8C;1101 1163 11AF; # (꺌; 꺌; 꺌; 꺌; 꺌; ) HANGUL SYLLABLE GGYAL +AE8D;AE8D;1101 1163 11B0;AE8D;1101 1163 11B0; # (꺍; 꺍; 꺍; 꺍; 꺍; ) HANGUL SYLLABLE GGYALG +AE8E;AE8E;1101 1163 11B1;AE8E;1101 1163 11B1; # (꺎; 꺎; 꺎; 꺎; 꺎; ) HANGUL SYLLABLE GGYALM +AE8F;AE8F;1101 1163 11B2;AE8F;1101 1163 11B2; # (꺏; 꺏; 꺏; 꺏; 꺏; ) HANGUL SYLLABLE GGYALB +AE90;AE90;1101 1163 11B3;AE90;1101 1163 11B3; # (꺐; 꺐; 꺐; 꺐; 꺐; ) HANGUL SYLLABLE GGYALS +AE91;AE91;1101 1163 11B4;AE91;1101 1163 11B4; # (꺑; 꺑; 꺑; 꺑; 꺑; ) HANGUL SYLLABLE GGYALT +AE92;AE92;1101 1163 11B5;AE92;1101 1163 11B5; # (꺒; 꺒; 꺒; 꺒; 꺒; ) HANGUL SYLLABLE GGYALP +AE93;AE93;1101 1163 11B6;AE93;1101 1163 11B6; # (꺓; 꺓; 꺓; 꺓; 꺓; ) HANGUL SYLLABLE GGYALH +AE94;AE94;1101 1163 11B7;AE94;1101 1163 11B7; # (꺔; 꺔; 꺔; 꺔; 꺔; ) HANGUL SYLLABLE GGYAM +AE95;AE95;1101 1163 11B8;AE95;1101 1163 11B8; # (꺕; 꺕; 꺕; 꺕; 꺕; ) HANGUL SYLLABLE GGYAB +AE96;AE96;1101 1163 11B9;AE96;1101 1163 11B9; # (꺖; 꺖; 꺖; 꺖; 꺖; ) HANGUL SYLLABLE GGYABS +AE97;AE97;1101 1163 11BA;AE97;1101 1163 11BA; # (꺗; 꺗; 꺗; 꺗; 꺗; ) HANGUL SYLLABLE GGYAS +AE98;AE98;1101 1163 11BB;AE98;1101 1163 11BB; # (꺘; 꺘; 꺘; 꺘; 꺘; ) HANGUL SYLLABLE GGYASS +AE99;AE99;1101 1163 11BC;AE99;1101 1163 11BC; # (꺙; 꺙; 꺙; 꺙; 꺙; ) HANGUL SYLLABLE GGYANG +AE9A;AE9A;1101 1163 11BD;AE9A;1101 1163 11BD; # (꺚; 꺚; 꺚; 꺚; 꺚; ) HANGUL SYLLABLE GGYAJ +AE9B;AE9B;1101 1163 11BE;AE9B;1101 1163 11BE; # (꺛; 꺛; 꺛; 꺛; 꺛; ) HANGUL SYLLABLE GGYAC +AE9C;AE9C;1101 1163 11BF;AE9C;1101 1163 11BF; # (꺜; 꺜; 꺜; 꺜; 꺜; ) HANGUL SYLLABLE GGYAK +AE9D;AE9D;1101 1163 11C0;AE9D;1101 1163 11C0; # (꺝; 꺝; 꺝; 꺝; 꺝; ) HANGUL SYLLABLE GGYAT +AE9E;AE9E;1101 1163 11C1;AE9E;1101 1163 11C1; # (꺞; 꺞; 꺞; 꺞; 꺞; ) HANGUL SYLLABLE GGYAP +AE9F;AE9F;1101 1163 11C2;AE9F;1101 1163 11C2; # (꺟; 꺟; 꺟; 꺟; 꺟; ) HANGUL SYLLABLE GGYAH +AEA0;AEA0;1101 1164;AEA0;1101 1164; # (꺠; 꺠; 꺠; 꺠; 꺠; ) HANGUL SYLLABLE GGYAE +AEA1;AEA1;1101 1164 11A8;AEA1;1101 1164 11A8; # (꺡; 꺡; 꺡; 꺡; 꺡; ) HANGUL SYLLABLE GGYAEG +AEA2;AEA2;1101 1164 11A9;AEA2;1101 1164 11A9; # (꺢; 꺢; 꺢; 꺢; 꺢; ) HANGUL SYLLABLE GGYAEGG +AEA3;AEA3;1101 1164 11AA;AEA3;1101 1164 11AA; # (꺣; 꺣; 꺣; 꺣; 꺣; ) HANGUL SYLLABLE GGYAEGS +AEA4;AEA4;1101 1164 11AB;AEA4;1101 1164 11AB; # (꺤; 꺤; 꺤; 꺤; 꺤; ) HANGUL SYLLABLE GGYAEN +AEA5;AEA5;1101 1164 11AC;AEA5;1101 1164 11AC; # (꺥; 꺥; 꺥; 꺥; 꺥; ) HANGUL SYLLABLE GGYAENJ +AEA6;AEA6;1101 1164 11AD;AEA6;1101 1164 11AD; # (꺦; 꺦; 꺦; 꺦; 꺦; ) HANGUL SYLLABLE GGYAENH +AEA7;AEA7;1101 1164 11AE;AEA7;1101 1164 11AE; # (꺧; 꺧; 꺧; 꺧; 꺧; ) HANGUL SYLLABLE GGYAED +AEA8;AEA8;1101 1164 11AF;AEA8;1101 1164 11AF; # (꺨; 꺨; 꺨; 꺨; 꺨; ) HANGUL SYLLABLE GGYAEL +AEA9;AEA9;1101 1164 11B0;AEA9;1101 1164 11B0; # (꺩; 꺩; 꺩; 꺩; 꺩; ) HANGUL SYLLABLE GGYAELG +AEAA;AEAA;1101 1164 11B1;AEAA;1101 1164 11B1; # (꺪; 꺪; 꺪; 꺪; 꺪; ) HANGUL SYLLABLE GGYAELM +AEAB;AEAB;1101 1164 11B2;AEAB;1101 1164 11B2; # (꺫; 꺫; 꺫; 꺫; 꺫; ) HANGUL SYLLABLE GGYAELB +AEAC;AEAC;1101 1164 11B3;AEAC;1101 1164 11B3; # (꺬; 꺬; 꺬; 꺬; 꺬; ) HANGUL SYLLABLE GGYAELS +AEAD;AEAD;1101 1164 11B4;AEAD;1101 1164 11B4; # (꺭; 꺭; 꺭; 꺭; 꺭; ) HANGUL SYLLABLE GGYAELT +AEAE;AEAE;1101 1164 11B5;AEAE;1101 1164 11B5; # (꺮; 꺮; 꺮; 꺮; 꺮; ) HANGUL SYLLABLE GGYAELP +AEAF;AEAF;1101 1164 11B6;AEAF;1101 1164 11B6; # (꺯; 꺯; 꺯; 꺯; 꺯; ) HANGUL SYLLABLE GGYAELH +AEB0;AEB0;1101 1164 11B7;AEB0;1101 1164 11B7; # (꺰; 꺰; 꺰; 꺰; 꺰; ) HANGUL SYLLABLE GGYAEM +AEB1;AEB1;1101 1164 11B8;AEB1;1101 1164 11B8; # (꺱; 꺱; 꺱; 꺱; 꺱; ) HANGUL SYLLABLE GGYAEB +AEB2;AEB2;1101 1164 11B9;AEB2;1101 1164 11B9; # (꺲; 꺲; 꺲; 꺲; 꺲; ) HANGUL SYLLABLE GGYAEBS +AEB3;AEB3;1101 1164 11BA;AEB3;1101 1164 11BA; # (꺳; 꺳; 꺳; 꺳; 꺳; ) HANGUL SYLLABLE GGYAES +AEB4;AEB4;1101 1164 11BB;AEB4;1101 1164 11BB; # (꺴; 꺴; 꺴; 꺴; 꺴; ) HANGUL SYLLABLE GGYAESS +AEB5;AEB5;1101 1164 11BC;AEB5;1101 1164 11BC; # (꺵; 꺵; 꺵; 꺵; 꺵; ) HANGUL SYLLABLE GGYAENG +AEB6;AEB6;1101 1164 11BD;AEB6;1101 1164 11BD; # (꺶; 꺶; 꺶; 꺶; 꺶; ) HANGUL SYLLABLE GGYAEJ +AEB7;AEB7;1101 1164 11BE;AEB7;1101 1164 11BE; # (꺷; 꺷; 꺷; 꺷; 꺷; ) HANGUL SYLLABLE GGYAEC +AEB8;AEB8;1101 1164 11BF;AEB8;1101 1164 11BF; # (꺸; 꺸; 꺸; 꺸; 꺸; ) HANGUL SYLLABLE GGYAEK +AEB9;AEB9;1101 1164 11C0;AEB9;1101 1164 11C0; # (꺹; 꺹; 꺹; 꺹; 꺹; ) HANGUL SYLLABLE GGYAET +AEBA;AEBA;1101 1164 11C1;AEBA;1101 1164 11C1; # (꺺; 꺺; 꺺; 꺺; 꺺; ) HANGUL SYLLABLE GGYAEP +AEBB;AEBB;1101 1164 11C2;AEBB;1101 1164 11C2; # (꺻; 꺻; 꺻; 꺻; 꺻; ) HANGUL SYLLABLE GGYAEH +AEBC;AEBC;1101 1165;AEBC;1101 1165; # (꺼; 꺼; 꺼; 꺼; 꺼; ) HANGUL SYLLABLE GGEO +AEBD;AEBD;1101 1165 11A8;AEBD;1101 1165 11A8; # (꺽; 꺽; 꺽; 꺽; 꺽; ) HANGUL SYLLABLE GGEOG +AEBE;AEBE;1101 1165 11A9;AEBE;1101 1165 11A9; # (꺾; 꺾; 꺾; 꺾; 꺾; ) HANGUL SYLLABLE GGEOGG +AEBF;AEBF;1101 1165 11AA;AEBF;1101 1165 11AA; # (꺿; 꺿; 꺿; 꺿; 꺿; ) HANGUL SYLLABLE GGEOGS +AEC0;AEC0;1101 1165 11AB;AEC0;1101 1165 11AB; # (껀; 껀; 껀; 껀; 껀; ) HANGUL SYLLABLE GGEON +AEC1;AEC1;1101 1165 11AC;AEC1;1101 1165 11AC; # (껁; 껁; 껁; 껁; 껁; ) HANGUL SYLLABLE GGEONJ +AEC2;AEC2;1101 1165 11AD;AEC2;1101 1165 11AD; # (껂; 껂; 껂; 껂; 껂; ) HANGUL SYLLABLE GGEONH +AEC3;AEC3;1101 1165 11AE;AEC3;1101 1165 11AE; # (껃; 껃; 껃; 껃; 껃; ) HANGUL SYLLABLE GGEOD +AEC4;AEC4;1101 1165 11AF;AEC4;1101 1165 11AF; # (껄; 껄; 껄; 껄; 껄; ) HANGUL SYLLABLE GGEOL +AEC5;AEC5;1101 1165 11B0;AEC5;1101 1165 11B0; # (껅; 껅; 껅; 껅; 껅; ) HANGUL SYLLABLE GGEOLG +AEC6;AEC6;1101 1165 11B1;AEC6;1101 1165 11B1; # (껆; 껆; 껆; 껆; 껆; ) HANGUL SYLLABLE GGEOLM +AEC7;AEC7;1101 1165 11B2;AEC7;1101 1165 11B2; # (껇; 껇; 껇; 껇; 껇; ) HANGUL SYLLABLE GGEOLB +AEC8;AEC8;1101 1165 11B3;AEC8;1101 1165 11B3; # (껈; 껈; 껈; 껈; 껈; ) HANGUL SYLLABLE GGEOLS +AEC9;AEC9;1101 1165 11B4;AEC9;1101 1165 11B4; # (껉; 껉; 껉; 껉; 껉; ) HANGUL SYLLABLE GGEOLT +AECA;AECA;1101 1165 11B5;AECA;1101 1165 11B5; # (껊; 껊; 껊; 껊; 껊; ) HANGUL SYLLABLE GGEOLP +AECB;AECB;1101 1165 11B6;AECB;1101 1165 11B6; # (껋; 껋; 껋; 껋; 껋; ) HANGUL SYLLABLE GGEOLH +AECC;AECC;1101 1165 11B7;AECC;1101 1165 11B7; # (껌; 껌; 껌; 껌; 껌; ) HANGUL SYLLABLE GGEOM +AECD;AECD;1101 1165 11B8;AECD;1101 1165 11B8; # (껍; 껍; 껍; 껍; 껍; ) HANGUL SYLLABLE GGEOB +AECE;AECE;1101 1165 11B9;AECE;1101 1165 11B9; # (껎; 껎; 껎; 껎; 껎; ) HANGUL SYLLABLE GGEOBS +AECF;AECF;1101 1165 11BA;AECF;1101 1165 11BA; # (껏; 껏; 껏; 껏; 껏; ) HANGUL SYLLABLE GGEOS +AED0;AED0;1101 1165 11BB;AED0;1101 1165 11BB; # (껐; 껐; 껐; 껐; 껐; ) HANGUL SYLLABLE GGEOSS +AED1;AED1;1101 1165 11BC;AED1;1101 1165 11BC; # (껑; 껑; 껑; 껑; 껑; ) HANGUL SYLLABLE GGEONG +AED2;AED2;1101 1165 11BD;AED2;1101 1165 11BD; # (껒; 껒; 껒; 껒; 껒; ) HANGUL SYLLABLE GGEOJ +AED3;AED3;1101 1165 11BE;AED3;1101 1165 11BE; # (껓; 껓; 껓; 껓; 껓; ) HANGUL SYLLABLE GGEOC +AED4;AED4;1101 1165 11BF;AED4;1101 1165 11BF; # (껔; 껔; 껔; 껔; 껔; ) HANGUL SYLLABLE GGEOK +AED5;AED5;1101 1165 11C0;AED5;1101 1165 11C0; # (껕; 껕; 껕; 껕; 껕; ) HANGUL SYLLABLE GGEOT +AED6;AED6;1101 1165 11C1;AED6;1101 1165 11C1; # (껖; 껖; 껖; 껖; 껖; ) HANGUL SYLLABLE GGEOP +AED7;AED7;1101 1165 11C2;AED7;1101 1165 11C2; # (껗; 껗; 껗; 껗; 껗; ) HANGUL SYLLABLE GGEOH +AED8;AED8;1101 1166;AED8;1101 1166; # (께; 께; 께; 께; 께; ) HANGUL SYLLABLE GGE +AED9;AED9;1101 1166 11A8;AED9;1101 1166 11A8; # (껙; 껙; 껙; 껙; 껙; ) HANGUL SYLLABLE GGEG +AEDA;AEDA;1101 1166 11A9;AEDA;1101 1166 11A9; # (껚; 껚; 껚; 껚; 껚; ) HANGUL SYLLABLE GGEGG +AEDB;AEDB;1101 1166 11AA;AEDB;1101 1166 11AA; # (껛; 껛; 껛; 껛; 껛; ) HANGUL SYLLABLE GGEGS +AEDC;AEDC;1101 1166 11AB;AEDC;1101 1166 11AB; # (껜; 껜; 껜; 껜; 껜; ) HANGUL SYLLABLE GGEN +AEDD;AEDD;1101 1166 11AC;AEDD;1101 1166 11AC; # (껝; 껝; 껝; 껝; 껝; ) HANGUL SYLLABLE GGENJ +AEDE;AEDE;1101 1166 11AD;AEDE;1101 1166 11AD; # (껞; 껞; 껞; 껞; 껞; ) HANGUL SYLLABLE GGENH +AEDF;AEDF;1101 1166 11AE;AEDF;1101 1166 11AE; # (껟; 껟; 껟; 껟; 껟; ) HANGUL SYLLABLE GGED +AEE0;AEE0;1101 1166 11AF;AEE0;1101 1166 11AF; # (껠; 껠; 껠; 껠; 껠; ) HANGUL SYLLABLE GGEL +AEE1;AEE1;1101 1166 11B0;AEE1;1101 1166 11B0; # (껡; 껡; 껡; 껡; 껡; ) HANGUL SYLLABLE GGELG +AEE2;AEE2;1101 1166 11B1;AEE2;1101 1166 11B1; # (껢; 껢; 껢; 껢; 껢; ) HANGUL SYLLABLE GGELM +AEE3;AEE3;1101 1166 11B2;AEE3;1101 1166 11B2; # (껣; 껣; 껣; 껣; 껣; ) HANGUL SYLLABLE GGELB +AEE4;AEE4;1101 1166 11B3;AEE4;1101 1166 11B3; # (껤; 껤; 껤; 껤; 껤; ) HANGUL SYLLABLE GGELS +AEE5;AEE5;1101 1166 11B4;AEE5;1101 1166 11B4; # (껥; 껥; 껥; 껥; 껥; ) HANGUL SYLLABLE GGELT +AEE6;AEE6;1101 1166 11B5;AEE6;1101 1166 11B5; # (껦; 껦; 껦; 껦; 껦; ) HANGUL SYLLABLE GGELP +AEE7;AEE7;1101 1166 11B6;AEE7;1101 1166 11B6; # (껧; 껧; 껧; 껧; 껧; ) HANGUL SYLLABLE GGELH +AEE8;AEE8;1101 1166 11B7;AEE8;1101 1166 11B7; # (껨; 껨; 껨; 껨; 껨; ) HANGUL SYLLABLE GGEM +AEE9;AEE9;1101 1166 11B8;AEE9;1101 1166 11B8; # (껩; 껩; 껩; 껩; 껩; ) HANGUL SYLLABLE GGEB +AEEA;AEEA;1101 1166 11B9;AEEA;1101 1166 11B9; # (껪; 껪; 껪; 껪; 껪; ) HANGUL SYLLABLE GGEBS +AEEB;AEEB;1101 1166 11BA;AEEB;1101 1166 11BA; # (껫; 껫; 껫; 껫; 껫; ) HANGUL SYLLABLE GGES +AEEC;AEEC;1101 1166 11BB;AEEC;1101 1166 11BB; # (껬; 껬; 껬; 껬; 껬; ) HANGUL SYLLABLE GGESS +AEED;AEED;1101 1166 11BC;AEED;1101 1166 11BC; # (껭; 껭; 껭; 껭; 껭; ) HANGUL SYLLABLE GGENG +AEEE;AEEE;1101 1166 11BD;AEEE;1101 1166 11BD; # (껮; 껮; 껮; 껮; 껮; ) HANGUL SYLLABLE GGEJ +AEEF;AEEF;1101 1166 11BE;AEEF;1101 1166 11BE; # (껯; 껯; 껯; 껯; 껯; ) HANGUL SYLLABLE GGEC +AEF0;AEF0;1101 1166 11BF;AEF0;1101 1166 11BF; # (껰; 껰; 껰; 껰; 껰; ) HANGUL SYLLABLE GGEK +AEF1;AEF1;1101 1166 11C0;AEF1;1101 1166 11C0; # (껱; 껱; 껱; 껱; 껱; ) HANGUL SYLLABLE GGET +AEF2;AEF2;1101 1166 11C1;AEF2;1101 1166 11C1; # (껲; 껲; 껲; 껲; 껲; ) HANGUL SYLLABLE GGEP +AEF3;AEF3;1101 1166 11C2;AEF3;1101 1166 11C2; # (껳; 껳; 껳; 껳; 껳; ) HANGUL SYLLABLE GGEH +AEF4;AEF4;1101 1167;AEF4;1101 1167; # (껴; 껴; 껴; 껴; 껴; ) HANGUL SYLLABLE GGYEO +AEF5;AEF5;1101 1167 11A8;AEF5;1101 1167 11A8; # (껵; 껵; 껵; 껵; 껵; ) HANGUL SYLLABLE GGYEOG +AEF6;AEF6;1101 1167 11A9;AEF6;1101 1167 11A9; # (껶; 껶; 껶; 껶; 껶; ) HANGUL SYLLABLE GGYEOGG +AEF7;AEF7;1101 1167 11AA;AEF7;1101 1167 11AA; # (껷; 껷; 껷; 껷; 껷; ) HANGUL SYLLABLE GGYEOGS +AEF8;AEF8;1101 1167 11AB;AEF8;1101 1167 11AB; # (껸; 껸; 껸; 껸; 껸; ) HANGUL SYLLABLE GGYEON +AEF9;AEF9;1101 1167 11AC;AEF9;1101 1167 11AC; # (껹; 껹; 껹; 껹; 껹; ) HANGUL SYLLABLE GGYEONJ +AEFA;AEFA;1101 1167 11AD;AEFA;1101 1167 11AD; # (껺; 껺; 껺; 껺; 껺; ) HANGUL SYLLABLE GGYEONH +AEFB;AEFB;1101 1167 11AE;AEFB;1101 1167 11AE; # (껻; 껻; 껻; 껻; 껻; ) HANGUL SYLLABLE GGYEOD +AEFC;AEFC;1101 1167 11AF;AEFC;1101 1167 11AF; # (껼; 껼; 껼; 껼; 껼; ) HANGUL SYLLABLE GGYEOL +AEFD;AEFD;1101 1167 11B0;AEFD;1101 1167 11B0; # (껽; 껽; 껽; 껽; 껽; ) HANGUL SYLLABLE GGYEOLG +AEFE;AEFE;1101 1167 11B1;AEFE;1101 1167 11B1; # (껾; 껾; 껾; 껾; 껾; ) HANGUL SYLLABLE GGYEOLM +AEFF;AEFF;1101 1167 11B2;AEFF;1101 1167 11B2; # (껿; 껿; 껿; 껿; 껿; ) HANGUL SYLLABLE GGYEOLB +AF00;AF00;1101 1167 11B3;AF00;1101 1167 11B3; # (꼀; 꼀; 꼀; 꼀; 꼀; ) HANGUL SYLLABLE GGYEOLS +AF01;AF01;1101 1167 11B4;AF01;1101 1167 11B4; # (꼁; 꼁; 꼁; 꼁; 꼁; ) HANGUL SYLLABLE GGYEOLT +AF02;AF02;1101 1167 11B5;AF02;1101 1167 11B5; # (꼂; 꼂; 꼂; 꼂; 꼂; ) HANGUL SYLLABLE GGYEOLP +AF03;AF03;1101 1167 11B6;AF03;1101 1167 11B6; # (꼃; 꼃; 꼃; 꼃; 꼃; ) HANGUL SYLLABLE GGYEOLH +AF04;AF04;1101 1167 11B7;AF04;1101 1167 11B7; # (꼄; 꼄; 꼄; 꼄; 꼄; ) HANGUL SYLLABLE GGYEOM +AF05;AF05;1101 1167 11B8;AF05;1101 1167 11B8; # (꼅; 꼅; 꼅; 꼅; 꼅; ) HANGUL SYLLABLE GGYEOB +AF06;AF06;1101 1167 11B9;AF06;1101 1167 11B9; # (꼆; 꼆; 꼆; 꼆; 꼆; ) HANGUL SYLLABLE GGYEOBS +AF07;AF07;1101 1167 11BA;AF07;1101 1167 11BA; # (꼇; 꼇; 꼇; 꼇; 꼇; ) HANGUL SYLLABLE GGYEOS +AF08;AF08;1101 1167 11BB;AF08;1101 1167 11BB; # (꼈; 꼈; 꼈; 꼈; 꼈; ) HANGUL SYLLABLE GGYEOSS +AF09;AF09;1101 1167 11BC;AF09;1101 1167 11BC; # (꼉; 꼉; 꼉; 꼉; 꼉; ) HANGUL SYLLABLE GGYEONG +AF0A;AF0A;1101 1167 11BD;AF0A;1101 1167 11BD; # (꼊; 꼊; 꼊; 꼊; 꼊; ) HANGUL SYLLABLE GGYEOJ +AF0B;AF0B;1101 1167 11BE;AF0B;1101 1167 11BE; # (꼋; 꼋; 꼋; 꼋; 꼋; ) HANGUL SYLLABLE GGYEOC +AF0C;AF0C;1101 1167 11BF;AF0C;1101 1167 11BF; # (꼌; 꼌; 꼌; 꼌; 꼌; ) HANGUL SYLLABLE GGYEOK +AF0D;AF0D;1101 1167 11C0;AF0D;1101 1167 11C0; # (꼍; 꼍; 꼍; 꼍; 꼍; ) HANGUL SYLLABLE GGYEOT +AF0E;AF0E;1101 1167 11C1;AF0E;1101 1167 11C1; # (꼎; 꼎; 꼎; 꼎; 꼎; ) HANGUL SYLLABLE GGYEOP +AF0F;AF0F;1101 1167 11C2;AF0F;1101 1167 11C2; # (꼏; 꼏; 꼏; 꼏; 꼏; ) HANGUL SYLLABLE GGYEOH +AF10;AF10;1101 1168;AF10;1101 1168; # (꼐; 꼐; 꼐; 꼐; 꼐; ) HANGUL SYLLABLE GGYE +AF11;AF11;1101 1168 11A8;AF11;1101 1168 11A8; # (꼑; 꼑; 꼑; 꼑; 꼑; ) HANGUL SYLLABLE GGYEG +AF12;AF12;1101 1168 11A9;AF12;1101 1168 11A9; # (꼒; 꼒; 꼒; 꼒; 꼒; ) HANGUL SYLLABLE GGYEGG +AF13;AF13;1101 1168 11AA;AF13;1101 1168 11AA; # (꼓; 꼓; 꼓; 꼓; 꼓; ) HANGUL SYLLABLE GGYEGS +AF14;AF14;1101 1168 11AB;AF14;1101 1168 11AB; # (꼔; 꼔; 꼔; 꼔; 꼔; ) HANGUL SYLLABLE GGYEN +AF15;AF15;1101 1168 11AC;AF15;1101 1168 11AC; # (꼕; 꼕; 꼕; 꼕; 꼕; ) HANGUL SYLLABLE GGYENJ +AF16;AF16;1101 1168 11AD;AF16;1101 1168 11AD; # (꼖; 꼖; 꼖; 꼖; 꼖; ) HANGUL SYLLABLE GGYENH +AF17;AF17;1101 1168 11AE;AF17;1101 1168 11AE; # (꼗; 꼗; 꼗; 꼗; 꼗; ) HANGUL SYLLABLE GGYED +AF18;AF18;1101 1168 11AF;AF18;1101 1168 11AF; # (꼘; 꼘; 꼘; 꼘; 꼘; ) HANGUL SYLLABLE GGYEL +AF19;AF19;1101 1168 11B0;AF19;1101 1168 11B0; # (꼙; 꼙; 꼙; 꼙; 꼙; ) HANGUL SYLLABLE GGYELG +AF1A;AF1A;1101 1168 11B1;AF1A;1101 1168 11B1; # (꼚; 꼚; 꼚; 꼚; 꼚; ) HANGUL SYLLABLE GGYELM +AF1B;AF1B;1101 1168 11B2;AF1B;1101 1168 11B2; # (꼛; 꼛; 꼛; 꼛; 꼛; ) HANGUL SYLLABLE GGYELB +AF1C;AF1C;1101 1168 11B3;AF1C;1101 1168 11B3; # (꼜; 꼜; 꼜; 꼜; 꼜; ) HANGUL SYLLABLE GGYELS +AF1D;AF1D;1101 1168 11B4;AF1D;1101 1168 11B4; # (꼝; 꼝; 꼝; 꼝; 꼝; ) HANGUL SYLLABLE GGYELT +AF1E;AF1E;1101 1168 11B5;AF1E;1101 1168 11B5; # (꼞; 꼞; 꼞; 꼞; 꼞; ) HANGUL SYLLABLE GGYELP +AF1F;AF1F;1101 1168 11B6;AF1F;1101 1168 11B6; # (꼟; 꼟; 꼟; 꼟; 꼟; ) HANGUL SYLLABLE GGYELH +AF20;AF20;1101 1168 11B7;AF20;1101 1168 11B7; # (꼠; 꼠; 꼠; 꼠; 꼠; ) HANGUL SYLLABLE GGYEM +AF21;AF21;1101 1168 11B8;AF21;1101 1168 11B8; # (꼡; 꼡; 꼡; 꼡; 꼡; ) HANGUL SYLLABLE GGYEB +AF22;AF22;1101 1168 11B9;AF22;1101 1168 11B9; # (꼢; 꼢; 꼢; 꼢; 꼢; ) HANGUL SYLLABLE GGYEBS +AF23;AF23;1101 1168 11BA;AF23;1101 1168 11BA; # (꼣; 꼣; 꼣; 꼣; 꼣; ) HANGUL SYLLABLE GGYES +AF24;AF24;1101 1168 11BB;AF24;1101 1168 11BB; # (꼤; 꼤; 꼤; 꼤; 꼤; ) HANGUL SYLLABLE GGYESS +AF25;AF25;1101 1168 11BC;AF25;1101 1168 11BC; # (꼥; 꼥; 꼥; 꼥; 꼥; ) HANGUL SYLLABLE GGYENG +AF26;AF26;1101 1168 11BD;AF26;1101 1168 11BD; # (꼦; 꼦; 꼦; 꼦; 꼦; ) HANGUL SYLLABLE GGYEJ +AF27;AF27;1101 1168 11BE;AF27;1101 1168 11BE; # (꼧; 꼧; 꼧; 꼧; 꼧; ) HANGUL SYLLABLE GGYEC +AF28;AF28;1101 1168 11BF;AF28;1101 1168 11BF; # (꼨; 꼨; 꼨; 꼨; 꼨; ) HANGUL SYLLABLE GGYEK +AF29;AF29;1101 1168 11C0;AF29;1101 1168 11C0; # (꼩; 꼩; 꼩; 꼩; 꼩; ) HANGUL SYLLABLE GGYET +AF2A;AF2A;1101 1168 11C1;AF2A;1101 1168 11C1; # (꼪; 꼪; 꼪; 꼪; 꼪; ) HANGUL SYLLABLE GGYEP +AF2B;AF2B;1101 1168 11C2;AF2B;1101 1168 11C2; # (꼫; 꼫; 꼫; 꼫; 꼫; ) HANGUL SYLLABLE GGYEH +AF2C;AF2C;1101 1169;AF2C;1101 1169; # (꼬; 꼬; 꼬; 꼬; 꼬; ) HANGUL SYLLABLE GGO +AF2D;AF2D;1101 1169 11A8;AF2D;1101 1169 11A8; # (꼭; 꼭; 꼭; 꼭; 꼭; ) HANGUL SYLLABLE GGOG +AF2E;AF2E;1101 1169 11A9;AF2E;1101 1169 11A9; # (꼮; 꼮; 꼮; 꼮; 꼮; ) HANGUL SYLLABLE GGOGG +AF2F;AF2F;1101 1169 11AA;AF2F;1101 1169 11AA; # (꼯; 꼯; 꼯; 꼯; 꼯; ) HANGUL SYLLABLE GGOGS +AF30;AF30;1101 1169 11AB;AF30;1101 1169 11AB; # (꼰; 꼰; 꼰; 꼰; 꼰; ) HANGUL SYLLABLE GGON +AF31;AF31;1101 1169 11AC;AF31;1101 1169 11AC; # (꼱; 꼱; 꼱; 꼱; 꼱; ) HANGUL SYLLABLE GGONJ +AF32;AF32;1101 1169 11AD;AF32;1101 1169 11AD; # (꼲; 꼲; 꼲; 꼲; 꼲; ) HANGUL SYLLABLE GGONH +AF33;AF33;1101 1169 11AE;AF33;1101 1169 11AE; # (꼳; 꼳; 꼳; 꼳; 꼳; ) HANGUL SYLLABLE GGOD +AF34;AF34;1101 1169 11AF;AF34;1101 1169 11AF; # (꼴; 꼴; 꼴; 꼴; 꼴; ) HANGUL SYLLABLE GGOL +AF35;AF35;1101 1169 11B0;AF35;1101 1169 11B0; # (꼵; 꼵; 꼵; 꼵; 꼵; ) HANGUL SYLLABLE GGOLG +AF36;AF36;1101 1169 11B1;AF36;1101 1169 11B1; # (꼶; 꼶; 꼶; 꼶; 꼶; ) HANGUL SYLLABLE GGOLM +AF37;AF37;1101 1169 11B2;AF37;1101 1169 11B2; # (꼷; 꼷; 꼷; 꼷; 꼷; ) HANGUL SYLLABLE GGOLB +AF38;AF38;1101 1169 11B3;AF38;1101 1169 11B3; # (꼸; 꼸; 꼸; 꼸; 꼸; ) HANGUL SYLLABLE GGOLS +AF39;AF39;1101 1169 11B4;AF39;1101 1169 11B4; # (꼹; 꼹; 꼹; 꼹; 꼹; ) HANGUL SYLLABLE GGOLT +AF3A;AF3A;1101 1169 11B5;AF3A;1101 1169 11B5; # (꼺; 꼺; 꼺; 꼺; 꼺; ) HANGUL SYLLABLE GGOLP +AF3B;AF3B;1101 1169 11B6;AF3B;1101 1169 11B6; # (꼻; 꼻; 꼻; 꼻; 꼻; ) HANGUL SYLLABLE GGOLH +AF3C;AF3C;1101 1169 11B7;AF3C;1101 1169 11B7; # (꼼; 꼼; 꼼; 꼼; 꼼; ) HANGUL SYLLABLE GGOM +AF3D;AF3D;1101 1169 11B8;AF3D;1101 1169 11B8; # (꼽; 꼽; 꼽; 꼽; 꼽; ) HANGUL SYLLABLE GGOB +AF3E;AF3E;1101 1169 11B9;AF3E;1101 1169 11B9; # (꼾; 꼾; 꼾; 꼾; 꼾; ) HANGUL SYLLABLE GGOBS +AF3F;AF3F;1101 1169 11BA;AF3F;1101 1169 11BA; # (꼿; 꼿; 꼿; 꼿; 꼿; ) HANGUL SYLLABLE GGOS +AF40;AF40;1101 1169 11BB;AF40;1101 1169 11BB; # (꽀; 꽀; 꽀; 꽀; 꽀; ) HANGUL SYLLABLE GGOSS +AF41;AF41;1101 1169 11BC;AF41;1101 1169 11BC; # (꽁; 꽁; 꽁; 꽁; 꽁; ) HANGUL SYLLABLE GGONG +AF42;AF42;1101 1169 11BD;AF42;1101 1169 11BD; # (꽂; 꽂; 꽂; 꽂; 꽂; ) HANGUL SYLLABLE GGOJ +AF43;AF43;1101 1169 11BE;AF43;1101 1169 11BE; # (꽃; 꽃; 꽃; 꽃; 꽃; ) HANGUL SYLLABLE GGOC +AF44;AF44;1101 1169 11BF;AF44;1101 1169 11BF; # (꽄; 꽄; 꽄; 꽄; 꽄; ) HANGUL SYLLABLE GGOK +AF45;AF45;1101 1169 11C0;AF45;1101 1169 11C0; # (꽅; 꽅; 꽅; 꽅; 꽅; ) HANGUL SYLLABLE GGOT +AF46;AF46;1101 1169 11C1;AF46;1101 1169 11C1; # (꽆; 꽆; 꽆; 꽆; 꽆; ) HANGUL SYLLABLE GGOP +AF47;AF47;1101 1169 11C2;AF47;1101 1169 11C2; # (꽇; 꽇; 꽇; 꽇; 꽇; ) HANGUL SYLLABLE GGOH +AF48;AF48;1101 116A;AF48;1101 116A; # (꽈; 꽈; 꽈; 꽈; 꽈; ) HANGUL SYLLABLE GGWA +AF49;AF49;1101 116A 11A8;AF49;1101 116A 11A8; # (꽉; 꽉; 꽉; 꽉; 꽉; ) HANGUL SYLLABLE GGWAG +AF4A;AF4A;1101 116A 11A9;AF4A;1101 116A 11A9; # (꽊; 꽊; 꽊; 꽊; 꽊; ) HANGUL SYLLABLE GGWAGG +AF4B;AF4B;1101 116A 11AA;AF4B;1101 116A 11AA; # (꽋; 꽋; 꽋; 꽋; 꽋; ) HANGUL SYLLABLE GGWAGS +AF4C;AF4C;1101 116A 11AB;AF4C;1101 116A 11AB; # (꽌; 꽌; 꽌; 꽌; 꽌; ) HANGUL SYLLABLE GGWAN +AF4D;AF4D;1101 116A 11AC;AF4D;1101 116A 11AC; # (꽍; 꽍; 꽍; 꽍; 꽍; ) HANGUL SYLLABLE GGWANJ +AF4E;AF4E;1101 116A 11AD;AF4E;1101 116A 11AD; # (꽎; 꽎; 꽎; 꽎; 꽎; ) HANGUL SYLLABLE GGWANH +AF4F;AF4F;1101 116A 11AE;AF4F;1101 116A 11AE; # (꽏; 꽏; 꽏; 꽏; 꽏; ) HANGUL SYLLABLE GGWAD +AF50;AF50;1101 116A 11AF;AF50;1101 116A 11AF; # (꽐; 꽐; 꽐; 꽐; 꽐; ) HANGUL SYLLABLE GGWAL +AF51;AF51;1101 116A 11B0;AF51;1101 116A 11B0; # (꽑; 꽑; 꽑; 꽑; 꽑; ) HANGUL SYLLABLE GGWALG +AF52;AF52;1101 116A 11B1;AF52;1101 116A 11B1; # (꽒; 꽒; 꽒; 꽒; 꽒; ) HANGUL SYLLABLE GGWALM +AF53;AF53;1101 116A 11B2;AF53;1101 116A 11B2; # (꽓; 꽓; 꽓; 꽓; 꽓; ) HANGUL SYLLABLE GGWALB +AF54;AF54;1101 116A 11B3;AF54;1101 116A 11B3; # (꽔; 꽔; 꽔; 꽔; 꽔; ) HANGUL SYLLABLE GGWALS +AF55;AF55;1101 116A 11B4;AF55;1101 116A 11B4; # (꽕; 꽕; 꽕; 꽕; 꽕; ) HANGUL SYLLABLE GGWALT +AF56;AF56;1101 116A 11B5;AF56;1101 116A 11B5; # (꽖; 꽖; 꽖; 꽖; 꽖; ) HANGUL SYLLABLE GGWALP +AF57;AF57;1101 116A 11B6;AF57;1101 116A 11B6; # (꽗; 꽗; 꽗; 꽗; 꽗; ) HANGUL SYLLABLE GGWALH +AF58;AF58;1101 116A 11B7;AF58;1101 116A 11B7; # (꽘; 꽘; 꽘; 꽘; 꽘; ) HANGUL SYLLABLE GGWAM +AF59;AF59;1101 116A 11B8;AF59;1101 116A 11B8; # (꽙; 꽙; 꽙; 꽙; 꽙; ) HANGUL SYLLABLE GGWAB +AF5A;AF5A;1101 116A 11B9;AF5A;1101 116A 11B9; # (꽚; 꽚; 꽚; 꽚; 꽚; ) HANGUL SYLLABLE GGWABS +AF5B;AF5B;1101 116A 11BA;AF5B;1101 116A 11BA; # (꽛; 꽛; 꽛; 꽛; 꽛; ) HANGUL SYLLABLE GGWAS +AF5C;AF5C;1101 116A 11BB;AF5C;1101 116A 11BB; # (꽜; 꽜; 꽜; 꽜; 꽜; ) HANGUL SYLLABLE GGWASS +AF5D;AF5D;1101 116A 11BC;AF5D;1101 116A 11BC; # (꽝; 꽝; 꽝; 꽝; 꽝; ) HANGUL SYLLABLE GGWANG +AF5E;AF5E;1101 116A 11BD;AF5E;1101 116A 11BD; # (꽞; 꽞; 꽞; 꽞; 꽞; ) HANGUL SYLLABLE GGWAJ +AF5F;AF5F;1101 116A 11BE;AF5F;1101 116A 11BE; # (꽟; 꽟; 꽟; 꽟; 꽟; ) HANGUL SYLLABLE GGWAC +AF60;AF60;1101 116A 11BF;AF60;1101 116A 11BF; # (꽠; 꽠; 꽠; 꽠; 꽠; ) HANGUL SYLLABLE GGWAK +AF61;AF61;1101 116A 11C0;AF61;1101 116A 11C0; # (꽡; 꽡; 꽡; 꽡; 꽡; ) HANGUL SYLLABLE GGWAT +AF62;AF62;1101 116A 11C1;AF62;1101 116A 11C1; # (꽢; 꽢; 꽢; 꽢; 꽢; ) HANGUL SYLLABLE GGWAP +AF63;AF63;1101 116A 11C2;AF63;1101 116A 11C2; # (꽣; 꽣; 꽣; 꽣; 꽣; ) HANGUL SYLLABLE GGWAH +AF64;AF64;1101 116B;AF64;1101 116B; # (꽤; 꽤; 꽤; 꽤; 꽤; ) HANGUL SYLLABLE GGWAE +AF65;AF65;1101 116B 11A8;AF65;1101 116B 11A8; # (꽥; 꽥; 꽥; 꽥; 꽥; ) HANGUL SYLLABLE GGWAEG +AF66;AF66;1101 116B 11A9;AF66;1101 116B 11A9; # (꽦; 꽦; 꽦; 꽦; 꽦; ) HANGUL SYLLABLE GGWAEGG +AF67;AF67;1101 116B 11AA;AF67;1101 116B 11AA; # (꽧; 꽧; 꽧; 꽧; 꽧; ) HANGUL SYLLABLE GGWAEGS +AF68;AF68;1101 116B 11AB;AF68;1101 116B 11AB; # (꽨; 꽨; 꽨; 꽨; 꽨; ) HANGUL SYLLABLE GGWAEN +AF69;AF69;1101 116B 11AC;AF69;1101 116B 11AC; # (꽩; 꽩; 꽩; 꽩; 꽩; ) HANGUL SYLLABLE GGWAENJ +AF6A;AF6A;1101 116B 11AD;AF6A;1101 116B 11AD; # (꽪; 꽪; 꽪; 꽪; 꽪; ) HANGUL SYLLABLE GGWAENH +AF6B;AF6B;1101 116B 11AE;AF6B;1101 116B 11AE; # (꽫; 꽫; 꽫; 꽫; 꽫; ) HANGUL SYLLABLE GGWAED +AF6C;AF6C;1101 116B 11AF;AF6C;1101 116B 11AF; # (꽬; 꽬; 꽬; 꽬; 꽬; ) HANGUL SYLLABLE GGWAEL +AF6D;AF6D;1101 116B 11B0;AF6D;1101 116B 11B0; # (꽭; 꽭; 꽭; 꽭; 꽭; ) HANGUL SYLLABLE GGWAELG +AF6E;AF6E;1101 116B 11B1;AF6E;1101 116B 11B1; # (꽮; 꽮; 꽮; 꽮; 꽮; ) HANGUL SYLLABLE GGWAELM +AF6F;AF6F;1101 116B 11B2;AF6F;1101 116B 11B2; # (꽯; 꽯; 꽯; 꽯; 꽯; ) HANGUL SYLLABLE GGWAELB +AF70;AF70;1101 116B 11B3;AF70;1101 116B 11B3; # (꽰; 꽰; 꽰; 꽰; 꽰; ) HANGUL SYLLABLE GGWAELS +AF71;AF71;1101 116B 11B4;AF71;1101 116B 11B4; # (꽱; 꽱; 꽱; 꽱; 꽱; ) HANGUL SYLLABLE GGWAELT +AF72;AF72;1101 116B 11B5;AF72;1101 116B 11B5; # (꽲; 꽲; 꽲; 꽲; 꽲; ) HANGUL SYLLABLE GGWAELP +AF73;AF73;1101 116B 11B6;AF73;1101 116B 11B6; # (꽳; 꽳; 꽳; 꽳; 꽳; ) HANGUL SYLLABLE GGWAELH +AF74;AF74;1101 116B 11B7;AF74;1101 116B 11B7; # (꽴; 꽴; 꽴; 꽴; 꽴; ) HANGUL SYLLABLE GGWAEM +AF75;AF75;1101 116B 11B8;AF75;1101 116B 11B8; # (꽵; 꽵; 꽵; 꽵; 꽵; ) HANGUL SYLLABLE GGWAEB +AF76;AF76;1101 116B 11B9;AF76;1101 116B 11B9; # (꽶; 꽶; 꽶; 꽶; 꽶; ) HANGUL SYLLABLE GGWAEBS +AF77;AF77;1101 116B 11BA;AF77;1101 116B 11BA; # (꽷; 꽷; 꽷; 꽷; 꽷; ) HANGUL SYLLABLE GGWAES +AF78;AF78;1101 116B 11BB;AF78;1101 116B 11BB; # (꽸; 꽸; 꽸; 꽸; 꽸; ) HANGUL SYLLABLE GGWAESS +AF79;AF79;1101 116B 11BC;AF79;1101 116B 11BC; # (꽹; 꽹; 꽹; 꽹; 꽹; ) HANGUL SYLLABLE GGWAENG +AF7A;AF7A;1101 116B 11BD;AF7A;1101 116B 11BD; # (꽺; 꽺; 꽺; 꽺; 꽺; ) HANGUL SYLLABLE GGWAEJ +AF7B;AF7B;1101 116B 11BE;AF7B;1101 116B 11BE; # (꽻; 꽻; 꽻; 꽻; 꽻; ) HANGUL SYLLABLE GGWAEC +AF7C;AF7C;1101 116B 11BF;AF7C;1101 116B 11BF; # (꽼; 꽼; 꽼; 꽼; 꽼; ) HANGUL SYLLABLE GGWAEK +AF7D;AF7D;1101 116B 11C0;AF7D;1101 116B 11C0; # (꽽; 꽽; 꽽; 꽽; 꽽; ) HANGUL SYLLABLE GGWAET +AF7E;AF7E;1101 116B 11C1;AF7E;1101 116B 11C1; # (꽾; 꽾; 꽾; 꽾; 꽾; ) HANGUL SYLLABLE GGWAEP +AF7F;AF7F;1101 116B 11C2;AF7F;1101 116B 11C2; # (꽿; 꽿; 꽿; 꽿; 꽿; ) HANGUL SYLLABLE GGWAEH +AF80;AF80;1101 116C;AF80;1101 116C; # (꾀; 꾀; 꾀; 꾀; 꾀; ) HANGUL SYLLABLE GGOE +AF81;AF81;1101 116C 11A8;AF81;1101 116C 11A8; # (꾁; 꾁; 꾁; 꾁; 꾁; ) HANGUL SYLLABLE GGOEG +AF82;AF82;1101 116C 11A9;AF82;1101 116C 11A9; # (꾂; 꾂; 꾂; 꾂; 꾂; ) HANGUL SYLLABLE GGOEGG +AF83;AF83;1101 116C 11AA;AF83;1101 116C 11AA; # (꾃; 꾃; 꾃; 꾃; 꾃; ) HANGUL SYLLABLE GGOEGS +AF84;AF84;1101 116C 11AB;AF84;1101 116C 11AB; # (꾄; 꾄; 꾄; 꾄; 꾄; ) HANGUL SYLLABLE GGOEN +AF85;AF85;1101 116C 11AC;AF85;1101 116C 11AC; # (꾅; 꾅; 꾅; 꾅; 꾅; ) HANGUL SYLLABLE GGOENJ +AF86;AF86;1101 116C 11AD;AF86;1101 116C 11AD; # (꾆; 꾆; 꾆; 꾆; 꾆; ) HANGUL SYLLABLE GGOENH +AF87;AF87;1101 116C 11AE;AF87;1101 116C 11AE; # (꾇; 꾇; 꾇; 꾇; 꾇; ) HANGUL SYLLABLE GGOED +AF88;AF88;1101 116C 11AF;AF88;1101 116C 11AF; # (꾈; 꾈; 꾈; 꾈; 꾈; ) HANGUL SYLLABLE GGOEL +AF89;AF89;1101 116C 11B0;AF89;1101 116C 11B0; # (꾉; 꾉; 꾉; 꾉; 꾉; ) HANGUL SYLLABLE GGOELG +AF8A;AF8A;1101 116C 11B1;AF8A;1101 116C 11B1; # (꾊; 꾊; 꾊; 꾊; 꾊; ) HANGUL SYLLABLE GGOELM +AF8B;AF8B;1101 116C 11B2;AF8B;1101 116C 11B2; # (꾋; 꾋; 꾋; 꾋; 꾋; ) HANGUL SYLLABLE GGOELB +AF8C;AF8C;1101 116C 11B3;AF8C;1101 116C 11B3; # (꾌; 꾌; 꾌; 꾌; 꾌; ) HANGUL SYLLABLE GGOELS +AF8D;AF8D;1101 116C 11B4;AF8D;1101 116C 11B4; # (꾍; 꾍; 꾍; 꾍; 꾍; ) HANGUL SYLLABLE GGOELT +AF8E;AF8E;1101 116C 11B5;AF8E;1101 116C 11B5; # (꾎; 꾎; 꾎; 꾎; 꾎; ) HANGUL SYLLABLE GGOELP +AF8F;AF8F;1101 116C 11B6;AF8F;1101 116C 11B6; # (꾏; 꾏; 꾏; 꾏; 꾏; ) HANGUL SYLLABLE GGOELH +AF90;AF90;1101 116C 11B7;AF90;1101 116C 11B7; # (꾐; 꾐; 꾐; 꾐; 꾐; ) HANGUL SYLLABLE GGOEM +AF91;AF91;1101 116C 11B8;AF91;1101 116C 11B8; # (꾑; 꾑; 꾑; 꾑; 꾑; ) HANGUL SYLLABLE GGOEB +AF92;AF92;1101 116C 11B9;AF92;1101 116C 11B9; # (꾒; 꾒; 꾒; 꾒; 꾒; ) HANGUL SYLLABLE GGOEBS +AF93;AF93;1101 116C 11BA;AF93;1101 116C 11BA; # (꾓; 꾓; 꾓; 꾓; 꾓; ) HANGUL SYLLABLE GGOES +AF94;AF94;1101 116C 11BB;AF94;1101 116C 11BB; # (꾔; 꾔; 꾔; 꾔; 꾔; ) HANGUL SYLLABLE GGOESS +AF95;AF95;1101 116C 11BC;AF95;1101 116C 11BC; # (꾕; 꾕; 꾕; 꾕; 꾕; ) HANGUL SYLLABLE GGOENG +AF96;AF96;1101 116C 11BD;AF96;1101 116C 11BD; # (꾖; 꾖; 꾖; 꾖; 꾖; ) HANGUL SYLLABLE GGOEJ +AF97;AF97;1101 116C 11BE;AF97;1101 116C 11BE; # (꾗; 꾗; 꾗; 꾗; 꾗; ) HANGUL SYLLABLE GGOEC +AF98;AF98;1101 116C 11BF;AF98;1101 116C 11BF; # (꾘; 꾘; 꾘; 꾘; 꾘; ) HANGUL SYLLABLE GGOEK +AF99;AF99;1101 116C 11C0;AF99;1101 116C 11C0; # (꾙; 꾙; 꾙; 꾙; 꾙; ) HANGUL SYLLABLE GGOET +AF9A;AF9A;1101 116C 11C1;AF9A;1101 116C 11C1; # (꾚; 꾚; 꾚; 꾚; 꾚; ) HANGUL SYLLABLE GGOEP +AF9B;AF9B;1101 116C 11C2;AF9B;1101 116C 11C2; # (꾛; 꾛; 꾛; 꾛; 꾛; ) HANGUL SYLLABLE GGOEH +AF9C;AF9C;1101 116D;AF9C;1101 116D; # (꾜; 꾜; 꾜; 꾜; 꾜; ) HANGUL SYLLABLE GGYO +AF9D;AF9D;1101 116D 11A8;AF9D;1101 116D 11A8; # (꾝; 꾝; 꾝; 꾝; 꾝; ) HANGUL SYLLABLE GGYOG +AF9E;AF9E;1101 116D 11A9;AF9E;1101 116D 11A9; # (꾞; 꾞; 꾞; 꾞; 꾞; ) HANGUL SYLLABLE GGYOGG +AF9F;AF9F;1101 116D 11AA;AF9F;1101 116D 11AA; # (꾟; 꾟; 꾟; 꾟; 꾟; ) HANGUL SYLLABLE GGYOGS +AFA0;AFA0;1101 116D 11AB;AFA0;1101 116D 11AB; # (꾠; 꾠; 꾠; 꾠; 꾠; ) HANGUL SYLLABLE GGYON +AFA1;AFA1;1101 116D 11AC;AFA1;1101 116D 11AC; # (꾡; 꾡; 꾡; 꾡; 꾡; ) HANGUL SYLLABLE GGYONJ +AFA2;AFA2;1101 116D 11AD;AFA2;1101 116D 11AD; # (꾢; 꾢; 꾢; 꾢; 꾢; ) HANGUL SYLLABLE GGYONH +AFA3;AFA3;1101 116D 11AE;AFA3;1101 116D 11AE; # (꾣; 꾣; 꾣; 꾣; 꾣; ) HANGUL SYLLABLE GGYOD +AFA4;AFA4;1101 116D 11AF;AFA4;1101 116D 11AF; # (꾤; 꾤; 꾤; 꾤; 꾤; ) HANGUL SYLLABLE GGYOL +AFA5;AFA5;1101 116D 11B0;AFA5;1101 116D 11B0; # (꾥; 꾥; 꾥; 꾥; 꾥; ) HANGUL SYLLABLE GGYOLG +AFA6;AFA6;1101 116D 11B1;AFA6;1101 116D 11B1; # (꾦; 꾦; 꾦; 꾦; 꾦; ) HANGUL SYLLABLE GGYOLM +AFA7;AFA7;1101 116D 11B2;AFA7;1101 116D 11B2; # (꾧; 꾧; 꾧; 꾧; 꾧; ) HANGUL SYLLABLE GGYOLB +AFA8;AFA8;1101 116D 11B3;AFA8;1101 116D 11B3; # (꾨; 꾨; 꾨; 꾨; 꾨; ) HANGUL SYLLABLE GGYOLS +AFA9;AFA9;1101 116D 11B4;AFA9;1101 116D 11B4; # (꾩; 꾩; 꾩; 꾩; 꾩; ) HANGUL SYLLABLE GGYOLT +AFAA;AFAA;1101 116D 11B5;AFAA;1101 116D 11B5; # (꾪; 꾪; 꾪; 꾪; 꾪; ) HANGUL SYLLABLE GGYOLP +AFAB;AFAB;1101 116D 11B6;AFAB;1101 116D 11B6; # (꾫; 꾫; 꾫; 꾫; 꾫; ) HANGUL SYLLABLE GGYOLH +AFAC;AFAC;1101 116D 11B7;AFAC;1101 116D 11B7; # (꾬; 꾬; 꾬; 꾬; 꾬; ) HANGUL SYLLABLE GGYOM +AFAD;AFAD;1101 116D 11B8;AFAD;1101 116D 11B8; # (꾭; 꾭; 꾭; 꾭; 꾭; ) HANGUL SYLLABLE GGYOB +AFAE;AFAE;1101 116D 11B9;AFAE;1101 116D 11B9; # (꾮; 꾮; 꾮; 꾮; 꾮; ) HANGUL SYLLABLE GGYOBS +AFAF;AFAF;1101 116D 11BA;AFAF;1101 116D 11BA; # (꾯; 꾯; 꾯; 꾯; 꾯; ) HANGUL SYLLABLE GGYOS +AFB0;AFB0;1101 116D 11BB;AFB0;1101 116D 11BB; # (꾰; 꾰; 꾰; 꾰; 꾰; ) HANGUL SYLLABLE GGYOSS +AFB1;AFB1;1101 116D 11BC;AFB1;1101 116D 11BC; # (꾱; 꾱; 꾱; 꾱; 꾱; ) HANGUL SYLLABLE GGYONG +AFB2;AFB2;1101 116D 11BD;AFB2;1101 116D 11BD; # (꾲; 꾲; 꾲; 꾲; 꾲; ) HANGUL SYLLABLE GGYOJ +AFB3;AFB3;1101 116D 11BE;AFB3;1101 116D 11BE; # (꾳; 꾳; 꾳; 꾳; 꾳; ) HANGUL SYLLABLE GGYOC +AFB4;AFB4;1101 116D 11BF;AFB4;1101 116D 11BF; # (꾴; 꾴; 꾴; 꾴; 꾴; ) HANGUL SYLLABLE GGYOK +AFB5;AFB5;1101 116D 11C0;AFB5;1101 116D 11C0; # (꾵; 꾵; 꾵; 꾵; 꾵; ) HANGUL SYLLABLE GGYOT +AFB6;AFB6;1101 116D 11C1;AFB6;1101 116D 11C1; # (꾶; 꾶; 꾶; 꾶; 꾶; ) HANGUL SYLLABLE GGYOP +AFB7;AFB7;1101 116D 11C2;AFB7;1101 116D 11C2; # (꾷; 꾷; 꾷; 꾷; 꾷; ) HANGUL SYLLABLE GGYOH +AFB8;AFB8;1101 116E;AFB8;1101 116E; # (꾸; 꾸; 꾸; 꾸; 꾸; ) HANGUL SYLLABLE GGU +AFB9;AFB9;1101 116E 11A8;AFB9;1101 116E 11A8; # (꾹; 꾹; 꾹; 꾹; 꾹; ) HANGUL SYLLABLE GGUG +AFBA;AFBA;1101 116E 11A9;AFBA;1101 116E 11A9; # (꾺; 꾺; 꾺; 꾺; 꾺; ) HANGUL SYLLABLE GGUGG +AFBB;AFBB;1101 116E 11AA;AFBB;1101 116E 11AA; # (꾻; 꾻; 꾻; 꾻; 꾻; ) HANGUL SYLLABLE GGUGS +AFBC;AFBC;1101 116E 11AB;AFBC;1101 116E 11AB; # (꾼; 꾼; 꾼; 꾼; 꾼; ) HANGUL SYLLABLE GGUN +AFBD;AFBD;1101 116E 11AC;AFBD;1101 116E 11AC; # (꾽; 꾽; 꾽; 꾽; 꾽; ) HANGUL SYLLABLE GGUNJ +AFBE;AFBE;1101 116E 11AD;AFBE;1101 116E 11AD; # (꾾; 꾾; 꾾; 꾾; 꾾; ) HANGUL SYLLABLE GGUNH +AFBF;AFBF;1101 116E 11AE;AFBF;1101 116E 11AE; # (꾿; 꾿; 꾿; 꾿; 꾿; ) HANGUL SYLLABLE GGUD +AFC0;AFC0;1101 116E 11AF;AFC0;1101 116E 11AF; # (꿀; 꿀; 꿀; 꿀; 꿀; ) HANGUL SYLLABLE GGUL +AFC1;AFC1;1101 116E 11B0;AFC1;1101 116E 11B0; # (꿁; 꿁; 꿁; 꿁; 꿁; ) HANGUL SYLLABLE GGULG +AFC2;AFC2;1101 116E 11B1;AFC2;1101 116E 11B1; # (꿂; 꿂; 꿂; 꿂; 꿂; ) HANGUL SYLLABLE GGULM +AFC3;AFC3;1101 116E 11B2;AFC3;1101 116E 11B2; # (꿃; 꿃; 꿃; 꿃; 꿃; ) HANGUL SYLLABLE GGULB +AFC4;AFC4;1101 116E 11B3;AFC4;1101 116E 11B3; # (꿄; 꿄; 꿄; 꿄; 꿄; ) HANGUL SYLLABLE GGULS +AFC5;AFC5;1101 116E 11B4;AFC5;1101 116E 11B4; # (꿅; 꿅; 꿅; 꿅; 꿅; ) HANGUL SYLLABLE GGULT +AFC6;AFC6;1101 116E 11B5;AFC6;1101 116E 11B5; # (꿆; 꿆; 꿆; 꿆; 꿆; ) HANGUL SYLLABLE GGULP +AFC7;AFC7;1101 116E 11B6;AFC7;1101 116E 11B6; # (꿇; 꿇; 꿇; 꿇; 꿇; ) HANGUL SYLLABLE GGULH +AFC8;AFC8;1101 116E 11B7;AFC8;1101 116E 11B7; # (꿈; 꿈; 꿈; 꿈; 꿈; ) HANGUL SYLLABLE GGUM +AFC9;AFC9;1101 116E 11B8;AFC9;1101 116E 11B8; # (꿉; 꿉; 꿉; 꿉; 꿉; ) HANGUL SYLLABLE GGUB +AFCA;AFCA;1101 116E 11B9;AFCA;1101 116E 11B9; # (꿊; 꿊; 꿊; 꿊; 꿊; ) HANGUL SYLLABLE GGUBS +AFCB;AFCB;1101 116E 11BA;AFCB;1101 116E 11BA; # (꿋; 꿋; 꿋; 꿋; 꿋; ) HANGUL SYLLABLE GGUS +AFCC;AFCC;1101 116E 11BB;AFCC;1101 116E 11BB; # (꿌; 꿌; 꿌; 꿌; 꿌; ) HANGUL SYLLABLE GGUSS +AFCD;AFCD;1101 116E 11BC;AFCD;1101 116E 11BC; # (꿍; 꿍; 꿍; 꿍; 꿍; ) HANGUL SYLLABLE GGUNG +AFCE;AFCE;1101 116E 11BD;AFCE;1101 116E 11BD; # (꿎; 꿎; 꿎; 꿎; 꿎; ) HANGUL SYLLABLE GGUJ +AFCF;AFCF;1101 116E 11BE;AFCF;1101 116E 11BE; # (꿏; 꿏; 꿏; 꿏; 꿏; ) HANGUL SYLLABLE GGUC +AFD0;AFD0;1101 116E 11BF;AFD0;1101 116E 11BF; # (꿐; 꿐; 꿐; 꿐; 꿐; ) HANGUL SYLLABLE GGUK +AFD1;AFD1;1101 116E 11C0;AFD1;1101 116E 11C0; # (꿑; 꿑; 꿑; 꿑; 꿑; ) HANGUL SYLLABLE GGUT +AFD2;AFD2;1101 116E 11C1;AFD2;1101 116E 11C1; # (꿒; 꿒; 꿒; 꿒; 꿒; ) HANGUL SYLLABLE GGUP +AFD3;AFD3;1101 116E 11C2;AFD3;1101 116E 11C2; # (꿓; 꿓; 꿓; 꿓; 꿓; ) HANGUL SYLLABLE GGUH +AFD4;AFD4;1101 116F;AFD4;1101 116F; # (꿔; 꿔; 꿔; 꿔; 꿔; ) HANGUL SYLLABLE GGWEO +AFD5;AFD5;1101 116F 11A8;AFD5;1101 116F 11A8; # (꿕; 꿕; 꿕; 꿕; 꿕; ) HANGUL SYLLABLE GGWEOG +AFD6;AFD6;1101 116F 11A9;AFD6;1101 116F 11A9; # (꿖; 꿖; 꿖; 꿖; 꿖; ) HANGUL SYLLABLE GGWEOGG +AFD7;AFD7;1101 116F 11AA;AFD7;1101 116F 11AA; # (꿗; 꿗; 꿗; 꿗; 꿗; ) HANGUL SYLLABLE GGWEOGS +AFD8;AFD8;1101 116F 11AB;AFD8;1101 116F 11AB; # (꿘; 꿘; 꿘; 꿘; 꿘; ) HANGUL SYLLABLE GGWEON +AFD9;AFD9;1101 116F 11AC;AFD9;1101 116F 11AC; # (꿙; 꿙; 꿙; 꿙; 꿙; ) HANGUL SYLLABLE GGWEONJ +AFDA;AFDA;1101 116F 11AD;AFDA;1101 116F 11AD; # (꿚; 꿚; 꿚; 꿚; 꿚; ) HANGUL SYLLABLE GGWEONH +AFDB;AFDB;1101 116F 11AE;AFDB;1101 116F 11AE; # (꿛; 꿛; 꿛; 꿛; 꿛; ) HANGUL SYLLABLE GGWEOD +AFDC;AFDC;1101 116F 11AF;AFDC;1101 116F 11AF; # (꿜; 꿜; 꿜; 꿜; 꿜; ) HANGUL SYLLABLE GGWEOL +AFDD;AFDD;1101 116F 11B0;AFDD;1101 116F 11B0; # (꿝; 꿝; 꿝; 꿝; 꿝; ) HANGUL SYLLABLE GGWEOLG +AFDE;AFDE;1101 116F 11B1;AFDE;1101 116F 11B1; # (꿞; 꿞; 꿞; 꿞; 꿞; ) HANGUL SYLLABLE GGWEOLM +AFDF;AFDF;1101 116F 11B2;AFDF;1101 116F 11B2; # (꿟; 꿟; 꿟; 꿟; 꿟; ) HANGUL SYLLABLE GGWEOLB +AFE0;AFE0;1101 116F 11B3;AFE0;1101 116F 11B3; # (꿠; 꿠; 꿠; 꿠; 꿠; ) HANGUL SYLLABLE GGWEOLS +AFE1;AFE1;1101 116F 11B4;AFE1;1101 116F 11B4; # (꿡; 꿡; 꿡; 꿡; 꿡; ) HANGUL SYLLABLE GGWEOLT +AFE2;AFE2;1101 116F 11B5;AFE2;1101 116F 11B5; # (꿢; 꿢; 꿢; 꿢; 꿢; ) HANGUL SYLLABLE GGWEOLP +AFE3;AFE3;1101 116F 11B6;AFE3;1101 116F 11B6; # (꿣; 꿣; 꿣; 꿣; 꿣; ) HANGUL SYLLABLE GGWEOLH +AFE4;AFE4;1101 116F 11B7;AFE4;1101 116F 11B7; # (꿤; 꿤; 꿤; 꿤; 꿤; ) HANGUL SYLLABLE GGWEOM +AFE5;AFE5;1101 116F 11B8;AFE5;1101 116F 11B8; # (꿥; 꿥; 꿥; 꿥; 꿥; ) HANGUL SYLLABLE GGWEOB +AFE6;AFE6;1101 116F 11B9;AFE6;1101 116F 11B9; # (꿦; 꿦; 꿦; 꿦; 꿦; ) HANGUL SYLLABLE GGWEOBS +AFE7;AFE7;1101 116F 11BA;AFE7;1101 116F 11BA; # (꿧; 꿧; 꿧; 꿧; 꿧; ) HANGUL SYLLABLE GGWEOS +AFE8;AFE8;1101 116F 11BB;AFE8;1101 116F 11BB; # (꿨; 꿨; 꿨; 꿨; 꿨; ) HANGUL SYLLABLE GGWEOSS +AFE9;AFE9;1101 116F 11BC;AFE9;1101 116F 11BC; # (꿩; 꿩; 꿩; 꿩; 꿩; ) HANGUL SYLLABLE GGWEONG +AFEA;AFEA;1101 116F 11BD;AFEA;1101 116F 11BD; # (꿪; 꿪; 꿪; 꿪; 꿪; ) HANGUL SYLLABLE GGWEOJ +AFEB;AFEB;1101 116F 11BE;AFEB;1101 116F 11BE; # (꿫; 꿫; 꿫; 꿫; 꿫; ) HANGUL SYLLABLE GGWEOC +AFEC;AFEC;1101 116F 11BF;AFEC;1101 116F 11BF; # (꿬; 꿬; 꿬; 꿬; 꿬; ) HANGUL SYLLABLE GGWEOK +AFED;AFED;1101 116F 11C0;AFED;1101 116F 11C0; # (꿭; 꿭; 꿭; 꿭; 꿭; ) HANGUL SYLLABLE GGWEOT +AFEE;AFEE;1101 116F 11C1;AFEE;1101 116F 11C1; # (꿮; 꿮; 꿮; 꿮; 꿮; ) HANGUL SYLLABLE GGWEOP +AFEF;AFEF;1101 116F 11C2;AFEF;1101 116F 11C2; # (꿯; 꿯; 꿯; 꿯; 꿯; ) HANGUL SYLLABLE GGWEOH +AFF0;AFF0;1101 1170;AFF0;1101 1170; # (꿰; 꿰; 꿰; 꿰; 꿰; ) HANGUL SYLLABLE GGWE +AFF1;AFF1;1101 1170 11A8;AFF1;1101 1170 11A8; # (꿱; 꿱; 꿱; 꿱; 꿱; ) HANGUL SYLLABLE GGWEG +AFF2;AFF2;1101 1170 11A9;AFF2;1101 1170 11A9; # (꿲; 꿲; 꿲; 꿲; 꿲; ) HANGUL SYLLABLE GGWEGG +AFF3;AFF3;1101 1170 11AA;AFF3;1101 1170 11AA; # (꿳; 꿳; 꿳; 꿳; 꿳; ) HANGUL SYLLABLE GGWEGS +AFF4;AFF4;1101 1170 11AB;AFF4;1101 1170 11AB; # (꿴; 꿴; 꿴; 꿴; 꿴; ) HANGUL SYLLABLE GGWEN +AFF5;AFF5;1101 1170 11AC;AFF5;1101 1170 11AC; # (꿵; 꿵; 꿵; 꿵; 꿵; ) HANGUL SYLLABLE GGWENJ +AFF6;AFF6;1101 1170 11AD;AFF6;1101 1170 11AD; # (꿶; 꿶; 꿶; 꿶; 꿶; ) HANGUL SYLLABLE GGWENH +AFF7;AFF7;1101 1170 11AE;AFF7;1101 1170 11AE; # (꿷; 꿷; 꿷; 꿷; 꿷; ) HANGUL SYLLABLE GGWED +AFF8;AFF8;1101 1170 11AF;AFF8;1101 1170 11AF; # (꿸; 꿸; 꿸; 꿸; 꿸; ) HANGUL SYLLABLE GGWEL +AFF9;AFF9;1101 1170 11B0;AFF9;1101 1170 11B0; # (꿹; 꿹; 꿹; 꿹; 꿹; ) HANGUL SYLLABLE GGWELG +AFFA;AFFA;1101 1170 11B1;AFFA;1101 1170 11B1; # (꿺; 꿺; 꿺; 꿺; 꿺; ) HANGUL SYLLABLE GGWELM +AFFB;AFFB;1101 1170 11B2;AFFB;1101 1170 11B2; # (꿻; 꿻; 꿻; 꿻; 꿻; ) HANGUL SYLLABLE GGWELB +AFFC;AFFC;1101 1170 11B3;AFFC;1101 1170 11B3; # (꿼; 꿼; 꿼; 꿼; 꿼; ) HANGUL SYLLABLE GGWELS +AFFD;AFFD;1101 1170 11B4;AFFD;1101 1170 11B4; # (꿽; 꿽; 꿽; 꿽; 꿽; ) HANGUL SYLLABLE GGWELT +AFFE;AFFE;1101 1170 11B5;AFFE;1101 1170 11B5; # (꿾; 꿾; 꿾; 꿾; 꿾; ) HANGUL SYLLABLE GGWELP +AFFF;AFFF;1101 1170 11B6;AFFF;1101 1170 11B6; # (꿿; 꿿; 꿿; 꿿; 꿿; ) HANGUL SYLLABLE GGWELH +B000;B000;1101 1170 11B7;B000;1101 1170 11B7; # (뀀; 뀀; 뀀; 뀀; 뀀; ) HANGUL SYLLABLE GGWEM +B001;B001;1101 1170 11B8;B001;1101 1170 11B8; # (뀁; 뀁; 뀁; 뀁; 뀁; ) HANGUL SYLLABLE GGWEB +B002;B002;1101 1170 11B9;B002;1101 1170 11B9; # (뀂; 뀂; 뀂; 뀂; 뀂; ) HANGUL SYLLABLE GGWEBS +B003;B003;1101 1170 11BA;B003;1101 1170 11BA; # (뀃; 뀃; 뀃; 뀃; 뀃; ) HANGUL SYLLABLE GGWES +B004;B004;1101 1170 11BB;B004;1101 1170 11BB; # (뀄; 뀄; 뀄; 뀄; 뀄; ) HANGUL SYLLABLE GGWESS +B005;B005;1101 1170 11BC;B005;1101 1170 11BC; # (뀅; 뀅; 뀅; 뀅; 뀅; ) HANGUL SYLLABLE GGWENG +B006;B006;1101 1170 11BD;B006;1101 1170 11BD; # (뀆; 뀆; 뀆; 뀆; 뀆; ) HANGUL SYLLABLE GGWEJ +B007;B007;1101 1170 11BE;B007;1101 1170 11BE; # (뀇; 뀇; 뀇; 뀇; 뀇; ) HANGUL SYLLABLE GGWEC +B008;B008;1101 1170 11BF;B008;1101 1170 11BF; # (뀈; 뀈; 뀈; 뀈; 뀈; ) HANGUL SYLLABLE GGWEK +B009;B009;1101 1170 11C0;B009;1101 1170 11C0; # (뀉; 뀉; 뀉; 뀉; 뀉; ) HANGUL SYLLABLE GGWET +B00A;B00A;1101 1170 11C1;B00A;1101 1170 11C1; # (뀊; 뀊; 뀊; 뀊; 뀊; ) HANGUL SYLLABLE GGWEP +B00B;B00B;1101 1170 11C2;B00B;1101 1170 11C2; # (뀋; 뀋; 뀋; 뀋; 뀋; ) HANGUL SYLLABLE GGWEH +B00C;B00C;1101 1171;B00C;1101 1171; # (뀌; 뀌; 뀌; 뀌; 뀌; ) HANGUL SYLLABLE GGWI +B00D;B00D;1101 1171 11A8;B00D;1101 1171 11A8; # (뀍; 뀍; 뀍; 뀍; 뀍; ) HANGUL SYLLABLE GGWIG +B00E;B00E;1101 1171 11A9;B00E;1101 1171 11A9; # (뀎; 뀎; 뀎; 뀎; 뀎; ) HANGUL SYLLABLE GGWIGG +B00F;B00F;1101 1171 11AA;B00F;1101 1171 11AA; # (뀏; 뀏; 뀏; 뀏; 뀏; ) HANGUL SYLLABLE GGWIGS +B010;B010;1101 1171 11AB;B010;1101 1171 11AB; # (뀐; 뀐; 뀐; 뀐; 뀐; ) HANGUL SYLLABLE GGWIN +B011;B011;1101 1171 11AC;B011;1101 1171 11AC; # (뀑; 뀑; 뀑; 뀑; 뀑; ) HANGUL SYLLABLE GGWINJ +B012;B012;1101 1171 11AD;B012;1101 1171 11AD; # (뀒; 뀒; 뀒; 뀒; 뀒; ) HANGUL SYLLABLE GGWINH +B013;B013;1101 1171 11AE;B013;1101 1171 11AE; # (뀓; 뀓; 뀓; 뀓; 뀓; ) HANGUL SYLLABLE GGWID +B014;B014;1101 1171 11AF;B014;1101 1171 11AF; # (뀔; 뀔; 뀔; 뀔; 뀔; ) HANGUL SYLLABLE GGWIL +B015;B015;1101 1171 11B0;B015;1101 1171 11B0; # (뀕; 뀕; 뀕; 뀕; 뀕; ) HANGUL SYLLABLE GGWILG +B016;B016;1101 1171 11B1;B016;1101 1171 11B1; # (뀖; 뀖; 뀖; 뀖; 뀖; ) HANGUL SYLLABLE GGWILM +B017;B017;1101 1171 11B2;B017;1101 1171 11B2; # (뀗; 뀗; 뀗; 뀗; 뀗; ) HANGUL SYLLABLE GGWILB +B018;B018;1101 1171 11B3;B018;1101 1171 11B3; # (뀘; 뀘; 뀘; 뀘; 뀘; ) HANGUL SYLLABLE GGWILS +B019;B019;1101 1171 11B4;B019;1101 1171 11B4; # (뀙; 뀙; 뀙; 뀙; 뀙; ) HANGUL SYLLABLE GGWILT +B01A;B01A;1101 1171 11B5;B01A;1101 1171 11B5; # (뀚; 뀚; 뀚; 뀚; 뀚; ) HANGUL SYLLABLE GGWILP +B01B;B01B;1101 1171 11B6;B01B;1101 1171 11B6; # (뀛; 뀛; 뀛; 뀛; 뀛; ) HANGUL SYLLABLE GGWILH +B01C;B01C;1101 1171 11B7;B01C;1101 1171 11B7; # (뀜; 뀜; 뀜; 뀜; 뀜; ) HANGUL SYLLABLE GGWIM +B01D;B01D;1101 1171 11B8;B01D;1101 1171 11B8; # (뀝; 뀝; 뀝; 뀝; 뀝; ) HANGUL SYLLABLE GGWIB +B01E;B01E;1101 1171 11B9;B01E;1101 1171 11B9; # (뀞; 뀞; 뀞; 뀞; 뀞; ) HANGUL SYLLABLE GGWIBS +B01F;B01F;1101 1171 11BA;B01F;1101 1171 11BA; # (뀟; 뀟; 뀟; 뀟; 뀟; ) HANGUL SYLLABLE GGWIS +B020;B020;1101 1171 11BB;B020;1101 1171 11BB; # (뀠; 뀠; 뀠; 뀠; 뀠; ) HANGUL SYLLABLE GGWISS +B021;B021;1101 1171 11BC;B021;1101 1171 11BC; # (뀡; 뀡; 뀡; 뀡; 뀡; ) HANGUL SYLLABLE GGWING +B022;B022;1101 1171 11BD;B022;1101 1171 11BD; # (뀢; 뀢; 뀢; 뀢; 뀢; ) HANGUL SYLLABLE GGWIJ +B023;B023;1101 1171 11BE;B023;1101 1171 11BE; # (뀣; 뀣; 뀣; 뀣; 뀣; ) HANGUL SYLLABLE GGWIC +B024;B024;1101 1171 11BF;B024;1101 1171 11BF; # (뀤; 뀤; 뀤; 뀤; 뀤; ) HANGUL SYLLABLE GGWIK +B025;B025;1101 1171 11C0;B025;1101 1171 11C0; # (뀥; 뀥; 뀥; 뀥; 뀥; ) HANGUL SYLLABLE GGWIT +B026;B026;1101 1171 11C1;B026;1101 1171 11C1; # (뀦; 뀦; 뀦; 뀦; 뀦; ) HANGUL SYLLABLE GGWIP +B027;B027;1101 1171 11C2;B027;1101 1171 11C2; # (뀧; 뀧; 뀧; 뀧; 뀧; ) HANGUL SYLLABLE GGWIH +B028;B028;1101 1172;B028;1101 1172; # (뀨; 뀨; 뀨; 뀨; 뀨; ) HANGUL SYLLABLE GGYU +B029;B029;1101 1172 11A8;B029;1101 1172 11A8; # (뀩; 뀩; 뀩; 뀩; 뀩; ) HANGUL SYLLABLE GGYUG +B02A;B02A;1101 1172 11A9;B02A;1101 1172 11A9; # (뀪; 뀪; 뀪; 뀪; 뀪; ) HANGUL SYLLABLE GGYUGG +B02B;B02B;1101 1172 11AA;B02B;1101 1172 11AA; # (뀫; 뀫; 뀫; 뀫; 뀫; ) HANGUL SYLLABLE GGYUGS +B02C;B02C;1101 1172 11AB;B02C;1101 1172 11AB; # (뀬; 뀬; 뀬; 뀬; 뀬; ) HANGUL SYLLABLE GGYUN +B02D;B02D;1101 1172 11AC;B02D;1101 1172 11AC; # (뀭; 뀭; 뀭; 뀭; 뀭; ) HANGUL SYLLABLE GGYUNJ +B02E;B02E;1101 1172 11AD;B02E;1101 1172 11AD; # (뀮; 뀮; 뀮; 뀮; 뀮; ) HANGUL SYLLABLE GGYUNH +B02F;B02F;1101 1172 11AE;B02F;1101 1172 11AE; # (뀯; 뀯; 뀯; 뀯; 뀯; ) HANGUL SYLLABLE GGYUD +B030;B030;1101 1172 11AF;B030;1101 1172 11AF; # (뀰; 뀰; 뀰; 뀰; 뀰; ) HANGUL SYLLABLE GGYUL +B031;B031;1101 1172 11B0;B031;1101 1172 11B0; # (뀱; 뀱; 뀱; 뀱; 뀱; ) HANGUL SYLLABLE GGYULG +B032;B032;1101 1172 11B1;B032;1101 1172 11B1; # (뀲; 뀲; 뀲; 뀲; 뀲; ) HANGUL SYLLABLE GGYULM +B033;B033;1101 1172 11B2;B033;1101 1172 11B2; # (뀳; 뀳; 뀳; 뀳; 뀳; ) HANGUL SYLLABLE GGYULB +B034;B034;1101 1172 11B3;B034;1101 1172 11B3; # (뀴; 뀴; 뀴; 뀴; 뀴; ) HANGUL SYLLABLE GGYULS +B035;B035;1101 1172 11B4;B035;1101 1172 11B4; # (뀵; 뀵; 뀵; 뀵; 뀵; ) HANGUL SYLLABLE GGYULT +B036;B036;1101 1172 11B5;B036;1101 1172 11B5; # (뀶; 뀶; 뀶; 뀶; 뀶; ) HANGUL SYLLABLE GGYULP +B037;B037;1101 1172 11B6;B037;1101 1172 11B6; # (뀷; 뀷; 뀷; 뀷; 뀷; ) HANGUL SYLLABLE GGYULH +B038;B038;1101 1172 11B7;B038;1101 1172 11B7; # (뀸; 뀸; 뀸; 뀸; 뀸; ) HANGUL SYLLABLE GGYUM +B039;B039;1101 1172 11B8;B039;1101 1172 11B8; # (뀹; 뀹; 뀹; 뀹; 뀹; ) HANGUL SYLLABLE GGYUB +B03A;B03A;1101 1172 11B9;B03A;1101 1172 11B9; # (뀺; 뀺; 뀺; 뀺; 뀺; ) HANGUL SYLLABLE GGYUBS +B03B;B03B;1101 1172 11BA;B03B;1101 1172 11BA; # (뀻; 뀻; 뀻; 뀻; 뀻; ) HANGUL SYLLABLE GGYUS +B03C;B03C;1101 1172 11BB;B03C;1101 1172 11BB; # (뀼; 뀼; 뀼; 뀼; 뀼; ) HANGUL SYLLABLE GGYUSS +B03D;B03D;1101 1172 11BC;B03D;1101 1172 11BC; # (뀽; 뀽; 뀽; 뀽; 뀽; ) HANGUL SYLLABLE GGYUNG +B03E;B03E;1101 1172 11BD;B03E;1101 1172 11BD; # (뀾; 뀾; 뀾; 뀾; 뀾; ) HANGUL SYLLABLE GGYUJ +B03F;B03F;1101 1172 11BE;B03F;1101 1172 11BE; # (뀿; 뀿; 뀿; 뀿; 뀿; ) HANGUL SYLLABLE GGYUC +B040;B040;1101 1172 11BF;B040;1101 1172 11BF; # (끀; 끀; 끀; 끀; 끀; ) HANGUL SYLLABLE GGYUK +B041;B041;1101 1172 11C0;B041;1101 1172 11C0; # (끁; 끁; 끁; 끁; 끁; ) HANGUL SYLLABLE GGYUT +B042;B042;1101 1172 11C1;B042;1101 1172 11C1; # (끂; 끂; 끂; 끂; 끂; ) HANGUL SYLLABLE GGYUP +B043;B043;1101 1172 11C2;B043;1101 1172 11C2; # (끃; 끃; 끃; 끃; 끃; ) HANGUL SYLLABLE GGYUH +B044;B044;1101 1173;B044;1101 1173; # (끄; 끄; 끄; 끄; 끄; ) HANGUL SYLLABLE GGEU +B045;B045;1101 1173 11A8;B045;1101 1173 11A8; # (끅; 끅; 끅; 끅; 끅; ) HANGUL SYLLABLE GGEUG +B046;B046;1101 1173 11A9;B046;1101 1173 11A9; # (끆; 끆; 끆; 끆; 끆; ) HANGUL SYLLABLE GGEUGG +B047;B047;1101 1173 11AA;B047;1101 1173 11AA; # (끇; 끇; 끇; 끇; 끇; ) HANGUL SYLLABLE GGEUGS +B048;B048;1101 1173 11AB;B048;1101 1173 11AB; # (끈; 끈; 끈; 끈; 끈; ) HANGUL SYLLABLE GGEUN +B049;B049;1101 1173 11AC;B049;1101 1173 11AC; # (끉; 끉; 끉; 끉; 끉; ) HANGUL SYLLABLE GGEUNJ +B04A;B04A;1101 1173 11AD;B04A;1101 1173 11AD; # (끊; 끊; 끊; 끊; 끊; ) HANGUL SYLLABLE GGEUNH +B04B;B04B;1101 1173 11AE;B04B;1101 1173 11AE; # (끋; 끋; 끋; 끋; 끋; ) HANGUL SYLLABLE GGEUD +B04C;B04C;1101 1173 11AF;B04C;1101 1173 11AF; # (끌; 끌; 끌; 끌; 끌; ) HANGUL SYLLABLE GGEUL +B04D;B04D;1101 1173 11B0;B04D;1101 1173 11B0; # (끍; 끍; 끍; 끍; 끍; ) HANGUL SYLLABLE GGEULG +B04E;B04E;1101 1173 11B1;B04E;1101 1173 11B1; # (끎; 끎; 끎; 끎; 끎; ) HANGUL SYLLABLE GGEULM +B04F;B04F;1101 1173 11B2;B04F;1101 1173 11B2; # (끏; 끏; 끏; 끏; 끏; ) HANGUL SYLLABLE GGEULB +B050;B050;1101 1173 11B3;B050;1101 1173 11B3; # (끐; 끐; 끐; 끐; 끐; ) HANGUL SYLLABLE GGEULS +B051;B051;1101 1173 11B4;B051;1101 1173 11B4; # (끑; 끑; 끑; 끑; 끑; ) HANGUL SYLLABLE GGEULT +B052;B052;1101 1173 11B5;B052;1101 1173 11B5; # (끒; 끒; 끒; 끒; 끒; ) HANGUL SYLLABLE GGEULP +B053;B053;1101 1173 11B6;B053;1101 1173 11B6; # (끓; 끓; 끓; 끓; 끓; ) HANGUL SYLLABLE GGEULH +B054;B054;1101 1173 11B7;B054;1101 1173 11B7; # (끔; 끔; 끔; 끔; 끔; ) HANGUL SYLLABLE GGEUM +B055;B055;1101 1173 11B8;B055;1101 1173 11B8; # (끕; 끕; 끕; 끕; 끕; ) HANGUL SYLLABLE GGEUB +B056;B056;1101 1173 11B9;B056;1101 1173 11B9; # (끖; 끖; 끖; 끖; 끖; ) HANGUL SYLLABLE GGEUBS +B057;B057;1101 1173 11BA;B057;1101 1173 11BA; # (끗; 끗; 끗; 끗; 끗; ) HANGUL SYLLABLE GGEUS +B058;B058;1101 1173 11BB;B058;1101 1173 11BB; # (끘; 끘; 끘; 끘; 끘; ) HANGUL SYLLABLE GGEUSS +B059;B059;1101 1173 11BC;B059;1101 1173 11BC; # (끙; 끙; 끙; 끙; 끙; ) HANGUL SYLLABLE GGEUNG +B05A;B05A;1101 1173 11BD;B05A;1101 1173 11BD; # (끚; 끚; 끚; 끚; 끚; ) HANGUL SYLLABLE GGEUJ +B05B;B05B;1101 1173 11BE;B05B;1101 1173 11BE; # (끛; 끛; 끛; 끛; 끛; ) HANGUL SYLLABLE GGEUC +B05C;B05C;1101 1173 11BF;B05C;1101 1173 11BF; # (끜; 끜; 끜; 끜; 끜; ) HANGUL SYLLABLE GGEUK +B05D;B05D;1101 1173 11C0;B05D;1101 1173 11C0; # (끝; 끝; 끝; 끝; 끝; ) HANGUL SYLLABLE GGEUT +B05E;B05E;1101 1173 11C1;B05E;1101 1173 11C1; # (끞; 끞; 끞; 끞; 끞; ) HANGUL SYLLABLE GGEUP +B05F;B05F;1101 1173 11C2;B05F;1101 1173 11C2; # (끟; 끟; 끟; 끟; 끟; ) HANGUL SYLLABLE GGEUH +B060;B060;1101 1174;B060;1101 1174; # (끠; 끠; 끠; 끠; 끠; ) HANGUL SYLLABLE GGYI +B061;B061;1101 1174 11A8;B061;1101 1174 11A8; # (끡; 끡; 끡; 끡; 끡; ) HANGUL SYLLABLE GGYIG +B062;B062;1101 1174 11A9;B062;1101 1174 11A9; # (끢; 끢; 끢; 끢; 끢; ) HANGUL SYLLABLE GGYIGG +B063;B063;1101 1174 11AA;B063;1101 1174 11AA; # (끣; 끣; 끣; 끣; 끣; ) HANGUL SYLLABLE GGYIGS +B064;B064;1101 1174 11AB;B064;1101 1174 11AB; # (끤; 끤; 끤; 끤; 끤; ) HANGUL SYLLABLE GGYIN +B065;B065;1101 1174 11AC;B065;1101 1174 11AC; # (끥; 끥; 끥; 끥; 끥; ) HANGUL SYLLABLE GGYINJ +B066;B066;1101 1174 11AD;B066;1101 1174 11AD; # (끦; 끦; 끦; 끦; 끦; ) HANGUL SYLLABLE GGYINH +B067;B067;1101 1174 11AE;B067;1101 1174 11AE; # (끧; 끧; 끧; 끧; 끧; ) HANGUL SYLLABLE GGYID +B068;B068;1101 1174 11AF;B068;1101 1174 11AF; # (끨; 끨; 끨; 끨; 끨; ) HANGUL SYLLABLE GGYIL +B069;B069;1101 1174 11B0;B069;1101 1174 11B0; # (끩; 끩; 끩; 끩; 끩; ) HANGUL SYLLABLE GGYILG +B06A;B06A;1101 1174 11B1;B06A;1101 1174 11B1; # (끪; 끪; 끪; 끪; 끪; ) HANGUL SYLLABLE GGYILM +B06B;B06B;1101 1174 11B2;B06B;1101 1174 11B2; # (끫; 끫; 끫; 끫; 끫; ) HANGUL SYLLABLE GGYILB +B06C;B06C;1101 1174 11B3;B06C;1101 1174 11B3; # (끬; 끬; 끬; 끬; 끬; ) HANGUL SYLLABLE GGYILS +B06D;B06D;1101 1174 11B4;B06D;1101 1174 11B4; # (끭; 끭; 끭; 끭; 끭; ) HANGUL SYLLABLE GGYILT +B06E;B06E;1101 1174 11B5;B06E;1101 1174 11B5; # (끮; 끮; 끮; 끮; 끮; ) HANGUL SYLLABLE GGYILP +B06F;B06F;1101 1174 11B6;B06F;1101 1174 11B6; # (끯; 끯; 끯; 끯; 끯; ) HANGUL SYLLABLE GGYILH +B070;B070;1101 1174 11B7;B070;1101 1174 11B7; # (끰; 끰; 끰; 끰; 끰; ) HANGUL SYLLABLE GGYIM +B071;B071;1101 1174 11B8;B071;1101 1174 11B8; # (끱; 끱; 끱; 끱; 끱; ) HANGUL SYLLABLE GGYIB +B072;B072;1101 1174 11B9;B072;1101 1174 11B9; # (끲; 끲; 끲; 끲; 끲; ) HANGUL SYLLABLE GGYIBS +B073;B073;1101 1174 11BA;B073;1101 1174 11BA; # (끳; 끳; 끳; 끳; 끳; ) HANGUL SYLLABLE GGYIS +B074;B074;1101 1174 11BB;B074;1101 1174 11BB; # (끴; 끴; 끴; 끴; 끴; ) HANGUL SYLLABLE GGYISS +B075;B075;1101 1174 11BC;B075;1101 1174 11BC; # (끵; 끵; 끵; 끵; 끵; ) HANGUL SYLLABLE GGYING +B076;B076;1101 1174 11BD;B076;1101 1174 11BD; # (끶; 끶; 끶; 끶; 끶; ) HANGUL SYLLABLE GGYIJ +B077;B077;1101 1174 11BE;B077;1101 1174 11BE; # (끷; 끷; 끷; 끷; 끷; ) HANGUL SYLLABLE GGYIC +B078;B078;1101 1174 11BF;B078;1101 1174 11BF; # (끸; 끸; 끸; 끸; 끸; ) HANGUL SYLLABLE GGYIK +B079;B079;1101 1174 11C0;B079;1101 1174 11C0; # (끹; 끹; 끹; 끹; 끹; ) HANGUL SYLLABLE GGYIT +B07A;B07A;1101 1174 11C1;B07A;1101 1174 11C1; # (끺; 끺; 끺; 끺; 끺; ) HANGUL SYLLABLE GGYIP +B07B;B07B;1101 1174 11C2;B07B;1101 1174 11C2; # (끻; 끻; 끻; 끻; 끻; ) HANGUL SYLLABLE GGYIH +B07C;B07C;1101 1175;B07C;1101 1175; # (끼; 끼; 끼; 끼; 끼; ) HANGUL SYLLABLE GGI +B07D;B07D;1101 1175 11A8;B07D;1101 1175 11A8; # (끽; 끽; 끽; 끽; 끽; ) HANGUL SYLLABLE GGIG +B07E;B07E;1101 1175 11A9;B07E;1101 1175 11A9; # (끾; 끾; 끾; 끾; 끾; ) HANGUL SYLLABLE GGIGG +B07F;B07F;1101 1175 11AA;B07F;1101 1175 11AA; # (끿; 끿; 끿; 끿; 끿; ) HANGUL SYLLABLE GGIGS +B080;B080;1101 1175 11AB;B080;1101 1175 11AB; # (낀; 낀; 낀; 낀; 낀; ) HANGUL SYLLABLE GGIN +B081;B081;1101 1175 11AC;B081;1101 1175 11AC; # (낁; 낁; 낁; 낁; 낁; ) HANGUL SYLLABLE GGINJ +B082;B082;1101 1175 11AD;B082;1101 1175 11AD; # (낂; 낂; 낂; 낂; 낂; ) HANGUL SYLLABLE GGINH +B083;B083;1101 1175 11AE;B083;1101 1175 11AE; # (낃; 낃; 낃; 낃; 낃; ) HANGUL SYLLABLE GGID +B084;B084;1101 1175 11AF;B084;1101 1175 11AF; # (낄; 낄; 낄; 낄; 낄; ) HANGUL SYLLABLE GGIL +B085;B085;1101 1175 11B0;B085;1101 1175 11B0; # (낅; 낅; 낅; 낅; 낅; ) HANGUL SYLLABLE GGILG +B086;B086;1101 1175 11B1;B086;1101 1175 11B1; # (낆; 낆; 낆; 낆; 낆; ) HANGUL SYLLABLE GGILM +B087;B087;1101 1175 11B2;B087;1101 1175 11B2; # (낇; 낇; 낇; 낇; 낇; ) HANGUL SYLLABLE GGILB +B088;B088;1101 1175 11B3;B088;1101 1175 11B3; # (낈; 낈; 낈; 낈; 낈; ) HANGUL SYLLABLE GGILS +B089;B089;1101 1175 11B4;B089;1101 1175 11B4; # (낉; 낉; 낉; 낉; 낉; ) HANGUL SYLLABLE GGILT +B08A;B08A;1101 1175 11B5;B08A;1101 1175 11B5; # (낊; 낊; 낊; 낊; 낊; ) HANGUL SYLLABLE GGILP +B08B;B08B;1101 1175 11B6;B08B;1101 1175 11B6; # (낋; 낋; 낋; 낋; 낋; ) HANGUL SYLLABLE GGILH +B08C;B08C;1101 1175 11B7;B08C;1101 1175 11B7; # (낌; 낌; 낌; 낌; 낌; ) HANGUL SYLLABLE GGIM +B08D;B08D;1101 1175 11B8;B08D;1101 1175 11B8; # (낍; 낍; 낍; 낍; 낍; ) HANGUL SYLLABLE GGIB +B08E;B08E;1101 1175 11B9;B08E;1101 1175 11B9; # (낎; 낎; 낎; 낎; 낎; ) HANGUL SYLLABLE GGIBS +B08F;B08F;1101 1175 11BA;B08F;1101 1175 11BA; # (낏; 낏; 낏; 낏; 낏; ) HANGUL SYLLABLE GGIS +B090;B090;1101 1175 11BB;B090;1101 1175 11BB; # (낐; 낐; 낐; 낐; 낐; ) HANGUL SYLLABLE GGISS +B091;B091;1101 1175 11BC;B091;1101 1175 11BC; # (낑; 낑; 낑; 낑; 낑; ) HANGUL SYLLABLE GGING +B092;B092;1101 1175 11BD;B092;1101 1175 11BD; # (낒; 낒; 낒; 낒; 낒; ) HANGUL SYLLABLE GGIJ +B093;B093;1101 1175 11BE;B093;1101 1175 11BE; # (낓; 낓; 낓; 낓; 낓; ) HANGUL SYLLABLE GGIC +B094;B094;1101 1175 11BF;B094;1101 1175 11BF; # (낔; 낔; 낔; 낔; 낔; ) HANGUL SYLLABLE GGIK +B095;B095;1101 1175 11C0;B095;1101 1175 11C0; # (낕; 낕; 낕; 낕; 낕; ) HANGUL SYLLABLE GGIT +B096;B096;1101 1175 11C1;B096;1101 1175 11C1; # (낖; 낖; 낖; 낖; 낖; ) HANGUL SYLLABLE GGIP +B097;B097;1101 1175 11C2;B097;1101 1175 11C2; # (낗; 낗; 낗; 낗; 낗; ) HANGUL SYLLABLE GGIH +B098;B098;1102 1161;B098;1102 1161; # (나; 나; 나; 나; 나; ) HANGUL SYLLABLE NA +B099;B099;1102 1161 11A8;B099;1102 1161 11A8; # (낙; 낙; 낙; 낙; 낙; ) HANGUL SYLLABLE NAG +B09A;B09A;1102 1161 11A9;B09A;1102 1161 11A9; # (낚; 낚; 낚; 낚; 낚; ) HANGUL SYLLABLE NAGG +B09B;B09B;1102 1161 11AA;B09B;1102 1161 11AA; # (낛; 낛; 낛; 낛; 낛; ) HANGUL SYLLABLE NAGS +B09C;B09C;1102 1161 11AB;B09C;1102 1161 11AB; # (난; 난; 난; 난; 난; ) HANGUL SYLLABLE NAN +B09D;B09D;1102 1161 11AC;B09D;1102 1161 11AC; # (낝; 낝; 낝; 낝; 낝; ) HANGUL SYLLABLE NANJ +B09E;B09E;1102 1161 11AD;B09E;1102 1161 11AD; # (낞; 낞; 낞; 낞; 낞; ) HANGUL SYLLABLE NANH +B09F;B09F;1102 1161 11AE;B09F;1102 1161 11AE; # (낟; 낟; 낟; 낟; 낟; ) HANGUL SYLLABLE NAD +B0A0;B0A0;1102 1161 11AF;B0A0;1102 1161 11AF; # (날; 날; 날; 날; 날; ) HANGUL SYLLABLE NAL +B0A1;B0A1;1102 1161 11B0;B0A1;1102 1161 11B0; # (낡; 낡; 낡; 낡; 낡; ) HANGUL SYLLABLE NALG +B0A2;B0A2;1102 1161 11B1;B0A2;1102 1161 11B1; # (낢; 낢; 낢; 낢; 낢; ) HANGUL SYLLABLE NALM +B0A3;B0A3;1102 1161 11B2;B0A3;1102 1161 11B2; # (낣; 낣; 낣; 낣; 낣; ) HANGUL SYLLABLE NALB +B0A4;B0A4;1102 1161 11B3;B0A4;1102 1161 11B3; # (낤; 낤; 낤; 낤; 낤; ) HANGUL SYLLABLE NALS +B0A5;B0A5;1102 1161 11B4;B0A5;1102 1161 11B4; # (낥; 낥; 낥; 낥; 낥; ) HANGUL SYLLABLE NALT +B0A6;B0A6;1102 1161 11B5;B0A6;1102 1161 11B5; # (낦; 낦; 낦; 낦; 낦; ) HANGUL SYLLABLE NALP +B0A7;B0A7;1102 1161 11B6;B0A7;1102 1161 11B6; # (낧; 낧; 낧; 낧; 낧; ) HANGUL SYLLABLE NALH +B0A8;B0A8;1102 1161 11B7;B0A8;1102 1161 11B7; # (남; 남; 남; 남; 남; ) HANGUL SYLLABLE NAM +B0A9;B0A9;1102 1161 11B8;B0A9;1102 1161 11B8; # (납; 납; 납; 납; 납; ) HANGUL SYLLABLE NAB +B0AA;B0AA;1102 1161 11B9;B0AA;1102 1161 11B9; # (낪; 낪; 낪; 낪; 낪; ) HANGUL SYLLABLE NABS +B0AB;B0AB;1102 1161 11BA;B0AB;1102 1161 11BA; # (낫; 낫; 낫; 낫; 낫; ) HANGUL SYLLABLE NAS +B0AC;B0AC;1102 1161 11BB;B0AC;1102 1161 11BB; # (났; 났; 났; 났; 났; ) HANGUL SYLLABLE NASS +B0AD;B0AD;1102 1161 11BC;B0AD;1102 1161 11BC; # (낭; 낭; 낭; 낭; 낭; ) HANGUL SYLLABLE NANG +B0AE;B0AE;1102 1161 11BD;B0AE;1102 1161 11BD; # (낮; 낮; 낮; 낮; 낮; ) HANGUL SYLLABLE NAJ +B0AF;B0AF;1102 1161 11BE;B0AF;1102 1161 11BE; # (낯; 낯; 낯; 낯; 낯; ) HANGUL SYLLABLE NAC +B0B0;B0B0;1102 1161 11BF;B0B0;1102 1161 11BF; # (낰; 낰; 낰; 낰; 낰; ) HANGUL SYLLABLE NAK +B0B1;B0B1;1102 1161 11C0;B0B1;1102 1161 11C0; # (낱; 낱; 낱; 낱; 낱; ) HANGUL SYLLABLE NAT +B0B2;B0B2;1102 1161 11C1;B0B2;1102 1161 11C1; # (낲; 낲; 낲; 낲; 낲; ) HANGUL SYLLABLE NAP +B0B3;B0B3;1102 1161 11C2;B0B3;1102 1161 11C2; # (낳; 낳; 낳; 낳; 낳; ) HANGUL SYLLABLE NAH +B0B4;B0B4;1102 1162;B0B4;1102 1162; # (내; 내; 내; 내; 내; ) HANGUL SYLLABLE NAE +B0B5;B0B5;1102 1162 11A8;B0B5;1102 1162 11A8; # (낵; 낵; 낵; 낵; 낵; ) HANGUL SYLLABLE NAEG +B0B6;B0B6;1102 1162 11A9;B0B6;1102 1162 11A9; # (낶; 낶; 낶; 낶; 낶; ) HANGUL SYLLABLE NAEGG +B0B7;B0B7;1102 1162 11AA;B0B7;1102 1162 11AA; # (낷; 낷; 낷; 낷; 낷; ) HANGUL SYLLABLE NAEGS +B0B8;B0B8;1102 1162 11AB;B0B8;1102 1162 11AB; # (낸; 낸; 낸; 낸; 낸; ) HANGUL SYLLABLE NAEN +B0B9;B0B9;1102 1162 11AC;B0B9;1102 1162 11AC; # (낹; 낹; 낹; 낹; 낹; ) HANGUL SYLLABLE NAENJ +B0BA;B0BA;1102 1162 11AD;B0BA;1102 1162 11AD; # (낺; 낺; 낺; 낺; 낺; ) HANGUL SYLLABLE NAENH +B0BB;B0BB;1102 1162 11AE;B0BB;1102 1162 11AE; # (낻; 낻; 낻; 낻; 낻; ) HANGUL SYLLABLE NAED +B0BC;B0BC;1102 1162 11AF;B0BC;1102 1162 11AF; # (낼; 낼; 낼; 낼; 낼; ) HANGUL SYLLABLE NAEL +B0BD;B0BD;1102 1162 11B0;B0BD;1102 1162 11B0; # (낽; 낽; 낽; 낽; 낽; ) HANGUL SYLLABLE NAELG +B0BE;B0BE;1102 1162 11B1;B0BE;1102 1162 11B1; # (낾; 낾; 낾; 낾; 낾; ) HANGUL SYLLABLE NAELM +B0BF;B0BF;1102 1162 11B2;B0BF;1102 1162 11B2; # (낿; 낿; 낿; 낿; 낿; ) HANGUL SYLLABLE NAELB +B0C0;B0C0;1102 1162 11B3;B0C0;1102 1162 11B3; # (냀; 냀; 냀; 냀; 냀; ) HANGUL SYLLABLE NAELS +B0C1;B0C1;1102 1162 11B4;B0C1;1102 1162 11B4; # (냁; 냁; 냁; 냁; 냁; ) HANGUL SYLLABLE NAELT +B0C2;B0C2;1102 1162 11B5;B0C2;1102 1162 11B5; # (냂; 냂; 냂; 냂; 냂; ) HANGUL SYLLABLE NAELP +B0C3;B0C3;1102 1162 11B6;B0C3;1102 1162 11B6; # (냃; 냃; 냃; 냃; 냃; ) HANGUL SYLLABLE NAELH +B0C4;B0C4;1102 1162 11B7;B0C4;1102 1162 11B7; # (냄; 냄; 냄; 냄; 냄; ) HANGUL SYLLABLE NAEM +B0C5;B0C5;1102 1162 11B8;B0C5;1102 1162 11B8; # (냅; 냅; 냅; 냅; 냅; ) HANGUL SYLLABLE NAEB +B0C6;B0C6;1102 1162 11B9;B0C6;1102 1162 11B9; # (냆; 냆; 냆; 냆; 냆; ) HANGUL SYLLABLE NAEBS +B0C7;B0C7;1102 1162 11BA;B0C7;1102 1162 11BA; # (냇; 냇; 냇; 냇; 냇; ) HANGUL SYLLABLE NAES +B0C8;B0C8;1102 1162 11BB;B0C8;1102 1162 11BB; # (냈; 냈; 냈; 냈; 냈; ) HANGUL SYLLABLE NAESS +B0C9;B0C9;1102 1162 11BC;B0C9;1102 1162 11BC; # (냉; 냉; 냉; 냉; 냉; ) HANGUL SYLLABLE NAENG +B0CA;B0CA;1102 1162 11BD;B0CA;1102 1162 11BD; # (냊; 냊; 냊; 냊; 냊; ) HANGUL SYLLABLE NAEJ +B0CB;B0CB;1102 1162 11BE;B0CB;1102 1162 11BE; # (냋; 냋; 냋; 냋; 냋; ) HANGUL SYLLABLE NAEC +B0CC;B0CC;1102 1162 11BF;B0CC;1102 1162 11BF; # (냌; 냌; 냌; 냌; 냌; ) HANGUL SYLLABLE NAEK +B0CD;B0CD;1102 1162 11C0;B0CD;1102 1162 11C0; # (냍; 냍; 냍; 냍; 냍; ) HANGUL SYLLABLE NAET +B0CE;B0CE;1102 1162 11C1;B0CE;1102 1162 11C1; # (냎; 냎; 냎; 냎; 냎; ) HANGUL SYLLABLE NAEP +B0CF;B0CF;1102 1162 11C2;B0CF;1102 1162 11C2; # (냏; 냏; 냏; 냏; 냏; ) HANGUL SYLLABLE NAEH +B0D0;B0D0;1102 1163;B0D0;1102 1163; # (냐; 냐; 냐; 냐; 냐; ) HANGUL SYLLABLE NYA +B0D1;B0D1;1102 1163 11A8;B0D1;1102 1163 11A8; # (냑; 냑; 냑; 냑; 냑; ) HANGUL SYLLABLE NYAG +B0D2;B0D2;1102 1163 11A9;B0D2;1102 1163 11A9; # (냒; 냒; 냒; 냒; 냒; ) HANGUL SYLLABLE NYAGG +B0D3;B0D3;1102 1163 11AA;B0D3;1102 1163 11AA; # (냓; 냓; 냓; 냓; 냓; ) HANGUL SYLLABLE NYAGS +B0D4;B0D4;1102 1163 11AB;B0D4;1102 1163 11AB; # (냔; 냔; 냔; 냔; 냔; ) HANGUL SYLLABLE NYAN +B0D5;B0D5;1102 1163 11AC;B0D5;1102 1163 11AC; # (냕; 냕; 냕; 냕; 냕; ) HANGUL SYLLABLE NYANJ +B0D6;B0D6;1102 1163 11AD;B0D6;1102 1163 11AD; # (냖; 냖; 냖; 냖; 냖; ) HANGUL SYLLABLE NYANH +B0D7;B0D7;1102 1163 11AE;B0D7;1102 1163 11AE; # (냗; 냗; 냗; 냗; 냗; ) HANGUL SYLLABLE NYAD +B0D8;B0D8;1102 1163 11AF;B0D8;1102 1163 11AF; # (냘; 냘; 냘; 냘; 냘; ) HANGUL SYLLABLE NYAL +B0D9;B0D9;1102 1163 11B0;B0D9;1102 1163 11B0; # (냙; 냙; 냙; 냙; 냙; ) HANGUL SYLLABLE NYALG +B0DA;B0DA;1102 1163 11B1;B0DA;1102 1163 11B1; # (냚; 냚; 냚; 냚; 냚; ) HANGUL SYLLABLE NYALM +B0DB;B0DB;1102 1163 11B2;B0DB;1102 1163 11B2; # (냛; 냛; 냛; 냛; 냛; ) HANGUL SYLLABLE NYALB +B0DC;B0DC;1102 1163 11B3;B0DC;1102 1163 11B3; # (냜; 냜; 냜; 냜; 냜; ) HANGUL SYLLABLE NYALS +B0DD;B0DD;1102 1163 11B4;B0DD;1102 1163 11B4; # (냝; 냝; 냝; 냝; 냝; ) HANGUL SYLLABLE NYALT +B0DE;B0DE;1102 1163 11B5;B0DE;1102 1163 11B5; # (냞; 냞; 냞; 냞; 냞; ) HANGUL SYLLABLE NYALP +B0DF;B0DF;1102 1163 11B6;B0DF;1102 1163 11B6; # (냟; 냟; 냟; 냟; 냟; ) HANGUL SYLLABLE NYALH +B0E0;B0E0;1102 1163 11B7;B0E0;1102 1163 11B7; # (냠; 냠; 냠; 냠; 냠; ) HANGUL SYLLABLE NYAM +B0E1;B0E1;1102 1163 11B8;B0E1;1102 1163 11B8; # (냡; 냡; 냡; 냡; 냡; ) HANGUL SYLLABLE NYAB +B0E2;B0E2;1102 1163 11B9;B0E2;1102 1163 11B9; # (냢; 냢; 냢; 냢; 냢; ) HANGUL SYLLABLE NYABS +B0E3;B0E3;1102 1163 11BA;B0E3;1102 1163 11BA; # (냣; 냣; 냣; 냣; 냣; ) HANGUL SYLLABLE NYAS +B0E4;B0E4;1102 1163 11BB;B0E4;1102 1163 11BB; # (냤; 냤; 냤; 냤; 냤; ) HANGUL SYLLABLE NYASS +B0E5;B0E5;1102 1163 11BC;B0E5;1102 1163 11BC; # (냥; 냥; 냥; 냥; 냥; ) HANGUL SYLLABLE NYANG +B0E6;B0E6;1102 1163 11BD;B0E6;1102 1163 11BD; # (냦; 냦; 냦; 냦; 냦; ) HANGUL SYLLABLE NYAJ +B0E7;B0E7;1102 1163 11BE;B0E7;1102 1163 11BE; # (냧; 냧; 냧; 냧; 냧; ) HANGUL SYLLABLE NYAC +B0E8;B0E8;1102 1163 11BF;B0E8;1102 1163 11BF; # (냨; 냨; 냨; 냨; 냨; ) HANGUL SYLLABLE NYAK +B0E9;B0E9;1102 1163 11C0;B0E9;1102 1163 11C0; # (냩; 냩; 냩; 냩; 냩; ) HANGUL SYLLABLE NYAT +B0EA;B0EA;1102 1163 11C1;B0EA;1102 1163 11C1; # (냪; 냪; 냪; 냪; 냪; ) HANGUL SYLLABLE NYAP +B0EB;B0EB;1102 1163 11C2;B0EB;1102 1163 11C2; # (냫; 냫; 냫; 냫; 냫; ) HANGUL SYLLABLE NYAH +B0EC;B0EC;1102 1164;B0EC;1102 1164; # (냬; 냬; 냬; 냬; 냬; ) HANGUL SYLLABLE NYAE +B0ED;B0ED;1102 1164 11A8;B0ED;1102 1164 11A8; # (냭; 냭; 냭; 냭; 냭; ) HANGUL SYLLABLE NYAEG +B0EE;B0EE;1102 1164 11A9;B0EE;1102 1164 11A9; # (냮; 냮; 냮; 냮; 냮; ) HANGUL SYLLABLE NYAEGG +B0EF;B0EF;1102 1164 11AA;B0EF;1102 1164 11AA; # (냯; 냯; 냯; 냯; 냯; ) HANGUL SYLLABLE NYAEGS +B0F0;B0F0;1102 1164 11AB;B0F0;1102 1164 11AB; # (냰; 냰; 냰; 냰; 냰; ) HANGUL SYLLABLE NYAEN +B0F1;B0F1;1102 1164 11AC;B0F1;1102 1164 11AC; # (냱; 냱; 냱; 냱; 냱; ) HANGUL SYLLABLE NYAENJ +B0F2;B0F2;1102 1164 11AD;B0F2;1102 1164 11AD; # (냲; 냲; 냲; 냲; 냲; ) HANGUL SYLLABLE NYAENH +B0F3;B0F3;1102 1164 11AE;B0F3;1102 1164 11AE; # (냳; 냳; 냳; 냳; 냳; ) HANGUL SYLLABLE NYAED +B0F4;B0F4;1102 1164 11AF;B0F4;1102 1164 11AF; # (냴; 냴; 냴; 냴; 냴; ) HANGUL SYLLABLE NYAEL +B0F5;B0F5;1102 1164 11B0;B0F5;1102 1164 11B0; # (냵; 냵; 냵; 냵; 냵; ) HANGUL SYLLABLE NYAELG +B0F6;B0F6;1102 1164 11B1;B0F6;1102 1164 11B1; # (냶; 냶; 냶; 냶; 냶; ) HANGUL SYLLABLE NYAELM +B0F7;B0F7;1102 1164 11B2;B0F7;1102 1164 11B2; # (냷; 냷; 냷; 냷; 냷; ) HANGUL SYLLABLE NYAELB +B0F8;B0F8;1102 1164 11B3;B0F8;1102 1164 11B3; # (냸; 냸; 냸; 냸; 냸; ) HANGUL SYLLABLE NYAELS +B0F9;B0F9;1102 1164 11B4;B0F9;1102 1164 11B4; # (냹; 냹; 냹; 냹; 냹; ) HANGUL SYLLABLE NYAELT +B0FA;B0FA;1102 1164 11B5;B0FA;1102 1164 11B5; # (냺; 냺; 냺; 냺; 냺; ) HANGUL SYLLABLE NYAELP +B0FB;B0FB;1102 1164 11B6;B0FB;1102 1164 11B6; # (냻; 냻; 냻; 냻; 냻; ) HANGUL SYLLABLE NYAELH +B0FC;B0FC;1102 1164 11B7;B0FC;1102 1164 11B7; # (냼; 냼; 냼; 냼; 냼; ) HANGUL SYLLABLE NYAEM +B0FD;B0FD;1102 1164 11B8;B0FD;1102 1164 11B8; # (냽; 냽; 냽; 냽; 냽; ) HANGUL SYLLABLE NYAEB +B0FE;B0FE;1102 1164 11B9;B0FE;1102 1164 11B9; # (냾; 냾; 냾; 냾; 냾; ) HANGUL SYLLABLE NYAEBS +B0FF;B0FF;1102 1164 11BA;B0FF;1102 1164 11BA; # (냿; 냿; 냿; 냿; 냿; ) HANGUL SYLLABLE NYAES +B100;B100;1102 1164 11BB;B100;1102 1164 11BB; # (넀; 넀; 넀; 넀; 넀; ) HANGUL SYLLABLE NYAESS +B101;B101;1102 1164 11BC;B101;1102 1164 11BC; # (넁; 넁; 넁; 넁; 넁; ) HANGUL SYLLABLE NYAENG +B102;B102;1102 1164 11BD;B102;1102 1164 11BD; # (넂; 넂; 넂; 넂; 넂; ) HANGUL SYLLABLE NYAEJ +B103;B103;1102 1164 11BE;B103;1102 1164 11BE; # (넃; 넃; 넃; 넃; 넃; ) HANGUL SYLLABLE NYAEC +B104;B104;1102 1164 11BF;B104;1102 1164 11BF; # (넄; 넄; 넄; 넄; 넄; ) HANGUL SYLLABLE NYAEK +B105;B105;1102 1164 11C0;B105;1102 1164 11C0; # (넅; 넅; 넅; 넅; 넅; ) HANGUL SYLLABLE NYAET +B106;B106;1102 1164 11C1;B106;1102 1164 11C1; # (넆; 넆; 넆; 넆; 넆; ) HANGUL SYLLABLE NYAEP +B107;B107;1102 1164 11C2;B107;1102 1164 11C2; # (넇; 넇; 넇; 넇; 넇; ) HANGUL SYLLABLE NYAEH +B108;B108;1102 1165;B108;1102 1165; # (너; 너; 너; 너; 너; ) HANGUL SYLLABLE NEO +B109;B109;1102 1165 11A8;B109;1102 1165 11A8; # (넉; 넉; 넉; 넉; 넉; ) HANGUL SYLLABLE NEOG +B10A;B10A;1102 1165 11A9;B10A;1102 1165 11A9; # (넊; 넊; 넊; 넊; 넊; ) HANGUL SYLLABLE NEOGG +B10B;B10B;1102 1165 11AA;B10B;1102 1165 11AA; # (넋; 넋; 넋; 넋; 넋; ) HANGUL SYLLABLE NEOGS +B10C;B10C;1102 1165 11AB;B10C;1102 1165 11AB; # (넌; 넌; 넌; 넌; 넌; ) HANGUL SYLLABLE NEON +B10D;B10D;1102 1165 11AC;B10D;1102 1165 11AC; # (넍; 넍; 넍; 넍; 넍; ) HANGUL SYLLABLE NEONJ +B10E;B10E;1102 1165 11AD;B10E;1102 1165 11AD; # (넎; 넎; 넎; 넎; 넎; ) HANGUL SYLLABLE NEONH +B10F;B10F;1102 1165 11AE;B10F;1102 1165 11AE; # (넏; 넏; 넏; 넏; 넏; ) HANGUL SYLLABLE NEOD +B110;B110;1102 1165 11AF;B110;1102 1165 11AF; # (널; 널; 널; 널; 널; ) HANGUL SYLLABLE NEOL +B111;B111;1102 1165 11B0;B111;1102 1165 11B0; # (넑; 넑; 넑; 넑; 넑; ) HANGUL SYLLABLE NEOLG +B112;B112;1102 1165 11B1;B112;1102 1165 11B1; # (넒; 넒; 넒; 넒; 넒; ) HANGUL SYLLABLE NEOLM +B113;B113;1102 1165 11B2;B113;1102 1165 11B2; # (넓; 넓; 넓; 넓; 넓; ) HANGUL SYLLABLE NEOLB +B114;B114;1102 1165 11B3;B114;1102 1165 11B3; # (넔; 넔; 넔; 넔; 넔; ) HANGUL SYLLABLE NEOLS +B115;B115;1102 1165 11B4;B115;1102 1165 11B4; # (넕; 넕; 넕; 넕; 넕; ) HANGUL SYLLABLE NEOLT +B116;B116;1102 1165 11B5;B116;1102 1165 11B5; # (넖; 넖; 넖; 넖; 넖; ) HANGUL SYLLABLE NEOLP +B117;B117;1102 1165 11B6;B117;1102 1165 11B6; # (넗; 넗; 넗; 넗; 넗; ) HANGUL SYLLABLE NEOLH +B118;B118;1102 1165 11B7;B118;1102 1165 11B7; # (넘; 넘; 넘; 넘; 넘; ) HANGUL SYLLABLE NEOM +B119;B119;1102 1165 11B8;B119;1102 1165 11B8; # (넙; 넙; 넙; 넙; 넙; ) HANGUL SYLLABLE NEOB +B11A;B11A;1102 1165 11B9;B11A;1102 1165 11B9; # (넚; 넚; 넚; 넚; 넚; ) HANGUL SYLLABLE NEOBS +B11B;B11B;1102 1165 11BA;B11B;1102 1165 11BA; # (넛; 넛; 넛; 넛; 넛; ) HANGUL SYLLABLE NEOS +B11C;B11C;1102 1165 11BB;B11C;1102 1165 11BB; # (넜; 넜; 넜; 넜; 넜; ) HANGUL SYLLABLE NEOSS +B11D;B11D;1102 1165 11BC;B11D;1102 1165 11BC; # (넝; 넝; 넝; 넝; 넝; ) HANGUL SYLLABLE NEONG +B11E;B11E;1102 1165 11BD;B11E;1102 1165 11BD; # (넞; 넞; 넞; 넞; 넞; ) HANGUL SYLLABLE NEOJ +B11F;B11F;1102 1165 11BE;B11F;1102 1165 11BE; # (넟; 넟; 넟; 넟; 넟; ) HANGUL SYLLABLE NEOC +B120;B120;1102 1165 11BF;B120;1102 1165 11BF; # (넠; 넠; 넠; 넠; 넠; ) HANGUL SYLLABLE NEOK +B121;B121;1102 1165 11C0;B121;1102 1165 11C0; # (넡; 넡; 넡; 넡; 넡; ) HANGUL SYLLABLE NEOT +B122;B122;1102 1165 11C1;B122;1102 1165 11C1; # (넢; 넢; 넢; 넢; 넢; ) HANGUL SYLLABLE NEOP +B123;B123;1102 1165 11C2;B123;1102 1165 11C2; # (넣; 넣; 넣; 넣; 넣; ) HANGUL SYLLABLE NEOH +B124;B124;1102 1166;B124;1102 1166; # (네; 네; 네; 네; 네; ) HANGUL SYLLABLE NE +B125;B125;1102 1166 11A8;B125;1102 1166 11A8; # (넥; 넥; 넥; 넥; 넥; ) HANGUL SYLLABLE NEG +B126;B126;1102 1166 11A9;B126;1102 1166 11A9; # (넦; 넦; 넦; 넦; 넦; ) HANGUL SYLLABLE NEGG +B127;B127;1102 1166 11AA;B127;1102 1166 11AA; # (넧; 넧; 넧; 넧; 넧; ) HANGUL SYLLABLE NEGS +B128;B128;1102 1166 11AB;B128;1102 1166 11AB; # (넨; 넨; 넨; 넨; 넨; ) HANGUL SYLLABLE NEN +B129;B129;1102 1166 11AC;B129;1102 1166 11AC; # (넩; 넩; 넩; 넩; 넩; ) HANGUL SYLLABLE NENJ +B12A;B12A;1102 1166 11AD;B12A;1102 1166 11AD; # (넪; 넪; 넪; 넪; 넪; ) HANGUL SYLLABLE NENH +B12B;B12B;1102 1166 11AE;B12B;1102 1166 11AE; # (넫; 넫; 넫; 넫; 넫; ) HANGUL SYLLABLE NED +B12C;B12C;1102 1166 11AF;B12C;1102 1166 11AF; # (넬; 넬; 넬; 넬; 넬; ) HANGUL SYLLABLE NEL +B12D;B12D;1102 1166 11B0;B12D;1102 1166 11B0; # (넭; 넭; 넭; 넭; 넭; ) HANGUL SYLLABLE NELG +B12E;B12E;1102 1166 11B1;B12E;1102 1166 11B1; # (넮; 넮; 넮; 넮; 넮; ) HANGUL SYLLABLE NELM +B12F;B12F;1102 1166 11B2;B12F;1102 1166 11B2; # (넯; 넯; 넯; 넯; 넯; ) HANGUL SYLLABLE NELB +B130;B130;1102 1166 11B3;B130;1102 1166 11B3; # (넰; 넰; 넰; 넰; 넰; ) HANGUL SYLLABLE NELS +B131;B131;1102 1166 11B4;B131;1102 1166 11B4; # (넱; 넱; 넱; 넱; 넱; ) HANGUL SYLLABLE NELT +B132;B132;1102 1166 11B5;B132;1102 1166 11B5; # (넲; 넲; 넲; 넲; 넲; ) HANGUL SYLLABLE NELP +B133;B133;1102 1166 11B6;B133;1102 1166 11B6; # (넳; 넳; 넳; 넳; 넳; ) HANGUL SYLLABLE NELH +B134;B134;1102 1166 11B7;B134;1102 1166 11B7; # (넴; 넴; 넴; 넴; 넴; ) HANGUL SYLLABLE NEM +B135;B135;1102 1166 11B8;B135;1102 1166 11B8; # (넵; 넵; 넵; 넵; 넵; ) HANGUL SYLLABLE NEB +B136;B136;1102 1166 11B9;B136;1102 1166 11B9; # (넶; 넶; 넶; 넶; 넶; ) HANGUL SYLLABLE NEBS +B137;B137;1102 1166 11BA;B137;1102 1166 11BA; # (넷; 넷; 넷; 넷; 넷; ) HANGUL SYLLABLE NES +B138;B138;1102 1166 11BB;B138;1102 1166 11BB; # (넸; 넸; 넸; 넸; 넸; ) HANGUL SYLLABLE NESS +B139;B139;1102 1166 11BC;B139;1102 1166 11BC; # (넹; 넹; 넹; 넹; 넹; ) HANGUL SYLLABLE NENG +B13A;B13A;1102 1166 11BD;B13A;1102 1166 11BD; # (넺; 넺; 넺; 넺; 넺; ) HANGUL SYLLABLE NEJ +B13B;B13B;1102 1166 11BE;B13B;1102 1166 11BE; # (넻; 넻; 넻; 넻; 넻; ) HANGUL SYLLABLE NEC +B13C;B13C;1102 1166 11BF;B13C;1102 1166 11BF; # (넼; 넼; 넼; 넼; 넼; ) HANGUL SYLLABLE NEK +B13D;B13D;1102 1166 11C0;B13D;1102 1166 11C0; # (넽; 넽; 넽; 넽; 넽; ) HANGUL SYLLABLE NET +B13E;B13E;1102 1166 11C1;B13E;1102 1166 11C1; # (넾; 넾; 넾; 넾; 넾; ) HANGUL SYLLABLE NEP +B13F;B13F;1102 1166 11C2;B13F;1102 1166 11C2; # (넿; 넿; 넿; 넿; 넿; ) HANGUL SYLLABLE NEH +B140;B140;1102 1167;B140;1102 1167; # (녀; 녀; 녀; 녀; 녀; ) HANGUL SYLLABLE NYEO +B141;B141;1102 1167 11A8;B141;1102 1167 11A8; # (녁; 녁; 녁; 녁; 녁; ) HANGUL SYLLABLE NYEOG +B142;B142;1102 1167 11A9;B142;1102 1167 11A9; # (녂; 녂; 녂; 녂; 녂; ) HANGUL SYLLABLE NYEOGG +B143;B143;1102 1167 11AA;B143;1102 1167 11AA; # (녃; 녃; 녃; 녃; 녃; ) HANGUL SYLLABLE NYEOGS +B144;B144;1102 1167 11AB;B144;1102 1167 11AB; # (년; 년; 년; 년; 년; ) HANGUL SYLLABLE NYEON +B145;B145;1102 1167 11AC;B145;1102 1167 11AC; # (녅; 녅; 녅; 녅; 녅; ) HANGUL SYLLABLE NYEONJ +B146;B146;1102 1167 11AD;B146;1102 1167 11AD; # (녆; 녆; 녆; 녆; 녆; ) HANGUL SYLLABLE NYEONH +B147;B147;1102 1167 11AE;B147;1102 1167 11AE; # (녇; 녇; 녇; 녇; 녇; ) HANGUL SYLLABLE NYEOD +B148;B148;1102 1167 11AF;B148;1102 1167 11AF; # (녈; 녈; 녈; 녈; 녈; ) HANGUL SYLLABLE NYEOL +B149;B149;1102 1167 11B0;B149;1102 1167 11B0; # (녉; 녉; 녉; 녉; 녉; ) HANGUL SYLLABLE NYEOLG +B14A;B14A;1102 1167 11B1;B14A;1102 1167 11B1; # (녊; 녊; 녊; 녊; 녊; ) HANGUL SYLLABLE NYEOLM +B14B;B14B;1102 1167 11B2;B14B;1102 1167 11B2; # (녋; 녋; 녋; 녋; 녋; ) HANGUL SYLLABLE NYEOLB +B14C;B14C;1102 1167 11B3;B14C;1102 1167 11B3; # (녌; 녌; 녌; 녌; 녌; ) HANGUL SYLLABLE NYEOLS +B14D;B14D;1102 1167 11B4;B14D;1102 1167 11B4; # (녍; 녍; 녍; 녍; 녍; ) HANGUL SYLLABLE NYEOLT +B14E;B14E;1102 1167 11B5;B14E;1102 1167 11B5; # (녎; 녎; 녎; 녎; 녎; ) HANGUL SYLLABLE NYEOLP +B14F;B14F;1102 1167 11B6;B14F;1102 1167 11B6; # (녏; 녏; 녏; 녏; 녏; ) HANGUL SYLLABLE NYEOLH +B150;B150;1102 1167 11B7;B150;1102 1167 11B7; # (념; 념; 념; 념; 념; ) HANGUL SYLLABLE NYEOM +B151;B151;1102 1167 11B8;B151;1102 1167 11B8; # (녑; 녑; 녑; 녑; 녑; ) HANGUL SYLLABLE NYEOB +B152;B152;1102 1167 11B9;B152;1102 1167 11B9; # (녒; 녒; 녒; 녒; 녒; ) HANGUL SYLLABLE NYEOBS +B153;B153;1102 1167 11BA;B153;1102 1167 11BA; # (녓; 녓; 녓; 녓; 녓; ) HANGUL SYLLABLE NYEOS +B154;B154;1102 1167 11BB;B154;1102 1167 11BB; # (녔; 녔; 녔; 녔; 녔; ) HANGUL SYLLABLE NYEOSS +B155;B155;1102 1167 11BC;B155;1102 1167 11BC; # (녕; 녕; 녕; 녕; 녕; ) HANGUL SYLLABLE NYEONG +B156;B156;1102 1167 11BD;B156;1102 1167 11BD; # (녖; 녖; 녖; 녖; 녖; ) HANGUL SYLLABLE NYEOJ +B157;B157;1102 1167 11BE;B157;1102 1167 11BE; # (녗; 녗; 녗; 녗; 녗; ) HANGUL SYLLABLE NYEOC +B158;B158;1102 1167 11BF;B158;1102 1167 11BF; # (녘; 녘; 녘; 녘; 녘; ) HANGUL SYLLABLE NYEOK +B159;B159;1102 1167 11C0;B159;1102 1167 11C0; # (녙; 녙; 녙; 녙; 녙; ) HANGUL SYLLABLE NYEOT +B15A;B15A;1102 1167 11C1;B15A;1102 1167 11C1; # (녚; 녚; 녚; 녚; 녚; ) HANGUL SYLLABLE NYEOP +B15B;B15B;1102 1167 11C2;B15B;1102 1167 11C2; # (녛; 녛; 녛; 녛; 녛; ) HANGUL SYLLABLE NYEOH +B15C;B15C;1102 1168;B15C;1102 1168; # (녜; 녜; 녜; 녜; 녜; ) HANGUL SYLLABLE NYE +B15D;B15D;1102 1168 11A8;B15D;1102 1168 11A8; # (녝; 녝; 녝; 녝; 녝; ) HANGUL SYLLABLE NYEG +B15E;B15E;1102 1168 11A9;B15E;1102 1168 11A9; # (녞; 녞; 녞; 녞; 녞; ) HANGUL SYLLABLE NYEGG +B15F;B15F;1102 1168 11AA;B15F;1102 1168 11AA; # (녟; 녟; 녟; 녟; 녟; ) HANGUL SYLLABLE NYEGS +B160;B160;1102 1168 11AB;B160;1102 1168 11AB; # (녠; 녠; 녠; 녠; 녠; ) HANGUL SYLLABLE NYEN +B161;B161;1102 1168 11AC;B161;1102 1168 11AC; # (녡; 녡; 녡; 녡; 녡; ) HANGUL SYLLABLE NYENJ +B162;B162;1102 1168 11AD;B162;1102 1168 11AD; # (녢; 녢; 녢; 녢; 녢; ) HANGUL SYLLABLE NYENH +B163;B163;1102 1168 11AE;B163;1102 1168 11AE; # (녣; 녣; 녣; 녣; 녣; ) HANGUL SYLLABLE NYED +B164;B164;1102 1168 11AF;B164;1102 1168 11AF; # (녤; 녤; 녤; 녤; 녤; ) HANGUL SYLLABLE NYEL +B165;B165;1102 1168 11B0;B165;1102 1168 11B0; # (녥; 녥; 녥; 녥; 녥; ) HANGUL SYLLABLE NYELG +B166;B166;1102 1168 11B1;B166;1102 1168 11B1; # (녦; 녦; 녦; 녦; 녦; ) HANGUL SYLLABLE NYELM +B167;B167;1102 1168 11B2;B167;1102 1168 11B2; # (녧; 녧; 녧; 녧; 녧; ) HANGUL SYLLABLE NYELB +B168;B168;1102 1168 11B3;B168;1102 1168 11B3; # (녨; 녨; 녨; 녨; 녨; ) HANGUL SYLLABLE NYELS +B169;B169;1102 1168 11B4;B169;1102 1168 11B4; # (녩; 녩; 녩; 녩; 녩; ) HANGUL SYLLABLE NYELT +B16A;B16A;1102 1168 11B5;B16A;1102 1168 11B5; # (녪; 녪; 녪; 녪; 녪; ) HANGUL SYLLABLE NYELP +B16B;B16B;1102 1168 11B6;B16B;1102 1168 11B6; # (녫; 녫; 녫; 녫; 녫; ) HANGUL SYLLABLE NYELH +B16C;B16C;1102 1168 11B7;B16C;1102 1168 11B7; # (녬; 녬; 녬; 녬; 녬; ) HANGUL SYLLABLE NYEM +B16D;B16D;1102 1168 11B8;B16D;1102 1168 11B8; # (녭; 녭; 녭; 녭; 녭; ) HANGUL SYLLABLE NYEB +B16E;B16E;1102 1168 11B9;B16E;1102 1168 11B9; # (녮; 녮; 녮; 녮; 녮; ) HANGUL SYLLABLE NYEBS +B16F;B16F;1102 1168 11BA;B16F;1102 1168 11BA; # (녯; 녯; 녯; 녯; 녯; ) HANGUL SYLLABLE NYES +B170;B170;1102 1168 11BB;B170;1102 1168 11BB; # (녰; 녰; 녰; 녰; 녰; ) HANGUL SYLLABLE NYESS +B171;B171;1102 1168 11BC;B171;1102 1168 11BC; # (녱; 녱; 녱; 녱; 녱; ) HANGUL SYLLABLE NYENG +B172;B172;1102 1168 11BD;B172;1102 1168 11BD; # (녲; 녲; 녲; 녲; 녲; ) HANGUL SYLLABLE NYEJ +B173;B173;1102 1168 11BE;B173;1102 1168 11BE; # (녳; 녳; 녳; 녳; 녳; ) HANGUL SYLLABLE NYEC +B174;B174;1102 1168 11BF;B174;1102 1168 11BF; # (녴; 녴; 녴; 녴; 녴; ) HANGUL SYLLABLE NYEK +B175;B175;1102 1168 11C0;B175;1102 1168 11C0; # (녵; 녵; 녵; 녵; 녵; ) HANGUL SYLLABLE NYET +B176;B176;1102 1168 11C1;B176;1102 1168 11C1; # (녶; 녶; 녶; 녶; 녶; ) HANGUL SYLLABLE NYEP +B177;B177;1102 1168 11C2;B177;1102 1168 11C2; # (녷; 녷; 녷; 녷; 녷; ) HANGUL SYLLABLE NYEH +B178;B178;1102 1169;B178;1102 1169; # (노; 노; 노; 노; 노; ) HANGUL SYLLABLE NO +B179;B179;1102 1169 11A8;B179;1102 1169 11A8; # (녹; 녹; 녹; 녹; 녹; ) HANGUL SYLLABLE NOG +B17A;B17A;1102 1169 11A9;B17A;1102 1169 11A9; # (녺; 녺; 녺; 녺; 녺; ) HANGUL SYLLABLE NOGG +B17B;B17B;1102 1169 11AA;B17B;1102 1169 11AA; # (녻; 녻; 녻; 녻; 녻; ) HANGUL SYLLABLE NOGS +B17C;B17C;1102 1169 11AB;B17C;1102 1169 11AB; # (논; 논; 논; 논; 논; ) HANGUL SYLLABLE NON +B17D;B17D;1102 1169 11AC;B17D;1102 1169 11AC; # (녽; 녽; 녽; 녽; 녽; ) HANGUL SYLLABLE NONJ +B17E;B17E;1102 1169 11AD;B17E;1102 1169 11AD; # (녾; 녾; 녾; 녾; 녾; ) HANGUL SYLLABLE NONH +B17F;B17F;1102 1169 11AE;B17F;1102 1169 11AE; # (녿; 녿; 녿; 녿; 녿; ) HANGUL SYLLABLE NOD +B180;B180;1102 1169 11AF;B180;1102 1169 11AF; # (놀; 놀; 놀; 놀; 놀; ) HANGUL SYLLABLE NOL +B181;B181;1102 1169 11B0;B181;1102 1169 11B0; # (놁; 놁; 놁; 놁; 놁; ) HANGUL SYLLABLE NOLG +B182;B182;1102 1169 11B1;B182;1102 1169 11B1; # (놂; 놂; 놂; 놂; 놂; ) HANGUL SYLLABLE NOLM +B183;B183;1102 1169 11B2;B183;1102 1169 11B2; # (놃; 놃; 놃; 놃; 놃; ) HANGUL SYLLABLE NOLB +B184;B184;1102 1169 11B3;B184;1102 1169 11B3; # (놄; 놄; 놄; 놄; 놄; ) HANGUL SYLLABLE NOLS +B185;B185;1102 1169 11B4;B185;1102 1169 11B4; # (놅; 놅; 놅; 놅; 놅; ) HANGUL SYLLABLE NOLT +B186;B186;1102 1169 11B5;B186;1102 1169 11B5; # (놆; 놆; 놆; 놆; 놆; ) HANGUL SYLLABLE NOLP +B187;B187;1102 1169 11B6;B187;1102 1169 11B6; # (놇; 놇; 놇; 놇; 놇; ) HANGUL SYLLABLE NOLH +B188;B188;1102 1169 11B7;B188;1102 1169 11B7; # (놈; 놈; 놈; 놈; 놈; ) HANGUL SYLLABLE NOM +B189;B189;1102 1169 11B8;B189;1102 1169 11B8; # (놉; 놉; 놉; 놉; 놉; ) HANGUL SYLLABLE NOB +B18A;B18A;1102 1169 11B9;B18A;1102 1169 11B9; # (놊; 놊; 놊; 놊; 놊; ) HANGUL SYLLABLE NOBS +B18B;B18B;1102 1169 11BA;B18B;1102 1169 11BA; # (놋; 놋; 놋; 놋; 놋; ) HANGUL SYLLABLE NOS +B18C;B18C;1102 1169 11BB;B18C;1102 1169 11BB; # (놌; 놌; 놌; 놌; 놌; ) HANGUL SYLLABLE NOSS +B18D;B18D;1102 1169 11BC;B18D;1102 1169 11BC; # (농; 농; 농; 농; 농; ) HANGUL SYLLABLE NONG +B18E;B18E;1102 1169 11BD;B18E;1102 1169 11BD; # (놎; 놎; 놎; 놎; 놎; ) HANGUL SYLLABLE NOJ +B18F;B18F;1102 1169 11BE;B18F;1102 1169 11BE; # (놏; 놏; 놏; 놏; 놏; ) HANGUL SYLLABLE NOC +B190;B190;1102 1169 11BF;B190;1102 1169 11BF; # (놐; 놐; 놐; 놐; 놐; ) HANGUL SYLLABLE NOK +B191;B191;1102 1169 11C0;B191;1102 1169 11C0; # (놑; 놑; 놑; 놑; 놑; ) HANGUL SYLLABLE NOT +B192;B192;1102 1169 11C1;B192;1102 1169 11C1; # (높; 높; 높; 높; 높; ) HANGUL SYLLABLE NOP +B193;B193;1102 1169 11C2;B193;1102 1169 11C2; # (놓; 놓; 놓; 놓; 놓; ) HANGUL SYLLABLE NOH +B194;B194;1102 116A;B194;1102 116A; # (놔; 놔; 놔; 놔; 놔; ) HANGUL SYLLABLE NWA +B195;B195;1102 116A 11A8;B195;1102 116A 11A8; # (놕; 놕; 놕; 놕; 놕; ) HANGUL SYLLABLE NWAG +B196;B196;1102 116A 11A9;B196;1102 116A 11A9; # (놖; 놖; 놖; 놖; 놖; ) HANGUL SYLLABLE NWAGG +B197;B197;1102 116A 11AA;B197;1102 116A 11AA; # (놗; 놗; 놗; 놗; 놗; ) HANGUL SYLLABLE NWAGS +B198;B198;1102 116A 11AB;B198;1102 116A 11AB; # (놘; 놘; 놘; 놘; 놘; ) HANGUL SYLLABLE NWAN +B199;B199;1102 116A 11AC;B199;1102 116A 11AC; # (놙; 놙; 놙; 놙; 놙; ) HANGUL SYLLABLE NWANJ +B19A;B19A;1102 116A 11AD;B19A;1102 116A 11AD; # (놚; 놚; 놚; 놚; 놚; ) HANGUL SYLLABLE NWANH +B19B;B19B;1102 116A 11AE;B19B;1102 116A 11AE; # (놛; 놛; 놛; 놛; 놛; ) HANGUL SYLLABLE NWAD +B19C;B19C;1102 116A 11AF;B19C;1102 116A 11AF; # (놜; 놜; 놜; 놜; 놜; ) HANGUL SYLLABLE NWAL +B19D;B19D;1102 116A 11B0;B19D;1102 116A 11B0; # (놝; 놝; 놝; 놝; 놝; ) HANGUL SYLLABLE NWALG +B19E;B19E;1102 116A 11B1;B19E;1102 116A 11B1; # (놞; 놞; 놞; 놞; 놞; ) HANGUL SYLLABLE NWALM +B19F;B19F;1102 116A 11B2;B19F;1102 116A 11B2; # (놟; 놟; 놟; 놟; 놟; ) HANGUL SYLLABLE NWALB +B1A0;B1A0;1102 116A 11B3;B1A0;1102 116A 11B3; # (놠; 놠; 놠; 놠; 놠; ) HANGUL SYLLABLE NWALS +B1A1;B1A1;1102 116A 11B4;B1A1;1102 116A 11B4; # (놡; 놡; 놡; 놡; 놡; ) HANGUL SYLLABLE NWALT +B1A2;B1A2;1102 116A 11B5;B1A2;1102 116A 11B5; # (놢; 놢; 놢; 놢; 놢; ) HANGUL SYLLABLE NWALP +B1A3;B1A3;1102 116A 11B6;B1A3;1102 116A 11B6; # (놣; 놣; 놣; 놣; 놣; ) HANGUL SYLLABLE NWALH +B1A4;B1A4;1102 116A 11B7;B1A4;1102 116A 11B7; # (놤; 놤; 놤; 놤; 놤; ) HANGUL SYLLABLE NWAM +B1A5;B1A5;1102 116A 11B8;B1A5;1102 116A 11B8; # (놥; 놥; 놥; 놥; 놥; ) HANGUL SYLLABLE NWAB +B1A6;B1A6;1102 116A 11B9;B1A6;1102 116A 11B9; # (놦; 놦; 놦; 놦; 놦; ) HANGUL SYLLABLE NWABS +B1A7;B1A7;1102 116A 11BA;B1A7;1102 116A 11BA; # (놧; 놧; 놧; 놧; 놧; ) HANGUL SYLLABLE NWAS +B1A8;B1A8;1102 116A 11BB;B1A8;1102 116A 11BB; # (놨; 놨; 놨; 놨; 놨; ) HANGUL SYLLABLE NWASS +B1A9;B1A9;1102 116A 11BC;B1A9;1102 116A 11BC; # (놩; 놩; 놩; 놩; 놩; ) HANGUL SYLLABLE NWANG +B1AA;B1AA;1102 116A 11BD;B1AA;1102 116A 11BD; # (놪; 놪; 놪; 놪; 놪; ) HANGUL SYLLABLE NWAJ +B1AB;B1AB;1102 116A 11BE;B1AB;1102 116A 11BE; # (놫; 놫; 놫; 놫; 놫; ) HANGUL SYLLABLE NWAC +B1AC;B1AC;1102 116A 11BF;B1AC;1102 116A 11BF; # (놬; 놬; 놬; 놬; 놬; ) HANGUL SYLLABLE NWAK +B1AD;B1AD;1102 116A 11C0;B1AD;1102 116A 11C0; # (놭; 놭; 놭; 놭; 놭; ) HANGUL SYLLABLE NWAT +B1AE;B1AE;1102 116A 11C1;B1AE;1102 116A 11C1; # (놮; 놮; 놮; 놮; 놮; ) HANGUL SYLLABLE NWAP +B1AF;B1AF;1102 116A 11C2;B1AF;1102 116A 11C2; # (놯; 놯; 놯; 놯; 놯; ) HANGUL SYLLABLE NWAH +B1B0;B1B0;1102 116B;B1B0;1102 116B; # (놰; 놰; 놰; 놰; 놰; ) HANGUL SYLLABLE NWAE +B1B1;B1B1;1102 116B 11A8;B1B1;1102 116B 11A8; # (놱; 놱; 놱; 놱; 놱; ) HANGUL SYLLABLE NWAEG +B1B2;B1B2;1102 116B 11A9;B1B2;1102 116B 11A9; # (놲; 놲; 놲; 놲; 놲; ) HANGUL SYLLABLE NWAEGG +B1B3;B1B3;1102 116B 11AA;B1B3;1102 116B 11AA; # (놳; 놳; 놳; 놳; 놳; ) HANGUL SYLLABLE NWAEGS +B1B4;B1B4;1102 116B 11AB;B1B4;1102 116B 11AB; # (놴; 놴; 놴; 놴; 놴; ) HANGUL SYLLABLE NWAEN +B1B5;B1B5;1102 116B 11AC;B1B5;1102 116B 11AC; # (놵; 놵; 놵; 놵; 놵; ) HANGUL SYLLABLE NWAENJ +B1B6;B1B6;1102 116B 11AD;B1B6;1102 116B 11AD; # (놶; 놶; 놶; 놶; 놶; ) HANGUL SYLLABLE NWAENH +B1B7;B1B7;1102 116B 11AE;B1B7;1102 116B 11AE; # (놷; 놷; 놷; 놷; 놷; ) HANGUL SYLLABLE NWAED +B1B8;B1B8;1102 116B 11AF;B1B8;1102 116B 11AF; # (놸; 놸; 놸; 놸; 놸; ) HANGUL SYLLABLE NWAEL +B1B9;B1B9;1102 116B 11B0;B1B9;1102 116B 11B0; # (놹; 놹; 놹; 놹; 놹; ) HANGUL SYLLABLE NWAELG +B1BA;B1BA;1102 116B 11B1;B1BA;1102 116B 11B1; # (놺; 놺; 놺; 놺; 놺; ) HANGUL SYLLABLE NWAELM +B1BB;B1BB;1102 116B 11B2;B1BB;1102 116B 11B2; # (놻; 놻; 놻; 놻; 놻; ) HANGUL SYLLABLE NWAELB +B1BC;B1BC;1102 116B 11B3;B1BC;1102 116B 11B3; # (놼; 놼; 놼; 놼; 놼; ) HANGUL SYLLABLE NWAELS +B1BD;B1BD;1102 116B 11B4;B1BD;1102 116B 11B4; # (놽; 놽; 놽; 놽; 놽; ) HANGUL SYLLABLE NWAELT +B1BE;B1BE;1102 116B 11B5;B1BE;1102 116B 11B5; # (놾; 놾; 놾; 놾; 놾; ) HANGUL SYLLABLE NWAELP +B1BF;B1BF;1102 116B 11B6;B1BF;1102 116B 11B6; # (놿; 놿; 놿; 놿; 놿; ) HANGUL SYLLABLE NWAELH +B1C0;B1C0;1102 116B 11B7;B1C0;1102 116B 11B7; # (뇀; 뇀; 뇀; 뇀; 뇀; ) HANGUL SYLLABLE NWAEM +B1C1;B1C1;1102 116B 11B8;B1C1;1102 116B 11B8; # (뇁; 뇁; 뇁; 뇁; 뇁; ) HANGUL SYLLABLE NWAEB +B1C2;B1C2;1102 116B 11B9;B1C2;1102 116B 11B9; # (뇂; 뇂; 뇂; 뇂; 뇂; ) HANGUL SYLLABLE NWAEBS +B1C3;B1C3;1102 116B 11BA;B1C3;1102 116B 11BA; # (뇃; 뇃; 뇃; 뇃; 뇃; ) HANGUL SYLLABLE NWAES +B1C4;B1C4;1102 116B 11BB;B1C4;1102 116B 11BB; # (뇄; 뇄; 뇄; 뇄; 뇄; ) HANGUL SYLLABLE NWAESS +B1C5;B1C5;1102 116B 11BC;B1C5;1102 116B 11BC; # (뇅; 뇅; 뇅; 뇅; 뇅; ) HANGUL SYLLABLE NWAENG +B1C6;B1C6;1102 116B 11BD;B1C6;1102 116B 11BD; # (뇆; 뇆; 뇆; 뇆; 뇆; ) HANGUL SYLLABLE NWAEJ +B1C7;B1C7;1102 116B 11BE;B1C7;1102 116B 11BE; # (뇇; 뇇; 뇇; 뇇; 뇇; ) HANGUL SYLLABLE NWAEC +B1C8;B1C8;1102 116B 11BF;B1C8;1102 116B 11BF; # (뇈; 뇈; 뇈; 뇈; 뇈; ) HANGUL SYLLABLE NWAEK +B1C9;B1C9;1102 116B 11C0;B1C9;1102 116B 11C0; # (뇉; 뇉; 뇉; 뇉; 뇉; ) HANGUL SYLLABLE NWAET +B1CA;B1CA;1102 116B 11C1;B1CA;1102 116B 11C1; # (뇊; 뇊; 뇊; 뇊; 뇊; ) HANGUL SYLLABLE NWAEP +B1CB;B1CB;1102 116B 11C2;B1CB;1102 116B 11C2; # (뇋; 뇋; 뇋; 뇋; 뇋; ) HANGUL SYLLABLE NWAEH +B1CC;B1CC;1102 116C;B1CC;1102 116C; # (뇌; 뇌; 뇌; 뇌; 뇌; ) HANGUL SYLLABLE NOE +B1CD;B1CD;1102 116C 11A8;B1CD;1102 116C 11A8; # (뇍; 뇍; 뇍; 뇍; 뇍; ) HANGUL SYLLABLE NOEG +B1CE;B1CE;1102 116C 11A9;B1CE;1102 116C 11A9; # (뇎; 뇎; 뇎; 뇎; 뇎; ) HANGUL SYLLABLE NOEGG +B1CF;B1CF;1102 116C 11AA;B1CF;1102 116C 11AA; # (뇏; 뇏; 뇏; 뇏; 뇏; ) HANGUL SYLLABLE NOEGS +B1D0;B1D0;1102 116C 11AB;B1D0;1102 116C 11AB; # (뇐; 뇐; 뇐; 뇐; 뇐; ) HANGUL SYLLABLE NOEN +B1D1;B1D1;1102 116C 11AC;B1D1;1102 116C 11AC; # (뇑; 뇑; 뇑; 뇑; 뇑; ) HANGUL SYLLABLE NOENJ +B1D2;B1D2;1102 116C 11AD;B1D2;1102 116C 11AD; # (뇒; 뇒; 뇒; 뇒; 뇒; ) HANGUL SYLLABLE NOENH +B1D3;B1D3;1102 116C 11AE;B1D3;1102 116C 11AE; # (뇓; 뇓; 뇓; 뇓; 뇓; ) HANGUL SYLLABLE NOED +B1D4;B1D4;1102 116C 11AF;B1D4;1102 116C 11AF; # (뇔; 뇔; 뇔; 뇔; 뇔; ) HANGUL SYLLABLE NOEL +B1D5;B1D5;1102 116C 11B0;B1D5;1102 116C 11B0; # (뇕; 뇕; 뇕; 뇕; 뇕; ) HANGUL SYLLABLE NOELG +B1D6;B1D6;1102 116C 11B1;B1D6;1102 116C 11B1; # (뇖; 뇖; 뇖; 뇖; 뇖; ) HANGUL SYLLABLE NOELM +B1D7;B1D7;1102 116C 11B2;B1D7;1102 116C 11B2; # (뇗; 뇗; 뇗; 뇗; 뇗; ) HANGUL SYLLABLE NOELB +B1D8;B1D8;1102 116C 11B3;B1D8;1102 116C 11B3; # (뇘; 뇘; 뇘; 뇘; 뇘; ) HANGUL SYLLABLE NOELS +B1D9;B1D9;1102 116C 11B4;B1D9;1102 116C 11B4; # (뇙; 뇙; 뇙; 뇙; 뇙; ) HANGUL SYLLABLE NOELT +B1DA;B1DA;1102 116C 11B5;B1DA;1102 116C 11B5; # (뇚; 뇚; 뇚; 뇚; 뇚; ) HANGUL SYLLABLE NOELP +B1DB;B1DB;1102 116C 11B6;B1DB;1102 116C 11B6; # (뇛; 뇛; 뇛; 뇛; 뇛; ) HANGUL SYLLABLE NOELH +B1DC;B1DC;1102 116C 11B7;B1DC;1102 116C 11B7; # (뇜; 뇜; 뇜; 뇜; 뇜; ) HANGUL SYLLABLE NOEM +B1DD;B1DD;1102 116C 11B8;B1DD;1102 116C 11B8; # (뇝; 뇝; 뇝; 뇝; 뇝; ) HANGUL SYLLABLE NOEB +B1DE;B1DE;1102 116C 11B9;B1DE;1102 116C 11B9; # (뇞; 뇞; 뇞; 뇞; 뇞; ) HANGUL SYLLABLE NOEBS +B1DF;B1DF;1102 116C 11BA;B1DF;1102 116C 11BA; # (뇟; 뇟; 뇟; 뇟; 뇟; ) HANGUL SYLLABLE NOES +B1E0;B1E0;1102 116C 11BB;B1E0;1102 116C 11BB; # (뇠; 뇠; 뇠; 뇠; 뇠; ) HANGUL SYLLABLE NOESS +B1E1;B1E1;1102 116C 11BC;B1E1;1102 116C 11BC; # (뇡; 뇡; 뇡; 뇡; 뇡; ) HANGUL SYLLABLE NOENG +B1E2;B1E2;1102 116C 11BD;B1E2;1102 116C 11BD; # (뇢; 뇢; 뇢; 뇢; 뇢; ) HANGUL SYLLABLE NOEJ +B1E3;B1E3;1102 116C 11BE;B1E3;1102 116C 11BE; # (뇣; 뇣; 뇣; 뇣; 뇣; ) HANGUL SYLLABLE NOEC +B1E4;B1E4;1102 116C 11BF;B1E4;1102 116C 11BF; # (뇤; 뇤; 뇤; 뇤; 뇤; ) HANGUL SYLLABLE NOEK +B1E5;B1E5;1102 116C 11C0;B1E5;1102 116C 11C0; # (뇥; 뇥; 뇥; 뇥; 뇥; ) HANGUL SYLLABLE NOET +B1E6;B1E6;1102 116C 11C1;B1E6;1102 116C 11C1; # (뇦; 뇦; 뇦; 뇦; 뇦; ) HANGUL SYLLABLE NOEP +B1E7;B1E7;1102 116C 11C2;B1E7;1102 116C 11C2; # (뇧; 뇧; 뇧; 뇧; 뇧; ) HANGUL SYLLABLE NOEH +B1E8;B1E8;1102 116D;B1E8;1102 116D; # (뇨; 뇨; 뇨; 뇨; 뇨; ) HANGUL SYLLABLE NYO +B1E9;B1E9;1102 116D 11A8;B1E9;1102 116D 11A8; # (뇩; 뇩; 뇩; 뇩; 뇩; ) HANGUL SYLLABLE NYOG +B1EA;B1EA;1102 116D 11A9;B1EA;1102 116D 11A9; # (뇪; 뇪; 뇪; 뇪; 뇪; ) HANGUL SYLLABLE NYOGG +B1EB;B1EB;1102 116D 11AA;B1EB;1102 116D 11AA; # (뇫; 뇫; 뇫; 뇫; 뇫; ) HANGUL SYLLABLE NYOGS +B1EC;B1EC;1102 116D 11AB;B1EC;1102 116D 11AB; # (뇬; 뇬; 뇬; 뇬; 뇬; ) HANGUL SYLLABLE NYON +B1ED;B1ED;1102 116D 11AC;B1ED;1102 116D 11AC; # (뇭; 뇭; 뇭; 뇭; 뇭; ) HANGUL SYLLABLE NYONJ +B1EE;B1EE;1102 116D 11AD;B1EE;1102 116D 11AD; # (뇮; 뇮; 뇮; 뇮; 뇮; ) HANGUL SYLLABLE NYONH +B1EF;B1EF;1102 116D 11AE;B1EF;1102 116D 11AE; # (뇯; 뇯; 뇯; 뇯; 뇯; ) HANGUL SYLLABLE NYOD +B1F0;B1F0;1102 116D 11AF;B1F0;1102 116D 11AF; # (뇰; 뇰; 뇰; 뇰; 뇰; ) HANGUL SYLLABLE NYOL +B1F1;B1F1;1102 116D 11B0;B1F1;1102 116D 11B0; # (뇱; 뇱; 뇱; 뇱; 뇱; ) HANGUL SYLLABLE NYOLG +B1F2;B1F2;1102 116D 11B1;B1F2;1102 116D 11B1; # (뇲; 뇲; 뇲; 뇲; 뇲; ) HANGUL SYLLABLE NYOLM +B1F3;B1F3;1102 116D 11B2;B1F3;1102 116D 11B2; # (뇳; 뇳; 뇳; 뇳; 뇳; ) HANGUL SYLLABLE NYOLB +B1F4;B1F4;1102 116D 11B3;B1F4;1102 116D 11B3; # (뇴; 뇴; 뇴; 뇴; 뇴; ) HANGUL SYLLABLE NYOLS +B1F5;B1F5;1102 116D 11B4;B1F5;1102 116D 11B4; # (뇵; 뇵; 뇵; 뇵; 뇵; ) HANGUL SYLLABLE NYOLT +B1F6;B1F6;1102 116D 11B5;B1F6;1102 116D 11B5; # (뇶; 뇶; 뇶; 뇶; 뇶; ) HANGUL SYLLABLE NYOLP +B1F7;B1F7;1102 116D 11B6;B1F7;1102 116D 11B6; # (뇷; 뇷; 뇷; 뇷; 뇷; ) HANGUL SYLLABLE NYOLH +B1F8;B1F8;1102 116D 11B7;B1F8;1102 116D 11B7; # (뇸; 뇸; 뇸; 뇸; 뇸; ) HANGUL SYLLABLE NYOM +B1F9;B1F9;1102 116D 11B8;B1F9;1102 116D 11B8; # (뇹; 뇹; 뇹; 뇹; 뇹; ) HANGUL SYLLABLE NYOB +B1FA;B1FA;1102 116D 11B9;B1FA;1102 116D 11B9; # (뇺; 뇺; 뇺; 뇺; 뇺; ) HANGUL SYLLABLE NYOBS +B1FB;B1FB;1102 116D 11BA;B1FB;1102 116D 11BA; # (뇻; 뇻; 뇻; 뇻; 뇻; ) HANGUL SYLLABLE NYOS +B1FC;B1FC;1102 116D 11BB;B1FC;1102 116D 11BB; # (뇼; 뇼; 뇼; 뇼; 뇼; ) HANGUL SYLLABLE NYOSS +B1FD;B1FD;1102 116D 11BC;B1FD;1102 116D 11BC; # (뇽; 뇽; 뇽; 뇽; 뇽; ) HANGUL SYLLABLE NYONG +B1FE;B1FE;1102 116D 11BD;B1FE;1102 116D 11BD; # (뇾; 뇾; 뇾; 뇾; 뇾; ) HANGUL SYLLABLE NYOJ +B1FF;B1FF;1102 116D 11BE;B1FF;1102 116D 11BE; # (뇿; 뇿; 뇿; 뇿; 뇿; ) HANGUL SYLLABLE NYOC +B200;B200;1102 116D 11BF;B200;1102 116D 11BF; # (눀; 눀; 눀; 눀; 눀; ) HANGUL SYLLABLE NYOK +B201;B201;1102 116D 11C0;B201;1102 116D 11C0; # (눁; 눁; 눁; 눁; 눁; ) HANGUL SYLLABLE NYOT +B202;B202;1102 116D 11C1;B202;1102 116D 11C1; # (눂; 눂; 눂; 눂; 눂; ) HANGUL SYLLABLE NYOP +B203;B203;1102 116D 11C2;B203;1102 116D 11C2; # (눃; 눃; 눃; 눃; 눃; ) HANGUL SYLLABLE NYOH +B204;B204;1102 116E;B204;1102 116E; # (누; 누; 누; 누; 누; ) HANGUL SYLLABLE NU +B205;B205;1102 116E 11A8;B205;1102 116E 11A8; # (눅; 눅; 눅; 눅; 눅; ) HANGUL SYLLABLE NUG +B206;B206;1102 116E 11A9;B206;1102 116E 11A9; # (눆; 눆; 눆; 눆; 눆; ) HANGUL SYLLABLE NUGG +B207;B207;1102 116E 11AA;B207;1102 116E 11AA; # (눇; 눇; 눇; 눇; 눇; ) HANGUL SYLLABLE NUGS +B208;B208;1102 116E 11AB;B208;1102 116E 11AB; # (눈; 눈; 눈; 눈; 눈; ) HANGUL SYLLABLE NUN +B209;B209;1102 116E 11AC;B209;1102 116E 11AC; # (눉; 눉; 눉; 눉; 눉; ) HANGUL SYLLABLE NUNJ +B20A;B20A;1102 116E 11AD;B20A;1102 116E 11AD; # (눊; 눊; 눊; 눊; 눊; ) HANGUL SYLLABLE NUNH +B20B;B20B;1102 116E 11AE;B20B;1102 116E 11AE; # (눋; 눋; 눋; 눋; 눋; ) HANGUL SYLLABLE NUD +B20C;B20C;1102 116E 11AF;B20C;1102 116E 11AF; # (눌; 눌; 눌; 눌; 눌; ) HANGUL SYLLABLE NUL +B20D;B20D;1102 116E 11B0;B20D;1102 116E 11B0; # (눍; 눍; 눍; 눍; 눍; ) HANGUL SYLLABLE NULG +B20E;B20E;1102 116E 11B1;B20E;1102 116E 11B1; # (눎; 눎; 눎; 눎; 눎; ) HANGUL SYLLABLE NULM +B20F;B20F;1102 116E 11B2;B20F;1102 116E 11B2; # (눏; 눏; 눏; 눏; 눏; ) HANGUL SYLLABLE NULB +B210;B210;1102 116E 11B3;B210;1102 116E 11B3; # (눐; 눐; 눐; 눐; 눐; ) HANGUL SYLLABLE NULS +B211;B211;1102 116E 11B4;B211;1102 116E 11B4; # (눑; 눑; 눑; 눑; 눑; ) HANGUL SYLLABLE NULT +B212;B212;1102 116E 11B5;B212;1102 116E 11B5; # (눒; 눒; 눒; 눒; 눒; ) HANGUL SYLLABLE NULP +B213;B213;1102 116E 11B6;B213;1102 116E 11B6; # (눓; 눓; 눓; 눓; 눓; ) HANGUL SYLLABLE NULH +B214;B214;1102 116E 11B7;B214;1102 116E 11B7; # (눔; 눔; 눔; 눔; 눔; ) HANGUL SYLLABLE NUM +B215;B215;1102 116E 11B8;B215;1102 116E 11B8; # (눕; 눕; 눕; 눕; 눕; ) HANGUL SYLLABLE NUB +B216;B216;1102 116E 11B9;B216;1102 116E 11B9; # (눖; 눖; 눖; 눖; 눖; ) HANGUL SYLLABLE NUBS +B217;B217;1102 116E 11BA;B217;1102 116E 11BA; # (눗; 눗; 눗; 눗; 눗; ) HANGUL SYLLABLE NUS +B218;B218;1102 116E 11BB;B218;1102 116E 11BB; # (눘; 눘; 눘; 눘; 눘; ) HANGUL SYLLABLE NUSS +B219;B219;1102 116E 11BC;B219;1102 116E 11BC; # (눙; 눙; 눙; 눙; 눙; ) HANGUL SYLLABLE NUNG +B21A;B21A;1102 116E 11BD;B21A;1102 116E 11BD; # (눚; 눚; 눚; 눚; 눚; ) HANGUL SYLLABLE NUJ +B21B;B21B;1102 116E 11BE;B21B;1102 116E 11BE; # (눛; 눛; 눛; 눛; 눛; ) HANGUL SYLLABLE NUC +B21C;B21C;1102 116E 11BF;B21C;1102 116E 11BF; # (눜; 눜; 눜; 눜; 눜; ) HANGUL SYLLABLE NUK +B21D;B21D;1102 116E 11C0;B21D;1102 116E 11C0; # (눝; 눝; 눝; 눝; 눝; ) HANGUL SYLLABLE NUT +B21E;B21E;1102 116E 11C1;B21E;1102 116E 11C1; # (눞; 눞; 눞; 눞; 눞; ) HANGUL SYLLABLE NUP +B21F;B21F;1102 116E 11C2;B21F;1102 116E 11C2; # (눟; 눟; 눟; 눟; 눟; ) HANGUL SYLLABLE NUH +B220;B220;1102 116F;B220;1102 116F; # (눠; 눠; 눠; 눠; 눠; ) HANGUL SYLLABLE NWEO +B221;B221;1102 116F 11A8;B221;1102 116F 11A8; # (눡; 눡; 눡; 눡; 눡; ) HANGUL SYLLABLE NWEOG +B222;B222;1102 116F 11A9;B222;1102 116F 11A9; # (눢; 눢; 눢; 눢; 눢; ) HANGUL SYLLABLE NWEOGG +B223;B223;1102 116F 11AA;B223;1102 116F 11AA; # (눣; 눣; 눣; 눣; 눣; ) HANGUL SYLLABLE NWEOGS +B224;B224;1102 116F 11AB;B224;1102 116F 11AB; # (눤; 눤; 눤; 눤; 눤; ) HANGUL SYLLABLE NWEON +B225;B225;1102 116F 11AC;B225;1102 116F 11AC; # (눥; 눥; 눥; 눥; 눥; ) HANGUL SYLLABLE NWEONJ +B226;B226;1102 116F 11AD;B226;1102 116F 11AD; # (눦; 눦; 눦; 눦; 눦; ) HANGUL SYLLABLE NWEONH +B227;B227;1102 116F 11AE;B227;1102 116F 11AE; # (눧; 눧; 눧; 눧; 눧; ) HANGUL SYLLABLE NWEOD +B228;B228;1102 116F 11AF;B228;1102 116F 11AF; # (눨; 눨; 눨; 눨; 눨; ) HANGUL SYLLABLE NWEOL +B229;B229;1102 116F 11B0;B229;1102 116F 11B0; # (눩; 눩; 눩; 눩; 눩; ) HANGUL SYLLABLE NWEOLG +B22A;B22A;1102 116F 11B1;B22A;1102 116F 11B1; # (눪; 눪; 눪; 눪; 눪; ) HANGUL SYLLABLE NWEOLM +B22B;B22B;1102 116F 11B2;B22B;1102 116F 11B2; # (눫; 눫; 눫; 눫; 눫; ) HANGUL SYLLABLE NWEOLB +B22C;B22C;1102 116F 11B3;B22C;1102 116F 11B3; # (눬; 눬; 눬; 눬; 눬; ) HANGUL SYLLABLE NWEOLS +B22D;B22D;1102 116F 11B4;B22D;1102 116F 11B4; # (눭; 눭; 눭; 눭; 눭; ) HANGUL SYLLABLE NWEOLT +B22E;B22E;1102 116F 11B5;B22E;1102 116F 11B5; # (눮; 눮; 눮; 눮; 눮; ) HANGUL SYLLABLE NWEOLP +B22F;B22F;1102 116F 11B6;B22F;1102 116F 11B6; # (눯; 눯; 눯; 눯; 눯; ) HANGUL SYLLABLE NWEOLH +B230;B230;1102 116F 11B7;B230;1102 116F 11B7; # (눰; 눰; 눰; 눰; 눰; ) HANGUL SYLLABLE NWEOM +B231;B231;1102 116F 11B8;B231;1102 116F 11B8; # (눱; 눱; 눱; 눱; 눱; ) HANGUL SYLLABLE NWEOB +B232;B232;1102 116F 11B9;B232;1102 116F 11B9; # (눲; 눲; 눲; 눲; 눲; ) HANGUL SYLLABLE NWEOBS +B233;B233;1102 116F 11BA;B233;1102 116F 11BA; # (눳; 눳; 눳; 눳; 눳; ) HANGUL SYLLABLE NWEOS +B234;B234;1102 116F 11BB;B234;1102 116F 11BB; # (눴; 눴; 눴; 눴; 눴; ) HANGUL SYLLABLE NWEOSS +B235;B235;1102 116F 11BC;B235;1102 116F 11BC; # (눵; 눵; 눵; 눵; 눵; ) HANGUL SYLLABLE NWEONG +B236;B236;1102 116F 11BD;B236;1102 116F 11BD; # (눶; 눶; 눶; 눶; 눶; ) HANGUL SYLLABLE NWEOJ +B237;B237;1102 116F 11BE;B237;1102 116F 11BE; # (눷; 눷; 눷; 눷; 눷; ) HANGUL SYLLABLE NWEOC +B238;B238;1102 116F 11BF;B238;1102 116F 11BF; # (눸; 눸; 눸; 눸; 눸; ) HANGUL SYLLABLE NWEOK +B239;B239;1102 116F 11C0;B239;1102 116F 11C0; # (눹; 눹; 눹; 눹; 눹; ) HANGUL SYLLABLE NWEOT +B23A;B23A;1102 116F 11C1;B23A;1102 116F 11C1; # (눺; 눺; 눺; 눺; 눺; ) HANGUL SYLLABLE NWEOP +B23B;B23B;1102 116F 11C2;B23B;1102 116F 11C2; # (눻; 눻; 눻; 눻; 눻; ) HANGUL SYLLABLE NWEOH +B23C;B23C;1102 1170;B23C;1102 1170; # (눼; 눼; 눼; 눼; 눼; ) HANGUL SYLLABLE NWE +B23D;B23D;1102 1170 11A8;B23D;1102 1170 11A8; # (눽; 눽; 눽; 눽; 눽; ) HANGUL SYLLABLE NWEG +B23E;B23E;1102 1170 11A9;B23E;1102 1170 11A9; # (눾; 눾; 눾; 눾; 눾; ) HANGUL SYLLABLE NWEGG +B23F;B23F;1102 1170 11AA;B23F;1102 1170 11AA; # (눿; 눿; 눿; 눿; 눿; ) HANGUL SYLLABLE NWEGS +B240;B240;1102 1170 11AB;B240;1102 1170 11AB; # (뉀; 뉀; 뉀; 뉀; 뉀; ) HANGUL SYLLABLE NWEN +B241;B241;1102 1170 11AC;B241;1102 1170 11AC; # (뉁; 뉁; 뉁; 뉁; 뉁; ) HANGUL SYLLABLE NWENJ +B242;B242;1102 1170 11AD;B242;1102 1170 11AD; # (뉂; 뉂; 뉂; 뉂; 뉂; ) HANGUL SYLLABLE NWENH +B243;B243;1102 1170 11AE;B243;1102 1170 11AE; # (뉃; 뉃; 뉃; 뉃; 뉃; ) HANGUL SYLLABLE NWED +B244;B244;1102 1170 11AF;B244;1102 1170 11AF; # (뉄; 뉄; 뉄; 뉄; 뉄; ) HANGUL SYLLABLE NWEL +B245;B245;1102 1170 11B0;B245;1102 1170 11B0; # (뉅; 뉅; 뉅; 뉅; 뉅; ) HANGUL SYLLABLE NWELG +B246;B246;1102 1170 11B1;B246;1102 1170 11B1; # (뉆; 뉆; 뉆; 뉆; 뉆; ) HANGUL SYLLABLE NWELM +B247;B247;1102 1170 11B2;B247;1102 1170 11B2; # (뉇; 뉇; 뉇; 뉇; 뉇; ) HANGUL SYLLABLE NWELB +B248;B248;1102 1170 11B3;B248;1102 1170 11B3; # (뉈; 뉈; 뉈; 뉈; 뉈; ) HANGUL SYLLABLE NWELS +B249;B249;1102 1170 11B4;B249;1102 1170 11B4; # (뉉; 뉉; 뉉; 뉉; 뉉; ) HANGUL SYLLABLE NWELT +B24A;B24A;1102 1170 11B5;B24A;1102 1170 11B5; # (뉊; 뉊; 뉊; 뉊; 뉊; ) HANGUL SYLLABLE NWELP +B24B;B24B;1102 1170 11B6;B24B;1102 1170 11B6; # (뉋; 뉋; 뉋; 뉋; 뉋; ) HANGUL SYLLABLE NWELH +B24C;B24C;1102 1170 11B7;B24C;1102 1170 11B7; # (뉌; 뉌; 뉌; 뉌; 뉌; ) HANGUL SYLLABLE NWEM +B24D;B24D;1102 1170 11B8;B24D;1102 1170 11B8; # (뉍; 뉍; 뉍; 뉍; 뉍; ) HANGUL SYLLABLE NWEB +B24E;B24E;1102 1170 11B9;B24E;1102 1170 11B9; # (뉎; 뉎; 뉎; 뉎; 뉎; ) HANGUL SYLLABLE NWEBS +B24F;B24F;1102 1170 11BA;B24F;1102 1170 11BA; # (뉏; 뉏; 뉏; 뉏; 뉏; ) HANGUL SYLLABLE NWES +B250;B250;1102 1170 11BB;B250;1102 1170 11BB; # (뉐; 뉐; 뉐; 뉐; 뉐; ) HANGUL SYLLABLE NWESS +B251;B251;1102 1170 11BC;B251;1102 1170 11BC; # (뉑; 뉑; 뉑; 뉑; 뉑; ) HANGUL SYLLABLE NWENG +B252;B252;1102 1170 11BD;B252;1102 1170 11BD; # (뉒; 뉒; 뉒; 뉒; 뉒; ) HANGUL SYLLABLE NWEJ +B253;B253;1102 1170 11BE;B253;1102 1170 11BE; # (뉓; 뉓; 뉓; 뉓; 뉓; ) HANGUL SYLLABLE NWEC +B254;B254;1102 1170 11BF;B254;1102 1170 11BF; # (뉔; 뉔; 뉔; 뉔; 뉔; ) HANGUL SYLLABLE NWEK +B255;B255;1102 1170 11C0;B255;1102 1170 11C0; # (뉕; 뉕; 뉕; 뉕; 뉕; ) HANGUL SYLLABLE NWET +B256;B256;1102 1170 11C1;B256;1102 1170 11C1; # (뉖; 뉖; 뉖; 뉖; 뉖; ) HANGUL SYLLABLE NWEP +B257;B257;1102 1170 11C2;B257;1102 1170 11C2; # (뉗; 뉗; 뉗; 뉗; 뉗; ) HANGUL SYLLABLE NWEH +B258;B258;1102 1171;B258;1102 1171; # (뉘; 뉘; 뉘; 뉘; 뉘; ) HANGUL SYLLABLE NWI +B259;B259;1102 1171 11A8;B259;1102 1171 11A8; # (뉙; 뉙; 뉙; 뉙; 뉙; ) HANGUL SYLLABLE NWIG +B25A;B25A;1102 1171 11A9;B25A;1102 1171 11A9; # (뉚; 뉚; 뉚; 뉚; 뉚; ) HANGUL SYLLABLE NWIGG +B25B;B25B;1102 1171 11AA;B25B;1102 1171 11AA; # (뉛; 뉛; 뉛; 뉛; 뉛; ) HANGUL SYLLABLE NWIGS +B25C;B25C;1102 1171 11AB;B25C;1102 1171 11AB; # (뉜; 뉜; 뉜; 뉜; 뉜; ) HANGUL SYLLABLE NWIN +B25D;B25D;1102 1171 11AC;B25D;1102 1171 11AC; # (뉝; 뉝; 뉝; 뉝; 뉝; ) HANGUL SYLLABLE NWINJ +B25E;B25E;1102 1171 11AD;B25E;1102 1171 11AD; # (뉞; 뉞; 뉞; 뉞; 뉞; ) HANGUL SYLLABLE NWINH +B25F;B25F;1102 1171 11AE;B25F;1102 1171 11AE; # (뉟; 뉟; 뉟; 뉟; 뉟; ) HANGUL SYLLABLE NWID +B260;B260;1102 1171 11AF;B260;1102 1171 11AF; # (뉠; 뉠; 뉠; 뉠; 뉠; ) HANGUL SYLLABLE NWIL +B261;B261;1102 1171 11B0;B261;1102 1171 11B0; # (뉡; 뉡; 뉡; 뉡; 뉡; ) HANGUL SYLLABLE NWILG +B262;B262;1102 1171 11B1;B262;1102 1171 11B1; # (뉢; 뉢; 뉢; 뉢; 뉢; ) HANGUL SYLLABLE NWILM +B263;B263;1102 1171 11B2;B263;1102 1171 11B2; # (뉣; 뉣; 뉣; 뉣; 뉣; ) HANGUL SYLLABLE NWILB +B264;B264;1102 1171 11B3;B264;1102 1171 11B3; # (뉤; 뉤; 뉤; 뉤; 뉤; ) HANGUL SYLLABLE NWILS +B265;B265;1102 1171 11B4;B265;1102 1171 11B4; # (뉥; 뉥; 뉥; 뉥; 뉥; ) HANGUL SYLLABLE NWILT +B266;B266;1102 1171 11B5;B266;1102 1171 11B5; # (뉦; 뉦; 뉦; 뉦; 뉦; ) HANGUL SYLLABLE NWILP +B267;B267;1102 1171 11B6;B267;1102 1171 11B6; # (뉧; 뉧; 뉧; 뉧; 뉧; ) HANGUL SYLLABLE NWILH +B268;B268;1102 1171 11B7;B268;1102 1171 11B7; # (뉨; 뉨; 뉨; 뉨; 뉨; ) HANGUL SYLLABLE NWIM +B269;B269;1102 1171 11B8;B269;1102 1171 11B8; # (뉩; 뉩; 뉩; 뉩; 뉩; ) HANGUL SYLLABLE NWIB +B26A;B26A;1102 1171 11B9;B26A;1102 1171 11B9; # (뉪; 뉪; 뉪; 뉪; 뉪; ) HANGUL SYLLABLE NWIBS +B26B;B26B;1102 1171 11BA;B26B;1102 1171 11BA; # (뉫; 뉫; 뉫; 뉫; 뉫; ) HANGUL SYLLABLE NWIS +B26C;B26C;1102 1171 11BB;B26C;1102 1171 11BB; # (뉬; 뉬; 뉬; 뉬; 뉬; ) HANGUL SYLLABLE NWISS +B26D;B26D;1102 1171 11BC;B26D;1102 1171 11BC; # (뉭; 뉭; 뉭; 뉭; 뉭; ) HANGUL SYLLABLE NWING +B26E;B26E;1102 1171 11BD;B26E;1102 1171 11BD; # (뉮; 뉮; 뉮; 뉮; 뉮; ) HANGUL SYLLABLE NWIJ +B26F;B26F;1102 1171 11BE;B26F;1102 1171 11BE; # (뉯; 뉯; 뉯; 뉯; 뉯; ) HANGUL SYLLABLE NWIC +B270;B270;1102 1171 11BF;B270;1102 1171 11BF; # (뉰; 뉰; 뉰; 뉰; 뉰; ) HANGUL SYLLABLE NWIK +B271;B271;1102 1171 11C0;B271;1102 1171 11C0; # (뉱; 뉱; 뉱; 뉱; 뉱; ) HANGUL SYLLABLE NWIT +B272;B272;1102 1171 11C1;B272;1102 1171 11C1; # (뉲; 뉲; 뉲; 뉲; 뉲; ) HANGUL SYLLABLE NWIP +B273;B273;1102 1171 11C2;B273;1102 1171 11C2; # (뉳; 뉳; 뉳; 뉳; 뉳; ) HANGUL SYLLABLE NWIH +B274;B274;1102 1172;B274;1102 1172; # (뉴; 뉴; 뉴; 뉴; 뉴; ) HANGUL SYLLABLE NYU +B275;B275;1102 1172 11A8;B275;1102 1172 11A8; # (뉵; 뉵; 뉵; 뉵; 뉵; ) HANGUL SYLLABLE NYUG +B276;B276;1102 1172 11A9;B276;1102 1172 11A9; # (뉶; 뉶; 뉶; 뉶; 뉶; ) HANGUL SYLLABLE NYUGG +B277;B277;1102 1172 11AA;B277;1102 1172 11AA; # (뉷; 뉷; 뉷; 뉷; 뉷; ) HANGUL SYLLABLE NYUGS +B278;B278;1102 1172 11AB;B278;1102 1172 11AB; # (뉸; 뉸; 뉸; 뉸; 뉸; ) HANGUL SYLLABLE NYUN +B279;B279;1102 1172 11AC;B279;1102 1172 11AC; # (뉹; 뉹; 뉹; 뉹; 뉹; ) HANGUL SYLLABLE NYUNJ +B27A;B27A;1102 1172 11AD;B27A;1102 1172 11AD; # (뉺; 뉺; 뉺; 뉺; 뉺; ) HANGUL SYLLABLE NYUNH +B27B;B27B;1102 1172 11AE;B27B;1102 1172 11AE; # (뉻; 뉻; 뉻; 뉻; 뉻; ) HANGUL SYLLABLE NYUD +B27C;B27C;1102 1172 11AF;B27C;1102 1172 11AF; # (뉼; 뉼; 뉼; 뉼; 뉼; ) HANGUL SYLLABLE NYUL +B27D;B27D;1102 1172 11B0;B27D;1102 1172 11B0; # (뉽; 뉽; 뉽; 뉽; 뉽; ) HANGUL SYLLABLE NYULG +B27E;B27E;1102 1172 11B1;B27E;1102 1172 11B1; # (뉾; 뉾; 뉾; 뉾; 뉾; ) HANGUL SYLLABLE NYULM +B27F;B27F;1102 1172 11B2;B27F;1102 1172 11B2; # (뉿; 뉿; 뉿; 뉿; 뉿; ) HANGUL SYLLABLE NYULB +B280;B280;1102 1172 11B3;B280;1102 1172 11B3; # (늀; 늀; 늀; 늀; 늀; ) HANGUL SYLLABLE NYULS +B281;B281;1102 1172 11B4;B281;1102 1172 11B4; # (늁; 늁; 늁; 늁; 늁; ) HANGUL SYLLABLE NYULT +B282;B282;1102 1172 11B5;B282;1102 1172 11B5; # (늂; 늂; 늂; 늂; 늂; ) HANGUL SYLLABLE NYULP +B283;B283;1102 1172 11B6;B283;1102 1172 11B6; # (늃; 늃; 늃; 늃; 늃; ) HANGUL SYLLABLE NYULH +B284;B284;1102 1172 11B7;B284;1102 1172 11B7; # (늄; 늄; 늄; 늄; 늄; ) HANGUL SYLLABLE NYUM +B285;B285;1102 1172 11B8;B285;1102 1172 11B8; # (늅; 늅; 늅; 늅; 늅; ) HANGUL SYLLABLE NYUB +B286;B286;1102 1172 11B9;B286;1102 1172 11B9; # (늆; 늆; 늆; 늆; 늆; ) HANGUL SYLLABLE NYUBS +B287;B287;1102 1172 11BA;B287;1102 1172 11BA; # (늇; 늇; 늇; 늇; 늇; ) HANGUL SYLLABLE NYUS +B288;B288;1102 1172 11BB;B288;1102 1172 11BB; # (늈; 늈; 늈; 늈; 늈; ) HANGUL SYLLABLE NYUSS +B289;B289;1102 1172 11BC;B289;1102 1172 11BC; # (늉; 늉; 늉; 늉; 늉; ) HANGUL SYLLABLE NYUNG +B28A;B28A;1102 1172 11BD;B28A;1102 1172 11BD; # (늊; 늊; 늊; 늊; 늊; ) HANGUL SYLLABLE NYUJ +B28B;B28B;1102 1172 11BE;B28B;1102 1172 11BE; # (늋; 늋; 늋; 늋; 늋; ) HANGUL SYLLABLE NYUC +B28C;B28C;1102 1172 11BF;B28C;1102 1172 11BF; # (늌; 늌; 늌; 늌; 늌; ) HANGUL SYLLABLE NYUK +B28D;B28D;1102 1172 11C0;B28D;1102 1172 11C0; # (늍; 늍; 늍; 늍; 늍; ) HANGUL SYLLABLE NYUT +B28E;B28E;1102 1172 11C1;B28E;1102 1172 11C1; # (늎; 늎; 늎; 늎; 늎; ) HANGUL SYLLABLE NYUP +B28F;B28F;1102 1172 11C2;B28F;1102 1172 11C2; # (늏; 늏; 늏; 늏; 늏; ) HANGUL SYLLABLE NYUH +B290;B290;1102 1173;B290;1102 1173; # (느; 느; 느; 느; 느; ) HANGUL SYLLABLE NEU +B291;B291;1102 1173 11A8;B291;1102 1173 11A8; # (늑; 늑; 늑; 늑; 늑; ) HANGUL SYLLABLE NEUG +B292;B292;1102 1173 11A9;B292;1102 1173 11A9; # (늒; 늒; 늒; 늒; 늒; ) HANGUL SYLLABLE NEUGG +B293;B293;1102 1173 11AA;B293;1102 1173 11AA; # (늓; 늓; 늓; 늓; 늓; ) HANGUL SYLLABLE NEUGS +B294;B294;1102 1173 11AB;B294;1102 1173 11AB; # (는; 는; 는; 는; 는; ) HANGUL SYLLABLE NEUN +B295;B295;1102 1173 11AC;B295;1102 1173 11AC; # (늕; 늕; 늕; 늕; 늕; ) HANGUL SYLLABLE NEUNJ +B296;B296;1102 1173 11AD;B296;1102 1173 11AD; # (늖; 늖; 늖; 늖; 늖; ) HANGUL SYLLABLE NEUNH +B297;B297;1102 1173 11AE;B297;1102 1173 11AE; # (늗; 늗; 늗; 늗; 늗; ) HANGUL SYLLABLE NEUD +B298;B298;1102 1173 11AF;B298;1102 1173 11AF; # (늘; 늘; 늘; 늘; 늘; ) HANGUL SYLLABLE NEUL +B299;B299;1102 1173 11B0;B299;1102 1173 11B0; # (늙; 늙; 늙; 늙; 늙; ) HANGUL SYLLABLE NEULG +B29A;B29A;1102 1173 11B1;B29A;1102 1173 11B1; # (늚; 늚; 늚; 늚; 늚; ) HANGUL SYLLABLE NEULM +B29B;B29B;1102 1173 11B2;B29B;1102 1173 11B2; # (늛; 늛; 늛; 늛; 늛; ) HANGUL SYLLABLE NEULB +B29C;B29C;1102 1173 11B3;B29C;1102 1173 11B3; # (늜; 늜; 늜; 늜; 늜; ) HANGUL SYLLABLE NEULS +B29D;B29D;1102 1173 11B4;B29D;1102 1173 11B4; # (늝; 늝; 늝; 늝; 늝; ) HANGUL SYLLABLE NEULT +B29E;B29E;1102 1173 11B5;B29E;1102 1173 11B5; # (늞; 늞; 늞; 늞; 늞; ) HANGUL SYLLABLE NEULP +B29F;B29F;1102 1173 11B6;B29F;1102 1173 11B6; # (늟; 늟; 늟; 늟; 늟; ) HANGUL SYLLABLE NEULH +B2A0;B2A0;1102 1173 11B7;B2A0;1102 1173 11B7; # (늠; 늠; 늠; 늠; 늠; ) HANGUL SYLLABLE NEUM +B2A1;B2A1;1102 1173 11B8;B2A1;1102 1173 11B8; # (늡; 늡; 늡; 늡; 늡; ) HANGUL SYLLABLE NEUB +B2A2;B2A2;1102 1173 11B9;B2A2;1102 1173 11B9; # (늢; 늢; 늢; 늢; 늢; ) HANGUL SYLLABLE NEUBS +B2A3;B2A3;1102 1173 11BA;B2A3;1102 1173 11BA; # (늣; 늣; 늣; 늣; 늣; ) HANGUL SYLLABLE NEUS +B2A4;B2A4;1102 1173 11BB;B2A4;1102 1173 11BB; # (늤; 늤; 늤; 늤; 늤; ) HANGUL SYLLABLE NEUSS +B2A5;B2A5;1102 1173 11BC;B2A5;1102 1173 11BC; # (능; 능; 능; 능; 능; ) HANGUL SYLLABLE NEUNG +B2A6;B2A6;1102 1173 11BD;B2A6;1102 1173 11BD; # (늦; 늦; 늦; 늦; 늦; ) HANGUL SYLLABLE NEUJ +B2A7;B2A7;1102 1173 11BE;B2A7;1102 1173 11BE; # (늧; 늧; 늧; 늧; 늧; ) HANGUL SYLLABLE NEUC +B2A8;B2A8;1102 1173 11BF;B2A8;1102 1173 11BF; # (늨; 늨; 늨; 늨; 늨; ) HANGUL SYLLABLE NEUK +B2A9;B2A9;1102 1173 11C0;B2A9;1102 1173 11C0; # (늩; 늩; 늩; 늩; 늩; ) HANGUL SYLLABLE NEUT +B2AA;B2AA;1102 1173 11C1;B2AA;1102 1173 11C1; # (늪; 늪; 늪; 늪; 늪; ) HANGUL SYLLABLE NEUP +B2AB;B2AB;1102 1173 11C2;B2AB;1102 1173 11C2; # (늫; 늫; 늫; 늫; 늫; ) HANGUL SYLLABLE NEUH +B2AC;B2AC;1102 1174;B2AC;1102 1174; # (늬; 늬; 늬; 늬; 늬; ) HANGUL SYLLABLE NYI +B2AD;B2AD;1102 1174 11A8;B2AD;1102 1174 11A8; # (늭; 늭; 늭; 늭; 늭; ) HANGUL SYLLABLE NYIG +B2AE;B2AE;1102 1174 11A9;B2AE;1102 1174 11A9; # (늮; 늮; 늮; 늮; 늮; ) HANGUL SYLLABLE NYIGG +B2AF;B2AF;1102 1174 11AA;B2AF;1102 1174 11AA; # (늯; 늯; 늯; 늯; 늯; ) HANGUL SYLLABLE NYIGS +B2B0;B2B0;1102 1174 11AB;B2B0;1102 1174 11AB; # (늰; 늰; 늰; 늰; 늰; ) HANGUL SYLLABLE NYIN +B2B1;B2B1;1102 1174 11AC;B2B1;1102 1174 11AC; # (늱; 늱; 늱; 늱; 늱; ) HANGUL SYLLABLE NYINJ +B2B2;B2B2;1102 1174 11AD;B2B2;1102 1174 11AD; # (늲; 늲; 늲; 늲; 늲; ) HANGUL SYLLABLE NYINH +B2B3;B2B3;1102 1174 11AE;B2B3;1102 1174 11AE; # (늳; 늳; 늳; 늳; 늳; ) HANGUL SYLLABLE NYID +B2B4;B2B4;1102 1174 11AF;B2B4;1102 1174 11AF; # (늴; 늴; 늴; 늴; 늴; ) HANGUL SYLLABLE NYIL +B2B5;B2B5;1102 1174 11B0;B2B5;1102 1174 11B0; # (늵; 늵; 늵; 늵; 늵; ) HANGUL SYLLABLE NYILG +B2B6;B2B6;1102 1174 11B1;B2B6;1102 1174 11B1; # (늶; 늶; 늶; 늶; 늶; ) HANGUL SYLLABLE NYILM +B2B7;B2B7;1102 1174 11B2;B2B7;1102 1174 11B2; # (늷; 늷; 늷; 늷; 늷; ) HANGUL SYLLABLE NYILB +B2B8;B2B8;1102 1174 11B3;B2B8;1102 1174 11B3; # (늸; 늸; 늸; 늸; 늸; ) HANGUL SYLLABLE NYILS +B2B9;B2B9;1102 1174 11B4;B2B9;1102 1174 11B4; # (늹; 늹; 늹; 늹; 늹; ) HANGUL SYLLABLE NYILT +B2BA;B2BA;1102 1174 11B5;B2BA;1102 1174 11B5; # (늺; 늺; 늺; 늺; 늺; ) HANGUL SYLLABLE NYILP +B2BB;B2BB;1102 1174 11B6;B2BB;1102 1174 11B6; # (늻; 늻; 늻; 늻; 늻; ) HANGUL SYLLABLE NYILH +B2BC;B2BC;1102 1174 11B7;B2BC;1102 1174 11B7; # (늼; 늼; 늼; 늼; 늼; ) HANGUL SYLLABLE NYIM +B2BD;B2BD;1102 1174 11B8;B2BD;1102 1174 11B8; # (늽; 늽; 늽; 늽; 늽; ) HANGUL SYLLABLE NYIB +B2BE;B2BE;1102 1174 11B9;B2BE;1102 1174 11B9; # (늾; 늾; 늾; 늾; 늾; ) HANGUL SYLLABLE NYIBS +B2BF;B2BF;1102 1174 11BA;B2BF;1102 1174 11BA; # (늿; 늿; 늿; 늿; 늿; ) HANGUL SYLLABLE NYIS +B2C0;B2C0;1102 1174 11BB;B2C0;1102 1174 11BB; # (닀; 닀; 닀; 닀; 닀; ) HANGUL SYLLABLE NYISS +B2C1;B2C1;1102 1174 11BC;B2C1;1102 1174 11BC; # (닁; 닁; 닁; 닁; 닁; ) HANGUL SYLLABLE NYING +B2C2;B2C2;1102 1174 11BD;B2C2;1102 1174 11BD; # (닂; 닂; 닂; 닂; 닂; ) HANGUL SYLLABLE NYIJ +B2C3;B2C3;1102 1174 11BE;B2C3;1102 1174 11BE; # (닃; 닃; 닃; 닃; 닃; ) HANGUL SYLLABLE NYIC +B2C4;B2C4;1102 1174 11BF;B2C4;1102 1174 11BF; # (닄; 닄; 닄; 닄; 닄; ) HANGUL SYLLABLE NYIK +B2C5;B2C5;1102 1174 11C0;B2C5;1102 1174 11C0; # (닅; 닅; 닅; 닅; 닅; ) HANGUL SYLLABLE NYIT +B2C6;B2C6;1102 1174 11C1;B2C6;1102 1174 11C1; # (닆; 닆; 닆; 닆; 닆; ) HANGUL SYLLABLE NYIP +B2C7;B2C7;1102 1174 11C2;B2C7;1102 1174 11C2; # (닇; 닇; 닇; 닇; 닇; ) HANGUL SYLLABLE NYIH +B2C8;B2C8;1102 1175;B2C8;1102 1175; # (니; 니; 니; 니; 니; ) HANGUL SYLLABLE NI +B2C9;B2C9;1102 1175 11A8;B2C9;1102 1175 11A8; # (닉; 닉; 닉; 닉; 닉; ) HANGUL SYLLABLE NIG +B2CA;B2CA;1102 1175 11A9;B2CA;1102 1175 11A9; # (닊; 닊; 닊; 닊; 닊; ) HANGUL SYLLABLE NIGG +B2CB;B2CB;1102 1175 11AA;B2CB;1102 1175 11AA; # (닋; 닋; 닋; 닋; 닋; ) HANGUL SYLLABLE NIGS +B2CC;B2CC;1102 1175 11AB;B2CC;1102 1175 11AB; # (닌; 닌; 닌; 닌; 닌; ) HANGUL SYLLABLE NIN +B2CD;B2CD;1102 1175 11AC;B2CD;1102 1175 11AC; # (닍; 닍; 닍; 닍; 닍; ) HANGUL SYLLABLE NINJ +B2CE;B2CE;1102 1175 11AD;B2CE;1102 1175 11AD; # (닎; 닎; 닎; 닎; 닎; ) HANGUL SYLLABLE NINH +B2CF;B2CF;1102 1175 11AE;B2CF;1102 1175 11AE; # (닏; 닏; 닏; 닏; 닏; ) HANGUL SYLLABLE NID +B2D0;B2D0;1102 1175 11AF;B2D0;1102 1175 11AF; # (닐; 닐; 닐; 닐; 닐; ) HANGUL SYLLABLE NIL +B2D1;B2D1;1102 1175 11B0;B2D1;1102 1175 11B0; # (닑; 닑; 닑; 닑; 닑; ) HANGUL SYLLABLE NILG +B2D2;B2D2;1102 1175 11B1;B2D2;1102 1175 11B1; # (닒; 닒; 닒; 닒; 닒; ) HANGUL SYLLABLE NILM +B2D3;B2D3;1102 1175 11B2;B2D3;1102 1175 11B2; # (닓; 닓; 닓; 닓; 닓; ) HANGUL SYLLABLE NILB +B2D4;B2D4;1102 1175 11B3;B2D4;1102 1175 11B3; # (닔; 닔; 닔; 닔; 닔; ) HANGUL SYLLABLE NILS +B2D5;B2D5;1102 1175 11B4;B2D5;1102 1175 11B4; # (닕; 닕; 닕; 닕; 닕; ) HANGUL SYLLABLE NILT +B2D6;B2D6;1102 1175 11B5;B2D6;1102 1175 11B5; # (닖; 닖; 닖; 닖; 닖; ) HANGUL SYLLABLE NILP +B2D7;B2D7;1102 1175 11B6;B2D7;1102 1175 11B6; # (닗; 닗; 닗; 닗; 닗; ) HANGUL SYLLABLE NILH +B2D8;B2D8;1102 1175 11B7;B2D8;1102 1175 11B7; # (님; 님; 님; 님; 님; ) HANGUL SYLLABLE NIM +B2D9;B2D9;1102 1175 11B8;B2D9;1102 1175 11B8; # (닙; 닙; 닙; 닙; 닙; ) HANGUL SYLLABLE NIB +B2DA;B2DA;1102 1175 11B9;B2DA;1102 1175 11B9; # (닚; 닚; 닚; 닚; 닚; ) HANGUL SYLLABLE NIBS +B2DB;B2DB;1102 1175 11BA;B2DB;1102 1175 11BA; # (닛; 닛; 닛; 닛; 닛; ) HANGUL SYLLABLE NIS +B2DC;B2DC;1102 1175 11BB;B2DC;1102 1175 11BB; # (닜; 닜; 닜; 닜; 닜; ) HANGUL SYLLABLE NISS +B2DD;B2DD;1102 1175 11BC;B2DD;1102 1175 11BC; # (닝; 닝; 닝; 닝; 닝; ) HANGUL SYLLABLE NING +B2DE;B2DE;1102 1175 11BD;B2DE;1102 1175 11BD; # (닞; 닞; 닞; 닞; 닞; ) HANGUL SYLLABLE NIJ +B2DF;B2DF;1102 1175 11BE;B2DF;1102 1175 11BE; # (닟; 닟; 닟; 닟; 닟; ) HANGUL SYLLABLE NIC +B2E0;B2E0;1102 1175 11BF;B2E0;1102 1175 11BF; # (닠; 닠; 닠; 닠; 닠; ) HANGUL SYLLABLE NIK +B2E1;B2E1;1102 1175 11C0;B2E1;1102 1175 11C0; # (닡; 닡; 닡; 닡; 닡; ) HANGUL SYLLABLE NIT +B2E2;B2E2;1102 1175 11C1;B2E2;1102 1175 11C1; # (닢; 닢; 닢; 닢; 닢; ) HANGUL SYLLABLE NIP +B2E3;B2E3;1102 1175 11C2;B2E3;1102 1175 11C2; # (닣; 닣; 닣; 닣; 닣; ) HANGUL SYLLABLE NIH +B2E4;B2E4;1103 1161;B2E4;1103 1161; # (다; 다; 다; 다; 다; ) HANGUL SYLLABLE DA +B2E5;B2E5;1103 1161 11A8;B2E5;1103 1161 11A8; # (닥; 닥; 닥; 닥; 닥; ) HANGUL SYLLABLE DAG +B2E6;B2E6;1103 1161 11A9;B2E6;1103 1161 11A9; # (닦; 닦; 닦; 닦; 닦; ) HANGUL SYLLABLE DAGG +B2E7;B2E7;1103 1161 11AA;B2E7;1103 1161 11AA; # (닧; 닧; 닧; 닧; 닧; ) HANGUL SYLLABLE DAGS +B2E8;B2E8;1103 1161 11AB;B2E8;1103 1161 11AB; # (단; 단; 단; 단; 단; ) HANGUL SYLLABLE DAN +B2E9;B2E9;1103 1161 11AC;B2E9;1103 1161 11AC; # (닩; 닩; 닩; 닩; 닩; ) HANGUL SYLLABLE DANJ +B2EA;B2EA;1103 1161 11AD;B2EA;1103 1161 11AD; # (닪; 닪; 닪; 닪; 닪; ) HANGUL SYLLABLE DANH +B2EB;B2EB;1103 1161 11AE;B2EB;1103 1161 11AE; # (닫; 닫; 닫; 닫; 닫; ) HANGUL SYLLABLE DAD +B2EC;B2EC;1103 1161 11AF;B2EC;1103 1161 11AF; # (달; 달; 달; 달; 달; ) HANGUL SYLLABLE DAL +B2ED;B2ED;1103 1161 11B0;B2ED;1103 1161 11B0; # (닭; 닭; 닭; 닭; 닭; ) HANGUL SYLLABLE DALG +B2EE;B2EE;1103 1161 11B1;B2EE;1103 1161 11B1; # (닮; 닮; 닮; 닮; 닮; ) HANGUL SYLLABLE DALM +B2EF;B2EF;1103 1161 11B2;B2EF;1103 1161 11B2; # (닯; 닯; 닯; 닯; 닯; ) HANGUL SYLLABLE DALB +B2F0;B2F0;1103 1161 11B3;B2F0;1103 1161 11B3; # (닰; 닰; 닰; 닰; 닰; ) HANGUL SYLLABLE DALS +B2F1;B2F1;1103 1161 11B4;B2F1;1103 1161 11B4; # (닱; 닱; 닱; 닱; 닱; ) HANGUL SYLLABLE DALT +B2F2;B2F2;1103 1161 11B5;B2F2;1103 1161 11B5; # (닲; 닲; 닲; 닲; 닲; ) HANGUL SYLLABLE DALP +B2F3;B2F3;1103 1161 11B6;B2F3;1103 1161 11B6; # (닳; 닳; 닳; 닳; 닳; ) HANGUL SYLLABLE DALH +B2F4;B2F4;1103 1161 11B7;B2F4;1103 1161 11B7; # (담; 담; 담; 담; 담; ) HANGUL SYLLABLE DAM +B2F5;B2F5;1103 1161 11B8;B2F5;1103 1161 11B8; # (답; 답; 답; 답; 답; ) HANGUL SYLLABLE DAB +B2F6;B2F6;1103 1161 11B9;B2F6;1103 1161 11B9; # (닶; 닶; 닶; 닶; 닶; ) HANGUL SYLLABLE DABS +B2F7;B2F7;1103 1161 11BA;B2F7;1103 1161 11BA; # (닷; 닷; 닷; 닷; 닷; ) HANGUL SYLLABLE DAS +B2F8;B2F8;1103 1161 11BB;B2F8;1103 1161 11BB; # (닸; 닸; 닸; 닸; 닸; ) HANGUL SYLLABLE DASS +B2F9;B2F9;1103 1161 11BC;B2F9;1103 1161 11BC; # (당; 당; 당; 당; 당; ) HANGUL SYLLABLE DANG +B2FA;B2FA;1103 1161 11BD;B2FA;1103 1161 11BD; # (닺; 닺; 닺; 닺; 닺; ) HANGUL SYLLABLE DAJ +B2FB;B2FB;1103 1161 11BE;B2FB;1103 1161 11BE; # (닻; 닻; 닻; 닻; 닻; ) HANGUL SYLLABLE DAC +B2FC;B2FC;1103 1161 11BF;B2FC;1103 1161 11BF; # (닼; 닼; 닼; 닼; 닼; ) HANGUL SYLLABLE DAK +B2FD;B2FD;1103 1161 11C0;B2FD;1103 1161 11C0; # (닽; 닽; 닽; 닽; 닽; ) HANGUL SYLLABLE DAT +B2FE;B2FE;1103 1161 11C1;B2FE;1103 1161 11C1; # (닾; 닾; 닾; 닾; 닾; ) HANGUL SYLLABLE DAP +B2FF;B2FF;1103 1161 11C2;B2FF;1103 1161 11C2; # (닿; 닿; 닿; 닿; 닿; ) HANGUL SYLLABLE DAH +B300;B300;1103 1162;B300;1103 1162; # (대; 대; 대; 대; 대; ) HANGUL SYLLABLE DAE +B301;B301;1103 1162 11A8;B301;1103 1162 11A8; # (댁; 댁; 댁; 댁; 댁; ) HANGUL SYLLABLE DAEG +B302;B302;1103 1162 11A9;B302;1103 1162 11A9; # (댂; 댂; 댂; 댂; 댂; ) HANGUL SYLLABLE DAEGG +B303;B303;1103 1162 11AA;B303;1103 1162 11AA; # (댃; 댃; 댃; 댃; 댃; ) HANGUL SYLLABLE DAEGS +B304;B304;1103 1162 11AB;B304;1103 1162 11AB; # (댄; 댄; 댄; 댄; 댄; ) HANGUL SYLLABLE DAEN +B305;B305;1103 1162 11AC;B305;1103 1162 11AC; # (댅; 댅; 댅; 댅; 댅; ) HANGUL SYLLABLE DAENJ +B306;B306;1103 1162 11AD;B306;1103 1162 11AD; # (댆; 댆; 댆; 댆; 댆; ) HANGUL SYLLABLE DAENH +B307;B307;1103 1162 11AE;B307;1103 1162 11AE; # (댇; 댇; 댇; 댇; 댇; ) HANGUL SYLLABLE DAED +B308;B308;1103 1162 11AF;B308;1103 1162 11AF; # (댈; 댈; 댈; 댈; 댈; ) HANGUL SYLLABLE DAEL +B309;B309;1103 1162 11B0;B309;1103 1162 11B0; # (댉; 댉; 댉; 댉; 댉; ) HANGUL SYLLABLE DAELG +B30A;B30A;1103 1162 11B1;B30A;1103 1162 11B1; # (댊; 댊; 댊; 댊; 댊; ) HANGUL SYLLABLE DAELM +B30B;B30B;1103 1162 11B2;B30B;1103 1162 11B2; # (댋; 댋; 댋; 댋; 댋; ) HANGUL SYLLABLE DAELB +B30C;B30C;1103 1162 11B3;B30C;1103 1162 11B3; # (댌; 댌; 댌; 댌; 댌; ) HANGUL SYLLABLE DAELS +B30D;B30D;1103 1162 11B4;B30D;1103 1162 11B4; # (댍; 댍; 댍; 댍; 댍; ) HANGUL SYLLABLE DAELT +B30E;B30E;1103 1162 11B5;B30E;1103 1162 11B5; # (댎; 댎; 댎; 댎; 댎; ) HANGUL SYLLABLE DAELP +B30F;B30F;1103 1162 11B6;B30F;1103 1162 11B6; # (댏; 댏; 댏; 댏; 댏; ) HANGUL SYLLABLE DAELH +B310;B310;1103 1162 11B7;B310;1103 1162 11B7; # (댐; 댐; 댐; 댐; 댐; ) HANGUL SYLLABLE DAEM +B311;B311;1103 1162 11B8;B311;1103 1162 11B8; # (댑; 댑; 댑; 댑; 댑; ) HANGUL SYLLABLE DAEB +B312;B312;1103 1162 11B9;B312;1103 1162 11B9; # (댒; 댒; 댒; 댒; 댒; ) HANGUL SYLLABLE DAEBS +B313;B313;1103 1162 11BA;B313;1103 1162 11BA; # (댓; 댓; 댓; 댓; 댓; ) HANGUL SYLLABLE DAES +B314;B314;1103 1162 11BB;B314;1103 1162 11BB; # (댔; 댔; 댔; 댔; 댔; ) HANGUL SYLLABLE DAESS +B315;B315;1103 1162 11BC;B315;1103 1162 11BC; # (댕; 댕; 댕; 댕; 댕; ) HANGUL SYLLABLE DAENG +B316;B316;1103 1162 11BD;B316;1103 1162 11BD; # (댖; 댖; 댖; 댖; 댖; ) HANGUL SYLLABLE DAEJ +B317;B317;1103 1162 11BE;B317;1103 1162 11BE; # (댗; 댗; 댗; 댗; 댗; ) HANGUL SYLLABLE DAEC +B318;B318;1103 1162 11BF;B318;1103 1162 11BF; # (댘; 댘; 댘; 댘; 댘; ) HANGUL SYLLABLE DAEK +B319;B319;1103 1162 11C0;B319;1103 1162 11C0; # (댙; 댙; 댙; 댙; 댙; ) HANGUL SYLLABLE DAET +B31A;B31A;1103 1162 11C1;B31A;1103 1162 11C1; # (댚; 댚; 댚; 댚; 댚; ) HANGUL SYLLABLE DAEP +B31B;B31B;1103 1162 11C2;B31B;1103 1162 11C2; # (댛; 댛; 댛; 댛; 댛; ) HANGUL SYLLABLE DAEH +B31C;B31C;1103 1163;B31C;1103 1163; # (댜; 댜; 댜; 댜; 댜; ) HANGUL SYLLABLE DYA +B31D;B31D;1103 1163 11A8;B31D;1103 1163 11A8; # (댝; 댝; 댝; 댝; 댝; ) HANGUL SYLLABLE DYAG +B31E;B31E;1103 1163 11A9;B31E;1103 1163 11A9; # (댞; 댞; 댞; 댞; 댞; ) HANGUL SYLLABLE DYAGG +B31F;B31F;1103 1163 11AA;B31F;1103 1163 11AA; # (댟; 댟; 댟; 댟; 댟; ) HANGUL SYLLABLE DYAGS +B320;B320;1103 1163 11AB;B320;1103 1163 11AB; # (댠; 댠; 댠; 댠; 댠; ) HANGUL SYLLABLE DYAN +B321;B321;1103 1163 11AC;B321;1103 1163 11AC; # (댡; 댡; 댡; 댡; 댡; ) HANGUL SYLLABLE DYANJ +B322;B322;1103 1163 11AD;B322;1103 1163 11AD; # (댢; 댢; 댢; 댢; 댢; ) HANGUL SYLLABLE DYANH +B323;B323;1103 1163 11AE;B323;1103 1163 11AE; # (댣; 댣; 댣; 댣; 댣; ) HANGUL SYLLABLE DYAD +B324;B324;1103 1163 11AF;B324;1103 1163 11AF; # (댤; 댤; 댤; 댤; 댤; ) HANGUL SYLLABLE DYAL +B325;B325;1103 1163 11B0;B325;1103 1163 11B0; # (댥; 댥; 댥; 댥; 댥; ) HANGUL SYLLABLE DYALG +B326;B326;1103 1163 11B1;B326;1103 1163 11B1; # (댦; 댦; 댦; 댦; 댦; ) HANGUL SYLLABLE DYALM +B327;B327;1103 1163 11B2;B327;1103 1163 11B2; # (댧; 댧; 댧; 댧; 댧; ) HANGUL SYLLABLE DYALB +B328;B328;1103 1163 11B3;B328;1103 1163 11B3; # (댨; 댨; 댨; 댨; 댨; ) HANGUL SYLLABLE DYALS +B329;B329;1103 1163 11B4;B329;1103 1163 11B4; # (댩; 댩; 댩; 댩; 댩; ) HANGUL SYLLABLE DYALT +B32A;B32A;1103 1163 11B5;B32A;1103 1163 11B5; # (댪; 댪; 댪; 댪; 댪; ) HANGUL SYLLABLE DYALP +B32B;B32B;1103 1163 11B6;B32B;1103 1163 11B6; # (댫; 댫; 댫; 댫; 댫; ) HANGUL SYLLABLE DYALH +B32C;B32C;1103 1163 11B7;B32C;1103 1163 11B7; # (댬; 댬; 댬; 댬; 댬; ) HANGUL SYLLABLE DYAM +B32D;B32D;1103 1163 11B8;B32D;1103 1163 11B8; # (댭; 댭; 댭; 댭; 댭; ) HANGUL SYLLABLE DYAB +B32E;B32E;1103 1163 11B9;B32E;1103 1163 11B9; # (댮; 댮; 댮; 댮; 댮; ) HANGUL SYLLABLE DYABS +B32F;B32F;1103 1163 11BA;B32F;1103 1163 11BA; # (댯; 댯; 댯; 댯; 댯; ) HANGUL SYLLABLE DYAS +B330;B330;1103 1163 11BB;B330;1103 1163 11BB; # (댰; 댰; 댰; 댰; 댰; ) HANGUL SYLLABLE DYASS +B331;B331;1103 1163 11BC;B331;1103 1163 11BC; # (댱; 댱; 댱; 댱; 댱; ) HANGUL SYLLABLE DYANG +B332;B332;1103 1163 11BD;B332;1103 1163 11BD; # (댲; 댲; 댲; 댲; 댲; ) HANGUL SYLLABLE DYAJ +B333;B333;1103 1163 11BE;B333;1103 1163 11BE; # (댳; 댳; 댳; 댳; 댳; ) HANGUL SYLLABLE DYAC +B334;B334;1103 1163 11BF;B334;1103 1163 11BF; # (댴; 댴; 댴; 댴; 댴; ) HANGUL SYLLABLE DYAK +B335;B335;1103 1163 11C0;B335;1103 1163 11C0; # (댵; 댵; 댵; 댵; 댵; ) HANGUL SYLLABLE DYAT +B336;B336;1103 1163 11C1;B336;1103 1163 11C1; # (댶; 댶; 댶; 댶; 댶; ) HANGUL SYLLABLE DYAP +B337;B337;1103 1163 11C2;B337;1103 1163 11C2; # (댷; 댷; 댷; 댷; 댷; ) HANGUL SYLLABLE DYAH +B338;B338;1103 1164;B338;1103 1164; # (댸; 댸; 댸; 댸; 댸; ) HANGUL SYLLABLE DYAE +B339;B339;1103 1164 11A8;B339;1103 1164 11A8; # (댹; 댹; 댹; 댹; 댹; ) HANGUL SYLLABLE DYAEG +B33A;B33A;1103 1164 11A9;B33A;1103 1164 11A9; # (댺; 댺; 댺; 댺; 댺; ) HANGUL SYLLABLE DYAEGG +B33B;B33B;1103 1164 11AA;B33B;1103 1164 11AA; # (댻; 댻; 댻; 댻; 댻; ) HANGUL SYLLABLE DYAEGS +B33C;B33C;1103 1164 11AB;B33C;1103 1164 11AB; # (댼; 댼; 댼; 댼; 댼; ) HANGUL SYLLABLE DYAEN +B33D;B33D;1103 1164 11AC;B33D;1103 1164 11AC; # (댽; 댽; 댽; 댽; 댽; ) HANGUL SYLLABLE DYAENJ +B33E;B33E;1103 1164 11AD;B33E;1103 1164 11AD; # (댾; 댾; 댾; 댾; 댾; ) HANGUL SYLLABLE DYAENH +B33F;B33F;1103 1164 11AE;B33F;1103 1164 11AE; # (댿; 댿; 댿; 댿; 댿; ) HANGUL SYLLABLE DYAED +B340;B340;1103 1164 11AF;B340;1103 1164 11AF; # (덀; 덀; 덀; 덀; 덀; ) HANGUL SYLLABLE DYAEL +B341;B341;1103 1164 11B0;B341;1103 1164 11B0; # (덁; 덁; 덁; 덁; 덁; ) HANGUL SYLLABLE DYAELG +B342;B342;1103 1164 11B1;B342;1103 1164 11B1; # (덂; 덂; 덂; 덂; 덂; ) HANGUL SYLLABLE DYAELM +B343;B343;1103 1164 11B2;B343;1103 1164 11B2; # (덃; 덃; 덃; 덃; 덃; ) HANGUL SYLLABLE DYAELB +B344;B344;1103 1164 11B3;B344;1103 1164 11B3; # (덄; 덄; 덄; 덄; 덄; ) HANGUL SYLLABLE DYAELS +B345;B345;1103 1164 11B4;B345;1103 1164 11B4; # (덅; 덅; 덅; 덅; 덅; ) HANGUL SYLLABLE DYAELT +B346;B346;1103 1164 11B5;B346;1103 1164 11B5; # (덆; 덆; 덆; 덆; 덆; ) HANGUL SYLLABLE DYAELP +B347;B347;1103 1164 11B6;B347;1103 1164 11B6; # (덇; 덇; 덇; 덇; 덇; ) HANGUL SYLLABLE DYAELH +B348;B348;1103 1164 11B7;B348;1103 1164 11B7; # (덈; 덈; 덈; 덈; 덈; ) HANGUL SYLLABLE DYAEM +B349;B349;1103 1164 11B8;B349;1103 1164 11B8; # (덉; 덉; 덉; 덉; 덉; ) HANGUL SYLLABLE DYAEB +B34A;B34A;1103 1164 11B9;B34A;1103 1164 11B9; # (덊; 덊; 덊; 덊; 덊; ) HANGUL SYLLABLE DYAEBS +B34B;B34B;1103 1164 11BA;B34B;1103 1164 11BA; # (덋; 덋; 덋; 덋; 덋; ) HANGUL SYLLABLE DYAES +B34C;B34C;1103 1164 11BB;B34C;1103 1164 11BB; # (덌; 덌; 덌; 덌; 덌; ) HANGUL SYLLABLE DYAESS +B34D;B34D;1103 1164 11BC;B34D;1103 1164 11BC; # (덍; 덍; 덍; 덍; 덍; ) HANGUL SYLLABLE DYAENG +B34E;B34E;1103 1164 11BD;B34E;1103 1164 11BD; # (덎; 덎; 덎; 덎; 덎; ) HANGUL SYLLABLE DYAEJ +B34F;B34F;1103 1164 11BE;B34F;1103 1164 11BE; # (덏; 덏; 덏; 덏; 덏; ) HANGUL SYLLABLE DYAEC +B350;B350;1103 1164 11BF;B350;1103 1164 11BF; # (덐; 덐; 덐; 덐; 덐; ) HANGUL SYLLABLE DYAEK +B351;B351;1103 1164 11C0;B351;1103 1164 11C0; # (덑; 덑; 덑; 덑; 덑; ) HANGUL SYLLABLE DYAET +B352;B352;1103 1164 11C1;B352;1103 1164 11C1; # (덒; 덒; 덒; 덒; 덒; ) HANGUL SYLLABLE DYAEP +B353;B353;1103 1164 11C2;B353;1103 1164 11C2; # (덓; 덓; 덓; 덓; 덓; ) HANGUL SYLLABLE DYAEH +B354;B354;1103 1165;B354;1103 1165; # (더; 더; 더; 더; 더; ) HANGUL SYLLABLE DEO +B355;B355;1103 1165 11A8;B355;1103 1165 11A8; # (덕; 덕; 덕; 덕; 덕; ) HANGUL SYLLABLE DEOG +B356;B356;1103 1165 11A9;B356;1103 1165 11A9; # (덖; 덖; 덖; 덖; 덖; ) HANGUL SYLLABLE DEOGG +B357;B357;1103 1165 11AA;B357;1103 1165 11AA; # (덗; 덗; 덗; 덗; 덗; ) HANGUL SYLLABLE DEOGS +B358;B358;1103 1165 11AB;B358;1103 1165 11AB; # (던; 던; 던; 던; 던; ) HANGUL SYLLABLE DEON +B359;B359;1103 1165 11AC;B359;1103 1165 11AC; # (덙; 덙; 덙; 덙; 덙; ) HANGUL SYLLABLE DEONJ +B35A;B35A;1103 1165 11AD;B35A;1103 1165 11AD; # (덚; 덚; 덚; 덚; 덚; ) HANGUL SYLLABLE DEONH +B35B;B35B;1103 1165 11AE;B35B;1103 1165 11AE; # (덛; 덛; 덛; 덛; 덛; ) HANGUL SYLLABLE DEOD +B35C;B35C;1103 1165 11AF;B35C;1103 1165 11AF; # (덜; 덜; 덜; 덜; 덜; ) HANGUL SYLLABLE DEOL +B35D;B35D;1103 1165 11B0;B35D;1103 1165 11B0; # (덝; 덝; 덝; 덝; 덝; ) HANGUL SYLLABLE DEOLG +B35E;B35E;1103 1165 11B1;B35E;1103 1165 11B1; # (덞; 덞; 덞; 덞; 덞; ) HANGUL SYLLABLE DEOLM +B35F;B35F;1103 1165 11B2;B35F;1103 1165 11B2; # (덟; 덟; 덟; 덟; 덟; ) HANGUL SYLLABLE DEOLB +B360;B360;1103 1165 11B3;B360;1103 1165 11B3; # (덠; 덠; 덠; 덠; 덠; ) HANGUL SYLLABLE DEOLS +B361;B361;1103 1165 11B4;B361;1103 1165 11B4; # (덡; 덡; 덡; 덡; 덡; ) HANGUL SYLLABLE DEOLT +B362;B362;1103 1165 11B5;B362;1103 1165 11B5; # (덢; 덢; 덢; 덢; 덢; ) HANGUL SYLLABLE DEOLP +B363;B363;1103 1165 11B6;B363;1103 1165 11B6; # (덣; 덣; 덣; 덣; 덣; ) HANGUL SYLLABLE DEOLH +B364;B364;1103 1165 11B7;B364;1103 1165 11B7; # (덤; 덤; 덤; 덤; 덤; ) HANGUL SYLLABLE DEOM +B365;B365;1103 1165 11B8;B365;1103 1165 11B8; # (덥; 덥; 덥; 덥; 덥; ) HANGUL SYLLABLE DEOB +B366;B366;1103 1165 11B9;B366;1103 1165 11B9; # (덦; 덦; 덦; 덦; 덦; ) HANGUL SYLLABLE DEOBS +B367;B367;1103 1165 11BA;B367;1103 1165 11BA; # (덧; 덧; 덧; 덧; 덧; ) HANGUL SYLLABLE DEOS +B368;B368;1103 1165 11BB;B368;1103 1165 11BB; # (덨; 덨; 덨; 덨; 덨; ) HANGUL SYLLABLE DEOSS +B369;B369;1103 1165 11BC;B369;1103 1165 11BC; # (덩; 덩; 덩; 덩; 덩; ) HANGUL SYLLABLE DEONG +B36A;B36A;1103 1165 11BD;B36A;1103 1165 11BD; # (덪; 덪; 덪; 덪; 덪; ) HANGUL SYLLABLE DEOJ +B36B;B36B;1103 1165 11BE;B36B;1103 1165 11BE; # (덫; 덫; 덫; 덫; 덫; ) HANGUL SYLLABLE DEOC +B36C;B36C;1103 1165 11BF;B36C;1103 1165 11BF; # (덬; 덬; 덬; 덬; 덬; ) HANGUL SYLLABLE DEOK +B36D;B36D;1103 1165 11C0;B36D;1103 1165 11C0; # (덭; 덭; 덭; 덭; 덭; ) HANGUL SYLLABLE DEOT +B36E;B36E;1103 1165 11C1;B36E;1103 1165 11C1; # (덮; 덮; 덮; 덮; 덮; ) HANGUL SYLLABLE DEOP +B36F;B36F;1103 1165 11C2;B36F;1103 1165 11C2; # (덯; 덯; 덯; 덯; 덯; ) HANGUL SYLLABLE DEOH +B370;B370;1103 1166;B370;1103 1166; # (데; 데; 데; 데; 데; ) HANGUL SYLLABLE DE +B371;B371;1103 1166 11A8;B371;1103 1166 11A8; # (덱; 덱; 덱; 덱; 덱; ) HANGUL SYLLABLE DEG +B372;B372;1103 1166 11A9;B372;1103 1166 11A9; # (덲; 덲; 덲; 덲; 덲; ) HANGUL SYLLABLE DEGG +B373;B373;1103 1166 11AA;B373;1103 1166 11AA; # (덳; 덳; 덳; 덳; 덳; ) HANGUL SYLLABLE DEGS +B374;B374;1103 1166 11AB;B374;1103 1166 11AB; # (덴; 덴; 덴; 덴; 덴; ) HANGUL SYLLABLE DEN +B375;B375;1103 1166 11AC;B375;1103 1166 11AC; # (덵; 덵; 덵; 덵; 덵; ) HANGUL SYLLABLE DENJ +B376;B376;1103 1166 11AD;B376;1103 1166 11AD; # (덶; 덶; 덶; 덶; 덶; ) HANGUL SYLLABLE DENH +B377;B377;1103 1166 11AE;B377;1103 1166 11AE; # (덷; 덷; 덷; 덷; 덷; ) HANGUL SYLLABLE DED +B378;B378;1103 1166 11AF;B378;1103 1166 11AF; # (델; 델; 델; 델; 델; ) HANGUL SYLLABLE DEL +B379;B379;1103 1166 11B0;B379;1103 1166 11B0; # (덹; 덹; 덹; 덹; 덹; ) HANGUL SYLLABLE DELG +B37A;B37A;1103 1166 11B1;B37A;1103 1166 11B1; # (덺; 덺; 덺; 덺; 덺; ) HANGUL SYLLABLE DELM +B37B;B37B;1103 1166 11B2;B37B;1103 1166 11B2; # (덻; 덻; 덻; 덻; 덻; ) HANGUL SYLLABLE DELB +B37C;B37C;1103 1166 11B3;B37C;1103 1166 11B3; # (덼; 덼; 덼; 덼; 덼; ) HANGUL SYLLABLE DELS +B37D;B37D;1103 1166 11B4;B37D;1103 1166 11B4; # (덽; 덽; 덽; 덽; 덽; ) HANGUL SYLLABLE DELT +B37E;B37E;1103 1166 11B5;B37E;1103 1166 11B5; # (덾; 덾; 덾; 덾; 덾; ) HANGUL SYLLABLE DELP +B37F;B37F;1103 1166 11B6;B37F;1103 1166 11B6; # (덿; 덿; 덿; 덿; 덿; ) HANGUL SYLLABLE DELH +B380;B380;1103 1166 11B7;B380;1103 1166 11B7; # (뎀; 뎀; 뎀; 뎀; 뎀; ) HANGUL SYLLABLE DEM +B381;B381;1103 1166 11B8;B381;1103 1166 11B8; # (뎁; 뎁; 뎁; 뎁; 뎁; ) HANGUL SYLLABLE DEB +B382;B382;1103 1166 11B9;B382;1103 1166 11B9; # (뎂; 뎂; 뎂; 뎂; 뎂; ) HANGUL SYLLABLE DEBS +B383;B383;1103 1166 11BA;B383;1103 1166 11BA; # (뎃; 뎃; 뎃; 뎃; 뎃; ) HANGUL SYLLABLE DES +B384;B384;1103 1166 11BB;B384;1103 1166 11BB; # (뎄; 뎄; 뎄; 뎄; 뎄; ) HANGUL SYLLABLE DESS +B385;B385;1103 1166 11BC;B385;1103 1166 11BC; # (뎅; 뎅; 뎅; 뎅; 뎅; ) HANGUL SYLLABLE DENG +B386;B386;1103 1166 11BD;B386;1103 1166 11BD; # (뎆; 뎆; 뎆; 뎆; 뎆; ) HANGUL SYLLABLE DEJ +B387;B387;1103 1166 11BE;B387;1103 1166 11BE; # (뎇; 뎇; 뎇; 뎇; 뎇; ) HANGUL SYLLABLE DEC +B388;B388;1103 1166 11BF;B388;1103 1166 11BF; # (뎈; 뎈; 뎈; 뎈; 뎈; ) HANGUL SYLLABLE DEK +B389;B389;1103 1166 11C0;B389;1103 1166 11C0; # (뎉; 뎉; 뎉; 뎉; 뎉; ) HANGUL SYLLABLE DET +B38A;B38A;1103 1166 11C1;B38A;1103 1166 11C1; # (뎊; 뎊; 뎊; 뎊; 뎊; ) HANGUL SYLLABLE DEP +B38B;B38B;1103 1166 11C2;B38B;1103 1166 11C2; # (뎋; 뎋; 뎋; 뎋; 뎋; ) HANGUL SYLLABLE DEH +B38C;B38C;1103 1167;B38C;1103 1167; # (뎌; 뎌; 뎌; 뎌; 뎌; ) HANGUL SYLLABLE DYEO +B38D;B38D;1103 1167 11A8;B38D;1103 1167 11A8; # (뎍; 뎍; 뎍; 뎍; 뎍; ) HANGUL SYLLABLE DYEOG +B38E;B38E;1103 1167 11A9;B38E;1103 1167 11A9; # (뎎; 뎎; 뎎; 뎎; 뎎; ) HANGUL SYLLABLE DYEOGG +B38F;B38F;1103 1167 11AA;B38F;1103 1167 11AA; # (뎏; 뎏; 뎏; 뎏; 뎏; ) HANGUL SYLLABLE DYEOGS +B390;B390;1103 1167 11AB;B390;1103 1167 11AB; # (뎐; 뎐; 뎐; 뎐; 뎐; ) HANGUL SYLLABLE DYEON +B391;B391;1103 1167 11AC;B391;1103 1167 11AC; # (뎑; 뎑; 뎑; 뎑; 뎑; ) HANGUL SYLLABLE DYEONJ +B392;B392;1103 1167 11AD;B392;1103 1167 11AD; # (뎒; 뎒; 뎒; 뎒; 뎒; ) HANGUL SYLLABLE DYEONH +B393;B393;1103 1167 11AE;B393;1103 1167 11AE; # (뎓; 뎓; 뎓; 뎓; 뎓; ) HANGUL SYLLABLE DYEOD +B394;B394;1103 1167 11AF;B394;1103 1167 11AF; # (뎔; 뎔; 뎔; 뎔; 뎔; ) HANGUL SYLLABLE DYEOL +B395;B395;1103 1167 11B0;B395;1103 1167 11B0; # (뎕; 뎕; 뎕; 뎕; 뎕; ) HANGUL SYLLABLE DYEOLG +B396;B396;1103 1167 11B1;B396;1103 1167 11B1; # (뎖; 뎖; 뎖; 뎖; 뎖; ) HANGUL SYLLABLE DYEOLM +B397;B397;1103 1167 11B2;B397;1103 1167 11B2; # (뎗; 뎗; 뎗; 뎗; 뎗; ) HANGUL SYLLABLE DYEOLB +B398;B398;1103 1167 11B3;B398;1103 1167 11B3; # (뎘; 뎘; 뎘; 뎘; 뎘; ) HANGUL SYLLABLE DYEOLS +B399;B399;1103 1167 11B4;B399;1103 1167 11B4; # (뎙; 뎙; 뎙; 뎙; 뎙; ) HANGUL SYLLABLE DYEOLT +B39A;B39A;1103 1167 11B5;B39A;1103 1167 11B5; # (뎚; 뎚; 뎚; 뎚; 뎚; ) HANGUL SYLLABLE DYEOLP +B39B;B39B;1103 1167 11B6;B39B;1103 1167 11B6; # (뎛; 뎛; 뎛; 뎛; 뎛; ) HANGUL SYLLABLE DYEOLH +B39C;B39C;1103 1167 11B7;B39C;1103 1167 11B7; # (뎜; 뎜; 뎜; 뎜; 뎜; ) HANGUL SYLLABLE DYEOM +B39D;B39D;1103 1167 11B8;B39D;1103 1167 11B8; # (뎝; 뎝; 뎝; 뎝; 뎝; ) HANGUL SYLLABLE DYEOB +B39E;B39E;1103 1167 11B9;B39E;1103 1167 11B9; # (뎞; 뎞; 뎞; 뎞; 뎞; ) HANGUL SYLLABLE DYEOBS +B39F;B39F;1103 1167 11BA;B39F;1103 1167 11BA; # (뎟; 뎟; 뎟; 뎟; 뎟; ) HANGUL SYLLABLE DYEOS +B3A0;B3A0;1103 1167 11BB;B3A0;1103 1167 11BB; # (뎠; 뎠; 뎠; 뎠; 뎠; ) HANGUL SYLLABLE DYEOSS +B3A1;B3A1;1103 1167 11BC;B3A1;1103 1167 11BC; # (뎡; 뎡; 뎡; 뎡; 뎡; ) HANGUL SYLLABLE DYEONG +B3A2;B3A2;1103 1167 11BD;B3A2;1103 1167 11BD; # (뎢; 뎢; 뎢; 뎢; 뎢; ) HANGUL SYLLABLE DYEOJ +B3A3;B3A3;1103 1167 11BE;B3A3;1103 1167 11BE; # (뎣; 뎣; 뎣; 뎣; 뎣; ) HANGUL SYLLABLE DYEOC +B3A4;B3A4;1103 1167 11BF;B3A4;1103 1167 11BF; # (뎤; 뎤; 뎤; 뎤; 뎤; ) HANGUL SYLLABLE DYEOK +B3A5;B3A5;1103 1167 11C0;B3A5;1103 1167 11C0; # (뎥; 뎥; 뎥; 뎥; 뎥; ) HANGUL SYLLABLE DYEOT +B3A6;B3A6;1103 1167 11C1;B3A6;1103 1167 11C1; # (뎦; 뎦; 뎦; 뎦; 뎦; ) HANGUL SYLLABLE DYEOP +B3A7;B3A7;1103 1167 11C2;B3A7;1103 1167 11C2; # (뎧; 뎧; 뎧; 뎧; 뎧; ) HANGUL SYLLABLE DYEOH +B3A8;B3A8;1103 1168;B3A8;1103 1168; # (뎨; 뎨; 뎨; 뎨; 뎨; ) HANGUL SYLLABLE DYE +B3A9;B3A9;1103 1168 11A8;B3A9;1103 1168 11A8; # (뎩; 뎩; 뎩; 뎩; 뎩; ) HANGUL SYLLABLE DYEG +B3AA;B3AA;1103 1168 11A9;B3AA;1103 1168 11A9; # (뎪; 뎪; 뎪; 뎪; 뎪; ) HANGUL SYLLABLE DYEGG +B3AB;B3AB;1103 1168 11AA;B3AB;1103 1168 11AA; # (뎫; 뎫; 뎫; 뎫; 뎫; ) HANGUL SYLLABLE DYEGS +B3AC;B3AC;1103 1168 11AB;B3AC;1103 1168 11AB; # (뎬; 뎬; 뎬; 뎬; 뎬; ) HANGUL SYLLABLE DYEN +B3AD;B3AD;1103 1168 11AC;B3AD;1103 1168 11AC; # (뎭; 뎭; 뎭; 뎭; 뎭; ) HANGUL SYLLABLE DYENJ +B3AE;B3AE;1103 1168 11AD;B3AE;1103 1168 11AD; # (뎮; 뎮; 뎮; 뎮; 뎮; ) HANGUL SYLLABLE DYENH +B3AF;B3AF;1103 1168 11AE;B3AF;1103 1168 11AE; # (뎯; 뎯; 뎯; 뎯; 뎯; ) HANGUL SYLLABLE DYED +B3B0;B3B0;1103 1168 11AF;B3B0;1103 1168 11AF; # (뎰; 뎰; 뎰; 뎰; 뎰; ) HANGUL SYLLABLE DYEL +B3B1;B3B1;1103 1168 11B0;B3B1;1103 1168 11B0; # (뎱; 뎱; 뎱; 뎱; 뎱; ) HANGUL SYLLABLE DYELG +B3B2;B3B2;1103 1168 11B1;B3B2;1103 1168 11B1; # (뎲; 뎲; 뎲; 뎲; 뎲; ) HANGUL SYLLABLE DYELM +B3B3;B3B3;1103 1168 11B2;B3B3;1103 1168 11B2; # (뎳; 뎳; 뎳; 뎳; 뎳; ) HANGUL SYLLABLE DYELB +B3B4;B3B4;1103 1168 11B3;B3B4;1103 1168 11B3; # (뎴; 뎴; 뎴; 뎴; 뎴; ) HANGUL SYLLABLE DYELS +B3B5;B3B5;1103 1168 11B4;B3B5;1103 1168 11B4; # (뎵; 뎵; 뎵; 뎵; 뎵; ) HANGUL SYLLABLE DYELT +B3B6;B3B6;1103 1168 11B5;B3B6;1103 1168 11B5; # (뎶; 뎶; 뎶; 뎶; 뎶; ) HANGUL SYLLABLE DYELP +B3B7;B3B7;1103 1168 11B6;B3B7;1103 1168 11B6; # (뎷; 뎷; 뎷; 뎷; 뎷; ) HANGUL SYLLABLE DYELH +B3B8;B3B8;1103 1168 11B7;B3B8;1103 1168 11B7; # (뎸; 뎸; 뎸; 뎸; 뎸; ) HANGUL SYLLABLE DYEM +B3B9;B3B9;1103 1168 11B8;B3B9;1103 1168 11B8; # (뎹; 뎹; 뎹; 뎹; 뎹; ) HANGUL SYLLABLE DYEB +B3BA;B3BA;1103 1168 11B9;B3BA;1103 1168 11B9; # (뎺; 뎺; 뎺; 뎺; 뎺; ) HANGUL SYLLABLE DYEBS +B3BB;B3BB;1103 1168 11BA;B3BB;1103 1168 11BA; # (뎻; 뎻; 뎻; 뎻; 뎻; ) HANGUL SYLLABLE DYES +B3BC;B3BC;1103 1168 11BB;B3BC;1103 1168 11BB; # (뎼; 뎼; 뎼; 뎼; 뎼; ) HANGUL SYLLABLE DYESS +B3BD;B3BD;1103 1168 11BC;B3BD;1103 1168 11BC; # (뎽; 뎽; 뎽; 뎽; 뎽; ) HANGUL SYLLABLE DYENG +B3BE;B3BE;1103 1168 11BD;B3BE;1103 1168 11BD; # (뎾; 뎾; 뎾; 뎾; 뎾; ) HANGUL SYLLABLE DYEJ +B3BF;B3BF;1103 1168 11BE;B3BF;1103 1168 11BE; # (뎿; 뎿; 뎿; 뎿; 뎿; ) HANGUL SYLLABLE DYEC +B3C0;B3C0;1103 1168 11BF;B3C0;1103 1168 11BF; # (돀; 돀; 돀; 돀; 돀; ) HANGUL SYLLABLE DYEK +B3C1;B3C1;1103 1168 11C0;B3C1;1103 1168 11C0; # (돁; 돁; 돁; 돁; 돁; ) HANGUL SYLLABLE DYET +B3C2;B3C2;1103 1168 11C1;B3C2;1103 1168 11C1; # (돂; 돂; 돂; 돂; 돂; ) HANGUL SYLLABLE DYEP +B3C3;B3C3;1103 1168 11C2;B3C3;1103 1168 11C2; # (돃; 돃; 돃; 돃; 돃; ) HANGUL SYLLABLE DYEH +B3C4;B3C4;1103 1169;B3C4;1103 1169; # (도; 도; 도; 도; 도; ) HANGUL SYLLABLE DO +B3C5;B3C5;1103 1169 11A8;B3C5;1103 1169 11A8; # (독; 독; 독; 독; 독; ) HANGUL SYLLABLE DOG +B3C6;B3C6;1103 1169 11A9;B3C6;1103 1169 11A9; # (돆; 돆; 돆; 돆; 돆; ) HANGUL SYLLABLE DOGG +B3C7;B3C7;1103 1169 11AA;B3C7;1103 1169 11AA; # (돇; 돇; 돇; 돇; 돇; ) HANGUL SYLLABLE DOGS +B3C8;B3C8;1103 1169 11AB;B3C8;1103 1169 11AB; # (돈; 돈; 돈; 돈; 돈; ) HANGUL SYLLABLE DON +B3C9;B3C9;1103 1169 11AC;B3C9;1103 1169 11AC; # (돉; 돉; 돉; 돉; 돉; ) HANGUL SYLLABLE DONJ +B3CA;B3CA;1103 1169 11AD;B3CA;1103 1169 11AD; # (돊; 돊; 돊; 돊; 돊; ) HANGUL SYLLABLE DONH +B3CB;B3CB;1103 1169 11AE;B3CB;1103 1169 11AE; # (돋; 돋; 돋; 돋; 돋; ) HANGUL SYLLABLE DOD +B3CC;B3CC;1103 1169 11AF;B3CC;1103 1169 11AF; # (돌; 돌; 돌; 돌; 돌; ) HANGUL SYLLABLE DOL +B3CD;B3CD;1103 1169 11B0;B3CD;1103 1169 11B0; # (돍; 돍; 돍; 돍; 돍; ) HANGUL SYLLABLE DOLG +B3CE;B3CE;1103 1169 11B1;B3CE;1103 1169 11B1; # (돎; 돎; 돎; 돎; 돎; ) HANGUL SYLLABLE DOLM +B3CF;B3CF;1103 1169 11B2;B3CF;1103 1169 11B2; # (돏; 돏; 돏; 돏; 돏; ) HANGUL SYLLABLE DOLB +B3D0;B3D0;1103 1169 11B3;B3D0;1103 1169 11B3; # (돐; 돐; 돐; 돐; 돐; ) HANGUL SYLLABLE DOLS +B3D1;B3D1;1103 1169 11B4;B3D1;1103 1169 11B4; # (돑; 돑; 돑; 돑; 돑; ) HANGUL SYLLABLE DOLT +B3D2;B3D2;1103 1169 11B5;B3D2;1103 1169 11B5; # (돒; 돒; 돒; 돒; 돒; ) HANGUL SYLLABLE DOLP +B3D3;B3D3;1103 1169 11B6;B3D3;1103 1169 11B6; # (돓; 돓; 돓; 돓; 돓; ) HANGUL SYLLABLE DOLH +B3D4;B3D4;1103 1169 11B7;B3D4;1103 1169 11B7; # (돔; 돔; 돔; 돔; 돔; ) HANGUL SYLLABLE DOM +B3D5;B3D5;1103 1169 11B8;B3D5;1103 1169 11B8; # (돕; 돕; 돕; 돕; 돕; ) HANGUL SYLLABLE DOB +B3D6;B3D6;1103 1169 11B9;B3D6;1103 1169 11B9; # (돖; 돖; 돖; 돖; 돖; ) HANGUL SYLLABLE DOBS +B3D7;B3D7;1103 1169 11BA;B3D7;1103 1169 11BA; # (돗; 돗; 돗; 돗; 돗; ) HANGUL SYLLABLE DOS +B3D8;B3D8;1103 1169 11BB;B3D8;1103 1169 11BB; # (돘; 돘; 돘; 돘; 돘; ) HANGUL SYLLABLE DOSS +B3D9;B3D9;1103 1169 11BC;B3D9;1103 1169 11BC; # (동; 동; 동; 동; 동; ) HANGUL SYLLABLE DONG +B3DA;B3DA;1103 1169 11BD;B3DA;1103 1169 11BD; # (돚; 돚; 돚; 돚; 돚; ) HANGUL SYLLABLE DOJ +B3DB;B3DB;1103 1169 11BE;B3DB;1103 1169 11BE; # (돛; 돛; 돛; 돛; 돛; ) HANGUL SYLLABLE DOC +B3DC;B3DC;1103 1169 11BF;B3DC;1103 1169 11BF; # (돜; 돜; 돜; 돜; 돜; ) HANGUL SYLLABLE DOK +B3DD;B3DD;1103 1169 11C0;B3DD;1103 1169 11C0; # (돝; 돝; 돝; 돝; 돝; ) HANGUL SYLLABLE DOT +B3DE;B3DE;1103 1169 11C1;B3DE;1103 1169 11C1; # (돞; 돞; 돞; 돞; 돞; ) HANGUL SYLLABLE DOP +B3DF;B3DF;1103 1169 11C2;B3DF;1103 1169 11C2; # (돟; 돟; 돟; 돟; 돟; ) HANGUL SYLLABLE DOH +B3E0;B3E0;1103 116A;B3E0;1103 116A; # (돠; 돠; 돠; 돠; 돠; ) HANGUL SYLLABLE DWA +B3E1;B3E1;1103 116A 11A8;B3E1;1103 116A 11A8; # (돡; 돡; 돡; 돡; 돡; ) HANGUL SYLLABLE DWAG +B3E2;B3E2;1103 116A 11A9;B3E2;1103 116A 11A9; # (돢; 돢; 돢; 돢; 돢; ) HANGUL SYLLABLE DWAGG +B3E3;B3E3;1103 116A 11AA;B3E3;1103 116A 11AA; # (돣; 돣; 돣; 돣; 돣; ) HANGUL SYLLABLE DWAGS +B3E4;B3E4;1103 116A 11AB;B3E4;1103 116A 11AB; # (돤; 돤; 돤; 돤; 돤; ) HANGUL SYLLABLE DWAN +B3E5;B3E5;1103 116A 11AC;B3E5;1103 116A 11AC; # (돥; 돥; 돥; 돥; 돥; ) HANGUL SYLLABLE DWANJ +B3E6;B3E6;1103 116A 11AD;B3E6;1103 116A 11AD; # (돦; 돦; 돦; 돦; 돦; ) HANGUL SYLLABLE DWANH +B3E7;B3E7;1103 116A 11AE;B3E7;1103 116A 11AE; # (돧; 돧; 돧; 돧; 돧; ) HANGUL SYLLABLE DWAD +B3E8;B3E8;1103 116A 11AF;B3E8;1103 116A 11AF; # (돨; 돨; 돨; 돨; 돨; ) HANGUL SYLLABLE DWAL +B3E9;B3E9;1103 116A 11B0;B3E9;1103 116A 11B0; # (돩; 돩; 돩; 돩; 돩; ) HANGUL SYLLABLE DWALG +B3EA;B3EA;1103 116A 11B1;B3EA;1103 116A 11B1; # (돪; 돪; 돪; 돪; 돪; ) HANGUL SYLLABLE DWALM +B3EB;B3EB;1103 116A 11B2;B3EB;1103 116A 11B2; # (돫; 돫; 돫; 돫; 돫; ) HANGUL SYLLABLE DWALB +B3EC;B3EC;1103 116A 11B3;B3EC;1103 116A 11B3; # (돬; 돬; 돬; 돬; 돬; ) HANGUL SYLLABLE DWALS +B3ED;B3ED;1103 116A 11B4;B3ED;1103 116A 11B4; # (돭; 돭; 돭; 돭; 돭; ) HANGUL SYLLABLE DWALT +B3EE;B3EE;1103 116A 11B5;B3EE;1103 116A 11B5; # (돮; 돮; 돮; 돮; 돮; ) HANGUL SYLLABLE DWALP +B3EF;B3EF;1103 116A 11B6;B3EF;1103 116A 11B6; # (돯; 돯; 돯; 돯; 돯; ) HANGUL SYLLABLE DWALH +B3F0;B3F0;1103 116A 11B7;B3F0;1103 116A 11B7; # (돰; 돰; 돰; 돰; 돰; ) HANGUL SYLLABLE DWAM +B3F1;B3F1;1103 116A 11B8;B3F1;1103 116A 11B8; # (돱; 돱; 돱; 돱; 돱; ) HANGUL SYLLABLE DWAB +B3F2;B3F2;1103 116A 11B9;B3F2;1103 116A 11B9; # (돲; 돲; 돲; 돲; 돲; ) HANGUL SYLLABLE DWABS +B3F3;B3F3;1103 116A 11BA;B3F3;1103 116A 11BA; # (돳; 돳; 돳; 돳; 돳; ) HANGUL SYLLABLE DWAS +B3F4;B3F4;1103 116A 11BB;B3F4;1103 116A 11BB; # (돴; 돴; 돴; 돴; 돴; ) HANGUL SYLLABLE DWASS +B3F5;B3F5;1103 116A 11BC;B3F5;1103 116A 11BC; # (돵; 돵; 돵; 돵; 돵; ) HANGUL SYLLABLE DWANG +B3F6;B3F6;1103 116A 11BD;B3F6;1103 116A 11BD; # (돶; 돶; 돶; 돶; 돶; ) HANGUL SYLLABLE DWAJ +B3F7;B3F7;1103 116A 11BE;B3F7;1103 116A 11BE; # (돷; 돷; 돷; 돷; 돷; ) HANGUL SYLLABLE DWAC +B3F8;B3F8;1103 116A 11BF;B3F8;1103 116A 11BF; # (돸; 돸; 돸; 돸; 돸; ) HANGUL SYLLABLE DWAK +B3F9;B3F9;1103 116A 11C0;B3F9;1103 116A 11C0; # (돹; 돹; 돹; 돹; 돹; ) HANGUL SYLLABLE DWAT +B3FA;B3FA;1103 116A 11C1;B3FA;1103 116A 11C1; # (돺; 돺; 돺; 돺; 돺; ) HANGUL SYLLABLE DWAP +B3FB;B3FB;1103 116A 11C2;B3FB;1103 116A 11C2; # (돻; 돻; 돻; 돻; 돻; ) HANGUL SYLLABLE DWAH +B3FC;B3FC;1103 116B;B3FC;1103 116B; # (돼; 돼; 돼; 돼; 돼; ) HANGUL SYLLABLE DWAE +B3FD;B3FD;1103 116B 11A8;B3FD;1103 116B 11A8; # (돽; 돽; 돽; 돽; 돽; ) HANGUL SYLLABLE DWAEG +B3FE;B3FE;1103 116B 11A9;B3FE;1103 116B 11A9; # (돾; 돾; 돾; 돾; 돾; ) HANGUL SYLLABLE DWAEGG +B3FF;B3FF;1103 116B 11AA;B3FF;1103 116B 11AA; # (돿; 돿; 돿; 돿; 돿; ) HANGUL SYLLABLE DWAEGS +B400;B400;1103 116B 11AB;B400;1103 116B 11AB; # (됀; 됀; 됀; 됀; 됀; ) HANGUL SYLLABLE DWAEN +B401;B401;1103 116B 11AC;B401;1103 116B 11AC; # (됁; 됁; 됁; 됁; 됁; ) HANGUL SYLLABLE DWAENJ +B402;B402;1103 116B 11AD;B402;1103 116B 11AD; # (됂; 됂; 됂; 됂; 됂; ) HANGUL SYLLABLE DWAENH +B403;B403;1103 116B 11AE;B403;1103 116B 11AE; # (됃; 됃; 됃; 됃; 됃; ) HANGUL SYLLABLE DWAED +B404;B404;1103 116B 11AF;B404;1103 116B 11AF; # (됄; 됄; 됄; 됄; 됄; ) HANGUL SYLLABLE DWAEL +B405;B405;1103 116B 11B0;B405;1103 116B 11B0; # (됅; 됅; 됅; 됅; 됅; ) HANGUL SYLLABLE DWAELG +B406;B406;1103 116B 11B1;B406;1103 116B 11B1; # (됆; 됆; 됆; 됆; 됆; ) HANGUL SYLLABLE DWAELM +B407;B407;1103 116B 11B2;B407;1103 116B 11B2; # (됇; 됇; 됇; 됇; 됇; ) HANGUL SYLLABLE DWAELB +B408;B408;1103 116B 11B3;B408;1103 116B 11B3; # (됈; 됈; 됈; 됈; 됈; ) HANGUL SYLLABLE DWAELS +B409;B409;1103 116B 11B4;B409;1103 116B 11B4; # (됉; 됉; 됉; 됉; 됉; ) HANGUL SYLLABLE DWAELT +B40A;B40A;1103 116B 11B5;B40A;1103 116B 11B5; # (됊; 됊; 됊; 됊; 됊; ) HANGUL SYLLABLE DWAELP +B40B;B40B;1103 116B 11B6;B40B;1103 116B 11B6; # (됋; 됋; 됋; 됋; 됋; ) HANGUL SYLLABLE DWAELH +B40C;B40C;1103 116B 11B7;B40C;1103 116B 11B7; # (됌; 됌; 됌; 됌; 됌; ) HANGUL SYLLABLE DWAEM +B40D;B40D;1103 116B 11B8;B40D;1103 116B 11B8; # (됍; 됍; 됍; 됍; 됍; ) HANGUL SYLLABLE DWAEB +B40E;B40E;1103 116B 11B9;B40E;1103 116B 11B9; # (됎; 됎; 됎; 됎; 됎; ) HANGUL SYLLABLE DWAEBS +B40F;B40F;1103 116B 11BA;B40F;1103 116B 11BA; # (됏; 됏; 됏; 됏; 됏; ) HANGUL SYLLABLE DWAES +B410;B410;1103 116B 11BB;B410;1103 116B 11BB; # (됐; 됐; 됐; 됐; 됐; ) HANGUL SYLLABLE DWAESS +B411;B411;1103 116B 11BC;B411;1103 116B 11BC; # (됑; 됑; 됑; 됑; 됑; ) HANGUL SYLLABLE DWAENG +B412;B412;1103 116B 11BD;B412;1103 116B 11BD; # (됒; 됒; 됒; 됒; 됒; ) HANGUL SYLLABLE DWAEJ +B413;B413;1103 116B 11BE;B413;1103 116B 11BE; # (됓; 됓; 됓; 됓; 됓; ) HANGUL SYLLABLE DWAEC +B414;B414;1103 116B 11BF;B414;1103 116B 11BF; # (됔; 됔; 됔; 됔; 됔; ) HANGUL SYLLABLE DWAEK +B415;B415;1103 116B 11C0;B415;1103 116B 11C0; # (됕; 됕; 됕; 됕; 됕; ) HANGUL SYLLABLE DWAET +B416;B416;1103 116B 11C1;B416;1103 116B 11C1; # (됖; 됖; 됖; 됖; 됖; ) HANGUL SYLLABLE DWAEP +B417;B417;1103 116B 11C2;B417;1103 116B 11C2; # (됗; 됗; 됗; 됗; 됗; ) HANGUL SYLLABLE DWAEH +B418;B418;1103 116C;B418;1103 116C; # (되; 되; 되; 되; 되; ) HANGUL SYLLABLE DOE +B419;B419;1103 116C 11A8;B419;1103 116C 11A8; # (됙; 됙; 됙; 됙; 됙; ) HANGUL SYLLABLE DOEG +B41A;B41A;1103 116C 11A9;B41A;1103 116C 11A9; # (됚; 됚; 됚; 됚; 됚; ) HANGUL SYLLABLE DOEGG +B41B;B41B;1103 116C 11AA;B41B;1103 116C 11AA; # (됛; 됛; 됛; 됛; 됛; ) HANGUL SYLLABLE DOEGS +B41C;B41C;1103 116C 11AB;B41C;1103 116C 11AB; # (된; 된; 된; 된; 된; ) HANGUL SYLLABLE DOEN +B41D;B41D;1103 116C 11AC;B41D;1103 116C 11AC; # (됝; 됝; 됝; 됝; 됝; ) HANGUL SYLLABLE DOENJ +B41E;B41E;1103 116C 11AD;B41E;1103 116C 11AD; # (됞; 됞; 됞; 됞; 됞; ) HANGUL SYLLABLE DOENH +B41F;B41F;1103 116C 11AE;B41F;1103 116C 11AE; # (됟; 됟; 됟; 됟; 됟; ) HANGUL SYLLABLE DOED +B420;B420;1103 116C 11AF;B420;1103 116C 11AF; # (될; 될; 될; 될; 될; ) HANGUL SYLLABLE DOEL +B421;B421;1103 116C 11B0;B421;1103 116C 11B0; # (됡; 됡; 됡; 됡; 됡; ) HANGUL SYLLABLE DOELG +B422;B422;1103 116C 11B1;B422;1103 116C 11B1; # (됢; 됢; 됢; 됢; 됢; ) HANGUL SYLLABLE DOELM +B423;B423;1103 116C 11B2;B423;1103 116C 11B2; # (됣; 됣; 됣; 됣; 됣; ) HANGUL SYLLABLE DOELB +B424;B424;1103 116C 11B3;B424;1103 116C 11B3; # (됤; 됤; 됤; 됤; 됤; ) HANGUL SYLLABLE DOELS +B425;B425;1103 116C 11B4;B425;1103 116C 11B4; # (됥; 됥; 됥; 됥; 됥; ) HANGUL SYLLABLE DOELT +B426;B426;1103 116C 11B5;B426;1103 116C 11B5; # (됦; 됦; 됦; 됦; 됦; ) HANGUL SYLLABLE DOELP +B427;B427;1103 116C 11B6;B427;1103 116C 11B6; # (됧; 됧; 됧; 됧; 됧; ) HANGUL SYLLABLE DOELH +B428;B428;1103 116C 11B7;B428;1103 116C 11B7; # (됨; 됨; 됨; 됨; 됨; ) HANGUL SYLLABLE DOEM +B429;B429;1103 116C 11B8;B429;1103 116C 11B8; # (됩; 됩; 됩; 됩; 됩; ) HANGUL SYLLABLE DOEB +B42A;B42A;1103 116C 11B9;B42A;1103 116C 11B9; # (됪; 됪; 됪; 됪; 됪; ) HANGUL SYLLABLE DOEBS +B42B;B42B;1103 116C 11BA;B42B;1103 116C 11BA; # (됫; 됫; 됫; 됫; 됫; ) HANGUL SYLLABLE DOES +B42C;B42C;1103 116C 11BB;B42C;1103 116C 11BB; # (됬; 됬; 됬; 됬; 됬; ) HANGUL SYLLABLE DOESS +B42D;B42D;1103 116C 11BC;B42D;1103 116C 11BC; # (됭; 됭; 됭; 됭; 됭; ) HANGUL SYLLABLE DOENG +B42E;B42E;1103 116C 11BD;B42E;1103 116C 11BD; # (됮; 됮; 됮; 됮; 됮; ) HANGUL SYLLABLE DOEJ +B42F;B42F;1103 116C 11BE;B42F;1103 116C 11BE; # (됯; 됯; 됯; 됯; 됯; ) HANGUL SYLLABLE DOEC +B430;B430;1103 116C 11BF;B430;1103 116C 11BF; # (됰; 됰; 됰; 됰; 됰; ) HANGUL SYLLABLE DOEK +B431;B431;1103 116C 11C0;B431;1103 116C 11C0; # (됱; 됱; 됱; 됱; 됱; ) HANGUL SYLLABLE DOET +B432;B432;1103 116C 11C1;B432;1103 116C 11C1; # (됲; 됲; 됲; 됲; 됲; ) HANGUL SYLLABLE DOEP +B433;B433;1103 116C 11C2;B433;1103 116C 11C2; # (됳; 됳; 됳; 됳; 됳; ) HANGUL SYLLABLE DOEH +B434;B434;1103 116D;B434;1103 116D; # (됴; 됴; 됴; 됴; 됴; ) HANGUL SYLLABLE DYO +B435;B435;1103 116D 11A8;B435;1103 116D 11A8; # (됵; 됵; 됵; 됵; 됵; ) HANGUL SYLLABLE DYOG +B436;B436;1103 116D 11A9;B436;1103 116D 11A9; # (됶; 됶; 됶; 됶; 됶; ) HANGUL SYLLABLE DYOGG +B437;B437;1103 116D 11AA;B437;1103 116D 11AA; # (됷; 됷; 됷; 됷; 됷; ) HANGUL SYLLABLE DYOGS +B438;B438;1103 116D 11AB;B438;1103 116D 11AB; # (됸; 됸; 됸; 됸; 됸; ) HANGUL SYLLABLE DYON +B439;B439;1103 116D 11AC;B439;1103 116D 11AC; # (됹; 됹; 됹; 됹; 됹; ) HANGUL SYLLABLE DYONJ +B43A;B43A;1103 116D 11AD;B43A;1103 116D 11AD; # (됺; 됺; 됺; 됺; 됺; ) HANGUL SYLLABLE DYONH +B43B;B43B;1103 116D 11AE;B43B;1103 116D 11AE; # (됻; 됻; 됻; 됻; 됻; ) HANGUL SYLLABLE DYOD +B43C;B43C;1103 116D 11AF;B43C;1103 116D 11AF; # (됼; 됼; 됼; 됼; 됼; ) HANGUL SYLLABLE DYOL +B43D;B43D;1103 116D 11B0;B43D;1103 116D 11B0; # (됽; 됽; 됽; 됽; 됽; ) HANGUL SYLLABLE DYOLG +B43E;B43E;1103 116D 11B1;B43E;1103 116D 11B1; # (됾; 됾; 됾; 됾; 됾; ) HANGUL SYLLABLE DYOLM +B43F;B43F;1103 116D 11B2;B43F;1103 116D 11B2; # (됿; 됿; 됿; 됿; 됿; ) HANGUL SYLLABLE DYOLB +B440;B440;1103 116D 11B3;B440;1103 116D 11B3; # (둀; 둀; 둀; 둀; 둀; ) HANGUL SYLLABLE DYOLS +B441;B441;1103 116D 11B4;B441;1103 116D 11B4; # (둁; 둁; 둁; 둁; 둁; ) HANGUL SYLLABLE DYOLT +B442;B442;1103 116D 11B5;B442;1103 116D 11B5; # (둂; 둂; 둂; 둂; 둂; ) HANGUL SYLLABLE DYOLP +B443;B443;1103 116D 11B6;B443;1103 116D 11B6; # (둃; 둃; 둃; 둃; 둃; ) HANGUL SYLLABLE DYOLH +B444;B444;1103 116D 11B7;B444;1103 116D 11B7; # (둄; 둄; 둄; 둄; 둄; ) HANGUL SYLLABLE DYOM +B445;B445;1103 116D 11B8;B445;1103 116D 11B8; # (둅; 둅; 둅; 둅; 둅; ) HANGUL SYLLABLE DYOB +B446;B446;1103 116D 11B9;B446;1103 116D 11B9; # (둆; 둆; 둆; 둆; 둆; ) HANGUL SYLLABLE DYOBS +B447;B447;1103 116D 11BA;B447;1103 116D 11BA; # (둇; 둇; 둇; 둇; 둇; ) HANGUL SYLLABLE DYOS +B448;B448;1103 116D 11BB;B448;1103 116D 11BB; # (둈; 둈; 둈; 둈; 둈; ) HANGUL SYLLABLE DYOSS +B449;B449;1103 116D 11BC;B449;1103 116D 11BC; # (둉; 둉; 둉; 둉; 둉; ) HANGUL SYLLABLE DYONG +B44A;B44A;1103 116D 11BD;B44A;1103 116D 11BD; # (둊; 둊; 둊; 둊; 둊; ) HANGUL SYLLABLE DYOJ +B44B;B44B;1103 116D 11BE;B44B;1103 116D 11BE; # (둋; 둋; 둋; 둋; 둋; ) HANGUL SYLLABLE DYOC +B44C;B44C;1103 116D 11BF;B44C;1103 116D 11BF; # (둌; 둌; 둌; 둌; 둌; ) HANGUL SYLLABLE DYOK +B44D;B44D;1103 116D 11C0;B44D;1103 116D 11C0; # (둍; 둍; 둍; 둍; 둍; ) HANGUL SYLLABLE DYOT +B44E;B44E;1103 116D 11C1;B44E;1103 116D 11C1; # (둎; 둎; 둎; 둎; 둎; ) HANGUL SYLLABLE DYOP +B44F;B44F;1103 116D 11C2;B44F;1103 116D 11C2; # (둏; 둏; 둏; 둏; 둏; ) HANGUL SYLLABLE DYOH +B450;B450;1103 116E;B450;1103 116E; # (두; 두; 두; 두; 두; ) HANGUL SYLLABLE DU +B451;B451;1103 116E 11A8;B451;1103 116E 11A8; # (둑; 둑; 둑; 둑; 둑; ) HANGUL SYLLABLE DUG +B452;B452;1103 116E 11A9;B452;1103 116E 11A9; # (둒; 둒; 둒; 둒; 둒; ) HANGUL SYLLABLE DUGG +B453;B453;1103 116E 11AA;B453;1103 116E 11AA; # (둓; 둓; 둓; 둓; 둓; ) HANGUL SYLLABLE DUGS +B454;B454;1103 116E 11AB;B454;1103 116E 11AB; # (둔; 둔; 둔; 둔; 둔; ) HANGUL SYLLABLE DUN +B455;B455;1103 116E 11AC;B455;1103 116E 11AC; # (둕; 둕; 둕; 둕; 둕; ) HANGUL SYLLABLE DUNJ +B456;B456;1103 116E 11AD;B456;1103 116E 11AD; # (둖; 둖; 둖; 둖; 둖; ) HANGUL SYLLABLE DUNH +B457;B457;1103 116E 11AE;B457;1103 116E 11AE; # (둗; 둗; 둗; 둗; 둗; ) HANGUL SYLLABLE DUD +B458;B458;1103 116E 11AF;B458;1103 116E 11AF; # (둘; 둘; 둘; 둘; 둘; ) HANGUL SYLLABLE DUL +B459;B459;1103 116E 11B0;B459;1103 116E 11B0; # (둙; 둙; 둙; 둙; 둙; ) HANGUL SYLLABLE DULG +B45A;B45A;1103 116E 11B1;B45A;1103 116E 11B1; # (둚; 둚; 둚; 둚; 둚; ) HANGUL SYLLABLE DULM +B45B;B45B;1103 116E 11B2;B45B;1103 116E 11B2; # (둛; 둛; 둛; 둛; 둛; ) HANGUL SYLLABLE DULB +B45C;B45C;1103 116E 11B3;B45C;1103 116E 11B3; # (둜; 둜; 둜; 둜; 둜; ) HANGUL SYLLABLE DULS +B45D;B45D;1103 116E 11B4;B45D;1103 116E 11B4; # (둝; 둝; 둝; 둝; 둝; ) HANGUL SYLLABLE DULT +B45E;B45E;1103 116E 11B5;B45E;1103 116E 11B5; # (둞; 둞; 둞; 둞; 둞; ) HANGUL SYLLABLE DULP +B45F;B45F;1103 116E 11B6;B45F;1103 116E 11B6; # (둟; 둟; 둟; 둟; 둟; ) HANGUL SYLLABLE DULH +B460;B460;1103 116E 11B7;B460;1103 116E 11B7; # (둠; 둠; 둠; 둠; 둠; ) HANGUL SYLLABLE DUM +B461;B461;1103 116E 11B8;B461;1103 116E 11B8; # (둡; 둡; 둡; 둡; 둡; ) HANGUL SYLLABLE DUB +B462;B462;1103 116E 11B9;B462;1103 116E 11B9; # (둢; 둢; 둢; 둢; 둢; ) HANGUL SYLLABLE DUBS +B463;B463;1103 116E 11BA;B463;1103 116E 11BA; # (둣; 둣; 둣; 둣; 둣; ) HANGUL SYLLABLE DUS +B464;B464;1103 116E 11BB;B464;1103 116E 11BB; # (둤; 둤; 둤; 둤; 둤; ) HANGUL SYLLABLE DUSS +B465;B465;1103 116E 11BC;B465;1103 116E 11BC; # (둥; 둥; 둥; 둥; 둥; ) HANGUL SYLLABLE DUNG +B466;B466;1103 116E 11BD;B466;1103 116E 11BD; # (둦; 둦; 둦; 둦; 둦; ) HANGUL SYLLABLE DUJ +B467;B467;1103 116E 11BE;B467;1103 116E 11BE; # (둧; 둧; 둧; 둧; 둧; ) HANGUL SYLLABLE DUC +B468;B468;1103 116E 11BF;B468;1103 116E 11BF; # (둨; 둨; 둨; 둨; 둨; ) HANGUL SYLLABLE DUK +B469;B469;1103 116E 11C0;B469;1103 116E 11C0; # (둩; 둩; 둩; 둩; 둩; ) HANGUL SYLLABLE DUT +B46A;B46A;1103 116E 11C1;B46A;1103 116E 11C1; # (둪; 둪; 둪; 둪; 둪; ) HANGUL SYLLABLE DUP +B46B;B46B;1103 116E 11C2;B46B;1103 116E 11C2; # (둫; 둫; 둫; 둫; 둫; ) HANGUL SYLLABLE DUH +B46C;B46C;1103 116F;B46C;1103 116F; # (둬; 둬; 둬; 둬; 둬; ) HANGUL SYLLABLE DWEO +B46D;B46D;1103 116F 11A8;B46D;1103 116F 11A8; # (둭; 둭; 둭; 둭; 둭; ) HANGUL SYLLABLE DWEOG +B46E;B46E;1103 116F 11A9;B46E;1103 116F 11A9; # (둮; 둮; 둮; 둮; 둮; ) HANGUL SYLLABLE DWEOGG +B46F;B46F;1103 116F 11AA;B46F;1103 116F 11AA; # (둯; 둯; 둯; 둯; 둯; ) HANGUL SYLLABLE DWEOGS +B470;B470;1103 116F 11AB;B470;1103 116F 11AB; # (둰; 둰; 둰; 둰; 둰; ) HANGUL SYLLABLE DWEON +B471;B471;1103 116F 11AC;B471;1103 116F 11AC; # (둱; 둱; 둱; 둱; 둱; ) HANGUL SYLLABLE DWEONJ +B472;B472;1103 116F 11AD;B472;1103 116F 11AD; # (둲; 둲; 둲; 둲; 둲; ) HANGUL SYLLABLE DWEONH +B473;B473;1103 116F 11AE;B473;1103 116F 11AE; # (둳; 둳; 둳; 둳; 둳; ) HANGUL SYLLABLE DWEOD +B474;B474;1103 116F 11AF;B474;1103 116F 11AF; # (둴; 둴; 둴; 둴; 둴; ) HANGUL SYLLABLE DWEOL +B475;B475;1103 116F 11B0;B475;1103 116F 11B0; # (둵; 둵; 둵; 둵; 둵; ) HANGUL SYLLABLE DWEOLG +B476;B476;1103 116F 11B1;B476;1103 116F 11B1; # (둶; 둶; 둶; 둶; 둶; ) HANGUL SYLLABLE DWEOLM +B477;B477;1103 116F 11B2;B477;1103 116F 11B2; # (둷; 둷; 둷; 둷; 둷; ) HANGUL SYLLABLE DWEOLB +B478;B478;1103 116F 11B3;B478;1103 116F 11B3; # (둸; 둸; 둸; 둸; 둸; ) HANGUL SYLLABLE DWEOLS +B479;B479;1103 116F 11B4;B479;1103 116F 11B4; # (둹; 둹; 둹; 둹; 둹; ) HANGUL SYLLABLE DWEOLT +B47A;B47A;1103 116F 11B5;B47A;1103 116F 11B5; # (둺; 둺; 둺; 둺; 둺; ) HANGUL SYLLABLE DWEOLP +B47B;B47B;1103 116F 11B6;B47B;1103 116F 11B6; # (둻; 둻; 둻; 둻; 둻; ) HANGUL SYLLABLE DWEOLH +B47C;B47C;1103 116F 11B7;B47C;1103 116F 11B7; # (둼; 둼; 둼; 둼; 둼; ) HANGUL SYLLABLE DWEOM +B47D;B47D;1103 116F 11B8;B47D;1103 116F 11B8; # (둽; 둽; 둽; 둽; 둽; ) HANGUL SYLLABLE DWEOB +B47E;B47E;1103 116F 11B9;B47E;1103 116F 11B9; # (둾; 둾; 둾; 둾; 둾; ) HANGUL SYLLABLE DWEOBS +B47F;B47F;1103 116F 11BA;B47F;1103 116F 11BA; # (둿; 둿; 둿; 둿; 둿; ) HANGUL SYLLABLE DWEOS +B480;B480;1103 116F 11BB;B480;1103 116F 11BB; # (뒀; 뒀; 뒀; 뒀; 뒀; ) HANGUL SYLLABLE DWEOSS +B481;B481;1103 116F 11BC;B481;1103 116F 11BC; # (뒁; 뒁; 뒁; 뒁; 뒁; ) HANGUL SYLLABLE DWEONG +B482;B482;1103 116F 11BD;B482;1103 116F 11BD; # (뒂; 뒂; 뒂; 뒂; 뒂; ) HANGUL SYLLABLE DWEOJ +B483;B483;1103 116F 11BE;B483;1103 116F 11BE; # (뒃; 뒃; 뒃; 뒃; 뒃; ) HANGUL SYLLABLE DWEOC +B484;B484;1103 116F 11BF;B484;1103 116F 11BF; # (뒄; 뒄; 뒄; 뒄; 뒄; ) HANGUL SYLLABLE DWEOK +B485;B485;1103 116F 11C0;B485;1103 116F 11C0; # (뒅; 뒅; 뒅; 뒅; 뒅; ) HANGUL SYLLABLE DWEOT +B486;B486;1103 116F 11C1;B486;1103 116F 11C1; # (뒆; 뒆; 뒆; 뒆; 뒆; ) HANGUL SYLLABLE DWEOP +B487;B487;1103 116F 11C2;B487;1103 116F 11C2; # (뒇; 뒇; 뒇; 뒇; 뒇; ) HANGUL SYLLABLE DWEOH +B488;B488;1103 1170;B488;1103 1170; # (뒈; 뒈; 뒈; 뒈; 뒈; ) HANGUL SYLLABLE DWE +B489;B489;1103 1170 11A8;B489;1103 1170 11A8; # (뒉; 뒉; 뒉; 뒉; 뒉; ) HANGUL SYLLABLE DWEG +B48A;B48A;1103 1170 11A9;B48A;1103 1170 11A9; # (뒊; 뒊; 뒊; 뒊; 뒊; ) HANGUL SYLLABLE DWEGG +B48B;B48B;1103 1170 11AA;B48B;1103 1170 11AA; # (뒋; 뒋; 뒋; 뒋; 뒋; ) HANGUL SYLLABLE DWEGS +B48C;B48C;1103 1170 11AB;B48C;1103 1170 11AB; # (뒌; 뒌; 뒌; 뒌; 뒌; ) HANGUL SYLLABLE DWEN +B48D;B48D;1103 1170 11AC;B48D;1103 1170 11AC; # (뒍; 뒍; 뒍; 뒍; 뒍; ) HANGUL SYLLABLE DWENJ +B48E;B48E;1103 1170 11AD;B48E;1103 1170 11AD; # (뒎; 뒎; 뒎; 뒎; 뒎; ) HANGUL SYLLABLE DWENH +B48F;B48F;1103 1170 11AE;B48F;1103 1170 11AE; # (뒏; 뒏; 뒏; 뒏; 뒏; ) HANGUL SYLLABLE DWED +B490;B490;1103 1170 11AF;B490;1103 1170 11AF; # (뒐; 뒐; 뒐; 뒐; 뒐; ) HANGUL SYLLABLE DWEL +B491;B491;1103 1170 11B0;B491;1103 1170 11B0; # (뒑; 뒑; 뒑; 뒑; 뒑; ) HANGUL SYLLABLE DWELG +B492;B492;1103 1170 11B1;B492;1103 1170 11B1; # (뒒; 뒒; 뒒; 뒒; 뒒; ) HANGUL SYLLABLE DWELM +B493;B493;1103 1170 11B2;B493;1103 1170 11B2; # (뒓; 뒓; 뒓; 뒓; 뒓; ) HANGUL SYLLABLE DWELB +B494;B494;1103 1170 11B3;B494;1103 1170 11B3; # (뒔; 뒔; 뒔; 뒔; 뒔; ) HANGUL SYLLABLE DWELS +B495;B495;1103 1170 11B4;B495;1103 1170 11B4; # (뒕; 뒕; 뒕; 뒕; 뒕; ) HANGUL SYLLABLE DWELT +B496;B496;1103 1170 11B5;B496;1103 1170 11B5; # (뒖; 뒖; 뒖; 뒖; 뒖; ) HANGUL SYLLABLE DWELP +B497;B497;1103 1170 11B6;B497;1103 1170 11B6; # (뒗; 뒗; 뒗; 뒗; 뒗; ) HANGUL SYLLABLE DWELH +B498;B498;1103 1170 11B7;B498;1103 1170 11B7; # (뒘; 뒘; 뒘; 뒘; 뒘; ) HANGUL SYLLABLE DWEM +B499;B499;1103 1170 11B8;B499;1103 1170 11B8; # (뒙; 뒙; 뒙; 뒙; 뒙; ) HANGUL SYLLABLE DWEB +B49A;B49A;1103 1170 11B9;B49A;1103 1170 11B9; # (뒚; 뒚; 뒚; 뒚; 뒚; ) HANGUL SYLLABLE DWEBS +B49B;B49B;1103 1170 11BA;B49B;1103 1170 11BA; # (뒛; 뒛; 뒛; 뒛; 뒛; ) HANGUL SYLLABLE DWES +B49C;B49C;1103 1170 11BB;B49C;1103 1170 11BB; # (뒜; 뒜; 뒜; 뒜; 뒜; ) HANGUL SYLLABLE DWESS +B49D;B49D;1103 1170 11BC;B49D;1103 1170 11BC; # (뒝; 뒝; 뒝; 뒝; 뒝; ) HANGUL SYLLABLE DWENG +B49E;B49E;1103 1170 11BD;B49E;1103 1170 11BD; # (뒞; 뒞; 뒞; 뒞; 뒞; ) HANGUL SYLLABLE DWEJ +B49F;B49F;1103 1170 11BE;B49F;1103 1170 11BE; # (뒟; 뒟; 뒟; 뒟; 뒟; ) HANGUL SYLLABLE DWEC +B4A0;B4A0;1103 1170 11BF;B4A0;1103 1170 11BF; # (뒠; 뒠; 뒠; 뒠; 뒠; ) HANGUL SYLLABLE DWEK +B4A1;B4A1;1103 1170 11C0;B4A1;1103 1170 11C0; # (뒡; 뒡; 뒡; 뒡; 뒡; ) HANGUL SYLLABLE DWET +B4A2;B4A2;1103 1170 11C1;B4A2;1103 1170 11C1; # (뒢; 뒢; 뒢; 뒢; 뒢; ) HANGUL SYLLABLE DWEP +B4A3;B4A3;1103 1170 11C2;B4A3;1103 1170 11C2; # (뒣; 뒣; 뒣; 뒣; 뒣; ) HANGUL SYLLABLE DWEH +B4A4;B4A4;1103 1171;B4A4;1103 1171; # (뒤; 뒤; 뒤; 뒤; 뒤; ) HANGUL SYLLABLE DWI +B4A5;B4A5;1103 1171 11A8;B4A5;1103 1171 11A8; # (뒥; 뒥; 뒥; 뒥; 뒥; ) HANGUL SYLLABLE DWIG +B4A6;B4A6;1103 1171 11A9;B4A6;1103 1171 11A9; # (뒦; 뒦; 뒦; 뒦; 뒦; ) HANGUL SYLLABLE DWIGG +B4A7;B4A7;1103 1171 11AA;B4A7;1103 1171 11AA; # (뒧; 뒧; 뒧; 뒧; 뒧; ) HANGUL SYLLABLE DWIGS +B4A8;B4A8;1103 1171 11AB;B4A8;1103 1171 11AB; # (뒨; 뒨; 뒨; 뒨; 뒨; ) HANGUL SYLLABLE DWIN +B4A9;B4A9;1103 1171 11AC;B4A9;1103 1171 11AC; # (뒩; 뒩; 뒩; 뒩; 뒩; ) HANGUL SYLLABLE DWINJ +B4AA;B4AA;1103 1171 11AD;B4AA;1103 1171 11AD; # (뒪; 뒪; 뒪; 뒪; 뒪; ) HANGUL SYLLABLE DWINH +B4AB;B4AB;1103 1171 11AE;B4AB;1103 1171 11AE; # (뒫; 뒫; 뒫; 뒫; 뒫; ) HANGUL SYLLABLE DWID +B4AC;B4AC;1103 1171 11AF;B4AC;1103 1171 11AF; # (뒬; 뒬; 뒬; 뒬; 뒬; ) HANGUL SYLLABLE DWIL +B4AD;B4AD;1103 1171 11B0;B4AD;1103 1171 11B0; # (뒭; 뒭; 뒭; 뒭; 뒭; ) HANGUL SYLLABLE DWILG +B4AE;B4AE;1103 1171 11B1;B4AE;1103 1171 11B1; # (뒮; 뒮; 뒮; 뒮; 뒮; ) HANGUL SYLLABLE DWILM +B4AF;B4AF;1103 1171 11B2;B4AF;1103 1171 11B2; # (뒯; 뒯; 뒯; 뒯; 뒯; ) HANGUL SYLLABLE DWILB +B4B0;B4B0;1103 1171 11B3;B4B0;1103 1171 11B3; # (뒰; 뒰; 뒰; 뒰; 뒰; ) HANGUL SYLLABLE DWILS +B4B1;B4B1;1103 1171 11B4;B4B1;1103 1171 11B4; # (뒱; 뒱; 뒱; 뒱; 뒱; ) HANGUL SYLLABLE DWILT +B4B2;B4B2;1103 1171 11B5;B4B2;1103 1171 11B5; # (뒲; 뒲; 뒲; 뒲; 뒲; ) HANGUL SYLLABLE DWILP +B4B3;B4B3;1103 1171 11B6;B4B3;1103 1171 11B6; # (뒳; 뒳; 뒳; 뒳; 뒳; ) HANGUL SYLLABLE DWILH +B4B4;B4B4;1103 1171 11B7;B4B4;1103 1171 11B7; # (뒴; 뒴; 뒴; 뒴; 뒴; ) HANGUL SYLLABLE DWIM +B4B5;B4B5;1103 1171 11B8;B4B5;1103 1171 11B8; # (뒵; 뒵; 뒵; 뒵; 뒵; ) HANGUL SYLLABLE DWIB +B4B6;B4B6;1103 1171 11B9;B4B6;1103 1171 11B9; # (뒶; 뒶; 뒶; 뒶; 뒶; ) HANGUL SYLLABLE DWIBS +B4B7;B4B7;1103 1171 11BA;B4B7;1103 1171 11BA; # (뒷; 뒷; 뒷; 뒷; 뒷; ) HANGUL SYLLABLE DWIS +B4B8;B4B8;1103 1171 11BB;B4B8;1103 1171 11BB; # (뒸; 뒸; 뒸; 뒸; 뒸; ) HANGUL SYLLABLE DWISS +B4B9;B4B9;1103 1171 11BC;B4B9;1103 1171 11BC; # (뒹; 뒹; 뒹; 뒹; 뒹; ) HANGUL SYLLABLE DWING +B4BA;B4BA;1103 1171 11BD;B4BA;1103 1171 11BD; # (뒺; 뒺; 뒺; 뒺; 뒺; ) HANGUL SYLLABLE DWIJ +B4BB;B4BB;1103 1171 11BE;B4BB;1103 1171 11BE; # (뒻; 뒻; 뒻; 뒻; 뒻; ) HANGUL SYLLABLE DWIC +B4BC;B4BC;1103 1171 11BF;B4BC;1103 1171 11BF; # (뒼; 뒼; 뒼; 뒼; 뒼; ) HANGUL SYLLABLE DWIK +B4BD;B4BD;1103 1171 11C0;B4BD;1103 1171 11C0; # (뒽; 뒽; 뒽; 뒽; 뒽; ) HANGUL SYLLABLE DWIT +B4BE;B4BE;1103 1171 11C1;B4BE;1103 1171 11C1; # (뒾; 뒾; 뒾; 뒾; 뒾; ) HANGUL SYLLABLE DWIP +B4BF;B4BF;1103 1171 11C2;B4BF;1103 1171 11C2; # (뒿; 뒿; 뒿; 뒿; 뒿; ) HANGUL SYLLABLE DWIH +B4C0;B4C0;1103 1172;B4C0;1103 1172; # (듀; 듀; 듀; 듀; 듀; ) HANGUL SYLLABLE DYU +B4C1;B4C1;1103 1172 11A8;B4C1;1103 1172 11A8; # (듁; 듁; 듁; 듁; 듁; ) HANGUL SYLLABLE DYUG +B4C2;B4C2;1103 1172 11A9;B4C2;1103 1172 11A9; # (듂; 듂; 듂; 듂; 듂; ) HANGUL SYLLABLE DYUGG +B4C3;B4C3;1103 1172 11AA;B4C3;1103 1172 11AA; # (듃; 듃; 듃; 듃; 듃; ) HANGUL SYLLABLE DYUGS +B4C4;B4C4;1103 1172 11AB;B4C4;1103 1172 11AB; # (듄; 듄; 듄; 듄; 듄; ) HANGUL SYLLABLE DYUN +B4C5;B4C5;1103 1172 11AC;B4C5;1103 1172 11AC; # (듅; 듅; 듅; 듅; 듅; ) HANGUL SYLLABLE DYUNJ +B4C6;B4C6;1103 1172 11AD;B4C6;1103 1172 11AD; # (듆; 듆; 듆; 듆; 듆; ) HANGUL SYLLABLE DYUNH +B4C7;B4C7;1103 1172 11AE;B4C7;1103 1172 11AE; # (듇; 듇; 듇; 듇; 듇; ) HANGUL SYLLABLE DYUD +B4C8;B4C8;1103 1172 11AF;B4C8;1103 1172 11AF; # (듈; 듈; 듈; 듈; 듈; ) HANGUL SYLLABLE DYUL +B4C9;B4C9;1103 1172 11B0;B4C9;1103 1172 11B0; # (듉; 듉; 듉; 듉; 듉; ) HANGUL SYLLABLE DYULG +B4CA;B4CA;1103 1172 11B1;B4CA;1103 1172 11B1; # (듊; 듊; 듊; 듊; 듊; ) HANGUL SYLLABLE DYULM +B4CB;B4CB;1103 1172 11B2;B4CB;1103 1172 11B2; # (듋; 듋; 듋; 듋; 듋; ) HANGUL SYLLABLE DYULB +B4CC;B4CC;1103 1172 11B3;B4CC;1103 1172 11B3; # (듌; 듌; 듌; 듌; 듌; ) HANGUL SYLLABLE DYULS +B4CD;B4CD;1103 1172 11B4;B4CD;1103 1172 11B4; # (듍; 듍; 듍; 듍; 듍; ) HANGUL SYLLABLE DYULT +B4CE;B4CE;1103 1172 11B5;B4CE;1103 1172 11B5; # (듎; 듎; 듎; 듎; 듎; ) HANGUL SYLLABLE DYULP +B4CF;B4CF;1103 1172 11B6;B4CF;1103 1172 11B6; # (듏; 듏; 듏; 듏; 듏; ) HANGUL SYLLABLE DYULH +B4D0;B4D0;1103 1172 11B7;B4D0;1103 1172 11B7; # (듐; 듐; 듐; 듐; 듐; ) HANGUL SYLLABLE DYUM +B4D1;B4D1;1103 1172 11B8;B4D1;1103 1172 11B8; # (듑; 듑; 듑; 듑; 듑; ) HANGUL SYLLABLE DYUB +B4D2;B4D2;1103 1172 11B9;B4D2;1103 1172 11B9; # (듒; 듒; 듒; 듒; 듒; ) HANGUL SYLLABLE DYUBS +B4D3;B4D3;1103 1172 11BA;B4D3;1103 1172 11BA; # (듓; 듓; 듓; 듓; 듓; ) HANGUL SYLLABLE DYUS +B4D4;B4D4;1103 1172 11BB;B4D4;1103 1172 11BB; # (듔; 듔; 듔; 듔; 듔; ) HANGUL SYLLABLE DYUSS +B4D5;B4D5;1103 1172 11BC;B4D5;1103 1172 11BC; # (듕; 듕; 듕; 듕; 듕; ) HANGUL SYLLABLE DYUNG +B4D6;B4D6;1103 1172 11BD;B4D6;1103 1172 11BD; # (듖; 듖; 듖; 듖; 듖; ) HANGUL SYLLABLE DYUJ +B4D7;B4D7;1103 1172 11BE;B4D7;1103 1172 11BE; # (듗; 듗; 듗; 듗; 듗; ) HANGUL SYLLABLE DYUC +B4D8;B4D8;1103 1172 11BF;B4D8;1103 1172 11BF; # (듘; 듘; 듘; 듘; 듘; ) HANGUL SYLLABLE DYUK +B4D9;B4D9;1103 1172 11C0;B4D9;1103 1172 11C0; # (듙; 듙; 듙; 듙; 듙; ) HANGUL SYLLABLE DYUT +B4DA;B4DA;1103 1172 11C1;B4DA;1103 1172 11C1; # (듚; 듚; 듚; 듚; 듚; ) HANGUL SYLLABLE DYUP +B4DB;B4DB;1103 1172 11C2;B4DB;1103 1172 11C2; # (듛; 듛; 듛; 듛; 듛; ) HANGUL SYLLABLE DYUH +B4DC;B4DC;1103 1173;B4DC;1103 1173; # (드; 드; 드; 드; 드; ) HANGUL SYLLABLE DEU +B4DD;B4DD;1103 1173 11A8;B4DD;1103 1173 11A8; # (득; 득; 득; 득; 득; ) HANGUL SYLLABLE DEUG +B4DE;B4DE;1103 1173 11A9;B4DE;1103 1173 11A9; # (듞; 듞; 듞; 듞; 듞; ) HANGUL SYLLABLE DEUGG +B4DF;B4DF;1103 1173 11AA;B4DF;1103 1173 11AA; # (듟; 듟; 듟; 듟; 듟; ) HANGUL SYLLABLE DEUGS +B4E0;B4E0;1103 1173 11AB;B4E0;1103 1173 11AB; # (든; 든; 든; 든; 든; ) HANGUL SYLLABLE DEUN +B4E1;B4E1;1103 1173 11AC;B4E1;1103 1173 11AC; # (듡; 듡; 듡; 듡; 듡; ) HANGUL SYLLABLE DEUNJ +B4E2;B4E2;1103 1173 11AD;B4E2;1103 1173 11AD; # (듢; 듢; 듢; 듢; 듢; ) HANGUL SYLLABLE DEUNH +B4E3;B4E3;1103 1173 11AE;B4E3;1103 1173 11AE; # (듣; 듣; 듣; 듣; 듣; ) HANGUL SYLLABLE DEUD +B4E4;B4E4;1103 1173 11AF;B4E4;1103 1173 11AF; # (들; 들; 들; 들; 들; ) HANGUL SYLLABLE DEUL +B4E5;B4E5;1103 1173 11B0;B4E5;1103 1173 11B0; # (듥; 듥; 듥; 듥; 듥; ) HANGUL SYLLABLE DEULG +B4E6;B4E6;1103 1173 11B1;B4E6;1103 1173 11B1; # (듦; 듦; 듦; 듦; 듦; ) HANGUL SYLLABLE DEULM +B4E7;B4E7;1103 1173 11B2;B4E7;1103 1173 11B2; # (듧; 듧; 듧; 듧; 듧; ) HANGUL SYLLABLE DEULB +B4E8;B4E8;1103 1173 11B3;B4E8;1103 1173 11B3; # (듨; 듨; 듨; 듨; 듨; ) HANGUL SYLLABLE DEULS +B4E9;B4E9;1103 1173 11B4;B4E9;1103 1173 11B4; # (듩; 듩; 듩; 듩; 듩; ) HANGUL SYLLABLE DEULT +B4EA;B4EA;1103 1173 11B5;B4EA;1103 1173 11B5; # (듪; 듪; 듪; 듪; 듪; ) HANGUL SYLLABLE DEULP +B4EB;B4EB;1103 1173 11B6;B4EB;1103 1173 11B6; # (듫; 듫; 듫; 듫; 듫; ) HANGUL SYLLABLE DEULH +B4EC;B4EC;1103 1173 11B7;B4EC;1103 1173 11B7; # (듬; 듬; 듬; 듬; 듬; ) HANGUL SYLLABLE DEUM +B4ED;B4ED;1103 1173 11B8;B4ED;1103 1173 11B8; # (듭; 듭; 듭; 듭; 듭; ) HANGUL SYLLABLE DEUB +B4EE;B4EE;1103 1173 11B9;B4EE;1103 1173 11B9; # (듮; 듮; 듮; 듮; 듮; ) HANGUL SYLLABLE DEUBS +B4EF;B4EF;1103 1173 11BA;B4EF;1103 1173 11BA; # (듯; 듯; 듯; 듯; 듯; ) HANGUL SYLLABLE DEUS +B4F0;B4F0;1103 1173 11BB;B4F0;1103 1173 11BB; # (듰; 듰; 듰; 듰; 듰; ) HANGUL SYLLABLE DEUSS +B4F1;B4F1;1103 1173 11BC;B4F1;1103 1173 11BC; # (등; 등; 등; 등; 등; ) HANGUL SYLLABLE DEUNG +B4F2;B4F2;1103 1173 11BD;B4F2;1103 1173 11BD; # (듲; 듲; 듲; 듲; 듲; ) HANGUL SYLLABLE DEUJ +B4F3;B4F3;1103 1173 11BE;B4F3;1103 1173 11BE; # (듳; 듳; 듳; 듳; 듳; ) HANGUL SYLLABLE DEUC +B4F4;B4F4;1103 1173 11BF;B4F4;1103 1173 11BF; # (듴; 듴; 듴; 듴; 듴; ) HANGUL SYLLABLE DEUK +B4F5;B4F5;1103 1173 11C0;B4F5;1103 1173 11C0; # (듵; 듵; 듵; 듵; 듵; ) HANGUL SYLLABLE DEUT +B4F6;B4F6;1103 1173 11C1;B4F6;1103 1173 11C1; # (듶; 듶; 듶; 듶; 듶; ) HANGUL SYLLABLE DEUP +B4F7;B4F7;1103 1173 11C2;B4F7;1103 1173 11C2; # (듷; 듷; 듷; 듷; 듷; ) HANGUL SYLLABLE DEUH +B4F8;B4F8;1103 1174;B4F8;1103 1174; # (듸; 듸; 듸; 듸; 듸; ) HANGUL SYLLABLE DYI +B4F9;B4F9;1103 1174 11A8;B4F9;1103 1174 11A8; # (듹; 듹; 듹; 듹; 듹; ) HANGUL SYLLABLE DYIG +B4FA;B4FA;1103 1174 11A9;B4FA;1103 1174 11A9; # (듺; 듺; 듺; 듺; 듺; ) HANGUL SYLLABLE DYIGG +B4FB;B4FB;1103 1174 11AA;B4FB;1103 1174 11AA; # (듻; 듻; 듻; 듻; 듻; ) HANGUL SYLLABLE DYIGS +B4FC;B4FC;1103 1174 11AB;B4FC;1103 1174 11AB; # (듼; 듼; 듼; 듼; 듼; ) HANGUL SYLLABLE DYIN +B4FD;B4FD;1103 1174 11AC;B4FD;1103 1174 11AC; # (듽; 듽; 듽; 듽; 듽; ) HANGUL SYLLABLE DYINJ +B4FE;B4FE;1103 1174 11AD;B4FE;1103 1174 11AD; # (듾; 듾; 듾; 듾; 듾; ) HANGUL SYLLABLE DYINH +B4FF;B4FF;1103 1174 11AE;B4FF;1103 1174 11AE; # (듿; 듿; 듿; 듿; 듿; ) HANGUL SYLLABLE DYID +B500;B500;1103 1174 11AF;B500;1103 1174 11AF; # (딀; 딀; 딀; 딀; 딀; ) HANGUL SYLLABLE DYIL +B501;B501;1103 1174 11B0;B501;1103 1174 11B0; # (딁; 딁; 딁; 딁; 딁; ) HANGUL SYLLABLE DYILG +B502;B502;1103 1174 11B1;B502;1103 1174 11B1; # (딂; 딂; 딂; 딂; 딂; ) HANGUL SYLLABLE DYILM +B503;B503;1103 1174 11B2;B503;1103 1174 11B2; # (딃; 딃; 딃; 딃; 딃; ) HANGUL SYLLABLE DYILB +B504;B504;1103 1174 11B3;B504;1103 1174 11B3; # (딄; 딄; 딄; 딄; 딄; ) HANGUL SYLLABLE DYILS +B505;B505;1103 1174 11B4;B505;1103 1174 11B4; # (딅; 딅; 딅; 딅; 딅; ) HANGUL SYLLABLE DYILT +B506;B506;1103 1174 11B5;B506;1103 1174 11B5; # (딆; 딆; 딆; 딆; 딆; ) HANGUL SYLLABLE DYILP +B507;B507;1103 1174 11B6;B507;1103 1174 11B6; # (딇; 딇; 딇; 딇; 딇; ) HANGUL SYLLABLE DYILH +B508;B508;1103 1174 11B7;B508;1103 1174 11B7; # (딈; 딈; 딈; 딈; 딈; ) HANGUL SYLLABLE DYIM +B509;B509;1103 1174 11B8;B509;1103 1174 11B8; # (딉; 딉; 딉; 딉; 딉; ) HANGUL SYLLABLE DYIB +B50A;B50A;1103 1174 11B9;B50A;1103 1174 11B9; # (딊; 딊; 딊; 딊; 딊; ) HANGUL SYLLABLE DYIBS +B50B;B50B;1103 1174 11BA;B50B;1103 1174 11BA; # (딋; 딋; 딋; 딋; 딋; ) HANGUL SYLLABLE DYIS +B50C;B50C;1103 1174 11BB;B50C;1103 1174 11BB; # (딌; 딌; 딌; 딌; 딌; ) HANGUL SYLLABLE DYISS +B50D;B50D;1103 1174 11BC;B50D;1103 1174 11BC; # (딍; 딍; 딍; 딍; 딍; ) HANGUL SYLLABLE DYING +B50E;B50E;1103 1174 11BD;B50E;1103 1174 11BD; # (딎; 딎; 딎; 딎; 딎; ) HANGUL SYLLABLE DYIJ +B50F;B50F;1103 1174 11BE;B50F;1103 1174 11BE; # (딏; 딏; 딏; 딏; 딏; ) HANGUL SYLLABLE DYIC +B510;B510;1103 1174 11BF;B510;1103 1174 11BF; # (딐; 딐; 딐; 딐; 딐; ) HANGUL SYLLABLE DYIK +B511;B511;1103 1174 11C0;B511;1103 1174 11C0; # (딑; 딑; 딑; 딑; 딑; ) HANGUL SYLLABLE DYIT +B512;B512;1103 1174 11C1;B512;1103 1174 11C1; # (딒; 딒; 딒; 딒; 딒; ) HANGUL SYLLABLE DYIP +B513;B513;1103 1174 11C2;B513;1103 1174 11C2; # (딓; 딓; 딓; 딓; 딓; ) HANGUL SYLLABLE DYIH +B514;B514;1103 1175;B514;1103 1175; # (디; 디; 디; 디; 디; ) HANGUL SYLLABLE DI +B515;B515;1103 1175 11A8;B515;1103 1175 11A8; # (딕; 딕; 딕; 딕; 딕; ) HANGUL SYLLABLE DIG +B516;B516;1103 1175 11A9;B516;1103 1175 11A9; # (딖; 딖; 딖; 딖; 딖; ) HANGUL SYLLABLE DIGG +B517;B517;1103 1175 11AA;B517;1103 1175 11AA; # (딗; 딗; 딗; 딗; 딗; ) HANGUL SYLLABLE DIGS +B518;B518;1103 1175 11AB;B518;1103 1175 11AB; # (딘; 딘; 딘; 딘; 딘; ) HANGUL SYLLABLE DIN +B519;B519;1103 1175 11AC;B519;1103 1175 11AC; # (딙; 딙; 딙; 딙; 딙; ) HANGUL SYLLABLE DINJ +B51A;B51A;1103 1175 11AD;B51A;1103 1175 11AD; # (딚; 딚; 딚; 딚; 딚; ) HANGUL SYLLABLE DINH +B51B;B51B;1103 1175 11AE;B51B;1103 1175 11AE; # (딛; 딛; 딛; 딛; 딛; ) HANGUL SYLLABLE DID +B51C;B51C;1103 1175 11AF;B51C;1103 1175 11AF; # (딜; 딜; 딜; 딜; 딜; ) HANGUL SYLLABLE DIL +B51D;B51D;1103 1175 11B0;B51D;1103 1175 11B0; # (딝; 딝; 딝; 딝; 딝; ) HANGUL SYLLABLE DILG +B51E;B51E;1103 1175 11B1;B51E;1103 1175 11B1; # (딞; 딞; 딞; 딞; 딞; ) HANGUL SYLLABLE DILM +B51F;B51F;1103 1175 11B2;B51F;1103 1175 11B2; # (딟; 딟; 딟; 딟; 딟; ) HANGUL SYLLABLE DILB +B520;B520;1103 1175 11B3;B520;1103 1175 11B3; # (딠; 딠; 딠; 딠; 딠; ) HANGUL SYLLABLE DILS +B521;B521;1103 1175 11B4;B521;1103 1175 11B4; # (딡; 딡; 딡; 딡; 딡; ) HANGUL SYLLABLE DILT +B522;B522;1103 1175 11B5;B522;1103 1175 11B5; # (딢; 딢; 딢; 딢; 딢; ) HANGUL SYLLABLE DILP +B523;B523;1103 1175 11B6;B523;1103 1175 11B6; # (딣; 딣; 딣; 딣; 딣; ) HANGUL SYLLABLE DILH +B524;B524;1103 1175 11B7;B524;1103 1175 11B7; # (딤; 딤; 딤; 딤; 딤; ) HANGUL SYLLABLE DIM +B525;B525;1103 1175 11B8;B525;1103 1175 11B8; # (딥; 딥; 딥; 딥; 딥; ) HANGUL SYLLABLE DIB +B526;B526;1103 1175 11B9;B526;1103 1175 11B9; # (딦; 딦; 딦; 딦; 딦; ) HANGUL SYLLABLE DIBS +B527;B527;1103 1175 11BA;B527;1103 1175 11BA; # (딧; 딧; 딧; 딧; 딧; ) HANGUL SYLLABLE DIS +B528;B528;1103 1175 11BB;B528;1103 1175 11BB; # (딨; 딨; 딨; 딨; 딨; ) HANGUL SYLLABLE DISS +B529;B529;1103 1175 11BC;B529;1103 1175 11BC; # (딩; 딩; 딩; 딩; 딩; ) HANGUL SYLLABLE DING +B52A;B52A;1103 1175 11BD;B52A;1103 1175 11BD; # (딪; 딪; 딪; 딪; 딪; ) HANGUL SYLLABLE DIJ +B52B;B52B;1103 1175 11BE;B52B;1103 1175 11BE; # (딫; 딫; 딫; 딫; 딫; ) HANGUL SYLLABLE DIC +B52C;B52C;1103 1175 11BF;B52C;1103 1175 11BF; # (딬; 딬; 딬; 딬; 딬; ) HANGUL SYLLABLE DIK +B52D;B52D;1103 1175 11C0;B52D;1103 1175 11C0; # (딭; 딭; 딭; 딭; 딭; ) HANGUL SYLLABLE DIT +B52E;B52E;1103 1175 11C1;B52E;1103 1175 11C1; # (딮; 딮; 딮; 딮; 딮; ) HANGUL SYLLABLE DIP +B52F;B52F;1103 1175 11C2;B52F;1103 1175 11C2; # (딯; 딯; 딯; 딯; 딯; ) HANGUL SYLLABLE DIH +B530;B530;1104 1161;B530;1104 1161; # (따; 따; 따; 따; 따; ) HANGUL SYLLABLE DDA +B531;B531;1104 1161 11A8;B531;1104 1161 11A8; # (딱; 딱; 딱; 딱; 딱; ) HANGUL SYLLABLE DDAG +B532;B532;1104 1161 11A9;B532;1104 1161 11A9; # (딲; 딲; 딲; 딲; 딲; ) HANGUL SYLLABLE DDAGG +B533;B533;1104 1161 11AA;B533;1104 1161 11AA; # (딳; 딳; 딳; 딳; 딳; ) HANGUL SYLLABLE DDAGS +B534;B534;1104 1161 11AB;B534;1104 1161 11AB; # (딴; 딴; 딴; 딴; 딴; ) HANGUL SYLLABLE DDAN +B535;B535;1104 1161 11AC;B535;1104 1161 11AC; # (딵; 딵; 딵; 딵; 딵; ) HANGUL SYLLABLE DDANJ +B536;B536;1104 1161 11AD;B536;1104 1161 11AD; # (딶; 딶; 딶; 딶; 딶; ) HANGUL SYLLABLE DDANH +B537;B537;1104 1161 11AE;B537;1104 1161 11AE; # (딷; 딷; 딷; 딷; 딷; ) HANGUL SYLLABLE DDAD +B538;B538;1104 1161 11AF;B538;1104 1161 11AF; # (딸; 딸; 딸; 딸; 딸; ) HANGUL SYLLABLE DDAL +B539;B539;1104 1161 11B0;B539;1104 1161 11B0; # (딹; 딹; 딹; 딹; 딹; ) HANGUL SYLLABLE DDALG +B53A;B53A;1104 1161 11B1;B53A;1104 1161 11B1; # (딺; 딺; 딺; 딺; 딺; ) HANGUL SYLLABLE DDALM +B53B;B53B;1104 1161 11B2;B53B;1104 1161 11B2; # (딻; 딻; 딻; 딻; 딻; ) HANGUL SYLLABLE DDALB +B53C;B53C;1104 1161 11B3;B53C;1104 1161 11B3; # (딼; 딼; 딼; 딼; 딼; ) HANGUL SYLLABLE DDALS +B53D;B53D;1104 1161 11B4;B53D;1104 1161 11B4; # (딽; 딽; 딽; 딽; 딽; ) HANGUL SYLLABLE DDALT +B53E;B53E;1104 1161 11B5;B53E;1104 1161 11B5; # (딾; 딾; 딾; 딾; 딾; ) HANGUL SYLLABLE DDALP +B53F;B53F;1104 1161 11B6;B53F;1104 1161 11B6; # (딿; 딿; 딿; 딿; 딿; ) HANGUL SYLLABLE DDALH +B540;B540;1104 1161 11B7;B540;1104 1161 11B7; # (땀; 땀; 땀; 땀; 땀; ) HANGUL SYLLABLE DDAM +B541;B541;1104 1161 11B8;B541;1104 1161 11B8; # (땁; 땁; 땁; 땁; 땁; ) HANGUL SYLLABLE DDAB +B542;B542;1104 1161 11B9;B542;1104 1161 11B9; # (땂; 땂; 땂; 땂; 땂; ) HANGUL SYLLABLE DDABS +B543;B543;1104 1161 11BA;B543;1104 1161 11BA; # (땃; 땃; 땃; 땃; 땃; ) HANGUL SYLLABLE DDAS +B544;B544;1104 1161 11BB;B544;1104 1161 11BB; # (땄; 땄; 땄; 땄; 땄; ) HANGUL SYLLABLE DDASS +B545;B545;1104 1161 11BC;B545;1104 1161 11BC; # (땅; 땅; 땅; 땅; 땅; ) HANGUL SYLLABLE DDANG +B546;B546;1104 1161 11BD;B546;1104 1161 11BD; # (땆; 땆; 땆; 땆; 땆; ) HANGUL SYLLABLE DDAJ +B547;B547;1104 1161 11BE;B547;1104 1161 11BE; # (땇; 땇; 땇; 땇; 땇; ) HANGUL SYLLABLE DDAC +B548;B548;1104 1161 11BF;B548;1104 1161 11BF; # (땈; 땈; 땈; 땈; 땈; ) HANGUL SYLLABLE DDAK +B549;B549;1104 1161 11C0;B549;1104 1161 11C0; # (땉; 땉; 땉; 땉; 땉; ) HANGUL SYLLABLE DDAT +B54A;B54A;1104 1161 11C1;B54A;1104 1161 11C1; # (땊; 땊; 땊; 땊; 땊; ) HANGUL SYLLABLE DDAP +B54B;B54B;1104 1161 11C2;B54B;1104 1161 11C2; # (땋; 땋; 땋; 땋; 땋; ) HANGUL SYLLABLE DDAH +B54C;B54C;1104 1162;B54C;1104 1162; # (때; 때; 때; 때; 때; ) HANGUL SYLLABLE DDAE +B54D;B54D;1104 1162 11A8;B54D;1104 1162 11A8; # (땍; 땍; 땍; 땍; 땍; ) HANGUL SYLLABLE DDAEG +B54E;B54E;1104 1162 11A9;B54E;1104 1162 11A9; # (땎; 땎; 땎; 땎; 땎; ) HANGUL SYLLABLE DDAEGG +B54F;B54F;1104 1162 11AA;B54F;1104 1162 11AA; # (땏; 땏; 땏; 땏; 땏; ) HANGUL SYLLABLE DDAEGS +B550;B550;1104 1162 11AB;B550;1104 1162 11AB; # (땐; 땐; 땐; 땐; 땐; ) HANGUL SYLLABLE DDAEN +B551;B551;1104 1162 11AC;B551;1104 1162 11AC; # (땑; 땑; 땑; 땑; 땑; ) HANGUL SYLLABLE DDAENJ +B552;B552;1104 1162 11AD;B552;1104 1162 11AD; # (땒; 땒; 땒; 땒; 땒; ) HANGUL SYLLABLE DDAENH +B553;B553;1104 1162 11AE;B553;1104 1162 11AE; # (땓; 땓; 땓; 땓; 땓; ) HANGUL SYLLABLE DDAED +B554;B554;1104 1162 11AF;B554;1104 1162 11AF; # (땔; 땔; 땔; 땔; 땔; ) HANGUL SYLLABLE DDAEL +B555;B555;1104 1162 11B0;B555;1104 1162 11B0; # (땕; 땕; 땕; 땕; 땕; ) HANGUL SYLLABLE DDAELG +B556;B556;1104 1162 11B1;B556;1104 1162 11B1; # (땖; 땖; 땖; 땖; 땖; ) HANGUL SYLLABLE DDAELM +B557;B557;1104 1162 11B2;B557;1104 1162 11B2; # (땗; 땗; 땗; 땗; 땗; ) HANGUL SYLLABLE DDAELB +B558;B558;1104 1162 11B3;B558;1104 1162 11B3; # (땘; 땘; 땘; 땘; 땘; ) HANGUL SYLLABLE DDAELS +B559;B559;1104 1162 11B4;B559;1104 1162 11B4; # (땙; 땙; 땙; 땙; 땙; ) HANGUL SYLLABLE DDAELT +B55A;B55A;1104 1162 11B5;B55A;1104 1162 11B5; # (땚; 땚; 땚; 땚; 땚; ) HANGUL SYLLABLE DDAELP +B55B;B55B;1104 1162 11B6;B55B;1104 1162 11B6; # (땛; 땛; 땛; 땛; 땛; ) HANGUL SYLLABLE DDAELH +B55C;B55C;1104 1162 11B7;B55C;1104 1162 11B7; # (땜; 땜; 땜; 땜; 땜; ) HANGUL SYLLABLE DDAEM +B55D;B55D;1104 1162 11B8;B55D;1104 1162 11B8; # (땝; 땝; 땝; 땝; 땝; ) HANGUL SYLLABLE DDAEB +B55E;B55E;1104 1162 11B9;B55E;1104 1162 11B9; # (땞; 땞; 땞; 땞; 땞; ) HANGUL SYLLABLE DDAEBS +B55F;B55F;1104 1162 11BA;B55F;1104 1162 11BA; # (땟; 땟; 땟; 땟; 땟; ) HANGUL SYLLABLE DDAES +B560;B560;1104 1162 11BB;B560;1104 1162 11BB; # (땠; 땠; 땠; 땠; 땠; ) HANGUL SYLLABLE DDAESS +B561;B561;1104 1162 11BC;B561;1104 1162 11BC; # (땡; 땡; 땡; 땡; 땡; ) HANGUL SYLLABLE DDAENG +B562;B562;1104 1162 11BD;B562;1104 1162 11BD; # (땢; 땢; 땢; 땢; 땢; ) HANGUL SYLLABLE DDAEJ +B563;B563;1104 1162 11BE;B563;1104 1162 11BE; # (땣; 땣; 땣; 땣; 땣; ) HANGUL SYLLABLE DDAEC +B564;B564;1104 1162 11BF;B564;1104 1162 11BF; # (땤; 땤; 땤; 땤; 땤; ) HANGUL SYLLABLE DDAEK +B565;B565;1104 1162 11C0;B565;1104 1162 11C0; # (땥; 땥; 땥; 땥; 땥; ) HANGUL SYLLABLE DDAET +B566;B566;1104 1162 11C1;B566;1104 1162 11C1; # (땦; 땦; 땦; 땦; 땦; ) HANGUL SYLLABLE DDAEP +B567;B567;1104 1162 11C2;B567;1104 1162 11C2; # (땧; 땧; 땧; 땧; 땧; ) HANGUL SYLLABLE DDAEH +B568;B568;1104 1163;B568;1104 1163; # (땨; 땨; 땨; 땨; 땨; ) HANGUL SYLLABLE DDYA +B569;B569;1104 1163 11A8;B569;1104 1163 11A8; # (땩; 땩; 땩; 땩; 땩; ) HANGUL SYLLABLE DDYAG +B56A;B56A;1104 1163 11A9;B56A;1104 1163 11A9; # (땪; 땪; 땪; 땪; 땪; ) HANGUL SYLLABLE DDYAGG +B56B;B56B;1104 1163 11AA;B56B;1104 1163 11AA; # (땫; 땫; 땫; 땫; 땫; ) HANGUL SYLLABLE DDYAGS +B56C;B56C;1104 1163 11AB;B56C;1104 1163 11AB; # (땬; 땬; 땬; 땬; 땬; ) HANGUL SYLLABLE DDYAN +B56D;B56D;1104 1163 11AC;B56D;1104 1163 11AC; # (땭; 땭; 땭; 땭; 땭; ) HANGUL SYLLABLE DDYANJ +B56E;B56E;1104 1163 11AD;B56E;1104 1163 11AD; # (땮; 땮; 땮; 땮; 땮; ) HANGUL SYLLABLE DDYANH +B56F;B56F;1104 1163 11AE;B56F;1104 1163 11AE; # (땯; 땯; 땯; 땯; 땯; ) HANGUL SYLLABLE DDYAD +B570;B570;1104 1163 11AF;B570;1104 1163 11AF; # (땰; 땰; 땰; 땰; 땰; ) HANGUL SYLLABLE DDYAL +B571;B571;1104 1163 11B0;B571;1104 1163 11B0; # (땱; 땱; 땱; 땱; 땱; ) HANGUL SYLLABLE DDYALG +B572;B572;1104 1163 11B1;B572;1104 1163 11B1; # (땲; 땲; 땲; 땲; 땲; ) HANGUL SYLLABLE DDYALM +B573;B573;1104 1163 11B2;B573;1104 1163 11B2; # (땳; 땳; 땳; 땳; 땳; ) HANGUL SYLLABLE DDYALB +B574;B574;1104 1163 11B3;B574;1104 1163 11B3; # (땴; 땴; 땴; 땴; 땴; ) HANGUL SYLLABLE DDYALS +B575;B575;1104 1163 11B4;B575;1104 1163 11B4; # (땵; 땵; 땵; 땵; 땵; ) HANGUL SYLLABLE DDYALT +B576;B576;1104 1163 11B5;B576;1104 1163 11B5; # (땶; 땶; 땶; 땶; 땶; ) HANGUL SYLLABLE DDYALP +B577;B577;1104 1163 11B6;B577;1104 1163 11B6; # (땷; 땷; 땷; 땷; 땷; ) HANGUL SYLLABLE DDYALH +B578;B578;1104 1163 11B7;B578;1104 1163 11B7; # (땸; 땸; 땸; 땸; 땸; ) HANGUL SYLLABLE DDYAM +B579;B579;1104 1163 11B8;B579;1104 1163 11B8; # (땹; 땹; 땹; 땹; 땹; ) HANGUL SYLLABLE DDYAB +B57A;B57A;1104 1163 11B9;B57A;1104 1163 11B9; # (땺; 땺; 땺; 땺; 땺; ) HANGUL SYLLABLE DDYABS +B57B;B57B;1104 1163 11BA;B57B;1104 1163 11BA; # (땻; 땻; 땻; 땻; 땻; ) HANGUL SYLLABLE DDYAS +B57C;B57C;1104 1163 11BB;B57C;1104 1163 11BB; # (땼; 땼; 땼; 땼; 땼; ) HANGUL SYLLABLE DDYASS +B57D;B57D;1104 1163 11BC;B57D;1104 1163 11BC; # (땽; 땽; 땽; 땽; 땽; ) HANGUL SYLLABLE DDYANG +B57E;B57E;1104 1163 11BD;B57E;1104 1163 11BD; # (땾; 땾; 땾; 땾; 땾; ) HANGUL SYLLABLE DDYAJ +B57F;B57F;1104 1163 11BE;B57F;1104 1163 11BE; # (땿; 땿; 땿; 땿; 땿; ) HANGUL SYLLABLE DDYAC +B580;B580;1104 1163 11BF;B580;1104 1163 11BF; # (떀; 떀; 떀; 떀; 떀; ) HANGUL SYLLABLE DDYAK +B581;B581;1104 1163 11C0;B581;1104 1163 11C0; # (떁; 떁; 떁; 떁; 떁; ) HANGUL SYLLABLE DDYAT +B582;B582;1104 1163 11C1;B582;1104 1163 11C1; # (떂; 떂; 떂; 떂; 떂; ) HANGUL SYLLABLE DDYAP +B583;B583;1104 1163 11C2;B583;1104 1163 11C2; # (떃; 떃; 떃; 떃; 떃; ) HANGUL SYLLABLE DDYAH +B584;B584;1104 1164;B584;1104 1164; # (떄; 떄; 떄; 떄; 떄; ) HANGUL SYLLABLE DDYAE +B585;B585;1104 1164 11A8;B585;1104 1164 11A8; # (떅; 떅; 떅; 떅; 떅; ) HANGUL SYLLABLE DDYAEG +B586;B586;1104 1164 11A9;B586;1104 1164 11A9; # (떆; 떆; 떆; 떆; 떆; ) HANGUL SYLLABLE DDYAEGG +B587;B587;1104 1164 11AA;B587;1104 1164 11AA; # (떇; 떇; 떇; 떇; 떇; ) HANGUL SYLLABLE DDYAEGS +B588;B588;1104 1164 11AB;B588;1104 1164 11AB; # (떈; 떈; 떈; 떈; 떈; ) HANGUL SYLLABLE DDYAEN +B589;B589;1104 1164 11AC;B589;1104 1164 11AC; # (떉; 떉; 떉; 떉; 떉; ) HANGUL SYLLABLE DDYAENJ +B58A;B58A;1104 1164 11AD;B58A;1104 1164 11AD; # (떊; 떊; 떊; 떊; 떊; ) HANGUL SYLLABLE DDYAENH +B58B;B58B;1104 1164 11AE;B58B;1104 1164 11AE; # (떋; 떋; 떋; 떋; 떋; ) HANGUL SYLLABLE DDYAED +B58C;B58C;1104 1164 11AF;B58C;1104 1164 11AF; # (떌; 떌; 떌; 떌; 떌; ) HANGUL SYLLABLE DDYAEL +B58D;B58D;1104 1164 11B0;B58D;1104 1164 11B0; # (떍; 떍; 떍; 떍; 떍; ) HANGUL SYLLABLE DDYAELG +B58E;B58E;1104 1164 11B1;B58E;1104 1164 11B1; # (떎; 떎; 떎; 떎; 떎; ) HANGUL SYLLABLE DDYAELM +B58F;B58F;1104 1164 11B2;B58F;1104 1164 11B2; # (떏; 떏; 떏; 떏; 떏; ) HANGUL SYLLABLE DDYAELB +B590;B590;1104 1164 11B3;B590;1104 1164 11B3; # (떐; 떐; 떐; 떐; 떐; ) HANGUL SYLLABLE DDYAELS +B591;B591;1104 1164 11B4;B591;1104 1164 11B4; # (떑; 떑; 떑; 떑; 떑; ) HANGUL SYLLABLE DDYAELT +B592;B592;1104 1164 11B5;B592;1104 1164 11B5; # (떒; 떒; 떒; 떒; 떒; ) HANGUL SYLLABLE DDYAELP +B593;B593;1104 1164 11B6;B593;1104 1164 11B6; # (떓; 떓; 떓; 떓; 떓; ) HANGUL SYLLABLE DDYAELH +B594;B594;1104 1164 11B7;B594;1104 1164 11B7; # (떔; 떔; 떔; 떔; 떔; ) HANGUL SYLLABLE DDYAEM +B595;B595;1104 1164 11B8;B595;1104 1164 11B8; # (떕; 떕; 떕; 떕; 떕; ) HANGUL SYLLABLE DDYAEB +B596;B596;1104 1164 11B9;B596;1104 1164 11B9; # (떖; 떖; 떖; 떖; 떖; ) HANGUL SYLLABLE DDYAEBS +B597;B597;1104 1164 11BA;B597;1104 1164 11BA; # (떗; 떗; 떗; 떗; 떗; ) HANGUL SYLLABLE DDYAES +B598;B598;1104 1164 11BB;B598;1104 1164 11BB; # (떘; 떘; 떘; 떘; 떘; ) HANGUL SYLLABLE DDYAESS +B599;B599;1104 1164 11BC;B599;1104 1164 11BC; # (떙; 떙; 떙; 떙; 떙; ) HANGUL SYLLABLE DDYAENG +B59A;B59A;1104 1164 11BD;B59A;1104 1164 11BD; # (떚; 떚; 떚; 떚; 떚; ) HANGUL SYLLABLE DDYAEJ +B59B;B59B;1104 1164 11BE;B59B;1104 1164 11BE; # (떛; 떛; 떛; 떛; 떛; ) HANGUL SYLLABLE DDYAEC +B59C;B59C;1104 1164 11BF;B59C;1104 1164 11BF; # (떜; 떜; 떜; 떜; 떜; ) HANGUL SYLLABLE DDYAEK +B59D;B59D;1104 1164 11C0;B59D;1104 1164 11C0; # (떝; 떝; 떝; 떝; 떝; ) HANGUL SYLLABLE DDYAET +B59E;B59E;1104 1164 11C1;B59E;1104 1164 11C1; # (떞; 떞; 떞; 떞; 떞; ) HANGUL SYLLABLE DDYAEP +B59F;B59F;1104 1164 11C2;B59F;1104 1164 11C2; # (떟; 떟; 떟; 떟; 떟; ) HANGUL SYLLABLE DDYAEH +B5A0;B5A0;1104 1165;B5A0;1104 1165; # (떠; 떠; 떠; 떠; 떠; ) HANGUL SYLLABLE DDEO +B5A1;B5A1;1104 1165 11A8;B5A1;1104 1165 11A8; # (떡; 떡; 떡; 떡; 떡; ) HANGUL SYLLABLE DDEOG +B5A2;B5A2;1104 1165 11A9;B5A2;1104 1165 11A9; # (떢; 떢; 떢; 떢; 떢; ) HANGUL SYLLABLE DDEOGG +B5A3;B5A3;1104 1165 11AA;B5A3;1104 1165 11AA; # (떣; 떣; 떣; 떣; 떣; ) HANGUL SYLLABLE DDEOGS +B5A4;B5A4;1104 1165 11AB;B5A4;1104 1165 11AB; # (떤; 떤; 떤; 떤; 떤; ) HANGUL SYLLABLE DDEON +B5A5;B5A5;1104 1165 11AC;B5A5;1104 1165 11AC; # (떥; 떥; 떥; 떥; 떥; ) HANGUL SYLLABLE DDEONJ +B5A6;B5A6;1104 1165 11AD;B5A6;1104 1165 11AD; # (떦; 떦; 떦; 떦; 떦; ) HANGUL SYLLABLE DDEONH +B5A7;B5A7;1104 1165 11AE;B5A7;1104 1165 11AE; # (떧; 떧; 떧; 떧; 떧; ) HANGUL SYLLABLE DDEOD +B5A8;B5A8;1104 1165 11AF;B5A8;1104 1165 11AF; # (떨; 떨; 떨; 떨; 떨; ) HANGUL SYLLABLE DDEOL +B5A9;B5A9;1104 1165 11B0;B5A9;1104 1165 11B0; # (떩; 떩; 떩; 떩; 떩; ) HANGUL SYLLABLE DDEOLG +B5AA;B5AA;1104 1165 11B1;B5AA;1104 1165 11B1; # (떪; 떪; 떪; 떪; 떪; ) HANGUL SYLLABLE DDEOLM +B5AB;B5AB;1104 1165 11B2;B5AB;1104 1165 11B2; # (떫; 떫; 떫; 떫; 떫; ) HANGUL SYLLABLE DDEOLB +B5AC;B5AC;1104 1165 11B3;B5AC;1104 1165 11B3; # (떬; 떬; 떬; 떬; 떬; ) HANGUL SYLLABLE DDEOLS +B5AD;B5AD;1104 1165 11B4;B5AD;1104 1165 11B4; # (떭; 떭; 떭; 떭; 떭; ) HANGUL SYLLABLE DDEOLT +B5AE;B5AE;1104 1165 11B5;B5AE;1104 1165 11B5; # (떮; 떮; 떮; 떮; 떮; ) HANGUL SYLLABLE DDEOLP +B5AF;B5AF;1104 1165 11B6;B5AF;1104 1165 11B6; # (떯; 떯; 떯; 떯; 떯; ) HANGUL SYLLABLE DDEOLH +B5B0;B5B0;1104 1165 11B7;B5B0;1104 1165 11B7; # (떰; 떰; 떰; 떰; 떰; ) HANGUL SYLLABLE DDEOM +B5B1;B5B1;1104 1165 11B8;B5B1;1104 1165 11B8; # (떱; 떱; 떱; 떱; 떱; ) HANGUL SYLLABLE DDEOB +B5B2;B5B2;1104 1165 11B9;B5B2;1104 1165 11B9; # (떲; 떲; 떲; 떲; 떲; ) HANGUL SYLLABLE DDEOBS +B5B3;B5B3;1104 1165 11BA;B5B3;1104 1165 11BA; # (떳; 떳; 떳; 떳; 떳; ) HANGUL SYLLABLE DDEOS +B5B4;B5B4;1104 1165 11BB;B5B4;1104 1165 11BB; # (떴; 떴; 떴; 떴; 떴; ) HANGUL SYLLABLE DDEOSS +B5B5;B5B5;1104 1165 11BC;B5B5;1104 1165 11BC; # (떵; 떵; 떵; 떵; 떵; ) HANGUL SYLLABLE DDEONG +B5B6;B5B6;1104 1165 11BD;B5B6;1104 1165 11BD; # (떶; 떶; 떶; 떶; 떶; ) HANGUL SYLLABLE DDEOJ +B5B7;B5B7;1104 1165 11BE;B5B7;1104 1165 11BE; # (떷; 떷; 떷; 떷; 떷; ) HANGUL SYLLABLE DDEOC +B5B8;B5B8;1104 1165 11BF;B5B8;1104 1165 11BF; # (떸; 떸; 떸; 떸; 떸; ) HANGUL SYLLABLE DDEOK +B5B9;B5B9;1104 1165 11C0;B5B9;1104 1165 11C0; # (떹; 떹; 떹; 떹; 떹; ) HANGUL SYLLABLE DDEOT +B5BA;B5BA;1104 1165 11C1;B5BA;1104 1165 11C1; # (떺; 떺; 떺; 떺; 떺; ) HANGUL SYLLABLE DDEOP +B5BB;B5BB;1104 1165 11C2;B5BB;1104 1165 11C2; # (떻; 떻; 떻; 떻; 떻; ) HANGUL SYLLABLE DDEOH +B5BC;B5BC;1104 1166;B5BC;1104 1166; # (떼; 떼; 떼; 떼; 떼; ) HANGUL SYLLABLE DDE +B5BD;B5BD;1104 1166 11A8;B5BD;1104 1166 11A8; # (떽; 떽; 떽; 떽; 떽; ) HANGUL SYLLABLE DDEG +B5BE;B5BE;1104 1166 11A9;B5BE;1104 1166 11A9; # (떾; 떾; 떾; 떾; 떾; ) HANGUL SYLLABLE DDEGG +B5BF;B5BF;1104 1166 11AA;B5BF;1104 1166 11AA; # (떿; 떿; 떿; 떿; 떿; ) HANGUL SYLLABLE DDEGS +B5C0;B5C0;1104 1166 11AB;B5C0;1104 1166 11AB; # (뗀; 뗀; 뗀; 뗀; 뗀; ) HANGUL SYLLABLE DDEN +B5C1;B5C1;1104 1166 11AC;B5C1;1104 1166 11AC; # (뗁; 뗁; 뗁; 뗁; 뗁; ) HANGUL SYLLABLE DDENJ +B5C2;B5C2;1104 1166 11AD;B5C2;1104 1166 11AD; # (뗂; 뗂; 뗂; 뗂; 뗂; ) HANGUL SYLLABLE DDENH +B5C3;B5C3;1104 1166 11AE;B5C3;1104 1166 11AE; # (뗃; 뗃; 뗃; 뗃; 뗃; ) HANGUL SYLLABLE DDED +B5C4;B5C4;1104 1166 11AF;B5C4;1104 1166 11AF; # (뗄; 뗄; 뗄; 뗄; 뗄; ) HANGUL SYLLABLE DDEL +B5C5;B5C5;1104 1166 11B0;B5C5;1104 1166 11B0; # (뗅; 뗅; 뗅; 뗅; 뗅; ) HANGUL SYLLABLE DDELG +B5C6;B5C6;1104 1166 11B1;B5C6;1104 1166 11B1; # (뗆; 뗆; 뗆; 뗆; 뗆; ) HANGUL SYLLABLE DDELM +B5C7;B5C7;1104 1166 11B2;B5C7;1104 1166 11B2; # (뗇; 뗇; 뗇; 뗇; 뗇; ) HANGUL SYLLABLE DDELB +B5C8;B5C8;1104 1166 11B3;B5C8;1104 1166 11B3; # (뗈; 뗈; 뗈; 뗈; 뗈; ) HANGUL SYLLABLE DDELS +B5C9;B5C9;1104 1166 11B4;B5C9;1104 1166 11B4; # (뗉; 뗉; 뗉; 뗉; 뗉; ) HANGUL SYLLABLE DDELT +B5CA;B5CA;1104 1166 11B5;B5CA;1104 1166 11B5; # (뗊; 뗊; 뗊; 뗊; 뗊; ) HANGUL SYLLABLE DDELP +B5CB;B5CB;1104 1166 11B6;B5CB;1104 1166 11B6; # (뗋; 뗋; 뗋; 뗋; 뗋; ) HANGUL SYLLABLE DDELH +B5CC;B5CC;1104 1166 11B7;B5CC;1104 1166 11B7; # (뗌; 뗌; 뗌; 뗌; 뗌; ) HANGUL SYLLABLE DDEM +B5CD;B5CD;1104 1166 11B8;B5CD;1104 1166 11B8; # (뗍; 뗍; 뗍; 뗍; 뗍; ) HANGUL SYLLABLE DDEB +B5CE;B5CE;1104 1166 11B9;B5CE;1104 1166 11B9; # (뗎; 뗎; 뗎; 뗎; 뗎; ) HANGUL SYLLABLE DDEBS +B5CF;B5CF;1104 1166 11BA;B5CF;1104 1166 11BA; # (뗏; 뗏; 뗏; 뗏; 뗏; ) HANGUL SYLLABLE DDES +B5D0;B5D0;1104 1166 11BB;B5D0;1104 1166 11BB; # (뗐; 뗐; 뗐; 뗐; 뗐; ) HANGUL SYLLABLE DDESS +B5D1;B5D1;1104 1166 11BC;B5D1;1104 1166 11BC; # (뗑; 뗑; 뗑; 뗑; 뗑; ) HANGUL SYLLABLE DDENG +B5D2;B5D2;1104 1166 11BD;B5D2;1104 1166 11BD; # (뗒; 뗒; 뗒; 뗒; 뗒; ) HANGUL SYLLABLE DDEJ +B5D3;B5D3;1104 1166 11BE;B5D3;1104 1166 11BE; # (뗓; 뗓; 뗓; 뗓; 뗓; ) HANGUL SYLLABLE DDEC +B5D4;B5D4;1104 1166 11BF;B5D4;1104 1166 11BF; # (뗔; 뗔; 뗔; 뗔; 뗔; ) HANGUL SYLLABLE DDEK +B5D5;B5D5;1104 1166 11C0;B5D5;1104 1166 11C0; # (뗕; 뗕; 뗕; 뗕; 뗕; ) HANGUL SYLLABLE DDET +B5D6;B5D6;1104 1166 11C1;B5D6;1104 1166 11C1; # (뗖; 뗖; 뗖; 뗖; 뗖; ) HANGUL SYLLABLE DDEP +B5D7;B5D7;1104 1166 11C2;B5D7;1104 1166 11C2; # (뗗; 뗗; 뗗; 뗗; 뗗; ) HANGUL SYLLABLE DDEH +B5D8;B5D8;1104 1167;B5D8;1104 1167; # (뗘; 뗘; 뗘; 뗘; 뗘; ) HANGUL SYLLABLE DDYEO +B5D9;B5D9;1104 1167 11A8;B5D9;1104 1167 11A8; # (뗙; 뗙; 뗙; 뗙; 뗙; ) HANGUL SYLLABLE DDYEOG +B5DA;B5DA;1104 1167 11A9;B5DA;1104 1167 11A9; # (뗚; 뗚; 뗚; 뗚; 뗚; ) HANGUL SYLLABLE DDYEOGG +B5DB;B5DB;1104 1167 11AA;B5DB;1104 1167 11AA; # (뗛; 뗛; 뗛; 뗛; 뗛; ) HANGUL SYLLABLE DDYEOGS +B5DC;B5DC;1104 1167 11AB;B5DC;1104 1167 11AB; # (뗜; 뗜; 뗜; 뗜; 뗜; ) HANGUL SYLLABLE DDYEON +B5DD;B5DD;1104 1167 11AC;B5DD;1104 1167 11AC; # (뗝; 뗝; 뗝; 뗝; 뗝; ) HANGUL SYLLABLE DDYEONJ +B5DE;B5DE;1104 1167 11AD;B5DE;1104 1167 11AD; # (뗞; 뗞; 뗞; 뗞; 뗞; ) HANGUL SYLLABLE DDYEONH +B5DF;B5DF;1104 1167 11AE;B5DF;1104 1167 11AE; # (뗟; 뗟; 뗟; 뗟; 뗟; ) HANGUL SYLLABLE DDYEOD +B5E0;B5E0;1104 1167 11AF;B5E0;1104 1167 11AF; # (뗠; 뗠; 뗠; 뗠; 뗠; ) HANGUL SYLLABLE DDYEOL +B5E1;B5E1;1104 1167 11B0;B5E1;1104 1167 11B0; # (뗡; 뗡; 뗡; 뗡; 뗡; ) HANGUL SYLLABLE DDYEOLG +B5E2;B5E2;1104 1167 11B1;B5E2;1104 1167 11B1; # (뗢; 뗢; 뗢; 뗢; 뗢; ) HANGUL SYLLABLE DDYEOLM +B5E3;B5E3;1104 1167 11B2;B5E3;1104 1167 11B2; # (뗣; 뗣; 뗣; 뗣; 뗣; ) HANGUL SYLLABLE DDYEOLB +B5E4;B5E4;1104 1167 11B3;B5E4;1104 1167 11B3; # (뗤; 뗤; 뗤; 뗤; 뗤; ) HANGUL SYLLABLE DDYEOLS +B5E5;B5E5;1104 1167 11B4;B5E5;1104 1167 11B4; # (뗥; 뗥; 뗥; 뗥; 뗥; ) HANGUL SYLLABLE DDYEOLT +B5E6;B5E6;1104 1167 11B5;B5E6;1104 1167 11B5; # (뗦; 뗦; 뗦; 뗦; 뗦; ) HANGUL SYLLABLE DDYEOLP +B5E7;B5E7;1104 1167 11B6;B5E7;1104 1167 11B6; # (뗧; 뗧; 뗧; 뗧; 뗧; ) HANGUL SYLLABLE DDYEOLH +B5E8;B5E8;1104 1167 11B7;B5E8;1104 1167 11B7; # (뗨; 뗨; 뗨; 뗨; 뗨; ) HANGUL SYLLABLE DDYEOM +B5E9;B5E9;1104 1167 11B8;B5E9;1104 1167 11B8; # (뗩; 뗩; 뗩; 뗩; 뗩; ) HANGUL SYLLABLE DDYEOB +B5EA;B5EA;1104 1167 11B9;B5EA;1104 1167 11B9; # (뗪; 뗪; 뗪; 뗪; 뗪; ) HANGUL SYLLABLE DDYEOBS +B5EB;B5EB;1104 1167 11BA;B5EB;1104 1167 11BA; # (뗫; 뗫; 뗫; 뗫; 뗫; ) HANGUL SYLLABLE DDYEOS +B5EC;B5EC;1104 1167 11BB;B5EC;1104 1167 11BB; # (뗬; 뗬; 뗬; 뗬; 뗬; ) HANGUL SYLLABLE DDYEOSS +B5ED;B5ED;1104 1167 11BC;B5ED;1104 1167 11BC; # (뗭; 뗭; 뗭; 뗭; 뗭; ) HANGUL SYLLABLE DDYEONG +B5EE;B5EE;1104 1167 11BD;B5EE;1104 1167 11BD; # (뗮; 뗮; 뗮; 뗮; 뗮; ) HANGUL SYLLABLE DDYEOJ +B5EF;B5EF;1104 1167 11BE;B5EF;1104 1167 11BE; # (뗯; 뗯; 뗯; 뗯; 뗯; ) HANGUL SYLLABLE DDYEOC +B5F0;B5F0;1104 1167 11BF;B5F0;1104 1167 11BF; # (뗰; 뗰; 뗰; 뗰; 뗰; ) HANGUL SYLLABLE DDYEOK +B5F1;B5F1;1104 1167 11C0;B5F1;1104 1167 11C0; # (뗱; 뗱; 뗱; 뗱; 뗱; ) HANGUL SYLLABLE DDYEOT +B5F2;B5F2;1104 1167 11C1;B5F2;1104 1167 11C1; # (뗲; 뗲; 뗲; 뗲; 뗲; ) HANGUL SYLLABLE DDYEOP +B5F3;B5F3;1104 1167 11C2;B5F3;1104 1167 11C2; # (뗳; 뗳; 뗳; 뗳; 뗳; ) HANGUL SYLLABLE DDYEOH +B5F4;B5F4;1104 1168;B5F4;1104 1168; # (뗴; 뗴; 뗴; 뗴; 뗴; ) HANGUL SYLLABLE DDYE +B5F5;B5F5;1104 1168 11A8;B5F5;1104 1168 11A8; # (뗵; 뗵; 뗵; 뗵; 뗵; ) HANGUL SYLLABLE DDYEG +B5F6;B5F6;1104 1168 11A9;B5F6;1104 1168 11A9; # (뗶; 뗶; 뗶; 뗶; 뗶; ) HANGUL SYLLABLE DDYEGG +B5F7;B5F7;1104 1168 11AA;B5F7;1104 1168 11AA; # (뗷; 뗷; 뗷; 뗷; 뗷; ) HANGUL SYLLABLE DDYEGS +B5F8;B5F8;1104 1168 11AB;B5F8;1104 1168 11AB; # (뗸; 뗸; 뗸; 뗸; 뗸; ) HANGUL SYLLABLE DDYEN +B5F9;B5F9;1104 1168 11AC;B5F9;1104 1168 11AC; # (뗹; 뗹; 뗹; 뗹; 뗹; ) HANGUL SYLLABLE DDYENJ +B5FA;B5FA;1104 1168 11AD;B5FA;1104 1168 11AD; # (뗺; 뗺; 뗺; 뗺; 뗺; ) HANGUL SYLLABLE DDYENH +B5FB;B5FB;1104 1168 11AE;B5FB;1104 1168 11AE; # (뗻; 뗻; 뗻; 뗻; 뗻; ) HANGUL SYLLABLE DDYED +B5FC;B5FC;1104 1168 11AF;B5FC;1104 1168 11AF; # (뗼; 뗼; 뗼; 뗼; 뗼; ) HANGUL SYLLABLE DDYEL +B5FD;B5FD;1104 1168 11B0;B5FD;1104 1168 11B0; # (뗽; 뗽; 뗽; 뗽; 뗽; ) HANGUL SYLLABLE DDYELG +B5FE;B5FE;1104 1168 11B1;B5FE;1104 1168 11B1; # (뗾; 뗾; 뗾; 뗾; 뗾; ) HANGUL SYLLABLE DDYELM +B5FF;B5FF;1104 1168 11B2;B5FF;1104 1168 11B2; # (뗿; 뗿; 뗿; 뗿; 뗿; ) HANGUL SYLLABLE DDYELB +B600;B600;1104 1168 11B3;B600;1104 1168 11B3; # (똀; 똀; 똀; 똀; 똀; ) HANGUL SYLLABLE DDYELS +B601;B601;1104 1168 11B4;B601;1104 1168 11B4; # (똁; 똁; 똁; 똁; 똁; ) HANGUL SYLLABLE DDYELT +B602;B602;1104 1168 11B5;B602;1104 1168 11B5; # (똂; 똂; 똂; 똂; 똂; ) HANGUL SYLLABLE DDYELP +B603;B603;1104 1168 11B6;B603;1104 1168 11B6; # (똃; 똃; 똃; 똃; 똃; ) HANGUL SYLLABLE DDYELH +B604;B604;1104 1168 11B7;B604;1104 1168 11B7; # (똄; 똄; 똄; 똄; 똄; ) HANGUL SYLLABLE DDYEM +B605;B605;1104 1168 11B8;B605;1104 1168 11B8; # (똅; 똅; 똅; 똅; 똅; ) HANGUL SYLLABLE DDYEB +B606;B606;1104 1168 11B9;B606;1104 1168 11B9; # (똆; 똆; 똆; 똆; 똆; ) HANGUL SYLLABLE DDYEBS +B607;B607;1104 1168 11BA;B607;1104 1168 11BA; # (똇; 똇; 똇; 똇; 똇; ) HANGUL SYLLABLE DDYES +B608;B608;1104 1168 11BB;B608;1104 1168 11BB; # (똈; 똈; 똈; 똈; 똈; ) HANGUL SYLLABLE DDYESS +B609;B609;1104 1168 11BC;B609;1104 1168 11BC; # (똉; 똉; 똉; 똉; 똉; ) HANGUL SYLLABLE DDYENG +B60A;B60A;1104 1168 11BD;B60A;1104 1168 11BD; # (똊; 똊; 똊; 똊; 똊; ) HANGUL SYLLABLE DDYEJ +B60B;B60B;1104 1168 11BE;B60B;1104 1168 11BE; # (똋; 똋; 똋; 똋; 똋; ) HANGUL SYLLABLE DDYEC +B60C;B60C;1104 1168 11BF;B60C;1104 1168 11BF; # (똌; 똌; 똌; 똌; 똌; ) HANGUL SYLLABLE DDYEK +B60D;B60D;1104 1168 11C0;B60D;1104 1168 11C0; # (똍; 똍; 똍; 똍; 똍; ) HANGUL SYLLABLE DDYET +B60E;B60E;1104 1168 11C1;B60E;1104 1168 11C1; # (똎; 똎; 똎; 똎; 똎; ) HANGUL SYLLABLE DDYEP +B60F;B60F;1104 1168 11C2;B60F;1104 1168 11C2; # (똏; 똏; 똏; 똏; 똏; ) HANGUL SYLLABLE DDYEH +B610;B610;1104 1169;B610;1104 1169; # (또; 또; 또; 또; 또; ) HANGUL SYLLABLE DDO +B611;B611;1104 1169 11A8;B611;1104 1169 11A8; # (똑; 똑; 똑; 똑; 똑; ) HANGUL SYLLABLE DDOG +B612;B612;1104 1169 11A9;B612;1104 1169 11A9; # (똒; 똒; 똒; 똒; 똒; ) HANGUL SYLLABLE DDOGG +B613;B613;1104 1169 11AA;B613;1104 1169 11AA; # (똓; 똓; 똓; 똓; 똓; ) HANGUL SYLLABLE DDOGS +B614;B614;1104 1169 11AB;B614;1104 1169 11AB; # (똔; 똔; 똔; 똔; 똔; ) HANGUL SYLLABLE DDON +B615;B615;1104 1169 11AC;B615;1104 1169 11AC; # (똕; 똕; 똕; 똕; 똕; ) HANGUL SYLLABLE DDONJ +B616;B616;1104 1169 11AD;B616;1104 1169 11AD; # (똖; 똖; 똖; 똖; 똖; ) HANGUL SYLLABLE DDONH +B617;B617;1104 1169 11AE;B617;1104 1169 11AE; # (똗; 똗; 똗; 똗; 똗; ) HANGUL SYLLABLE DDOD +B618;B618;1104 1169 11AF;B618;1104 1169 11AF; # (똘; 똘; 똘; 똘; 똘; ) HANGUL SYLLABLE DDOL +B619;B619;1104 1169 11B0;B619;1104 1169 11B0; # (똙; 똙; 똙; 똙; 똙; ) HANGUL SYLLABLE DDOLG +B61A;B61A;1104 1169 11B1;B61A;1104 1169 11B1; # (똚; 똚; 똚; 똚; 똚; ) HANGUL SYLLABLE DDOLM +B61B;B61B;1104 1169 11B2;B61B;1104 1169 11B2; # (똛; 똛; 똛; 똛; 똛; ) HANGUL SYLLABLE DDOLB +B61C;B61C;1104 1169 11B3;B61C;1104 1169 11B3; # (똜; 똜; 똜; 똜; 똜; ) HANGUL SYLLABLE DDOLS +B61D;B61D;1104 1169 11B4;B61D;1104 1169 11B4; # (똝; 똝; 똝; 똝; 똝; ) HANGUL SYLLABLE DDOLT +B61E;B61E;1104 1169 11B5;B61E;1104 1169 11B5; # (똞; 똞; 똞; 똞; 똞; ) HANGUL SYLLABLE DDOLP +B61F;B61F;1104 1169 11B6;B61F;1104 1169 11B6; # (똟; 똟; 똟; 똟; 똟; ) HANGUL SYLLABLE DDOLH +B620;B620;1104 1169 11B7;B620;1104 1169 11B7; # (똠; 똠; 똠; 똠; 똠; ) HANGUL SYLLABLE DDOM +B621;B621;1104 1169 11B8;B621;1104 1169 11B8; # (똡; 똡; 똡; 똡; 똡; ) HANGUL SYLLABLE DDOB +B622;B622;1104 1169 11B9;B622;1104 1169 11B9; # (똢; 똢; 똢; 똢; 똢; ) HANGUL SYLLABLE DDOBS +B623;B623;1104 1169 11BA;B623;1104 1169 11BA; # (똣; 똣; 똣; 똣; 똣; ) HANGUL SYLLABLE DDOS +B624;B624;1104 1169 11BB;B624;1104 1169 11BB; # (똤; 똤; 똤; 똤; 똤; ) HANGUL SYLLABLE DDOSS +B625;B625;1104 1169 11BC;B625;1104 1169 11BC; # (똥; 똥; 똥; 똥; 똥; ) HANGUL SYLLABLE DDONG +B626;B626;1104 1169 11BD;B626;1104 1169 11BD; # (똦; 똦; 똦; 똦; 똦; ) HANGUL SYLLABLE DDOJ +B627;B627;1104 1169 11BE;B627;1104 1169 11BE; # (똧; 똧; 똧; 똧; 똧; ) HANGUL SYLLABLE DDOC +B628;B628;1104 1169 11BF;B628;1104 1169 11BF; # (똨; 똨; 똨; 똨; 똨; ) HANGUL SYLLABLE DDOK +B629;B629;1104 1169 11C0;B629;1104 1169 11C0; # (똩; 똩; 똩; 똩; 똩; ) HANGUL SYLLABLE DDOT +B62A;B62A;1104 1169 11C1;B62A;1104 1169 11C1; # (똪; 똪; 똪; 똪; 똪; ) HANGUL SYLLABLE DDOP +B62B;B62B;1104 1169 11C2;B62B;1104 1169 11C2; # (똫; 똫; 똫; 똫; 똫; ) HANGUL SYLLABLE DDOH +B62C;B62C;1104 116A;B62C;1104 116A; # (똬; 똬; 똬; 똬; 똬; ) HANGUL SYLLABLE DDWA +B62D;B62D;1104 116A 11A8;B62D;1104 116A 11A8; # (똭; 똭; 똭; 똭; 똭; ) HANGUL SYLLABLE DDWAG +B62E;B62E;1104 116A 11A9;B62E;1104 116A 11A9; # (똮; 똮; 똮; 똮; 똮; ) HANGUL SYLLABLE DDWAGG +B62F;B62F;1104 116A 11AA;B62F;1104 116A 11AA; # (똯; 똯; 똯; 똯; 똯; ) HANGUL SYLLABLE DDWAGS +B630;B630;1104 116A 11AB;B630;1104 116A 11AB; # (똰; 똰; 똰; 똰; 똰; ) HANGUL SYLLABLE DDWAN +B631;B631;1104 116A 11AC;B631;1104 116A 11AC; # (똱; 똱; 똱; 똱; 똱; ) HANGUL SYLLABLE DDWANJ +B632;B632;1104 116A 11AD;B632;1104 116A 11AD; # (똲; 똲; 똲; 똲; 똲; ) HANGUL SYLLABLE DDWANH +B633;B633;1104 116A 11AE;B633;1104 116A 11AE; # (똳; 똳; 똳; 똳; 똳; ) HANGUL SYLLABLE DDWAD +B634;B634;1104 116A 11AF;B634;1104 116A 11AF; # (똴; 똴; 똴; 똴; 똴; ) HANGUL SYLLABLE DDWAL +B635;B635;1104 116A 11B0;B635;1104 116A 11B0; # (똵; 똵; 똵; 똵; 똵; ) HANGUL SYLLABLE DDWALG +B636;B636;1104 116A 11B1;B636;1104 116A 11B1; # (똶; 똶; 똶; 똶; 똶; ) HANGUL SYLLABLE DDWALM +B637;B637;1104 116A 11B2;B637;1104 116A 11B2; # (똷; 똷; 똷; 똷; 똷; ) HANGUL SYLLABLE DDWALB +B638;B638;1104 116A 11B3;B638;1104 116A 11B3; # (똸; 똸; 똸; 똸; 똸; ) HANGUL SYLLABLE DDWALS +B639;B639;1104 116A 11B4;B639;1104 116A 11B4; # (똹; 똹; 똹; 똹; 똹; ) HANGUL SYLLABLE DDWALT +B63A;B63A;1104 116A 11B5;B63A;1104 116A 11B5; # (똺; 똺; 똺; 똺; 똺; ) HANGUL SYLLABLE DDWALP +B63B;B63B;1104 116A 11B6;B63B;1104 116A 11B6; # (똻; 똻; 똻; 똻; 똻; ) HANGUL SYLLABLE DDWALH +B63C;B63C;1104 116A 11B7;B63C;1104 116A 11B7; # (똼; 똼; 똼; 똼; 똼; ) HANGUL SYLLABLE DDWAM +B63D;B63D;1104 116A 11B8;B63D;1104 116A 11B8; # (똽; 똽; 똽; 똽; 똽; ) HANGUL SYLLABLE DDWAB +B63E;B63E;1104 116A 11B9;B63E;1104 116A 11B9; # (똾; 똾; 똾; 똾; 똾; ) HANGUL SYLLABLE DDWABS +B63F;B63F;1104 116A 11BA;B63F;1104 116A 11BA; # (똿; 똿; 똿; 똿; 똿; ) HANGUL SYLLABLE DDWAS +B640;B640;1104 116A 11BB;B640;1104 116A 11BB; # (뙀; 뙀; 뙀; 뙀; 뙀; ) HANGUL SYLLABLE DDWASS +B641;B641;1104 116A 11BC;B641;1104 116A 11BC; # (뙁; 뙁; 뙁; 뙁; 뙁; ) HANGUL SYLLABLE DDWANG +B642;B642;1104 116A 11BD;B642;1104 116A 11BD; # (뙂; 뙂; 뙂; 뙂; 뙂; ) HANGUL SYLLABLE DDWAJ +B643;B643;1104 116A 11BE;B643;1104 116A 11BE; # (뙃; 뙃; 뙃; 뙃; 뙃; ) HANGUL SYLLABLE DDWAC +B644;B644;1104 116A 11BF;B644;1104 116A 11BF; # (뙄; 뙄; 뙄; 뙄; 뙄; ) HANGUL SYLLABLE DDWAK +B645;B645;1104 116A 11C0;B645;1104 116A 11C0; # (뙅; 뙅; 뙅; 뙅; 뙅; ) HANGUL SYLLABLE DDWAT +B646;B646;1104 116A 11C1;B646;1104 116A 11C1; # (뙆; 뙆; 뙆; 뙆; 뙆; ) HANGUL SYLLABLE DDWAP +B647;B647;1104 116A 11C2;B647;1104 116A 11C2; # (뙇; 뙇; 뙇; 뙇; 뙇; ) HANGUL SYLLABLE DDWAH +B648;B648;1104 116B;B648;1104 116B; # (뙈; 뙈; 뙈; 뙈; 뙈; ) HANGUL SYLLABLE DDWAE +B649;B649;1104 116B 11A8;B649;1104 116B 11A8; # (뙉; 뙉; 뙉; 뙉; 뙉; ) HANGUL SYLLABLE DDWAEG +B64A;B64A;1104 116B 11A9;B64A;1104 116B 11A9; # (뙊; 뙊; 뙊; 뙊; 뙊; ) HANGUL SYLLABLE DDWAEGG +B64B;B64B;1104 116B 11AA;B64B;1104 116B 11AA; # (뙋; 뙋; 뙋; 뙋; 뙋; ) HANGUL SYLLABLE DDWAEGS +B64C;B64C;1104 116B 11AB;B64C;1104 116B 11AB; # (뙌; 뙌; 뙌; 뙌; 뙌; ) HANGUL SYLLABLE DDWAEN +B64D;B64D;1104 116B 11AC;B64D;1104 116B 11AC; # (뙍; 뙍; 뙍; 뙍; 뙍; ) HANGUL SYLLABLE DDWAENJ +B64E;B64E;1104 116B 11AD;B64E;1104 116B 11AD; # (뙎; 뙎; 뙎; 뙎; 뙎; ) HANGUL SYLLABLE DDWAENH +B64F;B64F;1104 116B 11AE;B64F;1104 116B 11AE; # (뙏; 뙏; 뙏; 뙏; 뙏; ) HANGUL SYLLABLE DDWAED +B650;B650;1104 116B 11AF;B650;1104 116B 11AF; # (뙐; 뙐; 뙐; 뙐; 뙐; ) HANGUL SYLLABLE DDWAEL +B651;B651;1104 116B 11B0;B651;1104 116B 11B0; # (뙑; 뙑; 뙑; 뙑; 뙑; ) HANGUL SYLLABLE DDWAELG +B652;B652;1104 116B 11B1;B652;1104 116B 11B1; # (뙒; 뙒; 뙒; 뙒; 뙒; ) HANGUL SYLLABLE DDWAELM +B653;B653;1104 116B 11B2;B653;1104 116B 11B2; # (뙓; 뙓; 뙓; 뙓; 뙓; ) HANGUL SYLLABLE DDWAELB +B654;B654;1104 116B 11B3;B654;1104 116B 11B3; # (뙔; 뙔; 뙔; 뙔; 뙔; ) HANGUL SYLLABLE DDWAELS +B655;B655;1104 116B 11B4;B655;1104 116B 11B4; # (뙕; 뙕; 뙕; 뙕; 뙕; ) HANGUL SYLLABLE DDWAELT +B656;B656;1104 116B 11B5;B656;1104 116B 11B5; # (뙖; 뙖; 뙖; 뙖; 뙖; ) HANGUL SYLLABLE DDWAELP +B657;B657;1104 116B 11B6;B657;1104 116B 11B6; # (뙗; 뙗; 뙗; 뙗; 뙗; ) HANGUL SYLLABLE DDWAELH +B658;B658;1104 116B 11B7;B658;1104 116B 11B7; # (뙘; 뙘; 뙘; 뙘; 뙘; ) HANGUL SYLLABLE DDWAEM +B659;B659;1104 116B 11B8;B659;1104 116B 11B8; # (뙙; 뙙; 뙙; 뙙; 뙙; ) HANGUL SYLLABLE DDWAEB +B65A;B65A;1104 116B 11B9;B65A;1104 116B 11B9; # (뙚; 뙚; 뙚; 뙚; 뙚; ) HANGUL SYLLABLE DDWAEBS +B65B;B65B;1104 116B 11BA;B65B;1104 116B 11BA; # (뙛; 뙛; 뙛; 뙛; 뙛; ) HANGUL SYLLABLE DDWAES +B65C;B65C;1104 116B 11BB;B65C;1104 116B 11BB; # (뙜; 뙜; 뙜; 뙜; 뙜; ) HANGUL SYLLABLE DDWAESS +B65D;B65D;1104 116B 11BC;B65D;1104 116B 11BC; # (뙝; 뙝; 뙝; 뙝; 뙝; ) HANGUL SYLLABLE DDWAENG +B65E;B65E;1104 116B 11BD;B65E;1104 116B 11BD; # (뙞; 뙞; 뙞; 뙞; 뙞; ) HANGUL SYLLABLE DDWAEJ +B65F;B65F;1104 116B 11BE;B65F;1104 116B 11BE; # (뙟; 뙟; 뙟; 뙟; 뙟; ) HANGUL SYLLABLE DDWAEC +B660;B660;1104 116B 11BF;B660;1104 116B 11BF; # (뙠; 뙠; 뙠; 뙠; 뙠; ) HANGUL SYLLABLE DDWAEK +B661;B661;1104 116B 11C0;B661;1104 116B 11C0; # (뙡; 뙡; 뙡; 뙡; 뙡; ) HANGUL SYLLABLE DDWAET +B662;B662;1104 116B 11C1;B662;1104 116B 11C1; # (뙢; 뙢; 뙢; 뙢; 뙢; ) HANGUL SYLLABLE DDWAEP +B663;B663;1104 116B 11C2;B663;1104 116B 11C2; # (뙣; 뙣; 뙣; 뙣; 뙣; ) HANGUL SYLLABLE DDWAEH +B664;B664;1104 116C;B664;1104 116C; # (뙤; 뙤; 뙤; 뙤; 뙤; ) HANGUL SYLLABLE DDOE +B665;B665;1104 116C 11A8;B665;1104 116C 11A8; # (뙥; 뙥; 뙥; 뙥; 뙥; ) HANGUL SYLLABLE DDOEG +B666;B666;1104 116C 11A9;B666;1104 116C 11A9; # (뙦; 뙦; 뙦; 뙦; 뙦; ) HANGUL SYLLABLE DDOEGG +B667;B667;1104 116C 11AA;B667;1104 116C 11AA; # (뙧; 뙧; 뙧; 뙧; 뙧; ) HANGUL SYLLABLE DDOEGS +B668;B668;1104 116C 11AB;B668;1104 116C 11AB; # (뙨; 뙨; 뙨; 뙨; 뙨; ) HANGUL SYLLABLE DDOEN +B669;B669;1104 116C 11AC;B669;1104 116C 11AC; # (뙩; 뙩; 뙩; 뙩; 뙩; ) HANGUL SYLLABLE DDOENJ +B66A;B66A;1104 116C 11AD;B66A;1104 116C 11AD; # (뙪; 뙪; 뙪; 뙪; 뙪; ) HANGUL SYLLABLE DDOENH +B66B;B66B;1104 116C 11AE;B66B;1104 116C 11AE; # (뙫; 뙫; 뙫; 뙫; 뙫; ) HANGUL SYLLABLE DDOED +B66C;B66C;1104 116C 11AF;B66C;1104 116C 11AF; # (뙬; 뙬; 뙬; 뙬; 뙬; ) HANGUL SYLLABLE DDOEL +B66D;B66D;1104 116C 11B0;B66D;1104 116C 11B0; # (뙭; 뙭; 뙭; 뙭; 뙭; ) HANGUL SYLLABLE DDOELG +B66E;B66E;1104 116C 11B1;B66E;1104 116C 11B1; # (뙮; 뙮; 뙮; 뙮; 뙮; ) HANGUL SYLLABLE DDOELM +B66F;B66F;1104 116C 11B2;B66F;1104 116C 11B2; # (뙯; 뙯; 뙯; 뙯; 뙯; ) HANGUL SYLLABLE DDOELB +B670;B670;1104 116C 11B3;B670;1104 116C 11B3; # (뙰; 뙰; 뙰; 뙰; 뙰; ) HANGUL SYLLABLE DDOELS +B671;B671;1104 116C 11B4;B671;1104 116C 11B4; # (뙱; 뙱; 뙱; 뙱; 뙱; ) HANGUL SYLLABLE DDOELT +B672;B672;1104 116C 11B5;B672;1104 116C 11B5; # (뙲; 뙲; 뙲; 뙲; 뙲; ) HANGUL SYLLABLE DDOELP +B673;B673;1104 116C 11B6;B673;1104 116C 11B6; # (뙳; 뙳; 뙳; 뙳; 뙳; ) HANGUL SYLLABLE DDOELH +B674;B674;1104 116C 11B7;B674;1104 116C 11B7; # (뙴; 뙴; 뙴; 뙴; 뙴; ) HANGUL SYLLABLE DDOEM +B675;B675;1104 116C 11B8;B675;1104 116C 11B8; # (뙵; 뙵; 뙵; 뙵; 뙵; ) HANGUL SYLLABLE DDOEB +B676;B676;1104 116C 11B9;B676;1104 116C 11B9; # (뙶; 뙶; 뙶; 뙶; 뙶; ) HANGUL SYLLABLE DDOEBS +B677;B677;1104 116C 11BA;B677;1104 116C 11BA; # (뙷; 뙷; 뙷; 뙷; 뙷; ) HANGUL SYLLABLE DDOES +B678;B678;1104 116C 11BB;B678;1104 116C 11BB; # (뙸; 뙸; 뙸; 뙸; 뙸; ) HANGUL SYLLABLE DDOESS +B679;B679;1104 116C 11BC;B679;1104 116C 11BC; # (뙹; 뙹; 뙹; 뙹; 뙹; ) HANGUL SYLLABLE DDOENG +B67A;B67A;1104 116C 11BD;B67A;1104 116C 11BD; # (뙺; 뙺; 뙺; 뙺; 뙺; ) HANGUL SYLLABLE DDOEJ +B67B;B67B;1104 116C 11BE;B67B;1104 116C 11BE; # (뙻; 뙻; 뙻; 뙻; 뙻; ) HANGUL SYLLABLE DDOEC +B67C;B67C;1104 116C 11BF;B67C;1104 116C 11BF; # (뙼; 뙼; 뙼; 뙼; 뙼; ) HANGUL SYLLABLE DDOEK +B67D;B67D;1104 116C 11C0;B67D;1104 116C 11C0; # (뙽; 뙽; 뙽; 뙽; 뙽; ) HANGUL SYLLABLE DDOET +B67E;B67E;1104 116C 11C1;B67E;1104 116C 11C1; # (뙾; 뙾; 뙾; 뙾; 뙾; ) HANGUL SYLLABLE DDOEP +B67F;B67F;1104 116C 11C2;B67F;1104 116C 11C2; # (뙿; 뙿; 뙿; 뙿; 뙿; ) HANGUL SYLLABLE DDOEH +B680;B680;1104 116D;B680;1104 116D; # (뚀; 뚀; 뚀; 뚀; 뚀; ) HANGUL SYLLABLE DDYO +B681;B681;1104 116D 11A8;B681;1104 116D 11A8; # (뚁; 뚁; 뚁; 뚁; 뚁; ) HANGUL SYLLABLE DDYOG +B682;B682;1104 116D 11A9;B682;1104 116D 11A9; # (뚂; 뚂; 뚂; 뚂; 뚂; ) HANGUL SYLLABLE DDYOGG +B683;B683;1104 116D 11AA;B683;1104 116D 11AA; # (뚃; 뚃; 뚃; 뚃; 뚃; ) HANGUL SYLLABLE DDYOGS +B684;B684;1104 116D 11AB;B684;1104 116D 11AB; # (뚄; 뚄; 뚄; 뚄; 뚄; ) HANGUL SYLLABLE DDYON +B685;B685;1104 116D 11AC;B685;1104 116D 11AC; # (뚅; 뚅; 뚅; 뚅; 뚅; ) HANGUL SYLLABLE DDYONJ +B686;B686;1104 116D 11AD;B686;1104 116D 11AD; # (뚆; 뚆; 뚆; 뚆; 뚆; ) HANGUL SYLLABLE DDYONH +B687;B687;1104 116D 11AE;B687;1104 116D 11AE; # (뚇; 뚇; 뚇; 뚇; 뚇; ) HANGUL SYLLABLE DDYOD +B688;B688;1104 116D 11AF;B688;1104 116D 11AF; # (뚈; 뚈; 뚈; 뚈; 뚈; ) HANGUL SYLLABLE DDYOL +B689;B689;1104 116D 11B0;B689;1104 116D 11B0; # (뚉; 뚉; 뚉; 뚉; 뚉; ) HANGUL SYLLABLE DDYOLG +B68A;B68A;1104 116D 11B1;B68A;1104 116D 11B1; # (뚊; 뚊; 뚊; 뚊; 뚊; ) HANGUL SYLLABLE DDYOLM +B68B;B68B;1104 116D 11B2;B68B;1104 116D 11B2; # (뚋; 뚋; 뚋; 뚋; 뚋; ) HANGUL SYLLABLE DDYOLB +B68C;B68C;1104 116D 11B3;B68C;1104 116D 11B3; # (뚌; 뚌; 뚌; 뚌; 뚌; ) HANGUL SYLLABLE DDYOLS +B68D;B68D;1104 116D 11B4;B68D;1104 116D 11B4; # (뚍; 뚍; 뚍; 뚍; 뚍; ) HANGUL SYLLABLE DDYOLT +B68E;B68E;1104 116D 11B5;B68E;1104 116D 11B5; # (뚎; 뚎; 뚎; 뚎; 뚎; ) HANGUL SYLLABLE DDYOLP +B68F;B68F;1104 116D 11B6;B68F;1104 116D 11B6; # (뚏; 뚏; 뚏; 뚏; 뚏; ) HANGUL SYLLABLE DDYOLH +B690;B690;1104 116D 11B7;B690;1104 116D 11B7; # (뚐; 뚐; 뚐; 뚐; 뚐; ) HANGUL SYLLABLE DDYOM +B691;B691;1104 116D 11B8;B691;1104 116D 11B8; # (뚑; 뚑; 뚑; 뚑; 뚑; ) HANGUL SYLLABLE DDYOB +B692;B692;1104 116D 11B9;B692;1104 116D 11B9; # (뚒; 뚒; 뚒; 뚒; 뚒; ) HANGUL SYLLABLE DDYOBS +B693;B693;1104 116D 11BA;B693;1104 116D 11BA; # (뚓; 뚓; 뚓; 뚓; 뚓; ) HANGUL SYLLABLE DDYOS +B694;B694;1104 116D 11BB;B694;1104 116D 11BB; # (뚔; 뚔; 뚔; 뚔; 뚔; ) HANGUL SYLLABLE DDYOSS +B695;B695;1104 116D 11BC;B695;1104 116D 11BC; # (뚕; 뚕; 뚕; 뚕; 뚕; ) HANGUL SYLLABLE DDYONG +B696;B696;1104 116D 11BD;B696;1104 116D 11BD; # (뚖; 뚖; 뚖; 뚖; 뚖; ) HANGUL SYLLABLE DDYOJ +B697;B697;1104 116D 11BE;B697;1104 116D 11BE; # (뚗; 뚗; 뚗; 뚗; 뚗; ) HANGUL SYLLABLE DDYOC +B698;B698;1104 116D 11BF;B698;1104 116D 11BF; # (뚘; 뚘; 뚘; 뚘; 뚘; ) HANGUL SYLLABLE DDYOK +B699;B699;1104 116D 11C0;B699;1104 116D 11C0; # (뚙; 뚙; 뚙; 뚙; 뚙; ) HANGUL SYLLABLE DDYOT +B69A;B69A;1104 116D 11C1;B69A;1104 116D 11C1; # (뚚; 뚚; 뚚; 뚚; 뚚; ) HANGUL SYLLABLE DDYOP +B69B;B69B;1104 116D 11C2;B69B;1104 116D 11C2; # (뚛; 뚛; 뚛; 뚛; 뚛; ) HANGUL SYLLABLE DDYOH +B69C;B69C;1104 116E;B69C;1104 116E; # (뚜; 뚜; 뚜; 뚜; 뚜; ) HANGUL SYLLABLE DDU +B69D;B69D;1104 116E 11A8;B69D;1104 116E 11A8; # (뚝; 뚝; 뚝; 뚝; 뚝; ) HANGUL SYLLABLE DDUG +B69E;B69E;1104 116E 11A9;B69E;1104 116E 11A9; # (뚞; 뚞; 뚞; 뚞; 뚞; ) HANGUL SYLLABLE DDUGG +B69F;B69F;1104 116E 11AA;B69F;1104 116E 11AA; # (뚟; 뚟; 뚟; 뚟; 뚟; ) HANGUL SYLLABLE DDUGS +B6A0;B6A0;1104 116E 11AB;B6A0;1104 116E 11AB; # (뚠; 뚠; 뚠; 뚠; 뚠; ) HANGUL SYLLABLE DDUN +B6A1;B6A1;1104 116E 11AC;B6A1;1104 116E 11AC; # (뚡; 뚡; 뚡; 뚡; 뚡; ) HANGUL SYLLABLE DDUNJ +B6A2;B6A2;1104 116E 11AD;B6A2;1104 116E 11AD; # (뚢; 뚢; 뚢; 뚢; 뚢; ) HANGUL SYLLABLE DDUNH +B6A3;B6A3;1104 116E 11AE;B6A3;1104 116E 11AE; # (뚣; 뚣; 뚣; 뚣; 뚣; ) HANGUL SYLLABLE DDUD +B6A4;B6A4;1104 116E 11AF;B6A4;1104 116E 11AF; # (뚤; 뚤; 뚤; 뚤; 뚤; ) HANGUL SYLLABLE DDUL +B6A5;B6A5;1104 116E 11B0;B6A5;1104 116E 11B0; # (뚥; 뚥; 뚥; 뚥; 뚥; ) HANGUL SYLLABLE DDULG +B6A6;B6A6;1104 116E 11B1;B6A6;1104 116E 11B1; # (뚦; 뚦; 뚦; 뚦; 뚦; ) HANGUL SYLLABLE DDULM +B6A7;B6A7;1104 116E 11B2;B6A7;1104 116E 11B2; # (뚧; 뚧; 뚧; 뚧; 뚧; ) HANGUL SYLLABLE DDULB +B6A8;B6A8;1104 116E 11B3;B6A8;1104 116E 11B3; # (뚨; 뚨; 뚨; 뚨; 뚨; ) HANGUL SYLLABLE DDULS +B6A9;B6A9;1104 116E 11B4;B6A9;1104 116E 11B4; # (뚩; 뚩; 뚩; 뚩; 뚩; ) HANGUL SYLLABLE DDULT +B6AA;B6AA;1104 116E 11B5;B6AA;1104 116E 11B5; # (뚪; 뚪; 뚪; 뚪; 뚪; ) HANGUL SYLLABLE DDULP +B6AB;B6AB;1104 116E 11B6;B6AB;1104 116E 11B6; # (뚫; 뚫; 뚫; 뚫; 뚫; ) HANGUL SYLLABLE DDULH +B6AC;B6AC;1104 116E 11B7;B6AC;1104 116E 11B7; # (뚬; 뚬; 뚬; 뚬; 뚬; ) HANGUL SYLLABLE DDUM +B6AD;B6AD;1104 116E 11B8;B6AD;1104 116E 11B8; # (뚭; 뚭; 뚭; 뚭; 뚭; ) HANGUL SYLLABLE DDUB +B6AE;B6AE;1104 116E 11B9;B6AE;1104 116E 11B9; # (뚮; 뚮; 뚮; 뚮; 뚮; ) HANGUL SYLLABLE DDUBS +B6AF;B6AF;1104 116E 11BA;B6AF;1104 116E 11BA; # (뚯; 뚯; 뚯; 뚯; 뚯; ) HANGUL SYLLABLE DDUS +B6B0;B6B0;1104 116E 11BB;B6B0;1104 116E 11BB; # (뚰; 뚰; 뚰; 뚰; 뚰; ) HANGUL SYLLABLE DDUSS +B6B1;B6B1;1104 116E 11BC;B6B1;1104 116E 11BC; # (뚱; 뚱; 뚱; 뚱; 뚱; ) HANGUL SYLLABLE DDUNG +B6B2;B6B2;1104 116E 11BD;B6B2;1104 116E 11BD; # (뚲; 뚲; 뚲; 뚲; 뚲; ) HANGUL SYLLABLE DDUJ +B6B3;B6B3;1104 116E 11BE;B6B3;1104 116E 11BE; # (뚳; 뚳; 뚳; 뚳; 뚳; ) HANGUL SYLLABLE DDUC +B6B4;B6B4;1104 116E 11BF;B6B4;1104 116E 11BF; # (뚴; 뚴; 뚴; 뚴; 뚴; ) HANGUL SYLLABLE DDUK +B6B5;B6B5;1104 116E 11C0;B6B5;1104 116E 11C0; # (뚵; 뚵; 뚵; 뚵; 뚵; ) HANGUL SYLLABLE DDUT +B6B6;B6B6;1104 116E 11C1;B6B6;1104 116E 11C1; # (뚶; 뚶; 뚶; 뚶; 뚶; ) HANGUL SYLLABLE DDUP +B6B7;B6B7;1104 116E 11C2;B6B7;1104 116E 11C2; # (뚷; 뚷; 뚷; 뚷; 뚷; ) HANGUL SYLLABLE DDUH +B6B8;B6B8;1104 116F;B6B8;1104 116F; # (뚸; 뚸; 뚸; 뚸; 뚸; ) HANGUL SYLLABLE DDWEO +B6B9;B6B9;1104 116F 11A8;B6B9;1104 116F 11A8; # (뚹; 뚹; 뚹; 뚹; 뚹; ) HANGUL SYLLABLE DDWEOG +B6BA;B6BA;1104 116F 11A9;B6BA;1104 116F 11A9; # (뚺; 뚺; 뚺; 뚺; 뚺; ) HANGUL SYLLABLE DDWEOGG +B6BB;B6BB;1104 116F 11AA;B6BB;1104 116F 11AA; # (뚻; 뚻; 뚻; 뚻; 뚻; ) HANGUL SYLLABLE DDWEOGS +B6BC;B6BC;1104 116F 11AB;B6BC;1104 116F 11AB; # (뚼; 뚼; 뚼; 뚼; 뚼; ) HANGUL SYLLABLE DDWEON +B6BD;B6BD;1104 116F 11AC;B6BD;1104 116F 11AC; # (뚽; 뚽; 뚽; 뚽; 뚽; ) HANGUL SYLLABLE DDWEONJ +B6BE;B6BE;1104 116F 11AD;B6BE;1104 116F 11AD; # (뚾; 뚾; 뚾; 뚾; 뚾; ) HANGUL SYLLABLE DDWEONH +B6BF;B6BF;1104 116F 11AE;B6BF;1104 116F 11AE; # (뚿; 뚿; 뚿; 뚿; 뚿; ) HANGUL SYLLABLE DDWEOD +B6C0;B6C0;1104 116F 11AF;B6C0;1104 116F 11AF; # (뛀; 뛀; 뛀; 뛀; 뛀; ) HANGUL SYLLABLE DDWEOL +B6C1;B6C1;1104 116F 11B0;B6C1;1104 116F 11B0; # (뛁; 뛁; 뛁; 뛁; 뛁; ) HANGUL SYLLABLE DDWEOLG +B6C2;B6C2;1104 116F 11B1;B6C2;1104 116F 11B1; # (뛂; 뛂; 뛂; 뛂; 뛂; ) HANGUL SYLLABLE DDWEOLM +B6C3;B6C3;1104 116F 11B2;B6C3;1104 116F 11B2; # (뛃; 뛃; 뛃; 뛃; 뛃; ) HANGUL SYLLABLE DDWEOLB +B6C4;B6C4;1104 116F 11B3;B6C4;1104 116F 11B3; # (뛄; 뛄; 뛄; 뛄; 뛄; ) HANGUL SYLLABLE DDWEOLS +B6C5;B6C5;1104 116F 11B4;B6C5;1104 116F 11B4; # (뛅; 뛅; 뛅; 뛅; 뛅; ) HANGUL SYLLABLE DDWEOLT +B6C6;B6C6;1104 116F 11B5;B6C6;1104 116F 11B5; # (뛆; 뛆; 뛆; 뛆; 뛆; ) HANGUL SYLLABLE DDWEOLP +B6C7;B6C7;1104 116F 11B6;B6C7;1104 116F 11B6; # (뛇; 뛇; 뛇; 뛇; 뛇; ) HANGUL SYLLABLE DDWEOLH +B6C8;B6C8;1104 116F 11B7;B6C8;1104 116F 11B7; # (뛈; 뛈; 뛈; 뛈; 뛈; ) HANGUL SYLLABLE DDWEOM +B6C9;B6C9;1104 116F 11B8;B6C9;1104 116F 11B8; # (뛉; 뛉; 뛉; 뛉; 뛉; ) HANGUL SYLLABLE DDWEOB +B6CA;B6CA;1104 116F 11B9;B6CA;1104 116F 11B9; # (뛊; 뛊; 뛊; 뛊; 뛊; ) HANGUL SYLLABLE DDWEOBS +B6CB;B6CB;1104 116F 11BA;B6CB;1104 116F 11BA; # (뛋; 뛋; 뛋; 뛋; 뛋; ) HANGUL SYLLABLE DDWEOS +B6CC;B6CC;1104 116F 11BB;B6CC;1104 116F 11BB; # (뛌; 뛌; 뛌; 뛌; 뛌; ) HANGUL SYLLABLE DDWEOSS +B6CD;B6CD;1104 116F 11BC;B6CD;1104 116F 11BC; # (뛍; 뛍; 뛍; 뛍; 뛍; ) HANGUL SYLLABLE DDWEONG +B6CE;B6CE;1104 116F 11BD;B6CE;1104 116F 11BD; # (뛎; 뛎; 뛎; 뛎; 뛎; ) HANGUL SYLLABLE DDWEOJ +B6CF;B6CF;1104 116F 11BE;B6CF;1104 116F 11BE; # (뛏; 뛏; 뛏; 뛏; 뛏; ) HANGUL SYLLABLE DDWEOC +B6D0;B6D0;1104 116F 11BF;B6D0;1104 116F 11BF; # (뛐; 뛐; 뛐; 뛐; 뛐; ) HANGUL SYLLABLE DDWEOK +B6D1;B6D1;1104 116F 11C0;B6D1;1104 116F 11C0; # (뛑; 뛑; 뛑; 뛑; 뛑; ) HANGUL SYLLABLE DDWEOT +B6D2;B6D2;1104 116F 11C1;B6D2;1104 116F 11C1; # (뛒; 뛒; 뛒; 뛒; 뛒; ) HANGUL SYLLABLE DDWEOP +B6D3;B6D3;1104 116F 11C2;B6D3;1104 116F 11C2; # (뛓; 뛓; 뛓; 뛓; 뛓; ) HANGUL SYLLABLE DDWEOH +B6D4;B6D4;1104 1170;B6D4;1104 1170; # (뛔; 뛔; 뛔; 뛔; 뛔; ) HANGUL SYLLABLE DDWE +B6D5;B6D5;1104 1170 11A8;B6D5;1104 1170 11A8; # (뛕; 뛕; 뛕; 뛕; 뛕; ) HANGUL SYLLABLE DDWEG +B6D6;B6D6;1104 1170 11A9;B6D6;1104 1170 11A9; # (뛖; 뛖; 뛖; 뛖; 뛖; ) HANGUL SYLLABLE DDWEGG +B6D7;B6D7;1104 1170 11AA;B6D7;1104 1170 11AA; # (뛗; 뛗; 뛗; 뛗; 뛗; ) HANGUL SYLLABLE DDWEGS +B6D8;B6D8;1104 1170 11AB;B6D8;1104 1170 11AB; # (뛘; 뛘; 뛘; 뛘; 뛘; ) HANGUL SYLLABLE DDWEN +B6D9;B6D9;1104 1170 11AC;B6D9;1104 1170 11AC; # (뛙; 뛙; 뛙; 뛙; 뛙; ) HANGUL SYLLABLE DDWENJ +B6DA;B6DA;1104 1170 11AD;B6DA;1104 1170 11AD; # (뛚; 뛚; 뛚; 뛚; 뛚; ) HANGUL SYLLABLE DDWENH +B6DB;B6DB;1104 1170 11AE;B6DB;1104 1170 11AE; # (뛛; 뛛; 뛛; 뛛; 뛛; ) HANGUL SYLLABLE DDWED +B6DC;B6DC;1104 1170 11AF;B6DC;1104 1170 11AF; # (뛜; 뛜; 뛜; 뛜; 뛜; ) HANGUL SYLLABLE DDWEL +B6DD;B6DD;1104 1170 11B0;B6DD;1104 1170 11B0; # (뛝; 뛝; 뛝; 뛝; 뛝; ) HANGUL SYLLABLE DDWELG +B6DE;B6DE;1104 1170 11B1;B6DE;1104 1170 11B1; # (뛞; 뛞; 뛞; 뛞; 뛞; ) HANGUL SYLLABLE DDWELM +B6DF;B6DF;1104 1170 11B2;B6DF;1104 1170 11B2; # (뛟; 뛟; 뛟; 뛟; 뛟; ) HANGUL SYLLABLE DDWELB +B6E0;B6E0;1104 1170 11B3;B6E0;1104 1170 11B3; # (뛠; 뛠; 뛠; 뛠; 뛠; ) HANGUL SYLLABLE DDWELS +B6E1;B6E1;1104 1170 11B4;B6E1;1104 1170 11B4; # (뛡; 뛡; 뛡; 뛡; 뛡; ) HANGUL SYLLABLE DDWELT +B6E2;B6E2;1104 1170 11B5;B6E2;1104 1170 11B5; # (뛢; 뛢; 뛢; 뛢; 뛢; ) HANGUL SYLLABLE DDWELP +B6E3;B6E3;1104 1170 11B6;B6E3;1104 1170 11B6; # (뛣; 뛣; 뛣; 뛣; 뛣; ) HANGUL SYLLABLE DDWELH +B6E4;B6E4;1104 1170 11B7;B6E4;1104 1170 11B7; # (뛤; 뛤; 뛤; 뛤; 뛤; ) HANGUL SYLLABLE DDWEM +B6E5;B6E5;1104 1170 11B8;B6E5;1104 1170 11B8; # (뛥; 뛥; 뛥; 뛥; 뛥; ) HANGUL SYLLABLE DDWEB +B6E6;B6E6;1104 1170 11B9;B6E6;1104 1170 11B9; # (뛦; 뛦; 뛦; 뛦; 뛦; ) HANGUL SYLLABLE DDWEBS +B6E7;B6E7;1104 1170 11BA;B6E7;1104 1170 11BA; # (뛧; 뛧; 뛧; 뛧; 뛧; ) HANGUL SYLLABLE DDWES +B6E8;B6E8;1104 1170 11BB;B6E8;1104 1170 11BB; # (뛨; 뛨; 뛨; 뛨; 뛨; ) HANGUL SYLLABLE DDWESS +B6E9;B6E9;1104 1170 11BC;B6E9;1104 1170 11BC; # (뛩; 뛩; 뛩; 뛩; 뛩; ) HANGUL SYLLABLE DDWENG +B6EA;B6EA;1104 1170 11BD;B6EA;1104 1170 11BD; # (뛪; 뛪; 뛪; 뛪; 뛪; ) HANGUL SYLLABLE DDWEJ +B6EB;B6EB;1104 1170 11BE;B6EB;1104 1170 11BE; # (뛫; 뛫; 뛫; 뛫; 뛫; ) HANGUL SYLLABLE DDWEC +B6EC;B6EC;1104 1170 11BF;B6EC;1104 1170 11BF; # (뛬; 뛬; 뛬; 뛬; 뛬; ) HANGUL SYLLABLE DDWEK +B6ED;B6ED;1104 1170 11C0;B6ED;1104 1170 11C0; # (뛭; 뛭; 뛭; 뛭; 뛭; ) HANGUL SYLLABLE DDWET +B6EE;B6EE;1104 1170 11C1;B6EE;1104 1170 11C1; # (뛮; 뛮; 뛮; 뛮; 뛮; ) HANGUL SYLLABLE DDWEP +B6EF;B6EF;1104 1170 11C2;B6EF;1104 1170 11C2; # (뛯; 뛯; 뛯; 뛯; 뛯; ) HANGUL SYLLABLE DDWEH +B6F0;B6F0;1104 1171;B6F0;1104 1171; # (뛰; 뛰; 뛰; 뛰; 뛰; ) HANGUL SYLLABLE DDWI +B6F1;B6F1;1104 1171 11A8;B6F1;1104 1171 11A8; # (뛱; 뛱; 뛱; 뛱; 뛱; ) HANGUL SYLLABLE DDWIG +B6F2;B6F2;1104 1171 11A9;B6F2;1104 1171 11A9; # (뛲; 뛲; 뛲; 뛲; 뛲; ) HANGUL SYLLABLE DDWIGG +B6F3;B6F3;1104 1171 11AA;B6F3;1104 1171 11AA; # (뛳; 뛳; 뛳; 뛳; 뛳; ) HANGUL SYLLABLE DDWIGS +B6F4;B6F4;1104 1171 11AB;B6F4;1104 1171 11AB; # (뛴; 뛴; 뛴; 뛴; 뛴; ) HANGUL SYLLABLE DDWIN +B6F5;B6F5;1104 1171 11AC;B6F5;1104 1171 11AC; # (뛵; 뛵; 뛵; 뛵; 뛵; ) HANGUL SYLLABLE DDWINJ +B6F6;B6F6;1104 1171 11AD;B6F6;1104 1171 11AD; # (뛶; 뛶; 뛶; 뛶; 뛶; ) HANGUL SYLLABLE DDWINH +B6F7;B6F7;1104 1171 11AE;B6F7;1104 1171 11AE; # (뛷; 뛷; 뛷; 뛷; 뛷; ) HANGUL SYLLABLE DDWID +B6F8;B6F8;1104 1171 11AF;B6F8;1104 1171 11AF; # (뛸; 뛸; 뛸; 뛸; 뛸; ) HANGUL SYLLABLE DDWIL +B6F9;B6F9;1104 1171 11B0;B6F9;1104 1171 11B0; # (뛹; 뛹; 뛹; 뛹; 뛹; ) HANGUL SYLLABLE DDWILG +B6FA;B6FA;1104 1171 11B1;B6FA;1104 1171 11B1; # (뛺; 뛺; 뛺; 뛺; 뛺; ) HANGUL SYLLABLE DDWILM +B6FB;B6FB;1104 1171 11B2;B6FB;1104 1171 11B2; # (뛻; 뛻; 뛻; 뛻; 뛻; ) HANGUL SYLLABLE DDWILB +B6FC;B6FC;1104 1171 11B3;B6FC;1104 1171 11B3; # (뛼; 뛼; 뛼; 뛼; 뛼; ) HANGUL SYLLABLE DDWILS +B6FD;B6FD;1104 1171 11B4;B6FD;1104 1171 11B4; # (뛽; 뛽; 뛽; 뛽; 뛽; ) HANGUL SYLLABLE DDWILT +B6FE;B6FE;1104 1171 11B5;B6FE;1104 1171 11B5; # (뛾; 뛾; 뛾; 뛾; 뛾; ) HANGUL SYLLABLE DDWILP +B6FF;B6FF;1104 1171 11B6;B6FF;1104 1171 11B6; # (뛿; 뛿; 뛿; 뛿; 뛿; ) HANGUL SYLLABLE DDWILH +B700;B700;1104 1171 11B7;B700;1104 1171 11B7; # (뜀; 뜀; 뜀; 뜀; 뜀; ) HANGUL SYLLABLE DDWIM +B701;B701;1104 1171 11B8;B701;1104 1171 11B8; # (뜁; 뜁; 뜁; 뜁; 뜁; ) HANGUL SYLLABLE DDWIB +B702;B702;1104 1171 11B9;B702;1104 1171 11B9; # (뜂; 뜂; 뜂; 뜂; 뜂; ) HANGUL SYLLABLE DDWIBS +B703;B703;1104 1171 11BA;B703;1104 1171 11BA; # (뜃; 뜃; 뜃; 뜃; 뜃; ) HANGUL SYLLABLE DDWIS +B704;B704;1104 1171 11BB;B704;1104 1171 11BB; # (뜄; 뜄; 뜄; 뜄; 뜄; ) HANGUL SYLLABLE DDWISS +B705;B705;1104 1171 11BC;B705;1104 1171 11BC; # (뜅; 뜅; 뜅; 뜅; 뜅; ) HANGUL SYLLABLE DDWING +B706;B706;1104 1171 11BD;B706;1104 1171 11BD; # (뜆; 뜆; 뜆; 뜆; 뜆; ) HANGUL SYLLABLE DDWIJ +B707;B707;1104 1171 11BE;B707;1104 1171 11BE; # (뜇; 뜇; 뜇; 뜇; 뜇; ) HANGUL SYLLABLE DDWIC +B708;B708;1104 1171 11BF;B708;1104 1171 11BF; # (뜈; 뜈; 뜈; 뜈; 뜈; ) HANGUL SYLLABLE DDWIK +B709;B709;1104 1171 11C0;B709;1104 1171 11C0; # (뜉; 뜉; 뜉; 뜉; 뜉; ) HANGUL SYLLABLE DDWIT +B70A;B70A;1104 1171 11C1;B70A;1104 1171 11C1; # (뜊; 뜊; 뜊; 뜊; 뜊; ) HANGUL SYLLABLE DDWIP +B70B;B70B;1104 1171 11C2;B70B;1104 1171 11C2; # (뜋; 뜋; 뜋; 뜋; 뜋; ) HANGUL SYLLABLE DDWIH +B70C;B70C;1104 1172;B70C;1104 1172; # (뜌; 뜌; 뜌; 뜌; 뜌; ) HANGUL SYLLABLE DDYU +B70D;B70D;1104 1172 11A8;B70D;1104 1172 11A8; # (뜍; 뜍; 뜍; 뜍; 뜍; ) HANGUL SYLLABLE DDYUG +B70E;B70E;1104 1172 11A9;B70E;1104 1172 11A9; # (뜎; 뜎; 뜎; 뜎; 뜎; ) HANGUL SYLLABLE DDYUGG +B70F;B70F;1104 1172 11AA;B70F;1104 1172 11AA; # (뜏; 뜏; 뜏; 뜏; 뜏; ) HANGUL SYLLABLE DDYUGS +B710;B710;1104 1172 11AB;B710;1104 1172 11AB; # (뜐; 뜐; 뜐; 뜐; 뜐; ) HANGUL SYLLABLE DDYUN +B711;B711;1104 1172 11AC;B711;1104 1172 11AC; # (뜑; 뜑; 뜑; 뜑; 뜑; ) HANGUL SYLLABLE DDYUNJ +B712;B712;1104 1172 11AD;B712;1104 1172 11AD; # (뜒; 뜒; 뜒; 뜒; 뜒; ) HANGUL SYLLABLE DDYUNH +B713;B713;1104 1172 11AE;B713;1104 1172 11AE; # (뜓; 뜓; 뜓; 뜓; 뜓; ) HANGUL SYLLABLE DDYUD +B714;B714;1104 1172 11AF;B714;1104 1172 11AF; # (뜔; 뜔; 뜔; 뜔; 뜔; ) HANGUL SYLLABLE DDYUL +B715;B715;1104 1172 11B0;B715;1104 1172 11B0; # (뜕; 뜕; 뜕; 뜕; 뜕; ) HANGUL SYLLABLE DDYULG +B716;B716;1104 1172 11B1;B716;1104 1172 11B1; # (뜖; 뜖; 뜖; 뜖; 뜖; ) HANGUL SYLLABLE DDYULM +B717;B717;1104 1172 11B2;B717;1104 1172 11B2; # (뜗; 뜗; 뜗; 뜗; 뜗; ) HANGUL SYLLABLE DDYULB +B718;B718;1104 1172 11B3;B718;1104 1172 11B3; # (뜘; 뜘; 뜘; 뜘; 뜘; ) HANGUL SYLLABLE DDYULS +B719;B719;1104 1172 11B4;B719;1104 1172 11B4; # (뜙; 뜙; 뜙; 뜙; 뜙; ) HANGUL SYLLABLE DDYULT +B71A;B71A;1104 1172 11B5;B71A;1104 1172 11B5; # (뜚; 뜚; 뜚; 뜚; 뜚; ) HANGUL SYLLABLE DDYULP +B71B;B71B;1104 1172 11B6;B71B;1104 1172 11B6; # (뜛; 뜛; 뜛; 뜛; 뜛; ) HANGUL SYLLABLE DDYULH +B71C;B71C;1104 1172 11B7;B71C;1104 1172 11B7; # (뜜; 뜜; 뜜; 뜜; 뜜; ) HANGUL SYLLABLE DDYUM +B71D;B71D;1104 1172 11B8;B71D;1104 1172 11B8; # (뜝; 뜝; 뜝; 뜝; 뜝; ) HANGUL SYLLABLE DDYUB +B71E;B71E;1104 1172 11B9;B71E;1104 1172 11B9; # (뜞; 뜞; 뜞; 뜞; 뜞; ) HANGUL SYLLABLE DDYUBS +B71F;B71F;1104 1172 11BA;B71F;1104 1172 11BA; # (뜟; 뜟; 뜟; 뜟; 뜟; ) HANGUL SYLLABLE DDYUS +B720;B720;1104 1172 11BB;B720;1104 1172 11BB; # (뜠; 뜠; 뜠; 뜠; 뜠; ) HANGUL SYLLABLE DDYUSS +B721;B721;1104 1172 11BC;B721;1104 1172 11BC; # (뜡; 뜡; 뜡; 뜡; 뜡; ) HANGUL SYLLABLE DDYUNG +B722;B722;1104 1172 11BD;B722;1104 1172 11BD; # (뜢; 뜢; 뜢; 뜢; 뜢; ) HANGUL SYLLABLE DDYUJ +B723;B723;1104 1172 11BE;B723;1104 1172 11BE; # (뜣; 뜣; 뜣; 뜣; 뜣; ) HANGUL SYLLABLE DDYUC +B724;B724;1104 1172 11BF;B724;1104 1172 11BF; # (뜤; 뜤; 뜤; 뜤; 뜤; ) HANGUL SYLLABLE DDYUK +B725;B725;1104 1172 11C0;B725;1104 1172 11C0; # (뜥; 뜥; 뜥; 뜥; 뜥; ) HANGUL SYLLABLE DDYUT +B726;B726;1104 1172 11C1;B726;1104 1172 11C1; # (뜦; 뜦; 뜦; 뜦; 뜦; ) HANGUL SYLLABLE DDYUP +B727;B727;1104 1172 11C2;B727;1104 1172 11C2; # (뜧; 뜧; 뜧; 뜧; 뜧; ) HANGUL SYLLABLE DDYUH +B728;B728;1104 1173;B728;1104 1173; # (뜨; 뜨; 뜨; 뜨; 뜨; ) HANGUL SYLLABLE DDEU +B729;B729;1104 1173 11A8;B729;1104 1173 11A8; # (뜩; 뜩; 뜩; 뜩; 뜩; ) HANGUL SYLLABLE DDEUG +B72A;B72A;1104 1173 11A9;B72A;1104 1173 11A9; # (뜪; 뜪; 뜪; 뜪; 뜪; ) HANGUL SYLLABLE DDEUGG +B72B;B72B;1104 1173 11AA;B72B;1104 1173 11AA; # (뜫; 뜫; 뜫; 뜫; 뜫; ) HANGUL SYLLABLE DDEUGS +B72C;B72C;1104 1173 11AB;B72C;1104 1173 11AB; # (뜬; 뜬; 뜬; 뜬; 뜬; ) HANGUL SYLLABLE DDEUN +B72D;B72D;1104 1173 11AC;B72D;1104 1173 11AC; # (뜭; 뜭; 뜭; 뜭; 뜭; ) HANGUL SYLLABLE DDEUNJ +B72E;B72E;1104 1173 11AD;B72E;1104 1173 11AD; # (뜮; 뜮; 뜮; 뜮; 뜮; ) HANGUL SYLLABLE DDEUNH +B72F;B72F;1104 1173 11AE;B72F;1104 1173 11AE; # (뜯; 뜯; 뜯; 뜯; 뜯; ) HANGUL SYLLABLE DDEUD +B730;B730;1104 1173 11AF;B730;1104 1173 11AF; # (뜰; 뜰; 뜰; 뜰; 뜰; ) HANGUL SYLLABLE DDEUL +B731;B731;1104 1173 11B0;B731;1104 1173 11B0; # (뜱; 뜱; 뜱; 뜱; 뜱; ) HANGUL SYLLABLE DDEULG +B732;B732;1104 1173 11B1;B732;1104 1173 11B1; # (뜲; 뜲; 뜲; 뜲; 뜲; ) HANGUL SYLLABLE DDEULM +B733;B733;1104 1173 11B2;B733;1104 1173 11B2; # (뜳; 뜳; 뜳; 뜳; 뜳; ) HANGUL SYLLABLE DDEULB +B734;B734;1104 1173 11B3;B734;1104 1173 11B3; # (뜴; 뜴; 뜴; 뜴; 뜴; ) HANGUL SYLLABLE DDEULS +B735;B735;1104 1173 11B4;B735;1104 1173 11B4; # (뜵; 뜵; 뜵; 뜵; 뜵; ) HANGUL SYLLABLE DDEULT +B736;B736;1104 1173 11B5;B736;1104 1173 11B5; # (뜶; 뜶; 뜶; 뜶; 뜶; ) HANGUL SYLLABLE DDEULP +B737;B737;1104 1173 11B6;B737;1104 1173 11B6; # (뜷; 뜷; 뜷; 뜷; 뜷; ) HANGUL SYLLABLE DDEULH +B738;B738;1104 1173 11B7;B738;1104 1173 11B7; # (뜸; 뜸; 뜸; 뜸; 뜸; ) HANGUL SYLLABLE DDEUM +B739;B739;1104 1173 11B8;B739;1104 1173 11B8; # (뜹; 뜹; 뜹; 뜹; 뜹; ) HANGUL SYLLABLE DDEUB +B73A;B73A;1104 1173 11B9;B73A;1104 1173 11B9; # (뜺; 뜺; 뜺; 뜺; 뜺; ) HANGUL SYLLABLE DDEUBS +B73B;B73B;1104 1173 11BA;B73B;1104 1173 11BA; # (뜻; 뜻; 뜻; 뜻; 뜻; ) HANGUL SYLLABLE DDEUS +B73C;B73C;1104 1173 11BB;B73C;1104 1173 11BB; # (뜼; 뜼; 뜼; 뜼; 뜼; ) HANGUL SYLLABLE DDEUSS +B73D;B73D;1104 1173 11BC;B73D;1104 1173 11BC; # (뜽; 뜽; 뜽; 뜽; 뜽; ) HANGUL SYLLABLE DDEUNG +B73E;B73E;1104 1173 11BD;B73E;1104 1173 11BD; # (뜾; 뜾; 뜾; 뜾; 뜾; ) HANGUL SYLLABLE DDEUJ +B73F;B73F;1104 1173 11BE;B73F;1104 1173 11BE; # (뜿; 뜿; 뜿; 뜿; 뜿; ) HANGUL SYLLABLE DDEUC +B740;B740;1104 1173 11BF;B740;1104 1173 11BF; # (띀; 띀; 띀; 띀; 띀; ) HANGUL SYLLABLE DDEUK +B741;B741;1104 1173 11C0;B741;1104 1173 11C0; # (띁; 띁; 띁; 띁; 띁; ) HANGUL SYLLABLE DDEUT +B742;B742;1104 1173 11C1;B742;1104 1173 11C1; # (띂; 띂; 띂; 띂; 띂; ) HANGUL SYLLABLE DDEUP +B743;B743;1104 1173 11C2;B743;1104 1173 11C2; # (띃; 띃; 띃; 띃; 띃; ) HANGUL SYLLABLE DDEUH +B744;B744;1104 1174;B744;1104 1174; # (띄; 띄; 띄; 띄; 띄; ) HANGUL SYLLABLE DDYI +B745;B745;1104 1174 11A8;B745;1104 1174 11A8; # (띅; 띅; 띅; 띅; 띅; ) HANGUL SYLLABLE DDYIG +B746;B746;1104 1174 11A9;B746;1104 1174 11A9; # (띆; 띆; 띆; 띆; 띆; ) HANGUL SYLLABLE DDYIGG +B747;B747;1104 1174 11AA;B747;1104 1174 11AA; # (띇; 띇; 띇; 띇; 띇; ) HANGUL SYLLABLE DDYIGS +B748;B748;1104 1174 11AB;B748;1104 1174 11AB; # (띈; 띈; 띈; 띈; 띈; ) HANGUL SYLLABLE DDYIN +B749;B749;1104 1174 11AC;B749;1104 1174 11AC; # (띉; 띉; 띉; 띉; 띉; ) HANGUL SYLLABLE DDYINJ +B74A;B74A;1104 1174 11AD;B74A;1104 1174 11AD; # (띊; 띊; 띊; 띊; 띊; ) HANGUL SYLLABLE DDYINH +B74B;B74B;1104 1174 11AE;B74B;1104 1174 11AE; # (띋; 띋; 띋; 띋; 띋; ) HANGUL SYLLABLE DDYID +B74C;B74C;1104 1174 11AF;B74C;1104 1174 11AF; # (띌; 띌; 띌; 띌; 띌; ) HANGUL SYLLABLE DDYIL +B74D;B74D;1104 1174 11B0;B74D;1104 1174 11B0; # (띍; 띍; 띍; 띍; 띍; ) HANGUL SYLLABLE DDYILG +B74E;B74E;1104 1174 11B1;B74E;1104 1174 11B1; # (띎; 띎; 띎; 띎; 띎; ) HANGUL SYLLABLE DDYILM +B74F;B74F;1104 1174 11B2;B74F;1104 1174 11B2; # (띏; 띏; 띏; 띏; 띏; ) HANGUL SYLLABLE DDYILB +B750;B750;1104 1174 11B3;B750;1104 1174 11B3; # (띐; 띐; 띐; 띐; 띐; ) HANGUL SYLLABLE DDYILS +B751;B751;1104 1174 11B4;B751;1104 1174 11B4; # (띑; 띑; 띑; 띑; 띑; ) HANGUL SYLLABLE DDYILT +B752;B752;1104 1174 11B5;B752;1104 1174 11B5; # (띒; 띒; 띒; 띒; 띒; ) HANGUL SYLLABLE DDYILP +B753;B753;1104 1174 11B6;B753;1104 1174 11B6; # (띓; 띓; 띓; 띓; 띓; ) HANGUL SYLLABLE DDYILH +B754;B754;1104 1174 11B7;B754;1104 1174 11B7; # (띔; 띔; 띔; 띔; 띔; ) HANGUL SYLLABLE DDYIM +B755;B755;1104 1174 11B8;B755;1104 1174 11B8; # (띕; 띕; 띕; 띕; 띕; ) HANGUL SYLLABLE DDYIB +B756;B756;1104 1174 11B9;B756;1104 1174 11B9; # (띖; 띖; 띖; 띖; 띖; ) HANGUL SYLLABLE DDYIBS +B757;B757;1104 1174 11BA;B757;1104 1174 11BA; # (띗; 띗; 띗; 띗; 띗; ) HANGUL SYLLABLE DDYIS +B758;B758;1104 1174 11BB;B758;1104 1174 11BB; # (띘; 띘; 띘; 띘; 띘; ) HANGUL SYLLABLE DDYISS +B759;B759;1104 1174 11BC;B759;1104 1174 11BC; # (띙; 띙; 띙; 띙; 띙; ) HANGUL SYLLABLE DDYING +B75A;B75A;1104 1174 11BD;B75A;1104 1174 11BD; # (띚; 띚; 띚; 띚; 띚; ) HANGUL SYLLABLE DDYIJ +B75B;B75B;1104 1174 11BE;B75B;1104 1174 11BE; # (띛; 띛; 띛; 띛; 띛; ) HANGUL SYLLABLE DDYIC +B75C;B75C;1104 1174 11BF;B75C;1104 1174 11BF; # (띜; 띜; 띜; 띜; 띜; ) HANGUL SYLLABLE DDYIK +B75D;B75D;1104 1174 11C0;B75D;1104 1174 11C0; # (띝; 띝; 띝; 띝; 띝; ) HANGUL SYLLABLE DDYIT +B75E;B75E;1104 1174 11C1;B75E;1104 1174 11C1; # (띞; 띞; 띞; 띞; 띞; ) HANGUL SYLLABLE DDYIP +B75F;B75F;1104 1174 11C2;B75F;1104 1174 11C2; # (띟; 띟; 띟; 띟; 띟; ) HANGUL SYLLABLE DDYIH +B760;B760;1104 1175;B760;1104 1175; # (띠; 띠; 띠; 띠; 띠; ) HANGUL SYLLABLE DDI +B761;B761;1104 1175 11A8;B761;1104 1175 11A8; # (띡; 띡; 띡; 띡; 띡; ) HANGUL SYLLABLE DDIG +B762;B762;1104 1175 11A9;B762;1104 1175 11A9; # (띢; 띢; 띢; 띢; 띢; ) HANGUL SYLLABLE DDIGG +B763;B763;1104 1175 11AA;B763;1104 1175 11AA; # (띣; 띣; 띣; 띣; 띣; ) HANGUL SYLLABLE DDIGS +B764;B764;1104 1175 11AB;B764;1104 1175 11AB; # (띤; 띤; 띤; 띤; 띤; ) HANGUL SYLLABLE DDIN +B765;B765;1104 1175 11AC;B765;1104 1175 11AC; # (띥; 띥; 띥; 띥; 띥; ) HANGUL SYLLABLE DDINJ +B766;B766;1104 1175 11AD;B766;1104 1175 11AD; # (띦; 띦; 띦; 띦; 띦; ) HANGUL SYLLABLE DDINH +B767;B767;1104 1175 11AE;B767;1104 1175 11AE; # (띧; 띧; 띧; 띧; 띧; ) HANGUL SYLLABLE DDID +B768;B768;1104 1175 11AF;B768;1104 1175 11AF; # (띨; 띨; 띨; 띨; 띨; ) HANGUL SYLLABLE DDIL +B769;B769;1104 1175 11B0;B769;1104 1175 11B0; # (띩; 띩; 띩; 띩; 띩; ) HANGUL SYLLABLE DDILG +B76A;B76A;1104 1175 11B1;B76A;1104 1175 11B1; # (띪; 띪; 띪; 띪; 띪; ) HANGUL SYLLABLE DDILM +B76B;B76B;1104 1175 11B2;B76B;1104 1175 11B2; # (띫; 띫; 띫; 띫; 띫; ) HANGUL SYLLABLE DDILB +B76C;B76C;1104 1175 11B3;B76C;1104 1175 11B3; # (띬; 띬; 띬; 띬; 띬; ) HANGUL SYLLABLE DDILS +B76D;B76D;1104 1175 11B4;B76D;1104 1175 11B4; # (띭; 띭; 띭; 띭; 띭; ) HANGUL SYLLABLE DDILT +B76E;B76E;1104 1175 11B5;B76E;1104 1175 11B5; # (띮; 띮; 띮; 띮; 띮; ) HANGUL SYLLABLE DDILP +B76F;B76F;1104 1175 11B6;B76F;1104 1175 11B6; # (띯; 띯; 띯; 띯; 띯; ) HANGUL SYLLABLE DDILH +B770;B770;1104 1175 11B7;B770;1104 1175 11B7; # (띰; 띰; 띰; 띰; 띰; ) HANGUL SYLLABLE DDIM +B771;B771;1104 1175 11B8;B771;1104 1175 11B8; # (띱; 띱; 띱; 띱; 띱; ) HANGUL SYLLABLE DDIB +B772;B772;1104 1175 11B9;B772;1104 1175 11B9; # (띲; 띲; 띲; 띲; 띲; ) HANGUL SYLLABLE DDIBS +B773;B773;1104 1175 11BA;B773;1104 1175 11BA; # (띳; 띳; 띳; 띳; 띳; ) HANGUL SYLLABLE DDIS +B774;B774;1104 1175 11BB;B774;1104 1175 11BB; # (띴; 띴; 띴; 띴; 띴; ) HANGUL SYLLABLE DDISS +B775;B775;1104 1175 11BC;B775;1104 1175 11BC; # (띵; 띵; 띵; 띵; 띵; ) HANGUL SYLLABLE DDING +B776;B776;1104 1175 11BD;B776;1104 1175 11BD; # (띶; 띶; 띶; 띶; 띶; ) HANGUL SYLLABLE DDIJ +B777;B777;1104 1175 11BE;B777;1104 1175 11BE; # (띷; 띷; 띷; 띷; 띷; ) HANGUL SYLLABLE DDIC +B778;B778;1104 1175 11BF;B778;1104 1175 11BF; # (띸; 띸; 띸; 띸; 띸; ) HANGUL SYLLABLE DDIK +B779;B779;1104 1175 11C0;B779;1104 1175 11C0; # (띹; 띹; 띹; 띹; 띹; ) HANGUL SYLLABLE DDIT +B77A;B77A;1104 1175 11C1;B77A;1104 1175 11C1; # (띺; 띺; 띺; 띺; 띺; ) HANGUL SYLLABLE DDIP +B77B;B77B;1104 1175 11C2;B77B;1104 1175 11C2; # (띻; 띻; 띻; 띻; 띻; ) HANGUL SYLLABLE DDIH +B77C;B77C;1105 1161;B77C;1105 1161; # (라; 라; 라; 라; 라; ) HANGUL SYLLABLE RA +B77D;B77D;1105 1161 11A8;B77D;1105 1161 11A8; # (락; 락; 락; 락; 락; ) HANGUL SYLLABLE RAG +B77E;B77E;1105 1161 11A9;B77E;1105 1161 11A9; # (띾; 띾; 띾; 띾; 띾; ) HANGUL SYLLABLE RAGG +B77F;B77F;1105 1161 11AA;B77F;1105 1161 11AA; # (띿; 띿; 띿; 띿; 띿; ) HANGUL SYLLABLE RAGS +B780;B780;1105 1161 11AB;B780;1105 1161 11AB; # (란; 란; 란; 란; 란; ) HANGUL SYLLABLE RAN +B781;B781;1105 1161 11AC;B781;1105 1161 11AC; # (랁; 랁; 랁; 랁; 랁; ) HANGUL SYLLABLE RANJ +B782;B782;1105 1161 11AD;B782;1105 1161 11AD; # (랂; 랂; 랂; 랂; 랂; ) HANGUL SYLLABLE RANH +B783;B783;1105 1161 11AE;B783;1105 1161 11AE; # (랃; 랃; 랃; 랃; 랃; ) HANGUL SYLLABLE RAD +B784;B784;1105 1161 11AF;B784;1105 1161 11AF; # (랄; 랄; 랄; 랄; 랄; ) HANGUL SYLLABLE RAL +B785;B785;1105 1161 11B0;B785;1105 1161 11B0; # (랅; 랅; 랅; 랅; 랅; ) HANGUL SYLLABLE RALG +B786;B786;1105 1161 11B1;B786;1105 1161 11B1; # (랆; 랆; 랆; 랆; 랆; ) HANGUL SYLLABLE RALM +B787;B787;1105 1161 11B2;B787;1105 1161 11B2; # (랇; 랇; 랇; 랇; 랇; ) HANGUL SYLLABLE RALB +B788;B788;1105 1161 11B3;B788;1105 1161 11B3; # (랈; 랈; 랈; 랈; 랈; ) HANGUL SYLLABLE RALS +B789;B789;1105 1161 11B4;B789;1105 1161 11B4; # (랉; 랉; 랉; 랉; 랉; ) HANGUL SYLLABLE RALT +B78A;B78A;1105 1161 11B5;B78A;1105 1161 11B5; # (랊; 랊; 랊; 랊; 랊; ) HANGUL SYLLABLE RALP +B78B;B78B;1105 1161 11B6;B78B;1105 1161 11B6; # (랋; 랋; 랋; 랋; 랋; ) HANGUL SYLLABLE RALH +B78C;B78C;1105 1161 11B7;B78C;1105 1161 11B7; # (람; 람; 람; 람; 람; ) HANGUL SYLLABLE RAM +B78D;B78D;1105 1161 11B8;B78D;1105 1161 11B8; # (랍; 랍; 랍; 랍; 랍; ) HANGUL SYLLABLE RAB +B78E;B78E;1105 1161 11B9;B78E;1105 1161 11B9; # (랎; 랎; 랎; 랎; 랎; ) HANGUL SYLLABLE RABS +B78F;B78F;1105 1161 11BA;B78F;1105 1161 11BA; # (랏; 랏; 랏; 랏; 랏; ) HANGUL SYLLABLE RAS +B790;B790;1105 1161 11BB;B790;1105 1161 11BB; # (랐; 랐; 랐; 랐; 랐; ) HANGUL SYLLABLE RASS +B791;B791;1105 1161 11BC;B791;1105 1161 11BC; # (랑; 랑; 랑; 랑; 랑; ) HANGUL SYLLABLE RANG +B792;B792;1105 1161 11BD;B792;1105 1161 11BD; # (랒; 랒; 랒; 랒; 랒; ) HANGUL SYLLABLE RAJ +B793;B793;1105 1161 11BE;B793;1105 1161 11BE; # (랓; 랓; 랓; 랓; 랓; ) HANGUL SYLLABLE RAC +B794;B794;1105 1161 11BF;B794;1105 1161 11BF; # (랔; 랔; 랔; 랔; 랔; ) HANGUL SYLLABLE RAK +B795;B795;1105 1161 11C0;B795;1105 1161 11C0; # (랕; 랕; 랕; 랕; 랕; ) HANGUL SYLLABLE RAT +B796;B796;1105 1161 11C1;B796;1105 1161 11C1; # (랖; 랖; 랖; 랖; 랖; ) HANGUL SYLLABLE RAP +B797;B797;1105 1161 11C2;B797;1105 1161 11C2; # (랗; 랗; 랗; 랗; 랗; ) HANGUL SYLLABLE RAH +B798;B798;1105 1162;B798;1105 1162; # (래; 래; 래; 래; 래; ) HANGUL SYLLABLE RAE +B799;B799;1105 1162 11A8;B799;1105 1162 11A8; # (랙; 랙; 랙; 랙; 랙; ) HANGUL SYLLABLE RAEG +B79A;B79A;1105 1162 11A9;B79A;1105 1162 11A9; # (랚; 랚; 랚; 랚; 랚; ) HANGUL SYLLABLE RAEGG +B79B;B79B;1105 1162 11AA;B79B;1105 1162 11AA; # (랛; 랛; 랛; 랛; 랛; ) HANGUL SYLLABLE RAEGS +B79C;B79C;1105 1162 11AB;B79C;1105 1162 11AB; # (랜; 랜; 랜; 랜; 랜; ) HANGUL SYLLABLE RAEN +B79D;B79D;1105 1162 11AC;B79D;1105 1162 11AC; # (랝; 랝; 랝; 랝; 랝; ) HANGUL SYLLABLE RAENJ +B79E;B79E;1105 1162 11AD;B79E;1105 1162 11AD; # (랞; 랞; 랞; 랞; 랞; ) HANGUL SYLLABLE RAENH +B79F;B79F;1105 1162 11AE;B79F;1105 1162 11AE; # (랟; 랟; 랟; 랟; 랟; ) HANGUL SYLLABLE RAED +B7A0;B7A0;1105 1162 11AF;B7A0;1105 1162 11AF; # (랠; 랠; 랠; 랠; 랠; ) HANGUL SYLLABLE RAEL +B7A1;B7A1;1105 1162 11B0;B7A1;1105 1162 11B0; # (랡; 랡; 랡; 랡; 랡; ) HANGUL SYLLABLE RAELG +B7A2;B7A2;1105 1162 11B1;B7A2;1105 1162 11B1; # (랢; 랢; 랢; 랢; 랢; ) HANGUL SYLLABLE RAELM +B7A3;B7A3;1105 1162 11B2;B7A3;1105 1162 11B2; # (랣; 랣; 랣; 랣; 랣; ) HANGUL SYLLABLE RAELB +B7A4;B7A4;1105 1162 11B3;B7A4;1105 1162 11B3; # (랤; 랤; 랤; 랤; 랤; ) HANGUL SYLLABLE RAELS +B7A5;B7A5;1105 1162 11B4;B7A5;1105 1162 11B4; # (랥; 랥; 랥; 랥; 랥; ) HANGUL SYLLABLE RAELT +B7A6;B7A6;1105 1162 11B5;B7A6;1105 1162 11B5; # (랦; 랦; 랦; 랦; 랦; ) HANGUL SYLLABLE RAELP +B7A7;B7A7;1105 1162 11B6;B7A7;1105 1162 11B6; # (랧; 랧; 랧; 랧; 랧; ) HANGUL SYLLABLE RAELH +B7A8;B7A8;1105 1162 11B7;B7A8;1105 1162 11B7; # (램; 램; 램; 램; 램; ) HANGUL SYLLABLE RAEM +B7A9;B7A9;1105 1162 11B8;B7A9;1105 1162 11B8; # (랩; 랩; 랩; 랩; 랩; ) HANGUL SYLLABLE RAEB +B7AA;B7AA;1105 1162 11B9;B7AA;1105 1162 11B9; # (랪; 랪; 랪; 랪; 랪; ) HANGUL SYLLABLE RAEBS +B7AB;B7AB;1105 1162 11BA;B7AB;1105 1162 11BA; # (랫; 랫; 랫; 랫; 랫; ) HANGUL SYLLABLE RAES +B7AC;B7AC;1105 1162 11BB;B7AC;1105 1162 11BB; # (랬; 랬; 랬; 랬; 랬; ) HANGUL SYLLABLE RAESS +B7AD;B7AD;1105 1162 11BC;B7AD;1105 1162 11BC; # (랭; 랭; 랭; 랭; 랭; ) HANGUL SYLLABLE RAENG +B7AE;B7AE;1105 1162 11BD;B7AE;1105 1162 11BD; # (랮; 랮; 랮; 랮; 랮; ) HANGUL SYLLABLE RAEJ +B7AF;B7AF;1105 1162 11BE;B7AF;1105 1162 11BE; # (랯; 랯; 랯; 랯; 랯; ) HANGUL SYLLABLE RAEC +B7B0;B7B0;1105 1162 11BF;B7B0;1105 1162 11BF; # (랰; 랰; 랰; 랰; 랰; ) HANGUL SYLLABLE RAEK +B7B1;B7B1;1105 1162 11C0;B7B1;1105 1162 11C0; # (랱; 랱; 랱; 랱; 랱; ) HANGUL SYLLABLE RAET +B7B2;B7B2;1105 1162 11C1;B7B2;1105 1162 11C1; # (랲; 랲; 랲; 랲; 랲; ) HANGUL SYLLABLE RAEP +B7B3;B7B3;1105 1162 11C2;B7B3;1105 1162 11C2; # (랳; 랳; 랳; 랳; 랳; ) HANGUL SYLLABLE RAEH +B7B4;B7B4;1105 1163;B7B4;1105 1163; # (랴; 랴; 랴; 랴; 랴; ) HANGUL SYLLABLE RYA +B7B5;B7B5;1105 1163 11A8;B7B5;1105 1163 11A8; # (략; 략; 략; 략; 략; ) HANGUL SYLLABLE RYAG +B7B6;B7B6;1105 1163 11A9;B7B6;1105 1163 11A9; # (랶; 랶; 랶; 랶; 랶; ) HANGUL SYLLABLE RYAGG +B7B7;B7B7;1105 1163 11AA;B7B7;1105 1163 11AA; # (랷; 랷; 랷; 랷; 랷; ) HANGUL SYLLABLE RYAGS +B7B8;B7B8;1105 1163 11AB;B7B8;1105 1163 11AB; # (랸; 랸; 랸; 랸; 랸; ) HANGUL SYLLABLE RYAN +B7B9;B7B9;1105 1163 11AC;B7B9;1105 1163 11AC; # (랹; 랹; 랹; 랹; 랹; ) HANGUL SYLLABLE RYANJ +B7BA;B7BA;1105 1163 11AD;B7BA;1105 1163 11AD; # (랺; 랺; 랺; 랺; 랺; ) HANGUL SYLLABLE RYANH +B7BB;B7BB;1105 1163 11AE;B7BB;1105 1163 11AE; # (랻; 랻; 랻; 랻; 랻; ) HANGUL SYLLABLE RYAD +B7BC;B7BC;1105 1163 11AF;B7BC;1105 1163 11AF; # (랼; 랼; 랼; 랼; 랼; ) HANGUL SYLLABLE RYAL +B7BD;B7BD;1105 1163 11B0;B7BD;1105 1163 11B0; # (랽; 랽; 랽; 랽; 랽; ) HANGUL SYLLABLE RYALG +B7BE;B7BE;1105 1163 11B1;B7BE;1105 1163 11B1; # (랾; 랾; 랾; 랾; 랾; ) HANGUL SYLLABLE RYALM +B7BF;B7BF;1105 1163 11B2;B7BF;1105 1163 11B2; # (랿; 랿; 랿; 랿; 랿; ) HANGUL SYLLABLE RYALB +B7C0;B7C0;1105 1163 11B3;B7C0;1105 1163 11B3; # (럀; 럀; 럀; 럀; 럀; ) HANGUL SYLLABLE RYALS +B7C1;B7C1;1105 1163 11B4;B7C1;1105 1163 11B4; # (럁; 럁; 럁; 럁; 럁; ) HANGUL SYLLABLE RYALT +B7C2;B7C2;1105 1163 11B5;B7C2;1105 1163 11B5; # (럂; 럂; 럂; 럂; 럂; ) HANGUL SYLLABLE RYALP +B7C3;B7C3;1105 1163 11B6;B7C3;1105 1163 11B6; # (럃; 럃; 럃; 럃; 럃; ) HANGUL SYLLABLE RYALH +B7C4;B7C4;1105 1163 11B7;B7C4;1105 1163 11B7; # (럄; 럄; 럄; 럄; 럄; ) HANGUL SYLLABLE RYAM +B7C5;B7C5;1105 1163 11B8;B7C5;1105 1163 11B8; # (럅; 럅; 럅; 럅; 럅; ) HANGUL SYLLABLE RYAB +B7C6;B7C6;1105 1163 11B9;B7C6;1105 1163 11B9; # (럆; 럆; 럆; 럆; 럆; ) HANGUL SYLLABLE RYABS +B7C7;B7C7;1105 1163 11BA;B7C7;1105 1163 11BA; # (럇; 럇; 럇; 럇; 럇; ) HANGUL SYLLABLE RYAS +B7C8;B7C8;1105 1163 11BB;B7C8;1105 1163 11BB; # (럈; 럈; 럈; 럈; 럈; ) HANGUL SYLLABLE RYASS +B7C9;B7C9;1105 1163 11BC;B7C9;1105 1163 11BC; # (량; 량; 량; 량; 량; ) HANGUL SYLLABLE RYANG +B7CA;B7CA;1105 1163 11BD;B7CA;1105 1163 11BD; # (럊; 럊; 럊; 럊; 럊; ) HANGUL SYLLABLE RYAJ +B7CB;B7CB;1105 1163 11BE;B7CB;1105 1163 11BE; # (럋; 럋; 럋; 럋; 럋; ) HANGUL SYLLABLE RYAC +B7CC;B7CC;1105 1163 11BF;B7CC;1105 1163 11BF; # (럌; 럌; 럌; 럌; 럌; ) HANGUL SYLLABLE RYAK +B7CD;B7CD;1105 1163 11C0;B7CD;1105 1163 11C0; # (럍; 럍; 럍; 럍; 럍; ) HANGUL SYLLABLE RYAT +B7CE;B7CE;1105 1163 11C1;B7CE;1105 1163 11C1; # (럎; 럎; 럎; 럎; 럎; ) HANGUL SYLLABLE RYAP +B7CF;B7CF;1105 1163 11C2;B7CF;1105 1163 11C2; # (럏; 럏; 럏; 럏; 럏; ) HANGUL SYLLABLE RYAH +B7D0;B7D0;1105 1164;B7D0;1105 1164; # (럐; 럐; 럐; 럐; 럐; ) HANGUL SYLLABLE RYAE +B7D1;B7D1;1105 1164 11A8;B7D1;1105 1164 11A8; # (럑; 럑; 럑; 럑; 럑; ) HANGUL SYLLABLE RYAEG +B7D2;B7D2;1105 1164 11A9;B7D2;1105 1164 11A9; # (럒; 럒; 럒; 럒; 럒; ) HANGUL SYLLABLE RYAEGG +B7D3;B7D3;1105 1164 11AA;B7D3;1105 1164 11AA; # (럓; 럓; 럓; 럓; 럓; ) HANGUL SYLLABLE RYAEGS +B7D4;B7D4;1105 1164 11AB;B7D4;1105 1164 11AB; # (럔; 럔; 럔; 럔; 럔; ) HANGUL SYLLABLE RYAEN +B7D5;B7D5;1105 1164 11AC;B7D5;1105 1164 11AC; # (럕; 럕; 럕; 럕; 럕; ) HANGUL SYLLABLE RYAENJ +B7D6;B7D6;1105 1164 11AD;B7D6;1105 1164 11AD; # (럖; 럖; 럖; 럖; 럖; ) HANGUL SYLLABLE RYAENH +B7D7;B7D7;1105 1164 11AE;B7D7;1105 1164 11AE; # (럗; 럗; 럗; 럗; 럗; ) HANGUL SYLLABLE RYAED +B7D8;B7D8;1105 1164 11AF;B7D8;1105 1164 11AF; # (럘; 럘; 럘; 럘; 럘; ) HANGUL SYLLABLE RYAEL +B7D9;B7D9;1105 1164 11B0;B7D9;1105 1164 11B0; # (럙; 럙; 럙; 럙; 럙; ) HANGUL SYLLABLE RYAELG +B7DA;B7DA;1105 1164 11B1;B7DA;1105 1164 11B1; # (럚; 럚; 럚; 럚; 럚; ) HANGUL SYLLABLE RYAELM +B7DB;B7DB;1105 1164 11B2;B7DB;1105 1164 11B2; # (럛; 럛; 럛; 럛; 럛; ) HANGUL SYLLABLE RYAELB +B7DC;B7DC;1105 1164 11B3;B7DC;1105 1164 11B3; # (럜; 럜; 럜; 럜; 럜; ) HANGUL SYLLABLE RYAELS +B7DD;B7DD;1105 1164 11B4;B7DD;1105 1164 11B4; # (럝; 럝; 럝; 럝; 럝; ) HANGUL SYLLABLE RYAELT +B7DE;B7DE;1105 1164 11B5;B7DE;1105 1164 11B5; # (럞; 럞; 럞; 럞; 럞; ) HANGUL SYLLABLE RYAELP +B7DF;B7DF;1105 1164 11B6;B7DF;1105 1164 11B6; # (럟; 럟; 럟; 럟; 럟; ) HANGUL SYLLABLE RYAELH +B7E0;B7E0;1105 1164 11B7;B7E0;1105 1164 11B7; # (럠; 럠; 럠; 럠; 럠; ) HANGUL SYLLABLE RYAEM +B7E1;B7E1;1105 1164 11B8;B7E1;1105 1164 11B8; # (럡; 럡; 럡; 럡; 럡; ) HANGUL SYLLABLE RYAEB +B7E2;B7E2;1105 1164 11B9;B7E2;1105 1164 11B9; # (럢; 럢; 럢; 럢; 럢; ) HANGUL SYLLABLE RYAEBS +B7E3;B7E3;1105 1164 11BA;B7E3;1105 1164 11BA; # (럣; 럣; 럣; 럣; 럣; ) HANGUL SYLLABLE RYAES +B7E4;B7E4;1105 1164 11BB;B7E4;1105 1164 11BB; # (럤; 럤; 럤; 럤; 럤; ) HANGUL SYLLABLE RYAESS +B7E5;B7E5;1105 1164 11BC;B7E5;1105 1164 11BC; # (럥; 럥; 럥; 럥; 럥; ) HANGUL SYLLABLE RYAENG +B7E6;B7E6;1105 1164 11BD;B7E6;1105 1164 11BD; # (럦; 럦; 럦; 럦; 럦; ) HANGUL SYLLABLE RYAEJ +B7E7;B7E7;1105 1164 11BE;B7E7;1105 1164 11BE; # (럧; 럧; 럧; 럧; 럧; ) HANGUL SYLLABLE RYAEC +B7E8;B7E8;1105 1164 11BF;B7E8;1105 1164 11BF; # (럨; 럨; 럨; 럨; 럨; ) HANGUL SYLLABLE RYAEK +B7E9;B7E9;1105 1164 11C0;B7E9;1105 1164 11C0; # (럩; 럩; 럩; 럩; 럩; ) HANGUL SYLLABLE RYAET +B7EA;B7EA;1105 1164 11C1;B7EA;1105 1164 11C1; # (럪; 럪; 럪; 럪; 럪; ) HANGUL SYLLABLE RYAEP +B7EB;B7EB;1105 1164 11C2;B7EB;1105 1164 11C2; # (럫; 럫; 럫; 럫; 럫; ) HANGUL SYLLABLE RYAEH +B7EC;B7EC;1105 1165;B7EC;1105 1165; # (러; 러; 러; 러; 러; ) HANGUL SYLLABLE REO +B7ED;B7ED;1105 1165 11A8;B7ED;1105 1165 11A8; # (럭; 럭; 럭; 럭; 럭; ) HANGUL SYLLABLE REOG +B7EE;B7EE;1105 1165 11A9;B7EE;1105 1165 11A9; # (럮; 럮; 럮; 럮; 럮; ) HANGUL SYLLABLE REOGG +B7EF;B7EF;1105 1165 11AA;B7EF;1105 1165 11AA; # (럯; 럯; 럯; 럯; 럯; ) HANGUL SYLLABLE REOGS +B7F0;B7F0;1105 1165 11AB;B7F0;1105 1165 11AB; # (런; 런; 런; 런; 런; ) HANGUL SYLLABLE REON +B7F1;B7F1;1105 1165 11AC;B7F1;1105 1165 11AC; # (럱; 럱; 럱; 럱; 럱; ) HANGUL SYLLABLE REONJ +B7F2;B7F2;1105 1165 11AD;B7F2;1105 1165 11AD; # (럲; 럲; 럲; 럲; 럲; ) HANGUL SYLLABLE REONH +B7F3;B7F3;1105 1165 11AE;B7F3;1105 1165 11AE; # (럳; 럳; 럳; 럳; 럳; ) HANGUL SYLLABLE REOD +B7F4;B7F4;1105 1165 11AF;B7F4;1105 1165 11AF; # (럴; 럴; 럴; 럴; 럴; ) HANGUL SYLLABLE REOL +B7F5;B7F5;1105 1165 11B0;B7F5;1105 1165 11B0; # (럵; 럵; 럵; 럵; 럵; ) HANGUL SYLLABLE REOLG +B7F6;B7F6;1105 1165 11B1;B7F6;1105 1165 11B1; # (럶; 럶; 럶; 럶; 럶; ) HANGUL SYLLABLE REOLM +B7F7;B7F7;1105 1165 11B2;B7F7;1105 1165 11B2; # (럷; 럷; 럷; 럷; 럷; ) HANGUL SYLLABLE REOLB +B7F8;B7F8;1105 1165 11B3;B7F8;1105 1165 11B3; # (럸; 럸; 럸; 럸; 럸; ) HANGUL SYLLABLE REOLS +B7F9;B7F9;1105 1165 11B4;B7F9;1105 1165 11B4; # (럹; 럹; 럹; 럹; 럹; ) HANGUL SYLLABLE REOLT +B7FA;B7FA;1105 1165 11B5;B7FA;1105 1165 11B5; # (럺; 럺; 럺; 럺; 럺; ) HANGUL SYLLABLE REOLP +B7FB;B7FB;1105 1165 11B6;B7FB;1105 1165 11B6; # (럻; 럻; 럻; 럻; 럻; ) HANGUL SYLLABLE REOLH +B7FC;B7FC;1105 1165 11B7;B7FC;1105 1165 11B7; # (럼; 럼; 럼; 럼; 럼; ) HANGUL SYLLABLE REOM +B7FD;B7FD;1105 1165 11B8;B7FD;1105 1165 11B8; # (럽; 럽; 럽; 럽; 럽; ) HANGUL SYLLABLE REOB +B7FE;B7FE;1105 1165 11B9;B7FE;1105 1165 11B9; # (럾; 럾; 럾; 럾; 럾; ) HANGUL SYLLABLE REOBS +B7FF;B7FF;1105 1165 11BA;B7FF;1105 1165 11BA; # (럿; 럿; 럿; 럿; 럿; ) HANGUL SYLLABLE REOS +B800;B800;1105 1165 11BB;B800;1105 1165 11BB; # (렀; 렀; 렀; 렀; 렀; ) HANGUL SYLLABLE REOSS +B801;B801;1105 1165 11BC;B801;1105 1165 11BC; # (렁; 렁; 렁; 렁; 렁; ) HANGUL SYLLABLE REONG +B802;B802;1105 1165 11BD;B802;1105 1165 11BD; # (렂; 렂; 렂; 렂; 렂; ) HANGUL SYLLABLE REOJ +B803;B803;1105 1165 11BE;B803;1105 1165 11BE; # (렃; 렃; 렃; 렃; 렃; ) HANGUL SYLLABLE REOC +B804;B804;1105 1165 11BF;B804;1105 1165 11BF; # (렄; 렄; 렄; 렄; 렄; ) HANGUL SYLLABLE REOK +B805;B805;1105 1165 11C0;B805;1105 1165 11C0; # (렅; 렅; 렅; 렅; 렅; ) HANGUL SYLLABLE REOT +B806;B806;1105 1165 11C1;B806;1105 1165 11C1; # (렆; 렆; 렆; 렆; 렆; ) HANGUL SYLLABLE REOP +B807;B807;1105 1165 11C2;B807;1105 1165 11C2; # (렇; 렇; 렇; 렇; 렇; ) HANGUL SYLLABLE REOH +B808;B808;1105 1166;B808;1105 1166; # (레; 레; 레; 레; 레; ) HANGUL SYLLABLE RE +B809;B809;1105 1166 11A8;B809;1105 1166 11A8; # (렉; 렉; 렉; 렉; 렉; ) HANGUL SYLLABLE REG +B80A;B80A;1105 1166 11A9;B80A;1105 1166 11A9; # (렊; 렊; 렊; 렊; 렊; ) HANGUL SYLLABLE REGG +B80B;B80B;1105 1166 11AA;B80B;1105 1166 11AA; # (렋; 렋; 렋; 렋; 렋; ) HANGUL SYLLABLE REGS +B80C;B80C;1105 1166 11AB;B80C;1105 1166 11AB; # (렌; 렌; 렌; 렌; 렌; ) HANGUL SYLLABLE REN +B80D;B80D;1105 1166 11AC;B80D;1105 1166 11AC; # (렍; 렍; 렍; 렍; 렍; ) HANGUL SYLLABLE RENJ +B80E;B80E;1105 1166 11AD;B80E;1105 1166 11AD; # (렎; 렎; 렎; 렎; 렎; ) HANGUL SYLLABLE RENH +B80F;B80F;1105 1166 11AE;B80F;1105 1166 11AE; # (렏; 렏; 렏; 렏; 렏; ) HANGUL SYLLABLE RED +B810;B810;1105 1166 11AF;B810;1105 1166 11AF; # (렐; 렐; 렐; 렐; 렐; ) HANGUL SYLLABLE REL +B811;B811;1105 1166 11B0;B811;1105 1166 11B0; # (렑; 렑; 렑; 렑; 렑; ) HANGUL SYLLABLE RELG +B812;B812;1105 1166 11B1;B812;1105 1166 11B1; # (렒; 렒; 렒; 렒; 렒; ) HANGUL SYLLABLE RELM +B813;B813;1105 1166 11B2;B813;1105 1166 11B2; # (렓; 렓; 렓; 렓; 렓; ) HANGUL SYLLABLE RELB +B814;B814;1105 1166 11B3;B814;1105 1166 11B3; # (렔; 렔; 렔; 렔; 렔; ) HANGUL SYLLABLE RELS +B815;B815;1105 1166 11B4;B815;1105 1166 11B4; # (렕; 렕; 렕; 렕; 렕; ) HANGUL SYLLABLE RELT +B816;B816;1105 1166 11B5;B816;1105 1166 11B5; # (렖; 렖; 렖; 렖; 렖; ) HANGUL SYLLABLE RELP +B817;B817;1105 1166 11B6;B817;1105 1166 11B6; # (렗; 렗; 렗; 렗; 렗; ) HANGUL SYLLABLE RELH +B818;B818;1105 1166 11B7;B818;1105 1166 11B7; # (렘; 렘; 렘; 렘; 렘; ) HANGUL SYLLABLE REM +B819;B819;1105 1166 11B8;B819;1105 1166 11B8; # (렙; 렙; 렙; 렙; 렙; ) HANGUL SYLLABLE REB +B81A;B81A;1105 1166 11B9;B81A;1105 1166 11B9; # (렚; 렚; 렚; 렚; 렚; ) HANGUL SYLLABLE REBS +B81B;B81B;1105 1166 11BA;B81B;1105 1166 11BA; # (렛; 렛; 렛; 렛; 렛; ) HANGUL SYLLABLE RES +B81C;B81C;1105 1166 11BB;B81C;1105 1166 11BB; # (렜; 렜; 렜; 렜; 렜; ) HANGUL SYLLABLE RESS +B81D;B81D;1105 1166 11BC;B81D;1105 1166 11BC; # (렝; 렝; 렝; 렝; 렝; ) HANGUL SYLLABLE RENG +B81E;B81E;1105 1166 11BD;B81E;1105 1166 11BD; # (렞; 렞; 렞; 렞; 렞; ) HANGUL SYLLABLE REJ +B81F;B81F;1105 1166 11BE;B81F;1105 1166 11BE; # (렟; 렟; 렟; 렟; 렟; ) HANGUL SYLLABLE REC +B820;B820;1105 1166 11BF;B820;1105 1166 11BF; # (렠; 렠; 렠; 렠; 렠; ) HANGUL SYLLABLE REK +B821;B821;1105 1166 11C0;B821;1105 1166 11C0; # (렡; 렡; 렡; 렡; 렡; ) HANGUL SYLLABLE RET +B822;B822;1105 1166 11C1;B822;1105 1166 11C1; # (렢; 렢; 렢; 렢; 렢; ) HANGUL SYLLABLE REP +B823;B823;1105 1166 11C2;B823;1105 1166 11C2; # (렣; 렣; 렣; 렣; 렣; ) HANGUL SYLLABLE REH +B824;B824;1105 1167;B824;1105 1167; # (려; 려; 려; 려; 려; ) HANGUL SYLLABLE RYEO +B825;B825;1105 1167 11A8;B825;1105 1167 11A8; # (력; 력; 력; 력; 력; ) HANGUL SYLLABLE RYEOG +B826;B826;1105 1167 11A9;B826;1105 1167 11A9; # (렦; 렦; 렦; 렦; 렦; ) HANGUL SYLLABLE RYEOGG +B827;B827;1105 1167 11AA;B827;1105 1167 11AA; # (렧; 렧; 렧; 렧; 렧; ) HANGUL SYLLABLE RYEOGS +B828;B828;1105 1167 11AB;B828;1105 1167 11AB; # (련; 련; 련; 련; 련; ) HANGUL SYLLABLE RYEON +B829;B829;1105 1167 11AC;B829;1105 1167 11AC; # (렩; 렩; 렩; 렩; 렩; ) HANGUL SYLLABLE RYEONJ +B82A;B82A;1105 1167 11AD;B82A;1105 1167 11AD; # (렪; 렪; 렪; 렪; 렪; ) HANGUL SYLLABLE RYEONH +B82B;B82B;1105 1167 11AE;B82B;1105 1167 11AE; # (렫; 렫; 렫; 렫; 렫; ) HANGUL SYLLABLE RYEOD +B82C;B82C;1105 1167 11AF;B82C;1105 1167 11AF; # (렬; 렬; 렬; 렬; 렬; ) HANGUL SYLLABLE RYEOL +B82D;B82D;1105 1167 11B0;B82D;1105 1167 11B0; # (렭; 렭; 렭; 렭; 렭; ) HANGUL SYLLABLE RYEOLG +B82E;B82E;1105 1167 11B1;B82E;1105 1167 11B1; # (렮; 렮; 렮; 렮; 렮; ) HANGUL SYLLABLE RYEOLM +B82F;B82F;1105 1167 11B2;B82F;1105 1167 11B2; # (렯; 렯; 렯; 렯; 렯; ) HANGUL SYLLABLE RYEOLB +B830;B830;1105 1167 11B3;B830;1105 1167 11B3; # (렰; 렰; 렰; 렰; 렰; ) HANGUL SYLLABLE RYEOLS +B831;B831;1105 1167 11B4;B831;1105 1167 11B4; # (렱; 렱; 렱; 렱; 렱; ) HANGUL SYLLABLE RYEOLT +B832;B832;1105 1167 11B5;B832;1105 1167 11B5; # (렲; 렲; 렲; 렲; 렲; ) HANGUL SYLLABLE RYEOLP +B833;B833;1105 1167 11B6;B833;1105 1167 11B6; # (렳; 렳; 렳; 렳; 렳; ) HANGUL SYLLABLE RYEOLH +B834;B834;1105 1167 11B7;B834;1105 1167 11B7; # (렴; 렴; 렴; 렴; 렴; ) HANGUL SYLLABLE RYEOM +B835;B835;1105 1167 11B8;B835;1105 1167 11B8; # (렵; 렵; 렵; 렵; 렵; ) HANGUL SYLLABLE RYEOB +B836;B836;1105 1167 11B9;B836;1105 1167 11B9; # (렶; 렶; 렶; 렶; 렶; ) HANGUL SYLLABLE RYEOBS +B837;B837;1105 1167 11BA;B837;1105 1167 11BA; # (렷; 렷; 렷; 렷; 렷; ) HANGUL SYLLABLE RYEOS +B838;B838;1105 1167 11BB;B838;1105 1167 11BB; # (렸; 렸; 렸; 렸; 렸; ) HANGUL SYLLABLE RYEOSS +B839;B839;1105 1167 11BC;B839;1105 1167 11BC; # (령; 령; 령; 령; 령; ) HANGUL SYLLABLE RYEONG +B83A;B83A;1105 1167 11BD;B83A;1105 1167 11BD; # (렺; 렺; 렺; 렺; 렺; ) HANGUL SYLLABLE RYEOJ +B83B;B83B;1105 1167 11BE;B83B;1105 1167 11BE; # (렻; 렻; 렻; 렻; 렻; ) HANGUL SYLLABLE RYEOC +B83C;B83C;1105 1167 11BF;B83C;1105 1167 11BF; # (렼; 렼; 렼; 렼; 렼; ) HANGUL SYLLABLE RYEOK +B83D;B83D;1105 1167 11C0;B83D;1105 1167 11C0; # (렽; 렽; 렽; 렽; 렽; ) HANGUL SYLLABLE RYEOT +B83E;B83E;1105 1167 11C1;B83E;1105 1167 11C1; # (렾; 렾; 렾; 렾; 렾; ) HANGUL SYLLABLE RYEOP +B83F;B83F;1105 1167 11C2;B83F;1105 1167 11C2; # (렿; 렿; 렿; 렿; 렿; ) HANGUL SYLLABLE RYEOH +B840;B840;1105 1168;B840;1105 1168; # (례; 례; 례; 례; 례; ) HANGUL SYLLABLE RYE +B841;B841;1105 1168 11A8;B841;1105 1168 11A8; # (롁; 롁; 롁; 롁; 롁; ) HANGUL SYLLABLE RYEG +B842;B842;1105 1168 11A9;B842;1105 1168 11A9; # (롂; 롂; 롂; 롂; 롂; ) HANGUL SYLLABLE RYEGG +B843;B843;1105 1168 11AA;B843;1105 1168 11AA; # (롃; 롃; 롃; 롃; 롃; ) HANGUL SYLLABLE RYEGS +B844;B844;1105 1168 11AB;B844;1105 1168 11AB; # (롄; 롄; 롄; 롄; 롄; ) HANGUL SYLLABLE RYEN +B845;B845;1105 1168 11AC;B845;1105 1168 11AC; # (롅; 롅; 롅; 롅; 롅; ) HANGUL SYLLABLE RYENJ +B846;B846;1105 1168 11AD;B846;1105 1168 11AD; # (롆; 롆; 롆; 롆; 롆; ) HANGUL SYLLABLE RYENH +B847;B847;1105 1168 11AE;B847;1105 1168 11AE; # (롇; 롇; 롇; 롇; 롇; ) HANGUL SYLLABLE RYED +B848;B848;1105 1168 11AF;B848;1105 1168 11AF; # (롈; 롈; 롈; 롈; 롈; ) HANGUL SYLLABLE RYEL +B849;B849;1105 1168 11B0;B849;1105 1168 11B0; # (롉; 롉; 롉; 롉; 롉; ) HANGUL SYLLABLE RYELG +B84A;B84A;1105 1168 11B1;B84A;1105 1168 11B1; # (롊; 롊; 롊; 롊; 롊; ) HANGUL SYLLABLE RYELM +B84B;B84B;1105 1168 11B2;B84B;1105 1168 11B2; # (롋; 롋; 롋; 롋; 롋; ) HANGUL SYLLABLE RYELB +B84C;B84C;1105 1168 11B3;B84C;1105 1168 11B3; # (롌; 롌; 롌; 롌; 롌; ) HANGUL SYLLABLE RYELS +B84D;B84D;1105 1168 11B4;B84D;1105 1168 11B4; # (롍; 롍; 롍; 롍; 롍; ) HANGUL SYLLABLE RYELT +B84E;B84E;1105 1168 11B5;B84E;1105 1168 11B5; # (롎; 롎; 롎; 롎; 롎; ) HANGUL SYLLABLE RYELP +B84F;B84F;1105 1168 11B6;B84F;1105 1168 11B6; # (롏; 롏; 롏; 롏; 롏; ) HANGUL SYLLABLE RYELH +B850;B850;1105 1168 11B7;B850;1105 1168 11B7; # (롐; 롐; 롐; 롐; 롐; ) HANGUL SYLLABLE RYEM +B851;B851;1105 1168 11B8;B851;1105 1168 11B8; # (롑; 롑; 롑; 롑; 롑; ) HANGUL SYLLABLE RYEB +B852;B852;1105 1168 11B9;B852;1105 1168 11B9; # (롒; 롒; 롒; 롒; 롒; ) HANGUL SYLLABLE RYEBS +B853;B853;1105 1168 11BA;B853;1105 1168 11BA; # (롓; 롓; 롓; 롓; 롓; ) HANGUL SYLLABLE RYES +B854;B854;1105 1168 11BB;B854;1105 1168 11BB; # (롔; 롔; 롔; 롔; 롔; ) HANGUL SYLLABLE RYESS +B855;B855;1105 1168 11BC;B855;1105 1168 11BC; # (롕; 롕; 롕; 롕; 롕; ) HANGUL SYLLABLE RYENG +B856;B856;1105 1168 11BD;B856;1105 1168 11BD; # (롖; 롖; 롖; 롖; 롖; ) HANGUL SYLLABLE RYEJ +B857;B857;1105 1168 11BE;B857;1105 1168 11BE; # (롗; 롗; 롗; 롗; 롗; ) HANGUL SYLLABLE RYEC +B858;B858;1105 1168 11BF;B858;1105 1168 11BF; # (롘; 롘; 롘; 롘; 롘; ) HANGUL SYLLABLE RYEK +B859;B859;1105 1168 11C0;B859;1105 1168 11C0; # (롙; 롙; 롙; 롙; 롙; ) HANGUL SYLLABLE RYET +B85A;B85A;1105 1168 11C1;B85A;1105 1168 11C1; # (롚; 롚; 롚; 롚; 롚; ) HANGUL SYLLABLE RYEP +B85B;B85B;1105 1168 11C2;B85B;1105 1168 11C2; # (롛; 롛; 롛; 롛; 롛; ) HANGUL SYLLABLE RYEH +B85C;B85C;1105 1169;B85C;1105 1169; # (로; 로; 로; 로; 로; ) HANGUL SYLLABLE RO +B85D;B85D;1105 1169 11A8;B85D;1105 1169 11A8; # (록; 록; 록; 록; 록; ) HANGUL SYLLABLE ROG +B85E;B85E;1105 1169 11A9;B85E;1105 1169 11A9; # (롞; 롞; 롞; 롞; 롞; ) HANGUL SYLLABLE ROGG +B85F;B85F;1105 1169 11AA;B85F;1105 1169 11AA; # (롟; 롟; 롟; 롟; 롟; ) HANGUL SYLLABLE ROGS +B860;B860;1105 1169 11AB;B860;1105 1169 11AB; # (론; 론; 론; 론; 론; ) HANGUL SYLLABLE RON +B861;B861;1105 1169 11AC;B861;1105 1169 11AC; # (롡; 롡; 롡; 롡; 롡; ) HANGUL SYLLABLE RONJ +B862;B862;1105 1169 11AD;B862;1105 1169 11AD; # (롢; 롢; 롢; 롢; 롢; ) HANGUL SYLLABLE RONH +B863;B863;1105 1169 11AE;B863;1105 1169 11AE; # (롣; 롣; 롣; 롣; 롣; ) HANGUL SYLLABLE ROD +B864;B864;1105 1169 11AF;B864;1105 1169 11AF; # (롤; 롤; 롤; 롤; 롤; ) HANGUL SYLLABLE ROL +B865;B865;1105 1169 11B0;B865;1105 1169 11B0; # (롥; 롥; 롥; 롥; 롥; ) HANGUL SYLLABLE ROLG +B866;B866;1105 1169 11B1;B866;1105 1169 11B1; # (롦; 롦; 롦; 롦; 롦; ) HANGUL SYLLABLE ROLM +B867;B867;1105 1169 11B2;B867;1105 1169 11B2; # (롧; 롧; 롧; 롧; 롧; ) HANGUL SYLLABLE ROLB +B868;B868;1105 1169 11B3;B868;1105 1169 11B3; # (롨; 롨; 롨; 롨; 롨; ) HANGUL SYLLABLE ROLS +B869;B869;1105 1169 11B4;B869;1105 1169 11B4; # (롩; 롩; 롩; 롩; 롩; ) HANGUL SYLLABLE ROLT +B86A;B86A;1105 1169 11B5;B86A;1105 1169 11B5; # (롪; 롪; 롪; 롪; 롪; ) HANGUL SYLLABLE ROLP +B86B;B86B;1105 1169 11B6;B86B;1105 1169 11B6; # (롫; 롫; 롫; 롫; 롫; ) HANGUL SYLLABLE ROLH +B86C;B86C;1105 1169 11B7;B86C;1105 1169 11B7; # (롬; 롬; 롬; 롬; 롬; ) HANGUL SYLLABLE ROM +B86D;B86D;1105 1169 11B8;B86D;1105 1169 11B8; # (롭; 롭; 롭; 롭; 롭; ) HANGUL SYLLABLE ROB +B86E;B86E;1105 1169 11B9;B86E;1105 1169 11B9; # (롮; 롮; 롮; 롮; 롮; ) HANGUL SYLLABLE ROBS +B86F;B86F;1105 1169 11BA;B86F;1105 1169 11BA; # (롯; 롯; 롯; 롯; 롯; ) HANGUL SYLLABLE ROS +B870;B870;1105 1169 11BB;B870;1105 1169 11BB; # (롰; 롰; 롰; 롰; 롰; ) HANGUL SYLLABLE ROSS +B871;B871;1105 1169 11BC;B871;1105 1169 11BC; # (롱; 롱; 롱; 롱; 롱; ) HANGUL SYLLABLE RONG +B872;B872;1105 1169 11BD;B872;1105 1169 11BD; # (롲; 롲; 롲; 롲; 롲; ) HANGUL SYLLABLE ROJ +B873;B873;1105 1169 11BE;B873;1105 1169 11BE; # (롳; 롳; 롳; 롳; 롳; ) HANGUL SYLLABLE ROC +B874;B874;1105 1169 11BF;B874;1105 1169 11BF; # (롴; 롴; 롴; 롴; 롴; ) HANGUL SYLLABLE ROK +B875;B875;1105 1169 11C0;B875;1105 1169 11C0; # (롵; 롵; 롵; 롵; 롵; ) HANGUL SYLLABLE ROT +B876;B876;1105 1169 11C1;B876;1105 1169 11C1; # (롶; 롶; 롶; 롶; 롶; ) HANGUL SYLLABLE ROP +B877;B877;1105 1169 11C2;B877;1105 1169 11C2; # (롷; 롷; 롷; 롷; 롷; ) HANGUL SYLLABLE ROH +B878;B878;1105 116A;B878;1105 116A; # (롸; 롸; 롸; 롸; 롸; ) HANGUL SYLLABLE RWA +B879;B879;1105 116A 11A8;B879;1105 116A 11A8; # (롹; 롹; 롹; 롹; 롹; ) HANGUL SYLLABLE RWAG +B87A;B87A;1105 116A 11A9;B87A;1105 116A 11A9; # (롺; 롺; 롺; 롺; 롺; ) HANGUL SYLLABLE RWAGG +B87B;B87B;1105 116A 11AA;B87B;1105 116A 11AA; # (롻; 롻; 롻; 롻; 롻; ) HANGUL SYLLABLE RWAGS +B87C;B87C;1105 116A 11AB;B87C;1105 116A 11AB; # (롼; 롼; 롼; 롼; 롼; ) HANGUL SYLLABLE RWAN +B87D;B87D;1105 116A 11AC;B87D;1105 116A 11AC; # (롽; 롽; 롽; 롽; 롽; ) HANGUL SYLLABLE RWANJ +B87E;B87E;1105 116A 11AD;B87E;1105 116A 11AD; # (롾; 롾; 롾; 롾; 롾; ) HANGUL SYLLABLE RWANH +B87F;B87F;1105 116A 11AE;B87F;1105 116A 11AE; # (롿; 롿; 롿; 롿; 롿; ) HANGUL SYLLABLE RWAD +B880;B880;1105 116A 11AF;B880;1105 116A 11AF; # (뢀; 뢀; 뢀; 뢀; 뢀; ) HANGUL SYLLABLE RWAL +B881;B881;1105 116A 11B0;B881;1105 116A 11B0; # (뢁; 뢁; 뢁; 뢁; 뢁; ) HANGUL SYLLABLE RWALG +B882;B882;1105 116A 11B1;B882;1105 116A 11B1; # (뢂; 뢂; 뢂; 뢂; 뢂; ) HANGUL SYLLABLE RWALM +B883;B883;1105 116A 11B2;B883;1105 116A 11B2; # (뢃; 뢃; 뢃; 뢃; 뢃; ) HANGUL SYLLABLE RWALB +B884;B884;1105 116A 11B3;B884;1105 116A 11B3; # (뢄; 뢄; 뢄; 뢄; 뢄; ) HANGUL SYLLABLE RWALS +B885;B885;1105 116A 11B4;B885;1105 116A 11B4; # (뢅; 뢅; 뢅; 뢅; 뢅; ) HANGUL SYLLABLE RWALT +B886;B886;1105 116A 11B5;B886;1105 116A 11B5; # (뢆; 뢆; 뢆; 뢆; 뢆; ) HANGUL SYLLABLE RWALP +B887;B887;1105 116A 11B6;B887;1105 116A 11B6; # (뢇; 뢇; 뢇; 뢇; 뢇; ) HANGUL SYLLABLE RWALH +B888;B888;1105 116A 11B7;B888;1105 116A 11B7; # (뢈; 뢈; 뢈; 뢈; 뢈; ) HANGUL SYLLABLE RWAM +B889;B889;1105 116A 11B8;B889;1105 116A 11B8; # (뢉; 뢉; 뢉; 뢉; 뢉; ) HANGUL SYLLABLE RWAB +B88A;B88A;1105 116A 11B9;B88A;1105 116A 11B9; # (뢊; 뢊; 뢊; 뢊; 뢊; ) HANGUL SYLLABLE RWABS +B88B;B88B;1105 116A 11BA;B88B;1105 116A 11BA; # (뢋; 뢋; 뢋; 뢋; 뢋; ) HANGUL SYLLABLE RWAS +B88C;B88C;1105 116A 11BB;B88C;1105 116A 11BB; # (뢌; 뢌; 뢌; 뢌; 뢌; ) HANGUL SYLLABLE RWASS +B88D;B88D;1105 116A 11BC;B88D;1105 116A 11BC; # (뢍; 뢍; 뢍; 뢍; 뢍; ) HANGUL SYLLABLE RWANG +B88E;B88E;1105 116A 11BD;B88E;1105 116A 11BD; # (뢎; 뢎; 뢎; 뢎; 뢎; ) HANGUL SYLLABLE RWAJ +B88F;B88F;1105 116A 11BE;B88F;1105 116A 11BE; # (뢏; 뢏; 뢏; 뢏; 뢏; ) HANGUL SYLLABLE RWAC +B890;B890;1105 116A 11BF;B890;1105 116A 11BF; # (뢐; 뢐; 뢐; 뢐; 뢐; ) HANGUL SYLLABLE RWAK +B891;B891;1105 116A 11C0;B891;1105 116A 11C0; # (뢑; 뢑; 뢑; 뢑; 뢑; ) HANGUL SYLLABLE RWAT +B892;B892;1105 116A 11C1;B892;1105 116A 11C1; # (뢒; 뢒; 뢒; 뢒; 뢒; ) HANGUL SYLLABLE RWAP +B893;B893;1105 116A 11C2;B893;1105 116A 11C2; # (뢓; 뢓; 뢓; 뢓; 뢓; ) HANGUL SYLLABLE RWAH +B894;B894;1105 116B;B894;1105 116B; # (뢔; 뢔; 뢔; 뢔; 뢔; ) HANGUL SYLLABLE RWAE +B895;B895;1105 116B 11A8;B895;1105 116B 11A8; # (뢕; 뢕; 뢕; 뢕; 뢕; ) HANGUL SYLLABLE RWAEG +B896;B896;1105 116B 11A9;B896;1105 116B 11A9; # (뢖; 뢖; 뢖; 뢖; 뢖; ) HANGUL SYLLABLE RWAEGG +B897;B897;1105 116B 11AA;B897;1105 116B 11AA; # (뢗; 뢗; 뢗; 뢗; 뢗; ) HANGUL SYLLABLE RWAEGS +B898;B898;1105 116B 11AB;B898;1105 116B 11AB; # (뢘; 뢘; 뢘; 뢘; 뢘; ) HANGUL SYLLABLE RWAEN +B899;B899;1105 116B 11AC;B899;1105 116B 11AC; # (뢙; 뢙; 뢙; 뢙; 뢙; ) HANGUL SYLLABLE RWAENJ +B89A;B89A;1105 116B 11AD;B89A;1105 116B 11AD; # (뢚; 뢚; 뢚; 뢚; 뢚; ) HANGUL SYLLABLE RWAENH +B89B;B89B;1105 116B 11AE;B89B;1105 116B 11AE; # (뢛; 뢛; 뢛; 뢛; 뢛; ) HANGUL SYLLABLE RWAED +B89C;B89C;1105 116B 11AF;B89C;1105 116B 11AF; # (뢜; 뢜; 뢜; 뢜; 뢜; ) HANGUL SYLLABLE RWAEL +B89D;B89D;1105 116B 11B0;B89D;1105 116B 11B0; # (뢝; 뢝; 뢝; 뢝; 뢝; ) HANGUL SYLLABLE RWAELG +B89E;B89E;1105 116B 11B1;B89E;1105 116B 11B1; # (뢞; 뢞; 뢞; 뢞; 뢞; ) HANGUL SYLLABLE RWAELM +B89F;B89F;1105 116B 11B2;B89F;1105 116B 11B2; # (뢟; 뢟; 뢟; 뢟; 뢟; ) HANGUL SYLLABLE RWAELB +B8A0;B8A0;1105 116B 11B3;B8A0;1105 116B 11B3; # (뢠; 뢠; 뢠; 뢠; 뢠; ) HANGUL SYLLABLE RWAELS +B8A1;B8A1;1105 116B 11B4;B8A1;1105 116B 11B4; # (뢡; 뢡; 뢡; 뢡; 뢡; ) HANGUL SYLLABLE RWAELT +B8A2;B8A2;1105 116B 11B5;B8A2;1105 116B 11B5; # (뢢; 뢢; 뢢; 뢢; 뢢; ) HANGUL SYLLABLE RWAELP +B8A3;B8A3;1105 116B 11B6;B8A3;1105 116B 11B6; # (뢣; 뢣; 뢣; 뢣; 뢣; ) HANGUL SYLLABLE RWAELH +B8A4;B8A4;1105 116B 11B7;B8A4;1105 116B 11B7; # (뢤; 뢤; 뢤; 뢤; 뢤; ) HANGUL SYLLABLE RWAEM +B8A5;B8A5;1105 116B 11B8;B8A5;1105 116B 11B8; # (뢥; 뢥; 뢥; 뢥; 뢥; ) HANGUL SYLLABLE RWAEB +B8A6;B8A6;1105 116B 11B9;B8A6;1105 116B 11B9; # (뢦; 뢦; 뢦; 뢦; 뢦; ) HANGUL SYLLABLE RWAEBS +B8A7;B8A7;1105 116B 11BA;B8A7;1105 116B 11BA; # (뢧; 뢧; 뢧; 뢧; 뢧; ) HANGUL SYLLABLE RWAES +B8A8;B8A8;1105 116B 11BB;B8A8;1105 116B 11BB; # (뢨; 뢨; 뢨; 뢨; 뢨; ) HANGUL SYLLABLE RWAESS +B8A9;B8A9;1105 116B 11BC;B8A9;1105 116B 11BC; # (뢩; 뢩; 뢩; 뢩; 뢩; ) HANGUL SYLLABLE RWAENG +B8AA;B8AA;1105 116B 11BD;B8AA;1105 116B 11BD; # (뢪; 뢪; 뢪; 뢪; 뢪; ) HANGUL SYLLABLE RWAEJ +B8AB;B8AB;1105 116B 11BE;B8AB;1105 116B 11BE; # (뢫; 뢫; 뢫; 뢫; 뢫; ) HANGUL SYLLABLE RWAEC +B8AC;B8AC;1105 116B 11BF;B8AC;1105 116B 11BF; # (뢬; 뢬; 뢬; 뢬; 뢬; ) HANGUL SYLLABLE RWAEK +B8AD;B8AD;1105 116B 11C0;B8AD;1105 116B 11C0; # (뢭; 뢭; 뢭; 뢭; 뢭; ) HANGUL SYLLABLE RWAET +B8AE;B8AE;1105 116B 11C1;B8AE;1105 116B 11C1; # (뢮; 뢮; 뢮; 뢮; 뢮; ) HANGUL SYLLABLE RWAEP +B8AF;B8AF;1105 116B 11C2;B8AF;1105 116B 11C2; # (뢯; 뢯; 뢯; 뢯; 뢯; ) HANGUL SYLLABLE RWAEH +B8B0;B8B0;1105 116C;B8B0;1105 116C; # (뢰; 뢰; 뢰; 뢰; 뢰; ) HANGUL SYLLABLE ROE +B8B1;B8B1;1105 116C 11A8;B8B1;1105 116C 11A8; # (뢱; 뢱; 뢱; 뢱; 뢱; ) HANGUL SYLLABLE ROEG +B8B2;B8B2;1105 116C 11A9;B8B2;1105 116C 11A9; # (뢲; 뢲; 뢲; 뢲; 뢲; ) HANGUL SYLLABLE ROEGG +B8B3;B8B3;1105 116C 11AA;B8B3;1105 116C 11AA; # (뢳; 뢳; 뢳; 뢳; 뢳; ) HANGUL SYLLABLE ROEGS +B8B4;B8B4;1105 116C 11AB;B8B4;1105 116C 11AB; # (뢴; 뢴; 뢴; 뢴; 뢴; ) HANGUL SYLLABLE ROEN +B8B5;B8B5;1105 116C 11AC;B8B5;1105 116C 11AC; # (뢵; 뢵; 뢵; 뢵; 뢵; ) HANGUL SYLLABLE ROENJ +B8B6;B8B6;1105 116C 11AD;B8B6;1105 116C 11AD; # (뢶; 뢶; 뢶; 뢶; 뢶; ) HANGUL SYLLABLE ROENH +B8B7;B8B7;1105 116C 11AE;B8B7;1105 116C 11AE; # (뢷; 뢷; 뢷; 뢷; 뢷; ) HANGUL SYLLABLE ROED +B8B8;B8B8;1105 116C 11AF;B8B8;1105 116C 11AF; # (뢸; 뢸; 뢸; 뢸; 뢸; ) HANGUL SYLLABLE ROEL +B8B9;B8B9;1105 116C 11B0;B8B9;1105 116C 11B0; # (뢹; 뢹; 뢹; 뢹; 뢹; ) HANGUL SYLLABLE ROELG +B8BA;B8BA;1105 116C 11B1;B8BA;1105 116C 11B1; # (뢺; 뢺; 뢺; 뢺; 뢺; ) HANGUL SYLLABLE ROELM +B8BB;B8BB;1105 116C 11B2;B8BB;1105 116C 11B2; # (뢻; 뢻; 뢻; 뢻; 뢻; ) HANGUL SYLLABLE ROELB +B8BC;B8BC;1105 116C 11B3;B8BC;1105 116C 11B3; # (뢼; 뢼; 뢼; 뢼; 뢼; ) HANGUL SYLLABLE ROELS +B8BD;B8BD;1105 116C 11B4;B8BD;1105 116C 11B4; # (뢽; 뢽; 뢽; 뢽; 뢽; ) HANGUL SYLLABLE ROELT +B8BE;B8BE;1105 116C 11B5;B8BE;1105 116C 11B5; # (뢾; 뢾; 뢾; 뢾; 뢾; ) HANGUL SYLLABLE ROELP +B8BF;B8BF;1105 116C 11B6;B8BF;1105 116C 11B6; # (뢿; 뢿; 뢿; 뢿; 뢿; ) HANGUL SYLLABLE ROELH +B8C0;B8C0;1105 116C 11B7;B8C0;1105 116C 11B7; # (룀; 룀; 룀; 룀; 룀; ) HANGUL SYLLABLE ROEM +B8C1;B8C1;1105 116C 11B8;B8C1;1105 116C 11B8; # (룁; 룁; 룁; 룁; 룁; ) HANGUL SYLLABLE ROEB +B8C2;B8C2;1105 116C 11B9;B8C2;1105 116C 11B9; # (룂; 룂; 룂; 룂; 룂; ) HANGUL SYLLABLE ROEBS +B8C3;B8C3;1105 116C 11BA;B8C3;1105 116C 11BA; # (룃; 룃; 룃; 룃; 룃; ) HANGUL SYLLABLE ROES +B8C4;B8C4;1105 116C 11BB;B8C4;1105 116C 11BB; # (룄; 룄; 룄; 룄; 룄; ) HANGUL SYLLABLE ROESS +B8C5;B8C5;1105 116C 11BC;B8C5;1105 116C 11BC; # (룅; 룅; 룅; 룅; 룅; ) HANGUL SYLLABLE ROENG +B8C6;B8C6;1105 116C 11BD;B8C6;1105 116C 11BD; # (룆; 룆; 룆; 룆; 룆; ) HANGUL SYLLABLE ROEJ +B8C7;B8C7;1105 116C 11BE;B8C7;1105 116C 11BE; # (룇; 룇; 룇; 룇; 룇; ) HANGUL SYLLABLE ROEC +B8C8;B8C8;1105 116C 11BF;B8C8;1105 116C 11BF; # (룈; 룈; 룈; 룈; 룈; ) HANGUL SYLLABLE ROEK +B8C9;B8C9;1105 116C 11C0;B8C9;1105 116C 11C0; # (룉; 룉; 룉; 룉; 룉; ) HANGUL SYLLABLE ROET +B8CA;B8CA;1105 116C 11C1;B8CA;1105 116C 11C1; # (룊; 룊; 룊; 룊; 룊; ) HANGUL SYLLABLE ROEP +B8CB;B8CB;1105 116C 11C2;B8CB;1105 116C 11C2; # (룋; 룋; 룋; 룋; 룋; ) HANGUL SYLLABLE ROEH +B8CC;B8CC;1105 116D;B8CC;1105 116D; # (료; 료; 료; 료; 료; ) HANGUL SYLLABLE RYO +B8CD;B8CD;1105 116D 11A8;B8CD;1105 116D 11A8; # (룍; 룍; 룍; 룍; 룍; ) HANGUL SYLLABLE RYOG +B8CE;B8CE;1105 116D 11A9;B8CE;1105 116D 11A9; # (룎; 룎; 룎; 룎; 룎; ) HANGUL SYLLABLE RYOGG +B8CF;B8CF;1105 116D 11AA;B8CF;1105 116D 11AA; # (룏; 룏; 룏; 룏; 룏; ) HANGUL SYLLABLE RYOGS +B8D0;B8D0;1105 116D 11AB;B8D0;1105 116D 11AB; # (룐; 룐; 룐; 룐; 룐; ) HANGUL SYLLABLE RYON +B8D1;B8D1;1105 116D 11AC;B8D1;1105 116D 11AC; # (룑; 룑; 룑; 룑; 룑; ) HANGUL SYLLABLE RYONJ +B8D2;B8D2;1105 116D 11AD;B8D2;1105 116D 11AD; # (룒; 룒; 룒; 룒; 룒; ) HANGUL SYLLABLE RYONH +B8D3;B8D3;1105 116D 11AE;B8D3;1105 116D 11AE; # (룓; 룓; 룓; 룓; 룓; ) HANGUL SYLLABLE RYOD +B8D4;B8D4;1105 116D 11AF;B8D4;1105 116D 11AF; # (룔; 룔; 룔; 룔; 룔; ) HANGUL SYLLABLE RYOL +B8D5;B8D5;1105 116D 11B0;B8D5;1105 116D 11B0; # (룕; 룕; 룕; 룕; 룕; ) HANGUL SYLLABLE RYOLG +B8D6;B8D6;1105 116D 11B1;B8D6;1105 116D 11B1; # (룖; 룖; 룖; 룖; 룖; ) HANGUL SYLLABLE RYOLM +B8D7;B8D7;1105 116D 11B2;B8D7;1105 116D 11B2; # (룗; 룗; 룗; 룗; 룗; ) HANGUL SYLLABLE RYOLB +B8D8;B8D8;1105 116D 11B3;B8D8;1105 116D 11B3; # (룘; 룘; 룘; 룘; 룘; ) HANGUL SYLLABLE RYOLS +B8D9;B8D9;1105 116D 11B4;B8D9;1105 116D 11B4; # (룙; 룙; 룙; 룙; 룙; ) HANGUL SYLLABLE RYOLT +B8DA;B8DA;1105 116D 11B5;B8DA;1105 116D 11B5; # (룚; 룚; 룚; 룚; 룚; ) HANGUL SYLLABLE RYOLP +B8DB;B8DB;1105 116D 11B6;B8DB;1105 116D 11B6; # (룛; 룛; 룛; 룛; 룛; ) HANGUL SYLLABLE RYOLH +B8DC;B8DC;1105 116D 11B7;B8DC;1105 116D 11B7; # (룜; 룜; 룜; 룜; 룜; ) HANGUL SYLLABLE RYOM +B8DD;B8DD;1105 116D 11B8;B8DD;1105 116D 11B8; # (룝; 룝; 룝; 룝; 룝; ) HANGUL SYLLABLE RYOB +B8DE;B8DE;1105 116D 11B9;B8DE;1105 116D 11B9; # (룞; 룞; 룞; 룞; 룞; ) HANGUL SYLLABLE RYOBS +B8DF;B8DF;1105 116D 11BA;B8DF;1105 116D 11BA; # (룟; 룟; 룟; 룟; 룟; ) HANGUL SYLLABLE RYOS +B8E0;B8E0;1105 116D 11BB;B8E0;1105 116D 11BB; # (룠; 룠; 룠; 룠; 룠; ) HANGUL SYLLABLE RYOSS +B8E1;B8E1;1105 116D 11BC;B8E1;1105 116D 11BC; # (룡; 룡; 룡; 룡; 룡; ) HANGUL SYLLABLE RYONG +B8E2;B8E2;1105 116D 11BD;B8E2;1105 116D 11BD; # (룢; 룢; 룢; 룢; 룢; ) HANGUL SYLLABLE RYOJ +B8E3;B8E3;1105 116D 11BE;B8E3;1105 116D 11BE; # (룣; 룣; 룣; 룣; 룣; ) HANGUL SYLLABLE RYOC +B8E4;B8E4;1105 116D 11BF;B8E4;1105 116D 11BF; # (룤; 룤; 룤; 룤; 룤; ) HANGUL SYLLABLE RYOK +B8E5;B8E5;1105 116D 11C0;B8E5;1105 116D 11C0; # (룥; 룥; 룥; 룥; 룥; ) HANGUL SYLLABLE RYOT +B8E6;B8E6;1105 116D 11C1;B8E6;1105 116D 11C1; # (룦; 룦; 룦; 룦; 룦; ) HANGUL SYLLABLE RYOP +B8E7;B8E7;1105 116D 11C2;B8E7;1105 116D 11C2; # (룧; 룧; 룧; 룧; 룧; ) HANGUL SYLLABLE RYOH +B8E8;B8E8;1105 116E;B8E8;1105 116E; # (루; 루; 루; 루; 루; ) HANGUL SYLLABLE RU +B8E9;B8E9;1105 116E 11A8;B8E9;1105 116E 11A8; # (룩; 룩; 룩; 룩; 룩; ) HANGUL SYLLABLE RUG +B8EA;B8EA;1105 116E 11A9;B8EA;1105 116E 11A9; # (룪; 룪; 룪; 룪; 룪; ) HANGUL SYLLABLE RUGG +B8EB;B8EB;1105 116E 11AA;B8EB;1105 116E 11AA; # (룫; 룫; 룫; 룫; 룫; ) HANGUL SYLLABLE RUGS +B8EC;B8EC;1105 116E 11AB;B8EC;1105 116E 11AB; # (룬; 룬; 룬; 룬; 룬; ) HANGUL SYLLABLE RUN +B8ED;B8ED;1105 116E 11AC;B8ED;1105 116E 11AC; # (룭; 룭; 룭; 룭; 룭; ) HANGUL SYLLABLE RUNJ +B8EE;B8EE;1105 116E 11AD;B8EE;1105 116E 11AD; # (룮; 룮; 룮; 룮; 룮; ) HANGUL SYLLABLE RUNH +B8EF;B8EF;1105 116E 11AE;B8EF;1105 116E 11AE; # (룯; 룯; 룯; 룯; 룯; ) HANGUL SYLLABLE RUD +B8F0;B8F0;1105 116E 11AF;B8F0;1105 116E 11AF; # (룰; 룰; 룰; 룰; 룰; ) HANGUL SYLLABLE RUL +B8F1;B8F1;1105 116E 11B0;B8F1;1105 116E 11B0; # (룱; 룱; 룱; 룱; 룱; ) HANGUL SYLLABLE RULG +B8F2;B8F2;1105 116E 11B1;B8F2;1105 116E 11B1; # (룲; 룲; 룲; 룲; 룲; ) HANGUL SYLLABLE RULM +B8F3;B8F3;1105 116E 11B2;B8F3;1105 116E 11B2; # (룳; 룳; 룳; 룳; 룳; ) HANGUL SYLLABLE RULB +B8F4;B8F4;1105 116E 11B3;B8F4;1105 116E 11B3; # (룴; 룴; 룴; 룴; 룴; ) HANGUL SYLLABLE RULS +B8F5;B8F5;1105 116E 11B4;B8F5;1105 116E 11B4; # (룵; 룵; 룵; 룵; 룵; ) HANGUL SYLLABLE RULT +B8F6;B8F6;1105 116E 11B5;B8F6;1105 116E 11B5; # (룶; 룶; 룶; 룶; 룶; ) HANGUL SYLLABLE RULP +B8F7;B8F7;1105 116E 11B6;B8F7;1105 116E 11B6; # (룷; 룷; 룷; 룷; 룷; ) HANGUL SYLLABLE RULH +B8F8;B8F8;1105 116E 11B7;B8F8;1105 116E 11B7; # (룸; 룸; 룸; 룸; 룸; ) HANGUL SYLLABLE RUM +B8F9;B8F9;1105 116E 11B8;B8F9;1105 116E 11B8; # (룹; 룹; 룹; 룹; 룹; ) HANGUL SYLLABLE RUB +B8FA;B8FA;1105 116E 11B9;B8FA;1105 116E 11B9; # (룺; 룺; 룺; 룺; 룺; ) HANGUL SYLLABLE RUBS +B8FB;B8FB;1105 116E 11BA;B8FB;1105 116E 11BA; # (룻; 룻; 룻; 룻; 룻; ) HANGUL SYLLABLE RUS +B8FC;B8FC;1105 116E 11BB;B8FC;1105 116E 11BB; # (룼; 룼; 룼; 룼; 룼; ) HANGUL SYLLABLE RUSS +B8FD;B8FD;1105 116E 11BC;B8FD;1105 116E 11BC; # (룽; 룽; 룽; 룽; 룽; ) HANGUL SYLLABLE RUNG +B8FE;B8FE;1105 116E 11BD;B8FE;1105 116E 11BD; # (룾; 룾; 룾; 룾; 룾; ) HANGUL SYLLABLE RUJ +B8FF;B8FF;1105 116E 11BE;B8FF;1105 116E 11BE; # (룿; 룿; 룿; 룿; 룿; ) HANGUL SYLLABLE RUC +B900;B900;1105 116E 11BF;B900;1105 116E 11BF; # (뤀; 뤀; 뤀; 뤀; 뤀; ) HANGUL SYLLABLE RUK +B901;B901;1105 116E 11C0;B901;1105 116E 11C0; # (뤁; 뤁; 뤁; 뤁; 뤁; ) HANGUL SYLLABLE RUT +B902;B902;1105 116E 11C1;B902;1105 116E 11C1; # (뤂; 뤂; 뤂; 뤂; 뤂; ) HANGUL SYLLABLE RUP +B903;B903;1105 116E 11C2;B903;1105 116E 11C2; # (뤃; 뤃; 뤃; 뤃; 뤃; ) HANGUL SYLLABLE RUH +B904;B904;1105 116F;B904;1105 116F; # (뤄; 뤄; 뤄; 뤄; 뤄; ) HANGUL SYLLABLE RWEO +B905;B905;1105 116F 11A8;B905;1105 116F 11A8; # (뤅; 뤅; 뤅; 뤅; 뤅; ) HANGUL SYLLABLE RWEOG +B906;B906;1105 116F 11A9;B906;1105 116F 11A9; # (뤆; 뤆; 뤆; 뤆; 뤆; ) HANGUL SYLLABLE RWEOGG +B907;B907;1105 116F 11AA;B907;1105 116F 11AA; # (뤇; 뤇; 뤇; 뤇; 뤇; ) HANGUL SYLLABLE RWEOGS +B908;B908;1105 116F 11AB;B908;1105 116F 11AB; # (뤈; 뤈; 뤈; 뤈; 뤈; ) HANGUL SYLLABLE RWEON +B909;B909;1105 116F 11AC;B909;1105 116F 11AC; # (뤉; 뤉; 뤉; 뤉; 뤉; ) HANGUL SYLLABLE RWEONJ +B90A;B90A;1105 116F 11AD;B90A;1105 116F 11AD; # (뤊; 뤊; 뤊; 뤊; 뤊; ) HANGUL SYLLABLE RWEONH +B90B;B90B;1105 116F 11AE;B90B;1105 116F 11AE; # (뤋; 뤋; 뤋; 뤋; 뤋; ) HANGUL SYLLABLE RWEOD +B90C;B90C;1105 116F 11AF;B90C;1105 116F 11AF; # (뤌; 뤌; 뤌; 뤌; 뤌; ) HANGUL SYLLABLE RWEOL +B90D;B90D;1105 116F 11B0;B90D;1105 116F 11B0; # (뤍; 뤍; 뤍; 뤍; 뤍; ) HANGUL SYLLABLE RWEOLG +B90E;B90E;1105 116F 11B1;B90E;1105 116F 11B1; # (뤎; 뤎; 뤎; 뤎; 뤎; ) HANGUL SYLLABLE RWEOLM +B90F;B90F;1105 116F 11B2;B90F;1105 116F 11B2; # (뤏; 뤏; 뤏; 뤏; 뤏; ) HANGUL SYLLABLE RWEOLB +B910;B910;1105 116F 11B3;B910;1105 116F 11B3; # (뤐; 뤐; 뤐; 뤐; 뤐; ) HANGUL SYLLABLE RWEOLS +B911;B911;1105 116F 11B4;B911;1105 116F 11B4; # (뤑; 뤑; 뤑; 뤑; 뤑; ) HANGUL SYLLABLE RWEOLT +B912;B912;1105 116F 11B5;B912;1105 116F 11B5; # (뤒; 뤒; 뤒; 뤒; 뤒; ) HANGUL SYLLABLE RWEOLP +B913;B913;1105 116F 11B6;B913;1105 116F 11B6; # (뤓; 뤓; 뤓; 뤓; 뤓; ) HANGUL SYLLABLE RWEOLH +B914;B914;1105 116F 11B7;B914;1105 116F 11B7; # (뤔; 뤔; 뤔; 뤔; 뤔; ) HANGUL SYLLABLE RWEOM +B915;B915;1105 116F 11B8;B915;1105 116F 11B8; # (뤕; 뤕; 뤕; 뤕; 뤕; ) HANGUL SYLLABLE RWEOB +B916;B916;1105 116F 11B9;B916;1105 116F 11B9; # (뤖; 뤖; 뤖; 뤖; 뤖; ) HANGUL SYLLABLE RWEOBS +B917;B917;1105 116F 11BA;B917;1105 116F 11BA; # (뤗; 뤗; 뤗; 뤗; 뤗; ) HANGUL SYLLABLE RWEOS +B918;B918;1105 116F 11BB;B918;1105 116F 11BB; # (뤘; 뤘; 뤘; 뤘; 뤘; ) HANGUL SYLLABLE RWEOSS +B919;B919;1105 116F 11BC;B919;1105 116F 11BC; # (뤙; 뤙; 뤙; 뤙; 뤙; ) HANGUL SYLLABLE RWEONG +B91A;B91A;1105 116F 11BD;B91A;1105 116F 11BD; # (뤚; 뤚; 뤚; 뤚; 뤚; ) HANGUL SYLLABLE RWEOJ +B91B;B91B;1105 116F 11BE;B91B;1105 116F 11BE; # (뤛; 뤛; 뤛; 뤛; 뤛; ) HANGUL SYLLABLE RWEOC +B91C;B91C;1105 116F 11BF;B91C;1105 116F 11BF; # (뤜; 뤜; 뤜; 뤜; 뤜; ) HANGUL SYLLABLE RWEOK +B91D;B91D;1105 116F 11C0;B91D;1105 116F 11C0; # (뤝; 뤝; 뤝; 뤝; 뤝; ) HANGUL SYLLABLE RWEOT +B91E;B91E;1105 116F 11C1;B91E;1105 116F 11C1; # (뤞; 뤞; 뤞; 뤞; 뤞; ) HANGUL SYLLABLE RWEOP +B91F;B91F;1105 116F 11C2;B91F;1105 116F 11C2; # (뤟; 뤟; 뤟; 뤟; 뤟; ) HANGUL SYLLABLE RWEOH +B920;B920;1105 1170;B920;1105 1170; # (뤠; 뤠; 뤠; 뤠; 뤠; ) HANGUL SYLLABLE RWE +B921;B921;1105 1170 11A8;B921;1105 1170 11A8; # (뤡; 뤡; 뤡; 뤡; 뤡; ) HANGUL SYLLABLE RWEG +B922;B922;1105 1170 11A9;B922;1105 1170 11A9; # (뤢; 뤢; 뤢; 뤢; 뤢; ) HANGUL SYLLABLE RWEGG +B923;B923;1105 1170 11AA;B923;1105 1170 11AA; # (뤣; 뤣; 뤣; 뤣; 뤣; ) HANGUL SYLLABLE RWEGS +B924;B924;1105 1170 11AB;B924;1105 1170 11AB; # (뤤; 뤤; 뤤; 뤤; 뤤; ) HANGUL SYLLABLE RWEN +B925;B925;1105 1170 11AC;B925;1105 1170 11AC; # (뤥; 뤥; 뤥; 뤥; 뤥; ) HANGUL SYLLABLE RWENJ +B926;B926;1105 1170 11AD;B926;1105 1170 11AD; # (뤦; 뤦; 뤦; 뤦; 뤦; ) HANGUL SYLLABLE RWENH +B927;B927;1105 1170 11AE;B927;1105 1170 11AE; # (뤧; 뤧; 뤧; 뤧; 뤧; ) HANGUL SYLLABLE RWED +B928;B928;1105 1170 11AF;B928;1105 1170 11AF; # (뤨; 뤨; 뤨; 뤨; 뤨; ) HANGUL SYLLABLE RWEL +B929;B929;1105 1170 11B0;B929;1105 1170 11B0; # (뤩; 뤩; 뤩; 뤩; 뤩; ) HANGUL SYLLABLE RWELG +B92A;B92A;1105 1170 11B1;B92A;1105 1170 11B1; # (뤪; 뤪; 뤪; 뤪; 뤪; ) HANGUL SYLLABLE RWELM +B92B;B92B;1105 1170 11B2;B92B;1105 1170 11B2; # (뤫; 뤫; 뤫; 뤫; 뤫; ) HANGUL SYLLABLE RWELB +B92C;B92C;1105 1170 11B3;B92C;1105 1170 11B3; # (뤬; 뤬; 뤬; 뤬; 뤬; ) HANGUL SYLLABLE RWELS +B92D;B92D;1105 1170 11B4;B92D;1105 1170 11B4; # (뤭; 뤭; 뤭; 뤭; 뤭; ) HANGUL SYLLABLE RWELT +B92E;B92E;1105 1170 11B5;B92E;1105 1170 11B5; # (뤮; 뤮; 뤮; 뤮; 뤮; ) HANGUL SYLLABLE RWELP +B92F;B92F;1105 1170 11B6;B92F;1105 1170 11B6; # (뤯; 뤯; 뤯; 뤯; 뤯; ) HANGUL SYLLABLE RWELH +B930;B930;1105 1170 11B7;B930;1105 1170 11B7; # (뤰; 뤰; 뤰; 뤰; 뤰; ) HANGUL SYLLABLE RWEM +B931;B931;1105 1170 11B8;B931;1105 1170 11B8; # (뤱; 뤱; 뤱; 뤱; 뤱; ) HANGUL SYLLABLE RWEB +B932;B932;1105 1170 11B9;B932;1105 1170 11B9; # (뤲; 뤲; 뤲; 뤲; 뤲; ) HANGUL SYLLABLE RWEBS +B933;B933;1105 1170 11BA;B933;1105 1170 11BA; # (뤳; 뤳; 뤳; 뤳; 뤳; ) HANGUL SYLLABLE RWES +B934;B934;1105 1170 11BB;B934;1105 1170 11BB; # (뤴; 뤴; 뤴; 뤴; 뤴; ) HANGUL SYLLABLE RWESS +B935;B935;1105 1170 11BC;B935;1105 1170 11BC; # (뤵; 뤵; 뤵; 뤵; 뤵; ) HANGUL SYLLABLE RWENG +B936;B936;1105 1170 11BD;B936;1105 1170 11BD; # (뤶; 뤶; 뤶; 뤶; 뤶; ) HANGUL SYLLABLE RWEJ +B937;B937;1105 1170 11BE;B937;1105 1170 11BE; # (뤷; 뤷; 뤷; 뤷; 뤷; ) HANGUL SYLLABLE RWEC +B938;B938;1105 1170 11BF;B938;1105 1170 11BF; # (뤸; 뤸; 뤸; 뤸; 뤸; ) HANGUL SYLLABLE RWEK +B939;B939;1105 1170 11C0;B939;1105 1170 11C0; # (뤹; 뤹; 뤹; 뤹; 뤹; ) HANGUL SYLLABLE RWET +B93A;B93A;1105 1170 11C1;B93A;1105 1170 11C1; # (뤺; 뤺; 뤺; 뤺; 뤺; ) HANGUL SYLLABLE RWEP +B93B;B93B;1105 1170 11C2;B93B;1105 1170 11C2; # (뤻; 뤻; 뤻; 뤻; 뤻; ) HANGUL SYLLABLE RWEH +B93C;B93C;1105 1171;B93C;1105 1171; # (뤼; 뤼; 뤼; 뤼; 뤼; ) HANGUL SYLLABLE RWI +B93D;B93D;1105 1171 11A8;B93D;1105 1171 11A8; # (뤽; 뤽; 뤽; 뤽; 뤽; ) HANGUL SYLLABLE RWIG +B93E;B93E;1105 1171 11A9;B93E;1105 1171 11A9; # (뤾; 뤾; 뤾; 뤾; 뤾; ) HANGUL SYLLABLE RWIGG +B93F;B93F;1105 1171 11AA;B93F;1105 1171 11AA; # (뤿; 뤿; 뤿; 뤿; 뤿; ) HANGUL SYLLABLE RWIGS +B940;B940;1105 1171 11AB;B940;1105 1171 11AB; # (륀; 륀; 륀; 륀; 륀; ) HANGUL SYLLABLE RWIN +B941;B941;1105 1171 11AC;B941;1105 1171 11AC; # (륁; 륁; 륁; 륁; 륁; ) HANGUL SYLLABLE RWINJ +B942;B942;1105 1171 11AD;B942;1105 1171 11AD; # (륂; 륂; 륂; 륂; 륂; ) HANGUL SYLLABLE RWINH +B943;B943;1105 1171 11AE;B943;1105 1171 11AE; # (륃; 륃; 륃; 륃; 륃; ) HANGUL SYLLABLE RWID +B944;B944;1105 1171 11AF;B944;1105 1171 11AF; # (륄; 륄; 륄; 륄; 륄; ) HANGUL SYLLABLE RWIL +B945;B945;1105 1171 11B0;B945;1105 1171 11B0; # (륅; 륅; 륅; 륅; 륅; ) HANGUL SYLLABLE RWILG +B946;B946;1105 1171 11B1;B946;1105 1171 11B1; # (륆; 륆; 륆; 륆; 륆; ) HANGUL SYLLABLE RWILM +B947;B947;1105 1171 11B2;B947;1105 1171 11B2; # (륇; 륇; 륇; 륇; 륇; ) HANGUL SYLLABLE RWILB +B948;B948;1105 1171 11B3;B948;1105 1171 11B3; # (륈; 륈; 륈; 륈; 륈; ) HANGUL SYLLABLE RWILS +B949;B949;1105 1171 11B4;B949;1105 1171 11B4; # (륉; 륉; 륉; 륉; 륉; ) HANGUL SYLLABLE RWILT +B94A;B94A;1105 1171 11B5;B94A;1105 1171 11B5; # (륊; 륊; 륊; 륊; 륊; ) HANGUL SYLLABLE RWILP +B94B;B94B;1105 1171 11B6;B94B;1105 1171 11B6; # (륋; 륋; 륋; 륋; 륋; ) HANGUL SYLLABLE RWILH +B94C;B94C;1105 1171 11B7;B94C;1105 1171 11B7; # (륌; 륌; 륌; 륌; 륌; ) HANGUL SYLLABLE RWIM +B94D;B94D;1105 1171 11B8;B94D;1105 1171 11B8; # (륍; 륍; 륍; 륍; 륍; ) HANGUL SYLLABLE RWIB +B94E;B94E;1105 1171 11B9;B94E;1105 1171 11B9; # (륎; 륎; 륎; 륎; 륎; ) HANGUL SYLLABLE RWIBS +B94F;B94F;1105 1171 11BA;B94F;1105 1171 11BA; # (륏; 륏; 륏; 륏; 륏; ) HANGUL SYLLABLE RWIS +B950;B950;1105 1171 11BB;B950;1105 1171 11BB; # (륐; 륐; 륐; 륐; 륐; ) HANGUL SYLLABLE RWISS +B951;B951;1105 1171 11BC;B951;1105 1171 11BC; # (륑; 륑; 륑; 륑; 륑; ) HANGUL SYLLABLE RWING +B952;B952;1105 1171 11BD;B952;1105 1171 11BD; # (륒; 륒; 륒; 륒; 륒; ) HANGUL SYLLABLE RWIJ +B953;B953;1105 1171 11BE;B953;1105 1171 11BE; # (륓; 륓; 륓; 륓; 륓; ) HANGUL SYLLABLE RWIC +B954;B954;1105 1171 11BF;B954;1105 1171 11BF; # (륔; 륔; 륔; 륔; 륔; ) HANGUL SYLLABLE RWIK +B955;B955;1105 1171 11C0;B955;1105 1171 11C0; # (륕; 륕; 륕; 륕; 륕; ) HANGUL SYLLABLE RWIT +B956;B956;1105 1171 11C1;B956;1105 1171 11C1; # (륖; 륖; 륖; 륖; 륖; ) HANGUL SYLLABLE RWIP +B957;B957;1105 1171 11C2;B957;1105 1171 11C2; # (륗; 륗; 륗; 륗; 륗; ) HANGUL SYLLABLE RWIH +B958;B958;1105 1172;B958;1105 1172; # (류; 류; 류; 류; 류; ) HANGUL SYLLABLE RYU +B959;B959;1105 1172 11A8;B959;1105 1172 11A8; # (륙; 륙; 륙; 륙; 륙; ) HANGUL SYLLABLE RYUG +B95A;B95A;1105 1172 11A9;B95A;1105 1172 11A9; # (륚; 륚; 륚; 륚; 륚; ) HANGUL SYLLABLE RYUGG +B95B;B95B;1105 1172 11AA;B95B;1105 1172 11AA; # (륛; 륛; 륛; 륛; 륛; ) HANGUL SYLLABLE RYUGS +B95C;B95C;1105 1172 11AB;B95C;1105 1172 11AB; # (륜; 륜; 륜; 륜; 륜; ) HANGUL SYLLABLE RYUN +B95D;B95D;1105 1172 11AC;B95D;1105 1172 11AC; # (륝; 륝; 륝; 륝; 륝; ) HANGUL SYLLABLE RYUNJ +B95E;B95E;1105 1172 11AD;B95E;1105 1172 11AD; # (륞; 륞; 륞; 륞; 륞; ) HANGUL SYLLABLE RYUNH +B95F;B95F;1105 1172 11AE;B95F;1105 1172 11AE; # (륟; 륟; 륟; 륟; 륟; ) HANGUL SYLLABLE RYUD +B960;B960;1105 1172 11AF;B960;1105 1172 11AF; # (률; 률; 률; 률; 률; ) HANGUL SYLLABLE RYUL +B961;B961;1105 1172 11B0;B961;1105 1172 11B0; # (륡; 륡; 륡; 륡; 륡; ) HANGUL SYLLABLE RYULG +B962;B962;1105 1172 11B1;B962;1105 1172 11B1; # (륢; 륢; 륢; 륢; 륢; ) HANGUL SYLLABLE RYULM +B963;B963;1105 1172 11B2;B963;1105 1172 11B2; # (륣; 륣; 륣; 륣; 륣; ) HANGUL SYLLABLE RYULB +B964;B964;1105 1172 11B3;B964;1105 1172 11B3; # (륤; 륤; 륤; 륤; 륤; ) HANGUL SYLLABLE RYULS +B965;B965;1105 1172 11B4;B965;1105 1172 11B4; # (륥; 륥; 륥; 륥; 륥; ) HANGUL SYLLABLE RYULT +B966;B966;1105 1172 11B5;B966;1105 1172 11B5; # (륦; 륦; 륦; 륦; 륦; ) HANGUL SYLLABLE RYULP +B967;B967;1105 1172 11B6;B967;1105 1172 11B6; # (륧; 륧; 륧; 륧; 륧; ) HANGUL SYLLABLE RYULH +B968;B968;1105 1172 11B7;B968;1105 1172 11B7; # (륨; 륨; 륨; 륨; 륨; ) HANGUL SYLLABLE RYUM +B969;B969;1105 1172 11B8;B969;1105 1172 11B8; # (륩; 륩; 륩; 륩; 륩; ) HANGUL SYLLABLE RYUB +B96A;B96A;1105 1172 11B9;B96A;1105 1172 11B9; # (륪; 륪; 륪; 륪; 륪; ) HANGUL SYLLABLE RYUBS +B96B;B96B;1105 1172 11BA;B96B;1105 1172 11BA; # (륫; 륫; 륫; 륫; 륫; ) HANGUL SYLLABLE RYUS +B96C;B96C;1105 1172 11BB;B96C;1105 1172 11BB; # (륬; 륬; 륬; 륬; 륬; ) HANGUL SYLLABLE RYUSS +B96D;B96D;1105 1172 11BC;B96D;1105 1172 11BC; # (륭; 륭; 륭; 륭; 륭; ) HANGUL SYLLABLE RYUNG +B96E;B96E;1105 1172 11BD;B96E;1105 1172 11BD; # (륮; 륮; 륮; 륮; 륮; ) HANGUL SYLLABLE RYUJ +B96F;B96F;1105 1172 11BE;B96F;1105 1172 11BE; # (륯; 륯; 륯; 륯; 륯; ) HANGUL SYLLABLE RYUC +B970;B970;1105 1172 11BF;B970;1105 1172 11BF; # (륰; 륰; 륰; 륰; 륰; ) HANGUL SYLLABLE RYUK +B971;B971;1105 1172 11C0;B971;1105 1172 11C0; # (륱; 륱; 륱; 륱; 륱; ) HANGUL SYLLABLE RYUT +B972;B972;1105 1172 11C1;B972;1105 1172 11C1; # (륲; 륲; 륲; 륲; 륲; ) HANGUL SYLLABLE RYUP +B973;B973;1105 1172 11C2;B973;1105 1172 11C2; # (륳; 륳; 륳; 륳; 륳; ) HANGUL SYLLABLE RYUH +B974;B974;1105 1173;B974;1105 1173; # (르; 르; 르; 르; 르; ) HANGUL SYLLABLE REU +B975;B975;1105 1173 11A8;B975;1105 1173 11A8; # (륵; 륵; 륵; 륵; 륵; ) HANGUL SYLLABLE REUG +B976;B976;1105 1173 11A9;B976;1105 1173 11A9; # (륶; 륶; 륶; 륶; 륶; ) HANGUL SYLLABLE REUGG +B977;B977;1105 1173 11AA;B977;1105 1173 11AA; # (륷; 륷; 륷; 륷; 륷; ) HANGUL SYLLABLE REUGS +B978;B978;1105 1173 11AB;B978;1105 1173 11AB; # (른; 른; 른; 른; 른; ) HANGUL SYLLABLE REUN +B979;B979;1105 1173 11AC;B979;1105 1173 11AC; # (륹; 륹; 륹; 륹; 륹; ) HANGUL SYLLABLE REUNJ +B97A;B97A;1105 1173 11AD;B97A;1105 1173 11AD; # (륺; 륺; 륺; 륺; 륺; ) HANGUL SYLLABLE REUNH +B97B;B97B;1105 1173 11AE;B97B;1105 1173 11AE; # (륻; 륻; 륻; 륻; 륻; ) HANGUL SYLLABLE REUD +B97C;B97C;1105 1173 11AF;B97C;1105 1173 11AF; # (를; 를; 를; 를; 를; ) HANGUL SYLLABLE REUL +B97D;B97D;1105 1173 11B0;B97D;1105 1173 11B0; # (륽; 륽; 륽; 륽; 륽; ) HANGUL SYLLABLE REULG +B97E;B97E;1105 1173 11B1;B97E;1105 1173 11B1; # (륾; 륾; 륾; 륾; 륾; ) HANGUL SYLLABLE REULM +B97F;B97F;1105 1173 11B2;B97F;1105 1173 11B2; # (륿; 륿; 륿; 륿; 륿; ) HANGUL SYLLABLE REULB +B980;B980;1105 1173 11B3;B980;1105 1173 11B3; # (릀; 릀; 릀; 릀; 릀; ) HANGUL SYLLABLE REULS +B981;B981;1105 1173 11B4;B981;1105 1173 11B4; # (릁; 릁; 릁; 릁; 릁; ) HANGUL SYLLABLE REULT +B982;B982;1105 1173 11B5;B982;1105 1173 11B5; # (릂; 릂; 릂; 릂; 릂; ) HANGUL SYLLABLE REULP +B983;B983;1105 1173 11B6;B983;1105 1173 11B6; # (릃; 릃; 릃; 릃; 릃; ) HANGUL SYLLABLE REULH +B984;B984;1105 1173 11B7;B984;1105 1173 11B7; # (름; 름; 름; 름; 름; ) HANGUL SYLLABLE REUM +B985;B985;1105 1173 11B8;B985;1105 1173 11B8; # (릅; 릅; 릅; 릅; 릅; ) HANGUL SYLLABLE REUB +B986;B986;1105 1173 11B9;B986;1105 1173 11B9; # (릆; 릆; 릆; 릆; 릆; ) HANGUL SYLLABLE REUBS +B987;B987;1105 1173 11BA;B987;1105 1173 11BA; # (릇; 릇; 릇; 릇; 릇; ) HANGUL SYLLABLE REUS +B988;B988;1105 1173 11BB;B988;1105 1173 11BB; # (릈; 릈; 릈; 릈; 릈; ) HANGUL SYLLABLE REUSS +B989;B989;1105 1173 11BC;B989;1105 1173 11BC; # (릉; 릉; 릉; 릉; 릉; ) HANGUL SYLLABLE REUNG +B98A;B98A;1105 1173 11BD;B98A;1105 1173 11BD; # (릊; 릊; 릊; 릊; 릊; ) HANGUL SYLLABLE REUJ +B98B;B98B;1105 1173 11BE;B98B;1105 1173 11BE; # (릋; 릋; 릋; 릋; 릋; ) HANGUL SYLLABLE REUC +B98C;B98C;1105 1173 11BF;B98C;1105 1173 11BF; # (릌; 릌; 릌; 릌; 릌; ) HANGUL SYLLABLE REUK +B98D;B98D;1105 1173 11C0;B98D;1105 1173 11C0; # (릍; 릍; 릍; 릍; 릍; ) HANGUL SYLLABLE REUT +B98E;B98E;1105 1173 11C1;B98E;1105 1173 11C1; # (릎; 릎; 릎; 릎; 릎; ) HANGUL SYLLABLE REUP +B98F;B98F;1105 1173 11C2;B98F;1105 1173 11C2; # (릏; 릏; 릏; 릏; 릏; ) HANGUL SYLLABLE REUH +B990;B990;1105 1174;B990;1105 1174; # (릐; 릐; 릐; 릐; 릐; ) HANGUL SYLLABLE RYI +B991;B991;1105 1174 11A8;B991;1105 1174 11A8; # (릑; 릑; 릑; 릑; 릑; ) HANGUL SYLLABLE RYIG +B992;B992;1105 1174 11A9;B992;1105 1174 11A9; # (릒; 릒; 릒; 릒; 릒; ) HANGUL SYLLABLE RYIGG +B993;B993;1105 1174 11AA;B993;1105 1174 11AA; # (릓; 릓; 릓; 릓; 릓; ) HANGUL SYLLABLE RYIGS +B994;B994;1105 1174 11AB;B994;1105 1174 11AB; # (릔; 릔; 릔; 릔; 릔; ) HANGUL SYLLABLE RYIN +B995;B995;1105 1174 11AC;B995;1105 1174 11AC; # (릕; 릕; 릕; 릕; 릕; ) HANGUL SYLLABLE RYINJ +B996;B996;1105 1174 11AD;B996;1105 1174 11AD; # (릖; 릖; 릖; 릖; 릖; ) HANGUL SYLLABLE RYINH +B997;B997;1105 1174 11AE;B997;1105 1174 11AE; # (릗; 릗; 릗; 릗; 릗; ) HANGUL SYLLABLE RYID +B998;B998;1105 1174 11AF;B998;1105 1174 11AF; # (릘; 릘; 릘; 릘; 릘; ) HANGUL SYLLABLE RYIL +B999;B999;1105 1174 11B0;B999;1105 1174 11B0; # (릙; 릙; 릙; 릙; 릙; ) HANGUL SYLLABLE RYILG +B99A;B99A;1105 1174 11B1;B99A;1105 1174 11B1; # (릚; 릚; 릚; 릚; 릚; ) HANGUL SYLLABLE RYILM +B99B;B99B;1105 1174 11B2;B99B;1105 1174 11B2; # (릛; 릛; 릛; 릛; 릛; ) HANGUL SYLLABLE RYILB +B99C;B99C;1105 1174 11B3;B99C;1105 1174 11B3; # (릜; 릜; 릜; 릜; 릜; ) HANGUL SYLLABLE RYILS +B99D;B99D;1105 1174 11B4;B99D;1105 1174 11B4; # (릝; 릝; 릝; 릝; 릝; ) HANGUL SYLLABLE RYILT +B99E;B99E;1105 1174 11B5;B99E;1105 1174 11B5; # (릞; 릞; 릞; 릞; 릞; ) HANGUL SYLLABLE RYILP +B99F;B99F;1105 1174 11B6;B99F;1105 1174 11B6; # (릟; 릟; 릟; 릟; 릟; ) HANGUL SYLLABLE RYILH +B9A0;B9A0;1105 1174 11B7;B9A0;1105 1174 11B7; # (릠; 릠; 릠; 릠; 릠; ) HANGUL SYLLABLE RYIM +B9A1;B9A1;1105 1174 11B8;B9A1;1105 1174 11B8; # (릡; 릡; 릡; 릡; 릡; ) HANGUL SYLLABLE RYIB +B9A2;B9A2;1105 1174 11B9;B9A2;1105 1174 11B9; # (릢; 릢; 릢; 릢; 릢; ) HANGUL SYLLABLE RYIBS +B9A3;B9A3;1105 1174 11BA;B9A3;1105 1174 11BA; # (릣; 릣; 릣; 릣; 릣; ) HANGUL SYLLABLE RYIS +B9A4;B9A4;1105 1174 11BB;B9A4;1105 1174 11BB; # (릤; 릤; 릤; 릤; 릤; ) HANGUL SYLLABLE RYISS +B9A5;B9A5;1105 1174 11BC;B9A5;1105 1174 11BC; # (릥; 릥; 릥; 릥; 릥; ) HANGUL SYLLABLE RYING +B9A6;B9A6;1105 1174 11BD;B9A6;1105 1174 11BD; # (릦; 릦; 릦; 릦; 릦; ) HANGUL SYLLABLE RYIJ +B9A7;B9A7;1105 1174 11BE;B9A7;1105 1174 11BE; # (릧; 릧; 릧; 릧; 릧; ) HANGUL SYLLABLE RYIC +B9A8;B9A8;1105 1174 11BF;B9A8;1105 1174 11BF; # (릨; 릨; 릨; 릨; 릨; ) HANGUL SYLLABLE RYIK +B9A9;B9A9;1105 1174 11C0;B9A9;1105 1174 11C0; # (릩; 릩; 릩; 릩; 릩; ) HANGUL SYLLABLE RYIT +B9AA;B9AA;1105 1174 11C1;B9AA;1105 1174 11C1; # (릪; 릪; 릪; 릪; 릪; ) HANGUL SYLLABLE RYIP +B9AB;B9AB;1105 1174 11C2;B9AB;1105 1174 11C2; # (릫; 릫; 릫; 릫; 릫; ) HANGUL SYLLABLE RYIH +B9AC;B9AC;1105 1175;B9AC;1105 1175; # (리; 리; 리; 리; 리; ) HANGUL SYLLABLE RI +B9AD;B9AD;1105 1175 11A8;B9AD;1105 1175 11A8; # (릭; 릭; 릭; 릭; 릭; ) HANGUL SYLLABLE RIG +B9AE;B9AE;1105 1175 11A9;B9AE;1105 1175 11A9; # (릮; 릮; 릮; 릮; 릮; ) HANGUL SYLLABLE RIGG +B9AF;B9AF;1105 1175 11AA;B9AF;1105 1175 11AA; # (릯; 릯; 릯; 릯; 릯; ) HANGUL SYLLABLE RIGS +B9B0;B9B0;1105 1175 11AB;B9B0;1105 1175 11AB; # (린; 린; 린; 린; 린; ) HANGUL SYLLABLE RIN +B9B1;B9B1;1105 1175 11AC;B9B1;1105 1175 11AC; # (릱; 릱; 릱; 릱; 릱; ) HANGUL SYLLABLE RINJ +B9B2;B9B2;1105 1175 11AD;B9B2;1105 1175 11AD; # (릲; 릲; 릲; 릲; 릲; ) HANGUL SYLLABLE RINH +B9B3;B9B3;1105 1175 11AE;B9B3;1105 1175 11AE; # (릳; 릳; 릳; 릳; 릳; ) HANGUL SYLLABLE RID +B9B4;B9B4;1105 1175 11AF;B9B4;1105 1175 11AF; # (릴; 릴; 릴; 릴; 릴; ) HANGUL SYLLABLE RIL +B9B5;B9B5;1105 1175 11B0;B9B5;1105 1175 11B0; # (릵; 릵; 릵; 릵; 릵; ) HANGUL SYLLABLE RILG +B9B6;B9B6;1105 1175 11B1;B9B6;1105 1175 11B1; # (릶; 릶; 릶; 릶; 릶; ) HANGUL SYLLABLE RILM +B9B7;B9B7;1105 1175 11B2;B9B7;1105 1175 11B2; # (릷; 릷; 릷; 릷; 릷; ) HANGUL SYLLABLE RILB +B9B8;B9B8;1105 1175 11B3;B9B8;1105 1175 11B3; # (릸; 릸; 릸; 릸; 릸; ) HANGUL SYLLABLE RILS +B9B9;B9B9;1105 1175 11B4;B9B9;1105 1175 11B4; # (릹; 릹; 릹; 릹; 릹; ) HANGUL SYLLABLE RILT +B9BA;B9BA;1105 1175 11B5;B9BA;1105 1175 11B5; # (릺; 릺; 릺; 릺; 릺; ) HANGUL SYLLABLE RILP +B9BB;B9BB;1105 1175 11B6;B9BB;1105 1175 11B6; # (릻; 릻; 릻; 릻; 릻; ) HANGUL SYLLABLE RILH +B9BC;B9BC;1105 1175 11B7;B9BC;1105 1175 11B7; # (림; 림; 림; 림; 림; ) HANGUL SYLLABLE RIM +B9BD;B9BD;1105 1175 11B8;B9BD;1105 1175 11B8; # (립; 립; 립; 립; 립; ) HANGUL SYLLABLE RIB +B9BE;B9BE;1105 1175 11B9;B9BE;1105 1175 11B9; # (릾; 릾; 릾; 릾; 릾; ) HANGUL SYLLABLE RIBS +B9BF;B9BF;1105 1175 11BA;B9BF;1105 1175 11BA; # (릿; 릿; 릿; 릿; 릿; ) HANGUL SYLLABLE RIS +B9C0;B9C0;1105 1175 11BB;B9C0;1105 1175 11BB; # (맀; 맀; 맀; 맀; 맀; ) HANGUL SYLLABLE RISS +B9C1;B9C1;1105 1175 11BC;B9C1;1105 1175 11BC; # (링; 링; 링; 링; 링; ) HANGUL SYLLABLE RING +B9C2;B9C2;1105 1175 11BD;B9C2;1105 1175 11BD; # (맂; 맂; 맂; 맂; 맂; ) HANGUL SYLLABLE RIJ +B9C3;B9C3;1105 1175 11BE;B9C3;1105 1175 11BE; # (맃; 맃; 맃; 맃; 맃; ) HANGUL SYLLABLE RIC +B9C4;B9C4;1105 1175 11BF;B9C4;1105 1175 11BF; # (맄; 맄; 맄; 맄; 맄; ) HANGUL SYLLABLE RIK +B9C5;B9C5;1105 1175 11C0;B9C5;1105 1175 11C0; # (맅; 맅; 맅; 맅; 맅; ) HANGUL SYLLABLE RIT +B9C6;B9C6;1105 1175 11C1;B9C6;1105 1175 11C1; # (맆; 맆; 맆; 맆; 맆; ) HANGUL SYLLABLE RIP +B9C7;B9C7;1105 1175 11C2;B9C7;1105 1175 11C2; # (맇; 맇; 맇; 맇; 맇; ) HANGUL SYLLABLE RIH +B9C8;B9C8;1106 1161;B9C8;1106 1161; # (마; 마; 마; 마; 마; ) HANGUL SYLLABLE MA +B9C9;B9C9;1106 1161 11A8;B9C9;1106 1161 11A8; # (막; 막; 막; 막; 막; ) HANGUL SYLLABLE MAG +B9CA;B9CA;1106 1161 11A9;B9CA;1106 1161 11A9; # (맊; 맊; 맊; 맊; 맊; ) HANGUL SYLLABLE MAGG +B9CB;B9CB;1106 1161 11AA;B9CB;1106 1161 11AA; # (맋; 맋; 맋; 맋; 맋; ) HANGUL SYLLABLE MAGS +B9CC;B9CC;1106 1161 11AB;B9CC;1106 1161 11AB; # (만; 만; 만; 만; 만; ) HANGUL SYLLABLE MAN +B9CD;B9CD;1106 1161 11AC;B9CD;1106 1161 11AC; # (맍; 맍; 맍; 맍; 맍; ) HANGUL SYLLABLE MANJ +B9CE;B9CE;1106 1161 11AD;B9CE;1106 1161 11AD; # (많; 많; 많; 많; 많; ) HANGUL SYLLABLE MANH +B9CF;B9CF;1106 1161 11AE;B9CF;1106 1161 11AE; # (맏; 맏; 맏; 맏; 맏; ) HANGUL SYLLABLE MAD +B9D0;B9D0;1106 1161 11AF;B9D0;1106 1161 11AF; # (말; 말; 말; 말; 말; ) HANGUL SYLLABLE MAL +B9D1;B9D1;1106 1161 11B0;B9D1;1106 1161 11B0; # (맑; 맑; 맑; 맑; 맑; ) HANGUL SYLLABLE MALG +B9D2;B9D2;1106 1161 11B1;B9D2;1106 1161 11B1; # (맒; 맒; 맒; 맒; 맒; ) HANGUL SYLLABLE MALM +B9D3;B9D3;1106 1161 11B2;B9D3;1106 1161 11B2; # (맓; 맓; 맓; 맓; 맓; ) HANGUL SYLLABLE MALB +B9D4;B9D4;1106 1161 11B3;B9D4;1106 1161 11B3; # (맔; 맔; 맔; 맔; 맔; ) HANGUL SYLLABLE MALS +B9D5;B9D5;1106 1161 11B4;B9D5;1106 1161 11B4; # (맕; 맕; 맕; 맕; 맕; ) HANGUL SYLLABLE MALT +B9D6;B9D6;1106 1161 11B5;B9D6;1106 1161 11B5; # (맖; 맖; 맖; 맖; 맖; ) HANGUL SYLLABLE MALP +B9D7;B9D7;1106 1161 11B6;B9D7;1106 1161 11B6; # (맗; 맗; 맗; 맗; 맗; ) HANGUL SYLLABLE MALH +B9D8;B9D8;1106 1161 11B7;B9D8;1106 1161 11B7; # (맘; 맘; 맘; 맘; 맘; ) HANGUL SYLLABLE MAM +B9D9;B9D9;1106 1161 11B8;B9D9;1106 1161 11B8; # (맙; 맙; 맙; 맙; 맙; ) HANGUL SYLLABLE MAB +B9DA;B9DA;1106 1161 11B9;B9DA;1106 1161 11B9; # (맚; 맚; 맚; 맚; 맚; ) HANGUL SYLLABLE MABS +B9DB;B9DB;1106 1161 11BA;B9DB;1106 1161 11BA; # (맛; 맛; 맛; 맛; 맛; ) HANGUL SYLLABLE MAS +B9DC;B9DC;1106 1161 11BB;B9DC;1106 1161 11BB; # (맜; 맜; 맜; 맜; 맜; ) HANGUL SYLLABLE MASS +B9DD;B9DD;1106 1161 11BC;B9DD;1106 1161 11BC; # (망; 망; 망; 망; 망; ) HANGUL SYLLABLE MANG +B9DE;B9DE;1106 1161 11BD;B9DE;1106 1161 11BD; # (맞; 맞; 맞; 맞; 맞; ) HANGUL SYLLABLE MAJ +B9DF;B9DF;1106 1161 11BE;B9DF;1106 1161 11BE; # (맟; 맟; 맟; 맟; 맟; ) HANGUL SYLLABLE MAC +B9E0;B9E0;1106 1161 11BF;B9E0;1106 1161 11BF; # (맠; 맠; 맠; 맠; 맠; ) HANGUL SYLLABLE MAK +B9E1;B9E1;1106 1161 11C0;B9E1;1106 1161 11C0; # (맡; 맡; 맡; 맡; 맡; ) HANGUL SYLLABLE MAT +B9E2;B9E2;1106 1161 11C1;B9E2;1106 1161 11C1; # (맢; 맢; 맢; 맢; 맢; ) HANGUL SYLLABLE MAP +B9E3;B9E3;1106 1161 11C2;B9E3;1106 1161 11C2; # (맣; 맣; 맣; 맣; 맣; ) HANGUL SYLLABLE MAH +B9E4;B9E4;1106 1162;B9E4;1106 1162; # (매; 매; 매; 매; 매; ) HANGUL SYLLABLE MAE +B9E5;B9E5;1106 1162 11A8;B9E5;1106 1162 11A8; # (맥; 맥; 맥; 맥; 맥; ) HANGUL SYLLABLE MAEG +B9E6;B9E6;1106 1162 11A9;B9E6;1106 1162 11A9; # (맦; 맦; 맦; 맦; 맦; ) HANGUL SYLLABLE MAEGG +B9E7;B9E7;1106 1162 11AA;B9E7;1106 1162 11AA; # (맧; 맧; 맧; 맧; 맧; ) HANGUL SYLLABLE MAEGS +B9E8;B9E8;1106 1162 11AB;B9E8;1106 1162 11AB; # (맨; 맨; 맨; 맨; 맨; ) HANGUL SYLLABLE MAEN +B9E9;B9E9;1106 1162 11AC;B9E9;1106 1162 11AC; # (맩; 맩; 맩; 맩; 맩; ) HANGUL SYLLABLE MAENJ +B9EA;B9EA;1106 1162 11AD;B9EA;1106 1162 11AD; # (맪; 맪; 맪; 맪; 맪; ) HANGUL SYLLABLE MAENH +B9EB;B9EB;1106 1162 11AE;B9EB;1106 1162 11AE; # (맫; 맫; 맫; 맫; 맫; ) HANGUL SYLLABLE MAED +B9EC;B9EC;1106 1162 11AF;B9EC;1106 1162 11AF; # (맬; 맬; 맬; 맬; 맬; ) HANGUL SYLLABLE MAEL +B9ED;B9ED;1106 1162 11B0;B9ED;1106 1162 11B0; # (맭; 맭; 맭; 맭; 맭; ) HANGUL SYLLABLE MAELG +B9EE;B9EE;1106 1162 11B1;B9EE;1106 1162 11B1; # (맮; 맮; 맮; 맮; 맮; ) HANGUL SYLLABLE MAELM +B9EF;B9EF;1106 1162 11B2;B9EF;1106 1162 11B2; # (맯; 맯; 맯; 맯; 맯; ) HANGUL SYLLABLE MAELB +B9F0;B9F0;1106 1162 11B3;B9F0;1106 1162 11B3; # (맰; 맰; 맰; 맰; 맰; ) HANGUL SYLLABLE MAELS +B9F1;B9F1;1106 1162 11B4;B9F1;1106 1162 11B4; # (맱; 맱; 맱; 맱; 맱; ) HANGUL SYLLABLE MAELT +B9F2;B9F2;1106 1162 11B5;B9F2;1106 1162 11B5; # (맲; 맲; 맲; 맲; 맲; ) HANGUL SYLLABLE MAELP +B9F3;B9F3;1106 1162 11B6;B9F3;1106 1162 11B6; # (맳; 맳; 맳; 맳; 맳; ) HANGUL SYLLABLE MAELH +B9F4;B9F4;1106 1162 11B7;B9F4;1106 1162 11B7; # (맴; 맴; 맴; 맴; 맴; ) HANGUL SYLLABLE MAEM +B9F5;B9F5;1106 1162 11B8;B9F5;1106 1162 11B8; # (맵; 맵; 맵; 맵; 맵; ) HANGUL SYLLABLE MAEB +B9F6;B9F6;1106 1162 11B9;B9F6;1106 1162 11B9; # (맶; 맶; 맶; 맶; 맶; ) HANGUL SYLLABLE MAEBS +B9F7;B9F7;1106 1162 11BA;B9F7;1106 1162 11BA; # (맷; 맷; 맷; 맷; 맷; ) HANGUL SYLLABLE MAES +B9F8;B9F8;1106 1162 11BB;B9F8;1106 1162 11BB; # (맸; 맸; 맸; 맸; 맸; ) HANGUL SYLLABLE MAESS +B9F9;B9F9;1106 1162 11BC;B9F9;1106 1162 11BC; # (맹; 맹; 맹; 맹; 맹; ) HANGUL SYLLABLE MAENG +B9FA;B9FA;1106 1162 11BD;B9FA;1106 1162 11BD; # (맺; 맺; 맺; 맺; 맺; ) HANGUL SYLLABLE MAEJ +B9FB;B9FB;1106 1162 11BE;B9FB;1106 1162 11BE; # (맻; 맻; 맻; 맻; 맻; ) HANGUL SYLLABLE MAEC +B9FC;B9FC;1106 1162 11BF;B9FC;1106 1162 11BF; # (맼; 맼; 맼; 맼; 맼; ) HANGUL SYLLABLE MAEK +B9FD;B9FD;1106 1162 11C0;B9FD;1106 1162 11C0; # (맽; 맽; 맽; 맽; 맽; ) HANGUL SYLLABLE MAET +B9FE;B9FE;1106 1162 11C1;B9FE;1106 1162 11C1; # (맾; 맾; 맾; 맾; 맾; ) HANGUL SYLLABLE MAEP +B9FF;B9FF;1106 1162 11C2;B9FF;1106 1162 11C2; # (맿; 맿; 맿; 맿; 맿; ) HANGUL SYLLABLE MAEH +BA00;BA00;1106 1163;BA00;1106 1163; # (먀; 먀; 먀; 먀; 먀; ) HANGUL SYLLABLE MYA +BA01;BA01;1106 1163 11A8;BA01;1106 1163 11A8; # (먁; 먁; 먁; 먁; 먁; ) HANGUL SYLLABLE MYAG +BA02;BA02;1106 1163 11A9;BA02;1106 1163 11A9; # (먂; 먂; 먂; 먂; 먂; ) HANGUL SYLLABLE MYAGG +BA03;BA03;1106 1163 11AA;BA03;1106 1163 11AA; # (먃; 먃; 먃; 먃; 먃; ) HANGUL SYLLABLE MYAGS +BA04;BA04;1106 1163 11AB;BA04;1106 1163 11AB; # (먄; 먄; 먄; 먄; 먄; ) HANGUL SYLLABLE MYAN +BA05;BA05;1106 1163 11AC;BA05;1106 1163 11AC; # (먅; 먅; 먅; 먅; 먅; ) HANGUL SYLLABLE MYANJ +BA06;BA06;1106 1163 11AD;BA06;1106 1163 11AD; # (먆; 먆; 먆; 먆; 먆; ) HANGUL SYLLABLE MYANH +BA07;BA07;1106 1163 11AE;BA07;1106 1163 11AE; # (먇; 먇; 먇; 먇; 먇; ) HANGUL SYLLABLE MYAD +BA08;BA08;1106 1163 11AF;BA08;1106 1163 11AF; # (먈; 먈; 먈; 먈; 먈; ) HANGUL SYLLABLE MYAL +BA09;BA09;1106 1163 11B0;BA09;1106 1163 11B0; # (먉; 먉; 먉; 먉; 먉; ) HANGUL SYLLABLE MYALG +BA0A;BA0A;1106 1163 11B1;BA0A;1106 1163 11B1; # (먊; 먊; 먊; 먊; 먊; ) HANGUL SYLLABLE MYALM +BA0B;BA0B;1106 1163 11B2;BA0B;1106 1163 11B2; # (먋; 먋; 먋; 먋; 먋; ) HANGUL SYLLABLE MYALB +BA0C;BA0C;1106 1163 11B3;BA0C;1106 1163 11B3; # (먌; 먌; 먌; 먌; 먌; ) HANGUL SYLLABLE MYALS +BA0D;BA0D;1106 1163 11B4;BA0D;1106 1163 11B4; # (먍; 먍; 먍; 먍; 먍; ) HANGUL SYLLABLE MYALT +BA0E;BA0E;1106 1163 11B5;BA0E;1106 1163 11B5; # (먎; 먎; 먎; 먎; 먎; ) HANGUL SYLLABLE MYALP +BA0F;BA0F;1106 1163 11B6;BA0F;1106 1163 11B6; # (먏; 먏; 먏; 먏; 먏; ) HANGUL SYLLABLE MYALH +BA10;BA10;1106 1163 11B7;BA10;1106 1163 11B7; # (먐; 먐; 먐; 먐; 먐; ) HANGUL SYLLABLE MYAM +BA11;BA11;1106 1163 11B8;BA11;1106 1163 11B8; # (먑; 먑; 먑; 먑; 먑; ) HANGUL SYLLABLE MYAB +BA12;BA12;1106 1163 11B9;BA12;1106 1163 11B9; # (먒; 먒; 먒; 먒; 먒; ) HANGUL SYLLABLE MYABS +BA13;BA13;1106 1163 11BA;BA13;1106 1163 11BA; # (먓; 먓; 먓; 먓; 먓; ) HANGUL SYLLABLE MYAS +BA14;BA14;1106 1163 11BB;BA14;1106 1163 11BB; # (먔; 먔; 먔; 먔; 먔; ) HANGUL SYLLABLE MYASS +BA15;BA15;1106 1163 11BC;BA15;1106 1163 11BC; # (먕; 먕; 먕; 먕; 먕; ) HANGUL SYLLABLE MYANG +BA16;BA16;1106 1163 11BD;BA16;1106 1163 11BD; # (먖; 먖; 먖; 먖; 먖; ) HANGUL SYLLABLE MYAJ +BA17;BA17;1106 1163 11BE;BA17;1106 1163 11BE; # (먗; 먗; 먗; 먗; 먗; ) HANGUL SYLLABLE MYAC +BA18;BA18;1106 1163 11BF;BA18;1106 1163 11BF; # (먘; 먘; 먘; 먘; 먘; ) HANGUL SYLLABLE MYAK +BA19;BA19;1106 1163 11C0;BA19;1106 1163 11C0; # (먙; 먙; 먙; 먙; 먙; ) HANGUL SYLLABLE MYAT +BA1A;BA1A;1106 1163 11C1;BA1A;1106 1163 11C1; # (먚; 먚; 먚; 먚; 먚; ) HANGUL SYLLABLE MYAP +BA1B;BA1B;1106 1163 11C2;BA1B;1106 1163 11C2; # (먛; 먛; 먛; 먛; 먛; ) HANGUL SYLLABLE MYAH +BA1C;BA1C;1106 1164;BA1C;1106 1164; # (먜; 먜; 먜; 먜; 먜; ) HANGUL SYLLABLE MYAE +BA1D;BA1D;1106 1164 11A8;BA1D;1106 1164 11A8; # (먝; 먝; 먝; 먝; 먝; ) HANGUL SYLLABLE MYAEG +BA1E;BA1E;1106 1164 11A9;BA1E;1106 1164 11A9; # (먞; 먞; 먞; 먞; 먞; ) HANGUL SYLLABLE MYAEGG +BA1F;BA1F;1106 1164 11AA;BA1F;1106 1164 11AA; # (먟; 먟; 먟; 먟; 먟; ) HANGUL SYLLABLE MYAEGS +BA20;BA20;1106 1164 11AB;BA20;1106 1164 11AB; # (먠; 먠; 먠; 먠; 먠; ) HANGUL SYLLABLE MYAEN +BA21;BA21;1106 1164 11AC;BA21;1106 1164 11AC; # (먡; 먡; 먡; 먡; 먡; ) HANGUL SYLLABLE MYAENJ +BA22;BA22;1106 1164 11AD;BA22;1106 1164 11AD; # (먢; 먢; 먢; 먢; 먢; ) HANGUL SYLLABLE MYAENH +BA23;BA23;1106 1164 11AE;BA23;1106 1164 11AE; # (먣; 먣; 먣; 먣; 먣; ) HANGUL SYLLABLE MYAED +BA24;BA24;1106 1164 11AF;BA24;1106 1164 11AF; # (먤; 먤; 먤; 먤; 먤; ) HANGUL SYLLABLE MYAEL +BA25;BA25;1106 1164 11B0;BA25;1106 1164 11B0; # (먥; 먥; 먥; 먥; 먥; ) HANGUL SYLLABLE MYAELG +BA26;BA26;1106 1164 11B1;BA26;1106 1164 11B1; # (먦; 먦; 먦; 먦; 먦; ) HANGUL SYLLABLE MYAELM +BA27;BA27;1106 1164 11B2;BA27;1106 1164 11B2; # (먧; 먧; 먧; 먧; 먧; ) HANGUL SYLLABLE MYAELB +BA28;BA28;1106 1164 11B3;BA28;1106 1164 11B3; # (먨; 먨; 먨; 먨; 먨; ) HANGUL SYLLABLE MYAELS +BA29;BA29;1106 1164 11B4;BA29;1106 1164 11B4; # (먩; 먩; 먩; 먩; 먩; ) HANGUL SYLLABLE MYAELT +BA2A;BA2A;1106 1164 11B5;BA2A;1106 1164 11B5; # (먪; 먪; 먪; 먪; 먪; ) HANGUL SYLLABLE MYAELP +BA2B;BA2B;1106 1164 11B6;BA2B;1106 1164 11B6; # (먫; 먫; 먫; 먫; 먫; ) HANGUL SYLLABLE MYAELH +BA2C;BA2C;1106 1164 11B7;BA2C;1106 1164 11B7; # (먬; 먬; 먬; 먬; 먬; ) HANGUL SYLLABLE MYAEM +BA2D;BA2D;1106 1164 11B8;BA2D;1106 1164 11B8; # (먭; 먭; 먭; 먭; 먭; ) HANGUL SYLLABLE MYAEB +BA2E;BA2E;1106 1164 11B9;BA2E;1106 1164 11B9; # (먮; 먮; 먮; 먮; 먮; ) HANGUL SYLLABLE MYAEBS +BA2F;BA2F;1106 1164 11BA;BA2F;1106 1164 11BA; # (먯; 먯; 먯; 먯; 먯; ) HANGUL SYLLABLE MYAES +BA30;BA30;1106 1164 11BB;BA30;1106 1164 11BB; # (먰; 먰; 먰; 먰; 먰; ) HANGUL SYLLABLE MYAESS +BA31;BA31;1106 1164 11BC;BA31;1106 1164 11BC; # (먱; 먱; 먱; 먱; 먱; ) HANGUL SYLLABLE MYAENG +BA32;BA32;1106 1164 11BD;BA32;1106 1164 11BD; # (먲; 먲; 먲; 먲; 먲; ) HANGUL SYLLABLE MYAEJ +BA33;BA33;1106 1164 11BE;BA33;1106 1164 11BE; # (먳; 먳; 먳; 먳; 먳; ) HANGUL SYLLABLE MYAEC +BA34;BA34;1106 1164 11BF;BA34;1106 1164 11BF; # (먴; 먴; 먴; 먴; 먴; ) HANGUL SYLLABLE MYAEK +BA35;BA35;1106 1164 11C0;BA35;1106 1164 11C0; # (먵; 먵; 먵; 먵; 먵; ) HANGUL SYLLABLE MYAET +BA36;BA36;1106 1164 11C1;BA36;1106 1164 11C1; # (먶; 먶; 먶; 먶; 먶; ) HANGUL SYLLABLE MYAEP +BA37;BA37;1106 1164 11C2;BA37;1106 1164 11C2; # (먷; 먷; 먷; 먷; 먷; ) HANGUL SYLLABLE MYAEH +BA38;BA38;1106 1165;BA38;1106 1165; # (머; 머; 머; 머; 머; ) HANGUL SYLLABLE MEO +BA39;BA39;1106 1165 11A8;BA39;1106 1165 11A8; # (먹; 먹; 먹; 먹; 먹; ) HANGUL SYLLABLE MEOG +BA3A;BA3A;1106 1165 11A9;BA3A;1106 1165 11A9; # (먺; 먺; 먺; 먺; 먺; ) HANGUL SYLLABLE MEOGG +BA3B;BA3B;1106 1165 11AA;BA3B;1106 1165 11AA; # (먻; 먻; 먻; 먻; 먻; ) HANGUL SYLLABLE MEOGS +BA3C;BA3C;1106 1165 11AB;BA3C;1106 1165 11AB; # (먼; 먼; 먼; 먼; 먼; ) HANGUL SYLLABLE MEON +BA3D;BA3D;1106 1165 11AC;BA3D;1106 1165 11AC; # (먽; 먽; 먽; 먽; 먽; ) HANGUL SYLLABLE MEONJ +BA3E;BA3E;1106 1165 11AD;BA3E;1106 1165 11AD; # (먾; 먾; 먾; 먾; 먾; ) HANGUL SYLLABLE MEONH +BA3F;BA3F;1106 1165 11AE;BA3F;1106 1165 11AE; # (먿; 먿; 먿; 먿; 먿; ) HANGUL SYLLABLE MEOD +BA40;BA40;1106 1165 11AF;BA40;1106 1165 11AF; # (멀; 멀; 멀; 멀; 멀; ) HANGUL SYLLABLE MEOL +BA41;BA41;1106 1165 11B0;BA41;1106 1165 11B0; # (멁; 멁; 멁; 멁; 멁; ) HANGUL SYLLABLE MEOLG +BA42;BA42;1106 1165 11B1;BA42;1106 1165 11B1; # (멂; 멂; 멂; 멂; 멂; ) HANGUL SYLLABLE MEOLM +BA43;BA43;1106 1165 11B2;BA43;1106 1165 11B2; # (멃; 멃; 멃; 멃; 멃; ) HANGUL SYLLABLE MEOLB +BA44;BA44;1106 1165 11B3;BA44;1106 1165 11B3; # (멄; 멄; 멄; 멄; 멄; ) HANGUL SYLLABLE MEOLS +BA45;BA45;1106 1165 11B4;BA45;1106 1165 11B4; # (멅; 멅; 멅; 멅; 멅; ) HANGUL SYLLABLE MEOLT +BA46;BA46;1106 1165 11B5;BA46;1106 1165 11B5; # (멆; 멆; 멆; 멆; 멆; ) HANGUL SYLLABLE MEOLP +BA47;BA47;1106 1165 11B6;BA47;1106 1165 11B6; # (멇; 멇; 멇; 멇; 멇; ) HANGUL SYLLABLE MEOLH +BA48;BA48;1106 1165 11B7;BA48;1106 1165 11B7; # (멈; 멈; 멈; 멈; 멈; ) HANGUL SYLLABLE MEOM +BA49;BA49;1106 1165 11B8;BA49;1106 1165 11B8; # (멉; 멉; 멉; 멉; 멉; ) HANGUL SYLLABLE MEOB +BA4A;BA4A;1106 1165 11B9;BA4A;1106 1165 11B9; # (멊; 멊; 멊; 멊; 멊; ) HANGUL SYLLABLE MEOBS +BA4B;BA4B;1106 1165 11BA;BA4B;1106 1165 11BA; # (멋; 멋; 멋; 멋; 멋; ) HANGUL SYLLABLE MEOS +BA4C;BA4C;1106 1165 11BB;BA4C;1106 1165 11BB; # (멌; 멌; 멌; 멌; 멌; ) HANGUL SYLLABLE MEOSS +BA4D;BA4D;1106 1165 11BC;BA4D;1106 1165 11BC; # (멍; 멍; 멍; 멍; 멍; ) HANGUL SYLLABLE MEONG +BA4E;BA4E;1106 1165 11BD;BA4E;1106 1165 11BD; # (멎; 멎; 멎; 멎; 멎; ) HANGUL SYLLABLE MEOJ +BA4F;BA4F;1106 1165 11BE;BA4F;1106 1165 11BE; # (멏; 멏; 멏; 멏; 멏; ) HANGUL SYLLABLE MEOC +BA50;BA50;1106 1165 11BF;BA50;1106 1165 11BF; # (멐; 멐; 멐; 멐; 멐; ) HANGUL SYLLABLE MEOK +BA51;BA51;1106 1165 11C0;BA51;1106 1165 11C0; # (멑; 멑; 멑; 멑; 멑; ) HANGUL SYLLABLE MEOT +BA52;BA52;1106 1165 11C1;BA52;1106 1165 11C1; # (멒; 멒; 멒; 멒; 멒; ) HANGUL SYLLABLE MEOP +BA53;BA53;1106 1165 11C2;BA53;1106 1165 11C2; # (멓; 멓; 멓; 멓; 멓; ) HANGUL SYLLABLE MEOH +BA54;BA54;1106 1166;BA54;1106 1166; # (메; 메; 메; 메; 메; ) HANGUL SYLLABLE ME +BA55;BA55;1106 1166 11A8;BA55;1106 1166 11A8; # (멕; 멕; 멕; 멕; 멕; ) HANGUL SYLLABLE MEG +BA56;BA56;1106 1166 11A9;BA56;1106 1166 11A9; # (멖; 멖; 멖; 멖; 멖; ) HANGUL SYLLABLE MEGG +BA57;BA57;1106 1166 11AA;BA57;1106 1166 11AA; # (멗; 멗; 멗; 멗; 멗; ) HANGUL SYLLABLE MEGS +BA58;BA58;1106 1166 11AB;BA58;1106 1166 11AB; # (멘; 멘; 멘; 멘; 멘; ) HANGUL SYLLABLE MEN +BA59;BA59;1106 1166 11AC;BA59;1106 1166 11AC; # (멙; 멙; 멙; 멙; 멙; ) HANGUL SYLLABLE MENJ +BA5A;BA5A;1106 1166 11AD;BA5A;1106 1166 11AD; # (멚; 멚; 멚; 멚; 멚; ) HANGUL SYLLABLE MENH +BA5B;BA5B;1106 1166 11AE;BA5B;1106 1166 11AE; # (멛; 멛; 멛; 멛; 멛; ) HANGUL SYLLABLE MED +BA5C;BA5C;1106 1166 11AF;BA5C;1106 1166 11AF; # (멜; 멜; 멜; 멜; 멜; ) HANGUL SYLLABLE MEL +BA5D;BA5D;1106 1166 11B0;BA5D;1106 1166 11B0; # (멝; 멝; 멝; 멝; 멝; ) HANGUL SYLLABLE MELG +BA5E;BA5E;1106 1166 11B1;BA5E;1106 1166 11B1; # (멞; 멞; 멞; 멞; 멞; ) HANGUL SYLLABLE MELM +BA5F;BA5F;1106 1166 11B2;BA5F;1106 1166 11B2; # (멟; 멟; 멟; 멟; 멟; ) HANGUL SYLLABLE MELB +BA60;BA60;1106 1166 11B3;BA60;1106 1166 11B3; # (멠; 멠; 멠; 멠; 멠; ) HANGUL SYLLABLE MELS +BA61;BA61;1106 1166 11B4;BA61;1106 1166 11B4; # (멡; 멡; 멡; 멡; 멡; ) HANGUL SYLLABLE MELT +BA62;BA62;1106 1166 11B5;BA62;1106 1166 11B5; # (멢; 멢; 멢; 멢; 멢; ) HANGUL SYLLABLE MELP +BA63;BA63;1106 1166 11B6;BA63;1106 1166 11B6; # (멣; 멣; 멣; 멣; 멣; ) HANGUL SYLLABLE MELH +BA64;BA64;1106 1166 11B7;BA64;1106 1166 11B7; # (멤; 멤; 멤; 멤; 멤; ) HANGUL SYLLABLE MEM +BA65;BA65;1106 1166 11B8;BA65;1106 1166 11B8; # (멥; 멥; 멥; 멥; 멥; ) HANGUL SYLLABLE MEB +BA66;BA66;1106 1166 11B9;BA66;1106 1166 11B9; # (멦; 멦; 멦; 멦; 멦; ) HANGUL SYLLABLE MEBS +BA67;BA67;1106 1166 11BA;BA67;1106 1166 11BA; # (멧; 멧; 멧; 멧; 멧; ) HANGUL SYLLABLE MES +BA68;BA68;1106 1166 11BB;BA68;1106 1166 11BB; # (멨; 멨; 멨; 멨; 멨; ) HANGUL SYLLABLE MESS +BA69;BA69;1106 1166 11BC;BA69;1106 1166 11BC; # (멩; 멩; 멩; 멩; 멩; ) HANGUL SYLLABLE MENG +BA6A;BA6A;1106 1166 11BD;BA6A;1106 1166 11BD; # (멪; 멪; 멪; 멪; 멪; ) HANGUL SYLLABLE MEJ +BA6B;BA6B;1106 1166 11BE;BA6B;1106 1166 11BE; # (멫; 멫; 멫; 멫; 멫; ) HANGUL SYLLABLE MEC +BA6C;BA6C;1106 1166 11BF;BA6C;1106 1166 11BF; # (멬; 멬; 멬; 멬; 멬; ) HANGUL SYLLABLE MEK +BA6D;BA6D;1106 1166 11C0;BA6D;1106 1166 11C0; # (멭; 멭; 멭; 멭; 멭; ) HANGUL SYLLABLE MET +BA6E;BA6E;1106 1166 11C1;BA6E;1106 1166 11C1; # (멮; 멮; 멮; 멮; 멮; ) HANGUL SYLLABLE MEP +BA6F;BA6F;1106 1166 11C2;BA6F;1106 1166 11C2; # (멯; 멯; 멯; 멯; 멯; ) HANGUL SYLLABLE MEH +BA70;BA70;1106 1167;BA70;1106 1167; # (며; 며; 며; 며; 며; ) HANGUL SYLLABLE MYEO +BA71;BA71;1106 1167 11A8;BA71;1106 1167 11A8; # (멱; 멱; 멱; 멱; 멱; ) HANGUL SYLLABLE MYEOG +BA72;BA72;1106 1167 11A9;BA72;1106 1167 11A9; # (멲; 멲; 멲; 멲; 멲; ) HANGUL SYLLABLE MYEOGG +BA73;BA73;1106 1167 11AA;BA73;1106 1167 11AA; # (멳; 멳; 멳; 멳; 멳; ) HANGUL SYLLABLE MYEOGS +BA74;BA74;1106 1167 11AB;BA74;1106 1167 11AB; # (면; 면; 면; 면; 면; ) HANGUL SYLLABLE MYEON +BA75;BA75;1106 1167 11AC;BA75;1106 1167 11AC; # (멵; 멵; 멵; 멵; 멵; ) HANGUL SYLLABLE MYEONJ +BA76;BA76;1106 1167 11AD;BA76;1106 1167 11AD; # (멶; 멶; 멶; 멶; 멶; ) HANGUL SYLLABLE MYEONH +BA77;BA77;1106 1167 11AE;BA77;1106 1167 11AE; # (멷; 멷; 멷; 멷; 멷; ) HANGUL SYLLABLE MYEOD +BA78;BA78;1106 1167 11AF;BA78;1106 1167 11AF; # (멸; 멸; 멸; 멸; 멸; ) HANGUL SYLLABLE MYEOL +BA79;BA79;1106 1167 11B0;BA79;1106 1167 11B0; # (멹; 멹; 멹; 멹; 멹; ) HANGUL SYLLABLE MYEOLG +BA7A;BA7A;1106 1167 11B1;BA7A;1106 1167 11B1; # (멺; 멺; 멺; 멺; 멺; ) HANGUL SYLLABLE MYEOLM +BA7B;BA7B;1106 1167 11B2;BA7B;1106 1167 11B2; # (멻; 멻; 멻; 멻; 멻; ) HANGUL SYLLABLE MYEOLB +BA7C;BA7C;1106 1167 11B3;BA7C;1106 1167 11B3; # (멼; 멼; 멼; 멼; 멼; ) HANGUL SYLLABLE MYEOLS +BA7D;BA7D;1106 1167 11B4;BA7D;1106 1167 11B4; # (멽; 멽; 멽; 멽; 멽; ) HANGUL SYLLABLE MYEOLT +BA7E;BA7E;1106 1167 11B5;BA7E;1106 1167 11B5; # (멾; 멾; 멾; 멾; 멾; ) HANGUL SYLLABLE MYEOLP +BA7F;BA7F;1106 1167 11B6;BA7F;1106 1167 11B6; # (멿; 멿; 멿; 멿; 멿; ) HANGUL SYLLABLE MYEOLH +BA80;BA80;1106 1167 11B7;BA80;1106 1167 11B7; # (몀; 몀; 몀; 몀; 몀; ) HANGUL SYLLABLE MYEOM +BA81;BA81;1106 1167 11B8;BA81;1106 1167 11B8; # (몁; 몁; 몁; 몁; 몁; ) HANGUL SYLLABLE MYEOB +BA82;BA82;1106 1167 11B9;BA82;1106 1167 11B9; # (몂; 몂; 몂; 몂; 몂; ) HANGUL SYLLABLE MYEOBS +BA83;BA83;1106 1167 11BA;BA83;1106 1167 11BA; # (몃; 몃; 몃; 몃; 몃; ) HANGUL SYLLABLE MYEOS +BA84;BA84;1106 1167 11BB;BA84;1106 1167 11BB; # (몄; 몄; 몄; 몄; 몄; ) HANGUL SYLLABLE MYEOSS +BA85;BA85;1106 1167 11BC;BA85;1106 1167 11BC; # (명; 명; 명; 명; 명; ) HANGUL SYLLABLE MYEONG +BA86;BA86;1106 1167 11BD;BA86;1106 1167 11BD; # (몆; 몆; 몆; 몆; 몆; ) HANGUL SYLLABLE MYEOJ +BA87;BA87;1106 1167 11BE;BA87;1106 1167 11BE; # (몇; 몇; 몇; 몇; 몇; ) HANGUL SYLLABLE MYEOC +BA88;BA88;1106 1167 11BF;BA88;1106 1167 11BF; # (몈; 몈; 몈; 몈; 몈; ) HANGUL SYLLABLE MYEOK +BA89;BA89;1106 1167 11C0;BA89;1106 1167 11C0; # (몉; 몉; 몉; 몉; 몉; ) HANGUL SYLLABLE MYEOT +BA8A;BA8A;1106 1167 11C1;BA8A;1106 1167 11C1; # (몊; 몊; 몊; 몊; 몊; ) HANGUL SYLLABLE MYEOP +BA8B;BA8B;1106 1167 11C2;BA8B;1106 1167 11C2; # (몋; 몋; 몋; 몋; 몋; ) HANGUL SYLLABLE MYEOH +BA8C;BA8C;1106 1168;BA8C;1106 1168; # (몌; 몌; 몌; 몌; 몌; ) HANGUL SYLLABLE MYE +BA8D;BA8D;1106 1168 11A8;BA8D;1106 1168 11A8; # (몍; 몍; 몍; 몍; 몍; ) HANGUL SYLLABLE MYEG +BA8E;BA8E;1106 1168 11A9;BA8E;1106 1168 11A9; # (몎; 몎; 몎; 몎; 몎; ) HANGUL SYLLABLE MYEGG +BA8F;BA8F;1106 1168 11AA;BA8F;1106 1168 11AA; # (몏; 몏; 몏; 몏; 몏; ) HANGUL SYLLABLE MYEGS +BA90;BA90;1106 1168 11AB;BA90;1106 1168 11AB; # (몐; 몐; 몐; 몐; 몐; ) HANGUL SYLLABLE MYEN +BA91;BA91;1106 1168 11AC;BA91;1106 1168 11AC; # (몑; 몑; 몑; 몑; 몑; ) HANGUL SYLLABLE MYENJ +BA92;BA92;1106 1168 11AD;BA92;1106 1168 11AD; # (몒; 몒; 몒; 몒; 몒; ) HANGUL SYLLABLE MYENH +BA93;BA93;1106 1168 11AE;BA93;1106 1168 11AE; # (몓; 몓; 몓; 몓; 몓; ) HANGUL SYLLABLE MYED +BA94;BA94;1106 1168 11AF;BA94;1106 1168 11AF; # (몔; 몔; 몔; 몔; 몔; ) HANGUL SYLLABLE MYEL +BA95;BA95;1106 1168 11B0;BA95;1106 1168 11B0; # (몕; 몕; 몕; 몕; 몕; ) HANGUL SYLLABLE MYELG +BA96;BA96;1106 1168 11B1;BA96;1106 1168 11B1; # (몖; 몖; 몖; 몖; 몖; ) HANGUL SYLLABLE MYELM +BA97;BA97;1106 1168 11B2;BA97;1106 1168 11B2; # (몗; 몗; 몗; 몗; 몗; ) HANGUL SYLLABLE MYELB +BA98;BA98;1106 1168 11B3;BA98;1106 1168 11B3; # (몘; 몘; 몘; 몘; 몘; ) HANGUL SYLLABLE MYELS +BA99;BA99;1106 1168 11B4;BA99;1106 1168 11B4; # (몙; 몙; 몙; 몙; 몙; ) HANGUL SYLLABLE MYELT +BA9A;BA9A;1106 1168 11B5;BA9A;1106 1168 11B5; # (몚; 몚; 몚; 몚; 몚; ) HANGUL SYLLABLE MYELP +BA9B;BA9B;1106 1168 11B6;BA9B;1106 1168 11B6; # (몛; 몛; 몛; 몛; 몛; ) HANGUL SYLLABLE MYELH +BA9C;BA9C;1106 1168 11B7;BA9C;1106 1168 11B7; # (몜; 몜; 몜; 몜; 몜; ) HANGUL SYLLABLE MYEM +BA9D;BA9D;1106 1168 11B8;BA9D;1106 1168 11B8; # (몝; 몝; 몝; 몝; 몝; ) HANGUL SYLLABLE MYEB +BA9E;BA9E;1106 1168 11B9;BA9E;1106 1168 11B9; # (몞; 몞; 몞; 몞; 몞; ) HANGUL SYLLABLE MYEBS +BA9F;BA9F;1106 1168 11BA;BA9F;1106 1168 11BA; # (몟; 몟; 몟; 몟; 몟; ) HANGUL SYLLABLE MYES +BAA0;BAA0;1106 1168 11BB;BAA0;1106 1168 11BB; # (몠; 몠; 몠; 몠; 몠; ) HANGUL SYLLABLE MYESS +BAA1;BAA1;1106 1168 11BC;BAA1;1106 1168 11BC; # (몡; 몡; 몡; 몡; 몡; ) HANGUL SYLLABLE MYENG +BAA2;BAA2;1106 1168 11BD;BAA2;1106 1168 11BD; # (몢; 몢; 몢; 몢; 몢; ) HANGUL SYLLABLE MYEJ +BAA3;BAA3;1106 1168 11BE;BAA3;1106 1168 11BE; # (몣; 몣; 몣; 몣; 몣; ) HANGUL SYLLABLE MYEC +BAA4;BAA4;1106 1168 11BF;BAA4;1106 1168 11BF; # (몤; 몤; 몤; 몤; 몤; ) HANGUL SYLLABLE MYEK +BAA5;BAA5;1106 1168 11C0;BAA5;1106 1168 11C0; # (몥; 몥; 몥; 몥; 몥; ) HANGUL SYLLABLE MYET +BAA6;BAA6;1106 1168 11C1;BAA6;1106 1168 11C1; # (몦; 몦; 몦; 몦; 몦; ) HANGUL SYLLABLE MYEP +BAA7;BAA7;1106 1168 11C2;BAA7;1106 1168 11C2; # (몧; 몧; 몧; 몧; 몧; ) HANGUL SYLLABLE MYEH +BAA8;BAA8;1106 1169;BAA8;1106 1169; # (모; 모; 모; 모; 모; ) HANGUL SYLLABLE MO +BAA9;BAA9;1106 1169 11A8;BAA9;1106 1169 11A8; # (목; 목; 목; 목; 목; ) HANGUL SYLLABLE MOG +BAAA;BAAA;1106 1169 11A9;BAAA;1106 1169 11A9; # (몪; 몪; 몪; 몪; 몪; ) HANGUL SYLLABLE MOGG +BAAB;BAAB;1106 1169 11AA;BAAB;1106 1169 11AA; # (몫; 몫; 몫; 몫; 몫; ) HANGUL SYLLABLE MOGS +BAAC;BAAC;1106 1169 11AB;BAAC;1106 1169 11AB; # (몬; 몬; 몬; 몬; 몬; ) HANGUL SYLLABLE MON +BAAD;BAAD;1106 1169 11AC;BAAD;1106 1169 11AC; # (몭; 몭; 몭; 몭; 몭; ) HANGUL SYLLABLE MONJ +BAAE;BAAE;1106 1169 11AD;BAAE;1106 1169 11AD; # (몮; 몮; 몮; 몮; 몮; ) HANGUL SYLLABLE MONH +BAAF;BAAF;1106 1169 11AE;BAAF;1106 1169 11AE; # (몯; 몯; 몯; 몯; 몯; ) HANGUL SYLLABLE MOD +BAB0;BAB0;1106 1169 11AF;BAB0;1106 1169 11AF; # (몰; 몰; 몰; 몰; 몰; ) HANGUL SYLLABLE MOL +BAB1;BAB1;1106 1169 11B0;BAB1;1106 1169 11B0; # (몱; 몱; 몱; 몱; 몱; ) HANGUL SYLLABLE MOLG +BAB2;BAB2;1106 1169 11B1;BAB2;1106 1169 11B1; # (몲; 몲; 몲; 몲; 몲; ) HANGUL SYLLABLE MOLM +BAB3;BAB3;1106 1169 11B2;BAB3;1106 1169 11B2; # (몳; 몳; 몳; 몳; 몳; ) HANGUL SYLLABLE MOLB +BAB4;BAB4;1106 1169 11B3;BAB4;1106 1169 11B3; # (몴; 몴; 몴; 몴; 몴; ) HANGUL SYLLABLE MOLS +BAB5;BAB5;1106 1169 11B4;BAB5;1106 1169 11B4; # (몵; 몵; 몵; 몵; 몵; ) HANGUL SYLLABLE MOLT +BAB6;BAB6;1106 1169 11B5;BAB6;1106 1169 11B5; # (몶; 몶; 몶; 몶; 몶; ) HANGUL SYLLABLE MOLP +BAB7;BAB7;1106 1169 11B6;BAB7;1106 1169 11B6; # (몷; 몷; 몷; 몷; 몷; ) HANGUL SYLLABLE MOLH +BAB8;BAB8;1106 1169 11B7;BAB8;1106 1169 11B7; # (몸; 몸; 몸; 몸; 몸; ) HANGUL SYLLABLE MOM +BAB9;BAB9;1106 1169 11B8;BAB9;1106 1169 11B8; # (몹; 몹; 몹; 몹; 몹; ) HANGUL SYLLABLE MOB +BABA;BABA;1106 1169 11B9;BABA;1106 1169 11B9; # (몺; 몺; 몺; 몺; 몺; ) HANGUL SYLLABLE MOBS +BABB;BABB;1106 1169 11BA;BABB;1106 1169 11BA; # (못; 못; 못; 못; 못; ) HANGUL SYLLABLE MOS +BABC;BABC;1106 1169 11BB;BABC;1106 1169 11BB; # (몼; 몼; 몼; 몼; 몼; ) HANGUL SYLLABLE MOSS +BABD;BABD;1106 1169 11BC;BABD;1106 1169 11BC; # (몽; 몽; 몽; 몽; 몽; ) HANGUL SYLLABLE MONG +BABE;BABE;1106 1169 11BD;BABE;1106 1169 11BD; # (몾; 몾; 몾; 몾; 몾; ) HANGUL SYLLABLE MOJ +BABF;BABF;1106 1169 11BE;BABF;1106 1169 11BE; # (몿; 몿; 몿; 몿; 몿; ) HANGUL SYLLABLE MOC +BAC0;BAC0;1106 1169 11BF;BAC0;1106 1169 11BF; # (뫀; 뫀; 뫀; 뫀; 뫀; ) HANGUL SYLLABLE MOK +BAC1;BAC1;1106 1169 11C0;BAC1;1106 1169 11C0; # (뫁; 뫁; 뫁; 뫁; 뫁; ) HANGUL SYLLABLE MOT +BAC2;BAC2;1106 1169 11C1;BAC2;1106 1169 11C1; # (뫂; 뫂; 뫂; 뫂; 뫂; ) HANGUL SYLLABLE MOP +BAC3;BAC3;1106 1169 11C2;BAC3;1106 1169 11C2; # (뫃; 뫃; 뫃; 뫃; 뫃; ) HANGUL SYLLABLE MOH +BAC4;BAC4;1106 116A;BAC4;1106 116A; # (뫄; 뫄; 뫄; 뫄; 뫄; ) HANGUL SYLLABLE MWA +BAC5;BAC5;1106 116A 11A8;BAC5;1106 116A 11A8; # (뫅; 뫅; 뫅; 뫅; 뫅; ) HANGUL SYLLABLE MWAG +BAC6;BAC6;1106 116A 11A9;BAC6;1106 116A 11A9; # (뫆; 뫆; 뫆; 뫆; 뫆; ) HANGUL SYLLABLE MWAGG +BAC7;BAC7;1106 116A 11AA;BAC7;1106 116A 11AA; # (뫇; 뫇; 뫇; 뫇; 뫇; ) HANGUL SYLLABLE MWAGS +BAC8;BAC8;1106 116A 11AB;BAC8;1106 116A 11AB; # (뫈; 뫈; 뫈; 뫈; 뫈; ) HANGUL SYLLABLE MWAN +BAC9;BAC9;1106 116A 11AC;BAC9;1106 116A 11AC; # (뫉; 뫉; 뫉; 뫉; 뫉; ) HANGUL SYLLABLE MWANJ +BACA;BACA;1106 116A 11AD;BACA;1106 116A 11AD; # (뫊; 뫊; 뫊; 뫊; 뫊; ) HANGUL SYLLABLE MWANH +BACB;BACB;1106 116A 11AE;BACB;1106 116A 11AE; # (뫋; 뫋; 뫋; 뫋; 뫋; ) HANGUL SYLLABLE MWAD +BACC;BACC;1106 116A 11AF;BACC;1106 116A 11AF; # (뫌; 뫌; 뫌; 뫌; 뫌; ) HANGUL SYLLABLE MWAL +BACD;BACD;1106 116A 11B0;BACD;1106 116A 11B0; # (뫍; 뫍; 뫍; 뫍; 뫍; ) HANGUL SYLLABLE MWALG +BACE;BACE;1106 116A 11B1;BACE;1106 116A 11B1; # (뫎; 뫎; 뫎; 뫎; 뫎; ) HANGUL SYLLABLE MWALM +BACF;BACF;1106 116A 11B2;BACF;1106 116A 11B2; # (뫏; 뫏; 뫏; 뫏; 뫏; ) HANGUL SYLLABLE MWALB +BAD0;BAD0;1106 116A 11B3;BAD0;1106 116A 11B3; # (뫐; 뫐; 뫐; 뫐; 뫐; ) HANGUL SYLLABLE MWALS +BAD1;BAD1;1106 116A 11B4;BAD1;1106 116A 11B4; # (뫑; 뫑; 뫑; 뫑; 뫑; ) HANGUL SYLLABLE MWALT +BAD2;BAD2;1106 116A 11B5;BAD2;1106 116A 11B5; # (뫒; 뫒; 뫒; 뫒; 뫒; ) HANGUL SYLLABLE MWALP +BAD3;BAD3;1106 116A 11B6;BAD3;1106 116A 11B6; # (뫓; 뫓; 뫓; 뫓; 뫓; ) HANGUL SYLLABLE MWALH +BAD4;BAD4;1106 116A 11B7;BAD4;1106 116A 11B7; # (뫔; 뫔; 뫔; 뫔; 뫔; ) HANGUL SYLLABLE MWAM +BAD5;BAD5;1106 116A 11B8;BAD5;1106 116A 11B8; # (뫕; 뫕; 뫕; 뫕; 뫕; ) HANGUL SYLLABLE MWAB +BAD6;BAD6;1106 116A 11B9;BAD6;1106 116A 11B9; # (뫖; 뫖; 뫖; 뫖; 뫖; ) HANGUL SYLLABLE MWABS +BAD7;BAD7;1106 116A 11BA;BAD7;1106 116A 11BA; # (뫗; 뫗; 뫗; 뫗; 뫗; ) HANGUL SYLLABLE MWAS +BAD8;BAD8;1106 116A 11BB;BAD8;1106 116A 11BB; # (뫘; 뫘; 뫘; 뫘; 뫘; ) HANGUL SYLLABLE MWASS +BAD9;BAD9;1106 116A 11BC;BAD9;1106 116A 11BC; # (뫙; 뫙; 뫙; 뫙; 뫙; ) HANGUL SYLLABLE MWANG +BADA;BADA;1106 116A 11BD;BADA;1106 116A 11BD; # (뫚; 뫚; 뫚; 뫚; 뫚; ) HANGUL SYLLABLE MWAJ +BADB;BADB;1106 116A 11BE;BADB;1106 116A 11BE; # (뫛; 뫛; 뫛; 뫛; 뫛; ) HANGUL SYLLABLE MWAC +BADC;BADC;1106 116A 11BF;BADC;1106 116A 11BF; # (뫜; 뫜; 뫜; 뫜; 뫜; ) HANGUL SYLLABLE MWAK +BADD;BADD;1106 116A 11C0;BADD;1106 116A 11C0; # (뫝; 뫝; 뫝; 뫝; 뫝; ) HANGUL SYLLABLE MWAT +BADE;BADE;1106 116A 11C1;BADE;1106 116A 11C1; # (뫞; 뫞; 뫞; 뫞; 뫞; ) HANGUL SYLLABLE MWAP +BADF;BADF;1106 116A 11C2;BADF;1106 116A 11C2; # (뫟; 뫟; 뫟; 뫟; 뫟; ) HANGUL SYLLABLE MWAH +BAE0;BAE0;1106 116B;BAE0;1106 116B; # (뫠; 뫠; 뫠; 뫠; 뫠; ) HANGUL SYLLABLE MWAE +BAE1;BAE1;1106 116B 11A8;BAE1;1106 116B 11A8; # (뫡; 뫡; 뫡; 뫡; 뫡; ) HANGUL SYLLABLE MWAEG +BAE2;BAE2;1106 116B 11A9;BAE2;1106 116B 11A9; # (뫢; 뫢; 뫢; 뫢; 뫢; ) HANGUL SYLLABLE MWAEGG +BAE3;BAE3;1106 116B 11AA;BAE3;1106 116B 11AA; # (뫣; 뫣; 뫣; 뫣; 뫣; ) HANGUL SYLLABLE MWAEGS +BAE4;BAE4;1106 116B 11AB;BAE4;1106 116B 11AB; # (뫤; 뫤; 뫤; 뫤; 뫤; ) HANGUL SYLLABLE MWAEN +BAE5;BAE5;1106 116B 11AC;BAE5;1106 116B 11AC; # (뫥; 뫥; 뫥; 뫥; 뫥; ) HANGUL SYLLABLE MWAENJ +BAE6;BAE6;1106 116B 11AD;BAE6;1106 116B 11AD; # (뫦; 뫦; 뫦; 뫦; 뫦; ) HANGUL SYLLABLE MWAENH +BAE7;BAE7;1106 116B 11AE;BAE7;1106 116B 11AE; # (뫧; 뫧; 뫧; 뫧; 뫧; ) HANGUL SYLLABLE MWAED +BAE8;BAE8;1106 116B 11AF;BAE8;1106 116B 11AF; # (뫨; 뫨; 뫨; 뫨; 뫨; ) HANGUL SYLLABLE MWAEL +BAE9;BAE9;1106 116B 11B0;BAE9;1106 116B 11B0; # (뫩; 뫩; 뫩; 뫩; 뫩; ) HANGUL SYLLABLE MWAELG +BAEA;BAEA;1106 116B 11B1;BAEA;1106 116B 11B1; # (뫪; 뫪; 뫪; 뫪; 뫪; ) HANGUL SYLLABLE MWAELM +BAEB;BAEB;1106 116B 11B2;BAEB;1106 116B 11B2; # (뫫; 뫫; 뫫; 뫫; 뫫; ) HANGUL SYLLABLE MWAELB +BAEC;BAEC;1106 116B 11B3;BAEC;1106 116B 11B3; # (뫬; 뫬; 뫬; 뫬; 뫬; ) HANGUL SYLLABLE MWAELS +BAED;BAED;1106 116B 11B4;BAED;1106 116B 11B4; # (뫭; 뫭; 뫭; 뫭; 뫭; ) HANGUL SYLLABLE MWAELT +BAEE;BAEE;1106 116B 11B5;BAEE;1106 116B 11B5; # (뫮; 뫮; 뫮; 뫮; 뫮; ) HANGUL SYLLABLE MWAELP +BAEF;BAEF;1106 116B 11B6;BAEF;1106 116B 11B6; # (뫯; 뫯; 뫯; 뫯; 뫯; ) HANGUL SYLLABLE MWAELH +BAF0;BAF0;1106 116B 11B7;BAF0;1106 116B 11B7; # (뫰; 뫰; 뫰; 뫰; 뫰; ) HANGUL SYLLABLE MWAEM +BAF1;BAF1;1106 116B 11B8;BAF1;1106 116B 11B8; # (뫱; 뫱; 뫱; 뫱; 뫱; ) HANGUL SYLLABLE MWAEB +BAF2;BAF2;1106 116B 11B9;BAF2;1106 116B 11B9; # (뫲; 뫲; 뫲; 뫲; 뫲; ) HANGUL SYLLABLE MWAEBS +BAF3;BAF3;1106 116B 11BA;BAF3;1106 116B 11BA; # (뫳; 뫳; 뫳; 뫳; 뫳; ) HANGUL SYLLABLE MWAES +BAF4;BAF4;1106 116B 11BB;BAF4;1106 116B 11BB; # (뫴; 뫴; 뫴; 뫴; 뫴; ) HANGUL SYLLABLE MWAESS +BAF5;BAF5;1106 116B 11BC;BAF5;1106 116B 11BC; # (뫵; 뫵; 뫵; 뫵; 뫵; ) HANGUL SYLLABLE MWAENG +BAF6;BAF6;1106 116B 11BD;BAF6;1106 116B 11BD; # (뫶; 뫶; 뫶; 뫶; 뫶; ) HANGUL SYLLABLE MWAEJ +BAF7;BAF7;1106 116B 11BE;BAF7;1106 116B 11BE; # (뫷; 뫷; 뫷; 뫷; 뫷; ) HANGUL SYLLABLE MWAEC +BAF8;BAF8;1106 116B 11BF;BAF8;1106 116B 11BF; # (뫸; 뫸; 뫸; 뫸; 뫸; ) HANGUL SYLLABLE MWAEK +BAF9;BAF9;1106 116B 11C0;BAF9;1106 116B 11C0; # (뫹; 뫹; 뫹; 뫹; 뫹; ) HANGUL SYLLABLE MWAET +BAFA;BAFA;1106 116B 11C1;BAFA;1106 116B 11C1; # (뫺; 뫺; 뫺; 뫺; 뫺; ) HANGUL SYLLABLE MWAEP +BAFB;BAFB;1106 116B 11C2;BAFB;1106 116B 11C2; # (뫻; 뫻; 뫻; 뫻; 뫻; ) HANGUL SYLLABLE MWAEH +BAFC;BAFC;1106 116C;BAFC;1106 116C; # (뫼; 뫼; 뫼; 뫼; 뫼; ) HANGUL SYLLABLE MOE +BAFD;BAFD;1106 116C 11A8;BAFD;1106 116C 11A8; # (뫽; 뫽; 뫽; 뫽; 뫽; ) HANGUL SYLLABLE MOEG +BAFE;BAFE;1106 116C 11A9;BAFE;1106 116C 11A9; # (뫾; 뫾; 뫾; 뫾; 뫾; ) HANGUL SYLLABLE MOEGG +BAFF;BAFF;1106 116C 11AA;BAFF;1106 116C 11AA; # (뫿; 뫿; 뫿; 뫿; 뫿; ) HANGUL SYLLABLE MOEGS +BB00;BB00;1106 116C 11AB;BB00;1106 116C 11AB; # (묀; 묀; 묀; 묀; 묀; ) HANGUL SYLLABLE MOEN +BB01;BB01;1106 116C 11AC;BB01;1106 116C 11AC; # (묁; 묁; 묁; 묁; 묁; ) HANGUL SYLLABLE MOENJ +BB02;BB02;1106 116C 11AD;BB02;1106 116C 11AD; # (묂; 묂; 묂; 묂; 묂; ) HANGUL SYLLABLE MOENH +BB03;BB03;1106 116C 11AE;BB03;1106 116C 11AE; # (묃; 묃; 묃; 묃; 묃; ) HANGUL SYLLABLE MOED +BB04;BB04;1106 116C 11AF;BB04;1106 116C 11AF; # (묄; 묄; 묄; 묄; 묄; ) HANGUL SYLLABLE MOEL +BB05;BB05;1106 116C 11B0;BB05;1106 116C 11B0; # (묅; 묅; 묅; 묅; 묅; ) HANGUL SYLLABLE MOELG +BB06;BB06;1106 116C 11B1;BB06;1106 116C 11B1; # (묆; 묆; 묆; 묆; 묆; ) HANGUL SYLLABLE MOELM +BB07;BB07;1106 116C 11B2;BB07;1106 116C 11B2; # (묇; 묇; 묇; 묇; 묇; ) HANGUL SYLLABLE MOELB +BB08;BB08;1106 116C 11B3;BB08;1106 116C 11B3; # (묈; 묈; 묈; 묈; 묈; ) HANGUL SYLLABLE MOELS +BB09;BB09;1106 116C 11B4;BB09;1106 116C 11B4; # (묉; 묉; 묉; 묉; 묉; ) HANGUL SYLLABLE MOELT +BB0A;BB0A;1106 116C 11B5;BB0A;1106 116C 11B5; # (묊; 묊; 묊; 묊; 묊; ) HANGUL SYLLABLE MOELP +BB0B;BB0B;1106 116C 11B6;BB0B;1106 116C 11B6; # (묋; 묋; 묋; 묋; 묋; ) HANGUL SYLLABLE MOELH +BB0C;BB0C;1106 116C 11B7;BB0C;1106 116C 11B7; # (묌; 묌; 묌; 묌; 묌; ) HANGUL SYLLABLE MOEM +BB0D;BB0D;1106 116C 11B8;BB0D;1106 116C 11B8; # (묍; 묍; 묍; 묍; 묍; ) HANGUL SYLLABLE MOEB +BB0E;BB0E;1106 116C 11B9;BB0E;1106 116C 11B9; # (묎; 묎; 묎; 묎; 묎; ) HANGUL SYLLABLE MOEBS +BB0F;BB0F;1106 116C 11BA;BB0F;1106 116C 11BA; # (묏; 묏; 묏; 묏; 묏; ) HANGUL SYLLABLE MOES +BB10;BB10;1106 116C 11BB;BB10;1106 116C 11BB; # (묐; 묐; 묐; 묐; 묐; ) HANGUL SYLLABLE MOESS +BB11;BB11;1106 116C 11BC;BB11;1106 116C 11BC; # (묑; 묑; 묑; 묑; 묑; ) HANGUL SYLLABLE MOENG +BB12;BB12;1106 116C 11BD;BB12;1106 116C 11BD; # (묒; 묒; 묒; 묒; 묒; ) HANGUL SYLLABLE MOEJ +BB13;BB13;1106 116C 11BE;BB13;1106 116C 11BE; # (묓; 묓; 묓; 묓; 묓; ) HANGUL SYLLABLE MOEC +BB14;BB14;1106 116C 11BF;BB14;1106 116C 11BF; # (묔; 묔; 묔; 묔; 묔; ) HANGUL SYLLABLE MOEK +BB15;BB15;1106 116C 11C0;BB15;1106 116C 11C0; # (묕; 묕; 묕; 묕; 묕; ) HANGUL SYLLABLE MOET +BB16;BB16;1106 116C 11C1;BB16;1106 116C 11C1; # (묖; 묖; 묖; 묖; 묖; ) HANGUL SYLLABLE MOEP +BB17;BB17;1106 116C 11C2;BB17;1106 116C 11C2; # (묗; 묗; 묗; 묗; 묗; ) HANGUL SYLLABLE MOEH +BB18;BB18;1106 116D;BB18;1106 116D; # (묘; 묘; 묘; 묘; 묘; ) HANGUL SYLLABLE MYO +BB19;BB19;1106 116D 11A8;BB19;1106 116D 11A8; # (묙; 묙; 묙; 묙; 묙; ) HANGUL SYLLABLE MYOG +BB1A;BB1A;1106 116D 11A9;BB1A;1106 116D 11A9; # (묚; 묚; 묚; 묚; 묚; ) HANGUL SYLLABLE MYOGG +BB1B;BB1B;1106 116D 11AA;BB1B;1106 116D 11AA; # (묛; 묛; 묛; 묛; 묛; ) HANGUL SYLLABLE MYOGS +BB1C;BB1C;1106 116D 11AB;BB1C;1106 116D 11AB; # (묜; 묜; 묜; 묜; 묜; ) HANGUL SYLLABLE MYON +BB1D;BB1D;1106 116D 11AC;BB1D;1106 116D 11AC; # (묝; 묝; 묝; 묝; 묝; ) HANGUL SYLLABLE MYONJ +BB1E;BB1E;1106 116D 11AD;BB1E;1106 116D 11AD; # (묞; 묞; 묞; 묞; 묞; ) HANGUL SYLLABLE MYONH +BB1F;BB1F;1106 116D 11AE;BB1F;1106 116D 11AE; # (묟; 묟; 묟; 묟; 묟; ) HANGUL SYLLABLE MYOD +BB20;BB20;1106 116D 11AF;BB20;1106 116D 11AF; # (묠; 묠; 묠; 묠; 묠; ) HANGUL SYLLABLE MYOL +BB21;BB21;1106 116D 11B0;BB21;1106 116D 11B0; # (묡; 묡; 묡; 묡; 묡; ) HANGUL SYLLABLE MYOLG +BB22;BB22;1106 116D 11B1;BB22;1106 116D 11B1; # (묢; 묢; 묢; 묢; 묢; ) HANGUL SYLLABLE MYOLM +BB23;BB23;1106 116D 11B2;BB23;1106 116D 11B2; # (묣; 묣; 묣; 묣; 묣; ) HANGUL SYLLABLE MYOLB +BB24;BB24;1106 116D 11B3;BB24;1106 116D 11B3; # (묤; 묤; 묤; 묤; 묤; ) HANGUL SYLLABLE MYOLS +BB25;BB25;1106 116D 11B4;BB25;1106 116D 11B4; # (묥; 묥; 묥; 묥; 묥; ) HANGUL SYLLABLE MYOLT +BB26;BB26;1106 116D 11B5;BB26;1106 116D 11B5; # (묦; 묦; 묦; 묦; 묦; ) HANGUL SYLLABLE MYOLP +BB27;BB27;1106 116D 11B6;BB27;1106 116D 11B6; # (묧; 묧; 묧; 묧; 묧; ) HANGUL SYLLABLE MYOLH +BB28;BB28;1106 116D 11B7;BB28;1106 116D 11B7; # (묨; 묨; 묨; 묨; 묨; ) HANGUL SYLLABLE MYOM +BB29;BB29;1106 116D 11B8;BB29;1106 116D 11B8; # (묩; 묩; 묩; 묩; 묩; ) HANGUL SYLLABLE MYOB +BB2A;BB2A;1106 116D 11B9;BB2A;1106 116D 11B9; # (묪; 묪; 묪; 묪; 묪; ) HANGUL SYLLABLE MYOBS +BB2B;BB2B;1106 116D 11BA;BB2B;1106 116D 11BA; # (묫; 묫; 묫; 묫; 묫; ) HANGUL SYLLABLE MYOS +BB2C;BB2C;1106 116D 11BB;BB2C;1106 116D 11BB; # (묬; 묬; 묬; 묬; 묬; ) HANGUL SYLLABLE MYOSS +BB2D;BB2D;1106 116D 11BC;BB2D;1106 116D 11BC; # (묭; 묭; 묭; 묭; 묭; ) HANGUL SYLLABLE MYONG +BB2E;BB2E;1106 116D 11BD;BB2E;1106 116D 11BD; # (묮; 묮; 묮; 묮; 묮; ) HANGUL SYLLABLE MYOJ +BB2F;BB2F;1106 116D 11BE;BB2F;1106 116D 11BE; # (묯; 묯; 묯; 묯; 묯; ) HANGUL SYLLABLE MYOC +BB30;BB30;1106 116D 11BF;BB30;1106 116D 11BF; # (묰; 묰; 묰; 묰; 묰; ) HANGUL SYLLABLE MYOK +BB31;BB31;1106 116D 11C0;BB31;1106 116D 11C0; # (묱; 묱; 묱; 묱; 묱; ) HANGUL SYLLABLE MYOT +BB32;BB32;1106 116D 11C1;BB32;1106 116D 11C1; # (묲; 묲; 묲; 묲; 묲; ) HANGUL SYLLABLE MYOP +BB33;BB33;1106 116D 11C2;BB33;1106 116D 11C2; # (묳; 묳; 묳; 묳; 묳; ) HANGUL SYLLABLE MYOH +BB34;BB34;1106 116E;BB34;1106 116E; # (무; 무; 무; 무; 무; ) HANGUL SYLLABLE MU +BB35;BB35;1106 116E 11A8;BB35;1106 116E 11A8; # (묵; 묵; 묵; 묵; 묵; ) HANGUL SYLLABLE MUG +BB36;BB36;1106 116E 11A9;BB36;1106 116E 11A9; # (묶; 묶; 묶; 묶; 묶; ) HANGUL SYLLABLE MUGG +BB37;BB37;1106 116E 11AA;BB37;1106 116E 11AA; # (묷; 묷; 묷; 묷; 묷; ) HANGUL SYLLABLE MUGS +BB38;BB38;1106 116E 11AB;BB38;1106 116E 11AB; # (문; 문; 문; 문; 문; ) HANGUL SYLLABLE MUN +BB39;BB39;1106 116E 11AC;BB39;1106 116E 11AC; # (묹; 묹; 묹; 묹; 묹; ) HANGUL SYLLABLE MUNJ +BB3A;BB3A;1106 116E 11AD;BB3A;1106 116E 11AD; # (묺; 묺; 묺; 묺; 묺; ) HANGUL SYLLABLE MUNH +BB3B;BB3B;1106 116E 11AE;BB3B;1106 116E 11AE; # (묻; 묻; 묻; 묻; 묻; ) HANGUL SYLLABLE MUD +BB3C;BB3C;1106 116E 11AF;BB3C;1106 116E 11AF; # (물; 물; 물; 물; 물; ) HANGUL SYLLABLE MUL +BB3D;BB3D;1106 116E 11B0;BB3D;1106 116E 11B0; # (묽; 묽; 묽; 묽; 묽; ) HANGUL SYLLABLE MULG +BB3E;BB3E;1106 116E 11B1;BB3E;1106 116E 11B1; # (묾; 묾; 묾; 묾; 묾; ) HANGUL SYLLABLE MULM +BB3F;BB3F;1106 116E 11B2;BB3F;1106 116E 11B2; # (묿; 묿; 묿; 묿; 묿; ) HANGUL SYLLABLE MULB +BB40;BB40;1106 116E 11B3;BB40;1106 116E 11B3; # (뭀; 뭀; 뭀; 뭀; 뭀; ) HANGUL SYLLABLE MULS +BB41;BB41;1106 116E 11B4;BB41;1106 116E 11B4; # (뭁; 뭁; 뭁; 뭁; 뭁; ) HANGUL SYLLABLE MULT +BB42;BB42;1106 116E 11B5;BB42;1106 116E 11B5; # (뭂; 뭂; 뭂; 뭂; 뭂; ) HANGUL SYLLABLE MULP +BB43;BB43;1106 116E 11B6;BB43;1106 116E 11B6; # (뭃; 뭃; 뭃; 뭃; 뭃; ) HANGUL SYLLABLE MULH +BB44;BB44;1106 116E 11B7;BB44;1106 116E 11B7; # (뭄; 뭄; 뭄; 뭄; 뭄; ) HANGUL SYLLABLE MUM +BB45;BB45;1106 116E 11B8;BB45;1106 116E 11B8; # (뭅; 뭅; 뭅; 뭅; 뭅; ) HANGUL SYLLABLE MUB +BB46;BB46;1106 116E 11B9;BB46;1106 116E 11B9; # (뭆; 뭆; 뭆; 뭆; 뭆; ) HANGUL SYLLABLE MUBS +BB47;BB47;1106 116E 11BA;BB47;1106 116E 11BA; # (뭇; 뭇; 뭇; 뭇; 뭇; ) HANGUL SYLLABLE MUS +BB48;BB48;1106 116E 11BB;BB48;1106 116E 11BB; # (뭈; 뭈; 뭈; 뭈; 뭈; ) HANGUL SYLLABLE MUSS +BB49;BB49;1106 116E 11BC;BB49;1106 116E 11BC; # (뭉; 뭉; 뭉; 뭉; 뭉; ) HANGUL SYLLABLE MUNG +BB4A;BB4A;1106 116E 11BD;BB4A;1106 116E 11BD; # (뭊; 뭊; 뭊; 뭊; 뭊; ) HANGUL SYLLABLE MUJ +BB4B;BB4B;1106 116E 11BE;BB4B;1106 116E 11BE; # (뭋; 뭋; 뭋; 뭋; 뭋; ) HANGUL SYLLABLE MUC +BB4C;BB4C;1106 116E 11BF;BB4C;1106 116E 11BF; # (뭌; 뭌; 뭌; 뭌; 뭌; ) HANGUL SYLLABLE MUK +BB4D;BB4D;1106 116E 11C0;BB4D;1106 116E 11C0; # (뭍; 뭍; 뭍; 뭍; 뭍; ) HANGUL SYLLABLE MUT +BB4E;BB4E;1106 116E 11C1;BB4E;1106 116E 11C1; # (뭎; 뭎; 뭎; 뭎; 뭎; ) HANGUL SYLLABLE MUP +BB4F;BB4F;1106 116E 11C2;BB4F;1106 116E 11C2; # (뭏; 뭏; 뭏; 뭏; 뭏; ) HANGUL SYLLABLE MUH +BB50;BB50;1106 116F;BB50;1106 116F; # (뭐; 뭐; 뭐; 뭐; 뭐; ) HANGUL SYLLABLE MWEO +BB51;BB51;1106 116F 11A8;BB51;1106 116F 11A8; # (뭑; 뭑; 뭑; 뭑; 뭑; ) HANGUL SYLLABLE MWEOG +BB52;BB52;1106 116F 11A9;BB52;1106 116F 11A9; # (뭒; 뭒; 뭒; 뭒; 뭒; ) HANGUL SYLLABLE MWEOGG +BB53;BB53;1106 116F 11AA;BB53;1106 116F 11AA; # (뭓; 뭓; 뭓; 뭓; 뭓; ) HANGUL SYLLABLE MWEOGS +BB54;BB54;1106 116F 11AB;BB54;1106 116F 11AB; # (뭔; 뭔; 뭔; 뭔; 뭔; ) HANGUL SYLLABLE MWEON +BB55;BB55;1106 116F 11AC;BB55;1106 116F 11AC; # (뭕; 뭕; 뭕; 뭕; 뭕; ) HANGUL SYLLABLE MWEONJ +BB56;BB56;1106 116F 11AD;BB56;1106 116F 11AD; # (뭖; 뭖; 뭖; 뭖; 뭖; ) HANGUL SYLLABLE MWEONH +BB57;BB57;1106 116F 11AE;BB57;1106 116F 11AE; # (뭗; 뭗; 뭗; 뭗; 뭗; ) HANGUL SYLLABLE MWEOD +BB58;BB58;1106 116F 11AF;BB58;1106 116F 11AF; # (뭘; 뭘; 뭘; 뭘; 뭘; ) HANGUL SYLLABLE MWEOL +BB59;BB59;1106 116F 11B0;BB59;1106 116F 11B0; # (뭙; 뭙; 뭙; 뭙; 뭙; ) HANGUL SYLLABLE MWEOLG +BB5A;BB5A;1106 116F 11B1;BB5A;1106 116F 11B1; # (뭚; 뭚; 뭚; 뭚; 뭚; ) HANGUL SYLLABLE MWEOLM +BB5B;BB5B;1106 116F 11B2;BB5B;1106 116F 11B2; # (뭛; 뭛; 뭛; 뭛; 뭛; ) HANGUL SYLLABLE MWEOLB +BB5C;BB5C;1106 116F 11B3;BB5C;1106 116F 11B3; # (뭜; 뭜; 뭜; 뭜; 뭜; ) HANGUL SYLLABLE MWEOLS +BB5D;BB5D;1106 116F 11B4;BB5D;1106 116F 11B4; # (뭝; 뭝; 뭝; 뭝; 뭝; ) HANGUL SYLLABLE MWEOLT +BB5E;BB5E;1106 116F 11B5;BB5E;1106 116F 11B5; # (뭞; 뭞; 뭞; 뭞; 뭞; ) HANGUL SYLLABLE MWEOLP +BB5F;BB5F;1106 116F 11B6;BB5F;1106 116F 11B6; # (뭟; 뭟; 뭟; 뭟; 뭟; ) HANGUL SYLLABLE MWEOLH +BB60;BB60;1106 116F 11B7;BB60;1106 116F 11B7; # (뭠; 뭠; 뭠; 뭠; 뭠; ) HANGUL SYLLABLE MWEOM +BB61;BB61;1106 116F 11B8;BB61;1106 116F 11B8; # (뭡; 뭡; 뭡; 뭡; 뭡; ) HANGUL SYLLABLE MWEOB +BB62;BB62;1106 116F 11B9;BB62;1106 116F 11B9; # (뭢; 뭢; 뭢; 뭢; 뭢; ) HANGUL SYLLABLE MWEOBS +BB63;BB63;1106 116F 11BA;BB63;1106 116F 11BA; # (뭣; 뭣; 뭣; 뭣; 뭣; ) HANGUL SYLLABLE MWEOS +BB64;BB64;1106 116F 11BB;BB64;1106 116F 11BB; # (뭤; 뭤; 뭤; 뭤; 뭤; ) HANGUL SYLLABLE MWEOSS +BB65;BB65;1106 116F 11BC;BB65;1106 116F 11BC; # (뭥; 뭥; 뭥; 뭥; 뭥; ) HANGUL SYLLABLE MWEONG +BB66;BB66;1106 116F 11BD;BB66;1106 116F 11BD; # (뭦; 뭦; 뭦; 뭦; 뭦; ) HANGUL SYLLABLE MWEOJ +BB67;BB67;1106 116F 11BE;BB67;1106 116F 11BE; # (뭧; 뭧; 뭧; 뭧; 뭧; ) HANGUL SYLLABLE MWEOC +BB68;BB68;1106 116F 11BF;BB68;1106 116F 11BF; # (뭨; 뭨; 뭨; 뭨; 뭨; ) HANGUL SYLLABLE MWEOK +BB69;BB69;1106 116F 11C0;BB69;1106 116F 11C0; # (뭩; 뭩; 뭩; 뭩; 뭩; ) HANGUL SYLLABLE MWEOT +BB6A;BB6A;1106 116F 11C1;BB6A;1106 116F 11C1; # (뭪; 뭪; 뭪; 뭪; 뭪; ) HANGUL SYLLABLE MWEOP +BB6B;BB6B;1106 116F 11C2;BB6B;1106 116F 11C2; # (뭫; 뭫; 뭫; 뭫; 뭫; ) HANGUL SYLLABLE MWEOH +BB6C;BB6C;1106 1170;BB6C;1106 1170; # (뭬; 뭬; 뭬; 뭬; 뭬; ) HANGUL SYLLABLE MWE +BB6D;BB6D;1106 1170 11A8;BB6D;1106 1170 11A8; # (뭭; 뭭; 뭭; 뭭; 뭭; ) HANGUL SYLLABLE MWEG +BB6E;BB6E;1106 1170 11A9;BB6E;1106 1170 11A9; # (뭮; 뭮; 뭮; 뭮; 뭮; ) HANGUL SYLLABLE MWEGG +BB6F;BB6F;1106 1170 11AA;BB6F;1106 1170 11AA; # (뭯; 뭯; 뭯; 뭯; 뭯; ) HANGUL SYLLABLE MWEGS +BB70;BB70;1106 1170 11AB;BB70;1106 1170 11AB; # (뭰; 뭰; 뭰; 뭰; 뭰; ) HANGUL SYLLABLE MWEN +BB71;BB71;1106 1170 11AC;BB71;1106 1170 11AC; # (뭱; 뭱; 뭱; 뭱; 뭱; ) HANGUL SYLLABLE MWENJ +BB72;BB72;1106 1170 11AD;BB72;1106 1170 11AD; # (뭲; 뭲; 뭲; 뭲; 뭲; ) HANGUL SYLLABLE MWENH +BB73;BB73;1106 1170 11AE;BB73;1106 1170 11AE; # (뭳; 뭳; 뭳; 뭳; 뭳; ) HANGUL SYLLABLE MWED +BB74;BB74;1106 1170 11AF;BB74;1106 1170 11AF; # (뭴; 뭴; 뭴; 뭴; 뭴; ) HANGUL SYLLABLE MWEL +BB75;BB75;1106 1170 11B0;BB75;1106 1170 11B0; # (뭵; 뭵; 뭵; 뭵; 뭵; ) HANGUL SYLLABLE MWELG +BB76;BB76;1106 1170 11B1;BB76;1106 1170 11B1; # (뭶; 뭶; 뭶; 뭶; 뭶; ) HANGUL SYLLABLE MWELM +BB77;BB77;1106 1170 11B2;BB77;1106 1170 11B2; # (뭷; 뭷; 뭷; 뭷; 뭷; ) HANGUL SYLLABLE MWELB +BB78;BB78;1106 1170 11B3;BB78;1106 1170 11B3; # (뭸; 뭸; 뭸; 뭸; 뭸; ) HANGUL SYLLABLE MWELS +BB79;BB79;1106 1170 11B4;BB79;1106 1170 11B4; # (뭹; 뭹; 뭹; 뭹; 뭹; ) HANGUL SYLLABLE MWELT +BB7A;BB7A;1106 1170 11B5;BB7A;1106 1170 11B5; # (뭺; 뭺; 뭺; 뭺; 뭺; ) HANGUL SYLLABLE MWELP +BB7B;BB7B;1106 1170 11B6;BB7B;1106 1170 11B6; # (뭻; 뭻; 뭻; 뭻; 뭻; ) HANGUL SYLLABLE MWELH +BB7C;BB7C;1106 1170 11B7;BB7C;1106 1170 11B7; # (뭼; 뭼; 뭼; 뭼; 뭼; ) HANGUL SYLLABLE MWEM +BB7D;BB7D;1106 1170 11B8;BB7D;1106 1170 11B8; # (뭽; 뭽; 뭽; 뭽; 뭽; ) HANGUL SYLLABLE MWEB +BB7E;BB7E;1106 1170 11B9;BB7E;1106 1170 11B9; # (뭾; 뭾; 뭾; 뭾; 뭾; ) HANGUL SYLLABLE MWEBS +BB7F;BB7F;1106 1170 11BA;BB7F;1106 1170 11BA; # (뭿; 뭿; 뭿; 뭿; 뭿; ) HANGUL SYLLABLE MWES +BB80;BB80;1106 1170 11BB;BB80;1106 1170 11BB; # (뮀; 뮀; 뮀; 뮀; 뮀; ) HANGUL SYLLABLE MWESS +BB81;BB81;1106 1170 11BC;BB81;1106 1170 11BC; # (뮁; 뮁; 뮁; 뮁; 뮁; ) HANGUL SYLLABLE MWENG +BB82;BB82;1106 1170 11BD;BB82;1106 1170 11BD; # (뮂; 뮂; 뮂; 뮂; 뮂; ) HANGUL SYLLABLE MWEJ +BB83;BB83;1106 1170 11BE;BB83;1106 1170 11BE; # (뮃; 뮃; 뮃; 뮃; 뮃; ) HANGUL SYLLABLE MWEC +BB84;BB84;1106 1170 11BF;BB84;1106 1170 11BF; # (뮄; 뮄; 뮄; 뮄; 뮄; ) HANGUL SYLLABLE MWEK +BB85;BB85;1106 1170 11C0;BB85;1106 1170 11C0; # (뮅; 뮅; 뮅; 뮅; 뮅; ) HANGUL SYLLABLE MWET +BB86;BB86;1106 1170 11C1;BB86;1106 1170 11C1; # (뮆; 뮆; 뮆; 뮆; 뮆; ) HANGUL SYLLABLE MWEP +BB87;BB87;1106 1170 11C2;BB87;1106 1170 11C2; # (뮇; 뮇; 뮇; 뮇; 뮇; ) HANGUL SYLLABLE MWEH +BB88;BB88;1106 1171;BB88;1106 1171; # (뮈; 뮈; 뮈; 뮈; 뮈; ) HANGUL SYLLABLE MWI +BB89;BB89;1106 1171 11A8;BB89;1106 1171 11A8; # (뮉; 뮉; 뮉; 뮉; 뮉; ) HANGUL SYLLABLE MWIG +BB8A;BB8A;1106 1171 11A9;BB8A;1106 1171 11A9; # (뮊; 뮊; 뮊; 뮊; 뮊; ) HANGUL SYLLABLE MWIGG +BB8B;BB8B;1106 1171 11AA;BB8B;1106 1171 11AA; # (뮋; 뮋; 뮋; 뮋; 뮋; ) HANGUL SYLLABLE MWIGS +BB8C;BB8C;1106 1171 11AB;BB8C;1106 1171 11AB; # (뮌; 뮌; 뮌; 뮌; 뮌; ) HANGUL SYLLABLE MWIN +BB8D;BB8D;1106 1171 11AC;BB8D;1106 1171 11AC; # (뮍; 뮍; 뮍; 뮍; 뮍; ) HANGUL SYLLABLE MWINJ +BB8E;BB8E;1106 1171 11AD;BB8E;1106 1171 11AD; # (뮎; 뮎; 뮎; 뮎; 뮎; ) HANGUL SYLLABLE MWINH +BB8F;BB8F;1106 1171 11AE;BB8F;1106 1171 11AE; # (뮏; 뮏; 뮏; 뮏; 뮏; ) HANGUL SYLLABLE MWID +BB90;BB90;1106 1171 11AF;BB90;1106 1171 11AF; # (뮐; 뮐; 뮐; 뮐; 뮐; ) HANGUL SYLLABLE MWIL +BB91;BB91;1106 1171 11B0;BB91;1106 1171 11B0; # (뮑; 뮑; 뮑; 뮑; 뮑; ) HANGUL SYLLABLE MWILG +BB92;BB92;1106 1171 11B1;BB92;1106 1171 11B1; # (뮒; 뮒; 뮒; 뮒; 뮒; ) HANGUL SYLLABLE MWILM +BB93;BB93;1106 1171 11B2;BB93;1106 1171 11B2; # (뮓; 뮓; 뮓; 뮓; 뮓; ) HANGUL SYLLABLE MWILB +BB94;BB94;1106 1171 11B3;BB94;1106 1171 11B3; # (뮔; 뮔; 뮔; 뮔; 뮔; ) HANGUL SYLLABLE MWILS +BB95;BB95;1106 1171 11B4;BB95;1106 1171 11B4; # (뮕; 뮕; 뮕; 뮕; 뮕; ) HANGUL SYLLABLE MWILT +BB96;BB96;1106 1171 11B5;BB96;1106 1171 11B5; # (뮖; 뮖; 뮖; 뮖; 뮖; ) HANGUL SYLLABLE MWILP +BB97;BB97;1106 1171 11B6;BB97;1106 1171 11B6; # (뮗; 뮗; 뮗; 뮗; 뮗; ) HANGUL SYLLABLE MWILH +BB98;BB98;1106 1171 11B7;BB98;1106 1171 11B7; # (뮘; 뮘; 뮘; 뮘; 뮘; ) HANGUL SYLLABLE MWIM +BB99;BB99;1106 1171 11B8;BB99;1106 1171 11B8; # (뮙; 뮙; 뮙; 뮙; 뮙; ) HANGUL SYLLABLE MWIB +BB9A;BB9A;1106 1171 11B9;BB9A;1106 1171 11B9; # (뮚; 뮚; 뮚; 뮚; 뮚; ) HANGUL SYLLABLE MWIBS +BB9B;BB9B;1106 1171 11BA;BB9B;1106 1171 11BA; # (뮛; 뮛; 뮛; 뮛; 뮛; ) HANGUL SYLLABLE MWIS +BB9C;BB9C;1106 1171 11BB;BB9C;1106 1171 11BB; # (뮜; 뮜; 뮜; 뮜; 뮜; ) HANGUL SYLLABLE MWISS +BB9D;BB9D;1106 1171 11BC;BB9D;1106 1171 11BC; # (뮝; 뮝; 뮝; 뮝; 뮝; ) HANGUL SYLLABLE MWING +BB9E;BB9E;1106 1171 11BD;BB9E;1106 1171 11BD; # (뮞; 뮞; 뮞; 뮞; 뮞; ) HANGUL SYLLABLE MWIJ +BB9F;BB9F;1106 1171 11BE;BB9F;1106 1171 11BE; # (뮟; 뮟; 뮟; 뮟; 뮟; ) HANGUL SYLLABLE MWIC +BBA0;BBA0;1106 1171 11BF;BBA0;1106 1171 11BF; # (뮠; 뮠; 뮠; 뮠; 뮠; ) HANGUL SYLLABLE MWIK +BBA1;BBA1;1106 1171 11C0;BBA1;1106 1171 11C0; # (뮡; 뮡; 뮡; 뮡; 뮡; ) HANGUL SYLLABLE MWIT +BBA2;BBA2;1106 1171 11C1;BBA2;1106 1171 11C1; # (뮢; 뮢; 뮢; 뮢; 뮢; ) HANGUL SYLLABLE MWIP +BBA3;BBA3;1106 1171 11C2;BBA3;1106 1171 11C2; # (뮣; 뮣; 뮣; 뮣; 뮣; ) HANGUL SYLLABLE MWIH +BBA4;BBA4;1106 1172;BBA4;1106 1172; # (뮤; 뮤; 뮤; 뮤; 뮤; ) HANGUL SYLLABLE MYU +BBA5;BBA5;1106 1172 11A8;BBA5;1106 1172 11A8; # (뮥; 뮥; 뮥; 뮥; 뮥; ) HANGUL SYLLABLE MYUG +BBA6;BBA6;1106 1172 11A9;BBA6;1106 1172 11A9; # (뮦; 뮦; 뮦; 뮦; 뮦; ) HANGUL SYLLABLE MYUGG +BBA7;BBA7;1106 1172 11AA;BBA7;1106 1172 11AA; # (뮧; 뮧; 뮧; 뮧; 뮧; ) HANGUL SYLLABLE MYUGS +BBA8;BBA8;1106 1172 11AB;BBA8;1106 1172 11AB; # (뮨; 뮨; 뮨; 뮨; 뮨; ) HANGUL SYLLABLE MYUN +BBA9;BBA9;1106 1172 11AC;BBA9;1106 1172 11AC; # (뮩; 뮩; 뮩; 뮩; 뮩; ) HANGUL SYLLABLE MYUNJ +BBAA;BBAA;1106 1172 11AD;BBAA;1106 1172 11AD; # (뮪; 뮪; 뮪; 뮪; 뮪; ) HANGUL SYLLABLE MYUNH +BBAB;BBAB;1106 1172 11AE;BBAB;1106 1172 11AE; # (뮫; 뮫; 뮫; 뮫; 뮫; ) HANGUL SYLLABLE MYUD +BBAC;BBAC;1106 1172 11AF;BBAC;1106 1172 11AF; # (뮬; 뮬; 뮬; 뮬; 뮬; ) HANGUL SYLLABLE MYUL +BBAD;BBAD;1106 1172 11B0;BBAD;1106 1172 11B0; # (뮭; 뮭; 뮭; 뮭; 뮭; ) HANGUL SYLLABLE MYULG +BBAE;BBAE;1106 1172 11B1;BBAE;1106 1172 11B1; # (뮮; 뮮; 뮮; 뮮; 뮮; ) HANGUL SYLLABLE MYULM +BBAF;BBAF;1106 1172 11B2;BBAF;1106 1172 11B2; # (뮯; 뮯; 뮯; 뮯; 뮯; ) HANGUL SYLLABLE MYULB +BBB0;BBB0;1106 1172 11B3;BBB0;1106 1172 11B3; # (뮰; 뮰; 뮰; 뮰; 뮰; ) HANGUL SYLLABLE MYULS +BBB1;BBB1;1106 1172 11B4;BBB1;1106 1172 11B4; # (뮱; 뮱; 뮱; 뮱; 뮱; ) HANGUL SYLLABLE MYULT +BBB2;BBB2;1106 1172 11B5;BBB2;1106 1172 11B5; # (뮲; 뮲; 뮲; 뮲; 뮲; ) HANGUL SYLLABLE MYULP +BBB3;BBB3;1106 1172 11B6;BBB3;1106 1172 11B6; # (뮳; 뮳; 뮳; 뮳; 뮳; ) HANGUL SYLLABLE MYULH +BBB4;BBB4;1106 1172 11B7;BBB4;1106 1172 11B7; # (뮴; 뮴; 뮴; 뮴; 뮴; ) HANGUL SYLLABLE MYUM +BBB5;BBB5;1106 1172 11B8;BBB5;1106 1172 11B8; # (뮵; 뮵; 뮵; 뮵; 뮵; ) HANGUL SYLLABLE MYUB +BBB6;BBB6;1106 1172 11B9;BBB6;1106 1172 11B9; # (뮶; 뮶; 뮶; 뮶; 뮶; ) HANGUL SYLLABLE MYUBS +BBB7;BBB7;1106 1172 11BA;BBB7;1106 1172 11BA; # (뮷; 뮷; 뮷; 뮷; 뮷; ) HANGUL SYLLABLE MYUS +BBB8;BBB8;1106 1172 11BB;BBB8;1106 1172 11BB; # (뮸; 뮸; 뮸; 뮸; 뮸; ) HANGUL SYLLABLE MYUSS +BBB9;BBB9;1106 1172 11BC;BBB9;1106 1172 11BC; # (뮹; 뮹; 뮹; 뮹; 뮹; ) HANGUL SYLLABLE MYUNG +BBBA;BBBA;1106 1172 11BD;BBBA;1106 1172 11BD; # (뮺; 뮺; 뮺; 뮺; 뮺; ) HANGUL SYLLABLE MYUJ +BBBB;BBBB;1106 1172 11BE;BBBB;1106 1172 11BE; # (뮻; 뮻; 뮻; 뮻; 뮻; ) HANGUL SYLLABLE MYUC +BBBC;BBBC;1106 1172 11BF;BBBC;1106 1172 11BF; # (뮼; 뮼; 뮼; 뮼; 뮼; ) HANGUL SYLLABLE MYUK +BBBD;BBBD;1106 1172 11C0;BBBD;1106 1172 11C0; # (뮽; 뮽; 뮽; 뮽; 뮽; ) HANGUL SYLLABLE MYUT +BBBE;BBBE;1106 1172 11C1;BBBE;1106 1172 11C1; # (뮾; 뮾; 뮾; 뮾; 뮾; ) HANGUL SYLLABLE MYUP +BBBF;BBBF;1106 1172 11C2;BBBF;1106 1172 11C2; # (뮿; 뮿; 뮿; 뮿; 뮿; ) HANGUL SYLLABLE MYUH +BBC0;BBC0;1106 1173;BBC0;1106 1173; # (므; 므; 므; 므; 므; ) HANGUL SYLLABLE MEU +BBC1;BBC1;1106 1173 11A8;BBC1;1106 1173 11A8; # (믁; 믁; 믁; 믁; 믁; ) HANGUL SYLLABLE MEUG +BBC2;BBC2;1106 1173 11A9;BBC2;1106 1173 11A9; # (믂; 믂; 믂; 믂; 믂; ) HANGUL SYLLABLE MEUGG +BBC3;BBC3;1106 1173 11AA;BBC3;1106 1173 11AA; # (믃; 믃; 믃; 믃; 믃; ) HANGUL SYLLABLE MEUGS +BBC4;BBC4;1106 1173 11AB;BBC4;1106 1173 11AB; # (믄; 믄; 믄; 믄; 믄; ) HANGUL SYLLABLE MEUN +BBC5;BBC5;1106 1173 11AC;BBC5;1106 1173 11AC; # (믅; 믅; 믅; 믅; 믅; ) HANGUL SYLLABLE MEUNJ +BBC6;BBC6;1106 1173 11AD;BBC6;1106 1173 11AD; # (믆; 믆; 믆; 믆; 믆; ) HANGUL SYLLABLE MEUNH +BBC7;BBC7;1106 1173 11AE;BBC7;1106 1173 11AE; # (믇; 믇; 믇; 믇; 믇; ) HANGUL SYLLABLE MEUD +BBC8;BBC8;1106 1173 11AF;BBC8;1106 1173 11AF; # (믈; 믈; 믈; 믈; 믈; ) HANGUL SYLLABLE MEUL +BBC9;BBC9;1106 1173 11B0;BBC9;1106 1173 11B0; # (믉; 믉; 믉; 믉; 믉; ) HANGUL SYLLABLE MEULG +BBCA;BBCA;1106 1173 11B1;BBCA;1106 1173 11B1; # (믊; 믊; 믊; 믊; 믊; ) HANGUL SYLLABLE MEULM +BBCB;BBCB;1106 1173 11B2;BBCB;1106 1173 11B2; # (믋; 믋; 믋; 믋; 믋; ) HANGUL SYLLABLE MEULB +BBCC;BBCC;1106 1173 11B3;BBCC;1106 1173 11B3; # (믌; 믌; 믌; 믌; 믌; ) HANGUL SYLLABLE MEULS +BBCD;BBCD;1106 1173 11B4;BBCD;1106 1173 11B4; # (믍; 믍; 믍; 믍; 믍; ) HANGUL SYLLABLE MEULT +BBCE;BBCE;1106 1173 11B5;BBCE;1106 1173 11B5; # (믎; 믎; 믎; 믎; 믎; ) HANGUL SYLLABLE MEULP +BBCF;BBCF;1106 1173 11B6;BBCF;1106 1173 11B6; # (믏; 믏; 믏; 믏; 믏; ) HANGUL SYLLABLE MEULH +BBD0;BBD0;1106 1173 11B7;BBD0;1106 1173 11B7; # (믐; 믐; 믐; 믐; 믐; ) HANGUL SYLLABLE MEUM +BBD1;BBD1;1106 1173 11B8;BBD1;1106 1173 11B8; # (믑; 믑; 믑; 믑; 믑; ) HANGUL SYLLABLE MEUB +BBD2;BBD2;1106 1173 11B9;BBD2;1106 1173 11B9; # (믒; 믒; 믒; 믒; 믒; ) HANGUL SYLLABLE MEUBS +BBD3;BBD3;1106 1173 11BA;BBD3;1106 1173 11BA; # (믓; 믓; 믓; 믓; 믓; ) HANGUL SYLLABLE MEUS +BBD4;BBD4;1106 1173 11BB;BBD4;1106 1173 11BB; # (믔; 믔; 믔; 믔; 믔; ) HANGUL SYLLABLE MEUSS +BBD5;BBD5;1106 1173 11BC;BBD5;1106 1173 11BC; # (믕; 믕; 믕; 믕; 믕; ) HANGUL SYLLABLE MEUNG +BBD6;BBD6;1106 1173 11BD;BBD6;1106 1173 11BD; # (믖; 믖; 믖; 믖; 믖; ) HANGUL SYLLABLE MEUJ +BBD7;BBD7;1106 1173 11BE;BBD7;1106 1173 11BE; # (믗; 믗; 믗; 믗; 믗; ) HANGUL SYLLABLE MEUC +BBD8;BBD8;1106 1173 11BF;BBD8;1106 1173 11BF; # (믘; 믘; 믘; 믘; 믘; ) HANGUL SYLLABLE MEUK +BBD9;BBD9;1106 1173 11C0;BBD9;1106 1173 11C0; # (믙; 믙; 믙; 믙; 믙; ) HANGUL SYLLABLE MEUT +BBDA;BBDA;1106 1173 11C1;BBDA;1106 1173 11C1; # (믚; 믚; 믚; 믚; 믚; ) HANGUL SYLLABLE MEUP +BBDB;BBDB;1106 1173 11C2;BBDB;1106 1173 11C2; # (믛; 믛; 믛; 믛; 믛; ) HANGUL SYLLABLE MEUH +BBDC;BBDC;1106 1174;BBDC;1106 1174; # (믜; 믜; 믜; 믜; 믜; ) HANGUL SYLLABLE MYI +BBDD;BBDD;1106 1174 11A8;BBDD;1106 1174 11A8; # (믝; 믝; 믝; 믝; 믝; ) HANGUL SYLLABLE MYIG +BBDE;BBDE;1106 1174 11A9;BBDE;1106 1174 11A9; # (믞; 믞; 믞; 믞; 믞; ) HANGUL SYLLABLE MYIGG +BBDF;BBDF;1106 1174 11AA;BBDF;1106 1174 11AA; # (믟; 믟; 믟; 믟; 믟; ) HANGUL SYLLABLE MYIGS +BBE0;BBE0;1106 1174 11AB;BBE0;1106 1174 11AB; # (믠; 믠; 믠; 믠; 믠; ) HANGUL SYLLABLE MYIN +BBE1;BBE1;1106 1174 11AC;BBE1;1106 1174 11AC; # (믡; 믡; 믡; 믡; 믡; ) HANGUL SYLLABLE MYINJ +BBE2;BBE2;1106 1174 11AD;BBE2;1106 1174 11AD; # (믢; 믢; 믢; 믢; 믢; ) HANGUL SYLLABLE MYINH +BBE3;BBE3;1106 1174 11AE;BBE3;1106 1174 11AE; # (믣; 믣; 믣; 믣; 믣; ) HANGUL SYLLABLE MYID +BBE4;BBE4;1106 1174 11AF;BBE4;1106 1174 11AF; # (믤; 믤; 믤; 믤; 믤; ) HANGUL SYLLABLE MYIL +BBE5;BBE5;1106 1174 11B0;BBE5;1106 1174 11B0; # (믥; 믥; 믥; 믥; 믥; ) HANGUL SYLLABLE MYILG +BBE6;BBE6;1106 1174 11B1;BBE6;1106 1174 11B1; # (믦; 믦; 믦; 믦; 믦; ) HANGUL SYLLABLE MYILM +BBE7;BBE7;1106 1174 11B2;BBE7;1106 1174 11B2; # (믧; 믧; 믧; 믧; 믧; ) HANGUL SYLLABLE MYILB +BBE8;BBE8;1106 1174 11B3;BBE8;1106 1174 11B3; # (믨; 믨; 믨; 믨; 믨; ) HANGUL SYLLABLE MYILS +BBE9;BBE9;1106 1174 11B4;BBE9;1106 1174 11B4; # (믩; 믩; 믩; 믩; 믩; ) HANGUL SYLLABLE MYILT +BBEA;BBEA;1106 1174 11B5;BBEA;1106 1174 11B5; # (믪; 믪; 믪; 믪; 믪; ) HANGUL SYLLABLE MYILP +BBEB;BBEB;1106 1174 11B6;BBEB;1106 1174 11B6; # (믫; 믫; 믫; 믫; 믫; ) HANGUL SYLLABLE MYILH +BBEC;BBEC;1106 1174 11B7;BBEC;1106 1174 11B7; # (믬; 믬; 믬; 믬; 믬; ) HANGUL SYLLABLE MYIM +BBED;BBED;1106 1174 11B8;BBED;1106 1174 11B8; # (믭; 믭; 믭; 믭; 믭; ) HANGUL SYLLABLE MYIB +BBEE;BBEE;1106 1174 11B9;BBEE;1106 1174 11B9; # (믮; 믮; 믮; 믮; 믮; ) HANGUL SYLLABLE MYIBS +BBEF;BBEF;1106 1174 11BA;BBEF;1106 1174 11BA; # (믯; 믯; 믯; 믯; 믯; ) HANGUL SYLLABLE MYIS +BBF0;BBF0;1106 1174 11BB;BBF0;1106 1174 11BB; # (믰; 믰; 믰; 믰; 믰; ) HANGUL SYLLABLE MYISS +BBF1;BBF1;1106 1174 11BC;BBF1;1106 1174 11BC; # (믱; 믱; 믱; 믱; 믱; ) HANGUL SYLLABLE MYING +BBF2;BBF2;1106 1174 11BD;BBF2;1106 1174 11BD; # (믲; 믲; 믲; 믲; 믲; ) HANGUL SYLLABLE MYIJ +BBF3;BBF3;1106 1174 11BE;BBF3;1106 1174 11BE; # (믳; 믳; 믳; 믳; 믳; ) HANGUL SYLLABLE MYIC +BBF4;BBF4;1106 1174 11BF;BBF4;1106 1174 11BF; # (믴; 믴; 믴; 믴; 믴; ) HANGUL SYLLABLE MYIK +BBF5;BBF5;1106 1174 11C0;BBF5;1106 1174 11C0; # (믵; 믵; 믵; 믵; 믵; ) HANGUL SYLLABLE MYIT +BBF6;BBF6;1106 1174 11C1;BBF6;1106 1174 11C1; # (믶; 믶; 믶; 믶; 믶; ) HANGUL SYLLABLE MYIP +BBF7;BBF7;1106 1174 11C2;BBF7;1106 1174 11C2; # (믷; 믷; 믷; 믷; 믷; ) HANGUL SYLLABLE MYIH +BBF8;BBF8;1106 1175;BBF8;1106 1175; # (미; 미; 미; 미; 미; ) HANGUL SYLLABLE MI +BBF9;BBF9;1106 1175 11A8;BBF9;1106 1175 11A8; # (믹; 믹; 믹; 믹; 믹; ) HANGUL SYLLABLE MIG +BBFA;BBFA;1106 1175 11A9;BBFA;1106 1175 11A9; # (믺; 믺; 믺; 믺; 믺; ) HANGUL SYLLABLE MIGG +BBFB;BBFB;1106 1175 11AA;BBFB;1106 1175 11AA; # (믻; 믻; 믻; 믻; 믻; ) HANGUL SYLLABLE MIGS +BBFC;BBFC;1106 1175 11AB;BBFC;1106 1175 11AB; # (민; 민; 민; 민; 민; ) HANGUL SYLLABLE MIN +BBFD;BBFD;1106 1175 11AC;BBFD;1106 1175 11AC; # (믽; 믽; 믽; 믽; 믽; ) HANGUL SYLLABLE MINJ +BBFE;BBFE;1106 1175 11AD;BBFE;1106 1175 11AD; # (믾; 믾; 믾; 믾; 믾; ) HANGUL SYLLABLE MINH +BBFF;BBFF;1106 1175 11AE;BBFF;1106 1175 11AE; # (믿; 믿; 믿; 믿; 믿; ) HANGUL SYLLABLE MID +BC00;BC00;1106 1175 11AF;BC00;1106 1175 11AF; # (밀; 밀; 밀; 밀; 밀; ) HANGUL SYLLABLE MIL +BC01;BC01;1106 1175 11B0;BC01;1106 1175 11B0; # (밁; 밁; 밁; 밁; 밁; ) HANGUL SYLLABLE MILG +BC02;BC02;1106 1175 11B1;BC02;1106 1175 11B1; # (밂; 밂; 밂; 밂; 밂; ) HANGUL SYLLABLE MILM +BC03;BC03;1106 1175 11B2;BC03;1106 1175 11B2; # (밃; 밃; 밃; 밃; 밃; ) HANGUL SYLLABLE MILB +BC04;BC04;1106 1175 11B3;BC04;1106 1175 11B3; # (밄; 밄; 밄; 밄; 밄; ) HANGUL SYLLABLE MILS +BC05;BC05;1106 1175 11B4;BC05;1106 1175 11B4; # (밅; 밅; 밅; 밅; 밅; ) HANGUL SYLLABLE MILT +BC06;BC06;1106 1175 11B5;BC06;1106 1175 11B5; # (밆; 밆; 밆; 밆; 밆; ) HANGUL SYLLABLE MILP +BC07;BC07;1106 1175 11B6;BC07;1106 1175 11B6; # (밇; 밇; 밇; 밇; 밇; ) HANGUL SYLLABLE MILH +BC08;BC08;1106 1175 11B7;BC08;1106 1175 11B7; # (밈; 밈; 밈; 밈; 밈; ) HANGUL SYLLABLE MIM +BC09;BC09;1106 1175 11B8;BC09;1106 1175 11B8; # (밉; 밉; 밉; 밉; 밉; ) HANGUL SYLLABLE MIB +BC0A;BC0A;1106 1175 11B9;BC0A;1106 1175 11B9; # (밊; 밊; 밊; 밊; 밊; ) HANGUL SYLLABLE MIBS +BC0B;BC0B;1106 1175 11BA;BC0B;1106 1175 11BA; # (밋; 밋; 밋; 밋; 밋; ) HANGUL SYLLABLE MIS +BC0C;BC0C;1106 1175 11BB;BC0C;1106 1175 11BB; # (밌; 밌; 밌; 밌; 밌; ) HANGUL SYLLABLE MISS +BC0D;BC0D;1106 1175 11BC;BC0D;1106 1175 11BC; # (밍; 밍; 밍; 밍; 밍; ) HANGUL SYLLABLE MING +BC0E;BC0E;1106 1175 11BD;BC0E;1106 1175 11BD; # (밎; 밎; 밎; 밎; 밎; ) HANGUL SYLLABLE MIJ +BC0F;BC0F;1106 1175 11BE;BC0F;1106 1175 11BE; # (및; 및; 및; 및; 및; ) HANGUL SYLLABLE MIC +BC10;BC10;1106 1175 11BF;BC10;1106 1175 11BF; # (밐; 밐; 밐; 밐; 밐; ) HANGUL SYLLABLE MIK +BC11;BC11;1106 1175 11C0;BC11;1106 1175 11C0; # (밑; 밑; 밑; 밑; 밑; ) HANGUL SYLLABLE MIT +BC12;BC12;1106 1175 11C1;BC12;1106 1175 11C1; # (밒; 밒; 밒; 밒; 밒; ) HANGUL SYLLABLE MIP +BC13;BC13;1106 1175 11C2;BC13;1106 1175 11C2; # (밓; 밓; 밓; 밓; 밓; ) HANGUL SYLLABLE MIH +BC14;BC14;1107 1161;BC14;1107 1161; # (바; 바; 바; 바; 바; ) HANGUL SYLLABLE BA +BC15;BC15;1107 1161 11A8;BC15;1107 1161 11A8; # (박; 박; 박; 박; 박; ) HANGUL SYLLABLE BAG +BC16;BC16;1107 1161 11A9;BC16;1107 1161 11A9; # (밖; 밖; 밖; 밖; 밖; ) HANGUL SYLLABLE BAGG +BC17;BC17;1107 1161 11AA;BC17;1107 1161 11AA; # (밗; 밗; 밗; 밗; 밗; ) HANGUL SYLLABLE BAGS +BC18;BC18;1107 1161 11AB;BC18;1107 1161 11AB; # (반; 반; 반; 반; 반; ) HANGUL SYLLABLE BAN +BC19;BC19;1107 1161 11AC;BC19;1107 1161 11AC; # (밙; 밙; 밙; 밙; 밙; ) HANGUL SYLLABLE BANJ +BC1A;BC1A;1107 1161 11AD;BC1A;1107 1161 11AD; # (밚; 밚; 밚; 밚; 밚; ) HANGUL SYLLABLE BANH +BC1B;BC1B;1107 1161 11AE;BC1B;1107 1161 11AE; # (받; 받; 받; 받; 받; ) HANGUL SYLLABLE BAD +BC1C;BC1C;1107 1161 11AF;BC1C;1107 1161 11AF; # (발; 발; 발; 발; 발; ) HANGUL SYLLABLE BAL +BC1D;BC1D;1107 1161 11B0;BC1D;1107 1161 11B0; # (밝; 밝; 밝; 밝; 밝; ) HANGUL SYLLABLE BALG +BC1E;BC1E;1107 1161 11B1;BC1E;1107 1161 11B1; # (밞; 밞; 밞; 밞; 밞; ) HANGUL SYLLABLE BALM +BC1F;BC1F;1107 1161 11B2;BC1F;1107 1161 11B2; # (밟; 밟; 밟; 밟; 밟; ) HANGUL SYLLABLE BALB +BC20;BC20;1107 1161 11B3;BC20;1107 1161 11B3; # (밠; 밠; 밠; 밠; 밠; ) HANGUL SYLLABLE BALS +BC21;BC21;1107 1161 11B4;BC21;1107 1161 11B4; # (밡; 밡; 밡; 밡; 밡; ) HANGUL SYLLABLE BALT +BC22;BC22;1107 1161 11B5;BC22;1107 1161 11B5; # (밢; 밢; 밢; 밢; 밢; ) HANGUL SYLLABLE BALP +BC23;BC23;1107 1161 11B6;BC23;1107 1161 11B6; # (밣; 밣; 밣; 밣; 밣; ) HANGUL SYLLABLE BALH +BC24;BC24;1107 1161 11B7;BC24;1107 1161 11B7; # (밤; 밤; 밤; 밤; 밤; ) HANGUL SYLLABLE BAM +BC25;BC25;1107 1161 11B8;BC25;1107 1161 11B8; # (밥; 밥; 밥; 밥; 밥; ) HANGUL SYLLABLE BAB +BC26;BC26;1107 1161 11B9;BC26;1107 1161 11B9; # (밦; 밦; 밦; 밦; 밦; ) HANGUL SYLLABLE BABS +BC27;BC27;1107 1161 11BA;BC27;1107 1161 11BA; # (밧; 밧; 밧; 밧; 밧; ) HANGUL SYLLABLE BAS +BC28;BC28;1107 1161 11BB;BC28;1107 1161 11BB; # (밨; 밨; 밨; 밨; 밨; ) HANGUL SYLLABLE BASS +BC29;BC29;1107 1161 11BC;BC29;1107 1161 11BC; # (방; 방; 방; 방; 방; ) HANGUL SYLLABLE BANG +BC2A;BC2A;1107 1161 11BD;BC2A;1107 1161 11BD; # (밪; 밪; 밪; 밪; 밪; ) HANGUL SYLLABLE BAJ +BC2B;BC2B;1107 1161 11BE;BC2B;1107 1161 11BE; # (밫; 밫; 밫; 밫; 밫; ) HANGUL SYLLABLE BAC +BC2C;BC2C;1107 1161 11BF;BC2C;1107 1161 11BF; # (밬; 밬; 밬; 밬; 밬; ) HANGUL SYLLABLE BAK +BC2D;BC2D;1107 1161 11C0;BC2D;1107 1161 11C0; # (밭; 밭; 밭; 밭; 밭; ) HANGUL SYLLABLE BAT +BC2E;BC2E;1107 1161 11C1;BC2E;1107 1161 11C1; # (밮; 밮; 밮; 밮; 밮; ) HANGUL SYLLABLE BAP +BC2F;BC2F;1107 1161 11C2;BC2F;1107 1161 11C2; # (밯; 밯; 밯; 밯; 밯; ) HANGUL SYLLABLE BAH +BC30;BC30;1107 1162;BC30;1107 1162; # (배; 배; 배; 배; 배; ) HANGUL SYLLABLE BAE +BC31;BC31;1107 1162 11A8;BC31;1107 1162 11A8; # (백; 백; 백; 백; 백; ) HANGUL SYLLABLE BAEG +BC32;BC32;1107 1162 11A9;BC32;1107 1162 11A9; # (밲; 밲; 밲; 밲; 밲; ) HANGUL SYLLABLE BAEGG +BC33;BC33;1107 1162 11AA;BC33;1107 1162 11AA; # (밳; 밳; 밳; 밳; 밳; ) HANGUL SYLLABLE BAEGS +BC34;BC34;1107 1162 11AB;BC34;1107 1162 11AB; # (밴; 밴; 밴; 밴; 밴; ) HANGUL SYLLABLE BAEN +BC35;BC35;1107 1162 11AC;BC35;1107 1162 11AC; # (밵; 밵; 밵; 밵; 밵; ) HANGUL SYLLABLE BAENJ +BC36;BC36;1107 1162 11AD;BC36;1107 1162 11AD; # (밶; 밶; 밶; 밶; 밶; ) HANGUL SYLLABLE BAENH +BC37;BC37;1107 1162 11AE;BC37;1107 1162 11AE; # (밷; 밷; 밷; 밷; 밷; ) HANGUL SYLLABLE BAED +BC38;BC38;1107 1162 11AF;BC38;1107 1162 11AF; # (밸; 밸; 밸; 밸; 밸; ) HANGUL SYLLABLE BAEL +BC39;BC39;1107 1162 11B0;BC39;1107 1162 11B0; # (밹; 밹; 밹; 밹; 밹; ) HANGUL SYLLABLE BAELG +BC3A;BC3A;1107 1162 11B1;BC3A;1107 1162 11B1; # (밺; 밺; 밺; 밺; 밺; ) HANGUL SYLLABLE BAELM +BC3B;BC3B;1107 1162 11B2;BC3B;1107 1162 11B2; # (밻; 밻; 밻; 밻; 밻; ) HANGUL SYLLABLE BAELB +BC3C;BC3C;1107 1162 11B3;BC3C;1107 1162 11B3; # (밼; 밼; 밼; 밼; 밼; ) HANGUL SYLLABLE BAELS +BC3D;BC3D;1107 1162 11B4;BC3D;1107 1162 11B4; # (밽; 밽; 밽; 밽; 밽; ) HANGUL SYLLABLE BAELT +BC3E;BC3E;1107 1162 11B5;BC3E;1107 1162 11B5; # (밾; 밾; 밾; 밾; 밾; ) HANGUL SYLLABLE BAELP +BC3F;BC3F;1107 1162 11B6;BC3F;1107 1162 11B6; # (밿; 밿; 밿; 밿; 밿; ) HANGUL SYLLABLE BAELH +BC40;BC40;1107 1162 11B7;BC40;1107 1162 11B7; # (뱀; 뱀; 뱀; 뱀; 뱀; ) HANGUL SYLLABLE BAEM +BC41;BC41;1107 1162 11B8;BC41;1107 1162 11B8; # (뱁; 뱁; 뱁; 뱁; 뱁; ) HANGUL SYLLABLE BAEB +BC42;BC42;1107 1162 11B9;BC42;1107 1162 11B9; # (뱂; 뱂; 뱂; 뱂; 뱂; ) HANGUL SYLLABLE BAEBS +BC43;BC43;1107 1162 11BA;BC43;1107 1162 11BA; # (뱃; 뱃; 뱃; 뱃; 뱃; ) HANGUL SYLLABLE BAES +BC44;BC44;1107 1162 11BB;BC44;1107 1162 11BB; # (뱄; 뱄; 뱄; 뱄; 뱄; ) HANGUL SYLLABLE BAESS +BC45;BC45;1107 1162 11BC;BC45;1107 1162 11BC; # (뱅; 뱅; 뱅; 뱅; 뱅; ) HANGUL SYLLABLE BAENG +BC46;BC46;1107 1162 11BD;BC46;1107 1162 11BD; # (뱆; 뱆; 뱆; 뱆; 뱆; ) HANGUL SYLLABLE BAEJ +BC47;BC47;1107 1162 11BE;BC47;1107 1162 11BE; # (뱇; 뱇; 뱇; 뱇; 뱇; ) HANGUL SYLLABLE BAEC +BC48;BC48;1107 1162 11BF;BC48;1107 1162 11BF; # (뱈; 뱈; 뱈; 뱈; 뱈; ) HANGUL SYLLABLE BAEK +BC49;BC49;1107 1162 11C0;BC49;1107 1162 11C0; # (뱉; 뱉; 뱉; 뱉; 뱉; ) HANGUL SYLLABLE BAET +BC4A;BC4A;1107 1162 11C1;BC4A;1107 1162 11C1; # (뱊; 뱊; 뱊; 뱊; 뱊; ) HANGUL SYLLABLE BAEP +BC4B;BC4B;1107 1162 11C2;BC4B;1107 1162 11C2; # (뱋; 뱋; 뱋; 뱋; 뱋; ) HANGUL SYLLABLE BAEH +BC4C;BC4C;1107 1163;BC4C;1107 1163; # (뱌; 뱌; 뱌; 뱌; 뱌; ) HANGUL SYLLABLE BYA +BC4D;BC4D;1107 1163 11A8;BC4D;1107 1163 11A8; # (뱍; 뱍; 뱍; 뱍; 뱍; ) HANGUL SYLLABLE BYAG +BC4E;BC4E;1107 1163 11A9;BC4E;1107 1163 11A9; # (뱎; 뱎; 뱎; 뱎; 뱎; ) HANGUL SYLLABLE BYAGG +BC4F;BC4F;1107 1163 11AA;BC4F;1107 1163 11AA; # (뱏; 뱏; 뱏; 뱏; 뱏; ) HANGUL SYLLABLE BYAGS +BC50;BC50;1107 1163 11AB;BC50;1107 1163 11AB; # (뱐; 뱐; 뱐; 뱐; 뱐; ) HANGUL SYLLABLE BYAN +BC51;BC51;1107 1163 11AC;BC51;1107 1163 11AC; # (뱑; 뱑; 뱑; 뱑; 뱑; ) HANGUL SYLLABLE BYANJ +BC52;BC52;1107 1163 11AD;BC52;1107 1163 11AD; # (뱒; 뱒; 뱒; 뱒; 뱒; ) HANGUL SYLLABLE BYANH +BC53;BC53;1107 1163 11AE;BC53;1107 1163 11AE; # (뱓; 뱓; 뱓; 뱓; 뱓; ) HANGUL SYLLABLE BYAD +BC54;BC54;1107 1163 11AF;BC54;1107 1163 11AF; # (뱔; 뱔; 뱔; 뱔; 뱔; ) HANGUL SYLLABLE BYAL +BC55;BC55;1107 1163 11B0;BC55;1107 1163 11B0; # (뱕; 뱕; 뱕; 뱕; 뱕; ) HANGUL SYLLABLE BYALG +BC56;BC56;1107 1163 11B1;BC56;1107 1163 11B1; # (뱖; 뱖; 뱖; 뱖; 뱖; ) HANGUL SYLLABLE BYALM +BC57;BC57;1107 1163 11B2;BC57;1107 1163 11B2; # (뱗; 뱗; 뱗; 뱗; 뱗; ) HANGUL SYLLABLE BYALB +BC58;BC58;1107 1163 11B3;BC58;1107 1163 11B3; # (뱘; 뱘; 뱘; 뱘; 뱘; ) HANGUL SYLLABLE BYALS +BC59;BC59;1107 1163 11B4;BC59;1107 1163 11B4; # (뱙; 뱙; 뱙; 뱙; 뱙; ) HANGUL SYLLABLE BYALT +BC5A;BC5A;1107 1163 11B5;BC5A;1107 1163 11B5; # (뱚; 뱚; 뱚; 뱚; 뱚; ) HANGUL SYLLABLE BYALP +BC5B;BC5B;1107 1163 11B6;BC5B;1107 1163 11B6; # (뱛; 뱛; 뱛; 뱛; 뱛; ) HANGUL SYLLABLE BYALH +BC5C;BC5C;1107 1163 11B7;BC5C;1107 1163 11B7; # (뱜; 뱜; 뱜; 뱜; 뱜; ) HANGUL SYLLABLE BYAM +BC5D;BC5D;1107 1163 11B8;BC5D;1107 1163 11B8; # (뱝; 뱝; 뱝; 뱝; 뱝; ) HANGUL SYLLABLE BYAB +BC5E;BC5E;1107 1163 11B9;BC5E;1107 1163 11B9; # (뱞; 뱞; 뱞; 뱞; 뱞; ) HANGUL SYLLABLE BYABS +BC5F;BC5F;1107 1163 11BA;BC5F;1107 1163 11BA; # (뱟; 뱟; 뱟; 뱟; 뱟; ) HANGUL SYLLABLE BYAS +BC60;BC60;1107 1163 11BB;BC60;1107 1163 11BB; # (뱠; 뱠; 뱠; 뱠; 뱠; ) HANGUL SYLLABLE BYASS +BC61;BC61;1107 1163 11BC;BC61;1107 1163 11BC; # (뱡; 뱡; 뱡; 뱡; 뱡; ) HANGUL SYLLABLE BYANG +BC62;BC62;1107 1163 11BD;BC62;1107 1163 11BD; # (뱢; 뱢; 뱢; 뱢; 뱢; ) HANGUL SYLLABLE BYAJ +BC63;BC63;1107 1163 11BE;BC63;1107 1163 11BE; # (뱣; 뱣; 뱣; 뱣; 뱣; ) HANGUL SYLLABLE BYAC +BC64;BC64;1107 1163 11BF;BC64;1107 1163 11BF; # (뱤; 뱤; 뱤; 뱤; 뱤; ) HANGUL SYLLABLE BYAK +BC65;BC65;1107 1163 11C0;BC65;1107 1163 11C0; # (뱥; 뱥; 뱥; 뱥; 뱥; ) HANGUL SYLLABLE BYAT +BC66;BC66;1107 1163 11C1;BC66;1107 1163 11C1; # (뱦; 뱦; 뱦; 뱦; 뱦; ) HANGUL SYLLABLE BYAP +BC67;BC67;1107 1163 11C2;BC67;1107 1163 11C2; # (뱧; 뱧; 뱧; 뱧; 뱧; ) HANGUL SYLLABLE BYAH +BC68;BC68;1107 1164;BC68;1107 1164; # (뱨; 뱨; 뱨; 뱨; 뱨; ) HANGUL SYLLABLE BYAE +BC69;BC69;1107 1164 11A8;BC69;1107 1164 11A8; # (뱩; 뱩; 뱩; 뱩; 뱩; ) HANGUL SYLLABLE BYAEG +BC6A;BC6A;1107 1164 11A9;BC6A;1107 1164 11A9; # (뱪; 뱪; 뱪; 뱪; 뱪; ) HANGUL SYLLABLE BYAEGG +BC6B;BC6B;1107 1164 11AA;BC6B;1107 1164 11AA; # (뱫; 뱫; 뱫; 뱫; 뱫; ) HANGUL SYLLABLE BYAEGS +BC6C;BC6C;1107 1164 11AB;BC6C;1107 1164 11AB; # (뱬; 뱬; 뱬; 뱬; 뱬; ) HANGUL SYLLABLE BYAEN +BC6D;BC6D;1107 1164 11AC;BC6D;1107 1164 11AC; # (뱭; 뱭; 뱭; 뱭; 뱭; ) HANGUL SYLLABLE BYAENJ +BC6E;BC6E;1107 1164 11AD;BC6E;1107 1164 11AD; # (뱮; 뱮; 뱮; 뱮; 뱮; ) HANGUL SYLLABLE BYAENH +BC6F;BC6F;1107 1164 11AE;BC6F;1107 1164 11AE; # (뱯; 뱯; 뱯; 뱯; 뱯; ) HANGUL SYLLABLE BYAED +BC70;BC70;1107 1164 11AF;BC70;1107 1164 11AF; # (뱰; 뱰; 뱰; 뱰; 뱰; ) HANGUL SYLLABLE BYAEL +BC71;BC71;1107 1164 11B0;BC71;1107 1164 11B0; # (뱱; 뱱; 뱱; 뱱; 뱱; ) HANGUL SYLLABLE BYAELG +BC72;BC72;1107 1164 11B1;BC72;1107 1164 11B1; # (뱲; 뱲; 뱲; 뱲; 뱲; ) HANGUL SYLLABLE BYAELM +BC73;BC73;1107 1164 11B2;BC73;1107 1164 11B2; # (뱳; 뱳; 뱳; 뱳; 뱳; ) HANGUL SYLLABLE BYAELB +BC74;BC74;1107 1164 11B3;BC74;1107 1164 11B3; # (뱴; 뱴; 뱴; 뱴; 뱴; ) HANGUL SYLLABLE BYAELS +BC75;BC75;1107 1164 11B4;BC75;1107 1164 11B4; # (뱵; 뱵; 뱵; 뱵; 뱵; ) HANGUL SYLLABLE BYAELT +BC76;BC76;1107 1164 11B5;BC76;1107 1164 11B5; # (뱶; 뱶; 뱶; 뱶; 뱶; ) HANGUL SYLLABLE BYAELP +BC77;BC77;1107 1164 11B6;BC77;1107 1164 11B6; # (뱷; 뱷; 뱷; 뱷; 뱷; ) HANGUL SYLLABLE BYAELH +BC78;BC78;1107 1164 11B7;BC78;1107 1164 11B7; # (뱸; 뱸; 뱸; 뱸; 뱸; ) HANGUL SYLLABLE BYAEM +BC79;BC79;1107 1164 11B8;BC79;1107 1164 11B8; # (뱹; 뱹; 뱹; 뱹; 뱹; ) HANGUL SYLLABLE BYAEB +BC7A;BC7A;1107 1164 11B9;BC7A;1107 1164 11B9; # (뱺; 뱺; 뱺; 뱺; 뱺; ) HANGUL SYLLABLE BYAEBS +BC7B;BC7B;1107 1164 11BA;BC7B;1107 1164 11BA; # (뱻; 뱻; 뱻; 뱻; 뱻; ) HANGUL SYLLABLE BYAES +BC7C;BC7C;1107 1164 11BB;BC7C;1107 1164 11BB; # (뱼; 뱼; 뱼; 뱼; 뱼; ) HANGUL SYLLABLE BYAESS +BC7D;BC7D;1107 1164 11BC;BC7D;1107 1164 11BC; # (뱽; 뱽; 뱽; 뱽; 뱽; ) HANGUL SYLLABLE BYAENG +BC7E;BC7E;1107 1164 11BD;BC7E;1107 1164 11BD; # (뱾; 뱾; 뱾; 뱾; 뱾; ) HANGUL SYLLABLE BYAEJ +BC7F;BC7F;1107 1164 11BE;BC7F;1107 1164 11BE; # (뱿; 뱿; 뱿; 뱿; 뱿; ) HANGUL SYLLABLE BYAEC +BC80;BC80;1107 1164 11BF;BC80;1107 1164 11BF; # (벀; 벀; 벀; 벀; 벀; ) HANGUL SYLLABLE BYAEK +BC81;BC81;1107 1164 11C0;BC81;1107 1164 11C0; # (벁; 벁; 벁; 벁; 벁; ) HANGUL SYLLABLE BYAET +BC82;BC82;1107 1164 11C1;BC82;1107 1164 11C1; # (벂; 벂; 벂; 벂; 벂; ) HANGUL SYLLABLE BYAEP +BC83;BC83;1107 1164 11C2;BC83;1107 1164 11C2; # (벃; 벃; 벃; 벃; 벃; ) HANGUL SYLLABLE BYAEH +BC84;BC84;1107 1165;BC84;1107 1165; # (버; 버; 버; 버; 버; ) HANGUL SYLLABLE BEO +BC85;BC85;1107 1165 11A8;BC85;1107 1165 11A8; # (벅; 벅; 벅; 벅; 벅; ) HANGUL SYLLABLE BEOG +BC86;BC86;1107 1165 11A9;BC86;1107 1165 11A9; # (벆; 벆; 벆; 벆; 벆; ) HANGUL SYLLABLE BEOGG +BC87;BC87;1107 1165 11AA;BC87;1107 1165 11AA; # (벇; 벇; 벇; 벇; 벇; ) HANGUL SYLLABLE BEOGS +BC88;BC88;1107 1165 11AB;BC88;1107 1165 11AB; # (번; 번; 번; 번; 번; ) HANGUL SYLLABLE BEON +BC89;BC89;1107 1165 11AC;BC89;1107 1165 11AC; # (벉; 벉; 벉; 벉; 벉; ) HANGUL SYLLABLE BEONJ +BC8A;BC8A;1107 1165 11AD;BC8A;1107 1165 11AD; # (벊; 벊; 벊; 벊; 벊; ) HANGUL SYLLABLE BEONH +BC8B;BC8B;1107 1165 11AE;BC8B;1107 1165 11AE; # (벋; 벋; 벋; 벋; 벋; ) HANGUL SYLLABLE BEOD +BC8C;BC8C;1107 1165 11AF;BC8C;1107 1165 11AF; # (벌; 벌; 벌; 벌; 벌; ) HANGUL SYLLABLE BEOL +BC8D;BC8D;1107 1165 11B0;BC8D;1107 1165 11B0; # (벍; 벍; 벍; 벍; 벍; ) HANGUL SYLLABLE BEOLG +BC8E;BC8E;1107 1165 11B1;BC8E;1107 1165 11B1; # (벎; 벎; 벎; 벎; 벎; ) HANGUL SYLLABLE BEOLM +BC8F;BC8F;1107 1165 11B2;BC8F;1107 1165 11B2; # (벏; 벏; 벏; 벏; 벏; ) HANGUL SYLLABLE BEOLB +BC90;BC90;1107 1165 11B3;BC90;1107 1165 11B3; # (벐; 벐; 벐; 벐; 벐; ) HANGUL SYLLABLE BEOLS +BC91;BC91;1107 1165 11B4;BC91;1107 1165 11B4; # (벑; 벑; 벑; 벑; 벑; ) HANGUL SYLLABLE BEOLT +BC92;BC92;1107 1165 11B5;BC92;1107 1165 11B5; # (벒; 벒; 벒; 벒; 벒; ) HANGUL SYLLABLE BEOLP +BC93;BC93;1107 1165 11B6;BC93;1107 1165 11B6; # (벓; 벓; 벓; 벓; 벓; ) HANGUL SYLLABLE BEOLH +BC94;BC94;1107 1165 11B7;BC94;1107 1165 11B7; # (범; 범; 범; 범; 범; ) HANGUL SYLLABLE BEOM +BC95;BC95;1107 1165 11B8;BC95;1107 1165 11B8; # (법; 법; 법; 법; 법; ) HANGUL SYLLABLE BEOB +BC96;BC96;1107 1165 11B9;BC96;1107 1165 11B9; # (벖; 벖; 벖; 벖; 벖; ) HANGUL SYLLABLE BEOBS +BC97;BC97;1107 1165 11BA;BC97;1107 1165 11BA; # (벗; 벗; 벗; 벗; 벗; ) HANGUL SYLLABLE BEOS +BC98;BC98;1107 1165 11BB;BC98;1107 1165 11BB; # (벘; 벘; 벘; 벘; 벘; ) HANGUL SYLLABLE BEOSS +BC99;BC99;1107 1165 11BC;BC99;1107 1165 11BC; # (벙; 벙; 벙; 벙; 벙; ) HANGUL SYLLABLE BEONG +BC9A;BC9A;1107 1165 11BD;BC9A;1107 1165 11BD; # (벚; 벚; 벚; 벚; 벚; ) HANGUL SYLLABLE BEOJ +BC9B;BC9B;1107 1165 11BE;BC9B;1107 1165 11BE; # (벛; 벛; 벛; 벛; 벛; ) HANGUL SYLLABLE BEOC +BC9C;BC9C;1107 1165 11BF;BC9C;1107 1165 11BF; # (벜; 벜; 벜; 벜; 벜; ) HANGUL SYLLABLE BEOK +BC9D;BC9D;1107 1165 11C0;BC9D;1107 1165 11C0; # (벝; 벝; 벝; 벝; 벝; ) HANGUL SYLLABLE BEOT +BC9E;BC9E;1107 1165 11C1;BC9E;1107 1165 11C1; # (벞; 벞; 벞; 벞; 벞; ) HANGUL SYLLABLE BEOP +BC9F;BC9F;1107 1165 11C2;BC9F;1107 1165 11C2; # (벟; 벟; 벟; 벟; 벟; ) HANGUL SYLLABLE BEOH +BCA0;BCA0;1107 1166;BCA0;1107 1166; # (베; 베; 베; 베; 베; ) HANGUL SYLLABLE BE +BCA1;BCA1;1107 1166 11A8;BCA1;1107 1166 11A8; # (벡; 벡; 벡; 벡; 벡; ) HANGUL SYLLABLE BEG +BCA2;BCA2;1107 1166 11A9;BCA2;1107 1166 11A9; # (벢; 벢; 벢; 벢; 벢; ) HANGUL SYLLABLE BEGG +BCA3;BCA3;1107 1166 11AA;BCA3;1107 1166 11AA; # (벣; 벣; 벣; 벣; 벣; ) HANGUL SYLLABLE BEGS +BCA4;BCA4;1107 1166 11AB;BCA4;1107 1166 11AB; # (벤; 벤; 벤; 벤; 벤; ) HANGUL SYLLABLE BEN +BCA5;BCA5;1107 1166 11AC;BCA5;1107 1166 11AC; # (벥; 벥; 벥; 벥; 벥; ) HANGUL SYLLABLE BENJ +BCA6;BCA6;1107 1166 11AD;BCA6;1107 1166 11AD; # (벦; 벦; 벦; 벦; 벦; ) HANGUL SYLLABLE BENH +BCA7;BCA7;1107 1166 11AE;BCA7;1107 1166 11AE; # (벧; 벧; 벧; 벧; 벧; ) HANGUL SYLLABLE BED +BCA8;BCA8;1107 1166 11AF;BCA8;1107 1166 11AF; # (벨; 벨; 벨; 벨; 벨; ) HANGUL SYLLABLE BEL +BCA9;BCA9;1107 1166 11B0;BCA9;1107 1166 11B0; # (벩; 벩; 벩; 벩; 벩; ) HANGUL SYLLABLE BELG +BCAA;BCAA;1107 1166 11B1;BCAA;1107 1166 11B1; # (벪; 벪; 벪; 벪; 벪; ) HANGUL SYLLABLE BELM +BCAB;BCAB;1107 1166 11B2;BCAB;1107 1166 11B2; # (벫; 벫; 벫; 벫; 벫; ) HANGUL SYLLABLE BELB +BCAC;BCAC;1107 1166 11B3;BCAC;1107 1166 11B3; # (벬; 벬; 벬; 벬; 벬; ) HANGUL SYLLABLE BELS +BCAD;BCAD;1107 1166 11B4;BCAD;1107 1166 11B4; # (벭; 벭; 벭; 벭; 벭; ) HANGUL SYLLABLE BELT +BCAE;BCAE;1107 1166 11B5;BCAE;1107 1166 11B5; # (벮; 벮; 벮; 벮; 벮; ) HANGUL SYLLABLE BELP +BCAF;BCAF;1107 1166 11B6;BCAF;1107 1166 11B6; # (벯; 벯; 벯; 벯; 벯; ) HANGUL SYLLABLE BELH +BCB0;BCB0;1107 1166 11B7;BCB0;1107 1166 11B7; # (벰; 벰; 벰; 벰; 벰; ) HANGUL SYLLABLE BEM +BCB1;BCB1;1107 1166 11B8;BCB1;1107 1166 11B8; # (벱; 벱; 벱; 벱; 벱; ) HANGUL SYLLABLE BEB +BCB2;BCB2;1107 1166 11B9;BCB2;1107 1166 11B9; # (벲; 벲; 벲; 벲; 벲; ) HANGUL SYLLABLE BEBS +BCB3;BCB3;1107 1166 11BA;BCB3;1107 1166 11BA; # (벳; 벳; 벳; 벳; 벳; ) HANGUL SYLLABLE BES +BCB4;BCB4;1107 1166 11BB;BCB4;1107 1166 11BB; # (벴; 벴; 벴; 벴; 벴; ) HANGUL SYLLABLE BESS +BCB5;BCB5;1107 1166 11BC;BCB5;1107 1166 11BC; # (벵; 벵; 벵; 벵; 벵; ) HANGUL SYLLABLE BENG +BCB6;BCB6;1107 1166 11BD;BCB6;1107 1166 11BD; # (벶; 벶; 벶; 벶; 벶; ) HANGUL SYLLABLE BEJ +BCB7;BCB7;1107 1166 11BE;BCB7;1107 1166 11BE; # (벷; 벷; 벷; 벷; 벷; ) HANGUL SYLLABLE BEC +BCB8;BCB8;1107 1166 11BF;BCB8;1107 1166 11BF; # (벸; 벸; 벸; 벸; 벸; ) HANGUL SYLLABLE BEK +BCB9;BCB9;1107 1166 11C0;BCB9;1107 1166 11C0; # (벹; 벹; 벹; 벹; 벹; ) HANGUL SYLLABLE BET +BCBA;BCBA;1107 1166 11C1;BCBA;1107 1166 11C1; # (벺; 벺; 벺; 벺; 벺; ) HANGUL SYLLABLE BEP +BCBB;BCBB;1107 1166 11C2;BCBB;1107 1166 11C2; # (벻; 벻; 벻; 벻; 벻; ) HANGUL SYLLABLE BEH +BCBC;BCBC;1107 1167;BCBC;1107 1167; # (벼; 벼; 벼; 벼; 벼; ) HANGUL SYLLABLE BYEO +BCBD;BCBD;1107 1167 11A8;BCBD;1107 1167 11A8; # (벽; 벽; 벽; 벽; 벽; ) HANGUL SYLLABLE BYEOG +BCBE;BCBE;1107 1167 11A9;BCBE;1107 1167 11A9; # (벾; 벾; 벾; 벾; 벾; ) HANGUL SYLLABLE BYEOGG +BCBF;BCBF;1107 1167 11AA;BCBF;1107 1167 11AA; # (벿; 벿; 벿; 벿; 벿; ) HANGUL SYLLABLE BYEOGS +BCC0;BCC0;1107 1167 11AB;BCC0;1107 1167 11AB; # (변; 변; 변; 변; 변; ) HANGUL SYLLABLE BYEON +BCC1;BCC1;1107 1167 11AC;BCC1;1107 1167 11AC; # (볁; 볁; 볁; 볁; 볁; ) HANGUL SYLLABLE BYEONJ +BCC2;BCC2;1107 1167 11AD;BCC2;1107 1167 11AD; # (볂; 볂; 볂; 볂; 볂; ) HANGUL SYLLABLE BYEONH +BCC3;BCC3;1107 1167 11AE;BCC3;1107 1167 11AE; # (볃; 볃; 볃; 볃; 볃; ) HANGUL SYLLABLE BYEOD +BCC4;BCC4;1107 1167 11AF;BCC4;1107 1167 11AF; # (별; 별; 별; 별; 별; ) HANGUL SYLLABLE BYEOL +BCC5;BCC5;1107 1167 11B0;BCC5;1107 1167 11B0; # (볅; 볅; 볅; 볅; 볅; ) HANGUL SYLLABLE BYEOLG +BCC6;BCC6;1107 1167 11B1;BCC6;1107 1167 11B1; # (볆; 볆; 볆; 볆; 볆; ) HANGUL SYLLABLE BYEOLM +BCC7;BCC7;1107 1167 11B2;BCC7;1107 1167 11B2; # (볇; 볇; 볇; 볇; 볇; ) HANGUL SYLLABLE BYEOLB +BCC8;BCC8;1107 1167 11B3;BCC8;1107 1167 11B3; # (볈; 볈; 볈; 볈; 볈; ) HANGUL SYLLABLE BYEOLS +BCC9;BCC9;1107 1167 11B4;BCC9;1107 1167 11B4; # (볉; 볉; 볉; 볉; 볉; ) HANGUL SYLLABLE BYEOLT +BCCA;BCCA;1107 1167 11B5;BCCA;1107 1167 11B5; # (볊; 볊; 볊; 볊; 볊; ) HANGUL SYLLABLE BYEOLP +BCCB;BCCB;1107 1167 11B6;BCCB;1107 1167 11B6; # (볋; 볋; 볋; 볋; 볋; ) HANGUL SYLLABLE BYEOLH +BCCC;BCCC;1107 1167 11B7;BCCC;1107 1167 11B7; # (볌; 볌; 볌; 볌; 볌; ) HANGUL SYLLABLE BYEOM +BCCD;BCCD;1107 1167 11B8;BCCD;1107 1167 11B8; # (볍; 볍; 볍; 볍; 볍; ) HANGUL SYLLABLE BYEOB +BCCE;BCCE;1107 1167 11B9;BCCE;1107 1167 11B9; # (볎; 볎; 볎; 볎; 볎; ) HANGUL SYLLABLE BYEOBS +BCCF;BCCF;1107 1167 11BA;BCCF;1107 1167 11BA; # (볏; 볏; 볏; 볏; 볏; ) HANGUL SYLLABLE BYEOS +BCD0;BCD0;1107 1167 11BB;BCD0;1107 1167 11BB; # (볐; 볐; 볐; 볐; 볐; ) HANGUL SYLLABLE BYEOSS +BCD1;BCD1;1107 1167 11BC;BCD1;1107 1167 11BC; # (병; 병; 병; 병; 병; ) HANGUL SYLLABLE BYEONG +BCD2;BCD2;1107 1167 11BD;BCD2;1107 1167 11BD; # (볒; 볒; 볒; 볒; 볒; ) HANGUL SYLLABLE BYEOJ +BCD3;BCD3;1107 1167 11BE;BCD3;1107 1167 11BE; # (볓; 볓; 볓; 볓; 볓; ) HANGUL SYLLABLE BYEOC +BCD4;BCD4;1107 1167 11BF;BCD4;1107 1167 11BF; # (볔; 볔; 볔; 볔; 볔; ) HANGUL SYLLABLE BYEOK +BCD5;BCD5;1107 1167 11C0;BCD5;1107 1167 11C0; # (볕; 볕; 볕; 볕; 볕; ) HANGUL SYLLABLE BYEOT +BCD6;BCD6;1107 1167 11C1;BCD6;1107 1167 11C1; # (볖; 볖; 볖; 볖; 볖; ) HANGUL SYLLABLE BYEOP +BCD7;BCD7;1107 1167 11C2;BCD7;1107 1167 11C2; # (볗; 볗; 볗; 볗; 볗; ) HANGUL SYLLABLE BYEOH +BCD8;BCD8;1107 1168;BCD8;1107 1168; # (볘; 볘; 볘; 볘; 볘; ) HANGUL SYLLABLE BYE +BCD9;BCD9;1107 1168 11A8;BCD9;1107 1168 11A8; # (볙; 볙; 볙; 볙; 볙; ) HANGUL SYLLABLE BYEG +BCDA;BCDA;1107 1168 11A9;BCDA;1107 1168 11A9; # (볚; 볚; 볚; 볚; 볚; ) HANGUL SYLLABLE BYEGG +BCDB;BCDB;1107 1168 11AA;BCDB;1107 1168 11AA; # (볛; 볛; 볛; 볛; 볛; ) HANGUL SYLLABLE BYEGS +BCDC;BCDC;1107 1168 11AB;BCDC;1107 1168 11AB; # (볜; 볜; 볜; 볜; 볜; ) HANGUL SYLLABLE BYEN +BCDD;BCDD;1107 1168 11AC;BCDD;1107 1168 11AC; # (볝; 볝; 볝; 볝; 볝; ) HANGUL SYLLABLE BYENJ +BCDE;BCDE;1107 1168 11AD;BCDE;1107 1168 11AD; # (볞; 볞; 볞; 볞; 볞; ) HANGUL SYLLABLE BYENH +BCDF;BCDF;1107 1168 11AE;BCDF;1107 1168 11AE; # (볟; 볟; 볟; 볟; 볟; ) HANGUL SYLLABLE BYED +BCE0;BCE0;1107 1168 11AF;BCE0;1107 1168 11AF; # (볠; 볠; 볠; 볠; 볠; ) HANGUL SYLLABLE BYEL +BCE1;BCE1;1107 1168 11B0;BCE1;1107 1168 11B0; # (볡; 볡; 볡; 볡; 볡; ) HANGUL SYLLABLE BYELG +BCE2;BCE2;1107 1168 11B1;BCE2;1107 1168 11B1; # (볢; 볢; 볢; 볢; 볢; ) HANGUL SYLLABLE BYELM +BCE3;BCE3;1107 1168 11B2;BCE3;1107 1168 11B2; # (볣; 볣; 볣; 볣; 볣; ) HANGUL SYLLABLE BYELB +BCE4;BCE4;1107 1168 11B3;BCE4;1107 1168 11B3; # (볤; 볤; 볤; 볤; 볤; ) HANGUL SYLLABLE BYELS +BCE5;BCE5;1107 1168 11B4;BCE5;1107 1168 11B4; # (볥; 볥; 볥; 볥; 볥; ) HANGUL SYLLABLE BYELT +BCE6;BCE6;1107 1168 11B5;BCE6;1107 1168 11B5; # (볦; 볦; 볦; 볦; 볦; ) HANGUL SYLLABLE BYELP +BCE7;BCE7;1107 1168 11B6;BCE7;1107 1168 11B6; # (볧; 볧; 볧; 볧; 볧; ) HANGUL SYLLABLE BYELH +BCE8;BCE8;1107 1168 11B7;BCE8;1107 1168 11B7; # (볨; 볨; 볨; 볨; 볨; ) HANGUL SYLLABLE BYEM +BCE9;BCE9;1107 1168 11B8;BCE9;1107 1168 11B8; # (볩; 볩; 볩; 볩; 볩; ) HANGUL SYLLABLE BYEB +BCEA;BCEA;1107 1168 11B9;BCEA;1107 1168 11B9; # (볪; 볪; 볪; 볪; 볪; ) HANGUL SYLLABLE BYEBS +BCEB;BCEB;1107 1168 11BA;BCEB;1107 1168 11BA; # (볫; 볫; 볫; 볫; 볫; ) HANGUL SYLLABLE BYES +BCEC;BCEC;1107 1168 11BB;BCEC;1107 1168 11BB; # (볬; 볬; 볬; 볬; 볬; ) HANGUL SYLLABLE BYESS +BCED;BCED;1107 1168 11BC;BCED;1107 1168 11BC; # (볭; 볭; 볭; 볭; 볭; ) HANGUL SYLLABLE BYENG +BCEE;BCEE;1107 1168 11BD;BCEE;1107 1168 11BD; # (볮; 볮; 볮; 볮; 볮; ) HANGUL SYLLABLE BYEJ +BCEF;BCEF;1107 1168 11BE;BCEF;1107 1168 11BE; # (볯; 볯; 볯; 볯; 볯; ) HANGUL SYLLABLE BYEC +BCF0;BCF0;1107 1168 11BF;BCF0;1107 1168 11BF; # (볰; 볰; 볰; 볰; 볰; ) HANGUL SYLLABLE BYEK +BCF1;BCF1;1107 1168 11C0;BCF1;1107 1168 11C0; # (볱; 볱; 볱; 볱; 볱; ) HANGUL SYLLABLE BYET +BCF2;BCF2;1107 1168 11C1;BCF2;1107 1168 11C1; # (볲; 볲; 볲; 볲; 볲; ) HANGUL SYLLABLE BYEP +BCF3;BCF3;1107 1168 11C2;BCF3;1107 1168 11C2; # (볳; 볳; 볳; 볳; 볳; ) HANGUL SYLLABLE BYEH +BCF4;BCF4;1107 1169;BCF4;1107 1169; # (보; 보; 보; 보; 보; ) HANGUL SYLLABLE BO +BCF5;BCF5;1107 1169 11A8;BCF5;1107 1169 11A8; # (복; 복; 복; 복; 복; ) HANGUL SYLLABLE BOG +BCF6;BCF6;1107 1169 11A9;BCF6;1107 1169 11A9; # (볶; 볶; 볶; 볶; 볶; ) HANGUL SYLLABLE BOGG +BCF7;BCF7;1107 1169 11AA;BCF7;1107 1169 11AA; # (볷; 볷; 볷; 볷; 볷; ) HANGUL SYLLABLE BOGS +BCF8;BCF8;1107 1169 11AB;BCF8;1107 1169 11AB; # (본; 본; 본; 본; 본; ) HANGUL SYLLABLE BON +BCF9;BCF9;1107 1169 11AC;BCF9;1107 1169 11AC; # (볹; 볹; 볹; 볹; 볹; ) HANGUL SYLLABLE BONJ +BCFA;BCFA;1107 1169 11AD;BCFA;1107 1169 11AD; # (볺; 볺; 볺; 볺; 볺; ) HANGUL SYLLABLE BONH +BCFB;BCFB;1107 1169 11AE;BCFB;1107 1169 11AE; # (볻; 볻; 볻; 볻; 볻; ) HANGUL SYLLABLE BOD +BCFC;BCFC;1107 1169 11AF;BCFC;1107 1169 11AF; # (볼; 볼; 볼; 볼; 볼; ) HANGUL SYLLABLE BOL +BCFD;BCFD;1107 1169 11B0;BCFD;1107 1169 11B0; # (볽; 볽; 볽; 볽; 볽; ) HANGUL SYLLABLE BOLG +BCFE;BCFE;1107 1169 11B1;BCFE;1107 1169 11B1; # (볾; 볾; 볾; 볾; 볾; ) HANGUL SYLLABLE BOLM +BCFF;BCFF;1107 1169 11B2;BCFF;1107 1169 11B2; # (볿; 볿; 볿; 볿; 볿; ) HANGUL SYLLABLE BOLB +BD00;BD00;1107 1169 11B3;BD00;1107 1169 11B3; # (봀; 봀; 봀; 봀; 봀; ) HANGUL SYLLABLE BOLS +BD01;BD01;1107 1169 11B4;BD01;1107 1169 11B4; # (봁; 봁; 봁; 봁; 봁; ) HANGUL SYLLABLE BOLT +BD02;BD02;1107 1169 11B5;BD02;1107 1169 11B5; # (봂; 봂; 봂; 봂; 봂; ) HANGUL SYLLABLE BOLP +BD03;BD03;1107 1169 11B6;BD03;1107 1169 11B6; # (봃; 봃; 봃; 봃; 봃; ) HANGUL SYLLABLE BOLH +BD04;BD04;1107 1169 11B7;BD04;1107 1169 11B7; # (봄; 봄; 봄; 봄; 봄; ) HANGUL SYLLABLE BOM +BD05;BD05;1107 1169 11B8;BD05;1107 1169 11B8; # (봅; 봅; 봅; 봅; 봅; ) HANGUL SYLLABLE BOB +BD06;BD06;1107 1169 11B9;BD06;1107 1169 11B9; # (봆; 봆; 봆; 봆; 봆; ) HANGUL SYLLABLE BOBS +BD07;BD07;1107 1169 11BA;BD07;1107 1169 11BA; # (봇; 봇; 봇; 봇; 봇; ) HANGUL SYLLABLE BOS +BD08;BD08;1107 1169 11BB;BD08;1107 1169 11BB; # (봈; 봈; 봈; 봈; 봈; ) HANGUL SYLLABLE BOSS +BD09;BD09;1107 1169 11BC;BD09;1107 1169 11BC; # (봉; 봉; 봉; 봉; 봉; ) HANGUL SYLLABLE BONG +BD0A;BD0A;1107 1169 11BD;BD0A;1107 1169 11BD; # (봊; 봊; 봊; 봊; 봊; ) HANGUL SYLLABLE BOJ +BD0B;BD0B;1107 1169 11BE;BD0B;1107 1169 11BE; # (봋; 봋; 봋; 봋; 봋; ) HANGUL SYLLABLE BOC +BD0C;BD0C;1107 1169 11BF;BD0C;1107 1169 11BF; # (봌; 봌; 봌; 봌; 봌; ) HANGUL SYLLABLE BOK +BD0D;BD0D;1107 1169 11C0;BD0D;1107 1169 11C0; # (봍; 봍; 봍; 봍; 봍; ) HANGUL SYLLABLE BOT +BD0E;BD0E;1107 1169 11C1;BD0E;1107 1169 11C1; # (봎; 봎; 봎; 봎; 봎; ) HANGUL SYLLABLE BOP +BD0F;BD0F;1107 1169 11C2;BD0F;1107 1169 11C2; # (봏; 봏; 봏; 봏; 봏; ) HANGUL SYLLABLE BOH +BD10;BD10;1107 116A;BD10;1107 116A; # (봐; 봐; 봐; 봐; 봐; ) HANGUL SYLLABLE BWA +BD11;BD11;1107 116A 11A8;BD11;1107 116A 11A8; # (봑; 봑; 봑; 봑; 봑; ) HANGUL SYLLABLE BWAG +BD12;BD12;1107 116A 11A9;BD12;1107 116A 11A9; # (봒; 봒; 봒; 봒; 봒; ) HANGUL SYLLABLE BWAGG +BD13;BD13;1107 116A 11AA;BD13;1107 116A 11AA; # (봓; 봓; 봓; 봓; 봓; ) HANGUL SYLLABLE BWAGS +BD14;BD14;1107 116A 11AB;BD14;1107 116A 11AB; # (봔; 봔; 봔; 봔; 봔; ) HANGUL SYLLABLE BWAN +BD15;BD15;1107 116A 11AC;BD15;1107 116A 11AC; # (봕; 봕; 봕; 봕; 봕; ) HANGUL SYLLABLE BWANJ +BD16;BD16;1107 116A 11AD;BD16;1107 116A 11AD; # (봖; 봖; 봖; 봖; 봖; ) HANGUL SYLLABLE BWANH +BD17;BD17;1107 116A 11AE;BD17;1107 116A 11AE; # (봗; 봗; 봗; 봗; 봗; ) HANGUL SYLLABLE BWAD +BD18;BD18;1107 116A 11AF;BD18;1107 116A 11AF; # (봘; 봘; 봘; 봘; 봘; ) HANGUL SYLLABLE BWAL +BD19;BD19;1107 116A 11B0;BD19;1107 116A 11B0; # (봙; 봙; 봙; 봙; 봙; ) HANGUL SYLLABLE BWALG +BD1A;BD1A;1107 116A 11B1;BD1A;1107 116A 11B1; # (봚; 봚; 봚; 봚; 봚; ) HANGUL SYLLABLE BWALM +BD1B;BD1B;1107 116A 11B2;BD1B;1107 116A 11B2; # (봛; 봛; 봛; 봛; 봛; ) HANGUL SYLLABLE BWALB +BD1C;BD1C;1107 116A 11B3;BD1C;1107 116A 11B3; # (봜; 봜; 봜; 봜; 봜; ) HANGUL SYLLABLE BWALS +BD1D;BD1D;1107 116A 11B4;BD1D;1107 116A 11B4; # (봝; 봝; 봝; 봝; 봝; ) HANGUL SYLLABLE BWALT +BD1E;BD1E;1107 116A 11B5;BD1E;1107 116A 11B5; # (봞; 봞; 봞; 봞; 봞; ) HANGUL SYLLABLE BWALP +BD1F;BD1F;1107 116A 11B6;BD1F;1107 116A 11B6; # (봟; 봟; 봟; 봟; 봟; ) HANGUL SYLLABLE BWALH +BD20;BD20;1107 116A 11B7;BD20;1107 116A 11B7; # (봠; 봠; 봠; 봠; 봠; ) HANGUL SYLLABLE BWAM +BD21;BD21;1107 116A 11B8;BD21;1107 116A 11B8; # (봡; 봡; 봡; 봡; 봡; ) HANGUL SYLLABLE BWAB +BD22;BD22;1107 116A 11B9;BD22;1107 116A 11B9; # (봢; 봢; 봢; 봢; 봢; ) HANGUL SYLLABLE BWABS +BD23;BD23;1107 116A 11BA;BD23;1107 116A 11BA; # (봣; 봣; 봣; 봣; 봣; ) HANGUL SYLLABLE BWAS +BD24;BD24;1107 116A 11BB;BD24;1107 116A 11BB; # (봤; 봤; 봤; 봤; 봤; ) HANGUL SYLLABLE BWASS +BD25;BD25;1107 116A 11BC;BD25;1107 116A 11BC; # (봥; 봥; 봥; 봥; 봥; ) HANGUL SYLLABLE BWANG +BD26;BD26;1107 116A 11BD;BD26;1107 116A 11BD; # (봦; 봦; 봦; 봦; 봦; ) HANGUL SYLLABLE BWAJ +BD27;BD27;1107 116A 11BE;BD27;1107 116A 11BE; # (봧; 봧; 봧; 봧; 봧; ) HANGUL SYLLABLE BWAC +BD28;BD28;1107 116A 11BF;BD28;1107 116A 11BF; # (봨; 봨; 봨; 봨; 봨; ) HANGUL SYLLABLE BWAK +BD29;BD29;1107 116A 11C0;BD29;1107 116A 11C0; # (봩; 봩; 봩; 봩; 봩; ) HANGUL SYLLABLE BWAT +BD2A;BD2A;1107 116A 11C1;BD2A;1107 116A 11C1; # (봪; 봪; 봪; 봪; 봪; ) HANGUL SYLLABLE BWAP +BD2B;BD2B;1107 116A 11C2;BD2B;1107 116A 11C2; # (봫; 봫; 봫; 봫; 봫; ) HANGUL SYLLABLE BWAH +BD2C;BD2C;1107 116B;BD2C;1107 116B; # (봬; 봬; 봬; 봬; 봬; ) HANGUL SYLLABLE BWAE +BD2D;BD2D;1107 116B 11A8;BD2D;1107 116B 11A8; # (봭; 봭; 봭; 봭; 봭; ) HANGUL SYLLABLE BWAEG +BD2E;BD2E;1107 116B 11A9;BD2E;1107 116B 11A9; # (봮; 봮; 봮; 봮; 봮; ) HANGUL SYLLABLE BWAEGG +BD2F;BD2F;1107 116B 11AA;BD2F;1107 116B 11AA; # (봯; 봯; 봯; 봯; 봯; ) HANGUL SYLLABLE BWAEGS +BD30;BD30;1107 116B 11AB;BD30;1107 116B 11AB; # (봰; 봰; 봰; 봰; 봰; ) HANGUL SYLLABLE BWAEN +BD31;BD31;1107 116B 11AC;BD31;1107 116B 11AC; # (봱; 봱; 봱; 봱; 봱; ) HANGUL SYLLABLE BWAENJ +BD32;BD32;1107 116B 11AD;BD32;1107 116B 11AD; # (봲; 봲; 봲; 봲; 봲; ) HANGUL SYLLABLE BWAENH +BD33;BD33;1107 116B 11AE;BD33;1107 116B 11AE; # (봳; 봳; 봳; 봳; 봳; ) HANGUL SYLLABLE BWAED +BD34;BD34;1107 116B 11AF;BD34;1107 116B 11AF; # (봴; 봴; 봴; 봴; 봴; ) HANGUL SYLLABLE BWAEL +BD35;BD35;1107 116B 11B0;BD35;1107 116B 11B0; # (봵; 봵; 봵; 봵; 봵; ) HANGUL SYLLABLE BWAELG +BD36;BD36;1107 116B 11B1;BD36;1107 116B 11B1; # (봶; 봶; 봶; 봶; 봶; ) HANGUL SYLLABLE BWAELM +BD37;BD37;1107 116B 11B2;BD37;1107 116B 11B2; # (봷; 봷; 봷; 봷; 봷; ) HANGUL SYLLABLE BWAELB +BD38;BD38;1107 116B 11B3;BD38;1107 116B 11B3; # (봸; 봸; 봸; 봸; 봸; ) HANGUL SYLLABLE BWAELS +BD39;BD39;1107 116B 11B4;BD39;1107 116B 11B4; # (봹; 봹; 봹; 봹; 봹; ) HANGUL SYLLABLE BWAELT +BD3A;BD3A;1107 116B 11B5;BD3A;1107 116B 11B5; # (봺; 봺; 봺; 봺; 봺; ) HANGUL SYLLABLE BWAELP +BD3B;BD3B;1107 116B 11B6;BD3B;1107 116B 11B6; # (봻; 봻; 봻; 봻; 봻; ) HANGUL SYLLABLE BWAELH +BD3C;BD3C;1107 116B 11B7;BD3C;1107 116B 11B7; # (봼; 봼; 봼; 봼; 봼; ) HANGUL SYLLABLE BWAEM +BD3D;BD3D;1107 116B 11B8;BD3D;1107 116B 11B8; # (봽; 봽; 봽; 봽; 봽; ) HANGUL SYLLABLE BWAEB +BD3E;BD3E;1107 116B 11B9;BD3E;1107 116B 11B9; # (봾; 봾; 봾; 봾; 봾; ) HANGUL SYLLABLE BWAEBS +BD3F;BD3F;1107 116B 11BA;BD3F;1107 116B 11BA; # (봿; 봿; 봿; 봿; 봿; ) HANGUL SYLLABLE BWAES +BD40;BD40;1107 116B 11BB;BD40;1107 116B 11BB; # (뵀; 뵀; 뵀; 뵀; 뵀; ) HANGUL SYLLABLE BWAESS +BD41;BD41;1107 116B 11BC;BD41;1107 116B 11BC; # (뵁; 뵁; 뵁; 뵁; 뵁; ) HANGUL SYLLABLE BWAENG +BD42;BD42;1107 116B 11BD;BD42;1107 116B 11BD; # (뵂; 뵂; 뵂; 뵂; 뵂; ) HANGUL SYLLABLE BWAEJ +BD43;BD43;1107 116B 11BE;BD43;1107 116B 11BE; # (뵃; 뵃; 뵃; 뵃; 뵃; ) HANGUL SYLLABLE BWAEC +BD44;BD44;1107 116B 11BF;BD44;1107 116B 11BF; # (뵄; 뵄; 뵄; 뵄; 뵄; ) HANGUL SYLLABLE BWAEK +BD45;BD45;1107 116B 11C0;BD45;1107 116B 11C0; # (뵅; 뵅; 뵅; 뵅; 뵅; ) HANGUL SYLLABLE BWAET +BD46;BD46;1107 116B 11C1;BD46;1107 116B 11C1; # (뵆; 뵆; 뵆; 뵆; 뵆; ) HANGUL SYLLABLE BWAEP +BD47;BD47;1107 116B 11C2;BD47;1107 116B 11C2; # (뵇; 뵇; 뵇; 뵇; 뵇; ) HANGUL SYLLABLE BWAEH +BD48;BD48;1107 116C;BD48;1107 116C; # (뵈; 뵈; 뵈; 뵈; 뵈; ) HANGUL SYLLABLE BOE +BD49;BD49;1107 116C 11A8;BD49;1107 116C 11A8; # (뵉; 뵉; 뵉; 뵉; 뵉; ) HANGUL SYLLABLE BOEG +BD4A;BD4A;1107 116C 11A9;BD4A;1107 116C 11A9; # (뵊; 뵊; 뵊; 뵊; 뵊; ) HANGUL SYLLABLE BOEGG +BD4B;BD4B;1107 116C 11AA;BD4B;1107 116C 11AA; # (뵋; 뵋; 뵋; 뵋; 뵋; ) HANGUL SYLLABLE BOEGS +BD4C;BD4C;1107 116C 11AB;BD4C;1107 116C 11AB; # (뵌; 뵌; 뵌; 뵌; 뵌; ) HANGUL SYLLABLE BOEN +BD4D;BD4D;1107 116C 11AC;BD4D;1107 116C 11AC; # (뵍; 뵍; 뵍; 뵍; 뵍; ) HANGUL SYLLABLE BOENJ +BD4E;BD4E;1107 116C 11AD;BD4E;1107 116C 11AD; # (뵎; 뵎; 뵎; 뵎; 뵎; ) HANGUL SYLLABLE BOENH +BD4F;BD4F;1107 116C 11AE;BD4F;1107 116C 11AE; # (뵏; 뵏; 뵏; 뵏; 뵏; ) HANGUL SYLLABLE BOED +BD50;BD50;1107 116C 11AF;BD50;1107 116C 11AF; # (뵐; 뵐; 뵐; 뵐; 뵐; ) HANGUL SYLLABLE BOEL +BD51;BD51;1107 116C 11B0;BD51;1107 116C 11B0; # (뵑; 뵑; 뵑; 뵑; 뵑; ) HANGUL SYLLABLE BOELG +BD52;BD52;1107 116C 11B1;BD52;1107 116C 11B1; # (뵒; 뵒; 뵒; 뵒; 뵒; ) HANGUL SYLLABLE BOELM +BD53;BD53;1107 116C 11B2;BD53;1107 116C 11B2; # (뵓; 뵓; 뵓; 뵓; 뵓; ) HANGUL SYLLABLE BOELB +BD54;BD54;1107 116C 11B3;BD54;1107 116C 11B3; # (뵔; 뵔; 뵔; 뵔; 뵔; ) HANGUL SYLLABLE BOELS +BD55;BD55;1107 116C 11B4;BD55;1107 116C 11B4; # (뵕; 뵕; 뵕; 뵕; 뵕; ) HANGUL SYLLABLE BOELT +BD56;BD56;1107 116C 11B5;BD56;1107 116C 11B5; # (뵖; 뵖; 뵖; 뵖; 뵖; ) HANGUL SYLLABLE BOELP +BD57;BD57;1107 116C 11B6;BD57;1107 116C 11B6; # (뵗; 뵗; 뵗; 뵗; 뵗; ) HANGUL SYLLABLE BOELH +BD58;BD58;1107 116C 11B7;BD58;1107 116C 11B7; # (뵘; 뵘; 뵘; 뵘; 뵘; ) HANGUL SYLLABLE BOEM +BD59;BD59;1107 116C 11B8;BD59;1107 116C 11B8; # (뵙; 뵙; 뵙; 뵙; 뵙; ) HANGUL SYLLABLE BOEB +BD5A;BD5A;1107 116C 11B9;BD5A;1107 116C 11B9; # (뵚; 뵚; 뵚; 뵚; 뵚; ) HANGUL SYLLABLE BOEBS +BD5B;BD5B;1107 116C 11BA;BD5B;1107 116C 11BA; # (뵛; 뵛; 뵛; 뵛; 뵛; ) HANGUL SYLLABLE BOES +BD5C;BD5C;1107 116C 11BB;BD5C;1107 116C 11BB; # (뵜; 뵜; 뵜; 뵜; 뵜; ) HANGUL SYLLABLE BOESS +BD5D;BD5D;1107 116C 11BC;BD5D;1107 116C 11BC; # (뵝; 뵝; 뵝; 뵝; 뵝; ) HANGUL SYLLABLE BOENG +BD5E;BD5E;1107 116C 11BD;BD5E;1107 116C 11BD; # (뵞; 뵞; 뵞; 뵞; 뵞; ) HANGUL SYLLABLE BOEJ +BD5F;BD5F;1107 116C 11BE;BD5F;1107 116C 11BE; # (뵟; 뵟; 뵟; 뵟; 뵟; ) HANGUL SYLLABLE BOEC +BD60;BD60;1107 116C 11BF;BD60;1107 116C 11BF; # (뵠; 뵠; 뵠; 뵠; 뵠; ) HANGUL SYLLABLE BOEK +BD61;BD61;1107 116C 11C0;BD61;1107 116C 11C0; # (뵡; 뵡; 뵡; 뵡; 뵡; ) HANGUL SYLLABLE BOET +BD62;BD62;1107 116C 11C1;BD62;1107 116C 11C1; # (뵢; 뵢; 뵢; 뵢; 뵢; ) HANGUL SYLLABLE BOEP +BD63;BD63;1107 116C 11C2;BD63;1107 116C 11C2; # (뵣; 뵣; 뵣; 뵣; 뵣; ) HANGUL SYLLABLE BOEH +BD64;BD64;1107 116D;BD64;1107 116D; # (뵤; 뵤; 뵤; 뵤; 뵤; ) HANGUL SYLLABLE BYO +BD65;BD65;1107 116D 11A8;BD65;1107 116D 11A8; # (뵥; 뵥; 뵥; 뵥; 뵥; ) HANGUL SYLLABLE BYOG +BD66;BD66;1107 116D 11A9;BD66;1107 116D 11A9; # (뵦; 뵦; 뵦; 뵦; 뵦; ) HANGUL SYLLABLE BYOGG +BD67;BD67;1107 116D 11AA;BD67;1107 116D 11AA; # (뵧; 뵧; 뵧; 뵧; 뵧; ) HANGUL SYLLABLE BYOGS +BD68;BD68;1107 116D 11AB;BD68;1107 116D 11AB; # (뵨; 뵨; 뵨; 뵨; 뵨; ) HANGUL SYLLABLE BYON +BD69;BD69;1107 116D 11AC;BD69;1107 116D 11AC; # (뵩; 뵩; 뵩; 뵩; 뵩; ) HANGUL SYLLABLE BYONJ +BD6A;BD6A;1107 116D 11AD;BD6A;1107 116D 11AD; # (뵪; 뵪; 뵪; 뵪; 뵪; ) HANGUL SYLLABLE BYONH +BD6B;BD6B;1107 116D 11AE;BD6B;1107 116D 11AE; # (뵫; 뵫; 뵫; 뵫; 뵫; ) HANGUL SYLLABLE BYOD +BD6C;BD6C;1107 116D 11AF;BD6C;1107 116D 11AF; # (뵬; 뵬; 뵬; 뵬; 뵬; ) HANGUL SYLLABLE BYOL +BD6D;BD6D;1107 116D 11B0;BD6D;1107 116D 11B0; # (뵭; 뵭; 뵭; 뵭; 뵭; ) HANGUL SYLLABLE BYOLG +BD6E;BD6E;1107 116D 11B1;BD6E;1107 116D 11B1; # (뵮; 뵮; 뵮; 뵮; 뵮; ) HANGUL SYLLABLE BYOLM +BD6F;BD6F;1107 116D 11B2;BD6F;1107 116D 11B2; # (뵯; 뵯; 뵯; 뵯; 뵯; ) HANGUL SYLLABLE BYOLB +BD70;BD70;1107 116D 11B3;BD70;1107 116D 11B3; # (뵰; 뵰; 뵰; 뵰; 뵰; ) HANGUL SYLLABLE BYOLS +BD71;BD71;1107 116D 11B4;BD71;1107 116D 11B4; # (뵱; 뵱; 뵱; 뵱; 뵱; ) HANGUL SYLLABLE BYOLT +BD72;BD72;1107 116D 11B5;BD72;1107 116D 11B5; # (뵲; 뵲; 뵲; 뵲; 뵲; ) HANGUL SYLLABLE BYOLP +BD73;BD73;1107 116D 11B6;BD73;1107 116D 11B6; # (뵳; 뵳; 뵳; 뵳; 뵳; ) HANGUL SYLLABLE BYOLH +BD74;BD74;1107 116D 11B7;BD74;1107 116D 11B7; # (뵴; 뵴; 뵴; 뵴; 뵴; ) HANGUL SYLLABLE BYOM +BD75;BD75;1107 116D 11B8;BD75;1107 116D 11B8; # (뵵; 뵵; 뵵; 뵵; 뵵; ) HANGUL SYLLABLE BYOB +BD76;BD76;1107 116D 11B9;BD76;1107 116D 11B9; # (뵶; 뵶; 뵶; 뵶; 뵶; ) HANGUL SYLLABLE BYOBS +BD77;BD77;1107 116D 11BA;BD77;1107 116D 11BA; # (뵷; 뵷; 뵷; 뵷; 뵷; ) HANGUL SYLLABLE BYOS +BD78;BD78;1107 116D 11BB;BD78;1107 116D 11BB; # (뵸; 뵸; 뵸; 뵸; 뵸; ) HANGUL SYLLABLE BYOSS +BD79;BD79;1107 116D 11BC;BD79;1107 116D 11BC; # (뵹; 뵹; 뵹; 뵹; 뵹; ) HANGUL SYLLABLE BYONG +BD7A;BD7A;1107 116D 11BD;BD7A;1107 116D 11BD; # (뵺; 뵺; 뵺; 뵺; 뵺; ) HANGUL SYLLABLE BYOJ +BD7B;BD7B;1107 116D 11BE;BD7B;1107 116D 11BE; # (뵻; 뵻; 뵻; 뵻; 뵻; ) HANGUL SYLLABLE BYOC +BD7C;BD7C;1107 116D 11BF;BD7C;1107 116D 11BF; # (뵼; 뵼; 뵼; 뵼; 뵼; ) HANGUL SYLLABLE BYOK +BD7D;BD7D;1107 116D 11C0;BD7D;1107 116D 11C0; # (뵽; 뵽; 뵽; 뵽; 뵽; ) HANGUL SYLLABLE BYOT +BD7E;BD7E;1107 116D 11C1;BD7E;1107 116D 11C1; # (뵾; 뵾; 뵾; 뵾; 뵾; ) HANGUL SYLLABLE BYOP +BD7F;BD7F;1107 116D 11C2;BD7F;1107 116D 11C2; # (뵿; 뵿; 뵿; 뵿; 뵿; ) HANGUL SYLLABLE BYOH +BD80;BD80;1107 116E;BD80;1107 116E; # (부; 부; 부; 부; 부; ) HANGUL SYLLABLE BU +BD81;BD81;1107 116E 11A8;BD81;1107 116E 11A8; # (북; 북; 북; 북; 북; ) HANGUL SYLLABLE BUG +BD82;BD82;1107 116E 11A9;BD82;1107 116E 11A9; # (붂; 붂; 붂; 붂; 붂; ) HANGUL SYLLABLE BUGG +BD83;BD83;1107 116E 11AA;BD83;1107 116E 11AA; # (붃; 붃; 붃; 붃; 붃; ) HANGUL SYLLABLE BUGS +BD84;BD84;1107 116E 11AB;BD84;1107 116E 11AB; # (분; 분; 분; 분; 분; ) HANGUL SYLLABLE BUN +BD85;BD85;1107 116E 11AC;BD85;1107 116E 11AC; # (붅; 붅; 붅; 붅; 붅; ) HANGUL SYLLABLE BUNJ +BD86;BD86;1107 116E 11AD;BD86;1107 116E 11AD; # (붆; 붆; 붆; 붆; 붆; ) HANGUL SYLLABLE BUNH +BD87;BD87;1107 116E 11AE;BD87;1107 116E 11AE; # (붇; 붇; 붇; 붇; 붇; ) HANGUL SYLLABLE BUD +BD88;BD88;1107 116E 11AF;BD88;1107 116E 11AF; # (불; 불; 불; 불; 불; ) HANGUL SYLLABLE BUL +BD89;BD89;1107 116E 11B0;BD89;1107 116E 11B0; # (붉; 붉; 붉; 붉; 붉; ) HANGUL SYLLABLE BULG +BD8A;BD8A;1107 116E 11B1;BD8A;1107 116E 11B1; # (붊; 붊; 붊; 붊; 붊; ) HANGUL SYLLABLE BULM +BD8B;BD8B;1107 116E 11B2;BD8B;1107 116E 11B2; # (붋; 붋; 붋; 붋; 붋; ) HANGUL SYLLABLE BULB +BD8C;BD8C;1107 116E 11B3;BD8C;1107 116E 11B3; # (붌; 붌; 붌; 붌; 붌; ) HANGUL SYLLABLE BULS +BD8D;BD8D;1107 116E 11B4;BD8D;1107 116E 11B4; # (붍; 붍; 붍; 붍; 붍; ) HANGUL SYLLABLE BULT +BD8E;BD8E;1107 116E 11B5;BD8E;1107 116E 11B5; # (붎; 붎; 붎; 붎; 붎; ) HANGUL SYLLABLE BULP +BD8F;BD8F;1107 116E 11B6;BD8F;1107 116E 11B6; # (붏; 붏; 붏; 붏; 붏; ) HANGUL SYLLABLE BULH +BD90;BD90;1107 116E 11B7;BD90;1107 116E 11B7; # (붐; 붐; 붐; 붐; 붐; ) HANGUL SYLLABLE BUM +BD91;BD91;1107 116E 11B8;BD91;1107 116E 11B8; # (붑; 붑; 붑; 붑; 붑; ) HANGUL SYLLABLE BUB +BD92;BD92;1107 116E 11B9;BD92;1107 116E 11B9; # (붒; 붒; 붒; 붒; 붒; ) HANGUL SYLLABLE BUBS +BD93;BD93;1107 116E 11BA;BD93;1107 116E 11BA; # (붓; 붓; 붓; 붓; 붓; ) HANGUL SYLLABLE BUS +BD94;BD94;1107 116E 11BB;BD94;1107 116E 11BB; # (붔; 붔; 붔; 붔; 붔; ) HANGUL SYLLABLE BUSS +BD95;BD95;1107 116E 11BC;BD95;1107 116E 11BC; # (붕; 붕; 붕; 붕; 붕; ) HANGUL SYLLABLE BUNG +BD96;BD96;1107 116E 11BD;BD96;1107 116E 11BD; # (붖; 붖; 붖; 붖; 붖; ) HANGUL SYLLABLE BUJ +BD97;BD97;1107 116E 11BE;BD97;1107 116E 11BE; # (붗; 붗; 붗; 붗; 붗; ) HANGUL SYLLABLE BUC +BD98;BD98;1107 116E 11BF;BD98;1107 116E 11BF; # (붘; 붘; 붘; 붘; 붘; ) HANGUL SYLLABLE BUK +BD99;BD99;1107 116E 11C0;BD99;1107 116E 11C0; # (붙; 붙; 붙; 붙; 붙; ) HANGUL SYLLABLE BUT +BD9A;BD9A;1107 116E 11C1;BD9A;1107 116E 11C1; # (붚; 붚; 붚; 붚; 붚; ) HANGUL SYLLABLE BUP +BD9B;BD9B;1107 116E 11C2;BD9B;1107 116E 11C2; # (붛; 붛; 붛; 붛; 붛; ) HANGUL SYLLABLE BUH +BD9C;BD9C;1107 116F;BD9C;1107 116F; # (붜; 붜; 붜; 붜; 붜; ) HANGUL SYLLABLE BWEO +BD9D;BD9D;1107 116F 11A8;BD9D;1107 116F 11A8; # (붝; 붝; 붝; 붝; 붝; ) HANGUL SYLLABLE BWEOG +BD9E;BD9E;1107 116F 11A9;BD9E;1107 116F 11A9; # (붞; 붞; 붞; 붞; 붞; ) HANGUL SYLLABLE BWEOGG +BD9F;BD9F;1107 116F 11AA;BD9F;1107 116F 11AA; # (붟; 붟; 붟; 붟; 붟; ) HANGUL SYLLABLE BWEOGS +BDA0;BDA0;1107 116F 11AB;BDA0;1107 116F 11AB; # (붠; 붠; 붠; 붠; 붠; ) HANGUL SYLLABLE BWEON +BDA1;BDA1;1107 116F 11AC;BDA1;1107 116F 11AC; # (붡; 붡; 붡; 붡; 붡; ) HANGUL SYLLABLE BWEONJ +BDA2;BDA2;1107 116F 11AD;BDA2;1107 116F 11AD; # (붢; 붢; 붢; 붢; 붢; ) HANGUL SYLLABLE BWEONH +BDA3;BDA3;1107 116F 11AE;BDA3;1107 116F 11AE; # (붣; 붣; 붣; 붣; 붣; ) HANGUL SYLLABLE BWEOD +BDA4;BDA4;1107 116F 11AF;BDA4;1107 116F 11AF; # (붤; 붤; 붤; 붤; 붤; ) HANGUL SYLLABLE BWEOL +BDA5;BDA5;1107 116F 11B0;BDA5;1107 116F 11B0; # (붥; 붥; 붥; 붥; 붥; ) HANGUL SYLLABLE BWEOLG +BDA6;BDA6;1107 116F 11B1;BDA6;1107 116F 11B1; # (붦; 붦; 붦; 붦; 붦; ) HANGUL SYLLABLE BWEOLM +BDA7;BDA7;1107 116F 11B2;BDA7;1107 116F 11B2; # (붧; 붧; 붧; 붧; 붧; ) HANGUL SYLLABLE BWEOLB +BDA8;BDA8;1107 116F 11B3;BDA8;1107 116F 11B3; # (붨; 붨; 붨; 붨; 붨; ) HANGUL SYLLABLE BWEOLS +BDA9;BDA9;1107 116F 11B4;BDA9;1107 116F 11B4; # (붩; 붩; 붩; 붩; 붩; ) HANGUL SYLLABLE BWEOLT +BDAA;BDAA;1107 116F 11B5;BDAA;1107 116F 11B5; # (붪; 붪; 붪; 붪; 붪; ) HANGUL SYLLABLE BWEOLP +BDAB;BDAB;1107 116F 11B6;BDAB;1107 116F 11B6; # (붫; 붫; 붫; 붫; 붫; ) HANGUL SYLLABLE BWEOLH +BDAC;BDAC;1107 116F 11B7;BDAC;1107 116F 11B7; # (붬; 붬; 붬; 붬; 붬; ) HANGUL SYLLABLE BWEOM +BDAD;BDAD;1107 116F 11B8;BDAD;1107 116F 11B8; # (붭; 붭; 붭; 붭; 붭; ) HANGUL SYLLABLE BWEOB +BDAE;BDAE;1107 116F 11B9;BDAE;1107 116F 11B9; # (붮; 붮; 붮; 붮; 붮; ) HANGUL SYLLABLE BWEOBS +BDAF;BDAF;1107 116F 11BA;BDAF;1107 116F 11BA; # (붯; 붯; 붯; 붯; 붯; ) HANGUL SYLLABLE BWEOS +BDB0;BDB0;1107 116F 11BB;BDB0;1107 116F 11BB; # (붰; 붰; 붰; 붰; 붰; ) HANGUL SYLLABLE BWEOSS +BDB1;BDB1;1107 116F 11BC;BDB1;1107 116F 11BC; # (붱; 붱; 붱; 붱; 붱; ) HANGUL SYLLABLE BWEONG +BDB2;BDB2;1107 116F 11BD;BDB2;1107 116F 11BD; # (붲; 붲; 붲; 붲; 붲; ) HANGUL SYLLABLE BWEOJ +BDB3;BDB3;1107 116F 11BE;BDB3;1107 116F 11BE; # (붳; 붳; 붳; 붳; 붳; ) HANGUL SYLLABLE BWEOC +BDB4;BDB4;1107 116F 11BF;BDB4;1107 116F 11BF; # (붴; 붴; 붴; 붴; 붴; ) HANGUL SYLLABLE BWEOK +BDB5;BDB5;1107 116F 11C0;BDB5;1107 116F 11C0; # (붵; 붵; 붵; 붵; 붵; ) HANGUL SYLLABLE BWEOT +BDB6;BDB6;1107 116F 11C1;BDB6;1107 116F 11C1; # (붶; 붶; 붶; 붶; 붶; ) HANGUL SYLLABLE BWEOP +BDB7;BDB7;1107 116F 11C2;BDB7;1107 116F 11C2; # (붷; 붷; 붷; 붷; 붷; ) HANGUL SYLLABLE BWEOH +BDB8;BDB8;1107 1170;BDB8;1107 1170; # (붸; 붸; 붸; 붸; 붸; ) HANGUL SYLLABLE BWE +BDB9;BDB9;1107 1170 11A8;BDB9;1107 1170 11A8; # (붹; 붹; 붹; 붹; 붹; ) HANGUL SYLLABLE BWEG +BDBA;BDBA;1107 1170 11A9;BDBA;1107 1170 11A9; # (붺; 붺; 붺; 붺; 붺; ) HANGUL SYLLABLE BWEGG +BDBB;BDBB;1107 1170 11AA;BDBB;1107 1170 11AA; # (붻; 붻; 붻; 붻; 붻; ) HANGUL SYLLABLE BWEGS +BDBC;BDBC;1107 1170 11AB;BDBC;1107 1170 11AB; # (붼; 붼; 붼; 붼; 붼; ) HANGUL SYLLABLE BWEN +BDBD;BDBD;1107 1170 11AC;BDBD;1107 1170 11AC; # (붽; 붽; 붽; 붽; 붽; ) HANGUL SYLLABLE BWENJ +BDBE;BDBE;1107 1170 11AD;BDBE;1107 1170 11AD; # (붾; 붾; 붾; 붾; 붾; ) HANGUL SYLLABLE BWENH +BDBF;BDBF;1107 1170 11AE;BDBF;1107 1170 11AE; # (붿; 붿; 붿; 붿; 붿; ) HANGUL SYLLABLE BWED +BDC0;BDC0;1107 1170 11AF;BDC0;1107 1170 11AF; # (뷀; 뷀; 뷀; 뷀; 뷀; ) HANGUL SYLLABLE BWEL +BDC1;BDC1;1107 1170 11B0;BDC1;1107 1170 11B0; # (뷁; 뷁; 뷁; 뷁; 뷁; ) HANGUL SYLLABLE BWELG +BDC2;BDC2;1107 1170 11B1;BDC2;1107 1170 11B1; # (뷂; 뷂; 뷂; 뷂; 뷂; ) HANGUL SYLLABLE BWELM +BDC3;BDC3;1107 1170 11B2;BDC3;1107 1170 11B2; # (뷃; 뷃; 뷃; 뷃; 뷃; ) HANGUL SYLLABLE BWELB +BDC4;BDC4;1107 1170 11B3;BDC4;1107 1170 11B3; # (뷄; 뷄; 뷄; 뷄; 뷄; ) HANGUL SYLLABLE BWELS +BDC5;BDC5;1107 1170 11B4;BDC5;1107 1170 11B4; # (뷅; 뷅; 뷅; 뷅; 뷅; ) HANGUL SYLLABLE BWELT +BDC6;BDC6;1107 1170 11B5;BDC6;1107 1170 11B5; # (뷆; 뷆; 뷆; 뷆; 뷆; ) HANGUL SYLLABLE BWELP +BDC7;BDC7;1107 1170 11B6;BDC7;1107 1170 11B6; # (뷇; 뷇; 뷇; 뷇; 뷇; ) HANGUL SYLLABLE BWELH +BDC8;BDC8;1107 1170 11B7;BDC8;1107 1170 11B7; # (뷈; 뷈; 뷈; 뷈; 뷈; ) HANGUL SYLLABLE BWEM +BDC9;BDC9;1107 1170 11B8;BDC9;1107 1170 11B8; # (뷉; 뷉; 뷉; 뷉; 뷉; ) HANGUL SYLLABLE BWEB +BDCA;BDCA;1107 1170 11B9;BDCA;1107 1170 11B9; # (뷊; 뷊; 뷊; 뷊; 뷊; ) HANGUL SYLLABLE BWEBS +BDCB;BDCB;1107 1170 11BA;BDCB;1107 1170 11BA; # (뷋; 뷋; 뷋; 뷋; 뷋; ) HANGUL SYLLABLE BWES +BDCC;BDCC;1107 1170 11BB;BDCC;1107 1170 11BB; # (뷌; 뷌; 뷌; 뷌; 뷌; ) HANGUL SYLLABLE BWESS +BDCD;BDCD;1107 1170 11BC;BDCD;1107 1170 11BC; # (뷍; 뷍; 뷍; 뷍; 뷍; ) HANGUL SYLLABLE BWENG +BDCE;BDCE;1107 1170 11BD;BDCE;1107 1170 11BD; # (뷎; 뷎; 뷎; 뷎; 뷎; ) HANGUL SYLLABLE BWEJ +BDCF;BDCF;1107 1170 11BE;BDCF;1107 1170 11BE; # (뷏; 뷏; 뷏; 뷏; 뷏; ) HANGUL SYLLABLE BWEC +BDD0;BDD0;1107 1170 11BF;BDD0;1107 1170 11BF; # (뷐; 뷐; 뷐; 뷐; 뷐; ) HANGUL SYLLABLE BWEK +BDD1;BDD1;1107 1170 11C0;BDD1;1107 1170 11C0; # (뷑; 뷑; 뷑; 뷑; 뷑; ) HANGUL SYLLABLE BWET +BDD2;BDD2;1107 1170 11C1;BDD2;1107 1170 11C1; # (뷒; 뷒; 뷒; 뷒; 뷒; ) HANGUL SYLLABLE BWEP +BDD3;BDD3;1107 1170 11C2;BDD3;1107 1170 11C2; # (뷓; 뷓; 뷓; 뷓; 뷓; ) HANGUL SYLLABLE BWEH +BDD4;BDD4;1107 1171;BDD4;1107 1171; # (뷔; 뷔; 뷔; 뷔; 뷔; ) HANGUL SYLLABLE BWI +BDD5;BDD5;1107 1171 11A8;BDD5;1107 1171 11A8; # (뷕; 뷕; 뷕; 뷕; 뷕; ) HANGUL SYLLABLE BWIG +BDD6;BDD6;1107 1171 11A9;BDD6;1107 1171 11A9; # (뷖; 뷖; 뷖; 뷖; 뷖; ) HANGUL SYLLABLE BWIGG +BDD7;BDD7;1107 1171 11AA;BDD7;1107 1171 11AA; # (뷗; 뷗; 뷗; 뷗; 뷗; ) HANGUL SYLLABLE BWIGS +BDD8;BDD8;1107 1171 11AB;BDD8;1107 1171 11AB; # (뷘; 뷘; 뷘; 뷘; 뷘; ) HANGUL SYLLABLE BWIN +BDD9;BDD9;1107 1171 11AC;BDD9;1107 1171 11AC; # (뷙; 뷙; 뷙; 뷙; 뷙; ) HANGUL SYLLABLE BWINJ +BDDA;BDDA;1107 1171 11AD;BDDA;1107 1171 11AD; # (뷚; 뷚; 뷚; 뷚; 뷚; ) HANGUL SYLLABLE BWINH +BDDB;BDDB;1107 1171 11AE;BDDB;1107 1171 11AE; # (뷛; 뷛; 뷛; 뷛; 뷛; ) HANGUL SYLLABLE BWID +BDDC;BDDC;1107 1171 11AF;BDDC;1107 1171 11AF; # (뷜; 뷜; 뷜; 뷜; 뷜; ) HANGUL SYLLABLE BWIL +BDDD;BDDD;1107 1171 11B0;BDDD;1107 1171 11B0; # (뷝; 뷝; 뷝; 뷝; 뷝; ) HANGUL SYLLABLE BWILG +BDDE;BDDE;1107 1171 11B1;BDDE;1107 1171 11B1; # (뷞; 뷞; 뷞; 뷞; 뷞; ) HANGUL SYLLABLE BWILM +BDDF;BDDF;1107 1171 11B2;BDDF;1107 1171 11B2; # (뷟; 뷟; 뷟; 뷟; 뷟; ) HANGUL SYLLABLE BWILB +BDE0;BDE0;1107 1171 11B3;BDE0;1107 1171 11B3; # (뷠; 뷠; 뷠; 뷠; 뷠; ) HANGUL SYLLABLE BWILS +BDE1;BDE1;1107 1171 11B4;BDE1;1107 1171 11B4; # (뷡; 뷡; 뷡; 뷡; 뷡; ) HANGUL SYLLABLE BWILT +BDE2;BDE2;1107 1171 11B5;BDE2;1107 1171 11B5; # (뷢; 뷢; 뷢; 뷢; 뷢; ) HANGUL SYLLABLE BWILP +BDE3;BDE3;1107 1171 11B6;BDE3;1107 1171 11B6; # (뷣; 뷣; 뷣; 뷣; 뷣; ) HANGUL SYLLABLE BWILH +BDE4;BDE4;1107 1171 11B7;BDE4;1107 1171 11B7; # (뷤; 뷤; 뷤; 뷤; 뷤; ) HANGUL SYLLABLE BWIM +BDE5;BDE5;1107 1171 11B8;BDE5;1107 1171 11B8; # (뷥; 뷥; 뷥; 뷥; 뷥; ) HANGUL SYLLABLE BWIB +BDE6;BDE6;1107 1171 11B9;BDE6;1107 1171 11B9; # (뷦; 뷦; 뷦; 뷦; 뷦; ) HANGUL SYLLABLE BWIBS +BDE7;BDE7;1107 1171 11BA;BDE7;1107 1171 11BA; # (뷧; 뷧; 뷧; 뷧; 뷧; ) HANGUL SYLLABLE BWIS +BDE8;BDE8;1107 1171 11BB;BDE8;1107 1171 11BB; # (뷨; 뷨; 뷨; 뷨; 뷨; ) HANGUL SYLLABLE BWISS +BDE9;BDE9;1107 1171 11BC;BDE9;1107 1171 11BC; # (뷩; 뷩; 뷩; 뷩; 뷩; ) HANGUL SYLLABLE BWING +BDEA;BDEA;1107 1171 11BD;BDEA;1107 1171 11BD; # (뷪; 뷪; 뷪; 뷪; 뷪; ) HANGUL SYLLABLE BWIJ +BDEB;BDEB;1107 1171 11BE;BDEB;1107 1171 11BE; # (뷫; 뷫; 뷫; 뷫; 뷫; ) HANGUL SYLLABLE BWIC +BDEC;BDEC;1107 1171 11BF;BDEC;1107 1171 11BF; # (뷬; 뷬; 뷬; 뷬; 뷬; ) HANGUL SYLLABLE BWIK +BDED;BDED;1107 1171 11C0;BDED;1107 1171 11C0; # (뷭; 뷭; 뷭; 뷭; 뷭; ) HANGUL SYLLABLE BWIT +BDEE;BDEE;1107 1171 11C1;BDEE;1107 1171 11C1; # (뷮; 뷮; 뷮; 뷮; 뷮; ) HANGUL SYLLABLE BWIP +BDEF;BDEF;1107 1171 11C2;BDEF;1107 1171 11C2; # (뷯; 뷯; 뷯; 뷯; 뷯; ) HANGUL SYLLABLE BWIH +BDF0;BDF0;1107 1172;BDF0;1107 1172; # (뷰; 뷰; 뷰; 뷰; 뷰; ) HANGUL SYLLABLE BYU +BDF1;BDF1;1107 1172 11A8;BDF1;1107 1172 11A8; # (뷱; 뷱; 뷱; 뷱; 뷱; ) HANGUL SYLLABLE BYUG +BDF2;BDF2;1107 1172 11A9;BDF2;1107 1172 11A9; # (뷲; 뷲; 뷲; 뷲; 뷲; ) HANGUL SYLLABLE BYUGG +BDF3;BDF3;1107 1172 11AA;BDF3;1107 1172 11AA; # (뷳; 뷳; 뷳; 뷳; 뷳; ) HANGUL SYLLABLE BYUGS +BDF4;BDF4;1107 1172 11AB;BDF4;1107 1172 11AB; # (뷴; 뷴; 뷴; 뷴; 뷴; ) HANGUL SYLLABLE BYUN +BDF5;BDF5;1107 1172 11AC;BDF5;1107 1172 11AC; # (뷵; 뷵; 뷵; 뷵; 뷵; ) HANGUL SYLLABLE BYUNJ +BDF6;BDF6;1107 1172 11AD;BDF6;1107 1172 11AD; # (뷶; 뷶; 뷶; 뷶; 뷶; ) HANGUL SYLLABLE BYUNH +BDF7;BDF7;1107 1172 11AE;BDF7;1107 1172 11AE; # (뷷; 뷷; 뷷; 뷷; 뷷; ) HANGUL SYLLABLE BYUD +BDF8;BDF8;1107 1172 11AF;BDF8;1107 1172 11AF; # (뷸; 뷸; 뷸; 뷸; 뷸; ) HANGUL SYLLABLE BYUL +BDF9;BDF9;1107 1172 11B0;BDF9;1107 1172 11B0; # (뷹; 뷹; 뷹; 뷹; 뷹; ) HANGUL SYLLABLE BYULG +BDFA;BDFA;1107 1172 11B1;BDFA;1107 1172 11B1; # (뷺; 뷺; 뷺; 뷺; 뷺; ) HANGUL SYLLABLE BYULM +BDFB;BDFB;1107 1172 11B2;BDFB;1107 1172 11B2; # (뷻; 뷻; 뷻; 뷻; 뷻; ) HANGUL SYLLABLE BYULB +BDFC;BDFC;1107 1172 11B3;BDFC;1107 1172 11B3; # (뷼; 뷼; 뷼; 뷼; 뷼; ) HANGUL SYLLABLE BYULS +BDFD;BDFD;1107 1172 11B4;BDFD;1107 1172 11B4; # (뷽; 뷽; 뷽; 뷽; 뷽; ) HANGUL SYLLABLE BYULT +BDFE;BDFE;1107 1172 11B5;BDFE;1107 1172 11B5; # (뷾; 뷾; 뷾; 뷾; 뷾; ) HANGUL SYLLABLE BYULP +BDFF;BDFF;1107 1172 11B6;BDFF;1107 1172 11B6; # (뷿; 뷿; 뷿; 뷿; 뷿; ) HANGUL SYLLABLE BYULH +BE00;BE00;1107 1172 11B7;BE00;1107 1172 11B7; # (븀; 븀; 븀; 븀; 븀; ) HANGUL SYLLABLE BYUM +BE01;BE01;1107 1172 11B8;BE01;1107 1172 11B8; # (븁; 븁; 븁; 븁; 븁; ) HANGUL SYLLABLE BYUB +BE02;BE02;1107 1172 11B9;BE02;1107 1172 11B9; # (븂; 븂; 븂; 븂; 븂; ) HANGUL SYLLABLE BYUBS +BE03;BE03;1107 1172 11BA;BE03;1107 1172 11BA; # (븃; 븃; 븃; 븃; 븃; ) HANGUL SYLLABLE BYUS +BE04;BE04;1107 1172 11BB;BE04;1107 1172 11BB; # (븄; 븄; 븄; 븄; 븄; ) HANGUL SYLLABLE BYUSS +BE05;BE05;1107 1172 11BC;BE05;1107 1172 11BC; # (븅; 븅; 븅; 븅; 븅; ) HANGUL SYLLABLE BYUNG +BE06;BE06;1107 1172 11BD;BE06;1107 1172 11BD; # (븆; 븆; 븆; 븆; 븆; ) HANGUL SYLLABLE BYUJ +BE07;BE07;1107 1172 11BE;BE07;1107 1172 11BE; # (븇; 븇; 븇; 븇; 븇; ) HANGUL SYLLABLE BYUC +BE08;BE08;1107 1172 11BF;BE08;1107 1172 11BF; # (븈; 븈; 븈; 븈; 븈; ) HANGUL SYLLABLE BYUK +BE09;BE09;1107 1172 11C0;BE09;1107 1172 11C0; # (븉; 븉; 븉; 븉; 븉; ) HANGUL SYLLABLE BYUT +BE0A;BE0A;1107 1172 11C1;BE0A;1107 1172 11C1; # (븊; 븊; 븊; 븊; 븊; ) HANGUL SYLLABLE BYUP +BE0B;BE0B;1107 1172 11C2;BE0B;1107 1172 11C2; # (븋; 븋; 븋; 븋; 븋; ) HANGUL SYLLABLE BYUH +BE0C;BE0C;1107 1173;BE0C;1107 1173; # (브; 브; 브; 브; 브; ) HANGUL SYLLABLE BEU +BE0D;BE0D;1107 1173 11A8;BE0D;1107 1173 11A8; # (븍; 븍; 븍; 븍; 븍; ) HANGUL SYLLABLE BEUG +BE0E;BE0E;1107 1173 11A9;BE0E;1107 1173 11A9; # (븎; 븎; 븎; 븎; 븎; ) HANGUL SYLLABLE BEUGG +BE0F;BE0F;1107 1173 11AA;BE0F;1107 1173 11AA; # (븏; 븏; 븏; 븏; 븏; ) HANGUL SYLLABLE BEUGS +BE10;BE10;1107 1173 11AB;BE10;1107 1173 11AB; # (븐; 븐; 븐; 븐; 븐; ) HANGUL SYLLABLE BEUN +BE11;BE11;1107 1173 11AC;BE11;1107 1173 11AC; # (븑; 븑; 븑; 븑; 븑; ) HANGUL SYLLABLE BEUNJ +BE12;BE12;1107 1173 11AD;BE12;1107 1173 11AD; # (븒; 븒; 븒; 븒; 븒; ) HANGUL SYLLABLE BEUNH +BE13;BE13;1107 1173 11AE;BE13;1107 1173 11AE; # (븓; 븓; 븓; 븓; 븓; ) HANGUL SYLLABLE BEUD +BE14;BE14;1107 1173 11AF;BE14;1107 1173 11AF; # (블; 블; 블; 블; 블; ) HANGUL SYLLABLE BEUL +BE15;BE15;1107 1173 11B0;BE15;1107 1173 11B0; # (븕; 븕; 븕; 븕; 븕; ) HANGUL SYLLABLE BEULG +BE16;BE16;1107 1173 11B1;BE16;1107 1173 11B1; # (븖; 븖; 븖; 븖; 븖; ) HANGUL SYLLABLE BEULM +BE17;BE17;1107 1173 11B2;BE17;1107 1173 11B2; # (븗; 븗; 븗; 븗; 븗; ) HANGUL SYLLABLE BEULB +BE18;BE18;1107 1173 11B3;BE18;1107 1173 11B3; # (븘; 븘; 븘; 븘; 븘; ) HANGUL SYLLABLE BEULS +BE19;BE19;1107 1173 11B4;BE19;1107 1173 11B4; # (븙; 븙; 븙; 븙; 븙; ) HANGUL SYLLABLE BEULT +BE1A;BE1A;1107 1173 11B5;BE1A;1107 1173 11B5; # (븚; 븚; 븚; 븚; 븚; ) HANGUL SYLLABLE BEULP +BE1B;BE1B;1107 1173 11B6;BE1B;1107 1173 11B6; # (븛; 븛; 븛; 븛; 븛; ) HANGUL SYLLABLE BEULH +BE1C;BE1C;1107 1173 11B7;BE1C;1107 1173 11B7; # (븜; 븜; 븜; 븜; 븜; ) HANGUL SYLLABLE BEUM +BE1D;BE1D;1107 1173 11B8;BE1D;1107 1173 11B8; # (븝; 븝; 븝; 븝; 븝; ) HANGUL SYLLABLE BEUB +BE1E;BE1E;1107 1173 11B9;BE1E;1107 1173 11B9; # (븞; 븞; 븞; 븞; 븞; ) HANGUL SYLLABLE BEUBS +BE1F;BE1F;1107 1173 11BA;BE1F;1107 1173 11BA; # (븟; 븟; 븟; 븟; 븟; ) HANGUL SYLLABLE BEUS +BE20;BE20;1107 1173 11BB;BE20;1107 1173 11BB; # (븠; 븠; 븠; 븠; 븠; ) HANGUL SYLLABLE BEUSS +BE21;BE21;1107 1173 11BC;BE21;1107 1173 11BC; # (븡; 븡; 븡; 븡; 븡; ) HANGUL SYLLABLE BEUNG +BE22;BE22;1107 1173 11BD;BE22;1107 1173 11BD; # (븢; 븢; 븢; 븢; 븢; ) HANGUL SYLLABLE BEUJ +BE23;BE23;1107 1173 11BE;BE23;1107 1173 11BE; # (븣; 븣; 븣; 븣; 븣; ) HANGUL SYLLABLE BEUC +BE24;BE24;1107 1173 11BF;BE24;1107 1173 11BF; # (븤; 븤; 븤; 븤; 븤; ) HANGUL SYLLABLE BEUK +BE25;BE25;1107 1173 11C0;BE25;1107 1173 11C0; # (븥; 븥; 븥; 븥; 븥; ) HANGUL SYLLABLE BEUT +BE26;BE26;1107 1173 11C1;BE26;1107 1173 11C1; # (븦; 븦; 븦; 븦; 븦; ) HANGUL SYLLABLE BEUP +BE27;BE27;1107 1173 11C2;BE27;1107 1173 11C2; # (븧; 븧; 븧; 븧; 븧; ) HANGUL SYLLABLE BEUH +BE28;BE28;1107 1174;BE28;1107 1174; # (븨; 븨; 븨; 븨; 븨; ) HANGUL SYLLABLE BYI +BE29;BE29;1107 1174 11A8;BE29;1107 1174 11A8; # (븩; 븩; 븩; 븩; 븩; ) HANGUL SYLLABLE BYIG +BE2A;BE2A;1107 1174 11A9;BE2A;1107 1174 11A9; # (븪; 븪; 븪; 븪; 븪; ) HANGUL SYLLABLE BYIGG +BE2B;BE2B;1107 1174 11AA;BE2B;1107 1174 11AA; # (븫; 븫; 븫; 븫; 븫; ) HANGUL SYLLABLE BYIGS +BE2C;BE2C;1107 1174 11AB;BE2C;1107 1174 11AB; # (븬; 븬; 븬; 븬; 븬; ) HANGUL SYLLABLE BYIN +BE2D;BE2D;1107 1174 11AC;BE2D;1107 1174 11AC; # (븭; 븭; 븭; 븭; 븭; ) HANGUL SYLLABLE BYINJ +BE2E;BE2E;1107 1174 11AD;BE2E;1107 1174 11AD; # (븮; 븮; 븮; 븮; 븮; ) HANGUL SYLLABLE BYINH +BE2F;BE2F;1107 1174 11AE;BE2F;1107 1174 11AE; # (븯; 븯; 븯; 븯; 븯; ) HANGUL SYLLABLE BYID +BE30;BE30;1107 1174 11AF;BE30;1107 1174 11AF; # (븰; 븰; 븰; 븰; 븰; ) HANGUL SYLLABLE BYIL +BE31;BE31;1107 1174 11B0;BE31;1107 1174 11B0; # (븱; 븱; 븱; 븱; 븱; ) HANGUL SYLLABLE BYILG +BE32;BE32;1107 1174 11B1;BE32;1107 1174 11B1; # (븲; 븲; 븲; 븲; 븲; ) HANGUL SYLLABLE BYILM +BE33;BE33;1107 1174 11B2;BE33;1107 1174 11B2; # (븳; 븳; 븳; 븳; 븳; ) HANGUL SYLLABLE BYILB +BE34;BE34;1107 1174 11B3;BE34;1107 1174 11B3; # (븴; 븴; 븴; 븴; 븴; ) HANGUL SYLLABLE BYILS +BE35;BE35;1107 1174 11B4;BE35;1107 1174 11B4; # (븵; 븵; 븵; 븵; 븵; ) HANGUL SYLLABLE BYILT +BE36;BE36;1107 1174 11B5;BE36;1107 1174 11B5; # (븶; 븶; 븶; 븶; 븶; ) HANGUL SYLLABLE BYILP +BE37;BE37;1107 1174 11B6;BE37;1107 1174 11B6; # (븷; 븷; 븷; 븷; 븷; ) HANGUL SYLLABLE BYILH +BE38;BE38;1107 1174 11B7;BE38;1107 1174 11B7; # (븸; 븸; 븸; 븸; 븸; ) HANGUL SYLLABLE BYIM +BE39;BE39;1107 1174 11B8;BE39;1107 1174 11B8; # (븹; 븹; 븹; 븹; 븹; ) HANGUL SYLLABLE BYIB +BE3A;BE3A;1107 1174 11B9;BE3A;1107 1174 11B9; # (븺; 븺; 븺; 븺; 븺; ) HANGUL SYLLABLE BYIBS +BE3B;BE3B;1107 1174 11BA;BE3B;1107 1174 11BA; # (븻; 븻; 븻; 븻; 븻; ) HANGUL SYLLABLE BYIS +BE3C;BE3C;1107 1174 11BB;BE3C;1107 1174 11BB; # (븼; 븼; 븼; 븼; 븼; ) HANGUL SYLLABLE BYISS +BE3D;BE3D;1107 1174 11BC;BE3D;1107 1174 11BC; # (븽; 븽; 븽; 븽; 븽; ) HANGUL SYLLABLE BYING +BE3E;BE3E;1107 1174 11BD;BE3E;1107 1174 11BD; # (븾; 븾; 븾; 븾; 븾; ) HANGUL SYLLABLE BYIJ +BE3F;BE3F;1107 1174 11BE;BE3F;1107 1174 11BE; # (븿; 븿; 븿; 븿; 븿; ) HANGUL SYLLABLE BYIC +BE40;BE40;1107 1174 11BF;BE40;1107 1174 11BF; # (빀; 빀; 빀; 빀; 빀; ) HANGUL SYLLABLE BYIK +BE41;BE41;1107 1174 11C0;BE41;1107 1174 11C0; # (빁; 빁; 빁; 빁; 빁; ) HANGUL SYLLABLE BYIT +BE42;BE42;1107 1174 11C1;BE42;1107 1174 11C1; # (빂; 빂; 빂; 빂; 빂; ) HANGUL SYLLABLE BYIP +BE43;BE43;1107 1174 11C2;BE43;1107 1174 11C2; # (빃; 빃; 빃; 빃; 빃; ) HANGUL SYLLABLE BYIH +BE44;BE44;1107 1175;BE44;1107 1175; # (비; 비; 비; 비; 비; ) HANGUL SYLLABLE BI +BE45;BE45;1107 1175 11A8;BE45;1107 1175 11A8; # (빅; 빅; 빅; 빅; 빅; ) HANGUL SYLLABLE BIG +BE46;BE46;1107 1175 11A9;BE46;1107 1175 11A9; # (빆; 빆; 빆; 빆; 빆; ) HANGUL SYLLABLE BIGG +BE47;BE47;1107 1175 11AA;BE47;1107 1175 11AA; # (빇; 빇; 빇; 빇; 빇; ) HANGUL SYLLABLE BIGS +BE48;BE48;1107 1175 11AB;BE48;1107 1175 11AB; # (빈; 빈; 빈; 빈; 빈; ) HANGUL SYLLABLE BIN +BE49;BE49;1107 1175 11AC;BE49;1107 1175 11AC; # (빉; 빉; 빉; 빉; 빉; ) HANGUL SYLLABLE BINJ +BE4A;BE4A;1107 1175 11AD;BE4A;1107 1175 11AD; # (빊; 빊; 빊; 빊; 빊; ) HANGUL SYLLABLE BINH +BE4B;BE4B;1107 1175 11AE;BE4B;1107 1175 11AE; # (빋; 빋; 빋; 빋; 빋; ) HANGUL SYLLABLE BID +BE4C;BE4C;1107 1175 11AF;BE4C;1107 1175 11AF; # (빌; 빌; 빌; 빌; 빌; ) HANGUL SYLLABLE BIL +BE4D;BE4D;1107 1175 11B0;BE4D;1107 1175 11B0; # (빍; 빍; 빍; 빍; 빍; ) HANGUL SYLLABLE BILG +BE4E;BE4E;1107 1175 11B1;BE4E;1107 1175 11B1; # (빎; 빎; 빎; 빎; 빎; ) HANGUL SYLLABLE BILM +BE4F;BE4F;1107 1175 11B2;BE4F;1107 1175 11B2; # (빏; 빏; 빏; 빏; 빏; ) HANGUL SYLLABLE BILB +BE50;BE50;1107 1175 11B3;BE50;1107 1175 11B3; # (빐; 빐; 빐; 빐; 빐; ) HANGUL SYLLABLE BILS +BE51;BE51;1107 1175 11B4;BE51;1107 1175 11B4; # (빑; 빑; 빑; 빑; 빑; ) HANGUL SYLLABLE BILT +BE52;BE52;1107 1175 11B5;BE52;1107 1175 11B5; # (빒; 빒; 빒; 빒; 빒; ) HANGUL SYLLABLE BILP +BE53;BE53;1107 1175 11B6;BE53;1107 1175 11B6; # (빓; 빓; 빓; 빓; 빓; ) HANGUL SYLLABLE BILH +BE54;BE54;1107 1175 11B7;BE54;1107 1175 11B7; # (빔; 빔; 빔; 빔; 빔; ) HANGUL SYLLABLE BIM +BE55;BE55;1107 1175 11B8;BE55;1107 1175 11B8; # (빕; 빕; 빕; 빕; 빕; ) HANGUL SYLLABLE BIB +BE56;BE56;1107 1175 11B9;BE56;1107 1175 11B9; # (빖; 빖; 빖; 빖; 빖; ) HANGUL SYLLABLE BIBS +BE57;BE57;1107 1175 11BA;BE57;1107 1175 11BA; # (빗; 빗; 빗; 빗; 빗; ) HANGUL SYLLABLE BIS +BE58;BE58;1107 1175 11BB;BE58;1107 1175 11BB; # (빘; 빘; 빘; 빘; 빘; ) HANGUL SYLLABLE BISS +BE59;BE59;1107 1175 11BC;BE59;1107 1175 11BC; # (빙; 빙; 빙; 빙; 빙; ) HANGUL SYLLABLE BING +BE5A;BE5A;1107 1175 11BD;BE5A;1107 1175 11BD; # (빚; 빚; 빚; 빚; 빚; ) HANGUL SYLLABLE BIJ +BE5B;BE5B;1107 1175 11BE;BE5B;1107 1175 11BE; # (빛; 빛; 빛; 빛; 빛; ) HANGUL SYLLABLE BIC +BE5C;BE5C;1107 1175 11BF;BE5C;1107 1175 11BF; # (빜; 빜; 빜; 빜; 빜; ) HANGUL SYLLABLE BIK +BE5D;BE5D;1107 1175 11C0;BE5D;1107 1175 11C0; # (빝; 빝; 빝; 빝; 빝; ) HANGUL SYLLABLE BIT +BE5E;BE5E;1107 1175 11C1;BE5E;1107 1175 11C1; # (빞; 빞; 빞; 빞; 빞; ) HANGUL SYLLABLE BIP +BE5F;BE5F;1107 1175 11C2;BE5F;1107 1175 11C2; # (빟; 빟; 빟; 빟; 빟; ) HANGUL SYLLABLE BIH +BE60;BE60;1108 1161;BE60;1108 1161; # (빠; 빠; 빠; 빠; 빠; ) HANGUL SYLLABLE BBA +BE61;BE61;1108 1161 11A8;BE61;1108 1161 11A8; # (빡; 빡; 빡; 빡; 빡; ) HANGUL SYLLABLE BBAG +BE62;BE62;1108 1161 11A9;BE62;1108 1161 11A9; # (빢; 빢; 빢; 빢; 빢; ) HANGUL SYLLABLE BBAGG +BE63;BE63;1108 1161 11AA;BE63;1108 1161 11AA; # (빣; 빣; 빣; 빣; 빣; ) HANGUL SYLLABLE BBAGS +BE64;BE64;1108 1161 11AB;BE64;1108 1161 11AB; # (빤; 빤; 빤; 빤; 빤; ) HANGUL SYLLABLE BBAN +BE65;BE65;1108 1161 11AC;BE65;1108 1161 11AC; # (빥; 빥; 빥; 빥; 빥; ) HANGUL SYLLABLE BBANJ +BE66;BE66;1108 1161 11AD;BE66;1108 1161 11AD; # (빦; 빦; 빦; 빦; 빦; ) HANGUL SYLLABLE BBANH +BE67;BE67;1108 1161 11AE;BE67;1108 1161 11AE; # (빧; 빧; 빧; 빧; 빧; ) HANGUL SYLLABLE BBAD +BE68;BE68;1108 1161 11AF;BE68;1108 1161 11AF; # (빨; 빨; 빨; 빨; 빨; ) HANGUL SYLLABLE BBAL +BE69;BE69;1108 1161 11B0;BE69;1108 1161 11B0; # (빩; 빩; 빩; 빩; 빩; ) HANGUL SYLLABLE BBALG +BE6A;BE6A;1108 1161 11B1;BE6A;1108 1161 11B1; # (빪; 빪; 빪; 빪; 빪; ) HANGUL SYLLABLE BBALM +BE6B;BE6B;1108 1161 11B2;BE6B;1108 1161 11B2; # (빫; 빫; 빫; 빫; 빫; ) HANGUL SYLLABLE BBALB +BE6C;BE6C;1108 1161 11B3;BE6C;1108 1161 11B3; # (빬; 빬; 빬; 빬; 빬; ) HANGUL SYLLABLE BBALS +BE6D;BE6D;1108 1161 11B4;BE6D;1108 1161 11B4; # (빭; 빭; 빭; 빭; 빭; ) HANGUL SYLLABLE BBALT +BE6E;BE6E;1108 1161 11B5;BE6E;1108 1161 11B5; # (빮; 빮; 빮; 빮; 빮; ) HANGUL SYLLABLE BBALP +BE6F;BE6F;1108 1161 11B6;BE6F;1108 1161 11B6; # (빯; 빯; 빯; 빯; 빯; ) HANGUL SYLLABLE BBALH +BE70;BE70;1108 1161 11B7;BE70;1108 1161 11B7; # (빰; 빰; 빰; 빰; 빰; ) HANGUL SYLLABLE BBAM +BE71;BE71;1108 1161 11B8;BE71;1108 1161 11B8; # (빱; 빱; 빱; 빱; 빱; ) HANGUL SYLLABLE BBAB +BE72;BE72;1108 1161 11B9;BE72;1108 1161 11B9; # (빲; 빲; 빲; 빲; 빲; ) HANGUL SYLLABLE BBABS +BE73;BE73;1108 1161 11BA;BE73;1108 1161 11BA; # (빳; 빳; 빳; 빳; 빳; ) HANGUL SYLLABLE BBAS +BE74;BE74;1108 1161 11BB;BE74;1108 1161 11BB; # (빴; 빴; 빴; 빴; 빴; ) HANGUL SYLLABLE BBASS +BE75;BE75;1108 1161 11BC;BE75;1108 1161 11BC; # (빵; 빵; 빵; 빵; 빵; ) HANGUL SYLLABLE BBANG +BE76;BE76;1108 1161 11BD;BE76;1108 1161 11BD; # (빶; 빶; 빶; 빶; 빶; ) HANGUL SYLLABLE BBAJ +BE77;BE77;1108 1161 11BE;BE77;1108 1161 11BE; # (빷; 빷; 빷; 빷; 빷; ) HANGUL SYLLABLE BBAC +BE78;BE78;1108 1161 11BF;BE78;1108 1161 11BF; # (빸; 빸; 빸; 빸; 빸; ) HANGUL SYLLABLE BBAK +BE79;BE79;1108 1161 11C0;BE79;1108 1161 11C0; # (빹; 빹; 빹; 빹; 빹; ) HANGUL SYLLABLE BBAT +BE7A;BE7A;1108 1161 11C1;BE7A;1108 1161 11C1; # (빺; 빺; 빺; 빺; 빺; ) HANGUL SYLLABLE BBAP +BE7B;BE7B;1108 1161 11C2;BE7B;1108 1161 11C2; # (빻; 빻; 빻; 빻; 빻; ) HANGUL SYLLABLE BBAH +BE7C;BE7C;1108 1162;BE7C;1108 1162; # (빼; 빼; 빼; 빼; 빼; ) HANGUL SYLLABLE BBAE +BE7D;BE7D;1108 1162 11A8;BE7D;1108 1162 11A8; # (빽; 빽; 빽; 빽; 빽; ) HANGUL SYLLABLE BBAEG +BE7E;BE7E;1108 1162 11A9;BE7E;1108 1162 11A9; # (빾; 빾; 빾; 빾; 빾; ) HANGUL SYLLABLE BBAEGG +BE7F;BE7F;1108 1162 11AA;BE7F;1108 1162 11AA; # (빿; 빿; 빿; 빿; 빿; ) HANGUL SYLLABLE BBAEGS +BE80;BE80;1108 1162 11AB;BE80;1108 1162 11AB; # (뺀; 뺀; 뺀; 뺀; 뺀; ) HANGUL SYLLABLE BBAEN +BE81;BE81;1108 1162 11AC;BE81;1108 1162 11AC; # (뺁; 뺁; 뺁; 뺁; 뺁; ) HANGUL SYLLABLE BBAENJ +BE82;BE82;1108 1162 11AD;BE82;1108 1162 11AD; # (뺂; 뺂; 뺂; 뺂; 뺂; ) HANGUL SYLLABLE BBAENH +BE83;BE83;1108 1162 11AE;BE83;1108 1162 11AE; # (뺃; 뺃; 뺃; 뺃; 뺃; ) HANGUL SYLLABLE BBAED +BE84;BE84;1108 1162 11AF;BE84;1108 1162 11AF; # (뺄; 뺄; 뺄; 뺄; 뺄; ) HANGUL SYLLABLE BBAEL +BE85;BE85;1108 1162 11B0;BE85;1108 1162 11B0; # (뺅; 뺅; 뺅; 뺅; 뺅; ) HANGUL SYLLABLE BBAELG +BE86;BE86;1108 1162 11B1;BE86;1108 1162 11B1; # (뺆; 뺆; 뺆; 뺆; 뺆; ) HANGUL SYLLABLE BBAELM +BE87;BE87;1108 1162 11B2;BE87;1108 1162 11B2; # (뺇; 뺇; 뺇; 뺇; 뺇; ) HANGUL SYLLABLE BBAELB +BE88;BE88;1108 1162 11B3;BE88;1108 1162 11B3; # (뺈; 뺈; 뺈; 뺈; 뺈; ) HANGUL SYLLABLE BBAELS +BE89;BE89;1108 1162 11B4;BE89;1108 1162 11B4; # (뺉; 뺉; 뺉; 뺉; 뺉; ) HANGUL SYLLABLE BBAELT +BE8A;BE8A;1108 1162 11B5;BE8A;1108 1162 11B5; # (뺊; 뺊; 뺊; 뺊; 뺊; ) HANGUL SYLLABLE BBAELP +BE8B;BE8B;1108 1162 11B6;BE8B;1108 1162 11B6; # (뺋; 뺋; 뺋; 뺋; 뺋; ) HANGUL SYLLABLE BBAELH +BE8C;BE8C;1108 1162 11B7;BE8C;1108 1162 11B7; # (뺌; 뺌; 뺌; 뺌; 뺌; ) HANGUL SYLLABLE BBAEM +BE8D;BE8D;1108 1162 11B8;BE8D;1108 1162 11B8; # (뺍; 뺍; 뺍; 뺍; 뺍; ) HANGUL SYLLABLE BBAEB +BE8E;BE8E;1108 1162 11B9;BE8E;1108 1162 11B9; # (뺎; 뺎; 뺎; 뺎; 뺎; ) HANGUL SYLLABLE BBAEBS +BE8F;BE8F;1108 1162 11BA;BE8F;1108 1162 11BA; # (뺏; 뺏; 뺏; 뺏; 뺏; ) HANGUL SYLLABLE BBAES +BE90;BE90;1108 1162 11BB;BE90;1108 1162 11BB; # (뺐; 뺐; 뺐; 뺐; 뺐; ) HANGUL SYLLABLE BBAESS +BE91;BE91;1108 1162 11BC;BE91;1108 1162 11BC; # (뺑; 뺑; 뺑; 뺑; 뺑; ) HANGUL SYLLABLE BBAENG +BE92;BE92;1108 1162 11BD;BE92;1108 1162 11BD; # (뺒; 뺒; 뺒; 뺒; 뺒; ) HANGUL SYLLABLE BBAEJ +BE93;BE93;1108 1162 11BE;BE93;1108 1162 11BE; # (뺓; 뺓; 뺓; 뺓; 뺓; ) HANGUL SYLLABLE BBAEC +BE94;BE94;1108 1162 11BF;BE94;1108 1162 11BF; # (뺔; 뺔; 뺔; 뺔; 뺔; ) HANGUL SYLLABLE BBAEK +BE95;BE95;1108 1162 11C0;BE95;1108 1162 11C0; # (뺕; 뺕; 뺕; 뺕; 뺕; ) HANGUL SYLLABLE BBAET +BE96;BE96;1108 1162 11C1;BE96;1108 1162 11C1; # (뺖; 뺖; 뺖; 뺖; 뺖; ) HANGUL SYLLABLE BBAEP +BE97;BE97;1108 1162 11C2;BE97;1108 1162 11C2; # (뺗; 뺗; 뺗; 뺗; 뺗; ) HANGUL SYLLABLE BBAEH +BE98;BE98;1108 1163;BE98;1108 1163; # (뺘; 뺘; 뺘; 뺘; 뺘; ) HANGUL SYLLABLE BBYA +BE99;BE99;1108 1163 11A8;BE99;1108 1163 11A8; # (뺙; 뺙; 뺙; 뺙; 뺙; ) HANGUL SYLLABLE BBYAG +BE9A;BE9A;1108 1163 11A9;BE9A;1108 1163 11A9; # (뺚; 뺚; 뺚; 뺚; 뺚; ) HANGUL SYLLABLE BBYAGG +BE9B;BE9B;1108 1163 11AA;BE9B;1108 1163 11AA; # (뺛; 뺛; 뺛; 뺛; 뺛; ) HANGUL SYLLABLE BBYAGS +BE9C;BE9C;1108 1163 11AB;BE9C;1108 1163 11AB; # (뺜; 뺜; 뺜; 뺜; 뺜; ) HANGUL SYLLABLE BBYAN +BE9D;BE9D;1108 1163 11AC;BE9D;1108 1163 11AC; # (뺝; 뺝; 뺝; 뺝; 뺝; ) HANGUL SYLLABLE BBYANJ +BE9E;BE9E;1108 1163 11AD;BE9E;1108 1163 11AD; # (뺞; 뺞; 뺞; 뺞; 뺞; ) HANGUL SYLLABLE BBYANH +BE9F;BE9F;1108 1163 11AE;BE9F;1108 1163 11AE; # (뺟; 뺟; 뺟; 뺟; 뺟; ) HANGUL SYLLABLE BBYAD +BEA0;BEA0;1108 1163 11AF;BEA0;1108 1163 11AF; # (뺠; 뺠; 뺠; 뺠; 뺠; ) HANGUL SYLLABLE BBYAL +BEA1;BEA1;1108 1163 11B0;BEA1;1108 1163 11B0; # (뺡; 뺡; 뺡; 뺡; 뺡; ) HANGUL SYLLABLE BBYALG +BEA2;BEA2;1108 1163 11B1;BEA2;1108 1163 11B1; # (뺢; 뺢; 뺢; 뺢; 뺢; ) HANGUL SYLLABLE BBYALM +BEA3;BEA3;1108 1163 11B2;BEA3;1108 1163 11B2; # (뺣; 뺣; 뺣; 뺣; 뺣; ) HANGUL SYLLABLE BBYALB +BEA4;BEA4;1108 1163 11B3;BEA4;1108 1163 11B3; # (뺤; 뺤; 뺤; 뺤; 뺤; ) HANGUL SYLLABLE BBYALS +BEA5;BEA5;1108 1163 11B4;BEA5;1108 1163 11B4; # (뺥; 뺥; 뺥; 뺥; 뺥; ) HANGUL SYLLABLE BBYALT +BEA6;BEA6;1108 1163 11B5;BEA6;1108 1163 11B5; # (뺦; 뺦; 뺦; 뺦; 뺦; ) HANGUL SYLLABLE BBYALP +BEA7;BEA7;1108 1163 11B6;BEA7;1108 1163 11B6; # (뺧; 뺧; 뺧; 뺧; 뺧; ) HANGUL SYLLABLE BBYALH +BEA8;BEA8;1108 1163 11B7;BEA8;1108 1163 11B7; # (뺨; 뺨; 뺨; 뺨; 뺨; ) HANGUL SYLLABLE BBYAM +BEA9;BEA9;1108 1163 11B8;BEA9;1108 1163 11B8; # (뺩; 뺩; 뺩; 뺩; 뺩; ) HANGUL SYLLABLE BBYAB +BEAA;BEAA;1108 1163 11B9;BEAA;1108 1163 11B9; # (뺪; 뺪; 뺪; 뺪; 뺪; ) HANGUL SYLLABLE BBYABS +BEAB;BEAB;1108 1163 11BA;BEAB;1108 1163 11BA; # (뺫; 뺫; 뺫; 뺫; 뺫; ) HANGUL SYLLABLE BBYAS +BEAC;BEAC;1108 1163 11BB;BEAC;1108 1163 11BB; # (뺬; 뺬; 뺬; 뺬; 뺬; ) HANGUL SYLLABLE BBYASS +BEAD;BEAD;1108 1163 11BC;BEAD;1108 1163 11BC; # (뺭; 뺭; 뺭; 뺭; 뺭; ) HANGUL SYLLABLE BBYANG +BEAE;BEAE;1108 1163 11BD;BEAE;1108 1163 11BD; # (뺮; 뺮; 뺮; 뺮; 뺮; ) HANGUL SYLLABLE BBYAJ +BEAF;BEAF;1108 1163 11BE;BEAF;1108 1163 11BE; # (뺯; 뺯; 뺯; 뺯; 뺯; ) HANGUL SYLLABLE BBYAC +BEB0;BEB0;1108 1163 11BF;BEB0;1108 1163 11BF; # (뺰; 뺰; 뺰; 뺰; 뺰; ) HANGUL SYLLABLE BBYAK +BEB1;BEB1;1108 1163 11C0;BEB1;1108 1163 11C0; # (뺱; 뺱; 뺱; 뺱; 뺱; ) HANGUL SYLLABLE BBYAT +BEB2;BEB2;1108 1163 11C1;BEB2;1108 1163 11C1; # (뺲; 뺲; 뺲; 뺲; 뺲; ) HANGUL SYLLABLE BBYAP +BEB3;BEB3;1108 1163 11C2;BEB3;1108 1163 11C2; # (뺳; 뺳; 뺳; 뺳; 뺳; ) HANGUL SYLLABLE BBYAH +BEB4;BEB4;1108 1164;BEB4;1108 1164; # (뺴; 뺴; 뺴; 뺴; 뺴; ) HANGUL SYLLABLE BBYAE +BEB5;BEB5;1108 1164 11A8;BEB5;1108 1164 11A8; # (뺵; 뺵; 뺵; 뺵; 뺵; ) HANGUL SYLLABLE BBYAEG +BEB6;BEB6;1108 1164 11A9;BEB6;1108 1164 11A9; # (뺶; 뺶; 뺶; 뺶; 뺶; ) HANGUL SYLLABLE BBYAEGG +BEB7;BEB7;1108 1164 11AA;BEB7;1108 1164 11AA; # (뺷; 뺷; 뺷; 뺷; 뺷; ) HANGUL SYLLABLE BBYAEGS +BEB8;BEB8;1108 1164 11AB;BEB8;1108 1164 11AB; # (뺸; 뺸; 뺸; 뺸; 뺸; ) HANGUL SYLLABLE BBYAEN +BEB9;BEB9;1108 1164 11AC;BEB9;1108 1164 11AC; # (뺹; 뺹; 뺹; 뺹; 뺹; ) HANGUL SYLLABLE BBYAENJ +BEBA;BEBA;1108 1164 11AD;BEBA;1108 1164 11AD; # (뺺; 뺺; 뺺; 뺺; 뺺; ) HANGUL SYLLABLE BBYAENH +BEBB;BEBB;1108 1164 11AE;BEBB;1108 1164 11AE; # (뺻; 뺻; 뺻; 뺻; 뺻; ) HANGUL SYLLABLE BBYAED +BEBC;BEBC;1108 1164 11AF;BEBC;1108 1164 11AF; # (뺼; 뺼; 뺼; 뺼; 뺼; ) HANGUL SYLLABLE BBYAEL +BEBD;BEBD;1108 1164 11B0;BEBD;1108 1164 11B0; # (뺽; 뺽; 뺽; 뺽; 뺽; ) HANGUL SYLLABLE BBYAELG +BEBE;BEBE;1108 1164 11B1;BEBE;1108 1164 11B1; # (뺾; 뺾; 뺾; 뺾; 뺾; ) HANGUL SYLLABLE BBYAELM +BEBF;BEBF;1108 1164 11B2;BEBF;1108 1164 11B2; # (뺿; 뺿; 뺿; 뺿; 뺿; ) HANGUL SYLLABLE BBYAELB +BEC0;BEC0;1108 1164 11B3;BEC0;1108 1164 11B3; # (뻀; 뻀; 뻀; 뻀; 뻀; ) HANGUL SYLLABLE BBYAELS +BEC1;BEC1;1108 1164 11B4;BEC1;1108 1164 11B4; # (뻁; 뻁; 뻁; 뻁; 뻁; ) HANGUL SYLLABLE BBYAELT +BEC2;BEC2;1108 1164 11B5;BEC2;1108 1164 11B5; # (뻂; 뻂; 뻂; 뻂; 뻂; ) HANGUL SYLLABLE BBYAELP +BEC3;BEC3;1108 1164 11B6;BEC3;1108 1164 11B6; # (뻃; 뻃; 뻃; 뻃; 뻃; ) HANGUL SYLLABLE BBYAELH +BEC4;BEC4;1108 1164 11B7;BEC4;1108 1164 11B7; # (뻄; 뻄; 뻄; 뻄; 뻄; ) HANGUL SYLLABLE BBYAEM +BEC5;BEC5;1108 1164 11B8;BEC5;1108 1164 11B8; # (뻅; 뻅; 뻅; 뻅; 뻅; ) HANGUL SYLLABLE BBYAEB +BEC6;BEC6;1108 1164 11B9;BEC6;1108 1164 11B9; # (뻆; 뻆; 뻆; 뻆; 뻆; ) HANGUL SYLLABLE BBYAEBS +BEC7;BEC7;1108 1164 11BA;BEC7;1108 1164 11BA; # (뻇; 뻇; 뻇; 뻇; 뻇; ) HANGUL SYLLABLE BBYAES +BEC8;BEC8;1108 1164 11BB;BEC8;1108 1164 11BB; # (뻈; 뻈; 뻈; 뻈; 뻈; ) HANGUL SYLLABLE BBYAESS +BEC9;BEC9;1108 1164 11BC;BEC9;1108 1164 11BC; # (뻉; 뻉; 뻉; 뻉; 뻉; ) HANGUL SYLLABLE BBYAENG +BECA;BECA;1108 1164 11BD;BECA;1108 1164 11BD; # (뻊; 뻊; 뻊; 뻊; 뻊; ) HANGUL SYLLABLE BBYAEJ +BECB;BECB;1108 1164 11BE;BECB;1108 1164 11BE; # (뻋; 뻋; 뻋; 뻋; 뻋; ) HANGUL SYLLABLE BBYAEC +BECC;BECC;1108 1164 11BF;BECC;1108 1164 11BF; # (뻌; 뻌; 뻌; 뻌; 뻌; ) HANGUL SYLLABLE BBYAEK +BECD;BECD;1108 1164 11C0;BECD;1108 1164 11C0; # (뻍; 뻍; 뻍; 뻍; 뻍; ) HANGUL SYLLABLE BBYAET +BECE;BECE;1108 1164 11C1;BECE;1108 1164 11C1; # (뻎; 뻎; 뻎; 뻎; 뻎; ) HANGUL SYLLABLE BBYAEP +BECF;BECF;1108 1164 11C2;BECF;1108 1164 11C2; # (뻏; 뻏; 뻏; 뻏; 뻏; ) HANGUL SYLLABLE BBYAEH +BED0;BED0;1108 1165;BED0;1108 1165; # (뻐; 뻐; 뻐; 뻐; 뻐; ) HANGUL SYLLABLE BBEO +BED1;BED1;1108 1165 11A8;BED1;1108 1165 11A8; # (뻑; 뻑; 뻑; 뻑; 뻑; ) HANGUL SYLLABLE BBEOG +BED2;BED2;1108 1165 11A9;BED2;1108 1165 11A9; # (뻒; 뻒; 뻒; 뻒; 뻒; ) HANGUL SYLLABLE BBEOGG +BED3;BED3;1108 1165 11AA;BED3;1108 1165 11AA; # (뻓; 뻓; 뻓; 뻓; 뻓; ) HANGUL SYLLABLE BBEOGS +BED4;BED4;1108 1165 11AB;BED4;1108 1165 11AB; # (뻔; 뻔; 뻔; 뻔; 뻔; ) HANGUL SYLLABLE BBEON +BED5;BED5;1108 1165 11AC;BED5;1108 1165 11AC; # (뻕; 뻕; 뻕; 뻕; 뻕; ) HANGUL SYLLABLE BBEONJ +BED6;BED6;1108 1165 11AD;BED6;1108 1165 11AD; # (뻖; 뻖; 뻖; 뻖; 뻖; ) HANGUL SYLLABLE BBEONH +BED7;BED7;1108 1165 11AE;BED7;1108 1165 11AE; # (뻗; 뻗; 뻗; 뻗; 뻗; ) HANGUL SYLLABLE BBEOD +BED8;BED8;1108 1165 11AF;BED8;1108 1165 11AF; # (뻘; 뻘; 뻘; 뻘; 뻘; ) HANGUL SYLLABLE BBEOL +BED9;BED9;1108 1165 11B0;BED9;1108 1165 11B0; # (뻙; 뻙; 뻙; 뻙; 뻙; ) HANGUL SYLLABLE BBEOLG +BEDA;BEDA;1108 1165 11B1;BEDA;1108 1165 11B1; # (뻚; 뻚; 뻚; 뻚; 뻚; ) HANGUL SYLLABLE BBEOLM +BEDB;BEDB;1108 1165 11B2;BEDB;1108 1165 11B2; # (뻛; 뻛; 뻛; 뻛; 뻛; ) HANGUL SYLLABLE BBEOLB +BEDC;BEDC;1108 1165 11B3;BEDC;1108 1165 11B3; # (뻜; 뻜; 뻜; 뻜; 뻜; ) HANGUL SYLLABLE BBEOLS +BEDD;BEDD;1108 1165 11B4;BEDD;1108 1165 11B4; # (뻝; 뻝; 뻝; 뻝; 뻝; ) HANGUL SYLLABLE BBEOLT +BEDE;BEDE;1108 1165 11B5;BEDE;1108 1165 11B5; # (뻞; 뻞; 뻞; 뻞; 뻞; ) HANGUL SYLLABLE BBEOLP +BEDF;BEDF;1108 1165 11B6;BEDF;1108 1165 11B6; # (뻟; 뻟; 뻟; 뻟; 뻟; ) HANGUL SYLLABLE BBEOLH +BEE0;BEE0;1108 1165 11B7;BEE0;1108 1165 11B7; # (뻠; 뻠; 뻠; 뻠; 뻠; ) HANGUL SYLLABLE BBEOM +BEE1;BEE1;1108 1165 11B8;BEE1;1108 1165 11B8; # (뻡; 뻡; 뻡; 뻡; 뻡; ) HANGUL SYLLABLE BBEOB +BEE2;BEE2;1108 1165 11B9;BEE2;1108 1165 11B9; # (뻢; 뻢; 뻢; 뻢; 뻢; ) HANGUL SYLLABLE BBEOBS +BEE3;BEE3;1108 1165 11BA;BEE3;1108 1165 11BA; # (뻣; 뻣; 뻣; 뻣; 뻣; ) HANGUL SYLLABLE BBEOS +BEE4;BEE4;1108 1165 11BB;BEE4;1108 1165 11BB; # (뻤; 뻤; 뻤; 뻤; 뻤; ) HANGUL SYLLABLE BBEOSS +BEE5;BEE5;1108 1165 11BC;BEE5;1108 1165 11BC; # (뻥; 뻥; 뻥; 뻥; 뻥; ) HANGUL SYLLABLE BBEONG +BEE6;BEE6;1108 1165 11BD;BEE6;1108 1165 11BD; # (뻦; 뻦; 뻦; 뻦; 뻦; ) HANGUL SYLLABLE BBEOJ +BEE7;BEE7;1108 1165 11BE;BEE7;1108 1165 11BE; # (뻧; 뻧; 뻧; 뻧; 뻧; ) HANGUL SYLLABLE BBEOC +BEE8;BEE8;1108 1165 11BF;BEE8;1108 1165 11BF; # (뻨; 뻨; 뻨; 뻨; 뻨; ) HANGUL SYLLABLE BBEOK +BEE9;BEE9;1108 1165 11C0;BEE9;1108 1165 11C0; # (뻩; 뻩; 뻩; 뻩; 뻩; ) HANGUL SYLLABLE BBEOT +BEEA;BEEA;1108 1165 11C1;BEEA;1108 1165 11C1; # (뻪; 뻪; 뻪; 뻪; 뻪; ) HANGUL SYLLABLE BBEOP +BEEB;BEEB;1108 1165 11C2;BEEB;1108 1165 11C2; # (뻫; 뻫; 뻫; 뻫; 뻫; ) HANGUL SYLLABLE BBEOH +BEEC;BEEC;1108 1166;BEEC;1108 1166; # (뻬; 뻬; 뻬; 뻬; 뻬; ) HANGUL SYLLABLE BBE +BEED;BEED;1108 1166 11A8;BEED;1108 1166 11A8; # (뻭; 뻭; 뻭; 뻭; 뻭; ) HANGUL SYLLABLE BBEG +BEEE;BEEE;1108 1166 11A9;BEEE;1108 1166 11A9; # (뻮; 뻮; 뻮; 뻮; 뻮; ) HANGUL SYLLABLE BBEGG +BEEF;BEEF;1108 1166 11AA;BEEF;1108 1166 11AA; # (뻯; 뻯; 뻯; 뻯; 뻯; ) HANGUL SYLLABLE BBEGS +BEF0;BEF0;1108 1166 11AB;BEF0;1108 1166 11AB; # (뻰; 뻰; 뻰; 뻰; 뻰; ) HANGUL SYLLABLE BBEN +BEF1;BEF1;1108 1166 11AC;BEF1;1108 1166 11AC; # (뻱; 뻱; 뻱; 뻱; 뻱; ) HANGUL SYLLABLE BBENJ +BEF2;BEF2;1108 1166 11AD;BEF2;1108 1166 11AD; # (뻲; 뻲; 뻲; 뻲; 뻲; ) HANGUL SYLLABLE BBENH +BEF3;BEF3;1108 1166 11AE;BEF3;1108 1166 11AE; # (뻳; 뻳; 뻳; 뻳; 뻳; ) HANGUL SYLLABLE BBED +BEF4;BEF4;1108 1166 11AF;BEF4;1108 1166 11AF; # (뻴; 뻴; 뻴; 뻴; 뻴; ) HANGUL SYLLABLE BBEL +BEF5;BEF5;1108 1166 11B0;BEF5;1108 1166 11B0; # (뻵; 뻵; 뻵; 뻵; 뻵; ) HANGUL SYLLABLE BBELG +BEF6;BEF6;1108 1166 11B1;BEF6;1108 1166 11B1; # (뻶; 뻶; 뻶; 뻶; 뻶; ) HANGUL SYLLABLE BBELM +BEF7;BEF7;1108 1166 11B2;BEF7;1108 1166 11B2; # (뻷; 뻷; 뻷; 뻷; 뻷; ) HANGUL SYLLABLE BBELB +BEF8;BEF8;1108 1166 11B3;BEF8;1108 1166 11B3; # (뻸; 뻸; 뻸; 뻸; 뻸; ) HANGUL SYLLABLE BBELS +BEF9;BEF9;1108 1166 11B4;BEF9;1108 1166 11B4; # (뻹; 뻹; 뻹; 뻹; 뻹; ) HANGUL SYLLABLE BBELT +BEFA;BEFA;1108 1166 11B5;BEFA;1108 1166 11B5; # (뻺; 뻺; 뻺; 뻺; 뻺; ) HANGUL SYLLABLE BBELP +BEFB;BEFB;1108 1166 11B6;BEFB;1108 1166 11B6; # (뻻; 뻻; 뻻; 뻻; 뻻; ) HANGUL SYLLABLE BBELH +BEFC;BEFC;1108 1166 11B7;BEFC;1108 1166 11B7; # (뻼; 뻼; 뻼; 뻼; 뻼; ) HANGUL SYLLABLE BBEM +BEFD;BEFD;1108 1166 11B8;BEFD;1108 1166 11B8; # (뻽; 뻽; 뻽; 뻽; 뻽; ) HANGUL SYLLABLE BBEB +BEFE;BEFE;1108 1166 11B9;BEFE;1108 1166 11B9; # (뻾; 뻾; 뻾; 뻾; 뻾; ) HANGUL SYLLABLE BBEBS +BEFF;BEFF;1108 1166 11BA;BEFF;1108 1166 11BA; # (뻿; 뻿; 뻿; 뻿; 뻿; ) HANGUL SYLLABLE BBES +BF00;BF00;1108 1166 11BB;BF00;1108 1166 11BB; # (뼀; 뼀; 뼀; 뼀; 뼀; ) HANGUL SYLLABLE BBESS +BF01;BF01;1108 1166 11BC;BF01;1108 1166 11BC; # (뼁; 뼁; 뼁; 뼁; 뼁; ) HANGUL SYLLABLE BBENG +BF02;BF02;1108 1166 11BD;BF02;1108 1166 11BD; # (뼂; 뼂; 뼂; 뼂; 뼂; ) HANGUL SYLLABLE BBEJ +BF03;BF03;1108 1166 11BE;BF03;1108 1166 11BE; # (뼃; 뼃; 뼃; 뼃; 뼃; ) HANGUL SYLLABLE BBEC +BF04;BF04;1108 1166 11BF;BF04;1108 1166 11BF; # (뼄; 뼄; 뼄; 뼄; 뼄; ) HANGUL SYLLABLE BBEK +BF05;BF05;1108 1166 11C0;BF05;1108 1166 11C0; # (뼅; 뼅; 뼅; 뼅; 뼅; ) HANGUL SYLLABLE BBET +BF06;BF06;1108 1166 11C1;BF06;1108 1166 11C1; # (뼆; 뼆; 뼆; 뼆; 뼆; ) HANGUL SYLLABLE BBEP +BF07;BF07;1108 1166 11C2;BF07;1108 1166 11C2; # (뼇; 뼇; 뼇; 뼇; 뼇; ) HANGUL SYLLABLE BBEH +BF08;BF08;1108 1167;BF08;1108 1167; # (뼈; 뼈; 뼈; 뼈; 뼈; ) HANGUL SYLLABLE BBYEO +BF09;BF09;1108 1167 11A8;BF09;1108 1167 11A8; # (뼉; 뼉; 뼉; 뼉; 뼉; ) HANGUL SYLLABLE BBYEOG +BF0A;BF0A;1108 1167 11A9;BF0A;1108 1167 11A9; # (뼊; 뼊; 뼊; 뼊; 뼊; ) HANGUL SYLLABLE BBYEOGG +BF0B;BF0B;1108 1167 11AA;BF0B;1108 1167 11AA; # (뼋; 뼋; 뼋; 뼋; 뼋; ) HANGUL SYLLABLE BBYEOGS +BF0C;BF0C;1108 1167 11AB;BF0C;1108 1167 11AB; # (뼌; 뼌; 뼌; 뼌; 뼌; ) HANGUL SYLLABLE BBYEON +BF0D;BF0D;1108 1167 11AC;BF0D;1108 1167 11AC; # (뼍; 뼍; 뼍; 뼍; 뼍; ) HANGUL SYLLABLE BBYEONJ +BF0E;BF0E;1108 1167 11AD;BF0E;1108 1167 11AD; # (뼎; 뼎; 뼎; 뼎; 뼎; ) HANGUL SYLLABLE BBYEONH +BF0F;BF0F;1108 1167 11AE;BF0F;1108 1167 11AE; # (뼏; 뼏; 뼏; 뼏; 뼏; ) HANGUL SYLLABLE BBYEOD +BF10;BF10;1108 1167 11AF;BF10;1108 1167 11AF; # (뼐; 뼐; 뼐; 뼐; 뼐; ) HANGUL SYLLABLE BBYEOL +BF11;BF11;1108 1167 11B0;BF11;1108 1167 11B0; # (뼑; 뼑; 뼑; 뼑; 뼑; ) HANGUL SYLLABLE BBYEOLG +BF12;BF12;1108 1167 11B1;BF12;1108 1167 11B1; # (뼒; 뼒; 뼒; 뼒; 뼒; ) HANGUL SYLLABLE BBYEOLM +BF13;BF13;1108 1167 11B2;BF13;1108 1167 11B2; # (뼓; 뼓; 뼓; 뼓; 뼓; ) HANGUL SYLLABLE BBYEOLB +BF14;BF14;1108 1167 11B3;BF14;1108 1167 11B3; # (뼔; 뼔; 뼔; 뼔; 뼔; ) HANGUL SYLLABLE BBYEOLS +BF15;BF15;1108 1167 11B4;BF15;1108 1167 11B4; # (뼕; 뼕; 뼕; 뼕; 뼕; ) HANGUL SYLLABLE BBYEOLT +BF16;BF16;1108 1167 11B5;BF16;1108 1167 11B5; # (뼖; 뼖; 뼖; 뼖; 뼖; ) HANGUL SYLLABLE BBYEOLP +BF17;BF17;1108 1167 11B6;BF17;1108 1167 11B6; # (뼗; 뼗; 뼗; 뼗; 뼗; ) HANGUL SYLLABLE BBYEOLH +BF18;BF18;1108 1167 11B7;BF18;1108 1167 11B7; # (뼘; 뼘; 뼘; 뼘; 뼘; ) HANGUL SYLLABLE BBYEOM +BF19;BF19;1108 1167 11B8;BF19;1108 1167 11B8; # (뼙; 뼙; 뼙; 뼙; 뼙; ) HANGUL SYLLABLE BBYEOB +BF1A;BF1A;1108 1167 11B9;BF1A;1108 1167 11B9; # (뼚; 뼚; 뼚; 뼚; 뼚; ) HANGUL SYLLABLE BBYEOBS +BF1B;BF1B;1108 1167 11BA;BF1B;1108 1167 11BA; # (뼛; 뼛; 뼛; 뼛; 뼛; ) HANGUL SYLLABLE BBYEOS +BF1C;BF1C;1108 1167 11BB;BF1C;1108 1167 11BB; # (뼜; 뼜; 뼜; 뼜; 뼜; ) HANGUL SYLLABLE BBYEOSS +BF1D;BF1D;1108 1167 11BC;BF1D;1108 1167 11BC; # (뼝; 뼝; 뼝; 뼝; 뼝; ) HANGUL SYLLABLE BBYEONG +BF1E;BF1E;1108 1167 11BD;BF1E;1108 1167 11BD; # (뼞; 뼞; 뼞; 뼞; 뼞; ) HANGUL SYLLABLE BBYEOJ +BF1F;BF1F;1108 1167 11BE;BF1F;1108 1167 11BE; # (뼟; 뼟; 뼟; 뼟; 뼟; ) HANGUL SYLLABLE BBYEOC +BF20;BF20;1108 1167 11BF;BF20;1108 1167 11BF; # (뼠; 뼠; 뼠; 뼠; 뼠; ) HANGUL SYLLABLE BBYEOK +BF21;BF21;1108 1167 11C0;BF21;1108 1167 11C0; # (뼡; 뼡; 뼡; 뼡; 뼡; ) HANGUL SYLLABLE BBYEOT +BF22;BF22;1108 1167 11C1;BF22;1108 1167 11C1; # (뼢; 뼢; 뼢; 뼢; 뼢; ) HANGUL SYLLABLE BBYEOP +BF23;BF23;1108 1167 11C2;BF23;1108 1167 11C2; # (뼣; 뼣; 뼣; 뼣; 뼣; ) HANGUL SYLLABLE BBYEOH +BF24;BF24;1108 1168;BF24;1108 1168; # (뼤; 뼤; 뼤; 뼤; 뼤; ) HANGUL SYLLABLE BBYE +BF25;BF25;1108 1168 11A8;BF25;1108 1168 11A8; # (뼥; 뼥; 뼥; 뼥; 뼥; ) HANGUL SYLLABLE BBYEG +BF26;BF26;1108 1168 11A9;BF26;1108 1168 11A9; # (뼦; 뼦; 뼦; 뼦; 뼦; ) HANGUL SYLLABLE BBYEGG +BF27;BF27;1108 1168 11AA;BF27;1108 1168 11AA; # (뼧; 뼧; 뼧; 뼧; 뼧; ) HANGUL SYLLABLE BBYEGS +BF28;BF28;1108 1168 11AB;BF28;1108 1168 11AB; # (뼨; 뼨; 뼨; 뼨; 뼨; ) HANGUL SYLLABLE BBYEN +BF29;BF29;1108 1168 11AC;BF29;1108 1168 11AC; # (뼩; 뼩; 뼩; 뼩; 뼩; ) HANGUL SYLLABLE BBYENJ +BF2A;BF2A;1108 1168 11AD;BF2A;1108 1168 11AD; # (뼪; 뼪; 뼪; 뼪; 뼪; ) HANGUL SYLLABLE BBYENH +BF2B;BF2B;1108 1168 11AE;BF2B;1108 1168 11AE; # (뼫; 뼫; 뼫; 뼫; 뼫; ) HANGUL SYLLABLE BBYED +BF2C;BF2C;1108 1168 11AF;BF2C;1108 1168 11AF; # (뼬; 뼬; 뼬; 뼬; 뼬; ) HANGUL SYLLABLE BBYEL +BF2D;BF2D;1108 1168 11B0;BF2D;1108 1168 11B0; # (뼭; 뼭; 뼭; 뼭; 뼭; ) HANGUL SYLLABLE BBYELG +BF2E;BF2E;1108 1168 11B1;BF2E;1108 1168 11B1; # (뼮; 뼮; 뼮; 뼮; 뼮; ) HANGUL SYLLABLE BBYELM +BF2F;BF2F;1108 1168 11B2;BF2F;1108 1168 11B2; # (뼯; 뼯; 뼯; 뼯; 뼯; ) HANGUL SYLLABLE BBYELB +BF30;BF30;1108 1168 11B3;BF30;1108 1168 11B3; # (뼰; 뼰; 뼰; 뼰; 뼰; ) HANGUL SYLLABLE BBYELS +BF31;BF31;1108 1168 11B4;BF31;1108 1168 11B4; # (뼱; 뼱; 뼱; 뼱; 뼱; ) HANGUL SYLLABLE BBYELT +BF32;BF32;1108 1168 11B5;BF32;1108 1168 11B5; # (뼲; 뼲; 뼲; 뼲; 뼲; ) HANGUL SYLLABLE BBYELP +BF33;BF33;1108 1168 11B6;BF33;1108 1168 11B6; # (뼳; 뼳; 뼳; 뼳; 뼳; ) HANGUL SYLLABLE BBYELH +BF34;BF34;1108 1168 11B7;BF34;1108 1168 11B7; # (뼴; 뼴; 뼴; 뼴; 뼴; ) HANGUL SYLLABLE BBYEM +BF35;BF35;1108 1168 11B8;BF35;1108 1168 11B8; # (뼵; 뼵; 뼵; 뼵; 뼵; ) HANGUL SYLLABLE BBYEB +BF36;BF36;1108 1168 11B9;BF36;1108 1168 11B9; # (뼶; 뼶; 뼶; 뼶; 뼶; ) HANGUL SYLLABLE BBYEBS +BF37;BF37;1108 1168 11BA;BF37;1108 1168 11BA; # (뼷; 뼷; 뼷; 뼷; 뼷; ) HANGUL SYLLABLE BBYES +BF38;BF38;1108 1168 11BB;BF38;1108 1168 11BB; # (뼸; 뼸; 뼸; 뼸; 뼸; ) HANGUL SYLLABLE BBYESS +BF39;BF39;1108 1168 11BC;BF39;1108 1168 11BC; # (뼹; 뼹; 뼹; 뼹; 뼹; ) HANGUL SYLLABLE BBYENG +BF3A;BF3A;1108 1168 11BD;BF3A;1108 1168 11BD; # (뼺; 뼺; 뼺; 뼺; 뼺; ) HANGUL SYLLABLE BBYEJ +BF3B;BF3B;1108 1168 11BE;BF3B;1108 1168 11BE; # (뼻; 뼻; 뼻; 뼻; 뼻; ) HANGUL SYLLABLE BBYEC +BF3C;BF3C;1108 1168 11BF;BF3C;1108 1168 11BF; # (뼼; 뼼; 뼼; 뼼; 뼼; ) HANGUL SYLLABLE BBYEK +BF3D;BF3D;1108 1168 11C0;BF3D;1108 1168 11C0; # (뼽; 뼽; 뼽; 뼽; 뼽; ) HANGUL SYLLABLE BBYET +BF3E;BF3E;1108 1168 11C1;BF3E;1108 1168 11C1; # (뼾; 뼾; 뼾; 뼾; 뼾; ) HANGUL SYLLABLE BBYEP +BF3F;BF3F;1108 1168 11C2;BF3F;1108 1168 11C2; # (뼿; 뼿; 뼿; 뼿; 뼿; ) HANGUL SYLLABLE BBYEH +BF40;BF40;1108 1169;BF40;1108 1169; # (뽀; 뽀; 뽀; 뽀; 뽀; ) HANGUL SYLLABLE BBO +BF41;BF41;1108 1169 11A8;BF41;1108 1169 11A8; # (뽁; 뽁; 뽁; 뽁; 뽁; ) HANGUL SYLLABLE BBOG +BF42;BF42;1108 1169 11A9;BF42;1108 1169 11A9; # (뽂; 뽂; 뽂; 뽂; 뽂; ) HANGUL SYLLABLE BBOGG +BF43;BF43;1108 1169 11AA;BF43;1108 1169 11AA; # (뽃; 뽃; 뽃; 뽃; 뽃; ) HANGUL SYLLABLE BBOGS +BF44;BF44;1108 1169 11AB;BF44;1108 1169 11AB; # (뽄; 뽄; 뽄; 뽄; 뽄; ) HANGUL SYLLABLE BBON +BF45;BF45;1108 1169 11AC;BF45;1108 1169 11AC; # (뽅; 뽅; 뽅; 뽅; 뽅; ) HANGUL SYLLABLE BBONJ +BF46;BF46;1108 1169 11AD;BF46;1108 1169 11AD; # (뽆; 뽆; 뽆; 뽆; 뽆; ) HANGUL SYLLABLE BBONH +BF47;BF47;1108 1169 11AE;BF47;1108 1169 11AE; # (뽇; 뽇; 뽇; 뽇; 뽇; ) HANGUL SYLLABLE BBOD +BF48;BF48;1108 1169 11AF;BF48;1108 1169 11AF; # (뽈; 뽈; 뽈; 뽈; 뽈; ) HANGUL SYLLABLE BBOL +BF49;BF49;1108 1169 11B0;BF49;1108 1169 11B0; # (뽉; 뽉; 뽉; 뽉; 뽉; ) HANGUL SYLLABLE BBOLG +BF4A;BF4A;1108 1169 11B1;BF4A;1108 1169 11B1; # (뽊; 뽊; 뽊; 뽊; 뽊; ) HANGUL SYLLABLE BBOLM +BF4B;BF4B;1108 1169 11B2;BF4B;1108 1169 11B2; # (뽋; 뽋; 뽋; 뽋; 뽋; ) HANGUL SYLLABLE BBOLB +BF4C;BF4C;1108 1169 11B3;BF4C;1108 1169 11B3; # (뽌; 뽌; 뽌; 뽌; 뽌; ) HANGUL SYLLABLE BBOLS +BF4D;BF4D;1108 1169 11B4;BF4D;1108 1169 11B4; # (뽍; 뽍; 뽍; 뽍; 뽍; ) HANGUL SYLLABLE BBOLT +BF4E;BF4E;1108 1169 11B5;BF4E;1108 1169 11B5; # (뽎; 뽎; 뽎; 뽎; 뽎; ) HANGUL SYLLABLE BBOLP +BF4F;BF4F;1108 1169 11B6;BF4F;1108 1169 11B6; # (뽏; 뽏; 뽏; 뽏; 뽏; ) HANGUL SYLLABLE BBOLH +BF50;BF50;1108 1169 11B7;BF50;1108 1169 11B7; # (뽐; 뽐; 뽐; 뽐; 뽐; ) HANGUL SYLLABLE BBOM +BF51;BF51;1108 1169 11B8;BF51;1108 1169 11B8; # (뽑; 뽑; 뽑; 뽑; 뽑; ) HANGUL SYLLABLE BBOB +BF52;BF52;1108 1169 11B9;BF52;1108 1169 11B9; # (뽒; 뽒; 뽒; 뽒; 뽒; ) HANGUL SYLLABLE BBOBS +BF53;BF53;1108 1169 11BA;BF53;1108 1169 11BA; # (뽓; 뽓; 뽓; 뽓; 뽓; ) HANGUL SYLLABLE BBOS +BF54;BF54;1108 1169 11BB;BF54;1108 1169 11BB; # (뽔; 뽔; 뽔; 뽔; 뽔; ) HANGUL SYLLABLE BBOSS +BF55;BF55;1108 1169 11BC;BF55;1108 1169 11BC; # (뽕; 뽕; 뽕; 뽕; 뽕; ) HANGUL SYLLABLE BBONG +BF56;BF56;1108 1169 11BD;BF56;1108 1169 11BD; # (뽖; 뽖; 뽖; 뽖; 뽖; ) HANGUL SYLLABLE BBOJ +BF57;BF57;1108 1169 11BE;BF57;1108 1169 11BE; # (뽗; 뽗; 뽗; 뽗; 뽗; ) HANGUL SYLLABLE BBOC +BF58;BF58;1108 1169 11BF;BF58;1108 1169 11BF; # (뽘; 뽘; 뽘; 뽘; 뽘; ) HANGUL SYLLABLE BBOK +BF59;BF59;1108 1169 11C0;BF59;1108 1169 11C0; # (뽙; 뽙; 뽙; 뽙; 뽙; ) HANGUL SYLLABLE BBOT +BF5A;BF5A;1108 1169 11C1;BF5A;1108 1169 11C1; # (뽚; 뽚; 뽚; 뽚; 뽚; ) HANGUL SYLLABLE BBOP +BF5B;BF5B;1108 1169 11C2;BF5B;1108 1169 11C2; # (뽛; 뽛; 뽛; 뽛; 뽛; ) HANGUL SYLLABLE BBOH +BF5C;BF5C;1108 116A;BF5C;1108 116A; # (뽜; 뽜; 뽜; 뽜; 뽜; ) HANGUL SYLLABLE BBWA +BF5D;BF5D;1108 116A 11A8;BF5D;1108 116A 11A8; # (뽝; 뽝; 뽝; 뽝; 뽝; ) HANGUL SYLLABLE BBWAG +BF5E;BF5E;1108 116A 11A9;BF5E;1108 116A 11A9; # (뽞; 뽞; 뽞; 뽞; 뽞; ) HANGUL SYLLABLE BBWAGG +BF5F;BF5F;1108 116A 11AA;BF5F;1108 116A 11AA; # (뽟; 뽟; 뽟; 뽟; 뽟; ) HANGUL SYLLABLE BBWAGS +BF60;BF60;1108 116A 11AB;BF60;1108 116A 11AB; # (뽠; 뽠; 뽠; 뽠; 뽠; ) HANGUL SYLLABLE BBWAN +BF61;BF61;1108 116A 11AC;BF61;1108 116A 11AC; # (뽡; 뽡; 뽡; 뽡; 뽡; ) HANGUL SYLLABLE BBWANJ +BF62;BF62;1108 116A 11AD;BF62;1108 116A 11AD; # (뽢; 뽢; 뽢; 뽢; 뽢; ) HANGUL SYLLABLE BBWANH +BF63;BF63;1108 116A 11AE;BF63;1108 116A 11AE; # (뽣; 뽣; 뽣; 뽣; 뽣; ) HANGUL SYLLABLE BBWAD +BF64;BF64;1108 116A 11AF;BF64;1108 116A 11AF; # (뽤; 뽤; 뽤; 뽤; 뽤; ) HANGUL SYLLABLE BBWAL +BF65;BF65;1108 116A 11B0;BF65;1108 116A 11B0; # (뽥; 뽥; 뽥; 뽥; 뽥; ) HANGUL SYLLABLE BBWALG +BF66;BF66;1108 116A 11B1;BF66;1108 116A 11B1; # (뽦; 뽦; 뽦; 뽦; 뽦; ) HANGUL SYLLABLE BBWALM +BF67;BF67;1108 116A 11B2;BF67;1108 116A 11B2; # (뽧; 뽧; 뽧; 뽧; 뽧; ) HANGUL SYLLABLE BBWALB +BF68;BF68;1108 116A 11B3;BF68;1108 116A 11B3; # (뽨; 뽨; 뽨; 뽨; 뽨; ) HANGUL SYLLABLE BBWALS +BF69;BF69;1108 116A 11B4;BF69;1108 116A 11B4; # (뽩; 뽩; 뽩; 뽩; 뽩; ) HANGUL SYLLABLE BBWALT +BF6A;BF6A;1108 116A 11B5;BF6A;1108 116A 11B5; # (뽪; 뽪; 뽪; 뽪; 뽪; ) HANGUL SYLLABLE BBWALP +BF6B;BF6B;1108 116A 11B6;BF6B;1108 116A 11B6; # (뽫; 뽫; 뽫; 뽫; 뽫; ) HANGUL SYLLABLE BBWALH +BF6C;BF6C;1108 116A 11B7;BF6C;1108 116A 11B7; # (뽬; 뽬; 뽬; 뽬; 뽬; ) HANGUL SYLLABLE BBWAM +BF6D;BF6D;1108 116A 11B8;BF6D;1108 116A 11B8; # (뽭; 뽭; 뽭; 뽭; 뽭; ) HANGUL SYLLABLE BBWAB +BF6E;BF6E;1108 116A 11B9;BF6E;1108 116A 11B9; # (뽮; 뽮; 뽮; 뽮; 뽮; ) HANGUL SYLLABLE BBWABS +BF6F;BF6F;1108 116A 11BA;BF6F;1108 116A 11BA; # (뽯; 뽯; 뽯; 뽯; 뽯; ) HANGUL SYLLABLE BBWAS +BF70;BF70;1108 116A 11BB;BF70;1108 116A 11BB; # (뽰; 뽰; 뽰; 뽰; 뽰; ) HANGUL SYLLABLE BBWASS +BF71;BF71;1108 116A 11BC;BF71;1108 116A 11BC; # (뽱; 뽱; 뽱; 뽱; 뽱; ) HANGUL SYLLABLE BBWANG +BF72;BF72;1108 116A 11BD;BF72;1108 116A 11BD; # (뽲; 뽲; 뽲; 뽲; 뽲; ) HANGUL SYLLABLE BBWAJ +BF73;BF73;1108 116A 11BE;BF73;1108 116A 11BE; # (뽳; 뽳; 뽳; 뽳; 뽳; ) HANGUL SYLLABLE BBWAC +BF74;BF74;1108 116A 11BF;BF74;1108 116A 11BF; # (뽴; 뽴; 뽴; 뽴; 뽴; ) HANGUL SYLLABLE BBWAK +BF75;BF75;1108 116A 11C0;BF75;1108 116A 11C0; # (뽵; 뽵; 뽵; 뽵; 뽵; ) HANGUL SYLLABLE BBWAT +BF76;BF76;1108 116A 11C1;BF76;1108 116A 11C1; # (뽶; 뽶; 뽶; 뽶; 뽶; ) HANGUL SYLLABLE BBWAP +BF77;BF77;1108 116A 11C2;BF77;1108 116A 11C2; # (뽷; 뽷; 뽷; 뽷; 뽷; ) HANGUL SYLLABLE BBWAH +BF78;BF78;1108 116B;BF78;1108 116B; # (뽸; 뽸; 뽸; 뽸; 뽸; ) HANGUL SYLLABLE BBWAE +BF79;BF79;1108 116B 11A8;BF79;1108 116B 11A8; # (뽹; 뽹; 뽹; 뽹; 뽹; ) HANGUL SYLLABLE BBWAEG +BF7A;BF7A;1108 116B 11A9;BF7A;1108 116B 11A9; # (뽺; 뽺; 뽺; 뽺; 뽺; ) HANGUL SYLLABLE BBWAEGG +BF7B;BF7B;1108 116B 11AA;BF7B;1108 116B 11AA; # (뽻; 뽻; 뽻; 뽻; 뽻; ) HANGUL SYLLABLE BBWAEGS +BF7C;BF7C;1108 116B 11AB;BF7C;1108 116B 11AB; # (뽼; 뽼; 뽼; 뽼; 뽼; ) HANGUL SYLLABLE BBWAEN +BF7D;BF7D;1108 116B 11AC;BF7D;1108 116B 11AC; # (뽽; 뽽; 뽽; 뽽; 뽽; ) HANGUL SYLLABLE BBWAENJ +BF7E;BF7E;1108 116B 11AD;BF7E;1108 116B 11AD; # (뽾; 뽾; 뽾; 뽾; 뽾; ) HANGUL SYLLABLE BBWAENH +BF7F;BF7F;1108 116B 11AE;BF7F;1108 116B 11AE; # (뽿; 뽿; 뽿; 뽿; 뽿; ) HANGUL SYLLABLE BBWAED +BF80;BF80;1108 116B 11AF;BF80;1108 116B 11AF; # (뾀; 뾀; 뾀; 뾀; 뾀; ) HANGUL SYLLABLE BBWAEL +BF81;BF81;1108 116B 11B0;BF81;1108 116B 11B0; # (뾁; 뾁; 뾁; 뾁; 뾁; ) HANGUL SYLLABLE BBWAELG +BF82;BF82;1108 116B 11B1;BF82;1108 116B 11B1; # (뾂; 뾂; 뾂; 뾂; 뾂; ) HANGUL SYLLABLE BBWAELM +BF83;BF83;1108 116B 11B2;BF83;1108 116B 11B2; # (뾃; 뾃; 뾃; 뾃; 뾃; ) HANGUL SYLLABLE BBWAELB +BF84;BF84;1108 116B 11B3;BF84;1108 116B 11B3; # (뾄; 뾄; 뾄; 뾄; 뾄; ) HANGUL SYLLABLE BBWAELS +BF85;BF85;1108 116B 11B4;BF85;1108 116B 11B4; # (뾅; 뾅; 뾅; 뾅; 뾅; ) HANGUL SYLLABLE BBWAELT +BF86;BF86;1108 116B 11B5;BF86;1108 116B 11B5; # (뾆; 뾆; 뾆; 뾆; 뾆; ) HANGUL SYLLABLE BBWAELP +BF87;BF87;1108 116B 11B6;BF87;1108 116B 11B6; # (뾇; 뾇; 뾇; 뾇; 뾇; ) HANGUL SYLLABLE BBWAELH +BF88;BF88;1108 116B 11B7;BF88;1108 116B 11B7; # (뾈; 뾈; 뾈; 뾈; 뾈; ) HANGUL SYLLABLE BBWAEM +BF89;BF89;1108 116B 11B8;BF89;1108 116B 11B8; # (뾉; 뾉; 뾉; 뾉; 뾉; ) HANGUL SYLLABLE BBWAEB +BF8A;BF8A;1108 116B 11B9;BF8A;1108 116B 11B9; # (뾊; 뾊; 뾊; 뾊; 뾊; ) HANGUL SYLLABLE BBWAEBS +BF8B;BF8B;1108 116B 11BA;BF8B;1108 116B 11BA; # (뾋; 뾋; 뾋; 뾋; 뾋; ) HANGUL SYLLABLE BBWAES +BF8C;BF8C;1108 116B 11BB;BF8C;1108 116B 11BB; # (뾌; 뾌; 뾌; 뾌; 뾌; ) HANGUL SYLLABLE BBWAESS +BF8D;BF8D;1108 116B 11BC;BF8D;1108 116B 11BC; # (뾍; 뾍; 뾍; 뾍; 뾍; ) HANGUL SYLLABLE BBWAENG +BF8E;BF8E;1108 116B 11BD;BF8E;1108 116B 11BD; # (뾎; 뾎; 뾎; 뾎; 뾎; ) HANGUL SYLLABLE BBWAEJ +BF8F;BF8F;1108 116B 11BE;BF8F;1108 116B 11BE; # (뾏; 뾏; 뾏; 뾏; 뾏; ) HANGUL SYLLABLE BBWAEC +BF90;BF90;1108 116B 11BF;BF90;1108 116B 11BF; # (뾐; 뾐; 뾐; 뾐; 뾐; ) HANGUL SYLLABLE BBWAEK +BF91;BF91;1108 116B 11C0;BF91;1108 116B 11C0; # (뾑; 뾑; 뾑; 뾑; 뾑; ) HANGUL SYLLABLE BBWAET +BF92;BF92;1108 116B 11C1;BF92;1108 116B 11C1; # (뾒; 뾒; 뾒; 뾒; 뾒; ) HANGUL SYLLABLE BBWAEP +BF93;BF93;1108 116B 11C2;BF93;1108 116B 11C2; # (뾓; 뾓; 뾓; 뾓; 뾓; ) HANGUL SYLLABLE BBWAEH +BF94;BF94;1108 116C;BF94;1108 116C; # (뾔; 뾔; 뾔; 뾔; 뾔; ) HANGUL SYLLABLE BBOE +BF95;BF95;1108 116C 11A8;BF95;1108 116C 11A8; # (뾕; 뾕; 뾕; 뾕; 뾕; ) HANGUL SYLLABLE BBOEG +BF96;BF96;1108 116C 11A9;BF96;1108 116C 11A9; # (뾖; 뾖; 뾖; 뾖; 뾖; ) HANGUL SYLLABLE BBOEGG +BF97;BF97;1108 116C 11AA;BF97;1108 116C 11AA; # (뾗; 뾗; 뾗; 뾗; 뾗; ) HANGUL SYLLABLE BBOEGS +BF98;BF98;1108 116C 11AB;BF98;1108 116C 11AB; # (뾘; 뾘; 뾘; 뾘; 뾘; ) HANGUL SYLLABLE BBOEN +BF99;BF99;1108 116C 11AC;BF99;1108 116C 11AC; # (뾙; 뾙; 뾙; 뾙; 뾙; ) HANGUL SYLLABLE BBOENJ +BF9A;BF9A;1108 116C 11AD;BF9A;1108 116C 11AD; # (뾚; 뾚; 뾚; 뾚; 뾚; ) HANGUL SYLLABLE BBOENH +BF9B;BF9B;1108 116C 11AE;BF9B;1108 116C 11AE; # (뾛; 뾛; 뾛; 뾛; 뾛; ) HANGUL SYLLABLE BBOED +BF9C;BF9C;1108 116C 11AF;BF9C;1108 116C 11AF; # (뾜; 뾜; 뾜; 뾜; 뾜; ) HANGUL SYLLABLE BBOEL +BF9D;BF9D;1108 116C 11B0;BF9D;1108 116C 11B0; # (뾝; 뾝; 뾝; 뾝; 뾝; ) HANGUL SYLLABLE BBOELG +BF9E;BF9E;1108 116C 11B1;BF9E;1108 116C 11B1; # (뾞; 뾞; 뾞; 뾞; 뾞; ) HANGUL SYLLABLE BBOELM +BF9F;BF9F;1108 116C 11B2;BF9F;1108 116C 11B2; # (뾟; 뾟; 뾟; 뾟; 뾟; ) HANGUL SYLLABLE BBOELB +BFA0;BFA0;1108 116C 11B3;BFA0;1108 116C 11B3; # (뾠; 뾠; 뾠; 뾠; 뾠; ) HANGUL SYLLABLE BBOELS +BFA1;BFA1;1108 116C 11B4;BFA1;1108 116C 11B4; # (뾡; 뾡; 뾡; 뾡; 뾡; ) HANGUL SYLLABLE BBOELT +BFA2;BFA2;1108 116C 11B5;BFA2;1108 116C 11B5; # (뾢; 뾢; 뾢; 뾢; 뾢; ) HANGUL SYLLABLE BBOELP +BFA3;BFA3;1108 116C 11B6;BFA3;1108 116C 11B6; # (뾣; 뾣; 뾣; 뾣; 뾣; ) HANGUL SYLLABLE BBOELH +BFA4;BFA4;1108 116C 11B7;BFA4;1108 116C 11B7; # (뾤; 뾤; 뾤; 뾤; 뾤; ) HANGUL SYLLABLE BBOEM +BFA5;BFA5;1108 116C 11B8;BFA5;1108 116C 11B8; # (뾥; 뾥; 뾥; 뾥; 뾥; ) HANGUL SYLLABLE BBOEB +BFA6;BFA6;1108 116C 11B9;BFA6;1108 116C 11B9; # (뾦; 뾦; 뾦; 뾦; 뾦; ) HANGUL SYLLABLE BBOEBS +BFA7;BFA7;1108 116C 11BA;BFA7;1108 116C 11BA; # (뾧; 뾧; 뾧; 뾧; 뾧; ) HANGUL SYLLABLE BBOES +BFA8;BFA8;1108 116C 11BB;BFA8;1108 116C 11BB; # (뾨; 뾨; 뾨; 뾨; 뾨; ) HANGUL SYLLABLE BBOESS +BFA9;BFA9;1108 116C 11BC;BFA9;1108 116C 11BC; # (뾩; 뾩; 뾩; 뾩; 뾩; ) HANGUL SYLLABLE BBOENG +BFAA;BFAA;1108 116C 11BD;BFAA;1108 116C 11BD; # (뾪; 뾪; 뾪; 뾪; 뾪; ) HANGUL SYLLABLE BBOEJ +BFAB;BFAB;1108 116C 11BE;BFAB;1108 116C 11BE; # (뾫; 뾫; 뾫; 뾫; 뾫; ) HANGUL SYLLABLE BBOEC +BFAC;BFAC;1108 116C 11BF;BFAC;1108 116C 11BF; # (뾬; 뾬; 뾬; 뾬; 뾬; ) HANGUL SYLLABLE BBOEK +BFAD;BFAD;1108 116C 11C0;BFAD;1108 116C 11C0; # (뾭; 뾭; 뾭; 뾭; 뾭; ) HANGUL SYLLABLE BBOET +BFAE;BFAE;1108 116C 11C1;BFAE;1108 116C 11C1; # (뾮; 뾮; 뾮; 뾮; 뾮; ) HANGUL SYLLABLE BBOEP +BFAF;BFAF;1108 116C 11C2;BFAF;1108 116C 11C2; # (뾯; 뾯; 뾯; 뾯; 뾯; ) HANGUL SYLLABLE BBOEH +BFB0;BFB0;1108 116D;BFB0;1108 116D; # (뾰; 뾰; 뾰; 뾰; 뾰; ) HANGUL SYLLABLE BBYO +BFB1;BFB1;1108 116D 11A8;BFB1;1108 116D 11A8; # (뾱; 뾱; 뾱; 뾱; 뾱; ) HANGUL SYLLABLE BBYOG +BFB2;BFB2;1108 116D 11A9;BFB2;1108 116D 11A9; # (뾲; 뾲; 뾲; 뾲; 뾲; ) HANGUL SYLLABLE BBYOGG +BFB3;BFB3;1108 116D 11AA;BFB3;1108 116D 11AA; # (뾳; 뾳; 뾳; 뾳; 뾳; ) HANGUL SYLLABLE BBYOGS +BFB4;BFB4;1108 116D 11AB;BFB4;1108 116D 11AB; # (뾴; 뾴; 뾴; 뾴; 뾴; ) HANGUL SYLLABLE BBYON +BFB5;BFB5;1108 116D 11AC;BFB5;1108 116D 11AC; # (뾵; 뾵; 뾵; 뾵; 뾵; ) HANGUL SYLLABLE BBYONJ +BFB6;BFB6;1108 116D 11AD;BFB6;1108 116D 11AD; # (뾶; 뾶; 뾶; 뾶; 뾶; ) HANGUL SYLLABLE BBYONH +BFB7;BFB7;1108 116D 11AE;BFB7;1108 116D 11AE; # (뾷; 뾷; 뾷; 뾷; 뾷; ) HANGUL SYLLABLE BBYOD +BFB8;BFB8;1108 116D 11AF;BFB8;1108 116D 11AF; # (뾸; 뾸; 뾸; 뾸; 뾸; ) HANGUL SYLLABLE BBYOL +BFB9;BFB9;1108 116D 11B0;BFB9;1108 116D 11B0; # (뾹; 뾹; 뾹; 뾹; 뾹; ) HANGUL SYLLABLE BBYOLG +BFBA;BFBA;1108 116D 11B1;BFBA;1108 116D 11B1; # (뾺; 뾺; 뾺; 뾺; 뾺; ) HANGUL SYLLABLE BBYOLM +BFBB;BFBB;1108 116D 11B2;BFBB;1108 116D 11B2; # (뾻; 뾻; 뾻; 뾻; 뾻; ) HANGUL SYLLABLE BBYOLB +BFBC;BFBC;1108 116D 11B3;BFBC;1108 116D 11B3; # (뾼; 뾼; 뾼; 뾼; 뾼; ) HANGUL SYLLABLE BBYOLS +BFBD;BFBD;1108 116D 11B4;BFBD;1108 116D 11B4; # (뾽; 뾽; 뾽; 뾽; 뾽; ) HANGUL SYLLABLE BBYOLT +BFBE;BFBE;1108 116D 11B5;BFBE;1108 116D 11B5; # (뾾; 뾾; 뾾; 뾾; 뾾; ) HANGUL SYLLABLE BBYOLP +BFBF;BFBF;1108 116D 11B6;BFBF;1108 116D 11B6; # (뾿; 뾿; 뾿; 뾿; 뾿; ) HANGUL SYLLABLE BBYOLH +BFC0;BFC0;1108 116D 11B7;BFC0;1108 116D 11B7; # (뿀; 뿀; 뿀; 뿀; 뿀; ) HANGUL SYLLABLE BBYOM +BFC1;BFC1;1108 116D 11B8;BFC1;1108 116D 11B8; # (뿁; 뿁; 뿁; 뿁; 뿁; ) HANGUL SYLLABLE BBYOB +BFC2;BFC2;1108 116D 11B9;BFC2;1108 116D 11B9; # (뿂; 뿂; 뿂; 뿂; 뿂; ) HANGUL SYLLABLE BBYOBS +BFC3;BFC3;1108 116D 11BA;BFC3;1108 116D 11BA; # (뿃; 뿃; 뿃; 뿃; 뿃; ) HANGUL SYLLABLE BBYOS +BFC4;BFC4;1108 116D 11BB;BFC4;1108 116D 11BB; # (뿄; 뿄; 뿄; 뿄; 뿄; ) HANGUL SYLLABLE BBYOSS +BFC5;BFC5;1108 116D 11BC;BFC5;1108 116D 11BC; # (뿅; 뿅; 뿅; 뿅; 뿅; ) HANGUL SYLLABLE BBYONG +BFC6;BFC6;1108 116D 11BD;BFC6;1108 116D 11BD; # (뿆; 뿆; 뿆; 뿆; 뿆; ) HANGUL SYLLABLE BBYOJ +BFC7;BFC7;1108 116D 11BE;BFC7;1108 116D 11BE; # (뿇; 뿇; 뿇; 뿇; 뿇; ) HANGUL SYLLABLE BBYOC +BFC8;BFC8;1108 116D 11BF;BFC8;1108 116D 11BF; # (뿈; 뿈; 뿈; 뿈; 뿈; ) HANGUL SYLLABLE BBYOK +BFC9;BFC9;1108 116D 11C0;BFC9;1108 116D 11C0; # (뿉; 뿉; 뿉; 뿉; 뿉; ) HANGUL SYLLABLE BBYOT +BFCA;BFCA;1108 116D 11C1;BFCA;1108 116D 11C1; # (뿊; 뿊; 뿊; 뿊; 뿊; ) HANGUL SYLLABLE BBYOP +BFCB;BFCB;1108 116D 11C2;BFCB;1108 116D 11C2; # (뿋; 뿋; 뿋; 뿋; 뿋; ) HANGUL SYLLABLE BBYOH +BFCC;BFCC;1108 116E;BFCC;1108 116E; # (뿌; 뿌; 뿌; 뿌; 뿌; ) HANGUL SYLLABLE BBU +BFCD;BFCD;1108 116E 11A8;BFCD;1108 116E 11A8; # (뿍; 뿍; 뿍; 뿍; 뿍; ) HANGUL SYLLABLE BBUG +BFCE;BFCE;1108 116E 11A9;BFCE;1108 116E 11A9; # (뿎; 뿎; 뿎; 뿎; 뿎; ) HANGUL SYLLABLE BBUGG +BFCF;BFCF;1108 116E 11AA;BFCF;1108 116E 11AA; # (뿏; 뿏; 뿏; 뿏; 뿏; ) HANGUL SYLLABLE BBUGS +BFD0;BFD0;1108 116E 11AB;BFD0;1108 116E 11AB; # (뿐; 뿐; 뿐; 뿐; 뿐; ) HANGUL SYLLABLE BBUN +BFD1;BFD1;1108 116E 11AC;BFD1;1108 116E 11AC; # (뿑; 뿑; 뿑; 뿑; 뿑; ) HANGUL SYLLABLE BBUNJ +BFD2;BFD2;1108 116E 11AD;BFD2;1108 116E 11AD; # (뿒; 뿒; 뿒; 뿒; 뿒; ) HANGUL SYLLABLE BBUNH +BFD3;BFD3;1108 116E 11AE;BFD3;1108 116E 11AE; # (뿓; 뿓; 뿓; 뿓; 뿓; ) HANGUL SYLLABLE BBUD +BFD4;BFD4;1108 116E 11AF;BFD4;1108 116E 11AF; # (뿔; 뿔; 뿔; 뿔; 뿔; ) HANGUL SYLLABLE BBUL +BFD5;BFD5;1108 116E 11B0;BFD5;1108 116E 11B0; # (뿕; 뿕; 뿕; 뿕; 뿕; ) HANGUL SYLLABLE BBULG +BFD6;BFD6;1108 116E 11B1;BFD6;1108 116E 11B1; # (뿖; 뿖; 뿖; 뿖; 뿖; ) HANGUL SYLLABLE BBULM +BFD7;BFD7;1108 116E 11B2;BFD7;1108 116E 11B2; # (뿗; 뿗; 뿗; 뿗; 뿗; ) HANGUL SYLLABLE BBULB +BFD8;BFD8;1108 116E 11B3;BFD8;1108 116E 11B3; # (뿘; 뿘; 뿘; 뿘; 뿘; ) HANGUL SYLLABLE BBULS +BFD9;BFD9;1108 116E 11B4;BFD9;1108 116E 11B4; # (뿙; 뿙; 뿙; 뿙; 뿙; ) HANGUL SYLLABLE BBULT +BFDA;BFDA;1108 116E 11B5;BFDA;1108 116E 11B5; # (뿚; 뿚; 뿚; 뿚; 뿚; ) HANGUL SYLLABLE BBULP +BFDB;BFDB;1108 116E 11B6;BFDB;1108 116E 11B6; # (뿛; 뿛; 뿛; 뿛; 뿛; ) HANGUL SYLLABLE BBULH +BFDC;BFDC;1108 116E 11B7;BFDC;1108 116E 11B7; # (뿜; 뿜; 뿜; 뿜; 뿜; ) HANGUL SYLLABLE BBUM +BFDD;BFDD;1108 116E 11B8;BFDD;1108 116E 11B8; # (뿝; 뿝; 뿝; 뿝; 뿝; ) HANGUL SYLLABLE BBUB +BFDE;BFDE;1108 116E 11B9;BFDE;1108 116E 11B9; # (뿞; 뿞; 뿞; 뿞; 뿞; ) HANGUL SYLLABLE BBUBS +BFDF;BFDF;1108 116E 11BA;BFDF;1108 116E 11BA; # (뿟; 뿟; 뿟; 뿟; 뿟; ) HANGUL SYLLABLE BBUS +BFE0;BFE0;1108 116E 11BB;BFE0;1108 116E 11BB; # (뿠; 뿠; 뿠; 뿠; 뿠; ) HANGUL SYLLABLE BBUSS +BFE1;BFE1;1108 116E 11BC;BFE1;1108 116E 11BC; # (뿡; 뿡; 뿡; 뿡; 뿡; ) HANGUL SYLLABLE BBUNG +BFE2;BFE2;1108 116E 11BD;BFE2;1108 116E 11BD; # (뿢; 뿢; 뿢; 뿢; 뿢; ) HANGUL SYLLABLE BBUJ +BFE3;BFE3;1108 116E 11BE;BFE3;1108 116E 11BE; # (뿣; 뿣; 뿣; 뿣; 뿣; ) HANGUL SYLLABLE BBUC +BFE4;BFE4;1108 116E 11BF;BFE4;1108 116E 11BF; # (뿤; 뿤; 뿤; 뿤; 뿤; ) HANGUL SYLLABLE BBUK +BFE5;BFE5;1108 116E 11C0;BFE5;1108 116E 11C0; # (뿥; 뿥; 뿥; 뿥; 뿥; ) HANGUL SYLLABLE BBUT +BFE6;BFE6;1108 116E 11C1;BFE6;1108 116E 11C1; # (뿦; 뿦; 뿦; 뿦; 뿦; ) HANGUL SYLLABLE BBUP +BFE7;BFE7;1108 116E 11C2;BFE7;1108 116E 11C2; # (뿧; 뿧; 뿧; 뿧; 뿧; ) HANGUL SYLLABLE BBUH +BFE8;BFE8;1108 116F;BFE8;1108 116F; # (뿨; 뿨; 뿨; 뿨; 뿨; ) HANGUL SYLLABLE BBWEO +BFE9;BFE9;1108 116F 11A8;BFE9;1108 116F 11A8; # (뿩; 뿩; 뿩; 뿩; 뿩; ) HANGUL SYLLABLE BBWEOG +BFEA;BFEA;1108 116F 11A9;BFEA;1108 116F 11A9; # (뿪; 뿪; 뿪; 뿪; 뿪; ) HANGUL SYLLABLE BBWEOGG +BFEB;BFEB;1108 116F 11AA;BFEB;1108 116F 11AA; # (뿫; 뿫; 뿫; 뿫; 뿫; ) HANGUL SYLLABLE BBWEOGS +BFEC;BFEC;1108 116F 11AB;BFEC;1108 116F 11AB; # (뿬; 뿬; 뿬; 뿬; 뿬; ) HANGUL SYLLABLE BBWEON +BFED;BFED;1108 116F 11AC;BFED;1108 116F 11AC; # (뿭; 뿭; 뿭; 뿭; 뿭; ) HANGUL SYLLABLE BBWEONJ +BFEE;BFEE;1108 116F 11AD;BFEE;1108 116F 11AD; # (뿮; 뿮; 뿮; 뿮; 뿮; ) HANGUL SYLLABLE BBWEONH +BFEF;BFEF;1108 116F 11AE;BFEF;1108 116F 11AE; # (뿯; 뿯; 뿯; 뿯; 뿯; ) HANGUL SYLLABLE BBWEOD +BFF0;BFF0;1108 116F 11AF;BFF0;1108 116F 11AF; # (뿰; 뿰; 뿰; 뿰; 뿰; ) HANGUL SYLLABLE BBWEOL +BFF1;BFF1;1108 116F 11B0;BFF1;1108 116F 11B0; # (뿱; 뿱; 뿱; 뿱; 뿱; ) HANGUL SYLLABLE BBWEOLG +BFF2;BFF2;1108 116F 11B1;BFF2;1108 116F 11B1; # (뿲; 뿲; 뿲; 뿲; 뿲; ) HANGUL SYLLABLE BBWEOLM +BFF3;BFF3;1108 116F 11B2;BFF3;1108 116F 11B2; # (뿳; 뿳; 뿳; 뿳; 뿳; ) HANGUL SYLLABLE BBWEOLB +BFF4;BFF4;1108 116F 11B3;BFF4;1108 116F 11B3; # (뿴; 뿴; 뿴; 뿴; 뿴; ) HANGUL SYLLABLE BBWEOLS +BFF5;BFF5;1108 116F 11B4;BFF5;1108 116F 11B4; # (뿵; 뿵; 뿵; 뿵; 뿵; ) HANGUL SYLLABLE BBWEOLT +BFF6;BFF6;1108 116F 11B5;BFF6;1108 116F 11B5; # (뿶; 뿶; 뿶; 뿶; 뿶; ) HANGUL SYLLABLE BBWEOLP +BFF7;BFF7;1108 116F 11B6;BFF7;1108 116F 11B6; # (뿷; 뿷; 뿷; 뿷; 뿷; ) HANGUL SYLLABLE BBWEOLH +BFF8;BFF8;1108 116F 11B7;BFF8;1108 116F 11B7; # (뿸; 뿸; 뿸; 뿸; 뿸; ) HANGUL SYLLABLE BBWEOM +BFF9;BFF9;1108 116F 11B8;BFF9;1108 116F 11B8; # (뿹; 뿹; 뿹; 뿹; 뿹; ) HANGUL SYLLABLE BBWEOB +BFFA;BFFA;1108 116F 11B9;BFFA;1108 116F 11B9; # (뿺; 뿺; 뿺; 뿺; 뿺; ) HANGUL SYLLABLE BBWEOBS +BFFB;BFFB;1108 116F 11BA;BFFB;1108 116F 11BA; # (뿻; 뿻; 뿻; 뿻; 뿻; ) HANGUL SYLLABLE BBWEOS +BFFC;BFFC;1108 116F 11BB;BFFC;1108 116F 11BB; # (뿼; 뿼; 뿼; 뿼; 뿼; ) HANGUL SYLLABLE BBWEOSS +BFFD;BFFD;1108 116F 11BC;BFFD;1108 116F 11BC; # (뿽; 뿽; 뿽; 뿽; 뿽; ) HANGUL SYLLABLE BBWEONG +BFFE;BFFE;1108 116F 11BD;BFFE;1108 116F 11BD; # (뿾; 뿾; 뿾; 뿾; 뿾; ) HANGUL SYLLABLE BBWEOJ +BFFF;BFFF;1108 116F 11BE;BFFF;1108 116F 11BE; # (뿿; 뿿; 뿿; 뿿; 뿿; ) HANGUL SYLLABLE BBWEOC +C000;C000;1108 116F 11BF;C000;1108 116F 11BF; # (쀀; 쀀; 쀀; 쀀; 쀀; ) HANGUL SYLLABLE BBWEOK +C001;C001;1108 116F 11C0;C001;1108 116F 11C0; # (쀁; 쀁; 쀁; 쀁; 쀁; ) HANGUL SYLLABLE BBWEOT +C002;C002;1108 116F 11C1;C002;1108 116F 11C1; # (쀂; 쀂; 쀂; 쀂; 쀂; ) HANGUL SYLLABLE BBWEOP +C003;C003;1108 116F 11C2;C003;1108 116F 11C2; # (쀃; 쀃; 쀃; 쀃; 쀃; ) HANGUL SYLLABLE BBWEOH +C004;C004;1108 1170;C004;1108 1170; # (쀄; 쀄; 쀄; 쀄; 쀄; ) HANGUL SYLLABLE BBWE +C005;C005;1108 1170 11A8;C005;1108 1170 11A8; # (쀅; 쀅; 쀅; 쀅; 쀅; ) HANGUL SYLLABLE BBWEG +C006;C006;1108 1170 11A9;C006;1108 1170 11A9; # (쀆; 쀆; 쀆; 쀆; 쀆; ) HANGUL SYLLABLE BBWEGG +C007;C007;1108 1170 11AA;C007;1108 1170 11AA; # (쀇; 쀇; 쀇; 쀇; 쀇; ) HANGUL SYLLABLE BBWEGS +C008;C008;1108 1170 11AB;C008;1108 1170 11AB; # (쀈; 쀈; 쀈; 쀈; 쀈; ) HANGUL SYLLABLE BBWEN +C009;C009;1108 1170 11AC;C009;1108 1170 11AC; # (쀉; 쀉; 쀉; 쀉; 쀉; ) HANGUL SYLLABLE BBWENJ +C00A;C00A;1108 1170 11AD;C00A;1108 1170 11AD; # (쀊; 쀊; 쀊; 쀊; 쀊; ) HANGUL SYLLABLE BBWENH +C00B;C00B;1108 1170 11AE;C00B;1108 1170 11AE; # (쀋; 쀋; 쀋; 쀋; 쀋; ) HANGUL SYLLABLE BBWED +C00C;C00C;1108 1170 11AF;C00C;1108 1170 11AF; # (쀌; 쀌; 쀌; 쀌; 쀌; ) HANGUL SYLLABLE BBWEL +C00D;C00D;1108 1170 11B0;C00D;1108 1170 11B0; # (쀍; 쀍; 쀍; 쀍; 쀍; ) HANGUL SYLLABLE BBWELG +C00E;C00E;1108 1170 11B1;C00E;1108 1170 11B1; # (쀎; 쀎; 쀎; 쀎; 쀎; ) HANGUL SYLLABLE BBWELM +C00F;C00F;1108 1170 11B2;C00F;1108 1170 11B2; # (쀏; 쀏; 쀏; 쀏; 쀏; ) HANGUL SYLLABLE BBWELB +C010;C010;1108 1170 11B3;C010;1108 1170 11B3; # (쀐; 쀐; 쀐; 쀐; 쀐; ) HANGUL SYLLABLE BBWELS +C011;C011;1108 1170 11B4;C011;1108 1170 11B4; # (쀑; 쀑; 쀑; 쀑; 쀑; ) HANGUL SYLLABLE BBWELT +C012;C012;1108 1170 11B5;C012;1108 1170 11B5; # (쀒; 쀒; 쀒; 쀒; 쀒; ) HANGUL SYLLABLE BBWELP +C013;C013;1108 1170 11B6;C013;1108 1170 11B6; # (쀓; 쀓; 쀓; 쀓; 쀓; ) HANGUL SYLLABLE BBWELH +C014;C014;1108 1170 11B7;C014;1108 1170 11B7; # (쀔; 쀔; 쀔; 쀔; 쀔; ) HANGUL SYLLABLE BBWEM +C015;C015;1108 1170 11B8;C015;1108 1170 11B8; # (쀕; 쀕; 쀕; 쀕; 쀕; ) HANGUL SYLLABLE BBWEB +C016;C016;1108 1170 11B9;C016;1108 1170 11B9; # (쀖; 쀖; 쀖; 쀖; 쀖; ) HANGUL SYLLABLE BBWEBS +C017;C017;1108 1170 11BA;C017;1108 1170 11BA; # (쀗; 쀗; 쀗; 쀗; 쀗; ) HANGUL SYLLABLE BBWES +C018;C018;1108 1170 11BB;C018;1108 1170 11BB; # (쀘; 쀘; 쀘; 쀘; 쀘; ) HANGUL SYLLABLE BBWESS +C019;C019;1108 1170 11BC;C019;1108 1170 11BC; # (쀙; 쀙; 쀙; 쀙; 쀙; ) HANGUL SYLLABLE BBWENG +C01A;C01A;1108 1170 11BD;C01A;1108 1170 11BD; # (쀚; 쀚; 쀚; 쀚; 쀚; ) HANGUL SYLLABLE BBWEJ +C01B;C01B;1108 1170 11BE;C01B;1108 1170 11BE; # (쀛; 쀛; 쀛; 쀛; 쀛; ) HANGUL SYLLABLE BBWEC +C01C;C01C;1108 1170 11BF;C01C;1108 1170 11BF; # (쀜; 쀜; 쀜; 쀜; 쀜; ) HANGUL SYLLABLE BBWEK +C01D;C01D;1108 1170 11C0;C01D;1108 1170 11C0; # (쀝; 쀝; 쀝; 쀝; 쀝; ) HANGUL SYLLABLE BBWET +C01E;C01E;1108 1170 11C1;C01E;1108 1170 11C1; # (쀞; 쀞; 쀞; 쀞; 쀞; ) HANGUL SYLLABLE BBWEP +C01F;C01F;1108 1170 11C2;C01F;1108 1170 11C2; # (쀟; 쀟; 쀟; 쀟; 쀟; ) HANGUL SYLLABLE BBWEH +C020;C020;1108 1171;C020;1108 1171; # (쀠; 쀠; 쀠; 쀠; 쀠; ) HANGUL SYLLABLE BBWI +C021;C021;1108 1171 11A8;C021;1108 1171 11A8; # (쀡; 쀡; 쀡; 쀡; 쀡; ) HANGUL SYLLABLE BBWIG +C022;C022;1108 1171 11A9;C022;1108 1171 11A9; # (쀢; 쀢; 쀢; 쀢; 쀢; ) HANGUL SYLLABLE BBWIGG +C023;C023;1108 1171 11AA;C023;1108 1171 11AA; # (쀣; 쀣; 쀣; 쀣; 쀣; ) HANGUL SYLLABLE BBWIGS +C024;C024;1108 1171 11AB;C024;1108 1171 11AB; # (쀤; 쀤; 쀤; 쀤; 쀤; ) HANGUL SYLLABLE BBWIN +C025;C025;1108 1171 11AC;C025;1108 1171 11AC; # (쀥; 쀥; 쀥; 쀥; 쀥; ) HANGUL SYLLABLE BBWINJ +C026;C026;1108 1171 11AD;C026;1108 1171 11AD; # (쀦; 쀦; 쀦; 쀦; 쀦; ) HANGUL SYLLABLE BBWINH +C027;C027;1108 1171 11AE;C027;1108 1171 11AE; # (쀧; 쀧; 쀧; 쀧; 쀧; ) HANGUL SYLLABLE BBWID +C028;C028;1108 1171 11AF;C028;1108 1171 11AF; # (쀨; 쀨; 쀨; 쀨; 쀨; ) HANGUL SYLLABLE BBWIL +C029;C029;1108 1171 11B0;C029;1108 1171 11B0; # (쀩; 쀩; 쀩; 쀩; 쀩; ) HANGUL SYLLABLE BBWILG +C02A;C02A;1108 1171 11B1;C02A;1108 1171 11B1; # (쀪; 쀪; 쀪; 쀪; 쀪; ) HANGUL SYLLABLE BBWILM +C02B;C02B;1108 1171 11B2;C02B;1108 1171 11B2; # (쀫; 쀫; 쀫; 쀫; 쀫; ) HANGUL SYLLABLE BBWILB +C02C;C02C;1108 1171 11B3;C02C;1108 1171 11B3; # (쀬; 쀬; 쀬; 쀬; 쀬; ) HANGUL SYLLABLE BBWILS +C02D;C02D;1108 1171 11B4;C02D;1108 1171 11B4; # (쀭; 쀭; 쀭; 쀭; 쀭; ) HANGUL SYLLABLE BBWILT +C02E;C02E;1108 1171 11B5;C02E;1108 1171 11B5; # (쀮; 쀮; 쀮; 쀮; 쀮; ) HANGUL SYLLABLE BBWILP +C02F;C02F;1108 1171 11B6;C02F;1108 1171 11B6; # (쀯; 쀯; 쀯; 쀯; 쀯; ) HANGUL SYLLABLE BBWILH +C030;C030;1108 1171 11B7;C030;1108 1171 11B7; # (쀰; 쀰; 쀰; 쀰; 쀰; ) HANGUL SYLLABLE BBWIM +C031;C031;1108 1171 11B8;C031;1108 1171 11B8; # (쀱; 쀱; 쀱; 쀱; 쀱; ) HANGUL SYLLABLE BBWIB +C032;C032;1108 1171 11B9;C032;1108 1171 11B9; # (쀲; 쀲; 쀲; 쀲; 쀲; ) HANGUL SYLLABLE BBWIBS +C033;C033;1108 1171 11BA;C033;1108 1171 11BA; # (쀳; 쀳; 쀳; 쀳; 쀳; ) HANGUL SYLLABLE BBWIS +C034;C034;1108 1171 11BB;C034;1108 1171 11BB; # (쀴; 쀴; 쀴; 쀴; 쀴; ) HANGUL SYLLABLE BBWISS +C035;C035;1108 1171 11BC;C035;1108 1171 11BC; # (쀵; 쀵; 쀵; 쀵; 쀵; ) HANGUL SYLLABLE BBWING +C036;C036;1108 1171 11BD;C036;1108 1171 11BD; # (쀶; 쀶; 쀶; 쀶; 쀶; ) HANGUL SYLLABLE BBWIJ +C037;C037;1108 1171 11BE;C037;1108 1171 11BE; # (쀷; 쀷; 쀷; 쀷; 쀷; ) HANGUL SYLLABLE BBWIC +C038;C038;1108 1171 11BF;C038;1108 1171 11BF; # (쀸; 쀸; 쀸; 쀸; 쀸; ) HANGUL SYLLABLE BBWIK +C039;C039;1108 1171 11C0;C039;1108 1171 11C0; # (쀹; 쀹; 쀹; 쀹; 쀹; ) HANGUL SYLLABLE BBWIT +C03A;C03A;1108 1171 11C1;C03A;1108 1171 11C1; # (쀺; 쀺; 쀺; 쀺; 쀺; ) HANGUL SYLLABLE BBWIP +C03B;C03B;1108 1171 11C2;C03B;1108 1171 11C2; # (쀻; 쀻; 쀻; 쀻; 쀻; ) HANGUL SYLLABLE BBWIH +C03C;C03C;1108 1172;C03C;1108 1172; # (쀼; 쀼; 쀼; 쀼; 쀼; ) HANGUL SYLLABLE BBYU +C03D;C03D;1108 1172 11A8;C03D;1108 1172 11A8; # (쀽; 쀽; 쀽; 쀽; 쀽; ) HANGUL SYLLABLE BBYUG +C03E;C03E;1108 1172 11A9;C03E;1108 1172 11A9; # (쀾; 쀾; 쀾; 쀾; 쀾; ) HANGUL SYLLABLE BBYUGG +C03F;C03F;1108 1172 11AA;C03F;1108 1172 11AA; # (쀿; 쀿; 쀿; 쀿; 쀿; ) HANGUL SYLLABLE BBYUGS +C040;C040;1108 1172 11AB;C040;1108 1172 11AB; # (쁀; 쁀; 쁀; 쁀; 쁀; ) HANGUL SYLLABLE BBYUN +C041;C041;1108 1172 11AC;C041;1108 1172 11AC; # (쁁; 쁁; 쁁; 쁁; 쁁; ) HANGUL SYLLABLE BBYUNJ +C042;C042;1108 1172 11AD;C042;1108 1172 11AD; # (쁂; 쁂; 쁂; 쁂; 쁂; ) HANGUL SYLLABLE BBYUNH +C043;C043;1108 1172 11AE;C043;1108 1172 11AE; # (쁃; 쁃; 쁃; 쁃; 쁃; ) HANGUL SYLLABLE BBYUD +C044;C044;1108 1172 11AF;C044;1108 1172 11AF; # (쁄; 쁄; 쁄; 쁄; 쁄; ) HANGUL SYLLABLE BBYUL +C045;C045;1108 1172 11B0;C045;1108 1172 11B0; # (쁅; 쁅; 쁅; 쁅; 쁅; ) HANGUL SYLLABLE BBYULG +C046;C046;1108 1172 11B1;C046;1108 1172 11B1; # (쁆; 쁆; 쁆; 쁆; 쁆; ) HANGUL SYLLABLE BBYULM +C047;C047;1108 1172 11B2;C047;1108 1172 11B2; # (쁇; 쁇; 쁇; 쁇; 쁇; ) HANGUL SYLLABLE BBYULB +C048;C048;1108 1172 11B3;C048;1108 1172 11B3; # (쁈; 쁈; 쁈; 쁈; 쁈; ) HANGUL SYLLABLE BBYULS +C049;C049;1108 1172 11B4;C049;1108 1172 11B4; # (쁉; 쁉; 쁉; 쁉; 쁉; ) HANGUL SYLLABLE BBYULT +C04A;C04A;1108 1172 11B5;C04A;1108 1172 11B5; # (쁊; 쁊; 쁊; 쁊; 쁊; ) HANGUL SYLLABLE BBYULP +C04B;C04B;1108 1172 11B6;C04B;1108 1172 11B6; # (쁋; 쁋; 쁋; 쁋; 쁋; ) HANGUL SYLLABLE BBYULH +C04C;C04C;1108 1172 11B7;C04C;1108 1172 11B7; # (쁌; 쁌; 쁌; 쁌; 쁌; ) HANGUL SYLLABLE BBYUM +C04D;C04D;1108 1172 11B8;C04D;1108 1172 11B8; # (쁍; 쁍; 쁍; 쁍; 쁍; ) HANGUL SYLLABLE BBYUB +C04E;C04E;1108 1172 11B9;C04E;1108 1172 11B9; # (쁎; 쁎; 쁎; 쁎; 쁎; ) HANGUL SYLLABLE BBYUBS +C04F;C04F;1108 1172 11BA;C04F;1108 1172 11BA; # (쁏; 쁏; 쁏; 쁏; 쁏; ) HANGUL SYLLABLE BBYUS +C050;C050;1108 1172 11BB;C050;1108 1172 11BB; # (쁐; 쁐; 쁐; 쁐; 쁐; ) HANGUL SYLLABLE BBYUSS +C051;C051;1108 1172 11BC;C051;1108 1172 11BC; # (쁑; 쁑; 쁑; 쁑; 쁑; ) HANGUL SYLLABLE BBYUNG +C052;C052;1108 1172 11BD;C052;1108 1172 11BD; # (쁒; 쁒; 쁒; 쁒; 쁒; ) HANGUL SYLLABLE BBYUJ +C053;C053;1108 1172 11BE;C053;1108 1172 11BE; # (쁓; 쁓; 쁓; 쁓; 쁓; ) HANGUL SYLLABLE BBYUC +C054;C054;1108 1172 11BF;C054;1108 1172 11BF; # (쁔; 쁔; 쁔; 쁔; 쁔; ) HANGUL SYLLABLE BBYUK +C055;C055;1108 1172 11C0;C055;1108 1172 11C0; # (쁕; 쁕; 쁕; 쁕; 쁕; ) HANGUL SYLLABLE BBYUT +C056;C056;1108 1172 11C1;C056;1108 1172 11C1; # (쁖; 쁖; 쁖; 쁖; 쁖; ) HANGUL SYLLABLE BBYUP +C057;C057;1108 1172 11C2;C057;1108 1172 11C2; # (쁗; 쁗; 쁗; 쁗; 쁗; ) HANGUL SYLLABLE BBYUH +C058;C058;1108 1173;C058;1108 1173; # (쁘; 쁘; 쁘; 쁘; 쁘; ) HANGUL SYLLABLE BBEU +C059;C059;1108 1173 11A8;C059;1108 1173 11A8; # (쁙; 쁙; 쁙; 쁙; 쁙; ) HANGUL SYLLABLE BBEUG +C05A;C05A;1108 1173 11A9;C05A;1108 1173 11A9; # (쁚; 쁚; 쁚; 쁚; 쁚; ) HANGUL SYLLABLE BBEUGG +C05B;C05B;1108 1173 11AA;C05B;1108 1173 11AA; # (쁛; 쁛; 쁛; 쁛; 쁛; ) HANGUL SYLLABLE BBEUGS +C05C;C05C;1108 1173 11AB;C05C;1108 1173 11AB; # (쁜; 쁜; 쁜; 쁜; 쁜; ) HANGUL SYLLABLE BBEUN +C05D;C05D;1108 1173 11AC;C05D;1108 1173 11AC; # (쁝; 쁝; 쁝; 쁝; 쁝; ) HANGUL SYLLABLE BBEUNJ +C05E;C05E;1108 1173 11AD;C05E;1108 1173 11AD; # (쁞; 쁞; 쁞; 쁞; 쁞; ) HANGUL SYLLABLE BBEUNH +C05F;C05F;1108 1173 11AE;C05F;1108 1173 11AE; # (쁟; 쁟; 쁟; 쁟; 쁟; ) HANGUL SYLLABLE BBEUD +C060;C060;1108 1173 11AF;C060;1108 1173 11AF; # (쁠; 쁠; 쁠; 쁠; 쁠; ) HANGUL SYLLABLE BBEUL +C061;C061;1108 1173 11B0;C061;1108 1173 11B0; # (쁡; 쁡; 쁡; 쁡; 쁡; ) HANGUL SYLLABLE BBEULG +C062;C062;1108 1173 11B1;C062;1108 1173 11B1; # (쁢; 쁢; 쁢; 쁢; 쁢; ) HANGUL SYLLABLE BBEULM +C063;C063;1108 1173 11B2;C063;1108 1173 11B2; # (쁣; 쁣; 쁣; 쁣; 쁣; ) HANGUL SYLLABLE BBEULB +C064;C064;1108 1173 11B3;C064;1108 1173 11B3; # (쁤; 쁤; 쁤; 쁤; 쁤; ) HANGUL SYLLABLE BBEULS +C065;C065;1108 1173 11B4;C065;1108 1173 11B4; # (쁥; 쁥; 쁥; 쁥; 쁥; ) HANGUL SYLLABLE BBEULT +C066;C066;1108 1173 11B5;C066;1108 1173 11B5; # (쁦; 쁦; 쁦; 쁦; 쁦; ) HANGUL SYLLABLE BBEULP +C067;C067;1108 1173 11B6;C067;1108 1173 11B6; # (쁧; 쁧; 쁧; 쁧; 쁧; ) HANGUL SYLLABLE BBEULH +C068;C068;1108 1173 11B7;C068;1108 1173 11B7; # (쁨; 쁨; 쁨; 쁨; 쁨; ) HANGUL SYLLABLE BBEUM +C069;C069;1108 1173 11B8;C069;1108 1173 11B8; # (쁩; 쁩; 쁩; 쁩; 쁩; ) HANGUL SYLLABLE BBEUB +C06A;C06A;1108 1173 11B9;C06A;1108 1173 11B9; # (쁪; 쁪; 쁪; 쁪; 쁪; ) HANGUL SYLLABLE BBEUBS +C06B;C06B;1108 1173 11BA;C06B;1108 1173 11BA; # (쁫; 쁫; 쁫; 쁫; 쁫; ) HANGUL SYLLABLE BBEUS +C06C;C06C;1108 1173 11BB;C06C;1108 1173 11BB; # (쁬; 쁬; 쁬; 쁬; 쁬; ) HANGUL SYLLABLE BBEUSS +C06D;C06D;1108 1173 11BC;C06D;1108 1173 11BC; # (쁭; 쁭; 쁭; 쁭; 쁭; ) HANGUL SYLLABLE BBEUNG +C06E;C06E;1108 1173 11BD;C06E;1108 1173 11BD; # (쁮; 쁮; 쁮; 쁮; 쁮; ) HANGUL SYLLABLE BBEUJ +C06F;C06F;1108 1173 11BE;C06F;1108 1173 11BE; # (쁯; 쁯; 쁯; 쁯; 쁯; ) HANGUL SYLLABLE BBEUC +C070;C070;1108 1173 11BF;C070;1108 1173 11BF; # (쁰; 쁰; 쁰; 쁰; 쁰; ) HANGUL SYLLABLE BBEUK +C071;C071;1108 1173 11C0;C071;1108 1173 11C0; # (쁱; 쁱; 쁱; 쁱; 쁱; ) HANGUL SYLLABLE BBEUT +C072;C072;1108 1173 11C1;C072;1108 1173 11C1; # (쁲; 쁲; 쁲; 쁲; 쁲; ) HANGUL SYLLABLE BBEUP +C073;C073;1108 1173 11C2;C073;1108 1173 11C2; # (쁳; 쁳; 쁳; 쁳; 쁳; ) HANGUL SYLLABLE BBEUH +C074;C074;1108 1174;C074;1108 1174; # (쁴; 쁴; 쁴; 쁴; 쁴; ) HANGUL SYLLABLE BBYI +C075;C075;1108 1174 11A8;C075;1108 1174 11A8; # (쁵; 쁵; 쁵; 쁵; 쁵; ) HANGUL SYLLABLE BBYIG +C076;C076;1108 1174 11A9;C076;1108 1174 11A9; # (쁶; 쁶; 쁶; 쁶; 쁶; ) HANGUL SYLLABLE BBYIGG +C077;C077;1108 1174 11AA;C077;1108 1174 11AA; # (쁷; 쁷; 쁷; 쁷; 쁷; ) HANGUL SYLLABLE BBYIGS +C078;C078;1108 1174 11AB;C078;1108 1174 11AB; # (쁸; 쁸; 쁸; 쁸; 쁸; ) HANGUL SYLLABLE BBYIN +C079;C079;1108 1174 11AC;C079;1108 1174 11AC; # (쁹; 쁹; 쁹; 쁹; 쁹; ) HANGUL SYLLABLE BBYINJ +C07A;C07A;1108 1174 11AD;C07A;1108 1174 11AD; # (쁺; 쁺; 쁺; 쁺; 쁺; ) HANGUL SYLLABLE BBYINH +C07B;C07B;1108 1174 11AE;C07B;1108 1174 11AE; # (쁻; 쁻; 쁻; 쁻; 쁻; ) HANGUL SYLLABLE BBYID +C07C;C07C;1108 1174 11AF;C07C;1108 1174 11AF; # (쁼; 쁼; 쁼; 쁼; 쁼; ) HANGUL SYLLABLE BBYIL +C07D;C07D;1108 1174 11B0;C07D;1108 1174 11B0; # (쁽; 쁽; 쁽; 쁽; 쁽; ) HANGUL SYLLABLE BBYILG +C07E;C07E;1108 1174 11B1;C07E;1108 1174 11B1; # (쁾; 쁾; 쁾; 쁾; 쁾; ) HANGUL SYLLABLE BBYILM +C07F;C07F;1108 1174 11B2;C07F;1108 1174 11B2; # (쁿; 쁿; 쁿; 쁿; 쁿; ) HANGUL SYLLABLE BBYILB +C080;C080;1108 1174 11B3;C080;1108 1174 11B3; # (삀; 삀; 삀; 삀; 삀; ) HANGUL SYLLABLE BBYILS +C081;C081;1108 1174 11B4;C081;1108 1174 11B4; # (삁; 삁; 삁; 삁; 삁; ) HANGUL SYLLABLE BBYILT +C082;C082;1108 1174 11B5;C082;1108 1174 11B5; # (삂; 삂; 삂; 삂; 삂; ) HANGUL SYLLABLE BBYILP +C083;C083;1108 1174 11B6;C083;1108 1174 11B6; # (삃; 삃; 삃; 삃; 삃; ) HANGUL SYLLABLE BBYILH +C084;C084;1108 1174 11B7;C084;1108 1174 11B7; # (삄; 삄; 삄; 삄; 삄; ) HANGUL SYLLABLE BBYIM +C085;C085;1108 1174 11B8;C085;1108 1174 11B8; # (삅; 삅; 삅; 삅; 삅; ) HANGUL SYLLABLE BBYIB +C086;C086;1108 1174 11B9;C086;1108 1174 11B9; # (삆; 삆; 삆; 삆; 삆; ) HANGUL SYLLABLE BBYIBS +C087;C087;1108 1174 11BA;C087;1108 1174 11BA; # (삇; 삇; 삇; 삇; 삇; ) HANGUL SYLLABLE BBYIS +C088;C088;1108 1174 11BB;C088;1108 1174 11BB; # (삈; 삈; 삈; 삈; 삈; ) HANGUL SYLLABLE BBYISS +C089;C089;1108 1174 11BC;C089;1108 1174 11BC; # (삉; 삉; 삉; 삉; 삉; ) HANGUL SYLLABLE BBYING +C08A;C08A;1108 1174 11BD;C08A;1108 1174 11BD; # (삊; 삊; 삊; 삊; 삊; ) HANGUL SYLLABLE BBYIJ +C08B;C08B;1108 1174 11BE;C08B;1108 1174 11BE; # (삋; 삋; 삋; 삋; 삋; ) HANGUL SYLLABLE BBYIC +C08C;C08C;1108 1174 11BF;C08C;1108 1174 11BF; # (삌; 삌; 삌; 삌; 삌; ) HANGUL SYLLABLE BBYIK +C08D;C08D;1108 1174 11C0;C08D;1108 1174 11C0; # (삍; 삍; 삍; 삍; 삍; ) HANGUL SYLLABLE BBYIT +C08E;C08E;1108 1174 11C1;C08E;1108 1174 11C1; # (삎; 삎; 삎; 삎; 삎; ) HANGUL SYLLABLE BBYIP +C08F;C08F;1108 1174 11C2;C08F;1108 1174 11C2; # (삏; 삏; 삏; 삏; 삏; ) HANGUL SYLLABLE BBYIH +C090;C090;1108 1175;C090;1108 1175; # (삐; 삐; 삐; 삐; 삐; ) HANGUL SYLLABLE BBI +C091;C091;1108 1175 11A8;C091;1108 1175 11A8; # (삑; 삑; 삑; 삑; 삑; ) HANGUL SYLLABLE BBIG +C092;C092;1108 1175 11A9;C092;1108 1175 11A9; # (삒; 삒; 삒; 삒; 삒; ) HANGUL SYLLABLE BBIGG +C093;C093;1108 1175 11AA;C093;1108 1175 11AA; # (삓; 삓; 삓; 삓; 삓; ) HANGUL SYLLABLE BBIGS +C094;C094;1108 1175 11AB;C094;1108 1175 11AB; # (삔; 삔; 삔; 삔; 삔; ) HANGUL SYLLABLE BBIN +C095;C095;1108 1175 11AC;C095;1108 1175 11AC; # (삕; 삕; 삕; 삕; 삕; ) HANGUL SYLLABLE BBINJ +C096;C096;1108 1175 11AD;C096;1108 1175 11AD; # (삖; 삖; 삖; 삖; 삖; ) HANGUL SYLLABLE BBINH +C097;C097;1108 1175 11AE;C097;1108 1175 11AE; # (삗; 삗; 삗; 삗; 삗; ) HANGUL SYLLABLE BBID +C098;C098;1108 1175 11AF;C098;1108 1175 11AF; # (삘; 삘; 삘; 삘; 삘; ) HANGUL SYLLABLE BBIL +C099;C099;1108 1175 11B0;C099;1108 1175 11B0; # (삙; 삙; 삙; 삙; 삙; ) HANGUL SYLLABLE BBILG +C09A;C09A;1108 1175 11B1;C09A;1108 1175 11B1; # (삚; 삚; 삚; 삚; 삚; ) HANGUL SYLLABLE BBILM +C09B;C09B;1108 1175 11B2;C09B;1108 1175 11B2; # (삛; 삛; 삛; 삛; 삛; ) HANGUL SYLLABLE BBILB +C09C;C09C;1108 1175 11B3;C09C;1108 1175 11B3; # (삜; 삜; 삜; 삜; 삜; ) HANGUL SYLLABLE BBILS +C09D;C09D;1108 1175 11B4;C09D;1108 1175 11B4; # (삝; 삝; 삝; 삝; 삝; ) HANGUL SYLLABLE BBILT +C09E;C09E;1108 1175 11B5;C09E;1108 1175 11B5; # (삞; 삞; 삞; 삞; 삞; ) HANGUL SYLLABLE BBILP +C09F;C09F;1108 1175 11B6;C09F;1108 1175 11B6; # (삟; 삟; 삟; 삟; 삟; ) HANGUL SYLLABLE BBILH +C0A0;C0A0;1108 1175 11B7;C0A0;1108 1175 11B7; # (삠; 삠; 삠; 삠; 삠; ) HANGUL SYLLABLE BBIM +C0A1;C0A1;1108 1175 11B8;C0A1;1108 1175 11B8; # (삡; 삡; 삡; 삡; 삡; ) HANGUL SYLLABLE BBIB +C0A2;C0A2;1108 1175 11B9;C0A2;1108 1175 11B9; # (삢; 삢; 삢; 삢; 삢; ) HANGUL SYLLABLE BBIBS +C0A3;C0A3;1108 1175 11BA;C0A3;1108 1175 11BA; # (삣; 삣; 삣; 삣; 삣; ) HANGUL SYLLABLE BBIS +C0A4;C0A4;1108 1175 11BB;C0A4;1108 1175 11BB; # (삤; 삤; 삤; 삤; 삤; ) HANGUL SYLLABLE BBISS +C0A5;C0A5;1108 1175 11BC;C0A5;1108 1175 11BC; # (삥; 삥; 삥; 삥; 삥; ) HANGUL SYLLABLE BBING +C0A6;C0A6;1108 1175 11BD;C0A6;1108 1175 11BD; # (삦; 삦; 삦; 삦; 삦; ) HANGUL SYLLABLE BBIJ +C0A7;C0A7;1108 1175 11BE;C0A7;1108 1175 11BE; # (삧; 삧; 삧; 삧; 삧; ) HANGUL SYLLABLE BBIC +C0A8;C0A8;1108 1175 11BF;C0A8;1108 1175 11BF; # (삨; 삨; 삨; 삨; 삨; ) HANGUL SYLLABLE BBIK +C0A9;C0A9;1108 1175 11C0;C0A9;1108 1175 11C0; # (삩; 삩; 삩; 삩; 삩; ) HANGUL SYLLABLE BBIT +C0AA;C0AA;1108 1175 11C1;C0AA;1108 1175 11C1; # (삪; 삪; 삪; 삪; 삪; ) HANGUL SYLLABLE BBIP +C0AB;C0AB;1108 1175 11C2;C0AB;1108 1175 11C2; # (삫; 삫; 삫; 삫; 삫; ) HANGUL SYLLABLE BBIH +C0AC;C0AC;1109 1161;C0AC;1109 1161; # (사; 사; 사; 사; 사; ) HANGUL SYLLABLE SA +C0AD;C0AD;1109 1161 11A8;C0AD;1109 1161 11A8; # (삭; 삭; 삭; 삭; 삭; ) HANGUL SYLLABLE SAG +C0AE;C0AE;1109 1161 11A9;C0AE;1109 1161 11A9; # (삮; 삮; 삮; 삮; 삮; ) HANGUL SYLLABLE SAGG +C0AF;C0AF;1109 1161 11AA;C0AF;1109 1161 11AA; # (삯; 삯; 삯; 삯; 삯; ) HANGUL SYLLABLE SAGS +C0B0;C0B0;1109 1161 11AB;C0B0;1109 1161 11AB; # (산; 산; 산; 산; 산; ) HANGUL SYLLABLE SAN +C0B1;C0B1;1109 1161 11AC;C0B1;1109 1161 11AC; # (삱; 삱; 삱; 삱; 삱; ) HANGUL SYLLABLE SANJ +C0B2;C0B2;1109 1161 11AD;C0B2;1109 1161 11AD; # (삲; 삲; 삲; 삲; 삲; ) HANGUL SYLLABLE SANH +C0B3;C0B3;1109 1161 11AE;C0B3;1109 1161 11AE; # (삳; 삳; 삳; 삳; 삳; ) HANGUL SYLLABLE SAD +C0B4;C0B4;1109 1161 11AF;C0B4;1109 1161 11AF; # (살; 살; 살; 살; 살; ) HANGUL SYLLABLE SAL +C0B5;C0B5;1109 1161 11B0;C0B5;1109 1161 11B0; # (삵; 삵; 삵; 삵; 삵; ) HANGUL SYLLABLE SALG +C0B6;C0B6;1109 1161 11B1;C0B6;1109 1161 11B1; # (삶; 삶; 삶; 삶; 삶; ) HANGUL SYLLABLE SALM +C0B7;C0B7;1109 1161 11B2;C0B7;1109 1161 11B2; # (삷; 삷; 삷; 삷; 삷; ) HANGUL SYLLABLE SALB +C0B8;C0B8;1109 1161 11B3;C0B8;1109 1161 11B3; # (삸; 삸; 삸; 삸; 삸; ) HANGUL SYLLABLE SALS +C0B9;C0B9;1109 1161 11B4;C0B9;1109 1161 11B4; # (삹; 삹; 삹; 삹; 삹; ) HANGUL SYLLABLE SALT +C0BA;C0BA;1109 1161 11B5;C0BA;1109 1161 11B5; # (삺; 삺; 삺; 삺; 삺; ) HANGUL SYLLABLE SALP +C0BB;C0BB;1109 1161 11B6;C0BB;1109 1161 11B6; # (삻; 삻; 삻; 삻; 삻; ) HANGUL SYLLABLE SALH +C0BC;C0BC;1109 1161 11B7;C0BC;1109 1161 11B7; # (삼; 삼; 삼; 삼; 삼; ) HANGUL SYLLABLE SAM +C0BD;C0BD;1109 1161 11B8;C0BD;1109 1161 11B8; # (삽; 삽; 삽; 삽; 삽; ) HANGUL SYLLABLE SAB +C0BE;C0BE;1109 1161 11B9;C0BE;1109 1161 11B9; # (삾; 삾; 삾; 삾; 삾; ) HANGUL SYLLABLE SABS +C0BF;C0BF;1109 1161 11BA;C0BF;1109 1161 11BA; # (삿; 삿; 삿; 삿; 삿; ) HANGUL SYLLABLE SAS +C0C0;C0C0;1109 1161 11BB;C0C0;1109 1161 11BB; # (샀; 샀; 샀; 샀; 샀; ) HANGUL SYLLABLE SASS +C0C1;C0C1;1109 1161 11BC;C0C1;1109 1161 11BC; # (상; 상; 상; 상; 상; ) HANGUL SYLLABLE SANG +C0C2;C0C2;1109 1161 11BD;C0C2;1109 1161 11BD; # (샂; 샂; 샂; 샂; 샂; ) HANGUL SYLLABLE SAJ +C0C3;C0C3;1109 1161 11BE;C0C3;1109 1161 11BE; # (샃; 샃; 샃; 샃; 샃; ) HANGUL SYLLABLE SAC +C0C4;C0C4;1109 1161 11BF;C0C4;1109 1161 11BF; # (샄; 샄; 샄; 샄; 샄; ) HANGUL SYLLABLE SAK +C0C5;C0C5;1109 1161 11C0;C0C5;1109 1161 11C0; # (샅; 샅; 샅; 샅; 샅; ) HANGUL SYLLABLE SAT +C0C6;C0C6;1109 1161 11C1;C0C6;1109 1161 11C1; # (샆; 샆; 샆; 샆; 샆; ) HANGUL SYLLABLE SAP +C0C7;C0C7;1109 1161 11C2;C0C7;1109 1161 11C2; # (샇; 샇; 샇; 샇; 샇; ) HANGUL SYLLABLE SAH +C0C8;C0C8;1109 1162;C0C8;1109 1162; # (새; 새; 새; 새; 새; ) HANGUL SYLLABLE SAE +C0C9;C0C9;1109 1162 11A8;C0C9;1109 1162 11A8; # (색; 색; 색; 색; 색; ) HANGUL SYLLABLE SAEG +C0CA;C0CA;1109 1162 11A9;C0CA;1109 1162 11A9; # (샊; 샊; 샊; 샊; 샊; ) HANGUL SYLLABLE SAEGG +C0CB;C0CB;1109 1162 11AA;C0CB;1109 1162 11AA; # (샋; 샋; 샋; 샋; 샋; ) HANGUL SYLLABLE SAEGS +C0CC;C0CC;1109 1162 11AB;C0CC;1109 1162 11AB; # (샌; 샌; 샌; 샌; 샌; ) HANGUL SYLLABLE SAEN +C0CD;C0CD;1109 1162 11AC;C0CD;1109 1162 11AC; # (샍; 샍; 샍; 샍; 샍; ) HANGUL SYLLABLE SAENJ +C0CE;C0CE;1109 1162 11AD;C0CE;1109 1162 11AD; # (샎; 샎; 샎; 샎; 샎; ) HANGUL SYLLABLE SAENH +C0CF;C0CF;1109 1162 11AE;C0CF;1109 1162 11AE; # (샏; 샏; 샏; 샏; 샏; ) HANGUL SYLLABLE SAED +C0D0;C0D0;1109 1162 11AF;C0D0;1109 1162 11AF; # (샐; 샐; 샐; 샐; 샐; ) HANGUL SYLLABLE SAEL +C0D1;C0D1;1109 1162 11B0;C0D1;1109 1162 11B0; # (샑; 샑; 샑; 샑; 샑; ) HANGUL SYLLABLE SAELG +C0D2;C0D2;1109 1162 11B1;C0D2;1109 1162 11B1; # (샒; 샒; 샒; 샒; 샒; ) HANGUL SYLLABLE SAELM +C0D3;C0D3;1109 1162 11B2;C0D3;1109 1162 11B2; # (샓; 샓; 샓; 샓; 샓; ) HANGUL SYLLABLE SAELB +C0D4;C0D4;1109 1162 11B3;C0D4;1109 1162 11B3; # (샔; 샔; 샔; 샔; 샔; ) HANGUL SYLLABLE SAELS +C0D5;C0D5;1109 1162 11B4;C0D5;1109 1162 11B4; # (샕; 샕; 샕; 샕; 샕; ) HANGUL SYLLABLE SAELT +C0D6;C0D6;1109 1162 11B5;C0D6;1109 1162 11B5; # (샖; 샖; 샖; 샖; 샖; ) HANGUL SYLLABLE SAELP +C0D7;C0D7;1109 1162 11B6;C0D7;1109 1162 11B6; # (샗; 샗; 샗; 샗; 샗; ) HANGUL SYLLABLE SAELH +C0D8;C0D8;1109 1162 11B7;C0D8;1109 1162 11B7; # (샘; 샘; 샘; 샘; 샘; ) HANGUL SYLLABLE SAEM +C0D9;C0D9;1109 1162 11B8;C0D9;1109 1162 11B8; # (샙; 샙; 샙; 샙; 샙; ) HANGUL SYLLABLE SAEB +C0DA;C0DA;1109 1162 11B9;C0DA;1109 1162 11B9; # (샚; 샚; 샚; 샚; 샚; ) HANGUL SYLLABLE SAEBS +C0DB;C0DB;1109 1162 11BA;C0DB;1109 1162 11BA; # (샛; 샛; 샛; 샛; 샛; ) HANGUL SYLLABLE SAES +C0DC;C0DC;1109 1162 11BB;C0DC;1109 1162 11BB; # (샜; 샜; 샜; 샜; 샜; ) HANGUL SYLLABLE SAESS +C0DD;C0DD;1109 1162 11BC;C0DD;1109 1162 11BC; # (생; 생; 생; 생; 생; ) HANGUL SYLLABLE SAENG +C0DE;C0DE;1109 1162 11BD;C0DE;1109 1162 11BD; # (샞; 샞; 샞; 샞; 샞; ) HANGUL SYLLABLE SAEJ +C0DF;C0DF;1109 1162 11BE;C0DF;1109 1162 11BE; # (샟; 샟; 샟; 샟; 샟; ) HANGUL SYLLABLE SAEC +C0E0;C0E0;1109 1162 11BF;C0E0;1109 1162 11BF; # (샠; 샠; 샠; 샠; 샠; ) HANGUL SYLLABLE SAEK +C0E1;C0E1;1109 1162 11C0;C0E1;1109 1162 11C0; # (샡; 샡; 샡; 샡; 샡; ) HANGUL SYLLABLE SAET +C0E2;C0E2;1109 1162 11C1;C0E2;1109 1162 11C1; # (샢; 샢; 샢; 샢; 샢; ) HANGUL SYLLABLE SAEP +C0E3;C0E3;1109 1162 11C2;C0E3;1109 1162 11C2; # (샣; 샣; 샣; 샣; 샣; ) HANGUL SYLLABLE SAEH +C0E4;C0E4;1109 1163;C0E4;1109 1163; # (샤; 샤; 샤; 샤; 샤; ) HANGUL SYLLABLE SYA +C0E5;C0E5;1109 1163 11A8;C0E5;1109 1163 11A8; # (샥; 샥; 샥; 샥; 샥; ) HANGUL SYLLABLE SYAG +C0E6;C0E6;1109 1163 11A9;C0E6;1109 1163 11A9; # (샦; 샦; 샦; 샦; 샦; ) HANGUL SYLLABLE SYAGG +C0E7;C0E7;1109 1163 11AA;C0E7;1109 1163 11AA; # (샧; 샧; 샧; 샧; 샧; ) HANGUL SYLLABLE SYAGS +C0E8;C0E8;1109 1163 11AB;C0E8;1109 1163 11AB; # (샨; 샨; 샨; 샨; 샨; ) HANGUL SYLLABLE SYAN +C0E9;C0E9;1109 1163 11AC;C0E9;1109 1163 11AC; # (샩; 샩; 샩; 샩; 샩; ) HANGUL SYLLABLE SYANJ +C0EA;C0EA;1109 1163 11AD;C0EA;1109 1163 11AD; # (샪; 샪; 샪; 샪; 샪; ) HANGUL SYLLABLE SYANH +C0EB;C0EB;1109 1163 11AE;C0EB;1109 1163 11AE; # (샫; 샫; 샫; 샫; 샫; ) HANGUL SYLLABLE SYAD +C0EC;C0EC;1109 1163 11AF;C0EC;1109 1163 11AF; # (샬; 샬; 샬; 샬; 샬; ) HANGUL SYLLABLE SYAL +C0ED;C0ED;1109 1163 11B0;C0ED;1109 1163 11B0; # (샭; 샭; 샭; 샭; 샭; ) HANGUL SYLLABLE SYALG +C0EE;C0EE;1109 1163 11B1;C0EE;1109 1163 11B1; # (샮; 샮; 샮; 샮; 샮; ) HANGUL SYLLABLE SYALM +C0EF;C0EF;1109 1163 11B2;C0EF;1109 1163 11B2; # (샯; 샯; 샯; 샯; 샯; ) HANGUL SYLLABLE SYALB +C0F0;C0F0;1109 1163 11B3;C0F0;1109 1163 11B3; # (샰; 샰; 샰; 샰; 샰; ) HANGUL SYLLABLE SYALS +C0F1;C0F1;1109 1163 11B4;C0F1;1109 1163 11B4; # (샱; 샱; 샱; 샱; 샱; ) HANGUL SYLLABLE SYALT +C0F2;C0F2;1109 1163 11B5;C0F2;1109 1163 11B5; # (샲; 샲; 샲; 샲; 샲; ) HANGUL SYLLABLE SYALP +C0F3;C0F3;1109 1163 11B6;C0F3;1109 1163 11B6; # (샳; 샳; 샳; 샳; 샳; ) HANGUL SYLLABLE SYALH +C0F4;C0F4;1109 1163 11B7;C0F4;1109 1163 11B7; # (샴; 샴; 샴; 샴; 샴; ) HANGUL SYLLABLE SYAM +C0F5;C0F5;1109 1163 11B8;C0F5;1109 1163 11B8; # (샵; 샵; 샵; 샵; 샵; ) HANGUL SYLLABLE SYAB +C0F6;C0F6;1109 1163 11B9;C0F6;1109 1163 11B9; # (샶; 샶; 샶; 샶; 샶; ) HANGUL SYLLABLE SYABS +C0F7;C0F7;1109 1163 11BA;C0F7;1109 1163 11BA; # (샷; 샷; 샷; 샷; 샷; ) HANGUL SYLLABLE SYAS +C0F8;C0F8;1109 1163 11BB;C0F8;1109 1163 11BB; # (샸; 샸; 샸; 샸; 샸; ) HANGUL SYLLABLE SYASS +C0F9;C0F9;1109 1163 11BC;C0F9;1109 1163 11BC; # (샹; 샹; 샹; 샹; 샹; ) HANGUL SYLLABLE SYANG +C0FA;C0FA;1109 1163 11BD;C0FA;1109 1163 11BD; # (샺; 샺; 샺; 샺; 샺; ) HANGUL SYLLABLE SYAJ +C0FB;C0FB;1109 1163 11BE;C0FB;1109 1163 11BE; # (샻; 샻; 샻; 샻; 샻; ) HANGUL SYLLABLE SYAC +C0FC;C0FC;1109 1163 11BF;C0FC;1109 1163 11BF; # (샼; 샼; 샼; 샼; 샼; ) HANGUL SYLLABLE SYAK +C0FD;C0FD;1109 1163 11C0;C0FD;1109 1163 11C0; # (샽; 샽; 샽; 샽; 샽; ) HANGUL SYLLABLE SYAT +C0FE;C0FE;1109 1163 11C1;C0FE;1109 1163 11C1; # (샾; 샾; 샾; 샾; 샾; ) HANGUL SYLLABLE SYAP +C0FF;C0FF;1109 1163 11C2;C0FF;1109 1163 11C2; # (샿; 샿; 샿; 샿; 샿; ) HANGUL SYLLABLE SYAH +C100;C100;1109 1164;C100;1109 1164; # (섀; 섀; 섀; 섀; 섀; ) HANGUL SYLLABLE SYAE +C101;C101;1109 1164 11A8;C101;1109 1164 11A8; # (섁; 섁; 섁; 섁; 섁; ) HANGUL SYLLABLE SYAEG +C102;C102;1109 1164 11A9;C102;1109 1164 11A9; # (섂; 섂; 섂; 섂; 섂; ) HANGUL SYLLABLE SYAEGG +C103;C103;1109 1164 11AA;C103;1109 1164 11AA; # (섃; 섃; 섃; 섃; 섃; ) HANGUL SYLLABLE SYAEGS +C104;C104;1109 1164 11AB;C104;1109 1164 11AB; # (섄; 섄; 섄; 섄; 섄; ) HANGUL SYLLABLE SYAEN +C105;C105;1109 1164 11AC;C105;1109 1164 11AC; # (섅; 섅; 섅; 섅; 섅; ) HANGUL SYLLABLE SYAENJ +C106;C106;1109 1164 11AD;C106;1109 1164 11AD; # (섆; 섆; 섆; 섆; 섆; ) HANGUL SYLLABLE SYAENH +C107;C107;1109 1164 11AE;C107;1109 1164 11AE; # (섇; 섇; 섇; 섇; 섇; ) HANGUL SYLLABLE SYAED +C108;C108;1109 1164 11AF;C108;1109 1164 11AF; # (섈; 섈; 섈; 섈; 섈; ) HANGUL SYLLABLE SYAEL +C109;C109;1109 1164 11B0;C109;1109 1164 11B0; # (섉; 섉; 섉; 섉; 섉; ) HANGUL SYLLABLE SYAELG +C10A;C10A;1109 1164 11B1;C10A;1109 1164 11B1; # (섊; 섊; 섊; 섊; 섊; ) HANGUL SYLLABLE SYAELM +C10B;C10B;1109 1164 11B2;C10B;1109 1164 11B2; # (섋; 섋; 섋; 섋; 섋; ) HANGUL SYLLABLE SYAELB +C10C;C10C;1109 1164 11B3;C10C;1109 1164 11B3; # (섌; 섌; 섌; 섌; 섌; ) HANGUL SYLLABLE SYAELS +C10D;C10D;1109 1164 11B4;C10D;1109 1164 11B4; # (섍; 섍; 섍; 섍; 섍; ) HANGUL SYLLABLE SYAELT +C10E;C10E;1109 1164 11B5;C10E;1109 1164 11B5; # (섎; 섎; 섎; 섎; 섎; ) HANGUL SYLLABLE SYAELP +C10F;C10F;1109 1164 11B6;C10F;1109 1164 11B6; # (섏; 섏; 섏; 섏; 섏; ) HANGUL SYLLABLE SYAELH +C110;C110;1109 1164 11B7;C110;1109 1164 11B7; # (섐; 섐; 섐; 섐; 섐; ) HANGUL SYLLABLE SYAEM +C111;C111;1109 1164 11B8;C111;1109 1164 11B8; # (섑; 섑; 섑; 섑; 섑; ) HANGUL SYLLABLE SYAEB +C112;C112;1109 1164 11B9;C112;1109 1164 11B9; # (섒; 섒; 섒; 섒; 섒; ) HANGUL SYLLABLE SYAEBS +C113;C113;1109 1164 11BA;C113;1109 1164 11BA; # (섓; 섓; 섓; 섓; 섓; ) HANGUL SYLLABLE SYAES +C114;C114;1109 1164 11BB;C114;1109 1164 11BB; # (섔; 섔; 섔; 섔; 섔; ) HANGUL SYLLABLE SYAESS +C115;C115;1109 1164 11BC;C115;1109 1164 11BC; # (섕; 섕; 섕; 섕; 섕; ) HANGUL SYLLABLE SYAENG +C116;C116;1109 1164 11BD;C116;1109 1164 11BD; # (섖; 섖; 섖; 섖; 섖; ) HANGUL SYLLABLE SYAEJ +C117;C117;1109 1164 11BE;C117;1109 1164 11BE; # (섗; 섗; 섗; 섗; 섗; ) HANGUL SYLLABLE SYAEC +C118;C118;1109 1164 11BF;C118;1109 1164 11BF; # (섘; 섘; 섘; 섘; 섘; ) HANGUL SYLLABLE SYAEK +C119;C119;1109 1164 11C0;C119;1109 1164 11C0; # (섙; 섙; 섙; 섙; 섙; ) HANGUL SYLLABLE SYAET +C11A;C11A;1109 1164 11C1;C11A;1109 1164 11C1; # (섚; 섚; 섚; 섚; 섚; ) HANGUL SYLLABLE SYAEP +C11B;C11B;1109 1164 11C2;C11B;1109 1164 11C2; # (섛; 섛; 섛; 섛; 섛; ) HANGUL SYLLABLE SYAEH +C11C;C11C;1109 1165;C11C;1109 1165; # (서; 서; 서; 서; 서; ) HANGUL SYLLABLE SEO +C11D;C11D;1109 1165 11A8;C11D;1109 1165 11A8; # (석; 석; 석; 석; 석; ) HANGUL SYLLABLE SEOG +C11E;C11E;1109 1165 11A9;C11E;1109 1165 11A9; # (섞; 섞; 섞; 섞; 섞; ) HANGUL SYLLABLE SEOGG +C11F;C11F;1109 1165 11AA;C11F;1109 1165 11AA; # (섟; 섟; 섟; 섟; 섟; ) HANGUL SYLLABLE SEOGS +C120;C120;1109 1165 11AB;C120;1109 1165 11AB; # (선; 선; 선; 선; 선; ) HANGUL SYLLABLE SEON +C121;C121;1109 1165 11AC;C121;1109 1165 11AC; # (섡; 섡; 섡; 섡; 섡; ) HANGUL SYLLABLE SEONJ +C122;C122;1109 1165 11AD;C122;1109 1165 11AD; # (섢; 섢; 섢; 섢; 섢; ) HANGUL SYLLABLE SEONH +C123;C123;1109 1165 11AE;C123;1109 1165 11AE; # (섣; 섣; 섣; 섣; 섣; ) HANGUL SYLLABLE SEOD +C124;C124;1109 1165 11AF;C124;1109 1165 11AF; # (설; 설; 설; 설; 설; ) HANGUL SYLLABLE SEOL +C125;C125;1109 1165 11B0;C125;1109 1165 11B0; # (섥; 섥; 섥; 섥; 섥; ) HANGUL SYLLABLE SEOLG +C126;C126;1109 1165 11B1;C126;1109 1165 11B1; # (섦; 섦; 섦; 섦; 섦; ) HANGUL SYLLABLE SEOLM +C127;C127;1109 1165 11B2;C127;1109 1165 11B2; # (섧; 섧; 섧; 섧; 섧; ) HANGUL SYLLABLE SEOLB +C128;C128;1109 1165 11B3;C128;1109 1165 11B3; # (섨; 섨; 섨; 섨; 섨; ) HANGUL SYLLABLE SEOLS +C129;C129;1109 1165 11B4;C129;1109 1165 11B4; # (섩; 섩; 섩; 섩; 섩; ) HANGUL SYLLABLE SEOLT +C12A;C12A;1109 1165 11B5;C12A;1109 1165 11B5; # (섪; 섪; 섪; 섪; 섪; ) HANGUL SYLLABLE SEOLP +C12B;C12B;1109 1165 11B6;C12B;1109 1165 11B6; # (섫; 섫; 섫; 섫; 섫; ) HANGUL SYLLABLE SEOLH +C12C;C12C;1109 1165 11B7;C12C;1109 1165 11B7; # (섬; 섬; 섬; 섬; 섬; ) HANGUL SYLLABLE SEOM +C12D;C12D;1109 1165 11B8;C12D;1109 1165 11B8; # (섭; 섭; 섭; 섭; 섭; ) HANGUL SYLLABLE SEOB +C12E;C12E;1109 1165 11B9;C12E;1109 1165 11B9; # (섮; 섮; 섮; 섮; 섮; ) HANGUL SYLLABLE SEOBS +C12F;C12F;1109 1165 11BA;C12F;1109 1165 11BA; # (섯; 섯; 섯; 섯; 섯; ) HANGUL SYLLABLE SEOS +C130;C130;1109 1165 11BB;C130;1109 1165 11BB; # (섰; 섰; 섰; 섰; 섰; ) HANGUL SYLLABLE SEOSS +C131;C131;1109 1165 11BC;C131;1109 1165 11BC; # (성; 성; 성; 성; 성; ) HANGUL SYLLABLE SEONG +C132;C132;1109 1165 11BD;C132;1109 1165 11BD; # (섲; 섲; 섲; 섲; 섲; ) HANGUL SYLLABLE SEOJ +C133;C133;1109 1165 11BE;C133;1109 1165 11BE; # (섳; 섳; 섳; 섳; 섳; ) HANGUL SYLLABLE SEOC +C134;C134;1109 1165 11BF;C134;1109 1165 11BF; # (섴; 섴; 섴; 섴; 섴; ) HANGUL SYLLABLE SEOK +C135;C135;1109 1165 11C0;C135;1109 1165 11C0; # (섵; 섵; 섵; 섵; 섵; ) HANGUL SYLLABLE SEOT +C136;C136;1109 1165 11C1;C136;1109 1165 11C1; # (섶; 섶; 섶; 섶; 섶; ) HANGUL SYLLABLE SEOP +C137;C137;1109 1165 11C2;C137;1109 1165 11C2; # (섷; 섷; 섷; 섷; 섷; ) HANGUL SYLLABLE SEOH +C138;C138;1109 1166;C138;1109 1166; # (세; 세; 세; 세; 세; ) HANGUL SYLLABLE SE +C139;C139;1109 1166 11A8;C139;1109 1166 11A8; # (섹; 섹; 섹; 섹; 섹; ) HANGUL SYLLABLE SEG +C13A;C13A;1109 1166 11A9;C13A;1109 1166 11A9; # (섺; 섺; 섺; 섺; 섺; ) HANGUL SYLLABLE SEGG +C13B;C13B;1109 1166 11AA;C13B;1109 1166 11AA; # (섻; 섻; 섻; 섻; 섻; ) HANGUL SYLLABLE SEGS +C13C;C13C;1109 1166 11AB;C13C;1109 1166 11AB; # (센; 센; 센; 센; 센; ) HANGUL SYLLABLE SEN +C13D;C13D;1109 1166 11AC;C13D;1109 1166 11AC; # (섽; 섽; 섽; 섽; 섽; ) HANGUL SYLLABLE SENJ +C13E;C13E;1109 1166 11AD;C13E;1109 1166 11AD; # (섾; 섾; 섾; 섾; 섾; ) HANGUL SYLLABLE SENH +C13F;C13F;1109 1166 11AE;C13F;1109 1166 11AE; # (섿; 섿; 섿; 섿; 섿; ) HANGUL SYLLABLE SED +C140;C140;1109 1166 11AF;C140;1109 1166 11AF; # (셀; 셀; 셀; 셀; 셀; ) HANGUL SYLLABLE SEL +C141;C141;1109 1166 11B0;C141;1109 1166 11B0; # (셁; 셁; 셁; 셁; 셁; ) HANGUL SYLLABLE SELG +C142;C142;1109 1166 11B1;C142;1109 1166 11B1; # (셂; 셂; 셂; 셂; 셂; ) HANGUL SYLLABLE SELM +C143;C143;1109 1166 11B2;C143;1109 1166 11B2; # (셃; 셃; 셃; 셃; 셃; ) HANGUL SYLLABLE SELB +C144;C144;1109 1166 11B3;C144;1109 1166 11B3; # (셄; 셄; 셄; 셄; 셄; ) HANGUL SYLLABLE SELS +C145;C145;1109 1166 11B4;C145;1109 1166 11B4; # (셅; 셅; 셅; 셅; 셅; ) HANGUL SYLLABLE SELT +C146;C146;1109 1166 11B5;C146;1109 1166 11B5; # (셆; 셆; 셆; 셆; 셆; ) HANGUL SYLLABLE SELP +C147;C147;1109 1166 11B6;C147;1109 1166 11B6; # (셇; 셇; 셇; 셇; 셇; ) HANGUL SYLLABLE SELH +C148;C148;1109 1166 11B7;C148;1109 1166 11B7; # (셈; 셈; 셈; 셈; 셈; ) HANGUL SYLLABLE SEM +C149;C149;1109 1166 11B8;C149;1109 1166 11B8; # (셉; 셉; 셉; 셉; 셉; ) HANGUL SYLLABLE SEB +C14A;C14A;1109 1166 11B9;C14A;1109 1166 11B9; # (셊; 셊; 셊; 셊; 셊; ) HANGUL SYLLABLE SEBS +C14B;C14B;1109 1166 11BA;C14B;1109 1166 11BA; # (셋; 셋; 셋; 셋; 셋; ) HANGUL SYLLABLE SES +C14C;C14C;1109 1166 11BB;C14C;1109 1166 11BB; # (셌; 셌; 셌; 셌; 셌; ) HANGUL SYLLABLE SESS +C14D;C14D;1109 1166 11BC;C14D;1109 1166 11BC; # (셍; 셍; 셍; 셍; 셍; ) HANGUL SYLLABLE SENG +C14E;C14E;1109 1166 11BD;C14E;1109 1166 11BD; # (셎; 셎; 셎; 셎; 셎; ) HANGUL SYLLABLE SEJ +C14F;C14F;1109 1166 11BE;C14F;1109 1166 11BE; # (셏; 셏; 셏; 셏; 셏; ) HANGUL SYLLABLE SEC +C150;C150;1109 1166 11BF;C150;1109 1166 11BF; # (셐; 셐; 셐; 셐; 셐; ) HANGUL SYLLABLE SEK +C151;C151;1109 1166 11C0;C151;1109 1166 11C0; # (셑; 셑; 셑; 셑; 셑; ) HANGUL SYLLABLE SET +C152;C152;1109 1166 11C1;C152;1109 1166 11C1; # (셒; 셒; 셒; 셒; 셒; ) HANGUL SYLLABLE SEP +C153;C153;1109 1166 11C2;C153;1109 1166 11C2; # (셓; 셓; 셓; 셓; 셓; ) HANGUL SYLLABLE SEH +C154;C154;1109 1167;C154;1109 1167; # (셔; 셔; 셔; 셔; 셔; ) HANGUL SYLLABLE SYEO +C155;C155;1109 1167 11A8;C155;1109 1167 11A8; # (셕; 셕; 셕; 셕; 셕; ) HANGUL SYLLABLE SYEOG +C156;C156;1109 1167 11A9;C156;1109 1167 11A9; # (셖; 셖; 셖; 셖; 셖; ) HANGUL SYLLABLE SYEOGG +C157;C157;1109 1167 11AA;C157;1109 1167 11AA; # (셗; 셗; 셗; 셗; 셗; ) HANGUL SYLLABLE SYEOGS +C158;C158;1109 1167 11AB;C158;1109 1167 11AB; # (션; 션; 션; 션; 션; ) HANGUL SYLLABLE SYEON +C159;C159;1109 1167 11AC;C159;1109 1167 11AC; # (셙; 셙; 셙; 셙; 셙; ) HANGUL SYLLABLE SYEONJ +C15A;C15A;1109 1167 11AD;C15A;1109 1167 11AD; # (셚; 셚; 셚; 셚; 셚; ) HANGUL SYLLABLE SYEONH +C15B;C15B;1109 1167 11AE;C15B;1109 1167 11AE; # (셛; 셛; 셛; 셛; 셛; ) HANGUL SYLLABLE SYEOD +C15C;C15C;1109 1167 11AF;C15C;1109 1167 11AF; # (셜; 셜; 셜; 셜; 셜; ) HANGUL SYLLABLE SYEOL +C15D;C15D;1109 1167 11B0;C15D;1109 1167 11B0; # (셝; 셝; 셝; 셝; 셝; ) HANGUL SYLLABLE SYEOLG +C15E;C15E;1109 1167 11B1;C15E;1109 1167 11B1; # (셞; 셞; 셞; 셞; 셞; ) HANGUL SYLLABLE SYEOLM +C15F;C15F;1109 1167 11B2;C15F;1109 1167 11B2; # (셟; 셟; 셟; 셟; 셟; ) HANGUL SYLLABLE SYEOLB +C160;C160;1109 1167 11B3;C160;1109 1167 11B3; # (셠; 셠; 셠; 셠; 셠; ) HANGUL SYLLABLE SYEOLS +C161;C161;1109 1167 11B4;C161;1109 1167 11B4; # (셡; 셡; 셡; 셡; 셡; ) HANGUL SYLLABLE SYEOLT +C162;C162;1109 1167 11B5;C162;1109 1167 11B5; # (셢; 셢; 셢; 셢; 셢; ) HANGUL SYLLABLE SYEOLP +C163;C163;1109 1167 11B6;C163;1109 1167 11B6; # (셣; 셣; 셣; 셣; 셣; ) HANGUL SYLLABLE SYEOLH +C164;C164;1109 1167 11B7;C164;1109 1167 11B7; # (셤; 셤; 셤; 셤; 셤; ) HANGUL SYLLABLE SYEOM +C165;C165;1109 1167 11B8;C165;1109 1167 11B8; # (셥; 셥; 셥; 셥; 셥; ) HANGUL SYLLABLE SYEOB +C166;C166;1109 1167 11B9;C166;1109 1167 11B9; # (셦; 셦; 셦; 셦; 셦; ) HANGUL SYLLABLE SYEOBS +C167;C167;1109 1167 11BA;C167;1109 1167 11BA; # (셧; 셧; 셧; 셧; 셧; ) HANGUL SYLLABLE SYEOS +C168;C168;1109 1167 11BB;C168;1109 1167 11BB; # (셨; 셨; 셨; 셨; 셨; ) HANGUL SYLLABLE SYEOSS +C169;C169;1109 1167 11BC;C169;1109 1167 11BC; # (셩; 셩; 셩; 셩; 셩; ) HANGUL SYLLABLE SYEONG +C16A;C16A;1109 1167 11BD;C16A;1109 1167 11BD; # (셪; 셪; 셪; 셪; 셪; ) HANGUL SYLLABLE SYEOJ +C16B;C16B;1109 1167 11BE;C16B;1109 1167 11BE; # (셫; 셫; 셫; 셫; 셫; ) HANGUL SYLLABLE SYEOC +C16C;C16C;1109 1167 11BF;C16C;1109 1167 11BF; # (셬; 셬; 셬; 셬; 셬; ) HANGUL SYLLABLE SYEOK +C16D;C16D;1109 1167 11C0;C16D;1109 1167 11C0; # (셭; 셭; 셭; 셭; 셭; ) HANGUL SYLLABLE SYEOT +C16E;C16E;1109 1167 11C1;C16E;1109 1167 11C1; # (셮; 셮; 셮; 셮; 셮; ) HANGUL SYLLABLE SYEOP +C16F;C16F;1109 1167 11C2;C16F;1109 1167 11C2; # (셯; 셯; 셯; 셯; 셯; ) HANGUL SYLLABLE SYEOH +C170;C170;1109 1168;C170;1109 1168; # (셰; 셰; 셰; 셰; 셰; ) HANGUL SYLLABLE SYE +C171;C171;1109 1168 11A8;C171;1109 1168 11A8; # (셱; 셱; 셱; 셱; 셱; ) HANGUL SYLLABLE SYEG +C172;C172;1109 1168 11A9;C172;1109 1168 11A9; # (셲; 셲; 셲; 셲; 셲; ) HANGUL SYLLABLE SYEGG +C173;C173;1109 1168 11AA;C173;1109 1168 11AA; # (셳; 셳; 셳; 셳; 셳; ) HANGUL SYLLABLE SYEGS +C174;C174;1109 1168 11AB;C174;1109 1168 11AB; # (셴; 셴; 셴; 셴; 셴; ) HANGUL SYLLABLE SYEN +C175;C175;1109 1168 11AC;C175;1109 1168 11AC; # (셵; 셵; 셵; 셵; 셵; ) HANGUL SYLLABLE SYENJ +C176;C176;1109 1168 11AD;C176;1109 1168 11AD; # (셶; 셶; 셶; 셶; 셶; ) HANGUL SYLLABLE SYENH +C177;C177;1109 1168 11AE;C177;1109 1168 11AE; # (셷; 셷; 셷; 셷; 셷; ) HANGUL SYLLABLE SYED +C178;C178;1109 1168 11AF;C178;1109 1168 11AF; # (셸; 셸; 셸; 셸; 셸; ) HANGUL SYLLABLE SYEL +C179;C179;1109 1168 11B0;C179;1109 1168 11B0; # (셹; 셹; 셹; 셹; 셹; ) HANGUL SYLLABLE SYELG +C17A;C17A;1109 1168 11B1;C17A;1109 1168 11B1; # (셺; 셺; 셺; 셺; 셺; ) HANGUL SYLLABLE SYELM +C17B;C17B;1109 1168 11B2;C17B;1109 1168 11B2; # (셻; 셻; 셻; 셻; 셻; ) HANGUL SYLLABLE SYELB +C17C;C17C;1109 1168 11B3;C17C;1109 1168 11B3; # (셼; 셼; 셼; 셼; 셼; ) HANGUL SYLLABLE SYELS +C17D;C17D;1109 1168 11B4;C17D;1109 1168 11B4; # (셽; 셽; 셽; 셽; 셽; ) HANGUL SYLLABLE SYELT +C17E;C17E;1109 1168 11B5;C17E;1109 1168 11B5; # (셾; 셾; 셾; 셾; 셾; ) HANGUL SYLLABLE SYELP +C17F;C17F;1109 1168 11B6;C17F;1109 1168 11B6; # (셿; 셿; 셿; 셿; 셿; ) HANGUL SYLLABLE SYELH +C180;C180;1109 1168 11B7;C180;1109 1168 11B7; # (솀; 솀; 솀; 솀; 솀; ) HANGUL SYLLABLE SYEM +C181;C181;1109 1168 11B8;C181;1109 1168 11B8; # (솁; 솁; 솁; 솁; 솁; ) HANGUL SYLLABLE SYEB +C182;C182;1109 1168 11B9;C182;1109 1168 11B9; # (솂; 솂; 솂; 솂; 솂; ) HANGUL SYLLABLE SYEBS +C183;C183;1109 1168 11BA;C183;1109 1168 11BA; # (솃; 솃; 솃; 솃; 솃; ) HANGUL SYLLABLE SYES +C184;C184;1109 1168 11BB;C184;1109 1168 11BB; # (솄; 솄; 솄; 솄; 솄; ) HANGUL SYLLABLE SYESS +C185;C185;1109 1168 11BC;C185;1109 1168 11BC; # (솅; 솅; 솅; 솅; 솅; ) HANGUL SYLLABLE SYENG +C186;C186;1109 1168 11BD;C186;1109 1168 11BD; # (솆; 솆; 솆; 솆; 솆; ) HANGUL SYLLABLE SYEJ +C187;C187;1109 1168 11BE;C187;1109 1168 11BE; # (솇; 솇; 솇; 솇; 솇; ) HANGUL SYLLABLE SYEC +C188;C188;1109 1168 11BF;C188;1109 1168 11BF; # (솈; 솈; 솈; 솈; 솈; ) HANGUL SYLLABLE SYEK +C189;C189;1109 1168 11C0;C189;1109 1168 11C0; # (솉; 솉; 솉; 솉; 솉; ) HANGUL SYLLABLE SYET +C18A;C18A;1109 1168 11C1;C18A;1109 1168 11C1; # (솊; 솊; 솊; 솊; 솊; ) HANGUL SYLLABLE SYEP +C18B;C18B;1109 1168 11C2;C18B;1109 1168 11C2; # (솋; 솋; 솋; 솋; 솋; ) HANGUL SYLLABLE SYEH +C18C;C18C;1109 1169;C18C;1109 1169; # (소; 소; 소; 소; 소; ) HANGUL SYLLABLE SO +C18D;C18D;1109 1169 11A8;C18D;1109 1169 11A8; # (속; 속; 속; 속; 속; ) HANGUL SYLLABLE SOG +C18E;C18E;1109 1169 11A9;C18E;1109 1169 11A9; # (솎; 솎; 솎; 솎; 솎; ) HANGUL SYLLABLE SOGG +C18F;C18F;1109 1169 11AA;C18F;1109 1169 11AA; # (솏; 솏; 솏; 솏; 솏; ) HANGUL SYLLABLE SOGS +C190;C190;1109 1169 11AB;C190;1109 1169 11AB; # (손; 손; 손; 손; 손; ) HANGUL SYLLABLE SON +C191;C191;1109 1169 11AC;C191;1109 1169 11AC; # (솑; 솑; 솑; 솑; 솑; ) HANGUL SYLLABLE SONJ +C192;C192;1109 1169 11AD;C192;1109 1169 11AD; # (솒; 솒; 솒; 솒; 솒; ) HANGUL SYLLABLE SONH +C193;C193;1109 1169 11AE;C193;1109 1169 11AE; # (솓; 솓; 솓; 솓; 솓; ) HANGUL SYLLABLE SOD +C194;C194;1109 1169 11AF;C194;1109 1169 11AF; # (솔; 솔; 솔; 솔; 솔; ) HANGUL SYLLABLE SOL +C195;C195;1109 1169 11B0;C195;1109 1169 11B0; # (솕; 솕; 솕; 솕; 솕; ) HANGUL SYLLABLE SOLG +C196;C196;1109 1169 11B1;C196;1109 1169 11B1; # (솖; 솖; 솖; 솖; 솖; ) HANGUL SYLLABLE SOLM +C197;C197;1109 1169 11B2;C197;1109 1169 11B2; # (솗; 솗; 솗; 솗; 솗; ) HANGUL SYLLABLE SOLB +C198;C198;1109 1169 11B3;C198;1109 1169 11B3; # (솘; 솘; 솘; 솘; 솘; ) HANGUL SYLLABLE SOLS +C199;C199;1109 1169 11B4;C199;1109 1169 11B4; # (솙; 솙; 솙; 솙; 솙; ) HANGUL SYLLABLE SOLT +C19A;C19A;1109 1169 11B5;C19A;1109 1169 11B5; # (솚; 솚; 솚; 솚; 솚; ) HANGUL SYLLABLE SOLP +C19B;C19B;1109 1169 11B6;C19B;1109 1169 11B6; # (솛; 솛; 솛; 솛; 솛; ) HANGUL SYLLABLE SOLH +C19C;C19C;1109 1169 11B7;C19C;1109 1169 11B7; # (솜; 솜; 솜; 솜; 솜; ) HANGUL SYLLABLE SOM +C19D;C19D;1109 1169 11B8;C19D;1109 1169 11B8; # (솝; 솝; 솝; 솝; 솝; ) HANGUL SYLLABLE SOB +C19E;C19E;1109 1169 11B9;C19E;1109 1169 11B9; # (솞; 솞; 솞; 솞; 솞; ) HANGUL SYLLABLE SOBS +C19F;C19F;1109 1169 11BA;C19F;1109 1169 11BA; # (솟; 솟; 솟; 솟; 솟; ) HANGUL SYLLABLE SOS +C1A0;C1A0;1109 1169 11BB;C1A0;1109 1169 11BB; # (솠; 솠; 솠; 솠; 솠; ) HANGUL SYLLABLE SOSS +C1A1;C1A1;1109 1169 11BC;C1A1;1109 1169 11BC; # (송; 송; 송; 송; 송; ) HANGUL SYLLABLE SONG +C1A2;C1A2;1109 1169 11BD;C1A2;1109 1169 11BD; # (솢; 솢; 솢; 솢; 솢; ) HANGUL SYLLABLE SOJ +C1A3;C1A3;1109 1169 11BE;C1A3;1109 1169 11BE; # (솣; 솣; 솣; 솣; 솣; ) HANGUL SYLLABLE SOC +C1A4;C1A4;1109 1169 11BF;C1A4;1109 1169 11BF; # (솤; 솤; 솤; 솤; 솤; ) HANGUL SYLLABLE SOK +C1A5;C1A5;1109 1169 11C0;C1A5;1109 1169 11C0; # (솥; 솥; 솥; 솥; 솥; ) HANGUL SYLLABLE SOT +C1A6;C1A6;1109 1169 11C1;C1A6;1109 1169 11C1; # (솦; 솦; 솦; 솦; 솦; ) HANGUL SYLLABLE SOP +C1A7;C1A7;1109 1169 11C2;C1A7;1109 1169 11C2; # (솧; 솧; 솧; 솧; 솧; ) HANGUL SYLLABLE SOH +C1A8;C1A8;1109 116A;C1A8;1109 116A; # (솨; 솨; 솨; 솨; 솨; ) HANGUL SYLLABLE SWA +C1A9;C1A9;1109 116A 11A8;C1A9;1109 116A 11A8; # (솩; 솩; 솩; 솩; 솩; ) HANGUL SYLLABLE SWAG +C1AA;C1AA;1109 116A 11A9;C1AA;1109 116A 11A9; # (솪; 솪; 솪; 솪; 솪; ) HANGUL SYLLABLE SWAGG +C1AB;C1AB;1109 116A 11AA;C1AB;1109 116A 11AA; # (솫; 솫; 솫; 솫; 솫; ) HANGUL SYLLABLE SWAGS +C1AC;C1AC;1109 116A 11AB;C1AC;1109 116A 11AB; # (솬; 솬; 솬; 솬; 솬; ) HANGUL SYLLABLE SWAN +C1AD;C1AD;1109 116A 11AC;C1AD;1109 116A 11AC; # (솭; 솭; 솭; 솭; 솭; ) HANGUL SYLLABLE SWANJ +C1AE;C1AE;1109 116A 11AD;C1AE;1109 116A 11AD; # (솮; 솮; 솮; 솮; 솮; ) HANGUL SYLLABLE SWANH +C1AF;C1AF;1109 116A 11AE;C1AF;1109 116A 11AE; # (솯; 솯; 솯; 솯; 솯; ) HANGUL SYLLABLE SWAD +C1B0;C1B0;1109 116A 11AF;C1B0;1109 116A 11AF; # (솰; 솰; 솰; 솰; 솰; ) HANGUL SYLLABLE SWAL +C1B1;C1B1;1109 116A 11B0;C1B1;1109 116A 11B0; # (솱; 솱; 솱; 솱; 솱; ) HANGUL SYLLABLE SWALG +C1B2;C1B2;1109 116A 11B1;C1B2;1109 116A 11B1; # (솲; 솲; 솲; 솲; 솲; ) HANGUL SYLLABLE SWALM +C1B3;C1B3;1109 116A 11B2;C1B3;1109 116A 11B2; # (솳; 솳; 솳; 솳; 솳; ) HANGUL SYLLABLE SWALB +C1B4;C1B4;1109 116A 11B3;C1B4;1109 116A 11B3; # (솴; 솴; 솴; 솴; 솴; ) HANGUL SYLLABLE SWALS +C1B5;C1B5;1109 116A 11B4;C1B5;1109 116A 11B4; # (솵; 솵; 솵; 솵; 솵; ) HANGUL SYLLABLE SWALT +C1B6;C1B6;1109 116A 11B5;C1B6;1109 116A 11B5; # (솶; 솶; 솶; 솶; 솶; ) HANGUL SYLLABLE SWALP +C1B7;C1B7;1109 116A 11B6;C1B7;1109 116A 11B6; # (솷; 솷; 솷; 솷; 솷; ) HANGUL SYLLABLE SWALH +C1B8;C1B8;1109 116A 11B7;C1B8;1109 116A 11B7; # (솸; 솸; 솸; 솸; 솸; ) HANGUL SYLLABLE SWAM +C1B9;C1B9;1109 116A 11B8;C1B9;1109 116A 11B8; # (솹; 솹; 솹; 솹; 솹; ) HANGUL SYLLABLE SWAB +C1BA;C1BA;1109 116A 11B9;C1BA;1109 116A 11B9; # (솺; 솺; 솺; 솺; 솺; ) HANGUL SYLLABLE SWABS +C1BB;C1BB;1109 116A 11BA;C1BB;1109 116A 11BA; # (솻; 솻; 솻; 솻; 솻; ) HANGUL SYLLABLE SWAS +C1BC;C1BC;1109 116A 11BB;C1BC;1109 116A 11BB; # (솼; 솼; 솼; 솼; 솼; ) HANGUL SYLLABLE SWASS +C1BD;C1BD;1109 116A 11BC;C1BD;1109 116A 11BC; # (솽; 솽; 솽; 솽; 솽; ) HANGUL SYLLABLE SWANG +C1BE;C1BE;1109 116A 11BD;C1BE;1109 116A 11BD; # (솾; 솾; 솾; 솾; 솾; ) HANGUL SYLLABLE SWAJ +C1BF;C1BF;1109 116A 11BE;C1BF;1109 116A 11BE; # (솿; 솿; 솿; 솿; 솿; ) HANGUL SYLLABLE SWAC +C1C0;C1C0;1109 116A 11BF;C1C0;1109 116A 11BF; # (쇀; 쇀; 쇀; 쇀; 쇀; ) HANGUL SYLLABLE SWAK +C1C1;C1C1;1109 116A 11C0;C1C1;1109 116A 11C0; # (쇁; 쇁; 쇁; 쇁; 쇁; ) HANGUL SYLLABLE SWAT +C1C2;C1C2;1109 116A 11C1;C1C2;1109 116A 11C1; # (쇂; 쇂; 쇂; 쇂; 쇂; ) HANGUL SYLLABLE SWAP +C1C3;C1C3;1109 116A 11C2;C1C3;1109 116A 11C2; # (쇃; 쇃; 쇃; 쇃; 쇃; ) HANGUL SYLLABLE SWAH +C1C4;C1C4;1109 116B;C1C4;1109 116B; # (쇄; 쇄; 쇄; 쇄; 쇄; ) HANGUL SYLLABLE SWAE +C1C5;C1C5;1109 116B 11A8;C1C5;1109 116B 11A8; # (쇅; 쇅; 쇅; 쇅; 쇅; ) HANGUL SYLLABLE SWAEG +C1C6;C1C6;1109 116B 11A9;C1C6;1109 116B 11A9; # (쇆; 쇆; 쇆; 쇆; 쇆; ) HANGUL SYLLABLE SWAEGG +C1C7;C1C7;1109 116B 11AA;C1C7;1109 116B 11AA; # (쇇; 쇇; 쇇; 쇇; 쇇; ) HANGUL SYLLABLE SWAEGS +C1C8;C1C8;1109 116B 11AB;C1C8;1109 116B 11AB; # (쇈; 쇈; 쇈; 쇈; 쇈; ) HANGUL SYLLABLE SWAEN +C1C9;C1C9;1109 116B 11AC;C1C9;1109 116B 11AC; # (쇉; 쇉; 쇉; 쇉; 쇉; ) HANGUL SYLLABLE SWAENJ +C1CA;C1CA;1109 116B 11AD;C1CA;1109 116B 11AD; # (쇊; 쇊; 쇊; 쇊; 쇊; ) HANGUL SYLLABLE SWAENH +C1CB;C1CB;1109 116B 11AE;C1CB;1109 116B 11AE; # (쇋; 쇋; 쇋; 쇋; 쇋; ) HANGUL SYLLABLE SWAED +C1CC;C1CC;1109 116B 11AF;C1CC;1109 116B 11AF; # (쇌; 쇌; 쇌; 쇌; 쇌; ) HANGUL SYLLABLE SWAEL +C1CD;C1CD;1109 116B 11B0;C1CD;1109 116B 11B0; # (쇍; 쇍; 쇍; 쇍; 쇍; ) HANGUL SYLLABLE SWAELG +C1CE;C1CE;1109 116B 11B1;C1CE;1109 116B 11B1; # (쇎; 쇎; 쇎; 쇎; 쇎; ) HANGUL SYLLABLE SWAELM +C1CF;C1CF;1109 116B 11B2;C1CF;1109 116B 11B2; # (쇏; 쇏; 쇏; 쇏; 쇏; ) HANGUL SYLLABLE SWAELB +C1D0;C1D0;1109 116B 11B3;C1D0;1109 116B 11B3; # (쇐; 쇐; 쇐; 쇐; 쇐; ) HANGUL SYLLABLE SWAELS +C1D1;C1D1;1109 116B 11B4;C1D1;1109 116B 11B4; # (쇑; 쇑; 쇑; 쇑; 쇑; ) HANGUL SYLLABLE SWAELT +C1D2;C1D2;1109 116B 11B5;C1D2;1109 116B 11B5; # (쇒; 쇒; 쇒; 쇒; 쇒; ) HANGUL SYLLABLE SWAELP +C1D3;C1D3;1109 116B 11B6;C1D3;1109 116B 11B6; # (쇓; 쇓; 쇓; 쇓; 쇓; ) HANGUL SYLLABLE SWAELH +C1D4;C1D4;1109 116B 11B7;C1D4;1109 116B 11B7; # (쇔; 쇔; 쇔; 쇔; 쇔; ) HANGUL SYLLABLE SWAEM +C1D5;C1D5;1109 116B 11B8;C1D5;1109 116B 11B8; # (쇕; 쇕; 쇕; 쇕; 쇕; ) HANGUL SYLLABLE SWAEB +C1D6;C1D6;1109 116B 11B9;C1D6;1109 116B 11B9; # (쇖; 쇖; 쇖; 쇖; 쇖; ) HANGUL SYLLABLE SWAEBS +C1D7;C1D7;1109 116B 11BA;C1D7;1109 116B 11BA; # (쇗; 쇗; 쇗; 쇗; 쇗; ) HANGUL SYLLABLE SWAES +C1D8;C1D8;1109 116B 11BB;C1D8;1109 116B 11BB; # (쇘; 쇘; 쇘; 쇘; 쇘; ) HANGUL SYLLABLE SWAESS +C1D9;C1D9;1109 116B 11BC;C1D9;1109 116B 11BC; # (쇙; 쇙; 쇙; 쇙; 쇙; ) HANGUL SYLLABLE SWAENG +C1DA;C1DA;1109 116B 11BD;C1DA;1109 116B 11BD; # (쇚; 쇚; 쇚; 쇚; 쇚; ) HANGUL SYLLABLE SWAEJ +C1DB;C1DB;1109 116B 11BE;C1DB;1109 116B 11BE; # (쇛; 쇛; 쇛; 쇛; 쇛; ) HANGUL SYLLABLE SWAEC +C1DC;C1DC;1109 116B 11BF;C1DC;1109 116B 11BF; # (쇜; 쇜; 쇜; 쇜; 쇜; ) HANGUL SYLLABLE SWAEK +C1DD;C1DD;1109 116B 11C0;C1DD;1109 116B 11C0; # (쇝; 쇝; 쇝; 쇝; 쇝; ) HANGUL SYLLABLE SWAET +C1DE;C1DE;1109 116B 11C1;C1DE;1109 116B 11C1; # (쇞; 쇞; 쇞; 쇞; 쇞; ) HANGUL SYLLABLE SWAEP +C1DF;C1DF;1109 116B 11C2;C1DF;1109 116B 11C2; # (쇟; 쇟; 쇟; 쇟; 쇟; ) HANGUL SYLLABLE SWAEH +C1E0;C1E0;1109 116C;C1E0;1109 116C; # (쇠; 쇠; 쇠; 쇠; 쇠; ) HANGUL SYLLABLE SOE +C1E1;C1E1;1109 116C 11A8;C1E1;1109 116C 11A8; # (쇡; 쇡; 쇡; 쇡; 쇡; ) HANGUL SYLLABLE SOEG +C1E2;C1E2;1109 116C 11A9;C1E2;1109 116C 11A9; # (쇢; 쇢; 쇢; 쇢; 쇢; ) HANGUL SYLLABLE SOEGG +C1E3;C1E3;1109 116C 11AA;C1E3;1109 116C 11AA; # (쇣; 쇣; 쇣; 쇣; 쇣; ) HANGUL SYLLABLE SOEGS +C1E4;C1E4;1109 116C 11AB;C1E4;1109 116C 11AB; # (쇤; 쇤; 쇤; 쇤; 쇤; ) HANGUL SYLLABLE SOEN +C1E5;C1E5;1109 116C 11AC;C1E5;1109 116C 11AC; # (쇥; 쇥; 쇥; 쇥; 쇥; ) HANGUL SYLLABLE SOENJ +C1E6;C1E6;1109 116C 11AD;C1E6;1109 116C 11AD; # (쇦; 쇦; 쇦; 쇦; 쇦; ) HANGUL SYLLABLE SOENH +C1E7;C1E7;1109 116C 11AE;C1E7;1109 116C 11AE; # (쇧; 쇧; 쇧; 쇧; 쇧; ) HANGUL SYLLABLE SOED +C1E8;C1E8;1109 116C 11AF;C1E8;1109 116C 11AF; # (쇨; 쇨; 쇨; 쇨; 쇨; ) HANGUL SYLLABLE SOEL +C1E9;C1E9;1109 116C 11B0;C1E9;1109 116C 11B0; # (쇩; 쇩; 쇩; 쇩; 쇩; ) HANGUL SYLLABLE SOELG +C1EA;C1EA;1109 116C 11B1;C1EA;1109 116C 11B1; # (쇪; 쇪; 쇪; 쇪; 쇪; ) HANGUL SYLLABLE SOELM +C1EB;C1EB;1109 116C 11B2;C1EB;1109 116C 11B2; # (쇫; 쇫; 쇫; 쇫; 쇫; ) HANGUL SYLLABLE SOELB +C1EC;C1EC;1109 116C 11B3;C1EC;1109 116C 11B3; # (쇬; 쇬; 쇬; 쇬; 쇬; ) HANGUL SYLLABLE SOELS +C1ED;C1ED;1109 116C 11B4;C1ED;1109 116C 11B4; # (쇭; 쇭; 쇭; 쇭; 쇭; ) HANGUL SYLLABLE SOELT +C1EE;C1EE;1109 116C 11B5;C1EE;1109 116C 11B5; # (쇮; 쇮; 쇮; 쇮; 쇮; ) HANGUL SYLLABLE SOELP +C1EF;C1EF;1109 116C 11B6;C1EF;1109 116C 11B6; # (쇯; 쇯; 쇯; 쇯; 쇯; ) HANGUL SYLLABLE SOELH +C1F0;C1F0;1109 116C 11B7;C1F0;1109 116C 11B7; # (쇰; 쇰; 쇰; 쇰; 쇰; ) HANGUL SYLLABLE SOEM +C1F1;C1F1;1109 116C 11B8;C1F1;1109 116C 11B8; # (쇱; 쇱; 쇱; 쇱; 쇱; ) HANGUL SYLLABLE SOEB +C1F2;C1F2;1109 116C 11B9;C1F2;1109 116C 11B9; # (쇲; 쇲; 쇲; 쇲; 쇲; ) HANGUL SYLLABLE SOEBS +C1F3;C1F3;1109 116C 11BA;C1F3;1109 116C 11BA; # (쇳; 쇳; 쇳; 쇳; 쇳; ) HANGUL SYLLABLE SOES +C1F4;C1F4;1109 116C 11BB;C1F4;1109 116C 11BB; # (쇴; 쇴; 쇴; 쇴; 쇴; ) HANGUL SYLLABLE SOESS +C1F5;C1F5;1109 116C 11BC;C1F5;1109 116C 11BC; # (쇵; 쇵; 쇵; 쇵; 쇵; ) HANGUL SYLLABLE SOENG +C1F6;C1F6;1109 116C 11BD;C1F6;1109 116C 11BD; # (쇶; 쇶; 쇶; 쇶; 쇶; ) HANGUL SYLLABLE SOEJ +C1F7;C1F7;1109 116C 11BE;C1F7;1109 116C 11BE; # (쇷; 쇷; 쇷; 쇷; 쇷; ) HANGUL SYLLABLE SOEC +C1F8;C1F8;1109 116C 11BF;C1F8;1109 116C 11BF; # (쇸; 쇸; 쇸; 쇸; 쇸; ) HANGUL SYLLABLE SOEK +C1F9;C1F9;1109 116C 11C0;C1F9;1109 116C 11C0; # (쇹; 쇹; 쇹; 쇹; 쇹; ) HANGUL SYLLABLE SOET +C1FA;C1FA;1109 116C 11C1;C1FA;1109 116C 11C1; # (쇺; 쇺; 쇺; 쇺; 쇺; ) HANGUL SYLLABLE SOEP +C1FB;C1FB;1109 116C 11C2;C1FB;1109 116C 11C2; # (쇻; 쇻; 쇻; 쇻; 쇻; ) HANGUL SYLLABLE SOEH +C1FC;C1FC;1109 116D;C1FC;1109 116D; # (쇼; 쇼; 쇼; 쇼; 쇼; ) HANGUL SYLLABLE SYO +C1FD;C1FD;1109 116D 11A8;C1FD;1109 116D 11A8; # (쇽; 쇽; 쇽; 쇽; 쇽; ) HANGUL SYLLABLE SYOG +C1FE;C1FE;1109 116D 11A9;C1FE;1109 116D 11A9; # (쇾; 쇾; 쇾; 쇾; 쇾; ) HANGUL SYLLABLE SYOGG +C1FF;C1FF;1109 116D 11AA;C1FF;1109 116D 11AA; # (쇿; 쇿; 쇿; 쇿; 쇿; ) HANGUL SYLLABLE SYOGS +C200;C200;1109 116D 11AB;C200;1109 116D 11AB; # (숀; 숀; 숀; 숀; 숀; ) HANGUL SYLLABLE SYON +C201;C201;1109 116D 11AC;C201;1109 116D 11AC; # (숁; 숁; 숁; 숁; 숁; ) HANGUL SYLLABLE SYONJ +C202;C202;1109 116D 11AD;C202;1109 116D 11AD; # (숂; 숂; 숂; 숂; 숂; ) HANGUL SYLLABLE SYONH +C203;C203;1109 116D 11AE;C203;1109 116D 11AE; # (숃; 숃; 숃; 숃; 숃; ) HANGUL SYLLABLE SYOD +C204;C204;1109 116D 11AF;C204;1109 116D 11AF; # (숄; 숄; 숄; 숄; 숄; ) HANGUL SYLLABLE SYOL +C205;C205;1109 116D 11B0;C205;1109 116D 11B0; # (숅; 숅; 숅; 숅; 숅; ) HANGUL SYLLABLE SYOLG +C206;C206;1109 116D 11B1;C206;1109 116D 11B1; # (숆; 숆; 숆; 숆; 숆; ) HANGUL SYLLABLE SYOLM +C207;C207;1109 116D 11B2;C207;1109 116D 11B2; # (숇; 숇; 숇; 숇; 숇; ) HANGUL SYLLABLE SYOLB +C208;C208;1109 116D 11B3;C208;1109 116D 11B3; # (숈; 숈; 숈; 숈; 숈; ) HANGUL SYLLABLE SYOLS +C209;C209;1109 116D 11B4;C209;1109 116D 11B4; # (숉; 숉; 숉; 숉; 숉; ) HANGUL SYLLABLE SYOLT +C20A;C20A;1109 116D 11B5;C20A;1109 116D 11B5; # (숊; 숊; 숊; 숊; 숊; ) HANGUL SYLLABLE SYOLP +C20B;C20B;1109 116D 11B6;C20B;1109 116D 11B6; # (숋; 숋; 숋; 숋; 숋; ) HANGUL SYLLABLE SYOLH +C20C;C20C;1109 116D 11B7;C20C;1109 116D 11B7; # (숌; 숌; 숌; 숌; 숌; ) HANGUL SYLLABLE SYOM +C20D;C20D;1109 116D 11B8;C20D;1109 116D 11B8; # (숍; 숍; 숍; 숍; 숍; ) HANGUL SYLLABLE SYOB +C20E;C20E;1109 116D 11B9;C20E;1109 116D 11B9; # (숎; 숎; 숎; 숎; 숎; ) HANGUL SYLLABLE SYOBS +C20F;C20F;1109 116D 11BA;C20F;1109 116D 11BA; # (숏; 숏; 숏; 숏; 숏; ) HANGUL SYLLABLE SYOS +C210;C210;1109 116D 11BB;C210;1109 116D 11BB; # (숐; 숐; 숐; 숐; 숐; ) HANGUL SYLLABLE SYOSS +C211;C211;1109 116D 11BC;C211;1109 116D 11BC; # (숑; 숑; 숑; 숑; 숑; ) HANGUL SYLLABLE SYONG +C212;C212;1109 116D 11BD;C212;1109 116D 11BD; # (숒; 숒; 숒; 숒; 숒; ) HANGUL SYLLABLE SYOJ +C213;C213;1109 116D 11BE;C213;1109 116D 11BE; # (숓; 숓; 숓; 숓; 숓; ) HANGUL SYLLABLE SYOC +C214;C214;1109 116D 11BF;C214;1109 116D 11BF; # (숔; 숔; 숔; 숔; 숔; ) HANGUL SYLLABLE SYOK +C215;C215;1109 116D 11C0;C215;1109 116D 11C0; # (숕; 숕; 숕; 숕; 숕; ) HANGUL SYLLABLE SYOT +C216;C216;1109 116D 11C1;C216;1109 116D 11C1; # (숖; 숖; 숖; 숖; 숖; ) HANGUL SYLLABLE SYOP +C217;C217;1109 116D 11C2;C217;1109 116D 11C2; # (숗; 숗; 숗; 숗; 숗; ) HANGUL SYLLABLE SYOH +C218;C218;1109 116E;C218;1109 116E; # (수; 수; 수; 수; 수; ) HANGUL SYLLABLE SU +C219;C219;1109 116E 11A8;C219;1109 116E 11A8; # (숙; 숙; 숙; 숙; 숙; ) HANGUL SYLLABLE SUG +C21A;C21A;1109 116E 11A9;C21A;1109 116E 11A9; # (숚; 숚; 숚; 숚; 숚; ) HANGUL SYLLABLE SUGG +C21B;C21B;1109 116E 11AA;C21B;1109 116E 11AA; # (숛; 숛; 숛; 숛; 숛; ) HANGUL SYLLABLE SUGS +C21C;C21C;1109 116E 11AB;C21C;1109 116E 11AB; # (순; 순; 순; 순; 순; ) HANGUL SYLLABLE SUN +C21D;C21D;1109 116E 11AC;C21D;1109 116E 11AC; # (숝; 숝; 숝; 숝; 숝; ) HANGUL SYLLABLE SUNJ +C21E;C21E;1109 116E 11AD;C21E;1109 116E 11AD; # (숞; 숞; 숞; 숞; 숞; ) HANGUL SYLLABLE SUNH +C21F;C21F;1109 116E 11AE;C21F;1109 116E 11AE; # (숟; 숟; 숟; 숟; 숟; ) HANGUL SYLLABLE SUD +C220;C220;1109 116E 11AF;C220;1109 116E 11AF; # (술; 술; 술; 술; 술; ) HANGUL SYLLABLE SUL +C221;C221;1109 116E 11B0;C221;1109 116E 11B0; # (숡; 숡; 숡; 숡; 숡; ) HANGUL SYLLABLE SULG +C222;C222;1109 116E 11B1;C222;1109 116E 11B1; # (숢; 숢; 숢; 숢; 숢; ) HANGUL SYLLABLE SULM +C223;C223;1109 116E 11B2;C223;1109 116E 11B2; # (숣; 숣; 숣; 숣; 숣; ) HANGUL SYLLABLE SULB +C224;C224;1109 116E 11B3;C224;1109 116E 11B3; # (숤; 숤; 숤; 숤; 숤; ) HANGUL SYLLABLE SULS +C225;C225;1109 116E 11B4;C225;1109 116E 11B4; # (숥; 숥; 숥; 숥; 숥; ) HANGUL SYLLABLE SULT +C226;C226;1109 116E 11B5;C226;1109 116E 11B5; # (숦; 숦; 숦; 숦; 숦; ) HANGUL SYLLABLE SULP +C227;C227;1109 116E 11B6;C227;1109 116E 11B6; # (숧; 숧; 숧; 숧; 숧; ) HANGUL SYLLABLE SULH +C228;C228;1109 116E 11B7;C228;1109 116E 11B7; # (숨; 숨; 숨; 숨; 숨; ) HANGUL SYLLABLE SUM +C229;C229;1109 116E 11B8;C229;1109 116E 11B8; # (숩; 숩; 숩; 숩; 숩; ) HANGUL SYLLABLE SUB +C22A;C22A;1109 116E 11B9;C22A;1109 116E 11B9; # (숪; 숪; 숪; 숪; 숪; ) HANGUL SYLLABLE SUBS +C22B;C22B;1109 116E 11BA;C22B;1109 116E 11BA; # (숫; 숫; 숫; 숫; 숫; ) HANGUL SYLLABLE SUS +C22C;C22C;1109 116E 11BB;C22C;1109 116E 11BB; # (숬; 숬; 숬; 숬; 숬; ) HANGUL SYLLABLE SUSS +C22D;C22D;1109 116E 11BC;C22D;1109 116E 11BC; # (숭; 숭; 숭; 숭; 숭; ) HANGUL SYLLABLE SUNG +C22E;C22E;1109 116E 11BD;C22E;1109 116E 11BD; # (숮; 숮; 숮; 숮; 숮; ) HANGUL SYLLABLE SUJ +C22F;C22F;1109 116E 11BE;C22F;1109 116E 11BE; # (숯; 숯; 숯; 숯; 숯; ) HANGUL SYLLABLE SUC +C230;C230;1109 116E 11BF;C230;1109 116E 11BF; # (숰; 숰; 숰; 숰; 숰; ) HANGUL SYLLABLE SUK +C231;C231;1109 116E 11C0;C231;1109 116E 11C0; # (숱; 숱; 숱; 숱; 숱; ) HANGUL SYLLABLE SUT +C232;C232;1109 116E 11C1;C232;1109 116E 11C1; # (숲; 숲; 숲; 숲; 숲; ) HANGUL SYLLABLE SUP +C233;C233;1109 116E 11C2;C233;1109 116E 11C2; # (숳; 숳; 숳; 숳; 숳; ) HANGUL SYLLABLE SUH +C234;C234;1109 116F;C234;1109 116F; # (숴; 숴; 숴; 숴; 숴; ) HANGUL SYLLABLE SWEO +C235;C235;1109 116F 11A8;C235;1109 116F 11A8; # (숵; 숵; 숵; 숵; 숵; ) HANGUL SYLLABLE SWEOG +C236;C236;1109 116F 11A9;C236;1109 116F 11A9; # (숶; 숶; 숶; 숶; 숶; ) HANGUL SYLLABLE SWEOGG +C237;C237;1109 116F 11AA;C237;1109 116F 11AA; # (숷; 숷; 숷; 숷; 숷; ) HANGUL SYLLABLE SWEOGS +C238;C238;1109 116F 11AB;C238;1109 116F 11AB; # (숸; 숸; 숸; 숸; 숸; ) HANGUL SYLLABLE SWEON +C239;C239;1109 116F 11AC;C239;1109 116F 11AC; # (숹; 숹; 숹; 숹; 숹; ) HANGUL SYLLABLE SWEONJ +C23A;C23A;1109 116F 11AD;C23A;1109 116F 11AD; # (숺; 숺; 숺; 숺; 숺; ) HANGUL SYLLABLE SWEONH +C23B;C23B;1109 116F 11AE;C23B;1109 116F 11AE; # (숻; 숻; 숻; 숻; 숻; ) HANGUL SYLLABLE SWEOD +C23C;C23C;1109 116F 11AF;C23C;1109 116F 11AF; # (숼; 숼; 숼; 숼; 숼; ) HANGUL SYLLABLE SWEOL +C23D;C23D;1109 116F 11B0;C23D;1109 116F 11B0; # (숽; 숽; 숽; 숽; 숽; ) HANGUL SYLLABLE SWEOLG +C23E;C23E;1109 116F 11B1;C23E;1109 116F 11B1; # (숾; 숾; 숾; 숾; 숾; ) HANGUL SYLLABLE SWEOLM +C23F;C23F;1109 116F 11B2;C23F;1109 116F 11B2; # (숿; 숿; 숿; 숿; 숿; ) HANGUL SYLLABLE SWEOLB +C240;C240;1109 116F 11B3;C240;1109 116F 11B3; # (쉀; 쉀; 쉀; 쉀; 쉀; ) HANGUL SYLLABLE SWEOLS +C241;C241;1109 116F 11B4;C241;1109 116F 11B4; # (쉁; 쉁; 쉁; 쉁; 쉁; ) HANGUL SYLLABLE SWEOLT +C242;C242;1109 116F 11B5;C242;1109 116F 11B5; # (쉂; 쉂; 쉂; 쉂; 쉂; ) HANGUL SYLLABLE SWEOLP +C243;C243;1109 116F 11B6;C243;1109 116F 11B6; # (쉃; 쉃; 쉃; 쉃; 쉃; ) HANGUL SYLLABLE SWEOLH +C244;C244;1109 116F 11B7;C244;1109 116F 11B7; # (쉄; 쉄; 쉄; 쉄; 쉄; ) HANGUL SYLLABLE SWEOM +C245;C245;1109 116F 11B8;C245;1109 116F 11B8; # (쉅; 쉅; 쉅; 쉅; 쉅; ) HANGUL SYLLABLE SWEOB +C246;C246;1109 116F 11B9;C246;1109 116F 11B9; # (쉆; 쉆; 쉆; 쉆; 쉆; ) HANGUL SYLLABLE SWEOBS +C247;C247;1109 116F 11BA;C247;1109 116F 11BA; # (쉇; 쉇; 쉇; 쉇; 쉇; ) HANGUL SYLLABLE SWEOS +C248;C248;1109 116F 11BB;C248;1109 116F 11BB; # (쉈; 쉈; 쉈; 쉈; 쉈; ) HANGUL SYLLABLE SWEOSS +C249;C249;1109 116F 11BC;C249;1109 116F 11BC; # (쉉; 쉉; 쉉; 쉉; 쉉; ) HANGUL SYLLABLE SWEONG +C24A;C24A;1109 116F 11BD;C24A;1109 116F 11BD; # (쉊; 쉊; 쉊; 쉊; 쉊; ) HANGUL SYLLABLE SWEOJ +C24B;C24B;1109 116F 11BE;C24B;1109 116F 11BE; # (쉋; 쉋; 쉋; 쉋; 쉋; ) HANGUL SYLLABLE SWEOC +C24C;C24C;1109 116F 11BF;C24C;1109 116F 11BF; # (쉌; 쉌; 쉌; 쉌; 쉌; ) HANGUL SYLLABLE SWEOK +C24D;C24D;1109 116F 11C0;C24D;1109 116F 11C0; # (쉍; 쉍; 쉍; 쉍; 쉍; ) HANGUL SYLLABLE SWEOT +C24E;C24E;1109 116F 11C1;C24E;1109 116F 11C1; # (쉎; 쉎; 쉎; 쉎; 쉎; ) HANGUL SYLLABLE SWEOP +C24F;C24F;1109 116F 11C2;C24F;1109 116F 11C2; # (쉏; 쉏; 쉏; 쉏; 쉏; ) HANGUL SYLLABLE SWEOH +C250;C250;1109 1170;C250;1109 1170; # (쉐; 쉐; 쉐; 쉐; 쉐; ) HANGUL SYLLABLE SWE +C251;C251;1109 1170 11A8;C251;1109 1170 11A8; # (쉑; 쉑; 쉑; 쉑; 쉑; ) HANGUL SYLLABLE SWEG +C252;C252;1109 1170 11A9;C252;1109 1170 11A9; # (쉒; 쉒; 쉒; 쉒; 쉒; ) HANGUL SYLLABLE SWEGG +C253;C253;1109 1170 11AA;C253;1109 1170 11AA; # (쉓; 쉓; 쉓; 쉓; 쉓; ) HANGUL SYLLABLE SWEGS +C254;C254;1109 1170 11AB;C254;1109 1170 11AB; # (쉔; 쉔; 쉔; 쉔; 쉔; ) HANGUL SYLLABLE SWEN +C255;C255;1109 1170 11AC;C255;1109 1170 11AC; # (쉕; 쉕; 쉕; 쉕; 쉕; ) HANGUL SYLLABLE SWENJ +C256;C256;1109 1170 11AD;C256;1109 1170 11AD; # (쉖; 쉖; 쉖; 쉖; 쉖; ) HANGUL SYLLABLE SWENH +C257;C257;1109 1170 11AE;C257;1109 1170 11AE; # (쉗; 쉗; 쉗; 쉗; 쉗; ) HANGUL SYLLABLE SWED +C258;C258;1109 1170 11AF;C258;1109 1170 11AF; # (쉘; 쉘; 쉘; 쉘; 쉘; ) HANGUL SYLLABLE SWEL +C259;C259;1109 1170 11B0;C259;1109 1170 11B0; # (쉙; 쉙; 쉙; 쉙; 쉙; ) HANGUL SYLLABLE SWELG +C25A;C25A;1109 1170 11B1;C25A;1109 1170 11B1; # (쉚; 쉚; 쉚; 쉚; 쉚; ) HANGUL SYLLABLE SWELM +C25B;C25B;1109 1170 11B2;C25B;1109 1170 11B2; # (쉛; 쉛; 쉛; 쉛; 쉛; ) HANGUL SYLLABLE SWELB +C25C;C25C;1109 1170 11B3;C25C;1109 1170 11B3; # (쉜; 쉜; 쉜; 쉜; 쉜; ) HANGUL SYLLABLE SWELS +C25D;C25D;1109 1170 11B4;C25D;1109 1170 11B4; # (쉝; 쉝; 쉝; 쉝; 쉝; ) HANGUL SYLLABLE SWELT +C25E;C25E;1109 1170 11B5;C25E;1109 1170 11B5; # (쉞; 쉞; 쉞; 쉞; 쉞; ) HANGUL SYLLABLE SWELP +C25F;C25F;1109 1170 11B6;C25F;1109 1170 11B6; # (쉟; 쉟; 쉟; 쉟; 쉟; ) HANGUL SYLLABLE SWELH +C260;C260;1109 1170 11B7;C260;1109 1170 11B7; # (쉠; 쉠; 쉠; 쉠; 쉠; ) HANGUL SYLLABLE SWEM +C261;C261;1109 1170 11B8;C261;1109 1170 11B8; # (쉡; 쉡; 쉡; 쉡; 쉡; ) HANGUL SYLLABLE SWEB +C262;C262;1109 1170 11B9;C262;1109 1170 11B9; # (쉢; 쉢; 쉢; 쉢; 쉢; ) HANGUL SYLLABLE SWEBS +C263;C263;1109 1170 11BA;C263;1109 1170 11BA; # (쉣; 쉣; 쉣; 쉣; 쉣; ) HANGUL SYLLABLE SWES +C264;C264;1109 1170 11BB;C264;1109 1170 11BB; # (쉤; 쉤; 쉤; 쉤; 쉤; ) HANGUL SYLLABLE SWESS +C265;C265;1109 1170 11BC;C265;1109 1170 11BC; # (쉥; 쉥; 쉥; 쉥; 쉥; ) HANGUL SYLLABLE SWENG +C266;C266;1109 1170 11BD;C266;1109 1170 11BD; # (쉦; 쉦; 쉦; 쉦; 쉦; ) HANGUL SYLLABLE SWEJ +C267;C267;1109 1170 11BE;C267;1109 1170 11BE; # (쉧; 쉧; 쉧; 쉧; 쉧; ) HANGUL SYLLABLE SWEC +C268;C268;1109 1170 11BF;C268;1109 1170 11BF; # (쉨; 쉨; 쉨; 쉨; 쉨; ) HANGUL SYLLABLE SWEK +C269;C269;1109 1170 11C0;C269;1109 1170 11C0; # (쉩; 쉩; 쉩; 쉩; 쉩; ) HANGUL SYLLABLE SWET +C26A;C26A;1109 1170 11C1;C26A;1109 1170 11C1; # (쉪; 쉪; 쉪; 쉪; 쉪; ) HANGUL SYLLABLE SWEP +C26B;C26B;1109 1170 11C2;C26B;1109 1170 11C2; # (쉫; 쉫; 쉫; 쉫; 쉫; ) HANGUL SYLLABLE SWEH +C26C;C26C;1109 1171;C26C;1109 1171; # (쉬; 쉬; 쉬; 쉬; 쉬; ) HANGUL SYLLABLE SWI +C26D;C26D;1109 1171 11A8;C26D;1109 1171 11A8; # (쉭; 쉭; 쉭; 쉭; 쉭; ) HANGUL SYLLABLE SWIG +C26E;C26E;1109 1171 11A9;C26E;1109 1171 11A9; # (쉮; 쉮; 쉮; 쉮; 쉮; ) HANGUL SYLLABLE SWIGG +C26F;C26F;1109 1171 11AA;C26F;1109 1171 11AA; # (쉯; 쉯; 쉯; 쉯; 쉯; ) HANGUL SYLLABLE SWIGS +C270;C270;1109 1171 11AB;C270;1109 1171 11AB; # (쉰; 쉰; 쉰; 쉰; 쉰; ) HANGUL SYLLABLE SWIN +C271;C271;1109 1171 11AC;C271;1109 1171 11AC; # (쉱; 쉱; 쉱; 쉱; 쉱; ) HANGUL SYLLABLE SWINJ +C272;C272;1109 1171 11AD;C272;1109 1171 11AD; # (쉲; 쉲; 쉲; 쉲; 쉲; ) HANGUL SYLLABLE SWINH +C273;C273;1109 1171 11AE;C273;1109 1171 11AE; # (쉳; 쉳; 쉳; 쉳; 쉳; ) HANGUL SYLLABLE SWID +C274;C274;1109 1171 11AF;C274;1109 1171 11AF; # (쉴; 쉴; 쉴; 쉴; 쉴; ) HANGUL SYLLABLE SWIL +C275;C275;1109 1171 11B0;C275;1109 1171 11B0; # (쉵; 쉵; 쉵; 쉵; 쉵; ) HANGUL SYLLABLE SWILG +C276;C276;1109 1171 11B1;C276;1109 1171 11B1; # (쉶; 쉶; 쉶; 쉶; 쉶; ) HANGUL SYLLABLE SWILM +C277;C277;1109 1171 11B2;C277;1109 1171 11B2; # (쉷; 쉷; 쉷; 쉷; 쉷; ) HANGUL SYLLABLE SWILB +C278;C278;1109 1171 11B3;C278;1109 1171 11B3; # (쉸; 쉸; 쉸; 쉸; 쉸; ) HANGUL SYLLABLE SWILS +C279;C279;1109 1171 11B4;C279;1109 1171 11B4; # (쉹; 쉹; 쉹; 쉹; 쉹; ) HANGUL SYLLABLE SWILT +C27A;C27A;1109 1171 11B5;C27A;1109 1171 11B5; # (쉺; 쉺; 쉺; 쉺; 쉺; ) HANGUL SYLLABLE SWILP +C27B;C27B;1109 1171 11B6;C27B;1109 1171 11B6; # (쉻; 쉻; 쉻; 쉻; 쉻; ) HANGUL SYLLABLE SWILH +C27C;C27C;1109 1171 11B7;C27C;1109 1171 11B7; # (쉼; 쉼; 쉼; 쉼; 쉼; ) HANGUL SYLLABLE SWIM +C27D;C27D;1109 1171 11B8;C27D;1109 1171 11B8; # (쉽; 쉽; 쉽; 쉽; 쉽; ) HANGUL SYLLABLE SWIB +C27E;C27E;1109 1171 11B9;C27E;1109 1171 11B9; # (쉾; 쉾; 쉾; 쉾; 쉾; ) HANGUL SYLLABLE SWIBS +C27F;C27F;1109 1171 11BA;C27F;1109 1171 11BA; # (쉿; 쉿; 쉿; 쉿; 쉿; ) HANGUL SYLLABLE SWIS +C280;C280;1109 1171 11BB;C280;1109 1171 11BB; # (슀; 슀; 슀; 슀; 슀; ) HANGUL SYLLABLE SWISS +C281;C281;1109 1171 11BC;C281;1109 1171 11BC; # (슁; 슁; 슁; 슁; 슁; ) HANGUL SYLLABLE SWING +C282;C282;1109 1171 11BD;C282;1109 1171 11BD; # (슂; 슂; 슂; 슂; 슂; ) HANGUL SYLLABLE SWIJ +C283;C283;1109 1171 11BE;C283;1109 1171 11BE; # (슃; 슃; 슃; 슃; 슃; ) HANGUL SYLLABLE SWIC +C284;C284;1109 1171 11BF;C284;1109 1171 11BF; # (슄; 슄; 슄; 슄; 슄; ) HANGUL SYLLABLE SWIK +C285;C285;1109 1171 11C0;C285;1109 1171 11C0; # (슅; 슅; 슅; 슅; 슅; ) HANGUL SYLLABLE SWIT +C286;C286;1109 1171 11C1;C286;1109 1171 11C1; # (슆; 슆; 슆; 슆; 슆; ) HANGUL SYLLABLE SWIP +C287;C287;1109 1171 11C2;C287;1109 1171 11C2; # (슇; 슇; 슇; 슇; 슇; ) HANGUL SYLLABLE SWIH +C288;C288;1109 1172;C288;1109 1172; # (슈; 슈; 슈; 슈; 슈; ) HANGUL SYLLABLE SYU +C289;C289;1109 1172 11A8;C289;1109 1172 11A8; # (슉; 슉; 슉; 슉; 슉; ) HANGUL SYLLABLE SYUG +C28A;C28A;1109 1172 11A9;C28A;1109 1172 11A9; # (슊; 슊; 슊; 슊; 슊; ) HANGUL SYLLABLE SYUGG +C28B;C28B;1109 1172 11AA;C28B;1109 1172 11AA; # (슋; 슋; 슋; 슋; 슋; ) HANGUL SYLLABLE SYUGS +C28C;C28C;1109 1172 11AB;C28C;1109 1172 11AB; # (슌; 슌; 슌; 슌; 슌; ) HANGUL SYLLABLE SYUN +C28D;C28D;1109 1172 11AC;C28D;1109 1172 11AC; # (슍; 슍; 슍; 슍; 슍; ) HANGUL SYLLABLE SYUNJ +C28E;C28E;1109 1172 11AD;C28E;1109 1172 11AD; # (슎; 슎; 슎; 슎; 슎; ) HANGUL SYLLABLE SYUNH +C28F;C28F;1109 1172 11AE;C28F;1109 1172 11AE; # (슏; 슏; 슏; 슏; 슏; ) HANGUL SYLLABLE SYUD +C290;C290;1109 1172 11AF;C290;1109 1172 11AF; # (슐; 슐; 슐; 슐; 슐; ) HANGUL SYLLABLE SYUL +C291;C291;1109 1172 11B0;C291;1109 1172 11B0; # (슑; 슑; 슑; 슑; 슑; ) HANGUL SYLLABLE SYULG +C292;C292;1109 1172 11B1;C292;1109 1172 11B1; # (슒; 슒; 슒; 슒; 슒; ) HANGUL SYLLABLE SYULM +C293;C293;1109 1172 11B2;C293;1109 1172 11B2; # (슓; 슓; 슓; 슓; 슓; ) HANGUL SYLLABLE SYULB +C294;C294;1109 1172 11B3;C294;1109 1172 11B3; # (슔; 슔; 슔; 슔; 슔; ) HANGUL SYLLABLE SYULS +C295;C295;1109 1172 11B4;C295;1109 1172 11B4; # (슕; 슕; 슕; 슕; 슕; ) HANGUL SYLLABLE SYULT +C296;C296;1109 1172 11B5;C296;1109 1172 11B5; # (슖; 슖; 슖; 슖; 슖; ) HANGUL SYLLABLE SYULP +C297;C297;1109 1172 11B6;C297;1109 1172 11B6; # (슗; 슗; 슗; 슗; 슗; ) HANGUL SYLLABLE SYULH +C298;C298;1109 1172 11B7;C298;1109 1172 11B7; # (슘; 슘; 슘; 슘; 슘; ) HANGUL SYLLABLE SYUM +C299;C299;1109 1172 11B8;C299;1109 1172 11B8; # (슙; 슙; 슙; 슙; 슙; ) HANGUL SYLLABLE SYUB +C29A;C29A;1109 1172 11B9;C29A;1109 1172 11B9; # (슚; 슚; 슚; 슚; 슚; ) HANGUL SYLLABLE SYUBS +C29B;C29B;1109 1172 11BA;C29B;1109 1172 11BA; # (슛; 슛; 슛; 슛; 슛; ) HANGUL SYLLABLE SYUS +C29C;C29C;1109 1172 11BB;C29C;1109 1172 11BB; # (슜; 슜; 슜; 슜; 슜; ) HANGUL SYLLABLE SYUSS +C29D;C29D;1109 1172 11BC;C29D;1109 1172 11BC; # (슝; 슝; 슝; 슝; 슝; ) HANGUL SYLLABLE SYUNG +C29E;C29E;1109 1172 11BD;C29E;1109 1172 11BD; # (슞; 슞; 슞; 슞; 슞; ) HANGUL SYLLABLE SYUJ +C29F;C29F;1109 1172 11BE;C29F;1109 1172 11BE; # (슟; 슟; 슟; 슟; 슟; ) HANGUL SYLLABLE SYUC +C2A0;C2A0;1109 1172 11BF;C2A0;1109 1172 11BF; # (슠; 슠; 슠; 슠; 슠; ) HANGUL SYLLABLE SYUK +C2A1;C2A1;1109 1172 11C0;C2A1;1109 1172 11C0; # (슡; 슡; 슡; 슡; 슡; ) HANGUL SYLLABLE SYUT +C2A2;C2A2;1109 1172 11C1;C2A2;1109 1172 11C1; # (슢; 슢; 슢; 슢; 슢; ) HANGUL SYLLABLE SYUP +C2A3;C2A3;1109 1172 11C2;C2A3;1109 1172 11C2; # (슣; 슣; 슣; 슣; 슣; ) HANGUL SYLLABLE SYUH +C2A4;C2A4;1109 1173;C2A4;1109 1173; # (스; 스; 스; 스; 스; ) HANGUL SYLLABLE SEU +C2A5;C2A5;1109 1173 11A8;C2A5;1109 1173 11A8; # (슥; 슥; 슥; 슥; 슥; ) HANGUL SYLLABLE SEUG +C2A6;C2A6;1109 1173 11A9;C2A6;1109 1173 11A9; # (슦; 슦; 슦; 슦; 슦; ) HANGUL SYLLABLE SEUGG +C2A7;C2A7;1109 1173 11AA;C2A7;1109 1173 11AA; # (슧; 슧; 슧; 슧; 슧; ) HANGUL SYLLABLE SEUGS +C2A8;C2A8;1109 1173 11AB;C2A8;1109 1173 11AB; # (슨; 슨; 슨; 슨; 슨; ) HANGUL SYLLABLE SEUN +C2A9;C2A9;1109 1173 11AC;C2A9;1109 1173 11AC; # (슩; 슩; 슩; 슩; 슩; ) HANGUL SYLLABLE SEUNJ +C2AA;C2AA;1109 1173 11AD;C2AA;1109 1173 11AD; # (슪; 슪; 슪; 슪; 슪; ) HANGUL SYLLABLE SEUNH +C2AB;C2AB;1109 1173 11AE;C2AB;1109 1173 11AE; # (슫; 슫; 슫; 슫; 슫; ) HANGUL SYLLABLE SEUD +C2AC;C2AC;1109 1173 11AF;C2AC;1109 1173 11AF; # (슬; 슬; 슬; 슬; 슬; ) HANGUL SYLLABLE SEUL +C2AD;C2AD;1109 1173 11B0;C2AD;1109 1173 11B0; # (슭; 슭; 슭; 슭; 슭; ) HANGUL SYLLABLE SEULG +C2AE;C2AE;1109 1173 11B1;C2AE;1109 1173 11B1; # (슮; 슮; 슮; 슮; 슮; ) HANGUL SYLLABLE SEULM +C2AF;C2AF;1109 1173 11B2;C2AF;1109 1173 11B2; # (슯; 슯; 슯; 슯; 슯; ) HANGUL SYLLABLE SEULB +C2B0;C2B0;1109 1173 11B3;C2B0;1109 1173 11B3; # (슰; 슰; 슰; 슰; 슰; ) HANGUL SYLLABLE SEULS +C2B1;C2B1;1109 1173 11B4;C2B1;1109 1173 11B4; # (슱; 슱; 슱; 슱; 슱; ) HANGUL SYLLABLE SEULT +C2B2;C2B2;1109 1173 11B5;C2B2;1109 1173 11B5; # (슲; 슲; 슲; 슲; 슲; ) HANGUL SYLLABLE SEULP +C2B3;C2B3;1109 1173 11B6;C2B3;1109 1173 11B6; # (슳; 슳; 슳; 슳; 슳; ) HANGUL SYLLABLE SEULH +C2B4;C2B4;1109 1173 11B7;C2B4;1109 1173 11B7; # (슴; 슴; 슴; 슴; 슴; ) HANGUL SYLLABLE SEUM +C2B5;C2B5;1109 1173 11B8;C2B5;1109 1173 11B8; # (습; 습; 습; 습; 습; ) HANGUL SYLLABLE SEUB +C2B6;C2B6;1109 1173 11B9;C2B6;1109 1173 11B9; # (슶; 슶; 슶; 슶; 슶; ) HANGUL SYLLABLE SEUBS +C2B7;C2B7;1109 1173 11BA;C2B7;1109 1173 11BA; # (슷; 슷; 슷; 슷; 슷; ) HANGUL SYLLABLE SEUS +C2B8;C2B8;1109 1173 11BB;C2B8;1109 1173 11BB; # (슸; 슸; 슸; 슸; 슸; ) HANGUL SYLLABLE SEUSS +C2B9;C2B9;1109 1173 11BC;C2B9;1109 1173 11BC; # (승; 승; 승; 승; 승; ) HANGUL SYLLABLE SEUNG +C2BA;C2BA;1109 1173 11BD;C2BA;1109 1173 11BD; # (슺; 슺; 슺; 슺; 슺; ) HANGUL SYLLABLE SEUJ +C2BB;C2BB;1109 1173 11BE;C2BB;1109 1173 11BE; # (슻; 슻; 슻; 슻; 슻; ) HANGUL SYLLABLE SEUC +C2BC;C2BC;1109 1173 11BF;C2BC;1109 1173 11BF; # (슼; 슼; 슼; 슼; 슼; ) HANGUL SYLLABLE SEUK +C2BD;C2BD;1109 1173 11C0;C2BD;1109 1173 11C0; # (슽; 슽; 슽; 슽; 슽; ) HANGUL SYLLABLE SEUT +C2BE;C2BE;1109 1173 11C1;C2BE;1109 1173 11C1; # (슾; 슾; 슾; 슾; 슾; ) HANGUL SYLLABLE SEUP +C2BF;C2BF;1109 1173 11C2;C2BF;1109 1173 11C2; # (슿; 슿; 슿; 슿; 슿; ) HANGUL SYLLABLE SEUH +C2C0;C2C0;1109 1174;C2C0;1109 1174; # (싀; 싀; 싀; 싀; 싀; ) HANGUL SYLLABLE SYI +C2C1;C2C1;1109 1174 11A8;C2C1;1109 1174 11A8; # (싁; 싁; 싁; 싁; 싁; ) HANGUL SYLLABLE SYIG +C2C2;C2C2;1109 1174 11A9;C2C2;1109 1174 11A9; # (싂; 싂; 싂; 싂; 싂; ) HANGUL SYLLABLE SYIGG +C2C3;C2C3;1109 1174 11AA;C2C3;1109 1174 11AA; # (싃; 싃; 싃; 싃; 싃; ) HANGUL SYLLABLE SYIGS +C2C4;C2C4;1109 1174 11AB;C2C4;1109 1174 11AB; # (싄; 싄; 싄; 싄; 싄; ) HANGUL SYLLABLE SYIN +C2C5;C2C5;1109 1174 11AC;C2C5;1109 1174 11AC; # (싅; 싅; 싅; 싅; 싅; ) HANGUL SYLLABLE SYINJ +C2C6;C2C6;1109 1174 11AD;C2C6;1109 1174 11AD; # (싆; 싆; 싆; 싆; 싆; ) HANGUL SYLLABLE SYINH +C2C7;C2C7;1109 1174 11AE;C2C7;1109 1174 11AE; # (싇; 싇; 싇; 싇; 싇; ) HANGUL SYLLABLE SYID +C2C8;C2C8;1109 1174 11AF;C2C8;1109 1174 11AF; # (싈; 싈; 싈; 싈; 싈; ) HANGUL SYLLABLE SYIL +C2C9;C2C9;1109 1174 11B0;C2C9;1109 1174 11B0; # (싉; 싉; 싉; 싉; 싉; ) HANGUL SYLLABLE SYILG +C2CA;C2CA;1109 1174 11B1;C2CA;1109 1174 11B1; # (싊; 싊; 싊; 싊; 싊; ) HANGUL SYLLABLE SYILM +C2CB;C2CB;1109 1174 11B2;C2CB;1109 1174 11B2; # (싋; 싋; 싋; 싋; 싋; ) HANGUL SYLLABLE SYILB +C2CC;C2CC;1109 1174 11B3;C2CC;1109 1174 11B3; # (싌; 싌; 싌; 싌; 싌; ) HANGUL SYLLABLE SYILS +C2CD;C2CD;1109 1174 11B4;C2CD;1109 1174 11B4; # (싍; 싍; 싍; 싍; 싍; ) HANGUL SYLLABLE SYILT +C2CE;C2CE;1109 1174 11B5;C2CE;1109 1174 11B5; # (싎; 싎; 싎; 싎; 싎; ) HANGUL SYLLABLE SYILP +C2CF;C2CF;1109 1174 11B6;C2CF;1109 1174 11B6; # (싏; 싏; 싏; 싏; 싏; ) HANGUL SYLLABLE SYILH +C2D0;C2D0;1109 1174 11B7;C2D0;1109 1174 11B7; # (싐; 싐; 싐; 싐; 싐; ) HANGUL SYLLABLE SYIM +C2D1;C2D1;1109 1174 11B8;C2D1;1109 1174 11B8; # (싑; 싑; 싑; 싑; 싑; ) HANGUL SYLLABLE SYIB +C2D2;C2D2;1109 1174 11B9;C2D2;1109 1174 11B9; # (싒; 싒; 싒; 싒; 싒; ) HANGUL SYLLABLE SYIBS +C2D3;C2D3;1109 1174 11BA;C2D3;1109 1174 11BA; # (싓; 싓; 싓; 싓; 싓; ) HANGUL SYLLABLE SYIS +C2D4;C2D4;1109 1174 11BB;C2D4;1109 1174 11BB; # (싔; 싔; 싔; 싔; 싔; ) HANGUL SYLLABLE SYISS +C2D5;C2D5;1109 1174 11BC;C2D5;1109 1174 11BC; # (싕; 싕; 싕; 싕; 싕; ) HANGUL SYLLABLE SYING +C2D6;C2D6;1109 1174 11BD;C2D6;1109 1174 11BD; # (싖; 싖; 싖; 싖; 싖; ) HANGUL SYLLABLE SYIJ +C2D7;C2D7;1109 1174 11BE;C2D7;1109 1174 11BE; # (싗; 싗; 싗; 싗; 싗; ) HANGUL SYLLABLE SYIC +C2D8;C2D8;1109 1174 11BF;C2D8;1109 1174 11BF; # (싘; 싘; 싘; 싘; 싘; ) HANGUL SYLLABLE SYIK +C2D9;C2D9;1109 1174 11C0;C2D9;1109 1174 11C0; # (싙; 싙; 싙; 싙; 싙; ) HANGUL SYLLABLE SYIT +C2DA;C2DA;1109 1174 11C1;C2DA;1109 1174 11C1; # (싚; 싚; 싚; 싚; 싚; ) HANGUL SYLLABLE SYIP +C2DB;C2DB;1109 1174 11C2;C2DB;1109 1174 11C2; # (싛; 싛; 싛; 싛; 싛; ) HANGUL SYLLABLE SYIH +C2DC;C2DC;1109 1175;C2DC;1109 1175; # (시; 시; 시; 시; 시; ) HANGUL SYLLABLE SI +C2DD;C2DD;1109 1175 11A8;C2DD;1109 1175 11A8; # (식; 식; 식; 식; 식; ) HANGUL SYLLABLE SIG +C2DE;C2DE;1109 1175 11A9;C2DE;1109 1175 11A9; # (싞; 싞; 싞; 싞; 싞; ) HANGUL SYLLABLE SIGG +C2DF;C2DF;1109 1175 11AA;C2DF;1109 1175 11AA; # (싟; 싟; 싟; 싟; 싟; ) HANGUL SYLLABLE SIGS +C2E0;C2E0;1109 1175 11AB;C2E0;1109 1175 11AB; # (신; 신; 신; 신; 신; ) HANGUL SYLLABLE SIN +C2E1;C2E1;1109 1175 11AC;C2E1;1109 1175 11AC; # (싡; 싡; 싡; 싡; 싡; ) HANGUL SYLLABLE SINJ +C2E2;C2E2;1109 1175 11AD;C2E2;1109 1175 11AD; # (싢; 싢; 싢; 싢; 싢; ) HANGUL SYLLABLE SINH +C2E3;C2E3;1109 1175 11AE;C2E3;1109 1175 11AE; # (싣; 싣; 싣; 싣; 싣; ) HANGUL SYLLABLE SID +C2E4;C2E4;1109 1175 11AF;C2E4;1109 1175 11AF; # (실; 실; 실; 실; 실; ) HANGUL SYLLABLE SIL +C2E5;C2E5;1109 1175 11B0;C2E5;1109 1175 11B0; # (싥; 싥; 싥; 싥; 싥; ) HANGUL SYLLABLE SILG +C2E6;C2E6;1109 1175 11B1;C2E6;1109 1175 11B1; # (싦; 싦; 싦; 싦; 싦; ) HANGUL SYLLABLE SILM +C2E7;C2E7;1109 1175 11B2;C2E7;1109 1175 11B2; # (싧; 싧; 싧; 싧; 싧; ) HANGUL SYLLABLE SILB +C2E8;C2E8;1109 1175 11B3;C2E8;1109 1175 11B3; # (싨; 싨; 싨; 싨; 싨; ) HANGUL SYLLABLE SILS +C2E9;C2E9;1109 1175 11B4;C2E9;1109 1175 11B4; # (싩; 싩; 싩; 싩; 싩; ) HANGUL SYLLABLE SILT +C2EA;C2EA;1109 1175 11B5;C2EA;1109 1175 11B5; # (싪; 싪; 싪; 싪; 싪; ) HANGUL SYLLABLE SILP +C2EB;C2EB;1109 1175 11B6;C2EB;1109 1175 11B6; # (싫; 싫; 싫; 싫; 싫; ) HANGUL SYLLABLE SILH +C2EC;C2EC;1109 1175 11B7;C2EC;1109 1175 11B7; # (심; 심; 심; 심; 심; ) HANGUL SYLLABLE SIM +C2ED;C2ED;1109 1175 11B8;C2ED;1109 1175 11B8; # (십; 십; 십; 십; 십; ) HANGUL SYLLABLE SIB +C2EE;C2EE;1109 1175 11B9;C2EE;1109 1175 11B9; # (싮; 싮; 싮; 싮; 싮; ) HANGUL SYLLABLE SIBS +C2EF;C2EF;1109 1175 11BA;C2EF;1109 1175 11BA; # (싯; 싯; 싯; 싯; 싯; ) HANGUL SYLLABLE SIS +C2F0;C2F0;1109 1175 11BB;C2F0;1109 1175 11BB; # (싰; 싰; 싰; 싰; 싰; ) HANGUL SYLLABLE SISS +C2F1;C2F1;1109 1175 11BC;C2F1;1109 1175 11BC; # (싱; 싱; 싱; 싱; 싱; ) HANGUL SYLLABLE SING +C2F2;C2F2;1109 1175 11BD;C2F2;1109 1175 11BD; # (싲; 싲; 싲; 싲; 싲; ) HANGUL SYLLABLE SIJ +C2F3;C2F3;1109 1175 11BE;C2F3;1109 1175 11BE; # (싳; 싳; 싳; 싳; 싳; ) HANGUL SYLLABLE SIC +C2F4;C2F4;1109 1175 11BF;C2F4;1109 1175 11BF; # (싴; 싴; 싴; 싴; 싴; ) HANGUL SYLLABLE SIK +C2F5;C2F5;1109 1175 11C0;C2F5;1109 1175 11C0; # (싵; 싵; 싵; 싵; 싵; ) HANGUL SYLLABLE SIT +C2F6;C2F6;1109 1175 11C1;C2F6;1109 1175 11C1; # (싶; 싶; 싶; 싶; 싶; ) HANGUL SYLLABLE SIP +C2F7;C2F7;1109 1175 11C2;C2F7;1109 1175 11C2; # (싷; 싷; 싷; 싷; 싷; ) HANGUL SYLLABLE SIH +C2F8;C2F8;110A 1161;C2F8;110A 1161; # (싸; 싸; 싸; 싸; 싸; ) HANGUL SYLLABLE SSA +C2F9;C2F9;110A 1161 11A8;C2F9;110A 1161 11A8; # (싹; 싹; 싹; 싹; 싹; ) HANGUL SYLLABLE SSAG +C2FA;C2FA;110A 1161 11A9;C2FA;110A 1161 11A9; # (싺; 싺; 싺; 싺; 싺; ) HANGUL SYLLABLE SSAGG +C2FB;C2FB;110A 1161 11AA;C2FB;110A 1161 11AA; # (싻; 싻; 싻; 싻; 싻; ) HANGUL SYLLABLE SSAGS +C2FC;C2FC;110A 1161 11AB;C2FC;110A 1161 11AB; # (싼; 싼; 싼; 싼; 싼; ) HANGUL SYLLABLE SSAN +C2FD;C2FD;110A 1161 11AC;C2FD;110A 1161 11AC; # (싽; 싽; 싽; 싽; 싽; ) HANGUL SYLLABLE SSANJ +C2FE;C2FE;110A 1161 11AD;C2FE;110A 1161 11AD; # (싾; 싾; 싾; 싾; 싾; ) HANGUL SYLLABLE SSANH +C2FF;C2FF;110A 1161 11AE;C2FF;110A 1161 11AE; # (싿; 싿; 싿; 싿; 싿; ) HANGUL SYLLABLE SSAD +C300;C300;110A 1161 11AF;C300;110A 1161 11AF; # (쌀; 쌀; 쌀; 쌀; 쌀; ) HANGUL SYLLABLE SSAL +C301;C301;110A 1161 11B0;C301;110A 1161 11B0; # (쌁; 쌁; 쌁; 쌁; 쌁; ) HANGUL SYLLABLE SSALG +C302;C302;110A 1161 11B1;C302;110A 1161 11B1; # (쌂; 쌂; 쌂; 쌂; 쌂; ) HANGUL SYLLABLE SSALM +C303;C303;110A 1161 11B2;C303;110A 1161 11B2; # (쌃; 쌃; 쌃; 쌃; 쌃; ) HANGUL SYLLABLE SSALB +C304;C304;110A 1161 11B3;C304;110A 1161 11B3; # (쌄; 쌄; 쌄; 쌄; 쌄; ) HANGUL SYLLABLE SSALS +C305;C305;110A 1161 11B4;C305;110A 1161 11B4; # (쌅; 쌅; 쌅; 쌅; 쌅; ) HANGUL SYLLABLE SSALT +C306;C306;110A 1161 11B5;C306;110A 1161 11B5; # (쌆; 쌆; 쌆; 쌆; 쌆; ) HANGUL SYLLABLE SSALP +C307;C307;110A 1161 11B6;C307;110A 1161 11B6; # (쌇; 쌇; 쌇; 쌇; 쌇; ) HANGUL SYLLABLE SSALH +C308;C308;110A 1161 11B7;C308;110A 1161 11B7; # (쌈; 쌈; 쌈; 쌈; 쌈; ) HANGUL SYLLABLE SSAM +C309;C309;110A 1161 11B8;C309;110A 1161 11B8; # (쌉; 쌉; 쌉; 쌉; 쌉; ) HANGUL SYLLABLE SSAB +C30A;C30A;110A 1161 11B9;C30A;110A 1161 11B9; # (쌊; 쌊; 쌊; 쌊; 쌊; ) HANGUL SYLLABLE SSABS +C30B;C30B;110A 1161 11BA;C30B;110A 1161 11BA; # (쌋; 쌋; 쌋; 쌋; 쌋; ) HANGUL SYLLABLE SSAS +C30C;C30C;110A 1161 11BB;C30C;110A 1161 11BB; # (쌌; 쌌; 쌌; 쌌; 쌌; ) HANGUL SYLLABLE SSASS +C30D;C30D;110A 1161 11BC;C30D;110A 1161 11BC; # (쌍; 쌍; 쌍; 쌍; 쌍; ) HANGUL SYLLABLE SSANG +C30E;C30E;110A 1161 11BD;C30E;110A 1161 11BD; # (쌎; 쌎; 쌎; 쌎; 쌎; ) HANGUL SYLLABLE SSAJ +C30F;C30F;110A 1161 11BE;C30F;110A 1161 11BE; # (쌏; 쌏; 쌏; 쌏; 쌏; ) HANGUL SYLLABLE SSAC +C310;C310;110A 1161 11BF;C310;110A 1161 11BF; # (쌐; 쌐; 쌐; 쌐; 쌐; ) HANGUL SYLLABLE SSAK +C311;C311;110A 1161 11C0;C311;110A 1161 11C0; # (쌑; 쌑; 쌑; 쌑; 쌑; ) HANGUL SYLLABLE SSAT +C312;C312;110A 1161 11C1;C312;110A 1161 11C1; # (쌒; 쌒; 쌒; 쌒; 쌒; ) HANGUL SYLLABLE SSAP +C313;C313;110A 1161 11C2;C313;110A 1161 11C2; # (쌓; 쌓; 쌓; 쌓; 쌓; ) HANGUL SYLLABLE SSAH +C314;C314;110A 1162;C314;110A 1162; # (쌔; 쌔; 쌔; 쌔; 쌔; ) HANGUL SYLLABLE SSAE +C315;C315;110A 1162 11A8;C315;110A 1162 11A8; # (쌕; 쌕; 쌕; 쌕; 쌕; ) HANGUL SYLLABLE SSAEG +C316;C316;110A 1162 11A9;C316;110A 1162 11A9; # (쌖; 쌖; 쌖; 쌖; 쌖; ) HANGUL SYLLABLE SSAEGG +C317;C317;110A 1162 11AA;C317;110A 1162 11AA; # (쌗; 쌗; 쌗; 쌗; 쌗; ) HANGUL SYLLABLE SSAEGS +C318;C318;110A 1162 11AB;C318;110A 1162 11AB; # (쌘; 쌘; 쌘; 쌘; 쌘; ) HANGUL SYLLABLE SSAEN +C319;C319;110A 1162 11AC;C319;110A 1162 11AC; # (쌙; 쌙; 쌙; 쌙; 쌙; ) HANGUL SYLLABLE SSAENJ +C31A;C31A;110A 1162 11AD;C31A;110A 1162 11AD; # (쌚; 쌚; 쌚; 쌚; 쌚; ) HANGUL SYLLABLE SSAENH +C31B;C31B;110A 1162 11AE;C31B;110A 1162 11AE; # (쌛; 쌛; 쌛; 쌛; 쌛; ) HANGUL SYLLABLE SSAED +C31C;C31C;110A 1162 11AF;C31C;110A 1162 11AF; # (쌜; 쌜; 쌜; 쌜; 쌜; ) HANGUL SYLLABLE SSAEL +C31D;C31D;110A 1162 11B0;C31D;110A 1162 11B0; # (쌝; 쌝; 쌝; 쌝; 쌝; ) HANGUL SYLLABLE SSAELG +C31E;C31E;110A 1162 11B1;C31E;110A 1162 11B1; # (쌞; 쌞; 쌞; 쌞; 쌞; ) HANGUL SYLLABLE SSAELM +C31F;C31F;110A 1162 11B2;C31F;110A 1162 11B2; # (쌟; 쌟; 쌟; 쌟; 쌟; ) HANGUL SYLLABLE SSAELB +C320;C320;110A 1162 11B3;C320;110A 1162 11B3; # (쌠; 쌠; 쌠; 쌠; 쌠; ) HANGUL SYLLABLE SSAELS +C321;C321;110A 1162 11B4;C321;110A 1162 11B4; # (쌡; 쌡; 쌡; 쌡; 쌡; ) HANGUL SYLLABLE SSAELT +C322;C322;110A 1162 11B5;C322;110A 1162 11B5; # (쌢; 쌢; 쌢; 쌢; 쌢; ) HANGUL SYLLABLE SSAELP +C323;C323;110A 1162 11B6;C323;110A 1162 11B6; # (쌣; 쌣; 쌣; 쌣; 쌣; ) HANGUL SYLLABLE SSAELH +C324;C324;110A 1162 11B7;C324;110A 1162 11B7; # (쌤; 쌤; 쌤; 쌤; 쌤; ) HANGUL SYLLABLE SSAEM +C325;C325;110A 1162 11B8;C325;110A 1162 11B8; # (쌥; 쌥; 쌥; 쌥; 쌥; ) HANGUL SYLLABLE SSAEB +C326;C326;110A 1162 11B9;C326;110A 1162 11B9; # (쌦; 쌦; 쌦; 쌦; 쌦; ) HANGUL SYLLABLE SSAEBS +C327;C327;110A 1162 11BA;C327;110A 1162 11BA; # (쌧; 쌧; 쌧; 쌧; 쌧; ) HANGUL SYLLABLE SSAES +C328;C328;110A 1162 11BB;C328;110A 1162 11BB; # (쌨; 쌨; 쌨; 쌨; 쌨; ) HANGUL SYLLABLE SSAESS +C329;C329;110A 1162 11BC;C329;110A 1162 11BC; # (쌩; 쌩; 쌩; 쌩; 쌩; ) HANGUL SYLLABLE SSAENG +C32A;C32A;110A 1162 11BD;C32A;110A 1162 11BD; # (쌪; 쌪; 쌪; 쌪; 쌪; ) HANGUL SYLLABLE SSAEJ +C32B;C32B;110A 1162 11BE;C32B;110A 1162 11BE; # (쌫; 쌫; 쌫; 쌫; 쌫; ) HANGUL SYLLABLE SSAEC +C32C;C32C;110A 1162 11BF;C32C;110A 1162 11BF; # (쌬; 쌬; 쌬; 쌬; 쌬; ) HANGUL SYLLABLE SSAEK +C32D;C32D;110A 1162 11C0;C32D;110A 1162 11C0; # (쌭; 쌭; 쌭; 쌭; 쌭; ) HANGUL SYLLABLE SSAET +C32E;C32E;110A 1162 11C1;C32E;110A 1162 11C1; # (쌮; 쌮; 쌮; 쌮; 쌮; ) HANGUL SYLLABLE SSAEP +C32F;C32F;110A 1162 11C2;C32F;110A 1162 11C2; # (쌯; 쌯; 쌯; 쌯; 쌯; ) HANGUL SYLLABLE SSAEH +C330;C330;110A 1163;C330;110A 1163; # (쌰; 쌰; 쌰; 쌰; 쌰; ) HANGUL SYLLABLE SSYA +C331;C331;110A 1163 11A8;C331;110A 1163 11A8; # (쌱; 쌱; 쌱; 쌱; 쌱; ) HANGUL SYLLABLE SSYAG +C332;C332;110A 1163 11A9;C332;110A 1163 11A9; # (쌲; 쌲; 쌲; 쌲; 쌲; ) HANGUL SYLLABLE SSYAGG +C333;C333;110A 1163 11AA;C333;110A 1163 11AA; # (쌳; 쌳; 쌳; 쌳; 쌳; ) HANGUL SYLLABLE SSYAGS +C334;C334;110A 1163 11AB;C334;110A 1163 11AB; # (쌴; 쌴; 쌴; 쌴; 쌴; ) HANGUL SYLLABLE SSYAN +C335;C335;110A 1163 11AC;C335;110A 1163 11AC; # (쌵; 쌵; 쌵; 쌵; 쌵; ) HANGUL SYLLABLE SSYANJ +C336;C336;110A 1163 11AD;C336;110A 1163 11AD; # (쌶; 쌶; 쌶; 쌶; 쌶; ) HANGUL SYLLABLE SSYANH +C337;C337;110A 1163 11AE;C337;110A 1163 11AE; # (쌷; 쌷; 쌷; 쌷; 쌷; ) HANGUL SYLLABLE SSYAD +C338;C338;110A 1163 11AF;C338;110A 1163 11AF; # (쌸; 쌸; 쌸; 쌸; 쌸; ) HANGUL SYLLABLE SSYAL +C339;C339;110A 1163 11B0;C339;110A 1163 11B0; # (쌹; 쌹; 쌹; 쌹; 쌹; ) HANGUL SYLLABLE SSYALG +C33A;C33A;110A 1163 11B1;C33A;110A 1163 11B1; # (쌺; 쌺; 쌺; 쌺; 쌺; ) HANGUL SYLLABLE SSYALM +C33B;C33B;110A 1163 11B2;C33B;110A 1163 11B2; # (쌻; 쌻; 쌻; 쌻; 쌻; ) HANGUL SYLLABLE SSYALB +C33C;C33C;110A 1163 11B3;C33C;110A 1163 11B3; # (쌼; 쌼; 쌼; 쌼; 쌼; ) HANGUL SYLLABLE SSYALS +C33D;C33D;110A 1163 11B4;C33D;110A 1163 11B4; # (쌽; 쌽; 쌽; 쌽; 쌽; ) HANGUL SYLLABLE SSYALT +C33E;C33E;110A 1163 11B5;C33E;110A 1163 11B5; # (쌾; 쌾; 쌾; 쌾; 쌾; ) HANGUL SYLLABLE SSYALP +C33F;C33F;110A 1163 11B6;C33F;110A 1163 11B6; # (쌿; 쌿; 쌿; 쌿; 쌿; ) HANGUL SYLLABLE SSYALH +C340;C340;110A 1163 11B7;C340;110A 1163 11B7; # (썀; 썀; 썀; 썀; 썀; ) HANGUL SYLLABLE SSYAM +C341;C341;110A 1163 11B8;C341;110A 1163 11B8; # (썁; 썁; 썁; 썁; 썁; ) HANGUL SYLLABLE SSYAB +C342;C342;110A 1163 11B9;C342;110A 1163 11B9; # (썂; 썂; 썂; 썂; 썂; ) HANGUL SYLLABLE SSYABS +C343;C343;110A 1163 11BA;C343;110A 1163 11BA; # (썃; 썃; 썃; 썃; 썃; ) HANGUL SYLLABLE SSYAS +C344;C344;110A 1163 11BB;C344;110A 1163 11BB; # (썄; 썄; 썄; 썄; 썄; ) HANGUL SYLLABLE SSYASS +C345;C345;110A 1163 11BC;C345;110A 1163 11BC; # (썅; 썅; 썅; 썅; 썅; ) HANGUL SYLLABLE SSYANG +C346;C346;110A 1163 11BD;C346;110A 1163 11BD; # (썆; 썆; 썆; 썆; 썆; ) HANGUL SYLLABLE SSYAJ +C347;C347;110A 1163 11BE;C347;110A 1163 11BE; # (썇; 썇; 썇; 썇; 썇; ) HANGUL SYLLABLE SSYAC +C348;C348;110A 1163 11BF;C348;110A 1163 11BF; # (썈; 썈; 썈; 썈; 썈; ) HANGUL SYLLABLE SSYAK +C349;C349;110A 1163 11C0;C349;110A 1163 11C0; # (썉; 썉; 썉; 썉; 썉; ) HANGUL SYLLABLE SSYAT +C34A;C34A;110A 1163 11C1;C34A;110A 1163 11C1; # (썊; 썊; 썊; 썊; 썊; ) HANGUL SYLLABLE SSYAP +C34B;C34B;110A 1163 11C2;C34B;110A 1163 11C2; # (썋; 썋; 썋; 썋; 썋; ) HANGUL SYLLABLE SSYAH +C34C;C34C;110A 1164;C34C;110A 1164; # (썌; 썌; 썌; 썌; 썌; ) HANGUL SYLLABLE SSYAE +C34D;C34D;110A 1164 11A8;C34D;110A 1164 11A8; # (썍; 썍; 썍; 썍; 썍; ) HANGUL SYLLABLE SSYAEG +C34E;C34E;110A 1164 11A9;C34E;110A 1164 11A9; # (썎; 썎; 썎; 썎; 썎; ) HANGUL SYLLABLE SSYAEGG +C34F;C34F;110A 1164 11AA;C34F;110A 1164 11AA; # (썏; 썏; 썏; 썏; 썏; ) HANGUL SYLLABLE SSYAEGS +C350;C350;110A 1164 11AB;C350;110A 1164 11AB; # (썐; 썐; 썐; 썐; 썐; ) HANGUL SYLLABLE SSYAEN +C351;C351;110A 1164 11AC;C351;110A 1164 11AC; # (썑; 썑; 썑; 썑; 썑; ) HANGUL SYLLABLE SSYAENJ +C352;C352;110A 1164 11AD;C352;110A 1164 11AD; # (썒; 썒; 썒; 썒; 썒; ) HANGUL SYLLABLE SSYAENH +C353;C353;110A 1164 11AE;C353;110A 1164 11AE; # (썓; 썓; 썓; 썓; 썓; ) HANGUL SYLLABLE SSYAED +C354;C354;110A 1164 11AF;C354;110A 1164 11AF; # (썔; 썔; 썔; 썔; 썔; ) HANGUL SYLLABLE SSYAEL +C355;C355;110A 1164 11B0;C355;110A 1164 11B0; # (썕; 썕; 썕; 썕; 썕; ) HANGUL SYLLABLE SSYAELG +C356;C356;110A 1164 11B1;C356;110A 1164 11B1; # (썖; 썖; 썖; 썖; 썖; ) HANGUL SYLLABLE SSYAELM +C357;C357;110A 1164 11B2;C357;110A 1164 11B2; # (썗; 썗; 썗; 썗; 썗; ) HANGUL SYLLABLE SSYAELB +C358;C358;110A 1164 11B3;C358;110A 1164 11B3; # (썘; 썘; 썘; 썘; 썘; ) HANGUL SYLLABLE SSYAELS +C359;C359;110A 1164 11B4;C359;110A 1164 11B4; # (썙; 썙; 썙; 썙; 썙; ) HANGUL SYLLABLE SSYAELT +C35A;C35A;110A 1164 11B5;C35A;110A 1164 11B5; # (썚; 썚; 썚; 썚; 썚; ) HANGUL SYLLABLE SSYAELP +C35B;C35B;110A 1164 11B6;C35B;110A 1164 11B6; # (썛; 썛; 썛; 썛; 썛; ) HANGUL SYLLABLE SSYAELH +C35C;C35C;110A 1164 11B7;C35C;110A 1164 11B7; # (썜; 썜; 썜; 썜; 썜; ) HANGUL SYLLABLE SSYAEM +C35D;C35D;110A 1164 11B8;C35D;110A 1164 11B8; # (썝; 썝; 썝; 썝; 썝; ) HANGUL SYLLABLE SSYAEB +C35E;C35E;110A 1164 11B9;C35E;110A 1164 11B9; # (썞; 썞; 썞; 썞; 썞; ) HANGUL SYLLABLE SSYAEBS +C35F;C35F;110A 1164 11BA;C35F;110A 1164 11BA; # (썟; 썟; 썟; 썟; 썟; ) HANGUL SYLLABLE SSYAES +C360;C360;110A 1164 11BB;C360;110A 1164 11BB; # (썠; 썠; 썠; 썠; 썠; ) HANGUL SYLLABLE SSYAESS +C361;C361;110A 1164 11BC;C361;110A 1164 11BC; # (썡; 썡; 썡; 썡; 썡; ) HANGUL SYLLABLE SSYAENG +C362;C362;110A 1164 11BD;C362;110A 1164 11BD; # (썢; 썢; 썢; 썢; 썢; ) HANGUL SYLLABLE SSYAEJ +C363;C363;110A 1164 11BE;C363;110A 1164 11BE; # (썣; 썣; 썣; 썣; 썣; ) HANGUL SYLLABLE SSYAEC +C364;C364;110A 1164 11BF;C364;110A 1164 11BF; # (썤; 썤; 썤; 썤; 썤; ) HANGUL SYLLABLE SSYAEK +C365;C365;110A 1164 11C0;C365;110A 1164 11C0; # (썥; 썥; 썥; 썥; 썥; ) HANGUL SYLLABLE SSYAET +C366;C366;110A 1164 11C1;C366;110A 1164 11C1; # (썦; 썦; 썦; 썦; 썦; ) HANGUL SYLLABLE SSYAEP +C367;C367;110A 1164 11C2;C367;110A 1164 11C2; # (썧; 썧; 썧; 썧; 썧; ) HANGUL SYLLABLE SSYAEH +C368;C368;110A 1165;C368;110A 1165; # (써; 써; 써; 써; 써; ) HANGUL SYLLABLE SSEO +C369;C369;110A 1165 11A8;C369;110A 1165 11A8; # (썩; 썩; 썩; 썩; 썩; ) HANGUL SYLLABLE SSEOG +C36A;C36A;110A 1165 11A9;C36A;110A 1165 11A9; # (썪; 썪; 썪; 썪; 썪; ) HANGUL SYLLABLE SSEOGG +C36B;C36B;110A 1165 11AA;C36B;110A 1165 11AA; # (썫; 썫; 썫; 썫; 썫; ) HANGUL SYLLABLE SSEOGS +C36C;C36C;110A 1165 11AB;C36C;110A 1165 11AB; # (썬; 썬; 썬; 썬; 썬; ) HANGUL SYLLABLE SSEON +C36D;C36D;110A 1165 11AC;C36D;110A 1165 11AC; # (썭; 썭; 썭; 썭; 썭; ) HANGUL SYLLABLE SSEONJ +C36E;C36E;110A 1165 11AD;C36E;110A 1165 11AD; # (썮; 썮; 썮; 썮; 썮; ) HANGUL SYLLABLE SSEONH +C36F;C36F;110A 1165 11AE;C36F;110A 1165 11AE; # (썯; 썯; 썯; 썯; 썯; ) HANGUL SYLLABLE SSEOD +C370;C370;110A 1165 11AF;C370;110A 1165 11AF; # (썰; 썰; 썰; 썰; 썰; ) HANGUL SYLLABLE SSEOL +C371;C371;110A 1165 11B0;C371;110A 1165 11B0; # (썱; 썱; 썱; 썱; 썱; ) HANGUL SYLLABLE SSEOLG +C372;C372;110A 1165 11B1;C372;110A 1165 11B1; # (썲; 썲; 썲; 썲; 썲; ) HANGUL SYLLABLE SSEOLM +C373;C373;110A 1165 11B2;C373;110A 1165 11B2; # (썳; 썳; 썳; 썳; 썳; ) HANGUL SYLLABLE SSEOLB +C374;C374;110A 1165 11B3;C374;110A 1165 11B3; # (썴; 썴; 썴; 썴; 썴; ) HANGUL SYLLABLE SSEOLS +C375;C375;110A 1165 11B4;C375;110A 1165 11B4; # (썵; 썵; 썵; 썵; 썵; ) HANGUL SYLLABLE SSEOLT +C376;C376;110A 1165 11B5;C376;110A 1165 11B5; # (썶; 썶; 썶; 썶; 썶; ) HANGUL SYLLABLE SSEOLP +C377;C377;110A 1165 11B6;C377;110A 1165 11B6; # (썷; 썷; 썷; 썷; 썷; ) HANGUL SYLLABLE SSEOLH +C378;C378;110A 1165 11B7;C378;110A 1165 11B7; # (썸; 썸; 썸; 썸; 썸; ) HANGUL SYLLABLE SSEOM +C379;C379;110A 1165 11B8;C379;110A 1165 11B8; # (썹; 썹; 썹; 썹; 썹; ) HANGUL SYLLABLE SSEOB +C37A;C37A;110A 1165 11B9;C37A;110A 1165 11B9; # (썺; 썺; 썺; 썺; 썺; ) HANGUL SYLLABLE SSEOBS +C37B;C37B;110A 1165 11BA;C37B;110A 1165 11BA; # (썻; 썻; 썻; 썻; 썻; ) HANGUL SYLLABLE SSEOS +C37C;C37C;110A 1165 11BB;C37C;110A 1165 11BB; # (썼; 썼; 썼; 썼; 썼; ) HANGUL SYLLABLE SSEOSS +C37D;C37D;110A 1165 11BC;C37D;110A 1165 11BC; # (썽; 썽; 썽; 썽; 썽; ) HANGUL SYLLABLE SSEONG +C37E;C37E;110A 1165 11BD;C37E;110A 1165 11BD; # (썾; 썾; 썾; 썾; 썾; ) HANGUL SYLLABLE SSEOJ +C37F;C37F;110A 1165 11BE;C37F;110A 1165 11BE; # (썿; 썿; 썿; 썿; 썿; ) HANGUL SYLLABLE SSEOC +C380;C380;110A 1165 11BF;C380;110A 1165 11BF; # (쎀; 쎀; 쎀; 쎀; 쎀; ) HANGUL SYLLABLE SSEOK +C381;C381;110A 1165 11C0;C381;110A 1165 11C0; # (쎁; 쎁; 쎁; 쎁; 쎁; ) HANGUL SYLLABLE SSEOT +C382;C382;110A 1165 11C1;C382;110A 1165 11C1; # (쎂; 쎂; 쎂; 쎂; 쎂; ) HANGUL SYLLABLE SSEOP +C383;C383;110A 1165 11C2;C383;110A 1165 11C2; # (쎃; 쎃; 쎃; 쎃; 쎃; ) HANGUL SYLLABLE SSEOH +C384;C384;110A 1166;C384;110A 1166; # (쎄; 쎄; 쎄; 쎄; 쎄; ) HANGUL SYLLABLE SSE +C385;C385;110A 1166 11A8;C385;110A 1166 11A8; # (쎅; 쎅; 쎅; 쎅; 쎅; ) HANGUL SYLLABLE SSEG +C386;C386;110A 1166 11A9;C386;110A 1166 11A9; # (쎆; 쎆; 쎆; 쎆; 쎆; ) HANGUL SYLLABLE SSEGG +C387;C387;110A 1166 11AA;C387;110A 1166 11AA; # (쎇; 쎇; 쎇; 쎇; 쎇; ) HANGUL SYLLABLE SSEGS +C388;C388;110A 1166 11AB;C388;110A 1166 11AB; # (쎈; 쎈; 쎈; 쎈; 쎈; ) HANGUL SYLLABLE SSEN +C389;C389;110A 1166 11AC;C389;110A 1166 11AC; # (쎉; 쎉; 쎉; 쎉; 쎉; ) HANGUL SYLLABLE SSENJ +C38A;C38A;110A 1166 11AD;C38A;110A 1166 11AD; # (쎊; 쎊; 쎊; 쎊; 쎊; ) HANGUL SYLLABLE SSENH +C38B;C38B;110A 1166 11AE;C38B;110A 1166 11AE; # (쎋; 쎋; 쎋; 쎋; 쎋; ) HANGUL SYLLABLE SSED +C38C;C38C;110A 1166 11AF;C38C;110A 1166 11AF; # (쎌; 쎌; 쎌; 쎌; 쎌; ) HANGUL SYLLABLE SSEL +C38D;C38D;110A 1166 11B0;C38D;110A 1166 11B0; # (쎍; 쎍; 쎍; 쎍; 쎍; ) HANGUL SYLLABLE SSELG +C38E;C38E;110A 1166 11B1;C38E;110A 1166 11B1; # (쎎; 쎎; 쎎; 쎎; 쎎; ) HANGUL SYLLABLE SSELM +C38F;C38F;110A 1166 11B2;C38F;110A 1166 11B2; # (쎏; 쎏; 쎏; 쎏; 쎏; ) HANGUL SYLLABLE SSELB +C390;C390;110A 1166 11B3;C390;110A 1166 11B3; # (쎐; 쎐; 쎐; 쎐; 쎐; ) HANGUL SYLLABLE SSELS +C391;C391;110A 1166 11B4;C391;110A 1166 11B4; # (쎑; 쎑; 쎑; 쎑; 쎑; ) HANGUL SYLLABLE SSELT +C392;C392;110A 1166 11B5;C392;110A 1166 11B5; # (쎒; 쎒; 쎒; 쎒; 쎒; ) HANGUL SYLLABLE SSELP +C393;C393;110A 1166 11B6;C393;110A 1166 11B6; # (쎓; 쎓; 쎓; 쎓; 쎓; ) HANGUL SYLLABLE SSELH +C394;C394;110A 1166 11B7;C394;110A 1166 11B7; # (쎔; 쎔; 쎔; 쎔; 쎔; ) HANGUL SYLLABLE SSEM +C395;C395;110A 1166 11B8;C395;110A 1166 11B8; # (쎕; 쎕; 쎕; 쎕; 쎕; ) HANGUL SYLLABLE SSEB +C396;C396;110A 1166 11B9;C396;110A 1166 11B9; # (쎖; 쎖; 쎖; 쎖; 쎖; ) HANGUL SYLLABLE SSEBS +C397;C397;110A 1166 11BA;C397;110A 1166 11BA; # (쎗; 쎗; 쎗; 쎗; 쎗; ) HANGUL SYLLABLE SSES +C398;C398;110A 1166 11BB;C398;110A 1166 11BB; # (쎘; 쎘; 쎘; 쎘; 쎘; ) HANGUL SYLLABLE SSESS +C399;C399;110A 1166 11BC;C399;110A 1166 11BC; # (쎙; 쎙; 쎙; 쎙; 쎙; ) HANGUL SYLLABLE SSENG +C39A;C39A;110A 1166 11BD;C39A;110A 1166 11BD; # (쎚; 쎚; 쎚; 쎚; 쎚; ) HANGUL SYLLABLE SSEJ +C39B;C39B;110A 1166 11BE;C39B;110A 1166 11BE; # (쎛; 쎛; 쎛; 쎛; 쎛; ) HANGUL SYLLABLE SSEC +C39C;C39C;110A 1166 11BF;C39C;110A 1166 11BF; # (쎜; 쎜; 쎜; 쎜; 쎜; ) HANGUL SYLLABLE SSEK +C39D;C39D;110A 1166 11C0;C39D;110A 1166 11C0; # (쎝; 쎝; 쎝; 쎝; 쎝; ) HANGUL SYLLABLE SSET +C39E;C39E;110A 1166 11C1;C39E;110A 1166 11C1; # (쎞; 쎞; 쎞; 쎞; 쎞; ) HANGUL SYLLABLE SSEP +C39F;C39F;110A 1166 11C2;C39F;110A 1166 11C2; # (쎟; 쎟; 쎟; 쎟; 쎟; ) HANGUL SYLLABLE SSEH +C3A0;C3A0;110A 1167;C3A0;110A 1167; # (쎠; 쎠; 쎠; 쎠; 쎠; ) HANGUL SYLLABLE SSYEO +C3A1;C3A1;110A 1167 11A8;C3A1;110A 1167 11A8; # (쎡; 쎡; 쎡; 쎡; 쎡; ) HANGUL SYLLABLE SSYEOG +C3A2;C3A2;110A 1167 11A9;C3A2;110A 1167 11A9; # (쎢; 쎢; 쎢; 쎢; 쎢; ) HANGUL SYLLABLE SSYEOGG +C3A3;C3A3;110A 1167 11AA;C3A3;110A 1167 11AA; # (쎣; 쎣; 쎣; 쎣; 쎣; ) HANGUL SYLLABLE SSYEOGS +C3A4;C3A4;110A 1167 11AB;C3A4;110A 1167 11AB; # (쎤; 쎤; 쎤; 쎤; 쎤; ) HANGUL SYLLABLE SSYEON +C3A5;C3A5;110A 1167 11AC;C3A5;110A 1167 11AC; # (쎥; 쎥; 쎥; 쎥; 쎥; ) HANGUL SYLLABLE SSYEONJ +C3A6;C3A6;110A 1167 11AD;C3A6;110A 1167 11AD; # (쎦; 쎦; 쎦; 쎦; 쎦; ) HANGUL SYLLABLE SSYEONH +C3A7;C3A7;110A 1167 11AE;C3A7;110A 1167 11AE; # (쎧; 쎧; 쎧; 쎧; 쎧; ) HANGUL SYLLABLE SSYEOD +C3A8;C3A8;110A 1167 11AF;C3A8;110A 1167 11AF; # (쎨; 쎨; 쎨; 쎨; 쎨; ) HANGUL SYLLABLE SSYEOL +C3A9;C3A9;110A 1167 11B0;C3A9;110A 1167 11B0; # (쎩; 쎩; 쎩; 쎩; 쎩; ) HANGUL SYLLABLE SSYEOLG +C3AA;C3AA;110A 1167 11B1;C3AA;110A 1167 11B1; # (쎪; 쎪; 쎪; 쎪; 쎪; ) HANGUL SYLLABLE SSYEOLM +C3AB;C3AB;110A 1167 11B2;C3AB;110A 1167 11B2; # (쎫; 쎫; 쎫; 쎫; 쎫; ) HANGUL SYLLABLE SSYEOLB +C3AC;C3AC;110A 1167 11B3;C3AC;110A 1167 11B3; # (쎬; 쎬; 쎬; 쎬; 쎬; ) HANGUL SYLLABLE SSYEOLS +C3AD;C3AD;110A 1167 11B4;C3AD;110A 1167 11B4; # (쎭; 쎭; 쎭; 쎭; 쎭; ) HANGUL SYLLABLE SSYEOLT +C3AE;C3AE;110A 1167 11B5;C3AE;110A 1167 11B5; # (쎮; 쎮; 쎮; 쎮; 쎮; ) HANGUL SYLLABLE SSYEOLP +C3AF;C3AF;110A 1167 11B6;C3AF;110A 1167 11B6; # (쎯; 쎯; 쎯; 쎯; 쎯; ) HANGUL SYLLABLE SSYEOLH +C3B0;C3B0;110A 1167 11B7;C3B0;110A 1167 11B7; # (쎰; 쎰; 쎰; 쎰; 쎰; ) HANGUL SYLLABLE SSYEOM +C3B1;C3B1;110A 1167 11B8;C3B1;110A 1167 11B8; # (쎱; 쎱; 쎱; 쎱; 쎱; ) HANGUL SYLLABLE SSYEOB +C3B2;C3B2;110A 1167 11B9;C3B2;110A 1167 11B9; # (쎲; 쎲; 쎲; 쎲; 쎲; ) HANGUL SYLLABLE SSYEOBS +C3B3;C3B3;110A 1167 11BA;C3B3;110A 1167 11BA; # (쎳; 쎳; 쎳; 쎳; 쎳; ) HANGUL SYLLABLE SSYEOS +C3B4;C3B4;110A 1167 11BB;C3B4;110A 1167 11BB; # (쎴; 쎴; 쎴; 쎴; 쎴; ) HANGUL SYLLABLE SSYEOSS +C3B5;C3B5;110A 1167 11BC;C3B5;110A 1167 11BC; # (쎵; 쎵; 쎵; 쎵; 쎵; ) HANGUL SYLLABLE SSYEONG +C3B6;C3B6;110A 1167 11BD;C3B6;110A 1167 11BD; # (쎶; 쎶; 쎶; 쎶; 쎶; ) HANGUL SYLLABLE SSYEOJ +C3B7;C3B7;110A 1167 11BE;C3B7;110A 1167 11BE; # (쎷; 쎷; 쎷; 쎷; 쎷; ) HANGUL SYLLABLE SSYEOC +C3B8;C3B8;110A 1167 11BF;C3B8;110A 1167 11BF; # (쎸; 쎸; 쎸; 쎸; 쎸; ) HANGUL SYLLABLE SSYEOK +C3B9;C3B9;110A 1167 11C0;C3B9;110A 1167 11C0; # (쎹; 쎹; 쎹; 쎹; 쎹; ) HANGUL SYLLABLE SSYEOT +C3BA;C3BA;110A 1167 11C1;C3BA;110A 1167 11C1; # (쎺; 쎺; 쎺; 쎺; 쎺; ) HANGUL SYLLABLE SSYEOP +C3BB;C3BB;110A 1167 11C2;C3BB;110A 1167 11C2; # (쎻; 쎻; 쎻; 쎻; 쎻; ) HANGUL SYLLABLE SSYEOH +C3BC;C3BC;110A 1168;C3BC;110A 1168; # (쎼; 쎼; 쎼; 쎼; 쎼; ) HANGUL SYLLABLE SSYE +C3BD;C3BD;110A 1168 11A8;C3BD;110A 1168 11A8; # (쎽; 쎽; 쎽; 쎽; 쎽; ) HANGUL SYLLABLE SSYEG +C3BE;C3BE;110A 1168 11A9;C3BE;110A 1168 11A9; # (쎾; 쎾; 쎾; 쎾; 쎾; ) HANGUL SYLLABLE SSYEGG +C3BF;C3BF;110A 1168 11AA;C3BF;110A 1168 11AA; # (쎿; 쎿; 쎿; 쎿; 쎿; ) HANGUL SYLLABLE SSYEGS +C3C0;C3C0;110A 1168 11AB;C3C0;110A 1168 11AB; # (쏀; 쏀; 쏀; 쏀; 쏀; ) HANGUL SYLLABLE SSYEN +C3C1;C3C1;110A 1168 11AC;C3C1;110A 1168 11AC; # (쏁; 쏁; 쏁; 쏁; 쏁; ) HANGUL SYLLABLE SSYENJ +C3C2;C3C2;110A 1168 11AD;C3C2;110A 1168 11AD; # (쏂; 쏂; 쏂; 쏂; 쏂; ) HANGUL SYLLABLE SSYENH +C3C3;C3C3;110A 1168 11AE;C3C3;110A 1168 11AE; # (쏃; 쏃; 쏃; 쏃; 쏃; ) HANGUL SYLLABLE SSYED +C3C4;C3C4;110A 1168 11AF;C3C4;110A 1168 11AF; # (쏄; 쏄; 쏄; 쏄; 쏄; ) HANGUL SYLLABLE SSYEL +C3C5;C3C5;110A 1168 11B0;C3C5;110A 1168 11B0; # (쏅; 쏅; 쏅; 쏅; 쏅; ) HANGUL SYLLABLE SSYELG +C3C6;C3C6;110A 1168 11B1;C3C6;110A 1168 11B1; # (쏆; 쏆; 쏆; 쏆; 쏆; ) HANGUL SYLLABLE SSYELM +C3C7;C3C7;110A 1168 11B2;C3C7;110A 1168 11B2; # (쏇; 쏇; 쏇; 쏇; 쏇; ) HANGUL SYLLABLE SSYELB +C3C8;C3C8;110A 1168 11B3;C3C8;110A 1168 11B3; # (쏈; 쏈; 쏈; 쏈; 쏈; ) HANGUL SYLLABLE SSYELS +C3C9;C3C9;110A 1168 11B4;C3C9;110A 1168 11B4; # (쏉; 쏉; 쏉; 쏉; 쏉; ) HANGUL SYLLABLE SSYELT +C3CA;C3CA;110A 1168 11B5;C3CA;110A 1168 11B5; # (쏊; 쏊; 쏊; 쏊; 쏊; ) HANGUL SYLLABLE SSYELP +C3CB;C3CB;110A 1168 11B6;C3CB;110A 1168 11B6; # (쏋; 쏋; 쏋; 쏋; 쏋; ) HANGUL SYLLABLE SSYELH +C3CC;C3CC;110A 1168 11B7;C3CC;110A 1168 11B7; # (쏌; 쏌; 쏌; 쏌; 쏌; ) HANGUL SYLLABLE SSYEM +C3CD;C3CD;110A 1168 11B8;C3CD;110A 1168 11B8; # (쏍; 쏍; 쏍; 쏍; 쏍; ) HANGUL SYLLABLE SSYEB +C3CE;C3CE;110A 1168 11B9;C3CE;110A 1168 11B9; # (쏎; 쏎; 쏎; 쏎; 쏎; ) HANGUL SYLLABLE SSYEBS +C3CF;C3CF;110A 1168 11BA;C3CF;110A 1168 11BA; # (쏏; 쏏; 쏏; 쏏; 쏏; ) HANGUL SYLLABLE SSYES +C3D0;C3D0;110A 1168 11BB;C3D0;110A 1168 11BB; # (쏐; 쏐; 쏐; 쏐; 쏐; ) HANGUL SYLLABLE SSYESS +C3D1;C3D1;110A 1168 11BC;C3D1;110A 1168 11BC; # (쏑; 쏑; 쏑; 쏑; 쏑; ) HANGUL SYLLABLE SSYENG +C3D2;C3D2;110A 1168 11BD;C3D2;110A 1168 11BD; # (쏒; 쏒; 쏒; 쏒; 쏒; ) HANGUL SYLLABLE SSYEJ +C3D3;C3D3;110A 1168 11BE;C3D3;110A 1168 11BE; # (쏓; 쏓; 쏓; 쏓; 쏓; ) HANGUL SYLLABLE SSYEC +C3D4;C3D4;110A 1168 11BF;C3D4;110A 1168 11BF; # (쏔; 쏔; 쏔; 쏔; 쏔; ) HANGUL SYLLABLE SSYEK +C3D5;C3D5;110A 1168 11C0;C3D5;110A 1168 11C0; # (쏕; 쏕; 쏕; 쏕; 쏕; ) HANGUL SYLLABLE SSYET +C3D6;C3D6;110A 1168 11C1;C3D6;110A 1168 11C1; # (쏖; 쏖; 쏖; 쏖; 쏖; ) HANGUL SYLLABLE SSYEP +C3D7;C3D7;110A 1168 11C2;C3D7;110A 1168 11C2; # (쏗; 쏗; 쏗; 쏗; 쏗; ) HANGUL SYLLABLE SSYEH +C3D8;C3D8;110A 1169;C3D8;110A 1169; # (쏘; 쏘; 쏘; 쏘; 쏘; ) HANGUL SYLLABLE SSO +C3D9;C3D9;110A 1169 11A8;C3D9;110A 1169 11A8; # (쏙; 쏙; 쏙; 쏙; 쏙; ) HANGUL SYLLABLE SSOG +C3DA;C3DA;110A 1169 11A9;C3DA;110A 1169 11A9; # (쏚; 쏚; 쏚; 쏚; 쏚; ) HANGUL SYLLABLE SSOGG +C3DB;C3DB;110A 1169 11AA;C3DB;110A 1169 11AA; # (쏛; 쏛; 쏛; 쏛; 쏛; ) HANGUL SYLLABLE SSOGS +C3DC;C3DC;110A 1169 11AB;C3DC;110A 1169 11AB; # (쏜; 쏜; 쏜; 쏜; 쏜; ) HANGUL SYLLABLE SSON +C3DD;C3DD;110A 1169 11AC;C3DD;110A 1169 11AC; # (쏝; 쏝; 쏝; 쏝; 쏝; ) HANGUL SYLLABLE SSONJ +C3DE;C3DE;110A 1169 11AD;C3DE;110A 1169 11AD; # (쏞; 쏞; 쏞; 쏞; 쏞; ) HANGUL SYLLABLE SSONH +C3DF;C3DF;110A 1169 11AE;C3DF;110A 1169 11AE; # (쏟; 쏟; 쏟; 쏟; 쏟; ) HANGUL SYLLABLE SSOD +C3E0;C3E0;110A 1169 11AF;C3E0;110A 1169 11AF; # (쏠; 쏠; 쏠; 쏠; 쏠; ) HANGUL SYLLABLE SSOL +C3E1;C3E1;110A 1169 11B0;C3E1;110A 1169 11B0; # (쏡; 쏡; 쏡; 쏡; 쏡; ) HANGUL SYLLABLE SSOLG +C3E2;C3E2;110A 1169 11B1;C3E2;110A 1169 11B1; # (쏢; 쏢; 쏢; 쏢; 쏢; ) HANGUL SYLLABLE SSOLM +C3E3;C3E3;110A 1169 11B2;C3E3;110A 1169 11B2; # (쏣; 쏣; 쏣; 쏣; 쏣; ) HANGUL SYLLABLE SSOLB +C3E4;C3E4;110A 1169 11B3;C3E4;110A 1169 11B3; # (쏤; 쏤; 쏤; 쏤; 쏤; ) HANGUL SYLLABLE SSOLS +C3E5;C3E5;110A 1169 11B4;C3E5;110A 1169 11B4; # (쏥; 쏥; 쏥; 쏥; 쏥; ) HANGUL SYLLABLE SSOLT +C3E6;C3E6;110A 1169 11B5;C3E6;110A 1169 11B5; # (쏦; 쏦; 쏦; 쏦; 쏦; ) HANGUL SYLLABLE SSOLP +C3E7;C3E7;110A 1169 11B6;C3E7;110A 1169 11B6; # (쏧; 쏧; 쏧; 쏧; 쏧; ) HANGUL SYLLABLE SSOLH +C3E8;C3E8;110A 1169 11B7;C3E8;110A 1169 11B7; # (쏨; 쏨; 쏨; 쏨; 쏨; ) HANGUL SYLLABLE SSOM +C3E9;C3E9;110A 1169 11B8;C3E9;110A 1169 11B8; # (쏩; 쏩; 쏩; 쏩; 쏩; ) HANGUL SYLLABLE SSOB +C3EA;C3EA;110A 1169 11B9;C3EA;110A 1169 11B9; # (쏪; 쏪; 쏪; 쏪; 쏪; ) HANGUL SYLLABLE SSOBS +C3EB;C3EB;110A 1169 11BA;C3EB;110A 1169 11BA; # (쏫; 쏫; 쏫; 쏫; 쏫; ) HANGUL SYLLABLE SSOS +C3EC;C3EC;110A 1169 11BB;C3EC;110A 1169 11BB; # (쏬; 쏬; 쏬; 쏬; 쏬; ) HANGUL SYLLABLE SSOSS +C3ED;C3ED;110A 1169 11BC;C3ED;110A 1169 11BC; # (쏭; 쏭; 쏭; 쏭; 쏭; ) HANGUL SYLLABLE SSONG +C3EE;C3EE;110A 1169 11BD;C3EE;110A 1169 11BD; # (쏮; 쏮; 쏮; 쏮; 쏮; ) HANGUL SYLLABLE SSOJ +C3EF;C3EF;110A 1169 11BE;C3EF;110A 1169 11BE; # (쏯; 쏯; 쏯; 쏯; 쏯; ) HANGUL SYLLABLE SSOC +C3F0;C3F0;110A 1169 11BF;C3F0;110A 1169 11BF; # (쏰; 쏰; 쏰; 쏰; 쏰; ) HANGUL SYLLABLE SSOK +C3F1;C3F1;110A 1169 11C0;C3F1;110A 1169 11C0; # (쏱; 쏱; 쏱; 쏱; 쏱; ) HANGUL SYLLABLE SSOT +C3F2;C3F2;110A 1169 11C1;C3F2;110A 1169 11C1; # (쏲; 쏲; 쏲; 쏲; 쏲; ) HANGUL SYLLABLE SSOP +C3F3;C3F3;110A 1169 11C2;C3F3;110A 1169 11C2; # (쏳; 쏳; 쏳; 쏳; 쏳; ) HANGUL SYLLABLE SSOH +C3F4;C3F4;110A 116A;C3F4;110A 116A; # (쏴; 쏴; 쏴; 쏴; 쏴; ) HANGUL SYLLABLE SSWA +C3F5;C3F5;110A 116A 11A8;C3F5;110A 116A 11A8; # (쏵; 쏵; 쏵; 쏵; 쏵; ) HANGUL SYLLABLE SSWAG +C3F6;C3F6;110A 116A 11A9;C3F6;110A 116A 11A9; # (쏶; 쏶; 쏶; 쏶; 쏶; ) HANGUL SYLLABLE SSWAGG +C3F7;C3F7;110A 116A 11AA;C3F7;110A 116A 11AA; # (쏷; 쏷; 쏷; 쏷; 쏷; ) HANGUL SYLLABLE SSWAGS +C3F8;C3F8;110A 116A 11AB;C3F8;110A 116A 11AB; # (쏸; 쏸; 쏸; 쏸; 쏸; ) HANGUL SYLLABLE SSWAN +C3F9;C3F9;110A 116A 11AC;C3F9;110A 116A 11AC; # (쏹; 쏹; 쏹; 쏹; 쏹; ) HANGUL SYLLABLE SSWANJ +C3FA;C3FA;110A 116A 11AD;C3FA;110A 116A 11AD; # (쏺; 쏺; 쏺; 쏺; 쏺; ) HANGUL SYLLABLE SSWANH +C3FB;C3FB;110A 116A 11AE;C3FB;110A 116A 11AE; # (쏻; 쏻; 쏻; 쏻; 쏻; ) HANGUL SYLLABLE SSWAD +C3FC;C3FC;110A 116A 11AF;C3FC;110A 116A 11AF; # (쏼; 쏼; 쏼; 쏼; 쏼; ) HANGUL SYLLABLE SSWAL +C3FD;C3FD;110A 116A 11B0;C3FD;110A 116A 11B0; # (쏽; 쏽; 쏽; 쏽; 쏽; ) HANGUL SYLLABLE SSWALG +C3FE;C3FE;110A 116A 11B1;C3FE;110A 116A 11B1; # (쏾; 쏾; 쏾; 쏾; 쏾; ) HANGUL SYLLABLE SSWALM +C3FF;C3FF;110A 116A 11B2;C3FF;110A 116A 11B2; # (쏿; 쏿; 쏿; 쏿; 쏿; ) HANGUL SYLLABLE SSWALB +C400;C400;110A 116A 11B3;C400;110A 116A 11B3; # (쐀; 쐀; 쐀; 쐀; 쐀; ) HANGUL SYLLABLE SSWALS +C401;C401;110A 116A 11B4;C401;110A 116A 11B4; # (쐁; 쐁; 쐁; 쐁; 쐁; ) HANGUL SYLLABLE SSWALT +C402;C402;110A 116A 11B5;C402;110A 116A 11B5; # (쐂; 쐂; 쐂; 쐂; 쐂; ) HANGUL SYLLABLE SSWALP +C403;C403;110A 116A 11B6;C403;110A 116A 11B6; # (쐃; 쐃; 쐃; 쐃; 쐃; ) HANGUL SYLLABLE SSWALH +C404;C404;110A 116A 11B7;C404;110A 116A 11B7; # (쐄; 쐄; 쐄; 쐄; 쐄; ) HANGUL SYLLABLE SSWAM +C405;C405;110A 116A 11B8;C405;110A 116A 11B8; # (쐅; 쐅; 쐅; 쐅; 쐅; ) HANGUL SYLLABLE SSWAB +C406;C406;110A 116A 11B9;C406;110A 116A 11B9; # (쐆; 쐆; 쐆; 쐆; 쐆; ) HANGUL SYLLABLE SSWABS +C407;C407;110A 116A 11BA;C407;110A 116A 11BA; # (쐇; 쐇; 쐇; 쐇; 쐇; ) HANGUL SYLLABLE SSWAS +C408;C408;110A 116A 11BB;C408;110A 116A 11BB; # (쐈; 쐈; 쐈; 쐈; 쐈; ) HANGUL SYLLABLE SSWASS +C409;C409;110A 116A 11BC;C409;110A 116A 11BC; # (쐉; 쐉; 쐉; 쐉; 쐉; ) HANGUL SYLLABLE SSWANG +C40A;C40A;110A 116A 11BD;C40A;110A 116A 11BD; # (쐊; 쐊; 쐊; 쐊; 쐊; ) HANGUL SYLLABLE SSWAJ +C40B;C40B;110A 116A 11BE;C40B;110A 116A 11BE; # (쐋; 쐋; 쐋; 쐋; 쐋; ) HANGUL SYLLABLE SSWAC +C40C;C40C;110A 116A 11BF;C40C;110A 116A 11BF; # (쐌; 쐌; 쐌; 쐌; 쐌; ) HANGUL SYLLABLE SSWAK +C40D;C40D;110A 116A 11C0;C40D;110A 116A 11C0; # (쐍; 쐍; 쐍; 쐍; 쐍; ) HANGUL SYLLABLE SSWAT +C40E;C40E;110A 116A 11C1;C40E;110A 116A 11C1; # (쐎; 쐎; 쐎; 쐎; 쐎; ) HANGUL SYLLABLE SSWAP +C40F;C40F;110A 116A 11C2;C40F;110A 116A 11C2; # (쐏; 쐏; 쐏; 쐏; 쐏; ) HANGUL SYLLABLE SSWAH +C410;C410;110A 116B;C410;110A 116B; # (쐐; 쐐; 쐐; 쐐; 쐐; ) HANGUL SYLLABLE SSWAE +C411;C411;110A 116B 11A8;C411;110A 116B 11A8; # (쐑; 쐑; 쐑; 쐑; 쐑; ) HANGUL SYLLABLE SSWAEG +C412;C412;110A 116B 11A9;C412;110A 116B 11A9; # (쐒; 쐒; 쐒; 쐒; 쐒; ) HANGUL SYLLABLE SSWAEGG +C413;C413;110A 116B 11AA;C413;110A 116B 11AA; # (쐓; 쐓; 쐓; 쐓; 쐓; ) HANGUL SYLLABLE SSWAEGS +C414;C414;110A 116B 11AB;C414;110A 116B 11AB; # (쐔; 쐔; 쐔; 쐔; 쐔; ) HANGUL SYLLABLE SSWAEN +C415;C415;110A 116B 11AC;C415;110A 116B 11AC; # (쐕; 쐕; 쐕; 쐕; 쐕; ) HANGUL SYLLABLE SSWAENJ +C416;C416;110A 116B 11AD;C416;110A 116B 11AD; # (쐖; 쐖; 쐖; 쐖; 쐖; ) HANGUL SYLLABLE SSWAENH +C417;C417;110A 116B 11AE;C417;110A 116B 11AE; # (쐗; 쐗; 쐗; 쐗; 쐗; ) HANGUL SYLLABLE SSWAED +C418;C418;110A 116B 11AF;C418;110A 116B 11AF; # (쐘; 쐘; 쐘; 쐘; 쐘; ) HANGUL SYLLABLE SSWAEL +C419;C419;110A 116B 11B0;C419;110A 116B 11B0; # (쐙; 쐙; 쐙; 쐙; 쐙; ) HANGUL SYLLABLE SSWAELG +C41A;C41A;110A 116B 11B1;C41A;110A 116B 11B1; # (쐚; 쐚; 쐚; 쐚; 쐚; ) HANGUL SYLLABLE SSWAELM +C41B;C41B;110A 116B 11B2;C41B;110A 116B 11B2; # (쐛; 쐛; 쐛; 쐛; 쐛; ) HANGUL SYLLABLE SSWAELB +C41C;C41C;110A 116B 11B3;C41C;110A 116B 11B3; # (쐜; 쐜; 쐜; 쐜; 쐜; ) HANGUL SYLLABLE SSWAELS +C41D;C41D;110A 116B 11B4;C41D;110A 116B 11B4; # (쐝; 쐝; 쐝; 쐝; 쐝; ) HANGUL SYLLABLE SSWAELT +C41E;C41E;110A 116B 11B5;C41E;110A 116B 11B5; # (쐞; 쐞; 쐞; 쐞; 쐞; ) HANGUL SYLLABLE SSWAELP +C41F;C41F;110A 116B 11B6;C41F;110A 116B 11B6; # (쐟; 쐟; 쐟; 쐟; 쐟; ) HANGUL SYLLABLE SSWAELH +C420;C420;110A 116B 11B7;C420;110A 116B 11B7; # (쐠; 쐠; 쐠; 쐠; 쐠; ) HANGUL SYLLABLE SSWAEM +C421;C421;110A 116B 11B8;C421;110A 116B 11B8; # (쐡; 쐡; 쐡; 쐡; 쐡; ) HANGUL SYLLABLE SSWAEB +C422;C422;110A 116B 11B9;C422;110A 116B 11B9; # (쐢; 쐢; 쐢; 쐢; 쐢; ) HANGUL SYLLABLE SSWAEBS +C423;C423;110A 116B 11BA;C423;110A 116B 11BA; # (쐣; 쐣; 쐣; 쐣; 쐣; ) HANGUL SYLLABLE SSWAES +C424;C424;110A 116B 11BB;C424;110A 116B 11BB; # (쐤; 쐤; 쐤; 쐤; 쐤; ) HANGUL SYLLABLE SSWAESS +C425;C425;110A 116B 11BC;C425;110A 116B 11BC; # (쐥; 쐥; 쐥; 쐥; 쐥; ) HANGUL SYLLABLE SSWAENG +C426;C426;110A 116B 11BD;C426;110A 116B 11BD; # (쐦; 쐦; 쐦; 쐦; 쐦; ) HANGUL SYLLABLE SSWAEJ +C427;C427;110A 116B 11BE;C427;110A 116B 11BE; # (쐧; 쐧; 쐧; 쐧; 쐧; ) HANGUL SYLLABLE SSWAEC +C428;C428;110A 116B 11BF;C428;110A 116B 11BF; # (쐨; 쐨; 쐨; 쐨; 쐨; ) HANGUL SYLLABLE SSWAEK +C429;C429;110A 116B 11C0;C429;110A 116B 11C0; # (쐩; 쐩; 쐩; 쐩; 쐩; ) HANGUL SYLLABLE SSWAET +C42A;C42A;110A 116B 11C1;C42A;110A 116B 11C1; # (쐪; 쐪; 쐪; 쐪; 쐪; ) HANGUL SYLLABLE SSWAEP +C42B;C42B;110A 116B 11C2;C42B;110A 116B 11C2; # (쐫; 쐫; 쐫; 쐫; 쐫; ) HANGUL SYLLABLE SSWAEH +C42C;C42C;110A 116C;C42C;110A 116C; # (쐬; 쐬; 쐬; 쐬; 쐬; ) HANGUL SYLLABLE SSOE +C42D;C42D;110A 116C 11A8;C42D;110A 116C 11A8; # (쐭; 쐭; 쐭; 쐭; 쐭; ) HANGUL SYLLABLE SSOEG +C42E;C42E;110A 116C 11A9;C42E;110A 116C 11A9; # (쐮; 쐮; 쐮; 쐮; 쐮; ) HANGUL SYLLABLE SSOEGG +C42F;C42F;110A 116C 11AA;C42F;110A 116C 11AA; # (쐯; 쐯; 쐯; 쐯; 쐯; ) HANGUL SYLLABLE SSOEGS +C430;C430;110A 116C 11AB;C430;110A 116C 11AB; # (쐰; 쐰; 쐰; 쐰; 쐰; ) HANGUL SYLLABLE SSOEN +C431;C431;110A 116C 11AC;C431;110A 116C 11AC; # (쐱; 쐱; 쐱; 쐱; 쐱; ) HANGUL SYLLABLE SSOENJ +C432;C432;110A 116C 11AD;C432;110A 116C 11AD; # (쐲; 쐲; 쐲; 쐲; 쐲; ) HANGUL SYLLABLE SSOENH +C433;C433;110A 116C 11AE;C433;110A 116C 11AE; # (쐳; 쐳; 쐳; 쐳; 쐳; ) HANGUL SYLLABLE SSOED +C434;C434;110A 116C 11AF;C434;110A 116C 11AF; # (쐴; 쐴; 쐴; 쐴; 쐴; ) HANGUL SYLLABLE SSOEL +C435;C435;110A 116C 11B0;C435;110A 116C 11B0; # (쐵; 쐵; 쐵; 쐵; 쐵; ) HANGUL SYLLABLE SSOELG +C436;C436;110A 116C 11B1;C436;110A 116C 11B1; # (쐶; 쐶; 쐶; 쐶; 쐶; ) HANGUL SYLLABLE SSOELM +C437;C437;110A 116C 11B2;C437;110A 116C 11B2; # (쐷; 쐷; 쐷; 쐷; 쐷; ) HANGUL SYLLABLE SSOELB +C438;C438;110A 116C 11B3;C438;110A 116C 11B3; # (쐸; 쐸; 쐸; 쐸; 쐸; ) HANGUL SYLLABLE SSOELS +C439;C439;110A 116C 11B4;C439;110A 116C 11B4; # (쐹; 쐹; 쐹; 쐹; 쐹; ) HANGUL SYLLABLE SSOELT +C43A;C43A;110A 116C 11B5;C43A;110A 116C 11B5; # (쐺; 쐺; 쐺; 쐺; 쐺; ) HANGUL SYLLABLE SSOELP +C43B;C43B;110A 116C 11B6;C43B;110A 116C 11B6; # (쐻; 쐻; 쐻; 쐻; 쐻; ) HANGUL SYLLABLE SSOELH +C43C;C43C;110A 116C 11B7;C43C;110A 116C 11B7; # (쐼; 쐼; 쐼; 쐼; 쐼; ) HANGUL SYLLABLE SSOEM +C43D;C43D;110A 116C 11B8;C43D;110A 116C 11B8; # (쐽; 쐽; 쐽; 쐽; 쐽; ) HANGUL SYLLABLE SSOEB +C43E;C43E;110A 116C 11B9;C43E;110A 116C 11B9; # (쐾; 쐾; 쐾; 쐾; 쐾; ) HANGUL SYLLABLE SSOEBS +C43F;C43F;110A 116C 11BA;C43F;110A 116C 11BA; # (쐿; 쐿; 쐿; 쐿; 쐿; ) HANGUL SYLLABLE SSOES +C440;C440;110A 116C 11BB;C440;110A 116C 11BB; # (쑀; 쑀; 쑀; 쑀; 쑀; ) HANGUL SYLLABLE SSOESS +C441;C441;110A 116C 11BC;C441;110A 116C 11BC; # (쑁; 쑁; 쑁; 쑁; 쑁; ) HANGUL SYLLABLE SSOENG +C442;C442;110A 116C 11BD;C442;110A 116C 11BD; # (쑂; 쑂; 쑂; 쑂; 쑂; ) HANGUL SYLLABLE SSOEJ +C443;C443;110A 116C 11BE;C443;110A 116C 11BE; # (쑃; 쑃; 쑃; 쑃; 쑃; ) HANGUL SYLLABLE SSOEC +C444;C444;110A 116C 11BF;C444;110A 116C 11BF; # (쑄; 쑄; 쑄; 쑄; 쑄; ) HANGUL SYLLABLE SSOEK +C445;C445;110A 116C 11C0;C445;110A 116C 11C0; # (쑅; 쑅; 쑅; 쑅; 쑅; ) HANGUL SYLLABLE SSOET +C446;C446;110A 116C 11C1;C446;110A 116C 11C1; # (쑆; 쑆; 쑆; 쑆; 쑆; ) HANGUL SYLLABLE SSOEP +C447;C447;110A 116C 11C2;C447;110A 116C 11C2; # (쑇; 쑇; 쑇; 쑇; 쑇; ) HANGUL SYLLABLE SSOEH +C448;C448;110A 116D;C448;110A 116D; # (쑈; 쑈; 쑈; 쑈; 쑈; ) HANGUL SYLLABLE SSYO +C449;C449;110A 116D 11A8;C449;110A 116D 11A8; # (쑉; 쑉; 쑉; 쑉; 쑉; ) HANGUL SYLLABLE SSYOG +C44A;C44A;110A 116D 11A9;C44A;110A 116D 11A9; # (쑊; 쑊; 쑊; 쑊; 쑊; ) HANGUL SYLLABLE SSYOGG +C44B;C44B;110A 116D 11AA;C44B;110A 116D 11AA; # (쑋; 쑋; 쑋; 쑋; 쑋; ) HANGUL SYLLABLE SSYOGS +C44C;C44C;110A 116D 11AB;C44C;110A 116D 11AB; # (쑌; 쑌; 쑌; 쑌; 쑌; ) HANGUL SYLLABLE SSYON +C44D;C44D;110A 116D 11AC;C44D;110A 116D 11AC; # (쑍; 쑍; 쑍; 쑍; 쑍; ) HANGUL SYLLABLE SSYONJ +C44E;C44E;110A 116D 11AD;C44E;110A 116D 11AD; # (쑎; 쑎; 쑎; 쑎; 쑎; ) HANGUL SYLLABLE SSYONH +C44F;C44F;110A 116D 11AE;C44F;110A 116D 11AE; # (쑏; 쑏; 쑏; 쑏; 쑏; ) HANGUL SYLLABLE SSYOD +C450;C450;110A 116D 11AF;C450;110A 116D 11AF; # (쑐; 쑐; 쑐; 쑐; 쑐; ) HANGUL SYLLABLE SSYOL +C451;C451;110A 116D 11B0;C451;110A 116D 11B0; # (쑑; 쑑; 쑑; 쑑; 쑑; ) HANGUL SYLLABLE SSYOLG +C452;C452;110A 116D 11B1;C452;110A 116D 11B1; # (쑒; 쑒; 쑒; 쑒; 쑒; ) HANGUL SYLLABLE SSYOLM +C453;C453;110A 116D 11B2;C453;110A 116D 11B2; # (쑓; 쑓; 쑓; 쑓; 쑓; ) HANGUL SYLLABLE SSYOLB +C454;C454;110A 116D 11B3;C454;110A 116D 11B3; # (쑔; 쑔; 쑔; 쑔; 쑔; ) HANGUL SYLLABLE SSYOLS +C455;C455;110A 116D 11B4;C455;110A 116D 11B4; # (쑕; 쑕; 쑕; 쑕; 쑕; ) HANGUL SYLLABLE SSYOLT +C456;C456;110A 116D 11B5;C456;110A 116D 11B5; # (쑖; 쑖; 쑖; 쑖; 쑖; ) HANGUL SYLLABLE SSYOLP +C457;C457;110A 116D 11B6;C457;110A 116D 11B6; # (쑗; 쑗; 쑗; 쑗; 쑗; ) HANGUL SYLLABLE SSYOLH +C458;C458;110A 116D 11B7;C458;110A 116D 11B7; # (쑘; 쑘; 쑘; 쑘; 쑘; ) HANGUL SYLLABLE SSYOM +C459;C459;110A 116D 11B8;C459;110A 116D 11B8; # (쑙; 쑙; 쑙; 쑙; 쑙; ) HANGUL SYLLABLE SSYOB +C45A;C45A;110A 116D 11B9;C45A;110A 116D 11B9; # (쑚; 쑚; 쑚; 쑚; 쑚; ) HANGUL SYLLABLE SSYOBS +C45B;C45B;110A 116D 11BA;C45B;110A 116D 11BA; # (쑛; 쑛; 쑛; 쑛; 쑛; ) HANGUL SYLLABLE SSYOS +C45C;C45C;110A 116D 11BB;C45C;110A 116D 11BB; # (쑜; 쑜; 쑜; 쑜; 쑜; ) HANGUL SYLLABLE SSYOSS +C45D;C45D;110A 116D 11BC;C45D;110A 116D 11BC; # (쑝; 쑝; 쑝; 쑝; 쑝; ) HANGUL SYLLABLE SSYONG +C45E;C45E;110A 116D 11BD;C45E;110A 116D 11BD; # (쑞; 쑞; 쑞; 쑞; 쑞; ) HANGUL SYLLABLE SSYOJ +C45F;C45F;110A 116D 11BE;C45F;110A 116D 11BE; # (쑟; 쑟; 쑟; 쑟; 쑟; ) HANGUL SYLLABLE SSYOC +C460;C460;110A 116D 11BF;C460;110A 116D 11BF; # (쑠; 쑠; 쑠; 쑠; 쑠; ) HANGUL SYLLABLE SSYOK +C461;C461;110A 116D 11C0;C461;110A 116D 11C0; # (쑡; 쑡; 쑡; 쑡; 쑡; ) HANGUL SYLLABLE SSYOT +C462;C462;110A 116D 11C1;C462;110A 116D 11C1; # (쑢; 쑢; 쑢; 쑢; 쑢; ) HANGUL SYLLABLE SSYOP +C463;C463;110A 116D 11C2;C463;110A 116D 11C2; # (쑣; 쑣; 쑣; 쑣; 쑣; ) HANGUL SYLLABLE SSYOH +C464;C464;110A 116E;C464;110A 116E; # (쑤; 쑤; 쑤; 쑤; 쑤; ) HANGUL SYLLABLE SSU +C465;C465;110A 116E 11A8;C465;110A 116E 11A8; # (쑥; 쑥; 쑥; 쑥; 쑥; ) HANGUL SYLLABLE SSUG +C466;C466;110A 116E 11A9;C466;110A 116E 11A9; # (쑦; 쑦; 쑦; 쑦; 쑦; ) HANGUL SYLLABLE SSUGG +C467;C467;110A 116E 11AA;C467;110A 116E 11AA; # (쑧; 쑧; 쑧; 쑧; 쑧; ) HANGUL SYLLABLE SSUGS +C468;C468;110A 116E 11AB;C468;110A 116E 11AB; # (쑨; 쑨; 쑨; 쑨; 쑨; ) HANGUL SYLLABLE SSUN +C469;C469;110A 116E 11AC;C469;110A 116E 11AC; # (쑩; 쑩; 쑩; 쑩; 쑩; ) HANGUL SYLLABLE SSUNJ +C46A;C46A;110A 116E 11AD;C46A;110A 116E 11AD; # (쑪; 쑪; 쑪; 쑪; 쑪; ) HANGUL SYLLABLE SSUNH +C46B;C46B;110A 116E 11AE;C46B;110A 116E 11AE; # (쑫; 쑫; 쑫; 쑫; 쑫; ) HANGUL SYLLABLE SSUD +C46C;C46C;110A 116E 11AF;C46C;110A 116E 11AF; # (쑬; 쑬; 쑬; 쑬; 쑬; ) HANGUL SYLLABLE SSUL +C46D;C46D;110A 116E 11B0;C46D;110A 116E 11B0; # (쑭; 쑭; 쑭; 쑭; 쑭; ) HANGUL SYLLABLE SSULG +C46E;C46E;110A 116E 11B1;C46E;110A 116E 11B1; # (쑮; 쑮; 쑮; 쑮; 쑮; ) HANGUL SYLLABLE SSULM +C46F;C46F;110A 116E 11B2;C46F;110A 116E 11B2; # (쑯; 쑯; 쑯; 쑯; 쑯; ) HANGUL SYLLABLE SSULB +C470;C470;110A 116E 11B3;C470;110A 116E 11B3; # (쑰; 쑰; 쑰; 쑰; 쑰; ) HANGUL SYLLABLE SSULS +C471;C471;110A 116E 11B4;C471;110A 116E 11B4; # (쑱; 쑱; 쑱; 쑱; 쑱; ) HANGUL SYLLABLE SSULT +C472;C472;110A 116E 11B5;C472;110A 116E 11B5; # (쑲; 쑲; 쑲; 쑲; 쑲; ) HANGUL SYLLABLE SSULP +C473;C473;110A 116E 11B6;C473;110A 116E 11B6; # (쑳; 쑳; 쑳; 쑳; 쑳; ) HANGUL SYLLABLE SSULH +C474;C474;110A 116E 11B7;C474;110A 116E 11B7; # (쑴; 쑴; 쑴; 쑴; 쑴; ) HANGUL SYLLABLE SSUM +C475;C475;110A 116E 11B8;C475;110A 116E 11B8; # (쑵; 쑵; 쑵; 쑵; 쑵; ) HANGUL SYLLABLE SSUB +C476;C476;110A 116E 11B9;C476;110A 116E 11B9; # (쑶; 쑶; 쑶; 쑶; 쑶; ) HANGUL SYLLABLE SSUBS +C477;C477;110A 116E 11BA;C477;110A 116E 11BA; # (쑷; 쑷; 쑷; 쑷; 쑷; ) HANGUL SYLLABLE SSUS +C478;C478;110A 116E 11BB;C478;110A 116E 11BB; # (쑸; 쑸; 쑸; 쑸; 쑸; ) HANGUL SYLLABLE SSUSS +C479;C479;110A 116E 11BC;C479;110A 116E 11BC; # (쑹; 쑹; 쑹; 쑹; 쑹; ) HANGUL SYLLABLE SSUNG +C47A;C47A;110A 116E 11BD;C47A;110A 116E 11BD; # (쑺; 쑺; 쑺; 쑺; 쑺; ) HANGUL SYLLABLE SSUJ +C47B;C47B;110A 116E 11BE;C47B;110A 116E 11BE; # (쑻; 쑻; 쑻; 쑻; 쑻; ) HANGUL SYLLABLE SSUC +C47C;C47C;110A 116E 11BF;C47C;110A 116E 11BF; # (쑼; 쑼; 쑼; 쑼; 쑼; ) HANGUL SYLLABLE SSUK +C47D;C47D;110A 116E 11C0;C47D;110A 116E 11C0; # (쑽; 쑽; 쑽; 쑽; 쑽; ) HANGUL SYLLABLE SSUT +C47E;C47E;110A 116E 11C1;C47E;110A 116E 11C1; # (쑾; 쑾; 쑾; 쑾; 쑾; ) HANGUL SYLLABLE SSUP +C47F;C47F;110A 116E 11C2;C47F;110A 116E 11C2; # (쑿; 쑿; 쑿; 쑿; 쑿; ) HANGUL SYLLABLE SSUH +C480;C480;110A 116F;C480;110A 116F; # (쒀; 쒀; 쒀; 쒀; 쒀; ) HANGUL SYLLABLE SSWEO +C481;C481;110A 116F 11A8;C481;110A 116F 11A8; # (쒁; 쒁; 쒁; 쒁; 쒁; ) HANGUL SYLLABLE SSWEOG +C482;C482;110A 116F 11A9;C482;110A 116F 11A9; # (쒂; 쒂; 쒂; 쒂; 쒂; ) HANGUL SYLLABLE SSWEOGG +C483;C483;110A 116F 11AA;C483;110A 116F 11AA; # (쒃; 쒃; 쒃; 쒃; 쒃; ) HANGUL SYLLABLE SSWEOGS +C484;C484;110A 116F 11AB;C484;110A 116F 11AB; # (쒄; 쒄; 쒄; 쒄; 쒄; ) HANGUL SYLLABLE SSWEON +C485;C485;110A 116F 11AC;C485;110A 116F 11AC; # (쒅; 쒅; 쒅; 쒅; 쒅; ) HANGUL SYLLABLE SSWEONJ +C486;C486;110A 116F 11AD;C486;110A 116F 11AD; # (쒆; 쒆; 쒆; 쒆; 쒆; ) HANGUL SYLLABLE SSWEONH +C487;C487;110A 116F 11AE;C487;110A 116F 11AE; # (쒇; 쒇; 쒇; 쒇; 쒇; ) HANGUL SYLLABLE SSWEOD +C488;C488;110A 116F 11AF;C488;110A 116F 11AF; # (쒈; 쒈; 쒈; 쒈; 쒈; ) HANGUL SYLLABLE SSWEOL +C489;C489;110A 116F 11B0;C489;110A 116F 11B0; # (쒉; 쒉; 쒉; 쒉; 쒉; ) HANGUL SYLLABLE SSWEOLG +C48A;C48A;110A 116F 11B1;C48A;110A 116F 11B1; # (쒊; 쒊; 쒊; 쒊; 쒊; ) HANGUL SYLLABLE SSWEOLM +C48B;C48B;110A 116F 11B2;C48B;110A 116F 11B2; # (쒋; 쒋; 쒋; 쒋; 쒋; ) HANGUL SYLLABLE SSWEOLB +C48C;C48C;110A 116F 11B3;C48C;110A 116F 11B3; # (쒌; 쒌; 쒌; 쒌; 쒌; ) HANGUL SYLLABLE SSWEOLS +C48D;C48D;110A 116F 11B4;C48D;110A 116F 11B4; # (쒍; 쒍; 쒍; 쒍; 쒍; ) HANGUL SYLLABLE SSWEOLT +C48E;C48E;110A 116F 11B5;C48E;110A 116F 11B5; # (쒎; 쒎; 쒎; 쒎; 쒎; ) HANGUL SYLLABLE SSWEOLP +C48F;C48F;110A 116F 11B6;C48F;110A 116F 11B6; # (쒏; 쒏; 쒏; 쒏; 쒏; ) HANGUL SYLLABLE SSWEOLH +C490;C490;110A 116F 11B7;C490;110A 116F 11B7; # (쒐; 쒐; 쒐; 쒐; 쒐; ) HANGUL SYLLABLE SSWEOM +C491;C491;110A 116F 11B8;C491;110A 116F 11B8; # (쒑; 쒑; 쒑; 쒑; 쒑; ) HANGUL SYLLABLE SSWEOB +C492;C492;110A 116F 11B9;C492;110A 116F 11B9; # (쒒; 쒒; 쒒; 쒒; 쒒; ) HANGUL SYLLABLE SSWEOBS +C493;C493;110A 116F 11BA;C493;110A 116F 11BA; # (쒓; 쒓; 쒓; 쒓; 쒓; ) HANGUL SYLLABLE SSWEOS +C494;C494;110A 116F 11BB;C494;110A 116F 11BB; # (쒔; 쒔; 쒔; 쒔; 쒔; ) HANGUL SYLLABLE SSWEOSS +C495;C495;110A 116F 11BC;C495;110A 116F 11BC; # (쒕; 쒕; 쒕; 쒕; 쒕; ) HANGUL SYLLABLE SSWEONG +C496;C496;110A 116F 11BD;C496;110A 116F 11BD; # (쒖; 쒖; 쒖; 쒖; 쒖; ) HANGUL SYLLABLE SSWEOJ +C497;C497;110A 116F 11BE;C497;110A 116F 11BE; # (쒗; 쒗; 쒗; 쒗; 쒗; ) HANGUL SYLLABLE SSWEOC +C498;C498;110A 116F 11BF;C498;110A 116F 11BF; # (쒘; 쒘; 쒘; 쒘; 쒘; ) HANGUL SYLLABLE SSWEOK +C499;C499;110A 116F 11C0;C499;110A 116F 11C0; # (쒙; 쒙; 쒙; 쒙; 쒙; ) HANGUL SYLLABLE SSWEOT +C49A;C49A;110A 116F 11C1;C49A;110A 116F 11C1; # (쒚; 쒚; 쒚; 쒚; 쒚; ) HANGUL SYLLABLE SSWEOP +C49B;C49B;110A 116F 11C2;C49B;110A 116F 11C2; # (쒛; 쒛; 쒛; 쒛; 쒛; ) HANGUL SYLLABLE SSWEOH +C49C;C49C;110A 1170;C49C;110A 1170; # (쒜; 쒜; 쒜; 쒜; 쒜; ) HANGUL SYLLABLE SSWE +C49D;C49D;110A 1170 11A8;C49D;110A 1170 11A8; # (쒝; 쒝; 쒝; 쒝; 쒝; ) HANGUL SYLLABLE SSWEG +C49E;C49E;110A 1170 11A9;C49E;110A 1170 11A9; # (쒞; 쒞; 쒞; 쒞; 쒞; ) HANGUL SYLLABLE SSWEGG +C49F;C49F;110A 1170 11AA;C49F;110A 1170 11AA; # (쒟; 쒟; 쒟; 쒟; 쒟; ) HANGUL SYLLABLE SSWEGS +C4A0;C4A0;110A 1170 11AB;C4A0;110A 1170 11AB; # (쒠; 쒠; 쒠; 쒠; 쒠; ) HANGUL SYLLABLE SSWEN +C4A1;C4A1;110A 1170 11AC;C4A1;110A 1170 11AC; # (쒡; 쒡; 쒡; 쒡; 쒡; ) HANGUL SYLLABLE SSWENJ +C4A2;C4A2;110A 1170 11AD;C4A2;110A 1170 11AD; # (쒢; 쒢; 쒢; 쒢; 쒢; ) HANGUL SYLLABLE SSWENH +C4A3;C4A3;110A 1170 11AE;C4A3;110A 1170 11AE; # (쒣; 쒣; 쒣; 쒣; 쒣; ) HANGUL SYLLABLE SSWED +C4A4;C4A4;110A 1170 11AF;C4A4;110A 1170 11AF; # (쒤; 쒤; 쒤; 쒤; 쒤; ) HANGUL SYLLABLE SSWEL +C4A5;C4A5;110A 1170 11B0;C4A5;110A 1170 11B0; # (쒥; 쒥; 쒥; 쒥; 쒥; ) HANGUL SYLLABLE SSWELG +C4A6;C4A6;110A 1170 11B1;C4A6;110A 1170 11B1; # (쒦; 쒦; 쒦; 쒦; 쒦; ) HANGUL SYLLABLE SSWELM +C4A7;C4A7;110A 1170 11B2;C4A7;110A 1170 11B2; # (쒧; 쒧; 쒧; 쒧; 쒧; ) HANGUL SYLLABLE SSWELB +C4A8;C4A8;110A 1170 11B3;C4A8;110A 1170 11B3; # (쒨; 쒨; 쒨; 쒨; 쒨; ) HANGUL SYLLABLE SSWELS +C4A9;C4A9;110A 1170 11B4;C4A9;110A 1170 11B4; # (쒩; 쒩; 쒩; 쒩; 쒩; ) HANGUL SYLLABLE SSWELT +C4AA;C4AA;110A 1170 11B5;C4AA;110A 1170 11B5; # (쒪; 쒪; 쒪; 쒪; 쒪; ) HANGUL SYLLABLE SSWELP +C4AB;C4AB;110A 1170 11B6;C4AB;110A 1170 11B6; # (쒫; 쒫; 쒫; 쒫; 쒫; ) HANGUL SYLLABLE SSWELH +C4AC;C4AC;110A 1170 11B7;C4AC;110A 1170 11B7; # (쒬; 쒬; 쒬; 쒬; 쒬; ) HANGUL SYLLABLE SSWEM +C4AD;C4AD;110A 1170 11B8;C4AD;110A 1170 11B8; # (쒭; 쒭; 쒭; 쒭; 쒭; ) HANGUL SYLLABLE SSWEB +C4AE;C4AE;110A 1170 11B9;C4AE;110A 1170 11B9; # (쒮; 쒮; 쒮; 쒮; 쒮; ) HANGUL SYLLABLE SSWEBS +C4AF;C4AF;110A 1170 11BA;C4AF;110A 1170 11BA; # (쒯; 쒯; 쒯; 쒯; 쒯; ) HANGUL SYLLABLE SSWES +C4B0;C4B0;110A 1170 11BB;C4B0;110A 1170 11BB; # (쒰; 쒰; 쒰; 쒰; 쒰; ) HANGUL SYLLABLE SSWESS +C4B1;C4B1;110A 1170 11BC;C4B1;110A 1170 11BC; # (쒱; 쒱; 쒱; 쒱; 쒱; ) HANGUL SYLLABLE SSWENG +C4B2;C4B2;110A 1170 11BD;C4B2;110A 1170 11BD; # (쒲; 쒲; 쒲; 쒲; 쒲; ) HANGUL SYLLABLE SSWEJ +C4B3;C4B3;110A 1170 11BE;C4B3;110A 1170 11BE; # (쒳; 쒳; 쒳; 쒳; 쒳; ) HANGUL SYLLABLE SSWEC +C4B4;C4B4;110A 1170 11BF;C4B4;110A 1170 11BF; # (쒴; 쒴; 쒴; 쒴; 쒴; ) HANGUL SYLLABLE SSWEK +C4B5;C4B5;110A 1170 11C0;C4B5;110A 1170 11C0; # (쒵; 쒵; 쒵; 쒵; 쒵; ) HANGUL SYLLABLE SSWET +C4B6;C4B6;110A 1170 11C1;C4B6;110A 1170 11C1; # (쒶; 쒶; 쒶; 쒶; 쒶; ) HANGUL SYLLABLE SSWEP +C4B7;C4B7;110A 1170 11C2;C4B7;110A 1170 11C2; # (쒷; 쒷; 쒷; 쒷; 쒷; ) HANGUL SYLLABLE SSWEH +C4B8;C4B8;110A 1171;C4B8;110A 1171; # (쒸; 쒸; 쒸; 쒸; 쒸; ) HANGUL SYLLABLE SSWI +C4B9;C4B9;110A 1171 11A8;C4B9;110A 1171 11A8; # (쒹; 쒹; 쒹; 쒹; 쒹; ) HANGUL SYLLABLE SSWIG +C4BA;C4BA;110A 1171 11A9;C4BA;110A 1171 11A9; # (쒺; 쒺; 쒺; 쒺; 쒺; ) HANGUL SYLLABLE SSWIGG +C4BB;C4BB;110A 1171 11AA;C4BB;110A 1171 11AA; # (쒻; 쒻; 쒻; 쒻; 쒻; ) HANGUL SYLLABLE SSWIGS +C4BC;C4BC;110A 1171 11AB;C4BC;110A 1171 11AB; # (쒼; 쒼; 쒼; 쒼; 쒼; ) HANGUL SYLLABLE SSWIN +C4BD;C4BD;110A 1171 11AC;C4BD;110A 1171 11AC; # (쒽; 쒽; 쒽; 쒽; 쒽; ) HANGUL SYLLABLE SSWINJ +C4BE;C4BE;110A 1171 11AD;C4BE;110A 1171 11AD; # (쒾; 쒾; 쒾; 쒾; 쒾; ) HANGUL SYLLABLE SSWINH +C4BF;C4BF;110A 1171 11AE;C4BF;110A 1171 11AE; # (쒿; 쒿; 쒿; 쒿; 쒿; ) HANGUL SYLLABLE SSWID +C4C0;C4C0;110A 1171 11AF;C4C0;110A 1171 11AF; # (쓀; 쓀; 쓀; 쓀; 쓀; ) HANGUL SYLLABLE SSWIL +C4C1;C4C1;110A 1171 11B0;C4C1;110A 1171 11B0; # (쓁; 쓁; 쓁; 쓁; 쓁; ) HANGUL SYLLABLE SSWILG +C4C2;C4C2;110A 1171 11B1;C4C2;110A 1171 11B1; # (쓂; 쓂; 쓂; 쓂; 쓂; ) HANGUL SYLLABLE SSWILM +C4C3;C4C3;110A 1171 11B2;C4C3;110A 1171 11B2; # (쓃; 쓃; 쓃; 쓃; 쓃; ) HANGUL SYLLABLE SSWILB +C4C4;C4C4;110A 1171 11B3;C4C4;110A 1171 11B3; # (쓄; 쓄; 쓄; 쓄; 쓄; ) HANGUL SYLLABLE SSWILS +C4C5;C4C5;110A 1171 11B4;C4C5;110A 1171 11B4; # (쓅; 쓅; 쓅; 쓅; 쓅; ) HANGUL SYLLABLE SSWILT +C4C6;C4C6;110A 1171 11B5;C4C6;110A 1171 11B5; # (쓆; 쓆; 쓆; 쓆; 쓆; ) HANGUL SYLLABLE SSWILP +C4C7;C4C7;110A 1171 11B6;C4C7;110A 1171 11B6; # (쓇; 쓇; 쓇; 쓇; 쓇; ) HANGUL SYLLABLE SSWILH +C4C8;C4C8;110A 1171 11B7;C4C8;110A 1171 11B7; # (쓈; 쓈; 쓈; 쓈; 쓈; ) HANGUL SYLLABLE SSWIM +C4C9;C4C9;110A 1171 11B8;C4C9;110A 1171 11B8; # (쓉; 쓉; 쓉; 쓉; 쓉; ) HANGUL SYLLABLE SSWIB +C4CA;C4CA;110A 1171 11B9;C4CA;110A 1171 11B9; # (쓊; 쓊; 쓊; 쓊; 쓊; ) HANGUL SYLLABLE SSWIBS +C4CB;C4CB;110A 1171 11BA;C4CB;110A 1171 11BA; # (쓋; 쓋; 쓋; 쓋; 쓋; ) HANGUL SYLLABLE SSWIS +C4CC;C4CC;110A 1171 11BB;C4CC;110A 1171 11BB; # (쓌; 쓌; 쓌; 쓌; 쓌; ) HANGUL SYLLABLE SSWISS +C4CD;C4CD;110A 1171 11BC;C4CD;110A 1171 11BC; # (쓍; 쓍; 쓍; 쓍; 쓍; ) HANGUL SYLLABLE SSWING +C4CE;C4CE;110A 1171 11BD;C4CE;110A 1171 11BD; # (쓎; 쓎; 쓎; 쓎; 쓎; ) HANGUL SYLLABLE SSWIJ +C4CF;C4CF;110A 1171 11BE;C4CF;110A 1171 11BE; # (쓏; 쓏; 쓏; 쓏; 쓏; ) HANGUL SYLLABLE SSWIC +C4D0;C4D0;110A 1171 11BF;C4D0;110A 1171 11BF; # (쓐; 쓐; 쓐; 쓐; 쓐; ) HANGUL SYLLABLE SSWIK +C4D1;C4D1;110A 1171 11C0;C4D1;110A 1171 11C0; # (쓑; 쓑; 쓑; 쓑; 쓑; ) HANGUL SYLLABLE SSWIT +C4D2;C4D2;110A 1171 11C1;C4D2;110A 1171 11C1; # (쓒; 쓒; 쓒; 쓒; 쓒; ) HANGUL SYLLABLE SSWIP +C4D3;C4D3;110A 1171 11C2;C4D3;110A 1171 11C2; # (쓓; 쓓; 쓓; 쓓; 쓓; ) HANGUL SYLLABLE SSWIH +C4D4;C4D4;110A 1172;C4D4;110A 1172; # (쓔; 쓔; 쓔; 쓔; 쓔; ) HANGUL SYLLABLE SSYU +C4D5;C4D5;110A 1172 11A8;C4D5;110A 1172 11A8; # (쓕; 쓕; 쓕; 쓕; 쓕; ) HANGUL SYLLABLE SSYUG +C4D6;C4D6;110A 1172 11A9;C4D6;110A 1172 11A9; # (쓖; 쓖; 쓖; 쓖; 쓖; ) HANGUL SYLLABLE SSYUGG +C4D7;C4D7;110A 1172 11AA;C4D7;110A 1172 11AA; # (쓗; 쓗; 쓗; 쓗; 쓗; ) HANGUL SYLLABLE SSYUGS +C4D8;C4D8;110A 1172 11AB;C4D8;110A 1172 11AB; # (쓘; 쓘; 쓘; 쓘; 쓘; ) HANGUL SYLLABLE SSYUN +C4D9;C4D9;110A 1172 11AC;C4D9;110A 1172 11AC; # (쓙; 쓙; 쓙; 쓙; 쓙; ) HANGUL SYLLABLE SSYUNJ +C4DA;C4DA;110A 1172 11AD;C4DA;110A 1172 11AD; # (쓚; 쓚; 쓚; 쓚; 쓚; ) HANGUL SYLLABLE SSYUNH +C4DB;C4DB;110A 1172 11AE;C4DB;110A 1172 11AE; # (쓛; 쓛; 쓛; 쓛; 쓛; ) HANGUL SYLLABLE SSYUD +C4DC;C4DC;110A 1172 11AF;C4DC;110A 1172 11AF; # (쓜; 쓜; 쓜; 쓜; 쓜; ) HANGUL SYLLABLE SSYUL +C4DD;C4DD;110A 1172 11B0;C4DD;110A 1172 11B0; # (쓝; 쓝; 쓝; 쓝; 쓝; ) HANGUL SYLLABLE SSYULG +C4DE;C4DE;110A 1172 11B1;C4DE;110A 1172 11B1; # (쓞; 쓞; 쓞; 쓞; 쓞; ) HANGUL SYLLABLE SSYULM +C4DF;C4DF;110A 1172 11B2;C4DF;110A 1172 11B2; # (쓟; 쓟; 쓟; 쓟; 쓟; ) HANGUL SYLLABLE SSYULB +C4E0;C4E0;110A 1172 11B3;C4E0;110A 1172 11B3; # (쓠; 쓠; 쓠; 쓠; 쓠; ) HANGUL SYLLABLE SSYULS +C4E1;C4E1;110A 1172 11B4;C4E1;110A 1172 11B4; # (쓡; 쓡; 쓡; 쓡; 쓡; ) HANGUL SYLLABLE SSYULT +C4E2;C4E2;110A 1172 11B5;C4E2;110A 1172 11B5; # (쓢; 쓢; 쓢; 쓢; 쓢; ) HANGUL SYLLABLE SSYULP +C4E3;C4E3;110A 1172 11B6;C4E3;110A 1172 11B6; # (쓣; 쓣; 쓣; 쓣; 쓣; ) HANGUL SYLLABLE SSYULH +C4E4;C4E4;110A 1172 11B7;C4E4;110A 1172 11B7; # (쓤; 쓤; 쓤; 쓤; 쓤; ) HANGUL SYLLABLE SSYUM +C4E5;C4E5;110A 1172 11B8;C4E5;110A 1172 11B8; # (쓥; 쓥; 쓥; 쓥; 쓥; ) HANGUL SYLLABLE SSYUB +C4E6;C4E6;110A 1172 11B9;C4E6;110A 1172 11B9; # (쓦; 쓦; 쓦; 쓦; 쓦; ) HANGUL SYLLABLE SSYUBS +C4E7;C4E7;110A 1172 11BA;C4E7;110A 1172 11BA; # (쓧; 쓧; 쓧; 쓧; 쓧; ) HANGUL SYLLABLE SSYUS +C4E8;C4E8;110A 1172 11BB;C4E8;110A 1172 11BB; # (쓨; 쓨; 쓨; 쓨; 쓨; ) HANGUL SYLLABLE SSYUSS +C4E9;C4E9;110A 1172 11BC;C4E9;110A 1172 11BC; # (쓩; 쓩; 쓩; 쓩; 쓩; ) HANGUL SYLLABLE SSYUNG +C4EA;C4EA;110A 1172 11BD;C4EA;110A 1172 11BD; # (쓪; 쓪; 쓪; 쓪; 쓪; ) HANGUL SYLLABLE SSYUJ +C4EB;C4EB;110A 1172 11BE;C4EB;110A 1172 11BE; # (쓫; 쓫; 쓫; 쓫; 쓫; ) HANGUL SYLLABLE SSYUC +C4EC;C4EC;110A 1172 11BF;C4EC;110A 1172 11BF; # (쓬; 쓬; 쓬; 쓬; 쓬; ) HANGUL SYLLABLE SSYUK +C4ED;C4ED;110A 1172 11C0;C4ED;110A 1172 11C0; # (쓭; 쓭; 쓭; 쓭; 쓭; ) HANGUL SYLLABLE SSYUT +C4EE;C4EE;110A 1172 11C1;C4EE;110A 1172 11C1; # (쓮; 쓮; 쓮; 쓮; 쓮; ) HANGUL SYLLABLE SSYUP +C4EF;C4EF;110A 1172 11C2;C4EF;110A 1172 11C2; # (쓯; 쓯; 쓯; 쓯; 쓯; ) HANGUL SYLLABLE SSYUH +C4F0;C4F0;110A 1173;C4F0;110A 1173; # (쓰; 쓰; 쓰; 쓰; 쓰; ) HANGUL SYLLABLE SSEU +C4F1;C4F1;110A 1173 11A8;C4F1;110A 1173 11A8; # (쓱; 쓱; 쓱; 쓱; 쓱; ) HANGUL SYLLABLE SSEUG +C4F2;C4F2;110A 1173 11A9;C4F2;110A 1173 11A9; # (쓲; 쓲; 쓲; 쓲; 쓲; ) HANGUL SYLLABLE SSEUGG +C4F3;C4F3;110A 1173 11AA;C4F3;110A 1173 11AA; # (쓳; 쓳; 쓳; 쓳; 쓳; ) HANGUL SYLLABLE SSEUGS +C4F4;C4F4;110A 1173 11AB;C4F4;110A 1173 11AB; # (쓴; 쓴; 쓴; 쓴; 쓴; ) HANGUL SYLLABLE SSEUN +C4F5;C4F5;110A 1173 11AC;C4F5;110A 1173 11AC; # (쓵; 쓵; 쓵; 쓵; 쓵; ) HANGUL SYLLABLE SSEUNJ +C4F6;C4F6;110A 1173 11AD;C4F6;110A 1173 11AD; # (쓶; 쓶; 쓶; 쓶; 쓶; ) HANGUL SYLLABLE SSEUNH +C4F7;C4F7;110A 1173 11AE;C4F7;110A 1173 11AE; # (쓷; 쓷; 쓷; 쓷; 쓷; ) HANGUL SYLLABLE SSEUD +C4F8;C4F8;110A 1173 11AF;C4F8;110A 1173 11AF; # (쓸; 쓸; 쓸; 쓸; 쓸; ) HANGUL SYLLABLE SSEUL +C4F9;C4F9;110A 1173 11B0;C4F9;110A 1173 11B0; # (쓹; 쓹; 쓹; 쓹; 쓹; ) HANGUL SYLLABLE SSEULG +C4FA;C4FA;110A 1173 11B1;C4FA;110A 1173 11B1; # (쓺; 쓺; 쓺; 쓺; 쓺; ) HANGUL SYLLABLE SSEULM +C4FB;C4FB;110A 1173 11B2;C4FB;110A 1173 11B2; # (쓻; 쓻; 쓻; 쓻; 쓻; ) HANGUL SYLLABLE SSEULB +C4FC;C4FC;110A 1173 11B3;C4FC;110A 1173 11B3; # (쓼; 쓼; 쓼; 쓼; 쓼; ) HANGUL SYLLABLE SSEULS +C4FD;C4FD;110A 1173 11B4;C4FD;110A 1173 11B4; # (쓽; 쓽; 쓽; 쓽; 쓽; ) HANGUL SYLLABLE SSEULT +C4FE;C4FE;110A 1173 11B5;C4FE;110A 1173 11B5; # (쓾; 쓾; 쓾; 쓾; 쓾; ) HANGUL SYLLABLE SSEULP +C4FF;C4FF;110A 1173 11B6;C4FF;110A 1173 11B6; # (쓿; 쓿; 쓿; 쓿; 쓿; ) HANGUL SYLLABLE SSEULH +C500;C500;110A 1173 11B7;C500;110A 1173 11B7; # (씀; 씀; 씀; 씀; 씀; ) HANGUL SYLLABLE SSEUM +C501;C501;110A 1173 11B8;C501;110A 1173 11B8; # (씁; 씁; 씁; 씁; 씁; ) HANGUL SYLLABLE SSEUB +C502;C502;110A 1173 11B9;C502;110A 1173 11B9; # (씂; 씂; 씂; 씂; 씂; ) HANGUL SYLLABLE SSEUBS +C503;C503;110A 1173 11BA;C503;110A 1173 11BA; # (씃; 씃; 씃; 씃; 씃; ) HANGUL SYLLABLE SSEUS +C504;C504;110A 1173 11BB;C504;110A 1173 11BB; # (씄; 씄; 씄; 씄; 씄; ) HANGUL SYLLABLE SSEUSS +C505;C505;110A 1173 11BC;C505;110A 1173 11BC; # (씅; 씅; 씅; 씅; 씅; ) HANGUL SYLLABLE SSEUNG +C506;C506;110A 1173 11BD;C506;110A 1173 11BD; # (씆; 씆; 씆; 씆; 씆; ) HANGUL SYLLABLE SSEUJ +C507;C507;110A 1173 11BE;C507;110A 1173 11BE; # (씇; 씇; 씇; 씇; 씇; ) HANGUL SYLLABLE SSEUC +C508;C508;110A 1173 11BF;C508;110A 1173 11BF; # (씈; 씈; 씈; 씈; 씈; ) HANGUL SYLLABLE SSEUK +C509;C509;110A 1173 11C0;C509;110A 1173 11C0; # (씉; 씉; 씉; 씉; 씉; ) HANGUL SYLLABLE SSEUT +C50A;C50A;110A 1173 11C1;C50A;110A 1173 11C1; # (씊; 씊; 씊; 씊; 씊; ) HANGUL SYLLABLE SSEUP +C50B;C50B;110A 1173 11C2;C50B;110A 1173 11C2; # (씋; 씋; 씋; 씋; 씋; ) HANGUL SYLLABLE SSEUH +C50C;C50C;110A 1174;C50C;110A 1174; # (씌; 씌; 씌; 씌; 씌; ) HANGUL SYLLABLE SSYI +C50D;C50D;110A 1174 11A8;C50D;110A 1174 11A8; # (씍; 씍; 씍; 씍; 씍; ) HANGUL SYLLABLE SSYIG +C50E;C50E;110A 1174 11A9;C50E;110A 1174 11A9; # (씎; 씎; 씎; 씎; 씎; ) HANGUL SYLLABLE SSYIGG +C50F;C50F;110A 1174 11AA;C50F;110A 1174 11AA; # (씏; 씏; 씏; 씏; 씏; ) HANGUL SYLLABLE SSYIGS +C510;C510;110A 1174 11AB;C510;110A 1174 11AB; # (씐; 씐; 씐; 씐; 씐; ) HANGUL SYLLABLE SSYIN +C511;C511;110A 1174 11AC;C511;110A 1174 11AC; # (씑; 씑; 씑; 씑; 씑; ) HANGUL SYLLABLE SSYINJ +C512;C512;110A 1174 11AD;C512;110A 1174 11AD; # (씒; 씒; 씒; 씒; 씒; ) HANGUL SYLLABLE SSYINH +C513;C513;110A 1174 11AE;C513;110A 1174 11AE; # (씓; 씓; 씓; 씓; 씓; ) HANGUL SYLLABLE SSYID +C514;C514;110A 1174 11AF;C514;110A 1174 11AF; # (씔; 씔; 씔; 씔; 씔; ) HANGUL SYLLABLE SSYIL +C515;C515;110A 1174 11B0;C515;110A 1174 11B0; # (씕; 씕; 씕; 씕; 씕; ) HANGUL SYLLABLE SSYILG +C516;C516;110A 1174 11B1;C516;110A 1174 11B1; # (씖; 씖; 씖; 씖; 씖; ) HANGUL SYLLABLE SSYILM +C517;C517;110A 1174 11B2;C517;110A 1174 11B2; # (씗; 씗; 씗; 씗; 씗; ) HANGUL SYLLABLE SSYILB +C518;C518;110A 1174 11B3;C518;110A 1174 11B3; # (씘; 씘; 씘; 씘; 씘; ) HANGUL SYLLABLE SSYILS +C519;C519;110A 1174 11B4;C519;110A 1174 11B4; # (씙; 씙; 씙; 씙; 씙; ) HANGUL SYLLABLE SSYILT +C51A;C51A;110A 1174 11B5;C51A;110A 1174 11B5; # (씚; 씚; 씚; 씚; 씚; ) HANGUL SYLLABLE SSYILP +C51B;C51B;110A 1174 11B6;C51B;110A 1174 11B6; # (씛; 씛; 씛; 씛; 씛; ) HANGUL SYLLABLE SSYILH +C51C;C51C;110A 1174 11B7;C51C;110A 1174 11B7; # (씜; 씜; 씜; 씜; 씜; ) HANGUL SYLLABLE SSYIM +C51D;C51D;110A 1174 11B8;C51D;110A 1174 11B8; # (씝; 씝; 씝; 씝; 씝; ) HANGUL SYLLABLE SSYIB +C51E;C51E;110A 1174 11B9;C51E;110A 1174 11B9; # (씞; 씞; 씞; 씞; 씞; ) HANGUL SYLLABLE SSYIBS +C51F;C51F;110A 1174 11BA;C51F;110A 1174 11BA; # (씟; 씟; 씟; 씟; 씟; ) HANGUL SYLLABLE SSYIS +C520;C520;110A 1174 11BB;C520;110A 1174 11BB; # (씠; 씠; 씠; 씠; 씠; ) HANGUL SYLLABLE SSYISS +C521;C521;110A 1174 11BC;C521;110A 1174 11BC; # (씡; 씡; 씡; 씡; 씡; ) HANGUL SYLLABLE SSYING +C522;C522;110A 1174 11BD;C522;110A 1174 11BD; # (씢; 씢; 씢; 씢; 씢; ) HANGUL SYLLABLE SSYIJ +C523;C523;110A 1174 11BE;C523;110A 1174 11BE; # (씣; 씣; 씣; 씣; 씣; ) HANGUL SYLLABLE SSYIC +C524;C524;110A 1174 11BF;C524;110A 1174 11BF; # (씤; 씤; 씤; 씤; 씤; ) HANGUL SYLLABLE SSYIK +C525;C525;110A 1174 11C0;C525;110A 1174 11C0; # (씥; 씥; 씥; 씥; 씥; ) HANGUL SYLLABLE SSYIT +C526;C526;110A 1174 11C1;C526;110A 1174 11C1; # (씦; 씦; 씦; 씦; 씦; ) HANGUL SYLLABLE SSYIP +C527;C527;110A 1174 11C2;C527;110A 1174 11C2; # (씧; 씧; 씧; 씧; 씧; ) HANGUL SYLLABLE SSYIH +C528;C528;110A 1175;C528;110A 1175; # (씨; 씨; 씨; 씨; 씨; ) HANGUL SYLLABLE SSI +C529;C529;110A 1175 11A8;C529;110A 1175 11A8; # (씩; 씩; 씩; 씩; 씩; ) HANGUL SYLLABLE SSIG +C52A;C52A;110A 1175 11A9;C52A;110A 1175 11A9; # (씪; 씪; 씪; 씪; 씪; ) HANGUL SYLLABLE SSIGG +C52B;C52B;110A 1175 11AA;C52B;110A 1175 11AA; # (씫; 씫; 씫; 씫; 씫; ) HANGUL SYLLABLE SSIGS +C52C;C52C;110A 1175 11AB;C52C;110A 1175 11AB; # (씬; 씬; 씬; 씬; 씬; ) HANGUL SYLLABLE SSIN +C52D;C52D;110A 1175 11AC;C52D;110A 1175 11AC; # (씭; 씭; 씭; 씭; 씭; ) HANGUL SYLLABLE SSINJ +C52E;C52E;110A 1175 11AD;C52E;110A 1175 11AD; # (씮; 씮; 씮; 씮; 씮; ) HANGUL SYLLABLE SSINH +C52F;C52F;110A 1175 11AE;C52F;110A 1175 11AE; # (씯; 씯; 씯; 씯; 씯; ) HANGUL SYLLABLE SSID +C530;C530;110A 1175 11AF;C530;110A 1175 11AF; # (씰; 씰; 씰; 씰; 씰; ) HANGUL SYLLABLE SSIL +C531;C531;110A 1175 11B0;C531;110A 1175 11B0; # (씱; 씱; 씱; 씱; 씱; ) HANGUL SYLLABLE SSILG +C532;C532;110A 1175 11B1;C532;110A 1175 11B1; # (씲; 씲; 씲; 씲; 씲; ) HANGUL SYLLABLE SSILM +C533;C533;110A 1175 11B2;C533;110A 1175 11B2; # (씳; 씳; 씳; 씳; 씳; ) HANGUL SYLLABLE SSILB +C534;C534;110A 1175 11B3;C534;110A 1175 11B3; # (씴; 씴; 씴; 씴; 씴; ) HANGUL SYLLABLE SSILS +C535;C535;110A 1175 11B4;C535;110A 1175 11B4; # (씵; 씵; 씵; 씵; 씵; ) HANGUL SYLLABLE SSILT +C536;C536;110A 1175 11B5;C536;110A 1175 11B5; # (씶; 씶; 씶; 씶; 씶; ) HANGUL SYLLABLE SSILP +C537;C537;110A 1175 11B6;C537;110A 1175 11B6; # (씷; 씷; 씷; 씷; 씷; ) HANGUL SYLLABLE SSILH +C538;C538;110A 1175 11B7;C538;110A 1175 11B7; # (씸; 씸; 씸; 씸; 씸; ) HANGUL SYLLABLE SSIM +C539;C539;110A 1175 11B8;C539;110A 1175 11B8; # (씹; 씹; 씹; 씹; 씹; ) HANGUL SYLLABLE SSIB +C53A;C53A;110A 1175 11B9;C53A;110A 1175 11B9; # (씺; 씺; 씺; 씺; 씺; ) HANGUL SYLLABLE SSIBS +C53B;C53B;110A 1175 11BA;C53B;110A 1175 11BA; # (씻; 씻; 씻; 씻; 씻; ) HANGUL SYLLABLE SSIS +C53C;C53C;110A 1175 11BB;C53C;110A 1175 11BB; # (씼; 씼; 씼; 씼; 씼; ) HANGUL SYLLABLE SSISS +C53D;C53D;110A 1175 11BC;C53D;110A 1175 11BC; # (씽; 씽; 씽; 씽; 씽; ) HANGUL SYLLABLE SSING +C53E;C53E;110A 1175 11BD;C53E;110A 1175 11BD; # (씾; 씾; 씾; 씾; 씾; ) HANGUL SYLLABLE SSIJ +C53F;C53F;110A 1175 11BE;C53F;110A 1175 11BE; # (씿; 씿; 씿; 씿; 씿; ) HANGUL SYLLABLE SSIC +C540;C540;110A 1175 11BF;C540;110A 1175 11BF; # (앀; 앀; 앀; 앀; 앀; ) HANGUL SYLLABLE SSIK +C541;C541;110A 1175 11C0;C541;110A 1175 11C0; # (앁; 앁; 앁; 앁; 앁; ) HANGUL SYLLABLE SSIT +C542;C542;110A 1175 11C1;C542;110A 1175 11C1; # (앂; 앂; 앂; 앂; 앂; ) HANGUL SYLLABLE SSIP +C543;C543;110A 1175 11C2;C543;110A 1175 11C2; # (앃; 앃; 앃; 앃; 앃; ) HANGUL SYLLABLE SSIH +C544;C544;110B 1161;C544;110B 1161; # (아; 아; 아; 아; 아; ) HANGUL SYLLABLE A +C545;C545;110B 1161 11A8;C545;110B 1161 11A8; # (악; 악; 악; 악; 악; ) HANGUL SYLLABLE AG +C546;C546;110B 1161 11A9;C546;110B 1161 11A9; # (앆; 앆; 앆; 앆; 앆; ) HANGUL SYLLABLE AGG +C547;C547;110B 1161 11AA;C547;110B 1161 11AA; # (앇; 앇; 앇; 앇; 앇; ) HANGUL SYLLABLE AGS +C548;C548;110B 1161 11AB;C548;110B 1161 11AB; # (안; 안; 안; 안; 안; ) HANGUL SYLLABLE AN +C549;C549;110B 1161 11AC;C549;110B 1161 11AC; # (앉; 앉; 앉; 앉; 앉; ) HANGUL SYLLABLE ANJ +C54A;C54A;110B 1161 11AD;C54A;110B 1161 11AD; # (않; 않; 않; 않; 않; ) HANGUL SYLLABLE ANH +C54B;C54B;110B 1161 11AE;C54B;110B 1161 11AE; # (앋; 앋; 앋; 앋; 앋; ) HANGUL SYLLABLE AD +C54C;C54C;110B 1161 11AF;C54C;110B 1161 11AF; # (알; 알; 알; 알; 알; ) HANGUL SYLLABLE AL +C54D;C54D;110B 1161 11B0;C54D;110B 1161 11B0; # (앍; 앍; 앍; 앍; 앍; ) HANGUL SYLLABLE ALG +C54E;C54E;110B 1161 11B1;C54E;110B 1161 11B1; # (앎; 앎; 앎; 앎; 앎; ) HANGUL SYLLABLE ALM +C54F;C54F;110B 1161 11B2;C54F;110B 1161 11B2; # (앏; 앏; 앏; 앏; 앏; ) HANGUL SYLLABLE ALB +C550;C550;110B 1161 11B3;C550;110B 1161 11B3; # (앐; 앐; 앐; 앐; 앐; ) HANGUL SYLLABLE ALS +C551;C551;110B 1161 11B4;C551;110B 1161 11B4; # (앑; 앑; 앑; 앑; 앑; ) HANGUL SYLLABLE ALT +C552;C552;110B 1161 11B5;C552;110B 1161 11B5; # (앒; 앒; 앒; 앒; 앒; ) HANGUL SYLLABLE ALP +C553;C553;110B 1161 11B6;C553;110B 1161 11B6; # (앓; 앓; 앓; 앓; 앓; ) HANGUL SYLLABLE ALH +C554;C554;110B 1161 11B7;C554;110B 1161 11B7; # (암; 암; 암; 암; 암; ) HANGUL SYLLABLE AM +C555;C555;110B 1161 11B8;C555;110B 1161 11B8; # (압; 압; 압; 압; 압; ) HANGUL SYLLABLE AB +C556;C556;110B 1161 11B9;C556;110B 1161 11B9; # (앖; 앖; 앖; 앖; 앖; ) HANGUL SYLLABLE ABS +C557;C557;110B 1161 11BA;C557;110B 1161 11BA; # (앗; 앗; 앗; 앗; 앗; ) HANGUL SYLLABLE AS +C558;C558;110B 1161 11BB;C558;110B 1161 11BB; # (았; 았; 았; 았; 았; ) HANGUL SYLLABLE ASS +C559;C559;110B 1161 11BC;C559;110B 1161 11BC; # (앙; 앙; 앙; 앙; 앙; ) HANGUL SYLLABLE ANG +C55A;C55A;110B 1161 11BD;C55A;110B 1161 11BD; # (앚; 앚; 앚; 앚; 앚; ) HANGUL SYLLABLE AJ +C55B;C55B;110B 1161 11BE;C55B;110B 1161 11BE; # (앛; 앛; 앛; 앛; 앛; ) HANGUL SYLLABLE AC +C55C;C55C;110B 1161 11BF;C55C;110B 1161 11BF; # (앜; 앜; 앜; 앜; 앜; ) HANGUL SYLLABLE AK +C55D;C55D;110B 1161 11C0;C55D;110B 1161 11C0; # (앝; 앝; 앝; 앝; 앝; ) HANGUL SYLLABLE AT +C55E;C55E;110B 1161 11C1;C55E;110B 1161 11C1; # (앞; 앞; 앞; 앞; 앞; ) HANGUL SYLLABLE AP +C55F;C55F;110B 1161 11C2;C55F;110B 1161 11C2; # (앟; 앟; 앟; 앟; 앟; ) HANGUL SYLLABLE AH +C560;C560;110B 1162;C560;110B 1162; # (애; 애; 애; 애; 애; ) HANGUL SYLLABLE AE +C561;C561;110B 1162 11A8;C561;110B 1162 11A8; # (액; 액; 액; 액; 액; ) HANGUL SYLLABLE AEG +C562;C562;110B 1162 11A9;C562;110B 1162 11A9; # (앢; 앢; 앢; 앢; 앢; ) HANGUL SYLLABLE AEGG +C563;C563;110B 1162 11AA;C563;110B 1162 11AA; # (앣; 앣; 앣; 앣; 앣; ) HANGUL SYLLABLE AEGS +C564;C564;110B 1162 11AB;C564;110B 1162 11AB; # (앤; 앤; 앤; 앤; 앤; ) HANGUL SYLLABLE AEN +C565;C565;110B 1162 11AC;C565;110B 1162 11AC; # (앥; 앥; 앥; 앥; 앥; ) HANGUL SYLLABLE AENJ +C566;C566;110B 1162 11AD;C566;110B 1162 11AD; # (앦; 앦; 앦; 앦; 앦; ) HANGUL SYLLABLE AENH +C567;C567;110B 1162 11AE;C567;110B 1162 11AE; # (앧; 앧; 앧; 앧; 앧; ) HANGUL SYLLABLE AED +C568;C568;110B 1162 11AF;C568;110B 1162 11AF; # (앨; 앨; 앨; 앨; 앨; ) HANGUL SYLLABLE AEL +C569;C569;110B 1162 11B0;C569;110B 1162 11B0; # (앩; 앩; 앩; 앩; 앩; ) HANGUL SYLLABLE AELG +C56A;C56A;110B 1162 11B1;C56A;110B 1162 11B1; # (앪; 앪; 앪; 앪; 앪; ) HANGUL SYLLABLE AELM +C56B;C56B;110B 1162 11B2;C56B;110B 1162 11B2; # (앫; 앫; 앫; 앫; 앫; ) HANGUL SYLLABLE AELB +C56C;C56C;110B 1162 11B3;C56C;110B 1162 11B3; # (앬; 앬; 앬; 앬; 앬; ) HANGUL SYLLABLE AELS +C56D;C56D;110B 1162 11B4;C56D;110B 1162 11B4; # (앭; 앭; 앭; 앭; 앭; ) HANGUL SYLLABLE AELT +C56E;C56E;110B 1162 11B5;C56E;110B 1162 11B5; # (앮; 앮; 앮; 앮; 앮; ) HANGUL SYLLABLE AELP +C56F;C56F;110B 1162 11B6;C56F;110B 1162 11B6; # (앯; 앯; 앯; 앯; 앯; ) HANGUL SYLLABLE AELH +C570;C570;110B 1162 11B7;C570;110B 1162 11B7; # (앰; 앰; 앰; 앰; 앰; ) HANGUL SYLLABLE AEM +C571;C571;110B 1162 11B8;C571;110B 1162 11B8; # (앱; 앱; 앱; 앱; 앱; ) HANGUL SYLLABLE AEB +C572;C572;110B 1162 11B9;C572;110B 1162 11B9; # (앲; 앲; 앲; 앲; 앲; ) HANGUL SYLLABLE AEBS +C573;C573;110B 1162 11BA;C573;110B 1162 11BA; # (앳; 앳; 앳; 앳; 앳; ) HANGUL SYLLABLE AES +C574;C574;110B 1162 11BB;C574;110B 1162 11BB; # (앴; 앴; 앴; 앴; 앴; ) HANGUL SYLLABLE AESS +C575;C575;110B 1162 11BC;C575;110B 1162 11BC; # (앵; 앵; 앵; 앵; 앵; ) HANGUL SYLLABLE AENG +C576;C576;110B 1162 11BD;C576;110B 1162 11BD; # (앶; 앶; 앶; 앶; 앶; ) HANGUL SYLLABLE AEJ +C577;C577;110B 1162 11BE;C577;110B 1162 11BE; # (앷; 앷; 앷; 앷; 앷; ) HANGUL SYLLABLE AEC +C578;C578;110B 1162 11BF;C578;110B 1162 11BF; # (앸; 앸; 앸; 앸; 앸; ) HANGUL SYLLABLE AEK +C579;C579;110B 1162 11C0;C579;110B 1162 11C0; # (앹; 앹; 앹; 앹; 앹; ) HANGUL SYLLABLE AET +C57A;C57A;110B 1162 11C1;C57A;110B 1162 11C1; # (앺; 앺; 앺; 앺; 앺; ) HANGUL SYLLABLE AEP +C57B;C57B;110B 1162 11C2;C57B;110B 1162 11C2; # (앻; 앻; 앻; 앻; 앻; ) HANGUL SYLLABLE AEH +C57C;C57C;110B 1163;C57C;110B 1163; # (야; 야; 야; 야; 야; ) HANGUL SYLLABLE YA +C57D;C57D;110B 1163 11A8;C57D;110B 1163 11A8; # (약; 약; 약; 약; 약; ) HANGUL SYLLABLE YAG +C57E;C57E;110B 1163 11A9;C57E;110B 1163 11A9; # (앾; 앾; 앾; 앾; 앾; ) HANGUL SYLLABLE YAGG +C57F;C57F;110B 1163 11AA;C57F;110B 1163 11AA; # (앿; 앿; 앿; 앿; 앿; ) HANGUL SYLLABLE YAGS +C580;C580;110B 1163 11AB;C580;110B 1163 11AB; # (얀; 얀; 얀; 얀; 얀; ) HANGUL SYLLABLE YAN +C581;C581;110B 1163 11AC;C581;110B 1163 11AC; # (얁; 얁; 얁; 얁; 얁; ) HANGUL SYLLABLE YANJ +C582;C582;110B 1163 11AD;C582;110B 1163 11AD; # (얂; 얂; 얂; 얂; 얂; ) HANGUL SYLLABLE YANH +C583;C583;110B 1163 11AE;C583;110B 1163 11AE; # (얃; 얃; 얃; 얃; 얃; ) HANGUL SYLLABLE YAD +C584;C584;110B 1163 11AF;C584;110B 1163 11AF; # (얄; 얄; 얄; 얄; 얄; ) HANGUL SYLLABLE YAL +C585;C585;110B 1163 11B0;C585;110B 1163 11B0; # (얅; 얅; 얅; 얅; 얅; ) HANGUL SYLLABLE YALG +C586;C586;110B 1163 11B1;C586;110B 1163 11B1; # (얆; 얆; 얆; 얆; 얆; ) HANGUL SYLLABLE YALM +C587;C587;110B 1163 11B2;C587;110B 1163 11B2; # (얇; 얇; 얇; 얇; 얇; ) HANGUL SYLLABLE YALB +C588;C588;110B 1163 11B3;C588;110B 1163 11B3; # (얈; 얈; 얈; 얈; 얈; ) HANGUL SYLLABLE YALS +C589;C589;110B 1163 11B4;C589;110B 1163 11B4; # (얉; 얉; 얉; 얉; 얉; ) HANGUL SYLLABLE YALT +C58A;C58A;110B 1163 11B5;C58A;110B 1163 11B5; # (얊; 얊; 얊; 얊; 얊; ) HANGUL SYLLABLE YALP +C58B;C58B;110B 1163 11B6;C58B;110B 1163 11B6; # (얋; 얋; 얋; 얋; 얋; ) HANGUL SYLLABLE YALH +C58C;C58C;110B 1163 11B7;C58C;110B 1163 11B7; # (얌; 얌; 얌; 얌; 얌; ) HANGUL SYLLABLE YAM +C58D;C58D;110B 1163 11B8;C58D;110B 1163 11B8; # (얍; 얍; 얍; 얍; 얍; ) HANGUL SYLLABLE YAB +C58E;C58E;110B 1163 11B9;C58E;110B 1163 11B9; # (얎; 얎; 얎; 얎; 얎; ) HANGUL SYLLABLE YABS +C58F;C58F;110B 1163 11BA;C58F;110B 1163 11BA; # (얏; 얏; 얏; 얏; 얏; ) HANGUL SYLLABLE YAS +C590;C590;110B 1163 11BB;C590;110B 1163 11BB; # (얐; 얐; 얐; 얐; 얐; ) HANGUL SYLLABLE YASS +C591;C591;110B 1163 11BC;C591;110B 1163 11BC; # (양; 양; 양; 양; 양; ) HANGUL SYLLABLE YANG +C592;C592;110B 1163 11BD;C592;110B 1163 11BD; # (얒; 얒; 얒; 얒; 얒; ) HANGUL SYLLABLE YAJ +C593;C593;110B 1163 11BE;C593;110B 1163 11BE; # (얓; 얓; 얓; 얓; 얓; ) HANGUL SYLLABLE YAC +C594;C594;110B 1163 11BF;C594;110B 1163 11BF; # (얔; 얔; 얔; 얔; 얔; ) HANGUL SYLLABLE YAK +C595;C595;110B 1163 11C0;C595;110B 1163 11C0; # (얕; 얕; 얕; 얕; 얕; ) HANGUL SYLLABLE YAT +C596;C596;110B 1163 11C1;C596;110B 1163 11C1; # (얖; 얖; 얖; 얖; 얖; ) HANGUL SYLLABLE YAP +C597;C597;110B 1163 11C2;C597;110B 1163 11C2; # (얗; 얗; 얗; 얗; 얗; ) HANGUL SYLLABLE YAH +C598;C598;110B 1164;C598;110B 1164; # (얘; 얘; 얘; 얘; 얘; ) HANGUL SYLLABLE YAE +C599;C599;110B 1164 11A8;C599;110B 1164 11A8; # (얙; 얙; 얙; 얙; 얙; ) HANGUL SYLLABLE YAEG +C59A;C59A;110B 1164 11A9;C59A;110B 1164 11A9; # (얚; 얚; 얚; 얚; 얚; ) HANGUL SYLLABLE YAEGG +C59B;C59B;110B 1164 11AA;C59B;110B 1164 11AA; # (얛; 얛; 얛; 얛; 얛; ) HANGUL SYLLABLE YAEGS +C59C;C59C;110B 1164 11AB;C59C;110B 1164 11AB; # (얜; 얜; 얜; 얜; 얜; ) HANGUL SYLLABLE YAEN +C59D;C59D;110B 1164 11AC;C59D;110B 1164 11AC; # (얝; 얝; 얝; 얝; 얝; ) HANGUL SYLLABLE YAENJ +C59E;C59E;110B 1164 11AD;C59E;110B 1164 11AD; # (얞; 얞; 얞; 얞; 얞; ) HANGUL SYLLABLE YAENH +C59F;C59F;110B 1164 11AE;C59F;110B 1164 11AE; # (얟; 얟; 얟; 얟; 얟; ) HANGUL SYLLABLE YAED +C5A0;C5A0;110B 1164 11AF;C5A0;110B 1164 11AF; # (얠; 얠; 얠; 얠; 얠; ) HANGUL SYLLABLE YAEL +C5A1;C5A1;110B 1164 11B0;C5A1;110B 1164 11B0; # (얡; 얡; 얡; 얡; 얡; ) HANGUL SYLLABLE YAELG +C5A2;C5A2;110B 1164 11B1;C5A2;110B 1164 11B1; # (얢; 얢; 얢; 얢; 얢; ) HANGUL SYLLABLE YAELM +C5A3;C5A3;110B 1164 11B2;C5A3;110B 1164 11B2; # (얣; 얣; 얣; 얣; 얣; ) HANGUL SYLLABLE YAELB +C5A4;C5A4;110B 1164 11B3;C5A4;110B 1164 11B3; # (얤; 얤; 얤; 얤; 얤; ) HANGUL SYLLABLE YAELS +C5A5;C5A5;110B 1164 11B4;C5A5;110B 1164 11B4; # (얥; 얥; 얥; 얥; 얥; ) HANGUL SYLLABLE YAELT +C5A6;C5A6;110B 1164 11B5;C5A6;110B 1164 11B5; # (얦; 얦; 얦; 얦; 얦; ) HANGUL SYLLABLE YAELP +C5A7;C5A7;110B 1164 11B6;C5A7;110B 1164 11B6; # (얧; 얧; 얧; 얧; 얧; ) HANGUL SYLLABLE YAELH +C5A8;C5A8;110B 1164 11B7;C5A8;110B 1164 11B7; # (얨; 얨; 얨; 얨; 얨; ) HANGUL SYLLABLE YAEM +C5A9;C5A9;110B 1164 11B8;C5A9;110B 1164 11B8; # (얩; 얩; 얩; 얩; 얩; ) HANGUL SYLLABLE YAEB +C5AA;C5AA;110B 1164 11B9;C5AA;110B 1164 11B9; # (얪; 얪; 얪; 얪; 얪; ) HANGUL SYLLABLE YAEBS +C5AB;C5AB;110B 1164 11BA;C5AB;110B 1164 11BA; # (얫; 얫; 얫; 얫; 얫; ) HANGUL SYLLABLE YAES +C5AC;C5AC;110B 1164 11BB;C5AC;110B 1164 11BB; # (얬; 얬; 얬; 얬; 얬; ) HANGUL SYLLABLE YAESS +C5AD;C5AD;110B 1164 11BC;C5AD;110B 1164 11BC; # (얭; 얭; 얭; 얭; 얭; ) HANGUL SYLLABLE YAENG +C5AE;C5AE;110B 1164 11BD;C5AE;110B 1164 11BD; # (얮; 얮; 얮; 얮; 얮; ) HANGUL SYLLABLE YAEJ +C5AF;C5AF;110B 1164 11BE;C5AF;110B 1164 11BE; # (얯; 얯; 얯; 얯; 얯; ) HANGUL SYLLABLE YAEC +C5B0;C5B0;110B 1164 11BF;C5B0;110B 1164 11BF; # (얰; 얰; 얰; 얰; 얰; ) HANGUL SYLLABLE YAEK +C5B1;C5B1;110B 1164 11C0;C5B1;110B 1164 11C0; # (얱; 얱; 얱; 얱; 얱; ) HANGUL SYLLABLE YAET +C5B2;C5B2;110B 1164 11C1;C5B2;110B 1164 11C1; # (얲; 얲; 얲; 얲; 얲; ) HANGUL SYLLABLE YAEP +C5B3;C5B3;110B 1164 11C2;C5B3;110B 1164 11C2; # (얳; 얳; 얳; 얳; 얳; ) HANGUL SYLLABLE YAEH +C5B4;C5B4;110B 1165;C5B4;110B 1165; # (어; 어; 어; 어; 어; ) HANGUL SYLLABLE EO +C5B5;C5B5;110B 1165 11A8;C5B5;110B 1165 11A8; # (억; 억; 억; 억; 억; ) HANGUL SYLLABLE EOG +C5B6;C5B6;110B 1165 11A9;C5B6;110B 1165 11A9; # (얶; 얶; 얶; 얶; 얶; ) HANGUL SYLLABLE EOGG +C5B7;C5B7;110B 1165 11AA;C5B7;110B 1165 11AA; # (얷; 얷; 얷; 얷; 얷; ) HANGUL SYLLABLE EOGS +C5B8;C5B8;110B 1165 11AB;C5B8;110B 1165 11AB; # (언; 언; 언; 언; 언; ) HANGUL SYLLABLE EON +C5B9;C5B9;110B 1165 11AC;C5B9;110B 1165 11AC; # (얹; 얹; 얹; 얹; 얹; ) HANGUL SYLLABLE EONJ +C5BA;C5BA;110B 1165 11AD;C5BA;110B 1165 11AD; # (얺; 얺; 얺; 얺; 얺; ) HANGUL SYLLABLE EONH +C5BB;C5BB;110B 1165 11AE;C5BB;110B 1165 11AE; # (얻; 얻; 얻; 얻; 얻; ) HANGUL SYLLABLE EOD +C5BC;C5BC;110B 1165 11AF;C5BC;110B 1165 11AF; # (얼; 얼; 얼; 얼; 얼; ) HANGUL SYLLABLE EOL +C5BD;C5BD;110B 1165 11B0;C5BD;110B 1165 11B0; # (얽; 얽; 얽; 얽; 얽; ) HANGUL SYLLABLE EOLG +C5BE;C5BE;110B 1165 11B1;C5BE;110B 1165 11B1; # (얾; 얾; 얾; 얾; 얾; ) HANGUL SYLLABLE EOLM +C5BF;C5BF;110B 1165 11B2;C5BF;110B 1165 11B2; # (얿; 얿; 얿; 얿; 얿; ) HANGUL SYLLABLE EOLB +C5C0;C5C0;110B 1165 11B3;C5C0;110B 1165 11B3; # (엀; 엀; 엀; 엀; 엀; ) HANGUL SYLLABLE EOLS +C5C1;C5C1;110B 1165 11B4;C5C1;110B 1165 11B4; # (엁; 엁; 엁; 엁; 엁; ) HANGUL SYLLABLE EOLT +C5C2;C5C2;110B 1165 11B5;C5C2;110B 1165 11B5; # (엂; 엂; 엂; 엂; 엂; ) HANGUL SYLLABLE EOLP +C5C3;C5C3;110B 1165 11B6;C5C3;110B 1165 11B6; # (엃; 엃; 엃; 엃; 엃; ) HANGUL SYLLABLE EOLH +C5C4;C5C4;110B 1165 11B7;C5C4;110B 1165 11B7; # (엄; 엄; 엄; 엄; 엄; ) HANGUL SYLLABLE EOM +C5C5;C5C5;110B 1165 11B8;C5C5;110B 1165 11B8; # (업; 업; 업; 업; 업; ) HANGUL SYLLABLE EOB +C5C6;C5C6;110B 1165 11B9;C5C6;110B 1165 11B9; # (없; 없; 없; 없; 없; ) HANGUL SYLLABLE EOBS +C5C7;C5C7;110B 1165 11BA;C5C7;110B 1165 11BA; # (엇; 엇; 엇; 엇; 엇; ) HANGUL SYLLABLE EOS +C5C8;C5C8;110B 1165 11BB;C5C8;110B 1165 11BB; # (었; 었; 었; 었; 었; ) HANGUL SYLLABLE EOSS +C5C9;C5C9;110B 1165 11BC;C5C9;110B 1165 11BC; # (엉; 엉; 엉; 엉; 엉; ) HANGUL SYLLABLE EONG +C5CA;C5CA;110B 1165 11BD;C5CA;110B 1165 11BD; # (엊; 엊; 엊; 엊; 엊; ) HANGUL SYLLABLE EOJ +C5CB;C5CB;110B 1165 11BE;C5CB;110B 1165 11BE; # (엋; 엋; 엋; 엋; 엋; ) HANGUL SYLLABLE EOC +C5CC;C5CC;110B 1165 11BF;C5CC;110B 1165 11BF; # (엌; 엌; 엌; 엌; 엌; ) HANGUL SYLLABLE EOK +C5CD;C5CD;110B 1165 11C0;C5CD;110B 1165 11C0; # (엍; 엍; 엍; 엍; 엍; ) HANGUL SYLLABLE EOT +C5CE;C5CE;110B 1165 11C1;C5CE;110B 1165 11C1; # (엎; 엎; 엎; 엎; 엎; ) HANGUL SYLLABLE EOP +C5CF;C5CF;110B 1165 11C2;C5CF;110B 1165 11C2; # (엏; 엏; 엏; 엏; 엏; ) HANGUL SYLLABLE EOH +C5D0;C5D0;110B 1166;C5D0;110B 1166; # (에; 에; 에; 에; 에; ) HANGUL SYLLABLE E +C5D1;C5D1;110B 1166 11A8;C5D1;110B 1166 11A8; # (엑; 엑; 엑; 엑; 엑; ) HANGUL SYLLABLE EG +C5D2;C5D2;110B 1166 11A9;C5D2;110B 1166 11A9; # (엒; 엒; 엒; 엒; 엒; ) HANGUL SYLLABLE EGG +C5D3;C5D3;110B 1166 11AA;C5D3;110B 1166 11AA; # (엓; 엓; 엓; 엓; 엓; ) HANGUL SYLLABLE EGS +C5D4;C5D4;110B 1166 11AB;C5D4;110B 1166 11AB; # (엔; 엔; 엔; 엔; 엔; ) HANGUL SYLLABLE EN +C5D5;C5D5;110B 1166 11AC;C5D5;110B 1166 11AC; # (엕; 엕; 엕; 엕; 엕; ) HANGUL SYLLABLE ENJ +C5D6;C5D6;110B 1166 11AD;C5D6;110B 1166 11AD; # (엖; 엖; 엖; 엖; 엖; ) HANGUL SYLLABLE ENH +C5D7;C5D7;110B 1166 11AE;C5D7;110B 1166 11AE; # (엗; 엗; 엗; 엗; 엗; ) HANGUL SYLLABLE ED +C5D8;C5D8;110B 1166 11AF;C5D8;110B 1166 11AF; # (엘; 엘; 엘; 엘; 엘; ) HANGUL SYLLABLE EL +C5D9;C5D9;110B 1166 11B0;C5D9;110B 1166 11B0; # (엙; 엙; 엙; 엙; 엙; ) HANGUL SYLLABLE ELG +C5DA;C5DA;110B 1166 11B1;C5DA;110B 1166 11B1; # (엚; 엚; 엚; 엚; 엚; ) HANGUL SYLLABLE ELM +C5DB;C5DB;110B 1166 11B2;C5DB;110B 1166 11B2; # (엛; 엛; 엛; 엛; 엛; ) HANGUL SYLLABLE ELB +C5DC;C5DC;110B 1166 11B3;C5DC;110B 1166 11B3; # (엜; 엜; 엜; 엜; 엜; ) HANGUL SYLLABLE ELS +C5DD;C5DD;110B 1166 11B4;C5DD;110B 1166 11B4; # (엝; 엝; 엝; 엝; 엝; ) HANGUL SYLLABLE ELT +C5DE;C5DE;110B 1166 11B5;C5DE;110B 1166 11B5; # (엞; 엞; 엞; 엞; 엞; ) HANGUL SYLLABLE ELP +C5DF;C5DF;110B 1166 11B6;C5DF;110B 1166 11B6; # (엟; 엟; 엟; 엟; 엟; ) HANGUL SYLLABLE ELH +C5E0;C5E0;110B 1166 11B7;C5E0;110B 1166 11B7; # (엠; 엠; 엠; 엠; 엠; ) HANGUL SYLLABLE EM +C5E1;C5E1;110B 1166 11B8;C5E1;110B 1166 11B8; # (엡; 엡; 엡; 엡; 엡; ) HANGUL SYLLABLE EB +C5E2;C5E2;110B 1166 11B9;C5E2;110B 1166 11B9; # (엢; 엢; 엢; 엢; 엢; ) HANGUL SYLLABLE EBS +C5E3;C5E3;110B 1166 11BA;C5E3;110B 1166 11BA; # (엣; 엣; 엣; 엣; 엣; ) HANGUL SYLLABLE ES +C5E4;C5E4;110B 1166 11BB;C5E4;110B 1166 11BB; # (엤; 엤; 엤; 엤; 엤; ) HANGUL SYLLABLE ESS +C5E5;C5E5;110B 1166 11BC;C5E5;110B 1166 11BC; # (엥; 엥; 엥; 엥; 엥; ) HANGUL SYLLABLE ENG +C5E6;C5E6;110B 1166 11BD;C5E6;110B 1166 11BD; # (엦; 엦; 엦; 엦; 엦; ) HANGUL SYLLABLE EJ +C5E7;C5E7;110B 1166 11BE;C5E7;110B 1166 11BE; # (엧; 엧; 엧; 엧; 엧; ) HANGUL SYLLABLE EC +C5E8;C5E8;110B 1166 11BF;C5E8;110B 1166 11BF; # (엨; 엨; 엨; 엨; 엨; ) HANGUL SYLLABLE EK +C5E9;C5E9;110B 1166 11C0;C5E9;110B 1166 11C0; # (엩; 엩; 엩; 엩; 엩; ) HANGUL SYLLABLE ET +C5EA;C5EA;110B 1166 11C1;C5EA;110B 1166 11C1; # (엪; 엪; 엪; 엪; 엪; ) HANGUL SYLLABLE EP +C5EB;C5EB;110B 1166 11C2;C5EB;110B 1166 11C2; # (엫; 엫; 엫; 엫; 엫; ) HANGUL SYLLABLE EH +C5EC;C5EC;110B 1167;C5EC;110B 1167; # (여; 여; 여; 여; 여; ) HANGUL SYLLABLE YEO +C5ED;C5ED;110B 1167 11A8;C5ED;110B 1167 11A8; # (역; 역; 역; 역; 역; ) HANGUL SYLLABLE YEOG +C5EE;C5EE;110B 1167 11A9;C5EE;110B 1167 11A9; # (엮; 엮; 엮; 엮; 엮; ) HANGUL SYLLABLE YEOGG +C5EF;C5EF;110B 1167 11AA;C5EF;110B 1167 11AA; # (엯; 엯; 엯; 엯; 엯; ) HANGUL SYLLABLE YEOGS +C5F0;C5F0;110B 1167 11AB;C5F0;110B 1167 11AB; # (연; 연; 연; 연; 연; ) HANGUL SYLLABLE YEON +C5F1;C5F1;110B 1167 11AC;C5F1;110B 1167 11AC; # (엱; 엱; 엱; 엱; 엱; ) HANGUL SYLLABLE YEONJ +C5F2;C5F2;110B 1167 11AD;C5F2;110B 1167 11AD; # (엲; 엲; 엲; 엲; 엲; ) HANGUL SYLLABLE YEONH +C5F3;C5F3;110B 1167 11AE;C5F3;110B 1167 11AE; # (엳; 엳; 엳; 엳; 엳; ) HANGUL SYLLABLE YEOD +C5F4;C5F4;110B 1167 11AF;C5F4;110B 1167 11AF; # (열; 열; 열; 열; 열; ) HANGUL SYLLABLE YEOL +C5F5;C5F5;110B 1167 11B0;C5F5;110B 1167 11B0; # (엵; 엵; 엵; 엵; 엵; ) HANGUL SYLLABLE YEOLG +C5F6;C5F6;110B 1167 11B1;C5F6;110B 1167 11B1; # (엶; 엶; 엶; 엶; 엶; ) HANGUL SYLLABLE YEOLM +C5F7;C5F7;110B 1167 11B2;C5F7;110B 1167 11B2; # (엷; 엷; 엷; 엷; 엷; ) HANGUL SYLLABLE YEOLB +C5F8;C5F8;110B 1167 11B3;C5F8;110B 1167 11B3; # (엸; 엸; 엸; 엸; 엸; ) HANGUL SYLLABLE YEOLS +C5F9;C5F9;110B 1167 11B4;C5F9;110B 1167 11B4; # (엹; 엹; 엹; 엹; 엹; ) HANGUL SYLLABLE YEOLT +C5FA;C5FA;110B 1167 11B5;C5FA;110B 1167 11B5; # (엺; 엺; 엺; 엺; 엺; ) HANGUL SYLLABLE YEOLP +C5FB;C5FB;110B 1167 11B6;C5FB;110B 1167 11B6; # (엻; 엻; 엻; 엻; 엻; ) HANGUL SYLLABLE YEOLH +C5FC;C5FC;110B 1167 11B7;C5FC;110B 1167 11B7; # (염; 염; 염; 염; 염; ) HANGUL SYLLABLE YEOM +C5FD;C5FD;110B 1167 11B8;C5FD;110B 1167 11B8; # (엽; 엽; 엽; 엽; 엽; ) HANGUL SYLLABLE YEOB +C5FE;C5FE;110B 1167 11B9;C5FE;110B 1167 11B9; # (엾; 엾; 엾; 엾; 엾; ) HANGUL SYLLABLE YEOBS +C5FF;C5FF;110B 1167 11BA;C5FF;110B 1167 11BA; # (엿; 엿; 엿; 엿; 엿; ) HANGUL SYLLABLE YEOS +C600;C600;110B 1167 11BB;C600;110B 1167 11BB; # (였; 였; 였; 였; 였; ) HANGUL SYLLABLE YEOSS +C601;C601;110B 1167 11BC;C601;110B 1167 11BC; # (영; 영; 영; 영; 영; ) HANGUL SYLLABLE YEONG +C602;C602;110B 1167 11BD;C602;110B 1167 11BD; # (옂; 옂; 옂; 옂; 옂; ) HANGUL SYLLABLE YEOJ +C603;C603;110B 1167 11BE;C603;110B 1167 11BE; # (옃; 옃; 옃; 옃; 옃; ) HANGUL SYLLABLE YEOC +C604;C604;110B 1167 11BF;C604;110B 1167 11BF; # (옄; 옄; 옄; 옄; 옄; ) HANGUL SYLLABLE YEOK +C605;C605;110B 1167 11C0;C605;110B 1167 11C0; # (옅; 옅; 옅; 옅; 옅; ) HANGUL SYLLABLE YEOT +C606;C606;110B 1167 11C1;C606;110B 1167 11C1; # (옆; 옆; 옆; 옆; 옆; ) HANGUL SYLLABLE YEOP +C607;C607;110B 1167 11C2;C607;110B 1167 11C2; # (옇; 옇; 옇; 옇; 옇; ) HANGUL SYLLABLE YEOH +C608;C608;110B 1168;C608;110B 1168; # (예; 예; 예; 예; 예; ) HANGUL SYLLABLE YE +C609;C609;110B 1168 11A8;C609;110B 1168 11A8; # (옉; 옉; 옉; 옉; 옉; ) HANGUL SYLLABLE YEG +C60A;C60A;110B 1168 11A9;C60A;110B 1168 11A9; # (옊; 옊; 옊; 옊; 옊; ) HANGUL SYLLABLE YEGG +C60B;C60B;110B 1168 11AA;C60B;110B 1168 11AA; # (옋; 옋; 옋; 옋; 옋; ) HANGUL SYLLABLE YEGS +C60C;C60C;110B 1168 11AB;C60C;110B 1168 11AB; # (옌; 옌; 옌; 옌; 옌; ) HANGUL SYLLABLE YEN +C60D;C60D;110B 1168 11AC;C60D;110B 1168 11AC; # (옍; 옍; 옍; 옍; 옍; ) HANGUL SYLLABLE YENJ +C60E;C60E;110B 1168 11AD;C60E;110B 1168 11AD; # (옎; 옎; 옎; 옎; 옎; ) HANGUL SYLLABLE YENH +C60F;C60F;110B 1168 11AE;C60F;110B 1168 11AE; # (옏; 옏; 옏; 옏; 옏; ) HANGUL SYLLABLE YED +C610;C610;110B 1168 11AF;C610;110B 1168 11AF; # (옐; 옐; 옐; 옐; 옐; ) HANGUL SYLLABLE YEL +C611;C611;110B 1168 11B0;C611;110B 1168 11B0; # (옑; 옑; 옑; 옑; 옑; ) HANGUL SYLLABLE YELG +C612;C612;110B 1168 11B1;C612;110B 1168 11B1; # (옒; 옒; 옒; 옒; 옒; ) HANGUL SYLLABLE YELM +C613;C613;110B 1168 11B2;C613;110B 1168 11B2; # (옓; 옓; 옓; 옓; 옓; ) HANGUL SYLLABLE YELB +C614;C614;110B 1168 11B3;C614;110B 1168 11B3; # (옔; 옔; 옔; 옔; 옔; ) HANGUL SYLLABLE YELS +C615;C615;110B 1168 11B4;C615;110B 1168 11B4; # (옕; 옕; 옕; 옕; 옕; ) HANGUL SYLLABLE YELT +C616;C616;110B 1168 11B5;C616;110B 1168 11B5; # (옖; 옖; 옖; 옖; 옖; ) HANGUL SYLLABLE YELP +C617;C617;110B 1168 11B6;C617;110B 1168 11B6; # (옗; 옗; 옗; 옗; 옗; ) HANGUL SYLLABLE YELH +C618;C618;110B 1168 11B7;C618;110B 1168 11B7; # (옘; 옘; 옘; 옘; 옘; ) HANGUL SYLLABLE YEM +C619;C619;110B 1168 11B8;C619;110B 1168 11B8; # (옙; 옙; 옙; 옙; 옙; ) HANGUL SYLLABLE YEB +C61A;C61A;110B 1168 11B9;C61A;110B 1168 11B9; # (옚; 옚; 옚; 옚; 옚; ) HANGUL SYLLABLE YEBS +C61B;C61B;110B 1168 11BA;C61B;110B 1168 11BA; # (옛; 옛; 옛; 옛; 옛; ) HANGUL SYLLABLE YES +C61C;C61C;110B 1168 11BB;C61C;110B 1168 11BB; # (옜; 옜; 옜; 옜; 옜; ) HANGUL SYLLABLE YESS +C61D;C61D;110B 1168 11BC;C61D;110B 1168 11BC; # (옝; 옝; 옝; 옝; 옝; ) HANGUL SYLLABLE YENG +C61E;C61E;110B 1168 11BD;C61E;110B 1168 11BD; # (옞; 옞; 옞; 옞; 옞; ) HANGUL SYLLABLE YEJ +C61F;C61F;110B 1168 11BE;C61F;110B 1168 11BE; # (옟; 옟; 옟; 옟; 옟; ) HANGUL SYLLABLE YEC +C620;C620;110B 1168 11BF;C620;110B 1168 11BF; # (옠; 옠; 옠; 옠; 옠; ) HANGUL SYLLABLE YEK +C621;C621;110B 1168 11C0;C621;110B 1168 11C0; # (옡; 옡; 옡; 옡; 옡; ) HANGUL SYLLABLE YET +C622;C622;110B 1168 11C1;C622;110B 1168 11C1; # (옢; 옢; 옢; 옢; 옢; ) HANGUL SYLLABLE YEP +C623;C623;110B 1168 11C2;C623;110B 1168 11C2; # (옣; 옣; 옣; 옣; 옣; ) HANGUL SYLLABLE YEH +C624;C624;110B 1169;C624;110B 1169; # (오; 오; 오; 오; 오; ) HANGUL SYLLABLE O +C625;C625;110B 1169 11A8;C625;110B 1169 11A8; # (옥; 옥; 옥; 옥; 옥; ) HANGUL SYLLABLE OG +C626;C626;110B 1169 11A9;C626;110B 1169 11A9; # (옦; 옦; 옦; 옦; 옦; ) HANGUL SYLLABLE OGG +C627;C627;110B 1169 11AA;C627;110B 1169 11AA; # (옧; 옧; 옧; 옧; 옧; ) HANGUL SYLLABLE OGS +C628;C628;110B 1169 11AB;C628;110B 1169 11AB; # (온; 온; 온; 온; 온; ) HANGUL SYLLABLE ON +C629;C629;110B 1169 11AC;C629;110B 1169 11AC; # (옩; 옩; 옩; 옩; 옩; ) HANGUL SYLLABLE ONJ +C62A;C62A;110B 1169 11AD;C62A;110B 1169 11AD; # (옪; 옪; 옪; 옪; 옪; ) HANGUL SYLLABLE ONH +C62B;C62B;110B 1169 11AE;C62B;110B 1169 11AE; # (옫; 옫; 옫; 옫; 옫; ) HANGUL SYLLABLE OD +C62C;C62C;110B 1169 11AF;C62C;110B 1169 11AF; # (올; 올; 올; 올; 올; ) HANGUL SYLLABLE OL +C62D;C62D;110B 1169 11B0;C62D;110B 1169 11B0; # (옭; 옭; 옭; 옭; 옭; ) HANGUL SYLLABLE OLG +C62E;C62E;110B 1169 11B1;C62E;110B 1169 11B1; # (옮; 옮; 옮; 옮; 옮; ) HANGUL SYLLABLE OLM +C62F;C62F;110B 1169 11B2;C62F;110B 1169 11B2; # (옯; 옯; 옯; 옯; 옯; ) HANGUL SYLLABLE OLB +C630;C630;110B 1169 11B3;C630;110B 1169 11B3; # (옰; 옰; 옰; 옰; 옰; ) HANGUL SYLLABLE OLS +C631;C631;110B 1169 11B4;C631;110B 1169 11B4; # (옱; 옱; 옱; 옱; 옱; ) HANGUL SYLLABLE OLT +C632;C632;110B 1169 11B5;C632;110B 1169 11B5; # (옲; 옲; 옲; 옲; 옲; ) HANGUL SYLLABLE OLP +C633;C633;110B 1169 11B6;C633;110B 1169 11B6; # (옳; 옳; 옳; 옳; 옳; ) HANGUL SYLLABLE OLH +C634;C634;110B 1169 11B7;C634;110B 1169 11B7; # (옴; 옴; 옴; 옴; 옴; ) HANGUL SYLLABLE OM +C635;C635;110B 1169 11B8;C635;110B 1169 11B8; # (옵; 옵; 옵; 옵; 옵; ) HANGUL SYLLABLE OB +C636;C636;110B 1169 11B9;C636;110B 1169 11B9; # (옶; 옶; 옶; 옶; 옶; ) HANGUL SYLLABLE OBS +C637;C637;110B 1169 11BA;C637;110B 1169 11BA; # (옷; 옷; 옷; 옷; 옷; ) HANGUL SYLLABLE OS +C638;C638;110B 1169 11BB;C638;110B 1169 11BB; # (옸; 옸; 옸; 옸; 옸; ) HANGUL SYLLABLE OSS +C639;C639;110B 1169 11BC;C639;110B 1169 11BC; # (옹; 옹; 옹; 옹; 옹; ) HANGUL SYLLABLE ONG +C63A;C63A;110B 1169 11BD;C63A;110B 1169 11BD; # (옺; 옺; 옺; 옺; 옺; ) HANGUL SYLLABLE OJ +C63B;C63B;110B 1169 11BE;C63B;110B 1169 11BE; # (옻; 옻; 옻; 옻; 옻; ) HANGUL SYLLABLE OC +C63C;C63C;110B 1169 11BF;C63C;110B 1169 11BF; # (옼; 옼; 옼; 옼; 옼; ) HANGUL SYLLABLE OK +C63D;C63D;110B 1169 11C0;C63D;110B 1169 11C0; # (옽; 옽; 옽; 옽; 옽; ) HANGUL SYLLABLE OT +C63E;C63E;110B 1169 11C1;C63E;110B 1169 11C1; # (옾; 옾; 옾; 옾; 옾; ) HANGUL SYLLABLE OP +C63F;C63F;110B 1169 11C2;C63F;110B 1169 11C2; # (옿; 옿; 옿; 옿; 옿; ) HANGUL SYLLABLE OH +C640;C640;110B 116A;C640;110B 116A; # (와; 와; 와; 와; 와; ) HANGUL SYLLABLE WA +C641;C641;110B 116A 11A8;C641;110B 116A 11A8; # (왁; 왁; 왁; 왁; 왁; ) HANGUL SYLLABLE WAG +C642;C642;110B 116A 11A9;C642;110B 116A 11A9; # (왂; 왂; 왂; 왂; 왂; ) HANGUL SYLLABLE WAGG +C643;C643;110B 116A 11AA;C643;110B 116A 11AA; # (왃; 왃; 왃; 왃; 왃; ) HANGUL SYLLABLE WAGS +C644;C644;110B 116A 11AB;C644;110B 116A 11AB; # (완; 완; 완; 완; 완; ) HANGUL SYLLABLE WAN +C645;C645;110B 116A 11AC;C645;110B 116A 11AC; # (왅; 왅; 왅; 왅; 왅; ) HANGUL SYLLABLE WANJ +C646;C646;110B 116A 11AD;C646;110B 116A 11AD; # (왆; 왆; 왆; 왆; 왆; ) HANGUL SYLLABLE WANH +C647;C647;110B 116A 11AE;C647;110B 116A 11AE; # (왇; 왇; 왇; 왇; 왇; ) HANGUL SYLLABLE WAD +C648;C648;110B 116A 11AF;C648;110B 116A 11AF; # (왈; 왈; 왈; 왈; 왈; ) HANGUL SYLLABLE WAL +C649;C649;110B 116A 11B0;C649;110B 116A 11B0; # (왉; 왉; 왉; 왉; 왉; ) HANGUL SYLLABLE WALG +C64A;C64A;110B 116A 11B1;C64A;110B 116A 11B1; # (왊; 왊; 왊; 왊; 왊; ) HANGUL SYLLABLE WALM +C64B;C64B;110B 116A 11B2;C64B;110B 116A 11B2; # (왋; 왋; 왋; 왋; 왋; ) HANGUL SYLLABLE WALB +C64C;C64C;110B 116A 11B3;C64C;110B 116A 11B3; # (왌; 왌; 왌; 왌; 왌; ) HANGUL SYLLABLE WALS +C64D;C64D;110B 116A 11B4;C64D;110B 116A 11B4; # (왍; 왍; 왍; 왍; 왍; ) HANGUL SYLLABLE WALT +C64E;C64E;110B 116A 11B5;C64E;110B 116A 11B5; # (왎; 왎; 왎; 왎; 왎; ) HANGUL SYLLABLE WALP +C64F;C64F;110B 116A 11B6;C64F;110B 116A 11B6; # (왏; 왏; 왏; 왏; 왏; ) HANGUL SYLLABLE WALH +C650;C650;110B 116A 11B7;C650;110B 116A 11B7; # (왐; 왐; 왐; 왐; 왐; ) HANGUL SYLLABLE WAM +C651;C651;110B 116A 11B8;C651;110B 116A 11B8; # (왑; 왑; 왑; 왑; 왑; ) HANGUL SYLLABLE WAB +C652;C652;110B 116A 11B9;C652;110B 116A 11B9; # (왒; 왒; 왒; 왒; 왒; ) HANGUL SYLLABLE WABS +C653;C653;110B 116A 11BA;C653;110B 116A 11BA; # (왓; 왓; 왓; 왓; 왓; ) HANGUL SYLLABLE WAS +C654;C654;110B 116A 11BB;C654;110B 116A 11BB; # (왔; 왔; 왔; 왔; 왔; ) HANGUL SYLLABLE WASS +C655;C655;110B 116A 11BC;C655;110B 116A 11BC; # (왕; 왕; 왕; 왕; 왕; ) HANGUL SYLLABLE WANG +C656;C656;110B 116A 11BD;C656;110B 116A 11BD; # (왖; 왖; 왖; 왖; 왖; ) HANGUL SYLLABLE WAJ +C657;C657;110B 116A 11BE;C657;110B 116A 11BE; # (왗; 왗; 왗; 왗; 왗; ) HANGUL SYLLABLE WAC +C658;C658;110B 116A 11BF;C658;110B 116A 11BF; # (왘; 왘; 왘; 왘; 왘; ) HANGUL SYLLABLE WAK +C659;C659;110B 116A 11C0;C659;110B 116A 11C0; # (왙; 왙; 왙; 왙; 왙; ) HANGUL SYLLABLE WAT +C65A;C65A;110B 116A 11C1;C65A;110B 116A 11C1; # (왚; 왚; 왚; 왚; 왚; ) HANGUL SYLLABLE WAP +C65B;C65B;110B 116A 11C2;C65B;110B 116A 11C2; # (왛; 왛; 왛; 왛; 왛; ) HANGUL SYLLABLE WAH +C65C;C65C;110B 116B;C65C;110B 116B; # (왜; 왜; 왜; 왜; 왜; ) HANGUL SYLLABLE WAE +C65D;C65D;110B 116B 11A8;C65D;110B 116B 11A8; # (왝; 왝; 왝; 왝; 왝; ) HANGUL SYLLABLE WAEG +C65E;C65E;110B 116B 11A9;C65E;110B 116B 11A9; # (왞; 왞; 왞; 왞; 왞; ) HANGUL SYLLABLE WAEGG +C65F;C65F;110B 116B 11AA;C65F;110B 116B 11AA; # (왟; 왟; 왟; 왟; 왟; ) HANGUL SYLLABLE WAEGS +C660;C660;110B 116B 11AB;C660;110B 116B 11AB; # (왠; 왠; 왠; 왠; 왠; ) HANGUL SYLLABLE WAEN +C661;C661;110B 116B 11AC;C661;110B 116B 11AC; # (왡; 왡; 왡; 왡; 왡; ) HANGUL SYLLABLE WAENJ +C662;C662;110B 116B 11AD;C662;110B 116B 11AD; # (왢; 왢; 왢; 왢; 왢; ) HANGUL SYLLABLE WAENH +C663;C663;110B 116B 11AE;C663;110B 116B 11AE; # (왣; 왣; 왣; 왣; 왣; ) HANGUL SYLLABLE WAED +C664;C664;110B 116B 11AF;C664;110B 116B 11AF; # (왤; 왤; 왤; 왤; 왤; ) HANGUL SYLLABLE WAEL +C665;C665;110B 116B 11B0;C665;110B 116B 11B0; # (왥; 왥; 왥; 왥; 왥; ) HANGUL SYLLABLE WAELG +C666;C666;110B 116B 11B1;C666;110B 116B 11B1; # (왦; 왦; 왦; 왦; 왦; ) HANGUL SYLLABLE WAELM +C667;C667;110B 116B 11B2;C667;110B 116B 11B2; # (왧; 왧; 왧; 왧; 왧; ) HANGUL SYLLABLE WAELB +C668;C668;110B 116B 11B3;C668;110B 116B 11B3; # (왨; 왨; 왨; 왨; 왨; ) HANGUL SYLLABLE WAELS +C669;C669;110B 116B 11B4;C669;110B 116B 11B4; # (왩; 왩; 왩; 왩; 왩; ) HANGUL SYLLABLE WAELT +C66A;C66A;110B 116B 11B5;C66A;110B 116B 11B5; # (왪; 왪; 왪; 왪; 왪; ) HANGUL SYLLABLE WAELP +C66B;C66B;110B 116B 11B6;C66B;110B 116B 11B6; # (왫; 왫; 왫; 왫; 왫; ) HANGUL SYLLABLE WAELH +C66C;C66C;110B 116B 11B7;C66C;110B 116B 11B7; # (왬; 왬; 왬; 왬; 왬; ) HANGUL SYLLABLE WAEM +C66D;C66D;110B 116B 11B8;C66D;110B 116B 11B8; # (왭; 왭; 왭; 왭; 왭; ) HANGUL SYLLABLE WAEB +C66E;C66E;110B 116B 11B9;C66E;110B 116B 11B9; # (왮; 왮; 왮; 왮; 왮; ) HANGUL SYLLABLE WAEBS +C66F;C66F;110B 116B 11BA;C66F;110B 116B 11BA; # (왯; 왯; 왯; 왯; 왯; ) HANGUL SYLLABLE WAES +C670;C670;110B 116B 11BB;C670;110B 116B 11BB; # (왰; 왰; 왰; 왰; 왰; ) HANGUL SYLLABLE WAESS +C671;C671;110B 116B 11BC;C671;110B 116B 11BC; # (왱; 왱; 왱; 왱; 왱; ) HANGUL SYLLABLE WAENG +C672;C672;110B 116B 11BD;C672;110B 116B 11BD; # (왲; 왲; 왲; 왲; 왲; ) HANGUL SYLLABLE WAEJ +C673;C673;110B 116B 11BE;C673;110B 116B 11BE; # (왳; 왳; 왳; 왳; 왳; ) HANGUL SYLLABLE WAEC +C674;C674;110B 116B 11BF;C674;110B 116B 11BF; # (왴; 왴; 왴; 왴; 왴; ) HANGUL SYLLABLE WAEK +C675;C675;110B 116B 11C0;C675;110B 116B 11C0; # (왵; 왵; 왵; 왵; 왵; ) HANGUL SYLLABLE WAET +C676;C676;110B 116B 11C1;C676;110B 116B 11C1; # (왶; 왶; 왶; 왶; 왶; ) HANGUL SYLLABLE WAEP +C677;C677;110B 116B 11C2;C677;110B 116B 11C2; # (왷; 왷; 왷; 왷; 왷; ) HANGUL SYLLABLE WAEH +C678;C678;110B 116C;C678;110B 116C; # (외; 외; 외; 외; 외; ) HANGUL SYLLABLE OE +C679;C679;110B 116C 11A8;C679;110B 116C 11A8; # (왹; 왹; 왹; 왹; 왹; ) HANGUL SYLLABLE OEG +C67A;C67A;110B 116C 11A9;C67A;110B 116C 11A9; # (왺; 왺; 왺; 왺; 왺; ) HANGUL SYLLABLE OEGG +C67B;C67B;110B 116C 11AA;C67B;110B 116C 11AA; # (왻; 왻; 왻; 왻; 왻; ) HANGUL SYLLABLE OEGS +C67C;C67C;110B 116C 11AB;C67C;110B 116C 11AB; # (왼; 왼; 왼; 왼; 왼; ) HANGUL SYLLABLE OEN +C67D;C67D;110B 116C 11AC;C67D;110B 116C 11AC; # (왽; 왽; 왽; 왽; 왽; ) HANGUL SYLLABLE OENJ +C67E;C67E;110B 116C 11AD;C67E;110B 116C 11AD; # (왾; 왾; 왾; 왾; 왾; ) HANGUL SYLLABLE OENH +C67F;C67F;110B 116C 11AE;C67F;110B 116C 11AE; # (왿; 왿; 왿; 왿; 왿; ) HANGUL SYLLABLE OED +C680;C680;110B 116C 11AF;C680;110B 116C 11AF; # (욀; 욀; 욀; 욀; 욀; ) HANGUL SYLLABLE OEL +C681;C681;110B 116C 11B0;C681;110B 116C 11B0; # (욁; 욁; 욁; 욁; 욁; ) HANGUL SYLLABLE OELG +C682;C682;110B 116C 11B1;C682;110B 116C 11B1; # (욂; 욂; 욂; 욂; 욂; ) HANGUL SYLLABLE OELM +C683;C683;110B 116C 11B2;C683;110B 116C 11B2; # (욃; 욃; 욃; 욃; 욃; ) HANGUL SYLLABLE OELB +C684;C684;110B 116C 11B3;C684;110B 116C 11B3; # (욄; 욄; 욄; 욄; 욄; ) HANGUL SYLLABLE OELS +C685;C685;110B 116C 11B4;C685;110B 116C 11B4; # (욅; 욅; 욅; 욅; 욅; ) HANGUL SYLLABLE OELT +C686;C686;110B 116C 11B5;C686;110B 116C 11B5; # (욆; 욆; 욆; 욆; 욆; ) HANGUL SYLLABLE OELP +C687;C687;110B 116C 11B6;C687;110B 116C 11B6; # (욇; 욇; 욇; 욇; 욇; ) HANGUL SYLLABLE OELH +C688;C688;110B 116C 11B7;C688;110B 116C 11B7; # (욈; 욈; 욈; 욈; 욈; ) HANGUL SYLLABLE OEM +C689;C689;110B 116C 11B8;C689;110B 116C 11B8; # (욉; 욉; 욉; 욉; 욉; ) HANGUL SYLLABLE OEB +C68A;C68A;110B 116C 11B9;C68A;110B 116C 11B9; # (욊; 욊; 욊; 욊; 욊; ) HANGUL SYLLABLE OEBS +C68B;C68B;110B 116C 11BA;C68B;110B 116C 11BA; # (욋; 욋; 욋; 욋; 욋; ) HANGUL SYLLABLE OES +C68C;C68C;110B 116C 11BB;C68C;110B 116C 11BB; # (욌; 욌; 욌; 욌; 욌; ) HANGUL SYLLABLE OESS +C68D;C68D;110B 116C 11BC;C68D;110B 116C 11BC; # (욍; 욍; 욍; 욍; 욍; ) HANGUL SYLLABLE OENG +C68E;C68E;110B 116C 11BD;C68E;110B 116C 11BD; # (욎; 욎; 욎; 욎; 욎; ) HANGUL SYLLABLE OEJ +C68F;C68F;110B 116C 11BE;C68F;110B 116C 11BE; # (욏; 욏; 욏; 욏; 욏; ) HANGUL SYLLABLE OEC +C690;C690;110B 116C 11BF;C690;110B 116C 11BF; # (욐; 욐; 욐; 욐; 욐; ) HANGUL SYLLABLE OEK +C691;C691;110B 116C 11C0;C691;110B 116C 11C0; # (욑; 욑; 욑; 욑; 욑; ) HANGUL SYLLABLE OET +C692;C692;110B 116C 11C1;C692;110B 116C 11C1; # (욒; 욒; 욒; 욒; 욒; ) HANGUL SYLLABLE OEP +C693;C693;110B 116C 11C2;C693;110B 116C 11C2; # (욓; 욓; 욓; 욓; 욓; ) HANGUL SYLLABLE OEH +C694;C694;110B 116D;C694;110B 116D; # (요; 요; 요; 요; 요; ) HANGUL SYLLABLE YO +C695;C695;110B 116D 11A8;C695;110B 116D 11A8; # (욕; 욕; 욕; 욕; 욕; ) HANGUL SYLLABLE YOG +C696;C696;110B 116D 11A9;C696;110B 116D 11A9; # (욖; 욖; 욖; 욖; 욖; ) HANGUL SYLLABLE YOGG +C697;C697;110B 116D 11AA;C697;110B 116D 11AA; # (욗; 욗; 욗; 욗; 욗; ) HANGUL SYLLABLE YOGS +C698;C698;110B 116D 11AB;C698;110B 116D 11AB; # (욘; 욘; 욘; 욘; 욘; ) HANGUL SYLLABLE YON +C699;C699;110B 116D 11AC;C699;110B 116D 11AC; # (욙; 욙; 욙; 욙; 욙; ) HANGUL SYLLABLE YONJ +C69A;C69A;110B 116D 11AD;C69A;110B 116D 11AD; # (욚; 욚; 욚; 욚; 욚; ) HANGUL SYLLABLE YONH +C69B;C69B;110B 116D 11AE;C69B;110B 116D 11AE; # (욛; 욛; 욛; 욛; 욛; ) HANGUL SYLLABLE YOD +C69C;C69C;110B 116D 11AF;C69C;110B 116D 11AF; # (욜; 욜; 욜; 욜; 욜; ) HANGUL SYLLABLE YOL +C69D;C69D;110B 116D 11B0;C69D;110B 116D 11B0; # (욝; 욝; 욝; 욝; 욝; ) HANGUL SYLLABLE YOLG +C69E;C69E;110B 116D 11B1;C69E;110B 116D 11B1; # (욞; 욞; 욞; 욞; 욞; ) HANGUL SYLLABLE YOLM +C69F;C69F;110B 116D 11B2;C69F;110B 116D 11B2; # (욟; 욟; 욟; 욟; 욟; ) HANGUL SYLLABLE YOLB +C6A0;C6A0;110B 116D 11B3;C6A0;110B 116D 11B3; # (욠; 욠; 욠; 욠; 욠; ) HANGUL SYLLABLE YOLS +C6A1;C6A1;110B 116D 11B4;C6A1;110B 116D 11B4; # (욡; 욡; 욡; 욡; 욡; ) HANGUL SYLLABLE YOLT +C6A2;C6A2;110B 116D 11B5;C6A2;110B 116D 11B5; # (욢; 욢; 욢; 욢; 욢; ) HANGUL SYLLABLE YOLP +C6A3;C6A3;110B 116D 11B6;C6A3;110B 116D 11B6; # (욣; 욣; 욣; 욣; 욣; ) HANGUL SYLLABLE YOLH +C6A4;C6A4;110B 116D 11B7;C6A4;110B 116D 11B7; # (욤; 욤; 욤; 욤; 욤; ) HANGUL SYLLABLE YOM +C6A5;C6A5;110B 116D 11B8;C6A5;110B 116D 11B8; # (욥; 욥; 욥; 욥; 욥; ) HANGUL SYLLABLE YOB +C6A6;C6A6;110B 116D 11B9;C6A6;110B 116D 11B9; # (욦; 욦; 욦; 욦; 욦; ) HANGUL SYLLABLE YOBS +C6A7;C6A7;110B 116D 11BA;C6A7;110B 116D 11BA; # (욧; 욧; 욧; 욧; 욧; ) HANGUL SYLLABLE YOS +C6A8;C6A8;110B 116D 11BB;C6A8;110B 116D 11BB; # (욨; 욨; 욨; 욨; 욨; ) HANGUL SYLLABLE YOSS +C6A9;C6A9;110B 116D 11BC;C6A9;110B 116D 11BC; # (용; 용; 용; 용; 용; ) HANGUL SYLLABLE YONG +C6AA;C6AA;110B 116D 11BD;C6AA;110B 116D 11BD; # (욪; 욪; 욪; 욪; 욪; ) HANGUL SYLLABLE YOJ +C6AB;C6AB;110B 116D 11BE;C6AB;110B 116D 11BE; # (욫; 욫; 욫; 욫; 욫; ) HANGUL SYLLABLE YOC +C6AC;C6AC;110B 116D 11BF;C6AC;110B 116D 11BF; # (욬; 욬; 욬; 욬; 욬; ) HANGUL SYLLABLE YOK +C6AD;C6AD;110B 116D 11C0;C6AD;110B 116D 11C0; # (욭; 욭; 욭; 욭; 욭; ) HANGUL SYLLABLE YOT +C6AE;C6AE;110B 116D 11C1;C6AE;110B 116D 11C1; # (욮; 욮; 욮; 욮; 욮; ) HANGUL SYLLABLE YOP +C6AF;C6AF;110B 116D 11C2;C6AF;110B 116D 11C2; # (욯; 욯; 욯; 욯; 욯; ) HANGUL SYLLABLE YOH +C6B0;C6B0;110B 116E;C6B0;110B 116E; # (우; 우; 우; 우; 우; ) HANGUL SYLLABLE U +C6B1;C6B1;110B 116E 11A8;C6B1;110B 116E 11A8; # (욱; 욱; 욱; 욱; 욱; ) HANGUL SYLLABLE UG +C6B2;C6B2;110B 116E 11A9;C6B2;110B 116E 11A9; # (욲; 욲; 욲; 욲; 욲; ) HANGUL SYLLABLE UGG +C6B3;C6B3;110B 116E 11AA;C6B3;110B 116E 11AA; # (욳; 욳; 욳; 욳; 욳; ) HANGUL SYLLABLE UGS +C6B4;C6B4;110B 116E 11AB;C6B4;110B 116E 11AB; # (운; 운; 운; 운; 운; ) HANGUL SYLLABLE UN +C6B5;C6B5;110B 116E 11AC;C6B5;110B 116E 11AC; # (욵; 욵; 욵; 욵; 욵; ) HANGUL SYLLABLE UNJ +C6B6;C6B6;110B 116E 11AD;C6B6;110B 116E 11AD; # (욶; 욶; 욶; 욶; 욶; ) HANGUL SYLLABLE UNH +C6B7;C6B7;110B 116E 11AE;C6B7;110B 116E 11AE; # (욷; 욷; 욷; 욷; 욷; ) HANGUL SYLLABLE UD +C6B8;C6B8;110B 116E 11AF;C6B8;110B 116E 11AF; # (울; 울; 울; 울; 울; ) HANGUL SYLLABLE UL +C6B9;C6B9;110B 116E 11B0;C6B9;110B 116E 11B0; # (욹; 욹; 욹; 욹; 욹; ) HANGUL SYLLABLE ULG +C6BA;C6BA;110B 116E 11B1;C6BA;110B 116E 11B1; # (욺; 욺; 욺; 욺; 욺; ) HANGUL SYLLABLE ULM +C6BB;C6BB;110B 116E 11B2;C6BB;110B 116E 11B2; # (욻; 욻; 욻; 욻; 욻; ) HANGUL SYLLABLE ULB +C6BC;C6BC;110B 116E 11B3;C6BC;110B 116E 11B3; # (욼; 욼; 욼; 욼; 욼; ) HANGUL SYLLABLE ULS +C6BD;C6BD;110B 116E 11B4;C6BD;110B 116E 11B4; # (욽; 욽; 욽; 욽; 욽; ) HANGUL SYLLABLE ULT +C6BE;C6BE;110B 116E 11B5;C6BE;110B 116E 11B5; # (욾; 욾; 욾; 욾; 욾; ) HANGUL SYLLABLE ULP +C6BF;C6BF;110B 116E 11B6;C6BF;110B 116E 11B6; # (욿; 욿; 욿; 욿; 욿; ) HANGUL SYLLABLE ULH +C6C0;C6C0;110B 116E 11B7;C6C0;110B 116E 11B7; # (움; 움; 움; 움; 움; ) HANGUL SYLLABLE UM +C6C1;C6C1;110B 116E 11B8;C6C1;110B 116E 11B8; # (웁; 웁; 웁; 웁; 웁; ) HANGUL SYLLABLE UB +C6C2;C6C2;110B 116E 11B9;C6C2;110B 116E 11B9; # (웂; 웂; 웂; 웂; 웂; ) HANGUL SYLLABLE UBS +C6C3;C6C3;110B 116E 11BA;C6C3;110B 116E 11BA; # (웃; 웃; 웃; 웃; 웃; ) HANGUL SYLLABLE US +C6C4;C6C4;110B 116E 11BB;C6C4;110B 116E 11BB; # (웄; 웄; 웄; 웄; 웄; ) HANGUL SYLLABLE USS +C6C5;C6C5;110B 116E 11BC;C6C5;110B 116E 11BC; # (웅; 웅; 웅; 웅; 웅; ) HANGUL SYLLABLE UNG +C6C6;C6C6;110B 116E 11BD;C6C6;110B 116E 11BD; # (웆; 웆; 웆; 웆; 웆; ) HANGUL SYLLABLE UJ +C6C7;C6C7;110B 116E 11BE;C6C7;110B 116E 11BE; # (웇; 웇; 웇; 웇; 웇; ) HANGUL SYLLABLE UC +C6C8;C6C8;110B 116E 11BF;C6C8;110B 116E 11BF; # (웈; 웈; 웈; 웈; 웈; ) HANGUL SYLLABLE UK +C6C9;C6C9;110B 116E 11C0;C6C9;110B 116E 11C0; # (웉; 웉; 웉; 웉; 웉; ) HANGUL SYLLABLE UT +C6CA;C6CA;110B 116E 11C1;C6CA;110B 116E 11C1; # (웊; 웊; 웊; 웊; 웊; ) HANGUL SYLLABLE UP +C6CB;C6CB;110B 116E 11C2;C6CB;110B 116E 11C2; # (웋; 웋; 웋; 웋; 웋; ) HANGUL SYLLABLE UH +C6CC;C6CC;110B 116F;C6CC;110B 116F; # (워; 워; 워; 워; 워; ) HANGUL SYLLABLE WEO +C6CD;C6CD;110B 116F 11A8;C6CD;110B 116F 11A8; # (웍; 웍; 웍; 웍; 웍; ) HANGUL SYLLABLE WEOG +C6CE;C6CE;110B 116F 11A9;C6CE;110B 116F 11A9; # (웎; 웎; 웎; 웎; 웎; ) HANGUL SYLLABLE WEOGG +C6CF;C6CF;110B 116F 11AA;C6CF;110B 116F 11AA; # (웏; 웏; 웏; 웏; 웏; ) HANGUL SYLLABLE WEOGS +C6D0;C6D0;110B 116F 11AB;C6D0;110B 116F 11AB; # (원; 원; 원; 원; 원; ) HANGUL SYLLABLE WEON +C6D1;C6D1;110B 116F 11AC;C6D1;110B 116F 11AC; # (웑; 웑; 웑; 웑; 웑; ) HANGUL SYLLABLE WEONJ +C6D2;C6D2;110B 116F 11AD;C6D2;110B 116F 11AD; # (웒; 웒; 웒; 웒; 웒; ) HANGUL SYLLABLE WEONH +C6D3;C6D3;110B 116F 11AE;C6D3;110B 116F 11AE; # (웓; 웓; 웓; 웓; 웓; ) HANGUL SYLLABLE WEOD +C6D4;C6D4;110B 116F 11AF;C6D4;110B 116F 11AF; # (월; 월; 월; 월; 월; ) HANGUL SYLLABLE WEOL +C6D5;C6D5;110B 116F 11B0;C6D5;110B 116F 11B0; # (웕; 웕; 웕; 웕; 웕; ) HANGUL SYLLABLE WEOLG +C6D6;C6D6;110B 116F 11B1;C6D6;110B 116F 11B1; # (웖; 웖; 웖; 웖; 웖; ) HANGUL SYLLABLE WEOLM +C6D7;C6D7;110B 116F 11B2;C6D7;110B 116F 11B2; # (웗; 웗; 웗; 웗; 웗; ) HANGUL SYLLABLE WEOLB +C6D8;C6D8;110B 116F 11B3;C6D8;110B 116F 11B3; # (웘; 웘; 웘; 웘; 웘; ) HANGUL SYLLABLE WEOLS +C6D9;C6D9;110B 116F 11B4;C6D9;110B 116F 11B4; # (웙; 웙; 웙; 웙; 웙; ) HANGUL SYLLABLE WEOLT +C6DA;C6DA;110B 116F 11B5;C6DA;110B 116F 11B5; # (웚; 웚; 웚; 웚; 웚; ) HANGUL SYLLABLE WEOLP +C6DB;C6DB;110B 116F 11B6;C6DB;110B 116F 11B6; # (웛; 웛; 웛; 웛; 웛; ) HANGUL SYLLABLE WEOLH +C6DC;C6DC;110B 116F 11B7;C6DC;110B 116F 11B7; # (웜; 웜; 웜; 웜; 웜; ) HANGUL SYLLABLE WEOM +C6DD;C6DD;110B 116F 11B8;C6DD;110B 116F 11B8; # (웝; 웝; 웝; 웝; 웝; ) HANGUL SYLLABLE WEOB +C6DE;C6DE;110B 116F 11B9;C6DE;110B 116F 11B9; # (웞; 웞; 웞; 웞; 웞; ) HANGUL SYLLABLE WEOBS +C6DF;C6DF;110B 116F 11BA;C6DF;110B 116F 11BA; # (웟; 웟; 웟; 웟; 웟; ) HANGUL SYLLABLE WEOS +C6E0;C6E0;110B 116F 11BB;C6E0;110B 116F 11BB; # (웠; 웠; 웠; 웠; 웠; ) HANGUL SYLLABLE WEOSS +C6E1;C6E1;110B 116F 11BC;C6E1;110B 116F 11BC; # (웡; 웡; 웡; 웡; 웡; ) HANGUL SYLLABLE WEONG +C6E2;C6E2;110B 116F 11BD;C6E2;110B 116F 11BD; # (웢; 웢; 웢; 웢; 웢; ) HANGUL SYLLABLE WEOJ +C6E3;C6E3;110B 116F 11BE;C6E3;110B 116F 11BE; # (웣; 웣; 웣; 웣; 웣; ) HANGUL SYLLABLE WEOC +C6E4;C6E4;110B 116F 11BF;C6E4;110B 116F 11BF; # (웤; 웤; 웤; 웤; 웤; ) HANGUL SYLLABLE WEOK +C6E5;C6E5;110B 116F 11C0;C6E5;110B 116F 11C0; # (웥; 웥; 웥; 웥; 웥; ) HANGUL SYLLABLE WEOT +C6E6;C6E6;110B 116F 11C1;C6E6;110B 116F 11C1; # (웦; 웦; 웦; 웦; 웦; ) HANGUL SYLLABLE WEOP +C6E7;C6E7;110B 116F 11C2;C6E7;110B 116F 11C2; # (웧; 웧; 웧; 웧; 웧; ) HANGUL SYLLABLE WEOH +C6E8;C6E8;110B 1170;C6E8;110B 1170; # (웨; 웨; 웨; 웨; 웨; ) HANGUL SYLLABLE WE +C6E9;C6E9;110B 1170 11A8;C6E9;110B 1170 11A8; # (웩; 웩; 웩; 웩; 웩; ) HANGUL SYLLABLE WEG +C6EA;C6EA;110B 1170 11A9;C6EA;110B 1170 11A9; # (웪; 웪; 웪; 웪; 웪; ) HANGUL SYLLABLE WEGG +C6EB;C6EB;110B 1170 11AA;C6EB;110B 1170 11AA; # (웫; 웫; 웫; 웫; 웫; ) HANGUL SYLLABLE WEGS +C6EC;C6EC;110B 1170 11AB;C6EC;110B 1170 11AB; # (웬; 웬; 웬; 웬; 웬; ) HANGUL SYLLABLE WEN +C6ED;C6ED;110B 1170 11AC;C6ED;110B 1170 11AC; # (웭; 웭; 웭; 웭; 웭; ) HANGUL SYLLABLE WENJ +C6EE;C6EE;110B 1170 11AD;C6EE;110B 1170 11AD; # (웮; 웮; 웮; 웮; 웮; ) HANGUL SYLLABLE WENH +C6EF;C6EF;110B 1170 11AE;C6EF;110B 1170 11AE; # (웯; 웯; 웯; 웯; 웯; ) HANGUL SYLLABLE WED +C6F0;C6F0;110B 1170 11AF;C6F0;110B 1170 11AF; # (웰; 웰; 웰; 웰; 웰; ) HANGUL SYLLABLE WEL +C6F1;C6F1;110B 1170 11B0;C6F1;110B 1170 11B0; # (웱; 웱; 웱; 웱; 웱; ) HANGUL SYLLABLE WELG +C6F2;C6F2;110B 1170 11B1;C6F2;110B 1170 11B1; # (웲; 웲; 웲; 웲; 웲; ) HANGUL SYLLABLE WELM +C6F3;C6F3;110B 1170 11B2;C6F3;110B 1170 11B2; # (웳; 웳; 웳; 웳; 웳; ) HANGUL SYLLABLE WELB +C6F4;C6F4;110B 1170 11B3;C6F4;110B 1170 11B3; # (웴; 웴; 웴; 웴; 웴; ) HANGUL SYLLABLE WELS +C6F5;C6F5;110B 1170 11B4;C6F5;110B 1170 11B4; # (웵; 웵; 웵; 웵; 웵; ) HANGUL SYLLABLE WELT +C6F6;C6F6;110B 1170 11B5;C6F6;110B 1170 11B5; # (웶; 웶; 웶; 웶; 웶; ) HANGUL SYLLABLE WELP +C6F7;C6F7;110B 1170 11B6;C6F7;110B 1170 11B6; # (웷; 웷; 웷; 웷; 웷; ) HANGUL SYLLABLE WELH +C6F8;C6F8;110B 1170 11B7;C6F8;110B 1170 11B7; # (웸; 웸; 웸; 웸; 웸; ) HANGUL SYLLABLE WEM +C6F9;C6F9;110B 1170 11B8;C6F9;110B 1170 11B8; # (웹; 웹; 웹; 웹; 웹; ) HANGUL SYLLABLE WEB +C6FA;C6FA;110B 1170 11B9;C6FA;110B 1170 11B9; # (웺; 웺; 웺; 웺; 웺; ) HANGUL SYLLABLE WEBS +C6FB;C6FB;110B 1170 11BA;C6FB;110B 1170 11BA; # (웻; 웻; 웻; 웻; 웻; ) HANGUL SYLLABLE WES +C6FC;C6FC;110B 1170 11BB;C6FC;110B 1170 11BB; # (웼; 웼; 웼; 웼; 웼; ) HANGUL SYLLABLE WESS +C6FD;C6FD;110B 1170 11BC;C6FD;110B 1170 11BC; # (웽; 웽; 웽; 웽; 웽; ) HANGUL SYLLABLE WENG +C6FE;C6FE;110B 1170 11BD;C6FE;110B 1170 11BD; # (웾; 웾; 웾; 웾; 웾; ) HANGUL SYLLABLE WEJ +C6FF;C6FF;110B 1170 11BE;C6FF;110B 1170 11BE; # (웿; 웿; 웿; 웿; 웿; ) HANGUL SYLLABLE WEC +C700;C700;110B 1170 11BF;C700;110B 1170 11BF; # (윀; 윀; 윀; 윀; 윀; ) HANGUL SYLLABLE WEK +C701;C701;110B 1170 11C0;C701;110B 1170 11C0; # (윁; 윁; 윁; 윁; 윁; ) HANGUL SYLLABLE WET +C702;C702;110B 1170 11C1;C702;110B 1170 11C1; # (윂; 윂; 윂; 윂; 윂; ) HANGUL SYLLABLE WEP +C703;C703;110B 1170 11C2;C703;110B 1170 11C2; # (윃; 윃; 윃; 윃; 윃; ) HANGUL SYLLABLE WEH +C704;C704;110B 1171;C704;110B 1171; # (위; 위; 위; 위; 위; ) HANGUL SYLLABLE WI +C705;C705;110B 1171 11A8;C705;110B 1171 11A8; # (윅; 윅; 윅; 윅; 윅; ) HANGUL SYLLABLE WIG +C706;C706;110B 1171 11A9;C706;110B 1171 11A9; # (윆; 윆; 윆; 윆; 윆; ) HANGUL SYLLABLE WIGG +C707;C707;110B 1171 11AA;C707;110B 1171 11AA; # (윇; 윇; 윇; 윇; 윇; ) HANGUL SYLLABLE WIGS +C708;C708;110B 1171 11AB;C708;110B 1171 11AB; # (윈; 윈; 윈; 윈; 윈; ) HANGUL SYLLABLE WIN +C709;C709;110B 1171 11AC;C709;110B 1171 11AC; # (윉; 윉; 윉; 윉; 윉; ) HANGUL SYLLABLE WINJ +C70A;C70A;110B 1171 11AD;C70A;110B 1171 11AD; # (윊; 윊; 윊; 윊; 윊; ) HANGUL SYLLABLE WINH +C70B;C70B;110B 1171 11AE;C70B;110B 1171 11AE; # (윋; 윋; 윋; 윋; 윋; ) HANGUL SYLLABLE WID +C70C;C70C;110B 1171 11AF;C70C;110B 1171 11AF; # (윌; 윌; 윌; 윌; 윌; ) HANGUL SYLLABLE WIL +C70D;C70D;110B 1171 11B0;C70D;110B 1171 11B0; # (윍; 윍; 윍; 윍; 윍; ) HANGUL SYLLABLE WILG +C70E;C70E;110B 1171 11B1;C70E;110B 1171 11B1; # (윎; 윎; 윎; 윎; 윎; ) HANGUL SYLLABLE WILM +C70F;C70F;110B 1171 11B2;C70F;110B 1171 11B2; # (윏; 윏; 윏; 윏; 윏; ) HANGUL SYLLABLE WILB +C710;C710;110B 1171 11B3;C710;110B 1171 11B3; # (윐; 윐; 윐; 윐; 윐; ) HANGUL SYLLABLE WILS +C711;C711;110B 1171 11B4;C711;110B 1171 11B4; # (윑; 윑; 윑; 윑; 윑; ) HANGUL SYLLABLE WILT +C712;C712;110B 1171 11B5;C712;110B 1171 11B5; # (윒; 윒; 윒; 윒; 윒; ) HANGUL SYLLABLE WILP +C713;C713;110B 1171 11B6;C713;110B 1171 11B6; # (윓; 윓; 윓; 윓; 윓; ) HANGUL SYLLABLE WILH +C714;C714;110B 1171 11B7;C714;110B 1171 11B7; # (윔; 윔; 윔; 윔; 윔; ) HANGUL SYLLABLE WIM +C715;C715;110B 1171 11B8;C715;110B 1171 11B8; # (윕; 윕; 윕; 윕; 윕; ) HANGUL SYLLABLE WIB +C716;C716;110B 1171 11B9;C716;110B 1171 11B9; # (윖; 윖; 윖; 윖; 윖; ) HANGUL SYLLABLE WIBS +C717;C717;110B 1171 11BA;C717;110B 1171 11BA; # (윗; 윗; 윗; 윗; 윗; ) HANGUL SYLLABLE WIS +C718;C718;110B 1171 11BB;C718;110B 1171 11BB; # (윘; 윘; 윘; 윘; 윘; ) HANGUL SYLLABLE WISS +C719;C719;110B 1171 11BC;C719;110B 1171 11BC; # (윙; 윙; 윙; 윙; 윙; ) HANGUL SYLLABLE WING +C71A;C71A;110B 1171 11BD;C71A;110B 1171 11BD; # (윚; 윚; 윚; 윚; 윚; ) HANGUL SYLLABLE WIJ +C71B;C71B;110B 1171 11BE;C71B;110B 1171 11BE; # (윛; 윛; 윛; 윛; 윛; ) HANGUL SYLLABLE WIC +C71C;C71C;110B 1171 11BF;C71C;110B 1171 11BF; # (윜; 윜; 윜; 윜; 윜; ) HANGUL SYLLABLE WIK +C71D;C71D;110B 1171 11C0;C71D;110B 1171 11C0; # (윝; 윝; 윝; 윝; 윝; ) HANGUL SYLLABLE WIT +C71E;C71E;110B 1171 11C1;C71E;110B 1171 11C1; # (윞; 윞; 윞; 윞; 윞; ) HANGUL SYLLABLE WIP +C71F;C71F;110B 1171 11C2;C71F;110B 1171 11C2; # (윟; 윟; 윟; 윟; 윟; ) HANGUL SYLLABLE WIH +C720;C720;110B 1172;C720;110B 1172; # (유; 유; 유; 유; 유; ) HANGUL SYLLABLE YU +C721;C721;110B 1172 11A8;C721;110B 1172 11A8; # (육; 육; 육; 육; 육; ) HANGUL SYLLABLE YUG +C722;C722;110B 1172 11A9;C722;110B 1172 11A9; # (윢; 윢; 윢; 윢; 윢; ) HANGUL SYLLABLE YUGG +C723;C723;110B 1172 11AA;C723;110B 1172 11AA; # (윣; 윣; 윣; 윣; 윣; ) HANGUL SYLLABLE YUGS +C724;C724;110B 1172 11AB;C724;110B 1172 11AB; # (윤; 윤; 윤; 윤; 윤; ) HANGUL SYLLABLE YUN +C725;C725;110B 1172 11AC;C725;110B 1172 11AC; # (윥; 윥; 윥; 윥; 윥; ) HANGUL SYLLABLE YUNJ +C726;C726;110B 1172 11AD;C726;110B 1172 11AD; # (윦; 윦; 윦; 윦; 윦; ) HANGUL SYLLABLE YUNH +C727;C727;110B 1172 11AE;C727;110B 1172 11AE; # (윧; 윧; 윧; 윧; 윧; ) HANGUL SYLLABLE YUD +C728;C728;110B 1172 11AF;C728;110B 1172 11AF; # (율; 율; 율; 율; 율; ) HANGUL SYLLABLE YUL +C729;C729;110B 1172 11B0;C729;110B 1172 11B0; # (윩; 윩; 윩; 윩; 윩; ) HANGUL SYLLABLE YULG +C72A;C72A;110B 1172 11B1;C72A;110B 1172 11B1; # (윪; 윪; 윪; 윪; 윪; ) HANGUL SYLLABLE YULM +C72B;C72B;110B 1172 11B2;C72B;110B 1172 11B2; # (윫; 윫; 윫; 윫; 윫; ) HANGUL SYLLABLE YULB +C72C;C72C;110B 1172 11B3;C72C;110B 1172 11B3; # (윬; 윬; 윬; 윬; 윬; ) HANGUL SYLLABLE YULS +C72D;C72D;110B 1172 11B4;C72D;110B 1172 11B4; # (윭; 윭; 윭; 윭; 윭; ) HANGUL SYLLABLE YULT +C72E;C72E;110B 1172 11B5;C72E;110B 1172 11B5; # (윮; 윮; 윮; 윮; 윮; ) HANGUL SYLLABLE YULP +C72F;C72F;110B 1172 11B6;C72F;110B 1172 11B6; # (윯; 윯; 윯; 윯; 윯; ) HANGUL SYLLABLE YULH +C730;C730;110B 1172 11B7;C730;110B 1172 11B7; # (윰; 윰; 윰; 윰; 윰; ) HANGUL SYLLABLE YUM +C731;C731;110B 1172 11B8;C731;110B 1172 11B8; # (윱; 윱; 윱; 윱; 윱; ) HANGUL SYLLABLE YUB +C732;C732;110B 1172 11B9;C732;110B 1172 11B9; # (윲; 윲; 윲; 윲; 윲; ) HANGUL SYLLABLE YUBS +C733;C733;110B 1172 11BA;C733;110B 1172 11BA; # (윳; 윳; 윳; 윳; 윳; ) HANGUL SYLLABLE YUS +C734;C734;110B 1172 11BB;C734;110B 1172 11BB; # (윴; 윴; 윴; 윴; 윴; ) HANGUL SYLLABLE YUSS +C735;C735;110B 1172 11BC;C735;110B 1172 11BC; # (융; 융; 융; 융; 융; ) HANGUL SYLLABLE YUNG +C736;C736;110B 1172 11BD;C736;110B 1172 11BD; # (윶; 윶; 윶; 윶; 윶; ) HANGUL SYLLABLE YUJ +C737;C737;110B 1172 11BE;C737;110B 1172 11BE; # (윷; 윷; 윷; 윷; 윷; ) HANGUL SYLLABLE YUC +C738;C738;110B 1172 11BF;C738;110B 1172 11BF; # (윸; 윸; 윸; 윸; 윸; ) HANGUL SYLLABLE YUK +C739;C739;110B 1172 11C0;C739;110B 1172 11C0; # (윹; 윹; 윹; 윹; 윹; ) HANGUL SYLLABLE YUT +C73A;C73A;110B 1172 11C1;C73A;110B 1172 11C1; # (윺; 윺; 윺; 윺; 윺; ) HANGUL SYLLABLE YUP +C73B;C73B;110B 1172 11C2;C73B;110B 1172 11C2; # (윻; 윻; 윻; 윻; 윻; ) HANGUL SYLLABLE YUH +C73C;C73C;110B 1173;C73C;110B 1173; # (으; 으; 으; 으; 으; ) HANGUL SYLLABLE EU +C73D;C73D;110B 1173 11A8;C73D;110B 1173 11A8; # (윽; 윽; 윽; 윽; 윽; ) HANGUL SYLLABLE EUG +C73E;C73E;110B 1173 11A9;C73E;110B 1173 11A9; # (윾; 윾; 윾; 윾; 윾; ) HANGUL SYLLABLE EUGG +C73F;C73F;110B 1173 11AA;C73F;110B 1173 11AA; # (윿; 윿; 윿; 윿; 윿; ) HANGUL SYLLABLE EUGS +C740;C740;110B 1173 11AB;C740;110B 1173 11AB; # (은; 은; 은; 은; 은; ) HANGUL SYLLABLE EUN +C741;C741;110B 1173 11AC;C741;110B 1173 11AC; # (읁; 읁; 읁; 읁; 읁; ) HANGUL SYLLABLE EUNJ +C742;C742;110B 1173 11AD;C742;110B 1173 11AD; # (읂; 읂; 읂; 읂; 읂; ) HANGUL SYLLABLE EUNH +C743;C743;110B 1173 11AE;C743;110B 1173 11AE; # (읃; 읃; 읃; 읃; 읃; ) HANGUL SYLLABLE EUD +C744;C744;110B 1173 11AF;C744;110B 1173 11AF; # (을; 을; 을; 을; 을; ) HANGUL SYLLABLE EUL +C745;C745;110B 1173 11B0;C745;110B 1173 11B0; # (읅; 읅; 읅; 읅; 읅; ) HANGUL SYLLABLE EULG +C746;C746;110B 1173 11B1;C746;110B 1173 11B1; # (읆; 읆; 읆; 읆; 읆; ) HANGUL SYLLABLE EULM +C747;C747;110B 1173 11B2;C747;110B 1173 11B2; # (읇; 읇; 읇; 읇; 읇; ) HANGUL SYLLABLE EULB +C748;C748;110B 1173 11B3;C748;110B 1173 11B3; # (읈; 읈; 읈; 읈; 읈; ) HANGUL SYLLABLE EULS +C749;C749;110B 1173 11B4;C749;110B 1173 11B4; # (읉; 읉; 읉; 읉; 읉; ) HANGUL SYLLABLE EULT +C74A;C74A;110B 1173 11B5;C74A;110B 1173 11B5; # (읊; 읊; 읊; 읊; 읊; ) HANGUL SYLLABLE EULP +C74B;C74B;110B 1173 11B6;C74B;110B 1173 11B6; # (읋; 읋; 읋; 읋; 읋; ) HANGUL SYLLABLE EULH +C74C;C74C;110B 1173 11B7;C74C;110B 1173 11B7; # (음; 음; 음; 음; 음; ) HANGUL SYLLABLE EUM +C74D;C74D;110B 1173 11B8;C74D;110B 1173 11B8; # (읍; 읍; 읍; 읍; 읍; ) HANGUL SYLLABLE EUB +C74E;C74E;110B 1173 11B9;C74E;110B 1173 11B9; # (읎; 읎; 읎; 읎; 읎; ) HANGUL SYLLABLE EUBS +C74F;C74F;110B 1173 11BA;C74F;110B 1173 11BA; # (읏; 읏; 읏; 읏; 읏; ) HANGUL SYLLABLE EUS +C750;C750;110B 1173 11BB;C750;110B 1173 11BB; # (읐; 읐; 읐; 읐; 읐; ) HANGUL SYLLABLE EUSS +C751;C751;110B 1173 11BC;C751;110B 1173 11BC; # (응; 응; 응; 응; 응; ) HANGUL SYLLABLE EUNG +C752;C752;110B 1173 11BD;C752;110B 1173 11BD; # (읒; 읒; 읒; 읒; 읒; ) HANGUL SYLLABLE EUJ +C753;C753;110B 1173 11BE;C753;110B 1173 11BE; # (읓; 읓; 읓; 읓; 읓; ) HANGUL SYLLABLE EUC +C754;C754;110B 1173 11BF;C754;110B 1173 11BF; # (읔; 읔; 읔; 읔; 읔; ) HANGUL SYLLABLE EUK +C755;C755;110B 1173 11C0;C755;110B 1173 11C0; # (읕; 읕; 읕; 읕; 읕; ) HANGUL SYLLABLE EUT +C756;C756;110B 1173 11C1;C756;110B 1173 11C1; # (읖; 읖; 읖; 읖; 읖; ) HANGUL SYLLABLE EUP +C757;C757;110B 1173 11C2;C757;110B 1173 11C2; # (읗; 읗; 읗; 읗; 읗; ) HANGUL SYLLABLE EUH +C758;C758;110B 1174;C758;110B 1174; # (의; 의; 의; 의; 의; ) HANGUL SYLLABLE YI +C759;C759;110B 1174 11A8;C759;110B 1174 11A8; # (읙; 읙; 읙; 읙; 읙; ) HANGUL SYLLABLE YIG +C75A;C75A;110B 1174 11A9;C75A;110B 1174 11A9; # (읚; 읚; 읚; 읚; 읚; ) HANGUL SYLLABLE YIGG +C75B;C75B;110B 1174 11AA;C75B;110B 1174 11AA; # (읛; 읛; 읛; 읛; 읛; ) HANGUL SYLLABLE YIGS +C75C;C75C;110B 1174 11AB;C75C;110B 1174 11AB; # (읜; 읜; 읜; 읜; 읜; ) HANGUL SYLLABLE YIN +C75D;C75D;110B 1174 11AC;C75D;110B 1174 11AC; # (읝; 읝; 읝; 읝; 읝; ) HANGUL SYLLABLE YINJ +C75E;C75E;110B 1174 11AD;C75E;110B 1174 11AD; # (읞; 읞; 읞; 읞; 읞; ) HANGUL SYLLABLE YINH +C75F;C75F;110B 1174 11AE;C75F;110B 1174 11AE; # (읟; 읟; 읟; 읟; 읟; ) HANGUL SYLLABLE YID +C760;C760;110B 1174 11AF;C760;110B 1174 11AF; # (읠; 읠; 읠; 읠; 읠; ) HANGUL SYLLABLE YIL +C761;C761;110B 1174 11B0;C761;110B 1174 11B0; # (읡; 읡; 읡; 읡; 읡; ) HANGUL SYLLABLE YILG +C762;C762;110B 1174 11B1;C762;110B 1174 11B1; # (읢; 읢; 읢; 읢; 읢; ) HANGUL SYLLABLE YILM +C763;C763;110B 1174 11B2;C763;110B 1174 11B2; # (읣; 읣; 읣; 읣; 읣; ) HANGUL SYLLABLE YILB +C764;C764;110B 1174 11B3;C764;110B 1174 11B3; # (읤; 읤; 읤; 읤; 읤; ) HANGUL SYLLABLE YILS +C765;C765;110B 1174 11B4;C765;110B 1174 11B4; # (읥; 읥; 읥; 읥; 읥; ) HANGUL SYLLABLE YILT +C766;C766;110B 1174 11B5;C766;110B 1174 11B5; # (읦; 읦; 읦; 읦; 읦; ) HANGUL SYLLABLE YILP +C767;C767;110B 1174 11B6;C767;110B 1174 11B6; # (읧; 읧; 읧; 읧; 읧; ) HANGUL SYLLABLE YILH +C768;C768;110B 1174 11B7;C768;110B 1174 11B7; # (읨; 읨; 읨; 읨; 읨; ) HANGUL SYLLABLE YIM +C769;C769;110B 1174 11B8;C769;110B 1174 11B8; # (읩; 읩; 읩; 읩; 읩; ) HANGUL SYLLABLE YIB +C76A;C76A;110B 1174 11B9;C76A;110B 1174 11B9; # (읪; 읪; 읪; 읪; 읪; ) HANGUL SYLLABLE YIBS +C76B;C76B;110B 1174 11BA;C76B;110B 1174 11BA; # (읫; 읫; 읫; 읫; 읫; ) HANGUL SYLLABLE YIS +C76C;C76C;110B 1174 11BB;C76C;110B 1174 11BB; # (읬; 읬; 읬; 읬; 읬; ) HANGUL SYLLABLE YISS +C76D;C76D;110B 1174 11BC;C76D;110B 1174 11BC; # (읭; 읭; 읭; 읭; 읭; ) HANGUL SYLLABLE YING +C76E;C76E;110B 1174 11BD;C76E;110B 1174 11BD; # (읮; 읮; 읮; 읮; 읮; ) HANGUL SYLLABLE YIJ +C76F;C76F;110B 1174 11BE;C76F;110B 1174 11BE; # (읯; 읯; 읯; 읯; 읯; ) HANGUL SYLLABLE YIC +C770;C770;110B 1174 11BF;C770;110B 1174 11BF; # (읰; 읰; 읰; 읰; 읰; ) HANGUL SYLLABLE YIK +C771;C771;110B 1174 11C0;C771;110B 1174 11C0; # (읱; 읱; 읱; 읱; 읱; ) HANGUL SYLLABLE YIT +C772;C772;110B 1174 11C1;C772;110B 1174 11C1; # (읲; 읲; 읲; 읲; 읲; ) HANGUL SYLLABLE YIP +C773;C773;110B 1174 11C2;C773;110B 1174 11C2; # (읳; 읳; 읳; 읳; 읳; ) HANGUL SYLLABLE YIH +C774;C774;110B 1175;C774;110B 1175; # (이; 이; 이; 이; 이; ) HANGUL SYLLABLE I +C775;C775;110B 1175 11A8;C775;110B 1175 11A8; # (익; 익; 익; 익; 익; ) HANGUL SYLLABLE IG +C776;C776;110B 1175 11A9;C776;110B 1175 11A9; # (읶; 읶; 읶; 읶; 읶; ) HANGUL SYLLABLE IGG +C777;C777;110B 1175 11AA;C777;110B 1175 11AA; # (읷; 읷; 읷; 읷; 읷; ) HANGUL SYLLABLE IGS +C778;C778;110B 1175 11AB;C778;110B 1175 11AB; # (인; 인; 인; 인; 인; ) HANGUL SYLLABLE IN +C779;C779;110B 1175 11AC;C779;110B 1175 11AC; # (읹; 읹; 읹; 읹; 읹; ) HANGUL SYLLABLE INJ +C77A;C77A;110B 1175 11AD;C77A;110B 1175 11AD; # (읺; 읺; 읺; 읺; 읺; ) HANGUL SYLLABLE INH +C77B;C77B;110B 1175 11AE;C77B;110B 1175 11AE; # (읻; 읻; 읻; 읻; 읻; ) HANGUL SYLLABLE ID +C77C;C77C;110B 1175 11AF;C77C;110B 1175 11AF; # (일; 일; 일; 일; 일; ) HANGUL SYLLABLE IL +C77D;C77D;110B 1175 11B0;C77D;110B 1175 11B0; # (읽; 읽; 읽; 읽; 읽; ) HANGUL SYLLABLE ILG +C77E;C77E;110B 1175 11B1;C77E;110B 1175 11B1; # (읾; 읾; 읾; 읾; 읾; ) HANGUL SYLLABLE ILM +C77F;C77F;110B 1175 11B2;C77F;110B 1175 11B2; # (읿; 읿; 읿; 읿; 읿; ) HANGUL SYLLABLE ILB +C780;C780;110B 1175 11B3;C780;110B 1175 11B3; # (잀; 잀; 잀; 잀; 잀; ) HANGUL SYLLABLE ILS +C781;C781;110B 1175 11B4;C781;110B 1175 11B4; # (잁; 잁; 잁; 잁; 잁; ) HANGUL SYLLABLE ILT +C782;C782;110B 1175 11B5;C782;110B 1175 11B5; # (잂; 잂; 잂; 잂; 잂; ) HANGUL SYLLABLE ILP +C783;C783;110B 1175 11B6;C783;110B 1175 11B6; # (잃; 잃; 잃; 잃; 잃; ) HANGUL SYLLABLE ILH +C784;C784;110B 1175 11B7;C784;110B 1175 11B7; # (임; 임; 임; 임; 임; ) HANGUL SYLLABLE IM +C785;C785;110B 1175 11B8;C785;110B 1175 11B8; # (입; 입; 입; 입; 입; ) HANGUL SYLLABLE IB +C786;C786;110B 1175 11B9;C786;110B 1175 11B9; # (잆; 잆; 잆; 잆; 잆; ) HANGUL SYLLABLE IBS +C787;C787;110B 1175 11BA;C787;110B 1175 11BA; # (잇; 잇; 잇; 잇; 잇; ) HANGUL SYLLABLE IS +C788;C788;110B 1175 11BB;C788;110B 1175 11BB; # (있; 있; 있; 있; 있; ) HANGUL SYLLABLE ISS +C789;C789;110B 1175 11BC;C789;110B 1175 11BC; # (잉; 잉; 잉; 잉; 잉; ) HANGUL SYLLABLE ING +C78A;C78A;110B 1175 11BD;C78A;110B 1175 11BD; # (잊; 잊; 잊; 잊; 잊; ) HANGUL SYLLABLE IJ +C78B;C78B;110B 1175 11BE;C78B;110B 1175 11BE; # (잋; 잋; 잋; 잋; 잋; ) HANGUL SYLLABLE IC +C78C;C78C;110B 1175 11BF;C78C;110B 1175 11BF; # (잌; 잌; 잌; 잌; 잌; ) HANGUL SYLLABLE IK +C78D;C78D;110B 1175 11C0;C78D;110B 1175 11C0; # (잍; 잍; 잍; 잍; 잍; ) HANGUL SYLLABLE IT +C78E;C78E;110B 1175 11C1;C78E;110B 1175 11C1; # (잎; 잎; 잎; 잎; 잎; ) HANGUL SYLLABLE IP +C78F;C78F;110B 1175 11C2;C78F;110B 1175 11C2; # (잏; 잏; 잏; 잏; 잏; ) HANGUL SYLLABLE IH +C790;C790;110C 1161;C790;110C 1161; # (자; 자; 자; 자; 자; ) HANGUL SYLLABLE JA +C791;C791;110C 1161 11A8;C791;110C 1161 11A8; # (작; 작; 작; 작; 작; ) HANGUL SYLLABLE JAG +C792;C792;110C 1161 11A9;C792;110C 1161 11A9; # (잒; 잒; 잒; 잒; 잒; ) HANGUL SYLLABLE JAGG +C793;C793;110C 1161 11AA;C793;110C 1161 11AA; # (잓; 잓; 잓; 잓; 잓; ) HANGUL SYLLABLE JAGS +C794;C794;110C 1161 11AB;C794;110C 1161 11AB; # (잔; 잔; 잔; 잔; 잔; ) HANGUL SYLLABLE JAN +C795;C795;110C 1161 11AC;C795;110C 1161 11AC; # (잕; 잕; 잕; 잕; 잕; ) HANGUL SYLLABLE JANJ +C796;C796;110C 1161 11AD;C796;110C 1161 11AD; # (잖; 잖; 잖; 잖; 잖; ) HANGUL SYLLABLE JANH +C797;C797;110C 1161 11AE;C797;110C 1161 11AE; # (잗; 잗; 잗; 잗; 잗; ) HANGUL SYLLABLE JAD +C798;C798;110C 1161 11AF;C798;110C 1161 11AF; # (잘; 잘; 잘; 잘; 잘; ) HANGUL SYLLABLE JAL +C799;C799;110C 1161 11B0;C799;110C 1161 11B0; # (잙; 잙; 잙; 잙; 잙; ) HANGUL SYLLABLE JALG +C79A;C79A;110C 1161 11B1;C79A;110C 1161 11B1; # (잚; 잚; 잚; 잚; 잚; ) HANGUL SYLLABLE JALM +C79B;C79B;110C 1161 11B2;C79B;110C 1161 11B2; # (잛; 잛; 잛; 잛; 잛; ) HANGUL SYLLABLE JALB +C79C;C79C;110C 1161 11B3;C79C;110C 1161 11B3; # (잜; 잜; 잜; 잜; 잜; ) HANGUL SYLLABLE JALS +C79D;C79D;110C 1161 11B4;C79D;110C 1161 11B4; # (잝; 잝; 잝; 잝; 잝; ) HANGUL SYLLABLE JALT +C79E;C79E;110C 1161 11B5;C79E;110C 1161 11B5; # (잞; 잞; 잞; 잞; 잞; ) HANGUL SYLLABLE JALP +C79F;C79F;110C 1161 11B6;C79F;110C 1161 11B6; # (잟; 잟; 잟; 잟; 잟; ) HANGUL SYLLABLE JALH +C7A0;C7A0;110C 1161 11B7;C7A0;110C 1161 11B7; # (잠; 잠; 잠; 잠; 잠; ) HANGUL SYLLABLE JAM +C7A1;C7A1;110C 1161 11B8;C7A1;110C 1161 11B8; # (잡; 잡; 잡; 잡; 잡; ) HANGUL SYLLABLE JAB +C7A2;C7A2;110C 1161 11B9;C7A2;110C 1161 11B9; # (잢; 잢; 잢; 잢; 잢; ) HANGUL SYLLABLE JABS +C7A3;C7A3;110C 1161 11BA;C7A3;110C 1161 11BA; # (잣; 잣; 잣; 잣; 잣; ) HANGUL SYLLABLE JAS +C7A4;C7A4;110C 1161 11BB;C7A4;110C 1161 11BB; # (잤; 잤; 잤; 잤; 잤; ) HANGUL SYLLABLE JASS +C7A5;C7A5;110C 1161 11BC;C7A5;110C 1161 11BC; # (장; 장; 장; 장; 장; ) HANGUL SYLLABLE JANG +C7A6;C7A6;110C 1161 11BD;C7A6;110C 1161 11BD; # (잦; 잦; 잦; 잦; 잦; ) HANGUL SYLLABLE JAJ +C7A7;C7A7;110C 1161 11BE;C7A7;110C 1161 11BE; # (잧; 잧; 잧; 잧; 잧; ) HANGUL SYLLABLE JAC +C7A8;C7A8;110C 1161 11BF;C7A8;110C 1161 11BF; # (잨; 잨; 잨; 잨; 잨; ) HANGUL SYLLABLE JAK +C7A9;C7A9;110C 1161 11C0;C7A9;110C 1161 11C0; # (잩; 잩; 잩; 잩; 잩; ) HANGUL SYLLABLE JAT +C7AA;C7AA;110C 1161 11C1;C7AA;110C 1161 11C1; # (잪; 잪; 잪; 잪; 잪; ) HANGUL SYLLABLE JAP +C7AB;C7AB;110C 1161 11C2;C7AB;110C 1161 11C2; # (잫; 잫; 잫; 잫; 잫; ) HANGUL SYLLABLE JAH +C7AC;C7AC;110C 1162;C7AC;110C 1162; # (재; 재; 재; 재; 재; ) HANGUL SYLLABLE JAE +C7AD;C7AD;110C 1162 11A8;C7AD;110C 1162 11A8; # (잭; 잭; 잭; 잭; 잭; ) HANGUL SYLLABLE JAEG +C7AE;C7AE;110C 1162 11A9;C7AE;110C 1162 11A9; # (잮; 잮; 잮; 잮; 잮; ) HANGUL SYLLABLE JAEGG +C7AF;C7AF;110C 1162 11AA;C7AF;110C 1162 11AA; # (잯; 잯; 잯; 잯; 잯; ) HANGUL SYLLABLE JAEGS +C7B0;C7B0;110C 1162 11AB;C7B0;110C 1162 11AB; # (잰; 잰; 잰; 잰; 잰; ) HANGUL SYLLABLE JAEN +C7B1;C7B1;110C 1162 11AC;C7B1;110C 1162 11AC; # (잱; 잱; 잱; 잱; 잱; ) HANGUL SYLLABLE JAENJ +C7B2;C7B2;110C 1162 11AD;C7B2;110C 1162 11AD; # (잲; 잲; 잲; 잲; 잲; ) HANGUL SYLLABLE JAENH +C7B3;C7B3;110C 1162 11AE;C7B3;110C 1162 11AE; # (잳; 잳; 잳; 잳; 잳; ) HANGUL SYLLABLE JAED +C7B4;C7B4;110C 1162 11AF;C7B4;110C 1162 11AF; # (잴; 잴; 잴; 잴; 잴; ) HANGUL SYLLABLE JAEL +C7B5;C7B5;110C 1162 11B0;C7B5;110C 1162 11B0; # (잵; 잵; 잵; 잵; 잵; ) HANGUL SYLLABLE JAELG +C7B6;C7B6;110C 1162 11B1;C7B6;110C 1162 11B1; # (잶; 잶; 잶; 잶; 잶; ) HANGUL SYLLABLE JAELM +C7B7;C7B7;110C 1162 11B2;C7B7;110C 1162 11B2; # (잷; 잷; 잷; 잷; 잷; ) HANGUL SYLLABLE JAELB +C7B8;C7B8;110C 1162 11B3;C7B8;110C 1162 11B3; # (잸; 잸; 잸; 잸; 잸; ) HANGUL SYLLABLE JAELS +C7B9;C7B9;110C 1162 11B4;C7B9;110C 1162 11B4; # (잹; 잹; 잹; 잹; 잹; ) HANGUL SYLLABLE JAELT +C7BA;C7BA;110C 1162 11B5;C7BA;110C 1162 11B5; # (잺; 잺; 잺; 잺; 잺; ) HANGUL SYLLABLE JAELP +C7BB;C7BB;110C 1162 11B6;C7BB;110C 1162 11B6; # (잻; 잻; 잻; 잻; 잻; ) HANGUL SYLLABLE JAELH +C7BC;C7BC;110C 1162 11B7;C7BC;110C 1162 11B7; # (잼; 잼; 잼; 잼; 잼; ) HANGUL SYLLABLE JAEM +C7BD;C7BD;110C 1162 11B8;C7BD;110C 1162 11B8; # (잽; 잽; 잽; 잽; 잽; ) HANGUL SYLLABLE JAEB +C7BE;C7BE;110C 1162 11B9;C7BE;110C 1162 11B9; # (잾; 잾; 잾; 잾; 잾; ) HANGUL SYLLABLE JAEBS +C7BF;C7BF;110C 1162 11BA;C7BF;110C 1162 11BA; # (잿; 잿; 잿; 잿; 잿; ) HANGUL SYLLABLE JAES +C7C0;C7C0;110C 1162 11BB;C7C0;110C 1162 11BB; # (쟀; 쟀; 쟀; 쟀; 쟀; ) HANGUL SYLLABLE JAESS +C7C1;C7C1;110C 1162 11BC;C7C1;110C 1162 11BC; # (쟁; 쟁; 쟁; 쟁; 쟁; ) HANGUL SYLLABLE JAENG +C7C2;C7C2;110C 1162 11BD;C7C2;110C 1162 11BD; # (쟂; 쟂; 쟂; 쟂; 쟂; ) HANGUL SYLLABLE JAEJ +C7C3;C7C3;110C 1162 11BE;C7C3;110C 1162 11BE; # (쟃; 쟃; 쟃; 쟃; 쟃; ) HANGUL SYLLABLE JAEC +C7C4;C7C4;110C 1162 11BF;C7C4;110C 1162 11BF; # (쟄; 쟄; 쟄; 쟄; 쟄; ) HANGUL SYLLABLE JAEK +C7C5;C7C5;110C 1162 11C0;C7C5;110C 1162 11C0; # (쟅; 쟅; 쟅; 쟅; 쟅; ) HANGUL SYLLABLE JAET +C7C6;C7C6;110C 1162 11C1;C7C6;110C 1162 11C1; # (쟆; 쟆; 쟆; 쟆; 쟆; ) HANGUL SYLLABLE JAEP +C7C7;C7C7;110C 1162 11C2;C7C7;110C 1162 11C2; # (쟇; 쟇; 쟇; 쟇; 쟇; ) HANGUL SYLLABLE JAEH +C7C8;C7C8;110C 1163;C7C8;110C 1163; # (쟈; 쟈; 쟈; 쟈; 쟈; ) HANGUL SYLLABLE JYA +C7C9;C7C9;110C 1163 11A8;C7C9;110C 1163 11A8; # (쟉; 쟉; 쟉; 쟉; 쟉; ) HANGUL SYLLABLE JYAG +C7CA;C7CA;110C 1163 11A9;C7CA;110C 1163 11A9; # (쟊; 쟊; 쟊; 쟊; 쟊; ) HANGUL SYLLABLE JYAGG +C7CB;C7CB;110C 1163 11AA;C7CB;110C 1163 11AA; # (쟋; 쟋; 쟋; 쟋; 쟋; ) HANGUL SYLLABLE JYAGS +C7CC;C7CC;110C 1163 11AB;C7CC;110C 1163 11AB; # (쟌; 쟌; 쟌; 쟌; 쟌; ) HANGUL SYLLABLE JYAN +C7CD;C7CD;110C 1163 11AC;C7CD;110C 1163 11AC; # (쟍; 쟍; 쟍; 쟍; 쟍; ) HANGUL SYLLABLE JYANJ +C7CE;C7CE;110C 1163 11AD;C7CE;110C 1163 11AD; # (쟎; 쟎; 쟎; 쟎; 쟎; ) HANGUL SYLLABLE JYANH +C7CF;C7CF;110C 1163 11AE;C7CF;110C 1163 11AE; # (쟏; 쟏; 쟏; 쟏; 쟏; ) HANGUL SYLLABLE JYAD +C7D0;C7D0;110C 1163 11AF;C7D0;110C 1163 11AF; # (쟐; 쟐; 쟐; 쟐; 쟐; ) HANGUL SYLLABLE JYAL +C7D1;C7D1;110C 1163 11B0;C7D1;110C 1163 11B0; # (쟑; 쟑; 쟑; 쟑; 쟑; ) HANGUL SYLLABLE JYALG +C7D2;C7D2;110C 1163 11B1;C7D2;110C 1163 11B1; # (쟒; 쟒; 쟒; 쟒; 쟒; ) HANGUL SYLLABLE JYALM +C7D3;C7D3;110C 1163 11B2;C7D3;110C 1163 11B2; # (쟓; 쟓; 쟓; 쟓; 쟓; ) HANGUL SYLLABLE JYALB +C7D4;C7D4;110C 1163 11B3;C7D4;110C 1163 11B3; # (쟔; 쟔; 쟔; 쟔; 쟔; ) HANGUL SYLLABLE JYALS +C7D5;C7D5;110C 1163 11B4;C7D5;110C 1163 11B4; # (쟕; 쟕; 쟕; 쟕; 쟕; ) HANGUL SYLLABLE JYALT +C7D6;C7D6;110C 1163 11B5;C7D6;110C 1163 11B5; # (쟖; 쟖; 쟖; 쟖; 쟖; ) HANGUL SYLLABLE JYALP +C7D7;C7D7;110C 1163 11B6;C7D7;110C 1163 11B6; # (쟗; 쟗; 쟗; 쟗; 쟗; ) HANGUL SYLLABLE JYALH +C7D8;C7D8;110C 1163 11B7;C7D8;110C 1163 11B7; # (쟘; 쟘; 쟘; 쟘; 쟘; ) HANGUL SYLLABLE JYAM +C7D9;C7D9;110C 1163 11B8;C7D9;110C 1163 11B8; # (쟙; 쟙; 쟙; 쟙; 쟙; ) HANGUL SYLLABLE JYAB +C7DA;C7DA;110C 1163 11B9;C7DA;110C 1163 11B9; # (쟚; 쟚; 쟚; 쟚; 쟚; ) HANGUL SYLLABLE JYABS +C7DB;C7DB;110C 1163 11BA;C7DB;110C 1163 11BA; # (쟛; 쟛; 쟛; 쟛; 쟛; ) HANGUL SYLLABLE JYAS +C7DC;C7DC;110C 1163 11BB;C7DC;110C 1163 11BB; # (쟜; 쟜; 쟜; 쟜; 쟜; ) HANGUL SYLLABLE JYASS +C7DD;C7DD;110C 1163 11BC;C7DD;110C 1163 11BC; # (쟝; 쟝; 쟝; 쟝; 쟝; ) HANGUL SYLLABLE JYANG +C7DE;C7DE;110C 1163 11BD;C7DE;110C 1163 11BD; # (쟞; 쟞; 쟞; 쟞; 쟞; ) HANGUL SYLLABLE JYAJ +C7DF;C7DF;110C 1163 11BE;C7DF;110C 1163 11BE; # (쟟; 쟟; 쟟; 쟟; 쟟; ) HANGUL SYLLABLE JYAC +C7E0;C7E0;110C 1163 11BF;C7E0;110C 1163 11BF; # (쟠; 쟠; 쟠; 쟠; 쟠; ) HANGUL SYLLABLE JYAK +C7E1;C7E1;110C 1163 11C0;C7E1;110C 1163 11C0; # (쟡; 쟡; 쟡; 쟡; 쟡; ) HANGUL SYLLABLE JYAT +C7E2;C7E2;110C 1163 11C1;C7E2;110C 1163 11C1; # (쟢; 쟢; 쟢; 쟢; 쟢; ) HANGUL SYLLABLE JYAP +C7E3;C7E3;110C 1163 11C2;C7E3;110C 1163 11C2; # (쟣; 쟣; 쟣; 쟣; 쟣; ) HANGUL SYLLABLE JYAH +C7E4;C7E4;110C 1164;C7E4;110C 1164; # (쟤; 쟤; 쟤; 쟤; 쟤; ) HANGUL SYLLABLE JYAE +C7E5;C7E5;110C 1164 11A8;C7E5;110C 1164 11A8; # (쟥; 쟥; 쟥; 쟥; 쟥; ) HANGUL SYLLABLE JYAEG +C7E6;C7E6;110C 1164 11A9;C7E6;110C 1164 11A9; # (쟦; 쟦; 쟦; 쟦; 쟦; ) HANGUL SYLLABLE JYAEGG +C7E7;C7E7;110C 1164 11AA;C7E7;110C 1164 11AA; # (쟧; 쟧; 쟧; 쟧; 쟧; ) HANGUL SYLLABLE JYAEGS +C7E8;C7E8;110C 1164 11AB;C7E8;110C 1164 11AB; # (쟨; 쟨; 쟨; 쟨; 쟨; ) HANGUL SYLLABLE JYAEN +C7E9;C7E9;110C 1164 11AC;C7E9;110C 1164 11AC; # (쟩; 쟩; 쟩; 쟩; 쟩; ) HANGUL SYLLABLE JYAENJ +C7EA;C7EA;110C 1164 11AD;C7EA;110C 1164 11AD; # (쟪; 쟪; 쟪; 쟪; 쟪; ) HANGUL SYLLABLE JYAENH +C7EB;C7EB;110C 1164 11AE;C7EB;110C 1164 11AE; # (쟫; 쟫; 쟫; 쟫; 쟫; ) HANGUL SYLLABLE JYAED +C7EC;C7EC;110C 1164 11AF;C7EC;110C 1164 11AF; # (쟬; 쟬; 쟬; 쟬; 쟬; ) HANGUL SYLLABLE JYAEL +C7ED;C7ED;110C 1164 11B0;C7ED;110C 1164 11B0; # (쟭; 쟭; 쟭; 쟭; 쟭; ) HANGUL SYLLABLE JYAELG +C7EE;C7EE;110C 1164 11B1;C7EE;110C 1164 11B1; # (쟮; 쟮; 쟮; 쟮; 쟮; ) HANGUL SYLLABLE JYAELM +C7EF;C7EF;110C 1164 11B2;C7EF;110C 1164 11B2; # (쟯; 쟯; 쟯; 쟯; 쟯; ) HANGUL SYLLABLE JYAELB +C7F0;C7F0;110C 1164 11B3;C7F0;110C 1164 11B3; # (쟰; 쟰; 쟰; 쟰; 쟰; ) HANGUL SYLLABLE JYAELS +C7F1;C7F1;110C 1164 11B4;C7F1;110C 1164 11B4; # (쟱; 쟱; 쟱; 쟱; 쟱; ) HANGUL SYLLABLE JYAELT +C7F2;C7F2;110C 1164 11B5;C7F2;110C 1164 11B5; # (쟲; 쟲; 쟲; 쟲; 쟲; ) HANGUL SYLLABLE JYAELP +C7F3;C7F3;110C 1164 11B6;C7F3;110C 1164 11B6; # (쟳; 쟳; 쟳; 쟳; 쟳; ) HANGUL SYLLABLE JYAELH +C7F4;C7F4;110C 1164 11B7;C7F4;110C 1164 11B7; # (쟴; 쟴; 쟴; 쟴; 쟴; ) HANGUL SYLLABLE JYAEM +C7F5;C7F5;110C 1164 11B8;C7F5;110C 1164 11B8; # (쟵; 쟵; 쟵; 쟵; 쟵; ) HANGUL SYLLABLE JYAEB +C7F6;C7F6;110C 1164 11B9;C7F6;110C 1164 11B9; # (쟶; 쟶; 쟶; 쟶; 쟶; ) HANGUL SYLLABLE JYAEBS +C7F7;C7F7;110C 1164 11BA;C7F7;110C 1164 11BA; # (쟷; 쟷; 쟷; 쟷; 쟷; ) HANGUL SYLLABLE JYAES +C7F8;C7F8;110C 1164 11BB;C7F8;110C 1164 11BB; # (쟸; 쟸; 쟸; 쟸; 쟸; ) HANGUL SYLLABLE JYAESS +C7F9;C7F9;110C 1164 11BC;C7F9;110C 1164 11BC; # (쟹; 쟹; 쟹; 쟹; 쟹; ) HANGUL SYLLABLE JYAENG +C7FA;C7FA;110C 1164 11BD;C7FA;110C 1164 11BD; # (쟺; 쟺; 쟺; 쟺; 쟺; ) HANGUL SYLLABLE JYAEJ +C7FB;C7FB;110C 1164 11BE;C7FB;110C 1164 11BE; # (쟻; 쟻; 쟻; 쟻; 쟻; ) HANGUL SYLLABLE JYAEC +C7FC;C7FC;110C 1164 11BF;C7FC;110C 1164 11BF; # (쟼; 쟼; 쟼; 쟼; 쟼; ) HANGUL SYLLABLE JYAEK +C7FD;C7FD;110C 1164 11C0;C7FD;110C 1164 11C0; # (쟽; 쟽; 쟽; 쟽; 쟽; ) HANGUL SYLLABLE JYAET +C7FE;C7FE;110C 1164 11C1;C7FE;110C 1164 11C1; # (쟾; 쟾; 쟾; 쟾; 쟾; ) HANGUL SYLLABLE JYAEP +C7FF;C7FF;110C 1164 11C2;C7FF;110C 1164 11C2; # (쟿; 쟿; 쟿; 쟿; 쟿; ) HANGUL SYLLABLE JYAEH +C800;C800;110C 1165;C800;110C 1165; # (저; 저; 저; 저; 저; ) HANGUL SYLLABLE JEO +C801;C801;110C 1165 11A8;C801;110C 1165 11A8; # (적; 적; 적; 적; 적; ) HANGUL SYLLABLE JEOG +C802;C802;110C 1165 11A9;C802;110C 1165 11A9; # (젂; 젂; 젂; 젂; 젂; ) HANGUL SYLLABLE JEOGG +C803;C803;110C 1165 11AA;C803;110C 1165 11AA; # (젃; 젃; 젃; 젃; 젃; ) HANGUL SYLLABLE JEOGS +C804;C804;110C 1165 11AB;C804;110C 1165 11AB; # (전; 전; 전; 전; 전; ) HANGUL SYLLABLE JEON +C805;C805;110C 1165 11AC;C805;110C 1165 11AC; # (젅; 젅; 젅; 젅; 젅; ) HANGUL SYLLABLE JEONJ +C806;C806;110C 1165 11AD;C806;110C 1165 11AD; # (젆; 젆; 젆; 젆; 젆; ) HANGUL SYLLABLE JEONH +C807;C807;110C 1165 11AE;C807;110C 1165 11AE; # (젇; 젇; 젇; 젇; 젇; ) HANGUL SYLLABLE JEOD +C808;C808;110C 1165 11AF;C808;110C 1165 11AF; # (절; 절; 절; 절; 절; ) HANGUL SYLLABLE JEOL +C809;C809;110C 1165 11B0;C809;110C 1165 11B0; # (젉; 젉; 젉; 젉; 젉; ) HANGUL SYLLABLE JEOLG +C80A;C80A;110C 1165 11B1;C80A;110C 1165 11B1; # (젊; 젊; 젊; 젊; 젊; ) HANGUL SYLLABLE JEOLM +C80B;C80B;110C 1165 11B2;C80B;110C 1165 11B2; # (젋; 젋; 젋; 젋; 젋; ) HANGUL SYLLABLE JEOLB +C80C;C80C;110C 1165 11B3;C80C;110C 1165 11B3; # (젌; 젌; 젌; 젌; 젌; ) HANGUL SYLLABLE JEOLS +C80D;C80D;110C 1165 11B4;C80D;110C 1165 11B4; # (젍; 젍; 젍; 젍; 젍; ) HANGUL SYLLABLE JEOLT +C80E;C80E;110C 1165 11B5;C80E;110C 1165 11B5; # (젎; 젎; 젎; 젎; 젎; ) HANGUL SYLLABLE JEOLP +C80F;C80F;110C 1165 11B6;C80F;110C 1165 11B6; # (젏; 젏; 젏; 젏; 젏; ) HANGUL SYLLABLE JEOLH +C810;C810;110C 1165 11B7;C810;110C 1165 11B7; # (점; 점; 점; 점; 점; ) HANGUL SYLLABLE JEOM +C811;C811;110C 1165 11B8;C811;110C 1165 11B8; # (접; 접; 접; 접; 접; ) HANGUL SYLLABLE JEOB +C812;C812;110C 1165 11B9;C812;110C 1165 11B9; # (젒; 젒; 젒; 젒; 젒; ) HANGUL SYLLABLE JEOBS +C813;C813;110C 1165 11BA;C813;110C 1165 11BA; # (젓; 젓; 젓; 젓; 젓; ) HANGUL SYLLABLE JEOS +C814;C814;110C 1165 11BB;C814;110C 1165 11BB; # (젔; 젔; 젔; 젔; 젔; ) HANGUL SYLLABLE JEOSS +C815;C815;110C 1165 11BC;C815;110C 1165 11BC; # (정; 정; 정; 정; 정; ) HANGUL SYLLABLE JEONG +C816;C816;110C 1165 11BD;C816;110C 1165 11BD; # (젖; 젖; 젖; 젖; 젖; ) HANGUL SYLLABLE JEOJ +C817;C817;110C 1165 11BE;C817;110C 1165 11BE; # (젗; 젗; 젗; 젗; 젗; ) HANGUL SYLLABLE JEOC +C818;C818;110C 1165 11BF;C818;110C 1165 11BF; # (젘; 젘; 젘; 젘; 젘; ) HANGUL SYLLABLE JEOK +C819;C819;110C 1165 11C0;C819;110C 1165 11C0; # (젙; 젙; 젙; 젙; 젙; ) HANGUL SYLLABLE JEOT +C81A;C81A;110C 1165 11C1;C81A;110C 1165 11C1; # (젚; 젚; 젚; 젚; 젚; ) HANGUL SYLLABLE JEOP +C81B;C81B;110C 1165 11C2;C81B;110C 1165 11C2; # (젛; 젛; 젛; 젛; 젛; ) HANGUL SYLLABLE JEOH +C81C;C81C;110C 1166;C81C;110C 1166; # (제; 제; 제; 제; 제; ) HANGUL SYLLABLE JE +C81D;C81D;110C 1166 11A8;C81D;110C 1166 11A8; # (젝; 젝; 젝; 젝; 젝; ) HANGUL SYLLABLE JEG +C81E;C81E;110C 1166 11A9;C81E;110C 1166 11A9; # (젞; 젞; 젞; 젞; 젞; ) HANGUL SYLLABLE JEGG +C81F;C81F;110C 1166 11AA;C81F;110C 1166 11AA; # (젟; 젟; 젟; 젟; 젟; ) HANGUL SYLLABLE JEGS +C820;C820;110C 1166 11AB;C820;110C 1166 11AB; # (젠; 젠; 젠; 젠; 젠; ) HANGUL SYLLABLE JEN +C821;C821;110C 1166 11AC;C821;110C 1166 11AC; # (젡; 젡; 젡; 젡; 젡; ) HANGUL SYLLABLE JENJ +C822;C822;110C 1166 11AD;C822;110C 1166 11AD; # (젢; 젢; 젢; 젢; 젢; ) HANGUL SYLLABLE JENH +C823;C823;110C 1166 11AE;C823;110C 1166 11AE; # (젣; 젣; 젣; 젣; 젣; ) HANGUL SYLLABLE JED +C824;C824;110C 1166 11AF;C824;110C 1166 11AF; # (젤; 젤; 젤; 젤; 젤; ) HANGUL SYLLABLE JEL +C825;C825;110C 1166 11B0;C825;110C 1166 11B0; # (젥; 젥; 젥; 젥; 젥; ) HANGUL SYLLABLE JELG +C826;C826;110C 1166 11B1;C826;110C 1166 11B1; # (젦; 젦; 젦; 젦; 젦; ) HANGUL SYLLABLE JELM +C827;C827;110C 1166 11B2;C827;110C 1166 11B2; # (젧; 젧; 젧; 젧; 젧; ) HANGUL SYLLABLE JELB +C828;C828;110C 1166 11B3;C828;110C 1166 11B3; # (젨; 젨; 젨; 젨; 젨; ) HANGUL SYLLABLE JELS +C829;C829;110C 1166 11B4;C829;110C 1166 11B4; # (젩; 젩; 젩; 젩; 젩; ) HANGUL SYLLABLE JELT +C82A;C82A;110C 1166 11B5;C82A;110C 1166 11B5; # (젪; 젪; 젪; 젪; 젪; ) HANGUL SYLLABLE JELP +C82B;C82B;110C 1166 11B6;C82B;110C 1166 11B6; # (젫; 젫; 젫; 젫; 젫; ) HANGUL SYLLABLE JELH +C82C;C82C;110C 1166 11B7;C82C;110C 1166 11B7; # (젬; 젬; 젬; 젬; 젬; ) HANGUL SYLLABLE JEM +C82D;C82D;110C 1166 11B8;C82D;110C 1166 11B8; # (젭; 젭; 젭; 젭; 젭; ) HANGUL SYLLABLE JEB +C82E;C82E;110C 1166 11B9;C82E;110C 1166 11B9; # (젮; 젮; 젮; 젮; 젮; ) HANGUL SYLLABLE JEBS +C82F;C82F;110C 1166 11BA;C82F;110C 1166 11BA; # (젯; 젯; 젯; 젯; 젯; ) HANGUL SYLLABLE JES +C830;C830;110C 1166 11BB;C830;110C 1166 11BB; # (젰; 젰; 젰; 젰; 젰; ) HANGUL SYLLABLE JESS +C831;C831;110C 1166 11BC;C831;110C 1166 11BC; # (젱; 젱; 젱; 젱; 젱; ) HANGUL SYLLABLE JENG +C832;C832;110C 1166 11BD;C832;110C 1166 11BD; # (젲; 젲; 젲; 젲; 젲; ) HANGUL SYLLABLE JEJ +C833;C833;110C 1166 11BE;C833;110C 1166 11BE; # (젳; 젳; 젳; 젳; 젳; ) HANGUL SYLLABLE JEC +C834;C834;110C 1166 11BF;C834;110C 1166 11BF; # (젴; 젴; 젴; 젴; 젴; ) HANGUL SYLLABLE JEK +C835;C835;110C 1166 11C0;C835;110C 1166 11C0; # (젵; 젵; 젵; 젵; 젵; ) HANGUL SYLLABLE JET +C836;C836;110C 1166 11C1;C836;110C 1166 11C1; # (젶; 젶; 젶; 젶; 젶; ) HANGUL SYLLABLE JEP +C837;C837;110C 1166 11C2;C837;110C 1166 11C2; # (젷; 젷; 젷; 젷; 젷; ) HANGUL SYLLABLE JEH +C838;C838;110C 1167;C838;110C 1167; # (져; 져; 져; 져; 져; ) HANGUL SYLLABLE JYEO +C839;C839;110C 1167 11A8;C839;110C 1167 11A8; # (젹; 젹; 젹; 젹; 젹; ) HANGUL SYLLABLE JYEOG +C83A;C83A;110C 1167 11A9;C83A;110C 1167 11A9; # (젺; 젺; 젺; 젺; 젺; ) HANGUL SYLLABLE JYEOGG +C83B;C83B;110C 1167 11AA;C83B;110C 1167 11AA; # (젻; 젻; 젻; 젻; 젻; ) HANGUL SYLLABLE JYEOGS +C83C;C83C;110C 1167 11AB;C83C;110C 1167 11AB; # (젼; 젼; 젼; 젼; 젼; ) HANGUL SYLLABLE JYEON +C83D;C83D;110C 1167 11AC;C83D;110C 1167 11AC; # (젽; 젽; 젽; 젽; 젽; ) HANGUL SYLLABLE JYEONJ +C83E;C83E;110C 1167 11AD;C83E;110C 1167 11AD; # (젾; 젾; 젾; 젾; 젾; ) HANGUL SYLLABLE JYEONH +C83F;C83F;110C 1167 11AE;C83F;110C 1167 11AE; # (젿; 젿; 젿; 젿; 젿; ) HANGUL SYLLABLE JYEOD +C840;C840;110C 1167 11AF;C840;110C 1167 11AF; # (졀; 졀; 졀; 졀; 졀; ) HANGUL SYLLABLE JYEOL +C841;C841;110C 1167 11B0;C841;110C 1167 11B0; # (졁; 졁; 졁; 졁; 졁; ) HANGUL SYLLABLE JYEOLG +C842;C842;110C 1167 11B1;C842;110C 1167 11B1; # (졂; 졂; 졂; 졂; 졂; ) HANGUL SYLLABLE JYEOLM +C843;C843;110C 1167 11B2;C843;110C 1167 11B2; # (졃; 졃; 졃; 졃; 졃; ) HANGUL SYLLABLE JYEOLB +C844;C844;110C 1167 11B3;C844;110C 1167 11B3; # (졄; 졄; 졄; 졄; 졄; ) HANGUL SYLLABLE JYEOLS +C845;C845;110C 1167 11B4;C845;110C 1167 11B4; # (졅; 졅; 졅; 졅; 졅; ) HANGUL SYLLABLE JYEOLT +C846;C846;110C 1167 11B5;C846;110C 1167 11B5; # (졆; 졆; 졆; 졆; 졆; ) HANGUL SYLLABLE JYEOLP +C847;C847;110C 1167 11B6;C847;110C 1167 11B6; # (졇; 졇; 졇; 졇; 졇; ) HANGUL SYLLABLE JYEOLH +C848;C848;110C 1167 11B7;C848;110C 1167 11B7; # (졈; 졈; 졈; 졈; 졈; ) HANGUL SYLLABLE JYEOM +C849;C849;110C 1167 11B8;C849;110C 1167 11B8; # (졉; 졉; 졉; 졉; 졉; ) HANGUL SYLLABLE JYEOB +C84A;C84A;110C 1167 11B9;C84A;110C 1167 11B9; # (졊; 졊; 졊; 졊; 졊; ) HANGUL SYLLABLE JYEOBS +C84B;C84B;110C 1167 11BA;C84B;110C 1167 11BA; # (졋; 졋; 졋; 졋; 졋; ) HANGUL SYLLABLE JYEOS +C84C;C84C;110C 1167 11BB;C84C;110C 1167 11BB; # (졌; 졌; 졌; 졌; 졌; ) HANGUL SYLLABLE JYEOSS +C84D;C84D;110C 1167 11BC;C84D;110C 1167 11BC; # (졍; 졍; 졍; 졍; 졍; ) HANGUL SYLLABLE JYEONG +C84E;C84E;110C 1167 11BD;C84E;110C 1167 11BD; # (졎; 졎; 졎; 졎; 졎; ) HANGUL SYLLABLE JYEOJ +C84F;C84F;110C 1167 11BE;C84F;110C 1167 11BE; # (졏; 졏; 졏; 졏; 졏; ) HANGUL SYLLABLE JYEOC +C850;C850;110C 1167 11BF;C850;110C 1167 11BF; # (졐; 졐; 졐; 졐; 졐; ) HANGUL SYLLABLE JYEOK +C851;C851;110C 1167 11C0;C851;110C 1167 11C0; # (졑; 졑; 졑; 졑; 졑; ) HANGUL SYLLABLE JYEOT +C852;C852;110C 1167 11C1;C852;110C 1167 11C1; # (졒; 졒; 졒; 졒; 졒; ) HANGUL SYLLABLE JYEOP +C853;C853;110C 1167 11C2;C853;110C 1167 11C2; # (졓; 졓; 졓; 졓; 졓; ) HANGUL SYLLABLE JYEOH +C854;C854;110C 1168;C854;110C 1168; # (졔; 졔; 졔; 졔; 졔; ) HANGUL SYLLABLE JYE +C855;C855;110C 1168 11A8;C855;110C 1168 11A8; # (졕; 졕; 졕; 졕; 졕; ) HANGUL SYLLABLE JYEG +C856;C856;110C 1168 11A9;C856;110C 1168 11A9; # (졖; 졖; 졖; 졖; 졖; ) HANGUL SYLLABLE JYEGG +C857;C857;110C 1168 11AA;C857;110C 1168 11AA; # (졗; 졗; 졗; 졗; 졗; ) HANGUL SYLLABLE JYEGS +C858;C858;110C 1168 11AB;C858;110C 1168 11AB; # (졘; 졘; 졘; 졘; 졘; ) HANGUL SYLLABLE JYEN +C859;C859;110C 1168 11AC;C859;110C 1168 11AC; # (졙; 졙; 졙; 졙; 졙; ) HANGUL SYLLABLE JYENJ +C85A;C85A;110C 1168 11AD;C85A;110C 1168 11AD; # (졚; 졚; 졚; 졚; 졚; ) HANGUL SYLLABLE JYENH +C85B;C85B;110C 1168 11AE;C85B;110C 1168 11AE; # (졛; 졛; 졛; 졛; 졛; ) HANGUL SYLLABLE JYED +C85C;C85C;110C 1168 11AF;C85C;110C 1168 11AF; # (졜; 졜; 졜; 졜; 졜; ) HANGUL SYLLABLE JYEL +C85D;C85D;110C 1168 11B0;C85D;110C 1168 11B0; # (졝; 졝; 졝; 졝; 졝; ) HANGUL SYLLABLE JYELG +C85E;C85E;110C 1168 11B1;C85E;110C 1168 11B1; # (졞; 졞; 졞; 졞; 졞; ) HANGUL SYLLABLE JYELM +C85F;C85F;110C 1168 11B2;C85F;110C 1168 11B2; # (졟; 졟; 졟; 졟; 졟; ) HANGUL SYLLABLE JYELB +C860;C860;110C 1168 11B3;C860;110C 1168 11B3; # (졠; 졠; 졠; 졠; 졠; ) HANGUL SYLLABLE JYELS +C861;C861;110C 1168 11B4;C861;110C 1168 11B4; # (졡; 졡; 졡; 졡; 졡; ) HANGUL SYLLABLE JYELT +C862;C862;110C 1168 11B5;C862;110C 1168 11B5; # (졢; 졢; 졢; 졢; 졢; ) HANGUL SYLLABLE JYELP +C863;C863;110C 1168 11B6;C863;110C 1168 11B6; # (졣; 졣; 졣; 졣; 졣; ) HANGUL SYLLABLE JYELH +C864;C864;110C 1168 11B7;C864;110C 1168 11B7; # (졤; 졤; 졤; 졤; 졤; ) HANGUL SYLLABLE JYEM +C865;C865;110C 1168 11B8;C865;110C 1168 11B8; # (졥; 졥; 졥; 졥; 졥; ) HANGUL SYLLABLE JYEB +C866;C866;110C 1168 11B9;C866;110C 1168 11B9; # (졦; 졦; 졦; 졦; 졦; ) HANGUL SYLLABLE JYEBS +C867;C867;110C 1168 11BA;C867;110C 1168 11BA; # (졧; 졧; 졧; 졧; 졧; ) HANGUL SYLLABLE JYES +C868;C868;110C 1168 11BB;C868;110C 1168 11BB; # (졨; 졨; 졨; 졨; 졨; ) HANGUL SYLLABLE JYESS +C869;C869;110C 1168 11BC;C869;110C 1168 11BC; # (졩; 졩; 졩; 졩; 졩; ) HANGUL SYLLABLE JYENG +C86A;C86A;110C 1168 11BD;C86A;110C 1168 11BD; # (졪; 졪; 졪; 졪; 졪; ) HANGUL SYLLABLE JYEJ +C86B;C86B;110C 1168 11BE;C86B;110C 1168 11BE; # (졫; 졫; 졫; 졫; 졫; ) HANGUL SYLLABLE JYEC +C86C;C86C;110C 1168 11BF;C86C;110C 1168 11BF; # (졬; 졬; 졬; 졬; 졬; ) HANGUL SYLLABLE JYEK +C86D;C86D;110C 1168 11C0;C86D;110C 1168 11C0; # (졭; 졭; 졭; 졭; 졭; ) HANGUL SYLLABLE JYET +C86E;C86E;110C 1168 11C1;C86E;110C 1168 11C1; # (졮; 졮; 졮; 졮; 졮; ) HANGUL SYLLABLE JYEP +C86F;C86F;110C 1168 11C2;C86F;110C 1168 11C2; # (졯; 졯; 졯; 졯; 졯; ) HANGUL SYLLABLE JYEH +C870;C870;110C 1169;C870;110C 1169; # (조; 조; 조; 조; 조; ) HANGUL SYLLABLE JO +C871;C871;110C 1169 11A8;C871;110C 1169 11A8; # (족; 족; 족; 족; 족; ) HANGUL SYLLABLE JOG +C872;C872;110C 1169 11A9;C872;110C 1169 11A9; # (졲; 졲; 졲; 졲; 졲; ) HANGUL SYLLABLE JOGG +C873;C873;110C 1169 11AA;C873;110C 1169 11AA; # (졳; 졳; 졳; 졳; 졳; ) HANGUL SYLLABLE JOGS +C874;C874;110C 1169 11AB;C874;110C 1169 11AB; # (존; 존; 존; 존; 존; ) HANGUL SYLLABLE JON +C875;C875;110C 1169 11AC;C875;110C 1169 11AC; # (졵; 졵; 졵; 졵; 졵; ) HANGUL SYLLABLE JONJ +C876;C876;110C 1169 11AD;C876;110C 1169 11AD; # (졶; 졶; 졶; 졶; 졶; ) HANGUL SYLLABLE JONH +C877;C877;110C 1169 11AE;C877;110C 1169 11AE; # (졷; 졷; 졷; 졷; 졷; ) HANGUL SYLLABLE JOD +C878;C878;110C 1169 11AF;C878;110C 1169 11AF; # (졸; 졸; 졸; 졸; 졸; ) HANGUL SYLLABLE JOL +C879;C879;110C 1169 11B0;C879;110C 1169 11B0; # (졹; 졹; 졹; 졹; 졹; ) HANGUL SYLLABLE JOLG +C87A;C87A;110C 1169 11B1;C87A;110C 1169 11B1; # (졺; 졺; 졺; 졺; 졺; ) HANGUL SYLLABLE JOLM +C87B;C87B;110C 1169 11B2;C87B;110C 1169 11B2; # (졻; 졻; 졻; 졻; 졻; ) HANGUL SYLLABLE JOLB +C87C;C87C;110C 1169 11B3;C87C;110C 1169 11B3; # (졼; 졼; 졼; 졼; 졼; ) HANGUL SYLLABLE JOLS +C87D;C87D;110C 1169 11B4;C87D;110C 1169 11B4; # (졽; 졽; 졽; 졽; 졽; ) HANGUL SYLLABLE JOLT +C87E;C87E;110C 1169 11B5;C87E;110C 1169 11B5; # (졾; 졾; 졾; 졾; 졾; ) HANGUL SYLLABLE JOLP +C87F;C87F;110C 1169 11B6;C87F;110C 1169 11B6; # (졿; 졿; 졿; 졿; 졿; ) HANGUL SYLLABLE JOLH +C880;C880;110C 1169 11B7;C880;110C 1169 11B7; # (좀; 좀; 좀; 좀; 좀; ) HANGUL SYLLABLE JOM +C881;C881;110C 1169 11B8;C881;110C 1169 11B8; # (좁; 좁; 좁; 좁; 좁; ) HANGUL SYLLABLE JOB +C882;C882;110C 1169 11B9;C882;110C 1169 11B9; # (좂; 좂; 좂; 좂; 좂; ) HANGUL SYLLABLE JOBS +C883;C883;110C 1169 11BA;C883;110C 1169 11BA; # (좃; 좃; 좃; 좃; 좃; ) HANGUL SYLLABLE JOS +C884;C884;110C 1169 11BB;C884;110C 1169 11BB; # (좄; 좄; 좄; 좄; 좄; ) HANGUL SYLLABLE JOSS +C885;C885;110C 1169 11BC;C885;110C 1169 11BC; # (종; 종; 종; 종; 종; ) HANGUL SYLLABLE JONG +C886;C886;110C 1169 11BD;C886;110C 1169 11BD; # (좆; 좆; 좆; 좆; 좆; ) HANGUL SYLLABLE JOJ +C887;C887;110C 1169 11BE;C887;110C 1169 11BE; # (좇; 좇; 좇; 좇; 좇; ) HANGUL SYLLABLE JOC +C888;C888;110C 1169 11BF;C888;110C 1169 11BF; # (좈; 좈; 좈; 좈; 좈; ) HANGUL SYLLABLE JOK +C889;C889;110C 1169 11C0;C889;110C 1169 11C0; # (좉; 좉; 좉; 좉; 좉; ) HANGUL SYLLABLE JOT +C88A;C88A;110C 1169 11C1;C88A;110C 1169 11C1; # (좊; 좊; 좊; 좊; 좊; ) HANGUL SYLLABLE JOP +C88B;C88B;110C 1169 11C2;C88B;110C 1169 11C2; # (좋; 좋; 좋; 좋; 좋; ) HANGUL SYLLABLE JOH +C88C;C88C;110C 116A;C88C;110C 116A; # (좌; 좌; 좌; 좌; 좌; ) HANGUL SYLLABLE JWA +C88D;C88D;110C 116A 11A8;C88D;110C 116A 11A8; # (좍; 좍; 좍; 좍; 좍; ) HANGUL SYLLABLE JWAG +C88E;C88E;110C 116A 11A9;C88E;110C 116A 11A9; # (좎; 좎; 좎; 좎; 좎; ) HANGUL SYLLABLE JWAGG +C88F;C88F;110C 116A 11AA;C88F;110C 116A 11AA; # (좏; 좏; 좏; 좏; 좏; ) HANGUL SYLLABLE JWAGS +C890;C890;110C 116A 11AB;C890;110C 116A 11AB; # (좐; 좐; 좐; 좐; 좐; ) HANGUL SYLLABLE JWAN +C891;C891;110C 116A 11AC;C891;110C 116A 11AC; # (좑; 좑; 좑; 좑; 좑; ) HANGUL SYLLABLE JWANJ +C892;C892;110C 116A 11AD;C892;110C 116A 11AD; # (좒; 좒; 좒; 좒; 좒; ) HANGUL SYLLABLE JWANH +C893;C893;110C 116A 11AE;C893;110C 116A 11AE; # (좓; 좓; 좓; 좓; 좓; ) HANGUL SYLLABLE JWAD +C894;C894;110C 116A 11AF;C894;110C 116A 11AF; # (좔; 좔; 좔; 좔; 좔; ) HANGUL SYLLABLE JWAL +C895;C895;110C 116A 11B0;C895;110C 116A 11B0; # (좕; 좕; 좕; 좕; 좕; ) HANGUL SYLLABLE JWALG +C896;C896;110C 116A 11B1;C896;110C 116A 11B1; # (좖; 좖; 좖; 좖; 좖; ) HANGUL SYLLABLE JWALM +C897;C897;110C 116A 11B2;C897;110C 116A 11B2; # (좗; 좗; 좗; 좗; 좗; ) HANGUL SYLLABLE JWALB +C898;C898;110C 116A 11B3;C898;110C 116A 11B3; # (좘; 좘; 좘; 좘; 좘; ) HANGUL SYLLABLE JWALS +C899;C899;110C 116A 11B4;C899;110C 116A 11B4; # (좙; 좙; 좙; 좙; 좙; ) HANGUL SYLLABLE JWALT +C89A;C89A;110C 116A 11B5;C89A;110C 116A 11B5; # (좚; 좚; 좚; 좚; 좚; ) HANGUL SYLLABLE JWALP +C89B;C89B;110C 116A 11B6;C89B;110C 116A 11B6; # (좛; 좛; 좛; 좛; 좛; ) HANGUL SYLLABLE JWALH +C89C;C89C;110C 116A 11B7;C89C;110C 116A 11B7; # (좜; 좜; 좜; 좜; 좜; ) HANGUL SYLLABLE JWAM +C89D;C89D;110C 116A 11B8;C89D;110C 116A 11B8; # (좝; 좝; 좝; 좝; 좝; ) HANGUL SYLLABLE JWAB +C89E;C89E;110C 116A 11B9;C89E;110C 116A 11B9; # (좞; 좞; 좞; 좞; 좞; ) HANGUL SYLLABLE JWABS +C89F;C89F;110C 116A 11BA;C89F;110C 116A 11BA; # (좟; 좟; 좟; 좟; 좟; ) HANGUL SYLLABLE JWAS +C8A0;C8A0;110C 116A 11BB;C8A0;110C 116A 11BB; # (좠; 좠; 좠; 좠; 좠; ) HANGUL SYLLABLE JWASS +C8A1;C8A1;110C 116A 11BC;C8A1;110C 116A 11BC; # (좡; 좡; 좡; 좡; 좡; ) HANGUL SYLLABLE JWANG +C8A2;C8A2;110C 116A 11BD;C8A2;110C 116A 11BD; # (좢; 좢; 좢; 좢; 좢; ) HANGUL SYLLABLE JWAJ +C8A3;C8A3;110C 116A 11BE;C8A3;110C 116A 11BE; # (좣; 좣; 좣; 좣; 좣; ) HANGUL SYLLABLE JWAC +C8A4;C8A4;110C 116A 11BF;C8A4;110C 116A 11BF; # (좤; 좤; 좤; 좤; 좤; ) HANGUL SYLLABLE JWAK +C8A5;C8A5;110C 116A 11C0;C8A5;110C 116A 11C0; # (좥; 좥; 좥; 좥; 좥; ) HANGUL SYLLABLE JWAT +C8A6;C8A6;110C 116A 11C1;C8A6;110C 116A 11C1; # (좦; 좦; 좦; 좦; 좦; ) HANGUL SYLLABLE JWAP +C8A7;C8A7;110C 116A 11C2;C8A7;110C 116A 11C2; # (좧; 좧; 좧; 좧; 좧; ) HANGUL SYLLABLE JWAH +C8A8;C8A8;110C 116B;C8A8;110C 116B; # (좨; 좨; 좨; 좨; 좨; ) HANGUL SYLLABLE JWAE +C8A9;C8A9;110C 116B 11A8;C8A9;110C 116B 11A8; # (좩; 좩; 좩; 좩; 좩; ) HANGUL SYLLABLE JWAEG +C8AA;C8AA;110C 116B 11A9;C8AA;110C 116B 11A9; # (좪; 좪; 좪; 좪; 좪; ) HANGUL SYLLABLE JWAEGG +C8AB;C8AB;110C 116B 11AA;C8AB;110C 116B 11AA; # (좫; 좫; 좫; 좫; 좫; ) HANGUL SYLLABLE JWAEGS +C8AC;C8AC;110C 116B 11AB;C8AC;110C 116B 11AB; # (좬; 좬; 좬; 좬; 좬; ) HANGUL SYLLABLE JWAEN +C8AD;C8AD;110C 116B 11AC;C8AD;110C 116B 11AC; # (좭; 좭; 좭; 좭; 좭; ) HANGUL SYLLABLE JWAENJ +C8AE;C8AE;110C 116B 11AD;C8AE;110C 116B 11AD; # (좮; 좮; 좮; 좮; 좮; ) HANGUL SYLLABLE JWAENH +C8AF;C8AF;110C 116B 11AE;C8AF;110C 116B 11AE; # (좯; 좯; 좯; 좯; 좯; ) HANGUL SYLLABLE JWAED +C8B0;C8B0;110C 116B 11AF;C8B0;110C 116B 11AF; # (좰; 좰; 좰; 좰; 좰; ) HANGUL SYLLABLE JWAEL +C8B1;C8B1;110C 116B 11B0;C8B1;110C 116B 11B0; # (좱; 좱; 좱; 좱; 좱; ) HANGUL SYLLABLE JWAELG +C8B2;C8B2;110C 116B 11B1;C8B2;110C 116B 11B1; # (좲; 좲; 좲; 좲; 좲; ) HANGUL SYLLABLE JWAELM +C8B3;C8B3;110C 116B 11B2;C8B3;110C 116B 11B2; # (좳; 좳; 좳; 좳; 좳; ) HANGUL SYLLABLE JWAELB +C8B4;C8B4;110C 116B 11B3;C8B4;110C 116B 11B3; # (좴; 좴; 좴; 좴; 좴; ) HANGUL SYLLABLE JWAELS +C8B5;C8B5;110C 116B 11B4;C8B5;110C 116B 11B4; # (좵; 좵; 좵; 좵; 좵; ) HANGUL SYLLABLE JWAELT +C8B6;C8B6;110C 116B 11B5;C8B6;110C 116B 11B5; # (좶; 좶; 좶; 좶; 좶; ) HANGUL SYLLABLE JWAELP +C8B7;C8B7;110C 116B 11B6;C8B7;110C 116B 11B6; # (좷; 좷; 좷; 좷; 좷; ) HANGUL SYLLABLE JWAELH +C8B8;C8B8;110C 116B 11B7;C8B8;110C 116B 11B7; # (좸; 좸; 좸; 좸; 좸; ) HANGUL SYLLABLE JWAEM +C8B9;C8B9;110C 116B 11B8;C8B9;110C 116B 11B8; # (좹; 좹; 좹; 좹; 좹; ) HANGUL SYLLABLE JWAEB +C8BA;C8BA;110C 116B 11B9;C8BA;110C 116B 11B9; # (좺; 좺; 좺; 좺; 좺; ) HANGUL SYLLABLE JWAEBS +C8BB;C8BB;110C 116B 11BA;C8BB;110C 116B 11BA; # (좻; 좻; 좻; 좻; 좻; ) HANGUL SYLLABLE JWAES +C8BC;C8BC;110C 116B 11BB;C8BC;110C 116B 11BB; # (좼; 좼; 좼; 좼; 좼; ) HANGUL SYLLABLE JWAESS +C8BD;C8BD;110C 116B 11BC;C8BD;110C 116B 11BC; # (좽; 좽; 좽; 좽; 좽; ) HANGUL SYLLABLE JWAENG +C8BE;C8BE;110C 116B 11BD;C8BE;110C 116B 11BD; # (좾; 좾; 좾; 좾; 좾; ) HANGUL SYLLABLE JWAEJ +C8BF;C8BF;110C 116B 11BE;C8BF;110C 116B 11BE; # (좿; 좿; 좿; 좿; 좿; ) HANGUL SYLLABLE JWAEC +C8C0;C8C0;110C 116B 11BF;C8C0;110C 116B 11BF; # (죀; 죀; 죀; 죀; 죀; ) HANGUL SYLLABLE JWAEK +C8C1;C8C1;110C 116B 11C0;C8C1;110C 116B 11C0; # (죁; 죁; 죁; 죁; 죁; ) HANGUL SYLLABLE JWAET +C8C2;C8C2;110C 116B 11C1;C8C2;110C 116B 11C1; # (죂; 죂; 죂; 죂; 죂; ) HANGUL SYLLABLE JWAEP +C8C3;C8C3;110C 116B 11C2;C8C3;110C 116B 11C2; # (죃; 죃; 죃; 죃; 죃; ) HANGUL SYLLABLE JWAEH +C8C4;C8C4;110C 116C;C8C4;110C 116C; # (죄; 죄; 죄; 죄; 죄; ) HANGUL SYLLABLE JOE +C8C5;C8C5;110C 116C 11A8;C8C5;110C 116C 11A8; # (죅; 죅; 죅; 죅; 죅; ) HANGUL SYLLABLE JOEG +C8C6;C8C6;110C 116C 11A9;C8C6;110C 116C 11A9; # (죆; 죆; 죆; 죆; 죆; ) HANGUL SYLLABLE JOEGG +C8C7;C8C7;110C 116C 11AA;C8C7;110C 116C 11AA; # (죇; 죇; 죇; 죇; 죇; ) HANGUL SYLLABLE JOEGS +C8C8;C8C8;110C 116C 11AB;C8C8;110C 116C 11AB; # (죈; 죈; 죈; 죈; 죈; ) HANGUL SYLLABLE JOEN +C8C9;C8C9;110C 116C 11AC;C8C9;110C 116C 11AC; # (죉; 죉; 죉; 죉; 죉; ) HANGUL SYLLABLE JOENJ +C8CA;C8CA;110C 116C 11AD;C8CA;110C 116C 11AD; # (죊; 죊; 죊; 죊; 죊; ) HANGUL SYLLABLE JOENH +C8CB;C8CB;110C 116C 11AE;C8CB;110C 116C 11AE; # (죋; 죋; 죋; 죋; 죋; ) HANGUL SYLLABLE JOED +C8CC;C8CC;110C 116C 11AF;C8CC;110C 116C 11AF; # (죌; 죌; 죌; 죌; 죌; ) HANGUL SYLLABLE JOEL +C8CD;C8CD;110C 116C 11B0;C8CD;110C 116C 11B0; # (죍; 죍; 죍; 죍; 죍; ) HANGUL SYLLABLE JOELG +C8CE;C8CE;110C 116C 11B1;C8CE;110C 116C 11B1; # (죎; 죎; 죎; 죎; 죎; ) HANGUL SYLLABLE JOELM +C8CF;C8CF;110C 116C 11B2;C8CF;110C 116C 11B2; # (죏; 죏; 죏; 죏; 죏; ) HANGUL SYLLABLE JOELB +C8D0;C8D0;110C 116C 11B3;C8D0;110C 116C 11B3; # (죐; 죐; 죐; 죐; 죐; ) HANGUL SYLLABLE JOELS +C8D1;C8D1;110C 116C 11B4;C8D1;110C 116C 11B4; # (죑; 죑; 죑; 죑; 죑; ) HANGUL SYLLABLE JOELT +C8D2;C8D2;110C 116C 11B5;C8D2;110C 116C 11B5; # (죒; 죒; 죒; 죒; 죒; ) HANGUL SYLLABLE JOELP +C8D3;C8D3;110C 116C 11B6;C8D3;110C 116C 11B6; # (죓; 죓; 죓; 죓; 죓; ) HANGUL SYLLABLE JOELH +C8D4;C8D4;110C 116C 11B7;C8D4;110C 116C 11B7; # (죔; 죔; 죔; 죔; 죔; ) HANGUL SYLLABLE JOEM +C8D5;C8D5;110C 116C 11B8;C8D5;110C 116C 11B8; # (죕; 죕; 죕; 죕; 죕; ) HANGUL SYLLABLE JOEB +C8D6;C8D6;110C 116C 11B9;C8D6;110C 116C 11B9; # (죖; 죖; 죖; 죖; 죖; ) HANGUL SYLLABLE JOEBS +C8D7;C8D7;110C 116C 11BA;C8D7;110C 116C 11BA; # (죗; 죗; 죗; 죗; 죗; ) HANGUL SYLLABLE JOES +C8D8;C8D8;110C 116C 11BB;C8D8;110C 116C 11BB; # (죘; 죘; 죘; 죘; 죘; ) HANGUL SYLLABLE JOESS +C8D9;C8D9;110C 116C 11BC;C8D9;110C 116C 11BC; # (죙; 죙; 죙; 죙; 죙; ) HANGUL SYLLABLE JOENG +C8DA;C8DA;110C 116C 11BD;C8DA;110C 116C 11BD; # (죚; 죚; 죚; 죚; 죚; ) HANGUL SYLLABLE JOEJ +C8DB;C8DB;110C 116C 11BE;C8DB;110C 116C 11BE; # (죛; 죛; 죛; 죛; 죛; ) HANGUL SYLLABLE JOEC +C8DC;C8DC;110C 116C 11BF;C8DC;110C 116C 11BF; # (죜; 죜; 죜; 죜; 죜; ) HANGUL SYLLABLE JOEK +C8DD;C8DD;110C 116C 11C0;C8DD;110C 116C 11C0; # (죝; 죝; 죝; 죝; 죝; ) HANGUL SYLLABLE JOET +C8DE;C8DE;110C 116C 11C1;C8DE;110C 116C 11C1; # (죞; 죞; 죞; 죞; 죞; ) HANGUL SYLLABLE JOEP +C8DF;C8DF;110C 116C 11C2;C8DF;110C 116C 11C2; # (죟; 죟; 죟; 죟; 죟; ) HANGUL SYLLABLE JOEH +C8E0;C8E0;110C 116D;C8E0;110C 116D; # (죠; 죠; 죠; 죠; 죠; ) HANGUL SYLLABLE JYO +C8E1;C8E1;110C 116D 11A8;C8E1;110C 116D 11A8; # (죡; 죡; 죡; 죡; 죡; ) HANGUL SYLLABLE JYOG +C8E2;C8E2;110C 116D 11A9;C8E2;110C 116D 11A9; # (죢; 죢; 죢; 죢; 죢; ) HANGUL SYLLABLE JYOGG +C8E3;C8E3;110C 116D 11AA;C8E3;110C 116D 11AA; # (죣; 죣; 죣; 죣; 죣; ) HANGUL SYLLABLE JYOGS +C8E4;C8E4;110C 116D 11AB;C8E4;110C 116D 11AB; # (죤; 죤; 죤; 죤; 죤; ) HANGUL SYLLABLE JYON +C8E5;C8E5;110C 116D 11AC;C8E5;110C 116D 11AC; # (죥; 죥; 죥; 죥; 죥; ) HANGUL SYLLABLE JYONJ +C8E6;C8E6;110C 116D 11AD;C8E6;110C 116D 11AD; # (죦; 죦; 죦; 죦; 죦; ) HANGUL SYLLABLE JYONH +C8E7;C8E7;110C 116D 11AE;C8E7;110C 116D 11AE; # (죧; 죧; 죧; 죧; 죧; ) HANGUL SYLLABLE JYOD +C8E8;C8E8;110C 116D 11AF;C8E8;110C 116D 11AF; # (죨; 죨; 죨; 죨; 죨; ) HANGUL SYLLABLE JYOL +C8E9;C8E9;110C 116D 11B0;C8E9;110C 116D 11B0; # (죩; 죩; 죩; 죩; 죩; ) HANGUL SYLLABLE JYOLG +C8EA;C8EA;110C 116D 11B1;C8EA;110C 116D 11B1; # (죪; 죪; 죪; 죪; 죪; ) HANGUL SYLLABLE JYOLM +C8EB;C8EB;110C 116D 11B2;C8EB;110C 116D 11B2; # (죫; 죫; 죫; 죫; 죫; ) HANGUL SYLLABLE JYOLB +C8EC;C8EC;110C 116D 11B3;C8EC;110C 116D 11B3; # (죬; 죬; 죬; 죬; 죬; ) HANGUL SYLLABLE JYOLS +C8ED;C8ED;110C 116D 11B4;C8ED;110C 116D 11B4; # (죭; 죭; 죭; 죭; 죭; ) HANGUL SYLLABLE JYOLT +C8EE;C8EE;110C 116D 11B5;C8EE;110C 116D 11B5; # (죮; 죮; 죮; 죮; 죮; ) HANGUL SYLLABLE JYOLP +C8EF;C8EF;110C 116D 11B6;C8EF;110C 116D 11B6; # (죯; 죯; 죯; 죯; 죯; ) HANGUL SYLLABLE JYOLH +C8F0;C8F0;110C 116D 11B7;C8F0;110C 116D 11B7; # (죰; 죰; 죰; 죰; 죰; ) HANGUL SYLLABLE JYOM +C8F1;C8F1;110C 116D 11B8;C8F1;110C 116D 11B8; # (죱; 죱; 죱; 죱; 죱; ) HANGUL SYLLABLE JYOB +C8F2;C8F2;110C 116D 11B9;C8F2;110C 116D 11B9; # (죲; 죲; 죲; 죲; 죲; ) HANGUL SYLLABLE JYOBS +C8F3;C8F3;110C 116D 11BA;C8F3;110C 116D 11BA; # (죳; 죳; 죳; 죳; 죳; ) HANGUL SYLLABLE JYOS +C8F4;C8F4;110C 116D 11BB;C8F4;110C 116D 11BB; # (죴; 죴; 죴; 죴; 죴; ) HANGUL SYLLABLE JYOSS +C8F5;C8F5;110C 116D 11BC;C8F5;110C 116D 11BC; # (죵; 죵; 죵; 죵; 죵; ) HANGUL SYLLABLE JYONG +C8F6;C8F6;110C 116D 11BD;C8F6;110C 116D 11BD; # (죶; 죶; 죶; 죶; 죶; ) HANGUL SYLLABLE JYOJ +C8F7;C8F7;110C 116D 11BE;C8F7;110C 116D 11BE; # (죷; 죷; 죷; 죷; 죷; ) HANGUL SYLLABLE JYOC +C8F8;C8F8;110C 116D 11BF;C8F8;110C 116D 11BF; # (죸; 죸; 죸; 죸; 죸; ) HANGUL SYLLABLE JYOK +C8F9;C8F9;110C 116D 11C0;C8F9;110C 116D 11C0; # (죹; 죹; 죹; 죹; 죹; ) HANGUL SYLLABLE JYOT +C8FA;C8FA;110C 116D 11C1;C8FA;110C 116D 11C1; # (죺; 죺; 죺; 죺; 죺; ) HANGUL SYLLABLE JYOP +C8FB;C8FB;110C 116D 11C2;C8FB;110C 116D 11C2; # (죻; 죻; 죻; 죻; 죻; ) HANGUL SYLLABLE JYOH +C8FC;C8FC;110C 116E;C8FC;110C 116E; # (주; 주; 주; 주; 주; ) HANGUL SYLLABLE JU +C8FD;C8FD;110C 116E 11A8;C8FD;110C 116E 11A8; # (죽; 죽; 죽; 죽; 죽; ) HANGUL SYLLABLE JUG +C8FE;C8FE;110C 116E 11A9;C8FE;110C 116E 11A9; # (죾; 죾; 죾; 죾; 죾; ) HANGUL SYLLABLE JUGG +C8FF;C8FF;110C 116E 11AA;C8FF;110C 116E 11AA; # (죿; 죿; 죿; 죿; 죿; ) HANGUL SYLLABLE JUGS +C900;C900;110C 116E 11AB;C900;110C 116E 11AB; # (준; 준; 준; 준; 준; ) HANGUL SYLLABLE JUN +C901;C901;110C 116E 11AC;C901;110C 116E 11AC; # (줁; 줁; 줁; 줁; 줁; ) HANGUL SYLLABLE JUNJ +C902;C902;110C 116E 11AD;C902;110C 116E 11AD; # (줂; 줂; 줂; 줂; 줂; ) HANGUL SYLLABLE JUNH +C903;C903;110C 116E 11AE;C903;110C 116E 11AE; # (줃; 줃; 줃; 줃; 줃; ) HANGUL SYLLABLE JUD +C904;C904;110C 116E 11AF;C904;110C 116E 11AF; # (줄; 줄; 줄; 줄; 줄; ) HANGUL SYLLABLE JUL +C905;C905;110C 116E 11B0;C905;110C 116E 11B0; # (줅; 줅; 줅; 줅; 줅; ) HANGUL SYLLABLE JULG +C906;C906;110C 116E 11B1;C906;110C 116E 11B1; # (줆; 줆; 줆; 줆; 줆; ) HANGUL SYLLABLE JULM +C907;C907;110C 116E 11B2;C907;110C 116E 11B2; # (줇; 줇; 줇; 줇; 줇; ) HANGUL SYLLABLE JULB +C908;C908;110C 116E 11B3;C908;110C 116E 11B3; # (줈; 줈; 줈; 줈; 줈; ) HANGUL SYLLABLE JULS +C909;C909;110C 116E 11B4;C909;110C 116E 11B4; # (줉; 줉; 줉; 줉; 줉; ) HANGUL SYLLABLE JULT +C90A;C90A;110C 116E 11B5;C90A;110C 116E 11B5; # (줊; 줊; 줊; 줊; 줊; ) HANGUL SYLLABLE JULP +C90B;C90B;110C 116E 11B6;C90B;110C 116E 11B6; # (줋; 줋; 줋; 줋; 줋; ) HANGUL SYLLABLE JULH +C90C;C90C;110C 116E 11B7;C90C;110C 116E 11B7; # (줌; 줌; 줌; 줌; 줌; ) HANGUL SYLLABLE JUM +C90D;C90D;110C 116E 11B8;C90D;110C 116E 11B8; # (줍; 줍; 줍; 줍; 줍; ) HANGUL SYLLABLE JUB +C90E;C90E;110C 116E 11B9;C90E;110C 116E 11B9; # (줎; 줎; 줎; 줎; 줎; ) HANGUL SYLLABLE JUBS +C90F;C90F;110C 116E 11BA;C90F;110C 116E 11BA; # (줏; 줏; 줏; 줏; 줏; ) HANGUL SYLLABLE JUS +C910;C910;110C 116E 11BB;C910;110C 116E 11BB; # (줐; 줐; 줐; 줐; 줐; ) HANGUL SYLLABLE JUSS +C911;C911;110C 116E 11BC;C911;110C 116E 11BC; # (중; 중; 중; 중; 중; ) HANGUL SYLLABLE JUNG +C912;C912;110C 116E 11BD;C912;110C 116E 11BD; # (줒; 줒; 줒; 줒; 줒; ) HANGUL SYLLABLE JUJ +C913;C913;110C 116E 11BE;C913;110C 116E 11BE; # (줓; 줓; 줓; 줓; 줓; ) HANGUL SYLLABLE JUC +C914;C914;110C 116E 11BF;C914;110C 116E 11BF; # (줔; 줔; 줔; 줔; 줔; ) HANGUL SYLLABLE JUK +C915;C915;110C 116E 11C0;C915;110C 116E 11C0; # (줕; 줕; 줕; 줕; 줕; ) HANGUL SYLLABLE JUT +C916;C916;110C 116E 11C1;C916;110C 116E 11C1; # (줖; 줖; 줖; 줖; 줖; ) HANGUL SYLLABLE JUP +C917;C917;110C 116E 11C2;C917;110C 116E 11C2; # (줗; 줗; 줗; 줗; 줗; ) HANGUL SYLLABLE JUH +C918;C918;110C 116F;C918;110C 116F; # (줘; 줘; 줘; 줘; 줘; ) HANGUL SYLLABLE JWEO +C919;C919;110C 116F 11A8;C919;110C 116F 11A8; # (줙; 줙; 줙; 줙; 줙; ) HANGUL SYLLABLE JWEOG +C91A;C91A;110C 116F 11A9;C91A;110C 116F 11A9; # (줚; 줚; 줚; 줚; 줚; ) HANGUL SYLLABLE JWEOGG +C91B;C91B;110C 116F 11AA;C91B;110C 116F 11AA; # (줛; 줛; 줛; 줛; 줛; ) HANGUL SYLLABLE JWEOGS +C91C;C91C;110C 116F 11AB;C91C;110C 116F 11AB; # (줜; 줜; 줜; 줜; 줜; ) HANGUL SYLLABLE JWEON +C91D;C91D;110C 116F 11AC;C91D;110C 116F 11AC; # (줝; 줝; 줝; 줝; 줝; ) HANGUL SYLLABLE JWEONJ +C91E;C91E;110C 116F 11AD;C91E;110C 116F 11AD; # (줞; 줞; 줞; 줞; 줞; ) HANGUL SYLLABLE JWEONH +C91F;C91F;110C 116F 11AE;C91F;110C 116F 11AE; # (줟; 줟; 줟; 줟; 줟; ) HANGUL SYLLABLE JWEOD +C920;C920;110C 116F 11AF;C920;110C 116F 11AF; # (줠; 줠; 줠; 줠; 줠; ) HANGUL SYLLABLE JWEOL +C921;C921;110C 116F 11B0;C921;110C 116F 11B0; # (줡; 줡; 줡; 줡; 줡; ) HANGUL SYLLABLE JWEOLG +C922;C922;110C 116F 11B1;C922;110C 116F 11B1; # (줢; 줢; 줢; 줢; 줢; ) HANGUL SYLLABLE JWEOLM +C923;C923;110C 116F 11B2;C923;110C 116F 11B2; # (줣; 줣; 줣; 줣; 줣; ) HANGUL SYLLABLE JWEOLB +C924;C924;110C 116F 11B3;C924;110C 116F 11B3; # (줤; 줤; 줤; 줤; 줤; ) HANGUL SYLLABLE JWEOLS +C925;C925;110C 116F 11B4;C925;110C 116F 11B4; # (줥; 줥; 줥; 줥; 줥; ) HANGUL SYLLABLE JWEOLT +C926;C926;110C 116F 11B5;C926;110C 116F 11B5; # (줦; 줦; 줦; 줦; 줦; ) HANGUL SYLLABLE JWEOLP +C927;C927;110C 116F 11B6;C927;110C 116F 11B6; # (줧; 줧; 줧; 줧; 줧; ) HANGUL SYLLABLE JWEOLH +C928;C928;110C 116F 11B7;C928;110C 116F 11B7; # (줨; 줨; 줨; 줨; 줨; ) HANGUL SYLLABLE JWEOM +C929;C929;110C 116F 11B8;C929;110C 116F 11B8; # (줩; 줩; 줩; 줩; 줩; ) HANGUL SYLLABLE JWEOB +C92A;C92A;110C 116F 11B9;C92A;110C 116F 11B9; # (줪; 줪; 줪; 줪; 줪; ) HANGUL SYLLABLE JWEOBS +C92B;C92B;110C 116F 11BA;C92B;110C 116F 11BA; # (줫; 줫; 줫; 줫; 줫; ) HANGUL SYLLABLE JWEOS +C92C;C92C;110C 116F 11BB;C92C;110C 116F 11BB; # (줬; 줬; 줬; 줬; 줬; ) HANGUL SYLLABLE JWEOSS +C92D;C92D;110C 116F 11BC;C92D;110C 116F 11BC; # (줭; 줭; 줭; 줭; 줭; ) HANGUL SYLLABLE JWEONG +C92E;C92E;110C 116F 11BD;C92E;110C 116F 11BD; # (줮; 줮; 줮; 줮; 줮; ) HANGUL SYLLABLE JWEOJ +C92F;C92F;110C 116F 11BE;C92F;110C 116F 11BE; # (줯; 줯; 줯; 줯; 줯; ) HANGUL SYLLABLE JWEOC +C930;C930;110C 116F 11BF;C930;110C 116F 11BF; # (줰; 줰; 줰; 줰; 줰; ) HANGUL SYLLABLE JWEOK +C931;C931;110C 116F 11C0;C931;110C 116F 11C0; # (줱; 줱; 줱; 줱; 줱; ) HANGUL SYLLABLE JWEOT +C932;C932;110C 116F 11C1;C932;110C 116F 11C1; # (줲; 줲; 줲; 줲; 줲; ) HANGUL SYLLABLE JWEOP +C933;C933;110C 116F 11C2;C933;110C 116F 11C2; # (줳; 줳; 줳; 줳; 줳; ) HANGUL SYLLABLE JWEOH +C934;C934;110C 1170;C934;110C 1170; # (줴; 줴; 줴; 줴; 줴; ) HANGUL SYLLABLE JWE +C935;C935;110C 1170 11A8;C935;110C 1170 11A8; # (줵; 줵; 줵; 줵; 줵; ) HANGUL SYLLABLE JWEG +C936;C936;110C 1170 11A9;C936;110C 1170 11A9; # (줶; 줶; 줶; 줶; 줶; ) HANGUL SYLLABLE JWEGG +C937;C937;110C 1170 11AA;C937;110C 1170 11AA; # (줷; 줷; 줷; 줷; 줷; ) HANGUL SYLLABLE JWEGS +C938;C938;110C 1170 11AB;C938;110C 1170 11AB; # (줸; 줸; 줸; 줸; 줸; ) HANGUL SYLLABLE JWEN +C939;C939;110C 1170 11AC;C939;110C 1170 11AC; # (줹; 줹; 줹; 줹; 줹; ) HANGUL SYLLABLE JWENJ +C93A;C93A;110C 1170 11AD;C93A;110C 1170 11AD; # (줺; 줺; 줺; 줺; 줺; ) HANGUL SYLLABLE JWENH +C93B;C93B;110C 1170 11AE;C93B;110C 1170 11AE; # (줻; 줻; 줻; 줻; 줻; ) HANGUL SYLLABLE JWED +C93C;C93C;110C 1170 11AF;C93C;110C 1170 11AF; # (줼; 줼; 줼; 줼; 줼; ) HANGUL SYLLABLE JWEL +C93D;C93D;110C 1170 11B0;C93D;110C 1170 11B0; # (줽; 줽; 줽; 줽; 줽; ) HANGUL SYLLABLE JWELG +C93E;C93E;110C 1170 11B1;C93E;110C 1170 11B1; # (줾; 줾; 줾; 줾; 줾; ) HANGUL SYLLABLE JWELM +C93F;C93F;110C 1170 11B2;C93F;110C 1170 11B2; # (줿; 줿; 줿; 줿; 줿; ) HANGUL SYLLABLE JWELB +C940;C940;110C 1170 11B3;C940;110C 1170 11B3; # (쥀; 쥀; 쥀; 쥀; 쥀; ) HANGUL SYLLABLE JWELS +C941;C941;110C 1170 11B4;C941;110C 1170 11B4; # (쥁; 쥁; 쥁; 쥁; 쥁; ) HANGUL SYLLABLE JWELT +C942;C942;110C 1170 11B5;C942;110C 1170 11B5; # (쥂; 쥂; 쥂; 쥂; 쥂; ) HANGUL SYLLABLE JWELP +C943;C943;110C 1170 11B6;C943;110C 1170 11B6; # (쥃; 쥃; 쥃; 쥃; 쥃; ) HANGUL SYLLABLE JWELH +C944;C944;110C 1170 11B7;C944;110C 1170 11B7; # (쥄; 쥄; 쥄; 쥄; 쥄; ) HANGUL SYLLABLE JWEM +C945;C945;110C 1170 11B8;C945;110C 1170 11B8; # (쥅; 쥅; 쥅; 쥅; 쥅; ) HANGUL SYLLABLE JWEB +C946;C946;110C 1170 11B9;C946;110C 1170 11B9; # (쥆; 쥆; 쥆; 쥆; 쥆; ) HANGUL SYLLABLE JWEBS +C947;C947;110C 1170 11BA;C947;110C 1170 11BA; # (쥇; 쥇; 쥇; 쥇; 쥇; ) HANGUL SYLLABLE JWES +C948;C948;110C 1170 11BB;C948;110C 1170 11BB; # (쥈; 쥈; 쥈; 쥈; 쥈; ) HANGUL SYLLABLE JWESS +C949;C949;110C 1170 11BC;C949;110C 1170 11BC; # (쥉; 쥉; 쥉; 쥉; 쥉; ) HANGUL SYLLABLE JWENG +C94A;C94A;110C 1170 11BD;C94A;110C 1170 11BD; # (쥊; 쥊; 쥊; 쥊; 쥊; ) HANGUL SYLLABLE JWEJ +C94B;C94B;110C 1170 11BE;C94B;110C 1170 11BE; # (쥋; 쥋; 쥋; 쥋; 쥋; ) HANGUL SYLLABLE JWEC +C94C;C94C;110C 1170 11BF;C94C;110C 1170 11BF; # (쥌; 쥌; 쥌; 쥌; 쥌; ) HANGUL SYLLABLE JWEK +C94D;C94D;110C 1170 11C0;C94D;110C 1170 11C0; # (쥍; 쥍; 쥍; 쥍; 쥍; ) HANGUL SYLLABLE JWET +C94E;C94E;110C 1170 11C1;C94E;110C 1170 11C1; # (쥎; 쥎; 쥎; 쥎; 쥎; ) HANGUL SYLLABLE JWEP +C94F;C94F;110C 1170 11C2;C94F;110C 1170 11C2; # (쥏; 쥏; 쥏; 쥏; 쥏; ) HANGUL SYLLABLE JWEH +C950;C950;110C 1171;C950;110C 1171; # (쥐; 쥐; 쥐; 쥐; 쥐; ) HANGUL SYLLABLE JWI +C951;C951;110C 1171 11A8;C951;110C 1171 11A8; # (쥑; 쥑; 쥑; 쥑; 쥑; ) HANGUL SYLLABLE JWIG +C952;C952;110C 1171 11A9;C952;110C 1171 11A9; # (쥒; 쥒; 쥒; 쥒; 쥒; ) HANGUL SYLLABLE JWIGG +C953;C953;110C 1171 11AA;C953;110C 1171 11AA; # (쥓; 쥓; 쥓; 쥓; 쥓; ) HANGUL SYLLABLE JWIGS +C954;C954;110C 1171 11AB;C954;110C 1171 11AB; # (쥔; 쥔; 쥔; 쥔; 쥔; ) HANGUL SYLLABLE JWIN +C955;C955;110C 1171 11AC;C955;110C 1171 11AC; # (쥕; 쥕; 쥕; 쥕; 쥕; ) HANGUL SYLLABLE JWINJ +C956;C956;110C 1171 11AD;C956;110C 1171 11AD; # (쥖; 쥖; 쥖; 쥖; 쥖; ) HANGUL SYLLABLE JWINH +C957;C957;110C 1171 11AE;C957;110C 1171 11AE; # (쥗; 쥗; 쥗; 쥗; 쥗; ) HANGUL SYLLABLE JWID +C958;C958;110C 1171 11AF;C958;110C 1171 11AF; # (쥘; 쥘; 쥘; 쥘; 쥘; ) HANGUL SYLLABLE JWIL +C959;C959;110C 1171 11B0;C959;110C 1171 11B0; # (쥙; 쥙; 쥙; 쥙; 쥙; ) HANGUL SYLLABLE JWILG +C95A;C95A;110C 1171 11B1;C95A;110C 1171 11B1; # (쥚; 쥚; 쥚; 쥚; 쥚; ) HANGUL SYLLABLE JWILM +C95B;C95B;110C 1171 11B2;C95B;110C 1171 11B2; # (쥛; 쥛; 쥛; 쥛; 쥛; ) HANGUL SYLLABLE JWILB +C95C;C95C;110C 1171 11B3;C95C;110C 1171 11B3; # (쥜; 쥜; 쥜; 쥜; 쥜; ) HANGUL SYLLABLE JWILS +C95D;C95D;110C 1171 11B4;C95D;110C 1171 11B4; # (쥝; 쥝; 쥝; 쥝; 쥝; ) HANGUL SYLLABLE JWILT +C95E;C95E;110C 1171 11B5;C95E;110C 1171 11B5; # (쥞; 쥞; 쥞; 쥞; 쥞; ) HANGUL SYLLABLE JWILP +C95F;C95F;110C 1171 11B6;C95F;110C 1171 11B6; # (쥟; 쥟; 쥟; 쥟; 쥟; ) HANGUL SYLLABLE JWILH +C960;C960;110C 1171 11B7;C960;110C 1171 11B7; # (쥠; 쥠; 쥠; 쥠; 쥠; ) HANGUL SYLLABLE JWIM +C961;C961;110C 1171 11B8;C961;110C 1171 11B8; # (쥡; 쥡; 쥡; 쥡; 쥡; ) HANGUL SYLLABLE JWIB +C962;C962;110C 1171 11B9;C962;110C 1171 11B9; # (쥢; 쥢; 쥢; 쥢; 쥢; ) HANGUL SYLLABLE JWIBS +C963;C963;110C 1171 11BA;C963;110C 1171 11BA; # (쥣; 쥣; 쥣; 쥣; 쥣; ) HANGUL SYLLABLE JWIS +C964;C964;110C 1171 11BB;C964;110C 1171 11BB; # (쥤; 쥤; 쥤; 쥤; 쥤; ) HANGUL SYLLABLE JWISS +C965;C965;110C 1171 11BC;C965;110C 1171 11BC; # (쥥; 쥥; 쥥; 쥥; 쥥; ) HANGUL SYLLABLE JWING +C966;C966;110C 1171 11BD;C966;110C 1171 11BD; # (쥦; 쥦; 쥦; 쥦; 쥦; ) HANGUL SYLLABLE JWIJ +C967;C967;110C 1171 11BE;C967;110C 1171 11BE; # (쥧; 쥧; 쥧; 쥧; 쥧; ) HANGUL SYLLABLE JWIC +C968;C968;110C 1171 11BF;C968;110C 1171 11BF; # (쥨; 쥨; 쥨; 쥨; 쥨; ) HANGUL SYLLABLE JWIK +C969;C969;110C 1171 11C0;C969;110C 1171 11C0; # (쥩; 쥩; 쥩; 쥩; 쥩; ) HANGUL SYLLABLE JWIT +C96A;C96A;110C 1171 11C1;C96A;110C 1171 11C1; # (쥪; 쥪; 쥪; 쥪; 쥪; ) HANGUL SYLLABLE JWIP +C96B;C96B;110C 1171 11C2;C96B;110C 1171 11C2; # (쥫; 쥫; 쥫; 쥫; 쥫; ) HANGUL SYLLABLE JWIH +C96C;C96C;110C 1172;C96C;110C 1172; # (쥬; 쥬; 쥬; 쥬; 쥬; ) HANGUL SYLLABLE JYU +C96D;C96D;110C 1172 11A8;C96D;110C 1172 11A8; # (쥭; 쥭; 쥭; 쥭; 쥭; ) HANGUL SYLLABLE JYUG +C96E;C96E;110C 1172 11A9;C96E;110C 1172 11A9; # (쥮; 쥮; 쥮; 쥮; 쥮; ) HANGUL SYLLABLE JYUGG +C96F;C96F;110C 1172 11AA;C96F;110C 1172 11AA; # (쥯; 쥯; 쥯; 쥯; 쥯; ) HANGUL SYLLABLE JYUGS +C970;C970;110C 1172 11AB;C970;110C 1172 11AB; # (쥰; 쥰; 쥰; 쥰; 쥰; ) HANGUL SYLLABLE JYUN +C971;C971;110C 1172 11AC;C971;110C 1172 11AC; # (쥱; 쥱; 쥱; 쥱; 쥱; ) HANGUL SYLLABLE JYUNJ +C972;C972;110C 1172 11AD;C972;110C 1172 11AD; # (쥲; 쥲; 쥲; 쥲; 쥲; ) HANGUL SYLLABLE JYUNH +C973;C973;110C 1172 11AE;C973;110C 1172 11AE; # (쥳; 쥳; 쥳; 쥳; 쥳; ) HANGUL SYLLABLE JYUD +C974;C974;110C 1172 11AF;C974;110C 1172 11AF; # (쥴; 쥴; 쥴; 쥴; 쥴; ) HANGUL SYLLABLE JYUL +C975;C975;110C 1172 11B0;C975;110C 1172 11B0; # (쥵; 쥵; 쥵; 쥵; 쥵; ) HANGUL SYLLABLE JYULG +C976;C976;110C 1172 11B1;C976;110C 1172 11B1; # (쥶; 쥶; 쥶; 쥶; 쥶; ) HANGUL SYLLABLE JYULM +C977;C977;110C 1172 11B2;C977;110C 1172 11B2; # (쥷; 쥷; 쥷; 쥷; 쥷; ) HANGUL SYLLABLE JYULB +C978;C978;110C 1172 11B3;C978;110C 1172 11B3; # (쥸; 쥸; 쥸; 쥸; 쥸; ) HANGUL SYLLABLE JYULS +C979;C979;110C 1172 11B4;C979;110C 1172 11B4; # (쥹; 쥹; 쥹; 쥹; 쥹; ) HANGUL SYLLABLE JYULT +C97A;C97A;110C 1172 11B5;C97A;110C 1172 11B5; # (쥺; 쥺; 쥺; 쥺; 쥺; ) HANGUL SYLLABLE JYULP +C97B;C97B;110C 1172 11B6;C97B;110C 1172 11B6; # (쥻; 쥻; 쥻; 쥻; 쥻; ) HANGUL SYLLABLE JYULH +C97C;C97C;110C 1172 11B7;C97C;110C 1172 11B7; # (쥼; 쥼; 쥼; 쥼; 쥼; ) HANGUL SYLLABLE JYUM +C97D;C97D;110C 1172 11B8;C97D;110C 1172 11B8; # (쥽; 쥽; 쥽; 쥽; 쥽; ) HANGUL SYLLABLE JYUB +C97E;C97E;110C 1172 11B9;C97E;110C 1172 11B9; # (쥾; 쥾; 쥾; 쥾; 쥾; ) HANGUL SYLLABLE JYUBS +C97F;C97F;110C 1172 11BA;C97F;110C 1172 11BA; # (쥿; 쥿; 쥿; 쥿; 쥿; ) HANGUL SYLLABLE JYUS +C980;C980;110C 1172 11BB;C980;110C 1172 11BB; # (즀; 즀; 즀; 즀; 즀; ) HANGUL SYLLABLE JYUSS +C981;C981;110C 1172 11BC;C981;110C 1172 11BC; # (즁; 즁; 즁; 즁; 즁; ) HANGUL SYLLABLE JYUNG +C982;C982;110C 1172 11BD;C982;110C 1172 11BD; # (즂; 즂; 즂; 즂; 즂; ) HANGUL SYLLABLE JYUJ +C983;C983;110C 1172 11BE;C983;110C 1172 11BE; # (즃; 즃; 즃; 즃; 즃; ) HANGUL SYLLABLE JYUC +C984;C984;110C 1172 11BF;C984;110C 1172 11BF; # (즄; 즄; 즄; 즄; 즄; ) HANGUL SYLLABLE JYUK +C985;C985;110C 1172 11C0;C985;110C 1172 11C0; # (즅; 즅; 즅; 즅; 즅; ) HANGUL SYLLABLE JYUT +C986;C986;110C 1172 11C1;C986;110C 1172 11C1; # (즆; 즆; 즆; 즆; 즆; ) HANGUL SYLLABLE JYUP +C987;C987;110C 1172 11C2;C987;110C 1172 11C2; # (즇; 즇; 즇; 즇; 즇; ) HANGUL SYLLABLE JYUH +C988;C988;110C 1173;C988;110C 1173; # (즈; 즈; 즈; 즈; 즈; ) HANGUL SYLLABLE JEU +C989;C989;110C 1173 11A8;C989;110C 1173 11A8; # (즉; 즉; 즉; 즉; 즉; ) HANGUL SYLLABLE JEUG +C98A;C98A;110C 1173 11A9;C98A;110C 1173 11A9; # (즊; 즊; 즊; 즊; 즊; ) HANGUL SYLLABLE JEUGG +C98B;C98B;110C 1173 11AA;C98B;110C 1173 11AA; # (즋; 즋; 즋; 즋; 즋; ) HANGUL SYLLABLE JEUGS +C98C;C98C;110C 1173 11AB;C98C;110C 1173 11AB; # (즌; 즌; 즌; 즌; 즌; ) HANGUL SYLLABLE JEUN +C98D;C98D;110C 1173 11AC;C98D;110C 1173 11AC; # (즍; 즍; 즍; 즍; 즍; ) HANGUL SYLLABLE JEUNJ +C98E;C98E;110C 1173 11AD;C98E;110C 1173 11AD; # (즎; 즎; 즎; 즎; 즎; ) HANGUL SYLLABLE JEUNH +C98F;C98F;110C 1173 11AE;C98F;110C 1173 11AE; # (즏; 즏; 즏; 즏; 즏; ) HANGUL SYLLABLE JEUD +C990;C990;110C 1173 11AF;C990;110C 1173 11AF; # (즐; 즐; 즐; 즐; 즐; ) HANGUL SYLLABLE JEUL +C991;C991;110C 1173 11B0;C991;110C 1173 11B0; # (즑; 즑; 즑; 즑; 즑; ) HANGUL SYLLABLE JEULG +C992;C992;110C 1173 11B1;C992;110C 1173 11B1; # (즒; 즒; 즒; 즒; 즒; ) HANGUL SYLLABLE JEULM +C993;C993;110C 1173 11B2;C993;110C 1173 11B2; # (즓; 즓; 즓; 즓; 즓; ) HANGUL SYLLABLE JEULB +C994;C994;110C 1173 11B3;C994;110C 1173 11B3; # (즔; 즔; 즔; 즔; 즔; ) HANGUL SYLLABLE JEULS +C995;C995;110C 1173 11B4;C995;110C 1173 11B4; # (즕; 즕; 즕; 즕; 즕; ) HANGUL SYLLABLE JEULT +C996;C996;110C 1173 11B5;C996;110C 1173 11B5; # (즖; 즖; 즖; 즖; 즖; ) HANGUL SYLLABLE JEULP +C997;C997;110C 1173 11B6;C997;110C 1173 11B6; # (즗; 즗; 즗; 즗; 즗; ) HANGUL SYLLABLE JEULH +C998;C998;110C 1173 11B7;C998;110C 1173 11B7; # (즘; 즘; 즘; 즘; 즘; ) HANGUL SYLLABLE JEUM +C999;C999;110C 1173 11B8;C999;110C 1173 11B8; # (즙; 즙; 즙; 즙; 즙; ) HANGUL SYLLABLE JEUB +C99A;C99A;110C 1173 11B9;C99A;110C 1173 11B9; # (즚; 즚; 즚; 즚; 즚; ) HANGUL SYLLABLE JEUBS +C99B;C99B;110C 1173 11BA;C99B;110C 1173 11BA; # (즛; 즛; 즛; 즛; 즛; ) HANGUL SYLLABLE JEUS +C99C;C99C;110C 1173 11BB;C99C;110C 1173 11BB; # (즜; 즜; 즜; 즜; 즜; ) HANGUL SYLLABLE JEUSS +C99D;C99D;110C 1173 11BC;C99D;110C 1173 11BC; # (증; 증; 증; 증; 증; ) HANGUL SYLLABLE JEUNG +C99E;C99E;110C 1173 11BD;C99E;110C 1173 11BD; # (즞; 즞; 즞; 즞; 즞; ) HANGUL SYLLABLE JEUJ +C99F;C99F;110C 1173 11BE;C99F;110C 1173 11BE; # (즟; 즟; 즟; 즟; 즟; ) HANGUL SYLLABLE JEUC +C9A0;C9A0;110C 1173 11BF;C9A0;110C 1173 11BF; # (즠; 즠; 즠; 즠; 즠; ) HANGUL SYLLABLE JEUK +C9A1;C9A1;110C 1173 11C0;C9A1;110C 1173 11C0; # (즡; 즡; 즡; 즡; 즡; ) HANGUL SYLLABLE JEUT +C9A2;C9A2;110C 1173 11C1;C9A2;110C 1173 11C1; # (즢; 즢; 즢; 즢; 즢; ) HANGUL SYLLABLE JEUP +C9A3;C9A3;110C 1173 11C2;C9A3;110C 1173 11C2; # (즣; 즣; 즣; 즣; 즣; ) HANGUL SYLLABLE JEUH +C9A4;C9A4;110C 1174;C9A4;110C 1174; # (즤; 즤; 즤; 즤; 즤; ) HANGUL SYLLABLE JYI +C9A5;C9A5;110C 1174 11A8;C9A5;110C 1174 11A8; # (즥; 즥; 즥; 즥; 즥; ) HANGUL SYLLABLE JYIG +C9A6;C9A6;110C 1174 11A9;C9A6;110C 1174 11A9; # (즦; 즦; 즦; 즦; 즦; ) HANGUL SYLLABLE JYIGG +C9A7;C9A7;110C 1174 11AA;C9A7;110C 1174 11AA; # (즧; 즧; 즧; 즧; 즧; ) HANGUL SYLLABLE JYIGS +C9A8;C9A8;110C 1174 11AB;C9A8;110C 1174 11AB; # (즨; 즨; 즨; 즨; 즨; ) HANGUL SYLLABLE JYIN +C9A9;C9A9;110C 1174 11AC;C9A9;110C 1174 11AC; # (즩; 즩; 즩; 즩; 즩; ) HANGUL SYLLABLE JYINJ +C9AA;C9AA;110C 1174 11AD;C9AA;110C 1174 11AD; # (즪; 즪; 즪; 즪; 즪; ) HANGUL SYLLABLE JYINH +C9AB;C9AB;110C 1174 11AE;C9AB;110C 1174 11AE; # (즫; 즫; 즫; 즫; 즫; ) HANGUL SYLLABLE JYID +C9AC;C9AC;110C 1174 11AF;C9AC;110C 1174 11AF; # (즬; 즬; 즬; 즬; 즬; ) HANGUL SYLLABLE JYIL +C9AD;C9AD;110C 1174 11B0;C9AD;110C 1174 11B0; # (즭; 즭; 즭; 즭; 즭; ) HANGUL SYLLABLE JYILG +C9AE;C9AE;110C 1174 11B1;C9AE;110C 1174 11B1; # (즮; 즮; 즮; 즮; 즮; ) HANGUL SYLLABLE JYILM +C9AF;C9AF;110C 1174 11B2;C9AF;110C 1174 11B2; # (즯; 즯; 즯; 즯; 즯; ) HANGUL SYLLABLE JYILB +C9B0;C9B0;110C 1174 11B3;C9B0;110C 1174 11B3; # (즰; 즰; 즰; 즰; 즰; ) HANGUL SYLLABLE JYILS +C9B1;C9B1;110C 1174 11B4;C9B1;110C 1174 11B4; # (즱; 즱; 즱; 즱; 즱; ) HANGUL SYLLABLE JYILT +C9B2;C9B2;110C 1174 11B5;C9B2;110C 1174 11B5; # (즲; 즲; 즲; 즲; 즲; ) HANGUL SYLLABLE JYILP +C9B3;C9B3;110C 1174 11B6;C9B3;110C 1174 11B6; # (즳; 즳; 즳; 즳; 즳; ) HANGUL SYLLABLE JYILH +C9B4;C9B4;110C 1174 11B7;C9B4;110C 1174 11B7; # (즴; 즴; 즴; 즴; 즴; ) HANGUL SYLLABLE JYIM +C9B5;C9B5;110C 1174 11B8;C9B5;110C 1174 11B8; # (즵; 즵; 즵; 즵; 즵; ) HANGUL SYLLABLE JYIB +C9B6;C9B6;110C 1174 11B9;C9B6;110C 1174 11B9; # (즶; 즶; 즶; 즶; 즶; ) HANGUL SYLLABLE JYIBS +C9B7;C9B7;110C 1174 11BA;C9B7;110C 1174 11BA; # (즷; 즷; 즷; 즷; 즷; ) HANGUL SYLLABLE JYIS +C9B8;C9B8;110C 1174 11BB;C9B8;110C 1174 11BB; # (즸; 즸; 즸; 즸; 즸; ) HANGUL SYLLABLE JYISS +C9B9;C9B9;110C 1174 11BC;C9B9;110C 1174 11BC; # (즹; 즹; 즹; 즹; 즹; ) HANGUL SYLLABLE JYING +C9BA;C9BA;110C 1174 11BD;C9BA;110C 1174 11BD; # (즺; 즺; 즺; 즺; 즺; ) HANGUL SYLLABLE JYIJ +C9BB;C9BB;110C 1174 11BE;C9BB;110C 1174 11BE; # (즻; 즻; 즻; 즻; 즻; ) HANGUL SYLLABLE JYIC +C9BC;C9BC;110C 1174 11BF;C9BC;110C 1174 11BF; # (즼; 즼; 즼; 즼; 즼; ) HANGUL SYLLABLE JYIK +C9BD;C9BD;110C 1174 11C0;C9BD;110C 1174 11C0; # (즽; 즽; 즽; 즽; 즽; ) HANGUL SYLLABLE JYIT +C9BE;C9BE;110C 1174 11C1;C9BE;110C 1174 11C1; # (즾; 즾; 즾; 즾; 즾; ) HANGUL SYLLABLE JYIP +C9BF;C9BF;110C 1174 11C2;C9BF;110C 1174 11C2; # (즿; 즿; 즿; 즿; 즿; ) HANGUL SYLLABLE JYIH +C9C0;C9C0;110C 1175;C9C0;110C 1175; # (지; 지; 지; 지; 지; ) HANGUL SYLLABLE JI +C9C1;C9C1;110C 1175 11A8;C9C1;110C 1175 11A8; # (직; 직; 직; 직; 직; ) HANGUL SYLLABLE JIG +C9C2;C9C2;110C 1175 11A9;C9C2;110C 1175 11A9; # (짂; 짂; 짂; 짂; 짂; ) HANGUL SYLLABLE JIGG +C9C3;C9C3;110C 1175 11AA;C9C3;110C 1175 11AA; # (짃; 짃; 짃; 짃; 짃; ) HANGUL SYLLABLE JIGS +C9C4;C9C4;110C 1175 11AB;C9C4;110C 1175 11AB; # (진; 진; 진; 진; 진; ) HANGUL SYLLABLE JIN +C9C5;C9C5;110C 1175 11AC;C9C5;110C 1175 11AC; # (짅; 짅; 짅; 짅; 짅; ) HANGUL SYLLABLE JINJ +C9C6;C9C6;110C 1175 11AD;C9C6;110C 1175 11AD; # (짆; 짆; 짆; 짆; 짆; ) HANGUL SYLLABLE JINH +C9C7;C9C7;110C 1175 11AE;C9C7;110C 1175 11AE; # (짇; 짇; 짇; 짇; 짇; ) HANGUL SYLLABLE JID +C9C8;C9C8;110C 1175 11AF;C9C8;110C 1175 11AF; # (질; 질; 질; 질; 질; ) HANGUL SYLLABLE JIL +C9C9;C9C9;110C 1175 11B0;C9C9;110C 1175 11B0; # (짉; 짉; 짉; 짉; 짉; ) HANGUL SYLLABLE JILG +C9CA;C9CA;110C 1175 11B1;C9CA;110C 1175 11B1; # (짊; 짊; 짊; 짊; 짊; ) HANGUL SYLLABLE JILM +C9CB;C9CB;110C 1175 11B2;C9CB;110C 1175 11B2; # (짋; 짋; 짋; 짋; 짋; ) HANGUL SYLLABLE JILB +C9CC;C9CC;110C 1175 11B3;C9CC;110C 1175 11B3; # (짌; 짌; 짌; 짌; 짌; ) HANGUL SYLLABLE JILS +C9CD;C9CD;110C 1175 11B4;C9CD;110C 1175 11B4; # (짍; 짍; 짍; 짍; 짍; ) HANGUL SYLLABLE JILT +C9CE;C9CE;110C 1175 11B5;C9CE;110C 1175 11B5; # (짎; 짎; 짎; 짎; 짎; ) HANGUL SYLLABLE JILP +C9CF;C9CF;110C 1175 11B6;C9CF;110C 1175 11B6; # (짏; 짏; 짏; 짏; 짏; ) HANGUL SYLLABLE JILH +C9D0;C9D0;110C 1175 11B7;C9D0;110C 1175 11B7; # (짐; 짐; 짐; 짐; 짐; ) HANGUL SYLLABLE JIM +C9D1;C9D1;110C 1175 11B8;C9D1;110C 1175 11B8; # (집; 집; 집; 집; 집; ) HANGUL SYLLABLE JIB +C9D2;C9D2;110C 1175 11B9;C9D2;110C 1175 11B9; # (짒; 짒; 짒; 짒; 짒; ) HANGUL SYLLABLE JIBS +C9D3;C9D3;110C 1175 11BA;C9D3;110C 1175 11BA; # (짓; 짓; 짓; 짓; 짓; ) HANGUL SYLLABLE JIS +C9D4;C9D4;110C 1175 11BB;C9D4;110C 1175 11BB; # (짔; 짔; 짔; 짔; 짔; ) HANGUL SYLLABLE JISS +C9D5;C9D5;110C 1175 11BC;C9D5;110C 1175 11BC; # (징; 징; 징; 징; 징; ) HANGUL SYLLABLE JING +C9D6;C9D6;110C 1175 11BD;C9D6;110C 1175 11BD; # (짖; 짖; 짖; 짖; 짖; ) HANGUL SYLLABLE JIJ +C9D7;C9D7;110C 1175 11BE;C9D7;110C 1175 11BE; # (짗; 짗; 짗; 짗; 짗; ) HANGUL SYLLABLE JIC +C9D8;C9D8;110C 1175 11BF;C9D8;110C 1175 11BF; # (짘; 짘; 짘; 짘; 짘; ) HANGUL SYLLABLE JIK +C9D9;C9D9;110C 1175 11C0;C9D9;110C 1175 11C0; # (짙; 짙; 짙; 짙; 짙; ) HANGUL SYLLABLE JIT +C9DA;C9DA;110C 1175 11C1;C9DA;110C 1175 11C1; # (짚; 짚; 짚; 짚; 짚; ) HANGUL SYLLABLE JIP +C9DB;C9DB;110C 1175 11C2;C9DB;110C 1175 11C2; # (짛; 짛; 짛; 짛; 짛; ) HANGUL SYLLABLE JIH +C9DC;C9DC;110D 1161;C9DC;110D 1161; # (짜; 짜; 짜; 짜; 짜; ) HANGUL SYLLABLE JJA +C9DD;C9DD;110D 1161 11A8;C9DD;110D 1161 11A8; # (짝; 짝; 짝; 짝; 짝; ) HANGUL SYLLABLE JJAG +C9DE;C9DE;110D 1161 11A9;C9DE;110D 1161 11A9; # (짞; 짞; 짞; 짞; 짞; ) HANGUL SYLLABLE JJAGG +C9DF;C9DF;110D 1161 11AA;C9DF;110D 1161 11AA; # (짟; 짟; 짟; 짟; 짟; ) HANGUL SYLLABLE JJAGS +C9E0;C9E0;110D 1161 11AB;C9E0;110D 1161 11AB; # (짠; 짠; 짠; 짠; 짠; ) HANGUL SYLLABLE JJAN +C9E1;C9E1;110D 1161 11AC;C9E1;110D 1161 11AC; # (짡; 짡; 짡; 짡; 짡; ) HANGUL SYLLABLE JJANJ +C9E2;C9E2;110D 1161 11AD;C9E2;110D 1161 11AD; # (짢; 짢; 짢; 짢; 짢; ) HANGUL SYLLABLE JJANH +C9E3;C9E3;110D 1161 11AE;C9E3;110D 1161 11AE; # (짣; 짣; 짣; 짣; 짣; ) HANGUL SYLLABLE JJAD +C9E4;C9E4;110D 1161 11AF;C9E4;110D 1161 11AF; # (짤; 짤; 짤; 짤; 짤; ) HANGUL SYLLABLE JJAL +C9E5;C9E5;110D 1161 11B0;C9E5;110D 1161 11B0; # (짥; 짥; 짥; 짥; 짥; ) HANGUL SYLLABLE JJALG +C9E6;C9E6;110D 1161 11B1;C9E6;110D 1161 11B1; # (짦; 짦; 짦; 짦; 짦; ) HANGUL SYLLABLE JJALM +C9E7;C9E7;110D 1161 11B2;C9E7;110D 1161 11B2; # (짧; 짧; 짧; 짧; 짧; ) HANGUL SYLLABLE JJALB +C9E8;C9E8;110D 1161 11B3;C9E8;110D 1161 11B3; # (짨; 짨; 짨; 짨; 짨; ) HANGUL SYLLABLE JJALS +C9E9;C9E9;110D 1161 11B4;C9E9;110D 1161 11B4; # (짩; 짩; 짩; 짩; 짩; ) HANGUL SYLLABLE JJALT +C9EA;C9EA;110D 1161 11B5;C9EA;110D 1161 11B5; # (짪; 짪; 짪; 짪; 짪; ) HANGUL SYLLABLE JJALP +C9EB;C9EB;110D 1161 11B6;C9EB;110D 1161 11B6; # (짫; 짫; 짫; 짫; 짫; ) HANGUL SYLLABLE JJALH +C9EC;C9EC;110D 1161 11B7;C9EC;110D 1161 11B7; # (짬; 짬; 짬; 짬; 짬; ) HANGUL SYLLABLE JJAM +C9ED;C9ED;110D 1161 11B8;C9ED;110D 1161 11B8; # (짭; 짭; 짭; 짭; 짭; ) HANGUL SYLLABLE JJAB +C9EE;C9EE;110D 1161 11B9;C9EE;110D 1161 11B9; # (짮; 짮; 짮; 짮; 짮; ) HANGUL SYLLABLE JJABS +C9EF;C9EF;110D 1161 11BA;C9EF;110D 1161 11BA; # (짯; 짯; 짯; 짯; 짯; ) HANGUL SYLLABLE JJAS +C9F0;C9F0;110D 1161 11BB;C9F0;110D 1161 11BB; # (짰; 짰; 짰; 짰; 짰; ) HANGUL SYLLABLE JJASS +C9F1;C9F1;110D 1161 11BC;C9F1;110D 1161 11BC; # (짱; 짱; 짱; 짱; 짱; ) HANGUL SYLLABLE JJANG +C9F2;C9F2;110D 1161 11BD;C9F2;110D 1161 11BD; # (짲; 짲; 짲; 짲; 짲; ) HANGUL SYLLABLE JJAJ +C9F3;C9F3;110D 1161 11BE;C9F3;110D 1161 11BE; # (짳; 짳; 짳; 짳; 짳; ) HANGUL SYLLABLE JJAC +C9F4;C9F4;110D 1161 11BF;C9F4;110D 1161 11BF; # (짴; 짴; 짴; 짴; 짴; ) HANGUL SYLLABLE JJAK +C9F5;C9F5;110D 1161 11C0;C9F5;110D 1161 11C0; # (짵; 짵; 짵; 짵; 짵; ) HANGUL SYLLABLE JJAT +C9F6;C9F6;110D 1161 11C1;C9F6;110D 1161 11C1; # (짶; 짶; 짶; 짶; 짶; ) HANGUL SYLLABLE JJAP +C9F7;C9F7;110D 1161 11C2;C9F7;110D 1161 11C2; # (짷; 짷; 짷; 짷; 짷; ) HANGUL SYLLABLE JJAH +C9F8;C9F8;110D 1162;C9F8;110D 1162; # (째; 째; 째; 째; 째; ) HANGUL SYLLABLE JJAE +C9F9;C9F9;110D 1162 11A8;C9F9;110D 1162 11A8; # (짹; 짹; 짹; 짹; 짹; ) HANGUL SYLLABLE JJAEG +C9FA;C9FA;110D 1162 11A9;C9FA;110D 1162 11A9; # (짺; 짺; 짺; 짺; 짺; ) HANGUL SYLLABLE JJAEGG +C9FB;C9FB;110D 1162 11AA;C9FB;110D 1162 11AA; # (짻; 짻; 짻; 짻; 짻; ) HANGUL SYLLABLE JJAEGS +C9FC;C9FC;110D 1162 11AB;C9FC;110D 1162 11AB; # (짼; 짼; 짼; 짼; 짼; ) HANGUL SYLLABLE JJAEN +C9FD;C9FD;110D 1162 11AC;C9FD;110D 1162 11AC; # (짽; 짽; 짽; 짽; 짽; ) HANGUL SYLLABLE JJAENJ +C9FE;C9FE;110D 1162 11AD;C9FE;110D 1162 11AD; # (짾; 짾; 짾; 짾; 짾; ) HANGUL SYLLABLE JJAENH +C9FF;C9FF;110D 1162 11AE;C9FF;110D 1162 11AE; # (짿; 짿; 짿; 짿; 짿; ) HANGUL SYLLABLE JJAED +CA00;CA00;110D 1162 11AF;CA00;110D 1162 11AF; # (쨀; 쨀; 쨀; 쨀; 쨀; ) HANGUL SYLLABLE JJAEL +CA01;CA01;110D 1162 11B0;CA01;110D 1162 11B0; # (쨁; 쨁; 쨁; 쨁; 쨁; ) HANGUL SYLLABLE JJAELG +CA02;CA02;110D 1162 11B1;CA02;110D 1162 11B1; # (쨂; 쨂; 쨂; 쨂; 쨂; ) HANGUL SYLLABLE JJAELM +CA03;CA03;110D 1162 11B2;CA03;110D 1162 11B2; # (쨃; 쨃; 쨃; 쨃; 쨃; ) HANGUL SYLLABLE JJAELB +CA04;CA04;110D 1162 11B3;CA04;110D 1162 11B3; # (쨄; 쨄; 쨄; 쨄; 쨄; ) HANGUL SYLLABLE JJAELS +CA05;CA05;110D 1162 11B4;CA05;110D 1162 11B4; # (쨅; 쨅; 쨅; 쨅; 쨅; ) HANGUL SYLLABLE JJAELT +CA06;CA06;110D 1162 11B5;CA06;110D 1162 11B5; # (쨆; 쨆; 쨆; 쨆; 쨆; ) HANGUL SYLLABLE JJAELP +CA07;CA07;110D 1162 11B6;CA07;110D 1162 11B6; # (쨇; 쨇; 쨇; 쨇; 쨇; ) HANGUL SYLLABLE JJAELH +CA08;CA08;110D 1162 11B7;CA08;110D 1162 11B7; # (쨈; 쨈; 쨈; 쨈; 쨈; ) HANGUL SYLLABLE JJAEM +CA09;CA09;110D 1162 11B8;CA09;110D 1162 11B8; # (쨉; 쨉; 쨉; 쨉; 쨉; ) HANGUL SYLLABLE JJAEB +CA0A;CA0A;110D 1162 11B9;CA0A;110D 1162 11B9; # (쨊; 쨊; 쨊; 쨊; 쨊; ) HANGUL SYLLABLE JJAEBS +CA0B;CA0B;110D 1162 11BA;CA0B;110D 1162 11BA; # (쨋; 쨋; 쨋; 쨋; 쨋; ) HANGUL SYLLABLE JJAES +CA0C;CA0C;110D 1162 11BB;CA0C;110D 1162 11BB; # (쨌; 쨌; 쨌; 쨌; 쨌; ) HANGUL SYLLABLE JJAESS +CA0D;CA0D;110D 1162 11BC;CA0D;110D 1162 11BC; # (쨍; 쨍; 쨍; 쨍; 쨍; ) HANGUL SYLLABLE JJAENG +CA0E;CA0E;110D 1162 11BD;CA0E;110D 1162 11BD; # (쨎; 쨎; 쨎; 쨎; 쨎; ) HANGUL SYLLABLE JJAEJ +CA0F;CA0F;110D 1162 11BE;CA0F;110D 1162 11BE; # (쨏; 쨏; 쨏; 쨏; 쨏; ) HANGUL SYLLABLE JJAEC +CA10;CA10;110D 1162 11BF;CA10;110D 1162 11BF; # (쨐; 쨐; 쨐; 쨐; 쨐; ) HANGUL SYLLABLE JJAEK +CA11;CA11;110D 1162 11C0;CA11;110D 1162 11C0; # (쨑; 쨑; 쨑; 쨑; 쨑; ) HANGUL SYLLABLE JJAET +CA12;CA12;110D 1162 11C1;CA12;110D 1162 11C1; # (쨒; 쨒; 쨒; 쨒; 쨒; ) HANGUL SYLLABLE JJAEP +CA13;CA13;110D 1162 11C2;CA13;110D 1162 11C2; # (쨓; 쨓; 쨓; 쨓; 쨓; ) HANGUL SYLLABLE JJAEH +CA14;CA14;110D 1163;CA14;110D 1163; # (쨔; 쨔; 쨔; 쨔; 쨔; ) HANGUL SYLLABLE JJYA +CA15;CA15;110D 1163 11A8;CA15;110D 1163 11A8; # (쨕; 쨕; 쨕; 쨕; 쨕; ) HANGUL SYLLABLE JJYAG +CA16;CA16;110D 1163 11A9;CA16;110D 1163 11A9; # (쨖; 쨖; 쨖; 쨖; 쨖; ) HANGUL SYLLABLE JJYAGG +CA17;CA17;110D 1163 11AA;CA17;110D 1163 11AA; # (쨗; 쨗; 쨗; 쨗; 쨗; ) HANGUL SYLLABLE JJYAGS +CA18;CA18;110D 1163 11AB;CA18;110D 1163 11AB; # (쨘; 쨘; 쨘; 쨘; 쨘; ) HANGUL SYLLABLE JJYAN +CA19;CA19;110D 1163 11AC;CA19;110D 1163 11AC; # (쨙; 쨙; 쨙; 쨙; 쨙; ) HANGUL SYLLABLE JJYANJ +CA1A;CA1A;110D 1163 11AD;CA1A;110D 1163 11AD; # (쨚; 쨚; 쨚; 쨚; 쨚; ) HANGUL SYLLABLE JJYANH +CA1B;CA1B;110D 1163 11AE;CA1B;110D 1163 11AE; # (쨛; 쨛; 쨛; 쨛; 쨛; ) HANGUL SYLLABLE JJYAD +CA1C;CA1C;110D 1163 11AF;CA1C;110D 1163 11AF; # (쨜; 쨜; 쨜; 쨜; 쨜; ) HANGUL SYLLABLE JJYAL +CA1D;CA1D;110D 1163 11B0;CA1D;110D 1163 11B0; # (쨝; 쨝; 쨝; 쨝; 쨝; ) HANGUL SYLLABLE JJYALG +CA1E;CA1E;110D 1163 11B1;CA1E;110D 1163 11B1; # (쨞; 쨞; 쨞; 쨞; 쨞; ) HANGUL SYLLABLE JJYALM +CA1F;CA1F;110D 1163 11B2;CA1F;110D 1163 11B2; # (쨟; 쨟; 쨟; 쨟; 쨟; ) HANGUL SYLLABLE JJYALB +CA20;CA20;110D 1163 11B3;CA20;110D 1163 11B3; # (쨠; 쨠; 쨠; 쨠; 쨠; ) HANGUL SYLLABLE JJYALS +CA21;CA21;110D 1163 11B4;CA21;110D 1163 11B4; # (쨡; 쨡; 쨡; 쨡; 쨡; ) HANGUL SYLLABLE JJYALT +CA22;CA22;110D 1163 11B5;CA22;110D 1163 11B5; # (쨢; 쨢; 쨢; 쨢; 쨢; ) HANGUL SYLLABLE JJYALP +CA23;CA23;110D 1163 11B6;CA23;110D 1163 11B6; # (쨣; 쨣; 쨣; 쨣; 쨣; ) HANGUL SYLLABLE JJYALH +CA24;CA24;110D 1163 11B7;CA24;110D 1163 11B7; # (쨤; 쨤; 쨤; 쨤; 쨤; ) HANGUL SYLLABLE JJYAM +CA25;CA25;110D 1163 11B8;CA25;110D 1163 11B8; # (쨥; 쨥; 쨥; 쨥; 쨥; ) HANGUL SYLLABLE JJYAB +CA26;CA26;110D 1163 11B9;CA26;110D 1163 11B9; # (쨦; 쨦; 쨦; 쨦; 쨦; ) HANGUL SYLLABLE JJYABS +CA27;CA27;110D 1163 11BA;CA27;110D 1163 11BA; # (쨧; 쨧; 쨧; 쨧; 쨧; ) HANGUL SYLLABLE JJYAS +CA28;CA28;110D 1163 11BB;CA28;110D 1163 11BB; # (쨨; 쨨; 쨨; 쨨; 쨨; ) HANGUL SYLLABLE JJYASS +CA29;CA29;110D 1163 11BC;CA29;110D 1163 11BC; # (쨩; 쨩; 쨩; 쨩; 쨩; ) HANGUL SYLLABLE JJYANG +CA2A;CA2A;110D 1163 11BD;CA2A;110D 1163 11BD; # (쨪; 쨪; 쨪; 쨪; 쨪; ) HANGUL SYLLABLE JJYAJ +CA2B;CA2B;110D 1163 11BE;CA2B;110D 1163 11BE; # (쨫; 쨫; 쨫; 쨫; 쨫; ) HANGUL SYLLABLE JJYAC +CA2C;CA2C;110D 1163 11BF;CA2C;110D 1163 11BF; # (쨬; 쨬; 쨬; 쨬; 쨬; ) HANGUL SYLLABLE JJYAK +CA2D;CA2D;110D 1163 11C0;CA2D;110D 1163 11C0; # (쨭; 쨭; 쨭; 쨭; 쨭; ) HANGUL SYLLABLE JJYAT +CA2E;CA2E;110D 1163 11C1;CA2E;110D 1163 11C1; # (쨮; 쨮; 쨮; 쨮; 쨮; ) HANGUL SYLLABLE JJYAP +CA2F;CA2F;110D 1163 11C2;CA2F;110D 1163 11C2; # (쨯; 쨯; 쨯; 쨯; 쨯; ) HANGUL SYLLABLE JJYAH +CA30;CA30;110D 1164;CA30;110D 1164; # (쨰; 쨰; 쨰; 쨰; 쨰; ) HANGUL SYLLABLE JJYAE +CA31;CA31;110D 1164 11A8;CA31;110D 1164 11A8; # (쨱; 쨱; 쨱; 쨱; 쨱; ) HANGUL SYLLABLE JJYAEG +CA32;CA32;110D 1164 11A9;CA32;110D 1164 11A9; # (쨲; 쨲; 쨲; 쨲; 쨲; ) HANGUL SYLLABLE JJYAEGG +CA33;CA33;110D 1164 11AA;CA33;110D 1164 11AA; # (쨳; 쨳; 쨳; 쨳; 쨳; ) HANGUL SYLLABLE JJYAEGS +CA34;CA34;110D 1164 11AB;CA34;110D 1164 11AB; # (쨴; 쨴; 쨴; 쨴; 쨴; ) HANGUL SYLLABLE JJYAEN +CA35;CA35;110D 1164 11AC;CA35;110D 1164 11AC; # (쨵; 쨵; 쨵; 쨵; 쨵; ) HANGUL SYLLABLE JJYAENJ +CA36;CA36;110D 1164 11AD;CA36;110D 1164 11AD; # (쨶; 쨶; 쨶; 쨶; 쨶; ) HANGUL SYLLABLE JJYAENH +CA37;CA37;110D 1164 11AE;CA37;110D 1164 11AE; # (쨷; 쨷; 쨷; 쨷; 쨷; ) HANGUL SYLLABLE JJYAED +CA38;CA38;110D 1164 11AF;CA38;110D 1164 11AF; # (쨸; 쨸; 쨸; 쨸; 쨸; ) HANGUL SYLLABLE JJYAEL +CA39;CA39;110D 1164 11B0;CA39;110D 1164 11B0; # (쨹; 쨹; 쨹; 쨹; 쨹; ) HANGUL SYLLABLE JJYAELG +CA3A;CA3A;110D 1164 11B1;CA3A;110D 1164 11B1; # (쨺; 쨺; 쨺; 쨺; 쨺; ) HANGUL SYLLABLE JJYAELM +CA3B;CA3B;110D 1164 11B2;CA3B;110D 1164 11B2; # (쨻; 쨻; 쨻; 쨻; 쨻; ) HANGUL SYLLABLE JJYAELB +CA3C;CA3C;110D 1164 11B3;CA3C;110D 1164 11B3; # (쨼; 쨼; 쨼; 쨼; 쨼; ) HANGUL SYLLABLE JJYAELS +CA3D;CA3D;110D 1164 11B4;CA3D;110D 1164 11B4; # (쨽; 쨽; 쨽; 쨽; 쨽; ) HANGUL SYLLABLE JJYAELT +CA3E;CA3E;110D 1164 11B5;CA3E;110D 1164 11B5; # (쨾; 쨾; 쨾; 쨾; 쨾; ) HANGUL SYLLABLE JJYAELP +CA3F;CA3F;110D 1164 11B6;CA3F;110D 1164 11B6; # (쨿; 쨿; 쨿; 쨿; 쨿; ) HANGUL SYLLABLE JJYAELH +CA40;CA40;110D 1164 11B7;CA40;110D 1164 11B7; # (쩀; 쩀; 쩀; 쩀; 쩀; ) HANGUL SYLLABLE JJYAEM +CA41;CA41;110D 1164 11B8;CA41;110D 1164 11B8; # (쩁; 쩁; 쩁; 쩁; 쩁; ) HANGUL SYLLABLE JJYAEB +CA42;CA42;110D 1164 11B9;CA42;110D 1164 11B9; # (쩂; 쩂; 쩂; 쩂; 쩂; ) HANGUL SYLLABLE JJYAEBS +CA43;CA43;110D 1164 11BA;CA43;110D 1164 11BA; # (쩃; 쩃; 쩃; 쩃; 쩃; ) HANGUL SYLLABLE JJYAES +CA44;CA44;110D 1164 11BB;CA44;110D 1164 11BB; # (쩄; 쩄; 쩄; 쩄; 쩄; ) HANGUL SYLLABLE JJYAESS +CA45;CA45;110D 1164 11BC;CA45;110D 1164 11BC; # (쩅; 쩅; 쩅; 쩅; 쩅; ) HANGUL SYLLABLE JJYAENG +CA46;CA46;110D 1164 11BD;CA46;110D 1164 11BD; # (쩆; 쩆; 쩆; 쩆; 쩆; ) HANGUL SYLLABLE JJYAEJ +CA47;CA47;110D 1164 11BE;CA47;110D 1164 11BE; # (쩇; 쩇; 쩇; 쩇; 쩇; ) HANGUL SYLLABLE JJYAEC +CA48;CA48;110D 1164 11BF;CA48;110D 1164 11BF; # (쩈; 쩈; 쩈; 쩈; 쩈; ) HANGUL SYLLABLE JJYAEK +CA49;CA49;110D 1164 11C0;CA49;110D 1164 11C0; # (쩉; 쩉; 쩉; 쩉; 쩉; ) HANGUL SYLLABLE JJYAET +CA4A;CA4A;110D 1164 11C1;CA4A;110D 1164 11C1; # (쩊; 쩊; 쩊; 쩊; 쩊; ) HANGUL SYLLABLE JJYAEP +CA4B;CA4B;110D 1164 11C2;CA4B;110D 1164 11C2; # (쩋; 쩋; 쩋; 쩋; 쩋; ) HANGUL SYLLABLE JJYAEH +CA4C;CA4C;110D 1165;CA4C;110D 1165; # (쩌; 쩌; 쩌; 쩌; 쩌; ) HANGUL SYLLABLE JJEO +CA4D;CA4D;110D 1165 11A8;CA4D;110D 1165 11A8; # (쩍; 쩍; 쩍; 쩍; 쩍; ) HANGUL SYLLABLE JJEOG +CA4E;CA4E;110D 1165 11A9;CA4E;110D 1165 11A9; # (쩎; 쩎; 쩎; 쩎; 쩎; ) HANGUL SYLLABLE JJEOGG +CA4F;CA4F;110D 1165 11AA;CA4F;110D 1165 11AA; # (쩏; 쩏; 쩏; 쩏; 쩏; ) HANGUL SYLLABLE JJEOGS +CA50;CA50;110D 1165 11AB;CA50;110D 1165 11AB; # (쩐; 쩐; 쩐; 쩐; 쩐; ) HANGUL SYLLABLE JJEON +CA51;CA51;110D 1165 11AC;CA51;110D 1165 11AC; # (쩑; 쩑; 쩑; 쩑; 쩑; ) HANGUL SYLLABLE JJEONJ +CA52;CA52;110D 1165 11AD;CA52;110D 1165 11AD; # (쩒; 쩒; 쩒; 쩒; 쩒; ) HANGUL SYLLABLE JJEONH +CA53;CA53;110D 1165 11AE;CA53;110D 1165 11AE; # (쩓; 쩓; 쩓; 쩓; 쩓; ) HANGUL SYLLABLE JJEOD +CA54;CA54;110D 1165 11AF;CA54;110D 1165 11AF; # (쩔; 쩔; 쩔; 쩔; 쩔; ) HANGUL SYLLABLE JJEOL +CA55;CA55;110D 1165 11B0;CA55;110D 1165 11B0; # (쩕; 쩕; 쩕; 쩕; 쩕; ) HANGUL SYLLABLE JJEOLG +CA56;CA56;110D 1165 11B1;CA56;110D 1165 11B1; # (쩖; 쩖; 쩖; 쩖; 쩖; ) HANGUL SYLLABLE JJEOLM +CA57;CA57;110D 1165 11B2;CA57;110D 1165 11B2; # (쩗; 쩗; 쩗; 쩗; 쩗; ) HANGUL SYLLABLE JJEOLB +CA58;CA58;110D 1165 11B3;CA58;110D 1165 11B3; # (쩘; 쩘; 쩘; 쩘; 쩘; ) HANGUL SYLLABLE JJEOLS +CA59;CA59;110D 1165 11B4;CA59;110D 1165 11B4; # (쩙; 쩙; 쩙; 쩙; 쩙; ) HANGUL SYLLABLE JJEOLT +CA5A;CA5A;110D 1165 11B5;CA5A;110D 1165 11B5; # (쩚; 쩚; 쩚; 쩚; 쩚; ) HANGUL SYLLABLE JJEOLP +CA5B;CA5B;110D 1165 11B6;CA5B;110D 1165 11B6; # (쩛; 쩛; 쩛; 쩛; 쩛; ) HANGUL SYLLABLE JJEOLH +CA5C;CA5C;110D 1165 11B7;CA5C;110D 1165 11B7; # (쩜; 쩜; 쩜; 쩜; 쩜; ) HANGUL SYLLABLE JJEOM +CA5D;CA5D;110D 1165 11B8;CA5D;110D 1165 11B8; # (쩝; 쩝; 쩝; 쩝; 쩝; ) HANGUL SYLLABLE JJEOB +CA5E;CA5E;110D 1165 11B9;CA5E;110D 1165 11B9; # (쩞; 쩞; 쩞; 쩞; 쩞; ) HANGUL SYLLABLE JJEOBS +CA5F;CA5F;110D 1165 11BA;CA5F;110D 1165 11BA; # (쩟; 쩟; 쩟; 쩟; 쩟; ) HANGUL SYLLABLE JJEOS +CA60;CA60;110D 1165 11BB;CA60;110D 1165 11BB; # (쩠; 쩠; 쩠; 쩠; 쩠; ) HANGUL SYLLABLE JJEOSS +CA61;CA61;110D 1165 11BC;CA61;110D 1165 11BC; # (쩡; 쩡; 쩡; 쩡; 쩡; ) HANGUL SYLLABLE JJEONG +CA62;CA62;110D 1165 11BD;CA62;110D 1165 11BD; # (쩢; 쩢; 쩢; 쩢; 쩢; ) HANGUL SYLLABLE JJEOJ +CA63;CA63;110D 1165 11BE;CA63;110D 1165 11BE; # (쩣; 쩣; 쩣; 쩣; 쩣; ) HANGUL SYLLABLE JJEOC +CA64;CA64;110D 1165 11BF;CA64;110D 1165 11BF; # (쩤; 쩤; 쩤; 쩤; 쩤; ) HANGUL SYLLABLE JJEOK +CA65;CA65;110D 1165 11C0;CA65;110D 1165 11C0; # (쩥; 쩥; 쩥; 쩥; 쩥; ) HANGUL SYLLABLE JJEOT +CA66;CA66;110D 1165 11C1;CA66;110D 1165 11C1; # (쩦; 쩦; 쩦; 쩦; 쩦; ) HANGUL SYLLABLE JJEOP +CA67;CA67;110D 1165 11C2;CA67;110D 1165 11C2; # (쩧; 쩧; 쩧; 쩧; 쩧; ) HANGUL SYLLABLE JJEOH +CA68;CA68;110D 1166;CA68;110D 1166; # (쩨; 쩨; 쩨; 쩨; 쩨; ) HANGUL SYLLABLE JJE +CA69;CA69;110D 1166 11A8;CA69;110D 1166 11A8; # (쩩; 쩩; 쩩; 쩩; 쩩; ) HANGUL SYLLABLE JJEG +CA6A;CA6A;110D 1166 11A9;CA6A;110D 1166 11A9; # (쩪; 쩪; 쩪; 쩪; 쩪; ) HANGUL SYLLABLE JJEGG +CA6B;CA6B;110D 1166 11AA;CA6B;110D 1166 11AA; # (쩫; 쩫; 쩫; 쩫; 쩫; ) HANGUL SYLLABLE JJEGS +CA6C;CA6C;110D 1166 11AB;CA6C;110D 1166 11AB; # (쩬; 쩬; 쩬; 쩬; 쩬; ) HANGUL SYLLABLE JJEN +CA6D;CA6D;110D 1166 11AC;CA6D;110D 1166 11AC; # (쩭; 쩭; 쩭; 쩭; 쩭; ) HANGUL SYLLABLE JJENJ +CA6E;CA6E;110D 1166 11AD;CA6E;110D 1166 11AD; # (쩮; 쩮; 쩮; 쩮; 쩮; ) HANGUL SYLLABLE JJENH +CA6F;CA6F;110D 1166 11AE;CA6F;110D 1166 11AE; # (쩯; 쩯; 쩯; 쩯; 쩯; ) HANGUL SYLLABLE JJED +CA70;CA70;110D 1166 11AF;CA70;110D 1166 11AF; # (쩰; 쩰; 쩰; 쩰; 쩰; ) HANGUL SYLLABLE JJEL +CA71;CA71;110D 1166 11B0;CA71;110D 1166 11B0; # (쩱; 쩱; 쩱; 쩱; 쩱; ) HANGUL SYLLABLE JJELG +CA72;CA72;110D 1166 11B1;CA72;110D 1166 11B1; # (쩲; 쩲; 쩲; 쩲; 쩲; ) HANGUL SYLLABLE JJELM +CA73;CA73;110D 1166 11B2;CA73;110D 1166 11B2; # (쩳; 쩳; 쩳; 쩳; 쩳; ) HANGUL SYLLABLE JJELB +CA74;CA74;110D 1166 11B3;CA74;110D 1166 11B3; # (쩴; 쩴; 쩴; 쩴; 쩴; ) HANGUL SYLLABLE JJELS +CA75;CA75;110D 1166 11B4;CA75;110D 1166 11B4; # (쩵; 쩵; 쩵; 쩵; 쩵; ) HANGUL SYLLABLE JJELT +CA76;CA76;110D 1166 11B5;CA76;110D 1166 11B5; # (쩶; 쩶; 쩶; 쩶; 쩶; ) HANGUL SYLLABLE JJELP +CA77;CA77;110D 1166 11B6;CA77;110D 1166 11B6; # (쩷; 쩷; 쩷; 쩷; 쩷; ) HANGUL SYLLABLE JJELH +CA78;CA78;110D 1166 11B7;CA78;110D 1166 11B7; # (쩸; 쩸; 쩸; 쩸; 쩸; ) HANGUL SYLLABLE JJEM +CA79;CA79;110D 1166 11B8;CA79;110D 1166 11B8; # (쩹; 쩹; 쩹; 쩹; 쩹; ) HANGUL SYLLABLE JJEB +CA7A;CA7A;110D 1166 11B9;CA7A;110D 1166 11B9; # (쩺; 쩺; 쩺; 쩺; 쩺; ) HANGUL SYLLABLE JJEBS +CA7B;CA7B;110D 1166 11BA;CA7B;110D 1166 11BA; # (쩻; 쩻; 쩻; 쩻; 쩻; ) HANGUL SYLLABLE JJES +CA7C;CA7C;110D 1166 11BB;CA7C;110D 1166 11BB; # (쩼; 쩼; 쩼; 쩼; 쩼; ) HANGUL SYLLABLE JJESS +CA7D;CA7D;110D 1166 11BC;CA7D;110D 1166 11BC; # (쩽; 쩽; 쩽; 쩽; 쩽; ) HANGUL SYLLABLE JJENG +CA7E;CA7E;110D 1166 11BD;CA7E;110D 1166 11BD; # (쩾; 쩾; 쩾; 쩾; 쩾; ) HANGUL SYLLABLE JJEJ +CA7F;CA7F;110D 1166 11BE;CA7F;110D 1166 11BE; # (쩿; 쩿; 쩿; 쩿; 쩿; ) HANGUL SYLLABLE JJEC +CA80;CA80;110D 1166 11BF;CA80;110D 1166 11BF; # (쪀; 쪀; 쪀; 쪀; 쪀; ) HANGUL SYLLABLE JJEK +CA81;CA81;110D 1166 11C0;CA81;110D 1166 11C0; # (쪁; 쪁; 쪁; 쪁; 쪁; ) HANGUL SYLLABLE JJET +CA82;CA82;110D 1166 11C1;CA82;110D 1166 11C1; # (쪂; 쪂; 쪂; 쪂; 쪂; ) HANGUL SYLLABLE JJEP +CA83;CA83;110D 1166 11C2;CA83;110D 1166 11C2; # (쪃; 쪃; 쪃; 쪃; 쪃; ) HANGUL SYLLABLE JJEH +CA84;CA84;110D 1167;CA84;110D 1167; # (쪄; 쪄; 쪄; 쪄; 쪄; ) HANGUL SYLLABLE JJYEO +CA85;CA85;110D 1167 11A8;CA85;110D 1167 11A8; # (쪅; 쪅; 쪅; 쪅; 쪅; ) HANGUL SYLLABLE JJYEOG +CA86;CA86;110D 1167 11A9;CA86;110D 1167 11A9; # (쪆; 쪆; 쪆; 쪆; 쪆; ) HANGUL SYLLABLE JJYEOGG +CA87;CA87;110D 1167 11AA;CA87;110D 1167 11AA; # (쪇; 쪇; 쪇; 쪇; 쪇; ) HANGUL SYLLABLE JJYEOGS +CA88;CA88;110D 1167 11AB;CA88;110D 1167 11AB; # (쪈; 쪈; 쪈; 쪈; 쪈; ) HANGUL SYLLABLE JJYEON +CA89;CA89;110D 1167 11AC;CA89;110D 1167 11AC; # (쪉; 쪉; 쪉; 쪉; 쪉; ) HANGUL SYLLABLE JJYEONJ +CA8A;CA8A;110D 1167 11AD;CA8A;110D 1167 11AD; # (쪊; 쪊; 쪊; 쪊; 쪊; ) HANGUL SYLLABLE JJYEONH +CA8B;CA8B;110D 1167 11AE;CA8B;110D 1167 11AE; # (쪋; 쪋; 쪋; 쪋; 쪋; ) HANGUL SYLLABLE JJYEOD +CA8C;CA8C;110D 1167 11AF;CA8C;110D 1167 11AF; # (쪌; 쪌; 쪌; 쪌; 쪌; ) HANGUL SYLLABLE JJYEOL +CA8D;CA8D;110D 1167 11B0;CA8D;110D 1167 11B0; # (쪍; 쪍; 쪍; 쪍; 쪍; ) HANGUL SYLLABLE JJYEOLG +CA8E;CA8E;110D 1167 11B1;CA8E;110D 1167 11B1; # (쪎; 쪎; 쪎; 쪎; 쪎; ) HANGUL SYLLABLE JJYEOLM +CA8F;CA8F;110D 1167 11B2;CA8F;110D 1167 11B2; # (쪏; 쪏; 쪏; 쪏; 쪏; ) HANGUL SYLLABLE JJYEOLB +CA90;CA90;110D 1167 11B3;CA90;110D 1167 11B3; # (쪐; 쪐; 쪐; 쪐; 쪐; ) HANGUL SYLLABLE JJYEOLS +CA91;CA91;110D 1167 11B4;CA91;110D 1167 11B4; # (쪑; 쪑; 쪑; 쪑; 쪑; ) HANGUL SYLLABLE JJYEOLT +CA92;CA92;110D 1167 11B5;CA92;110D 1167 11B5; # (쪒; 쪒; 쪒; 쪒; 쪒; ) HANGUL SYLLABLE JJYEOLP +CA93;CA93;110D 1167 11B6;CA93;110D 1167 11B6; # (쪓; 쪓; 쪓; 쪓; 쪓; ) HANGUL SYLLABLE JJYEOLH +CA94;CA94;110D 1167 11B7;CA94;110D 1167 11B7; # (쪔; 쪔; 쪔; 쪔; 쪔; ) HANGUL SYLLABLE JJYEOM +CA95;CA95;110D 1167 11B8;CA95;110D 1167 11B8; # (쪕; 쪕; 쪕; 쪕; 쪕; ) HANGUL SYLLABLE JJYEOB +CA96;CA96;110D 1167 11B9;CA96;110D 1167 11B9; # (쪖; 쪖; 쪖; 쪖; 쪖; ) HANGUL SYLLABLE JJYEOBS +CA97;CA97;110D 1167 11BA;CA97;110D 1167 11BA; # (쪗; 쪗; 쪗; 쪗; 쪗; ) HANGUL SYLLABLE JJYEOS +CA98;CA98;110D 1167 11BB;CA98;110D 1167 11BB; # (쪘; 쪘; 쪘; 쪘; 쪘; ) HANGUL SYLLABLE JJYEOSS +CA99;CA99;110D 1167 11BC;CA99;110D 1167 11BC; # (쪙; 쪙; 쪙; 쪙; 쪙; ) HANGUL SYLLABLE JJYEONG +CA9A;CA9A;110D 1167 11BD;CA9A;110D 1167 11BD; # (쪚; 쪚; 쪚; 쪚; 쪚; ) HANGUL SYLLABLE JJYEOJ +CA9B;CA9B;110D 1167 11BE;CA9B;110D 1167 11BE; # (쪛; 쪛; 쪛; 쪛; 쪛; ) HANGUL SYLLABLE JJYEOC +CA9C;CA9C;110D 1167 11BF;CA9C;110D 1167 11BF; # (쪜; 쪜; 쪜; 쪜; 쪜; ) HANGUL SYLLABLE JJYEOK +CA9D;CA9D;110D 1167 11C0;CA9D;110D 1167 11C0; # (쪝; 쪝; 쪝; 쪝; 쪝; ) HANGUL SYLLABLE JJYEOT +CA9E;CA9E;110D 1167 11C1;CA9E;110D 1167 11C1; # (쪞; 쪞; 쪞; 쪞; 쪞; ) HANGUL SYLLABLE JJYEOP +CA9F;CA9F;110D 1167 11C2;CA9F;110D 1167 11C2; # (쪟; 쪟; 쪟; 쪟; 쪟; ) HANGUL SYLLABLE JJYEOH +CAA0;CAA0;110D 1168;CAA0;110D 1168; # (쪠; 쪠; 쪠; 쪠; 쪠; ) HANGUL SYLLABLE JJYE +CAA1;CAA1;110D 1168 11A8;CAA1;110D 1168 11A8; # (쪡; 쪡; 쪡; 쪡; 쪡; ) HANGUL SYLLABLE JJYEG +CAA2;CAA2;110D 1168 11A9;CAA2;110D 1168 11A9; # (쪢; 쪢; 쪢; 쪢; 쪢; ) HANGUL SYLLABLE JJYEGG +CAA3;CAA3;110D 1168 11AA;CAA3;110D 1168 11AA; # (쪣; 쪣; 쪣; 쪣; 쪣; ) HANGUL SYLLABLE JJYEGS +CAA4;CAA4;110D 1168 11AB;CAA4;110D 1168 11AB; # (쪤; 쪤; 쪤; 쪤; 쪤; ) HANGUL SYLLABLE JJYEN +CAA5;CAA5;110D 1168 11AC;CAA5;110D 1168 11AC; # (쪥; 쪥; 쪥; 쪥; 쪥; ) HANGUL SYLLABLE JJYENJ +CAA6;CAA6;110D 1168 11AD;CAA6;110D 1168 11AD; # (쪦; 쪦; 쪦; 쪦; 쪦; ) HANGUL SYLLABLE JJYENH +CAA7;CAA7;110D 1168 11AE;CAA7;110D 1168 11AE; # (쪧; 쪧; 쪧; 쪧; 쪧; ) HANGUL SYLLABLE JJYED +CAA8;CAA8;110D 1168 11AF;CAA8;110D 1168 11AF; # (쪨; 쪨; 쪨; 쪨; 쪨; ) HANGUL SYLLABLE JJYEL +CAA9;CAA9;110D 1168 11B0;CAA9;110D 1168 11B0; # (쪩; 쪩; 쪩; 쪩; 쪩; ) HANGUL SYLLABLE JJYELG +CAAA;CAAA;110D 1168 11B1;CAAA;110D 1168 11B1; # (쪪; 쪪; 쪪; 쪪; 쪪; ) HANGUL SYLLABLE JJYELM +CAAB;CAAB;110D 1168 11B2;CAAB;110D 1168 11B2; # (쪫; 쪫; 쪫; 쪫; 쪫; ) HANGUL SYLLABLE JJYELB +CAAC;CAAC;110D 1168 11B3;CAAC;110D 1168 11B3; # (쪬; 쪬; 쪬; 쪬; 쪬; ) HANGUL SYLLABLE JJYELS +CAAD;CAAD;110D 1168 11B4;CAAD;110D 1168 11B4; # (쪭; 쪭; 쪭; 쪭; 쪭; ) HANGUL SYLLABLE JJYELT +CAAE;CAAE;110D 1168 11B5;CAAE;110D 1168 11B5; # (쪮; 쪮; 쪮; 쪮; 쪮; ) HANGUL SYLLABLE JJYELP +CAAF;CAAF;110D 1168 11B6;CAAF;110D 1168 11B6; # (쪯; 쪯; 쪯; 쪯; 쪯; ) HANGUL SYLLABLE JJYELH +CAB0;CAB0;110D 1168 11B7;CAB0;110D 1168 11B7; # (쪰; 쪰; 쪰; 쪰; 쪰; ) HANGUL SYLLABLE JJYEM +CAB1;CAB1;110D 1168 11B8;CAB1;110D 1168 11B8; # (쪱; 쪱; 쪱; 쪱; 쪱; ) HANGUL SYLLABLE JJYEB +CAB2;CAB2;110D 1168 11B9;CAB2;110D 1168 11B9; # (쪲; 쪲; 쪲; 쪲; 쪲; ) HANGUL SYLLABLE JJYEBS +CAB3;CAB3;110D 1168 11BA;CAB3;110D 1168 11BA; # (쪳; 쪳; 쪳; 쪳; 쪳; ) HANGUL SYLLABLE JJYES +CAB4;CAB4;110D 1168 11BB;CAB4;110D 1168 11BB; # (쪴; 쪴; 쪴; 쪴; 쪴; ) HANGUL SYLLABLE JJYESS +CAB5;CAB5;110D 1168 11BC;CAB5;110D 1168 11BC; # (쪵; 쪵; 쪵; 쪵; 쪵; ) HANGUL SYLLABLE JJYENG +CAB6;CAB6;110D 1168 11BD;CAB6;110D 1168 11BD; # (쪶; 쪶; 쪶; 쪶; 쪶; ) HANGUL SYLLABLE JJYEJ +CAB7;CAB7;110D 1168 11BE;CAB7;110D 1168 11BE; # (쪷; 쪷; 쪷; 쪷; 쪷; ) HANGUL SYLLABLE JJYEC +CAB8;CAB8;110D 1168 11BF;CAB8;110D 1168 11BF; # (쪸; 쪸; 쪸; 쪸; 쪸; ) HANGUL SYLLABLE JJYEK +CAB9;CAB9;110D 1168 11C0;CAB9;110D 1168 11C0; # (쪹; 쪹; 쪹; 쪹; 쪹; ) HANGUL SYLLABLE JJYET +CABA;CABA;110D 1168 11C1;CABA;110D 1168 11C1; # (쪺; 쪺; 쪺; 쪺; 쪺; ) HANGUL SYLLABLE JJYEP +CABB;CABB;110D 1168 11C2;CABB;110D 1168 11C2; # (쪻; 쪻; 쪻; 쪻; 쪻; ) HANGUL SYLLABLE JJYEH +CABC;CABC;110D 1169;CABC;110D 1169; # (쪼; 쪼; 쪼; 쪼; 쪼; ) HANGUL SYLLABLE JJO +CABD;CABD;110D 1169 11A8;CABD;110D 1169 11A8; # (쪽; 쪽; 쪽; 쪽; 쪽; ) HANGUL SYLLABLE JJOG +CABE;CABE;110D 1169 11A9;CABE;110D 1169 11A9; # (쪾; 쪾; 쪾; 쪾; 쪾; ) HANGUL SYLLABLE JJOGG +CABF;CABF;110D 1169 11AA;CABF;110D 1169 11AA; # (쪿; 쪿; 쪿; 쪿; 쪿; ) HANGUL SYLLABLE JJOGS +CAC0;CAC0;110D 1169 11AB;CAC0;110D 1169 11AB; # (쫀; 쫀; 쫀; 쫀; 쫀; ) HANGUL SYLLABLE JJON +CAC1;CAC1;110D 1169 11AC;CAC1;110D 1169 11AC; # (쫁; 쫁; 쫁; 쫁; 쫁; ) HANGUL SYLLABLE JJONJ +CAC2;CAC2;110D 1169 11AD;CAC2;110D 1169 11AD; # (쫂; 쫂; 쫂; 쫂; 쫂; ) HANGUL SYLLABLE JJONH +CAC3;CAC3;110D 1169 11AE;CAC3;110D 1169 11AE; # (쫃; 쫃; 쫃; 쫃; 쫃; ) HANGUL SYLLABLE JJOD +CAC4;CAC4;110D 1169 11AF;CAC4;110D 1169 11AF; # (쫄; 쫄; 쫄; 쫄; 쫄; ) HANGUL SYLLABLE JJOL +CAC5;CAC5;110D 1169 11B0;CAC5;110D 1169 11B0; # (쫅; 쫅; 쫅; 쫅; 쫅; ) HANGUL SYLLABLE JJOLG +CAC6;CAC6;110D 1169 11B1;CAC6;110D 1169 11B1; # (쫆; 쫆; 쫆; 쫆; 쫆; ) HANGUL SYLLABLE JJOLM +CAC7;CAC7;110D 1169 11B2;CAC7;110D 1169 11B2; # (쫇; 쫇; 쫇; 쫇; 쫇; ) HANGUL SYLLABLE JJOLB +CAC8;CAC8;110D 1169 11B3;CAC8;110D 1169 11B3; # (쫈; 쫈; 쫈; 쫈; 쫈; ) HANGUL SYLLABLE JJOLS +CAC9;CAC9;110D 1169 11B4;CAC9;110D 1169 11B4; # (쫉; 쫉; 쫉; 쫉; 쫉; ) HANGUL SYLLABLE JJOLT +CACA;CACA;110D 1169 11B5;CACA;110D 1169 11B5; # (쫊; 쫊; 쫊; 쫊; 쫊; ) HANGUL SYLLABLE JJOLP +CACB;CACB;110D 1169 11B6;CACB;110D 1169 11B6; # (쫋; 쫋; 쫋; 쫋; 쫋; ) HANGUL SYLLABLE JJOLH +CACC;CACC;110D 1169 11B7;CACC;110D 1169 11B7; # (쫌; 쫌; 쫌; 쫌; 쫌; ) HANGUL SYLLABLE JJOM +CACD;CACD;110D 1169 11B8;CACD;110D 1169 11B8; # (쫍; 쫍; 쫍; 쫍; 쫍; ) HANGUL SYLLABLE JJOB +CACE;CACE;110D 1169 11B9;CACE;110D 1169 11B9; # (쫎; 쫎; 쫎; 쫎; 쫎; ) HANGUL SYLLABLE JJOBS +CACF;CACF;110D 1169 11BA;CACF;110D 1169 11BA; # (쫏; 쫏; 쫏; 쫏; 쫏; ) HANGUL SYLLABLE JJOS +CAD0;CAD0;110D 1169 11BB;CAD0;110D 1169 11BB; # (쫐; 쫐; 쫐; 쫐; 쫐; ) HANGUL SYLLABLE JJOSS +CAD1;CAD1;110D 1169 11BC;CAD1;110D 1169 11BC; # (쫑; 쫑; 쫑; 쫑; 쫑; ) HANGUL SYLLABLE JJONG +CAD2;CAD2;110D 1169 11BD;CAD2;110D 1169 11BD; # (쫒; 쫒; 쫒; 쫒; 쫒; ) HANGUL SYLLABLE JJOJ +CAD3;CAD3;110D 1169 11BE;CAD3;110D 1169 11BE; # (쫓; 쫓; 쫓; 쫓; 쫓; ) HANGUL SYLLABLE JJOC +CAD4;CAD4;110D 1169 11BF;CAD4;110D 1169 11BF; # (쫔; 쫔; 쫔; 쫔; 쫔; ) HANGUL SYLLABLE JJOK +CAD5;CAD5;110D 1169 11C0;CAD5;110D 1169 11C0; # (쫕; 쫕; 쫕; 쫕; 쫕; ) HANGUL SYLLABLE JJOT +CAD6;CAD6;110D 1169 11C1;CAD6;110D 1169 11C1; # (쫖; 쫖; 쫖; 쫖; 쫖; ) HANGUL SYLLABLE JJOP +CAD7;CAD7;110D 1169 11C2;CAD7;110D 1169 11C2; # (쫗; 쫗; 쫗; 쫗; 쫗; ) HANGUL SYLLABLE JJOH +CAD8;CAD8;110D 116A;CAD8;110D 116A; # (쫘; 쫘; 쫘; 쫘; 쫘; ) HANGUL SYLLABLE JJWA +CAD9;CAD9;110D 116A 11A8;CAD9;110D 116A 11A8; # (쫙; 쫙; 쫙; 쫙; 쫙; ) HANGUL SYLLABLE JJWAG +CADA;CADA;110D 116A 11A9;CADA;110D 116A 11A9; # (쫚; 쫚; 쫚; 쫚; 쫚; ) HANGUL SYLLABLE JJWAGG +CADB;CADB;110D 116A 11AA;CADB;110D 116A 11AA; # (쫛; 쫛; 쫛; 쫛; 쫛; ) HANGUL SYLLABLE JJWAGS +CADC;CADC;110D 116A 11AB;CADC;110D 116A 11AB; # (쫜; 쫜; 쫜; 쫜; 쫜; ) HANGUL SYLLABLE JJWAN +CADD;CADD;110D 116A 11AC;CADD;110D 116A 11AC; # (쫝; 쫝; 쫝; 쫝; 쫝; ) HANGUL SYLLABLE JJWANJ +CADE;CADE;110D 116A 11AD;CADE;110D 116A 11AD; # (쫞; 쫞; 쫞; 쫞; 쫞; ) HANGUL SYLLABLE JJWANH +CADF;CADF;110D 116A 11AE;CADF;110D 116A 11AE; # (쫟; 쫟; 쫟; 쫟; 쫟; ) HANGUL SYLLABLE JJWAD +CAE0;CAE0;110D 116A 11AF;CAE0;110D 116A 11AF; # (쫠; 쫠; 쫠; 쫠; 쫠; ) HANGUL SYLLABLE JJWAL +CAE1;CAE1;110D 116A 11B0;CAE1;110D 116A 11B0; # (쫡; 쫡; 쫡; 쫡; 쫡; ) HANGUL SYLLABLE JJWALG +CAE2;CAE2;110D 116A 11B1;CAE2;110D 116A 11B1; # (쫢; 쫢; 쫢; 쫢; 쫢; ) HANGUL SYLLABLE JJWALM +CAE3;CAE3;110D 116A 11B2;CAE3;110D 116A 11B2; # (쫣; 쫣; 쫣; 쫣; 쫣; ) HANGUL SYLLABLE JJWALB +CAE4;CAE4;110D 116A 11B3;CAE4;110D 116A 11B3; # (쫤; 쫤; 쫤; 쫤; 쫤; ) HANGUL SYLLABLE JJWALS +CAE5;CAE5;110D 116A 11B4;CAE5;110D 116A 11B4; # (쫥; 쫥; 쫥; 쫥; 쫥; ) HANGUL SYLLABLE JJWALT +CAE6;CAE6;110D 116A 11B5;CAE6;110D 116A 11B5; # (쫦; 쫦; 쫦; 쫦; 쫦; ) HANGUL SYLLABLE JJWALP +CAE7;CAE7;110D 116A 11B6;CAE7;110D 116A 11B6; # (쫧; 쫧; 쫧; 쫧; 쫧; ) HANGUL SYLLABLE JJWALH +CAE8;CAE8;110D 116A 11B7;CAE8;110D 116A 11B7; # (쫨; 쫨; 쫨; 쫨; 쫨; ) HANGUL SYLLABLE JJWAM +CAE9;CAE9;110D 116A 11B8;CAE9;110D 116A 11B8; # (쫩; 쫩; 쫩; 쫩; 쫩; ) HANGUL SYLLABLE JJWAB +CAEA;CAEA;110D 116A 11B9;CAEA;110D 116A 11B9; # (쫪; 쫪; 쫪; 쫪; 쫪; ) HANGUL SYLLABLE JJWABS +CAEB;CAEB;110D 116A 11BA;CAEB;110D 116A 11BA; # (쫫; 쫫; 쫫; 쫫; 쫫; ) HANGUL SYLLABLE JJWAS +CAEC;CAEC;110D 116A 11BB;CAEC;110D 116A 11BB; # (쫬; 쫬; 쫬; 쫬; 쫬; ) HANGUL SYLLABLE JJWASS +CAED;CAED;110D 116A 11BC;CAED;110D 116A 11BC; # (쫭; 쫭; 쫭; 쫭; 쫭; ) HANGUL SYLLABLE JJWANG +CAEE;CAEE;110D 116A 11BD;CAEE;110D 116A 11BD; # (쫮; 쫮; 쫮; 쫮; 쫮; ) HANGUL SYLLABLE JJWAJ +CAEF;CAEF;110D 116A 11BE;CAEF;110D 116A 11BE; # (쫯; 쫯; 쫯; 쫯; 쫯; ) HANGUL SYLLABLE JJWAC +CAF0;CAF0;110D 116A 11BF;CAF0;110D 116A 11BF; # (쫰; 쫰; 쫰; 쫰; 쫰; ) HANGUL SYLLABLE JJWAK +CAF1;CAF1;110D 116A 11C0;CAF1;110D 116A 11C0; # (쫱; 쫱; 쫱; 쫱; 쫱; ) HANGUL SYLLABLE JJWAT +CAF2;CAF2;110D 116A 11C1;CAF2;110D 116A 11C1; # (쫲; 쫲; 쫲; 쫲; 쫲; ) HANGUL SYLLABLE JJWAP +CAF3;CAF3;110D 116A 11C2;CAF3;110D 116A 11C2; # (쫳; 쫳; 쫳; 쫳; 쫳; ) HANGUL SYLLABLE JJWAH +CAF4;CAF4;110D 116B;CAF4;110D 116B; # (쫴; 쫴; 쫴; 쫴; 쫴; ) HANGUL SYLLABLE JJWAE +CAF5;CAF5;110D 116B 11A8;CAF5;110D 116B 11A8; # (쫵; 쫵; 쫵; 쫵; 쫵; ) HANGUL SYLLABLE JJWAEG +CAF6;CAF6;110D 116B 11A9;CAF6;110D 116B 11A9; # (쫶; 쫶; 쫶; 쫶; 쫶; ) HANGUL SYLLABLE JJWAEGG +CAF7;CAF7;110D 116B 11AA;CAF7;110D 116B 11AA; # (쫷; 쫷; 쫷; 쫷; 쫷; ) HANGUL SYLLABLE JJWAEGS +CAF8;CAF8;110D 116B 11AB;CAF8;110D 116B 11AB; # (쫸; 쫸; 쫸; 쫸; 쫸; ) HANGUL SYLLABLE JJWAEN +CAF9;CAF9;110D 116B 11AC;CAF9;110D 116B 11AC; # (쫹; 쫹; 쫹; 쫹; 쫹; ) HANGUL SYLLABLE JJWAENJ +CAFA;CAFA;110D 116B 11AD;CAFA;110D 116B 11AD; # (쫺; 쫺; 쫺; 쫺; 쫺; ) HANGUL SYLLABLE JJWAENH +CAFB;CAFB;110D 116B 11AE;CAFB;110D 116B 11AE; # (쫻; 쫻; 쫻; 쫻; 쫻; ) HANGUL SYLLABLE JJWAED +CAFC;CAFC;110D 116B 11AF;CAFC;110D 116B 11AF; # (쫼; 쫼; 쫼; 쫼; 쫼; ) HANGUL SYLLABLE JJWAEL +CAFD;CAFD;110D 116B 11B0;CAFD;110D 116B 11B0; # (쫽; 쫽; 쫽; 쫽; 쫽; ) HANGUL SYLLABLE JJWAELG +CAFE;CAFE;110D 116B 11B1;CAFE;110D 116B 11B1; # (쫾; 쫾; 쫾; 쫾; 쫾; ) HANGUL SYLLABLE JJWAELM +CAFF;CAFF;110D 116B 11B2;CAFF;110D 116B 11B2; # (쫿; 쫿; 쫿; 쫿; 쫿; ) HANGUL SYLLABLE JJWAELB +CB00;CB00;110D 116B 11B3;CB00;110D 116B 11B3; # (쬀; 쬀; 쬀; 쬀; 쬀; ) HANGUL SYLLABLE JJWAELS +CB01;CB01;110D 116B 11B4;CB01;110D 116B 11B4; # (쬁; 쬁; 쬁; 쬁; 쬁; ) HANGUL SYLLABLE JJWAELT +CB02;CB02;110D 116B 11B5;CB02;110D 116B 11B5; # (쬂; 쬂; 쬂; 쬂; 쬂; ) HANGUL SYLLABLE JJWAELP +CB03;CB03;110D 116B 11B6;CB03;110D 116B 11B6; # (쬃; 쬃; 쬃; 쬃; 쬃; ) HANGUL SYLLABLE JJWAELH +CB04;CB04;110D 116B 11B7;CB04;110D 116B 11B7; # (쬄; 쬄; 쬄; 쬄; 쬄; ) HANGUL SYLLABLE JJWAEM +CB05;CB05;110D 116B 11B8;CB05;110D 116B 11B8; # (쬅; 쬅; 쬅; 쬅; 쬅; ) HANGUL SYLLABLE JJWAEB +CB06;CB06;110D 116B 11B9;CB06;110D 116B 11B9; # (쬆; 쬆; 쬆; 쬆; 쬆; ) HANGUL SYLLABLE JJWAEBS +CB07;CB07;110D 116B 11BA;CB07;110D 116B 11BA; # (쬇; 쬇; 쬇; 쬇; 쬇; ) HANGUL SYLLABLE JJWAES +CB08;CB08;110D 116B 11BB;CB08;110D 116B 11BB; # (쬈; 쬈; 쬈; 쬈; 쬈; ) HANGUL SYLLABLE JJWAESS +CB09;CB09;110D 116B 11BC;CB09;110D 116B 11BC; # (쬉; 쬉; 쬉; 쬉; 쬉; ) HANGUL SYLLABLE JJWAENG +CB0A;CB0A;110D 116B 11BD;CB0A;110D 116B 11BD; # (쬊; 쬊; 쬊; 쬊; 쬊; ) HANGUL SYLLABLE JJWAEJ +CB0B;CB0B;110D 116B 11BE;CB0B;110D 116B 11BE; # (쬋; 쬋; 쬋; 쬋; 쬋; ) HANGUL SYLLABLE JJWAEC +CB0C;CB0C;110D 116B 11BF;CB0C;110D 116B 11BF; # (쬌; 쬌; 쬌; 쬌; 쬌; ) HANGUL SYLLABLE JJWAEK +CB0D;CB0D;110D 116B 11C0;CB0D;110D 116B 11C0; # (쬍; 쬍; 쬍; 쬍; 쬍; ) HANGUL SYLLABLE JJWAET +CB0E;CB0E;110D 116B 11C1;CB0E;110D 116B 11C1; # (쬎; 쬎; 쬎; 쬎; 쬎; ) HANGUL SYLLABLE JJWAEP +CB0F;CB0F;110D 116B 11C2;CB0F;110D 116B 11C2; # (쬏; 쬏; 쬏; 쬏; 쬏; ) HANGUL SYLLABLE JJWAEH +CB10;CB10;110D 116C;CB10;110D 116C; # (쬐; 쬐; 쬐; 쬐; 쬐; ) HANGUL SYLLABLE JJOE +CB11;CB11;110D 116C 11A8;CB11;110D 116C 11A8; # (쬑; 쬑; 쬑; 쬑; 쬑; ) HANGUL SYLLABLE JJOEG +CB12;CB12;110D 116C 11A9;CB12;110D 116C 11A9; # (쬒; 쬒; 쬒; 쬒; 쬒; ) HANGUL SYLLABLE JJOEGG +CB13;CB13;110D 116C 11AA;CB13;110D 116C 11AA; # (쬓; 쬓; 쬓; 쬓; 쬓; ) HANGUL SYLLABLE JJOEGS +CB14;CB14;110D 116C 11AB;CB14;110D 116C 11AB; # (쬔; 쬔; 쬔; 쬔; 쬔; ) HANGUL SYLLABLE JJOEN +CB15;CB15;110D 116C 11AC;CB15;110D 116C 11AC; # (쬕; 쬕; 쬕; 쬕; 쬕; ) HANGUL SYLLABLE JJOENJ +CB16;CB16;110D 116C 11AD;CB16;110D 116C 11AD; # (쬖; 쬖; 쬖; 쬖; 쬖; ) HANGUL SYLLABLE JJOENH +CB17;CB17;110D 116C 11AE;CB17;110D 116C 11AE; # (쬗; 쬗; 쬗; 쬗; 쬗; ) HANGUL SYLLABLE JJOED +CB18;CB18;110D 116C 11AF;CB18;110D 116C 11AF; # (쬘; 쬘; 쬘; 쬘; 쬘; ) HANGUL SYLLABLE JJOEL +CB19;CB19;110D 116C 11B0;CB19;110D 116C 11B0; # (쬙; 쬙; 쬙; 쬙; 쬙; ) HANGUL SYLLABLE JJOELG +CB1A;CB1A;110D 116C 11B1;CB1A;110D 116C 11B1; # (쬚; 쬚; 쬚; 쬚; 쬚; ) HANGUL SYLLABLE JJOELM +CB1B;CB1B;110D 116C 11B2;CB1B;110D 116C 11B2; # (쬛; 쬛; 쬛; 쬛; 쬛; ) HANGUL SYLLABLE JJOELB +CB1C;CB1C;110D 116C 11B3;CB1C;110D 116C 11B3; # (쬜; 쬜; 쬜; 쬜; 쬜; ) HANGUL SYLLABLE JJOELS +CB1D;CB1D;110D 116C 11B4;CB1D;110D 116C 11B4; # (쬝; 쬝; 쬝; 쬝; 쬝; ) HANGUL SYLLABLE JJOELT +CB1E;CB1E;110D 116C 11B5;CB1E;110D 116C 11B5; # (쬞; 쬞; 쬞; 쬞; 쬞; ) HANGUL SYLLABLE JJOELP +CB1F;CB1F;110D 116C 11B6;CB1F;110D 116C 11B6; # (쬟; 쬟; 쬟; 쬟; 쬟; ) HANGUL SYLLABLE JJOELH +CB20;CB20;110D 116C 11B7;CB20;110D 116C 11B7; # (쬠; 쬠; 쬠; 쬠; 쬠; ) HANGUL SYLLABLE JJOEM +CB21;CB21;110D 116C 11B8;CB21;110D 116C 11B8; # (쬡; 쬡; 쬡; 쬡; 쬡; ) HANGUL SYLLABLE JJOEB +CB22;CB22;110D 116C 11B9;CB22;110D 116C 11B9; # (쬢; 쬢; 쬢; 쬢; 쬢; ) HANGUL SYLLABLE JJOEBS +CB23;CB23;110D 116C 11BA;CB23;110D 116C 11BA; # (쬣; 쬣; 쬣; 쬣; 쬣; ) HANGUL SYLLABLE JJOES +CB24;CB24;110D 116C 11BB;CB24;110D 116C 11BB; # (쬤; 쬤; 쬤; 쬤; 쬤; ) HANGUL SYLLABLE JJOESS +CB25;CB25;110D 116C 11BC;CB25;110D 116C 11BC; # (쬥; 쬥; 쬥; 쬥; 쬥; ) HANGUL SYLLABLE JJOENG +CB26;CB26;110D 116C 11BD;CB26;110D 116C 11BD; # (쬦; 쬦; 쬦; 쬦; 쬦; ) HANGUL SYLLABLE JJOEJ +CB27;CB27;110D 116C 11BE;CB27;110D 116C 11BE; # (쬧; 쬧; 쬧; 쬧; 쬧; ) HANGUL SYLLABLE JJOEC +CB28;CB28;110D 116C 11BF;CB28;110D 116C 11BF; # (쬨; 쬨; 쬨; 쬨; 쬨; ) HANGUL SYLLABLE JJOEK +CB29;CB29;110D 116C 11C0;CB29;110D 116C 11C0; # (쬩; 쬩; 쬩; 쬩; 쬩; ) HANGUL SYLLABLE JJOET +CB2A;CB2A;110D 116C 11C1;CB2A;110D 116C 11C1; # (쬪; 쬪; 쬪; 쬪; 쬪; ) HANGUL SYLLABLE JJOEP +CB2B;CB2B;110D 116C 11C2;CB2B;110D 116C 11C2; # (쬫; 쬫; 쬫; 쬫; 쬫; ) HANGUL SYLLABLE JJOEH +CB2C;CB2C;110D 116D;CB2C;110D 116D; # (쬬; 쬬; 쬬; 쬬; 쬬; ) HANGUL SYLLABLE JJYO +CB2D;CB2D;110D 116D 11A8;CB2D;110D 116D 11A8; # (쬭; 쬭; 쬭; 쬭; 쬭; ) HANGUL SYLLABLE JJYOG +CB2E;CB2E;110D 116D 11A9;CB2E;110D 116D 11A9; # (쬮; 쬮; 쬮; 쬮; 쬮; ) HANGUL SYLLABLE JJYOGG +CB2F;CB2F;110D 116D 11AA;CB2F;110D 116D 11AA; # (쬯; 쬯; 쬯; 쬯; 쬯; ) HANGUL SYLLABLE JJYOGS +CB30;CB30;110D 116D 11AB;CB30;110D 116D 11AB; # (쬰; 쬰; 쬰; 쬰; 쬰; ) HANGUL SYLLABLE JJYON +CB31;CB31;110D 116D 11AC;CB31;110D 116D 11AC; # (쬱; 쬱; 쬱; 쬱; 쬱; ) HANGUL SYLLABLE JJYONJ +CB32;CB32;110D 116D 11AD;CB32;110D 116D 11AD; # (쬲; 쬲; 쬲; 쬲; 쬲; ) HANGUL SYLLABLE JJYONH +CB33;CB33;110D 116D 11AE;CB33;110D 116D 11AE; # (쬳; 쬳; 쬳; 쬳; 쬳; ) HANGUL SYLLABLE JJYOD +CB34;CB34;110D 116D 11AF;CB34;110D 116D 11AF; # (쬴; 쬴; 쬴; 쬴; 쬴; ) HANGUL SYLLABLE JJYOL +CB35;CB35;110D 116D 11B0;CB35;110D 116D 11B0; # (쬵; 쬵; 쬵; 쬵; 쬵; ) HANGUL SYLLABLE JJYOLG +CB36;CB36;110D 116D 11B1;CB36;110D 116D 11B1; # (쬶; 쬶; 쬶; 쬶; 쬶; ) HANGUL SYLLABLE JJYOLM +CB37;CB37;110D 116D 11B2;CB37;110D 116D 11B2; # (쬷; 쬷; 쬷; 쬷; 쬷; ) HANGUL SYLLABLE JJYOLB +CB38;CB38;110D 116D 11B3;CB38;110D 116D 11B3; # (쬸; 쬸; 쬸; 쬸; 쬸; ) HANGUL SYLLABLE JJYOLS +CB39;CB39;110D 116D 11B4;CB39;110D 116D 11B4; # (쬹; 쬹; 쬹; 쬹; 쬹; ) HANGUL SYLLABLE JJYOLT +CB3A;CB3A;110D 116D 11B5;CB3A;110D 116D 11B5; # (쬺; 쬺; 쬺; 쬺; 쬺; ) HANGUL SYLLABLE JJYOLP +CB3B;CB3B;110D 116D 11B6;CB3B;110D 116D 11B6; # (쬻; 쬻; 쬻; 쬻; 쬻; ) HANGUL SYLLABLE JJYOLH +CB3C;CB3C;110D 116D 11B7;CB3C;110D 116D 11B7; # (쬼; 쬼; 쬼; 쬼; 쬼; ) HANGUL SYLLABLE JJYOM +CB3D;CB3D;110D 116D 11B8;CB3D;110D 116D 11B8; # (쬽; 쬽; 쬽; 쬽; 쬽; ) HANGUL SYLLABLE JJYOB +CB3E;CB3E;110D 116D 11B9;CB3E;110D 116D 11B9; # (쬾; 쬾; 쬾; 쬾; 쬾; ) HANGUL SYLLABLE JJYOBS +CB3F;CB3F;110D 116D 11BA;CB3F;110D 116D 11BA; # (쬿; 쬿; 쬿; 쬿; 쬿; ) HANGUL SYLLABLE JJYOS +CB40;CB40;110D 116D 11BB;CB40;110D 116D 11BB; # (쭀; 쭀; 쭀; 쭀; 쭀; ) HANGUL SYLLABLE JJYOSS +CB41;CB41;110D 116D 11BC;CB41;110D 116D 11BC; # (쭁; 쭁; 쭁; 쭁; 쭁; ) HANGUL SYLLABLE JJYONG +CB42;CB42;110D 116D 11BD;CB42;110D 116D 11BD; # (쭂; 쭂; 쭂; 쭂; 쭂; ) HANGUL SYLLABLE JJYOJ +CB43;CB43;110D 116D 11BE;CB43;110D 116D 11BE; # (쭃; 쭃; 쭃; 쭃; 쭃; ) HANGUL SYLLABLE JJYOC +CB44;CB44;110D 116D 11BF;CB44;110D 116D 11BF; # (쭄; 쭄; 쭄; 쭄; 쭄; ) HANGUL SYLLABLE JJYOK +CB45;CB45;110D 116D 11C0;CB45;110D 116D 11C0; # (쭅; 쭅; 쭅; 쭅; 쭅; ) HANGUL SYLLABLE JJYOT +CB46;CB46;110D 116D 11C1;CB46;110D 116D 11C1; # (쭆; 쭆; 쭆; 쭆; 쭆; ) HANGUL SYLLABLE JJYOP +CB47;CB47;110D 116D 11C2;CB47;110D 116D 11C2; # (쭇; 쭇; 쭇; 쭇; 쭇; ) HANGUL SYLLABLE JJYOH +CB48;CB48;110D 116E;CB48;110D 116E; # (쭈; 쭈; 쭈; 쭈; 쭈; ) HANGUL SYLLABLE JJU +CB49;CB49;110D 116E 11A8;CB49;110D 116E 11A8; # (쭉; 쭉; 쭉; 쭉; 쭉; ) HANGUL SYLLABLE JJUG +CB4A;CB4A;110D 116E 11A9;CB4A;110D 116E 11A9; # (쭊; 쭊; 쭊; 쭊; 쭊; ) HANGUL SYLLABLE JJUGG +CB4B;CB4B;110D 116E 11AA;CB4B;110D 116E 11AA; # (쭋; 쭋; 쭋; 쭋; 쭋; ) HANGUL SYLLABLE JJUGS +CB4C;CB4C;110D 116E 11AB;CB4C;110D 116E 11AB; # (쭌; 쭌; 쭌; 쭌; 쭌; ) HANGUL SYLLABLE JJUN +CB4D;CB4D;110D 116E 11AC;CB4D;110D 116E 11AC; # (쭍; 쭍; 쭍; 쭍; 쭍; ) HANGUL SYLLABLE JJUNJ +CB4E;CB4E;110D 116E 11AD;CB4E;110D 116E 11AD; # (쭎; 쭎; 쭎; 쭎; 쭎; ) HANGUL SYLLABLE JJUNH +CB4F;CB4F;110D 116E 11AE;CB4F;110D 116E 11AE; # (쭏; 쭏; 쭏; 쭏; 쭏; ) HANGUL SYLLABLE JJUD +CB50;CB50;110D 116E 11AF;CB50;110D 116E 11AF; # (쭐; 쭐; 쭐; 쭐; 쭐; ) HANGUL SYLLABLE JJUL +CB51;CB51;110D 116E 11B0;CB51;110D 116E 11B0; # (쭑; 쭑; 쭑; 쭑; 쭑; ) HANGUL SYLLABLE JJULG +CB52;CB52;110D 116E 11B1;CB52;110D 116E 11B1; # (쭒; 쭒; 쭒; 쭒; 쭒; ) HANGUL SYLLABLE JJULM +CB53;CB53;110D 116E 11B2;CB53;110D 116E 11B2; # (쭓; 쭓; 쭓; 쭓; 쭓; ) HANGUL SYLLABLE JJULB +CB54;CB54;110D 116E 11B3;CB54;110D 116E 11B3; # (쭔; 쭔; 쭔; 쭔; 쭔; ) HANGUL SYLLABLE JJULS +CB55;CB55;110D 116E 11B4;CB55;110D 116E 11B4; # (쭕; 쭕; 쭕; 쭕; 쭕; ) HANGUL SYLLABLE JJULT +CB56;CB56;110D 116E 11B5;CB56;110D 116E 11B5; # (쭖; 쭖; 쭖; 쭖; 쭖; ) HANGUL SYLLABLE JJULP +CB57;CB57;110D 116E 11B6;CB57;110D 116E 11B6; # (쭗; 쭗; 쭗; 쭗; 쭗; ) HANGUL SYLLABLE JJULH +CB58;CB58;110D 116E 11B7;CB58;110D 116E 11B7; # (쭘; 쭘; 쭘; 쭘; 쭘; ) HANGUL SYLLABLE JJUM +CB59;CB59;110D 116E 11B8;CB59;110D 116E 11B8; # (쭙; 쭙; 쭙; 쭙; 쭙; ) HANGUL SYLLABLE JJUB +CB5A;CB5A;110D 116E 11B9;CB5A;110D 116E 11B9; # (쭚; 쭚; 쭚; 쭚; 쭚; ) HANGUL SYLLABLE JJUBS +CB5B;CB5B;110D 116E 11BA;CB5B;110D 116E 11BA; # (쭛; 쭛; 쭛; 쭛; 쭛; ) HANGUL SYLLABLE JJUS +CB5C;CB5C;110D 116E 11BB;CB5C;110D 116E 11BB; # (쭜; 쭜; 쭜; 쭜; 쭜; ) HANGUL SYLLABLE JJUSS +CB5D;CB5D;110D 116E 11BC;CB5D;110D 116E 11BC; # (쭝; 쭝; 쭝; 쭝; 쭝; ) HANGUL SYLLABLE JJUNG +CB5E;CB5E;110D 116E 11BD;CB5E;110D 116E 11BD; # (쭞; 쭞; 쭞; 쭞; 쭞; ) HANGUL SYLLABLE JJUJ +CB5F;CB5F;110D 116E 11BE;CB5F;110D 116E 11BE; # (쭟; 쭟; 쭟; 쭟; 쭟; ) HANGUL SYLLABLE JJUC +CB60;CB60;110D 116E 11BF;CB60;110D 116E 11BF; # (쭠; 쭠; 쭠; 쭠; 쭠; ) HANGUL SYLLABLE JJUK +CB61;CB61;110D 116E 11C0;CB61;110D 116E 11C0; # (쭡; 쭡; 쭡; 쭡; 쭡; ) HANGUL SYLLABLE JJUT +CB62;CB62;110D 116E 11C1;CB62;110D 116E 11C1; # (쭢; 쭢; 쭢; 쭢; 쭢; ) HANGUL SYLLABLE JJUP +CB63;CB63;110D 116E 11C2;CB63;110D 116E 11C2; # (쭣; 쭣; 쭣; 쭣; 쭣; ) HANGUL SYLLABLE JJUH +CB64;CB64;110D 116F;CB64;110D 116F; # (쭤; 쭤; 쭤; 쭤; 쭤; ) HANGUL SYLLABLE JJWEO +CB65;CB65;110D 116F 11A8;CB65;110D 116F 11A8; # (쭥; 쭥; 쭥; 쭥; 쭥; ) HANGUL SYLLABLE JJWEOG +CB66;CB66;110D 116F 11A9;CB66;110D 116F 11A9; # (쭦; 쭦; 쭦; 쭦; 쭦; ) HANGUL SYLLABLE JJWEOGG +CB67;CB67;110D 116F 11AA;CB67;110D 116F 11AA; # (쭧; 쭧; 쭧; 쭧; 쭧; ) HANGUL SYLLABLE JJWEOGS +CB68;CB68;110D 116F 11AB;CB68;110D 116F 11AB; # (쭨; 쭨; 쭨; 쭨; 쭨; ) HANGUL SYLLABLE JJWEON +CB69;CB69;110D 116F 11AC;CB69;110D 116F 11AC; # (쭩; 쭩; 쭩; 쭩; 쭩; ) HANGUL SYLLABLE JJWEONJ +CB6A;CB6A;110D 116F 11AD;CB6A;110D 116F 11AD; # (쭪; 쭪; 쭪; 쭪; 쭪; ) HANGUL SYLLABLE JJWEONH +CB6B;CB6B;110D 116F 11AE;CB6B;110D 116F 11AE; # (쭫; 쭫; 쭫; 쭫; 쭫; ) HANGUL SYLLABLE JJWEOD +CB6C;CB6C;110D 116F 11AF;CB6C;110D 116F 11AF; # (쭬; 쭬; 쭬; 쭬; 쭬; ) HANGUL SYLLABLE JJWEOL +CB6D;CB6D;110D 116F 11B0;CB6D;110D 116F 11B0; # (쭭; 쭭; 쭭; 쭭; 쭭; ) HANGUL SYLLABLE JJWEOLG +CB6E;CB6E;110D 116F 11B1;CB6E;110D 116F 11B1; # (쭮; 쭮; 쭮; 쭮; 쭮; ) HANGUL SYLLABLE JJWEOLM +CB6F;CB6F;110D 116F 11B2;CB6F;110D 116F 11B2; # (쭯; 쭯; 쭯; 쭯; 쭯; ) HANGUL SYLLABLE JJWEOLB +CB70;CB70;110D 116F 11B3;CB70;110D 116F 11B3; # (쭰; 쭰; 쭰; 쭰; 쭰; ) HANGUL SYLLABLE JJWEOLS +CB71;CB71;110D 116F 11B4;CB71;110D 116F 11B4; # (쭱; 쭱; 쭱; 쭱; 쭱; ) HANGUL SYLLABLE JJWEOLT +CB72;CB72;110D 116F 11B5;CB72;110D 116F 11B5; # (쭲; 쭲; 쭲; 쭲; 쭲; ) HANGUL SYLLABLE JJWEOLP +CB73;CB73;110D 116F 11B6;CB73;110D 116F 11B6; # (쭳; 쭳; 쭳; 쭳; 쭳; ) HANGUL SYLLABLE JJWEOLH +CB74;CB74;110D 116F 11B7;CB74;110D 116F 11B7; # (쭴; 쭴; 쭴; 쭴; 쭴; ) HANGUL SYLLABLE JJWEOM +CB75;CB75;110D 116F 11B8;CB75;110D 116F 11B8; # (쭵; 쭵; 쭵; 쭵; 쭵; ) HANGUL SYLLABLE JJWEOB +CB76;CB76;110D 116F 11B9;CB76;110D 116F 11B9; # (쭶; 쭶; 쭶; 쭶; 쭶; ) HANGUL SYLLABLE JJWEOBS +CB77;CB77;110D 116F 11BA;CB77;110D 116F 11BA; # (쭷; 쭷; 쭷; 쭷; 쭷; ) HANGUL SYLLABLE JJWEOS +CB78;CB78;110D 116F 11BB;CB78;110D 116F 11BB; # (쭸; 쭸; 쭸; 쭸; 쭸; ) HANGUL SYLLABLE JJWEOSS +CB79;CB79;110D 116F 11BC;CB79;110D 116F 11BC; # (쭹; 쭹; 쭹; 쭹; 쭹; ) HANGUL SYLLABLE JJWEONG +CB7A;CB7A;110D 116F 11BD;CB7A;110D 116F 11BD; # (쭺; 쭺; 쭺; 쭺; 쭺; ) HANGUL SYLLABLE JJWEOJ +CB7B;CB7B;110D 116F 11BE;CB7B;110D 116F 11BE; # (쭻; 쭻; 쭻; 쭻; 쭻; ) HANGUL SYLLABLE JJWEOC +CB7C;CB7C;110D 116F 11BF;CB7C;110D 116F 11BF; # (쭼; 쭼; 쭼; 쭼; 쭼; ) HANGUL SYLLABLE JJWEOK +CB7D;CB7D;110D 116F 11C0;CB7D;110D 116F 11C0; # (쭽; 쭽; 쭽; 쭽; 쭽; ) HANGUL SYLLABLE JJWEOT +CB7E;CB7E;110D 116F 11C1;CB7E;110D 116F 11C1; # (쭾; 쭾; 쭾; 쭾; 쭾; ) HANGUL SYLLABLE JJWEOP +CB7F;CB7F;110D 116F 11C2;CB7F;110D 116F 11C2; # (쭿; 쭿; 쭿; 쭿; 쭿; ) HANGUL SYLLABLE JJWEOH +CB80;CB80;110D 1170;CB80;110D 1170; # (쮀; 쮀; 쮀; 쮀; 쮀; ) HANGUL SYLLABLE JJWE +CB81;CB81;110D 1170 11A8;CB81;110D 1170 11A8; # (쮁; 쮁; 쮁; 쮁; 쮁; ) HANGUL SYLLABLE JJWEG +CB82;CB82;110D 1170 11A9;CB82;110D 1170 11A9; # (쮂; 쮂; 쮂; 쮂; 쮂; ) HANGUL SYLLABLE JJWEGG +CB83;CB83;110D 1170 11AA;CB83;110D 1170 11AA; # (쮃; 쮃; 쮃; 쮃; 쮃; ) HANGUL SYLLABLE JJWEGS +CB84;CB84;110D 1170 11AB;CB84;110D 1170 11AB; # (쮄; 쮄; 쮄; 쮄; 쮄; ) HANGUL SYLLABLE JJWEN +CB85;CB85;110D 1170 11AC;CB85;110D 1170 11AC; # (쮅; 쮅; 쮅; 쮅; 쮅; ) HANGUL SYLLABLE JJWENJ +CB86;CB86;110D 1170 11AD;CB86;110D 1170 11AD; # (쮆; 쮆; 쮆; 쮆; 쮆; ) HANGUL SYLLABLE JJWENH +CB87;CB87;110D 1170 11AE;CB87;110D 1170 11AE; # (쮇; 쮇; 쮇; 쮇; 쮇; ) HANGUL SYLLABLE JJWED +CB88;CB88;110D 1170 11AF;CB88;110D 1170 11AF; # (쮈; 쮈; 쮈; 쮈; 쮈; ) HANGUL SYLLABLE JJWEL +CB89;CB89;110D 1170 11B0;CB89;110D 1170 11B0; # (쮉; 쮉; 쮉; 쮉; 쮉; ) HANGUL SYLLABLE JJWELG +CB8A;CB8A;110D 1170 11B1;CB8A;110D 1170 11B1; # (쮊; 쮊; 쮊; 쮊; 쮊; ) HANGUL SYLLABLE JJWELM +CB8B;CB8B;110D 1170 11B2;CB8B;110D 1170 11B2; # (쮋; 쮋; 쮋; 쮋; 쮋; ) HANGUL SYLLABLE JJWELB +CB8C;CB8C;110D 1170 11B3;CB8C;110D 1170 11B3; # (쮌; 쮌; 쮌; 쮌; 쮌; ) HANGUL SYLLABLE JJWELS +CB8D;CB8D;110D 1170 11B4;CB8D;110D 1170 11B4; # (쮍; 쮍; 쮍; 쮍; 쮍; ) HANGUL SYLLABLE JJWELT +CB8E;CB8E;110D 1170 11B5;CB8E;110D 1170 11B5; # (쮎; 쮎; 쮎; 쮎; 쮎; ) HANGUL SYLLABLE JJWELP +CB8F;CB8F;110D 1170 11B6;CB8F;110D 1170 11B6; # (쮏; 쮏; 쮏; 쮏; 쮏; ) HANGUL SYLLABLE JJWELH +CB90;CB90;110D 1170 11B7;CB90;110D 1170 11B7; # (쮐; 쮐; 쮐; 쮐; 쮐; ) HANGUL SYLLABLE JJWEM +CB91;CB91;110D 1170 11B8;CB91;110D 1170 11B8; # (쮑; 쮑; 쮑; 쮑; 쮑; ) HANGUL SYLLABLE JJWEB +CB92;CB92;110D 1170 11B9;CB92;110D 1170 11B9; # (쮒; 쮒; 쮒; 쮒; 쮒; ) HANGUL SYLLABLE JJWEBS +CB93;CB93;110D 1170 11BA;CB93;110D 1170 11BA; # (쮓; 쮓; 쮓; 쮓; 쮓; ) HANGUL SYLLABLE JJWES +CB94;CB94;110D 1170 11BB;CB94;110D 1170 11BB; # (쮔; 쮔; 쮔; 쮔; 쮔; ) HANGUL SYLLABLE JJWESS +CB95;CB95;110D 1170 11BC;CB95;110D 1170 11BC; # (쮕; 쮕; 쮕; 쮕; 쮕; ) HANGUL SYLLABLE JJWENG +CB96;CB96;110D 1170 11BD;CB96;110D 1170 11BD; # (쮖; 쮖; 쮖; 쮖; 쮖; ) HANGUL SYLLABLE JJWEJ +CB97;CB97;110D 1170 11BE;CB97;110D 1170 11BE; # (쮗; 쮗; 쮗; 쮗; 쮗; ) HANGUL SYLLABLE JJWEC +CB98;CB98;110D 1170 11BF;CB98;110D 1170 11BF; # (쮘; 쮘; 쮘; 쮘; 쮘; ) HANGUL SYLLABLE JJWEK +CB99;CB99;110D 1170 11C0;CB99;110D 1170 11C0; # (쮙; 쮙; 쮙; 쮙; 쮙; ) HANGUL SYLLABLE JJWET +CB9A;CB9A;110D 1170 11C1;CB9A;110D 1170 11C1; # (쮚; 쮚; 쮚; 쮚; 쮚; ) HANGUL SYLLABLE JJWEP +CB9B;CB9B;110D 1170 11C2;CB9B;110D 1170 11C2; # (쮛; 쮛; 쮛; 쮛; 쮛; ) HANGUL SYLLABLE JJWEH +CB9C;CB9C;110D 1171;CB9C;110D 1171; # (쮜; 쮜; 쮜; 쮜; 쮜; ) HANGUL SYLLABLE JJWI +CB9D;CB9D;110D 1171 11A8;CB9D;110D 1171 11A8; # (쮝; 쮝; 쮝; 쮝; 쮝; ) HANGUL SYLLABLE JJWIG +CB9E;CB9E;110D 1171 11A9;CB9E;110D 1171 11A9; # (쮞; 쮞; 쮞; 쮞; 쮞; ) HANGUL SYLLABLE JJWIGG +CB9F;CB9F;110D 1171 11AA;CB9F;110D 1171 11AA; # (쮟; 쮟; 쮟; 쮟; 쮟; ) HANGUL SYLLABLE JJWIGS +CBA0;CBA0;110D 1171 11AB;CBA0;110D 1171 11AB; # (쮠; 쮠; 쮠; 쮠; 쮠; ) HANGUL SYLLABLE JJWIN +CBA1;CBA1;110D 1171 11AC;CBA1;110D 1171 11AC; # (쮡; 쮡; 쮡; 쮡; 쮡; ) HANGUL SYLLABLE JJWINJ +CBA2;CBA2;110D 1171 11AD;CBA2;110D 1171 11AD; # (쮢; 쮢; 쮢; 쮢; 쮢; ) HANGUL SYLLABLE JJWINH +CBA3;CBA3;110D 1171 11AE;CBA3;110D 1171 11AE; # (쮣; 쮣; 쮣; 쮣; 쮣; ) HANGUL SYLLABLE JJWID +CBA4;CBA4;110D 1171 11AF;CBA4;110D 1171 11AF; # (쮤; 쮤; 쮤; 쮤; 쮤; ) HANGUL SYLLABLE JJWIL +CBA5;CBA5;110D 1171 11B0;CBA5;110D 1171 11B0; # (쮥; 쮥; 쮥; 쮥; 쮥; ) HANGUL SYLLABLE JJWILG +CBA6;CBA6;110D 1171 11B1;CBA6;110D 1171 11B1; # (쮦; 쮦; 쮦; 쮦; 쮦; ) HANGUL SYLLABLE JJWILM +CBA7;CBA7;110D 1171 11B2;CBA7;110D 1171 11B2; # (쮧; 쮧; 쮧; 쮧; 쮧; ) HANGUL SYLLABLE JJWILB +CBA8;CBA8;110D 1171 11B3;CBA8;110D 1171 11B3; # (쮨; 쮨; 쮨; 쮨; 쮨; ) HANGUL SYLLABLE JJWILS +CBA9;CBA9;110D 1171 11B4;CBA9;110D 1171 11B4; # (쮩; 쮩; 쮩; 쮩; 쮩; ) HANGUL SYLLABLE JJWILT +CBAA;CBAA;110D 1171 11B5;CBAA;110D 1171 11B5; # (쮪; 쮪; 쮪; 쮪; 쮪; ) HANGUL SYLLABLE JJWILP +CBAB;CBAB;110D 1171 11B6;CBAB;110D 1171 11B6; # (쮫; 쮫; 쮫; 쮫; 쮫; ) HANGUL SYLLABLE JJWILH +CBAC;CBAC;110D 1171 11B7;CBAC;110D 1171 11B7; # (쮬; 쮬; 쮬; 쮬; 쮬; ) HANGUL SYLLABLE JJWIM +CBAD;CBAD;110D 1171 11B8;CBAD;110D 1171 11B8; # (쮭; 쮭; 쮭; 쮭; 쮭; ) HANGUL SYLLABLE JJWIB +CBAE;CBAE;110D 1171 11B9;CBAE;110D 1171 11B9; # (쮮; 쮮; 쮮; 쮮; 쮮; ) HANGUL SYLLABLE JJWIBS +CBAF;CBAF;110D 1171 11BA;CBAF;110D 1171 11BA; # (쮯; 쮯; 쮯; 쮯; 쮯; ) HANGUL SYLLABLE JJWIS +CBB0;CBB0;110D 1171 11BB;CBB0;110D 1171 11BB; # (쮰; 쮰; 쮰; 쮰; 쮰; ) HANGUL SYLLABLE JJWISS +CBB1;CBB1;110D 1171 11BC;CBB1;110D 1171 11BC; # (쮱; 쮱; 쮱; 쮱; 쮱; ) HANGUL SYLLABLE JJWING +CBB2;CBB2;110D 1171 11BD;CBB2;110D 1171 11BD; # (쮲; 쮲; 쮲; 쮲; 쮲; ) HANGUL SYLLABLE JJWIJ +CBB3;CBB3;110D 1171 11BE;CBB3;110D 1171 11BE; # (쮳; 쮳; 쮳; 쮳; 쮳; ) HANGUL SYLLABLE JJWIC +CBB4;CBB4;110D 1171 11BF;CBB4;110D 1171 11BF; # (쮴; 쮴; 쮴; 쮴; 쮴; ) HANGUL SYLLABLE JJWIK +CBB5;CBB5;110D 1171 11C0;CBB5;110D 1171 11C0; # (쮵; 쮵; 쮵; 쮵; 쮵; ) HANGUL SYLLABLE JJWIT +CBB6;CBB6;110D 1171 11C1;CBB6;110D 1171 11C1; # (쮶; 쮶; 쮶; 쮶; 쮶; ) HANGUL SYLLABLE JJWIP +CBB7;CBB7;110D 1171 11C2;CBB7;110D 1171 11C2; # (쮷; 쮷; 쮷; 쮷; 쮷; ) HANGUL SYLLABLE JJWIH +CBB8;CBB8;110D 1172;CBB8;110D 1172; # (쮸; 쮸; 쮸; 쮸; 쮸; ) HANGUL SYLLABLE JJYU +CBB9;CBB9;110D 1172 11A8;CBB9;110D 1172 11A8; # (쮹; 쮹; 쮹; 쮹; 쮹; ) HANGUL SYLLABLE JJYUG +CBBA;CBBA;110D 1172 11A9;CBBA;110D 1172 11A9; # (쮺; 쮺; 쮺; 쮺; 쮺; ) HANGUL SYLLABLE JJYUGG +CBBB;CBBB;110D 1172 11AA;CBBB;110D 1172 11AA; # (쮻; 쮻; 쮻; 쮻; 쮻; ) HANGUL SYLLABLE JJYUGS +CBBC;CBBC;110D 1172 11AB;CBBC;110D 1172 11AB; # (쮼; 쮼; 쮼; 쮼; 쮼; ) HANGUL SYLLABLE JJYUN +CBBD;CBBD;110D 1172 11AC;CBBD;110D 1172 11AC; # (쮽; 쮽; 쮽; 쮽; 쮽; ) HANGUL SYLLABLE JJYUNJ +CBBE;CBBE;110D 1172 11AD;CBBE;110D 1172 11AD; # (쮾; 쮾; 쮾; 쮾; 쮾; ) HANGUL SYLLABLE JJYUNH +CBBF;CBBF;110D 1172 11AE;CBBF;110D 1172 11AE; # (쮿; 쮿; 쮿; 쮿; 쮿; ) HANGUL SYLLABLE JJYUD +CBC0;CBC0;110D 1172 11AF;CBC0;110D 1172 11AF; # (쯀; 쯀; 쯀; 쯀; 쯀; ) HANGUL SYLLABLE JJYUL +CBC1;CBC1;110D 1172 11B0;CBC1;110D 1172 11B0; # (쯁; 쯁; 쯁; 쯁; 쯁; ) HANGUL SYLLABLE JJYULG +CBC2;CBC2;110D 1172 11B1;CBC2;110D 1172 11B1; # (쯂; 쯂; 쯂; 쯂; 쯂; ) HANGUL SYLLABLE JJYULM +CBC3;CBC3;110D 1172 11B2;CBC3;110D 1172 11B2; # (쯃; 쯃; 쯃; 쯃; 쯃; ) HANGUL SYLLABLE JJYULB +CBC4;CBC4;110D 1172 11B3;CBC4;110D 1172 11B3; # (쯄; 쯄; 쯄; 쯄; 쯄; ) HANGUL SYLLABLE JJYULS +CBC5;CBC5;110D 1172 11B4;CBC5;110D 1172 11B4; # (쯅; 쯅; 쯅; 쯅; 쯅; ) HANGUL SYLLABLE JJYULT +CBC6;CBC6;110D 1172 11B5;CBC6;110D 1172 11B5; # (쯆; 쯆; 쯆; 쯆; 쯆; ) HANGUL SYLLABLE JJYULP +CBC7;CBC7;110D 1172 11B6;CBC7;110D 1172 11B6; # (쯇; 쯇; 쯇; 쯇; 쯇; ) HANGUL SYLLABLE JJYULH +CBC8;CBC8;110D 1172 11B7;CBC8;110D 1172 11B7; # (쯈; 쯈; 쯈; 쯈; 쯈; ) HANGUL SYLLABLE JJYUM +CBC9;CBC9;110D 1172 11B8;CBC9;110D 1172 11B8; # (쯉; 쯉; 쯉; 쯉; 쯉; ) HANGUL SYLLABLE JJYUB +CBCA;CBCA;110D 1172 11B9;CBCA;110D 1172 11B9; # (쯊; 쯊; 쯊; 쯊; 쯊; ) HANGUL SYLLABLE JJYUBS +CBCB;CBCB;110D 1172 11BA;CBCB;110D 1172 11BA; # (쯋; 쯋; 쯋; 쯋; 쯋; ) HANGUL SYLLABLE JJYUS +CBCC;CBCC;110D 1172 11BB;CBCC;110D 1172 11BB; # (쯌; 쯌; 쯌; 쯌; 쯌; ) HANGUL SYLLABLE JJYUSS +CBCD;CBCD;110D 1172 11BC;CBCD;110D 1172 11BC; # (쯍; 쯍; 쯍; 쯍; 쯍; ) HANGUL SYLLABLE JJYUNG +CBCE;CBCE;110D 1172 11BD;CBCE;110D 1172 11BD; # (쯎; 쯎; 쯎; 쯎; 쯎; ) HANGUL SYLLABLE JJYUJ +CBCF;CBCF;110D 1172 11BE;CBCF;110D 1172 11BE; # (쯏; 쯏; 쯏; 쯏; 쯏; ) HANGUL SYLLABLE JJYUC +CBD0;CBD0;110D 1172 11BF;CBD0;110D 1172 11BF; # (쯐; 쯐; 쯐; 쯐; 쯐; ) HANGUL SYLLABLE JJYUK +CBD1;CBD1;110D 1172 11C0;CBD1;110D 1172 11C0; # (쯑; 쯑; 쯑; 쯑; 쯑; ) HANGUL SYLLABLE JJYUT +CBD2;CBD2;110D 1172 11C1;CBD2;110D 1172 11C1; # (쯒; 쯒; 쯒; 쯒; 쯒; ) HANGUL SYLLABLE JJYUP +CBD3;CBD3;110D 1172 11C2;CBD3;110D 1172 11C2; # (쯓; 쯓; 쯓; 쯓; 쯓; ) HANGUL SYLLABLE JJYUH +CBD4;CBD4;110D 1173;CBD4;110D 1173; # (쯔; 쯔; 쯔; 쯔; 쯔; ) HANGUL SYLLABLE JJEU +CBD5;CBD5;110D 1173 11A8;CBD5;110D 1173 11A8; # (쯕; 쯕; 쯕; 쯕; 쯕; ) HANGUL SYLLABLE JJEUG +CBD6;CBD6;110D 1173 11A9;CBD6;110D 1173 11A9; # (쯖; 쯖; 쯖; 쯖; 쯖; ) HANGUL SYLLABLE JJEUGG +CBD7;CBD7;110D 1173 11AA;CBD7;110D 1173 11AA; # (쯗; 쯗; 쯗; 쯗; 쯗; ) HANGUL SYLLABLE JJEUGS +CBD8;CBD8;110D 1173 11AB;CBD8;110D 1173 11AB; # (쯘; 쯘; 쯘; 쯘; 쯘; ) HANGUL SYLLABLE JJEUN +CBD9;CBD9;110D 1173 11AC;CBD9;110D 1173 11AC; # (쯙; 쯙; 쯙; 쯙; 쯙; ) HANGUL SYLLABLE JJEUNJ +CBDA;CBDA;110D 1173 11AD;CBDA;110D 1173 11AD; # (쯚; 쯚; 쯚; 쯚; 쯚; ) HANGUL SYLLABLE JJEUNH +CBDB;CBDB;110D 1173 11AE;CBDB;110D 1173 11AE; # (쯛; 쯛; 쯛; 쯛; 쯛; ) HANGUL SYLLABLE JJEUD +CBDC;CBDC;110D 1173 11AF;CBDC;110D 1173 11AF; # (쯜; 쯜; 쯜; 쯜; 쯜; ) HANGUL SYLLABLE JJEUL +CBDD;CBDD;110D 1173 11B0;CBDD;110D 1173 11B0; # (쯝; 쯝; 쯝; 쯝; 쯝; ) HANGUL SYLLABLE JJEULG +CBDE;CBDE;110D 1173 11B1;CBDE;110D 1173 11B1; # (쯞; 쯞; 쯞; 쯞; 쯞; ) HANGUL SYLLABLE JJEULM +CBDF;CBDF;110D 1173 11B2;CBDF;110D 1173 11B2; # (쯟; 쯟; 쯟; 쯟; 쯟; ) HANGUL SYLLABLE JJEULB +CBE0;CBE0;110D 1173 11B3;CBE0;110D 1173 11B3; # (쯠; 쯠; 쯠; 쯠; 쯠; ) HANGUL SYLLABLE JJEULS +CBE1;CBE1;110D 1173 11B4;CBE1;110D 1173 11B4; # (쯡; 쯡; 쯡; 쯡; 쯡; ) HANGUL SYLLABLE JJEULT +CBE2;CBE2;110D 1173 11B5;CBE2;110D 1173 11B5; # (쯢; 쯢; 쯢; 쯢; 쯢; ) HANGUL SYLLABLE JJEULP +CBE3;CBE3;110D 1173 11B6;CBE3;110D 1173 11B6; # (쯣; 쯣; 쯣; 쯣; 쯣; ) HANGUL SYLLABLE JJEULH +CBE4;CBE4;110D 1173 11B7;CBE4;110D 1173 11B7; # (쯤; 쯤; 쯤; 쯤; 쯤; ) HANGUL SYLLABLE JJEUM +CBE5;CBE5;110D 1173 11B8;CBE5;110D 1173 11B8; # (쯥; 쯥; 쯥; 쯥; 쯥; ) HANGUL SYLLABLE JJEUB +CBE6;CBE6;110D 1173 11B9;CBE6;110D 1173 11B9; # (쯦; 쯦; 쯦; 쯦; 쯦; ) HANGUL SYLLABLE JJEUBS +CBE7;CBE7;110D 1173 11BA;CBE7;110D 1173 11BA; # (쯧; 쯧; 쯧; 쯧; 쯧; ) HANGUL SYLLABLE JJEUS +CBE8;CBE8;110D 1173 11BB;CBE8;110D 1173 11BB; # (쯨; 쯨; 쯨; 쯨; 쯨; ) HANGUL SYLLABLE JJEUSS +CBE9;CBE9;110D 1173 11BC;CBE9;110D 1173 11BC; # (쯩; 쯩; 쯩; 쯩; 쯩; ) HANGUL SYLLABLE JJEUNG +CBEA;CBEA;110D 1173 11BD;CBEA;110D 1173 11BD; # (쯪; 쯪; 쯪; 쯪; 쯪; ) HANGUL SYLLABLE JJEUJ +CBEB;CBEB;110D 1173 11BE;CBEB;110D 1173 11BE; # (쯫; 쯫; 쯫; 쯫; 쯫; ) HANGUL SYLLABLE JJEUC +CBEC;CBEC;110D 1173 11BF;CBEC;110D 1173 11BF; # (쯬; 쯬; 쯬; 쯬; 쯬; ) HANGUL SYLLABLE JJEUK +CBED;CBED;110D 1173 11C0;CBED;110D 1173 11C0; # (쯭; 쯭; 쯭; 쯭; 쯭; ) HANGUL SYLLABLE JJEUT +CBEE;CBEE;110D 1173 11C1;CBEE;110D 1173 11C1; # (쯮; 쯮; 쯮; 쯮; 쯮; ) HANGUL SYLLABLE JJEUP +CBEF;CBEF;110D 1173 11C2;CBEF;110D 1173 11C2; # (쯯; 쯯; 쯯; 쯯; 쯯; ) HANGUL SYLLABLE JJEUH +CBF0;CBF0;110D 1174;CBF0;110D 1174; # (쯰; 쯰; 쯰; 쯰; 쯰; ) HANGUL SYLLABLE JJYI +CBF1;CBF1;110D 1174 11A8;CBF1;110D 1174 11A8; # (쯱; 쯱; 쯱; 쯱; 쯱; ) HANGUL SYLLABLE JJYIG +CBF2;CBF2;110D 1174 11A9;CBF2;110D 1174 11A9; # (쯲; 쯲; 쯲; 쯲; 쯲; ) HANGUL SYLLABLE JJYIGG +CBF3;CBF3;110D 1174 11AA;CBF3;110D 1174 11AA; # (쯳; 쯳; 쯳; 쯳; 쯳; ) HANGUL SYLLABLE JJYIGS +CBF4;CBF4;110D 1174 11AB;CBF4;110D 1174 11AB; # (쯴; 쯴; 쯴; 쯴; 쯴; ) HANGUL SYLLABLE JJYIN +CBF5;CBF5;110D 1174 11AC;CBF5;110D 1174 11AC; # (쯵; 쯵; 쯵; 쯵; 쯵; ) HANGUL SYLLABLE JJYINJ +CBF6;CBF6;110D 1174 11AD;CBF6;110D 1174 11AD; # (쯶; 쯶; 쯶; 쯶; 쯶; ) HANGUL SYLLABLE JJYINH +CBF7;CBF7;110D 1174 11AE;CBF7;110D 1174 11AE; # (쯷; 쯷; 쯷; 쯷; 쯷; ) HANGUL SYLLABLE JJYID +CBF8;CBF8;110D 1174 11AF;CBF8;110D 1174 11AF; # (쯸; 쯸; 쯸; 쯸; 쯸; ) HANGUL SYLLABLE JJYIL +CBF9;CBF9;110D 1174 11B0;CBF9;110D 1174 11B0; # (쯹; 쯹; 쯹; 쯹; 쯹; ) HANGUL SYLLABLE JJYILG +CBFA;CBFA;110D 1174 11B1;CBFA;110D 1174 11B1; # (쯺; 쯺; 쯺; 쯺; 쯺; ) HANGUL SYLLABLE JJYILM +CBFB;CBFB;110D 1174 11B2;CBFB;110D 1174 11B2; # (쯻; 쯻; 쯻; 쯻; 쯻; ) HANGUL SYLLABLE JJYILB +CBFC;CBFC;110D 1174 11B3;CBFC;110D 1174 11B3; # (쯼; 쯼; 쯼; 쯼; 쯼; ) HANGUL SYLLABLE JJYILS +CBFD;CBFD;110D 1174 11B4;CBFD;110D 1174 11B4; # (쯽; 쯽; 쯽; 쯽; 쯽; ) HANGUL SYLLABLE JJYILT +CBFE;CBFE;110D 1174 11B5;CBFE;110D 1174 11B5; # (쯾; 쯾; 쯾; 쯾; 쯾; ) HANGUL SYLLABLE JJYILP +CBFF;CBFF;110D 1174 11B6;CBFF;110D 1174 11B6; # (쯿; 쯿; 쯿; 쯿; 쯿; ) HANGUL SYLLABLE JJYILH +CC00;CC00;110D 1174 11B7;CC00;110D 1174 11B7; # (찀; 찀; 찀; 찀; 찀; ) HANGUL SYLLABLE JJYIM +CC01;CC01;110D 1174 11B8;CC01;110D 1174 11B8; # (찁; 찁; 찁; 찁; 찁; ) HANGUL SYLLABLE JJYIB +CC02;CC02;110D 1174 11B9;CC02;110D 1174 11B9; # (찂; 찂; 찂; 찂; 찂; ) HANGUL SYLLABLE JJYIBS +CC03;CC03;110D 1174 11BA;CC03;110D 1174 11BA; # (찃; 찃; 찃; 찃; 찃; ) HANGUL SYLLABLE JJYIS +CC04;CC04;110D 1174 11BB;CC04;110D 1174 11BB; # (찄; 찄; 찄; 찄; 찄; ) HANGUL SYLLABLE JJYISS +CC05;CC05;110D 1174 11BC;CC05;110D 1174 11BC; # (찅; 찅; 찅; 찅; 찅; ) HANGUL SYLLABLE JJYING +CC06;CC06;110D 1174 11BD;CC06;110D 1174 11BD; # (찆; 찆; 찆; 찆; 찆; ) HANGUL SYLLABLE JJYIJ +CC07;CC07;110D 1174 11BE;CC07;110D 1174 11BE; # (찇; 찇; 찇; 찇; 찇; ) HANGUL SYLLABLE JJYIC +CC08;CC08;110D 1174 11BF;CC08;110D 1174 11BF; # (찈; 찈; 찈; 찈; 찈; ) HANGUL SYLLABLE JJYIK +CC09;CC09;110D 1174 11C0;CC09;110D 1174 11C0; # (찉; 찉; 찉; 찉; 찉; ) HANGUL SYLLABLE JJYIT +CC0A;CC0A;110D 1174 11C1;CC0A;110D 1174 11C1; # (찊; 찊; 찊; 찊; 찊; ) HANGUL SYLLABLE JJYIP +CC0B;CC0B;110D 1174 11C2;CC0B;110D 1174 11C2; # (찋; 찋; 찋; 찋; 찋; ) HANGUL SYLLABLE JJYIH +CC0C;CC0C;110D 1175;CC0C;110D 1175; # (찌; 찌; 찌; 찌; 찌; ) HANGUL SYLLABLE JJI +CC0D;CC0D;110D 1175 11A8;CC0D;110D 1175 11A8; # (찍; 찍; 찍; 찍; 찍; ) HANGUL SYLLABLE JJIG +CC0E;CC0E;110D 1175 11A9;CC0E;110D 1175 11A9; # (찎; 찎; 찎; 찎; 찎; ) HANGUL SYLLABLE JJIGG +CC0F;CC0F;110D 1175 11AA;CC0F;110D 1175 11AA; # (찏; 찏; 찏; 찏; 찏; ) HANGUL SYLLABLE JJIGS +CC10;CC10;110D 1175 11AB;CC10;110D 1175 11AB; # (찐; 찐; 찐; 찐; 찐; ) HANGUL SYLLABLE JJIN +CC11;CC11;110D 1175 11AC;CC11;110D 1175 11AC; # (찑; 찑; 찑; 찑; 찑; ) HANGUL SYLLABLE JJINJ +CC12;CC12;110D 1175 11AD;CC12;110D 1175 11AD; # (찒; 찒; 찒; 찒; 찒; ) HANGUL SYLLABLE JJINH +CC13;CC13;110D 1175 11AE;CC13;110D 1175 11AE; # (찓; 찓; 찓; 찓; 찓; ) HANGUL SYLLABLE JJID +CC14;CC14;110D 1175 11AF;CC14;110D 1175 11AF; # (찔; 찔; 찔; 찔; 찔; ) HANGUL SYLLABLE JJIL +CC15;CC15;110D 1175 11B0;CC15;110D 1175 11B0; # (찕; 찕; 찕; 찕; 찕; ) HANGUL SYLLABLE JJILG +CC16;CC16;110D 1175 11B1;CC16;110D 1175 11B1; # (찖; 찖; 찖; 찖; 찖; ) HANGUL SYLLABLE JJILM +CC17;CC17;110D 1175 11B2;CC17;110D 1175 11B2; # (찗; 찗; 찗; 찗; 찗; ) HANGUL SYLLABLE JJILB +CC18;CC18;110D 1175 11B3;CC18;110D 1175 11B3; # (찘; 찘; 찘; 찘; 찘; ) HANGUL SYLLABLE JJILS +CC19;CC19;110D 1175 11B4;CC19;110D 1175 11B4; # (찙; 찙; 찙; 찙; 찙; ) HANGUL SYLLABLE JJILT +CC1A;CC1A;110D 1175 11B5;CC1A;110D 1175 11B5; # (찚; 찚; 찚; 찚; 찚; ) HANGUL SYLLABLE JJILP +CC1B;CC1B;110D 1175 11B6;CC1B;110D 1175 11B6; # (찛; 찛; 찛; 찛; 찛; ) HANGUL SYLLABLE JJILH +CC1C;CC1C;110D 1175 11B7;CC1C;110D 1175 11B7; # (찜; 찜; 찜; 찜; 찜; ) HANGUL SYLLABLE JJIM +CC1D;CC1D;110D 1175 11B8;CC1D;110D 1175 11B8; # (찝; 찝; 찝; 찝; 찝; ) HANGUL SYLLABLE JJIB +CC1E;CC1E;110D 1175 11B9;CC1E;110D 1175 11B9; # (찞; 찞; 찞; 찞; 찞; ) HANGUL SYLLABLE JJIBS +CC1F;CC1F;110D 1175 11BA;CC1F;110D 1175 11BA; # (찟; 찟; 찟; 찟; 찟; ) HANGUL SYLLABLE JJIS +CC20;CC20;110D 1175 11BB;CC20;110D 1175 11BB; # (찠; 찠; 찠; 찠; 찠; ) HANGUL SYLLABLE JJISS +CC21;CC21;110D 1175 11BC;CC21;110D 1175 11BC; # (찡; 찡; 찡; 찡; 찡; ) HANGUL SYLLABLE JJING +CC22;CC22;110D 1175 11BD;CC22;110D 1175 11BD; # (찢; 찢; 찢; 찢; 찢; ) HANGUL SYLLABLE JJIJ +CC23;CC23;110D 1175 11BE;CC23;110D 1175 11BE; # (찣; 찣; 찣; 찣; 찣; ) HANGUL SYLLABLE JJIC +CC24;CC24;110D 1175 11BF;CC24;110D 1175 11BF; # (찤; 찤; 찤; 찤; 찤; ) HANGUL SYLLABLE JJIK +CC25;CC25;110D 1175 11C0;CC25;110D 1175 11C0; # (찥; 찥; 찥; 찥; 찥; ) HANGUL SYLLABLE JJIT +CC26;CC26;110D 1175 11C1;CC26;110D 1175 11C1; # (찦; 찦; 찦; 찦; 찦; ) HANGUL SYLLABLE JJIP +CC27;CC27;110D 1175 11C2;CC27;110D 1175 11C2; # (찧; 찧; 찧; 찧; 찧; ) HANGUL SYLLABLE JJIH +CC28;CC28;110E 1161;CC28;110E 1161; # (차; 차; 차; 차; 차; ) HANGUL SYLLABLE CA +CC29;CC29;110E 1161 11A8;CC29;110E 1161 11A8; # (착; 착; 착; 착; 착; ) HANGUL SYLLABLE CAG +CC2A;CC2A;110E 1161 11A9;CC2A;110E 1161 11A9; # (찪; 찪; 찪; 찪; 찪; ) HANGUL SYLLABLE CAGG +CC2B;CC2B;110E 1161 11AA;CC2B;110E 1161 11AA; # (찫; 찫; 찫; 찫; 찫; ) HANGUL SYLLABLE CAGS +CC2C;CC2C;110E 1161 11AB;CC2C;110E 1161 11AB; # (찬; 찬; 찬; 찬; 찬; ) HANGUL SYLLABLE CAN +CC2D;CC2D;110E 1161 11AC;CC2D;110E 1161 11AC; # (찭; 찭; 찭; 찭; 찭; ) HANGUL SYLLABLE CANJ +CC2E;CC2E;110E 1161 11AD;CC2E;110E 1161 11AD; # (찮; 찮; 찮; 찮; 찮; ) HANGUL SYLLABLE CANH +CC2F;CC2F;110E 1161 11AE;CC2F;110E 1161 11AE; # (찯; 찯; 찯; 찯; 찯; ) HANGUL SYLLABLE CAD +CC30;CC30;110E 1161 11AF;CC30;110E 1161 11AF; # (찰; 찰; 찰; 찰; 찰; ) HANGUL SYLLABLE CAL +CC31;CC31;110E 1161 11B0;CC31;110E 1161 11B0; # (찱; 찱; 찱; 찱; 찱; ) HANGUL SYLLABLE CALG +CC32;CC32;110E 1161 11B1;CC32;110E 1161 11B1; # (찲; 찲; 찲; 찲; 찲; ) HANGUL SYLLABLE CALM +CC33;CC33;110E 1161 11B2;CC33;110E 1161 11B2; # (찳; 찳; 찳; 찳; 찳; ) HANGUL SYLLABLE CALB +CC34;CC34;110E 1161 11B3;CC34;110E 1161 11B3; # (찴; 찴; 찴; 찴; 찴; ) HANGUL SYLLABLE CALS +CC35;CC35;110E 1161 11B4;CC35;110E 1161 11B4; # (찵; 찵; 찵; 찵; 찵; ) HANGUL SYLLABLE CALT +CC36;CC36;110E 1161 11B5;CC36;110E 1161 11B5; # (찶; 찶; 찶; 찶; 찶; ) HANGUL SYLLABLE CALP +CC37;CC37;110E 1161 11B6;CC37;110E 1161 11B6; # (찷; 찷; 찷; 찷; 찷; ) HANGUL SYLLABLE CALH +CC38;CC38;110E 1161 11B7;CC38;110E 1161 11B7; # (참; 참; 참; 참; 참; ) HANGUL SYLLABLE CAM +CC39;CC39;110E 1161 11B8;CC39;110E 1161 11B8; # (찹; 찹; 찹; 찹; 찹; ) HANGUL SYLLABLE CAB +CC3A;CC3A;110E 1161 11B9;CC3A;110E 1161 11B9; # (찺; 찺; 찺; 찺; 찺; ) HANGUL SYLLABLE CABS +CC3B;CC3B;110E 1161 11BA;CC3B;110E 1161 11BA; # (찻; 찻; 찻; 찻; 찻; ) HANGUL SYLLABLE CAS +CC3C;CC3C;110E 1161 11BB;CC3C;110E 1161 11BB; # (찼; 찼; 찼; 찼; 찼; ) HANGUL SYLLABLE CASS +CC3D;CC3D;110E 1161 11BC;CC3D;110E 1161 11BC; # (창; 창; 창; 창; 창; ) HANGUL SYLLABLE CANG +CC3E;CC3E;110E 1161 11BD;CC3E;110E 1161 11BD; # (찾; 찾; 찾; 찾; 찾; ) HANGUL SYLLABLE CAJ +CC3F;CC3F;110E 1161 11BE;CC3F;110E 1161 11BE; # (찿; 찿; 찿; 찿; 찿; ) HANGUL SYLLABLE CAC +CC40;CC40;110E 1161 11BF;CC40;110E 1161 11BF; # (챀; 챀; 챀; 챀; 챀; ) HANGUL SYLLABLE CAK +CC41;CC41;110E 1161 11C0;CC41;110E 1161 11C0; # (챁; 챁; 챁; 챁; 챁; ) HANGUL SYLLABLE CAT +CC42;CC42;110E 1161 11C1;CC42;110E 1161 11C1; # (챂; 챂; 챂; 챂; 챂; ) HANGUL SYLLABLE CAP +CC43;CC43;110E 1161 11C2;CC43;110E 1161 11C2; # (챃; 챃; 챃; 챃; 챃; ) HANGUL SYLLABLE CAH +CC44;CC44;110E 1162;CC44;110E 1162; # (채; 채; 채; 채; 채; ) HANGUL SYLLABLE CAE +CC45;CC45;110E 1162 11A8;CC45;110E 1162 11A8; # (책; 책; 책; 책; 책; ) HANGUL SYLLABLE CAEG +CC46;CC46;110E 1162 11A9;CC46;110E 1162 11A9; # (챆; 챆; 챆; 챆; 챆; ) HANGUL SYLLABLE CAEGG +CC47;CC47;110E 1162 11AA;CC47;110E 1162 11AA; # (챇; 챇; 챇; 챇; 챇; ) HANGUL SYLLABLE CAEGS +CC48;CC48;110E 1162 11AB;CC48;110E 1162 11AB; # (챈; 챈; 챈; 챈; 챈; ) HANGUL SYLLABLE CAEN +CC49;CC49;110E 1162 11AC;CC49;110E 1162 11AC; # (챉; 챉; 챉; 챉; 챉; ) HANGUL SYLLABLE CAENJ +CC4A;CC4A;110E 1162 11AD;CC4A;110E 1162 11AD; # (챊; 챊; 챊; 챊; 챊; ) HANGUL SYLLABLE CAENH +CC4B;CC4B;110E 1162 11AE;CC4B;110E 1162 11AE; # (챋; 챋; 챋; 챋; 챋; ) HANGUL SYLLABLE CAED +CC4C;CC4C;110E 1162 11AF;CC4C;110E 1162 11AF; # (챌; 챌; 챌; 챌; 챌; ) HANGUL SYLLABLE CAEL +CC4D;CC4D;110E 1162 11B0;CC4D;110E 1162 11B0; # (챍; 챍; 챍; 챍; 챍; ) HANGUL SYLLABLE CAELG +CC4E;CC4E;110E 1162 11B1;CC4E;110E 1162 11B1; # (챎; 챎; 챎; 챎; 챎; ) HANGUL SYLLABLE CAELM +CC4F;CC4F;110E 1162 11B2;CC4F;110E 1162 11B2; # (챏; 챏; 챏; 챏; 챏; ) HANGUL SYLLABLE CAELB +CC50;CC50;110E 1162 11B3;CC50;110E 1162 11B3; # (챐; 챐; 챐; 챐; 챐; ) HANGUL SYLLABLE CAELS +CC51;CC51;110E 1162 11B4;CC51;110E 1162 11B4; # (챑; 챑; 챑; 챑; 챑; ) HANGUL SYLLABLE CAELT +CC52;CC52;110E 1162 11B5;CC52;110E 1162 11B5; # (챒; 챒; 챒; 챒; 챒; ) HANGUL SYLLABLE CAELP +CC53;CC53;110E 1162 11B6;CC53;110E 1162 11B6; # (챓; 챓; 챓; 챓; 챓; ) HANGUL SYLLABLE CAELH +CC54;CC54;110E 1162 11B7;CC54;110E 1162 11B7; # (챔; 챔; 챔; 챔; 챔; ) HANGUL SYLLABLE CAEM +CC55;CC55;110E 1162 11B8;CC55;110E 1162 11B8; # (챕; 챕; 챕; 챕; 챕; ) HANGUL SYLLABLE CAEB +CC56;CC56;110E 1162 11B9;CC56;110E 1162 11B9; # (챖; 챖; 챖; 챖; 챖; ) HANGUL SYLLABLE CAEBS +CC57;CC57;110E 1162 11BA;CC57;110E 1162 11BA; # (챗; 챗; 챗; 챗; 챗; ) HANGUL SYLLABLE CAES +CC58;CC58;110E 1162 11BB;CC58;110E 1162 11BB; # (챘; 챘; 챘; 챘; 챘; ) HANGUL SYLLABLE CAESS +CC59;CC59;110E 1162 11BC;CC59;110E 1162 11BC; # (챙; 챙; 챙; 챙; 챙; ) HANGUL SYLLABLE CAENG +CC5A;CC5A;110E 1162 11BD;CC5A;110E 1162 11BD; # (챚; 챚; 챚; 챚; 챚; ) HANGUL SYLLABLE CAEJ +CC5B;CC5B;110E 1162 11BE;CC5B;110E 1162 11BE; # (챛; 챛; 챛; 챛; 챛; ) HANGUL SYLLABLE CAEC +CC5C;CC5C;110E 1162 11BF;CC5C;110E 1162 11BF; # (챜; 챜; 챜; 챜; 챜; ) HANGUL SYLLABLE CAEK +CC5D;CC5D;110E 1162 11C0;CC5D;110E 1162 11C0; # (챝; 챝; 챝; 챝; 챝; ) HANGUL SYLLABLE CAET +CC5E;CC5E;110E 1162 11C1;CC5E;110E 1162 11C1; # (챞; 챞; 챞; 챞; 챞; ) HANGUL SYLLABLE CAEP +CC5F;CC5F;110E 1162 11C2;CC5F;110E 1162 11C2; # (챟; 챟; 챟; 챟; 챟; ) HANGUL SYLLABLE CAEH +CC60;CC60;110E 1163;CC60;110E 1163; # (챠; 챠; 챠; 챠; 챠; ) HANGUL SYLLABLE CYA +CC61;CC61;110E 1163 11A8;CC61;110E 1163 11A8; # (챡; 챡; 챡; 챡; 챡; ) HANGUL SYLLABLE CYAG +CC62;CC62;110E 1163 11A9;CC62;110E 1163 11A9; # (챢; 챢; 챢; 챢; 챢; ) HANGUL SYLLABLE CYAGG +CC63;CC63;110E 1163 11AA;CC63;110E 1163 11AA; # (챣; 챣; 챣; 챣; 챣; ) HANGUL SYLLABLE CYAGS +CC64;CC64;110E 1163 11AB;CC64;110E 1163 11AB; # (챤; 챤; 챤; 챤; 챤; ) HANGUL SYLLABLE CYAN +CC65;CC65;110E 1163 11AC;CC65;110E 1163 11AC; # (챥; 챥; 챥; 챥; 챥; ) HANGUL SYLLABLE CYANJ +CC66;CC66;110E 1163 11AD;CC66;110E 1163 11AD; # (챦; 챦; 챦; 챦; 챦; ) HANGUL SYLLABLE CYANH +CC67;CC67;110E 1163 11AE;CC67;110E 1163 11AE; # (챧; 챧; 챧; 챧; 챧; ) HANGUL SYLLABLE CYAD +CC68;CC68;110E 1163 11AF;CC68;110E 1163 11AF; # (챨; 챨; 챨; 챨; 챨; ) HANGUL SYLLABLE CYAL +CC69;CC69;110E 1163 11B0;CC69;110E 1163 11B0; # (챩; 챩; 챩; 챩; 챩; ) HANGUL SYLLABLE CYALG +CC6A;CC6A;110E 1163 11B1;CC6A;110E 1163 11B1; # (챪; 챪; 챪; 챪; 챪; ) HANGUL SYLLABLE CYALM +CC6B;CC6B;110E 1163 11B2;CC6B;110E 1163 11B2; # (챫; 챫; 챫; 챫; 챫; ) HANGUL SYLLABLE CYALB +CC6C;CC6C;110E 1163 11B3;CC6C;110E 1163 11B3; # (챬; 챬; 챬; 챬; 챬; ) HANGUL SYLLABLE CYALS +CC6D;CC6D;110E 1163 11B4;CC6D;110E 1163 11B4; # (챭; 챭; 챭; 챭; 챭; ) HANGUL SYLLABLE CYALT +CC6E;CC6E;110E 1163 11B5;CC6E;110E 1163 11B5; # (챮; 챮; 챮; 챮; 챮; ) HANGUL SYLLABLE CYALP +CC6F;CC6F;110E 1163 11B6;CC6F;110E 1163 11B6; # (챯; 챯; 챯; 챯; 챯; ) HANGUL SYLLABLE CYALH +CC70;CC70;110E 1163 11B7;CC70;110E 1163 11B7; # (챰; 챰; 챰; 챰; 챰; ) HANGUL SYLLABLE CYAM +CC71;CC71;110E 1163 11B8;CC71;110E 1163 11B8; # (챱; 챱; 챱; 챱; 챱; ) HANGUL SYLLABLE CYAB +CC72;CC72;110E 1163 11B9;CC72;110E 1163 11B9; # (챲; 챲; 챲; 챲; 챲; ) HANGUL SYLLABLE CYABS +CC73;CC73;110E 1163 11BA;CC73;110E 1163 11BA; # (챳; 챳; 챳; 챳; 챳; ) HANGUL SYLLABLE CYAS +CC74;CC74;110E 1163 11BB;CC74;110E 1163 11BB; # (챴; 챴; 챴; 챴; 챴; ) HANGUL SYLLABLE CYASS +CC75;CC75;110E 1163 11BC;CC75;110E 1163 11BC; # (챵; 챵; 챵; 챵; 챵; ) HANGUL SYLLABLE CYANG +CC76;CC76;110E 1163 11BD;CC76;110E 1163 11BD; # (챶; 챶; 챶; 챶; 챶; ) HANGUL SYLLABLE CYAJ +CC77;CC77;110E 1163 11BE;CC77;110E 1163 11BE; # (챷; 챷; 챷; 챷; 챷; ) HANGUL SYLLABLE CYAC +CC78;CC78;110E 1163 11BF;CC78;110E 1163 11BF; # (챸; 챸; 챸; 챸; 챸; ) HANGUL SYLLABLE CYAK +CC79;CC79;110E 1163 11C0;CC79;110E 1163 11C0; # (챹; 챹; 챹; 챹; 챹; ) HANGUL SYLLABLE CYAT +CC7A;CC7A;110E 1163 11C1;CC7A;110E 1163 11C1; # (챺; 챺; 챺; 챺; 챺; ) HANGUL SYLLABLE CYAP +CC7B;CC7B;110E 1163 11C2;CC7B;110E 1163 11C2; # (챻; 챻; 챻; 챻; 챻; ) HANGUL SYLLABLE CYAH +CC7C;CC7C;110E 1164;CC7C;110E 1164; # (챼; 챼; 챼; 챼; 챼; ) HANGUL SYLLABLE CYAE +CC7D;CC7D;110E 1164 11A8;CC7D;110E 1164 11A8; # (챽; 챽; 챽; 챽; 챽; ) HANGUL SYLLABLE CYAEG +CC7E;CC7E;110E 1164 11A9;CC7E;110E 1164 11A9; # (챾; 챾; 챾; 챾; 챾; ) HANGUL SYLLABLE CYAEGG +CC7F;CC7F;110E 1164 11AA;CC7F;110E 1164 11AA; # (챿; 챿; 챿; 챿; 챿; ) HANGUL SYLLABLE CYAEGS +CC80;CC80;110E 1164 11AB;CC80;110E 1164 11AB; # (첀; 첀; 첀; 첀; 첀; ) HANGUL SYLLABLE CYAEN +CC81;CC81;110E 1164 11AC;CC81;110E 1164 11AC; # (첁; 첁; 첁; 첁; 첁; ) HANGUL SYLLABLE CYAENJ +CC82;CC82;110E 1164 11AD;CC82;110E 1164 11AD; # (첂; 첂; 첂; 첂; 첂; ) HANGUL SYLLABLE CYAENH +CC83;CC83;110E 1164 11AE;CC83;110E 1164 11AE; # (첃; 첃; 첃; 첃; 첃; ) HANGUL SYLLABLE CYAED +CC84;CC84;110E 1164 11AF;CC84;110E 1164 11AF; # (첄; 첄; 첄; 첄; 첄; ) HANGUL SYLLABLE CYAEL +CC85;CC85;110E 1164 11B0;CC85;110E 1164 11B0; # (첅; 첅; 첅; 첅; 첅; ) HANGUL SYLLABLE CYAELG +CC86;CC86;110E 1164 11B1;CC86;110E 1164 11B1; # (첆; 첆; 첆; 첆; 첆; ) HANGUL SYLLABLE CYAELM +CC87;CC87;110E 1164 11B2;CC87;110E 1164 11B2; # (첇; 첇; 첇; 첇; 첇; ) HANGUL SYLLABLE CYAELB +CC88;CC88;110E 1164 11B3;CC88;110E 1164 11B3; # (첈; 첈; 첈; 첈; 첈; ) HANGUL SYLLABLE CYAELS +CC89;CC89;110E 1164 11B4;CC89;110E 1164 11B4; # (첉; 첉; 첉; 첉; 첉; ) HANGUL SYLLABLE CYAELT +CC8A;CC8A;110E 1164 11B5;CC8A;110E 1164 11B5; # (첊; 첊; 첊; 첊; 첊; ) HANGUL SYLLABLE CYAELP +CC8B;CC8B;110E 1164 11B6;CC8B;110E 1164 11B6; # (첋; 첋; 첋; 첋; 첋; ) HANGUL SYLLABLE CYAELH +CC8C;CC8C;110E 1164 11B7;CC8C;110E 1164 11B7; # (첌; 첌; 첌; 첌; 첌; ) HANGUL SYLLABLE CYAEM +CC8D;CC8D;110E 1164 11B8;CC8D;110E 1164 11B8; # (첍; 첍; 첍; 첍; 첍; ) HANGUL SYLLABLE CYAEB +CC8E;CC8E;110E 1164 11B9;CC8E;110E 1164 11B9; # (첎; 첎; 첎; 첎; 첎; ) HANGUL SYLLABLE CYAEBS +CC8F;CC8F;110E 1164 11BA;CC8F;110E 1164 11BA; # (첏; 첏; 첏; 첏; 첏; ) HANGUL SYLLABLE CYAES +CC90;CC90;110E 1164 11BB;CC90;110E 1164 11BB; # (첐; 첐; 첐; 첐; 첐; ) HANGUL SYLLABLE CYAESS +CC91;CC91;110E 1164 11BC;CC91;110E 1164 11BC; # (첑; 첑; 첑; 첑; 첑; ) HANGUL SYLLABLE CYAENG +CC92;CC92;110E 1164 11BD;CC92;110E 1164 11BD; # (첒; 첒; 첒; 첒; 첒; ) HANGUL SYLLABLE CYAEJ +CC93;CC93;110E 1164 11BE;CC93;110E 1164 11BE; # (첓; 첓; 첓; 첓; 첓; ) HANGUL SYLLABLE CYAEC +CC94;CC94;110E 1164 11BF;CC94;110E 1164 11BF; # (첔; 첔; 첔; 첔; 첔; ) HANGUL SYLLABLE CYAEK +CC95;CC95;110E 1164 11C0;CC95;110E 1164 11C0; # (첕; 첕; 첕; 첕; 첕; ) HANGUL SYLLABLE CYAET +CC96;CC96;110E 1164 11C1;CC96;110E 1164 11C1; # (첖; 첖; 첖; 첖; 첖; ) HANGUL SYLLABLE CYAEP +CC97;CC97;110E 1164 11C2;CC97;110E 1164 11C2; # (첗; 첗; 첗; 첗; 첗; ) HANGUL SYLLABLE CYAEH +CC98;CC98;110E 1165;CC98;110E 1165; # (처; 처; 처; 처; 처; ) HANGUL SYLLABLE CEO +CC99;CC99;110E 1165 11A8;CC99;110E 1165 11A8; # (척; 척; 척; 척; 척; ) HANGUL SYLLABLE CEOG +CC9A;CC9A;110E 1165 11A9;CC9A;110E 1165 11A9; # (첚; 첚; 첚; 첚; 첚; ) HANGUL SYLLABLE CEOGG +CC9B;CC9B;110E 1165 11AA;CC9B;110E 1165 11AA; # (첛; 첛; 첛; 첛; 첛; ) HANGUL SYLLABLE CEOGS +CC9C;CC9C;110E 1165 11AB;CC9C;110E 1165 11AB; # (천; 천; 천; 천; 천; ) HANGUL SYLLABLE CEON +CC9D;CC9D;110E 1165 11AC;CC9D;110E 1165 11AC; # (첝; 첝; 첝; 첝; 첝; ) HANGUL SYLLABLE CEONJ +CC9E;CC9E;110E 1165 11AD;CC9E;110E 1165 11AD; # (첞; 첞; 첞; 첞; 첞; ) HANGUL SYLLABLE CEONH +CC9F;CC9F;110E 1165 11AE;CC9F;110E 1165 11AE; # (첟; 첟; 첟; 첟; 첟; ) HANGUL SYLLABLE CEOD +CCA0;CCA0;110E 1165 11AF;CCA0;110E 1165 11AF; # (철; 철; 철; 철; 철; ) HANGUL SYLLABLE CEOL +CCA1;CCA1;110E 1165 11B0;CCA1;110E 1165 11B0; # (첡; 첡; 첡; 첡; 첡; ) HANGUL SYLLABLE CEOLG +CCA2;CCA2;110E 1165 11B1;CCA2;110E 1165 11B1; # (첢; 첢; 첢; 첢; 첢; ) HANGUL SYLLABLE CEOLM +CCA3;CCA3;110E 1165 11B2;CCA3;110E 1165 11B2; # (첣; 첣; 첣; 첣; 첣; ) HANGUL SYLLABLE CEOLB +CCA4;CCA4;110E 1165 11B3;CCA4;110E 1165 11B3; # (첤; 첤; 첤; 첤; 첤; ) HANGUL SYLLABLE CEOLS +CCA5;CCA5;110E 1165 11B4;CCA5;110E 1165 11B4; # (첥; 첥; 첥; 첥; 첥; ) HANGUL SYLLABLE CEOLT +CCA6;CCA6;110E 1165 11B5;CCA6;110E 1165 11B5; # (첦; 첦; 첦; 첦; 첦; ) HANGUL SYLLABLE CEOLP +CCA7;CCA7;110E 1165 11B6;CCA7;110E 1165 11B6; # (첧; 첧; 첧; 첧; 첧; ) HANGUL SYLLABLE CEOLH +CCA8;CCA8;110E 1165 11B7;CCA8;110E 1165 11B7; # (첨; 첨; 첨; 첨; 첨; ) HANGUL SYLLABLE CEOM +CCA9;CCA9;110E 1165 11B8;CCA9;110E 1165 11B8; # (첩; 첩; 첩; 첩; 첩; ) HANGUL SYLLABLE CEOB +CCAA;CCAA;110E 1165 11B9;CCAA;110E 1165 11B9; # (첪; 첪; 첪; 첪; 첪; ) HANGUL SYLLABLE CEOBS +CCAB;CCAB;110E 1165 11BA;CCAB;110E 1165 11BA; # (첫; 첫; 첫; 첫; 첫; ) HANGUL SYLLABLE CEOS +CCAC;CCAC;110E 1165 11BB;CCAC;110E 1165 11BB; # (첬; 첬; 첬; 첬; 첬; ) HANGUL SYLLABLE CEOSS +CCAD;CCAD;110E 1165 11BC;CCAD;110E 1165 11BC; # (청; 청; 청; 청; 청; ) HANGUL SYLLABLE CEONG +CCAE;CCAE;110E 1165 11BD;CCAE;110E 1165 11BD; # (첮; 첮; 첮; 첮; 첮; ) HANGUL SYLLABLE CEOJ +CCAF;CCAF;110E 1165 11BE;CCAF;110E 1165 11BE; # (첯; 첯; 첯; 첯; 첯; ) HANGUL SYLLABLE CEOC +CCB0;CCB0;110E 1165 11BF;CCB0;110E 1165 11BF; # (첰; 첰; 첰; 첰; 첰; ) HANGUL SYLLABLE CEOK +CCB1;CCB1;110E 1165 11C0;CCB1;110E 1165 11C0; # (첱; 첱; 첱; 첱; 첱; ) HANGUL SYLLABLE CEOT +CCB2;CCB2;110E 1165 11C1;CCB2;110E 1165 11C1; # (첲; 첲; 첲; 첲; 첲; ) HANGUL SYLLABLE CEOP +CCB3;CCB3;110E 1165 11C2;CCB3;110E 1165 11C2; # (첳; 첳; 첳; 첳; 첳; ) HANGUL SYLLABLE CEOH +CCB4;CCB4;110E 1166;CCB4;110E 1166; # (체; 체; 체; 체; 체; ) HANGUL SYLLABLE CE +CCB5;CCB5;110E 1166 11A8;CCB5;110E 1166 11A8; # (첵; 첵; 첵; 첵; 첵; ) HANGUL SYLLABLE CEG +CCB6;CCB6;110E 1166 11A9;CCB6;110E 1166 11A9; # (첶; 첶; 첶; 첶; 첶; ) HANGUL SYLLABLE CEGG +CCB7;CCB7;110E 1166 11AA;CCB7;110E 1166 11AA; # (첷; 첷; 첷; 첷; 첷; ) HANGUL SYLLABLE CEGS +CCB8;CCB8;110E 1166 11AB;CCB8;110E 1166 11AB; # (첸; 첸; 첸; 첸; 첸; ) HANGUL SYLLABLE CEN +CCB9;CCB9;110E 1166 11AC;CCB9;110E 1166 11AC; # (첹; 첹; 첹; 첹; 첹; ) HANGUL SYLLABLE CENJ +CCBA;CCBA;110E 1166 11AD;CCBA;110E 1166 11AD; # (첺; 첺; 첺; 첺; 첺; ) HANGUL SYLLABLE CENH +CCBB;CCBB;110E 1166 11AE;CCBB;110E 1166 11AE; # (첻; 첻; 첻; 첻; 첻; ) HANGUL SYLLABLE CED +CCBC;CCBC;110E 1166 11AF;CCBC;110E 1166 11AF; # (첼; 첼; 첼; 첼; 첼; ) HANGUL SYLLABLE CEL +CCBD;CCBD;110E 1166 11B0;CCBD;110E 1166 11B0; # (첽; 첽; 첽; 첽; 첽; ) HANGUL SYLLABLE CELG +CCBE;CCBE;110E 1166 11B1;CCBE;110E 1166 11B1; # (첾; 첾; 첾; 첾; 첾; ) HANGUL SYLLABLE CELM +CCBF;CCBF;110E 1166 11B2;CCBF;110E 1166 11B2; # (첿; 첿; 첿; 첿; 첿; ) HANGUL SYLLABLE CELB +CCC0;CCC0;110E 1166 11B3;CCC0;110E 1166 11B3; # (쳀; 쳀; 쳀; 쳀; 쳀; ) HANGUL SYLLABLE CELS +CCC1;CCC1;110E 1166 11B4;CCC1;110E 1166 11B4; # (쳁; 쳁; 쳁; 쳁; 쳁; ) HANGUL SYLLABLE CELT +CCC2;CCC2;110E 1166 11B5;CCC2;110E 1166 11B5; # (쳂; 쳂; 쳂; 쳂; 쳂; ) HANGUL SYLLABLE CELP +CCC3;CCC3;110E 1166 11B6;CCC3;110E 1166 11B6; # (쳃; 쳃; 쳃; 쳃; 쳃; ) HANGUL SYLLABLE CELH +CCC4;CCC4;110E 1166 11B7;CCC4;110E 1166 11B7; # (쳄; 쳄; 쳄; 쳄; 쳄; ) HANGUL SYLLABLE CEM +CCC5;CCC5;110E 1166 11B8;CCC5;110E 1166 11B8; # (쳅; 쳅; 쳅; 쳅; 쳅; ) HANGUL SYLLABLE CEB +CCC6;CCC6;110E 1166 11B9;CCC6;110E 1166 11B9; # (쳆; 쳆; 쳆; 쳆; 쳆; ) HANGUL SYLLABLE CEBS +CCC7;CCC7;110E 1166 11BA;CCC7;110E 1166 11BA; # (쳇; 쳇; 쳇; 쳇; 쳇; ) HANGUL SYLLABLE CES +CCC8;CCC8;110E 1166 11BB;CCC8;110E 1166 11BB; # (쳈; 쳈; 쳈; 쳈; 쳈; ) HANGUL SYLLABLE CESS +CCC9;CCC9;110E 1166 11BC;CCC9;110E 1166 11BC; # (쳉; 쳉; 쳉; 쳉; 쳉; ) HANGUL SYLLABLE CENG +CCCA;CCCA;110E 1166 11BD;CCCA;110E 1166 11BD; # (쳊; 쳊; 쳊; 쳊; 쳊; ) HANGUL SYLLABLE CEJ +CCCB;CCCB;110E 1166 11BE;CCCB;110E 1166 11BE; # (쳋; 쳋; 쳋; 쳋; 쳋; ) HANGUL SYLLABLE CEC +CCCC;CCCC;110E 1166 11BF;CCCC;110E 1166 11BF; # (쳌; 쳌; 쳌; 쳌; 쳌; ) HANGUL SYLLABLE CEK +CCCD;CCCD;110E 1166 11C0;CCCD;110E 1166 11C0; # (쳍; 쳍; 쳍; 쳍; 쳍; ) HANGUL SYLLABLE CET +CCCE;CCCE;110E 1166 11C1;CCCE;110E 1166 11C1; # (쳎; 쳎; 쳎; 쳎; 쳎; ) HANGUL SYLLABLE CEP +CCCF;CCCF;110E 1166 11C2;CCCF;110E 1166 11C2; # (쳏; 쳏; 쳏; 쳏; 쳏; ) HANGUL SYLLABLE CEH +CCD0;CCD0;110E 1167;CCD0;110E 1167; # (쳐; 쳐; 쳐; 쳐; 쳐; ) HANGUL SYLLABLE CYEO +CCD1;CCD1;110E 1167 11A8;CCD1;110E 1167 11A8; # (쳑; 쳑; 쳑; 쳑; 쳑; ) HANGUL SYLLABLE CYEOG +CCD2;CCD2;110E 1167 11A9;CCD2;110E 1167 11A9; # (쳒; 쳒; 쳒; 쳒; 쳒; ) HANGUL SYLLABLE CYEOGG +CCD3;CCD3;110E 1167 11AA;CCD3;110E 1167 11AA; # (쳓; 쳓; 쳓; 쳓; 쳓; ) HANGUL SYLLABLE CYEOGS +CCD4;CCD4;110E 1167 11AB;CCD4;110E 1167 11AB; # (쳔; 쳔; 쳔; 쳔; 쳔; ) HANGUL SYLLABLE CYEON +CCD5;CCD5;110E 1167 11AC;CCD5;110E 1167 11AC; # (쳕; 쳕; 쳕; 쳕; 쳕; ) HANGUL SYLLABLE CYEONJ +CCD6;CCD6;110E 1167 11AD;CCD6;110E 1167 11AD; # (쳖; 쳖; 쳖; 쳖; 쳖; ) HANGUL SYLLABLE CYEONH +CCD7;CCD7;110E 1167 11AE;CCD7;110E 1167 11AE; # (쳗; 쳗; 쳗; 쳗; 쳗; ) HANGUL SYLLABLE CYEOD +CCD8;CCD8;110E 1167 11AF;CCD8;110E 1167 11AF; # (쳘; 쳘; 쳘; 쳘; 쳘; ) HANGUL SYLLABLE CYEOL +CCD9;CCD9;110E 1167 11B0;CCD9;110E 1167 11B0; # (쳙; 쳙; 쳙; 쳙; 쳙; ) HANGUL SYLLABLE CYEOLG +CCDA;CCDA;110E 1167 11B1;CCDA;110E 1167 11B1; # (쳚; 쳚; 쳚; 쳚; 쳚; ) HANGUL SYLLABLE CYEOLM +CCDB;CCDB;110E 1167 11B2;CCDB;110E 1167 11B2; # (쳛; 쳛; 쳛; 쳛; 쳛; ) HANGUL SYLLABLE CYEOLB +CCDC;CCDC;110E 1167 11B3;CCDC;110E 1167 11B3; # (쳜; 쳜; 쳜; 쳜; 쳜; ) HANGUL SYLLABLE CYEOLS +CCDD;CCDD;110E 1167 11B4;CCDD;110E 1167 11B4; # (쳝; 쳝; 쳝; 쳝; 쳝; ) HANGUL SYLLABLE CYEOLT +CCDE;CCDE;110E 1167 11B5;CCDE;110E 1167 11B5; # (쳞; 쳞; 쳞; 쳞; 쳞; ) HANGUL SYLLABLE CYEOLP +CCDF;CCDF;110E 1167 11B6;CCDF;110E 1167 11B6; # (쳟; 쳟; 쳟; 쳟; 쳟; ) HANGUL SYLLABLE CYEOLH +CCE0;CCE0;110E 1167 11B7;CCE0;110E 1167 11B7; # (쳠; 쳠; 쳠; 쳠; 쳠; ) HANGUL SYLLABLE CYEOM +CCE1;CCE1;110E 1167 11B8;CCE1;110E 1167 11B8; # (쳡; 쳡; 쳡; 쳡; 쳡; ) HANGUL SYLLABLE CYEOB +CCE2;CCE2;110E 1167 11B9;CCE2;110E 1167 11B9; # (쳢; 쳢; 쳢; 쳢; 쳢; ) HANGUL SYLLABLE CYEOBS +CCE3;CCE3;110E 1167 11BA;CCE3;110E 1167 11BA; # (쳣; 쳣; 쳣; 쳣; 쳣; ) HANGUL SYLLABLE CYEOS +CCE4;CCE4;110E 1167 11BB;CCE4;110E 1167 11BB; # (쳤; 쳤; 쳤; 쳤; 쳤; ) HANGUL SYLLABLE CYEOSS +CCE5;CCE5;110E 1167 11BC;CCE5;110E 1167 11BC; # (쳥; 쳥; 쳥; 쳥; 쳥; ) HANGUL SYLLABLE CYEONG +CCE6;CCE6;110E 1167 11BD;CCE6;110E 1167 11BD; # (쳦; 쳦; 쳦; 쳦; 쳦; ) HANGUL SYLLABLE CYEOJ +CCE7;CCE7;110E 1167 11BE;CCE7;110E 1167 11BE; # (쳧; 쳧; 쳧; 쳧; 쳧; ) HANGUL SYLLABLE CYEOC +CCE8;CCE8;110E 1167 11BF;CCE8;110E 1167 11BF; # (쳨; 쳨; 쳨; 쳨; 쳨; ) HANGUL SYLLABLE CYEOK +CCE9;CCE9;110E 1167 11C0;CCE9;110E 1167 11C0; # (쳩; 쳩; 쳩; 쳩; 쳩; ) HANGUL SYLLABLE CYEOT +CCEA;CCEA;110E 1167 11C1;CCEA;110E 1167 11C1; # (쳪; 쳪; 쳪; 쳪; 쳪; ) HANGUL SYLLABLE CYEOP +CCEB;CCEB;110E 1167 11C2;CCEB;110E 1167 11C2; # (쳫; 쳫; 쳫; 쳫; 쳫; ) HANGUL SYLLABLE CYEOH +CCEC;CCEC;110E 1168;CCEC;110E 1168; # (쳬; 쳬; 쳬; 쳬; 쳬; ) HANGUL SYLLABLE CYE +CCED;CCED;110E 1168 11A8;CCED;110E 1168 11A8; # (쳭; 쳭; 쳭; 쳭; 쳭; ) HANGUL SYLLABLE CYEG +CCEE;CCEE;110E 1168 11A9;CCEE;110E 1168 11A9; # (쳮; 쳮; 쳮; 쳮; 쳮; ) HANGUL SYLLABLE CYEGG +CCEF;CCEF;110E 1168 11AA;CCEF;110E 1168 11AA; # (쳯; 쳯; 쳯; 쳯; 쳯; ) HANGUL SYLLABLE CYEGS +CCF0;CCF0;110E 1168 11AB;CCF0;110E 1168 11AB; # (쳰; 쳰; 쳰; 쳰; 쳰; ) HANGUL SYLLABLE CYEN +CCF1;CCF1;110E 1168 11AC;CCF1;110E 1168 11AC; # (쳱; 쳱; 쳱; 쳱; 쳱; ) HANGUL SYLLABLE CYENJ +CCF2;CCF2;110E 1168 11AD;CCF2;110E 1168 11AD; # (쳲; 쳲; 쳲; 쳲; 쳲; ) HANGUL SYLLABLE CYENH +CCF3;CCF3;110E 1168 11AE;CCF3;110E 1168 11AE; # (쳳; 쳳; 쳳; 쳳; 쳳; ) HANGUL SYLLABLE CYED +CCF4;CCF4;110E 1168 11AF;CCF4;110E 1168 11AF; # (쳴; 쳴; 쳴; 쳴; 쳴; ) HANGUL SYLLABLE CYEL +CCF5;CCF5;110E 1168 11B0;CCF5;110E 1168 11B0; # (쳵; 쳵; 쳵; 쳵; 쳵; ) HANGUL SYLLABLE CYELG +CCF6;CCF6;110E 1168 11B1;CCF6;110E 1168 11B1; # (쳶; 쳶; 쳶; 쳶; 쳶; ) HANGUL SYLLABLE CYELM +CCF7;CCF7;110E 1168 11B2;CCF7;110E 1168 11B2; # (쳷; 쳷; 쳷; 쳷; 쳷; ) HANGUL SYLLABLE CYELB +CCF8;CCF8;110E 1168 11B3;CCF8;110E 1168 11B3; # (쳸; 쳸; 쳸; 쳸; 쳸; ) HANGUL SYLLABLE CYELS +CCF9;CCF9;110E 1168 11B4;CCF9;110E 1168 11B4; # (쳹; 쳹; 쳹; 쳹; 쳹; ) HANGUL SYLLABLE CYELT +CCFA;CCFA;110E 1168 11B5;CCFA;110E 1168 11B5; # (쳺; 쳺; 쳺; 쳺; 쳺; ) HANGUL SYLLABLE CYELP +CCFB;CCFB;110E 1168 11B6;CCFB;110E 1168 11B6; # (쳻; 쳻; 쳻; 쳻; 쳻; ) HANGUL SYLLABLE CYELH +CCFC;CCFC;110E 1168 11B7;CCFC;110E 1168 11B7; # (쳼; 쳼; 쳼; 쳼; 쳼; ) HANGUL SYLLABLE CYEM +CCFD;CCFD;110E 1168 11B8;CCFD;110E 1168 11B8; # (쳽; 쳽; 쳽; 쳽; 쳽; ) HANGUL SYLLABLE CYEB +CCFE;CCFE;110E 1168 11B9;CCFE;110E 1168 11B9; # (쳾; 쳾; 쳾; 쳾; 쳾; ) HANGUL SYLLABLE CYEBS +CCFF;CCFF;110E 1168 11BA;CCFF;110E 1168 11BA; # (쳿; 쳿; 쳿; 쳿; 쳿; ) HANGUL SYLLABLE CYES +CD00;CD00;110E 1168 11BB;CD00;110E 1168 11BB; # (촀; 촀; 촀; 촀; 촀; ) HANGUL SYLLABLE CYESS +CD01;CD01;110E 1168 11BC;CD01;110E 1168 11BC; # (촁; 촁; 촁; 촁; 촁; ) HANGUL SYLLABLE CYENG +CD02;CD02;110E 1168 11BD;CD02;110E 1168 11BD; # (촂; 촂; 촂; 촂; 촂; ) HANGUL SYLLABLE CYEJ +CD03;CD03;110E 1168 11BE;CD03;110E 1168 11BE; # (촃; 촃; 촃; 촃; 촃; ) HANGUL SYLLABLE CYEC +CD04;CD04;110E 1168 11BF;CD04;110E 1168 11BF; # (촄; 촄; 촄; 촄; 촄; ) HANGUL SYLLABLE CYEK +CD05;CD05;110E 1168 11C0;CD05;110E 1168 11C0; # (촅; 촅; 촅; 촅; 촅; ) HANGUL SYLLABLE CYET +CD06;CD06;110E 1168 11C1;CD06;110E 1168 11C1; # (촆; 촆; 촆; 촆; 촆; ) HANGUL SYLLABLE CYEP +CD07;CD07;110E 1168 11C2;CD07;110E 1168 11C2; # (촇; 촇; 촇; 촇; 촇; ) HANGUL SYLLABLE CYEH +CD08;CD08;110E 1169;CD08;110E 1169; # (초; 초; 초; 초; 초; ) HANGUL SYLLABLE CO +CD09;CD09;110E 1169 11A8;CD09;110E 1169 11A8; # (촉; 촉; 촉; 촉; 촉; ) HANGUL SYLLABLE COG +CD0A;CD0A;110E 1169 11A9;CD0A;110E 1169 11A9; # (촊; 촊; 촊; 촊; 촊; ) HANGUL SYLLABLE COGG +CD0B;CD0B;110E 1169 11AA;CD0B;110E 1169 11AA; # (촋; 촋; 촋; 촋; 촋; ) HANGUL SYLLABLE COGS +CD0C;CD0C;110E 1169 11AB;CD0C;110E 1169 11AB; # (촌; 촌; 촌; 촌; 촌; ) HANGUL SYLLABLE CON +CD0D;CD0D;110E 1169 11AC;CD0D;110E 1169 11AC; # (촍; 촍; 촍; 촍; 촍; ) HANGUL SYLLABLE CONJ +CD0E;CD0E;110E 1169 11AD;CD0E;110E 1169 11AD; # (촎; 촎; 촎; 촎; 촎; ) HANGUL SYLLABLE CONH +CD0F;CD0F;110E 1169 11AE;CD0F;110E 1169 11AE; # (촏; 촏; 촏; 촏; 촏; ) HANGUL SYLLABLE COD +CD10;CD10;110E 1169 11AF;CD10;110E 1169 11AF; # (촐; 촐; 촐; 촐; 촐; ) HANGUL SYLLABLE COL +CD11;CD11;110E 1169 11B0;CD11;110E 1169 11B0; # (촑; 촑; 촑; 촑; 촑; ) HANGUL SYLLABLE COLG +CD12;CD12;110E 1169 11B1;CD12;110E 1169 11B1; # (촒; 촒; 촒; 촒; 촒; ) HANGUL SYLLABLE COLM +CD13;CD13;110E 1169 11B2;CD13;110E 1169 11B2; # (촓; 촓; 촓; 촓; 촓; ) HANGUL SYLLABLE COLB +CD14;CD14;110E 1169 11B3;CD14;110E 1169 11B3; # (촔; 촔; 촔; 촔; 촔; ) HANGUL SYLLABLE COLS +CD15;CD15;110E 1169 11B4;CD15;110E 1169 11B4; # (촕; 촕; 촕; 촕; 촕; ) HANGUL SYLLABLE COLT +CD16;CD16;110E 1169 11B5;CD16;110E 1169 11B5; # (촖; 촖; 촖; 촖; 촖; ) HANGUL SYLLABLE COLP +CD17;CD17;110E 1169 11B6;CD17;110E 1169 11B6; # (촗; 촗; 촗; 촗; 촗; ) HANGUL SYLLABLE COLH +CD18;CD18;110E 1169 11B7;CD18;110E 1169 11B7; # (촘; 촘; 촘; 촘; 촘; ) HANGUL SYLLABLE COM +CD19;CD19;110E 1169 11B8;CD19;110E 1169 11B8; # (촙; 촙; 촙; 촙; 촙; ) HANGUL SYLLABLE COB +CD1A;CD1A;110E 1169 11B9;CD1A;110E 1169 11B9; # (촚; 촚; 촚; 촚; 촚; ) HANGUL SYLLABLE COBS +CD1B;CD1B;110E 1169 11BA;CD1B;110E 1169 11BA; # (촛; 촛; 촛; 촛; 촛; ) HANGUL SYLLABLE COS +CD1C;CD1C;110E 1169 11BB;CD1C;110E 1169 11BB; # (촜; 촜; 촜; 촜; 촜; ) HANGUL SYLLABLE COSS +CD1D;CD1D;110E 1169 11BC;CD1D;110E 1169 11BC; # (총; 총; 총; 총; 총; ) HANGUL SYLLABLE CONG +CD1E;CD1E;110E 1169 11BD;CD1E;110E 1169 11BD; # (촞; 촞; 촞; 촞; 촞; ) HANGUL SYLLABLE COJ +CD1F;CD1F;110E 1169 11BE;CD1F;110E 1169 11BE; # (촟; 촟; 촟; 촟; 촟; ) HANGUL SYLLABLE COC +CD20;CD20;110E 1169 11BF;CD20;110E 1169 11BF; # (촠; 촠; 촠; 촠; 촠; ) HANGUL SYLLABLE COK +CD21;CD21;110E 1169 11C0;CD21;110E 1169 11C0; # (촡; 촡; 촡; 촡; 촡; ) HANGUL SYLLABLE COT +CD22;CD22;110E 1169 11C1;CD22;110E 1169 11C1; # (촢; 촢; 촢; 촢; 촢; ) HANGUL SYLLABLE COP +CD23;CD23;110E 1169 11C2;CD23;110E 1169 11C2; # (촣; 촣; 촣; 촣; 촣; ) HANGUL SYLLABLE COH +CD24;CD24;110E 116A;CD24;110E 116A; # (촤; 촤; 촤; 촤; 촤; ) HANGUL SYLLABLE CWA +CD25;CD25;110E 116A 11A8;CD25;110E 116A 11A8; # (촥; 촥; 촥; 촥; 촥; ) HANGUL SYLLABLE CWAG +CD26;CD26;110E 116A 11A9;CD26;110E 116A 11A9; # (촦; 촦; 촦; 촦; 촦; ) HANGUL SYLLABLE CWAGG +CD27;CD27;110E 116A 11AA;CD27;110E 116A 11AA; # (촧; 촧; 촧; 촧; 촧; ) HANGUL SYLLABLE CWAGS +CD28;CD28;110E 116A 11AB;CD28;110E 116A 11AB; # (촨; 촨; 촨; 촨; 촨; ) HANGUL SYLLABLE CWAN +CD29;CD29;110E 116A 11AC;CD29;110E 116A 11AC; # (촩; 촩; 촩; 촩; 촩; ) HANGUL SYLLABLE CWANJ +CD2A;CD2A;110E 116A 11AD;CD2A;110E 116A 11AD; # (촪; 촪; 촪; 촪; 촪; ) HANGUL SYLLABLE CWANH +CD2B;CD2B;110E 116A 11AE;CD2B;110E 116A 11AE; # (촫; 촫; 촫; 촫; 촫; ) HANGUL SYLLABLE CWAD +CD2C;CD2C;110E 116A 11AF;CD2C;110E 116A 11AF; # (촬; 촬; 촬; 촬; 촬; ) HANGUL SYLLABLE CWAL +CD2D;CD2D;110E 116A 11B0;CD2D;110E 116A 11B0; # (촭; 촭; 촭; 촭; 촭; ) HANGUL SYLLABLE CWALG +CD2E;CD2E;110E 116A 11B1;CD2E;110E 116A 11B1; # (촮; 촮; 촮; 촮; 촮; ) HANGUL SYLLABLE CWALM +CD2F;CD2F;110E 116A 11B2;CD2F;110E 116A 11B2; # (촯; 촯; 촯; 촯; 촯; ) HANGUL SYLLABLE CWALB +CD30;CD30;110E 116A 11B3;CD30;110E 116A 11B3; # (촰; 촰; 촰; 촰; 촰; ) HANGUL SYLLABLE CWALS +CD31;CD31;110E 116A 11B4;CD31;110E 116A 11B4; # (촱; 촱; 촱; 촱; 촱; ) HANGUL SYLLABLE CWALT +CD32;CD32;110E 116A 11B5;CD32;110E 116A 11B5; # (촲; 촲; 촲; 촲; 촲; ) HANGUL SYLLABLE CWALP +CD33;CD33;110E 116A 11B6;CD33;110E 116A 11B6; # (촳; 촳; 촳; 촳; 촳; ) HANGUL SYLLABLE CWALH +CD34;CD34;110E 116A 11B7;CD34;110E 116A 11B7; # (촴; 촴; 촴; 촴; 촴; ) HANGUL SYLLABLE CWAM +CD35;CD35;110E 116A 11B8;CD35;110E 116A 11B8; # (촵; 촵; 촵; 촵; 촵; ) HANGUL SYLLABLE CWAB +CD36;CD36;110E 116A 11B9;CD36;110E 116A 11B9; # (촶; 촶; 촶; 촶; 촶; ) HANGUL SYLLABLE CWABS +CD37;CD37;110E 116A 11BA;CD37;110E 116A 11BA; # (촷; 촷; 촷; 촷; 촷; ) HANGUL SYLLABLE CWAS +CD38;CD38;110E 116A 11BB;CD38;110E 116A 11BB; # (촸; 촸; 촸; 촸; 촸; ) HANGUL SYLLABLE CWASS +CD39;CD39;110E 116A 11BC;CD39;110E 116A 11BC; # (촹; 촹; 촹; 촹; 촹; ) HANGUL SYLLABLE CWANG +CD3A;CD3A;110E 116A 11BD;CD3A;110E 116A 11BD; # (촺; 촺; 촺; 촺; 촺; ) HANGUL SYLLABLE CWAJ +CD3B;CD3B;110E 116A 11BE;CD3B;110E 116A 11BE; # (촻; 촻; 촻; 촻; 촻; ) HANGUL SYLLABLE CWAC +CD3C;CD3C;110E 116A 11BF;CD3C;110E 116A 11BF; # (촼; 촼; 촼; 촼; 촼; ) HANGUL SYLLABLE CWAK +CD3D;CD3D;110E 116A 11C0;CD3D;110E 116A 11C0; # (촽; 촽; 촽; 촽; 촽; ) HANGUL SYLLABLE CWAT +CD3E;CD3E;110E 116A 11C1;CD3E;110E 116A 11C1; # (촾; 촾; 촾; 촾; 촾; ) HANGUL SYLLABLE CWAP +CD3F;CD3F;110E 116A 11C2;CD3F;110E 116A 11C2; # (촿; 촿; 촿; 촿; 촿; ) HANGUL SYLLABLE CWAH +CD40;CD40;110E 116B;CD40;110E 116B; # (쵀; 쵀; 쵀; 쵀; 쵀; ) HANGUL SYLLABLE CWAE +CD41;CD41;110E 116B 11A8;CD41;110E 116B 11A8; # (쵁; 쵁; 쵁; 쵁; 쵁; ) HANGUL SYLLABLE CWAEG +CD42;CD42;110E 116B 11A9;CD42;110E 116B 11A9; # (쵂; 쵂; 쵂; 쵂; 쵂; ) HANGUL SYLLABLE CWAEGG +CD43;CD43;110E 116B 11AA;CD43;110E 116B 11AA; # (쵃; 쵃; 쵃; 쵃; 쵃; ) HANGUL SYLLABLE CWAEGS +CD44;CD44;110E 116B 11AB;CD44;110E 116B 11AB; # (쵄; 쵄; 쵄; 쵄; 쵄; ) HANGUL SYLLABLE CWAEN +CD45;CD45;110E 116B 11AC;CD45;110E 116B 11AC; # (쵅; 쵅; 쵅; 쵅; 쵅; ) HANGUL SYLLABLE CWAENJ +CD46;CD46;110E 116B 11AD;CD46;110E 116B 11AD; # (쵆; 쵆; 쵆; 쵆; 쵆; ) HANGUL SYLLABLE CWAENH +CD47;CD47;110E 116B 11AE;CD47;110E 116B 11AE; # (쵇; 쵇; 쵇; 쵇; 쵇; ) HANGUL SYLLABLE CWAED +CD48;CD48;110E 116B 11AF;CD48;110E 116B 11AF; # (쵈; 쵈; 쵈; 쵈; 쵈; ) HANGUL SYLLABLE CWAEL +CD49;CD49;110E 116B 11B0;CD49;110E 116B 11B0; # (쵉; 쵉; 쵉; 쵉; 쵉; ) HANGUL SYLLABLE CWAELG +CD4A;CD4A;110E 116B 11B1;CD4A;110E 116B 11B1; # (쵊; 쵊; 쵊; 쵊; 쵊; ) HANGUL SYLLABLE CWAELM +CD4B;CD4B;110E 116B 11B2;CD4B;110E 116B 11B2; # (쵋; 쵋; 쵋; 쵋; 쵋; ) HANGUL SYLLABLE CWAELB +CD4C;CD4C;110E 116B 11B3;CD4C;110E 116B 11B3; # (쵌; 쵌; 쵌; 쵌; 쵌; ) HANGUL SYLLABLE CWAELS +CD4D;CD4D;110E 116B 11B4;CD4D;110E 116B 11B4; # (쵍; 쵍; 쵍; 쵍; 쵍; ) HANGUL SYLLABLE CWAELT +CD4E;CD4E;110E 116B 11B5;CD4E;110E 116B 11B5; # (쵎; 쵎; 쵎; 쵎; 쵎; ) HANGUL SYLLABLE CWAELP +CD4F;CD4F;110E 116B 11B6;CD4F;110E 116B 11B6; # (쵏; 쵏; 쵏; 쵏; 쵏; ) HANGUL SYLLABLE CWAELH +CD50;CD50;110E 116B 11B7;CD50;110E 116B 11B7; # (쵐; 쵐; 쵐; 쵐; 쵐; ) HANGUL SYLLABLE CWAEM +CD51;CD51;110E 116B 11B8;CD51;110E 116B 11B8; # (쵑; 쵑; 쵑; 쵑; 쵑; ) HANGUL SYLLABLE CWAEB +CD52;CD52;110E 116B 11B9;CD52;110E 116B 11B9; # (쵒; 쵒; 쵒; 쵒; 쵒; ) HANGUL SYLLABLE CWAEBS +CD53;CD53;110E 116B 11BA;CD53;110E 116B 11BA; # (쵓; 쵓; 쵓; 쵓; 쵓; ) HANGUL SYLLABLE CWAES +CD54;CD54;110E 116B 11BB;CD54;110E 116B 11BB; # (쵔; 쵔; 쵔; 쵔; 쵔; ) HANGUL SYLLABLE CWAESS +CD55;CD55;110E 116B 11BC;CD55;110E 116B 11BC; # (쵕; 쵕; 쵕; 쵕; 쵕; ) HANGUL SYLLABLE CWAENG +CD56;CD56;110E 116B 11BD;CD56;110E 116B 11BD; # (쵖; 쵖; 쵖; 쵖; 쵖; ) HANGUL SYLLABLE CWAEJ +CD57;CD57;110E 116B 11BE;CD57;110E 116B 11BE; # (쵗; 쵗; 쵗; 쵗; 쵗; ) HANGUL SYLLABLE CWAEC +CD58;CD58;110E 116B 11BF;CD58;110E 116B 11BF; # (쵘; 쵘; 쵘; 쵘; 쵘; ) HANGUL SYLLABLE CWAEK +CD59;CD59;110E 116B 11C0;CD59;110E 116B 11C0; # (쵙; 쵙; 쵙; 쵙; 쵙; ) HANGUL SYLLABLE CWAET +CD5A;CD5A;110E 116B 11C1;CD5A;110E 116B 11C1; # (쵚; 쵚; 쵚; 쵚; 쵚; ) HANGUL SYLLABLE CWAEP +CD5B;CD5B;110E 116B 11C2;CD5B;110E 116B 11C2; # (쵛; 쵛; 쵛; 쵛; 쵛; ) HANGUL SYLLABLE CWAEH +CD5C;CD5C;110E 116C;CD5C;110E 116C; # (최; 최; 최; 최; 최; ) HANGUL SYLLABLE COE +CD5D;CD5D;110E 116C 11A8;CD5D;110E 116C 11A8; # (쵝; 쵝; 쵝; 쵝; 쵝; ) HANGUL SYLLABLE COEG +CD5E;CD5E;110E 116C 11A9;CD5E;110E 116C 11A9; # (쵞; 쵞; 쵞; 쵞; 쵞; ) HANGUL SYLLABLE COEGG +CD5F;CD5F;110E 116C 11AA;CD5F;110E 116C 11AA; # (쵟; 쵟; 쵟; 쵟; 쵟; ) HANGUL SYLLABLE COEGS +CD60;CD60;110E 116C 11AB;CD60;110E 116C 11AB; # (쵠; 쵠; 쵠; 쵠; 쵠; ) HANGUL SYLLABLE COEN +CD61;CD61;110E 116C 11AC;CD61;110E 116C 11AC; # (쵡; 쵡; 쵡; 쵡; 쵡; ) HANGUL SYLLABLE COENJ +CD62;CD62;110E 116C 11AD;CD62;110E 116C 11AD; # (쵢; 쵢; 쵢; 쵢; 쵢; ) HANGUL SYLLABLE COENH +CD63;CD63;110E 116C 11AE;CD63;110E 116C 11AE; # (쵣; 쵣; 쵣; 쵣; 쵣; ) HANGUL SYLLABLE COED +CD64;CD64;110E 116C 11AF;CD64;110E 116C 11AF; # (쵤; 쵤; 쵤; 쵤; 쵤; ) HANGUL SYLLABLE COEL +CD65;CD65;110E 116C 11B0;CD65;110E 116C 11B0; # (쵥; 쵥; 쵥; 쵥; 쵥; ) HANGUL SYLLABLE COELG +CD66;CD66;110E 116C 11B1;CD66;110E 116C 11B1; # (쵦; 쵦; 쵦; 쵦; 쵦; ) HANGUL SYLLABLE COELM +CD67;CD67;110E 116C 11B2;CD67;110E 116C 11B2; # (쵧; 쵧; 쵧; 쵧; 쵧; ) HANGUL SYLLABLE COELB +CD68;CD68;110E 116C 11B3;CD68;110E 116C 11B3; # (쵨; 쵨; 쵨; 쵨; 쵨; ) HANGUL SYLLABLE COELS +CD69;CD69;110E 116C 11B4;CD69;110E 116C 11B4; # (쵩; 쵩; 쵩; 쵩; 쵩; ) HANGUL SYLLABLE COELT +CD6A;CD6A;110E 116C 11B5;CD6A;110E 116C 11B5; # (쵪; 쵪; 쵪; 쵪; 쵪; ) HANGUL SYLLABLE COELP +CD6B;CD6B;110E 116C 11B6;CD6B;110E 116C 11B6; # (쵫; 쵫; 쵫; 쵫; 쵫; ) HANGUL SYLLABLE COELH +CD6C;CD6C;110E 116C 11B7;CD6C;110E 116C 11B7; # (쵬; 쵬; 쵬; 쵬; 쵬; ) HANGUL SYLLABLE COEM +CD6D;CD6D;110E 116C 11B8;CD6D;110E 116C 11B8; # (쵭; 쵭; 쵭; 쵭; 쵭; ) HANGUL SYLLABLE COEB +CD6E;CD6E;110E 116C 11B9;CD6E;110E 116C 11B9; # (쵮; 쵮; 쵮; 쵮; 쵮; ) HANGUL SYLLABLE COEBS +CD6F;CD6F;110E 116C 11BA;CD6F;110E 116C 11BA; # (쵯; 쵯; 쵯; 쵯; 쵯; ) HANGUL SYLLABLE COES +CD70;CD70;110E 116C 11BB;CD70;110E 116C 11BB; # (쵰; 쵰; 쵰; 쵰; 쵰; ) HANGUL SYLLABLE COESS +CD71;CD71;110E 116C 11BC;CD71;110E 116C 11BC; # (쵱; 쵱; 쵱; 쵱; 쵱; ) HANGUL SYLLABLE COENG +CD72;CD72;110E 116C 11BD;CD72;110E 116C 11BD; # (쵲; 쵲; 쵲; 쵲; 쵲; ) HANGUL SYLLABLE COEJ +CD73;CD73;110E 116C 11BE;CD73;110E 116C 11BE; # (쵳; 쵳; 쵳; 쵳; 쵳; ) HANGUL SYLLABLE COEC +CD74;CD74;110E 116C 11BF;CD74;110E 116C 11BF; # (쵴; 쵴; 쵴; 쵴; 쵴; ) HANGUL SYLLABLE COEK +CD75;CD75;110E 116C 11C0;CD75;110E 116C 11C0; # (쵵; 쵵; 쵵; 쵵; 쵵; ) HANGUL SYLLABLE COET +CD76;CD76;110E 116C 11C1;CD76;110E 116C 11C1; # (쵶; 쵶; 쵶; 쵶; 쵶; ) HANGUL SYLLABLE COEP +CD77;CD77;110E 116C 11C2;CD77;110E 116C 11C2; # (쵷; 쵷; 쵷; 쵷; 쵷; ) HANGUL SYLLABLE COEH +CD78;CD78;110E 116D;CD78;110E 116D; # (쵸; 쵸; 쵸; 쵸; 쵸; ) HANGUL SYLLABLE CYO +CD79;CD79;110E 116D 11A8;CD79;110E 116D 11A8; # (쵹; 쵹; 쵹; 쵹; 쵹; ) HANGUL SYLLABLE CYOG +CD7A;CD7A;110E 116D 11A9;CD7A;110E 116D 11A9; # (쵺; 쵺; 쵺; 쵺; 쵺; ) HANGUL SYLLABLE CYOGG +CD7B;CD7B;110E 116D 11AA;CD7B;110E 116D 11AA; # (쵻; 쵻; 쵻; 쵻; 쵻; ) HANGUL SYLLABLE CYOGS +CD7C;CD7C;110E 116D 11AB;CD7C;110E 116D 11AB; # (쵼; 쵼; 쵼; 쵼; 쵼; ) HANGUL SYLLABLE CYON +CD7D;CD7D;110E 116D 11AC;CD7D;110E 116D 11AC; # (쵽; 쵽; 쵽; 쵽; 쵽; ) HANGUL SYLLABLE CYONJ +CD7E;CD7E;110E 116D 11AD;CD7E;110E 116D 11AD; # (쵾; 쵾; 쵾; 쵾; 쵾; ) HANGUL SYLLABLE CYONH +CD7F;CD7F;110E 116D 11AE;CD7F;110E 116D 11AE; # (쵿; 쵿; 쵿; 쵿; 쵿; ) HANGUL SYLLABLE CYOD +CD80;CD80;110E 116D 11AF;CD80;110E 116D 11AF; # (춀; 춀; 춀; 춀; 춀; ) HANGUL SYLLABLE CYOL +CD81;CD81;110E 116D 11B0;CD81;110E 116D 11B0; # (춁; 춁; 춁; 춁; 춁; ) HANGUL SYLLABLE CYOLG +CD82;CD82;110E 116D 11B1;CD82;110E 116D 11B1; # (춂; 춂; 춂; 춂; 춂; ) HANGUL SYLLABLE CYOLM +CD83;CD83;110E 116D 11B2;CD83;110E 116D 11B2; # (춃; 춃; 춃; 춃; 춃; ) HANGUL SYLLABLE CYOLB +CD84;CD84;110E 116D 11B3;CD84;110E 116D 11B3; # (춄; 춄; 춄; 춄; 춄; ) HANGUL SYLLABLE CYOLS +CD85;CD85;110E 116D 11B4;CD85;110E 116D 11B4; # (춅; 춅; 춅; 춅; 춅; ) HANGUL SYLLABLE CYOLT +CD86;CD86;110E 116D 11B5;CD86;110E 116D 11B5; # (춆; 춆; 춆; 춆; 춆; ) HANGUL SYLLABLE CYOLP +CD87;CD87;110E 116D 11B6;CD87;110E 116D 11B6; # (춇; 춇; 춇; 춇; 춇; ) HANGUL SYLLABLE CYOLH +CD88;CD88;110E 116D 11B7;CD88;110E 116D 11B7; # (춈; 춈; 춈; 춈; 춈; ) HANGUL SYLLABLE CYOM +CD89;CD89;110E 116D 11B8;CD89;110E 116D 11B8; # (춉; 춉; 춉; 춉; 춉; ) HANGUL SYLLABLE CYOB +CD8A;CD8A;110E 116D 11B9;CD8A;110E 116D 11B9; # (춊; 춊; 춊; 춊; 춊; ) HANGUL SYLLABLE CYOBS +CD8B;CD8B;110E 116D 11BA;CD8B;110E 116D 11BA; # (춋; 춋; 춋; 춋; 춋; ) HANGUL SYLLABLE CYOS +CD8C;CD8C;110E 116D 11BB;CD8C;110E 116D 11BB; # (춌; 춌; 춌; 춌; 춌; ) HANGUL SYLLABLE CYOSS +CD8D;CD8D;110E 116D 11BC;CD8D;110E 116D 11BC; # (춍; 춍; 춍; 춍; 춍; ) HANGUL SYLLABLE CYONG +CD8E;CD8E;110E 116D 11BD;CD8E;110E 116D 11BD; # (춎; 춎; 춎; 춎; 춎; ) HANGUL SYLLABLE CYOJ +CD8F;CD8F;110E 116D 11BE;CD8F;110E 116D 11BE; # (춏; 춏; 춏; 춏; 춏; ) HANGUL SYLLABLE CYOC +CD90;CD90;110E 116D 11BF;CD90;110E 116D 11BF; # (춐; 춐; 춐; 춐; 춐; ) HANGUL SYLLABLE CYOK +CD91;CD91;110E 116D 11C0;CD91;110E 116D 11C0; # (춑; 춑; 춑; 춑; 춑; ) HANGUL SYLLABLE CYOT +CD92;CD92;110E 116D 11C1;CD92;110E 116D 11C1; # (춒; 춒; 춒; 춒; 춒; ) HANGUL SYLLABLE CYOP +CD93;CD93;110E 116D 11C2;CD93;110E 116D 11C2; # (춓; 춓; 춓; 춓; 춓; ) HANGUL SYLLABLE CYOH +CD94;CD94;110E 116E;CD94;110E 116E; # (추; 추; 추; 추; 추; ) HANGUL SYLLABLE CU +CD95;CD95;110E 116E 11A8;CD95;110E 116E 11A8; # (축; 축; 축; 축; 축; ) HANGUL SYLLABLE CUG +CD96;CD96;110E 116E 11A9;CD96;110E 116E 11A9; # (춖; 춖; 춖; 춖; 춖; ) HANGUL SYLLABLE CUGG +CD97;CD97;110E 116E 11AA;CD97;110E 116E 11AA; # (춗; 춗; 춗; 춗; 춗; ) HANGUL SYLLABLE CUGS +CD98;CD98;110E 116E 11AB;CD98;110E 116E 11AB; # (춘; 춘; 춘; 춘; 춘; ) HANGUL SYLLABLE CUN +CD99;CD99;110E 116E 11AC;CD99;110E 116E 11AC; # (춙; 춙; 춙; 춙; 춙; ) HANGUL SYLLABLE CUNJ +CD9A;CD9A;110E 116E 11AD;CD9A;110E 116E 11AD; # (춚; 춚; 춚; 춚; 춚; ) HANGUL SYLLABLE CUNH +CD9B;CD9B;110E 116E 11AE;CD9B;110E 116E 11AE; # (춛; 춛; 춛; 춛; 춛; ) HANGUL SYLLABLE CUD +CD9C;CD9C;110E 116E 11AF;CD9C;110E 116E 11AF; # (출; 출; 출; 출; 출; ) HANGUL SYLLABLE CUL +CD9D;CD9D;110E 116E 11B0;CD9D;110E 116E 11B0; # (춝; 춝; 춝; 춝; 춝; ) HANGUL SYLLABLE CULG +CD9E;CD9E;110E 116E 11B1;CD9E;110E 116E 11B1; # (춞; 춞; 춞; 춞; 춞; ) HANGUL SYLLABLE CULM +CD9F;CD9F;110E 116E 11B2;CD9F;110E 116E 11B2; # (춟; 춟; 춟; 춟; 춟; ) HANGUL SYLLABLE CULB +CDA0;CDA0;110E 116E 11B3;CDA0;110E 116E 11B3; # (춠; 춠; 춠; 춠; 춠; ) HANGUL SYLLABLE CULS +CDA1;CDA1;110E 116E 11B4;CDA1;110E 116E 11B4; # (춡; 춡; 춡; 춡; 춡; ) HANGUL SYLLABLE CULT +CDA2;CDA2;110E 116E 11B5;CDA2;110E 116E 11B5; # (춢; 춢; 춢; 춢; 춢; ) HANGUL SYLLABLE CULP +CDA3;CDA3;110E 116E 11B6;CDA3;110E 116E 11B6; # (춣; 춣; 춣; 춣; 춣; ) HANGUL SYLLABLE CULH +CDA4;CDA4;110E 116E 11B7;CDA4;110E 116E 11B7; # (춤; 춤; 춤; 춤; 춤; ) HANGUL SYLLABLE CUM +CDA5;CDA5;110E 116E 11B8;CDA5;110E 116E 11B8; # (춥; 춥; 춥; 춥; 춥; ) HANGUL SYLLABLE CUB +CDA6;CDA6;110E 116E 11B9;CDA6;110E 116E 11B9; # (춦; 춦; 춦; 춦; 춦; ) HANGUL SYLLABLE CUBS +CDA7;CDA7;110E 116E 11BA;CDA7;110E 116E 11BA; # (춧; 춧; 춧; 춧; 춧; ) HANGUL SYLLABLE CUS +CDA8;CDA8;110E 116E 11BB;CDA8;110E 116E 11BB; # (춨; 춨; 춨; 춨; 춨; ) HANGUL SYLLABLE CUSS +CDA9;CDA9;110E 116E 11BC;CDA9;110E 116E 11BC; # (충; 충; 충; 충; 충; ) HANGUL SYLLABLE CUNG +CDAA;CDAA;110E 116E 11BD;CDAA;110E 116E 11BD; # (춪; 춪; 춪; 춪; 춪; ) HANGUL SYLLABLE CUJ +CDAB;CDAB;110E 116E 11BE;CDAB;110E 116E 11BE; # (춫; 춫; 춫; 춫; 춫; ) HANGUL SYLLABLE CUC +CDAC;CDAC;110E 116E 11BF;CDAC;110E 116E 11BF; # (춬; 춬; 춬; 춬; 춬; ) HANGUL SYLLABLE CUK +CDAD;CDAD;110E 116E 11C0;CDAD;110E 116E 11C0; # (춭; 춭; 춭; 춭; 춭; ) HANGUL SYLLABLE CUT +CDAE;CDAE;110E 116E 11C1;CDAE;110E 116E 11C1; # (춮; 춮; 춮; 춮; 춮; ) HANGUL SYLLABLE CUP +CDAF;CDAF;110E 116E 11C2;CDAF;110E 116E 11C2; # (춯; 춯; 춯; 춯; 춯; ) HANGUL SYLLABLE CUH +CDB0;CDB0;110E 116F;CDB0;110E 116F; # (춰; 춰; 춰; 춰; 춰; ) HANGUL SYLLABLE CWEO +CDB1;CDB1;110E 116F 11A8;CDB1;110E 116F 11A8; # (춱; 춱; 춱; 춱; 춱; ) HANGUL SYLLABLE CWEOG +CDB2;CDB2;110E 116F 11A9;CDB2;110E 116F 11A9; # (춲; 춲; 춲; 춲; 춲; ) HANGUL SYLLABLE CWEOGG +CDB3;CDB3;110E 116F 11AA;CDB3;110E 116F 11AA; # (춳; 춳; 춳; 춳; 춳; ) HANGUL SYLLABLE CWEOGS +CDB4;CDB4;110E 116F 11AB;CDB4;110E 116F 11AB; # (춴; 춴; 춴; 춴; 춴; ) HANGUL SYLLABLE CWEON +CDB5;CDB5;110E 116F 11AC;CDB5;110E 116F 11AC; # (춵; 춵; 춵; 춵; 춵; ) HANGUL SYLLABLE CWEONJ +CDB6;CDB6;110E 116F 11AD;CDB6;110E 116F 11AD; # (춶; 춶; 춶; 춶; 춶; ) HANGUL SYLLABLE CWEONH +CDB7;CDB7;110E 116F 11AE;CDB7;110E 116F 11AE; # (춷; 춷; 춷; 춷; 춷; ) HANGUL SYLLABLE CWEOD +CDB8;CDB8;110E 116F 11AF;CDB8;110E 116F 11AF; # (춸; 춸; 춸; 춸; 춸; ) HANGUL SYLLABLE CWEOL +CDB9;CDB9;110E 116F 11B0;CDB9;110E 116F 11B0; # (춹; 춹; 춹; 춹; 춹; ) HANGUL SYLLABLE CWEOLG +CDBA;CDBA;110E 116F 11B1;CDBA;110E 116F 11B1; # (춺; 춺; 춺; 춺; 춺; ) HANGUL SYLLABLE CWEOLM +CDBB;CDBB;110E 116F 11B2;CDBB;110E 116F 11B2; # (춻; 춻; 춻; 춻; 춻; ) HANGUL SYLLABLE CWEOLB +CDBC;CDBC;110E 116F 11B3;CDBC;110E 116F 11B3; # (춼; 춼; 춼; 춼; 춼; ) HANGUL SYLLABLE CWEOLS +CDBD;CDBD;110E 116F 11B4;CDBD;110E 116F 11B4; # (춽; 춽; 춽; 춽; 춽; ) HANGUL SYLLABLE CWEOLT +CDBE;CDBE;110E 116F 11B5;CDBE;110E 116F 11B5; # (춾; 춾; 춾; 춾; 춾; ) HANGUL SYLLABLE CWEOLP +CDBF;CDBF;110E 116F 11B6;CDBF;110E 116F 11B6; # (춿; 춿; 춿; 춿; 춿; ) HANGUL SYLLABLE CWEOLH +CDC0;CDC0;110E 116F 11B7;CDC0;110E 116F 11B7; # (췀; 췀; 췀; 췀; 췀; ) HANGUL SYLLABLE CWEOM +CDC1;CDC1;110E 116F 11B8;CDC1;110E 116F 11B8; # (췁; 췁; 췁; 췁; 췁; ) HANGUL SYLLABLE CWEOB +CDC2;CDC2;110E 116F 11B9;CDC2;110E 116F 11B9; # (췂; 췂; 췂; 췂; 췂; ) HANGUL SYLLABLE CWEOBS +CDC3;CDC3;110E 116F 11BA;CDC3;110E 116F 11BA; # (췃; 췃; 췃; 췃; 췃; ) HANGUL SYLLABLE CWEOS +CDC4;CDC4;110E 116F 11BB;CDC4;110E 116F 11BB; # (췄; 췄; 췄; 췄; 췄; ) HANGUL SYLLABLE CWEOSS +CDC5;CDC5;110E 116F 11BC;CDC5;110E 116F 11BC; # (췅; 췅; 췅; 췅; 췅; ) HANGUL SYLLABLE CWEONG +CDC6;CDC6;110E 116F 11BD;CDC6;110E 116F 11BD; # (췆; 췆; 췆; 췆; 췆; ) HANGUL SYLLABLE CWEOJ +CDC7;CDC7;110E 116F 11BE;CDC7;110E 116F 11BE; # (췇; 췇; 췇; 췇; 췇; ) HANGUL SYLLABLE CWEOC +CDC8;CDC8;110E 116F 11BF;CDC8;110E 116F 11BF; # (췈; 췈; 췈; 췈; 췈; ) HANGUL SYLLABLE CWEOK +CDC9;CDC9;110E 116F 11C0;CDC9;110E 116F 11C0; # (췉; 췉; 췉; 췉; 췉; ) HANGUL SYLLABLE CWEOT +CDCA;CDCA;110E 116F 11C1;CDCA;110E 116F 11C1; # (췊; 췊; 췊; 췊; 췊; ) HANGUL SYLLABLE CWEOP +CDCB;CDCB;110E 116F 11C2;CDCB;110E 116F 11C2; # (췋; 췋; 췋; 췋; 췋; ) HANGUL SYLLABLE CWEOH +CDCC;CDCC;110E 1170;CDCC;110E 1170; # (췌; 췌; 췌; 췌; 췌; ) HANGUL SYLLABLE CWE +CDCD;CDCD;110E 1170 11A8;CDCD;110E 1170 11A8; # (췍; 췍; 췍; 췍; 췍; ) HANGUL SYLLABLE CWEG +CDCE;CDCE;110E 1170 11A9;CDCE;110E 1170 11A9; # (췎; 췎; 췎; 췎; 췎; ) HANGUL SYLLABLE CWEGG +CDCF;CDCF;110E 1170 11AA;CDCF;110E 1170 11AA; # (췏; 췏; 췏; 췏; 췏; ) HANGUL SYLLABLE CWEGS +CDD0;CDD0;110E 1170 11AB;CDD0;110E 1170 11AB; # (췐; 췐; 췐; 췐; 췐; ) HANGUL SYLLABLE CWEN +CDD1;CDD1;110E 1170 11AC;CDD1;110E 1170 11AC; # (췑; 췑; 췑; 췑; 췑; ) HANGUL SYLLABLE CWENJ +CDD2;CDD2;110E 1170 11AD;CDD2;110E 1170 11AD; # (췒; 췒; 췒; 췒; 췒; ) HANGUL SYLLABLE CWENH +CDD3;CDD3;110E 1170 11AE;CDD3;110E 1170 11AE; # (췓; 췓; 췓; 췓; 췓; ) HANGUL SYLLABLE CWED +CDD4;CDD4;110E 1170 11AF;CDD4;110E 1170 11AF; # (췔; 췔; 췔; 췔; 췔; ) HANGUL SYLLABLE CWEL +CDD5;CDD5;110E 1170 11B0;CDD5;110E 1170 11B0; # (췕; 췕; 췕; 췕; 췕; ) HANGUL SYLLABLE CWELG +CDD6;CDD6;110E 1170 11B1;CDD6;110E 1170 11B1; # (췖; 췖; 췖; 췖; 췖; ) HANGUL SYLLABLE CWELM +CDD7;CDD7;110E 1170 11B2;CDD7;110E 1170 11B2; # (췗; 췗; 췗; 췗; 췗; ) HANGUL SYLLABLE CWELB +CDD8;CDD8;110E 1170 11B3;CDD8;110E 1170 11B3; # (췘; 췘; 췘; 췘; 췘; ) HANGUL SYLLABLE CWELS +CDD9;CDD9;110E 1170 11B4;CDD9;110E 1170 11B4; # (췙; 췙; 췙; 췙; 췙; ) HANGUL SYLLABLE CWELT +CDDA;CDDA;110E 1170 11B5;CDDA;110E 1170 11B5; # (췚; 췚; 췚; 췚; 췚; ) HANGUL SYLLABLE CWELP +CDDB;CDDB;110E 1170 11B6;CDDB;110E 1170 11B6; # (췛; 췛; 췛; 췛; 췛; ) HANGUL SYLLABLE CWELH +CDDC;CDDC;110E 1170 11B7;CDDC;110E 1170 11B7; # (췜; 췜; 췜; 췜; 췜; ) HANGUL SYLLABLE CWEM +CDDD;CDDD;110E 1170 11B8;CDDD;110E 1170 11B8; # (췝; 췝; 췝; 췝; 췝; ) HANGUL SYLLABLE CWEB +CDDE;CDDE;110E 1170 11B9;CDDE;110E 1170 11B9; # (췞; 췞; 췞; 췞; 췞; ) HANGUL SYLLABLE CWEBS +CDDF;CDDF;110E 1170 11BA;CDDF;110E 1170 11BA; # (췟; 췟; 췟; 췟; 췟; ) HANGUL SYLLABLE CWES +CDE0;CDE0;110E 1170 11BB;CDE0;110E 1170 11BB; # (췠; 췠; 췠; 췠; 췠; ) HANGUL SYLLABLE CWESS +CDE1;CDE1;110E 1170 11BC;CDE1;110E 1170 11BC; # (췡; 췡; 췡; 췡; 췡; ) HANGUL SYLLABLE CWENG +CDE2;CDE2;110E 1170 11BD;CDE2;110E 1170 11BD; # (췢; 췢; 췢; 췢; 췢; ) HANGUL SYLLABLE CWEJ +CDE3;CDE3;110E 1170 11BE;CDE3;110E 1170 11BE; # (췣; 췣; 췣; 췣; 췣; ) HANGUL SYLLABLE CWEC +CDE4;CDE4;110E 1170 11BF;CDE4;110E 1170 11BF; # (췤; 췤; 췤; 췤; 췤; ) HANGUL SYLLABLE CWEK +CDE5;CDE5;110E 1170 11C0;CDE5;110E 1170 11C0; # (췥; 췥; 췥; 췥; 췥; ) HANGUL SYLLABLE CWET +CDE6;CDE6;110E 1170 11C1;CDE6;110E 1170 11C1; # (췦; 췦; 췦; 췦; 췦; ) HANGUL SYLLABLE CWEP +CDE7;CDE7;110E 1170 11C2;CDE7;110E 1170 11C2; # (췧; 췧; 췧; 췧; 췧; ) HANGUL SYLLABLE CWEH +CDE8;CDE8;110E 1171;CDE8;110E 1171; # (취; 취; 취; 취; 취; ) HANGUL SYLLABLE CWI +CDE9;CDE9;110E 1171 11A8;CDE9;110E 1171 11A8; # (췩; 췩; 췩; 췩; 췩; ) HANGUL SYLLABLE CWIG +CDEA;CDEA;110E 1171 11A9;CDEA;110E 1171 11A9; # (췪; 췪; 췪; 췪; 췪; ) HANGUL SYLLABLE CWIGG +CDEB;CDEB;110E 1171 11AA;CDEB;110E 1171 11AA; # (췫; 췫; 췫; 췫; 췫; ) HANGUL SYLLABLE CWIGS +CDEC;CDEC;110E 1171 11AB;CDEC;110E 1171 11AB; # (췬; 췬; 췬; 췬; 췬; ) HANGUL SYLLABLE CWIN +CDED;CDED;110E 1171 11AC;CDED;110E 1171 11AC; # (췭; 췭; 췭; 췭; 췭; ) HANGUL SYLLABLE CWINJ +CDEE;CDEE;110E 1171 11AD;CDEE;110E 1171 11AD; # (췮; 췮; 췮; 췮; 췮; ) HANGUL SYLLABLE CWINH +CDEF;CDEF;110E 1171 11AE;CDEF;110E 1171 11AE; # (췯; 췯; 췯; 췯; 췯; ) HANGUL SYLLABLE CWID +CDF0;CDF0;110E 1171 11AF;CDF0;110E 1171 11AF; # (췰; 췰; 췰; 췰; 췰; ) HANGUL SYLLABLE CWIL +CDF1;CDF1;110E 1171 11B0;CDF1;110E 1171 11B0; # (췱; 췱; 췱; 췱; 췱; ) HANGUL SYLLABLE CWILG +CDF2;CDF2;110E 1171 11B1;CDF2;110E 1171 11B1; # (췲; 췲; 췲; 췲; 췲; ) HANGUL SYLLABLE CWILM +CDF3;CDF3;110E 1171 11B2;CDF3;110E 1171 11B2; # (췳; 췳; 췳; 췳; 췳; ) HANGUL SYLLABLE CWILB +CDF4;CDF4;110E 1171 11B3;CDF4;110E 1171 11B3; # (췴; 췴; 췴; 췴; 췴; ) HANGUL SYLLABLE CWILS +CDF5;CDF5;110E 1171 11B4;CDF5;110E 1171 11B4; # (췵; 췵; 췵; 췵; 췵; ) HANGUL SYLLABLE CWILT +CDF6;CDF6;110E 1171 11B5;CDF6;110E 1171 11B5; # (췶; 췶; 췶; 췶; 췶; ) HANGUL SYLLABLE CWILP +CDF7;CDF7;110E 1171 11B6;CDF7;110E 1171 11B6; # (췷; 췷; 췷; 췷; 췷; ) HANGUL SYLLABLE CWILH +CDF8;CDF8;110E 1171 11B7;CDF8;110E 1171 11B7; # (췸; 췸; 췸; 췸; 췸; ) HANGUL SYLLABLE CWIM +CDF9;CDF9;110E 1171 11B8;CDF9;110E 1171 11B8; # (췹; 췹; 췹; 췹; 췹; ) HANGUL SYLLABLE CWIB +CDFA;CDFA;110E 1171 11B9;CDFA;110E 1171 11B9; # (췺; 췺; 췺; 췺; 췺; ) HANGUL SYLLABLE CWIBS +CDFB;CDFB;110E 1171 11BA;CDFB;110E 1171 11BA; # (췻; 췻; 췻; 췻; 췻; ) HANGUL SYLLABLE CWIS +CDFC;CDFC;110E 1171 11BB;CDFC;110E 1171 11BB; # (췼; 췼; 췼; 췼; 췼; ) HANGUL SYLLABLE CWISS +CDFD;CDFD;110E 1171 11BC;CDFD;110E 1171 11BC; # (췽; 췽; 췽; 췽; 췽; ) HANGUL SYLLABLE CWING +CDFE;CDFE;110E 1171 11BD;CDFE;110E 1171 11BD; # (췾; 췾; 췾; 췾; 췾; ) HANGUL SYLLABLE CWIJ +CDFF;CDFF;110E 1171 11BE;CDFF;110E 1171 11BE; # (췿; 췿; 췿; 췿; 췿; ) HANGUL SYLLABLE CWIC +CE00;CE00;110E 1171 11BF;CE00;110E 1171 11BF; # (츀; 츀; 츀; 츀; 츀; ) HANGUL SYLLABLE CWIK +CE01;CE01;110E 1171 11C0;CE01;110E 1171 11C0; # (츁; 츁; 츁; 츁; 츁; ) HANGUL SYLLABLE CWIT +CE02;CE02;110E 1171 11C1;CE02;110E 1171 11C1; # (츂; 츂; 츂; 츂; 츂; ) HANGUL SYLLABLE CWIP +CE03;CE03;110E 1171 11C2;CE03;110E 1171 11C2; # (츃; 츃; 츃; 츃; 츃; ) HANGUL SYLLABLE CWIH +CE04;CE04;110E 1172;CE04;110E 1172; # (츄; 츄; 츄; 츄; 츄; ) HANGUL SYLLABLE CYU +CE05;CE05;110E 1172 11A8;CE05;110E 1172 11A8; # (츅; 츅; 츅; 츅; 츅; ) HANGUL SYLLABLE CYUG +CE06;CE06;110E 1172 11A9;CE06;110E 1172 11A9; # (츆; 츆; 츆; 츆; 츆; ) HANGUL SYLLABLE CYUGG +CE07;CE07;110E 1172 11AA;CE07;110E 1172 11AA; # (츇; 츇; 츇; 츇; 츇; ) HANGUL SYLLABLE CYUGS +CE08;CE08;110E 1172 11AB;CE08;110E 1172 11AB; # (츈; 츈; 츈; 츈; 츈; ) HANGUL SYLLABLE CYUN +CE09;CE09;110E 1172 11AC;CE09;110E 1172 11AC; # (츉; 츉; 츉; 츉; 츉; ) HANGUL SYLLABLE CYUNJ +CE0A;CE0A;110E 1172 11AD;CE0A;110E 1172 11AD; # (츊; 츊; 츊; 츊; 츊; ) HANGUL SYLLABLE CYUNH +CE0B;CE0B;110E 1172 11AE;CE0B;110E 1172 11AE; # (츋; 츋; 츋; 츋; 츋; ) HANGUL SYLLABLE CYUD +CE0C;CE0C;110E 1172 11AF;CE0C;110E 1172 11AF; # (츌; 츌; 츌; 츌; 츌; ) HANGUL SYLLABLE CYUL +CE0D;CE0D;110E 1172 11B0;CE0D;110E 1172 11B0; # (츍; 츍; 츍; 츍; 츍; ) HANGUL SYLLABLE CYULG +CE0E;CE0E;110E 1172 11B1;CE0E;110E 1172 11B1; # (츎; 츎; 츎; 츎; 츎; ) HANGUL SYLLABLE CYULM +CE0F;CE0F;110E 1172 11B2;CE0F;110E 1172 11B2; # (츏; 츏; 츏; 츏; 츏; ) HANGUL SYLLABLE CYULB +CE10;CE10;110E 1172 11B3;CE10;110E 1172 11B3; # (츐; 츐; 츐; 츐; 츐; ) HANGUL SYLLABLE CYULS +CE11;CE11;110E 1172 11B4;CE11;110E 1172 11B4; # (츑; 츑; 츑; 츑; 츑; ) HANGUL SYLLABLE CYULT +CE12;CE12;110E 1172 11B5;CE12;110E 1172 11B5; # (츒; 츒; 츒; 츒; 츒; ) HANGUL SYLLABLE CYULP +CE13;CE13;110E 1172 11B6;CE13;110E 1172 11B6; # (츓; 츓; 츓; 츓; 츓; ) HANGUL SYLLABLE CYULH +CE14;CE14;110E 1172 11B7;CE14;110E 1172 11B7; # (츔; 츔; 츔; 츔; 츔; ) HANGUL SYLLABLE CYUM +CE15;CE15;110E 1172 11B8;CE15;110E 1172 11B8; # (츕; 츕; 츕; 츕; 츕; ) HANGUL SYLLABLE CYUB +CE16;CE16;110E 1172 11B9;CE16;110E 1172 11B9; # (츖; 츖; 츖; 츖; 츖; ) HANGUL SYLLABLE CYUBS +CE17;CE17;110E 1172 11BA;CE17;110E 1172 11BA; # (츗; 츗; 츗; 츗; 츗; ) HANGUL SYLLABLE CYUS +CE18;CE18;110E 1172 11BB;CE18;110E 1172 11BB; # (츘; 츘; 츘; 츘; 츘; ) HANGUL SYLLABLE CYUSS +CE19;CE19;110E 1172 11BC;CE19;110E 1172 11BC; # (츙; 츙; 츙; 츙; 츙; ) HANGUL SYLLABLE CYUNG +CE1A;CE1A;110E 1172 11BD;CE1A;110E 1172 11BD; # (츚; 츚; 츚; 츚; 츚; ) HANGUL SYLLABLE CYUJ +CE1B;CE1B;110E 1172 11BE;CE1B;110E 1172 11BE; # (츛; 츛; 츛; 츛; 츛; ) HANGUL SYLLABLE CYUC +CE1C;CE1C;110E 1172 11BF;CE1C;110E 1172 11BF; # (츜; 츜; 츜; 츜; 츜; ) HANGUL SYLLABLE CYUK +CE1D;CE1D;110E 1172 11C0;CE1D;110E 1172 11C0; # (츝; 츝; 츝; 츝; 츝; ) HANGUL SYLLABLE CYUT +CE1E;CE1E;110E 1172 11C1;CE1E;110E 1172 11C1; # (츞; 츞; 츞; 츞; 츞; ) HANGUL SYLLABLE CYUP +CE1F;CE1F;110E 1172 11C2;CE1F;110E 1172 11C2; # (츟; 츟; 츟; 츟; 츟; ) HANGUL SYLLABLE CYUH +CE20;CE20;110E 1173;CE20;110E 1173; # (츠; 츠; 츠; 츠; 츠; ) HANGUL SYLLABLE CEU +CE21;CE21;110E 1173 11A8;CE21;110E 1173 11A8; # (측; 측; 측; 측; 측; ) HANGUL SYLLABLE CEUG +CE22;CE22;110E 1173 11A9;CE22;110E 1173 11A9; # (츢; 츢; 츢; 츢; 츢; ) HANGUL SYLLABLE CEUGG +CE23;CE23;110E 1173 11AA;CE23;110E 1173 11AA; # (츣; 츣; 츣; 츣; 츣; ) HANGUL SYLLABLE CEUGS +CE24;CE24;110E 1173 11AB;CE24;110E 1173 11AB; # (츤; 츤; 츤; 츤; 츤; ) HANGUL SYLLABLE CEUN +CE25;CE25;110E 1173 11AC;CE25;110E 1173 11AC; # (츥; 츥; 츥; 츥; 츥; ) HANGUL SYLLABLE CEUNJ +CE26;CE26;110E 1173 11AD;CE26;110E 1173 11AD; # (츦; 츦; 츦; 츦; 츦; ) HANGUL SYLLABLE CEUNH +CE27;CE27;110E 1173 11AE;CE27;110E 1173 11AE; # (츧; 츧; 츧; 츧; 츧; ) HANGUL SYLLABLE CEUD +CE28;CE28;110E 1173 11AF;CE28;110E 1173 11AF; # (츨; 츨; 츨; 츨; 츨; ) HANGUL SYLLABLE CEUL +CE29;CE29;110E 1173 11B0;CE29;110E 1173 11B0; # (츩; 츩; 츩; 츩; 츩; ) HANGUL SYLLABLE CEULG +CE2A;CE2A;110E 1173 11B1;CE2A;110E 1173 11B1; # (츪; 츪; 츪; 츪; 츪; ) HANGUL SYLLABLE CEULM +CE2B;CE2B;110E 1173 11B2;CE2B;110E 1173 11B2; # (츫; 츫; 츫; 츫; 츫; ) HANGUL SYLLABLE CEULB +CE2C;CE2C;110E 1173 11B3;CE2C;110E 1173 11B3; # (츬; 츬; 츬; 츬; 츬; ) HANGUL SYLLABLE CEULS +CE2D;CE2D;110E 1173 11B4;CE2D;110E 1173 11B4; # (츭; 츭; 츭; 츭; 츭; ) HANGUL SYLLABLE CEULT +CE2E;CE2E;110E 1173 11B5;CE2E;110E 1173 11B5; # (츮; 츮; 츮; 츮; 츮; ) HANGUL SYLLABLE CEULP +CE2F;CE2F;110E 1173 11B6;CE2F;110E 1173 11B6; # (츯; 츯; 츯; 츯; 츯; ) HANGUL SYLLABLE CEULH +CE30;CE30;110E 1173 11B7;CE30;110E 1173 11B7; # (츰; 츰; 츰; 츰; 츰; ) HANGUL SYLLABLE CEUM +CE31;CE31;110E 1173 11B8;CE31;110E 1173 11B8; # (츱; 츱; 츱; 츱; 츱; ) HANGUL SYLLABLE CEUB +CE32;CE32;110E 1173 11B9;CE32;110E 1173 11B9; # (츲; 츲; 츲; 츲; 츲; ) HANGUL SYLLABLE CEUBS +CE33;CE33;110E 1173 11BA;CE33;110E 1173 11BA; # (츳; 츳; 츳; 츳; 츳; ) HANGUL SYLLABLE CEUS +CE34;CE34;110E 1173 11BB;CE34;110E 1173 11BB; # (츴; 츴; 츴; 츴; 츴; ) HANGUL SYLLABLE CEUSS +CE35;CE35;110E 1173 11BC;CE35;110E 1173 11BC; # (층; 층; 층; 층; 층; ) HANGUL SYLLABLE CEUNG +CE36;CE36;110E 1173 11BD;CE36;110E 1173 11BD; # (츶; 츶; 츶; 츶; 츶; ) HANGUL SYLLABLE CEUJ +CE37;CE37;110E 1173 11BE;CE37;110E 1173 11BE; # (츷; 츷; 츷; 츷; 츷; ) HANGUL SYLLABLE CEUC +CE38;CE38;110E 1173 11BF;CE38;110E 1173 11BF; # (츸; 츸; 츸; 츸; 츸; ) HANGUL SYLLABLE CEUK +CE39;CE39;110E 1173 11C0;CE39;110E 1173 11C0; # (츹; 츹; 츹; 츹; 츹; ) HANGUL SYLLABLE CEUT +CE3A;CE3A;110E 1173 11C1;CE3A;110E 1173 11C1; # (츺; 츺; 츺; 츺; 츺; ) HANGUL SYLLABLE CEUP +CE3B;CE3B;110E 1173 11C2;CE3B;110E 1173 11C2; # (츻; 츻; 츻; 츻; 츻; ) HANGUL SYLLABLE CEUH +CE3C;CE3C;110E 1174;CE3C;110E 1174; # (츼; 츼; 츼; 츼; 츼; ) HANGUL SYLLABLE CYI +CE3D;CE3D;110E 1174 11A8;CE3D;110E 1174 11A8; # (츽; 츽; 츽; 츽; 츽; ) HANGUL SYLLABLE CYIG +CE3E;CE3E;110E 1174 11A9;CE3E;110E 1174 11A9; # (츾; 츾; 츾; 츾; 츾; ) HANGUL SYLLABLE CYIGG +CE3F;CE3F;110E 1174 11AA;CE3F;110E 1174 11AA; # (츿; 츿; 츿; 츿; 츿; ) HANGUL SYLLABLE CYIGS +CE40;CE40;110E 1174 11AB;CE40;110E 1174 11AB; # (칀; 칀; 칀; 칀; 칀; ) HANGUL SYLLABLE CYIN +CE41;CE41;110E 1174 11AC;CE41;110E 1174 11AC; # (칁; 칁; 칁; 칁; 칁; ) HANGUL SYLLABLE CYINJ +CE42;CE42;110E 1174 11AD;CE42;110E 1174 11AD; # (칂; 칂; 칂; 칂; 칂; ) HANGUL SYLLABLE CYINH +CE43;CE43;110E 1174 11AE;CE43;110E 1174 11AE; # (칃; 칃; 칃; 칃; 칃; ) HANGUL SYLLABLE CYID +CE44;CE44;110E 1174 11AF;CE44;110E 1174 11AF; # (칄; 칄; 칄; 칄; 칄; ) HANGUL SYLLABLE CYIL +CE45;CE45;110E 1174 11B0;CE45;110E 1174 11B0; # (칅; 칅; 칅; 칅; 칅; ) HANGUL SYLLABLE CYILG +CE46;CE46;110E 1174 11B1;CE46;110E 1174 11B1; # (칆; 칆; 칆; 칆; 칆; ) HANGUL SYLLABLE CYILM +CE47;CE47;110E 1174 11B2;CE47;110E 1174 11B2; # (칇; 칇; 칇; 칇; 칇; ) HANGUL SYLLABLE CYILB +CE48;CE48;110E 1174 11B3;CE48;110E 1174 11B3; # (칈; 칈; 칈; 칈; 칈; ) HANGUL SYLLABLE CYILS +CE49;CE49;110E 1174 11B4;CE49;110E 1174 11B4; # (칉; 칉; 칉; 칉; 칉; ) HANGUL SYLLABLE CYILT +CE4A;CE4A;110E 1174 11B5;CE4A;110E 1174 11B5; # (칊; 칊; 칊; 칊; 칊; ) HANGUL SYLLABLE CYILP +CE4B;CE4B;110E 1174 11B6;CE4B;110E 1174 11B6; # (칋; 칋; 칋; 칋; 칋; ) HANGUL SYLLABLE CYILH +CE4C;CE4C;110E 1174 11B7;CE4C;110E 1174 11B7; # (칌; 칌; 칌; 칌; 칌; ) HANGUL SYLLABLE CYIM +CE4D;CE4D;110E 1174 11B8;CE4D;110E 1174 11B8; # (칍; 칍; 칍; 칍; 칍; ) HANGUL SYLLABLE CYIB +CE4E;CE4E;110E 1174 11B9;CE4E;110E 1174 11B9; # (칎; 칎; 칎; 칎; 칎; ) HANGUL SYLLABLE CYIBS +CE4F;CE4F;110E 1174 11BA;CE4F;110E 1174 11BA; # (칏; 칏; 칏; 칏; 칏; ) HANGUL SYLLABLE CYIS +CE50;CE50;110E 1174 11BB;CE50;110E 1174 11BB; # (칐; 칐; 칐; 칐; 칐; ) HANGUL SYLLABLE CYISS +CE51;CE51;110E 1174 11BC;CE51;110E 1174 11BC; # (칑; 칑; 칑; 칑; 칑; ) HANGUL SYLLABLE CYING +CE52;CE52;110E 1174 11BD;CE52;110E 1174 11BD; # (칒; 칒; 칒; 칒; 칒; ) HANGUL SYLLABLE CYIJ +CE53;CE53;110E 1174 11BE;CE53;110E 1174 11BE; # (칓; 칓; 칓; 칓; 칓; ) HANGUL SYLLABLE CYIC +CE54;CE54;110E 1174 11BF;CE54;110E 1174 11BF; # (칔; 칔; 칔; 칔; 칔; ) HANGUL SYLLABLE CYIK +CE55;CE55;110E 1174 11C0;CE55;110E 1174 11C0; # (칕; 칕; 칕; 칕; 칕; ) HANGUL SYLLABLE CYIT +CE56;CE56;110E 1174 11C1;CE56;110E 1174 11C1; # (칖; 칖; 칖; 칖; 칖; ) HANGUL SYLLABLE CYIP +CE57;CE57;110E 1174 11C2;CE57;110E 1174 11C2; # (칗; 칗; 칗; 칗; 칗; ) HANGUL SYLLABLE CYIH +CE58;CE58;110E 1175;CE58;110E 1175; # (치; 치; 치; 치; 치; ) HANGUL SYLLABLE CI +CE59;CE59;110E 1175 11A8;CE59;110E 1175 11A8; # (칙; 칙; 칙; 칙; 칙; ) HANGUL SYLLABLE CIG +CE5A;CE5A;110E 1175 11A9;CE5A;110E 1175 11A9; # (칚; 칚; 칚; 칚; 칚; ) HANGUL SYLLABLE CIGG +CE5B;CE5B;110E 1175 11AA;CE5B;110E 1175 11AA; # (칛; 칛; 칛; 칛; 칛; ) HANGUL SYLLABLE CIGS +CE5C;CE5C;110E 1175 11AB;CE5C;110E 1175 11AB; # (친; 친; 친; 친; 친; ) HANGUL SYLLABLE CIN +CE5D;CE5D;110E 1175 11AC;CE5D;110E 1175 11AC; # (칝; 칝; 칝; 칝; 칝; ) HANGUL SYLLABLE CINJ +CE5E;CE5E;110E 1175 11AD;CE5E;110E 1175 11AD; # (칞; 칞; 칞; 칞; 칞; ) HANGUL SYLLABLE CINH +CE5F;CE5F;110E 1175 11AE;CE5F;110E 1175 11AE; # (칟; 칟; 칟; 칟; 칟; ) HANGUL SYLLABLE CID +CE60;CE60;110E 1175 11AF;CE60;110E 1175 11AF; # (칠; 칠; 칠; 칠; 칠; ) HANGUL SYLLABLE CIL +CE61;CE61;110E 1175 11B0;CE61;110E 1175 11B0; # (칡; 칡; 칡; 칡; 칡; ) HANGUL SYLLABLE CILG +CE62;CE62;110E 1175 11B1;CE62;110E 1175 11B1; # (칢; 칢; 칢; 칢; 칢; ) HANGUL SYLLABLE CILM +CE63;CE63;110E 1175 11B2;CE63;110E 1175 11B2; # (칣; 칣; 칣; 칣; 칣; ) HANGUL SYLLABLE CILB +CE64;CE64;110E 1175 11B3;CE64;110E 1175 11B3; # (칤; 칤; 칤; 칤; 칤; ) HANGUL SYLLABLE CILS +CE65;CE65;110E 1175 11B4;CE65;110E 1175 11B4; # (칥; 칥; 칥; 칥; 칥; ) HANGUL SYLLABLE CILT +CE66;CE66;110E 1175 11B5;CE66;110E 1175 11B5; # (칦; 칦; 칦; 칦; 칦; ) HANGUL SYLLABLE CILP +CE67;CE67;110E 1175 11B6;CE67;110E 1175 11B6; # (칧; 칧; 칧; 칧; 칧; ) HANGUL SYLLABLE CILH +CE68;CE68;110E 1175 11B7;CE68;110E 1175 11B7; # (침; 침; 침; 침; 침; ) HANGUL SYLLABLE CIM +CE69;CE69;110E 1175 11B8;CE69;110E 1175 11B8; # (칩; 칩; 칩; 칩; 칩; ) HANGUL SYLLABLE CIB +CE6A;CE6A;110E 1175 11B9;CE6A;110E 1175 11B9; # (칪; 칪; 칪; 칪; 칪; ) HANGUL SYLLABLE CIBS +CE6B;CE6B;110E 1175 11BA;CE6B;110E 1175 11BA; # (칫; 칫; 칫; 칫; 칫; ) HANGUL SYLLABLE CIS +CE6C;CE6C;110E 1175 11BB;CE6C;110E 1175 11BB; # (칬; 칬; 칬; 칬; 칬; ) HANGUL SYLLABLE CISS +CE6D;CE6D;110E 1175 11BC;CE6D;110E 1175 11BC; # (칭; 칭; 칭; 칭; 칭; ) HANGUL SYLLABLE CING +CE6E;CE6E;110E 1175 11BD;CE6E;110E 1175 11BD; # (칮; 칮; 칮; 칮; 칮; ) HANGUL SYLLABLE CIJ +CE6F;CE6F;110E 1175 11BE;CE6F;110E 1175 11BE; # (칯; 칯; 칯; 칯; 칯; ) HANGUL SYLLABLE CIC +CE70;CE70;110E 1175 11BF;CE70;110E 1175 11BF; # (칰; 칰; 칰; 칰; 칰; ) HANGUL SYLLABLE CIK +CE71;CE71;110E 1175 11C0;CE71;110E 1175 11C0; # (칱; 칱; 칱; 칱; 칱; ) HANGUL SYLLABLE CIT +CE72;CE72;110E 1175 11C1;CE72;110E 1175 11C1; # (칲; 칲; 칲; 칲; 칲; ) HANGUL SYLLABLE CIP +CE73;CE73;110E 1175 11C2;CE73;110E 1175 11C2; # (칳; 칳; 칳; 칳; 칳; ) HANGUL SYLLABLE CIH +CE74;CE74;110F 1161;CE74;110F 1161; # (카; 카; 카; 카; 카; ) HANGUL SYLLABLE KA +CE75;CE75;110F 1161 11A8;CE75;110F 1161 11A8; # (칵; 칵; 칵; 칵; 칵; ) HANGUL SYLLABLE KAG +CE76;CE76;110F 1161 11A9;CE76;110F 1161 11A9; # (칶; 칶; 칶; 칶; 칶; ) HANGUL SYLLABLE KAGG +CE77;CE77;110F 1161 11AA;CE77;110F 1161 11AA; # (칷; 칷; 칷; 칷; 칷; ) HANGUL SYLLABLE KAGS +CE78;CE78;110F 1161 11AB;CE78;110F 1161 11AB; # (칸; 칸; 칸; 칸; 칸; ) HANGUL SYLLABLE KAN +CE79;CE79;110F 1161 11AC;CE79;110F 1161 11AC; # (칹; 칹; 칹; 칹; 칹; ) HANGUL SYLLABLE KANJ +CE7A;CE7A;110F 1161 11AD;CE7A;110F 1161 11AD; # (칺; 칺; 칺; 칺; 칺; ) HANGUL SYLLABLE KANH +CE7B;CE7B;110F 1161 11AE;CE7B;110F 1161 11AE; # (칻; 칻; 칻; 칻; 칻; ) HANGUL SYLLABLE KAD +CE7C;CE7C;110F 1161 11AF;CE7C;110F 1161 11AF; # (칼; 칼; 칼; 칼; 칼; ) HANGUL SYLLABLE KAL +CE7D;CE7D;110F 1161 11B0;CE7D;110F 1161 11B0; # (칽; 칽; 칽; 칽; 칽; ) HANGUL SYLLABLE KALG +CE7E;CE7E;110F 1161 11B1;CE7E;110F 1161 11B1; # (칾; 칾; 칾; 칾; 칾; ) HANGUL SYLLABLE KALM +CE7F;CE7F;110F 1161 11B2;CE7F;110F 1161 11B2; # (칿; 칿; 칿; 칿; 칿; ) HANGUL SYLLABLE KALB +CE80;CE80;110F 1161 11B3;CE80;110F 1161 11B3; # (캀; 캀; 캀; 캀; 캀; ) HANGUL SYLLABLE KALS +CE81;CE81;110F 1161 11B4;CE81;110F 1161 11B4; # (캁; 캁; 캁; 캁; 캁; ) HANGUL SYLLABLE KALT +CE82;CE82;110F 1161 11B5;CE82;110F 1161 11B5; # (캂; 캂; 캂; 캂; 캂; ) HANGUL SYLLABLE KALP +CE83;CE83;110F 1161 11B6;CE83;110F 1161 11B6; # (캃; 캃; 캃; 캃; 캃; ) HANGUL SYLLABLE KALH +CE84;CE84;110F 1161 11B7;CE84;110F 1161 11B7; # (캄; 캄; 캄; 캄; 캄; ) HANGUL SYLLABLE KAM +CE85;CE85;110F 1161 11B8;CE85;110F 1161 11B8; # (캅; 캅; 캅; 캅; 캅; ) HANGUL SYLLABLE KAB +CE86;CE86;110F 1161 11B9;CE86;110F 1161 11B9; # (캆; 캆; 캆; 캆; 캆; ) HANGUL SYLLABLE KABS +CE87;CE87;110F 1161 11BA;CE87;110F 1161 11BA; # (캇; 캇; 캇; 캇; 캇; ) HANGUL SYLLABLE KAS +CE88;CE88;110F 1161 11BB;CE88;110F 1161 11BB; # (캈; 캈; 캈; 캈; 캈; ) HANGUL SYLLABLE KASS +CE89;CE89;110F 1161 11BC;CE89;110F 1161 11BC; # (캉; 캉; 캉; 캉; 캉; ) HANGUL SYLLABLE KANG +CE8A;CE8A;110F 1161 11BD;CE8A;110F 1161 11BD; # (캊; 캊; 캊; 캊; 캊; ) HANGUL SYLLABLE KAJ +CE8B;CE8B;110F 1161 11BE;CE8B;110F 1161 11BE; # (캋; 캋; 캋; 캋; 캋; ) HANGUL SYLLABLE KAC +CE8C;CE8C;110F 1161 11BF;CE8C;110F 1161 11BF; # (캌; 캌; 캌; 캌; 캌; ) HANGUL SYLLABLE KAK +CE8D;CE8D;110F 1161 11C0;CE8D;110F 1161 11C0; # (캍; 캍; 캍; 캍; 캍; ) HANGUL SYLLABLE KAT +CE8E;CE8E;110F 1161 11C1;CE8E;110F 1161 11C1; # (캎; 캎; 캎; 캎; 캎; ) HANGUL SYLLABLE KAP +CE8F;CE8F;110F 1161 11C2;CE8F;110F 1161 11C2; # (캏; 캏; 캏; 캏; 캏; ) HANGUL SYLLABLE KAH +CE90;CE90;110F 1162;CE90;110F 1162; # (캐; 캐; 캐; 캐; 캐; ) HANGUL SYLLABLE KAE +CE91;CE91;110F 1162 11A8;CE91;110F 1162 11A8; # (캑; 캑; 캑; 캑; 캑; ) HANGUL SYLLABLE KAEG +CE92;CE92;110F 1162 11A9;CE92;110F 1162 11A9; # (캒; 캒; 캒; 캒; 캒; ) HANGUL SYLLABLE KAEGG +CE93;CE93;110F 1162 11AA;CE93;110F 1162 11AA; # (캓; 캓; 캓; 캓; 캓; ) HANGUL SYLLABLE KAEGS +CE94;CE94;110F 1162 11AB;CE94;110F 1162 11AB; # (캔; 캔; 캔; 캔; 캔; ) HANGUL SYLLABLE KAEN +CE95;CE95;110F 1162 11AC;CE95;110F 1162 11AC; # (캕; 캕; 캕; 캕; 캕; ) HANGUL SYLLABLE KAENJ +CE96;CE96;110F 1162 11AD;CE96;110F 1162 11AD; # (캖; 캖; 캖; 캖; 캖; ) HANGUL SYLLABLE KAENH +CE97;CE97;110F 1162 11AE;CE97;110F 1162 11AE; # (캗; 캗; 캗; 캗; 캗; ) HANGUL SYLLABLE KAED +CE98;CE98;110F 1162 11AF;CE98;110F 1162 11AF; # (캘; 캘; 캘; 캘; 캘; ) HANGUL SYLLABLE KAEL +CE99;CE99;110F 1162 11B0;CE99;110F 1162 11B0; # (캙; 캙; 캙; 캙; 캙; ) HANGUL SYLLABLE KAELG +CE9A;CE9A;110F 1162 11B1;CE9A;110F 1162 11B1; # (캚; 캚; 캚; 캚; 캚; ) HANGUL SYLLABLE KAELM +CE9B;CE9B;110F 1162 11B2;CE9B;110F 1162 11B2; # (캛; 캛; 캛; 캛; 캛; ) HANGUL SYLLABLE KAELB +CE9C;CE9C;110F 1162 11B3;CE9C;110F 1162 11B3; # (캜; 캜; 캜; 캜; 캜; ) HANGUL SYLLABLE KAELS +CE9D;CE9D;110F 1162 11B4;CE9D;110F 1162 11B4; # (캝; 캝; 캝; 캝; 캝; ) HANGUL SYLLABLE KAELT +CE9E;CE9E;110F 1162 11B5;CE9E;110F 1162 11B5; # (캞; 캞; 캞; 캞; 캞; ) HANGUL SYLLABLE KAELP +CE9F;CE9F;110F 1162 11B6;CE9F;110F 1162 11B6; # (캟; 캟; 캟; 캟; 캟; ) HANGUL SYLLABLE KAELH +CEA0;CEA0;110F 1162 11B7;CEA0;110F 1162 11B7; # (캠; 캠; 캠; 캠; 캠; ) HANGUL SYLLABLE KAEM +CEA1;CEA1;110F 1162 11B8;CEA1;110F 1162 11B8; # (캡; 캡; 캡; 캡; 캡; ) HANGUL SYLLABLE KAEB +CEA2;CEA2;110F 1162 11B9;CEA2;110F 1162 11B9; # (캢; 캢; 캢; 캢; 캢; ) HANGUL SYLLABLE KAEBS +CEA3;CEA3;110F 1162 11BA;CEA3;110F 1162 11BA; # (캣; 캣; 캣; 캣; 캣; ) HANGUL SYLLABLE KAES +CEA4;CEA4;110F 1162 11BB;CEA4;110F 1162 11BB; # (캤; 캤; 캤; 캤; 캤; ) HANGUL SYLLABLE KAESS +CEA5;CEA5;110F 1162 11BC;CEA5;110F 1162 11BC; # (캥; 캥; 캥; 캥; 캥; ) HANGUL SYLLABLE KAENG +CEA6;CEA6;110F 1162 11BD;CEA6;110F 1162 11BD; # (캦; 캦; 캦; 캦; 캦; ) HANGUL SYLLABLE KAEJ +CEA7;CEA7;110F 1162 11BE;CEA7;110F 1162 11BE; # (캧; 캧; 캧; 캧; 캧; ) HANGUL SYLLABLE KAEC +CEA8;CEA8;110F 1162 11BF;CEA8;110F 1162 11BF; # (캨; 캨; 캨; 캨; 캨; ) HANGUL SYLLABLE KAEK +CEA9;CEA9;110F 1162 11C0;CEA9;110F 1162 11C0; # (캩; 캩; 캩; 캩; 캩; ) HANGUL SYLLABLE KAET +CEAA;CEAA;110F 1162 11C1;CEAA;110F 1162 11C1; # (캪; 캪; 캪; 캪; 캪; ) HANGUL SYLLABLE KAEP +CEAB;CEAB;110F 1162 11C2;CEAB;110F 1162 11C2; # (캫; 캫; 캫; 캫; 캫; ) HANGUL SYLLABLE KAEH +CEAC;CEAC;110F 1163;CEAC;110F 1163; # (캬; 캬; 캬; 캬; 캬; ) HANGUL SYLLABLE KYA +CEAD;CEAD;110F 1163 11A8;CEAD;110F 1163 11A8; # (캭; 캭; 캭; 캭; 캭; ) HANGUL SYLLABLE KYAG +CEAE;CEAE;110F 1163 11A9;CEAE;110F 1163 11A9; # (캮; 캮; 캮; 캮; 캮; ) HANGUL SYLLABLE KYAGG +CEAF;CEAF;110F 1163 11AA;CEAF;110F 1163 11AA; # (캯; 캯; 캯; 캯; 캯; ) HANGUL SYLLABLE KYAGS +CEB0;CEB0;110F 1163 11AB;CEB0;110F 1163 11AB; # (캰; 캰; 캰; 캰; 캰; ) HANGUL SYLLABLE KYAN +CEB1;CEB1;110F 1163 11AC;CEB1;110F 1163 11AC; # (캱; 캱; 캱; 캱; 캱; ) HANGUL SYLLABLE KYANJ +CEB2;CEB2;110F 1163 11AD;CEB2;110F 1163 11AD; # (캲; 캲; 캲; 캲; 캲; ) HANGUL SYLLABLE KYANH +CEB3;CEB3;110F 1163 11AE;CEB3;110F 1163 11AE; # (캳; 캳; 캳; 캳; 캳; ) HANGUL SYLLABLE KYAD +CEB4;CEB4;110F 1163 11AF;CEB4;110F 1163 11AF; # (캴; 캴; 캴; 캴; 캴; ) HANGUL SYLLABLE KYAL +CEB5;CEB5;110F 1163 11B0;CEB5;110F 1163 11B0; # (캵; 캵; 캵; 캵; 캵; ) HANGUL SYLLABLE KYALG +CEB6;CEB6;110F 1163 11B1;CEB6;110F 1163 11B1; # (캶; 캶; 캶; 캶; 캶; ) HANGUL SYLLABLE KYALM +CEB7;CEB7;110F 1163 11B2;CEB7;110F 1163 11B2; # (캷; 캷; 캷; 캷; 캷; ) HANGUL SYLLABLE KYALB +CEB8;CEB8;110F 1163 11B3;CEB8;110F 1163 11B3; # (캸; 캸; 캸; 캸; 캸; ) HANGUL SYLLABLE KYALS +CEB9;CEB9;110F 1163 11B4;CEB9;110F 1163 11B4; # (캹; 캹; 캹; 캹; 캹; ) HANGUL SYLLABLE KYALT +CEBA;CEBA;110F 1163 11B5;CEBA;110F 1163 11B5; # (캺; 캺; 캺; 캺; 캺; ) HANGUL SYLLABLE KYALP +CEBB;CEBB;110F 1163 11B6;CEBB;110F 1163 11B6; # (캻; 캻; 캻; 캻; 캻; ) HANGUL SYLLABLE KYALH +CEBC;CEBC;110F 1163 11B7;CEBC;110F 1163 11B7; # (캼; 캼; 캼; 캼; 캼; ) HANGUL SYLLABLE KYAM +CEBD;CEBD;110F 1163 11B8;CEBD;110F 1163 11B8; # (캽; 캽; 캽; 캽; 캽; ) HANGUL SYLLABLE KYAB +CEBE;CEBE;110F 1163 11B9;CEBE;110F 1163 11B9; # (캾; 캾; 캾; 캾; 캾; ) HANGUL SYLLABLE KYABS +CEBF;CEBF;110F 1163 11BA;CEBF;110F 1163 11BA; # (캿; 캿; 캿; 캿; 캿; ) HANGUL SYLLABLE KYAS +CEC0;CEC0;110F 1163 11BB;CEC0;110F 1163 11BB; # (컀; 컀; 컀; 컀; 컀; ) HANGUL SYLLABLE KYASS +CEC1;CEC1;110F 1163 11BC;CEC1;110F 1163 11BC; # (컁; 컁; 컁; 컁; 컁; ) HANGUL SYLLABLE KYANG +CEC2;CEC2;110F 1163 11BD;CEC2;110F 1163 11BD; # (컂; 컂; 컂; 컂; 컂; ) HANGUL SYLLABLE KYAJ +CEC3;CEC3;110F 1163 11BE;CEC3;110F 1163 11BE; # (컃; 컃; 컃; 컃; 컃; ) HANGUL SYLLABLE KYAC +CEC4;CEC4;110F 1163 11BF;CEC4;110F 1163 11BF; # (컄; 컄; 컄; 컄; 컄; ) HANGUL SYLLABLE KYAK +CEC5;CEC5;110F 1163 11C0;CEC5;110F 1163 11C0; # (컅; 컅; 컅; 컅; 컅; ) HANGUL SYLLABLE KYAT +CEC6;CEC6;110F 1163 11C1;CEC6;110F 1163 11C1; # (컆; 컆; 컆; 컆; 컆; ) HANGUL SYLLABLE KYAP +CEC7;CEC7;110F 1163 11C2;CEC7;110F 1163 11C2; # (컇; 컇; 컇; 컇; 컇; ) HANGUL SYLLABLE KYAH +CEC8;CEC8;110F 1164;CEC8;110F 1164; # (컈; 컈; 컈; 컈; 컈; ) HANGUL SYLLABLE KYAE +CEC9;CEC9;110F 1164 11A8;CEC9;110F 1164 11A8; # (컉; 컉; 컉; 컉; 컉; ) HANGUL SYLLABLE KYAEG +CECA;CECA;110F 1164 11A9;CECA;110F 1164 11A9; # (컊; 컊; 컊; 컊; 컊; ) HANGUL SYLLABLE KYAEGG +CECB;CECB;110F 1164 11AA;CECB;110F 1164 11AA; # (컋; 컋; 컋; 컋; 컋; ) HANGUL SYLLABLE KYAEGS +CECC;CECC;110F 1164 11AB;CECC;110F 1164 11AB; # (컌; 컌; 컌; 컌; 컌; ) HANGUL SYLLABLE KYAEN +CECD;CECD;110F 1164 11AC;CECD;110F 1164 11AC; # (컍; 컍; 컍; 컍; 컍; ) HANGUL SYLLABLE KYAENJ +CECE;CECE;110F 1164 11AD;CECE;110F 1164 11AD; # (컎; 컎; 컎; 컎; 컎; ) HANGUL SYLLABLE KYAENH +CECF;CECF;110F 1164 11AE;CECF;110F 1164 11AE; # (컏; 컏; 컏; 컏; 컏; ) HANGUL SYLLABLE KYAED +CED0;CED0;110F 1164 11AF;CED0;110F 1164 11AF; # (컐; 컐; 컐; 컐; 컐; ) HANGUL SYLLABLE KYAEL +CED1;CED1;110F 1164 11B0;CED1;110F 1164 11B0; # (컑; 컑; 컑; 컑; 컑; ) HANGUL SYLLABLE KYAELG +CED2;CED2;110F 1164 11B1;CED2;110F 1164 11B1; # (컒; 컒; 컒; 컒; 컒; ) HANGUL SYLLABLE KYAELM +CED3;CED3;110F 1164 11B2;CED3;110F 1164 11B2; # (컓; 컓; 컓; 컓; 컓; ) HANGUL SYLLABLE KYAELB +CED4;CED4;110F 1164 11B3;CED4;110F 1164 11B3; # (컔; 컔; 컔; 컔; 컔; ) HANGUL SYLLABLE KYAELS +CED5;CED5;110F 1164 11B4;CED5;110F 1164 11B4; # (컕; 컕; 컕; 컕; 컕; ) HANGUL SYLLABLE KYAELT +CED6;CED6;110F 1164 11B5;CED6;110F 1164 11B5; # (컖; 컖; 컖; 컖; 컖; ) HANGUL SYLLABLE KYAELP +CED7;CED7;110F 1164 11B6;CED7;110F 1164 11B6; # (컗; 컗; 컗; 컗; 컗; ) HANGUL SYLLABLE KYAELH +CED8;CED8;110F 1164 11B7;CED8;110F 1164 11B7; # (컘; 컘; 컘; 컘; 컘; ) HANGUL SYLLABLE KYAEM +CED9;CED9;110F 1164 11B8;CED9;110F 1164 11B8; # (컙; 컙; 컙; 컙; 컙; ) HANGUL SYLLABLE KYAEB +CEDA;CEDA;110F 1164 11B9;CEDA;110F 1164 11B9; # (컚; 컚; 컚; 컚; 컚; ) HANGUL SYLLABLE KYAEBS +CEDB;CEDB;110F 1164 11BA;CEDB;110F 1164 11BA; # (컛; 컛; 컛; 컛; 컛; ) HANGUL SYLLABLE KYAES +CEDC;CEDC;110F 1164 11BB;CEDC;110F 1164 11BB; # (컜; 컜; 컜; 컜; 컜; ) HANGUL SYLLABLE KYAESS +CEDD;CEDD;110F 1164 11BC;CEDD;110F 1164 11BC; # (컝; 컝; 컝; 컝; 컝; ) HANGUL SYLLABLE KYAENG +CEDE;CEDE;110F 1164 11BD;CEDE;110F 1164 11BD; # (컞; 컞; 컞; 컞; 컞; ) HANGUL SYLLABLE KYAEJ +CEDF;CEDF;110F 1164 11BE;CEDF;110F 1164 11BE; # (컟; 컟; 컟; 컟; 컟; ) HANGUL SYLLABLE KYAEC +CEE0;CEE0;110F 1164 11BF;CEE0;110F 1164 11BF; # (컠; 컠; 컠; 컠; 컠; ) HANGUL SYLLABLE KYAEK +CEE1;CEE1;110F 1164 11C0;CEE1;110F 1164 11C0; # (컡; 컡; 컡; 컡; 컡; ) HANGUL SYLLABLE KYAET +CEE2;CEE2;110F 1164 11C1;CEE2;110F 1164 11C1; # (컢; 컢; 컢; 컢; 컢; ) HANGUL SYLLABLE KYAEP +CEE3;CEE3;110F 1164 11C2;CEE3;110F 1164 11C2; # (컣; 컣; 컣; 컣; 컣; ) HANGUL SYLLABLE KYAEH +CEE4;CEE4;110F 1165;CEE4;110F 1165; # (커; 커; 커; 커; 커; ) HANGUL SYLLABLE KEO +CEE5;CEE5;110F 1165 11A8;CEE5;110F 1165 11A8; # (컥; 컥; 컥; 컥; 컥; ) HANGUL SYLLABLE KEOG +CEE6;CEE6;110F 1165 11A9;CEE6;110F 1165 11A9; # (컦; 컦; 컦; 컦; 컦; ) HANGUL SYLLABLE KEOGG +CEE7;CEE7;110F 1165 11AA;CEE7;110F 1165 11AA; # (컧; 컧; 컧; 컧; 컧; ) HANGUL SYLLABLE KEOGS +CEE8;CEE8;110F 1165 11AB;CEE8;110F 1165 11AB; # (컨; 컨; 컨; 컨; 컨; ) HANGUL SYLLABLE KEON +CEE9;CEE9;110F 1165 11AC;CEE9;110F 1165 11AC; # (컩; 컩; 컩; 컩; 컩; ) HANGUL SYLLABLE KEONJ +CEEA;CEEA;110F 1165 11AD;CEEA;110F 1165 11AD; # (컪; 컪; 컪; 컪; 컪; ) HANGUL SYLLABLE KEONH +CEEB;CEEB;110F 1165 11AE;CEEB;110F 1165 11AE; # (컫; 컫; 컫; 컫; 컫; ) HANGUL SYLLABLE KEOD +CEEC;CEEC;110F 1165 11AF;CEEC;110F 1165 11AF; # (컬; 컬; 컬; 컬; 컬; ) HANGUL SYLLABLE KEOL +CEED;CEED;110F 1165 11B0;CEED;110F 1165 11B0; # (컭; 컭; 컭; 컭; 컭; ) HANGUL SYLLABLE KEOLG +CEEE;CEEE;110F 1165 11B1;CEEE;110F 1165 11B1; # (컮; 컮; 컮; 컮; 컮; ) HANGUL SYLLABLE KEOLM +CEEF;CEEF;110F 1165 11B2;CEEF;110F 1165 11B2; # (컯; 컯; 컯; 컯; 컯; ) HANGUL SYLLABLE KEOLB +CEF0;CEF0;110F 1165 11B3;CEF0;110F 1165 11B3; # (컰; 컰; 컰; 컰; 컰; ) HANGUL SYLLABLE KEOLS +CEF1;CEF1;110F 1165 11B4;CEF1;110F 1165 11B4; # (컱; 컱; 컱; 컱; 컱; ) HANGUL SYLLABLE KEOLT +CEF2;CEF2;110F 1165 11B5;CEF2;110F 1165 11B5; # (컲; 컲; 컲; 컲; 컲; ) HANGUL SYLLABLE KEOLP +CEF3;CEF3;110F 1165 11B6;CEF3;110F 1165 11B6; # (컳; 컳; 컳; 컳; 컳; ) HANGUL SYLLABLE KEOLH +CEF4;CEF4;110F 1165 11B7;CEF4;110F 1165 11B7; # (컴; 컴; 컴; 컴; 컴; ) HANGUL SYLLABLE KEOM +CEF5;CEF5;110F 1165 11B8;CEF5;110F 1165 11B8; # (컵; 컵; 컵; 컵; 컵; ) HANGUL SYLLABLE KEOB +CEF6;CEF6;110F 1165 11B9;CEF6;110F 1165 11B9; # (컶; 컶; 컶; 컶; 컶; ) HANGUL SYLLABLE KEOBS +CEF7;CEF7;110F 1165 11BA;CEF7;110F 1165 11BA; # (컷; 컷; 컷; 컷; 컷; ) HANGUL SYLLABLE KEOS +CEF8;CEF8;110F 1165 11BB;CEF8;110F 1165 11BB; # (컸; 컸; 컸; 컸; 컸; ) HANGUL SYLLABLE KEOSS +CEF9;CEF9;110F 1165 11BC;CEF9;110F 1165 11BC; # (컹; 컹; 컹; 컹; 컹; ) HANGUL SYLLABLE KEONG +CEFA;CEFA;110F 1165 11BD;CEFA;110F 1165 11BD; # (컺; 컺; 컺; 컺; 컺; ) HANGUL SYLLABLE KEOJ +CEFB;CEFB;110F 1165 11BE;CEFB;110F 1165 11BE; # (컻; 컻; 컻; 컻; 컻; ) HANGUL SYLLABLE KEOC +CEFC;CEFC;110F 1165 11BF;CEFC;110F 1165 11BF; # (컼; 컼; 컼; 컼; 컼; ) HANGUL SYLLABLE KEOK +CEFD;CEFD;110F 1165 11C0;CEFD;110F 1165 11C0; # (컽; 컽; 컽; 컽; 컽; ) HANGUL SYLLABLE KEOT +CEFE;CEFE;110F 1165 11C1;CEFE;110F 1165 11C1; # (컾; 컾; 컾; 컾; 컾; ) HANGUL SYLLABLE KEOP +CEFF;CEFF;110F 1165 11C2;CEFF;110F 1165 11C2; # (컿; 컿; 컿; 컿; 컿; ) HANGUL SYLLABLE KEOH +CF00;CF00;110F 1166;CF00;110F 1166; # (케; 케; 케; 케; 케; ) HANGUL SYLLABLE KE +CF01;CF01;110F 1166 11A8;CF01;110F 1166 11A8; # (켁; 켁; 켁; 켁; 켁; ) HANGUL SYLLABLE KEG +CF02;CF02;110F 1166 11A9;CF02;110F 1166 11A9; # (켂; 켂; 켂; 켂; 켂; ) HANGUL SYLLABLE KEGG +CF03;CF03;110F 1166 11AA;CF03;110F 1166 11AA; # (켃; 켃; 켃; 켃; 켃; ) HANGUL SYLLABLE KEGS +CF04;CF04;110F 1166 11AB;CF04;110F 1166 11AB; # (켄; 켄; 켄; 켄; 켄; ) HANGUL SYLLABLE KEN +CF05;CF05;110F 1166 11AC;CF05;110F 1166 11AC; # (켅; 켅; 켅; 켅; 켅; ) HANGUL SYLLABLE KENJ +CF06;CF06;110F 1166 11AD;CF06;110F 1166 11AD; # (켆; 켆; 켆; 켆; 켆; ) HANGUL SYLLABLE KENH +CF07;CF07;110F 1166 11AE;CF07;110F 1166 11AE; # (켇; 켇; 켇; 켇; 켇; ) HANGUL SYLLABLE KED +CF08;CF08;110F 1166 11AF;CF08;110F 1166 11AF; # (켈; 켈; 켈; 켈; 켈; ) HANGUL SYLLABLE KEL +CF09;CF09;110F 1166 11B0;CF09;110F 1166 11B0; # (켉; 켉; 켉; 켉; 켉; ) HANGUL SYLLABLE KELG +CF0A;CF0A;110F 1166 11B1;CF0A;110F 1166 11B1; # (켊; 켊; 켊; 켊; 켊; ) HANGUL SYLLABLE KELM +CF0B;CF0B;110F 1166 11B2;CF0B;110F 1166 11B2; # (켋; 켋; 켋; 켋; 켋; ) HANGUL SYLLABLE KELB +CF0C;CF0C;110F 1166 11B3;CF0C;110F 1166 11B3; # (켌; 켌; 켌; 켌; 켌; ) HANGUL SYLLABLE KELS +CF0D;CF0D;110F 1166 11B4;CF0D;110F 1166 11B4; # (켍; 켍; 켍; 켍; 켍; ) HANGUL SYLLABLE KELT +CF0E;CF0E;110F 1166 11B5;CF0E;110F 1166 11B5; # (켎; 켎; 켎; 켎; 켎; ) HANGUL SYLLABLE KELP +CF0F;CF0F;110F 1166 11B6;CF0F;110F 1166 11B6; # (켏; 켏; 켏; 켏; 켏; ) HANGUL SYLLABLE KELH +CF10;CF10;110F 1166 11B7;CF10;110F 1166 11B7; # (켐; 켐; 켐; 켐; 켐; ) HANGUL SYLLABLE KEM +CF11;CF11;110F 1166 11B8;CF11;110F 1166 11B8; # (켑; 켑; 켑; 켑; 켑; ) HANGUL SYLLABLE KEB +CF12;CF12;110F 1166 11B9;CF12;110F 1166 11B9; # (켒; 켒; 켒; 켒; 켒; ) HANGUL SYLLABLE KEBS +CF13;CF13;110F 1166 11BA;CF13;110F 1166 11BA; # (켓; 켓; 켓; 켓; 켓; ) HANGUL SYLLABLE KES +CF14;CF14;110F 1166 11BB;CF14;110F 1166 11BB; # (켔; 켔; 켔; 켔; 켔; ) HANGUL SYLLABLE KESS +CF15;CF15;110F 1166 11BC;CF15;110F 1166 11BC; # (켕; 켕; 켕; 켕; 켕; ) HANGUL SYLLABLE KENG +CF16;CF16;110F 1166 11BD;CF16;110F 1166 11BD; # (켖; 켖; 켖; 켖; 켖; ) HANGUL SYLLABLE KEJ +CF17;CF17;110F 1166 11BE;CF17;110F 1166 11BE; # (켗; 켗; 켗; 켗; 켗; ) HANGUL SYLLABLE KEC +CF18;CF18;110F 1166 11BF;CF18;110F 1166 11BF; # (켘; 켘; 켘; 켘; 켘; ) HANGUL SYLLABLE KEK +CF19;CF19;110F 1166 11C0;CF19;110F 1166 11C0; # (켙; 켙; 켙; 켙; 켙; ) HANGUL SYLLABLE KET +CF1A;CF1A;110F 1166 11C1;CF1A;110F 1166 11C1; # (켚; 켚; 켚; 켚; 켚; ) HANGUL SYLLABLE KEP +CF1B;CF1B;110F 1166 11C2;CF1B;110F 1166 11C2; # (켛; 켛; 켛; 켛; 켛; ) HANGUL SYLLABLE KEH +CF1C;CF1C;110F 1167;CF1C;110F 1167; # (켜; 켜; 켜; 켜; 켜; ) HANGUL SYLLABLE KYEO +CF1D;CF1D;110F 1167 11A8;CF1D;110F 1167 11A8; # (켝; 켝; 켝; 켝; 켝; ) HANGUL SYLLABLE KYEOG +CF1E;CF1E;110F 1167 11A9;CF1E;110F 1167 11A9; # (켞; 켞; 켞; 켞; 켞; ) HANGUL SYLLABLE KYEOGG +CF1F;CF1F;110F 1167 11AA;CF1F;110F 1167 11AA; # (켟; 켟; 켟; 켟; 켟; ) HANGUL SYLLABLE KYEOGS +CF20;CF20;110F 1167 11AB;CF20;110F 1167 11AB; # (켠; 켠; 켠; 켠; 켠; ) HANGUL SYLLABLE KYEON +CF21;CF21;110F 1167 11AC;CF21;110F 1167 11AC; # (켡; 켡; 켡; 켡; 켡; ) HANGUL SYLLABLE KYEONJ +CF22;CF22;110F 1167 11AD;CF22;110F 1167 11AD; # (켢; 켢; 켢; 켢; 켢; ) HANGUL SYLLABLE KYEONH +CF23;CF23;110F 1167 11AE;CF23;110F 1167 11AE; # (켣; 켣; 켣; 켣; 켣; ) HANGUL SYLLABLE KYEOD +CF24;CF24;110F 1167 11AF;CF24;110F 1167 11AF; # (켤; 켤; 켤; 켤; 켤; ) HANGUL SYLLABLE KYEOL +CF25;CF25;110F 1167 11B0;CF25;110F 1167 11B0; # (켥; 켥; 켥; 켥; 켥; ) HANGUL SYLLABLE KYEOLG +CF26;CF26;110F 1167 11B1;CF26;110F 1167 11B1; # (켦; 켦; 켦; 켦; 켦; ) HANGUL SYLLABLE KYEOLM +CF27;CF27;110F 1167 11B2;CF27;110F 1167 11B2; # (켧; 켧; 켧; 켧; 켧; ) HANGUL SYLLABLE KYEOLB +CF28;CF28;110F 1167 11B3;CF28;110F 1167 11B3; # (켨; 켨; 켨; 켨; 켨; ) HANGUL SYLLABLE KYEOLS +CF29;CF29;110F 1167 11B4;CF29;110F 1167 11B4; # (켩; 켩; 켩; 켩; 켩; ) HANGUL SYLLABLE KYEOLT +CF2A;CF2A;110F 1167 11B5;CF2A;110F 1167 11B5; # (켪; 켪; 켪; 켪; 켪; ) HANGUL SYLLABLE KYEOLP +CF2B;CF2B;110F 1167 11B6;CF2B;110F 1167 11B6; # (켫; 켫; 켫; 켫; 켫; ) HANGUL SYLLABLE KYEOLH +CF2C;CF2C;110F 1167 11B7;CF2C;110F 1167 11B7; # (켬; 켬; 켬; 켬; 켬; ) HANGUL SYLLABLE KYEOM +CF2D;CF2D;110F 1167 11B8;CF2D;110F 1167 11B8; # (켭; 켭; 켭; 켭; 켭; ) HANGUL SYLLABLE KYEOB +CF2E;CF2E;110F 1167 11B9;CF2E;110F 1167 11B9; # (켮; 켮; 켮; 켮; 켮; ) HANGUL SYLLABLE KYEOBS +CF2F;CF2F;110F 1167 11BA;CF2F;110F 1167 11BA; # (켯; 켯; 켯; 켯; 켯; ) HANGUL SYLLABLE KYEOS +CF30;CF30;110F 1167 11BB;CF30;110F 1167 11BB; # (켰; 켰; 켰; 켰; 켰; ) HANGUL SYLLABLE KYEOSS +CF31;CF31;110F 1167 11BC;CF31;110F 1167 11BC; # (켱; 켱; 켱; 켱; 켱; ) HANGUL SYLLABLE KYEONG +CF32;CF32;110F 1167 11BD;CF32;110F 1167 11BD; # (켲; 켲; 켲; 켲; 켲; ) HANGUL SYLLABLE KYEOJ +CF33;CF33;110F 1167 11BE;CF33;110F 1167 11BE; # (켳; 켳; 켳; 켳; 켳; ) HANGUL SYLLABLE KYEOC +CF34;CF34;110F 1167 11BF;CF34;110F 1167 11BF; # (켴; 켴; 켴; 켴; 켴; ) HANGUL SYLLABLE KYEOK +CF35;CF35;110F 1167 11C0;CF35;110F 1167 11C0; # (켵; 켵; 켵; 켵; 켵; ) HANGUL SYLLABLE KYEOT +CF36;CF36;110F 1167 11C1;CF36;110F 1167 11C1; # (켶; 켶; 켶; 켶; 켶; ) HANGUL SYLLABLE KYEOP +CF37;CF37;110F 1167 11C2;CF37;110F 1167 11C2; # (켷; 켷; 켷; 켷; 켷; ) HANGUL SYLLABLE KYEOH +CF38;CF38;110F 1168;CF38;110F 1168; # (켸; 켸; 켸; 켸; 켸; ) HANGUL SYLLABLE KYE +CF39;CF39;110F 1168 11A8;CF39;110F 1168 11A8; # (켹; 켹; 켹; 켹; 켹; ) HANGUL SYLLABLE KYEG +CF3A;CF3A;110F 1168 11A9;CF3A;110F 1168 11A9; # (켺; 켺; 켺; 켺; 켺; ) HANGUL SYLLABLE KYEGG +CF3B;CF3B;110F 1168 11AA;CF3B;110F 1168 11AA; # (켻; 켻; 켻; 켻; 켻; ) HANGUL SYLLABLE KYEGS +CF3C;CF3C;110F 1168 11AB;CF3C;110F 1168 11AB; # (켼; 켼; 켼; 켼; 켼; ) HANGUL SYLLABLE KYEN +CF3D;CF3D;110F 1168 11AC;CF3D;110F 1168 11AC; # (켽; 켽; 켽; 켽; 켽; ) HANGUL SYLLABLE KYENJ +CF3E;CF3E;110F 1168 11AD;CF3E;110F 1168 11AD; # (켾; 켾; 켾; 켾; 켾; ) HANGUL SYLLABLE KYENH +CF3F;CF3F;110F 1168 11AE;CF3F;110F 1168 11AE; # (켿; 켿; 켿; 켿; 켿; ) HANGUL SYLLABLE KYED +CF40;CF40;110F 1168 11AF;CF40;110F 1168 11AF; # (콀; 콀; 콀; 콀; 콀; ) HANGUL SYLLABLE KYEL +CF41;CF41;110F 1168 11B0;CF41;110F 1168 11B0; # (콁; 콁; 콁; 콁; 콁; ) HANGUL SYLLABLE KYELG +CF42;CF42;110F 1168 11B1;CF42;110F 1168 11B1; # (콂; 콂; 콂; 콂; 콂; ) HANGUL SYLLABLE KYELM +CF43;CF43;110F 1168 11B2;CF43;110F 1168 11B2; # (콃; 콃; 콃; 콃; 콃; ) HANGUL SYLLABLE KYELB +CF44;CF44;110F 1168 11B3;CF44;110F 1168 11B3; # (콄; 콄; 콄; 콄; 콄; ) HANGUL SYLLABLE KYELS +CF45;CF45;110F 1168 11B4;CF45;110F 1168 11B4; # (콅; 콅; 콅; 콅; 콅; ) HANGUL SYLLABLE KYELT +CF46;CF46;110F 1168 11B5;CF46;110F 1168 11B5; # (콆; 콆; 콆; 콆; 콆; ) HANGUL SYLLABLE KYELP +CF47;CF47;110F 1168 11B6;CF47;110F 1168 11B6; # (콇; 콇; 콇; 콇; 콇; ) HANGUL SYLLABLE KYELH +CF48;CF48;110F 1168 11B7;CF48;110F 1168 11B7; # (콈; 콈; 콈; 콈; 콈; ) HANGUL SYLLABLE KYEM +CF49;CF49;110F 1168 11B8;CF49;110F 1168 11B8; # (콉; 콉; 콉; 콉; 콉; ) HANGUL SYLLABLE KYEB +CF4A;CF4A;110F 1168 11B9;CF4A;110F 1168 11B9; # (콊; 콊; 콊; 콊; 콊; ) HANGUL SYLLABLE KYEBS +CF4B;CF4B;110F 1168 11BA;CF4B;110F 1168 11BA; # (콋; 콋; 콋; 콋; 콋; ) HANGUL SYLLABLE KYES +CF4C;CF4C;110F 1168 11BB;CF4C;110F 1168 11BB; # (콌; 콌; 콌; 콌; 콌; ) HANGUL SYLLABLE KYESS +CF4D;CF4D;110F 1168 11BC;CF4D;110F 1168 11BC; # (콍; 콍; 콍; 콍; 콍; ) HANGUL SYLLABLE KYENG +CF4E;CF4E;110F 1168 11BD;CF4E;110F 1168 11BD; # (콎; 콎; 콎; 콎; 콎; ) HANGUL SYLLABLE KYEJ +CF4F;CF4F;110F 1168 11BE;CF4F;110F 1168 11BE; # (콏; 콏; 콏; 콏; 콏; ) HANGUL SYLLABLE KYEC +CF50;CF50;110F 1168 11BF;CF50;110F 1168 11BF; # (콐; 콐; 콐; 콐; 콐; ) HANGUL SYLLABLE KYEK +CF51;CF51;110F 1168 11C0;CF51;110F 1168 11C0; # (콑; 콑; 콑; 콑; 콑; ) HANGUL SYLLABLE KYET +CF52;CF52;110F 1168 11C1;CF52;110F 1168 11C1; # (콒; 콒; 콒; 콒; 콒; ) HANGUL SYLLABLE KYEP +CF53;CF53;110F 1168 11C2;CF53;110F 1168 11C2; # (콓; 콓; 콓; 콓; 콓; ) HANGUL SYLLABLE KYEH +CF54;CF54;110F 1169;CF54;110F 1169; # (코; 코; 코; 코; 코; ) HANGUL SYLLABLE KO +CF55;CF55;110F 1169 11A8;CF55;110F 1169 11A8; # (콕; 콕; 콕; 콕; 콕; ) HANGUL SYLLABLE KOG +CF56;CF56;110F 1169 11A9;CF56;110F 1169 11A9; # (콖; 콖; 콖; 콖; 콖; ) HANGUL SYLLABLE KOGG +CF57;CF57;110F 1169 11AA;CF57;110F 1169 11AA; # (콗; 콗; 콗; 콗; 콗; ) HANGUL SYLLABLE KOGS +CF58;CF58;110F 1169 11AB;CF58;110F 1169 11AB; # (콘; 콘; 콘; 콘; 콘; ) HANGUL SYLLABLE KON +CF59;CF59;110F 1169 11AC;CF59;110F 1169 11AC; # (콙; 콙; 콙; 콙; 콙; ) HANGUL SYLLABLE KONJ +CF5A;CF5A;110F 1169 11AD;CF5A;110F 1169 11AD; # (콚; 콚; 콚; 콚; 콚; ) HANGUL SYLLABLE KONH +CF5B;CF5B;110F 1169 11AE;CF5B;110F 1169 11AE; # (콛; 콛; 콛; 콛; 콛; ) HANGUL SYLLABLE KOD +CF5C;CF5C;110F 1169 11AF;CF5C;110F 1169 11AF; # (콜; 콜; 콜; 콜; 콜; ) HANGUL SYLLABLE KOL +CF5D;CF5D;110F 1169 11B0;CF5D;110F 1169 11B0; # (콝; 콝; 콝; 콝; 콝; ) HANGUL SYLLABLE KOLG +CF5E;CF5E;110F 1169 11B1;CF5E;110F 1169 11B1; # (콞; 콞; 콞; 콞; 콞; ) HANGUL SYLLABLE KOLM +CF5F;CF5F;110F 1169 11B2;CF5F;110F 1169 11B2; # (콟; 콟; 콟; 콟; 콟; ) HANGUL SYLLABLE KOLB +CF60;CF60;110F 1169 11B3;CF60;110F 1169 11B3; # (콠; 콠; 콠; 콠; 콠; ) HANGUL SYLLABLE KOLS +CF61;CF61;110F 1169 11B4;CF61;110F 1169 11B4; # (콡; 콡; 콡; 콡; 콡; ) HANGUL SYLLABLE KOLT +CF62;CF62;110F 1169 11B5;CF62;110F 1169 11B5; # (콢; 콢; 콢; 콢; 콢; ) HANGUL SYLLABLE KOLP +CF63;CF63;110F 1169 11B6;CF63;110F 1169 11B6; # (콣; 콣; 콣; 콣; 콣; ) HANGUL SYLLABLE KOLH +CF64;CF64;110F 1169 11B7;CF64;110F 1169 11B7; # (콤; 콤; 콤; 콤; 콤; ) HANGUL SYLLABLE KOM +CF65;CF65;110F 1169 11B8;CF65;110F 1169 11B8; # (콥; 콥; 콥; 콥; 콥; ) HANGUL SYLLABLE KOB +CF66;CF66;110F 1169 11B9;CF66;110F 1169 11B9; # (콦; 콦; 콦; 콦; 콦; ) HANGUL SYLLABLE KOBS +CF67;CF67;110F 1169 11BA;CF67;110F 1169 11BA; # (콧; 콧; 콧; 콧; 콧; ) HANGUL SYLLABLE KOS +CF68;CF68;110F 1169 11BB;CF68;110F 1169 11BB; # (콨; 콨; 콨; 콨; 콨; ) HANGUL SYLLABLE KOSS +CF69;CF69;110F 1169 11BC;CF69;110F 1169 11BC; # (콩; 콩; 콩; 콩; 콩; ) HANGUL SYLLABLE KONG +CF6A;CF6A;110F 1169 11BD;CF6A;110F 1169 11BD; # (콪; 콪; 콪; 콪; 콪; ) HANGUL SYLLABLE KOJ +CF6B;CF6B;110F 1169 11BE;CF6B;110F 1169 11BE; # (콫; 콫; 콫; 콫; 콫; ) HANGUL SYLLABLE KOC +CF6C;CF6C;110F 1169 11BF;CF6C;110F 1169 11BF; # (콬; 콬; 콬; 콬; 콬; ) HANGUL SYLLABLE KOK +CF6D;CF6D;110F 1169 11C0;CF6D;110F 1169 11C0; # (콭; 콭; 콭; 콭; 콭; ) HANGUL SYLLABLE KOT +CF6E;CF6E;110F 1169 11C1;CF6E;110F 1169 11C1; # (콮; 콮; 콮; 콮; 콮; ) HANGUL SYLLABLE KOP +CF6F;CF6F;110F 1169 11C2;CF6F;110F 1169 11C2; # (콯; 콯; 콯; 콯; 콯; ) HANGUL SYLLABLE KOH +CF70;CF70;110F 116A;CF70;110F 116A; # (콰; 콰; 콰; 콰; 콰; ) HANGUL SYLLABLE KWA +CF71;CF71;110F 116A 11A8;CF71;110F 116A 11A8; # (콱; 콱; 콱; 콱; 콱; ) HANGUL SYLLABLE KWAG +CF72;CF72;110F 116A 11A9;CF72;110F 116A 11A9; # (콲; 콲; 콲; 콲; 콲; ) HANGUL SYLLABLE KWAGG +CF73;CF73;110F 116A 11AA;CF73;110F 116A 11AA; # (콳; 콳; 콳; 콳; 콳; ) HANGUL SYLLABLE KWAGS +CF74;CF74;110F 116A 11AB;CF74;110F 116A 11AB; # (콴; 콴; 콴; 콴; 콴; ) HANGUL SYLLABLE KWAN +CF75;CF75;110F 116A 11AC;CF75;110F 116A 11AC; # (콵; 콵; 콵; 콵; 콵; ) HANGUL SYLLABLE KWANJ +CF76;CF76;110F 116A 11AD;CF76;110F 116A 11AD; # (콶; 콶; 콶; 콶; 콶; ) HANGUL SYLLABLE KWANH +CF77;CF77;110F 116A 11AE;CF77;110F 116A 11AE; # (콷; 콷; 콷; 콷; 콷; ) HANGUL SYLLABLE KWAD +CF78;CF78;110F 116A 11AF;CF78;110F 116A 11AF; # (콸; 콸; 콸; 콸; 콸; ) HANGUL SYLLABLE KWAL +CF79;CF79;110F 116A 11B0;CF79;110F 116A 11B0; # (콹; 콹; 콹; 콹; 콹; ) HANGUL SYLLABLE KWALG +CF7A;CF7A;110F 116A 11B1;CF7A;110F 116A 11B1; # (콺; 콺; 콺; 콺; 콺; ) HANGUL SYLLABLE KWALM +CF7B;CF7B;110F 116A 11B2;CF7B;110F 116A 11B2; # (콻; 콻; 콻; 콻; 콻; ) HANGUL SYLLABLE KWALB +CF7C;CF7C;110F 116A 11B3;CF7C;110F 116A 11B3; # (콼; 콼; 콼; 콼; 콼; ) HANGUL SYLLABLE KWALS +CF7D;CF7D;110F 116A 11B4;CF7D;110F 116A 11B4; # (콽; 콽; 콽; 콽; 콽; ) HANGUL SYLLABLE KWALT +CF7E;CF7E;110F 116A 11B5;CF7E;110F 116A 11B5; # (콾; 콾; 콾; 콾; 콾; ) HANGUL SYLLABLE KWALP +CF7F;CF7F;110F 116A 11B6;CF7F;110F 116A 11B6; # (콿; 콿; 콿; 콿; 콿; ) HANGUL SYLLABLE KWALH +CF80;CF80;110F 116A 11B7;CF80;110F 116A 11B7; # (쾀; 쾀; 쾀; 쾀; 쾀; ) HANGUL SYLLABLE KWAM +CF81;CF81;110F 116A 11B8;CF81;110F 116A 11B8; # (쾁; 쾁; 쾁; 쾁; 쾁; ) HANGUL SYLLABLE KWAB +CF82;CF82;110F 116A 11B9;CF82;110F 116A 11B9; # (쾂; 쾂; 쾂; 쾂; 쾂; ) HANGUL SYLLABLE KWABS +CF83;CF83;110F 116A 11BA;CF83;110F 116A 11BA; # (쾃; 쾃; 쾃; 쾃; 쾃; ) HANGUL SYLLABLE KWAS +CF84;CF84;110F 116A 11BB;CF84;110F 116A 11BB; # (쾄; 쾄; 쾄; 쾄; 쾄; ) HANGUL SYLLABLE KWASS +CF85;CF85;110F 116A 11BC;CF85;110F 116A 11BC; # (쾅; 쾅; 쾅; 쾅; 쾅; ) HANGUL SYLLABLE KWANG +CF86;CF86;110F 116A 11BD;CF86;110F 116A 11BD; # (쾆; 쾆; 쾆; 쾆; 쾆; ) HANGUL SYLLABLE KWAJ +CF87;CF87;110F 116A 11BE;CF87;110F 116A 11BE; # (쾇; 쾇; 쾇; 쾇; 쾇; ) HANGUL SYLLABLE KWAC +CF88;CF88;110F 116A 11BF;CF88;110F 116A 11BF; # (쾈; 쾈; 쾈; 쾈; 쾈; ) HANGUL SYLLABLE KWAK +CF89;CF89;110F 116A 11C0;CF89;110F 116A 11C0; # (쾉; 쾉; 쾉; 쾉; 쾉; ) HANGUL SYLLABLE KWAT +CF8A;CF8A;110F 116A 11C1;CF8A;110F 116A 11C1; # (쾊; 쾊; 쾊; 쾊; 쾊; ) HANGUL SYLLABLE KWAP +CF8B;CF8B;110F 116A 11C2;CF8B;110F 116A 11C2; # (쾋; 쾋; 쾋; 쾋; 쾋; ) HANGUL SYLLABLE KWAH +CF8C;CF8C;110F 116B;CF8C;110F 116B; # (쾌; 쾌; 쾌; 쾌; 쾌; ) HANGUL SYLLABLE KWAE +CF8D;CF8D;110F 116B 11A8;CF8D;110F 116B 11A8; # (쾍; 쾍; 쾍; 쾍; 쾍; ) HANGUL SYLLABLE KWAEG +CF8E;CF8E;110F 116B 11A9;CF8E;110F 116B 11A9; # (쾎; 쾎; 쾎; 쾎; 쾎; ) HANGUL SYLLABLE KWAEGG +CF8F;CF8F;110F 116B 11AA;CF8F;110F 116B 11AA; # (쾏; 쾏; 쾏; 쾏; 쾏; ) HANGUL SYLLABLE KWAEGS +CF90;CF90;110F 116B 11AB;CF90;110F 116B 11AB; # (쾐; 쾐; 쾐; 쾐; 쾐; ) HANGUL SYLLABLE KWAEN +CF91;CF91;110F 116B 11AC;CF91;110F 116B 11AC; # (쾑; 쾑; 쾑; 쾑; 쾑; ) HANGUL SYLLABLE KWAENJ +CF92;CF92;110F 116B 11AD;CF92;110F 116B 11AD; # (쾒; 쾒; 쾒; 쾒; 쾒; ) HANGUL SYLLABLE KWAENH +CF93;CF93;110F 116B 11AE;CF93;110F 116B 11AE; # (쾓; 쾓; 쾓; 쾓; 쾓; ) HANGUL SYLLABLE KWAED +CF94;CF94;110F 116B 11AF;CF94;110F 116B 11AF; # (쾔; 쾔; 쾔; 쾔; 쾔; ) HANGUL SYLLABLE KWAEL +CF95;CF95;110F 116B 11B0;CF95;110F 116B 11B0; # (쾕; 쾕; 쾕; 쾕; 쾕; ) HANGUL SYLLABLE KWAELG +CF96;CF96;110F 116B 11B1;CF96;110F 116B 11B1; # (쾖; 쾖; 쾖; 쾖; 쾖; ) HANGUL SYLLABLE KWAELM +CF97;CF97;110F 116B 11B2;CF97;110F 116B 11B2; # (쾗; 쾗; 쾗; 쾗; 쾗; ) HANGUL SYLLABLE KWAELB +CF98;CF98;110F 116B 11B3;CF98;110F 116B 11B3; # (쾘; 쾘; 쾘; 쾘; 쾘; ) HANGUL SYLLABLE KWAELS +CF99;CF99;110F 116B 11B4;CF99;110F 116B 11B4; # (쾙; 쾙; 쾙; 쾙; 쾙; ) HANGUL SYLLABLE KWAELT +CF9A;CF9A;110F 116B 11B5;CF9A;110F 116B 11B5; # (쾚; 쾚; 쾚; 쾚; 쾚; ) HANGUL SYLLABLE KWAELP +CF9B;CF9B;110F 116B 11B6;CF9B;110F 116B 11B6; # (쾛; 쾛; 쾛; 쾛; 쾛; ) HANGUL SYLLABLE KWAELH +CF9C;CF9C;110F 116B 11B7;CF9C;110F 116B 11B7; # (쾜; 쾜; 쾜; 쾜; 쾜; ) HANGUL SYLLABLE KWAEM +CF9D;CF9D;110F 116B 11B8;CF9D;110F 116B 11B8; # (쾝; 쾝; 쾝; 쾝; 쾝; ) HANGUL SYLLABLE KWAEB +CF9E;CF9E;110F 116B 11B9;CF9E;110F 116B 11B9; # (쾞; 쾞; 쾞; 쾞; 쾞; ) HANGUL SYLLABLE KWAEBS +CF9F;CF9F;110F 116B 11BA;CF9F;110F 116B 11BA; # (쾟; 쾟; 쾟; 쾟; 쾟; ) HANGUL SYLLABLE KWAES +CFA0;CFA0;110F 116B 11BB;CFA0;110F 116B 11BB; # (쾠; 쾠; 쾠; 쾠; 쾠; ) HANGUL SYLLABLE KWAESS +CFA1;CFA1;110F 116B 11BC;CFA1;110F 116B 11BC; # (쾡; 쾡; 쾡; 쾡; 쾡; ) HANGUL SYLLABLE KWAENG +CFA2;CFA2;110F 116B 11BD;CFA2;110F 116B 11BD; # (쾢; 쾢; 쾢; 쾢; 쾢; ) HANGUL SYLLABLE KWAEJ +CFA3;CFA3;110F 116B 11BE;CFA3;110F 116B 11BE; # (쾣; 쾣; 쾣; 쾣; 쾣; ) HANGUL SYLLABLE KWAEC +CFA4;CFA4;110F 116B 11BF;CFA4;110F 116B 11BF; # (쾤; 쾤; 쾤; 쾤; 쾤; ) HANGUL SYLLABLE KWAEK +CFA5;CFA5;110F 116B 11C0;CFA5;110F 116B 11C0; # (쾥; 쾥; 쾥; 쾥; 쾥; ) HANGUL SYLLABLE KWAET +CFA6;CFA6;110F 116B 11C1;CFA6;110F 116B 11C1; # (쾦; 쾦; 쾦; 쾦; 쾦; ) HANGUL SYLLABLE KWAEP +CFA7;CFA7;110F 116B 11C2;CFA7;110F 116B 11C2; # (쾧; 쾧; 쾧; 쾧; 쾧; ) HANGUL SYLLABLE KWAEH +CFA8;CFA8;110F 116C;CFA8;110F 116C; # (쾨; 쾨; 쾨; 쾨; 쾨; ) HANGUL SYLLABLE KOE +CFA9;CFA9;110F 116C 11A8;CFA9;110F 116C 11A8; # (쾩; 쾩; 쾩; 쾩; 쾩; ) HANGUL SYLLABLE KOEG +CFAA;CFAA;110F 116C 11A9;CFAA;110F 116C 11A9; # (쾪; 쾪; 쾪; 쾪; 쾪; ) HANGUL SYLLABLE KOEGG +CFAB;CFAB;110F 116C 11AA;CFAB;110F 116C 11AA; # (쾫; 쾫; 쾫; 쾫; 쾫; ) HANGUL SYLLABLE KOEGS +CFAC;CFAC;110F 116C 11AB;CFAC;110F 116C 11AB; # (쾬; 쾬; 쾬; 쾬; 쾬; ) HANGUL SYLLABLE KOEN +CFAD;CFAD;110F 116C 11AC;CFAD;110F 116C 11AC; # (쾭; 쾭; 쾭; 쾭; 쾭; ) HANGUL SYLLABLE KOENJ +CFAE;CFAE;110F 116C 11AD;CFAE;110F 116C 11AD; # (쾮; 쾮; 쾮; 쾮; 쾮; ) HANGUL SYLLABLE KOENH +CFAF;CFAF;110F 116C 11AE;CFAF;110F 116C 11AE; # (쾯; 쾯; 쾯; 쾯; 쾯; ) HANGUL SYLLABLE KOED +CFB0;CFB0;110F 116C 11AF;CFB0;110F 116C 11AF; # (쾰; 쾰; 쾰; 쾰; 쾰; ) HANGUL SYLLABLE KOEL +CFB1;CFB1;110F 116C 11B0;CFB1;110F 116C 11B0; # (쾱; 쾱; 쾱; 쾱; 쾱; ) HANGUL SYLLABLE KOELG +CFB2;CFB2;110F 116C 11B1;CFB2;110F 116C 11B1; # (쾲; 쾲; 쾲; 쾲; 쾲; ) HANGUL SYLLABLE KOELM +CFB3;CFB3;110F 116C 11B2;CFB3;110F 116C 11B2; # (쾳; 쾳; 쾳; 쾳; 쾳; ) HANGUL SYLLABLE KOELB +CFB4;CFB4;110F 116C 11B3;CFB4;110F 116C 11B3; # (쾴; 쾴; 쾴; 쾴; 쾴; ) HANGUL SYLLABLE KOELS +CFB5;CFB5;110F 116C 11B4;CFB5;110F 116C 11B4; # (쾵; 쾵; 쾵; 쾵; 쾵; ) HANGUL SYLLABLE KOELT +CFB6;CFB6;110F 116C 11B5;CFB6;110F 116C 11B5; # (쾶; 쾶; 쾶; 쾶; 쾶; ) HANGUL SYLLABLE KOELP +CFB7;CFB7;110F 116C 11B6;CFB7;110F 116C 11B6; # (쾷; 쾷; 쾷; 쾷; 쾷; ) HANGUL SYLLABLE KOELH +CFB8;CFB8;110F 116C 11B7;CFB8;110F 116C 11B7; # (쾸; 쾸; 쾸; 쾸; 쾸; ) HANGUL SYLLABLE KOEM +CFB9;CFB9;110F 116C 11B8;CFB9;110F 116C 11B8; # (쾹; 쾹; 쾹; 쾹; 쾹; ) HANGUL SYLLABLE KOEB +CFBA;CFBA;110F 116C 11B9;CFBA;110F 116C 11B9; # (쾺; 쾺; 쾺; 쾺; 쾺; ) HANGUL SYLLABLE KOEBS +CFBB;CFBB;110F 116C 11BA;CFBB;110F 116C 11BA; # (쾻; 쾻; 쾻; 쾻; 쾻; ) HANGUL SYLLABLE KOES +CFBC;CFBC;110F 116C 11BB;CFBC;110F 116C 11BB; # (쾼; 쾼; 쾼; 쾼; 쾼; ) HANGUL SYLLABLE KOESS +CFBD;CFBD;110F 116C 11BC;CFBD;110F 116C 11BC; # (쾽; 쾽; 쾽; 쾽; 쾽; ) HANGUL SYLLABLE KOENG +CFBE;CFBE;110F 116C 11BD;CFBE;110F 116C 11BD; # (쾾; 쾾; 쾾; 쾾; 쾾; ) HANGUL SYLLABLE KOEJ +CFBF;CFBF;110F 116C 11BE;CFBF;110F 116C 11BE; # (쾿; 쾿; 쾿; 쾿; 쾿; ) HANGUL SYLLABLE KOEC +CFC0;CFC0;110F 116C 11BF;CFC0;110F 116C 11BF; # (쿀; 쿀; 쿀; 쿀; 쿀; ) HANGUL SYLLABLE KOEK +CFC1;CFC1;110F 116C 11C0;CFC1;110F 116C 11C0; # (쿁; 쿁; 쿁; 쿁; 쿁; ) HANGUL SYLLABLE KOET +CFC2;CFC2;110F 116C 11C1;CFC2;110F 116C 11C1; # (쿂; 쿂; 쿂; 쿂; 쿂; ) HANGUL SYLLABLE KOEP +CFC3;CFC3;110F 116C 11C2;CFC3;110F 116C 11C2; # (쿃; 쿃; 쿃; 쿃; 쿃; ) HANGUL SYLLABLE KOEH +CFC4;CFC4;110F 116D;CFC4;110F 116D; # (쿄; 쿄; 쿄; 쿄; 쿄; ) HANGUL SYLLABLE KYO +CFC5;CFC5;110F 116D 11A8;CFC5;110F 116D 11A8; # (쿅; 쿅; 쿅; 쿅; 쿅; ) HANGUL SYLLABLE KYOG +CFC6;CFC6;110F 116D 11A9;CFC6;110F 116D 11A9; # (쿆; 쿆; 쿆; 쿆; 쿆; ) HANGUL SYLLABLE KYOGG +CFC7;CFC7;110F 116D 11AA;CFC7;110F 116D 11AA; # (쿇; 쿇; 쿇; 쿇; 쿇; ) HANGUL SYLLABLE KYOGS +CFC8;CFC8;110F 116D 11AB;CFC8;110F 116D 11AB; # (쿈; 쿈; 쿈; 쿈; 쿈; ) HANGUL SYLLABLE KYON +CFC9;CFC9;110F 116D 11AC;CFC9;110F 116D 11AC; # (쿉; 쿉; 쿉; 쿉; 쿉; ) HANGUL SYLLABLE KYONJ +CFCA;CFCA;110F 116D 11AD;CFCA;110F 116D 11AD; # (쿊; 쿊; 쿊; 쿊; 쿊; ) HANGUL SYLLABLE KYONH +CFCB;CFCB;110F 116D 11AE;CFCB;110F 116D 11AE; # (쿋; 쿋; 쿋; 쿋; 쿋; ) HANGUL SYLLABLE KYOD +CFCC;CFCC;110F 116D 11AF;CFCC;110F 116D 11AF; # (쿌; 쿌; 쿌; 쿌; 쿌; ) HANGUL SYLLABLE KYOL +CFCD;CFCD;110F 116D 11B0;CFCD;110F 116D 11B0; # (쿍; 쿍; 쿍; 쿍; 쿍; ) HANGUL SYLLABLE KYOLG +CFCE;CFCE;110F 116D 11B1;CFCE;110F 116D 11B1; # (쿎; 쿎; 쿎; 쿎; 쿎; ) HANGUL SYLLABLE KYOLM +CFCF;CFCF;110F 116D 11B2;CFCF;110F 116D 11B2; # (쿏; 쿏; 쿏; 쿏; 쿏; ) HANGUL SYLLABLE KYOLB +CFD0;CFD0;110F 116D 11B3;CFD0;110F 116D 11B3; # (쿐; 쿐; 쿐; 쿐; 쿐; ) HANGUL SYLLABLE KYOLS +CFD1;CFD1;110F 116D 11B4;CFD1;110F 116D 11B4; # (쿑; 쿑; 쿑; 쿑; 쿑; ) HANGUL SYLLABLE KYOLT +CFD2;CFD2;110F 116D 11B5;CFD2;110F 116D 11B5; # (쿒; 쿒; 쿒; 쿒; 쿒; ) HANGUL SYLLABLE KYOLP +CFD3;CFD3;110F 116D 11B6;CFD3;110F 116D 11B6; # (쿓; 쿓; 쿓; 쿓; 쿓; ) HANGUL SYLLABLE KYOLH +CFD4;CFD4;110F 116D 11B7;CFD4;110F 116D 11B7; # (쿔; 쿔; 쿔; 쿔; 쿔; ) HANGUL SYLLABLE KYOM +CFD5;CFD5;110F 116D 11B8;CFD5;110F 116D 11B8; # (쿕; 쿕; 쿕; 쿕; 쿕; ) HANGUL SYLLABLE KYOB +CFD6;CFD6;110F 116D 11B9;CFD6;110F 116D 11B9; # (쿖; 쿖; 쿖; 쿖; 쿖; ) HANGUL SYLLABLE KYOBS +CFD7;CFD7;110F 116D 11BA;CFD7;110F 116D 11BA; # (쿗; 쿗; 쿗; 쿗; 쿗; ) HANGUL SYLLABLE KYOS +CFD8;CFD8;110F 116D 11BB;CFD8;110F 116D 11BB; # (쿘; 쿘; 쿘; 쿘; 쿘; ) HANGUL SYLLABLE KYOSS +CFD9;CFD9;110F 116D 11BC;CFD9;110F 116D 11BC; # (쿙; 쿙; 쿙; 쿙; 쿙; ) HANGUL SYLLABLE KYONG +CFDA;CFDA;110F 116D 11BD;CFDA;110F 116D 11BD; # (쿚; 쿚; 쿚; 쿚; 쿚; ) HANGUL SYLLABLE KYOJ +CFDB;CFDB;110F 116D 11BE;CFDB;110F 116D 11BE; # (쿛; 쿛; 쿛; 쿛; 쿛; ) HANGUL SYLLABLE KYOC +CFDC;CFDC;110F 116D 11BF;CFDC;110F 116D 11BF; # (쿜; 쿜; 쿜; 쿜; 쿜; ) HANGUL SYLLABLE KYOK +CFDD;CFDD;110F 116D 11C0;CFDD;110F 116D 11C0; # (쿝; 쿝; 쿝; 쿝; 쿝; ) HANGUL SYLLABLE KYOT +CFDE;CFDE;110F 116D 11C1;CFDE;110F 116D 11C1; # (쿞; 쿞; 쿞; 쿞; 쿞; ) HANGUL SYLLABLE KYOP +CFDF;CFDF;110F 116D 11C2;CFDF;110F 116D 11C2; # (쿟; 쿟; 쿟; 쿟; 쿟; ) HANGUL SYLLABLE KYOH +CFE0;CFE0;110F 116E;CFE0;110F 116E; # (쿠; 쿠; 쿠; 쿠; 쿠; ) HANGUL SYLLABLE KU +CFE1;CFE1;110F 116E 11A8;CFE1;110F 116E 11A8; # (쿡; 쿡; 쿡; 쿡; 쿡; ) HANGUL SYLLABLE KUG +CFE2;CFE2;110F 116E 11A9;CFE2;110F 116E 11A9; # (쿢; 쿢; 쿢; 쿢; 쿢; ) HANGUL SYLLABLE KUGG +CFE3;CFE3;110F 116E 11AA;CFE3;110F 116E 11AA; # (쿣; 쿣; 쿣; 쿣; 쿣; ) HANGUL SYLLABLE KUGS +CFE4;CFE4;110F 116E 11AB;CFE4;110F 116E 11AB; # (쿤; 쿤; 쿤; 쿤; 쿤; ) HANGUL SYLLABLE KUN +CFE5;CFE5;110F 116E 11AC;CFE5;110F 116E 11AC; # (쿥; 쿥; 쿥; 쿥; 쿥; ) HANGUL SYLLABLE KUNJ +CFE6;CFE6;110F 116E 11AD;CFE6;110F 116E 11AD; # (쿦; 쿦; 쿦; 쿦; 쿦; ) HANGUL SYLLABLE KUNH +CFE7;CFE7;110F 116E 11AE;CFE7;110F 116E 11AE; # (쿧; 쿧; 쿧; 쿧; 쿧; ) HANGUL SYLLABLE KUD +CFE8;CFE8;110F 116E 11AF;CFE8;110F 116E 11AF; # (쿨; 쿨; 쿨; 쿨; 쿨; ) HANGUL SYLLABLE KUL +CFE9;CFE9;110F 116E 11B0;CFE9;110F 116E 11B0; # (쿩; 쿩; 쿩; 쿩; 쿩; ) HANGUL SYLLABLE KULG +CFEA;CFEA;110F 116E 11B1;CFEA;110F 116E 11B1; # (쿪; 쿪; 쿪; 쿪; 쿪; ) HANGUL SYLLABLE KULM +CFEB;CFEB;110F 116E 11B2;CFEB;110F 116E 11B2; # (쿫; 쿫; 쿫; 쿫; 쿫; ) HANGUL SYLLABLE KULB +CFEC;CFEC;110F 116E 11B3;CFEC;110F 116E 11B3; # (쿬; 쿬; 쿬; 쿬; 쿬; ) HANGUL SYLLABLE KULS +CFED;CFED;110F 116E 11B4;CFED;110F 116E 11B4; # (쿭; 쿭; 쿭; 쿭; 쿭; ) HANGUL SYLLABLE KULT +CFEE;CFEE;110F 116E 11B5;CFEE;110F 116E 11B5; # (쿮; 쿮; 쿮; 쿮; 쿮; ) HANGUL SYLLABLE KULP +CFEF;CFEF;110F 116E 11B6;CFEF;110F 116E 11B6; # (쿯; 쿯; 쿯; 쿯; 쿯; ) HANGUL SYLLABLE KULH +CFF0;CFF0;110F 116E 11B7;CFF0;110F 116E 11B7; # (쿰; 쿰; 쿰; 쿰; 쿰; ) HANGUL SYLLABLE KUM +CFF1;CFF1;110F 116E 11B8;CFF1;110F 116E 11B8; # (쿱; 쿱; 쿱; 쿱; 쿱; ) HANGUL SYLLABLE KUB +CFF2;CFF2;110F 116E 11B9;CFF2;110F 116E 11B9; # (쿲; 쿲; 쿲; 쿲; 쿲; ) HANGUL SYLLABLE KUBS +CFF3;CFF3;110F 116E 11BA;CFF3;110F 116E 11BA; # (쿳; 쿳; 쿳; 쿳; 쿳; ) HANGUL SYLLABLE KUS +CFF4;CFF4;110F 116E 11BB;CFF4;110F 116E 11BB; # (쿴; 쿴; 쿴; 쿴; 쿴; ) HANGUL SYLLABLE KUSS +CFF5;CFF5;110F 116E 11BC;CFF5;110F 116E 11BC; # (쿵; 쿵; 쿵; 쿵; 쿵; ) HANGUL SYLLABLE KUNG +CFF6;CFF6;110F 116E 11BD;CFF6;110F 116E 11BD; # (쿶; 쿶; 쿶; 쿶; 쿶; ) HANGUL SYLLABLE KUJ +CFF7;CFF7;110F 116E 11BE;CFF7;110F 116E 11BE; # (쿷; 쿷; 쿷; 쿷; 쿷; ) HANGUL SYLLABLE KUC +CFF8;CFF8;110F 116E 11BF;CFF8;110F 116E 11BF; # (쿸; 쿸; 쿸; 쿸; 쿸; ) HANGUL SYLLABLE KUK +CFF9;CFF9;110F 116E 11C0;CFF9;110F 116E 11C0; # (쿹; 쿹; 쿹; 쿹; 쿹; ) HANGUL SYLLABLE KUT +CFFA;CFFA;110F 116E 11C1;CFFA;110F 116E 11C1; # (쿺; 쿺; 쿺; 쿺; 쿺; ) HANGUL SYLLABLE KUP +CFFB;CFFB;110F 116E 11C2;CFFB;110F 116E 11C2; # (쿻; 쿻; 쿻; 쿻; 쿻; ) HANGUL SYLLABLE KUH +CFFC;CFFC;110F 116F;CFFC;110F 116F; # (쿼; 쿼; 쿼; 쿼; 쿼; ) HANGUL SYLLABLE KWEO +CFFD;CFFD;110F 116F 11A8;CFFD;110F 116F 11A8; # (쿽; 쿽; 쿽; 쿽; 쿽; ) HANGUL SYLLABLE KWEOG +CFFE;CFFE;110F 116F 11A9;CFFE;110F 116F 11A9; # (쿾; 쿾; 쿾; 쿾; 쿾; ) HANGUL SYLLABLE KWEOGG +CFFF;CFFF;110F 116F 11AA;CFFF;110F 116F 11AA; # (쿿; 쿿; 쿿; 쿿; 쿿; ) HANGUL SYLLABLE KWEOGS +D000;D000;110F 116F 11AB;D000;110F 116F 11AB; # (퀀; 퀀; 퀀; 퀀; 퀀; ) HANGUL SYLLABLE KWEON +D001;D001;110F 116F 11AC;D001;110F 116F 11AC; # (퀁; 퀁; 퀁; 퀁; 퀁; ) HANGUL SYLLABLE KWEONJ +D002;D002;110F 116F 11AD;D002;110F 116F 11AD; # (퀂; 퀂; 퀂; 퀂; 퀂; ) HANGUL SYLLABLE KWEONH +D003;D003;110F 116F 11AE;D003;110F 116F 11AE; # (퀃; 퀃; 퀃; 퀃; 퀃; ) HANGUL SYLLABLE KWEOD +D004;D004;110F 116F 11AF;D004;110F 116F 11AF; # (퀄; 퀄; 퀄; 퀄; 퀄; ) HANGUL SYLLABLE KWEOL +D005;D005;110F 116F 11B0;D005;110F 116F 11B0; # (퀅; 퀅; 퀅; 퀅; 퀅; ) HANGUL SYLLABLE KWEOLG +D006;D006;110F 116F 11B1;D006;110F 116F 11B1; # (퀆; 퀆; 퀆; 퀆; 퀆; ) HANGUL SYLLABLE KWEOLM +D007;D007;110F 116F 11B2;D007;110F 116F 11B2; # (퀇; 퀇; 퀇; 퀇; 퀇; ) HANGUL SYLLABLE KWEOLB +D008;D008;110F 116F 11B3;D008;110F 116F 11B3; # (퀈; 퀈; 퀈; 퀈; 퀈; ) HANGUL SYLLABLE KWEOLS +D009;D009;110F 116F 11B4;D009;110F 116F 11B4; # (퀉; 퀉; 퀉; 퀉; 퀉; ) HANGUL SYLLABLE KWEOLT +D00A;D00A;110F 116F 11B5;D00A;110F 116F 11B5; # (퀊; 퀊; 퀊; 퀊; 퀊; ) HANGUL SYLLABLE KWEOLP +D00B;D00B;110F 116F 11B6;D00B;110F 116F 11B6; # (퀋; 퀋; 퀋; 퀋; 퀋; ) HANGUL SYLLABLE KWEOLH +D00C;D00C;110F 116F 11B7;D00C;110F 116F 11B7; # (퀌; 퀌; 퀌; 퀌; 퀌; ) HANGUL SYLLABLE KWEOM +D00D;D00D;110F 116F 11B8;D00D;110F 116F 11B8; # (퀍; 퀍; 퀍; 퀍; 퀍; ) HANGUL SYLLABLE KWEOB +D00E;D00E;110F 116F 11B9;D00E;110F 116F 11B9; # (퀎; 퀎; 퀎; 퀎; 퀎; ) HANGUL SYLLABLE KWEOBS +D00F;D00F;110F 116F 11BA;D00F;110F 116F 11BA; # (퀏; 퀏; 퀏; 퀏; 퀏; ) HANGUL SYLLABLE KWEOS +D010;D010;110F 116F 11BB;D010;110F 116F 11BB; # (퀐; 퀐; 퀐; 퀐; 퀐; ) HANGUL SYLLABLE KWEOSS +D011;D011;110F 116F 11BC;D011;110F 116F 11BC; # (퀑; 퀑; 퀑; 퀑; 퀑; ) HANGUL SYLLABLE KWEONG +D012;D012;110F 116F 11BD;D012;110F 116F 11BD; # (퀒; 퀒; 퀒; 퀒; 퀒; ) HANGUL SYLLABLE KWEOJ +D013;D013;110F 116F 11BE;D013;110F 116F 11BE; # (퀓; 퀓; 퀓; 퀓; 퀓; ) HANGUL SYLLABLE KWEOC +D014;D014;110F 116F 11BF;D014;110F 116F 11BF; # (퀔; 퀔; 퀔; 퀔; 퀔; ) HANGUL SYLLABLE KWEOK +D015;D015;110F 116F 11C0;D015;110F 116F 11C0; # (퀕; 퀕; 퀕; 퀕; 퀕; ) HANGUL SYLLABLE KWEOT +D016;D016;110F 116F 11C1;D016;110F 116F 11C1; # (퀖; 퀖; 퀖; 퀖; 퀖; ) HANGUL SYLLABLE KWEOP +D017;D017;110F 116F 11C2;D017;110F 116F 11C2; # (퀗; 퀗; 퀗; 퀗; 퀗; ) HANGUL SYLLABLE KWEOH +D018;D018;110F 1170;D018;110F 1170; # (퀘; 퀘; 퀘; 퀘; 퀘; ) HANGUL SYLLABLE KWE +D019;D019;110F 1170 11A8;D019;110F 1170 11A8; # (퀙; 퀙; 퀙; 퀙; 퀙; ) HANGUL SYLLABLE KWEG +D01A;D01A;110F 1170 11A9;D01A;110F 1170 11A9; # (퀚; 퀚; 퀚; 퀚; 퀚; ) HANGUL SYLLABLE KWEGG +D01B;D01B;110F 1170 11AA;D01B;110F 1170 11AA; # (퀛; 퀛; 퀛; 퀛; 퀛; ) HANGUL SYLLABLE KWEGS +D01C;D01C;110F 1170 11AB;D01C;110F 1170 11AB; # (퀜; 퀜; 퀜; 퀜; 퀜; ) HANGUL SYLLABLE KWEN +D01D;D01D;110F 1170 11AC;D01D;110F 1170 11AC; # (퀝; 퀝; 퀝; 퀝; 퀝; ) HANGUL SYLLABLE KWENJ +D01E;D01E;110F 1170 11AD;D01E;110F 1170 11AD; # (퀞; 퀞; 퀞; 퀞; 퀞; ) HANGUL SYLLABLE KWENH +D01F;D01F;110F 1170 11AE;D01F;110F 1170 11AE; # (퀟; 퀟; 퀟; 퀟; 퀟; ) HANGUL SYLLABLE KWED +D020;D020;110F 1170 11AF;D020;110F 1170 11AF; # (퀠; 퀠; 퀠; 퀠; 퀠; ) HANGUL SYLLABLE KWEL +D021;D021;110F 1170 11B0;D021;110F 1170 11B0; # (퀡; 퀡; 퀡; 퀡; 퀡; ) HANGUL SYLLABLE KWELG +D022;D022;110F 1170 11B1;D022;110F 1170 11B1; # (퀢; 퀢; 퀢; 퀢; 퀢; ) HANGUL SYLLABLE KWELM +D023;D023;110F 1170 11B2;D023;110F 1170 11B2; # (퀣; 퀣; 퀣; 퀣; 퀣; ) HANGUL SYLLABLE KWELB +D024;D024;110F 1170 11B3;D024;110F 1170 11B3; # (퀤; 퀤; 퀤; 퀤; 퀤; ) HANGUL SYLLABLE KWELS +D025;D025;110F 1170 11B4;D025;110F 1170 11B4; # (퀥; 퀥; 퀥; 퀥; 퀥; ) HANGUL SYLLABLE KWELT +D026;D026;110F 1170 11B5;D026;110F 1170 11B5; # (퀦; 퀦; 퀦; 퀦; 퀦; ) HANGUL SYLLABLE KWELP +D027;D027;110F 1170 11B6;D027;110F 1170 11B6; # (퀧; 퀧; 퀧; 퀧; 퀧; ) HANGUL SYLLABLE KWELH +D028;D028;110F 1170 11B7;D028;110F 1170 11B7; # (퀨; 퀨; 퀨; 퀨; 퀨; ) HANGUL SYLLABLE KWEM +D029;D029;110F 1170 11B8;D029;110F 1170 11B8; # (퀩; 퀩; 퀩; 퀩; 퀩; ) HANGUL SYLLABLE KWEB +D02A;D02A;110F 1170 11B9;D02A;110F 1170 11B9; # (퀪; 퀪; 퀪; 퀪; 퀪; ) HANGUL SYLLABLE KWEBS +D02B;D02B;110F 1170 11BA;D02B;110F 1170 11BA; # (퀫; 퀫; 퀫; 퀫; 퀫; ) HANGUL SYLLABLE KWES +D02C;D02C;110F 1170 11BB;D02C;110F 1170 11BB; # (퀬; 퀬; 퀬; 퀬; 퀬; ) HANGUL SYLLABLE KWESS +D02D;D02D;110F 1170 11BC;D02D;110F 1170 11BC; # (퀭; 퀭; 퀭; 퀭; 퀭; ) HANGUL SYLLABLE KWENG +D02E;D02E;110F 1170 11BD;D02E;110F 1170 11BD; # (퀮; 퀮; 퀮; 퀮; 퀮; ) HANGUL SYLLABLE KWEJ +D02F;D02F;110F 1170 11BE;D02F;110F 1170 11BE; # (퀯; 퀯; 퀯; 퀯; 퀯; ) HANGUL SYLLABLE KWEC +D030;D030;110F 1170 11BF;D030;110F 1170 11BF; # (퀰; 퀰; 퀰; 퀰; 퀰; ) HANGUL SYLLABLE KWEK +D031;D031;110F 1170 11C0;D031;110F 1170 11C0; # (퀱; 퀱; 퀱; 퀱; 퀱; ) HANGUL SYLLABLE KWET +D032;D032;110F 1170 11C1;D032;110F 1170 11C1; # (퀲; 퀲; 퀲; 퀲; 퀲; ) HANGUL SYLLABLE KWEP +D033;D033;110F 1170 11C2;D033;110F 1170 11C2; # (퀳; 퀳; 퀳; 퀳; 퀳; ) HANGUL SYLLABLE KWEH +D034;D034;110F 1171;D034;110F 1171; # (퀴; 퀴; 퀴; 퀴; 퀴; ) HANGUL SYLLABLE KWI +D035;D035;110F 1171 11A8;D035;110F 1171 11A8; # (퀵; 퀵; 퀵; 퀵; 퀵; ) HANGUL SYLLABLE KWIG +D036;D036;110F 1171 11A9;D036;110F 1171 11A9; # (퀶; 퀶; 퀶; 퀶; 퀶; ) HANGUL SYLLABLE KWIGG +D037;D037;110F 1171 11AA;D037;110F 1171 11AA; # (퀷; 퀷; 퀷; 퀷; 퀷; ) HANGUL SYLLABLE KWIGS +D038;D038;110F 1171 11AB;D038;110F 1171 11AB; # (퀸; 퀸; 퀸; 퀸; 퀸; ) HANGUL SYLLABLE KWIN +D039;D039;110F 1171 11AC;D039;110F 1171 11AC; # (퀹; 퀹; 퀹; 퀹; 퀹; ) HANGUL SYLLABLE KWINJ +D03A;D03A;110F 1171 11AD;D03A;110F 1171 11AD; # (퀺; 퀺; 퀺; 퀺; 퀺; ) HANGUL SYLLABLE KWINH +D03B;D03B;110F 1171 11AE;D03B;110F 1171 11AE; # (퀻; 퀻; 퀻; 퀻; 퀻; ) HANGUL SYLLABLE KWID +D03C;D03C;110F 1171 11AF;D03C;110F 1171 11AF; # (퀼; 퀼; 퀼; 퀼; 퀼; ) HANGUL SYLLABLE KWIL +D03D;D03D;110F 1171 11B0;D03D;110F 1171 11B0; # (퀽; 퀽; 퀽; 퀽; 퀽; ) HANGUL SYLLABLE KWILG +D03E;D03E;110F 1171 11B1;D03E;110F 1171 11B1; # (퀾; 퀾; 퀾; 퀾; 퀾; ) HANGUL SYLLABLE KWILM +D03F;D03F;110F 1171 11B2;D03F;110F 1171 11B2; # (퀿; 퀿; 퀿; 퀿; 퀿; ) HANGUL SYLLABLE KWILB +D040;D040;110F 1171 11B3;D040;110F 1171 11B3; # (큀; 큀; 큀; 큀; 큀; ) HANGUL SYLLABLE KWILS +D041;D041;110F 1171 11B4;D041;110F 1171 11B4; # (큁; 큁; 큁; 큁; 큁; ) HANGUL SYLLABLE KWILT +D042;D042;110F 1171 11B5;D042;110F 1171 11B5; # (큂; 큂; 큂; 큂; 큂; ) HANGUL SYLLABLE KWILP +D043;D043;110F 1171 11B6;D043;110F 1171 11B6; # (큃; 큃; 큃; 큃; 큃; ) HANGUL SYLLABLE KWILH +D044;D044;110F 1171 11B7;D044;110F 1171 11B7; # (큄; 큄; 큄; 큄; 큄; ) HANGUL SYLLABLE KWIM +D045;D045;110F 1171 11B8;D045;110F 1171 11B8; # (큅; 큅; 큅; 큅; 큅; ) HANGUL SYLLABLE KWIB +D046;D046;110F 1171 11B9;D046;110F 1171 11B9; # (큆; 큆; 큆; 큆; 큆; ) HANGUL SYLLABLE KWIBS +D047;D047;110F 1171 11BA;D047;110F 1171 11BA; # (큇; 큇; 큇; 큇; 큇; ) HANGUL SYLLABLE KWIS +D048;D048;110F 1171 11BB;D048;110F 1171 11BB; # (큈; 큈; 큈; 큈; 큈; ) HANGUL SYLLABLE KWISS +D049;D049;110F 1171 11BC;D049;110F 1171 11BC; # (큉; 큉; 큉; 큉; 큉; ) HANGUL SYLLABLE KWING +D04A;D04A;110F 1171 11BD;D04A;110F 1171 11BD; # (큊; 큊; 큊; 큊; 큊; ) HANGUL SYLLABLE KWIJ +D04B;D04B;110F 1171 11BE;D04B;110F 1171 11BE; # (큋; 큋; 큋; 큋; 큋; ) HANGUL SYLLABLE KWIC +D04C;D04C;110F 1171 11BF;D04C;110F 1171 11BF; # (큌; 큌; 큌; 큌; 큌; ) HANGUL SYLLABLE KWIK +D04D;D04D;110F 1171 11C0;D04D;110F 1171 11C0; # (큍; 큍; 큍; 큍; 큍; ) HANGUL SYLLABLE KWIT +D04E;D04E;110F 1171 11C1;D04E;110F 1171 11C1; # (큎; 큎; 큎; 큎; 큎; ) HANGUL SYLLABLE KWIP +D04F;D04F;110F 1171 11C2;D04F;110F 1171 11C2; # (큏; 큏; 큏; 큏; 큏; ) HANGUL SYLLABLE KWIH +D050;D050;110F 1172;D050;110F 1172; # (큐; 큐; 큐; 큐; 큐; ) HANGUL SYLLABLE KYU +D051;D051;110F 1172 11A8;D051;110F 1172 11A8; # (큑; 큑; 큑; 큑; 큑; ) HANGUL SYLLABLE KYUG +D052;D052;110F 1172 11A9;D052;110F 1172 11A9; # (큒; 큒; 큒; 큒; 큒; ) HANGUL SYLLABLE KYUGG +D053;D053;110F 1172 11AA;D053;110F 1172 11AA; # (큓; 큓; 큓; 큓; 큓; ) HANGUL SYLLABLE KYUGS +D054;D054;110F 1172 11AB;D054;110F 1172 11AB; # (큔; 큔; 큔; 큔; 큔; ) HANGUL SYLLABLE KYUN +D055;D055;110F 1172 11AC;D055;110F 1172 11AC; # (큕; 큕; 큕; 큕; 큕; ) HANGUL SYLLABLE KYUNJ +D056;D056;110F 1172 11AD;D056;110F 1172 11AD; # (큖; 큖; 큖; 큖; 큖; ) HANGUL SYLLABLE KYUNH +D057;D057;110F 1172 11AE;D057;110F 1172 11AE; # (큗; 큗; 큗; 큗; 큗; ) HANGUL SYLLABLE KYUD +D058;D058;110F 1172 11AF;D058;110F 1172 11AF; # (큘; 큘; 큘; 큘; 큘; ) HANGUL SYLLABLE KYUL +D059;D059;110F 1172 11B0;D059;110F 1172 11B0; # (큙; 큙; 큙; 큙; 큙; ) HANGUL SYLLABLE KYULG +D05A;D05A;110F 1172 11B1;D05A;110F 1172 11B1; # (큚; 큚; 큚; 큚; 큚; ) HANGUL SYLLABLE KYULM +D05B;D05B;110F 1172 11B2;D05B;110F 1172 11B2; # (큛; 큛; 큛; 큛; 큛; ) HANGUL SYLLABLE KYULB +D05C;D05C;110F 1172 11B3;D05C;110F 1172 11B3; # (큜; 큜; 큜; 큜; 큜; ) HANGUL SYLLABLE KYULS +D05D;D05D;110F 1172 11B4;D05D;110F 1172 11B4; # (큝; 큝; 큝; 큝; 큝; ) HANGUL SYLLABLE KYULT +D05E;D05E;110F 1172 11B5;D05E;110F 1172 11B5; # (큞; 큞; 큞; 큞; 큞; ) HANGUL SYLLABLE KYULP +D05F;D05F;110F 1172 11B6;D05F;110F 1172 11B6; # (큟; 큟; 큟; 큟; 큟; ) HANGUL SYLLABLE KYULH +D060;D060;110F 1172 11B7;D060;110F 1172 11B7; # (큠; 큠; 큠; 큠; 큠; ) HANGUL SYLLABLE KYUM +D061;D061;110F 1172 11B8;D061;110F 1172 11B8; # (큡; 큡; 큡; 큡; 큡; ) HANGUL SYLLABLE KYUB +D062;D062;110F 1172 11B9;D062;110F 1172 11B9; # (큢; 큢; 큢; 큢; 큢; ) HANGUL SYLLABLE KYUBS +D063;D063;110F 1172 11BA;D063;110F 1172 11BA; # (큣; 큣; 큣; 큣; 큣; ) HANGUL SYLLABLE KYUS +D064;D064;110F 1172 11BB;D064;110F 1172 11BB; # (큤; 큤; 큤; 큤; 큤; ) HANGUL SYLLABLE KYUSS +D065;D065;110F 1172 11BC;D065;110F 1172 11BC; # (큥; 큥; 큥; 큥; 큥; ) HANGUL SYLLABLE KYUNG +D066;D066;110F 1172 11BD;D066;110F 1172 11BD; # (큦; 큦; 큦; 큦; 큦; ) HANGUL SYLLABLE KYUJ +D067;D067;110F 1172 11BE;D067;110F 1172 11BE; # (큧; 큧; 큧; 큧; 큧; ) HANGUL SYLLABLE KYUC +D068;D068;110F 1172 11BF;D068;110F 1172 11BF; # (큨; 큨; 큨; 큨; 큨; ) HANGUL SYLLABLE KYUK +D069;D069;110F 1172 11C0;D069;110F 1172 11C0; # (큩; 큩; 큩; 큩; 큩; ) HANGUL SYLLABLE KYUT +D06A;D06A;110F 1172 11C1;D06A;110F 1172 11C1; # (큪; 큪; 큪; 큪; 큪; ) HANGUL SYLLABLE KYUP +D06B;D06B;110F 1172 11C2;D06B;110F 1172 11C2; # (큫; 큫; 큫; 큫; 큫; ) HANGUL SYLLABLE KYUH +D06C;D06C;110F 1173;D06C;110F 1173; # (크; 크; 크; 크; 크; ) HANGUL SYLLABLE KEU +D06D;D06D;110F 1173 11A8;D06D;110F 1173 11A8; # (큭; 큭; 큭; 큭; 큭; ) HANGUL SYLLABLE KEUG +D06E;D06E;110F 1173 11A9;D06E;110F 1173 11A9; # (큮; 큮; 큮; 큮; 큮; ) HANGUL SYLLABLE KEUGG +D06F;D06F;110F 1173 11AA;D06F;110F 1173 11AA; # (큯; 큯; 큯; 큯; 큯; ) HANGUL SYLLABLE KEUGS +D070;D070;110F 1173 11AB;D070;110F 1173 11AB; # (큰; 큰; 큰; 큰; 큰; ) HANGUL SYLLABLE KEUN +D071;D071;110F 1173 11AC;D071;110F 1173 11AC; # (큱; 큱; 큱; 큱; 큱; ) HANGUL SYLLABLE KEUNJ +D072;D072;110F 1173 11AD;D072;110F 1173 11AD; # (큲; 큲; 큲; 큲; 큲; ) HANGUL SYLLABLE KEUNH +D073;D073;110F 1173 11AE;D073;110F 1173 11AE; # (큳; 큳; 큳; 큳; 큳; ) HANGUL SYLLABLE KEUD +D074;D074;110F 1173 11AF;D074;110F 1173 11AF; # (클; 클; 클; 클; 클; ) HANGUL SYLLABLE KEUL +D075;D075;110F 1173 11B0;D075;110F 1173 11B0; # (큵; 큵; 큵; 큵; 큵; ) HANGUL SYLLABLE KEULG +D076;D076;110F 1173 11B1;D076;110F 1173 11B1; # (큶; 큶; 큶; 큶; 큶; ) HANGUL SYLLABLE KEULM +D077;D077;110F 1173 11B2;D077;110F 1173 11B2; # (큷; 큷; 큷; 큷; 큷; ) HANGUL SYLLABLE KEULB +D078;D078;110F 1173 11B3;D078;110F 1173 11B3; # (큸; 큸; 큸; 큸; 큸; ) HANGUL SYLLABLE KEULS +D079;D079;110F 1173 11B4;D079;110F 1173 11B4; # (큹; 큹; 큹; 큹; 큹; ) HANGUL SYLLABLE KEULT +D07A;D07A;110F 1173 11B5;D07A;110F 1173 11B5; # (큺; 큺; 큺; 큺; 큺; ) HANGUL SYLLABLE KEULP +D07B;D07B;110F 1173 11B6;D07B;110F 1173 11B6; # (큻; 큻; 큻; 큻; 큻; ) HANGUL SYLLABLE KEULH +D07C;D07C;110F 1173 11B7;D07C;110F 1173 11B7; # (큼; 큼; 큼; 큼; 큼; ) HANGUL SYLLABLE KEUM +D07D;D07D;110F 1173 11B8;D07D;110F 1173 11B8; # (큽; 큽; 큽; 큽; 큽; ) HANGUL SYLLABLE KEUB +D07E;D07E;110F 1173 11B9;D07E;110F 1173 11B9; # (큾; 큾; 큾; 큾; 큾; ) HANGUL SYLLABLE KEUBS +D07F;D07F;110F 1173 11BA;D07F;110F 1173 11BA; # (큿; 큿; 큿; 큿; 큿; ) HANGUL SYLLABLE KEUS +D080;D080;110F 1173 11BB;D080;110F 1173 11BB; # (킀; 킀; 킀; 킀; 킀; ) HANGUL SYLLABLE KEUSS +D081;D081;110F 1173 11BC;D081;110F 1173 11BC; # (킁; 킁; 킁; 킁; 킁; ) HANGUL SYLLABLE KEUNG +D082;D082;110F 1173 11BD;D082;110F 1173 11BD; # (킂; 킂; 킂; 킂; 킂; ) HANGUL SYLLABLE KEUJ +D083;D083;110F 1173 11BE;D083;110F 1173 11BE; # (킃; 킃; 킃; 킃; 킃; ) HANGUL SYLLABLE KEUC +D084;D084;110F 1173 11BF;D084;110F 1173 11BF; # (킄; 킄; 킄; 킄; 킄; ) HANGUL SYLLABLE KEUK +D085;D085;110F 1173 11C0;D085;110F 1173 11C0; # (킅; 킅; 킅; 킅; 킅; ) HANGUL SYLLABLE KEUT +D086;D086;110F 1173 11C1;D086;110F 1173 11C1; # (킆; 킆; 킆; 킆; 킆; ) HANGUL SYLLABLE KEUP +D087;D087;110F 1173 11C2;D087;110F 1173 11C2; # (킇; 킇; 킇; 킇; 킇; ) HANGUL SYLLABLE KEUH +D088;D088;110F 1174;D088;110F 1174; # (킈; 킈; 킈; 킈; 킈; ) HANGUL SYLLABLE KYI +D089;D089;110F 1174 11A8;D089;110F 1174 11A8; # (킉; 킉; 킉; 킉; 킉; ) HANGUL SYLLABLE KYIG +D08A;D08A;110F 1174 11A9;D08A;110F 1174 11A9; # (킊; 킊; 킊; 킊; 킊; ) HANGUL SYLLABLE KYIGG +D08B;D08B;110F 1174 11AA;D08B;110F 1174 11AA; # (킋; 킋; 킋; 킋; 킋; ) HANGUL SYLLABLE KYIGS +D08C;D08C;110F 1174 11AB;D08C;110F 1174 11AB; # (킌; 킌; 킌; 킌; 킌; ) HANGUL SYLLABLE KYIN +D08D;D08D;110F 1174 11AC;D08D;110F 1174 11AC; # (킍; 킍; 킍; 킍; 킍; ) HANGUL SYLLABLE KYINJ +D08E;D08E;110F 1174 11AD;D08E;110F 1174 11AD; # (킎; 킎; 킎; 킎; 킎; ) HANGUL SYLLABLE KYINH +D08F;D08F;110F 1174 11AE;D08F;110F 1174 11AE; # (킏; 킏; 킏; 킏; 킏; ) HANGUL SYLLABLE KYID +D090;D090;110F 1174 11AF;D090;110F 1174 11AF; # (킐; 킐; 킐; 킐; 킐; ) HANGUL SYLLABLE KYIL +D091;D091;110F 1174 11B0;D091;110F 1174 11B0; # (킑; 킑; 킑; 킑; 킑; ) HANGUL SYLLABLE KYILG +D092;D092;110F 1174 11B1;D092;110F 1174 11B1; # (킒; 킒; 킒; 킒; 킒; ) HANGUL SYLLABLE KYILM +D093;D093;110F 1174 11B2;D093;110F 1174 11B2; # (킓; 킓; 킓; 킓; 킓; ) HANGUL SYLLABLE KYILB +D094;D094;110F 1174 11B3;D094;110F 1174 11B3; # (킔; 킔; 킔; 킔; 킔; ) HANGUL SYLLABLE KYILS +D095;D095;110F 1174 11B4;D095;110F 1174 11B4; # (킕; 킕; 킕; 킕; 킕; ) HANGUL SYLLABLE KYILT +D096;D096;110F 1174 11B5;D096;110F 1174 11B5; # (킖; 킖; 킖; 킖; 킖; ) HANGUL SYLLABLE KYILP +D097;D097;110F 1174 11B6;D097;110F 1174 11B6; # (킗; 킗; 킗; 킗; 킗; ) HANGUL SYLLABLE KYILH +D098;D098;110F 1174 11B7;D098;110F 1174 11B7; # (킘; 킘; 킘; 킘; 킘; ) HANGUL SYLLABLE KYIM +D099;D099;110F 1174 11B8;D099;110F 1174 11B8; # (킙; 킙; 킙; 킙; 킙; ) HANGUL SYLLABLE KYIB +D09A;D09A;110F 1174 11B9;D09A;110F 1174 11B9; # (킚; 킚; 킚; 킚; 킚; ) HANGUL SYLLABLE KYIBS +D09B;D09B;110F 1174 11BA;D09B;110F 1174 11BA; # (킛; 킛; 킛; 킛; 킛; ) HANGUL SYLLABLE KYIS +D09C;D09C;110F 1174 11BB;D09C;110F 1174 11BB; # (킜; 킜; 킜; 킜; 킜; ) HANGUL SYLLABLE KYISS +D09D;D09D;110F 1174 11BC;D09D;110F 1174 11BC; # (킝; 킝; 킝; 킝; 킝; ) HANGUL SYLLABLE KYING +D09E;D09E;110F 1174 11BD;D09E;110F 1174 11BD; # (킞; 킞; 킞; 킞; 킞; ) HANGUL SYLLABLE KYIJ +D09F;D09F;110F 1174 11BE;D09F;110F 1174 11BE; # (킟; 킟; 킟; 킟; 킟; ) HANGUL SYLLABLE KYIC +D0A0;D0A0;110F 1174 11BF;D0A0;110F 1174 11BF; # (킠; 킠; 킠; 킠; 킠; ) HANGUL SYLLABLE KYIK +D0A1;D0A1;110F 1174 11C0;D0A1;110F 1174 11C0; # (킡; 킡; 킡; 킡; 킡; ) HANGUL SYLLABLE KYIT +D0A2;D0A2;110F 1174 11C1;D0A2;110F 1174 11C1; # (킢; 킢; 킢; 킢; 킢; ) HANGUL SYLLABLE KYIP +D0A3;D0A3;110F 1174 11C2;D0A3;110F 1174 11C2; # (킣; 킣; 킣; 킣; 킣; ) HANGUL SYLLABLE KYIH +D0A4;D0A4;110F 1175;D0A4;110F 1175; # (키; 키; 키; 키; 키; ) HANGUL SYLLABLE KI +D0A5;D0A5;110F 1175 11A8;D0A5;110F 1175 11A8; # (킥; 킥; 킥; 킥; 킥; ) HANGUL SYLLABLE KIG +D0A6;D0A6;110F 1175 11A9;D0A6;110F 1175 11A9; # (킦; 킦; 킦; 킦; 킦; ) HANGUL SYLLABLE KIGG +D0A7;D0A7;110F 1175 11AA;D0A7;110F 1175 11AA; # (킧; 킧; 킧; 킧; 킧; ) HANGUL SYLLABLE KIGS +D0A8;D0A8;110F 1175 11AB;D0A8;110F 1175 11AB; # (킨; 킨; 킨; 킨; 킨; ) HANGUL SYLLABLE KIN +D0A9;D0A9;110F 1175 11AC;D0A9;110F 1175 11AC; # (킩; 킩; 킩; 킩; 킩; ) HANGUL SYLLABLE KINJ +D0AA;D0AA;110F 1175 11AD;D0AA;110F 1175 11AD; # (킪; 킪; 킪; 킪; 킪; ) HANGUL SYLLABLE KINH +D0AB;D0AB;110F 1175 11AE;D0AB;110F 1175 11AE; # (킫; 킫; 킫; 킫; 킫; ) HANGUL SYLLABLE KID +D0AC;D0AC;110F 1175 11AF;D0AC;110F 1175 11AF; # (킬; 킬; 킬; 킬; 킬; ) HANGUL SYLLABLE KIL +D0AD;D0AD;110F 1175 11B0;D0AD;110F 1175 11B0; # (킭; 킭; 킭; 킭; 킭; ) HANGUL SYLLABLE KILG +D0AE;D0AE;110F 1175 11B1;D0AE;110F 1175 11B1; # (킮; 킮; 킮; 킮; 킮; ) HANGUL SYLLABLE KILM +D0AF;D0AF;110F 1175 11B2;D0AF;110F 1175 11B2; # (킯; 킯; 킯; 킯; 킯; ) HANGUL SYLLABLE KILB +D0B0;D0B0;110F 1175 11B3;D0B0;110F 1175 11B3; # (킰; 킰; 킰; 킰; 킰; ) HANGUL SYLLABLE KILS +D0B1;D0B1;110F 1175 11B4;D0B1;110F 1175 11B4; # (킱; 킱; 킱; 킱; 킱; ) HANGUL SYLLABLE KILT +D0B2;D0B2;110F 1175 11B5;D0B2;110F 1175 11B5; # (킲; 킲; 킲; 킲; 킲; ) HANGUL SYLLABLE KILP +D0B3;D0B3;110F 1175 11B6;D0B3;110F 1175 11B6; # (킳; 킳; 킳; 킳; 킳; ) HANGUL SYLLABLE KILH +D0B4;D0B4;110F 1175 11B7;D0B4;110F 1175 11B7; # (킴; 킴; 킴; 킴; 킴; ) HANGUL SYLLABLE KIM +D0B5;D0B5;110F 1175 11B8;D0B5;110F 1175 11B8; # (킵; 킵; 킵; 킵; 킵; ) HANGUL SYLLABLE KIB +D0B6;D0B6;110F 1175 11B9;D0B6;110F 1175 11B9; # (킶; 킶; 킶; 킶; 킶; ) HANGUL SYLLABLE KIBS +D0B7;D0B7;110F 1175 11BA;D0B7;110F 1175 11BA; # (킷; 킷; 킷; 킷; 킷; ) HANGUL SYLLABLE KIS +D0B8;D0B8;110F 1175 11BB;D0B8;110F 1175 11BB; # (킸; 킸; 킸; 킸; 킸; ) HANGUL SYLLABLE KISS +D0B9;D0B9;110F 1175 11BC;D0B9;110F 1175 11BC; # (킹; 킹; 킹; 킹; 킹; ) HANGUL SYLLABLE KING +D0BA;D0BA;110F 1175 11BD;D0BA;110F 1175 11BD; # (킺; 킺; 킺; 킺; 킺; ) HANGUL SYLLABLE KIJ +D0BB;D0BB;110F 1175 11BE;D0BB;110F 1175 11BE; # (킻; 킻; 킻; 킻; 킻; ) HANGUL SYLLABLE KIC +D0BC;D0BC;110F 1175 11BF;D0BC;110F 1175 11BF; # (킼; 킼; 킼; 킼; 킼; ) HANGUL SYLLABLE KIK +D0BD;D0BD;110F 1175 11C0;D0BD;110F 1175 11C0; # (킽; 킽; 킽; 킽; 킽; ) HANGUL SYLLABLE KIT +D0BE;D0BE;110F 1175 11C1;D0BE;110F 1175 11C1; # (킾; 킾; 킾; 킾; 킾; ) HANGUL SYLLABLE KIP +D0BF;D0BF;110F 1175 11C2;D0BF;110F 1175 11C2; # (킿; 킿; 킿; 킿; 킿; ) HANGUL SYLLABLE KIH +D0C0;D0C0;1110 1161;D0C0;1110 1161; # (타; 타; 타; 타; 타; ) HANGUL SYLLABLE TA +D0C1;D0C1;1110 1161 11A8;D0C1;1110 1161 11A8; # (탁; 탁; 탁; 탁; 탁; ) HANGUL SYLLABLE TAG +D0C2;D0C2;1110 1161 11A9;D0C2;1110 1161 11A9; # (탂; 탂; 탂; 탂; 탂; ) HANGUL SYLLABLE TAGG +D0C3;D0C3;1110 1161 11AA;D0C3;1110 1161 11AA; # (탃; 탃; 탃; 탃; 탃; ) HANGUL SYLLABLE TAGS +D0C4;D0C4;1110 1161 11AB;D0C4;1110 1161 11AB; # (탄; 탄; 탄; 탄; 탄; ) HANGUL SYLLABLE TAN +D0C5;D0C5;1110 1161 11AC;D0C5;1110 1161 11AC; # (탅; 탅; 탅; 탅; 탅; ) HANGUL SYLLABLE TANJ +D0C6;D0C6;1110 1161 11AD;D0C6;1110 1161 11AD; # (탆; 탆; 탆; 탆; 탆; ) HANGUL SYLLABLE TANH +D0C7;D0C7;1110 1161 11AE;D0C7;1110 1161 11AE; # (탇; 탇; 탇; 탇; 탇; ) HANGUL SYLLABLE TAD +D0C8;D0C8;1110 1161 11AF;D0C8;1110 1161 11AF; # (탈; 탈; 탈; 탈; 탈; ) HANGUL SYLLABLE TAL +D0C9;D0C9;1110 1161 11B0;D0C9;1110 1161 11B0; # (탉; 탉; 탉; 탉; 탉; ) HANGUL SYLLABLE TALG +D0CA;D0CA;1110 1161 11B1;D0CA;1110 1161 11B1; # (탊; 탊; 탊; 탊; 탊; ) HANGUL SYLLABLE TALM +D0CB;D0CB;1110 1161 11B2;D0CB;1110 1161 11B2; # (탋; 탋; 탋; 탋; 탋; ) HANGUL SYLLABLE TALB +D0CC;D0CC;1110 1161 11B3;D0CC;1110 1161 11B3; # (탌; 탌; 탌; 탌; 탌; ) HANGUL SYLLABLE TALS +D0CD;D0CD;1110 1161 11B4;D0CD;1110 1161 11B4; # (탍; 탍; 탍; 탍; 탍; ) HANGUL SYLLABLE TALT +D0CE;D0CE;1110 1161 11B5;D0CE;1110 1161 11B5; # (탎; 탎; 탎; 탎; 탎; ) HANGUL SYLLABLE TALP +D0CF;D0CF;1110 1161 11B6;D0CF;1110 1161 11B6; # (탏; 탏; 탏; 탏; 탏; ) HANGUL SYLLABLE TALH +D0D0;D0D0;1110 1161 11B7;D0D0;1110 1161 11B7; # (탐; 탐; 탐; 탐; 탐; ) HANGUL SYLLABLE TAM +D0D1;D0D1;1110 1161 11B8;D0D1;1110 1161 11B8; # (탑; 탑; 탑; 탑; 탑; ) HANGUL SYLLABLE TAB +D0D2;D0D2;1110 1161 11B9;D0D2;1110 1161 11B9; # (탒; 탒; 탒; 탒; 탒; ) HANGUL SYLLABLE TABS +D0D3;D0D3;1110 1161 11BA;D0D3;1110 1161 11BA; # (탓; 탓; 탓; 탓; 탓; ) HANGUL SYLLABLE TAS +D0D4;D0D4;1110 1161 11BB;D0D4;1110 1161 11BB; # (탔; 탔; 탔; 탔; 탔; ) HANGUL SYLLABLE TASS +D0D5;D0D5;1110 1161 11BC;D0D5;1110 1161 11BC; # (탕; 탕; 탕; 탕; 탕; ) HANGUL SYLLABLE TANG +D0D6;D0D6;1110 1161 11BD;D0D6;1110 1161 11BD; # (탖; 탖; 탖; 탖; 탖; ) HANGUL SYLLABLE TAJ +D0D7;D0D7;1110 1161 11BE;D0D7;1110 1161 11BE; # (탗; 탗; 탗; 탗; 탗; ) HANGUL SYLLABLE TAC +D0D8;D0D8;1110 1161 11BF;D0D8;1110 1161 11BF; # (탘; 탘; 탘; 탘; 탘; ) HANGUL SYLLABLE TAK +D0D9;D0D9;1110 1161 11C0;D0D9;1110 1161 11C0; # (탙; 탙; 탙; 탙; 탙; ) HANGUL SYLLABLE TAT +D0DA;D0DA;1110 1161 11C1;D0DA;1110 1161 11C1; # (탚; 탚; 탚; 탚; 탚; ) HANGUL SYLLABLE TAP +D0DB;D0DB;1110 1161 11C2;D0DB;1110 1161 11C2; # (탛; 탛; 탛; 탛; 탛; ) HANGUL SYLLABLE TAH +D0DC;D0DC;1110 1162;D0DC;1110 1162; # (태; 태; 태; 태; 태; ) HANGUL SYLLABLE TAE +D0DD;D0DD;1110 1162 11A8;D0DD;1110 1162 11A8; # (택; 택; 택; 택; 택; ) HANGUL SYLLABLE TAEG +D0DE;D0DE;1110 1162 11A9;D0DE;1110 1162 11A9; # (탞; 탞; 탞; 탞; 탞; ) HANGUL SYLLABLE TAEGG +D0DF;D0DF;1110 1162 11AA;D0DF;1110 1162 11AA; # (탟; 탟; 탟; 탟; 탟; ) HANGUL SYLLABLE TAEGS +D0E0;D0E0;1110 1162 11AB;D0E0;1110 1162 11AB; # (탠; 탠; 탠; 탠; 탠; ) HANGUL SYLLABLE TAEN +D0E1;D0E1;1110 1162 11AC;D0E1;1110 1162 11AC; # (탡; 탡; 탡; 탡; 탡; ) HANGUL SYLLABLE TAENJ +D0E2;D0E2;1110 1162 11AD;D0E2;1110 1162 11AD; # (탢; 탢; 탢; 탢; 탢; ) HANGUL SYLLABLE TAENH +D0E3;D0E3;1110 1162 11AE;D0E3;1110 1162 11AE; # (탣; 탣; 탣; 탣; 탣; ) HANGUL SYLLABLE TAED +D0E4;D0E4;1110 1162 11AF;D0E4;1110 1162 11AF; # (탤; 탤; 탤; 탤; 탤; ) HANGUL SYLLABLE TAEL +D0E5;D0E5;1110 1162 11B0;D0E5;1110 1162 11B0; # (탥; 탥; 탥; 탥; 탥; ) HANGUL SYLLABLE TAELG +D0E6;D0E6;1110 1162 11B1;D0E6;1110 1162 11B1; # (탦; 탦; 탦; 탦; 탦; ) HANGUL SYLLABLE TAELM +D0E7;D0E7;1110 1162 11B2;D0E7;1110 1162 11B2; # (탧; 탧; 탧; 탧; 탧; ) HANGUL SYLLABLE TAELB +D0E8;D0E8;1110 1162 11B3;D0E8;1110 1162 11B3; # (탨; 탨; 탨; 탨; 탨; ) HANGUL SYLLABLE TAELS +D0E9;D0E9;1110 1162 11B4;D0E9;1110 1162 11B4; # (탩; 탩; 탩; 탩; 탩; ) HANGUL SYLLABLE TAELT +D0EA;D0EA;1110 1162 11B5;D0EA;1110 1162 11B5; # (탪; 탪; 탪; 탪; 탪; ) HANGUL SYLLABLE TAELP +D0EB;D0EB;1110 1162 11B6;D0EB;1110 1162 11B6; # (탫; 탫; 탫; 탫; 탫; ) HANGUL SYLLABLE TAELH +D0EC;D0EC;1110 1162 11B7;D0EC;1110 1162 11B7; # (탬; 탬; 탬; 탬; 탬; ) HANGUL SYLLABLE TAEM +D0ED;D0ED;1110 1162 11B8;D0ED;1110 1162 11B8; # (탭; 탭; 탭; 탭; 탭; ) HANGUL SYLLABLE TAEB +D0EE;D0EE;1110 1162 11B9;D0EE;1110 1162 11B9; # (탮; 탮; 탮; 탮; 탮; ) HANGUL SYLLABLE TAEBS +D0EF;D0EF;1110 1162 11BA;D0EF;1110 1162 11BA; # (탯; 탯; 탯; 탯; 탯; ) HANGUL SYLLABLE TAES +D0F0;D0F0;1110 1162 11BB;D0F0;1110 1162 11BB; # (탰; 탰; 탰; 탰; 탰; ) HANGUL SYLLABLE TAESS +D0F1;D0F1;1110 1162 11BC;D0F1;1110 1162 11BC; # (탱; 탱; 탱; 탱; 탱; ) HANGUL SYLLABLE TAENG +D0F2;D0F2;1110 1162 11BD;D0F2;1110 1162 11BD; # (탲; 탲; 탲; 탲; 탲; ) HANGUL SYLLABLE TAEJ +D0F3;D0F3;1110 1162 11BE;D0F3;1110 1162 11BE; # (탳; 탳; 탳; 탳; 탳; ) HANGUL SYLLABLE TAEC +D0F4;D0F4;1110 1162 11BF;D0F4;1110 1162 11BF; # (탴; 탴; 탴; 탴; 탴; ) HANGUL SYLLABLE TAEK +D0F5;D0F5;1110 1162 11C0;D0F5;1110 1162 11C0; # (탵; 탵; 탵; 탵; 탵; ) HANGUL SYLLABLE TAET +D0F6;D0F6;1110 1162 11C1;D0F6;1110 1162 11C1; # (탶; 탶; 탶; 탶; 탶; ) HANGUL SYLLABLE TAEP +D0F7;D0F7;1110 1162 11C2;D0F7;1110 1162 11C2; # (탷; 탷; 탷; 탷; 탷; ) HANGUL SYLLABLE TAEH +D0F8;D0F8;1110 1163;D0F8;1110 1163; # (탸; 탸; 탸; 탸; 탸; ) HANGUL SYLLABLE TYA +D0F9;D0F9;1110 1163 11A8;D0F9;1110 1163 11A8; # (탹; 탹; 탹; 탹; 탹; ) HANGUL SYLLABLE TYAG +D0FA;D0FA;1110 1163 11A9;D0FA;1110 1163 11A9; # (탺; 탺; 탺; 탺; 탺; ) HANGUL SYLLABLE TYAGG +D0FB;D0FB;1110 1163 11AA;D0FB;1110 1163 11AA; # (탻; 탻; 탻; 탻; 탻; ) HANGUL SYLLABLE TYAGS +D0FC;D0FC;1110 1163 11AB;D0FC;1110 1163 11AB; # (탼; 탼; 탼; 탼; 탼; ) HANGUL SYLLABLE TYAN +D0FD;D0FD;1110 1163 11AC;D0FD;1110 1163 11AC; # (탽; 탽; 탽; 탽; 탽; ) HANGUL SYLLABLE TYANJ +D0FE;D0FE;1110 1163 11AD;D0FE;1110 1163 11AD; # (탾; 탾; 탾; 탾; 탾; ) HANGUL SYLLABLE TYANH +D0FF;D0FF;1110 1163 11AE;D0FF;1110 1163 11AE; # (탿; 탿; 탿; 탿; 탿; ) HANGUL SYLLABLE TYAD +D100;D100;1110 1163 11AF;D100;1110 1163 11AF; # (턀; 턀; 턀; 턀; 턀; ) HANGUL SYLLABLE TYAL +D101;D101;1110 1163 11B0;D101;1110 1163 11B0; # (턁; 턁; 턁; 턁; 턁; ) HANGUL SYLLABLE TYALG +D102;D102;1110 1163 11B1;D102;1110 1163 11B1; # (턂; 턂; 턂; 턂; 턂; ) HANGUL SYLLABLE TYALM +D103;D103;1110 1163 11B2;D103;1110 1163 11B2; # (턃; 턃; 턃; 턃; 턃; ) HANGUL SYLLABLE TYALB +D104;D104;1110 1163 11B3;D104;1110 1163 11B3; # (턄; 턄; 턄; 턄; 턄; ) HANGUL SYLLABLE TYALS +D105;D105;1110 1163 11B4;D105;1110 1163 11B4; # (턅; 턅; 턅; 턅; 턅; ) HANGUL SYLLABLE TYALT +D106;D106;1110 1163 11B5;D106;1110 1163 11B5; # (턆; 턆; 턆; 턆; 턆; ) HANGUL SYLLABLE TYALP +D107;D107;1110 1163 11B6;D107;1110 1163 11B6; # (턇; 턇; 턇; 턇; 턇; ) HANGUL SYLLABLE TYALH +D108;D108;1110 1163 11B7;D108;1110 1163 11B7; # (턈; 턈; 턈; 턈; 턈; ) HANGUL SYLLABLE TYAM +D109;D109;1110 1163 11B8;D109;1110 1163 11B8; # (턉; 턉; 턉; 턉; 턉; ) HANGUL SYLLABLE TYAB +D10A;D10A;1110 1163 11B9;D10A;1110 1163 11B9; # (턊; 턊; 턊; 턊; 턊; ) HANGUL SYLLABLE TYABS +D10B;D10B;1110 1163 11BA;D10B;1110 1163 11BA; # (턋; 턋; 턋; 턋; 턋; ) HANGUL SYLLABLE TYAS +D10C;D10C;1110 1163 11BB;D10C;1110 1163 11BB; # (턌; 턌; 턌; 턌; 턌; ) HANGUL SYLLABLE TYASS +D10D;D10D;1110 1163 11BC;D10D;1110 1163 11BC; # (턍; 턍; 턍; 턍; 턍; ) HANGUL SYLLABLE TYANG +D10E;D10E;1110 1163 11BD;D10E;1110 1163 11BD; # (턎; 턎; 턎; 턎; 턎; ) HANGUL SYLLABLE TYAJ +D10F;D10F;1110 1163 11BE;D10F;1110 1163 11BE; # (턏; 턏; 턏; 턏; 턏; ) HANGUL SYLLABLE TYAC +D110;D110;1110 1163 11BF;D110;1110 1163 11BF; # (턐; 턐; 턐; 턐; 턐; ) HANGUL SYLLABLE TYAK +D111;D111;1110 1163 11C0;D111;1110 1163 11C0; # (턑; 턑; 턑; 턑; 턑; ) HANGUL SYLLABLE TYAT +D112;D112;1110 1163 11C1;D112;1110 1163 11C1; # (턒; 턒; 턒; 턒; 턒; ) HANGUL SYLLABLE TYAP +D113;D113;1110 1163 11C2;D113;1110 1163 11C2; # (턓; 턓; 턓; 턓; 턓; ) HANGUL SYLLABLE TYAH +D114;D114;1110 1164;D114;1110 1164; # (턔; 턔; 턔; 턔; 턔; ) HANGUL SYLLABLE TYAE +D115;D115;1110 1164 11A8;D115;1110 1164 11A8; # (턕; 턕; 턕; 턕; 턕; ) HANGUL SYLLABLE TYAEG +D116;D116;1110 1164 11A9;D116;1110 1164 11A9; # (턖; 턖; 턖; 턖; 턖; ) HANGUL SYLLABLE TYAEGG +D117;D117;1110 1164 11AA;D117;1110 1164 11AA; # (턗; 턗; 턗; 턗; 턗; ) HANGUL SYLLABLE TYAEGS +D118;D118;1110 1164 11AB;D118;1110 1164 11AB; # (턘; 턘; 턘; 턘; 턘; ) HANGUL SYLLABLE TYAEN +D119;D119;1110 1164 11AC;D119;1110 1164 11AC; # (턙; 턙; 턙; 턙; 턙; ) HANGUL SYLLABLE TYAENJ +D11A;D11A;1110 1164 11AD;D11A;1110 1164 11AD; # (턚; 턚; 턚; 턚; 턚; ) HANGUL SYLLABLE TYAENH +D11B;D11B;1110 1164 11AE;D11B;1110 1164 11AE; # (턛; 턛; 턛; 턛; 턛; ) HANGUL SYLLABLE TYAED +D11C;D11C;1110 1164 11AF;D11C;1110 1164 11AF; # (턜; 턜; 턜; 턜; 턜; ) HANGUL SYLLABLE TYAEL +D11D;D11D;1110 1164 11B0;D11D;1110 1164 11B0; # (턝; 턝; 턝; 턝; 턝; ) HANGUL SYLLABLE TYAELG +D11E;D11E;1110 1164 11B1;D11E;1110 1164 11B1; # (턞; 턞; 턞; 턞; 턞; ) HANGUL SYLLABLE TYAELM +D11F;D11F;1110 1164 11B2;D11F;1110 1164 11B2; # (턟; 턟; 턟; 턟; 턟; ) HANGUL SYLLABLE TYAELB +D120;D120;1110 1164 11B3;D120;1110 1164 11B3; # (턠; 턠; 턠; 턠; 턠; ) HANGUL SYLLABLE TYAELS +D121;D121;1110 1164 11B4;D121;1110 1164 11B4; # (턡; 턡; 턡; 턡; 턡; ) HANGUL SYLLABLE TYAELT +D122;D122;1110 1164 11B5;D122;1110 1164 11B5; # (턢; 턢; 턢; 턢; 턢; ) HANGUL SYLLABLE TYAELP +D123;D123;1110 1164 11B6;D123;1110 1164 11B6; # (턣; 턣; 턣; 턣; 턣; ) HANGUL SYLLABLE TYAELH +D124;D124;1110 1164 11B7;D124;1110 1164 11B7; # (턤; 턤; 턤; 턤; 턤; ) HANGUL SYLLABLE TYAEM +D125;D125;1110 1164 11B8;D125;1110 1164 11B8; # (턥; 턥; 턥; 턥; 턥; ) HANGUL SYLLABLE TYAEB +D126;D126;1110 1164 11B9;D126;1110 1164 11B9; # (턦; 턦; 턦; 턦; 턦; ) HANGUL SYLLABLE TYAEBS +D127;D127;1110 1164 11BA;D127;1110 1164 11BA; # (턧; 턧; 턧; 턧; 턧; ) HANGUL SYLLABLE TYAES +D128;D128;1110 1164 11BB;D128;1110 1164 11BB; # (턨; 턨; 턨; 턨; 턨; ) HANGUL SYLLABLE TYAESS +D129;D129;1110 1164 11BC;D129;1110 1164 11BC; # (턩; 턩; 턩; 턩; 턩; ) HANGUL SYLLABLE TYAENG +D12A;D12A;1110 1164 11BD;D12A;1110 1164 11BD; # (턪; 턪; 턪; 턪; 턪; ) HANGUL SYLLABLE TYAEJ +D12B;D12B;1110 1164 11BE;D12B;1110 1164 11BE; # (턫; 턫; 턫; 턫; 턫; ) HANGUL SYLLABLE TYAEC +D12C;D12C;1110 1164 11BF;D12C;1110 1164 11BF; # (턬; 턬; 턬; 턬; 턬; ) HANGUL SYLLABLE TYAEK +D12D;D12D;1110 1164 11C0;D12D;1110 1164 11C0; # (턭; 턭; 턭; 턭; 턭; ) HANGUL SYLLABLE TYAET +D12E;D12E;1110 1164 11C1;D12E;1110 1164 11C1; # (턮; 턮; 턮; 턮; 턮; ) HANGUL SYLLABLE TYAEP +D12F;D12F;1110 1164 11C2;D12F;1110 1164 11C2; # (턯; 턯; 턯; 턯; 턯; ) HANGUL SYLLABLE TYAEH +D130;D130;1110 1165;D130;1110 1165; # (터; 터; 터; 터; 터; ) HANGUL SYLLABLE TEO +D131;D131;1110 1165 11A8;D131;1110 1165 11A8; # (턱; 턱; 턱; 턱; 턱; ) HANGUL SYLLABLE TEOG +D132;D132;1110 1165 11A9;D132;1110 1165 11A9; # (턲; 턲; 턲; 턲; 턲; ) HANGUL SYLLABLE TEOGG +D133;D133;1110 1165 11AA;D133;1110 1165 11AA; # (턳; 턳; 턳; 턳; 턳; ) HANGUL SYLLABLE TEOGS +D134;D134;1110 1165 11AB;D134;1110 1165 11AB; # (턴; 턴; 턴; 턴; 턴; ) HANGUL SYLLABLE TEON +D135;D135;1110 1165 11AC;D135;1110 1165 11AC; # (턵; 턵; 턵; 턵; 턵; ) HANGUL SYLLABLE TEONJ +D136;D136;1110 1165 11AD;D136;1110 1165 11AD; # (턶; 턶; 턶; 턶; 턶; ) HANGUL SYLLABLE TEONH +D137;D137;1110 1165 11AE;D137;1110 1165 11AE; # (턷; 턷; 턷; 턷; 턷; ) HANGUL SYLLABLE TEOD +D138;D138;1110 1165 11AF;D138;1110 1165 11AF; # (털; 털; 털; 털; 털; ) HANGUL SYLLABLE TEOL +D139;D139;1110 1165 11B0;D139;1110 1165 11B0; # (턹; 턹; 턹; 턹; 턹; ) HANGUL SYLLABLE TEOLG +D13A;D13A;1110 1165 11B1;D13A;1110 1165 11B1; # (턺; 턺; 턺; 턺; 턺; ) HANGUL SYLLABLE TEOLM +D13B;D13B;1110 1165 11B2;D13B;1110 1165 11B2; # (턻; 턻; 턻; 턻; 턻; ) HANGUL SYLLABLE TEOLB +D13C;D13C;1110 1165 11B3;D13C;1110 1165 11B3; # (턼; 턼; 턼; 턼; 턼; ) HANGUL SYLLABLE TEOLS +D13D;D13D;1110 1165 11B4;D13D;1110 1165 11B4; # (턽; 턽; 턽; 턽; 턽; ) HANGUL SYLLABLE TEOLT +D13E;D13E;1110 1165 11B5;D13E;1110 1165 11B5; # (턾; 턾; 턾; 턾; 턾; ) HANGUL SYLLABLE TEOLP +D13F;D13F;1110 1165 11B6;D13F;1110 1165 11B6; # (턿; 턿; 턿; 턿; 턿; ) HANGUL SYLLABLE TEOLH +D140;D140;1110 1165 11B7;D140;1110 1165 11B7; # (텀; 텀; 텀; 텀; 텀; ) HANGUL SYLLABLE TEOM +D141;D141;1110 1165 11B8;D141;1110 1165 11B8; # (텁; 텁; 텁; 텁; 텁; ) HANGUL SYLLABLE TEOB +D142;D142;1110 1165 11B9;D142;1110 1165 11B9; # (텂; 텂; 텂; 텂; 텂; ) HANGUL SYLLABLE TEOBS +D143;D143;1110 1165 11BA;D143;1110 1165 11BA; # (텃; 텃; 텃; 텃; 텃; ) HANGUL SYLLABLE TEOS +D144;D144;1110 1165 11BB;D144;1110 1165 11BB; # (텄; 텄; 텄; 텄; 텄; ) HANGUL SYLLABLE TEOSS +D145;D145;1110 1165 11BC;D145;1110 1165 11BC; # (텅; 텅; 텅; 텅; 텅; ) HANGUL SYLLABLE TEONG +D146;D146;1110 1165 11BD;D146;1110 1165 11BD; # (텆; 텆; 텆; 텆; 텆; ) HANGUL SYLLABLE TEOJ +D147;D147;1110 1165 11BE;D147;1110 1165 11BE; # (텇; 텇; 텇; 텇; 텇; ) HANGUL SYLLABLE TEOC +D148;D148;1110 1165 11BF;D148;1110 1165 11BF; # (텈; 텈; 텈; 텈; 텈; ) HANGUL SYLLABLE TEOK +D149;D149;1110 1165 11C0;D149;1110 1165 11C0; # (텉; 텉; 텉; 텉; 텉; ) HANGUL SYLLABLE TEOT +D14A;D14A;1110 1165 11C1;D14A;1110 1165 11C1; # (텊; 텊; 텊; 텊; 텊; ) HANGUL SYLLABLE TEOP +D14B;D14B;1110 1165 11C2;D14B;1110 1165 11C2; # (텋; 텋; 텋; 텋; 텋; ) HANGUL SYLLABLE TEOH +D14C;D14C;1110 1166;D14C;1110 1166; # (테; 테; 테; 테; 테; ) HANGUL SYLLABLE TE +D14D;D14D;1110 1166 11A8;D14D;1110 1166 11A8; # (텍; 텍; 텍; 텍; 텍; ) HANGUL SYLLABLE TEG +D14E;D14E;1110 1166 11A9;D14E;1110 1166 11A9; # (텎; 텎; 텎; 텎; 텎; ) HANGUL SYLLABLE TEGG +D14F;D14F;1110 1166 11AA;D14F;1110 1166 11AA; # (텏; 텏; 텏; 텏; 텏; ) HANGUL SYLLABLE TEGS +D150;D150;1110 1166 11AB;D150;1110 1166 11AB; # (텐; 텐; 텐; 텐; 텐; ) HANGUL SYLLABLE TEN +D151;D151;1110 1166 11AC;D151;1110 1166 11AC; # (텑; 텑; 텑; 텑; 텑; ) HANGUL SYLLABLE TENJ +D152;D152;1110 1166 11AD;D152;1110 1166 11AD; # (텒; 텒; 텒; 텒; 텒; ) HANGUL SYLLABLE TENH +D153;D153;1110 1166 11AE;D153;1110 1166 11AE; # (텓; 텓; 텓; 텓; 텓; ) HANGUL SYLLABLE TED +D154;D154;1110 1166 11AF;D154;1110 1166 11AF; # (텔; 텔; 텔; 텔; 텔; ) HANGUL SYLLABLE TEL +D155;D155;1110 1166 11B0;D155;1110 1166 11B0; # (텕; 텕; 텕; 텕; 텕; ) HANGUL SYLLABLE TELG +D156;D156;1110 1166 11B1;D156;1110 1166 11B1; # (텖; 텖; 텖; 텖; 텖; ) HANGUL SYLLABLE TELM +D157;D157;1110 1166 11B2;D157;1110 1166 11B2; # (텗; 텗; 텗; 텗; 텗; ) HANGUL SYLLABLE TELB +D158;D158;1110 1166 11B3;D158;1110 1166 11B3; # (텘; 텘; 텘; 텘; 텘; ) HANGUL SYLLABLE TELS +D159;D159;1110 1166 11B4;D159;1110 1166 11B4; # (텙; 텙; 텙; 텙; 텙; ) HANGUL SYLLABLE TELT +D15A;D15A;1110 1166 11B5;D15A;1110 1166 11B5; # (텚; 텚; 텚; 텚; 텚; ) HANGUL SYLLABLE TELP +D15B;D15B;1110 1166 11B6;D15B;1110 1166 11B6; # (텛; 텛; 텛; 텛; 텛; ) HANGUL SYLLABLE TELH +D15C;D15C;1110 1166 11B7;D15C;1110 1166 11B7; # (템; 템; 템; 템; 템; ) HANGUL SYLLABLE TEM +D15D;D15D;1110 1166 11B8;D15D;1110 1166 11B8; # (텝; 텝; 텝; 텝; 텝; ) HANGUL SYLLABLE TEB +D15E;D15E;1110 1166 11B9;D15E;1110 1166 11B9; # (텞; 텞; 텞; 텞; 텞; ) HANGUL SYLLABLE TEBS +D15F;D15F;1110 1166 11BA;D15F;1110 1166 11BA; # (텟; 텟; 텟; 텟; 텟; ) HANGUL SYLLABLE TES +D160;D160;1110 1166 11BB;D160;1110 1166 11BB; # (텠; 텠; 텠; 텠; 텠; ) HANGUL SYLLABLE TESS +D161;D161;1110 1166 11BC;D161;1110 1166 11BC; # (텡; 텡; 텡; 텡; 텡; ) HANGUL SYLLABLE TENG +D162;D162;1110 1166 11BD;D162;1110 1166 11BD; # (텢; 텢; 텢; 텢; 텢; ) HANGUL SYLLABLE TEJ +D163;D163;1110 1166 11BE;D163;1110 1166 11BE; # (텣; 텣; 텣; 텣; 텣; ) HANGUL SYLLABLE TEC +D164;D164;1110 1166 11BF;D164;1110 1166 11BF; # (텤; 텤; 텤; 텤; 텤; ) HANGUL SYLLABLE TEK +D165;D165;1110 1166 11C0;D165;1110 1166 11C0; # (텥; 텥; 텥; 텥; 텥; ) HANGUL SYLLABLE TET +D166;D166;1110 1166 11C1;D166;1110 1166 11C1; # (텦; 텦; 텦; 텦; 텦; ) HANGUL SYLLABLE TEP +D167;D167;1110 1166 11C2;D167;1110 1166 11C2; # (텧; 텧; 텧; 텧; 텧; ) HANGUL SYLLABLE TEH +D168;D168;1110 1167;D168;1110 1167; # (텨; 텨; 텨; 텨; 텨; ) HANGUL SYLLABLE TYEO +D169;D169;1110 1167 11A8;D169;1110 1167 11A8; # (텩; 텩; 텩; 텩; 텩; ) HANGUL SYLLABLE TYEOG +D16A;D16A;1110 1167 11A9;D16A;1110 1167 11A9; # (텪; 텪; 텪; 텪; 텪; ) HANGUL SYLLABLE TYEOGG +D16B;D16B;1110 1167 11AA;D16B;1110 1167 11AA; # (텫; 텫; 텫; 텫; 텫; ) HANGUL SYLLABLE TYEOGS +D16C;D16C;1110 1167 11AB;D16C;1110 1167 11AB; # (텬; 텬; 텬; 텬; 텬; ) HANGUL SYLLABLE TYEON +D16D;D16D;1110 1167 11AC;D16D;1110 1167 11AC; # (텭; 텭; 텭; 텭; 텭; ) HANGUL SYLLABLE TYEONJ +D16E;D16E;1110 1167 11AD;D16E;1110 1167 11AD; # (텮; 텮; 텮; 텮; 텮; ) HANGUL SYLLABLE TYEONH +D16F;D16F;1110 1167 11AE;D16F;1110 1167 11AE; # (텯; 텯; 텯; 텯; 텯; ) HANGUL SYLLABLE TYEOD +D170;D170;1110 1167 11AF;D170;1110 1167 11AF; # (텰; 텰; 텰; 텰; 텰; ) HANGUL SYLLABLE TYEOL +D171;D171;1110 1167 11B0;D171;1110 1167 11B0; # (텱; 텱; 텱; 텱; 텱; ) HANGUL SYLLABLE TYEOLG +D172;D172;1110 1167 11B1;D172;1110 1167 11B1; # (텲; 텲; 텲; 텲; 텲; ) HANGUL SYLLABLE TYEOLM +D173;D173;1110 1167 11B2;D173;1110 1167 11B2; # (텳; 텳; 텳; 텳; 텳; ) HANGUL SYLLABLE TYEOLB +D174;D174;1110 1167 11B3;D174;1110 1167 11B3; # (텴; 텴; 텴; 텴; 텴; ) HANGUL SYLLABLE TYEOLS +D175;D175;1110 1167 11B4;D175;1110 1167 11B4; # (텵; 텵; 텵; 텵; 텵; ) HANGUL SYLLABLE TYEOLT +D176;D176;1110 1167 11B5;D176;1110 1167 11B5; # (텶; 텶; 텶; 텶; 텶; ) HANGUL SYLLABLE TYEOLP +D177;D177;1110 1167 11B6;D177;1110 1167 11B6; # (텷; 텷; 텷; 텷; 텷; ) HANGUL SYLLABLE TYEOLH +D178;D178;1110 1167 11B7;D178;1110 1167 11B7; # (텸; 텸; 텸; 텸; 텸; ) HANGUL SYLLABLE TYEOM +D179;D179;1110 1167 11B8;D179;1110 1167 11B8; # (텹; 텹; 텹; 텹; 텹; ) HANGUL SYLLABLE TYEOB +D17A;D17A;1110 1167 11B9;D17A;1110 1167 11B9; # (텺; 텺; 텺; 텺; 텺; ) HANGUL SYLLABLE TYEOBS +D17B;D17B;1110 1167 11BA;D17B;1110 1167 11BA; # (텻; 텻; 텻; 텻; 텻; ) HANGUL SYLLABLE TYEOS +D17C;D17C;1110 1167 11BB;D17C;1110 1167 11BB; # (텼; 텼; 텼; 텼; 텼; ) HANGUL SYLLABLE TYEOSS +D17D;D17D;1110 1167 11BC;D17D;1110 1167 11BC; # (텽; 텽; 텽; 텽; 텽; ) HANGUL SYLLABLE TYEONG +D17E;D17E;1110 1167 11BD;D17E;1110 1167 11BD; # (텾; 텾; 텾; 텾; 텾; ) HANGUL SYLLABLE TYEOJ +D17F;D17F;1110 1167 11BE;D17F;1110 1167 11BE; # (텿; 텿; 텿; 텿; 텿; ) HANGUL SYLLABLE TYEOC +D180;D180;1110 1167 11BF;D180;1110 1167 11BF; # (톀; 톀; 톀; 톀; 톀; ) HANGUL SYLLABLE TYEOK +D181;D181;1110 1167 11C0;D181;1110 1167 11C0; # (톁; 톁; 톁; 톁; 톁; ) HANGUL SYLLABLE TYEOT +D182;D182;1110 1167 11C1;D182;1110 1167 11C1; # (톂; 톂; 톂; 톂; 톂; ) HANGUL SYLLABLE TYEOP +D183;D183;1110 1167 11C2;D183;1110 1167 11C2; # (톃; 톃; 톃; 톃; 톃; ) HANGUL SYLLABLE TYEOH +D184;D184;1110 1168;D184;1110 1168; # (톄; 톄; 톄; 톄; 톄; ) HANGUL SYLLABLE TYE +D185;D185;1110 1168 11A8;D185;1110 1168 11A8; # (톅; 톅; 톅; 톅; 톅; ) HANGUL SYLLABLE TYEG +D186;D186;1110 1168 11A9;D186;1110 1168 11A9; # (톆; 톆; 톆; 톆; 톆; ) HANGUL SYLLABLE TYEGG +D187;D187;1110 1168 11AA;D187;1110 1168 11AA; # (톇; 톇; 톇; 톇; 톇; ) HANGUL SYLLABLE TYEGS +D188;D188;1110 1168 11AB;D188;1110 1168 11AB; # (톈; 톈; 톈; 톈; 톈; ) HANGUL SYLLABLE TYEN +D189;D189;1110 1168 11AC;D189;1110 1168 11AC; # (톉; 톉; 톉; 톉; 톉; ) HANGUL SYLLABLE TYENJ +D18A;D18A;1110 1168 11AD;D18A;1110 1168 11AD; # (톊; 톊; 톊; 톊; 톊; ) HANGUL SYLLABLE TYENH +D18B;D18B;1110 1168 11AE;D18B;1110 1168 11AE; # (톋; 톋; 톋; 톋; 톋; ) HANGUL SYLLABLE TYED +D18C;D18C;1110 1168 11AF;D18C;1110 1168 11AF; # (톌; 톌; 톌; 톌; 톌; ) HANGUL SYLLABLE TYEL +D18D;D18D;1110 1168 11B0;D18D;1110 1168 11B0; # (톍; 톍; 톍; 톍; 톍; ) HANGUL SYLLABLE TYELG +D18E;D18E;1110 1168 11B1;D18E;1110 1168 11B1; # (톎; 톎; 톎; 톎; 톎; ) HANGUL SYLLABLE TYELM +D18F;D18F;1110 1168 11B2;D18F;1110 1168 11B2; # (톏; 톏; 톏; 톏; 톏; ) HANGUL SYLLABLE TYELB +D190;D190;1110 1168 11B3;D190;1110 1168 11B3; # (톐; 톐; 톐; 톐; 톐; ) HANGUL SYLLABLE TYELS +D191;D191;1110 1168 11B4;D191;1110 1168 11B4; # (톑; 톑; 톑; 톑; 톑; ) HANGUL SYLLABLE TYELT +D192;D192;1110 1168 11B5;D192;1110 1168 11B5; # (톒; 톒; 톒; 톒; 톒; ) HANGUL SYLLABLE TYELP +D193;D193;1110 1168 11B6;D193;1110 1168 11B6; # (톓; 톓; 톓; 톓; 톓; ) HANGUL SYLLABLE TYELH +D194;D194;1110 1168 11B7;D194;1110 1168 11B7; # (톔; 톔; 톔; 톔; 톔; ) HANGUL SYLLABLE TYEM +D195;D195;1110 1168 11B8;D195;1110 1168 11B8; # (톕; 톕; 톕; 톕; 톕; ) HANGUL SYLLABLE TYEB +D196;D196;1110 1168 11B9;D196;1110 1168 11B9; # (톖; 톖; 톖; 톖; 톖; ) HANGUL SYLLABLE TYEBS +D197;D197;1110 1168 11BA;D197;1110 1168 11BA; # (톗; 톗; 톗; 톗; 톗; ) HANGUL SYLLABLE TYES +D198;D198;1110 1168 11BB;D198;1110 1168 11BB; # (톘; 톘; 톘; 톘; 톘; ) HANGUL SYLLABLE TYESS +D199;D199;1110 1168 11BC;D199;1110 1168 11BC; # (톙; 톙; 톙; 톙; 톙; ) HANGUL SYLLABLE TYENG +D19A;D19A;1110 1168 11BD;D19A;1110 1168 11BD; # (톚; 톚; 톚; 톚; 톚; ) HANGUL SYLLABLE TYEJ +D19B;D19B;1110 1168 11BE;D19B;1110 1168 11BE; # (톛; 톛; 톛; 톛; 톛; ) HANGUL SYLLABLE TYEC +D19C;D19C;1110 1168 11BF;D19C;1110 1168 11BF; # (톜; 톜; 톜; 톜; 톜; ) HANGUL SYLLABLE TYEK +D19D;D19D;1110 1168 11C0;D19D;1110 1168 11C0; # (톝; 톝; 톝; 톝; 톝; ) HANGUL SYLLABLE TYET +D19E;D19E;1110 1168 11C1;D19E;1110 1168 11C1; # (톞; 톞; 톞; 톞; 톞; ) HANGUL SYLLABLE TYEP +D19F;D19F;1110 1168 11C2;D19F;1110 1168 11C2; # (톟; 톟; 톟; 톟; 톟; ) HANGUL SYLLABLE TYEH +D1A0;D1A0;1110 1169;D1A0;1110 1169; # (토; 토; 토; 토; 토; ) HANGUL SYLLABLE TO +D1A1;D1A1;1110 1169 11A8;D1A1;1110 1169 11A8; # (톡; 톡; 톡; 톡; 톡; ) HANGUL SYLLABLE TOG +D1A2;D1A2;1110 1169 11A9;D1A2;1110 1169 11A9; # (톢; 톢; 톢; 톢; 톢; ) HANGUL SYLLABLE TOGG +D1A3;D1A3;1110 1169 11AA;D1A3;1110 1169 11AA; # (톣; 톣; 톣; 톣; 톣; ) HANGUL SYLLABLE TOGS +D1A4;D1A4;1110 1169 11AB;D1A4;1110 1169 11AB; # (톤; 톤; 톤; 톤; 톤; ) HANGUL SYLLABLE TON +D1A5;D1A5;1110 1169 11AC;D1A5;1110 1169 11AC; # (톥; 톥; 톥; 톥; 톥; ) HANGUL SYLLABLE TONJ +D1A6;D1A6;1110 1169 11AD;D1A6;1110 1169 11AD; # (톦; 톦; 톦; 톦; 톦; ) HANGUL SYLLABLE TONH +D1A7;D1A7;1110 1169 11AE;D1A7;1110 1169 11AE; # (톧; 톧; 톧; 톧; 톧; ) HANGUL SYLLABLE TOD +D1A8;D1A8;1110 1169 11AF;D1A8;1110 1169 11AF; # (톨; 톨; 톨; 톨; 톨; ) HANGUL SYLLABLE TOL +D1A9;D1A9;1110 1169 11B0;D1A9;1110 1169 11B0; # (톩; 톩; 톩; 톩; 톩; ) HANGUL SYLLABLE TOLG +D1AA;D1AA;1110 1169 11B1;D1AA;1110 1169 11B1; # (톪; 톪; 톪; 톪; 톪; ) HANGUL SYLLABLE TOLM +D1AB;D1AB;1110 1169 11B2;D1AB;1110 1169 11B2; # (톫; 톫; 톫; 톫; 톫; ) HANGUL SYLLABLE TOLB +D1AC;D1AC;1110 1169 11B3;D1AC;1110 1169 11B3; # (톬; 톬; 톬; 톬; 톬; ) HANGUL SYLLABLE TOLS +D1AD;D1AD;1110 1169 11B4;D1AD;1110 1169 11B4; # (톭; 톭; 톭; 톭; 톭; ) HANGUL SYLLABLE TOLT +D1AE;D1AE;1110 1169 11B5;D1AE;1110 1169 11B5; # (톮; 톮; 톮; 톮; 톮; ) HANGUL SYLLABLE TOLP +D1AF;D1AF;1110 1169 11B6;D1AF;1110 1169 11B6; # (톯; 톯; 톯; 톯; 톯; ) HANGUL SYLLABLE TOLH +D1B0;D1B0;1110 1169 11B7;D1B0;1110 1169 11B7; # (톰; 톰; 톰; 톰; 톰; ) HANGUL SYLLABLE TOM +D1B1;D1B1;1110 1169 11B8;D1B1;1110 1169 11B8; # (톱; 톱; 톱; 톱; 톱; ) HANGUL SYLLABLE TOB +D1B2;D1B2;1110 1169 11B9;D1B2;1110 1169 11B9; # (톲; 톲; 톲; 톲; 톲; ) HANGUL SYLLABLE TOBS +D1B3;D1B3;1110 1169 11BA;D1B3;1110 1169 11BA; # (톳; 톳; 톳; 톳; 톳; ) HANGUL SYLLABLE TOS +D1B4;D1B4;1110 1169 11BB;D1B4;1110 1169 11BB; # (톴; 톴; 톴; 톴; 톴; ) HANGUL SYLLABLE TOSS +D1B5;D1B5;1110 1169 11BC;D1B5;1110 1169 11BC; # (통; 통; 통; 통; 통; ) HANGUL SYLLABLE TONG +D1B6;D1B6;1110 1169 11BD;D1B6;1110 1169 11BD; # (톶; 톶; 톶; 톶; 톶; ) HANGUL SYLLABLE TOJ +D1B7;D1B7;1110 1169 11BE;D1B7;1110 1169 11BE; # (톷; 톷; 톷; 톷; 톷; ) HANGUL SYLLABLE TOC +D1B8;D1B8;1110 1169 11BF;D1B8;1110 1169 11BF; # (톸; 톸; 톸; 톸; 톸; ) HANGUL SYLLABLE TOK +D1B9;D1B9;1110 1169 11C0;D1B9;1110 1169 11C0; # (톹; 톹; 톹; 톹; 톹; ) HANGUL SYLLABLE TOT +D1BA;D1BA;1110 1169 11C1;D1BA;1110 1169 11C1; # (톺; 톺; 톺; 톺; 톺; ) HANGUL SYLLABLE TOP +D1BB;D1BB;1110 1169 11C2;D1BB;1110 1169 11C2; # (톻; 톻; 톻; 톻; 톻; ) HANGUL SYLLABLE TOH +D1BC;D1BC;1110 116A;D1BC;1110 116A; # (톼; 톼; 톼; 톼; 톼; ) HANGUL SYLLABLE TWA +D1BD;D1BD;1110 116A 11A8;D1BD;1110 116A 11A8; # (톽; 톽; 톽; 톽; 톽; ) HANGUL SYLLABLE TWAG +D1BE;D1BE;1110 116A 11A9;D1BE;1110 116A 11A9; # (톾; 톾; 톾; 톾; 톾; ) HANGUL SYLLABLE TWAGG +D1BF;D1BF;1110 116A 11AA;D1BF;1110 116A 11AA; # (톿; 톿; 톿; 톿; 톿; ) HANGUL SYLLABLE TWAGS +D1C0;D1C0;1110 116A 11AB;D1C0;1110 116A 11AB; # (퇀; 퇀; 퇀; 퇀; 퇀; ) HANGUL SYLLABLE TWAN +D1C1;D1C1;1110 116A 11AC;D1C1;1110 116A 11AC; # (퇁; 퇁; 퇁; 퇁; 퇁; ) HANGUL SYLLABLE TWANJ +D1C2;D1C2;1110 116A 11AD;D1C2;1110 116A 11AD; # (퇂; 퇂; 퇂; 퇂; 퇂; ) HANGUL SYLLABLE TWANH +D1C3;D1C3;1110 116A 11AE;D1C3;1110 116A 11AE; # (퇃; 퇃; 퇃; 퇃; 퇃; ) HANGUL SYLLABLE TWAD +D1C4;D1C4;1110 116A 11AF;D1C4;1110 116A 11AF; # (퇄; 퇄; 퇄; 퇄; 퇄; ) HANGUL SYLLABLE TWAL +D1C5;D1C5;1110 116A 11B0;D1C5;1110 116A 11B0; # (퇅; 퇅; 퇅; 퇅; 퇅; ) HANGUL SYLLABLE TWALG +D1C6;D1C6;1110 116A 11B1;D1C6;1110 116A 11B1; # (퇆; 퇆; 퇆; 퇆; 퇆; ) HANGUL SYLLABLE TWALM +D1C7;D1C7;1110 116A 11B2;D1C7;1110 116A 11B2; # (퇇; 퇇; 퇇; 퇇; 퇇; ) HANGUL SYLLABLE TWALB +D1C8;D1C8;1110 116A 11B3;D1C8;1110 116A 11B3; # (퇈; 퇈; 퇈; 퇈; 퇈; ) HANGUL SYLLABLE TWALS +D1C9;D1C9;1110 116A 11B4;D1C9;1110 116A 11B4; # (퇉; 퇉; 퇉; 퇉; 퇉; ) HANGUL SYLLABLE TWALT +D1CA;D1CA;1110 116A 11B5;D1CA;1110 116A 11B5; # (퇊; 퇊; 퇊; 퇊; 퇊; ) HANGUL SYLLABLE TWALP +D1CB;D1CB;1110 116A 11B6;D1CB;1110 116A 11B6; # (퇋; 퇋; 퇋; 퇋; 퇋; ) HANGUL SYLLABLE TWALH +D1CC;D1CC;1110 116A 11B7;D1CC;1110 116A 11B7; # (퇌; 퇌; 퇌; 퇌; 퇌; ) HANGUL SYLLABLE TWAM +D1CD;D1CD;1110 116A 11B8;D1CD;1110 116A 11B8; # (퇍; 퇍; 퇍; 퇍; 퇍; ) HANGUL SYLLABLE TWAB +D1CE;D1CE;1110 116A 11B9;D1CE;1110 116A 11B9; # (퇎; 퇎; 퇎; 퇎; 퇎; ) HANGUL SYLLABLE TWABS +D1CF;D1CF;1110 116A 11BA;D1CF;1110 116A 11BA; # (퇏; 퇏; 퇏; 퇏; 퇏; ) HANGUL SYLLABLE TWAS +D1D0;D1D0;1110 116A 11BB;D1D0;1110 116A 11BB; # (퇐; 퇐; 퇐; 퇐; 퇐; ) HANGUL SYLLABLE TWASS +D1D1;D1D1;1110 116A 11BC;D1D1;1110 116A 11BC; # (퇑; 퇑; 퇑; 퇑; 퇑; ) HANGUL SYLLABLE TWANG +D1D2;D1D2;1110 116A 11BD;D1D2;1110 116A 11BD; # (퇒; 퇒; 퇒; 퇒; 퇒; ) HANGUL SYLLABLE TWAJ +D1D3;D1D3;1110 116A 11BE;D1D3;1110 116A 11BE; # (퇓; 퇓; 퇓; 퇓; 퇓; ) HANGUL SYLLABLE TWAC +D1D4;D1D4;1110 116A 11BF;D1D4;1110 116A 11BF; # (퇔; 퇔; 퇔; 퇔; 퇔; ) HANGUL SYLLABLE TWAK +D1D5;D1D5;1110 116A 11C0;D1D5;1110 116A 11C0; # (퇕; 퇕; 퇕; 퇕; 퇕; ) HANGUL SYLLABLE TWAT +D1D6;D1D6;1110 116A 11C1;D1D6;1110 116A 11C1; # (퇖; 퇖; 퇖; 퇖; 퇖; ) HANGUL SYLLABLE TWAP +D1D7;D1D7;1110 116A 11C2;D1D7;1110 116A 11C2; # (퇗; 퇗; 퇗; 퇗; 퇗; ) HANGUL SYLLABLE TWAH +D1D8;D1D8;1110 116B;D1D8;1110 116B; # (퇘; 퇘; 퇘; 퇘; 퇘; ) HANGUL SYLLABLE TWAE +D1D9;D1D9;1110 116B 11A8;D1D9;1110 116B 11A8; # (퇙; 퇙; 퇙; 퇙; 퇙; ) HANGUL SYLLABLE TWAEG +D1DA;D1DA;1110 116B 11A9;D1DA;1110 116B 11A9; # (퇚; 퇚; 퇚; 퇚; 퇚; ) HANGUL SYLLABLE TWAEGG +D1DB;D1DB;1110 116B 11AA;D1DB;1110 116B 11AA; # (퇛; 퇛; 퇛; 퇛; 퇛; ) HANGUL SYLLABLE TWAEGS +D1DC;D1DC;1110 116B 11AB;D1DC;1110 116B 11AB; # (퇜; 퇜; 퇜; 퇜; 퇜; ) HANGUL SYLLABLE TWAEN +D1DD;D1DD;1110 116B 11AC;D1DD;1110 116B 11AC; # (퇝; 퇝; 퇝; 퇝; 퇝; ) HANGUL SYLLABLE TWAENJ +D1DE;D1DE;1110 116B 11AD;D1DE;1110 116B 11AD; # (퇞; 퇞; 퇞; 퇞; 퇞; ) HANGUL SYLLABLE TWAENH +D1DF;D1DF;1110 116B 11AE;D1DF;1110 116B 11AE; # (퇟; 퇟; 퇟; 퇟; 퇟; ) HANGUL SYLLABLE TWAED +D1E0;D1E0;1110 116B 11AF;D1E0;1110 116B 11AF; # (퇠; 퇠; 퇠; 퇠; 퇠; ) HANGUL SYLLABLE TWAEL +D1E1;D1E1;1110 116B 11B0;D1E1;1110 116B 11B0; # (퇡; 퇡; 퇡; 퇡; 퇡; ) HANGUL SYLLABLE TWAELG +D1E2;D1E2;1110 116B 11B1;D1E2;1110 116B 11B1; # (퇢; 퇢; 퇢; 퇢; 퇢; ) HANGUL SYLLABLE TWAELM +D1E3;D1E3;1110 116B 11B2;D1E3;1110 116B 11B2; # (퇣; 퇣; 퇣; 퇣; 퇣; ) HANGUL SYLLABLE TWAELB +D1E4;D1E4;1110 116B 11B3;D1E4;1110 116B 11B3; # (퇤; 퇤; 퇤; 퇤; 퇤; ) HANGUL SYLLABLE TWAELS +D1E5;D1E5;1110 116B 11B4;D1E5;1110 116B 11B4; # (퇥; 퇥; 퇥; 퇥; 퇥; ) HANGUL SYLLABLE TWAELT +D1E6;D1E6;1110 116B 11B5;D1E6;1110 116B 11B5; # (퇦; 퇦; 퇦; 퇦; 퇦; ) HANGUL SYLLABLE TWAELP +D1E7;D1E7;1110 116B 11B6;D1E7;1110 116B 11B6; # (퇧; 퇧; 퇧; 퇧; 퇧; ) HANGUL SYLLABLE TWAELH +D1E8;D1E8;1110 116B 11B7;D1E8;1110 116B 11B7; # (퇨; 퇨; 퇨; 퇨; 퇨; ) HANGUL SYLLABLE TWAEM +D1E9;D1E9;1110 116B 11B8;D1E9;1110 116B 11B8; # (퇩; 퇩; 퇩; 퇩; 퇩; ) HANGUL SYLLABLE TWAEB +D1EA;D1EA;1110 116B 11B9;D1EA;1110 116B 11B9; # (퇪; 퇪; 퇪; 퇪; 퇪; ) HANGUL SYLLABLE TWAEBS +D1EB;D1EB;1110 116B 11BA;D1EB;1110 116B 11BA; # (퇫; 퇫; 퇫; 퇫; 퇫; ) HANGUL SYLLABLE TWAES +D1EC;D1EC;1110 116B 11BB;D1EC;1110 116B 11BB; # (퇬; 퇬; 퇬; 퇬; 퇬; ) HANGUL SYLLABLE TWAESS +D1ED;D1ED;1110 116B 11BC;D1ED;1110 116B 11BC; # (퇭; 퇭; 퇭; 퇭; 퇭; ) HANGUL SYLLABLE TWAENG +D1EE;D1EE;1110 116B 11BD;D1EE;1110 116B 11BD; # (퇮; 퇮; 퇮; 퇮; 퇮; ) HANGUL SYLLABLE TWAEJ +D1EF;D1EF;1110 116B 11BE;D1EF;1110 116B 11BE; # (퇯; 퇯; 퇯; 퇯; 퇯; ) HANGUL SYLLABLE TWAEC +D1F0;D1F0;1110 116B 11BF;D1F0;1110 116B 11BF; # (퇰; 퇰; 퇰; 퇰; 퇰; ) HANGUL SYLLABLE TWAEK +D1F1;D1F1;1110 116B 11C0;D1F1;1110 116B 11C0; # (퇱; 퇱; 퇱; 퇱; 퇱; ) HANGUL SYLLABLE TWAET +D1F2;D1F2;1110 116B 11C1;D1F2;1110 116B 11C1; # (퇲; 퇲; 퇲; 퇲; 퇲; ) HANGUL SYLLABLE TWAEP +D1F3;D1F3;1110 116B 11C2;D1F3;1110 116B 11C2; # (퇳; 퇳; 퇳; 퇳; 퇳; ) HANGUL SYLLABLE TWAEH +D1F4;D1F4;1110 116C;D1F4;1110 116C; # (퇴; 퇴; 퇴; 퇴; 퇴; ) HANGUL SYLLABLE TOE +D1F5;D1F5;1110 116C 11A8;D1F5;1110 116C 11A8; # (퇵; 퇵; 퇵; 퇵; 퇵; ) HANGUL SYLLABLE TOEG +D1F6;D1F6;1110 116C 11A9;D1F6;1110 116C 11A9; # (퇶; 퇶; 퇶; 퇶; 퇶; ) HANGUL SYLLABLE TOEGG +D1F7;D1F7;1110 116C 11AA;D1F7;1110 116C 11AA; # (퇷; 퇷; 퇷; 퇷; 퇷; ) HANGUL SYLLABLE TOEGS +D1F8;D1F8;1110 116C 11AB;D1F8;1110 116C 11AB; # (퇸; 퇸; 퇸; 퇸; 퇸; ) HANGUL SYLLABLE TOEN +D1F9;D1F9;1110 116C 11AC;D1F9;1110 116C 11AC; # (퇹; 퇹; 퇹; 퇹; 퇹; ) HANGUL SYLLABLE TOENJ +D1FA;D1FA;1110 116C 11AD;D1FA;1110 116C 11AD; # (퇺; 퇺; 퇺; 퇺; 퇺; ) HANGUL SYLLABLE TOENH +D1FB;D1FB;1110 116C 11AE;D1FB;1110 116C 11AE; # (퇻; 퇻; 퇻; 퇻; 퇻; ) HANGUL SYLLABLE TOED +D1FC;D1FC;1110 116C 11AF;D1FC;1110 116C 11AF; # (퇼; 퇼; 퇼; 퇼; 퇼; ) HANGUL SYLLABLE TOEL +D1FD;D1FD;1110 116C 11B0;D1FD;1110 116C 11B0; # (퇽; 퇽; 퇽; 퇽; 퇽; ) HANGUL SYLLABLE TOELG +D1FE;D1FE;1110 116C 11B1;D1FE;1110 116C 11B1; # (퇾; 퇾; 퇾; 퇾; 퇾; ) HANGUL SYLLABLE TOELM +D1FF;D1FF;1110 116C 11B2;D1FF;1110 116C 11B2; # (퇿; 퇿; 퇿; 퇿; 퇿; ) HANGUL SYLLABLE TOELB +D200;D200;1110 116C 11B3;D200;1110 116C 11B3; # (툀; 툀; 툀; 툀; 툀; ) HANGUL SYLLABLE TOELS +D201;D201;1110 116C 11B4;D201;1110 116C 11B4; # (툁; 툁; 툁; 툁; 툁; ) HANGUL SYLLABLE TOELT +D202;D202;1110 116C 11B5;D202;1110 116C 11B5; # (툂; 툂; 툂; 툂; 툂; ) HANGUL SYLLABLE TOELP +D203;D203;1110 116C 11B6;D203;1110 116C 11B6; # (툃; 툃; 툃; 툃; 툃; ) HANGUL SYLLABLE TOELH +D204;D204;1110 116C 11B7;D204;1110 116C 11B7; # (툄; 툄; 툄; 툄; 툄; ) HANGUL SYLLABLE TOEM +D205;D205;1110 116C 11B8;D205;1110 116C 11B8; # (툅; 툅; 툅; 툅; 툅; ) HANGUL SYLLABLE TOEB +D206;D206;1110 116C 11B9;D206;1110 116C 11B9; # (툆; 툆; 툆; 툆; 툆; ) HANGUL SYLLABLE TOEBS +D207;D207;1110 116C 11BA;D207;1110 116C 11BA; # (툇; 툇; 툇; 툇; 툇; ) HANGUL SYLLABLE TOES +D208;D208;1110 116C 11BB;D208;1110 116C 11BB; # (툈; 툈; 툈; 툈; 툈; ) HANGUL SYLLABLE TOESS +D209;D209;1110 116C 11BC;D209;1110 116C 11BC; # (툉; 툉; 툉; 툉; 툉; ) HANGUL SYLLABLE TOENG +D20A;D20A;1110 116C 11BD;D20A;1110 116C 11BD; # (툊; 툊; 툊; 툊; 툊; ) HANGUL SYLLABLE TOEJ +D20B;D20B;1110 116C 11BE;D20B;1110 116C 11BE; # (툋; 툋; 툋; 툋; 툋; ) HANGUL SYLLABLE TOEC +D20C;D20C;1110 116C 11BF;D20C;1110 116C 11BF; # (툌; 툌; 툌; 툌; 툌; ) HANGUL SYLLABLE TOEK +D20D;D20D;1110 116C 11C0;D20D;1110 116C 11C0; # (툍; 툍; 툍; 툍; 툍; ) HANGUL SYLLABLE TOET +D20E;D20E;1110 116C 11C1;D20E;1110 116C 11C1; # (툎; 툎; 툎; 툎; 툎; ) HANGUL SYLLABLE TOEP +D20F;D20F;1110 116C 11C2;D20F;1110 116C 11C2; # (툏; 툏; 툏; 툏; 툏; ) HANGUL SYLLABLE TOEH +D210;D210;1110 116D;D210;1110 116D; # (툐; 툐; 툐; 툐; 툐; ) HANGUL SYLLABLE TYO +D211;D211;1110 116D 11A8;D211;1110 116D 11A8; # (툑; 툑; 툑; 툑; 툑; ) HANGUL SYLLABLE TYOG +D212;D212;1110 116D 11A9;D212;1110 116D 11A9; # (툒; 툒; 툒; 툒; 툒; ) HANGUL SYLLABLE TYOGG +D213;D213;1110 116D 11AA;D213;1110 116D 11AA; # (툓; 툓; 툓; 툓; 툓; ) HANGUL SYLLABLE TYOGS +D214;D214;1110 116D 11AB;D214;1110 116D 11AB; # (툔; 툔; 툔; 툔; 툔; ) HANGUL SYLLABLE TYON +D215;D215;1110 116D 11AC;D215;1110 116D 11AC; # (툕; 툕; 툕; 툕; 툕; ) HANGUL SYLLABLE TYONJ +D216;D216;1110 116D 11AD;D216;1110 116D 11AD; # (툖; 툖; 툖; 툖; 툖; ) HANGUL SYLLABLE TYONH +D217;D217;1110 116D 11AE;D217;1110 116D 11AE; # (툗; 툗; 툗; 툗; 툗; ) HANGUL SYLLABLE TYOD +D218;D218;1110 116D 11AF;D218;1110 116D 11AF; # (툘; 툘; 툘; 툘; 툘; ) HANGUL SYLLABLE TYOL +D219;D219;1110 116D 11B0;D219;1110 116D 11B0; # (툙; 툙; 툙; 툙; 툙; ) HANGUL SYLLABLE TYOLG +D21A;D21A;1110 116D 11B1;D21A;1110 116D 11B1; # (툚; 툚; 툚; 툚; 툚; ) HANGUL SYLLABLE TYOLM +D21B;D21B;1110 116D 11B2;D21B;1110 116D 11B2; # (툛; 툛; 툛; 툛; 툛; ) HANGUL SYLLABLE TYOLB +D21C;D21C;1110 116D 11B3;D21C;1110 116D 11B3; # (툜; 툜; 툜; 툜; 툜; ) HANGUL SYLLABLE TYOLS +D21D;D21D;1110 116D 11B4;D21D;1110 116D 11B4; # (툝; 툝; 툝; 툝; 툝; ) HANGUL SYLLABLE TYOLT +D21E;D21E;1110 116D 11B5;D21E;1110 116D 11B5; # (툞; 툞; 툞; 툞; 툞; ) HANGUL SYLLABLE TYOLP +D21F;D21F;1110 116D 11B6;D21F;1110 116D 11B6; # (툟; 툟; 툟; 툟; 툟; ) HANGUL SYLLABLE TYOLH +D220;D220;1110 116D 11B7;D220;1110 116D 11B7; # (툠; 툠; 툠; 툠; 툠; ) HANGUL SYLLABLE TYOM +D221;D221;1110 116D 11B8;D221;1110 116D 11B8; # (툡; 툡; 툡; 툡; 툡; ) HANGUL SYLLABLE TYOB +D222;D222;1110 116D 11B9;D222;1110 116D 11B9; # (툢; 툢; 툢; 툢; 툢; ) HANGUL SYLLABLE TYOBS +D223;D223;1110 116D 11BA;D223;1110 116D 11BA; # (툣; 툣; 툣; 툣; 툣; ) HANGUL SYLLABLE TYOS +D224;D224;1110 116D 11BB;D224;1110 116D 11BB; # (툤; 툤; 툤; 툤; 툤; ) HANGUL SYLLABLE TYOSS +D225;D225;1110 116D 11BC;D225;1110 116D 11BC; # (툥; 툥; 툥; 툥; 툥; ) HANGUL SYLLABLE TYONG +D226;D226;1110 116D 11BD;D226;1110 116D 11BD; # (툦; 툦; 툦; 툦; 툦; ) HANGUL SYLLABLE TYOJ +D227;D227;1110 116D 11BE;D227;1110 116D 11BE; # (툧; 툧; 툧; 툧; 툧; ) HANGUL SYLLABLE TYOC +D228;D228;1110 116D 11BF;D228;1110 116D 11BF; # (툨; 툨; 툨; 툨; 툨; ) HANGUL SYLLABLE TYOK +D229;D229;1110 116D 11C0;D229;1110 116D 11C0; # (툩; 툩; 툩; 툩; 툩; ) HANGUL SYLLABLE TYOT +D22A;D22A;1110 116D 11C1;D22A;1110 116D 11C1; # (툪; 툪; 툪; 툪; 툪; ) HANGUL SYLLABLE TYOP +D22B;D22B;1110 116D 11C2;D22B;1110 116D 11C2; # (툫; 툫; 툫; 툫; 툫; ) HANGUL SYLLABLE TYOH +D22C;D22C;1110 116E;D22C;1110 116E; # (투; 투; 투; 투; 투; ) HANGUL SYLLABLE TU +D22D;D22D;1110 116E 11A8;D22D;1110 116E 11A8; # (툭; 툭; 툭; 툭; 툭; ) HANGUL SYLLABLE TUG +D22E;D22E;1110 116E 11A9;D22E;1110 116E 11A9; # (툮; 툮; 툮; 툮; 툮; ) HANGUL SYLLABLE TUGG +D22F;D22F;1110 116E 11AA;D22F;1110 116E 11AA; # (툯; 툯; 툯; 툯; 툯; ) HANGUL SYLLABLE TUGS +D230;D230;1110 116E 11AB;D230;1110 116E 11AB; # (툰; 툰; 툰; 툰; 툰; ) HANGUL SYLLABLE TUN +D231;D231;1110 116E 11AC;D231;1110 116E 11AC; # (툱; 툱; 툱; 툱; 툱; ) HANGUL SYLLABLE TUNJ +D232;D232;1110 116E 11AD;D232;1110 116E 11AD; # (툲; 툲; 툲; 툲; 툲; ) HANGUL SYLLABLE TUNH +D233;D233;1110 116E 11AE;D233;1110 116E 11AE; # (툳; 툳; 툳; 툳; 툳; ) HANGUL SYLLABLE TUD +D234;D234;1110 116E 11AF;D234;1110 116E 11AF; # (툴; 툴; 툴; 툴; 툴; ) HANGUL SYLLABLE TUL +D235;D235;1110 116E 11B0;D235;1110 116E 11B0; # (툵; 툵; 툵; 툵; 툵; ) HANGUL SYLLABLE TULG +D236;D236;1110 116E 11B1;D236;1110 116E 11B1; # (툶; 툶; 툶; 툶; 툶; ) HANGUL SYLLABLE TULM +D237;D237;1110 116E 11B2;D237;1110 116E 11B2; # (툷; 툷; 툷; 툷; 툷; ) HANGUL SYLLABLE TULB +D238;D238;1110 116E 11B3;D238;1110 116E 11B3; # (툸; 툸; 툸; 툸; 툸; ) HANGUL SYLLABLE TULS +D239;D239;1110 116E 11B4;D239;1110 116E 11B4; # (툹; 툹; 툹; 툹; 툹; ) HANGUL SYLLABLE TULT +D23A;D23A;1110 116E 11B5;D23A;1110 116E 11B5; # (툺; 툺; 툺; 툺; 툺; ) HANGUL SYLLABLE TULP +D23B;D23B;1110 116E 11B6;D23B;1110 116E 11B6; # (툻; 툻; 툻; 툻; 툻; ) HANGUL SYLLABLE TULH +D23C;D23C;1110 116E 11B7;D23C;1110 116E 11B7; # (툼; 툼; 툼; 툼; 툼; ) HANGUL SYLLABLE TUM +D23D;D23D;1110 116E 11B8;D23D;1110 116E 11B8; # (툽; 툽; 툽; 툽; 툽; ) HANGUL SYLLABLE TUB +D23E;D23E;1110 116E 11B9;D23E;1110 116E 11B9; # (툾; 툾; 툾; 툾; 툾; ) HANGUL SYLLABLE TUBS +D23F;D23F;1110 116E 11BA;D23F;1110 116E 11BA; # (툿; 툿; 툿; 툿; 툿; ) HANGUL SYLLABLE TUS +D240;D240;1110 116E 11BB;D240;1110 116E 11BB; # (퉀; 퉀; 퉀; 퉀; 퉀; ) HANGUL SYLLABLE TUSS +D241;D241;1110 116E 11BC;D241;1110 116E 11BC; # (퉁; 퉁; 퉁; 퉁; 퉁; ) HANGUL SYLLABLE TUNG +D242;D242;1110 116E 11BD;D242;1110 116E 11BD; # (퉂; 퉂; 퉂; 퉂; 퉂; ) HANGUL SYLLABLE TUJ +D243;D243;1110 116E 11BE;D243;1110 116E 11BE; # (퉃; 퉃; 퉃; 퉃; 퉃; ) HANGUL SYLLABLE TUC +D244;D244;1110 116E 11BF;D244;1110 116E 11BF; # (퉄; 퉄; 퉄; 퉄; 퉄; ) HANGUL SYLLABLE TUK +D245;D245;1110 116E 11C0;D245;1110 116E 11C0; # (퉅; 퉅; 퉅; 퉅; 퉅; ) HANGUL SYLLABLE TUT +D246;D246;1110 116E 11C1;D246;1110 116E 11C1; # (퉆; 퉆; 퉆; 퉆; 퉆; ) HANGUL SYLLABLE TUP +D247;D247;1110 116E 11C2;D247;1110 116E 11C2; # (퉇; 퉇; 퉇; 퉇; 퉇; ) HANGUL SYLLABLE TUH +D248;D248;1110 116F;D248;1110 116F; # (퉈; 퉈; 퉈; 퉈; 퉈; ) HANGUL SYLLABLE TWEO +D249;D249;1110 116F 11A8;D249;1110 116F 11A8; # (퉉; 퉉; 퉉; 퉉; 퉉; ) HANGUL SYLLABLE TWEOG +D24A;D24A;1110 116F 11A9;D24A;1110 116F 11A9; # (퉊; 퉊; 퉊; 퉊; 퉊; ) HANGUL SYLLABLE TWEOGG +D24B;D24B;1110 116F 11AA;D24B;1110 116F 11AA; # (퉋; 퉋; 퉋; 퉋; 퉋; ) HANGUL SYLLABLE TWEOGS +D24C;D24C;1110 116F 11AB;D24C;1110 116F 11AB; # (퉌; 퉌; 퉌; 퉌; 퉌; ) HANGUL SYLLABLE TWEON +D24D;D24D;1110 116F 11AC;D24D;1110 116F 11AC; # (퉍; 퉍; 퉍; 퉍; 퉍; ) HANGUL SYLLABLE TWEONJ +D24E;D24E;1110 116F 11AD;D24E;1110 116F 11AD; # (퉎; 퉎; 퉎; 퉎; 퉎; ) HANGUL SYLLABLE TWEONH +D24F;D24F;1110 116F 11AE;D24F;1110 116F 11AE; # (퉏; 퉏; 퉏; 퉏; 퉏; ) HANGUL SYLLABLE TWEOD +D250;D250;1110 116F 11AF;D250;1110 116F 11AF; # (퉐; 퉐; 퉐; 퉐; 퉐; ) HANGUL SYLLABLE TWEOL +D251;D251;1110 116F 11B0;D251;1110 116F 11B0; # (퉑; 퉑; 퉑; 퉑; 퉑; ) HANGUL SYLLABLE TWEOLG +D252;D252;1110 116F 11B1;D252;1110 116F 11B1; # (퉒; 퉒; 퉒; 퉒; 퉒; ) HANGUL SYLLABLE TWEOLM +D253;D253;1110 116F 11B2;D253;1110 116F 11B2; # (퉓; 퉓; 퉓; 퉓; 퉓; ) HANGUL SYLLABLE TWEOLB +D254;D254;1110 116F 11B3;D254;1110 116F 11B3; # (퉔; 퉔; 퉔; 퉔; 퉔; ) HANGUL SYLLABLE TWEOLS +D255;D255;1110 116F 11B4;D255;1110 116F 11B4; # (퉕; 퉕; 퉕; 퉕; 퉕; ) HANGUL SYLLABLE TWEOLT +D256;D256;1110 116F 11B5;D256;1110 116F 11B5; # (퉖; 퉖; 퉖; 퉖; 퉖; ) HANGUL SYLLABLE TWEOLP +D257;D257;1110 116F 11B6;D257;1110 116F 11B6; # (퉗; 퉗; 퉗; 퉗; 퉗; ) HANGUL SYLLABLE TWEOLH +D258;D258;1110 116F 11B7;D258;1110 116F 11B7; # (퉘; 퉘; 퉘; 퉘; 퉘; ) HANGUL SYLLABLE TWEOM +D259;D259;1110 116F 11B8;D259;1110 116F 11B8; # (퉙; 퉙; 퉙; 퉙; 퉙; ) HANGUL SYLLABLE TWEOB +D25A;D25A;1110 116F 11B9;D25A;1110 116F 11B9; # (퉚; 퉚; 퉚; 퉚; 퉚; ) HANGUL SYLLABLE TWEOBS +D25B;D25B;1110 116F 11BA;D25B;1110 116F 11BA; # (퉛; 퉛; 퉛; 퉛; 퉛; ) HANGUL SYLLABLE TWEOS +D25C;D25C;1110 116F 11BB;D25C;1110 116F 11BB; # (퉜; 퉜; 퉜; 퉜; 퉜; ) HANGUL SYLLABLE TWEOSS +D25D;D25D;1110 116F 11BC;D25D;1110 116F 11BC; # (퉝; 퉝; 퉝; 퉝; 퉝; ) HANGUL SYLLABLE TWEONG +D25E;D25E;1110 116F 11BD;D25E;1110 116F 11BD; # (퉞; 퉞; 퉞; 퉞; 퉞; ) HANGUL SYLLABLE TWEOJ +D25F;D25F;1110 116F 11BE;D25F;1110 116F 11BE; # (퉟; 퉟; 퉟; 퉟; 퉟; ) HANGUL SYLLABLE TWEOC +D260;D260;1110 116F 11BF;D260;1110 116F 11BF; # (퉠; 퉠; 퉠; 퉠; 퉠; ) HANGUL SYLLABLE TWEOK +D261;D261;1110 116F 11C0;D261;1110 116F 11C0; # (퉡; 퉡; 퉡; 퉡; 퉡; ) HANGUL SYLLABLE TWEOT +D262;D262;1110 116F 11C1;D262;1110 116F 11C1; # (퉢; 퉢; 퉢; 퉢; 퉢; ) HANGUL SYLLABLE TWEOP +D263;D263;1110 116F 11C2;D263;1110 116F 11C2; # (퉣; 퉣; 퉣; 퉣; 퉣; ) HANGUL SYLLABLE TWEOH +D264;D264;1110 1170;D264;1110 1170; # (퉤; 퉤; 퉤; 퉤; 퉤; ) HANGUL SYLLABLE TWE +D265;D265;1110 1170 11A8;D265;1110 1170 11A8; # (퉥; 퉥; 퉥; 퉥; 퉥; ) HANGUL SYLLABLE TWEG +D266;D266;1110 1170 11A9;D266;1110 1170 11A9; # (퉦; 퉦; 퉦; 퉦; 퉦; ) HANGUL SYLLABLE TWEGG +D267;D267;1110 1170 11AA;D267;1110 1170 11AA; # (퉧; 퉧; 퉧; 퉧; 퉧; ) HANGUL SYLLABLE TWEGS +D268;D268;1110 1170 11AB;D268;1110 1170 11AB; # (퉨; 퉨; 퉨; 퉨; 퉨; ) HANGUL SYLLABLE TWEN +D269;D269;1110 1170 11AC;D269;1110 1170 11AC; # (퉩; 퉩; 퉩; 퉩; 퉩; ) HANGUL SYLLABLE TWENJ +D26A;D26A;1110 1170 11AD;D26A;1110 1170 11AD; # (퉪; 퉪; 퉪; 퉪; 퉪; ) HANGUL SYLLABLE TWENH +D26B;D26B;1110 1170 11AE;D26B;1110 1170 11AE; # (퉫; 퉫; 퉫; 퉫; 퉫; ) HANGUL SYLLABLE TWED +D26C;D26C;1110 1170 11AF;D26C;1110 1170 11AF; # (퉬; 퉬; 퉬; 퉬; 퉬; ) HANGUL SYLLABLE TWEL +D26D;D26D;1110 1170 11B0;D26D;1110 1170 11B0; # (퉭; 퉭; 퉭; 퉭; 퉭; ) HANGUL SYLLABLE TWELG +D26E;D26E;1110 1170 11B1;D26E;1110 1170 11B1; # (퉮; 퉮; 퉮; 퉮; 퉮; ) HANGUL SYLLABLE TWELM +D26F;D26F;1110 1170 11B2;D26F;1110 1170 11B2; # (퉯; 퉯; 퉯; 퉯; 퉯; ) HANGUL SYLLABLE TWELB +D270;D270;1110 1170 11B3;D270;1110 1170 11B3; # (퉰; 퉰; 퉰; 퉰; 퉰; ) HANGUL SYLLABLE TWELS +D271;D271;1110 1170 11B4;D271;1110 1170 11B4; # (퉱; 퉱; 퉱; 퉱; 퉱; ) HANGUL SYLLABLE TWELT +D272;D272;1110 1170 11B5;D272;1110 1170 11B5; # (퉲; 퉲; 퉲; 퉲; 퉲; ) HANGUL SYLLABLE TWELP +D273;D273;1110 1170 11B6;D273;1110 1170 11B6; # (퉳; 퉳; 퉳; 퉳; 퉳; ) HANGUL SYLLABLE TWELH +D274;D274;1110 1170 11B7;D274;1110 1170 11B7; # (퉴; 퉴; 퉴; 퉴; 퉴; ) HANGUL SYLLABLE TWEM +D275;D275;1110 1170 11B8;D275;1110 1170 11B8; # (퉵; 퉵; 퉵; 퉵; 퉵; ) HANGUL SYLLABLE TWEB +D276;D276;1110 1170 11B9;D276;1110 1170 11B9; # (퉶; 퉶; 퉶; 퉶; 퉶; ) HANGUL SYLLABLE TWEBS +D277;D277;1110 1170 11BA;D277;1110 1170 11BA; # (퉷; 퉷; 퉷; 퉷; 퉷; ) HANGUL SYLLABLE TWES +D278;D278;1110 1170 11BB;D278;1110 1170 11BB; # (퉸; 퉸; 퉸; 퉸; 퉸; ) HANGUL SYLLABLE TWESS +D279;D279;1110 1170 11BC;D279;1110 1170 11BC; # (퉹; 퉹; 퉹; 퉹; 퉹; ) HANGUL SYLLABLE TWENG +D27A;D27A;1110 1170 11BD;D27A;1110 1170 11BD; # (퉺; 퉺; 퉺; 퉺; 퉺; ) HANGUL SYLLABLE TWEJ +D27B;D27B;1110 1170 11BE;D27B;1110 1170 11BE; # (퉻; 퉻; 퉻; 퉻; 퉻; ) HANGUL SYLLABLE TWEC +D27C;D27C;1110 1170 11BF;D27C;1110 1170 11BF; # (퉼; 퉼; 퉼; 퉼; 퉼; ) HANGUL SYLLABLE TWEK +D27D;D27D;1110 1170 11C0;D27D;1110 1170 11C0; # (퉽; 퉽; 퉽; 퉽; 퉽; ) HANGUL SYLLABLE TWET +D27E;D27E;1110 1170 11C1;D27E;1110 1170 11C1; # (퉾; 퉾; 퉾; 퉾; 퉾; ) HANGUL SYLLABLE TWEP +D27F;D27F;1110 1170 11C2;D27F;1110 1170 11C2; # (퉿; 퉿; 퉿; 퉿; 퉿; ) HANGUL SYLLABLE TWEH +D280;D280;1110 1171;D280;1110 1171; # (튀; 튀; 튀; 튀; 튀; ) HANGUL SYLLABLE TWI +D281;D281;1110 1171 11A8;D281;1110 1171 11A8; # (튁; 튁; 튁; 튁; 튁; ) HANGUL SYLLABLE TWIG +D282;D282;1110 1171 11A9;D282;1110 1171 11A9; # (튂; 튂; 튂; 튂; 튂; ) HANGUL SYLLABLE TWIGG +D283;D283;1110 1171 11AA;D283;1110 1171 11AA; # (튃; 튃; 튃; 튃; 튃; ) HANGUL SYLLABLE TWIGS +D284;D284;1110 1171 11AB;D284;1110 1171 11AB; # (튄; 튄; 튄; 튄; 튄; ) HANGUL SYLLABLE TWIN +D285;D285;1110 1171 11AC;D285;1110 1171 11AC; # (튅; 튅; 튅; 튅; 튅; ) HANGUL SYLLABLE TWINJ +D286;D286;1110 1171 11AD;D286;1110 1171 11AD; # (튆; 튆; 튆; 튆; 튆; ) HANGUL SYLLABLE TWINH +D287;D287;1110 1171 11AE;D287;1110 1171 11AE; # (튇; 튇; 튇; 튇; 튇; ) HANGUL SYLLABLE TWID +D288;D288;1110 1171 11AF;D288;1110 1171 11AF; # (튈; 튈; 튈; 튈; 튈; ) HANGUL SYLLABLE TWIL +D289;D289;1110 1171 11B0;D289;1110 1171 11B0; # (튉; 튉; 튉; 튉; 튉; ) HANGUL SYLLABLE TWILG +D28A;D28A;1110 1171 11B1;D28A;1110 1171 11B1; # (튊; 튊; 튊; 튊; 튊; ) HANGUL SYLLABLE TWILM +D28B;D28B;1110 1171 11B2;D28B;1110 1171 11B2; # (튋; 튋; 튋; 튋; 튋; ) HANGUL SYLLABLE TWILB +D28C;D28C;1110 1171 11B3;D28C;1110 1171 11B3; # (튌; 튌; 튌; 튌; 튌; ) HANGUL SYLLABLE TWILS +D28D;D28D;1110 1171 11B4;D28D;1110 1171 11B4; # (튍; 튍; 튍; 튍; 튍; ) HANGUL SYLLABLE TWILT +D28E;D28E;1110 1171 11B5;D28E;1110 1171 11B5; # (튎; 튎; 튎; 튎; 튎; ) HANGUL SYLLABLE TWILP +D28F;D28F;1110 1171 11B6;D28F;1110 1171 11B6; # (튏; 튏; 튏; 튏; 튏; ) HANGUL SYLLABLE TWILH +D290;D290;1110 1171 11B7;D290;1110 1171 11B7; # (튐; 튐; 튐; 튐; 튐; ) HANGUL SYLLABLE TWIM +D291;D291;1110 1171 11B8;D291;1110 1171 11B8; # (튑; 튑; 튑; 튑; 튑; ) HANGUL SYLLABLE TWIB +D292;D292;1110 1171 11B9;D292;1110 1171 11B9; # (튒; 튒; 튒; 튒; 튒; ) HANGUL SYLLABLE TWIBS +D293;D293;1110 1171 11BA;D293;1110 1171 11BA; # (튓; 튓; 튓; 튓; 튓; ) HANGUL SYLLABLE TWIS +D294;D294;1110 1171 11BB;D294;1110 1171 11BB; # (튔; 튔; 튔; 튔; 튔; ) HANGUL SYLLABLE TWISS +D295;D295;1110 1171 11BC;D295;1110 1171 11BC; # (튕; 튕; 튕; 튕; 튕; ) HANGUL SYLLABLE TWING +D296;D296;1110 1171 11BD;D296;1110 1171 11BD; # (튖; 튖; 튖; 튖; 튖; ) HANGUL SYLLABLE TWIJ +D297;D297;1110 1171 11BE;D297;1110 1171 11BE; # (튗; 튗; 튗; 튗; 튗; ) HANGUL SYLLABLE TWIC +D298;D298;1110 1171 11BF;D298;1110 1171 11BF; # (튘; 튘; 튘; 튘; 튘; ) HANGUL SYLLABLE TWIK +D299;D299;1110 1171 11C0;D299;1110 1171 11C0; # (튙; 튙; 튙; 튙; 튙; ) HANGUL SYLLABLE TWIT +D29A;D29A;1110 1171 11C1;D29A;1110 1171 11C1; # (튚; 튚; 튚; 튚; 튚; ) HANGUL SYLLABLE TWIP +D29B;D29B;1110 1171 11C2;D29B;1110 1171 11C2; # (튛; 튛; 튛; 튛; 튛; ) HANGUL SYLLABLE TWIH +D29C;D29C;1110 1172;D29C;1110 1172; # (튜; 튜; 튜; 튜; 튜; ) HANGUL SYLLABLE TYU +D29D;D29D;1110 1172 11A8;D29D;1110 1172 11A8; # (튝; 튝; 튝; 튝; 튝; ) HANGUL SYLLABLE TYUG +D29E;D29E;1110 1172 11A9;D29E;1110 1172 11A9; # (튞; 튞; 튞; 튞; 튞; ) HANGUL SYLLABLE TYUGG +D29F;D29F;1110 1172 11AA;D29F;1110 1172 11AA; # (튟; 튟; 튟; 튟; 튟; ) HANGUL SYLLABLE TYUGS +D2A0;D2A0;1110 1172 11AB;D2A0;1110 1172 11AB; # (튠; 튠; 튠; 튠; 튠; ) HANGUL SYLLABLE TYUN +D2A1;D2A1;1110 1172 11AC;D2A1;1110 1172 11AC; # (튡; 튡; 튡; 튡; 튡; ) HANGUL SYLLABLE TYUNJ +D2A2;D2A2;1110 1172 11AD;D2A2;1110 1172 11AD; # (튢; 튢; 튢; 튢; 튢; ) HANGUL SYLLABLE TYUNH +D2A3;D2A3;1110 1172 11AE;D2A3;1110 1172 11AE; # (튣; 튣; 튣; 튣; 튣; ) HANGUL SYLLABLE TYUD +D2A4;D2A4;1110 1172 11AF;D2A4;1110 1172 11AF; # (튤; 튤; 튤; 튤; 튤; ) HANGUL SYLLABLE TYUL +D2A5;D2A5;1110 1172 11B0;D2A5;1110 1172 11B0; # (튥; 튥; 튥; 튥; 튥; ) HANGUL SYLLABLE TYULG +D2A6;D2A6;1110 1172 11B1;D2A6;1110 1172 11B1; # (튦; 튦; 튦; 튦; 튦; ) HANGUL SYLLABLE TYULM +D2A7;D2A7;1110 1172 11B2;D2A7;1110 1172 11B2; # (튧; 튧; 튧; 튧; 튧; ) HANGUL SYLLABLE TYULB +D2A8;D2A8;1110 1172 11B3;D2A8;1110 1172 11B3; # (튨; 튨; 튨; 튨; 튨; ) HANGUL SYLLABLE TYULS +D2A9;D2A9;1110 1172 11B4;D2A9;1110 1172 11B4; # (튩; 튩; 튩; 튩; 튩; ) HANGUL SYLLABLE TYULT +D2AA;D2AA;1110 1172 11B5;D2AA;1110 1172 11B5; # (튪; 튪; 튪; 튪; 튪; ) HANGUL SYLLABLE TYULP +D2AB;D2AB;1110 1172 11B6;D2AB;1110 1172 11B6; # (튫; 튫; 튫; 튫; 튫; ) HANGUL SYLLABLE TYULH +D2AC;D2AC;1110 1172 11B7;D2AC;1110 1172 11B7; # (튬; 튬; 튬; 튬; 튬; ) HANGUL SYLLABLE TYUM +D2AD;D2AD;1110 1172 11B8;D2AD;1110 1172 11B8; # (튭; 튭; 튭; 튭; 튭; ) HANGUL SYLLABLE TYUB +D2AE;D2AE;1110 1172 11B9;D2AE;1110 1172 11B9; # (튮; 튮; 튮; 튮; 튮; ) HANGUL SYLLABLE TYUBS +D2AF;D2AF;1110 1172 11BA;D2AF;1110 1172 11BA; # (튯; 튯; 튯; 튯; 튯; ) HANGUL SYLLABLE TYUS +D2B0;D2B0;1110 1172 11BB;D2B0;1110 1172 11BB; # (튰; 튰; 튰; 튰; 튰; ) HANGUL SYLLABLE TYUSS +D2B1;D2B1;1110 1172 11BC;D2B1;1110 1172 11BC; # (튱; 튱; 튱; 튱; 튱; ) HANGUL SYLLABLE TYUNG +D2B2;D2B2;1110 1172 11BD;D2B2;1110 1172 11BD; # (튲; 튲; 튲; 튲; 튲; ) HANGUL SYLLABLE TYUJ +D2B3;D2B3;1110 1172 11BE;D2B3;1110 1172 11BE; # (튳; 튳; 튳; 튳; 튳; ) HANGUL SYLLABLE TYUC +D2B4;D2B4;1110 1172 11BF;D2B4;1110 1172 11BF; # (튴; 튴; 튴; 튴; 튴; ) HANGUL SYLLABLE TYUK +D2B5;D2B5;1110 1172 11C0;D2B5;1110 1172 11C0; # (튵; 튵; 튵; 튵; 튵; ) HANGUL SYLLABLE TYUT +D2B6;D2B6;1110 1172 11C1;D2B6;1110 1172 11C1; # (튶; 튶; 튶; 튶; 튶; ) HANGUL SYLLABLE TYUP +D2B7;D2B7;1110 1172 11C2;D2B7;1110 1172 11C2; # (튷; 튷; 튷; 튷; 튷; ) HANGUL SYLLABLE TYUH +D2B8;D2B8;1110 1173;D2B8;1110 1173; # (트; 트; 트; 트; 트; ) HANGUL SYLLABLE TEU +D2B9;D2B9;1110 1173 11A8;D2B9;1110 1173 11A8; # (특; 특; 특; 특; 특; ) HANGUL SYLLABLE TEUG +D2BA;D2BA;1110 1173 11A9;D2BA;1110 1173 11A9; # (튺; 튺; 튺; 튺; 튺; ) HANGUL SYLLABLE TEUGG +D2BB;D2BB;1110 1173 11AA;D2BB;1110 1173 11AA; # (튻; 튻; 튻; 튻; 튻; ) HANGUL SYLLABLE TEUGS +D2BC;D2BC;1110 1173 11AB;D2BC;1110 1173 11AB; # (튼; 튼; 튼; 튼; 튼; ) HANGUL SYLLABLE TEUN +D2BD;D2BD;1110 1173 11AC;D2BD;1110 1173 11AC; # (튽; 튽; 튽; 튽; 튽; ) HANGUL SYLLABLE TEUNJ +D2BE;D2BE;1110 1173 11AD;D2BE;1110 1173 11AD; # (튾; 튾; 튾; 튾; 튾; ) HANGUL SYLLABLE TEUNH +D2BF;D2BF;1110 1173 11AE;D2BF;1110 1173 11AE; # (튿; 튿; 튿; 튿; 튿; ) HANGUL SYLLABLE TEUD +D2C0;D2C0;1110 1173 11AF;D2C0;1110 1173 11AF; # (틀; 틀; 틀; 틀; 틀; ) HANGUL SYLLABLE TEUL +D2C1;D2C1;1110 1173 11B0;D2C1;1110 1173 11B0; # (틁; 틁; 틁; 틁; 틁; ) HANGUL SYLLABLE TEULG +D2C2;D2C2;1110 1173 11B1;D2C2;1110 1173 11B1; # (틂; 틂; 틂; 틂; 틂; ) HANGUL SYLLABLE TEULM +D2C3;D2C3;1110 1173 11B2;D2C3;1110 1173 11B2; # (틃; 틃; 틃; 틃; 틃; ) HANGUL SYLLABLE TEULB +D2C4;D2C4;1110 1173 11B3;D2C4;1110 1173 11B3; # (틄; 틄; 틄; 틄; 틄; ) HANGUL SYLLABLE TEULS +D2C5;D2C5;1110 1173 11B4;D2C5;1110 1173 11B4; # (틅; 틅; 틅; 틅; 틅; ) HANGUL SYLLABLE TEULT +D2C6;D2C6;1110 1173 11B5;D2C6;1110 1173 11B5; # (틆; 틆; 틆; 틆; 틆; ) HANGUL SYLLABLE TEULP +D2C7;D2C7;1110 1173 11B6;D2C7;1110 1173 11B6; # (틇; 틇; 틇; 틇; 틇; ) HANGUL SYLLABLE TEULH +D2C8;D2C8;1110 1173 11B7;D2C8;1110 1173 11B7; # (틈; 틈; 틈; 틈; 틈; ) HANGUL SYLLABLE TEUM +D2C9;D2C9;1110 1173 11B8;D2C9;1110 1173 11B8; # (틉; 틉; 틉; 틉; 틉; ) HANGUL SYLLABLE TEUB +D2CA;D2CA;1110 1173 11B9;D2CA;1110 1173 11B9; # (틊; 틊; 틊; 틊; 틊; ) HANGUL SYLLABLE TEUBS +D2CB;D2CB;1110 1173 11BA;D2CB;1110 1173 11BA; # (틋; 틋; 틋; 틋; 틋; ) HANGUL SYLLABLE TEUS +D2CC;D2CC;1110 1173 11BB;D2CC;1110 1173 11BB; # (틌; 틌; 틌; 틌; 틌; ) HANGUL SYLLABLE TEUSS +D2CD;D2CD;1110 1173 11BC;D2CD;1110 1173 11BC; # (틍; 틍; 틍; 틍; 틍; ) HANGUL SYLLABLE TEUNG +D2CE;D2CE;1110 1173 11BD;D2CE;1110 1173 11BD; # (틎; 틎; 틎; 틎; 틎; ) HANGUL SYLLABLE TEUJ +D2CF;D2CF;1110 1173 11BE;D2CF;1110 1173 11BE; # (틏; 틏; 틏; 틏; 틏; ) HANGUL SYLLABLE TEUC +D2D0;D2D0;1110 1173 11BF;D2D0;1110 1173 11BF; # (틐; 틐; 틐; 틐; 틐; ) HANGUL SYLLABLE TEUK +D2D1;D2D1;1110 1173 11C0;D2D1;1110 1173 11C0; # (틑; 틑; 틑; 틑; 틑; ) HANGUL SYLLABLE TEUT +D2D2;D2D2;1110 1173 11C1;D2D2;1110 1173 11C1; # (틒; 틒; 틒; 틒; 틒; ) HANGUL SYLLABLE TEUP +D2D3;D2D3;1110 1173 11C2;D2D3;1110 1173 11C2; # (틓; 틓; 틓; 틓; 틓; ) HANGUL SYLLABLE TEUH +D2D4;D2D4;1110 1174;D2D4;1110 1174; # (틔; 틔; 틔; 틔; 틔; ) HANGUL SYLLABLE TYI +D2D5;D2D5;1110 1174 11A8;D2D5;1110 1174 11A8; # (틕; 틕; 틕; 틕; 틕; ) HANGUL SYLLABLE TYIG +D2D6;D2D6;1110 1174 11A9;D2D6;1110 1174 11A9; # (틖; 틖; 틖; 틖; 틖; ) HANGUL SYLLABLE TYIGG +D2D7;D2D7;1110 1174 11AA;D2D7;1110 1174 11AA; # (틗; 틗; 틗; 틗; 틗; ) HANGUL SYLLABLE TYIGS +D2D8;D2D8;1110 1174 11AB;D2D8;1110 1174 11AB; # (틘; 틘; 틘; 틘; 틘; ) HANGUL SYLLABLE TYIN +D2D9;D2D9;1110 1174 11AC;D2D9;1110 1174 11AC; # (틙; 틙; 틙; 틙; 틙; ) HANGUL SYLLABLE TYINJ +D2DA;D2DA;1110 1174 11AD;D2DA;1110 1174 11AD; # (틚; 틚; 틚; 틚; 틚; ) HANGUL SYLLABLE TYINH +D2DB;D2DB;1110 1174 11AE;D2DB;1110 1174 11AE; # (틛; 틛; 틛; 틛; 틛; ) HANGUL SYLLABLE TYID +D2DC;D2DC;1110 1174 11AF;D2DC;1110 1174 11AF; # (틜; 틜; 틜; 틜; 틜; ) HANGUL SYLLABLE TYIL +D2DD;D2DD;1110 1174 11B0;D2DD;1110 1174 11B0; # (틝; 틝; 틝; 틝; 틝; ) HANGUL SYLLABLE TYILG +D2DE;D2DE;1110 1174 11B1;D2DE;1110 1174 11B1; # (틞; 틞; 틞; 틞; 틞; ) HANGUL SYLLABLE TYILM +D2DF;D2DF;1110 1174 11B2;D2DF;1110 1174 11B2; # (틟; 틟; 틟; 틟; 틟; ) HANGUL SYLLABLE TYILB +D2E0;D2E0;1110 1174 11B3;D2E0;1110 1174 11B3; # (틠; 틠; 틠; 틠; 틠; ) HANGUL SYLLABLE TYILS +D2E1;D2E1;1110 1174 11B4;D2E1;1110 1174 11B4; # (틡; 틡; 틡; 틡; 틡; ) HANGUL SYLLABLE TYILT +D2E2;D2E2;1110 1174 11B5;D2E2;1110 1174 11B5; # (틢; 틢; 틢; 틢; 틢; ) HANGUL SYLLABLE TYILP +D2E3;D2E3;1110 1174 11B6;D2E3;1110 1174 11B6; # (틣; 틣; 틣; 틣; 틣; ) HANGUL SYLLABLE TYILH +D2E4;D2E4;1110 1174 11B7;D2E4;1110 1174 11B7; # (틤; 틤; 틤; 틤; 틤; ) HANGUL SYLLABLE TYIM +D2E5;D2E5;1110 1174 11B8;D2E5;1110 1174 11B8; # (틥; 틥; 틥; 틥; 틥; ) HANGUL SYLLABLE TYIB +D2E6;D2E6;1110 1174 11B9;D2E6;1110 1174 11B9; # (틦; 틦; 틦; 틦; 틦; ) HANGUL SYLLABLE TYIBS +D2E7;D2E7;1110 1174 11BA;D2E7;1110 1174 11BA; # (틧; 틧; 틧; 틧; 틧; ) HANGUL SYLLABLE TYIS +D2E8;D2E8;1110 1174 11BB;D2E8;1110 1174 11BB; # (틨; 틨; 틨; 틨; 틨; ) HANGUL SYLLABLE TYISS +D2E9;D2E9;1110 1174 11BC;D2E9;1110 1174 11BC; # (틩; 틩; 틩; 틩; 틩; ) HANGUL SYLLABLE TYING +D2EA;D2EA;1110 1174 11BD;D2EA;1110 1174 11BD; # (틪; 틪; 틪; 틪; 틪; ) HANGUL SYLLABLE TYIJ +D2EB;D2EB;1110 1174 11BE;D2EB;1110 1174 11BE; # (틫; 틫; 틫; 틫; 틫; ) HANGUL SYLLABLE TYIC +D2EC;D2EC;1110 1174 11BF;D2EC;1110 1174 11BF; # (틬; 틬; 틬; 틬; 틬; ) HANGUL SYLLABLE TYIK +D2ED;D2ED;1110 1174 11C0;D2ED;1110 1174 11C0; # (틭; 틭; 틭; 틭; 틭; ) HANGUL SYLLABLE TYIT +D2EE;D2EE;1110 1174 11C1;D2EE;1110 1174 11C1; # (틮; 틮; 틮; 틮; 틮; ) HANGUL SYLLABLE TYIP +D2EF;D2EF;1110 1174 11C2;D2EF;1110 1174 11C2; # (틯; 틯; 틯; 틯; 틯; ) HANGUL SYLLABLE TYIH +D2F0;D2F0;1110 1175;D2F0;1110 1175; # (티; 티; 티; 티; 티; ) HANGUL SYLLABLE TI +D2F1;D2F1;1110 1175 11A8;D2F1;1110 1175 11A8; # (틱; 틱; 틱; 틱; 틱; ) HANGUL SYLLABLE TIG +D2F2;D2F2;1110 1175 11A9;D2F2;1110 1175 11A9; # (틲; 틲; 틲; 틲; 틲; ) HANGUL SYLLABLE TIGG +D2F3;D2F3;1110 1175 11AA;D2F3;1110 1175 11AA; # (틳; 틳; 틳; 틳; 틳; ) HANGUL SYLLABLE TIGS +D2F4;D2F4;1110 1175 11AB;D2F4;1110 1175 11AB; # (틴; 틴; 틴; 틴; 틴; ) HANGUL SYLLABLE TIN +D2F5;D2F5;1110 1175 11AC;D2F5;1110 1175 11AC; # (틵; 틵; 틵; 틵; 틵; ) HANGUL SYLLABLE TINJ +D2F6;D2F6;1110 1175 11AD;D2F6;1110 1175 11AD; # (틶; 틶; 틶; 틶; 틶; ) HANGUL SYLLABLE TINH +D2F7;D2F7;1110 1175 11AE;D2F7;1110 1175 11AE; # (틷; 틷; 틷; 틷; 틷; ) HANGUL SYLLABLE TID +D2F8;D2F8;1110 1175 11AF;D2F8;1110 1175 11AF; # (틸; 틸; 틸; 틸; 틸; ) HANGUL SYLLABLE TIL +D2F9;D2F9;1110 1175 11B0;D2F9;1110 1175 11B0; # (틹; 틹; 틹; 틹; 틹; ) HANGUL SYLLABLE TILG +D2FA;D2FA;1110 1175 11B1;D2FA;1110 1175 11B1; # (틺; 틺; 틺; 틺; 틺; ) HANGUL SYLLABLE TILM +D2FB;D2FB;1110 1175 11B2;D2FB;1110 1175 11B2; # (틻; 틻; 틻; 틻; 틻; ) HANGUL SYLLABLE TILB +D2FC;D2FC;1110 1175 11B3;D2FC;1110 1175 11B3; # (틼; 틼; 틼; 틼; 틼; ) HANGUL SYLLABLE TILS +D2FD;D2FD;1110 1175 11B4;D2FD;1110 1175 11B4; # (틽; 틽; 틽; 틽; 틽; ) HANGUL SYLLABLE TILT +D2FE;D2FE;1110 1175 11B5;D2FE;1110 1175 11B5; # (틾; 틾; 틾; 틾; 틾; ) HANGUL SYLLABLE TILP +D2FF;D2FF;1110 1175 11B6;D2FF;1110 1175 11B6; # (틿; 틿; 틿; 틿; 틿; ) HANGUL SYLLABLE TILH +D300;D300;1110 1175 11B7;D300;1110 1175 11B7; # (팀; 팀; 팀; 팀; 팀; ) HANGUL SYLLABLE TIM +D301;D301;1110 1175 11B8;D301;1110 1175 11B8; # (팁; 팁; 팁; 팁; 팁; ) HANGUL SYLLABLE TIB +D302;D302;1110 1175 11B9;D302;1110 1175 11B9; # (팂; 팂; 팂; 팂; 팂; ) HANGUL SYLLABLE TIBS +D303;D303;1110 1175 11BA;D303;1110 1175 11BA; # (팃; 팃; 팃; 팃; 팃; ) HANGUL SYLLABLE TIS +D304;D304;1110 1175 11BB;D304;1110 1175 11BB; # (팄; 팄; 팄; 팄; 팄; ) HANGUL SYLLABLE TISS +D305;D305;1110 1175 11BC;D305;1110 1175 11BC; # (팅; 팅; 팅; 팅; 팅; ) HANGUL SYLLABLE TING +D306;D306;1110 1175 11BD;D306;1110 1175 11BD; # (팆; 팆; 팆; 팆; 팆; ) HANGUL SYLLABLE TIJ +D307;D307;1110 1175 11BE;D307;1110 1175 11BE; # (팇; 팇; 팇; 팇; 팇; ) HANGUL SYLLABLE TIC +D308;D308;1110 1175 11BF;D308;1110 1175 11BF; # (팈; 팈; 팈; 팈; 팈; ) HANGUL SYLLABLE TIK +D309;D309;1110 1175 11C0;D309;1110 1175 11C0; # (팉; 팉; 팉; 팉; 팉; ) HANGUL SYLLABLE TIT +D30A;D30A;1110 1175 11C1;D30A;1110 1175 11C1; # (팊; 팊; 팊; 팊; 팊; ) HANGUL SYLLABLE TIP +D30B;D30B;1110 1175 11C2;D30B;1110 1175 11C2; # (팋; 팋; 팋; 팋; 팋; ) HANGUL SYLLABLE TIH +D30C;D30C;1111 1161;D30C;1111 1161; # (파; 파; 파; 파; 파; ) HANGUL SYLLABLE PA +D30D;D30D;1111 1161 11A8;D30D;1111 1161 11A8; # (팍; 팍; 팍; 팍; 팍; ) HANGUL SYLLABLE PAG +D30E;D30E;1111 1161 11A9;D30E;1111 1161 11A9; # (팎; 팎; 팎; 팎; 팎; ) HANGUL SYLLABLE PAGG +D30F;D30F;1111 1161 11AA;D30F;1111 1161 11AA; # (팏; 팏; 팏; 팏; 팏; ) HANGUL SYLLABLE PAGS +D310;D310;1111 1161 11AB;D310;1111 1161 11AB; # (판; 판; 판; 판; 판; ) HANGUL SYLLABLE PAN +D311;D311;1111 1161 11AC;D311;1111 1161 11AC; # (팑; 팑; 팑; 팑; 팑; ) HANGUL SYLLABLE PANJ +D312;D312;1111 1161 11AD;D312;1111 1161 11AD; # (팒; 팒; 팒; 팒; 팒; ) HANGUL SYLLABLE PANH +D313;D313;1111 1161 11AE;D313;1111 1161 11AE; # (팓; 팓; 팓; 팓; 팓; ) HANGUL SYLLABLE PAD +D314;D314;1111 1161 11AF;D314;1111 1161 11AF; # (팔; 팔; 팔; 팔; 팔; ) HANGUL SYLLABLE PAL +D315;D315;1111 1161 11B0;D315;1111 1161 11B0; # (팕; 팕; 팕; 팕; 팕; ) HANGUL SYLLABLE PALG +D316;D316;1111 1161 11B1;D316;1111 1161 11B1; # (팖; 팖; 팖; 팖; 팖; ) HANGUL SYLLABLE PALM +D317;D317;1111 1161 11B2;D317;1111 1161 11B2; # (팗; 팗; 팗; 팗; 팗; ) HANGUL SYLLABLE PALB +D318;D318;1111 1161 11B3;D318;1111 1161 11B3; # (팘; 팘; 팘; 팘; 팘; ) HANGUL SYLLABLE PALS +D319;D319;1111 1161 11B4;D319;1111 1161 11B4; # (팙; 팙; 팙; 팙; 팙; ) HANGUL SYLLABLE PALT +D31A;D31A;1111 1161 11B5;D31A;1111 1161 11B5; # (팚; 팚; 팚; 팚; 팚; ) HANGUL SYLLABLE PALP +D31B;D31B;1111 1161 11B6;D31B;1111 1161 11B6; # (팛; 팛; 팛; 팛; 팛; ) HANGUL SYLLABLE PALH +D31C;D31C;1111 1161 11B7;D31C;1111 1161 11B7; # (팜; 팜; 팜; 팜; 팜; ) HANGUL SYLLABLE PAM +D31D;D31D;1111 1161 11B8;D31D;1111 1161 11B8; # (팝; 팝; 팝; 팝; 팝; ) HANGUL SYLLABLE PAB +D31E;D31E;1111 1161 11B9;D31E;1111 1161 11B9; # (팞; 팞; 팞; 팞; 팞; ) HANGUL SYLLABLE PABS +D31F;D31F;1111 1161 11BA;D31F;1111 1161 11BA; # (팟; 팟; 팟; 팟; 팟; ) HANGUL SYLLABLE PAS +D320;D320;1111 1161 11BB;D320;1111 1161 11BB; # (팠; 팠; 팠; 팠; 팠; ) HANGUL SYLLABLE PASS +D321;D321;1111 1161 11BC;D321;1111 1161 11BC; # (팡; 팡; 팡; 팡; 팡; ) HANGUL SYLLABLE PANG +D322;D322;1111 1161 11BD;D322;1111 1161 11BD; # (팢; 팢; 팢; 팢; 팢; ) HANGUL SYLLABLE PAJ +D323;D323;1111 1161 11BE;D323;1111 1161 11BE; # (팣; 팣; 팣; 팣; 팣; ) HANGUL SYLLABLE PAC +D324;D324;1111 1161 11BF;D324;1111 1161 11BF; # (팤; 팤; 팤; 팤; 팤; ) HANGUL SYLLABLE PAK +D325;D325;1111 1161 11C0;D325;1111 1161 11C0; # (팥; 팥; 팥; 팥; 팥; ) HANGUL SYLLABLE PAT +D326;D326;1111 1161 11C1;D326;1111 1161 11C1; # (팦; 팦; 팦; 팦; 팦; ) HANGUL SYLLABLE PAP +D327;D327;1111 1161 11C2;D327;1111 1161 11C2; # (팧; 팧; 팧; 팧; 팧; ) HANGUL SYLLABLE PAH +D328;D328;1111 1162;D328;1111 1162; # (패; 패; 패; 패; 패; ) HANGUL SYLLABLE PAE +D329;D329;1111 1162 11A8;D329;1111 1162 11A8; # (팩; 팩; 팩; 팩; 팩; ) HANGUL SYLLABLE PAEG +D32A;D32A;1111 1162 11A9;D32A;1111 1162 11A9; # (팪; 팪; 팪; 팪; 팪; ) HANGUL SYLLABLE PAEGG +D32B;D32B;1111 1162 11AA;D32B;1111 1162 11AA; # (팫; 팫; 팫; 팫; 팫; ) HANGUL SYLLABLE PAEGS +D32C;D32C;1111 1162 11AB;D32C;1111 1162 11AB; # (팬; 팬; 팬; 팬; 팬; ) HANGUL SYLLABLE PAEN +D32D;D32D;1111 1162 11AC;D32D;1111 1162 11AC; # (팭; 팭; 팭; 팭; 팭; ) HANGUL SYLLABLE PAENJ +D32E;D32E;1111 1162 11AD;D32E;1111 1162 11AD; # (팮; 팮; 팮; 팮; 팮; ) HANGUL SYLLABLE PAENH +D32F;D32F;1111 1162 11AE;D32F;1111 1162 11AE; # (팯; 팯; 팯; 팯; 팯; ) HANGUL SYLLABLE PAED +D330;D330;1111 1162 11AF;D330;1111 1162 11AF; # (팰; 팰; 팰; 팰; 팰; ) HANGUL SYLLABLE PAEL +D331;D331;1111 1162 11B0;D331;1111 1162 11B0; # (팱; 팱; 팱; 팱; 팱; ) HANGUL SYLLABLE PAELG +D332;D332;1111 1162 11B1;D332;1111 1162 11B1; # (팲; 팲; 팲; 팲; 팲; ) HANGUL SYLLABLE PAELM +D333;D333;1111 1162 11B2;D333;1111 1162 11B2; # (팳; 팳; 팳; 팳; 팳; ) HANGUL SYLLABLE PAELB +D334;D334;1111 1162 11B3;D334;1111 1162 11B3; # (팴; 팴; 팴; 팴; 팴; ) HANGUL SYLLABLE PAELS +D335;D335;1111 1162 11B4;D335;1111 1162 11B4; # (팵; 팵; 팵; 팵; 팵; ) HANGUL SYLLABLE PAELT +D336;D336;1111 1162 11B5;D336;1111 1162 11B5; # (팶; 팶; 팶; 팶; 팶; ) HANGUL SYLLABLE PAELP +D337;D337;1111 1162 11B6;D337;1111 1162 11B6; # (팷; 팷; 팷; 팷; 팷; ) HANGUL SYLLABLE PAELH +D338;D338;1111 1162 11B7;D338;1111 1162 11B7; # (팸; 팸; 팸; 팸; 팸; ) HANGUL SYLLABLE PAEM +D339;D339;1111 1162 11B8;D339;1111 1162 11B8; # (팹; 팹; 팹; 팹; 팹; ) HANGUL SYLLABLE PAEB +D33A;D33A;1111 1162 11B9;D33A;1111 1162 11B9; # (팺; 팺; 팺; 팺; 팺; ) HANGUL SYLLABLE PAEBS +D33B;D33B;1111 1162 11BA;D33B;1111 1162 11BA; # (팻; 팻; 팻; 팻; 팻; ) HANGUL SYLLABLE PAES +D33C;D33C;1111 1162 11BB;D33C;1111 1162 11BB; # (팼; 팼; 팼; 팼; 팼; ) HANGUL SYLLABLE PAESS +D33D;D33D;1111 1162 11BC;D33D;1111 1162 11BC; # (팽; 팽; 팽; 팽; 팽; ) HANGUL SYLLABLE PAENG +D33E;D33E;1111 1162 11BD;D33E;1111 1162 11BD; # (팾; 팾; 팾; 팾; 팾; ) HANGUL SYLLABLE PAEJ +D33F;D33F;1111 1162 11BE;D33F;1111 1162 11BE; # (팿; 팿; 팿; 팿; 팿; ) HANGUL SYLLABLE PAEC +D340;D340;1111 1162 11BF;D340;1111 1162 11BF; # (퍀; 퍀; 퍀; 퍀; 퍀; ) HANGUL SYLLABLE PAEK +D341;D341;1111 1162 11C0;D341;1111 1162 11C0; # (퍁; 퍁; 퍁; 퍁; 퍁; ) HANGUL SYLLABLE PAET +D342;D342;1111 1162 11C1;D342;1111 1162 11C1; # (퍂; 퍂; 퍂; 퍂; 퍂; ) HANGUL SYLLABLE PAEP +D343;D343;1111 1162 11C2;D343;1111 1162 11C2; # (퍃; 퍃; 퍃; 퍃; 퍃; ) HANGUL SYLLABLE PAEH +D344;D344;1111 1163;D344;1111 1163; # (퍄; 퍄; 퍄; 퍄; 퍄; ) HANGUL SYLLABLE PYA +D345;D345;1111 1163 11A8;D345;1111 1163 11A8; # (퍅; 퍅; 퍅; 퍅; 퍅; ) HANGUL SYLLABLE PYAG +D346;D346;1111 1163 11A9;D346;1111 1163 11A9; # (퍆; 퍆; 퍆; 퍆; 퍆; ) HANGUL SYLLABLE PYAGG +D347;D347;1111 1163 11AA;D347;1111 1163 11AA; # (퍇; 퍇; 퍇; 퍇; 퍇; ) HANGUL SYLLABLE PYAGS +D348;D348;1111 1163 11AB;D348;1111 1163 11AB; # (퍈; 퍈; 퍈; 퍈; 퍈; ) HANGUL SYLLABLE PYAN +D349;D349;1111 1163 11AC;D349;1111 1163 11AC; # (퍉; 퍉; 퍉; 퍉; 퍉; ) HANGUL SYLLABLE PYANJ +D34A;D34A;1111 1163 11AD;D34A;1111 1163 11AD; # (퍊; 퍊; 퍊; 퍊; 퍊; ) HANGUL SYLLABLE PYANH +D34B;D34B;1111 1163 11AE;D34B;1111 1163 11AE; # (퍋; 퍋; 퍋; 퍋; 퍋; ) HANGUL SYLLABLE PYAD +D34C;D34C;1111 1163 11AF;D34C;1111 1163 11AF; # (퍌; 퍌; 퍌; 퍌; 퍌; ) HANGUL SYLLABLE PYAL +D34D;D34D;1111 1163 11B0;D34D;1111 1163 11B0; # (퍍; 퍍; 퍍; 퍍; 퍍; ) HANGUL SYLLABLE PYALG +D34E;D34E;1111 1163 11B1;D34E;1111 1163 11B1; # (퍎; 퍎; 퍎; 퍎; 퍎; ) HANGUL SYLLABLE PYALM +D34F;D34F;1111 1163 11B2;D34F;1111 1163 11B2; # (퍏; 퍏; 퍏; 퍏; 퍏; ) HANGUL SYLLABLE PYALB +D350;D350;1111 1163 11B3;D350;1111 1163 11B3; # (퍐; 퍐; 퍐; 퍐; 퍐; ) HANGUL SYLLABLE PYALS +D351;D351;1111 1163 11B4;D351;1111 1163 11B4; # (퍑; 퍑; 퍑; 퍑; 퍑; ) HANGUL SYLLABLE PYALT +D352;D352;1111 1163 11B5;D352;1111 1163 11B5; # (퍒; 퍒; 퍒; 퍒; 퍒; ) HANGUL SYLLABLE PYALP +D353;D353;1111 1163 11B6;D353;1111 1163 11B6; # (퍓; 퍓; 퍓; 퍓; 퍓; ) HANGUL SYLLABLE PYALH +D354;D354;1111 1163 11B7;D354;1111 1163 11B7; # (퍔; 퍔; 퍔; 퍔; 퍔; ) HANGUL SYLLABLE PYAM +D355;D355;1111 1163 11B8;D355;1111 1163 11B8; # (퍕; 퍕; 퍕; 퍕; 퍕; ) HANGUL SYLLABLE PYAB +D356;D356;1111 1163 11B9;D356;1111 1163 11B9; # (퍖; 퍖; 퍖; 퍖; 퍖; ) HANGUL SYLLABLE PYABS +D357;D357;1111 1163 11BA;D357;1111 1163 11BA; # (퍗; 퍗; 퍗; 퍗; 퍗; ) HANGUL SYLLABLE PYAS +D358;D358;1111 1163 11BB;D358;1111 1163 11BB; # (퍘; 퍘; 퍘; 퍘; 퍘; ) HANGUL SYLLABLE PYASS +D359;D359;1111 1163 11BC;D359;1111 1163 11BC; # (퍙; 퍙; 퍙; 퍙; 퍙; ) HANGUL SYLLABLE PYANG +D35A;D35A;1111 1163 11BD;D35A;1111 1163 11BD; # (퍚; 퍚; 퍚; 퍚; 퍚; ) HANGUL SYLLABLE PYAJ +D35B;D35B;1111 1163 11BE;D35B;1111 1163 11BE; # (퍛; 퍛; 퍛; 퍛; 퍛; ) HANGUL SYLLABLE PYAC +D35C;D35C;1111 1163 11BF;D35C;1111 1163 11BF; # (퍜; 퍜; 퍜; 퍜; 퍜; ) HANGUL SYLLABLE PYAK +D35D;D35D;1111 1163 11C0;D35D;1111 1163 11C0; # (퍝; 퍝; 퍝; 퍝; 퍝; ) HANGUL SYLLABLE PYAT +D35E;D35E;1111 1163 11C1;D35E;1111 1163 11C1; # (퍞; 퍞; 퍞; 퍞; 퍞; ) HANGUL SYLLABLE PYAP +D35F;D35F;1111 1163 11C2;D35F;1111 1163 11C2; # (퍟; 퍟; 퍟; 퍟; 퍟; ) HANGUL SYLLABLE PYAH +D360;D360;1111 1164;D360;1111 1164; # (퍠; 퍠; 퍠; 퍠; 퍠; ) HANGUL SYLLABLE PYAE +D361;D361;1111 1164 11A8;D361;1111 1164 11A8; # (퍡; 퍡; 퍡; 퍡; 퍡; ) HANGUL SYLLABLE PYAEG +D362;D362;1111 1164 11A9;D362;1111 1164 11A9; # (퍢; 퍢; 퍢; 퍢; 퍢; ) HANGUL SYLLABLE PYAEGG +D363;D363;1111 1164 11AA;D363;1111 1164 11AA; # (퍣; 퍣; 퍣; 퍣; 퍣; ) HANGUL SYLLABLE PYAEGS +D364;D364;1111 1164 11AB;D364;1111 1164 11AB; # (퍤; 퍤; 퍤; 퍤; 퍤; ) HANGUL SYLLABLE PYAEN +D365;D365;1111 1164 11AC;D365;1111 1164 11AC; # (퍥; 퍥; 퍥; 퍥; 퍥; ) HANGUL SYLLABLE PYAENJ +D366;D366;1111 1164 11AD;D366;1111 1164 11AD; # (퍦; 퍦; 퍦; 퍦; 퍦; ) HANGUL SYLLABLE PYAENH +D367;D367;1111 1164 11AE;D367;1111 1164 11AE; # (퍧; 퍧; 퍧; 퍧; 퍧; ) HANGUL SYLLABLE PYAED +D368;D368;1111 1164 11AF;D368;1111 1164 11AF; # (퍨; 퍨; 퍨; 퍨; 퍨; ) HANGUL SYLLABLE PYAEL +D369;D369;1111 1164 11B0;D369;1111 1164 11B0; # (퍩; 퍩; 퍩; 퍩; 퍩; ) HANGUL SYLLABLE PYAELG +D36A;D36A;1111 1164 11B1;D36A;1111 1164 11B1; # (퍪; 퍪; 퍪; 퍪; 퍪; ) HANGUL SYLLABLE PYAELM +D36B;D36B;1111 1164 11B2;D36B;1111 1164 11B2; # (퍫; 퍫; 퍫; 퍫; 퍫; ) HANGUL SYLLABLE PYAELB +D36C;D36C;1111 1164 11B3;D36C;1111 1164 11B3; # (퍬; 퍬; 퍬; 퍬; 퍬; ) HANGUL SYLLABLE PYAELS +D36D;D36D;1111 1164 11B4;D36D;1111 1164 11B4; # (퍭; 퍭; 퍭; 퍭; 퍭; ) HANGUL SYLLABLE PYAELT +D36E;D36E;1111 1164 11B5;D36E;1111 1164 11B5; # (퍮; 퍮; 퍮; 퍮; 퍮; ) HANGUL SYLLABLE PYAELP +D36F;D36F;1111 1164 11B6;D36F;1111 1164 11B6; # (퍯; 퍯; 퍯; 퍯; 퍯; ) HANGUL SYLLABLE PYAELH +D370;D370;1111 1164 11B7;D370;1111 1164 11B7; # (퍰; 퍰; 퍰; 퍰; 퍰; ) HANGUL SYLLABLE PYAEM +D371;D371;1111 1164 11B8;D371;1111 1164 11B8; # (퍱; 퍱; 퍱; 퍱; 퍱; ) HANGUL SYLLABLE PYAEB +D372;D372;1111 1164 11B9;D372;1111 1164 11B9; # (퍲; 퍲; 퍲; 퍲; 퍲; ) HANGUL SYLLABLE PYAEBS +D373;D373;1111 1164 11BA;D373;1111 1164 11BA; # (퍳; 퍳; 퍳; 퍳; 퍳; ) HANGUL SYLLABLE PYAES +D374;D374;1111 1164 11BB;D374;1111 1164 11BB; # (퍴; 퍴; 퍴; 퍴; 퍴; ) HANGUL SYLLABLE PYAESS +D375;D375;1111 1164 11BC;D375;1111 1164 11BC; # (퍵; 퍵; 퍵; 퍵; 퍵; ) HANGUL SYLLABLE PYAENG +D376;D376;1111 1164 11BD;D376;1111 1164 11BD; # (퍶; 퍶; 퍶; 퍶; 퍶; ) HANGUL SYLLABLE PYAEJ +D377;D377;1111 1164 11BE;D377;1111 1164 11BE; # (퍷; 퍷; 퍷; 퍷; 퍷; ) HANGUL SYLLABLE PYAEC +D378;D378;1111 1164 11BF;D378;1111 1164 11BF; # (퍸; 퍸; 퍸; 퍸; 퍸; ) HANGUL SYLLABLE PYAEK +D379;D379;1111 1164 11C0;D379;1111 1164 11C0; # (퍹; 퍹; 퍹; 퍹; 퍹; ) HANGUL SYLLABLE PYAET +D37A;D37A;1111 1164 11C1;D37A;1111 1164 11C1; # (퍺; 퍺; 퍺; 퍺; 퍺; ) HANGUL SYLLABLE PYAEP +D37B;D37B;1111 1164 11C2;D37B;1111 1164 11C2; # (퍻; 퍻; 퍻; 퍻; 퍻; ) HANGUL SYLLABLE PYAEH +D37C;D37C;1111 1165;D37C;1111 1165; # (퍼; 퍼; 퍼; 퍼; 퍼; ) HANGUL SYLLABLE PEO +D37D;D37D;1111 1165 11A8;D37D;1111 1165 11A8; # (퍽; 퍽; 퍽; 퍽; 퍽; ) HANGUL SYLLABLE PEOG +D37E;D37E;1111 1165 11A9;D37E;1111 1165 11A9; # (퍾; 퍾; 퍾; 퍾; 퍾; ) HANGUL SYLLABLE PEOGG +D37F;D37F;1111 1165 11AA;D37F;1111 1165 11AA; # (퍿; 퍿; 퍿; 퍿; 퍿; ) HANGUL SYLLABLE PEOGS +D380;D380;1111 1165 11AB;D380;1111 1165 11AB; # (펀; 펀; 펀; 펀; 펀; ) HANGUL SYLLABLE PEON +D381;D381;1111 1165 11AC;D381;1111 1165 11AC; # (펁; 펁; 펁; 펁; 펁; ) HANGUL SYLLABLE PEONJ +D382;D382;1111 1165 11AD;D382;1111 1165 11AD; # (펂; 펂; 펂; 펂; 펂; ) HANGUL SYLLABLE PEONH +D383;D383;1111 1165 11AE;D383;1111 1165 11AE; # (펃; 펃; 펃; 펃; 펃; ) HANGUL SYLLABLE PEOD +D384;D384;1111 1165 11AF;D384;1111 1165 11AF; # (펄; 펄; 펄; 펄; 펄; ) HANGUL SYLLABLE PEOL +D385;D385;1111 1165 11B0;D385;1111 1165 11B0; # (펅; 펅; 펅; 펅; 펅; ) HANGUL SYLLABLE PEOLG +D386;D386;1111 1165 11B1;D386;1111 1165 11B1; # (펆; 펆; 펆; 펆; 펆; ) HANGUL SYLLABLE PEOLM +D387;D387;1111 1165 11B2;D387;1111 1165 11B2; # (펇; 펇; 펇; 펇; 펇; ) HANGUL SYLLABLE PEOLB +D388;D388;1111 1165 11B3;D388;1111 1165 11B3; # (펈; 펈; 펈; 펈; 펈; ) HANGUL SYLLABLE PEOLS +D389;D389;1111 1165 11B4;D389;1111 1165 11B4; # (펉; 펉; 펉; 펉; 펉; ) HANGUL SYLLABLE PEOLT +D38A;D38A;1111 1165 11B5;D38A;1111 1165 11B5; # (펊; 펊; 펊; 펊; 펊; ) HANGUL SYLLABLE PEOLP +D38B;D38B;1111 1165 11B6;D38B;1111 1165 11B6; # (펋; 펋; 펋; 펋; 펋; ) HANGUL SYLLABLE PEOLH +D38C;D38C;1111 1165 11B7;D38C;1111 1165 11B7; # (펌; 펌; 펌; 펌; 펌; ) HANGUL SYLLABLE PEOM +D38D;D38D;1111 1165 11B8;D38D;1111 1165 11B8; # (펍; 펍; 펍; 펍; 펍; ) HANGUL SYLLABLE PEOB +D38E;D38E;1111 1165 11B9;D38E;1111 1165 11B9; # (펎; 펎; 펎; 펎; 펎; ) HANGUL SYLLABLE PEOBS +D38F;D38F;1111 1165 11BA;D38F;1111 1165 11BA; # (펏; 펏; 펏; 펏; 펏; ) HANGUL SYLLABLE PEOS +D390;D390;1111 1165 11BB;D390;1111 1165 11BB; # (펐; 펐; 펐; 펐; 펐; ) HANGUL SYLLABLE PEOSS +D391;D391;1111 1165 11BC;D391;1111 1165 11BC; # (펑; 펑; 펑; 펑; 펑; ) HANGUL SYLLABLE PEONG +D392;D392;1111 1165 11BD;D392;1111 1165 11BD; # (펒; 펒; 펒; 펒; 펒; ) HANGUL SYLLABLE PEOJ +D393;D393;1111 1165 11BE;D393;1111 1165 11BE; # (펓; 펓; 펓; 펓; 펓; ) HANGUL SYLLABLE PEOC +D394;D394;1111 1165 11BF;D394;1111 1165 11BF; # (펔; 펔; 펔; 펔; 펔; ) HANGUL SYLLABLE PEOK +D395;D395;1111 1165 11C0;D395;1111 1165 11C0; # (펕; 펕; 펕; 펕; 펕; ) HANGUL SYLLABLE PEOT +D396;D396;1111 1165 11C1;D396;1111 1165 11C1; # (펖; 펖; 펖; 펖; 펖; ) HANGUL SYLLABLE PEOP +D397;D397;1111 1165 11C2;D397;1111 1165 11C2; # (펗; 펗; 펗; 펗; 펗; ) HANGUL SYLLABLE PEOH +D398;D398;1111 1166;D398;1111 1166; # (페; 페; 페; 페; 페; ) HANGUL SYLLABLE PE +D399;D399;1111 1166 11A8;D399;1111 1166 11A8; # (펙; 펙; 펙; 펙; 펙; ) HANGUL SYLLABLE PEG +D39A;D39A;1111 1166 11A9;D39A;1111 1166 11A9; # (펚; 펚; 펚; 펚; 펚; ) HANGUL SYLLABLE PEGG +D39B;D39B;1111 1166 11AA;D39B;1111 1166 11AA; # (펛; 펛; 펛; 펛; 펛; ) HANGUL SYLLABLE PEGS +D39C;D39C;1111 1166 11AB;D39C;1111 1166 11AB; # (펜; 펜; 펜; 펜; 펜; ) HANGUL SYLLABLE PEN +D39D;D39D;1111 1166 11AC;D39D;1111 1166 11AC; # (펝; 펝; 펝; 펝; 펝; ) HANGUL SYLLABLE PENJ +D39E;D39E;1111 1166 11AD;D39E;1111 1166 11AD; # (펞; 펞; 펞; 펞; 펞; ) HANGUL SYLLABLE PENH +D39F;D39F;1111 1166 11AE;D39F;1111 1166 11AE; # (펟; 펟; 펟; 펟; 펟; ) HANGUL SYLLABLE PED +D3A0;D3A0;1111 1166 11AF;D3A0;1111 1166 11AF; # (펠; 펠; 펠; 펠; 펠; ) HANGUL SYLLABLE PEL +D3A1;D3A1;1111 1166 11B0;D3A1;1111 1166 11B0; # (펡; 펡; 펡; 펡; 펡; ) HANGUL SYLLABLE PELG +D3A2;D3A2;1111 1166 11B1;D3A2;1111 1166 11B1; # (펢; 펢; 펢; 펢; 펢; ) HANGUL SYLLABLE PELM +D3A3;D3A3;1111 1166 11B2;D3A3;1111 1166 11B2; # (펣; 펣; 펣; 펣; 펣; ) HANGUL SYLLABLE PELB +D3A4;D3A4;1111 1166 11B3;D3A4;1111 1166 11B3; # (펤; 펤; 펤; 펤; 펤; ) HANGUL SYLLABLE PELS +D3A5;D3A5;1111 1166 11B4;D3A5;1111 1166 11B4; # (펥; 펥; 펥; 펥; 펥; ) HANGUL SYLLABLE PELT +D3A6;D3A6;1111 1166 11B5;D3A6;1111 1166 11B5; # (펦; 펦; 펦; 펦; 펦; ) HANGUL SYLLABLE PELP +D3A7;D3A7;1111 1166 11B6;D3A7;1111 1166 11B6; # (펧; 펧; 펧; 펧; 펧; ) HANGUL SYLLABLE PELH +D3A8;D3A8;1111 1166 11B7;D3A8;1111 1166 11B7; # (펨; 펨; 펨; 펨; 펨; ) HANGUL SYLLABLE PEM +D3A9;D3A9;1111 1166 11B8;D3A9;1111 1166 11B8; # (펩; 펩; 펩; 펩; 펩; ) HANGUL SYLLABLE PEB +D3AA;D3AA;1111 1166 11B9;D3AA;1111 1166 11B9; # (펪; 펪; 펪; 펪; 펪; ) HANGUL SYLLABLE PEBS +D3AB;D3AB;1111 1166 11BA;D3AB;1111 1166 11BA; # (펫; 펫; 펫; 펫; 펫; ) HANGUL SYLLABLE PES +D3AC;D3AC;1111 1166 11BB;D3AC;1111 1166 11BB; # (펬; 펬; 펬; 펬; 펬; ) HANGUL SYLLABLE PESS +D3AD;D3AD;1111 1166 11BC;D3AD;1111 1166 11BC; # (펭; 펭; 펭; 펭; 펭; ) HANGUL SYLLABLE PENG +D3AE;D3AE;1111 1166 11BD;D3AE;1111 1166 11BD; # (펮; 펮; 펮; 펮; 펮; ) HANGUL SYLLABLE PEJ +D3AF;D3AF;1111 1166 11BE;D3AF;1111 1166 11BE; # (펯; 펯; 펯; 펯; 펯; ) HANGUL SYLLABLE PEC +D3B0;D3B0;1111 1166 11BF;D3B0;1111 1166 11BF; # (펰; 펰; 펰; 펰; 펰; ) HANGUL SYLLABLE PEK +D3B1;D3B1;1111 1166 11C0;D3B1;1111 1166 11C0; # (펱; 펱; 펱; 펱; 펱; ) HANGUL SYLLABLE PET +D3B2;D3B2;1111 1166 11C1;D3B2;1111 1166 11C1; # (펲; 펲; 펲; 펲; 펲; ) HANGUL SYLLABLE PEP +D3B3;D3B3;1111 1166 11C2;D3B3;1111 1166 11C2; # (펳; 펳; 펳; 펳; 펳; ) HANGUL SYLLABLE PEH +D3B4;D3B4;1111 1167;D3B4;1111 1167; # (펴; 펴; 펴; 펴; 펴; ) HANGUL SYLLABLE PYEO +D3B5;D3B5;1111 1167 11A8;D3B5;1111 1167 11A8; # (펵; 펵; 펵; 펵; 펵; ) HANGUL SYLLABLE PYEOG +D3B6;D3B6;1111 1167 11A9;D3B6;1111 1167 11A9; # (펶; 펶; 펶; 펶; 펶; ) HANGUL SYLLABLE PYEOGG +D3B7;D3B7;1111 1167 11AA;D3B7;1111 1167 11AA; # (펷; 펷; 펷; 펷; 펷; ) HANGUL SYLLABLE PYEOGS +D3B8;D3B8;1111 1167 11AB;D3B8;1111 1167 11AB; # (편; 편; 편; 편; 편; ) HANGUL SYLLABLE PYEON +D3B9;D3B9;1111 1167 11AC;D3B9;1111 1167 11AC; # (펹; 펹; 펹; 펹; 펹; ) HANGUL SYLLABLE PYEONJ +D3BA;D3BA;1111 1167 11AD;D3BA;1111 1167 11AD; # (펺; 펺; 펺; 펺; 펺; ) HANGUL SYLLABLE PYEONH +D3BB;D3BB;1111 1167 11AE;D3BB;1111 1167 11AE; # (펻; 펻; 펻; 펻; 펻; ) HANGUL SYLLABLE PYEOD +D3BC;D3BC;1111 1167 11AF;D3BC;1111 1167 11AF; # (펼; 펼; 펼; 펼; 펼; ) HANGUL SYLLABLE PYEOL +D3BD;D3BD;1111 1167 11B0;D3BD;1111 1167 11B0; # (펽; 펽; 펽; 펽; 펽; ) HANGUL SYLLABLE PYEOLG +D3BE;D3BE;1111 1167 11B1;D3BE;1111 1167 11B1; # (펾; 펾; 펾; 펾; 펾; ) HANGUL SYLLABLE PYEOLM +D3BF;D3BF;1111 1167 11B2;D3BF;1111 1167 11B2; # (펿; 펿; 펿; 펿; 펿; ) HANGUL SYLLABLE PYEOLB +D3C0;D3C0;1111 1167 11B3;D3C0;1111 1167 11B3; # (폀; 폀; 폀; 폀; 폀; ) HANGUL SYLLABLE PYEOLS +D3C1;D3C1;1111 1167 11B4;D3C1;1111 1167 11B4; # (폁; 폁; 폁; 폁; 폁; ) HANGUL SYLLABLE PYEOLT +D3C2;D3C2;1111 1167 11B5;D3C2;1111 1167 11B5; # (폂; 폂; 폂; 폂; 폂; ) HANGUL SYLLABLE PYEOLP +D3C3;D3C3;1111 1167 11B6;D3C3;1111 1167 11B6; # (폃; 폃; 폃; 폃; 폃; ) HANGUL SYLLABLE PYEOLH +D3C4;D3C4;1111 1167 11B7;D3C4;1111 1167 11B7; # (폄; 폄; 폄; 폄; 폄; ) HANGUL SYLLABLE PYEOM +D3C5;D3C5;1111 1167 11B8;D3C5;1111 1167 11B8; # (폅; 폅; 폅; 폅; 폅; ) HANGUL SYLLABLE PYEOB +D3C6;D3C6;1111 1167 11B9;D3C6;1111 1167 11B9; # (폆; 폆; 폆; 폆; 폆; ) HANGUL SYLLABLE PYEOBS +D3C7;D3C7;1111 1167 11BA;D3C7;1111 1167 11BA; # (폇; 폇; 폇; 폇; 폇; ) HANGUL SYLLABLE PYEOS +D3C8;D3C8;1111 1167 11BB;D3C8;1111 1167 11BB; # (폈; 폈; 폈; 폈; 폈; ) HANGUL SYLLABLE PYEOSS +D3C9;D3C9;1111 1167 11BC;D3C9;1111 1167 11BC; # (평; 평; 평; 평; 평; ) HANGUL SYLLABLE PYEONG +D3CA;D3CA;1111 1167 11BD;D3CA;1111 1167 11BD; # (폊; 폊; 폊; 폊; 폊; ) HANGUL SYLLABLE PYEOJ +D3CB;D3CB;1111 1167 11BE;D3CB;1111 1167 11BE; # (폋; 폋; 폋; 폋; 폋; ) HANGUL SYLLABLE PYEOC +D3CC;D3CC;1111 1167 11BF;D3CC;1111 1167 11BF; # (폌; 폌; 폌; 폌; 폌; ) HANGUL SYLLABLE PYEOK +D3CD;D3CD;1111 1167 11C0;D3CD;1111 1167 11C0; # (폍; 폍; 폍; 폍; 폍; ) HANGUL SYLLABLE PYEOT +D3CE;D3CE;1111 1167 11C1;D3CE;1111 1167 11C1; # (폎; 폎; 폎; 폎; 폎; ) HANGUL SYLLABLE PYEOP +D3CF;D3CF;1111 1167 11C2;D3CF;1111 1167 11C2; # (폏; 폏; 폏; 폏; 폏; ) HANGUL SYLLABLE PYEOH +D3D0;D3D0;1111 1168;D3D0;1111 1168; # (폐; 폐; 폐; 폐; 폐; ) HANGUL SYLLABLE PYE +D3D1;D3D1;1111 1168 11A8;D3D1;1111 1168 11A8; # (폑; 폑; 폑; 폑; 폑; ) HANGUL SYLLABLE PYEG +D3D2;D3D2;1111 1168 11A9;D3D2;1111 1168 11A9; # (폒; 폒; 폒; 폒; 폒; ) HANGUL SYLLABLE PYEGG +D3D3;D3D3;1111 1168 11AA;D3D3;1111 1168 11AA; # (폓; 폓; 폓; 폓; 폓; ) HANGUL SYLLABLE PYEGS +D3D4;D3D4;1111 1168 11AB;D3D4;1111 1168 11AB; # (폔; 폔; 폔; 폔; 폔; ) HANGUL SYLLABLE PYEN +D3D5;D3D5;1111 1168 11AC;D3D5;1111 1168 11AC; # (폕; 폕; 폕; 폕; 폕; ) HANGUL SYLLABLE PYENJ +D3D6;D3D6;1111 1168 11AD;D3D6;1111 1168 11AD; # (폖; 폖; 폖; 폖; 폖; ) HANGUL SYLLABLE PYENH +D3D7;D3D7;1111 1168 11AE;D3D7;1111 1168 11AE; # (폗; 폗; 폗; 폗; 폗; ) HANGUL SYLLABLE PYED +D3D8;D3D8;1111 1168 11AF;D3D8;1111 1168 11AF; # (폘; 폘; 폘; 폘; 폘; ) HANGUL SYLLABLE PYEL +D3D9;D3D9;1111 1168 11B0;D3D9;1111 1168 11B0; # (폙; 폙; 폙; 폙; 폙; ) HANGUL SYLLABLE PYELG +D3DA;D3DA;1111 1168 11B1;D3DA;1111 1168 11B1; # (폚; 폚; 폚; 폚; 폚; ) HANGUL SYLLABLE PYELM +D3DB;D3DB;1111 1168 11B2;D3DB;1111 1168 11B2; # (폛; 폛; 폛; 폛; 폛; ) HANGUL SYLLABLE PYELB +D3DC;D3DC;1111 1168 11B3;D3DC;1111 1168 11B3; # (폜; 폜; 폜; 폜; 폜; ) HANGUL SYLLABLE PYELS +D3DD;D3DD;1111 1168 11B4;D3DD;1111 1168 11B4; # (폝; 폝; 폝; 폝; 폝; ) HANGUL SYLLABLE PYELT +D3DE;D3DE;1111 1168 11B5;D3DE;1111 1168 11B5; # (폞; 폞; 폞; 폞; 폞; ) HANGUL SYLLABLE PYELP +D3DF;D3DF;1111 1168 11B6;D3DF;1111 1168 11B6; # (폟; 폟; 폟; 폟; 폟; ) HANGUL SYLLABLE PYELH +D3E0;D3E0;1111 1168 11B7;D3E0;1111 1168 11B7; # (폠; 폠; 폠; 폠; 폠; ) HANGUL SYLLABLE PYEM +D3E1;D3E1;1111 1168 11B8;D3E1;1111 1168 11B8; # (폡; 폡; 폡; 폡; 폡; ) HANGUL SYLLABLE PYEB +D3E2;D3E2;1111 1168 11B9;D3E2;1111 1168 11B9; # (폢; 폢; 폢; 폢; 폢; ) HANGUL SYLLABLE PYEBS +D3E3;D3E3;1111 1168 11BA;D3E3;1111 1168 11BA; # (폣; 폣; 폣; 폣; 폣; ) HANGUL SYLLABLE PYES +D3E4;D3E4;1111 1168 11BB;D3E4;1111 1168 11BB; # (폤; 폤; 폤; 폤; 폤; ) HANGUL SYLLABLE PYESS +D3E5;D3E5;1111 1168 11BC;D3E5;1111 1168 11BC; # (폥; 폥; 폥; 폥; 폥; ) HANGUL SYLLABLE PYENG +D3E6;D3E6;1111 1168 11BD;D3E6;1111 1168 11BD; # (폦; 폦; 폦; 폦; 폦; ) HANGUL SYLLABLE PYEJ +D3E7;D3E7;1111 1168 11BE;D3E7;1111 1168 11BE; # (폧; 폧; 폧; 폧; 폧; ) HANGUL SYLLABLE PYEC +D3E8;D3E8;1111 1168 11BF;D3E8;1111 1168 11BF; # (폨; 폨; 폨; 폨; 폨; ) HANGUL SYLLABLE PYEK +D3E9;D3E9;1111 1168 11C0;D3E9;1111 1168 11C0; # (폩; 폩; 폩; 폩; 폩; ) HANGUL SYLLABLE PYET +D3EA;D3EA;1111 1168 11C1;D3EA;1111 1168 11C1; # (폪; 폪; 폪; 폪; 폪; ) HANGUL SYLLABLE PYEP +D3EB;D3EB;1111 1168 11C2;D3EB;1111 1168 11C2; # (폫; 폫; 폫; 폫; 폫; ) HANGUL SYLLABLE PYEH +D3EC;D3EC;1111 1169;D3EC;1111 1169; # (포; 포; 포; 포; 포; ) HANGUL SYLLABLE PO +D3ED;D3ED;1111 1169 11A8;D3ED;1111 1169 11A8; # (폭; 폭; 폭; 폭; 폭; ) HANGUL SYLLABLE POG +D3EE;D3EE;1111 1169 11A9;D3EE;1111 1169 11A9; # (폮; 폮; 폮; 폮; 폮; ) HANGUL SYLLABLE POGG +D3EF;D3EF;1111 1169 11AA;D3EF;1111 1169 11AA; # (폯; 폯; 폯; 폯; 폯; ) HANGUL SYLLABLE POGS +D3F0;D3F0;1111 1169 11AB;D3F0;1111 1169 11AB; # (폰; 폰; 폰; 폰; 폰; ) HANGUL SYLLABLE PON +D3F1;D3F1;1111 1169 11AC;D3F1;1111 1169 11AC; # (폱; 폱; 폱; 폱; 폱; ) HANGUL SYLLABLE PONJ +D3F2;D3F2;1111 1169 11AD;D3F2;1111 1169 11AD; # (폲; 폲; 폲; 폲; 폲; ) HANGUL SYLLABLE PONH +D3F3;D3F3;1111 1169 11AE;D3F3;1111 1169 11AE; # (폳; 폳; 폳; 폳; 폳; ) HANGUL SYLLABLE POD +D3F4;D3F4;1111 1169 11AF;D3F4;1111 1169 11AF; # (폴; 폴; 폴; 폴; 폴; ) HANGUL SYLLABLE POL +D3F5;D3F5;1111 1169 11B0;D3F5;1111 1169 11B0; # (폵; 폵; 폵; 폵; 폵; ) HANGUL SYLLABLE POLG +D3F6;D3F6;1111 1169 11B1;D3F6;1111 1169 11B1; # (폶; 폶; 폶; 폶; 폶; ) HANGUL SYLLABLE POLM +D3F7;D3F7;1111 1169 11B2;D3F7;1111 1169 11B2; # (폷; 폷; 폷; 폷; 폷; ) HANGUL SYLLABLE POLB +D3F8;D3F8;1111 1169 11B3;D3F8;1111 1169 11B3; # (폸; 폸; 폸; 폸; 폸; ) HANGUL SYLLABLE POLS +D3F9;D3F9;1111 1169 11B4;D3F9;1111 1169 11B4; # (폹; 폹; 폹; 폹; 폹; ) HANGUL SYLLABLE POLT +D3FA;D3FA;1111 1169 11B5;D3FA;1111 1169 11B5; # (폺; 폺; 폺; 폺; 폺; ) HANGUL SYLLABLE POLP +D3FB;D3FB;1111 1169 11B6;D3FB;1111 1169 11B6; # (폻; 폻; 폻; 폻; 폻; ) HANGUL SYLLABLE POLH +D3FC;D3FC;1111 1169 11B7;D3FC;1111 1169 11B7; # (폼; 폼; 폼; 폼; 폼; ) HANGUL SYLLABLE POM +D3FD;D3FD;1111 1169 11B8;D3FD;1111 1169 11B8; # (폽; 폽; 폽; 폽; 폽; ) HANGUL SYLLABLE POB +D3FE;D3FE;1111 1169 11B9;D3FE;1111 1169 11B9; # (폾; 폾; 폾; 폾; 폾; ) HANGUL SYLLABLE POBS +D3FF;D3FF;1111 1169 11BA;D3FF;1111 1169 11BA; # (폿; 폿; 폿; 폿; 폿; ) HANGUL SYLLABLE POS +D400;D400;1111 1169 11BB;D400;1111 1169 11BB; # (퐀; 퐀; 퐀; 퐀; 퐀; ) HANGUL SYLLABLE POSS +D401;D401;1111 1169 11BC;D401;1111 1169 11BC; # (퐁; 퐁; 퐁; 퐁; 퐁; ) HANGUL SYLLABLE PONG +D402;D402;1111 1169 11BD;D402;1111 1169 11BD; # (퐂; 퐂; 퐂; 퐂; 퐂; ) HANGUL SYLLABLE POJ +D403;D403;1111 1169 11BE;D403;1111 1169 11BE; # (퐃; 퐃; 퐃; 퐃; 퐃; ) HANGUL SYLLABLE POC +D404;D404;1111 1169 11BF;D404;1111 1169 11BF; # (퐄; 퐄; 퐄; 퐄; 퐄; ) HANGUL SYLLABLE POK +D405;D405;1111 1169 11C0;D405;1111 1169 11C0; # (퐅; 퐅; 퐅; 퐅; 퐅; ) HANGUL SYLLABLE POT +D406;D406;1111 1169 11C1;D406;1111 1169 11C1; # (퐆; 퐆; 퐆; 퐆; 퐆; ) HANGUL SYLLABLE POP +D407;D407;1111 1169 11C2;D407;1111 1169 11C2; # (퐇; 퐇; 퐇; 퐇; 퐇; ) HANGUL SYLLABLE POH +D408;D408;1111 116A;D408;1111 116A; # (퐈; 퐈; 퐈; 퐈; 퐈; ) HANGUL SYLLABLE PWA +D409;D409;1111 116A 11A8;D409;1111 116A 11A8; # (퐉; 퐉; 퐉; 퐉; 퐉; ) HANGUL SYLLABLE PWAG +D40A;D40A;1111 116A 11A9;D40A;1111 116A 11A9; # (퐊; 퐊; 퐊; 퐊; 퐊; ) HANGUL SYLLABLE PWAGG +D40B;D40B;1111 116A 11AA;D40B;1111 116A 11AA; # (퐋; 퐋; 퐋; 퐋; 퐋; ) HANGUL SYLLABLE PWAGS +D40C;D40C;1111 116A 11AB;D40C;1111 116A 11AB; # (퐌; 퐌; 퐌; 퐌; 퐌; ) HANGUL SYLLABLE PWAN +D40D;D40D;1111 116A 11AC;D40D;1111 116A 11AC; # (퐍; 퐍; 퐍; 퐍; 퐍; ) HANGUL SYLLABLE PWANJ +D40E;D40E;1111 116A 11AD;D40E;1111 116A 11AD; # (퐎; 퐎; 퐎; 퐎; 퐎; ) HANGUL SYLLABLE PWANH +D40F;D40F;1111 116A 11AE;D40F;1111 116A 11AE; # (퐏; 퐏; 퐏; 퐏; 퐏; ) HANGUL SYLLABLE PWAD +D410;D410;1111 116A 11AF;D410;1111 116A 11AF; # (퐐; 퐐; 퐐; 퐐; 퐐; ) HANGUL SYLLABLE PWAL +D411;D411;1111 116A 11B0;D411;1111 116A 11B0; # (퐑; 퐑; 퐑; 퐑; 퐑; ) HANGUL SYLLABLE PWALG +D412;D412;1111 116A 11B1;D412;1111 116A 11B1; # (퐒; 퐒; 퐒; 퐒; 퐒; ) HANGUL SYLLABLE PWALM +D413;D413;1111 116A 11B2;D413;1111 116A 11B2; # (퐓; 퐓; 퐓; 퐓; 퐓; ) HANGUL SYLLABLE PWALB +D414;D414;1111 116A 11B3;D414;1111 116A 11B3; # (퐔; 퐔; 퐔; 퐔; 퐔; ) HANGUL SYLLABLE PWALS +D415;D415;1111 116A 11B4;D415;1111 116A 11B4; # (퐕; 퐕; 퐕; 퐕; 퐕; ) HANGUL SYLLABLE PWALT +D416;D416;1111 116A 11B5;D416;1111 116A 11B5; # (퐖; 퐖; 퐖; 퐖; 퐖; ) HANGUL SYLLABLE PWALP +D417;D417;1111 116A 11B6;D417;1111 116A 11B6; # (퐗; 퐗; 퐗; 퐗; 퐗; ) HANGUL SYLLABLE PWALH +D418;D418;1111 116A 11B7;D418;1111 116A 11B7; # (퐘; 퐘; 퐘; 퐘; 퐘; ) HANGUL SYLLABLE PWAM +D419;D419;1111 116A 11B8;D419;1111 116A 11B8; # (퐙; 퐙; 퐙; 퐙; 퐙; ) HANGUL SYLLABLE PWAB +D41A;D41A;1111 116A 11B9;D41A;1111 116A 11B9; # (퐚; 퐚; 퐚; 퐚; 퐚; ) HANGUL SYLLABLE PWABS +D41B;D41B;1111 116A 11BA;D41B;1111 116A 11BA; # (퐛; 퐛; 퐛; 퐛; 퐛; ) HANGUL SYLLABLE PWAS +D41C;D41C;1111 116A 11BB;D41C;1111 116A 11BB; # (퐜; 퐜; 퐜; 퐜; 퐜; ) HANGUL SYLLABLE PWASS +D41D;D41D;1111 116A 11BC;D41D;1111 116A 11BC; # (퐝; 퐝; 퐝; 퐝; 퐝; ) HANGUL SYLLABLE PWANG +D41E;D41E;1111 116A 11BD;D41E;1111 116A 11BD; # (퐞; 퐞; 퐞; 퐞; 퐞; ) HANGUL SYLLABLE PWAJ +D41F;D41F;1111 116A 11BE;D41F;1111 116A 11BE; # (퐟; 퐟; 퐟; 퐟; 퐟; ) HANGUL SYLLABLE PWAC +D420;D420;1111 116A 11BF;D420;1111 116A 11BF; # (퐠; 퐠; 퐠; 퐠; 퐠; ) HANGUL SYLLABLE PWAK +D421;D421;1111 116A 11C0;D421;1111 116A 11C0; # (퐡; 퐡; 퐡; 퐡; 퐡; ) HANGUL SYLLABLE PWAT +D422;D422;1111 116A 11C1;D422;1111 116A 11C1; # (퐢; 퐢; 퐢; 퐢; 퐢; ) HANGUL SYLLABLE PWAP +D423;D423;1111 116A 11C2;D423;1111 116A 11C2; # (퐣; 퐣; 퐣; 퐣; 퐣; ) HANGUL SYLLABLE PWAH +D424;D424;1111 116B;D424;1111 116B; # (퐤; 퐤; 퐤; 퐤; 퐤; ) HANGUL SYLLABLE PWAE +D425;D425;1111 116B 11A8;D425;1111 116B 11A8; # (퐥; 퐥; 퐥; 퐥; 퐥; ) HANGUL SYLLABLE PWAEG +D426;D426;1111 116B 11A9;D426;1111 116B 11A9; # (퐦; 퐦; 퐦; 퐦; 퐦; ) HANGUL SYLLABLE PWAEGG +D427;D427;1111 116B 11AA;D427;1111 116B 11AA; # (퐧; 퐧; 퐧; 퐧; 퐧; ) HANGUL SYLLABLE PWAEGS +D428;D428;1111 116B 11AB;D428;1111 116B 11AB; # (퐨; 퐨; 퐨; 퐨; 퐨; ) HANGUL SYLLABLE PWAEN +D429;D429;1111 116B 11AC;D429;1111 116B 11AC; # (퐩; 퐩; 퐩; 퐩; 퐩; ) HANGUL SYLLABLE PWAENJ +D42A;D42A;1111 116B 11AD;D42A;1111 116B 11AD; # (퐪; 퐪; 퐪; 퐪; 퐪; ) HANGUL SYLLABLE PWAENH +D42B;D42B;1111 116B 11AE;D42B;1111 116B 11AE; # (퐫; 퐫; 퐫; 퐫; 퐫; ) HANGUL SYLLABLE PWAED +D42C;D42C;1111 116B 11AF;D42C;1111 116B 11AF; # (퐬; 퐬; 퐬; 퐬; 퐬; ) HANGUL SYLLABLE PWAEL +D42D;D42D;1111 116B 11B0;D42D;1111 116B 11B0; # (퐭; 퐭; 퐭; 퐭; 퐭; ) HANGUL SYLLABLE PWAELG +D42E;D42E;1111 116B 11B1;D42E;1111 116B 11B1; # (퐮; 퐮; 퐮; 퐮; 퐮; ) HANGUL SYLLABLE PWAELM +D42F;D42F;1111 116B 11B2;D42F;1111 116B 11B2; # (퐯; 퐯; 퐯; 퐯; 퐯; ) HANGUL SYLLABLE PWAELB +D430;D430;1111 116B 11B3;D430;1111 116B 11B3; # (퐰; 퐰; 퐰; 퐰; 퐰; ) HANGUL SYLLABLE PWAELS +D431;D431;1111 116B 11B4;D431;1111 116B 11B4; # (퐱; 퐱; 퐱; 퐱; 퐱; ) HANGUL SYLLABLE PWAELT +D432;D432;1111 116B 11B5;D432;1111 116B 11B5; # (퐲; 퐲; 퐲; 퐲; 퐲; ) HANGUL SYLLABLE PWAELP +D433;D433;1111 116B 11B6;D433;1111 116B 11B6; # (퐳; 퐳; 퐳; 퐳; 퐳; ) HANGUL SYLLABLE PWAELH +D434;D434;1111 116B 11B7;D434;1111 116B 11B7; # (퐴; 퐴; 퐴; 퐴; 퐴; ) HANGUL SYLLABLE PWAEM +D435;D435;1111 116B 11B8;D435;1111 116B 11B8; # (퐵; 퐵; 퐵; 퐵; 퐵; ) HANGUL SYLLABLE PWAEB +D436;D436;1111 116B 11B9;D436;1111 116B 11B9; # (퐶; 퐶; 퐶; 퐶; 퐶; ) HANGUL SYLLABLE PWAEBS +D437;D437;1111 116B 11BA;D437;1111 116B 11BA; # (퐷; 퐷; 퐷; 퐷; 퐷; ) HANGUL SYLLABLE PWAES +D438;D438;1111 116B 11BB;D438;1111 116B 11BB; # (퐸; 퐸; 퐸; 퐸; 퐸; ) HANGUL SYLLABLE PWAESS +D439;D439;1111 116B 11BC;D439;1111 116B 11BC; # (퐹; 퐹; 퐹; 퐹; 퐹; ) HANGUL SYLLABLE PWAENG +D43A;D43A;1111 116B 11BD;D43A;1111 116B 11BD; # (퐺; 퐺; 퐺; 퐺; 퐺; ) HANGUL SYLLABLE PWAEJ +D43B;D43B;1111 116B 11BE;D43B;1111 116B 11BE; # (퐻; 퐻; 퐻; 퐻; 퐻; ) HANGUL SYLLABLE PWAEC +D43C;D43C;1111 116B 11BF;D43C;1111 116B 11BF; # (퐼; 퐼; 퐼; 퐼; 퐼; ) HANGUL SYLLABLE PWAEK +D43D;D43D;1111 116B 11C0;D43D;1111 116B 11C0; # (퐽; 퐽; 퐽; 퐽; 퐽; ) HANGUL SYLLABLE PWAET +D43E;D43E;1111 116B 11C1;D43E;1111 116B 11C1; # (퐾; 퐾; 퐾; 퐾; 퐾; ) HANGUL SYLLABLE PWAEP +D43F;D43F;1111 116B 11C2;D43F;1111 116B 11C2; # (퐿; 퐿; 퐿; 퐿; 퐿; ) HANGUL SYLLABLE PWAEH +D440;D440;1111 116C;D440;1111 116C; # (푀; 푀; 푀; 푀; 푀; ) HANGUL SYLLABLE POE +D441;D441;1111 116C 11A8;D441;1111 116C 11A8; # (푁; 푁; 푁; 푁; 푁; ) HANGUL SYLLABLE POEG +D442;D442;1111 116C 11A9;D442;1111 116C 11A9; # (푂; 푂; 푂; 푂; 푂; ) HANGUL SYLLABLE POEGG +D443;D443;1111 116C 11AA;D443;1111 116C 11AA; # (푃; 푃; 푃; 푃; 푃; ) HANGUL SYLLABLE POEGS +D444;D444;1111 116C 11AB;D444;1111 116C 11AB; # (푄; 푄; 푄; 푄; 푄; ) HANGUL SYLLABLE POEN +D445;D445;1111 116C 11AC;D445;1111 116C 11AC; # (푅; 푅; 푅; 푅; 푅; ) HANGUL SYLLABLE POENJ +D446;D446;1111 116C 11AD;D446;1111 116C 11AD; # (푆; 푆; 푆; 푆; 푆; ) HANGUL SYLLABLE POENH +D447;D447;1111 116C 11AE;D447;1111 116C 11AE; # (푇; 푇; 푇; 푇; 푇; ) HANGUL SYLLABLE POED +D448;D448;1111 116C 11AF;D448;1111 116C 11AF; # (푈; 푈; 푈; 푈; 푈; ) HANGUL SYLLABLE POEL +D449;D449;1111 116C 11B0;D449;1111 116C 11B0; # (푉; 푉; 푉; 푉; 푉; ) HANGUL SYLLABLE POELG +D44A;D44A;1111 116C 11B1;D44A;1111 116C 11B1; # (푊; 푊; 푊; 푊; 푊; ) HANGUL SYLLABLE POELM +D44B;D44B;1111 116C 11B2;D44B;1111 116C 11B2; # (푋; 푋; 푋; 푋; 푋; ) HANGUL SYLLABLE POELB +D44C;D44C;1111 116C 11B3;D44C;1111 116C 11B3; # (푌; 푌; 푌; 푌; 푌; ) HANGUL SYLLABLE POELS +D44D;D44D;1111 116C 11B4;D44D;1111 116C 11B4; # (푍; 푍; 푍; 푍; 푍; ) HANGUL SYLLABLE POELT +D44E;D44E;1111 116C 11B5;D44E;1111 116C 11B5; # (푎; 푎; 푎; 푎; 푎; ) HANGUL SYLLABLE POELP +D44F;D44F;1111 116C 11B6;D44F;1111 116C 11B6; # (푏; 푏; 푏; 푏; 푏; ) HANGUL SYLLABLE POELH +D450;D450;1111 116C 11B7;D450;1111 116C 11B7; # (푐; 푐; 푐; 푐; 푐; ) HANGUL SYLLABLE POEM +D451;D451;1111 116C 11B8;D451;1111 116C 11B8; # (푑; 푑; 푑; 푑; 푑; ) HANGUL SYLLABLE POEB +D452;D452;1111 116C 11B9;D452;1111 116C 11B9; # (푒; 푒; 푒; 푒; 푒; ) HANGUL SYLLABLE POEBS +D453;D453;1111 116C 11BA;D453;1111 116C 11BA; # (푓; 푓; 푓; 푓; 푓; ) HANGUL SYLLABLE POES +D454;D454;1111 116C 11BB;D454;1111 116C 11BB; # (푔; 푔; 푔; 푔; 푔; ) HANGUL SYLLABLE POESS +D455;D455;1111 116C 11BC;D455;1111 116C 11BC; # (푕; 푕; 푕; 푕; 푕; ) HANGUL SYLLABLE POENG +D456;D456;1111 116C 11BD;D456;1111 116C 11BD; # (푖; 푖; 푖; 푖; 푖; ) HANGUL SYLLABLE POEJ +D457;D457;1111 116C 11BE;D457;1111 116C 11BE; # (푗; 푗; 푗; 푗; 푗; ) HANGUL SYLLABLE POEC +D458;D458;1111 116C 11BF;D458;1111 116C 11BF; # (푘; 푘; 푘; 푘; 푘; ) HANGUL SYLLABLE POEK +D459;D459;1111 116C 11C0;D459;1111 116C 11C0; # (푙; 푙; 푙; 푙; 푙; ) HANGUL SYLLABLE POET +D45A;D45A;1111 116C 11C1;D45A;1111 116C 11C1; # (푚; 푚; 푚; 푚; 푚; ) HANGUL SYLLABLE POEP +D45B;D45B;1111 116C 11C2;D45B;1111 116C 11C2; # (푛; 푛; 푛; 푛; 푛; ) HANGUL SYLLABLE POEH +D45C;D45C;1111 116D;D45C;1111 116D; # (표; 표; 표; 표; 표; ) HANGUL SYLLABLE PYO +D45D;D45D;1111 116D 11A8;D45D;1111 116D 11A8; # (푝; 푝; 푝; 푝; 푝; ) HANGUL SYLLABLE PYOG +D45E;D45E;1111 116D 11A9;D45E;1111 116D 11A9; # (푞; 푞; 푞; 푞; 푞; ) HANGUL SYLLABLE PYOGG +D45F;D45F;1111 116D 11AA;D45F;1111 116D 11AA; # (푟; 푟; 푟; 푟; 푟; ) HANGUL SYLLABLE PYOGS +D460;D460;1111 116D 11AB;D460;1111 116D 11AB; # (푠; 푠; 푠; 푠; 푠; ) HANGUL SYLLABLE PYON +D461;D461;1111 116D 11AC;D461;1111 116D 11AC; # (푡; 푡; 푡; 푡; 푡; ) HANGUL SYLLABLE PYONJ +D462;D462;1111 116D 11AD;D462;1111 116D 11AD; # (푢; 푢; 푢; 푢; 푢; ) HANGUL SYLLABLE PYONH +D463;D463;1111 116D 11AE;D463;1111 116D 11AE; # (푣; 푣; 푣; 푣; 푣; ) HANGUL SYLLABLE PYOD +D464;D464;1111 116D 11AF;D464;1111 116D 11AF; # (푤; 푤; 푤; 푤; 푤; ) HANGUL SYLLABLE PYOL +D465;D465;1111 116D 11B0;D465;1111 116D 11B0; # (푥; 푥; 푥; 푥; 푥; ) HANGUL SYLLABLE PYOLG +D466;D466;1111 116D 11B1;D466;1111 116D 11B1; # (푦; 푦; 푦; 푦; 푦; ) HANGUL SYLLABLE PYOLM +D467;D467;1111 116D 11B2;D467;1111 116D 11B2; # (푧; 푧; 푧; 푧; 푧; ) HANGUL SYLLABLE PYOLB +D468;D468;1111 116D 11B3;D468;1111 116D 11B3; # (푨; 푨; 푨; 푨; 푨; ) HANGUL SYLLABLE PYOLS +D469;D469;1111 116D 11B4;D469;1111 116D 11B4; # (푩; 푩; 푩; 푩; 푩; ) HANGUL SYLLABLE PYOLT +D46A;D46A;1111 116D 11B5;D46A;1111 116D 11B5; # (푪; 푪; 푪; 푪; 푪; ) HANGUL SYLLABLE PYOLP +D46B;D46B;1111 116D 11B6;D46B;1111 116D 11B6; # (푫; 푫; 푫; 푫; 푫; ) HANGUL SYLLABLE PYOLH +D46C;D46C;1111 116D 11B7;D46C;1111 116D 11B7; # (푬; 푬; 푬; 푬; 푬; ) HANGUL SYLLABLE PYOM +D46D;D46D;1111 116D 11B8;D46D;1111 116D 11B8; # (푭; 푭; 푭; 푭; 푭; ) HANGUL SYLLABLE PYOB +D46E;D46E;1111 116D 11B9;D46E;1111 116D 11B9; # (푮; 푮; 푮; 푮; 푮; ) HANGUL SYLLABLE PYOBS +D46F;D46F;1111 116D 11BA;D46F;1111 116D 11BA; # (푯; 푯; 푯; 푯; 푯; ) HANGUL SYLLABLE PYOS +D470;D470;1111 116D 11BB;D470;1111 116D 11BB; # (푰; 푰; 푰; 푰; 푰; ) HANGUL SYLLABLE PYOSS +D471;D471;1111 116D 11BC;D471;1111 116D 11BC; # (푱; 푱; 푱; 푱; 푱; ) HANGUL SYLLABLE PYONG +D472;D472;1111 116D 11BD;D472;1111 116D 11BD; # (푲; 푲; 푲; 푲; 푲; ) HANGUL SYLLABLE PYOJ +D473;D473;1111 116D 11BE;D473;1111 116D 11BE; # (푳; 푳; 푳; 푳; 푳; ) HANGUL SYLLABLE PYOC +D474;D474;1111 116D 11BF;D474;1111 116D 11BF; # (푴; 푴; 푴; 푴; 푴; ) HANGUL SYLLABLE PYOK +D475;D475;1111 116D 11C0;D475;1111 116D 11C0; # (푵; 푵; 푵; 푵; 푵; ) HANGUL SYLLABLE PYOT +D476;D476;1111 116D 11C1;D476;1111 116D 11C1; # (푶; 푶; 푶; 푶; 푶; ) HANGUL SYLLABLE PYOP +D477;D477;1111 116D 11C2;D477;1111 116D 11C2; # (푷; 푷; 푷; 푷; 푷; ) HANGUL SYLLABLE PYOH +D478;D478;1111 116E;D478;1111 116E; # (푸; 푸; 푸; 푸; 푸; ) HANGUL SYLLABLE PU +D479;D479;1111 116E 11A8;D479;1111 116E 11A8; # (푹; 푹; 푹; 푹; 푹; ) HANGUL SYLLABLE PUG +D47A;D47A;1111 116E 11A9;D47A;1111 116E 11A9; # (푺; 푺; 푺; 푺; 푺; ) HANGUL SYLLABLE PUGG +D47B;D47B;1111 116E 11AA;D47B;1111 116E 11AA; # (푻; 푻; 푻; 푻; 푻; ) HANGUL SYLLABLE PUGS +D47C;D47C;1111 116E 11AB;D47C;1111 116E 11AB; # (푼; 푼; 푼; 푼; 푼; ) HANGUL SYLLABLE PUN +D47D;D47D;1111 116E 11AC;D47D;1111 116E 11AC; # (푽; 푽; 푽; 푽; 푽; ) HANGUL SYLLABLE PUNJ +D47E;D47E;1111 116E 11AD;D47E;1111 116E 11AD; # (푾; 푾; 푾; 푾; 푾; ) HANGUL SYLLABLE PUNH +D47F;D47F;1111 116E 11AE;D47F;1111 116E 11AE; # (푿; 푿; 푿; 푿; 푿; ) HANGUL SYLLABLE PUD +D480;D480;1111 116E 11AF;D480;1111 116E 11AF; # (풀; 풀; 풀; 풀; 풀; ) HANGUL SYLLABLE PUL +D481;D481;1111 116E 11B0;D481;1111 116E 11B0; # (풁; 풁; 풁; 풁; 풁; ) HANGUL SYLLABLE PULG +D482;D482;1111 116E 11B1;D482;1111 116E 11B1; # (풂; 풂; 풂; 풂; 풂; ) HANGUL SYLLABLE PULM +D483;D483;1111 116E 11B2;D483;1111 116E 11B2; # (풃; 풃; 풃; 풃; 풃; ) HANGUL SYLLABLE PULB +D484;D484;1111 116E 11B3;D484;1111 116E 11B3; # (풄; 풄; 풄; 풄; 풄; ) HANGUL SYLLABLE PULS +D485;D485;1111 116E 11B4;D485;1111 116E 11B4; # (풅; 풅; 풅; 풅; 풅; ) HANGUL SYLLABLE PULT +D486;D486;1111 116E 11B5;D486;1111 116E 11B5; # (풆; 풆; 풆; 풆; 풆; ) HANGUL SYLLABLE PULP +D487;D487;1111 116E 11B6;D487;1111 116E 11B6; # (풇; 풇; 풇; 풇; 풇; ) HANGUL SYLLABLE PULH +D488;D488;1111 116E 11B7;D488;1111 116E 11B7; # (품; 품; 품; 품; 품; ) HANGUL SYLLABLE PUM +D489;D489;1111 116E 11B8;D489;1111 116E 11B8; # (풉; 풉; 풉; 풉; 풉; ) HANGUL SYLLABLE PUB +D48A;D48A;1111 116E 11B9;D48A;1111 116E 11B9; # (풊; 풊; 풊; 풊; 풊; ) HANGUL SYLLABLE PUBS +D48B;D48B;1111 116E 11BA;D48B;1111 116E 11BA; # (풋; 풋; 풋; 풋; 풋; ) HANGUL SYLLABLE PUS +D48C;D48C;1111 116E 11BB;D48C;1111 116E 11BB; # (풌; 풌; 풌; 풌; 풌; ) HANGUL SYLLABLE PUSS +D48D;D48D;1111 116E 11BC;D48D;1111 116E 11BC; # (풍; 풍; 풍; 풍; 풍; ) HANGUL SYLLABLE PUNG +D48E;D48E;1111 116E 11BD;D48E;1111 116E 11BD; # (풎; 풎; 풎; 풎; 풎; ) HANGUL SYLLABLE PUJ +D48F;D48F;1111 116E 11BE;D48F;1111 116E 11BE; # (풏; 풏; 풏; 풏; 풏; ) HANGUL SYLLABLE PUC +D490;D490;1111 116E 11BF;D490;1111 116E 11BF; # (풐; 풐; 풐; 풐; 풐; ) HANGUL SYLLABLE PUK +D491;D491;1111 116E 11C0;D491;1111 116E 11C0; # (풑; 풑; 풑; 풑; 풑; ) HANGUL SYLLABLE PUT +D492;D492;1111 116E 11C1;D492;1111 116E 11C1; # (풒; 풒; 풒; 풒; 풒; ) HANGUL SYLLABLE PUP +D493;D493;1111 116E 11C2;D493;1111 116E 11C2; # (풓; 풓; 풓; 풓; 풓; ) HANGUL SYLLABLE PUH +D494;D494;1111 116F;D494;1111 116F; # (풔; 풔; 풔; 풔; 풔; ) HANGUL SYLLABLE PWEO +D495;D495;1111 116F 11A8;D495;1111 116F 11A8; # (풕; 풕; 풕; 풕; 풕; ) HANGUL SYLLABLE PWEOG +D496;D496;1111 116F 11A9;D496;1111 116F 11A9; # (풖; 풖; 풖; 풖; 풖; ) HANGUL SYLLABLE PWEOGG +D497;D497;1111 116F 11AA;D497;1111 116F 11AA; # (풗; 풗; 풗; 풗; 풗; ) HANGUL SYLLABLE PWEOGS +D498;D498;1111 116F 11AB;D498;1111 116F 11AB; # (풘; 풘; 풘; 풘; 풘; ) HANGUL SYLLABLE PWEON +D499;D499;1111 116F 11AC;D499;1111 116F 11AC; # (풙; 풙; 풙; 풙; 풙; ) HANGUL SYLLABLE PWEONJ +D49A;D49A;1111 116F 11AD;D49A;1111 116F 11AD; # (풚; 풚; 풚; 풚; 풚; ) HANGUL SYLLABLE PWEONH +D49B;D49B;1111 116F 11AE;D49B;1111 116F 11AE; # (풛; 풛; 풛; 풛; 풛; ) HANGUL SYLLABLE PWEOD +D49C;D49C;1111 116F 11AF;D49C;1111 116F 11AF; # (풜; 풜; 풜; 풜; 풜; ) HANGUL SYLLABLE PWEOL +D49D;D49D;1111 116F 11B0;D49D;1111 116F 11B0; # (풝; 풝; 풝; 풝; 풝; ) HANGUL SYLLABLE PWEOLG +D49E;D49E;1111 116F 11B1;D49E;1111 116F 11B1; # (풞; 풞; 풞; 풞; 풞; ) HANGUL SYLLABLE PWEOLM +D49F;D49F;1111 116F 11B2;D49F;1111 116F 11B2; # (풟; 풟; 풟; 풟; 풟; ) HANGUL SYLLABLE PWEOLB +D4A0;D4A0;1111 116F 11B3;D4A0;1111 116F 11B3; # (풠; 풠; 풠; 풠; 풠; ) HANGUL SYLLABLE PWEOLS +D4A1;D4A1;1111 116F 11B4;D4A1;1111 116F 11B4; # (풡; 풡; 풡; 풡; 풡; ) HANGUL SYLLABLE PWEOLT +D4A2;D4A2;1111 116F 11B5;D4A2;1111 116F 11B5; # (풢; 풢; 풢; 풢; 풢; ) HANGUL SYLLABLE PWEOLP +D4A3;D4A3;1111 116F 11B6;D4A3;1111 116F 11B6; # (풣; 풣; 풣; 풣; 풣; ) HANGUL SYLLABLE PWEOLH +D4A4;D4A4;1111 116F 11B7;D4A4;1111 116F 11B7; # (풤; 풤; 풤; 풤; 풤; ) HANGUL SYLLABLE PWEOM +D4A5;D4A5;1111 116F 11B8;D4A5;1111 116F 11B8; # (풥; 풥; 풥; 풥; 풥; ) HANGUL SYLLABLE PWEOB +D4A6;D4A6;1111 116F 11B9;D4A6;1111 116F 11B9; # (풦; 풦; 풦; 풦; 풦; ) HANGUL SYLLABLE PWEOBS +D4A7;D4A7;1111 116F 11BA;D4A7;1111 116F 11BA; # (풧; 풧; 풧; 풧; 풧; ) HANGUL SYLLABLE PWEOS +D4A8;D4A8;1111 116F 11BB;D4A8;1111 116F 11BB; # (풨; 풨; 풨; 풨; 풨; ) HANGUL SYLLABLE PWEOSS +D4A9;D4A9;1111 116F 11BC;D4A9;1111 116F 11BC; # (풩; 풩; 풩; 풩; 풩; ) HANGUL SYLLABLE PWEONG +D4AA;D4AA;1111 116F 11BD;D4AA;1111 116F 11BD; # (풪; 풪; 풪; 풪; 풪; ) HANGUL SYLLABLE PWEOJ +D4AB;D4AB;1111 116F 11BE;D4AB;1111 116F 11BE; # (풫; 풫; 풫; 풫; 풫; ) HANGUL SYLLABLE PWEOC +D4AC;D4AC;1111 116F 11BF;D4AC;1111 116F 11BF; # (풬; 풬; 풬; 풬; 풬; ) HANGUL SYLLABLE PWEOK +D4AD;D4AD;1111 116F 11C0;D4AD;1111 116F 11C0; # (풭; 풭; 풭; 풭; 풭; ) HANGUL SYLLABLE PWEOT +D4AE;D4AE;1111 116F 11C1;D4AE;1111 116F 11C1; # (풮; 풮; 풮; 풮; 풮; ) HANGUL SYLLABLE PWEOP +D4AF;D4AF;1111 116F 11C2;D4AF;1111 116F 11C2; # (풯; 풯; 풯; 풯; 풯; ) HANGUL SYLLABLE PWEOH +D4B0;D4B0;1111 1170;D4B0;1111 1170; # (풰; 풰; 풰; 풰; 풰; ) HANGUL SYLLABLE PWE +D4B1;D4B1;1111 1170 11A8;D4B1;1111 1170 11A8; # (풱; 풱; 풱; 풱; 풱; ) HANGUL SYLLABLE PWEG +D4B2;D4B2;1111 1170 11A9;D4B2;1111 1170 11A9; # (풲; 풲; 풲; 풲; 풲; ) HANGUL SYLLABLE PWEGG +D4B3;D4B3;1111 1170 11AA;D4B3;1111 1170 11AA; # (풳; 풳; 풳; 풳; 풳; ) HANGUL SYLLABLE PWEGS +D4B4;D4B4;1111 1170 11AB;D4B4;1111 1170 11AB; # (풴; 풴; 풴; 풴; 풴; ) HANGUL SYLLABLE PWEN +D4B5;D4B5;1111 1170 11AC;D4B5;1111 1170 11AC; # (풵; 풵; 풵; 풵; 풵; ) HANGUL SYLLABLE PWENJ +D4B6;D4B6;1111 1170 11AD;D4B6;1111 1170 11AD; # (풶; 풶; 풶; 풶; 풶; ) HANGUL SYLLABLE PWENH +D4B7;D4B7;1111 1170 11AE;D4B7;1111 1170 11AE; # (풷; 풷; 풷; 풷; 풷; ) HANGUL SYLLABLE PWED +D4B8;D4B8;1111 1170 11AF;D4B8;1111 1170 11AF; # (풸; 풸; 풸; 풸; 풸; ) HANGUL SYLLABLE PWEL +D4B9;D4B9;1111 1170 11B0;D4B9;1111 1170 11B0; # (풹; 풹; 풹; 풹; 풹; ) HANGUL SYLLABLE PWELG +D4BA;D4BA;1111 1170 11B1;D4BA;1111 1170 11B1; # (풺; 풺; 풺; 풺; 풺; ) HANGUL SYLLABLE PWELM +D4BB;D4BB;1111 1170 11B2;D4BB;1111 1170 11B2; # (풻; 풻; 풻; 풻; 풻; ) HANGUL SYLLABLE PWELB +D4BC;D4BC;1111 1170 11B3;D4BC;1111 1170 11B3; # (풼; 풼; 풼; 풼; 풼; ) HANGUL SYLLABLE PWELS +D4BD;D4BD;1111 1170 11B4;D4BD;1111 1170 11B4; # (풽; 풽; 풽; 풽; 풽; ) HANGUL SYLLABLE PWELT +D4BE;D4BE;1111 1170 11B5;D4BE;1111 1170 11B5; # (풾; 풾; 풾; 풾; 풾; ) HANGUL SYLLABLE PWELP +D4BF;D4BF;1111 1170 11B6;D4BF;1111 1170 11B6; # (풿; 풿; 풿; 풿; 풿; ) HANGUL SYLLABLE PWELH +D4C0;D4C0;1111 1170 11B7;D4C0;1111 1170 11B7; # (퓀; 퓀; 퓀; 퓀; 퓀; ) HANGUL SYLLABLE PWEM +D4C1;D4C1;1111 1170 11B8;D4C1;1111 1170 11B8; # (퓁; 퓁; 퓁; 퓁; 퓁; ) HANGUL SYLLABLE PWEB +D4C2;D4C2;1111 1170 11B9;D4C2;1111 1170 11B9; # (퓂; 퓂; 퓂; 퓂; 퓂; ) HANGUL SYLLABLE PWEBS +D4C3;D4C3;1111 1170 11BA;D4C3;1111 1170 11BA; # (퓃; 퓃; 퓃; 퓃; 퓃; ) HANGUL SYLLABLE PWES +D4C4;D4C4;1111 1170 11BB;D4C4;1111 1170 11BB; # (퓄; 퓄; 퓄; 퓄; 퓄; ) HANGUL SYLLABLE PWESS +D4C5;D4C5;1111 1170 11BC;D4C5;1111 1170 11BC; # (퓅; 퓅; 퓅; 퓅; 퓅; ) HANGUL SYLLABLE PWENG +D4C6;D4C6;1111 1170 11BD;D4C6;1111 1170 11BD; # (퓆; 퓆; 퓆; 퓆; 퓆; ) HANGUL SYLLABLE PWEJ +D4C7;D4C7;1111 1170 11BE;D4C7;1111 1170 11BE; # (퓇; 퓇; 퓇; 퓇; 퓇; ) HANGUL SYLLABLE PWEC +D4C8;D4C8;1111 1170 11BF;D4C8;1111 1170 11BF; # (퓈; 퓈; 퓈; 퓈; 퓈; ) HANGUL SYLLABLE PWEK +D4C9;D4C9;1111 1170 11C0;D4C9;1111 1170 11C0; # (퓉; 퓉; 퓉; 퓉; 퓉; ) HANGUL SYLLABLE PWET +D4CA;D4CA;1111 1170 11C1;D4CA;1111 1170 11C1; # (퓊; 퓊; 퓊; 퓊; 퓊; ) HANGUL SYLLABLE PWEP +D4CB;D4CB;1111 1170 11C2;D4CB;1111 1170 11C2; # (퓋; 퓋; 퓋; 퓋; 퓋; ) HANGUL SYLLABLE PWEH +D4CC;D4CC;1111 1171;D4CC;1111 1171; # (퓌; 퓌; 퓌; 퓌; 퓌; ) HANGUL SYLLABLE PWI +D4CD;D4CD;1111 1171 11A8;D4CD;1111 1171 11A8; # (퓍; 퓍; 퓍; 퓍; 퓍; ) HANGUL SYLLABLE PWIG +D4CE;D4CE;1111 1171 11A9;D4CE;1111 1171 11A9; # (퓎; 퓎; 퓎; 퓎; 퓎; ) HANGUL SYLLABLE PWIGG +D4CF;D4CF;1111 1171 11AA;D4CF;1111 1171 11AA; # (퓏; 퓏; 퓏; 퓏; 퓏; ) HANGUL SYLLABLE PWIGS +D4D0;D4D0;1111 1171 11AB;D4D0;1111 1171 11AB; # (퓐; 퓐; 퓐; 퓐; 퓐; ) HANGUL SYLLABLE PWIN +D4D1;D4D1;1111 1171 11AC;D4D1;1111 1171 11AC; # (퓑; 퓑; 퓑; 퓑; 퓑; ) HANGUL SYLLABLE PWINJ +D4D2;D4D2;1111 1171 11AD;D4D2;1111 1171 11AD; # (퓒; 퓒; 퓒; 퓒; 퓒; ) HANGUL SYLLABLE PWINH +D4D3;D4D3;1111 1171 11AE;D4D3;1111 1171 11AE; # (퓓; 퓓; 퓓; 퓓; 퓓; ) HANGUL SYLLABLE PWID +D4D4;D4D4;1111 1171 11AF;D4D4;1111 1171 11AF; # (퓔; 퓔; 퓔; 퓔; 퓔; ) HANGUL SYLLABLE PWIL +D4D5;D4D5;1111 1171 11B0;D4D5;1111 1171 11B0; # (퓕; 퓕; 퓕; 퓕; 퓕; ) HANGUL SYLLABLE PWILG +D4D6;D4D6;1111 1171 11B1;D4D6;1111 1171 11B1; # (퓖; 퓖; 퓖; 퓖; 퓖; ) HANGUL SYLLABLE PWILM +D4D7;D4D7;1111 1171 11B2;D4D7;1111 1171 11B2; # (퓗; 퓗; 퓗; 퓗; 퓗; ) HANGUL SYLLABLE PWILB +D4D8;D4D8;1111 1171 11B3;D4D8;1111 1171 11B3; # (퓘; 퓘; 퓘; 퓘; 퓘; ) HANGUL SYLLABLE PWILS +D4D9;D4D9;1111 1171 11B4;D4D9;1111 1171 11B4; # (퓙; 퓙; 퓙; 퓙; 퓙; ) HANGUL SYLLABLE PWILT +D4DA;D4DA;1111 1171 11B5;D4DA;1111 1171 11B5; # (퓚; 퓚; 퓚; 퓚; 퓚; ) HANGUL SYLLABLE PWILP +D4DB;D4DB;1111 1171 11B6;D4DB;1111 1171 11B6; # (퓛; 퓛; 퓛; 퓛; 퓛; ) HANGUL SYLLABLE PWILH +D4DC;D4DC;1111 1171 11B7;D4DC;1111 1171 11B7; # (퓜; 퓜; 퓜; 퓜; 퓜; ) HANGUL SYLLABLE PWIM +D4DD;D4DD;1111 1171 11B8;D4DD;1111 1171 11B8; # (퓝; 퓝; 퓝; 퓝; 퓝; ) HANGUL SYLLABLE PWIB +D4DE;D4DE;1111 1171 11B9;D4DE;1111 1171 11B9; # (퓞; 퓞; 퓞; 퓞; 퓞; ) HANGUL SYLLABLE PWIBS +D4DF;D4DF;1111 1171 11BA;D4DF;1111 1171 11BA; # (퓟; 퓟; 퓟; 퓟; 퓟; ) HANGUL SYLLABLE PWIS +D4E0;D4E0;1111 1171 11BB;D4E0;1111 1171 11BB; # (퓠; 퓠; 퓠; 퓠; 퓠; ) HANGUL SYLLABLE PWISS +D4E1;D4E1;1111 1171 11BC;D4E1;1111 1171 11BC; # (퓡; 퓡; 퓡; 퓡; 퓡; ) HANGUL SYLLABLE PWING +D4E2;D4E2;1111 1171 11BD;D4E2;1111 1171 11BD; # (퓢; 퓢; 퓢; 퓢; 퓢; ) HANGUL SYLLABLE PWIJ +D4E3;D4E3;1111 1171 11BE;D4E3;1111 1171 11BE; # (퓣; 퓣; 퓣; 퓣; 퓣; ) HANGUL SYLLABLE PWIC +D4E4;D4E4;1111 1171 11BF;D4E4;1111 1171 11BF; # (퓤; 퓤; 퓤; 퓤; 퓤; ) HANGUL SYLLABLE PWIK +D4E5;D4E5;1111 1171 11C0;D4E5;1111 1171 11C0; # (퓥; 퓥; 퓥; 퓥; 퓥; ) HANGUL SYLLABLE PWIT +D4E6;D4E6;1111 1171 11C1;D4E6;1111 1171 11C1; # (퓦; 퓦; 퓦; 퓦; 퓦; ) HANGUL SYLLABLE PWIP +D4E7;D4E7;1111 1171 11C2;D4E7;1111 1171 11C2; # (퓧; 퓧; 퓧; 퓧; 퓧; ) HANGUL SYLLABLE PWIH +D4E8;D4E8;1111 1172;D4E8;1111 1172; # (퓨; 퓨; 퓨; 퓨; 퓨; ) HANGUL SYLLABLE PYU +D4E9;D4E9;1111 1172 11A8;D4E9;1111 1172 11A8; # (퓩; 퓩; 퓩; 퓩; 퓩; ) HANGUL SYLLABLE PYUG +D4EA;D4EA;1111 1172 11A9;D4EA;1111 1172 11A9; # (퓪; 퓪; 퓪; 퓪; 퓪; ) HANGUL SYLLABLE PYUGG +D4EB;D4EB;1111 1172 11AA;D4EB;1111 1172 11AA; # (퓫; 퓫; 퓫; 퓫; 퓫; ) HANGUL SYLLABLE PYUGS +D4EC;D4EC;1111 1172 11AB;D4EC;1111 1172 11AB; # (퓬; 퓬; 퓬; 퓬; 퓬; ) HANGUL SYLLABLE PYUN +D4ED;D4ED;1111 1172 11AC;D4ED;1111 1172 11AC; # (퓭; 퓭; 퓭; 퓭; 퓭; ) HANGUL SYLLABLE PYUNJ +D4EE;D4EE;1111 1172 11AD;D4EE;1111 1172 11AD; # (퓮; 퓮; 퓮; 퓮; 퓮; ) HANGUL SYLLABLE PYUNH +D4EF;D4EF;1111 1172 11AE;D4EF;1111 1172 11AE; # (퓯; 퓯; 퓯; 퓯; 퓯; ) HANGUL SYLLABLE PYUD +D4F0;D4F0;1111 1172 11AF;D4F0;1111 1172 11AF; # (퓰; 퓰; 퓰; 퓰; 퓰; ) HANGUL SYLLABLE PYUL +D4F1;D4F1;1111 1172 11B0;D4F1;1111 1172 11B0; # (퓱; 퓱; 퓱; 퓱; 퓱; ) HANGUL SYLLABLE PYULG +D4F2;D4F2;1111 1172 11B1;D4F2;1111 1172 11B1; # (퓲; 퓲; 퓲; 퓲; 퓲; ) HANGUL SYLLABLE PYULM +D4F3;D4F3;1111 1172 11B2;D4F3;1111 1172 11B2; # (퓳; 퓳; 퓳; 퓳; 퓳; ) HANGUL SYLLABLE PYULB +D4F4;D4F4;1111 1172 11B3;D4F4;1111 1172 11B3; # (퓴; 퓴; 퓴; 퓴; 퓴; ) HANGUL SYLLABLE PYULS +D4F5;D4F5;1111 1172 11B4;D4F5;1111 1172 11B4; # (퓵; 퓵; 퓵; 퓵; 퓵; ) HANGUL SYLLABLE PYULT +D4F6;D4F6;1111 1172 11B5;D4F6;1111 1172 11B5; # (퓶; 퓶; 퓶; 퓶; 퓶; ) HANGUL SYLLABLE PYULP +D4F7;D4F7;1111 1172 11B6;D4F7;1111 1172 11B6; # (퓷; 퓷; 퓷; 퓷; 퓷; ) HANGUL SYLLABLE PYULH +D4F8;D4F8;1111 1172 11B7;D4F8;1111 1172 11B7; # (퓸; 퓸; 퓸; 퓸; 퓸; ) HANGUL SYLLABLE PYUM +D4F9;D4F9;1111 1172 11B8;D4F9;1111 1172 11B8; # (퓹; 퓹; 퓹; 퓹; 퓹; ) HANGUL SYLLABLE PYUB +D4FA;D4FA;1111 1172 11B9;D4FA;1111 1172 11B9; # (퓺; 퓺; 퓺; 퓺; 퓺; ) HANGUL SYLLABLE PYUBS +D4FB;D4FB;1111 1172 11BA;D4FB;1111 1172 11BA; # (퓻; 퓻; 퓻; 퓻; 퓻; ) HANGUL SYLLABLE PYUS +D4FC;D4FC;1111 1172 11BB;D4FC;1111 1172 11BB; # (퓼; 퓼; 퓼; 퓼; 퓼; ) HANGUL SYLLABLE PYUSS +D4FD;D4FD;1111 1172 11BC;D4FD;1111 1172 11BC; # (퓽; 퓽; 퓽; 퓽; 퓽; ) HANGUL SYLLABLE PYUNG +D4FE;D4FE;1111 1172 11BD;D4FE;1111 1172 11BD; # (퓾; 퓾; 퓾; 퓾; 퓾; ) HANGUL SYLLABLE PYUJ +D4FF;D4FF;1111 1172 11BE;D4FF;1111 1172 11BE; # (퓿; 퓿; 퓿; 퓿; 퓿; ) HANGUL SYLLABLE PYUC +D500;D500;1111 1172 11BF;D500;1111 1172 11BF; # (픀; 픀; 픀; 픀; 픀; ) HANGUL SYLLABLE PYUK +D501;D501;1111 1172 11C0;D501;1111 1172 11C0; # (픁; 픁; 픁; 픁; 픁; ) HANGUL SYLLABLE PYUT +D502;D502;1111 1172 11C1;D502;1111 1172 11C1; # (픂; 픂; 픂; 픂; 픂; ) HANGUL SYLLABLE PYUP +D503;D503;1111 1172 11C2;D503;1111 1172 11C2; # (픃; 픃; 픃; 픃; 픃; ) HANGUL SYLLABLE PYUH +D504;D504;1111 1173;D504;1111 1173; # (프; 프; 프; 프; 프; ) HANGUL SYLLABLE PEU +D505;D505;1111 1173 11A8;D505;1111 1173 11A8; # (픅; 픅; 픅; 픅; 픅; ) HANGUL SYLLABLE PEUG +D506;D506;1111 1173 11A9;D506;1111 1173 11A9; # (픆; 픆; 픆; 픆; 픆; ) HANGUL SYLLABLE PEUGG +D507;D507;1111 1173 11AA;D507;1111 1173 11AA; # (픇; 픇; 픇; 픇; 픇; ) HANGUL SYLLABLE PEUGS +D508;D508;1111 1173 11AB;D508;1111 1173 11AB; # (픈; 픈; 픈; 픈; 픈; ) HANGUL SYLLABLE PEUN +D509;D509;1111 1173 11AC;D509;1111 1173 11AC; # (픉; 픉; 픉; 픉; 픉; ) HANGUL SYLLABLE PEUNJ +D50A;D50A;1111 1173 11AD;D50A;1111 1173 11AD; # (픊; 픊; 픊; 픊; 픊; ) HANGUL SYLLABLE PEUNH +D50B;D50B;1111 1173 11AE;D50B;1111 1173 11AE; # (픋; 픋; 픋; 픋; 픋; ) HANGUL SYLLABLE PEUD +D50C;D50C;1111 1173 11AF;D50C;1111 1173 11AF; # (플; 플; 플; 플; 플; ) HANGUL SYLLABLE PEUL +D50D;D50D;1111 1173 11B0;D50D;1111 1173 11B0; # (픍; 픍; 픍; 픍; 픍; ) HANGUL SYLLABLE PEULG +D50E;D50E;1111 1173 11B1;D50E;1111 1173 11B1; # (픎; 픎; 픎; 픎; 픎; ) HANGUL SYLLABLE PEULM +D50F;D50F;1111 1173 11B2;D50F;1111 1173 11B2; # (픏; 픏; 픏; 픏; 픏; ) HANGUL SYLLABLE PEULB +D510;D510;1111 1173 11B3;D510;1111 1173 11B3; # (픐; 픐; 픐; 픐; 픐; ) HANGUL SYLLABLE PEULS +D511;D511;1111 1173 11B4;D511;1111 1173 11B4; # (픑; 픑; 픑; 픑; 픑; ) HANGUL SYLLABLE PEULT +D512;D512;1111 1173 11B5;D512;1111 1173 11B5; # (픒; 픒; 픒; 픒; 픒; ) HANGUL SYLLABLE PEULP +D513;D513;1111 1173 11B6;D513;1111 1173 11B6; # (픓; 픓; 픓; 픓; 픓; ) HANGUL SYLLABLE PEULH +D514;D514;1111 1173 11B7;D514;1111 1173 11B7; # (픔; 픔; 픔; 픔; 픔; ) HANGUL SYLLABLE PEUM +D515;D515;1111 1173 11B8;D515;1111 1173 11B8; # (픕; 픕; 픕; 픕; 픕; ) HANGUL SYLLABLE PEUB +D516;D516;1111 1173 11B9;D516;1111 1173 11B9; # (픖; 픖; 픖; 픖; 픖; ) HANGUL SYLLABLE PEUBS +D517;D517;1111 1173 11BA;D517;1111 1173 11BA; # (픗; 픗; 픗; 픗; 픗; ) HANGUL SYLLABLE PEUS +D518;D518;1111 1173 11BB;D518;1111 1173 11BB; # (픘; 픘; 픘; 픘; 픘; ) HANGUL SYLLABLE PEUSS +D519;D519;1111 1173 11BC;D519;1111 1173 11BC; # (픙; 픙; 픙; 픙; 픙; ) HANGUL SYLLABLE PEUNG +D51A;D51A;1111 1173 11BD;D51A;1111 1173 11BD; # (픚; 픚; 픚; 픚; 픚; ) HANGUL SYLLABLE PEUJ +D51B;D51B;1111 1173 11BE;D51B;1111 1173 11BE; # (픛; 픛; 픛; 픛; 픛; ) HANGUL SYLLABLE PEUC +D51C;D51C;1111 1173 11BF;D51C;1111 1173 11BF; # (픜; 픜; 픜; 픜; 픜; ) HANGUL SYLLABLE PEUK +D51D;D51D;1111 1173 11C0;D51D;1111 1173 11C0; # (픝; 픝; 픝; 픝; 픝; ) HANGUL SYLLABLE PEUT +D51E;D51E;1111 1173 11C1;D51E;1111 1173 11C1; # (픞; 픞; 픞; 픞; 픞; ) HANGUL SYLLABLE PEUP +D51F;D51F;1111 1173 11C2;D51F;1111 1173 11C2; # (픟; 픟; 픟; 픟; 픟; ) HANGUL SYLLABLE PEUH +D520;D520;1111 1174;D520;1111 1174; # (픠; 픠; 픠; 픠; 픠; ) HANGUL SYLLABLE PYI +D521;D521;1111 1174 11A8;D521;1111 1174 11A8; # (픡; 픡; 픡; 픡; 픡; ) HANGUL SYLLABLE PYIG +D522;D522;1111 1174 11A9;D522;1111 1174 11A9; # (픢; 픢; 픢; 픢; 픢; ) HANGUL SYLLABLE PYIGG +D523;D523;1111 1174 11AA;D523;1111 1174 11AA; # (픣; 픣; 픣; 픣; 픣; ) HANGUL SYLLABLE PYIGS +D524;D524;1111 1174 11AB;D524;1111 1174 11AB; # (픤; 픤; 픤; 픤; 픤; ) HANGUL SYLLABLE PYIN +D525;D525;1111 1174 11AC;D525;1111 1174 11AC; # (픥; 픥; 픥; 픥; 픥; ) HANGUL SYLLABLE PYINJ +D526;D526;1111 1174 11AD;D526;1111 1174 11AD; # (픦; 픦; 픦; 픦; 픦; ) HANGUL SYLLABLE PYINH +D527;D527;1111 1174 11AE;D527;1111 1174 11AE; # (픧; 픧; 픧; 픧; 픧; ) HANGUL SYLLABLE PYID +D528;D528;1111 1174 11AF;D528;1111 1174 11AF; # (픨; 픨; 픨; 픨; 픨; ) HANGUL SYLLABLE PYIL +D529;D529;1111 1174 11B0;D529;1111 1174 11B0; # (픩; 픩; 픩; 픩; 픩; ) HANGUL SYLLABLE PYILG +D52A;D52A;1111 1174 11B1;D52A;1111 1174 11B1; # (픪; 픪; 픪; 픪; 픪; ) HANGUL SYLLABLE PYILM +D52B;D52B;1111 1174 11B2;D52B;1111 1174 11B2; # (픫; 픫; 픫; 픫; 픫; ) HANGUL SYLLABLE PYILB +D52C;D52C;1111 1174 11B3;D52C;1111 1174 11B3; # (픬; 픬; 픬; 픬; 픬; ) HANGUL SYLLABLE PYILS +D52D;D52D;1111 1174 11B4;D52D;1111 1174 11B4; # (픭; 픭; 픭; 픭; 픭; ) HANGUL SYLLABLE PYILT +D52E;D52E;1111 1174 11B5;D52E;1111 1174 11B5; # (픮; 픮; 픮; 픮; 픮; ) HANGUL SYLLABLE PYILP +D52F;D52F;1111 1174 11B6;D52F;1111 1174 11B6; # (픯; 픯; 픯; 픯; 픯; ) HANGUL SYLLABLE PYILH +D530;D530;1111 1174 11B7;D530;1111 1174 11B7; # (픰; 픰; 픰; 픰; 픰; ) HANGUL SYLLABLE PYIM +D531;D531;1111 1174 11B8;D531;1111 1174 11B8; # (픱; 픱; 픱; 픱; 픱; ) HANGUL SYLLABLE PYIB +D532;D532;1111 1174 11B9;D532;1111 1174 11B9; # (픲; 픲; 픲; 픲; 픲; ) HANGUL SYLLABLE PYIBS +D533;D533;1111 1174 11BA;D533;1111 1174 11BA; # (픳; 픳; 픳; 픳; 픳; ) HANGUL SYLLABLE PYIS +D534;D534;1111 1174 11BB;D534;1111 1174 11BB; # (픴; 픴; 픴; 픴; 픴; ) HANGUL SYLLABLE PYISS +D535;D535;1111 1174 11BC;D535;1111 1174 11BC; # (픵; 픵; 픵; 픵; 픵; ) HANGUL SYLLABLE PYING +D536;D536;1111 1174 11BD;D536;1111 1174 11BD; # (픶; 픶; 픶; 픶; 픶; ) HANGUL SYLLABLE PYIJ +D537;D537;1111 1174 11BE;D537;1111 1174 11BE; # (픷; 픷; 픷; 픷; 픷; ) HANGUL SYLLABLE PYIC +D538;D538;1111 1174 11BF;D538;1111 1174 11BF; # (픸; 픸; 픸; 픸; 픸; ) HANGUL SYLLABLE PYIK +D539;D539;1111 1174 11C0;D539;1111 1174 11C0; # (픹; 픹; 픹; 픹; 픹; ) HANGUL SYLLABLE PYIT +D53A;D53A;1111 1174 11C1;D53A;1111 1174 11C1; # (픺; 픺; 픺; 픺; 픺; ) HANGUL SYLLABLE PYIP +D53B;D53B;1111 1174 11C2;D53B;1111 1174 11C2; # (픻; 픻; 픻; 픻; 픻; ) HANGUL SYLLABLE PYIH +D53C;D53C;1111 1175;D53C;1111 1175; # (피; 피; 피; 피; 피; ) HANGUL SYLLABLE PI +D53D;D53D;1111 1175 11A8;D53D;1111 1175 11A8; # (픽; 픽; 픽; 픽; 픽; ) HANGUL SYLLABLE PIG +D53E;D53E;1111 1175 11A9;D53E;1111 1175 11A9; # (픾; 픾; 픾; 픾; 픾; ) HANGUL SYLLABLE PIGG +D53F;D53F;1111 1175 11AA;D53F;1111 1175 11AA; # (픿; 픿; 픿; 픿; 픿; ) HANGUL SYLLABLE PIGS +D540;D540;1111 1175 11AB;D540;1111 1175 11AB; # (핀; 핀; 핀; 핀; 핀; ) HANGUL SYLLABLE PIN +D541;D541;1111 1175 11AC;D541;1111 1175 11AC; # (핁; 핁; 핁; 핁; 핁; ) HANGUL SYLLABLE PINJ +D542;D542;1111 1175 11AD;D542;1111 1175 11AD; # (핂; 핂; 핂; 핂; 핂; ) HANGUL SYLLABLE PINH +D543;D543;1111 1175 11AE;D543;1111 1175 11AE; # (핃; 핃; 핃; 핃; 핃; ) HANGUL SYLLABLE PID +D544;D544;1111 1175 11AF;D544;1111 1175 11AF; # (필; 필; 필; 필; 필; ) HANGUL SYLLABLE PIL +D545;D545;1111 1175 11B0;D545;1111 1175 11B0; # (핅; 핅; 핅; 핅; 핅; ) HANGUL SYLLABLE PILG +D546;D546;1111 1175 11B1;D546;1111 1175 11B1; # (핆; 핆; 핆; 핆; 핆; ) HANGUL SYLLABLE PILM +D547;D547;1111 1175 11B2;D547;1111 1175 11B2; # (핇; 핇; 핇; 핇; 핇; ) HANGUL SYLLABLE PILB +D548;D548;1111 1175 11B3;D548;1111 1175 11B3; # (핈; 핈; 핈; 핈; 핈; ) HANGUL SYLLABLE PILS +D549;D549;1111 1175 11B4;D549;1111 1175 11B4; # (핉; 핉; 핉; 핉; 핉; ) HANGUL SYLLABLE PILT +D54A;D54A;1111 1175 11B5;D54A;1111 1175 11B5; # (핊; 핊; 핊; 핊; 핊; ) HANGUL SYLLABLE PILP +D54B;D54B;1111 1175 11B6;D54B;1111 1175 11B6; # (핋; 핋; 핋; 핋; 핋; ) HANGUL SYLLABLE PILH +D54C;D54C;1111 1175 11B7;D54C;1111 1175 11B7; # (핌; 핌; 핌; 핌; 핌; ) HANGUL SYLLABLE PIM +D54D;D54D;1111 1175 11B8;D54D;1111 1175 11B8; # (핍; 핍; 핍; 핍; 핍; ) HANGUL SYLLABLE PIB +D54E;D54E;1111 1175 11B9;D54E;1111 1175 11B9; # (핎; 핎; 핎; 핎; 핎; ) HANGUL SYLLABLE PIBS +D54F;D54F;1111 1175 11BA;D54F;1111 1175 11BA; # (핏; 핏; 핏; 핏; 핏; ) HANGUL SYLLABLE PIS +D550;D550;1111 1175 11BB;D550;1111 1175 11BB; # (핐; 핐; 핐; 핐; 핐; ) HANGUL SYLLABLE PISS +D551;D551;1111 1175 11BC;D551;1111 1175 11BC; # (핑; 핑; 핑; 핑; 핑; ) HANGUL SYLLABLE PING +D552;D552;1111 1175 11BD;D552;1111 1175 11BD; # (핒; 핒; 핒; 핒; 핒; ) HANGUL SYLLABLE PIJ +D553;D553;1111 1175 11BE;D553;1111 1175 11BE; # (핓; 핓; 핓; 핓; 핓; ) HANGUL SYLLABLE PIC +D554;D554;1111 1175 11BF;D554;1111 1175 11BF; # (핔; 핔; 핔; 핔; 핔; ) HANGUL SYLLABLE PIK +D555;D555;1111 1175 11C0;D555;1111 1175 11C0; # (핕; 핕; 핕; 핕; 핕; ) HANGUL SYLLABLE PIT +D556;D556;1111 1175 11C1;D556;1111 1175 11C1; # (핖; 핖; 핖; 핖; 핖; ) HANGUL SYLLABLE PIP +D557;D557;1111 1175 11C2;D557;1111 1175 11C2; # (핗; 핗; 핗; 핗; 핗; ) HANGUL SYLLABLE PIH +D558;D558;1112 1161;D558;1112 1161; # (하; 하; 하; 하; 하; ) HANGUL SYLLABLE HA +D559;D559;1112 1161 11A8;D559;1112 1161 11A8; # (학; 학; 학; 학; 학; ) HANGUL SYLLABLE HAG +D55A;D55A;1112 1161 11A9;D55A;1112 1161 11A9; # (핚; 핚; 핚; 핚; 핚; ) HANGUL SYLLABLE HAGG +D55B;D55B;1112 1161 11AA;D55B;1112 1161 11AA; # (핛; 핛; 핛; 핛; 핛; ) HANGUL SYLLABLE HAGS +D55C;D55C;1112 1161 11AB;D55C;1112 1161 11AB; # (한; 한; 한; 한; 한; ) HANGUL SYLLABLE HAN +D55D;D55D;1112 1161 11AC;D55D;1112 1161 11AC; # (핝; 핝; 핝; 핝; 핝; ) HANGUL SYLLABLE HANJ +D55E;D55E;1112 1161 11AD;D55E;1112 1161 11AD; # (핞; 핞; 핞; 핞; 핞; ) HANGUL SYLLABLE HANH +D55F;D55F;1112 1161 11AE;D55F;1112 1161 11AE; # (핟; 핟; 핟; 핟; 핟; ) HANGUL SYLLABLE HAD +D560;D560;1112 1161 11AF;D560;1112 1161 11AF; # (할; 할; 할; 할; 할; ) HANGUL SYLLABLE HAL +D561;D561;1112 1161 11B0;D561;1112 1161 11B0; # (핡; 핡; 핡; 핡; 핡; ) HANGUL SYLLABLE HALG +D562;D562;1112 1161 11B1;D562;1112 1161 11B1; # (핢; 핢; 핢; 핢; 핢; ) HANGUL SYLLABLE HALM +D563;D563;1112 1161 11B2;D563;1112 1161 11B2; # (핣; 핣; 핣; 핣; 핣; ) HANGUL SYLLABLE HALB +D564;D564;1112 1161 11B3;D564;1112 1161 11B3; # (핤; 핤; 핤; 핤; 핤; ) HANGUL SYLLABLE HALS +D565;D565;1112 1161 11B4;D565;1112 1161 11B4; # (핥; 핥; 핥; 핥; 핥; ) HANGUL SYLLABLE HALT +D566;D566;1112 1161 11B5;D566;1112 1161 11B5; # (핦; 핦; 핦; 핦; 핦; ) HANGUL SYLLABLE HALP +D567;D567;1112 1161 11B6;D567;1112 1161 11B6; # (핧; 핧; 핧; 핧; 핧; ) HANGUL SYLLABLE HALH +D568;D568;1112 1161 11B7;D568;1112 1161 11B7; # (함; 함; 함; 함; 함; ) HANGUL SYLLABLE HAM +D569;D569;1112 1161 11B8;D569;1112 1161 11B8; # (합; 합; 합; 합; 합; ) HANGUL SYLLABLE HAB +D56A;D56A;1112 1161 11B9;D56A;1112 1161 11B9; # (핪; 핪; 핪; 핪; 핪; ) HANGUL SYLLABLE HABS +D56B;D56B;1112 1161 11BA;D56B;1112 1161 11BA; # (핫; 핫; 핫; 핫; 핫; ) HANGUL SYLLABLE HAS +D56C;D56C;1112 1161 11BB;D56C;1112 1161 11BB; # (핬; 핬; 핬; 핬; 핬; ) HANGUL SYLLABLE HASS +D56D;D56D;1112 1161 11BC;D56D;1112 1161 11BC; # (항; 항; 항; 항; 항; ) HANGUL SYLLABLE HANG +D56E;D56E;1112 1161 11BD;D56E;1112 1161 11BD; # (핮; 핮; 핮; 핮; 핮; ) HANGUL SYLLABLE HAJ +D56F;D56F;1112 1161 11BE;D56F;1112 1161 11BE; # (핯; 핯; 핯; 핯; 핯; ) HANGUL SYLLABLE HAC +D570;D570;1112 1161 11BF;D570;1112 1161 11BF; # (핰; 핰; 핰; 핰; 핰; ) HANGUL SYLLABLE HAK +D571;D571;1112 1161 11C0;D571;1112 1161 11C0; # (핱; 핱; 핱; 핱; 핱; ) HANGUL SYLLABLE HAT +D572;D572;1112 1161 11C1;D572;1112 1161 11C1; # (핲; 핲; 핲; 핲; 핲; ) HANGUL SYLLABLE HAP +D573;D573;1112 1161 11C2;D573;1112 1161 11C2; # (핳; 핳; 핳; 핳; 핳; ) HANGUL SYLLABLE HAH +D574;D574;1112 1162;D574;1112 1162; # (해; 해; 해; 해; 해; ) HANGUL SYLLABLE HAE +D575;D575;1112 1162 11A8;D575;1112 1162 11A8; # (핵; 핵; 핵; 핵; 핵; ) HANGUL SYLLABLE HAEG +D576;D576;1112 1162 11A9;D576;1112 1162 11A9; # (핶; 핶; 핶; 핶; 핶; ) HANGUL SYLLABLE HAEGG +D577;D577;1112 1162 11AA;D577;1112 1162 11AA; # (핷; 핷; 핷; 핷; 핷; ) HANGUL SYLLABLE HAEGS +D578;D578;1112 1162 11AB;D578;1112 1162 11AB; # (핸; 핸; 핸; 핸; 핸; ) HANGUL SYLLABLE HAEN +D579;D579;1112 1162 11AC;D579;1112 1162 11AC; # (핹; 핹; 핹; 핹; 핹; ) HANGUL SYLLABLE HAENJ +D57A;D57A;1112 1162 11AD;D57A;1112 1162 11AD; # (핺; 핺; 핺; 핺; 핺; ) HANGUL SYLLABLE HAENH +D57B;D57B;1112 1162 11AE;D57B;1112 1162 11AE; # (핻; 핻; 핻; 핻; 핻; ) HANGUL SYLLABLE HAED +D57C;D57C;1112 1162 11AF;D57C;1112 1162 11AF; # (핼; 핼; 핼; 핼; 핼; ) HANGUL SYLLABLE HAEL +D57D;D57D;1112 1162 11B0;D57D;1112 1162 11B0; # (핽; 핽; 핽; 핽; 핽; ) HANGUL SYLLABLE HAELG +D57E;D57E;1112 1162 11B1;D57E;1112 1162 11B1; # (핾; 핾; 핾; 핾; 핾; ) HANGUL SYLLABLE HAELM +D57F;D57F;1112 1162 11B2;D57F;1112 1162 11B2; # (핿; 핿; 핿; 핿; 핿; ) HANGUL SYLLABLE HAELB +D580;D580;1112 1162 11B3;D580;1112 1162 11B3; # (햀; 햀; 햀; 햀; 햀; ) HANGUL SYLLABLE HAELS +D581;D581;1112 1162 11B4;D581;1112 1162 11B4; # (햁; 햁; 햁; 햁; 햁; ) HANGUL SYLLABLE HAELT +D582;D582;1112 1162 11B5;D582;1112 1162 11B5; # (햂; 햂; 햂; 햂; 햂; ) HANGUL SYLLABLE HAELP +D583;D583;1112 1162 11B6;D583;1112 1162 11B6; # (햃; 햃; 햃; 햃; 햃; ) HANGUL SYLLABLE HAELH +D584;D584;1112 1162 11B7;D584;1112 1162 11B7; # (햄; 햄; 햄; 햄; 햄; ) HANGUL SYLLABLE HAEM +D585;D585;1112 1162 11B8;D585;1112 1162 11B8; # (햅; 햅; 햅; 햅; 햅; ) HANGUL SYLLABLE HAEB +D586;D586;1112 1162 11B9;D586;1112 1162 11B9; # (햆; 햆; 햆; 햆; 햆; ) HANGUL SYLLABLE HAEBS +D587;D587;1112 1162 11BA;D587;1112 1162 11BA; # (햇; 햇; 햇; 햇; 햇; ) HANGUL SYLLABLE HAES +D588;D588;1112 1162 11BB;D588;1112 1162 11BB; # (했; 했; 했; 했; 했; ) HANGUL SYLLABLE HAESS +D589;D589;1112 1162 11BC;D589;1112 1162 11BC; # (행; 행; 행; 행; 행; ) HANGUL SYLLABLE HAENG +D58A;D58A;1112 1162 11BD;D58A;1112 1162 11BD; # (햊; 햊; 햊; 햊; 햊; ) HANGUL SYLLABLE HAEJ +D58B;D58B;1112 1162 11BE;D58B;1112 1162 11BE; # (햋; 햋; 햋; 햋; 햋; ) HANGUL SYLLABLE HAEC +D58C;D58C;1112 1162 11BF;D58C;1112 1162 11BF; # (햌; 햌; 햌; 햌; 햌; ) HANGUL SYLLABLE HAEK +D58D;D58D;1112 1162 11C0;D58D;1112 1162 11C0; # (햍; 햍; 햍; 햍; 햍; ) HANGUL SYLLABLE HAET +D58E;D58E;1112 1162 11C1;D58E;1112 1162 11C1; # (햎; 햎; 햎; 햎; 햎; ) HANGUL SYLLABLE HAEP +D58F;D58F;1112 1162 11C2;D58F;1112 1162 11C2; # (햏; 햏; 햏; 햏; 햏; ) HANGUL SYLLABLE HAEH +D590;D590;1112 1163;D590;1112 1163; # (햐; 햐; 햐; 햐; 햐; ) HANGUL SYLLABLE HYA +D591;D591;1112 1163 11A8;D591;1112 1163 11A8; # (햑; 햑; 햑; 햑; 햑; ) HANGUL SYLLABLE HYAG +D592;D592;1112 1163 11A9;D592;1112 1163 11A9; # (햒; 햒; 햒; 햒; 햒; ) HANGUL SYLLABLE HYAGG +D593;D593;1112 1163 11AA;D593;1112 1163 11AA; # (햓; 햓; 햓; 햓; 햓; ) HANGUL SYLLABLE HYAGS +D594;D594;1112 1163 11AB;D594;1112 1163 11AB; # (햔; 햔; 햔; 햔; 햔; ) HANGUL SYLLABLE HYAN +D595;D595;1112 1163 11AC;D595;1112 1163 11AC; # (햕; 햕; 햕; 햕; 햕; ) HANGUL SYLLABLE HYANJ +D596;D596;1112 1163 11AD;D596;1112 1163 11AD; # (햖; 햖; 햖; 햖; 햖; ) HANGUL SYLLABLE HYANH +D597;D597;1112 1163 11AE;D597;1112 1163 11AE; # (햗; 햗; 햗; 햗; 햗; ) HANGUL SYLLABLE HYAD +D598;D598;1112 1163 11AF;D598;1112 1163 11AF; # (햘; 햘; 햘; 햘; 햘; ) HANGUL SYLLABLE HYAL +D599;D599;1112 1163 11B0;D599;1112 1163 11B0; # (햙; 햙; 햙; 햙; 햙; ) HANGUL SYLLABLE HYALG +D59A;D59A;1112 1163 11B1;D59A;1112 1163 11B1; # (햚; 햚; 햚; 햚; 햚; ) HANGUL SYLLABLE HYALM +D59B;D59B;1112 1163 11B2;D59B;1112 1163 11B2; # (햛; 햛; 햛; 햛; 햛; ) HANGUL SYLLABLE HYALB +D59C;D59C;1112 1163 11B3;D59C;1112 1163 11B3; # (햜; 햜; 햜; 햜; 햜; ) HANGUL SYLLABLE HYALS +D59D;D59D;1112 1163 11B4;D59D;1112 1163 11B4; # (햝; 햝; 햝; 햝; 햝; ) HANGUL SYLLABLE HYALT +D59E;D59E;1112 1163 11B5;D59E;1112 1163 11B5; # (햞; 햞; 햞; 햞; 햞; ) HANGUL SYLLABLE HYALP +D59F;D59F;1112 1163 11B6;D59F;1112 1163 11B6; # (햟; 햟; 햟; 햟; 햟; ) HANGUL SYLLABLE HYALH +D5A0;D5A0;1112 1163 11B7;D5A0;1112 1163 11B7; # (햠; 햠; 햠; 햠; 햠; ) HANGUL SYLLABLE HYAM +D5A1;D5A1;1112 1163 11B8;D5A1;1112 1163 11B8; # (햡; 햡; 햡; 햡; 햡; ) HANGUL SYLLABLE HYAB +D5A2;D5A2;1112 1163 11B9;D5A2;1112 1163 11B9; # (햢; 햢; 햢; 햢; 햢; ) HANGUL SYLLABLE HYABS +D5A3;D5A3;1112 1163 11BA;D5A3;1112 1163 11BA; # (햣; 햣; 햣; 햣; 햣; ) HANGUL SYLLABLE HYAS +D5A4;D5A4;1112 1163 11BB;D5A4;1112 1163 11BB; # (햤; 햤; 햤; 햤; 햤; ) HANGUL SYLLABLE HYASS +D5A5;D5A5;1112 1163 11BC;D5A5;1112 1163 11BC; # (향; 향; 향; 향; 향; ) HANGUL SYLLABLE HYANG +D5A6;D5A6;1112 1163 11BD;D5A6;1112 1163 11BD; # (햦; 햦; 햦; 햦; 햦; ) HANGUL SYLLABLE HYAJ +D5A7;D5A7;1112 1163 11BE;D5A7;1112 1163 11BE; # (햧; 햧; 햧; 햧; 햧; ) HANGUL SYLLABLE HYAC +D5A8;D5A8;1112 1163 11BF;D5A8;1112 1163 11BF; # (햨; 햨; 햨; 햨; 햨; ) HANGUL SYLLABLE HYAK +D5A9;D5A9;1112 1163 11C0;D5A9;1112 1163 11C0; # (햩; 햩; 햩; 햩; 햩; ) HANGUL SYLLABLE HYAT +D5AA;D5AA;1112 1163 11C1;D5AA;1112 1163 11C1; # (햪; 햪; 햪; 햪; 햪; ) HANGUL SYLLABLE HYAP +D5AB;D5AB;1112 1163 11C2;D5AB;1112 1163 11C2; # (햫; 햫; 햫; 햫; 햫; ) HANGUL SYLLABLE HYAH +D5AC;D5AC;1112 1164;D5AC;1112 1164; # (햬; 햬; 햬; 햬; 햬; ) HANGUL SYLLABLE HYAE +D5AD;D5AD;1112 1164 11A8;D5AD;1112 1164 11A8; # (햭; 햭; 햭; 햭; 햭; ) HANGUL SYLLABLE HYAEG +D5AE;D5AE;1112 1164 11A9;D5AE;1112 1164 11A9; # (햮; 햮; 햮; 햮; 햮; ) HANGUL SYLLABLE HYAEGG +D5AF;D5AF;1112 1164 11AA;D5AF;1112 1164 11AA; # (햯; 햯; 햯; 햯; 햯; ) HANGUL SYLLABLE HYAEGS +D5B0;D5B0;1112 1164 11AB;D5B0;1112 1164 11AB; # (햰; 햰; 햰; 햰; 햰; ) HANGUL SYLLABLE HYAEN +D5B1;D5B1;1112 1164 11AC;D5B1;1112 1164 11AC; # (햱; 햱; 햱; 햱; 햱; ) HANGUL SYLLABLE HYAENJ +D5B2;D5B2;1112 1164 11AD;D5B2;1112 1164 11AD; # (햲; 햲; 햲; 햲; 햲; ) HANGUL SYLLABLE HYAENH +D5B3;D5B3;1112 1164 11AE;D5B3;1112 1164 11AE; # (햳; 햳; 햳; 햳; 햳; ) HANGUL SYLLABLE HYAED +D5B4;D5B4;1112 1164 11AF;D5B4;1112 1164 11AF; # (햴; 햴; 햴; 햴; 햴; ) HANGUL SYLLABLE HYAEL +D5B5;D5B5;1112 1164 11B0;D5B5;1112 1164 11B0; # (햵; 햵; 햵; 햵; 햵; ) HANGUL SYLLABLE HYAELG +D5B6;D5B6;1112 1164 11B1;D5B6;1112 1164 11B1; # (햶; 햶; 햶; 햶; 햶; ) HANGUL SYLLABLE HYAELM +D5B7;D5B7;1112 1164 11B2;D5B7;1112 1164 11B2; # (햷; 햷; 햷; 햷; 햷; ) HANGUL SYLLABLE HYAELB +D5B8;D5B8;1112 1164 11B3;D5B8;1112 1164 11B3; # (햸; 햸; 햸; 햸; 햸; ) HANGUL SYLLABLE HYAELS +D5B9;D5B9;1112 1164 11B4;D5B9;1112 1164 11B4; # (햹; 햹; 햹; 햹; 햹; ) HANGUL SYLLABLE HYAELT +D5BA;D5BA;1112 1164 11B5;D5BA;1112 1164 11B5; # (햺; 햺; 햺; 햺; 햺; ) HANGUL SYLLABLE HYAELP +D5BB;D5BB;1112 1164 11B6;D5BB;1112 1164 11B6; # (햻; 햻; 햻; 햻; 햻; ) HANGUL SYLLABLE HYAELH +D5BC;D5BC;1112 1164 11B7;D5BC;1112 1164 11B7; # (햼; 햼; 햼; 햼; 햼; ) HANGUL SYLLABLE HYAEM +D5BD;D5BD;1112 1164 11B8;D5BD;1112 1164 11B8; # (햽; 햽; 햽; 햽; 햽; ) HANGUL SYLLABLE HYAEB +D5BE;D5BE;1112 1164 11B9;D5BE;1112 1164 11B9; # (햾; 햾; 햾; 햾; 햾; ) HANGUL SYLLABLE HYAEBS +D5BF;D5BF;1112 1164 11BA;D5BF;1112 1164 11BA; # (햿; 햿; 햿; 햿; 햿; ) HANGUL SYLLABLE HYAES +D5C0;D5C0;1112 1164 11BB;D5C0;1112 1164 11BB; # (헀; 헀; 헀; 헀; 헀; ) HANGUL SYLLABLE HYAESS +D5C1;D5C1;1112 1164 11BC;D5C1;1112 1164 11BC; # (헁; 헁; 헁; 헁; 헁; ) HANGUL SYLLABLE HYAENG +D5C2;D5C2;1112 1164 11BD;D5C2;1112 1164 11BD; # (헂; 헂; 헂; 헂; 헂; ) HANGUL SYLLABLE HYAEJ +D5C3;D5C3;1112 1164 11BE;D5C3;1112 1164 11BE; # (헃; 헃; 헃; 헃; 헃; ) HANGUL SYLLABLE HYAEC +D5C4;D5C4;1112 1164 11BF;D5C4;1112 1164 11BF; # (헄; 헄; 헄; 헄; 헄; ) HANGUL SYLLABLE HYAEK +D5C5;D5C5;1112 1164 11C0;D5C5;1112 1164 11C0; # (헅; 헅; 헅; 헅; 헅; ) HANGUL SYLLABLE HYAET +D5C6;D5C6;1112 1164 11C1;D5C6;1112 1164 11C1; # (헆; 헆; 헆; 헆; 헆; ) HANGUL SYLLABLE HYAEP +D5C7;D5C7;1112 1164 11C2;D5C7;1112 1164 11C2; # (헇; 헇; 헇; 헇; 헇; ) HANGUL SYLLABLE HYAEH +D5C8;D5C8;1112 1165;D5C8;1112 1165; # (허; 허; 허; 허; 허; ) HANGUL SYLLABLE HEO +D5C9;D5C9;1112 1165 11A8;D5C9;1112 1165 11A8; # (헉; 헉; 헉; 헉; 헉; ) HANGUL SYLLABLE HEOG +D5CA;D5CA;1112 1165 11A9;D5CA;1112 1165 11A9; # (헊; 헊; 헊; 헊; 헊; ) HANGUL SYLLABLE HEOGG +D5CB;D5CB;1112 1165 11AA;D5CB;1112 1165 11AA; # (헋; 헋; 헋; 헋; 헋; ) HANGUL SYLLABLE HEOGS +D5CC;D5CC;1112 1165 11AB;D5CC;1112 1165 11AB; # (헌; 헌; 헌; 헌; 헌; ) HANGUL SYLLABLE HEON +D5CD;D5CD;1112 1165 11AC;D5CD;1112 1165 11AC; # (헍; 헍; 헍; 헍; 헍; ) HANGUL SYLLABLE HEONJ +D5CE;D5CE;1112 1165 11AD;D5CE;1112 1165 11AD; # (헎; 헎; 헎; 헎; 헎; ) HANGUL SYLLABLE HEONH +D5CF;D5CF;1112 1165 11AE;D5CF;1112 1165 11AE; # (헏; 헏; 헏; 헏; 헏; ) HANGUL SYLLABLE HEOD +D5D0;D5D0;1112 1165 11AF;D5D0;1112 1165 11AF; # (헐; 헐; 헐; 헐; 헐; ) HANGUL SYLLABLE HEOL +D5D1;D5D1;1112 1165 11B0;D5D1;1112 1165 11B0; # (헑; 헑; 헑; 헑; 헑; ) HANGUL SYLLABLE HEOLG +D5D2;D5D2;1112 1165 11B1;D5D2;1112 1165 11B1; # (헒; 헒; 헒; 헒; 헒; ) HANGUL SYLLABLE HEOLM +D5D3;D5D3;1112 1165 11B2;D5D3;1112 1165 11B2; # (헓; 헓; 헓; 헓; 헓; ) HANGUL SYLLABLE HEOLB +D5D4;D5D4;1112 1165 11B3;D5D4;1112 1165 11B3; # (헔; 헔; 헔; 헔; 헔; ) HANGUL SYLLABLE HEOLS +D5D5;D5D5;1112 1165 11B4;D5D5;1112 1165 11B4; # (헕; 헕; 헕; 헕; 헕; ) HANGUL SYLLABLE HEOLT +D5D6;D5D6;1112 1165 11B5;D5D6;1112 1165 11B5; # (헖; 헖; 헖; 헖; 헖; ) HANGUL SYLLABLE HEOLP +D5D7;D5D7;1112 1165 11B6;D5D7;1112 1165 11B6; # (헗; 헗; 헗; 헗; 헗; ) HANGUL SYLLABLE HEOLH +D5D8;D5D8;1112 1165 11B7;D5D8;1112 1165 11B7; # (험; 험; 험; 험; 험; ) HANGUL SYLLABLE HEOM +D5D9;D5D9;1112 1165 11B8;D5D9;1112 1165 11B8; # (헙; 헙; 헙; 헙; 헙; ) HANGUL SYLLABLE HEOB +D5DA;D5DA;1112 1165 11B9;D5DA;1112 1165 11B9; # (헚; 헚; 헚; 헚; 헚; ) HANGUL SYLLABLE HEOBS +D5DB;D5DB;1112 1165 11BA;D5DB;1112 1165 11BA; # (헛; 헛; 헛; 헛; 헛; ) HANGUL SYLLABLE HEOS +D5DC;D5DC;1112 1165 11BB;D5DC;1112 1165 11BB; # (헜; 헜; 헜; 헜; 헜; ) HANGUL SYLLABLE HEOSS +D5DD;D5DD;1112 1165 11BC;D5DD;1112 1165 11BC; # (헝; 헝; 헝; 헝; 헝; ) HANGUL SYLLABLE HEONG +D5DE;D5DE;1112 1165 11BD;D5DE;1112 1165 11BD; # (헞; 헞; 헞; 헞; 헞; ) HANGUL SYLLABLE HEOJ +D5DF;D5DF;1112 1165 11BE;D5DF;1112 1165 11BE; # (헟; 헟; 헟; 헟; 헟; ) HANGUL SYLLABLE HEOC +D5E0;D5E0;1112 1165 11BF;D5E0;1112 1165 11BF; # (헠; 헠; 헠; 헠; 헠; ) HANGUL SYLLABLE HEOK +D5E1;D5E1;1112 1165 11C0;D5E1;1112 1165 11C0; # (헡; 헡; 헡; 헡; 헡; ) HANGUL SYLLABLE HEOT +D5E2;D5E2;1112 1165 11C1;D5E2;1112 1165 11C1; # (헢; 헢; 헢; 헢; 헢; ) HANGUL SYLLABLE HEOP +D5E3;D5E3;1112 1165 11C2;D5E3;1112 1165 11C2; # (헣; 헣; 헣; 헣; 헣; ) HANGUL SYLLABLE HEOH +D5E4;D5E4;1112 1166;D5E4;1112 1166; # (헤; 헤; 헤; 헤; 헤; ) HANGUL SYLLABLE HE +D5E5;D5E5;1112 1166 11A8;D5E5;1112 1166 11A8; # (헥; 헥; 헥; 헥; 헥; ) HANGUL SYLLABLE HEG +D5E6;D5E6;1112 1166 11A9;D5E6;1112 1166 11A9; # (헦; 헦; 헦; 헦; 헦; ) HANGUL SYLLABLE HEGG +D5E7;D5E7;1112 1166 11AA;D5E7;1112 1166 11AA; # (헧; 헧; 헧; 헧; 헧; ) HANGUL SYLLABLE HEGS +D5E8;D5E8;1112 1166 11AB;D5E8;1112 1166 11AB; # (헨; 헨; 헨; 헨; 헨; ) HANGUL SYLLABLE HEN +D5E9;D5E9;1112 1166 11AC;D5E9;1112 1166 11AC; # (헩; 헩; 헩; 헩; 헩; ) HANGUL SYLLABLE HENJ +D5EA;D5EA;1112 1166 11AD;D5EA;1112 1166 11AD; # (헪; 헪; 헪; 헪; 헪; ) HANGUL SYLLABLE HENH +D5EB;D5EB;1112 1166 11AE;D5EB;1112 1166 11AE; # (헫; 헫; 헫; 헫; 헫; ) HANGUL SYLLABLE HED +D5EC;D5EC;1112 1166 11AF;D5EC;1112 1166 11AF; # (헬; 헬; 헬; 헬; 헬; ) HANGUL SYLLABLE HEL +D5ED;D5ED;1112 1166 11B0;D5ED;1112 1166 11B0; # (헭; 헭; 헭; 헭; 헭; ) HANGUL SYLLABLE HELG +D5EE;D5EE;1112 1166 11B1;D5EE;1112 1166 11B1; # (헮; 헮; 헮; 헮; 헮; ) HANGUL SYLLABLE HELM +D5EF;D5EF;1112 1166 11B2;D5EF;1112 1166 11B2; # (헯; 헯; 헯; 헯; 헯; ) HANGUL SYLLABLE HELB +D5F0;D5F0;1112 1166 11B3;D5F0;1112 1166 11B3; # (헰; 헰; 헰; 헰; 헰; ) HANGUL SYLLABLE HELS +D5F1;D5F1;1112 1166 11B4;D5F1;1112 1166 11B4; # (헱; 헱; 헱; 헱; 헱; ) HANGUL SYLLABLE HELT +D5F2;D5F2;1112 1166 11B5;D5F2;1112 1166 11B5; # (헲; 헲; 헲; 헲; 헲; ) HANGUL SYLLABLE HELP +D5F3;D5F3;1112 1166 11B6;D5F3;1112 1166 11B6; # (헳; 헳; 헳; 헳; 헳; ) HANGUL SYLLABLE HELH +D5F4;D5F4;1112 1166 11B7;D5F4;1112 1166 11B7; # (헴; 헴; 헴; 헴; 헴; ) HANGUL SYLLABLE HEM +D5F5;D5F5;1112 1166 11B8;D5F5;1112 1166 11B8; # (헵; 헵; 헵; 헵; 헵; ) HANGUL SYLLABLE HEB +D5F6;D5F6;1112 1166 11B9;D5F6;1112 1166 11B9; # (헶; 헶; 헶; 헶; 헶; ) HANGUL SYLLABLE HEBS +D5F7;D5F7;1112 1166 11BA;D5F7;1112 1166 11BA; # (헷; 헷; 헷; 헷; 헷; ) HANGUL SYLLABLE HES +D5F8;D5F8;1112 1166 11BB;D5F8;1112 1166 11BB; # (헸; 헸; 헸; 헸; 헸; ) HANGUL SYLLABLE HESS +D5F9;D5F9;1112 1166 11BC;D5F9;1112 1166 11BC; # (헹; 헹; 헹; 헹; 헹; ) HANGUL SYLLABLE HENG +D5FA;D5FA;1112 1166 11BD;D5FA;1112 1166 11BD; # (헺; 헺; 헺; 헺; 헺; ) HANGUL SYLLABLE HEJ +D5FB;D5FB;1112 1166 11BE;D5FB;1112 1166 11BE; # (헻; 헻; 헻; 헻; 헻; ) HANGUL SYLLABLE HEC +D5FC;D5FC;1112 1166 11BF;D5FC;1112 1166 11BF; # (헼; 헼; 헼; 헼; 헼; ) HANGUL SYLLABLE HEK +D5FD;D5FD;1112 1166 11C0;D5FD;1112 1166 11C0; # (헽; 헽; 헽; 헽; 헽; ) HANGUL SYLLABLE HET +D5FE;D5FE;1112 1166 11C1;D5FE;1112 1166 11C1; # (헾; 헾; 헾; 헾; 헾; ) HANGUL SYLLABLE HEP +D5FF;D5FF;1112 1166 11C2;D5FF;1112 1166 11C2; # (헿; 헿; 헿; 헿; 헿; ) HANGUL SYLLABLE HEH +D600;D600;1112 1167;D600;1112 1167; # (혀; 혀; 혀; 혀; 혀; ) HANGUL SYLLABLE HYEO +D601;D601;1112 1167 11A8;D601;1112 1167 11A8; # (혁; 혁; 혁; 혁; 혁; ) HANGUL SYLLABLE HYEOG +D602;D602;1112 1167 11A9;D602;1112 1167 11A9; # (혂; 혂; 혂; 혂; 혂; ) HANGUL SYLLABLE HYEOGG +D603;D603;1112 1167 11AA;D603;1112 1167 11AA; # (혃; 혃; 혃; 혃; 혃; ) HANGUL SYLLABLE HYEOGS +D604;D604;1112 1167 11AB;D604;1112 1167 11AB; # (현; 현; 현; 현; 현; ) HANGUL SYLLABLE HYEON +D605;D605;1112 1167 11AC;D605;1112 1167 11AC; # (혅; 혅; 혅; 혅; 혅; ) HANGUL SYLLABLE HYEONJ +D606;D606;1112 1167 11AD;D606;1112 1167 11AD; # (혆; 혆; 혆; 혆; 혆; ) HANGUL SYLLABLE HYEONH +D607;D607;1112 1167 11AE;D607;1112 1167 11AE; # (혇; 혇; 혇; 혇; 혇; ) HANGUL SYLLABLE HYEOD +D608;D608;1112 1167 11AF;D608;1112 1167 11AF; # (혈; 혈; 혈; 혈; 혈; ) HANGUL SYLLABLE HYEOL +D609;D609;1112 1167 11B0;D609;1112 1167 11B0; # (혉; 혉; 혉; 혉; 혉; ) HANGUL SYLLABLE HYEOLG +D60A;D60A;1112 1167 11B1;D60A;1112 1167 11B1; # (혊; 혊; 혊; 혊; 혊; ) HANGUL SYLLABLE HYEOLM +D60B;D60B;1112 1167 11B2;D60B;1112 1167 11B2; # (혋; 혋; 혋; 혋; 혋; ) HANGUL SYLLABLE HYEOLB +D60C;D60C;1112 1167 11B3;D60C;1112 1167 11B3; # (혌; 혌; 혌; 혌; 혌; ) HANGUL SYLLABLE HYEOLS +D60D;D60D;1112 1167 11B4;D60D;1112 1167 11B4; # (혍; 혍; 혍; 혍; 혍; ) HANGUL SYLLABLE HYEOLT +D60E;D60E;1112 1167 11B5;D60E;1112 1167 11B5; # (혎; 혎; 혎; 혎; 혎; ) HANGUL SYLLABLE HYEOLP +D60F;D60F;1112 1167 11B6;D60F;1112 1167 11B6; # (혏; 혏; 혏; 혏; 혏; ) HANGUL SYLLABLE HYEOLH +D610;D610;1112 1167 11B7;D610;1112 1167 11B7; # (혐; 혐; 혐; 혐; 혐; ) HANGUL SYLLABLE HYEOM +D611;D611;1112 1167 11B8;D611;1112 1167 11B8; # (협; 협; 협; 협; 협; ) HANGUL SYLLABLE HYEOB +D612;D612;1112 1167 11B9;D612;1112 1167 11B9; # (혒; 혒; 혒; 혒; 혒; ) HANGUL SYLLABLE HYEOBS +D613;D613;1112 1167 11BA;D613;1112 1167 11BA; # (혓; 혓; 혓; 혓; 혓; ) HANGUL SYLLABLE HYEOS +D614;D614;1112 1167 11BB;D614;1112 1167 11BB; # (혔; 혔; 혔; 혔; 혔; ) HANGUL SYLLABLE HYEOSS +D615;D615;1112 1167 11BC;D615;1112 1167 11BC; # (형; 형; 형; 형; 형; ) HANGUL SYLLABLE HYEONG +D616;D616;1112 1167 11BD;D616;1112 1167 11BD; # (혖; 혖; 혖; 혖; 혖; ) HANGUL SYLLABLE HYEOJ +D617;D617;1112 1167 11BE;D617;1112 1167 11BE; # (혗; 혗; 혗; 혗; 혗; ) HANGUL SYLLABLE HYEOC +D618;D618;1112 1167 11BF;D618;1112 1167 11BF; # (혘; 혘; 혘; 혘; 혘; ) HANGUL SYLLABLE HYEOK +D619;D619;1112 1167 11C0;D619;1112 1167 11C0; # (혙; 혙; 혙; 혙; 혙; ) HANGUL SYLLABLE HYEOT +D61A;D61A;1112 1167 11C1;D61A;1112 1167 11C1; # (혚; 혚; 혚; 혚; 혚; ) HANGUL SYLLABLE HYEOP +D61B;D61B;1112 1167 11C2;D61B;1112 1167 11C2; # (혛; 혛; 혛; 혛; 혛; ) HANGUL SYLLABLE HYEOH +D61C;D61C;1112 1168;D61C;1112 1168; # (혜; 혜; 혜; 혜; 혜; ) HANGUL SYLLABLE HYE +D61D;D61D;1112 1168 11A8;D61D;1112 1168 11A8; # (혝; 혝; 혝; 혝; 혝; ) HANGUL SYLLABLE HYEG +D61E;D61E;1112 1168 11A9;D61E;1112 1168 11A9; # (혞; 혞; 혞; 혞; 혞; ) HANGUL SYLLABLE HYEGG +D61F;D61F;1112 1168 11AA;D61F;1112 1168 11AA; # (혟; 혟; 혟; 혟; 혟; ) HANGUL SYLLABLE HYEGS +D620;D620;1112 1168 11AB;D620;1112 1168 11AB; # (혠; 혠; 혠; 혠; 혠; ) HANGUL SYLLABLE HYEN +D621;D621;1112 1168 11AC;D621;1112 1168 11AC; # (혡; 혡; 혡; 혡; 혡; ) HANGUL SYLLABLE HYENJ +D622;D622;1112 1168 11AD;D622;1112 1168 11AD; # (혢; 혢; 혢; 혢; 혢; ) HANGUL SYLLABLE HYENH +D623;D623;1112 1168 11AE;D623;1112 1168 11AE; # (혣; 혣; 혣; 혣; 혣; ) HANGUL SYLLABLE HYED +D624;D624;1112 1168 11AF;D624;1112 1168 11AF; # (혤; 혤; 혤; 혤; 혤; ) HANGUL SYLLABLE HYEL +D625;D625;1112 1168 11B0;D625;1112 1168 11B0; # (혥; 혥; 혥; 혥; 혥; ) HANGUL SYLLABLE HYELG +D626;D626;1112 1168 11B1;D626;1112 1168 11B1; # (혦; 혦; 혦; 혦; 혦; ) HANGUL SYLLABLE HYELM +D627;D627;1112 1168 11B2;D627;1112 1168 11B2; # (혧; 혧; 혧; 혧; 혧; ) HANGUL SYLLABLE HYELB +D628;D628;1112 1168 11B3;D628;1112 1168 11B3; # (혨; 혨; 혨; 혨; 혨; ) HANGUL SYLLABLE HYELS +D629;D629;1112 1168 11B4;D629;1112 1168 11B4; # (혩; 혩; 혩; 혩; 혩; ) HANGUL SYLLABLE HYELT +D62A;D62A;1112 1168 11B5;D62A;1112 1168 11B5; # (혪; 혪; 혪; 혪; 혪; ) HANGUL SYLLABLE HYELP +D62B;D62B;1112 1168 11B6;D62B;1112 1168 11B6; # (혫; 혫; 혫; 혫; 혫; ) HANGUL SYLLABLE HYELH +D62C;D62C;1112 1168 11B7;D62C;1112 1168 11B7; # (혬; 혬; 혬; 혬; 혬; ) HANGUL SYLLABLE HYEM +D62D;D62D;1112 1168 11B8;D62D;1112 1168 11B8; # (혭; 혭; 혭; 혭; 혭; ) HANGUL SYLLABLE HYEB +D62E;D62E;1112 1168 11B9;D62E;1112 1168 11B9; # (혮; 혮; 혮; 혮; 혮; ) HANGUL SYLLABLE HYEBS +D62F;D62F;1112 1168 11BA;D62F;1112 1168 11BA; # (혯; 혯; 혯; 혯; 혯; ) HANGUL SYLLABLE HYES +D630;D630;1112 1168 11BB;D630;1112 1168 11BB; # (혰; 혰; 혰; 혰; 혰; ) HANGUL SYLLABLE HYESS +D631;D631;1112 1168 11BC;D631;1112 1168 11BC; # (혱; 혱; 혱; 혱; 혱; ) HANGUL SYLLABLE HYENG +D632;D632;1112 1168 11BD;D632;1112 1168 11BD; # (혲; 혲; 혲; 혲; 혲; ) HANGUL SYLLABLE HYEJ +D633;D633;1112 1168 11BE;D633;1112 1168 11BE; # (혳; 혳; 혳; 혳; 혳; ) HANGUL SYLLABLE HYEC +D634;D634;1112 1168 11BF;D634;1112 1168 11BF; # (혴; 혴; 혴; 혴; 혴; ) HANGUL SYLLABLE HYEK +D635;D635;1112 1168 11C0;D635;1112 1168 11C0; # (혵; 혵; 혵; 혵; 혵; ) HANGUL SYLLABLE HYET +D636;D636;1112 1168 11C1;D636;1112 1168 11C1; # (혶; 혶; 혶; 혶; 혶; ) HANGUL SYLLABLE HYEP +D637;D637;1112 1168 11C2;D637;1112 1168 11C2; # (혷; 혷; 혷; 혷; 혷; ) HANGUL SYLLABLE HYEH +D638;D638;1112 1169;D638;1112 1169; # (호; 호; 호; 호; 호; ) HANGUL SYLLABLE HO +D639;D639;1112 1169 11A8;D639;1112 1169 11A8; # (혹; 혹; 혹; 혹; 혹; ) HANGUL SYLLABLE HOG +D63A;D63A;1112 1169 11A9;D63A;1112 1169 11A9; # (혺; 혺; 혺; 혺; 혺; ) HANGUL SYLLABLE HOGG +D63B;D63B;1112 1169 11AA;D63B;1112 1169 11AA; # (혻; 혻; 혻; 혻; 혻; ) HANGUL SYLLABLE HOGS +D63C;D63C;1112 1169 11AB;D63C;1112 1169 11AB; # (혼; 혼; 혼; 혼; 혼; ) HANGUL SYLLABLE HON +D63D;D63D;1112 1169 11AC;D63D;1112 1169 11AC; # (혽; 혽; 혽; 혽; 혽; ) HANGUL SYLLABLE HONJ +D63E;D63E;1112 1169 11AD;D63E;1112 1169 11AD; # (혾; 혾; 혾; 혾; 혾; ) HANGUL SYLLABLE HONH +D63F;D63F;1112 1169 11AE;D63F;1112 1169 11AE; # (혿; 혿; 혿; 혿; 혿; ) HANGUL SYLLABLE HOD +D640;D640;1112 1169 11AF;D640;1112 1169 11AF; # (홀; 홀; 홀; 홀; 홀; ) HANGUL SYLLABLE HOL +D641;D641;1112 1169 11B0;D641;1112 1169 11B0; # (홁; 홁; 홁; 홁; 홁; ) HANGUL SYLLABLE HOLG +D642;D642;1112 1169 11B1;D642;1112 1169 11B1; # (홂; 홂; 홂; 홂; 홂; ) HANGUL SYLLABLE HOLM +D643;D643;1112 1169 11B2;D643;1112 1169 11B2; # (홃; 홃; 홃; 홃; 홃; ) HANGUL SYLLABLE HOLB +D644;D644;1112 1169 11B3;D644;1112 1169 11B3; # (홄; 홄; 홄; 홄; 홄; ) HANGUL SYLLABLE HOLS +D645;D645;1112 1169 11B4;D645;1112 1169 11B4; # (홅; 홅; 홅; 홅; 홅; ) HANGUL SYLLABLE HOLT +D646;D646;1112 1169 11B5;D646;1112 1169 11B5; # (홆; 홆; 홆; 홆; 홆; ) HANGUL SYLLABLE HOLP +D647;D647;1112 1169 11B6;D647;1112 1169 11B6; # (홇; 홇; 홇; 홇; 홇; ) HANGUL SYLLABLE HOLH +D648;D648;1112 1169 11B7;D648;1112 1169 11B7; # (홈; 홈; 홈; 홈; 홈; ) HANGUL SYLLABLE HOM +D649;D649;1112 1169 11B8;D649;1112 1169 11B8; # (홉; 홉; 홉; 홉; 홉; ) HANGUL SYLLABLE HOB +D64A;D64A;1112 1169 11B9;D64A;1112 1169 11B9; # (홊; 홊; 홊; 홊; 홊; ) HANGUL SYLLABLE HOBS +D64B;D64B;1112 1169 11BA;D64B;1112 1169 11BA; # (홋; 홋; 홋; 홋; 홋; ) HANGUL SYLLABLE HOS +D64C;D64C;1112 1169 11BB;D64C;1112 1169 11BB; # (홌; 홌; 홌; 홌; 홌; ) HANGUL SYLLABLE HOSS +D64D;D64D;1112 1169 11BC;D64D;1112 1169 11BC; # (홍; 홍; 홍; 홍; 홍; ) HANGUL SYLLABLE HONG +D64E;D64E;1112 1169 11BD;D64E;1112 1169 11BD; # (홎; 홎; 홎; 홎; 홎; ) HANGUL SYLLABLE HOJ +D64F;D64F;1112 1169 11BE;D64F;1112 1169 11BE; # (홏; 홏; 홏; 홏; 홏; ) HANGUL SYLLABLE HOC +D650;D650;1112 1169 11BF;D650;1112 1169 11BF; # (홐; 홐; 홐; 홐; 홐; ) HANGUL SYLLABLE HOK +D651;D651;1112 1169 11C0;D651;1112 1169 11C0; # (홑; 홑; 홑; 홑; 홑; ) HANGUL SYLLABLE HOT +D652;D652;1112 1169 11C1;D652;1112 1169 11C1; # (홒; 홒; 홒; 홒; 홒; ) HANGUL SYLLABLE HOP +D653;D653;1112 1169 11C2;D653;1112 1169 11C2; # (홓; 홓; 홓; 홓; 홓; ) HANGUL SYLLABLE HOH +D654;D654;1112 116A;D654;1112 116A; # (화; 화; 화; 화; 화; ) HANGUL SYLLABLE HWA +D655;D655;1112 116A 11A8;D655;1112 116A 11A8; # (확; 확; 확; 확; 확; ) HANGUL SYLLABLE HWAG +D656;D656;1112 116A 11A9;D656;1112 116A 11A9; # (홖; 홖; 홖; 홖; 홖; ) HANGUL SYLLABLE HWAGG +D657;D657;1112 116A 11AA;D657;1112 116A 11AA; # (홗; 홗; 홗; 홗; 홗; ) HANGUL SYLLABLE HWAGS +D658;D658;1112 116A 11AB;D658;1112 116A 11AB; # (환; 환; 환; 환; 환; ) HANGUL SYLLABLE HWAN +D659;D659;1112 116A 11AC;D659;1112 116A 11AC; # (홙; 홙; 홙; 홙; 홙; ) HANGUL SYLLABLE HWANJ +D65A;D65A;1112 116A 11AD;D65A;1112 116A 11AD; # (홚; 홚; 홚; 홚; 홚; ) HANGUL SYLLABLE HWANH +D65B;D65B;1112 116A 11AE;D65B;1112 116A 11AE; # (홛; 홛; 홛; 홛; 홛; ) HANGUL SYLLABLE HWAD +D65C;D65C;1112 116A 11AF;D65C;1112 116A 11AF; # (활; 활; 활; 활; 활; ) HANGUL SYLLABLE HWAL +D65D;D65D;1112 116A 11B0;D65D;1112 116A 11B0; # (홝; 홝; 홝; 홝; 홝; ) HANGUL SYLLABLE HWALG +D65E;D65E;1112 116A 11B1;D65E;1112 116A 11B1; # (홞; 홞; 홞; 홞; 홞; ) HANGUL SYLLABLE HWALM +D65F;D65F;1112 116A 11B2;D65F;1112 116A 11B2; # (홟; 홟; 홟; 홟; 홟; ) HANGUL SYLLABLE HWALB +D660;D660;1112 116A 11B3;D660;1112 116A 11B3; # (홠; 홠; 홠; 홠; 홠; ) HANGUL SYLLABLE HWALS +D661;D661;1112 116A 11B4;D661;1112 116A 11B4; # (홡; 홡; 홡; 홡; 홡; ) HANGUL SYLLABLE HWALT +D662;D662;1112 116A 11B5;D662;1112 116A 11B5; # (홢; 홢; 홢; 홢; 홢; ) HANGUL SYLLABLE HWALP +D663;D663;1112 116A 11B6;D663;1112 116A 11B6; # (홣; 홣; 홣; 홣; 홣; ) HANGUL SYLLABLE HWALH +D664;D664;1112 116A 11B7;D664;1112 116A 11B7; # (홤; 홤; 홤; 홤; 홤; ) HANGUL SYLLABLE HWAM +D665;D665;1112 116A 11B8;D665;1112 116A 11B8; # (홥; 홥; 홥; 홥; 홥; ) HANGUL SYLLABLE HWAB +D666;D666;1112 116A 11B9;D666;1112 116A 11B9; # (홦; 홦; 홦; 홦; 홦; ) HANGUL SYLLABLE HWABS +D667;D667;1112 116A 11BA;D667;1112 116A 11BA; # (홧; 홧; 홧; 홧; 홧; ) HANGUL SYLLABLE HWAS +D668;D668;1112 116A 11BB;D668;1112 116A 11BB; # (홨; 홨; 홨; 홨; 홨; ) HANGUL SYLLABLE HWASS +D669;D669;1112 116A 11BC;D669;1112 116A 11BC; # (황; 황; 황; 황; 황; ) HANGUL SYLLABLE HWANG +D66A;D66A;1112 116A 11BD;D66A;1112 116A 11BD; # (홪; 홪; 홪; 홪; 홪; ) HANGUL SYLLABLE HWAJ +D66B;D66B;1112 116A 11BE;D66B;1112 116A 11BE; # (홫; 홫; 홫; 홫; 홫; ) HANGUL SYLLABLE HWAC +D66C;D66C;1112 116A 11BF;D66C;1112 116A 11BF; # (홬; 홬; 홬; 홬; 홬; ) HANGUL SYLLABLE HWAK +D66D;D66D;1112 116A 11C0;D66D;1112 116A 11C0; # (홭; 홭; 홭; 홭; 홭; ) HANGUL SYLLABLE HWAT +D66E;D66E;1112 116A 11C1;D66E;1112 116A 11C1; # (홮; 홮; 홮; 홮; 홮; ) HANGUL SYLLABLE HWAP +D66F;D66F;1112 116A 11C2;D66F;1112 116A 11C2; # (홯; 홯; 홯; 홯; 홯; ) HANGUL SYLLABLE HWAH +D670;D670;1112 116B;D670;1112 116B; # (홰; 홰; 홰; 홰; 홰; ) HANGUL SYLLABLE HWAE +D671;D671;1112 116B 11A8;D671;1112 116B 11A8; # (홱; 홱; 홱; 홱; 홱; ) HANGUL SYLLABLE HWAEG +D672;D672;1112 116B 11A9;D672;1112 116B 11A9; # (홲; 홲; 홲; 홲; 홲; ) HANGUL SYLLABLE HWAEGG +D673;D673;1112 116B 11AA;D673;1112 116B 11AA; # (홳; 홳; 홳; 홳; 홳; ) HANGUL SYLLABLE HWAEGS +D674;D674;1112 116B 11AB;D674;1112 116B 11AB; # (홴; 홴; 홴; 홴; 홴; ) HANGUL SYLLABLE HWAEN +D675;D675;1112 116B 11AC;D675;1112 116B 11AC; # (홵; 홵; 홵; 홵; 홵; ) HANGUL SYLLABLE HWAENJ +D676;D676;1112 116B 11AD;D676;1112 116B 11AD; # (홶; 홶; 홶; 홶; 홶; ) HANGUL SYLLABLE HWAENH +D677;D677;1112 116B 11AE;D677;1112 116B 11AE; # (홷; 홷; 홷; 홷; 홷; ) HANGUL SYLLABLE HWAED +D678;D678;1112 116B 11AF;D678;1112 116B 11AF; # (홸; 홸; 홸; 홸; 홸; ) HANGUL SYLLABLE HWAEL +D679;D679;1112 116B 11B0;D679;1112 116B 11B0; # (홹; 홹; 홹; 홹; 홹; ) HANGUL SYLLABLE HWAELG +D67A;D67A;1112 116B 11B1;D67A;1112 116B 11B1; # (홺; 홺; 홺; 홺; 홺; ) HANGUL SYLLABLE HWAELM +D67B;D67B;1112 116B 11B2;D67B;1112 116B 11B2; # (홻; 홻; 홻; 홻; 홻; ) HANGUL SYLLABLE HWAELB +D67C;D67C;1112 116B 11B3;D67C;1112 116B 11B3; # (홼; 홼; 홼; 홼; 홼; ) HANGUL SYLLABLE HWAELS +D67D;D67D;1112 116B 11B4;D67D;1112 116B 11B4; # (홽; 홽; 홽; 홽; 홽; ) HANGUL SYLLABLE HWAELT +D67E;D67E;1112 116B 11B5;D67E;1112 116B 11B5; # (홾; 홾; 홾; 홾; 홾; ) HANGUL SYLLABLE HWAELP +D67F;D67F;1112 116B 11B6;D67F;1112 116B 11B6; # (홿; 홿; 홿; 홿; 홿; ) HANGUL SYLLABLE HWAELH +D680;D680;1112 116B 11B7;D680;1112 116B 11B7; # (횀; 횀; 횀; 횀; 횀; ) HANGUL SYLLABLE HWAEM +D681;D681;1112 116B 11B8;D681;1112 116B 11B8; # (횁; 횁; 횁; 횁; 횁; ) HANGUL SYLLABLE HWAEB +D682;D682;1112 116B 11B9;D682;1112 116B 11B9; # (횂; 횂; 횂; 횂; 횂; ) HANGUL SYLLABLE HWAEBS +D683;D683;1112 116B 11BA;D683;1112 116B 11BA; # (횃; 횃; 횃; 횃; 횃; ) HANGUL SYLLABLE HWAES +D684;D684;1112 116B 11BB;D684;1112 116B 11BB; # (횄; 횄; 횄; 횄; 횄; ) HANGUL SYLLABLE HWAESS +D685;D685;1112 116B 11BC;D685;1112 116B 11BC; # (횅; 횅; 횅; 횅; 횅; ) HANGUL SYLLABLE HWAENG +D686;D686;1112 116B 11BD;D686;1112 116B 11BD; # (횆; 횆; 횆; 횆; 횆; ) HANGUL SYLLABLE HWAEJ +D687;D687;1112 116B 11BE;D687;1112 116B 11BE; # (횇; 횇; 횇; 횇; 횇; ) HANGUL SYLLABLE HWAEC +D688;D688;1112 116B 11BF;D688;1112 116B 11BF; # (횈; 횈; 횈; 횈; 횈; ) HANGUL SYLLABLE HWAEK +D689;D689;1112 116B 11C0;D689;1112 116B 11C0; # (횉; 횉; 횉; 횉; 횉; ) HANGUL SYLLABLE HWAET +D68A;D68A;1112 116B 11C1;D68A;1112 116B 11C1; # (횊; 횊; 횊; 횊; 횊; ) HANGUL SYLLABLE HWAEP +D68B;D68B;1112 116B 11C2;D68B;1112 116B 11C2; # (횋; 횋; 횋; 횋; 횋; ) HANGUL SYLLABLE HWAEH +D68C;D68C;1112 116C;D68C;1112 116C; # (회; 회; 회; 회; 회; ) HANGUL SYLLABLE HOE +D68D;D68D;1112 116C 11A8;D68D;1112 116C 11A8; # (획; 획; 획; 획; 획; ) HANGUL SYLLABLE HOEG +D68E;D68E;1112 116C 11A9;D68E;1112 116C 11A9; # (횎; 횎; 횎; 횎; 횎; ) HANGUL SYLLABLE HOEGG +D68F;D68F;1112 116C 11AA;D68F;1112 116C 11AA; # (횏; 횏; 횏; 횏; 횏; ) HANGUL SYLLABLE HOEGS +D690;D690;1112 116C 11AB;D690;1112 116C 11AB; # (횐; 횐; 횐; 횐; 횐; ) HANGUL SYLLABLE HOEN +D691;D691;1112 116C 11AC;D691;1112 116C 11AC; # (횑; 횑; 횑; 횑; 횑; ) HANGUL SYLLABLE HOENJ +D692;D692;1112 116C 11AD;D692;1112 116C 11AD; # (횒; 횒; 횒; 횒; 횒; ) HANGUL SYLLABLE HOENH +D693;D693;1112 116C 11AE;D693;1112 116C 11AE; # (횓; 횓; 횓; 횓; 횓; ) HANGUL SYLLABLE HOED +D694;D694;1112 116C 11AF;D694;1112 116C 11AF; # (횔; 횔; 횔; 횔; 횔; ) HANGUL SYLLABLE HOEL +D695;D695;1112 116C 11B0;D695;1112 116C 11B0; # (횕; 횕; 횕; 횕; 횕; ) HANGUL SYLLABLE HOELG +D696;D696;1112 116C 11B1;D696;1112 116C 11B1; # (횖; 횖; 횖; 횖; 횖; ) HANGUL SYLLABLE HOELM +D697;D697;1112 116C 11B2;D697;1112 116C 11B2; # (횗; 횗; 횗; 횗; 횗; ) HANGUL SYLLABLE HOELB +D698;D698;1112 116C 11B3;D698;1112 116C 11B3; # (횘; 횘; 횘; 횘; 횘; ) HANGUL SYLLABLE HOELS +D699;D699;1112 116C 11B4;D699;1112 116C 11B4; # (횙; 횙; 횙; 횙; 횙; ) HANGUL SYLLABLE HOELT +D69A;D69A;1112 116C 11B5;D69A;1112 116C 11B5; # (횚; 횚; 횚; 횚; 횚; ) HANGUL SYLLABLE HOELP +D69B;D69B;1112 116C 11B6;D69B;1112 116C 11B6; # (횛; 횛; 횛; 횛; 횛; ) HANGUL SYLLABLE HOELH +D69C;D69C;1112 116C 11B7;D69C;1112 116C 11B7; # (횜; 횜; 횜; 횜; 횜; ) HANGUL SYLLABLE HOEM +D69D;D69D;1112 116C 11B8;D69D;1112 116C 11B8; # (횝; 횝; 횝; 횝; 횝; ) HANGUL SYLLABLE HOEB +D69E;D69E;1112 116C 11B9;D69E;1112 116C 11B9; # (횞; 횞; 횞; 횞; 횞; ) HANGUL SYLLABLE HOEBS +D69F;D69F;1112 116C 11BA;D69F;1112 116C 11BA; # (횟; 횟; 횟; 횟; 횟; ) HANGUL SYLLABLE HOES +D6A0;D6A0;1112 116C 11BB;D6A0;1112 116C 11BB; # (횠; 횠; 횠; 횠; 횠; ) HANGUL SYLLABLE HOESS +D6A1;D6A1;1112 116C 11BC;D6A1;1112 116C 11BC; # (횡; 횡; 횡; 횡; 횡; ) HANGUL SYLLABLE HOENG +D6A2;D6A2;1112 116C 11BD;D6A2;1112 116C 11BD; # (횢; 횢; 횢; 횢; 횢; ) HANGUL SYLLABLE HOEJ +D6A3;D6A3;1112 116C 11BE;D6A3;1112 116C 11BE; # (횣; 횣; 횣; 횣; 횣; ) HANGUL SYLLABLE HOEC +D6A4;D6A4;1112 116C 11BF;D6A4;1112 116C 11BF; # (횤; 횤; 횤; 횤; 횤; ) HANGUL SYLLABLE HOEK +D6A5;D6A5;1112 116C 11C0;D6A5;1112 116C 11C0; # (횥; 횥; 횥; 횥; 횥; ) HANGUL SYLLABLE HOET +D6A6;D6A6;1112 116C 11C1;D6A6;1112 116C 11C1; # (횦; 횦; 횦; 횦; 횦; ) HANGUL SYLLABLE HOEP +D6A7;D6A7;1112 116C 11C2;D6A7;1112 116C 11C2; # (횧; 횧; 횧; 횧; 횧; ) HANGUL SYLLABLE HOEH +D6A8;D6A8;1112 116D;D6A8;1112 116D; # (효; 효; 효; 효; 효; ) HANGUL SYLLABLE HYO +D6A9;D6A9;1112 116D 11A8;D6A9;1112 116D 11A8; # (횩; 횩; 횩; 횩; 횩; ) HANGUL SYLLABLE HYOG +D6AA;D6AA;1112 116D 11A9;D6AA;1112 116D 11A9; # (횪; 횪; 횪; 횪; 횪; ) HANGUL SYLLABLE HYOGG +D6AB;D6AB;1112 116D 11AA;D6AB;1112 116D 11AA; # (횫; 횫; 횫; 횫; 횫; ) HANGUL SYLLABLE HYOGS +D6AC;D6AC;1112 116D 11AB;D6AC;1112 116D 11AB; # (횬; 횬; 횬; 횬; 횬; ) HANGUL SYLLABLE HYON +D6AD;D6AD;1112 116D 11AC;D6AD;1112 116D 11AC; # (횭; 횭; 횭; 횭; 횭; ) HANGUL SYLLABLE HYONJ +D6AE;D6AE;1112 116D 11AD;D6AE;1112 116D 11AD; # (횮; 횮; 횮; 횮; 횮; ) HANGUL SYLLABLE HYONH +D6AF;D6AF;1112 116D 11AE;D6AF;1112 116D 11AE; # (횯; 횯; 횯; 횯; 횯; ) HANGUL SYLLABLE HYOD +D6B0;D6B0;1112 116D 11AF;D6B0;1112 116D 11AF; # (횰; 횰; 횰; 횰; 횰; ) HANGUL SYLLABLE HYOL +D6B1;D6B1;1112 116D 11B0;D6B1;1112 116D 11B0; # (횱; 횱; 횱; 횱; 횱; ) HANGUL SYLLABLE HYOLG +D6B2;D6B2;1112 116D 11B1;D6B2;1112 116D 11B1; # (횲; 횲; 횲; 횲; 횲; ) HANGUL SYLLABLE HYOLM +D6B3;D6B3;1112 116D 11B2;D6B3;1112 116D 11B2; # (횳; 횳; 횳; 횳; 횳; ) HANGUL SYLLABLE HYOLB +D6B4;D6B4;1112 116D 11B3;D6B4;1112 116D 11B3; # (횴; 횴; 횴; 횴; 횴; ) HANGUL SYLLABLE HYOLS +D6B5;D6B5;1112 116D 11B4;D6B5;1112 116D 11B4; # (횵; 횵; 횵; 횵; 횵; ) HANGUL SYLLABLE HYOLT +D6B6;D6B6;1112 116D 11B5;D6B6;1112 116D 11B5; # (횶; 횶; 횶; 횶; 횶; ) HANGUL SYLLABLE HYOLP +D6B7;D6B7;1112 116D 11B6;D6B7;1112 116D 11B6; # (횷; 횷; 횷; 횷; 횷; ) HANGUL SYLLABLE HYOLH +D6B8;D6B8;1112 116D 11B7;D6B8;1112 116D 11B7; # (횸; 횸; 횸; 횸; 횸; ) HANGUL SYLLABLE HYOM +D6B9;D6B9;1112 116D 11B8;D6B9;1112 116D 11B8; # (횹; 횹; 횹; 횹; 횹; ) HANGUL SYLLABLE HYOB +D6BA;D6BA;1112 116D 11B9;D6BA;1112 116D 11B9; # (횺; 횺; 횺; 횺; 횺; ) HANGUL SYLLABLE HYOBS +D6BB;D6BB;1112 116D 11BA;D6BB;1112 116D 11BA; # (횻; 횻; 횻; 횻; 횻; ) HANGUL SYLLABLE HYOS +D6BC;D6BC;1112 116D 11BB;D6BC;1112 116D 11BB; # (횼; 횼; 횼; 횼; 횼; ) HANGUL SYLLABLE HYOSS +D6BD;D6BD;1112 116D 11BC;D6BD;1112 116D 11BC; # (횽; 횽; 횽; 횽; 횽; ) HANGUL SYLLABLE HYONG +D6BE;D6BE;1112 116D 11BD;D6BE;1112 116D 11BD; # (횾; 횾; 횾; 횾; 횾; ) HANGUL SYLLABLE HYOJ +D6BF;D6BF;1112 116D 11BE;D6BF;1112 116D 11BE; # (횿; 횿; 횿; 횿; 횿; ) HANGUL SYLLABLE HYOC +D6C0;D6C0;1112 116D 11BF;D6C0;1112 116D 11BF; # (훀; 훀; 훀; 훀; 훀; ) HANGUL SYLLABLE HYOK +D6C1;D6C1;1112 116D 11C0;D6C1;1112 116D 11C0; # (훁; 훁; 훁; 훁; 훁; ) HANGUL SYLLABLE HYOT +D6C2;D6C2;1112 116D 11C1;D6C2;1112 116D 11C1; # (훂; 훂; 훂; 훂; 훂; ) HANGUL SYLLABLE HYOP +D6C3;D6C3;1112 116D 11C2;D6C3;1112 116D 11C2; # (훃; 훃; 훃; 훃; 훃; ) HANGUL SYLLABLE HYOH +D6C4;D6C4;1112 116E;D6C4;1112 116E; # (후; 후; 후; 후; 후; ) HANGUL SYLLABLE HU +D6C5;D6C5;1112 116E 11A8;D6C5;1112 116E 11A8; # (훅; 훅; 훅; 훅; 훅; ) HANGUL SYLLABLE HUG +D6C6;D6C6;1112 116E 11A9;D6C6;1112 116E 11A9; # (훆; 훆; 훆; 훆; 훆; ) HANGUL SYLLABLE HUGG +D6C7;D6C7;1112 116E 11AA;D6C7;1112 116E 11AA; # (훇; 훇; 훇; 훇; 훇; ) HANGUL SYLLABLE HUGS +D6C8;D6C8;1112 116E 11AB;D6C8;1112 116E 11AB; # (훈; 훈; 훈; 훈; 훈; ) HANGUL SYLLABLE HUN +D6C9;D6C9;1112 116E 11AC;D6C9;1112 116E 11AC; # (훉; 훉; 훉; 훉; 훉; ) HANGUL SYLLABLE HUNJ +D6CA;D6CA;1112 116E 11AD;D6CA;1112 116E 11AD; # (훊; 훊; 훊; 훊; 훊; ) HANGUL SYLLABLE HUNH +D6CB;D6CB;1112 116E 11AE;D6CB;1112 116E 11AE; # (훋; 훋; 훋; 훋; 훋; ) HANGUL SYLLABLE HUD +D6CC;D6CC;1112 116E 11AF;D6CC;1112 116E 11AF; # (훌; 훌; 훌; 훌; 훌; ) HANGUL SYLLABLE HUL +D6CD;D6CD;1112 116E 11B0;D6CD;1112 116E 11B0; # (훍; 훍; 훍; 훍; 훍; ) HANGUL SYLLABLE HULG +D6CE;D6CE;1112 116E 11B1;D6CE;1112 116E 11B1; # (훎; 훎; 훎; 훎; 훎; ) HANGUL SYLLABLE HULM +D6CF;D6CF;1112 116E 11B2;D6CF;1112 116E 11B2; # (훏; 훏; 훏; 훏; 훏; ) HANGUL SYLLABLE HULB +D6D0;D6D0;1112 116E 11B3;D6D0;1112 116E 11B3; # (훐; 훐; 훐; 훐; 훐; ) HANGUL SYLLABLE HULS +D6D1;D6D1;1112 116E 11B4;D6D1;1112 116E 11B4; # (훑; 훑; 훑; 훑; 훑; ) HANGUL SYLLABLE HULT +D6D2;D6D2;1112 116E 11B5;D6D2;1112 116E 11B5; # (훒; 훒; 훒; 훒; 훒; ) HANGUL SYLLABLE HULP +D6D3;D6D3;1112 116E 11B6;D6D3;1112 116E 11B6; # (훓; 훓; 훓; 훓; 훓; ) HANGUL SYLLABLE HULH +D6D4;D6D4;1112 116E 11B7;D6D4;1112 116E 11B7; # (훔; 훔; 훔; 훔; 훔; ) HANGUL SYLLABLE HUM +D6D5;D6D5;1112 116E 11B8;D6D5;1112 116E 11B8; # (훕; 훕; 훕; 훕; 훕; ) HANGUL SYLLABLE HUB +D6D6;D6D6;1112 116E 11B9;D6D6;1112 116E 11B9; # (훖; 훖; 훖; 훖; 훖; ) HANGUL SYLLABLE HUBS +D6D7;D6D7;1112 116E 11BA;D6D7;1112 116E 11BA; # (훗; 훗; 훗; 훗; 훗; ) HANGUL SYLLABLE HUS +D6D8;D6D8;1112 116E 11BB;D6D8;1112 116E 11BB; # (훘; 훘; 훘; 훘; 훘; ) HANGUL SYLLABLE HUSS +D6D9;D6D9;1112 116E 11BC;D6D9;1112 116E 11BC; # (훙; 훙; 훙; 훙; 훙; ) HANGUL SYLLABLE HUNG +D6DA;D6DA;1112 116E 11BD;D6DA;1112 116E 11BD; # (훚; 훚; 훚; 훚; 훚; ) HANGUL SYLLABLE HUJ +D6DB;D6DB;1112 116E 11BE;D6DB;1112 116E 11BE; # (훛; 훛; 훛; 훛; 훛; ) HANGUL SYLLABLE HUC +D6DC;D6DC;1112 116E 11BF;D6DC;1112 116E 11BF; # (훜; 훜; 훜; 훜; 훜; ) HANGUL SYLLABLE HUK +D6DD;D6DD;1112 116E 11C0;D6DD;1112 116E 11C0; # (훝; 훝; 훝; 훝; 훝; ) HANGUL SYLLABLE HUT +D6DE;D6DE;1112 116E 11C1;D6DE;1112 116E 11C1; # (훞; 훞; 훞; 훞; 훞; ) HANGUL SYLLABLE HUP +D6DF;D6DF;1112 116E 11C2;D6DF;1112 116E 11C2; # (훟; 훟; 훟; 훟; 훟; ) HANGUL SYLLABLE HUH +D6E0;D6E0;1112 116F;D6E0;1112 116F; # (훠; 훠; 훠; 훠; 훠; ) HANGUL SYLLABLE HWEO +D6E1;D6E1;1112 116F 11A8;D6E1;1112 116F 11A8; # (훡; 훡; 훡; 훡; 훡; ) HANGUL SYLLABLE HWEOG +D6E2;D6E2;1112 116F 11A9;D6E2;1112 116F 11A9; # (훢; 훢; 훢; 훢; 훢; ) HANGUL SYLLABLE HWEOGG +D6E3;D6E3;1112 116F 11AA;D6E3;1112 116F 11AA; # (훣; 훣; 훣; 훣; 훣; ) HANGUL SYLLABLE HWEOGS +D6E4;D6E4;1112 116F 11AB;D6E4;1112 116F 11AB; # (훤; 훤; 훤; 훤; 훤; ) HANGUL SYLLABLE HWEON +D6E5;D6E5;1112 116F 11AC;D6E5;1112 116F 11AC; # (훥; 훥; 훥; 훥; 훥; ) HANGUL SYLLABLE HWEONJ +D6E6;D6E6;1112 116F 11AD;D6E6;1112 116F 11AD; # (훦; 훦; 훦; 훦; 훦; ) HANGUL SYLLABLE HWEONH +D6E7;D6E7;1112 116F 11AE;D6E7;1112 116F 11AE; # (훧; 훧; 훧; 훧; 훧; ) HANGUL SYLLABLE HWEOD +D6E8;D6E8;1112 116F 11AF;D6E8;1112 116F 11AF; # (훨; 훨; 훨; 훨; 훨; ) HANGUL SYLLABLE HWEOL +D6E9;D6E9;1112 116F 11B0;D6E9;1112 116F 11B0; # (훩; 훩; 훩; 훩; 훩; ) HANGUL SYLLABLE HWEOLG +D6EA;D6EA;1112 116F 11B1;D6EA;1112 116F 11B1; # (훪; 훪; 훪; 훪; 훪; ) HANGUL SYLLABLE HWEOLM +D6EB;D6EB;1112 116F 11B2;D6EB;1112 116F 11B2; # (훫; 훫; 훫; 훫; 훫; ) HANGUL SYLLABLE HWEOLB +D6EC;D6EC;1112 116F 11B3;D6EC;1112 116F 11B3; # (훬; 훬; 훬; 훬; 훬; ) HANGUL SYLLABLE HWEOLS +D6ED;D6ED;1112 116F 11B4;D6ED;1112 116F 11B4; # (훭; 훭; 훭; 훭; 훭; ) HANGUL SYLLABLE HWEOLT +D6EE;D6EE;1112 116F 11B5;D6EE;1112 116F 11B5; # (훮; 훮; 훮; 훮; 훮; ) HANGUL SYLLABLE HWEOLP +D6EF;D6EF;1112 116F 11B6;D6EF;1112 116F 11B6; # (훯; 훯; 훯; 훯; 훯; ) HANGUL SYLLABLE HWEOLH +D6F0;D6F0;1112 116F 11B7;D6F0;1112 116F 11B7; # (훰; 훰; 훰; 훰; 훰; ) HANGUL SYLLABLE HWEOM +D6F1;D6F1;1112 116F 11B8;D6F1;1112 116F 11B8; # (훱; 훱; 훱; 훱; 훱; ) HANGUL SYLLABLE HWEOB +D6F2;D6F2;1112 116F 11B9;D6F2;1112 116F 11B9; # (훲; 훲; 훲; 훲; 훲; ) HANGUL SYLLABLE HWEOBS +D6F3;D6F3;1112 116F 11BA;D6F3;1112 116F 11BA; # (훳; 훳; 훳; 훳; 훳; ) HANGUL SYLLABLE HWEOS +D6F4;D6F4;1112 116F 11BB;D6F4;1112 116F 11BB; # (훴; 훴; 훴; 훴; 훴; ) HANGUL SYLLABLE HWEOSS +D6F5;D6F5;1112 116F 11BC;D6F5;1112 116F 11BC; # (훵; 훵; 훵; 훵; 훵; ) HANGUL SYLLABLE HWEONG +D6F6;D6F6;1112 116F 11BD;D6F6;1112 116F 11BD; # (훶; 훶; 훶; 훶; 훶; ) HANGUL SYLLABLE HWEOJ +D6F7;D6F7;1112 116F 11BE;D6F7;1112 116F 11BE; # (훷; 훷; 훷; 훷; 훷; ) HANGUL SYLLABLE HWEOC +D6F8;D6F8;1112 116F 11BF;D6F8;1112 116F 11BF; # (훸; 훸; 훸; 훸; 훸; ) HANGUL SYLLABLE HWEOK +D6F9;D6F9;1112 116F 11C0;D6F9;1112 116F 11C0; # (훹; 훹; 훹; 훹; 훹; ) HANGUL SYLLABLE HWEOT +D6FA;D6FA;1112 116F 11C1;D6FA;1112 116F 11C1; # (훺; 훺; 훺; 훺; 훺; ) HANGUL SYLLABLE HWEOP +D6FB;D6FB;1112 116F 11C2;D6FB;1112 116F 11C2; # (훻; 훻; 훻; 훻; 훻; ) HANGUL SYLLABLE HWEOH +D6FC;D6FC;1112 1170;D6FC;1112 1170; # (훼; 훼; 훼; 훼; 훼; ) HANGUL SYLLABLE HWE +D6FD;D6FD;1112 1170 11A8;D6FD;1112 1170 11A8; # (훽; 훽; 훽; 훽; 훽; ) HANGUL SYLLABLE HWEG +D6FE;D6FE;1112 1170 11A9;D6FE;1112 1170 11A9; # (훾; 훾; 훾; 훾; 훾; ) HANGUL SYLLABLE HWEGG +D6FF;D6FF;1112 1170 11AA;D6FF;1112 1170 11AA; # (훿; 훿; 훿; 훿; 훿; ) HANGUL SYLLABLE HWEGS +D700;D700;1112 1170 11AB;D700;1112 1170 11AB; # (휀; 휀; 휀; 휀; 휀; ) HANGUL SYLLABLE HWEN +D701;D701;1112 1170 11AC;D701;1112 1170 11AC; # (휁; 휁; 휁; 휁; 휁; ) HANGUL SYLLABLE HWENJ +D702;D702;1112 1170 11AD;D702;1112 1170 11AD; # (휂; 휂; 휂; 휂; 휂; ) HANGUL SYLLABLE HWENH +D703;D703;1112 1170 11AE;D703;1112 1170 11AE; # (휃; 휃; 휃; 휃; 휃; ) HANGUL SYLLABLE HWED +D704;D704;1112 1170 11AF;D704;1112 1170 11AF; # (휄; 휄; 휄; 휄; 휄; ) HANGUL SYLLABLE HWEL +D705;D705;1112 1170 11B0;D705;1112 1170 11B0; # (휅; 휅; 휅; 휅; 휅; ) HANGUL SYLLABLE HWELG +D706;D706;1112 1170 11B1;D706;1112 1170 11B1; # (휆; 휆; 휆; 휆; 휆; ) HANGUL SYLLABLE HWELM +D707;D707;1112 1170 11B2;D707;1112 1170 11B2; # (휇; 휇; 휇; 휇; 휇; ) HANGUL SYLLABLE HWELB +D708;D708;1112 1170 11B3;D708;1112 1170 11B3; # (휈; 휈; 휈; 휈; 휈; ) HANGUL SYLLABLE HWELS +D709;D709;1112 1170 11B4;D709;1112 1170 11B4; # (휉; 휉; 휉; 휉; 휉; ) HANGUL SYLLABLE HWELT +D70A;D70A;1112 1170 11B5;D70A;1112 1170 11B5; # (휊; 휊; 휊; 휊; 휊; ) HANGUL SYLLABLE HWELP +D70B;D70B;1112 1170 11B6;D70B;1112 1170 11B6; # (휋; 휋; 휋; 휋; 휋; ) HANGUL SYLLABLE HWELH +D70C;D70C;1112 1170 11B7;D70C;1112 1170 11B7; # (휌; 휌; 휌; 휌; 휌; ) HANGUL SYLLABLE HWEM +D70D;D70D;1112 1170 11B8;D70D;1112 1170 11B8; # (휍; 휍; 휍; 휍; 휍; ) HANGUL SYLLABLE HWEB +D70E;D70E;1112 1170 11B9;D70E;1112 1170 11B9; # (휎; 휎; 휎; 휎; 휎; ) HANGUL SYLLABLE HWEBS +D70F;D70F;1112 1170 11BA;D70F;1112 1170 11BA; # (휏; 휏; 휏; 휏; 휏; ) HANGUL SYLLABLE HWES +D710;D710;1112 1170 11BB;D710;1112 1170 11BB; # (휐; 휐; 휐; 휐; 휐; ) HANGUL SYLLABLE HWESS +D711;D711;1112 1170 11BC;D711;1112 1170 11BC; # (휑; 휑; 휑; 휑; 휑; ) HANGUL SYLLABLE HWENG +D712;D712;1112 1170 11BD;D712;1112 1170 11BD; # (휒; 휒; 휒; 휒; 휒; ) HANGUL SYLLABLE HWEJ +D713;D713;1112 1170 11BE;D713;1112 1170 11BE; # (휓; 휓; 휓; 휓; 휓; ) HANGUL SYLLABLE HWEC +D714;D714;1112 1170 11BF;D714;1112 1170 11BF; # (휔; 휔; 휔; 휔; 휔; ) HANGUL SYLLABLE HWEK +D715;D715;1112 1170 11C0;D715;1112 1170 11C0; # (휕; 휕; 휕; 휕; 휕; ) HANGUL SYLLABLE HWET +D716;D716;1112 1170 11C1;D716;1112 1170 11C1; # (휖; 휖; 휖; 휖; 휖; ) HANGUL SYLLABLE HWEP +D717;D717;1112 1170 11C2;D717;1112 1170 11C2; # (휗; 휗; 휗; 휗; 휗; ) HANGUL SYLLABLE HWEH +D718;D718;1112 1171;D718;1112 1171; # (휘; 휘; 휘; 휘; 휘; ) HANGUL SYLLABLE HWI +D719;D719;1112 1171 11A8;D719;1112 1171 11A8; # (휙; 휙; 휙; 휙; 휙; ) HANGUL SYLLABLE HWIG +D71A;D71A;1112 1171 11A9;D71A;1112 1171 11A9; # (휚; 휚; 휚; 휚; 휚; ) HANGUL SYLLABLE HWIGG +D71B;D71B;1112 1171 11AA;D71B;1112 1171 11AA; # (휛; 휛; 휛; 휛; 휛; ) HANGUL SYLLABLE HWIGS +D71C;D71C;1112 1171 11AB;D71C;1112 1171 11AB; # (휜; 휜; 휜; 휜; 휜; ) HANGUL SYLLABLE HWIN +D71D;D71D;1112 1171 11AC;D71D;1112 1171 11AC; # (휝; 휝; 휝; 휝; 휝; ) HANGUL SYLLABLE HWINJ +D71E;D71E;1112 1171 11AD;D71E;1112 1171 11AD; # (휞; 휞; 휞; 휞; 휞; ) HANGUL SYLLABLE HWINH +D71F;D71F;1112 1171 11AE;D71F;1112 1171 11AE; # (휟; 휟; 휟; 휟; 휟; ) HANGUL SYLLABLE HWID +D720;D720;1112 1171 11AF;D720;1112 1171 11AF; # (휠; 휠; 휠; 휠; 휠; ) HANGUL SYLLABLE HWIL +D721;D721;1112 1171 11B0;D721;1112 1171 11B0; # (휡; 휡; 휡; 휡; 휡; ) HANGUL SYLLABLE HWILG +D722;D722;1112 1171 11B1;D722;1112 1171 11B1; # (휢; 휢; 휢; 휢; 휢; ) HANGUL SYLLABLE HWILM +D723;D723;1112 1171 11B2;D723;1112 1171 11B2; # (휣; 휣; 휣; 휣; 휣; ) HANGUL SYLLABLE HWILB +D724;D724;1112 1171 11B3;D724;1112 1171 11B3; # (휤; 휤; 휤; 휤; 휤; ) HANGUL SYLLABLE HWILS +D725;D725;1112 1171 11B4;D725;1112 1171 11B4; # (휥; 휥; 휥; 휥; 휥; ) HANGUL SYLLABLE HWILT +D726;D726;1112 1171 11B5;D726;1112 1171 11B5; # (휦; 휦; 휦; 휦; 휦; ) HANGUL SYLLABLE HWILP +D727;D727;1112 1171 11B6;D727;1112 1171 11B6; # (휧; 휧; 휧; 휧; 휧; ) HANGUL SYLLABLE HWILH +D728;D728;1112 1171 11B7;D728;1112 1171 11B7; # (휨; 휨; 휨; 휨; 휨; ) HANGUL SYLLABLE HWIM +D729;D729;1112 1171 11B8;D729;1112 1171 11B8; # (휩; 휩; 휩; 휩; 휩; ) HANGUL SYLLABLE HWIB +D72A;D72A;1112 1171 11B9;D72A;1112 1171 11B9; # (휪; 휪; 휪; 휪; 휪; ) HANGUL SYLLABLE HWIBS +D72B;D72B;1112 1171 11BA;D72B;1112 1171 11BA; # (휫; 휫; 휫; 휫; 휫; ) HANGUL SYLLABLE HWIS +D72C;D72C;1112 1171 11BB;D72C;1112 1171 11BB; # (휬; 휬; 휬; 휬; 휬; ) HANGUL SYLLABLE HWISS +D72D;D72D;1112 1171 11BC;D72D;1112 1171 11BC; # (휭; 휭; 휭; 휭; 휭; ) HANGUL SYLLABLE HWING +D72E;D72E;1112 1171 11BD;D72E;1112 1171 11BD; # (휮; 휮; 휮; 휮; 휮; ) HANGUL SYLLABLE HWIJ +D72F;D72F;1112 1171 11BE;D72F;1112 1171 11BE; # (휯; 휯; 휯; 휯; 휯; ) HANGUL SYLLABLE HWIC +D730;D730;1112 1171 11BF;D730;1112 1171 11BF; # (휰; 휰; 휰; 휰; 휰; ) HANGUL SYLLABLE HWIK +D731;D731;1112 1171 11C0;D731;1112 1171 11C0; # (휱; 휱; 휱; 휱; 휱; ) HANGUL SYLLABLE HWIT +D732;D732;1112 1171 11C1;D732;1112 1171 11C1; # (휲; 휲; 휲; 휲; 휲; ) HANGUL SYLLABLE HWIP +D733;D733;1112 1171 11C2;D733;1112 1171 11C2; # (휳; 휳; 휳; 휳; 휳; ) HANGUL SYLLABLE HWIH +D734;D734;1112 1172;D734;1112 1172; # (휴; 휴; 휴; 휴; 휴; ) HANGUL SYLLABLE HYU +D735;D735;1112 1172 11A8;D735;1112 1172 11A8; # (휵; 휵; 휵; 휵; 휵; ) HANGUL SYLLABLE HYUG +D736;D736;1112 1172 11A9;D736;1112 1172 11A9; # (휶; 휶; 휶; 휶; 휶; ) HANGUL SYLLABLE HYUGG +D737;D737;1112 1172 11AA;D737;1112 1172 11AA; # (휷; 휷; 휷; 휷; 휷; ) HANGUL SYLLABLE HYUGS +D738;D738;1112 1172 11AB;D738;1112 1172 11AB; # (휸; 휸; 휸; 휸; 휸; ) HANGUL SYLLABLE HYUN +D739;D739;1112 1172 11AC;D739;1112 1172 11AC; # (휹; 휹; 휹; 휹; 휹; ) HANGUL SYLLABLE HYUNJ +D73A;D73A;1112 1172 11AD;D73A;1112 1172 11AD; # (휺; 휺; 휺; 휺; 휺; ) HANGUL SYLLABLE HYUNH +D73B;D73B;1112 1172 11AE;D73B;1112 1172 11AE; # (휻; 휻; 휻; 휻; 휻; ) HANGUL SYLLABLE HYUD +D73C;D73C;1112 1172 11AF;D73C;1112 1172 11AF; # (휼; 휼; 휼; 휼; 휼; ) HANGUL SYLLABLE HYUL +D73D;D73D;1112 1172 11B0;D73D;1112 1172 11B0; # (휽; 휽; 휽; 휽; 휽; ) HANGUL SYLLABLE HYULG +D73E;D73E;1112 1172 11B1;D73E;1112 1172 11B1; # (휾; 휾; 휾; 휾; 휾; ) HANGUL SYLLABLE HYULM +D73F;D73F;1112 1172 11B2;D73F;1112 1172 11B2; # (휿; 휿; 휿; 휿; 휿; ) HANGUL SYLLABLE HYULB +D740;D740;1112 1172 11B3;D740;1112 1172 11B3; # (흀; 흀; 흀; 흀; 흀; ) HANGUL SYLLABLE HYULS +D741;D741;1112 1172 11B4;D741;1112 1172 11B4; # (흁; 흁; 흁; 흁; 흁; ) HANGUL SYLLABLE HYULT +D742;D742;1112 1172 11B5;D742;1112 1172 11B5; # (흂; 흂; 흂; 흂; 흂; ) HANGUL SYLLABLE HYULP +D743;D743;1112 1172 11B6;D743;1112 1172 11B6; # (흃; 흃; 흃; 흃; 흃; ) HANGUL SYLLABLE HYULH +D744;D744;1112 1172 11B7;D744;1112 1172 11B7; # (흄; 흄; 흄; 흄; 흄; ) HANGUL SYLLABLE HYUM +D745;D745;1112 1172 11B8;D745;1112 1172 11B8; # (흅; 흅; 흅; 흅; 흅; ) HANGUL SYLLABLE HYUB +D746;D746;1112 1172 11B9;D746;1112 1172 11B9; # (흆; 흆; 흆; 흆; 흆; ) HANGUL SYLLABLE HYUBS +D747;D747;1112 1172 11BA;D747;1112 1172 11BA; # (흇; 흇; 흇; 흇; 흇; ) HANGUL SYLLABLE HYUS +D748;D748;1112 1172 11BB;D748;1112 1172 11BB; # (흈; 흈; 흈; 흈; 흈; ) HANGUL SYLLABLE HYUSS +D749;D749;1112 1172 11BC;D749;1112 1172 11BC; # (흉; 흉; 흉; 흉; 흉; ) HANGUL SYLLABLE HYUNG +D74A;D74A;1112 1172 11BD;D74A;1112 1172 11BD; # (흊; 흊; 흊; 흊; 흊; ) HANGUL SYLLABLE HYUJ +D74B;D74B;1112 1172 11BE;D74B;1112 1172 11BE; # (흋; 흋; 흋; 흋; 흋; ) HANGUL SYLLABLE HYUC +D74C;D74C;1112 1172 11BF;D74C;1112 1172 11BF; # (흌; 흌; 흌; 흌; 흌; ) HANGUL SYLLABLE HYUK +D74D;D74D;1112 1172 11C0;D74D;1112 1172 11C0; # (흍; 흍; 흍; 흍; 흍; ) HANGUL SYLLABLE HYUT +D74E;D74E;1112 1172 11C1;D74E;1112 1172 11C1; # (흎; 흎; 흎; 흎; 흎; ) HANGUL SYLLABLE HYUP +D74F;D74F;1112 1172 11C2;D74F;1112 1172 11C2; # (흏; 흏; 흏; 흏; 흏; ) HANGUL SYLLABLE HYUH +D750;D750;1112 1173;D750;1112 1173; # (흐; 흐; 흐; 흐; 흐; ) HANGUL SYLLABLE HEU +D751;D751;1112 1173 11A8;D751;1112 1173 11A8; # (흑; 흑; 흑; 흑; 흑; ) HANGUL SYLLABLE HEUG +D752;D752;1112 1173 11A9;D752;1112 1173 11A9; # (흒; 흒; 흒; 흒; 흒; ) HANGUL SYLLABLE HEUGG +D753;D753;1112 1173 11AA;D753;1112 1173 11AA; # (흓; 흓; 흓; 흓; 흓; ) HANGUL SYLLABLE HEUGS +D754;D754;1112 1173 11AB;D754;1112 1173 11AB; # (흔; 흔; 흔; 흔; 흔; ) HANGUL SYLLABLE HEUN +D755;D755;1112 1173 11AC;D755;1112 1173 11AC; # (흕; 흕; 흕; 흕; 흕; ) HANGUL SYLLABLE HEUNJ +D756;D756;1112 1173 11AD;D756;1112 1173 11AD; # (흖; 흖; 흖; 흖; 흖; ) HANGUL SYLLABLE HEUNH +D757;D757;1112 1173 11AE;D757;1112 1173 11AE; # (흗; 흗; 흗; 흗; 흗; ) HANGUL SYLLABLE HEUD +D758;D758;1112 1173 11AF;D758;1112 1173 11AF; # (흘; 흘; 흘; 흘; 흘; ) HANGUL SYLLABLE HEUL +D759;D759;1112 1173 11B0;D759;1112 1173 11B0; # (흙; 흙; 흙; 흙; 흙; ) HANGUL SYLLABLE HEULG +D75A;D75A;1112 1173 11B1;D75A;1112 1173 11B1; # (흚; 흚; 흚; 흚; 흚; ) HANGUL SYLLABLE HEULM +D75B;D75B;1112 1173 11B2;D75B;1112 1173 11B2; # (흛; 흛; 흛; 흛; 흛; ) HANGUL SYLLABLE HEULB +D75C;D75C;1112 1173 11B3;D75C;1112 1173 11B3; # (흜; 흜; 흜; 흜; 흜; ) HANGUL SYLLABLE HEULS +D75D;D75D;1112 1173 11B4;D75D;1112 1173 11B4; # (흝; 흝; 흝; 흝; 흝; ) HANGUL SYLLABLE HEULT +D75E;D75E;1112 1173 11B5;D75E;1112 1173 11B5; # (흞; 흞; 흞; 흞; 흞; ) HANGUL SYLLABLE HEULP +D75F;D75F;1112 1173 11B6;D75F;1112 1173 11B6; # (흟; 흟; 흟; 흟; 흟; ) HANGUL SYLLABLE HEULH +D760;D760;1112 1173 11B7;D760;1112 1173 11B7; # (흠; 흠; 흠; 흠; 흠; ) HANGUL SYLLABLE HEUM +D761;D761;1112 1173 11B8;D761;1112 1173 11B8; # (흡; 흡; 흡; 흡; 흡; ) HANGUL SYLLABLE HEUB +D762;D762;1112 1173 11B9;D762;1112 1173 11B9; # (흢; 흢; 흢; 흢; 흢; ) HANGUL SYLLABLE HEUBS +D763;D763;1112 1173 11BA;D763;1112 1173 11BA; # (흣; 흣; 흣; 흣; 흣; ) HANGUL SYLLABLE HEUS +D764;D764;1112 1173 11BB;D764;1112 1173 11BB; # (흤; 흤; 흤; 흤; 흤; ) HANGUL SYLLABLE HEUSS +D765;D765;1112 1173 11BC;D765;1112 1173 11BC; # (흥; 흥; 흥; 흥; 흥; ) HANGUL SYLLABLE HEUNG +D766;D766;1112 1173 11BD;D766;1112 1173 11BD; # (흦; 흦; 흦; 흦; 흦; ) HANGUL SYLLABLE HEUJ +D767;D767;1112 1173 11BE;D767;1112 1173 11BE; # (흧; 흧; 흧; 흧; 흧; ) HANGUL SYLLABLE HEUC +D768;D768;1112 1173 11BF;D768;1112 1173 11BF; # (흨; 흨; 흨; 흨; 흨; ) HANGUL SYLLABLE HEUK +D769;D769;1112 1173 11C0;D769;1112 1173 11C0; # (흩; 흩; 흩; 흩; 흩; ) HANGUL SYLLABLE HEUT +D76A;D76A;1112 1173 11C1;D76A;1112 1173 11C1; # (흪; 흪; 흪; 흪; 흪; ) HANGUL SYLLABLE HEUP +D76B;D76B;1112 1173 11C2;D76B;1112 1173 11C2; # (흫; 흫; 흫; 흫; 흫; ) HANGUL SYLLABLE HEUH +D76C;D76C;1112 1174;D76C;1112 1174; # (희; 희; 희; 희; 희; ) HANGUL SYLLABLE HYI +D76D;D76D;1112 1174 11A8;D76D;1112 1174 11A8; # (흭; 흭; 흭; 흭; 흭; ) HANGUL SYLLABLE HYIG +D76E;D76E;1112 1174 11A9;D76E;1112 1174 11A9; # (흮; 흮; 흮; 흮; 흮; ) HANGUL SYLLABLE HYIGG +D76F;D76F;1112 1174 11AA;D76F;1112 1174 11AA; # (흯; 흯; 흯; 흯; 흯; ) HANGUL SYLLABLE HYIGS +D770;D770;1112 1174 11AB;D770;1112 1174 11AB; # (흰; 흰; 흰; 흰; 흰; ) HANGUL SYLLABLE HYIN +D771;D771;1112 1174 11AC;D771;1112 1174 11AC; # (흱; 흱; 흱; 흱; 흱; ) HANGUL SYLLABLE HYINJ +D772;D772;1112 1174 11AD;D772;1112 1174 11AD; # (흲; 흲; 흲; 흲; 흲; ) HANGUL SYLLABLE HYINH +D773;D773;1112 1174 11AE;D773;1112 1174 11AE; # (흳; 흳; 흳; 흳; 흳; ) HANGUL SYLLABLE HYID +D774;D774;1112 1174 11AF;D774;1112 1174 11AF; # (흴; 흴; 흴; 흴; 흴; ) HANGUL SYLLABLE HYIL +D775;D775;1112 1174 11B0;D775;1112 1174 11B0; # (흵; 흵; 흵; 흵; 흵; ) HANGUL SYLLABLE HYILG +D776;D776;1112 1174 11B1;D776;1112 1174 11B1; # (흶; 흶; 흶; 흶; 흶; ) HANGUL SYLLABLE HYILM +D777;D777;1112 1174 11B2;D777;1112 1174 11B2; # (흷; 흷; 흷; 흷; 흷; ) HANGUL SYLLABLE HYILB +D778;D778;1112 1174 11B3;D778;1112 1174 11B3; # (흸; 흸; 흸; 흸; 흸; ) HANGUL SYLLABLE HYILS +D779;D779;1112 1174 11B4;D779;1112 1174 11B4; # (흹; 흹; 흹; 흹; 흹; ) HANGUL SYLLABLE HYILT +D77A;D77A;1112 1174 11B5;D77A;1112 1174 11B5; # (흺; 흺; 흺; 흺; 흺; ) HANGUL SYLLABLE HYILP +D77B;D77B;1112 1174 11B6;D77B;1112 1174 11B6; # (흻; 흻; 흻; 흻; 흻; ) HANGUL SYLLABLE HYILH +D77C;D77C;1112 1174 11B7;D77C;1112 1174 11B7; # (흼; 흼; 흼; 흼; 흼; ) HANGUL SYLLABLE HYIM +D77D;D77D;1112 1174 11B8;D77D;1112 1174 11B8; # (흽; 흽; 흽; 흽; 흽; ) HANGUL SYLLABLE HYIB +D77E;D77E;1112 1174 11B9;D77E;1112 1174 11B9; # (흾; 흾; 흾; 흾; 흾; ) HANGUL SYLLABLE HYIBS +D77F;D77F;1112 1174 11BA;D77F;1112 1174 11BA; # (흿; 흿; 흿; 흿; 흿; ) HANGUL SYLLABLE HYIS +D780;D780;1112 1174 11BB;D780;1112 1174 11BB; # (힀; 힀; 힀; 힀; 힀; ) HANGUL SYLLABLE HYISS +D781;D781;1112 1174 11BC;D781;1112 1174 11BC; # (힁; 힁; 힁; 힁; 힁; ) HANGUL SYLLABLE HYING +D782;D782;1112 1174 11BD;D782;1112 1174 11BD; # (힂; 힂; 힂; 힂; 힂; ) HANGUL SYLLABLE HYIJ +D783;D783;1112 1174 11BE;D783;1112 1174 11BE; # (힃; 힃; 힃; 힃; 힃; ) HANGUL SYLLABLE HYIC +D784;D784;1112 1174 11BF;D784;1112 1174 11BF; # (힄; 힄; 힄; 힄; 힄; ) HANGUL SYLLABLE HYIK +D785;D785;1112 1174 11C0;D785;1112 1174 11C0; # (힅; 힅; 힅; 힅; 힅; ) HANGUL SYLLABLE HYIT +D786;D786;1112 1174 11C1;D786;1112 1174 11C1; # (힆; 힆; 힆; 힆; 힆; ) HANGUL SYLLABLE HYIP +D787;D787;1112 1174 11C2;D787;1112 1174 11C2; # (힇; 힇; 힇; 힇; 힇; ) HANGUL SYLLABLE HYIH +D788;D788;1112 1175;D788;1112 1175; # (히; 히; 히; 히; 히; ) HANGUL SYLLABLE HI +D789;D789;1112 1175 11A8;D789;1112 1175 11A8; # (힉; 힉; 힉; 힉; 힉; ) HANGUL SYLLABLE HIG +D78A;D78A;1112 1175 11A9;D78A;1112 1175 11A9; # (힊; 힊; 힊; 힊; 힊; ) HANGUL SYLLABLE HIGG +D78B;D78B;1112 1175 11AA;D78B;1112 1175 11AA; # (힋; 힋; 힋; 힋; 힋; ) HANGUL SYLLABLE HIGS +D78C;D78C;1112 1175 11AB;D78C;1112 1175 11AB; # (힌; 힌; 힌; 힌; 힌; ) HANGUL SYLLABLE HIN +D78D;D78D;1112 1175 11AC;D78D;1112 1175 11AC; # (힍; 힍; 힍; 힍; 힍; ) HANGUL SYLLABLE HINJ +D78E;D78E;1112 1175 11AD;D78E;1112 1175 11AD; # (힎; 힎; 힎; 힎; 힎; ) HANGUL SYLLABLE HINH +D78F;D78F;1112 1175 11AE;D78F;1112 1175 11AE; # (힏; 힏; 힏; 힏; 힏; ) HANGUL SYLLABLE HID +D790;D790;1112 1175 11AF;D790;1112 1175 11AF; # (힐; 힐; 힐; 힐; 힐; ) HANGUL SYLLABLE HIL +D791;D791;1112 1175 11B0;D791;1112 1175 11B0; # (힑; 힑; 힑; 힑; 힑; ) HANGUL SYLLABLE HILG +D792;D792;1112 1175 11B1;D792;1112 1175 11B1; # (힒; 힒; 힒; 힒; 힒; ) HANGUL SYLLABLE HILM +D793;D793;1112 1175 11B2;D793;1112 1175 11B2; # (힓; 힓; 힓; 힓; 힓; ) HANGUL SYLLABLE HILB +D794;D794;1112 1175 11B3;D794;1112 1175 11B3; # (힔; 힔; 힔; 힔; 힔; ) HANGUL SYLLABLE HILS +D795;D795;1112 1175 11B4;D795;1112 1175 11B4; # (힕; 힕; 힕; 힕; 힕; ) HANGUL SYLLABLE HILT +D796;D796;1112 1175 11B5;D796;1112 1175 11B5; # (힖; 힖; 힖; 힖; 힖; ) HANGUL SYLLABLE HILP +D797;D797;1112 1175 11B6;D797;1112 1175 11B6; # (힗; 힗; 힗; 힗; 힗; ) HANGUL SYLLABLE HILH +D798;D798;1112 1175 11B7;D798;1112 1175 11B7; # (힘; 힘; 힘; 힘; 힘; ) HANGUL SYLLABLE HIM +D799;D799;1112 1175 11B8;D799;1112 1175 11B8; # (힙; 힙; 힙; 힙; 힙; ) HANGUL SYLLABLE HIB +D79A;D79A;1112 1175 11B9;D79A;1112 1175 11B9; # (힚; 힚; 힚; 힚; 힚; ) HANGUL SYLLABLE HIBS +D79B;D79B;1112 1175 11BA;D79B;1112 1175 11BA; # (힛; 힛; 힛; 힛; 힛; ) HANGUL SYLLABLE HIS +D79C;D79C;1112 1175 11BB;D79C;1112 1175 11BB; # (힜; 힜; 힜; 힜; 힜; ) HANGUL SYLLABLE HISS +D79D;D79D;1112 1175 11BC;D79D;1112 1175 11BC; # (힝; 힝; 힝; 힝; 힝; ) HANGUL SYLLABLE HING +D79E;D79E;1112 1175 11BD;D79E;1112 1175 11BD; # (힞; 힞; 힞; 힞; 힞; ) HANGUL SYLLABLE HIJ +D79F;D79F;1112 1175 11BE;D79F;1112 1175 11BE; # (힟; 힟; 힟; 힟; 힟; ) HANGUL SYLLABLE HIC +D7A0;D7A0;1112 1175 11BF;D7A0;1112 1175 11BF; # (힠; 힠; 힠; 힠; 힠; ) HANGUL SYLLABLE HIK +D7A1;D7A1;1112 1175 11C0;D7A1;1112 1175 11C0; # (힡; 힡; 힡; 힡; 힡; ) HANGUL SYLLABLE HIT +D7A2;D7A2;1112 1175 11C1;D7A2;1112 1175 11C1; # (힢; 힢; 힢; 힢; 힢; ) HANGUL SYLLABLE HIP +D7A3;D7A3;1112 1175 11C2;D7A3;1112 1175 11C2; # (힣; 힣; 힣; 힣; 힣; ) HANGUL SYLLABLE HIH +F900;8C48;8C48;8C48;8C48; # (豈; 豈; 豈; 豈; 豈; ) CJK COMPATIBILITY IDEOGRAPH-F900 +F901;66F4;66F4;66F4;66F4; # (更; 更; 更; 更; 更; ) CJK COMPATIBILITY IDEOGRAPH-F901 +F902;8ECA;8ECA;8ECA;8ECA; # (車; 車; 車; 車; 車; ) CJK COMPATIBILITY IDEOGRAPH-F902 +F903;8CC8;8CC8;8CC8;8CC8; # (賈; 賈; 賈; 賈; 賈; ) CJK COMPATIBILITY IDEOGRAPH-F903 +F904;6ED1;6ED1;6ED1;6ED1; # (滑; 滑; 滑; 滑; 滑; ) CJK COMPATIBILITY IDEOGRAPH-F904 +F905;4E32;4E32;4E32;4E32; # (串; 串; 串; 串; 串; ) CJK COMPATIBILITY IDEOGRAPH-F905 +F906;53E5;53E5;53E5;53E5; # (句; 句; 句; 句; 句; ) CJK COMPATIBILITY IDEOGRAPH-F906 +F907;9F9C;9F9C;9F9C;9F9C; # (龜; 龜; 龜; 龜; 龜; ) CJK COMPATIBILITY IDEOGRAPH-F907 +F908;9F9C;9F9C;9F9C;9F9C; # (龜; 龜; 龜; 龜; 龜; ) CJK COMPATIBILITY IDEOGRAPH-F908 +F909;5951;5951;5951;5951; # (契; 契; 契; 契; 契; ) CJK COMPATIBILITY IDEOGRAPH-F909 +F90A;91D1;91D1;91D1;91D1; # (金; 金; 金; 金; 金; ) CJK COMPATIBILITY IDEOGRAPH-F90A +F90B;5587;5587;5587;5587; # (喇; 喇; 喇; 喇; 喇; ) CJK COMPATIBILITY IDEOGRAPH-F90B +F90C;5948;5948;5948;5948; # (奈; 奈; 奈; 奈; 奈; ) CJK COMPATIBILITY IDEOGRAPH-F90C +F90D;61F6;61F6;61F6;61F6; # (懶; 懶; 懶; 懶; 懶; ) CJK COMPATIBILITY IDEOGRAPH-F90D +F90E;7669;7669;7669;7669; # (癩; 癩; 癩; 癩; 癩; ) CJK COMPATIBILITY IDEOGRAPH-F90E +F90F;7F85;7F85;7F85;7F85; # (羅; 羅; 羅; 羅; 羅; ) CJK COMPATIBILITY IDEOGRAPH-F90F +F910;863F;863F;863F;863F; # (蘿; 蘿; 蘿; 蘿; 蘿; ) CJK COMPATIBILITY IDEOGRAPH-F910 +F911;87BA;87BA;87BA;87BA; # (螺; 螺; 螺; 螺; 螺; ) CJK COMPATIBILITY IDEOGRAPH-F911 +F912;88F8;88F8;88F8;88F8; # (裸; 裸; 裸; 裸; 裸; ) CJK COMPATIBILITY IDEOGRAPH-F912 +F913;908F;908F;908F;908F; # (邏; 邏; 邏; 邏; 邏; ) CJK COMPATIBILITY IDEOGRAPH-F913 +F914;6A02;6A02;6A02;6A02; # (樂; 樂; 樂; 樂; 樂; ) CJK COMPATIBILITY IDEOGRAPH-F914 +F915;6D1B;6D1B;6D1B;6D1B; # (洛; 洛; 洛; 洛; 洛; ) CJK COMPATIBILITY IDEOGRAPH-F915 +F916;70D9;70D9;70D9;70D9; # (烙; 烙; 烙; 烙; 烙; ) CJK COMPATIBILITY IDEOGRAPH-F916 +F917;73DE;73DE;73DE;73DE; # (珞; 珞; 珞; 珞; 珞; ) CJK COMPATIBILITY IDEOGRAPH-F917 +F918;843D;843D;843D;843D; # (落; 落; 落; 落; 落; ) CJK COMPATIBILITY IDEOGRAPH-F918 +F919;916A;916A;916A;916A; # (酪; 酪; 酪; 酪; 酪; ) CJK COMPATIBILITY IDEOGRAPH-F919 +F91A;99F1;99F1;99F1;99F1; # (駱; 駱; 駱; 駱; 駱; ) CJK COMPATIBILITY IDEOGRAPH-F91A +F91B;4E82;4E82;4E82;4E82; # (亂; 亂; 亂; 亂; 亂; ) CJK COMPATIBILITY IDEOGRAPH-F91B +F91C;5375;5375;5375;5375; # (卵; 卵; 卵; 卵; 卵; ) CJK COMPATIBILITY IDEOGRAPH-F91C +F91D;6B04;6B04;6B04;6B04; # (欄; 欄; 欄; 欄; 欄; ) CJK COMPATIBILITY IDEOGRAPH-F91D +F91E;721B;721B;721B;721B; # (爛; 爛; 爛; 爛; 爛; ) CJK COMPATIBILITY IDEOGRAPH-F91E +F91F;862D;862D;862D;862D; # (蘭; 蘭; 蘭; 蘭; 蘭; ) CJK COMPATIBILITY IDEOGRAPH-F91F +F920;9E1E;9E1E;9E1E;9E1E; # (鸞; 鸞; 鸞; 鸞; 鸞; ) CJK COMPATIBILITY IDEOGRAPH-F920 +F921;5D50;5D50;5D50;5D50; # (嵐; 嵐; 嵐; 嵐; 嵐; ) CJK COMPATIBILITY IDEOGRAPH-F921 +F922;6FEB;6FEB;6FEB;6FEB; # (濫; 濫; 濫; 濫; 濫; ) CJK COMPATIBILITY IDEOGRAPH-F922 +F923;85CD;85CD;85CD;85CD; # (藍; 藍; 藍; 藍; 藍; ) CJK COMPATIBILITY IDEOGRAPH-F923 +F924;8964;8964;8964;8964; # (襤; 襤; 襤; 襤; 襤; ) CJK COMPATIBILITY IDEOGRAPH-F924 +F925;62C9;62C9;62C9;62C9; # (拉; 拉; 拉; 拉; 拉; ) CJK COMPATIBILITY IDEOGRAPH-F925 +F926;81D8;81D8;81D8;81D8; # (臘; 臘; 臘; 臘; 臘; ) CJK COMPATIBILITY IDEOGRAPH-F926 +F927;881F;881F;881F;881F; # (蠟; 蠟; 蠟; 蠟; 蠟; ) CJK COMPATIBILITY IDEOGRAPH-F927 +F928;5ECA;5ECA;5ECA;5ECA; # (廊; 廊; 廊; 廊; 廊; ) CJK COMPATIBILITY IDEOGRAPH-F928 +F929;6717;6717;6717;6717; # (朗; 朗; 朗; 朗; 朗; ) CJK COMPATIBILITY IDEOGRAPH-F929 +F92A;6D6A;6D6A;6D6A;6D6A; # (浪; 浪; 浪; 浪; 浪; ) CJK COMPATIBILITY IDEOGRAPH-F92A +F92B;72FC;72FC;72FC;72FC; # (狼; 狼; 狼; 狼; 狼; ) CJK COMPATIBILITY IDEOGRAPH-F92B +F92C;90CE;90CE;90CE;90CE; # (郎; 郎; 郎; 郎; 郎; ) CJK COMPATIBILITY IDEOGRAPH-F92C +F92D;4F86;4F86;4F86;4F86; # (來; 來; 來; 來; 來; ) CJK COMPATIBILITY IDEOGRAPH-F92D +F92E;51B7;51B7;51B7;51B7; # (冷; 冷; 冷; 冷; 冷; ) CJK COMPATIBILITY IDEOGRAPH-F92E +F92F;52DE;52DE;52DE;52DE; # (勞; 勞; 勞; 勞; 勞; ) CJK COMPATIBILITY IDEOGRAPH-F92F +F930;64C4;64C4;64C4;64C4; # (擄; 擄; 擄; 擄; 擄; ) CJK COMPATIBILITY IDEOGRAPH-F930 +F931;6AD3;6AD3;6AD3;6AD3; # (櫓; 櫓; 櫓; 櫓; 櫓; ) CJK COMPATIBILITY IDEOGRAPH-F931 +F932;7210;7210;7210;7210; # (爐; 爐; 爐; 爐; 爐; ) CJK COMPATIBILITY IDEOGRAPH-F932 +F933;76E7;76E7;76E7;76E7; # (盧; 盧; 盧; 盧; 盧; ) CJK COMPATIBILITY IDEOGRAPH-F933 +F934;8001;8001;8001;8001; # (老; 老; 老; 老; 老; ) CJK COMPATIBILITY IDEOGRAPH-F934 +F935;8606;8606;8606;8606; # (蘆; 蘆; 蘆; 蘆; 蘆; ) CJK COMPATIBILITY IDEOGRAPH-F935 +F936;865C;865C;865C;865C; # (虜; 虜; 虜; 虜; 虜; ) CJK COMPATIBILITY IDEOGRAPH-F936 +F937;8DEF;8DEF;8DEF;8DEF; # (路; 路; 路; 路; 路; ) CJK COMPATIBILITY IDEOGRAPH-F937 +F938;9732;9732;9732;9732; # (露; 露; 露; 露; 露; ) CJK COMPATIBILITY IDEOGRAPH-F938 +F939;9B6F;9B6F;9B6F;9B6F; # (魯; 魯; 魯; 魯; 魯; ) CJK COMPATIBILITY IDEOGRAPH-F939 +F93A;9DFA;9DFA;9DFA;9DFA; # (鷺; 鷺; 鷺; 鷺; 鷺; ) CJK COMPATIBILITY IDEOGRAPH-F93A +F93B;788C;788C;788C;788C; # (碌; 碌; 碌; 碌; 碌; ) CJK COMPATIBILITY IDEOGRAPH-F93B +F93C;797F;797F;797F;797F; # (祿; 祿; 祿; 祿; 祿; ) CJK COMPATIBILITY IDEOGRAPH-F93C +F93D;7DA0;7DA0;7DA0;7DA0; # (綠; 綠; 綠; 綠; 綠; ) CJK COMPATIBILITY IDEOGRAPH-F93D +F93E;83C9;83C9;83C9;83C9; # (菉; 菉; 菉; 菉; 菉; ) CJK COMPATIBILITY IDEOGRAPH-F93E +F93F;9304;9304;9304;9304; # (錄; 錄; 錄; 錄; 錄; ) CJK COMPATIBILITY IDEOGRAPH-F93F +F940;9E7F;9E7F;9E7F;9E7F; # (鹿; 鹿; 鹿; 鹿; 鹿; ) CJK COMPATIBILITY IDEOGRAPH-F940 +F941;8AD6;8AD6;8AD6;8AD6; # (論; 論; 論; 論; 論; ) CJK COMPATIBILITY IDEOGRAPH-F941 +F942;58DF;58DF;58DF;58DF; # (壟; 壟; 壟; 壟; 壟; ) CJK COMPATIBILITY IDEOGRAPH-F942 +F943;5F04;5F04;5F04;5F04; # (弄; 弄; 弄; 弄; 弄; ) CJK COMPATIBILITY IDEOGRAPH-F943 +F944;7C60;7C60;7C60;7C60; # (籠; 籠; 籠; 籠; 籠; ) CJK COMPATIBILITY IDEOGRAPH-F944 +F945;807E;807E;807E;807E; # (聾; 聾; 聾; 聾; 聾; ) CJK COMPATIBILITY IDEOGRAPH-F945 +F946;7262;7262;7262;7262; # (牢; 牢; 牢; 牢; 牢; ) CJK COMPATIBILITY IDEOGRAPH-F946 +F947;78CA;78CA;78CA;78CA; # (磊; 磊; 磊; 磊; 磊; ) CJK COMPATIBILITY IDEOGRAPH-F947 +F948;8CC2;8CC2;8CC2;8CC2; # (賂; 賂; 賂; 賂; 賂; ) CJK COMPATIBILITY IDEOGRAPH-F948 +F949;96F7;96F7;96F7;96F7; # (雷; 雷; 雷; 雷; 雷; ) CJK COMPATIBILITY IDEOGRAPH-F949 +F94A;58D8;58D8;58D8;58D8; # (壘; 壘; 壘; 壘; 壘; ) CJK COMPATIBILITY IDEOGRAPH-F94A +F94B;5C62;5C62;5C62;5C62; # (屢; 屢; 屢; 屢; 屢; ) CJK COMPATIBILITY IDEOGRAPH-F94B +F94C;6A13;6A13;6A13;6A13; # (樓; 樓; 樓; 樓; 樓; ) CJK COMPATIBILITY IDEOGRAPH-F94C +F94D;6DDA;6DDA;6DDA;6DDA; # (淚; 淚; 淚; 淚; 淚; ) CJK COMPATIBILITY IDEOGRAPH-F94D +F94E;6F0F;6F0F;6F0F;6F0F; # (漏; 漏; 漏; 漏; 漏; ) CJK COMPATIBILITY IDEOGRAPH-F94E +F94F;7D2F;7D2F;7D2F;7D2F; # (累; 累; 累; 累; 累; ) CJK COMPATIBILITY IDEOGRAPH-F94F +F950;7E37;7E37;7E37;7E37; # (縷; 縷; 縷; 縷; 縷; ) CJK COMPATIBILITY IDEOGRAPH-F950 +F951;964B;964B;964B;964B; # (陋; 陋; 陋; 陋; 陋; ) CJK COMPATIBILITY IDEOGRAPH-F951 +F952;52D2;52D2;52D2;52D2; # (勒; 勒; 勒; 勒; 勒; ) CJK COMPATIBILITY IDEOGRAPH-F952 +F953;808B;808B;808B;808B; # (肋; 肋; 肋; 肋; 肋; ) CJK COMPATIBILITY IDEOGRAPH-F953 +F954;51DC;51DC;51DC;51DC; # (凜; 凜; 凜; 凜; 凜; ) CJK COMPATIBILITY IDEOGRAPH-F954 +F955;51CC;51CC;51CC;51CC; # (凌; 凌; 凌; 凌; 凌; ) CJK COMPATIBILITY IDEOGRAPH-F955 +F956;7A1C;7A1C;7A1C;7A1C; # (稜; 稜; 稜; 稜; 稜; ) CJK COMPATIBILITY IDEOGRAPH-F956 +F957;7DBE;7DBE;7DBE;7DBE; # (綾; 綾; 綾; 綾; 綾; ) CJK COMPATIBILITY IDEOGRAPH-F957 +F958;83F1;83F1;83F1;83F1; # (菱; 菱; 菱; 菱; 菱; ) CJK COMPATIBILITY IDEOGRAPH-F958 +F959;9675;9675;9675;9675; # (陵; 陵; 陵; 陵; 陵; ) CJK COMPATIBILITY IDEOGRAPH-F959 +F95A;8B80;8B80;8B80;8B80; # (讀; 讀; 讀; 讀; 讀; ) CJK COMPATIBILITY IDEOGRAPH-F95A +F95B;62CF;62CF;62CF;62CF; # (拏; 拏; 拏; 拏; 拏; ) CJK COMPATIBILITY IDEOGRAPH-F95B +F95C;6A02;6A02;6A02;6A02; # (樂; 樂; 樂; 樂; 樂; ) CJK COMPATIBILITY IDEOGRAPH-F95C +F95D;8AFE;8AFE;8AFE;8AFE; # (諾; 諾; 諾; 諾; 諾; ) CJK COMPATIBILITY IDEOGRAPH-F95D +F95E;4E39;4E39;4E39;4E39; # (丹; 丹; 丹; 丹; 丹; ) CJK COMPATIBILITY IDEOGRAPH-F95E +F95F;5BE7;5BE7;5BE7;5BE7; # (寧; 寧; 寧; 寧; 寧; ) CJK COMPATIBILITY IDEOGRAPH-F95F +F960;6012;6012;6012;6012; # (怒; 怒; 怒; 怒; 怒; ) CJK COMPATIBILITY IDEOGRAPH-F960 +F961;7387;7387;7387;7387; # (率; 率; 率; 率; 率; ) CJK COMPATIBILITY IDEOGRAPH-F961 +F962;7570;7570;7570;7570; # (異; 異; 異; 異; 異; ) CJK COMPATIBILITY IDEOGRAPH-F962 +F963;5317;5317;5317;5317; # (北; 北; 北; 北; 北; ) CJK COMPATIBILITY IDEOGRAPH-F963 +F964;78FB;78FB;78FB;78FB; # (磻; 磻; 磻; 磻; 磻; ) CJK COMPATIBILITY IDEOGRAPH-F964 +F965;4FBF;4FBF;4FBF;4FBF; # (便; 便; 便; 便; 便; ) CJK COMPATIBILITY IDEOGRAPH-F965 +F966;5FA9;5FA9;5FA9;5FA9; # (復; 復; 復; 復; 復; ) CJK COMPATIBILITY IDEOGRAPH-F966 +F967;4E0D;4E0D;4E0D;4E0D; # (不; 不; 不; 不; 不; ) CJK COMPATIBILITY IDEOGRAPH-F967 +F968;6CCC;6CCC;6CCC;6CCC; # (泌; 泌; 泌; 泌; 泌; ) CJK COMPATIBILITY IDEOGRAPH-F968 +F969;6578;6578;6578;6578; # (數; 數; 數; 數; 數; ) CJK COMPATIBILITY IDEOGRAPH-F969 +F96A;7D22;7D22;7D22;7D22; # (索; 索; 索; 索; 索; ) CJK COMPATIBILITY IDEOGRAPH-F96A +F96B;53C3;53C3;53C3;53C3; # (參; 參; 參; 參; 參; ) CJK COMPATIBILITY IDEOGRAPH-F96B +F96C;585E;585E;585E;585E; # (塞; 塞; 塞; 塞; 塞; ) CJK COMPATIBILITY IDEOGRAPH-F96C +F96D;7701;7701;7701;7701; # (省; 省; 省; 省; 省; ) CJK COMPATIBILITY IDEOGRAPH-F96D +F96E;8449;8449;8449;8449; # (葉; 葉; 葉; 葉; 葉; ) CJK COMPATIBILITY IDEOGRAPH-F96E +F96F;8AAA;8AAA;8AAA;8AAA; # (說; 說; 說; 說; 說; ) CJK COMPATIBILITY IDEOGRAPH-F96F +F970;6BBA;6BBA;6BBA;6BBA; # (殺; 殺; 殺; 殺; 殺; ) CJK COMPATIBILITY IDEOGRAPH-F970 +F971;8FB0;8FB0;8FB0;8FB0; # (辰; 辰; 辰; 辰; 辰; ) CJK COMPATIBILITY IDEOGRAPH-F971 +F972;6C88;6C88;6C88;6C88; # (沈; 沈; 沈; 沈; 沈; ) CJK COMPATIBILITY IDEOGRAPH-F972 +F973;62FE;62FE;62FE;62FE; # (拾; 拾; 拾; 拾; 拾; ) CJK COMPATIBILITY IDEOGRAPH-F973 +F974;82E5;82E5;82E5;82E5; # (若; 若; 若; 若; 若; ) CJK COMPATIBILITY IDEOGRAPH-F974 +F975;63A0;63A0;63A0;63A0; # (掠; 掠; 掠; 掠; 掠; ) CJK COMPATIBILITY IDEOGRAPH-F975 +F976;7565;7565;7565;7565; # (略; 略; 略; 略; 略; ) CJK COMPATIBILITY IDEOGRAPH-F976 +F977;4EAE;4EAE;4EAE;4EAE; # (亮; 亮; 亮; 亮; 亮; ) CJK COMPATIBILITY IDEOGRAPH-F977 +F978;5169;5169;5169;5169; # (兩; 兩; 兩; 兩; 兩; ) CJK COMPATIBILITY IDEOGRAPH-F978 +F979;51C9;51C9;51C9;51C9; # (凉; 凉; 凉; 凉; 凉; ) CJK COMPATIBILITY IDEOGRAPH-F979 +F97A;6881;6881;6881;6881; # (梁; 梁; 梁; 梁; 梁; ) CJK COMPATIBILITY IDEOGRAPH-F97A +F97B;7CE7;7CE7;7CE7;7CE7; # (糧; 糧; 糧; 糧; 糧; ) CJK COMPATIBILITY IDEOGRAPH-F97B +F97C;826F;826F;826F;826F; # (良; 良; 良; 良; 良; ) CJK COMPATIBILITY IDEOGRAPH-F97C +F97D;8AD2;8AD2;8AD2;8AD2; # (諒; 諒; 諒; 諒; 諒; ) CJK COMPATIBILITY IDEOGRAPH-F97D +F97E;91CF;91CF;91CF;91CF; # (量; 量; 量; 量; 量; ) CJK COMPATIBILITY IDEOGRAPH-F97E +F97F;52F5;52F5;52F5;52F5; # (勵; 勵; 勵; 勵; 勵; ) CJK COMPATIBILITY IDEOGRAPH-F97F +F980;5442;5442;5442;5442; # (呂; 呂; 呂; 呂; 呂; ) CJK COMPATIBILITY IDEOGRAPH-F980 +F981;5973;5973;5973;5973; # (女; 女; 女; 女; 女; ) CJK COMPATIBILITY IDEOGRAPH-F981 +F982;5EEC;5EEC;5EEC;5EEC; # (廬; 廬; 廬; 廬; 廬; ) CJK COMPATIBILITY IDEOGRAPH-F982 +F983;65C5;65C5;65C5;65C5; # (旅; 旅; 旅; 旅; 旅; ) CJK COMPATIBILITY IDEOGRAPH-F983 +F984;6FFE;6FFE;6FFE;6FFE; # (濾; 濾; 濾; 濾; 濾; ) CJK COMPATIBILITY IDEOGRAPH-F984 +F985;792A;792A;792A;792A; # (礪; 礪; 礪; 礪; 礪; ) CJK COMPATIBILITY IDEOGRAPH-F985 +F986;95AD;95AD;95AD;95AD; # (閭; 閭; 閭; 閭; 閭; ) CJK COMPATIBILITY IDEOGRAPH-F986 +F987;9A6A;9A6A;9A6A;9A6A; # (驪; 驪; 驪; 驪; 驪; ) CJK COMPATIBILITY IDEOGRAPH-F987 +F988;9E97;9E97;9E97;9E97; # (麗; 麗; 麗; 麗; 麗; ) CJK COMPATIBILITY IDEOGRAPH-F988 +F989;9ECE;9ECE;9ECE;9ECE; # (黎; 黎; 黎; 黎; 黎; ) CJK COMPATIBILITY IDEOGRAPH-F989 +F98A;529B;529B;529B;529B; # (力; 力; 力; 力; 力; ) CJK COMPATIBILITY IDEOGRAPH-F98A +F98B;66C6;66C6;66C6;66C6; # (曆; 曆; 曆; 曆; 曆; ) CJK COMPATIBILITY IDEOGRAPH-F98B +F98C;6B77;6B77;6B77;6B77; # (歷; 歷; 歷; 歷; 歷; ) CJK COMPATIBILITY IDEOGRAPH-F98C +F98D;8F62;8F62;8F62;8F62; # (轢; 轢; 轢; 轢; 轢; ) CJK COMPATIBILITY IDEOGRAPH-F98D +F98E;5E74;5E74;5E74;5E74; # (年; 年; 年; 年; 年; ) CJK COMPATIBILITY IDEOGRAPH-F98E +F98F;6190;6190;6190;6190; # (憐; 憐; 憐; 憐; 憐; ) CJK COMPATIBILITY IDEOGRAPH-F98F +F990;6200;6200;6200;6200; # (戀; 戀; 戀; 戀; 戀; ) CJK COMPATIBILITY IDEOGRAPH-F990 +F991;649A;649A;649A;649A; # (撚; 撚; 撚; 撚; 撚; ) CJK COMPATIBILITY IDEOGRAPH-F991 +F992;6F23;6F23;6F23;6F23; # (漣; 漣; 漣; 漣; 漣; ) CJK COMPATIBILITY IDEOGRAPH-F992 +F993;7149;7149;7149;7149; # (煉; 煉; 煉; 煉; 煉; ) CJK COMPATIBILITY IDEOGRAPH-F993 +F994;7489;7489;7489;7489; # (璉; 璉; 璉; 璉; 璉; ) CJK COMPATIBILITY IDEOGRAPH-F994 +F995;79CA;79CA;79CA;79CA; # (秊; 秊; 秊; 秊; 秊; ) CJK COMPATIBILITY IDEOGRAPH-F995 +F996;7DF4;7DF4;7DF4;7DF4; # (練; 練; 練; 練; 練; ) CJK COMPATIBILITY IDEOGRAPH-F996 +F997;806F;806F;806F;806F; # (聯; 聯; 聯; 聯; 聯; ) CJK COMPATIBILITY IDEOGRAPH-F997 +F998;8F26;8F26;8F26;8F26; # (輦; 輦; 輦; 輦; 輦; ) CJK COMPATIBILITY IDEOGRAPH-F998 +F999;84EE;84EE;84EE;84EE; # (蓮; 蓮; 蓮; 蓮; 蓮; ) CJK COMPATIBILITY IDEOGRAPH-F999 +F99A;9023;9023;9023;9023; # (連; 連; 連; 連; 連; ) CJK COMPATIBILITY IDEOGRAPH-F99A +F99B;934A;934A;934A;934A; # (鍊; 鍊; 鍊; 鍊; 鍊; ) CJK COMPATIBILITY IDEOGRAPH-F99B +F99C;5217;5217;5217;5217; # (列; 列; 列; 列; 列; ) CJK COMPATIBILITY IDEOGRAPH-F99C +F99D;52A3;52A3;52A3;52A3; # (劣; 劣; 劣; 劣; 劣; ) CJK COMPATIBILITY IDEOGRAPH-F99D +F99E;54BD;54BD;54BD;54BD; # (咽; 咽; 咽; 咽; 咽; ) CJK COMPATIBILITY IDEOGRAPH-F99E +F99F;70C8;70C8;70C8;70C8; # (烈; 烈; 烈; 烈; 烈; ) CJK COMPATIBILITY IDEOGRAPH-F99F +F9A0;88C2;88C2;88C2;88C2; # (裂; 裂; 裂; 裂; 裂; ) CJK COMPATIBILITY IDEOGRAPH-F9A0 +F9A1;8AAA;8AAA;8AAA;8AAA; # (說; 說; 說; 說; 說; ) CJK COMPATIBILITY IDEOGRAPH-F9A1 +F9A2;5EC9;5EC9;5EC9;5EC9; # (廉; 廉; 廉; 廉; 廉; ) CJK COMPATIBILITY IDEOGRAPH-F9A2 +F9A3;5FF5;5FF5;5FF5;5FF5; # (念; 念; 念; 念; 念; ) CJK COMPATIBILITY IDEOGRAPH-F9A3 +F9A4;637B;637B;637B;637B; # (捻; 捻; 捻; 捻; 捻; ) CJK COMPATIBILITY IDEOGRAPH-F9A4 +F9A5;6BAE;6BAE;6BAE;6BAE; # (殮; 殮; 殮; 殮; 殮; ) CJK COMPATIBILITY IDEOGRAPH-F9A5 +F9A6;7C3E;7C3E;7C3E;7C3E; # (簾; 簾; 簾; 簾; 簾; ) CJK COMPATIBILITY IDEOGRAPH-F9A6 +F9A7;7375;7375;7375;7375; # (獵; 獵; 獵; 獵; 獵; ) CJK COMPATIBILITY IDEOGRAPH-F9A7 +F9A8;4EE4;4EE4;4EE4;4EE4; # (令; 令; 令; 令; 令; ) CJK COMPATIBILITY IDEOGRAPH-F9A8 +F9A9;56F9;56F9;56F9;56F9; # (囹; 囹; 囹; 囹; 囹; ) CJK COMPATIBILITY IDEOGRAPH-F9A9 +F9AA;5BE7;5BE7;5BE7;5BE7; # (寧; 寧; 寧; 寧; 寧; ) CJK COMPATIBILITY IDEOGRAPH-F9AA +F9AB;5DBA;5DBA;5DBA;5DBA; # (嶺; 嶺; 嶺; 嶺; 嶺; ) CJK COMPATIBILITY IDEOGRAPH-F9AB +F9AC;601C;601C;601C;601C; # (怜; 怜; 怜; 怜; 怜; ) CJK COMPATIBILITY IDEOGRAPH-F9AC +F9AD;73B2;73B2;73B2;73B2; # (玲; 玲; 玲; 玲; 玲; ) CJK COMPATIBILITY IDEOGRAPH-F9AD +F9AE;7469;7469;7469;7469; # (瑩; 瑩; 瑩; 瑩; 瑩; ) CJK COMPATIBILITY IDEOGRAPH-F9AE +F9AF;7F9A;7F9A;7F9A;7F9A; # (羚; 羚; 羚; 羚; 羚; ) CJK COMPATIBILITY IDEOGRAPH-F9AF +F9B0;8046;8046;8046;8046; # (聆; 聆; 聆; 聆; 聆; ) CJK COMPATIBILITY IDEOGRAPH-F9B0 +F9B1;9234;9234;9234;9234; # (鈴; 鈴; 鈴; 鈴; 鈴; ) CJK COMPATIBILITY IDEOGRAPH-F9B1 +F9B2;96F6;96F6;96F6;96F6; # (零; 零; 零; 零; 零; ) CJK COMPATIBILITY IDEOGRAPH-F9B2 +F9B3;9748;9748;9748;9748; # (靈; 靈; 靈; 靈; 靈; ) CJK COMPATIBILITY IDEOGRAPH-F9B3 +F9B4;9818;9818;9818;9818; # (領; 領; 領; 領; 領; ) CJK COMPATIBILITY IDEOGRAPH-F9B4 +F9B5;4F8B;4F8B;4F8B;4F8B; # (例; 例; 例; 例; 例; ) CJK COMPATIBILITY IDEOGRAPH-F9B5 +F9B6;79AE;79AE;79AE;79AE; # (禮; 禮; 禮; 禮; 禮; ) CJK COMPATIBILITY IDEOGRAPH-F9B6 +F9B7;91B4;91B4;91B4;91B4; # (醴; 醴; 醴; 醴; 醴; ) CJK COMPATIBILITY IDEOGRAPH-F9B7 +F9B8;96B8;96B8;96B8;96B8; # (隸; 隸; 隸; 隸; 隸; ) CJK COMPATIBILITY IDEOGRAPH-F9B8 +F9B9;60E1;60E1;60E1;60E1; # (惡; 惡; 惡; 惡; 惡; ) CJK COMPATIBILITY IDEOGRAPH-F9B9 +F9BA;4E86;4E86;4E86;4E86; # (了; 了; 了; 了; 了; ) CJK COMPATIBILITY IDEOGRAPH-F9BA +F9BB;50DA;50DA;50DA;50DA; # (僚; 僚; 僚; 僚; 僚; ) CJK COMPATIBILITY IDEOGRAPH-F9BB +F9BC;5BEE;5BEE;5BEE;5BEE; # (寮; 寮; 寮; 寮; 寮; ) CJK COMPATIBILITY IDEOGRAPH-F9BC +F9BD;5C3F;5C3F;5C3F;5C3F; # (尿; 尿; 尿; 尿; 尿; ) CJK COMPATIBILITY IDEOGRAPH-F9BD +F9BE;6599;6599;6599;6599; # (料; 料; 料; 料; 料; ) CJK COMPATIBILITY IDEOGRAPH-F9BE +F9BF;6A02;6A02;6A02;6A02; # (樂; 樂; 樂; 樂; 樂; ) CJK COMPATIBILITY IDEOGRAPH-F9BF +F9C0;71CE;71CE;71CE;71CE; # (燎; 燎; 燎; 燎; 燎; ) CJK COMPATIBILITY IDEOGRAPH-F9C0 +F9C1;7642;7642;7642;7642; # (療; 療; 療; 療; 療; ) CJK COMPATIBILITY IDEOGRAPH-F9C1 +F9C2;84FC;84FC;84FC;84FC; # (蓼; 蓼; 蓼; 蓼; 蓼; ) CJK COMPATIBILITY IDEOGRAPH-F9C2 +F9C3;907C;907C;907C;907C; # (遼; 遼; 遼; 遼; 遼; ) CJK COMPATIBILITY IDEOGRAPH-F9C3 +F9C4;9F8D;9F8D;9F8D;9F8D; # (龍; 龍; 龍; 龍; 龍; ) CJK COMPATIBILITY IDEOGRAPH-F9C4 +F9C5;6688;6688;6688;6688; # (暈; 暈; 暈; 暈; 暈; ) CJK COMPATIBILITY IDEOGRAPH-F9C5 +F9C6;962E;962E;962E;962E; # (阮; 阮; 阮; 阮; 阮; ) CJK COMPATIBILITY IDEOGRAPH-F9C6 +F9C7;5289;5289;5289;5289; # (劉; 劉; 劉; 劉; 劉; ) CJK COMPATIBILITY IDEOGRAPH-F9C7 +F9C8;677B;677B;677B;677B; # (杻; 杻; 杻; 杻; 杻; ) CJK COMPATIBILITY IDEOGRAPH-F9C8 +F9C9;67F3;67F3;67F3;67F3; # (柳; 柳; 柳; 柳; 柳; ) CJK COMPATIBILITY IDEOGRAPH-F9C9 +F9CA;6D41;6D41;6D41;6D41; # (流; 流; 流; 流; 流; ) CJK COMPATIBILITY IDEOGRAPH-F9CA +F9CB;6E9C;6E9C;6E9C;6E9C; # (溜; 溜; 溜; 溜; 溜; ) CJK COMPATIBILITY IDEOGRAPH-F9CB +F9CC;7409;7409;7409;7409; # (琉; 琉; 琉; 琉; 琉; ) CJK COMPATIBILITY IDEOGRAPH-F9CC +F9CD;7559;7559;7559;7559; # (留; 留; 留; 留; 留; ) CJK COMPATIBILITY IDEOGRAPH-F9CD +F9CE;786B;786B;786B;786B; # (硫; 硫; 硫; 硫; 硫; ) CJK COMPATIBILITY IDEOGRAPH-F9CE +F9CF;7D10;7D10;7D10;7D10; # (紐; 紐; 紐; 紐; 紐; ) CJK COMPATIBILITY IDEOGRAPH-F9CF +F9D0;985E;985E;985E;985E; # (類; 類; 類; 類; 類; ) CJK COMPATIBILITY IDEOGRAPH-F9D0 +F9D1;516D;516D;516D;516D; # (六; 六; 六; 六; 六; ) CJK COMPATIBILITY IDEOGRAPH-F9D1 +F9D2;622E;622E;622E;622E; # (戮; 戮; 戮; 戮; 戮; ) CJK COMPATIBILITY IDEOGRAPH-F9D2 +F9D3;9678;9678;9678;9678; # (陸; 陸; 陸; 陸; 陸; ) CJK COMPATIBILITY IDEOGRAPH-F9D3 +F9D4;502B;502B;502B;502B; # (倫; 倫; 倫; 倫; 倫; ) CJK COMPATIBILITY IDEOGRAPH-F9D4 +F9D5;5D19;5D19;5D19;5D19; # (崙; 崙; 崙; 崙; 崙; ) CJK COMPATIBILITY IDEOGRAPH-F9D5 +F9D6;6DEA;6DEA;6DEA;6DEA; # (淪; 淪; 淪; 淪; 淪; ) CJK COMPATIBILITY IDEOGRAPH-F9D6 +F9D7;8F2A;8F2A;8F2A;8F2A; # (輪; 輪; 輪; 輪; 輪; ) CJK COMPATIBILITY IDEOGRAPH-F9D7 +F9D8;5F8B;5F8B;5F8B;5F8B; # (律; 律; 律; 律; 律; ) CJK COMPATIBILITY IDEOGRAPH-F9D8 +F9D9;6144;6144;6144;6144; # (慄; 慄; 慄; 慄; 慄; ) CJK COMPATIBILITY IDEOGRAPH-F9D9 +F9DA;6817;6817;6817;6817; # (栗; 栗; 栗; 栗; 栗; ) CJK COMPATIBILITY IDEOGRAPH-F9DA +F9DB;7387;7387;7387;7387; # (率; 率; 率; 率; 率; ) CJK COMPATIBILITY IDEOGRAPH-F9DB +F9DC;9686;9686;9686;9686; # (隆; 隆; 隆; 隆; 隆; ) CJK COMPATIBILITY IDEOGRAPH-F9DC +F9DD;5229;5229;5229;5229; # (利; 利; 利; 利; 利; ) CJK COMPATIBILITY IDEOGRAPH-F9DD +F9DE;540F;540F;540F;540F; # (吏; 吏; 吏; 吏; 吏; ) CJK COMPATIBILITY IDEOGRAPH-F9DE +F9DF;5C65;5C65;5C65;5C65; # (履; 履; 履; 履; 履; ) CJK COMPATIBILITY IDEOGRAPH-F9DF +F9E0;6613;6613;6613;6613; # (易; 易; 易; 易; 易; ) CJK COMPATIBILITY IDEOGRAPH-F9E0 +F9E1;674E;674E;674E;674E; # (李; 李; 李; 李; 李; ) CJK COMPATIBILITY IDEOGRAPH-F9E1 +F9E2;68A8;68A8;68A8;68A8; # (梨; 梨; 梨; 梨; 梨; ) CJK COMPATIBILITY IDEOGRAPH-F9E2 +F9E3;6CE5;6CE5;6CE5;6CE5; # (泥; 泥; 泥; 泥; 泥; ) CJK COMPATIBILITY IDEOGRAPH-F9E3 +F9E4;7406;7406;7406;7406; # (理; 理; 理; 理; 理; ) CJK COMPATIBILITY IDEOGRAPH-F9E4 +F9E5;75E2;75E2;75E2;75E2; # (痢; 痢; 痢; 痢; 痢; ) CJK COMPATIBILITY IDEOGRAPH-F9E5 +F9E6;7F79;7F79;7F79;7F79; # (罹; 罹; 罹; 罹; 罹; ) CJK COMPATIBILITY IDEOGRAPH-F9E6 +F9E7;88CF;88CF;88CF;88CF; # (裏; 裏; 裏; 裏; 裏; ) CJK COMPATIBILITY IDEOGRAPH-F9E7 +F9E8;88E1;88E1;88E1;88E1; # (裡; 裡; 裡; 裡; 裡; ) CJK COMPATIBILITY IDEOGRAPH-F9E8 +F9E9;91CC;91CC;91CC;91CC; # (里; 里; 里; 里; 里; ) CJK COMPATIBILITY IDEOGRAPH-F9E9 +F9EA;96E2;96E2;96E2;96E2; # (離; 離; 離; 離; 離; ) CJK COMPATIBILITY IDEOGRAPH-F9EA +F9EB;533F;533F;533F;533F; # (匿; 匿; 匿; 匿; 匿; ) CJK COMPATIBILITY IDEOGRAPH-F9EB +F9EC;6EBA;6EBA;6EBA;6EBA; # (溺; 溺; 溺; 溺; 溺; ) CJK COMPATIBILITY IDEOGRAPH-F9EC +F9ED;541D;541D;541D;541D; # (吝; 吝; 吝; 吝; 吝; ) CJK COMPATIBILITY IDEOGRAPH-F9ED +F9EE;71D0;71D0;71D0;71D0; # (燐; 燐; 燐; 燐; 燐; ) CJK COMPATIBILITY IDEOGRAPH-F9EE +F9EF;7498;7498;7498;7498; # (璘; 璘; 璘; 璘; 璘; ) CJK COMPATIBILITY IDEOGRAPH-F9EF +F9F0;85FA;85FA;85FA;85FA; # (藺; 藺; 藺; 藺; 藺; ) CJK COMPATIBILITY IDEOGRAPH-F9F0 +F9F1;96A3;96A3;96A3;96A3; # (隣; 隣; 隣; 隣; 隣; ) CJK COMPATIBILITY IDEOGRAPH-F9F1 +F9F2;9C57;9C57;9C57;9C57; # (鱗; 鱗; 鱗; 鱗; 鱗; ) CJK COMPATIBILITY IDEOGRAPH-F9F2 +F9F3;9E9F;9E9F;9E9F;9E9F; # (麟; 麟; 麟; 麟; 麟; ) CJK COMPATIBILITY IDEOGRAPH-F9F3 +F9F4;6797;6797;6797;6797; # (林; 林; 林; 林; 林; ) CJK COMPATIBILITY IDEOGRAPH-F9F4 +F9F5;6DCB;6DCB;6DCB;6DCB; # (淋; 淋; 淋; 淋; 淋; ) CJK COMPATIBILITY IDEOGRAPH-F9F5 +F9F6;81E8;81E8;81E8;81E8; # (臨; 臨; 臨; 臨; 臨; ) CJK COMPATIBILITY IDEOGRAPH-F9F6 +F9F7;7ACB;7ACB;7ACB;7ACB; # (立; 立; 立; 立; 立; ) CJK COMPATIBILITY IDEOGRAPH-F9F7 +F9F8;7B20;7B20;7B20;7B20; # (笠; 笠; 笠; 笠; 笠; ) CJK COMPATIBILITY IDEOGRAPH-F9F8 +F9F9;7C92;7C92;7C92;7C92; # (粒; 粒; 粒; 粒; 粒; ) CJK COMPATIBILITY IDEOGRAPH-F9F9 +F9FA;72C0;72C0;72C0;72C0; # (狀; 狀; 狀; 狀; 狀; ) CJK COMPATIBILITY IDEOGRAPH-F9FA +F9FB;7099;7099;7099;7099; # (炙; 炙; 炙; 炙; 炙; ) CJK COMPATIBILITY IDEOGRAPH-F9FB +F9FC;8B58;8B58;8B58;8B58; # (識; 識; 識; 識; 識; ) CJK COMPATIBILITY IDEOGRAPH-F9FC +F9FD;4EC0;4EC0;4EC0;4EC0; # (什; 什; 什; 什; 什; ) CJK COMPATIBILITY IDEOGRAPH-F9FD +F9FE;8336;8336;8336;8336; # (茶; 茶; 茶; 茶; 茶; ) CJK COMPATIBILITY IDEOGRAPH-F9FE +F9FF;523A;523A;523A;523A; # (刺; 刺; 刺; 刺; 刺; ) CJK COMPATIBILITY IDEOGRAPH-F9FF +FA00;5207;5207;5207;5207; # (切; 切; 切; 切; 切; ) CJK COMPATIBILITY IDEOGRAPH-FA00 +FA01;5EA6;5EA6;5EA6;5EA6; # (度; 度; 度; 度; 度; ) CJK COMPATIBILITY IDEOGRAPH-FA01 +FA02;62D3;62D3;62D3;62D3; # (拓; 拓; 拓; 拓; 拓; ) CJK COMPATIBILITY IDEOGRAPH-FA02 +FA03;7CD6;7CD6;7CD6;7CD6; # (糖; 糖; 糖; 糖; 糖; ) CJK COMPATIBILITY IDEOGRAPH-FA03 +FA04;5B85;5B85;5B85;5B85; # (宅; 宅; 宅; 宅; 宅; ) CJK COMPATIBILITY IDEOGRAPH-FA04 +FA05;6D1E;6D1E;6D1E;6D1E; # (洞; 洞; 洞; 洞; 洞; ) CJK COMPATIBILITY IDEOGRAPH-FA05 +FA06;66B4;66B4;66B4;66B4; # (暴; 暴; 暴; 暴; 暴; ) CJK COMPATIBILITY IDEOGRAPH-FA06 +FA07;8F3B;8F3B;8F3B;8F3B; # (輻; 輻; 輻; 輻; 輻; ) CJK COMPATIBILITY IDEOGRAPH-FA07 +FA08;884C;884C;884C;884C; # (行; 行; 行; 行; 行; ) CJK COMPATIBILITY IDEOGRAPH-FA08 +FA09;964D;964D;964D;964D; # (降; 降; 降; 降; 降; ) CJK COMPATIBILITY IDEOGRAPH-FA09 +FA0A;898B;898B;898B;898B; # (見; 見; 見; 見; 見; ) CJK COMPATIBILITY IDEOGRAPH-FA0A +FA0B;5ED3;5ED3;5ED3;5ED3; # (廓; 廓; 廓; 廓; 廓; ) CJK COMPATIBILITY IDEOGRAPH-FA0B +FA0C;5140;5140;5140;5140; # (兀; 兀; 兀; 兀; 兀; ) CJK COMPATIBILITY IDEOGRAPH-FA0C +FA0D;55C0;55C0;55C0;55C0; # (嗀; 嗀; 嗀; 嗀; 嗀; ) CJK COMPATIBILITY IDEOGRAPH-FA0D +FA10;585A;585A;585A;585A; # (塚; 塚; 塚; 塚; 塚; ) CJK COMPATIBILITY IDEOGRAPH-FA10 +FA12;6674;6674;6674;6674; # (晴; 晴; 晴; 晴; 晴; ) CJK COMPATIBILITY IDEOGRAPH-FA12 +FA15;51DE;51DE;51DE;51DE; # (凞; 凞; 凞; 凞; 凞; ) CJK COMPATIBILITY IDEOGRAPH-FA15 +FA16;732A;732A;732A;732A; # (猪; 猪; 猪; 猪; 猪; ) CJK COMPATIBILITY IDEOGRAPH-FA16 +FA17;76CA;76CA;76CA;76CA; # (益; 益; 益; 益; 益; ) CJK COMPATIBILITY IDEOGRAPH-FA17 +FA18;793C;793C;793C;793C; # (礼; 礼; 礼; 礼; 礼; ) CJK COMPATIBILITY IDEOGRAPH-FA18 +FA19;795E;795E;795E;795E; # (神; 神; 神; 神; 神; ) CJK COMPATIBILITY IDEOGRAPH-FA19 +FA1A;7965;7965;7965;7965; # (祥; 祥; 祥; 祥; 祥; ) CJK COMPATIBILITY IDEOGRAPH-FA1A +FA1B;798F;798F;798F;798F; # (福; 福; 福; 福; 福; ) CJK COMPATIBILITY IDEOGRAPH-FA1B +FA1C;9756;9756;9756;9756; # (靖; 靖; 靖; 靖; 靖; ) CJK COMPATIBILITY IDEOGRAPH-FA1C +FA1D;7CBE;7CBE;7CBE;7CBE; # (精; 精; 精; 精; 精; ) CJK COMPATIBILITY IDEOGRAPH-FA1D +FA1E;7FBD;7FBD;7FBD;7FBD; # (羽; 羽; 羽; 羽; 羽; ) CJK COMPATIBILITY IDEOGRAPH-FA1E +FA20;8612;8612;8612;8612; # (蘒; 蘒; 蘒; 蘒; 蘒; ) CJK COMPATIBILITY IDEOGRAPH-FA20 +FA22;8AF8;8AF8;8AF8;8AF8; # (諸; 諸; 諸; 諸; 諸; ) CJK COMPATIBILITY IDEOGRAPH-FA22 +FA25;9038;9038;9038;9038; # (逸; 逸; 逸; 逸; 逸; ) CJK COMPATIBILITY IDEOGRAPH-FA25 +FA26;90FD;90FD;90FD;90FD; # (都; 都; 都; 都; 都; ) CJK COMPATIBILITY IDEOGRAPH-FA26 +FA2A;98EF;98EF;98EF;98EF; # (飯; 飯; 飯; 飯; 飯; ) CJK COMPATIBILITY IDEOGRAPH-FA2A +FA2B;98FC;98FC;98FC;98FC; # (飼; 飼; 飼; 飼; 飼; ) CJK COMPATIBILITY IDEOGRAPH-FA2B +FA2C;9928;9928;9928;9928; # (館; 館; 館; 館; 館; ) CJK COMPATIBILITY IDEOGRAPH-FA2C +FA2D;9DB4;9DB4;9DB4;9DB4; # (鶴; 鶴; 鶴; 鶴; 鶴; ) CJK COMPATIBILITY IDEOGRAPH-FA2D +FA30;4FAE;4FAE;4FAE;4FAE; # (侮; 侮; 侮; 侮; 侮; ) CJK COMPATIBILITY IDEOGRAPH-FA30 +FA31;50E7;50E7;50E7;50E7; # (僧; 僧; 僧; 僧; 僧; ) CJK COMPATIBILITY IDEOGRAPH-FA31 +FA32;514D;514D;514D;514D; # (免; 免; 免; 免; 免; ) CJK COMPATIBILITY IDEOGRAPH-FA32 +FA33;52C9;52C9;52C9;52C9; # (勉; 勉; 勉; 勉; 勉; ) CJK COMPATIBILITY IDEOGRAPH-FA33 +FA34;52E4;52E4;52E4;52E4; # (勤; 勤; 勤; 勤; 勤; ) CJK COMPATIBILITY IDEOGRAPH-FA34 +FA35;5351;5351;5351;5351; # (卑; 卑; 卑; 卑; 卑; ) CJK COMPATIBILITY IDEOGRAPH-FA35 +FA36;559D;559D;559D;559D; # (喝; 喝; 喝; 喝; 喝; ) CJK COMPATIBILITY IDEOGRAPH-FA36 +FA37;5606;5606;5606;5606; # (嘆; 嘆; 嘆; 嘆; 嘆; ) CJK COMPATIBILITY IDEOGRAPH-FA37 +FA38;5668;5668;5668;5668; # (器; 器; 器; 器; 器; ) CJK COMPATIBILITY IDEOGRAPH-FA38 +FA39;5840;5840;5840;5840; # (塀; 塀; 塀; 塀; 塀; ) CJK COMPATIBILITY IDEOGRAPH-FA39 +FA3A;58A8;58A8;58A8;58A8; # (墨; 墨; 墨; 墨; 墨; ) CJK COMPATIBILITY IDEOGRAPH-FA3A +FA3B;5C64;5C64;5C64;5C64; # (層; 層; 層; 層; 層; ) CJK COMPATIBILITY IDEOGRAPH-FA3B +FA3C;5C6E;5C6E;5C6E;5C6E; # (屮; 屮; 屮; 屮; 屮; ) CJK COMPATIBILITY IDEOGRAPH-FA3C +FA3D;6094;6094;6094;6094; # (悔; 悔; 悔; 悔; 悔; ) CJK COMPATIBILITY IDEOGRAPH-FA3D +FA3E;6168;6168;6168;6168; # (慨; 慨; 慨; 慨; 慨; ) CJK COMPATIBILITY IDEOGRAPH-FA3E +FA3F;618E;618E;618E;618E; # (憎; 憎; 憎; 憎; 憎; ) CJK COMPATIBILITY IDEOGRAPH-FA3F +FA40;61F2;61F2;61F2;61F2; # (懲; 懲; 懲; 懲; 懲; ) CJK COMPATIBILITY IDEOGRAPH-FA40 +FA41;654F;654F;654F;654F; # (敏; 敏; 敏; 敏; 敏; ) CJK COMPATIBILITY IDEOGRAPH-FA41 +FA42;65E2;65E2;65E2;65E2; # (既; 既; 既; 既; 既; ) CJK COMPATIBILITY IDEOGRAPH-FA42 +FA43;6691;6691;6691;6691; # (暑; 暑; 暑; 暑; 暑; ) CJK COMPATIBILITY IDEOGRAPH-FA43 +FA44;6885;6885;6885;6885; # (梅; 梅; 梅; 梅; 梅; ) CJK COMPATIBILITY IDEOGRAPH-FA44 +FA45;6D77;6D77;6D77;6D77; # (海; 海; 海; 海; 海; ) CJK COMPATIBILITY IDEOGRAPH-FA45 +FA46;6E1A;6E1A;6E1A;6E1A; # (渚; 渚; 渚; 渚; 渚; ) CJK COMPATIBILITY IDEOGRAPH-FA46 +FA47;6F22;6F22;6F22;6F22; # (漢; 漢; 漢; 漢; 漢; ) CJK COMPATIBILITY IDEOGRAPH-FA47 +FA48;716E;716E;716E;716E; # (煮; 煮; 煮; 煮; 煮; ) CJK COMPATIBILITY IDEOGRAPH-FA48 +FA49;722B;722B;722B;722B; # (爫; 爫; 爫; 爫; 爫; ) CJK COMPATIBILITY IDEOGRAPH-FA49 +FA4A;7422;7422;7422;7422; # (琢; 琢; 琢; 琢; 琢; ) CJK COMPATIBILITY IDEOGRAPH-FA4A +FA4B;7891;7891;7891;7891; # (碑; 碑; 碑; 碑; 碑; ) CJK COMPATIBILITY IDEOGRAPH-FA4B +FA4C;793E;793E;793E;793E; # (社; 社; 社; 社; 社; ) CJK COMPATIBILITY IDEOGRAPH-FA4C +FA4D;7949;7949;7949;7949; # (祉; 祉; 祉; 祉; 祉; ) CJK COMPATIBILITY IDEOGRAPH-FA4D +FA4E;7948;7948;7948;7948; # (祈; 祈; 祈; 祈; 祈; ) CJK COMPATIBILITY IDEOGRAPH-FA4E +FA4F;7950;7950;7950;7950; # (祐; 祐; 祐; 祐; 祐; ) CJK COMPATIBILITY IDEOGRAPH-FA4F +FA50;7956;7956;7956;7956; # (祖; 祖; 祖; 祖; 祖; ) CJK COMPATIBILITY IDEOGRAPH-FA50 +FA51;795D;795D;795D;795D; # (祝; 祝; 祝; 祝; 祝; ) CJK COMPATIBILITY IDEOGRAPH-FA51 +FA52;798D;798D;798D;798D; # (禍; 禍; 禍; 禍; 禍; ) CJK COMPATIBILITY IDEOGRAPH-FA52 +FA53;798E;798E;798E;798E; # (禎; 禎; 禎; 禎; 禎; ) CJK COMPATIBILITY IDEOGRAPH-FA53 +FA54;7A40;7A40;7A40;7A40; # (穀; 穀; 穀; 穀; 穀; ) CJK COMPATIBILITY IDEOGRAPH-FA54 +FA55;7A81;7A81;7A81;7A81; # (突; 突; 突; 突; 突; ) CJK COMPATIBILITY IDEOGRAPH-FA55 +FA56;7BC0;7BC0;7BC0;7BC0; # (節; 節; 節; 節; 節; ) CJK COMPATIBILITY IDEOGRAPH-FA56 +FA57;7DF4;7DF4;7DF4;7DF4; # (練; 練; 練; 練; 練; ) CJK COMPATIBILITY IDEOGRAPH-FA57 +FA58;7E09;7E09;7E09;7E09; # (縉; 縉; 縉; 縉; 縉; ) CJK COMPATIBILITY IDEOGRAPH-FA58 +FA59;7E41;7E41;7E41;7E41; # (繁; 繁; 繁; 繁; 繁; ) CJK COMPATIBILITY IDEOGRAPH-FA59 +FA5A;7F72;7F72;7F72;7F72; # (署; 署; 署; 署; 署; ) CJK COMPATIBILITY IDEOGRAPH-FA5A +FA5B;8005;8005;8005;8005; # (者; 者; 者; 者; 者; ) CJK COMPATIBILITY IDEOGRAPH-FA5B +FA5C;81ED;81ED;81ED;81ED; # (臭; 臭; 臭; 臭; 臭; ) CJK COMPATIBILITY IDEOGRAPH-FA5C +FA5D;8279;8279;8279;8279; # (艹; 艹; 艹; 艹; 艹; ) CJK COMPATIBILITY IDEOGRAPH-FA5D +FA5E;8279;8279;8279;8279; # (艹; 艹; 艹; 艹; 艹; ) CJK COMPATIBILITY IDEOGRAPH-FA5E +FA5F;8457;8457;8457;8457; # (著; 著; 著; 著; 著; ) CJK COMPATIBILITY IDEOGRAPH-FA5F +FA60;8910;8910;8910;8910; # (褐; 褐; 褐; 褐; 褐; ) CJK COMPATIBILITY IDEOGRAPH-FA60 +FA61;8996;8996;8996;8996; # (視; 視; 視; 視; 視; ) CJK COMPATIBILITY IDEOGRAPH-FA61 +FA62;8B01;8B01;8B01;8B01; # (謁; 謁; 謁; 謁; 謁; ) CJK COMPATIBILITY IDEOGRAPH-FA62 +FA63;8B39;8B39;8B39;8B39; # (謹; 謹; 謹; 謹; 謹; ) CJK COMPATIBILITY IDEOGRAPH-FA63 +FA64;8CD3;8CD3;8CD3;8CD3; # (賓; 賓; 賓; 賓; 賓; ) CJK COMPATIBILITY IDEOGRAPH-FA64 +FA65;8D08;8D08;8D08;8D08; # (贈; 贈; 贈; 贈; 贈; ) CJK COMPATIBILITY IDEOGRAPH-FA65 +FA66;8FB6;8FB6;8FB6;8FB6; # (辶; 辶; 辶; 辶; 辶; ) CJK COMPATIBILITY IDEOGRAPH-FA66 +FA67;9038;9038;9038;9038; # (逸; 逸; 逸; 逸; 逸; ) CJK COMPATIBILITY IDEOGRAPH-FA67 +FA68;96E3;96E3;96E3;96E3; # (難; 難; 難; 難; 難; ) CJK COMPATIBILITY IDEOGRAPH-FA68 +FA69;97FF;97FF;97FF;97FF; # (響; 響; 響; 響; 響; ) CJK COMPATIBILITY IDEOGRAPH-FA69 +FA6A;983B;983B;983B;983B; # (頻; 頻; 頻; 頻; 頻; ) CJK COMPATIBILITY IDEOGRAPH-FA6A +FB00;FB00;FB00;0066 0066;0066 0066; # (ff; ff; ff; ff; ff; ) LATIN SMALL LIGATURE FF +FB01;FB01;FB01;0066 0069;0066 0069; # (fi; fi; fi; fi; fi; ) LATIN SMALL LIGATURE FI +FB02;FB02;FB02;0066 006C;0066 006C; # (fl; fl; fl; fl; fl; ) LATIN SMALL LIGATURE FL +FB03;FB03;FB03;0066 0066 0069;0066 0066 0069; # (ffi; ffi; ffi; ffi; ffi; ) LATIN SMALL LIGATURE FFI +FB04;FB04;FB04;0066 0066 006C;0066 0066 006C; # (ffl; ffl; ffl; ffl; ffl; ) LATIN SMALL LIGATURE FFL +FB05;FB05;FB05;0073 0074;0073 0074; # (ſt; ſt; ſt; st; st; ) LATIN SMALL LIGATURE LONG S T +FB06;FB06;FB06;0073 0074;0073 0074; # (st; st; st; st; st; ) LATIN SMALL LIGATURE ST +FB13;FB13;FB13;0574 0576;0574 0576; # (ﬓ; ﬓ; ﬓ; մն; մն; ) ARMENIAN SMALL LIGATURE MEN NOW +FB14;FB14;FB14;0574 0565;0574 0565; # (ﬔ; ﬔ; ﬔ; մե; մե; ) ARMENIAN SMALL LIGATURE MEN ECH +FB15;FB15;FB15;0574 056B;0574 056B; # (ﬕ; ﬕ; ﬕ; մի; մի; ) ARMENIAN SMALL LIGATURE MEN INI +FB16;FB16;FB16;057E 0576;057E 0576; # (ﬖ; ﬖ; ﬖ; վն; վն; ) ARMENIAN SMALL LIGATURE VEW NOW +FB17;FB17;FB17;0574 056D;0574 056D; # (ﬗ; ﬗ; ﬗ; մխ; մխ; ) ARMENIAN SMALL LIGATURE MEN XEH +FB1D;05D9 05B4;05D9 05B4;05D9 05B4;05D9 05B4; # (יִ; י◌ִ; י◌ִ; י◌ִ; י◌ִ; ) HEBREW LETTER YOD WITH HIRIQ +FB1F;05F2 05B7;05F2 05B7;05F2 05B7;05F2 05B7; # (ײַ; ײ◌ַ; ײ◌ַ; ײ◌ַ; ײ◌ַ; ) HEBREW LIGATURE YIDDISH YOD YOD PATAH +FB20;FB20;FB20;05E2;05E2; # (ﬠ; ﬠ; ﬠ; ע; ע; ) HEBREW LETTER ALTERNATIVE AYIN +FB21;FB21;FB21;05D0;05D0; # (ﬡ; ﬡ; ﬡ; א; א; ) HEBREW LETTER WIDE ALEF +FB22;FB22;FB22;05D3;05D3; # (ﬢ; ﬢ; ﬢ; ד; ד; ) HEBREW LETTER WIDE DALET +FB23;FB23;FB23;05D4;05D4; # (ﬣ; ﬣ; ﬣ; ה; ה; ) HEBREW LETTER WIDE HE +FB24;FB24;FB24;05DB;05DB; # (ﬤ; ﬤ; ﬤ; כ; כ; ) HEBREW LETTER WIDE KAF +FB25;FB25;FB25;05DC;05DC; # (ﬥ; ﬥ; ﬥ; ל; ל; ) HEBREW LETTER WIDE LAMED +FB26;FB26;FB26;05DD;05DD; # (ﬦ; ﬦ; ﬦ; ם; ם; ) HEBREW LETTER WIDE FINAL MEM +FB27;FB27;FB27;05E8;05E8; # (ﬧ; ﬧ; ﬧ; ר; ר; ) HEBREW LETTER WIDE RESH +FB28;FB28;FB28;05EA;05EA; # (ﬨ; ﬨ; ﬨ; ת; ת; ) HEBREW LETTER WIDE TAV +FB29;FB29;FB29;002B;002B; # (﬩; ﬩; ﬩; +; +; ) HEBREW LETTER ALTERNATIVE PLUS SIGN +FB2A;05E9 05C1;05E9 05C1;05E9 05C1;05E9 05C1; # (שׁ; ש◌ׁ; ש◌ׁ; ש◌ׁ; ש◌ׁ; ) HEBREW LETTER SHIN WITH SHIN DOT +FB2B;05E9 05C2;05E9 05C2;05E9 05C2;05E9 05C2; # (שׂ; ש◌ׂ; ש◌ׂ; ש◌ׂ; ש◌ׂ; ) HEBREW LETTER SHIN WITH SIN DOT +FB2C;05E9 05BC 05C1;05E9 05BC 05C1;05E9 05BC 05C1;05E9 05BC 05C1; # (שּׁ; ש◌ּ◌ׁ; ש◌ּ◌ׁ; ש◌ּ◌ׁ; ש◌ּ◌ׁ; ) HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT +FB2D;05E9 05BC 05C2;05E9 05BC 05C2;05E9 05BC 05C2;05E9 05BC 05C2; # (שּׂ; ש◌ּ◌ׂ; ש◌ּ◌ׂ; ש◌ּ◌ׂ; ש◌ּ◌ׂ; ) HEBREW LETTER SHIN WITH DAGESH AND SIN DOT +FB2E;05D0 05B7;05D0 05B7;05D0 05B7;05D0 05B7; # (אַ; א◌ַ; א◌ַ; א◌ַ; א◌ַ; ) HEBREW LETTER ALEF WITH PATAH +FB2F;05D0 05B8;05D0 05B8;05D0 05B8;05D0 05B8; # (אָ; א◌ָ; א◌ָ; א◌ָ; א◌ָ; ) HEBREW LETTER ALEF WITH QAMATS +FB30;05D0 05BC;05D0 05BC;05D0 05BC;05D0 05BC; # (אּ; א◌ּ; א◌ּ; א◌ּ; א◌ּ; ) HEBREW LETTER ALEF WITH MAPIQ +FB31;05D1 05BC;05D1 05BC;05D1 05BC;05D1 05BC; # (בּ; ב◌ּ; ב◌ּ; ב◌ּ; ב◌ּ; ) HEBREW LETTER BET WITH DAGESH +FB32;05D2 05BC;05D2 05BC;05D2 05BC;05D2 05BC; # (גּ; ג◌ּ; ג◌ּ; ג◌ּ; ג◌ּ; ) HEBREW LETTER GIMEL WITH DAGESH +FB33;05D3 05BC;05D3 05BC;05D3 05BC;05D3 05BC; # (דּ; ד◌ּ; ד◌ּ; ד◌ּ; ד◌ּ; ) HEBREW LETTER DALET WITH DAGESH +FB34;05D4 05BC;05D4 05BC;05D4 05BC;05D4 05BC; # (הּ; ה◌ּ; ה◌ּ; ה◌ּ; ה◌ּ; ) HEBREW LETTER HE WITH MAPIQ +FB35;05D5 05BC;05D5 05BC;05D5 05BC;05D5 05BC; # (וּ; ו◌ּ; ו◌ּ; ו◌ּ; ו◌ּ; ) HEBREW LETTER VAV WITH DAGESH +FB36;05D6 05BC;05D6 05BC;05D6 05BC;05D6 05BC; # (זּ; ז◌ּ; ז◌ּ; ז◌ּ; ז◌ּ; ) HEBREW LETTER ZAYIN WITH DAGESH +FB38;05D8 05BC;05D8 05BC;05D8 05BC;05D8 05BC; # (טּ; ט◌ּ; ט◌ּ; ט◌ּ; ט◌ּ; ) HEBREW LETTER TET WITH DAGESH +FB39;05D9 05BC;05D9 05BC;05D9 05BC;05D9 05BC; # (יּ; י◌ּ; י◌ּ; י◌ּ; י◌ּ; ) HEBREW LETTER YOD WITH DAGESH +FB3A;05DA 05BC;05DA 05BC;05DA 05BC;05DA 05BC; # (ךּ; ך◌ּ; ך◌ּ; ך◌ּ; ך◌ּ; ) HEBREW LETTER FINAL KAF WITH DAGESH +FB3B;05DB 05BC;05DB 05BC;05DB 05BC;05DB 05BC; # (כּ; כ◌ּ; כ◌ּ; כ◌ּ; כ◌ּ; ) HEBREW LETTER KAF WITH DAGESH +FB3C;05DC 05BC;05DC 05BC;05DC 05BC;05DC 05BC; # (לּ; ל◌ּ; ל◌ּ; ל◌ּ; ל◌ּ; ) HEBREW LETTER LAMED WITH DAGESH +FB3E;05DE 05BC;05DE 05BC;05DE 05BC;05DE 05BC; # (מּ; מ◌ּ; מ◌ּ; מ◌ּ; מ◌ּ; ) HEBREW LETTER MEM WITH DAGESH +FB40;05E0 05BC;05E0 05BC;05E0 05BC;05E0 05BC; # (נּ; נ◌ּ; נ◌ּ; נ◌ּ; נ◌ּ; ) HEBREW LETTER NUN WITH DAGESH +FB41;05E1 05BC;05E1 05BC;05E1 05BC;05E1 05BC; # (סּ; ס◌ּ; ס◌ּ; ס◌ּ; ס◌ּ; ) HEBREW LETTER SAMEKH WITH DAGESH +FB43;05E3 05BC;05E3 05BC;05E3 05BC;05E3 05BC; # (ףּ; ף◌ּ; ף◌ּ; ף◌ּ; ף◌ּ; ) HEBREW LETTER FINAL PE WITH DAGESH +FB44;05E4 05BC;05E4 05BC;05E4 05BC;05E4 05BC; # (פּ; פ◌ּ; פ◌ּ; פ◌ּ; פ◌ּ; ) HEBREW LETTER PE WITH DAGESH +FB46;05E6 05BC;05E6 05BC;05E6 05BC;05E6 05BC; # (צּ; צ◌ּ; צ◌ּ; צ◌ּ; צ◌ּ; ) HEBREW LETTER TSADI WITH DAGESH +FB47;05E7 05BC;05E7 05BC;05E7 05BC;05E7 05BC; # (קּ; ק◌ּ; ק◌ּ; ק◌ּ; ק◌ּ; ) HEBREW LETTER QOF WITH DAGESH +FB48;05E8 05BC;05E8 05BC;05E8 05BC;05E8 05BC; # (רּ; ר◌ּ; ר◌ּ; ר◌ּ; ר◌ּ; ) HEBREW LETTER RESH WITH DAGESH +FB49;05E9 05BC;05E9 05BC;05E9 05BC;05E9 05BC; # (שּ; ש◌ּ; ש◌ּ; ש◌ּ; ש◌ּ; ) HEBREW LETTER SHIN WITH DAGESH +FB4A;05EA 05BC;05EA 05BC;05EA 05BC;05EA 05BC; # (תּ; ת◌ּ; ת◌ּ; ת◌ּ; ת◌ּ; ) HEBREW LETTER TAV WITH DAGESH +FB4B;05D5 05B9;05D5 05B9;05D5 05B9;05D5 05B9; # (וֹ; ו◌ֹ; ו◌ֹ; ו◌ֹ; ו◌ֹ; ) HEBREW LETTER VAV WITH HOLAM +FB4C;05D1 05BF;05D1 05BF;05D1 05BF;05D1 05BF; # (בֿ; ב◌ֿ; ב◌ֿ; ב◌ֿ; ב◌ֿ; ) HEBREW LETTER BET WITH RAFE +FB4D;05DB 05BF;05DB 05BF;05DB 05BF;05DB 05BF; # (כֿ; כ◌ֿ; כ◌ֿ; כ◌ֿ; כ◌ֿ; ) HEBREW LETTER KAF WITH RAFE +FB4E;05E4 05BF;05E4 05BF;05E4 05BF;05E4 05BF; # (פֿ; פ◌ֿ; פ◌ֿ; פ◌ֿ; פ◌ֿ; ) HEBREW LETTER PE WITH RAFE +FB4F;FB4F;FB4F;05D0 05DC;05D0 05DC; # (ﭏ; ﭏ; ﭏ; אל; אל; ) HEBREW LIGATURE ALEF LAMED +FB50;FB50;FB50;0671;0671; # (ﭐ; ﭐ; ﭐ; ٱ; ٱ; ) ARABIC LETTER ALEF WASLA ISOLATED FORM +FB51;FB51;FB51;0671;0671; # (ﭑ; ﭑ; ﭑ; ٱ; ٱ; ) ARABIC LETTER ALEF WASLA FINAL FORM +FB52;FB52;FB52;067B;067B; # (ﭒ; ﭒ; ﭒ; ٻ; ٻ; ) ARABIC LETTER BEEH ISOLATED FORM +FB53;FB53;FB53;067B;067B; # (ﭓ; ﭓ; ﭓ; ٻ; ٻ; ) ARABIC LETTER BEEH FINAL FORM +FB54;FB54;FB54;067B;067B; # (ﭔ; ﭔ; ﭔ; ٻ; ٻ; ) ARABIC LETTER BEEH INITIAL FORM +FB55;FB55;FB55;067B;067B; # (ﭕ; ﭕ; ﭕ; ٻ; ٻ; ) ARABIC LETTER BEEH MEDIAL FORM +FB56;FB56;FB56;067E;067E; # (ﭖ; ﭖ; ﭖ; پ; پ; ) ARABIC LETTER PEH ISOLATED FORM +FB57;FB57;FB57;067E;067E; # (ﭗ; ﭗ; ﭗ; پ; پ; ) ARABIC LETTER PEH FINAL FORM +FB58;FB58;FB58;067E;067E; # (ﭘ; ﭘ; ﭘ; پ; پ; ) ARABIC LETTER PEH INITIAL FORM +FB59;FB59;FB59;067E;067E; # (ﭙ; ﭙ; ﭙ; پ; پ; ) ARABIC LETTER PEH MEDIAL FORM +FB5A;FB5A;FB5A;0680;0680; # (ﭚ; ﭚ; ﭚ; ڀ; ڀ; ) ARABIC LETTER BEHEH ISOLATED FORM +FB5B;FB5B;FB5B;0680;0680; # (ﭛ; ﭛ; ﭛ; ڀ; ڀ; ) ARABIC LETTER BEHEH FINAL FORM +FB5C;FB5C;FB5C;0680;0680; # (ﭜ; ﭜ; ﭜ; ڀ; ڀ; ) ARABIC LETTER BEHEH INITIAL FORM +FB5D;FB5D;FB5D;0680;0680; # (ﭝ; ﭝ; ﭝ; ڀ; ڀ; ) ARABIC LETTER BEHEH MEDIAL FORM +FB5E;FB5E;FB5E;067A;067A; # (ﭞ; ﭞ; ﭞ; ٺ; ٺ; ) ARABIC LETTER TTEHEH ISOLATED FORM +FB5F;FB5F;FB5F;067A;067A; # (ﭟ; ﭟ; ﭟ; ٺ; ٺ; ) ARABIC LETTER TTEHEH FINAL FORM +FB60;FB60;FB60;067A;067A; # (ﭠ; ﭠ; ﭠ; ٺ; ٺ; ) ARABIC LETTER TTEHEH INITIAL FORM +FB61;FB61;FB61;067A;067A; # (ﭡ; ﭡ; ﭡ; ٺ; ٺ; ) ARABIC LETTER TTEHEH MEDIAL FORM +FB62;FB62;FB62;067F;067F; # (ﭢ; ﭢ; ﭢ; ٿ; ٿ; ) ARABIC LETTER TEHEH ISOLATED FORM +FB63;FB63;FB63;067F;067F; # (ﭣ; ﭣ; ﭣ; ٿ; ٿ; ) ARABIC LETTER TEHEH FINAL FORM +FB64;FB64;FB64;067F;067F; # (ﭤ; ﭤ; ﭤ; ٿ; ٿ; ) ARABIC LETTER TEHEH INITIAL FORM +FB65;FB65;FB65;067F;067F; # (ﭥ; ﭥ; ﭥ; ٿ; ٿ; ) ARABIC LETTER TEHEH MEDIAL FORM +FB66;FB66;FB66;0679;0679; # (ﭦ; ﭦ; ﭦ; ٹ; ٹ; ) ARABIC LETTER TTEH ISOLATED FORM +FB67;FB67;FB67;0679;0679; # (ﭧ; ﭧ; ﭧ; ٹ; ٹ; ) ARABIC LETTER TTEH FINAL FORM +FB68;FB68;FB68;0679;0679; # (ﭨ; ﭨ; ﭨ; ٹ; ٹ; ) ARABIC LETTER TTEH INITIAL FORM +FB69;FB69;FB69;0679;0679; # (ﭩ; ﭩ; ﭩ; ٹ; ٹ; ) ARABIC LETTER TTEH MEDIAL FORM +FB6A;FB6A;FB6A;06A4;06A4; # (ﭪ; ﭪ; ﭪ; ڤ; ڤ; ) ARABIC LETTER VEH ISOLATED FORM +FB6B;FB6B;FB6B;06A4;06A4; # (ﭫ; ﭫ; ﭫ; ڤ; ڤ; ) ARABIC LETTER VEH FINAL FORM +FB6C;FB6C;FB6C;06A4;06A4; # (ﭬ; ﭬ; ﭬ; ڤ; ڤ; ) ARABIC LETTER VEH INITIAL FORM +FB6D;FB6D;FB6D;06A4;06A4; # (ﭭ; ﭭ; ﭭ; ڤ; ڤ; ) ARABIC LETTER VEH MEDIAL FORM +FB6E;FB6E;FB6E;06A6;06A6; # (ﭮ; ﭮ; ﭮ; ڦ; ڦ; ) ARABIC LETTER PEHEH ISOLATED FORM +FB6F;FB6F;FB6F;06A6;06A6; # (ﭯ; ﭯ; ﭯ; ڦ; ڦ; ) ARABIC LETTER PEHEH FINAL FORM +FB70;FB70;FB70;06A6;06A6; # (ﭰ; ﭰ; ﭰ; ڦ; ڦ; ) ARABIC LETTER PEHEH INITIAL FORM +FB71;FB71;FB71;06A6;06A6; # (ﭱ; ﭱ; ﭱ; ڦ; ڦ; ) ARABIC LETTER PEHEH MEDIAL FORM +FB72;FB72;FB72;0684;0684; # (ﭲ; ﭲ; ﭲ; ڄ; ڄ; ) ARABIC LETTER DYEH ISOLATED FORM +FB73;FB73;FB73;0684;0684; # (ﭳ; ﭳ; ﭳ; ڄ; ڄ; ) ARABIC LETTER DYEH FINAL FORM +FB74;FB74;FB74;0684;0684; # (ﭴ; ﭴ; ﭴ; ڄ; ڄ; ) ARABIC LETTER DYEH INITIAL FORM +FB75;FB75;FB75;0684;0684; # (ﭵ; ﭵ; ﭵ; ڄ; ڄ; ) ARABIC LETTER DYEH MEDIAL FORM +FB76;FB76;FB76;0683;0683; # (ﭶ; ﭶ; ﭶ; ڃ; ڃ; ) ARABIC LETTER NYEH ISOLATED FORM +FB77;FB77;FB77;0683;0683; # (ﭷ; ﭷ; ﭷ; ڃ; ڃ; ) ARABIC LETTER NYEH FINAL FORM +FB78;FB78;FB78;0683;0683; # (ﭸ; ﭸ; ﭸ; ڃ; ڃ; ) ARABIC LETTER NYEH INITIAL FORM +FB79;FB79;FB79;0683;0683; # (ﭹ; ﭹ; ﭹ; ڃ; ڃ; ) ARABIC LETTER NYEH MEDIAL FORM +FB7A;FB7A;FB7A;0686;0686; # (ﭺ; ﭺ; ﭺ; چ; چ; ) ARABIC LETTER TCHEH ISOLATED FORM +FB7B;FB7B;FB7B;0686;0686; # (ﭻ; ﭻ; ﭻ; چ; چ; ) ARABIC LETTER TCHEH FINAL FORM +FB7C;FB7C;FB7C;0686;0686; # (ﭼ; ﭼ; ﭼ; چ; چ; ) ARABIC LETTER TCHEH INITIAL FORM +FB7D;FB7D;FB7D;0686;0686; # (ﭽ; ﭽ; ﭽ; چ; چ; ) ARABIC LETTER TCHEH MEDIAL FORM +FB7E;FB7E;FB7E;0687;0687; # (ﭾ; ﭾ; ﭾ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH ISOLATED FORM +FB7F;FB7F;FB7F;0687;0687; # (ﭿ; ﭿ; ﭿ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH FINAL FORM +FB80;FB80;FB80;0687;0687; # (ﮀ; ﮀ; ﮀ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH INITIAL FORM +FB81;FB81;FB81;0687;0687; # (ﮁ; ﮁ; ﮁ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH MEDIAL FORM +FB82;FB82;FB82;068D;068D; # (ﮂ; ﮂ; ﮂ; ڍ; ڍ; ) ARABIC LETTER DDAHAL ISOLATED FORM +FB83;FB83;FB83;068D;068D; # (ﮃ; ﮃ; ﮃ; ڍ; ڍ; ) ARABIC LETTER DDAHAL FINAL FORM +FB84;FB84;FB84;068C;068C; # (ﮄ; ﮄ; ﮄ; ڌ; ڌ; ) ARABIC LETTER DAHAL ISOLATED FORM +FB85;FB85;FB85;068C;068C; # (ﮅ; ﮅ; ﮅ; ڌ; ڌ; ) ARABIC LETTER DAHAL FINAL FORM +FB86;FB86;FB86;068E;068E; # (ﮆ; ﮆ; ﮆ; ڎ; ڎ; ) ARABIC LETTER DUL ISOLATED FORM +FB87;FB87;FB87;068E;068E; # (ﮇ; ﮇ; ﮇ; ڎ; ڎ; ) ARABIC LETTER DUL FINAL FORM +FB88;FB88;FB88;0688;0688; # (ﮈ; ﮈ; ﮈ; ڈ; ڈ; ) ARABIC LETTER DDAL ISOLATED FORM +FB89;FB89;FB89;0688;0688; # (ﮉ; ﮉ; ﮉ; ڈ; ڈ; ) ARABIC LETTER DDAL FINAL FORM +FB8A;FB8A;FB8A;0698;0698; # (ﮊ; ﮊ; ﮊ; ژ; ژ; ) ARABIC LETTER JEH ISOLATED FORM +FB8B;FB8B;FB8B;0698;0698; # (ﮋ; ﮋ; ﮋ; ژ; ژ; ) ARABIC LETTER JEH FINAL FORM +FB8C;FB8C;FB8C;0691;0691; # (ﮌ; ﮌ; ﮌ; ڑ; ڑ; ) ARABIC LETTER RREH ISOLATED FORM +FB8D;FB8D;FB8D;0691;0691; # (ﮍ; ﮍ; ﮍ; ڑ; ڑ; ) ARABIC LETTER RREH FINAL FORM +FB8E;FB8E;FB8E;06A9;06A9; # (ﮎ; ﮎ; ﮎ; ک; ک; ) ARABIC LETTER KEHEH ISOLATED FORM +FB8F;FB8F;FB8F;06A9;06A9; # (ﮏ; ﮏ; ﮏ; ک; ک; ) ARABIC LETTER KEHEH FINAL FORM +FB90;FB90;FB90;06A9;06A9; # (ﮐ; ﮐ; ﮐ; ک; ک; ) ARABIC LETTER KEHEH INITIAL FORM +FB91;FB91;FB91;06A9;06A9; # (ﮑ; ﮑ; ﮑ; ک; ک; ) ARABIC LETTER KEHEH MEDIAL FORM +FB92;FB92;FB92;06AF;06AF; # (ﮒ; ﮒ; ﮒ; گ; گ; ) ARABIC LETTER GAF ISOLATED FORM +FB93;FB93;FB93;06AF;06AF; # (ﮓ; ﮓ; ﮓ; گ; گ; ) ARABIC LETTER GAF FINAL FORM +FB94;FB94;FB94;06AF;06AF; # (ﮔ; ﮔ; ﮔ; گ; گ; ) ARABIC LETTER GAF INITIAL FORM +FB95;FB95;FB95;06AF;06AF; # (ﮕ; ﮕ; ﮕ; گ; گ; ) ARABIC LETTER GAF MEDIAL FORM +FB96;FB96;FB96;06B3;06B3; # (ﮖ; ﮖ; ﮖ; ڳ; ڳ; ) ARABIC LETTER GUEH ISOLATED FORM +FB97;FB97;FB97;06B3;06B3; # (ﮗ; ﮗ; ﮗ; ڳ; ڳ; ) ARABIC LETTER GUEH FINAL FORM +FB98;FB98;FB98;06B3;06B3; # (ﮘ; ﮘ; ﮘ; ڳ; ڳ; ) ARABIC LETTER GUEH INITIAL FORM +FB99;FB99;FB99;06B3;06B3; # (ﮙ; ﮙ; ﮙ; ڳ; ڳ; ) ARABIC LETTER GUEH MEDIAL FORM +FB9A;FB9A;FB9A;06B1;06B1; # (ﮚ; ﮚ; ﮚ; ڱ; ڱ; ) ARABIC LETTER NGOEH ISOLATED FORM +FB9B;FB9B;FB9B;06B1;06B1; # (ﮛ; ﮛ; ﮛ; ڱ; ڱ; ) ARABIC LETTER NGOEH FINAL FORM +FB9C;FB9C;FB9C;06B1;06B1; # (ﮜ; ﮜ; ﮜ; ڱ; ڱ; ) ARABIC LETTER NGOEH INITIAL FORM +FB9D;FB9D;FB9D;06B1;06B1; # (ﮝ; ﮝ; ﮝ; ڱ; ڱ; ) ARABIC LETTER NGOEH MEDIAL FORM +FB9E;FB9E;FB9E;06BA;06BA; # (ﮞ; ﮞ; ﮞ; ں; ں; ) ARABIC LETTER NOON GHUNNA ISOLATED FORM +FB9F;FB9F;FB9F;06BA;06BA; # (ﮟ; ﮟ; ﮟ; ں; ں; ) ARABIC LETTER NOON GHUNNA FINAL FORM +FBA0;FBA0;FBA0;06BB;06BB; # (ﮠ; ﮠ; ﮠ; ڻ; ڻ; ) ARABIC LETTER RNOON ISOLATED FORM +FBA1;FBA1;FBA1;06BB;06BB; # (ﮡ; ﮡ; ﮡ; ڻ; ڻ; ) ARABIC LETTER RNOON FINAL FORM +FBA2;FBA2;FBA2;06BB;06BB; # (ﮢ; ﮢ; ﮢ; ڻ; ڻ; ) ARABIC LETTER RNOON INITIAL FORM +FBA3;FBA3;FBA3;06BB;06BB; # (ﮣ; ﮣ; ﮣ; ڻ; ڻ; ) ARABIC LETTER RNOON MEDIAL FORM +FBA4;FBA4;FBA4;06C0;06D5 0654; # (ﮤ; ﮤ; ﮤ; ۀ; ە◌ٔ; ) ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM +FBA5;FBA5;FBA5;06C0;06D5 0654; # (ﮥ; ﮥ; ﮥ; ۀ; ە◌ٔ; ) ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM +FBA6;FBA6;FBA6;06C1;06C1; # (ﮦ; ﮦ; ﮦ; ہ; ہ; ) ARABIC LETTER HEH GOAL ISOLATED FORM +FBA7;FBA7;FBA7;06C1;06C1; # (ﮧ; ﮧ; ﮧ; ہ; ہ; ) ARABIC LETTER HEH GOAL FINAL FORM +FBA8;FBA8;FBA8;06C1;06C1; # (ﮨ; ﮨ; ﮨ; ہ; ہ; ) ARABIC LETTER HEH GOAL INITIAL FORM +FBA9;FBA9;FBA9;06C1;06C1; # (ﮩ; ﮩ; ﮩ; ہ; ہ; ) ARABIC LETTER HEH GOAL MEDIAL FORM +FBAA;FBAA;FBAA;06BE;06BE; # (ﮪ; ﮪ; ﮪ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM +FBAB;FBAB;FBAB;06BE;06BE; # (ﮫ; ﮫ; ﮫ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE FINAL FORM +FBAC;FBAC;FBAC;06BE;06BE; # (ﮬ; ﮬ; ﮬ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE INITIAL FORM +FBAD;FBAD;FBAD;06BE;06BE; # (ﮭ; ﮭ; ﮭ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM +FBAE;FBAE;FBAE;06D2;06D2; # (ﮮ; ﮮ; ﮮ; ے; ے; ) ARABIC LETTER YEH BARREE ISOLATED FORM +FBAF;FBAF;FBAF;06D2;06D2; # (ﮯ; ﮯ; ﮯ; ے; ے; ) ARABIC LETTER YEH BARREE FINAL FORM +FBB0;FBB0;FBB0;06D3;06D2 0654; # (ﮰ; ﮰ; ﮰ; ۓ; ے◌ٔ; ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM +FBB1;FBB1;FBB1;06D3;06D2 0654; # (ﮱ; ﮱ; ﮱ; ۓ; ے◌ٔ; ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBD3;FBD3;FBD3;06AD;06AD; # (ﯓ; ﯓ; ﯓ; ڭ; ڭ; ) ARABIC LETTER NG ISOLATED FORM +FBD4;FBD4;FBD4;06AD;06AD; # (ﯔ; ﯔ; ﯔ; ڭ; ڭ; ) ARABIC LETTER NG FINAL FORM +FBD5;FBD5;FBD5;06AD;06AD; # (ﯕ; ﯕ; ﯕ; ڭ; ڭ; ) ARABIC LETTER NG INITIAL FORM +FBD6;FBD6;FBD6;06AD;06AD; # (ﯖ; ﯖ; ﯖ; ڭ; ڭ; ) ARABIC LETTER NG MEDIAL FORM +FBD7;FBD7;FBD7;06C7;06C7; # (ﯗ; ﯗ; ﯗ; ۇ; ۇ; ) ARABIC LETTER U ISOLATED FORM +FBD8;FBD8;FBD8;06C7;06C7; # (ﯘ; ﯘ; ﯘ; ۇ; ۇ; ) ARABIC LETTER U FINAL FORM +FBD9;FBD9;FBD9;06C6;06C6; # (ﯙ; ﯙ; ﯙ; ۆ; ۆ; ) ARABIC LETTER OE ISOLATED FORM +FBDA;FBDA;FBDA;06C6;06C6; # (ﯚ; ﯚ; ﯚ; ۆ; ۆ; ) ARABIC LETTER OE FINAL FORM +FBDB;FBDB;FBDB;06C8;06C8; # (ﯛ; ﯛ; ﯛ; ۈ; ۈ; ) ARABIC LETTER YU ISOLATED FORM +FBDC;FBDC;FBDC;06C8;06C8; # (ﯜ; ﯜ; ﯜ; ۈ; ۈ; ) ARABIC LETTER YU FINAL FORM +FBDD;FBDD;FBDD;06C7 0674;06C7 0674; # (ﯝ; ﯝ; ﯝ; ۇٴ; ۇٴ; ) ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM +FBDE;FBDE;FBDE;06CB;06CB; # (ﯞ; ﯞ; ﯞ; ۋ; ۋ; ) ARABIC LETTER VE ISOLATED FORM +FBDF;FBDF;FBDF;06CB;06CB; # (ﯟ; ﯟ; ﯟ; ۋ; ۋ; ) ARABIC LETTER VE FINAL FORM +FBE0;FBE0;FBE0;06C5;06C5; # (ﯠ; ﯠ; ﯠ; ۅ; ۅ; ) ARABIC LETTER KIRGHIZ OE ISOLATED FORM +FBE1;FBE1;FBE1;06C5;06C5; # (ﯡ; ﯡ; ﯡ; ۅ; ۅ; ) ARABIC LETTER KIRGHIZ OE FINAL FORM +FBE2;FBE2;FBE2;06C9;06C9; # (ﯢ; ﯢ; ﯢ; ۉ; ۉ; ) ARABIC LETTER KIRGHIZ YU ISOLATED FORM +FBE3;FBE3;FBE3;06C9;06C9; # (ﯣ; ﯣ; ﯣ; ۉ; ۉ; ) ARABIC LETTER KIRGHIZ YU FINAL FORM +FBE4;FBE4;FBE4;06D0;06D0; # (ﯤ; ﯤ; ﯤ; ې; ې; ) ARABIC LETTER E ISOLATED FORM +FBE5;FBE5;FBE5;06D0;06D0; # (ﯥ; ﯥ; ﯥ; ې; ې; ) ARABIC LETTER E FINAL FORM +FBE6;FBE6;FBE6;06D0;06D0; # (ﯦ; ﯦ; ﯦ; ې; ې; ) ARABIC LETTER E INITIAL FORM +FBE7;FBE7;FBE7;06D0;06D0; # (ﯧ; ﯧ; ﯧ; ې; ې; ) ARABIC LETTER E MEDIAL FORM +FBE8;FBE8;FBE8;0649;0649; # (ﯨ; ﯨ; ﯨ; ى; ى; ) ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM +FBE9;FBE9;FBE9;0649;0649; # (ﯩ; ﯩ; ﯩ; ى; ى; ) ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM +FBEA;FBEA;FBEA;0626 0627;064A 0654 0627; # (ﯪ; ﯪ; ﯪ; ئا; ي◌ٔا; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM +FBEB;FBEB;FBEB;0626 0627;064A 0654 0627; # (ﯫ; ﯫ; ﯫ; ئا; ي◌ٔا; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM +FBEC;FBEC;FBEC;0626 06D5;064A 0654 06D5; # (ﯬ; ﯬ; ﯬ; ئە; ي◌ٔە; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM +FBED;FBED;FBED;0626 06D5;064A 0654 06D5; # (ﯭ; ﯭ; ﯭ; ئە; ي◌ٔە; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM +FBEE;FBEE;FBEE;0626 0648;064A 0654 0648; # (ﯮ; ﯮ; ﯮ; ئو; ي◌ٔو; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM +FBEF;FBEF;FBEF;0626 0648;064A 0654 0648; # (ﯯ; ﯯ; ﯯ; ئو; ي◌ٔو; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM +FBF0;FBF0;FBF0;0626 06C7;064A 0654 06C7; # (ﯰ; ﯰ; ﯰ; ئۇ; ي◌ٔۇ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM +FBF1;FBF1;FBF1;0626 06C7;064A 0654 06C7; # (ﯱ; ﯱ; ﯱ; ئۇ; ي◌ٔۇ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM +FBF2;FBF2;FBF2;0626 06C6;064A 0654 06C6; # (ﯲ; ﯲ; ﯲ; ئۆ; ي◌ٔۆ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM +FBF3;FBF3;FBF3;0626 06C6;064A 0654 06C6; # (ﯳ; ﯳ; ﯳ; ئۆ; ي◌ٔۆ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM +FBF4;FBF4;FBF4;0626 06C8;064A 0654 06C8; # (ﯴ; ﯴ; ﯴ; ئۈ; ي◌ٔۈ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM +FBF5;FBF5;FBF5;0626 06C8;064A 0654 06C8; # (ﯵ; ﯵ; ﯵ; ئۈ; ي◌ٔۈ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM +FBF6;FBF6;FBF6;0626 06D0;064A 0654 06D0; # (ﯶ; ﯶ; ﯶ; ئې; ي◌ٔې; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM +FBF7;FBF7;FBF7;0626 06D0;064A 0654 06D0; # (ﯷ; ﯷ; ﯷ; ئې; ي◌ٔې; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM +FBF8;FBF8;FBF8;0626 06D0;064A 0654 06D0; # (ﯸ; ﯸ; ﯸ; ئې; ي◌ٔې; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM +FBF9;FBF9;FBF9;0626 0649;064A 0654 0649; # (ﯹ; ﯹ; ﯹ; ئى; ي◌ٔى; ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FBFA;FBFA;FBFA;0626 0649;064A 0654 0649; # (ﯺ; ﯺ; ﯺ; ئى; ي◌ٔى; ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FBFB;FBFB;FBFB;0626 0649;064A 0654 0649; # (ﯻ; ﯻ; ﯻ; ئى; ي◌ٔى; ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM +FBFC;FBFC;FBFC;06CC;06CC; # (ﯼ; ﯼ; ﯼ; ی; ی; ) ARABIC LETTER FARSI YEH ISOLATED FORM +FBFD;FBFD;FBFD;06CC;06CC; # (ﯽ; ﯽ; ﯽ; ی; ی; ) ARABIC LETTER FARSI YEH FINAL FORM +FBFE;FBFE;FBFE;06CC;06CC; # (ﯾ; ﯾ; ﯾ; ی; ی; ) ARABIC LETTER FARSI YEH INITIAL FORM +FBFF;FBFF;FBFF;06CC;06CC; # (ﯿ; ﯿ; ﯿ; ی; ی; ) ARABIC LETTER FARSI YEH MEDIAL FORM +FC00;FC00;FC00;0626 062C;064A 0654 062C; # (ﰀ; ﰀ; ﰀ; ئج; ي◌ٔج; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM +FC01;FC01;FC01;0626 062D;064A 0654 062D; # (ﰁ; ﰁ; ﰁ; ئح; ي◌ٔح; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM +FC02;FC02;FC02;0626 0645;064A 0654 0645; # (ﰂ; ﰂ; ﰂ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM +FC03;FC03;FC03;0626 0649;064A 0654 0649; # (ﰃ; ﰃ; ﰃ; ئى; ي◌ٔى; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FC04;FC04;FC04;0626 064A;064A 0654 064A; # (ﰄ; ﰄ; ﰄ; ئي; ي◌ٔي; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM +FC05;FC05;FC05;0628 062C;0628 062C; # (ﰅ; ﰅ; ﰅ; بج; بج; ) ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM +FC06;FC06;FC06;0628 062D;0628 062D; # (ﰆ; ﰆ; ﰆ; بح; بح; ) ARABIC LIGATURE BEH WITH HAH ISOLATED FORM +FC07;FC07;FC07;0628 062E;0628 062E; # (ﰇ; ﰇ; ﰇ; بخ; بخ; ) ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM +FC08;FC08;FC08;0628 0645;0628 0645; # (ﰈ; ﰈ; ﰈ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM +FC09;FC09;FC09;0628 0649;0628 0649; # (ﰉ; ﰉ; ﰉ; بى; بى; ) ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM +FC0A;FC0A;FC0A;0628 064A;0628 064A; # (ﰊ; ﰊ; ﰊ; بي; بي; ) ARABIC LIGATURE BEH WITH YEH ISOLATED FORM +FC0B;FC0B;FC0B;062A 062C;062A 062C; # (ﰋ; ﰋ; ﰋ; تج; تج; ) ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM +FC0C;FC0C;FC0C;062A 062D;062A 062D; # (ﰌ; ﰌ; ﰌ; تح; تح; ) ARABIC LIGATURE TEH WITH HAH ISOLATED FORM +FC0D;FC0D;FC0D;062A 062E;062A 062E; # (ﰍ; ﰍ; ﰍ; تخ; تخ; ) ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM +FC0E;FC0E;FC0E;062A 0645;062A 0645; # (ﰎ; ﰎ; ﰎ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM +FC0F;FC0F;FC0F;062A 0649;062A 0649; # (ﰏ; ﰏ; ﰏ; تى; تى; ) ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM +FC10;FC10;FC10;062A 064A;062A 064A; # (ﰐ; ﰐ; ﰐ; تي; تي; ) ARABIC LIGATURE TEH WITH YEH ISOLATED FORM +FC11;FC11;FC11;062B 062C;062B 062C; # (ﰑ; ﰑ; ﰑ; ثج; ثج; ) ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM +FC12;FC12;FC12;062B 0645;062B 0645; # (ﰒ; ﰒ; ﰒ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM +FC13;FC13;FC13;062B 0649;062B 0649; # (ﰓ; ﰓ; ﰓ; ثى; ثى; ) ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM +FC14;FC14;FC14;062B 064A;062B 064A; # (ﰔ; ﰔ; ﰔ; ثي; ثي; ) ARABIC LIGATURE THEH WITH YEH ISOLATED FORM +FC15;FC15;FC15;062C 062D;062C 062D; # (ﰕ; ﰕ; ﰕ; جح; جح; ) ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM +FC16;FC16;FC16;062C 0645;062C 0645; # (ﰖ; ﰖ; ﰖ; جم; جم; ) ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM +FC17;FC17;FC17;062D 062C;062D 062C; # (ﰗ; ﰗ; ﰗ; حج; حج; ) ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM +FC18;FC18;FC18;062D 0645;062D 0645; # (ﰘ; ﰘ; ﰘ; حم; حم; ) ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM +FC19;FC19;FC19;062E 062C;062E 062C; # (ﰙ; ﰙ; ﰙ; خج; خج; ) ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM +FC1A;FC1A;FC1A;062E 062D;062E 062D; # (ﰚ; ﰚ; ﰚ; خح; خح; ) ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM +FC1B;FC1B;FC1B;062E 0645;062E 0645; # (ﰛ; ﰛ; ﰛ; خم; خم; ) ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM +FC1C;FC1C;FC1C;0633 062C;0633 062C; # (ﰜ; ﰜ; ﰜ; سج; سج; ) ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM +FC1D;FC1D;FC1D;0633 062D;0633 062D; # (ﰝ; ﰝ; ﰝ; سح; سح; ) ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM +FC1E;FC1E;FC1E;0633 062E;0633 062E; # (ﰞ; ﰞ; ﰞ; سخ; سخ; ) ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM +FC1F;FC1F;FC1F;0633 0645;0633 0645; # (ﰟ; ﰟ; ﰟ; سم; سم; ) ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM +FC20;FC20;FC20;0635 062D;0635 062D; # (ﰠ; ﰠ; ﰠ; صح; صح; ) ARABIC LIGATURE SAD WITH HAH ISOLATED FORM +FC21;FC21;FC21;0635 0645;0635 0645; # (ﰡ; ﰡ; ﰡ; صم; صم; ) ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM +FC22;FC22;FC22;0636 062C;0636 062C; # (ﰢ; ﰢ; ﰢ; ضج; ضج; ) ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM +FC23;FC23;FC23;0636 062D;0636 062D; # (ﰣ; ﰣ; ﰣ; ضح; ضح; ) ARABIC LIGATURE DAD WITH HAH ISOLATED FORM +FC24;FC24;FC24;0636 062E;0636 062E; # (ﰤ; ﰤ; ﰤ; ضخ; ضخ; ) ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM +FC25;FC25;FC25;0636 0645;0636 0645; # (ﰥ; ﰥ; ﰥ; ضم; ضم; ) ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM +FC26;FC26;FC26;0637 062D;0637 062D; # (ﰦ; ﰦ; ﰦ; طح; طح; ) ARABIC LIGATURE TAH WITH HAH ISOLATED FORM +FC27;FC27;FC27;0637 0645;0637 0645; # (ﰧ; ﰧ; ﰧ; طم; طم; ) ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM +FC28;FC28;FC28;0638 0645;0638 0645; # (ﰨ; ﰨ; ﰨ; ظم; ظم; ) ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM +FC29;FC29;FC29;0639 062C;0639 062C; # (ﰩ; ﰩ; ﰩ; عج; عج; ) ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM +FC2A;FC2A;FC2A;0639 0645;0639 0645; # (ﰪ; ﰪ; ﰪ; عم; عم; ) ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM +FC2B;FC2B;FC2B;063A 062C;063A 062C; # (ﰫ; ﰫ; ﰫ; غج; غج; ) ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM +FC2C;FC2C;FC2C;063A 0645;063A 0645; # (ﰬ; ﰬ; ﰬ; غم; غم; ) ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM +FC2D;FC2D;FC2D;0641 062C;0641 062C; # (ﰭ; ﰭ; ﰭ; فج; فج; ) ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM +FC2E;FC2E;FC2E;0641 062D;0641 062D; # (ﰮ; ﰮ; ﰮ; فح; فح; ) ARABIC LIGATURE FEH WITH HAH ISOLATED FORM +FC2F;FC2F;FC2F;0641 062E;0641 062E; # (ﰯ; ﰯ; ﰯ; فخ; فخ; ) ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM +FC30;FC30;FC30;0641 0645;0641 0645; # (ﰰ; ﰰ; ﰰ; فم; فم; ) ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM +FC31;FC31;FC31;0641 0649;0641 0649; # (ﰱ; ﰱ; ﰱ; فى; فى; ) ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM +FC32;FC32;FC32;0641 064A;0641 064A; # (ﰲ; ﰲ; ﰲ; في; في; ) ARABIC LIGATURE FEH WITH YEH ISOLATED FORM +FC33;FC33;FC33;0642 062D;0642 062D; # (ﰳ; ﰳ; ﰳ; قح; قح; ) ARABIC LIGATURE QAF WITH HAH ISOLATED FORM +FC34;FC34;FC34;0642 0645;0642 0645; # (ﰴ; ﰴ; ﰴ; قم; قم; ) ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM +FC35;FC35;FC35;0642 0649;0642 0649; # (ﰵ; ﰵ; ﰵ; قى; قى; ) ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM +FC36;FC36;FC36;0642 064A;0642 064A; # (ﰶ; ﰶ; ﰶ; قي; قي; ) ARABIC LIGATURE QAF WITH YEH ISOLATED FORM +FC37;FC37;FC37;0643 0627;0643 0627; # (ﰷ; ﰷ; ﰷ; كا; كا; ) ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM +FC38;FC38;FC38;0643 062C;0643 062C; # (ﰸ; ﰸ; ﰸ; كج; كج; ) ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM +FC39;FC39;FC39;0643 062D;0643 062D; # (ﰹ; ﰹ; ﰹ; كح; كح; ) ARABIC LIGATURE KAF WITH HAH ISOLATED FORM +FC3A;FC3A;FC3A;0643 062E;0643 062E; # (ﰺ; ﰺ; ﰺ; كخ; كخ; ) ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM +FC3B;FC3B;FC3B;0643 0644;0643 0644; # (ﰻ; ﰻ; ﰻ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM ISOLATED FORM +FC3C;FC3C;FC3C;0643 0645;0643 0645; # (ﰼ; ﰼ; ﰼ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM +FC3D;FC3D;FC3D;0643 0649;0643 0649; # (ﰽ; ﰽ; ﰽ; كى; كى; ) ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM +FC3E;FC3E;FC3E;0643 064A;0643 064A; # (ﰾ; ﰾ; ﰾ; كي; كي; ) ARABIC LIGATURE KAF WITH YEH ISOLATED FORM +FC3F;FC3F;FC3F;0644 062C;0644 062C; # (ﰿ; ﰿ; ﰿ; لج; لج; ) ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM +FC40;FC40;FC40;0644 062D;0644 062D; # (ﱀ; ﱀ; ﱀ; لح; لح; ) ARABIC LIGATURE LAM WITH HAH ISOLATED FORM +FC41;FC41;FC41;0644 062E;0644 062E; # (ﱁ; ﱁ; ﱁ; لخ; لخ; ) ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM +FC42;FC42;FC42;0644 0645;0644 0645; # (ﱂ; ﱂ; ﱂ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM +FC43;FC43;FC43;0644 0649;0644 0649; # (ﱃ; ﱃ; ﱃ; لى; لى; ) ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM +FC44;FC44;FC44;0644 064A;0644 064A; # (ﱄ; ﱄ; ﱄ; لي; لي; ) ARABIC LIGATURE LAM WITH YEH ISOLATED FORM +FC45;FC45;FC45;0645 062C;0645 062C; # (ﱅ; ﱅ; ﱅ; مج; مج; ) ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM +FC46;FC46;FC46;0645 062D;0645 062D; # (ﱆ; ﱆ; ﱆ; مح; مح; ) ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM +FC47;FC47;FC47;0645 062E;0645 062E; # (ﱇ; ﱇ; ﱇ; مخ; مخ; ) ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM +FC48;FC48;FC48;0645 0645;0645 0645; # (ﱈ; ﱈ; ﱈ; مم; مم; ) ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM +FC49;FC49;FC49;0645 0649;0645 0649; # (ﱉ; ﱉ; ﱉ; مى; مى; ) ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM +FC4A;FC4A;FC4A;0645 064A;0645 064A; # (ﱊ; ﱊ; ﱊ; مي; مي; ) ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM +FC4B;FC4B;FC4B;0646 062C;0646 062C; # (ﱋ; ﱋ; ﱋ; نج; نج; ) ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM +FC4C;FC4C;FC4C;0646 062D;0646 062D; # (ﱌ; ﱌ; ﱌ; نح; نح; ) ARABIC LIGATURE NOON WITH HAH ISOLATED FORM +FC4D;FC4D;FC4D;0646 062E;0646 062E; # (ﱍ; ﱍ; ﱍ; نخ; نخ; ) ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM +FC4E;FC4E;FC4E;0646 0645;0646 0645; # (ﱎ; ﱎ; ﱎ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM +FC4F;FC4F;FC4F;0646 0649;0646 0649; # (ﱏ; ﱏ; ﱏ; نى; نى; ) ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM +FC50;FC50;FC50;0646 064A;0646 064A; # (ﱐ; ﱐ; ﱐ; ني; ني; ) ARABIC LIGATURE NOON WITH YEH ISOLATED FORM +FC51;FC51;FC51;0647 062C;0647 062C; # (ﱑ; ﱑ; ﱑ; هج; هج; ) ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM +FC52;FC52;FC52;0647 0645;0647 0645; # (ﱒ; ﱒ; ﱒ; هم; هم; ) ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM +FC53;FC53;FC53;0647 0649;0647 0649; # (ﱓ; ﱓ; ﱓ; هى; هى; ) ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM +FC54;FC54;FC54;0647 064A;0647 064A; # (ﱔ; ﱔ; ﱔ; هي; هي; ) ARABIC LIGATURE HEH WITH YEH ISOLATED FORM +FC55;FC55;FC55;064A 062C;064A 062C; # (ﱕ; ﱕ; ﱕ; يج; يج; ) ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM +FC56;FC56;FC56;064A 062D;064A 062D; # (ﱖ; ﱖ; ﱖ; يح; يح; ) ARABIC LIGATURE YEH WITH HAH ISOLATED FORM +FC57;FC57;FC57;064A 062E;064A 062E; # (ﱗ; ﱗ; ﱗ; يخ; يخ; ) ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM +FC58;FC58;FC58;064A 0645;064A 0645; # (ﱘ; ﱘ; ﱘ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM +FC59;FC59;FC59;064A 0649;064A 0649; # (ﱙ; ﱙ; ﱙ; يى; يى; ) ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM +FC5A;FC5A;FC5A;064A 064A;064A 064A; # (ﱚ; ﱚ; ﱚ; يي; يي; ) ARABIC LIGATURE YEH WITH YEH ISOLATED FORM +FC5B;FC5B;FC5B;0630 0670;0630 0670; # (ﱛ; ﱛ; ﱛ; ذ◌ٰ; ذ◌ٰ; ) ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5C;FC5C;FC5C;0631 0670;0631 0670; # (ﱜ; ﱜ; ﱜ; ر◌ٰ; ر◌ٰ; ) ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5D;FC5D;FC5D;0649 0670;0649 0670; # (ﱝ; ﱝ; ﱝ; ى◌ٰ; ى◌ٰ; ) ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5E;FC5E;FC5E;0020 064C 0651;0020 064C 0651; # (ﱞ; ﱞ; ﱞ; ◌ٌ◌ّ; ◌ٌ◌ّ; ) ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM +FC5F;FC5F;FC5F;0020 064D 0651;0020 064D 0651; # (ﱟ; ﱟ; ﱟ; ◌ٍ◌ّ; ◌ٍ◌ّ; ) ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM +FC60;FC60;FC60;0020 064E 0651;0020 064E 0651; # (ﱠ; ﱠ; ﱠ; ◌َ◌ّ; ◌َ◌ّ; ) ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM +FC61;FC61;FC61;0020 064F 0651;0020 064F 0651; # (ﱡ; ﱡ; ﱡ; ◌ُ◌ّ; ◌ُ◌ّ; ) ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM +FC62;FC62;FC62;0020 0650 0651;0020 0650 0651; # (ﱢ; ﱢ; ﱢ; ◌ِ◌ّ; ◌ِ◌ّ; ) ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM +FC63;FC63;FC63;0020 0651 0670;0020 0651 0670; # (ﱣ; ﱣ; ﱣ; ◌ّ◌ٰ; ◌ّ◌ٰ; ) ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM +FC64;FC64;FC64;0626 0631;064A 0654 0631; # (ﱤ; ﱤ; ﱤ; ئر; ي◌ٔر; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM +FC65;FC65;FC65;0626 0632;064A 0654 0632; # (ﱥ; ﱥ; ﱥ; ئز; ي◌ٔز; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM +FC66;FC66;FC66;0626 0645;064A 0654 0645; # (ﱦ; ﱦ; ﱦ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM +FC67;FC67;FC67;0626 0646;064A 0654 0646; # (ﱧ; ﱧ; ﱧ; ئن; ي◌ٔن; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM +FC68;FC68;FC68;0626 0649;064A 0654 0649; # (ﱨ; ﱨ; ﱨ; ئى; ي◌ٔى; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FC69;FC69;FC69;0626 064A;064A 0654 064A; # (ﱩ; ﱩ; ﱩ; ئي; ي◌ٔي; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM +FC6A;FC6A;FC6A;0628 0631;0628 0631; # (ﱪ; ﱪ; ﱪ; بر; بر; ) ARABIC LIGATURE BEH WITH REH FINAL FORM +FC6B;FC6B;FC6B;0628 0632;0628 0632; # (ﱫ; ﱫ; ﱫ; بز; بز; ) ARABIC LIGATURE BEH WITH ZAIN FINAL FORM +FC6C;FC6C;FC6C;0628 0645;0628 0645; # (ﱬ; ﱬ; ﱬ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM FINAL FORM +FC6D;FC6D;FC6D;0628 0646;0628 0646; # (ﱭ; ﱭ; ﱭ; بن; بن; ) ARABIC LIGATURE BEH WITH NOON FINAL FORM +FC6E;FC6E;FC6E;0628 0649;0628 0649; # (ﱮ; ﱮ; ﱮ; بى; بى; ) ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM +FC6F;FC6F;FC6F;0628 064A;0628 064A; # (ﱯ; ﱯ; ﱯ; بي; بي; ) ARABIC LIGATURE BEH WITH YEH FINAL FORM +FC70;FC70;FC70;062A 0631;062A 0631; # (ﱰ; ﱰ; ﱰ; تر; تر; ) ARABIC LIGATURE TEH WITH REH FINAL FORM +FC71;FC71;FC71;062A 0632;062A 0632; # (ﱱ; ﱱ; ﱱ; تز; تز; ) ARABIC LIGATURE TEH WITH ZAIN FINAL FORM +FC72;FC72;FC72;062A 0645;062A 0645; # (ﱲ; ﱲ; ﱲ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM FINAL FORM +FC73;FC73;FC73;062A 0646;062A 0646; # (ﱳ; ﱳ; ﱳ; تن; تن; ) ARABIC LIGATURE TEH WITH NOON FINAL FORM +FC74;FC74;FC74;062A 0649;062A 0649; # (ﱴ; ﱴ; ﱴ; تى; تى; ) ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM +FC75;FC75;FC75;062A 064A;062A 064A; # (ﱵ; ﱵ; ﱵ; تي; تي; ) ARABIC LIGATURE TEH WITH YEH FINAL FORM +FC76;FC76;FC76;062B 0631;062B 0631; # (ﱶ; ﱶ; ﱶ; ثر; ثر; ) ARABIC LIGATURE THEH WITH REH FINAL FORM +FC77;FC77;FC77;062B 0632;062B 0632; # (ﱷ; ﱷ; ﱷ; ثز; ثز; ) ARABIC LIGATURE THEH WITH ZAIN FINAL FORM +FC78;FC78;FC78;062B 0645;062B 0645; # (ﱸ; ﱸ; ﱸ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM FINAL FORM +FC79;FC79;FC79;062B 0646;062B 0646; # (ﱹ; ﱹ; ﱹ; ثن; ثن; ) ARABIC LIGATURE THEH WITH NOON FINAL FORM +FC7A;FC7A;FC7A;062B 0649;062B 0649; # (ﱺ; ﱺ; ﱺ; ثى; ثى; ) ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM +FC7B;FC7B;FC7B;062B 064A;062B 064A; # (ﱻ; ﱻ; ﱻ; ثي; ثي; ) ARABIC LIGATURE THEH WITH YEH FINAL FORM +FC7C;FC7C;FC7C;0641 0649;0641 0649; # (ﱼ; ﱼ; ﱼ; فى; فى; ) ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM +FC7D;FC7D;FC7D;0641 064A;0641 064A; # (ﱽ; ﱽ; ﱽ; في; في; ) ARABIC LIGATURE FEH WITH YEH FINAL FORM +FC7E;FC7E;FC7E;0642 0649;0642 0649; # (ﱾ; ﱾ; ﱾ; قى; قى; ) ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM +FC7F;FC7F;FC7F;0642 064A;0642 064A; # (ﱿ; ﱿ; ﱿ; قي; قي; ) ARABIC LIGATURE QAF WITH YEH FINAL FORM +FC80;FC80;FC80;0643 0627;0643 0627; # (ﲀ; ﲀ; ﲀ; كا; كا; ) ARABIC LIGATURE KAF WITH ALEF FINAL FORM +FC81;FC81;FC81;0643 0644;0643 0644; # (ﲁ; ﲁ; ﲁ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM FINAL FORM +FC82;FC82;FC82;0643 0645;0643 0645; # (ﲂ; ﲂ; ﲂ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM FINAL FORM +FC83;FC83;FC83;0643 0649;0643 0649; # (ﲃ; ﲃ; ﲃ; كى; كى; ) ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM +FC84;FC84;FC84;0643 064A;0643 064A; # (ﲄ; ﲄ; ﲄ; كي; كي; ) ARABIC LIGATURE KAF WITH YEH FINAL FORM +FC85;FC85;FC85;0644 0645;0644 0645; # (ﲅ; ﲅ; ﲅ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM FINAL FORM +FC86;FC86;FC86;0644 0649;0644 0649; # (ﲆ; ﲆ; ﲆ; لى; لى; ) ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM +FC87;FC87;FC87;0644 064A;0644 064A; # (ﲇ; ﲇ; ﲇ; لي; لي; ) ARABIC LIGATURE LAM WITH YEH FINAL FORM +FC88;FC88;FC88;0645 0627;0645 0627; # (ﲈ; ﲈ; ﲈ; ما; ما; ) ARABIC LIGATURE MEEM WITH ALEF FINAL FORM +FC89;FC89;FC89;0645 0645;0645 0645; # (ﲉ; ﲉ; ﲉ; مم; مم; ) ARABIC LIGATURE MEEM WITH MEEM FINAL FORM +FC8A;FC8A;FC8A;0646 0631;0646 0631; # (ﲊ; ﲊ; ﲊ; نر; نر; ) ARABIC LIGATURE NOON WITH REH FINAL FORM +FC8B;FC8B;FC8B;0646 0632;0646 0632; # (ﲋ; ﲋ; ﲋ; نز; نز; ) ARABIC LIGATURE NOON WITH ZAIN FINAL FORM +FC8C;FC8C;FC8C;0646 0645;0646 0645; # (ﲌ; ﲌ; ﲌ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM FINAL FORM +FC8D;FC8D;FC8D;0646 0646;0646 0646; # (ﲍ; ﲍ; ﲍ; نن; نن; ) ARABIC LIGATURE NOON WITH NOON FINAL FORM +FC8E;FC8E;FC8E;0646 0649;0646 0649; # (ﲎ; ﲎ; ﲎ; نى; نى; ) ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM +FC8F;FC8F;FC8F;0646 064A;0646 064A; # (ﲏ; ﲏ; ﲏ; ني; ني; ) ARABIC LIGATURE NOON WITH YEH FINAL FORM +FC90;FC90;FC90;0649 0670;0649 0670; # (ﲐ; ﲐ; ﲐ; ى◌ٰ; ى◌ٰ; ) ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM +FC91;FC91;FC91;064A 0631;064A 0631; # (ﲑ; ﲑ; ﲑ; ير; ير; ) ARABIC LIGATURE YEH WITH REH FINAL FORM +FC92;FC92;FC92;064A 0632;064A 0632; # (ﲒ; ﲒ; ﲒ; يز; يز; ) ARABIC LIGATURE YEH WITH ZAIN FINAL FORM +FC93;FC93;FC93;064A 0645;064A 0645; # (ﲓ; ﲓ; ﲓ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM FINAL FORM +FC94;FC94;FC94;064A 0646;064A 0646; # (ﲔ; ﲔ; ﲔ; ين; ين; ) ARABIC LIGATURE YEH WITH NOON FINAL FORM +FC95;FC95;FC95;064A 0649;064A 0649; # (ﲕ; ﲕ; ﲕ; يى; يى; ) ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM +FC96;FC96;FC96;064A 064A;064A 064A; # (ﲖ; ﲖ; ﲖ; يي; يي; ) ARABIC LIGATURE YEH WITH YEH FINAL FORM +FC97;FC97;FC97;0626 062C;064A 0654 062C; # (ﲗ; ﲗ; ﲗ; ئج; ي◌ٔج; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM +FC98;FC98;FC98;0626 062D;064A 0654 062D; # (ﲘ; ﲘ; ﲘ; ئح; ي◌ٔح; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM +FC99;FC99;FC99;0626 062E;064A 0654 062E; # (ﲙ; ﲙ; ﲙ; ئخ; ي◌ٔخ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM +FC9A;FC9A;FC9A;0626 0645;064A 0654 0645; # (ﲚ; ﲚ; ﲚ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM +FC9B;FC9B;FC9B;0626 0647;064A 0654 0647; # (ﲛ; ﲛ; ﲛ; ئه; ي◌ٔه; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM +FC9C;FC9C;FC9C;0628 062C;0628 062C; # (ﲜ; ﲜ; ﲜ; بج; بج; ) ARABIC LIGATURE BEH WITH JEEM INITIAL FORM +FC9D;FC9D;FC9D;0628 062D;0628 062D; # (ﲝ; ﲝ; ﲝ; بح; بح; ) ARABIC LIGATURE BEH WITH HAH INITIAL FORM +FC9E;FC9E;FC9E;0628 062E;0628 062E; # (ﲞ; ﲞ; ﲞ; بخ; بخ; ) ARABIC LIGATURE BEH WITH KHAH INITIAL FORM +FC9F;FC9F;FC9F;0628 0645;0628 0645; # (ﲟ; ﲟ; ﲟ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM INITIAL FORM +FCA0;FCA0;FCA0;0628 0647;0628 0647; # (ﲠ; ﲠ; ﲠ; به; به; ) ARABIC LIGATURE BEH WITH HEH INITIAL FORM +FCA1;FCA1;FCA1;062A 062C;062A 062C; # (ﲡ; ﲡ; ﲡ; تج; تج; ) ARABIC LIGATURE TEH WITH JEEM INITIAL FORM +FCA2;FCA2;FCA2;062A 062D;062A 062D; # (ﲢ; ﲢ; ﲢ; تح; تح; ) ARABIC LIGATURE TEH WITH HAH INITIAL FORM +FCA3;FCA3;FCA3;062A 062E;062A 062E; # (ﲣ; ﲣ; ﲣ; تخ; تخ; ) ARABIC LIGATURE TEH WITH KHAH INITIAL FORM +FCA4;FCA4;FCA4;062A 0645;062A 0645; # (ﲤ; ﲤ; ﲤ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM INITIAL FORM +FCA5;FCA5;FCA5;062A 0647;062A 0647; # (ﲥ; ﲥ; ﲥ; ته; ته; ) ARABIC LIGATURE TEH WITH HEH INITIAL FORM +FCA6;FCA6;FCA6;062B 0645;062B 0645; # (ﲦ; ﲦ; ﲦ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM INITIAL FORM +FCA7;FCA7;FCA7;062C 062D;062C 062D; # (ﲧ; ﲧ; ﲧ; جح; جح; ) ARABIC LIGATURE JEEM WITH HAH INITIAL FORM +FCA8;FCA8;FCA8;062C 0645;062C 0645; # (ﲨ; ﲨ; ﲨ; جم; جم; ) ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM +FCA9;FCA9;FCA9;062D 062C;062D 062C; # (ﲩ; ﲩ; ﲩ; حج; حج; ) ARABIC LIGATURE HAH WITH JEEM INITIAL FORM +FCAA;FCAA;FCAA;062D 0645;062D 0645; # (ﲪ; ﲪ; ﲪ; حم; حم; ) ARABIC LIGATURE HAH WITH MEEM INITIAL FORM +FCAB;FCAB;FCAB;062E 062C;062E 062C; # (ﲫ; ﲫ; ﲫ; خج; خج; ) ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM +FCAC;FCAC;FCAC;062E 0645;062E 0645; # (ﲬ; ﲬ; ﲬ; خم; خم; ) ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM +FCAD;FCAD;FCAD;0633 062C;0633 062C; # (ﲭ; ﲭ; ﲭ; سج; سج; ) ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM +FCAE;FCAE;FCAE;0633 062D;0633 062D; # (ﲮ; ﲮ; ﲮ; سح; سح; ) ARABIC LIGATURE SEEN WITH HAH INITIAL FORM +FCAF;FCAF;FCAF;0633 062E;0633 062E; # (ﲯ; ﲯ; ﲯ; سخ; سخ; ) ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM +FCB0;FCB0;FCB0;0633 0645;0633 0645; # (ﲰ; ﲰ; ﲰ; سم; سم; ) ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM +FCB1;FCB1;FCB1;0635 062D;0635 062D; # (ﲱ; ﲱ; ﲱ; صح; صح; ) ARABIC LIGATURE SAD WITH HAH INITIAL FORM +FCB2;FCB2;FCB2;0635 062E;0635 062E; # (ﲲ; ﲲ; ﲲ; صخ; صخ; ) ARABIC LIGATURE SAD WITH KHAH INITIAL FORM +FCB3;FCB3;FCB3;0635 0645;0635 0645; # (ﲳ; ﲳ; ﲳ; صم; صم; ) ARABIC LIGATURE SAD WITH MEEM INITIAL FORM +FCB4;FCB4;FCB4;0636 062C;0636 062C; # (ﲴ; ﲴ; ﲴ; ضج; ضج; ) ARABIC LIGATURE DAD WITH JEEM INITIAL FORM +FCB5;FCB5;FCB5;0636 062D;0636 062D; # (ﲵ; ﲵ; ﲵ; ضح; ضح; ) ARABIC LIGATURE DAD WITH HAH INITIAL FORM +FCB6;FCB6;FCB6;0636 062E;0636 062E; # (ﲶ; ﲶ; ﲶ; ضخ; ضخ; ) ARABIC LIGATURE DAD WITH KHAH INITIAL FORM +FCB7;FCB7;FCB7;0636 0645;0636 0645; # (ﲷ; ﲷ; ﲷ; ضم; ضم; ) ARABIC LIGATURE DAD WITH MEEM INITIAL FORM +FCB8;FCB8;FCB8;0637 062D;0637 062D; # (ﲸ; ﲸ; ﲸ; طح; طح; ) ARABIC LIGATURE TAH WITH HAH INITIAL FORM +FCB9;FCB9;FCB9;0638 0645;0638 0645; # (ﲹ; ﲹ; ﲹ; ظم; ظم; ) ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM +FCBA;FCBA;FCBA;0639 062C;0639 062C; # (ﲺ; ﲺ; ﲺ; عج; عج; ) ARABIC LIGATURE AIN WITH JEEM INITIAL FORM +FCBB;FCBB;FCBB;0639 0645;0639 0645; # (ﲻ; ﲻ; ﲻ; عم; عم; ) ARABIC LIGATURE AIN WITH MEEM INITIAL FORM +FCBC;FCBC;FCBC;063A 062C;063A 062C; # (ﲼ; ﲼ; ﲼ; غج; غج; ) ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM +FCBD;FCBD;FCBD;063A 0645;063A 0645; # (ﲽ; ﲽ; ﲽ; غم; غم; ) ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM +FCBE;FCBE;FCBE;0641 062C;0641 062C; # (ﲾ; ﲾ; ﲾ; فج; فج; ) ARABIC LIGATURE FEH WITH JEEM INITIAL FORM +FCBF;FCBF;FCBF;0641 062D;0641 062D; # (ﲿ; ﲿ; ﲿ; فح; فح; ) ARABIC LIGATURE FEH WITH HAH INITIAL FORM +FCC0;FCC0;FCC0;0641 062E;0641 062E; # (ﳀ; ﳀ; ﳀ; فخ; فخ; ) ARABIC LIGATURE FEH WITH KHAH INITIAL FORM +FCC1;FCC1;FCC1;0641 0645;0641 0645; # (ﳁ; ﳁ; ﳁ; فم; فم; ) ARABIC LIGATURE FEH WITH MEEM INITIAL FORM +FCC2;FCC2;FCC2;0642 062D;0642 062D; # (ﳂ; ﳂ; ﳂ; قح; قح; ) ARABIC LIGATURE QAF WITH HAH INITIAL FORM +FCC3;FCC3;FCC3;0642 0645;0642 0645; # (ﳃ; ﳃ; ﳃ; قم; قم; ) ARABIC LIGATURE QAF WITH MEEM INITIAL FORM +FCC4;FCC4;FCC4;0643 062C;0643 062C; # (ﳄ; ﳄ; ﳄ; كج; كج; ) ARABIC LIGATURE KAF WITH JEEM INITIAL FORM +FCC5;FCC5;FCC5;0643 062D;0643 062D; # (ﳅ; ﳅ; ﳅ; كح; كح; ) ARABIC LIGATURE KAF WITH HAH INITIAL FORM +FCC6;FCC6;FCC6;0643 062E;0643 062E; # (ﳆ; ﳆ; ﳆ; كخ; كخ; ) ARABIC LIGATURE KAF WITH KHAH INITIAL FORM +FCC7;FCC7;FCC7;0643 0644;0643 0644; # (ﳇ; ﳇ; ﳇ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM INITIAL FORM +FCC8;FCC8;FCC8;0643 0645;0643 0645; # (ﳈ; ﳈ; ﳈ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM INITIAL FORM +FCC9;FCC9;FCC9;0644 062C;0644 062C; # (ﳉ; ﳉ; ﳉ; لج; لج; ) ARABIC LIGATURE LAM WITH JEEM INITIAL FORM +FCCA;FCCA;FCCA;0644 062D;0644 062D; # (ﳊ; ﳊ; ﳊ; لح; لح; ) ARABIC LIGATURE LAM WITH HAH INITIAL FORM +FCCB;FCCB;FCCB;0644 062E;0644 062E; # (ﳋ; ﳋ; ﳋ; لخ; لخ; ) ARABIC LIGATURE LAM WITH KHAH INITIAL FORM +FCCC;FCCC;FCCC;0644 0645;0644 0645; # (ﳌ; ﳌ; ﳌ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM INITIAL FORM +FCCD;FCCD;FCCD;0644 0647;0644 0647; # (ﳍ; ﳍ; ﳍ; له; له; ) ARABIC LIGATURE LAM WITH HEH INITIAL FORM +FCCE;FCCE;FCCE;0645 062C;0645 062C; # (ﳎ; ﳎ; ﳎ; مج; مج; ) ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM +FCCF;FCCF;FCCF;0645 062D;0645 062D; # (ﳏ; ﳏ; ﳏ; مح; مح; ) ARABIC LIGATURE MEEM WITH HAH INITIAL FORM +FCD0;FCD0;FCD0;0645 062E;0645 062E; # (ﳐ; ﳐ; ﳐ; مخ; مخ; ) ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM +FCD1;FCD1;FCD1;0645 0645;0645 0645; # (ﳑ; ﳑ; ﳑ; مم; مم; ) ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM +FCD2;FCD2;FCD2;0646 062C;0646 062C; # (ﳒ; ﳒ; ﳒ; نج; نج; ) ARABIC LIGATURE NOON WITH JEEM INITIAL FORM +FCD3;FCD3;FCD3;0646 062D;0646 062D; # (ﳓ; ﳓ; ﳓ; نح; نح; ) ARABIC LIGATURE NOON WITH HAH INITIAL FORM +FCD4;FCD4;FCD4;0646 062E;0646 062E; # (ﳔ; ﳔ; ﳔ; نخ; نخ; ) ARABIC LIGATURE NOON WITH KHAH INITIAL FORM +FCD5;FCD5;FCD5;0646 0645;0646 0645; # (ﳕ; ﳕ; ﳕ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM INITIAL FORM +FCD6;FCD6;FCD6;0646 0647;0646 0647; # (ﳖ; ﳖ; ﳖ; نه; نه; ) ARABIC LIGATURE NOON WITH HEH INITIAL FORM +FCD7;FCD7;FCD7;0647 062C;0647 062C; # (ﳗ; ﳗ; ﳗ; هج; هج; ) ARABIC LIGATURE HEH WITH JEEM INITIAL FORM +FCD8;FCD8;FCD8;0647 0645;0647 0645; # (ﳘ; ﳘ; ﳘ; هم; هم; ) ARABIC LIGATURE HEH WITH MEEM INITIAL FORM +FCD9;FCD9;FCD9;0647 0670;0647 0670; # (ﳙ; ﳙ; ﳙ; ه◌ٰ; ه◌ٰ; ) ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM +FCDA;FCDA;FCDA;064A 062C;064A 062C; # (ﳚ; ﳚ; ﳚ; يج; يج; ) ARABIC LIGATURE YEH WITH JEEM INITIAL FORM +FCDB;FCDB;FCDB;064A 062D;064A 062D; # (ﳛ; ﳛ; ﳛ; يح; يح; ) ARABIC LIGATURE YEH WITH HAH INITIAL FORM +FCDC;FCDC;FCDC;064A 062E;064A 062E; # (ﳜ; ﳜ; ﳜ; يخ; يخ; ) ARABIC LIGATURE YEH WITH KHAH INITIAL FORM +FCDD;FCDD;FCDD;064A 0645;064A 0645; # (ﳝ; ﳝ; ﳝ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM INITIAL FORM +FCDE;FCDE;FCDE;064A 0647;064A 0647; # (ﳞ; ﳞ; ﳞ; يه; يه; ) ARABIC LIGATURE YEH WITH HEH INITIAL FORM +FCDF;FCDF;FCDF;0626 0645;064A 0654 0645; # (ﳟ; ﳟ; ﳟ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM +FCE0;FCE0;FCE0;0626 0647;064A 0654 0647; # (ﳠ; ﳠ; ﳠ; ئه; ي◌ٔه; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM +FCE1;FCE1;FCE1;0628 0645;0628 0645; # (ﳡ; ﳡ; ﳡ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM +FCE2;FCE2;FCE2;0628 0647;0628 0647; # (ﳢ; ﳢ; ﳢ; به; به; ) ARABIC LIGATURE BEH WITH HEH MEDIAL FORM +FCE3;FCE3;FCE3;062A 0645;062A 0645; # (ﳣ; ﳣ; ﳣ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM +FCE4;FCE4;FCE4;062A 0647;062A 0647; # (ﳤ; ﳤ; ﳤ; ته; ته; ) ARABIC LIGATURE TEH WITH HEH MEDIAL FORM +FCE5;FCE5;FCE5;062B 0645;062B 0645; # (ﳥ; ﳥ; ﳥ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM +FCE6;FCE6;FCE6;062B 0647;062B 0647; # (ﳦ; ﳦ; ﳦ; ثه; ثه; ) ARABIC LIGATURE THEH WITH HEH MEDIAL FORM +FCE7;FCE7;FCE7;0633 0645;0633 0645; # (ﳧ; ﳧ; ﳧ; سم; سم; ) ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM +FCE8;FCE8;FCE8;0633 0647;0633 0647; # (ﳨ; ﳨ; ﳨ; سه; سه; ) ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM +FCE9;FCE9;FCE9;0634 0645;0634 0645; # (ﳩ; ﳩ; ﳩ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM +FCEA;FCEA;FCEA;0634 0647;0634 0647; # (ﳪ; ﳪ; ﳪ; شه; شه; ) ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM +FCEB;FCEB;FCEB;0643 0644;0643 0644; # (ﳫ; ﳫ; ﳫ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM MEDIAL FORM +FCEC;FCEC;FCEC;0643 0645;0643 0645; # (ﳬ; ﳬ; ﳬ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM +FCED;FCED;FCED;0644 0645;0644 0645; # (ﳭ; ﳭ; ﳭ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM +FCEE;FCEE;FCEE;0646 0645;0646 0645; # (ﳮ; ﳮ; ﳮ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM +FCEF;FCEF;FCEF;0646 0647;0646 0647; # (ﳯ; ﳯ; ﳯ; نه; نه; ) ARABIC LIGATURE NOON WITH HEH MEDIAL FORM +FCF0;FCF0;FCF0;064A 0645;064A 0645; # (ﳰ; ﳰ; ﳰ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM +FCF1;FCF1;FCF1;064A 0647;064A 0647; # (ﳱ; ﳱ; ﳱ; يه; يه; ) ARABIC LIGATURE YEH WITH HEH MEDIAL FORM +FCF2;FCF2;FCF2;0640 064E 0651;0640 064E 0651; # (ﳲ; ﳲ; ﳲ; ـ◌َ◌ّ; ـ◌َ◌ّ; ) ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM +FCF3;FCF3;FCF3;0640 064F 0651;0640 064F 0651; # (ﳳ; ﳳ; ﳳ; ـ◌ُ◌ّ; ـ◌ُ◌ّ; ) ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM +FCF4;FCF4;FCF4;0640 0650 0651;0640 0650 0651; # (ﳴ; ﳴ; ﳴ; ـ◌ِ◌ّ; ـ◌ِ◌ّ; ) ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM +FCF5;FCF5;FCF5;0637 0649;0637 0649; # (ﳵ; ﳵ; ﳵ; طى; طى; ) ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM +FCF6;FCF6;FCF6;0637 064A;0637 064A; # (ﳶ; ﳶ; ﳶ; طي; طي; ) ARABIC LIGATURE TAH WITH YEH ISOLATED FORM +FCF7;FCF7;FCF7;0639 0649;0639 0649; # (ﳷ; ﳷ; ﳷ; عى; عى; ) ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM +FCF8;FCF8;FCF8;0639 064A;0639 064A; # (ﳸ; ﳸ; ﳸ; عي; عي; ) ARABIC LIGATURE AIN WITH YEH ISOLATED FORM +FCF9;FCF9;FCF9;063A 0649;063A 0649; # (ﳹ; ﳹ; ﳹ; غى; غى; ) ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM +FCFA;FCFA;FCFA;063A 064A;063A 064A; # (ﳺ; ﳺ; ﳺ; غي; غي; ) ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM +FCFB;FCFB;FCFB;0633 0649;0633 0649; # (ﳻ; ﳻ; ﳻ; سى; سى; ) ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM +FCFC;FCFC;FCFC;0633 064A;0633 064A; # (ﳼ; ﳼ; ﳼ; سي; سي; ) ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM +FCFD;FCFD;FCFD;0634 0649;0634 0649; # (ﳽ; ﳽ; ﳽ; شى; شى; ) ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM +FCFE;FCFE;FCFE;0634 064A;0634 064A; # (ﳾ; ﳾ; ﳾ; شي; شي; ) ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM +FCFF;FCFF;FCFF;062D 0649;062D 0649; # (ﳿ; ﳿ; ﳿ; حى; حى; ) ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM +FD00;FD00;FD00;062D 064A;062D 064A; # (ﴀ; ﴀ; ﴀ; حي; حي; ) ARABIC LIGATURE HAH WITH YEH ISOLATED FORM +FD01;FD01;FD01;062C 0649;062C 0649; # (ﴁ; ﴁ; ﴁ; جى; جى; ) ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM +FD02;FD02;FD02;062C 064A;062C 064A; # (ﴂ; ﴂ; ﴂ; جي; جي; ) ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM +FD03;FD03;FD03;062E 0649;062E 0649; # (ﴃ; ﴃ; ﴃ; خى; خى; ) ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM +FD04;FD04;FD04;062E 064A;062E 064A; # (ﴄ; ﴄ; ﴄ; خي; خي; ) ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM +FD05;FD05;FD05;0635 0649;0635 0649; # (ﴅ; ﴅ; ﴅ; صى; صى; ) ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM +FD06;FD06;FD06;0635 064A;0635 064A; # (ﴆ; ﴆ; ﴆ; صي; صي; ) ARABIC LIGATURE SAD WITH YEH ISOLATED FORM +FD07;FD07;FD07;0636 0649;0636 0649; # (ﴇ; ﴇ; ﴇ; ضى; ضى; ) ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM +FD08;FD08;FD08;0636 064A;0636 064A; # (ﴈ; ﴈ; ﴈ; ضي; ضي; ) ARABIC LIGATURE DAD WITH YEH ISOLATED FORM +FD09;FD09;FD09;0634 062C;0634 062C; # (ﴉ; ﴉ; ﴉ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM +FD0A;FD0A;FD0A;0634 062D;0634 062D; # (ﴊ; ﴊ; ﴊ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM +FD0B;FD0B;FD0B;0634 062E;0634 062E; # (ﴋ; ﴋ; ﴋ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM +FD0C;FD0C;FD0C;0634 0645;0634 0645; # (ﴌ; ﴌ; ﴌ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM +FD0D;FD0D;FD0D;0634 0631;0634 0631; # (ﴍ; ﴍ; ﴍ; شر; شر; ) ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM +FD0E;FD0E;FD0E;0633 0631;0633 0631; # (ﴎ; ﴎ; ﴎ; سر; سر; ) ARABIC LIGATURE SEEN WITH REH ISOLATED FORM +FD0F;FD0F;FD0F;0635 0631;0635 0631; # (ﴏ; ﴏ; ﴏ; صر; صر; ) ARABIC LIGATURE SAD WITH REH ISOLATED FORM +FD10;FD10;FD10;0636 0631;0636 0631; # (ﴐ; ﴐ; ﴐ; ضر; ضر; ) ARABIC LIGATURE DAD WITH REH ISOLATED FORM +FD11;FD11;FD11;0637 0649;0637 0649; # (ﴑ; ﴑ; ﴑ; طى; طى; ) ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM +FD12;FD12;FD12;0637 064A;0637 064A; # (ﴒ; ﴒ; ﴒ; طي; طي; ) ARABIC LIGATURE TAH WITH YEH FINAL FORM +FD13;FD13;FD13;0639 0649;0639 0649; # (ﴓ; ﴓ; ﴓ; عى; عى; ) ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM +FD14;FD14;FD14;0639 064A;0639 064A; # (ﴔ; ﴔ; ﴔ; عي; عي; ) ARABIC LIGATURE AIN WITH YEH FINAL FORM +FD15;FD15;FD15;063A 0649;063A 0649; # (ﴕ; ﴕ; ﴕ; غى; غى; ) ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM +FD16;FD16;FD16;063A 064A;063A 064A; # (ﴖ; ﴖ; ﴖ; غي; غي; ) ARABIC LIGATURE GHAIN WITH YEH FINAL FORM +FD17;FD17;FD17;0633 0649;0633 0649; # (ﴗ; ﴗ; ﴗ; سى; سى; ) ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM +FD18;FD18;FD18;0633 064A;0633 064A; # (ﴘ; ﴘ; ﴘ; سي; سي; ) ARABIC LIGATURE SEEN WITH YEH FINAL FORM +FD19;FD19;FD19;0634 0649;0634 0649; # (ﴙ; ﴙ; ﴙ; شى; شى; ) ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM +FD1A;FD1A;FD1A;0634 064A;0634 064A; # (ﴚ; ﴚ; ﴚ; شي; شي; ) ARABIC LIGATURE SHEEN WITH YEH FINAL FORM +FD1B;FD1B;FD1B;062D 0649;062D 0649; # (ﴛ; ﴛ; ﴛ; حى; حى; ) ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM +FD1C;FD1C;FD1C;062D 064A;062D 064A; # (ﴜ; ﴜ; ﴜ; حي; حي; ) ARABIC LIGATURE HAH WITH YEH FINAL FORM +FD1D;FD1D;FD1D;062C 0649;062C 0649; # (ﴝ; ﴝ; ﴝ; جى; جى; ) ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM +FD1E;FD1E;FD1E;062C 064A;062C 064A; # (ﴞ; ﴞ; ﴞ; جي; جي; ) ARABIC LIGATURE JEEM WITH YEH FINAL FORM +FD1F;FD1F;FD1F;062E 0649;062E 0649; # (ﴟ; ﴟ; ﴟ; خى; خى; ) ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM +FD20;FD20;FD20;062E 064A;062E 064A; # (ﴠ; ﴠ; ﴠ; خي; خي; ) ARABIC LIGATURE KHAH WITH YEH FINAL FORM +FD21;FD21;FD21;0635 0649;0635 0649; # (ﴡ; ﴡ; ﴡ; صى; صى; ) ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM +FD22;FD22;FD22;0635 064A;0635 064A; # (ﴢ; ﴢ; ﴢ; صي; صي; ) ARABIC LIGATURE SAD WITH YEH FINAL FORM +FD23;FD23;FD23;0636 0649;0636 0649; # (ﴣ; ﴣ; ﴣ; ضى; ضى; ) ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM +FD24;FD24;FD24;0636 064A;0636 064A; # (ﴤ; ﴤ; ﴤ; ضي; ضي; ) ARABIC LIGATURE DAD WITH YEH FINAL FORM +FD25;FD25;FD25;0634 062C;0634 062C; # (ﴥ; ﴥ; ﴥ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM +FD26;FD26;FD26;0634 062D;0634 062D; # (ﴦ; ﴦ; ﴦ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH FINAL FORM +FD27;FD27;FD27;0634 062E;0634 062E; # (ﴧ; ﴧ; ﴧ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM +FD28;FD28;FD28;0634 0645;0634 0645; # (ﴨ; ﴨ; ﴨ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM +FD29;FD29;FD29;0634 0631;0634 0631; # (ﴩ; ﴩ; ﴩ; شر; شر; ) ARABIC LIGATURE SHEEN WITH REH FINAL FORM +FD2A;FD2A;FD2A;0633 0631;0633 0631; # (ﴪ; ﴪ; ﴪ; سر; سر; ) ARABIC LIGATURE SEEN WITH REH FINAL FORM +FD2B;FD2B;FD2B;0635 0631;0635 0631; # (ﴫ; ﴫ; ﴫ; صر; صر; ) ARABIC LIGATURE SAD WITH REH FINAL FORM +FD2C;FD2C;FD2C;0636 0631;0636 0631; # (ﴬ; ﴬ; ﴬ; ضر; ضر; ) ARABIC LIGATURE DAD WITH REH FINAL FORM +FD2D;FD2D;FD2D;0634 062C;0634 062C; # (ﴭ; ﴭ; ﴭ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM +FD2E;FD2E;FD2E;0634 062D;0634 062D; # (ﴮ; ﴮ; ﴮ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM +FD2F;FD2F;FD2F;0634 062E;0634 062E; # (ﴯ; ﴯ; ﴯ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM +FD30;FD30;FD30;0634 0645;0634 0645; # (ﴰ; ﴰ; ﴰ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM +FD31;FD31;FD31;0633 0647;0633 0647; # (ﴱ; ﴱ; ﴱ; سه; سه; ) ARABIC LIGATURE SEEN WITH HEH INITIAL FORM +FD32;FD32;FD32;0634 0647;0634 0647; # (ﴲ; ﴲ; ﴲ; شه; شه; ) ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM +FD33;FD33;FD33;0637 0645;0637 0645; # (ﴳ; ﴳ; ﴳ; طم; طم; ) ARABIC LIGATURE TAH WITH MEEM INITIAL FORM +FD34;FD34;FD34;0633 062C;0633 062C; # (ﴴ; ﴴ; ﴴ; سج; سج; ) ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM +FD35;FD35;FD35;0633 062D;0633 062D; # (ﴵ; ﴵ; ﴵ; سح; سح; ) ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM +FD36;FD36;FD36;0633 062E;0633 062E; # (ﴶ; ﴶ; ﴶ; سخ; سخ; ) ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM +FD37;FD37;FD37;0634 062C;0634 062C; # (ﴷ; ﴷ; ﴷ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM +FD38;FD38;FD38;0634 062D;0634 062D; # (ﴸ; ﴸ; ﴸ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM +FD39;FD39;FD39;0634 062E;0634 062E; # (ﴹ; ﴹ; ﴹ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM +FD3A;FD3A;FD3A;0637 0645;0637 0645; # (ﴺ; ﴺ; ﴺ; طم; طم; ) ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM +FD3B;FD3B;FD3B;0638 0645;0638 0645; # (ﴻ; ﴻ; ﴻ; ظم; ظم; ) ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM +FD3C;FD3C;FD3C;0627 064B;0627 064B; # (ﴼ; ﴼ; ﴼ; ا◌ً; ا◌ً; ) ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM +FD3D;FD3D;FD3D;0627 064B;0627 064B; # (ﴽ; ﴽ; ﴽ; ا◌ً; ا◌ً; ) ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD50;FD50;FD50;062A 062C 0645;062A 062C 0645; # (ﵐ; ﵐ; ﵐ; تجم; تجم; ) ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM +FD51;FD51;FD51;062A 062D 062C;062A 062D 062C; # (ﵑ; ﵑ; ﵑ; تحج; تحج; ) ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM +FD52;FD52;FD52;062A 062D 062C;062A 062D 062C; # (ﵒ; ﵒ; ﵒ; تحج; تحج; ) ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM +FD53;FD53;FD53;062A 062D 0645;062A 062D 0645; # (ﵓ; ﵓ; ﵓ; تحم; تحم; ) ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM +FD54;FD54;FD54;062A 062E 0645;062A 062E 0645; # (ﵔ; ﵔ; ﵔ; تخم; تخم; ) ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM +FD55;FD55;FD55;062A 0645 062C;062A 0645 062C; # (ﵕ; ﵕ; ﵕ; تمج; تمج; ) ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM +FD56;FD56;FD56;062A 0645 062D;062A 0645 062D; # (ﵖ; ﵖ; ﵖ; تمح; تمح; ) ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM +FD57;FD57;FD57;062A 0645 062E;062A 0645 062E; # (ﵗ; ﵗ; ﵗ; تمخ; تمخ; ) ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM +FD58;FD58;FD58;062C 0645 062D;062C 0645 062D; # (ﵘ; ﵘ; ﵘ; جمح; جمح; ) ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM +FD59;FD59;FD59;062C 0645 062D;062C 0645 062D; # (ﵙ; ﵙ; ﵙ; جمح; جمح; ) ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM +FD5A;FD5A;FD5A;062D 0645 064A;062D 0645 064A; # (ﵚ; ﵚ; ﵚ; حمي; حمي; ) ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM +FD5B;FD5B;FD5B;062D 0645 0649;062D 0645 0649; # (ﵛ; ﵛ; ﵛ; حمى; حمى; ) ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD5C;FD5C;FD5C;0633 062D 062C;0633 062D 062C; # (ﵜ; ﵜ; ﵜ; سحج; سحج; ) ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM +FD5D;FD5D;FD5D;0633 062C 062D;0633 062C 062D; # (ﵝ; ﵝ; ﵝ; سجح; سجح; ) ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM +FD5E;FD5E;FD5E;0633 062C 0649;0633 062C 0649; # (ﵞ; ﵞ; ﵞ; سجى; سجى; ) ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD5F;FD5F;FD5F;0633 0645 062D;0633 0645 062D; # (ﵟ; ﵟ; ﵟ; سمح; سمح; ) ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM +FD60;FD60;FD60;0633 0645 062D;0633 0645 062D; # (ﵠ; ﵠ; ﵠ; سمح; سمح; ) ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM +FD61;FD61;FD61;0633 0645 062C;0633 0645 062C; # (ﵡ; ﵡ; ﵡ; سمج; سمج; ) ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM +FD62;FD62;FD62;0633 0645 0645;0633 0645 0645; # (ﵢ; ﵢ; ﵢ; سمم; سمم; ) ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM +FD63;FD63;FD63;0633 0645 0645;0633 0645 0645; # (ﵣ; ﵣ; ﵣ; سمم; سمم; ) ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM +FD64;FD64;FD64;0635 062D 062D;0635 062D 062D; # (ﵤ; ﵤ; ﵤ; صحح; صحح; ) ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM +FD65;FD65;FD65;0635 062D 062D;0635 062D 062D; # (ﵥ; ﵥ; ﵥ; صحح; صحح; ) ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM +FD66;FD66;FD66;0635 0645 0645;0635 0645 0645; # (ﵦ; ﵦ; ﵦ; صمم; صمم; ) ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM +FD67;FD67;FD67;0634 062D 0645;0634 062D 0645; # (ﵧ; ﵧ; ﵧ; شحم; شحم; ) ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM +FD68;FD68;FD68;0634 062D 0645;0634 062D 0645; # (ﵨ; ﵨ; ﵨ; شحم; شحم; ) ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM +FD69;FD69;FD69;0634 062C 064A;0634 062C 064A; # (ﵩ; ﵩ; ﵩ; شجي; شجي; ) ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM +FD6A;FD6A;FD6A;0634 0645 062E;0634 0645 062E; # (ﵪ; ﵪ; ﵪ; شمخ; شمخ; ) ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM +FD6B;FD6B;FD6B;0634 0645 062E;0634 0645 062E; # (ﵫ; ﵫ; ﵫ; شمخ; شمخ; ) ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM +FD6C;FD6C;FD6C;0634 0645 0645;0634 0645 0645; # (ﵬ; ﵬ; ﵬ; شمم; شمم; ) ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM +FD6D;FD6D;FD6D;0634 0645 0645;0634 0645 0645; # (ﵭ; ﵭ; ﵭ; شمم; شمم; ) ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM +FD6E;FD6E;FD6E;0636 062D 0649;0636 062D 0649; # (ﵮ; ﵮ; ﵮ; ضحى; ضحى; ) ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM +FD6F;FD6F;FD6F;0636 062E 0645;0636 062E 0645; # (ﵯ; ﵯ; ﵯ; ضخم; ضخم; ) ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM +FD70;FD70;FD70;0636 062E 0645;0636 062E 0645; # (ﵰ; ﵰ; ﵰ; ضخم; ضخم; ) ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM +FD71;FD71;FD71;0637 0645 062D;0637 0645 062D; # (ﵱ; ﵱ; ﵱ; طمح; طمح; ) ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM +FD72;FD72;FD72;0637 0645 062D;0637 0645 062D; # (ﵲ; ﵲ; ﵲ; طمح; طمح; ) ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM +FD73;FD73;FD73;0637 0645 0645;0637 0645 0645; # (ﵳ; ﵳ; ﵳ; طمم; طمم; ) ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM +FD74;FD74;FD74;0637 0645 064A;0637 0645 064A; # (ﵴ; ﵴ; ﵴ; طمي; طمي; ) ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM +FD75;FD75;FD75;0639 062C 0645;0639 062C 0645; # (ﵵ; ﵵ; ﵵ; عجم; عجم; ) ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM +FD76;FD76;FD76;0639 0645 0645;0639 0645 0645; # (ﵶ; ﵶ; ﵶ; عمم; عمم; ) ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM +FD77;FD77;FD77;0639 0645 0645;0639 0645 0645; # (ﵷ; ﵷ; ﵷ; عمم; عمم; ) ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM +FD78;FD78;FD78;0639 0645 0649;0639 0645 0649; # (ﵸ; ﵸ; ﵸ; عمى; عمى; ) ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD79;FD79;FD79;063A 0645 0645;063A 0645 0645; # (ﵹ; ﵹ; ﵹ; غمم; غمم; ) ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM +FD7A;FD7A;FD7A;063A 0645 064A;063A 0645 064A; # (ﵺ; ﵺ; ﵺ; غمي; غمي; ) ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM +FD7B;FD7B;FD7B;063A 0645 0649;063A 0645 0649; # (ﵻ; ﵻ; ﵻ; غمى; غمى; ) ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD7C;FD7C;FD7C;0641 062E 0645;0641 062E 0645; # (ﵼ; ﵼ; ﵼ; فخم; فخم; ) ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM +FD7D;FD7D;FD7D;0641 062E 0645;0641 062E 0645; # (ﵽ; ﵽ; ﵽ; فخم; فخم; ) ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM +FD7E;FD7E;FD7E;0642 0645 062D;0642 0645 062D; # (ﵾ; ﵾ; ﵾ; قمح; قمح; ) ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM +FD7F;FD7F;FD7F;0642 0645 0645;0642 0645 0645; # (ﵿ; ﵿ; ﵿ; قمم; قمم; ) ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM +FD80;FD80;FD80;0644 062D 0645;0644 062D 0645; # (ﶀ; ﶀ; ﶀ; لحم; لحم; ) ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM +FD81;FD81;FD81;0644 062D 064A;0644 062D 064A; # (ﶁ; ﶁ; ﶁ; لحي; لحي; ) ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM +FD82;FD82;FD82;0644 062D 0649;0644 062D 0649; # (ﶂ; ﶂ; ﶂ; لحى; لحى; ) ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM +FD83;FD83;FD83;0644 062C 062C;0644 062C 062C; # (ﶃ; ﶃ; ﶃ; لجج; لجج; ) ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM +FD84;FD84;FD84;0644 062C 062C;0644 062C 062C; # (ﶄ; ﶄ; ﶄ; لجج; لجج; ) ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM +FD85;FD85;FD85;0644 062E 0645;0644 062E 0645; # (ﶅ; ﶅ; ﶅ; لخم; لخم; ) ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM +FD86;FD86;FD86;0644 062E 0645;0644 062E 0645; # (ﶆ; ﶆ; ﶆ; لخم; لخم; ) ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM +FD87;FD87;FD87;0644 0645 062D;0644 0645 062D; # (ﶇ; ﶇ; ﶇ; لمح; لمح; ) ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM +FD88;FD88;FD88;0644 0645 062D;0644 0645 062D; # (ﶈ; ﶈ; ﶈ; لمح; لمح; ) ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM +FD89;FD89;FD89;0645 062D 062C;0645 062D 062C; # (ﶉ; ﶉ; ﶉ; محج; محج; ) ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM +FD8A;FD8A;FD8A;0645 062D 0645;0645 062D 0645; # (ﶊ; ﶊ; ﶊ; محم; محم; ) ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM +FD8B;FD8B;FD8B;0645 062D 064A;0645 062D 064A; # (ﶋ; ﶋ; ﶋ; محي; محي; ) ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM +FD8C;FD8C;FD8C;0645 062C 062D;0645 062C 062D; # (ﶌ; ﶌ; ﶌ; مجح; مجح; ) ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM +FD8D;FD8D;FD8D;0645 062C 0645;0645 062C 0645; # (ﶍ; ﶍ; ﶍ; مجم; مجم; ) ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM +FD8E;FD8E;FD8E;0645 062E 062C;0645 062E 062C; # (ﶎ; ﶎ; ﶎ; مخج; مخج; ) ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM +FD8F;FD8F;FD8F;0645 062E 0645;0645 062E 0645; # (ﶏ; ﶏ; ﶏ; مخم; مخم; ) ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD92;FD92;FD92;0645 062C 062E;0645 062C 062E; # (ﶒ; ﶒ; ﶒ; مجخ; مجخ; ) ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM +FD93;FD93;FD93;0647 0645 062C;0647 0645 062C; # (ﶓ; ﶓ; ﶓ; همج; همج; ) ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM +FD94;FD94;FD94;0647 0645 0645;0647 0645 0645; # (ﶔ; ﶔ; ﶔ; همم; همم; ) ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM +FD95;FD95;FD95;0646 062D 0645;0646 062D 0645; # (ﶕ; ﶕ; ﶕ; نحم; نحم; ) ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM +FD96;FD96;FD96;0646 062D 0649;0646 062D 0649; # (ﶖ; ﶖ; ﶖ; نحى; نحى; ) ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM +FD97;FD97;FD97;0646 062C 0645;0646 062C 0645; # (ﶗ; ﶗ; ﶗ; نجم; نجم; ) ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM +FD98;FD98;FD98;0646 062C 0645;0646 062C 0645; # (ﶘ; ﶘ; ﶘ; نجم; نجم; ) ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM +FD99;FD99;FD99;0646 062C 0649;0646 062C 0649; # (ﶙ; ﶙ; ﶙ; نجى; نجى; ) ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD9A;FD9A;FD9A;0646 0645 064A;0646 0645 064A; # (ﶚ; ﶚ; ﶚ; نمي; نمي; ) ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM +FD9B;FD9B;FD9B;0646 0645 0649;0646 0645 0649; # (ﶛ; ﶛ; ﶛ; نمى; نمى; ) ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD9C;FD9C;FD9C;064A 0645 0645;064A 0645 0645; # (ﶜ; ﶜ; ﶜ; يمم; يمم; ) ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM +FD9D;FD9D;FD9D;064A 0645 0645;064A 0645 0645; # (ﶝ; ﶝ; ﶝ; يمم; يمم; ) ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM +FD9E;FD9E;FD9E;0628 062E 064A;0628 062E 064A; # (ﶞ; ﶞ; ﶞ; بخي; بخي; ) ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM +FD9F;FD9F;FD9F;062A 062C 064A;062A 062C 064A; # (ﶟ; ﶟ; ﶟ; تجي; تجي; ) ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM +FDA0;FDA0;FDA0;062A 062C 0649;062A 062C 0649; # (ﶠ; ﶠ; ﶠ; تجى; تجى; ) ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM +FDA1;FDA1;FDA1;062A 062E 064A;062A 062E 064A; # (ﶡ; ﶡ; ﶡ; تخي; تخي; ) ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM +FDA2;FDA2;FDA2;062A 062E 0649;062A 062E 0649; # (ﶢ; ﶢ; ﶢ; تخى; تخى; ) ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA3;FDA3;FDA3;062A 0645 064A;062A 0645 064A; # (ﶣ; ﶣ; ﶣ; تمي; تمي; ) ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM +FDA4;FDA4;FDA4;062A 0645 0649;062A 0645 0649; # (ﶤ; ﶤ; ﶤ; تمى; تمى; ) ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA5;FDA5;FDA5;062C 0645 064A;062C 0645 064A; # (ﶥ; ﶥ; ﶥ; جمي; جمي; ) ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM +FDA6;FDA6;FDA6;062C 062D 0649;062C 062D 0649; # (ﶦ; ﶦ; ﶦ; جحى; جحى; ) ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM +FDA7;FDA7;FDA7;062C 0645 0649;062C 0645 0649; # (ﶧ; ﶧ; ﶧ; جمى; جمى; ) ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA8;FDA8;FDA8;0633 062E 0649;0633 062E 0649; # (ﶨ; ﶨ; ﶨ; سخى; سخى; ) ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA9;FDA9;FDA9;0635 062D 064A;0635 062D 064A; # (ﶩ; ﶩ; ﶩ; صحي; صحي; ) ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM +FDAA;FDAA;FDAA;0634 062D 064A;0634 062D 064A; # (ﶪ; ﶪ; ﶪ; شحي; شحي; ) ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM +FDAB;FDAB;FDAB;0636 062D 064A;0636 062D 064A; # (ﶫ; ﶫ; ﶫ; ضحي; ضحي; ) ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM +FDAC;FDAC;FDAC;0644 062C 064A;0644 062C 064A; # (ﶬ; ﶬ; ﶬ; لجي; لجي; ) ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM +FDAD;FDAD;FDAD;0644 0645 064A;0644 0645 064A; # (ﶭ; ﶭ; ﶭ; لمي; لمي; ) ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM +FDAE;FDAE;FDAE;064A 062D 064A;064A 062D 064A; # (ﶮ; ﶮ; ﶮ; يحي; يحي; ) ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM +FDAF;FDAF;FDAF;064A 062C 064A;064A 062C 064A; # (ﶯ; ﶯ; ﶯ; يجي; يجي; ) ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM +FDB0;FDB0;FDB0;064A 0645 064A;064A 0645 064A; # (ﶰ; ﶰ; ﶰ; يمي; يمي; ) ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM +FDB1;FDB1;FDB1;0645 0645 064A;0645 0645 064A; # (ﶱ; ﶱ; ﶱ; ممي; ممي; ) ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM +FDB2;FDB2;FDB2;0642 0645 064A;0642 0645 064A; # (ﶲ; ﶲ; ﶲ; قمي; قمي; ) ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM +FDB3;FDB3;FDB3;0646 062D 064A;0646 062D 064A; # (ﶳ; ﶳ; ﶳ; نحي; نحي; ) ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM +FDB4;FDB4;FDB4;0642 0645 062D;0642 0645 062D; # (ﶴ; ﶴ; ﶴ; قمح; قمح; ) ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM +FDB5;FDB5;FDB5;0644 062D 0645;0644 062D 0645; # (ﶵ; ﶵ; ﶵ; لحم; لحم; ) ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM +FDB6;FDB6;FDB6;0639 0645 064A;0639 0645 064A; # (ﶶ; ﶶ; ﶶ; عمي; عمي; ) ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM +FDB7;FDB7;FDB7;0643 0645 064A;0643 0645 064A; # (ﶷ; ﶷ; ﶷ; كمي; كمي; ) ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM +FDB8;FDB8;FDB8;0646 062C 062D;0646 062C 062D; # (ﶸ; ﶸ; ﶸ; نجح; نجح; ) ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM +FDB9;FDB9;FDB9;0645 062E 064A;0645 062E 064A; # (ﶹ; ﶹ; ﶹ; مخي; مخي; ) ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM +FDBA;FDBA;FDBA;0644 062C 0645;0644 062C 0645; # (ﶺ; ﶺ; ﶺ; لجم; لجم; ) ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM +FDBB;FDBB;FDBB;0643 0645 0645;0643 0645 0645; # (ﶻ; ﶻ; ﶻ; كمم; كمم; ) ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM +FDBC;FDBC;FDBC;0644 062C 0645;0644 062C 0645; # (ﶼ; ﶼ; ﶼ; لجم; لجم; ) ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM +FDBD;FDBD;FDBD;0646 062C 062D;0646 062C 062D; # (ﶽ; ﶽ; ﶽ; نجح; نجح; ) ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM +FDBE;FDBE;FDBE;062C 062D 064A;062C 062D 064A; # (ﶾ; ﶾ; ﶾ; جحي; جحي; ) ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM +FDBF;FDBF;FDBF;062D 062C 064A;062D 062C 064A; # (ﶿ; ﶿ; ﶿ; حجي; حجي; ) ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM +FDC0;FDC0;FDC0;0645 062C 064A;0645 062C 064A; # (ﷀ; ﷀ; ﷀ; مجي; مجي; ) ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM +FDC1;FDC1;FDC1;0641 0645 064A;0641 0645 064A; # (ﷁ; ﷁ; ﷁ; فمي; فمي; ) ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM +FDC2;FDC2;FDC2;0628 062D 064A;0628 062D 064A; # (ﷂ; ﷂ; ﷂ; بحي; بحي; ) ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM +FDC3;FDC3;FDC3;0643 0645 0645;0643 0645 0645; # (ﷃ; ﷃ; ﷃ; كمم; كمم; ) ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM +FDC4;FDC4;FDC4;0639 062C 0645;0639 062C 0645; # (ﷄ; ﷄ; ﷄ; عجم; عجم; ) ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM +FDC5;FDC5;FDC5;0635 0645 0645;0635 0645 0645; # (ﷅ; ﷅ; ﷅ; صمم; صمم; ) ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM +FDC6;FDC6;FDC6;0633 062E 064A;0633 062E 064A; # (ﷆ; ﷆ; ﷆ; سخي; سخي; ) ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM +FDC7;FDC7;FDC7;0646 062C 064A;0646 062C 064A; # (ﷇ; ﷇ; ﷇ; نجي; نجي; ) ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDF0;FDF0;FDF0;0635 0644 06D2;0635 0644 06D2; # (ﷰ; ﷰ; ﷰ; صلے; صلے; ) ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM +FDF1;FDF1;FDF1;0642 0644 06D2;0642 0644 06D2; # (ﷱ; ﷱ; ﷱ; قلے; قلے; ) ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM +FDF2;FDF2;FDF2;0627 0644 0644 0647;0627 0644 0644 0647; # (ﷲ; ﷲ; ﷲ; الله; الله; ) ARABIC LIGATURE ALLAH ISOLATED FORM +FDF3;FDF3;FDF3;0627 0643 0628 0631;0627 0643 0628 0631; # (ﷳ; ﷳ; ﷳ; اكبر; اكبر; ) ARABIC LIGATURE AKBAR ISOLATED FORM +FDF4;FDF4;FDF4;0645 062D 0645 062F;0645 062D 0645 062F; # (ﷴ; ﷴ; ﷴ; محمد; محمد; ) ARABIC LIGATURE MOHAMMAD ISOLATED FORM +FDF5;FDF5;FDF5;0635 0644 0639 0645;0635 0644 0639 0645; # (ﷵ; ﷵ; ﷵ; صلعم; صلعم; ) ARABIC LIGATURE SALAM ISOLATED FORM +FDF6;FDF6;FDF6;0631 0633 0648 0644;0631 0633 0648 0644; # (ﷶ; ﷶ; ﷶ; رسول; رسول; ) ARABIC LIGATURE RASOUL ISOLATED FORM +FDF7;FDF7;FDF7;0639 0644 064A 0647;0639 0644 064A 0647; # (ﷷ; ﷷ; ﷷ; عليه; عليه; ) ARABIC LIGATURE ALAYHE ISOLATED FORM +FDF8;FDF8;FDF8;0648 0633 0644 0645;0648 0633 0644 0645; # (ﷸ; ﷸ; ﷸ; وسلم; وسلم; ) ARABIC LIGATURE WASALLAM ISOLATED FORM +FDF9;FDF9;FDF9;0635 0644 0649;0635 0644 0649; # (ﷹ; ﷹ; ﷹ; صلى; صلى; ) ARABIC LIGATURE SALLA ISOLATED FORM +FDFA;FDFA;FDFA;0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645; # (ﷺ; ﷺ; ﷺ; صلى الله عليه وسلم; صلى الله عليه وسلم; ) ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM +FDFB;FDFB;FDFB;062C 0644 0020 062C 0644 0627 0644 0647;062C 0644 0020 062C 0644 0627 0644 0647; # (ﷻ; ﷻ; ﷻ; جل جلاله; جل جلاله; ) ARABIC LIGATURE JALLAJALALOUHOU +FDFC;FDFC;FDFC;0631 06CC 0627 0644;0631 06CC 0627 0644; # (﷼; ﷼; ﷼; ریال; ریال; ) RIAL SIGN +FE30;FE30;FE30;002E 002E;002E 002E; # (︰; ︰; ︰; ..; ..; ) PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31;FE31;FE31;2014;2014; # (︱; ︱; ︱; —; —; ) PRESENTATION FORM FOR VERTICAL EM DASH +FE32;FE32;FE32;2013;2013; # (︲; ︲; ︲; –; –; ) PRESENTATION FORM FOR VERTICAL EN DASH +FE33;FE33;FE33;005F;005F; # (︳; ︳; ︳; _; _; ) PRESENTATION FORM FOR VERTICAL LOW LINE +FE34;FE34;FE34;005F;005F; # (︴; ︴; ︴; _; _; ) PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE35;FE35;FE35;0028;0028; # (︵; ︵; ︵; (; (; ) PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE36;FE36;FE36;0029;0029; # (︶; ︶; ︶; ); ); ) PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE37;FE37;FE37;007B;007B; # (︷; ︷; ︷; {; {; ) PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE38;FE38;FE38;007D;007D; # (︸; ︸; ︸; }; }; ) PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE39;FE39;FE39;3014;3014; # (︹; ︹; ︹; 〔; 〔; ) PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3A;FE3A;FE3A;3015;3015; # (︺; ︺; ︺; 〕; 〕; ) PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3B;FE3B;FE3B;3010;3010; # (︻; ︻; ︻; 【; 【; ) PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3C;FE3C;FE3C;3011;3011; # (︼; ︼; ︼; 】; 】; ) PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3D;FE3D;FE3D;300A;300A; # (︽; ︽; ︽; 《; 《; ) PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3E;FE3E;FE3E;300B;300B; # (︾; ︾; ︾; 》; 》; ) PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE3F;FE3F;FE3F;3008;3008; # (︿; ︿; ︿; 〈; 〈; ) PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE40;FE40;FE40;3009;3009; # (﹀; ﹀; ﹀; 〉; 〉; ) PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE41;FE41;FE41;300C;300C; # (﹁; ﹁; ﹁; 「; 「; ) PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42;FE42;FE42;300D;300D; # (﹂; ﹂; ﹂; 」; 」; ) PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43;FE43;FE43;300E;300E; # (﹃; ﹃; ﹃; 『; 『; ) PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44;FE44;FE44;300F;300F; # (﹄; ﹄; ﹄; 』; 』; ) PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE49;FE49;FE49;0020 0305;0020 0305; # (﹉; ﹉; ﹉; ◌̅; ◌̅; ) DASHED OVERLINE +FE4A;FE4A;FE4A;0020 0305;0020 0305; # (﹊; ﹊; ﹊; ◌̅; ◌̅; ) CENTRELINE OVERLINE +FE4B;FE4B;FE4B;0020 0305;0020 0305; # (﹋; ﹋; ﹋; ◌̅; ◌̅; ) WAVY OVERLINE +FE4C;FE4C;FE4C;0020 0305;0020 0305; # (﹌; ﹌; ﹌; ◌̅; ◌̅; ) DOUBLE WAVY OVERLINE +FE4D;FE4D;FE4D;005F;005F; # (﹍; ﹍; ﹍; _; _; ) DASHED LOW LINE +FE4E;FE4E;FE4E;005F;005F; # (﹎; ﹎; ﹎; _; _; ) CENTRELINE LOW LINE +FE4F;FE4F;FE4F;005F;005F; # (﹏; ﹏; ﹏; _; _; ) WAVY LOW LINE +FE50;FE50;FE50;002C;002C; # (﹐; ﹐; ﹐; ,; ,; ) SMALL COMMA +FE51;FE51;FE51;3001;3001; # (﹑; ﹑; ﹑; 、; 、; ) SMALL IDEOGRAPHIC COMMA +FE52;FE52;FE52;002E;002E; # (﹒; ﹒; ﹒; .; .; ) SMALL FULL STOP +FE54;FE54;FE54;003B;003B; # (﹔; ﹔; ﹔; ;; ;; ) SMALL SEMICOLON +FE55;FE55;FE55;003A;003A; # (﹕; ﹕; ﹕; :; :; ) SMALL COLON +FE56;FE56;FE56;003F;003F; # (﹖; ﹖; ﹖; ?; ?; ) SMALL QUESTION MARK +FE57;FE57;FE57;0021;0021; # (﹗; ﹗; ﹗; !; !; ) SMALL EXCLAMATION MARK +FE58;FE58;FE58;2014;2014; # (﹘; ﹘; ﹘; —; —; ) SMALL EM DASH +FE59;FE59;FE59;0028;0028; # (﹙; ﹙; ﹙; (; (; ) SMALL LEFT PARENTHESIS +FE5A;FE5A;FE5A;0029;0029; # (﹚; ﹚; ﹚; ); ); ) SMALL RIGHT PARENTHESIS +FE5B;FE5B;FE5B;007B;007B; # (﹛; ﹛; ﹛; {; {; ) SMALL LEFT CURLY BRACKET +FE5C;FE5C;FE5C;007D;007D; # (﹜; ﹜; ﹜; }; }; ) SMALL RIGHT CURLY BRACKET +FE5D;FE5D;FE5D;3014;3014; # (﹝; ﹝; ﹝; 〔; 〔; ) SMALL LEFT TORTOISE SHELL BRACKET +FE5E;FE5E;FE5E;3015;3015; # (﹞; ﹞; ﹞; 〕; 〕; ) SMALL RIGHT TORTOISE SHELL BRACKET +FE5F;FE5F;FE5F;0023;0023; # (﹟; ﹟; ﹟; #; #; ) SMALL NUMBER SIGN +FE60;FE60;FE60;0026;0026; # (﹠; ﹠; ﹠; &; &; ) SMALL AMPERSAND +FE61;FE61;FE61;002A;002A; # (﹡; ﹡; ﹡; *; *; ) SMALL ASTERISK +FE62;FE62;FE62;002B;002B; # (﹢; ﹢; ﹢; +; +; ) SMALL PLUS SIGN +FE63;FE63;FE63;002D;002D; # (﹣; ﹣; ﹣; -; -; ) SMALL HYPHEN-MINUS +FE64;FE64;FE64;003C;003C; # (﹤; ﹤; ﹤; <; <; ) SMALL LESS-THAN SIGN +FE65;FE65;FE65;003E;003E; # (﹥; ﹥; ﹥; >; >; ) SMALL GREATER-THAN SIGN +FE66;FE66;FE66;003D;003D; # (﹦; ﹦; ﹦; =; =; ) SMALL EQUALS SIGN +FE68;FE68;FE68;005C;005C; # (﹨; ﹨; ﹨; \; \; ) SMALL REVERSE SOLIDUS +FE69;FE69;FE69;0024;0024; # (﹩; ﹩; ﹩; $; $; ) SMALL DOLLAR SIGN +FE6A;FE6A;FE6A;0025;0025; # (﹪; ﹪; ﹪; %; %; ) SMALL PERCENT SIGN +FE6B;FE6B;FE6B;0040;0040; # (﹫; ﹫; ﹫; @; @; ) SMALL COMMERCIAL AT +FE70;FE70;FE70;0020 064B;0020 064B; # (ﹰ; ﹰ; ﹰ; ◌ً; ◌ً; ) ARABIC FATHATAN ISOLATED FORM +FE71;FE71;FE71;0640 064B;0640 064B; # (ﹱ; ﹱ; ﹱ; ـ◌ً; ـ◌ً; ) ARABIC TATWEEL WITH FATHATAN ABOVE +FE72;FE72;FE72;0020 064C;0020 064C; # (ﹲ; ﹲ; ﹲ; ◌ٌ; ◌ٌ; ) ARABIC DAMMATAN ISOLATED FORM +FE74;FE74;FE74;0020 064D;0020 064D; # (ﹴ; ﹴ; ﹴ; ◌ٍ; ◌ٍ; ) ARABIC KASRATAN ISOLATED FORM +FE76;FE76;FE76;0020 064E;0020 064E; # (ﹶ; ﹶ; ﹶ; ◌َ; ◌َ; ) ARABIC FATHA ISOLATED FORM +FE77;FE77;FE77;0640 064E;0640 064E; # (ﹷ; ﹷ; ﹷ; ـ◌َ; ـ◌َ; ) ARABIC FATHA MEDIAL FORM +FE78;FE78;FE78;0020 064F;0020 064F; # (ﹸ; ﹸ; ﹸ; ◌ُ; ◌ُ; ) ARABIC DAMMA ISOLATED FORM +FE79;FE79;FE79;0640 064F;0640 064F; # (ﹹ; ﹹ; ﹹ; ـ◌ُ; ـ◌ُ; ) ARABIC DAMMA MEDIAL FORM +FE7A;FE7A;FE7A;0020 0650;0020 0650; # (ﹺ; ﹺ; ﹺ; ◌ِ; ◌ِ; ) ARABIC KASRA ISOLATED FORM +FE7B;FE7B;FE7B;0640 0650;0640 0650; # (ﹻ; ﹻ; ﹻ; ـ◌ِ; ـ◌ِ; ) ARABIC KASRA MEDIAL FORM +FE7C;FE7C;FE7C;0020 0651;0020 0651; # (ﹼ; ﹼ; ﹼ; ◌ّ; ◌ّ; ) ARABIC SHADDA ISOLATED FORM +FE7D;FE7D;FE7D;0640 0651;0640 0651; # (ﹽ; ﹽ; ﹽ; ـ◌ّ; ـ◌ّ; ) ARABIC SHADDA MEDIAL FORM +FE7E;FE7E;FE7E;0020 0652;0020 0652; # (ﹾ; ﹾ; ﹾ; ◌ْ; ◌ْ; ) ARABIC SUKUN ISOLATED FORM +FE7F;FE7F;FE7F;0640 0652;0640 0652; # (ﹿ; ﹿ; ﹿ; ـ◌ْ; ـ◌ْ; ) ARABIC SUKUN MEDIAL FORM +FE80;FE80;FE80;0621;0621; # (ﺀ; ﺀ; ﺀ; ء; ء; ) ARABIC LETTER HAMZA ISOLATED FORM +FE81;FE81;FE81;0622;0627 0653; # (ﺁ; ﺁ; ﺁ; آ; ا◌ٓ; ) ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM +FE82;FE82;FE82;0622;0627 0653; # (ﺂ; ﺂ; ﺂ; آ; ا◌ٓ; ) ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM +FE83;FE83;FE83;0623;0627 0654; # (ﺃ; ﺃ; ﺃ; أ; ا◌ٔ; ) ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM +FE84;FE84;FE84;0623;0627 0654; # (ﺄ; ﺄ; ﺄ; أ; ا◌ٔ; ) ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM +FE85;FE85;FE85;0624;0648 0654; # (ﺅ; ﺅ; ﺅ; ؤ; و◌ٔ; ) ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM +FE86;FE86;FE86;0624;0648 0654; # (ﺆ; ﺆ; ﺆ; ؤ; و◌ٔ; ) ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM +FE87;FE87;FE87;0625;0627 0655; # (ﺇ; ﺇ; ﺇ; إ; ا◌ٕ; ) ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM +FE88;FE88;FE88;0625;0627 0655; # (ﺈ; ﺈ; ﺈ; إ; ا◌ٕ; ) ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM +FE89;FE89;FE89;0626;064A 0654; # (ﺉ; ﺉ; ﺉ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM +FE8A;FE8A;FE8A;0626;064A 0654; # (ﺊ; ﺊ; ﺊ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM +FE8B;FE8B;FE8B;0626;064A 0654; # (ﺋ; ﺋ; ﺋ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM +FE8C;FE8C;FE8C;0626;064A 0654; # (ﺌ; ﺌ; ﺌ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM +FE8D;FE8D;FE8D;0627;0627; # (ﺍ; ﺍ; ﺍ; ا; ا; ) ARABIC LETTER ALEF ISOLATED FORM +FE8E;FE8E;FE8E;0627;0627; # (ﺎ; ﺎ; ﺎ; ا; ا; ) ARABIC LETTER ALEF FINAL FORM +FE8F;FE8F;FE8F;0628;0628; # (ﺏ; ﺏ; ﺏ; ب; ب; ) ARABIC LETTER BEH ISOLATED FORM +FE90;FE90;FE90;0628;0628; # (ﺐ; ﺐ; ﺐ; ب; ب; ) ARABIC LETTER BEH FINAL FORM +FE91;FE91;FE91;0628;0628; # (ﺑ; ﺑ; ﺑ; ب; ب; ) ARABIC LETTER BEH INITIAL FORM +FE92;FE92;FE92;0628;0628; # (ﺒ; ﺒ; ﺒ; ب; ب; ) ARABIC LETTER BEH MEDIAL FORM +FE93;FE93;FE93;0629;0629; # (ﺓ; ﺓ; ﺓ; ة; ة; ) ARABIC LETTER TEH MARBUTA ISOLATED FORM +FE94;FE94;FE94;0629;0629; # (ﺔ; ﺔ; ﺔ; ة; ة; ) ARABIC LETTER TEH MARBUTA FINAL FORM +FE95;FE95;FE95;062A;062A; # (ﺕ; ﺕ; ﺕ; ت; ت; ) ARABIC LETTER TEH ISOLATED FORM +FE96;FE96;FE96;062A;062A; # (ﺖ; ﺖ; ﺖ; ت; ت; ) ARABIC LETTER TEH FINAL FORM +FE97;FE97;FE97;062A;062A; # (ﺗ; ﺗ; ﺗ; ت; ت; ) ARABIC LETTER TEH INITIAL FORM +FE98;FE98;FE98;062A;062A; # (ﺘ; ﺘ; ﺘ; ت; ت; ) ARABIC LETTER TEH MEDIAL FORM +FE99;FE99;FE99;062B;062B; # (ﺙ; ﺙ; ﺙ; ث; ث; ) ARABIC LETTER THEH ISOLATED FORM +FE9A;FE9A;FE9A;062B;062B; # (ﺚ; ﺚ; ﺚ; ث; ث; ) ARABIC LETTER THEH FINAL FORM +FE9B;FE9B;FE9B;062B;062B; # (ﺛ; ﺛ; ﺛ; ث; ث; ) ARABIC LETTER THEH INITIAL FORM +FE9C;FE9C;FE9C;062B;062B; # (ﺜ; ﺜ; ﺜ; ث; ث; ) ARABIC LETTER THEH MEDIAL FORM +FE9D;FE9D;FE9D;062C;062C; # (ﺝ; ﺝ; ﺝ; ج; ج; ) ARABIC LETTER JEEM ISOLATED FORM +FE9E;FE9E;FE9E;062C;062C; # (ﺞ; ﺞ; ﺞ; ج; ج; ) ARABIC LETTER JEEM FINAL FORM +FE9F;FE9F;FE9F;062C;062C; # (ﺟ; ﺟ; ﺟ; ج; ج; ) ARABIC LETTER JEEM INITIAL FORM +FEA0;FEA0;FEA0;062C;062C; # (ﺠ; ﺠ; ﺠ; ج; ج; ) ARABIC LETTER JEEM MEDIAL FORM +FEA1;FEA1;FEA1;062D;062D; # (ﺡ; ﺡ; ﺡ; ح; ح; ) ARABIC LETTER HAH ISOLATED FORM +FEA2;FEA2;FEA2;062D;062D; # (ﺢ; ﺢ; ﺢ; ح; ح; ) ARABIC LETTER HAH FINAL FORM +FEA3;FEA3;FEA3;062D;062D; # (ﺣ; ﺣ; ﺣ; ح; ح; ) ARABIC LETTER HAH INITIAL FORM +FEA4;FEA4;FEA4;062D;062D; # (ﺤ; ﺤ; ﺤ; ح; ح; ) ARABIC LETTER HAH MEDIAL FORM +FEA5;FEA5;FEA5;062E;062E; # (ﺥ; ﺥ; ﺥ; خ; خ; ) ARABIC LETTER KHAH ISOLATED FORM +FEA6;FEA6;FEA6;062E;062E; # (ﺦ; ﺦ; ﺦ; خ; خ; ) ARABIC LETTER KHAH FINAL FORM +FEA7;FEA7;FEA7;062E;062E; # (ﺧ; ﺧ; ﺧ; خ; خ; ) ARABIC LETTER KHAH INITIAL FORM +FEA8;FEA8;FEA8;062E;062E; # (ﺨ; ﺨ; ﺨ; خ; خ; ) ARABIC LETTER KHAH MEDIAL FORM +FEA9;FEA9;FEA9;062F;062F; # (ﺩ; ﺩ; ﺩ; د; د; ) ARABIC LETTER DAL ISOLATED FORM +FEAA;FEAA;FEAA;062F;062F; # (ﺪ; ﺪ; ﺪ; د; د; ) ARABIC LETTER DAL FINAL FORM +FEAB;FEAB;FEAB;0630;0630; # (ﺫ; ﺫ; ﺫ; ذ; ذ; ) ARABIC LETTER THAL ISOLATED FORM +FEAC;FEAC;FEAC;0630;0630; # (ﺬ; ﺬ; ﺬ; ذ; ذ; ) ARABIC LETTER THAL FINAL FORM +FEAD;FEAD;FEAD;0631;0631; # (ﺭ; ﺭ; ﺭ; ر; ر; ) ARABIC LETTER REH ISOLATED FORM +FEAE;FEAE;FEAE;0631;0631; # (ﺮ; ﺮ; ﺮ; ر; ر; ) ARABIC LETTER REH FINAL FORM +FEAF;FEAF;FEAF;0632;0632; # (ﺯ; ﺯ; ﺯ; ز; ز; ) ARABIC LETTER ZAIN ISOLATED FORM +FEB0;FEB0;FEB0;0632;0632; # (ﺰ; ﺰ; ﺰ; ز; ز; ) ARABIC LETTER ZAIN FINAL FORM +FEB1;FEB1;FEB1;0633;0633; # (ﺱ; ﺱ; ﺱ; س; س; ) ARABIC LETTER SEEN ISOLATED FORM +FEB2;FEB2;FEB2;0633;0633; # (ﺲ; ﺲ; ﺲ; س; س; ) ARABIC LETTER SEEN FINAL FORM +FEB3;FEB3;FEB3;0633;0633; # (ﺳ; ﺳ; ﺳ; س; س; ) ARABIC LETTER SEEN INITIAL FORM +FEB4;FEB4;FEB4;0633;0633; # (ﺴ; ﺴ; ﺴ; س; س; ) ARABIC LETTER SEEN MEDIAL FORM +FEB5;FEB5;FEB5;0634;0634; # (ﺵ; ﺵ; ﺵ; ش; ش; ) ARABIC LETTER SHEEN ISOLATED FORM +FEB6;FEB6;FEB6;0634;0634; # (ﺶ; ﺶ; ﺶ; ش; ش; ) ARABIC LETTER SHEEN FINAL FORM +FEB7;FEB7;FEB7;0634;0634; # (ﺷ; ﺷ; ﺷ; ش; ش; ) ARABIC LETTER SHEEN INITIAL FORM +FEB8;FEB8;FEB8;0634;0634; # (ﺸ; ﺸ; ﺸ; ش; ش; ) ARABIC LETTER SHEEN MEDIAL FORM +FEB9;FEB9;FEB9;0635;0635; # (ﺹ; ﺹ; ﺹ; ص; ص; ) ARABIC LETTER SAD ISOLATED FORM +FEBA;FEBA;FEBA;0635;0635; # (ﺺ; ﺺ; ﺺ; ص; ص; ) ARABIC LETTER SAD FINAL FORM +FEBB;FEBB;FEBB;0635;0635; # (ﺻ; ﺻ; ﺻ; ص; ص; ) ARABIC LETTER SAD INITIAL FORM +FEBC;FEBC;FEBC;0635;0635; # (ﺼ; ﺼ; ﺼ; ص; ص; ) ARABIC LETTER SAD MEDIAL FORM +FEBD;FEBD;FEBD;0636;0636; # (ﺽ; ﺽ; ﺽ; ض; ض; ) ARABIC LETTER DAD ISOLATED FORM +FEBE;FEBE;FEBE;0636;0636; # (ﺾ; ﺾ; ﺾ; ض; ض; ) ARABIC LETTER DAD FINAL FORM +FEBF;FEBF;FEBF;0636;0636; # (ﺿ; ﺿ; ﺿ; ض; ض; ) ARABIC LETTER DAD INITIAL FORM +FEC0;FEC0;FEC0;0636;0636; # (ﻀ; ﻀ; ﻀ; ض; ض; ) ARABIC LETTER DAD MEDIAL FORM +FEC1;FEC1;FEC1;0637;0637; # (ﻁ; ﻁ; ﻁ; ط; ط; ) ARABIC LETTER TAH ISOLATED FORM +FEC2;FEC2;FEC2;0637;0637; # (ﻂ; ﻂ; ﻂ; ط; ط; ) ARABIC LETTER TAH FINAL FORM +FEC3;FEC3;FEC3;0637;0637; # (ﻃ; ﻃ; ﻃ; ط; ط; ) ARABIC LETTER TAH INITIAL FORM +FEC4;FEC4;FEC4;0637;0637; # (ﻄ; ﻄ; ﻄ; ط; ط; ) ARABIC LETTER TAH MEDIAL FORM +FEC5;FEC5;FEC5;0638;0638; # (ﻅ; ﻅ; ﻅ; ظ; ظ; ) ARABIC LETTER ZAH ISOLATED FORM +FEC6;FEC6;FEC6;0638;0638; # (ﻆ; ﻆ; ﻆ; ظ; ظ; ) ARABIC LETTER ZAH FINAL FORM +FEC7;FEC7;FEC7;0638;0638; # (ﻇ; ﻇ; ﻇ; ظ; ظ; ) ARABIC LETTER ZAH INITIAL FORM +FEC8;FEC8;FEC8;0638;0638; # (ﻈ; ﻈ; ﻈ; ظ; ظ; ) ARABIC LETTER ZAH MEDIAL FORM +FEC9;FEC9;FEC9;0639;0639; # (ﻉ; ﻉ; ﻉ; ع; ع; ) ARABIC LETTER AIN ISOLATED FORM +FECA;FECA;FECA;0639;0639; # (ﻊ; ﻊ; ﻊ; ع; ع; ) ARABIC LETTER AIN FINAL FORM +FECB;FECB;FECB;0639;0639; # (ﻋ; ﻋ; ﻋ; ع; ع; ) ARABIC LETTER AIN INITIAL FORM +FECC;FECC;FECC;0639;0639; # (ﻌ; ﻌ; ﻌ; ع; ع; ) ARABIC LETTER AIN MEDIAL FORM +FECD;FECD;FECD;063A;063A; # (ﻍ; ﻍ; ﻍ; غ; غ; ) ARABIC LETTER GHAIN ISOLATED FORM +FECE;FECE;FECE;063A;063A; # (ﻎ; ﻎ; ﻎ; غ; غ; ) ARABIC LETTER GHAIN FINAL FORM +FECF;FECF;FECF;063A;063A; # (ﻏ; ﻏ; ﻏ; غ; غ; ) ARABIC LETTER GHAIN INITIAL FORM +FED0;FED0;FED0;063A;063A; # (ﻐ; ﻐ; ﻐ; غ; غ; ) ARABIC LETTER GHAIN MEDIAL FORM +FED1;FED1;FED1;0641;0641; # (ﻑ; ﻑ; ﻑ; ف; ف; ) ARABIC LETTER FEH ISOLATED FORM +FED2;FED2;FED2;0641;0641; # (ﻒ; ﻒ; ﻒ; ف; ف; ) ARABIC LETTER FEH FINAL FORM +FED3;FED3;FED3;0641;0641; # (ﻓ; ﻓ; ﻓ; ف; ف; ) ARABIC LETTER FEH INITIAL FORM +FED4;FED4;FED4;0641;0641; # (ﻔ; ﻔ; ﻔ; ف; ف; ) ARABIC LETTER FEH MEDIAL FORM +FED5;FED5;FED5;0642;0642; # (ﻕ; ﻕ; ﻕ; ق; ق; ) ARABIC LETTER QAF ISOLATED FORM +FED6;FED6;FED6;0642;0642; # (ﻖ; ﻖ; ﻖ; ق; ق; ) ARABIC LETTER QAF FINAL FORM +FED7;FED7;FED7;0642;0642; # (ﻗ; ﻗ; ﻗ; ق; ق; ) ARABIC LETTER QAF INITIAL FORM +FED8;FED8;FED8;0642;0642; # (ﻘ; ﻘ; ﻘ; ق; ق; ) ARABIC LETTER QAF MEDIAL FORM +FED9;FED9;FED9;0643;0643; # (ﻙ; ﻙ; ﻙ; ك; ك; ) ARABIC LETTER KAF ISOLATED FORM +FEDA;FEDA;FEDA;0643;0643; # (ﻚ; ﻚ; ﻚ; ك; ك; ) ARABIC LETTER KAF FINAL FORM +FEDB;FEDB;FEDB;0643;0643; # (ﻛ; ﻛ; ﻛ; ك; ك; ) ARABIC LETTER KAF INITIAL FORM +FEDC;FEDC;FEDC;0643;0643; # (ﻜ; ﻜ; ﻜ; ك; ك; ) ARABIC LETTER KAF MEDIAL FORM +FEDD;FEDD;FEDD;0644;0644; # (ﻝ; ﻝ; ﻝ; ل; ل; ) ARABIC LETTER LAM ISOLATED FORM +FEDE;FEDE;FEDE;0644;0644; # (ﻞ; ﻞ; ﻞ; ل; ل; ) ARABIC LETTER LAM FINAL FORM +FEDF;FEDF;FEDF;0644;0644; # (ﻟ; ﻟ; ﻟ; ل; ل; ) ARABIC LETTER LAM INITIAL FORM +FEE0;FEE0;FEE0;0644;0644; # (ﻠ; ﻠ; ﻠ; ل; ل; ) ARABIC LETTER LAM MEDIAL FORM +FEE1;FEE1;FEE1;0645;0645; # (ﻡ; ﻡ; ﻡ; م; م; ) ARABIC LETTER MEEM ISOLATED FORM +FEE2;FEE2;FEE2;0645;0645; # (ﻢ; ﻢ; ﻢ; م; م; ) ARABIC LETTER MEEM FINAL FORM +FEE3;FEE3;FEE3;0645;0645; # (ﻣ; ﻣ; ﻣ; م; م; ) ARABIC LETTER MEEM INITIAL FORM +FEE4;FEE4;FEE4;0645;0645; # (ﻤ; ﻤ; ﻤ; م; م; ) ARABIC LETTER MEEM MEDIAL FORM +FEE5;FEE5;FEE5;0646;0646; # (ﻥ; ﻥ; ﻥ; ن; ن; ) ARABIC LETTER NOON ISOLATED FORM +FEE6;FEE6;FEE6;0646;0646; # (ﻦ; ﻦ; ﻦ; ن; ن; ) ARABIC LETTER NOON FINAL FORM +FEE7;FEE7;FEE7;0646;0646; # (ﻧ; ﻧ; ﻧ; ن; ن; ) ARABIC LETTER NOON INITIAL FORM +FEE8;FEE8;FEE8;0646;0646; # (ﻨ; ﻨ; ﻨ; ن; ن; ) ARABIC LETTER NOON MEDIAL FORM +FEE9;FEE9;FEE9;0647;0647; # (ﻩ; ﻩ; ﻩ; ه; ه; ) ARABIC LETTER HEH ISOLATED FORM +FEEA;FEEA;FEEA;0647;0647; # (ﻪ; ﻪ; ﻪ; ه; ه; ) ARABIC LETTER HEH FINAL FORM +FEEB;FEEB;FEEB;0647;0647; # (ﻫ; ﻫ; ﻫ; ه; ه; ) ARABIC LETTER HEH INITIAL FORM +FEEC;FEEC;FEEC;0647;0647; # (ﻬ; ﻬ; ﻬ; ه; ه; ) ARABIC LETTER HEH MEDIAL FORM +FEED;FEED;FEED;0648;0648; # (ﻭ; ﻭ; ﻭ; و; و; ) ARABIC LETTER WAW ISOLATED FORM +FEEE;FEEE;FEEE;0648;0648; # (ﻮ; ﻮ; ﻮ; و; و; ) ARABIC LETTER WAW FINAL FORM +FEEF;FEEF;FEEF;0649;0649; # (ﻯ; ﻯ; ﻯ; ى; ى; ) ARABIC LETTER ALEF MAKSURA ISOLATED FORM +FEF0;FEF0;FEF0;0649;0649; # (ﻰ; ﻰ; ﻰ; ى; ى; ) ARABIC LETTER ALEF MAKSURA FINAL FORM +FEF1;FEF1;FEF1;064A;064A; # (ﻱ; ﻱ; ﻱ; ي; ي; ) ARABIC LETTER YEH ISOLATED FORM +FEF2;FEF2;FEF2;064A;064A; # (ﻲ; ﻲ; ﻲ; ي; ي; ) ARABIC LETTER YEH FINAL FORM +FEF3;FEF3;FEF3;064A;064A; # (ﻳ; ﻳ; ﻳ; ي; ي; ) ARABIC LETTER YEH INITIAL FORM +FEF4;FEF4;FEF4;064A;064A; # (ﻴ; ﻴ; ﻴ; ي; ي; ) ARABIC LETTER YEH MEDIAL FORM +FEF5;FEF5;FEF5;0644 0622;0644 0627 0653; # (ﻵ; ﻵ; ﻵ; لآ; لا◌ٓ; ) ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM +FEF6;FEF6;FEF6;0644 0622;0644 0627 0653; # (ﻶ; ﻶ; ﻶ; لآ; لا◌ٓ; ) ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM +FEF7;FEF7;FEF7;0644 0623;0644 0627 0654; # (ﻷ; ﻷ; ﻷ; لأ; لا◌ٔ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM +FEF8;FEF8;FEF8;0644 0623;0644 0627 0654; # (ﻸ; ﻸ; ﻸ; لأ; لا◌ٔ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM +FEF9;FEF9;FEF9;0644 0625;0644 0627 0655; # (ﻹ; ﻹ; ﻹ; لإ; لا◌ٕ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM +FEFA;FEFA;FEFA;0644 0625;0644 0627 0655; # (ﻺ; ﻺ; ﻺ; لإ; لا◌ٕ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM +FEFB;FEFB;FEFB;0644 0627;0644 0627; # (ﻻ; ﻻ; ﻻ; لا; لا; ) ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM +FEFC;FEFC;FEFC;0644 0627;0644 0627; # (ﻼ; ﻼ; ﻼ; لا; لا; ) ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FF01;FF01;FF01;0021;0021; # (!; !; !; !; !; ) FULLWIDTH EXCLAMATION MARK +FF02;FF02;FF02;0022;0022; # ("; "; "; "; "; ) FULLWIDTH QUOTATION MARK +FF03;FF03;FF03;0023;0023; # (#; #; #; #; #; ) FULLWIDTH NUMBER SIGN +FF04;FF04;FF04;0024;0024; # ($; $; $; $; $; ) FULLWIDTH DOLLAR SIGN +FF05;FF05;FF05;0025;0025; # (%; %; %; %; %; ) FULLWIDTH PERCENT SIGN +FF06;FF06;FF06;0026;0026; # (&; &; &; &; &; ) FULLWIDTH AMPERSAND +FF07;FF07;FF07;0027;0027; # ('; '; '; '; '; ) FULLWIDTH APOSTROPHE +FF08;FF08;FF08;0028;0028; # ((; (; (; (; (; ) FULLWIDTH LEFT PARENTHESIS +FF09;FF09;FF09;0029;0029; # (); ); ); ); ); ) FULLWIDTH RIGHT PARENTHESIS +FF0A;FF0A;FF0A;002A;002A; # (*; *; *; *; *; ) FULLWIDTH ASTERISK +FF0B;FF0B;FF0B;002B;002B; # (+; +; +; +; +; ) FULLWIDTH PLUS SIGN +FF0C;FF0C;FF0C;002C;002C; # (,; ,; ,; ,; ,; ) FULLWIDTH COMMA +FF0D;FF0D;FF0D;002D;002D; # (-; -; -; -; -; ) FULLWIDTH HYPHEN-MINUS +FF0E;FF0E;FF0E;002E;002E; # (.; .; .; .; .; ) FULLWIDTH FULL STOP +FF0F;FF0F;FF0F;002F;002F; # (/; /; /; /; /; ) FULLWIDTH SOLIDUS +FF10;FF10;FF10;0030;0030; # (0; 0; 0; 0; 0; ) FULLWIDTH DIGIT ZERO +FF11;FF11;FF11;0031;0031; # (1; 1; 1; 1; 1; ) FULLWIDTH DIGIT ONE +FF12;FF12;FF12;0032;0032; # (2; 2; 2; 2; 2; ) FULLWIDTH DIGIT TWO +FF13;FF13;FF13;0033;0033; # (3; 3; 3; 3; 3; ) FULLWIDTH DIGIT THREE +FF14;FF14;FF14;0034;0034; # (4; 4; 4; 4; 4; ) FULLWIDTH DIGIT FOUR +FF15;FF15;FF15;0035;0035; # (5; 5; 5; 5; 5; ) FULLWIDTH DIGIT FIVE +FF16;FF16;FF16;0036;0036; # (6; 6; 6; 6; 6; ) FULLWIDTH DIGIT SIX +FF17;FF17;FF17;0037;0037; # (7; 7; 7; 7; 7; ) FULLWIDTH DIGIT SEVEN +FF18;FF18;FF18;0038;0038; # (8; 8; 8; 8; 8; ) FULLWIDTH DIGIT EIGHT +FF19;FF19;FF19;0039;0039; # (9; 9; 9; 9; 9; ) FULLWIDTH DIGIT NINE +FF1A;FF1A;FF1A;003A;003A; # (:; :; :; :; :; ) FULLWIDTH COLON +FF1B;FF1B;FF1B;003B;003B; # (;; ;; ;; ;; ;; ) FULLWIDTH SEMICOLON +FF1C;FF1C;FF1C;003C;003C; # (<; <; <; <; <; ) FULLWIDTH LESS-THAN SIGN +FF1D;FF1D;FF1D;003D;003D; # (=; =; =; =; =; ) FULLWIDTH EQUALS SIGN +FF1E;FF1E;FF1E;003E;003E; # (>; >; >; >; >; ) FULLWIDTH GREATER-THAN SIGN +FF1F;FF1F;FF1F;003F;003F; # (?; ?; ?; ?; ?; ) FULLWIDTH QUESTION MARK +FF20;FF20;FF20;0040;0040; # (@; @; @; @; @; ) FULLWIDTH COMMERCIAL AT +FF21;FF21;FF21;0041;0041; # (A; A; A; A; A; ) FULLWIDTH LATIN CAPITAL LETTER A +FF22;FF22;FF22;0042;0042; # (B; B; B; B; B; ) FULLWIDTH LATIN CAPITAL LETTER B +FF23;FF23;FF23;0043;0043; # (C; C; C; C; C; ) FULLWIDTH LATIN CAPITAL LETTER C +FF24;FF24;FF24;0044;0044; # (D; D; D; D; D; ) FULLWIDTH LATIN CAPITAL LETTER D +FF25;FF25;FF25;0045;0045; # (E; E; E; E; E; ) FULLWIDTH LATIN CAPITAL LETTER E +FF26;FF26;FF26;0046;0046; # (F; F; F; F; F; ) FULLWIDTH LATIN CAPITAL LETTER F +FF27;FF27;FF27;0047;0047; # (G; G; G; G; G; ) FULLWIDTH LATIN CAPITAL LETTER G +FF28;FF28;FF28;0048;0048; # (H; H; H; H; H; ) FULLWIDTH LATIN CAPITAL LETTER H +FF29;FF29;FF29;0049;0049; # (I; I; I; I; I; ) FULLWIDTH LATIN CAPITAL LETTER I +FF2A;FF2A;FF2A;004A;004A; # (J; J; J; J; J; ) FULLWIDTH LATIN CAPITAL LETTER J +FF2B;FF2B;FF2B;004B;004B; # (K; K; K; K; K; ) FULLWIDTH LATIN CAPITAL LETTER K +FF2C;FF2C;FF2C;004C;004C; # (L; L; L; L; L; ) FULLWIDTH LATIN CAPITAL LETTER L +FF2D;FF2D;FF2D;004D;004D; # (M; M; M; M; M; ) FULLWIDTH LATIN CAPITAL LETTER M +FF2E;FF2E;FF2E;004E;004E; # (N; N; N; N; N; ) FULLWIDTH LATIN CAPITAL LETTER N +FF2F;FF2F;FF2F;004F;004F; # (O; O; O; O; O; ) FULLWIDTH LATIN CAPITAL LETTER O +FF30;FF30;FF30;0050;0050; # (P; P; P; P; P; ) FULLWIDTH LATIN CAPITAL LETTER P +FF31;FF31;FF31;0051;0051; # (Q; Q; Q; Q; Q; ) FULLWIDTH LATIN CAPITAL LETTER Q +FF32;FF32;FF32;0052;0052; # (R; R; R; R; R; ) FULLWIDTH LATIN CAPITAL LETTER R +FF33;FF33;FF33;0053;0053; # (S; S; S; S; S; ) FULLWIDTH LATIN CAPITAL LETTER S +FF34;FF34;FF34;0054;0054; # (T; T; T; T; T; ) FULLWIDTH LATIN CAPITAL LETTER T +FF35;FF35;FF35;0055;0055; # (U; U; U; U; U; ) FULLWIDTH LATIN CAPITAL LETTER U +FF36;FF36;FF36;0056;0056; # (V; V; V; V; V; ) FULLWIDTH LATIN CAPITAL LETTER V +FF37;FF37;FF37;0057;0057; # (W; W; W; W; W; ) FULLWIDTH LATIN CAPITAL LETTER W +FF38;FF38;FF38;0058;0058; # (X; X; X; X; X; ) FULLWIDTH LATIN CAPITAL LETTER X +FF39;FF39;FF39;0059;0059; # (Y; Y; Y; Y; Y; ) FULLWIDTH LATIN CAPITAL LETTER Y +FF3A;FF3A;FF3A;005A;005A; # (Z; Z; Z; Z; Z; ) FULLWIDTH LATIN CAPITAL LETTER Z +FF3B;FF3B;FF3B;005B;005B; # ([; [; [; [; [; ) FULLWIDTH LEFT SQUARE BRACKET +FF3C;FF3C;FF3C;005C;005C; # (\; \; \; \; \; ) FULLWIDTH REVERSE SOLIDUS +FF3D;FF3D;FF3D;005D;005D; # (]; ]; ]; ]; ]; ) FULLWIDTH RIGHT SQUARE BRACKET +FF3E;FF3E;FF3E;005E;005E; # (^; ^; ^; ^; ^; ) FULLWIDTH CIRCUMFLEX ACCENT +FF3F;FF3F;FF3F;005F;005F; # (_; _; _; _; _; ) FULLWIDTH LOW LINE +FF40;FF40;FF40;0060;0060; # (`; `; `; `; `; ) FULLWIDTH GRAVE ACCENT +FF41;FF41;FF41;0061;0061; # (a; a; a; a; a; ) FULLWIDTH LATIN SMALL LETTER A +FF42;FF42;FF42;0062;0062; # (b; b; b; b; b; ) FULLWIDTH LATIN SMALL LETTER B +FF43;FF43;FF43;0063;0063; # (c; c; c; c; c; ) FULLWIDTH LATIN SMALL LETTER C +FF44;FF44;FF44;0064;0064; # (d; d; d; d; d; ) FULLWIDTH LATIN SMALL LETTER D +FF45;FF45;FF45;0065;0065; # (e; e; e; e; e; ) FULLWIDTH LATIN SMALL LETTER E +FF46;FF46;FF46;0066;0066; # (f; f; f; f; f; ) FULLWIDTH LATIN SMALL LETTER F +FF47;FF47;FF47;0067;0067; # (g; g; g; g; g; ) FULLWIDTH LATIN SMALL LETTER G +FF48;FF48;FF48;0068;0068; # (h; h; h; h; h; ) FULLWIDTH LATIN SMALL LETTER H +FF49;FF49;FF49;0069;0069; # (i; i; i; i; i; ) FULLWIDTH LATIN SMALL LETTER I +FF4A;FF4A;FF4A;006A;006A; # (j; j; j; j; j; ) FULLWIDTH LATIN SMALL LETTER J +FF4B;FF4B;FF4B;006B;006B; # (k; k; k; k; k; ) FULLWIDTH LATIN SMALL LETTER K +FF4C;FF4C;FF4C;006C;006C; # (l; l; l; l; l; ) FULLWIDTH LATIN SMALL LETTER L +FF4D;FF4D;FF4D;006D;006D; # (m; m; m; m; m; ) FULLWIDTH LATIN SMALL LETTER M +FF4E;FF4E;FF4E;006E;006E; # (n; n; n; n; n; ) FULLWIDTH LATIN SMALL LETTER N +FF4F;FF4F;FF4F;006F;006F; # (o; o; o; o; o; ) FULLWIDTH LATIN SMALL LETTER O +FF50;FF50;FF50;0070;0070; # (p; p; p; p; p; ) FULLWIDTH LATIN SMALL LETTER P +FF51;FF51;FF51;0071;0071; # (q; q; q; q; q; ) FULLWIDTH LATIN SMALL LETTER Q +FF52;FF52;FF52;0072;0072; # (r; r; r; r; r; ) FULLWIDTH LATIN SMALL LETTER R +FF53;FF53;FF53;0073;0073; # (s; s; s; s; s; ) FULLWIDTH LATIN SMALL LETTER S +FF54;FF54;FF54;0074;0074; # (t; t; t; t; t; ) FULLWIDTH LATIN SMALL LETTER T +FF55;FF55;FF55;0075;0075; # (u; u; u; u; u; ) FULLWIDTH LATIN SMALL LETTER U +FF56;FF56;FF56;0076;0076; # (v; v; v; v; v; ) FULLWIDTH LATIN SMALL LETTER V +FF57;FF57;FF57;0077;0077; # (w; w; w; w; w; ) FULLWIDTH LATIN SMALL LETTER W +FF58;FF58;FF58;0078;0078; # (x; x; x; x; x; ) FULLWIDTH LATIN SMALL LETTER X +FF59;FF59;FF59;0079;0079; # (y; y; y; y; y; ) FULLWIDTH LATIN SMALL LETTER Y +FF5A;FF5A;FF5A;007A;007A; # (z; z; z; z; z; ) FULLWIDTH LATIN SMALL LETTER Z +FF5B;FF5B;FF5B;007B;007B; # ({; {; {; {; {; ) FULLWIDTH LEFT CURLY BRACKET +FF5C;FF5C;FF5C;007C;007C; # (|; |; |; |; |; ) FULLWIDTH VERTICAL LINE +FF5D;FF5D;FF5D;007D;007D; # (}; }; }; }; }; ) FULLWIDTH RIGHT CURLY BRACKET +FF5E;FF5E;FF5E;007E;007E; # (~; ~; ~; ~; ~; ) FULLWIDTH TILDE +FF5F;FF5F;FF5F;2985;2985; # (⦅; ⦅; ⦅; ⦅; ⦅; ) FULLWIDTH LEFT WHITE PARENTHESIS +FF60;FF60;FF60;2986;2986; # (⦆; ⦆; ⦆; ⦆; ⦆; ) FULLWIDTH RIGHT WHITE PARENTHESIS +FF61;FF61;FF61;3002;3002; # (。; 。; 。; 。; 。; ) HALFWIDTH IDEOGRAPHIC FULL STOP +FF62;FF62;FF62;300C;300C; # (「; 「; 「; 「; 「; ) HALFWIDTH LEFT CORNER BRACKET +FF63;FF63;FF63;300D;300D; # (」; 」; 」; 」; 」; ) HALFWIDTH RIGHT CORNER BRACKET +FF64;FF64;FF64;3001;3001; # (、; 、; 、; 、; 、; ) HALFWIDTH IDEOGRAPHIC COMMA +FF65;FF65;FF65;30FB;30FB; # (・; ・; ・; ・; ・; ) HALFWIDTH KATAKANA MIDDLE DOT +FF66;FF66;FF66;30F2;30F2; # (ヲ; ヲ; ヲ; ヲ; ヲ; ) HALFWIDTH KATAKANA LETTER WO +FF67;FF67;FF67;30A1;30A1; # (ァ; ァ; ァ; ァ; ァ; ) HALFWIDTH KATAKANA LETTER SMALL A +FF68;FF68;FF68;30A3;30A3; # (ィ; ィ; ィ; ィ; ィ; ) HALFWIDTH KATAKANA LETTER SMALL I +FF69;FF69;FF69;30A5;30A5; # (ゥ; ゥ; ゥ; ゥ; ゥ; ) HALFWIDTH KATAKANA LETTER SMALL U +FF6A;FF6A;FF6A;30A7;30A7; # (ェ; ェ; ェ; ェ; ェ; ) HALFWIDTH KATAKANA LETTER SMALL E +FF6B;FF6B;FF6B;30A9;30A9; # (ォ; ォ; ォ; ォ; ォ; ) HALFWIDTH KATAKANA LETTER SMALL O +FF6C;FF6C;FF6C;30E3;30E3; # (ャ; ャ; ャ; ャ; ャ; ) HALFWIDTH KATAKANA LETTER SMALL YA +FF6D;FF6D;FF6D;30E5;30E5; # (ュ; ュ; ュ; ュ; ュ; ) HALFWIDTH KATAKANA LETTER SMALL YU +FF6E;FF6E;FF6E;30E7;30E7; # (ョ; ョ; ョ; ョ; ョ; ) HALFWIDTH KATAKANA LETTER SMALL YO +FF6F;FF6F;FF6F;30C3;30C3; # (ッ; ッ; ッ; ッ; ッ; ) HALFWIDTH KATAKANA LETTER SMALL TU +FF70;FF70;FF70;30FC;30FC; # (ー; ー; ー; ー; ー; ) HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF71;FF71;FF71;30A2;30A2; # (ア; ア; ア; ア; ア; ) HALFWIDTH KATAKANA LETTER A +FF72;FF72;FF72;30A4;30A4; # (イ; イ; イ; イ; イ; ) HALFWIDTH KATAKANA LETTER I +FF73;FF73;FF73;30A6;30A6; # (ウ; ウ; ウ; ウ; ウ; ) HALFWIDTH KATAKANA LETTER U +FF74;FF74;FF74;30A8;30A8; # (エ; エ; エ; エ; エ; ) HALFWIDTH KATAKANA LETTER E +FF75;FF75;FF75;30AA;30AA; # (オ; オ; オ; オ; オ; ) HALFWIDTH KATAKANA LETTER O +FF76;FF76;FF76;30AB;30AB; # (カ; カ; カ; カ; カ; ) HALFWIDTH KATAKANA LETTER KA +FF77;FF77;FF77;30AD;30AD; # (キ; キ; キ; キ; キ; ) HALFWIDTH KATAKANA LETTER KI +FF78;FF78;FF78;30AF;30AF; # (ク; ク; ク; ク; ク; ) HALFWIDTH KATAKANA LETTER KU +FF79;FF79;FF79;30B1;30B1; # (ケ; ケ; ケ; ケ; ケ; ) HALFWIDTH KATAKANA LETTER KE +FF7A;FF7A;FF7A;30B3;30B3; # (コ; コ; コ; コ; コ; ) HALFWIDTH KATAKANA LETTER KO +FF7B;FF7B;FF7B;30B5;30B5; # (サ; サ; サ; サ; サ; ) HALFWIDTH KATAKANA LETTER SA +FF7C;FF7C;FF7C;30B7;30B7; # (シ; シ; シ; シ; シ; ) HALFWIDTH KATAKANA LETTER SI +FF7D;FF7D;FF7D;30B9;30B9; # (ス; ス; ス; ス; ス; ) HALFWIDTH KATAKANA LETTER SU +FF7E;FF7E;FF7E;30BB;30BB; # (セ; セ; セ; セ; セ; ) HALFWIDTH KATAKANA LETTER SE +FF7F;FF7F;FF7F;30BD;30BD; # (ソ; ソ; ソ; ソ; ソ; ) HALFWIDTH KATAKANA LETTER SO +FF80;FF80;FF80;30BF;30BF; # (タ; タ; タ; タ; タ; ) HALFWIDTH KATAKANA LETTER TA +FF81;FF81;FF81;30C1;30C1; # (チ; チ; チ; チ; チ; ) HALFWIDTH KATAKANA LETTER TI +FF82;FF82;FF82;30C4;30C4; # (ツ; ツ; ツ; ツ; ツ; ) HALFWIDTH KATAKANA LETTER TU +FF83;FF83;FF83;30C6;30C6; # (テ; テ; テ; テ; テ; ) HALFWIDTH KATAKANA LETTER TE +FF84;FF84;FF84;30C8;30C8; # (ト; ト; ト; ト; ト; ) HALFWIDTH KATAKANA LETTER TO +FF85;FF85;FF85;30CA;30CA; # (ナ; ナ; ナ; ナ; ナ; ) HALFWIDTH KATAKANA LETTER NA +FF86;FF86;FF86;30CB;30CB; # (ニ; ニ; ニ; ニ; ニ; ) HALFWIDTH KATAKANA LETTER NI +FF87;FF87;FF87;30CC;30CC; # (ヌ; ヌ; ヌ; ヌ; ヌ; ) HALFWIDTH KATAKANA LETTER NU +FF88;FF88;FF88;30CD;30CD; # (ネ; ネ; ネ; ネ; ネ; ) HALFWIDTH KATAKANA LETTER NE +FF89;FF89;FF89;30CE;30CE; # (ノ; ノ; ノ; ノ; ノ; ) HALFWIDTH KATAKANA LETTER NO +FF8A;FF8A;FF8A;30CF;30CF; # (ハ; ハ; ハ; ハ; ハ; ) HALFWIDTH KATAKANA LETTER HA +FF8B;FF8B;FF8B;30D2;30D2; # (ヒ; ヒ; ヒ; ヒ; ヒ; ) HALFWIDTH KATAKANA LETTER HI +FF8C;FF8C;FF8C;30D5;30D5; # (フ; フ; フ; フ; フ; ) HALFWIDTH KATAKANA LETTER HU +FF8D;FF8D;FF8D;30D8;30D8; # (ヘ; ヘ; ヘ; ヘ; ヘ; ) HALFWIDTH KATAKANA LETTER HE +FF8E;FF8E;FF8E;30DB;30DB; # (ホ; ホ; ホ; ホ; ホ; ) HALFWIDTH KATAKANA LETTER HO +FF8F;FF8F;FF8F;30DE;30DE; # (マ; マ; マ; マ; マ; ) HALFWIDTH KATAKANA LETTER MA +FF90;FF90;FF90;30DF;30DF; # (ミ; ミ; ミ; ミ; ミ; ) HALFWIDTH KATAKANA LETTER MI +FF91;FF91;FF91;30E0;30E0; # (ム; ム; ム; ム; ム; ) HALFWIDTH KATAKANA LETTER MU +FF92;FF92;FF92;30E1;30E1; # (メ; メ; メ; メ; メ; ) HALFWIDTH KATAKANA LETTER ME +FF93;FF93;FF93;30E2;30E2; # (モ; モ; モ; モ; モ; ) HALFWIDTH KATAKANA LETTER MO +FF94;FF94;FF94;30E4;30E4; # (ヤ; ヤ; ヤ; ヤ; ヤ; ) HALFWIDTH KATAKANA LETTER YA +FF95;FF95;FF95;30E6;30E6; # (ユ; ユ; ユ; ユ; ユ; ) HALFWIDTH KATAKANA LETTER YU +FF96;FF96;FF96;30E8;30E8; # (ヨ; ヨ; ヨ; ヨ; ヨ; ) HALFWIDTH KATAKANA LETTER YO +FF97;FF97;FF97;30E9;30E9; # (ラ; ラ; ラ; ラ; ラ; ) HALFWIDTH KATAKANA LETTER RA +FF98;FF98;FF98;30EA;30EA; # (リ; リ; リ; リ; リ; ) HALFWIDTH KATAKANA LETTER RI +FF99;FF99;FF99;30EB;30EB; # (ル; ル; ル; ル; ル; ) HALFWIDTH KATAKANA LETTER RU +FF9A;FF9A;FF9A;30EC;30EC; # (レ; レ; レ; レ; レ; ) HALFWIDTH KATAKANA LETTER RE +FF9B;FF9B;FF9B;30ED;30ED; # (ロ; ロ; ロ; ロ; ロ; ) HALFWIDTH KATAKANA LETTER RO +FF9C;FF9C;FF9C;30EF;30EF; # (ワ; ワ; ワ; ワ; ワ; ) HALFWIDTH KATAKANA LETTER WA +FF9D;FF9D;FF9D;30F3;30F3; # (ン; ン; ン; ン; ン; ) HALFWIDTH KATAKANA LETTER N +FF9E;FF9E;FF9E;3099;3099; # (゙; ゙; ゙; ◌゙; ◌゙; ) HALFWIDTH KATAKANA VOICED SOUND MARK +FF9F;FF9F;FF9F;309A;309A; # (゚; ゚; ゚; ◌゚; ◌゚; ) HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +FFA0;FFA0;FFA0;1160;1160; # (ᅠ; ᅠ; ᅠ; ᅠ; ᅠ; ) HALFWIDTH HANGUL FILLER +FFA1;FFA1;FFA1;1100;1100; # (ᄀ; ᄀ; ᄀ; ᄀ; ᄀ; ) HALFWIDTH HANGUL LETTER KIYEOK +FFA2;FFA2;FFA2;1101;1101; # (ᄁ; ᄁ; ᄁ; ᄁ; ᄁ; ) HALFWIDTH HANGUL LETTER SSANGKIYEOK +FFA3;FFA3;FFA3;11AA;11AA; # (ᆪ; ᆪ; ᆪ; ᆪ; ᆪ; ) HALFWIDTH HANGUL LETTER KIYEOK-SIOS +FFA4;FFA4;FFA4;1102;1102; # (ᄂ; ᄂ; ᄂ; ᄂ; ᄂ; ) HALFWIDTH HANGUL LETTER NIEUN +FFA5;FFA5;FFA5;11AC;11AC; # (ᆬ; ᆬ; ᆬ; ᆬ; ᆬ; ) HALFWIDTH HANGUL LETTER NIEUN-CIEUC +FFA6;FFA6;FFA6;11AD;11AD; # (ᆭ; ᆭ; ᆭ; ᆭ; ᆭ; ) HALFWIDTH HANGUL LETTER NIEUN-HIEUH +FFA7;FFA7;FFA7;1103;1103; # (ᄃ; ᄃ; ᄃ; ᄃ; ᄃ; ) HALFWIDTH HANGUL LETTER TIKEUT +FFA8;FFA8;FFA8;1104;1104; # (ᄄ; ᄄ; ᄄ; ᄄ; ᄄ; ) HALFWIDTH HANGUL LETTER SSANGTIKEUT +FFA9;FFA9;FFA9;1105;1105; # (ᄅ; ᄅ; ᄅ; ᄅ; ᄅ; ) HALFWIDTH HANGUL LETTER RIEUL +FFAA;FFAA;FFAA;11B0;11B0; # (ᆰ; ᆰ; ᆰ; ᆰ; ᆰ; ) HALFWIDTH HANGUL LETTER RIEUL-KIYEOK +FFAB;FFAB;FFAB;11B1;11B1; # (ᆱ; ᆱ; ᆱ; ᆱ; ᆱ; ) HALFWIDTH HANGUL LETTER RIEUL-MIEUM +FFAC;FFAC;FFAC;11B2;11B2; # (ᆲ; ᆲ; ᆲ; ᆲ; ᆲ; ) HALFWIDTH HANGUL LETTER RIEUL-PIEUP +FFAD;FFAD;FFAD;11B3;11B3; # (ᆳ; ᆳ; ᆳ; ᆳ; ᆳ; ) HALFWIDTH HANGUL LETTER RIEUL-SIOS +FFAE;FFAE;FFAE;11B4;11B4; # (ᆴ; ᆴ; ᆴ; ᆴ; ᆴ; ) HALFWIDTH HANGUL LETTER RIEUL-THIEUTH +FFAF;FFAF;FFAF;11B5;11B5; # (ᆵ; ᆵ; ᆵ; ᆵ; ᆵ; ) HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH +FFB0;FFB0;FFB0;111A;111A; # (ᄚ; ᄚ; ᄚ; ᄚ; ᄚ; ) HALFWIDTH HANGUL LETTER RIEUL-HIEUH +FFB1;FFB1;FFB1;1106;1106; # (ᄆ; ᄆ; ᄆ; ᄆ; ᄆ; ) HALFWIDTH HANGUL LETTER MIEUM +FFB2;FFB2;FFB2;1107;1107; # (ᄇ; ᄇ; ᄇ; ᄇ; ᄇ; ) HALFWIDTH HANGUL LETTER PIEUP +FFB3;FFB3;FFB3;1108;1108; # (ᄈ; ᄈ; ᄈ; ᄈ; ᄈ; ) HALFWIDTH HANGUL LETTER SSANGPIEUP +FFB4;FFB4;FFB4;1121;1121; # (ᄡ; ᄡ; ᄡ; ᄡ; ᄡ; ) HALFWIDTH HANGUL LETTER PIEUP-SIOS +FFB5;FFB5;FFB5;1109;1109; # (ᄉ; ᄉ; ᄉ; ᄉ; ᄉ; ) HALFWIDTH HANGUL LETTER SIOS +FFB6;FFB6;FFB6;110A;110A; # (ᄊ; ᄊ; ᄊ; ᄊ; ᄊ; ) HALFWIDTH HANGUL LETTER SSANGSIOS +FFB7;FFB7;FFB7;110B;110B; # (ᄋ; ᄋ; ᄋ; ᄋ; ᄋ; ) HALFWIDTH HANGUL LETTER IEUNG +FFB8;FFB8;FFB8;110C;110C; # (ᄌ; ᄌ; ᄌ; ᄌ; ᄌ; ) HALFWIDTH HANGUL LETTER CIEUC +FFB9;FFB9;FFB9;110D;110D; # (ᄍ; ᄍ; ᄍ; ᄍ; ᄍ; ) HALFWIDTH HANGUL LETTER SSANGCIEUC +FFBA;FFBA;FFBA;110E;110E; # (ᄎ; ᄎ; ᄎ; ᄎ; ᄎ; ) HALFWIDTH HANGUL LETTER CHIEUCH +FFBB;FFBB;FFBB;110F;110F; # (ᄏ; ᄏ; ᄏ; ᄏ; ᄏ; ) HALFWIDTH HANGUL LETTER KHIEUKH +FFBC;FFBC;FFBC;1110;1110; # (ᄐ; ᄐ; ᄐ; ᄐ; ᄐ; ) HALFWIDTH HANGUL LETTER THIEUTH +FFBD;FFBD;FFBD;1111;1111; # (ᄑ; ᄑ; ᄑ; ᄑ; ᄑ; ) HALFWIDTH HANGUL LETTER PHIEUPH +FFBE;FFBE;FFBE;1112;1112; # (ᄒ; ᄒ; ᄒ; ᄒ; ᄒ; ) HALFWIDTH HANGUL LETTER HIEUH +FFC2;FFC2;FFC2;1161;1161; # (ᅡ; ᅡ; ᅡ; ᅡ; ᅡ; ) HALFWIDTH HANGUL LETTER A +FFC3;FFC3;FFC3;1162;1162; # (ᅢ; ᅢ; ᅢ; ᅢ; ᅢ; ) HALFWIDTH HANGUL LETTER AE +FFC4;FFC4;FFC4;1163;1163; # (ᅣ; ᅣ; ᅣ; ᅣ; ᅣ; ) HALFWIDTH HANGUL LETTER YA +FFC5;FFC5;FFC5;1164;1164; # (ᅤ; ᅤ; ᅤ; ᅤ; ᅤ; ) HALFWIDTH HANGUL LETTER YAE +FFC6;FFC6;FFC6;1165;1165; # (ᅥ; ᅥ; ᅥ; ᅥ; ᅥ; ) HALFWIDTH HANGUL LETTER EO +FFC7;FFC7;FFC7;1166;1166; # (ᅦ; ᅦ; ᅦ; ᅦ; ᅦ; ) HALFWIDTH HANGUL LETTER E +FFCA;FFCA;FFCA;1167;1167; # (ᅧ; ᅧ; ᅧ; ᅧ; ᅧ; ) HALFWIDTH HANGUL LETTER YEO +FFCB;FFCB;FFCB;1168;1168; # (ᅨ; ᅨ; ᅨ; ᅨ; ᅨ; ) HALFWIDTH HANGUL LETTER YE +FFCC;FFCC;FFCC;1169;1169; # (ᅩ; ᅩ; ᅩ; ᅩ; ᅩ; ) HALFWIDTH HANGUL LETTER O +FFCD;FFCD;FFCD;116A;116A; # (ᅪ; ᅪ; ᅪ; ᅪ; ᅪ; ) HALFWIDTH HANGUL LETTER WA +FFCE;FFCE;FFCE;116B;116B; # (ᅫ; ᅫ; ᅫ; ᅫ; ᅫ; ) HALFWIDTH HANGUL LETTER WAE +FFCF;FFCF;FFCF;116C;116C; # (ᅬ; ᅬ; ᅬ; ᅬ; ᅬ; ) HALFWIDTH HANGUL LETTER OE +FFD2;FFD2;FFD2;116D;116D; # (ᅭ; ᅭ; ᅭ; ᅭ; ᅭ; ) HALFWIDTH HANGUL LETTER YO +FFD3;FFD3;FFD3;116E;116E; # (ᅮ; ᅮ; ᅮ; ᅮ; ᅮ; ) HALFWIDTH HANGUL LETTER U +FFD4;FFD4;FFD4;116F;116F; # (ᅯ; ᅯ; ᅯ; ᅯ; ᅯ; ) HALFWIDTH HANGUL LETTER WEO +FFD5;FFD5;FFD5;1170;1170; # (ᅰ; ᅰ; ᅰ; ᅰ; ᅰ; ) HALFWIDTH HANGUL LETTER WE +FFD6;FFD6;FFD6;1171;1171; # (ᅱ; ᅱ; ᅱ; ᅱ; ᅱ; ) HALFWIDTH HANGUL LETTER WI +FFD7;FFD7;FFD7;1172;1172; # (ᅲ; ᅲ; ᅲ; ᅲ; ᅲ; ) HALFWIDTH HANGUL LETTER YU +FFDA;FFDA;FFDA;1173;1173; # (ᅳ; ᅳ; ᅳ; ᅳ; ᅳ; ) HALFWIDTH HANGUL LETTER EU +FFDB;FFDB;FFDB;1174;1174; # (ᅴ; ᅴ; ᅴ; ᅴ; ᅴ; ) HALFWIDTH HANGUL LETTER YI +FFDC;FFDC;FFDC;1175;1175; # (ᅵ; ᅵ; ᅵ; ᅵ; ᅵ; ) HALFWIDTH HANGUL LETTER I +FFE0;FFE0;FFE0;00A2;00A2; # (¢; ¢; ¢; ¢; ¢; ) FULLWIDTH CENT SIGN +FFE1;FFE1;FFE1;00A3;00A3; # (£; £; £; £; £; ) FULLWIDTH POUND SIGN +FFE2;FFE2;FFE2;00AC;00AC; # (¬; ¬; ¬; ¬; ¬; ) FULLWIDTH NOT SIGN +FFE3;FFE3;FFE3;0020 0304;0020 0304; # ( ̄;  ̄;  ̄; ◌̄; ◌̄; ) FULLWIDTH MACRON +FFE4;FFE4;FFE4;00A6;00A6; # (¦; ¦; ¦; ¦; ¦; ) FULLWIDTH BROKEN BAR +FFE5;FFE5;FFE5;00A5;00A5; # (¥; ¥; ¥; ¥; ¥; ) FULLWIDTH YEN SIGN +FFE6;FFE6;FFE6;20A9;20A9; # (₩; ₩; ₩; ₩; ₩; ) FULLWIDTH WON SIGN +FFE8;FFE8;FFE8;2502;2502; # (│; │; │; │; │; ) HALFWIDTH FORMS LIGHT VERTICAL +FFE9;FFE9;FFE9;2190;2190; # (←; ←; ←; ←; ←; ) HALFWIDTH LEFTWARDS ARROW +FFEA;FFEA;FFEA;2191;2191; # (↑; ↑; ↑; ↑; ↑; ) HALFWIDTH UPWARDS ARROW +FFEB;FFEB;FFEB;2192;2192; # (→; →; →; →; →; ) HALFWIDTH RIGHTWARDS ARROW +FFEC;FFEC;FFEC;2193;2193; # (↓; ↓; ↓; ↓; ↓; ) HALFWIDTH DOWNWARDS ARROW +FFED;FFED;FFED;25A0;25A0; # (■; ■; ■; ■; ■; ) HALFWIDTH BLACK SQUARE +FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE +1D15E;1D157 1D165;1D157 1D165;1D157 1D165;1D157 1D165; # (𝅗𝅥𝅗𝅥; 𝅗𝅗𝅥𝅥; 𝅗𝅗𝅥𝅥; 𝅗𝅗𝅥𝅥; 𝅗𝅗𝅥𝅥; ) MUSICAL SYMBOL HALF NOTE +1D15F;1D158 1D165;1D158 1D165;1D158 1D165;1D158 1D165; # (𝅘𝅥𝅘𝅥; 𝅘𝅘𝅥𝅥; 𝅘𝅘𝅥𝅥; 𝅘𝅘𝅥𝅥; 𝅘𝅘𝅥𝅥; ) MUSICAL SYMBOL QUARTER NOTE +1D160;1D158 1D165 1D16E;1D158 1D165 1D16E;1D158 1D165 1D16E;1D158 1D165 1D16E; # (𝅘𝅥𝅮𝅘𝅥𝅮; 𝅘𝅘𝅥𝅥𝅮𝅮; 𝅘𝅘𝅥𝅥𝅮𝅮; 𝅘𝅘𝅥𝅥𝅮𝅮; 𝅘𝅘𝅥𝅥𝅮𝅮; ) MUSICAL SYMBOL EIGHTH NOTE +1D161;1D158 1D165 1D16F;1D158 1D165 1D16F;1D158 1D165 1D16F;1D158 1D165 1D16F; # (𝅘𝅥𝅯𝅘𝅥𝅯; 𝅘𝅘𝅥𝅥𝅯𝅯; 𝅘𝅘𝅥𝅥𝅯𝅯; 𝅘𝅘𝅥𝅥𝅯𝅯; 𝅘𝅘𝅥𝅥𝅯𝅯; ) MUSICAL SYMBOL SIXTEENTH NOTE +1D162;1D158 1D165 1D170;1D158 1D165 1D170;1D158 1D165 1D170;1D158 1D165 1D170; # (𝅘𝅥𝅰𝅘𝅥𝅰; 𝅘𝅘𝅥𝅥𝅰𝅰; 𝅘𝅘𝅥𝅥𝅰𝅰; 𝅘𝅘𝅥𝅥𝅰𝅰; 𝅘𝅘𝅥𝅥𝅰𝅰; ) MUSICAL SYMBOL THIRTY-SECOND NOTE +1D163;1D158 1D165 1D171;1D158 1D165 1D171;1D158 1D165 1D171;1D158 1D165 1D171; # (𝅘𝅥𝅱𝅘𝅥𝅱; 𝅘𝅘𝅥𝅥𝅱𝅱; 𝅘𝅘𝅥𝅥𝅱𝅱; 𝅘𝅘𝅥𝅥𝅱𝅱; 𝅘𝅘𝅥𝅥𝅱𝅱; ) MUSICAL SYMBOL SIXTY-FOURTH NOTE +1D164;1D158 1D165 1D172;1D158 1D165 1D172;1D158 1D165 1D172;1D158 1D165 1D172; # (𝅘𝅥𝅲𝅘𝅥𝅲; 𝅘𝅘𝅥𝅥𝅲𝅲; 𝅘𝅘𝅥𝅥𝅲𝅲; 𝅘𝅘𝅥𝅥𝅲𝅲; 𝅘𝅘𝅥𝅥𝅲𝅲; ) MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D1BB;1D1B9 1D165;1D1B9 1D165;1D1B9 1D165;1D1B9 1D165; # (𝆹𝅥𝆹𝅥; 𝆹𝆹𝅥𝅥; 𝆹𝆹𝅥𝅥; 𝆹𝆹𝅥𝅥; 𝆹𝆹𝅥𝅥; ) MUSICAL SYMBOL MINIMA +1D1BC;1D1BA 1D165;1D1BA 1D165;1D1BA 1D165;1D1BA 1D165; # (𝆺𝅥𝆺𝅥; 𝆺𝆺𝅥𝅥; 𝆺𝆺𝅥𝅥; 𝆺𝆺𝅥𝅥; 𝆺𝆺𝅥𝅥; ) MUSICAL SYMBOL MINIMA BLACK +1D1BD;1D1B9 1D165 1D16E;1D1B9 1D165 1D16E;1D1B9 1D165 1D16E;1D1B9 1D165 1D16E; # (𝆹𝅥𝅮𝆹𝅥𝅮; 𝆹𝆹𝅥𝅥𝅮𝅮; 𝆹𝆹𝅥𝅥𝅮𝅮; 𝆹𝆹𝅥𝅥𝅮𝅮; 𝆹𝆹𝅥𝅥𝅮𝅮; ) MUSICAL SYMBOL SEMIMINIMA WHITE +1D1BE;1D1BA 1D165 1D16E;1D1BA 1D165 1D16E;1D1BA 1D165 1D16E;1D1BA 1D165 1D16E; # (𝆺𝅥𝅮𝆺𝅥𝅮; 𝆺𝆺𝅥𝅥𝅮𝅮; 𝆺𝆺𝅥𝅥𝅮𝅮; 𝆺𝆺𝅥𝅥𝅮𝅮; 𝆺𝆺𝅥𝅥𝅮𝅮; ) MUSICAL SYMBOL SEMIMINIMA BLACK +1D1BF;1D1B9 1D165 1D16F;1D1B9 1D165 1D16F;1D1B9 1D165 1D16F;1D1B9 1D165 1D16F; # (𝆹𝅥𝅯𝆹𝅥𝅯; 𝆹𝆹𝅥𝅥𝅯𝅯; 𝆹𝆹𝅥𝅥𝅯𝅯; 𝆹𝆹𝅥𝅥𝅯𝅯; 𝆹𝆹𝅥𝅥𝅯𝅯; ) MUSICAL SYMBOL FUSA WHITE +1D1C0;1D1BA 1D165 1D16F;1D1BA 1D165 1D16F;1D1BA 1D165 1D16F;1D1BA 1D165 1D16F; # (𝆺𝅥𝅯𝆺𝅥𝅯; 𝆺𝆺𝅥𝅥𝅯𝅯; 𝆺𝆺𝅥𝅥𝅯𝅯; 𝆺𝆺𝅥𝅥𝅯𝅯; 𝆺𝆺𝅥𝅥𝅯𝅯; ) MUSICAL SYMBOL FUSA BLACK +1D400;1D400;1D400;0041;0041; # (𝐀𝐀; 𝐀𝐀; 𝐀𝐀; A; A; ) MATHEMATICAL BOLD CAPITAL A +1D401;1D401;1D401;0042;0042; # (𝐁𝐁; 𝐁𝐁; 𝐁𝐁; B; B; ) MATHEMATICAL BOLD CAPITAL B +1D402;1D402;1D402;0043;0043; # (𝐂𝐂; 𝐂𝐂; 𝐂𝐂; C; C; ) MATHEMATICAL BOLD CAPITAL C +1D403;1D403;1D403;0044;0044; # (𝐃𝐃; 𝐃𝐃; 𝐃𝐃; D; D; ) MATHEMATICAL BOLD CAPITAL D +1D404;1D404;1D404;0045;0045; # (𝐄𝐄; 𝐄𝐄; 𝐄𝐄; E; E; ) MATHEMATICAL BOLD CAPITAL E +1D405;1D405;1D405;0046;0046; # (𝐅𝐅; 𝐅𝐅; 𝐅𝐅; F; F; ) MATHEMATICAL BOLD CAPITAL F +1D406;1D406;1D406;0047;0047; # (𝐆𝐆; 𝐆𝐆; 𝐆𝐆; G; G; ) MATHEMATICAL BOLD CAPITAL G +1D407;1D407;1D407;0048;0048; # (𝐇𝐇; 𝐇𝐇; 𝐇𝐇; H; H; ) MATHEMATICAL BOLD CAPITAL H +1D408;1D408;1D408;0049;0049; # (𝐈𝐈; 𝐈𝐈; 𝐈𝐈; I; I; ) MATHEMATICAL BOLD CAPITAL I +1D409;1D409;1D409;004A;004A; # (𝐉𝐉; 𝐉𝐉; 𝐉𝐉; J; J; ) MATHEMATICAL BOLD CAPITAL J +1D40A;1D40A;1D40A;004B;004B; # (𝐊𝐊; 𝐊𝐊; 𝐊𝐊; K; K; ) MATHEMATICAL BOLD CAPITAL K +1D40B;1D40B;1D40B;004C;004C; # (𝐋𝐋; 𝐋𝐋; 𝐋𝐋; L; L; ) MATHEMATICAL BOLD CAPITAL L +1D40C;1D40C;1D40C;004D;004D; # (𝐌𝐌; 𝐌𝐌; 𝐌𝐌; M; M; ) MATHEMATICAL BOLD CAPITAL M +1D40D;1D40D;1D40D;004E;004E; # (𝐍𝐍; 𝐍𝐍; 𝐍𝐍; N; N; ) MATHEMATICAL BOLD CAPITAL N +1D40E;1D40E;1D40E;004F;004F; # (𝐎𝐎; 𝐎𝐎; 𝐎𝐎; O; O; ) MATHEMATICAL BOLD CAPITAL O +1D40F;1D40F;1D40F;0050;0050; # (𝐏𝐏; 𝐏𝐏; 𝐏𝐏; P; P; ) MATHEMATICAL BOLD CAPITAL P +1D410;1D410;1D410;0051;0051; # (𝐐𝐐; 𝐐𝐐; 𝐐𝐐; Q; Q; ) MATHEMATICAL BOLD CAPITAL Q +1D411;1D411;1D411;0052;0052; # (𝐑𝐑; 𝐑𝐑; 𝐑𝐑; R; R; ) MATHEMATICAL BOLD CAPITAL R +1D412;1D412;1D412;0053;0053; # (𝐒𝐒; 𝐒𝐒; 𝐒𝐒; S; S; ) MATHEMATICAL BOLD CAPITAL S +1D413;1D413;1D413;0054;0054; # (𝐓𝐓; 𝐓𝐓; 𝐓𝐓; T; T; ) MATHEMATICAL BOLD CAPITAL T +1D414;1D414;1D414;0055;0055; # (𝐔𝐔; 𝐔𝐔; 𝐔𝐔; U; U; ) MATHEMATICAL BOLD CAPITAL U +1D415;1D415;1D415;0056;0056; # (𝐕𝐕; 𝐕𝐕; 𝐕𝐕; V; V; ) MATHEMATICAL BOLD CAPITAL V +1D416;1D416;1D416;0057;0057; # (𝐖𝐖; 𝐖𝐖; 𝐖𝐖; W; W; ) MATHEMATICAL BOLD CAPITAL W +1D417;1D417;1D417;0058;0058; # (𝐗𝐗; 𝐗𝐗; 𝐗𝐗; X; X; ) MATHEMATICAL BOLD CAPITAL X +1D418;1D418;1D418;0059;0059; # (𝐘𝐘; 𝐘𝐘; 𝐘𝐘; Y; Y; ) MATHEMATICAL BOLD CAPITAL Y +1D419;1D419;1D419;005A;005A; # (𝐙𝐙; 𝐙𝐙; 𝐙𝐙; Z; Z; ) MATHEMATICAL BOLD CAPITAL Z +1D41A;1D41A;1D41A;0061;0061; # (𝐚𝐚; 𝐚𝐚; 𝐚𝐚; a; a; ) MATHEMATICAL BOLD SMALL A +1D41B;1D41B;1D41B;0062;0062; # (𝐛𝐛; 𝐛𝐛; 𝐛𝐛; b; b; ) MATHEMATICAL BOLD SMALL B +1D41C;1D41C;1D41C;0063;0063; # (𝐜𝐜; 𝐜𝐜; 𝐜𝐜; c; c; ) MATHEMATICAL BOLD SMALL C +1D41D;1D41D;1D41D;0064;0064; # (𝐝𝐝; 𝐝𝐝; 𝐝𝐝; d; d; ) MATHEMATICAL BOLD SMALL D +1D41E;1D41E;1D41E;0065;0065; # (𝐞𝐞; 𝐞𝐞; 𝐞𝐞; e; e; ) MATHEMATICAL BOLD SMALL E +1D41F;1D41F;1D41F;0066;0066; # (𝐟𝐟; 𝐟𝐟; 𝐟𝐟; f; f; ) MATHEMATICAL BOLD SMALL F +1D420;1D420;1D420;0067;0067; # (𝐠𝐠; 𝐠𝐠; 𝐠𝐠; g; g; ) MATHEMATICAL BOLD SMALL G +1D421;1D421;1D421;0068;0068; # (𝐡𝐡; 𝐡𝐡; 𝐡𝐡; h; h; ) MATHEMATICAL BOLD SMALL H +1D422;1D422;1D422;0069;0069; # (𝐢𝐢; 𝐢𝐢; 𝐢𝐢; i; i; ) MATHEMATICAL BOLD SMALL I +1D423;1D423;1D423;006A;006A; # (𝐣𝐣; 𝐣𝐣; 𝐣𝐣; j; j; ) MATHEMATICAL BOLD SMALL J +1D424;1D424;1D424;006B;006B; # (𝐤𝐤; 𝐤𝐤; 𝐤𝐤; k; k; ) MATHEMATICAL BOLD SMALL K +1D425;1D425;1D425;006C;006C; # (𝐥𝐥; 𝐥𝐥; 𝐥𝐥; l; l; ) MATHEMATICAL BOLD SMALL L +1D426;1D426;1D426;006D;006D; # (𝐦𝐦; 𝐦𝐦; 𝐦𝐦; m; m; ) MATHEMATICAL BOLD SMALL M +1D427;1D427;1D427;006E;006E; # (𝐧𝐧; 𝐧𝐧; 𝐧𝐧; n; n; ) MATHEMATICAL BOLD SMALL N +1D428;1D428;1D428;006F;006F; # (𝐨𝐨; 𝐨𝐨; 𝐨𝐨; o; o; ) MATHEMATICAL BOLD SMALL O +1D429;1D429;1D429;0070;0070; # (𝐩𝐩; 𝐩𝐩; 𝐩𝐩; p; p; ) MATHEMATICAL BOLD SMALL P +1D42A;1D42A;1D42A;0071;0071; # (𝐪𝐪; 𝐪𝐪; 𝐪𝐪; q; q; ) MATHEMATICAL BOLD SMALL Q +1D42B;1D42B;1D42B;0072;0072; # (𝐫𝐫; 𝐫𝐫; 𝐫𝐫; r; r; ) MATHEMATICAL BOLD SMALL R +1D42C;1D42C;1D42C;0073;0073; # (𝐬𝐬; 𝐬𝐬; 𝐬𝐬; s; s; ) MATHEMATICAL BOLD SMALL S +1D42D;1D42D;1D42D;0074;0074; # (𝐭𝐭; 𝐭𝐭; 𝐭𝐭; t; t; ) MATHEMATICAL BOLD SMALL T +1D42E;1D42E;1D42E;0075;0075; # (𝐮𝐮; 𝐮𝐮; 𝐮𝐮; u; u; ) MATHEMATICAL BOLD SMALL U +1D42F;1D42F;1D42F;0076;0076; # (𝐯𝐯; 𝐯𝐯; 𝐯𝐯; v; v; ) MATHEMATICAL BOLD SMALL V +1D430;1D430;1D430;0077;0077; # (𝐰𝐰; 𝐰𝐰; 𝐰𝐰; w; w; ) MATHEMATICAL BOLD SMALL W +1D431;1D431;1D431;0078;0078; # (𝐱𝐱; 𝐱𝐱; 𝐱𝐱; x; x; ) MATHEMATICAL BOLD SMALL X +1D432;1D432;1D432;0079;0079; # (𝐲𝐲; 𝐲𝐲; 𝐲𝐲; y; y; ) MATHEMATICAL BOLD SMALL Y +1D433;1D433;1D433;007A;007A; # (𝐳𝐳; 𝐳𝐳; 𝐳𝐳; z; z; ) MATHEMATICAL BOLD SMALL Z +1D434;1D434;1D434;0041;0041; # (𝐴𝐴; 𝐴𝐴; 𝐴𝐴; A; A; ) MATHEMATICAL ITALIC CAPITAL A +1D435;1D435;1D435;0042;0042; # (𝐵𝐵; 𝐵𝐵; 𝐵𝐵; B; B; ) MATHEMATICAL ITALIC CAPITAL B +1D436;1D436;1D436;0043;0043; # (𝐶𝐶; 𝐶𝐶; 𝐶𝐶; C; C; ) MATHEMATICAL ITALIC CAPITAL C +1D437;1D437;1D437;0044;0044; # (𝐷𝐷; 𝐷𝐷; 𝐷𝐷; D; D; ) MATHEMATICAL ITALIC CAPITAL D +1D438;1D438;1D438;0045;0045; # (𝐸𝐸; 𝐸𝐸; 𝐸𝐸; E; E; ) MATHEMATICAL ITALIC CAPITAL E +1D439;1D439;1D439;0046;0046; # (𝐹𝐹; 𝐹𝐹; 𝐹𝐹; F; F; ) MATHEMATICAL ITALIC CAPITAL F +1D43A;1D43A;1D43A;0047;0047; # (𝐺𝐺; 𝐺𝐺; 𝐺𝐺; G; G; ) MATHEMATICAL ITALIC CAPITAL G +1D43B;1D43B;1D43B;0048;0048; # (𝐻𝐻; 𝐻𝐻; 𝐻𝐻; H; H; ) MATHEMATICAL ITALIC CAPITAL H +1D43C;1D43C;1D43C;0049;0049; # (𝐼𝐼; 𝐼𝐼; 𝐼𝐼; I; I; ) MATHEMATICAL ITALIC CAPITAL I +1D43D;1D43D;1D43D;004A;004A; # (𝐽𝐽; 𝐽𝐽; 𝐽𝐽; J; J; ) MATHEMATICAL ITALIC CAPITAL J +1D43E;1D43E;1D43E;004B;004B; # (𝐾𝐾; 𝐾𝐾; 𝐾𝐾; K; K; ) MATHEMATICAL ITALIC CAPITAL K +1D43F;1D43F;1D43F;004C;004C; # (𝐿𝐿; 𝐿𝐿; 𝐿𝐿; L; L; ) MATHEMATICAL ITALIC CAPITAL L +1D440;1D440;1D440;004D;004D; # (𝑀𝑀; 𝑀𝑀; 𝑀𝑀; M; M; ) MATHEMATICAL ITALIC CAPITAL M +1D441;1D441;1D441;004E;004E; # (𝑁𝑁; 𝑁𝑁; 𝑁𝑁; N; N; ) MATHEMATICAL ITALIC CAPITAL N +1D442;1D442;1D442;004F;004F; # (𝑂𝑂; 𝑂𝑂; 𝑂𝑂; O; O; ) MATHEMATICAL ITALIC CAPITAL O +1D443;1D443;1D443;0050;0050; # (𝑃𝑃; 𝑃𝑃; 𝑃𝑃; P; P; ) MATHEMATICAL ITALIC CAPITAL P +1D444;1D444;1D444;0051;0051; # (𝑄𝑄; 𝑄𝑄; 𝑄𝑄; Q; Q; ) MATHEMATICAL ITALIC CAPITAL Q +1D445;1D445;1D445;0052;0052; # (𝑅𝑅; 𝑅𝑅; 𝑅𝑅; R; R; ) MATHEMATICAL ITALIC CAPITAL R +1D446;1D446;1D446;0053;0053; # (𝑆𝑆; 𝑆𝑆; 𝑆𝑆; S; S; ) MATHEMATICAL ITALIC CAPITAL S +1D447;1D447;1D447;0054;0054; # (𝑇𝑇; 𝑇𝑇; 𝑇𝑇; T; T; ) MATHEMATICAL ITALIC CAPITAL T +1D448;1D448;1D448;0055;0055; # (𝑈𝑈; 𝑈𝑈; 𝑈𝑈; U; U; ) MATHEMATICAL ITALIC CAPITAL U +1D449;1D449;1D449;0056;0056; # (𝑉𝑉; 𝑉𝑉; 𝑉𝑉; V; V; ) MATHEMATICAL ITALIC CAPITAL V +1D44A;1D44A;1D44A;0057;0057; # (𝑊𝑊; 𝑊𝑊; 𝑊𝑊; W; W; ) MATHEMATICAL ITALIC CAPITAL W +1D44B;1D44B;1D44B;0058;0058; # (𝑋𝑋; 𝑋𝑋; 𝑋𝑋; X; X; ) MATHEMATICAL ITALIC CAPITAL X +1D44C;1D44C;1D44C;0059;0059; # (𝑌𝑌; 𝑌𝑌; 𝑌𝑌; Y; Y; ) MATHEMATICAL ITALIC CAPITAL Y +1D44D;1D44D;1D44D;005A;005A; # (𝑍𝑍; 𝑍𝑍; 𝑍𝑍; Z; Z; ) MATHEMATICAL ITALIC CAPITAL Z +1D44E;1D44E;1D44E;0061;0061; # (𝑎𝑎; 𝑎𝑎; 𝑎𝑎; a; a; ) MATHEMATICAL ITALIC SMALL A +1D44F;1D44F;1D44F;0062;0062; # (𝑏𝑏; 𝑏𝑏; 𝑏𝑏; b; b; ) MATHEMATICAL ITALIC SMALL B +1D450;1D450;1D450;0063;0063; # (𝑐𝑐; 𝑐𝑐; 𝑐𝑐; c; c; ) MATHEMATICAL ITALIC SMALL C +1D451;1D451;1D451;0064;0064; # (𝑑𝑑; 𝑑𝑑; 𝑑𝑑; d; d; ) MATHEMATICAL ITALIC SMALL D +1D452;1D452;1D452;0065;0065; # (𝑒𝑒; 𝑒𝑒; 𝑒𝑒; e; e; ) MATHEMATICAL ITALIC SMALL E +1D453;1D453;1D453;0066;0066; # (𝑓𝑓; 𝑓𝑓; 𝑓𝑓; f; f; ) MATHEMATICAL ITALIC SMALL F +1D454;1D454;1D454;0067;0067; # (𝑔𝑔; 𝑔𝑔; 𝑔𝑔; g; g; ) MATHEMATICAL ITALIC SMALL G +1D456;1D456;1D456;0069;0069; # (𝑖𝑖; 𝑖𝑖; 𝑖𝑖; i; i; ) MATHEMATICAL ITALIC SMALL I +1D457;1D457;1D457;006A;006A; # (𝑗𝑗; 𝑗𝑗; 𝑗𝑗; j; j; ) MATHEMATICAL ITALIC SMALL J +1D458;1D458;1D458;006B;006B; # (𝑘𝑘; 𝑘𝑘; 𝑘𝑘; k; k; ) MATHEMATICAL ITALIC SMALL K +1D459;1D459;1D459;006C;006C; # (𝑙𝑙; 𝑙𝑙; 𝑙𝑙; l; l; ) MATHEMATICAL ITALIC SMALL L +1D45A;1D45A;1D45A;006D;006D; # (𝑚𝑚; 𝑚𝑚; 𝑚𝑚; m; m; ) MATHEMATICAL ITALIC SMALL M +1D45B;1D45B;1D45B;006E;006E; # (𝑛𝑛; 𝑛𝑛; 𝑛𝑛; n; n; ) MATHEMATICAL ITALIC SMALL N +1D45C;1D45C;1D45C;006F;006F; # (𝑜𝑜; 𝑜𝑜; 𝑜𝑜; o; o; ) MATHEMATICAL ITALIC SMALL O +1D45D;1D45D;1D45D;0070;0070; # (𝑝𝑝; 𝑝𝑝; 𝑝𝑝; p; p; ) MATHEMATICAL ITALIC SMALL P +1D45E;1D45E;1D45E;0071;0071; # (𝑞𝑞; 𝑞𝑞; 𝑞𝑞; q; q; ) MATHEMATICAL ITALIC SMALL Q +1D45F;1D45F;1D45F;0072;0072; # (𝑟𝑟; 𝑟𝑟; 𝑟𝑟; r; r; ) MATHEMATICAL ITALIC SMALL R +1D460;1D460;1D460;0073;0073; # (𝑠𝑠; 𝑠𝑠; 𝑠𝑠; s; s; ) MATHEMATICAL ITALIC SMALL S +1D461;1D461;1D461;0074;0074; # (𝑡𝑡; 𝑡𝑡; 𝑡𝑡; t; t; ) MATHEMATICAL ITALIC SMALL T +1D462;1D462;1D462;0075;0075; # (𝑢𝑢; 𝑢𝑢; 𝑢𝑢; u; u; ) MATHEMATICAL ITALIC SMALL U +1D463;1D463;1D463;0076;0076; # (𝑣𝑣; 𝑣𝑣; 𝑣𝑣; v; v; ) MATHEMATICAL ITALIC SMALL V +1D464;1D464;1D464;0077;0077; # (𝑤𝑤; 𝑤𝑤; 𝑤𝑤; w; w; ) MATHEMATICAL ITALIC SMALL W +1D465;1D465;1D465;0078;0078; # (𝑥𝑥; 𝑥𝑥; 𝑥𝑥; x; x; ) MATHEMATICAL ITALIC SMALL X +1D466;1D466;1D466;0079;0079; # (𝑦𝑦; 𝑦𝑦; 𝑦𝑦; y; y; ) MATHEMATICAL ITALIC SMALL Y +1D467;1D467;1D467;007A;007A; # (𝑧𝑧; 𝑧𝑧; 𝑧𝑧; z; z; ) MATHEMATICAL ITALIC SMALL Z +1D468;1D468;1D468;0041;0041; # (𝑨𝑨; 𝑨𝑨; 𝑨𝑨; A; A; ) MATHEMATICAL BOLD ITALIC CAPITAL A +1D469;1D469;1D469;0042;0042; # (𝑩𝑩; 𝑩𝑩; 𝑩𝑩; B; B; ) MATHEMATICAL BOLD ITALIC CAPITAL B +1D46A;1D46A;1D46A;0043;0043; # (𝑪𝑪; 𝑪𝑪; 𝑪𝑪; C; C; ) MATHEMATICAL BOLD ITALIC CAPITAL C +1D46B;1D46B;1D46B;0044;0044; # (𝑫𝑫; 𝑫𝑫; 𝑫𝑫; D; D; ) MATHEMATICAL BOLD ITALIC CAPITAL D +1D46C;1D46C;1D46C;0045;0045; # (𝑬𝑬; 𝑬𝑬; 𝑬𝑬; E; E; ) MATHEMATICAL BOLD ITALIC CAPITAL E +1D46D;1D46D;1D46D;0046;0046; # (𝑭𝑭; 𝑭𝑭; 𝑭𝑭; F; F; ) MATHEMATICAL BOLD ITALIC CAPITAL F +1D46E;1D46E;1D46E;0047;0047; # (𝑮𝑮; 𝑮𝑮; 𝑮𝑮; G; G; ) MATHEMATICAL BOLD ITALIC CAPITAL G +1D46F;1D46F;1D46F;0048;0048; # (𝑯𝑯; 𝑯𝑯; 𝑯𝑯; H; H; ) MATHEMATICAL BOLD ITALIC CAPITAL H +1D470;1D470;1D470;0049;0049; # (𝑰𝑰; 𝑰𝑰; 𝑰𝑰; I; I; ) MATHEMATICAL BOLD ITALIC CAPITAL I +1D471;1D471;1D471;004A;004A; # (𝑱𝑱; 𝑱𝑱; 𝑱𝑱; J; J; ) MATHEMATICAL BOLD ITALIC CAPITAL J +1D472;1D472;1D472;004B;004B; # (𝑲𝑲; 𝑲𝑲; 𝑲𝑲; K; K; ) MATHEMATICAL BOLD ITALIC CAPITAL K +1D473;1D473;1D473;004C;004C; # (𝑳𝑳; 𝑳𝑳; 𝑳𝑳; L; L; ) MATHEMATICAL BOLD ITALIC CAPITAL L +1D474;1D474;1D474;004D;004D; # (𝑴𝑴; 𝑴𝑴; 𝑴𝑴; M; M; ) MATHEMATICAL BOLD ITALIC CAPITAL M +1D475;1D475;1D475;004E;004E; # (𝑵𝑵; 𝑵𝑵; 𝑵𝑵; N; N; ) MATHEMATICAL BOLD ITALIC CAPITAL N +1D476;1D476;1D476;004F;004F; # (𝑶𝑶; 𝑶𝑶; 𝑶𝑶; O; O; ) MATHEMATICAL BOLD ITALIC CAPITAL O +1D477;1D477;1D477;0050;0050; # (𝑷𝑷; 𝑷𝑷; 𝑷𝑷; P; P; ) MATHEMATICAL BOLD ITALIC CAPITAL P +1D478;1D478;1D478;0051;0051; # (𝑸𝑸; 𝑸𝑸; 𝑸𝑸; Q; Q; ) MATHEMATICAL BOLD ITALIC CAPITAL Q +1D479;1D479;1D479;0052;0052; # (𝑹𝑹; 𝑹𝑹; 𝑹𝑹; R; R; ) MATHEMATICAL BOLD ITALIC CAPITAL R +1D47A;1D47A;1D47A;0053;0053; # (𝑺𝑺; 𝑺𝑺; 𝑺𝑺; S; S; ) MATHEMATICAL BOLD ITALIC CAPITAL S +1D47B;1D47B;1D47B;0054;0054; # (𝑻𝑻; 𝑻𝑻; 𝑻𝑻; T; T; ) MATHEMATICAL BOLD ITALIC CAPITAL T +1D47C;1D47C;1D47C;0055;0055; # (𝑼𝑼; 𝑼𝑼; 𝑼𝑼; U; U; ) MATHEMATICAL BOLD ITALIC CAPITAL U +1D47D;1D47D;1D47D;0056;0056; # (𝑽𝑽; 𝑽𝑽; 𝑽𝑽; V; V; ) MATHEMATICAL BOLD ITALIC CAPITAL V +1D47E;1D47E;1D47E;0057;0057; # (𝑾𝑾; 𝑾𝑾; 𝑾𝑾; W; W; ) MATHEMATICAL BOLD ITALIC CAPITAL W +1D47F;1D47F;1D47F;0058;0058; # (𝑿𝑿; 𝑿𝑿; 𝑿𝑿; X; X; ) MATHEMATICAL BOLD ITALIC CAPITAL X +1D480;1D480;1D480;0059;0059; # (𝒀𝒀; 𝒀𝒀; 𝒀𝒀; Y; Y; ) MATHEMATICAL BOLD ITALIC CAPITAL Y +1D481;1D481;1D481;005A;005A; # (𝒁𝒁; 𝒁𝒁; 𝒁𝒁; Z; Z; ) MATHEMATICAL BOLD ITALIC CAPITAL Z +1D482;1D482;1D482;0061;0061; # (𝒂𝒂; 𝒂𝒂; 𝒂𝒂; a; a; ) MATHEMATICAL BOLD ITALIC SMALL A +1D483;1D483;1D483;0062;0062; # (𝒃𝒃; 𝒃𝒃; 𝒃𝒃; b; b; ) MATHEMATICAL BOLD ITALIC SMALL B +1D484;1D484;1D484;0063;0063; # (𝒄𝒄; 𝒄𝒄; 𝒄𝒄; c; c; ) MATHEMATICAL BOLD ITALIC SMALL C +1D485;1D485;1D485;0064;0064; # (𝒅𝒅; 𝒅𝒅; 𝒅𝒅; d; d; ) MATHEMATICAL BOLD ITALIC SMALL D +1D486;1D486;1D486;0065;0065; # (𝒆𝒆; 𝒆𝒆; 𝒆𝒆; e; e; ) MATHEMATICAL BOLD ITALIC SMALL E +1D487;1D487;1D487;0066;0066; # (𝒇𝒇; 𝒇𝒇; 𝒇𝒇; f; f; ) MATHEMATICAL BOLD ITALIC SMALL F +1D488;1D488;1D488;0067;0067; # (𝒈𝒈; 𝒈𝒈; 𝒈𝒈; g; g; ) MATHEMATICAL BOLD ITALIC SMALL G +1D489;1D489;1D489;0068;0068; # (𝒉𝒉; 𝒉𝒉; 𝒉𝒉; h; h; ) MATHEMATICAL BOLD ITALIC SMALL H +1D48A;1D48A;1D48A;0069;0069; # (𝒊𝒊; 𝒊𝒊; 𝒊𝒊; i; i; ) MATHEMATICAL BOLD ITALIC SMALL I +1D48B;1D48B;1D48B;006A;006A; # (𝒋𝒋; 𝒋𝒋; 𝒋𝒋; j; j; ) MATHEMATICAL BOLD ITALIC SMALL J +1D48C;1D48C;1D48C;006B;006B; # (𝒌𝒌; 𝒌𝒌; 𝒌𝒌; k; k; ) MATHEMATICAL BOLD ITALIC SMALL K +1D48D;1D48D;1D48D;006C;006C; # (𝒍𝒍; 𝒍𝒍; 𝒍𝒍; l; l; ) MATHEMATICAL BOLD ITALIC SMALL L +1D48E;1D48E;1D48E;006D;006D; # (𝒎𝒎; 𝒎𝒎; 𝒎𝒎; m; m; ) MATHEMATICAL BOLD ITALIC SMALL M +1D48F;1D48F;1D48F;006E;006E; # (𝒏𝒏; 𝒏𝒏; 𝒏𝒏; n; n; ) MATHEMATICAL BOLD ITALIC SMALL N +1D490;1D490;1D490;006F;006F; # (𝒐𝒐; 𝒐𝒐; 𝒐𝒐; o; o; ) MATHEMATICAL BOLD ITALIC SMALL O +1D491;1D491;1D491;0070;0070; # (𝒑𝒑; 𝒑𝒑; 𝒑𝒑; p; p; ) MATHEMATICAL BOLD ITALIC SMALL P +1D492;1D492;1D492;0071;0071; # (𝒒𝒒; 𝒒𝒒; 𝒒𝒒; q; q; ) MATHEMATICAL BOLD ITALIC SMALL Q +1D493;1D493;1D493;0072;0072; # (𝒓𝒓; 𝒓𝒓; 𝒓𝒓; r; r; ) MATHEMATICAL BOLD ITALIC SMALL R +1D494;1D494;1D494;0073;0073; # (𝒔𝒔; 𝒔𝒔; 𝒔𝒔; s; s; ) MATHEMATICAL BOLD ITALIC SMALL S +1D495;1D495;1D495;0074;0074; # (𝒕𝒕; 𝒕𝒕; 𝒕𝒕; t; t; ) MATHEMATICAL BOLD ITALIC SMALL T +1D496;1D496;1D496;0075;0075; # (𝒖𝒖; 𝒖𝒖; 𝒖𝒖; u; u; ) MATHEMATICAL BOLD ITALIC SMALL U +1D497;1D497;1D497;0076;0076; # (𝒗𝒗; 𝒗𝒗; 𝒗𝒗; v; v; ) MATHEMATICAL BOLD ITALIC SMALL V +1D498;1D498;1D498;0077;0077; # (𝒘𝒘; 𝒘𝒘; 𝒘𝒘; w; w; ) MATHEMATICAL BOLD ITALIC SMALL W +1D499;1D499;1D499;0078;0078; # (𝒙𝒙; 𝒙𝒙; 𝒙𝒙; x; x; ) MATHEMATICAL BOLD ITALIC SMALL X +1D49A;1D49A;1D49A;0079;0079; # (𝒚𝒚; 𝒚𝒚; 𝒚𝒚; y; y; ) MATHEMATICAL BOLD ITALIC SMALL Y +1D49B;1D49B;1D49B;007A;007A; # (𝒛𝒛; 𝒛𝒛; 𝒛𝒛; z; z; ) MATHEMATICAL BOLD ITALIC SMALL Z +1D49C;1D49C;1D49C;0041;0041; # (𝒜𝒜; 𝒜𝒜; 𝒜𝒜; A; A; ) MATHEMATICAL SCRIPT CAPITAL A +1D49E;1D49E;1D49E;0043;0043; # (𝒞𝒞; 𝒞𝒞; 𝒞𝒞; C; C; ) MATHEMATICAL SCRIPT CAPITAL C +1D49F;1D49F;1D49F;0044;0044; # (𝒟𝒟; 𝒟𝒟; 𝒟𝒟; D; D; ) MATHEMATICAL SCRIPT CAPITAL D +1D4A2;1D4A2;1D4A2;0047;0047; # (𝒢𝒢; 𝒢𝒢; 𝒢𝒢; G; G; ) MATHEMATICAL SCRIPT CAPITAL G +1D4A5;1D4A5;1D4A5;004A;004A; # (𝒥𝒥; 𝒥𝒥; 𝒥𝒥; J; J; ) MATHEMATICAL SCRIPT CAPITAL J +1D4A6;1D4A6;1D4A6;004B;004B; # (𝒦𝒦; 𝒦𝒦; 𝒦𝒦; K; K; ) MATHEMATICAL SCRIPT CAPITAL K +1D4A9;1D4A9;1D4A9;004E;004E; # (𝒩𝒩; 𝒩𝒩; 𝒩𝒩; N; N; ) MATHEMATICAL SCRIPT CAPITAL N +1D4AA;1D4AA;1D4AA;004F;004F; # (𝒪𝒪; 𝒪𝒪; 𝒪𝒪; O; O; ) MATHEMATICAL SCRIPT CAPITAL O +1D4AB;1D4AB;1D4AB;0050;0050; # (𝒫𝒫; 𝒫𝒫; 𝒫𝒫; P; P; ) MATHEMATICAL SCRIPT CAPITAL P +1D4AC;1D4AC;1D4AC;0051;0051; # (𝒬𝒬; 𝒬𝒬; 𝒬𝒬; Q; Q; ) MATHEMATICAL SCRIPT CAPITAL Q +1D4AE;1D4AE;1D4AE;0053;0053; # (𝒮𝒮; 𝒮𝒮; 𝒮𝒮; S; S; ) MATHEMATICAL SCRIPT CAPITAL S +1D4AF;1D4AF;1D4AF;0054;0054; # (𝒯𝒯; 𝒯𝒯; 𝒯𝒯; T; T; ) MATHEMATICAL SCRIPT CAPITAL T +1D4B0;1D4B0;1D4B0;0055;0055; # (𝒰𝒰; 𝒰𝒰; 𝒰𝒰; U; U; ) MATHEMATICAL SCRIPT CAPITAL U +1D4B1;1D4B1;1D4B1;0056;0056; # (𝒱𝒱; 𝒱𝒱; 𝒱𝒱; V; V; ) MATHEMATICAL SCRIPT CAPITAL V +1D4B2;1D4B2;1D4B2;0057;0057; # (𝒲𝒲; 𝒲𝒲; 𝒲𝒲; W; W; ) MATHEMATICAL SCRIPT CAPITAL W +1D4B3;1D4B3;1D4B3;0058;0058; # (𝒳𝒳; 𝒳𝒳; 𝒳𝒳; X; X; ) MATHEMATICAL SCRIPT CAPITAL X +1D4B4;1D4B4;1D4B4;0059;0059; # (𝒴𝒴; 𝒴𝒴; 𝒴𝒴; Y; Y; ) MATHEMATICAL SCRIPT CAPITAL Y +1D4B5;1D4B5;1D4B5;005A;005A; # (𝒵𝒵; 𝒵𝒵; 𝒵𝒵; Z; Z; ) MATHEMATICAL SCRIPT CAPITAL Z +1D4B6;1D4B6;1D4B6;0061;0061; # (𝒶𝒶; 𝒶𝒶; 𝒶𝒶; a; a; ) MATHEMATICAL SCRIPT SMALL A +1D4B7;1D4B7;1D4B7;0062;0062; # (𝒷𝒷; 𝒷𝒷; 𝒷𝒷; b; b; ) MATHEMATICAL SCRIPT SMALL B +1D4B8;1D4B8;1D4B8;0063;0063; # (𝒸𝒸; 𝒸𝒸; 𝒸𝒸; c; c; ) MATHEMATICAL SCRIPT SMALL C +1D4B9;1D4B9;1D4B9;0064;0064; # (𝒹𝒹; 𝒹𝒹; 𝒹𝒹; d; d; ) MATHEMATICAL SCRIPT SMALL D +1D4BB;1D4BB;1D4BB;0066;0066; # (𝒻𝒻; 𝒻𝒻; 𝒻𝒻; f; f; ) MATHEMATICAL SCRIPT SMALL F +1D4BD;1D4BD;1D4BD;0068;0068; # (𝒽𝒽; 𝒽𝒽; 𝒽𝒽; h; h; ) MATHEMATICAL SCRIPT SMALL H +1D4BE;1D4BE;1D4BE;0069;0069; # (𝒾𝒾; 𝒾𝒾; 𝒾𝒾; i; i; ) MATHEMATICAL SCRIPT SMALL I +1D4BF;1D4BF;1D4BF;006A;006A; # (𝒿𝒿; 𝒿𝒿; 𝒿𝒿; j; j; ) MATHEMATICAL SCRIPT SMALL J +1D4C0;1D4C0;1D4C0;006B;006B; # (𝓀𝓀; 𝓀𝓀; 𝓀𝓀; k; k; ) MATHEMATICAL SCRIPT SMALL K +1D4C2;1D4C2;1D4C2;006D;006D; # (𝓂𝓂; 𝓂𝓂; 𝓂𝓂; m; m; ) MATHEMATICAL SCRIPT SMALL M +1D4C3;1D4C3;1D4C3;006E;006E; # (𝓃𝓃; 𝓃𝓃; 𝓃𝓃; n; n; ) MATHEMATICAL SCRIPT SMALL N +1D4C5;1D4C5;1D4C5;0070;0070; # (𝓅𝓅; 𝓅𝓅; 𝓅𝓅; p; p; ) MATHEMATICAL SCRIPT SMALL P +1D4C6;1D4C6;1D4C6;0071;0071; # (𝓆𝓆; 𝓆𝓆; 𝓆𝓆; q; q; ) MATHEMATICAL SCRIPT SMALL Q +1D4C7;1D4C7;1D4C7;0072;0072; # (𝓇𝓇; 𝓇𝓇; 𝓇𝓇; r; r; ) MATHEMATICAL SCRIPT SMALL R +1D4C8;1D4C8;1D4C8;0073;0073; # (𝓈𝓈; 𝓈𝓈; 𝓈𝓈; s; s; ) MATHEMATICAL SCRIPT SMALL S +1D4C9;1D4C9;1D4C9;0074;0074; # (𝓉𝓉; 𝓉𝓉; 𝓉𝓉; t; t; ) MATHEMATICAL SCRIPT SMALL T +1D4CA;1D4CA;1D4CA;0075;0075; # (𝓊𝓊; 𝓊𝓊; 𝓊𝓊; u; u; ) MATHEMATICAL SCRIPT SMALL U +1D4CB;1D4CB;1D4CB;0076;0076; # (𝓋𝓋; 𝓋𝓋; 𝓋𝓋; v; v; ) MATHEMATICAL SCRIPT SMALL V +1D4CC;1D4CC;1D4CC;0077;0077; # (𝓌𝓌; 𝓌𝓌; 𝓌𝓌; w; w; ) MATHEMATICAL SCRIPT SMALL W +1D4CD;1D4CD;1D4CD;0078;0078; # (𝓍𝓍; 𝓍𝓍; 𝓍𝓍; x; x; ) MATHEMATICAL SCRIPT SMALL X +1D4CE;1D4CE;1D4CE;0079;0079; # (𝓎𝓎; 𝓎𝓎; 𝓎𝓎; y; y; ) MATHEMATICAL SCRIPT SMALL Y +1D4CF;1D4CF;1D4CF;007A;007A; # (𝓏𝓏; 𝓏𝓏; 𝓏𝓏; z; z; ) MATHEMATICAL SCRIPT SMALL Z +1D4D0;1D4D0;1D4D0;0041;0041; # (𝓐𝓐; 𝓐𝓐; 𝓐𝓐; A; A; ) MATHEMATICAL BOLD SCRIPT CAPITAL A +1D4D1;1D4D1;1D4D1;0042;0042; # (𝓑𝓑; 𝓑𝓑; 𝓑𝓑; B; B; ) MATHEMATICAL BOLD SCRIPT CAPITAL B +1D4D2;1D4D2;1D4D2;0043;0043; # (𝓒𝓒; 𝓒𝓒; 𝓒𝓒; C; C; ) MATHEMATICAL BOLD SCRIPT CAPITAL C +1D4D3;1D4D3;1D4D3;0044;0044; # (𝓓𝓓; 𝓓𝓓; 𝓓𝓓; D; D; ) MATHEMATICAL BOLD SCRIPT CAPITAL D +1D4D4;1D4D4;1D4D4;0045;0045; # (𝓔𝓔; 𝓔𝓔; 𝓔𝓔; E; E; ) MATHEMATICAL BOLD SCRIPT CAPITAL E +1D4D5;1D4D5;1D4D5;0046;0046; # (𝓕𝓕; 𝓕𝓕; 𝓕𝓕; F; F; ) MATHEMATICAL BOLD SCRIPT CAPITAL F +1D4D6;1D4D6;1D4D6;0047;0047; # (𝓖𝓖; 𝓖𝓖; 𝓖𝓖; G; G; ) MATHEMATICAL BOLD SCRIPT CAPITAL G +1D4D7;1D4D7;1D4D7;0048;0048; # (𝓗𝓗; 𝓗𝓗; 𝓗𝓗; H; H; ) MATHEMATICAL BOLD SCRIPT CAPITAL H +1D4D8;1D4D8;1D4D8;0049;0049; # (𝓘𝓘; 𝓘𝓘; 𝓘𝓘; I; I; ) MATHEMATICAL BOLD SCRIPT CAPITAL I +1D4D9;1D4D9;1D4D9;004A;004A; # (𝓙𝓙; 𝓙𝓙; 𝓙𝓙; J; J; ) MATHEMATICAL BOLD SCRIPT CAPITAL J +1D4DA;1D4DA;1D4DA;004B;004B; # (𝓚𝓚; 𝓚𝓚; 𝓚𝓚; K; K; ) MATHEMATICAL BOLD SCRIPT CAPITAL K +1D4DB;1D4DB;1D4DB;004C;004C; # (𝓛𝓛; 𝓛𝓛; 𝓛𝓛; L; L; ) MATHEMATICAL BOLD SCRIPT CAPITAL L +1D4DC;1D4DC;1D4DC;004D;004D; # (𝓜𝓜; 𝓜𝓜; 𝓜𝓜; M; M; ) MATHEMATICAL BOLD SCRIPT CAPITAL M +1D4DD;1D4DD;1D4DD;004E;004E; # (𝓝𝓝; 𝓝𝓝; 𝓝𝓝; N; N; ) MATHEMATICAL BOLD SCRIPT CAPITAL N +1D4DE;1D4DE;1D4DE;004F;004F; # (𝓞𝓞; 𝓞𝓞; 𝓞𝓞; O; O; ) MATHEMATICAL BOLD SCRIPT CAPITAL O +1D4DF;1D4DF;1D4DF;0050;0050; # (𝓟𝓟; 𝓟𝓟; 𝓟𝓟; P; P; ) MATHEMATICAL BOLD SCRIPT CAPITAL P +1D4E0;1D4E0;1D4E0;0051;0051; # (𝓠𝓠; 𝓠𝓠; 𝓠𝓠; Q; Q; ) MATHEMATICAL BOLD SCRIPT CAPITAL Q +1D4E1;1D4E1;1D4E1;0052;0052; # (𝓡𝓡; 𝓡𝓡; 𝓡𝓡; R; R; ) MATHEMATICAL BOLD SCRIPT CAPITAL R +1D4E2;1D4E2;1D4E2;0053;0053; # (𝓢𝓢; 𝓢𝓢; 𝓢𝓢; S; S; ) MATHEMATICAL BOLD SCRIPT CAPITAL S +1D4E3;1D4E3;1D4E3;0054;0054; # (𝓣𝓣; 𝓣𝓣; 𝓣𝓣; T; T; ) MATHEMATICAL BOLD SCRIPT CAPITAL T +1D4E4;1D4E4;1D4E4;0055;0055; # (𝓤𝓤; 𝓤𝓤; 𝓤𝓤; U; U; ) MATHEMATICAL BOLD SCRIPT CAPITAL U +1D4E5;1D4E5;1D4E5;0056;0056; # (𝓥𝓥; 𝓥𝓥; 𝓥𝓥; V; V; ) MATHEMATICAL BOLD SCRIPT CAPITAL V +1D4E6;1D4E6;1D4E6;0057;0057; # (𝓦𝓦; 𝓦𝓦; 𝓦𝓦; W; W; ) MATHEMATICAL BOLD SCRIPT CAPITAL W +1D4E7;1D4E7;1D4E7;0058;0058; # (𝓧𝓧; 𝓧𝓧; 𝓧𝓧; X; X; ) MATHEMATICAL BOLD SCRIPT CAPITAL X +1D4E8;1D4E8;1D4E8;0059;0059; # (𝓨𝓨; 𝓨𝓨; 𝓨𝓨; Y; Y; ) MATHEMATICAL BOLD SCRIPT CAPITAL Y +1D4E9;1D4E9;1D4E9;005A;005A; # (𝓩𝓩; 𝓩𝓩; 𝓩𝓩; Z; Z; ) MATHEMATICAL BOLD SCRIPT CAPITAL Z +1D4EA;1D4EA;1D4EA;0061;0061; # (𝓪𝓪; 𝓪𝓪; 𝓪𝓪; a; a; ) MATHEMATICAL BOLD SCRIPT SMALL A +1D4EB;1D4EB;1D4EB;0062;0062; # (𝓫𝓫; 𝓫𝓫; 𝓫𝓫; b; b; ) MATHEMATICAL BOLD SCRIPT SMALL B +1D4EC;1D4EC;1D4EC;0063;0063; # (𝓬𝓬; 𝓬𝓬; 𝓬𝓬; c; c; ) MATHEMATICAL BOLD SCRIPT SMALL C +1D4ED;1D4ED;1D4ED;0064;0064; # (𝓭𝓭; 𝓭𝓭; 𝓭𝓭; d; d; ) MATHEMATICAL BOLD SCRIPT SMALL D +1D4EE;1D4EE;1D4EE;0065;0065; # (𝓮𝓮; 𝓮𝓮; 𝓮𝓮; e; e; ) MATHEMATICAL BOLD SCRIPT SMALL E +1D4EF;1D4EF;1D4EF;0066;0066; # (𝓯𝓯; 𝓯𝓯; 𝓯𝓯; f; f; ) MATHEMATICAL BOLD SCRIPT SMALL F +1D4F0;1D4F0;1D4F0;0067;0067; # (𝓰𝓰; 𝓰𝓰; 𝓰𝓰; g; g; ) MATHEMATICAL BOLD SCRIPT SMALL G +1D4F1;1D4F1;1D4F1;0068;0068; # (𝓱𝓱; 𝓱𝓱; 𝓱𝓱; h; h; ) MATHEMATICAL BOLD SCRIPT SMALL H +1D4F2;1D4F2;1D4F2;0069;0069; # (𝓲𝓲; 𝓲𝓲; 𝓲𝓲; i; i; ) MATHEMATICAL BOLD SCRIPT SMALL I +1D4F3;1D4F3;1D4F3;006A;006A; # (𝓳𝓳; 𝓳𝓳; 𝓳𝓳; j; j; ) MATHEMATICAL BOLD SCRIPT SMALL J +1D4F4;1D4F4;1D4F4;006B;006B; # (𝓴𝓴; 𝓴𝓴; 𝓴𝓴; k; k; ) MATHEMATICAL BOLD SCRIPT SMALL K +1D4F5;1D4F5;1D4F5;006C;006C; # (𝓵𝓵; 𝓵𝓵; 𝓵𝓵; l; l; ) MATHEMATICAL BOLD SCRIPT SMALL L +1D4F6;1D4F6;1D4F6;006D;006D; # (𝓶𝓶; 𝓶𝓶; 𝓶𝓶; m; m; ) MATHEMATICAL BOLD SCRIPT SMALL M +1D4F7;1D4F7;1D4F7;006E;006E; # (𝓷𝓷; 𝓷𝓷; 𝓷𝓷; n; n; ) MATHEMATICAL BOLD SCRIPT SMALL N +1D4F8;1D4F8;1D4F8;006F;006F; # (𝓸𝓸; 𝓸𝓸; 𝓸𝓸; o; o; ) MATHEMATICAL BOLD SCRIPT SMALL O +1D4F9;1D4F9;1D4F9;0070;0070; # (𝓹𝓹; 𝓹𝓹; 𝓹𝓹; p; p; ) MATHEMATICAL BOLD SCRIPT SMALL P +1D4FA;1D4FA;1D4FA;0071;0071; # (𝓺𝓺; 𝓺𝓺; 𝓺𝓺; q; q; ) MATHEMATICAL BOLD SCRIPT SMALL Q +1D4FB;1D4FB;1D4FB;0072;0072; # (𝓻𝓻; 𝓻𝓻; 𝓻𝓻; r; r; ) MATHEMATICAL BOLD SCRIPT SMALL R +1D4FC;1D4FC;1D4FC;0073;0073; # (𝓼𝓼; 𝓼𝓼; 𝓼𝓼; s; s; ) MATHEMATICAL BOLD SCRIPT SMALL S +1D4FD;1D4FD;1D4FD;0074;0074; # (𝓽𝓽; 𝓽𝓽; 𝓽𝓽; t; t; ) MATHEMATICAL BOLD SCRIPT SMALL T +1D4FE;1D4FE;1D4FE;0075;0075; # (𝓾𝓾; 𝓾𝓾; 𝓾𝓾; u; u; ) MATHEMATICAL BOLD SCRIPT SMALL U +1D4FF;1D4FF;1D4FF;0076;0076; # (𝓿𝓿; 𝓿𝓿; 𝓿𝓿; v; v; ) MATHEMATICAL BOLD SCRIPT SMALL V +1D500;1D500;1D500;0077;0077; # (𝔀𝔀; 𝔀𝔀; 𝔀𝔀; w; w; ) MATHEMATICAL BOLD SCRIPT SMALL W +1D501;1D501;1D501;0078;0078; # (𝔁𝔁; 𝔁𝔁; 𝔁𝔁; x; x; ) MATHEMATICAL BOLD SCRIPT SMALL X +1D502;1D502;1D502;0079;0079; # (𝔂𝔂; 𝔂𝔂; 𝔂𝔂; y; y; ) MATHEMATICAL BOLD SCRIPT SMALL Y +1D503;1D503;1D503;007A;007A; # (𝔃𝔃; 𝔃𝔃; 𝔃𝔃; z; z; ) MATHEMATICAL BOLD SCRIPT SMALL Z +1D504;1D504;1D504;0041;0041; # (𝔄𝔄; 𝔄𝔄; 𝔄𝔄; A; A; ) MATHEMATICAL FRAKTUR CAPITAL A +1D505;1D505;1D505;0042;0042; # (𝔅𝔅; 𝔅𝔅; 𝔅𝔅; B; B; ) MATHEMATICAL FRAKTUR CAPITAL B +1D507;1D507;1D507;0044;0044; # (𝔇𝔇; 𝔇𝔇; 𝔇𝔇; D; D; ) MATHEMATICAL FRAKTUR CAPITAL D +1D508;1D508;1D508;0045;0045; # (𝔈𝔈; 𝔈𝔈; 𝔈𝔈; E; E; ) MATHEMATICAL FRAKTUR CAPITAL E +1D509;1D509;1D509;0046;0046; # (𝔉𝔉; 𝔉𝔉; 𝔉𝔉; F; F; ) MATHEMATICAL FRAKTUR CAPITAL F +1D50A;1D50A;1D50A;0047;0047; # (𝔊𝔊; 𝔊𝔊; 𝔊𝔊; G; G; ) MATHEMATICAL FRAKTUR CAPITAL G +1D50D;1D50D;1D50D;004A;004A; # (𝔍𝔍; 𝔍𝔍; 𝔍𝔍; J; J; ) MATHEMATICAL FRAKTUR CAPITAL J +1D50E;1D50E;1D50E;004B;004B; # (𝔎𝔎; 𝔎𝔎; 𝔎𝔎; K; K; ) MATHEMATICAL FRAKTUR CAPITAL K +1D50F;1D50F;1D50F;004C;004C; # (𝔏𝔏; 𝔏𝔏; 𝔏𝔏; L; L; ) MATHEMATICAL FRAKTUR CAPITAL L +1D510;1D510;1D510;004D;004D; # (𝔐𝔐; 𝔐𝔐; 𝔐𝔐; M; M; ) MATHEMATICAL FRAKTUR CAPITAL M +1D511;1D511;1D511;004E;004E; # (𝔑𝔑; 𝔑𝔑; 𝔑𝔑; N; N; ) MATHEMATICAL FRAKTUR CAPITAL N +1D512;1D512;1D512;004F;004F; # (𝔒𝔒; 𝔒𝔒; 𝔒𝔒; O; O; ) MATHEMATICAL FRAKTUR CAPITAL O +1D513;1D513;1D513;0050;0050; # (𝔓𝔓; 𝔓𝔓; 𝔓𝔓; P; P; ) MATHEMATICAL FRAKTUR CAPITAL P +1D514;1D514;1D514;0051;0051; # (𝔔𝔔; 𝔔𝔔; 𝔔𝔔; Q; Q; ) MATHEMATICAL FRAKTUR CAPITAL Q +1D516;1D516;1D516;0053;0053; # (𝔖𝔖; 𝔖𝔖; 𝔖𝔖; S; S; ) MATHEMATICAL FRAKTUR CAPITAL S +1D517;1D517;1D517;0054;0054; # (𝔗𝔗; 𝔗𝔗; 𝔗𝔗; T; T; ) MATHEMATICAL FRAKTUR CAPITAL T +1D518;1D518;1D518;0055;0055; # (𝔘𝔘; 𝔘𝔘; 𝔘𝔘; U; U; ) MATHEMATICAL FRAKTUR CAPITAL U +1D519;1D519;1D519;0056;0056; # (𝔙𝔙; 𝔙𝔙; 𝔙𝔙; V; V; ) MATHEMATICAL FRAKTUR CAPITAL V +1D51A;1D51A;1D51A;0057;0057; # (𝔚𝔚; 𝔚𝔚; 𝔚𝔚; W; W; ) MATHEMATICAL FRAKTUR CAPITAL W +1D51B;1D51B;1D51B;0058;0058; # (𝔛𝔛; 𝔛𝔛; 𝔛𝔛; X; X; ) MATHEMATICAL FRAKTUR CAPITAL X +1D51C;1D51C;1D51C;0059;0059; # (𝔜𝔜; 𝔜𝔜; 𝔜𝔜; Y; Y; ) MATHEMATICAL FRAKTUR CAPITAL Y +1D51E;1D51E;1D51E;0061;0061; # (𝔞𝔞; 𝔞𝔞; 𝔞𝔞; a; a; ) MATHEMATICAL FRAKTUR SMALL A +1D51F;1D51F;1D51F;0062;0062; # (𝔟𝔟; 𝔟𝔟; 𝔟𝔟; b; b; ) MATHEMATICAL FRAKTUR SMALL B +1D520;1D520;1D520;0063;0063; # (𝔠𝔠; 𝔠𝔠; 𝔠𝔠; c; c; ) MATHEMATICAL FRAKTUR SMALL C +1D521;1D521;1D521;0064;0064; # (𝔡𝔡; 𝔡𝔡; 𝔡𝔡; d; d; ) MATHEMATICAL FRAKTUR SMALL D +1D522;1D522;1D522;0065;0065; # (𝔢𝔢; 𝔢𝔢; 𝔢𝔢; e; e; ) MATHEMATICAL FRAKTUR SMALL E +1D523;1D523;1D523;0066;0066; # (𝔣𝔣; 𝔣𝔣; 𝔣𝔣; f; f; ) MATHEMATICAL FRAKTUR SMALL F +1D524;1D524;1D524;0067;0067; # (𝔤𝔤; 𝔤𝔤; 𝔤𝔤; g; g; ) MATHEMATICAL FRAKTUR SMALL G +1D525;1D525;1D525;0068;0068; # (𝔥𝔥; 𝔥𝔥; 𝔥𝔥; h; h; ) MATHEMATICAL FRAKTUR SMALL H +1D526;1D526;1D526;0069;0069; # (𝔦𝔦; 𝔦𝔦; 𝔦𝔦; i; i; ) MATHEMATICAL FRAKTUR SMALL I +1D527;1D527;1D527;006A;006A; # (𝔧𝔧; 𝔧𝔧; 𝔧𝔧; j; j; ) MATHEMATICAL FRAKTUR SMALL J +1D528;1D528;1D528;006B;006B; # (𝔨𝔨; 𝔨𝔨; 𝔨𝔨; k; k; ) MATHEMATICAL FRAKTUR SMALL K +1D529;1D529;1D529;006C;006C; # (𝔩𝔩; 𝔩𝔩; 𝔩𝔩; l; l; ) MATHEMATICAL FRAKTUR SMALL L +1D52A;1D52A;1D52A;006D;006D; # (𝔪𝔪; 𝔪𝔪; 𝔪𝔪; m; m; ) MATHEMATICAL FRAKTUR SMALL M +1D52B;1D52B;1D52B;006E;006E; # (𝔫𝔫; 𝔫𝔫; 𝔫𝔫; n; n; ) MATHEMATICAL FRAKTUR SMALL N +1D52C;1D52C;1D52C;006F;006F; # (𝔬𝔬; 𝔬𝔬; 𝔬𝔬; o; o; ) MATHEMATICAL FRAKTUR SMALL O +1D52D;1D52D;1D52D;0070;0070; # (𝔭𝔭; 𝔭𝔭; 𝔭𝔭; p; p; ) MATHEMATICAL FRAKTUR SMALL P +1D52E;1D52E;1D52E;0071;0071; # (𝔮𝔮; 𝔮𝔮; 𝔮𝔮; q; q; ) MATHEMATICAL FRAKTUR SMALL Q +1D52F;1D52F;1D52F;0072;0072; # (𝔯𝔯; 𝔯𝔯; 𝔯𝔯; r; r; ) MATHEMATICAL FRAKTUR SMALL R +1D530;1D530;1D530;0073;0073; # (𝔰𝔰; 𝔰𝔰; 𝔰𝔰; s; s; ) MATHEMATICAL FRAKTUR SMALL S +1D531;1D531;1D531;0074;0074; # (𝔱𝔱; 𝔱𝔱; 𝔱𝔱; t; t; ) MATHEMATICAL FRAKTUR SMALL T +1D532;1D532;1D532;0075;0075; # (𝔲𝔲; 𝔲𝔲; 𝔲𝔲; u; u; ) MATHEMATICAL FRAKTUR SMALL U +1D533;1D533;1D533;0076;0076; # (𝔳𝔳; 𝔳𝔳; 𝔳𝔳; v; v; ) MATHEMATICAL FRAKTUR SMALL V +1D534;1D534;1D534;0077;0077; # (𝔴𝔴; 𝔴𝔴; 𝔴𝔴; w; w; ) MATHEMATICAL FRAKTUR SMALL W +1D535;1D535;1D535;0078;0078; # (𝔵𝔵; 𝔵𝔵; 𝔵𝔵; x; x; ) MATHEMATICAL FRAKTUR SMALL X +1D536;1D536;1D536;0079;0079; # (𝔶𝔶; 𝔶𝔶; 𝔶𝔶; y; y; ) MATHEMATICAL FRAKTUR SMALL Y +1D537;1D537;1D537;007A;007A; # (𝔷𝔷; 𝔷𝔷; 𝔷𝔷; z; z; ) MATHEMATICAL FRAKTUR SMALL Z +1D538;1D538;1D538;0041;0041; # (𝔸𝔸; 𝔸𝔸; 𝔸𝔸; A; A; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL A +1D539;1D539;1D539;0042;0042; # (𝔹𝔹; 𝔹𝔹; 𝔹𝔹; B; B; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B;1D53B;1D53B;0044;0044; # (𝔻𝔻; 𝔻𝔻; 𝔻𝔻; D; D; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL D +1D53C;1D53C;1D53C;0045;0045; # (𝔼𝔼; 𝔼𝔼; 𝔼𝔼; E; E; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL E +1D53D;1D53D;1D53D;0046;0046; # (𝔽𝔽; 𝔽𝔽; 𝔽𝔽; F; F; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL F +1D53E;1D53E;1D53E;0047;0047; # (𝔾𝔾; 𝔾𝔾; 𝔾𝔾; G; G; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540;1D540;1D540;0049;0049; # (𝕀𝕀; 𝕀𝕀; 𝕀𝕀; I; I; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL I +1D541;1D541;1D541;004A;004A; # (𝕁𝕁; 𝕁𝕁; 𝕁𝕁; J; J; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL J +1D542;1D542;1D542;004B;004B; # (𝕂𝕂; 𝕂𝕂; 𝕂𝕂; K; K; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL K +1D543;1D543;1D543;004C;004C; # (𝕃𝕃; 𝕃𝕃; 𝕃𝕃; L; L; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL L +1D544;1D544;1D544;004D;004D; # (𝕄𝕄; 𝕄𝕄; 𝕄𝕄; M; M; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546;1D546;1D546;004F;004F; # (𝕆𝕆; 𝕆𝕆; 𝕆𝕆; O; O; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A;1D54A;1D54A;0053;0053; # (𝕊𝕊; 𝕊𝕊; 𝕊𝕊; S; S; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL S +1D54B;1D54B;1D54B;0054;0054; # (𝕋𝕋; 𝕋𝕋; 𝕋𝕋; T; T; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL T +1D54C;1D54C;1D54C;0055;0055; # (𝕌𝕌; 𝕌𝕌; 𝕌𝕌; U; U; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL U +1D54D;1D54D;1D54D;0056;0056; # (𝕍𝕍; 𝕍𝕍; 𝕍𝕍; V; V; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL V +1D54E;1D54E;1D54E;0057;0057; # (𝕎𝕎; 𝕎𝕎; 𝕎𝕎; W; W; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL W +1D54F;1D54F;1D54F;0058;0058; # (𝕏𝕏; 𝕏𝕏; 𝕏𝕏; X; X; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL X +1D550;1D550;1D550;0059;0059; # (𝕐𝕐; 𝕐𝕐; 𝕐𝕐; Y; Y; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552;1D552;1D552;0061;0061; # (𝕒𝕒; 𝕒𝕒; 𝕒𝕒; a; a; ) MATHEMATICAL DOUBLE-STRUCK SMALL A +1D553;1D553;1D553;0062;0062; # (𝕓𝕓; 𝕓𝕓; 𝕓𝕓; b; b; ) MATHEMATICAL DOUBLE-STRUCK SMALL B +1D554;1D554;1D554;0063;0063; # (𝕔𝕔; 𝕔𝕔; 𝕔𝕔; c; c; ) MATHEMATICAL DOUBLE-STRUCK SMALL C +1D555;1D555;1D555;0064;0064; # (𝕕𝕕; 𝕕𝕕; 𝕕𝕕; d; d; ) MATHEMATICAL DOUBLE-STRUCK SMALL D +1D556;1D556;1D556;0065;0065; # (𝕖𝕖; 𝕖𝕖; 𝕖𝕖; e; e; ) MATHEMATICAL DOUBLE-STRUCK SMALL E +1D557;1D557;1D557;0066;0066; # (𝕗𝕗; 𝕗𝕗; 𝕗𝕗; f; f; ) MATHEMATICAL DOUBLE-STRUCK SMALL F +1D558;1D558;1D558;0067;0067; # (𝕘𝕘; 𝕘𝕘; 𝕘𝕘; g; g; ) MATHEMATICAL DOUBLE-STRUCK SMALL G +1D559;1D559;1D559;0068;0068; # (𝕙𝕙; 𝕙𝕙; 𝕙𝕙; h; h; ) MATHEMATICAL DOUBLE-STRUCK SMALL H +1D55A;1D55A;1D55A;0069;0069; # (𝕚𝕚; 𝕚𝕚; 𝕚𝕚; i; i; ) MATHEMATICAL DOUBLE-STRUCK SMALL I +1D55B;1D55B;1D55B;006A;006A; # (𝕛𝕛; 𝕛𝕛; 𝕛𝕛; j; j; ) MATHEMATICAL DOUBLE-STRUCK SMALL J +1D55C;1D55C;1D55C;006B;006B; # (𝕜𝕜; 𝕜𝕜; 𝕜𝕜; k; k; ) MATHEMATICAL DOUBLE-STRUCK SMALL K +1D55D;1D55D;1D55D;006C;006C; # (𝕝𝕝; 𝕝𝕝; 𝕝𝕝; l; l; ) MATHEMATICAL DOUBLE-STRUCK SMALL L +1D55E;1D55E;1D55E;006D;006D; # (𝕞𝕞; 𝕞𝕞; 𝕞𝕞; m; m; ) MATHEMATICAL DOUBLE-STRUCK SMALL M +1D55F;1D55F;1D55F;006E;006E; # (𝕟𝕟; 𝕟𝕟; 𝕟𝕟; n; n; ) MATHEMATICAL DOUBLE-STRUCK SMALL N +1D560;1D560;1D560;006F;006F; # (𝕠𝕠; 𝕠𝕠; 𝕠𝕠; o; o; ) MATHEMATICAL DOUBLE-STRUCK SMALL O +1D561;1D561;1D561;0070;0070; # (𝕡𝕡; 𝕡𝕡; 𝕡𝕡; p; p; ) MATHEMATICAL DOUBLE-STRUCK SMALL P +1D562;1D562;1D562;0071;0071; # (𝕢𝕢; 𝕢𝕢; 𝕢𝕢; q; q; ) MATHEMATICAL DOUBLE-STRUCK SMALL Q +1D563;1D563;1D563;0072;0072; # (𝕣𝕣; 𝕣𝕣; 𝕣𝕣; r; r; ) MATHEMATICAL DOUBLE-STRUCK SMALL R +1D564;1D564;1D564;0073;0073; # (𝕤𝕤; 𝕤𝕤; 𝕤𝕤; s; s; ) MATHEMATICAL DOUBLE-STRUCK SMALL S +1D565;1D565;1D565;0074;0074; # (𝕥𝕥; 𝕥𝕥; 𝕥𝕥; t; t; ) MATHEMATICAL DOUBLE-STRUCK SMALL T +1D566;1D566;1D566;0075;0075; # (𝕦𝕦; 𝕦𝕦; 𝕦𝕦; u; u; ) MATHEMATICAL DOUBLE-STRUCK SMALL U +1D567;1D567;1D567;0076;0076; # (𝕧𝕧; 𝕧𝕧; 𝕧𝕧; v; v; ) MATHEMATICAL DOUBLE-STRUCK SMALL V +1D568;1D568;1D568;0077;0077; # (𝕨𝕨; 𝕨𝕨; 𝕨𝕨; w; w; ) MATHEMATICAL DOUBLE-STRUCK SMALL W +1D569;1D569;1D569;0078;0078; # (𝕩𝕩; 𝕩𝕩; 𝕩𝕩; x; x; ) MATHEMATICAL DOUBLE-STRUCK SMALL X +1D56A;1D56A;1D56A;0079;0079; # (𝕪𝕪; 𝕪𝕪; 𝕪𝕪; y; y; ) MATHEMATICAL DOUBLE-STRUCK SMALL Y +1D56B;1D56B;1D56B;007A;007A; # (𝕫𝕫; 𝕫𝕫; 𝕫𝕫; z; z; ) MATHEMATICAL DOUBLE-STRUCK SMALL Z +1D56C;1D56C;1D56C;0041;0041; # (𝕬𝕬; 𝕬𝕬; 𝕬𝕬; A; A; ) MATHEMATICAL BOLD FRAKTUR CAPITAL A +1D56D;1D56D;1D56D;0042;0042; # (𝕭𝕭; 𝕭𝕭; 𝕭𝕭; B; B; ) MATHEMATICAL BOLD FRAKTUR CAPITAL B +1D56E;1D56E;1D56E;0043;0043; # (𝕮𝕮; 𝕮𝕮; 𝕮𝕮; C; C; ) MATHEMATICAL BOLD FRAKTUR CAPITAL C +1D56F;1D56F;1D56F;0044;0044; # (𝕯𝕯; 𝕯𝕯; 𝕯𝕯; D; D; ) MATHEMATICAL BOLD FRAKTUR CAPITAL D +1D570;1D570;1D570;0045;0045; # (𝕰𝕰; 𝕰𝕰; 𝕰𝕰; E; E; ) MATHEMATICAL BOLD FRAKTUR CAPITAL E +1D571;1D571;1D571;0046;0046; # (𝕱𝕱; 𝕱𝕱; 𝕱𝕱; F; F; ) MATHEMATICAL BOLD FRAKTUR CAPITAL F +1D572;1D572;1D572;0047;0047; # (𝕲𝕲; 𝕲𝕲; 𝕲𝕲; G; G; ) MATHEMATICAL BOLD FRAKTUR CAPITAL G +1D573;1D573;1D573;0048;0048; # (𝕳𝕳; 𝕳𝕳; 𝕳𝕳; H; H; ) MATHEMATICAL BOLD FRAKTUR CAPITAL H +1D574;1D574;1D574;0049;0049; # (𝕴𝕴; 𝕴𝕴; 𝕴𝕴; I; I; ) MATHEMATICAL BOLD FRAKTUR CAPITAL I +1D575;1D575;1D575;004A;004A; # (𝕵𝕵; 𝕵𝕵; 𝕵𝕵; J; J; ) MATHEMATICAL BOLD FRAKTUR CAPITAL J +1D576;1D576;1D576;004B;004B; # (𝕶𝕶; 𝕶𝕶; 𝕶𝕶; K; K; ) MATHEMATICAL BOLD FRAKTUR CAPITAL K +1D577;1D577;1D577;004C;004C; # (𝕷𝕷; 𝕷𝕷; 𝕷𝕷; L; L; ) MATHEMATICAL BOLD FRAKTUR CAPITAL L +1D578;1D578;1D578;004D;004D; # (𝕸𝕸; 𝕸𝕸; 𝕸𝕸; M; M; ) MATHEMATICAL BOLD FRAKTUR CAPITAL M +1D579;1D579;1D579;004E;004E; # (𝕹𝕹; 𝕹𝕹; 𝕹𝕹; N; N; ) MATHEMATICAL BOLD FRAKTUR CAPITAL N +1D57A;1D57A;1D57A;004F;004F; # (𝕺𝕺; 𝕺𝕺; 𝕺𝕺; O; O; ) MATHEMATICAL BOLD FRAKTUR CAPITAL O +1D57B;1D57B;1D57B;0050;0050; # (𝕻𝕻; 𝕻𝕻; 𝕻𝕻; P; P; ) MATHEMATICAL BOLD FRAKTUR CAPITAL P +1D57C;1D57C;1D57C;0051;0051; # (𝕼𝕼; 𝕼𝕼; 𝕼𝕼; Q; Q; ) MATHEMATICAL BOLD FRAKTUR CAPITAL Q +1D57D;1D57D;1D57D;0052;0052; # (𝕽𝕽; 𝕽𝕽; 𝕽𝕽; R; R; ) MATHEMATICAL BOLD FRAKTUR CAPITAL R +1D57E;1D57E;1D57E;0053;0053; # (𝕾𝕾; 𝕾𝕾; 𝕾𝕾; S; S; ) MATHEMATICAL BOLD FRAKTUR CAPITAL S +1D57F;1D57F;1D57F;0054;0054; # (𝕿𝕿; 𝕿𝕿; 𝕿𝕿; T; T; ) MATHEMATICAL BOLD FRAKTUR CAPITAL T +1D580;1D580;1D580;0055;0055; # (𝖀𝖀; 𝖀𝖀; 𝖀𝖀; U; U; ) MATHEMATICAL BOLD FRAKTUR CAPITAL U +1D581;1D581;1D581;0056;0056; # (𝖁𝖁; 𝖁𝖁; 𝖁𝖁; V; V; ) MATHEMATICAL BOLD FRAKTUR CAPITAL V +1D582;1D582;1D582;0057;0057; # (𝖂𝖂; 𝖂𝖂; 𝖂𝖂; W; W; ) MATHEMATICAL BOLD FRAKTUR CAPITAL W +1D583;1D583;1D583;0058;0058; # (𝖃𝖃; 𝖃𝖃; 𝖃𝖃; X; X; ) MATHEMATICAL BOLD FRAKTUR CAPITAL X +1D584;1D584;1D584;0059;0059; # (𝖄𝖄; 𝖄𝖄; 𝖄𝖄; Y; Y; ) MATHEMATICAL BOLD FRAKTUR CAPITAL Y +1D585;1D585;1D585;005A;005A; # (𝖅𝖅; 𝖅𝖅; 𝖅𝖅; Z; Z; ) MATHEMATICAL BOLD FRAKTUR CAPITAL Z +1D586;1D586;1D586;0061;0061; # (𝖆𝖆; 𝖆𝖆; 𝖆𝖆; a; a; ) MATHEMATICAL BOLD FRAKTUR SMALL A +1D587;1D587;1D587;0062;0062; # (𝖇𝖇; 𝖇𝖇; 𝖇𝖇; b; b; ) MATHEMATICAL BOLD FRAKTUR SMALL B +1D588;1D588;1D588;0063;0063; # (𝖈𝖈; 𝖈𝖈; 𝖈𝖈; c; c; ) MATHEMATICAL BOLD FRAKTUR SMALL C +1D589;1D589;1D589;0064;0064; # (𝖉𝖉; 𝖉𝖉; 𝖉𝖉; d; d; ) MATHEMATICAL BOLD FRAKTUR SMALL D +1D58A;1D58A;1D58A;0065;0065; # (𝖊𝖊; 𝖊𝖊; 𝖊𝖊; e; e; ) MATHEMATICAL BOLD FRAKTUR SMALL E +1D58B;1D58B;1D58B;0066;0066; # (𝖋𝖋; 𝖋𝖋; 𝖋𝖋; f; f; ) MATHEMATICAL BOLD FRAKTUR SMALL F +1D58C;1D58C;1D58C;0067;0067; # (𝖌𝖌; 𝖌𝖌; 𝖌𝖌; g; g; ) MATHEMATICAL BOLD FRAKTUR SMALL G +1D58D;1D58D;1D58D;0068;0068; # (𝖍𝖍; 𝖍𝖍; 𝖍𝖍; h; h; ) MATHEMATICAL BOLD FRAKTUR SMALL H +1D58E;1D58E;1D58E;0069;0069; # (𝖎𝖎; 𝖎𝖎; 𝖎𝖎; i; i; ) MATHEMATICAL BOLD FRAKTUR SMALL I +1D58F;1D58F;1D58F;006A;006A; # (𝖏𝖏; 𝖏𝖏; 𝖏𝖏; j; j; ) MATHEMATICAL BOLD FRAKTUR SMALL J +1D590;1D590;1D590;006B;006B; # (𝖐𝖐; 𝖐𝖐; 𝖐𝖐; k; k; ) MATHEMATICAL BOLD FRAKTUR SMALL K +1D591;1D591;1D591;006C;006C; # (𝖑𝖑; 𝖑𝖑; 𝖑𝖑; l; l; ) MATHEMATICAL BOLD FRAKTUR SMALL L +1D592;1D592;1D592;006D;006D; # (𝖒𝖒; 𝖒𝖒; 𝖒𝖒; m; m; ) MATHEMATICAL BOLD FRAKTUR SMALL M +1D593;1D593;1D593;006E;006E; # (𝖓𝖓; 𝖓𝖓; 𝖓𝖓; n; n; ) MATHEMATICAL BOLD FRAKTUR SMALL N +1D594;1D594;1D594;006F;006F; # (𝖔𝖔; 𝖔𝖔; 𝖔𝖔; o; o; ) MATHEMATICAL BOLD FRAKTUR SMALL O +1D595;1D595;1D595;0070;0070; # (𝖕𝖕; 𝖕𝖕; 𝖕𝖕; p; p; ) MATHEMATICAL BOLD FRAKTUR SMALL P +1D596;1D596;1D596;0071;0071; # (𝖖𝖖; 𝖖𝖖; 𝖖𝖖; q; q; ) MATHEMATICAL BOLD FRAKTUR SMALL Q +1D597;1D597;1D597;0072;0072; # (𝖗𝖗; 𝖗𝖗; 𝖗𝖗; r; r; ) MATHEMATICAL BOLD FRAKTUR SMALL R +1D598;1D598;1D598;0073;0073; # (𝖘𝖘; 𝖘𝖘; 𝖘𝖘; s; s; ) MATHEMATICAL BOLD FRAKTUR SMALL S +1D599;1D599;1D599;0074;0074; # (𝖙𝖙; 𝖙𝖙; 𝖙𝖙; t; t; ) MATHEMATICAL BOLD FRAKTUR SMALL T +1D59A;1D59A;1D59A;0075;0075; # (𝖚𝖚; 𝖚𝖚; 𝖚𝖚; u; u; ) MATHEMATICAL BOLD FRAKTUR SMALL U +1D59B;1D59B;1D59B;0076;0076; # (𝖛𝖛; 𝖛𝖛; 𝖛𝖛; v; v; ) MATHEMATICAL BOLD FRAKTUR SMALL V +1D59C;1D59C;1D59C;0077;0077; # (𝖜𝖜; 𝖜𝖜; 𝖜𝖜; w; w; ) MATHEMATICAL BOLD FRAKTUR SMALL W +1D59D;1D59D;1D59D;0078;0078; # (𝖝𝖝; 𝖝𝖝; 𝖝𝖝; x; x; ) MATHEMATICAL BOLD FRAKTUR SMALL X +1D59E;1D59E;1D59E;0079;0079; # (𝖞𝖞; 𝖞𝖞; 𝖞𝖞; y; y; ) MATHEMATICAL BOLD FRAKTUR SMALL Y +1D59F;1D59F;1D59F;007A;007A; # (𝖟𝖟; 𝖟𝖟; 𝖟𝖟; z; z; ) MATHEMATICAL BOLD FRAKTUR SMALL Z +1D5A0;1D5A0;1D5A0;0041;0041; # (𝖠𝖠; 𝖠𝖠; 𝖠𝖠; A; A; ) MATHEMATICAL SANS-SERIF CAPITAL A +1D5A1;1D5A1;1D5A1;0042;0042; # (𝖡𝖡; 𝖡𝖡; 𝖡𝖡; B; B; ) MATHEMATICAL SANS-SERIF CAPITAL B +1D5A2;1D5A2;1D5A2;0043;0043; # (𝖢𝖢; 𝖢𝖢; 𝖢𝖢; C; C; ) MATHEMATICAL SANS-SERIF CAPITAL C +1D5A3;1D5A3;1D5A3;0044;0044; # (𝖣𝖣; 𝖣𝖣; 𝖣𝖣; D; D; ) MATHEMATICAL SANS-SERIF CAPITAL D +1D5A4;1D5A4;1D5A4;0045;0045; # (𝖤𝖤; 𝖤𝖤; 𝖤𝖤; E; E; ) MATHEMATICAL SANS-SERIF CAPITAL E +1D5A5;1D5A5;1D5A5;0046;0046; # (𝖥𝖥; 𝖥𝖥; 𝖥𝖥; F; F; ) MATHEMATICAL SANS-SERIF CAPITAL F +1D5A6;1D5A6;1D5A6;0047;0047; # (𝖦𝖦; 𝖦𝖦; 𝖦𝖦; G; G; ) MATHEMATICAL SANS-SERIF CAPITAL G +1D5A7;1D5A7;1D5A7;0048;0048; # (𝖧𝖧; 𝖧𝖧; 𝖧𝖧; H; H; ) MATHEMATICAL SANS-SERIF CAPITAL H +1D5A8;1D5A8;1D5A8;0049;0049; # (𝖨𝖨; 𝖨𝖨; 𝖨𝖨; I; I; ) MATHEMATICAL SANS-SERIF CAPITAL I +1D5A9;1D5A9;1D5A9;004A;004A; # (𝖩𝖩; 𝖩𝖩; 𝖩𝖩; J; J; ) MATHEMATICAL SANS-SERIF CAPITAL J +1D5AA;1D5AA;1D5AA;004B;004B; # (𝖪𝖪; 𝖪𝖪; 𝖪𝖪; K; K; ) MATHEMATICAL SANS-SERIF CAPITAL K +1D5AB;1D5AB;1D5AB;004C;004C; # (𝖫𝖫; 𝖫𝖫; 𝖫𝖫; L; L; ) MATHEMATICAL SANS-SERIF CAPITAL L +1D5AC;1D5AC;1D5AC;004D;004D; # (𝖬𝖬; 𝖬𝖬; 𝖬𝖬; M; M; ) MATHEMATICAL SANS-SERIF CAPITAL M +1D5AD;1D5AD;1D5AD;004E;004E; # (𝖭𝖭; 𝖭𝖭; 𝖭𝖭; N; N; ) MATHEMATICAL SANS-SERIF CAPITAL N +1D5AE;1D5AE;1D5AE;004F;004F; # (𝖮𝖮; 𝖮𝖮; 𝖮𝖮; O; O; ) MATHEMATICAL SANS-SERIF CAPITAL O +1D5AF;1D5AF;1D5AF;0050;0050; # (𝖯𝖯; 𝖯𝖯; 𝖯𝖯; P; P; ) MATHEMATICAL SANS-SERIF CAPITAL P +1D5B0;1D5B0;1D5B0;0051;0051; # (𝖰𝖰; 𝖰𝖰; 𝖰𝖰; Q; Q; ) MATHEMATICAL SANS-SERIF CAPITAL Q +1D5B1;1D5B1;1D5B1;0052;0052; # (𝖱𝖱; 𝖱𝖱; 𝖱𝖱; R; R; ) MATHEMATICAL SANS-SERIF CAPITAL R +1D5B2;1D5B2;1D5B2;0053;0053; # (𝖲𝖲; 𝖲𝖲; 𝖲𝖲; S; S; ) MATHEMATICAL SANS-SERIF CAPITAL S +1D5B3;1D5B3;1D5B3;0054;0054; # (𝖳𝖳; 𝖳𝖳; 𝖳𝖳; T; T; ) MATHEMATICAL SANS-SERIF CAPITAL T +1D5B4;1D5B4;1D5B4;0055;0055; # (𝖴𝖴; 𝖴𝖴; 𝖴𝖴; U; U; ) MATHEMATICAL SANS-SERIF CAPITAL U +1D5B5;1D5B5;1D5B5;0056;0056; # (𝖵𝖵; 𝖵𝖵; 𝖵𝖵; V; V; ) MATHEMATICAL SANS-SERIF CAPITAL V +1D5B6;1D5B6;1D5B6;0057;0057; # (𝖶𝖶; 𝖶𝖶; 𝖶𝖶; W; W; ) MATHEMATICAL SANS-SERIF CAPITAL W +1D5B7;1D5B7;1D5B7;0058;0058; # (𝖷𝖷; 𝖷𝖷; 𝖷𝖷; X; X; ) MATHEMATICAL SANS-SERIF CAPITAL X +1D5B8;1D5B8;1D5B8;0059;0059; # (𝖸𝖸; 𝖸𝖸; 𝖸𝖸; Y; Y; ) MATHEMATICAL SANS-SERIF CAPITAL Y +1D5B9;1D5B9;1D5B9;005A;005A; # (𝖹𝖹; 𝖹𝖹; 𝖹𝖹; Z; Z; ) MATHEMATICAL SANS-SERIF CAPITAL Z +1D5BA;1D5BA;1D5BA;0061;0061; # (𝖺𝖺; 𝖺𝖺; 𝖺𝖺; a; a; ) MATHEMATICAL SANS-SERIF SMALL A +1D5BB;1D5BB;1D5BB;0062;0062; # (𝖻𝖻; 𝖻𝖻; 𝖻𝖻; b; b; ) MATHEMATICAL SANS-SERIF SMALL B +1D5BC;1D5BC;1D5BC;0063;0063; # (𝖼𝖼; 𝖼𝖼; 𝖼𝖼; c; c; ) MATHEMATICAL SANS-SERIF SMALL C +1D5BD;1D5BD;1D5BD;0064;0064; # (𝖽𝖽; 𝖽𝖽; 𝖽𝖽; d; d; ) MATHEMATICAL SANS-SERIF SMALL D +1D5BE;1D5BE;1D5BE;0065;0065; # (𝖾𝖾; 𝖾𝖾; 𝖾𝖾; e; e; ) MATHEMATICAL SANS-SERIF SMALL E +1D5BF;1D5BF;1D5BF;0066;0066; # (𝖿𝖿; 𝖿𝖿; 𝖿𝖿; f; f; ) MATHEMATICAL SANS-SERIF SMALL F +1D5C0;1D5C0;1D5C0;0067;0067; # (𝗀𝗀; 𝗀𝗀; 𝗀𝗀; g; g; ) MATHEMATICAL SANS-SERIF SMALL G +1D5C1;1D5C1;1D5C1;0068;0068; # (𝗁𝗁; 𝗁𝗁; 𝗁𝗁; h; h; ) MATHEMATICAL SANS-SERIF SMALL H +1D5C2;1D5C2;1D5C2;0069;0069; # (𝗂𝗂; 𝗂𝗂; 𝗂𝗂; i; i; ) MATHEMATICAL SANS-SERIF SMALL I +1D5C3;1D5C3;1D5C3;006A;006A; # (𝗃𝗃; 𝗃𝗃; 𝗃𝗃; j; j; ) MATHEMATICAL SANS-SERIF SMALL J +1D5C4;1D5C4;1D5C4;006B;006B; # (𝗄𝗄; 𝗄𝗄; 𝗄𝗄; k; k; ) MATHEMATICAL SANS-SERIF SMALL K +1D5C5;1D5C5;1D5C5;006C;006C; # (𝗅𝗅; 𝗅𝗅; 𝗅𝗅; l; l; ) MATHEMATICAL SANS-SERIF SMALL L +1D5C6;1D5C6;1D5C6;006D;006D; # (𝗆𝗆; 𝗆𝗆; 𝗆𝗆; m; m; ) MATHEMATICAL SANS-SERIF SMALL M +1D5C7;1D5C7;1D5C7;006E;006E; # (𝗇𝗇; 𝗇𝗇; 𝗇𝗇; n; n; ) MATHEMATICAL SANS-SERIF SMALL N +1D5C8;1D5C8;1D5C8;006F;006F; # (𝗈𝗈; 𝗈𝗈; 𝗈𝗈; o; o; ) MATHEMATICAL SANS-SERIF SMALL O +1D5C9;1D5C9;1D5C9;0070;0070; # (𝗉𝗉; 𝗉𝗉; 𝗉𝗉; p; p; ) MATHEMATICAL SANS-SERIF SMALL P +1D5CA;1D5CA;1D5CA;0071;0071; # (𝗊𝗊; 𝗊𝗊; 𝗊𝗊; q; q; ) MATHEMATICAL SANS-SERIF SMALL Q +1D5CB;1D5CB;1D5CB;0072;0072; # (𝗋𝗋; 𝗋𝗋; 𝗋𝗋; r; r; ) MATHEMATICAL SANS-SERIF SMALL R +1D5CC;1D5CC;1D5CC;0073;0073; # (𝗌𝗌; 𝗌𝗌; 𝗌𝗌; s; s; ) MATHEMATICAL SANS-SERIF SMALL S +1D5CD;1D5CD;1D5CD;0074;0074; # (𝗍𝗍; 𝗍𝗍; 𝗍𝗍; t; t; ) MATHEMATICAL SANS-SERIF SMALL T +1D5CE;1D5CE;1D5CE;0075;0075; # (𝗎𝗎; 𝗎𝗎; 𝗎𝗎; u; u; ) MATHEMATICAL SANS-SERIF SMALL U +1D5CF;1D5CF;1D5CF;0076;0076; # (𝗏𝗏; 𝗏𝗏; 𝗏𝗏; v; v; ) MATHEMATICAL SANS-SERIF SMALL V +1D5D0;1D5D0;1D5D0;0077;0077; # (𝗐𝗐; 𝗐𝗐; 𝗐𝗐; w; w; ) MATHEMATICAL SANS-SERIF SMALL W +1D5D1;1D5D1;1D5D1;0078;0078; # (𝗑𝗑; 𝗑𝗑; 𝗑𝗑; x; x; ) MATHEMATICAL SANS-SERIF SMALL X +1D5D2;1D5D2;1D5D2;0079;0079; # (𝗒𝗒; 𝗒𝗒; 𝗒𝗒; y; y; ) MATHEMATICAL SANS-SERIF SMALL Y +1D5D3;1D5D3;1D5D3;007A;007A; # (𝗓𝗓; 𝗓𝗓; 𝗓𝗓; z; z; ) MATHEMATICAL SANS-SERIF SMALL Z +1D5D4;1D5D4;1D5D4;0041;0041; # (𝗔𝗔; 𝗔𝗔; 𝗔𝗔; A; A; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL A +1D5D5;1D5D5;1D5D5;0042;0042; # (𝗕𝗕; 𝗕𝗕; 𝗕𝗕; B; B; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL B +1D5D6;1D5D6;1D5D6;0043;0043; # (𝗖𝗖; 𝗖𝗖; 𝗖𝗖; C; C; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL C +1D5D7;1D5D7;1D5D7;0044;0044; # (𝗗𝗗; 𝗗𝗗; 𝗗𝗗; D; D; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL D +1D5D8;1D5D8;1D5D8;0045;0045; # (𝗘𝗘; 𝗘𝗘; 𝗘𝗘; E; E; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL E +1D5D9;1D5D9;1D5D9;0046;0046; # (𝗙𝗙; 𝗙𝗙; 𝗙𝗙; F; F; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL F +1D5DA;1D5DA;1D5DA;0047;0047; # (𝗚𝗚; 𝗚𝗚; 𝗚𝗚; G; G; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL G +1D5DB;1D5DB;1D5DB;0048;0048; # (𝗛𝗛; 𝗛𝗛; 𝗛𝗛; H; H; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL H +1D5DC;1D5DC;1D5DC;0049;0049; # (𝗜𝗜; 𝗜𝗜; 𝗜𝗜; I; I; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL I +1D5DD;1D5DD;1D5DD;004A;004A; # (𝗝𝗝; 𝗝𝗝; 𝗝𝗝; J; J; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL J +1D5DE;1D5DE;1D5DE;004B;004B; # (𝗞𝗞; 𝗞𝗞; 𝗞𝗞; K; K; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL K +1D5DF;1D5DF;1D5DF;004C;004C; # (𝗟𝗟; 𝗟𝗟; 𝗟𝗟; L; L; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL L +1D5E0;1D5E0;1D5E0;004D;004D; # (𝗠𝗠; 𝗠𝗠; 𝗠𝗠; M; M; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL M +1D5E1;1D5E1;1D5E1;004E;004E; # (𝗡𝗡; 𝗡𝗡; 𝗡𝗡; N; N; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL N +1D5E2;1D5E2;1D5E2;004F;004F; # (𝗢𝗢; 𝗢𝗢; 𝗢𝗢; O; O; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL O +1D5E3;1D5E3;1D5E3;0050;0050; # (𝗣𝗣; 𝗣𝗣; 𝗣𝗣; P; P; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL P +1D5E4;1D5E4;1D5E4;0051;0051; # (𝗤𝗤; 𝗤𝗤; 𝗤𝗤; Q; Q; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Q +1D5E5;1D5E5;1D5E5;0052;0052; # (𝗥𝗥; 𝗥𝗥; 𝗥𝗥; R; R; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL R +1D5E6;1D5E6;1D5E6;0053;0053; # (𝗦𝗦; 𝗦𝗦; 𝗦𝗦; S; S; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL S +1D5E7;1D5E7;1D5E7;0054;0054; # (𝗧𝗧; 𝗧𝗧; 𝗧𝗧; T; T; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL T +1D5E8;1D5E8;1D5E8;0055;0055; # (𝗨𝗨; 𝗨𝗨; 𝗨𝗨; U; U; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL U +1D5E9;1D5E9;1D5E9;0056;0056; # (𝗩𝗩; 𝗩𝗩; 𝗩𝗩; V; V; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL V +1D5EA;1D5EA;1D5EA;0057;0057; # (𝗪𝗪; 𝗪𝗪; 𝗪𝗪; W; W; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL W +1D5EB;1D5EB;1D5EB;0058;0058; # (𝗫𝗫; 𝗫𝗫; 𝗫𝗫; X; X; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL X +1D5EC;1D5EC;1D5EC;0059;0059; # (𝗬𝗬; 𝗬𝗬; 𝗬𝗬; Y; Y; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Y +1D5ED;1D5ED;1D5ED;005A;005A; # (𝗭𝗭; 𝗭𝗭; 𝗭𝗭; Z; Z; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Z +1D5EE;1D5EE;1D5EE;0061;0061; # (𝗮𝗮; 𝗮𝗮; 𝗮𝗮; a; a; ) MATHEMATICAL SANS-SERIF BOLD SMALL A +1D5EF;1D5EF;1D5EF;0062;0062; # (𝗯𝗯; 𝗯𝗯; 𝗯𝗯; b; b; ) MATHEMATICAL SANS-SERIF BOLD SMALL B +1D5F0;1D5F0;1D5F0;0063;0063; # (𝗰𝗰; 𝗰𝗰; 𝗰𝗰; c; c; ) MATHEMATICAL SANS-SERIF BOLD SMALL C +1D5F1;1D5F1;1D5F1;0064;0064; # (𝗱𝗱; 𝗱𝗱; 𝗱𝗱; d; d; ) MATHEMATICAL SANS-SERIF BOLD SMALL D +1D5F2;1D5F2;1D5F2;0065;0065; # (𝗲𝗲; 𝗲𝗲; 𝗲𝗲; e; e; ) MATHEMATICAL SANS-SERIF BOLD SMALL E +1D5F3;1D5F3;1D5F3;0066;0066; # (𝗳𝗳; 𝗳𝗳; 𝗳𝗳; f; f; ) MATHEMATICAL SANS-SERIF BOLD SMALL F +1D5F4;1D5F4;1D5F4;0067;0067; # (𝗴𝗴; 𝗴𝗴; 𝗴𝗴; g; g; ) MATHEMATICAL SANS-SERIF BOLD SMALL G +1D5F5;1D5F5;1D5F5;0068;0068; # (𝗵𝗵; 𝗵𝗵; 𝗵𝗵; h; h; ) MATHEMATICAL SANS-SERIF BOLD SMALL H +1D5F6;1D5F6;1D5F6;0069;0069; # (𝗶𝗶; 𝗶𝗶; 𝗶𝗶; i; i; ) MATHEMATICAL SANS-SERIF BOLD SMALL I +1D5F7;1D5F7;1D5F7;006A;006A; # (𝗷𝗷; 𝗷𝗷; 𝗷𝗷; j; j; ) MATHEMATICAL SANS-SERIF BOLD SMALL J +1D5F8;1D5F8;1D5F8;006B;006B; # (𝗸𝗸; 𝗸𝗸; 𝗸𝗸; k; k; ) MATHEMATICAL SANS-SERIF BOLD SMALL K +1D5F9;1D5F9;1D5F9;006C;006C; # (𝗹𝗹; 𝗹𝗹; 𝗹𝗹; l; l; ) MATHEMATICAL SANS-SERIF BOLD SMALL L +1D5FA;1D5FA;1D5FA;006D;006D; # (𝗺𝗺; 𝗺𝗺; 𝗺𝗺; m; m; ) MATHEMATICAL SANS-SERIF BOLD SMALL M +1D5FB;1D5FB;1D5FB;006E;006E; # (𝗻𝗻; 𝗻𝗻; 𝗻𝗻; n; n; ) MATHEMATICAL SANS-SERIF BOLD SMALL N +1D5FC;1D5FC;1D5FC;006F;006F; # (𝗼𝗼; 𝗼𝗼; 𝗼𝗼; o; o; ) MATHEMATICAL SANS-SERIF BOLD SMALL O +1D5FD;1D5FD;1D5FD;0070;0070; # (𝗽𝗽; 𝗽𝗽; 𝗽𝗽; p; p; ) MATHEMATICAL SANS-SERIF BOLD SMALL P +1D5FE;1D5FE;1D5FE;0071;0071; # (𝗾𝗾; 𝗾𝗾; 𝗾𝗾; q; q; ) MATHEMATICAL SANS-SERIF BOLD SMALL Q +1D5FF;1D5FF;1D5FF;0072;0072; # (𝗿𝗿; 𝗿𝗿; 𝗿𝗿; r; r; ) MATHEMATICAL SANS-SERIF BOLD SMALL R +1D600;1D600;1D600;0073;0073; # (𝘀𝘀; 𝘀𝘀; 𝘀𝘀; s; s; ) MATHEMATICAL SANS-SERIF BOLD SMALL S +1D601;1D601;1D601;0074;0074; # (𝘁𝘁; 𝘁𝘁; 𝘁𝘁; t; t; ) MATHEMATICAL SANS-SERIF BOLD SMALL T +1D602;1D602;1D602;0075;0075; # (𝘂𝘂; 𝘂𝘂; 𝘂𝘂; u; u; ) MATHEMATICAL SANS-SERIF BOLD SMALL U +1D603;1D603;1D603;0076;0076; # (𝘃𝘃; 𝘃𝘃; 𝘃𝘃; v; v; ) MATHEMATICAL SANS-SERIF BOLD SMALL V +1D604;1D604;1D604;0077;0077; # (𝘄𝘄; 𝘄𝘄; 𝘄𝘄; w; w; ) MATHEMATICAL SANS-SERIF BOLD SMALL W +1D605;1D605;1D605;0078;0078; # (𝘅𝘅; 𝘅𝘅; 𝘅𝘅; x; x; ) MATHEMATICAL SANS-SERIF BOLD SMALL X +1D606;1D606;1D606;0079;0079; # (𝘆𝘆; 𝘆𝘆; 𝘆𝘆; y; y; ) MATHEMATICAL SANS-SERIF BOLD SMALL Y +1D607;1D607;1D607;007A;007A; # (𝘇𝘇; 𝘇𝘇; 𝘇𝘇; z; z; ) MATHEMATICAL SANS-SERIF BOLD SMALL Z +1D608;1D608;1D608;0041;0041; # (𝘈𝘈; 𝘈𝘈; 𝘈𝘈; A; A; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL A +1D609;1D609;1D609;0042;0042; # (𝘉𝘉; 𝘉𝘉; 𝘉𝘉; B; B; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL B +1D60A;1D60A;1D60A;0043;0043; # (𝘊𝘊; 𝘊𝘊; 𝘊𝘊; C; C; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL C +1D60B;1D60B;1D60B;0044;0044; # (𝘋𝘋; 𝘋𝘋; 𝘋𝘋; D; D; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL D +1D60C;1D60C;1D60C;0045;0045; # (𝘌𝘌; 𝘌𝘌; 𝘌𝘌; E; E; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL E +1D60D;1D60D;1D60D;0046;0046; # (𝘍𝘍; 𝘍𝘍; 𝘍𝘍; F; F; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL F +1D60E;1D60E;1D60E;0047;0047; # (𝘎𝘎; 𝘎𝘎; 𝘎𝘎; G; G; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL G +1D60F;1D60F;1D60F;0048;0048; # (𝘏𝘏; 𝘏𝘏; 𝘏𝘏; H; H; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL H +1D610;1D610;1D610;0049;0049; # (𝘐𝘐; 𝘐𝘐; 𝘐𝘐; I; I; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL I +1D611;1D611;1D611;004A;004A; # (𝘑𝘑; 𝘑𝘑; 𝘑𝘑; J; J; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL J +1D612;1D612;1D612;004B;004B; # (𝘒𝘒; 𝘒𝘒; 𝘒𝘒; K; K; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL K +1D613;1D613;1D613;004C;004C; # (𝘓𝘓; 𝘓𝘓; 𝘓𝘓; L; L; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL L +1D614;1D614;1D614;004D;004D; # (𝘔𝘔; 𝘔𝘔; 𝘔𝘔; M; M; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL M +1D615;1D615;1D615;004E;004E; # (𝘕𝘕; 𝘕𝘕; 𝘕𝘕; N; N; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL N +1D616;1D616;1D616;004F;004F; # (𝘖𝘖; 𝘖𝘖; 𝘖𝘖; O; O; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL O +1D617;1D617;1D617;0050;0050; # (𝘗𝘗; 𝘗𝘗; 𝘗𝘗; P; P; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL P +1D618;1D618;1D618;0051;0051; # (𝘘𝘘; 𝘘𝘘; 𝘘𝘘; Q; Q; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q +1D619;1D619;1D619;0052;0052; # (𝘙𝘙; 𝘙𝘙; 𝘙𝘙; R; R; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL R +1D61A;1D61A;1D61A;0053;0053; # (𝘚𝘚; 𝘚𝘚; 𝘚𝘚; S; S; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL S +1D61B;1D61B;1D61B;0054;0054; # (𝘛𝘛; 𝘛𝘛; 𝘛𝘛; T; T; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL T +1D61C;1D61C;1D61C;0055;0055; # (𝘜𝘜; 𝘜𝘜; 𝘜𝘜; U; U; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL U +1D61D;1D61D;1D61D;0056;0056; # (𝘝𝘝; 𝘝𝘝; 𝘝𝘝; V; V; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL V +1D61E;1D61E;1D61E;0057;0057; # (𝘞𝘞; 𝘞𝘞; 𝘞𝘞; W; W; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL W +1D61F;1D61F;1D61F;0058;0058; # (𝘟𝘟; 𝘟𝘟; 𝘟𝘟; X; X; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL X +1D620;1D620;1D620;0059;0059; # (𝘠𝘠; 𝘠𝘠; 𝘠𝘠; Y; Y; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y +1D621;1D621;1D621;005A;005A; # (𝘡𝘡; 𝘡𝘡; 𝘡𝘡; Z; Z; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z +1D622;1D622;1D622;0061;0061; # (𝘢𝘢; 𝘢𝘢; 𝘢𝘢; a; a; ) MATHEMATICAL SANS-SERIF ITALIC SMALL A +1D623;1D623;1D623;0062;0062; # (𝘣𝘣; 𝘣𝘣; 𝘣𝘣; b; b; ) MATHEMATICAL SANS-SERIF ITALIC SMALL B +1D624;1D624;1D624;0063;0063; # (𝘤𝘤; 𝘤𝘤; 𝘤𝘤; c; c; ) MATHEMATICAL SANS-SERIF ITALIC SMALL C +1D625;1D625;1D625;0064;0064; # (𝘥𝘥; 𝘥𝘥; 𝘥𝘥; d; d; ) MATHEMATICAL SANS-SERIF ITALIC SMALL D +1D626;1D626;1D626;0065;0065; # (𝘦𝘦; 𝘦𝘦; 𝘦𝘦; e; e; ) MATHEMATICAL SANS-SERIF ITALIC SMALL E +1D627;1D627;1D627;0066;0066; # (𝘧𝘧; 𝘧𝘧; 𝘧𝘧; f; f; ) MATHEMATICAL SANS-SERIF ITALIC SMALL F +1D628;1D628;1D628;0067;0067; # (𝘨𝘨; 𝘨𝘨; 𝘨𝘨; g; g; ) MATHEMATICAL SANS-SERIF ITALIC SMALL G +1D629;1D629;1D629;0068;0068; # (𝘩𝘩; 𝘩𝘩; 𝘩𝘩; h; h; ) MATHEMATICAL SANS-SERIF ITALIC SMALL H +1D62A;1D62A;1D62A;0069;0069; # (𝘪𝘪; 𝘪𝘪; 𝘪𝘪; i; i; ) MATHEMATICAL SANS-SERIF ITALIC SMALL I +1D62B;1D62B;1D62B;006A;006A; # (𝘫𝘫; 𝘫𝘫; 𝘫𝘫; j; j; ) MATHEMATICAL SANS-SERIF ITALIC SMALL J +1D62C;1D62C;1D62C;006B;006B; # (𝘬𝘬; 𝘬𝘬; 𝘬𝘬; k; k; ) MATHEMATICAL SANS-SERIF ITALIC SMALL K +1D62D;1D62D;1D62D;006C;006C; # (𝘭𝘭; 𝘭𝘭; 𝘭𝘭; l; l; ) MATHEMATICAL SANS-SERIF ITALIC SMALL L +1D62E;1D62E;1D62E;006D;006D; # (𝘮𝘮; 𝘮𝘮; 𝘮𝘮; m; m; ) MATHEMATICAL SANS-SERIF ITALIC SMALL M +1D62F;1D62F;1D62F;006E;006E; # (𝘯𝘯; 𝘯𝘯; 𝘯𝘯; n; n; ) MATHEMATICAL SANS-SERIF ITALIC SMALL N +1D630;1D630;1D630;006F;006F; # (𝘰𝘰; 𝘰𝘰; 𝘰𝘰; o; o; ) MATHEMATICAL SANS-SERIF ITALIC SMALL O +1D631;1D631;1D631;0070;0070; # (𝘱𝘱; 𝘱𝘱; 𝘱𝘱; p; p; ) MATHEMATICAL SANS-SERIF ITALIC SMALL P +1D632;1D632;1D632;0071;0071; # (𝘲𝘲; 𝘲𝘲; 𝘲𝘲; q; q; ) MATHEMATICAL SANS-SERIF ITALIC SMALL Q +1D633;1D633;1D633;0072;0072; # (𝘳𝘳; 𝘳𝘳; 𝘳𝘳; r; r; ) MATHEMATICAL SANS-SERIF ITALIC SMALL R +1D634;1D634;1D634;0073;0073; # (𝘴𝘴; 𝘴𝘴; 𝘴𝘴; s; s; ) MATHEMATICAL SANS-SERIF ITALIC SMALL S +1D635;1D635;1D635;0074;0074; # (𝘵𝘵; 𝘵𝘵; 𝘵𝘵; t; t; ) MATHEMATICAL SANS-SERIF ITALIC SMALL T +1D636;1D636;1D636;0075;0075; # (𝘶𝘶; 𝘶𝘶; 𝘶𝘶; u; u; ) MATHEMATICAL SANS-SERIF ITALIC SMALL U +1D637;1D637;1D637;0076;0076; # (𝘷𝘷; 𝘷𝘷; 𝘷𝘷; v; v; ) MATHEMATICAL SANS-SERIF ITALIC SMALL V +1D638;1D638;1D638;0077;0077; # (𝘸𝘸; 𝘸𝘸; 𝘸𝘸; w; w; ) MATHEMATICAL SANS-SERIF ITALIC SMALL W +1D639;1D639;1D639;0078;0078; # (𝘹𝘹; 𝘹𝘹; 𝘹𝘹; x; x; ) MATHEMATICAL SANS-SERIF ITALIC SMALL X +1D63A;1D63A;1D63A;0079;0079; # (𝘺𝘺; 𝘺𝘺; 𝘺𝘺; y; y; ) MATHEMATICAL SANS-SERIF ITALIC SMALL Y +1D63B;1D63B;1D63B;007A;007A; # (𝘻𝘻; 𝘻𝘻; 𝘻𝘻; z; z; ) MATHEMATICAL SANS-SERIF ITALIC SMALL Z +1D63C;1D63C;1D63C;0041;0041; # (𝘼𝘼; 𝘼𝘼; 𝘼𝘼; A; A; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A +1D63D;1D63D;1D63D;0042;0042; # (𝘽𝘽; 𝘽𝘽; 𝘽𝘽; B; B; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B +1D63E;1D63E;1D63E;0043;0043; # (𝘾𝘾; 𝘾𝘾; 𝘾𝘾; C; C; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C +1D63F;1D63F;1D63F;0044;0044; # (𝘿𝘿; 𝘿𝘿; 𝘿𝘿; D; D; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D +1D640;1D640;1D640;0045;0045; # (𝙀𝙀; 𝙀𝙀; 𝙀𝙀; E; E; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E +1D641;1D641;1D641;0046;0046; # (𝙁𝙁; 𝙁𝙁; 𝙁𝙁; F; F; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F +1D642;1D642;1D642;0047;0047; # (𝙂𝙂; 𝙂𝙂; 𝙂𝙂; G; G; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G +1D643;1D643;1D643;0048;0048; # (𝙃𝙃; 𝙃𝙃; 𝙃𝙃; H; H; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H +1D644;1D644;1D644;0049;0049; # (𝙄𝙄; 𝙄𝙄; 𝙄𝙄; I; I; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I +1D645;1D645;1D645;004A;004A; # (𝙅𝙅; 𝙅𝙅; 𝙅𝙅; J; J; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J +1D646;1D646;1D646;004B;004B; # (𝙆𝙆; 𝙆𝙆; 𝙆𝙆; K; K; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K +1D647;1D647;1D647;004C;004C; # (𝙇𝙇; 𝙇𝙇; 𝙇𝙇; L; L; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L +1D648;1D648;1D648;004D;004D; # (𝙈𝙈; 𝙈𝙈; 𝙈𝙈; M; M; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M +1D649;1D649;1D649;004E;004E; # (𝙉𝙉; 𝙉𝙉; 𝙉𝙉; N; N; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N +1D64A;1D64A;1D64A;004F;004F; # (𝙊𝙊; 𝙊𝙊; 𝙊𝙊; O; O; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O +1D64B;1D64B;1D64B;0050;0050; # (𝙋𝙋; 𝙋𝙋; 𝙋𝙋; P; P; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P +1D64C;1D64C;1D64C;0051;0051; # (𝙌𝙌; 𝙌𝙌; 𝙌𝙌; Q; Q; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q +1D64D;1D64D;1D64D;0052;0052; # (𝙍𝙍; 𝙍𝙍; 𝙍𝙍; R; R; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R +1D64E;1D64E;1D64E;0053;0053; # (𝙎𝙎; 𝙎𝙎; 𝙎𝙎; S; S; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S +1D64F;1D64F;1D64F;0054;0054; # (𝙏𝙏; 𝙏𝙏; 𝙏𝙏; T; T; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T +1D650;1D650;1D650;0055;0055; # (𝙐𝙐; 𝙐𝙐; 𝙐𝙐; U; U; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U +1D651;1D651;1D651;0056;0056; # (𝙑𝙑; 𝙑𝙑; 𝙑𝙑; V; V; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V +1D652;1D652;1D652;0057;0057; # (𝙒𝙒; 𝙒𝙒; 𝙒𝙒; W; W; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W +1D653;1D653;1D653;0058;0058; # (𝙓𝙓; 𝙓𝙓; 𝙓𝙓; X; X; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X +1D654;1D654;1D654;0059;0059; # (𝙔𝙔; 𝙔𝙔; 𝙔𝙔; Y; Y; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y +1D655;1D655;1D655;005A;005A; # (𝙕𝙕; 𝙕𝙕; 𝙕𝙕; Z; Z; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z +1D656;1D656;1D656;0061;0061; # (𝙖𝙖; 𝙖𝙖; 𝙖𝙖; a; a; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A +1D657;1D657;1D657;0062;0062; # (𝙗𝙗; 𝙗𝙗; 𝙗𝙗; b; b; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B +1D658;1D658;1D658;0063;0063; # (𝙘𝙘; 𝙘𝙘; 𝙘𝙘; c; c; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C +1D659;1D659;1D659;0064;0064; # (𝙙𝙙; 𝙙𝙙; 𝙙𝙙; d; d; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D +1D65A;1D65A;1D65A;0065;0065; # (𝙚𝙚; 𝙚𝙚; 𝙚𝙚; e; e; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E +1D65B;1D65B;1D65B;0066;0066; # (𝙛𝙛; 𝙛𝙛; 𝙛𝙛; f; f; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F +1D65C;1D65C;1D65C;0067;0067; # (𝙜𝙜; 𝙜𝙜; 𝙜𝙜; g; g; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G +1D65D;1D65D;1D65D;0068;0068; # (𝙝𝙝; 𝙝𝙝; 𝙝𝙝; h; h; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H +1D65E;1D65E;1D65E;0069;0069; # (𝙞𝙞; 𝙞𝙞; 𝙞𝙞; i; i; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I +1D65F;1D65F;1D65F;006A;006A; # (𝙟𝙟; 𝙟𝙟; 𝙟𝙟; j; j; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J +1D660;1D660;1D660;006B;006B; # (𝙠𝙠; 𝙠𝙠; 𝙠𝙠; k; k; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K +1D661;1D661;1D661;006C;006C; # (𝙡𝙡; 𝙡𝙡; 𝙡𝙡; l; l; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L +1D662;1D662;1D662;006D;006D; # (𝙢𝙢; 𝙢𝙢; 𝙢𝙢; m; m; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M +1D663;1D663;1D663;006E;006E; # (𝙣𝙣; 𝙣𝙣; 𝙣𝙣; n; n; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N +1D664;1D664;1D664;006F;006F; # (𝙤𝙤; 𝙤𝙤; 𝙤𝙤; o; o; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O +1D665;1D665;1D665;0070;0070; # (𝙥𝙥; 𝙥𝙥; 𝙥𝙥; p; p; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P +1D666;1D666;1D666;0071;0071; # (𝙦𝙦; 𝙦𝙦; 𝙦𝙦; q; q; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q +1D667;1D667;1D667;0072;0072; # (𝙧𝙧; 𝙧𝙧; 𝙧𝙧; r; r; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R +1D668;1D668;1D668;0073;0073; # (𝙨𝙨; 𝙨𝙨; 𝙨𝙨; s; s; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S +1D669;1D669;1D669;0074;0074; # (𝙩𝙩; 𝙩𝙩; 𝙩𝙩; t; t; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T +1D66A;1D66A;1D66A;0075;0075; # (𝙪𝙪; 𝙪𝙪; 𝙪𝙪; u; u; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U +1D66B;1D66B;1D66B;0076;0076; # (𝙫𝙫; 𝙫𝙫; 𝙫𝙫; v; v; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V +1D66C;1D66C;1D66C;0077;0077; # (𝙬𝙬; 𝙬𝙬; 𝙬𝙬; w; w; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W +1D66D;1D66D;1D66D;0078;0078; # (𝙭𝙭; 𝙭𝙭; 𝙭𝙭; x; x; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X +1D66E;1D66E;1D66E;0079;0079; # (𝙮𝙮; 𝙮𝙮; 𝙮𝙮; y; y; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y +1D66F;1D66F;1D66F;007A;007A; # (𝙯𝙯; 𝙯𝙯; 𝙯𝙯; z; z; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z +1D670;1D670;1D670;0041;0041; # (𝙰𝙰; 𝙰𝙰; 𝙰𝙰; A; A; ) MATHEMATICAL MONOSPACE CAPITAL A +1D671;1D671;1D671;0042;0042; # (𝙱𝙱; 𝙱𝙱; 𝙱𝙱; B; B; ) MATHEMATICAL MONOSPACE CAPITAL B +1D672;1D672;1D672;0043;0043; # (𝙲𝙲; 𝙲𝙲; 𝙲𝙲; C; C; ) MATHEMATICAL MONOSPACE CAPITAL C +1D673;1D673;1D673;0044;0044; # (𝙳𝙳; 𝙳𝙳; 𝙳𝙳; D; D; ) MATHEMATICAL MONOSPACE CAPITAL D +1D674;1D674;1D674;0045;0045; # (𝙴𝙴; 𝙴𝙴; 𝙴𝙴; E; E; ) MATHEMATICAL MONOSPACE CAPITAL E +1D675;1D675;1D675;0046;0046; # (𝙵𝙵; 𝙵𝙵; 𝙵𝙵; F; F; ) MATHEMATICAL MONOSPACE CAPITAL F +1D676;1D676;1D676;0047;0047; # (𝙶𝙶; 𝙶𝙶; 𝙶𝙶; G; G; ) MATHEMATICAL MONOSPACE CAPITAL G +1D677;1D677;1D677;0048;0048; # (𝙷𝙷; 𝙷𝙷; 𝙷𝙷; H; H; ) MATHEMATICAL MONOSPACE CAPITAL H +1D678;1D678;1D678;0049;0049; # (𝙸𝙸; 𝙸𝙸; 𝙸𝙸; I; I; ) MATHEMATICAL MONOSPACE CAPITAL I +1D679;1D679;1D679;004A;004A; # (𝙹𝙹; 𝙹𝙹; 𝙹𝙹; J; J; ) MATHEMATICAL MONOSPACE CAPITAL J +1D67A;1D67A;1D67A;004B;004B; # (𝙺𝙺; 𝙺𝙺; 𝙺𝙺; K; K; ) MATHEMATICAL MONOSPACE CAPITAL K +1D67B;1D67B;1D67B;004C;004C; # (𝙻𝙻; 𝙻𝙻; 𝙻𝙻; L; L; ) MATHEMATICAL MONOSPACE CAPITAL L +1D67C;1D67C;1D67C;004D;004D; # (𝙼𝙼; 𝙼𝙼; 𝙼𝙼; M; M; ) MATHEMATICAL MONOSPACE CAPITAL M +1D67D;1D67D;1D67D;004E;004E; # (𝙽𝙽; 𝙽𝙽; 𝙽𝙽; N; N; ) MATHEMATICAL MONOSPACE CAPITAL N +1D67E;1D67E;1D67E;004F;004F; # (𝙾𝙾; 𝙾𝙾; 𝙾𝙾; O; O; ) MATHEMATICAL MONOSPACE CAPITAL O +1D67F;1D67F;1D67F;0050;0050; # (𝙿𝙿; 𝙿𝙿; 𝙿𝙿; P; P; ) MATHEMATICAL MONOSPACE CAPITAL P +1D680;1D680;1D680;0051;0051; # (𝚀𝚀; 𝚀𝚀; 𝚀𝚀; Q; Q; ) MATHEMATICAL MONOSPACE CAPITAL Q +1D681;1D681;1D681;0052;0052; # (𝚁𝚁; 𝚁𝚁; 𝚁𝚁; R; R; ) MATHEMATICAL MONOSPACE CAPITAL R +1D682;1D682;1D682;0053;0053; # (𝚂𝚂; 𝚂𝚂; 𝚂𝚂; S; S; ) MATHEMATICAL MONOSPACE CAPITAL S +1D683;1D683;1D683;0054;0054; # (𝚃𝚃; 𝚃𝚃; 𝚃𝚃; T; T; ) MATHEMATICAL MONOSPACE CAPITAL T +1D684;1D684;1D684;0055;0055; # (𝚄𝚄; 𝚄𝚄; 𝚄𝚄; U; U; ) MATHEMATICAL MONOSPACE CAPITAL U +1D685;1D685;1D685;0056;0056; # (𝚅𝚅; 𝚅𝚅; 𝚅𝚅; V; V; ) MATHEMATICAL MONOSPACE CAPITAL V +1D686;1D686;1D686;0057;0057; # (𝚆𝚆; 𝚆𝚆; 𝚆𝚆; W; W; ) MATHEMATICAL MONOSPACE CAPITAL W +1D687;1D687;1D687;0058;0058; # (𝚇𝚇; 𝚇𝚇; 𝚇𝚇; X; X; ) MATHEMATICAL MONOSPACE CAPITAL X +1D688;1D688;1D688;0059;0059; # (𝚈𝚈; 𝚈𝚈; 𝚈𝚈; Y; Y; ) MATHEMATICAL MONOSPACE CAPITAL Y +1D689;1D689;1D689;005A;005A; # (𝚉𝚉; 𝚉𝚉; 𝚉𝚉; Z; Z; ) MATHEMATICAL MONOSPACE CAPITAL Z +1D68A;1D68A;1D68A;0061;0061; # (𝚊𝚊; 𝚊𝚊; 𝚊𝚊; a; a; ) MATHEMATICAL MONOSPACE SMALL A +1D68B;1D68B;1D68B;0062;0062; # (𝚋𝚋; 𝚋𝚋; 𝚋𝚋; b; b; ) MATHEMATICAL MONOSPACE SMALL B +1D68C;1D68C;1D68C;0063;0063; # (𝚌𝚌; 𝚌𝚌; 𝚌𝚌; c; c; ) MATHEMATICAL MONOSPACE SMALL C +1D68D;1D68D;1D68D;0064;0064; # (𝚍𝚍; 𝚍𝚍; 𝚍𝚍; d; d; ) MATHEMATICAL MONOSPACE SMALL D +1D68E;1D68E;1D68E;0065;0065; # (𝚎𝚎; 𝚎𝚎; 𝚎𝚎; e; e; ) MATHEMATICAL MONOSPACE SMALL E +1D68F;1D68F;1D68F;0066;0066; # (𝚏𝚏; 𝚏𝚏; 𝚏𝚏; f; f; ) MATHEMATICAL MONOSPACE SMALL F +1D690;1D690;1D690;0067;0067; # (𝚐𝚐; 𝚐𝚐; 𝚐𝚐; g; g; ) MATHEMATICAL MONOSPACE SMALL G +1D691;1D691;1D691;0068;0068; # (𝚑𝚑; 𝚑𝚑; 𝚑𝚑; h; h; ) MATHEMATICAL MONOSPACE SMALL H +1D692;1D692;1D692;0069;0069; # (𝚒𝚒; 𝚒𝚒; 𝚒𝚒; i; i; ) MATHEMATICAL MONOSPACE SMALL I +1D693;1D693;1D693;006A;006A; # (𝚓𝚓; 𝚓𝚓; 𝚓𝚓; j; j; ) MATHEMATICAL MONOSPACE SMALL J +1D694;1D694;1D694;006B;006B; # (𝚔𝚔; 𝚔𝚔; 𝚔𝚔; k; k; ) MATHEMATICAL MONOSPACE SMALL K +1D695;1D695;1D695;006C;006C; # (𝚕𝚕; 𝚕𝚕; 𝚕𝚕; l; l; ) MATHEMATICAL MONOSPACE SMALL L +1D696;1D696;1D696;006D;006D; # (𝚖𝚖; 𝚖𝚖; 𝚖𝚖; m; m; ) MATHEMATICAL MONOSPACE SMALL M +1D697;1D697;1D697;006E;006E; # (𝚗𝚗; 𝚗𝚗; 𝚗𝚗; n; n; ) MATHEMATICAL MONOSPACE SMALL N +1D698;1D698;1D698;006F;006F; # (𝚘𝚘; 𝚘𝚘; 𝚘𝚘; o; o; ) MATHEMATICAL MONOSPACE SMALL O +1D699;1D699;1D699;0070;0070; # (𝚙𝚙; 𝚙𝚙; 𝚙𝚙; p; p; ) MATHEMATICAL MONOSPACE SMALL P +1D69A;1D69A;1D69A;0071;0071; # (𝚚𝚚; 𝚚𝚚; 𝚚𝚚; q; q; ) MATHEMATICAL MONOSPACE SMALL Q +1D69B;1D69B;1D69B;0072;0072; # (𝚛𝚛; 𝚛𝚛; 𝚛𝚛; r; r; ) MATHEMATICAL MONOSPACE SMALL R +1D69C;1D69C;1D69C;0073;0073; # (𝚜𝚜; 𝚜𝚜; 𝚜𝚜; s; s; ) MATHEMATICAL MONOSPACE SMALL S +1D69D;1D69D;1D69D;0074;0074; # (𝚝𝚝; 𝚝𝚝; 𝚝𝚝; t; t; ) MATHEMATICAL MONOSPACE SMALL T +1D69E;1D69E;1D69E;0075;0075; # (𝚞𝚞; 𝚞𝚞; 𝚞𝚞; u; u; ) MATHEMATICAL MONOSPACE SMALL U +1D69F;1D69F;1D69F;0076;0076; # (𝚟𝚟; 𝚟𝚟; 𝚟𝚟; v; v; ) MATHEMATICAL MONOSPACE SMALL V +1D6A0;1D6A0;1D6A0;0077;0077; # (𝚠𝚠; 𝚠𝚠; 𝚠𝚠; w; w; ) MATHEMATICAL MONOSPACE SMALL W +1D6A1;1D6A1;1D6A1;0078;0078; # (𝚡𝚡; 𝚡𝚡; 𝚡𝚡; x; x; ) MATHEMATICAL MONOSPACE SMALL X +1D6A2;1D6A2;1D6A2;0079;0079; # (𝚢𝚢; 𝚢𝚢; 𝚢𝚢; y; y; ) MATHEMATICAL MONOSPACE SMALL Y +1D6A3;1D6A3;1D6A3;007A;007A; # (𝚣𝚣; 𝚣𝚣; 𝚣𝚣; z; z; ) MATHEMATICAL MONOSPACE SMALL Z +1D6A8;1D6A8;1D6A8;0391;0391; # (𝚨𝚨; 𝚨𝚨; 𝚨𝚨; Α; Α; ) MATHEMATICAL BOLD CAPITAL ALPHA +1D6A9;1D6A9;1D6A9;0392;0392; # (𝚩𝚩; 𝚩𝚩; 𝚩𝚩; Β; Β; ) MATHEMATICAL BOLD CAPITAL BETA +1D6AA;1D6AA;1D6AA;0393;0393; # (𝚪𝚪; 𝚪𝚪; 𝚪𝚪; Γ; Γ; ) MATHEMATICAL BOLD CAPITAL GAMMA +1D6AB;1D6AB;1D6AB;0394;0394; # (𝚫𝚫; 𝚫𝚫; 𝚫𝚫; Δ; Δ; ) MATHEMATICAL BOLD CAPITAL DELTA +1D6AC;1D6AC;1D6AC;0395;0395; # (𝚬𝚬; 𝚬𝚬; 𝚬𝚬; Ε; Ε; ) MATHEMATICAL BOLD CAPITAL EPSILON +1D6AD;1D6AD;1D6AD;0396;0396; # (𝚭𝚭; 𝚭𝚭; 𝚭𝚭; Ζ; Ζ; ) MATHEMATICAL BOLD CAPITAL ZETA +1D6AE;1D6AE;1D6AE;0397;0397; # (𝚮𝚮; 𝚮𝚮; 𝚮𝚮; Η; Η; ) MATHEMATICAL BOLD CAPITAL ETA +1D6AF;1D6AF;1D6AF;0398;0398; # (𝚯𝚯; 𝚯𝚯; 𝚯𝚯; Θ; Θ; ) MATHEMATICAL BOLD CAPITAL THETA +1D6B0;1D6B0;1D6B0;0399;0399; # (𝚰𝚰; 𝚰𝚰; 𝚰𝚰; Ι; Ι; ) MATHEMATICAL BOLD CAPITAL IOTA +1D6B1;1D6B1;1D6B1;039A;039A; # (𝚱𝚱; 𝚱𝚱; 𝚱𝚱; Κ; Κ; ) MATHEMATICAL BOLD CAPITAL KAPPA +1D6B2;1D6B2;1D6B2;039B;039B; # (𝚲𝚲; 𝚲𝚲; 𝚲𝚲; Λ; Λ; ) MATHEMATICAL BOLD CAPITAL LAMDA +1D6B3;1D6B3;1D6B3;039C;039C; # (𝚳𝚳; 𝚳𝚳; 𝚳𝚳; Μ; Μ; ) MATHEMATICAL BOLD CAPITAL MU +1D6B4;1D6B4;1D6B4;039D;039D; # (𝚴𝚴; 𝚴𝚴; 𝚴𝚴; Ν; Ν; ) MATHEMATICAL BOLD CAPITAL NU +1D6B5;1D6B5;1D6B5;039E;039E; # (𝚵𝚵; 𝚵𝚵; 𝚵𝚵; Ξ; Ξ; ) MATHEMATICAL BOLD CAPITAL XI +1D6B6;1D6B6;1D6B6;039F;039F; # (𝚶𝚶; 𝚶𝚶; 𝚶𝚶; Ο; Ο; ) MATHEMATICAL BOLD CAPITAL OMICRON +1D6B7;1D6B7;1D6B7;03A0;03A0; # (𝚷𝚷; 𝚷𝚷; 𝚷𝚷; Π; Π; ) MATHEMATICAL BOLD CAPITAL PI +1D6B8;1D6B8;1D6B8;03A1;03A1; # (𝚸𝚸; 𝚸𝚸; 𝚸𝚸; Ρ; Ρ; ) MATHEMATICAL BOLD CAPITAL RHO +1D6B9;1D6B9;1D6B9;0398;0398; # (𝚹𝚹; 𝚹𝚹; 𝚹𝚹; Θ; Θ; ) MATHEMATICAL BOLD CAPITAL THETA SYMBOL +1D6BA;1D6BA;1D6BA;03A3;03A3; # (𝚺𝚺; 𝚺𝚺; 𝚺𝚺; Σ; Σ; ) MATHEMATICAL BOLD CAPITAL SIGMA +1D6BB;1D6BB;1D6BB;03A4;03A4; # (𝚻𝚻; 𝚻𝚻; 𝚻𝚻; Τ; Τ; ) MATHEMATICAL BOLD CAPITAL TAU +1D6BC;1D6BC;1D6BC;03A5;03A5; # (𝚼𝚼; 𝚼𝚼; 𝚼𝚼; Υ; Υ; ) MATHEMATICAL BOLD CAPITAL UPSILON +1D6BD;1D6BD;1D6BD;03A6;03A6; # (𝚽𝚽; 𝚽𝚽; 𝚽𝚽; Φ; Φ; ) MATHEMATICAL BOLD CAPITAL PHI +1D6BE;1D6BE;1D6BE;03A7;03A7; # (𝚾𝚾; 𝚾𝚾; 𝚾𝚾; Χ; Χ; ) MATHEMATICAL BOLD CAPITAL CHI +1D6BF;1D6BF;1D6BF;03A8;03A8; # (𝚿𝚿; 𝚿𝚿; 𝚿𝚿; Ψ; Ψ; ) MATHEMATICAL BOLD CAPITAL PSI +1D6C0;1D6C0;1D6C0;03A9;03A9; # (𝛀𝛀; 𝛀𝛀; 𝛀𝛀; Ω; Ω; ) MATHEMATICAL BOLD CAPITAL OMEGA +1D6C1;1D6C1;1D6C1;2207;2207; # (𝛁𝛁; 𝛁𝛁; 𝛁𝛁; ∇; ∇; ) MATHEMATICAL BOLD NABLA +1D6C2;1D6C2;1D6C2;03B1;03B1; # (𝛂𝛂; 𝛂𝛂; 𝛂𝛂; α; α; ) MATHEMATICAL BOLD SMALL ALPHA +1D6C3;1D6C3;1D6C3;03B2;03B2; # (𝛃𝛃; 𝛃𝛃; 𝛃𝛃; β; β; ) MATHEMATICAL BOLD SMALL BETA +1D6C4;1D6C4;1D6C4;03B3;03B3; # (𝛄𝛄; 𝛄𝛄; 𝛄𝛄; γ; γ; ) MATHEMATICAL BOLD SMALL GAMMA +1D6C5;1D6C5;1D6C5;03B4;03B4; # (𝛅𝛅; 𝛅𝛅; 𝛅𝛅; δ; δ; ) MATHEMATICAL BOLD SMALL DELTA +1D6C6;1D6C6;1D6C6;03B5;03B5; # (𝛆𝛆; 𝛆𝛆; 𝛆𝛆; ε; ε; ) MATHEMATICAL BOLD SMALL EPSILON +1D6C7;1D6C7;1D6C7;03B6;03B6; # (𝛇𝛇; 𝛇𝛇; 𝛇𝛇; ζ; ζ; ) MATHEMATICAL BOLD SMALL ZETA +1D6C8;1D6C8;1D6C8;03B7;03B7; # (𝛈𝛈; 𝛈𝛈; 𝛈𝛈; η; η; ) MATHEMATICAL BOLD SMALL ETA +1D6C9;1D6C9;1D6C9;03B8;03B8; # (𝛉𝛉; 𝛉𝛉; 𝛉𝛉; θ; θ; ) MATHEMATICAL BOLD SMALL THETA +1D6CA;1D6CA;1D6CA;03B9;03B9; # (𝛊𝛊; 𝛊𝛊; 𝛊𝛊; ι; ι; ) MATHEMATICAL BOLD SMALL IOTA +1D6CB;1D6CB;1D6CB;03BA;03BA; # (𝛋𝛋; 𝛋𝛋; 𝛋𝛋; κ; κ; ) MATHEMATICAL BOLD SMALL KAPPA +1D6CC;1D6CC;1D6CC;03BB;03BB; # (𝛌𝛌; 𝛌𝛌; 𝛌𝛌; λ; λ; ) MATHEMATICAL BOLD SMALL LAMDA +1D6CD;1D6CD;1D6CD;03BC;03BC; # (𝛍𝛍; 𝛍𝛍; 𝛍𝛍; μ; μ; ) MATHEMATICAL BOLD SMALL MU +1D6CE;1D6CE;1D6CE;03BD;03BD; # (𝛎𝛎; 𝛎𝛎; 𝛎𝛎; ν; ν; ) MATHEMATICAL BOLD SMALL NU +1D6CF;1D6CF;1D6CF;03BE;03BE; # (𝛏𝛏; 𝛏𝛏; 𝛏𝛏; ξ; ξ; ) MATHEMATICAL BOLD SMALL XI +1D6D0;1D6D0;1D6D0;03BF;03BF; # (𝛐𝛐; 𝛐𝛐; 𝛐𝛐; ο; ο; ) MATHEMATICAL BOLD SMALL OMICRON +1D6D1;1D6D1;1D6D1;03C0;03C0; # (𝛑𝛑; 𝛑𝛑; 𝛑𝛑; π; π; ) MATHEMATICAL BOLD SMALL PI +1D6D2;1D6D2;1D6D2;03C1;03C1; # (𝛒𝛒; 𝛒𝛒; 𝛒𝛒; ρ; ρ; ) MATHEMATICAL BOLD SMALL RHO +1D6D3;1D6D3;1D6D3;03C2;03C2; # (𝛓𝛓; 𝛓𝛓; 𝛓𝛓; ς; ς; ) MATHEMATICAL BOLD SMALL FINAL SIGMA +1D6D4;1D6D4;1D6D4;03C3;03C3; # (𝛔𝛔; 𝛔𝛔; 𝛔𝛔; σ; σ; ) MATHEMATICAL BOLD SMALL SIGMA +1D6D5;1D6D5;1D6D5;03C4;03C4; # (𝛕𝛕; 𝛕𝛕; 𝛕𝛕; τ; τ; ) MATHEMATICAL BOLD SMALL TAU +1D6D6;1D6D6;1D6D6;03C5;03C5; # (𝛖𝛖; 𝛖𝛖; 𝛖𝛖; υ; υ; ) MATHEMATICAL BOLD SMALL UPSILON +1D6D7;1D6D7;1D6D7;03C6;03C6; # (𝛗𝛗; 𝛗𝛗; 𝛗𝛗; φ; φ; ) MATHEMATICAL BOLD SMALL PHI +1D6D8;1D6D8;1D6D8;03C7;03C7; # (𝛘𝛘; 𝛘𝛘; 𝛘𝛘; χ; χ; ) MATHEMATICAL BOLD SMALL CHI +1D6D9;1D6D9;1D6D9;03C8;03C8; # (𝛙𝛙; 𝛙𝛙; 𝛙𝛙; ψ; ψ; ) MATHEMATICAL BOLD SMALL PSI +1D6DA;1D6DA;1D6DA;03C9;03C9; # (𝛚𝛚; 𝛚𝛚; 𝛚𝛚; ω; ω; ) MATHEMATICAL BOLD SMALL OMEGA +1D6DB;1D6DB;1D6DB;2202;2202; # (𝛛𝛛; 𝛛𝛛; 𝛛𝛛; ∂; ∂; ) MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6DC;1D6DC;1D6DC;03B5;03B5; # (𝛜𝛜; 𝛜𝛜; 𝛜𝛜; ε; ε; ) MATHEMATICAL BOLD EPSILON SYMBOL +1D6DD;1D6DD;1D6DD;03B8;03B8; # (𝛝𝛝; 𝛝𝛝; 𝛝𝛝; θ; θ; ) MATHEMATICAL BOLD THETA SYMBOL +1D6DE;1D6DE;1D6DE;03BA;03BA; # (𝛞𝛞; 𝛞𝛞; 𝛞𝛞; κ; κ; ) MATHEMATICAL BOLD KAPPA SYMBOL +1D6DF;1D6DF;1D6DF;03C6;03C6; # (𝛟𝛟; 𝛟𝛟; 𝛟𝛟; φ; φ; ) MATHEMATICAL BOLD PHI SYMBOL +1D6E0;1D6E0;1D6E0;03C1;03C1; # (𝛠𝛠; 𝛠𝛠; 𝛠𝛠; ρ; ρ; ) MATHEMATICAL BOLD RHO SYMBOL +1D6E1;1D6E1;1D6E1;03C0;03C0; # (𝛡𝛡; 𝛡𝛡; 𝛡𝛡; π; π; ) MATHEMATICAL BOLD PI SYMBOL +1D6E2;1D6E2;1D6E2;0391;0391; # (𝛢𝛢; 𝛢𝛢; 𝛢𝛢; Α; Α; ) MATHEMATICAL ITALIC CAPITAL ALPHA +1D6E3;1D6E3;1D6E3;0392;0392; # (𝛣𝛣; 𝛣𝛣; 𝛣𝛣; Β; Β; ) MATHEMATICAL ITALIC CAPITAL BETA +1D6E4;1D6E4;1D6E4;0393;0393; # (𝛤𝛤; 𝛤𝛤; 𝛤𝛤; Γ; Γ; ) MATHEMATICAL ITALIC CAPITAL GAMMA +1D6E5;1D6E5;1D6E5;0394;0394; # (𝛥𝛥; 𝛥𝛥; 𝛥𝛥; Δ; Δ; ) MATHEMATICAL ITALIC CAPITAL DELTA +1D6E6;1D6E6;1D6E6;0395;0395; # (𝛦𝛦; 𝛦𝛦; 𝛦𝛦; Ε; Ε; ) MATHEMATICAL ITALIC CAPITAL EPSILON +1D6E7;1D6E7;1D6E7;0396;0396; # (𝛧𝛧; 𝛧𝛧; 𝛧𝛧; Ζ; Ζ; ) MATHEMATICAL ITALIC CAPITAL ZETA +1D6E8;1D6E8;1D6E8;0397;0397; # (𝛨𝛨; 𝛨𝛨; 𝛨𝛨; Η; Η; ) MATHEMATICAL ITALIC CAPITAL ETA +1D6E9;1D6E9;1D6E9;0398;0398; # (𝛩𝛩; 𝛩𝛩; 𝛩𝛩; Θ; Θ; ) MATHEMATICAL ITALIC CAPITAL THETA +1D6EA;1D6EA;1D6EA;0399;0399; # (𝛪𝛪; 𝛪𝛪; 𝛪𝛪; Ι; Ι; ) MATHEMATICAL ITALIC CAPITAL IOTA +1D6EB;1D6EB;1D6EB;039A;039A; # (𝛫𝛫; 𝛫𝛫; 𝛫𝛫; Κ; Κ; ) MATHEMATICAL ITALIC CAPITAL KAPPA +1D6EC;1D6EC;1D6EC;039B;039B; # (𝛬𝛬; 𝛬𝛬; 𝛬𝛬; Λ; Λ; ) MATHEMATICAL ITALIC CAPITAL LAMDA +1D6ED;1D6ED;1D6ED;039C;039C; # (𝛭𝛭; 𝛭𝛭; 𝛭𝛭; Μ; Μ; ) MATHEMATICAL ITALIC CAPITAL MU +1D6EE;1D6EE;1D6EE;039D;039D; # (𝛮𝛮; 𝛮𝛮; 𝛮𝛮; Ν; Ν; ) MATHEMATICAL ITALIC CAPITAL NU +1D6EF;1D6EF;1D6EF;039E;039E; # (𝛯𝛯; 𝛯𝛯; 𝛯𝛯; Ξ; Ξ; ) MATHEMATICAL ITALIC CAPITAL XI +1D6F0;1D6F0;1D6F0;039F;039F; # (𝛰𝛰; 𝛰𝛰; 𝛰𝛰; Ο; Ο; ) MATHEMATICAL ITALIC CAPITAL OMICRON +1D6F1;1D6F1;1D6F1;03A0;03A0; # (𝛱𝛱; 𝛱𝛱; 𝛱𝛱; Π; Π; ) MATHEMATICAL ITALIC CAPITAL PI +1D6F2;1D6F2;1D6F2;03A1;03A1; # (𝛲𝛲; 𝛲𝛲; 𝛲𝛲; Ρ; Ρ; ) MATHEMATICAL ITALIC CAPITAL RHO +1D6F3;1D6F3;1D6F3;0398;0398; # (𝛳𝛳; 𝛳𝛳; 𝛳𝛳; Θ; Θ; ) MATHEMATICAL ITALIC CAPITAL THETA SYMBOL +1D6F4;1D6F4;1D6F4;03A3;03A3; # (𝛴𝛴; 𝛴𝛴; 𝛴𝛴; Σ; Σ; ) MATHEMATICAL ITALIC CAPITAL SIGMA +1D6F5;1D6F5;1D6F5;03A4;03A4; # (𝛵𝛵; 𝛵𝛵; 𝛵𝛵; Τ; Τ; ) MATHEMATICAL ITALIC CAPITAL TAU +1D6F6;1D6F6;1D6F6;03A5;03A5; # (𝛶𝛶; 𝛶𝛶; 𝛶𝛶; Υ; Υ; ) MATHEMATICAL ITALIC CAPITAL UPSILON +1D6F7;1D6F7;1D6F7;03A6;03A6; # (𝛷𝛷; 𝛷𝛷; 𝛷𝛷; Φ; Φ; ) MATHEMATICAL ITALIC CAPITAL PHI +1D6F8;1D6F8;1D6F8;03A7;03A7; # (𝛸𝛸; 𝛸𝛸; 𝛸𝛸; Χ; Χ; ) MATHEMATICAL ITALIC CAPITAL CHI +1D6F9;1D6F9;1D6F9;03A8;03A8; # (𝛹𝛹; 𝛹𝛹; 𝛹𝛹; Ψ; Ψ; ) MATHEMATICAL ITALIC CAPITAL PSI +1D6FA;1D6FA;1D6FA;03A9;03A9; # (𝛺𝛺; 𝛺𝛺; 𝛺𝛺; Ω; Ω; ) MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FB;1D6FB;1D6FB;2207;2207; # (𝛻𝛻; 𝛻𝛻; 𝛻𝛻; ∇; ∇; ) MATHEMATICAL ITALIC NABLA +1D6FC;1D6FC;1D6FC;03B1;03B1; # (𝛼𝛼; 𝛼𝛼; 𝛼𝛼; α; α; ) MATHEMATICAL ITALIC SMALL ALPHA +1D6FD;1D6FD;1D6FD;03B2;03B2; # (𝛽𝛽; 𝛽𝛽; 𝛽𝛽; β; β; ) MATHEMATICAL ITALIC SMALL BETA +1D6FE;1D6FE;1D6FE;03B3;03B3; # (𝛾𝛾; 𝛾𝛾; 𝛾𝛾; γ; γ; ) MATHEMATICAL ITALIC SMALL GAMMA +1D6FF;1D6FF;1D6FF;03B4;03B4; # (𝛿𝛿; 𝛿𝛿; 𝛿𝛿; δ; δ; ) MATHEMATICAL ITALIC SMALL DELTA +1D700;1D700;1D700;03B5;03B5; # (𝜀𝜀; 𝜀𝜀; 𝜀𝜀; ε; ε; ) MATHEMATICAL ITALIC SMALL EPSILON +1D701;1D701;1D701;03B6;03B6; # (𝜁𝜁; 𝜁𝜁; 𝜁𝜁; ζ; ζ; ) MATHEMATICAL ITALIC SMALL ZETA +1D702;1D702;1D702;03B7;03B7; # (𝜂𝜂; 𝜂𝜂; 𝜂𝜂; η; η; ) MATHEMATICAL ITALIC SMALL ETA +1D703;1D703;1D703;03B8;03B8; # (𝜃𝜃; 𝜃𝜃; 𝜃𝜃; θ; θ; ) MATHEMATICAL ITALIC SMALL THETA +1D704;1D704;1D704;03B9;03B9; # (𝜄𝜄; 𝜄𝜄; 𝜄𝜄; ι; ι; ) MATHEMATICAL ITALIC SMALL IOTA +1D705;1D705;1D705;03BA;03BA; # (𝜅𝜅; 𝜅𝜅; 𝜅𝜅; κ; κ; ) MATHEMATICAL ITALIC SMALL KAPPA +1D706;1D706;1D706;03BB;03BB; # (𝜆𝜆; 𝜆𝜆; 𝜆𝜆; λ; λ; ) MATHEMATICAL ITALIC SMALL LAMDA +1D707;1D707;1D707;03BC;03BC; # (𝜇𝜇; 𝜇𝜇; 𝜇𝜇; μ; μ; ) MATHEMATICAL ITALIC SMALL MU +1D708;1D708;1D708;03BD;03BD; # (𝜈𝜈; 𝜈𝜈; 𝜈𝜈; ν; ν; ) MATHEMATICAL ITALIC SMALL NU +1D709;1D709;1D709;03BE;03BE; # (𝜉𝜉; 𝜉𝜉; 𝜉𝜉; ξ; ξ; ) MATHEMATICAL ITALIC SMALL XI +1D70A;1D70A;1D70A;03BF;03BF; # (𝜊𝜊; 𝜊𝜊; 𝜊𝜊; ο; ο; ) MATHEMATICAL ITALIC SMALL OMICRON +1D70B;1D70B;1D70B;03C0;03C0; # (𝜋𝜋; 𝜋𝜋; 𝜋𝜋; π; π; ) MATHEMATICAL ITALIC SMALL PI +1D70C;1D70C;1D70C;03C1;03C1; # (𝜌𝜌; 𝜌𝜌; 𝜌𝜌; ρ; ρ; ) MATHEMATICAL ITALIC SMALL RHO +1D70D;1D70D;1D70D;03C2;03C2; # (𝜍𝜍; 𝜍𝜍; 𝜍𝜍; ς; ς; ) MATHEMATICAL ITALIC SMALL FINAL SIGMA +1D70E;1D70E;1D70E;03C3;03C3; # (𝜎𝜎; 𝜎𝜎; 𝜎𝜎; σ; σ; ) MATHEMATICAL ITALIC SMALL SIGMA +1D70F;1D70F;1D70F;03C4;03C4; # (𝜏𝜏; 𝜏𝜏; 𝜏𝜏; τ; τ; ) MATHEMATICAL ITALIC SMALL TAU +1D710;1D710;1D710;03C5;03C5; # (𝜐𝜐; 𝜐𝜐; 𝜐𝜐; υ; υ; ) MATHEMATICAL ITALIC SMALL UPSILON +1D711;1D711;1D711;03C6;03C6; # (𝜑𝜑; 𝜑𝜑; 𝜑𝜑; φ; φ; ) MATHEMATICAL ITALIC SMALL PHI +1D712;1D712;1D712;03C7;03C7; # (𝜒𝜒; 𝜒𝜒; 𝜒𝜒; χ; χ; ) MATHEMATICAL ITALIC SMALL CHI +1D713;1D713;1D713;03C8;03C8; # (𝜓𝜓; 𝜓𝜓; 𝜓𝜓; ψ; ψ; ) MATHEMATICAL ITALIC SMALL PSI +1D714;1D714;1D714;03C9;03C9; # (𝜔𝜔; 𝜔𝜔; 𝜔𝜔; ω; ω; ) MATHEMATICAL ITALIC SMALL OMEGA +1D715;1D715;1D715;2202;2202; # (𝜕𝜕; 𝜕𝜕; 𝜕𝜕; ∂; ∂; ) MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D716;1D716;1D716;03B5;03B5; # (𝜖𝜖; 𝜖𝜖; 𝜖𝜖; ε; ε; ) MATHEMATICAL ITALIC EPSILON SYMBOL +1D717;1D717;1D717;03B8;03B8; # (𝜗𝜗; 𝜗𝜗; 𝜗𝜗; θ; θ; ) MATHEMATICAL ITALIC THETA SYMBOL +1D718;1D718;1D718;03BA;03BA; # (𝜘𝜘; 𝜘𝜘; 𝜘𝜘; κ; κ; ) MATHEMATICAL ITALIC KAPPA SYMBOL +1D719;1D719;1D719;03C6;03C6; # (𝜙𝜙; 𝜙𝜙; 𝜙𝜙; φ; φ; ) MATHEMATICAL ITALIC PHI SYMBOL +1D71A;1D71A;1D71A;03C1;03C1; # (𝜚𝜚; 𝜚𝜚; 𝜚𝜚; ρ; ρ; ) MATHEMATICAL ITALIC RHO SYMBOL +1D71B;1D71B;1D71B;03C0;03C0; # (𝜛𝜛; 𝜛𝜛; 𝜛𝜛; π; π; ) MATHEMATICAL ITALIC PI SYMBOL +1D71C;1D71C;1D71C;0391;0391; # (𝜜𝜜; 𝜜𝜜; 𝜜𝜜; Α; Α; ) MATHEMATICAL BOLD ITALIC CAPITAL ALPHA +1D71D;1D71D;1D71D;0392;0392; # (𝜝𝜝; 𝜝𝜝; 𝜝𝜝; Β; Β; ) MATHEMATICAL BOLD ITALIC CAPITAL BETA +1D71E;1D71E;1D71E;0393;0393; # (𝜞𝜞; 𝜞𝜞; 𝜞𝜞; Γ; Γ; ) MATHEMATICAL BOLD ITALIC CAPITAL GAMMA +1D71F;1D71F;1D71F;0394;0394; # (𝜟𝜟; 𝜟𝜟; 𝜟𝜟; Δ; Δ; ) MATHEMATICAL BOLD ITALIC CAPITAL DELTA +1D720;1D720;1D720;0395;0395; # (𝜠𝜠; 𝜠𝜠; 𝜠𝜠; Ε; Ε; ) MATHEMATICAL BOLD ITALIC CAPITAL EPSILON +1D721;1D721;1D721;0396;0396; # (𝜡𝜡; 𝜡𝜡; 𝜡𝜡; Ζ; Ζ; ) MATHEMATICAL BOLD ITALIC CAPITAL ZETA +1D722;1D722;1D722;0397;0397; # (𝜢𝜢; 𝜢𝜢; 𝜢𝜢; Η; Η; ) MATHEMATICAL BOLD ITALIC CAPITAL ETA +1D723;1D723;1D723;0398;0398; # (𝜣𝜣; 𝜣𝜣; 𝜣𝜣; Θ; Θ; ) MATHEMATICAL BOLD ITALIC CAPITAL THETA +1D724;1D724;1D724;0399;0399; # (𝜤𝜤; 𝜤𝜤; 𝜤𝜤; Ι; Ι; ) MATHEMATICAL BOLD ITALIC CAPITAL IOTA +1D725;1D725;1D725;039A;039A; # (𝜥𝜥; 𝜥𝜥; 𝜥𝜥; Κ; Κ; ) MATHEMATICAL BOLD ITALIC CAPITAL KAPPA +1D726;1D726;1D726;039B;039B; # (𝜦𝜦; 𝜦𝜦; 𝜦𝜦; Λ; Λ; ) MATHEMATICAL BOLD ITALIC CAPITAL LAMDA +1D727;1D727;1D727;039C;039C; # (𝜧𝜧; 𝜧𝜧; 𝜧𝜧; Μ; Μ; ) MATHEMATICAL BOLD ITALIC CAPITAL MU +1D728;1D728;1D728;039D;039D; # (𝜨𝜨; 𝜨𝜨; 𝜨𝜨; Ν; Ν; ) MATHEMATICAL BOLD ITALIC CAPITAL NU +1D729;1D729;1D729;039E;039E; # (𝜩𝜩; 𝜩𝜩; 𝜩𝜩; Ξ; Ξ; ) MATHEMATICAL BOLD ITALIC CAPITAL XI +1D72A;1D72A;1D72A;039F;039F; # (𝜪𝜪; 𝜪𝜪; 𝜪𝜪; Ο; Ο; ) MATHEMATICAL BOLD ITALIC CAPITAL OMICRON +1D72B;1D72B;1D72B;03A0;03A0; # (𝜫𝜫; 𝜫𝜫; 𝜫𝜫; Π; Π; ) MATHEMATICAL BOLD ITALIC CAPITAL PI +1D72C;1D72C;1D72C;03A1;03A1; # (𝜬𝜬; 𝜬𝜬; 𝜬𝜬; Ρ; Ρ; ) MATHEMATICAL BOLD ITALIC CAPITAL RHO +1D72D;1D72D;1D72D;0398;0398; # (𝜭𝜭; 𝜭𝜭; 𝜭𝜭; Θ; Θ; ) MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL +1D72E;1D72E;1D72E;03A3;03A3; # (𝜮𝜮; 𝜮𝜮; 𝜮𝜮; Σ; Σ; ) MATHEMATICAL BOLD ITALIC CAPITAL SIGMA +1D72F;1D72F;1D72F;03A4;03A4; # (𝜯𝜯; 𝜯𝜯; 𝜯𝜯; Τ; Τ; ) MATHEMATICAL BOLD ITALIC CAPITAL TAU +1D730;1D730;1D730;03A5;03A5; # (𝜰𝜰; 𝜰𝜰; 𝜰𝜰; Υ; Υ; ) MATHEMATICAL BOLD ITALIC CAPITAL UPSILON +1D731;1D731;1D731;03A6;03A6; # (𝜱𝜱; 𝜱𝜱; 𝜱𝜱; Φ; Φ; ) MATHEMATICAL BOLD ITALIC CAPITAL PHI +1D732;1D732;1D732;03A7;03A7; # (𝜲𝜲; 𝜲𝜲; 𝜲𝜲; Χ; Χ; ) MATHEMATICAL BOLD ITALIC CAPITAL CHI +1D733;1D733;1D733;03A8;03A8; # (𝜳𝜳; 𝜳𝜳; 𝜳𝜳; Ψ; Ψ; ) MATHEMATICAL BOLD ITALIC CAPITAL PSI +1D734;1D734;1D734;03A9;03A9; # (𝜴𝜴; 𝜴𝜴; 𝜴𝜴; Ω; Ω; ) MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D735;1D735;1D735;2207;2207; # (𝜵𝜵; 𝜵𝜵; 𝜵𝜵; ∇; ∇; ) MATHEMATICAL BOLD ITALIC NABLA +1D736;1D736;1D736;03B1;03B1; # (𝜶𝜶; 𝜶𝜶; 𝜶𝜶; α; α; ) MATHEMATICAL BOLD ITALIC SMALL ALPHA +1D737;1D737;1D737;03B2;03B2; # (𝜷𝜷; 𝜷𝜷; 𝜷𝜷; β; β; ) MATHEMATICAL BOLD ITALIC SMALL BETA +1D738;1D738;1D738;03B3;03B3; # (𝜸𝜸; 𝜸𝜸; 𝜸𝜸; γ; γ; ) MATHEMATICAL BOLD ITALIC SMALL GAMMA +1D739;1D739;1D739;03B4;03B4; # (𝜹𝜹; 𝜹𝜹; 𝜹𝜹; δ; δ; ) MATHEMATICAL BOLD ITALIC SMALL DELTA +1D73A;1D73A;1D73A;03B5;03B5; # (𝜺𝜺; 𝜺𝜺; 𝜺𝜺; ε; ε; ) MATHEMATICAL BOLD ITALIC SMALL EPSILON +1D73B;1D73B;1D73B;03B6;03B6; # (𝜻𝜻; 𝜻𝜻; 𝜻𝜻; ζ; ζ; ) MATHEMATICAL BOLD ITALIC SMALL ZETA +1D73C;1D73C;1D73C;03B7;03B7; # (𝜼𝜼; 𝜼𝜼; 𝜼𝜼; η; η; ) MATHEMATICAL BOLD ITALIC SMALL ETA +1D73D;1D73D;1D73D;03B8;03B8; # (𝜽𝜽; 𝜽𝜽; 𝜽𝜽; θ; θ; ) MATHEMATICAL BOLD ITALIC SMALL THETA +1D73E;1D73E;1D73E;03B9;03B9; # (𝜾𝜾; 𝜾𝜾; 𝜾𝜾; ι; ι; ) MATHEMATICAL BOLD ITALIC SMALL IOTA +1D73F;1D73F;1D73F;03BA;03BA; # (𝜿𝜿; 𝜿𝜿; 𝜿𝜿; κ; κ; ) MATHEMATICAL BOLD ITALIC SMALL KAPPA +1D740;1D740;1D740;03BB;03BB; # (𝝀𝝀; 𝝀𝝀; 𝝀𝝀; λ; λ; ) MATHEMATICAL BOLD ITALIC SMALL LAMDA +1D741;1D741;1D741;03BC;03BC; # (𝝁𝝁; 𝝁𝝁; 𝝁𝝁; μ; μ; ) MATHEMATICAL BOLD ITALIC SMALL MU +1D742;1D742;1D742;03BD;03BD; # (𝝂𝝂; 𝝂𝝂; 𝝂𝝂; ν; ν; ) MATHEMATICAL BOLD ITALIC SMALL NU +1D743;1D743;1D743;03BE;03BE; # (𝝃𝝃; 𝝃𝝃; 𝝃𝝃; ξ; ξ; ) MATHEMATICAL BOLD ITALIC SMALL XI +1D744;1D744;1D744;03BF;03BF; # (𝝄𝝄; 𝝄𝝄; 𝝄𝝄; ο; ο; ) MATHEMATICAL BOLD ITALIC SMALL OMICRON +1D745;1D745;1D745;03C0;03C0; # (𝝅𝝅; 𝝅𝝅; 𝝅𝝅; π; π; ) MATHEMATICAL BOLD ITALIC SMALL PI +1D746;1D746;1D746;03C1;03C1; # (𝝆𝝆; 𝝆𝝆; 𝝆𝝆; ρ; ρ; ) MATHEMATICAL BOLD ITALIC SMALL RHO +1D747;1D747;1D747;03C2;03C2; # (𝝇𝝇; 𝝇𝝇; 𝝇𝝇; ς; ς; ) MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA +1D748;1D748;1D748;03C3;03C3; # (𝝈𝝈; 𝝈𝝈; 𝝈𝝈; σ; σ; ) MATHEMATICAL BOLD ITALIC SMALL SIGMA +1D749;1D749;1D749;03C4;03C4; # (𝝉𝝉; 𝝉𝝉; 𝝉𝝉; τ; τ; ) MATHEMATICAL BOLD ITALIC SMALL TAU +1D74A;1D74A;1D74A;03C5;03C5; # (𝝊𝝊; 𝝊𝝊; 𝝊𝝊; υ; υ; ) MATHEMATICAL BOLD ITALIC SMALL UPSILON +1D74B;1D74B;1D74B;03C6;03C6; # (𝝋𝝋; 𝝋𝝋; 𝝋𝝋; φ; φ; ) MATHEMATICAL BOLD ITALIC SMALL PHI +1D74C;1D74C;1D74C;03C7;03C7; # (𝝌𝝌; 𝝌𝝌; 𝝌𝝌; χ; χ; ) MATHEMATICAL BOLD ITALIC SMALL CHI +1D74D;1D74D;1D74D;03C8;03C8; # (𝝍𝝍; 𝝍𝝍; 𝝍𝝍; ψ; ψ; ) MATHEMATICAL BOLD ITALIC SMALL PSI +1D74E;1D74E;1D74E;03C9;03C9; # (𝝎𝝎; 𝝎𝝎; 𝝎𝝎; ω; ω; ) MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D74F;1D74F;1D74F;2202;2202; # (𝝏𝝏; 𝝏𝝏; 𝝏𝝏; ∂; ∂; ) MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D750;1D750;1D750;03B5;03B5; # (𝝐𝝐; 𝝐𝝐; 𝝐𝝐; ε; ε; ) MATHEMATICAL BOLD ITALIC EPSILON SYMBOL +1D751;1D751;1D751;03B8;03B8; # (𝝑𝝑; 𝝑𝝑; 𝝑𝝑; θ; θ; ) MATHEMATICAL BOLD ITALIC THETA SYMBOL +1D752;1D752;1D752;03BA;03BA; # (𝝒𝝒; 𝝒𝝒; 𝝒𝝒; κ; κ; ) MATHEMATICAL BOLD ITALIC KAPPA SYMBOL +1D753;1D753;1D753;03C6;03C6; # (𝝓𝝓; 𝝓𝝓; 𝝓𝝓; φ; φ; ) MATHEMATICAL BOLD ITALIC PHI SYMBOL +1D754;1D754;1D754;03C1;03C1; # (𝝔𝝔; 𝝔𝝔; 𝝔𝝔; ρ; ρ; ) MATHEMATICAL BOLD ITALIC RHO SYMBOL +1D755;1D755;1D755;03C0;03C0; # (𝝕𝝕; 𝝕𝝕; 𝝕𝝕; π; π; ) MATHEMATICAL BOLD ITALIC PI SYMBOL +1D756;1D756;1D756;0391;0391; # (𝝖𝝖; 𝝖𝝖; 𝝖𝝖; Α; Α; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA +1D757;1D757;1D757;0392;0392; # (𝝗𝝗; 𝝗𝝗; 𝝗𝝗; Β; Β; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA +1D758;1D758;1D758;0393;0393; # (𝝘𝝘; 𝝘𝝘; 𝝘𝝘; Γ; Γ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA +1D759;1D759;1D759;0394;0394; # (𝝙𝝙; 𝝙𝝙; 𝝙𝝙; Δ; Δ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA +1D75A;1D75A;1D75A;0395;0395; # (𝝚𝝚; 𝝚𝝚; 𝝚𝝚; Ε; Ε; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON +1D75B;1D75B;1D75B;0396;0396; # (𝝛𝝛; 𝝛𝝛; 𝝛𝝛; Ζ; Ζ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA +1D75C;1D75C;1D75C;0397;0397; # (𝝜𝝜; 𝝜𝝜; 𝝜𝝜; Η; Η; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA +1D75D;1D75D;1D75D;0398;0398; # (𝝝𝝝; 𝝝𝝝; 𝝝𝝝; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA +1D75E;1D75E;1D75E;0399;0399; # (𝝞𝝞; 𝝞𝝞; 𝝞𝝞; Ι; Ι; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA +1D75F;1D75F;1D75F;039A;039A; # (𝝟𝝟; 𝝟𝝟; 𝝟𝝟; Κ; Κ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA +1D760;1D760;1D760;039B;039B; # (𝝠𝝠; 𝝠𝝠; 𝝠𝝠; Λ; Λ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA +1D761;1D761;1D761;039C;039C; # (𝝡𝝡; 𝝡𝝡; 𝝡𝝡; Μ; Μ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL MU +1D762;1D762;1D762;039D;039D; # (𝝢𝝢; 𝝢𝝢; 𝝢𝝢; Ν; Ν; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL NU +1D763;1D763;1D763;039E;039E; # (𝝣𝝣; 𝝣𝝣; 𝝣𝝣; Ξ; Ξ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL XI +1D764;1D764;1D764;039F;039F; # (𝝤𝝤; 𝝤𝝤; 𝝤𝝤; Ο; Ο; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON +1D765;1D765;1D765;03A0;03A0; # (𝝥𝝥; 𝝥𝝥; 𝝥𝝥; Π; Π; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PI +1D766;1D766;1D766;03A1;03A1; # (𝝦𝝦; 𝝦𝝦; 𝝦𝝦; Ρ; Ρ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO +1D767;1D767;1D767;0398;0398; # (𝝧𝝧; 𝝧𝝧; 𝝧𝝧; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL +1D768;1D768;1D768;03A3;03A3; # (𝝨𝝨; 𝝨𝝨; 𝝨𝝨; Σ; Σ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA +1D769;1D769;1D769;03A4;03A4; # (𝝩𝝩; 𝝩𝝩; 𝝩𝝩; Τ; Τ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU +1D76A;1D76A;1D76A;03A5;03A5; # (𝝪𝝪; 𝝪𝝪; 𝝪𝝪; Υ; Υ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON +1D76B;1D76B;1D76B;03A6;03A6; # (𝝫𝝫; 𝝫𝝫; 𝝫𝝫; Φ; Φ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI +1D76C;1D76C;1D76C;03A7;03A7; # (𝝬𝝬; 𝝬𝝬; 𝝬𝝬; Χ; Χ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI +1D76D;1D76D;1D76D;03A8;03A8; # (𝝭𝝭; 𝝭𝝭; 𝝭𝝭; Ψ; Ψ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI +1D76E;1D76E;1D76E;03A9;03A9; # (𝝮𝝮; 𝝮𝝮; 𝝮𝝮; Ω; Ω; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D76F;1D76F;1D76F;2207;2207; # (𝝯𝝯; 𝝯𝝯; 𝝯𝝯; ∇; ∇; ) MATHEMATICAL SANS-SERIF BOLD NABLA +1D770;1D770;1D770;03B1;03B1; # (𝝰𝝰; 𝝰𝝰; 𝝰𝝰; α; α; ) MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA +1D771;1D771;1D771;03B2;03B2; # (𝝱𝝱; 𝝱𝝱; 𝝱𝝱; β; β; ) MATHEMATICAL SANS-SERIF BOLD SMALL BETA +1D772;1D772;1D772;03B3;03B3; # (𝝲𝝲; 𝝲𝝲; 𝝲𝝲; γ; γ; ) MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA +1D773;1D773;1D773;03B4;03B4; # (𝝳𝝳; 𝝳𝝳; 𝝳𝝳; δ; δ; ) MATHEMATICAL SANS-SERIF BOLD SMALL DELTA +1D774;1D774;1D774;03B5;03B5; # (𝝴𝝴; 𝝴𝝴; 𝝴𝝴; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON +1D775;1D775;1D775;03B6;03B6; # (𝝵𝝵; 𝝵𝝵; 𝝵𝝵; ζ; ζ; ) MATHEMATICAL SANS-SERIF BOLD SMALL ZETA +1D776;1D776;1D776;03B7;03B7; # (𝝶𝝶; 𝝶𝝶; 𝝶𝝶; η; η; ) MATHEMATICAL SANS-SERIF BOLD SMALL ETA +1D777;1D777;1D777;03B8;03B8; # (𝝷𝝷; 𝝷𝝷; 𝝷𝝷; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD SMALL THETA +1D778;1D778;1D778;03B9;03B9; # (𝝸𝝸; 𝝸𝝸; 𝝸𝝸; ι; ι; ) MATHEMATICAL SANS-SERIF BOLD SMALL IOTA +1D779;1D779;1D779;03BA;03BA; # (𝝹𝝹; 𝝹𝝹; 𝝹𝝹; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA +1D77A;1D77A;1D77A;03BB;03BB; # (𝝺𝝺; 𝝺𝝺; 𝝺𝝺; λ; λ; ) MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA +1D77B;1D77B;1D77B;03BC;03BC; # (𝝻𝝻; 𝝻𝝻; 𝝻𝝻; μ; μ; ) MATHEMATICAL SANS-SERIF BOLD SMALL MU +1D77C;1D77C;1D77C;03BD;03BD; # (𝝼𝝼; 𝝼𝝼; 𝝼𝝼; ν; ν; ) MATHEMATICAL SANS-SERIF BOLD SMALL NU +1D77D;1D77D;1D77D;03BE;03BE; # (𝝽𝝽; 𝝽𝝽; 𝝽𝝽; ξ; ξ; ) MATHEMATICAL SANS-SERIF BOLD SMALL XI +1D77E;1D77E;1D77E;03BF;03BF; # (𝝾𝝾; 𝝾𝝾; 𝝾𝝾; ο; ο; ) MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON +1D77F;1D77F;1D77F;03C0;03C0; # (𝝿𝝿; 𝝿𝝿; 𝝿𝝿; π; π; ) MATHEMATICAL SANS-SERIF BOLD SMALL PI +1D780;1D780;1D780;03C1;03C1; # (𝞀𝞀; 𝞀𝞀; 𝞀𝞀; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD SMALL RHO +1D781;1D781;1D781;03C2;03C2; # (𝞁𝞁; 𝞁𝞁; 𝞁𝞁; ς; ς; ) MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA +1D782;1D782;1D782;03C3;03C3; # (𝞂𝞂; 𝞂𝞂; 𝞂𝞂; σ; σ; ) MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA +1D783;1D783;1D783;03C4;03C4; # (𝞃𝞃; 𝞃𝞃; 𝞃𝞃; τ; τ; ) MATHEMATICAL SANS-SERIF BOLD SMALL TAU +1D784;1D784;1D784;03C5;03C5; # (𝞄𝞄; 𝞄𝞄; 𝞄𝞄; υ; υ; ) MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON +1D785;1D785;1D785;03C6;03C6; # (𝞅𝞅; 𝞅𝞅; 𝞅𝞅; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD SMALL PHI +1D786;1D786;1D786;03C7;03C7; # (𝞆𝞆; 𝞆𝞆; 𝞆𝞆; χ; χ; ) MATHEMATICAL SANS-SERIF BOLD SMALL CHI +1D787;1D787;1D787;03C8;03C8; # (𝞇𝞇; 𝞇𝞇; 𝞇𝞇; ψ; ψ; ) MATHEMATICAL SANS-SERIF BOLD SMALL PSI +1D788;1D788;1D788;03C9;03C9; # (𝞈𝞈; 𝞈𝞈; 𝞈𝞈; ω; ω; ) MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D789;1D789;1D789;2202;2202; # (𝞉𝞉; 𝞉𝞉; 𝞉𝞉; ∂; ∂; ) MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D78A;1D78A;1D78A;03B5;03B5; # (𝞊𝞊; 𝞊𝞊; 𝞊𝞊; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL +1D78B;1D78B;1D78B;03B8;03B8; # (𝞋𝞋; 𝞋𝞋; 𝞋𝞋; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL +1D78C;1D78C;1D78C;03BA;03BA; # (𝞌𝞌; 𝞌𝞌; 𝞌𝞌; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL +1D78D;1D78D;1D78D;03C6;03C6; # (𝞍𝞍; 𝞍𝞍; 𝞍𝞍; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL +1D78E;1D78E;1D78E;03C1;03C1; # (𝞎𝞎; 𝞎𝞎; 𝞎𝞎; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL +1D78F;1D78F;1D78F;03C0;03C0; # (𝞏𝞏; 𝞏𝞏; 𝞏𝞏; π; π; ) MATHEMATICAL SANS-SERIF BOLD PI SYMBOL +1D790;1D790;1D790;0391;0391; # (𝞐𝞐; 𝞐𝞐; 𝞐𝞐; Α; Α; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA +1D791;1D791;1D791;0392;0392; # (𝞑𝞑; 𝞑𝞑; 𝞑𝞑; Β; Β; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA +1D792;1D792;1D792;0393;0393; # (𝞒𝞒; 𝞒𝞒; 𝞒𝞒; Γ; Γ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA +1D793;1D793;1D793;0394;0394; # (𝞓𝞓; 𝞓𝞓; 𝞓𝞓; Δ; Δ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA +1D794;1D794;1D794;0395;0395; # (𝞔𝞔; 𝞔𝞔; 𝞔𝞔; Ε; Ε; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON +1D795;1D795;1D795;0396;0396; # (𝞕𝞕; 𝞕𝞕; 𝞕𝞕; Ζ; Ζ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA +1D796;1D796;1D796;0397;0397; # (𝞖𝞖; 𝞖𝞖; 𝞖𝞖; Η; Η; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA +1D797;1D797;1D797;0398;0398; # (𝞗𝞗; 𝞗𝞗; 𝞗𝞗; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA +1D798;1D798;1D798;0399;0399; # (𝞘𝞘; 𝞘𝞘; 𝞘𝞘; Ι; Ι; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA +1D799;1D799;1D799;039A;039A; # (𝞙𝞙; 𝞙𝞙; 𝞙𝞙; Κ; Κ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA +1D79A;1D79A;1D79A;039B;039B; # (𝞚𝞚; 𝞚𝞚; 𝞚𝞚; Λ; Λ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA +1D79B;1D79B;1D79B;039C;039C; # (𝞛𝞛; 𝞛𝞛; 𝞛𝞛; Μ; Μ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU +1D79C;1D79C;1D79C;039D;039D; # (𝞜𝞜; 𝞜𝞜; 𝞜𝞜; Ν; Ν; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU +1D79D;1D79D;1D79D;039E;039E; # (𝞝𝞝; 𝞝𝞝; 𝞝𝞝; Ξ; Ξ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI +1D79E;1D79E;1D79E;039F;039F; # (𝞞𝞞; 𝞞𝞞; 𝞞𝞞; Ο; Ο; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON +1D79F;1D79F;1D79F;03A0;03A0; # (𝞟𝞟; 𝞟𝞟; 𝞟𝞟; Π; Π; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI +1D7A0;1D7A0;1D7A0;03A1;03A1; # (𝞠𝞠; 𝞠𝞠; 𝞠𝞠; Ρ; Ρ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO +1D7A1;1D7A1;1D7A1;0398;0398; # (𝞡𝞡; 𝞡𝞡; 𝞡𝞡; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL +1D7A2;1D7A2;1D7A2;03A3;03A3; # (𝞢𝞢; 𝞢𝞢; 𝞢𝞢; Σ; Σ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA +1D7A3;1D7A3;1D7A3;03A4;03A4; # (𝞣𝞣; 𝞣𝞣; 𝞣𝞣; Τ; Τ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU +1D7A4;1D7A4;1D7A4;03A5;03A5; # (𝞤𝞤; 𝞤𝞤; 𝞤𝞤; Υ; Υ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON +1D7A5;1D7A5;1D7A5;03A6;03A6; # (𝞥𝞥; 𝞥𝞥; 𝞥𝞥; Φ; Φ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI +1D7A6;1D7A6;1D7A6;03A7;03A7; # (𝞦𝞦; 𝞦𝞦; 𝞦𝞦; Χ; Χ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI +1D7A7;1D7A7;1D7A7;03A8;03A8; # (𝞧𝞧; 𝞧𝞧; 𝞧𝞧; Ψ; Ψ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI +1D7A8;1D7A8;1D7A8;03A9;03A9; # (𝞨𝞨; 𝞨𝞨; 𝞨𝞨; Ω; Ω; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7A9;1D7A9;1D7A9;2207;2207; # (𝞩𝞩; 𝞩𝞩; 𝞩𝞩; ∇; ∇; ) MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7AA;1D7AA;1D7AA;03B1;03B1; # (𝞪𝞪; 𝞪𝞪; 𝞪𝞪; α; α; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA +1D7AB;1D7AB;1D7AB;03B2;03B2; # (𝞫𝞫; 𝞫𝞫; 𝞫𝞫; β; β; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA +1D7AC;1D7AC;1D7AC;03B3;03B3; # (𝞬𝞬; 𝞬𝞬; 𝞬𝞬; γ; γ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA +1D7AD;1D7AD;1D7AD;03B4;03B4; # (𝞭𝞭; 𝞭𝞭; 𝞭𝞭; δ; δ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA +1D7AE;1D7AE;1D7AE;03B5;03B5; # (𝞮𝞮; 𝞮𝞮; 𝞮𝞮; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON +1D7AF;1D7AF;1D7AF;03B6;03B6; # (𝞯𝞯; 𝞯𝞯; 𝞯𝞯; ζ; ζ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA +1D7B0;1D7B0;1D7B0;03B7;03B7; # (𝞰𝞰; 𝞰𝞰; 𝞰𝞰; η; η; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA +1D7B1;1D7B1;1D7B1;03B8;03B8; # (𝞱𝞱; 𝞱𝞱; 𝞱𝞱; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA +1D7B2;1D7B2;1D7B2;03B9;03B9; # (𝞲𝞲; 𝞲𝞲; 𝞲𝞲; ι; ι; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA +1D7B3;1D7B3;1D7B3;03BA;03BA; # (𝞳𝞳; 𝞳𝞳; 𝞳𝞳; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA +1D7B4;1D7B4;1D7B4;03BB;03BB; # (𝞴𝞴; 𝞴𝞴; 𝞴𝞴; λ; λ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA +1D7B5;1D7B5;1D7B5;03BC;03BC; # (𝞵𝞵; 𝞵𝞵; 𝞵𝞵; μ; μ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU +1D7B6;1D7B6;1D7B6;03BD;03BD; # (𝞶𝞶; 𝞶𝞶; 𝞶𝞶; ν; ν; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU +1D7B7;1D7B7;1D7B7;03BE;03BE; # (𝞷𝞷; 𝞷𝞷; 𝞷𝞷; ξ; ξ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI +1D7B8;1D7B8;1D7B8;03BF;03BF; # (𝞸𝞸; 𝞸𝞸; 𝞸𝞸; ο; ο; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON +1D7B9;1D7B9;1D7B9;03C0;03C0; # (𝞹𝞹; 𝞹𝞹; 𝞹𝞹; π; π; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI +1D7BA;1D7BA;1D7BA;03C1;03C1; # (𝞺𝞺; 𝞺𝞺; 𝞺𝞺; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO +1D7BB;1D7BB;1D7BB;03C2;03C2; # (𝞻𝞻; 𝞻𝞻; 𝞻𝞻; ς; ς; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA +1D7BC;1D7BC;1D7BC;03C3;03C3; # (𝞼𝞼; 𝞼𝞼; 𝞼𝞼; σ; σ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA +1D7BD;1D7BD;1D7BD;03C4;03C4; # (𝞽𝞽; 𝞽𝞽; 𝞽𝞽; τ; τ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU +1D7BE;1D7BE;1D7BE;03C5;03C5; # (𝞾𝞾; 𝞾𝞾; 𝞾𝞾; υ; υ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON +1D7BF;1D7BF;1D7BF;03C6;03C6; # (𝞿𝞿; 𝞿𝞿; 𝞿𝞿; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI +1D7C0;1D7C0;1D7C0;03C7;03C7; # (𝟀𝟀; 𝟀𝟀; 𝟀𝟀; χ; χ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI +1D7C1;1D7C1;1D7C1;03C8;03C8; # (𝟁𝟁; 𝟁𝟁; 𝟁𝟁; ψ; ψ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI +1D7C2;1D7C2;1D7C2;03C9;03C9; # (𝟂𝟂; 𝟂𝟂; 𝟂𝟂; ω; ω; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C3;1D7C3;1D7C3;2202;2202; # (𝟃𝟃; 𝟃𝟃; 𝟃𝟃; ∂; ∂; ) MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D7C4;1D7C4;1D7C4;03B5;03B5; # (𝟄𝟄; 𝟄𝟄; 𝟄𝟄; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL +1D7C5;1D7C5;1D7C5;03B8;03B8; # (𝟅𝟅; 𝟅𝟅; 𝟅𝟅; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL +1D7C6;1D7C6;1D7C6;03BA;03BA; # (𝟆𝟆; 𝟆𝟆; 𝟆𝟆; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL +1D7C7;1D7C7;1D7C7;03C6;03C6; # (𝟇𝟇; 𝟇𝟇; 𝟇𝟇; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL +1D7C8;1D7C8;1D7C8;03C1;03C1; # (𝟈𝟈; 𝟈𝟈; 𝟈𝟈; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL +1D7C9;1D7C9;1D7C9;03C0;03C0; # (𝟉𝟉; 𝟉𝟉; 𝟉𝟉; π; π; ) MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL +1D7CE;1D7CE;1D7CE;0030;0030; # (𝟎𝟎; 𝟎𝟎; 𝟎𝟎; 0; 0; ) MATHEMATICAL BOLD DIGIT ZERO +1D7CF;1D7CF;1D7CF;0031;0031; # (𝟏𝟏; 𝟏𝟏; 𝟏𝟏; 1; 1; ) MATHEMATICAL BOLD DIGIT ONE +1D7D0;1D7D0;1D7D0;0032;0032; # (𝟐𝟐; 𝟐𝟐; 𝟐𝟐; 2; 2; ) MATHEMATICAL BOLD DIGIT TWO +1D7D1;1D7D1;1D7D1;0033;0033; # (𝟑𝟑; 𝟑𝟑; 𝟑𝟑; 3; 3; ) MATHEMATICAL BOLD DIGIT THREE +1D7D2;1D7D2;1D7D2;0034;0034; # (𝟒𝟒; 𝟒𝟒; 𝟒𝟒; 4; 4; ) MATHEMATICAL BOLD DIGIT FOUR +1D7D3;1D7D3;1D7D3;0035;0035; # (𝟓𝟓; 𝟓𝟓; 𝟓𝟓; 5; 5; ) MATHEMATICAL BOLD DIGIT FIVE +1D7D4;1D7D4;1D7D4;0036;0036; # (𝟔𝟔; 𝟔𝟔; 𝟔𝟔; 6; 6; ) MATHEMATICAL BOLD DIGIT SIX +1D7D5;1D7D5;1D7D5;0037;0037; # (𝟕𝟕; 𝟕𝟕; 𝟕𝟕; 7; 7; ) MATHEMATICAL BOLD DIGIT SEVEN +1D7D6;1D7D6;1D7D6;0038;0038; # (𝟖𝟖; 𝟖𝟖; 𝟖𝟖; 8; 8; ) MATHEMATICAL BOLD DIGIT EIGHT +1D7D7;1D7D7;1D7D7;0039;0039; # (𝟗𝟗; 𝟗𝟗; 𝟗𝟗; 9; 9; ) MATHEMATICAL BOLD DIGIT NINE +1D7D8;1D7D8;1D7D8;0030;0030; # (𝟘𝟘; 𝟘𝟘; 𝟘𝟘; 0; 0; ) MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO +1D7D9;1D7D9;1D7D9;0031;0031; # (𝟙𝟙; 𝟙𝟙; 𝟙𝟙; 1; 1; ) MATHEMATICAL DOUBLE-STRUCK DIGIT ONE +1D7DA;1D7DA;1D7DA;0032;0032; # (𝟚𝟚; 𝟚𝟚; 𝟚𝟚; 2; 2; ) MATHEMATICAL DOUBLE-STRUCK DIGIT TWO +1D7DB;1D7DB;1D7DB;0033;0033; # (𝟛𝟛; 𝟛𝟛; 𝟛𝟛; 3; 3; ) MATHEMATICAL DOUBLE-STRUCK DIGIT THREE +1D7DC;1D7DC;1D7DC;0034;0034; # (𝟜𝟜; 𝟜𝟜; 𝟜𝟜; 4; 4; ) MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR +1D7DD;1D7DD;1D7DD;0035;0035; # (𝟝𝟝; 𝟝𝟝; 𝟝𝟝; 5; 5; ) MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE +1D7DE;1D7DE;1D7DE;0036;0036; # (𝟞𝟞; 𝟞𝟞; 𝟞𝟞; 6; 6; ) MATHEMATICAL DOUBLE-STRUCK DIGIT SIX +1D7DF;1D7DF;1D7DF;0037;0037; # (𝟟𝟟; 𝟟𝟟; 𝟟𝟟; 7; 7; ) MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN +1D7E0;1D7E0;1D7E0;0038;0038; # (𝟠𝟠; 𝟠𝟠; 𝟠𝟠; 8; 8; ) MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT +1D7E1;1D7E1;1D7E1;0039;0039; # (𝟡𝟡; 𝟡𝟡; 𝟡𝟡; 9; 9; ) MATHEMATICAL DOUBLE-STRUCK DIGIT NINE +1D7E2;1D7E2;1D7E2;0030;0030; # (𝟢𝟢; 𝟢𝟢; 𝟢𝟢; 0; 0; ) MATHEMATICAL SANS-SERIF DIGIT ZERO +1D7E3;1D7E3;1D7E3;0031;0031; # (𝟣𝟣; 𝟣𝟣; 𝟣𝟣; 1; 1; ) MATHEMATICAL SANS-SERIF DIGIT ONE +1D7E4;1D7E4;1D7E4;0032;0032; # (𝟤𝟤; 𝟤𝟤; 𝟤𝟤; 2; 2; ) MATHEMATICAL SANS-SERIF DIGIT TWO +1D7E5;1D7E5;1D7E5;0033;0033; # (𝟥𝟥; 𝟥𝟥; 𝟥𝟥; 3; 3; ) MATHEMATICAL SANS-SERIF DIGIT THREE +1D7E6;1D7E6;1D7E6;0034;0034; # (𝟦𝟦; 𝟦𝟦; 𝟦𝟦; 4; 4; ) MATHEMATICAL SANS-SERIF DIGIT FOUR +1D7E7;1D7E7;1D7E7;0035;0035; # (𝟧𝟧; 𝟧𝟧; 𝟧𝟧; 5; 5; ) MATHEMATICAL SANS-SERIF DIGIT FIVE +1D7E8;1D7E8;1D7E8;0036;0036; # (𝟨𝟨; 𝟨𝟨; 𝟨𝟨; 6; 6; ) MATHEMATICAL SANS-SERIF DIGIT SIX +1D7E9;1D7E9;1D7E9;0037;0037; # (𝟩𝟩; 𝟩𝟩; 𝟩𝟩; 7; 7; ) MATHEMATICAL SANS-SERIF DIGIT SEVEN +1D7EA;1D7EA;1D7EA;0038;0038; # (𝟪𝟪; 𝟪𝟪; 𝟪𝟪; 8; 8; ) MATHEMATICAL SANS-SERIF DIGIT EIGHT +1D7EB;1D7EB;1D7EB;0039;0039; # (𝟫𝟫; 𝟫𝟫; 𝟫𝟫; 9; 9; ) MATHEMATICAL SANS-SERIF DIGIT NINE +1D7EC;1D7EC;1D7EC;0030;0030; # (𝟬𝟬; 𝟬𝟬; 𝟬𝟬; 0; 0; ) MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO +1D7ED;1D7ED;1D7ED;0031;0031; # (𝟭𝟭; 𝟭𝟭; 𝟭𝟭; 1; 1; ) MATHEMATICAL SANS-SERIF BOLD DIGIT ONE +1D7EE;1D7EE;1D7EE;0032;0032; # (𝟮𝟮; 𝟮𝟮; 𝟮𝟮; 2; 2; ) MATHEMATICAL SANS-SERIF BOLD DIGIT TWO +1D7EF;1D7EF;1D7EF;0033;0033; # (𝟯𝟯; 𝟯𝟯; 𝟯𝟯; 3; 3; ) MATHEMATICAL SANS-SERIF BOLD DIGIT THREE +1D7F0;1D7F0;1D7F0;0034;0034; # (𝟰𝟰; 𝟰𝟰; 𝟰𝟰; 4; 4; ) MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR +1D7F1;1D7F1;1D7F1;0035;0035; # (𝟱𝟱; 𝟱𝟱; 𝟱𝟱; 5; 5; ) MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE +1D7F2;1D7F2;1D7F2;0036;0036; # (𝟲𝟲; 𝟲𝟲; 𝟲𝟲; 6; 6; ) MATHEMATICAL SANS-SERIF BOLD DIGIT SIX +1D7F3;1D7F3;1D7F3;0037;0037; # (𝟳𝟳; 𝟳𝟳; 𝟳𝟳; 7; 7; ) MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN +1D7F4;1D7F4;1D7F4;0038;0038; # (𝟴𝟴; 𝟴𝟴; 𝟴𝟴; 8; 8; ) MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT +1D7F5;1D7F5;1D7F5;0039;0039; # (𝟵𝟵; 𝟵𝟵; 𝟵𝟵; 9; 9; ) MATHEMATICAL SANS-SERIF BOLD DIGIT NINE +1D7F6;1D7F6;1D7F6;0030;0030; # (𝟶𝟶; 𝟶𝟶; 𝟶𝟶; 0; 0; ) MATHEMATICAL MONOSPACE DIGIT ZERO +1D7F7;1D7F7;1D7F7;0031;0031; # (𝟷𝟷; 𝟷𝟷; 𝟷𝟷; 1; 1; ) MATHEMATICAL MONOSPACE DIGIT ONE +1D7F8;1D7F8;1D7F8;0032;0032; # (𝟸𝟸; 𝟸𝟸; 𝟸𝟸; 2; 2; ) MATHEMATICAL MONOSPACE DIGIT TWO +1D7F9;1D7F9;1D7F9;0033;0033; # (𝟹𝟹; 𝟹𝟹; 𝟹𝟹; 3; 3; ) MATHEMATICAL MONOSPACE DIGIT THREE +1D7FA;1D7FA;1D7FA;0034;0034; # (𝟺𝟺; 𝟺𝟺; 𝟺𝟺; 4; 4; ) MATHEMATICAL MONOSPACE DIGIT FOUR +1D7FB;1D7FB;1D7FB;0035;0035; # (𝟻𝟻; 𝟻𝟻; 𝟻𝟻; 5; 5; ) MATHEMATICAL MONOSPACE DIGIT FIVE +1D7FC;1D7FC;1D7FC;0036;0036; # (𝟼𝟼; 𝟼𝟼; 𝟼𝟼; 6; 6; ) MATHEMATICAL MONOSPACE DIGIT SIX +1D7FD;1D7FD;1D7FD;0037;0037; # (𝟽𝟽; 𝟽𝟽; 𝟽𝟽; 7; 7; ) MATHEMATICAL MONOSPACE DIGIT SEVEN +1D7FE;1D7FE;1D7FE;0038;0038; # (𝟾𝟾; 𝟾𝟾; 𝟾𝟾; 8; 8; ) MATHEMATICAL MONOSPACE DIGIT EIGHT +1D7FF;1D7FF;1D7FF;0039;0039; # (𝟿𝟿; 𝟿𝟿; 𝟿𝟿; 9; 9; ) MATHEMATICAL MONOSPACE DIGIT NINE +2F800;4E3D;4E3D;4E3D;4E3D; # (丽丽; 丽; 丽; 丽; 丽; ) CJK COMPATIBILITY IDEOGRAPH-2F800 +2F801;4E38;4E38;4E38;4E38; # (丸丸; 丸; 丸; 丸; 丸; ) CJK COMPATIBILITY IDEOGRAPH-2F801 +2F802;4E41;4E41;4E41;4E41; # (乁乁; 乁; 乁; 乁; 乁; ) CJK COMPATIBILITY IDEOGRAPH-2F802 +2F803;20122;20122;20122;20122; # (𠄢𠄢; 𠄢𠄢; 𠄢𠄢; 𠄢𠄢; 𠄢𠄢; ) CJK COMPATIBILITY IDEOGRAPH-2F803 +2F804;4F60;4F60;4F60;4F60; # (你你; 你; 你; 你; 你; ) CJK COMPATIBILITY IDEOGRAPH-2F804 +2F805;4FAE;4FAE;4FAE;4FAE; # (侮侮; 侮; 侮; 侮; 侮; ) CJK COMPATIBILITY IDEOGRAPH-2F805 +2F806;4FBB;4FBB;4FBB;4FBB; # (侻侻; 侻; 侻; 侻; 侻; ) CJK COMPATIBILITY IDEOGRAPH-2F806 +2F807;5002;5002;5002;5002; # (倂倂; 倂; 倂; 倂; 倂; ) CJK COMPATIBILITY IDEOGRAPH-2F807 +2F808;507A;507A;507A;507A; # (偺偺; 偺; 偺; 偺; 偺; ) CJK COMPATIBILITY IDEOGRAPH-2F808 +2F809;5099;5099;5099;5099; # (備備; 備; 備; 備; 備; ) CJK COMPATIBILITY IDEOGRAPH-2F809 +2F80A;50E7;50E7;50E7;50E7; # (僧僧; 僧; 僧; 僧; 僧; ) CJK COMPATIBILITY IDEOGRAPH-2F80A +2F80B;50CF;50CF;50CF;50CF; # (像像; 像; 像; 像; 像; ) CJK COMPATIBILITY IDEOGRAPH-2F80B +2F80C;349E;349E;349E;349E; # (㒞㒞; 㒞; 㒞; 㒞; 㒞; ) CJK COMPATIBILITY IDEOGRAPH-2F80C +2F80D;2063A;2063A;2063A;2063A; # (𠘺𠘺; 𠘺𠘺; 𠘺𠘺; 𠘺𠘺; 𠘺𠘺; ) CJK COMPATIBILITY IDEOGRAPH-2F80D +2F80E;514D;514D;514D;514D; # (免免; 免; 免; 免; 免; ) CJK COMPATIBILITY IDEOGRAPH-2F80E +2F80F;5154;5154;5154;5154; # (兔兔; 兔; 兔; 兔; 兔; ) CJK COMPATIBILITY IDEOGRAPH-2F80F +2F810;5164;5164;5164;5164; # (兤兤; 兤; 兤; 兤; 兤; ) CJK COMPATIBILITY IDEOGRAPH-2F810 +2F811;5177;5177;5177;5177; # (具具; 具; 具; 具; 具; ) CJK COMPATIBILITY IDEOGRAPH-2F811 +2F812;2051C;2051C;2051C;2051C; # (𠔜𠔜; 𠔜𠔜; 𠔜𠔜; 𠔜𠔜; 𠔜𠔜; ) CJK COMPATIBILITY IDEOGRAPH-2F812 +2F813;34B9;34B9;34B9;34B9; # (㒹㒹; 㒹; 㒹; 㒹; 㒹; ) CJK COMPATIBILITY IDEOGRAPH-2F813 +2F814;5167;5167;5167;5167; # (內內; 內; 內; 內; 內; ) CJK COMPATIBILITY IDEOGRAPH-2F814 +2F815;518D;518D;518D;518D; # (再再; 再; 再; 再; 再; ) CJK COMPATIBILITY IDEOGRAPH-2F815 +2F816;2054B;2054B;2054B;2054B; # (𠕋𠕋; 𠕋𠕋; 𠕋𠕋; 𠕋𠕋; 𠕋𠕋; ) CJK COMPATIBILITY IDEOGRAPH-2F816 +2F817;5197;5197;5197;5197; # (冗冗; 冗; 冗; 冗; 冗; ) CJK COMPATIBILITY IDEOGRAPH-2F817 +2F818;51A4;51A4;51A4;51A4; # (冤冤; 冤; 冤; 冤; 冤; ) CJK COMPATIBILITY IDEOGRAPH-2F818 +2F819;4ECC;4ECC;4ECC;4ECC; # (仌仌; 仌; 仌; 仌; 仌; ) CJK COMPATIBILITY IDEOGRAPH-2F819 +2F81A;51AC;51AC;51AC;51AC; # (冬冬; 冬; 冬; 冬; 冬; ) CJK COMPATIBILITY IDEOGRAPH-2F81A +2F81B;51B5;51B5;51B5;51B5; # (况况; 况; 况; 况; 况; ) CJK COMPATIBILITY IDEOGRAPH-2F81B +2F81C;291DF;291DF;291DF;291DF; # (𩇟𩇟; 𩇟𩇟; 𩇟𩇟; 𩇟𩇟; 𩇟𩇟; ) CJK COMPATIBILITY IDEOGRAPH-2F81C +2F81D;51F5;51F5;51F5;51F5; # (凵凵; 凵; 凵; 凵; 凵; ) CJK COMPATIBILITY IDEOGRAPH-2F81D +2F81E;5203;5203;5203;5203; # (刃刃; 刃; 刃; 刃; 刃; ) CJK COMPATIBILITY IDEOGRAPH-2F81E +2F81F;34DF;34DF;34DF;34DF; # (㓟㓟; 㓟; 㓟; 㓟; 㓟; ) CJK COMPATIBILITY IDEOGRAPH-2F81F +2F820;523B;523B;523B;523B; # (刻刻; 刻; 刻; 刻; 刻; ) CJK COMPATIBILITY IDEOGRAPH-2F820 +2F821;5246;5246;5246;5246; # (剆剆; 剆; 剆; 剆; 剆; ) CJK COMPATIBILITY IDEOGRAPH-2F821 +2F822;5272;5272;5272;5272; # (割割; 割; 割; 割; 割; ) CJK COMPATIBILITY IDEOGRAPH-2F822 +2F823;5277;5277;5277;5277; # (剷剷; 剷; 剷; 剷; 剷; ) CJK COMPATIBILITY IDEOGRAPH-2F823 +2F824;3515;3515;3515;3515; # (㔕㔕; 㔕; 㔕; 㔕; 㔕; ) CJK COMPATIBILITY IDEOGRAPH-2F824 +2F825;52C7;52C7;52C7;52C7; # (勇勇; 勇; 勇; 勇; 勇; ) CJK COMPATIBILITY IDEOGRAPH-2F825 +2F826;52C9;52C9;52C9;52C9; # (勉勉; 勉; 勉; 勉; 勉; ) CJK COMPATIBILITY IDEOGRAPH-2F826 +2F827;52E4;52E4;52E4;52E4; # (勤勤; 勤; 勤; 勤; 勤; ) CJK COMPATIBILITY IDEOGRAPH-2F827 +2F828;52FA;52FA;52FA;52FA; # (勺勺; 勺; 勺; 勺; 勺; ) CJK COMPATIBILITY IDEOGRAPH-2F828 +2F829;5305;5305;5305;5305; # (包包; 包; 包; 包; 包; ) CJK COMPATIBILITY IDEOGRAPH-2F829 +2F82A;5306;5306;5306;5306; # (匆匆; 匆; 匆; 匆; 匆; ) CJK COMPATIBILITY IDEOGRAPH-2F82A +2F82B;5317;5317;5317;5317; # (北北; 北; 北; 北; 北; ) CJK COMPATIBILITY IDEOGRAPH-2F82B +2F82C;5349;5349;5349;5349; # (卉卉; 卉; 卉; 卉; 卉; ) CJK COMPATIBILITY IDEOGRAPH-2F82C +2F82D;5351;5351;5351;5351; # (卑卑; 卑; 卑; 卑; 卑; ) CJK COMPATIBILITY IDEOGRAPH-2F82D +2F82E;535A;535A;535A;535A; # (博博; 博; 博; 博; 博; ) CJK COMPATIBILITY IDEOGRAPH-2F82E +2F82F;5373;5373;5373;5373; # (即即; 即; 即; 即; 即; ) CJK COMPATIBILITY IDEOGRAPH-2F82F +2F830;537D;537D;537D;537D; # (卽卽; 卽; 卽; 卽; 卽; ) CJK COMPATIBILITY IDEOGRAPH-2F830 +2F831;537F;537F;537F;537F; # (卿卿; 卿; 卿; 卿; 卿; ) CJK COMPATIBILITY IDEOGRAPH-2F831 +2F832;537F;537F;537F;537F; # (卿卿; 卿; 卿; 卿; 卿; ) CJK COMPATIBILITY IDEOGRAPH-2F832 +2F833;537F;537F;537F;537F; # (卿卿; 卿; 卿; 卿; 卿; ) CJK COMPATIBILITY IDEOGRAPH-2F833 +2F834;20A2C;20A2C;20A2C;20A2C; # (𠨬𠨬; 𠨬𠨬; 𠨬𠨬; 𠨬𠨬; 𠨬𠨬; ) CJK COMPATIBILITY IDEOGRAPH-2F834 +2F835;7070;7070;7070;7070; # (灰灰; 灰; 灰; 灰; 灰; ) CJK COMPATIBILITY IDEOGRAPH-2F835 +2F836;53CA;53CA;53CA;53CA; # (及及; 及; 及; 及; 及; ) CJK COMPATIBILITY IDEOGRAPH-2F836 +2F837;53DF;53DF;53DF;53DF; # (叟叟; 叟; 叟; 叟; 叟; ) CJK COMPATIBILITY IDEOGRAPH-2F837 +2F838;20B63;20B63;20B63;20B63; # (𠭣𠭣; 𠭣𠭣; 𠭣𠭣; 𠭣𠭣; 𠭣𠭣; ) CJK COMPATIBILITY IDEOGRAPH-2F838 +2F839;53EB;53EB;53EB;53EB; # (叫叫; 叫; 叫; 叫; 叫; ) CJK COMPATIBILITY IDEOGRAPH-2F839 +2F83A;53F1;53F1;53F1;53F1; # (叱叱; 叱; 叱; 叱; 叱; ) CJK COMPATIBILITY IDEOGRAPH-2F83A +2F83B;5406;5406;5406;5406; # (吆吆; 吆; 吆; 吆; 吆; ) CJK COMPATIBILITY IDEOGRAPH-2F83B +2F83C;549E;549E;549E;549E; # (咞咞; 咞; 咞; 咞; 咞; ) CJK COMPATIBILITY IDEOGRAPH-2F83C +2F83D;5438;5438;5438;5438; # (吸吸; 吸; 吸; 吸; 吸; ) CJK COMPATIBILITY IDEOGRAPH-2F83D +2F83E;5448;5448;5448;5448; # (呈呈; 呈; 呈; 呈; 呈; ) CJK COMPATIBILITY IDEOGRAPH-2F83E +2F83F;5468;5468;5468;5468; # (周周; 周; 周; 周; 周; ) CJK COMPATIBILITY IDEOGRAPH-2F83F +2F840;54A2;54A2;54A2;54A2; # (咢咢; 咢; 咢; 咢; 咢; ) CJK COMPATIBILITY IDEOGRAPH-2F840 +2F841;54F6;54F6;54F6;54F6; # (哶哶; 哶; 哶; 哶; 哶; ) CJK COMPATIBILITY IDEOGRAPH-2F841 +2F842;5510;5510;5510;5510; # (唐唐; 唐; 唐; 唐; 唐; ) CJK COMPATIBILITY IDEOGRAPH-2F842 +2F843;5553;5553;5553;5553; # (啓啓; 啓; 啓; 啓; 啓; ) CJK COMPATIBILITY IDEOGRAPH-2F843 +2F844;5563;5563;5563;5563; # (啣啣; 啣; 啣; 啣; 啣; ) CJK COMPATIBILITY IDEOGRAPH-2F844 +2F845;5584;5584;5584;5584; # (善善; 善; 善; 善; 善; ) CJK COMPATIBILITY IDEOGRAPH-2F845 +2F846;5584;5584;5584;5584; # (善善; 善; 善; 善; 善; ) CJK COMPATIBILITY IDEOGRAPH-2F846 +2F847;5599;5599;5599;5599; # (喙喙; 喙; 喙; 喙; 喙; ) CJK COMPATIBILITY IDEOGRAPH-2F847 +2F848;55AB;55AB;55AB;55AB; # (喫喫; 喫; 喫; 喫; 喫; ) CJK COMPATIBILITY IDEOGRAPH-2F848 +2F849;55B3;55B3;55B3;55B3; # (喳喳; 喳; 喳; 喳; 喳; ) CJK COMPATIBILITY IDEOGRAPH-2F849 +2F84A;55C2;55C2;55C2;55C2; # (嗂嗂; 嗂; 嗂; 嗂; 嗂; ) CJK COMPATIBILITY IDEOGRAPH-2F84A +2F84B;5716;5716;5716;5716; # (圖圖; 圖; 圖; 圖; 圖; ) CJK COMPATIBILITY IDEOGRAPH-2F84B +2F84C;5606;5606;5606;5606; # (嘆嘆; 嘆; 嘆; 嘆; 嘆; ) CJK COMPATIBILITY IDEOGRAPH-2F84C +2F84D;5717;5717;5717;5717; # (圗圗; 圗; 圗; 圗; 圗; ) CJK COMPATIBILITY IDEOGRAPH-2F84D +2F84E;5651;5651;5651;5651; # (噑噑; 噑; 噑; 噑; 噑; ) CJK COMPATIBILITY IDEOGRAPH-2F84E +2F84F;5674;5674;5674;5674; # (噴噴; 噴; 噴; 噴; 噴; ) CJK COMPATIBILITY IDEOGRAPH-2F84F +2F850;5207;5207;5207;5207; # (切切; 切; 切; 切; 切; ) CJK COMPATIBILITY IDEOGRAPH-2F850 +2F851;58EE;58EE;58EE;58EE; # (壮壮; 壮; 壮; 壮; 壮; ) CJK COMPATIBILITY IDEOGRAPH-2F851 +2F852;57CE;57CE;57CE;57CE; # (城城; 城; 城; 城; 城; ) CJK COMPATIBILITY IDEOGRAPH-2F852 +2F853;57F4;57F4;57F4;57F4; # (埴埴; 埴; 埴; 埴; 埴; ) CJK COMPATIBILITY IDEOGRAPH-2F853 +2F854;580D;580D;580D;580D; # (堍堍; 堍; 堍; 堍; 堍; ) CJK COMPATIBILITY IDEOGRAPH-2F854 +2F855;578B;578B;578B;578B; # (型型; 型; 型; 型; 型; ) CJK COMPATIBILITY IDEOGRAPH-2F855 +2F856;5832;5832;5832;5832; # (堲堲; 堲; 堲; 堲; 堲; ) CJK COMPATIBILITY IDEOGRAPH-2F856 +2F857;5831;5831;5831;5831; # (報報; 報; 報; 報; 報; ) CJK COMPATIBILITY IDEOGRAPH-2F857 +2F858;58AC;58AC;58AC;58AC; # (墬墬; 墬; 墬; 墬; 墬; ) CJK COMPATIBILITY IDEOGRAPH-2F858 +2F859;214E4;214E4;214E4;214E4; # (𡓤𡓤; 𡓤𡓤; 𡓤𡓤; 𡓤𡓤; 𡓤𡓤; ) CJK COMPATIBILITY IDEOGRAPH-2F859 +2F85A;58F2;58F2;58F2;58F2; # (売売; 売; 売; 売; 売; ) CJK COMPATIBILITY IDEOGRAPH-2F85A +2F85B;58F7;58F7;58F7;58F7; # (壷壷; 壷; 壷; 壷; 壷; ) CJK COMPATIBILITY IDEOGRAPH-2F85B +2F85C;5906;5906;5906;5906; # (夆夆; 夆; 夆; 夆; 夆; ) CJK COMPATIBILITY IDEOGRAPH-2F85C +2F85D;591A;591A;591A;591A; # (多多; 多; 多; 多; 多; ) CJK COMPATIBILITY IDEOGRAPH-2F85D +2F85E;5922;5922;5922;5922; # (夢夢; 夢; 夢; 夢; 夢; ) CJK COMPATIBILITY IDEOGRAPH-2F85E +2F85F;5962;5962;5962;5962; # (奢奢; 奢; 奢; 奢; 奢; ) CJK COMPATIBILITY IDEOGRAPH-2F85F +2F860;216A8;216A8;216A8;216A8; # (𡚨𡚨; 𡚨𡚨; 𡚨𡚨; 𡚨𡚨; 𡚨𡚨; ) CJK COMPATIBILITY IDEOGRAPH-2F860 +2F861;216EA;216EA;216EA;216EA; # (𡛪𡛪; 𡛪𡛪; 𡛪𡛪; 𡛪𡛪; 𡛪𡛪; ) CJK COMPATIBILITY IDEOGRAPH-2F861 +2F862;59EC;59EC;59EC;59EC; # (姬姬; 姬; 姬; 姬; 姬; ) CJK COMPATIBILITY IDEOGRAPH-2F862 +2F863;5A1B;5A1B;5A1B;5A1B; # (娛娛; 娛; 娛; 娛; 娛; ) CJK COMPATIBILITY IDEOGRAPH-2F863 +2F864;5A27;5A27;5A27;5A27; # (娧娧; 娧; 娧; 娧; 娧; ) CJK COMPATIBILITY IDEOGRAPH-2F864 +2F865;59D8;59D8;59D8;59D8; # (姘姘; 姘; 姘; 姘; 姘; ) CJK COMPATIBILITY IDEOGRAPH-2F865 +2F866;5A66;5A66;5A66;5A66; # (婦婦; 婦; 婦; 婦; 婦; ) CJK COMPATIBILITY IDEOGRAPH-2F866 +2F867;36EE;36EE;36EE;36EE; # (㛮㛮; 㛮; 㛮; 㛮; 㛮; ) CJK COMPATIBILITY IDEOGRAPH-2F867 +2F868;2136A;2136A;2136A;2136A; # (㛼㛼; 𡍪𡍪; 𡍪𡍪; 𡍪𡍪; 𡍪𡍪; ) CJK COMPATIBILITY IDEOGRAPH-2F868 +2F869;5B08;5B08;5B08;5B08; # (嬈嬈; 嬈; 嬈; 嬈; 嬈; ) CJK COMPATIBILITY IDEOGRAPH-2F869 +2F86A;5B3E;5B3E;5B3E;5B3E; # (嬾嬾; 嬾; 嬾; 嬾; 嬾; ) CJK COMPATIBILITY IDEOGRAPH-2F86A +2F86B;5B3E;5B3E;5B3E;5B3E; # (嬾嬾; 嬾; 嬾; 嬾; 嬾; ) CJK COMPATIBILITY IDEOGRAPH-2F86B +2F86C;219C8;219C8;219C8;219C8; # (𡧈𡧈; 𡧈𡧈; 𡧈𡧈; 𡧈𡧈; 𡧈𡧈; ) CJK COMPATIBILITY IDEOGRAPH-2F86C +2F86D;5BC3;5BC3;5BC3;5BC3; # (寃寃; 寃; 寃; 寃; 寃; ) CJK COMPATIBILITY IDEOGRAPH-2F86D +2F86E;5BD8;5BD8;5BD8;5BD8; # (寘寘; 寘; 寘; 寘; 寘; ) CJK COMPATIBILITY IDEOGRAPH-2F86E +2F86F;5BE7;5BE7;5BE7;5BE7; # (寧寧; 寧; 寧; 寧; 寧; ) CJK COMPATIBILITY IDEOGRAPH-2F86F +2F870;5BF3;5BF3;5BF3;5BF3; # (寳寳; 寳; 寳; 寳; 寳; ) CJK COMPATIBILITY IDEOGRAPH-2F870 +2F871;21B18;21B18;21B18;21B18; # (𡬘𡬘; 𡬘𡬘; 𡬘𡬘; 𡬘𡬘; 𡬘𡬘; ) CJK COMPATIBILITY IDEOGRAPH-2F871 +2F872;5BFF;5BFF;5BFF;5BFF; # (寿寿; 寿; 寿; 寿; 寿; ) CJK COMPATIBILITY IDEOGRAPH-2F872 +2F873;5C06;5C06;5C06;5C06; # (将将; 将; 将; 将; 将; ) CJK COMPATIBILITY IDEOGRAPH-2F873 +2F874;5F33;5F33;5F33;5F33; # (当当; 弳; 弳; 弳; 弳; ) CJK COMPATIBILITY IDEOGRAPH-2F874 +2F875;5C22;5C22;5C22;5C22; # (尢尢; 尢; 尢; 尢; 尢; ) CJK COMPATIBILITY IDEOGRAPH-2F875 +2F876;3781;3781;3781;3781; # (㞁㞁; 㞁; 㞁; 㞁; 㞁; ) CJK COMPATIBILITY IDEOGRAPH-2F876 +2F877;5C60;5C60;5C60;5C60; # (屠屠; 屠; 屠; 屠; 屠; ) CJK COMPATIBILITY IDEOGRAPH-2F877 +2F878;5C6E;5C6E;5C6E;5C6E; # (屮屮; 屮; 屮; 屮; 屮; ) CJK COMPATIBILITY IDEOGRAPH-2F878 +2F879;5CC0;5CC0;5CC0;5CC0; # (峀峀; 峀; 峀; 峀; 峀; ) CJK COMPATIBILITY IDEOGRAPH-2F879 +2F87A;5C8D;5C8D;5C8D;5C8D; # (岍岍; 岍; 岍; 岍; 岍; ) CJK COMPATIBILITY IDEOGRAPH-2F87A +2F87B;21DE4;21DE4;21DE4;21DE4; # (𡷤𡷤; 𡷤𡷤; 𡷤𡷤; 𡷤𡷤; 𡷤𡷤; ) CJK COMPATIBILITY IDEOGRAPH-2F87B +2F87C;5D43;5D43;5D43;5D43; # (嵃嵃; 嵃; 嵃; 嵃; 嵃; ) CJK COMPATIBILITY IDEOGRAPH-2F87C +2F87D;21DE6;21DE6;21DE6;21DE6; # (𡷦𡷦; 𡷦𡷦; 𡷦𡷦; 𡷦𡷦; 𡷦𡷦; ) CJK COMPATIBILITY IDEOGRAPH-2F87D +2F87E;5D6E;5D6E;5D6E;5D6E; # (嵮嵮; 嵮; 嵮; 嵮; 嵮; ) CJK COMPATIBILITY IDEOGRAPH-2F87E +2F87F;5D6B;5D6B;5D6B;5D6B; # (嵫嵫; 嵫; 嵫; 嵫; 嵫; ) CJK COMPATIBILITY IDEOGRAPH-2F87F +2F880;5D7C;5D7C;5D7C;5D7C; # (嵼嵼; 嵼; 嵼; 嵼; 嵼; ) CJK COMPATIBILITY IDEOGRAPH-2F880 +2F881;5DE1;5DE1;5DE1;5DE1; # (巡巡; 巡; 巡; 巡; 巡; ) CJK COMPATIBILITY IDEOGRAPH-2F881 +2F882;5DE2;5DE2;5DE2;5DE2; # (巢巢; 巢; 巢; 巢; 巢; ) CJK COMPATIBILITY IDEOGRAPH-2F882 +2F883;382F;382F;382F;382F; # (㠯㠯; 㠯; 㠯; 㠯; 㠯; ) CJK COMPATIBILITY IDEOGRAPH-2F883 +2F884;5DFD;5DFD;5DFD;5DFD; # (巽巽; 巽; 巽; 巽; 巽; ) CJK COMPATIBILITY IDEOGRAPH-2F884 +2F885;5E28;5E28;5E28;5E28; # (帨帨; 帨; 帨; 帨; 帨; ) CJK COMPATIBILITY IDEOGRAPH-2F885 +2F886;5E3D;5E3D;5E3D;5E3D; # (帽帽; 帽; 帽; 帽; 帽; ) CJK COMPATIBILITY IDEOGRAPH-2F886 +2F887;5E69;5E69;5E69;5E69; # (幩幩; 幩; 幩; 幩; 幩; ) CJK COMPATIBILITY IDEOGRAPH-2F887 +2F888;3862;3862;3862;3862; # (㡢㡢; 㡢; 㡢; 㡢; 㡢; ) CJK COMPATIBILITY IDEOGRAPH-2F888 +2F889;22183;22183;22183;22183; # (𢆃𢆃; 𢆃𢆃; 𢆃𢆃; 𢆃𢆃; 𢆃𢆃; ) CJK COMPATIBILITY IDEOGRAPH-2F889 +2F88A;387C;387C;387C;387C; # (㡼㡼; 㡼; 㡼; 㡼; 㡼; ) CJK COMPATIBILITY IDEOGRAPH-2F88A +2F88B;5EB0;5EB0;5EB0;5EB0; # (庰庰; 庰; 庰; 庰; 庰; ) CJK COMPATIBILITY IDEOGRAPH-2F88B +2F88C;5EB3;5EB3;5EB3;5EB3; # (庳庳; 庳; 庳; 庳; 庳; ) CJK COMPATIBILITY IDEOGRAPH-2F88C +2F88D;5EB6;5EB6;5EB6;5EB6; # (庶庶; 庶; 庶; 庶; 庶; ) CJK COMPATIBILITY IDEOGRAPH-2F88D +2F88E;5ECA;5ECA;5ECA;5ECA; # (廊廊; 廊; 廊; 廊; 廊; ) CJK COMPATIBILITY IDEOGRAPH-2F88E +2F88F;2A392;2A392;2A392;2A392; # (𪎒𪎒; 𪎒𪎒; 𪎒𪎒; 𪎒𪎒; 𪎒𪎒; ) CJK COMPATIBILITY IDEOGRAPH-2F88F +2F890;5EFE;5EFE;5EFE;5EFE; # (廾廾; 廾; 廾; 廾; 廾; ) CJK COMPATIBILITY IDEOGRAPH-2F890 +2F891;22331;22331;22331;22331; # (𢌱𢌱; 𢌱𢌱; 𢌱𢌱; 𢌱𢌱; 𢌱𢌱; ) CJK COMPATIBILITY IDEOGRAPH-2F891 +2F892;22331;22331;22331;22331; # (𢌱𢌱; 𢌱𢌱; 𢌱𢌱; 𢌱𢌱; 𢌱𢌱; ) CJK COMPATIBILITY IDEOGRAPH-2F892 +2F893;8201;8201;8201;8201; # (舁舁; 舁; 舁; 舁; 舁; ) CJK COMPATIBILITY IDEOGRAPH-2F893 +2F894;5F22;5F22;5F22;5F22; # (弢弢; 弢; 弢; 弢; 弢; ) CJK COMPATIBILITY IDEOGRAPH-2F894 +2F895;5F22;5F22;5F22;5F22; # (弢弢; 弢; 弢; 弢; 弢; ) CJK COMPATIBILITY IDEOGRAPH-2F895 +2F896;38C7;38C7;38C7;38C7; # (㣇㣇; 㣇; 㣇; 㣇; 㣇; ) CJK COMPATIBILITY IDEOGRAPH-2F896 +2F897;232B8;232B8;232B8;232B8; # (𣊸𣊸; 𣊸𣊸; 𣊸𣊸; 𣊸𣊸; 𣊸𣊸; ) CJK COMPATIBILITY IDEOGRAPH-2F897 +2F898;261DA;261DA;261DA;261DA; # (𦇚𦇚; 𦇚𦇚; 𦇚𦇚; 𦇚𦇚; 𦇚𦇚; ) CJK COMPATIBILITY IDEOGRAPH-2F898 +2F899;5F62;5F62;5F62;5F62; # (形形; 形; 形; 形; 形; ) CJK COMPATIBILITY IDEOGRAPH-2F899 +2F89A;5F6B;5F6B;5F6B;5F6B; # (彫彫; 彫; 彫; 彫; 彫; ) CJK COMPATIBILITY IDEOGRAPH-2F89A +2F89B;38E3;38E3;38E3;38E3; # (㣣㣣; 㣣; 㣣; 㣣; 㣣; ) CJK COMPATIBILITY IDEOGRAPH-2F89B +2F89C;5F9A;5F9A;5F9A;5F9A; # (徚徚; 徚; 徚; 徚; 徚; ) CJK COMPATIBILITY IDEOGRAPH-2F89C +2F89D;5FCD;5FCD;5FCD;5FCD; # (忍忍; 忍; 忍; 忍; 忍; ) CJK COMPATIBILITY IDEOGRAPH-2F89D +2F89E;5FD7;5FD7;5FD7;5FD7; # (志志; 志; 志; 志; 志; ) CJK COMPATIBILITY IDEOGRAPH-2F89E +2F89F;5FF9;5FF9;5FF9;5FF9; # (忹忹; 忹; 忹; 忹; 忹; ) CJK COMPATIBILITY IDEOGRAPH-2F89F +2F8A0;6081;6081;6081;6081; # (悁悁; 悁; 悁; 悁; 悁; ) CJK COMPATIBILITY IDEOGRAPH-2F8A0 +2F8A1;393A;393A;393A;393A; # (㤺㤺; 㤺; 㤺; 㤺; 㤺; ) CJK COMPATIBILITY IDEOGRAPH-2F8A1 +2F8A2;391C;391C;391C;391C; # (㤜㤜; 㤜; 㤜; 㤜; 㤜; ) CJK COMPATIBILITY IDEOGRAPH-2F8A2 +2F8A3;6094;6094;6094;6094; # (悔悔; 悔; 悔; 悔; 悔; ) CJK COMPATIBILITY IDEOGRAPH-2F8A3 +2F8A4;226D4;226D4;226D4;226D4; # (𢛔𢛔; 𢛔𢛔; 𢛔𢛔; 𢛔𢛔; 𢛔𢛔; ) CJK COMPATIBILITY IDEOGRAPH-2F8A4 +2F8A5;60C7;60C7;60C7;60C7; # (惇惇; 惇; 惇; 惇; 惇; ) CJK COMPATIBILITY IDEOGRAPH-2F8A5 +2F8A6;6148;6148;6148;6148; # (慈慈; 慈; 慈; 慈; 慈; ) CJK COMPATIBILITY IDEOGRAPH-2F8A6 +2F8A7;614C;614C;614C;614C; # (慌慌; 慌; 慌; 慌; 慌; ) CJK COMPATIBILITY IDEOGRAPH-2F8A7 +2F8A8;614E;614E;614E;614E; # (慎慎; 慎; 慎; 慎; 慎; ) CJK COMPATIBILITY IDEOGRAPH-2F8A8 +2F8A9;614C;614C;614C;614C; # (慌慌; 慌; 慌; 慌; 慌; ) CJK COMPATIBILITY IDEOGRAPH-2F8A9 +2F8AA;617A;617A;617A;617A; # (慺慺; 慺; 慺; 慺; 慺; ) CJK COMPATIBILITY IDEOGRAPH-2F8AA +2F8AB;618E;618E;618E;618E; # (憎憎; 憎; 憎; 憎; 憎; ) CJK COMPATIBILITY IDEOGRAPH-2F8AB +2F8AC;61B2;61B2;61B2;61B2; # (憲憲; 憲; 憲; 憲; 憲; ) CJK COMPATIBILITY IDEOGRAPH-2F8AC +2F8AD;61A4;61A4;61A4;61A4; # (憤憤; 憤; 憤; 憤; 憤; ) CJK COMPATIBILITY IDEOGRAPH-2F8AD +2F8AE;61AF;61AF;61AF;61AF; # (憯憯; 憯; 憯; 憯; 憯; ) CJK COMPATIBILITY IDEOGRAPH-2F8AE +2F8AF;61DE;61DE;61DE;61DE; # (懞懞; 懞; 懞; 懞; 懞; ) CJK COMPATIBILITY IDEOGRAPH-2F8AF +2F8B0;61F2;61F2;61F2;61F2; # (懲懲; 懲; 懲; 懲; 懲; ) CJK COMPATIBILITY IDEOGRAPH-2F8B0 +2F8B1;61F6;61F6;61F6;61F6; # (懶懶; 懶; 懶; 懶; 懶; ) CJK COMPATIBILITY IDEOGRAPH-2F8B1 +2F8B2;6210;6210;6210;6210; # (成成; 成; 成; 成; 成; ) CJK COMPATIBILITY IDEOGRAPH-2F8B2 +2F8B3;621B;621B;621B;621B; # (戛戛; 戛; 戛; 戛; 戛; ) CJK COMPATIBILITY IDEOGRAPH-2F8B3 +2F8B4;625D;625D;625D;625D; # (扝扝; 扝; 扝; 扝; 扝; ) CJK COMPATIBILITY IDEOGRAPH-2F8B4 +2F8B5;62B1;62B1;62B1;62B1; # (抱抱; 抱; 抱; 抱; 抱; ) CJK COMPATIBILITY IDEOGRAPH-2F8B5 +2F8B6;62D4;62D4;62D4;62D4; # (拔拔; 拔; 拔; 拔; 拔; ) CJK COMPATIBILITY IDEOGRAPH-2F8B6 +2F8B7;6350;6350;6350;6350; # (捐捐; 捐; 捐; 捐; 捐; ) CJK COMPATIBILITY IDEOGRAPH-2F8B7 +2F8B8;22B0C;22B0C;22B0C;22B0C; # (𢬌𢬌; 𢬌𢬌; 𢬌𢬌; 𢬌𢬌; 𢬌𢬌; ) CJK COMPATIBILITY IDEOGRAPH-2F8B8 +2F8B9;633D;633D;633D;633D; # (挽挽; 挽; 挽; 挽; 挽; ) CJK COMPATIBILITY IDEOGRAPH-2F8B9 +2F8BA;62FC;62FC;62FC;62FC; # (拼拼; 拼; 拼; 拼; 拼; ) CJK COMPATIBILITY IDEOGRAPH-2F8BA +2F8BB;6368;6368;6368;6368; # (捨捨; 捨; 捨; 捨; 捨; ) CJK COMPATIBILITY IDEOGRAPH-2F8BB +2F8BC;6383;6383;6383;6383; # (掃掃; 掃; 掃; 掃; 掃; ) CJK COMPATIBILITY IDEOGRAPH-2F8BC +2F8BD;63E4;63E4;63E4;63E4; # (揤揤; 揤; 揤; 揤; 揤; ) CJK COMPATIBILITY IDEOGRAPH-2F8BD +2F8BE;22BF1;22BF1;22BF1;22BF1; # (𢯱𢯱; 𢯱𢯱; 𢯱𢯱; 𢯱𢯱; 𢯱𢯱; ) CJK COMPATIBILITY IDEOGRAPH-2F8BE +2F8BF;6422;6422;6422;6422; # (搢搢; 搢; 搢; 搢; 搢; ) CJK COMPATIBILITY IDEOGRAPH-2F8BF +2F8C0;63C5;63C5;63C5;63C5; # (揅揅; 揅; 揅; 揅; 揅; ) CJK COMPATIBILITY IDEOGRAPH-2F8C0 +2F8C1;63A9;63A9;63A9;63A9; # (掩掩; 掩; 掩; 掩; 掩; ) CJK COMPATIBILITY IDEOGRAPH-2F8C1 +2F8C2;3A2E;3A2E;3A2E;3A2E; # (㨮㨮; 㨮; 㨮; 㨮; 㨮; ) CJK COMPATIBILITY IDEOGRAPH-2F8C2 +2F8C3;6469;6469;6469;6469; # (摩摩; 摩; 摩; 摩; 摩; ) CJK COMPATIBILITY IDEOGRAPH-2F8C3 +2F8C4;647E;647E;647E;647E; # (摾摾; 摾; 摾; 摾; 摾; ) CJK COMPATIBILITY IDEOGRAPH-2F8C4 +2F8C5;649D;649D;649D;649D; # (撝撝; 撝; 撝; 撝; 撝; ) CJK COMPATIBILITY IDEOGRAPH-2F8C5 +2F8C6;6477;6477;6477;6477; # (摷摷; 摷; 摷; 摷; 摷; ) CJK COMPATIBILITY IDEOGRAPH-2F8C6 +2F8C7;3A6C;3A6C;3A6C;3A6C; # (㩬㩬; 㩬; 㩬; 㩬; 㩬; ) CJK COMPATIBILITY IDEOGRAPH-2F8C7 +2F8C8;654F;654F;654F;654F; # (敏敏; 敏; 敏; 敏; 敏; ) CJK COMPATIBILITY IDEOGRAPH-2F8C8 +2F8C9;656C;656C;656C;656C; # (敬敬; 敬; 敬; 敬; 敬; ) CJK COMPATIBILITY IDEOGRAPH-2F8C9 +2F8CA;2300A;2300A;2300A;2300A; # (𣀊𣀊; 𣀊𣀊; 𣀊𣀊; 𣀊𣀊; 𣀊𣀊; ) CJK COMPATIBILITY IDEOGRAPH-2F8CA +2F8CB;65E3;65E3;65E3;65E3; # (旣旣; 旣; 旣; 旣; 旣; ) CJK COMPATIBILITY IDEOGRAPH-2F8CB +2F8CC;66F8;66F8;66F8;66F8; # (書書; 書; 書; 書; 書; ) CJK COMPATIBILITY IDEOGRAPH-2F8CC +2F8CD;6649;6649;6649;6649; # (晉晉; 晉; 晉; 晉; 晉; ) CJK COMPATIBILITY IDEOGRAPH-2F8CD +2F8CE;3B19;3B19;3B19;3B19; # (㬙㬙; 㬙; 㬙; 㬙; 㬙; ) CJK COMPATIBILITY IDEOGRAPH-2F8CE +2F8CF;6691;6691;6691;6691; # (暑暑; 暑; 暑; 暑; 暑; ) CJK COMPATIBILITY IDEOGRAPH-2F8CF +2F8D0;3B08;3B08;3B08;3B08; # (㬈㬈; 㬈; 㬈; 㬈; 㬈; ) CJK COMPATIBILITY IDEOGRAPH-2F8D0 +2F8D1;3AE4;3AE4;3AE4;3AE4; # (㫤㫤; 㫤; 㫤; 㫤; 㫤; ) CJK COMPATIBILITY IDEOGRAPH-2F8D1 +2F8D2;5192;5192;5192;5192; # (冒冒; 冒; 冒; 冒; 冒; ) CJK COMPATIBILITY IDEOGRAPH-2F8D2 +2F8D3;5195;5195;5195;5195; # (冕冕; 冕; 冕; 冕; 冕; ) CJK COMPATIBILITY IDEOGRAPH-2F8D3 +2F8D4;6700;6700;6700;6700; # (最最; 最; 最; 最; 最; ) CJK COMPATIBILITY IDEOGRAPH-2F8D4 +2F8D5;669C;669C;669C;669C; # (暜暜; 暜; 暜; 暜; 暜; ) CJK COMPATIBILITY IDEOGRAPH-2F8D5 +2F8D6;80AD;80AD;80AD;80AD; # (肭肭; 肭; 肭; 肭; 肭; ) CJK COMPATIBILITY IDEOGRAPH-2F8D6 +2F8D7;43D9;43D9;43D9;43D9; # (䏙䏙; 䏙; 䏙; 䏙; 䏙; ) CJK COMPATIBILITY IDEOGRAPH-2F8D7 +2F8D8;6717;6717;6717;6717; # (朗朗; 朗; 朗; 朗; 朗; ) CJK COMPATIBILITY IDEOGRAPH-2F8D8 +2F8D9;671B;671B;671B;671B; # (望望; 望; 望; 望; 望; ) CJK COMPATIBILITY IDEOGRAPH-2F8D9 +2F8DA;6721;6721;6721;6721; # (朡朡; 朡; 朡; 朡; 朡; ) CJK COMPATIBILITY IDEOGRAPH-2F8DA +2F8DB;675E;675E;675E;675E; # (杞杞; 杞; 杞; 杞; 杞; ) CJK COMPATIBILITY IDEOGRAPH-2F8DB +2F8DC;6753;6753;6753;6753; # (杓杓; 杓; 杓; 杓; 杓; ) CJK COMPATIBILITY IDEOGRAPH-2F8DC +2F8DD;233C3;233C3;233C3;233C3; # (𣏃𣏃; 𣏃𣏃; 𣏃𣏃; 𣏃𣏃; 𣏃𣏃; ) CJK COMPATIBILITY IDEOGRAPH-2F8DD +2F8DE;3B49;3B49;3B49;3B49; # (㭉㭉; 㭉; 㭉; 㭉; 㭉; ) CJK COMPATIBILITY IDEOGRAPH-2F8DE +2F8DF;67FA;67FA;67FA;67FA; # (柺柺; 柺; 柺; 柺; 柺; ) CJK COMPATIBILITY IDEOGRAPH-2F8DF +2F8E0;6785;6785;6785;6785; # (枅枅; 枅; 枅; 枅; 枅; ) CJK COMPATIBILITY IDEOGRAPH-2F8E0 +2F8E1;6852;6852;6852;6852; # (桒桒; 桒; 桒; 桒; 桒; ) CJK COMPATIBILITY IDEOGRAPH-2F8E1 +2F8E2;6885;6885;6885;6885; # (梅梅; 梅; 梅; 梅; 梅; ) CJK COMPATIBILITY IDEOGRAPH-2F8E2 +2F8E3;2346D;2346D;2346D;2346D; # (𣑭𣑭; 𣑭𣑭; 𣑭𣑭; 𣑭𣑭; 𣑭𣑭; ) CJK COMPATIBILITY IDEOGRAPH-2F8E3 +2F8E4;688E;688E;688E;688E; # (梎梎; 梎; 梎; 梎; 梎; ) CJK COMPATIBILITY IDEOGRAPH-2F8E4 +2F8E5;681F;681F;681F;681F; # (栟栟; 栟; 栟; 栟; 栟; ) CJK COMPATIBILITY IDEOGRAPH-2F8E5 +2F8E6;6914;6914;6914;6914; # (椔椔; 椔; 椔; 椔; 椔; ) CJK COMPATIBILITY IDEOGRAPH-2F8E6 +2F8E7;3B9D;3B9D;3B9D;3B9D; # (㮝㮝; 㮝; 㮝; 㮝; 㮝; ) CJK COMPATIBILITY IDEOGRAPH-2F8E7 +2F8E8;6942;6942;6942;6942; # (楂楂; 楂; 楂; 楂; 楂; ) CJK COMPATIBILITY IDEOGRAPH-2F8E8 +2F8E9;69A3;69A3;69A3;69A3; # (榣榣; 榣; 榣; 榣; 榣; ) CJK COMPATIBILITY IDEOGRAPH-2F8E9 +2F8EA;69EA;69EA;69EA;69EA; # (槪槪; 槪; 槪; 槪; 槪; ) CJK COMPATIBILITY IDEOGRAPH-2F8EA +2F8EB;6AA8;6AA8;6AA8;6AA8; # (檨檨; 檨; 檨; 檨; 檨; ) CJK COMPATIBILITY IDEOGRAPH-2F8EB +2F8EC;236A3;236A3;236A3;236A3; # (𣚣𣚣; 𣚣𣚣; 𣚣𣚣; 𣚣𣚣; 𣚣𣚣; ) CJK COMPATIBILITY IDEOGRAPH-2F8EC +2F8ED;6ADB;6ADB;6ADB;6ADB; # (櫛櫛; 櫛; 櫛; 櫛; 櫛; ) CJK COMPATIBILITY IDEOGRAPH-2F8ED +2F8EE;3C18;3C18;3C18;3C18; # (㰘㰘; 㰘; 㰘; 㰘; 㰘; ) CJK COMPATIBILITY IDEOGRAPH-2F8EE +2F8EF;6B21;6B21;6B21;6B21; # (次次; 次; 次; 次; 次; ) CJK COMPATIBILITY IDEOGRAPH-2F8EF +2F8F0;238A7;238A7;238A7;238A7; # (𣢧𣢧; 𣢧𣢧; 𣢧𣢧; 𣢧𣢧; 𣢧𣢧; ) CJK COMPATIBILITY IDEOGRAPH-2F8F0 +2F8F1;6B54;6B54;6B54;6B54; # (歔歔; 歔; 歔; 歔; 歔; ) CJK COMPATIBILITY IDEOGRAPH-2F8F1 +2F8F2;3C4E;3C4E;3C4E;3C4E; # (㱎㱎; 㱎; 㱎; 㱎; 㱎; ) CJK COMPATIBILITY IDEOGRAPH-2F8F2 +2F8F3;6B72;6B72;6B72;6B72; # (歲歲; 歲; 歲; 歲; 歲; ) CJK COMPATIBILITY IDEOGRAPH-2F8F3 +2F8F4;6B9F;6B9F;6B9F;6B9F; # (殟殟; 殟; 殟; 殟; 殟; ) CJK COMPATIBILITY IDEOGRAPH-2F8F4 +2F8F5;6BBA;6BBA;6BBA;6BBA; # (殺殺; 殺; 殺; 殺; 殺; ) CJK COMPATIBILITY IDEOGRAPH-2F8F5 +2F8F6;6BBB;6BBB;6BBB;6BBB; # (殻殻; 殻; 殻; 殻; 殻; ) CJK COMPATIBILITY IDEOGRAPH-2F8F6 +2F8F7;23A8D;23A8D;23A8D;23A8D; # (𣪍𣪍; 𣪍𣪍; 𣪍𣪍; 𣪍𣪍; 𣪍𣪍; ) CJK COMPATIBILITY IDEOGRAPH-2F8F7 +2F8F8;21D0B;21D0B;21D0B;21D0B; # (𡴋𡴋; 𡴋𡴋; 𡴋𡴋; 𡴋𡴋; 𡴋𡴋; ) CJK COMPATIBILITY IDEOGRAPH-2F8F8 +2F8F9;23AFA;23AFA;23AFA;23AFA; # (𣫺𣫺; 𣫺𣫺; 𣫺𣫺; 𣫺𣫺; 𣫺𣫺; ) CJK COMPATIBILITY IDEOGRAPH-2F8F9 +2F8FA;6C4E;6C4E;6C4E;6C4E; # (汎汎; 汎; 汎; 汎; 汎; ) CJK COMPATIBILITY IDEOGRAPH-2F8FA +2F8FB;23CBC;23CBC;23CBC;23CBC; # (𣲼𣲼; 𣲼𣲼; 𣲼𣲼; 𣲼𣲼; 𣲼𣲼; ) CJK COMPATIBILITY IDEOGRAPH-2F8FB +2F8FC;6CBF;6CBF;6CBF;6CBF; # (沿沿; 沿; 沿; 沿; 沿; ) CJK COMPATIBILITY IDEOGRAPH-2F8FC +2F8FD;6CCD;6CCD;6CCD;6CCD; # (泍泍; 泍; 泍; 泍; 泍; ) CJK COMPATIBILITY IDEOGRAPH-2F8FD +2F8FE;6C67;6C67;6C67;6C67; # (汧汧; 汧; 汧; 汧; 汧; ) CJK COMPATIBILITY IDEOGRAPH-2F8FE +2F8FF;6D16;6D16;6D16;6D16; # (洖洖; 洖; 洖; 洖; 洖; ) CJK COMPATIBILITY IDEOGRAPH-2F8FF +2F900;6D3E;6D3E;6D3E;6D3E; # (派派; 派; 派; 派; 派; ) CJK COMPATIBILITY IDEOGRAPH-2F900 +2F901;6D77;6D77;6D77;6D77; # (海海; 海; 海; 海; 海; ) CJK COMPATIBILITY IDEOGRAPH-2F901 +2F902;6D41;6D41;6D41;6D41; # (流流; 流; 流; 流; 流; ) CJK COMPATIBILITY IDEOGRAPH-2F902 +2F903;6D69;6D69;6D69;6D69; # (浩浩; 浩; 浩; 浩; 浩; ) CJK COMPATIBILITY IDEOGRAPH-2F903 +2F904;6D78;6D78;6D78;6D78; # (浸浸; 浸; 浸; 浸; 浸; ) CJK COMPATIBILITY IDEOGRAPH-2F904 +2F905;6D85;6D85;6D85;6D85; # (涅涅; 涅; 涅; 涅; 涅; ) CJK COMPATIBILITY IDEOGRAPH-2F905 +2F906;23D1E;23D1E;23D1E;23D1E; # (𣴞𣴞; 𣴞𣴞; 𣴞𣴞; 𣴞𣴞; 𣴞𣴞; ) CJK COMPATIBILITY IDEOGRAPH-2F906 +2F907;6D34;6D34;6D34;6D34; # (洴洴; 洴; 洴; 洴; 洴; ) CJK COMPATIBILITY IDEOGRAPH-2F907 +2F908;6E2F;6E2F;6E2F;6E2F; # (港港; 港; 港; 港; 港; ) CJK COMPATIBILITY IDEOGRAPH-2F908 +2F909;6E6E;6E6E;6E6E;6E6E; # (湮湮; 湮; 湮; 湮; 湮; ) CJK COMPATIBILITY IDEOGRAPH-2F909 +2F90A;3D33;3D33;3D33;3D33; # (㴳㴳; 㴳; 㴳; 㴳; 㴳; ) CJK COMPATIBILITY IDEOGRAPH-2F90A +2F90B;6ECB;6ECB;6ECB;6ECB; # (滋滋; 滋; 滋; 滋; 滋; ) CJK COMPATIBILITY IDEOGRAPH-2F90B +2F90C;6EC7;6EC7;6EC7;6EC7; # (滇滇; 滇; 滇; 滇; 滇; ) CJK COMPATIBILITY IDEOGRAPH-2F90C +2F90D;23ED1;23ED1;23ED1;23ED1; # (𣻑𣻑; 𣻑𣻑; 𣻑𣻑; 𣻑𣻑; 𣻑𣻑; ) CJK COMPATIBILITY IDEOGRAPH-2F90D +2F90E;6DF9;6DF9;6DF9;6DF9; # (淹淹; 淹; 淹; 淹; 淹; ) CJK COMPATIBILITY IDEOGRAPH-2F90E +2F90F;6F6E;6F6E;6F6E;6F6E; # (潮潮; 潮; 潮; 潮; 潮; ) CJK COMPATIBILITY IDEOGRAPH-2F90F +2F910;23F5E;23F5E;23F5E;23F5E; # (𣽞𣽞; 𣽞𣽞; 𣽞𣽞; 𣽞𣽞; 𣽞𣽞; ) CJK COMPATIBILITY IDEOGRAPH-2F910 +2F911;23F8E;23F8E;23F8E;23F8E; # (𣾎𣾎; 𣾎𣾎; 𣾎𣾎; 𣾎𣾎; 𣾎𣾎; ) CJK COMPATIBILITY IDEOGRAPH-2F911 +2F912;6FC6;6FC6;6FC6;6FC6; # (濆濆; 濆; 濆; 濆; 濆; ) CJK COMPATIBILITY IDEOGRAPH-2F912 +2F913;7039;7039;7039;7039; # (瀹瀹; 瀹; 瀹; 瀹; 瀹; ) CJK COMPATIBILITY IDEOGRAPH-2F913 +2F914;701E;701E;701E;701E; # (瀞瀞; 瀞; 瀞; 瀞; 瀞; ) CJK COMPATIBILITY IDEOGRAPH-2F914 +2F915;701B;701B;701B;701B; # (瀛瀛; 瀛; 瀛; 瀛; 瀛; ) CJK COMPATIBILITY IDEOGRAPH-2F915 +2F916;3D96;3D96;3D96;3D96; # (㶖㶖; 㶖; 㶖; 㶖; 㶖; ) CJK COMPATIBILITY IDEOGRAPH-2F916 +2F917;704A;704A;704A;704A; # (灊灊; 灊; 灊; 灊; 灊; ) CJK COMPATIBILITY IDEOGRAPH-2F917 +2F918;707D;707D;707D;707D; # (災災; 災; 災; 災; 災; ) CJK COMPATIBILITY IDEOGRAPH-2F918 +2F919;7077;7077;7077;7077; # (灷灷; 灷; 灷; 灷; 灷; ) CJK COMPATIBILITY IDEOGRAPH-2F919 +2F91A;70AD;70AD;70AD;70AD; # (炭炭; 炭; 炭; 炭; 炭; ) CJK COMPATIBILITY IDEOGRAPH-2F91A +2F91B;20525;20525;20525;20525; # (𠔥𠔥; 𠔥𠔥; 𠔥𠔥; 𠔥𠔥; 𠔥𠔥; ) CJK COMPATIBILITY IDEOGRAPH-2F91B +2F91C;7145;7145;7145;7145; # (煅煅; 煅; 煅; 煅; 煅; ) CJK COMPATIBILITY IDEOGRAPH-2F91C +2F91D;24263;24263;24263;24263; # (𤉣𤉣; 𤉣𤉣; 𤉣𤉣; 𤉣𤉣; 𤉣𤉣; ) CJK COMPATIBILITY IDEOGRAPH-2F91D +2F91E;719C;719C;719C;719C; # (熜熜; 熜; 熜; 熜; 熜; ) CJK COMPATIBILITY IDEOGRAPH-2F91E +2F91F;43AB;43AB;43AB;43AB; # (𤎫𤎫; 䎫; 䎫; 䎫; 䎫; ) CJK COMPATIBILITY IDEOGRAPH-2F91F +2F920;7228;7228;7228;7228; # (爨爨; 爨; 爨; 爨; 爨; ) CJK COMPATIBILITY IDEOGRAPH-2F920 +2F921;7235;7235;7235;7235; # (爵爵; 爵; 爵; 爵; 爵; ) CJK COMPATIBILITY IDEOGRAPH-2F921 +2F922;7250;7250;7250;7250; # (牐牐; 牐; 牐; 牐; 牐; ) CJK COMPATIBILITY IDEOGRAPH-2F922 +2F923;24608;24608;24608;24608; # (𤘈𤘈; 𤘈𤘈; 𤘈𤘈; 𤘈𤘈; 𤘈𤘈; ) CJK COMPATIBILITY IDEOGRAPH-2F923 +2F924;7280;7280;7280;7280; # (犀犀; 犀; 犀; 犀; 犀; ) CJK COMPATIBILITY IDEOGRAPH-2F924 +2F925;7295;7295;7295;7295; # (犕犕; 犕; 犕; 犕; 犕; ) CJK COMPATIBILITY IDEOGRAPH-2F925 +2F926;24735;24735;24735;24735; # (𤜵𤜵; 𤜵𤜵; 𤜵𤜵; 𤜵𤜵; 𤜵𤜵; ) CJK COMPATIBILITY IDEOGRAPH-2F926 +2F927;24814;24814;24814;24814; # (𤠔𤠔; 𤠔𤠔; 𤠔𤠔; 𤠔𤠔; 𤠔𤠔; ) CJK COMPATIBILITY IDEOGRAPH-2F927 +2F928;737A;737A;737A;737A; # (獺獺; 獺; 獺; 獺; 獺; ) CJK COMPATIBILITY IDEOGRAPH-2F928 +2F929;738B;738B;738B;738B; # (王王; 王; 王; 王; 王; ) CJK COMPATIBILITY IDEOGRAPH-2F929 +2F92A;3EAC;3EAC;3EAC;3EAC; # (㺬㺬; 㺬; 㺬; 㺬; 㺬; ) CJK COMPATIBILITY IDEOGRAPH-2F92A +2F92B;73A5;73A5;73A5;73A5; # (玥玥; 玥; 玥; 玥; 玥; ) CJK COMPATIBILITY IDEOGRAPH-2F92B +2F92C;3EB8;3EB8;3EB8;3EB8; # (㺸㺸; 㺸; 㺸; 㺸; 㺸; ) CJK COMPATIBILITY IDEOGRAPH-2F92C +2F92D;3EB8;3EB8;3EB8;3EB8; # (㺸㺸; 㺸; 㺸; 㺸; 㺸; ) CJK COMPATIBILITY IDEOGRAPH-2F92D +2F92E;7447;7447;7447;7447; # (瑇瑇; 瑇; 瑇; 瑇; 瑇; ) CJK COMPATIBILITY IDEOGRAPH-2F92E +2F92F;745C;745C;745C;745C; # (瑜瑜; 瑜; 瑜; 瑜; 瑜; ) CJK COMPATIBILITY IDEOGRAPH-2F92F +2F930;7471;7471;7471;7471; # (瑱瑱; 瑱; 瑱; 瑱; 瑱; ) CJK COMPATIBILITY IDEOGRAPH-2F930 +2F931;7485;7485;7485;7485; # (璅璅; 璅; 璅; 璅; 璅; ) CJK COMPATIBILITY IDEOGRAPH-2F931 +2F932;74CA;74CA;74CA;74CA; # (瓊瓊; 瓊; 瓊; 瓊; 瓊; ) CJK COMPATIBILITY IDEOGRAPH-2F932 +2F933;3F1B;3F1B;3F1B;3F1B; # (㼛㼛; 㼛; 㼛; 㼛; 㼛; ) CJK COMPATIBILITY IDEOGRAPH-2F933 +2F934;7524;7524;7524;7524; # (甤甤; 甤; 甤; 甤; 甤; ) CJK COMPATIBILITY IDEOGRAPH-2F934 +2F935;24C36;24C36;24C36;24C36; # (𤰶𤰶; 𤰶𤰶; 𤰶𤰶; 𤰶𤰶; 𤰶𤰶; ) CJK COMPATIBILITY IDEOGRAPH-2F935 +2F936;753E;753E;753E;753E; # (甾甾; 甾; 甾; 甾; 甾; ) CJK COMPATIBILITY IDEOGRAPH-2F936 +2F937;24C92;24C92;24C92;24C92; # (𤲒𤲒; 𤲒𤲒; 𤲒𤲒; 𤲒𤲒; 𤲒𤲒; ) CJK COMPATIBILITY IDEOGRAPH-2F937 +2F938;7570;7570;7570;7570; # (異異; 異; 異; 異; 異; ) CJK COMPATIBILITY IDEOGRAPH-2F938 +2F939;2219F;2219F;2219F;2219F; # (𢆟𢆟; 𢆟𢆟; 𢆟𢆟; 𢆟𢆟; 𢆟𢆟; ) CJK COMPATIBILITY IDEOGRAPH-2F939 +2F93A;7610;7610;7610;7610; # (瘐瘐; 瘐; 瘐; 瘐; 瘐; ) CJK COMPATIBILITY IDEOGRAPH-2F93A +2F93B;24FA1;24FA1;24FA1;24FA1; # (𤾡𤾡; 𤾡𤾡; 𤾡𤾡; 𤾡𤾡; 𤾡𤾡; ) CJK COMPATIBILITY IDEOGRAPH-2F93B +2F93C;24FB8;24FB8;24FB8;24FB8; # (𤾸𤾸; 𤾸𤾸; 𤾸𤾸; 𤾸𤾸; 𤾸𤾸; ) CJK COMPATIBILITY IDEOGRAPH-2F93C +2F93D;25044;25044;25044;25044; # (𥁄𥁄; 𥁄𥁄; 𥁄𥁄; 𥁄𥁄; 𥁄𥁄; ) CJK COMPATIBILITY IDEOGRAPH-2F93D +2F93E;3FFC;3FFC;3FFC;3FFC; # (㿼㿼; 㿼; 㿼; 㿼; 㿼; ) CJK COMPATIBILITY IDEOGRAPH-2F93E +2F93F;4008;4008;4008;4008; # (䀈䀈; 䀈; 䀈; 䀈; 䀈; ) CJK COMPATIBILITY IDEOGRAPH-2F93F +2F940;76F4;76F4;76F4;76F4; # (直直; 直; 直; 直; 直; ) CJK COMPATIBILITY IDEOGRAPH-2F940 +2F941;250F3;250F3;250F3;250F3; # (𥃳𥃳; 𥃳𥃳; 𥃳𥃳; 𥃳𥃳; 𥃳𥃳; ) CJK COMPATIBILITY IDEOGRAPH-2F941 +2F942;250F2;250F2;250F2;250F2; # (𥃲𥃲; 𥃲𥃲; 𥃲𥃲; 𥃲𥃲; 𥃲𥃲; ) CJK COMPATIBILITY IDEOGRAPH-2F942 +2F943;25119;25119;25119;25119; # (𥄙𥄙; 𥄙𥄙; 𥄙𥄙; 𥄙𥄙; 𥄙𥄙; ) CJK COMPATIBILITY IDEOGRAPH-2F943 +2F944;25133;25133;25133;25133; # (𥄳𥄳; 𥄳𥄳; 𥄳𥄳; 𥄳𥄳; 𥄳𥄳; ) CJK COMPATIBILITY IDEOGRAPH-2F944 +2F945;771E;771E;771E;771E; # (眞眞; 眞; 眞; 眞; 眞; ) CJK COMPATIBILITY IDEOGRAPH-2F945 +2F946;771F;771F;771F;771F; # (真真; 真; 真; 真; 真; ) CJK COMPATIBILITY IDEOGRAPH-2F946 +2F947;771F;771F;771F;771F; # (真真; 真; 真; 真; 真; ) CJK COMPATIBILITY IDEOGRAPH-2F947 +2F948;774A;774A;774A;774A; # (睊睊; 睊; 睊; 睊; 睊; ) CJK COMPATIBILITY IDEOGRAPH-2F948 +2F949;4039;4039;4039;4039; # (䀹䀹; 䀹; 䀹; 䀹; 䀹; ) CJK COMPATIBILITY IDEOGRAPH-2F949 +2F94A;778B;778B;778B;778B; # (瞋瞋; 瞋; 瞋; 瞋; 瞋; ) CJK COMPATIBILITY IDEOGRAPH-2F94A +2F94B;4046;4046;4046;4046; # (䁆䁆; 䁆; 䁆; 䁆; 䁆; ) CJK COMPATIBILITY IDEOGRAPH-2F94B +2F94C;4096;4096;4096;4096; # (䂖䂖; 䂖; 䂖; 䂖; 䂖; ) CJK COMPATIBILITY IDEOGRAPH-2F94C +2F94D;2541D;2541D;2541D;2541D; # (𥐝𥐝; 𥐝𥐝; 𥐝𥐝; 𥐝𥐝; 𥐝𥐝; ) CJK COMPATIBILITY IDEOGRAPH-2F94D +2F94E;784E;784E;784E;784E; # (硎硎; 硎; 硎; 硎; 硎; ) CJK COMPATIBILITY IDEOGRAPH-2F94E +2F94F;788C;788C;788C;788C; # (碌碌; 碌; 碌; 碌; 碌; ) CJK COMPATIBILITY IDEOGRAPH-2F94F +2F950;78CC;78CC;78CC;78CC; # (磌磌; 磌; 磌; 磌; 磌; ) CJK COMPATIBILITY IDEOGRAPH-2F950 +2F951;40E3;40E3;40E3;40E3; # (䃣䃣; 䃣; 䃣; 䃣; 䃣; ) CJK COMPATIBILITY IDEOGRAPH-2F951 +2F952;25626;25626;25626;25626; # (𥘦𥘦; 𥘦𥘦; 𥘦𥘦; 𥘦𥘦; 𥘦𥘦; ) CJK COMPATIBILITY IDEOGRAPH-2F952 +2F953;7956;7956;7956;7956; # (祖祖; 祖; 祖; 祖; 祖; ) CJK COMPATIBILITY IDEOGRAPH-2F953 +2F954;2569A;2569A;2569A;2569A; # (𥚚𥚚; 𥚚𥚚; 𥚚𥚚; 𥚚𥚚; 𥚚𥚚; ) CJK COMPATIBILITY IDEOGRAPH-2F954 +2F955;256C5;256C5;256C5;256C5; # (𥛅𥛅; 𥛅𥛅; 𥛅𥛅; 𥛅𥛅; 𥛅𥛅; ) CJK COMPATIBILITY IDEOGRAPH-2F955 +2F956;798F;798F;798F;798F; # (福福; 福; 福; 福; 福; ) CJK COMPATIBILITY IDEOGRAPH-2F956 +2F957;79EB;79EB;79EB;79EB; # (秫秫; 秫; 秫; 秫; 秫; ) CJK COMPATIBILITY IDEOGRAPH-2F957 +2F958;412F;412F;412F;412F; # (䄯䄯; 䄯; 䄯; 䄯; 䄯; ) CJK COMPATIBILITY IDEOGRAPH-2F958 +2F959;7A40;7A40;7A40;7A40; # (穀穀; 穀; 穀; 穀; 穀; ) CJK COMPATIBILITY IDEOGRAPH-2F959 +2F95A;7A4A;7A4A;7A4A;7A4A; # (穊穊; 穊; 穊; 穊; 穊; ) CJK COMPATIBILITY IDEOGRAPH-2F95A +2F95B;7A4F;7A4F;7A4F;7A4F; # (穏穏; 穏; 穏; 穏; 穏; ) CJK COMPATIBILITY IDEOGRAPH-2F95B +2F95C;2597C;2597C;2597C;2597C; # (𥥼𥥼; 𥥼𥥼; 𥥼𥥼; 𥥼𥥼; 𥥼𥥼; ) CJK COMPATIBILITY IDEOGRAPH-2F95C +2F95D;25AA7;25AA7;25AA7;25AA7; # (𥪧𥪧; 𥪧𥪧; 𥪧𥪧; 𥪧𥪧; 𥪧𥪧; ) CJK COMPATIBILITY IDEOGRAPH-2F95D +2F95E;25AA7;25AA7;25AA7;25AA7; # (𥪧𥪧; 𥪧𥪧; 𥪧𥪧; 𥪧𥪧; 𥪧𥪧; ) CJK COMPATIBILITY IDEOGRAPH-2F95E +2F95F;7AAE;7AAE;7AAE;7AAE; # (竮竮; 窮; 窮; 窮; 窮; ) CJK COMPATIBILITY IDEOGRAPH-2F95F +2F960;4202;4202;4202;4202; # (䈂䈂; 䈂; 䈂; 䈂; 䈂; ) CJK COMPATIBILITY IDEOGRAPH-2F960 +2F961;25BAB;25BAB;25BAB;25BAB; # (𥮫𥮫; 𥮫𥮫; 𥮫𥮫; 𥮫𥮫; 𥮫𥮫; ) CJK COMPATIBILITY IDEOGRAPH-2F961 +2F962;7BC6;7BC6;7BC6;7BC6; # (篆篆; 篆; 篆; 篆; 篆; ) CJK COMPATIBILITY IDEOGRAPH-2F962 +2F963;7BC9;7BC9;7BC9;7BC9; # (築築; 築; 築; 築; 築; ) CJK COMPATIBILITY IDEOGRAPH-2F963 +2F964;4227;4227;4227;4227; # (䈧䈧; 䈧; 䈧; 䈧; 䈧; ) CJK COMPATIBILITY IDEOGRAPH-2F964 +2F965;25C80;25C80;25C80;25C80; # (𥲀𥲀; 𥲀𥲀; 𥲀𥲀; 𥲀𥲀; 𥲀𥲀; ) CJK COMPATIBILITY IDEOGRAPH-2F965 +2F966;7CD2;7CD2;7CD2;7CD2; # (糒糒; 糒; 糒; 糒; 糒; ) CJK COMPATIBILITY IDEOGRAPH-2F966 +2F967;42A0;42A0;42A0;42A0; # (䊠䊠; 䊠; 䊠; 䊠; 䊠; ) CJK COMPATIBILITY IDEOGRAPH-2F967 +2F968;7CE8;7CE8;7CE8;7CE8; # (糨糨; 糨; 糨; 糨; 糨; ) CJK COMPATIBILITY IDEOGRAPH-2F968 +2F969;7CE3;7CE3;7CE3;7CE3; # (糣糣; 糣; 糣; 糣; 糣; ) CJK COMPATIBILITY IDEOGRAPH-2F969 +2F96A;7D00;7D00;7D00;7D00; # (紀紀; 紀; 紀; 紀; 紀; ) CJK COMPATIBILITY IDEOGRAPH-2F96A +2F96B;25F86;25F86;25F86;25F86; # (𥾆𥾆; 𥾆𥾆; 𥾆𥾆; 𥾆𥾆; 𥾆𥾆; ) CJK COMPATIBILITY IDEOGRAPH-2F96B +2F96C;7D63;7D63;7D63;7D63; # (絣絣; 絣; 絣; 絣; 絣; ) CJK COMPATIBILITY IDEOGRAPH-2F96C +2F96D;4301;4301;4301;4301; # (䌁䌁; 䌁; 䌁; 䌁; 䌁; ) CJK COMPATIBILITY IDEOGRAPH-2F96D +2F96E;7DC7;7DC7;7DC7;7DC7; # (緇緇; 緇; 緇; 緇; 緇; ) CJK COMPATIBILITY IDEOGRAPH-2F96E +2F96F;7E02;7E02;7E02;7E02; # (縂縂; 縂; 縂; 縂; 縂; ) CJK COMPATIBILITY IDEOGRAPH-2F96F +2F970;7E45;7E45;7E45;7E45; # (繅繅; 繅; 繅; 繅; 繅; ) CJK COMPATIBILITY IDEOGRAPH-2F970 +2F971;4334;4334;4334;4334; # (䌴䌴; 䌴; 䌴; 䌴; 䌴; ) CJK COMPATIBILITY IDEOGRAPH-2F971 +2F972;26228;26228;26228;26228; # (𦈨𦈨; 𦈨𦈨; 𦈨𦈨; 𦈨𦈨; 𦈨𦈨; ) CJK COMPATIBILITY IDEOGRAPH-2F972 +2F973;26247;26247;26247;26247; # (𦉇𦉇; 𦉇𦉇; 𦉇𦉇; 𦉇𦉇; 𦉇𦉇; ) CJK COMPATIBILITY IDEOGRAPH-2F973 +2F974;4359;4359;4359;4359; # (䍙䍙; 䍙; 䍙; 䍙; 䍙; ) CJK COMPATIBILITY IDEOGRAPH-2F974 +2F975;262D9;262D9;262D9;262D9; # (𦋙𦋙; 𦋙𦋙; 𦋙𦋙; 𦋙𦋙; 𦋙𦋙; ) CJK COMPATIBILITY IDEOGRAPH-2F975 +2F976;7F7A;7F7A;7F7A;7F7A; # (罺罺; 罺; 罺; 罺; 罺; ) CJK COMPATIBILITY IDEOGRAPH-2F976 +2F977;2633E;2633E;2633E;2633E; # (𦌾𦌾; 𦌾𦌾; 𦌾𦌾; 𦌾𦌾; 𦌾𦌾; ) CJK COMPATIBILITY IDEOGRAPH-2F977 +2F978;7F95;7F95;7F95;7F95; # (羕羕; 羕; 羕; 羕; 羕; ) CJK COMPATIBILITY IDEOGRAPH-2F978 +2F979;7FFA;7FFA;7FFA;7FFA; # (翺翺; 翺; 翺; 翺; 翺; ) CJK COMPATIBILITY IDEOGRAPH-2F979 +2F97A;8005;8005;8005;8005; # (者者; 者; 者; 者; 者; ) CJK COMPATIBILITY IDEOGRAPH-2F97A +2F97B;264DA;264DA;264DA;264DA; # (𦓚𦓚; 𦓚𦓚; 𦓚𦓚; 𦓚𦓚; 𦓚𦓚; ) CJK COMPATIBILITY IDEOGRAPH-2F97B +2F97C;26523;26523;26523;26523; # (𦔣𦔣; 𦔣𦔣; 𦔣𦔣; 𦔣𦔣; 𦔣𦔣; ) CJK COMPATIBILITY IDEOGRAPH-2F97C +2F97D;8060;8060;8060;8060; # (聠聠; 聠; 聠; 聠; 聠; ) CJK COMPATIBILITY IDEOGRAPH-2F97D +2F97E;265A8;265A8;265A8;265A8; # (𦖨𦖨; 𦖨𦖨; 𦖨𦖨; 𦖨𦖨; 𦖨𦖨; ) CJK COMPATIBILITY IDEOGRAPH-2F97E +2F97F;8070;8070;8070;8070; # (聰聰; 聰; 聰; 聰; 聰; ) CJK COMPATIBILITY IDEOGRAPH-2F97F +2F980;2335F;2335F;2335F;2335F; # (𣍟𣍟; 𣍟𣍟; 𣍟𣍟; 𣍟𣍟; 𣍟𣍟; ) CJK COMPATIBILITY IDEOGRAPH-2F980 +2F981;43D5;43D5;43D5;43D5; # (䏕䏕; 䏕; 䏕; 䏕; 䏕; ) CJK COMPATIBILITY IDEOGRAPH-2F981 +2F982;80B2;80B2;80B2;80B2; # (育育; 育; 育; 育; 育; ) CJK COMPATIBILITY IDEOGRAPH-2F982 +2F983;8103;8103;8103;8103; # (脃脃; 脃; 脃; 脃; 脃; ) CJK COMPATIBILITY IDEOGRAPH-2F983 +2F984;440B;440B;440B;440B; # (䐋䐋; 䐋; 䐋; 䐋; 䐋; ) CJK COMPATIBILITY IDEOGRAPH-2F984 +2F985;813E;813E;813E;813E; # (脾脾; 脾; 脾; 脾; 脾; ) CJK COMPATIBILITY IDEOGRAPH-2F985 +2F986;5AB5;5AB5;5AB5;5AB5; # (媵媵; 媵; 媵; 媵; 媵; ) CJK COMPATIBILITY IDEOGRAPH-2F986 +2F987;267A7;267A7;267A7;267A7; # (𦞧𦞧; 𦞧𦞧; 𦞧𦞧; 𦞧𦞧; 𦞧𦞧; ) CJK COMPATIBILITY IDEOGRAPH-2F987 +2F988;267B5;267B5;267B5;267B5; # (𦞵𦞵; 𦞵𦞵; 𦞵𦞵; 𦞵𦞵; 𦞵𦞵; ) CJK COMPATIBILITY IDEOGRAPH-2F988 +2F989;23393;23393;23393;23393; # (𣎓𣎓; 𣎓𣎓; 𣎓𣎓; 𣎓𣎓; 𣎓𣎓; ) CJK COMPATIBILITY IDEOGRAPH-2F989 +2F98A;2339C;2339C;2339C;2339C; # (𣎜𣎜; 𣎜𣎜; 𣎜𣎜; 𣎜𣎜; 𣎜𣎜; ) CJK COMPATIBILITY IDEOGRAPH-2F98A +2F98B;8201;8201;8201;8201; # (舁舁; 舁; 舁; 舁; 舁; ) CJK COMPATIBILITY IDEOGRAPH-2F98B +2F98C;8204;8204;8204;8204; # (舄舄; 舄; 舄; 舄; 舄; ) CJK COMPATIBILITY IDEOGRAPH-2F98C +2F98D;8F9E;8F9E;8F9E;8F9E; # (辞辞; 辞; 辞; 辞; 辞; ) CJK COMPATIBILITY IDEOGRAPH-2F98D +2F98E;446B;446B;446B;446B; # (䑫䑫; 䑫; 䑫; 䑫; 䑫; ) CJK COMPATIBILITY IDEOGRAPH-2F98E +2F98F;8291;8291;8291;8291; # (芑芑; 芑; 芑; 芑; 芑; ) CJK COMPATIBILITY IDEOGRAPH-2F98F +2F990;828B;828B;828B;828B; # (芋芋; 芋; 芋; 芋; 芋; ) CJK COMPATIBILITY IDEOGRAPH-2F990 +2F991;829D;829D;829D;829D; # (芝芝; 芝; 芝; 芝; 芝; ) CJK COMPATIBILITY IDEOGRAPH-2F991 +2F992;52B3;52B3;52B3;52B3; # (劳劳; 劳; 劳; 劳; 劳; ) CJK COMPATIBILITY IDEOGRAPH-2F992 +2F993;82B1;82B1;82B1;82B1; # (花花; 花; 花; 花; 花; ) CJK COMPATIBILITY IDEOGRAPH-2F993 +2F994;82B3;82B3;82B3;82B3; # (芳芳; 芳; 芳; 芳; 芳; ) CJK COMPATIBILITY IDEOGRAPH-2F994 +2F995;82BD;82BD;82BD;82BD; # (芽芽; 芽; 芽; 芽; 芽; ) CJK COMPATIBILITY IDEOGRAPH-2F995 +2F996;82E6;82E6;82E6;82E6; # (苦苦; 苦; 苦; 苦; 苦; ) CJK COMPATIBILITY IDEOGRAPH-2F996 +2F997;26B3C;26B3C;26B3C;26B3C; # (𦬼𦬼; 𦬼𦬼; 𦬼𦬼; 𦬼𦬼; 𦬼𦬼; ) CJK COMPATIBILITY IDEOGRAPH-2F997 +2F998;82E5;82E5;82E5;82E5; # (若若; 若; 若; 若; 若; ) CJK COMPATIBILITY IDEOGRAPH-2F998 +2F999;831D;831D;831D;831D; # (茝茝; 茝; 茝; 茝; 茝; ) CJK COMPATIBILITY IDEOGRAPH-2F999 +2F99A;8363;8363;8363;8363; # (荣荣; 荣; 荣; 荣; 荣; ) CJK COMPATIBILITY IDEOGRAPH-2F99A +2F99B;83AD;83AD;83AD;83AD; # (莭莭; 莭; 莭; 莭; 莭; ) CJK COMPATIBILITY IDEOGRAPH-2F99B +2F99C;8323;8323;8323;8323; # (茣茣; 茣; 茣; 茣; 茣; ) CJK COMPATIBILITY IDEOGRAPH-2F99C +2F99D;83BD;83BD;83BD;83BD; # (莽莽; 莽; 莽; 莽; 莽; ) CJK COMPATIBILITY IDEOGRAPH-2F99D +2F99E;83E7;83E7;83E7;83E7; # (菧菧; 菧; 菧; 菧; 菧; ) CJK COMPATIBILITY IDEOGRAPH-2F99E +2F99F;8457;8457;8457;8457; # (著著; 著; 著; 著; 著; ) CJK COMPATIBILITY IDEOGRAPH-2F99F +2F9A0;8353;8353;8353;8353; # (荓荓; 荓; 荓; 荓; 荓; ) CJK COMPATIBILITY IDEOGRAPH-2F9A0 +2F9A1;83CA;83CA;83CA;83CA; # (菊菊; 菊; 菊; 菊; 菊; ) CJK COMPATIBILITY IDEOGRAPH-2F9A1 +2F9A2;83CC;83CC;83CC;83CC; # (菌菌; 菌; 菌; 菌; 菌; ) CJK COMPATIBILITY IDEOGRAPH-2F9A2 +2F9A3;83DC;83DC;83DC;83DC; # (菜菜; 菜; 菜; 菜; 菜; ) CJK COMPATIBILITY IDEOGRAPH-2F9A3 +2F9A4;26C36;26C36;26C36;26C36; # (𦰶𦰶; 𦰶𦰶; 𦰶𦰶; 𦰶𦰶; 𦰶𦰶; ) CJK COMPATIBILITY IDEOGRAPH-2F9A4 +2F9A5;26D6B;26D6B;26D6B;26D6B; # (𦵫𦵫; 𦵫𦵫; 𦵫𦵫; 𦵫𦵫; 𦵫𦵫; ) CJK COMPATIBILITY IDEOGRAPH-2F9A5 +2F9A6;26CD5;26CD5;26CD5;26CD5; # (𦳕𦳕; 𦳕𦳕; 𦳕𦳕; 𦳕𦳕; 𦳕𦳕; ) CJK COMPATIBILITY IDEOGRAPH-2F9A6 +2F9A7;452B;452B;452B;452B; # (䔫䔫; 䔫; 䔫; 䔫; 䔫; ) CJK COMPATIBILITY IDEOGRAPH-2F9A7 +2F9A8;84F1;84F1;84F1;84F1; # (蓱蓱; 蓱; 蓱; 蓱; 蓱; ) CJK COMPATIBILITY IDEOGRAPH-2F9A8 +2F9A9;84F3;84F3;84F3;84F3; # (蓳蓳; 蓳; 蓳; 蓳; 蓳; ) CJK COMPATIBILITY IDEOGRAPH-2F9A9 +2F9AA;8516;8516;8516;8516; # (蔖蔖; 蔖; 蔖; 蔖; 蔖; ) CJK COMPATIBILITY IDEOGRAPH-2F9AA +2F9AB;273CA;273CA;273CA;273CA; # (𧏊𧏊; 𧏊𧏊; 𧏊𧏊; 𧏊𧏊; 𧏊𧏊; ) CJK COMPATIBILITY IDEOGRAPH-2F9AB +2F9AC;8564;8564;8564;8564; # (蕤蕤; 蕤; 蕤; 蕤; 蕤; ) CJK COMPATIBILITY IDEOGRAPH-2F9AC +2F9AD;26F2C;26F2C;26F2C;26F2C; # (𦼬𦼬; 𦼬𦼬; 𦼬𦼬; 𦼬𦼬; 𦼬𦼬; ) CJK COMPATIBILITY IDEOGRAPH-2F9AD +2F9AE;455D;455D;455D;455D; # (䕝䕝; 䕝; 䕝; 䕝; 䕝; ) CJK COMPATIBILITY IDEOGRAPH-2F9AE +2F9AF;4561;4561;4561;4561; # (䕡䕡; 䕡; 䕡; 䕡; 䕡; ) CJK COMPATIBILITY IDEOGRAPH-2F9AF +2F9B0;26FB1;26FB1;26FB1;26FB1; # (𦾱𦾱; 𦾱𦾱; 𦾱𦾱; 𦾱𦾱; 𦾱𦾱; ) CJK COMPATIBILITY IDEOGRAPH-2F9B0 +2F9B1;270D2;270D2;270D2;270D2; # (𧃒𧃒; 𧃒𧃒; 𧃒𧃒; 𧃒𧃒; 𧃒𧃒; ) CJK COMPATIBILITY IDEOGRAPH-2F9B1 +2F9B2;456B;456B;456B;456B; # (䕫䕫; 䕫; 䕫; 䕫; 䕫; ) CJK COMPATIBILITY IDEOGRAPH-2F9B2 +2F9B3;8650;8650;8650;8650; # (虐虐; 虐; 虐; 虐; 虐; ) CJK COMPATIBILITY IDEOGRAPH-2F9B3 +2F9B4;865C;865C;865C;865C; # (虜虜; 虜; 虜; 虜; 虜; ) CJK COMPATIBILITY IDEOGRAPH-2F9B4 +2F9B5;8667;8667;8667;8667; # (虧虧; 虧; 虧; 虧; 虧; ) CJK COMPATIBILITY IDEOGRAPH-2F9B5 +2F9B6;8669;8669;8669;8669; # (虩虩; 虩; 虩; 虩; 虩; ) CJK COMPATIBILITY IDEOGRAPH-2F9B6 +2F9B7;86A9;86A9;86A9;86A9; # (蚩蚩; 蚩; 蚩; 蚩; 蚩; ) CJK COMPATIBILITY IDEOGRAPH-2F9B7 +2F9B8;8688;8688;8688;8688; # (蚈蚈; 蚈; 蚈; 蚈; 蚈; ) CJK COMPATIBILITY IDEOGRAPH-2F9B8 +2F9B9;870E;870E;870E;870E; # (蜎蜎; 蜎; 蜎; 蜎; 蜎; ) CJK COMPATIBILITY IDEOGRAPH-2F9B9 +2F9BA;86E2;86E2;86E2;86E2; # (蛢蛢; 蛢; 蛢; 蛢; 蛢; ) CJK COMPATIBILITY IDEOGRAPH-2F9BA +2F9BB;8779;8779;8779;8779; # (蝹蝹; 蝹; 蝹; 蝹; 蝹; ) CJK COMPATIBILITY IDEOGRAPH-2F9BB +2F9BC;8728;8728;8728;8728; # (蜨蜨; 蜨; 蜨; 蜨; 蜨; ) CJK COMPATIBILITY IDEOGRAPH-2F9BC +2F9BD;876B;876B;876B;876B; # (蝫蝫; 蝫; 蝫; 蝫; 蝫; ) CJK COMPATIBILITY IDEOGRAPH-2F9BD +2F9BE;8786;8786;8786;8786; # (螆螆; 螆; 螆; 螆; 螆; ) CJK COMPATIBILITY IDEOGRAPH-2F9BE +2F9BF;4D57;4D57;4D57;4D57; # (䗗䗗; 䵗; 䵗; 䵗; 䵗; ) CJK COMPATIBILITY IDEOGRAPH-2F9BF +2F9C0;87E1;87E1;87E1;87E1; # (蟡蟡; 蟡; 蟡; 蟡; 蟡; ) CJK COMPATIBILITY IDEOGRAPH-2F9C0 +2F9C1;8801;8801;8801;8801; # (蠁蠁; 蠁; 蠁; 蠁; 蠁; ) CJK COMPATIBILITY IDEOGRAPH-2F9C1 +2F9C2;45F9;45F9;45F9;45F9; # (䗹䗹; 䗹; 䗹; 䗹; 䗹; ) CJK COMPATIBILITY IDEOGRAPH-2F9C2 +2F9C3;8860;8860;8860;8860; # (衠衠; 衠; 衠; 衠; 衠; ) CJK COMPATIBILITY IDEOGRAPH-2F9C3 +2F9C4;8863;8863;8863;8863; # (衣衣; 衣; 衣; 衣; 衣; ) CJK COMPATIBILITY IDEOGRAPH-2F9C4 +2F9C5;27667;27667;27667;27667; # (𧙧𧙧; 𧙧𧙧; 𧙧𧙧; 𧙧𧙧; 𧙧𧙧; ) CJK COMPATIBILITY IDEOGRAPH-2F9C5 +2F9C6;88D7;88D7;88D7;88D7; # (裗裗; 裗; 裗; 裗; 裗; ) CJK COMPATIBILITY IDEOGRAPH-2F9C6 +2F9C7;88DE;88DE;88DE;88DE; # (裞裞; 裞; 裞; 裞; 裞; ) CJK COMPATIBILITY IDEOGRAPH-2F9C7 +2F9C8;4635;4635;4635;4635; # (䘵䘵; 䘵; 䘵; 䘵; 䘵; ) CJK COMPATIBILITY IDEOGRAPH-2F9C8 +2F9C9;88FA;88FA;88FA;88FA; # (裺裺; 裺; 裺; 裺; 裺; ) CJK COMPATIBILITY IDEOGRAPH-2F9C9 +2F9CA;34BB;34BB;34BB;34BB; # (㒻㒻; 㒻; 㒻; 㒻; 㒻; ) CJK COMPATIBILITY IDEOGRAPH-2F9CA +2F9CB;278AE;278AE;278AE;278AE; # (𧢮𧢮; 𧢮𧢮; 𧢮𧢮; 𧢮𧢮; 𧢮𧢮; ) CJK COMPATIBILITY IDEOGRAPH-2F9CB +2F9CC;27966;27966;27966;27966; # (𧥦𧥦; 𧥦𧥦; 𧥦𧥦; 𧥦𧥦; 𧥦𧥦; ) CJK COMPATIBILITY IDEOGRAPH-2F9CC +2F9CD;46BE;46BE;46BE;46BE; # (䚾䚾; 䚾; 䚾; 䚾; 䚾; ) CJK COMPATIBILITY IDEOGRAPH-2F9CD +2F9CE;46C7;46C7;46C7;46C7; # (䛇䛇; 䛇; 䛇; 䛇; 䛇; ) CJK COMPATIBILITY IDEOGRAPH-2F9CE +2F9CF;8AA0;8AA0;8AA0;8AA0; # (誠誠; 誠; 誠; 誠; 誠; ) CJK COMPATIBILITY IDEOGRAPH-2F9CF +2F9D0;8AED;8AED;8AED;8AED; # (諭諭; 諭; 諭; 諭; 諭; ) CJK COMPATIBILITY IDEOGRAPH-2F9D0 +2F9D1;8B8A;8B8A;8B8A;8B8A; # (變變; 變; 變; 變; 變; ) CJK COMPATIBILITY IDEOGRAPH-2F9D1 +2F9D2;8C55;8C55;8C55;8C55; # (豕豕; 豕; 豕; 豕; 豕; ) CJK COMPATIBILITY IDEOGRAPH-2F9D2 +2F9D3;27CA8;27CA8;27CA8;27CA8; # (𧲨𧲨; 𧲨𧲨; 𧲨𧲨; 𧲨𧲨; 𧲨𧲨; ) CJK COMPATIBILITY IDEOGRAPH-2F9D3 +2F9D4;8CAB;8CAB;8CAB;8CAB; # (貫貫; 貫; 貫; 貫; 貫; ) CJK COMPATIBILITY IDEOGRAPH-2F9D4 +2F9D5;8CC1;8CC1;8CC1;8CC1; # (賁賁; 賁; 賁; 賁; 賁; ) CJK COMPATIBILITY IDEOGRAPH-2F9D5 +2F9D6;8D1B;8D1B;8D1B;8D1B; # (贛贛; 贛; 贛; 贛; 贛; ) CJK COMPATIBILITY IDEOGRAPH-2F9D6 +2F9D7;8D77;8D77;8D77;8D77; # (起起; 起; 起; 起; 起; ) CJK COMPATIBILITY IDEOGRAPH-2F9D7 +2F9D8;27F2F;27F2F;27F2F;27F2F; # (𧼯𧼯; 𧼯𧼯; 𧼯𧼯; 𧼯𧼯; 𧼯𧼯; ) CJK COMPATIBILITY IDEOGRAPH-2F9D8 +2F9D9;20804;20804;20804;20804; # (𠠄𠠄; 𠠄𠠄; 𠠄𠠄; 𠠄𠠄; 𠠄𠠄; ) CJK COMPATIBILITY IDEOGRAPH-2F9D9 +2F9DA;8DCB;8DCB;8DCB;8DCB; # (跋跋; 跋; 跋; 跋; 跋; ) CJK COMPATIBILITY IDEOGRAPH-2F9DA +2F9DB;8DBC;8DBC;8DBC;8DBC; # (趼趼; 趼; 趼; 趼; 趼; ) CJK COMPATIBILITY IDEOGRAPH-2F9DB +2F9DC;8DF0;8DF0;8DF0;8DF0; # (跰跰; 跰; 跰; 跰; 跰; ) CJK COMPATIBILITY IDEOGRAPH-2F9DC +2F9DD;208DE;208DE;208DE;208DE; # (𠣞𠣞; 𠣞𠣞; 𠣞𠣞; 𠣞𠣞; 𠣞𠣞; ) CJK COMPATIBILITY IDEOGRAPH-2F9DD +2F9DE;8ED4;8ED4;8ED4;8ED4; # (軔軔; 軔; 軔; 軔; 軔; ) CJK COMPATIBILITY IDEOGRAPH-2F9DE +2F9DF;8F38;8F38;8F38;8F38; # (輸輸; 輸; 輸; 輸; 輸; ) CJK COMPATIBILITY IDEOGRAPH-2F9DF +2F9E0;285D2;285D2;285D2;285D2; # (𨗒𨗒; 𨗒𨗒; 𨗒𨗒; 𨗒𨗒; 𨗒𨗒; ) CJK COMPATIBILITY IDEOGRAPH-2F9E0 +2F9E1;285ED;285ED;285ED;285ED; # (𨗭𨗭; 𨗭𨗭; 𨗭𨗭; 𨗭𨗭; 𨗭𨗭; ) CJK COMPATIBILITY IDEOGRAPH-2F9E1 +2F9E2;9094;9094;9094;9094; # (邔邔; 邔; 邔; 邔; 邔; ) CJK COMPATIBILITY IDEOGRAPH-2F9E2 +2F9E3;90F1;90F1;90F1;90F1; # (郱郱; 郱; 郱; 郱; 郱; ) CJK COMPATIBILITY IDEOGRAPH-2F9E3 +2F9E4;9111;9111;9111;9111; # (鄑鄑; 鄑; 鄑; 鄑; 鄑; ) CJK COMPATIBILITY IDEOGRAPH-2F9E4 +2F9E5;2872E;2872E;2872E;2872E; # (𨜮𨜮; 𨜮𨜮; 𨜮𨜮; 𨜮𨜮; 𨜮𨜮; ) CJK COMPATIBILITY IDEOGRAPH-2F9E5 +2F9E6;911B;911B;911B;911B; # (鄛鄛; 鄛; 鄛; 鄛; 鄛; ) CJK COMPATIBILITY IDEOGRAPH-2F9E6 +2F9E7;9238;9238;9238;9238; # (鈸鈸; 鈸; 鈸; 鈸; 鈸; ) CJK COMPATIBILITY IDEOGRAPH-2F9E7 +2F9E8;92D7;92D7;92D7;92D7; # (鋗鋗; 鋗; 鋗; 鋗; 鋗; ) CJK COMPATIBILITY IDEOGRAPH-2F9E8 +2F9E9;92D8;92D8;92D8;92D8; # (鋘鋘; 鋘; 鋘; 鋘; 鋘; ) CJK COMPATIBILITY IDEOGRAPH-2F9E9 +2F9EA;927C;927C;927C;927C; # (鉼鉼; 鉼; 鉼; 鉼; 鉼; ) CJK COMPATIBILITY IDEOGRAPH-2F9EA +2F9EB;93F9;93F9;93F9;93F9; # (鏹鏹; 鏹; 鏹; 鏹; 鏹; ) CJK COMPATIBILITY IDEOGRAPH-2F9EB +2F9EC;9415;9415;9415;9415; # (鐕鐕; 鐕; 鐕; 鐕; 鐕; ) CJK COMPATIBILITY IDEOGRAPH-2F9EC +2F9ED;28BFA;28BFA;28BFA;28BFA; # (𨯺𨯺; 𨯺𨯺; 𨯺𨯺; 𨯺𨯺; 𨯺𨯺; ) CJK COMPATIBILITY IDEOGRAPH-2F9ED +2F9EE;958B;958B;958B;958B; # (開開; 開; 開; 開; 開; ) CJK COMPATIBILITY IDEOGRAPH-2F9EE +2F9EF;4995;4995;4995;4995; # (䦕䦕; 䦕; 䦕; 䦕; 䦕; ) CJK COMPATIBILITY IDEOGRAPH-2F9EF +2F9F0;95B7;95B7;95B7;95B7; # (閷閷; 閷; 閷; 閷; 閷; ) CJK COMPATIBILITY IDEOGRAPH-2F9F0 +2F9F1;28D77;28D77;28D77;28D77; # (𨵷𨵷; 𨵷𨵷; 𨵷𨵷; 𨵷𨵷; 𨵷𨵷; ) CJK COMPATIBILITY IDEOGRAPH-2F9F1 +2F9F2;49E6;49E6;49E6;49E6; # (䧦䧦; 䧦; 䧦; 䧦; 䧦; ) CJK COMPATIBILITY IDEOGRAPH-2F9F2 +2F9F3;96C3;96C3;96C3;96C3; # (雃雃; 雃; 雃; 雃; 雃; ) CJK COMPATIBILITY IDEOGRAPH-2F9F3 +2F9F4;5DB2;5DB2;5DB2;5DB2; # (嶲嶲; 嶲; 嶲; 嶲; 嶲; ) CJK COMPATIBILITY IDEOGRAPH-2F9F4 +2F9F5;9723;9723;9723;9723; # (霣霣; 霣; 霣; 霣; 霣; ) CJK COMPATIBILITY IDEOGRAPH-2F9F5 +2F9F6;29145;29145;29145;29145; # (𩅅𩅅; 𩅅𩅅; 𩅅𩅅; 𩅅𩅅; 𩅅𩅅; ) CJK COMPATIBILITY IDEOGRAPH-2F9F6 +2F9F7;2921A;2921A;2921A;2921A; # (𩈚𩈚; 𩈚𩈚; 𩈚𩈚; 𩈚𩈚; 𩈚𩈚; ) CJK COMPATIBILITY IDEOGRAPH-2F9F7 +2F9F8;4A6E;4A6E;4A6E;4A6E; # (䩮䩮; 䩮; 䩮; 䩮; 䩮; ) CJK COMPATIBILITY IDEOGRAPH-2F9F8 +2F9F9;4A76;4A76;4A76;4A76; # (䩶䩶; 䩶; 䩶; 䩶; 䩶; ) CJK COMPATIBILITY IDEOGRAPH-2F9F9 +2F9FA;97E0;97E0;97E0;97E0; # (韠韠; 韠; 韠; 韠; 韠; ) CJK COMPATIBILITY IDEOGRAPH-2F9FA +2F9FB;2940A;2940A;2940A;2940A; # (𩐊𩐊; 𩐊𩐊; 𩐊𩐊; 𩐊𩐊; 𩐊𩐊; ) CJK COMPATIBILITY IDEOGRAPH-2F9FB +2F9FC;4AB2;4AB2;4AB2;4AB2; # (䪲䪲; 䪲; 䪲; 䪲; 䪲; ) CJK COMPATIBILITY IDEOGRAPH-2F9FC +2F9FD;29496;29496;29496;29496; # (𩒖𩒖; 𩒖𩒖; 𩒖𩒖; 𩒖𩒖; 𩒖𩒖; ) CJK COMPATIBILITY IDEOGRAPH-2F9FD +2F9FE;980B;980B;980B;980B; # (頋頋; 頋; 頋; 頋; 頋; ) CJK COMPATIBILITY IDEOGRAPH-2F9FE +2F9FF;980B;980B;980B;980B; # (頋頋; 頋; 頋; 頋; 頋; ) CJK COMPATIBILITY IDEOGRAPH-2F9FF +2FA00;9829;9829;9829;9829; # (頩頩; 頩; 頩; 頩; 頩; ) CJK COMPATIBILITY IDEOGRAPH-2FA00 +2FA01;295B6;295B6;295B6;295B6; # (𩖶𩖶; 𩖶𩖶; 𩖶𩖶; 𩖶𩖶; 𩖶𩖶; ) CJK COMPATIBILITY IDEOGRAPH-2FA01 +2FA02;98E2;98E2;98E2;98E2; # (飢飢; 飢; 飢; 飢; 飢; ) CJK COMPATIBILITY IDEOGRAPH-2FA02 +2FA03;4B33;4B33;4B33;4B33; # (䬳䬳; 䬳; 䬳; 䬳; 䬳; ) CJK COMPATIBILITY IDEOGRAPH-2FA03 +2FA04;9929;9929;9929;9929; # (餩餩; 餩; 餩; 餩; 餩; ) CJK COMPATIBILITY IDEOGRAPH-2FA04 +2FA05;99A7;99A7;99A7;99A7; # (馧馧; 馧; 馧; 馧; 馧; ) CJK COMPATIBILITY IDEOGRAPH-2FA05 +2FA06;99C2;99C2;99C2;99C2; # (駂駂; 駂; 駂; 駂; 駂; ) CJK COMPATIBILITY IDEOGRAPH-2FA06 +2FA07;99FE;99FE;99FE;99FE; # (駾駾; 駾; 駾; 駾; 駾; ) CJK COMPATIBILITY IDEOGRAPH-2FA07 +2FA08;4BCE;4BCE;4BCE;4BCE; # (䯎䯎; 䯎; 䯎; 䯎; 䯎; ) CJK COMPATIBILITY IDEOGRAPH-2FA08 +2FA09;29B30;29B30;29B30;29B30; # (𩬰𩬰; 𩬰𩬰; 𩬰𩬰; 𩬰𩬰; 𩬰𩬰; ) CJK COMPATIBILITY IDEOGRAPH-2FA09 +2FA0A;9B12;9B12;9B12;9B12; # (鬒鬒; 鬒; 鬒; 鬒; 鬒; ) CJK COMPATIBILITY IDEOGRAPH-2FA0A +2FA0B;9C40;9C40;9C40;9C40; # (鱀鱀; 鱀; 鱀; 鱀; 鱀; ) CJK COMPATIBILITY IDEOGRAPH-2FA0B +2FA0C;9CFD;9CFD;9CFD;9CFD; # (鳽鳽; 鳽; 鳽; 鳽; 鳽; ) CJK COMPATIBILITY IDEOGRAPH-2FA0C +2FA0D;4CCE;4CCE;4CCE;4CCE; # (䳎䳎; 䳎; 䳎; 䳎; 䳎; ) CJK COMPATIBILITY IDEOGRAPH-2FA0D +2FA0E;4CED;4CED;4CED;4CED; # (䳭䳭; 䳭; 䳭; 䳭; 䳭; ) CJK COMPATIBILITY IDEOGRAPH-2FA0E +2FA0F;9D67;9D67;9D67;9D67; # (鵧鵧; 鵧; 鵧; 鵧; 鵧; ) CJK COMPATIBILITY IDEOGRAPH-2FA0F +2FA10;2A0CE;2A0CE;2A0CE;2A0CE; # (𪃎𪃎; 𪃎𪃎; 𪃎𪃎; 𪃎𪃎; 𪃎𪃎; ) CJK COMPATIBILITY IDEOGRAPH-2FA10 +2FA11;4CF8;4CF8;4CF8;4CF8; # (䳸䳸; 䳸; 䳸; 䳸; 䳸; ) CJK COMPATIBILITY IDEOGRAPH-2FA11 +2FA12;2A105;2A105;2A105;2A105; # (𪄅𪄅; 𪄅𪄅; 𪄅𪄅; 𪄅𪄅; 𪄅𪄅; ) CJK COMPATIBILITY IDEOGRAPH-2FA12 +2FA13;2A20E;2A20E;2A20E;2A20E; # (𪈎𪈎; 𪈎𪈎; 𪈎𪈎; 𪈎𪈎; 𪈎𪈎; ) CJK COMPATIBILITY IDEOGRAPH-2FA13 +2FA14;2A291;2A291;2A291;2A291; # (𪊑𪊑; 𪊑𪊑; 𪊑𪊑; 𪊑𪊑; 𪊑𪊑; ) CJK COMPATIBILITY IDEOGRAPH-2FA14 +2FA15;9EBB;9EBB;9EBB;9EBB; # (麻麻; 麻; 麻; 麻; 麻; ) CJK COMPATIBILITY IDEOGRAPH-2FA15 +2FA16;4D56;4D56;4D56;4D56; # (䵖䵖; 䵖; 䵖; 䵖; 䵖; ) CJK COMPATIBILITY IDEOGRAPH-2FA16 +2FA17;9EF9;9EF9;9EF9;9EF9; # (黹黹; 黹; 黹; 黹; 黹; ) CJK COMPATIBILITY IDEOGRAPH-2FA17 +2FA18;9EFE;9EFE;9EFE;9EFE; # (黾黾; 黾; 黾; 黾; 黾; ) CJK COMPATIBILITY IDEOGRAPH-2FA18 +2FA19;9F05;9F05;9F05;9F05; # (鼅鼅; 鼅; 鼅; 鼅; 鼅; ) CJK COMPATIBILITY IDEOGRAPH-2FA19 +2FA1A;9F0F;9F0F;9F0F;9F0F; # (鼏鼏; 鼏; 鼏; 鼏; 鼏; ) CJK COMPATIBILITY IDEOGRAPH-2FA1A +2FA1B;9F16;9F16;9F16;9F16; # (鼖鼖; 鼖; 鼖; 鼖; 鼖; ) CJK COMPATIBILITY IDEOGRAPH-2FA1B +2FA1C;9F3B;9F3B;9F3B;9F3B; # (鼻鼻; 鼻; 鼻; 鼻; 鼻; ) CJK COMPATIBILITY IDEOGRAPH-2FA1C +2FA1D;2A600;2A600;2A600;2A600; # (𪘀𪘀; 𪘀𪘀; 𪘀𪘀; 𪘀𪘀; 𪘀𪘀; ) CJK COMPATIBILITY IDEOGRAPH-2FA1D +# +@Part2 # Canonical Order Test +# +0061 0315 0300 05AE 0300 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̕◌̀◌֮◌̀b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 0300 0315 0300 05AE 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̀◌̕◌̀◌֮b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0301 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062; # (a◌̕◌̀◌֮◌́b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE ACCENT, LATIN SMALL LETTER B +0061 0301 0315 0300 05AE 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062; # (a◌́◌̕◌̀◌֮b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0302 0062;00E0 05AE 0302 0315 0062;0061 05AE 0300 0302 0315 0062;00E0 05AE 0302 0315 0062;0061 05AE 0300 0302 0315 0062; # (a◌̕◌̀◌֮◌̂b; à◌֮◌̂◌̕b; a◌֮◌̀◌̂◌̕b; à◌֮◌̂◌̕b; a◌֮◌̀◌̂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CIRCUMFLEX ACCENT, LATIN SMALL LETTER B +0061 0302 0315 0300 05AE 0062;1EA7 05AE 0315 0062;0061 05AE 0302 0300 0315 0062;1EA7 05AE 0315 0062;0061 05AE 0302 0300 0315 0062; # (a◌̂◌̕◌̀◌֮b; ầ◌֮◌̕b; a◌֮◌̂◌̀◌̕b; ầ◌֮◌̕b; a◌֮◌̂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CIRCUMFLEX ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0303 0062;00E0 05AE 0303 0315 0062;0061 05AE 0300 0303 0315 0062;00E0 05AE 0303 0315 0062;0061 05AE 0300 0303 0315 0062; # (a◌̕◌̀◌֮◌̃b; à◌֮◌̃◌̕b; a◌֮◌̀◌̃◌̕b; à◌֮◌̃◌̕b; a◌֮◌̀◌̃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TILDE, LATIN SMALL LETTER B +0061 0303 0315 0300 05AE 0062;00E3 05AE 0300 0315 0062;0061 05AE 0303 0300 0315 0062;00E3 05AE 0300 0315 0062;0061 05AE 0303 0300 0315 0062; # (a◌̃◌̕◌̀◌֮b; ã◌֮◌̀◌̕b; a◌֮◌̃◌̀◌̕b; ã◌֮◌̀◌̕b; a◌֮◌̃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TILDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0304 0062;00E0 05AE 0304 0315 0062;0061 05AE 0300 0304 0315 0062;00E0 05AE 0304 0315 0062;0061 05AE 0300 0304 0315 0062; # (a◌̕◌̀◌֮◌̄b; à◌֮◌̄◌̕b; a◌֮◌̀◌̄◌̕b; à◌֮◌̄◌̕b; a◌֮◌̀◌̄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON, LATIN SMALL LETTER B +0061 0304 0315 0300 05AE 0062;0101 05AE 0300 0315 0062;0061 05AE 0304 0300 0315 0062;0101 05AE 0300 0315 0062;0061 05AE 0304 0300 0315 0062; # (a◌̄◌̕◌̀◌֮b; ā◌֮◌̀◌̕b; a◌֮◌̄◌̀◌̕b; ā◌֮◌̀◌̕b; a◌֮◌̄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0305 0062;00E0 05AE 0305 0315 0062;0061 05AE 0300 0305 0315 0062;00E0 05AE 0305 0315 0062;0061 05AE 0300 0305 0315 0062; # (a◌̕◌̀◌֮◌̅b; à◌֮◌̅◌̕b; a◌֮◌̀◌̅◌̕b; à◌֮◌̅◌̕b; a◌֮◌̀◌̅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OVERLINE, LATIN SMALL LETTER B +0061 0305 0315 0300 05AE 0062;0061 05AE 0305 0300 0315 0062;0061 05AE 0305 0300 0315 0062;0061 05AE 0305 0300 0315 0062;0061 05AE 0305 0300 0315 0062; # (a◌̅◌̕◌̀◌֮b; a◌֮◌̅◌̀◌̕b; a◌֮◌̅◌̀◌̕b; a◌֮◌̅◌̀◌̕b; a◌֮◌̅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OVERLINE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0306 0062;00E0 05AE 0306 0315 0062;0061 05AE 0300 0306 0315 0062;00E0 05AE 0306 0315 0062;0061 05AE 0300 0306 0315 0062; # (a◌̕◌̀◌֮◌̆b; à◌֮◌̆◌̕b; a◌֮◌̀◌̆◌̕b; à◌֮◌̆◌̕b; a◌֮◌̀◌̆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BREVE, LATIN SMALL LETTER B +0061 0306 0315 0300 05AE 0062;1EB1 05AE 0315 0062;0061 05AE 0306 0300 0315 0062;1EB1 05AE 0315 0062;0061 05AE 0306 0300 0315 0062; # (a◌̆◌̕◌̀◌֮b; ằ◌֮◌̕b; a◌֮◌̆◌̀◌̕b; ằ◌֮◌̕b; a◌֮◌̆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BREVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0307 0062;00E0 05AE 0307 0315 0062;0061 05AE 0300 0307 0315 0062;00E0 05AE 0307 0315 0062;0061 05AE 0300 0307 0315 0062; # (a◌̕◌̀◌֮◌̇b; à◌֮◌̇◌̕b; a◌֮◌̀◌̇◌̕b; à◌֮◌̇◌̕b; a◌֮◌̀◌̇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOT ABOVE, LATIN SMALL LETTER B +0061 0307 0315 0300 05AE 0062;0227 05AE 0300 0315 0062;0061 05AE 0307 0300 0315 0062;0227 05AE 0300 0315 0062;0061 05AE 0307 0300 0315 0062; # (a◌̇◌̕◌̀◌֮b; ȧ◌֮◌̀◌̕b; a◌֮◌̇◌̀◌̕b; ȧ◌֮◌̀◌̕b; a◌֮◌̇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0308 0062;00E0 05AE 0308 0315 0062;0061 05AE 0300 0308 0315 0062;00E0 05AE 0308 0315 0062;0061 05AE 0300 0308 0315 0062; # (a◌̕◌̀◌֮◌̈b; à◌֮◌̈◌̕b; a◌֮◌̀◌̈◌̕b; à◌֮◌̈◌̕b; a◌֮◌̀◌̈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DIAERESIS, LATIN SMALL LETTER B +0061 0308 0315 0300 05AE 0062;00E4 05AE 0300 0315 0062;0061 05AE 0308 0300 0315 0062;00E4 05AE 0300 0315 0062;0061 05AE 0308 0300 0315 0062; # (a◌̈◌̕◌̀◌֮b; ä◌֮◌̀◌̕b; a◌֮◌̈◌̀◌̕b; ä◌֮◌̀◌̕b; a◌֮◌̈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0309 0062;00E0 05AE 0309 0315 0062;0061 05AE 0300 0309 0315 0062;00E0 05AE 0309 0315 0062;0061 05AE 0300 0309 0315 0062; # (a◌̕◌̀◌֮◌̉b; à◌֮◌̉◌̕b; a◌֮◌̀◌̉◌̕b; à◌֮◌̉◌̕b; a◌֮◌̀◌̉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING HOOK ABOVE, LATIN SMALL LETTER B +0061 0309 0315 0300 05AE 0062;1EA3 05AE 0300 0315 0062;0061 05AE 0309 0300 0315 0062;1EA3 05AE 0300 0315 0062;0061 05AE 0309 0300 0315 0062; # (a◌̉◌̕◌̀◌֮b; ả◌֮◌̀◌̕b; a◌֮◌̉◌̀◌̕b; ả◌֮◌̀◌̕b; a◌֮◌̉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING HOOK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030A 0062;00E0 05AE 030A 0315 0062;0061 05AE 0300 030A 0315 0062;00E0 05AE 030A 0315 0062;0061 05AE 0300 030A 0315 0062; # (a◌̕◌̀◌֮◌̊b; à◌֮◌̊◌̕b; a◌֮◌̀◌̊◌̕b; à◌֮◌̊◌̕b; a◌֮◌̀◌̊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RING ABOVE, LATIN SMALL LETTER B +0061 030A 0315 0300 05AE 0062;00E5 05AE 0300 0315 0062;0061 05AE 030A 0300 0315 0062;00E5 05AE 0300 0315 0062;0061 05AE 030A 0300 0315 0062; # (a◌̊◌̕◌̀◌֮b; å◌֮◌̀◌̕b; a◌֮◌̊◌̀◌̕b; å◌֮◌̀◌̕b; a◌֮◌̊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030B 0062;00E0 05AE 030B 0315 0062;0061 05AE 0300 030B 0315 0062;00E0 05AE 030B 0315 0062;0061 05AE 0300 030B 0315 0062; # (a◌̕◌̀◌֮◌̋b; à◌֮◌̋◌̕b; a◌֮◌̀◌̋◌̕b; à◌֮◌̋◌̕b; a◌֮◌̀◌̋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE ACUTE ACCENT, LATIN SMALL LETTER B +0061 030B 0315 0300 05AE 0062;0061 05AE 030B 0300 0315 0062;0061 05AE 030B 0300 0315 0062;0061 05AE 030B 0300 0315 0062;0061 05AE 030B 0300 0315 0062; # (a◌̋◌̕◌̀◌֮b; a◌֮◌̋◌̀◌̕b; a◌֮◌̋◌̀◌̕b; a◌֮◌̋◌̀◌̕b; a◌֮◌̋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030C 0062;00E0 05AE 030C 0315 0062;0061 05AE 0300 030C 0315 0062;00E0 05AE 030C 0315 0062;0061 05AE 0300 030C 0315 0062; # (a◌̕◌̀◌֮◌̌b; à◌֮◌̌◌̕b; a◌֮◌̀◌̌◌̕b; à◌֮◌̌◌̕b; a◌֮◌̀◌̌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CARON, LATIN SMALL LETTER B +0061 030C 0315 0300 05AE 0062;01CE 05AE 0300 0315 0062;0061 05AE 030C 0300 0315 0062;01CE 05AE 0300 0315 0062;0061 05AE 030C 0300 0315 0062; # (a◌̌◌̕◌̀◌֮b; ǎ◌֮◌̀◌̕b; a◌֮◌̌◌̀◌̕b; ǎ◌֮◌̀◌̕b; a◌֮◌̌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CARON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030D 0062;00E0 05AE 030D 0315 0062;0061 05AE 0300 030D 0315 0062;00E0 05AE 030D 0315 0062;0061 05AE 0300 030D 0315 0062; # (a◌̕◌̀◌֮◌̍b; à◌֮◌̍◌̕b; a◌֮◌̀◌̍◌̕b; à◌֮◌̍◌̕b; a◌֮◌̀◌̍◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING VERTICAL LINE ABOVE, LATIN SMALL LETTER B +0061 030D 0315 0300 05AE 0062;0061 05AE 030D 0300 0315 0062;0061 05AE 030D 0300 0315 0062;0061 05AE 030D 0300 0315 0062;0061 05AE 030D 0300 0315 0062; # (a◌̍◌̕◌̀◌֮b; a◌֮◌̍◌̀◌̕b; a◌֮◌̍◌̀◌̕b; a◌֮◌̍◌̀◌̕b; a◌֮◌̍◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING VERTICAL LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030E 0062;00E0 05AE 030E 0315 0062;0061 05AE 0300 030E 0315 0062;00E0 05AE 030E 0315 0062;0061 05AE 0300 030E 0315 0062; # (a◌̕◌̀◌֮◌̎b; à◌֮◌̎◌̕b; a◌֮◌̀◌̎◌̕b; à◌֮◌̎◌̕b; a◌֮◌̀◌̎◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE VERTICAL LINE ABOVE, LATIN SMALL LETTER B +0061 030E 0315 0300 05AE 0062;0061 05AE 030E 0300 0315 0062;0061 05AE 030E 0300 0315 0062;0061 05AE 030E 0300 0315 0062;0061 05AE 030E 0300 0315 0062; # (a◌̎◌̕◌̀◌֮b; a◌֮◌̎◌̀◌̕b; a◌֮◌̎◌̀◌̕b; a◌֮◌̎◌̀◌̕b; a◌֮◌̎◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030F 0062;00E0 05AE 030F 0315 0062;0061 05AE 0300 030F 0315 0062;00E0 05AE 030F 0315 0062;0061 05AE 0300 030F 0315 0062; # (a◌̕◌̀◌֮◌̏b; à◌֮◌̏◌̕b; a◌֮◌̀◌̏◌̕b; à◌֮◌̏◌̕b; a◌֮◌̀◌̏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE GRAVE ACCENT, LATIN SMALL LETTER B +0061 030F 0315 0300 05AE 0062;0201 05AE 0300 0315 0062;0061 05AE 030F 0300 0315 0062;0201 05AE 0300 0315 0062;0061 05AE 030F 0300 0315 0062; # (a◌̏◌̕◌̀◌֮b; ȁ◌֮◌̀◌̕b; a◌֮◌̏◌̀◌̕b; ȁ◌֮◌̀◌̕b; a◌֮◌̏◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0310 0062;00E0 05AE 0310 0315 0062;0061 05AE 0300 0310 0315 0062;00E0 05AE 0310 0315 0062;0061 05AE 0300 0310 0315 0062; # (a◌̕◌̀◌֮◌̐b; à◌֮◌̐◌̕b; a◌֮◌̀◌̐◌̕b; à◌֮◌̐◌̕b; a◌֮◌̀◌̐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CANDRABINDU, LATIN SMALL LETTER B +0061 0310 0315 0300 05AE 0062;0061 05AE 0310 0300 0315 0062;0061 05AE 0310 0300 0315 0062;0061 05AE 0310 0300 0315 0062;0061 05AE 0310 0300 0315 0062; # (a◌̐◌̕◌̀◌֮b; a◌֮◌̐◌̀◌̕b; a◌֮◌̐◌̀◌̕b; a◌֮◌̐◌̀◌̕b; a◌֮◌̐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CANDRABINDU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0311 0062;00E0 05AE 0311 0315 0062;0061 05AE 0300 0311 0315 0062;00E0 05AE 0311 0315 0062;0061 05AE 0300 0311 0315 0062; # (a◌̕◌̀◌֮◌̑b; à◌֮◌̑◌̕b; a◌֮◌̀◌̑◌̕b; à◌֮◌̑◌̕b; a◌֮◌̀◌̑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING INVERTED BREVE, LATIN SMALL LETTER B +0061 0311 0315 0300 05AE 0062;0203 05AE 0300 0315 0062;0061 05AE 0311 0300 0315 0062;0203 05AE 0300 0315 0062;0061 05AE 0311 0300 0315 0062; # (a◌̑◌̕◌̀◌֮b; ȃ◌֮◌̀◌̕b; a◌֮◌̑◌̀◌̕b; ȃ◌֮◌̀◌̕b; a◌֮◌̑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING INVERTED BREVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0312 0062;00E0 05AE 0312 0315 0062;0061 05AE 0300 0312 0315 0062;00E0 05AE 0312 0315 0062;0061 05AE 0300 0312 0315 0062; # (a◌̕◌̀◌֮◌̒b; à◌֮◌̒◌̕b; a◌֮◌̀◌̒◌̕b; à◌֮◌̒◌̕b; a◌֮◌̀◌̒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TURNED COMMA ABOVE, LATIN SMALL LETTER B +0061 0312 0315 0300 05AE 0062;0061 05AE 0312 0300 0315 0062;0061 05AE 0312 0300 0315 0062;0061 05AE 0312 0300 0315 0062;0061 05AE 0312 0300 0315 0062; # (a◌̒◌̕◌̀◌֮b; a◌֮◌̒◌̀◌̕b; a◌֮◌̒◌̀◌̕b; a◌֮◌̒◌̀◌̕b; a◌֮◌̒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TURNED COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0313 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062; # (a◌̕◌̀◌֮◌̓b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING COMMA ABOVE, LATIN SMALL LETTER B +0061 0313 0315 0300 05AE 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062; # (a◌̓◌̕◌̀◌֮b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0314 0062;00E0 05AE 0314 0315 0062;0061 05AE 0300 0314 0315 0062;00E0 05AE 0314 0315 0062;0061 05AE 0300 0314 0315 0062; # (a◌̕◌̀◌֮◌̔b; à◌֮◌̔◌̕b; a◌֮◌̀◌̔◌̕b; à◌֮◌̔◌̕b; a◌֮◌̀◌̔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING REVERSED COMMA ABOVE, LATIN SMALL LETTER B +0061 0314 0315 0300 05AE 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062; # (a◌̔◌̕◌̀◌֮b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING REVERSED COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0362 0315 0300 0315 0062;00E0 0315 0315 0362 0062;0061 0300 0315 0315 0362 0062;00E0 0315 0315 0362 0062;0061 0300 0315 0315 0362 0062; # (a◌͢◌̕◌̀◌̕b; à◌̕◌̕◌͢b; a◌̀◌̕◌̕◌͢b; à◌̕◌̕◌͢b; a◌̀◌̕◌̕◌͢b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 0315 0362 0315 0300 0062;00E0 0315 0315 0362 0062;0061 0300 0315 0315 0362 0062;00E0 0315 0315 0362 0062;0061 0300 0315 0315 0362 0062; # (a◌̕◌͢◌̕◌̀b; à◌̕◌̕◌͢b; a◌̀◌̕◌̕◌͢b; à◌̕◌̕◌͢b; a◌̀◌̕◌̕◌͢b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 059A 0316 302A 0316 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062; # (a◌֚◌̖◌〪◌̖b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 0316 059A 0316 302A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062; # (a◌̖◌֚◌̖◌〪b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0317 0062;0061 302A 0316 0317 059A 0062;0061 302A 0316 0317 059A 0062;0061 302A 0316 0317 059A 0062;0061 302A 0316 0317 059A 0062; # (a◌֚◌̖◌〪◌̗b; a◌〪◌̖◌̗◌֚b; a◌〪◌̖◌̗◌֚b; a◌〪◌̖◌̗◌֚b; a◌〪◌̖◌̗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING ACUTE ACCENT BELOW, LATIN SMALL LETTER B +0061 0317 059A 0316 302A 0062;0061 302A 0317 0316 059A 0062;0061 302A 0317 0316 059A 0062;0061 302A 0317 0316 059A 0062;0061 302A 0317 0316 059A 0062; # (a◌̗◌֚◌̖◌〪b; a◌〪◌̗◌̖◌֚b; a◌〪◌̗◌̖◌֚b; a◌〪◌̗◌̖◌֚b; a◌〪◌̗◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ACUTE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0318 0062;0061 302A 0316 0318 059A 0062;0061 302A 0316 0318 059A 0062;0061 302A 0316 0318 059A 0062;0061 302A 0316 0318 059A 0062; # (a◌֚◌̖◌〪◌̘b; a◌〪◌̖◌̘◌֚b; a◌〪◌̖◌̘◌֚b; a◌〪◌̖◌̘◌֚b; a◌〪◌̖◌̘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT TACK BELOW, LATIN SMALL LETTER B +0061 0318 059A 0316 302A 0062;0061 302A 0318 0316 059A 0062;0061 302A 0318 0316 059A 0062;0061 302A 0318 0316 059A 0062;0061 302A 0318 0316 059A 0062; # (a◌̘◌֚◌̖◌〪b; a◌〪◌̘◌̖◌֚b; a◌〪◌̘◌̖◌֚b; a◌〪◌̘◌̖◌֚b; a◌〪◌̘◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0319 0062;0061 302A 0316 0319 059A 0062;0061 302A 0316 0319 059A 0062;0061 302A 0316 0319 059A 0062;0061 302A 0316 0319 059A 0062; # (a◌֚◌̖◌〪◌̙b; a◌〪◌̖◌̙◌֚b; a◌〪◌̖◌̙◌֚b; a◌〪◌̖◌̙◌֚b; a◌〪◌̖◌̙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT TACK BELOW, LATIN SMALL LETTER B +0061 0319 059A 0316 302A 0062;0061 302A 0319 0316 059A 0062;0061 302A 0319 0316 059A 0062;0061 302A 0319 0316 059A 0062;0061 302A 0319 0316 059A 0062; # (a◌̙◌֚◌̖◌〪b; a◌〪◌̙◌̖◌֚b; a◌〪◌̙◌̖◌֚b; a◌〪◌̙◌̖◌֚b; a◌〪◌̙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0362 0315 0300 031A 0062;00E0 0315 031A 0362 0062;0061 0300 0315 031A 0362 0062;00E0 0315 031A 0362 0062;0061 0300 0315 031A 0362 0062; # (a◌͢◌̕◌̀◌̚b; à◌̕◌̚◌͢b; a◌̀◌̕◌̚◌͢b; à◌̕◌̚◌͢b; a◌̀◌̕◌̚◌͢b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING LEFT ANGLE ABOVE, LATIN SMALL LETTER B +0061 031A 0362 0315 0300 0062;00E0 031A 0315 0362 0062;0061 0300 031A 0315 0362 0062;00E0 031A 0315 0362 0062;0061 0300 031A 0315 0362 0062; # (a◌̚◌͢◌̕◌̀b; à◌̚◌̕◌͢b; a◌̀◌̚◌̕◌͢b; à◌̚◌̕◌͢b; a◌̀◌̚◌̕◌͢b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE ABOVE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 302A 031B 0321 031B 0062;0061 0321 031B 031B 302A 0062;0061 0321 031B 031B 302A 0062;0061 0321 031B 031B 302A 0062;0061 0321 031B 031B 302A 0062; # (a◌〪◌̛◌̡◌̛b; a◌̡◌̛◌̛◌〪b; a◌̡◌̛◌̛◌〪b; a◌̡◌̛◌̛◌〪b; a◌̡◌̛◌̛◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, COMBINING HORN, LATIN SMALL LETTER B +0061 031B 302A 031B 0321 0062;0061 0321 031B 031B 302A 0062;0061 0321 031B 031B 302A 0062;0061 0321 031B 031B 302A 0062;0061 0321 031B 031B 302A 0062; # (a◌̛◌〪◌̛◌̡b; a◌̡◌̛◌̛◌〪b; a◌̡◌̛◌̛◌〪b; a◌̡◌̛◌̛◌〪b; a◌̡◌̛◌̛◌〪b; ) LATIN SMALL LETTER A, COMBINING HORN, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 059A 0316 302A 031C 0062;0061 302A 0316 031C 059A 0062;0061 302A 0316 031C 059A 0062;0061 302A 0316 031C 059A 0062;0061 302A 0316 031C 059A 0062; # (a◌֚◌̖◌〪◌̜b; a◌〪◌̖◌̜◌֚b; a◌〪◌̖◌̜◌֚b; a◌〪◌̖◌̜◌֚b; a◌〪◌̖◌̜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT HALF RING BELOW, LATIN SMALL LETTER B +0061 031C 059A 0316 302A 0062;0061 302A 031C 0316 059A 0062;0061 302A 031C 0316 059A 0062;0061 302A 031C 0316 059A 0062;0061 302A 031C 0316 059A 0062; # (a◌̜◌֚◌̖◌〪b; a◌〪◌̜◌̖◌֚b; a◌〪◌̜◌̖◌֚b; a◌〪◌̜◌̖◌֚b; a◌〪◌̜◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 031D 0062;0061 302A 0316 031D 059A 0062;0061 302A 0316 031D 059A 0062;0061 302A 0316 031D 059A 0062;0061 302A 0316 031D 059A 0062; # (a◌֚◌̖◌〪◌̝b; a◌〪◌̖◌̝◌֚b; a◌〪◌̖◌̝◌֚b; a◌〪◌̖◌̝◌֚b; a◌〪◌̖◌̝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING UP TACK BELOW, LATIN SMALL LETTER B +0061 031D 059A 0316 302A 0062;0061 302A 031D 0316 059A 0062;0061 302A 031D 0316 059A 0062;0061 302A 031D 0316 059A 0062;0061 302A 031D 0316 059A 0062; # (a◌̝◌֚◌̖◌〪b; a◌〪◌̝◌̖◌֚b; a◌〪◌̝◌̖◌֚b; a◌〪◌̝◌̖◌֚b; a◌〪◌̝◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UP TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 031E 0062;0061 302A 0316 031E 059A 0062;0061 302A 0316 031E 059A 0062;0061 302A 0316 031E 059A 0062;0061 302A 0316 031E 059A 0062; # (a◌֚◌̖◌〪◌̞b; a◌〪◌̖◌̞◌֚b; a◌〪◌̖◌̞◌֚b; a◌〪◌̖◌̞◌֚b; a◌〪◌̖◌̞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOWN TACK BELOW, LATIN SMALL LETTER B +0061 031E 059A 0316 302A 0062;0061 302A 031E 0316 059A 0062;0061 302A 031E 0316 059A 0062;0061 302A 031E 0316 059A 0062;0061 302A 031E 0316 059A 0062; # (a◌̞◌֚◌̖◌〪b; a◌〪◌̞◌̖◌֚b; a◌〪◌̞◌̖◌֚b; a◌〪◌̞◌̖◌֚b; a◌〪◌̞◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOWN TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 031F 0062;0061 302A 0316 031F 059A 0062;0061 302A 0316 031F 059A 0062;0061 302A 0316 031F 059A 0062;0061 302A 0316 031F 059A 0062; # (a◌֚◌̖◌〪◌̟b; a◌〪◌̖◌̟◌֚b; a◌〪◌̖◌̟◌֚b; a◌〪◌̖◌̟◌֚b; a◌〪◌̖◌̟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING PLUS SIGN BELOW, LATIN SMALL LETTER B +0061 031F 059A 0316 302A 0062;0061 302A 031F 0316 059A 0062;0061 302A 031F 0316 059A 0062;0061 302A 031F 0316 059A 0062;0061 302A 031F 0316 059A 0062; # (a◌̟◌֚◌̖◌〪b; a◌〪◌̟◌̖◌֚b; a◌〪◌̟◌̖◌֚b; a◌〪◌̟◌̖◌֚b; a◌〪◌̟◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PLUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0320 0062;0061 302A 0316 0320 059A 0062;0061 302A 0316 0320 059A 0062;0061 302A 0316 0320 059A 0062;0061 302A 0316 0320 059A 0062; # (a◌֚◌̖◌〪◌̠b; a◌〪◌̖◌̠◌֚b; a◌〪◌̖◌̠◌֚b; a◌〪◌̖◌̠◌֚b; a◌〪◌̖◌̠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING MINUS SIGN BELOW, LATIN SMALL LETTER B +0061 0320 059A 0316 302A 0062;0061 302A 0320 0316 059A 0062;0061 302A 0320 0316 059A 0062;0061 302A 0320 0316 059A 0062;0061 302A 0320 0316 059A 0062; # (a◌̠◌֚◌̖◌〪b; a◌〪◌̠◌̖◌֚b; a◌〪◌̠◌̖◌֚b; a◌〪◌̠◌̖◌֚b; a◌〪◌̠◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MINUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 031B 0321 0F74 0321 0062;0061 0F74 0321 0321 031B 0062;0061 0F74 0321 0321 031B 0062;0061 0F74 0321 0321 031B 0062;0061 0F74 0321 0321 031B 0062; # (a◌̛◌̡◌ུ◌̡b; a◌ུ◌̡◌̡◌̛b; a◌ུ◌̡◌̡◌̛b; a◌ུ◌̡◌̡◌̛b; a◌ུ◌̡◌̡◌̛b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 0321 031B 0321 0F74 0062;0061 0F74 0321 0321 031B 0062;0061 0F74 0321 0321 031B 0062;0061 0F74 0321 0321 031B 0062;0061 0F74 0321 0321 031B 0062; # (a◌̡◌̛◌̡◌ུb; a◌ུ◌̡◌̡◌̛b; a◌ུ◌̡◌̡◌̛b; a◌ུ◌̡◌̡◌̛b; a◌ུ◌̡◌̡◌̛b; ) LATIN SMALL LETTER A, COMBINING PALATALIZED HOOK BELOW, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 031B 0321 0F74 0322 0062;0061 0F74 0321 0322 031B 0062;0061 0F74 0321 0322 031B 0062;0061 0F74 0321 0322 031B 0062;0061 0F74 0321 0322 031B 0062; # (a◌̛◌̡◌ུ◌̢b; a◌ུ◌̡◌̢◌̛b; a◌ུ◌̡◌̢◌̛b; a◌ུ◌̡◌̢◌̛b; a◌ུ◌̡◌̢◌̛b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING RETROFLEX HOOK BELOW, LATIN SMALL LETTER B +0061 0322 031B 0321 0F74 0062;0061 0F74 0322 0321 031B 0062;0061 0F74 0322 0321 031B 0062;0061 0F74 0322 0321 031B 0062;0061 0F74 0322 0321 031B 0062; # (a◌̢◌̛◌̡◌ུb; a◌ུ◌̢◌̡◌̛b; a◌ུ◌̢◌̡◌̛b; a◌ུ◌̢◌̡◌̛b; a◌ུ◌̢◌̡◌̛b; ) LATIN SMALL LETTER A, COMBINING RETROFLEX HOOK BELOW, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 059A 0316 302A 0323 0062;0061 302A 0316 0323 059A 0062;0061 302A 0316 0323 059A 0062;0061 302A 0316 0323 059A 0062;0061 302A 0316 0323 059A 0062; # (a◌֚◌̖◌〪◌̣b; a◌〪◌̖◌̣◌֚b; a◌〪◌̖◌̣◌֚b; a◌〪◌̖◌̣◌֚b; a◌〪◌̖◌̣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 0323 059A 0316 302A 0062;1EA1 302A 0316 059A 0062;0061 302A 0323 0316 059A 0062;1EA1 302A 0316 059A 0062;0061 302A 0323 0316 059A 0062; # (a◌̣◌֚◌̖◌〪b; ạ◌〪◌̖◌֚b; a◌〪◌̣◌̖◌֚b; ạ◌〪◌̖◌֚b; a◌〪◌̣◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0324 0062;0061 302A 0316 0324 059A 0062;0061 302A 0316 0324 059A 0062;0061 302A 0316 0324 059A 0062;0061 302A 0316 0324 059A 0062; # (a◌֚◌̖◌〪◌̤b; a◌〪◌̖◌̤◌֚b; a◌〪◌̖◌̤◌֚b; a◌〪◌̖◌̤◌֚b; a◌〪◌̖◌̤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DIAERESIS BELOW, LATIN SMALL LETTER B +0061 0324 059A 0316 302A 0062;0061 302A 0324 0316 059A 0062;0061 302A 0324 0316 059A 0062;0061 302A 0324 0316 059A 0062;0061 302A 0324 0316 059A 0062; # (a◌̤◌֚◌̖◌〪b; a◌〪◌̤◌̖◌֚b; a◌〪◌̤◌̖◌֚b; a◌〪◌̤◌̖◌֚b; a◌〪◌̤◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0325 0062;0061 302A 0316 0325 059A 0062;0061 302A 0316 0325 059A 0062;0061 302A 0316 0325 059A 0062;0061 302A 0316 0325 059A 0062; # (a◌֚◌̖◌〪◌̥b; a◌〪◌̖◌̥◌֚b; a◌〪◌̖◌̥◌֚b; a◌〪◌̖◌̥◌֚b; a◌〪◌̖◌̥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RING BELOW, LATIN SMALL LETTER B +0061 0325 059A 0316 302A 0062;1E01 302A 0316 059A 0062;0061 302A 0325 0316 059A 0062;1E01 302A 0316 059A 0062;0061 302A 0325 0316 059A 0062; # (a◌̥◌֚◌̖◌〪b; ḁ◌〪◌̖◌֚b; a◌〪◌̥◌̖◌֚b; ḁ◌〪◌̖◌֚b; a◌〪◌̥◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0326 0062;0061 302A 0316 0326 059A 0062;0061 302A 0316 0326 059A 0062;0061 302A 0316 0326 059A 0062;0061 302A 0316 0326 059A 0062; # (a◌֚◌̖◌〪◌̦b; a◌〪◌̖◌̦◌֚b; a◌〪◌̖◌̦◌֚b; a◌〪◌̖◌̦◌֚b; a◌〪◌̖◌̦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING COMMA BELOW, LATIN SMALL LETTER B +0061 0326 059A 0316 302A 0062;0061 302A 0326 0316 059A 0062;0061 302A 0326 0316 059A 0062;0061 302A 0326 0316 059A 0062;0061 302A 0326 0316 059A 0062; # (a◌̦◌֚◌̖◌〪b; a◌〪◌̦◌̖◌֚b; a◌〪◌̦◌̖◌֚b; a◌〪◌̦◌̖◌֚b; a◌〪◌̦◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING COMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 031B 0321 0F74 0327 0062;0061 0F74 0321 0327 031B 0062;0061 0F74 0321 0327 031B 0062;0061 0F74 0321 0327 031B 0062;0061 0F74 0321 0327 031B 0062; # (a◌̛◌̡◌ུ◌̧b; a◌ུ◌̡◌̧◌̛b; a◌ུ◌̡◌̧◌̛b; a◌ུ◌̡◌̧◌̛b; a◌ུ◌̡◌̧◌̛b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING CEDILLA, LATIN SMALL LETTER B +0061 0327 031B 0321 0F74 0062;0061 0F74 0327 0321 031B 0062;0061 0F74 0327 0321 031B 0062;0061 0F74 0327 0321 031B 0062;0061 0F74 0327 0321 031B 0062; # (a◌̧◌̛◌̡◌ུb; a◌ུ◌̧◌̡◌̛b; a◌ུ◌̧◌̡◌̛b; a◌ུ◌̧◌̡◌̛b; a◌ུ◌̧◌̡◌̛b; ) LATIN SMALL LETTER A, COMBINING CEDILLA, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 031B 0321 0F74 0328 0062;0061 0F74 0321 0328 031B 0062;0061 0F74 0321 0328 031B 0062;0061 0F74 0321 0328 031B 0062;0061 0F74 0321 0328 031B 0062; # (a◌̛◌̡◌ུ◌̨b; a◌ུ◌̡◌̨◌̛b; a◌ུ◌̡◌̨◌̛b; a◌ུ◌̡◌̨◌̛b; a◌ུ◌̡◌̨◌̛b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING OGONEK, LATIN SMALL LETTER B +0061 0328 031B 0321 0F74 0062;0105 0F74 0321 031B 0062;0061 0F74 0328 0321 031B 0062;0105 0F74 0321 031B 0062;0061 0F74 0328 0321 031B 0062; # (a◌̨◌̛◌̡◌ུb; ą◌ུ◌̡◌̛b; a◌ུ◌̨◌̡◌̛b; ą◌ུ◌̡◌̛b; a◌ུ◌̨◌̡◌̛b; ) LATIN SMALL LETTER A, COMBINING OGONEK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 059A 0316 302A 0329 0062;0061 302A 0316 0329 059A 0062;0061 302A 0316 0329 059A 0062;0061 302A 0316 0329 059A 0062;0061 302A 0316 0329 059A 0062; # (a◌֚◌̖◌〪◌̩b; a◌〪◌̖◌̩◌֚b; a◌〪◌̖◌̩◌֚b; a◌〪◌̖◌̩◌֚b; a◌〪◌̖◌̩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING VERTICAL LINE BELOW, LATIN SMALL LETTER B +0061 0329 059A 0316 302A 0062;0061 302A 0329 0316 059A 0062;0061 302A 0329 0316 059A 0062;0061 302A 0329 0316 059A 0062;0061 302A 0329 0316 059A 0062; # (a◌̩◌֚◌̖◌〪b; a◌〪◌̩◌̖◌֚b; a◌〪◌̩◌̖◌֚b; a◌〪◌̩◌̖◌֚b; a◌〪◌̩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 032A 0062;0061 302A 0316 032A 059A 0062;0061 302A 0316 032A 059A 0062;0061 302A 0316 032A 059A 0062;0061 302A 0316 032A 059A 0062; # (a◌֚◌̖◌〪◌̪b; a◌〪◌̖◌̪◌֚b; a◌〪◌̖◌̪◌֚b; a◌〪◌̖◌̪◌֚b; a◌〪◌̖◌̪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING BRIDGE BELOW, LATIN SMALL LETTER B +0061 032A 059A 0316 302A 0062;0061 302A 032A 0316 059A 0062;0061 302A 032A 0316 059A 0062;0061 302A 032A 0316 059A 0062;0061 302A 032A 0316 059A 0062; # (a◌̪◌֚◌̖◌〪b; a◌〪◌̪◌̖◌֚b; a◌〪◌̪◌̖◌֚b; a◌〪◌̪◌̖◌֚b; a◌〪◌̪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 032B 0062;0061 302A 0316 032B 059A 0062;0061 302A 0316 032B 059A 0062;0061 302A 0316 032B 059A 0062;0061 302A 0316 032B 059A 0062; # (a◌֚◌̖◌〪◌̫b; a◌〪◌̖◌̫◌֚b; a◌〪◌̖◌̫◌֚b; a◌〪◌̖◌̫◌֚b; a◌〪◌̖◌̫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING INVERTED DOUBLE ARCH BELOW, LATIN SMALL LETTER B +0061 032B 059A 0316 302A 0062;0061 302A 032B 0316 059A 0062;0061 302A 032B 0316 059A 0062;0061 302A 032B 0316 059A 0062;0061 302A 032B 0316 059A 0062; # (a◌̫◌֚◌̖◌〪b; a◌〪◌̫◌̖◌֚b; a◌〪◌̫◌̖◌֚b; a◌〪◌̫◌̖◌֚b; a◌〪◌̫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED DOUBLE ARCH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 032C 0062;0061 302A 0316 032C 059A 0062;0061 302A 0316 032C 059A 0062;0061 302A 0316 032C 059A 0062;0061 302A 0316 032C 059A 0062; # (a◌֚◌̖◌〪◌̬b; a◌〪◌̖◌̬◌֚b; a◌〪◌̖◌̬◌֚b; a◌〪◌̖◌̬◌֚b; a◌〪◌̖◌̬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING CARON BELOW, LATIN SMALL LETTER B +0061 032C 059A 0316 302A 0062;0061 302A 032C 0316 059A 0062;0061 302A 032C 0316 059A 0062;0061 302A 032C 0316 059A 0062;0061 302A 032C 0316 059A 0062; # (a◌̬◌֚◌̖◌〪b; a◌〪◌̬◌̖◌֚b; a◌〪◌̬◌̖◌֚b; a◌〪◌̬◌̖◌֚b; a◌〪◌̬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CARON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 032D 0062;0061 302A 0316 032D 059A 0062;0061 302A 0316 032D 059A 0062;0061 302A 0316 032D 059A 0062;0061 302A 0316 032D 059A 0062; # (a◌֚◌̖◌〪◌̭b; a◌〪◌̖◌̭◌֚b; a◌〪◌̖◌̭◌֚b; a◌〪◌̖◌̭◌֚b; a◌〪◌̖◌̭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING CIRCUMFLEX ACCENT BELOW, LATIN SMALL LETTER B +0061 032D 059A 0316 302A 0062;0061 302A 032D 0316 059A 0062;0061 302A 032D 0316 059A 0062;0061 302A 032D 0316 059A 0062;0061 302A 032D 0316 059A 0062; # (a◌̭◌֚◌̖◌〪b; a◌〪◌̭◌̖◌֚b; a◌〪◌̭◌̖◌֚b; a◌〪◌̭◌̖◌֚b; a◌〪◌̭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CIRCUMFLEX ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 032E 0062;0061 302A 0316 032E 059A 0062;0061 302A 0316 032E 059A 0062;0061 302A 0316 032E 059A 0062;0061 302A 0316 032E 059A 0062; # (a◌֚◌̖◌〪◌̮b; a◌〪◌̖◌̮◌֚b; a◌〪◌̖◌̮◌֚b; a◌〪◌̖◌̮◌֚b; a◌〪◌̖◌̮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING BREVE BELOW, LATIN SMALL LETTER B +0061 032E 059A 0316 302A 0062;0061 302A 032E 0316 059A 0062;0061 302A 032E 0316 059A 0062;0061 302A 032E 0316 059A 0062;0061 302A 032E 0316 059A 0062; # (a◌̮◌֚◌̖◌〪b; a◌〪◌̮◌̖◌֚b; a◌〪◌̮◌̖◌֚b; a◌〪◌̮◌̖◌֚b; a◌〪◌̮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 032F 0062;0061 302A 0316 032F 059A 0062;0061 302A 0316 032F 059A 0062;0061 302A 0316 032F 059A 0062;0061 302A 0316 032F 059A 0062; # (a◌֚◌̖◌〪◌̯b; a◌〪◌̖◌̯◌֚b; a◌〪◌̖◌̯◌֚b; a◌〪◌̖◌̯◌֚b; a◌〪◌̖◌̯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING INVERTED BREVE BELOW, LATIN SMALL LETTER B +0061 032F 059A 0316 302A 0062;0061 302A 032F 0316 059A 0062;0061 302A 032F 0316 059A 0062;0061 302A 032F 0316 059A 0062;0061 302A 032F 0316 059A 0062; # (a◌̯◌֚◌̖◌〪b; a◌〪◌̯◌̖◌֚b; a◌〪◌̯◌̖◌֚b; a◌〪◌̯◌̖◌֚b; a◌〪◌̯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0330 0062;0061 302A 0316 0330 059A 0062;0061 302A 0316 0330 059A 0062;0061 302A 0316 0330 059A 0062;0061 302A 0316 0330 059A 0062; # (a◌֚◌̖◌〪◌̰b; a◌〪◌̖◌̰◌֚b; a◌〪◌̖◌̰◌֚b; a◌〪◌̖◌̰◌֚b; a◌〪◌̖◌̰◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING TILDE BELOW, LATIN SMALL LETTER B +0061 0330 059A 0316 302A 0062;0061 302A 0330 0316 059A 0062;0061 302A 0330 0316 059A 0062;0061 302A 0330 0316 059A 0062;0061 302A 0330 0316 059A 0062; # (a◌̰◌֚◌̖◌〪b; a◌〪◌̰◌̖◌֚b; a◌〪◌̰◌̖◌֚b; a◌〪◌̰◌̖◌֚b; a◌〪◌̰◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0331 0062;0061 302A 0316 0331 059A 0062;0061 302A 0316 0331 059A 0062;0061 302A 0316 0331 059A 0062;0061 302A 0316 0331 059A 0062; # (a◌֚◌̖◌〪◌̱b; a◌〪◌̖◌̱◌֚b; a◌〪◌̖◌̱◌֚b; a◌〪◌̖◌̱◌֚b; a◌〪◌̖◌̱◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING MACRON BELOW, LATIN SMALL LETTER B +0061 0331 059A 0316 302A 0062;0061 302A 0331 0316 059A 0062;0061 302A 0331 0316 059A 0062;0061 302A 0331 0316 059A 0062;0061 302A 0331 0316 059A 0062; # (a◌̱◌֚◌̖◌〪b; a◌〪◌̱◌̖◌֚b; a◌〪◌̱◌̖◌֚b; a◌〪◌̱◌̖◌֚b; a◌〪◌̱◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0332 0062;0061 302A 0316 0332 059A 0062;0061 302A 0316 0332 059A 0062;0061 302A 0316 0332 059A 0062;0061 302A 0316 0332 059A 0062; # (a◌֚◌̖◌〪◌̲b; a◌〪◌̖◌̲◌֚b; a◌〪◌̖◌̲◌֚b; a◌〪◌̖◌̲◌֚b; a◌〪◌̖◌̲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LOW LINE, LATIN SMALL LETTER B +0061 0332 059A 0316 302A 0062;0061 302A 0332 0316 059A 0062;0061 302A 0332 0316 059A 0062;0061 302A 0332 0316 059A 0062;0061 302A 0332 0316 059A 0062; # (a◌̲◌֚◌̖◌〪b; a◌〪◌̲◌̖◌֚b; a◌〪◌̲◌̖◌֚b; a◌〪◌̲◌̖◌֚b; a◌〪◌̲◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0333 0062;0061 302A 0316 0333 059A 0062;0061 302A 0316 0333 059A 0062;0061 302A 0316 0333 059A 0062;0061 302A 0316 0333 059A 0062; # (a◌֚◌̖◌〪◌̳b; a◌〪◌̖◌̳◌֚b; a◌〪◌̖◌̳◌֚b; a◌〪◌̖◌̳◌֚b; a◌〪◌̖◌̳◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOUBLE LOW LINE, LATIN SMALL LETTER B +0061 0333 059A 0316 302A 0062;0061 302A 0333 0316 059A 0062;0061 302A 0333 0316 059A 0062;0061 302A 0333 0316 059A 0062;0061 302A 0333 0316 059A 0062; # (a◌̳◌֚◌̖◌〪b; a◌〪◌̳◌̖◌֚b; a◌〪◌̳◌̖◌֚b; a◌〪◌̳◌̖◌֚b; a◌〪◌̳◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 093C 0334 0334 0062;0061 0334 0334 093C 0062;0061 0334 0334 093C 0062;0061 0334 0334 093C 0062;0061 0334 0334 093C 0062; # (a◌़◌̴◌̴b; a◌̴◌̴◌़b; a◌̴◌̴◌़b; a◌̴◌̴◌़b; a◌̴◌̴◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0334 093C 0334 0062;0061 0334 0334 093C 0062;0061 0334 0334 093C 0062;0061 0334 0334 093C 0062;0061 0334 0334 093C 0062; # (a◌̴◌़◌̴b; a◌̴◌̴◌़b; a◌̴◌̴◌़b; a◌̴◌̴◌़b; a◌̴◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING TILDE OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 0335 0062;0061 0334 0335 093C 0062;0061 0334 0335 093C 0062;0061 0334 0335 093C 0062;0061 0334 0335 093C 0062; # (a◌़◌̴◌̵b; a◌̴◌̵◌़b; a◌̴◌̵◌़b; a◌̴◌̵◌़b; a◌̴◌̵◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING SHORT STROKE OVERLAY, LATIN SMALL LETTER B +0061 0335 093C 0334 0062;0061 0335 0334 093C 0062;0061 0335 0334 093C 0062;0061 0335 0334 093C 0062;0061 0335 0334 093C 0062; # (a◌̵◌़◌̴b; a◌̵◌̴◌़b; a◌̵◌̴◌़b; a◌̵◌̴◌़b; a◌̵◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING SHORT STROKE OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 0336 0062;0061 0334 0336 093C 0062;0061 0334 0336 093C 0062;0061 0334 0336 093C 0062;0061 0334 0336 093C 0062; # (a◌़◌̴◌̶b; a◌̴◌̶◌़b; a◌̴◌̶◌़b; a◌̴◌̶◌़b; a◌̴◌̶◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING LONG STROKE OVERLAY, LATIN SMALL LETTER B +0061 0336 093C 0334 0062;0061 0336 0334 093C 0062;0061 0336 0334 093C 0062;0061 0336 0334 093C 0062;0061 0336 0334 093C 0062; # (a◌̶◌़◌̴b; a◌̶◌̴◌़b; a◌̶◌̴◌़b; a◌̶◌̴◌़b; a◌̶◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING LONG STROKE OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 0337 0062;0061 0334 0337 093C 0062;0061 0334 0337 093C 0062;0061 0334 0337 093C 0062;0061 0334 0337 093C 0062; # (a◌़◌̴◌̷b; a◌̴◌̷◌़b; a◌̴◌̷◌़b; a◌̴◌̷◌़b; a◌̴◌̷◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING SHORT SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 0337 093C 0334 0062;0061 0337 0334 093C 0062;0061 0337 0334 093C 0062;0061 0337 0334 093C 0062;0061 0337 0334 093C 0062; # (a◌̷◌़◌̴b; a◌̷◌̴◌़b; a◌̷◌̴◌़b; a◌̷◌̴◌़b; a◌̷◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING SHORT SOLIDUS OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 0338 0062;0061 0334 0338 093C 0062;0061 0334 0338 093C 0062;0061 0334 0338 093C 0062;0061 0334 0338 093C 0062; # (a◌़◌̴◌̸b; a◌̴◌̸◌़b; a◌̴◌̸◌़b; a◌̴◌̸◌़b; a◌̴◌̸◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING LONG SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 0338 093C 0334 0062;0061 0338 0334 093C 0062;0061 0338 0334 093C 0062;0061 0338 0334 093C 0062;0061 0338 0334 093C 0062; # (a◌̸◌़◌̴b; a◌̸◌̴◌़b; a◌̸◌̴◌़b; a◌̸◌̴◌़b; a◌̸◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING LONG SOLIDUS OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 059A 0316 302A 0339 0062;0061 302A 0316 0339 059A 0062;0061 302A 0316 0339 059A 0062;0061 302A 0316 0339 059A 0062;0061 302A 0316 0339 059A 0062; # (a◌֚◌̖◌〪◌̹b; a◌〪◌̖◌̹◌֚b; a◌〪◌̖◌̹◌֚b; a◌〪◌̖◌̹◌֚b; a◌〪◌̖◌̹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT HALF RING BELOW, LATIN SMALL LETTER B +0061 0339 059A 0316 302A 0062;0061 302A 0339 0316 059A 0062;0061 302A 0339 0316 059A 0062;0061 302A 0339 0316 059A 0062;0061 302A 0339 0316 059A 0062; # (a◌̹◌֚◌̖◌〪b; a◌〪◌̹◌̖◌֚b; a◌〪◌̹◌̖◌֚b; a◌〪◌̹◌̖◌֚b; a◌〪◌̹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 033A 0062;0061 302A 0316 033A 059A 0062;0061 302A 0316 033A 059A 0062;0061 302A 0316 033A 059A 0062;0061 302A 0316 033A 059A 0062; # (a◌֚◌̖◌〪◌̺b; a◌〪◌̖◌̺◌֚b; a◌〪◌̖◌̺◌֚b; a◌〪◌̖◌̺◌֚b; a◌〪◌̖◌̺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING INVERTED BRIDGE BELOW, LATIN SMALL LETTER B +0061 033A 059A 0316 302A 0062;0061 302A 033A 0316 059A 0062;0061 302A 033A 0316 059A 0062;0061 302A 033A 0316 059A 0062;0061 302A 033A 0316 059A 0062; # (a◌̺◌֚◌̖◌〪b; a◌〪◌̺◌̖◌֚b; a◌〪◌̺◌̖◌֚b; a◌〪◌̺◌̖◌֚b; a◌〪◌̺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 033B 0062;0061 302A 0316 033B 059A 0062;0061 302A 0316 033B 059A 0062;0061 302A 0316 033B 059A 0062;0061 302A 0316 033B 059A 0062; # (a◌֚◌̖◌〪◌̻b; a◌〪◌̖◌̻◌֚b; a◌〪◌̖◌̻◌֚b; a◌〪◌̖◌̻◌֚b; a◌〪◌̖◌̻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING SQUARE BELOW, LATIN SMALL LETTER B +0061 033B 059A 0316 302A 0062;0061 302A 033B 0316 059A 0062;0061 302A 033B 0316 059A 0062;0061 302A 033B 0316 059A 0062;0061 302A 033B 0316 059A 0062; # (a◌̻◌֚◌̖◌〪b; a◌〪◌̻◌̖◌֚b; a◌〪◌̻◌̖◌֚b; a◌〪◌̻◌̖◌֚b; a◌〪◌̻◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SQUARE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 033C 0062;0061 302A 0316 033C 059A 0062;0061 302A 0316 033C 059A 0062;0061 302A 0316 033C 059A 0062;0061 302A 0316 033C 059A 0062; # (a◌֚◌̖◌〪◌̼b; a◌〪◌̖◌̼◌֚b; a◌〪◌̖◌̼◌֚b; a◌〪◌̖◌̼◌֚b; a◌〪◌̖◌̼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING SEAGULL BELOW, LATIN SMALL LETTER B +0061 033C 059A 0316 302A 0062;0061 302A 033C 0316 059A 0062;0061 302A 033C 0316 059A 0062;0061 302A 033C 0316 059A 0062;0061 302A 033C 0316 059A 0062; # (a◌̼◌֚◌̖◌〪b; a◌〪◌̼◌̖◌֚b; a◌〪◌̼◌̖◌֚b; a◌〪◌̼◌̖◌֚b; a◌〪◌̼◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SEAGULL BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 033D 0062;00E0 05AE 033D 0315 0062;0061 05AE 0300 033D 0315 0062;00E0 05AE 033D 0315 0062;0061 05AE 0300 033D 0315 0062; # (a◌̕◌̀◌֮◌̽b; à◌֮◌̽◌̕b; a◌֮◌̀◌̽◌̕b; à◌֮◌̽◌̕b; a◌֮◌̀◌̽◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING X ABOVE, LATIN SMALL LETTER B +0061 033D 0315 0300 05AE 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062; # (a◌̽◌̕◌̀◌֮b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING X ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 033E 0062;00E0 05AE 033E 0315 0062;0061 05AE 0300 033E 0315 0062;00E0 05AE 033E 0315 0062;0061 05AE 0300 033E 0315 0062; # (a◌̕◌̀◌֮◌̾b; à◌֮◌̾◌̕b; a◌֮◌̀◌̾◌̕b; à◌֮◌̾◌̕b; a◌֮◌̀◌̾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING VERTICAL TILDE, LATIN SMALL LETTER B +0061 033E 0315 0300 05AE 0062;0061 05AE 033E 0300 0315 0062;0061 05AE 033E 0300 0315 0062;0061 05AE 033E 0300 0315 0062;0061 05AE 033E 0300 0315 0062; # (a◌̾◌̕◌̀◌֮b; a◌֮◌̾◌̀◌̕b; a◌֮◌̾◌̀◌̕b; a◌֮◌̾◌̀◌̕b; a◌֮◌̾◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING VERTICAL TILDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 033F 0062;00E0 05AE 033F 0315 0062;0061 05AE 0300 033F 0315 0062;00E0 05AE 033F 0315 0062;0061 05AE 0300 033F 0315 0062; # (a◌̕◌̀◌֮◌̿b; à◌֮◌̿◌̕b; a◌֮◌̀◌̿◌̕b; à◌֮◌̿◌̕b; a◌֮◌̀◌̿◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE OVERLINE, LATIN SMALL LETTER B +0061 033F 0315 0300 05AE 0062;0061 05AE 033F 0300 0315 0062;0061 05AE 033F 0300 0315 0062;0061 05AE 033F 0300 0315 0062;0061 05AE 033F 0300 0315 0062; # (a◌̿◌̕◌̀◌֮b; a◌֮◌̿◌̀◌̕b; a◌֮◌̿◌̀◌̕b; a◌֮◌̿◌̀◌̕b; a◌֮◌̿◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE OVERLINE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0340 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̕◌̀◌֮◌̀b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRAVE TONE MARK, LATIN SMALL LETTER B +0061 0340 0315 0300 05AE 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̀◌̕◌̀◌֮b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE TONE MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0341 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062; # (a◌̕◌̀◌֮◌́b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE TONE MARK, LATIN SMALL LETTER B +0061 0341 0315 0300 05AE 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062; # (a◌́◌̕◌̀◌֮b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE TONE MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0342 0062;00E0 05AE 0342 0315 0062;0061 05AE 0300 0342 0315 0062;00E0 05AE 0342 0315 0062;0061 05AE 0300 0342 0315 0062; # (a◌̕◌̀◌֮◌͂b; à◌֮◌͂◌̕b; a◌֮◌̀◌͂◌̕b; à◌֮◌͂◌̕b; a◌֮◌̀◌͂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK PERISPOMENI, LATIN SMALL LETTER B +0061 0342 0315 0300 05AE 0062;0061 05AE 0342 0300 0315 0062;0061 05AE 0342 0300 0315 0062;0061 05AE 0342 0300 0315 0062;0061 05AE 0342 0300 0315 0062; # (a◌͂◌̕◌̀◌֮b; a◌֮◌͂◌̀◌̕b; a◌֮◌͂◌̀◌̕b; a◌֮◌͂◌̀◌̕b; a◌֮◌͂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK PERISPOMENI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0343 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062; # (a◌̕◌̀◌֮◌̓b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK KORONIS, LATIN SMALL LETTER B +0061 0343 0315 0300 05AE 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062; # (a◌̓◌̕◌̀◌֮b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK KORONIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0344 0062;00E0 05AE 0308 0301 0315 0062;0061 05AE 0300 0308 0301 0315 0062;00E0 05AE 0308 0301 0315 0062;0061 05AE 0300 0308 0301 0315 0062; # (a◌̕◌̀◌֮◌̈́b; à◌֮◌̈◌́◌̕b; a◌֮◌̀◌̈◌́◌̕b; à◌֮◌̈◌́◌̕b; a◌֮◌̀◌̈◌́◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK DIALYTIKA TONOS, LATIN SMALL LETTER B +0061 0344 0315 0300 05AE 0062;00E4 05AE 0301 0300 0315 0062;0061 05AE 0308 0301 0300 0315 0062;00E4 05AE 0301 0300 0315 0062;0061 05AE 0308 0301 0300 0315 0062; # (a◌̈́◌̕◌̀◌֮b; ä◌֮◌́◌̀◌̕b; a◌֮◌̈◌́◌̀◌̕b; ä◌֮◌́◌̀◌̕b; a◌֮◌̈◌́◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK DIALYTIKA TONOS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0345 0360 0345 0062;0061 0360 0345 0345 0062;0061 0360 0345 0345 0062;0061 0360 0345 0345 0062;0061 0360 0345 0345 0062; # (a◌ͅ◌͠◌ͅb; a◌͠◌ͅ◌ͅb; a◌͠◌ͅ◌ͅb; a◌͠◌ͅ◌ͅb; a◌͠◌ͅ◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE TILDE, COMBINING GREEK YPOGEGRAMMENI, LATIN SMALL LETTER B +0061 0345 0345 0360 0062;0061 0360 0345 0345 0062;0061 0360 0345 0345 0062;0061 0360 0345 0345 0062;0061 0360 0345 0345 0062; # (a◌ͅ◌ͅ◌͠b; a◌͠◌ͅ◌ͅb; a◌͠◌ͅ◌ͅb; a◌͠◌ͅ◌ͅb; a◌͠◌ͅ◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE TILDE, LATIN SMALL LETTER B +0061 0315 0300 05AE 0346 0062;00E0 05AE 0346 0315 0062;0061 05AE 0300 0346 0315 0062;00E0 05AE 0346 0315 0062;0061 05AE 0300 0346 0315 0062; # (a◌̕◌̀◌֮◌͆b; à◌֮◌͆◌̕b; a◌֮◌̀◌͆◌̕b; à◌֮◌͆◌̕b; a◌֮◌̀◌͆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BRIDGE ABOVE, LATIN SMALL LETTER B +0061 0346 0315 0300 05AE 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062; # (a◌͆◌̕◌̀◌֮b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BRIDGE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0347 0062;0061 302A 0316 0347 059A 0062;0061 302A 0316 0347 059A 0062;0061 302A 0316 0347 059A 0062;0061 302A 0316 0347 059A 0062; # (a◌֚◌̖◌〪◌͇b; a◌〪◌̖◌͇◌֚b; a◌〪◌̖◌͇◌֚b; a◌〪◌̖◌͇◌֚b; a◌〪◌̖◌͇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING EQUALS SIGN BELOW, LATIN SMALL LETTER B +0061 0347 059A 0316 302A 0062;0061 302A 0347 0316 059A 0062;0061 302A 0347 0316 059A 0062;0061 302A 0347 0316 059A 0062;0061 302A 0347 0316 059A 0062; # (a◌͇◌֚◌̖◌〪b; a◌〪◌͇◌̖◌֚b; a◌〪◌͇◌̖◌֚b; a◌〪◌͇◌̖◌֚b; a◌〪◌͇◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING EQUALS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0348 0062;0061 302A 0316 0348 059A 0062;0061 302A 0316 0348 059A 0062;0061 302A 0316 0348 059A 0062;0061 302A 0316 0348 059A 0062; # (a◌֚◌̖◌〪◌͈b; a◌〪◌̖◌͈◌֚b; a◌〪◌̖◌͈◌֚b; a◌〪◌̖◌͈◌֚b; a◌〪◌̖◌͈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOUBLE VERTICAL LINE BELOW, LATIN SMALL LETTER B +0061 0348 059A 0316 302A 0062;0061 302A 0348 0316 059A 0062;0061 302A 0348 0316 059A 0062;0061 302A 0348 0316 059A 0062;0061 302A 0348 0316 059A 0062; # (a◌͈◌֚◌̖◌〪b; a◌〪◌͈◌̖◌֚b; a◌〪◌͈◌̖◌֚b; a◌〪◌͈◌̖◌֚b; a◌〪◌͈◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0349 0062;0061 302A 0316 0349 059A 0062;0061 302A 0316 0349 059A 0062;0061 302A 0316 0349 059A 0062;0061 302A 0316 0349 059A 0062; # (a◌֚◌̖◌〪◌͉b; a◌〪◌̖◌͉◌֚b; a◌〪◌̖◌͉◌֚b; a◌〪◌̖◌͉◌֚b; a◌〪◌̖◌͉◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT ANGLE BELOW, LATIN SMALL LETTER B +0061 0349 059A 0316 302A 0062;0061 302A 0349 0316 059A 0062;0061 302A 0349 0316 059A 0062;0061 302A 0349 0316 059A 0062;0061 302A 0349 0316 059A 0062; # (a◌͉◌֚◌̖◌〪b; a◌〪◌͉◌̖◌֚b; a◌〪◌͉◌̖◌֚b; a◌〪◌͉◌̖◌֚b; a◌〪◌͉◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 034A 0062;00E0 05AE 034A 0315 0062;0061 05AE 0300 034A 0315 0062;00E0 05AE 034A 0315 0062;0061 05AE 0300 034A 0315 0062; # (a◌̕◌̀◌֮◌͊b; à◌֮◌͊◌̕b; a◌֮◌̀◌͊◌̕b; à◌֮◌͊◌̕b; a◌֮◌̀◌͊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING NOT TILDE ABOVE, LATIN SMALL LETTER B +0061 034A 0315 0300 05AE 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062; # (a◌͊◌̕◌̀◌֮b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING NOT TILDE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 034B 0062;00E0 05AE 034B 0315 0062;0061 05AE 0300 034B 0315 0062;00E0 05AE 034B 0315 0062;0061 05AE 0300 034B 0315 0062; # (a◌̕◌̀◌֮◌͋b; à◌֮◌͋◌̕b; a◌֮◌̀◌͋◌̕b; à◌֮◌͋◌̕b; a◌֮◌̀◌͋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING HOMOTHETIC ABOVE, LATIN SMALL LETTER B +0061 034B 0315 0300 05AE 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062; # (a◌͋◌̕◌̀◌֮b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING HOMOTHETIC ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 034C 0062;00E0 05AE 034C 0315 0062;0061 05AE 0300 034C 0315 0062;00E0 05AE 034C 0315 0062;0061 05AE 0300 034C 0315 0062; # (a◌̕◌̀◌֮◌͌b; à◌֮◌͌◌̕b; a◌֮◌̀◌͌◌̕b; à◌֮◌͌◌̕b; a◌֮◌̀◌͌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ALMOST EQUAL TO ABOVE, LATIN SMALL LETTER B +0061 034C 0315 0300 05AE 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062; # (a◌͌◌̕◌̀◌֮b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ALMOST EQUAL TO ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 034D 0062;0061 302A 0316 034D 059A 0062;0061 302A 0316 034D 059A 0062;0061 302A 0316 034D 059A 0062;0061 302A 0316 034D 059A 0062; # (a◌֚◌̖◌〪◌͍b; a◌〪◌̖◌͍◌֚b; a◌〪◌̖◌͍◌֚b; a◌〪◌̖◌͍◌֚b; a◌〪◌̖◌͍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT RIGHT ARROW BELOW, LATIN SMALL LETTER B +0061 034D 059A 0316 302A 0062;0061 302A 034D 0316 059A 0062;0061 302A 034D 0316 059A 0062;0061 302A 034D 0316 059A 0062;0061 302A 034D 0316 059A 0062; # (a◌͍◌֚◌̖◌〪b; a◌〪◌͍◌̖◌֚b; a◌〪◌͍◌̖◌֚b; a◌〪◌͍◌̖◌֚b; a◌〪◌͍◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 034E 0062;0061 302A 0316 034E 059A 0062;0061 302A 0316 034E 059A 0062;0061 302A 0316 034E 059A 0062;0061 302A 0316 034E 059A 0062; # (a◌֚◌̖◌〪◌͎b; a◌〪◌̖◌͎◌֚b; a◌〪◌̖◌͎◌֚b; a◌〪◌̖◌͎◌֚b; a◌〪◌̖◌͎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING UPWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 034E 059A 0316 302A 0062;0061 302A 034E 0316 059A 0062;0061 302A 034E 0316 059A 0062;0061 302A 034E 0316 059A 0062;0061 302A 034E 0316 059A 0062; # (a◌͎◌֚◌̖◌〪b; a◌〪◌͎◌̖◌֚b; a◌〪◌͎◌̖◌֚b; a◌〪◌͎◌̖◌֚b; a◌〪◌͎◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UPWARDS ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0345 0360 0362 0360 0062;0061 0362 0360 0360 0345 0062;0061 0362 0360 0360 0345 0062;0061 0362 0360 0360 0345 0062;0061 0362 0360 0360 0345 0062; # (a◌ͅ◌͠◌͢◌͠b; a◌͢◌͠◌͠◌ͅb; a◌͢◌͠◌͠◌ͅb; a◌͢◌͠◌͠◌ͅb; a◌͢◌͠◌͠◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE TILDE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING DOUBLE TILDE, LATIN SMALL LETTER B +0061 0360 0345 0360 0362 0062;0061 0362 0360 0360 0345 0062;0061 0362 0360 0360 0345 0062;0061 0362 0360 0360 0345 0062;0061 0362 0360 0360 0345 0062; # (a◌͠◌ͅ◌͠◌͢b; a◌͢◌͠◌͠◌ͅb; a◌͢◌͠◌͠◌ͅb; a◌͢◌͠◌͠◌ͅb; a◌͢◌͠◌͠◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE TILDE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 0345 0360 0362 0361 0062;0061 0362 0360 0361 0345 0062;0061 0362 0360 0361 0345 0062;0061 0362 0360 0361 0345 0062;0061 0362 0360 0361 0345 0062; # (a◌ͅ◌͠◌͢◌͡b; a◌͢◌͠◌͡◌ͅb; a◌͢◌͠◌͡◌ͅb; a◌͢◌͠◌͡◌ͅb; a◌͢◌͠◌͡◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE TILDE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING DOUBLE INVERTED BREVE, LATIN SMALL LETTER B +0061 0361 0345 0360 0362 0062;0061 0362 0361 0360 0345 0062;0061 0362 0361 0360 0345 0062;0061 0362 0361 0360 0345 0062;0061 0362 0361 0360 0345 0062; # (a◌͡◌ͅ◌͠◌͢b; a◌͢◌͡◌͠◌ͅb; a◌͢◌͡◌͠◌ͅb; a◌͢◌͡◌͠◌ͅb; a◌͢◌͡◌͠◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE INVERTED BREVE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE TILDE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 0360 0362 0315 0362 0062;0061 0315 0362 0362 0360 0062;0061 0315 0362 0362 0360 0062;0061 0315 0362 0362 0360 0062;0061 0315 0362 0362 0360 0062; # (a◌͠◌͢◌̕◌͢b; a◌̕◌͢◌͢◌͠b; a◌̕◌͢◌͢◌͠b; a◌̕◌͢◌͢◌͠b; a◌̕◌͢◌͢◌͠b; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 0362 0360 0362 0315 0062;0061 0315 0362 0362 0360 0062;0061 0315 0362 0362 0360 0062;0061 0315 0362 0362 0360 0062;0061 0315 0362 0362 0360 0062; # (a◌͢◌͠◌͢◌̕b; a◌̕◌͢◌͢◌͠b; a◌̕◌͢◌͢◌͠b; a◌̕◌͢◌͢◌͠b; a◌̕◌͢◌͢◌͠b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING DOUBLE TILDE, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0363 0062;00E0 05AE 0363 0315 0062;0061 05AE 0300 0363 0315 0062;00E0 05AE 0363 0315 0062;0061 05AE 0300 0363 0315 0062; # (a◌̕◌̀◌֮◌ͣb; à◌֮◌ͣ◌̕b; a◌֮◌̀◌ͣ◌̕b; à◌֮◌ͣ◌̕b; a◌֮◌̀◌ͣ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER A, LATIN SMALL LETTER B +0061 0363 0315 0300 05AE 0062;0061 05AE 0363 0300 0315 0062;0061 05AE 0363 0300 0315 0062;0061 05AE 0363 0300 0315 0062;0061 05AE 0363 0300 0315 0062; # (a◌ͣ◌̕◌̀◌֮b; a◌֮◌ͣ◌̀◌̕b; a◌֮◌ͣ◌̀◌̕b; a◌֮◌ͣ◌̀◌̕b; a◌֮◌ͣ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0364 0062;00E0 05AE 0364 0315 0062;0061 05AE 0300 0364 0315 0062;00E0 05AE 0364 0315 0062;0061 05AE 0300 0364 0315 0062; # (a◌̕◌̀◌֮◌ͤb; à◌֮◌ͤ◌̕b; a◌֮◌̀◌ͤ◌̕b; à◌֮◌ͤ◌̕b; a◌֮◌̀◌ͤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER E, LATIN SMALL LETTER B +0061 0364 0315 0300 05AE 0062;0061 05AE 0364 0300 0315 0062;0061 05AE 0364 0300 0315 0062;0061 05AE 0364 0300 0315 0062;0061 05AE 0364 0300 0315 0062; # (a◌ͤ◌̕◌̀◌֮b; a◌֮◌ͤ◌̀◌̕b; a◌֮◌ͤ◌̀◌̕b; a◌֮◌ͤ◌̀◌̕b; a◌֮◌ͤ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER E, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0365 0062;00E0 05AE 0365 0315 0062;0061 05AE 0300 0365 0315 0062;00E0 05AE 0365 0315 0062;0061 05AE 0300 0365 0315 0062; # (a◌̕◌̀◌֮◌ͥb; à◌֮◌ͥ◌̕b; a◌֮◌̀◌ͥ◌̕b; à◌֮◌ͥ◌̕b; a◌֮◌̀◌ͥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER I, LATIN SMALL LETTER B +0061 0365 0315 0300 05AE 0062;0061 05AE 0365 0300 0315 0062;0061 05AE 0365 0300 0315 0062;0061 05AE 0365 0300 0315 0062;0061 05AE 0365 0300 0315 0062; # (a◌ͥ◌̕◌̀◌֮b; a◌֮◌ͥ◌̀◌̕b; a◌֮◌ͥ◌̀◌̕b; a◌֮◌ͥ◌̀◌̕b; a◌֮◌ͥ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0366 0062;00E0 05AE 0366 0315 0062;0061 05AE 0300 0366 0315 0062;00E0 05AE 0366 0315 0062;0061 05AE 0300 0366 0315 0062; # (a◌̕◌̀◌֮◌ͦb; à◌֮◌ͦ◌̕b; a◌֮◌̀◌ͦ◌̕b; à◌֮◌ͦ◌̕b; a◌֮◌̀◌ͦ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER O, LATIN SMALL LETTER B +0061 0366 0315 0300 05AE 0062;0061 05AE 0366 0300 0315 0062;0061 05AE 0366 0300 0315 0062;0061 05AE 0366 0300 0315 0062;0061 05AE 0366 0300 0315 0062; # (a◌ͦ◌̕◌̀◌֮b; a◌֮◌ͦ◌̀◌̕b; a◌֮◌ͦ◌̀◌̕b; a◌֮◌ͦ◌̀◌̕b; a◌֮◌ͦ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER O, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0367 0062;00E0 05AE 0367 0315 0062;0061 05AE 0300 0367 0315 0062;00E0 05AE 0367 0315 0062;0061 05AE 0300 0367 0315 0062; # (a◌̕◌̀◌֮◌ͧb; à◌֮◌ͧ◌̕b; a◌֮◌̀◌ͧ◌̕b; à◌֮◌ͧ◌̕b; a◌֮◌̀◌ͧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER U, LATIN SMALL LETTER B +0061 0367 0315 0300 05AE 0062;0061 05AE 0367 0300 0315 0062;0061 05AE 0367 0300 0315 0062;0061 05AE 0367 0300 0315 0062;0061 05AE 0367 0300 0315 0062; # (a◌ͧ◌̕◌̀◌֮b; a◌֮◌ͧ◌̀◌̕b; a◌֮◌ͧ◌̀◌̕b; a◌֮◌ͧ◌̀◌̕b; a◌֮◌ͧ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER U, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0368 0062;00E0 05AE 0368 0315 0062;0061 05AE 0300 0368 0315 0062;00E0 05AE 0368 0315 0062;0061 05AE 0300 0368 0315 0062; # (a◌̕◌̀◌֮◌ͨb; à◌֮◌ͨ◌̕b; a◌֮◌̀◌ͨ◌̕b; à◌֮◌ͨ◌̕b; a◌֮◌̀◌ͨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER C, LATIN SMALL LETTER B +0061 0368 0315 0300 05AE 0062;0061 05AE 0368 0300 0315 0062;0061 05AE 0368 0300 0315 0062;0061 05AE 0368 0300 0315 0062;0061 05AE 0368 0300 0315 0062; # (a◌ͨ◌̕◌̀◌֮b; a◌֮◌ͨ◌̀◌̕b; a◌֮◌ͨ◌̀◌̕b; a◌֮◌ͨ◌̀◌̕b; a◌֮◌ͨ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER C, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0369 0062;00E0 05AE 0369 0315 0062;0061 05AE 0300 0369 0315 0062;00E0 05AE 0369 0315 0062;0061 05AE 0300 0369 0315 0062; # (a◌̕◌̀◌֮◌ͩb; à◌֮◌ͩ◌̕b; a◌֮◌̀◌ͩ◌̕b; à◌֮◌ͩ◌̕b; a◌֮◌̀◌ͩ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER D, LATIN SMALL LETTER B +0061 0369 0315 0300 05AE 0062;0061 05AE 0369 0300 0315 0062;0061 05AE 0369 0300 0315 0062;0061 05AE 0369 0300 0315 0062;0061 05AE 0369 0300 0315 0062; # (a◌ͩ◌̕◌̀◌֮b; a◌֮◌ͩ◌̀◌̕b; a◌֮◌ͩ◌̀◌̕b; a◌֮◌ͩ◌̀◌̕b; a◌֮◌ͩ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER D, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036A 0062;00E0 05AE 036A 0315 0062;0061 05AE 0300 036A 0315 0062;00E0 05AE 036A 0315 0062;0061 05AE 0300 036A 0315 0062; # (a◌̕◌̀◌֮◌ͪb; à◌֮◌ͪ◌̕b; a◌֮◌̀◌ͪ◌̕b; à◌֮◌ͪ◌̕b; a◌֮◌̀◌ͪ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER H, LATIN SMALL LETTER B +0061 036A 0315 0300 05AE 0062;0061 05AE 036A 0300 0315 0062;0061 05AE 036A 0300 0315 0062;0061 05AE 036A 0300 0315 0062;0061 05AE 036A 0300 0315 0062; # (a◌ͪ◌̕◌̀◌֮b; a◌֮◌ͪ◌̀◌̕b; a◌֮◌ͪ◌̀◌̕b; a◌֮◌ͪ◌̀◌̕b; a◌֮◌ͪ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER H, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036B 0062;00E0 05AE 036B 0315 0062;0061 05AE 0300 036B 0315 0062;00E0 05AE 036B 0315 0062;0061 05AE 0300 036B 0315 0062; # (a◌̕◌̀◌֮◌ͫb; à◌֮◌ͫ◌̕b; a◌֮◌̀◌ͫ◌̕b; à◌֮◌ͫ◌̕b; a◌֮◌̀◌ͫ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER M, LATIN SMALL LETTER B +0061 036B 0315 0300 05AE 0062;0061 05AE 036B 0300 0315 0062;0061 05AE 036B 0300 0315 0062;0061 05AE 036B 0300 0315 0062;0061 05AE 036B 0300 0315 0062; # (a◌ͫ◌̕◌̀◌֮b; a◌֮◌ͫ◌̀◌̕b; a◌֮◌ͫ◌̀◌̕b; a◌֮◌ͫ◌̀◌̕b; a◌֮◌ͫ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER M, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036C 0062;00E0 05AE 036C 0315 0062;0061 05AE 0300 036C 0315 0062;00E0 05AE 036C 0315 0062;0061 05AE 0300 036C 0315 0062; # (a◌̕◌̀◌֮◌ͬb; à◌֮◌ͬ◌̕b; a◌֮◌̀◌ͬ◌̕b; à◌֮◌ͬ◌̕b; a◌֮◌̀◌ͬ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER R, LATIN SMALL LETTER B +0061 036C 0315 0300 05AE 0062;0061 05AE 036C 0300 0315 0062;0061 05AE 036C 0300 0315 0062;0061 05AE 036C 0300 0315 0062;0061 05AE 036C 0300 0315 0062; # (a◌ͬ◌̕◌̀◌֮b; a◌֮◌ͬ◌̀◌̕b; a◌֮◌ͬ◌̀◌̕b; a◌֮◌ͬ◌̀◌̕b; a◌֮◌ͬ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER R, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036D 0062;00E0 05AE 036D 0315 0062;0061 05AE 0300 036D 0315 0062;00E0 05AE 036D 0315 0062;0061 05AE 0300 036D 0315 0062; # (a◌̕◌̀◌֮◌ͭb; à◌֮◌ͭ◌̕b; a◌֮◌̀◌ͭ◌̕b; à◌֮◌ͭ◌̕b; a◌֮◌̀◌ͭ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER T, LATIN SMALL LETTER B +0061 036D 0315 0300 05AE 0062;0061 05AE 036D 0300 0315 0062;0061 05AE 036D 0300 0315 0062;0061 05AE 036D 0300 0315 0062;0061 05AE 036D 0300 0315 0062; # (a◌ͭ◌̕◌̀◌֮b; a◌֮◌ͭ◌̀◌̕b; a◌֮◌ͭ◌̀◌̕b; a◌֮◌ͭ◌̀◌̕b; a◌֮◌ͭ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER T, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036E 0062;00E0 05AE 036E 0315 0062;0061 05AE 0300 036E 0315 0062;00E0 05AE 036E 0315 0062;0061 05AE 0300 036E 0315 0062; # (a◌̕◌̀◌֮◌ͮb; à◌֮◌ͮ◌̕b; a◌֮◌̀◌ͮ◌̕b; à◌֮◌ͮ◌̕b; a◌֮◌̀◌ͮ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER V, LATIN SMALL LETTER B +0061 036E 0315 0300 05AE 0062;0061 05AE 036E 0300 0315 0062;0061 05AE 036E 0300 0315 0062;0061 05AE 036E 0300 0315 0062;0061 05AE 036E 0300 0315 0062; # (a◌ͮ◌̕◌̀◌֮b; a◌֮◌ͮ◌̀◌̕b; a◌֮◌ͮ◌̀◌̕b; a◌֮◌ͮ◌̀◌̕b; a◌֮◌ͮ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER V, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036F 0062;00E0 05AE 036F 0315 0062;0061 05AE 0300 036F 0315 0062;00E0 05AE 036F 0315 0062;0061 05AE 0300 036F 0315 0062; # (a◌̕◌̀◌֮◌ͯb; à◌֮◌ͯ◌̕b; a◌֮◌̀◌ͯ◌̕b; à◌֮◌ͯ◌̕b; a◌֮◌̀◌ͯ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER X, LATIN SMALL LETTER B +0061 036F 0315 0300 05AE 0062;0061 05AE 036F 0300 0315 0062;0061 05AE 036F 0300 0315 0062;0061 05AE 036F 0300 0315 0062;0061 05AE 036F 0300 0315 0062; # (a◌ͯ◌̕◌̀◌֮b; a◌֮◌ͯ◌̀◌̕b; a◌֮◌ͯ◌̀◌̕b; a◌֮◌ͯ◌̀◌̕b; a◌֮◌ͯ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER X, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0483 0062;00E0 05AE 0483 0315 0062;0061 05AE 0300 0483 0315 0062;00E0 05AE 0483 0315 0062;0061 05AE 0300 0483 0315 0062; # (a◌̕◌̀◌֮◌҃b; à◌֮◌҃◌̕b; a◌֮◌̀◌҃◌̕b; à◌֮◌҃◌̕b; a◌֮◌̀◌҃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO, LATIN SMALL LETTER B +0061 0483 0315 0300 05AE 0062;0061 05AE 0483 0300 0315 0062;0061 05AE 0483 0300 0315 0062;0061 05AE 0483 0300 0315 0062;0061 05AE 0483 0300 0315 0062; # (a◌҃◌̕◌̀◌֮b; a◌֮◌҃◌̀◌̕b; a◌֮◌҃◌̀◌̕b; a◌֮◌҃◌̀◌̕b; a◌֮◌҃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0484 0062;00E0 05AE 0484 0315 0062;0061 05AE 0300 0484 0315 0062;00E0 05AE 0484 0315 0062;0061 05AE 0300 0484 0315 0062; # (a◌̕◌̀◌֮◌҄b; à◌֮◌҄◌̕b; a◌֮◌̀◌҄◌̕b; à◌֮◌҄◌̕b; a◌֮◌̀◌҄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC PALATALIZATION, LATIN SMALL LETTER B +0061 0484 0315 0300 05AE 0062;0061 05AE 0484 0300 0315 0062;0061 05AE 0484 0300 0315 0062;0061 05AE 0484 0300 0315 0062;0061 05AE 0484 0300 0315 0062; # (a◌҄◌̕◌̀◌֮b; a◌֮◌҄◌̀◌̕b; a◌֮◌҄◌̀◌̕b; a◌֮◌҄◌̀◌̕b; a◌֮◌҄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PALATALIZATION, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0485 0062;00E0 05AE 0485 0315 0062;0061 05AE 0300 0485 0315 0062;00E0 05AE 0485 0315 0062;0061 05AE 0300 0485 0315 0062; # (a◌̕◌̀◌֮◌҅b; à◌֮◌҅◌̕b; a◌֮◌̀◌҅◌̕b; à◌֮◌҅◌̕b; a◌֮◌̀◌҅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC DASIA PNEUMATA, LATIN SMALL LETTER B +0061 0485 0315 0300 05AE 0062;0061 05AE 0485 0300 0315 0062;0061 05AE 0485 0300 0315 0062;0061 05AE 0485 0300 0315 0062;0061 05AE 0485 0300 0315 0062; # (a◌҅◌̕◌̀◌֮b; a◌֮◌҅◌̀◌̕b; a◌֮◌҅◌̀◌̕b; a◌֮◌҅◌̀◌̕b; a◌֮◌҅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC DASIA PNEUMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0486 0062;00E0 05AE 0486 0315 0062;0061 05AE 0300 0486 0315 0062;00E0 05AE 0486 0315 0062;0061 05AE 0300 0486 0315 0062; # (a◌̕◌̀◌֮◌҆b; à◌֮◌҆◌̕b; a◌֮◌̀◌҆◌̕b; à◌֮◌҆◌̕b; a◌֮◌̀◌҆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC PSILI PNEUMATA, LATIN SMALL LETTER B +0061 0486 0315 0300 05AE 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062; # (a◌҆◌̕◌̀◌֮b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PSILI PNEUMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0591 0062;0061 302A 0316 0591 059A 0062;0061 302A 0316 0591 059A 0062;0061 302A 0316 0591 059A 0062;0061 302A 0316 0591 059A 0062; # (a◌֚◌̖◌〪◌֑b; a◌〪◌̖◌֑◌֚b; a◌〪◌̖◌֑◌֚b; a◌〪◌̖◌֑◌֚b; a◌〪◌̖◌֑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT ETNAHTA, LATIN SMALL LETTER B +0061 0591 059A 0316 302A 0062;0061 302A 0591 0316 059A 0062;0061 302A 0591 0316 059A 0062;0061 302A 0591 0316 059A 0062;0061 302A 0591 0316 059A 0062; # (a◌֑◌֚◌̖◌〪b; a◌〪◌֑◌̖◌֚b; a◌〪◌֑◌̖◌֚b; a◌〪◌֑◌̖◌֚b; a◌〪◌֑◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ETNAHTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0592 0062;00E0 05AE 0592 0315 0062;0061 05AE 0300 0592 0315 0062;00E0 05AE 0592 0315 0062;0061 05AE 0300 0592 0315 0062; # (a◌̕◌̀◌֮◌֒b; à◌֮◌֒◌̕b; a◌֮◌̀◌֒◌̕b; à◌֮◌֒◌̕b; a◌֮◌̀◌֒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT SEGOL, LATIN SMALL LETTER B +0061 0592 0315 0300 05AE 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062; # (a◌֒◌̕◌̀◌֮b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT SEGOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0593 0062;00E0 05AE 0593 0315 0062;0061 05AE 0300 0593 0315 0062;00E0 05AE 0593 0315 0062;0061 05AE 0300 0593 0315 0062; # (a◌̕◌̀◌֮◌֓b; à◌֮◌֓◌̕b; a◌֮◌̀◌֓◌̕b; à◌֮◌֓◌̕b; a◌֮◌̀◌֓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT SHALSHELET, LATIN SMALL LETTER B +0061 0593 0315 0300 05AE 0062;0061 05AE 0593 0300 0315 0062;0061 05AE 0593 0300 0315 0062;0061 05AE 0593 0300 0315 0062;0061 05AE 0593 0300 0315 0062; # (a◌֓◌̕◌̀◌֮b; a◌֮◌֓◌̀◌̕b; a◌֮◌֓◌̀◌̕b; a◌֮◌֓◌̀◌̕b; a◌֮◌֓◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT SHALSHELET, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0594 0062;00E0 05AE 0594 0315 0062;0061 05AE 0300 0594 0315 0062;00E0 05AE 0594 0315 0062;0061 05AE 0300 0594 0315 0062; # (a◌̕◌̀◌֮◌֔b; à◌֮◌֔◌̕b; a◌֮◌̀◌֔◌̕b; à◌֮◌֔◌̕b; a◌֮◌̀◌֔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZAQEF QATAN, LATIN SMALL LETTER B +0061 0594 0315 0300 05AE 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062; # (a◌֔◌̕◌̀◌֮b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZAQEF QATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0595 0062;00E0 05AE 0595 0315 0062;0061 05AE 0300 0595 0315 0062;00E0 05AE 0595 0315 0062;0061 05AE 0300 0595 0315 0062; # (a◌̕◌̀◌֮◌֕b; à◌֮◌֕◌̕b; a◌֮◌̀◌֕◌̕b; à◌֮◌֕◌̕b; a◌֮◌̀◌֕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZAQEF GADOL, LATIN SMALL LETTER B +0061 0595 0315 0300 05AE 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062; # (a◌֕◌̕◌̀◌֮b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZAQEF GADOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0596 0062;0061 302A 0316 0596 059A 0062;0061 302A 0316 0596 059A 0062;0061 302A 0316 0596 059A 0062;0061 302A 0316 0596 059A 0062; # (a◌֚◌̖◌〪◌֖b; a◌〪◌̖◌֖◌֚b; a◌〪◌̖◌֖◌֚b; a◌〪◌̖◌֖◌֚b; a◌〪◌̖◌֖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT TIPEHA, LATIN SMALL LETTER B +0061 0596 059A 0316 302A 0062;0061 302A 0596 0316 059A 0062;0061 302A 0596 0316 059A 0062;0061 302A 0596 0316 059A 0062;0061 302A 0596 0316 059A 0062; # (a◌֖◌֚◌̖◌〪b; a◌〪◌֖◌̖◌֚b; a◌〪◌֖◌̖◌֚b; a◌〪◌֖◌̖◌֚b; a◌〪◌֖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TIPEHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0597 0062;00E0 05AE 0597 0315 0062;0061 05AE 0300 0597 0315 0062;00E0 05AE 0597 0315 0062;0061 05AE 0300 0597 0315 0062; # (a◌̕◌̀◌֮◌֗b; à◌֮◌֗◌̕b; a◌֮◌̀◌֗◌̕b; à◌֮◌֗◌̕b; a◌֮◌̀◌֗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT REVIA, LATIN SMALL LETTER B +0061 0597 0315 0300 05AE 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062; # (a◌֗◌̕◌̀◌֮b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT REVIA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0598 0062;00E0 05AE 0598 0315 0062;0061 05AE 0300 0598 0315 0062;00E0 05AE 0598 0315 0062;0061 05AE 0300 0598 0315 0062; # (a◌̕◌̀◌֮◌֘b; à◌֮◌֘◌̕b; a◌֮◌̀◌֘◌̕b; à◌֮◌֘◌̕b; a◌֮◌̀◌֘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZARQA, LATIN SMALL LETTER B +0061 0598 0315 0300 05AE 0062;0061 05AE 0598 0300 0315 0062;0061 05AE 0598 0300 0315 0062;0061 05AE 0598 0300 0315 0062;0061 05AE 0598 0300 0315 0062; # (a◌֘◌̕◌̀◌֮b; a◌֮◌֘◌̀◌̕b; a◌֮◌֘◌̀◌̕b; a◌֮◌֘◌̀◌̕b; a◌֮◌֘◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZARQA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0599 0062;00E0 05AE 0599 0315 0062;0061 05AE 0300 0599 0315 0062;00E0 05AE 0599 0315 0062;0061 05AE 0300 0599 0315 0062; # (a◌̕◌̀◌֮◌֙b; à◌֮◌֙◌̕b; a◌֮◌̀◌֙◌̕b; à◌֮◌֙◌̕b; a◌֮◌̀◌֙◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT PASHTA, LATIN SMALL LETTER B +0061 0599 0315 0300 05AE 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062; # (a◌֙◌̕◌̀◌֮b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT PASHTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 302E 059A 0316 059A 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062; # (a◌〮◌֚◌̖◌֚b; a◌̖◌֚◌֚◌〮b; a◌̖◌֚◌֚◌〮b; a◌̖◌֚◌֚◌〮b; a◌̖◌֚◌֚◌〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, LATIN SMALL LETTER B +0061 059A 302E 059A 0316 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062; # (a◌֚◌〮◌֚◌̖b; a◌̖◌֚◌֚◌〮b; a◌̖◌֚◌֚◌〮b; a◌̖◌֚◌֚◌〮b; a◌̖◌֚◌֚◌〮b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 059A 0316 302A 059B 0062;0061 302A 0316 059B 059A 0062;0061 302A 0316 059B 059A 0062;0061 302A 0316 059B 059A 0062;0061 302A 0316 059B 059A 0062; # (a◌֚◌̖◌〪◌֛b; a◌〪◌̖◌֛◌֚b; a◌〪◌̖◌֛◌֚b; a◌〪◌̖◌֛◌֚b; a◌〪◌̖◌֛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT TEVIR, LATIN SMALL LETTER B +0061 059B 059A 0316 302A 0062;0061 302A 059B 0316 059A 0062;0061 302A 059B 0316 059A 0062;0061 302A 059B 0316 059A 0062;0061 302A 059B 0316 059A 0062; # (a◌֛◌֚◌̖◌〪b; a◌〪◌֛◌̖◌֚b; a◌〪◌֛◌̖◌֚b; a◌〪◌֛◌̖◌֚b; a◌〪◌֛◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TEVIR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 059C 0062;00E0 05AE 059C 0315 0062;0061 05AE 0300 059C 0315 0062;00E0 05AE 059C 0315 0062;0061 05AE 0300 059C 0315 0062; # (a◌̕◌̀◌֮◌֜b; à◌֮◌֜◌̕b; a◌֮◌̀◌֜◌̕b; à◌֮◌֜◌̕b; a◌֮◌̀◌֜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERESH, LATIN SMALL LETTER B +0061 059C 0315 0300 05AE 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062; # (a◌֜◌̕◌̀◌֮b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERESH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 059D 0062;00E0 05AE 059D 0315 0062;0061 05AE 0300 059D 0315 0062;00E0 05AE 059D 0315 0062;0061 05AE 0300 059D 0315 0062; # (a◌̕◌̀◌֮◌֝b; à◌֮◌֝◌̕b; a◌֮◌̀◌֝◌̕b; à◌֮◌֝◌̕b; a◌֮◌̀◌֝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERESH MUQDAM, LATIN SMALL LETTER B +0061 059D 0315 0300 05AE 0062;0061 05AE 059D 0300 0315 0062;0061 05AE 059D 0300 0315 0062;0061 05AE 059D 0300 0315 0062;0061 05AE 059D 0300 0315 0062; # (a◌֝◌̕◌̀◌֮b; a◌֮◌֝◌̀◌̕b; a◌֮◌֝◌̀◌̕b; a◌֮◌֝◌̀◌̕b; a◌֮◌֝◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERESH MUQDAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 059E 0062;00E0 05AE 059E 0315 0062;0061 05AE 0300 059E 0315 0062;00E0 05AE 059E 0315 0062;0061 05AE 0300 059E 0315 0062; # (a◌̕◌̀◌֮◌֞b; à◌֮◌֞◌̕b; a◌֮◌̀◌֞◌̕b; à◌֮◌֞◌̕b; a◌֮◌̀◌֞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERSHAYIM, LATIN SMALL LETTER B +0061 059E 0315 0300 05AE 0062;0061 05AE 059E 0300 0315 0062;0061 05AE 059E 0300 0315 0062;0061 05AE 059E 0300 0315 0062;0061 05AE 059E 0300 0315 0062; # (a◌֞◌̕◌̀◌֮b; a◌֮◌֞◌̀◌̕b; a◌֮◌֞◌̀◌̕b; a◌֮◌֞◌̀◌̕b; a◌֮◌֞◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERSHAYIM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 059F 0062;00E0 05AE 059F 0315 0062;0061 05AE 0300 059F 0315 0062;00E0 05AE 059F 0315 0062;0061 05AE 0300 059F 0315 0062; # (a◌̕◌̀◌֮◌֟b; à◌֮◌֟◌̕b; a◌֮◌̀◌֟◌̕b; à◌֮◌֟◌̕b; a◌֮◌̀◌֟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT QARNEY PARA, LATIN SMALL LETTER B +0061 059F 0315 0300 05AE 0062;0061 05AE 059F 0300 0315 0062;0061 05AE 059F 0300 0315 0062;0061 05AE 059F 0300 0315 0062;0061 05AE 059F 0300 0315 0062; # (a◌֟◌̕◌̀◌֮b; a◌֮◌֟◌̀◌̕b; a◌֮◌֟◌̀◌̕b; a◌֮◌֟◌̀◌̕b; a◌֮◌֟◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT QARNEY PARA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A0 0062;00E0 05AE 05A0 0315 0062;0061 05AE 0300 05A0 0315 0062;00E0 05AE 05A0 0315 0062;0061 05AE 0300 05A0 0315 0062; # (a◌̕◌̀◌֮◌֠b; à◌֮◌֠◌̕b; a◌֮◌̀◌֠◌̕b; à◌֮◌֠◌̕b; a◌֮◌̀◌֠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT TELISHA GEDOLA, LATIN SMALL LETTER B +0061 05A0 0315 0300 05AE 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062; # (a◌֠◌̕◌̀◌֮b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT TELISHA GEDOLA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A1 0062;00E0 05AE 05A1 0315 0062;0061 05AE 0300 05A1 0315 0062;00E0 05AE 05A1 0315 0062;0061 05AE 0300 05A1 0315 0062; # (a◌̕◌̀◌֮◌֡b; à◌֮◌֡◌̕b; a◌֮◌̀◌֡◌̕b; à◌֮◌֡◌̕b; a◌֮◌̀◌֡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT PAZER, LATIN SMALL LETTER B +0061 05A1 0315 0300 05AE 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062; # (a◌֡◌̕◌̀◌֮b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT PAZER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 05A3 0062;0061 302A 0316 05A3 059A 0062;0061 302A 0316 05A3 059A 0062;0061 302A 0316 05A3 059A 0062;0061 302A 0316 05A3 059A 0062; # (a◌֚◌̖◌〪◌֣b; a◌〪◌̖◌֣◌֚b; a◌〪◌̖◌֣◌֚b; a◌〪◌̖◌֣◌֚b; a◌〪◌̖◌֣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MUNAH, LATIN SMALL LETTER B +0061 05A3 059A 0316 302A 0062;0061 302A 05A3 0316 059A 0062;0061 302A 05A3 0316 059A 0062;0061 302A 05A3 0316 059A 0062;0061 302A 05A3 0316 059A 0062; # (a◌֣◌֚◌̖◌〪b; a◌〪◌֣◌̖◌֚b; a◌〪◌֣◌̖◌֚b; a◌〪◌֣◌̖◌֚b; a◌〪◌֣◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MUNAH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 05A4 0062;0061 302A 0316 05A4 059A 0062;0061 302A 0316 05A4 059A 0062;0061 302A 0316 05A4 059A 0062;0061 302A 0316 05A4 059A 0062; # (a◌֚◌̖◌〪◌֤b; a◌〪◌̖◌֤◌֚b; a◌〪◌̖◌֤◌֚b; a◌〪◌̖◌֤◌֚b; a◌〪◌̖◌֤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MAHAPAKH, LATIN SMALL LETTER B +0061 05A4 059A 0316 302A 0062;0061 302A 05A4 0316 059A 0062;0061 302A 05A4 0316 059A 0062;0061 302A 05A4 0316 059A 0062;0061 302A 05A4 0316 059A 0062; # (a◌֤◌֚◌̖◌〪b; a◌〪◌֤◌̖◌֚b; a◌〪◌֤◌̖◌֚b; a◌〪◌֤◌̖◌֚b; a◌〪◌֤◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MAHAPAKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 05A5 0062;0061 302A 0316 05A5 059A 0062;0061 302A 0316 05A5 059A 0062;0061 302A 0316 05A5 059A 0062;0061 302A 0316 05A5 059A 0062; # (a◌֚◌̖◌〪◌֥b; a◌〪◌̖◌֥◌֚b; a◌〪◌̖◌֥◌֚b; a◌〪◌̖◌֥◌֚b; a◌〪◌̖◌֥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MERKHA, LATIN SMALL LETTER B +0061 05A5 059A 0316 302A 0062;0061 302A 05A5 0316 059A 0062;0061 302A 05A5 0316 059A 0062;0061 302A 05A5 0316 059A 0062;0061 302A 05A5 0316 059A 0062; # (a◌֥◌֚◌̖◌〪b; a◌〪◌֥◌̖◌֚b; a◌〪◌֥◌̖◌֚b; a◌〪◌֥◌̖◌֚b; a◌〪◌֥◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 05A6 0062;0061 302A 0316 05A6 059A 0062;0061 302A 0316 05A6 059A 0062;0061 302A 0316 05A6 059A 0062;0061 302A 0316 05A6 059A 0062; # (a◌֚◌̖◌〪◌֦b; a◌〪◌̖◌֦◌֚b; a◌〪◌̖◌֦◌֚b; a◌〪◌̖◌֦◌֚b; a◌〪◌̖◌֦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MERKHA KEFULA, LATIN SMALL LETTER B +0061 05A6 059A 0316 302A 0062;0061 302A 05A6 0316 059A 0062;0061 302A 05A6 0316 059A 0062;0061 302A 05A6 0316 059A 0062;0061 302A 05A6 0316 059A 0062; # (a◌֦◌֚◌̖◌〪b; a◌〪◌֦◌̖◌֚b; a◌〪◌֦◌̖◌֚b; a◌〪◌֦◌̖◌֚b; a◌〪◌֦◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA KEFULA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 05A7 0062;0061 302A 0316 05A7 059A 0062;0061 302A 0316 05A7 059A 0062;0061 302A 0316 05A7 059A 0062;0061 302A 0316 05A7 059A 0062; # (a◌֚◌̖◌〪◌֧b; a◌〪◌̖◌֧◌֚b; a◌〪◌̖◌֧◌֚b; a◌〪◌̖◌֧◌֚b; a◌〪◌̖◌֧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT DARGA, LATIN SMALL LETTER B +0061 05A7 059A 0316 302A 0062;0061 302A 05A7 0316 059A 0062;0061 302A 05A7 0316 059A 0062;0061 302A 05A7 0316 059A 0062;0061 302A 05A7 0316 059A 0062; # (a◌֧◌֚◌̖◌〪b; a◌〪◌֧◌̖◌֚b; a◌〪◌֧◌̖◌֚b; a◌〪◌֧◌̖◌֚b; a◌〪◌֧◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT DARGA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A8 0062;00E0 05AE 05A8 0315 0062;0061 05AE 0300 05A8 0315 0062;00E0 05AE 05A8 0315 0062;0061 05AE 0300 05A8 0315 0062; # (a◌̕◌̀◌֮◌֨b; à◌֮◌֨◌̕b; a◌֮◌̀◌֨◌̕b; à◌֮◌֨◌̕b; a◌֮◌̀◌֨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT QADMA, LATIN SMALL LETTER B +0061 05A8 0315 0300 05AE 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062; # (a◌֨◌̕◌̀◌֮b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT QADMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A9 0062;00E0 05AE 05A9 0315 0062;0061 05AE 0300 05A9 0315 0062;00E0 05AE 05A9 0315 0062;0061 05AE 0300 05A9 0315 0062; # (a◌̕◌̀◌֮◌֩b; à◌֮◌֩◌̕b; a◌֮◌̀◌֩◌̕b; à◌֮◌֩◌̕b; a◌֮◌̀◌֩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT TELISHA QETANA, LATIN SMALL LETTER B +0061 05A9 0315 0300 05AE 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062; # (a◌֩◌̕◌̀◌֮b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT TELISHA QETANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 05AA 0062;0061 302A 0316 05AA 059A 0062;0061 302A 0316 05AA 059A 0062;0061 302A 0316 05AA 059A 0062;0061 302A 0316 05AA 059A 0062; # (a◌֚◌̖◌〪◌֪b; a◌〪◌̖◌֪◌֚b; a◌〪◌̖◌֪◌֚b; a◌〪◌̖◌֪◌֚b; a◌〪◌̖◌֪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT YERAH BEN YOMO, LATIN SMALL LETTER B +0061 05AA 059A 0316 302A 0062;0061 302A 05AA 0316 059A 0062;0061 302A 05AA 0316 059A 0062;0061 302A 05AA 0316 059A 0062;0061 302A 05AA 0316 059A 0062; # (a◌֪◌֚◌̖◌〪b; a◌〪◌֪◌̖◌֚b; a◌〪◌֪◌̖◌֚b; a◌〪◌֪◌̖◌֚b; a◌〪◌֪◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YERAH BEN YOMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 05AB 0062;00E0 05AE 05AB 0315 0062;0061 05AE 0300 05AB 0315 0062;00E0 05AE 05AB 0315 0062;0061 05AE 0300 05AB 0315 0062; # (a◌̕◌̀◌֮◌֫b; à◌֮◌֫◌̕b; a◌֮◌̀◌֫◌̕b; à◌֮◌֫◌̕b; a◌֮◌̀◌֫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT OLE, LATIN SMALL LETTER B +0061 05AB 0315 0300 05AE 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062; # (a◌֫◌̕◌̀◌֮b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT OLE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05AC 0062;00E0 05AE 05AC 0315 0062;0061 05AE 0300 05AC 0315 0062;00E0 05AE 05AC 0315 0062;0061 05AE 0300 05AC 0315 0062; # (a◌̕◌̀◌֮◌֬b; à◌֮◌֬◌̕b; a◌֮◌̀◌֬◌̕b; à◌֮◌֬◌̕b; a◌֮◌̀◌֬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ILUY, LATIN SMALL LETTER B +0061 05AC 0315 0300 05AE 0062;0061 05AE 05AC 0300 0315 0062;0061 05AE 05AC 0300 0315 0062;0061 05AE 05AC 0300 0315 0062;0061 05AE 05AC 0300 0315 0062; # (a◌֬◌̕◌̀◌֮b; a◌֮◌֬◌̀◌̕b; a◌֮◌֬◌̀◌̕b; a◌֮◌֬◌̀◌̕b; a◌֮◌֬◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ILUY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 302E 059A 0316 05AD 0062;0061 0316 059A 05AD 302E 0062;0061 0316 059A 05AD 302E 0062;0061 0316 059A 05AD 302E 0062;0061 0316 059A 05AD 302E 0062; # (a◌〮◌֚◌̖◌֭b; a◌̖◌֚◌֭◌〮b; a◌̖◌֚◌֭◌〮b; a◌̖◌֚◌֭◌〮b; a◌̖◌֚◌֭◌〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT DEHI, LATIN SMALL LETTER B +0061 05AD 302E 059A 0316 0062;0061 0316 05AD 059A 302E 0062;0061 0316 05AD 059A 302E 0062;0061 0316 05AD 059A 302E 0062;0061 0316 05AD 059A 302E 0062; # (a◌֭◌〮◌֚◌̖b; a◌̖◌֭◌֚◌〮b; a◌̖◌֭◌֚◌〮b; a◌̖◌֭◌֚◌〮b; a◌̖◌֭◌֚◌〮b; ) LATIN SMALL LETTER A, HEBREW ACCENT DEHI, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 05AE 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062; # (a◌̀◌𝅭𝅭֮◌֮b; à𝅭𝅭◌֮◌֮b; a𝅭𝅭◌֮◌֮◌̀b; à𝅭𝅭◌֮◌֮b; a𝅭𝅭◌֮◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05AE 0300 05AE 1D16D 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062; # (a◌֮◌̀◌𝅭𝅭֮b; à𝅭𝅭◌֮◌֮b; a𝅭𝅭◌֮◌֮◌̀b; à𝅭𝅭◌֮◌֮b; a𝅭𝅭◌֮◌֮◌̀b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZINOR, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE 05AF 0062;00E0 05AE 05AF 0315 0062;0061 05AE 0300 05AF 0315 0062;00E0 05AE 05AF 0315 0062;0061 05AE 0300 05AF 0315 0062; # (a◌̕◌̀◌֮◌֯b; à◌֮◌֯◌̕b; a◌֮◌̀◌֯◌̕b; à◌֮◌֯◌̕b; a◌֮◌̀◌֯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW MARK MASORA CIRCLE, LATIN SMALL LETTER B +0061 05AF 0315 0300 05AE 0062;0061 05AE 05AF 0300 0315 0062;0061 05AE 05AF 0300 0315 0062;0061 05AE 05AF 0300 0315 0062;0061 05AE 05AF 0300 0315 0062; # (a◌֯◌̕◌̀◌֮b; a◌֮◌֯◌̀◌̕b; a◌֮◌֯◌̀◌̕b; a◌֮◌֯◌̀◌̕b; a◌֮◌֯◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW MARK MASORA CIRCLE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B1 05B0 094D 05B0 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062; # (a◌ֱ◌ְ◌्◌ְb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, HEBREW POINT SHEVA, LATIN SMALL LETTER B +0061 05B0 05B1 05B0 094D 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062; # (a◌ְ◌ֱ◌ְ◌्b; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, LATIN SMALL LETTER B +0061 05B2 05B1 05B0 05B1 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062; # (a◌ֲ◌ֱ◌ְ◌ֱb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, HEBREW POINT HATAF SEGOL, LATIN SMALL LETTER B +0061 05B1 05B2 05B1 05B0 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062; # (a◌ֱ◌ֲ◌ֱ◌ְb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF SEGOL, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, LATIN SMALL LETTER B +0061 05B3 05B2 05B1 05B2 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062; # (a◌ֳ◌ֲ◌ֱ◌ֲb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, HEBREW POINT HATAF PATAH, LATIN SMALL LETTER B +0061 05B2 05B3 05B2 05B1 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062; # (a◌ֲ◌ֳ◌ֲ◌ֱb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, LATIN SMALL LETTER B +0061 05B4 05B3 05B2 05B3 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062; # (a◌ִ◌ֳ◌ֲ◌ֳb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; ) LATIN SMALL LETTER A, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF QAMATS, LATIN SMALL LETTER B +0061 05B3 05B4 05B3 05B2 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062; # (a◌ֳ◌ִ◌ֳ◌ֲb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF QAMATS, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, LATIN SMALL LETTER B +0061 05B5 05B4 05B3 05B4 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062; # (a◌ֵ◌ִ◌ֳ◌ִb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; ) LATIN SMALL LETTER A, HEBREW POINT TSERE, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, HEBREW POINT HIRIQ, LATIN SMALL LETTER B +0061 05B4 05B5 05B4 05B3 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062; # (a◌ִ◌ֵ◌ִ◌ֳb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; ) LATIN SMALL LETTER A, HEBREW POINT HIRIQ, HEBREW POINT TSERE, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, LATIN SMALL LETTER B +0061 05B6 05B5 05B4 05B5 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062; # (a◌ֶ◌ֵ◌ִ◌ֵb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; ) LATIN SMALL LETTER A, HEBREW POINT SEGOL, HEBREW POINT TSERE, HEBREW POINT HIRIQ, HEBREW POINT TSERE, LATIN SMALL LETTER B +0061 05B5 05B6 05B5 05B4 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062; # (a◌ֵ◌ֶ◌ֵ◌ִb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; ) LATIN SMALL LETTER A, HEBREW POINT TSERE, HEBREW POINT SEGOL, HEBREW POINT TSERE, HEBREW POINT HIRIQ, LATIN SMALL LETTER B +0061 05B7 05B6 05B5 05B6 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062; # (a◌ַ◌ֶ◌ֵ◌ֶb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; ) LATIN SMALL LETTER A, HEBREW POINT PATAH, HEBREW POINT SEGOL, HEBREW POINT TSERE, HEBREW POINT SEGOL, LATIN SMALL LETTER B +0061 05B6 05B7 05B6 05B5 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062; # (a◌ֶ◌ַ◌ֶ◌ֵb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; ) LATIN SMALL LETTER A, HEBREW POINT SEGOL, HEBREW POINT PATAH, HEBREW POINT SEGOL, HEBREW POINT TSERE, LATIN SMALL LETTER B +0061 05B8 05B7 05B6 05B7 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062; # (a◌ָ◌ַ◌ֶ◌ַb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; ) LATIN SMALL LETTER A, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT SEGOL, HEBREW POINT PATAH, LATIN SMALL LETTER B +0061 05B7 05B8 05B7 05B6 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062; # (a◌ַ◌ָ◌ַ◌ֶb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; ) LATIN SMALL LETTER A, HEBREW POINT PATAH, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT SEGOL, LATIN SMALL LETTER B +0061 05B9 05B8 05B7 05B8 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062; # (a◌ֹ◌ָ◌ַ◌ָb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT QAMATS, LATIN SMALL LETTER B +0061 05B8 05B9 05B8 05B7 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062; # (a◌ָ◌ֹ◌ָ◌ַb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, LATIN SMALL LETTER B +0061 05BB 05B9 05B8 05B9 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062; # (a◌ֻ◌ֹ◌ָ◌ֹb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; ) LATIN SMALL LETTER A, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT HOLAM, LATIN SMALL LETTER B +0061 05B9 05BB 05B9 05B8 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062; # (a◌ֹ◌ֻ◌ֹ◌ָb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, LATIN SMALL LETTER B +0061 05BC 05BB 05B9 05BB 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062; # (a◌ּ◌ֻ◌ֹ◌ֻb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; ) LATIN SMALL LETTER A, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QUBUTS, LATIN SMALL LETTER B +0061 05BB 05BC 05BB 05B9 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062; # (a◌ֻ◌ּ◌ֻ◌ֹb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; ) LATIN SMALL LETTER A, HEBREW POINT QUBUTS, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, LATIN SMALL LETTER B +0061 05BD 05BC 05BB 05BC 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062; # (a◌ֽ◌ּ◌ֻ◌ּb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; ) LATIN SMALL LETTER A, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, HEBREW POINT DAGESH OR MAPIQ, LATIN SMALL LETTER B +0061 05BC 05BD 05BC 05BB 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062; # (a◌ּ◌ֽ◌ּ◌ֻb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; ) LATIN SMALL LETTER A, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, LATIN SMALL LETTER B +0061 05BF 05BD 05BC 05BD 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062; # (a◌ֿ◌ֽ◌ּ◌ֽb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; ) LATIN SMALL LETTER A, HEBREW POINT RAFE, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT METEG, LATIN SMALL LETTER B +0061 05BD 05BF 05BD 05BC 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062; # (a◌ֽ◌ֿ◌ֽ◌ּb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; ) LATIN SMALL LETTER A, HEBREW POINT METEG, HEBREW POINT RAFE, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, LATIN SMALL LETTER B +0061 05C1 05BF 05BD 05BF 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062; # (a◌ׁ◌ֿ◌ֽ◌ֿb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; ) LATIN SMALL LETTER A, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, HEBREW POINT METEG, HEBREW POINT RAFE, LATIN SMALL LETTER B +0061 05BF 05C1 05BF 05BD 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062; # (a◌ֿ◌ׁ◌ֿ◌ֽb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; ) LATIN SMALL LETTER A, HEBREW POINT RAFE, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, HEBREW POINT METEG, LATIN SMALL LETTER B +0061 05C2 05C1 05BF 05C1 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062; # (a◌ׂ◌ׁ◌ֿ◌ׁb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; ) LATIN SMALL LETTER A, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, HEBREW POINT SHIN DOT, LATIN SMALL LETTER B +0061 05C1 05C2 05C1 05BF 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062; # (a◌ׁ◌ׂ◌ׁ◌ֿb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; ) LATIN SMALL LETTER A, HEBREW POINT SHIN DOT, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, LATIN SMALL LETTER B +0061 FB1E 05C2 05C1 05C2 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062; # (a◌ﬞ◌ׂ◌ׁ◌ׂb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; ) LATIN SMALL LETTER A, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, HEBREW POINT SIN DOT, LATIN SMALL LETTER B +0061 05C2 FB1E 05C2 05C1 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062; # (a◌ׂ◌ﬞ◌ׂ◌ׁb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; ) LATIN SMALL LETTER A, HEBREW POINT SIN DOT, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE 05C4 0062;00E0 05AE 05C4 0315 0062;0061 05AE 0300 05C4 0315 0062;00E0 05AE 05C4 0315 0062;0061 05AE 0300 05C4 0315 0062; # (a◌̕◌̀◌֮◌ׄb; à◌֮◌ׄ◌̕b; a◌֮◌̀◌ׄ◌̕b; à◌֮◌ׄ◌̕b; a◌֮◌̀◌ׄ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW MARK UPPER DOT, LATIN SMALL LETTER B +0061 05C4 0315 0300 05AE 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062; # (a◌ׄ◌̕◌̀◌֮b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW MARK UPPER DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 064C 064B FB1E 064B 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062; # (a◌ٌ◌ً◌ﬞ◌ًb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; ) LATIN SMALL LETTER A, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, ARABIC FATHATAN, LATIN SMALL LETTER B +0061 064B 064C 064B FB1E 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062; # (a◌ً◌ٌ◌ً◌ﬞb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; ) LATIN SMALL LETTER A, ARABIC FATHATAN, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, LATIN SMALL LETTER B +0061 064D 064C 064B 064C 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062; # (a◌ٍ◌ٌ◌ً◌ٌb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; ) LATIN SMALL LETTER A, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, ARABIC DAMMATAN, LATIN SMALL LETTER B +0061 064C 064D 064C 064B 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062; # (a◌ٌ◌ٍ◌ٌ◌ًb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; ) LATIN SMALL LETTER A, ARABIC DAMMATAN, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, LATIN SMALL LETTER B +0061 064E 064D 064C 064D 0062;0061 064C 064D 064D 064E 0062;0061 064C 064D 064D 064E 0062;0061 064C 064D 064D 064E 0062;0061 064C 064D 064D 064E 0062; # (a◌َ◌ٍ◌ٌ◌ٍb; a◌ٌ◌ٍ◌ٍ◌َb; a◌ٌ◌ٍ◌ٍ◌َb; a◌ٌ◌ٍ◌ٍ◌َb; a◌ٌ◌ٍ◌ٍ◌َb; ) LATIN SMALL LETTER A, ARABIC FATHA, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC KASRATAN, LATIN SMALL LETTER B +0061 064D 064E 064D 064C 0062;0061 064C 064D 064D 064E 0062;0061 064C 064D 064D 064E 0062;0061 064C 064D 064D 064E 0062;0061 064C 064D 064D 064E 0062; # (a◌ٍ◌َ◌ٍ◌ٌb; a◌ٌ◌ٍ◌ٍ◌َb; a◌ٌ◌ٍ◌ٍ◌َb; a◌ٌ◌ٍ◌ٍ◌َb; a◌ٌ◌ٍ◌ٍ◌َb; ) LATIN SMALL LETTER A, ARABIC KASRATAN, ARABIC FATHA, ARABIC KASRATAN, ARABIC DAMMATAN, LATIN SMALL LETTER B +0061 064F 064E 064D 064E 0062;0061 064D 064E 064E 064F 0062;0061 064D 064E 064E 064F 0062;0061 064D 064E 064E 064F 0062;0061 064D 064E 064E 064F 0062; # (a◌ُ◌َ◌ٍ◌َb; a◌ٍ◌َ◌َ◌ُb; a◌ٍ◌َ◌َ◌ُb; a◌ٍ◌َ◌َ◌ُb; a◌ٍ◌َ◌َ◌ُb; ) LATIN SMALL LETTER A, ARABIC DAMMA, ARABIC FATHA, ARABIC KASRATAN, ARABIC FATHA, LATIN SMALL LETTER B +0061 064E 064F 064E 064D 0062;0061 064D 064E 064E 064F 0062;0061 064D 064E 064E 064F 0062;0061 064D 064E 064E 064F 0062;0061 064D 064E 064E 064F 0062; # (a◌َ◌ُ◌َ◌ٍb; a◌ٍ◌َ◌َ◌ُb; a◌ٍ◌َ◌َ◌ُb; a◌ٍ◌َ◌َ◌ُb; a◌ٍ◌َ◌َ◌ُb; ) LATIN SMALL LETTER A, ARABIC FATHA, ARABIC DAMMA, ARABIC FATHA, ARABIC KASRATAN, LATIN SMALL LETTER B +0061 0650 064F 064E 064F 0062;0061 064E 064F 064F 0650 0062;0061 064E 064F 064F 0650 0062;0061 064E 064F 064F 0650 0062;0061 064E 064F 064F 0650 0062; # (a◌ِ◌ُ◌َ◌ُb; a◌َ◌ُ◌ُ◌ِb; a◌َ◌ُ◌ُ◌ِb; a◌َ◌ُ◌ُ◌ِb; a◌َ◌ُ◌ُ◌ِb; ) LATIN SMALL LETTER A, ARABIC KASRA, ARABIC DAMMA, ARABIC FATHA, ARABIC DAMMA, LATIN SMALL LETTER B +0061 064F 0650 064F 064E 0062;0061 064E 064F 064F 0650 0062;0061 064E 064F 064F 0650 0062;0061 064E 064F 064F 0650 0062;0061 064E 064F 064F 0650 0062; # (a◌ُ◌ِ◌ُ◌َb; a◌َ◌ُ◌ُ◌ِb; a◌َ◌ُ◌ُ◌ِb; a◌َ◌ُ◌ُ◌ِb; a◌َ◌ُ◌ُ◌ِb; ) LATIN SMALL LETTER A, ARABIC DAMMA, ARABIC KASRA, ARABIC DAMMA, ARABIC FATHA, LATIN SMALL LETTER B +0061 0651 0650 064F 0650 0062;0061 064F 0650 0650 0651 0062;0061 064F 0650 0650 0651 0062;0061 064F 0650 0650 0651 0062;0061 064F 0650 0650 0651 0062; # (a◌ّ◌ِ◌ُ◌ِb; a◌ُ◌ِ◌ِ◌ّb; a◌ُ◌ِ◌ِ◌ّb; a◌ُ◌ِ◌ِ◌ّb; a◌ُ◌ِ◌ِ◌ّb; ) LATIN SMALL LETTER A, ARABIC SHADDA, ARABIC KASRA, ARABIC DAMMA, ARABIC KASRA, LATIN SMALL LETTER B +0061 0650 0651 0650 064F 0062;0061 064F 0650 0650 0651 0062;0061 064F 0650 0650 0651 0062;0061 064F 0650 0650 0651 0062;0061 064F 0650 0650 0651 0062; # (a◌ِ◌ّ◌ِ◌ُb; a◌ُ◌ِ◌ِ◌ّb; a◌ُ◌ِ◌ِ◌ّb; a◌ُ◌ِ◌ِ◌ّb; a◌ُ◌ِ◌ِ◌ّb; ) LATIN SMALL LETTER A, ARABIC KASRA, ARABIC SHADDA, ARABIC KASRA, ARABIC DAMMA, LATIN SMALL LETTER B +0061 0652 0651 0650 0651 0062;0061 0650 0651 0651 0652 0062;0061 0650 0651 0651 0652 0062;0061 0650 0651 0651 0652 0062;0061 0650 0651 0651 0652 0062; # (a◌ْ◌ّ◌ِ◌ّb; a◌ِ◌ّ◌ّ◌ْb; a◌ِ◌ّ◌ّ◌ْb; a◌ِ◌ّ◌ّ◌ْb; a◌ِ◌ّ◌ّ◌ْb; ) LATIN SMALL LETTER A, ARABIC SUKUN, ARABIC SHADDA, ARABIC KASRA, ARABIC SHADDA, LATIN SMALL LETTER B +0061 0651 0652 0651 0650 0062;0061 0650 0651 0651 0652 0062;0061 0650 0651 0651 0652 0062;0061 0650 0651 0651 0652 0062;0061 0650 0651 0651 0652 0062; # (a◌ّ◌ْ◌ّ◌ِb; a◌ِ◌ّ◌ّ◌ْb; a◌ِ◌ّ◌ّ◌ْb; a◌ِ◌ّ◌ّ◌ْb; a◌ِ◌ّ◌ّ◌ْb; ) LATIN SMALL LETTER A, ARABIC SHADDA, ARABIC SUKUN, ARABIC SHADDA, ARABIC KASRA, LATIN SMALL LETTER B +0061 0670 0652 0651 0652 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062; # (a◌ٰ◌ْ◌ّ◌ْb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; ) LATIN SMALL LETTER A, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC SHADDA, ARABIC SUKUN, LATIN SMALL LETTER B +0061 0652 0670 0652 0651 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062; # (a◌ْ◌ٰ◌ْ◌ّb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; ) LATIN SMALL LETTER A, ARABIC SUKUN, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC SHADDA, LATIN SMALL LETTER B +0061 0315 0300 05AE 0653 0062;00E0 05AE 0653 0315 0062;0061 05AE 0300 0653 0315 0062;00E0 05AE 0653 0315 0062;0061 05AE 0300 0653 0315 0062; # (a◌̕◌̀◌֮◌ٓb; à◌֮◌ٓ◌̕b; a◌֮◌̀◌ٓ◌̕b; à◌֮◌ٓ◌̕b; a◌֮◌̀◌ٓ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MADDAH ABOVE, LATIN SMALL LETTER B +0061 0653 0315 0300 05AE 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062; # (a◌ٓ◌̕◌̀◌֮b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MADDAH ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0654 0062;00E0 05AE 0654 0315 0062;0061 05AE 0300 0654 0315 0062;00E0 05AE 0654 0315 0062;0061 05AE 0300 0654 0315 0062; # (a◌̕◌̀◌֮◌ٔb; à◌֮◌ٔ◌̕b; a◌֮◌̀◌ٔ◌̕b; à◌֮◌ٔ◌̕b; a◌֮◌̀◌ٔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC HAMZA ABOVE, LATIN SMALL LETTER B +0061 0654 0315 0300 05AE 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062; # (a◌ٔ◌̕◌̀◌֮b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC HAMZA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0655 0062;0061 302A 0316 0655 059A 0062;0061 302A 0316 0655 059A 0062;0061 302A 0316 0655 059A 0062;0061 302A 0316 0655 059A 0062; # (a◌֚◌̖◌〪◌ٕb; a◌〪◌̖◌ٕ◌֚b; a◌〪◌̖◌ٕ◌֚b; a◌〪◌̖◌ٕ◌֚b; a◌〪◌̖◌ٕ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC HAMZA BELOW, LATIN SMALL LETTER B +0061 0655 059A 0316 302A 0062;0061 302A 0655 0316 059A 0062;0061 302A 0655 0316 059A 0062;0061 302A 0655 0316 059A 0062;0061 302A 0655 0316 059A 0062; # (a◌ٕ◌֚◌̖◌〪b; a◌〪◌ٕ◌̖◌֚b; a◌〪◌ٕ◌̖◌֚b; a◌〪◌ٕ◌̖◌֚b; a◌〪◌ٕ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0711 0670 0652 0670 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062; # (a◌ܑ◌ٰ◌ْ◌ٰb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; ) LATIN SMALL LETTER A, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER B +0061 0670 0711 0670 0652 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062; # (a◌ٰ◌ܑ◌ٰ◌ْb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; ) LATIN SMALL LETTER A, ARABIC LETTER SUPERSCRIPT ALEF, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D6 0062;00E0 05AE 06D6 0315 0062;0061 05AE 0300 06D6 0315 0062;00E0 05AE 06D6 0315 0062;0061 05AE 0300 06D6 0315 0062; # (a◌̕◌̀◌֮◌ۖb; à◌֮◌ۖ◌̕b; a◌֮◌̀◌ۖ◌̕b; à◌֮◌ۖ◌̕b; a◌֮◌̀◌ۖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA, LATIN SMALL LETTER B +0061 06D6 0315 0300 05AE 0062;0061 05AE 06D6 0300 0315 0062;0061 05AE 06D6 0300 0315 0062;0061 05AE 06D6 0300 0315 0062;0061 05AE 06D6 0300 0315 0062; # (a◌ۖ◌̕◌̀◌֮b; a◌֮◌ۖ◌̀◌̕b; a◌֮◌ۖ◌̀◌̕b; a◌֮◌ۖ◌̀◌̕b; a◌֮◌ۖ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D7 0062;00E0 05AE 06D7 0315 0062;0061 05AE 0300 06D7 0315 0062;00E0 05AE 06D7 0315 0062;0061 05AE 0300 06D7 0315 0062; # (a◌̕◌̀◌֮◌ۗb; à◌֮◌ۗ◌̕b; a◌֮◌̀◌ۗ◌̕b; à◌֮◌ۗ◌̕b; a◌֮◌̀◌ۗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA, LATIN SMALL LETTER B +0061 06D7 0315 0300 05AE 0062;0061 05AE 06D7 0300 0315 0062;0061 05AE 06D7 0300 0315 0062;0061 05AE 06D7 0300 0315 0062;0061 05AE 06D7 0300 0315 0062; # (a◌ۗ◌̕◌̀◌֮b; a◌֮◌ۗ◌̀◌̕b; a◌֮◌ۗ◌̀◌̕b; a◌֮◌ۗ◌̀◌̕b; a◌֮◌ۗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D8 0062;00E0 05AE 06D8 0315 0062;0061 05AE 0300 06D8 0315 0062;00E0 05AE 06D8 0315 0062;0061 05AE 0300 06D8 0315 0062; # (a◌̕◌̀◌֮◌ۘb; à◌֮◌ۘ◌̕b; a◌֮◌̀◌ۘ◌̕b; à◌֮◌ۘ◌̕b; a◌֮◌̀◌ۘ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MEEM INITIAL FORM, LATIN SMALL LETTER B +0061 06D8 0315 0300 05AE 0062;0061 05AE 06D8 0300 0315 0062;0061 05AE 06D8 0300 0315 0062;0061 05AE 06D8 0300 0315 0062;0061 05AE 06D8 0300 0315 0062; # (a◌ۘ◌̕◌̀◌֮b; a◌֮◌ۘ◌̀◌̕b; a◌֮◌ۘ◌̀◌̕b; a◌֮◌ۘ◌̀◌̕b; a◌֮◌ۘ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MEEM INITIAL FORM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D9 0062;00E0 05AE 06D9 0315 0062;0061 05AE 0300 06D9 0315 0062;00E0 05AE 06D9 0315 0062;0061 05AE 0300 06D9 0315 0062; # (a◌̕◌̀◌֮◌ۙb; à◌֮◌ۙ◌̕b; a◌֮◌̀◌ۙ◌̕b; à◌֮◌ۙ◌̕b; a◌֮◌̀◌ۙ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LAM ALEF, LATIN SMALL LETTER B +0061 06D9 0315 0300 05AE 0062;0061 05AE 06D9 0300 0315 0062;0061 05AE 06D9 0300 0315 0062;0061 05AE 06D9 0300 0315 0062;0061 05AE 06D9 0300 0315 0062; # (a◌ۙ◌̕◌̀◌֮b; a◌֮◌ۙ◌̀◌̕b; a◌֮◌ۙ◌̀◌̕b; a◌֮◌ۙ◌̀◌̕b; a◌֮◌ۙ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LAM ALEF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DA 0062;00E0 05AE 06DA 0315 0062;0061 05AE 0300 06DA 0315 0062;00E0 05AE 06DA 0315 0062;0061 05AE 0300 06DA 0315 0062; # (a◌̕◌̀◌֮◌ۚb; à◌֮◌ۚ◌̕b; a◌֮◌̀◌ۚ◌̕b; à◌֮◌ۚ◌̕b; a◌֮◌̀◌ۚ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH JEEM, LATIN SMALL LETTER B +0061 06DA 0315 0300 05AE 0062;0061 05AE 06DA 0300 0315 0062;0061 05AE 06DA 0300 0315 0062;0061 05AE 06DA 0300 0315 0062;0061 05AE 06DA 0300 0315 0062; # (a◌ۚ◌̕◌̀◌֮b; a◌֮◌ۚ◌̀◌̕b; a◌֮◌ۚ◌̀◌̕b; a◌֮◌ۚ◌̀◌̕b; a◌֮◌ۚ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH JEEM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DB 0062;00E0 05AE 06DB 0315 0062;0061 05AE 0300 06DB 0315 0062;00E0 05AE 06DB 0315 0062;0061 05AE 0300 06DB 0315 0062; # (a◌̕◌̀◌֮◌ۛb; à◌֮◌ۛ◌̕b; a◌֮◌̀◌ۛ◌̕b; à◌֮◌ۛ◌̕b; a◌֮◌̀◌ۛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH THREE DOTS, LATIN SMALL LETTER B +0061 06DB 0315 0300 05AE 0062;0061 05AE 06DB 0300 0315 0062;0061 05AE 06DB 0300 0315 0062;0061 05AE 06DB 0300 0315 0062;0061 05AE 06DB 0300 0315 0062; # (a◌ۛ◌̕◌̀◌֮b; a◌֮◌ۛ◌̀◌̕b; a◌֮◌ۛ◌̀◌̕b; a◌֮◌ۛ◌̀◌̕b; a◌֮◌ۛ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH THREE DOTS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DC 0062;00E0 05AE 06DC 0315 0062;0061 05AE 0300 06DC 0315 0062;00E0 05AE 06DC 0315 0062;0061 05AE 0300 06DC 0315 0062; # (a◌̕◌̀◌֮◌ۜb; à◌֮◌ۜ◌̕b; a◌֮◌̀◌ۜ◌̕b; à◌֮◌ۜ◌̕b; a◌֮◌̀◌ۜ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SEEN, LATIN SMALL LETTER B +0061 06DC 0315 0300 05AE 0062;0061 05AE 06DC 0300 0315 0062;0061 05AE 06DC 0300 0315 0062;0061 05AE 06DC 0300 0315 0062;0061 05AE 06DC 0300 0315 0062; # (a◌ۜ◌̕◌̀◌֮b; a◌֮◌ۜ◌̀◌̕b; a◌֮◌ۜ◌̀◌̕b; a◌֮◌ۜ◌̀◌̕b; a◌֮◌ۜ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SEEN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DF 0062;00E0 05AE 06DF 0315 0062;0061 05AE 0300 06DF 0315 0062;00E0 05AE 06DF 0315 0062;0061 05AE 0300 06DF 0315 0062; # (a◌̕◌̀◌֮◌۟b; à◌֮◌۟◌̕b; a◌֮◌̀◌۟◌̕b; à◌֮◌۟◌̕b; a◌֮◌̀◌۟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH ROUNDED ZERO, LATIN SMALL LETTER B +0061 06DF 0315 0300 05AE 0062;0061 05AE 06DF 0300 0315 0062;0061 05AE 06DF 0300 0315 0062;0061 05AE 06DF 0300 0315 0062;0061 05AE 06DF 0300 0315 0062; # (a◌۟◌̕◌̀◌֮b; a◌֮◌۟◌̀◌̕b; a◌֮◌۟◌̀◌̕b; a◌֮◌۟◌̀◌̕b; a◌֮◌۟◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH ROUNDED ZERO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E0 0062;00E0 05AE 06E0 0315 0062;0061 05AE 0300 06E0 0315 0062;00E0 05AE 06E0 0315 0062;0061 05AE 0300 06E0 0315 0062; # (a◌̕◌̀◌֮◌۠b; à◌֮◌۠◌̕b; a◌֮◌̀◌۠◌̕b; à◌֮◌۠◌̕b; a◌֮◌̀◌۠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO, LATIN SMALL LETTER B +0061 06E0 0315 0300 05AE 0062;0061 05AE 06E0 0300 0315 0062;0061 05AE 06E0 0300 0315 0062;0061 05AE 06E0 0300 0315 0062;0061 05AE 06E0 0300 0315 0062; # (a◌۠◌̕◌̀◌֮b; a◌֮◌۠◌̀◌̕b; a◌֮◌۠◌̀◌̕b; a◌֮◌۠◌̀◌̕b; a◌֮◌۠◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E1 0062;00E0 05AE 06E1 0315 0062;0061 05AE 0300 06E1 0315 0062;00E0 05AE 06E1 0315 0062;0061 05AE 0300 06E1 0315 0062; # (a◌̕◌̀◌֮◌ۡb; à◌֮◌ۡ◌̕b; a◌֮◌̀◌ۡ◌̕b; à◌֮◌ۡ◌̕b; a◌֮◌̀◌ۡ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH DOTLESS HEAD OF KHAH, LATIN SMALL LETTER B +0061 06E1 0315 0300 05AE 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062; # (a◌ۡ◌̕◌̀◌֮b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH DOTLESS HEAD OF KHAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E2 0062;00E0 05AE 06E2 0315 0062;0061 05AE 0300 06E2 0315 0062;00E0 05AE 06E2 0315 0062;0061 05AE 0300 06E2 0315 0062; # (a◌̕◌̀◌֮◌ۢb; à◌֮◌ۢ◌̕b; a◌֮◌̀◌ۢ◌̕b; à◌֮◌ۢ◌̕b; a◌֮◌̀◌ۢ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MEEM ISOLATED FORM, LATIN SMALL LETTER B +0061 06E2 0315 0300 05AE 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062; # (a◌ۢ◌̕◌̀◌֮b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MEEM ISOLATED FORM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 06E3 0062;0061 302A 0316 06E3 059A 0062;0061 302A 0316 06E3 059A 0062;0061 302A 0316 06E3 059A 0062;0061 302A 0316 06E3 059A 0062; # (a◌֚◌̖◌〪◌ۣb; a◌〪◌̖◌ۣ◌֚b; a◌〪◌̖◌ۣ◌֚b; a◌〪◌̖◌ۣ◌֚b; a◌〪◌̖◌ۣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW SEEN, LATIN SMALL LETTER B +0061 06E3 059A 0316 302A 0062;0061 302A 06E3 0316 059A 0062;0061 302A 06E3 0316 059A 0062;0061 302A 06E3 0316 059A 0062;0061 302A 06E3 0316 059A 0062; # (a◌ۣ◌֚◌̖◌〪b; a◌〪◌ۣ◌̖◌֚b; a◌〪◌ۣ◌̖◌֚b; a◌〪◌ۣ◌̖◌֚b; a◌〪◌ۣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW SEEN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E4 0062;00E0 05AE 06E4 0315 0062;0061 05AE 0300 06E4 0315 0062;00E0 05AE 06E4 0315 0062;0061 05AE 0300 06E4 0315 0062; # (a◌̕◌̀◌֮◌ۤb; à◌֮◌ۤ◌̕b; a◌֮◌̀◌ۤ◌̕b; à◌֮◌ۤ◌̕b; a◌֮◌̀◌ۤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MADDA, LATIN SMALL LETTER B +0061 06E4 0315 0300 05AE 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062; # (a◌ۤ◌̕◌̀◌֮b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E7 0062;00E0 05AE 06E7 0315 0062;0061 05AE 0300 06E7 0315 0062;00E0 05AE 06E7 0315 0062;0061 05AE 0300 06E7 0315 0062; # (a◌̕◌̀◌֮◌ۧb; à◌֮◌ۧ◌̕b; a◌֮◌̀◌ۧ◌̕b; à◌֮◌ۧ◌̕b; a◌֮◌̀◌ۧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH YEH, LATIN SMALL LETTER B +0061 06E7 0315 0300 05AE 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062; # (a◌ۧ◌̕◌̀◌֮b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH YEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E8 0062;00E0 05AE 06E8 0315 0062;0061 05AE 0300 06E8 0315 0062;00E0 05AE 06E8 0315 0062;0061 05AE 0300 06E8 0315 0062; # (a◌̕◌̀◌֮◌ۨb; à◌֮◌ۨ◌̕b; a◌֮◌̀◌ۨ◌̕b; à◌֮◌ۨ◌̕b; a◌֮◌̀◌ۨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH NOON, LATIN SMALL LETTER B +0061 06E8 0315 0300 05AE 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062; # (a◌ۨ◌̕◌̀◌֮b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH NOON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 06EA 0062;0061 302A 0316 06EA 059A 0062;0061 302A 0316 06EA 059A 0062;0061 302A 0316 06EA 059A 0062;0061 302A 0316 06EA 059A 0062; # (a◌֚◌̖◌〪◌۪b; a◌〪◌̖◌۪◌֚b; a◌〪◌̖◌۪◌֚b; a◌〪◌̖◌۪◌֚b; a◌〪◌̖◌۪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC EMPTY CENTRE LOW STOP, LATIN SMALL LETTER B +0061 06EA 059A 0316 302A 0062;0061 302A 06EA 0316 059A 0062;0061 302A 06EA 0316 059A 0062;0061 302A 06EA 0316 059A 0062;0061 302A 06EA 0316 059A 0062; # (a◌۪◌֚◌̖◌〪b; a◌〪◌۪◌̖◌֚b; a◌〪◌۪◌̖◌֚b; a◌〪◌۪◌̖◌֚b; a◌〪◌۪◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE LOW STOP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 06EB 0062;00E0 05AE 06EB 0315 0062;0061 05AE 0300 06EB 0315 0062;00E0 05AE 06EB 0315 0062;0061 05AE 0300 06EB 0315 0062; # (a◌̕◌̀◌֮◌۫b; à◌֮◌۫◌̕b; a◌֮◌̀◌۫◌̕b; à◌֮◌۫◌̕b; a◌֮◌̀◌۫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC EMPTY CENTRE HIGH STOP, LATIN SMALL LETTER B +0061 06EB 0315 0300 05AE 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062; # (a◌۫◌̕◌̀◌֮b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE HIGH STOP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06EC 0062;00E0 05AE 06EC 0315 0062;0061 05AE 0300 06EC 0315 0062;00E0 05AE 06EC 0315 0062;0061 05AE 0300 06EC 0315 0062; # (a◌̕◌̀◌֮◌۬b; à◌֮◌۬◌̕b; a◌֮◌̀◌۬◌̕b; à◌֮◌۬◌̕b; a◌֮◌̀◌۬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE, LATIN SMALL LETTER B +0061 06EC 0315 0300 05AE 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062; # (a◌۬◌̕◌̀◌֮b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 06ED 0062;0061 302A 0316 06ED 059A 0062;0061 302A 0316 06ED 059A 0062;0061 302A 0316 06ED 059A 0062;0061 302A 0316 06ED 059A 0062; # (a◌֚◌̖◌〪◌ۭb; a◌〪◌̖◌ۭ◌֚b; a◌〪◌̖◌ۭ◌֚b; a◌〪◌̖◌ۭ◌֚b; a◌〪◌̖◌ۭ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW MEEM, LATIN SMALL LETTER B +0061 06ED 059A 0316 302A 0062;0061 302A 06ED 0316 059A 0062;0061 302A 06ED 0316 059A 0062;0061 302A 06ED 0316 059A 0062;0061 302A 06ED 0316 059A 0062; # (a◌ۭ◌֚◌̖◌〪b; a◌〪◌ۭ◌̖◌֚b; a◌〪◌ۭ◌̖◌֚b; a◌〪◌ۭ◌̖◌֚b; a◌〪◌ۭ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW MEEM, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0C55 0711 0670 0711 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062; # (a◌ౕ◌ܑ◌ٰ◌ܑb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; ) LATIN SMALL LETTER A, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, SYRIAC LETTER SUPERSCRIPT ALAPH, LATIN SMALL LETTER B +0061 0711 0C55 0711 0670 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062; # (a◌ܑ◌ౕ◌ܑ◌ٰb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; ) LATIN SMALL LETTER A, SYRIAC LETTER SUPERSCRIPT ALAPH, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER B +0061 0315 0300 05AE 0730 0062;00E0 05AE 0730 0315 0062;0061 05AE 0300 0730 0315 0062;00E0 05AE 0730 0315 0062;0061 05AE 0300 0730 0315 0062; # (a◌̕◌̀◌֮◌ܰb; à◌֮◌ܰ◌̕b; a◌֮◌̀◌ܰ◌̕b; à◌֮◌ܰ◌̕b; a◌֮◌̀◌ܰ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC PTHAHA ABOVE, LATIN SMALL LETTER B +0061 0730 0315 0300 05AE 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062; # (a◌ܰ◌̕◌̀◌֮b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0731 0062;0061 302A 0316 0731 059A 0062;0061 302A 0316 0731 059A 0062;0061 302A 0316 0731 059A 0062;0061 302A 0316 0731 059A 0062; # (a◌֚◌̖◌〪◌ܱb; a◌〪◌̖◌ܱ◌֚b; a◌〪◌̖◌ܱ◌֚b; a◌〪◌̖◌ܱ◌֚b; a◌〪◌̖◌ܱ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC PTHAHA BELOW, LATIN SMALL LETTER B +0061 0731 059A 0316 302A 0062;0061 302A 0731 0316 059A 0062;0061 302A 0731 0316 059A 0062;0061 302A 0731 0316 059A 0062;0061 302A 0731 0316 059A 0062; # (a◌ܱ◌֚◌̖◌〪b; a◌〪◌ܱ◌̖◌֚b; a◌〪◌ܱ◌̖◌֚b; a◌〪◌ܱ◌̖◌֚b; a◌〪◌ܱ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0732 0062;00E0 05AE 0732 0315 0062;0061 05AE 0300 0732 0315 0062;00E0 05AE 0732 0315 0062;0061 05AE 0300 0732 0315 0062; # (a◌̕◌̀◌֮◌ܲb; à◌֮◌ܲ◌̕b; a◌֮◌̀◌ܲ◌̕b; à◌֮◌ܲ◌̕b; a◌֮◌̀◌ܲ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC PTHAHA DOTTED, LATIN SMALL LETTER B +0061 0732 0315 0300 05AE 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062; # (a◌ܲ◌̕◌̀◌֮b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA DOTTED, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0733 0062;00E0 05AE 0733 0315 0062;0061 05AE 0300 0733 0315 0062;00E0 05AE 0733 0315 0062;0061 05AE 0300 0733 0315 0062; # (a◌̕◌̀◌֮◌ܳb; à◌֮◌ܳ◌̕b; a◌֮◌̀◌ܳ◌̕b; à◌֮◌ܳ◌̕b; a◌֮◌̀◌ܳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ZQAPHA ABOVE, LATIN SMALL LETTER B +0061 0733 0315 0300 05AE 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062; # (a◌ܳ◌̕◌̀◌֮b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0734 0062;0061 302A 0316 0734 059A 0062;0061 302A 0316 0734 059A 0062;0061 302A 0316 0734 059A 0062;0061 302A 0316 0734 059A 0062; # (a◌֚◌̖◌〪◌ܴb; a◌〪◌̖◌ܴ◌֚b; a◌〪◌̖◌ܴ◌֚b; a◌〪◌̖◌ܴ◌֚b; a◌〪◌̖◌ܴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC ZQAPHA BELOW, LATIN SMALL LETTER B +0061 0734 059A 0316 302A 0062;0061 302A 0734 0316 059A 0062;0061 302A 0734 0316 059A 0062;0061 302A 0734 0316 059A 0062;0061 302A 0734 0316 059A 0062; # (a◌ܴ◌֚◌̖◌〪b; a◌〪◌ܴ◌̖◌֚b; a◌〪◌ܴ◌̖◌֚b; a◌〪◌ܴ◌̖◌֚b; a◌〪◌ܴ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0735 0062;00E0 05AE 0735 0315 0062;0061 05AE 0300 0735 0315 0062;00E0 05AE 0735 0315 0062;0061 05AE 0300 0735 0315 0062; # (a◌̕◌̀◌֮◌ܵb; à◌֮◌ܵ◌̕b; a◌֮◌̀◌ܵ◌̕b; à◌֮◌ܵ◌̕b; a◌֮◌̀◌ܵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ZQAPHA DOTTED, LATIN SMALL LETTER B +0061 0735 0315 0300 05AE 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062; # (a◌ܵ◌̕◌̀◌֮b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA DOTTED, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0736 0062;00E0 05AE 0736 0315 0062;0061 05AE 0300 0736 0315 0062;00E0 05AE 0736 0315 0062;0061 05AE 0300 0736 0315 0062; # (a◌̕◌̀◌֮◌ܶb; à◌֮◌ܶ◌̕b; a◌֮◌̀◌ܶ◌̕b; à◌֮◌ܶ◌̕b; a◌֮◌̀◌ܶ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC RBASA ABOVE, LATIN SMALL LETTER B +0061 0736 0315 0300 05AE 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062; # (a◌ܶ◌̕◌̀◌֮b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC RBASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0737 0062;0061 302A 0316 0737 059A 0062;0061 302A 0316 0737 059A 0062;0061 302A 0316 0737 059A 0062;0061 302A 0316 0737 059A 0062; # (a◌֚◌̖◌〪◌ܷb; a◌〪◌̖◌ܷ◌֚b; a◌〪◌̖◌ܷ◌֚b; a◌〪◌̖◌ܷ◌֚b; a◌〪◌̖◌ܷ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC RBASA BELOW, LATIN SMALL LETTER B +0061 0737 059A 0316 302A 0062;0061 302A 0737 0316 059A 0062;0061 302A 0737 0316 059A 0062;0061 302A 0737 0316 059A 0062;0061 302A 0737 0316 059A 0062; # (a◌ܷ◌֚◌̖◌〪b; a◌〪◌ܷ◌̖◌֚b; a◌〪◌ܷ◌̖◌֚b; a◌〪◌ܷ◌̖◌֚b; a◌〪◌ܷ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0738 0062;0061 302A 0316 0738 059A 0062;0061 302A 0316 0738 059A 0062;0061 302A 0316 0738 059A 0062;0061 302A 0316 0738 059A 0062; # (a◌֚◌̖◌〪◌ܸb; a◌〪◌̖◌ܸ◌֚b; a◌〪◌̖◌ܸ◌֚b; a◌〪◌̖◌ܸ◌֚b; a◌〪◌̖◌ܸ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC DOTTED ZLAMA HORIZONTAL, LATIN SMALL LETTER B +0061 0738 059A 0316 302A 0062;0061 302A 0738 0316 059A 0062;0061 302A 0738 0316 059A 0062;0061 302A 0738 0316 059A 0062;0061 302A 0738 0316 059A 0062; # (a◌ܸ◌֚◌̖◌〪b; a◌〪◌ܸ◌̖◌֚b; a◌〪◌ܸ◌̖◌֚b; a◌〪◌ܸ◌̖◌֚b; a◌〪◌ܸ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA HORIZONTAL, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0739 0062;0061 302A 0316 0739 059A 0062;0061 302A 0316 0739 059A 0062;0061 302A 0316 0739 059A 0062;0061 302A 0316 0739 059A 0062; # (a◌֚◌̖◌〪◌ܹb; a◌〪◌̖◌ܹ◌֚b; a◌〪◌̖◌ܹ◌֚b; a◌〪◌̖◌ܹ◌֚b; a◌〪◌̖◌ܹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC DOTTED ZLAMA ANGULAR, LATIN SMALL LETTER B +0061 0739 059A 0316 302A 0062;0061 302A 0739 0316 059A 0062;0061 302A 0739 0316 059A 0062;0061 302A 0739 0316 059A 0062;0061 302A 0739 0316 059A 0062; # (a◌ܹ◌֚◌̖◌〪b; a◌〪◌ܹ◌̖◌֚b; a◌〪◌ܹ◌̖◌֚b; a◌〪◌ܹ◌̖◌֚b; a◌〪◌ܹ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA ANGULAR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 073A 0062;00E0 05AE 073A 0315 0062;0061 05AE 0300 073A 0315 0062;00E0 05AE 073A 0315 0062;0061 05AE 0300 073A 0315 0062; # (a◌̕◌̀◌֮◌ܺb; à◌֮◌ܺ◌̕b; a◌֮◌̀◌ܺ◌̕b; à◌֮◌ܺ◌̕b; a◌֮◌̀◌ܺ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC HBASA ABOVE, LATIN SMALL LETTER B +0061 073A 0315 0300 05AE 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062; # (a◌ܺ◌̕◌̀◌֮b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC HBASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 073B 0062;0061 302A 0316 073B 059A 0062;0061 302A 0316 073B 059A 0062;0061 302A 0316 073B 059A 0062;0061 302A 0316 073B 059A 0062; # (a◌֚◌̖◌〪◌ܻb; a◌〪◌̖◌ܻ◌֚b; a◌〪◌̖◌ܻ◌֚b; a◌〪◌̖◌ܻ◌֚b; a◌〪◌̖◌ܻ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC HBASA BELOW, LATIN SMALL LETTER B +0061 073B 059A 0316 302A 0062;0061 302A 073B 0316 059A 0062;0061 302A 073B 0316 059A 0062;0061 302A 073B 0316 059A 0062;0061 302A 073B 0316 059A 0062; # (a◌ܻ◌֚◌̖◌〪b; a◌〪◌ܻ◌̖◌֚b; a◌〪◌ܻ◌̖◌֚b; a◌〪◌ܻ◌̖◌֚b; a◌〪◌ܻ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 073C 0062;0061 302A 0316 073C 059A 0062;0061 302A 0316 073C 059A 0062;0061 302A 0316 073C 059A 0062;0061 302A 0316 073C 059A 0062; # (a◌֚◌̖◌〪◌ܼb; a◌〪◌̖◌ܼ◌֚b; a◌〪◌̖◌ܼ◌֚b; a◌〪◌̖◌ܼ◌֚b; a◌〪◌̖◌ܼ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC HBASA-ESASA DOTTED, LATIN SMALL LETTER B +0061 073C 059A 0316 302A 0062;0061 302A 073C 0316 059A 0062;0061 302A 073C 0316 059A 0062;0061 302A 073C 0316 059A 0062;0061 302A 073C 0316 059A 0062; # (a◌ܼ◌֚◌̖◌〪b; a◌〪◌ܼ◌̖◌֚b; a◌〪◌ܼ◌̖◌֚b; a◌〪◌ܼ◌̖◌֚b; a◌〪◌ܼ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA-ESASA DOTTED, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 073D 0062;00E0 05AE 073D 0315 0062;0061 05AE 0300 073D 0315 0062;00E0 05AE 073D 0315 0062;0061 05AE 0300 073D 0315 0062; # (a◌̕◌̀◌֮◌ܽb; à◌֮◌ܽ◌̕b; a◌֮◌̀◌ܽ◌̕b; à◌֮◌ܽ◌̕b; a◌֮◌̀◌ܽ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ESASA ABOVE, LATIN SMALL LETTER B +0061 073D 0315 0300 05AE 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062; # (a◌ܽ◌̕◌̀◌֮b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ESASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 073E 0062;0061 302A 0316 073E 059A 0062;0061 302A 0316 073E 059A 0062;0061 302A 0316 073E 059A 0062;0061 302A 0316 073E 059A 0062; # (a◌֚◌̖◌〪◌ܾb; a◌〪◌̖◌ܾ◌֚b; a◌〪◌̖◌ܾ◌֚b; a◌〪◌̖◌ܾ◌֚b; a◌〪◌̖◌ܾ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC ESASA BELOW, LATIN SMALL LETTER B +0061 073E 059A 0316 302A 0062;0061 302A 073E 0316 059A 0062;0061 302A 073E 0316 059A 0062;0061 302A 073E 0316 059A 0062;0061 302A 073E 0316 059A 0062; # (a◌ܾ◌֚◌̖◌〪b; a◌〪◌ܾ◌̖◌֚b; a◌〪◌ܾ◌̖◌֚b; a◌〪◌ܾ◌̖◌֚b; a◌〪◌ܾ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ESASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 073F 0062;00E0 05AE 073F 0315 0062;0061 05AE 0300 073F 0315 0062;00E0 05AE 073F 0315 0062;0061 05AE 0300 073F 0315 0062; # (a◌̕◌̀◌֮◌ܿb; à◌֮◌ܿ◌̕b; a◌֮◌̀◌ܿ◌̕b; à◌֮◌ܿ◌̕b; a◌֮◌̀◌ܿ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC RWAHA, LATIN SMALL LETTER B +0061 073F 0315 0300 05AE 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062; # (a◌ܿ◌̕◌̀◌֮b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC RWAHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0740 0062;00E0 05AE 0740 0315 0062;0061 05AE 0300 0740 0315 0062;00E0 05AE 0740 0315 0062;0061 05AE 0300 0740 0315 0062; # (a◌̕◌̀◌֮◌݀b; à◌֮◌݀◌̕b; a◌֮◌̀◌݀◌̕b; à◌֮◌݀◌̕b; a◌֮◌̀◌݀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC FEMININE DOT, LATIN SMALL LETTER B +0061 0740 0315 0300 05AE 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062; # (a◌݀◌̕◌̀◌֮b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC FEMININE DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0741 0062;00E0 05AE 0741 0315 0062;0061 05AE 0300 0741 0315 0062;00E0 05AE 0741 0315 0062;0061 05AE 0300 0741 0315 0062; # (a◌̕◌̀◌֮◌݁b; à◌֮◌݁◌̕b; a◌֮◌̀◌݁◌̕b; à◌֮◌݁◌̕b; a◌֮◌̀◌݁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC QUSHSHAYA, LATIN SMALL LETTER B +0061 0741 0315 0300 05AE 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062; # (a◌݁◌̕◌̀◌֮b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC QUSHSHAYA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0742 0062;0061 302A 0316 0742 059A 0062;0061 302A 0316 0742 059A 0062;0061 302A 0316 0742 059A 0062;0061 302A 0316 0742 059A 0062; # (a◌֚◌̖◌〪◌݂b; a◌〪◌̖◌݂◌֚b; a◌〪◌̖◌݂◌֚b; a◌〪◌̖◌݂◌֚b; a◌〪◌̖◌݂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC RUKKAKHA, LATIN SMALL LETTER B +0061 0742 059A 0316 302A 0062;0061 302A 0742 0316 059A 0062;0061 302A 0742 0316 059A 0062;0061 302A 0742 0316 059A 0062;0061 302A 0742 0316 059A 0062; # (a◌݂◌֚◌̖◌〪b; a◌〪◌݂◌̖◌֚b; a◌〪◌݂◌̖◌֚b; a◌〪◌݂◌̖◌֚b; a◌〪◌݂◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RUKKAKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0743 0062;00E0 05AE 0743 0315 0062;0061 05AE 0300 0743 0315 0062;00E0 05AE 0743 0315 0062;0061 05AE 0300 0743 0315 0062; # (a◌̕◌̀◌֮◌݃b; à◌֮◌݃◌̕b; a◌֮◌̀◌݃◌̕b; à◌֮◌݃◌̕b; a◌֮◌̀◌݃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC TWO VERTICAL DOTS ABOVE, LATIN SMALL LETTER B +0061 0743 0315 0300 05AE 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062; # (a◌݃◌̕◌̀◌֮b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0744 0062;0061 302A 0316 0744 059A 0062;0061 302A 0316 0744 059A 0062;0061 302A 0316 0744 059A 0062;0061 302A 0316 0744 059A 0062; # (a◌֚◌̖◌〪◌݄b; a◌〪◌̖◌݄◌֚b; a◌〪◌̖◌݄◌֚b; a◌〪◌̖◌݄◌֚b; a◌〪◌̖◌݄◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC TWO VERTICAL DOTS BELOW, LATIN SMALL LETTER B +0061 0744 059A 0316 302A 0062;0061 302A 0744 0316 059A 0062;0061 302A 0744 0316 059A 0062;0061 302A 0744 0316 059A 0062;0061 302A 0744 0316 059A 0062; # (a◌݄◌֚◌̖◌〪b; a◌〪◌݄◌̖◌֚b; a◌〪◌݄◌̖◌֚b; a◌〪◌݄◌̖◌֚b; a◌〪◌݄◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0745 0062;00E0 05AE 0745 0315 0062;0061 05AE 0300 0745 0315 0062;00E0 05AE 0745 0315 0062;0061 05AE 0300 0745 0315 0062; # (a◌̕◌̀◌֮◌݅b; à◌֮◌݅◌̕b; a◌֮◌̀◌݅◌̕b; à◌֮◌݅◌̕b; a◌֮◌̀◌݅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC THREE DOTS ABOVE, LATIN SMALL LETTER B +0061 0745 0315 0300 05AE 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062; # (a◌݅◌̕◌̀◌֮b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0746 0062;0061 302A 0316 0746 059A 0062;0061 302A 0316 0746 059A 0062;0061 302A 0316 0746 059A 0062;0061 302A 0316 0746 059A 0062; # (a◌֚◌̖◌〪◌݆b; a◌〪◌̖◌݆◌֚b; a◌〪◌̖◌݆◌֚b; a◌〪◌̖◌݆◌֚b; a◌〪◌̖◌݆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC THREE DOTS BELOW, LATIN SMALL LETTER B +0061 0746 059A 0316 302A 0062;0061 302A 0746 0316 059A 0062;0061 302A 0746 0316 059A 0062;0061 302A 0746 0316 059A 0062;0061 302A 0746 0316 059A 0062; # (a◌݆◌֚◌̖◌〪b; a◌〪◌݆◌̖◌֚b; a◌〪◌݆◌̖◌֚b; a◌〪◌݆◌̖◌֚b; a◌〪◌݆◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0747 0062;00E0 05AE 0747 0315 0062;0061 05AE 0300 0747 0315 0062;00E0 05AE 0747 0315 0062;0061 05AE 0300 0747 0315 0062; # (a◌̕◌̀◌֮◌݇b; à◌֮◌݇◌̕b; a◌֮◌̀◌݇◌̕b; à◌֮◌݇◌̕b; a◌֮◌̀◌݇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC OBLIQUE LINE ABOVE, LATIN SMALL LETTER B +0061 0747 0315 0300 05AE 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062; # (a◌݇◌̕◌̀◌֮b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0748 0062;0061 302A 0316 0748 059A 0062;0061 302A 0316 0748 059A 0062;0061 302A 0316 0748 059A 0062;0061 302A 0316 0748 059A 0062; # (a◌֚◌̖◌〪◌݈b; a◌〪◌̖◌݈◌֚b; a◌〪◌̖◌݈◌֚b; a◌〪◌̖◌݈◌֚b; a◌〪◌̖◌݈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC OBLIQUE LINE BELOW, LATIN SMALL LETTER B +0061 0748 059A 0316 302A 0062;0061 302A 0748 0316 059A 0062;0061 302A 0748 0316 059A 0062;0061 302A 0748 0316 059A 0062;0061 302A 0748 0316 059A 0062; # (a◌݈◌֚◌̖◌〪b; a◌〪◌݈◌̖◌֚b; a◌〪◌݈◌̖◌֚b; a◌〪◌݈◌̖◌֚b; a◌〪◌݈◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0749 0062;00E0 05AE 0749 0315 0062;0061 05AE 0300 0749 0315 0062;00E0 05AE 0749 0315 0062;0061 05AE 0300 0749 0315 0062; # (a◌̕◌̀◌֮◌݉b; à◌֮◌݉◌̕b; a◌֮◌̀◌݉◌̕b; à◌֮◌݉◌̕b; a◌֮◌̀◌݉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC MUSIC, LATIN SMALL LETTER B +0061 0749 0315 0300 05AE 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062; # (a◌݉◌̕◌̀◌֮b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC MUSIC, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 074A 0062;00E0 05AE 074A 0315 0062;0061 05AE 0300 074A 0315 0062;00E0 05AE 074A 0315 0062;0061 05AE 0300 074A 0315 0062; # (a◌̕◌̀◌֮◌݊b; à◌֮◌݊◌̕b; a◌֮◌̀◌݊◌̕b; à◌֮◌݊◌̕b; a◌֮◌̀◌݊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC BARREKH, LATIN SMALL LETTER B +0061 074A 0315 0300 05AE 0062;0061 05AE 074A 0300 0315 0062;0061 05AE 074A 0300 0315 0062;0061 05AE 074A 0300 0315 0062;0061 05AE 074A 0300 0315 0062; # (a◌݊◌̕◌̀◌֮b; a◌֮◌݊◌̀◌̕b; a◌֮◌݊◌̀◌̕b; a◌֮◌݊◌̀◌̕b; a◌֮◌݊◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC BARREKH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 0334 093C 0062;0061 0334 093C 093C 3099 0062;0061 0334 093C 093C 3099 0062;0061 0334 093C 093C 3099 0062;0061 0334 093C 093C 3099 0062; # (a◌゙◌़◌̴◌़b; a◌̴◌़◌़◌゙b; a◌̴◌़◌़◌゙b; a◌̴◌़◌़◌゙b; a◌̴◌़◌़◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, DEVANAGARI SIGN NUKTA, LATIN SMALL LETTER B +0061 093C 3099 093C 0334 0062;0061 0334 093C 093C 3099 0062;0061 0334 093C 093C 3099 0062;0061 0334 093C 093C 3099 0062;0061 0334 093C 093C 3099 0062; # (a◌़◌゙◌़◌̴b; a◌̴◌़◌़◌゙b; a◌̴◌़◌़◌゙b; a◌̴◌़◌़◌゙b; a◌̴◌़◌़◌゙b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 094D 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062; # (a◌ְ◌्◌゙◌्b; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN VIRAMA, LATIN SMALL LETTER B +0061 094D 05B0 094D 3099 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062; # (a◌्◌ְ◌्◌゙b; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0951 0062;00E0 05AE 0951 0315 0062;0061 05AE 0300 0951 0315 0062;00E0 05AE 0951 0315 0062;0061 05AE 0300 0951 0315 0062; # (a◌̕◌̀◌֮◌॑b; à◌֮◌॑◌̕b; a◌֮◌̀◌॑◌̕b; à◌֮◌॑◌̕b; a◌֮◌̀◌॑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI STRESS SIGN UDATTA, LATIN SMALL LETTER B +0061 0951 0315 0300 05AE 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062; # (a◌॑◌̕◌̀◌֮b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN UDATTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0952 0062;0061 302A 0316 0952 059A 0062;0061 302A 0316 0952 059A 0062;0061 302A 0316 0952 059A 0062;0061 302A 0316 0952 059A 0062; # (a◌֚◌̖◌〪◌॒b; a◌〪◌̖◌॒◌֚b; a◌〪◌̖◌॒◌֚b; a◌〪◌̖◌॒◌֚b; a◌〪◌̖◌॒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, DEVANAGARI STRESS SIGN ANUDATTA, LATIN SMALL LETTER B +0061 0952 059A 0316 302A 0062;0061 302A 0952 0316 059A 0062;0061 302A 0952 0316 059A 0062;0061 302A 0952 0316 059A 0062;0061 302A 0952 0316 059A 0062; # (a◌॒◌֚◌̖◌〪b; a◌〪◌॒◌̖◌֚b; a◌〪◌॒◌̖◌֚b; a◌〪◌॒◌̖◌֚b; a◌〪◌॒◌̖◌֚b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0953 0062;00E0 05AE 0953 0315 0062;0061 05AE 0300 0953 0315 0062;00E0 05AE 0953 0315 0062;0061 05AE 0300 0953 0315 0062; # (a◌̕◌̀◌֮◌॓b; à◌֮◌॓◌̕b; a◌֮◌̀◌॓◌̕b; à◌֮◌॓◌̕b; a◌֮◌̀◌॓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI GRAVE ACCENT, LATIN SMALL LETTER B +0061 0953 0315 0300 05AE 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062; # (a◌॓◌̕◌̀◌֮b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0954 0062;00E0 05AE 0954 0315 0062;0061 05AE 0300 0954 0315 0062;00E0 05AE 0954 0315 0062;0061 05AE 0300 0954 0315 0062; # (a◌̕◌̀◌֮◌॔b; à◌֮◌॔◌̕b; a◌֮◌̀◌॔◌̕b; à◌֮◌॔◌̕b; a◌֮◌̀◌॔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI ACUTE ACCENT, LATIN SMALL LETTER B +0061 0954 0315 0300 05AE 0062;0061 05AE 0954 0300 0315 0062;0061 05AE 0954 0300 0315 0062;0061 05AE 0954 0300 0315 0062;0061 05AE 0954 0300 0315 0062; # (a◌॔◌̕◌̀◌֮b; a◌֮◌॔◌̀◌̕b; a◌֮◌॔◌̀◌̕b; a◌֮◌॔◌̀◌̕b; a◌֮◌॔◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 0334 09BC 0062;0061 0334 093C 09BC 3099 0062;0061 0334 093C 09BC 3099 0062;0061 0334 093C 09BC 3099 0062;0061 0334 093C 09BC 3099 0062; # (a◌゙◌़◌̴◌়b; a◌̴◌़◌়◌゙b; a◌̴◌़◌়◌゙b; a◌̴◌़◌়◌゙b; a◌̴◌़◌়◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BENGALI SIGN NUKTA, LATIN SMALL LETTER B +0061 09BC 3099 093C 0334 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062; # (a◌়◌゙◌़◌̴b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; ) LATIN SMALL LETTER A, BENGALI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 09CD 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062; # (a◌ְ◌्◌゙◌্b; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BENGALI SIGN VIRAMA, LATIN SMALL LETTER B +0061 09CD 05B0 094D 3099 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062; # (a◌্◌ְ◌्◌゙b; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; ) LATIN SMALL LETTER A, BENGALI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 0A3C 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062; # (a◌゙◌़◌̴◌਼b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, GURMUKHI SIGN NUKTA, LATIN SMALL LETTER B +0061 0A3C 3099 093C 0334 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062; # (a◌਼◌゙◌़◌̴b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; ) LATIN SMALL LETTER A, GURMUKHI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 0A4D 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062; # (a◌ְ◌्◌゙◌੍b; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GURMUKHI SIGN VIRAMA, LATIN SMALL LETTER B +0061 0A4D 05B0 094D 3099 0062;0061 3099 0A4D 094D 05B0 0062;0061 3099 0A4D 094D 05B0 0062;0061 3099 0A4D 094D 05B0 0062;0061 3099 0A4D 094D 05B0 0062; # (a◌੍◌ְ◌्◌゙b; a◌゙◌੍◌्◌ְb; a◌゙◌੍◌्◌ְb; a◌゙◌੍◌्◌ְb; a◌゙◌੍◌्◌ְb; ) LATIN SMALL LETTER A, GURMUKHI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 0ABC 0062;0061 0334 093C 0ABC 3099 0062;0061 0334 093C 0ABC 3099 0062;0061 0334 093C 0ABC 3099 0062;0061 0334 093C 0ABC 3099 0062; # (a◌゙◌़◌̴◌઼b; a◌̴◌़◌઼◌゙b; a◌̴◌़◌઼◌゙b; a◌̴◌़◌઼◌゙b; a◌̴◌़◌઼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, GUJARATI SIGN NUKTA, LATIN SMALL LETTER B +0061 0ABC 3099 093C 0334 0062;0061 0334 0ABC 093C 3099 0062;0061 0334 0ABC 093C 3099 0062;0061 0334 0ABC 093C 3099 0062;0061 0334 0ABC 093C 3099 0062; # (a◌઼◌゙◌़◌̴b; a◌̴◌઼◌़◌゙b; a◌̴◌઼◌़◌゙b; a◌̴◌઼◌़◌゙b; a◌̴◌઼◌़◌゙b; ) LATIN SMALL LETTER A, GUJARATI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 0ACD 0062;0061 3099 094D 0ACD 05B0 0062;0061 3099 094D 0ACD 05B0 0062;0061 3099 094D 0ACD 05B0 0062;0061 3099 094D 0ACD 05B0 0062; # (a◌ְ◌्◌゙◌્b; a◌゙◌्◌્◌ְb; a◌゙◌्◌્◌ְb; a◌゙◌्◌્◌ְb; a◌゙◌्◌્◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GUJARATI SIGN VIRAMA, LATIN SMALL LETTER B +0061 0ACD 05B0 094D 3099 0062;0061 3099 0ACD 094D 05B0 0062;0061 3099 0ACD 094D 05B0 0062;0061 3099 0ACD 094D 05B0 0062;0061 3099 0ACD 094D 05B0 0062; # (a◌્◌ְ◌्◌゙b; a◌゙◌્◌्◌ְb; a◌゙◌્◌्◌ְb; a◌゙◌્◌्◌ְb; a◌゙◌્◌्◌ְb; ) LATIN SMALL LETTER A, GUJARATI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 0B3C 0062;0061 0334 093C 0B3C 3099 0062;0061 0334 093C 0B3C 3099 0062;0061 0334 093C 0B3C 3099 0062;0061 0334 093C 0B3C 3099 0062; # (a◌゙◌़◌̴◌଼b; a◌̴◌़◌଼◌゙b; a◌̴◌़◌଼◌゙b; a◌̴◌़◌଼◌゙b; a◌̴◌़◌଼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, ORIYA SIGN NUKTA, LATIN SMALL LETTER B +0061 0B3C 3099 093C 0334 0062;0061 0334 0B3C 093C 3099 0062;0061 0334 0B3C 093C 3099 0062;0061 0334 0B3C 093C 3099 0062;0061 0334 0B3C 093C 3099 0062; # (a◌଼◌゙◌़◌̴b; a◌̴◌଼◌़◌゙b; a◌̴◌଼◌़◌゙b; a◌̴◌଼◌़◌゙b; a◌̴◌଼◌़◌゙b; ) LATIN SMALL LETTER A, ORIYA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 0B4D 0062;0061 3099 094D 0B4D 05B0 0062;0061 3099 094D 0B4D 05B0 0062;0061 3099 094D 0B4D 05B0 0062;0061 3099 094D 0B4D 05B0 0062; # (a◌ְ◌्◌゙◌୍b; a◌゙◌्◌୍◌ְb; a◌゙◌्◌୍◌ְb; a◌゙◌्◌୍◌ְb; a◌゙◌्◌୍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ORIYA SIGN VIRAMA, LATIN SMALL LETTER B +0061 0B4D 05B0 094D 3099 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062; # (a◌୍◌ְ◌्◌゙b; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; ) LATIN SMALL LETTER A, ORIYA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0BCD 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062; # (a◌ְ◌्◌゙◌்b; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAMIL SIGN VIRAMA, LATIN SMALL LETTER B +0061 0BCD 05B0 094D 3099 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062; # (a◌்◌ְ◌्◌゙b; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; ) LATIN SMALL LETTER A, TAMIL SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0C4D 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062; # (a◌ְ◌्◌゙◌్b; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TELUGU SIGN VIRAMA, LATIN SMALL LETTER B +0061 0C4D 05B0 094D 3099 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062; # (a◌్◌ְ◌्◌゙b; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; ) LATIN SMALL LETTER A, TELUGU SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0C56 0C55 0711 0C55 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062; # (a◌ౖ◌ౕ◌ܑ◌ౕb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; ) LATIN SMALL LETTER A, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, TELUGU LENGTH MARK, LATIN SMALL LETTER B +0061 0C55 0C56 0C55 0711 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062; # (a◌ౕ◌ౖ◌ౕ◌ܑb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; ) LATIN SMALL LETTER A, TELUGU LENGTH MARK, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, LATIN SMALL LETTER B +0061 0E38 0C56 0C55 0C56 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062; # (a◌ุ◌ౖ◌ౕ◌ౖb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; ) LATIN SMALL LETTER A, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, TELUGU AI LENGTH MARK, LATIN SMALL LETTER B +0061 0C56 0E38 0C56 0C55 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062; # (a◌ౖ◌ุ◌ౖ◌ౕb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; ) LATIN SMALL LETTER A, TELUGU AI LENGTH MARK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0CCD 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062; # (a◌ְ◌्◌゙◌್b; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KANNADA SIGN VIRAMA, LATIN SMALL LETTER B +0061 0CCD 05B0 094D 3099 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062; # (a◌್◌ְ◌्◌゙b; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; ) LATIN SMALL LETTER A, KANNADA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0D4D 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062; # (a◌ְ◌्◌゙◌്b; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VIRAMA, LATIN SMALL LETTER B +0061 0D4D 05B0 094D 3099 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062; # (a◌്◌ְ◌्◌゙b; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0DCA 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062; # (a◌ְ◌्◌゙◌්b; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SINHALA SIGN AL-LAKUNA, LATIN SMALL LETTER B +0061 0DCA 05B0 094D 3099 0062;0061 3099 0DCA 094D 05B0 0062;0061 3099 0DCA 094D 05B0 0062;0061 3099 0DCA 094D 05B0 0062;0061 3099 0DCA 094D 05B0 0062; # (a◌්◌ְ◌्◌゙b; a◌゙◌්◌्◌ְb; a◌゙◌්◌्◌ְb; a◌゙◌්◌्◌ְb; a◌゙◌්◌्◌ְb; ) LATIN SMALL LETTER A, SINHALA SIGN AL-LAKUNA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0E48 0E38 0C56 0E38 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062; # (a◌่◌ุ◌ౖ◌ุb; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0E38 0E48 0E38 0C56 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062; # (a◌ุ◌่◌ุ◌ౖb; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER SARA U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, LATIN SMALL LETTER B +0061 0E48 0E38 0C56 0E39 0062;0061 0C56 0E38 0E39 0E48 0062;0061 0C56 0E38 0E39 0E48 0062;0061 0C56 0E38 0E39 0E48 0062;0061 0C56 0E38 0E39 0E48 0062; # (a◌่◌ุ◌ౖ◌ูb; a◌ౖ◌ุ◌ู◌่b; a◌ౖ◌ุ◌ู◌่b; a◌ౖ◌ุ◌ู◌่b; a◌ౖ◌ุ◌ู◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, THAI CHARACTER SARA UU, LATIN SMALL LETTER B +0061 0E39 0E48 0E38 0C56 0062;0061 0C56 0E39 0E38 0E48 0062;0061 0C56 0E39 0E38 0E48 0062;0061 0C56 0E39 0E38 0E48 0062;0061 0C56 0E39 0E38 0E48 0062; # (a◌ู◌่◌ุ◌ౖb; a◌ౖ◌ู◌ุ◌่b; a◌ౖ◌ู◌ุ◌่b; a◌ౖ◌ู◌ุ◌่b; a◌ౖ◌ู◌ุ◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER SARA UU, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0E3A 0062;0061 3099 094D 0E3A 05B0 0062;0061 3099 094D 0E3A 05B0 0062;0061 3099 094D 0E3A 05B0 0062;0061 3099 094D 0E3A 05B0 0062; # (a◌ְ◌्◌゙◌ฺb; a◌゙◌्◌ฺ◌ְb; a◌゙◌्◌ฺ◌ְb; a◌゙◌्◌ฺ◌ְb; a◌゙◌्◌ฺ◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, THAI CHARACTER PHINTHU, LATIN SMALL LETTER B +0061 0E3A 05B0 094D 3099 0062;0061 3099 0E3A 094D 05B0 0062;0061 3099 0E3A 094D 05B0 0062;0061 3099 0E3A 094D 05B0 0062;0061 3099 0E3A 094D 05B0 0062; # (a◌ฺ◌ְ◌्◌゙b; a◌゙◌ฺ◌्◌ְb; a◌゙◌ฺ◌्◌ְb; a◌゙◌ฺ◌्◌ְb; a◌゙◌ฺ◌्◌ְb; ) LATIN SMALL LETTER A, THAI CHARACTER PHINTHU, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E48 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062; # (a◌ຸ◌่◌ุ◌่b; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI EK, LATIN SMALL LETTER B +0061 0E48 0EB8 0E48 0E38 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062; # (a◌่◌ຸ◌่◌ุb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E49 0062;0061 0E38 0E48 0E49 0EB8 0062;0061 0E38 0E48 0E49 0EB8 0062;0061 0E38 0E48 0E49 0EB8 0062;0061 0E38 0E48 0E49 0EB8 0062; # (a◌ຸ◌่◌ุ◌้b; a◌ุ◌่◌้◌ຸb; a◌ุ◌่◌้◌ຸb; a◌ุ◌่◌้◌ຸb; a◌ุ◌่◌้◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI THO, LATIN SMALL LETTER B +0061 0E49 0EB8 0E48 0E38 0062;0061 0E38 0E49 0E48 0EB8 0062;0061 0E38 0E49 0E48 0EB8 0062;0061 0E38 0E49 0E48 0EB8 0062;0061 0E38 0E49 0E48 0EB8 0062; # (a◌้◌ຸ◌่◌ุb; a◌ุ◌้◌่◌ຸb; a◌ุ◌้◌่◌ຸb; a◌ุ◌้◌่◌ຸb; a◌ุ◌้◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI THO, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E4A 0062;0061 0E38 0E48 0E4A 0EB8 0062;0061 0E38 0E48 0E4A 0EB8 0062;0061 0E38 0E48 0E4A 0EB8 0062;0061 0E38 0E48 0E4A 0EB8 0062; # (a◌ຸ◌่◌ุ◌๊b; a◌ุ◌่◌๊◌ຸb; a◌ุ◌่◌๊◌ຸb; a◌ุ◌่◌๊◌ຸb; a◌ุ◌่◌๊◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI TRI, LATIN SMALL LETTER B +0061 0E4A 0EB8 0E48 0E38 0062;0061 0E38 0E4A 0E48 0EB8 0062;0061 0E38 0E4A 0E48 0EB8 0062;0061 0E38 0E4A 0E48 0EB8 0062;0061 0E38 0E4A 0E48 0EB8 0062; # (a◌๊◌ຸ◌่◌ุb; a◌ุ◌๊◌่◌ຸb; a◌ุ◌๊◌่◌ຸb; a◌ุ◌๊◌่◌ຸb; a◌ุ◌๊◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI TRI, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E4B 0062;0061 0E38 0E48 0E4B 0EB8 0062;0061 0E38 0E48 0E4B 0EB8 0062;0061 0E38 0E48 0E4B 0EB8 0062;0061 0E38 0E48 0E4B 0EB8 0062; # (a◌ຸ◌่◌ุ◌๋b; a◌ุ◌่◌๋◌ຸb; a◌ุ◌่◌๋◌ຸb; a◌ุ◌่◌๋◌ຸb; a◌ุ◌่◌๋◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI CHATTAWA, LATIN SMALL LETTER B +0061 0E4B 0EB8 0E48 0E38 0062;0061 0E38 0E4B 0E48 0EB8 0062;0061 0E38 0E4B 0E48 0EB8 0062;0061 0E38 0E4B 0E48 0EB8 0062;0061 0E38 0E4B 0E48 0EB8 0062; # (a◌๋◌ຸ◌่◌ุb; a◌ุ◌๋◌่◌ຸb; a◌ุ◌๋◌่◌ຸb; a◌ุ◌๋◌่◌ຸb; a◌ุ◌๋◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI CHATTAWA, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EC8 0EB8 0E48 0EB8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062; # (a◌່◌ຸ◌่◌ຸb; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; ) LATIN SMALL LETTER A, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0EB8 0EC8 0EB8 0E48 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062; # (a◌ຸ◌່◌ຸ◌่b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LATIN SMALL LETTER B +0061 0EC8 0EB8 0E48 0EB9 0062;0061 0E48 0EB8 0EB9 0EC8 0062;0061 0E48 0EB8 0EB9 0EC8 0062;0061 0E48 0EB8 0EB9 0EC8 0062;0061 0E48 0EB8 0EB9 0EC8 0062; # (a◌່◌ຸ◌่◌ູb; a◌่◌ຸ◌ູ◌່b; a◌่◌ຸ◌ູ◌່b; a◌่◌ຸ◌ູ◌່b; a◌่◌ຸ◌ູ◌່b; ) LATIN SMALL LETTER A, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LAO VOWEL SIGN UU, LATIN SMALL LETTER B +0061 0EB9 0EC8 0EB8 0E48 0062;0061 0E48 0EB9 0EB8 0EC8 0062;0061 0E48 0EB9 0EB8 0EC8 0062;0061 0E48 0EB9 0EB8 0EC8 0062;0061 0E48 0EB9 0EB8 0EC8 0062; # (a◌ູ◌່◌ຸ◌่b; a◌่◌ູ◌ຸ◌່b; a◌่◌ູ◌ຸ◌່b; a◌่◌ູ◌ຸ◌່b; a◌่◌ູ◌ຸ◌່b; ) LATIN SMALL LETTER A, LAO VOWEL SIGN UU, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0EC8 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062; # (a◌ཱ◌່◌ຸ◌່b; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI EK, LATIN SMALL LETTER B +0061 0EC8 0F71 0EC8 0EB8 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062; # (a◌່◌ཱ◌່◌ຸb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI EK, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0EC9 0062;0061 0EB8 0EC8 0EC9 0F71 0062;0061 0EB8 0EC8 0EC9 0F71 0062;0061 0EB8 0EC8 0EC9 0F71 0062;0061 0EB8 0EC8 0EC9 0F71 0062; # (a◌ཱ◌່◌ຸ◌້b; a◌ຸ◌່◌້◌ཱb; a◌ຸ◌່◌້◌ཱb; a◌ຸ◌່◌້◌ཱb; a◌ຸ◌່◌້◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI THO, LATIN SMALL LETTER B +0061 0EC9 0F71 0EC8 0EB8 0062;0061 0EB8 0EC9 0EC8 0F71 0062;0061 0EB8 0EC9 0EC8 0F71 0062;0061 0EB8 0EC9 0EC8 0F71 0062;0061 0EB8 0EC9 0EC8 0F71 0062; # (a◌້◌ཱ◌່◌ຸb; a◌ຸ◌້◌່◌ཱb; a◌ຸ◌້◌່◌ཱb; a◌ຸ◌້◌່◌ཱb; a◌ຸ◌້◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI THO, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0ECA 0062;0061 0EB8 0EC8 0ECA 0F71 0062;0061 0EB8 0EC8 0ECA 0F71 0062;0061 0EB8 0EC8 0ECA 0F71 0062;0061 0EB8 0EC8 0ECA 0F71 0062; # (a◌ཱ◌່◌ຸ◌໊b; a◌ຸ◌່◌໊◌ཱb; a◌ຸ◌່◌໊◌ཱb; a◌ຸ◌່◌໊◌ཱb; a◌ຸ◌່◌໊◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI TI, LATIN SMALL LETTER B +0061 0ECA 0F71 0EC8 0EB8 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062; # (a◌໊◌ཱ◌່◌ຸb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI TI, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0ECB 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062; # (a◌ཱ◌່◌ຸ◌໋b; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI CATAWA, LATIN SMALL LETTER B +0061 0ECB 0F71 0EC8 0EB8 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062; # (a◌໋◌ཱ◌່◌ຸb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI CATAWA, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 059A 0316 302A 0F18 0062;0061 302A 0316 0F18 059A 0062;0061 302A 0316 0F18 059A 0062;0061 302A 0316 0F18 059A 0062;0061 302A 0316 0F18 059A 0062; # (a◌֚◌̖◌〪◌༘b; a◌〪◌̖◌༘◌֚b; a◌〪◌̖◌༘◌֚b; a◌〪◌̖◌༘◌֚b; a◌〪◌̖◌༘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, LATIN SMALL LETTER B +0061 0F18 059A 0316 302A 0062;0061 302A 0F18 0316 059A 0062;0061 302A 0F18 0316 059A 0062;0061 302A 0F18 0316 059A 0062;0061 302A 0F18 0316 059A 0062; # (a◌༘◌֚◌̖◌〪b; a◌〪◌༘◌̖◌֚b; a◌〪◌༘◌̖◌֚b; a◌〪◌༘◌̖◌֚b; a◌〪◌༘◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0F19 0062;0061 302A 0316 0F19 059A 0062;0061 302A 0316 0F19 059A 0062;0061 302A 0316 0F19 059A 0062;0061 302A 0316 0F19 059A 0062; # (a◌֚◌̖◌〪◌༙b; a◌〪◌̖◌༙◌֚b; a◌〪◌̖◌༙◌֚b; a◌〪◌̖◌༙◌֚b; a◌〪◌̖◌༙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, LATIN SMALL LETTER B +0061 0F19 059A 0316 302A 0062;0061 302A 0F19 0316 059A 0062;0061 302A 0F19 0316 059A 0062;0061 302A 0F19 0316 059A 0062;0061 302A 0F19 0316 059A 0062; # (a◌༙◌֚◌̖◌〪b; a◌〪◌༙◌̖◌֚b; a◌〪◌༙◌̖◌֚b; a◌〪◌༙◌̖◌֚b; a◌〪◌༙◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0F35 0062;0061 302A 0316 0F35 059A 0062;0061 302A 0316 0F35 059A 0062;0061 302A 0316 0F35 059A 0062;0061 302A 0316 0F35 059A 0062; # (a◌֚◌̖◌〪◌༵b; a◌〪◌̖◌༵◌֚b; a◌〪◌̖◌༵◌֚b; a◌〪◌̖◌༵◌֚b; a◌〪◌̖◌༵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN MARK NGAS BZUNG NYI ZLA, LATIN SMALL LETTER B +0061 0F35 059A 0316 302A 0062;0061 302A 0F35 0316 059A 0062;0061 302A 0F35 0316 059A 0062;0061 302A 0F35 0316 059A 0062;0061 302A 0F35 0316 059A 0062; # (a◌༵◌֚◌̖◌〪b; a◌〪◌༵◌̖◌֚b; a◌〪◌༵◌̖◌֚b; a◌〪◌༵◌̖◌֚b; a◌〪◌༵◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG NYI ZLA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 0F37 0062;0061 302A 0316 0F37 059A 0062;0061 302A 0316 0F37 059A 0062;0061 302A 0316 0F37 059A 0062;0061 302A 0316 0F37 059A 0062; # (a◌֚◌̖◌〪◌༷b; a◌〪◌̖◌༷◌֚b; a◌〪◌̖◌༷◌֚b; a◌〪◌̖◌༷◌֚b; a◌〪◌̖◌༷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN MARK NGAS BZUNG SGOR RTAGS, LATIN SMALL LETTER B +0061 0F37 059A 0316 302A 0062;0061 302A 0F37 0316 059A 0062;0061 302A 0F37 0316 059A 0062;0061 302A 0F37 0316 059A 0062;0061 302A 0F37 0316 059A 0062; # (a◌༷◌֚◌̖◌〪b; a◌〪◌༷◌̖◌֚b; a◌〪◌༷◌̖◌֚b; a◌〪◌༷◌̖◌֚b; a◌〪◌༷◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG SGOR RTAGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 302A 031B 0321 0F39 0062;0061 0321 031B 0F39 302A 0062;0061 0321 031B 0F39 302A 0062;0061 0321 031B 0F39 302A 0062;0061 0321 031B 0F39 302A 0062; # (a◌〪◌̛◌̡◌༹b; a◌̡◌̛◌༹◌〪b; a◌̡◌̛◌༹◌〪b; a◌̡◌̛◌༹◌〪b; a◌̡◌̛◌༹◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, TIBETAN MARK TSA -PHRU, LATIN SMALL LETTER B +0061 0F39 302A 031B 0321 0062;0061 0321 0F39 031B 302A 0062;0061 0321 0F39 031B 302A 0062;0061 0321 0F39 031B 302A 0062;0061 0321 0F39 031B 302A 0062; # (a◌༹◌〪◌̛◌̡b; a◌̡◌༹◌̛◌〪b; a◌̡◌༹◌̛◌〪b; a◌̡◌༹◌̛◌〪b; a◌̡◌༹◌̛◌〪b; ) LATIN SMALL LETTER A, TIBETAN MARK TSA -PHRU, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 0F72 0F71 0EC8 0F71 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062; # (a◌ི◌ཱ◌່◌ཱb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F71 0F72 0F71 0EC8 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062; # (a◌ཱ◌ི◌ཱ◌່b; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F72 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062; # (a◌ུ◌ི◌ཱ◌ིb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN I, LATIN SMALL LETTER B +0061 0F72 0F74 0F72 0F71 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062; # (a◌ི◌ུ◌ི◌ཱb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0321 0F74 0F72 0F74 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062; # (a◌̡◌ུ◌ི◌ུb; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; ) LATIN SMALL LETTER A, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F74 0321 0F74 0F72 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062; # (a◌ུ◌̡◌ུ◌ིb; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7A 0062;0061 0F71 0F72 0F7A 0F74 0062;0061 0F71 0F72 0F7A 0F74 0062;0061 0F71 0F72 0F7A 0F74 0062;0061 0F71 0F72 0F7A 0F74 0062; # (a◌ུ◌ི◌ཱ◌ེb; a◌ཱ◌ི◌ེ◌ུb; a◌ཱ◌ི◌ེ◌ུb; a◌ཱ◌ི◌ེ◌ུb; a◌ཱ◌ི◌ེ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN E, LATIN SMALL LETTER B +0061 0F7A 0F74 0F72 0F71 0062;0061 0F71 0F7A 0F72 0F74 0062;0061 0F71 0F7A 0F72 0F74 0062;0061 0F71 0F7A 0F72 0F74 0062;0061 0F71 0F7A 0F72 0F74 0062; # (a◌ེ◌ུ◌ི◌ཱb; a◌ཱ◌ེ◌ི◌ུb; a◌ཱ◌ེ◌ི◌ུb; a◌ཱ◌ེ◌ི◌ུb; a◌ཱ◌ེ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN E, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7B 0062;0061 0F71 0F72 0F7B 0F74 0062;0061 0F71 0F72 0F7B 0F74 0062;0061 0F71 0F72 0F7B 0F74 0062;0061 0F71 0F72 0F7B 0F74 0062; # (a◌ུ◌ི◌ཱ◌ཻb; a◌ཱ◌ི◌ཻ◌ུb; a◌ཱ◌ི◌ཻ◌ུb; a◌ཱ◌ི◌ཻ◌ུb; a◌ཱ◌ི◌ཻ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN EE, LATIN SMALL LETTER B +0061 0F7B 0F74 0F72 0F71 0062;0061 0F71 0F7B 0F72 0F74 0062;0061 0F71 0F7B 0F72 0F74 0062;0061 0F71 0F7B 0F72 0F74 0062;0061 0F71 0F7B 0F72 0F74 0062; # (a◌ཻ◌ུ◌ི◌ཱb; a◌ཱ◌ཻ◌ི◌ུb; a◌ཱ◌ཻ◌ི◌ུb; a◌ཱ◌ཻ◌ི◌ུb; a◌ཱ◌ཻ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN EE, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7C 0062;0061 0F71 0F72 0F7C 0F74 0062;0061 0F71 0F72 0F7C 0F74 0062;0061 0F71 0F72 0F7C 0F74 0062;0061 0F71 0F72 0F7C 0F74 0062; # (a◌ུ◌ི◌ཱ◌ོb; a◌ཱ◌ི◌ོ◌ུb; a◌ཱ◌ི◌ོ◌ུb; a◌ཱ◌ི◌ོ◌ུb; a◌ཱ◌ི◌ོ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN O, LATIN SMALL LETTER B +0061 0F7C 0F74 0F72 0F71 0062;0061 0F71 0F7C 0F72 0F74 0062;0061 0F71 0F7C 0F72 0F74 0062;0061 0F71 0F7C 0F72 0F74 0062;0061 0F71 0F7C 0F72 0F74 0062; # (a◌ོ◌ུ◌ི◌ཱb; a◌ཱ◌ོ◌ི◌ུb; a◌ཱ◌ོ◌ི◌ུb; a◌ཱ◌ོ◌ི◌ུb; a◌ཱ◌ོ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN O, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7D 0062;0061 0F71 0F72 0F7D 0F74 0062;0061 0F71 0F72 0F7D 0F74 0062;0061 0F71 0F72 0F7D 0F74 0062;0061 0F71 0F72 0F7D 0F74 0062; # (a◌ུ◌ི◌ཱ◌ཽb; a◌ཱ◌ི◌ཽ◌ུb; a◌ཱ◌ི◌ཽ◌ུb; a◌ཱ◌ི◌ཽ◌ུb; a◌ཱ◌ི◌ཽ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN OO, LATIN SMALL LETTER B +0061 0F7D 0F74 0F72 0F71 0062;0061 0F71 0F7D 0F72 0F74 0062;0061 0F71 0F7D 0F72 0F74 0062;0061 0F71 0F7D 0F72 0F74 0062;0061 0F71 0F7D 0F72 0F74 0062; # (a◌ཽ◌ུ◌ི◌ཱb; a◌ཱ◌ཽ◌ི◌ུb; a◌ཱ◌ཽ◌ི◌ུb; a◌ཱ◌ཽ◌ི◌ུb; a◌ཱ◌ཽ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN OO, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F80 0062;0061 0F71 0F72 0F80 0F74 0062;0061 0F71 0F72 0F80 0F74 0062;0061 0F71 0F72 0F80 0F74 0062;0061 0F71 0F72 0F80 0F74 0062; # (a◌ུ◌ི◌ཱ◌ྀb; a◌ཱ◌ི◌ྀ◌ུb; a◌ཱ◌ི◌ྀ◌ུb; a◌ཱ◌ི◌ྀ◌ུb; a◌ཱ◌ི◌ྀ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN REVERSED I, LATIN SMALL LETTER B +0061 0F80 0F74 0F72 0F71 0062;0061 0F71 0F80 0F72 0F74 0062;0061 0F71 0F80 0F72 0F74 0062;0061 0F71 0F80 0F72 0F74 0062;0061 0F71 0F80 0F72 0F74 0062; # (a◌ྀ◌ུ◌ི◌ཱb; a◌ཱ◌ྀ◌ི◌ུb; a◌ཱ◌ྀ◌ི◌ུb; a◌ཱ◌ྀ◌ི◌ུb; a◌ཱ◌ྀ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN REVERSED I, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F82 0062;00E0 05AE 0F82 0315 0062;0061 05AE 0300 0F82 0315 0062;00E0 05AE 0F82 0315 0062;0061 05AE 0300 0F82 0315 0062; # (a◌̕◌̀◌֮◌ྂb; à◌֮◌ྂ◌̕b; a◌֮◌̀◌ྂ◌̕b; à◌֮◌ྂ◌̕b; a◌֮◌̀◌ྂ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN NYI ZLA NAA DA, LATIN SMALL LETTER B +0061 0F82 0315 0300 05AE 0062;0061 05AE 0F82 0300 0315 0062;0061 05AE 0F82 0300 0315 0062;0061 05AE 0F82 0300 0315 0062;0061 05AE 0F82 0300 0315 0062; # (a◌ྂ◌̕◌̀◌֮b; a◌֮◌ྂ◌̀◌̕b; a◌֮◌ྂ◌̀◌̕b; a◌֮◌ྂ◌̀◌̕b; a◌֮◌ྂ◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN NYI ZLA NAA DA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F83 0062;00E0 05AE 0F83 0315 0062;0061 05AE 0300 0F83 0315 0062;00E0 05AE 0F83 0315 0062;0061 05AE 0300 0F83 0315 0062; # (a◌̕◌̀◌֮◌ྃb; à◌֮◌ྃ◌̕b; a◌֮◌̀◌ྃ◌̕b; à◌֮◌ྃ◌̕b; a◌֮◌̀◌ྃ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN SNA LDAN, LATIN SMALL LETTER B +0061 0F83 0315 0300 05AE 0062;0061 05AE 0F83 0300 0315 0062;0061 05AE 0F83 0300 0315 0062;0061 05AE 0F83 0300 0315 0062;0061 05AE 0F83 0300 0315 0062; # (a◌ྃ◌̕◌̀◌֮b; a◌֮◌ྃ◌̀◌̕b; a◌֮◌ྃ◌̀◌̕b; a◌֮◌ྃ◌̀◌̕b; a◌֮◌ྃ◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN SNA LDAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 0F84 0062;0061 3099 094D 0F84 05B0 0062;0061 3099 094D 0F84 05B0 0062;0061 3099 094D 0F84 05B0 0062;0061 3099 094D 0F84 05B0 0062; # (a◌ְ◌्◌゙◌྄b; a◌゙◌्◌྄◌ְb; a◌゙◌्◌྄◌ְb; a◌゙◌्◌྄◌ְb; a◌゙◌्◌྄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIBETAN MARK HALANTA, LATIN SMALL LETTER B +0061 0F84 05B0 094D 3099 0062;0061 3099 0F84 094D 05B0 0062;0061 3099 0F84 094D 05B0 0062;0061 3099 0F84 094D 05B0 0062;0061 3099 0F84 094D 05B0 0062; # (a◌྄◌ְ◌्◌゙b; a◌゙◌྄◌्◌ְb; a◌゙◌྄◌्◌ְb; a◌゙◌྄◌्◌ְb; a◌゙◌྄◌्◌ְb; ) LATIN SMALL LETTER A, TIBETAN MARK HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F86 0062;00E0 05AE 0F86 0315 0062;0061 05AE 0300 0F86 0315 0062;00E0 05AE 0F86 0315 0062;0061 05AE 0300 0F86 0315 0062; # (a◌̕◌̀◌֮◌྆b; à◌֮◌྆◌̕b; a◌֮◌̀◌྆◌̕b; à◌֮◌྆◌̕b; a◌֮◌̀◌྆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN LCI RTAGS, LATIN SMALL LETTER B +0061 0F86 0315 0300 05AE 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062; # (a◌྆◌̕◌̀◌֮b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN LCI RTAGS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F87 0062;00E0 05AE 0F87 0315 0062;0061 05AE 0300 0F87 0315 0062;00E0 05AE 0F87 0315 0062;0061 05AE 0300 0F87 0315 0062; # (a◌̕◌̀◌֮◌྇b; à◌֮◌྇◌̕b; a◌֮◌̀◌྇◌̕b; à◌֮◌྇◌̕b; a◌֮◌̀◌྇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN YANG RTAGS, LATIN SMALL LETTER B +0061 0F87 0315 0300 05AE 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062; # (a◌྇◌̕◌̀◌֮b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN YANG RTAGS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 0FC6 0062;0061 302A 0316 0FC6 059A 0062;0061 302A 0316 0FC6 059A 0062;0061 302A 0316 0FC6 059A 0062;0061 302A 0316 0FC6 059A 0062; # (a◌֚◌̖◌〪◌࿆b; a◌〪◌̖◌࿆◌֚b; a◌〪◌̖◌࿆◌֚b; a◌〪◌̖◌࿆◌֚b; a◌〪◌̖◌࿆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN SYMBOL PADMA GDAN, LATIN SMALL LETTER B +0061 0FC6 059A 0316 302A 0062;0061 302A 0FC6 0316 059A 0062;0061 302A 0FC6 0316 059A 0062;0061 302A 0FC6 0316 059A 0062;0061 302A 0FC6 0316 059A 0062; # (a◌࿆◌֚◌̖◌〪b; a◌〪◌࿆◌̖◌֚b; a◌〪◌࿆◌̖◌֚b; a◌〪◌࿆◌̖◌֚b; a◌〪◌࿆◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN SYMBOL PADMA GDAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 1037 0062;0061 0334 093C 1037 3099 0062;0061 0334 093C 1037 3099 0062;0061 0334 093C 1037 3099 0062;0061 0334 093C 1037 3099 0062; # (a◌゙◌़◌̴◌့b; a◌̴◌़◌့◌゙b; a◌̴◌़◌့◌゙b; a◌̴◌़◌့◌゙b; a◌̴◌़◌့◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, MYANMAR SIGN DOT BELOW, LATIN SMALL LETTER B +0061 1037 3099 093C 0334 0062;0061 0334 1037 093C 3099 0062;0061 0334 1037 093C 3099 0062;0061 0334 1037 093C 3099 0062;0061 0334 1037 093C 3099 0062; # (a◌့◌゙◌़◌̴b; a◌̴◌့◌़◌゙b; a◌̴◌့◌़◌゙b; a◌̴◌့◌़◌゙b; a◌̴◌့◌़◌゙b; ) LATIN SMALL LETTER A, MYANMAR SIGN DOT BELOW, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 1039 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062; # (a◌ְ◌्◌゙◌္b; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MYANMAR SIGN VIRAMA, LATIN SMALL LETTER B +0061 1039 05B0 094D 3099 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062; # (a◌္◌ְ◌्◌゙b; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; ) LATIN SMALL LETTER A, MYANMAR SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1714 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062; # (a◌ְ◌्◌゙◌᜔b; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAGALOG SIGN VIRAMA, LATIN SMALL LETTER B +0061 1714 05B0 094D 3099 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062; # (a◌᜔◌ְ◌्◌゙b; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; ) LATIN SMALL LETTER A, TAGALOG SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1734 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062; # (a◌ְ◌्◌゙◌᜴b; a◌゙◌्◌᜴◌ְb; a◌゙◌्◌᜴◌ְb; a◌゙◌्◌᜴◌ְb; a◌゙◌्◌᜴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, HANUNOO SIGN PAMUDPOD, LATIN SMALL LETTER B +0061 1734 05B0 094D 3099 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062; # (a◌᜴◌ְ◌्◌゙b; a◌゙◌᜴◌्◌ְb; a◌゙◌᜴◌्◌ְb; a◌゙◌᜴◌्◌ְb; a◌゙◌᜴◌्◌ְb; ) LATIN SMALL LETTER A, HANUNOO SIGN PAMUDPOD, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 17D2 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062; # (a◌ְ◌्◌゙◌្b; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHMER SIGN COENG, LATIN SMALL LETTER B +0061 17D2 05B0 094D 3099 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062; # (a◌្◌ְ◌्◌゙b; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; ) LATIN SMALL LETTER A, KHMER SIGN COENG, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 18A9 0062;00E0 1D16D 05AE 18A9 0062;0061 1D16D 05AE 18A9 0300 0062;00E0 1D16D 05AE 18A9 0062;0061 1D16D 05AE 18A9 0300 0062; # (a◌̀◌𝅭𝅭֮◌ᢩb; à𝅭𝅭◌֮◌ᢩb; a𝅭𝅭◌֮◌ᢩ◌̀b; à𝅭𝅭◌֮◌ᢩb; a𝅭𝅭◌֮◌ᢩ◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, MONGOLIAN LETTER ALI GALI DAGALGA, LATIN SMALL LETTER B +0061 18A9 0300 05AE 1D16D 0062;00E0 1D16D 18A9 05AE 0062;0061 1D16D 18A9 05AE 0300 0062;00E0 1D16D 18A9 05AE 0062;0061 1D16D 18A9 05AE 0300 0062; # (a◌ᢩ◌̀◌𝅭𝅭֮b; à𝅭𝅭◌ᢩ◌֮b; a𝅭𝅭◌ᢩ◌֮◌̀b; à𝅭𝅭◌ᢩ◌֮b; a𝅭𝅭◌ᢩ◌֮◌̀b; ) LATIN SMALL LETTER A, MONGOLIAN LETTER ALI GALI DAGALGA, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D0 0062;00E0 05AE 20D0 0315 0062;0061 05AE 0300 20D0 0315 0062;00E0 05AE 20D0 0315 0062;0061 05AE 0300 20D0 0315 0062; # (a◌̕◌̀◌֮◌⃐b; à◌֮◌⃐◌̕b; a◌֮◌̀◌⃐◌̕b; à◌֮◌⃐◌̕b; a◌֮◌̀◌⃐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT HARPOON ABOVE, LATIN SMALL LETTER B +0061 20D0 0315 0300 05AE 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062; # (a◌⃐◌̕◌̀◌֮b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT HARPOON ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D1 0062;00E0 05AE 20D1 0315 0062;0061 05AE 0300 20D1 0315 0062;00E0 05AE 20D1 0315 0062;0061 05AE 0300 20D1 0315 0062; # (a◌̕◌̀◌֮◌⃑b; à◌֮◌⃑◌̕b; a◌֮◌̀◌⃑◌̕b; à◌֮◌⃑◌̕b; a◌֮◌̀◌⃑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT HARPOON ABOVE, LATIN SMALL LETTER B +0061 20D1 0315 0300 05AE 0062;0061 05AE 20D1 0300 0315 0062;0061 05AE 20D1 0300 0315 0062;0061 05AE 20D1 0300 0315 0062;0061 05AE 20D1 0300 0315 0062; # (a◌⃑◌̕◌̀◌֮b; a◌֮◌⃑◌̀◌̕b; a◌֮◌⃑◌̀◌̕b; a◌֮◌⃑◌̀◌̕b; a◌֮◌⃑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT HARPOON ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 093C 0334 20D2 0062;0061 0334 20D2 093C 0062;0061 0334 20D2 093C 0062;0061 0334 20D2 093C 0062;0061 0334 20D2 093C 0062; # (a◌़◌̴◌⃒b; a◌̴◌⃒◌़b; a◌̴◌⃒◌़b; a◌̴◌⃒◌़b; a◌̴◌⃒◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING LONG VERTICAL LINE OVERLAY, LATIN SMALL LETTER B +0061 20D2 093C 0334 0062;0061 20D2 0334 093C 0062;0061 20D2 0334 093C 0062;0061 20D2 0334 093C 0062;0061 20D2 0334 093C 0062; # (a◌⃒◌़◌̴b; a◌⃒◌̴◌़b; a◌⃒◌̴◌़b; a◌⃒◌̴◌़b; a◌⃒◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING LONG VERTICAL LINE OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 20D3 0062;0061 0334 20D3 093C 0062;0061 0334 20D3 093C 0062;0061 0334 20D3 093C 0062;0061 0334 20D3 093C 0062; # (a◌़◌̴◌⃓b; a◌̴◌⃓◌़b; a◌̴◌⃓◌़b; a◌̴◌⃓◌़b; a◌̴◌⃓◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING SHORT VERTICAL LINE OVERLAY, LATIN SMALL LETTER B +0061 20D3 093C 0334 0062;0061 20D3 0334 093C 0062;0061 20D3 0334 093C 0062;0061 20D3 0334 093C 0062;0061 20D3 0334 093C 0062; # (a◌⃓◌़◌̴b; a◌⃓◌̴◌़b; a◌⃓◌̴◌़b; a◌⃓◌̴◌़b; a◌⃓◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING SHORT VERTICAL LINE OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D4 0062;00E0 05AE 20D4 0315 0062;0061 05AE 0300 20D4 0315 0062;00E0 05AE 20D4 0315 0062;0061 05AE 0300 20D4 0315 0062; # (a◌̕◌̀◌֮◌⃔b; à◌֮◌⃔◌̕b; a◌֮◌̀◌⃔◌̕b; à◌֮◌⃔◌̕b; a◌֮◌̀◌⃔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ANTICLOCKWISE ARROW ABOVE, LATIN SMALL LETTER B +0061 20D4 0315 0300 05AE 0062;0061 05AE 20D4 0300 0315 0062;0061 05AE 20D4 0300 0315 0062;0061 05AE 20D4 0300 0315 0062;0061 05AE 20D4 0300 0315 0062; # (a◌⃔◌̕◌̀◌֮b; a◌֮◌⃔◌̀◌̕b; a◌֮◌⃔◌̀◌̕b; a◌֮◌⃔◌̀◌̕b; a◌֮◌⃔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ANTICLOCKWISE ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D5 0062;00E0 05AE 20D5 0315 0062;0061 05AE 0300 20D5 0315 0062;00E0 05AE 20D5 0315 0062;0061 05AE 0300 20D5 0315 0062; # (a◌̕◌̀◌֮◌⃕b; à◌֮◌⃕◌̕b; a◌֮◌̀◌⃕◌̕b; à◌֮◌⃕◌̕b; a◌֮◌̀◌⃕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CLOCKWISE ARROW ABOVE, LATIN SMALL LETTER B +0061 20D5 0315 0300 05AE 0062;0061 05AE 20D5 0300 0315 0062;0061 05AE 20D5 0300 0315 0062;0061 05AE 20D5 0300 0315 0062;0061 05AE 20D5 0300 0315 0062; # (a◌⃕◌̕◌̀◌֮b; a◌֮◌⃕◌̀◌̕b; a◌֮◌⃕◌̀◌̕b; a◌֮◌⃕◌̀◌̕b; a◌֮◌⃕◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CLOCKWISE ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D6 0062;00E0 05AE 20D6 0315 0062;0061 05AE 0300 20D6 0315 0062;00E0 05AE 20D6 0315 0062;0061 05AE 0300 20D6 0315 0062; # (a◌̕◌̀◌֮◌⃖b; à◌֮◌⃖◌̕b; a◌֮◌̀◌⃖◌̕b; à◌֮◌⃖◌̕b; a◌֮◌̀◌⃖◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT ARROW ABOVE, LATIN SMALL LETTER B +0061 20D6 0315 0300 05AE 0062;0061 05AE 20D6 0300 0315 0062;0061 05AE 20D6 0300 0315 0062;0061 05AE 20D6 0300 0315 0062;0061 05AE 20D6 0300 0315 0062; # (a◌⃖◌̕◌̀◌֮b; a◌֮◌⃖◌̀◌̕b; a◌֮◌⃖◌̀◌̕b; a◌֮◌⃖◌̀◌̕b; a◌֮◌⃖◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D7 0062;00E0 05AE 20D7 0315 0062;0061 05AE 0300 20D7 0315 0062;00E0 05AE 20D7 0315 0062;0061 05AE 0300 20D7 0315 0062; # (a◌̕◌̀◌֮◌⃗b; à◌֮◌⃗◌̕b; a◌֮◌̀◌⃗◌̕b; à◌֮◌⃗◌̕b; a◌֮◌̀◌⃗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT ARROW ABOVE, LATIN SMALL LETTER B +0061 20D7 0315 0300 05AE 0062;0061 05AE 20D7 0300 0315 0062;0061 05AE 20D7 0300 0315 0062;0061 05AE 20D7 0300 0315 0062;0061 05AE 20D7 0300 0315 0062; # (a◌⃗◌̕◌̀◌֮b; a◌֮◌⃗◌̀◌̕b; a◌֮◌⃗◌̀◌̕b; a◌֮◌⃗◌̀◌̕b; a◌֮◌⃗◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 093C 0334 20D8 0062;0061 0334 20D8 093C 0062;0061 0334 20D8 093C 0062;0061 0334 20D8 093C 0062;0061 0334 20D8 093C 0062; # (a◌़◌̴◌⃘b; a◌̴◌⃘◌़b; a◌̴◌⃘◌़b; a◌̴◌⃘◌़b; a◌̴◌⃘◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING RING OVERLAY, LATIN SMALL LETTER B +0061 20D8 093C 0334 0062;0061 20D8 0334 093C 0062;0061 20D8 0334 093C 0062;0061 20D8 0334 093C 0062;0061 20D8 0334 093C 0062; # (a◌⃘◌़◌̴b; a◌⃘◌̴◌़b; a◌⃘◌̴◌़b; a◌⃘◌̴◌़b; a◌⃘◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING RING OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 20D9 0062;0061 0334 20D9 093C 0062;0061 0334 20D9 093C 0062;0061 0334 20D9 093C 0062;0061 0334 20D9 093C 0062; # (a◌़◌̴◌⃙b; a◌̴◌⃙◌़b; a◌̴◌⃙◌़b; a◌̴◌⃙◌़b; a◌̴◌⃙◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING CLOCKWISE RING OVERLAY, LATIN SMALL LETTER B +0061 20D9 093C 0334 0062;0061 20D9 0334 093C 0062;0061 20D9 0334 093C 0062;0061 20D9 0334 093C 0062;0061 20D9 0334 093C 0062; # (a◌⃙◌़◌̴b; a◌⃙◌̴◌़b; a◌⃙◌̴◌़b; a◌⃙◌̴◌़b; a◌⃙◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING CLOCKWISE RING OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 20DA 0062;0061 0334 20DA 093C 0062;0061 0334 20DA 093C 0062;0061 0334 20DA 093C 0062;0061 0334 20DA 093C 0062; # (a◌़◌̴◌⃚b; a◌̴◌⃚◌़b; a◌̴◌⃚◌़b; a◌̴◌⃚◌़b; a◌̴◌⃚◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING ANTICLOCKWISE RING OVERLAY, LATIN SMALL LETTER B +0061 20DA 093C 0334 0062;0061 20DA 0334 093C 0062;0061 20DA 0334 093C 0062;0061 20DA 0334 093C 0062;0061 20DA 0334 093C 0062; # (a◌⃚◌़◌̴b; a◌⃚◌̴◌़b; a◌⃚◌̴◌़b; a◌⃚◌̴◌़b; a◌⃚◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING ANTICLOCKWISE RING OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 20DB 0062;00E0 05AE 20DB 0315 0062;0061 05AE 0300 20DB 0315 0062;00E0 05AE 20DB 0315 0062;0061 05AE 0300 20DB 0315 0062; # (a◌̕◌̀◌֮◌⃛b; à◌֮◌⃛◌̕b; a◌֮◌̀◌⃛◌̕b; à◌֮◌⃛◌̕b; a◌֮◌̀◌⃛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING THREE DOTS ABOVE, LATIN SMALL LETTER B +0061 20DB 0315 0300 05AE 0062;0061 05AE 20DB 0300 0315 0062;0061 05AE 20DB 0300 0315 0062;0061 05AE 20DB 0300 0315 0062;0061 05AE 20DB 0300 0315 0062; # (a◌⃛◌̕◌̀◌֮b; a◌֮◌⃛◌̀◌̕b; a◌֮◌⃛◌̀◌̕b; a◌֮◌⃛◌̀◌̕b; a◌֮◌⃛◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING THREE DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20DC 0062;00E0 05AE 20DC 0315 0062;0061 05AE 0300 20DC 0315 0062;00E0 05AE 20DC 0315 0062;0061 05AE 0300 20DC 0315 0062; # (a◌̕◌̀◌֮◌⃜b; à◌֮◌⃜◌̕b; a◌֮◌̀◌⃜◌̕b; à◌֮◌⃜◌̕b; a◌֮◌̀◌⃜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING FOUR DOTS ABOVE, LATIN SMALL LETTER B +0061 20DC 0315 0300 05AE 0062;0061 05AE 20DC 0300 0315 0062;0061 05AE 20DC 0300 0315 0062;0061 05AE 20DC 0300 0315 0062;0061 05AE 20DC 0300 0315 0062; # (a◌⃜◌̕◌̀◌֮b; a◌֮◌⃜◌̀◌̕b; a◌֮◌⃜◌̀◌̕b; a◌֮◌⃜◌̀◌̕b; a◌֮◌⃜◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING FOUR DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20E1 0062;00E0 05AE 20E1 0315 0062;0061 05AE 0300 20E1 0315 0062;00E0 05AE 20E1 0315 0062;0061 05AE 0300 20E1 0315 0062; # (a◌̕◌̀◌֮◌⃡b; à◌֮◌⃡◌̕b; a◌֮◌̀◌⃡◌̕b; à◌֮◌⃡◌̕b; a◌֮◌̀◌⃡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT RIGHT ARROW ABOVE, LATIN SMALL LETTER B +0061 20E1 0315 0300 05AE 0062;0061 05AE 20E1 0300 0315 0062;0061 05AE 20E1 0300 0315 0062;0061 05AE 20E1 0300 0315 0062;0061 05AE 20E1 0300 0315 0062; # (a◌⃡◌̕◌̀◌֮b; a◌֮◌⃡◌̀◌̕b; a◌֮◌⃡◌̀◌̕b; a◌֮◌⃡◌̀◌̕b; a◌֮◌⃡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT RIGHT ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 093C 0334 20E5 0062;0061 0334 20E5 093C 0062;0061 0334 20E5 093C 0062;0061 0334 20E5 093C 0062;0061 0334 20E5 093C 0062; # (a◌़◌̴◌⃥b; a◌̴◌⃥◌़b; a◌̴◌⃥◌़b; a◌̴◌⃥◌़b; a◌̴◌⃥◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING REVERSE SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 20E5 093C 0334 0062;0061 20E5 0334 093C 0062;0061 20E5 0334 093C 0062;0061 20E5 0334 093C 0062;0061 20E5 0334 093C 0062; # (a◌⃥◌़◌̴b; a◌⃥◌̴◌़b; a◌⃥◌̴◌़b; a◌⃥◌̴◌़b; a◌⃥◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING REVERSE SOLIDUS OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 20E6 0062;0061 0334 20E6 093C 0062;0061 0334 20E6 093C 0062;0061 0334 20E6 093C 0062;0061 0334 20E6 093C 0062; # (a◌़◌̴◌⃦b; a◌̴◌⃦◌़b; a◌̴◌⃦◌़b; a◌̴◌⃦◌़b; a◌̴◌⃦◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING DOUBLE VERTICAL STROKE OVERLAY, LATIN SMALL LETTER B +0061 20E6 093C 0334 0062;0061 20E6 0334 093C 0062;0061 20E6 0334 093C 0062;0061 20E6 0334 093C 0062;0061 20E6 0334 093C 0062; # (a◌⃦◌़◌̴b; a◌⃦◌̴◌़b; a◌⃦◌̴◌़b; a◌⃦◌̴◌़b; a◌⃦◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL STROKE OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 20E7 0062;00E0 05AE 20E7 0315 0062;0061 05AE 0300 20E7 0315 0062;00E0 05AE 20E7 0315 0062;0061 05AE 0300 20E7 0315 0062; # (a◌̕◌̀◌֮◌⃧b; à◌֮◌⃧◌̕b; a◌֮◌̀◌⃧◌̕b; à◌֮◌⃧◌̕b; a◌֮◌̀◌⃧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ANNUITY SYMBOL, LATIN SMALL LETTER B +0061 20E7 0315 0300 05AE 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062; # (a◌⃧◌̕◌̀◌֮b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ANNUITY SYMBOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 20E8 0062;0061 302A 0316 20E8 059A 0062;0061 302A 0316 20E8 059A 0062;0061 302A 0316 20E8 059A 0062;0061 302A 0316 20E8 059A 0062; # (a◌֚◌̖◌〪◌⃨b; a◌〪◌̖◌⃨◌֚b; a◌〪◌̖◌⃨◌֚b; a◌〪◌̖◌⃨◌֚b; a◌〪◌̖◌⃨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING TRIPLE UNDERDOT, LATIN SMALL LETTER B +0061 20E8 059A 0316 302A 0062;0061 302A 20E8 0316 059A 0062;0061 302A 20E8 0316 059A 0062;0061 302A 20E8 0316 059A 0062;0061 302A 20E8 0316 059A 0062; # (a◌⃨◌֚◌̖◌〪b; a◌〪◌⃨◌̖◌֚b; a◌〪◌⃨◌̖◌֚b; a◌〪◌⃨◌̖◌֚b; a◌〪◌⃨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TRIPLE UNDERDOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 20E9 0062;00E0 05AE 20E9 0315 0062;0061 05AE 0300 20E9 0315 0062;00E0 05AE 20E9 0315 0062;0061 05AE 0300 20E9 0315 0062; # (a◌̕◌̀◌֮◌⃩b; à◌֮◌⃩◌̕b; a◌֮◌̀◌⃩◌̕b; à◌֮◌⃩◌̕b; a◌֮◌̀◌⃩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING WIDE BRIDGE ABOVE, LATIN SMALL LETTER B +0061 20E9 0315 0300 05AE 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062; # (a◌⃩◌̕◌̀◌֮b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING WIDE BRIDGE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 093C 0334 20EA 0062;0061 0334 20EA 093C 0062;0061 0334 20EA 093C 0062;0061 0334 20EA 093C 0062;0061 0334 20EA 093C 0062; # (a◌़◌̴◌⃪b; a◌̴◌⃪◌़b; a◌̴◌⃪◌़b; a◌̴◌⃪◌़b; a◌̴◌⃪◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING LEFTWARDS ARROW OVERLAY, LATIN SMALL LETTER B +0061 20EA 093C 0334 0062;0061 20EA 0334 093C 0062;0061 20EA 0334 093C 0062;0061 20EA 0334 093C 0062;0061 20EA 0334 093C 0062; # (a◌⃪◌़◌̴b; a◌⃪◌̴◌़b; a◌⃪◌̴◌़b; a◌⃪◌̴◌़b; a◌⃪◌̴◌़b; ) LATIN SMALL LETTER A, COMBINING LEFTWARDS ARROW OVERLAY, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0316 302A 031B 302A 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062; # (a◌̖◌〪◌̛◌〪b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 302A 0316 302A 031B 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062; # (a◌〪◌̖◌〪◌̛b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 302B 0062;00E0 1D16D 05AE 302B 0062;0061 1D16D 05AE 302B 0300 0062;00E0 1D16D 05AE 302B 0062;0061 1D16D 05AE 302B 0300 0062; # (a◌̀◌𝅭𝅭֮◌〫b; à𝅭𝅭◌֮◌〫b; a𝅭𝅭◌֮◌〫◌̀b; à𝅭𝅭◌֮◌〫b; a𝅭𝅭◌֮◌〫◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, IDEOGRAPHIC RISING TONE MARK, LATIN SMALL LETTER B +0061 302B 0300 05AE 1D16D 0062;00E0 1D16D 302B 05AE 0062;0061 1D16D 302B 05AE 0300 0062;00E0 1D16D 302B 05AE 0062;0061 1D16D 302B 05AE 0300 0062; # (a◌〫◌̀◌𝅭𝅭֮b; à𝅭𝅭◌〫◌֮b; a𝅭𝅭◌〫◌֮◌̀b; à𝅭𝅭◌〫◌֮b; a𝅭𝅭◌〫◌֮◌̀b; ) LATIN SMALL LETTER A, IDEOGRAPHIC RISING TONE MARK, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 0362 0315 0300 302C 0062;00E0 0315 302C 0362 0062;0061 0300 0315 302C 0362 0062;00E0 0315 302C 0362 0062;0061 0300 0315 302C 0362 0062; # (a◌͢◌̕◌̀◌〬b; à◌̕◌〬◌͢b; a◌̀◌̕◌〬◌͢b; à◌̕◌〬◌͢b; a◌̀◌̕◌〬◌͢b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, IDEOGRAPHIC DEPARTING TONE MARK, LATIN SMALL LETTER B +0061 302C 0362 0315 0300 0062;00E0 302C 0315 0362 0062;0061 0300 302C 0315 0362 0062;00E0 302C 0315 0362 0062;0061 0300 302C 0315 0362 0062; # (a◌〬◌͢◌̕◌̀b; à◌〬◌̕◌͢b; a◌̀◌〬◌̕◌͢b; à◌〬◌̕◌͢b; a◌̀◌〬◌̕◌͢b; ) LATIN SMALL LETTER A, IDEOGRAPHIC DEPARTING TONE MARK, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 302E 059A 0316 302D 0062;0061 0316 059A 302D 302E 0062;0061 0316 059A 302D 302E 0062;0061 0316 059A 302D 302E 0062;0061 0316 059A 302D 302E 0062; # (a◌〮◌֚◌̖◌〭b; a◌̖◌֚◌〭◌〮b; a◌̖◌֚◌〭◌〮b; a◌̖◌֚◌〭◌〮b; a◌̖◌֚◌〭◌〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC ENTERING TONE MARK, LATIN SMALL LETTER B +0061 302D 302E 059A 0316 0062;0061 0316 302D 059A 302E 0062;0061 0316 302D 059A 302E 0062;0061 0316 302D 059A 302E 0062;0061 0316 302D 059A 302E 0062; # (a◌〭◌〮◌֚◌̖b; a◌̖◌〭◌֚◌〮b; a◌̖◌〭◌֚◌〮b; a◌̖◌〭◌֚◌〮b; a◌̖◌〭◌֚◌〮b; ) LATIN SMALL LETTER A, IDEOGRAPHIC ENTERING TONE MARK, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 1D16D 302E 059A 302E 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062; # (a𝅭𝅭◌〮◌֚◌〮b; a◌֚◌〮◌〮𝅭𝅭b; a◌֚◌〮◌〮𝅭𝅭b; a◌֚◌〮◌〮𝅭𝅭b; a◌֚◌〮◌〮𝅭𝅭b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, HANGUL SINGLE DOT TONE MARK, LATIN SMALL LETTER B +0061 302E 1D16D 302E 059A 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062; # (a◌〮𝅭𝅭◌〮◌֚b; a◌֚◌〮◌〮𝅭𝅭b; a◌֚◌〮◌〮𝅭𝅭b; a◌֚◌〮◌〮𝅭𝅭b; a◌֚◌〮◌〮𝅭𝅭b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, LATIN SMALL LETTER B +0061 1D16D 302E 059A 302F 0062;0061 059A 302E 302F 1D16D 0062;0061 059A 302E 302F 1D16D 0062;0061 059A 302E 302F 1D16D 0062;0061 059A 302E 302F 1D16D 0062; # (a𝅭𝅭◌〮◌֚◌〯b; a◌֚◌〮◌〯𝅭𝅭b; a◌֚◌〮◌〯𝅭𝅭b; a◌֚◌〮◌〯𝅭𝅭b; a◌֚◌〮◌〯𝅭𝅭b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, HANGUL DOUBLE DOT TONE MARK, LATIN SMALL LETTER B +0061 302F 1D16D 302E 059A 0062;0061 059A 302F 302E 1D16D 0062;0061 059A 302F 302E 1D16D 0062;0061 059A 302F 302E 1D16D 0062;0061 059A 302F 302E 1D16D 0062; # (a◌〯𝅭𝅭◌〮◌֚b; a◌֚◌〯◌〮𝅭𝅭b; a◌֚◌〯◌〮𝅭𝅭b; a◌֚◌〯◌〮𝅭𝅭b; a◌֚◌〯◌〮𝅭𝅭b; ) LATIN SMALL LETTER A, HANGUL DOUBLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, LATIN SMALL LETTER B +0061 094D 3099 093C 3099 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062; # (a◌्◌゙◌़◌゙b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 094D 3099 093C 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062; # (a◌゙◌्◌゙◌़b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, LATIN SMALL LETTER B +0061 094D 3099 093C 309A 0062;0061 093C 3099 309A 094D 0062;0061 093C 3099 309A 094D 0062;0061 093C 3099 309A 094D 0062;0061 093C 3099 309A 094D 0062; # (a◌्◌゙◌़◌゚b; a◌़◌゙◌゚◌्b; a◌़◌゙◌゚◌्b; a◌़◌゙◌゚◌्b; a◌़◌゙◌゚◌्b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK, LATIN SMALL LETTER B +0061 309A 094D 3099 093C 0062;0061 093C 309A 3099 094D 0062;0061 093C 309A 3099 094D 0062;0061 093C 309A 3099 094D 0062;0061 093C 309A 3099 094D 0062; # (a◌゚◌्◌゙◌़b; a◌़◌゚◌゙◌्b; a◌़◌゚◌゙◌्b; a◌़◌゚◌゙◌्b; a◌़◌゚◌゙◌्b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, LATIN SMALL LETTER B +0061 064B FB1E 05C2 FB1E 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062; # (a◌ً◌ﬞ◌ׂ◌ﬞb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; ) LATIN SMALL LETTER A, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT JUDEO-SPANISH VARIKA, LATIN SMALL LETTER B +0061 FB1E 064B FB1E 05C2 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062; # (a◌ﬞ◌ً◌ﬞ◌ׂb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; ) LATIN SMALL LETTER A, HEBREW POINT JUDEO-SPANISH VARIKA, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE FE20 0062;00E0 05AE FE20 0315 0062;0061 05AE 0300 FE20 0315 0062;00E0 05AE FE20 0315 0062;0061 05AE 0300 FE20 0315 0062; # (a◌̕◌̀◌֮◌︠b; à◌֮◌︠◌̕b; a◌֮◌̀◌︠◌̕b; à◌֮◌︠◌̕b; a◌֮◌̀◌︠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LIGATURE LEFT HALF, LATIN SMALL LETTER B +0061 FE20 0315 0300 05AE 0062;0061 05AE FE20 0300 0315 0062;0061 05AE FE20 0300 0315 0062;0061 05AE FE20 0300 0315 0062;0061 05AE FE20 0300 0315 0062; # (a◌︠◌̕◌̀◌֮b; a◌֮◌︠◌̀◌̕b; a◌֮◌︠◌̀◌̕b; a◌֮◌︠◌̀◌̕b; a◌֮◌︠◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LIGATURE LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE21 0062;00E0 05AE FE21 0315 0062;0061 05AE 0300 FE21 0315 0062;00E0 05AE FE21 0315 0062;0061 05AE 0300 FE21 0315 0062; # (a◌̕◌̀◌֮◌︡b; à◌֮◌︡◌̕b; a◌֮◌̀◌︡◌̕b; à◌֮◌︡◌̕b; a◌֮◌̀◌︡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LIGATURE RIGHT HALF, LATIN SMALL LETTER B +0061 FE21 0315 0300 05AE 0062;0061 05AE FE21 0300 0315 0062;0061 05AE FE21 0300 0315 0062;0061 05AE FE21 0300 0315 0062;0061 05AE FE21 0300 0315 0062; # (a◌︡◌̕◌̀◌֮b; a◌֮◌︡◌̀◌̕b; a◌֮◌︡◌̀◌̕b; a◌֮◌︡◌̀◌̕b; a◌֮◌︡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LIGATURE RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE22 0062;00E0 05AE FE22 0315 0062;0061 05AE 0300 FE22 0315 0062;00E0 05AE FE22 0315 0062;0061 05AE 0300 FE22 0315 0062; # (a◌̕◌̀◌֮◌︢b; à◌֮◌︢◌̕b; a◌֮◌̀◌︢◌̕b; à◌֮◌︢◌̕b; a◌֮◌̀◌︢◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE TILDE LEFT HALF, LATIN SMALL LETTER B +0061 FE22 0315 0300 05AE 0062;0061 05AE FE22 0300 0315 0062;0061 05AE FE22 0300 0315 0062;0061 05AE FE22 0300 0315 0062;0061 05AE FE22 0300 0315 0062; # (a◌︢◌̕◌̀◌֮b; a◌֮◌︢◌̀◌̕b; a◌֮◌︢◌̀◌̕b; a◌֮◌︢◌̀◌̕b; a◌֮◌︢◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE23 0062;00E0 05AE FE23 0315 0062;0061 05AE 0300 FE23 0315 0062;00E0 05AE FE23 0315 0062;0061 05AE 0300 FE23 0315 0062; # (a◌̕◌̀◌֮◌︣b; à◌֮◌︣◌̕b; a◌֮◌̀◌︣◌̕b; à◌֮◌︣◌̕b; a◌֮◌̀◌︣◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE TILDE RIGHT HALF, LATIN SMALL LETTER B +0061 FE23 0315 0300 05AE 0062;0061 05AE FE23 0300 0315 0062;0061 05AE FE23 0300 0315 0062;0061 05AE FE23 0300 0315 0062;0061 05AE FE23 0300 0315 0062; # (a◌︣◌̕◌̀◌֮b; a◌֮◌︣◌̀◌̕b; a◌֮◌︣◌̀◌̕b; a◌֮◌︣◌̀◌̕b; a◌֮◌︣◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 302A 031B 0321 1D165 0062;0061 0321 031B 1D165 302A 0062;0061 0321 031B 1D165 302A 0062;0061 0321 031B 1D165 302A 0062;0061 0321 031B 1D165 302A 0062; # (a◌〪◌̛◌̡𝅥𝅥b; a◌̡◌̛𝅥𝅥◌〪b; a◌̡◌̛𝅥𝅥◌〪b; a◌̡◌̛𝅥𝅥◌〪b; a◌̡◌̛𝅥𝅥◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING STEM, LATIN SMALL LETTER B +0061 1D165 302A 031B 0321 0062;0061 0321 1D165 031B 302A 0062;0061 0321 1D165 031B 302A 0062;0061 0321 1D165 031B 302A 0062;0061 0321 1D165 031B 302A 0062; # (a𝅥𝅥◌〪◌̛◌̡b; a◌̡𝅥𝅥◌̛◌〪b; a◌̡𝅥𝅥◌̛◌〪b; a◌̡𝅥𝅥◌̛◌〪b; a◌̡𝅥𝅥◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STEM, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 302A 031B 0321 1D166 0062;0061 0321 031B 1D166 302A 0062;0061 0321 031B 1D166 302A 0062;0061 0321 031B 1D166 302A 0062;0061 0321 031B 1D166 302A 0062; # (a◌〪◌̛◌̡𝅦𝅦b; a◌̡◌̛𝅦𝅦◌〪b; a◌̡◌̛𝅦𝅦◌〪b; a◌̡◌̛𝅦𝅦◌〪b; a◌̡◌̛𝅦𝅦◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, LATIN SMALL LETTER B +0061 1D166 302A 031B 0321 0062;0061 0321 1D166 031B 302A 0062;0061 0321 1D166 031B 302A 0062;0061 0321 1D166 031B 302A 0062;0061 0321 1D166 031B 302A 0062; # (a𝅦𝅦◌〪◌̛◌̡b; a◌̡𝅦𝅦◌̛◌〪b; a◌̡𝅦𝅦◌̛◌〪b; a◌̡𝅦𝅦◌̛◌〪b; a◌̡𝅦𝅦◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 093C 0334 1D167 0062;0061 0334 1D167 093C 0062;0061 0334 1D167 093C 0062;0061 0334 1D167 093C 0062;0061 0334 1D167 093C 0062; # (a◌़◌̴◌𝅧◌𝅧b; a◌̴◌𝅧◌𝅧◌़b; a◌̴◌𝅧◌𝅧◌़b; a◌̴◌𝅧◌𝅧◌़b; a◌̴◌𝅧◌𝅧◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-1, LATIN SMALL LETTER B +0061 1D167 093C 0334 0062;0061 1D167 0334 093C 0062;0061 1D167 0334 093C 0062;0061 1D167 0334 093C 0062;0061 1D167 0334 093C 0062; # (a◌𝅧◌𝅧◌़◌̴b; a◌𝅧◌𝅧◌̴◌़b; a◌𝅧◌𝅧◌̴◌़b; a◌𝅧◌𝅧◌̴◌़b; a◌𝅧◌𝅧◌̴◌़b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-1, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 1D168 0062;0061 0334 1D168 093C 0062;0061 0334 1D168 093C 0062;0061 0334 1D168 093C 0062;0061 0334 1D168 093C 0062; # (a◌़◌̴◌𝅨◌𝅨b; a◌̴◌𝅨◌𝅨◌़b; a◌̴◌𝅨◌𝅨◌़b; a◌̴◌𝅨◌𝅨◌़b; a◌̴◌𝅨◌𝅨◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-2, LATIN SMALL LETTER B +0061 1D168 093C 0334 0062;0061 1D168 0334 093C 0062;0061 1D168 0334 093C 0062;0061 1D168 0334 093C 0062;0061 1D168 0334 093C 0062; # (a◌𝅨◌𝅨◌़◌̴b; a◌𝅨◌𝅨◌̴◌़b; a◌𝅨◌𝅨◌̴◌़b; a◌𝅨◌𝅨◌̴◌़b; a◌𝅨◌𝅨◌̴◌़b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-2, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 0334 1D169 0062;0061 0334 1D169 093C 0062;0061 0334 1D169 093C 0062;0061 0334 1D169 093C 0062;0061 0334 1D169 093C 0062; # (a◌़◌̴◌𝅩◌𝅩b; a◌̴◌𝅩◌𝅩◌़b; a◌̴◌𝅩◌𝅩◌़b; a◌̴◌𝅩◌𝅩◌़b; a◌̴◌𝅩◌𝅩◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-3, LATIN SMALL LETTER B +0061 1D169 093C 0334 0062;0061 1D169 0334 093C 0062;0061 1D169 0334 093C 0062;0061 1D169 0334 093C 0062;0061 1D169 0334 093C 0062; # (a◌𝅩◌𝅩◌़◌̴b; a◌𝅩◌𝅩◌̴◌़b; a◌𝅩◌𝅩◌̴◌़b; a◌𝅩◌𝅩◌̴◌़b; a◌𝅩◌𝅩◌̴◌़b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-3, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05AE 1D16D 302E 1D16D 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062; # (a◌𝅭𝅭֮◌〮𝅭𝅭b; a◌〮𝅭𝅭𝅭𝅭◌֮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 1D16D 05AE 1D16D 302E 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062; # (a𝅭𝅭◌𝅭𝅭֮◌〮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; a◌〮𝅭𝅭𝅭𝅭◌֮b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, LATIN SMALL LETTER B +0061 302A 031B 0321 1D16E 0062;0061 0321 031B 1D16E 302A 0062;0061 0321 031B 1D16E 302A 0062;0061 0321 031B 1D16E 302A 0062;0061 0321 031B 1D16E 302A 0062; # (a◌〪◌̛◌̡𝅮𝅮b; a◌̡◌̛𝅮𝅮◌〪b; a◌̡◌̛𝅮𝅮◌〪b; a◌̡◌̛𝅮𝅮◌〪b; a◌̡◌̛𝅮𝅮◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING FLAG-1, LATIN SMALL LETTER B +0061 1D16E 302A 031B 0321 0062;0061 0321 1D16E 031B 302A 0062;0061 0321 1D16E 031B 302A 0062;0061 0321 1D16E 031B 302A 0062;0061 0321 1D16E 031B 302A 0062; # (a𝅮𝅮◌〪◌̛◌̡b; a◌̡𝅮𝅮◌̛◌〪b; a◌̡𝅮𝅮◌̛◌〪b; a◌̡𝅮𝅮◌̛◌〪b; a◌̡𝅮𝅮◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-1, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 302A 031B 0321 1D16F 0062;0061 0321 031B 1D16F 302A 0062;0061 0321 031B 1D16F 302A 0062;0061 0321 031B 1D16F 302A 0062;0061 0321 031B 1D16F 302A 0062; # (a◌〪◌̛◌̡𝅯𝅯b; a◌̡◌̛𝅯𝅯◌〪b; a◌̡◌̛𝅯𝅯◌〪b; a◌̡◌̛𝅯𝅯◌〪b; a◌̡◌̛𝅯𝅯◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING FLAG-2, LATIN SMALL LETTER B +0061 1D16F 302A 031B 0321 0062;0061 0321 1D16F 031B 302A 0062;0061 0321 1D16F 031B 302A 0062;0061 0321 1D16F 031B 302A 0062;0061 0321 1D16F 031B 302A 0062; # (a𝅯𝅯◌〪◌̛◌̡b; a◌̡𝅯𝅯◌̛◌〪b; a◌̡𝅯𝅯◌̛◌〪b; a◌̡𝅯𝅯◌̛◌〪b; a◌̡𝅯𝅯◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-2, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 302A 031B 0321 1D170 0062;0061 0321 031B 1D170 302A 0062;0061 0321 031B 1D170 302A 0062;0061 0321 031B 1D170 302A 0062;0061 0321 031B 1D170 302A 0062; # (a◌〪◌̛◌̡𝅰𝅰b; a◌̡◌̛𝅰𝅰◌〪b; a◌̡◌̛𝅰𝅰◌〪b; a◌̡◌̛𝅰𝅰◌〪b; a◌̡◌̛𝅰𝅰◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING FLAG-3, LATIN SMALL LETTER B +0061 1D170 302A 031B 0321 0062;0061 0321 1D170 031B 302A 0062;0061 0321 1D170 031B 302A 0062;0061 0321 1D170 031B 302A 0062;0061 0321 1D170 031B 302A 0062; # (a𝅰𝅰◌〪◌̛◌̡b; a◌̡𝅰𝅰◌̛◌〪b; a◌̡𝅰𝅰◌̛◌〪b; a◌̡𝅰𝅰◌̛◌〪b; a◌̡𝅰𝅰◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-3, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 302A 031B 0321 1D171 0062;0061 0321 031B 1D171 302A 0062;0061 0321 031B 1D171 302A 0062;0061 0321 031B 1D171 302A 0062;0061 0321 031B 1D171 302A 0062; # (a◌〪◌̛◌̡𝅱𝅱b; a◌̡◌̛𝅱𝅱◌〪b; a◌̡◌̛𝅱𝅱◌〪b; a◌̡◌̛𝅱𝅱◌〪b; a◌̡◌̛𝅱𝅱◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING FLAG-4, LATIN SMALL LETTER B +0061 1D171 302A 031B 0321 0062;0061 0321 1D171 031B 302A 0062;0061 0321 1D171 031B 302A 0062;0061 0321 1D171 031B 302A 0062;0061 0321 1D171 031B 302A 0062; # (a𝅱𝅱◌〪◌̛◌̡b; a◌̡𝅱𝅱◌̛◌〪b; a◌̡𝅱𝅱◌̛◌〪b; a◌̡𝅱𝅱◌̛◌〪b; a◌̡𝅱𝅱◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-4, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 302A 031B 0321 1D172 0062;0061 0321 031B 1D172 302A 0062;0061 0321 031B 1D172 302A 0062;0061 0321 031B 1D172 302A 0062;0061 0321 031B 1D172 302A 0062; # (a◌〪◌̛◌̡𝅲𝅲b; a◌̡◌̛𝅲𝅲◌〪b; a◌̡◌̛𝅲𝅲◌〪b; a◌̡◌̛𝅲𝅲◌〪b; a◌̡◌̛𝅲𝅲◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, MUSICAL SYMBOL COMBINING FLAG-5, LATIN SMALL LETTER B +0061 1D172 302A 031B 0321 0062;0061 0321 1D172 031B 302A 0062;0061 0321 1D172 031B 302A 0062;0061 0321 1D172 031B 302A 0062;0061 0321 1D172 031B 302A 0062; # (a𝅲𝅲◌〪◌̛◌̡b; a◌̡𝅲𝅲◌̛◌〪b; a◌̡𝅲𝅲◌̛◌〪b; a◌̡𝅲𝅲◌̛◌〪b; a◌̡𝅲𝅲◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-5, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 059A 0316 302A 1D17B 0062;0061 302A 0316 1D17B 059A 0062;0061 302A 0316 1D17B 059A 0062;0061 302A 0316 1D17B 059A 0062;0061 302A 0316 1D17B 059A 0062; # (a◌֚◌̖◌〪◌𝅻◌𝅻b; a◌〪◌̖◌𝅻◌𝅻◌֚b; a◌〪◌̖◌𝅻◌𝅻◌֚b; a◌〪◌̖◌𝅻◌𝅻◌֚b; a◌〪◌̖◌𝅻◌𝅻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING ACCENT, LATIN SMALL LETTER B +0061 1D17B 059A 0316 302A 0062;0061 302A 1D17B 0316 059A 0062;0061 302A 1D17B 0316 059A 0062;0061 302A 1D17B 0316 059A 0062;0061 302A 1D17B 0316 059A 0062; # (a◌𝅻◌𝅻◌֚◌̖◌〪b; a◌〪◌𝅻◌𝅻◌̖◌֚b; a◌〪◌𝅻◌𝅻◌̖◌֚b; a◌〪◌𝅻◌𝅻◌̖◌֚b; a◌〪◌𝅻◌𝅻◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D17C 0062;0061 302A 0316 1D17C 059A 0062;0061 302A 0316 1D17C 059A 0062;0061 302A 0316 1D17C 059A 0062;0061 302A 0316 1D17C 059A 0062; # (a◌֚◌̖◌〪◌𝅼◌𝅼b; a◌〪◌̖◌𝅼◌𝅼◌֚b; a◌〪◌̖◌𝅼◌𝅼◌֚b; a◌〪◌̖◌𝅼◌𝅼◌֚b; a◌〪◌̖◌𝅼◌𝅼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING STACCATO, LATIN SMALL LETTER B +0061 1D17C 059A 0316 302A 0062;0061 302A 1D17C 0316 059A 0062;0061 302A 1D17C 0316 059A 0062;0061 302A 1D17C 0316 059A 0062;0061 302A 1D17C 0316 059A 0062; # (a◌𝅼◌𝅼◌֚◌̖◌〪b; a◌〪◌𝅼◌𝅼◌̖◌֚b; a◌〪◌𝅼◌𝅼◌̖◌֚b; a◌〪◌𝅼◌𝅼◌̖◌֚b; a◌〪◌𝅼◌𝅼◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D17D 0062;0061 302A 0316 1D17D 059A 0062;0061 302A 0316 1D17D 059A 0062;0061 302A 0316 1D17D 059A 0062;0061 302A 0316 1D17D 059A 0062; # (a◌֚◌̖◌〪◌𝅽◌𝅽b; a◌〪◌̖◌𝅽◌𝅽◌֚b; a◌〪◌̖◌𝅽◌𝅽◌֚b; a◌〪◌̖◌𝅽◌𝅽◌֚b; a◌〪◌̖◌𝅽◌𝅽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING TENUTO, LATIN SMALL LETTER B +0061 1D17D 059A 0316 302A 0062;0061 302A 1D17D 0316 059A 0062;0061 302A 1D17D 0316 059A 0062;0061 302A 1D17D 0316 059A 0062;0061 302A 1D17D 0316 059A 0062; # (a◌𝅽◌𝅽◌֚◌̖◌〪b; a◌〪◌𝅽◌𝅽◌̖◌֚b; a◌〪◌𝅽◌𝅽◌̖◌֚b; a◌〪◌𝅽◌𝅽◌̖◌֚b; a◌〪◌𝅽◌𝅽◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TENUTO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D17E 0062;0061 302A 0316 1D17E 059A 0062;0061 302A 0316 1D17E 059A 0062;0061 302A 0316 1D17E 059A 0062;0061 302A 0316 1D17E 059A 0062; # (a◌֚◌̖◌〪◌𝅾◌𝅾b; a◌〪◌̖◌𝅾◌𝅾◌֚b; a◌〪◌̖◌𝅾◌𝅾◌֚b; a◌〪◌̖◌𝅾◌𝅾◌֚b; a◌〪◌̖◌𝅾◌𝅾◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING STACCATISSIMO, LATIN SMALL LETTER B +0061 1D17E 059A 0316 302A 0062;0061 302A 1D17E 0316 059A 0062;0061 302A 1D17E 0316 059A 0062;0061 302A 1D17E 0316 059A 0062;0061 302A 1D17E 0316 059A 0062; # (a◌𝅾◌𝅾◌֚◌̖◌〪b; a◌〪◌𝅾◌𝅾◌̖◌֚b; a◌〪◌𝅾◌𝅾◌̖◌֚b; a◌〪◌𝅾◌𝅾◌̖◌֚b; a◌〪◌𝅾◌𝅾◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATISSIMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D17F 0062;0061 302A 0316 1D17F 059A 0062;0061 302A 0316 1D17F 059A 0062;0061 302A 0316 1D17F 059A 0062;0061 302A 0316 1D17F 059A 0062; # (a◌֚◌̖◌〪◌𝅿◌𝅿b; a◌〪◌̖◌𝅿◌𝅿◌֚b; a◌〪◌̖◌𝅿◌𝅿◌֚b; a◌〪◌̖◌𝅿◌𝅿◌֚b; a◌〪◌̖◌𝅿◌𝅿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING MARCATO, LATIN SMALL LETTER B +0061 1D17F 059A 0316 302A 0062;0061 302A 1D17F 0316 059A 0062;0061 302A 1D17F 0316 059A 0062;0061 302A 1D17F 0316 059A 0062;0061 302A 1D17F 0316 059A 0062; # (a◌𝅿◌𝅿◌֚◌̖◌〪b; a◌〪◌𝅿◌𝅿◌̖◌֚b; a◌〪◌𝅿◌𝅿◌̖◌֚b; a◌〪◌𝅿◌𝅿◌̖◌֚b; a◌〪◌𝅿◌𝅿◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D180 0062;0061 302A 0316 1D180 059A 0062;0061 302A 0316 1D180 059A 0062;0061 302A 0316 1D180 059A 0062;0061 302A 0316 1D180 059A 0062; # (a◌֚◌̖◌〪◌𝆀◌𝆀b; a◌〪◌̖◌𝆀◌𝆀◌֚b; a◌〪◌̖◌𝆀◌𝆀◌֚b; a◌〪◌̖◌𝆀◌𝆀◌֚b; a◌〪◌̖◌𝆀◌𝆀◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, LATIN SMALL LETTER B +0061 1D180 059A 0316 302A 0062;0061 302A 1D180 0316 059A 0062;0061 302A 1D180 0316 059A 0062;0061 302A 1D180 0316 059A 0062;0061 302A 1D180 0316 059A 0062; # (a◌𝆀◌𝆀◌֚◌̖◌〪b; a◌〪◌𝆀◌𝆀◌̖◌֚b; a◌〪◌𝆀◌𝆀◌̖◌֚b; a◌〪◌𝆀◌𝆀◌̖◌֚b; a◌〪◌𝆀◌𝆀◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D181 0062;0061 302A 0316 1D181 059A 0062;0061 302A 0316 1D181 059A 0062;0061 302A 0316 1D181 059A 0062;0061 302A 0316 1D181 059A 0062; # (a◌֚◌̖◌〪◌𝆁◌𝆁b; a◌〪◌̖◌𝆁◌𝆁◌֚b; a◌〪◌̖◌𝆁◌𝆁◌֚b; a◌〪◌̖◌𝆁◌𝆁◌֚b; a◌〪◌̖◌𝆁◌𝆁◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, LATIN SMALL LETTER B +0061 1D181 059A 0316 302A 0062;0061 302A 1D181 0316 059A 0062;0061 302A 1D181 0316 059A 0062;0061 302A 1D181 0316 059A 0062;0061 302A 1D181 0316 059A 0062; # (a◌𝆁◌𝆁◌֚◌̖◌〪b; a◌〪◌𝆁◌𝆁◌̖◌֚b; a◌〪◌𝆁◌𝆁◌̖◌֚b; a◌〪◌𝆁◌𝆁◌̖◌֚b; a◌〪◌𝆁◌𝆁◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D182 0062;0061 302A 0316 1D182 059A 0062;0061 302A 0316 1D182 059A 0062;0061 302A 0316 1D182 059A 0062;0061 302A 0316 1D182 059A 0062; # (a◌֚◌̖◌〪◌𝆂◌𝆂b; a◌〪◌̖◌𝆂◌𝆂◌֚b; a◌〪◌̖◌𝆂◌𝆂◌֚b; a◌〪◌̖◌𝆂◌𝆂◌֚b; a◌〪◌̖◌𝆂◌𝆂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING LOURE, LATIN SMALL LETTER B +0061 1D182 059A 0316 302A 0062;0061 302A 1D182 0316 059A 0062;0061 302A 1D182 0316 059A 0062;0061 302A 1D182 0316 059A 0062;0061 302A 1D182 0316 059A 0062; # (a◌𝆂◌𝆂◌֚◌̖◌〪b; a◌〪◌𝆂◌𝆂◌̖◌֚b; a◌〪◌𝆂◌𝆂◌̖◌֚b; a◌〪◌𝆂◌𝆂◌̖◌֚b; a◌〪◌𝆂◌𝆂◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING LOURE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D185 0062;00E0 05AE 1D185 0315 0062;0061 05AE 0300 1D185 0315 0062;00E0 05AE 1D185 0315 0062;0061 05AE 0300 1D185 0315 0062; # (a◌̕◌̀◌֮◌𝆅◌𝆅b; à◌֮◌𝆅◌𝆅◌̕b; a◌֮◌̀◌𝆅◌𝆅◌̕b; à◌֮◌𝆅◌𝆅◌̕b; a◌֮◌̀◌𝆅◌𝆅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING DOIT, LATIN SMALL LETTER B +0061 1D185 0315 0300 05AE 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062; # (a◌𝆅◌𝆅◌̕◌̀◌֮b; a◌֮◌𝆅◌𝆅◌̀◌̕b; a◌֮◌𝆅◌𝆅◌̀◌̕b; a◌֮◌𝆅◌𝆅◌̀◌̕b; a◌֮◌𝆅◌𝆅◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOIT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D186 0062;00E0 05AE 1D186 0315 0062;0061 05AE 0300 1D186 0315 0062;00E0 05AE 1D186 0315 0062;0061 05AE 0300 1D186 0315 0062; # (a◌̕◌̀◌֮◌𝆆◌𝆆b; à◌֮◌𝆆◌𝆆◌̕b; a◌֮◌̀◌𝆆◌𝆆◌̕b; à◌֮◌𝆆◌𝆆◌̕b; a◌֮◌̀◌𝆆◌𝆆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING RIP, LATIN SMALL LETTER B +0061 1D186 0315 0300 05AE 0062;0061 05AE 1D186 0300 0315 0062;0061 05AE 1D186 0300 0315 0062;0061 05AE 1D186 0300 0315 0062;0061 05AE 1D186 0300 0315 0062; # (a◌𝆆◌𝆆◌̕◌̀◌֮b; a◌֮◌𝆆◌𝆆◌̀◌̕b; a◌֮◌𝆆◌𝆆◌̀◌̕b; a◌֮◌𝆆◌𝆆◌̀◌̕b; a◌֮◌𝆆◌𝆆◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING RIP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D187 0062;00E0 05AE 1D187 0315 0062;0061 05AE 0300 1D187 0315 0062;00E0 05AE 1D187 0315 0062;0061 05AE 0300 1D187 0315 0062; # (a◌̕◌̀◌֮◌𝆇◌𝆇b; à◌֮◌𝆇◌𝆇◌̕b; a◌֮◌̀◌𝆇◌𝆇◌̕b; à◌֮◌𝆇◌𝆇◌̕b; a◌֮◌̀◌𝆇◌𝆇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING FLIP, LATIN SMALL LETTER B +0061 1D187 0315 0300 05AE 0062;0061 05AE 1D187 0300 0315 0062;0061 05AE 1D187 0300 0315 0062;0061 05AE 1D187 0300 0315 0062;0061 05AE 1D187 0300 0315 0062; # (a◌𝆇◌𝆇◌̕◌̀◌֮b; a◌֮◌𝆇◌𝆇◌̀◌̕b; a◌֮◌𝆇◌𝆇◌̀◌̕b; a◌֮◌𝆇◌𝆇◌̀◌̕b; a◌֮◌𝆇◌𝆇◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLIP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D188 0062;00E0 05AE 1D188 0315 0062;0061 05AE 0300 1D188 0315 0062;00E0 05AE 1D188 0315 0062;0061 05AE 0300 1D188 0315 0062; # (a◌̕◌̀◌֮◌𝆈◌𝆈b; à◌֮◌𝆈◌𝆈◌̕b; a◌֮◌̀◌𝆈◌𝆈◌̕b; à◌֮◌𝆈◌𝆈◌̕b; a◌֮◌̀◌𝆈◌𝆈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING SMEAR, LATIN SMALL LETTER B +0061 1D188 0315 0300 05AE 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062; # (a◌𝆈◌𝆈◌̕◌̀◌֮b; a◌֮◌𝆈◌𝆈◌̀◌̕b; a◌֮◌𝆈◌𝆈◌̀◌̕b; a◌֮◌𝆈◌𝆈◌̀◌̕b; a◌֮◌𝆈◌𝆈◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SMEAR, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D189 0062;00E0 05AE 1D189 0315 0062;0061 05AE 0300 1D189 0315 0062;00E0 05AE 1D189 0315 0062;0061 05AE 0300 1D189 0315 0062; # (a◌̕◌̀◌֮◌𝆉◌𝆉b; à◌֮◌𝆉◌𝆉◌̕b; a◌֮◌̀◌𝆉◌𝆉◌̕b; à◌֮◌𝆉◌𝆉◌̕b; a◌֮◌̀◌𝆉◌𝆉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING BEND, LATIN SMALL LETTER B +0061 1D189 0315 0300 05AE 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062; # (a◌𝆉◌𝆉◌̕◌̀◌֮b; a◌֮◌𝆉◌𝆉◌̀◌̕b; a◌֮◌𝆉◌𝆉◌̀◌̕b; a◌֮◌𝆉◌𝆉◌̀◌̕b; a◌֮◌𝆉◌𝆉◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING BEND, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 1D18A 0062;0061 302A 0316 1D18A 059A 0062;0061 302A 0316 1D18A 059A 0062;0061 302A 0316 1D18A 059A 0062;0061 302A 0316 1D18A 059A 0062; # (a◌֚◌̖◌〪◌𝆊◌𝆊b; a◌〪◌̖◌𝆊◌𝆊◌֚b; a◌〪◌̖◌𝆊◌𝆊◌֚b; a◌〪◌̖◌𝆊◌𝆊◌֚b; a◌〪◌̖◌𝆊◌𝆊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, LATIN SMALL LETTER B +0061 1D18A 059A 0316 302A 0062;0061 302A 1D18A 0316 059A 0062;0061 302A 1D18A 0316 059A 0062;0061 302A 1D18A 0316 059A 0062;0061 302A 1D18A 0316 059A 0062; # (a◌𝆊◌𝆊◌֚◌̖◌〪b; a◌〪◌𝆊◌𝆊◌̖◌֚b; a◌〪◌𝆊◌𝆊◌̖◌֚b; a◌〪◌𝆊◌𝆊◌̖◌֚b; a◌〪◌𝆊◌𝆊◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 302A 1D18B 0062;0061 302A 0316 1D18B 059A 0062;0061 302A 0316 1D18B 059A 0062;0061 302A 0316 1D18B 059A 0062;0061 302A 0316 1D18B 059A 0062; # (a◌֚◌̖◌〪◌𝆋◌𝆋b; a◌〪◌̖◌𝆋◌𝆋◌֚b; a◌〪◌̖◌𝆋◌𝆋◌֚b; a◌〪◌̖◌𝆋◌𝆋◌֚b; a◌〪◌̖◌𝆋◌𝆋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, LATIN SMALL LETTER B +0061 1D18B 059A 0316 302A 0062;0061 302A 1D18B 0316 059A 0062;0061 302A 1D18B 0316 059A 0062;0061 302A 1D18B 0316 059A 0062;0061 302A 1D18B 0316 059A 0062; # (a◌𝆋◌𝆋◌֚◌̖◌〪b; a◌〪◌𝆋◌𝆋◌̖◌֚b; a◌〪◌𝆋◌𝆋◌̖◌֚b; a◌〪◌𝆋◌𝆋◌̖◌֚b; a◌〪◌𝆋◌𝆋◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AA 0062;00E0 05AE 1D1AA 0315 0062;0061 05AE 0300 1D1AA 0315 0062;00E0 05AE 1D1AA 0315 0062;0061 05AE 0300 1D1AA 0315 0062; # (a◌̕◌̀◌֮◌𝆪◌𝆪b; à◌֮◌𝆪◌𝆪◌̕b; a◌֮◌̀◌𝆪◌𝆪◌̕b; à◌֮◌𝆪◌𝆪◌̕b; a◌֮◌̀◌𝆪◌𝆪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING DOWN BOW, LATIN SMALL LETTER B +0061 1D1AA 0315 0300 05AE 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062; # (a◌𝆪◌𝆪◌̕◌̀◌֮b; a◌֮◌𝆪◌𝆪◌̀◌̕b; a◌֮◌𝆪◌𝆪◌̀◌̕b; a◌֮◌𝆪◌𝆪◌̀◌̕b; a◌֮◌𝆪◌𝆪◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOWN BOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AB 0062;00E0 05AE 1D1AB 0315 0062;0061 05AE 0300 1D1AB 0315 0062;00E0 05AE 1D1AB 0315 0062;0061 05AE 0300 1D1AB 0315 0062; # (a◌̕◌̀◌֮◌𝆫◌𝆫b; à◌֮◌𝆫◌𝆫◌̕b; a◌֮◌̀◌𝆫◌𝆫◌̕b; à◌֮◌𝆫◌𝆫◌̕b; a◌֮◌̀◌𝆫◌𝆫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING UP BOW, LATIN SMALL LETTER B +0061 1D1AB 0315 0300 05AE 0062;0061 05AE 1D1AB 0300 0315 0062;0061 05AE 1D1AB 0300 0315 0062;0061 05AE 1D1AB 0300 0315 0062;0061 05AE 1D1AB 0300 0315 0062; # (a◌𝆫◌𝆫◌̕◌̀◌֮b; a◌֮◌𝆫◌𝆫◌̀◌̕b; a◌֮◌𝆫◌𝆫◌̀◌̕b; a◌֮◌𝆫◌𝆫◌̀◌̕b; a◌֮◌𝆫◌𝆫◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING UP BOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AC 0062;00E0 05AE 1D1AC 0315 0062;0061 05AE 0300 1D1AC 0315 0062;00E0 05AE 1D1AC 0315 0062;0061 05AE 0300 1D1AC 0315 0062; # (a◌̕◌̀◌֮◌𝆬◌𝆬b; à◌֮◌𝆬◌𝆬◌̕b; a◌֮◌̀◌𝆬◌𝆬◌̕b; à◌֮◌𝆬◌𝆬◌̕b; a◌֮◌̀◌𝆬◌𝆬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING HARMONIC, LATIN SMALL LETTER B +0061 1D1AC 0315 0300 05AE 0062;0061 05AE 1D1AC 0300 0315 0062;0061 05AE 1D1AC 0300 0315 0062;0061 05AE 1D1AC 0300 0315 0062;0061 05AE 1D1AC 0300 0315 0062; # (a◌𝆬◌𝆬◌̕◌̀◌֮b; a◌֮◌𝆬◌𝆬◌̀◌̕b; a◌֮◌𝆬◌𝆬◌̀◌̕b; a◌֮◌𝆬◌𝆬◌̀◌̕b; a◌֮◌𝆬◌𝆬◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING HARMONIC, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AD 0062;00E0 05AE 1D1AD 0315 0062;0061 05AE 0300 1D1AD 0315 0062;00E0 05AE 1D1AD 0315 0062;0061 05AE 0300 1D1AD 0315 0062; # (a◌̕◌̀◌֮◌𝆭◌𝆭b; à◌֮◌𝆭◌𝆭◌̕b; a◌֮◌̀◌𝆭◌𝆭◌̕b; à◌֮◌𝆭◌𝆭◌̕b; a◌֮◌̀◌𝆭◌𝆭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING SNAP PIZZICATO, LATIN SMALL LETTER B +0061 1D1AD 0315 0300 05AE 0062;0061 05AE 1D1AD 0300 0315 0062;0061 05AE 1D1AD 0300 0315 0062;0061 05AE 1D1AD 0300 0315 0062;0061 05AE 1D1AD 0300 0315 0062; # (a◌𝆭◌𝆭◌̕◌̀◌֮b; a◌֮◌𝆭◌𝆭◌̀◌̕b; a◌֮◌𝆭◌𝆭◌̀◌̕b; a◌֮◌𝆭◌𝆭◌̀◌̕b; a◌֮◌𝆭◌𝆭◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SNAP PIZZICATO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +# +# END OF FILE diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 2299d1fab2e..ace56aab7ac 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3,6 +3,7 @@ import bisect import contextlib import copy import decimal +import fractions import io import itertools import os @@ -2626,6 +2627,10 @@ class TestDateTime(TestDate): expected = time.localtime(ts) got = self.theclass.fromtimestamp(ts) self.verify_field_equality(expected, got) + got = self.theclass.fromtimestamp(decimal.Decimal(ts)) + self.verify_field_equality(expected, got) + got = self.theclass.fromtimestamp(fractions.Fraction(ts)) + self.verify_field_equality(expected, got) def test_fromtimestamp_keyword_arg(self): import time @@ -2641,6 +2646,12 @@ class TestDateTime(TestDate): with self.assertWarns(DeprecationWarning): got = self.theclass.utcfromtimestamp(ts) self.verify_field_equality(expected, got) + with self.assertWarns(DeprecationWarning): + got = self.theclass.utcfromtimestamp(decimal.Decimal(ts)) + self.verify_field_equality(expected, got) + with self.assertWarns(DeprecationWarning): + got = self.theclass.utcfromtimestamp(fractions.Fraction(ts)) + self.verify_field_equality(expected, got) # Run with US-style DST rules: DST begins 2 a.m. on second Sunday in # March (M3.2.0) and ends 2 a.m. on first Sunday in November (M11.1.0). @@ -2728,6 +2739,108 @@ class TestDateTime(TestDate): self.assertEqual(t.second, 0) self.assertEqual(t.microsecond, 7812) + @support.run_with_tz('MSK-03') # Something east of Greenwich + def test_microsecond_rounding_decimal(self): + D = decimal.Decimal + def utcfromtimestamp(*args, **kwargs): + with self.assertWarns(DeprecationWarning): + return self.theclass.utcfromtimestamp(*args, **kwargs) + + for fts in [self.theclass.fromtimestamp, + utcfromtimestamp]: + zero = fts(D(0)) + self.assertEqual(zero.second, 0) + self.assertEqual(zero.microsecond, 0) + one = fts(D('0.000_001')) + try: + minus_one = fts(D('-0.000_001')) + except OSError: + # localtime(-1) and gmtime(-1) is not supported on Windows + pass + else: + self.assertEqual(minus_one.second, 59) + self.assertEqual(minus_one.microsecond, 999_999) + + t = fts(D('-0.000_000_1')) + self.assertEqual(t, zero) + t = fts(D('-0.000_000_9')) + self.assertEqual(t, minus_one) + t = fts(D(-1)/2**7) + self.assertEqual(t.second, 59) + self.assertEqual(t.microsecond, 992188) + + t = fts(D('0.000_000_1')) + self.assertEqual(t, zero) + t = fts(D('0.000_000_5')) + self.assertEqual(t, zero) + t = fts(D('0.000_000_500_000_000_000_000_1')) + self.assertEqual(t, one) + t = fts(D('0.000_000_9')) + self.assertEqual(t, one) + t = fts(D('0.999_999_499_999_999_9')) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 999_999) + t = fts(D('0.999_999_5')) + self.assertEqual(t.second, 1) + self.assertEqual(t.microsecond, 0) + t = fts(D('0.999_999_9')) + self.assertEqual(t.second, 1) + self.assertEqual(t.microsecond, 0) + t = fts(D(1)/2**7) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 7812) + + @support.run_with_tz('MSK-03') # Something east of Greenwich + def test_microsecond_rounding_fraction(self): + F = fractions.Fraction + def utcfromtimestamp(*args, **kwargs): + with self.assertWarns(DeprecationWarning): + return self.theclass.utcfromtimestamp(*args, **kwargs) + + for fts in [self.theclass.fromtimestamp, + utcfromtimestamp]: + zero = fts(F(0)) + self.assertEqual(zero.second, 0) + self.assertEqual(zero.microsecond, 0) + one = fts(F(1, 1_000_000)) + try: + minus_one = fts(F(-1, 1_000_000)) + except OSError: + # localtime(-1) and gmtime(-1) is not supported on Windows + pass + else: + self.assertEqual(minus_one.second, 59) + self.assertEqual(minus_one.microsecond, 999_999) + + t = fts(F(-1, 10_000_000)) + self.assertEqual(t, zero) + t = fts(F(-9, 10_000_000)) + self.assertEqual(t, minus_one) + t = fts(F(-1, 2**7)) + self.assertEqual(t.second, 59) + self.assertEqual(t.microsecond, 992188) + + t = fts(F(1, 10_000_000)) + self.assertEqual(t, zero) + t = fts(F(5, 10_000_000)) + self.assertEqual(t, zero) + t = fts(F(5_000_000_000, 9_999_999_999_999_999)) + self.assertEqual(t, one) + t = fts(F(9, 10_000_000)) + self.assertEqual(t, one) + t = fts(F(9_999_995_000_000_000, 10_000_000_000_000_001)) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 999_999) + t = fts(F(9_999_995, 10_000_000)) + self.assertEqual(t.second, 1) + self.assertEqual(t.microsecond, 0) + t = fts(F(9_999_999, 10_000_000)) + self.assertEqual(t.second, 1) + self.assertEqual(t.microsecond, 0) + t = fts(F(1, 2**7)) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 7812) + def test_timestamp_limits(self): with self.subTest("minimum UTC"): min_dt = self.theclass.min.replace(tzinfo=timezone.utc) @@ -2907,6 +3020,12 @@ class TestDateTime(TestDate): strptime("-00:02:01.000003", "%z").utcoffset(), -timedelta(minutes=2, seconds=1, microseconds=3) ) + self.assertEqual(strptime("+01:07", "%:z").utcoffset(), + 1 * HOUR + 7 * MINUTE) + self.assertEqual(strptime("-10:02", "%:z").utcoffset(), + -(10 * HOUR + 2 * MINUTE)) + self.assertEqual(strptime("-00:00:01.00001", "%:z").utcoffset(), + -timedelta(seconds=1, microseconds=10)) # Only local timezone and UTC are supported for tzseconds, tzname in ((0, 'UTC'), (0, 'GMT'), (-_time.timezone, _time.tzname[0])): @@ -2936,6 +3055,16 @@ class TestDateTime(TestDate): with self.assertRaises(ValueError): strptime("-000", "%z") with self.assertRaises(ValueError): strptime("z", "%z") + def test_strptime_ampm(self): + dt = datetime(1999, 3, 17, 0, 44, 55, 2) + for hour in range(0, 24): + with self.subTest(hour=hour): + new_dt = dt.replace(hour=hour) + dt_str = new_dt.strftime("%I %p") + + self.assertEqual(self.theclass.strptime(dt_str, "%I %p").hour, + hour) + def test_strptime_single_digit(self): # bpo-34903: Check that single digit dates and times are allowed. @@ -2985,7 +3114,7 @@ class TestDateTime(TestDate): self.theclass.strptime('02-29,2024', '%m-%d,%Y') def test_strptime_z_empty(self): - for directive in ('z',): + for directive in ('z', ':z'): string = '2025-04-25 11:42:47' format = f'%Y-%m-%d %H:%M:%S%{directive}' target = self.theclass(2025, 4, 25, 11, 42, 47) @@ -4053,6 +4182,12 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase): strptime("-00:02:01.000003", "%z").utcoffset(), -timedelta(minutes=2, seconds=1, microseconds=3) ) + self.assertEqual(strptime("+01:07", "%:z").utcoffset(), + 1 * HOUR + 7 * MINUTE) + self.assertEqual(strptime("-10:02", "%:z").utcoffset(), + -(10 * HOUR + 2 * MINUTE)) + self.assertEqual(strptime("-00:00:01.00001", "%:z").utcoffset(), + -timedelta(seconds=1, microseconds=10)) # Only local timezone and UTC are supported for tzseconds, tzname in ((0, 'UTC'), (0, 'GMT'), (-_time.timezone, _time.tzname[0])): @@ -4082,9 +4217,11 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase): self.assertEqual(strptime("UTC", "%Z").tzinfo, None) def test_strptime_errors(self): - for tzstr in ("-2400", "-000", "z"): + for tzstr in ("-2400", "-000", "z", "24:00"): with self.assertRaises(ValueError): self.theclass.strptime(tzstr, "%z") + with self.assertRaises(ValueError): + self.theclass.strptime(tzstr, "%:z") def test_strptime_single_digit(self): # bpo-34903: Check that single digit times are allowed. @@ -6163,21 +6300,21 @@ class TestLocalTimeDisambiguation(unittest.TestCase): gdt = datetime(1941, 6, 23, 20, 59, 59, tzinfo=timezone.utc) ldt = gdt.astimezone(Vilnius) - self.assertEqual(ldt.strftime("%c %Z%z"), + self.assertEqual(ldt.strftime("%a %b %d %H:%M:%S %Y %Z%z"), 'Mon Jun 23 23:59:59 1941 MSK+0300') self.assertEqual(ldt.fold, 0) self.assertFalse(ldt.dst()) gdt = datetime(1941, 6, 23, 21, tzinfo=timezone.utc) ldt = gdt.astimezone(Vilnius) - self.assertEqual(ldt.strftime("%c %Z%z"), + self.assertEqual(ldt.strftime("%a %b %d %H:%M:%S %Y %Z%z"), 'Mon Jun 23 23:00:00 1941 CEST+0200') self.assertEqual(ldt.fold, 1) self.assertTrue(ldt.dst()) gdt = datetime(1941, 6, 23, 22, tzinfo=timezone.utc) ldt = gdt.astimezone(Vilnius) - self.assertEqual(ldt.strftime("%c %Z%z"), + self.assertEqual(ldt.strftime("%a %b %d %H:%M:%S %Y %Z%z"), 'Tue Jun 24 00:00:00 1941 CEST+0200') self.assertEqual(ldt.fold, 0) self.assertTrue(ldt.dst()) @@ -6187,22 +6324,22 @@ class TestLocalTimeDisambiguation(unittest.TestCase): ldt = datetime(1941, 6, 23, 22, 59, 59, tzinfo=Vilnius) gdt = ldt.astimezone(timezone.utc) - self.assertEqual(gdt.strftime("%c %Z"), + self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"), 'Mon Jun 23 19:59:59 1941 UTC') ldt = datetime(1941, 6, 23, 23, 59, 59, tzinfo=Vilnius) gdt = ldt.astimezone(timezone.utc) - self.assertEqual(gdt.strftime("%c %Z"), + self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"), 'Mon Jun 23 20:59:59 1941 UTC') ldt = datetime(1941, 6, 23, 23, 59, 59, tzinfo=Vilnius, fold=1) gdt = ldt.astimezone(timezone.utc) - self.assertEqual(gdt.strftime("%c %Z"), + self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"), 'Mon Jun 23 21:59:59 1941 UTC') ldt = datetime(1941, 6, 24, 0, tzinfo=Vilnius) gdt = ldt.astimezone(timezone.utc) - self.assertEqual(gdt.strftime("%c %Z"), + self.assertEqual(gdt.strftime("%a %b %d %H:%M:%S %Y %Z"), 'Mon Jun 23 22:00:00 1941 UTC') def test_constructors(self): diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py index 07681d75448..e7a12e4d0b6 100644 --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -271,6 +271,9 @@ def _create_parser(): group = parser.add_argument_group('Selecting tests') group.add_argument('-r', '--randomize', action='store_true', help='randomize test execution order.' + more_details) + group.add_argument('--no-randomize', dest='no_randomize', action='store_true', + help='do not randomize test execution order, even if ' + 'it would be implied by another option') group.add_argument('--prioritize', metavar='TEST1,TEST2,...', action='append', type=priority_list, help='select these tests first, even if the order is' @@ -461,7 +464,11 @@ def _parse_args(args, **kwargs): if ns.python is None: ns.rerun = True ns.print_slow = True - ns.verbose3 = True + if not ns.verbose: + ns.verbose3 = True + else: + # --verbose has the priority over --verbose3 + pass else: ns._add_python_opts = False @@ -539,6 +546,8 @@ def _parse_args(args, **kwargs): ns.use_resources.append(r) if ns.random_seed is not None: ns.randomize = True + if ns.no_randomize: + ns.randomize = False if ns.verbose: ns.header = True diff --git a/Lib/test/libregrtest/findtests.py b/Lib/test/libregrtest/findtests.py index f01c1240774..6c0e50846a4 100644 --- a/Lib/test/libregrtest/findtests.py +++ b/Lib/test/libregrtest/findtests.py @@ -24,10 +24,12 @@ SPLITTESTDIRS: set[TestName] = { "test_future_stmt", "test_gdb", "test_inspect", - "test_pydoc", + "test_io", "test_multiprocessing_fork", "test_multiprocessing_forkserver", "test_multiprocessing_spawn", + "test_os", + "test_pydoc", } diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index a2d01b157ac..0fc2548789e 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -646,15 +646,23 @@ class Regrtest: return (environ, keep_environ) def _add_ci_python_opts(self, python_opts, keep_environ): - # --fast-ci and --slow-ci add options to Python: - # "-u -W default -bb -E" + # --fast-ci and --slow-ci add options to Python. + # + # Some platforms run tests in embedded mode and cannot change options + # after startup, so if this function changes, consider also updating: + # * gradle_task in Android/android.py - # Unbuffered stdout and stderr - if not sys.stdout.write_through: + # Unbuffered stdout and stderr. This isn't helpful on Android, because + # it would cause lines to be split into multiple log messages. + if not sys.stdout.write_through and sys.platform != "android": python_opts.append('-u') - # Add warnings filter 'error' - if 'default' not in sys.warnoptions: + # Add warnings filter 'error', unless the user specified a different + # filter. Ignore BytesWarning since it's controlled by '-b' below. + if not [ + opt for opt in sys.warnoptions + if not opt.endswith("::BytesWarning") + ]: python_opts.extend(('-W', 'error')) # Error on bytes/str comparison @@ -673,8 +681,12 @@ class Regrtest: cmd_text = shlex.join(cmd) try: - print(f"+ {cmd_text}", flush=True) + # Android and iOS run tests in embedded mode. To update their + # Python options, see the comment in _add_ci_python_opts. + if not cmd[0]: + raise ValueError("No Python executable is present") + print(f"+ {cmd_text}", flush=True) if hasattr(os, 'execv') and not MS_WINDOWS: os.execv(cmd[0], cmd) # On success, execv() do no return. diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 5c78515506d..e7da17e500e 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -93,6 +93,13 @@ def runtest_refleak(test_name, test_func, for obj in abc.__subclasses__() + [abc]: abcs[obj] = _get_dump(obj)[0] + # `ByteString` is not included in `collections.abc.__all__` + with warnings.catch_warnings(action='ignore', category=DeprecationWarning): + ByteString = collections.abc.ByteString + # Mypy doesn't even think `ByteString` is a class, hence the `type: ignore` + for obj in ByteString.__subclasses__() + [ByteString]: # type: ignore[attr-defined] + abcs[obj] = _get_dump(obj)[0] + # bpo-31217: Integer pool to get a single integer object for the same # value. The pool is used to prevent false alarm when checking for memory # block leaks. Fill the pool with values in -1000..1000 which are the most @@ -254,6 +261,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs, linecache_data): # Clear ABC registries, restoring previously saved ABC registries. abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] + with warnings.catch_warnings(action='ignore', category=DeprecationWarning): + abs_classes.append(collections.abc.ByteString) abs_classes = filter(isabstract, abs_classes) for abc in abs_classes: for obj in abc.__subclasses__() + [abc]: diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index 4cf1a075b30..138465012a2 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -9,6 +9,13 @@ from test.support import os_helper from .utils import print_warning +# Import termios to save and restore terminal echo. This is only available on +# Unix, and it's fine if the module can't be found. +try: + import termios # noqa: F401 +except ModuleNotFoundError: + pass + class SkipTestEnvironment(Exception): pass @@ -65,6 +72,7 @@ class saved_test_environment: 'shutil_archive_formats', 'shutil_unpack_formats', 'asyncio.events._event_loop_policy', 'urllib.requests._url_tempfiles', 'urllib.requests._opener', + 'stty_echo', ) def get_module(self, name): @@ -292,6 +300,24 @@ class saved_test_environment: warnings = self.get_module('warnings') warnings.showwarning = fxn + def get_stty_echo(self): + termios = self.try_get_module('termios') + if not os.isatty(fd := sys.__stdin__.fileno()): + return None + attrs = termios.tcgetattr(fd) + lflags = attrs[3] + return bool(lflags & termios.ECHO) + def restore_stty_echo(self, echo): + termios = self.get_module('termios') + attrs = termios.tcgetattr(fd := sys.__stdin__.fileno()) + if echo: + # Turn echo on. + attrs[3] |= termios.ECHO + else: + # Turn echo off. + attrs[3] &= ~termios.ECHO + termios.tcsetattr(fd, termios.TCSADRAIN, attrs) + def resource_info(self): for name in self.resources: method_suffix = name.replace('.', '_') diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index 9bfc414cd61..b9b76a44e3b 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -8,6 +8,7 @@ import sys import unittest from test import support from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII +from _colorize import can_colorize # type: ignore[import-not-found] from .filter import set_match_tests from .runtests import RunTests @@ -139,3 +140,10 @@ def setup_tests(runtests: RunTests) -> None: gc.set_threshold(runtests.gc_threshold) random.seed(runtests.random_seed) + + # sys.stdout is redirected to a StringIO in single process mode on which + # color auto-detect fails as StringIO is not a TTY. If the original + # sys.stdout supports color pass that through with FORCE_COLOR so that when + # results are printed, such as with -W, they get color. + if can_colorize(file=sys.stdout): + os.environ['FORCE_COLOR'] = "1" diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index d94fb84a743..cfb009c203e 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -294,6 +294,25 @@ def clear_caches(): else: importlib_metadata.FastPath.__new__.cache_clear() + try: + encodings = sys.modules['encodings'] + except KeyError: + pass + else: + encodings._cache.clear() + + try: + codecs = sys.modules['codecs'] + except KeyError: + pass + else: + # There's no direct API to clear the codecs search cache, but + # `unregister` clears it implicitly. + def noop_search_function(name): + return None + codecs.register(noop_search_function) + codecs.unregister(noop_search_function) + def get_build_info(): # Get most important configure and build options as a list of strings. diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py index 5d75bf7ae78..1ad67e1cebf 100644 --- a/Lib/test/libregrtest/worker.py +++ b/Lib/test/libregrtest/worker.py @@ -1,6 +1,7 @@ import subprocess import sys import os +from _colorize import can_colorize # type: ignore[import-not-found] from typing import Any, NoReturn from test.support import os_helper, Py_DEBUG @@ -32,6 +33,12 @@ def create_worker_process(runtests: WorkerRunTests, output_fd: int, env['TEMP'] = tmp_dir env['TMP'] = tmp_dir + # The subcommand is run with a temporary output which means it is not a TTY + # and won't auto-color. The test results are printed to stdout so if we can + # color that have the subprocess use color. + if can_colorize(file=sys.stdout): + env['FORCE_COLOR'] = '1' + # Running the child from the same working directory as regrtest's original # invocation ensures that TEMPDIR for the child is the same when # sysconfig.is_python_build() is true. See issue 15300. diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index 68d6bad2094..e76f79c274e 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -32,13 +32,13 @@ class CommonTest(seq_tests.CommonTest): self.assertEqual(a, b) def test_getitem_error(self): - a = [] + a = self.type2test([]) msg = "list indices must be integers or slices" with self.assertRaisesRegex(TypeError, msg): a['a'] def test_setitem_error(self): - a = [] + a = self.type2test([]) msg = "list indices must be integers or slices" with self.assertRaisesRegex(TypeError, msg): a['a'] = "python" @@ -561,7 +561,7 @@ class CommonTest(seq_tests.CommonTest): class F(object): def __iter__(self): raise KeyboardInterrupt - self.assertRaises(KeyboardInterrupt, list, F()) + self.assertRaises(KeyboardInterrupt, self.type2test, F()) def test_exhausted_iterator(self): a = self.type2test([1, 2, 3]) diff --git a/Lib/test/mp_preload_flush.py b/Lib/test/mp_preload_flush.py index 3501554d366..c195a9ef6b2 100644 --- a/Lib/test/mp_preload_flush.py +++ b/Lib/test/mp_preload_flush.py @@ -1,15 +1,11 @@ import multiprocessing import sys -modname = 'preloaded_module' +print(__name__, end='', file=sys.stderr) +print(__name__, end='', file=sys.stdout) if __name__ == '__main__': - if modname in sys.modules: - raise AssertionError(f'{modname!r} is not in sys.modules') multiprocessing.set_start_method('forkserver') - multiprocessing.set_forkserver_preload([modname]) for _ in range(2): p = multiprocessing.Process() p.start() p.join() -elif modname not in sys.modules: - raise AssertionError(f'{modname!r} is not in sys.modules') diff --git a/Lib/test/mp_preload_main.py b/Lib/test/mp_preload_main.py new file mode 100644 index 00000000000..acb342822ec --- /dev/null +++ b/Lib/test/mp_preload_main.py @@ -0,0 +1,14 @@ +import multiprocessing + +print(f"{__name__}") + +def f(): + print("f") + +if __name__ == "__main__": + ctx = multiprocessing.get_context("forkserver") + ctx.set_forkserver_preload(['__main__']) + for _ in range(2): + p = ctx.Process(target=f) + p.start() + p.join() diff --git a/Lib/test/multibytecodec_support.py b/Lib/test/multibytecodec_support.py index dbf0cc428e3..6b4c57d0b4b 100644 --- a/Lib/test/multibytecodec_support.py +++ b/Lib/test/multibytecodec_support.py @@ -282,6 +282,23 @@ class TestBase: with self.assertRaises(AttributeError): del e.errors + def test_null_terminator(self): + # see gh-101828 + text = "フルーツ" + try: + text.encode(self.encoding) + except UnicodeEncodeError: + text = "Python is cool" + encode_w_null = (text + "\0").encode(self.encoding) + encode_plus_null = text.encode(self.encoding) + "\0".encode(self.encoding) + self.assertTrue(encode_w_null.endswith(b'\x00')) + self.assertEqual(encode_w_null, encode_plus_null) + + encode_w_null_2 = (text + "\0" + text + "\0").encode(self.encoding) + encode_plus_null_2 = encode_plus_null + encode_plus_null + self.assertEqual(encode_w_null_2.count(b'\x00'), 2) + self.assertEqual(encode_w_null_2, encode_plus_null_2) + class TestBase_Mapping(unittest.TestCase): pass_enctest = [] diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 1a7658b13fa..4e3468bfcde 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -74,6 +74,15 @@ def count_opcode(code, pickle): def identity(x): return x +def itersize(start, stop): + # Produce geometrical increasing sequence from start to stop + # (inclusively) for tests. + size = start + while size < stop: + yield size + size <<= 1 + yield stop + class UnseekableIO(io.BytesIO): def peek(self, *args): @@ -853,9 +862,8 @@ class AbstractUnpickleTests: self.assertEqual(getattr(obj, slot, None), getattr(objcopy, slot, None), msg=msg) - def check_unpickling_error(self, errors, data): - with self.subTest(data=data), \ - self.assertRaises(errors): + def check_unpickling_error_strict(self, errors, data): + with self.assertRaises(errors): try: self.loads(data) except BaseException as exc: @@ -864,6 +872,10 @@ class AbstractUnpickleTests: (data, exc.__class__.__name__, exc)) raise + def check_unpickling_error(self, errors, data): + with self.subTest(data=data): + self.check_unpickling_error_strict(errors, data) + def test_load_from_data0(self): self.assert_is_copy(self._testdata, self.loads(DATA0)) @@ -1150,6 +1162,155 @@ class AbstractUnpickleTests: dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.' self.check_unpickling_error(ValueError, dumped) + def test_too_large_put(self): + # Test that PUT with large id does not cause allocation of + # too large memo table. The C implementation uses a dict-based memo + # for sparse indices (when idx > memo_len * 2) instead of allocating + # a massive array. This test verifies large sparse indices work without + # causing memory exhaustion. + # + # The following simple pickle creates an empty list, memoizes it + # using a large index, then loads it back on the stack, builds + # a tuple containing 2 identical empty lists and returns it. + data = lambda n: (b'((lp' + str(n).encode() + b'\n' + + b'g' + str(n).encode() + b'\nt.') + # 0: ( MARK + # 1: ( MARK + # 2: l LIST (MARK at 1) + # 3: p PUT 1000000000000 + # 18: g GET 1000000000000 + # 33: t TUPLE (MARK at 0) + # 34: . STOP + for idx in [10**6, 10**9, 10**12]: + if idx > sys.maxsize: + continue + self.assertEqual(self.loads(data(idx)), ([],)*2) + + def test_too_large_long_binput(self): + # Test that LONG_BINPUT with large id does not cause allocation of + # too large memo table. The C implementation uses a dict-based memo + # for sparse indices (when idx > memo_len * 2) instead of allocating + # a massive array. This test verifies large sparse indices work without + # causing memory exhaustion. + # + # The following simple pickle creates an empty list, memoizes it + # using a large index, then loads it back on the stack, builds + # a tuple containing 2 identical empty lists and returns it. + data = lambda n: (b'(]r' + struct.pack(' sys.maxsize')) + + def test_truncated_large_binunicode8(self): + data = lambda size: b'\x8d' + struct.pack(' types.FunctionType: f.__code__ = f.__code__.replace() return f +on_github_actions = "GITHUB_ACTIONS" in os.environ #======================================================================= # Check for the presence of docstrings. @@ -2898,7 +2997,7 @@ def force_color(color: bool): from .os_helper import EnvironmentVarGuard with ( - swap_attr(_colorize, "can_colorize", lambda file=None: color), + swap_attr(_colorize, "can_colorize", lambda *, file=None: color), EnvironmentVarGuard() as env, ): env.unset("FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS") diff --git a/Lib/test/support/_hypothesis_stubs/__init__.py b/Lib/test/support/_hypothesis_stubs/__init__.py index 6ba5bb814b9..6fa013b55b2 100644 --- a/Lib/test/support/_hypothesis_stubs/__init__.py +++ b/Lib/test/support/_hypothesis_stubs/__init__.py @@ -24,7 +24,13 @@ def given(*_args, **_kwargs): @functools.wraps(f) def test_function(self): for example_args, example_kwargs in examples: - with self.subTest(*example_args, **example_kwargs): + if len(example_args) < 2: + subtest_args = example_args + else: + # subTest takes up to one positional argument. + # When there are more, display them as a tuple + subtest_args = [example_args] + with self.subTest(*subtest_args, **example_kwargs): f(self, *example_args, **example_kwargs) else: diff --git a/Lib/test/support/hashlib_helper.py b/Lib/test/support/hashlib_helper.py index 96be74e4105..49077d7cb4d 100644 --- a/Lib/test/support/hashlib_helper.py +++ b/Lib/test/support/hashlib_helper.py @@ -9,15 +9,68 @@ from test.support import import_helper from types import MappingProxyType -def try_import_module(module_name): - """Try to import a module and return None on failure.""" +def _parse_fullname(fullname, *, strict=False): + """Parse a fully-qualified name ``.``. + + The ``module_name`` component contains one or more dots. + The ``member_name`` component does not contain any dot. + + If *strict* is true, *fullname* must be a string. Otherwise, + it can be None, and, ``module_name`` and ``member_name`` will + also be None. + """ + if fullname is None: + assert not strict + return None, None + assert isinstance(fullname, str), fullname + assert fullname.count(".") >= 1, fullname + module_name, member_name = fullname.rsplit(".", maxsplit=1) + return module_name, member_name + + +def _import_module(module_name, *, strict=False): + """Import a module from its fully-qualified name. + + If *strict* is false, import failures are suppressed and None is returned. + """ + if module_name is None: + # To prevent a TypeError in importlib.import_module + if strict: + raise ImportError("no module to import") + return None try: return importlib.import_module(module_name) - except ImportError: + except ImportError as exc: + if strict: + raise exc return None -class HID(enum.StrEnum): +def _import_member(module_name, member_name, *, strict=False): + """Import a member from a module. + + If *strict* is false, import failures are suppressed and None is returned. + """ + if member_name is None: + if strict: + raise ImportError(f"no member to import from {module_name}") + return None + module = _import_module(module_name, strict=strict) + if strict: + return getattr(module, member_name) + return getattr(module, member_name, None) + + +class Implementation(enum.StrEnum): + # Indicate that the hash function is implemented by a built-in module. + builtin = enum.auto() + # Indicate that the hash function is implemented by OpenSSL. + openssl = enum.auto() + # Indicate that the hash function is provided through the public API. + hashlib = enum.auto() + + +class _HashId(enum.StrEnum): """Enumeration containing the canonical digest names. Those names should only be used by hashlib.new() or hmac.new(). @@ -57,62 +110,162 @@ class HID(enum.StrEnum): return self.startswith("blake2") -CANONICAL_DIGEST_NAMES = frozenset(map(str, HID.__members__)) +CANONICAL_DIGEST_NAMES = frozenset(map(str, _HashId.__members__)) NON_HMAC_DIGEST_NAMES = frozenset(( - HID.shake_128, HID.shake_256, - HID.blake2s, HID.blake2b, + _HashId.shake_128, _HashId.shake_256, + _HashId.blake2s, _HashId.blake2b, )) -class HashInfo: - """Dataclass storing explicit hash constructor names. +class _HashInfoItem: + """Interface for interacting with a named object. - - *builtin* is the fully-qualified name for the explicit HACL* - hash constructor function, e.g., "_md5.md5". + The object is entirely described by its fully-qualified *fullname*. - - *openssl* is the name of the "_hashlib" module method for the explicit - OpenSSL hash constructor function, e.g., "openssl_md5". - - - *hashlib* is the name of the "hashlib" module method for the explicit - hash constructor function, e.g., "md5". + *fullname* must be None or a string ".". """ - def __init__(self, builtin, openssl=None, hashlib=None): - assert isinstance(builtin, str), builtin - assert len(builtin.split(".")) == 2, builtin + def __init__(self, fullname=None, *, strict=False): + module_name, member_name = _parse_fullname(fullname, strict=strict) + self.fullname = fullname + self.module_name = module_name + self.member_name = member_name - self.builtin = builtin - self.builtin_module_name, self.builtin_method_name = ( - self.builtin.split(".", maxsplit=1) + def import_module(self, *, strict=False): + """Import the described module. + + If *strict* is true, an ImportError may be raised if importing fails, + otherwise, None is returned on error. + """ + return _import_module(self.module_name, strict=strict) + + def import_member(self, *, strict=False): + """Import the described member. + + If *strict* is true, an AttributeError or an ImportError may be + raised if importing fails; otherwise, None is returned on error. + """ + return _import_member( + self.module_name, self.member_name, strict=strict ) - assert openssl is None or openssl.startswith("openssl_") - self.openssl = self.openssl_method_name = openssl - self.openssl_module_name = "_hashlib" if openssl else None - assert hashlib is None or isinstance(hashlib, str) - self.hashlib = self.hashlib_method_name = hashlib - self.hashlib_module_name = "hashlib" if hashlib else None +class _HashInfoBase: + """Base dataclass containing "backend" information. + + Subclasses may define an attribute named after one of the known + implementations ("builtin", "openssl" or "hashlib") which stores + an _HashInfoItem object. + + Those attributes can be retrieved through __getitem__(), e.g., + ``info["builtin"]`` returns the _HashInfoItem corresponding to + the builtin implementation. + """ + + def __init__(self, canonical_name): + assert isinstance(canonical_name, _HashId), canonical_name + self.canonical_name = canonical_name + + def __getitem__(self, implementation): + try: + attrname = Implementation(implementation) + except ValueError: + raise self.invalid_implementation_error(implementation) from None + + try: + provider = getattr(self, attrname) + except AttributeError: + raise self.invalid_implementation_error(implementation) from None + + if not isinstance(provider, _HashInfoItem): + raise KeyError(implementation) + return provider + + def invalid_implementation_error(self, implementation): + msg = f"no implementation {implementation} for {self.canonical_name}" + return AssertionError(msg) + + +class _HashTypeInfo(_HashInfoBase): + """Dataclass containing information for hash functions types. + + - *canonical_name* must be a _HashId. + + - *builtin* is the fully-qualified name for the builtin HACL* type, + e.g., "_md5.MD5Type". + + - *openssl* is the fully-qualified name for the OpenSSL wrapper type, + e.g., "_hashlib.HASH". + """ + + def __init__(self, canonical_name, builtin, openssl): + super().__init__(canonical_name) + self.builtin = _HashInfoItem(builtin, strict=True) + self.openssl = _HashInfoItem(openssl, strict=True) + + def fullname(self, implementation): + """Get the fully qualified name of a given implementation. + + This returns a string of the form "MODULE_NAME.OBJECT_NAME" or None + if the hash function does not have a corresponding implementation. + + *implementation* must be "builtin" or "openssl". + """ + return self[implementation].fullname def module_name(self, implementation): - match implementation: - case "builtin": - return self.builtin_module_name - case "openssl": - return self.openssl_module_name - case "hashlib": - return self.hashlib_module_name - raise AssertionError(f"invalid implementation {implementation}") + """Get the name of the module containing the hash object type.""" + return self[implementation].module_name - def method_name(self, implementation): - match implementation: - case "builtin": - return self.builtin_method_name - case "openssl": - return self.openssl_method_name - case "hashlib": - return self.hashlib_method_name - raise AssertionError(f"invalid implementation {implementation}") + def object_type_name(self, implementation): + """Get the name of the hash object class name.""" + return self[implementation].member_name + + def import_module(self, implementation, *, allow_skip=False): + """Import the module containing the hash object type. + + On error, return None if *allow_skip* is false, or raise SkipNoHash. + """ + target = self[implementation] + module = target.import_module() + if allow_skip and module is None: + reason = f"cannot import module {target.module_name}" + raise SkipNoHash(self.canonical_name, implementation, reason) + return module + + def import_object_type(self, implementation, *, allow_skip=False): + """Get the runtime hash object type. + + On error, return None if *allow_skip* is false, or raise SkipNoHash. + """ + target = self[implementation] + member = target.import_member() + if allow_skip and member is None: + reason = f"cannot import class {target.fullname}" + raise SkipNoHash(self.canonical_name, implementation, reason) + return member + + +class _HashFuncInfo(_HashInfoBase): + """Dataclass containing information for hash functions constructors. + + - *canonical_name* must be a _HashId. + + - *builtin* is the fully-qualified name of the HACL* + hash constructor function, e.g., "_md5.md5". + + - *openssl* is the fully-qualified name of the "_hashlib" method + for the OpenSSL named constructor, e.g., "_hashlib.openssl_md5". + + - *hashlib* is the fully-qualified name of the "hashlib" method + for the explicit named hash constructor, e.g., "hashlib.md5". + """ + + def __init__(self, canonical_name, builtin, openssl=None, hashlib=None): + super().__init__(canonical_name) + self.builtin = _HashInfoItem(builtin, strict=True) + self.openssl = _HashInfoItem(openssl, strict=False) + self.hashlib = _HashInfoItem(hashlib, strict=False) def fullname(self, implementation): """Get the fully qualified name of a given implementation. @@ -122,63 +275,239 @@ class HashInfo: *implementation* must be "builtin", "openssl" or "hashlib". """ - module_name = self.module_name(implementation) - method_name = self.method_name(implementation) - if module_name is None or method_name is None: - return None - return f"{module_name}.{method_name}" + return self[implementation].fullname + + def module_name(self, implementation): + """Get the name of the constructor function module. + + The *implementation* must be "builtin", "openssl" or "hashlib". + """ + return self[implementation].module_name + + def method_name(self, implementation): + """Get the name of the constructor function module method. + + Use fullname() to get the constructor function fully-qualified name. + + The *implementation* must be "builtin", "openssl" or "hashlib". + """ + return self[implementation].member_name -# Mapping from a "canonical" name to a pair (HACL*, _hashlib.*, hashlib.*) -# constructors. If the constructor name is None, then this means that the -# algorithm can only be used by the "agile" new() interfaces. -_EXPLICIT_CONSTRUCTORS = MappingProxyType({ # fmt: skip - HID.md5: HashInfo("_md5.md5", "openssl_md5", "md5"), - HID.sha1: HashInfo("_sha1.sha1", "openssl_sha1", "sha1"), - HID.sha224: HashInfo("_sha2.sha224", "openssl_sha224", "sha224"), - HID.sha256: HashInfo("_sha2.sha256", "openssl_sha256", "sha256"), - HID.sha384: HashInfo("_sha2.sha384", "openssl_sha384", "sha384"), - HID.sha512: HashInfo("_sha2.sha512", "openssl_sha512", "sha512"), - HID.sha3_224: HashInfo( - "_sha3.sha3_224", "openssl_sha3_224", "sha3_224" +class _HashInfo: + """Dataclass containing information for supported hash functions. + + Attributes + ---------- + canonical_name : _HashId + The hash function canonical name. + type : _HashTypeInfo + The hash object types information. + func : _HashTypeInfo + The hash object constructors information. + """ + + def __init__( + self, + canonical_name, + builtin_object_type_fullname, + openssl_object_type_fullname, + builtin_method_fullname, + openssl_method_fullname=None, + hashlib_method_fullname=None, + ): + """ + - *canonical_name* must be a _HashId. + + - *builtin_object_type_fullname* is the fully-qualified name + for the builtin HACL* type, e.g., "_md5.MD5Type". + + - *openssl_object_type_fullname* is the fully-qualified name + for the OpenSSL wrapper type, e.g., "_hashlib.HASH". + + - *builtin_method_fullname* is the fully-qualified name + of the HACL* hash constructor function, e.g., "_md5.md5". + + - *openssl_method_fullname* is the fully-qualified name + of the "_hashlib" module method for the explicit OpenSSL + hash constructor function, e.g., "_hashlib.openssl_md5". + + - *hashlib_method_fullname* is the fully-qualified name + of the "hashlib" module method for the explicit hash + constructor function, e.g., "hashlib.md5". + """ + assert isinstance(canonical_name, _HashId), canonical_name + self.canonical_name = canonical_name + self.type = _HashTypeInfo( + canonical_name, + builtin_object_type_fullname, + openssl_object_type_fullname, + ) + self.func = _HashFuncInfo( + canonical_name, + builtin_method_fullname, + openssl_method_fullname, + hashlib_method_fullname, + ) + + +_HASHINFO_DATABASE = MappingProxyType({ + _HashId.md5: _HashInfo( + _HashId.md5, + "_md5.MD5Type", + "_hashlib.HASH", + "_md5.md5", + "_hashlib.openssl_md5", + "hashlib.md5", ), - HID.sha3_256: HashInfo( - "_sha3.sha3_256", "openssl_sha3_256", "sha3_256" + _HashId.sha1: _HashInfo( + _HashId.sha1, + "_sha1.SHA1Type", + "_hashlib.HASH", + "_sha1.sha1", + "_hashlib.openssl_sha1", + "hashlib.sha1", ), - HID.sha3_384: HashInfo( - "_sha3.sha3_384", "openssl_sha3_384", "sha3_384" + _HashId.sha224: _HashInfo( + _HashId.sha224, + "_sha2.SHA224Type", + "_hashlib.HASH", + "_sha2.sha224", + "_hashlib.openssl_sha224", + "hashlib.sha224", ), - HID.sha3_512: HashInfo( - "_sha3.sha3_512", "openssl_sha3_512", "sha3_512" + _HashId.sha256: _HashInfo( + _HashId.sha256, + "_sha2.SHA256Type", + "_hashlib.HASH", + "_sha2.sha256", + "_hashlib.openssl_sha256", + "hashlib.sha256", ), - HID.shake_128: HashInfo( - "_sha3.shake_128", "openssl_shake_128", "shake_128" + _HashId.sha384: _HashInfo( + _HashId.sha384, + "_sha2.SHA384Type", + "_hashlib.HASH", + "_sha2.sha384", + "_hashlib.openssl_sha384", + "hashlib.sha384", ), - HID.shake_256: HashInfo( - "_sha3.shake_256", "openssl_shake_256", "shake_256" + _HashId.sha512: _HashInfo( + _HashId.sha512, + "_sha2.SHA512Type", + "_hashlib.HASH", + "_sha2.sha512", + "_hashlib.openssl_sha512", + "hashlib.sha512", + ), + _HashId.sha3_224: _HashInfo( + _HashId.sha3_224, + "_sha3.sha3_224", + "_hashlib.HASH", + "_sha3.sha3_224", + "_hashlib.openssl_sha3_224", + "hashlib.sha3_224", + ), + _HashId.sha3_256: _HashInfo( + _HashId.sha3_256, + "_sha3.sha3_256", + "_hashlib.HASH", + "_sha3.sha3_256", + "_hashlib.openssl_sha3_256", + "hashlib.sha3_256", + ), + _HashId.sha3_384: _HashInfo( + _HashId.sha3_384, + "_sha3.sha3_384", + "_hashlib.HASH", + "_sha3.sha3_384", + "_hashlib.openssl_sha3_384", + "hashlib.sha3_384", + ), + _HashId.sha3_512: _HashInfo( + _HashId.sha3_512, + "_sha3.sha3_512", + "_hashlib.HASH", + "_sha3.sha3_512", + "_hashlib.openssl_sha3_512", + "hashlib.sha3_512", + ), + _HashId.shake_128: _HashInfo( + _HashId.shake_128, + "_sha3.shake_128", + "_hashlib.HASHXOF", + "_sha3.shake_128", + "_hashlib.openssl_shake_128", + "hashlib.shake_128", + ), + _HashId.shake_256: _HashInfo( + _HashId.shake_256, + "_sha3.shake_256", + "_hashlib.HASHXOF", + "_sha3.shake_256", + "_hashlib.openssl_shake_256", + "hashlib.shake_256", + ), + _HashId.blake2s: _HashInfo( + _HashId.blake2s, + "_blake2.blake2s", + "_hashlib.HASH", + "_blake2.blake2s", + None, + "hashlib.blake2s", + ), + _HashId.blake2b: _HashInfo( + _HashId.blake2b, + "_blake2.blake2b", + "_hashlib.HASH", + "_blake2.blake2b", + None, + "hashlib.blake2b", ), - HID.blake2s: HashInfo("_blake2.blake2s", None, "blake2s"), - HID.blake2b: HashInfo("_blake2.blake2b", None, "blake2b"), }) -assert _EXPLICIT_CONSTRUCTORS.keys() == CANONICAL_DIGEST_NAMES -get_hash_info = _EXPLICIT_CONSTRUCTORS.__getitem__ +assert _HASHINFO_DATABASE.keys() == CANONICAL_DIGEST_NAMES + + +def get_hash_type_info(name): + info = _HASHINFO_DATABASE[name] + assert isinstance(info, _HashInfo), info + return info.type + + +def get_hash_func_info(name): + info = _HASHINFO_DATABASE[name] + assert isinstance(info, _HashInfo), info + return info.func + + +def _iter_hash_func_info(excluded): + for name, info in _HASHINFO_DATABASE.items(): + if name not in excluded: + yield info.func + # Mapping from canonical hash names to their explicit HACL* HMAC constructor. # There is currently no OpenSSL one-shot named function and there will likely # be none in the future. -_EXPLICIT_HMAC_CONSTRUCTORS = { - HID(name): f"_hmac.compute_{name}" - for name in CANONICAL_DIGEST_NAMES +_HMACINFO_DATABASE = { + _HashId(canonical_name): _HashInfoItem(f"_hmac.compute_{canonical_name}") + for canonical_name in CANONICAL_DIGEST_NAMES } # Neither HACL* nor OpenSSL supports HMAC over XOFs. -_EXPLICIT_HMAC_CONSTRUCTORS[HID.shake_128] = None -_EXPLICIT_HMAC_CONSTRUCTORS[HID.shake_256] = None +_HMACINFO_DATABASE[_HashId.shake_128] = _HashInfoItem() +_HMACINFO_DATABASE[_HashId.shake_256] = _HashInfoItem() # Strictly speaking, HMAC-BLAKE is meaningless as BLAKE2 is already a # keyed hash function. However, as it's exposed by HACL*, we test it. -_EXPLICIT_HMAC_CONSTRUCTORS[HID.blake2s] = '_hmac.compute_blake2s_32' -_EXPLICIT_HMAC_CONSTRUCTORS[HID.blake2b] = '_hmac.compute_blake2b_32' -_EXPLICIT_HMAC_CONSTRUCTORS = MappingProxyType(_EXPLICIT_HMAC_CONSTRUCTORS) -assert _EXPLICIT_HMAC_CONSTRUCTORS.keys() == CANONICAL_DIGEST_NAMES +_HMACINFO_DATABASE[_HashId.blake2s] = _HashInfoItem('_hmac.compute_blake2s_32') +_HMACINFO_DATABASE[_HashId.blake2b] = _HashInfoItem('_hmac.compute_blake2b_32') +_HMACINFO_DATABASE = MappingProxyType(_HMACINFO_DATABASE) +assert _HMACINFO_DATABASE.keys() == CANONICAL_DIGEST_NAMES + + +def get_hmac_item_info(name): + info = _HMACINFO_DATABASE[name] + assert isinstance(info, _HashInfoItem), info + return info def _decorate_func_or_class(decorator_func, func_or_class): @@ -230,26 +559,42 @@ def _ensure_wrapper_signature(wrapper, wrapped): ) -def requires_hashlib(): - _hashlib = try_import_module("_hashlib") +def _make_conditional_decorator(test, /, *test_args, **test_kwargs): + def decorator_func(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + test(*test_args, **test_kwargs) + return func(*args, **kwargs) + return wrapper + return functools.partial(_decorate_func_or_class, decorator_func) + + +def requires_openssl_hashlib(): + _hashlib = _import_module("_hashlib") return unittest.skipIf(_hashlib is None, "requires _hashlib") def requires_builtin_hmac(): - _hmac = try_import_module("_hmac") + _hmac = _import_module("_hmac") return unittest.skipIf(_hmac is None, "requires _hmac") class SkipNoHash(unittest.SkipTest): """A SkipTest exception raised when a hash is not available.""" - def __init__(self, digestname, implementation=None, interface=None): + def __init__(self, digestname, implementation=None, reason=None): parts = ["missing", implementation, f"hash algorithm {digestname!r}"] - if interface is not None: - parts.append(f"for {interface}") + if reason is not None: + parts.insert(0, f"{reason}: ") super().__init__(" ".join(filter(None, parts))) +class SkipNoHashInCall(SkipNoHash): + + def __init__(self, func, digestname, implementation=None): + super().__init__(digestname, implementation, f"cannot use {func}") + + def _hashlib_new(digestname, openssl, /, **kwargs): """Check availability of [hashlib|_hashlib].new(digestname, **kwargs). @@ -264,13 +609,12 @@ def _hashlib_new(digestname, openssl, /, **kwargs): # exceptions as it should be unconditionally available. hashlib = importlib.import_module("hashlib") # re-import '_hashlib' in case it was mocked - _hashlib = try_import_module("_hashlib") + _hashlib = _import_module("_hashlib") module = _hashlib if openssl and _hashlib is not None else hashlib try: module.new(digestname, **kwargs) except ValueError as exc: - interface = f"{module.__name__}.new" - raise SkipNoHash(digestname, interface=interface) from exc + raise SkipNoHashInCall(f"{module.__name__}.new", digestname) from exc return functools.partial(module.new, digestname) @@ -315,7 +659,7 @@ def _openssl_new(digestname, /, **kwargs): try: _hashlib.new(digestname, **kwargs) except ValueError as exc: - raise SkipNoHash(digestname, interface="_hashlib.new") from exc + raise SkipNoHashInCall("_hashlib.new", digestname) from exc return functools.partial(_hashlib.new, digestname) @@ -326,14 +670,15 @@ def _openssl_hash(digestname, /, **kwargs): or SkipTest is raised if none exists. """ assert isinstance(digestname, str), digestname - fullname = f"_hashlib.openssl_{digestname}" + method_name = f"openssl_{digestname}" + fullname = f"_hashlib.{method_name}" try: # re-import '_hashlib' in case it was mocked _hashlib = importlib.import_module("_hashlib") except ImportError as exc: raise SkipNoHash(fullname, "openssl") from exc try: - constructor = getattr(_hashlib, f"openssl_{digestname}", None) + constructor = getattr(_hashlib, method_name) except AttributeError as exc: raise SkipNoHash(fullname, "openssl") from exc try: @@ -343,16 +688,6 @@ def _openssl_hash(digestname, /, **kwargs): return constructor -def _make_requires_hashdigest_decorator(test, /, *test_args, **test_kwargs): - def decorator_func(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - test(*test_args, **test_kwargs) - return func(*args, **kwargs) - return wrapper - return functools.partial(_decorate_func_or_class, decorator_func) - - def requires_hashdigest(digestname, openssl=None, *, usedforsecurity=True): """Decorator raising SkipTest if a hashing algorithm is not available. @@ -370,7 +705,7 @@ def requires_hashdigest(digestname, openssl=None, *, usedforsecurity=True): ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS ValueError: unsupported hash type md4 """ - return _make_requires_hashdigest_decorator( + return _make_conditional_decorator( _hashlib_new, digestname, openssl, usedforsecurity=usedforsecurity ) @@ -380,34 +715,35 @@ def requires_openssl_hashdigest(digestname, *, usedforsecurity=True): The hashing algorithm may be missing or blocked by a strict crypto policy. """ - return _make_requires_hashdigest_decorator( + return _make_conditional_decorator( _openssl_new, digestname, usedforsecurity=usedforsecurity ) -def requires_builtin_hashdigest( - module_name, digestname, *, usedforsecurity=True -): - """Decorator raising SkipTest if a HACL* hashing algorithm is missing. - - - The *module_name* is the C extension module name based on HACL*. - - The *digestname* is one of its member, e.g., 'md5'. - """ - return _make_requires_hashdigest_decorator( - _builtin_hash, module_name, digestname, usedforsecurity=usedforsecurity +def _make_requires_builtin_hashdigest_decorator(item, *, usedforsecurity=True): + assert isinstance(item, _HashInfoItem), item + return _make_conditional_decorator( + _builtin_hash, + item.module_name, + item.member_name, + usedforsecurity=usedforsecurity, ) -def requires_builtin_hashes(*ignored, usedforsecurity=True): +def requires_builtin_hashdigest(canonical_name, *, usedforsecurity=True): + """Decorator raising SkipTest if a HACL* hashing algorithm is missing.""" + info = get_hash_func_info(canonical_name) + return _make_requires_builtin_hashdigest_decorator( + info.builtin, usedforsecurity=usedforsecurity + ) + + +def requires_builtin_hashes(*, exclude=(), usedforsecurity=True): """Decorator raising SkipTest if one HACL* hashing algorithm is missing.""" return _chain_decorators(( - requires_builtin_hashdigest( - api.builtin_module_name, - api.builtin_method_name, - usedforsecurity=usedforsecurity, - ) - for name, api in _EXPLICIT_CONSTRUCTORS.items() - if name not in ignored + _make_requires_builtin_hashdigest_decorator( + info.builtin, usedforsecurity=usedforsecurity + ) for info in _iter_hash_func_info(exclude) )) @@ -424,69 +760,31 @@ class HashFunctionsTrait: implementation of HMAC). """ - DIGEST_NAMES = [ - 'md5', 'sha1', - 'sha224', 'sha256', 'sha384', 'sha512', - 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', - ] - # Default 'usedforsecurity' to use when checking a hash function. # When the trait properties are callables (e.g., _md5.md5) and # not strings, they must be called with the same 'usedforsecurity'. usedforsecurity = True - @classmethod - def setUpClass(cls): - super().setUpClass() - assert CANONICAL_DIGEST_NAMES.issuperset(cls.DIGEST_NAMES) - def is_valid_digest_name(self, digestname): - self.assertIn(digestname, self.DIGEST_NAMES) + self.assertIn(digestname, _HashId) def _find_constructor(self, digestname): # By default, a missing algorithm skips the test that uses it. self.is_valid_digest_name(digestname) self.skipTest(f"missing hash function: {digestname}") - @property - def md5(self): - return self._find_constructor("md5") + md5 = property(lambda self: self._find_constructor("md5")) + sha1 = property(lambda self: self._find_constructor("sha1")) - @property - def sha1(self): - return self._find_constructor("sha1") + sha224 = property(lambda self: self._find_constructor("sha224")) + sha256 = property(lambda self: self._find_constructor("sha256")) + sha384 = property(lambda self: self._find_constructor("sha384")) + sha512 = property(lambda self: self._find_constructor("sha512")) - @property - def sha224(self): - return self._find_constructor("sha224") - - @property - def sha256(self): - return self._find_constructor("sha256") - - @property - def sha384(self): - return self._find_constructor("sha384") - - @property - def sha512(self): - return self._find_constructor("sha512") - - @property - def sha3_224(self): - return self._find_constructor("sha3_224") - - @property - def sha3_256(self): - return self._find_constructor("sha3_256") - - @property - def sha3_384(self): - return self._find_constructor("sha3_384") - - @property - def sha3_512(self): - return self._find_constructor("sha3_512") + sha3_224 = property(lambda self: self._find_constructor("sha3_224")) + sha3_256 = property(lambda self: self._find_constructor("sha3_256")) + sha3_384 = property(lambda self: self._find_constructor("sha3_384")) + sha3_512 = property(lambda self: self._find_constructor("sha3_512")) class NamedHashFunctionsTrait(HashFunctionsTrait): @@ -497,7 +795,7 @@ class NamedHashFunctionsTrait(HashFunctionsTrait): def _find_constructor(self, digestname): self.is_valid_digest_name(digestname) - return digestname + return str(digestname) # ensure that we are an exact string class OpenSSLHashFunctionsTrait(HashFunctionsTrait): @@ -523,10 +821,10 @@ class BuiltinHashFunctionsTrait(HashFunctionsTrait): def _find_constructor(self, digestname): self.is_valid_digest_name(digestname) - info = _EXPLICIT_CONSTRUCTORS[digestname] + info = get_hash_func_info(digestname) return _builtin_hash( - info.builtin_module_name, - info.builtin_method_name, + info.builtin.module_name, + info.builtin.member_name, usedforsecurity=self.usedforsecurity, ) @@ -542,7 +840,7 @@ def find_gil_minsize(modules_names, default=2048): """ sizes = [] for module_name in modules_names: - module = try_import_module(module_name) + module = _import_module(module_name) if module is not None: sizes.append(getattr(module, '_GIL_MINSIZE', default)) return max(sizes, default=default) @@ -553,7 +851,7 @@ def _block_openssl_hash_new(blocked_name): assert isinstance(blocked_name, str), blocked_name # re-import '_hashlib' in case it was mocked - if (_hashlib := try_import_module("_hashlib")) is None: + if (_hashlib := _import_module("_hashlib")) is None: return contextlib.nullcontext() @functools.wraps(wrapped := _hashlib.new) @@ -572,7 +870,7 @@ def _block_openssl_hmac_new(blocked_name): assert isinstance(blocked_name, str), blocked_name # re-import '_hashlib' in case it was mocked - if (_hashlib := try_import_module("_hashlib")) is None: + if (_hashlib := _import_module("_hashlib")) is None: return contextlib.nullcontext() @functools.wraps(wrapped := _hashlib.hmac_new) @@ -590,7 +888,7 @@ def _block_openssl_hmac_digest(blocked_name): assert isinstance(blocked_name, str), blocked_name # re-import '_hashlib' in case it was mocked - if (_hashlib := try_import_module("_hashlib")) is None: + if (_hashlib := _import_module("_hashlib")) is None: return contextlib.nullcontext() @functools.wraps(wrapped := _hashlib.hmac_digest) @@ -607,7 +905,7 @@ def _block_builtin_hash_new(name): """Block a buitin-in hash name from the hashlib.new() interface.""" assert isinstance(name, str), name assert name.lower() == name, f"invalid name: {name}" - assert name in HID, f"invalid hash: {name}" + assert name in _HashId, f"invalid hash: {name}" # Re-import 'hashlib' in case it was mocked hashlib = importlib.import_module('hashlib') @@ -620,7 +918,7 @@ def _block_builtin_hash_new(name): # so we need to block the possibility of importing it, but only # during the call to __get_builtin_constructor(). get_builtin_constructor = getattr(hashlib, '__get_builtin_constructor') - builtin_module_name = _EXPLICIT_CONSTRUCTORS[name].builtin_module_name + builtin_module_name = get_hash_func_info(name).builtin.module_name @functools.wraps(get_builtin_constructor) def get_builtin_constructor_mock(name): @@ -632,7 +930,7 @@ def _block_builtin_hash_new(name): return unittest.mock.patch.multiple( hashlib, __get_builtin_constructor=get_builtin_constructor_mock, - __builtin_constructor_cache=builtin_constructor_cache_mock + __builtin_constructor_cache=builtin_constructor_cache_mock, ) @@ -640,7 +938,7 @@ def _block_builtin_hmac_new(blocked_name): assert isinstance(blocked_name, str), blocked_name # re-import '_hmac' in case it was mocked - if (_hmac := try_import_module("_hmac")) is None: + if (_hmac := _import_module("_hmac")) is None: return contextlib.nullcontext() @functools.wraps(wrapped := _hmac.new) @@ -657,7 +955,7 @@ def _block_builtin_hmac_digest(blocked_name): assert isinstance(blocked_name, str), blocked_name # re-import '_hmac' in case it was mocked - if (_hmac := try_import_module("_hmac")) is None: + if (_hmac := _import_module("_hmac")) is None: return contextlib.nullcontext() @functools.wraps(wrapped := _hmac.compute_digest) @@ -671,30 +969,19 @@ def _block_builtin_hmac_digest(blocked_name): def _make_hash_constructor_blocker(name, dummy, implementation): - info = _EXPLICIT_CONSTRUCTORS[name] - module_name = info.module_name(implementation) - method_name = info.method_name(implementation) - if module_name is None or method_name is None: + info = get_hash_func_info(name)[implementation] + if (wrapped := info.import_member()) is None: # function shouldn't exist for this implementation return contextlib.nullcontext() - - try: - module = importlib.import_module(module_name) - except ImportError: - # module is already disabled - return contextlib.nullcontext() - - wrapped = getattr(module, method_name) wrapper = functools.wraps(wrapped)(dummy) _ensure_wrapper_signature(wrapper, wrapped) - return unittest.mock.patch(info.fullname(implementation), wrapper) + return unittest.mock.patch(info.fullname, wrapper) def _block_hashlib_hash_constructor(name): """Block explicit public constructors.""" def dummy(data=b'', *, usedforsecurity=True, string=None): raise ValueError(f"blocked explicit public hash name: {name}") - return _make_hash_constructor_blocker(name, dummy, 'hashlib') @@ -714,23 +1001,18 @@ def _block_builtin_hash_constructor(name): def _block_builtin_hmac_constructor(name): """Block explicit HACL* HMAC constructors.""" - fullname = _EXPLICIT_HMAC_CONSTRUCTORS[name] - if fullname is None: + info = get_hmac_item_info(name) + assert info.module_name is None or info.module_name == "_hmac", info + if (wrapped := info.import_member()) is None: # function shouldn't exist for this implementation return contextlib.nullcontext() - assert fullname.count('.') == 1, fullname - module_name, method = fullname.split('.', maxsplit=1) - assert module_name == '_hmac', module_name - try: - module = importlib.import_module(module_name) - except ImportError: - # module is already disabled - return contextlib.nullcontext() - @functools.wraps(wrapped := getattr(module, method)) + + @functools.wraps(wrapped) def wrapper(key, obj): raise ValueError(f"blocked hash name: {name}") + _ensure_wrapper_signature(wrapper, wrapped) - return unittest.mock.patch(fullname, wrapper) + return unittest.mock.patch(info.fullname, wrapper) @contextlib.contextmanager @@ -760,14 +1042,14 @@ def block_algorithm(name, *, allow_openssl=False, allow_builtin=False): # the OpenSSL implementation, except with usedforsecurity=False. # However, blocking such functions also means blocking them # so we again need to block them if we want to. - (_hashlib := try_import_module("_hashlib")) + (_hashlib := _import_module("_hashlib")) and _hashlib.get_fips_mode() and not allow_openssl ) or ( # Without OpenSSL, hashlib.() functions are aliases # to built-in functions, so both of them must be blocked # as the module may have been imported before the HACL ones. - not (_hashlib := try_import_module("_hashlib")) + not (_hashlib := _import_module("_hashlib")) and not allow_builtin ): stack.enter_context(_block_hashlib_hash_constructor(name)) @@ -794,3 +1076,21 @@ def block_algorithm(name, *, allow_openssl=False, allow_builtin=False): # _hmac.compute_digest(..., name) stack.enter_context(_block_builtin_hmac_digest(name)) yield + + +@contextlib.contextmanager +def block_openssl_algorithms(*, exclude=()): + """Block OpenSSL implementations, except those given in *exclude*.""" + with contextlib.ExitStack() as stack: + for name in CANONICAL_DIGEST_NAMES.difference(exclude): + stack.enter_context(block_algorithm(name, allow_builtin=True)) + yield + + +@contextlib.contextmanager +def block_builtin_algorithms(*, exclude=()): + """Block HACL* implementations, except those given in *exclude*.""" + with contextlib.ExitStack() as stack: + for name in CANONICAL_DIGEST_NAMES.difference(exclude): + stack.enter_context(block_algorithm(name, allow_openssl=True)) + yield diff --git a/Lib/test/support/pty_helper.py b/Lib/test/support/pty_helper.py index 6587fd40333..dbe7fa42909 100644 --- a/Lib/test/support/pty_helper.py +++ b/Lib/test/support/pty_helper.py @@ -15,6 +15,14 @@ def run_pty(script, input=b"dummy input\r", env=None): output = bytearray() [master, slave] = pty.openpty() args = (sys.executable, '-c', script) + + # Isolate readline from personal init files by setting INPUTRC + # to an empty file. See also GH-142353. + if env is None: + env = {**os.environ.copy(), "INPUTRC": os.devnull} + else: + env.setdefault("INPUTRC", os.devnull) + proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave, env=env) os.close(slave) with ExitStack() as cleanup: diff --git a/Lib/test/support/socket_helper.py b/Lib/test/support/socket_helper.py index 87941ee1791..a41e487f3e4 100644 --- a/Lib/test/support/socket_helper.py +++ b/Lib/test/support/socket_helper.py @@ -259,6 +259,10 @@ def transient_internet(resource_name, *, timeout=_NOT_SET, errnos=()): # raise OSError('socket error', msg) from msg elif len(a) >= 2 and isinstance(a[1], OSError): err = a[1] + # The error can also be wrapped as __cause__: + # raise URLError(f"ftp error: {exp}") from exp + elif isinstance(err, urllib.error.URLError) and err.__cause__: + err = err.__cause__ else: break filter_error(err) diff --git a/Lib/test/test__colorize.py b/Lib/test/test__colorize.py index b2f0bb1386f..67e0595943d 100644 --- a/Lib/test/test__colorize.py +++ b/Lib/test/test__colorize.py @@ -1,4 +1,5 @@ import contextlib +import dataclasses import io import sys import unittest @@ -21,6 +22,42 @@ def supports_virtual_terminal(): return contextlib.nullcontext() +class TestTheme(unittest.TestCase): + + def test_attributes(self): + # only theme configurations attributes by default + for field in dataclasses.fields(_colorize.Theme): + with self.subTest(field.name): + self.assertIsSubclass(field.type, _colorize.ThemeSection) + self.assertIsNotNone(field.default_factory) + + def test_copy_with(self): + theme = _colorize.Theme() + + copy = theme.copy_with() + self.assertEqual(theme, copy) + + unittest_no_colors = _colorize.Unittest.no_colors() + copy = theme.copy_with(unittest=unittest_no_colors) + self.assertEqual(copy.argparse, theme.argparse) + self.assertEqual(copy.difflib, theme.difflib) + self.assertEqual(copy.syntax, theme.syntax) + self.assertEqual(copy.traceback, theme.traceback) + self.assertEqual(copy.unittest, unittest_no_colors) + + def test_no_colors(self): + # idempotence test + theme_no_colors = _colorize.Theme().no_colors() + theme_no_colors_no_colors = theme_no_colors.no_colors() + self.assertEqual(theme_no_colors, theme_no_colors_no_colors) + + # attributes check + for section in dataclasses.fields(_colorize.Theme): + with self.subTest(section.name): + section_theme = getattr(theme_no_colors, section.name) + self.assertEqual(section_theme, section.type.no_colors()) + + class TestColorizeFunction(unittest.TestCase): def test_colorized_detection_checks_for_environment_variables(self): def check(env, fallback, expected): @@ -129,6 +166,17 @@ class TestColorizeFunction(unittest.TestCase): file.isatty.return_value = False self.assertEqual(_colorize.can_colorize(file=file), False) + # The documentation for file.fileno says: + # > An OSError is raised if the IO object does not use a file descriptor. + # gh-141570: Check OSError is caught and handled + with unittest.mock.patch("os.isatty", side_effect=ZeroDivisionError): + file = unittest.mock.MagicMock() + file.fileno.side_effect = OSError + file.isatty.return_value = True + self.assertEqual(_colorize.can_colorize(file=file), True) + file.isatty.return_value = False + self.assertEqual(_colorize.can_colorize(file=file), False) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test__interpchannels.py b/Lib/test/test__interpchannels.py index 858d31a73cf..d7cf77368ef 100644 --- a/Lib/test/test__interpchannels.py +++ b/Lib/test/test__interpchannels.py @@ -6,7 +6,7 @@ import threading import time import unittest -from test.support import import_helper, skip_if_sanitizer +from test.support import import_helper _channels = import_helper.import_module('_interpchannels') from concurrent.interpreters import _crossinterp @@ -365,7 +365,6 @@ class ChannelIDTests(TestBase): #self.assertIsNot(got, obj) -@skip_if_sanitizer('gh-129824: race on _waiting_release', thread=True) class ChannelTests(TestBase): def test_create_cid(self): diff --git a/Lib/test/test_android.py b/Lib/test/test_android.py index de83ce081c2..c6c4a15a7ee 100644 --- a/Lib/test/test_android.py +++ b/Lib/test/test_android.py @@ -91,34 +91,38 @@ class TestAndroidOutput(unittest.TestCase): self.logcat_thread = None @contextmanager - def unbuffered(self, stream): - stream.reconfigure(write_through=True) + def reconfigure(self, stream, **settings): + original_settings = {key: getattr(stream, key, None) for key in settings.keys()} + stream.reconfigure(**settings) try: yield finally: - stream.reconfigure(write_through=False) + stream.reconfigure(**original_settings) - # In --verbose3 mode, sys.stdout and sys.stderr are captured, so we can't - # test them directly. Detect this mode and use some temporary streams with - # the same properties. def stream_context(self, stream_name, level): - # https://developer.android.com/ndk/reference/group/logging - prio = {"I": 4, "W": 5}[level] - stack = ExitStack() stack.enter_context(self.subTest(stream_name)) + + # In --verbose3 mode, sys.stdout and sys.stderr are captured, so we can't + # test them directly. Detect this mode and use some temporary streams with + # the same properties. stream = getattr(sys, stream_name) native_stream = getattr(sys, f"__{stream_name}__") if isinstance(stream, io.StringIO): + # https://developer.android.com/ndk/reference/group/logging + prio = {"I": 4, "W": 5}[level] stack.enter_context( patch( f"sys.{stream_name}", - TextLogStream( - prio, f"python.{stream_name}", native_stream.fileno(), - errors="backslashreplace" + stream := TextLogStream( + prio, f"python.{stream_name}", native_stream, ), ) ) + + # The tests assume the stream is initially buffered. + stack.enter_context(self.reconfigure(stream, write_through=False)) + return stack def test_str(self): @@ -145,7 +149,7 @@ class TestAndroidOutput(unittest.TestCase): self.assert_logs(level, tag, lines) # Single-line messages, - with self.unbuffered(stream): + with self.reconfigure(stream, write_through=True): write("", []) write("a") @@ -192,7 +196,7 @@ class TestAndroidOutput(unittest.TestCase): # However, buffering can be turned off completely if you want a # flush after every write. - with self.unbuffered(stream): + with self.reconfigure(stream, write_through=True): write("\nx", ["", "x"]) write("\na\n", ["", "a"]) write("\n", [""]) diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index 88e0d611647..8208d0e9c94 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -7,8 +7,9 @@ import collections import functools import itertools import pickle -from string.templatelib import Template +from string.templatelib import Template, Interpolation import typing +import sys import unittest from annotationlib import ( Format, @@ -73,6 +74,30 @@ class TestForwardRefFormat(unittest.TestCase): anno = get_annotations(inner, format=Format.FORWARDREF) self.assertEqual(anno["arg"], x) + def test_multiple_closure(self): + def inner(arg: x[y]): + pass + + fwdref = get_annotations(inner, format=Format.FORWARDREF)["arg"] + self.assertIsInstance(fwdref, ForwardRef) + self.assertEqual(fwdref.__forward_arg__, "x[y]") + with self.assertRaises(NameError): + fwdref.evaluate() + + y = str + fwdref = get_annotations(inner, format=Format.FORWARDREF)["arg"] + self.assertIsInstance(fwdref, ForwardRef) + extra_name, extra_val = next(iter(fwdref.__extra_names__.items())) + self.assertEqual(fwdref.__forward_arg__.replace(extra_name, extra_val.__name__), "x[str]") + with self.assertRaises(NameError): + fwdref.evaluate() + + x = list + self.assertEqual(fwdref.evaluate(), x[y]) + + fwdref = get_annotations(inner, format=Format.FORWARDREF)["arg"] + self.assertEqual(fwdref, x[y]) + def test_function(self): def f(x: int, y: doesntexist): pass @@ -94,6 +119,10 @@ class TestForwardRefFormat(unittest.TestCase): alpha: some | obj, beta: +some, gamma: some < obj, + delta: some | {obj: module}, + epsilon: some | {obj, module}, + zeta: some | [obj], + eta: some | (), ): pass @@ -122,6 +151,69 @@ class TestForwardRefFormat(unittest.TestCase): self.assertIsInstance(gamma_anno, ForwardRef) self.assertEqual(gamma_anno, support.EqualToForwardRef("some < obj", owner=f)) + delta_anno = anno["delta"] + self.assertIsInstance(delta_anno, ForwardRef) + self.assertEqual(delta_anno, support.EqualToForwardRef("some | {obj: module}", owner=f)) + + epsilon_anno = anno["epsilon"] + self.assertIsInstance(epsilon_anno, ForwardRef) + self.assertEqual(epsilon_anno, support.EqualToForwardRef("some | {obj, module}", owner=f)) + + zeta_anno = anno["zeta"] + self.assertIsInstance(zeta_anno, ForwardRef) + self.assertEqual(zeta_anno, support.EqualToForwardRef("some | [obj]", owner=f)) + + eta_anno = anno["eta"] + self.assertIsInstance(eta_anno, ForwardRef) + self.assertEqual(eta_anno, support.EqualToForwardRef("some | ()", owner=f)) + + def test_partially_nonexistent(self): + # These annotations start with a non-existent variable and then use + # global types with defined values. This partially evaluates by putting + # those globals into `fwdref.__extra_names__`. + def f( + x: obj | int, + y: container[int:obj, int], + z: dict_val | {str: int}, + alpha: set_val | {str, int}, + beta: obj | bool | int, + gamma: obj | call_func(int, kwd=bool), + ): + pass + + def func(*args, **kwargs): + return Union[*args, *(kwargs.values())] + + anno = get_annotations(f, format=Format.FORWARDREF) + globals_ = { + "obj": str, "container": list, "dict_val": {1: 2}, "set_val": {1, 2}, + "call_func": func + } + + x_anno = anno["x"] + self.assertIsInstance(x_anno, ForwardRef) + self.assertEqual(x_anno.evaluate(globals=globals_), str | int) + + y_anno = anno["y"] + self.assertIsInstance(y_anno, ForwardRef) + self.assertEqual(y_anno.evaluate(globals=globals_), list[int:str, int]) + + z_anno = anno["z"] + self.assertIsInstance(z_anno, ForwardRef) + self.assertEqual(z_anno.evaluate(globals=globals_), {1: 2} | {str: int}) + + alpha_anno = anno["alpha"] + self.assertIsInstance(alpha_anno, ForwardRef) + self.assertEqual(alpha_anno.evaluate(globals=globals_), {1, 2} | {str, int}) + + beta_anno = anno["beta"] + self.assertIsInstance(beta_anno, ForwardRef) + self.assertEqual(beta_anno.evaluate(globals=globals_), str | bool | int) + + gamma_anno = anno["gamma"] + self.assertIsInstance(gamma_anno, ForwardRef) + self.assertEqual(gamma_anno.evaluate(globals=globals_), str | func(int, kwd=bool)) + def test_partially_nonexistent_union(self): # Test unions with '|' syntax equal unions with typing.Union[] with some forwardrefs class UnionForwardrefs: @@ -282,6 +374,7 @@ class TestStringFormat(unittest.TestCase): a: t"a{b}c{d}e{f}g", b: t"{a:{1}}", c: t"{a | b * c}", + gh138558: t"{ 0}", ): pass annos = get_annotations(f, format=Format.STRING) @@ -293,6 +386,7 @@ class TestStringFormat(unittest.TestCase): # interpolations in the format spec are eagerly evaluated so we can't recover the source "b": "t'{a:1}'", "c": "t'{a | b * c}'", + "gh138558": "t'{ 0}'", }) def g( @@ -753,6 +847,8 @@ class TestGetAnnotations(unittest.TestCase): for kwargs in [ {"eval_str": True}, + {"eval_str": True, "globals": isa.__dict__, "locals": {}}, + {"eval_str": True, "globals": {}, "locals": isa.__dict__}, {"format": Format.VALUE, "eval_str": True}, ]: with self.subTest(**kwargs): @@ -785,6 +881,12 @@ class TestGetAnnotations(unittest.TestCase): self.assertEqual(get_annotations(isa2, eval_str=True), {}) self.assertEqual(get_annotations(isa2, eval_str=False), {}) + def test_stringized_annotations_with_star_unpack(self): + def f(*args: "*tuple[int, ...]"): ... + self.assertEqual(get_annotations(f, eval_str=True), + {'args': (*tuple[int, ...],)[0]}) + + def test_stringized_annotations_on_wrapper(self): isa = inspect_stringized_annotations wrapped = times_three(isa.function) @@ -803,6 +905,44 @@ class TestGetAnnotations(unittest.TestCase): {"a": "int", "b": "str", "return": "MyClass"}, ) + def test_stringized_annotations_on_partial_wrapper(self): + isa = inspect_stringized_annotations + + def times_three_str(fn: typing.Callable[[str], isa.MyClass]): + @functools.wraps(fn) + def wrapper(b: "str") -> "MyClass": + return fn(b * 3) + + return wrapper + + wrapped = times_three_str(functools.partial(isa.function, 1)) + self.assertEqual(wrapped("x"), isa.MyClass(1, "xxx")) + self.assertIsNot(wrapped.__globals__, isa.function.__globals__) + self.assertEqual( + get_annotations(wrapped, eval_str=True), + {"b": str, "return": isa.MyClass}, + ) + self.assertEqual( + get_annotations(wrapped, eval_str=False), + {"b": "str", "return": "MyClass"}, + ) + + # If functools is not loaded, names will be evaluated in the current + # module instead of being unwrapped to the original. + functools_mod = sys.modules["functools"] + del sys.modules["functools"] + + self.assertEqual( + get_annotations(wrapped, eval_str=True), + {"b": str, "return": MyClass}, + ) + self.assertEqual( + get_annotations(wrapped, eval_str=False), + {"b": "str", "return": "MyClass"}, + ) + + sys.modules["functools"] = functools_mod + def test_stringized_annotations_on_class(self): isa = inspect_stringized_annotations # test that local namespace lookups work @@ -815,6 +955,16 @@ class TestGetAnnotations(unittest.TestCase): {"x": int}, ) + def test_stringized_annotations_on_custom_object(self): + class HasAnnotations: + @property + def __annotations__(self): + return {"x": "int"} + + ha = HasAnnotations() + self.assertEqual(get_annotations(ha), {"x": "int"}) + self.assertEqual(get_annotations(ha, eval_str=True), {"x": int}) + def test_stringized_annotation_permutations(self): def define_class(name, has_future, has_annos, base_text, extra_names=None): lines = [] @@ -982,6 +1132,23 @@ class TestGetAnnotations(unittest.TestCase): {"x": "int"}, ) + def test_non_dict_annotate(self): + class WeirdAnnotate: + def __annotate__(self, *args, **kwargs): + return "not a dict" + + wa = WeirdAnnotate() + for format in Format: + if format == Format.VALUE_WITH_FAKE_GLOBALS: + continue + with ( + self.subTest(format=format), + self.assertRaisesRegex( + ValueError, r".*__annotate__ returned a non-dict" + ), + ): + get_annotations(wa, format=format) + def test_no_annotations(self): class CustomClass: pass @@ -1186,6 +1353,40 @@ class TestGetAnnotations(unittest.TestCase): }, ) + def test_nonlocal_in_annotation_scope(self): + class Demo: + nonlocal sequence_b + x: sequence_b + y: sequence_b[int] + + fwdrefs = get_annotations(Demo, format=Format.FORWARDREF) + + self.assertIsInstance(fwdrefs["x"], ForwardRef) + self.assertIsInstance(fwdrefs["y"], ForwardRef) + + sequence_b = list + self.assertIs(fwdrefs["x"].evaluate(), list) + self.assertEqual(fwdrefs["y"].evaluate(), list[int]) + + def test_raises_error_from_value(self): + # test that if VALUE is the only supported format, but raises an error + # that error is propagated from get_annotations + class DemoException(Exception): ... + + def annotate(format, /): + if format == Format.VALUE: + raise DemoException() + else: + raise NotImplementedError(format) + + def f(): ... + + f.__annotate__ = annotate + + for fmt in [Format.VALUE, Format.FORWARDREF, Format.STRING]: + with self.assertRaises(DemoException): + get_annotations(f, format=fmt) + class TestCallEvaluateFunction(unittest.TestCase): def test_evaluation(self): @@ -1205,6 +1406,206 @@ class TestCallEvaluateFunction(unittest.TestCase): "undefined", ) + def test_fake_global_evaluation(self): + # This will raise an AttributeError + def evaluate_union(format, exc=NotImplementedError): + if format == Format.VALUE_WITH_FAKE_GLOBALS: + # Return a ForwardRef + return builtins.undefined | list[int] + raise exc + + self.assertEqual( + annotationlib.call_evaluate_function(evaluate_union, Format.FORWARDREF), + support.EqualToForwardRef("builtins.undefined | list[int]"), + ) + + # This will raise an AttributeError + def evaluate_intermediate(format, exc=NotImplementedError): + if format == Format.VALUE_WITH_FAKE_GLOBALS: + intermediate = builtins.undefined + # Return a literal + return intermediate is None + raise exc + + self.assertIs( + annotationlib.call_evaluate_function(evaluate_intermediate, Format.FORWARDREF), + False, + ) + + +class TestCallAnnotateFunction(unittest.TestCase): + # Tests for user defined annotate functions. + + # Format and NotImplementedError are provided as arguments so they exist in + # the fake globals namespace. + # This avoids non-matching conditions passing by being converted to stringifiers. + # See: https://github.com/python/cpython/issues/138764 + + def test_user_annotate_value(self): + def annotate(format, /): + if format == Format.VALUE: + return {"x": str} + else: + raise NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.VALUE, + ) + + self.assertEqual(annotations, {"x": str}) + + def test_user_annotate_forwardref_supported(self): + # If Format.FORWARDREF is supported prefer it over Format.VALUE + def annotate(format, /, __Format=Format, __NotImplementedError=NotImplementedError): + if format == __Format.VALUE: + return {'x': str} + elif format == __Format.VALUE_WITH_FAKE_GLOBALS: + return {'x': int} + elif format == __Format.FORWARDREF: + return {'x': float} + else: + raise __NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.FORWARDREF + ) + + self.assertEqual(annotations, {"x": float}) + + def test_user_annotate_forwardref_fakeglobals(self): + # If Format.FORWARDREF is not supported, use Format.VALUE_WITH_FAKE_GLOBALS + # before falling back to Format.VALUE + def annotate(format, /, __Format=Format, __NotImplementedError=NotImplementedError): + if format == __Format.VALUE: + return {'x': str} + elif format == __Format.VALUE_WITH_FAKE_GLOBALS: + return {'x': int} + else: + raise __NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.FORWARDREF + ) + + self.assertEqual(annotations, {"x": int}) + + def test_user_annotate_forwardref_value_fallback(self): + # If Format.FORWARDREF and Format.VALUE_WITH_FAKE_GLOBALS are not supported + # use Format.VALUE + def annotate(format, /, __Format=Format, __NotImplementedError=NotImplementedError): + if format == __Format.VALUE: + return {"x": str} + else: + raise __NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.FORWARDREF, + ) + + self.assertEqual(annotations, {"x": str}) + + def test_user_annotate_string_supported(self): + # If Format.STRING is supported prefer it over Format.VALUE + def annotate(format, /, __Format=Format, __NotImplementedError=NotImplementedError): + if format == __Format.VALUE: + return {'x': str} + elif format == __Format.VALUE_WITH_FAKE_GLOBALS: + return {'x': int} + elif format == __Format.STRING: + return {'x': "float"} + else: + raise __NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.STRING, + ) + + self.assertEqual(annotations, {"x": "float"}) + + def test_user_annotate_string_fakeglobals(self): + # If Format.STRING is not supported but Format.VALUE_WITH_FAKE_GLOBALS is + # prefer that over Format.VALUE + def annotate(format, /, __Format=Format, __NotImplementedError=NotImplementedError): + if format == __Format.VALUE: + return {'x': str} + elif format == __Format.VALUE_WITH_FAKE_GLOBALS: + return {'x': int} + else: + raise __NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.STRING, + ) + + self.assertEqual(annotations, {"x": "int"}) + + def test_user_annotate_string_value_fallback(self): + # If Format.STRING and Format.VALUE_WITH_FAKE_GLOBALS are not + # supported fall back to Format.VALUE and convert to strings + def annotate(format, /, __Format=Format, __NotImplementedError=NotImplementedError): + if format == __Format.VALUE: + return {"x": str} + else: + raise __NotImplementedError(format) + + annotations = annotationlib.call_annotate_function( + annotate, + Format.STRING, + ) + + self.assertEqual(annotations, {"x": "str"}) + + def test_condition_not_stringified(self): + # Make sure the first condition isn't evaluated as True by being converted + # to a _Stringifier + def annotate(format, /): + if format == Format.FORWARDREF: + return {"x": str} + else: + raise NotImplementedError(format) + + with self.assertRaises(NotImplementedError): + annotationlib.call_annotate_function(annotate, Format.STRING) + + def test_unsupported_formats(self): + def annotate(format, /): + if format == Format.FORWARDREF: + return {"x": str} + else: + raise NotImplementedError(format) + + with self.assertRaises(ValueError): + annotationlib.call_annotate_function(annotate, Format.VALUE_WITH_FAKE_GLOBALS) + + with self.assertRaises(RuntimeError): + annotationlib.call_annotate_function(annotate, Format.VALUE) + + with self.assertRaises(ValueError): + # Some non-Format value + annotationlib.call_annotate_function(annotate, 7) + + def test_error_from_value_raised(self): + # Test that the error from format.VALUE is raised + # if all formats fail + + class DemoException(Exception): ... + + def annotate(format, /): + if format == Format.VALUE: + raise DemoException() + else: + raise NotImplementedError(format) + + for fmt in [Format.VALUE, Format.FORWARDREF, Format.STRING]: + with self.assertRaises(DemoException): + annotationlib.call_annotate_function(annotate, format=fmt) + class MetaclassTests(unittest.TestCase): def test_annotated_meta(self): @@ -1350,6 +1751,24 @@ class TestTypeRepr(unittest.TestCase): self.assertEqual(type_repr("1"), "'1'") self.assertEqual(type_repr(Format.VALUE), repr(Format.VALUE)) self.assertEqual(type_repr(MyClass()), "my repr") + # gh138558 tests + self.assertEqual(type_repr(t'''{ 0 + & 1 + | 2 + }'''), 't"""{ 0\n & 1\n | 2}"""') + self.assertEqual( + type_repr(Template("hi", Interpolation(42, "42"))), "t'hi{42}'" + ) + self.assertEqual( + type_repr(Template("hi", Interpolation(42))), + "Template('hi', Interpolation(42, '', None, ''))", + ) + self.assertEqual( + type_repr(Template("hi", Interpolation(42, " "))), + "Template('hi', Interpolation(42, ' ', None, ''))", + ) + # gh138558: perhaps in the future, we can improve this behavior: + self.assertEqual(type_repr(Template(Interpolation(42, "99"))), "t'{99}'") class TestAnnotationsToString(unittest.TestCase): @@ -1471,6 +1890,14 @@ class TestForwardRefClass(unittest.TestCase): repr(List[ForwardRef("int", module="mod")]), "typing.List[ForwardRef('int', module='mod')]", ) + self.assertEqual( + repr(List[ForwardRef("int", module="mod", is_class=True)]), + "typing.List[ForwardRef('int', module='mod', is_class=True)]", + ) + self.assertEqual( + repr(List[ForwardRef("int", owner="class")]), + "typing.List[ForwardRef('int', owner='class')]", + ) def test_forward_recursion_actually(self): def namespace1(): @@ -1576,6 +2003,19 @@ class TestForwardRefClass(unittest.TestCase): support.EqualToForwardRef('"a" + 1'), ) + def test_evaluate_notimplemented_format(self): + class C: + x: alias + + fwdref = get_annotations(C, format=Format.FORWARDREF)["x"] + + with self.assertRaises(NotImplementedError): + fwdref.evaluate(format=Format.VALUE_WITH_FAKE_GLOBALS) + + with self.assertRaises(NotImplementedError): + # Some other unsupported value + fwdref.evaluate(format=7) + def test_evaluate_with_type_params(self): class Gen[T]: alias = int @@ -1675,6 +2115,32 @@ class TestForwardRefClass(unittest.TestCase): self.assertEqual(exc.exception.name, "doesntexist") + def test_evaluate_undefined_generic(self): + # Test the codepath where have to eval() with undefined variables. + class C: + x: alias[int, undef] + + generic = get_annotations(C, format=Format.FORWARDREF)["x"].evaluate( + format=Format.FORWARDREF, + globals={"alias": dict} + ) + self.assertNotIsInstance(generic, ForwardRef) + self.assertIs(generic.__origin__, dict) + self.assertEqual(len(generic.__args__), 2) + self.assertIs(generic.__args__[0], int) + self.assertIsInstance(generic.__args__[1], ForwardRef) + + generic = get_annotations(C, format=Format.FORWARDREF)["x"].evaluate( + format=Format.FORWARDREF, + globals={"alias": Union}, + locals={"alias": dict} + ) + self.assertNotIsInstance(generic, ForwardRef) + self.assertIs(generic.__origin__, dict) + self.assertEqual(len(generic.__args__), 2) + self.assertIs(generic.__args__[0], int) + self.assertIsInstance(generic.__args__[1], ForwardRef) + def test_fwdref_invalid_syntax(self): fr = ForwardRef("if") with self.assertRaises(SyntaxError): @@ -1683,6 +2149,56 @@ class TestForwardRefClass(unittest.TestCase): with self.assertRaises(SyntaxError): fr.evaluate() + def test_re_evaluate_generics(self): + global global_alias + + # If we've already run this test before, + # ensure the variable is still undefined + if "global_alias" in globals(): + del global_alias + + class C: + x: global_alias[int] + + # Evaluate the ForwardRef once + evaluated = get_annotations(C, format=Format.FORWARDREF)["x"].evaluate( + format=Format.FORWARDREF + ) + + # Now define the global and ensure that the ForwardRef evaluates + global_alias = list + self.assertEqual(evaluated.evaluate(), list[int]) + + def test_fwdref_evaluate_argument_mutation(self): + class C[T]: + nonlocal alias + x: alias[T] + + # Mutable arguments + globals_ = globals() + globals_copy = globals_.copy() + locals_ = locals() + locals_copy = locals_.copy() + + # Evaluate the ForwardRef, ensuring we use __cell__ and type params + get_annotations(C, format=Format.FORWARDREF)["x"].evaluate( + globals=globals_, + locals=locals_, + type_params=C.__type_params__, + format=Format.FORWARDREF, + ) + + # Check if the passed in mutable arguments equal the originals + self.assertEqual(globals_, globals_copy) + self.assertEqual(locals_, locals_copy) + + alias = list + + def test_fwdref_final_class(self): + with self.assertRaises(TypeError): + class C(ForwardRef): + pass + class TestAnnotationLib(unittest.TestCase): def test__all__(self): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index fc73174d98c..758af98d5cb 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -22,6 +22,7 @@ from test.support import ( captured_stderr, force_not_colorized, force_not_colorized_test_class, + swap_attr, ) from test.support import import_helper from test.support import os_helper @@ -580,13 +581,22 @@ class TestOptionalsShortLong(ParserTestCase): class TestOptionalsDest(ParserTestCase): """Tests various means of setting destination""" - argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')] + argument_signatures = [ + Sig('-x', '-foobar', '--foo-bar', '-barfoo', '-X'), + Sig('--baz', dest='zabbaz'), + Sig('-y', '-qux', '-Y'), + Sig('-z'), + ] failures = ['a'] successes = [ - ('--foo-bar f', NS(foo_bar='f', zabbaz=None)), - ('--baz g', NS(foo_bar=None, zabbaz='g')), - ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')), - ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')), + ('--foo-bar f', NS(foo_bar='f', zabbaz=None, qux=None, z=None)), + ('-x f', NS(foo_bar='f', zabbaz=None, qux=None, z=None)), + ('--baz g', NS(foo_bar=None, zabbaz='g', qux=None, z=None)), + ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i', qux=None, z=None)), + ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j', qux=None, z=None)), + ('-qux l', NS(foo_bar=None, zabbaz=None, qux='l', z=None)), + ('-y l', NS(foo_bar=None, zabbaz=None, qux='l', z=None)), + ('-z m', NS(foo_bar=None, zabbaz=None, qux=None, z='m')), ] @@ -795,6 +805,76 @@ class TestBooleanOptionalAction(ParserTestCase): self.assertEqual(str(cm.exception), "invalid option name '--no-foo' for BooleanOptionalAction") +class TestBooleanOptionalActionSingleDash(ParserTestCase): + """Tests BooleanOptionalAction with single dash""" + + argument_signatures = [ + Sig('-foo', '-x', action=argparse.BooleanOptionalAction), + ] + failures = ['--foo', '--no-foo', '-no-foo', '-no-x', '-nox'] + successes = [ + ('', NS(foo=None)), + ('-foo', NS(foo=True)), + ('-nofoo', NS(foo=False)), + ('-x', NS(foo=True)), + ] + + def test_invalid_name(self): + parser = argparse.ArgumentParser() + with self.assertRaises(ValueError) as cm: + parser.add_argument('-nofoo', action=argparse.BooleanOptionalAction) + self.assertEqual(str(cm.exception), + "invalid option name '-nofoo' for BooleanOptionalAction") + +class TestBooleanOptionalActionAlternatePrefixChars(ParserTestCase): + """Tests BooleanOptionalAction with custom prefixes""" + + parser_signature = Sig(prefix_chars='+-', add_help=False) + argument_signatures = [Sig('++foo', action=argparse.BooleanOptionalAction)] + failures = ['--foo', '--no-foo'] + successes = [ + ('', NS(foo=None)), + ('++foo', NS(foo=True)), + ('++no-foo', NS(foo=False)), + ] + + def test_invalid_name(self): + parser = argparse.ArgumentParser(prefix_chars='+/') + with self.assertRaisesRegex(ValueError, + 'BooleanOptionalAction.*is not valid for positional arguments'): + parser.add_argument('--foo', action=argparse.BooleanOptionalAction) + with self.assertRaises(ValueError) as cm: + parser.add_argument('++no-foo', action=argparse.BooleanOptionalAction) + self.assertEqual(str(cm.exception), + "invalid option name '++no-foo' for BooleanOptionalAction") + +class TestBooleanOptionalActionSingleAlternatePrefixChar(ParserTestCase): + """Tests BooleanOptionalAction with single alternate prefix char""" + + parser_signature = Sig(prefix_chars='+/', add_help=False) + argument_signatures = [ + Sig('+foo', '+x', action=argparse.BooleanOptionalAction), + ] + failures = ['++foo', '++no-foo', '++nofoo', + '-no-foo', '-nofoo', '+no-foo', '-nofoo', + '+no-x', '+nox', '-no-x', '-nox'] + successes = [ + ('', NS(foo=None)), + ('+foo', NS(foo=True)), + ('+nofoo', NS(foo=False)), + ('+x', NS(foo=True)), + ] + + def test_invalid_name(self): + parser = argparse.ArgumentParser(prefix_chars='+/') + with self.assertRaisesRegex(ValueError, + 'BooleanOptionalAction.*is not valid for positional arguments'): + parser.add_argument('-foo', action=argparse.BooleanOptionalAction) + with self.assertRaises(ValueError) as cm: + parser.add_argument('+nofoo', action=argparse.BooleanOptionalAction) + self.assertEqual(str(cm.exception), + "invalid option name '+nofoo' for BooleanOptionalAction") + class TestBooleanOptionalActionRequired(ParserTestCase): """Tests BooleanOptionalAction required""" @@ -2282,11 +2362,12 @@ class TestNegativeNumber(ParserTestCase): ('--complex -1e-3j', NS(int=None, float=None, complex=-0.001j)), ] +@force_not_colorized_test_class class TestArgumentAndSubparserSuggestions(TestCase): """Test error handling and suggestion when a user makes a typo""" def test_wrong_argument_error_with_suggestions(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=['bar', 'baz']) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('bazz',)) @@ -2306,7 +2387,7 @@ class TestArgumentAndSubparserSuggestions(TestCase): ) def test_wrong_argument_subparsers_with_suggestions(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() subparsers = parser.add_subparsers(required=True) subparsers.add_parser('foo') subparsers.add_parser('bar') @@ -2330,18 +2411,19 @@ class TestArgumentAndSubparserSuggestions(TestCase): excinfo.exception.stderr, ) - def test_wrong_argument_no_suggestion_implicit(self): - parser = ErrorRaisingArgumentParser() + def test_wrong_argument_with_suggestion_explicit(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser.add_argument('foo', choices=['bar', 'baz']) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('bazz',)) self.assertIn( - "error: argument foo: invalid choice: 'bazz' (choose from bar, baz)", + "error: argument foo: invalid choice: 'bazz', maybe you meant" + " 'baz'? (choose from bar, baz)", excinfo.exception.stderr, ) def test_suggestions_choices_empty(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=[]) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('bazz',)) @@ -2351,7 +2433,7 @@ class TestArgumentAndSubparserSuggestions(TestCase): ) def test_suggestions_choices_int(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=[1, 2]) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('3',)) @@ -2361,7 +2443,7 @@ class TestArgumentAndSubparserSuggestions(TestCase): ) def test_suggestions_choices_mixed_types(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=[1, '2']) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('3',)) @@ -2688,6 +2770,16 @@ class TestAddSubparsers(TestCase): ret = parser.parse_args(()) self.assertIsNone(ret.command) + def test_subparser_help_with_parent_required_optional(self): + parser = ErrorRaisingArgumentParser(prog='PROG') + parser.add_argument('--foo', required=True) + parser.add_argument('--bar') + subparsers = parser.add_subparsers() + parser_sub = subparsers.add_parser('sub') + parser_sub.add_argument('arg') + self.assertEqual(parser_sub.format_usage(), + 'usage: PROG --foo FOO sub [-h] arg\n') + def test_help(self): self.assertEqual(self.parser.format_usage(), 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') @@ -3306,12 +3398,11 @@ class TestMutuallyExclusiveGroupErrors(TestCase): ''' self.assertEqual(cmd_foo.format_help(), textwrap.dedent(expected)) - def test_empty_group(self): + def test_usage_empty_group(self): # See issue 26952 - parser = argparse.ArgumentParser() + parser = ErrorRaisingArgumentParser(prog='PROG') group = parser.add_mutually_exclusive_group() - with self.assertRaises(ValueError): - parser.parse_args(['-h']) + self.assertEqual(parser.format_usage(), 'usage: PROG [-h]\n') def test_nested_mutex_groups(self): parser = argparse.ArgumentParser(prog='PROG') @@ -3579,25 +3670,29 @@ class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase): group.add_argument('-b', action='store_true', help='b help') parser.add_argument('-y', action='store_true', help='y help') group.add_argument('-c', action='store_true', help='c help') + parser.add_argument('-z', action='store_true', help='z help') return parser failures = ['-a -b', '-b -c', '-a -c', '-a -b -c'] successes = [ - ('-a', NS(a=True, b=False, c=False, x=False, y=False)), - ('-b', NS(a=False, b=True, c=False, x=False, y=False)), - ('-c', NS(a=False, b=False, c=True, x=False, y=False)), - ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)), - ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)), - ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)), + ('-a', NS(a=True, b=False, c=False, x=False, y=False, z=False)), + ('-b', NS(a=False, b=True, c=False, x=False, y=False, z=False)), + ('-c', NS(a=False, b=False, c=True, x=False, y=False, z=False)), + ('-a -x', NS(a=True, b=False, c=False, x=True, y=False, z=False)), + ('-y -b', NS(a=False, b=True, c=False, x=False, y=True, z=False)), + ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True, z=False)), ] successes_when_not_required = [ - ('', NS(a=False, b=False, c=False, x=False, y=False)), - ('-x', NS(a=False, b=False, c=False, x=True, y=False)), - ('-y', NS(a=False, b=False, c=False, x=False, y=True)), + ('', NS(a=False, b=False, c=False, x=False, y=False, z=False)), + ('-x', NS(a=False, b=False, c=False, x=True, y=False, z=False)), + ('-y', NS(a=False, b=False, c=False, x=False, y=True, z=False)), ] - usage_when_required = usage_when_not_required = '''\ - usage: PROG [-h] [-x] [-a] [-b] [-y] [-c] + usage_when_not_required = '''\ + usage: PROG [-h] [-x] [-a | -b | -c] [-y] [-z] + ''' + usage_when_required = '''\ + usage: PROG [-h] [-x] (-a | -b | -c) [-y] [-z] ''' help = '''\ @@ -3608,6 +3703,7 @@ class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase): -b b help -y y help -c c help + -z z help ''' @@ -3661,23 +3757,27 @@ class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase): group.add_argument('a', nargs='?', help='a help') group.add_argument('-b', action='store_true', help='b help') group.add_argument('-c', action='store_true', help='c help') + parser.add_argument('-z', action='store_true', help='z help') return parser failures = ['X A -b', '-b -c', '-c X A'] successes = [ - ('X A', NS(a='A', b=False, c=False, x='X', y=False)), - ('X -b', NS(a=None, b=True, c=False, x='X', y=False)), - ('X -c', NS(a=None, b=False, c=True, x='X', y=False)), - ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)), - ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)), + ('X A', NS(a='A', b=False, c=False, x='X', y=False, z=False)), + ('X -b', NS(a=None, b=True, c=False, x='X', y=False, z=False)), + ('X -c', NS(a=None, b=False, c=True, x='X', y=False, z=False)), + ('X A -y', NS(a='A', b=False, c=False, x='X', y=True, z=False)), + ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True, z=False)), ] successes_when_not_required = [ - ('X', NS(a=None, b=False, c=False, x='X', y=False)), - ('X -y', NS(a=None, b=False, c=False, x='X', y=True)), + ('X', NS(a=None, b=False, c=False, x='X', y=False, z=False)), + ('X -y', NS(a=None, b=False, c=False, x='X', y=True, z=False)), ] - usage_when_required = usage_when_not_required = '''\ - usage: PROG [-h] [-y] [-b] [-c] x [a] + usage_when_not_required = '''\ + usage: PROG [-h] [-y] [-z] x [-b | -c | a] + ''' + usage_when_required = '''\ + usage: PROG [-h] [-y] [-z] x (-b | -c | a) ''' help = '''\ @@ -3690,6 +3790,7 @@ class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase): -y y help -b b help -c c help + -z z help ''' @@ -4884,6 +4985,25 @@ class TestHelpUsageNoWhitespaceCrash(TestCase): ''') self.assertEqual(parser.format_usage(), usage) + def test_mutex_groups_with_mixed_optionals_positionals_wrap(self): + # https://github.com/python/cpython/issues/75949 + # Mutually exclusive groups containing both optionals and positionals + # should preserve pipe separators when the usage line wraps. + parser = argparse.ArgumentParser(prog='PROG') + g = parser.add_mutually_exclusive_group() + g.add_argument('-v', '--verbose', action='store_true') + g.add_argument('-q', '--quiet', action='store_true') + g.add_argument('-x', '--extra-long-option-name', nargs='?') + g.add_argument('-y', '--yet-another-long-option', nargs='?') + g.add_argument('positional', nargs='?') + + usage = textwrap.dedent('''\ + usage: PROG [-h] + [-v | -q | -x [EXTRA_LONG_OPTION_NAME] | + -y [YET_ANOTHER_LONG_OPTION] | positional] + ''') + self.assertEqual(parser.format_usage(), usage) + class TestHelpVariableExpansion(HelpTestCase): """Test that variables are expanded properly in help messages""" @@ -5299,6 +5419,7 @@ class TestHelpArgumentDefaults(HelpTestCase): argument_signatures = [ Sig('--foo', help='foo help - oh and by the way, %(default)s'), Sig('--bar', action='store_true', help='bar help'), + Sig('--required', required=True, help='some help'), Sig('--taz', action=argparse.BooleanOptionalAction, help='Whether to taz it', default=True), Sig('--corge', action=argparse.BooleanOptionalAction, @@ -5312,8 +5433,8 @@ class TestHelpArgumentDefaults(HelpTestCase): [Sig('--baz', type=int, default=42, help='baz help')]), ] usage = '''\ - usage: PROG [-h] [--foo FOO] [--bar] [--taz | --no-taz] [--corge | --no-corge] - [--quux QUUX] [--baz BAZ] + usage: PROG [-h] [--foo FOO] [--bar] --required REQUIRED [--taz | --no-taz] + [--corge | --no-corge] [--quux QUUX] [--baz BAZ] spam [badger] ''' help = usage + '''\ @@ -5328,6 +5449,7 @@ class TestHelpArgumentDefaults(HelpTestCase): -h, --help show this help message and exit --foo FOO foo help - oh and by the way, None --bar bar help (default: False) + --required REQUIRED some help --taz, --no-taz Whether to taz it (default: True) --corge, --no-corge Whether to corge it --quux QUUX Set the quux (default: 42) @@ -5574,6 +5696,11 @@ class TestHelpCustomHelpFormatter(TestCase): a-very-long-command command that does something ''')) + def test_direct_formatter_instantiation(self): + formatter = argparse.HelpFormatter(prog="program") + formatter.add_usage(usage=None, actions=[], groups=[]) + help_text = formatter.format_help() + self.assertEqual(help_text, "usage: program\n") # ===================================== # Optional/Positional constructor tests @@ -5608,6 +5735,8 @@ class TestInvalidArgumentConstructors(TestCase): self.assertTypeError('-', errmsg='dest= is required') self.assertTypeError('--', errmsg='dest= is required') self.assertTypeError('---', errmsg='dest= is required') + self.assertTypeError('-', '--', '---', + errmsg="dest= is required for options like '-', '--', '---'") def test_invalid_prefix(self): self.assertValueError('--foo', '+foo', @@ -5830,6 +5959,7 @@ class TestConflictHandling(TestCase): # Help and Version option tests # ============================= +@force_not_colorized_test_class class TestOptionalsHelpVersionActions(TestCase): """Test the help and version actions""" @@ -6144,6 +6274,7 @@ class TestTypeFunctionCallOnlyOnce(TestCase): # Check that deprecated arguments output warning # ============================================== +@force_not_colorized_test_class class TestDeprecatedArguments(TestCase): def test_deprecated_option(self): @@ -7128,7 +7259,8 @@ class TestColorized(TestCase): def setUp(self): super().setUp() # Ensure color even if ran with NO_COLOR=1 - _colorize.can_colorize = lambda *args, **kwargs: True + self.enterContext(swap_attr(_colorize, 'can_colorize', + lambda *args, **kwargs: True)) self.theme = _colorize.get_theme(force_color=True).argparse def test_argparse_color(self): @@ -7176,6 +7308,13 @@ class TestColorized(TestCase): choices=("Aaaaa", "Bbbbb", "Ccccc", "Ddddd"), help="pick one", ) + parser.add_argument( + "--optional8", + default="A", + metavar="X", + choices=("A", "B", "C"), + help="among %(choices)s, default is %(default)s", + ) parser.add_argument("+f") parser.add_argument("++bar") @@ -7201,6 +7340,8 @@ class TestColorized(TestCase): short_b = self.theme.short_option label_b = self.theme.label pos_b = self.theme.action + default = self.theme.default + interp = self.theme.interpolated_value reset = self.theme.reset # Act @@ -7213,8 +7354,8 @@ class TestColorized(TestCase): f"""\ {heading}usage: {reset}{prog}PROG{reset} [{short}-h{reset}] [{short}-v{reset} | {short}-q{reset}] [{short}-o{reset}] [{long}--optional2 {label}OPTIONAL2{reset}] [{long}--optional3 {label}{{X,Y,Z}}{reset}] [{long}--optional4 {label}{{X,Y,Z}}{reset}] [{long}--optional5 {label}{{X,Y,Z}}{reset}] [{long}--optional6 {label}{{X,Y,Z}}{reset}] - [{short}-p {label}{{Aaaaa,Bbbbb,Ccccc,Ddddd}}{reset}] [{short}+f {label}F{reset}] [{long}++bar {label}BAR{reset}] [{long}-+baz {label}BAZ{reset}] - [{short}-c {label}COUNT{reset}] + [{short}-p {label}{{Aaaaa,Bbbbb,Ccccc,Ddddd}}{reset}] [{long}--optional8 {label}X{reset}] [{short}+f {label}F{reset}] [{long}++bar {label}BAR{reset}] + [{long}-+baz {label}BAZ{reset}] [{short}-c {label}COUNT{reset}] {pos}x{reset} {pos}y{reset} {pos}this_indeed_is_a_very_long_action_name{reset} {pos}{{sub1,sub2}} ...{reset} Colorful help @@ -7227,17 +7368,18 @@ class TestColorized(TestCase): {heading}options:{reset} {short_b}-h{reset}, {long_b}--help{reset} show this help message and exit - {short_b}-v{reset}, {long_b}--verbose{reset} more spam (default: False) - {short_b}-q{reset}, {long_b}--quiet{reset} less spam (default: False) + {short_b}-v{reset}, {long_b}--verbose{reset} more spam {default}(default: {reset}{interp}False{reset}{default}){reset} + {short_b}-q{reset}, {long_b}--quiet{reset} less spam {default}(default: {reset}{interp}False{reset}{default}){reset} {short_b}-o{reset}, {long_b}--optional1{reset} {long_b}--optional2{reset} {label_b}OPTIONAL2{reset} - pick one (default: None) + pick one {default}(default: {reset}{interp}None{reset}{default}){reset} {long_b}--optional3{reset} {label_b}{{X,Y,Z}}{reset} - {long_b}--optional4{reset} {label_b}{{X,Y,Z}}{reset} pick one (default: None) - {long_b}--optional5{reset} {label_b}{{X,Y,Z}}{reset} pick one (default: None) - {long_b}--optional6{reset} {label_b}{{X,Y,Z}}{reset} pick one (default: None) + {long_b}--optional4{reset} {label_b}{{X,Y,Z}}{reset} pick one {default}(default: {reset}{interp}None{reset}{default}){reset} + {long_b}--optional5{reset} {label_b}{{X,Y,Z}}{reset} pick one {default}(default: {reset}{interp}None{reset}{default}){reset} + {long_b}--optional6{reset} {label_b}{{X,Y,Z}}{reset} pick one {default}(default: {reset}{interp}None{reset}{default}){reset} {short_b}-p{reset}, {long_b}--optional7{reset} {label_b}{{Aaaaa,Bbbbb,Ccccc,Ddddd}}{reset} - pick one (default: None) + pick one {default}(default: {reset}{interp}None{reset}{default}){reset} + {long_b}--optional8{reset} {label_b}X{reset} among {interp}A, B, C{reset}, default is {interp}A{reset} {short_b}+f{reset} {label_b}F{reset} {long_b}++bar{reset} {label_b}BAR{reset} {long_b}-+baz{reset} {label_b}BAZ{reset} @@ -7253,7 +7395,28 @@ class TestColorized(TestCase): ), ) - def test_argparse_color_usage(self): + def test_argparse_color_mutually_exclusive_group_usage(self): + parser = argparse.ArgumentParser(color=True, prog="PROG") + group = parser.add_mutually_exclusive_group() + group.add_argument('--foo', action='store_true', help='FOO') + group.add_argument('--spam', help='SPAM') + group.add_argument('badger', nargs='*', help='BADGER') + + prog = self.theme.prog + heading = self.theme.heading + long = self.theme.summary_long_option + short = self.theme.summary_short_option + label = self.theme.summary_label + pos = self.theme.summary_action + reset = self.theme.reset + + self.assertEqual(parser.format_usage(), + f"{heading}usage: {reset}{prog}PROG{reset} [{short}-h{reset}] " + f"[{long}--foo{reset} | " + f"{long}--spam {label}SPAM{reset} | " + f"{pos}badger ...{reset}]\n") + + def test_argparse_color_custom_usage(self): # Arrange parser = argparse.ArgumentParser( add_help=False, @@ -7311,11 +7474,11 @@ class TestColorized(TestCase): {heading}usage: {reset}{prog}PROG{reset} [{short}-h{reset}] [{short}+f {label}FOO{reset}] {pos}spam{reset} {heading}positional arguments:{reset} - {pos_b}spam{reset} spam help + {pos_b}spam{reset} spam help {heading}options:{reset} - {short_b}-h{reset}, {long_b}--help{reset} show this help message and exit - {short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help + {short_b}-h{reset}, {long_b}--help{reset} show this help message and exit + {short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help ''')) def test_custom_formatter_class(self): @@ -7348,13 +7511,202 @@ class TestColorized(TestCase): {heading}usage: {reset}{prog}PROG{reset} [{short}-h{reset}] [{short}+f {label}FOO{reset}] {pos}spam{reset} {heading}positional arguments:{reset} - {pos_b}spam{reset} spam help + {pos_b}spam{reset} spam help {heading}options:{reset} - {short_b}-h{reset}, {long_b}--help{reset} show this help message and exit - {short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help + {short_b}-h{reset}, {long_b}--help{reset} show this help message and exit + {short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help ''')) + def test_subparser_prog_is_stored_without_color(self): + parser = argparse.ArgumentParser(prog='complex', color=True) + sub = parser.add_subparsers(dest='command') + demo_parser = sub.add_parser('demo') + + self.assertNotIn('\x1b[', demo_parser.prog) + + demo_parser.color = False + help_text = demo_parser.format_help() + self.assertNotIn('\x1b[', help_text) + + def test_error_and_warning_keywords_colorized(self): + parser = argparse.ArgumentParser(prog='PROG') + parser.add_argument('foo') + + with self.assertRaises(SystemExit): + with captured_stderr() as stderr: + parser.parse_args([]) + + err = stderr.getvalue() + error_color = self.theme.error + reset = self.theme.reset + self.assertIn(f'{error_color}error:{reset}', err) + + with captured_stderr() as stderr: + parser._warning('test warning') + + warn = stderr.getvalue() + warning_color = self.theme.warning + self.assertIn(f'{warning_color}warning:{reset}', warn) + + def test_error_and_warning_not_colorized_when_disabled(self): + parser = argparse.ArgumentParser(prog='PROG', color=False) + parser.add_argument('foo') + + with self.assertRaises(SystemExit): + with captured_stderr() as stderr: + parser.parse_args([]) + + err = stderr.getvalue() + self.assertNotIn('\x1b[', err) + self.assertIn('error:', err) + + with captured_stderr() as stderr: + parser._warning('test warning') + + warn = stderr.getvalue() + self.assertNotIn('\x1b[', warn) + self.assertIn('warning:', warn) + + def test_backtick_markup_in_epilog(self): + parser = argparse.ArgumentParser( + prog='PROG', + color=True, + epilog='Example: `python -m myapp --verbose`', + ) + + prog_extra = self.theme.prog_extra + reset = self.theme.reset + + help_text = parser.format_help() + self.assertIn(f'Example: {prog_extra}python -m myapp --verbose{reset}', + help_text) + self.assertNotIn('`', help_text) + + def test_backtick_markup_in_description(self): + parser = argparse.ArgumentParser( + prog='PROG', + color=True, + description='Run `python -m myapp` to start.', + ) + + prog_extra = self.theme.prog_extra + reset = self.theme.reset + + help_text = parser.format_help() + self.assertIn(f'Run {prog_extra}python -m myapp{reset} to start.', + help_text) + + def test_backtick_markup_multiple(self): + parser = argparse.ArgumentParser( + prog='PROG', + color=True, + epilog='Try `app run` or `app test`.', + ) + + prog_extra = self.theme.prog_extra + reset = self.theme.reset + + help_text = parser.format_help() + self.assertIn(f'{prog_extra}app run{reset}', help_text) + self.assertIn(f'{prog_extra}app test{reset}', help_text) + + def test_backtick_markup_not_applied_when_color_disabled(self): + # When color is disabled, backticks are preserved as-is + parser = argparse.ArgumentParser( + prog='PROG', + color=False, + epilog='Example: `python -m myapp`', + ) + + help_text = parser.format_help() + self.assertIn('`python -m myapp`', help_text) + self.assertNotIn('\x1b[', help_text) + + def test_backtick_markup_with_format_string(self): + parser = argparse.ArgumentParser( + prog='myapp', + color=True, + epilog='Run `%(prog)s --help` for more info.', + ) + + prog_extra = self.theme.prog_extra + reset = self.theme.reset + + help_text = parser.format_help() + self.assertIn(f'{prog_extra}myapp --help{reset}', help_text) + + def test_backtick_markup_in_subparser(self): + parser = argparse.ArgumentParser(prog='PROG', color=True) + subparsers = parser.add_subparsers() + sub = subparsers.add_parser( + 'sub', + description='Run `PROG sub --foo` to start.', + ) + + prog_extra = self.theme.prog_extra + reset = self.theme.reset + + help_text = sub.format_help() + self.assertIn(f'{prog_extra}PROG sub --foo{reset}', help_text) + + def test_backtick_markup_special_regex_chars(self): + parser = argparse.ArgumentParser( + prog='PROG', + color=True, + epilog='`grep "foo.*bar" | sort`', + ) + + prog_extra = self.theme.prog_extra + reset = self.theme.reset + + help_text = parser.format_help() + self.assertIn(f'{prog_extra}grep "foo.*bar" | sort{reset}', help_text) + + def test_print_help_uses_target_file_for_color_decision(self): + parser = argparse.ArgumentParser(prog='PROG', color=True) + parser.add_argument('--opt') + output = io.StringIO() + calls = [] + + def fake_can_colorize(*, file=None): + calls.append(file) + return file is None + + with swap_attr(_colorize, 'can_colorize', fake_can_colorize): + parser.print_help(file=output) + + self.assertIs(calls[-1], output) + self.assertIn(output, calls) + self.assertNotIn('\x1b[', output.getvalue()) + + def test_print_usage_uses_target_file_for_color_decision(self): + parser = argparse.ArgumentParser(prog='PROG', color=True) + parser.add_argument('--opt') + output = io.StringIO() + calls = [] + + def fake_can_colorize(*, file=None): + calls.append(file) + return file is None + + with swap_attr(_colorize, 'can_colorize', fake_can_colorize): + parser.print_usage(file=output) + + self.assertIs(calls[-1], output) + self.assertIn(output, calls) + self.assertNotIn('\x1b[', output.getvalue()) + + +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(argparse, "__version__") + self.assertEqual(cm.filename, __file__) + def tearDownModule(): # Remove global references to avoid looking like we have refleaks. diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 58ea89c4fac..83b3c978da3 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1255,6 +1255,14 @@ class UnicodeTest(StringTest, unittest.TestCase): with self.assertWarns(DeprecationWarning): array.array("u") + def test_empty_string_mem_leak_gh140474(self): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + for _ in range(1000): + a = array.array('u', '') + self.assertEqual(len(a), 0) + self.assertEqual(a.typecode, 'u') + class UCS4Test(UnicodeTest): typecode = 'w' diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 1e6f6007430..d2b76b46dbe 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -13,6 +13,7 @@ import tempfile import textwrap import types import unittest +import warnings import weakref from io import StringIO from pathlib import Path @@ -991,7 +992,8 @@ class AST_Tests(unittest.TestCase): @skip_wasi_stack_overflow() @skip_emscripten_stack_overflow() def test_ast_recursion_limit(self): - crash_depth = 500_000 + # Android test devices have less memory. + crash_depth = 100_000 if sys.platform == "android" else 500_000 success_depth = 200 if _testinternalcapi is not None: remaining = _testinternalcapi.get_c_recursion_remaining() @@ -1057,61 +1059,6 @@ class AST_Tests(unittest.TestCase): r"Exceeds the limit \(\d+ digits\)"): repr(ast.Constant(value=eval(source))) - def test_pep_765_warnings(self): - srcs = [ - textwrap.dedent(""" - def f(): - try: - pass - finally: - return 42 - """), - textwrap.dedent(""" - for x in y: - try: - pass - finally: - break - """), - textwrap.dedent(""" - for x in y: - try: - pass - finally: - continue - """), - ] - for src in srcs: - with self.assertWarnsRegex(SyntaxWarning, 'finally'): - ast.parse(src) - - def test_pep_765_no_warnings(self): - srcs = [ - textwrap.dedent(""" - try: - pass - finally: - def f(): - return 42 - """), - textwrap.dedent(""" - try: - pass - finally: - for x in y: - break - """), - textwrap.dedent(""" - try: - pass - finally: - for x in y: - continue - """), - ] - for src in srcs: - ast.parse(src) - def test_tstring(self): # Test AST structure for simple t-string tree = ast.parse('t"Hello"') @@ -1124,6 +1071,29 @@ class AST_Tests(unittest.TestCase): self.assertIsInstance(tree.body[0].value.values[0], ast.Constant) self.assertIsInstance(tree.body[0].value.values[1], ast.Interpolation) + def test_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with open(filename, 'rb') as f: + source = f.read() + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'\z') + ast.parse(source) + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10]) + for wm in wlog: + self.assertEqual(wm.filename, '') + self.assertIs(wm.category, SyntaxWarning) + + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'package\.module\z') + warnings.filterwarnings('error', module=r'') + ast.parse(source, filename, module='package.module') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + class CopyTests(unittest.TestCase): """Test copying and pickling AST nodes.""" @@ -3088,8 +3058,8 @@ class EndPositionTests(unittest.TestCase): class NodeTransformerTests(ASTTestMixin, unittest.TestCase): def assertASTTransformation(self, transformer_class, - initial_code, expected_code): - initial_ast = ast.parse(dedent(initial_code)) + code, expected_code): + initial_ast = ast.parse(dedent(code)) expected_ast = ast.parse(dedent(expected_code)) transformer = transformer_class() @@ -3308,6 +3278,15 @@ class ASTConstructorTests(unittest.TestCase): self.assertEqual(obj.a, 1) self.assertEqual(obj.b, 2) + def test_malformed_fields_with_bytes(self): + class BadFields(ast.AST): + _fields = (b'\xff'*64,) + _field_types = {'a': int} + + # This should not crash + with self.assertWarnsRegex(DeprecationWarning, r"Field b'\\xff\\xff.*' .*"): + obj = BadFields() + def test_complete_field_types(self): class _AllFieldTypes(ast.AST): _fields = ('a', 'b') diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index da79ee9260a..0561b54a3f1 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -316,11 +316,9 @@ class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase) asyncio.all_tasks = asyncio.tasks.all_tasks = self._all_tasks return super().tearDown() - - @unittest.skip("skip") def test_issue105987(self): code = """if 1: - from _asyncio import _swap_current_task + from _asyncio import _swap_current_task, _set_running_loop class DummyTask: pass @@ -329,6 +327,7 @@ class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase) pass l = DummyLoop() + _set_running_loop(l) _swap_current_task(l, DummyTask()) t = _swap_current_task(l, None) """ diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 9d77e7e5889..4bb5d4fb816 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -854,6 +854,22 @@ class SelectorSocketTransportTests(test_utils.TestCase): self.assertTrue(self.sock.send.called) self.assertTrue(self.loop.writers) + def test_writelines_after_connection_lost(self): + # GH-136234 + transport = self.socket_transport() + self.sock.send = mock.Mock() + self.sock.send.side_effect = ConnectionResetError + transport.write(b'data1') # Will fail immediately, causing connection lost + + transport.writelines([b'data2']) + self.assertFalse(transport._buffer) + self.assertFalse(self.loop.writers) + + test_utils.run_briefly(self.loop) # Allow _call_connection_lost to run + transport.writelines([b'data2']) + self.assertFalse(transport._buffer) + self.assertFalse(self.loop.writers) + @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg') def test_write_sendmsg_full(self): data = memoryview(b'data') diff --git a/Lib/test/test_asyncio/test_ssl.py b/Lib/test/test_asyncio/test_ssl.py index 06118f3a615..ca15fc3bdd4 100644 --- a/Lib/test/test_asyncio/test_ssl.py +++ b/Lib/test/test_asyncio/test_ssl.py @@ -27,6 +27,7 @@ from test.test_asyncio import utils as test_utils MACOS = (sys.platform == 'darwin') BUF_MULTIPLIER = 1024 if not MACOS else 64 +HANDSHAKE_TIMEOUT = support.LONG_TIMEOUT def tearDownModule(): @@ -257,15 +258,12 @@ class TestSSL(test_utils.TestCase): await fut async def start_server(): - extras = {} - extras = dict(ssl_handshake_timeout=support.SHORT_TIMEOUT) - srv = await asyncio.start_server( handle_client, '127.0.0.1', 0, family=socket.AF_INET, ssl=sslctx, - **extras) + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) try: srv_socks = srv.sockets @@ -322,14 +320,11 @@ class TestSSL(test_utils.TestCase): sock.close() async def client(addr): - extras = {} - extras = dict(ssl_handshake_timeout=support.SHORT_TIMEOUT) - reader, writer = await asyncio.open_connection( *addr, ssl=client_sslctx, server_hostname='', - **extras) + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) writer.write(A_DATA) self.assertEqual(await reader.readexactly(2), b'OK') @@ -349,7 +344,8 @@ class TestSSL(test_utils.TestCase): reader, writer = await asyncio.open_connection( sock=sock, ssl=client_sslctx, - server_hostname='') + server_hostname='', + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) writer.write(A_DATA) self.assertEqual(await reader.readexactly(2), b'OK') @@ -448,7 +444,7 @@ class TestSSL(test_utils.TestCase): *addr, ssl=client_sslctx, server_hostname='', - ssl_handshake_timeout=support.SHORT_TIMEOUT) + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) writer.close() await self.wait_closed(writer) @@ -610,7 +606,7 @@ class TestSSL(test_utils.TestCase): extras = {} if server_ssl: - extras = dict(ssl_handshake_timeout=support.SHORT_TIMEOUT) + extras = dict(ssl_handshake_timeout=HANDSHAKE_TIMEOUT) f = loop.create_task( loop.connect_accepted_socket( @@ -659,7 +655,8 @@ class TestSSL(test_utils.TestCase): reader, writer = await asyncio.open_connection( *addr, ssl=client_sslctx, - server_hostname='') + server_hostname='', + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) self.assertEqual(await reader.readline(), b'A\n') writer.write(b'B') @@ -1152,14 +1149,11 @@ class TestSSL(test_utils.TestCase): await fut async def start_server(): - extras = {} - srv = await self.loop.create_server( server_protocol_factory, '127.0.0.1', 0, family=socket.AF_INET, - ssl=sslctx_1, - **extras) + ssl=sslctx_1) try: srv_socks = srv.sockets @@ -1209,14 +1203,11 @@ class TestSSL(test_utils.TestCase): sock.close() async def client(addr): - extras = {} - extras = dict(ssl_handshake_timeout=support.SHORT_TIMEOUT) - reader, writer = await asyncio.open_connection( *addr, ssl=client_sslctx, server_hostname='', - **extras) + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) writer.write(A_DATA) self.assertEqual(await reader.readexactly(2), b'OK') @@ -1286,7 +1277,8 @@ class TestSSL(test_utils.TestCase): reader, writer = await asyncio.open_connection( *addr, ssl=client_sslctx, - server_hostname='') + server_hostname='', + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) sslprotocol = writer.transport._ssl_protocol writer.write(b'ping') data = await reader.readexactly(4) @@ -1398,7 +1390,8 @@ class TestSSL(test_utils.TestCase): reader, writer = await asyncio.open_connection( *addr, ssl=client_sslctx, - server_hostname='') + server_hostname='', + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) writer.write(b'ping') data = await reader.readexactly(4) self.assertEqual(data, b'pong') @@ -1529,7 +1522,8 @@ class TestSSL(test_utils.TestCase): reader, writer = await asyncio.open_connection( *addr, ssl=client_sslctx, - server_hostname='') + server_hostname='', + ssl_handshake_timeout=HANDSHAKE_TIMEOUT) writer.write(b'ping') data = await reader.readexactly(4) self.assertEqual(data, b'pong') diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 3a17c169c34..bf301740741 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -11,7 +11,7 @@ from asyncio import base_subprocess from asyncio import subprocess from test.test_asyncio import utils as test_utils from test import support -from test.support import os_helper +from test.support import os_helper, warnings_helper, gc_collect if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") @@ -879,6 +879,44 @@ class SubprocessMixin: self.loop.run_until_complete(main()) + @warnings_helper.ignore_warnings(category=ResourceWarning) + def test_subprocess_read_pipe_cancelled(self): + async def main(): + loop = asyncio.get_running_loop() + loop.connect_read_pipe = mock.AsyncMock(side_effect=asyncio.CancelledError) + with self.assertRaises(asyncio.CancelledError): + await asyncio.create_subprocess_exec(*PROGRAM_BLOCKED, stderr=asyncio.subprocess.PIPE) + + asyncio.run(main()) + gc_collect() + + @warnings_helper.ignore_warnings(category=ResourceWarning) + def test_subprocess_write_pipe_cancelled(self): + async def main(): + loop = asyncio.get_running_loop() + loop.connect_write_pipe = mock.AsyncMock(side_effect=asyncio.CancelledError) + with self.assertRaises(asyncio.CancelledError): + await asyncio.create_subprocess_exec(*PROGRAM_BLOCKED, stdin=asyncio.subprocess.PIPE) + + asyncio.run(main()) + gc_collect() + + @warnings_helper.ignore_warnings(category=ResourceWarning) + def test_subprocess_read_write_pipe_cancelled(self): + async def main(): + loop = asyncio.get_running_loop() + loop.connect_read_pipe = mock.AsyncMock(side_effect=asyncio.CancelledError) + loop.connect_write_pipe = mock.AsyncMock(side_effect=asyncio.CancelledError) + with self.assertRaises(asyncio.CancelledError): + await asyncio.create_subprocess_exec( + *PROGRAM_BLOCKED, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + asyncio.run(main()) + gc_collect() if sys.platform != 'win32': # Unix diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 931a43816a2..a3c5351fed0 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -3045,6 +3045,26 @@ class BaseTaskIntrospectionTests: _enter_task = None _leave_task = None all_tasks = None + Task = None + + def test_register_task_resurrection(self): + register_task = self._register_task + class EvilLoop: + def get_debug(self): + return False + + def call_exception_handler(self, context): + register_task(context["task"]) + + async def coro_fn (): + pass + + coro = coro_fn() + self.addCleanup(coro.close) + loop = EvilLoop() + with self.assertRaises(AttributeError): + self.Task(coro, loop=loop) + def test__register_task_1(self): class TaskLike: @@ -3175,6 +3195,7 @@ class PyIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests): _leave_task = staticmethod(tasks._py_leave_task) all_tasks = staticmethod(tasks._py_all_tasks) current_task = staticmethod(tasks._py_current_task) + Task = tasks._PyTask @unittest.skipUnless(hasattr(tasks, '_c_register_task'), @@ -3187,10 +3208,12 @@ class CIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests): _leave_task = staticmethod(tasks._c_leave_task) all_tasks = staticmethod(tasks._c_all_tasks) current_task = staticmethod(tasks._c_current_task) + Task = tasks._CTask else: _register_task = _unregister_task = _enter_task = _leave_task = None + class BaseCurrentLoopTests: current_task = None @@ -3680,6 +3703,30 @@ class RunCoroutineThreadsafeTests(test_utils.TestCase): (loop, context), kwargs = callback.call_args self.assertEqual(context['exception'], exc_context.exception) + def test_run_coroutine_threadsafe_and_cancel(self): + task = None + thread_future = None + # Use a custom task factory to capture the created Task + def task_factory(loop, coro): + nonlocal task + task = asyncio.Task(coro, loop=loop) + return task + + self.addCleanup(self.loop.set_task_factory, + self.loop.get_task_factory()) + + async def target(): + nonlocal thread_future + self.loop.set_task_factory(task_factory) + thread_future = asyncio.run_coroutine_threadsafe(asyncio.sleep(10), self.loop) + await asyncio.sleep(0) + + thread_future.cancel() + + self.loop.run_until_complete(target()) + self.assertTrue(task.cancelled()) + self.assertTrue(thread_future.cancelled()) + class SleepTests(test_utils.TestCase): def setUp(self): diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index a69a5e32b1b..d2b3de3b9a4 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -1180,32 +1180,68 @@ class TestFunctional(unittest.TestCase): @support.requires_fork() -class TestFork(unittest.IsolatedAsyncioTestCase): +class TestFork(unittest.TestCase): - async def test_fork_not_share_event_loop(self): - with warnings_helper.ignore_fork_in_thread_deprecation_warnings(): - # The forked process should not share the event loop with the parent - loop = asyncio.get_running_loop() - r, w = os.pipe() - self.addCleanup(os.close, r) - self.addCleanup(os.close, w) - pid = os.fork() - if pid == 0: - # child - try: - loop = asyncio.get_event_loop() - os.write(w, b'LOOP:' + str(id(loop)).encode()) - except RuntimeError: - os.write(w, b'NO LOOP') - except BaseException as e: - os.write(w, b'ERROR:' + ascii(e).encode()) - finally: - os._exit(0) - else: - # parent - result = os.read(r, 100) - self.assertEqual(result, b'NO LOOP') - wait_process(pid, exitcode=0) + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() + def test_fork_not_share_current_task(self): + loop = object() + task = object() + asyncio._set_running_loop(loop) + self.addCleanup(asyncio._set_running_loop, None) + asyncio.tasks._enter_task(loop, task) + self.addCleanup(asyncio.tasks._leave_task, loop, task) + self.assertIs(asyncio.current_task(), task) + r, w = os.pipe() + self.addCleanup(os.close, r) + self.addCleanup(os.close, w) + pid = os.fork() + if pid == 0: + # child + try: + asyncio._set_running_loop(loop) + current_task = asyncio.current_task() + if current_task is None: + os.write(w, b'NO TASK') + else: + os.write(w, b'TASK:' + str(id(current_task)).encode()) + except BaseException as e: + os.write(w, b'ERROR:' + ascii(e).encode()) + finally: + asyncio._set_running_loop(None) + os._exit(0) + else: + # parent + result = os.read(r, 100) + self.assertEqual(result, b'NO TASK') + wait_process(pid, exitcode=0) + + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() + def test_fork_not_share_event_loop(self): + # The forked process should not share the event loop with the parent + loop = object() + asyncio._set_running_loop(loop) + self.assertIs(asyncio.get_running_loop(), loop) + self.addCleanup(asyncio._set_running_loop, None) + r, w = os.pipe() + self.addCleanup(os.close, r) + self.addCleanup(os.close, w) + pid = os.fork() + if pid == 0: + # child + try: + loop = asyncio.get_event_loop() + os.write(w, b'LOOP:' + str(id(loop)).encode()) + except RuntimeError: + os.write(w, b'NO LOOP') + except BaseException as e: + os.write(w, b'ERROR:' + ascii(e).encode()) + finally: + os._exit(0) + else: + # parent + result = os.read(r, 100) + self.assertEqual(result, b'NO LOOP') + wait_process(pid, exitcode=0) @warnings_helper.ignore_fork_in_thread_deprecation_warnings() @hashlib_helper.requires_hashdigest('md5') diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py index eb01da6e88a..8256ff183f2 100644 --- a/Lib/test/test_atexit.py +++ b/Lib/test/test_atexit.py @@ -1,9 +1,11 @@ import atexit import os +import subprocess import textwrap import unittest from test import support -from test.support import script_helper +from test.support import SuppressCrashReport, script_helper +from test.support import os_helper from test.support import threading_helper class GeneralTest(unittest.TestCase): @@ -79,6 +81,62 @@ class FunctionalTest(unittest.TestCase): # want them to affect the rest of the tests. script_helper.assert_python_ok("-c", textwrap.dedent(source)) + @threading_helper.requires_working_threading() + def test_thread_created_in_atexit(self): + source = """if True: + import atexit + import threading + import time + + + def run(): + print(24) + time.sleep(1) + print(42) + + @atexit.register + def start_thread(): + threading.Thread(target=run).start() + """ + return_code, stdout, stderr = script_helper.assert_python_ok("-c", source) + self.assertEqual(return_code, 0) + self.assertEqual(stdout, f"24{os.linesep}42{os.linesep}".encode("utf-8")) + self.assertEqual(stderr, b"") + + @threading_helper.requires_working_threading() + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_thread_created_in_atexit_subinterpreter(self): + try: + from concurrent import interpreters + except ImportError: + self.skipTest("subinterpreters are not available") + + read, write = os.pipe() + source = f"""if True: + import atexit + import threading + import time + import os + + def run(): + os.write({write}, b'spanish') + time.sleep(1) + os.write({write}, b'inquisition') + + @atexit.register + def start_thread(): + threading.Thread(target=run).start() + """ + interp = interpreters.create() + try: + interp.exec(source) + + # Close the interpreter to invoke atexit callbacks + interp.close() + self.assertEqual(os.read(read, 100), b"spanishinquisition") + finally: + os.close(read) + os.close(write) @support.cpython_only class SubinterpreterTest(unittest.TestCase): @@ -133,6 +191,37 @@ class SubinterpreterTest(unittest.TestCase): self.assertEqual(os.read(r, len(expected)), expected) os.close(r) + # Python built with Py_TRACE_REFS fail with a fatal error in + # _PyRefchain_Trace() on memory allocation error. + @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + def test_atexit_with_low_memory(self): + # gh-140080: Test that setting low memory after registering an atexit + # callback doesn't cause an infinite loop during finalization. + code = textwrap.dedent(""" + import atexit + import _testcapi + + def callback(): + print("hello") + + atexit.register(callback) + # Simulate low memory condition + _testcapi.set_nomemory(0) + """) + + with os_helper.temp_dir() as temp_dir: + script = script_helper.make_script(temp_dir, 'test_atexit_script', code) + with SuppressCrashReport(): + with script_helper.spawn_python(script, + stderr=subprocess.PIPE) as proc: + proc.wait() + stdout = proc.stdout.read() + stderr = proc.stderr.read() + + self.assertIn(proc.returncode, (0, 1)) + self.assertNotIn(b"hello", stdout) + self.assertIn(b"MemoryError", stderr) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 077765fcda2..db4e1eb9999 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -331,5 +331,14 @@ class AuditTest(unittest.TestCase): if returncode: self.fail(stderr) + def test_import_module(self): + self.do_test("test_import_module") + + def test_builtin__import__(self): + self.do_test("test_builtin__import__") + + def test_import_statement(self): + self.do_test("test_import_statement") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py index ce2e3e3726f..ac3f0940545 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -1,6 +1,7 @@ import unittest import base64 import binascii +import string import os from array import array from test.support import cpython_only @@ -14,6 +15,8 @@ class LazyImportTest(unittest.TestCase): def test_lazy_import(self): ensure_lazy_imports("base64", {"re", "getopt"}) +from test.support.hypothesis_helper import hypothesis + class LegacyBase64TestCase(unittest.TestCase): @@ -68,6 +71,13 @@ class LegacyBase64TestCase(unittest.TestCase): eq(base64.decodebytes(array('B', b'YWJj\n')), b'abc') self.check_type_errors(base64.decodebytes) + @hypothesis.given(payload=hypothesis.strategies.binary()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz') + def test_bytes_encode_decode_round_trip(self, payload): + encoded = base64.encodebytes(payload) + decoded = base64.decodebytes(encoded) + self.assertEqual(payload, decoded) + def test_encode(self): eq = self.assertEqual from io import BytesIO, StringIO @@ -96,6 +106,19 @@ class LegacyBase64TestCase(unittest.TestCase): self.assertRaises(TypeError, base64.encode, BytesIO(b'YWJj\n'), StringIO()) self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), StringIO()) + @hypothesis.given(payload=hypothesis.strategies.binary()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz') + def test_legacy_encode_decode_round_trip(self, payload): + from io import BytesIO + payload_file_r = BytesIO(payload) + encoded_file_w = BytesIO() + base64.encode(payload_file_r, encoded_file_w) + encoded_file_r = BytesIO(encoded_file_w.getvalue()) + decoded_file_w = BytesIO() + base64.decode(encoded_file_r, decoded_file_w) + decoded = decoded_file_w.getvalue() + self.assertEqual(payload, decoded) + class BaseXYTestCase(unittest.TestCase): @@ -208,18 +231,6 @@ class BaseXYTestCase(unittest.TestCase): self.check_other_types(base64.b64decode, b"YWJj", b"abc") self.check_decode_type_errors(base64.b64decode) - # Test with arbitrary alternative characters - tests_altchars = {(b'01a*b$cd', b'*$'): b'\xd3V\xbeo\xf7\x1d', - } - for (data, altchars), res in tests_altchars.items(): - data_str = data.decode('ascii') - altchars_str = altchars.decode('ascii') - - eq(base64.b64decode(data, altchars=altchars), res) - eq(base64.b64decode(data_str, altchars=altchars), res) - eq(base64.b64decode(data, altchars=altchars_str), res) - eq(base64.b64decode(data_str, altchars=altchars_str), res) - # Test standard alphabet for data, res in tests.items(): eq(base64.standard_b64decode(data), res) @@ -240,6 +251,20 @@ class BaseXYTestCase(unittest.TestCase): b'\xd3V\xbeo\xf7\x1d') self.check_decode_type_errors(base64.urlsafe_b64decode) + def test_b64decode_altchars(self): + # Test with arbitrary alternative characters + eq = self.assertEqual + res = b'\xd3V\xbeo\xf7\x1d' + for altchars in b'*$', b'+/', b'/+', b'+_', b'-+', b'-/', b'/_': + data = b'01a%cb%ccd' % tuple(altchars) + data_str = data.decode('ascii') + altchars_str = altchars.decode('ascii') + + eq(base64.b64decode(data, altchars=altchars), res) + eq(base64.b64decode(data_str, altchars=altchars), res) + eq(base64.b64decode(data, altchars=altchars_str), res) + eq(base64.b64decode(data_str, altchars=altchars_str), res) + def test_b64decode_padding_error(self): self.assertRaises(binascii.Error, base64.b64decode, b'abc') self.assertRaises(binascii.Error, base64.b64decode, 'abc') @@ -272,9 +297,49 @@ class BaseXYTestCase(unittest.TestCase): base64.b64decode(bstr.decode('ascii'), validate=True) # Normal alphabet characters not discarded when alternative given - res = b'\xFB\xEF\xBE\xFF\xFF\xFF' - self.assertEqual(base64.b64decode(b'++[[//]]', b'[]'), res) - self.assertEqual(base64.urlsafe_b64decode(b'++--//__'), res) + res = b'\xfb\xef\xff' + self.assertEqual(base64.b64decode(b'++//', validate=True), res) + self.assertEqual(base64.b64decode(b'++//', '-_', validate=True), res) + self.assertEqual(base64.b64decode(b'--__', '-_', validate=True), res) + self.assertEqual(base64.urlsafe_b64decode(b'++//'), res) + self.assertEqual(base64.urlsafe_b64decode(b'--__'), res) + + def _altchars_strategy(): + """Generate 'altchars' for base64 encoding.""" + reserved_chars = (string.digits + string.ascii_letters + "=").encode() + allowed_chars = hypothesis.strategies.sampled_from( + [n for n in range(256) if n not in reserved_chars]) + two_bytes_strategy = hypothesis.strategies.lists( + allowed_chars, min_size=2, max_size=2, unique=True).map(bytes) + return (hypothesis.strategies.none() + | hypothesis.strategies.just(b"_-") + | two_bytes_strategy) + + @hypothesis.given( + payload=hypothesis.strategies.binary(), + altchars=_altchars_strategy(), + validate=hypothesis.strategies.booleans()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', b"_-", True) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', b"_-", False) + def test_b64_encode_decode_round_trip(self, payload, altchars, validate): + encoded = base64.b64encode(payload, altchars=altchars) + decoded = base64.b64decode(encoded, altchars=altchars, + validate=validate) + self.assertEqual(payload, decoded) + + @hypothesis.given(payload=hypothesis.strategies.binary()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz') + def test_standard_b64_encode_decode_round_trip(self, payload): + encoded = base64.standard_b64encode(payload) + decoded = base64.standard_b64decode(encoded) + self.assertEqual(payload, decoded) + + @hypothesis.given(payload=hypothesis.strategies.binary()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz') + def test_urlsafe_b64_encode_decode_round_trip(self, payload): + encoded = base64.urlsafe_b64encode(payload) + decoded = base64.urlsafe_b64decode(encoded) + self.assertEqual(payload, decoded) def test_b32encode(self): eq = self.assertEqual @@ -329,23 +394,33 @@ class BaseXYTestCase(unittest.TestCase): self.assertRaises(binascii.Error, base64.b32decode, b'me======') self.assertRaises(binascii.Error, base64.b32decode, 'me======') + def test_b32decode_map01(self): # Mapping zero and one - eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe') - eq(base64.b32decode('MLO23456'), b'b\xdd\xad\xf3\xbe') + eq = self.assertEqual + res_L = b'b\xdd\xad\xf3\xbe' + res_I = b'b\x1d\xad\xf3\xbe' + eq(base64.b32decode(b'MLO23456'), res_L) + eq(base64.b32decode('MLO23456'), res_L) + eq(base64.b32decode(b'MIO23456'), res_I) + eq(base64.b32decode('MIO23456'), res_I) + self.assertRaises(binascii.Error, base64.b32decode, b'M1023456') + self.assertRaises(binascii.Error, base64.b32decode, b'M1O23456') + self.assertRaises(binascii.Error, base64.b32decode, b'ML023456') + self.assertRaises(binascii.Error, base64.b32decode, b'MI023456') - map_tests = {(b'M1023456', b'L'): b'b\xdd\xad\xf3\xbe', - (b'M1023456', b'I'): b'b\x1d\xad\xf3\xbe', - } - for (data, map01), res in map_tests.items(): - data_str = data.decode('ascii') + data = b'M1023456' + data_str = data.decode('ascii') + for map01, res in [(b'L', res_L), (b'I', res_I)]: map01_str = map01.decode('ascii') eq(base64.b32decode(data, map01=map01), res) eq(base64.b32decode(data_str, map01=map01), res) eq(base64.b32decode(data, map01=map01_str), res) eq(base64.b32decode(data_str, map01=map01_str), res) - self.assertRaises(binascii.Error, base64.b32decode, data) - self.assertRaises(binascii.Error, base64.b32decode, data_str) + + eq(base64.b32decode(b'M1O23456', map01=map01), res) + eq(base64.b32decode(b'M%c023456' % map01, map01=map01), res) + eq(base64.b32decode(b'M%cO23456' % map01, map01=map01), res) def test_b32decode_error(self): tests = [b'abc', b'ABCDEF==', b'==ABCDEF'] @@ -363,6 +438,19 @@ class BaseXYTestCase(unittest.TestCase): with self.assertRaises(binascii.Error): base64.b32decode(data.decode('ascii')) + @hypothesis.given( + payload=hypothesis.strategies.binary(), + casefold=hypothesis.strategies.booleans(), + map01=( + hypothesis.strategies.none() + | hypothesis.strategies.binary(min_size=1, max_size=1))) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, None) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, None) + def test_b32_encode_decode_round_trip(self, payload, casefold, map01): + encoded = base64.b32encode(payload) + decoded = base64.b32decode(encoded, casefold=casefold, map01=map01) + self.assertEqual(payload, decoded) + def test_b32hexencode(self): test_cases = [ # to_encode, expected @@ -432,6 +520,15 @@ class BaseXYTestCase(unittest.TestCase): with self.assertRaises(binascii.Error): base64.b32hexdecode(data.decode('ascii')) + @hypothesis.given( + payload=hypothesis.strategies.binary(), + casefold=hypothesis.strategies.booleans()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False) + def test_b32_hexencode_decode_round_trip(self, payload, casefold): + encoded = base64.b32hexencode(payload) + decoded = base64.b32hexdecode(encoded, casefold=casefold) + self.assertEqual(payload, decoded) def test_b16encode(self): eq = self.assertEqual @@ -469,6 +566,16 @@ class BaseXYTestCase(unittest.TestCase): # Incorrect "padding" self.assertRaises(binascii.Error, base64.b16decode, '010') + @hypothesis.given( + payload=hypothesis.strategies.binary(), + casefold=hypothesis.strategies.booleans()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False) + def test_b16_encode_decode_round_trip(self, payload, casefold): + endoded = base64.b16encode(payload) + decoded = base64.b16decode(endoded, casefold=casefold) + self.assertEqual(payload, decoded) + def test_a85encode(self): eq = self.assertEqual @@ -799,6 +906,61 @@ class BaseXYTestCase(unittest.TestCase): self.assertRaises(ValueError, base64.z85decode, b'%nSc') self.assertRaises(ValueError, base64.z85decode, b'%nSc1') + def add_padding(self, payload): + """Add the expected padding for test_?85_encode_decode_round_trip.""" + if len(payload) % 4 != 0: + padding = b"\0" * ((-len(payload)) % 4) + payload = payload + padding + return payload + + @hypothesis.given( + payload=hypothesis.strategies.binary(), + foldspaces=hypothesis.strategies.booleans(), + wrapcol=( + hypothesis.strategies.just(0) + | hypothesis.strategies.integers(1, 1000)), + pad=hypothesis.strategies.booleans(), + adobe=hypothesis.strategies.booleans(), + ) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, 0, False, False) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, 20, True, True) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, 0, False, True) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, 20, True, False) + def test_a85_encode_decode_round_trip( + self, payload, foldspaces, wrapcol, pad, adobe + ): + encoded = base64.a85encode( + payload, foldspaces=foldspaces, wrapcol=wrapcol, + pad=pad, adobe=adobe, + ) + if wrapcol: + if adobe and wrapcol == 1: + # "adobe" needs wrapcol to be at least 2. + # a85decode quietly uses 2 if 1 is given; it's not worth + # loudly deprecating this behavior. + wrapcol = 2 + for line in encoded.splitlines(keepends=False): + self.assertLessEqual(len(line), wrapcol) + if adobe: + self.assertTrue(encoded.startswith(b'<~')) + self.assertTrue(encoded.endswith(b'~>')) + decoded = base64.a85decode(encoded, foldspaces=foldspaces, adobe=adobe) + if pad: + payload = self.add_padding(payload) + self.assertEqual(payload, decoded) + + @hypothesis.given( + payload=hypothesis.strategies.binary(), + pad=hypothesis.strategies.booleans()) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True) + @hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False) + def test_b85_encode_decode_round_trip(self, payload, pad): + encoded = base64.b85encode(payload, pad=pad) + if pad: + payload = self.add_padding(payload) + decoded = base64.b85decode(encoded) + self.assertEqual(payload, decoded) + def test_decode_nonascii_str(self): decode_funcs = (base64.b64decode, base64.standard_b64decode, diff --git a/Lib/test/test_bufio.py b/Lib/test/test_bufio.py deleted file mode 100644 index cb9cb4d0bc7..00000000000 --- a/Lib/test/test_bufio.py +++ /dev/null @@ -1,73 +0,0 @@ -import unittest -from test.support import os_helper - -import io # C implementation. -import _pyio as pyio # Python implementation. - -# Simple test to ensure that optimizations in the IO library deliver the -# expected results. For best testing, run this under a debug-build Python too -# (to exercise asserts in the C code). - -lengths = list(range(1, 257)) + [512, 1000, 1024, 2048, 4096, 8192, 10000, - 16384, 32768, 65536, 1000000] - -class BufferSizeTest: - def try_one(self, s): - # Write s + "\n" + s to file, then open it and ensure that successive - # .readline()s deliver what we wrote. - - # Ensure we can open TESTFN for writing. - os_helper.unlink(os_helper.TESTFN) - - # Since C doesn't guarantee we can write/read arbitrary bytes in text - # files, use binary mode. - f = self.open(os_helper.TESTFN, "wb") - try: - # write once with \n and once without - f.write(s) - f.write(b"\n") - f.write(s) - f.close() - f = self.open(os_helper.TESTFN, "rb") - line = f.readline() - self.assertEqual(line, s + b"\n") - line = f.readline() - self.assertEqual(line, s) - line = f.readline() - self.assertFalse(line) # Must be at EOF - f.close() - finally: - os_helper.unlink(os_helper.TESTFN) - - def drive_one(self, pattern): - for length in lengths: - # Repeat string 'pattern' as often as needed to reach total length - # 'length'. Then call try_one with that string, a string one larger - # than that, and a string one smaller than that. Try this with all - # small sizes and various powers of 2, so we exercise all likely - # stdio buffer sizes, and "off by one" errors on both sides. - q, r = divmod(length, len(pattern)) - teststring = pattern * q + pattern[:r] - self.assertEqual(len(teststring), length) - self.try_one(teststring) - self.try_one(teststring + b"x") - self.try_one(teststring[:-1]) - - def test_primepat(self): - # A pattern with prime length, to avoid simple relationships with - # stdio buffer sizes. - self.drive_one(b"1234567890\00\01\02\03\04\05\06") - - def test_nullpat(self): - self.drive_one(b'\0' * 1000) - - -class CBufferSizeTest(BufferSizeTest, unittest.TestCase): - open = io.open - -class PyBufferSizeTest(BufferSizeTest, unittest.TestCase): - open = staticmethod(pyio.open) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_build_details.py b/Lib/test/test_build_details.py index bc04963f5ad..ba9afe69ba4 100644 --- a/Lib/test/test_build_details.py +++ b/Lib/test/test_build_details.py @@ -1,12 +1,34 @@ +import importlib import json import os +import os.path import sys import sysconfig import string import unittest +from pathlib import Path from test.support import is_android, is_apple_mobile, is_wasm32 +BASE_PATH = Path( + __file__, # Lib/test/test_build_details.py + '..', # Lib/test + '..', # Lib + '..', # +).resolve() +MODULE_PATH = BASE_PATH / 'Tools' / 'build' / 'generate-build-details.py' + +try: + # Import "generate-build-details.py" as "generate_build_details" + spec = importlib.util.spec_from_file_location( + "generate_build_details", MODULE_PATH + ) + generate_build_details = importlib.util.module_from_spec(spec) + sys.modules["generate_build_details"] = generate_build_details + spec.loader.exec_module(generate_build_details) +except (FileNotFoundError, ImportError): + generate_build_details = None + class FormatTestsBase: @property @@ -31,16 +53,15 @@ class FormatTestsBase: value = value[part] return value - def test_parse(self): - self.data - def test_top_level_container(self): self.assertIsInstance(self.data, dict) for key, value in self.data.items(): with self.subTest(key=key): - if key in ('schema_version', 'base_prefix', 'base_interpreter', 'platform'): + if key in ('schema_version', 'base_prefix', 'base_interpreter', + 'platform'): self.assertIsInstance(value, str) - elif key in ('language', 'implementation', 'abi', 'suffixes', 'libpython', 'c_api', 'arbitrary_data'): + elif key in ('language', 'implementation', 'abi', 'suffixes', + 'libpython', 'c_api', 'arbitrary_data'): self.assertIsInstance(value, dict) def test_base_prefix(self): @@ -71,15 +92,20 @@ class FormatTestsBase: self.assertEqual(len(value), sys.version_info.n_fields) for part_name, part_value in value.items(): with self.subTest(part=part_name): - self.assertEqual(part_value, getattr(sys.version_info, part_name)) + sys_version_value = getattr(sys.version_info, part_name) + self.assertEqual(part_value, sys_version_value) def test_implementation(self): + impl_ver = sys.implementation.version for key, value in self.key('implementation').items(): with self.subTest(part=key): if key == 'version': - self.assertEqual(len(value), len(sys.implementation.version)) + self.assertEqual(len(value), len(impl_ver)) for part_name, part_value in value.items(): - self.assertEqual(getattr(sys.implementation.version, part_name), part_value) + self.assertFalse(isinstance(sys.implementation.version, dict)) + getattr(sys.implementation.version, part_name) + sys_implementation_value = getattr(impl_ver, part_name) + self.assertEqual(sys_implementation_value, part_value) else: self.assertEqual(getattr(sys.implementation, key), value) @@ -99,7 +125,8 @@ class CPythonBuildDetailsTests(unittest.TestCase, FormatTestsBase): def location(self): if sysconfig.is_python_build(): projectdir = sysconfig.get_config_var('projectbase') - with open(os.path.join(projectdir, 'pybuilddir.txt')) as f: + pybuilddir = os.path.join(projectdir, 'pybuilddir.txt') + with open(pybuilddir, encoding='utf-8') as f: dirname = os.path.join(projectdir, f.read()) else: dirname = sysconfig.get_path('stdlib') @@ -107,7 +134,7 @@ class CPythonBuildDetailsTests(unittest.TestCase, FormatTestsBase): @property def contents(self): - with open(self.location, 'r') as f: + with open(self.location, 'r', encoding='utf-8') as f: return f.read() @needs_installed_python @@ -147,5 +174,64 @@ class CPythonBuildDetailsTests(unittest.TestCase, FormatTestsBase): self.assertTrue(os.path.exists(os.path.join(value['pkgconfig_path'], f'python-{version}.pc'))) +@unittest.skipIf( + generate_build_details is None, + "Failed to import generate-build-details" +) +@unittest.skipIf(os.name != 'posix', 'Feature only implemented on POSIX right now') +@unittest.skipIf(is_wasm32, 'Feature not available on WebAssembly builds') +class BuildDetailsRelativePathsTests(unittest.TestCase): + @property + def build_details_absolute_paths(self): + data = generate_build_details.generate_data(schema_version='1.0') + return json.loads(json.dumps(data)) + + @property + def build_details_relative_paths(self): + data = self.build_details_absolute_paths + generate_build_details.make_paths_relative(data, config_path=None) + return data + + def test_round_trip(self): + data_abs_path = self.build_details_absolute_paths + data_rel_path = self.build_details_relative_paths + + self.assertEqual(data_abs_path['base_prefix'], + data_rel_path['base_prefix']) + + base_prefix = data_abs_path['base_prefix'] + + top_level_keys = ('base_interpreter',) + for key in top_level_keys: + self.assertEqual(key in data_abs_path, key in data_rel_path) + if key not in data_abs_path: + continue + + abs_rel_path = os.path.join(base_prefix, data_rel_path[key]) + abs_rel_path = os.path.normpath(abs_rel_path) + self.assertEqual(data_abs_path[key], abs_rel_path) + + second_level_keys = ( + ('libpython', 'dynamic'), + ('libpython', 'dynamic_stableabi'), + ('libpython', 'static'), + ('c_api', 'headers'), + ('c_api', 'pkgconfig_path'), + + ) + for part, key in second_level_keys: + self.assertEqual(part in data_abs_path, part in data_rel_path) + if part not in data_abs_path: + continue + self.assertEqual(key in data_abs_path[part], + key in data_rel_path[part]) + if key not in data_abs_path[part]: + continue + + abs_rel_path = os.path.join(base_prefix, data_rel_path[part][key]) + abs_rel_path = os.path.normpath(abs_rel_path) + self.assertEqual(data_abs_path[part][key], abs_rel_path) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 85cfe5c90f4..ce60a5d095d 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1088,6 +1088,29 @@ class BuiltinTest(ComplexesAreIdenticalMixin, unittest.TestCase): three_freevars.__globals__, closure=my_closure) + def test_exec_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with open(filename, 'rb') as f: + source = f.read() + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'\z') + exec(source, {}) + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, '') + self.assertIs(wm.category, SyntaxWarning) + + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'package.module\z') + warnings.filterwarnings('error', module=r'') + exec(source, {'__name__': 'package.module', '__file__': filename}) + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, '') + self.assertIs(wm.category, SyntaxWarning) + def test_filter(self): self.assertEqual(list(filter(lambda c: 'a' <= c <= 'z', 'Hello World')), list('elloorld')) @@ -1184,6 +1207,16 @@ class BuiltinTest(ComplexesAreIdenticalMixin, unittest.TestCase): return self self.assertEqual(hash(Z(42)), hash(42)) + def test_invalid_hash_typeerror(self): + # GH-140406: The returned object from __hash__() would leak if it + # wasn't an integer. + class A: + def __hash__(self): + return 1.0 + + with self.assertRaises(TypeError): + hash(A()) + def test_hex(self): self.assertEqual(hex(16), '0x10') self.assertEqual(hex(-16), '-0x10') @@ -1375,6 +1408,22 @@ class BuiltinTest(ComplexesAreIdenticalMixin, unittest.TestCase): self.assertRaises(ValueError, tuple, map(pack, (1, 2), (1, 2), 'abc', strict=True)) + # gh-140517: Testing refleaks with mortal objects. + t1 = (None, object()) + t2 = (object(), object()) + t3 = (object(),) + + self.assertRaises(ValueError, tuple, + map(pack, t1, 'a', strict=True)) + self.assertRaises(ValueError, tuple, + map(pack, t1, t2, 'a', strict=True)) + self.assertRaises(ValueError, tuple, + map(pack, t1, t2, t3, strict=True)) + self.assertRaises(ValueError, tuple, + map(pack, 'a', t1, strict=True)) + self.assertRaises(ValueError, tuple, + map(pack, 'a', t2, t3, strict=True)) + def test_map_strict_iterators(self): x = iter(range(5)) y = [0] diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 5e57b6d0eee..a55ec6cf3b8 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -549,6 +549,17 @@ class BaseBytesTest: self.assertEqual(three_bytes.hex(':', 2), 'b9:01ef') self.assertEqual(three_bytes.hex(':', 1), 'b9:01:ef') self.assertEqual(three_bytes.hex('*', -2), 'b901*ef') + self.assertEqual(three_bytes.hex(sep=':', bytes_per_sep=2), 'b9:01ef') + self.assertEqual(three_bytes.hex(sep='*', bytes_per_sep=-2), 'b901*ef') + for bytes_per_sep in 3, -3, 2**31-1, -(2**31-1): + with self.subTest(bytes_per_sep=bytes_per_sep): + self.assertEqual(three_bytes.hex(':', bytes_per_sep), 'b901ef') + for bytes_per_sep in 2**31, -2**31, 2**1000, -2**1000: + with self.subTest(bytes_per_sep=bytes_per_sep): + try: + self.assertEqual(three_bytes.hex(':', bytes_per_sep), 'b901ef') + except OverflowError: + pass value = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000' self.assertEqual(value.hex('.', 8), '7b7305000000776f.726c646902000000.730500000068656c.6c6f690100000030') @@ -802,6 +813,13 @@ class BaseBytesTest: with self.assertRaisesRegex(TypeError, msg): operator.mod(format_bytes, value) + def test_memory_leak_gh_140939(self): + # gh-140939: MemoryError is raised without leaking + _testcapi = import_helper.import_module('_testcapi') + with self.assertRaises(MemoryError): + b = self.type2test(b'%*b') + b % (_testcapi.PY_SSIZE_T_MAX, b'abc') + def test_imod(self): b = self.type2test(b'hello, %b!') orig = b @@ -1390,6 +1408,16 @@ class ByteArrayTest(BaseBytesTest, unittest.TestCase): b.append(ord('p')) self.assertEqual(b, b'p') + # Cleared object should be empty. + b = bytearray(b'abc') + b.clear() + self.assertEqual(b.__alloc__(), 0) + base_size = sys.getsizeof(bytearray()) + self.assertEqual(sys.getsizeof(b), base_size) + c = b.copy() + self.assertEqual(c.__alloc__(), 0) + self.assertEqual(sys.getsizeof(c), base_size) + def test_copy(self): b = bytearray(b'abc') bb = b.copy() @@ -1451,6 +1479,87 @@ class ByteArrayTest(BaseBytesTest, unittest.TestCase): self.assertRaises(MemoryError, bytearray().resize, sys.maxsize) self.assertRaises(MemoryError, bytearray(1000).resize, sys.maxsize) + def test_take_bytes(self): + ba = bytearray(b'ab') + self.assertEqual(ba.take_bytes(), b'ab') + self.assertEqual(len(ba), 0) + self.assertEqual(ba, bytearray(b'')) + self.assertEqual(ba.__alloc__(), 0) + base_size = sys.getsizeof(bytearray()) + self.assertEqual(sys.getsizeof(ba), base_size) + + # Positive and negative slicing. + ba = bytearray(b'abcdef') + self.assertEqual(ba.take_bytes(1), b'a') + self.assertEqual(ba, bytearray(b'bcdef')) + self.assertEqual(len(ba), 5) + self.assertEqual(ba.take_bytes(-5), b'') + self.assertEqual(ba, bytearray(b'bcdef')) + self.assertEqual(len(ba), 5) + self.assertEqual(ba.take_bytes(-3), b'bc') + self.assertEqual(ba, bytearray(b'def')) + self.assertEqual(len(ba), 3) + self.assertEqual(ba.take_bytes(3), b'def') + self.assertEqual(ba, bytearray(b'')) + self.assertEqual(len(ba), 0) + + # Take nothing from emptiness. + self.assertEqual(ba.take_bytes(0), b'') + self.assertEqual(ba.take_bytes(), b'') + self.assertEqual(ba.take_bytes(None), b'') + + # Out of bounds, bad take value. + self.assertRaises(IndexError, ba.take_bytes, -1) + self.assertRaises(TypeError, ba.take_bytes, 3.14) + ba = bytearray(b'abcdef') + self.assertRaises(IndexError, ba.take_bytes, 7) + + # Offset between physical and logical start (ob_bytes != ob_start). + ba = bytearray(b'abcde') + del ba[:2] + self.assertEqual(ba, bytearray(b'cde')) + self.assertEqual(ba.take_bytes(), b'cde') + + # Overallocation at end. + ba = bytearray(b'abcde') + del ba[-2:] + self.assertEqual(ba, bytearray(b'abc')) + self.assertEqual(ba.take_bytes(), b'abc') + ba = bytearray(b'abcde') + ba.resize(4) + self.assertEqual(ba.take_bytes(), b'abcd') + + # Take of a bytearray with references should fail. + ba = bytearray(b'abc') + with memoryview(ba) as mv: + self.assertRaises(BufferError, ba.take_bytes) + self.assertEqual(ba.take_bytes(), b'abc') + + @support.cpython_only # tests an implementation detail + def test_take_bytes_optimization(self): + # Validate optimization around taking lots of little chunks out of a + # much bigger buffer. Save work by only copying a little rather than + # moving a lot. + ba = bytearray(b'abcdef' + b'0' * 1000) + start_alloc = ba.__alloc__() + + # Take two bytes at a time, checking alloc doesn't change. + self.assertEqual(ba.take_bytes(2), b'ab') + self.assertEqual(ba.__alloc__(), start_alloc) + self.assertEqual(len(ba), 4 + 1000) + self.assertEqual(ba.take_bytes(2), b'cd') + self.assertEqual(ba.__alloc__(), start_alloc) + self.assertEqual(len(ba), 2 + 1000) + self.assertEqual(ba.take_bytes(2), b'ef') + self.assertEqual(ba.__alloc__(), start_alloc) + self.assertEqual(len(ba), 0 + 1000) + self.assertEqual(ba.__alloc__(), start_alloc) + + # Take over half, alloc shrinks to exact size. + self.assertEqual(ba.take_bytes(501), b'0' * 501) + self.assertEqual(len(ba), 499) + bytes_header_size = sys.getsizeof(b'') + self.assertEqual(ba.__alloc__(), 499 + bytes_header_size) def test_setitem(self): def setitem_as_mapping(b, i, val): @@ -1979,7 +2088,7 @@ class AssortedBytesTest(unittest.TestCase): self.assertEqual(f(bytearray([7, 8, 9, 10, 11, 12, 13])), r"bytearray(b'\x07\x08\t\n\x0b\x0c\r')") self.assertEqual(f(bytearray(b'"')), """bytearray(b'"')""") # '"' - self.assertEqual(f(bytearray(b"'")), r'''bytearray(b"\'")''') # "\'" + self.assertEqual(f(bytearray(b"'")), '''bytearray(b"'")''') # "'" self.assertEqual(f(bytearray(b"'\"")), r"""bytearray(b'\'"')""") # '\'"' self.assertEqual(f(bytearray(b"\"'\"")), r"""bytearray(b'"\'"')""") # '"\'"' self.assertEqual(f(bytearray(b'\'"\'')), r"""bytearray(b'\'"\'')""") # '\'"\'' @@ -2557,6 +2666,22 @@ class FreeThreadingTest(unittest.TestCase): c = a.zfill(0x400000) assert not c or c[-1] not in (0xdd, 0xcd) + def resize(b, a): # MODIFIES! + b.wait() + a.resize(10) + + def take_bytes(b, a): # MODIFIES! + b.wait() + c = a.take_bytes() + assert not c or c[0] == 48 # '0' + + def take_bytes_n(b, a): # MODIFIES! + b.wait() + try: + c = a.take_bytes(10) + assert c == b'0123456789' + except IndexError: pass + def check(funcs, a=None, *args): if a is None: a = bytearray(b'0' * 0x400000) @@ -2618,6 +2743,12 @@ class FreeThreadingTest(unittest.TestCase): check([clear] + [startswith] * 10) check([clear] + [strip] * 10) + check([clear] + [resize] * 10) + + check([clear] + [take_bytes] * 10) + check([take_bytes_n] * 10, bytearray(b'0123456789' * 0x400)) + check([take_bytes_n] * 10, bytearray(b'0123456789' * 5)) + check([clear] + [contains] * 10) check([clear] + [subscript] * 10) check([clear2] + [ass_subscript2] * 10, None, bytearray(b'0' * 0x400000)) diff --git a/Lib/test/test_c_locale_coercion.py b/Lib/test/test_c_locale_coercion.py index e4b0b8c451f..340bec3c71b 100644 --- a/Lib/test/test_c_locale_coercion.py +++ b/Lib/test/test_c_locale_coercion.py @@ -12,8 +12,10 @@ from test import support from test.support.script_helper import run_python_until_end -# Set the list of ways we expect to be able to ask for the "C" locale -EXPECTED_C_LOCALE_EQUIVALENTS = ["C", "invalid.ascii"] +# Set the list of ways we expect to be able to ask for the "C" locale. +# 'invalid.ascii' is an invalid LOCALE name and so should get turned in to the +# default locale, which is traditionally C. +EXPECTED_C_LOCALE_EQUIVALENTS = ["C", "POSIX", "invalid.ascii"] # Set our expectation for the default encoding used in the C locale # for the filesystem encoding and the standard streams @@ -21,6 +23,7 @@ EXPECTED_C_LOCALE_STREAM_ENCODING = "ascii" EXPECTED_C_LOCALE_FS_ENCODING = "ascii" # Set our expectation for the default locale used when none is specified +DEFAULT_LOCALE_IS_C = True EXPECT_COERCION_IN_DEFAULT_LOCALE = True TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"] @@ -30,12 +33,12 @@ if sys.platform == "android": # Android defaults to using UTF-8 for all system interfaces EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8" EXPECTED_C_LOCALE_FS_ENCODING = "utf-8" -elif sys.platform.startswith("linux"): - # Linux distros typically alias the POSIX locale directly to the C - # locale. - # TODO: Once https://bugs.python.org/issue30672 is addressed, we'll be - # able to check this case unconditionally - EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX") +elif support.linked_to_musl(): + # MUSL defaults to utf-8 unless the C locale is set explicitly. + EXPECTED_C_LOCALE_EQUIVALENTS = ["C"] + DEFAULT_LOCALE_IS_C = False + DEFAULT_ENCODING = 'utf-8' + EXPECT_COERCION_IN_DEFAULT_LOCALE = False elif sys.platform.startswith("aix"): # AIX uses iso8859-1 in the C locale, other *nix platforms use ASCII EXPECTED_C_LOCALE_STREAM_ENCODING = "iso8859-1" @@ -362,9 +365,14 @@ class LocaleCoercionTests(_LocaleHandlingTestCase): base_var_dict["PYTHONCOERCECLOCALE"] = coerce_c_locale # Check behaviour for the default locale + _fs_encoding = fs_encoding + _stream_encoding = stream_encoding + if not DEFAULT_LOCALE_IS_C and 'LC_ALL' not in extra_vars: + _fs_encoding = _stream_encoding = DEFAULT_ENCODING with self.subTest(default_locale=True, PYTHONCOERCECLOCALE=coerce_c_locale): - if EXPECT_COERCION_IN_DEFAULT_LOCALE: + if (EXPECT_COERCION_IN_DEFAULT_LOCALE + or (not DEFAULT_LOCALE_IS_C and 'LC_ALL' in extra_vars)): _expected_warnings = expected_warnings _coercion_expected = coercion_expected else: @@ -378,8 +386,8 @@ class LocaleCoercionTests(_LocaleHandlingTestCase): _expected_warnings == [CLI_COERCION_WARNING]): _expected_warnings = None self._check_child_encoding_details(base_var_dict, - fs_encoding, - stream_encoding, + _fs_encoding, + _stream_encoding, None, _expected_warnings, _coercion_expected) @@ -454,8 +462,9 @@ class LocaleCoercionTests(_LocaleHandlingTestCase): loc = locale.setlocale(locale.LC_CTYPE, "") except locale.Error as e: self.skipTest(str(e)) - if loc == "C": - self.skipTest("test requires LC_CTYPE locale different than C") + if loc in ("C", "POSIX"): + self.skipTest("test requires LC_CTYPE locale different " + "than C and POSIX") if loc in TARGET_LOCALES : self.skipTest("coerced LC_CTYPE locale: %s" % loc) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index c129b3e51ba..fe9a59d335b 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -113,18 +113,25 @@ Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su default_format = dict(year="year", month="month", encoding="ascii") +result_2004_css = """""" + result_2004_html = """\ - - - + + - - + + Calendar for 2004 +{css_styles} + - -
    2004
    +
    +
    2004
    @@ -133,7 +140,7 @@ result_2004_html = """\
    January
    MonTueWedThuFriSatSun
       1234
    19202122232425
    262728293031 
    -
    +
    @@ -142,7 +149,7 @@ result_2004_html = """\
    February
    MonTueWedThuFriSatSun
          1
    16171819202122
    23242526272829
    -
    +
    @@ -151,7 +158,7 @@ result_2004_html = """\
    March
    MonTueWedThuFriSatSun
    1234567
    22232425262728
    293031    
    -
    +
    @@ -160,7 +167,7 @@ result_2004_html = """\
    April
    MonTueWedThuFriSatSun
       1234
    19202122232425
    2627282930  
    -
    +
    @@ -170,7 +177,7 @@ result_2004_html = """\
    May
    MonTueWedThuFriSatSun
         12
    24252627282930
    31      
    -
    +
    @@ -179,7 +186,7 @@ result_2004_html = """\
    June
    MonTueWedThuFriSatSun
     123456
    21222324252627
    282930    
    -
    +
    @@ -188,7 +195,7 @@ result_2004_html = """\
    July
    MonTueWedThuFriSatSun
       1234
    19202122232425
    262728293031 
    -
    + - - + + - - - - - - + + + + + + - - + + - - - - - - - - - + + + + + + + + +
    @@ -198,7 +205,7 @@ result_2004_html = """\
    August
    MonTueWedThuFriSatSun
          1
    23242526272829
    3031     
    -
    + - - + + - - - - - - + + + + + + - - + + - - - - - - - - - + + + + + + + + +
    @@ -207,7 +214,7 @@ result_2004_html = """\
    September
    MonTueWedThuFriSatSun
      12345
    20212223242526
    27282930   
    -
    + - - + + - - - - - - + + + + + + - - + + - - - - - - - - - + + + + + + + + +
    @@ -216,7 +223,7 @@ result_2004_html = """\
    October
    MonTueWedThuFriSatSun
        123
    18192021222324
    25262728293031
    -
    + - - - - - + + + + +
    @@ -225,7 +232,7 @@ result_2004_html = """\
    November
    MonTueWedThuFriSatSun
    1234567
    22232425262728
    2930     
    -
    + - - - - - + + + + +
    @@ -238,6 +245,34 @@ result_2004_html = """\ """ +result_2009_6_html = """\ + + + + + +Calendar for 2009 + + + + +
    December
    MonTueWedThuFriSatSun
      12345
    + + + + + + + +
    June 2009
    MonTueWedThuFriSatSun
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
    + + +""" + result_2004_days = [ [[[0, 0, 0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], @@ -385,10 +420,12 @@ class OutputTestCase(unittest.TestCase): cal = calendar.HTMLCalendar() format_ = default_format.copy() format_["encoding"] = req or 'utf-8' + format_with_css = {**format_, "css_styles": result_2004_css} + formatted_html = result_2004_html.format(**format_with_css) output = cal.formatyearpage(2004, encoding=req) self.assertEqual( output, - result_2004_html.format(**format_).encode(res) + formatted_html.encode(res) ) def test_output(self): @@ -497,6 +534,13 @@ class OutputTestCase(unittest.TestCase): calendar.format(["1", "2", "3"], colwidth=3, spacing=1) self.assertEqual(out.getvalue().strip(), "1 2 3") + def test_format_html_year_with_month(self): + self.assertEqual( + calendar.HTMLCalendar().formatmonthpage(2009, 6).decode("ascii"), + result_2009_6_html + ) + + class CalendarTestCase(unittest.TestCase): def test_deprecation_warning(self): @@ -1093,7 +1137,6 @@ class CommandLineTestCase(unittest.TestCase): self.assertFailure('2004', '1', 'spam') self.assertFailure('2004', '1', '1') self.assertFailure('2004', '1', '1', 'spam') - self.assertFailure('-t', 'html', '2004', '1') def test_output_current_year(self): for run in self.runners: @@ -1183,7 +1226,7 @@ class CommandLineTestCase(unittest.TestCase): output = run('--type', 'text', '2004') self.assertEqual(output, conv(result_2004_text)) output = run('--type', 'html', '2004') - self.assertStartsWith(output, b'') self.assertIn(b'Calendar for 2004', output) def test_html_output_current_year(self): @@ -1196,15 +1239,16 @@ class CommandLineTestCase(unittest.TestCase): def test_html_output_year_encoding(self): for run in self.runners: output = run('-t', 'html', '--encoding', 'ascii', '2004') - self.assertEqual(output, result_2004_html.format(**default_format).encode('ascii')) + format_with_css = default_format.copy() + format_with_css["css_styles"] = result_2004_css + self.assertEqual(output, result_2004_html.format(**format_with_css).encode('ascii')) def test_html_output_year_css(self): self.assertFailure('-t', 'html', '-c') self.assertFailure('-t', 'html', '--css') for run in self.runners: output = run('-t', 'html', '--css', 'custom.css', '2004') - self.assertIn(b'', output) + self.assertIn(b'', output) class MiscTestCase(unittest.TestCase): @@ -1258,7 +1302,7 @@ class TestSubClassingCase(unittest.TestCase): def test_format_year(self): self.assertIn( - ('' % + ('
    ' % self.cal.cssclass_year), self.cal.formatyear(2017)) def test_format_year_head(self): diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 2c28f106ec7..f42526aee19 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -12,6 +12,10 @@ try: import _testlimitedcapi except ImportError: _testlimitedcapi = None +try: + import _testinternalcapi +except ImportError: + _testinternalcapi = None import struct import collections import itertools @@ -1037,6 +1041,23 @@ class TestErrorMessagesSuggestions(unittest.TestCase): @cpython_only class TestRecursion(unittest.TestCase): + def test_margin_is_sufficient(self): + + def get_sp(): + return _testinternalcapi.get_stack_pointer() + + this_sp = _testinternalcapi.get_stack_pointer() + lower_sp = _testcapi.pyobject_vectorcall(get_sp, (), ()) + if _testcapi._Py_STACK_GROWS_DOWN: + self.assertLess(lower_sp, this_sp) + safe_margin = this_sp - lower_sp + else: + self.assertGreater(lower_sp, this_sp) + safe_margin = lower_sp - this_sp + # Add an (arbitrary) extra 25% for safety + safe_margin = safe_margin * 5 / 4 + self.assertLess(safe_margin, _testinternalcapi.get_stack_margin()) + @skip_on_s390x @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack") @skip_if_sanitizer("requires deep stack", thread=True) diff --git a/Lib/test/test_capi/test_bytearray.py b/Lib/test/test_capi/test_bytearray.py index 52565ea34c6..cb7ad8b2225 100644 --- a/Lib/test/test_capi/test_bytearray.py +++ b/Lib/test/test_capi/test_bytearray.py @@ -1,3 +1,4 @@ +import sys import unittest from test.support import import_helper @@ -55,7 +56,9 @@ class CAPITest(unittest.TestCase): self.assertEqual(fromstringandsize(b'', 0), bytearray()) self.assertEqual(fromstringandsize(NULL, 0), bytearray()) self.assertEqual(len(fromstringandsize(NULL, 3)), 3) - self.assertRaises(MemoryError, fromstringandsize, NULL, PY_SSIZE_T_MAX) + self.assertRaises(OverflowError, fromstringandsize, NULL, PY_SSIZE_T_MAX) + self.assertRaises(OverflowError, fromstringandsize, NULL, + PY_SSIZE_T_MAX-sys.getsizeof(b'') + 1) self.assertRaises(SystemError, fromstringandsize, b'abc', -1) self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN) diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py index bc820bd68d9..410ebab729c 100644 --- a/Lib/test/test_capi/test_bytes.py +++ b/Lib/test/test_capi/test_bytes.py @@ -299,5 +299,95 @@ class CAPITest(unittest.TestCase): bytes_join(b'', NULL) +class BytesWriterTest(unittest.TestCase): + result_type = bytes + + def create_writer(self, alloc=0, string=b''): + return _testcapi.PyBytesWriter(alloc, string, 0) + + def test_create(self): + # Test PyBytesWriter_Create() + writer = self.create_writer() + self.assertEqual(writer.get_size(), 0) + self.assertEqual(writer.finish(), self.result_type(b'')) + + writer = self.create_writer(3, b'abc') + self.assertEqual(writer.get_size(), 3) + self.assertEqual(writer.finish(), self.result_type(b'abc')) + + writer = self.create_writer(10, b'abc') + self.assertEqual(writer.get_size(), 10) + self.assertEqual(writer.finish_with_size(3), self.result_type(b'abc')) + + def test_write_bytes(self): + # Test PyBytesWriter_WriteBytes() + writer = self.create_writer() + writer.write_bytes(b'Hello World!', -1) + self.assertEqual(writer.finish(), self.result_type(b'Hello World!')) + + writer = self.create_writer() + writer.write_bytes(b'Hello ', -1) + writer.write_bytes(b'World! ', 6) + self.assertEqual(writer.finish(), self.result_type(b'Hello World!')) + + def test_resize(self): + # Test PyBytesWriter_Resize() + writer = self.create_writer() + writer.resize(len(b'number=123456'), b'number=123456') + writer.resize(len(b'number=123456'), b'') + self.assertEqual(writer.get_size(), len(b'number=123456')) + self.assertEqual(writer.finish(), self.result_type(b'number=123456')) + + writer = self.create_writer() + writer.resize(0, b'') + writer.resize(len(b'number=123456'), b'number=123456') + self.assertEqual(writer.finish(), self.result_type(b'number=123456')) + + writer = self.create_writer() + writer.resize(len(b'number='), b'number=') + writer.resize(len(b'number=123456'), b'123456') + self.assertEqual(writer.finish(), self.result_type(b'number=123456')) + + writer = self.create_writer() + writer.resize(len(b'number='), b'number=') + writer.resize(len(b'number='), b'') + writer.resize(len(b'number=123456'), b'123456') + self.assertEqual(writer.finish(), self.result_type(b'number=123456')) + + writer = self.create_writer() + writer.resize(len(b'number'), b'number') + writer.resize(len(b'number='), b'=') + writer.resize(len(b'number=123'), b'123') + writer.resize(len(b'number=123456'), b'456') + self.assertEqual(writer.finish(), self.result_type(b'number=123456')) + + def test_format_i(self): + # Test PyBytesWriter_Format() + writer = self.create_writer() + writer.format_i(b'x=%i', 123456) + self.assertEqual(writer.finish(), self.result_type(b'x=123456')) + + writer = self.create_writer() + writer.format_i(b'x=%i, ', 123) + writer.format_i(b'y=%i', 456) + self.assertEqual(writer.finish(), self.result_type(b'x=123, y=456')) + + def test_example_abc(self): + self.assertEqual(_testcapi.byteswriter_abc(), b'abc') + + def test_example_resize(self): + self.assertEqual(_testcapi.byteswriter_resize(), b'Hello World') + + def test_example_highlevel(self): + self.assertEqual(_testcapi.byteswriter_highlevel(), b'Hello World!') + + +class ByteArrayWriterTest(BytesWriterTest): + result_type = bytearray + + def create_writer(self, alloc=0, string=b''): + return _testcapi.PyBytesWriter(alloc, string, 1) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_capi/test_codecs.py b/Lib/test/test_capi/test_codecs.py index a0355c7a388..1a3f476ed0f 100644 --- a/Lib/test/test_capi/test_codecs.py +++ b/Lib/test/test_capi/test_codecs.py @@ -630,7 +630,6 @@ class CAPICodecs(unittest.TestCase): for name in [ encoding_name, encoding_name.upper(), - encoding_name.replace('_', '-'), ]: with self.subTest(name): self.assertTrue(_testcapi.codec_known_encoding(name)) diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py index f7efe0d0254..df7017e6436 100644 --- a/Lib/test/test_capi/test_float.py +++ b/Lib/test/test_capi/test_float.py @@ -1,5 +1,6 @@ import math import random +import platform import sys import unittest import warnings @@ -28,6 +29,23 @@ INF = float("inf") NAN = float("nan") +def make_nan(size, sign, quiet, payload=None): + if size == 8: + payload_mask = 0x7ffffffffffff + i = (sign << 63) + (0x7ff << 52) + (quiet << 51) + elif size == 4: + payload_mask = 0x3fffff + i = (sign << 31) + (0xff << 23) + (quiet << 22) + elif size == 2: + payload_mask = 0x1ff + i = (sign << 15) + (0x1f << 10) + (quiet << 9) + else: + raise ValueError("size must be either 2, 4, or 8") + if payload is None: + payload = random.randint(not quiet, payload_mask) + return i + payload + + class CAPIFloatTest(unittest.TestCase): def test_check(self): # Test PyFloat_Check() @@ -197,16 +215,11 @@ class CAPIFloatTest(unittest.TestCase): # PyFloat_Pack/Unpack*() API. See also gh-130317 and # e.g. https://developercommunity.visualstudio.com/t/155064 signaling = 0 - quiet = int(not signaling) - if size == 8: - payload = random.randint(signaling, 0x7ffffffffffff) - i = (sign << 63) + (0x7ff << 52) + (quiet << 51) + payload - elif size == 4: - payload = random.randint(signaling, 0x3fffff) - i = (sign << 31) + (0xff << 23) + (quiet << 22) + payload - elif size == 2: - payload = random.randint(signaling, 0x1ff) - i = (sign << 15) + (0x1f << 10) + (quiet << 9) + payload + if platform.machine().startswith('parisc'): + # HP PA RISC uses 0 for quiet, see: + # https://en.wikipedia.org/wiki/NaN#Encoding + signaling = 1 + i = make_nan(size, sign, not signaling) data = bytes.fromhex(f'{i:x}') for endian in (BIG_ENDIAN, LITTLE_ENDIAN): with self.subTest(data=data, size=size, endian=endian): @@ -216,6 +229,32 @@ class CAPIFloatTest(unittest.TestCase): self.assertTrue(math.isnan(value)) self.assertEqual(data1, data2) + @unittest.skipUnless(HAVE_IEEE_754, "requires IEEE 754") + @unittest.skipUnless(sys.maxsize != 2147483647, "requires 64-bit mode") + def test_pack_unpack_nans_for_different_formats(self): + pack = _testcapi.float_pack + unpack = _testcapi.float_unpack + + for endian in (BIG_ENDIAN, LITTLE_ENDIAN): + with self.subTest(endian=endian): + byteorder = "big" if endian == BIG_ENDIAN else "little" + + # Convert sNaN to qNaN, if payload got truncated + data = make_nan(8, 0, False, 0x80001).to_bytes(8, byteorder) + snan_low = unpack(data, endian) + qnan4 = make_nan(4, 0, True, 0).to_bytes(4, byteorder) + qnan2 = make_nan(2, 0, True, 0).to_bytes(2, byteorder) + self.assertEqual(pack(4, snan_low, endian), qnan4) + self.assertEqual(pack(2, snan_low, endian), qnan2) + + # Preserve NaN type, if payload not truncated + data = make_nan(8, 0, False, 0x80000000001).to_bytes(8, byteorder) + snan_high = unpack(data, endian) + snan4 = make_nan(4, 0, False, 16384).to_bytes(4, byteorder) + snan2 = make_nan(2, 0, False, 2).to_bytes(2, byteorder) + self.assertEqual(pack(4, snan_high, endian), snan4) + self.assertEqual(pack(2, snan_high, endian), snan2) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_capi/test_immortal.py b/Lib/test/test_capi/test_immortal.py index 660e8a0e789..6b882d65a42 100644 --- a/Lib/test/test_capi/test_immortal.py +++ b/Lib/test/test_capi/test_immortal.py @@ -25,14 +25,14 @@ class TestUnstableCAPI(unittest.TestCase): class TestInternalCAPI(unittest.TestCase): def test_immortal_builtins(self): - for obj in range(-5, 256): + for obj in range(-5, 1025): self.assertTrue(_testinternalcapi.is_static_immortal(obj)) self.assertTrue(_testinternalcapi.is_static_immortal(None)) self.assertTrue(_testinternalcapi.is_static_immortal(False)) self.assertTrue(_testinternalcapi.is_static_immortal(True)) self.assertTrue(_testinternalcapi.is_static_immortal(...)) self.assertTrue(_testinternalcapi.is_static_immortal(())) - for obj in range(300, 400): + for obj in range(1025, 1125): self.assertFalse(_testinternalcapi.is_static_immortal(obj)) for obj in ([], {}, set()): self.assertFalse(_testinternalcapi.is_static_immortal(obj)) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index ef950f5df04..3997acbdf84 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -22,6 +22,7 @@ import operator from test import support from test.support import MISSING_C_DOCSTRINGS from test.support import import_helper +from test.support import script_helper from test.support import threading_helper from test.support import warnings_helper from test.support import requires_limited_api @@ -306,7 +307,7 @@ class CAPITest(unittest.TestCase): CURRENT_THREAD_REGEX + r' File .*, line 6 in \n' r'\n' - r'Extension modules: _testcapi \(total: 1\)\n') + r'Extension modules: ') else: # Python built with NDEBUG macro defined: # test _Py_CheckFunctionResult() instead. @@ -1641,6 +1642,36 @@ class TestPendingCalls(unittest.TestCase): self.assertEqual(actual, int(interpid)) + @threading_helper.requires_working_threading() + def test_pending_call_creates_thread(self): + source = """ + import _testinternalcapi + import threading + import time + + + def output(): + print(24) + time.sleep(1) + print(42) + + + def callback(): + threading.Thread(target=output).start() + + + def create_pending_call(): + time.sleep(1) + _testinternalcapi.simple_pending_call(callback) + + + threading.Thread(target=create_pending_call).start() + """ + return_code, stdout, stderr = script_helper.assert_python_ok('-c', textwrap.dedent(source)) + self.assertEqual(return_code, 0) + self.assertEqual(stdout, f"24{os.linesep}42{os.linesep}".encode("utf-8")) + self.assertEqual(stderr, b"") + class SubinterpreterTest(unittest.TestCase): @@ -1949,6 +1980,43 @@ class SubinterpreterTest(unittest.TestCase): subinterp_attr_id = os.read(r, 100) self.assertEqual(main_attr_id, subinterp_attr_id) + @threading_helper.requires_working_threading() + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + @requires_subinterpreters + def test_pending_call_creates_thread_subinterpreter(self): + interpreters = import_helper.import_module("concurrent.interpreters") + r, w = os.pipe() + source = f"""if True: + import _testinternalcapi + import threading + import time + import os + + + def output(): + time.sleep(1) + os.write({w}, b"x") + os.close({w}) + + + def callback(): + threading.Thread(target=output).start() + + + def create_pending_call(): + time.sleep(1) + _testinternalcapi.simple_pending_call(callback) + + + threading.Thread(target=create_pending_call).start() + """ + interp = interpreters.create() + interp.exec(source) + interp.close() + data = os.read(r, 1) + self.assertEqual(data, b"x") + os.close(r) + @requires_subinterpreters class InterpreterConfigTests(unittest.TestCase): diff --git a/Lib/test/test_capi/test_modsupport.py b/Lib/test/test_capi/test_modsupport.py new file mode 100644 index 00000000000..1520489f843 --- /dev/null +++ b/Lib/test/test_capi/test_modsupport.py @@ -0,0 +1,154 @@ +import sys +import unittest +import sysconfig + +from test.support import subTests +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') + + +class Test_ABIInfo_Check(unittest.TestCase): + @subTests('modname', (None, 'test_mod')) + def test_zero(self, modname): + _testcapi.pyabiinfo_check(modname, 0, 0, 0, 0, 0) + _testcapi.pyabiinfo_check(modname, 1, 0, 0, 0, 0) + + def test_large_major_version(self): + with self.assertRaisesRegex(ImportError, + '^PyABIInfo version too high$'): + _testcapi.pyabiinfo_check(None, 2, 0, 0, 0, 0) + with self.assertRaisesRegex(ImportError, + '^test_mod: PyABIInfo version too high$'): + _testcapi.pyabiinfo_check("test_mod", 2, 0, 0, 0, 0) + + @subTests('modname', (None, 'test_mod')) + def test_large_minor_version(self, modname): + _testcapi.pyabiinfo_check(modname, 1, 2, 0, 0, 0) + + @subTests('modname', (None, 'test_mod')) + @subTests('major', (0, 1)) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + def test_positive_regular(self, modname, major, minor, build): + ver = sys.hexversion + truncated = ver & 0xffff0000 + filled = truncated | 0x12b8 + maxed = truncated | 0xffff + for abi_version in (0, ver, truncated, filled, maxed): + with self.subTest(abi_version=abi_version): + _testcapi.pyabiinfo_check(modname, major, minor, 0, + build, abi_version) + + @subTests('modname', (None, 'test_mod')) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + @subTests('offset', (+0x00010000, -0x00010000)) + def test_negative_regular(self, modname, minor, build, offset): + ver = sys.hexversion + offset + truncated = ver & 0xffff0000 + filled = truncated | 0x12b8 + maxed = truncated | 0xffff + for abi_version in (ver, truncated, filled, maxed): + with self.subTest(abi_version=abi_version): + with self.assertRaisesRegex( + ImportError, + r'incompatible ABI version \(3\.\d+\)$'): + _testcapi.pyabiinfo_check(modname, 1, minor, 0, + build, + abi_version) + + @subTests('modname', (None, 'test_mod')) + @subTests('major', (0, 1)) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + @subTests('abi_version', ( + 0, + 0x03020000, + sys.hexversion, + sys.hexversion & 0xffff0000, + sys.hexversion - 0x00010000, + )) + def test_positive_stable(self, modname, major, minor, build, abi_version): + _testcapi.pyabiinfo_check(modname, major, minor, + _testcapi.PyABIInfo_STABLE, + build, + abi_version) + + @subTests('modname', (None, 'test_mod')) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + @subTests('abi_version_and_msg', ( + (1, 'invalid'), + (3, 'invalid'), + (0x0301ffff, 'invalid'), + ((sys.hexversion & 0xffff0000) + 0x00010000, 'incompatible future'), + (sys.hexversion + 0x00010000, 'incompatible future'), + (0x04000000, 'incompatible future'), + )) + def test_negative_stable(self, modname, minor, build, abi_version_and_msg): + abi_version, msg = abi_version_and_msg + with self.assertRaisesRegex( + ImportError, + rf'{msg} stable ABI version \(\d+\.\d+\)$'): + _testcapi.pyabiinfo_check(modname, 1, minor, + _testcapi.PyABIInfo_STABLE, + build, + abi_version) + + @subTests('modname', (None, 'test_mod')) + @subTests('major', (0, 1)) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + @subTests('abi_version', (0, sys.hexversion)) + def test_positive_internal(self, modname, major, minor, build, abi_version): + _testcapi.pyabiinfo_check(modname, major, minor, + _testcapi.PyABIInfo_INTERNAL, + build, + abi_version) + + @subTests('modname', (None, 'test_mod')) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + @subTests('abi_version', ( + sys.hexversion - 0x00010000, + sys.hexversion - 1, + sys.hexversion + 1, + sys.hexversion + 0x00010000, + )) + def test_negative_internal(self, modname, minor, build, abi_version): + with self.assertRaisesRegex( + ImportError, + r'incompatible internal ABI \(0x[\da-f]+ != 0x[\da-f]+\)$'): + _testcapi.pyabiinfo_check(modname, 1, minor, + _testcapi.PyABIInfo_INTERNAL, + build, + abi_version) + + @subTests('modname', (None, 'test_mod')) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + @subTests('ft_flag', ( + 0, + (_testcapi.PyABIInfo_FREETHREADED + if sysconfig.get_config_var("Py_GIL_DISABLED") + else _testcapi.PyABIInfo_GIL), + _testcapi.PyABIInfo_FREETHREADING_AGNOSTIC, + )) + def test_positive_freethreading(self, modname, minor, build, ft_flag): + self.assertEqual(ft_flag & _testcapi.PyABIInfo_FREETHREADING_AGNOSTIC, + ft_flag) + _testcapi.pyabiinfo_check(modname, 1, minor, ft_flag, build, 0) + + @subTests('modname', (None, 'test_mod')) + @subTests('minor', (0, 1, 9)) + @subTests('build', (0, sys.hexversion)) + def test_negative_freethreading(self, modname, minor, build): + if sysconfig.get_config_var("Py_GIL_DISABLED"): + ft_flag = _testcapi.PyABIInfo_GIL + msg = "incompatible with free-threaded CPython" + else: + ft_flag = _testcapi.PyABIInfo_FREETHREADED + msg = "only compatible with free-threaded CPython" + with self.assertRaisesRegex(ImportError, msg): + _testcapi.pyabiinfo_check(modname, 1, minor, ft_flag, build, 0) diff --git a/Lib/test/test_capi/test_module.py b/Lib/test/test_capi/test_module.py new file mode 100644 index 00000000000..823e2ab6b2e --- /dev/null +++ b/Lib/test/test_capi/test_module.py @@ -0,0 +1,186 @@ +# The C functions used by this module are in: +# Modules/_testcapi/module.c + +import unittest +import types +from test.support import import_helper, subTests, requires_gil_enabled + +# Skip this test if the _testcapi module isn't available. +_testcapi = import_helper.import_module('_testcapi') + + +class FakeSpec: + name = 'testmod' + +DEF_SLOTS = ( + 'Py_mod_name', 'Py_mod_doc', 'Py_mod_state_size', 'Py_mod_methods', + 'Py_mod_state_traverse', 'Py_mod_state_clear', 'Py_mod_state_free', + 'Py_mod_token', +) + +def def_and_token(mod): + return ( + _testcapi.pymodule_get_def(mod), + _testcapi.pymodule_get_token(mod), + ) + +class TestModFromSlotsAndSpec(unittest.TestCase): + @requires_gil_enabled("empty slots re-enable GIL") + def test_empty(self): + mod = _testcapi.module_from_slots_empty(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + size = _testcapi.pymodule_get_state_size(mod) + self.assertEqual(size, 0) + + def test_null_slots(self): + with self.assertRaises(SystemError): + _testcapi.module_from_slots_null(FakeSpec()) + + def test_none_spec(self): + # The spec currently must contain a name + with self.assertRaises(AttributeError): + _testcapi.module_from_slots_empty(None) + with self.assertRaises(AttributeError): + _testcapi.module_from_slots_name(None) + + def test_name(self): + # Py_mod_name (and PyModuleDef.m_name) are currently ignored when + # spec is given. + # We still test that it's accepted. + mod = _testcapi.module_from_slots_name(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, None) + + def test_doc(self): + mod = _testcapi.module_from_slots_doc(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, 'the docstring') + + def test_size(self): + mod = _testcapi.module_from_slots_size(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, None) + size = _testcapi.pymodule_get_state_size(mod) + self.assertEqual(size, 123) + + def test_methods(self): + mod = _testcapi.module_from_slots_methods(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, None) + self.assertEqual(mod.a_method(456), (mod, 456)) + + def test_gc(self): + mod = _testcapi.module_from_slots_gc(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, None) + + # Check that the requested hook functions (which module_from_slots_gc + # stores as attributes) match what's in the module (as retrieved by + # _testinternalcapi.module_get_gc_hooks) + _testinternalcapi = import_helper.import_module('_testinternalcapi') + traverse, clear, free = _testinternalcapi.module_get_gc_hooks(mod) + self.assertEqual(traverse, mod.traverse) + self.assertEqual(clear, mod.clear) + self.assertEqual(free, mod.free) + + def test_token(self): + mod = _testcapi.module_from_slots_token(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, _testcapi.module_test_token)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, None) + + def test_exec(self): + mod = _testcapi.module_from_slots_exec(FakeSpec()) + self.assertIsInstance(mod, types.ModuleType) + self.assertEqual(def_and_token(mod), (0, 0)) + self.assertEqual(mod.__name__, 'testmod') + self.assertEqual(mod.__doc__, None) + self.assertEqual(mod.a_number, 456) + + def test_create(self): + spec = FakeSpec() + spec._gimme_this = "not a module object" + mod = _testcapi.module_from_slots_create(spec) + self.assertIsInstance(mod, str) + self.assertEqual(mod, "not a module object") + with self.assertRaises(TypeError): + _testcapi.pymodule_get_def(mod), + with self.assertRaises(TypeError): + _testcapi.pymodule_get_token(mod) + + def test_def_slot(self): + """Slots that replace PyModuleDef fields can't be used with PyModuleDef + """ + for name in DEF_SLOTS: + with self.subTest(name): + spec = FakeSpec() + spec._test_slot_id = getattr(_testcapi, name) + with self.assertRaises(SystemError) as cm: + _testcapi.module_from_def_slot(spec) + self.assertIn(name, str(cm.exception)) + self.assertIn("PyModuleDef", str(cm.exception)) + + def test_repeated_def_slot(self): + """Slots that replace PyModuleDef fields can't be repeated""" + for name in (*DEF_SLOTS, 'Py_mod_exec'): + with self.subTest(name): + spec = FakeSpec() + spec._test_slot_id = getattr(_testcapi, name) + with self.assertRaises(SystemError) as cm: + _testcapi.module_from_slots_repeat_slot(spec) + self.assertIn(name, str(cm.exception)) + self.assertIn("more than one", str(cm.exception)) + + def test_null_def_slot(self): + """Slots that replace PyModuleDef fields can't be NULL""" + for name in (*DEF_SLOTS, 'Py_mod_exec'): + with self.subTest(name): + spec = FakeSpec() + spec._test_slot_id = getattr(_testcapi, name) + with self.assertRaises(SystemError) as cm: + _testcapi.module_from_slots_null_slot(spec) + self.assertIn(name, str(cm.exception)) + self.assertIn("NULL", str(cm.exception)) + + def test_def_multiple_exec(self): + """PyModule_Exec runs all exec slots of PyModuleDef-defined module""" + mod = _testcapi.module_from_def_multiple_exec(FakeSpec()) + self.assertFalse(hasattr(mod, 'a_number')) + _testcapi.pymodule_exec(mod) + self.assertEqual(mod.a_number, 456) + self.assertEqual(mod.another_number, 789) + _testcapi.pymodule_exec(mod) + self.assertEqual(mod.a_number, 456) + self.assertEqual(mod.another_number, -789) + def_ptr, token = def_and_token(mod) + self.assertEqual(def_ptr, token) + + def test_def_token(self): + """In PyModuleDef-defined modules, the def is the token""" + mod = _testcapi.module_from_def_multiple_exec(FakeSpec()) + def_ptr, token = def_and_token(mod) + self.assertEqual(def_ptr, token) + self.assertGreater(def_ptr, 0) + + @subTests('name, expected_size', [ + (__name__, 0), # Python module + ('_testsinglephase', -1), # single-phase init + ('sys', -1), + ]) + def test_get_state_size(self, name, expected_size): + mod = import_helper.import_module(name) + size = _testcapi.pymodule_get_state_size(mod) + self.assertEqual(size, expected_size) diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py index d4056727d07..67572ab1ba2 100644 --- a/Lib/test/test_capi/test_object.py +++ b/Lib/test/test_capi/test_object.py @@ -1,4 +1,5 @@ import enum +import os import sys import textwrap import unittest @@ -13,6 +14,9 @@ _testlimitedcapi = import_helper.import_module('_testlimitedcapi') _testcapi = import_helper.import_module('_testcapi') _testinternalcapi = import_helper.import_module('_testinternalcapi') +NULL = None +STDERR_FD = 2 + class Constant(enum.IntEnum): Py_CONSTANT_NONE = 0 @@ -247,5 +251,60 @@ class CAPITest(unittest.TestCase): func(object()) + # Test that a newly created object in C is not considered + # a uniquely referenced temporary, because it's not on the stack. + # gh-142586: do the test in a loop over a list to test for handling + # tagged ints on the stack. + for i in [0, 1, 2]: + self.assertFalse(_testcapi.pyobject_is_unique_temporary_new_object()) + + def pyobject_dump(self, obj, release_gil=False): + pyobject_dump = _testcapi.pyobject_dump + + try: + old_stderr = os.dup(STDERR_FD) + except OSError as exc: + # os.dup(STDERR_FD) is not supported on WASI + self.skipTest(f"os.dup() failed with {exc!r}") + + filename = os_helper.TESTFN + try: + try: + with open(filename, "wb") as fp: + fd = fp.fileno() + os.dup2(fd, STDERR_FD) + pyobject_dump(obj, release_gil) + finally: + os.dup2(old_stderr, STDERR_FD) + os.close(old_stderr) + + with open(filename) as fp: + return fp.read().rstrip() + finally: + os_helper.unlink(filename) + + def test_pyobject_dump(self): + # test string object + str_obj = 'test string' + output = self.pyobject_dump(str_obj) + hex_regex = r'(0x)?[0-9a-fA-F]+' + regex = ( + fr"object address : {hex_regex}\n" + r"object refcount : [0-9]+\n" + fr"object type : {hex_regex}\n" + r"object type name: str\n" + r"object repr : 'test string'" + ) + self.assertRegex(output, regex) + + # release the GIL + output = self.pyobject_dump(str_obj, release_gil=True) + self.assertRegex(output, regex) + + # test NULL object + output = self.pyobject_dump(NULL) + self.assertRegex(output, r'') + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index c796b0dd4b5..6f1b115b312 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5,6 +5,7 @@ import textwrap import unittest import gc import os +import types import _opcode @@ -14,8 +15,10 @@ from test.support import (script_helper, requires_specialization, _testinternalcapi = import_helper.import_module("_testinternalcapi") -from _testinternalcapi import TIER2_THRESHOLD +from _testinternalcapi import _PY_NSMALLPOSINTS, TIER2_THRESHOLD +#For test of issue 136154 +GLOBAL_136154 = 42 @contextlib.contextmanager def clear_executors(func): @@ -37,6 +40,17 @@ def get_first_executor(func): pass return None +def get_all_executors(func): + code = func.__code__ + co_code = code.co_code + executors = [] + for i in range(0, len(co_code), 2): + try: + executors.append(_opcode.get_executor(code, i)) + except ValueError: + pass + return executors + def iter_opnames(ex): for item in ex: @@ -419,32 +433,6 @@ class TestUops(unittest.TestCase): uops = get_opnames(ex) self.assertIn("_FOR_ITER_TIER_TWO", uops) - def test_confidence_score(self): - def testfunc(n): - bits = 0 - for i in range(n): - if i & 0x01: - bits += 1 - if i & 0x02: - bits += 1 - if i&0x04: - bits += 1 - if i&0x08: - bits += 1 - if i&0x10: - bits += 1 - return bits - - x = testfunc(TIER2_THRESHOLD * 2) - - self.assertEqual(x, TIER2_THRESHOLD * 5) - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - ops = list(iter_opnames(ex)) - #Since branch is 50/50 the trace could go either way. - count = ops.count("_GUARD_IS_TRUE_POP") + ops.count("_GUARD_IS_FALSE_POP") - self.assertLessEqual(count, 2) - @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") @@ -678,7 +666,7 @@ class TestUopsOptimization(unittest.TestCase): self.assertLessEqual(len(guard_nos_float_count), 1) # TODO gh-115506: this assertion may change after propagating constants. # We'll also need to verify that propagation actually occurs. - self.assertIn("_BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS", uops) + self.assertIn("_POP_TOP_NOP", uops) def test_float_subtract_constant_propagation(self): def testfunc(n): @@ -700,7 +688,7 @@ class TestUopsOptimization(unittest.TestCase): self.assertLessEqual(len(guard_nos_float_count), 1) # TODO gh-115506: this assertion may change after propagating constants. # We'll also need to verify that propagation actually occurs. - self.assertIn("_BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS", uops) + self.assertIn("_POP_TOP_NOP", uops) def test_float_multiply_constant_propagation(self): def testfunc(n): @@ -722,7 +710,7 @@ class TestUopsOptimization(unittest.TestCase): self.assertLessEqual(len(guard_nos_float_count), 1) # TODO gh-115506: this assertion may change after propagating constants. # We'll also need to verify that propagation actually occurs. - self.assertIn("_BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS", uops) + self.assertIn("_POP_TOP_NOP", uops) def test_add_unicode_propagation(self): def testfunc(n): @@ -844,38 +832,7 @@ class TestUopsOptimization(unittest.TestCase): self.assertLessEqual(len(guard_nos_unicode_count), 1) self.assertIn("_COMPARE_OP_STR", uops) - def test_type_inconsistency(self): - ns = {} - src = textwrap.dedent(""" - def testfunc(n): - for i in range(n): - x = _test_global + _test_global - """) - exec(src, ns, ns) - testfunc = ns['testfunc'] - ns['_test_global'] = 0 - _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) - self.assertIsNone(ex) - ns['_test_global'] = 1 - _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) - self.assertIsNotNone(ex) - uops = get_opnames(ex) - self.assertNotIn("_GUARD_TOS_INT", uops) - self.assertNotIn("_GUARD_NOS_INT", uops) - self.assertNotIn("_BINARY_OP_ADD_INT", uops) - self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops) - # Try again, but between the runs, set the global to a float. - # This should result in no executor the second time. - ns = {} - exec(src, ns, ns) - testfunc = ns['testfunc'] - ns['_test_global'] = 0 - _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) - self.assertIsNone(ex) - ns['_test_global'] = 3.14 - _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) - self.assertIsNone(ex) - + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_sequential(self): def dummy12(x): return x - 1 @@ -904,6 +861,7 @@ class TestUopsOptimization(unittest.TestCase): largest_stack = _testinternalcapi.get_co_framesize(dummy13.__code__) self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_nested(self): def dummy12(x): return x + 3 @@ -934,6 +892,7 @@ class TestUopsOptimization(unittest.TestCase): ) self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_several_calls(self): def dummy12(x): return x + 3 @@ -969,6 +928,7 @@ class TestUopsOptimization(unittest.TestCase): ) self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_several_calls_different_order(self): # same as `several_calls` but with top-level calls reversed def dummy12(x): @@ -1005,6 +965,7 @@ class TestUopsOptimization(unittest.TestCase): ) self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_complex(self): def dummy0(x): return x @@ -1054,6 +1015,7 @@ class TestUopsOptimization(unittest.TestCase): ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands ) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_large_framesize(self): # Create a function with a large framesize. This ensures _CHECK_STACK_SPACE is # actually doing its job. Note that the resulting trace hits @@ -1115,6 +1077,7 @@ class TestUopsOptimization(unittest.TestCase): ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands ) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_recursion(self): def dummy15(x): while x > 0: @@ -1463,8 +1426,9 @@ class TestUopsOptimization(unittest.TestCase): self.assertEqual(res, 3) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertNotIn("_BINARY_OP_ADD_INT", uops) - self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops) + # TODO (gh-142764): Re-enable after we get back automatic constant propagation. + # self.assertNotIn("_BINARY_OP_ADD_INT", uops) + # self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_GUARD_NOS_INT", uops) self.assertNotIn("_GUARD_TOS_INT", uops) @@ -1614,6 +1578,75 @@ class TestUopsOptimization(unittest.TestCase): # But all of the appends we care about are still there: self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG")) + def test_unary_negative_pop_top_load_const_inline_borrow(self): + def testfunc(n): + x = 0 + for i in range(n): + a = 1 + result = -a + if result < 0: + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_UNARY_NEGATIVE", uops) + self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) + + def test_unary_not_pop_top_load_const_inline_borrow(self): + def testfunc(n): + x = 0 + for i in range(n): + a = 42 + result = not a + if result: + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 0) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_UNARY_NOT", uops) + self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) + + def test_unary_invert_pop_top_load_const_inline_borrow(self): + def testfunc(n): + x = 0 + for i in range(n): + a = 0 + result = ~a + if result < 0: + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_UNARY_INVERT", uops) + self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) + + def test_compare_op_pop_two_load_const_inline_borrow(self): + def testfunc(n): + x = 0 + for _ in range(n): + a = 10 + b = 10.0 + if a == b: + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_COMPARE_OP", uops) + self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops) + + @unittest.skip("TODO (gh-142764): Re-enable after we get back automatic constant propagation.") def test_compare_op_int_pop_two_load_const_inline_borrow(self): def testfunc(n): x = 0 @@ -1665,6 +1698,23 @@ class TestUopsOptimization(unittest.TestCase): self.assertNotIn("_COMPARE_OP_FLOAT", uops) self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops) + def test_contains_op_pop_two_load_const_inline_borrow(self): + def testfunc(n): + x = 0 + for _ in range(n): + a = "foo" + s = "foo bar baz" + if a in s: + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_CONTAINS_OP", uops) + self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops) + def test_to_bool_bool_contains_op_set(self): """ Test that _TO_BOOL_BOOL is removed from code like: @@ -1877,6 +1927,21 @@ class TestUopsOptimization(unittest.TestCase): uops = get_opnames(ex) self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops) + def test_call_tuple_1_pop_top(self): + def testfunc(n): + x = 0 + for _ in range(n): + t = tuple(()) + x += len(t) == 0 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_CALL_TUPLE_1", uops) + self.assertIn("_POP_TOP_NOP", uops) + def test_call_str_1(self): def testfunc(n): x = 0 @@ -1894,6 +1959,20 @@ class TestUopsOptimization(unittest.TestCase): self.assertNotIn("_GUARD_NOS_NULL", uops) self.assertNotIn("_GUARD_CALLABLE_STR_1", uops) + def test_call_str_1_pop_top(self): + def testfunc(n): + x = 0 + for _ in range(n): + t = str("") + x += 1 if len(t) == 0 else 0 + return x + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_CALL_STR_1", uops) + self.assertIn("_POP_TOP_NOP", uops) + def test_call_str_1_result_is_str(self): def testfunc(n): x = 0 @@ -1987,8 +2066,9 @@ class TestUopsOptimization(unittest.TestCase): uops = get_opnames(ex) self.assertIn("_CALL_TUPLE_1", uops) self.assertIn("_UNPACK_SEQUENCE_TWO_TUPLE", uops) - self.assertNotIn("_COMPARE_OP_INT", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + # TODO (gh-142764): Re-enable after we get back automatic constant propagation. + # self.assertNotIn("_COMPARE_OP_INT", uops) + # self.assertNotIn("_GUARD_IS_TRUE_POP", uops) def test_call_len(self): def testfunc(n): @@ -2003,8 +2083,13 @@ class TestUopsOptimization(unittest.TestCase): self.assertIn("_CALL_LEN", uops) self.assertNotIn("_GUARD_NOS_INT", uops) self.assertNotIn("_GUARD_TOS_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) def test_call_len_known_length_small_int(self): + # Make sure that len(t) is optimized for a tuple of length 5. + # See https://github.com/python/cpython/issues/139393. + self.assertGreater(_PY_NSMALLPOSINTS, 5) + def testfunc(n): x = 0 for _ in range(n): @@ -2025,13 +2110,17 @@ class TestUopsOptimization(unittest.TestCase): self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) def test_call_len_known_length(self): + # Make sure that len(t) is not optimized for a tuple of length 2048. + # See https://github.com/python/cpython/issues/139393. + self.assertLess(_PY_NSMALLPOSINTS, 2048) + def testfunc(n): class C: - t = tuple(range(300)) + t = tuple(range(2048)) x = 0 for _ in range(n): - if len(C.t) == 300: # comparison + guard removed + if len(C.t) == 2048: # comparison + guard removed x += 1 return x @@ -2044,8 +2133,24 @@ class TestUopsOptimization(unittest.TestCase): # length allows us to optimize more code, such as conditionals # in this case self.assertIn("_CALL_LEN", uops) - self.assertNotIn("_COMPARE_OP_INT", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + # TODO (gh-142764): Re-enable after we get back automatic constant propagation. + # self.assertNotIn("_COMPARE_OP_INT", uops) + # self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + + def test_call_builtin_o(self): + def testfunc(n): + x = 0 + for _ in range(n): + y = abs(1) + x += y + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_CALL_BUILTIN_O", uops) + self.assertIn("_POP_TOP", uops) def test_get_len_with_const_tuple(self): def testfunc(n): @@ -2105,8 +2210,9 @@ class TestUopsOptimization(unittest.TestCase): self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertIn("_BINARY_OP_SUBSCR_TUPLE_INT", uops) - self.assertNotIn("_COMPARE_OP_INT", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + # TODO (gh-142764): Re-enable after we get back automatic constant propagation. + # self.assertNotIn("_COMPARE_OP_INT", uops) + # self.assertNotIn("_GUARD_IS_TRUE_POP", uops) def test_call_isinstance_guards_removed(self): def testfunc(n): @@ -2144,6 +2250,18 @@ class TestUopsOptimization(unittest.TestCase): self.assertIn("_GUARD_NOS_LIST", uops) self.assertIn("_GUARD_CALLABLE_LIST_APPEND", uops) + def test_call_list_append_pop_top(self): + def testfunc(n): + a = [] + for i in range(n): + a.append(1) + return sum(a) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + uops = get_opnames(ex) + self.assertIn("_CALL_LIST_APPEND", uops) + self.assertIn("_POP_TOP_NOP", uops) + def test_call_isinstance_is_true(self): def testfunc(n): x = 0 @@ -2353,7 +2471,102 @@ class TestUopsOptimization(unittest.TestCase): self.assertAlmostEqual(res, TIER2_THRESHOLD * (0.1 + 0.1)) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS", uops) + self.assertIn("_POP_TOP_NOP", uops) + + def test_load_attr_instance_value(self): + def testfunc(n): + class C(): + pass + c = C() + c.x = n + x = 0 + for _ in range(n): + x = c.x + return x + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertIn("_LOAD_ATTR_INSTANCE_VALUE", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertIn("_POP_TOP_NOP", uops) + + def test_int_add_op_refcount_elimination(self): + def testfunc(n): + c = 1 + res = 0 + for _ in range(n): + res = c + c + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_ADD_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) + + def test_int_sub_op_refcount_elimination(self): + def testfunc(n): + c = 1 + res = 0 + for _ in range(n): + res = c - c + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_SUBTRACT_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) + + def test_int_mul_op_refcount_elimination(self): + def testfunc(n): + c = 1 + res = 0 + for _ in range(n): + res = c * c + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_MULTIPLY_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) + + def test_int_cmp_op_refcount_elimination(self): + def testfunc(n): + c = 1 + res = 0 + for _ in range(n): + res = c == c + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_COMPARE_OP_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) + + def test_unicode_add_op_refcount_elimination(self): + def testfunc(n): + c = "a" + res = "" + for _ in range(n): + res = c + c + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, "aa") + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_ADD_UNICODE", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) def test_remove_guard_for_slice_list(self): def f(n): @@ -2398,6 +2611,98 @@ class TestUopsOptimization(unittest.TestCase): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertNotIn("_GUARD_NOS_INT", uops) + def test_store_attr_instance_value(self): + def testfunc(n): + class C: + pass + c = C() + for i in range(n): + c.a = i + return c.a + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD - 1) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertIn("_STORE_ATTR_INSTANCE_VALUE", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertIn("_POP_TOP_NOP", uops) + + def test_store_attr_with_hint(self): + def testfunc(n): + class C: + pass + c = C() + for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): + setattr(c, f"_{i}", None) + + for i in range(n): + c.x = i + return c.x + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD - 1) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertIn("_STORE_ATTR_WITH_HINT", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertIn("_POP_TOP_NOP", uops) + + def test_store_subscr_int(self): + def testfunc(n): + l = [0, 0, 0, 0] + for _ in range(n): + l[0] = 1 + l[1] = 2 + l[2] = 3 + l[3] = 4 + return sum(l) + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 10) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_STORE_SUBSCR_LIST_INT", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertNotIn("_POP_TOP_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) + + def test_store_attr_slot(self): + class C: + __slots__ = ('x',) + + def testfunc(n): + c = C() + for _ in range(n): + c.x = 42 + y = c.x + return y + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 42) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_STORE_ATTR_SLOT", uops) + self.assertIn("_POP_TOP_NOP", uops) + + def test_store_subscr_dict(self): + def testfunc(n): + d = {} + for _ in range(n): + d['a'] = 1 + d['b'] = 2 + d['c'] = 3 + d['d'] = 4 + return sum(d.values()) + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 10) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_STORE_SUBSCR_DICT", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertIn("_POP_TOP_NOP", uops) + def test_attr_promotion_failure(self): # We're not testing for any specific uops here, just # testing it doesn't crash. @@ -2424,8 +2729,6 @@ class TestUopsOptimization(unittest.TestCase): testfunc(_testinternalcapi.TIER2_THRESHOLD) - ex = get_first_executor(testfunc) - assert ex is not None """)) def test_pop_top_specialize_none(self): @@ -2501,6 +2804,190 @@ class TestUopsOptimization(unittest.TestCase): # For now... until we constant propagate it away. self.assertIn("_BINARY_OP", uops) + def test_jitted_code_sees_changed_globals(self): + "Issue 136154: Check that jitted code spots the change in the globals" + + def make_f(): + def f(): + return GLOBAL_136154 + return f + + make_f_with_bad_globals = types.FunctionType(make_f.__code__, {}) + + def jitted(funcs): + for func in funcs: + func() + + # Make a "good" f: + f = make_f() + # Compile jitted for the "good" f: + jitted([f] * TIER2_THRESHOLD) + # This "bad" f has different globals, but the *same* code/function versions: + f_with_bad_globals = make_f_with_bad_globals() + # A "good" f to enter the JIT code, and a "bad" f to trigger the bug: + with self.assertRaises(NameError): + jitted([f, f_with_bad_globals]) + + def test_reference_tracking_across_call_doesnt_crash(self): + + def f1(): + for _ in range(TIER2_THRESHOLD + 1): + # Choose a value that won't occur elsewhere to avoid sharing + str("value that won't occur elsewhere to avoid sharing") + + f1() + + def f2(): + for _ in range(TIER2_THRESHOLD + 1): + # Choose a value that won't occur elsewhere to avoid sharing + tuple((31, -17, 25, "won't occur elsewhere")) + + f2() + + def test_next_instr_for_exception_handler_set(self): + # gh-140104: We just want the exception to be caught properly. + def f(): + for i in range(TIER2_THRESHOLD + 3): + try: + undefined_variable(i) + except Exception: + pass + + f() + + def test_next_instr_for_exception_handler_set_lasts_instr(self): + # gh-140104: We just want the exception to be caught properly. + def f(): + a_list = [] + for _ in range(TIER2_THRESHOLD + 3): + try: + a_list[""] = 0 + except Exception: + pass + + f() + + def test_interpreter_finalization_with_generator_alive(self): + script_helper.assert_python_ok("-c", textwrap.dedent(""" + import sys + t = tuple(range(%d)) + def simple_for(): + for x in t: + x + + def gen(): + try: + yield + except: + simple_for() + + sys.settrace(lambda *args: None) + simple_for() + g = gen() + next(g) + """ % _testinternalcapi.SPECIALIZATION_THRESHOLD)) + + def test_executor_side_exits_create_another_executor(self): + def f(): + for x in range(TIER2_THRESHOLD + 3): + for y in range(TIER2_THRESHOLD + 3): + z = x + y + + f() + all_executors = get_all_executors(f) + # Inner loop warms up first. + # Outer loop warms up later, linking to the inner one. + # Therefore, we have at least two executors. + self.assertGreaterEqual(len(all_executors), 2) + for executor in all_executors: + opnames = list(get_opnames(executor)) + # Assert all executors first terminator ends in + # _EXIT_TRACE or _JUMP_TO_TOP, not _DEOPT + for idx, op in enumerate(opnames): + if op == "_EXIT_TRACE" or op == "_JUMP_TO_TOP": + break + elif op == "_DEOPT": + self.fail(f"_DEOPT encountered first at executor" + f" {executor} at offset {idx} rather" + f" than expected _EXIT_TRACE") + + def test_enter_executor_valid_op_arg(self): + script_helper.assert_python_ok("-c", textwrap.dedent(""" + import sys + sys.setrecursionlimit(30) # reduce time of the run + + str_v1 = '' + tuple_v2 = (None, None, None, None, None) + small_int_v3 = 4 + + def f1(): + + for _ in range(10): + abs(0) + + tuple_v2[small_int_v3] + tuple_v2[small_int_v3] + tuple_v2[small_int_v3] + + def recursive_wrapper_4569(): + str_v1 > str_v1 + str_v1 > str_v1 + str_v1 > str_v1 + recursive_wrapper_4569() + + recursive_wrapper_4569() + + for i_f1 in range(19000): + try: + f1() + except RecursionError: + pass + """)) + + def test_attribute_changes_are_watched(self): + # Just running to make sure it doesn't crash. + script_helper.assert_python_ok("-c", textwrap.dedent(""" + from concurrent.futures import ThreadPoolExecutor + from unittest import TestCase + NTHREADS = 6 + BOTTOM = 0 + TOP = 1250000 + class A: + attr = 10**1000 + class TestType(TestCase): + def read(id0): + for _ in range(BOTTOM, TOP): + A.attr + def write(id0): + x = A.attr + x += 1 + A.attr = x + with ThreadPoolExecutor(NTHREADS) as pool: + pool.submit(read, (1,)) + pool.submit(write, (1,)) + """)) + + def test_handling_of_tos_cache_with_side_exits(self): + # https://github.com/python/cpython/issues/142718 + class EvilAttr: + def __init__(self, d): + self.d = d + + def __del__(self): + try: + del self.d['attr'] + except Exception: + pass + + class Obj: + pass + + obj = Obj() + obj.__dict__ = {} + + for _ in range(TIER2_THRESHOLD+1): + obj.attr = EvilAttr(obj.__dict__) + def global_identity(x): return x diff --git a/Lib/test/test_capi/test_tuple.py b/Lib/test/test_capi/test_tuple.py index 7c07bc64e24..d6669d7802c 100644 --- a/Lib/test/test_capi/test_tuple.py +++ b/Lib/test/test_capi/test_tuple.py @@ -14,6 +14,12 @@ class TupleSubclass(tuple): class CAPITest(unittest.TestCase): + def _not_tracked(self, t): + self.assertFalse(gc.is_tracked(t), t) + + def _tracked(self, t): + self.assertTrue(gc.is_tracked(t), t) + def test_check(self): # Test PyTuple_Check() check = _testlimitedcapi.tuple_check @@ -52,16 +58,47 @@ class CAPITest(unittest.TestCase): self.assertEqual(tup1, ()) self.assertEqual(size(tup1), 0) self.assertIs(type(tup1), tuple) + self._not_tracked(tup1) + tup2 = tuple_new(1) self.assertIs(type(tup2), tuple) self.assertEqual(size(tup2), 1) self.assertIsNot(tup2, tup1) self.assertTrue(checknull(tup2, 0)) + self._tracked(tup2) self.assertRaises(SystemError, tuple_new, -1) self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN) self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX) + def test_tuple_fromarray(self): + # Test PyTuple_FromArray() + tuple_fromarray = _testcapi.tuple_fromarray + + tup = tuple([i] for i in range(5)) + copy = tuple_fromarray(tup) + self.assertEqual(copy, tup) + self._tracked(copy) + + tup = tuple(42**i for i in range(5)) + copy = tuple_fromarray(tup) + self.assertEqual(copy, tup) + self._not_tracked(copy) + + tup = () + copy = tuple_fromarray(tup) + self.assertIs(copy, tup) + + copy = tuple_fromarray(NULL, 0) + self.assertIs(copy, ()) + + with self.assertRaises(SystemError): + tuple_fromarray(NULL, -1) + with self.assertRaises(SystemError): + tuple_fromarray(NULL, PY_SSIZE_T_MIN) + with self.assertRaises(MemoryError): + tuple_fromarray(NULL, PY_SSIZE_T_MAX) + def test_tuple_pack(self): # Test PyTuple_Pack() pack = _testlimitedcapi.tuple_pack @@ -70,6 +107,10 @@ class CAPITest(unittest.TestCase): self.assertEqual(pack(1, [1]), ([1],)) self.assertEqual(pack(2, [1], [2]), ([1], [2])) + self._tracked(pack(1, [1])) + self._tracked(pack(2, [1], b'abc')) + self._not_tracked(pack(2, 42, b'abc')) + self.assertRaises(SystemError, pack, PY_SSIZE_T_MIN) self.assertRaises(SystemError, pack, -1) self.assertRaises(MemoryError, pack, PY_SSIZE_T_MAX) diff --git a/Lib/test/test_capi/test_type.py b/Lib/test/test_capi/test_type.py index 15fb4a93e2a..e6a8ef9eed6 100644 --- a/Lib/test/test_capi/test_type.py +++ b/Lib/test/test_capi/test_type.py @@ -195,6 +195,24 @@ class TypeTests(unittest.TestCase): with self.assertRaises(TypeError): _testcapi.pytype_getmodulebydef(H2) + def test_get_module_by_token(self): + token = _testcapi.pymodule_get_token(_testcapi) + + heaptype = _testcapi.create_type_with_token('_testcapi.H', 0) + mod = _testcapi.pytype_getmodulebytoken(heaptype, token) + self.assertIs(mod, _testcapi) + + class H1(heaptype): pass + mod = _testcapi.pytype_getmodulebytoken(H1, token) + self.assertIs(mod, _testcapi) + + with self.assertRaises(TypeError): + _testcapi.pytype_getmodulebytoken(int, token) + + class H2(int): pass + with self.assertRaises(TypeError): + _testcapi.pytype_getmodulebytoken(H2, token) + def test_freeze(self): # test PyType_Freeze() type_freeze = _testcapi.type_freeze @@ -274,3 +292,10 @@ class TypeTests(unittest.TestCase): obj.__dict__ = {'bar': 3} self.assertEqual(obj.__dict__, {'bar': 3}) self.assertEqual(obj.bar, 3) + + def test_extension_managed_weakref_nogc_type(self): + msg = ("type _testcapi.ManagedWeakrefNoGCType " + "has the Py_TPFLAGS_MANAGED_WEAKREF " + "flag but not Py_TPFLAGS_HAVE_GC flag") + with self.assertRaisesRegex(SystemError, msg): + _testcapi.create_managed_weakref_nogc_type() diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index 8644479d83d..bef72032513 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -514,6 +514,10 @@ class TestFuncWatchers(unittest.TestCase): _testcapi.set_func_kwdefaults_via_capi(myfunc, new_kwdefaults) self.assertIn((_testcapi.PYFUNC_EVENT_MODIFY_KWDEFAULTS, myfunc, new_kwdefaults), events) + new_qualname = "foo.bar" + myfunc.__qualname__ = new_qualname + self.assertIn((_testcapi.PYFUNC_EVENT_MODIFY_QUALNAME, myfunc, new_qualname), events) + # Clear events reference to func events = [] del myfunc diff --git a/Lib/test/test_cext/__init__.py b/Lib/test/test_cext/__init__.py index fb93c6ccbb6..a52c2241f5d 100644 --- a/Lib/test/test_cext/__init__.py +++ b/Lib/test/test_cext/__init__.py @@ -14,7 +14,6 @@ from test import support SOURCES = [ os.path.join(os.path.dirname(__file__), 'extension.c'), - os.path.join(os.path.dirname(__file__), 'create_moduledef.c'), ] SETUP = os.path.join(os.path.dirname(__file__), 'setup.py') diff --git a/Lib/test/test_cext/create_moduledef.c b/Lib/test/test_cext/create_moduledef.c deleted file mode 100644 index 249c3163552..00000000000 --- a/Lib/test/test_cext/create_moduledef.c +++ /dev/null @@ -1,29 +0,0 @@ -// Workaround for testing _Py_OPAQUE_PYOBJECT. -// See end of 'extension.c' - - -#undef _Py_OPAQUE_PYOBJECT -#undef Py_LIMITED_API -#include "Python.h" - - -// (repeated definition to avoid creating a header) -extern PyObject *testcext_create_moduledef( - const char *name, const char *doc, - PyMethodDef *methods, PyModuleDef_Slot *slots); - -PyObject *testcext_create_moduledef( - const char *name, const char *doc, - PyMethodDef *methods, PyModuleDef_Slot *slots) { - - static struct PyModuleDef _testcext_module = { - PyModuleDef_HEAD_INIT, - }; - if (!_testcext_module.m_name) { - _testcext_module.m_name = name; - _testcext_module.m_doc = doc; - _testcext_module.m_methods = methods; - _testcext_module.m_slots = slots; - } - return PyModuleDef_Init(&_testcext_module); -} diff --git a/Lib/test/test_cext/extension.c b/Lib/test/test_cext/extension.c index 73fc67ae59d..0f668c1da32 100644 --- a/Lib/test/test_cext/extension.c +++ b/Lib/test/test_cext/extension.c @@ -78,7 +78,7 @@ _testcext_exec( return 0; } -#define _FUNC_NAME(NAME) PyInit_ ## NAME +#define _FUNC_NAME(NAME) PyModExport_ ## NAME #define FUNC_NAME(NAME) _FUNC_NAME(NAME) // Converting from function pointer to void* has undefined behavior, but @@ -88,58 +88,40 @@ _testcext_exec( _Py_COMP_DIAG_PUSH #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wcast-qual" #elif defined(__clang__) #pragma clang diagnostic ignored "-Wpedantic" +#pragma clang diagnostic ignored "-Wcast-qual" #endif +PyDoc_STRVAR(_testcext_doc, "C test extension."); + static PyModuleDef_Slot _testcext_slots[] = { + {Py_mod_name, STR(MODULE_NAME)}, + {Py_mod_doc, (void*)(char*)_testcext_doc}, {Py_mod_exec, (void*)_testcext_exec}, + {Py_mod_methods, _testcext_methods}, {0, NULL} }; _Py_COMP_DIAG_POP -PyDoc_STRVAR(_testcext_doc, "C test extension."); - -#ifndef _Py_OPAQUE_PYOBJECT - -static struct PyModuleDef _testcext_module = { - PyModuleDef_HEAD_INIT, // m_base - STR(MODULE_NAME), // m_name - _testcext_doc, // m_doc - 0, // m_size - _testcext_methods, // m_methods - _testcext_slots, // m_slots - NULL, // m_traverse - NULL, // m_clear - NULL, // m_free -}; - - -PyMODINIT_FUNC +PyMODEXPORT_FUNC FUNC_NAME(MODULE_NAME)(void) { - return PyModuleDef_Init(&_testcext_module); + return _testcext_slots; } -#else // _Py_OPAQUE_PYOBJECT - -// Opaque PyObject means that PyModuleDef is also opaque and cannot be -// declared statically. See PEP 793. -// So, this part of module creation is split into a separate source file -// which uses non-limited API. - -// (repeated definition to avoid creating a header) -extern PyObject *testcext_create_moduledef( - const char *name, const char *doc, - PyMethodDef *methods, PyModuleDef_Slot *slots); +// Also define the soft-deprecated entrypoint to ensure it isn't called +#define _INITFUNC_NAME(NAME) PyInit_ ## NAME +#define INITFUNC_NAME(NAME) _INITFUNC_NAME(NAME) PyMODINIT_FUNC -FUNC_NAME(MODULE_NAME)(void) +INITFUNC_NAME(MODULE_NAME)(void) { - return testcext_create_moduledef( - STR(MODULE_NAME), _testcext_doc, _testcext_methods, _testcext_slots); + PyErr_SetString( + PyExc_AssertionError, + "PyInit_* function called while a PyModExport_* one is available"); + return NULL; } - -#endif // _Py_OPAQUE_PYOBJECT diff --git a/Lib/test/test_cext/setup.py b/Lib/test/test_cext/setup.py index 4d71e4751f7..67dfddec751 100644 --- a/Lib/test/test_cext/setup.py +++ b/Lib/test/test_cext/setup.py @@ -99,7 +99,6 @@ def main(): # Define _Py_OPAQUE_PYOBJECT macro if opaque_pyobject: cflags.append(f'-D_Py_OPAQUE_PYOBJECT') - sources.append('create_moduledef.c') if internal: cflags.append('-DTEST_INTERNAL_C_API=1') diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 8c7a62a74ba..64222555166 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -859,7 +859,12 @@ class ClassTests(unittest.TestCase): from _testinternalcapi import has_inline_values -Py_TPFLAGS_MANAGED_DICT = (1 << 2) +Py_TPFLAGS_INLINE_VALUES = (1 << 2) +Py_TPFLAGS_MANAGED_DICT = (1 << 4) + +class NoManagedDict: + __slots__ = ('a',) + class Plain: pass @@ -874,11 +879,31 @@ class WithAttrs: self.d = 4 +class VarSizedSubclass(tuple): + pass + + class TestInlineValues(unittest.TestCase): - def test_flags(self): - self.assertEqual(Plain.__flags__ & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) - self.assertEqual(WithAttrs.__flags__ & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) + def test_no_flags_for_slots_class(self): + flags = NoManagedDict.__flags__ + self.assertEqual(flags & Py_TPFLAGS_MANAGED_DICT, 0) + self.assertEqual(flags & Py_TPFLAGS_INLINE_VALUES, 0) + self.assertFalse(has_inline_values(NoManagedDict())) + + def test_both_flags_for_regular_class(self): + for cls in (Plain, WithAttrs): + with self.subTest(cls=cls.__name__): + flags = cls.__flags__ + self.assertEqual(flags & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) + self.assertEqual(flags & Py_TPFLAGS_INLINE_VALUES, Py_TPFLAGS_INLINE_VALUES) + self.assertTrue(has_inline_values(cls())) + + def test_managed_dict_only_for_varsized_subclass(self): + flags = VarSizedSubclass.__flags__ + self.assertEqual(flags & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) + self.assertEqual(flags & Py_TPFLAGS_INLINE_VALUES, 0) + self.assertFalse(has_inline_values(VarSizedSubclass())) def test_has_inline_values(self): c = Plain() diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index f8d9b0af8f9..e71f9fc181b 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -4,6 +4,7 @@ from functools import partial from test import support, test_tools +from test.support import force_not_colorized_test_class from test.support import os_helper from test.support.os_helper import TESTFN, unlink, rmtree from textwrap import dedent @@ -357,6 +358,32 @@ class ClinicWholeFileTest(TestCase): """ self.expect_failure(block, err, lineno=6) + def test_double_star_after_var_keyword(self): + err = "Function 'my_test_func' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + block = """ + /*[clinic input] + my_test_func + + pos_arg: object + **kwds: dict + ** + [clinic start generated code]*/ + """ + self.expect_failure(block, err, lineno=5) + + def test_var_keyword_after_star(self): + err = "Function 'my_test_func' has an invalid parameter declaration: '**'" + block = """ + /*[clinic input] + my_test_func + + pos_arg: object + ** + **kwds: dict + [clinic start generated code]*/ + """ + self.expect_failure(block, err, lineno=5) + def test_module_already_got_one(self): err = "Already defined module 'm'!" block = """ @@ -748,6 +775,16 @@ class ClinicWholeFileTest(TestCase): """) self.clinic.parse(raw) + def test_var_keyword_non_dict(self): + err = "'var_keyword_object' is not a valid converter" + block = """ + /*[clinic input] + my_test_func + + **kwds: object + [clinic start generated code]*/ + """ + self.expect_failure(block, err, lineno=4) class ParseFileUnitTest(TestCase): def expect_parsing_failure( @@ -1608,6 +1645,11 @@ class ClinicParserTest(TestCase): [ a: object ] + """, """ + with_kwds + [ + **kwds: dict + ] """) err = ( "You cannot use optional groups ('[' and ']') unless all " @@ -1991,6 +2033,44 @@ class ClinicParserTest(TestCase): err = "Function 'bar': '/' must precede '*'" self.expect_failure(block, err) + def test_slash_after_var_keyword(self): + block = """ + module foo + foo.bar + x: int + y: int + **kwds: dict + z: int + / + """ + err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + self.expect_failure(block, err) + + def test_star_after_var_keyword(self): + block = """ + module foo + foo.bar + x: int + y: int + **kwds: dict + z: int + * + """ + err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + self.expect_failure(block, err) + + def test_parameter_after_var_keyword(self): + block = """ + module foo + foo.bar + x: int + y: int + **kwds: dict + z: int + """ + err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + self.expect_failure(block, err) + def test_depr_star_must_come_after_slash(self): block = """ module foo @@ -2079,6 +2159,16 @@ class ClinicParserTest(TestCase): """ self.expect_failure(block, err, lineno=3) + def test_parameters_no_more_than_one_var_keyword(self): + err = "Encountered parameter line when not expecting parameters: **var_keyword_2: dict" + block = """ + module foo + foo.bar + **var_keyword_1: dict + **var_keyword_2: dict + """ + self.expect_failure(block, err, lineno=3) + def test_function_not_at_column_0(self): function = self.parse_function(""" module foo @@ -2513,6 +2603,14 @@ class ClinicParserTest(TestCase): """ self.expect_failure(block, err, lineno=1) + def test_var_keyword_cannot_take_default_value(self): + err = "Function 'fn' has an invalid parameter declaration:" + block = """ + fn + **kwds: dict = None + """ + self.expect_failure(block, err, lineno=1) + def test_default_is_not_of_correct_type(self): err = ("int_converter: default value 2.5 for field 'a' " "is not of type 'int'") @@ -2610,7 +2708,58 @@ class ClinicParserTest(TestCase): """ self.expect_failure(block, err, lineno=2) + def test_var_keyword_with_pos_or_kw(self): + block = """ + module foo + foo.bar + x: int + **kwds: dict + """ + err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + self.expect_failure(block, err) + def test_var_keyword_with_kw_only(self): + block = """ + module foo + foo.bar + x: int + / + * + y: int + **kwds: dict + """ + err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + self.expect_failure(block, err) + + def test_var_keyword_with_pos_or_kw_and_kw_only(self): + block = """ + module foo + foo.bar + x: int + / + y: int + * + z: int + **kwds: dict + """ + err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" + self.expect_failure(block, err) + + def test_allow_negative_accepted_by_py_ssize_t_converter_only(self): + errmsg = re.escape("converter_init() got an unexpected keyword argument 'allow_negative'") + unsupported_converters = [converter_name for converter_name in converters.keys() + if converter_name != "Py_ssize_t"] + for converter in unsupported_converters: + with self.subTest(converter=converter): + block = f""" + module m + m.func + a: {converter}(allow_negative=True) + """ + with self.assertRaisesRegex((AssertionError, TypeError), errmsg): + self.parse_function(block) + +@force_not_colorized_test_class class ClinicExternalTest(TestCase): maxDiff = None @@ -2833,6 +2982,8 @@ class ClinicExternalTest(TestCase): "uint64", "uint8", "unicode", + "unicode_fs_decoded", + "unicode_fs_encoded", "unsigned_char", "unsigned_int", "unsigned_long", @@ -3194,8 +3345,12 @@ class ClinicFunctionalTest(unittest.TestCase): ac_tester.py_ssize_t_converter(PY_SSIZE_T_MAX + 1) with self.assertRaises(TypeError): ac_tester.py_ssize_t_converter([]) - self.assertEqual(ac_tester.py_ssize_t_converter(), (12, 34, 56)) - self.assertEqual(ac_tester.py_ssize_t_converter(1, 2, None), (1, 2, 56)) + with self.assertRaises(ValueError): + ac_tester.py_ssize_t_converter(12, 34, 56, -1) + with self.assertRaises(ValueError): + ac_tester.py_ssize_t_converter(12, 34, 56, 78, -1) + self.assertEqual(ac_tester.py_ssize_t_converter(), (12, 34, 56, 78, 90, -12, -34)) + self.assertEqual(ac_tester.py_ssize_t_converter(1, 2, None, 3, None, 4, None), (1, 2, 56, 3, 90, 4, -34)) def test_slice_index_converter(self): from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX @@ -3937,6 +4092,49 @@ class ClinicFunctionalTest(unittest.TestCase): check("a", b="b", c="c", d="d", e="e", f="f", g="g") self.assertRaises(TypeError, fn, a="a", b="b", c="c", d="d", e="e", f="f", g="g") + def test_lone_kwds(self): + with self.assertRaises(TypeError): + ac_tester.lone_kwds(1, 2) + self.assertEqual(ac_tester.lone_kwds(), ({},)) + self.assertEqual(ac_tester.lone_kwds(y='y'), ({'y': 'y'},)) + kwds = {'y': 'y', 'z': 'z'} + self.assertEqual(ac_tester.lone_kwds(y='y', z='z'), (kwds,)) + self.assertEqual(ac_tester.lone_kwds(**kwds), (kwds,)) + + def test_kwds_with_pos_only(self): + with self.assertRaises(TypeError): + ac_tester.kwds_with_pos_only() + with self.assertRaises(TypeError): + ac_tester.kwds_with_pos_only(y='y') + with self.assertRaises(TypeError): + ac_tester.kwds_with_pos_only(1, y='y') + self.assertEqual(ac_tester.kwds_with_pos_only(1, 2), (1, 2, {})) + self.assertEqual(ac_tester.kwds_with_pos_only(1, 2, y='y'), (1, 2, {'y': 'y'})) + kwds = {'y': 'y', 'z': 'z'} + self.assertEqual(ac_tester.kwds_with_pos_only(1, 2, y='y', z='z'), (1, 2, kwds)) + self.assertEqual(ac_tester.kwds_with_pos_only(1, 2, **kwds), (1, 2, kwds)) + + def test_kwds_with_stararg(self): + self.assertEqual(ac_tester.kwds_with_stararg(), ((), {})) + self.assertEqual(ac_tester.kwds_with_stararg(1, 2), ((1, 2), {})) + self.assertEqual(ac_tester.kwds_with_stararg(y='y'), ((), {'y': 'y'})) + args = (1, 2) + kwds = {'y': 'y', 'z': 'z'} + self.assertEqual(ac_tester.kwds_with_stararg(1, 2, y='y', z='z'), (args, kwds)) + self.assertEqual(ac_tester.kwds_with_stararg(*args, **kwds), (args, kwds)) + + def test_kwds_with_pos_only_and_stararg(self): + with self.assertRaises(TypeError): + ac_tester.kwds_with_pos_only_and_stararg() + with self.assertRaises(TypeError): + ac_tester.kwds_with_pos_only_and_stararg(y='y') + self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2), (1, 2, (), {})) + self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2, y='y'), (1, 2, (), {'y': 'y'})) + args = ('lobster', 'thermidor') + kwds = {'y': 'y', 'z': 'z'} + self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2, 'lobster', 'thermidor', y='y', z='z'), (1, 2, args, kwds)) + self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2, *args, **kwds), (1, 2, args, kwds)) + class LimitedCAPIOutputTests(unittest.TestCase): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 784c45aa96f..8695df9eb0c 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -44,7 +44,6 @@ from importlib.machinery import BuiltinImporter _loader = __loader__ if __loader__ is BuiltinImporter else type(__loader__) print('__loader__==%a' % _loader) print('__file__==%a' % __file__) -print('__cached__==%a' % __cached__) print('__package__==%r' % __package__) # Check PEP 451 details import os.path @@ -58,8 +57,6 @@ if __package__ is not None: assertEqual(__spec__.parent, __package__) assertIdentical(__spec__.submodule_search_locations, None) assertEqual(__spec__.origin, __file__) - if __spec__.cached is not None: - assertEqual(__spec__.cached, __cached__) # Check the sys module import sys assertIdentical(globals(), sys.modules[__name__].__dict__) @@ -810,6 +807,30 @@ class CmdLineTest(unittest.TestCase): out, err = p.communicate() self.assertEqual(out, b"12345678912345678912345\n") + def test_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + rc, out, err = assert_python_ok( + '-Werror', + '-Walways:::__main__', + '-Werror:::test.test_import.data.syntax_warnings', + '-Werror:::syntax_warnings', + filename) + self.assertEqual(err.count(b': SyntaxWarning: '), 6) + + def test_zipfile_run_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with open(filename, 'rb') as f: + source = f.read() + with os_helper.temp_dir() as script_dir: + zip_name, _ = make_zip_pkg( + script_dir, 'test_zip', 'test_pkg', '__main__', source) + rc, out, err = assert_python_ok( + '-Werror', + '-Walways:::__main__', + '-Werror:::test_pkg.__main__', + os.path.join(zip_name, 'test_pkg') + ) + self.assertEqual(err.count(b': SyntaxWarning: '), 12) def tearDownModule(): diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index fd7769e8c27..c31faec9ee5 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -13,6 +13,7 @@ import warnings from test import support from test.support import os_helper +from test.support import warnings_helper try: import _testlimitedcapi @@ -3873,32 +3874,27 @@ class Rot13UtilTest(unittest.TestCase): class CodecNameNormalizationTest(unittest.TestCase): """Test codec name normalization""" def test_codecs_lookup(self): - FOUND = (1, 2, 3, 4) - NOT_FOUND = (None, None, None, None) def search_function(encoding): - if encoding == "aaa_8": - return FOUND + if encoding.startswith("test."): + return (encoding, 2, 3, 4) else: - return NOT_FOUND + return None codecs.register(search_function) self.addCleanup(codecs.unregister, search_function) - self.assertEqual(FOUND, codecs.lookup('aaa_8')) - self.assertEqual(FOUND, codecs.lookup('AAA-8')) - self.assertEqual(FOUND, codecs.lookup('AAA---8')) - self.assertEqual(FOUND, codecs.lookup('AAA 8')) - self.assertEqual(FOUND, codecs.lookup('aaa\xe9\u20ac-8')) - self.assertEqual(NOT_FOUND, codecs.lookup('AAA.8')) - self.assertEqual(NOT_FOUND, codecs.lookup('AAA...8')) - self.assertEqual(NOT_FOUND, codecs.lookup('BBB-8')) - self.assertEqual(NOT_FOUND, codecs.lookup('BBB.8')) - self.assertEqual(NOT_FOUND, codecs.lookup('a\xe9\u20ac-8')) + self.assertEqual(codecs.lookup('test.aaa_8'), ('test.aaa_8', 2, 3, 4)) + self.assertEqual(codecs.lookup('TEST.AAA-8'), ('test.aaa-8', 2, 3, 4)) + self.assertEqual(codecs.lookup('TEST.AAA 8'), ('test.aaa-8', 2, 3, 4)) + self.assertEqual(codecs.lookup('TEST.AAA---8'), ('test.aaa---8', 2, 3, 4)) + self.assertEqual(codecs.lookup('TEST.AAA 8'), ('test.aaa---8', 2, 3, 4)) + self.assertEqual(codecs.lookup('TEST.AAA.8'), ('test.aaa.8', 2, 3, 4)) + self.assertEqual(codecs.lookup('TEST.AAA...8'), ('test.aaa...8', 2, 3, 4)) + with self.assertWarns(DeprecationWarning): + self.assertEqual(codecs.lookup('TEST.AAA\xe9\u20ac-8'), ('test.aaa\xe9\u20ac-8', 2, 3, 4)) def test_encodings_normalize_encoding(self): - # encodings.normalize_encoding() ignores non-ASCII characters. normalize = encodings.normalize_encoding self.assertEqual(normalize('utf_8'), 'utf_8') - self.assertEqual(normalize('utf\xE9\u20AC\U0010ffff-8'), 'utf_8') self.assertEqual(normalize('utf 8'), 'utf_8') # encodings.normalize_encoding() doesn't convert # characters to lower case. @@ -3906,6 +3902,11 @@ class CodecNameNormalizationTest(unittest.TestCase): self.assertEqual(normalize('utf.8'), 'utf.8') self.assertEqual(normalize('utf...8'), 'utf...8') + # Non-ASCII *encoding* is deprecated. + msg = "Support for non-ascii encoding names will be removed in 3.17" + with warnings_helper.check_warnings((msg, DeprecationWarning)): + self.assertEqual(normalize('utf\xE9\u20AC\U0010ffff-8'), 'utf_8') + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index f33e4b3256a..22595239252 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -12,6 +12,7 @@ from itertools import product, chain, combinations import string import sys from test import support +from test.support.import_helper import import_fresh_module import types import unittest @@ -1934,6 +1935,44 @@ class TestCollectionABCs(ABCTestCase): assert_index_same( nativeseq, seqseq, (letter, start, stop)) + def test_ByteString(self): + previous_sys_modules = sys.modules.copy() + self.addCleanup(sys.modules.update, previous_sys_modules) + + for module in "collections", "_collections_abc", "collections.abc": + sys.modules.pop(module, None) + + with self.assertWarns(DeprecationWarning): + from collections.abc import ByteString + for sample in [bytes, bytearray]: + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(sample(), ByteString) + self.assertTrue(issubclass(sample, ByteString)) + for sample in [str, list, tuple]: + with self.assertWarns(DeprecationWarning): + self.assertNotIsInstance(sample(), ByteString) + self.assertFalse(issubclass(sample, ByteString)) + with self.assertWarns(DeprecationWarning): + self.assertNotIsInstance(memoryview(b""), ByteString) + self.assertFalse(issubclass(memoryview, ByteString)) + with self.assertWarns(DeprecationWarning): + self.validate_abstract_methods(ByteString, '__getitem__', '__len__') + + with self.assertWarns(DeprecationWarning): + class X(ByteString): pass + + with self.assertWarns(DeprecationWarning): + # No metaclass conflict + class Z(ByteString, Awaitable): pass + + def test_ByteString_attribute_access(self): + collections_abc = import_fresh_module( + "collections.abc", + fresh=("collections", "_collections_abc") + ) + with self.assertWarns(DeprecationWarning): + collections_abc.ByteString + def test_Buffer(self): for sample in [bytes, bytearray, memoryview]: self.assertIsInstance(sample(b"x"), Buffer) @@ -2140,6 +2179,7 @@ class TestCounter(unittest.TestCase): self.assertTrue(correctly_ordered(p - q)) self.assertTrue(correctly_ordered(p | q)) self.assertTrue(correctly_ordered(p & q)) + self.assertTrue(correctly_ordered(p ^ q)) p, q = Counter(ps), Counter(qs) p += q @@ -2157,6 +2197,10 @@ class TestCounter(unittest.TestCase): p &= q self.assertTrue(correctly_ordered(p)) + p, q = Counter(ps), Counter(qs) + p ^= q + self.assertTrue(correctly_ordered(p)) + p, q = Counter(ps), Counter(qs) p.update(q) self.assertTrue(correctly_ordered(p)) @@ -2239,6 +2283,7 @@ class TestCounter(unittest.TestCase): (Counter.__sub__, lambda x, y: max(0, x-y)), (Counter.__or__, lambda x, y: max(0,x,y)), (Counter.__and__, lambda x, y: max(0, min(x,y))), + (Counter.__xor__, lambda x, y: max(0, max(x,y) - min(x,y))), ]: result = counterop(p, q) for x in elements: @@ -2256,6 +2301,7 @@ class TestCounter(unittest.TestCase): (Counter.__sub__, set.__sub__), (Counter.__or__, set.__or__), (Counter.__and__, set.__and__), + (Counter.__xor__, set.__xor__), ]: counter_result = counterop(p, q) set_result = setop(set(p.elements()), set(q.elements())) @@ -2274,6 +2320,7 @@ class TestCounter(unittest.TestCase): (Counter.__isub__, Counter.__sub__), (Counter.__ior__, Counter.__or__), (Counter.__iand__, Counter.__and__), + (Counter.__ixor__, Counter.__xor__), ]: c = p.copy() c_id = id(c) @@ -2349,6 +2396,7 @@ class TestCounter(unittest.TestCase): self.assertEqual(set(cp - cq), sp - sq) self.assertEqual(set(cp | cq), sp | sq) self.assertEqual(set(cp & cq), sp & sq) + self.assertEqual(set(cp ^ cq), sp ^ sq) self.assertEqual(cp == cq, sp == sq) self.assertEqual(cp != cq, sp != sq) self.assertEqual(cp <= cq, sp <= sq) @@ -2376,6 +2424,40 @@ class TestCounter(unittest.TestCase): self.assertTrue(Counter(a=3, b=2, c=0) > Counter('aab')) self.assertFalse(Counter(a=2, b=1, c=0) > Counter('aab')) + def test_symmetric_difference(self): + population = (-4, -3, -2, -1, 0, 1, 2, 3, 4) + + for a, b1, b2, c in product(population, repeat=4): + p = Counter(a=a, b=b1) + q = Counter(b=b2, c=c) + r = p ^ q + + # Elementwise invariants + for k in ('a', 'b', 'c'): + self.assertEqual(r[k], max(p[k], q[k]) - min(p[k], q[k])) + self.assertEqual(r[k], abs(p[k] - q[k])) + + # Invariant for all positive, negative, and zero counts + self.assertEqual(r, (p - q) | (q - p)) + + # Invariant for non-negative counts + if a >= 0 and b1 >= 0 and b2 >= 0 and c >= 0: + self.assertEqual(r, (p | q) - (p & q)) + + # Zeros and negatives eliminated + self.assertTrue(all(value > 0 for value in r.values())) + + # Output preserves input order: p first and then q + keys = list(p) + list(q) + indices = [keys.index(k) for k in r] + self.assertEqual(indices, sorted(indices)) + + # Inplace operation matches binary operation + pp = Counter(p) + qq = Counter(q) + pp ^= qq + self.assertEqual(pp, r) + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite(collections)) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e4483c26cfd..fa611f480d6 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -651,6 +651,21 @@ class TestSpecifics(unittest.TestCase): compile('pass', filename, 'exec') self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec') + def test_compile_filename_refleak(self): + # Regression tests for reference leak in PyUnicode_FSDecoder. + # See https://github.com/python/cpython/issues/139748. + mortal_str = 'this is a mortal string' + # check error path when 'mode' AC conversion failed + self.assertRaises(TypeError, compile, b'', mortal_str, mode=1234) + # check error path when 'optimize' AC conversion failed + self.assertRaises(OverflowError, compile, b'', mortal_str, + 'exec', optimize=1 << 1000) + # check error path when 'dont_inherit' AC conversion failed + class EvilBool: + def __bool__(self): raise ValueError + self.assertRaises(ValueError, compile, b'', mortal_str, + 'exec', dont_inherit=EvilBool()) + @support.cpython_only def test_same_filename_used(self): s = """def f(): pass\ndef g(): pass""" @@ -713,7 +728,8 @@ class TestSpecifics(unittest.TestCase): def test_compiler_recursion_limit(self): # Compiler frames are small limit = 100 - crash_depth = limit * 5000 + # Android test devices have less memory. + crash_depth = limit * (1000 if sys.platform == "android" else 5000) success_depth = limit def check_limit(prefix, repeated, mode="single"): @@ -1021,11 +1037,13 @@ class TestSpecifics(unittest.TestCase): # An implicit test for PyUnicode_FSDecoder(). compile("42", FakePath("test_compile_pathlike"), "single") + # bpo-31113: Stack overflow when compile a long sequence of + # complex statements. @support.requires_resource('cpu') def test_stack_overflow(self): - # bpo-31113: Stack overflow when compile a long sequence of - # complex statements. - compile("if a: b\n" * 200000, "", "exec") + # Android test devices have less memory. + size = 100_000 if sys.platform == "android" else 200_000 + compile("if a: b\n" * size, "", "exec") # Multiple users rely on the fact that CPython does not generate # bytecode for dead code blocks. See bpo-37500 for more context. @@ -1615,6 +1633,17 @@ class TestSpecifics(unittest.TestCase): def f(): a if (1 if b else c) else d + def test_lineno_propagation_empty_blocks(self): + # Smoke test. See gh-138714. + def f(): + while name: + try: + break + except: + pass + else: + 1 if 1 else 1 + def test_global_declaration_in_except_used_in_else(self): # See gh-111123 code = textwrap.dedent("""\ @@ -1653,22 +1682,21 @@ class TestSpecifics(unittest.TestCase): self.assertRaises(NameError, ns['foo']) def test_compile_warnings(self): - # See gh-131927 - # Compile warnings originating from the same file and - # line are now only emitted once. + # Each invocation of compile() emits compiler warnings, even if they + # have the same message and line number. + source = textwrap.dedent(r""" + # tokenizer + 1or 0 # line 3 + # code generator + 1 is 1 # line 5 + """) with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("default") - compile('1 is 1', '', 'eval') - compile('1 is 1', '', 'eval') + for i in range(2): + # Even if compile() is at the same line. + compile(source, '', 'exec') - self.assertEqual(len(caught), 1) - - with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("always") - compile('1 is 1', '', 'eval') - compile('1 is 1', '', 'eval') - - self.assertEqual(len(caught), 2) + self.assertEqual([wm.lineno for wm in caught], [3, 5] * 2) def test_compile_warning_in_finally(self): # Ensure that warnings inside finally blocks are @@ -1679,16 +1707,131 @@ class TestSpecifics(unittest.TestCase): try: pass finally: - 1 is 1 + 1 is 1 # line 5 + try: + pass + finally: # nested + 1 is 1 # line 9 """) with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("default") + warnings.simplefilter("always") compile(source, '', 'exec') - self.assertEqual(len(caught), 1) - self.assertEqual(caught[0].category, SyntaxWarning) - self.assertIn("\"is\" with 'int' literal", str(caught[0].message)) + self.assertEqual(sorted(wm.lineno for wm in caught), [5, 9]) + for wm in caught: + self.assertEqual(wm.category, SyntaxWarning) + self.assertIn("\"is\" with 'int' literal", str(wm.message)) + + # Other code path is used for "try" with "except*". + source = textwrap.dedent(""" + try: + pass + except *Exception: + pass + finally: + 1 is 1 # line 7 + try: + pass + except *Exception: + pass + finally: # nested + 1 is 1 # line 13 + """) + + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + compile(source, '', 'exec') + + self.assertEqual(sorted(wm.lineno for wm in caught), [7, 13]) + for wm in caught: + self.assertEqual(wm.category, SyntaxWarning) + self.assertIn("\"is\" with 'int' literal", str(wm.message)) + + def test_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with open(filename, 'rb') as f: + source = f.read() + module_re = r'test\.test_import\.data\.syntax_warnings\z' + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=module_re) + compile(source, filename, 'exec') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'package\.module\z') + warnings.filterwarnings('error', module=module_re) + compile(source, filename, 'exec', module='package.module') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + + @support.subTests('src', [ + textwrap.dedent(""" + def f(): + try: + pass + finally: + return 42 + """), + textwrap.dedent(""" + for x in y: + try: + pass + finally: + break + """), + textwrap.dedent(""" + for x in y: + try: + pass + finally: + continue + """), + ]) + def test_pep_765_warnings(self, src): + with self.assertWarnsRegex(SyntaxWarning, 'finally'): + compile(src, '', 'exec') + with warnings.catch_warnings(): + warnings.simplefilter("error") + tree = ast.parse(src) + with self.assertWarnsRegex(SyntaxWarning, 'finally'): + compile(tree, '', 'exec') + + @support.subTests('src', [ + textwrap.dedent(""" + try: + pass + finally: + def f(): + return 42 + """), + textwrap.dedent(""" + try: + pass + finally: + for x in y: + break + """), + textwrap.dedent(""" + try: + pass + finally: + for x in y: + continue + """), + ]) + def test_pep_765_no_warnings(self, src): + with warnings.catch_warnings(): + warnings.simplefilter("error") + compile(src, '', 'exec') + class TestBooleanExpression(unittest.TestCase): class Value: diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index 9685f980119..731419a48bd 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -106,6 +106,21 @@ class ProcessPoolExecutorTest(ExecutorTest): self.assertIn('raise RuntimeError(123) # some comment', f1.getvalue()) + def test_traceback_when_child_process_terminates_abruptly(self): + # gh-139462 enhancement - BrokenProcessPool exceptions + # should describe which process terminated. + exit_code = 99 + with self.executor_type(max_workers=1) as executor: + future = executor.submit(os._exit, exit_code) + with self.assertRaises(BrokenProcessPool) as bpe: + future.result() + + cause = bpe.exception.__cause__ + self.assertIsInstance(cause, futures.process._RemoteTraceback) + self.assertIn( + f"terminated abruptly with exit code {exit_code}", cause.tb + ) + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() @hashlib_helper.requires_hashdigest('md5') def test_ressources_gced_in_workers(self): diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py index 467ec09d99e..cfef24727e8 100644 --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -672,7 +672,7 @@ class TestCopy(unittest.TestCase): def test_reduce_5tuple(self): class C(dict): def __reduce__(self): - return (C, (), self.__dict__, None, self.items()) + return (C, (), self.__dict__, None, iter(self.items())) def __eq__(self, other): return (dict(self) == dict(other) and self.__dict__ == other.__dict__) diff --git a/Lib/test/test_cppext/extension.cpp b/Lib/test/test_cppext/extension.cpp index 1affa176088..f95655eccde 100644 --- a/Lib/test/test_cppext/extension.cpp +++ b/Lib/test/test_cppext/extension.cpp @@ -14,6 +14,7 @@ #ifdef TEST_INTERNAL_C_API // gh-135906: Check for compiler warnings in the internal C API +# include "internal/pycore_backoff.h" # include "internal/pycore_frame.h" #endif diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 60feab225a1..df79840088a 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -918,6 +918,14 @@ class TestDictFields(unittest.TestCase): reader = csv.DictReader(f, fieldnames) self.assertEqual(reader.fieldnames, fieldnames) + def test_dict_reader_set_fieldnames(self): + fieldnames = ["a", "b", "c"] + f = StringIO() + reader = csv.DictReader(f) + self.assertIsNone(reader.fieldnames) + reader.fieldnames = fieldnames + self.assertEqual(reader.fieldnames, fieldnames) + def test_dict_writer_fieldnames_rejects_iter(self): fieldnames = ["a", "b", "c"] f = StringIO() @@ -933,6 +941,7 @@ class TestDictFields(unittest.TestCase): def test_dict_reader_fieldnames_is_optional(self): f = StringIO() reader = csv.DictReader(f, fieldnames=None) + self.assertIsNone(reader.fieldnames) def test_read_dict_fields(self): with TemporaryFile("w+", encoding="utf-8") as fileobj: @@ -1353,6 +1362,19 @@ ghijkl\0mno ghi\0jkl """ + sample15 = "\n\n\n" + sample16 = "abc\ndef\nghi" + + sample17 = ["letter,offset"] + sample17.extend(f"{chr(ord('a') + i)},{i}" for i in range(20)) + sample17.append("v,twenty_one") # 'u' was skipped + sample17 = '\n'.join(sample17) + + sample18 = ["letter,offset"] + sample18.extend(f"{chr(ord('a') + i)},{i}" for i in range(21)) + sample18.append("v,twenty_one") # 'u' was not skipped + sample18 = '\n'.join(sample18) + def test_issue43625(self): sniffer = csv.Sniffer() self.assertTrue(sniffer.has_header(self.sample12)) @@ -1374,6 +1396,11 @@ ghi\0jkl self.assertIs(sniffer.has_header(self.sample8), False) self.assertIs(sniffer.has_header(self.header2 + self.sample8), True) + def test_has_header_checks_20_rows(self): + sniffer = csv.Sniffer() + self.assertFalse(sniffer.has_header(self.sample17)) + self.assertTrue(sniffer.has_header(self.sample18)) + def test_guess_quote_and_delimiter(self): sniffer = csv.Sniffer() for header in (";'123;4';", "'123;4';", ";'123;4'", "'123;4'"): @@ -1423,6 +1450,10 @@ ghi\0jkl self.assertEqual(dialect.quotechar, "'") dialect = sniffer.sniff(self.sample14) self.assertEqual(dialect.delimiter, '\0') + self.assertRaisesRegex(csv.Error, "Could not determine delimiter", + sniffer.sniff, self.sample15) + self.assertRaisesRegex(csv.Error, "Could not determine delimiter", + sniffer.sniff, self.sample16) def test_doublequote(self): sniffer = csv.Sniffer() @@ -1437,6 +1468,56 @@ ghi\0jkl dialect = sniffer.sniff(self.sample9) self.assertTrue(dialect.doublequote) + def test_guess_delimiter_crlf_not_chosen(self): + # Ensure that we pick the real delimiter ("|") over "\r" in a tie. + sniffer = csv.Sniffer() + sample = "a|b\r\nc|d\r\ne|f\r\n" + self.assertEqual(sniffer.sniff(sample).delimiter, "|") + self.assertNotEqual(sniffer.sniff(sample).delimiter, "\r") + + def test_zero_mode_tie_order_independence(self): + sniffer = csv.Sniffer() + # ":" appears in half the rows (1, 0, 1, 0) - a tie between + # 0 and 1 per line. + # "," appears once every row (true delimiter). + # + # Even if the zero-frequency bucket is appended vs. inserted, the tie + # yields an adjusted score of 0, so ":" should not be promoted and + # "," must be selected. + sample = ( + "a,b:c\n" + "d,e\n" + "f,g:c\n" + "h,i\n" + ) + dialect = sniffer.sniff(sample) + self.assertEqual(dialect.delimiter, ",") + + def test_zero_mode_tie_order_comma_first(self): + sniffer = csv.Sniffer() + pattern = ( + "a,b\n" + "c:d\n" + "e,f\n" + "g:h\n" + ) + sample = pattern * 10 + with self.assertRaisesRegex(csv.Error, "Could not determine delimiter"): + sniffer.sniff(sample) + + def test_zero_mode_tie_order_colon_first(self): + sniffer = csv.Sniffer() + pattern = ( + "a:b\n" + "c,d\n" + "e:f\n" + "g,h\n" + ) + sample = pattern * 10 + with self.assertRaisesRegex(csv.Error, "Could not determine delimiter"): + sniffer.sniff(sample) + + class NUL: def write(s, *args): pass @@ -1603,5 +1684,16 @@ class MiscTestCase(unittest.TestCase): with self.subTest(tp=tp): check_disallow_instantiation(self, tp) + +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(csv, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/__init__.py b/Lib/test/test_ctypes/__init__.py index eb9126cbe18..d848beb1ff1 100644 --- a/Lib/test/test_ctypes/__init__.py +++ b/Lib/test/test_ctypes/__init__.py @@ -1,4 +1,5 @@ import os +import unittest from test import support from test.support import import_helper @@ -6,5 +7,21 @@ from test.support import import_helper # skip tests if the _ctypes extension was not built import_helper.import_module('ctypes') + +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + import ctypes + import _ctypes + + for mod in (ctypes, _ctypes): + with self.subTest(mod=mod): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(mod, "__version__") + self.assertEqual(cm.filename, __file__) + + def load_tests(*args): return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_ctypes/test_dlerror.py b/Lib/test/test_ctypes/test_dlerror.py index 8af34e62b94..5658234f9ec 100644 --- a/Lib/test/test_ctypes/test_dlerror.py +++ b/Lib/test/test_ctypes/test_dlerror.py @@ -32,6 +32,7 @@ void *foo(void) @unittest.skipUnless(sys.platform.startswith('linux'), 'test requires GNU IFUNC support') +@unittest.skipIf(test.support.linked_to_musl(), "Requires glibc") class TestNullDlsym(unittest.TestCase): """GH-126554: Ensure that we catch NULL dlsym return values diff --git a/Lib/test/test_ctypes/test_find.py b/Lib/test/test_ctypes/test_find.py index 3bd41a0e435..8bc84c3d2ef 100644 --- a/Lib/test/test_ctypes/test_find.py +++ b/Lib/test/test_ctypes/test_find.py @@ -153,5 +153,73 @@ class FindLibraryAndroid(unittest.TestCase): self.assertIsNone(find_library(name)) +@unittest.skipUnless(test.support.is_emscripten, + 'Test only valid for Emscripten') +class FindLibraryEmscripten(unittest.TestCase): + @classmethod + def setUpClass(cls): + import tempfile + + # A very simple wasm module + # In WAT format: (module) + cls.wasm_module = b'\x00asm\x01\x00\x00\x00\x00\x08\x04name\x02\x01\x00' + + cls.non_wasm_content = b'This is not a WASM file' + + cls.temp_dir = tempfile.mkdtemp() + cls.libdummy_so_path = os.path.join(cls.temp_dir, 'libdummy.so') + with open(cls.libdummy_so_path, 'wb') as f: + f.write(cls.wasm_module) + + cls.libother_wasm_path = os.path.join(cls.temp_dir, 'libother.wasm') + with open(cls.libother_wasm_path, 'wb') as f: + f.write(cls.wasm_module) + + cls.libnowasm_so_path = os.path.join(cls.temp_dir, 'libnowasm.so') + with open(cls.libnowasm_so_path, 'wb') as f: + f.write(cls.non_wasm_content) + + @classmethod + def tearDownClass(cls): + import shutil + shutil.rmtree(cls.temp_dir) + + def test_find_wasm_file_with_so_extension(self): + with os_helper.EnvironmentVarGuard() as env: + env.set('LD_LIBRARY_PATH', self.temp_dir) + result = find_library('dummy') + self.assertEqual(result, self.libdummy_so_path) + def test_find_wasm_file_with_wasm_extension(self): + with os_helper.EnvironmentVarGuard() as env: + env.set('LD_LIBRARY_PATH', self.temp_dir) + result = find_library('other') + self.assertEqual(result, self.libother_wasm_path) + + def test_ignore_non_wasm_file(self): + with os_helper.EnvironmentVarGuard() as env: + env.set('LD_LIBRARY_PATH', self.temp_dir) + result = find_library('nowasm') + self.assertIsNone(result) + + def test_find_nothing_without_ld_library_path(self): + with os_helper.EnvironmentVarGuard() as env: + if 'LD_LIBRARY_PATH' in env: + del env['LD_LIBRARY_PATH'] + result = find_library('dummy') + self.assertIsNone(result) + result = find_library('other') + self.assertIsNone(result) + + def test_find_nothing_with_wrong_ld_library_path(self): + import tempfile + with tempfile.TemporaryDirectory() as empty_dir: + with os_helper.EnvironmentVarGuard() as env: + env.set('LD_LIBRARY_PATH', empty_dir) + result = find_library('dummy') + self.assertIsNone(result) + result = find_library('other') + self.assertIsNone(result) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_loading.py b/Lib/test/test_ctypes/test_loading.py index 13ed813ad98..3b8332fbb30 100644 --- a/Lib/test/test_ctypes/test_loading.py +++ b/Lib/test/test_ctypes/test_loading.py @@ -100,6 +100,12 @@ class LoaderTest(unittest.TestCase): self.assertRaises(AttributeError, dll.__getitem__, 1234) + @unittest.skipUnless(os.name == "nt", 'Windows-specific test') + def test_load_without_name_and_with_handle(self): + handle = ctypes.windll.kernel32._handle + lib = ctypes.WinDLL(name=None, handle=handle) + self.assertIs(handle, lib._handle) + @unittest.skipUnless(os.name == "nt", 'Windows-specific test') def test_1703286_A(self): # On winXP 64-bit, advapi32 loads at an address that does diff --git a/Lib/test/test_ctypes/test_macholib.py b/Lib/test/test_ctypes/test_macholib.py index 9d906179956..9a5e18ed589 100644 --- a/Lib/test/test_ctypes/test_macholib.py +++ b/Lib/test/test_ctypes/test_macholib.py @@ -108,5 +108,17 @@ class MachOTest(unittest.TestCase): d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug')) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + import ctypes.macholib + + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(ctypes.macholib, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_prototypes.py b/Lib/test/test_ctypes/test_prototypes.py index 63ae799ea86..d976e8da0e2 100644 --- a/Lib/test/test_ctypes/test_prototypes.py +++ b/Lib/test/test_ctypes/test_prototypes.py @@ -72,6 +72,32 @@ class CharPointersTestCase(unittest.TestCase): self.assertEqual(func(None), None) self.assertEqual(func(input=None), None) + def test_invalid_paramflags(self): + proto = CFUNCTYPE(c_int, c_char_p) + with self.assertRaises(ValueError): + func = proto(("myprintf", testdll), ((1, "fmt"), (1, "arg1"))) + + def test_invalid_setattr_argtypes(self): + proto = CFUNCTYPE(c_int, c_char_p) + func = proto(("myprintf", testdll), ((1, "fmt"),)) + + with self.assertRaisesRegex(TypeError, "_argtypes_ must be a sequence of types"): + func.argtypes = 123 + self.assertEqual(func.argtypes, (c_char_p,)) + + with self.assertRaisesRegex(ValueError, "paramflags must have the same length as argtypes"): + func.argtypes = (c_char_p, c_int) + self.assertEqual(func.argtypes, (c_char_p,)) + + def test_paramflags_outarg(self): + proto = CFUNCTYPE(c_int, c_char_p, c_int) + with self.assertRaisesRegex(TypeError, "must be a pointer type"): + func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out"))) + + proto = CFUNCTYPE(c_int, c_char_p, c_void_p) + func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out"))) + with self.assertRaisesRegex(TypeError, "must be a pointer type"): + func.argtypes = (c_char_p, c_int) def test_int_pointer_arg(self): func = testdll._testfunc_p_p diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index 6bf5e5b3e55..3b335429b98 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -927,6 +927,20 @@ class TestCase(unittest.TestCase): validate_class(C) + def test_incomplete_annotations(self): + # gh-142214 + @dataclass + class C: + "doc" # needed because otherwise we fetch the annotations at the wrong time + x: int + + C.__annotate__ = lambda _: {} + + self.assertEqual( + annotationlib.get_annotations(C.__init__), + {"return": None} + ) + def test_missing_default(self): # Test that MISSING works the same as a default not being # specified. @@ -2471,6 +2485,149 @@ class TestInit(unittest.TestCase): self.assertEqual(D(5).a, 10) +class TestInitAnnotate(unittest.TestCase): + # Tests for the generated __annotate__ function for __init__ + # See: https://github.com/python/cpython/issues/137530 + + def test_annotate_function(self): + # No forward references + @dataclass + class A: + a: int + + value_annos = annotationlib.get_annotations(A.__init__, format=annotationlib.Format.VALUE) + forwardref_annos = annotationlib.get_annotations(A.__init__, format=annotationlib.Format.FORWARDREF) + string_annos = annotationlib.get_annotations(A.__init__, format=annotationlib.Format.STRING) + + self.assertEqual(value_annos, {'a': int, 'return': None}) + self.assertEqual(forwardref_annos, {'a': int, 'return': None}) + self.assertEqual(string_annos, {'a': 'int', 'return': 'None'}) + + self.assertTrue(getattr(A.__init__.__annotate__, "__generated_by_dataclasses__")) + + def test_annotate_function_forwardref(self): + # With forward references + @dataclass + class B: + b: undefined + + # VALUE annotations should raise while unresolvable + with self.assertRaises(NameError): + _ = annotationlib.get_annotations(B.__init__, format=annotationlib.Format.VALUE) + + forwardref_annos = annotationlib.get_annotations(B.__init__, format=annotationlib.Format.FORWARDREF) + string_annos = annotationlib.get_annotations(B.__init__, format=annotationlib.Format.STRING) + + self.assertEqual(forwardref_annos, {'b': support.EqualToForwardRef('undefined', owner=B, is_class=True), 'return': None}) + self.assertEqual(string_annos, {'b': 'undefined', 'return': 'None'}) + + # Now VALUE and FORWARDREF should resolve, STRING should be unchanged + undefined = int + + value_annos = annotationlib.get_annotations(B.__init__, format=annotationlib.Format.VALUE) + forwardref_annos = annotationlib.get_annotations(B.__init__, format=annotationlib.Format.FORWARDREF) + string_annos = annotationlib.get_annotations(B.__init__, format=annotationlib.Format.STRING) + + self.assertEqual(value_annos, {'b': int, 'return': None}) + self.assertEqual(forwardref_annos, {'b': int, 'return': None}) + self.assertEqual(string_annos, {'b': 'undefined', 'return': 'None'}) + + def test_annotate_function_init_false(self): + # Check `init=False` attributes don't get into the annotations of the __init__ function + @dataclass + class C: + c: str = field(init=False) + + self.assertEqual(annotationlib.get_annotations(C.__init__), {'return': None}) + + def test_annotate_function_contains_forwardref(self): + # Check string annotations on objects containing a ForwardRef + @dataclass + class D: + d: list[undefined] + + with self.assertRaises(NameError): + annotationlib.get_annotations(D.__init__) + + self.assertEqual( + annotationlib.get_annotations(D.__init__, format=annotationlib.Format.FORWARDREF), + {"d": list[support.EqualToForwardRef("undefined", is_class=True, owner=D)], "return": None} + ) + + self.assertEqual( + annotationlib.get_annotations(D.__init__, format=annotationlib.Format.STRING), + {"d": "list[undefined]", "return": "None"} + ) + + # Now test when it is defined + undefined = str + + # VALUE should now resolve + self.assertEqual( + annotationlib.get_annotations(D.__init__), + {"d": list[str], "return": None} + ) + + self.assertEqual( + annotationlib.get_annotations(D.__init__, format=annotationlib.Format.FORWARDREF), + {"d": list[str], "return": None} + ) + + self.assertEqual( + annotationlib.get_annotations(D.__init__, format=annotationlib.Format.STRING), + {"d": "list[undefined]", "return": "None"} + ) + + def test_annotate_function_not_replaced(self): + # Check that __annotate__ is not replaced on non-generated __init__ functions + @dataclass(slots=True) + class E: + x: str + def __init__(self, x: int) -> None: + self.x = x + + self.assertEqual( + annotationlib.get_annotations(E.__init__), {"x": int, "return": None} + ) + + self.assertFalse(hasattr(E.__init__.__annotate__, "__generated_by_dataclasses__")) + + def test_slots_true_init_false(self): + # Test that slots=True and init=False work together and + # that __annotate__ is not added to __init__. + + @dataclass(slots=True, init=False) + class F: + x: int + + f = F() + f.x = 10 + self.assertEqual(f.x, 10) + + self.assertFalse(hasattr(F.__init__, "__annotate__")) + + def test_init_false_forwardref(self): + # Test forward references in fields not required for __init__ annotations. + + # At the moment this raises a NameError for VALUE annotations even though the + # undefined annotation is not required for the __init__ annotations. + # Ideally this will be fixed but currently there is no good way to resolve this + + @dataclass + class F: + not_in_init: list[undefined] = field(init=False, default=None) + in_init: int + + annos = annotationlib.get_annotations(F.__init__, format=annotationlib.Format.FORWARDREF) + self.assertEqual( + annos, + {"in_init": int, "return": None}, + ) + + with self.assertRaises(NameError): + annos = annotationlib.get_annotations(F.__init__) # NameError on not_in_init + + class TestRepr(unittest.TestCase): def test_repr(self): @dataclass @@ -3831,7 +3988,15 @@ class TestSlots(unittest.TestCase): return SlotsTest - for make in (make_simple, make_with_annotations, make_with_annotations_and_method): + def make_with_forwardref(): + @dataclass(slots=True) + class SlotsTest: + x: undefined + y: list[undefined] + + return SlotsTest + + for make in (make_simple, make_with_annotations, make_with_annotations_and_method, make_with_forwardref): with self.subTest(make=make): C = make() support.gc_collect() diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py index e0b988b7b95..66268c42a30 100644 --- a/Lib/test/test_dbm_gnu.py +++ b/Lib/test/test_dbm_gnu.py @@ -74,12 +74,12 @@ class TestGdbm(unittest.TestCase): # Test the flag parameter open() by trying all supported flag modes. all = set(gdbm.open_flags) # Test standard flags (presumably "crwn"). - modes = all - set('fsum') + modes = all - set('fsu') for mode in sorted(modes): # put "c" mode first self.g = gdbm.open(filename, mode) self.g.close() - # Test additional flags (presumably "fsum"). + # Test additional flags (presumably "fsu"). flags = all - set('crwn') for mode in modes: for flag in flags: @@ -217,29 +217,6 @@ class TestGdbm(unittest.TestCase): create_empty_file(os.path.join(d, 'test')) self.assertRaises(gdbm.error, gdbm.open, filename, 'r') - @unittest.skipUnless('m' in gdbm.open_flags, "requires 'm' in open_flags") - def test_nommap_no_crash(self): - self.g = g = gdbm.open(filename, 'nm') - os.truncate(filename, 0) - - g.get(b'a', b'c') - g.keys() - g.firstkey() - g.nextkey(b'a') - with self.assertRaises(KeyError): - g[b'a'] - with self.assertRaises(gdbm.error): - len(g) - - with self.assertRaises(gdbm.error): - g[b'a'] = b'c' - with self.assertRaises(gdbm.error): - del g[b'a'] - with self.assertRaises(gdbm.error): - g.setdefault(b'a', b'c') - with self.assertRaises(gdbm.error): - g.reorganize() - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 08a8f4c3b36..b520b062ebc 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -4474,7 +4474,7 @@ class CheckAttributes(unittest.TestCase): self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False) self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False) - self.assertEqual(C.__version__, P.__version__) + self.assertEqual(C.SPEC_VERSION, P.SPEC_VERSION) self.assertLessEqual(set(dir(C)), set(dir(P))) self.assertEqual([n for n in dir(C) if n[:2] != '__'], sorted(P.__all__)) @@ -5929,6 +5929,23 @@ class SignatureTest(unittest.TestCase): doit('Context') +class TestModule: + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(self.decimal, "__version__") + self.assertEqual(cm.filename, __file__) + + +@requires_cdecimal +class CTestModule(TestModule, unittest.TestCase): + decimal = C +class PyTestModule(TestModule, unittest.TestCase): + decimal = P + + def load_tests(loader, tests, pattern): if TODO_TESTS is not None: # Run only Arithmetic tests diff --git a/Lib/test/test_defaultdict.py b/Lib/test/test_defaultdict.py index bdbe9b81e8f..fbd7354a915 100644 --- a/Lib/test/test_defaultdict.py +++ b/Lib/test/test_defaultdict.py @@ -186,5 +186,23 @@ class TestDefaultDict(unittest.TestCase): with self.assertRaises(TypeError): i |= None + def test_factory_conflict_with_set_value(self): + key = "conflict_test" + count = 0 + + def default_factory(): + nonlocal count + count += 1 + local_count = count + if count == 1: + test_dict[key] + return local_count + + test_dict = defaultdict(default_factory) + + self.assertEqual(count, 0) + self.assertEqual(test_dict[key], 2) + self.assertEqual(count, 2) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 9dfeeccb81b..82a48ad4d1a 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1329,18 +1329,17 @@ class ClassPropertiesAndMethods(unittest.TestCase): self.assertNotHasAttr(a, "__weakref__") a.foo = 42 self.assertEqual(a.__dict__, {"foo": 42}) + with self.assertRaises(TypeError): + weakref.ref(a) class W(object): __slots__ = ["__weakref__"] a = W() self.assertHasAttr(a, "__weakref__") self.assertNotHasAttr(a, "__dict__") - try: + with self.assertRaises(AttributeError): a.foo = 42 - except AttributeError: - pass - else: - self.fail("shouldn't be allowed to set a.foo") + self.assertIs(weakref.ref(a)(), a) class C1(W, D): __slots__ = [] @@ -1349,6 +1348,7 @@ class ClassPropertiesAndMethods(unittest.TestCase): self.assertHasAttr(a, "__weakref__") a.foo = 42 self.assertEqual(a.__dict__, {"foo": 42}) + self.assertIs(weakref.ref(a)(), a) class C2(D, W): __slots__ = [] @@ -1357,6 +1357,77 @@ class ClassPropertiesAndMethods(unittest.TestCase): self.assertHasAttr(a, "__weakref__") a.foo = 42 self.assertEqual(a.__dict__, {"foo": 42}) + self.assertIs(weakref.ref(a)(), a) + + @unittest.skipIf(_testcapi is None, 'need the _testcapi module') + def test_slots_special_before_items(self): + class D(_testcapi.HeapCCollection): + __slots__ = ["__dict__"] + a = D(1, 2, 3) + self.assertHasAttr(a, "__dict__") + self.assertNotHasAttr(a, "__weakref__") + a.foo = 42 + self.assertEqual(a.__dict__, {"foo": 42}) + with self.assertRaises(TypeError): + weakref.ref(a) + del a.__dict__ + self.assertNotHasAttr(a, "foo") + self.assertEqual(a.__dict__, {}) + self.assertEqual(list(a), [1, 2, 3]) + + class W(_testcapi.HeapCCollection): + __slots__ = ["__weakref__"] + a = W(1, 2, 3) + self.assertHasAttr(a, "__weakref__") + self.assertNotHasAttr(a, "__dict__") + with self.assertRaises(AttributeError): + a.foo = 42 + self.assertIs(weakref.ref(a)(), a) + + with self.assertRaises(TypeError): + class X(_testcapi.HeapCCollection): + __slots__ = ['x'] + + with self.assertRaises(TypeError): + class X(_testcapi.HeapCCollection): + __slots__ = ['__dict__', 'x'] + + @support.subTests(('base', 'arg'), [ + (tuple, (1, 2, 3)), + (int, 9876543210**2), + (bytes, b'ab'), + ]) + def test_slots_special_after_items(self, base, arg): + class D(base): + __slots__ = ["__dict__"] + a = D(arg) + self.assertHasAttr(a, "__dict__") + self.assertNotHasAttr(a, "__weakref__") + a.foo = 42 + self.assertEqual(a.__dict__, {"foo": 42}) + with self.assertRaises(TypeError): + weakref.ref(a) + del a.__dict__ + self.assertNotHasAttr(a, "foo") + self.assertEqual(a.__dict__, {}) + self.assertEqual(a, base(arg)) + + class W(base): + __slots__ = ["__weakref__"] + a = W(arg) + self.assertHasAttr(a, "__weakref__") + self.assertNotHasAttr(a, "__dict__") + with self.assertRaises(AttributeError): + a.foo = 42 + self.assertIs(weakref.ref(a)(), a) + self.assertEqual(a, base(arg)) + + with self.assertRaises(TypeError): + class X(base): + __slots__ = ['x'] + with self.assertRaises(TypeError): + class X(base): + __slots__ = ['__dict__', 'x'] def test_slots_special2(self): # Testing __qualname__ and __classcell__ in __slots__ @@ -4077,42 +4148,167 @@ class ClassPropertiesAndMethods(unittest.TestCase): self.assertEqual(e.a, 2) self.assertEqual(C2.__subclasses__(), [D]) - try: + with self.assertRaisesRegex(TypeError, + "cannot delete '__bases__' attribute of type 'D'"): del D.__bases__ - except (TypeError, AttributeError): - pass - else: - self.fail("shouldn't be able to delete .__bases__") - - try: + with self.assertRaisesRegex(TypeError, 'can only assign non-empty tuple'): D.__bases__ = () - except TypeError as msg: - if str(msg) == "a new-style class can't have only classic bases": - self.fail("wrong error message for .__bases__ = ()") - else: - self.fail("shouldn't be able to set .__bases__ to ()") - - try: - D.__bases__ = (D,) - except TypeError: - pass - else: - # actually, we'll have crashed by here... - self.fail("shouldn't be able to create inheritance cycles") - - try: + with self.assertRaisesRegex(TypeError, 'can only assign tuple'): + D.__bases__ = [C] + with self.assertRaisesRegex(TypeError, 'duplicate base class'): D.__bases__ = (C, C) - except TypeError: - pass - else: - self.fail("didn't detect repeated base classes") - - try: + with self.assertRaisesRegex(TypeError, 'inheritance cycle'): + D.__bases__ = (D,) + with self.assertRaisesRegex(TypeError, 'inheritance cycle'): D.__bases__ = (E,) - except TypeError: + + class A: + __slots__ = () + def __repr__(self): + return '' + class A_with_dict: + __slots__ = ('__dict__',) + def __repr__(self): + return '' + class A_with_dict_weakref: + def __repr__(self): + return '' + class A_with_slots: + __slots__ = ('x',) + def __repr__(self): + return '' + class A_with_slots_dict: + __slots__ = ('x', '__dict__') + def __repr__(self): + return '' + + class B: + __slots__ = () + b = B() + r = repr(b) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B.__bases__ = (int,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B.__bases__ = (A_with_dict_weakref,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B.__bases__ = (A_with_dict,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B.__bases__ = (A_with_slots,) + B.__bases__ = (A,) + self.assertNotHasAttr(b, '__dict__') + self.assertNotHasAttr(b, '__weakref__') + self.assertEqual(repr(b), '') + B.__bases__ = (object,) + self.assertEqual(repr(b), r) + + class B_with_dict_weakref: pass - else: - self.fail("shouldn't be able to create inheritance cycles") + b = B_with_dict_weakref() + with self.assertRaisesRegex(TypeError, 'layout differs'): + B.__bases__ = (A_with_slots,) + B_with_dict_weakref.__bases__ = (A_with_dict_weakref,) + self.assertEqual(repr(b), '') + B_with_dict_weakref.__bases__ = (A_with_dict,) + self.assertEqual(repr(b), '') + B_with_dict_weakref.__bases__ = (A,) + self.assertEqual(repr(b), '') + B_with_dict_weakref.__bases__ = (object,) + + class B_with_slots: + __slots__ = ('x',) + b = B_with_slots() + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_with_slots.__bases__ = (A_with_dict_weakref,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_with_slots.__bases__ = (A_with_dict,) + B_with_slots.__bases__ = (A,) + self.assertEqual(repr(b), '') + + class B_with_slots_dict: + __slots__ = ('x', '__dict__') + b = B_with_slots_dict() + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_with_slots_dict.__bases__ = (A_with_dict_weakref,) + B_with_slots_dict.__bases__ = (A_with_dict,) + self.assertEqual(repr(b), '') + B_with_slots_dict.__bases__ = (A,) + self.assertEqual(repr(b), '') + + class B_with_slots_dict_weakref: + __slots__ = ('x', '__dict__', '__weakref__') + b = B_with_slots_dict_weakref() + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_with_slots_dict_weakref.__bases__ = (A_with_slots_dict,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_with_slots_dict_weakref.__bases__ = (A_with_slots,) + B_with_slots_dict_weakref.__bases__ = (A_with_dict_weakref,) + self.assertEqual(repr(b), '') + B_with_slots_dict_weakref.__bases__ = (A_with_dict,) + self.assertEqual(repr(b), '') + B_with_slots_dict_weakref.__bases__ = (A,) + self.assertEqual(repr(b), '') + + class C_with_slots(A_with_slots): + __slots__ = () + c = C_with_slots() + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots.__bases__ = (A_with_slots_dict,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots.__bases__ = (A_with_dict_weakref,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots.__bases__ = (A_with_dict,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots.__bases__ = (A,) + C_with_slots.__bases__ = (A_with_slots,) + self.assertEqual(repr(c), '') + + class C_with_slots_dict(A_with_slots): + pass + c = C_with_slots_dict() + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots_dict.__bases__ = (A_with_dict_weakref,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots_dict.__bases__ = (A_with_dict,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + C_with_slots_dict.__bases__ = (A,) + C_with_slots_dict.__bases__ = (A_with_slots_dict,) + self.assertEqual(repr(c), '') + C_with_slots_dict.__bases__ = (A_with_slots,) + self.assertEqual(repr(c), '') + + class A_int(int): + __slots__ = () + def __repr__(self): + return '' + class B_int(int): + __slots__ = () + b = B_int(42) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_int.__bases__ = (object,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_int.__bases__ = (tuple,) + with self.assertRaisesRegex(TypeError, 'is not an acceptable base type'): + B_int.__bases__ = (bool,) + B_int.__bases__ = (A_int,) + self.assertEqual(repr(b), '') + B_int.__bases__ = (int,) + self.assertEqual(repr(b), '42') + + class A_tuple(tuple): + __slots__ = () + def __repr__(self): + return '' + class B_tuple(tuple): + __slots__ = () + b = B_tuple((1, 2)) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_tuple.__bases__ = (object,) + with self.assertRaisesRegex(TypeError, 'layout differs'): + B_tuple.__bases__ = (int,) + B_tuple.__bases__ = (A_tuple,) + self.assertEqual(repr(b), '') + B_tuple.__bases__ = (tuple,) + self.assertEqual(repr(b), '(1, 2)') def test_assign_bases_many_subclasses(self): # This is intended to check that typeobject.c:queue_slot_update() can @@ -4165,26 +4361,14 @@ class ClassPropertiesAndMethods(unittest.TestCase): class D(C): pass - try: + with self.assertRaisesRegex(TypeError, 'layout differs'): L.__bases__ = (dict,) - except TypeError: - pass - else: - self.fail("shouldn't turn list subclass into dict subclass") - try: + with self.assertRaisesRegex(TypeError, 'immutable type'): list.__bases__ = (dict,) - except TypeError: - pass - else: - self.fail("shouldn't be able to assign to list.__bases__") - try: + with self.assertRaisesRegex(TypeError, 'layout differs'): D.__bases__ = (C, list) - except TypeError: - pass - else: - self.fail("best_base calculation found wanting") def test_unsubclassable_types(self): with self.assertRaises(TypeError): @@ -4949,7 +5133,7 @@ class ClassPropertiesAndMethods(unittest.TestCase): with self.assertRaises(TypeError) as cm: type(X).__dict__["__doc__"].__delete__(X) - self.assertIn("cannot delete '__doc__' attribute of immutable type 'X'", str(cm.exception)) + self.assertIn("cannot delete '__doc__' attribute of type 'X'", str(cm.exception)) self.assertEqual(X.__doc__, "banana") def test_qualname(self): diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 60c62430370..665b3e843dd 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1601,6 +1601,34 @@ class DictTest(unittest.TestCase): with self.assertRaises(KeyError): d.get(key2) + def test_clear_at_lookup(self): + class X: + def __hash__(self): + return 1 + def __eq__(self, other): + nonlocal d + d.clear() + + d = {} + for _ in range(10): + d[X()] = None + + self.assertEqual(len(d), 1) + + d = {} + for _ in range(10): + d.setdefault(X(), None) + + self.assertEqual(len(d), 1) + + def test_split_table_update_with_str_subclass(self): + class MyStr(str): pass + class MyClass: pass + obj = MyClass() + obj.attr = 1 + obj.__dict__[MyStr('attr')] = 2 + self.assertEqual(obj.attr, 2) + class CAPITest(unittest.TestCase): diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index 0eab3f523dc..771fd46e042 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -29,6 +29,16 @@ class TestWithAscii(unittest.TestCase): ('delete', 40, 41, 40, 40), ('equal', 41, 81, 40, 80)]) + def test_opcode_caching(self): + sm = difflib.SequenceMatcher(None, 'b' * 100, 'a' + 'b' * 100) + opcode = sm.get_opcodes() + self.assertEqual(opcode, + [ ('insert', 0, 0, 0, 1), + ('equal', 0, 100, 1, 101)]) + # Implementation detail: opcodes are cached; + # `get_opcodes()` returns the same object + self.assertIs(opcode, sm.get_opcodes()) + def test_bjunk(self): sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40) @@ -293,6 +303,15 @@ class TestDiffer(unittest.TestCase): '+ kitten\n', '+ puppy\n']) + def test_one_insert(self): + m = difflib.Differ().compare('b' * 2, 'a' + 'b' * 2) + self.assertEqual(list(m), ['+ a', ' b', ' b']) + + def test_one_delete(self): + m = difflib.Differ().compare('a' + 'b' * 2, 'b' * 2) + self.assertEqual(list(m), ['- a', ' b', ' b']) + + class TestOutputFormat(unittest.TestCase): def test_tab_delimiter(self): args = [['one'], ['two'], 'Original', 'Current', @@ -601,6 +620,26 @@ class TestFindLongest(unittest.TestCase): self.assertFalse(self.longer_match_exists(a, b, match.size)) +class TestCloseMatches(unittest.TestCase): + # Happy paths are tested in the doctests of `difflib.get_close_matches`. + + def test_invalid_inputs(self): + self.assertRaises(ValueError, difflib.get_close_matches, "spam", ['egg'], n=0) + self.assertRaises(ValueError, difflib.get_close_matches, "spam", ['egg'], n=-1) + self.assertRaises(ValueError, difflib.get_close_matches, "spam", ['egg'], cutoff=1.1) + self.assertRaises(ValueError, difflib.get_close_matches, "spam", ['egg'], cutoff=-0.1) + + +class TestRestore(unittest.TestCase): + # Happy paths are tested in the doctests of `difflib.restore`. + + def test_invalid_input(self): + with self.assertRaises(ValueError): + ''.join(difflib.restore([], 0)) + with self.assertRaises(ValueError): + ''.join(difflib.restore([], 3)) + + def setUpModule(): difflib.HtmlDiff._default_prefix = 0 diff --git a/Lib/test/test_difflib_expect.html b/Lib/test/test_difflib_expect.html index 2346a6f9f8d..240e2c33368 100644 --- a/Lib/test/test_difflib_expect.html +++ b/Lib/test/test_difflib_expect.html @@ -59,11 +59,11 @@ - - - - - + + + + + @@ -75,11 +75,11 @@ - - - - - + + + + + @@ -91,11 +91,11 @@ - - - - - + + + + + @@ -133,11 +133,11 @@ - - - - - + + + + + @@ -150,11 +150,11 @@ - - - - - + + + + + @@ -167,11 +167,11 @@ - - - - - + + + + + @@ -192,11 +192,11 @@ - - - - - + + + + + @@ -209,11 +209,11 @@ - - - - - + + + + + @@ -226,11 +226,11 @@ - - - - - + + + + + @@ -247,11 +247,11 @@ - - - - - + + + + + @@ -263,11 +263,11 @@ - - - - - + + + + + @@ -279,11 +279,11 @@ - - - - - + + + + + @@ -300,25 +300,25 @@ - - - - - + + + + + - - - - - + + + + + - - - - - + + + + +

    from
    to
    f1f1
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    61236123
    71237123
    81238123
    1412314123
    1512315123
    1616
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    2112321123
    2212322123
    2312323123
    2912329123
    3012330123
    3131
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    3612336123
    3712337123
    3812338123

    from
    to
    f1f1
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    61236123
    71237123
    81238123
    1412314123
    1512315123
    1616
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    2112321123
    2212322123
    2312323123
    2912329123
    3012330123
    3131
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    3612336123
    3712337123
    3812338123
    94569456
    1045610456
    1111
    n12   1. Beautiful is beTTer than ugly.n12   1. Beautiful is better than ugly.
    13   2. Explicit is better than implicit.
    14   3. Simple is better than complex.13   3.   Simple is better than complex.
    15   4. Complex is better than complicated.14   4. Complicated is better than complex.
    15   5. Flat is better than nested.
    n12   1. Beautiful is beTTer than ugly.n12   1. Beautiful is better than ugly.
    13   2. Explicit is better than implicit.
    14   3. Simple is better than complex.13   3.   Simple is better than complex.
    15   4. Complex is better than complicated.14   4. Complicated is better than complex.
    15   5. Flat is better than nested.
    1612316123
    1712317123
    1812318123
    2412324123
    2512325123
    2626
    n27   1. Beautiful is beTTer than ugly.n27   1. Beautiful is better than ugly.
    28   2. Explicit is better than implicit.
    29   3. Simple is better than complex.28   3.   Simple is better than complex.
    30   4. Complex is better than complicated.29   4. Complicated is better than complex.
    30   5. Flat is better than nested.
    n27   1. Beautiful is beTTer than ugly.n27   1. Beautiful is better than ugly.
    28   2. Explicit is better than implicit.
    29   3. Simple is better than complex.28   3.   Simple is better than complex.
    30   4. Complex is better than complicated.29   4. Complicated is better than complex.
    30   5. Flat is better than nested.
    3112331123
    3212332123
    3312333123
    3912339123
    4012340123
    4141
    t42   1. Beautiful is beTTer than ugly.t42   1. Beautiful is better than ugly.
    43   2. Explicit is better than implicit.
    44   3. Simple is better than complex.43   3.   Simple is better than complex.
    45   4. Complex is better than complicated.44   4. Complicated is better than complex.
    45   5. Flat is better than nested.
    t42   1. Beautiful is beTTer than ugly.t42   1. Beautiful is better than ugly.
    43   2. Explicit is better than implicit.
    44   3. Simple is better than complex.43   3.   Simple is better than complex.
    45   4. Complex is better than complicated.44   4. Complicated is better than complex.
    45   5. Flat is better than nested.
    4612346123
    4712347123
    4812348123

    from
    to
    f1f1
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    61236123
    71237123
    81238123
    1412314123
    1512315123
    1616
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    2112321123
    2212322123
    2312323123
    2912329123
    3012330123
    3131
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    3612336123
    3712337123
    3812338123

    from
    to
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    n2   1. Beautiful is beTTer than ugly.n2   1. Beautiful is better than ugly.
    3   2. Explicit is better than implicit.
    4   3. Simple is better than complex.3   3.   Simple is better than complex.
    5   4. Complex is better than complicated.4   4. Complicated is better than complex.
    5   5. Flat is better than nested.
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    n17   1. Beautiful is beTTer than ugly.n17   1. Beautiful is better than ugly.
    18   2. Explicit is better than implicit.
    19   3. Simple is better than complex.18   3.   Simple is better than complex.
    20   4. Complex is better than complicated.19   4. Complicated is better than complex.
    20   5. Flat is better than nested.
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.
    t32   1. Beautiful is beTTer than ugly.t32   1. Beautiful is better than ugly.
    33   2. Explicit is better than implicit.
    34   3. Simple is better than complex.33   3.   Simple is better than complex.
    35   4. Complex is better than complicated.34   4. Complicated is better than complex.
    35   5. Flat is better than nested.

    Same Context

    @@ -418,11 +418,11 @@
    f1f1
    t2    Line 1: preceded by from:[tt] to:[ssss]t2    Line 1: preceded by from:[tt] to:[ssss]
    3      Line 2: preceded by from:[sstt] to:[sssst]3      Line 2: preceded by from:[sstt] to:[sssst]
    4      Line 3: preceded by from:[sstst] to:[ssssss]4      Line 3: preceded by from:[sstst] to:[ssssss]
    5Line 4:   has from:[sst] to:[sss] after :5Line 4:   has from:[sst] to:[sss] after :
    6Line 5: has from:[t] to:[ss] at end 6Line 5: has from:[t] to:[ss] at end
    t2    Line 1: preceded by from:[tt] to:[ssss]t2    Line 1: preceded by from:[tt] to:[ssss]
    3      Line 2: preceded by from:[sstt] to:[sssst]3      Line 2: preceded by from:[sstt] to:[sssst]
    4      Line 3: preceded by from:[sstst] to:[ssssss]4      Line 3: preceded by from:[sstst] to:[ssssss]
    5Line 4:   has from:[sst] to:[sss] after :5Line 4:   has from:[sst] to:[sss] after :
    6Line 5: has from:[t] to:[ss] at end 6Line 5: has from:[t] to:[ss] at end

    tabsize=default

    @@ -434,11 +434,11 @@
    f1f1
    t2                Line 1: preceded by from:[tt] to:[ssss]t2    Line 1: preceded by from:[tt] to:[ssss]
    3                Line 2: preceded by from:[sstt] to:[sssst]3        Line 2: preceded by from:[sstt] to:[sssst]
    4                Line 3: preceded by from:[sstst] to:[ssssss]4      Line 3: preceded by from:[sstst] to:[ssssss]
    5Line 4:         has from:[sst] to:[sss] after :5Line 4:   has from:[sst] to:[sss] after :
    6Line 5: has from:[t] to:[ss] at end     6Line 5: has from:[t] to:[ss] at end
    t2                Line 1: preceded by from:[tt] to:[ssss]t2    Line 1: preceded by from:[tt] to:[ssss]
    3                Line 2: preceded by from:[sstt] to:[sssst]3        Line 2: preceded by from:[sstt] to:[sssst]
    4                Line 3: preceded by from:[sstst] to:[ssssss]4      Line 3: preceded by from:[sstst] to:[ssssss]
    5Line 4:         has from:[sst] to:[sss] after :5Line 4:   has from:[sst] to:[sss] after :
    6Line 5: has from:[t] to:[ss] at end     6Line 5: has from:[t] to:[ss] at end

    Context (wrapcolumn=14,numlines=0)

    @@ -449,31 +449,31 @@
    n4line 2n4line 2    adde
     >d
    n4line 2n4line 2    adde
     >d
    n6line 4   changn6line 4   chanG
    >ed>Ed
    7line 5   chang7line 5a  chanG
    >ed>ed
    8line 6   chang8line 6a  chang
    >ed>Ed
    n6line 4   changn6line 4   chanG
    >ed>Ed
    7line 5   chang7line 5a  chanG
    >ed>ed
    8line 6   chang8line 6a  chang
    >ed>Ed
    n10line 8  subtran10line 8
    >cted 
    n10line 8  subtran10line 8
    >cted 
    t1212345678901234t121234567890
    >56789012345689 
    >012345 
    13short line13another long l
     >ine that needs
     > to be wrapped
    14just fits in!!14just fitS in!!
    15just fits in t15just fits in t
    >wo lines yup!!>wo lineS yup!!
    t1212345678901234t121234567890
    >56789012345689 
    >012345 
    13short line13another long l
     >ine that needs
     > to be wrapped
    14just fits in!!14just fitS in!!
    15just fits in t15just fits in t
    >wo lines yup!!>wo lineS yup!!

    wrapcolumn=14,splitlines()

    @@ -489,28 +489,28 @@
    >56789012345689>56789012345689
    >012345>012345
    3line 13line 1
    n4line 2n4line 2    adde
     >d
    n4line 2n4line 2    adde
     >d
    5line 35line 3
    n6line 4   changn6line 4   chanG
    >ed>Ed
    7line 5   chang7line 5a  chanG
    >ed>ed
    8line 6   chang8line 6a  chang
    >ed>Ed
    n6line 4   changn6line 4   chanG
    >ed>Ed
    7line 5   chang7line 5a  chanG
    >ed>ed
    8line 6   chang8line 6a  chang
    >ed>Ed
    9line 79line 7
    n10line 8  subtran10line 8
    >cted 
    n10line 8  subtran10line 8
    >cted 
    11line 911line 9
    t1212345678901234t121234567890
    >56789012345689 
    >012345 
    13short line13another long l
     >ine that needs
     > to be wrapped
    14just fits in!!14just fitS in!!
    15just fits in t15just fits in t
    >wo lines yup!!>wo lineS yup!!
    t1212345678901234t121234567890
    >56789012345689 
    >012345 
    13short line13another long l
     >ine that needs
     > to be wrapped
    14just fits in!!14just fitS in!!
    15just fits in t15just fits in t
    >wo lines yup!!>wo lineS yup!!
    16the end16the end
    @@ -527,28 +527,28 @@
    >56789012345689>56789012345689
    >012345>012345
    3line 13line 1
    n4line 2n4line 2    adde
     >d
    n4line 2n4line 2    adde
     >d
    5line 35line 3
    n6line 4   changn6line 4   chanG
    >ed>Ed
    7line 5   chang7line 5a  chanG
    >ed>ed
    8line 6   chang8line 6a  chang
    >ed>Ed
    n6line 4   changn6line 4   chanG
    >ed>Ed
    7line 5   chang7line 5a  chanG
    >ed>ed
    8line 6   chang8line 6a  chang
    >ed>Ed
    9line 79line 7
    n10line 8  subtran10line 8
    >cted 
    n10line 8  subtran10line 8
    >cted 
    11line 911line 9
    t1212345678901234t121234567890
    >56789012345689 
    >012345 
    13short line13another long l
     >ine that needs
     > to be wrapped
    14just fits in!!14just fitS in!!
    15just fits in t15just fits in t
    >wo lines yup!!>wo lineS yup!!
    t1212345678901234t121234567890
    >56789012345689 
    >012345 
    13short line13another long l
     >ine that needs
     > to be wrapped
    14just fits in!!14just fitS in!!
    15just fits in t15just fits in t
    >wo lines yup!!>wo lineS yup!!
    16the end16the end
    diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py index 0fa74407e3c..241d09db1fa 100644 --- a/Lib/test/test_doctest/test_doctest.py +++ b/Lib/test/test_doctest/test_doctest.py @@ -833,6 +833,118 @@ class TestDocTestFinder(unittest.TestCase): self.assertEqual(len(include_empty_finder.find(mod)), 1) self.assertEqual(len(exclude_empty_finder.find(mod)), 0) + def test_lineno_of_test_dict_strings(self): + """Test line numbers are found for __test__ dict strings.""" + module_content = '''\ +"""Module docstring.""" + +def dummy_function(): + """Dummy function docstring.""" + pass + +__test__ = { + 'test_string': """ + This is a test string. + >>> 1 + 1 + 2 + """, +} +''' + with tempfile.TemporaryDirectory() as tmpdir: + module_path = os.path.join(tmpdir, 'test_module_lineno.py') + with open(module_path, 'w') as f: + f.write(module_content) + + sys.path.insert(0, tmpdir) + try: + import test_module_lineno + finder = doctest.DocTestFinder() + tests = finder.find(test_module_lineno) + + test_dict_test = None + for test in tests: + if '__test__' in test.name: + test_dict_test = test + break + + self.assertIsNotNone( + test_dict_test, + "__test__ dict test not found" + ) + # gh-69113: line number should not be None for __test__ strings + self.assertIsNotNone( + test_dict_test.lineno, + "Line number should not be None for __test__ dict strings" + ) + self.assertGreater( + test_dict_test.lineno, + 0, + "Line number should be positive" + ) + finally: + if 'test_module_lineno' in sys.modules: + del sys.modules['test_module_lineno'] + sys.path.pop(0) + + def test_lineno_multiline_matching(self): + """Test multi-line matching when no unique line exists.""" + # gh-69113: test that line numbers are found even when lines + # appear multiple times (e.g., ">>> x = 1" in both test entries) + module_content = '''\ +"""Module docstring.""" + +__test__ = { + 'test_one': """ + >>> x = 1 + >>> x + 1 + """, + 'test_two': """ + >>> x = 1 + >>> x + 2 + """, +} +''' + with tempfile.TemporaryDirectory() as tmpdir: + module_path = os.path.join(tmpdir, 'test_module_multiline.py') + with open(module_path, 'w') as f: + f.write(module_content) + + sys.path.insert(0, tmpdir) + try: + import test_module_multiline + finder = doctest.DocTestFinder() + tests = finder.find(test_module_multiline) + + test_one = None + test_two = None + for test in tests: + if 'test_one' in test.name: + test_one = test + elif 'test_two' in test.name: + test_two = test + + self.assertIsNotNone(test_one, "test_one not found") + self.assertIsNotNone(test_two, "test_two not found") + self.assertIsNotNone( + test_one.lineno, + "Line number should not be None for test_one" + ) + self.assertIsNotNone( + test_two.lineno, + "Line number should not be None for test_two" + ) + self.assertNotEqual( + test_one.lineno, + test_two.lineno, + "test_one and test_two should have different line numbers" + ) + finally: + if 'test_module_multiline' in sys.modules: + del sys.modules['test_module_multiline'] + sys.path.pop(0) + def test_DocTestParser(): r""" Unit tests for the `DocTestParser` class. @@ -2434,7 +2546,8 @@ def test_DocTestSuite_errors(): >>> print(result.failures[1][1]) # doctest: +ELLIPSIS Traceback (most recent call last): - File "...sample_doctest_errors.py", line None, in test.test_doctest.sample_doctest_errors.__test__.bad + File "...sample_doctest_errors.py", line 37, in test.test_doctest.sample_doctest_errors.__test__.bad + >...>> 2 + 2 AssertionError: Failed example: 2 + 2 Expected: @@ -2464,7 +2577,8 @@ def test_DocTestSuite_errors(): >>> print(result.errors[1][1]) # doctest: +ELLIPSIS Traceback (most recent call last): - File "...sample_doctest_errors.py", line None, in test.test_doctest.sample_doctest_errors.__test__.bad + File "...sample_doctest_errors.py", line 39, in test.test_doctest.sample_doctest_errors.__test__.bad + >...>> 1/0 File "", line 1, in 1/0 ~^~ @@ -3256,7 +3370,7 @@ Tests for error reporting in the testmod() function. ~^~ ZeroDivisionError: division by zero ********************************************************************** - File "...sample_doctest_errors.py", line ?, in test.test_doctest.sample_doctest_errors.__test__.bad + File "...sample_doctest_errors.py", line 37, in test.test_doctest.sample_doctest_errors.__test__.bad Failed example: 2 + 2 Expected: @@ -3264,7 +3378,7 @@ Tests for error reporting in the testmod() function. Got: 4 ********************************************************************** - File "...sample_doctest_errors.py", line ?, in test.test_doctest.sample_doctest_errors.__test__.bad + File "...sample_doctest_errors.py", line 39, in test.test_doctest.sample_doctest_errors.__test__.bad Failed example: 1/0 Exception raised: diff --git a/Lib/test/test_email/data/msg_35.txt b/Lib/test/test_email/data/msg_35.txt index be7d5a2f7b9..0e2bbcaf718 100644 --- a/Lib/test/test_email/data/msg_35.txt +++ b/Lib/test/test_email/data/msg_35.txt @@ -1,4 +1,4 @@ From: aperson@dom.ain To: bperson@dom.ain Subject: here's something interesting -counter to RFC 2822, there's no separating newline here +counter to RFC 5322, there's no separating newline here diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index 179e236ecdf..f33844910be 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -2867,6 +2867,81 @@ class TestParser(TestParserMixin, TestEmailBase): ) self.assertEqual(msg_id.token_type, 'msg-id') + def test_parse_message_ids_valid(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + " ", + " ", + " ", + [], + ) + self.assertEqual(message_ids.token_type, 'message-id-list') + + def test_parse_message_ids_empty(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + " ", + " ", + " ", + [errors.InvalidHeaderDefect], + ) + self.assertEqual(message_ids.token_type, 'message-id-list') + + def test_parse_message_ids_comment(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + " (foo's message from \"bar\")", + " (foo's message from \"bar\")", + " ", + [], + ) + self.assertEqual(message_ids.message_ids[0].value, ' ') + self.assertEqual(message_ids.token_type, 'message-id-list') + + def test_parse_message_ids_no_sep(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + "", + "", + "", + [], + ) + self.assertEqual(message_ids.message_ids[0].value, '') + self.assertEqual(message_ids.message_ids[1].value, '') + self.assertEqual(message_ids.token_type, 'message-id-list') + + def test_parse_message_ids_comma_sep(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + ",", + " ", + " ", + [errors.InvalidHeaderDefect], + ) + self.assertEqual(message_ids.message_ids[0].value, '') + self.assertEqual(message_ids.message_ids[1].value, '') + self.assertEqual(message_ids.token_type, 'message-id-list') + + def test_parse_message_ids_invalid_id(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + "", + "", + "", + [errors.InvalidHeaderDefect]*2, + ) + self.assertEqual(message_ids.token_type, 'message-id-list') + + def test_parse_message_ids_broken_ang(self): + message_ids = self._test_parse_x( + parser.parse_message_ids, + " >bar@foo", + " >bar@foo", + " >bar@foo", + [errors.InvalidHeaderDefect]*1, + ) + self.assertEqual(message_ids.token_type, 'message-id-list') + @parameterize @@ -3255,5 +3330,15 @@ class TestFolding(TestEmailBase): " filename*1*=_TEST_TES.txt\n", ) + def test_fold_unfoldable_element_stealing_whitespace(self): + # gh-142006: When an element is too long to fit on the current line + # the previous line's trailing whitespace should not trigger a double newline. + policy = self.policy.clone(max_line_length=10) + # The non-whitespace text needs to exactly fill the max_line_length (10). + text = ("a" * 9) + ", " + ("b" * 20) + expected = ("a" * 9) + ",\n " + ("b" * 20) + "\n" + token = parser.get_address_list(text)[0] + self._test(token, expected, policy=policy) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_email/test_defect_handling.py b/Lib/test/test_email/test_defect_handling.py index 44e76c8ce5e..acc4accccac 100644 --- a/Lib/test/test_email/test_defect_handling.py +++ b/Lib/test/test_email/test_defect_handling.py @@ -126,12 +126,10 @@ class TestDefectsBase: errors.InvalidMultipartContentTransferEncodingDefect) def test_multipart_no_cte_no_defect(self): - if self.raise_expected: return msg = self._str_msg(self.multipart_msg.format('')) self.assertEqual(len(self.get_defects(msg)), 0) def test_multipart_valid_cte_no_defect(self): - if self.raise_expected: return for cte in ('7bit', '8bit', 'BINary'): msg = self._str_msg( self.multipart_msg.format("\nContent-Transfer-Encoding: "+cte)) @@ -300,6 +298,47 @@ class TestDefectsBase: self.assertDefectsEqual(self.get_defects(msg), [errors.CloseBoundaryNotFoundDefect]) + def test_line_beginning_colon(self): + string = ( + "Subject: Dummy subject\r\n: faulty header line\r\n\r\nbody\r\n" + ) + + with self._raise_point(errors.InvalidHeaderDefect): + msg = self._str_msg(string) + self.assertEqual(len(self.get_defects(msg)), 1) + self.assertDefectsEqual( + self.get_defects(msg), [errors.InvalidHeaderDefect] + ) + + if msg: + self.assertEqual(msg.items(), [("Subject", "Dummy subject")]) + self.assertEqual(msg.get_payload(), "body\r\n") + + def test_misplaced_envelope(self): + string = ( + "Subject: Dummy subject\r\nFrom wtf\r\nTo: abc\r\n\r\nbody\r\n" + ) + with self._raise_point(errors.MisplacedEnvelopeHeaderDefect): + msg = self._str_msg(string) + self.assertEqual(len(self.get_defects(msg)), 1) + self.assertDefectsEqual( + self.get_defects(msg), [errors.MisplacedEnvelopeHeaderDefect] + ) + + if msg: + headers = [("Subject", "Dummy subject"), ("To", "abc")] + self.assertEqual(msg.items(), headers) + self.assertEqual(msg.get_payload(), "body\r\n") + + + +class TestCompat32(TestDefectsBase, TestEmailBase): + + policy = policy.compat32 + + def get_defects(self, obj): + return obj.defects + class TestDefectDetection(TestDefectsBase, TestEmailBase): @@ -332,6 +371,9 @@ class TestDefectRaising(TestDefectsBase, TestEmailBase): with self.assertRaises(defect): yield + def get_defects(self, obj): + return obj.defects + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index b8116d073a2..4e6c213510c 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -41,6 +41,7 @@ from email import utils from test import support from test.support import threading_helper +from test.support import warnings_helper from test.support.os_helper import unlink from test.test_email import openfile, TestEmailBase @@ -481,6 +482,27 @@ class TestMessageAPI(TestEmailBase): "Content-Type: foo; bar*0=\"baz\\\"foobar\"; bar*1=\"\\\"baz\"") self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz') + def test_get_param_linear_complexity(self): + # Ensure that email.message._parseparam() is fast. + # See https://github.com/python/cpython/issues/136063. + N = 100_000 + for s, r in [ + ("", ""), + ("foo=bar", "foo=bar"), + (" FOO = bar ", "foo=bar"), + ]: + with self.subTest(s=s, r=r, N=N): + src = f'{s};' * (N - 1) + s + res = email.message._parseparam(src) + self.assertEqual(len(res), N) + self.assertEqual(len(set(res)), 1) + self.assertEqual(res[0], r) + + # This will be considered as a single parameter. + malformed = 's="' + ';' * (N - 1) + res = email.message._parseparam(malformed) + self.assertEqual(res, [malformed]) + def test_field_containment(self): msg = email.message_from_string('Header: exists') self.assertIn('header', msg) @@ -2241,70 +2263,6 @@ class TestNonConformant(TestEmailBase): eq(msg.get_content_maintype(), 'text') eq(msg.get_content_subtype(), 'plain') - # test_defect_handling - def test_same_boundary_inner_outer(self): - msg = self._msgobj('msg_15.txt') - # XXX We can probably eventually do better - inner = msg.get_payload(0) - self.assertHasAttr(inner, 'defects') - self.assertEqual(len(inner.defects), 1) - self.assertIsInstance(inner.defects[0], - errors.StartBoundaryNotFoundDefect) - - # test_defect_handling - def test_multipart_no_boundary(self): - msg = self._msgobj('msg_25.txt') - self.assertIsInstance(msg.get_payload(), str) - self.assertEqual(len(msg.defects), 2) - self.assertIsInstance(msg.defects[0], - errors.NoBoundaryInMultipartDefect) - self.assertIsInstance(msg.defects[1], - errors.MultipartInvariantViolationDefect) - - multipart_msg = textwrap.dedent("""\ - Date: Wed, 14 Nov 2007 12:56:23 GMT - From: foo@bar.invalid - To: foo@bar.invalid - Subject: Content-Transfer-Encoding: base64 and multipart - MIME-Version: 1.0 - Content-Type: multipart/mixed; - boundary="===============3344438784458119861=="{} - - --===============3344438784458119861== - Content-Type: text/plain - - Test message - - --===============3344438784458119861== - Content-Type: application/octet-stream - Content-Transfer-Encoding: base64 - - YWJj - - --===============3344438784458119861==-- - """) - - # test_defect_handling - def test_multipart_invalid_cte(self): - msg = self._str_msg( - self.multipart_msg.format("\nContent-Transfer-Encoding: base64")) - self.assertEqual(len(msg.defects), 1) - self.assertIsInstance(msg.defects[0], - errors.InvalidMultipartContentTransferEncodingDefect) - - # test_defect_handling - def test_multipart_no_cte_no_defect(self): - msg = self._str_msg(self.multipart_msg.format('')) - self.assertEqual(len(msg.defects), 0) - - # test_defect_handling - def test_multipart_valid_cte_no_defect(self): - for cte in ('7bit', '8bit', 'BINary'): - msg = self._str_msg( - self.multipart_msg.format( - "\nContent-Transfer-Encoding: {}".format(cte))) - self.assertEqual(len(msg.defects), 0) - # test_headerregistry.TestContentTypeHeader invalid_1 and invalid_2. def test_invalid_content_type(self): eq = self.assertEqual @@ -2352,7 +2310,7 @@ From: aperson@dom.ain To: bperson@dom.ain Subject: here's something interesting -counter to RFC 2822, there's no separating newline here +counter to RFC 5322, there's no separating newline here """) # test_defect_handling @@ -2381,30 +2339,6 @@ counter to RFC 2822, there's no separating newline here self.assertIsInstance(bad.defects[0], errors.StartBoundaryNotFoundDefect) - # test_defect_handling - def test_first_line_is_continuation_header(self): - eq = self.assertEqual - m = ' Line 1\nSubject: test\n\nbody' - msg = email.message_from_string(m) - eq(msg.keys(), ['Subject']) - eq(msg.get_payload(), 'body') - eq(len(msg.defects), 1) - self.assertDefectsEqual(msg.defects, - [errors.FirstHeaderLineIsContinuationDefect]) - eq(msg.defects[0].line, ' Line 1\n') - - # test_defect_handling - def test_missing_header_body_separator(self): - # Our heuristic if we see a line that doesn't look like a header (no - # leading whitespace but no ':') is to assume that the blank line that - # separates the header from the body is missing, and to stop parsing - # headers and start parsing the body. - msg = self._str_msg('Subject: test\nnot a header\nTo: abc\n\nb\n') - self.assertEqual(msg.keys(), ['Subject']) - self.assertEqual(msg.get_payload(), 'not a header\nTo: abc\n\nb\n') - self.assertDefectsEqual(msg.defects, - [errors.MissingHeaderBodySeparatorDefect]) - def test_string_payload_with_extra_space_after_cte(self): # https://github.com/python/cpython/issues/98188 cte = "base64 " @@ -2508,49 +2442,49 @@ Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz foo bar =?mac-iceland?q?r=8Aksm?= [(b'andr\xe9=zz', 'iso-8859-1')]) def test_rfc2047_rfc2047_1(self): - # 1st testcase at end of rfc2047 + # 1st testcase at end of RFC 2047 s = '(=?ISO-8859-1?Q?a?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'a', 'iso-8859-1'), (b')', None)]) def test_rfc2047_rfc2047_2(self): - # 2nd testcase at end of rfc2047 + # 2nd testcase at end of RFC 2047 s = '(=?ISO-8859-1?Q?a?= b)' self.assertEqual(decode_header(s), [(b'(', None), (b'a', 'iso-8859-1'), (b' b)', None)]) def test_rfc2047_rfc2047_3(self): - # 3rd testcase at end of rfc2047 + # 3rd testcase at end of RFC 2047 s = '(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) def test_rfc2047_rfc2047_4(self): - # 4th testcase at end of rfc2047 + # 4th testcase at end of RFC 2047 s = '(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) def test_rfc2047_rfc2047_5a(self): - # 5th testcase at end of rfc2047 newline is \r\n + # 5th testcase at end of RFC 2047 newline is \r\n s = '(=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) def test_rfc2047_rfc2047_5b(self): - # 5th testcase at end of rfc2047 newline is \n + # 5th testcase at end of RFC 2047 newline is \n s = '(=?ISO-8859-1?Q?a?=\n =?ISO-8859-1?Q?b?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) def test_rfc2047_rfc2047_6(self): - # 6th testcase at end of rfc2047 + # 6th testcase at end of RFC 2047 s = '(=?ISO-8859-1?Q?a_b?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'a b', 'iso-8859-1'), (b')', None)]) def test_rfc2047_rfc2047_7(self): - # 7th testcase at end of rfc2047 + # 7th testcase at end of RFC 2047 s = '(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)' self.assertEqual(decode_header(s), [(b'(', None), (b'a', 'iso-8859-1'), (b' b', 'iso-8859-2'), @@ -3252,8 +3186,8 @@ class TestMiscellaneous(TestEmailBase): """Test for parsing a date with a two-digit year. Parsing a date with a two-digit year should return the correct - four-digit year. RFC822 allows two-digit years, but RFC2822 (which - obsoletes RFC822) requires four-digit years. + four-digit year. RFC 822 allows two-digit years, but RFC 5322 (which + obsoletes RFC 2822, which obsoletes RFC 822) requires four-digit years. """ self.assertEqual(utils.parsedate_tz('25 Feb 03 13:47:26 -0800'), @@ -3304,7 +3238,7 @@ class TestMiscellaneous(TestEmailBase): self.assertEqual(utils.parseaddr(utils.formataddr((a, b))), (a, b)) def test_quotes_unicode_names(self): - # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + # issue 1690608. email.utils.formataddr() should be RFC 2047 aware. name = "H\u00e4ns W\u00fcrst" addr = 'person@dom.ain' utf8_base64 = "=?utf-8?b?SMOkbnMgV8O8cnN0?= " @@ -3314,7 +3248,7 @@ class TestMiscellaneous(TestEmailBase): latin1_quopri) def test_accepts_any_charset_like_object(self): - # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + # issue 1690608. email.utils.formataddr() should be RFC 2047 aware. name = "H\u00e4ns W\u00fcrst" addr = 'person@dom.ain' utf8_base64 = "=?utf-8?b?SMOkbnMgV8O8cnN0?= " @@ -3329,7 +3263,7 @@ class TestMiscellaneous(TestEmailBase): utf8_base64) def test_invalid_charset_like_object_raises_error(self): - # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + # issue 1690608. email.utils.formataddr() should be RFC 2047 aware. name = "H\u00e4ns W\u00fcrst" addr = 'person@dom.ain' # An object without a header_encode method: @@ -3338,7 +3272,7 @@ class TestMiscellaneous(TestEmailBase): bad_charset) def test_unicode_address_raises_error(self): - # issue 1690608. email.utils.formataddr() should be rfc2047 aware. + # issue 1690608. email.utils.formataddr() should be RFC 2047 aware. addr = 'pers\u00f6n@dom.in' self.assertRaises(UnicodeError, utils.formataddr, (None, addr)) self.assertRaises(UnicodeError, utils.formataddr, ("Name", addr)) @@ -3359,7 +3293,7 @@ class TestMiscellaneous(TestEmailBase): # string containing a quoted backslash, followed by 'example' and two # backslashes, followed by another quoted string containing a space and # the word 'example'. parseaddr copies those two backslashes - # literally. Per rfc5322 this is not technically correct since a \ may + # literally. Per RFC 5322 this is not technically correct since a \ may # not appear in an address outside of a quoted string. It is probably # a sensible Postel interpretation, though. eq = self.assertEqual @@ -3371,12 +3305,12 @@ class TestMiscellaneous(TestEmailBase): ('', '"\\\\"example\\\\" example"@example.com')) def test_parseaddr_preserves_spaces_in_local_part(self): - # issue 9286. A normal RFC5322 local part should not contain any + # issue 9286. A normal RFC 5322 local part should not contain any # folding white space, but legacy local parts can (they are a sequence # of atoms, not dotatoms). On the other hand we strip whitespace from # before the @ and around dots, on the assumption that the whitespace # around the punctuation is a mistake in what would otherwise be - # an RFC5322 local part. Leading whitespace is, usual, stripped as well. + # an RFC 5322 local part. Leading whitespace is, usual, stripped as well. self.assertEqual(('', "merwok wok@xample.com"), utils.parseaddr("merwok wok@xample.com")) self.assertEqual(('', "merwok wok@xample.com"), @@ -5717,7 +5651,8 @@ Content-Disposition: inline; filename*=utf-8\udce2\udc80\udc9d''myfile.txt """ msg = email.message_from_string(m) - self.assertEqual(msg.get_filename(), 'myfile.txt') + with warnings_helper.check_warnings(('', DeprecationWarning)): + self.assertEqual(msg.get_filename(), 'myfile.txt') def test_rfc2231_single_tick_in_filename_extended(self): eq = self.assertEqual diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py index ff7a6da644d..95c6afbee41 100644 --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -8,6 +8,7 @@ from test.test_email import TestEmailBase, parameterize from email import headerregistry from email.headerregistry import Address, Group from test.support import ALWAYS_EQ +from test.support import warnings_helper DITTO = object() @@ -247,7 +248,15 @@ class TestContentTypeHeader(TestHeaderBase): decoded = args[2] if l>2 and args[2] is not DITTO else source header = 'Content-Type:' + ' ' if source else '' folded = args[3] if l>3 else header + decoded + '\n' - h = self.make_header('Content-Type', source) + # Both rfc2231 test cases with utf-8%E2%80%9D raise warnings, + # clear encoding cache to ensure test isolation. + if 'utf-8%E2%80%9D' in source and 'ascii' not in source: + import encodings + encodings._cache.clear() + with warnings_helper.check_warnings(('', DeprecationWarning)): + h = self.make_header('Content-Type', source) + else: + h = self.make_header('Content-Type', source) self.assertEqual(h.content_type, content_type) self.assertEqual(h.maintype, maintype) self.assertEqual(h.subtype, subtype) @@ -1812,5 +1821,18 @@ class TestFolding(TestHeaderBase): h.fold(policy=policy.default.clone(max_line_length=20)), 'Message-ID:\n <ईमेलfromMessage@wők.com>\n') + def test_fold_references(self): + h = self.make_header( + 'References', + ' ' + '' + ) + self.assertEqual( + h.fold(policy=policy.default.clone(max_line_length=20)), + 'References: ' + '\n' + ' \n') + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_email/test_message.py b/Lib/test/test_email/test_message.py index b4128f70f18..56ad446694d 100644 --- a/Lib/test/test_email/test_message.py +++ b/Lib/test/test_email/test_message.py @@ -1004,6 +1004,32 @@ class TestEmailMessage(TestEmailMessageBase, TestEmailBase): parsed_msg = message_from_bytes(m.as_bytes(), policy=policy.default) self.assertEqual(parsed_msg['Message-ID'], m['Message-ID']) + def test_no_wrapping_max_line_length(self): + # Test that falsey 'max_line_length' are converted to sys.maxsize. + for n in [0, None]: + with self.subTest(max_line_length=n): + self.do_test_no_wrapping_max_line_length(n) + + def do_test_no_wrapping_max_line_length(self, falsey): + self.assertFalse(falsey) + pol = policy.default.clone(max_line_length=falsey) + subj = "S" * 100 + body = "B" * 100 + msg = EmailMessage(policy=pol) + msg["From"] = "a@ex.com" + msg["To"] = "b@ex.com" + msg["Subject"] = subj + msg.set_content(body) + + raw = msg.as_bytes() + self.assertNotIn(b"=\n", raw, + "Found fold indicator; wrapping not disabled") + + parsed = message_from_bytes(raw, policy=policy.default) + self.assertEqual(parsed["Subject"], subj) + parsed_body = parsed.get_body().get_content().rstrip('\n') + self.assertEqual(parsed_body, body) + def test_invalid_header_names(self): invalid_headers = [ ('Invalid Header', 'contains space'), diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 22dfdb6bb6f..b5367941227 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -239,6 +239,37 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase): lines = "\n".join(lines) + "\n" self.assertEqual(out, lines) + def test_create_module_from_initfunc(self): + out, err = self.run_embedded_interpreter("test_create_module_from_initfunc") + self.assertEqual(self._nogil_filtered_err(err, "embedded_ext"), "") + self.assertEqual(out, + "\n" + "my_test_extension.executed='yes'\n" + "my_test_extension.exec_slot_ran='yes'\n" + "\n" + "embedded_ext.executed='yes'\n" + ) + + def test_inittab_submodule_multiphase(self): + out, err = self.run_embedded_interpreter("test_inittab_submodule_multiphase") + self.assertEqual(err, "") + self.assertEqual(out, + "\n" + "\n" + "Hello from sub-module\n" + "mp_pkg.mp_submod.mp_submod_exec_slot_ran='yes'\n" + "mp_pkg.mp_pkg_exec_slot_ran='yes'\n" + ) + + def test_inittab_submodule_singlephase(self): + out, err = self.run_embedded_interpreter("test_inittab_submodule_singlephase") + self.assertEqual(self._nogil_filtered_err(err, "sp_pkg"), "") + self.assertEqual(out, + "\n" + "\n" + "Hello from sub-module\n" + ) + def test_forced_io_encoding(self): # Checks forced configuration of embedded interpreter IO streams env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape") @@ -516,6 +547,24 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase): out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) self.assertEqual(out, '1\n2\n3\n' * INIT_LOOPS) + @staticmethod + def _nogil_filtered_err(err: str, mod_name: str) -> str: + if not support.Py_GIL_DISABLED: + return err + + # the test imports a singlephase init extension, so it emits a warning + # under the free-threaded build + expected_runtime_warning = ( + "RuntimeWarning: The global interpreter lock (GIL)" + f" has been enabled to load module '{mod_name}'" + ) + filtered_err_lines = [ + line + for line in err.strip().splitlines() + if expected_runtime_warning not in line + ] + return "\n".join(filtered_err_lines) + def config_dev_mode(preconfig, config): preconfig['allocator'] = PYMEM_ALLOCATOR_DEBUG @@ -1232,21 +1281,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): self.check_all_configs("test_init_dont_configure_locale", {}, preconfig, api=API_PYTHON) - @unittest.skip('as of 3.11 this test no longer works because ' - 'path calculations do not occur on read') - def test_init_read_set(self): - config = { - 'program_name': './init_read_set', - 'executable': 'my_executable', - 'base_executable': 'my_executable', - } - def modify_path(path): - path.insert(1, "test_path_insert1") - path.append("test_path_append") - self.check_all_configs("test_init_read_set", config, - api=API_PYTHON, - modify_path_cb=modify_path) - def test_init_sys_add(self): config = { 'faulthandler': 1, diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index 6d3c91b0b6d..f6743d57ca2 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -60,6 +60,11 @@ class EnsurepipMixin: self.run_pip.return_value = 0 self.addCleanup(run_pip_patch.stop) + # Allow testing on zlib-less platforms by avoiding the check for zlib in _bootstrap() + zlib_patch = unittest.mock.patch.dict('sys.modules', {'zlib': unittest.mock.MagicMock()}) + zlib_patch.start() + self.addCleanup(zlib_patch.stop) + # Avoid side effects on the actual os module real_devnull = os.devnull os_patch = unittest.mock.patch("ensurepip.os") @@ -185,6 +190,16 @@ class TestBootstrap(EnsurepipMixin, unittest.TestCase): ensurepip.bootstrap() self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) + def test_missing_zlib(self): + with unittest.mock.patch.dict('sys.modules', {'zlib': None}): + with self.assertRaises(ModuleNotFoundError) as cm: + ensurepip.bootstrap() + + error_msg = str(cm.exception) + self.assertIn("ensurepip requires the standard library module 'zlib'", error_msg) + + self.assertFalse(self.run_pip.called) + @contextlib.contextmanager def fake_pip(version=ensurepip.version()): if version is None: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 2dd585f246d..779457119e8 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4887,7 +4887,7 @@ class TestInternals(unittest.TestCase): def _generate_next_value_(name, start, count, last): return name - def test_auto_order_wierd(self): + def test_auto_order_weird(self): weird_auto = auto() weird_auto.value = 'pathological case' class Color(Enum): @@ -5324,7 +5324,7 @@ class TestStdLib(unittest.TestCase): class MiscTestCase(unittest.TestCase): def test__all__(self): - support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'}) + support.check__all__(self, enum) @cpython_only def test_lazy_import(self): @@ -5529,12 +5529,16 @@ class TestEnumDict(unittest.TestCase): # helpers def enum_dir(cls): + if issubclass(cls, Flag): + members = list(cls._member_map_.keys()) + else: + members = cls._member_names_ interesting = set([ '__class__', '__contains__', '__doc__', '__getitem__', '__iter__', '__len__', '__members__', '__module__', '__name__', '__qualname__', ] - + cls._member_names_ + + members ) if cls._new_member_ is not object.__new__: interesting.add('__new__') diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index 5df2c41c6b5..ace7ec72917 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -1,4 +1,4 @@ -import collections.abc +import collections import types import unittest from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, exceeds_recursion_limit @@ -193,6 +193,77 @@ class StrAndReprTests(unittest.TestCase): "MyEG('flat', [ValueError(1), TypeError(2)]), " "TypeError(2)])")) + def test_exceptions_mutation(self): + class MyEG(ExceptionGroup): + pass + + excs = [ValueError(1), TypeError(2)] + eg = MyEG('test', excs) + + self.assertEqual(repr(eg), "MyEG('test', [ValueError(1), TypeError(2)])") + excs.clear() + + # Ensure that clearing the exceptions sequence doesn't change the repr. + self.assertEqual(repr(eg), "MyEG('test', [ValueError(1), TypeError(2)])") + + # Ensure that the args are still as passed. + self.assertEqual(eg.args, ('test', [])) + + excs = (ValueError(1), KeyboardInterrupt(2)) + eg = BaseExceptionGroup('test', excs) + + # Ensure that immutable sequences still work fine. + self.assertEqual( + repr(eg), + "BaseExceptionGroup('test', (ValueError(1), KeyboardInterrupt(2)))" + ) + + # Test non-standard custom sequences. + excs = collections.deque([ValueError(1), TypeError(2)]) + eg = ExceptionGroup('test', excs) + + self.assertEqual( + repr(eg), + "ExceptionGroup('test', deque([ValueError(1), TypeError(2)]))" + ) + excs.clear() + + # Ensure that clearing the exceptions sequence doesn't change the repr. + self.assertEqual( + repr(eg), + "ExceptionGroup('test', deque([ValueError(1), TypeError(2)]))" + ) + + def test_repr_raises(self): + class MySeq(collections.abc.Sequence): + def __init__(self, raises): + self.raises = raises + + def __len__(self): + return 1 + + def __getitem__(self, index): + if index == 0: + return ValueError(1) + raise IndexError + + def __repr__(self): + if self.raises: + raise self.raises + return None + + seq = MySeq(None) + with self.assertRaisesRegex( + TypeError, + r".*MySeq\.__repr__\(\) must return a str, not NoneType" + ): + ExceptionGroup("test", seq) + + seq = MySeq(ValueError) + with self.assertRaises(ValueError): + BaseExceptionGroup("test", seq) + + def create_simple_eg(): excs = [] diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 59f77f91d85..6f212d2f91e 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -224,6 +224,8 @@ class ExceptionTests(unittest.TestCase): if not isinstance(src, str): src = src.decode(encoding, 'replace') line = src.split('\n')[lineno-1] + if lineno == 1: + line = line.removeprefix('\ufeff') self.assertIn(line, cm.exception.text) def test_error_offset_continuation_characters(self): @@ -239,7 +241,9 @@ class ExceptionTests(unittest.TestCase): check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20) check(b'# -*- coding: cp1251 -*-\nPython = "\xcf\xb3\xf2\xee\xed" +', 2, 19, encoding='cp1251') - check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 10) + check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 12) + check(b'\n\n\nPython = "\xcf\xb3\xf2\xee\xed" +', 4, 12) + check(b'\xef\xbb\xbfPython = "\xcf\xb3\xf2\xee\xed" +', 1, 12) check('x = "a', 1, 5) check('lambda x: x = 2', 1, 1) check('f{a + b + c}', 1, 2) @@ -248,7 +252,16 @@ class ExceptionTests(unittest.TestCase): check('[\nfile\nfor str(file)\nin\n[]\n]', 3, 5) check('[file for\n str(file) in []]', 2, 2) check("ages = {'Alice'=22, 'Bob'=23}", 1, 9) - check('match ...:\n case {**rest, "key": value}:\n ...', 2, 19) + check(dedent("""\ + match ...: + case {**rest1, "after": after}: + ... + """), 2, 11) + check(dedent("""\ + match ...: + case {"before": before, **rest2, "after": after}: + ... + """), 2, 29) check("[a b c d e f]", 1, 2) check("for x yfff:", 1, 7) check("f(a for a in b, c)", 1, 3, 1, 15) @@ -287,7 +300,7 @@ class ExceptionTests(unittest.TestCase): check("pass\npass\npass\n(1+)\npass\npass\npass", 4, 4) check("(1+)", 1, 4) check("[interesting\nfoo()\n", 1, 1) - check(b"\xef\xbb\xbf#coding: utf8\nprint('\xe6\x88\x91')\n", 0, -1) + check(b"\xef\xbb\xbf#coding: utf8\nprint('\xe6\x88\x91')\n", 1, 0) check("""f''' { (123_a) @@ -1910,6 +1923,39 @@ class ExceptionTests(unittest.TestCase): exc2 = None + @cpython_only + # Python built with Py_TRACE_REFS fail with a fatal error in + # _PyRefchain_Trace() on memory allocation error. + @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + def test_exec_set_nomemory_hang(self): + import_module("_testcapi") + # gh-134163: A MemoryError inside code that was wrapped by a try/except + # block would lead to an infinite loop. + + # The frame_lasti needs to be greater than 257 to prevent + # PyLong_FromLong() from returning cached integers, which + # don't require a memory allocation. Prepend some dummy code + # to artificially increase the instruction index. + warmup_code = "a = list(range(0, 1))\n" * 60 + user_input = warmup_code + dedent(""" + try: + import _testcapi + _testcapi.set_nomemory(0) + b = list(range(1000, 2000)) + except Exception as e: + import traceback + traceback.print_exc() + """) + with SuppressCrashReport(): + with script_helper.spawn_python('-c', user_input) as p: + p.wait() + output = p.stdout.read() + + self.assertIn(p.returncode, (0, 1)) + self.assertGreater(len(output), 0) # At minimum, should not hang + self.assertIn(b"MemoryError", output) + + class NameErrorTests(unittest.TestCase): def test_name_error_has_name(self): try: diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py index d9d85fe79af..f003a5837ae 100644 --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -137,7 +137,7 @@ Verify clearing of SF bug #733667 >>> g(*Nothing()) Traceback (most recent call last): ... - TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing + TypeError: Value after * must be an iterable, not Nothing >>> class Nothing: ... def __len__(self): return 5 @@ -146,7 +146,7 @@ Verify clearing of SF bug #733667 >>> g(*Nothing()) Traceback (most recent call last): ... - TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing + TypeError: Value after * must be an iterable, not Nothing >>> class Nothing(): ... def __len__(self): return 5 @@ -266,7 +266,7 @@ What about willful misconduct? >>> h(*h) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after * must be an iterable, not function + TypeError: Value after * must be an iterable, not function >>> h(1, *h) Traceback (most recent call last): @@ -281,55 +281,53 @@ What about willful misconduct? >>> dir(*h) Traceback (most recent call last): ... - TypeError: dir() argument after * must be an iterable, not function + TypeError: Value after * must be an iterable, not function >>> nothing = None >>> nothing(*h) Traceback (most recent call last): ... - TypeError: None argument after * must be an iterable, \ -not function + TypeError: Value after * must be an iterable, not function >>> h(**h) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after ** must be a mapping, not function + TypeError: Value after ** must be a mapping, not function >>> h(**[]) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after ** must be a mapping, not list + TypeError: Value after ** must be a mapping, not list >>> h(a=1, **h) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after ** must be a mapping, not function + TypeError: Value after ** must be a mapping, not function >>> h(a=1, **[]) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after ** must be a mapping, not list + TypeError: Value after ** must be a mapping, not list >>> h(**{'a': 1}, **h) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after ** must be a mapping, not function + TypeError: Value after ** must be a mapping, not function >>> h(**{'a': 1}, **[]) Traceback (most recent call last): ... - TypeError: test.test_extcall.h() argument after ** must be a mapping, not list + TypeError: Value after ** must be a mapping, not list >>> dir(**h) Traceback (most recent call last): ... - TypeError: dir() argument after ** must be a mapping, not function + TypeError: Value after ** must be a mapping, not function >>> nothing(**h) Traceback (most recent call last): ... - TypeError: None argument after ** must be a mapping, \ -not function + TypeError: Value after ** must be a mapping, not function >>> dir(b=1, **{'b': 1}) Traceback (most recent call last): diff --git a/Lib/test/test_external_inspection.py b/Lib/test/test_external_inspection.py index 354a82a800f..e298f1db4e2 100644 --- a/Lib/test/test_external_inspection.py +++ b/Lib/test/test_external_inspection.py @@ -1,11 +1,13 @@ import unittest import os import textwrap +import contextlib import importlib import sys import socket import threading import time +from contextlib import contextmanager from asyncio import staggered, taskgroups, base_events, tasks from unittest.mock import ANY from test.support import ( @@ -13,12 +15,34 @@ from test.support import ( SHORT_TIMEOUT, busy_retry, requires_gil_enabled, + requires_remote_subprocess_debugging, ) from test.support.script_helper import make_script from test.support.socket_helper import find_unused_port import subprocess +# Profiling mode constants +PROFILING_MODE_WALL = 0 +PROFILING_MODE_CPU = 1 +PROFILING_MODE_GIL = 2 +PROFILING_MODE_ALL = 3 +PROFILING_MODE_EXCEPTION = 4 + +# Thread status flags +THREAD_STATUS_HAS_GIL = 1 << 0 +THREAD_STATUS_ON_CPU = 1 << 1 +THREAD_STATUS_UNKNOWN = 1 << 2 +THREAD_STATUS_HAS_EXCEPTION = 1 << 4 + +# Maximum number of retry attempts for operations that may fail transiently +MAX_TRIES = 10 + +try: + from concurrent import interpreters +except ImportError: + interpreters = None + PROCESS_VM_READV_SUPPORTED = False try: @@ -31,12 +55,149 @@ except ImportError: ) +# ============================================================================ +# Module-level helper functions +# ============================================================================ + + def _make_test_script(script_dir, script_basename, source): to_return = make_script(script_dir, script_basename, source) importlib.invalidate_caches() return to_return +def _create_server_socket(port, backlog=1): + """Create and configure a server socket for test communication.""" + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_socket.bind(("localhost", port)) + server_socket.settimeout(SHORT_TIMEOUT) + server_socket.listen(backlog) + return server_socket + + +def _wait_for_signal(sock, expected_signals, timeout=SHORT_TIMEOUT): + """ + Wait for expected signal(s) from a socket with proper timeout and EOF handling. + + Args: + sock: Connected socket to read from + expected_signals: Single bytes object or list of bytes objects to wait for + timeout: Socket timeout in seconds + + Returns: + bytes: Complete accumulated response buffer + + Raises: + RuntimeError: If connection closed before signal received or timeout + """ + if isinstance(expected_signals, bytes): + expected_signals = [expected_signals] + + sock.settimeout(timeout) + buffer = b"" + + while True: + # Check if all expected signals are in buffer + if all(sig in buffer for sig in expected_signals): + return buffer + + try: + chunk = sock.recv(4096) + if not chunk: + # EOF - connection closed + raise RuntimeError( + f"Connection closed before receiving expected signals. " + f"Expected: {expected_signals}, Got: {buffer[-200:]!r}" + ) + buffer += chunk + except socket.timeout: + raise RuntimeError( + f"Timeout waiting for signals. " + f"Expected: {expected_signals}, Got: {buffer[-200:]!r}" + ) + + +def _wait_for_n_signals(sock, signal_pattern, count, timeout=SHORT_TIMEOUT): + """ + Wait for N occurrences of a signal pattern. + + Args: + sock: Connected socket to read from + signal_pattern: bytes pattern to count (e.g., b"ready") + count: Number of occurrences expected + timeout: Socket timeout in seconds + + Returns: + bytes: Complete accumulated response buffer + + Raises: + RuntimeError: If connection closed or timeout before receiving all signals + """ + sock.settimeout(timeout) + buffer = b"" + found_count = 0 + + while found_count < count: + try: + chunk = sock.recv(4096) + if not chunk: + raise RuntimeError( + f"Connection closed after {found_count}/{count} signals. " + f"Last 200 bytes: {buffer[-200:]!r}" + ) + buffer += chunk + # Count occurrences in entire buffer + found_count = buffer.count(signal_pattern) + except socket.timeout: + raise RuntimeError( + f"Timeout waiting for {count} signals (found {found_count}). " + f"Last 200 bytes: {buffer[-200:]!r}" + ) + + return buffer + + +@contextmanager +def _managed_subprocess(args, timeout=SHORT_TIMEOUT): + """ + Context manager for subprocess lifecycle management. + + Ensures process is properly terminated and cleaned up even on exceptions. + Uses graceful termination first, then forceful kill if needed. + """ + p = subprocess.Popen(args) + try: + yield p + finally: + try: + p.terminate() + try: + p.wait(timeout=timeout) + except subprocess.TimeoutExpired: + p.kill() + try: + p.wait(timeout=timeout) + except subprocess.TimeoutExpired: + pass # Process refuses to die, nothing more we can do + except OSError: + pass # Process already dead + + +def _cleanup_sockets(*sockets): + """Safely close multiple sockets, ignoring errors.""" + for sock in sockets: + if sock is not None: + try: + sock.close() + except OSError: + pass + + +# ============================================================================ +# Decorators and skip conditions +# ============================================================================ + skip_if_not_supported = unittest.skipIf( ( sys.platform != "darwin" @@ -47,36 +208,219 @@ skip_if_not_supported = unittest.skipIf( ) +def requires_subinterpreters(meth): + """Decorator to skip a test if subinterpreters are not supported.""" + return unittest.skipIf(interpreters is None, "subinterpreters required")( + meth + ) + + +# ============================================================================ +# Simple wrapper functions for RemoteUnwinder +# ============================================================================ + def get_stack_trace(pid): - unwinder = RemoteUnwinder(pid, all_threads=True, debug=True) - return unwinder.get_stack_trace() + for _ in busy_retry(SHORT_TIMEOUT): + try: + unwinder = RemoteUnwinder(pid, all_threads=True, debug=True) + return unwinder.get_stack_trace() + except RuntimeError as e: + continue + raise RuntimeError("Failed to get stack trace after retries") def get_async_stack_trace(pid): - unwinder = RemoteUnwinder(pid, debug=True) - return unwinder.get_async_stack_trace() + for _ in busy_retry(SHORT_TIMEOUT): + try: + unwinder = RemoteUnwinder(pid, debug=True) + return unwinder.get_async_stack_trace() + except RuntimeError as e: + continue + raise RuntimeError("Failed to get async stack trace after retries") def get_all_awaited_by(pid): - unwinder = RemoteUnwinder(pid, debug=True) - return unwinder.get_all_awaited_by() + for _ in busy_retry(SHORT_TIMEOUT): + try: + unwinder = RemoteUnwinder(pid, debug=True) + return unwinder.get_all_awaited_by() + except RuntimeError as e: + continue + raise RuntimeError("Failed to get all awaited_by after retries") -class TestGetStackTrace(unittest.TestCase): +# ============================================================================ +# Base test class with shared infrastructure +# ============================================================================ + + +class RemoteInspectionTestBase(unittest.TestCase): + """Base class for remote inspection tests with common helpers.""" + maxDiff = None + def _run_script_and_get_trace( + self, + script, + trace_func, + wait_for_signals=None, + port=None, + backlog=1, + ): + """ + Common pattern: run a script, wait for signals, get trace. + + Args: + script: Script content (will be formatted with port if {port} present) + trace_func: Function to call with pid to get trace (e.g., get_stack_trace) + wait_for_signals: Signal(s) to wait for before getting trace + port: Port to use (auto-selected if None) + backlog: Socket listen backlog + + Returns: + tuple: (trace_result, script_name) + """ + if port is None: + port = find_unused_port() + + # Format script with port if needed + if "{port}" in script or "{{port}}" in script: + script = script.replace("{{port}}", "{port}").format(port=port) + + with os_helper.temp_dir() as work_dir: + script_dir = os.path.join(work_dir, "script_pkg") + os.mkdir(script_dir) + + server_socket = _create_server_socket(port, backlog) + script_name = _make_test_script(script_dir, "script", script) + client_socket = None + + try: + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None + + if wait_for_signals: + _wait_for_signal(client_socket, wait_for_signals) + + trace = trace_func(p.pid) + return trace, script_name + finally: + _cleanup_sockets(client_socket, server_socket) + + def _find_frame_in_trace(self, stack_trace, predicate): + """ + Find a frame matching predicate in stack trace. + + Args: + stack_trace: List of InterpreterInfo objects + predicate: Function(frame) -> bool + + Returns: + FrameInfo or None + """ + for interpreter_info in stack_trace: + for thread_info in interpreter_info.threads: + for frame in thread_info.frame_info: + if predicate(frame): + return frame + return None + + def _find_thread_by_id(self, stack_trace, thread_id): + """Find a thread by its native thread ID.""" + for interpreter_info in stack_trace: + for thread_info in interpreter_info.threads: + if thread_info.thread_id == thread_id: + return thread_info + return None + + def _find_thread_with_frame(self, stack_trace, frame_predicate): + """Find a thread containing a frame matching predicate.""" + for interpreter_info in stack_trace: + for thread_info in interpreter_info.threads: + for frame in thread_info.frame_info: + if frame_predicate(frame): + return thread_info + return None + + def _get_thread_statuses(self, stack_trace): + """Extract thread_id -> status mapping from stack trace.""" + statuses = {} + for interpreter_info in stack_trace: + for thread_info in interpreter_info.threads: + statuses[thread_info.thread_id] = thread_info.status + return statuses + + def _get_task_id_map(self, stack_trace): + """Create task_id -> task mapping from async stack trace.""" + return {task.task_id: task for task in stack_trace[0].awaited_by} + + def _get_awaited_by_relationships(self, stack_trace): + """Extract task name to awaited_by set mapping.""" + id_to_task = self._get_task_id_map(stack_trace) + return { + task.task_name: set( + id_to_task[awaited.task_name].task_name + for awaited in task.awaited_by + ) + for task in stack_trace[0].awaited_by + } + + def _extract_coroutine_stacks(self, stack_trace): + """Extract and format coroutine stacks from tasks.""" + return { + task.task_name: sorted( + tuple(tuple(frame) for frame in coro.call_stack) + for coro in task.coroutine_stack + ) + for task in stack_trace[0].awaited_by + } + + @staticmethod + def _frame_to_lineno_tuple(frame): + """Convert frame to (filename, lineno, funcname, opcode) tuple. + + This extracts just the line number from the location, ignoring column + offsets which can vary due to sampling timing (e.g., when two statements + are on the same line, the sample might catch either one). + """ + filename, location, funcname, opcode = frame + return (filename, location.lineno, funcname, opcode) + + def _extract_coroutine_stacks_lineno_only(self, stack_trace): + """Extract coroutine stacks with line numbers only (no column offsets). + + Use this for tests where sampling timing can cause column offset + variations (e.g., 'expr1; expr2' on the same line). + """ + return { + task.task_name: sorted( + tuple(self._frame_to_lineno_tuple(frame) for frame in coro.call_stack) + for coro in task.coroutine_stack + ) + for task in stack_trace[0].awaited_by + } + + +# ============================================================================ +# Test classes +# ============================================================================ + + +@requires_remote_subprocess_debugging() +class TestGetStackTrace(RemoteInspectionTestBase): @skip_if_not_supported @unittest.skipIf( sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, "Test only runs on Linux with process_vm_readv support", ) def test_remote_stack_trace(self): - # Spawn a process with some realistic Python code port = find_unused_port() script = textwrap.dedent( f"""\ import time, sys, socket, threading - # Connect to the test process + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) @@ -89,66 +433,59 @@ class TestGetStackTrace(unittest.TestCase): foo() def foo(): - sock.sendall(b"ready:thread\\n"); time.sleep(10_000) # same line number + sock.sendall(b"ready:thread\\n"); time.sleep(10_000) t = threading.Thread(target=bar) t.start() - sock.sendall(b"ready:main\\n"); t.join() # same line number + sock.sendall(b"ready:main\\n"); t.join() """ ) - stack_trace = None + with os_helper.temp_dir() as work_dir: script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - # Create a socket server to communicate with the target process - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) - + server_socket = _create_server_socket(port) script_name = _make_test_script(script_dir, "script", script) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() - response = b"" - while ( - b"ready:main" not in response - or b"ready:thread" not in response - ): - response += client_socket.recv(1024) - stack_trace = get_stack_trace(p.pid) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None + + _wait_for_signal( + client_socket, [b"ready:main", b"ready:thread"] + ) + + stack_trace = get_stack_trace(p.pid) + + # Find expected thread stack by funcname + found_thread = self._find_thread_with_frame( + stack_trace, + lambda f: f.funcname == "foo" and f.location.lineno == 15, + ) + self.assertIsNotNone( + found_thread, "Expected thread stack trace not found" + ) + # Check the funcnames in order + funcnames = [f.funcname for f in found_thread.frame_info] + self.assertEqual( + funcnames[:6], + ["foo", "baz", "bar", "Thread.run", "Thread._bootstrap_inner", "Thread._bootstrap"] + ) + + # Check main thread + found_main = self._find_frame_in_trace( + stack_trace, + lambda f: f.funcname == "" and f.location.lineno == 19, + ) + self.assertIsNotNone( + found_main, "Main thread stack trace not found" + ) finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) - - thread_expected_stack_trace = [ - FrameInfo([script_name, 15, "foo"]), - FrameInfo([script_name, 12, "baz"]), - FrameInfo([script_name, 9, "bar"]), - FrameInfo([threading.__file__, ANY, "Thread.run"]), - ] - # Is possible that there are more threads, so we check that the - # expected stack traces are in the result (looking at you Windows!) - self.assertIn((ANY, thread_expected_stack_trace), stack_trace) - - # Check that the main thread stack trace is in the result - frame = FrameInfo([script_name, 19, ""]) - for _, stack in stack_trace: - if frame in stack: - break - else: - self.fail("Main thread stack trace not found in result") + _cleanup_sockets(client_socket, server_socket) @skip_if_not_supported @unittest.skipIf( @@ -156,7 +493,6 @@ class TestGetStackTrace(unittest.TestCase): "Test only runs on Linux with process_vm_readv support", ) def test_async_remote_stack_trace(self): - # Spawn a process with some realistic Python code port = find_unused_port() script = textwrap.dedent( f"""\ @@ -164,12 +500,12 @@ class TestGetStackTrace(unittest.TestCase): import time import sys import socket - # Connect to the test process + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) def c5(): - sock.sendall(b"ready"); time.sleep(10_000) # same line number + sock.sendall(b"ready"); time.sleep(10_000) async def c4(): await asyncio.sleep(0) @@ -200,7 +536,7 @@ class TestGetStackTrace(unittest.TestCase): asyncio.run(main(), loop_factory={{TASK_FACTORY}}) """ ) - stack_trace = None + for task_factory_variant in "asyncio.new_event_loop", "new_eager_loop": with ( self.subTest(task_factory_variant=task_factory_variant), @@ -208,195 +544,152 @@ class TestGetStackTrace(unittest.TestCase): ): script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - server_socket = socket.socket( - socket.AF_INET, socket.SOCK_STREAM - ) - server_socket.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 - ) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) + + server_socket = _create_server_socket(port) script_name = _make_test_script( script_dir, "script", script.format(TASK_FACTORY=task_factory_variant), ) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() - response = client_socket.recv(1024) - self.assertEqual(response, b"ready") - stack_trace = get_async_stack_trace(p.pid) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) - finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) + with _managed_subprocess( + [sys.executable, script_name] + ) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None - # First check all the tasks are present - tasks_names = [ - task.task_name for task in stack_trace[0].awaited_by - ] - for task_name in ["c2_root", "sub_main_1", "sub_main_2"]: - self.assertIn(task_name, tasks_names) + response = _wait_for_signal(client_socket, b"ready") + self.assertIn(b"ready", response) - # Now ensure that the awaited_by_relationships are correct - id_to_task = { - task.task_id: task for task in stack_trace[0].awaited_by - } - task_name_to_awaited_by = { - task.task_name: set( - id_to_task[awaited.task_name].task_name - for awaited in task.awaited_by - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - task_name_to_awaited_by, - { - "c2_root": {"Task-1", "sub_main_1", "sub_main_2"}, - "Task-1": set(), - "sub_main_1": {"Task-1"}, - "sub_main_2": {"Task-1"}, - }, - ) + stack_trace = get_async_stack_trace(p.pid) - # Now ensure that the coroutine stacks are correct - coroutine_stacks = { - task.task_name: sorted( - tuple(tuple(frame) for frame in coro.call_stack) - for coro in task.coroutine_stack - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - coroutine_stacks, - { - "Task-1": [ - ( - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] - ), - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] - ), - tuple([script_name, 26, "main"]), - ) - ], - "c2_root": [ - ( - tuple([script_name, 10, "c5"]), - tuple([script_name, 14, "c4"]), - tuple([script_name, 17, "c3"]), - tuple([script_name, 20, "c2"]), - ) - ], - "sub_main_1": [(tuple([script_name, 23, "c1"]),)], - "sub_main_2": [(tuple([script_name, 23, "c1"]),)], - }, - ) + # Check all tasks are present + tasks_names = [ + task.task_name + for task in stack_trace[0].awaited_by + ] + for task_name in [ + "c2_root", + "sub_main_1", + "sub_main_2", + ]: + self.assertIn(task_name, tasks_names) - # Now ensure the coroutine stacks for the awaited_by relationships are correct. - awaited_by_coroutine_stacks = { - task.task_name: sorted( - ( - id_to_task[coro.task_name].task_name, - tuple(tuple(frame) for frame in coro.call_stack), + # Check awaited_by relationships + relationships = self._get_awaited_by_relationships( + stack_trace ) - for coro in task.awaited_by - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - awaited_by_coroutine_stacks, - { - "Task-1": [], - "c2_root": [ - ( - "Task-1", + self.assertEqual( + relationships, + { + "c2_root": { + "Task-1", + "sub_main_1", + "sub_main_2", + }, + "Task-1": set(), + "sub_main_1": {"Task-1"}, + "sub_main_2": {"Task-1"}, + }, + ) + + # Check coroutine stacks (using line numbers only to avoid + # flakiness from column offset variations when sampling + # catches different statements on the same line) + coroutine_stacks = self._extract_coroutine_stacks_lineno_only( + stack_trace + ) + self.assertEqual( + coroutine_stacks, + { + "Task-1": [ + ( + (taskgroups.__file__, ANY, "TaskGroup._aexit", None), + (taskgroups.__file__, ANY, "TaskGroup.__aexit__", None), + (script_name, 26, "main", None), + ) + ], + "c2_root": [ + ( + (script_name, 10, "c5", None), + (script_name, 14, "c4", None), + (script_name, 17, "c3", None), + (script_name, 20, "c2", None), + ) + ], + "sub_main_1": [ + ((script_name, 23, "c1", None),) + ], + "sub_main_2": [ + ((script_name, 23, "c1", None),) + ], + }, + ) + + # Check awaited_by coroutine stacks (line numbers only) + id_to_task = self._get_task_id_map(stack_trace) + awaited_by_coroutine_stacks = { + task.task_name: sorted( ( + id_to_task[coro.task_name].task_name, tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] + self._frame_to_lineno_tuple(frame) + for frame in coro.call_stack ), - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] - ), - tuple([script_name, 26, "main"]), - ), - ), - ("sub_main_1", (tuple([script_name, 23, "c1"]),)), - ("sub_main_2", (tuple([script_name, 23, "c1"]),)), - ], - "sub_main_1": [ - ( - "Task-1", - ( - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] - ), - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] - ), - tuple([script_name, 26, "main"]), - ), + ) + for coro in task.awaited_by ) - ], - "sub_main_2": [ - ( - "Task-1", - ( - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] + for task in stack_trace[0].awaited_by + } + self.assertEqual( + awaited_by_coroutine_stacks, + { + "Task-1": [], + "c2_root": [ + ( + "Task-1", + ( + (taskgroups.__file__, ANY, "TaskGroup._aexit", None), + (taskgroups.__file__, ANY, "TaskGroup.__aexit__", None), + (script_name, 26, "main", None), + ), ), - tuple( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] + ( + "sub_main_1", + ((script_name, 23, "c1", None),), ), - tuple([script_name, 26, "main"]), - ), - ) - ], - }, - ) + ( + "sub_main_2", + ((script_name, 23, "c1", None),), + ), + ], + "sub_main_1": [ + ( + "Task-1", + ( + (taskgroups.__file__, ANY, "TaskGroup._aexit", None), + (taskgroups.__file__, ANY, "TaskGroup.__aexit__", None), + (script_name, 26, "main", None), + ), + ) + ], + "sub_main_2": [ + ( + "Task-1", + ( + (taskgroups.__file__, ANY, "TaskGroup._aexit", None), + (taskgroups.__file__, ANY, "TaskGroup.__aexit__", None), + (script_name, 26, "main", None), + ), + ) + ], + }, + ) + finally: + _cleanup_sockets(client_socket, server_socket) @skip_if_not_supported @unittest.skipIf( @@ -404,7 +697,6 @@ class TestGetStackTrace(unittest.TestCase): "Test only runs on Linux with process_vm_readv support", ) def test_asyncgen_remote_stack_trace(self): - # Spawn a process with some realistic Python code port = find_unused_port() script = textwrap.dedent( f"""\ @@ -412,12 +704,12 @@ class TestGetStackTrace(unittest.TestCase): import time import sys import socket - # Connect to the test process + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) async def gen_nested_call(): - sock.sendall(b"ready"); time.sleep(10_000) # same line number + sock.sendall(b"ready"); time.sleep(10_000) async def gen(): for num in range(2): @@ -432,59 +724,53 @@ class TestGetStackTrace(unittest.TestCase): asyncio.run(main()) """ ) - stack_trace = None + with os_helper.temp_dir() as work_dir: script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - # Create a socket server to communicate with the target process - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) + + server_socket = _create_server_socket(port) script_name = _make_test_script(script_dir, "script", script) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() - response = client_socket.recv(1024) - self.assertEqual(response, b"ready") - stack_trace = get_async_stack_trace(p.pid) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) - finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None - # For this simple asyncgen test, we only expect one task with the full coroutine stack - self.assertEqual(len(stack_trace[0].awaited_by), 1) - task = stack_trace[0].awaited_by[0] - self.assertEqual(task.task_name, "Task-1") + response = _wait_for_signal(client_socket, b"ready") + self.assertIn(b"ready", response) - # Check the coroutine stack - based on actual output, only shows main - coroutine_stack = sorted( - tuple(tuple(frame) for frame in coro.call_stack) - for coro in task.coroutine_stack - ) - self.assertEqual( - coroutine_stack, - [ - ( - tuple([script_name, 10, "gen_nested_call"]), - tuple([script_name, 16, "gen"]), - tuple([script_name, 19, "main"]), + stack_trace = get_async_stack_trace(p.pid) + + # For this simple asyncgen test, we only expect one task + self.assertEqual(len(stack_trace[0].awaited_by), 1) + task = stack_trace[0].awaited_by[0] + self.assertEqual(task.task_name, "Task-1") + + # Check the coroutine stack (using line numbers only to avoid + # flakiness from column offset variations when sampling + # catches different statements on the same line) + coroutine_stack = sorted( + tuple(self._frame_to_lineno_tuple(frame) for frame in coro.call_stack) + for coro in task.coroutine_stack + ) + self.assertEqual( + coroutine_stack, + [ + ( + (script_name, 10, "gen_nested_call", None), + (script_name, 16, "gen", None), + (script_name, 19, "main", None), + ) + ], ) - ], - ) - # No awaited_by relationships expected for this simple case - self.assertEqual(task.awaited_by, []) + # No awaited_by relationships expected + self.assertEqual(task.awaited_by, []) + finally: + _cleanup_sockets(client_socket, server_socket) @skip_if_not_supported @unittest.skipIf( @@ -492,7 +778,6 @@ class TestGetStackTrace(unittest.TestCase): "Test only runs on Linux with process_vm_readv support", ) def test_async_gather_remote_stack_trace(self): - # Spawn a process with some realistic Python code port = find_unused_port() script = textwrap.dedent( f"""\ @@ -500,13 +785,13 @@ class TestGetStackTrace(unittest.TestCase): import time import sys import socket - # Connect to the test process + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) async def deep(): await asyncio.sleep(0) - sock.sendall(b"ready"); time.sleep(10_000) # same line number + sock.sendall(b"ready"); time.sleep(10_000) async def c1(): await asyncio.sleep(0) @@ -521,103 +806,89 @@ class TestGetStackTrace(unittest.TestCase): asyncio.run(main()) """ ) - stack_trace = None + with os_helper.temp_dir() as work_dir: script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - # Create a socket server to communicate with the target process - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) + + server_socket = _create_server_socket(port) script_name = _make_test_script(script_dir, "script", script) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() - response = client_socket.recv(1024) - self.assertEqual(response, b"ready") - stack_trace = get_async_stack_trace(p.pid) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) - finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None - # First check all the tasks are present - tasks_names = [ - task.task_name for task in stack_trace[0].awaited_by - ] - for task_name in ["Task-1", "Task-2"]: - self.assertIn(task_name, tasks_names) + response = _wait_for_signal(client_socket, b"ready") + self.assertIn(b"ready", response) - # Now ensure that the awaited_by_relationships are correct - id_to_task = { - task.task_id: task for task in stack_trace[0].awaited_by - } - task_name_to_awaited_by = { - task.task_name: set( - id_to_task[awaited.task_name].task_name - for awaited in task.awaited_by - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - task_name_to_awaited_by, - { - "Task-1": set(), - "Task-2": {"Task-1"}, - }, - ) + stack_trace = get_async_stack_trace(p.pid) - # Now ensure that the coroutine stacks are correct - coroutine_stacks = { - task.task_name: sorted( - tuple(tuple(frame) for frame in coro.call_stack) - for coro in task.coroutine_stack - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - coroutine_stacks, - { - "Task-1": [(tuple([script_name, 21, "main"]),)], - "Task-2": [ - ( - tuple([script_name, 11, "deep"]), - tuple([script_name, 15, "c1"]), - ) - ], - }, - ) + # Check all tasks are present + tasks_names = [ + task.task_name for task in stack_trace[0].awaited_by + ] + for task_name in ["Task-1", "Task-2"]: + self.assertIn(task_name, tasks_names) - # Now ensure the coroutine stacks for the awaited_by relationships are correct. - awaited_by_coroutine_stacks = { - task.task_name: sorted( - ( - id_to_task[coro.task_name].task_name, - tuple(tuple(frame) for frame in coro.call_stack), + # Check awaited_by relationships + relationships = self._get_awaited_by_relationships( + stack_trace ) - for coro in task.awaited_by - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - awaited_by_coroutine_stacks, - { - "Task-1": [], - "Task-2": [ - ("Task-1", (tuple([script_name, 21, "main"]),)) - ], - }, - ) + self.assertEqual( + relationships, + { + "Task-1": set(), + "Task-2": {"Task-1"}, + }, + ) + + # Check coroutine stacks (using line numbers only to avoid + # flakiness from column offset variations when sampling + # catches different statements on the same line) + coroutine_stacks = self._extract_coroutine_stacks_lineno_only( + stack_trace + ) + self.assertEqual( + coroutine_stacks, + { + "Task-1": [((script_name, 21, "main", None),)], + "Task-2": [ + ( + (script_name, 11, "deep", None), + (script_name, 15, "c1", None), + ) + ], + }, + ) + + # Check awaited_by coroutine stacks (line numbers only) + id_to_task = self._get_task_id_map(stack_trace) + awaited_by_coroutine_stacks = { + task.task_name: sorted( + ( + id_to_task[coro.task_name].task_name, + tuple( + self._frame_to_lineno_tuple(frame) for frame in coro.call_stack + ), + ) + for coro in task.awaited_by + ) + for task in stack_trace[0].awaited_by + } + self.assertEqual( + awaited_by_coroutine_stacks, + { + "Task-1": [], + "Task-2": [ + ("Task-1", ((script_name, 21, "main", None),)) + ], + }, + ) + finally: + _cleanup_sockets(client_socket, server_socket) @skip_if_not_supported @unittest.skipIf( @@ -625,7 +896,6 @@ class TestGetStackTrace(unittest.TestCase): "Test only runs on Linux with process_vm_readv support", ) def test_async_staggered_race_remote_stack_trace(self): - # Spawn a process with some realistic Python code port = find_unused_port() script = textwrap.dedent( f"""\ @@ -633,13 +903,13 @@ class TestGetStackTrace(unittest.TestCase): import time import sys import socket - # Connect to the test process + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) async def deep(): await asyncio.sleep(0) - sock.sendall(b"ready"); time.sleep(10_000) # same line number + sock.sendall(b"ready"); time.sleep(10_000) async def c1(): await asyncio.sleep(0) @@ -657,123 +927,101 @@ class TestGetStackTrace(unittest.TestCase): asyncio.run(main()) """ ) - stack_trace = None + with os_helper.temp_dir() as work_dir: script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - # Create a socket server to communicate with the target process - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) + + server_socket = _create_server_socket(port) script_name = _make_test_script(script_dir, "script", script) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() - response = client_socket.recv(1024) - self.assertEqual(response, b"ready") - stack_trace = get_async_stack_trace(p.pid) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) - finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None - # First check all the tasks are present - tasks_names = [ - task.task_name for task in stack_trace[0].awaited_by - ] - for task_name in ["Task-1", "Task-2"]: - self.assertIn(task_name, tasks_names) + response = _wait_for_signal(client_socket, b"ready") + self.assertIn(b"ready", response) - # Now ensure that the awaited_by_relationships are correct - id_to_task = { - task.task_id: task for task in stack_trace[0].awaited_by - } - task_name_to_awaited_by = { - task.task_name: set( - id_to_task[awaited.task_name].task_name - for awaited in task.awaited_by - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - task_name_to_awaited_by, - { - "Task-1": set(), - "Task-2": {"Task-1"}, - }, - ) + stack_trace = get_async_stack_trace(p.pid) - # Now ensure that the coroutine stacks are correct - coroutine_stacks = { - task.task_name: sorted( - tuple(tuple(frame) for frame in coro.call_stack) - for coro in task.coroutine_stack - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - coroutine_stacks, - { - "Task-1": [ - ( - tuple([staggered.__file__, ANY, "staggered_race"]), - tuple([script_name, 21, "main"]), - ) - ], - "Task-2": [ - ( - tuple([script_name, 11, "deep"]), - tuple([script_name, 15, "c1"]), - tuple( - [ - staggered.__file__, - ANY, - "staggered_race..run_one_coro", - ] - ), - ) - ], - }, - ) + # Check all tasks are present + tasks_names = [ + task.task_name for task in stack_trace[0].awaited_by + ] + for task_name in ["Task-1", "Task-2"]: + self.assertIn(task_name, tasks_names) - # Now ensure the coroutine stacks for the awaited_by relationships are correct. - awaited_by_coroutine_stacks = { - task.task_name: sorted( - ( - id_to_task[coro.task_name].task_name, - tuple(tuple(frame) for frame in coro.call_stack), + # Check awaited_by relationships + relationships = self._get_awaited_by_relationships( + stack_trace ) - for coro in task.awaited_by - ) - for task in stack_trace[0].awaited_by - } - self.assertEqual( - awaited_by_coroutine_stacks, - { - "Task-1": [], - "Task-2": [ - ( - "Task-1", + self.assertEqual( + relationships, + { + "Task-1": set(), + "Task-2": {"Task-1"}, + }, + ) + + # Check coroutine stacks (using line numbers only to avoid + # flakiness from column offset variations when sampling + # catches different statements on the same line) + coroutine_stacks = self._extract_coroutine_stacks_lineno_only( + stack_trace + ) + self.assertEqual( + coroutine_stacks, + { + "Task-1": [ + ( + (staggered.__file__, ANY, "staggered_race", None), + (script_name, 21, "main", None), + ) + ], + "Task-2": [ + ( + (script_name, 11, "deep", None), + (script_name, 15, "c1", None), + (staggered.__file__, ANY, "staggered_race..run_one_coro", None), + ) + ], + }, + ) + + # Check awaited_by coroutine stacks (line numbers only) + id_to_task = self._get_task_id_map(stack_trace) + awaited_by_coroutine_stacks = { + task.task_name: sorted( ( + id_to_task[coro.task_name].task_name, tuple( - [staggered.__file__, ANY, "staggered_race"] + self._frame_to_lineno_tuple(frame) for frame in coro.call_stack ), - tuple([script_name, 21, "main"]), - ), + ) + for coro in task.awaited_by ) - ], - }, - ) + for task in stack_trace[0].awaited_by + } + self.assertEqual( + awaited_by_coroutine_stacks, + { + "Task-1": [], + "Task-2": [ + ( + "Task-1", + ( + (staggered.__file__, ANY, "staggered_race", None), + (script_name, 21, "main", None), + ), + ) + ], + }, + ) + finally: + _cleanup_sockets(client_socket, server_socket) @skip_if_not_supported @unittest.skipIf( @@ -781,6 +1029,10 @@ class TestGetStackTrace(unittest.TestCase): "Test only runs on Linux with process_vm_readv support", ) def test_async_global_awaited_by(self): + # Reduced from 1000 to 100 to avoid file descriptor exhaustion + # when running tests in parallel (e.g., -j 20) + NUM_TASKS = 100 + port = find_unused_port() script = textwrap.dedent( f"""\ @@ -796,7 +1048,6 @@ class TestGetStackTrace(unittest.TestCase): PORT = socket_helper.find_unused_port() connections = 0 - # Connect to the test process sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) @@ -819,23 +1070,16 @@ class TestGetStackTrace(unittest.TestCase): assert message == data.decode() writer.close() await writer.wait_closed() - # Signal we are ready to sleep sock.sendall(b"ready") await asyncio.sleep(SHORT_TIMEOUT) async def echo_client_spam(server): async with asyncio.TaskGroup() as tg: - while connections < 1000: + while connections < {NUM_TASKS}: msg = list(ascii_lowercase + digits) random.shuffle(msg) tg.create_task(echo_client("".join(msg))) await asyncio.sleep(0) - # at least a 1000 tasks created. Each task will signal - # when is ready to avoid the race caused by the fact that - # tasks are waited on tg.__exit__ and we cannot signal when - # that happens otherwise - # at this point all client tasks completed without assertion errors - # let's wrap up the test server.close() await server.wait_closed() @@ -850,231 +1094,207 @@ class TestGetStackTrace(unittest.TestCase): asyncio.run(main()) """ ) - stack_trace = None + with os_helper.temp_dir() as work_dir: script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - # Create a socket server to communicate with the target process - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) + + server_socket = _create_server_socket(port) script_name = _make_test_script(script_dir, "script", script) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() - for _ in range(1000): - expected_response = b"ready" - response = client_socket.recv(len(expected_response)) - self.assertEqual(response, expected_response) - for _ in busy_retry(SHORT_TIMEOUT): + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None + + # Wait for NUM_TASKS "ready" signals try: - all_awaited_by = get_all_awaited_by(p.pid) - except RuntimeError as re: - # This call reads a linked list in another process with - # no synchronization. That occasionally leads to invalid - # reads. Here we avoid making the test flaky. - msg = str(re) - if msg.startswith("Task list appears corrupted"): - continue - elif msg.startswith( - "Invalid linked list structure reading remote memory" - ): - continue - elif msg.startswith("Unknown error reading memory"): - continue - elif msg.startswith("Unhandled frame owner"): - continue - raise # Unrecognized exception, safest not to ignore it - else: - break - # expected: a list of two elements: 1 thread, 1 interp - self.assertEqual(len(all_awaited_by), 2) - # expected: a tuple with the thread ID and the awaited_by list - self.assertEqual(len(all_awaited_by[0]), 2) - # expected: no tasks in the fallback per-interp task list - self.assertEqual(all_awaited_by[1], (0, [])) - entries = all_awaited_by[0][1] - # expected: at least 1000 pending tasks - self.assertGreaterEqual(len(entries), 1000) - # the first three tasks stem from the code structure - main_stack = [ - FrameInfo([taskgroups.__file__, ANY, "TaskGroup._aexit"]), - FrameInfo( - [taskgroups.__file__, ANY, "TaskGroup.__aexit__"] - ), - FrameInfo([script_name, 60, "main"]), - ] - self.assertIn( - TaskInfo( - [ANY, "Task-1", [CoroInfo([main_stack, ANY])], []] - ), - entries, - ) - self.assertIn( - TaskInfo( - [ - ANY, - "server task", - [ - CoroInfo( - [ - [ - FrameInfo( - [ - base_events.__file__, - ANY, - "Server.serve_forever", - ] - ) - ], - ANY, - ] - ) - ], - [ - CoroInfo( - [ - [ - FrameInfo( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] - ), - FrameInfo( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] - ), - FrameInfo( - [script_name, ANY, "main"] - ), - ], - ANY, - ] - ) - ], - ] - ), - entries, - ) - self.assertIn( - TaskInfo( - [ - ANY, - "Task-4", - [ - CoroInfo( - [ - [ - FrameInfo( - [tasks.__file__, ANY, "sleep"] - ), - FrameInfo( - [ - script_name, - 38, - "echo_client", - ] - ), - ], - ANY, - ] - ) - ], - [ - CoroInfo( - [ - [ - FrameInfo( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] - ), - FrameInfo( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] - ), - FrameInfo( - [ - script_name, - 41, - "echo_client_spam", - ] - ), - ], - ANY, - ] - ) - ], - ] - ), - entries, - ) + _wait_for_n_signals(client_socket, b"ready", NUM_TASKS) + except RuntimeError as e: + self.fail(str(e)) - expected_awaited_by = [ - CoroInfo( - [ - [ - FrameInfo( - [ - taskgroups.__file__, - ANY, - "TaskGroup._aexit", - ] - ), - FrameInfo( - [ - taskgroups.__file__, - ANY, - "TaskGroup.__aexit__", - ] - ), - FrameInfo( - [script_name, 41, "echo_client_spam"] - ), - ], - ANY, - ] - ) - ] - tasks_with_awaited = [ - task - for task in entries - if task.awaited_by == expected_awaited_by - ] - self.assertGreaterEqual(len(tasks_with_awaited), 1000) + all_awaited_by = get_all_awaited_by(p.pid) - # the final task will have some random number, but it should for - # sure be one of the echo client spam horde (In windows this is not true - # for some reason) - if sys.platform != "win32": - self.assertEqual( - tasks_with_awaited[-1].awaited_by, - entries[-1].awaited_by, + # Expected: a list of two elements: 1 thread, 1 interp + self.assertEqual(len(all_awaited_by), 2) + # Expected: a tuple with the thread ID and the awaited_by list + self.assertEqual(len(all_awaited_by[0]), 2) + # Expected: no tasks in the fallback per-interp task list + self.assertEqual(all_awaited_by[1], (0, [])) + + entries = all_awaited_by[0][1] + # Expected: at least NUM_TASKS pending tasks + self.assertGreaterEqual(len(entries), NUM_TASKS) + + # Check the main task structure + main_stack = [ + FrameInfo( + [taskgroups.__file__, ANY, "TaskGroup._aexit", ANY] + ), + FrameInfo( + [taskgroups.__file__, ANY, "TaskGroup.__aexit__", ANY] + ), + FrameInfo([script_name, ANY, "main", ANY]), + ] + self.assertIn( + TaskInfo( + [ANY, "Task-1", [CoroInfo([main_stack, ANY])], []] + ), + entries, ) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) + self.assertIn( + TaskInfo( + [ + ANY, + "server task", + [ + CoroInfo( + [ + [ + FrameInfo( + [ + base_events.__file__, + ANY, + "Server.serve_forever", + ANY, + ] + ) + ], + ANY, + ] + ) + ], + [ + CoroInfo( + [ + [ + FrameInfo( + [ + taskgroups.__file__, + ANY, + "TaskGroup._aexit", + ANY, + ] + ), + FrameInfo( + [ + taskgroups.__file__, + ANY, + "TaskGroup.__aexit__", + ANY, + ] + ), + FrameInfo( + [script_name, ANY, "main", ANY] + ), + ], + ANY, + ] + ) + ], + ] + ), + entries, + ) + self.assertIn( + TaskInfo( + [ + ANY, + "Task-4", + [ + CoroInfo( + [ + [ + FrameInfo( + [ + tasks.__file__, + ANY, + "sleep", + ANY, + ] + ), + FrameInfo( + [ + script_name, + ANY, + "echo_client", + ANY, + ] + ), + ], + ANY, + ] + ) + ], + [ + CoroInfo( + [ + [ + FrameInfo( + [ + taskgroups.__file__, + ANY, + "TaskGroup._aexit", + ANY, + ] + ), + FrameInfo( + [ + taskgroups.__file__, + ANY, + "TaskGroup.__aexit__", + ANY, + ] + ), + FrameInfo( + [ + script_name, + ANY, + "echo_client_spam", + ANY, + ] + ), + ], + ANY, + ] + ) + ], + ] + ), + entries, + ) + + # Find tasks awaited by echo_client_spam via TaskGroup + def matches_awaited_by_pattern(task): + if len(task.awaited_by) != 1: + return False + coro = task.awaited_by[0] + if len(coro.call_stack) != 3: + return False + funcnames = [f.funcname for f in coro.call_stack] + return funcnames == [ + "TaskGroup._aexit", + "TaskGroup.__aexit__", + "echo_client_spam", + ] + + tasks_with_awaited = [ + task + for task in entries + if matches_awaited_by_pattern(task) + ] + self.assertGreaterEqual(len(tasks_with_awaited), NUM_TASKS) + + # Final task should be from echo client spam (not on Windows) + if sys.platform != "win32": + self.assertEqual( + tasks_with_awaited[-1].awaited_by, + entries[-1].awaited_by, + ) finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) + _cleanup_sockets(client_socket, server_socket) @skip_if_not_supported @unittest.skipIf( @@ -1083,34 +1303,342 @@ class TestGetStackTrace(unittest.TestCase): ) def test_self_trace(self): stack_trace = get_stack_trace(os.getpid()) - # Is possible that there are more threads, so we check that the - # expected stack traces are in the result (looking at you Windows!) - this_tread_stack = None - for thread_id, stack in stack_trace: - if thread_id == threading.get_native_id(): - this_tread_stack = stack + + this_thread_stack = None + for interpreter_info in stack_trace: + for thread_info in interpreter_info.threads: + if thread_info.thread_id == threading.get_native_id(): + this_thread_stack = thread_info.frame_info + break + if this_thread_stack: break - self.assertIsNotNone(this_tread_stack) - self.assertEqual( - stack[:2], - [ - FrameInfo( - [ - __file__, - get_stack_trace.__code__.co_firstlineno + 2, - "get_stack_trace", - ] - ), - FrameInfo( - [ - __file__, - self.test_self_trace.__code__.co_firstlineno + 6, - "TestGetStackTrace.test_self_trace", - ] - ), - ], + + self.assertIsNotNone(this_thread_stack) + # Check the top two frames + self.assertGreaterEqual(len(this_thread_stack), 2) + self.assertEqual(this_thread_stack[0].funcname, "get_stack_trace") + self.assertTrue(this_thread_stack[0].filename.endswith("test_external_inspection.py")) + self.assertEqual(this_thread_stack[1].funcname, "TestGetStackTrace.test_self_trace") + self.assertTrue(this_thread_stack[1].filename.endswith("test_external_inspection.py")) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + @requires_subinterpreters + def test_subinterpreter_stack_trace(self): + port = find_unused_port() + + import pickle + + subinterp_code = textwrap.dedent(f""" + import socket + import time + + def sub_worker(): + def nested_func(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + sock.sendall(b"ready:sub\\n") + time.sleep(10_000) + nested_func() + + sub_worker() + """).strip() + + pickled_code = pickle.dumps(subinterp_code) + + script = textwrap.dedent( + f""" + from concurrent import interpreters + import time + import sys + import socket + import threading + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + + def main_worker(): + sock.sendall(b"ready:main\\n") + time.sleep(10_000) + + def run_subinterp(): + subinterp = interpreters.create() + import pickle + pickled_code = {pickled_code!r} + subinterp_code = pickle.loads(pickled_code) + subinterp.exec(subinterp_code) + + sub_thread = threading.Thread(target=run_subinterp) + sub_thread.start() + + main_thread = threading.Thread(target=main_worker) + main_thread.start() + + main_thread.join() + sub_thread.join() + """ ) + with os_helper.temp_dir() as work_dir: + script_dir = os.path.join(work_dir, "script_pkg") + os.mkdir(script_dir) + + server_socket = _create_server_socket(port) + script_name = _make_test_script(script_dir, "script", script) + client_sockets = [] + + try: + with _managed_subprocess([sys.executable, script_name]) as p: + # Accept connections from both main and subinterpreter + responses = set() + while len(responses) < 2: + try: + client_socket, _ = server_socket.accept() + client_sockets.append(client_socket) + response = client_socket.recv(1024) + if b"ready:main" in response: + responses.add("main") + if b"ready:sub" in response: + responses.add("sub") + except socket.timeout: + break + + server_socket.close() + server_socket = None + + stack_trace = get_stack_trace(p.pid) + + # Verify we have at least one interpreter + self.assertGreaterEqual(len(stack_trace), 1) + + # Look for main interpreter (ID 0) and subinterpreter (ID > 0) + main_interp = None + sub_interp = None + for interpreter_info in stack_trace: + if interpreter_info.interpreter_id == 0: + main_interp = interpreter_info + elif interpreter_info.interpreter_id > 0: + sub_interp = interpreter_info + + self.assertIsNotNone( + main_interp, "Main interpreter should be present" + ) + + # Check main interpreter has expected stack trace + main_found = self._find_frame_in_trace( + [main_interp], lambda f: f.funcname == "main_worker" + ) + self.assertIsNotNone( + main_found, + "Main interpreter should have main_worker in stack", + ) + + # If subinterpreter is present, check its stack trace + if sub_interp: + sub_found = self._find_frame_in_trace( + [sub_interp], + lambda f: f.funcname + in ("sub_worker", "nested_func"), + ) + self.assertIsNotNone( + sub_found, + "Subinterpreter should have sub_worker or nested_func in stack", + ) + finally: + _cleanup_sockets(*client_sockets, server_socket) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + @requires_subinterpreters + def test_multiple_subinterpreters_with_threads(self): + port = find_unused_port() + + import pickle + + subinterp1_code = textwrap.dedent(f""" + import socket + import time + import threading + + def worker1(): + def nested_func(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + sock.sendall(b"ready:sub1-t1\\n") + time.sleep(10_000) + nested_func() + + def worker2(): + def nested_func(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + sock.sendall(b"ready:sub1-t2\\n") + time.sleep(10_000) + nested_func() + + t1 = threading.Thread(target=worker1) + t2 = threading.Thread(target=worker2) + t1.start() + t2.start() + t1.join() + t2.join() + """).strip() + + subinterp2_code = textwrap.dedent(f""" + import socket + import time + import threading + + def worker1(): + def nested_func(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + sock.sendall(b"ready:sub2-t1\\n") + time.sleep(10_000) + nested_func() + + def worker2(): + def nested_func(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + sock.sendall(b"ready:sub2-t2\\n") + time.sleep(10_000) + nested_func() + + t1 = threading.Thread(target=worker1) + t2 = threading.Thread(target=worker2) + t1.start() + t2.start() + t1.join() + t2.join() + """).strip() + + pickled_code1 = pickle.dumps(subinterp1_code) + pickled_code2 = pickle.dumps(subinterp2_code) + + script = textwrap.dedent( + f""" + from concurrent import interpreters + import time + import sys + import socket + import threading + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + + def main_worker(): + sock.sendall(b"ready:main\\n") + time.sleep(10_000) + + def run_subinterp1(): + subinterp = interpreters.create() + import pickle + pickled_code = {pickled_code1!r} + subinterp_code = pickle.loads(pickled_code) + subinterp.exec(subinterp_code) + + def run_subinterp2(): + subinterp = interpreters.create() + import pickle + pickled_code = {pickled_code2!r} + subinterp_code = pickle.loads(pickled_code) + subinterp.exec(subinterp_code) + + sub1_thread = threading.Thread(target=run_subinterp1) + sub2_thread = threading.Thread(target=run_subinterp2) + sub1_thread.start() + sub2_thread.start() + + main_thread = threading.Thread(target=main_worker) + main_thread.start() + + main_thread.join() + sub1_thread.join() + sub2_thread.join() + """ + ) + + with os_helper.temp_dir() as work_dir: + script_dir = os.path.join(work_dir, "script_pkg") + os.mkdir(script_dir) + + server_socket = _create_server_socket(port, backlog=5) + script_name = _make_test_script(script_dir, "script", script) + client_sockets = [] + + try: + with _managed_subprocess([sys.executable, script_name]) as p: + # Accept connections from main and all subinterpreter threads + expected_responses = { + "ready:main", + "ready:sub1-t1", + "ready:sub1-t2", + "ready:sub2-t1", + "ready:sub2-t2", + } + responses = set() + + while len(responses) < 5: + try: + client_socket, _ = server_socket.accept() + client_sockets.append(client_socket) + response = client_socket.recv(1024) + response_str = response.decode().strip() + if response_str in expected_responses: + responses.add(response_str) + except socket.timeout: + break + + server_socket.close() + server_socket = None + + stack_trace = get_stack_trace(p.pid) + + # Verify we have multiple interpreters + self.assertGreaterEqual(len(stack_trace), 2) + + # Count interpreters by ID + interpreter_ids = { + interp.interpreter_id for interp in stack_trace + } + self.assertIn( + 0, + interpreter_ids, + "Main interpreter should be present", + ) + self.assertGreaterEqual(len(interpreter_ids), 3) + + # Count total threads + total_threads = sum( + len(interp.threads) for interp in stack_trace + ) + self.assertGreaterEqual(total_threads, 5) + + # Look for expected function names + all_funcnames = set() + for interpreter_info in stack_trace: + for thread_info in interpreter_info.threads: + for frame in thread_info.frame_info: + all_funcnames.add(frame.funcname) + + expected_funcs = { + "main_worker", + "worker1", + "worker2", + "nested_func", + } + found_funcs = expected_funcs.intersection(all_funcnames) + self.assertGreater(len(found_funcs), 0) + finally: + _cleanup_sockets(*client_sockets, server_socket) + @skip_if_not_supported @unittest.skipIf( sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, @@ -1118,54 +1646,41 @@ class TestGetStackTrace(unittest.TestCase): ) @requires_gil_enabled("Free threaded builds don't have an 'active thread'") def test_only_active_thread(self): - # Test that only_active_thread parameter works correctly port = find_unused_port() script = textwrap.dedent( f"""\ import time, sys, socket, threading - # Connect to the test process sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', {port})) def worker_thread(name, barrier, ready_event): - barrier.wait() # Synchronize thread start - ready_event.wait() # Wait for main thread signal - # Sleep to keep thread alive + barrier.wait() + ready_event.wait() time.sleep(10_000) def main_work(): - # Do busy work to hold the GIL sock.sendall(b"working\\n") count = 0 while count < 100000000: count += 1 if count % 10000000 == 0: - pass # Keep main thread busy + pass sock.sendall(b"done\\n") - # Create synchronization primitives num_threads = 3 - barrier = threading.Barrier(num_threads + 1) # +1 for main thread + barrier = threading.Barrier(num_threads + 1) ready_event = threading.Event() - # Start worker threads threads = [] for i in range(num_threads): t = threading.Thread(target=worker_thread, args=(f"Worker-{{i}}", barrier, ready_event)) t.start() threads.append(t) - # Wait for all threads to be ready barrier.wait() - - # Signal ready to parent process sock.sendall(b"ready\\n") - - # Signal threads to start waiting ready_event.set() - - # Now do busy work to hold the GIL main_work() """ ) @@ -1174,87 +1689,201 @@ class TestGetStackTrace(unittest.TestCase): script_dir = os.path.join(work_dir, "script_pkg") os.mkdir(script_dir) - # Create a socket server to communicate with the target process - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) - + server_socket = _create_server_socket(port) script_name = _make_test_script(script_dir, "script", script) client_socket = None + try: - p = subprocess.Popen([sys.executable, script_name]) - client_socket, _ = server_socket.accept() - server_socket.close() + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None - # Wait for ready signal - response = b"" - while b"ready" not in response: - response += client_socket.recv(1024) + # Wait for ready and working signals + _wait_for_signal(client_socket, [b"ready", b"working"]) - # Wait for the main thread to start its busy work - while b"working" not in response: - response += client_socket.recv(1024) + # Get stack trace with all threads + unwinder_all = RemoteUnwinder(p.pid, all_threads=True) + for _ in range(MAX_TRIES): + all_traces = unwinder_all.get_stack_trace() + found = self._find_frame_in_trace( + all_traces, + lambda f: f.funcname == "main_work" + and f.location.lineno > 12, + ) + if found: + break + time.sleep(0.1) + else: + self.fail( + "Main thread did not start its busy work on time" + ) - # Get stack trace with all threads - unwinder_all = RemoteUnwinder(p.pid, all_threads=True) - for _ in range(10): - # Wait for the main thread to start its busy work - all_traces = unwinder_all.get_stack_trace() - found = False - for thread_id, stack in all_traces: - if not stack: - continue - current_frame = stack[0] - if ( - current_frame.funcname == "main_work" - and current_frame.lineno > 15 - ): - found = True - - if found: - break - # Give a bit of time to take the next sample - time.sleep(0.1) - else: - self.fail( - "Main thread did not start its busy work on time" + # Get stack trace with only GIL holder + unwinder_gil = RemoteUnwinder( + p.pid, only_active_thread=True ) + gil_traces = unwinder_gil.get_stack_trace() - # Get stack trace with only GIL holder - unwinder_gil = RemoteUnwinder(p.pid, only_active_thread=True) - gil_traces = unwinder_gil.get_stack_trace() + # Count threads + total_threads = sum( + len(interp.threads) for interp in all_traces + ) + self.assertGreater(total_threads, 1) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) + total_gil_threads = sum( + len(interp.threads) for interp in gil_traces + ) + self.assertEqual(total_gil_threads, 1) + + # Get the GIL holder thread ID + gil_thread_id = None + for interpreter_info in gil_traces: + if interpreter_info.threads: + gil_thread_id = interpreter_info.threads[ + 0 + ].thread_id + break + + # Get all thread IDs + all_thread_ids = [] + for interpreter_info in all_traces: + for thread_info in interpreter_info.threads: + all_thread_ids.append(thread_info.thread_id) + + self.assertIn(gil_thread_id, all_thread_ids) finally: - if client_socket is not None: - client_socket.close() - p.kill() - p.terminate() - p.wait(timeout=SHORT_TIMEOUT) + _cleanup_sockets(client_socket, server_socket) - # Verify we got multiple threads in all_traces - self.assertGreater( - len(all_traces), 1, "Should have multiple threads" - ) + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_opcodes_collection(self): + """Test that opcodes are collected when the opcodes flag is set.""" + script = textwrap.dedent( + """\ + import time, sys, socket - # Verify we got exactly one thread in gil_traces - self.assertEqual( - len(gil_traces), 1, "Should have exactly one GIL holder" - ) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) - # The GIL holder should be in the all_traces list - gil_thread_id = gil_traces[0][0] - all_thread_ids = [trace[0] for trace in all_traces] - self.assertIn( - gil_thread_id, - all_thread_ids, - "GIL holder should be among all threads", - ) + def foo(): + sock.sendall(b"ready") + time.sleep(10_000) + + foo() + """ + ) + + def get_trace_with_opcodes(pid): + return RemoteUnwinder(pid, opcodes=True).get_stack_trace() + + stack_trace, _ = self._run_script_and_get_trace( + script, get_trace_with_opcodes, wait_for_signals=b"ready" + ) + + # Find our foo frame and verify it has an opcode + foo_frame = self._find_frame_in_trace( + stack_trace, lambda f: f.funcname == "foo" + ) + self.assertIsNotNone(foo_frame, "Could not find foo frame") + self.assertIsInstance(foo_frame.opcode, int) + self.assertGreaterEqual(foo_frame.opcode, 0) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_location_tuple_format(self): + """Test that location is a 4-tuple (lineno, end_lineno, col_offset, end_col_offset).""" + script = textwrap.dedent( + """\ + import time, sys, socket + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + + def foo(): + sock.sendall(b"ready") + time.sleep(10_000) + + foo() + """ + ) + + def get_trace_with_opcodes(pid): + return RemoteUnwinder(pid, opcodes=True).get_stack_trace() + + stack_trace, _ = self._run_script_and_get_trace( + script, get_trace_with_opcodes, wait_for_signals=b"ready" + ) + + # Find our foo frame + foo_frame = self._find_frame_in_trace( + stack_trace, lambda f: f.funcname == "foo" + ) + self.assertIsNotNone(foo_frame, "Could not find foo frame") + + # Check location is a 4-tuple with valid values + location = foo_frame.location + self.assertIsInstance(location, tuple) + self.assertEqual(len(location), 4) + lineno, end_lineno, col_offset, end_col_offset = location + self.assertIsInstance(lineno, int) + self.assertGreater(lineno, 0) + self.assertIsInstance(end_lineno, int) + self.assertGreaterEqual(end_lineno, lineno) + self.assertIsInstance(col_offset, int) + self.assertGreaterEqual(col_offset, 0) + self.assertIsInstance(end_col_offset, int) + self.assertGreaterEqual(end_col_offset, col_offset) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_location_tuple_exact_values(self): + """Test exact values of location tuple including column offsets.""" + script = textwrap.dedent( + """\ + import time, sys, socket + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + + def foo(): + sock.sendall(b"ready") + time.sleep(10_000) + + foo() + """ + ) + + def get_trace_with_opcodes(pid): + return RemoteUnwinder(pid, opcodes=True).get_stack_trace() + + stack_trace, _ = self._run_script_and_get_trace( + script, get_trace_with_opcodes, wait_for_signals=b"ready" + ) + + foo_frame = self._find_frame_in_trace( + stack_trace, lambda f: f.funcname == "foo" + ) + self.assertIsNotNone(foo_frame, "Could not find foo frame") + + # Can catch either sock.sendall (line 7) or time.sleep (line 8) + location = foo_frame.location + valid_locations = [ + (7, 7, 4, 26), # sock.sendall(b"ready") + (8, 8, 4, 22), # time.sleep(10_000) + ] + actual = (location.lineno, location.end_lineno, + location.col_offset, location.end_col_offset) + self.assertIn(actual, valid_locations) class TestUnsupportedPlatformHandling(unittest.TestCase): @@ -1262,16 +1891,1599 @@ class TestUnsupportedPlatformHandling(unittest.TestCase): sys.platform in ("linux", "darwin", "win32"), "Test only runs on unsupported platforms (not Linux, macOS, or Windows)", ) - @unittest.skipIf(sys.platform == "android", "Android raises Linux-specific exception") + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) def test_unsupported_platform_error(self): with self.assertRaises(RuntimeError) as cm: RemoteUnwinder(os.getpid()) self.assertIn( "Reading the PyRuntime section is not supported on this platform", - str(cm.exception) + str(cm.exception), ) +@requires_remote_subprocess_debugging() +class TestDetectionOfThreadStatus(RemoteInspectionTestBase): + def _run_thread_status_test(self, mode, check_condition): + """ + Common pattern for thread status detection tests. + + Args: + mode: Profiling mode (PROFILING_MODE_CPU, PROFILING_MODE_GIL, etc.) + check_condition: Function(statuses, sleeper_tid, busy_tid) -> bool + """ + port = find_unused_port() + script = textwrap.dedent( + f"""\ + import time, sys, socket, threading + import os + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', {port})) + + def sleeper(): + tid = threading.get_native_id() + sock.sendall(f'ready:sleeper:{{tid}}\\n'.encode()) + time.sleep(10000) + + def busy(): + tid = threading.get_native_id() + sock.sendall(f'ready:busy:{{tid}}\\n'.encode()) + x = 0 + while True: + x = x + 1 + time.sleep(0.5) + + t1 = threading.Thread(target=sleeper) + t2 = threading.Thread(target=busy) + t1.start() + t2.start() + sock.sendall(b'ready:main\\n') + t1.join() + t2.join() + sock.close() + """ + ) + + with os_helper.temp_dir() as work_dir: + script_dir = os.path.join(work_dir, "script_pkg") + os.mkdir(script_dir) + + server_socket = _create_server_socket(port) + script_name = _make_test_script( + script_dir, "thread_status_script", script + ) + client_socket = None + + try: + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None + + # Wait for all ready signals and parse TIDs + response = _wait_for_signal( + client_socket, + [b"ready:main", b"ready:sleeper", b"ready:busy"], + ) + + sleeper_tid = None + busy_tid = None + for line in response.split(b"\n"): + if line.startswith(b"ready:sleeper:"): + try: + sleeper_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + elif line.startswith(b"ready:busy:"): + try: + busy_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + + self.assertIsNotNone( + sleeper_tid, "Sleeper thread id not received" + ) + self.assertIsNotNone( + busy_tid, "Busy thread id not received" + ) + + # Sample until we see expected thread states + statuses = {} + unwinder = RemoteUnwinder( + p.pid, + all_threads=True, + mode=mode, + skip_non_matching_threads=False, + ) + for _ in range(MAX_TRIES): + traces = unwinder.get_stack_trace() + statuses = self._get_thread_statuses(traces) + + if check_condition( + statuses, sleeper_tid, busy_tid + ): + break + time.sleep(0.5) + + return statuses, sleeper_tid, busy_tid + finally: + _cleanup_sockets(client_socket, server_socket) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_thread_status_detection(self): + def check_cpu_status(statuses, sleeper_tid, busy_tid): + return ( + sleeper_tid in statuses + and busy_tid in statuses + and not (statuses[sleeper_tid] & THREAD_STATUS_ON_CPU) + and (statuses[busy_tid] & THREAD_STATUS_ON_CPU) + ) + + statuses, sleeper_tid, busy_tid = self._run_thread_status_test( + PROFILING_MODE_CPU, check_cpu_status + ) + + self.assertIn(sleeper_tid, statuses) + self.assertIn(busy_tid, statuses) + self.assertFalse( + statuses[sleeper_tid] & THREAD_STATUS_ON_CPU, + "Sleeper thread should be off CPU", + ) + self.assertTrue( + statuses[busy_tid] & THREAD_STATUS_ON_CPU, + "Busy thread should be on CPU", + ) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_thread_status_gil_detection(self): + def check_gil_status(statuses, sleeper_tid, busy_tid): + return ( + sleeper_tid in statuses + and busy_tid in statuses + and not (statuses[sleeper_tid] & THREAD_STATUS_HAS_GIL) + and (statuses[busy_tid] & THREAD_STATUS_HAS_GIL) + ) + + statuses, sleeper_tid, busy_tid = self._run_thread_status_test( + PROFILING_MODE_GIL, check_gil_status + ) + + self.assertIn(sleeper_tid, statuses) + self.assertIn(busy_tid, statuses) + self.assertFalse( + statuses[sleeper_tid] & THREAD_STATUS_HAS_GIL, + "Sleeper thread should not have GIL", + ) + self.assertTrue( + statuses[busy_tid] & THREAD_STATUS_HAS_GIL, + "Busy thread should have GIL", + ) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_thread_status_all_mode_detection(self): + port = find_unused_port() + script = textwrap.dedent( + f"""\ + import socket + import threading + import time + import sys + + def sleeper_thread(): + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"sleeper:" + str(threading.get_native_id()).encode()) + while True: + time.sleep(1) + + def busy_thread(): + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"busy:" + str(threading.get_native_id()).encode()) + while True: + sum(range(100000)) + + t1 = threading.Thread(target=sleeper_thread) + t2 = threading.Thread(target=busy_thread) + t1.start() + t2.start() + t1.join() + t2.join() + """ + ) + + with os_helper.temp_dir() as tmp_dir: + script_file = make_script(tmp_dir, "script", script) + server_socket = _create_server_socket(port, backlog=2) + client_sockets = [] + + try: + with _managed_subprocess( + [sys.executable, script_file], + ) as p: + sleeper_tid = None + busy_tid = None + + # Receive thread IDs from the child process + for _ in range(2): + client_socket, _ = server_socket.accept() + client_sockets.append(client_socket) + line = client_socket.recv(1024) + if line: + if line.startswith(b"sleeper:"): + try: + sleeper_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + elif line.startswith(b"busy:"): + try: + busy_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + + server_socket.close() + server_socket = None + + statuses = {} + unwinder = RemoteUnwinder( + p.pid, + all_threads=True, + mode=PROFILING_MODE_ALL, + skip_non_matching_threads=False, + ) + for _ in range(MAX_TRIES): + traces = unwinder.get_stack_trace() + statuses = self._get_thread_statuses(traces) + + # Check ALL mode provides both GIL and CPU info + if ( + sleeper_tid in statuses + and busy_tid in statuses + and not ( + statuses[sleeper_tid] + & THREAD_STATUS_ON_CPU + ) + and not ( + statuses[sleeper_tid] + & THREAD_STATUS_HAS_GIL + ) + and (statuses[busy_tid] & THREAD_STATUS_ON_CPU) + and ( + statuses[busy_tid] & THREAD_STATUS_HAS_GIL + ) + ): + break + time.sleep(0.5) + + self.assertIsNotNone( + sleeper_tid, "Sleeper thread id not received" + ) + self.assertIsNotNone( + busy_tid, "Busy thread id not received" + ) + self.assertIn(sleeper_tid, statuses) + self.assertIn(busy_tid, statuses) + + # Sleeper: off CPU, no GIL + self.assertFalse( + statuses[sleeper_tid] & THREAD_STATUS_ON_CPU, + "Sleeper should be off CPU", + ) + self.assertFalse( + statuses[sleeper_tid] & THREAD_STATUS_HAS_GIL, + "Sleeper should not have GIL", + ) + + # Busy: on CPU, has GIL + self.assertTrue( + statuses[busy_tid] & THREAD_STATUS_ON_CPU, + "Busy should be on CPU", + ) + self.assertTrue( + statuses[busy_tid] & THREAD_STATUS_HAS_GIL, + "Busy should have GIL", + ) + finally: + _cleanup_sockets(*client_sockets, server_socket) + + def _make_exception_test_script(self, port): + """Create script with exception and normal threads for testing.""" + return textwrap.dedent( + f"""\ + import socket + import threading + import time + + def exception_thread(): + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"exception:" + str(threading.get_native_id()).encode()) + try: + raise ValueError("test exception") + except ValueError: + while True: + time.sleep(0.01) + + def normal_thread(): + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"normal:" + str(threading.get_native_id()).encode()) + while True: + sum(range(1000)) + + t1 = threading.Thread(target=exception_thread) + t2 = threading.Thread(target=normal_thread) + t1.start() + t2.start() + t1.join() + t2.join() + """ + ) + + @contextmanager + def _run_exception_test_process(self): + """Context manager to run exception test script and yield thread IDs and process.""" + port = find_unused_port() + script = self._make_exception_test_script(port) + + with os_helper.temp_dir() as tmp_dir: + script_file = make_script(tmp_dir, "script", script) + server_socket = _create_server_socket(port, backlog=2) + client_sockets = [] + + try: + with _managed_subprocess([sys.executable, script_file]) as p: + exception_tid = None + normal_tid = None + + for _ in range(2): + client_socket, _ = server_socket.accept() + client_sockets.append(client_socket) + line = client_socket.recv(1024) + if line: + if line.startswith(b"exception:"): + try: + exception_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + elif line.startswith(b"normal:"): + try: + normal_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + + server_socket.close() + server_socket = None + + yield p, exception_tid, normal_tid + finally: + _cleanup_sockets(*client_sockets, server_socket) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_thread_status_exception_detection(self): + """Test that THREAD_STATUS_HAS_EXCEPTION is set when thread has an active exception.""" + with self._run_exception_test_process() as (p, exception_tid, normal_tid): + self.assertIsNotNone(exception_tid, "Exception thread id not received") + self.assertIsNotNone(normal_tid, "Normal thread id not received") + + statuses = {} + unwinder = RemoteUnwinder( + p.pid, + all_threads=True, + mode=PROFILING_MODE_ALL, + skip_non_matching_threads=False, + ) + for _ in range(MAX_TRIES): + traces = unwinder.get_stack_trace() + statuses = self._get_thread_statuses(traces) + + if ( + exception_tid in statuses + and normal_tid in statuses + and (statuses[exception_tid] & THREAD_STATUS_HAS_EXCEPTION) + and not (statuses[normal_tid] & THREAD_STATUS_HAS_EXCEPTION) + ): + break + time.sleep(0.5) + + self.assertIn(exception_tid, statuses) + self.assertIn(normal_tid, statuses) + self.assertTrue( + statuses[exception_tid] & THREAD_STATUS_HAS_EXCEPTION, + "Exception thread should have HAS_EXCEPTION flag", + ) + self.assertFalse( + statuses[normal_tid] & THREAD_STATUS_HAS_EXCEPTION, + "Normal thread should not have HAS_EXCEPTION flag", + ) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_thread_status_exception_mode_filtering(self): + """Test that PROFILING_MODE_EXCEPTION correctly filters threads.""" + with self._run_exception_test_process() as (p, exception_tid, normal_tid): + self.assertIsNotNone(exception_tid, "Exception thread id not received") + self.assertIsNotNone(normal_tid, "Normal thread id not received") + + unwinder = RemoteUnwinder( + p.pid, + all_threads=True, + mode=PROFILING_MODE_EXCEPTION, + skip_non_matching_threads=True, + ) + for _ in range(MAX_TRIES): + traces = unwinder.get_stack_trace() + statuses = self._get_thread_statuses(traces) + + if exception_tid in statuses: + self.assertNotIn( + normal_tid, + statuses, + "Normal thread should be filtered out in exception mode", + ) + return + time.sleep(0.5) + + self.fail("Never found exception thread in exception mode") + +@requires_remote_subprocess_debugging() +class TestExceptionDetectionScenarios(RemoteInspectionTestBase): + """Test exception detection across all scenarios. + + This class verifies the exact conditions under which THREAD_STATUS_HAS_EXCEPTION + is set. Each test covers a specific scenario: + + 1. except_block: Thread inside except block + -> SHOULD have HAS_EXCEPTION (exc_info->exc_value is set) + + 2. finally_propagating: Exception propagating through finally block + -> SHOULD have HAS_EXCEPTION (current_exception is set) + + 3. finally_after_except: Finally block after except handled exception + -> Should NOT have HAS_EXCEPTION (exc_info cleared after except) + + 4. finally_no_exception: Finally block with no exception raised + -> Should NOT have HAS_EXCEPTION (no exception state) + """ + + def _make_single_scenario_script(self, port, scenario): + """Create script for a single exception scenario.""" + scenarios = { + "except_block": f"""\ +import socket +import threading +import time + +def target_thread(): + '''Inside except block - exception info is present''' + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"ready:" + str(threading.get_native_id()).encode()) + try: + raise ValueError("test") + except ValueError: + while True: + time.sleep(0.01) + +t = threading.Thread(target=target_thread) +t.start() +t.join() +""", + "finally_propagating": f"""\ +import socket +import threading +import time + +def target_thread(): + '''Exception propagating through finally - current_exception is set''' + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"ready:" + str(threading.get_native_id()).encode()) + try: + try: + raise ValueError("propagating") + finally: + # Exception is propagating through here + while True: + time.sleep(0.01) + except: + pass # Never reached due to infinite loop + +t = threading.Thread(target=target_thread) +t.start() +t.join() +""", + "finally_after_except": f"""\ +import socket +import threading +import time + +def target_thread(): + '''Finally runs after except handled - exc_info is cleared''' + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"ready:" + str(threading.get_native_id()).encode()) + try: + raise ValueError("test") + except ValueError: + pass # Exception caught and handled + finally: + while True: + time.sleep(0.01) + +t = threading.Thread(target=target_thread) +t.start() +t.join() +""", + "finally_no_exception": f"""\ +import socket +import threading +import time + +def target_thread(): + '''Finally with no exception at all''' + conn = socket.create_connection(("localhost", {port})) + conn.sendall(b"ready:" + str(threading.get_native_id()).encode()) + try: + pass # No exception + finally: + while True: + time.sleep(0.01) + +t = threading.Thread(target=target_thread) +t.start() +t.join() +""", + } + + return scenarios[scenario] + + @contextmanager + def _run_scenario_process(self, scenario): + """Context manager to run a single scenario and yield thread ID and process.""" + port = find_unused_port() + script = self._make_single_scenario_script(port, scenario) + + with os_helper.temp_dir() as tmp_dir: + script_file = make_script(tmp_dir, "script", script) + server_socket = _create_server_socket(port, backlog=1) + client_socket = None + + try: + with _managed_subprocess([sys.executable, script_file]) as p: + thread_tid = None + + client_socket, _ = server_socket.accept() + line = client_socket.recv(1024) + if line and line.startswith(b"ready:"): + try: + thread_tid = int(line.split(b":")[-1]) + except (ValueError, IndexError): + pass + + server_socket.close() + server_socket = None + + yield p, thread_tid + finally: + _cleanup_sockets(client_socket, server_socket) + + def _check_exception_status(self, p, thread_tid, expect_exception): + """Helper to check if thread has expected exception status.""" + unwinder = RemoteUnwinder( + p.pid, + all_threads=True, + mode=PROFILING_MODE_ALL, + skip_non_matching_threads=False, + ) + + # Collect multiple samples for reliability + results = [] + for _ in range(MAX_TRIES): + traces = unwinder.get_stack_trace() + statuses = self._get_thread_statuses(traces) + + if thread_tid in statuses: + has_exc = bool(statuses[thread_tid] & THREAD_STATUS_HAS_EXCEPTION) + results.append(has_exc) + + if len(results) >= 3: + break + + time.sleep(0.2) + + # Check majority of samples match expected + if not results: + self.fail("Never found target thread in stack traces") + + majority = sum(results) > len(results) // 2 + if expect_exception: + self.assertTrue( + majority, + f"Thread should have HAS_EXCEPTION flag, got {results}" + ) + else: + self.assertFalse( + majority, + f"Thread should NOT have HAS_EXCEPTION flag, got {results}" + ) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_except_block_has_exception(self): + """Test that thread inside except block has HAS_EXCEPTION flag. + + When a thread is executing inside an except block, exc_info->exc_value + is set, so THREAD_STATUS_HAS_EXCEPTION should be True. + """ + with self._run_scenario_process("except_block") as (p, thread_tid): + self.assertIsNotNone(thread_tid, "Thread ID not received") + self._check_exception_status(p, thread_tid, expect_exception=True) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_finally_propagating_has_exception(self): + """Test that finally block with propagating exception has HAS_EXCEPTION flag. + + When an exception is propagating through a finally block (not yet caught), + current_exception is set, so THREAD_STATUS_HAS_EXCEPTION should be True. + """ + with self._run_scenario_process("finally_propagating") as (p, thread_tid): + self.assertIsNotNone(thread_tid, "Thread ID not received") + self._check_exception_status(p, thread_tid, expect_exception=True) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_finally_after_except_no_exception(self): + """Test that finally block after except has NO HAS_EXCEPTION flag. + + When a finally block runs after an except block has handled the exception, + Python clears exc_info before entering finally, so THREAD_STATUS_HAS_EXCEPTION + should be False. + """ + with self._run_scenario_process("finally_after_except") as (p, thread_tid): + self.assertIsNotNone(thread_tid, "Thread ID not received") + self._check_exception_status(p, thread_tid, expect_exception=False) + + @unittest.skipIf( + sys.platform not in ("linux", "darwin", "win32"), + "Test only runs on supported platforms (Linux, macOS, or Windows)", + ) + @unittest.skipIf( + sys.platform == "android", "Android raises Linux-specific exception" + ) + def test_finally_no_exception_no_flag(self): + """Test that finally block with no exception has NO HAS_EXCEPTION flag. + + When a finally block runs during normal execution (no exception raised), + there is no exception state, so THREAD_STATUS_HAS_EXCEPTION should be False. + """ + with self._run_scenario_process("finally_no_exception") as (p, thread_tid): + self.assertIsNotNone(thread_tid, "Thread ID not received") + self._check_exception_status(p, thread_tid, expect_exception=False) + + +@requires_remote_subprocess_debugging() +class TestFrameCaching(RemoteInspectionTestBase): + """Test that frame caching produces correct results. + + Uses socket-based synchronization for deterministic testing. + All tests verify cache reuse via object identity checks (assertIs). + """ + + @contextmanager + def _target_process(self, script_body): + """Context manager for running a target process with socket sync.""" + port = find_unused_port() + script = f"""\ +import socket +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +sock.connect(('localhost', {port})) +{textwrap.dedent(script_body)} +""" + + with os_helper.temp_dir() as work_dir: + script_dir = os.path.join(work_dir, "script_pkg") + os.mkdir(script_dir) + + server_socket = _create_server_socket(port) + script_name = _make_test_script(script_dir, "script", script) + client_socket = None + + try: + with _managed_subprocess([sys.executable, script_name]) as p: + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None + + def make_unwinder(cache_frames=True): + return RemoteUnwinder( + p.pid, all_threads=True, cache_frames=cache_frames + ) + + yield p, client_socket, make_unwinder + finally: + _cleanup_sockets(client_socket, server_socket) + + def _get_frames_with_retry(self, unwinder, required_funcs): + """Get frames containing required_funcs, with retry for transient errors.""" + for _ in range(MAX_TRIES): + with contextlib.suppress(OSError, RuntimeError): + traces = unwinder.get_stack_trace() + for interp in traces: + for thread in interp.threads: + funcs = {f.funcname for f in thread.frame_info} + if required_funcs.issubset(funcs): + return thread.frame_info + time.sleep(0.1) + return None + + def _sample_frames( + self, + client_socket, + unwinder, + wait_signal, + send_ack, + required_funcs, + expected_frames=1, + ): + """Wait for signal, sample frames with retry until required funcs present, send ack.""" + _wait_for_signal(client_socket, wait_signal) + frames = None + for _ in range(MAX_TRIES): + frames = self._get_frames_with_retry(unwinder, required_funcs) + if frames and len(frames) >= expected_frames: + break + time.sleep(0.1) + client_socket.sendall(send_ack) + return frames + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_cache_hit_same_stack(self): + """Test that consecutive samples reuse cached parent frame objects. + + The current frame (index 0) is always re-read from memory to get + updated line numbers, so it may be a different object. Parent frames + (index 1+) should be identical objects from cache. + """ + script_body = """\ + def level3(): + sock.sendall(b"sync1") + sock.recv(16) + sock.sendall(b"sync2") + sock.recv(16) + sock.sendall(b"sync3") + sock.recv(16) + + def level2(): + level3() + + def level1(): + level2() + + level1() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + expected = {"level1", "level2", "level3"} + + frames1 = self._sample_frames( + client_socket, unwinder, b"sync1", b"ack", expected + ) + frames2 = self._sample_frames( + client_socket, unwinder, b"sync2", b"ack", expected + ) + frames3 = self._sample_frames( + client_socket, unwinder, b"sync3", b"done", expected + ) + + self.assertIsNotNone(frames1) + self.assertIsNotNone(frames2) + self.assertIsNotNone(frames3) + self.assertEqual(len(frames1), len(frames2)) + self.assertEqual(len(frames2), len(frames3)) + + # Current frame (index 0) is always re-read, so check value equality + self.assertEqual(frames1[0].funcname, frames2[0].funcname) + self.assertEqual(frames2[0].funcname, frames3[0].funcname) + + # Parent frames (index 1+) must be identical objects (cache reuse) + for i in range(1, len(frames1)): + f1, f2, f3 = frames1[i], frames2[i], frames3[i] + self.assertIs( + f1, f2, f"Frame {i}: samples 1-2 must be same object" + ) + self.assertIs( + f2, f3, f"Frame {i}: samples 2-3 must be same object" + ) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_line_number_updates_in_same_frame(self): + """Test that line numbers are correctly updated when execution moves within a function. + + When the profiler samples at different points within the same function, + it must report the correct line number for each sample, not stale cached values. + """ + script_body = """\ + def outer(): + inner() + + def inner(): + sock.sendall(b"line_a"); sock.recv(16) + sock.sendall(b"line_b"); sock.recv(16) + sock.sendall(b"line_c"); sock.recv(16) + sock.sendall(b"line_d"); sock.recv(16) + + outer() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + + frames_a = self._sample_frames( + client_socket, unwinder, b"line_a", b"ack", {"inner"} + ) + frames_b = self._sample_frames( + client_socket, unwinder, b"line_b", b"ack", {"inner"} + ) + frames_c = self._sample_frames( + client_socket, unwinder, b"line_c", b"ack", {"inner"} + ) + frames_d = self._sample_frames( + client_socket, unwinder, b"line_d", b"done", {"inner"} + ) + + self.assertIsNotNone(frames_a) + self.assertIsNotNone(frames_b) + self.assertIsNotNone(frames_c) + self.assertIsNotNone(frames_d) + + # Get the 'inner' frame from each sample (should be index 0) + inner_a = frames_a[0] + inner_b = frames_b[0] + inner_c = frames_c[0] + inner_d = frames_d[0] + + self.assertEqual(inner_a.funcname, "inner") + self.assertEqual(inner_b.funcname, "inner") + self.assertEqual(inner_c.funcname, "inner") + self.assertEqual(inner_d.funcname, "inner") + + # Line numbers must be different and increasing (execution moves forward) + self.assertLess( + inner_a.location.lineno, inner_b.location.lineno, "Line B should be after line A" + ) + self.assertLess( + inner_b.location.lineno, inner_c.location.lineno, "Line C should be after line B" + ) + self.assertLess( + inner_c.location.lineno, inner_d.location.lineno, "Line D should be after line C" + ) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_cache_invalidation_on_return(self): + """Test cache invalidation when stack shrinks (function returns).""" + script_body = """\ + def inner(): + sock.sendall(b"at_inner") + sock.recv(16) + + def outer(): + inner() + sock.sendall(b"at_outer") + sock.recv(16) + + outer() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + + frames_deep = self._sample_frames( + client_socket, + unwinder, + b"at_inner", + b"ack", + {"inner", "outer"}, + ) + frames_shallow = self._sample_frames( + client_socket, unwinder, b"at_outer", b"done", {"outer"} + ) + + self.assertIsNotNone(frames_deep) + self.assertIsNotNone(frames_shallow) + + funcs_deep = [f.funcname for f in frames_deep] + funcs_shallow = [f.funcname for f in frames_shallow] + + self.assertIn("inner", funcs_deep) + self.assertIn("outer", funcs_deep) + self.assertNotIn("inner", funcs_shallow) + self.assertIn("outer", funcs_shallow) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_cache_invalidation_on_call(self): + """Test cache invalidation when stack grows (new function called).""" + script_body = """\ + def deeper(): + sock.sendall(b"at_deeper") + sock.recv(16) + + def middle(): + sock.sendall(b"at_middle") + sock.recv(16) + deeper() + + def top(): + middle() + + top() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + + frames_before = self._sample_frames( + client_socket, + unwinder, + b"at_middle", + b"ack", + {"middle", "top"}, + ) + frames_after = self._sample_frames( + client_socket, + unwinder, + b"at_deeper", + b"done", + {"deeper", "middle", "top"}, + ) + + self.assertIsNotNone(frames_before) + self.assertIsNotNone(frames_after) + + funcs_before = [f.funcname for f in frames_before] + funcs_after = [f.funcname for f in frames_after] + + self.assertIn("middle", funcs_before) + self.assertIn("top", funcs_before) + self.assertNotIn("deeper", funcs_before) + + self.assertIn("deeper", funcs_after) + self.assertIn("middle", funcs_after) + self.assertIn("top", funcs_after) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_partial_stack_reuse(self): + """Test that unchanged bottom frames are reused when top changes (A→B→C to A→B→D).""" + script_body = """\ + def func_c(): + sock.sendall(b"at_c") + sock.recv(16) + + def func_d(): + sock.sendall(b"at_d") + sock.recv(16) + + def func_b(): + func_c() + func_d() + + def func_a(): + func_b() + + func_a() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + + # Sample at C: stack is A→B→C + frames_c = self._sample_frames( + client_socket, + unwinder, + b"at_c", + b"ack", + {"func_a", "func_b", "func_c"}, + ) + # Sample at D: stack is A→B→D (C returned, D called) + frames_d = self._sample_frames( + client_socket, + unwinder, + b"at_d", + b"done", + {"func_a", "func_b", "func_d"}, + ) + + self.assertIsNotNone(frames_c) + self.assertIsNotNone(frames_d) + + # Find func_a and func_b frames in both samples + def find_frame(frames, funcname): + for f in frames: + if f.funcname == funcname: + return f + return None + + frame_a_in_c = find_frame(frames_c, "func_a") + frame_b_in_c = find_frame(frames_c, "func_b") + frame_a_in_d = find_frame(frames_d, "func_a") + frame_b_in_d = find_frame(frames_d, "func_b") + + self.assertIsNotNone(frame_a_in_c) + self.assertIsNotNone(frame_b_in_c) + self.assertIsNotNone(frame_a_in_d) + self.assertIsNotNone(frame_b_in_d) + + # The bottom frames (A, B) should be the SAME objects (cache reuse) + self.assertIs( + frame_a_in_c, + frame_a_in_d, + "func_a frame should be reused from cache", + ) + self.assertIs( + frame_b_in_c, + frame_b_in_d, + "func_b frame should be reused from cache", + ) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_recursive_frames(self): + """Test caching with same function appearing multiple times (recursion).""" + script_body = """\ + def recurse(n): + if n <= 0: + sock.sendall(b"sync1") + sock.recv(16) + sock.sendall(b"sync2") + sock.recv(16) + else: + recurse(n - 1) + + recurse(5) + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + + frames1 = self._sample_frames( + client_socket, unwinder, b"sync1", b"ack", {"recurse"} + ) + frames2 = self._sample_frames( + client_socket, unwinder, b"sync2", b"done", {"recurse"} + ) + + self.assertIsNotNone(frames1) + self.assertIsNotNone(frames2) + + # Should have multiple "recurse" frames (6 total: recurse(5) down to recurse(0)) + recurse_count = sum(1 for f in frames1 if f.funcname == "recurse") + self.assertEqual(recurse_count, 6, "Should have 6 recursive frames") + + self.assertEqual(len(frames1), len(frames2)) + + # Current frame (index 0) is re-read, check value equality + self.assertEqual(frames1[0].funcname, frames2[0].funcname) + + # Parent frames (index 1+) should be identical objects (cache reuse) + for i in range(1, len(frames1)): + self.assertIs( + frames1[i], + frames2[i], + f"Frame {i}: recursive frames must be same object", + ) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_cache_vs_no_cache_equivalence(self): + """Test that cache_frames=True and cache_frames=False produce equivalent results.""" + script_body = """\ + def level3(): + sock.sendall(b"ready"); sock.recv(16) + + def level2(): + level3() + + def level1(): + level2() + + level1() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + _wait_for_signal(client_socket, b"ready") + + # Sample with cache + unwinder_cache = make_unwinder(cache_frames=True) + frames_cached = self._get_frames_with_retry( + unwinder_cache, {"level1", "level2", "level3"} + ) + + # Sample without cache + unwinder_no_cache = make_unwinder(cache_frames=False) + frames_no_cache = self._get_frames_with_retry( + unwinder_no_cache, {"level1", "level2", "level3"} + ) + + client_socket.sendall(b"done") + + self.assertIsNotNone(frames_cached) + self.assertIsNotNone(frames_no_cache) + + # Same number of frames + self.assertEqual(len(frames_cached), len(frames_no_cache)) + + # Same function names in same order + funcs_cached = [f.funcname for f in frames_cached] + funcs_no_cache = [f.funcname for f in frames_no_cache] + self.assertEqual(funcs_cached, funcs_no_cache) + + # For level3 (leaf frame), due to timing races we can be at either + # sock.sendall() or sock.recv() - both are valid. For parent frames, + # the locations should match exactly. + # Valid locations for level3: line 3 has two statements + # sock.sendall(b"ready") -> col 4-26 + # sock.recv(16) -> col 28-41 + level3_valid_cols = {(4, 26), (28, 41)} + + for i in range(len(frames_cached)): + loc_cached = frames_cached[i].location + loc_no_cache = frames_no_cache[i].location + + if frames_cached[i].funcname == "level3": + # Leaf frame: can be at either statement + self.assertIn( + (loc_cached.col_offset, loc_cached.end_col_offset), + level3_valid_cols, + ) + self.assertIn( + (loc_no_cache.col_offset, loc_no_cache.end_col_offset), + level3_valid_cols, + ) + else: + # Parent frames: must match exactly + self.assertEqual(loc_cached, loc_no_cache) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_cache_per_thread_isolation(self): + """Test that frame cache is per-thread and cache invalidation works independently.""" + script_body = """\ + import threading + + lock = threading.Lock() + + def sync(msg): + with lock: + sock.sendall(msg + b"\\n") + sock.recv(1) + + # Thread 1 functions + def baz1(): + sync(b"t1:baz1") + + def bar1(): + baz1() + + def blech1(): + sync(b"t1:blech1") + + def foo1(): + bar1() # Goes down to baz1, syncs + blech1() # Returns up, goes down to blech1, syncs + + # Thread 2 functions + def baz2(): + sync(b"t2:baz2") + + def bar2(): + baz2() + + def blech2(): + sync(b"t2:blech2") + + def foo2(): + bar2() # Goes down to baz2, syncs + blech2() # Returns up, goes down to blech2, syncs + + t1 = threading.Thread(target=foo1) + t2 = threading.Thread(target=foo2) + t1.start() + t2.start() + t1.join() + t2.join() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder = make_unwinder(cache_frames=True) + + # Message dispatch table: signal -> required functions for that thread + dispatch = { + b"t1:baz1": {"baz1", "bar1", "foo1"}, + b"t2:baz2": {"baz2", "bar2", "foo2"}, + b"t1:blech1": {"blech1", "foo1"}, + b"t2:blech2": {"blech2", "foo2"}, + } + + # Track results for each sync point + results = {} + + # Process 4 sync points (order depends on thread scheduling) + buffer = _wait_for_signal(client_socket, b"\n") + for i in range(4): + # Extract first message from buffer + msg, sep, buffer = buffer.partition(b"\n") + self.assertIn(msg, dispatch, f"Unexpected message: {msg!r}") + + # Sample frames for the thread at this sync point + required_funcs = dispatch[msg] + frames = self._get_frames_with_retry(unwinder, required_funcs) + self.assertIsNotNone(frames, f"Thread not found for {msg!r}") + results[msg] = [f.funcname for f in frames] + + # Release thread and wait for next message (if not last) + client_socket.sendall(b"k") + if i < 3: + buffer += _wait_for_signal(client_socket, b"\n") + + # Validate Phase 1: baz snapshots + t1_baz = results.get(b"t1:baz1") + t2_baz = results.get(b"t2:baz2") + self.assertIsNotNone(t1_baz, "Missing t1:baz1 snapshot") + self.assertIsNotNone(t2_baz, "Missing t2:baz2 snapshot") + + # Thread 1 at baz1: should have foo1->bar1->baz1 + self.assertIn("baz1", t1_baz) + self.assertIn("bar1", t1_baz) + self.assertIn("foo1", t1_baz) + self.assertNotIn("blech1", t1_baz) + # No cross-contamination + self.assertNotIn("baz2", t1_baz) + self.assertNotIn("bar2", t1_baz) + self.assertNotIn("foo2", t1_baz) + + # Thread 2 at baz2: should have foo2->bar2->baz2 + self.assertIn("baz2", t2_baz) + self.assertIn("bar2", t2_baz) + self.assertIn("foo2", t2_baz) + self.assertNotIn("blech2", t2_baz) + # No cross-contamination + self.assertNotIn("baz1", t2_baz) + self.assertNotIn("bar1", t2_baz) + self.assertNotIn("foo1", t2_baz) + + # Validate Phase 2: blech snapshots (cache invalidation test) + t1_blech = results.get(b"t1:blech1") + t2_blech = results.get(b"t2:blech2") + self.assertIsNotNone(t1_blech, "Missing t1:blech1 snapshot") + self.assertIsNotNone(t2_blech, "Missing t2:blech2 snapshot") + + # Thread 1 at blech1: bar1/baz1 should be GONE (cache invalidated) + self.assertIn("blech1", t1_blech) + self.assertIn("foo1", t1_blech) + self.assertNotIn( + "bar1", t1_blech, "Cache not invalidated: bar1 still present" + ) + self.assertNotIn( + "baz1", t1_blech, "Cache not invalidated: baz1 still present" + ) + # No cross-contamination + self.assertNotIn("blech2", t1_blech) + + # Thread 2 at blech2: bar2/baz2 should be GONE (cache invalidated) + self.assertIn("blech2", t2_blech) + self.assertIn("foo2", t2_blech) + self.assertNotIn( + "bar2", t2_blech, "Cache not invalidated: bar2 still present" + ) + self.assertNotIn( + "baz2", t2_blech, "Cache not invalidated: baz2 still present" + ) + # No cross-contamination + self.assertNotIn("blech1", t2_blech) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_new_unwinder_with_stale_last_profiled_frame(self): + """Test that a new unwinder returns complete stack when cache lookup misses.""" + script_body = """\ + def level4(): + sock.sendall(b"sync1") + sock.recv(16) + sock.sendall(b"sync2") + sock.recv(16) + + def level3(): + level4() + + def level2(): + level3() + + def level1(): + level2() + + level1() + """ + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + expected = {"level1", "level2", "level3", "level4"} + + # First unwinder samples - this sets last_profiled_frame in target + unwinder1 = make_unwinder(cache_frames=True) + frames1 = self._sample_frames( + client_socket, unwinder1, b"sync1", b"ack", expected + ) + + # Create NEW unwinder (empty cache) and sample + # The target still has last_profiled_frame set from unwinder1 + unwinder2 = make_unwinder(cache_frames=True) + frames2 = self._sample_frames( + client_socket, unwinder2, b"sync2", b"done", expected + ) + + self.assertIsNotNone(frames1) + self.assertIsNotNone(frames2) + + funcs1 = [f.funcname for f in frames1] + funcs2 = [f.funcname for f in frames2] + + # Both should have all levels + for level in ["level1", "level2", "level3", "level4"]: + self.assertIn(level, funcs1, f"{level} missing from first sample") + self.assertIn(level, funcs2, f"{level} missing from second sample") + + # Should have same stack depth + self.assertEqual( + len(frames1), + len(frames2), + "New unwinder should return complete stack despite stale last_profiled_frame", + ) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_cache_exhaustion(self): + """Test cache works when frame limit (1024) is exceeded. + + FRAME_CACHE_MAX_FRAMES=1024. With 1100 recursive frames, + the cache can't store all of them but should still work. + """ + # Use 1100 to exceed FRAME_CACHE_MAX_FRAMES=1024 + depth = 1100 + script_body = f"""\ +import sys +sys.setrecursionlimit(2000) + +def recurse(n): + if n <= 0: + sock.sendall(b"ready") + sock.recv(16) # wait for ack + sock.sendall(b"ready2") + sock.recv(16) # wait for done + return + recurse(n - 1) + +recurse({depth}) +""" + + with self._target_process(script_body) as ( + p, + client_socket, + make_unwinder, + ): + unwinder_cache = make_unwinder(cache_frames=True) + unwinder_no_cache = make_unwinder(cache_frames=False) + + frames_cached = self._sample_frames( + client_socket, + unwinder_cache, + b"ready", + b"ack", + {"recurse"}, + expected_frames=1102, + ) + # Sample again with no cache for comparison + frames_no_cache = self._sample_frames( + client_socket, + unwinder_no_cache, + b"ready2", + b"done", + {"recurse"}, + expected_frames=1102, + ) + + self.assertIsNotNone(frames_cached) + self.assertIsNotNone(frames_no_cache) + + # Both should have many recurse frames (> 1024 limit) + cached_count = [f.funcname for f in frames_cached].count("recurse") + no_cache_count = [f.funcname for f in frames_no_cache].count("recurse") + + self.assertGreater( + cached_count, 1000, "Should have >1000 recurse frames" + ) + self.assertGreater( + no_cache_count, 1000, "Should have >1000 recurse frames" + ) + + # Both modes should produce same frame count + self.assertEqual( + len(frames_cached), + len(frames_no_cache), + "Cache exhaustion should not affect stack completeness", + ) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_get_stats(self): + """Test that get_stats() returns statistics when stats=True.""" + script_body = """\ + sock.sendall(b"ready") + sock.recv(16) + """ + + with self._target_process(script_body) as (p, client_socket, _): + unwinder = RemoteUnwinder(p.pid, all_threads=True, stats=True) + _wait_for_signal(client_socket, b"ready") + + # Take a sample + unwinder.get_stack_trace() + + stats = unwinder.get_stats() + client_socket.sendall(b"done") + + # Verify expected keys exist + expected_keys = [ + "total_samples", + "frame_cache_hits", + "frame_cache_misses", + "frame_cache_partial_hits", + "frames_read_from_cache", + "frames_read_from_memory", + "frame_cache_hit_rate", + ] + for key in expected_keys: + self.assertIn(key, stats) + + self.assertEqual(stats["total_samples"], 1) + + @skip_if_not_supported + @unittest.skipIf( + sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, + "Test only runs on Linux with process_vm_readv support", + ) + def test_get_stats_disabled_raises(self): + """Test that get_stats() raises RuntimeError when stats=False.""" + script_body = """\ + sock.sendall(b"ready") + sock.recv(16) + """ + + with self._target_process(script_body) as (p, client_socket, _): + unwinder = RemoteUnwinder( + p.pid, all_threads=True + ) # stats=False by default + _wait_for_signal(client_socket, b"ready") + + with self.assertRaises(RuntimeError): + unwinder.get_stats() + + client_socket.sendall(b"done") + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_free_threading/test_bz2.py b/Lib/test/test_free_threading/test_bz2.py new file mode 100644 index 00000000000..3bb531ec04c --- /dev/null +++ b/Lib/test/test_free_threading/test_bz2.py @@ -0,0 +1,64 @@ +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +bz2 = import_helper.import_module("bz2") +from bz2 import BZ2Compressor, BZ2Decompressor + +from test.test_bz2 import ext_decompress, BaseTest + + +NTHREADS = 10 +TEXT = BaseTest.TEXT + + +@threading_helper.requires_working_threading() +class TestBZ2(unittest.TestCase): + def test_compressor(self): + bz2c = BZ2Compressor() + + def worker(): + # it should return empty bytes as it buffers data internally + data = bz2c.compress(TEXT) + self.assertEqual(data, b"") + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + data = bz2c.flush() + # The decompressed data should be TEXT repeated NTHREADS times + decompressed = ext_decompress(data) + self.assertEqual(decompressed, TEXT * NTHREADS) + + def test_decompressor(self): + chunk_size = 128 + chunks = [bytes([ord("a") + i]) * chunk_size for i in range(NTHREADS)] + input_data = b"".join(chunks) + compressed = bz2.compress(input_data) + + bz2d = BZ2Decompressor() + output = [] + + def worker(): + data = bz2d.decompress(compressed, chunk_size) + self.assertEqual(len(data), chunk_size) + output.append(data) + # Read attributes concurrently with other threads decompressing + self.assertIsInstance(bz2d.eof, bool) + self.assertIsInstance(bz2d.needs_input, bool) + self.assertIsInstance(bz2d.unused_data, bytes) + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(len(output), NTHREADS) + # Verify the expected chunks (order doesn't matter due to append race) + self.assertEqual(set(output), set(chunks)) + self.assertTrue(bz2d.eof) + self.assertFalse(bz2d.needs_input) + # Each thread added full compressed data to the buffer, but only 1 copy + # is consumed to produce the output. The rest remains as unused_data. + self.assertEqual( + len(bz2d.unused_data), len(compressed) * (NTHREADS - 1) + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_capi.py b/Lib/test/test_free_threading/test_capi.py new file mode 100644 index 00000000000..146d7cfc97a --- /dev/null +++ b/Lib/test/test_free_threading/test_capi.py @@ -0,0 +1,47 @@ +import ctypes +import sys +import unittest + +from test.support import threading_helper +from test.support.threading_helper import run_concurrently + + +_PyImport_AddModuleRef = ctypes.pythonapi.PyImport_AddModuleRef +_PyImport_AddModuleRef.argtypes = (ctypes.c_char_p,) +_PyImport_AddModuleRef.restype = ctypes.py_object + + +@threading_helper.requires_working_threading() +class TestImportCAPI(unittest.TestCase): + def test_pyimport_addmoduleref_thread_safe(self): + # gh-137422: Concurrent calls to PyImport_AddModuleRef with the same + # module name must return the same module object. + + NUM_ITERS = 10 + NTHREADS = 4 + + module_name = f"test_free_threading_addmoduleref_{id(self)}" + module_name_bytes = module_name.encode() + sys.modules.pop(module_name, None) + results = [] + + def worker(): + module = _PyImport_AddModuleRef(module_name_bytes) + results.append(module) + + for _ in range(NUM_ITERS): + try: + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(len(results), NTHREADS) + reference = results[0] + for module in results[1:]: + self.assertIs(module, reference) + self.assertIn(module_name, sys.modules) + self.assertIs(sys.modules[module_name], reference) + finally: + results.clear() + sys.modules.pop(module_name, None) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_cprofile.py b/Lib/test/test_free_threading/test_cprofile.py new file mode 100644 index 00000000000..361b800d6b9 --- /dev/null +++ b/Lib/test/test_free_threading/test_cprofile.py @@ -0,0 +1,43 @@ +import unittest + +from test.support import threading_helper + +import cProfile +import pstats + + +NTHREADS = 10 +INSERT_PER_THREAD = 1000 + + +@threading_helper.requires_working_threading() +class TestCProfile(unittest.TestCase): + def test_cprofile_racing_list_insert(self): + def list_insert(lst): + for i in range(INSERT_PER_THREAD): + lst.insert(0, i) + + lst = [] + + with cProfile.Profile() as pr: + threading_helper.run_concurrently( + worker_func=list_insert, nthreads=NTHREADS, args=(lst,) + ) + pr.create_stats() + ps = pstats.Stats(pr) + stats_profile = ps.get_stats_profile() + list_insert_profile = stats_profile.func_profiles[ + "" + ] + # Even though there is no explicit recursive call to insert, + # cProfile may record some calls as recursive due to limitations + # in its handling of multithreaded programs. This issue is not + # directly related to FT Python itself; however, it tends to be + # more noticeable when using FT Python. Therefore, consider only + # the calls section and disregard the recursive part. + list_insert_ncalls = list_insert_profile.ncalls.split("/")[0] + self.assertEqual( + int(list_insert_ncalls), NTHREADS * INSERT_PER_THREAD + ) + + self.assertEqual(len(lst), NTHREADS * INSERT_PER_THREAD) diff --git a/Lib/test/test_free_threading/test_csv.py b/Lib/test/test_free_threading/test_csv.py new file mode 100644 index 00000000000..beb4510a128 --- /dev/null +++ b/Lib/test/test_free_threading/test_csv.py @@ -0,0 +1,50 @@ +import csv +import io +import unittest + +from test.support import threading_helper +from test.support.threading_helper import run_concurrently + + +NTHREADS = 10 + + +@threading_helper.requires_working_threading() +class TestCSV(unittest.TestCase): + def test_concurrent_reader_next(self): + input_rows = [f"{i},{i},{i}" for i in range(50)] + input_stream = io.StringIO("\n".join(input_rows)) + reader = csv.reader(input_stream) + output_rows = [] + + def read_row(): + for row in reader: + self.assertEqual(len(row), 3) + output_rows.append(",".join(row)) + + run_concurrently(worker_func=read_row, nthreads=NTHREADS) + self.assertSetEqual(set(input_rows), set(output_rows)) + + def test_concurrent_writer_writerow(self): + output_stream = io.StringIO() + writer = csv.writer(output_stream) + row_per_thread = 10 + expected_rows = [] + + def write_row(): + for i in range(row_per_thread): + writer.writerow([i, i, i]) + expected_rows.append(f"{i},{i},{i}") + + run_concurrently(worker_func=write_row, nthreads=NTHREADS) + + # Rewind to the start of the stream and parse the rows + output_stream.seek(0) + output_rows = [line.strip() for line in output_stream.readlines()] + + self.assertEqual(len(output_rows), NTHREADS * row_per_thread) + self.assertListEqual(sorted(output_rows), sorted(expected_rows)) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_dbm_gnu.py b/Lib/test/test_free_threading/test_dbm_gnu.py new file mode 100644 index 00000000000..d2d7b78be71 --- /dev/null +++ b/Lib/test/test_free_threading/test_dbm_gnu.py @@ -0,0 +1,79 @@ +import unittest + +from test.support import import_helper, os_helper, threading_helper +from test.support.threading_helper import run_concurrently + +import threading + +gdbm = import_helper.import_module("dbm.gnu") + +NTHREADS = 10 +KEY_PER_THREAD = 1000 + +gdbm_filename = "test_gdbm_file" + + +@threading_helper.requires_working_threading() +class TestGdbm(unittest.TestCase): + def test_racing_dbm_gnu(self): + def gdbm_multi_op_worker(db): + # Each thread sets, gets, and iterates + tid = threading.get_ident() + + # Insert keys + for i in range(KEY_PER_THREAD): + db[f"key_{tid}_{i}"] = f"value_{tid}_{i}" + + for i in range(KEY_PER_THREAD): + # Keys and values are stored as bytes; encode values for + # comparison + key = f"key_{tid}_{i}" + value = f"value_{tid}_{i}".encode() + self.assertIn(key, db) + self.assertEqual(db[key], value) + self.assertEqual(db.get(key), value) + self.assertIsNone(db.get("not_exist")) + with self.assertRaises(KeyError): + db["not_exist"] + + # Iterate over the database keys and verify only those belonging + # to this thread. Other threads may concurrently delete their keys. + key_prefix = f"key_{tid}".encode() + key = db.firstkey() + key_count = 0 + while key: + if key.startswith(key_prefix): + self.assertIn(key, db) + key_count += 1 + key = db.nextkey(key) + + # Can't assert key_count == KEY_PER_THREAD because concurrent + # threads may insert or delete keys during iteration. This can + # cause keys to be skipped or counted multiple times, making the + # count unreliable. + # See: https://www.gnu.org.ua/software/gdbm/manual/Sequential.html + # self.assertEqual(key_count, KEY_PER_THREAD) + + # Delete this thread's keys + for i in range(KEY_PER_THREAD): + key = f"key_{tid}_{i}" + del db[key] + self.assertNotIn(key, db) + with self.assertRaises(KeyError): + del db["not_exist"] + + # Re-insert keys + for i in range(KEY_PER_THREAD): + db[f"key_{tid}_{i}"] = f"value_{tid}_{i}" + + with os_helper.temp_dir() as tmpdirname: + db = gdbm.open(f"{tmpdirname}/{gdbm_filename}", "c") + run_concurrently( + worker_func=gdbm_multi_op_worker, nthreads=NTHREADS, args=(db,) + ) + self.assertEqual(len(db), NTHREADS * KEY_PER_THREAD) + db.close() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_io.py b/Lib/test/test_free_threading/test_io.py index 41d89e04da8..c67aaff31b3 100644 --- a/Lib/test/test_free_threading/test_io.py +++ b/Lib/test/test_free_threading/test_io.py @@ -41,7 +41,7 @@ class ThreadSafetyMixin: def truncate(barrier, b, *ignore): barrier.wait() try: b.truncate(0) - except: BufferError # ignore exported buffer + except BufferError: pass # ignore exported buffer def read(barrier, b, *ignore): barrier.wait() diff --git a/Lib/test/test_free_threading/test_json.py b/Lib/test/test_free_threading/test_json.py new file mode 100644 index 00000000000..010eb322a15 --- /dev/null +++ b/Lib/test/test_free_threading/test_json.py @@ -0,0 +1,79 @@ +from threading import Barrier, Thread +from test.test_json import CTest +from test.support import threading_helper + + +def encode_json_helper( + json, worker, data, number_of_threads=12, number_of_json_encodings=100 +): + worker_threads = [] + barrier = Barrier(number_of_threads) + for index in range(number_of_threads): + worker_threads.append( + Thread(target=worker, args=[barrier, data, index]) + ) + for t in worker_threads: + t.start() + for ii in range(number_of_json_encodings): + json.dumps(data) + data.clear() + for t in worker_threads: + t.join() + + +class MyMapping(dict): + def __init__(self): + self.mapping = [] + + def items(self): + return self.mapping + + +@threading_helper.reap_threads +@threading_helper.requires_working_threading() +class TestJsonEncoding(CTest): + # Test encoding json with concurrent threads modifying the data cannot + # corrupt the interpreter + + def test_json_mutating_list(self): + def worker(barrier, data, index): + barrier.wait() + while data: + for d in data: + if len(d) > 5: + d.clear() + else: + d.append(index) + + data = [[], []] + encode_json_helper(self.json, worker, data) + + def test_json_mutating_exact_dict(self): + def worker(barrier, data, index): + barrier.wait() + while data: + for d in data: + if len(d) > 5: + try: + key = list(d)[0] + d.pop(key) + except (KeyError, IndexError): + pass + else: + d[index] = index + + data = [{}, {}] + encode_json_helper(self.json, worker, data) + + def test_json_mutating_mapping(self): + def worker(barrier, data, index): + barrier.wait() + while data: + for d in data: + if len(d.mapping) > 3: + d.mapping.clear() + else: + d.mapping.append((index, index)) + + data = [MyMapping(), MyMapping()] + encode_json_helper(self.json, worker, data) diff --git a/Lib/test/test_free_threading/test_lzma.py b/Lib/test/test_free_threading/test_lzma.py new file mode 100644 index 00000000000..38d7e5db489 --- /dev/null +++ b/Lib/test/test_free_threading/test_lzma.py @@ -0,0 +1,56 @@ +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +lzma = import_helper.import_module("lzma") +from lzma import LZMACompressor, LZMADecompressor + +from test.test_lzma import INPUT + + +NTHREADS = 10 + + +@threading_helper.requires_working_threading() +class TestLZMA(unittest.TestCase): + def test_compressor(self): + lzc = LZMACompressor() + + # First compress() outputs LZMA header + header = lzc.compress(INPUT) + self.assertGreater(len(header), 0) + + def worker(): + # it should return empty bytes as it buffers data internally + data = lzc.compress(INPUT) + self.assertEqual(data, b"") + + run_concurrently(worker_func=worker, nthreads=NTHREADS - 1) + full_compressed = header + lzc.flush() + decompressed = lzma.decompress(full_compressed) + # The decompressed data should be INPUT repeated NTHREADS times + self.assertEqual(decompressed, INPUT * NTHREADS) + + def test_decompressor(self): + chunk_size = 128 + chunks = [bytes([ord("a") + i]) * chunk_size for i in range(NTHREADS)] + input_data = b"".join(chunks) + compressed = lzma.compress(input_data) + + lzd = LZMADecompressor() + output = [] + + def worker(): + data = lzd.decompress(compressed, chunk_size) + self.assertEqual(len(data), chunk_size) + output.append(data) + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(len(output), NTHREADS) + # Verify the expected chunks (order doesn't matter due to append race) + self.assertSetEqual(set(output), set(chunks)) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_mmap.py b/Lib/test/test_free_threading/test_mmap.py new file mode 100644 index 00000000000..ece13d33f3b --- /dev/null +++ b/Lib/test/test_free_threading/test_mmap.py @@ -0,0 +1,315 @@ +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +import os +import string +import tempfile +import threading + +from collections import Counter + +mmap = import_helper.import_module("mmap") + +NTHREADS = 10 +ANONYMOUS_MEM = -1 + + +@threading_helper.requires_working_threading() +class MmapTests(unittest.TestCase): + def test_read_and_read_byte(self): + ascii_uppercase = string.ascii_uppercase.encode() + # Choose a total mmap size that evenly divides across threads and the + # read pattern (3 bytes per loop). + mmap_size = 3 * NTHREADS * len(ascii_uppercase) + num_bytes_to_read_per_thread = mmap_size // NTHREADS + bytes_read_from_mmap = [] + + def read(mm_obj): + nread = 0 + while nread < num_bytes_to_read_per_thread: + b = mm_obj.read_byte() + bytes_read_from_mmap.append(b) + b = mm_obj.read(2) + bytes_read_from_mmap.extend(b) + nread += 3 + + with mmap.mmap(ANONYMOUS_MEM, mmap_size) as mm_obj: + for i in range(mmap_size // len(ascii_uppercase)): + mm_obj.write(ascii_uppercase) + + mm_obj.seek(0) + run_concurrently( + worker_func=read, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + self.assertEqual(len(bytes_read_from_mmap), mmap_size) + # Count each letter/byte to verify read correctness + counter = Counter(bytes_read_from_mmap) + self.assertEqual(len(counter), len(ascii_uppercase)) + # Each letter/byte should be read (3 * NTHREADS) times + for letter in ascii_uppercase: + self.assertEqual(counter[letter], 3 * NTHREADS) + + def test_readline(self): + num_lines = 1000 + lines_read_from_mmap = [] + expected_lines = [] + + def readline(mm_obj): + for i in range(num_lines // NTHREADS): + line = mm_obj.readline() + lines_read_from_mmap.append(line) + + # Allocate mmap enough for num_lines (max line 5 bytes including NL) + with mmap.mmap(ANONYMOUS_MEM, num_lines * 5) as mm_obj: + for i in range(num_lines): + line = b"%d\n" % i + mm_obj.write(line) + expected_lines.append(line) + + mm_obj.seek(0) + run_concurrently( + worker_func=readline, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + self.assertEqual(len(lines_read_from_mmap), num_lines) + # Every line should be read once by threads; order is non-deterministic + # Sort numerically by integer value + lines_read_from_mmap.sort(key=lambda x: int(x)) + self.assertEqual(lines_read_from_mmap, expected_lines) + + def test_write_and_write_byte(self): + thread_letters = list(string.ascii_uppercase) + self.assertLessEqual(NTHREADS, len(thread_letters)) + per_thread_write_loop = 100 + + def write(mm_obj): + # Each thread picks a unique letter to write + thread_letter = thread_letters.pop(0) + thread_bytes = (thread_letter * 2).encode() + for _ in range(per_thread_write_loop): + mm_obj.write_byte(thread_bytes[0]) + mm_obj.write(thread_bytes) + + with mmap.mmap( + ANONYMOUS_MEM, per_thread_write_loop * 3 * NTHREADS + ) as mm_obj: + run_concurrently( + worker_func=write, + args=(mm_obj,), + nthreads=NTHREADS, + ) + mm_obj.seek(0) + data = mm_obj.read() + self.assertEqual(len(data), NTHREADS * per_thread_write_loop * 3) + counter = Counter(data) + self.assertEqual(len(counter), NTHREADS) + # Each thread letter should be written `per_thread_write_loop` * 3 + for letter in counter: + self.assertEqual(counter[letter], per_thread_write_loop * 3) + + def test_move(self): + ascii_uppercase = string.ascii_uppercase.encode() + num_letters = len(ascii_uppercase) + + def move(mm_obj): + for i in range(num_letters): + # Move 1 byte from the first half to the second half + mm_obj.move(0 + i, num_letters + i, 1) + + with mmap.mmap(ANONYMOUS_MEM, 2 * num_letters) as mm_obj: + mm_obj.write(ascii_uppercase) + run_concurrently( + worker_func=move, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_seek_and_tell(self): + seek_per_thread = 10 + + def seek(mm_obj): + self.assertTrue(mm_obj.seekable()) + for _ in range(seek_per_thread): + before_seek = mm_obj.tell() + mm_obj.seek(1, os.SEEK_CUR) + self.assertLess(before_seek, mm_obj.tell()) + + with mmap.mmap(ANONYMOUS_MEM, 1024) as mm_obj: + run_concurrently( + worker_func=seek, + args=(mm_obj,), + nthreads=NTHREADS, + ) + # Each thread seeks from current position, the end position should + # be the sum of all seeks from all threads. + self.assertEqual(mm_obj.tell(), NTHREADS * seek_per_thread) + + def test_slice_update_and_slice_read(self): + thread_letters = list(string.ascii_uppercase) + self.assertLessEqual(NTHREADS, len(thread_letters)) + + def slice_update_and_slice_read(mm_obj): + # Each thread picks a unique letter to write + thread_letter = thread_letters.pop(0) + thread_bytes = (thread_letter * 1024).encode() + for _ in range(100): + mm_obj[:] = thread_bytes + read_bytes = mm_obj[:] + # Read bytes should be all the same letter, showing no + # interleaving + self.assertTrue(all_same(read_bytes)) + + with mmap.mmap(ANONYMOUS_MEM, 1024) as mm_obj: + run_concurrently( + worker_func=slice_update_and_slice_read, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_item_update_and_item_read(self): + thread_indexes = [i for i in range(NTHREADS)] + + def item_update_and_item_read(mm_obj): + # Each thread picks a unique index to write + thread_index = thread_indexes.pop() + for i in range(100): + mm_obj[thread_index] = i + self.assertEqual(mm_obj[thread_index], i) + + # Read values set by other threads, all values + # should be less than '100' + for val in mm_obj: + self.assertLess(int.from_bytes(val), 100) + + with mmap.mmap(ANONYMOUS_MEM, NTHREADS + 1) as mm_obj: + run_concurrently( + worker_func=item_update_and_item_read, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + @unittest.skipUnless(os.name == "posix", "requires Posix") + @unittest.skipUnless(hasattr(mmap.mmap, "resize"), "requires mmap.resize") + def test_resize_and_size(self): + thread_indexes = [i for i in range(NTHREADS)] + + def resize_and_item_update(mm_obj): + # Each thread picks a unique index to write + thread_index = thread_indexes.pop() + mm_obj.resize(2048) + self.assertEqual(mm_obj.size(), 2048) + for i in range(100): + mm_obj[thread_index] = i + self.assertEqual(mm_obj[thread_index], i) + + with mmap.mmap(ANONYMOUS_MEM, 1024, flags=mmap.MAP_PRIVATE) as mm_obj: + run_concurrently( + worker_func=resize_and_item_update, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_close_and_closed(self): + def close_mmap(mm_obj): + mm_obj.close() + self.assertTrue(mm_obj.closed) + + with mmap.mmap(ANONYMOUS_MEM, 1) as mm_obj: + run_concurrently( + worker_func=close_mmap, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_find_and_rfind(self): + per_thread_loop = 10 + + def find_and_rfind(mm_obj): + pattern = b'Thread-Ident:"%d"' % threading.get_ident() + mm_obj.write(pattern) + for _ in range(per_thread_loop): + found_at = mm_obj.find(pattern, 0) + self.assertNotEqual(found_at, -1) + # Should not find it after the `found_at` + self.assertEqual(mm_obj.find(pattern, found_at + 1), -1) + found_at_rev = mm_obj.rfind(pattern, 0) + self.assertEqual(found_at, found_at_rev) + # Should not find it after the `found_at` + self.assertEqual(mm_obj.rfind(pattern, found_at + 1), -1) + + with mmap.mmap(ANONYMOUS_MEM, 1024) as mm_obj: + run_concurrently( + worker_func=find_and_rfind, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + @unittest.skipUnless(os.name == "posix", "requires Posix") + @unittest.skipUnless(hasattr(mmap.mmap, "resize"), "requires mmap.resize") + def test_flush(self): + mmap_filename = "test_mmap_file" + resize_to = 1024 + + def resize_and_flush(mm_obj): + mm_obj.resize(resize_to) + mm_obj.flush() + + with tempfile.TemporaryDirectory() as tmpdirname: + file_path = f"{tmpdirname}/{mmap_filename}" + with open(file_path, "wb+") as file: + file.write(b"CPython") + file.flush() + with mmap.mmap(file.fileno(), 1) as mm_obj: + run_concurrently( + worker_func=resize_and_flush, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + self.assertEqual(os.path.getsize(file_path), resize_to) + + def test_mmap_export_as_memoryview(self): + """ + Each thread creates a memoryview and updates the internal state of the + mmap object. + """ + buffer_size = 42 + + def create_memoryview_from_mmap(mm_obj): + memoryviews = [] + for _ in range(100): + mv = memoryview(mm_obj) + memoryviews.append(mv) + self.assertEqual(len(mv), buffer_size) + self.assertEqual(mv[:7], b"CPython") + + # Cannot close the mmap while it is exported as buffers + with self.assertRaisesRegex( + BufferError, "cannot close exported pointers exist" + ): + mm_obj.close() + + with mmap.mmap(ANONYMOUS_MEM, 42) as mm_obj: + mm_obj.write(b"CPython") + run_concurrently( + worker_func=create_memoryview_from_mmap, + args=(mm_obj,), + nthreads=NTHREADS, + ) + # Implicit mm_obj.close() verifies all exports (memoryviews) are + # properly freed. + + +def all_same(lst): + return all(item == lst[0] for item in lst) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_monitoring.py b/Lib/test/test_free_threading/test_monitoring.py index 407bf7cbdee..2cd6e7b035e 100644 --- a/Lib/test/test_free_threading/test_monitoring.py +++ b/Lib/test/test_free_threading/test_monitoring.py @@ -35,10 +35,10 @@ class InstrumentationMultiThreadedMixin: return n return self.work(n - 1, funcs) + self.work(n - 2, funcs) - def start_work(self, n, funcs): + def start_work(self, n, funcs, barrier): # With the GIL builds we need to make sure that the hooks have # a chance to run as it's possible to run w/o releasing the GIL. - time.sleep(0.1) + barrier.wait() self.work(n, funcs) def after_test(self): @@ -53,14 +53,16 @@ class InstrumentationMultiThreadedMixin: exec("def f(): pass", x) funcs.append(x["f"]) + barrier = Barrier(self.thread_count + 1) threads = [] for i in range(self.thread_count): # Each thread gets a copy of the func list to avoid contention - t = Thread(target=self.start_work, args=(self.fib, list(funcs))) + t = Thread(target=self.start_work, args=(self.fib, list(funcs), barrier)) t.start() threads.append(t) self.after_threads() + barrier.wait() while True: any_alive = False @@ -73,6 +75,9 @@ class InstrumentationMultiThreadedMixin: break self.during_threads() + # Sleep to avoid setting monitoring events too rapidly and + # overflowing the global version counter + time.sleep(0.0001) self.after_test() @@ -117,7 +122,6 @@ class MonitoringMultiThreaded( def setUp(self): super().setUp() self.set = False - self.called = False monitoring.register_callback( self.tool_id, monitoring.events.LINE, self.callback ) @@ -127,10 +131,7 @@ class MonitoringMultiThreaded( super().tearDown() def callback(self, *args): - self.called = True - - def after_test(self): - self.assertTrue(self.called) + pass def during_threads(self): if self.set: @@ -148,16 +149,11 @@ class SetTraceMultiThreaded(InstrumentationMultiThreadedMixin, TestCase): def setUp(self): self.set = False - self.called = False - - def after_test(self): - self.assertTrue(self.called) def tearDown(self): sys.settrace(None) def trace_func(self, frame, event, arg): - self.called = True return self.trace_func def during_threads(self): @@ -174,16 +170,11 @@ class SetProfileMultiThreaded(InstrumentationMultiThreadedMixin, TestCase): def setUp(self): self.set = False - self.called = False - - def after_test(self): - self.assertTrue(self.called) def tearDown(self): sys.setprofile(None) def trace_func(self, frame, event, arg): - self.called = True return self.trace_func def during_threads(self): @@ -200,16 +191,11 @@ class SetProfileAllThreadsMultiThreaded(InstrumentationMultiThreadedMixin, TestC def setUp(self): self.set = False - self.called = False - - def after_test(self): - self.assertTrue(self.called) def tearDown(self): threading.setprofile_all_threads(None) def trace_func(self, frame, event, arg): - self.called = True return self.trace_func def during_threads(self): diff --git a/Lib/test/test_free_threading/test_re.py b/Lib/test/test_free_threading/test_re.py new file mode 100644 index 00000000000..56f25045d1b --- /dev/null +++ b/Lib/test/test_free_threading/test_re.py @@ -0,0 +1,62 @@ +import re +import unittest + +from test.support import threading_helper +from test.support.threading_helper import run_concurrently + + +NTHREADS = 10 + + +@threading_helper.requires_working_threading() +class TestRe(unittest.TestCase): + def test_pattern_sub(self): + """Pattern substitution should work across threads""" + pattern = re.compile(r"\w+@\w+\.\w+") + text = "e-mail: test@python.org or user@pycon.org. " * 5 + results = [] + + def worker(): + substituted = pattern.sub("(redacted)", text) + results.append(substituted.count("(redacted)")) + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(results, [2 * 5] * NTHREADS) + + def test_pattern_search(self): + """Pattern search should work across threads.""" + emails = ["alice@python.org", "bob@pycon.org"] * 10 + pattern = re.compile(r"\w+@\w+\.\w+") + results = [] + + def worker(): + matches = [pattern.search(e).group() for e in emails] + results.append(len(matches)) + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(results, [2 * 10] * NTHREADS) + + def test_scanner_concurrent_access(self): + """Shared scanner should reject concurrent access.""" + pattern = re.compile(r"\w+") + scanner = pattern.scanner("word " * 10) + + def worker(): + for _ in range(100): + try: + scanner.search() + except ValueError as e: + if "already executing" in str(e): + pass + else: + raise + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + # This test has no assertions. Its purpose is to catch crashes and + # enable thread sanitizer to detect race conditions. While "already + # executing" errors are very likely, they're not guaranteed due to + # non-deterministic thread scheduling, so we can't assert errors > 0. + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_resource.py b/Lib/test/test_free_threading/test_resource.py new file mode 100644 index 00000000000..ecd0e535c44 --- /dev/null +++ b/Lib/test/test_free_threading/test_resource.py @@ -0,0 +1,41 @@ +import unittest +from test.support import import_helper, threading_helper + +resource = import_helper.import_module("resource") + + +NTHREADS = 10 +LOOP_PER_THREAD = 1000 + + +@threading_helper.requires_working_threading() +class ResourceTest(unittest.TestCase): + @unittest.skipUnless(hasattr(resource, "getrusage"), "needs getrusage") + @unittest.skipUnless( + hasattr(resource, "RUSAGE_THREAD"), "needs RUSAGE_THREAD" + ) + def test_getrusage(self): + ru_utime_lst = [] + + def dummy_work(ru_utime_lst): + for _ in range(LOOP_PER_THREAD): + pass + + usage_process = resource.getrusage(resource.RUSAGE_SELF) + usage_thread = resource.getrusage(resource.RUSAGE_THREAD) + # Process user time should be greater than thread user time + self.assertGreater(usage_process.ru_utime, usage_thread.ru_utime) + ru_utime_lst.append(usage_thread.ru_utime) + + threading_helper.run_concurrently( + worker_func=dummy_work, args=(ru_utime_lst,), nthreads=NTHREADS + ) + + usage_process = resource.getrusage(resource.RUSAGE_SELF) + self.assertEqual(len(ru_utime_lst), NTHREADS) + # Process user time should be greater than sum of all thread user times + self.assertGreater(usage_process.ru_utime, sum(ru_utime_lst)) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_set.py b/Lib/test/test_free_threading/test_set.py index a66e03bcc4c..9dd3d68d5da 100644 --- a/Lib/test/test_free_threading/test_set.py +++ b/Lib/test/test_free_threading/test_set.py @@ -1,18 +1,14 @@ import unittest - -from threading import Thread, Barrier -from unittest import TestCase - +from threading import Thread, Barrier, Event from test.support import threading_helper -@threading_helper.requires_working_threading() -class TestSet(TestCase): +class TestSetRepr(unittest.TestCase): def test_repr_clear(self): """Test repr() of a set while another thread is calling clear()""" NUM_ITERS = 10 NUM_REPR_THREADS = 10 - barrier = Barrier(NUM_REPR_THREADS + 1) + barrier = Barrier(NUM_REPR_THREADS + 1, timeout=2) s = {1, 2, 3, 4, 5, 6, 7, 8} def clear_set(): @@ -37,5 +33,131 @@ class TestSet(TestCase): self.assertIn(set_repr, ("set()", "{1, 2, 3, 4, 5, 6, 7, 8}")) +class RaceTestBase: + def test_contains_mutate(self): + """Test set contains operation combined with mutation.""" + barrier = Barrier(2, timeout=2) + s = set() + done = Event() + + NUM_LOOPS = 1000 + + def read_set(): + barrier.wait() + while not done.is_set(): + for i in range(self.SET_SIZE): + item = i >> 1 + result = item in s + + def mutate_set(): + barrier.wait() + for i in range(NUM_LOOPS): + s.clear() + for j in range(self.SET_SIZE): + s.add(j) + for j in range(self.SET_SIZE): + s.discard(j) + # executes the set_swap_bodies() function + s.__iand__(set(k for k in range(10, 20))) + done.set() + + threads = [Thread(target=read_set), Thread(target=mutate_set)] + for t in threads: + t.start() + for t in threads: + t.join() + + def test_contains_frozenset(self): + barrier = Barrier(3, timeout=2) + done = Event() + + NUM_LOOPS = 1_000 + + # This mutates the key used for contains test, not the container + # itself. This works because frozenset allows the key to be a set(). + s = set() + + def mutate_set(): + barrier.wait() + while not done.is_set(): + s.add(0) + s.add(1) + s.clear() + + def read_set(): + barrier.wait() + container = frozenset([frozenset([0])]) + self.assertTrue(set([0]) in container) + for _ in range(NUM_LOOPS): + # Will return True when {0} is the key and False otherwise + result = s in container + done.set() + + threads = [ + Thread(target=read_set), + Thread(target=read_set), + Thread(target=mutate_set), + ] + for t in threads: + t.start() + for t in threads: + t.join() + + def test_contains_hash_mutate(self): + """Test set contains operation with mutating hash method.""" + barrier = Barrier(2, timeout=2) + + NUM_LOOPS = 1_000 + SET_SIZE = self.SET_SIZE + + s = set(range(SET_SIZE)) + + class Key: + def __init__(self): + self.count = 0 + self.value = 0 + + def __hash__(self): + self.count += 1 + # This intends to trigger the SET_LOOKKEY_CHANGED case + # of set_lookkey_threadsafe() since calling clear() + # will cause the 'table' pointer to change. + if self.count % 2 == 0: + s.clear() + else: + s.update(range(SET_SIZE)) + return hash(self.value) + + def __eq__(self, other): + return self.value == other + + key = Key() + self.assertTrue(key in s) + self.assertFalse(key in s) + self.assertTrue(key in s) + self.assertFalse(key in s) + + def read_set(): + barrier.wait() + for i in range(NUM_LOOPS): + result = key in s + + threads = [Thread(target=read_set), Thread(target=read_set)] + for t in threads: + t.start() + for t in threads: + t.join() + + +@threading_helper.requires_working_threading() +class SmallSetTest(RaceTestBase, unittest.TestCase): + SET_SIZE = 6 # smaller than PySet_MINSIZE + + +@threading_helper.requires_working_threading() +class LargeSetTest(RaceTestBase, unittest.TestCase): + SET_SIZE = 20 # larger than PySet_MINSIZE + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_free_threading/test_suggestions.py b/Lib/test/test_free_threading/test_suggestions.py new file mode 100755 index 00000000000..2c10a511b86 --- /dev/null +++ b/Lib/test/test_free_threading/test_suggestions.py @@ -0,0 +1,24 @@ +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +suggestions = import_helper.import_module("_suggestions") + +NTHREADS = 10 + + +@threading_helper.requires_working_threading() +class SuggestionsTests(unittest.TestCase): + def test_generate_suggestions(self): + candidates = [str(i) for i in range(100)] + + def worker(): + _ = suggestions._generate_suggestions(candidates, "42") + candidates.clear() + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 2d995751005..1255d842dbf 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -141,6 +141,25 @@ class TestType(TestCase): self.run_one(writer, reader) + def test_bases_change(self): + class BaseA: + pass + + class Derived(BaseA): + pass + + def writer(): + for _ in range(1000): + class BaseB: + pass + Derived.__bases__ = (BaseB,) + + def reader(): + for _ in range(1000): + Derived.__base__ + + self.run_one(writer, reader) + def run_one(self, writer_func, reader_func): barrier = threading.Barrier(NTHREADS) diff --git a/Lib/test/test_free_threading/test_uuid.py b/Lib/test/test_free_threading/test_uuid.py new file mode 100755 index 00000000000..d794afc552a --- /dev/null +++ b/Lib/test/test_free_threading/test_uuid.py @@ -0,0 +1,60 @@ +import os +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently +from uuid import SafeUUID + +c_uuid = import_helper.import_module("_uuid") + +NTHREADS = 10 +UUID_PER_THREAD = 1000 + + +@threading_helper.requires_working_threading() +class UUIDTests(unittest.TestCase): + @unittest.skipUnless(os.name == "posix", "POSIX only") + def test_generate_time_safe(self): + uuids = [] + + def worker(): + local_uuids = [] + for _ in range(UUID_PER_THREAD): + uuid, is_safe = c_uuid.generate_time_safe() + self.assertIs(type(uuid), bytes) + self.assertEqual(len(uuid), 16) + # Collect the UUID only if it is safe. If not, we cannot ensure + # UUID uniqueness. According to uuid_generate_time_safe() man + # page, it is theoretically possible for two concurrently + # running processes to generate the same UUID(s) if the return + # value is not 0. + if is_safe == SafeUUID.safe: + local_uuids.append(uuid) + + # Merge all safe uuids + uuids.extend(local_uuids) + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(len(uuids), len(set(uuids))) + + @unittest.skipUnless(os.name == "nt", "Windows only") + def test_UuidCreate(self): + uuids = [] + + def worker(): + local_uuids = [] + for _ in range(UUID_PER_THREAD): + uuid = c_uuid.UuidCreate() + self.assertIs(type(uuid), bytes) + self.assertEqual(len(uuid), 16) + local_uuids.append(uuid) + + # Merge all uuids + uuids.extend(local_uuids) + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + self.assertEqual(len(uuids), len(set(uuids))) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_free_threading/test_zlib.py b/Lib/test/test_free_threading/test_zlib.py new file mode 100644 index 00000000000..7c4ed04f4a7 --- /dev/null +++ b/Lib/test/test_free_threading/test_zlib.py @@ -0,0 +1,80 @@ +import itertools +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +zlib = import_helper.import_module("zlib") + +from test.test_zlib import HAMLET_SCENE + + +NTHREADS = 10 + + +@threading_helper.requires_working_threading() +class TestZlib(unittest.TestCase): + def test_compressor(self): + comp = zlib.compressobj() + + # First compress() outputs zlib header + header = comp.compress(HAMLET_SCENE) + self.assertGreater(len(header), 0) + + def worker(): + # it should return empty bytes as it buffers data internally + data = comp.compress(HAMLET_SCENE) + self.assertEqual(data, b"") + + run_concurrently(worker_func=worker, nthreads=NTHREADS - 1) + full_compressed = header + comp.flush() + decompressed = zlib.decompress(full_compressed) + # The decompressed data should be HAMLET_SCENE repeated NTHREADS times + self.assertEqual(decompressed, HAMLET_SCENE * NTHREADS) + + def test_decompressor_concurrent_attribute_reads(self): + input_data = HAMLET_SCENE * NTHREADS + compressed = zlib.compress(input_data) + + decomp = zlib.decompressobj() + decomp_size_per_loop = len(input_data) // 1000 + decompressed_parts = [] + + def decomp_worker(): + # Decompress in chunks, which updates eof, unused_data, unconsumed_tail + decompressed_parts.append( + decomp.decompress(compressed, decomp_size_per_loop) + ) + while decomp.unconsumed_tail: + decompressed_parts.append( + decomp.decompress( + decomp.unconsumed_tail, decomp_size_per_loop + ) + ) + + def decomp_attr_reader(): + # Read attributes concurrently while another thread decompresses + for _ in range(1000): + _ = decomp.unused_data + _ = decomp.unconsumed_tail + _ = decomp.eof + + counter = itertools.count() + + def worker(): + # First thread decompresses, others read attributes + if next(counter) == 0: + decomp_worker() + else: + decomp_attr_reader() + + run_concurrently(worker_func=worker, nthreads=NTHREADS) + + self.assertTrue(decomp.eof) + self.assertEqual(decomp.unused_data, b"") + decompressed = b"".join(decompressed_parts) + self.assertEqual(decompressed, HAMLET_SCENE * NTHREADS) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 41cefe0e286..05d0cbd2445 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1859,6 +1859,13 @@ print(f'''{{ # Test multiple format specs in same raw f-string self.assertEqual(rf"{UnchangedFormat():\xFF} {UnchangedFormat():\n}", '\\xFF \\n') + def test_gh139516(self): + with temp_cwd(): + script = 'script.py' + with open(script, 'wb') as f: + f.write('''def f(a): pass\nf"{f(a=lambda: 'à'\n)}"'''.encode()) + assert_python_ok(script) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index f7e09fd771e..090926fd8d8 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -406,6 +406,7 @@ class TestPartial: def test_setstate_errors(self): f = self.partial(signature) + self.assertRaises(TypeError, f.__setstate__, (capture, (), {})) self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, {}, None)) self.assertRaises(TypeError, f.__setstate__, [capture, (), {}, None]) @@ -413,6 +414,8 @@ class TestPartial: self.assertRaises(TypeError, f.__setstate__, (capture, None, {}, None)) self.assertRaises(TypeError, f.__setstate__, (capture, [], {}, None)) self.assertRaises(TypeError, f.__setstate__, (capture, (), [], None)) + self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, ())) + self.assertRaises(TypeError, f.__setstate__, (capture, (), {}, 'test')) def test_setstate_subclasses(self): f = self.partial(signature) @@ -2782,7 +2785,7 @@ class TestSingleDispatch(unittest.TestCase): @functools.singledispatchmethod @classmethod def go(cls, item, arg): - pass + return item - arg @go.register @classmethod @@ -2791,7 +2794,9 @@ class TestSingleDispatch(unittest.TestCase): s = Slot() self.assertEqual(s.go(1, 1), 2) + self.assertEqual(s.go(1.5, 1), 0.5) self.assertEqual(Slot.go(1, 1), 2) + self.assertEqual(Slot.go(1.5, 1), 0.5) def test_staticmethod_slotted_class(self): class A: @@ -3482,6 +3487,37 @@ class TestSingleDispatch(unittest.TestCase): self.assertEqual(str(Signature.from_callable(A.static_func)), '(item, arg: int) -> str') + def test_method_non_descriptor(self): + class Callable: + def __init__(self, value): + self.value = value + def __call__(self, arg): + return self.value, arg + + class A: + t = functools.singledispatchmethod(Callable('general')) + t.register(int, Callable('special')) + + @functools.singledispatchmethod + def u(self, arg): + return 'general', arg + u.register(int, Callable('special')) + + v = functools.singledispatchmethod(Callable('general')) + @v.register(int) + def _(self, arg): + return 'special', arg + + a = A() + self.assertEqual(a.t(0), ('special', 0)) + self.assertEqual(a.t(2.5), ('general', 2.5)) + self.assertEqual(A.t(0), ('special', 0)) + self.assertEqual(A.t(2.5), ('general', 2.5)) + self.assertEqual(a.u(0), ('special', 0)) + self.assertEqual(a.u(2.5), ('general', 2.5)) + self.assertEqual(a.v(0), ('special', 0)) + self.assertEqual(a.v(2.5), ('general', 2.5)) + class CachedCostItem: _cost = 1 diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index 43289090534..6aa6361d5d0 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -801,6 +801,32 @@ class GCTests(unittest.TestCase): rc, out, err = assert_python_ok('-c', code) self.assertEqual(out.strip(), b'__del__ called') + @unittest.skipIf(Py_GIL_DISABLED, "requires GC generations or increments") + def test_gc_debug_stats(self): + # Checks that debug information is printed to stderr + # when DEBUG_STATS is set. + code = """if 1: + import gc + gc.set_debug(%s) + gc.collect() + """ + _, _, err = assert_python_ok("-c", code % "gc.DEBUG_STATS") + self.assertRegex(err, b"gc: collecting generation [0-9]+") + self.assertRegex( + err, + b"gc: objects in each generation: [0-9]+ [0-9]+ [0-9]+", + ) + self.assertRegex( + err, b"gc: objects in permanent generation: [0-9]+" + ) + self.assertRegex( + err, + b"gc: done, .* unreachable, .* uncollectable, .* elapsed", + ) + + _, _, err = assert_python_ok("-c", code % "0") + self.assertNotIn(b"elapsed", err) + def test_global_del_SystemExit(self): code = """if 1: class ClassWithDel: @@ -820,11 +846,15 @@ class GCTests(unittest.TestCase): self.assertEqual(len(stats), 3) for st in stats: self.assertIsInstance(st, dict) - self.assertEqual(set(st), - {"collected", "collections", "uncollectable"}) + self.assertEqual( + set(st), + {"collected", "collections", "uncollectable", "candidates", "duration"} + ) self.assertGreaterEqual(st["collected"], 0) self.assertGreaterEqual(st["collections"], 0) self.assertGreaterEqual(st["uncollectable"], 0) + self.assertGreaterEqual(st["candidates"], 0) + self.assertGreaterEqual(st["duration"], 0) # Check that collection counts are incremented correctly if gc.isenabled(): self.addCleanup(gc.enable) @@ -835,11 +865,25 @@ class GCTests(unittest.TestCase): self.assertEqual(new[0]["collections"], old[0]["collections"] + 1) self.assertEqual(new[1]["collections"], old[1]["collections"]) self.assertEqual(new[2]["collections"], old[2]["collections"]) + self.assertGreater(new[0]["duration"], old[0]["duration"]) + self.assertEqual(new[1]["duration"], old[1]["duration"]) + self.assertEqual(new[2]["duration"], old[2]["duration"]) + for stat in ["collected", "uncollectable", "candidates"]: + self.assertGreaterEqual(new[0][stat], old[0][stat]) + self.assertEqual(new[1][stat], old[1][stat]) + self.assertEqual(new[2][stat], old[2][stat]) gc.collect(2) - new = gc.get_stats() - self.assertEqual(new[0]["collections"], old[0]["collections"] + 1) + old, new = new, gc.get_stats() + self.assertEqual(new[0]["collections"], old[0]["collections"]) self.assertEqual(new[1]["collections"], old[1]["collections"]) self.assertEqual(new[2]["collections"], old[2]["collections"] + 1) + self.assertEqual(new[0]["duration"], old[0]["duration"]) + self.assertEqual(new[1]["duration"], old[1]["duration"]) + self.assertGreater(new[2]["duration"], old[2]["duration"]) + for stat in ["collected", "uncollectable", "candidates"]: + self.assertEqual(new[0][stat], old[0][stat]) + self.assertEqual(new[1][stat], old[1][stat]) + self.assertGreaterEqual(new[2][stat], old[2][stat]) def test_freeze(self): gc.freeze() @@ -1187,6 +1231,24 @@ class GCTests(unittest.TestCase): assert_python_ok("-c", code_inside_function) + @unittest.skipUnless(Py_GIL_DISABLED, "requires free-threaded GC") + @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") + def test_tuple_untrack_counts(self): + # This ensures that the free-threaded GC is counting untracked tuples + # in the "long_lived_total" count. This is required to avoid + # performance issues from running the GC too frequently. See + # GH-142531 as an example. + gc.collect() + count = _testinternalcapi.get_long_lived_total() + n = 20_000 + tuples = [(x,) for x in range(n)] + gc.collect() + new_count = _testinternalcapi.get_long_lived_total() + self.assertFalse(gc.is_tracked(tuples[0])) + # Use n // 2 just in case some other objects were collected. + self.assertTrue(new_count - count > (n // 2)) + + class IncrementalGCTests(unittest.TestCase): @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") @requires_gil_enabled("Free threading does not support incremental GC") @@ -1272,9 +1334,11 @@ class GCCallbackTests(unittest.TestCase): # Check that we got the right info dict for all callbacks for v in self.visit: info = v[2] - self.assertTrue("generation" in info) - self.assertTrue("collected" in info) - self.assertTrue("uncollectable" in info) + self.assertIn("generation", info) + self.assertIn("collected", info) + self.assertIn("uncollectable", info) + self.assertIn("candidates", info) + self.assertIn("duration", info) def test_collect_generation(self): self.preclean() @@ -1447,10 +1511,11 @@ class GCTogglingTests(unittest.TestCase): # The free-threaded build doesn't have multiple generations, so # just trigger a GC manually. gc.collect() + assert not detector.gc_happened while not detector.gc_happened: i += 1 - if i > 10000: - self.fail("gc didn't happen after 10000 iterations") + if i > 100000: + self.fail("gc didn't happen after 100000 iterations") self.assertEqual(len(ouch), 0) junk.append([]) # this will eventually trigger gc @@ -1522,8 +1587,8 @@ class GCTogglingTests(unittest.TestCase): gc.collect() while not detector.gc_happened: i += 1 - if i > 10000: - self.fail("gc didn't happen after 10000 iterations") + if i > 50000: + self.fail("gc didn't happen after 50000 iterations") self.assertEqual(len(ouch), 0) junk.append([]) # this will eventually trigger gc @@ -1540,8 +1605,8 @@ class GCTogglingTests(unittest.TestCase): detector = GC_Detector() while not detector.gc_happened: i += 1 - if i > 10000: - self.fail("gc didn't happen after 10000 iterations") + if i > 100000: + self.fail("gc didn't happen after 100000 iterations") junk.append([]) # this will eventually trigger gc try: @@ -1551,14 +1616,28 @@ class GCTogglingTests(unittest.TestCase): detector = GC_Detector() while not detector.gc_happened: i += 1 - if i > 10000: + if i > 100000: break junk.append([]) # this may eventually trigger gc (if it is enabled) - self.assertEqual(i, 10001) + self.assertEqual(i, 100001) finally: gc.enable() + # Ensure that setting *threshold0* to zero disables collection. + @gc_threshold(0) + def test_threshold_zero(self): + junk = [] + i = 0 + detector = GC_Detector() + while not detector.gc_happened: + i += 1 + if i > 50000: + break + junk.append([]) # this may eventually trigger gc (if it is enabled) + + self.assertEqual(i, 50001) + class PythonFinalizationTests(unittest.TestCase): def test_ast_fini(self): diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index ec44a0f9ce3..de0dbab480f 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -132,7 +132,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -154,7 +154,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -165,7 +165,7 @@ class TestGeneratedCases(unittest.TestCase): value = stack_pointer[-1]; SPAM(value); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -179,7 +179,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -190,7 +190,7 @@ class TestGeneratedCases(unittest.TestCase): res = SPAM(); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -205,7 +205,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -232,7 +232,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -247,7 +247,7 @@ class TestGeneratedCases(unittest.TestCase): res = SPAM(left, right); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -262,7 +262,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -296,7 +296,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -313,7 +313,7 @@ class TestGeneratedCases(unittest.TestCase): } TARGET(OP3) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP3; (void)(opcode); #endif @@ -355,7 +355,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(A) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = A; (void)(opcode); #endif @@ -366,19 +366,19 @@ class TestGeneratedCases(unittest.TestCase): _PyStackRef res; arg = stack_pointer[-1]; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); escaping_call(); stack_pointer = _PyFrame_GetStackPointer(frame); res = Py_None; stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(B) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = B; (void)(opcode); #endif @@ -421,7 +421,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -444,7 +444,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -470,7 +470,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -489,7 +489,7 @@ class TestGeneratedCases(unittest.TestCase): res = 0; stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -505,7 +505,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -523,7 +523,7 @@ class TestGeneratedCases(unittest.TestCase): } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -537,7 +537,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -553,7 +553,7 @@ class TestGeneratedCases(unittest.TestCase): uint32_t extra = read_u32(&this_instr[2].cache); (void)extra; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -570,7 +570,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -604,7 +604,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -640,12 +640,12 @@ class TestGeneratedCases(unittest.TestCase): } stack_pointer[-3] = res; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(OP1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -667,7 +667,7 @@ class TestGeneratedCases(unittest.TestCase): } TARGET(OP3) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP3; (void)(opcode); #endif @@ -688,7 +688,7 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer[-3] = res; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -702,7 +702,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -728,7 +728,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -751,7 +751,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -777,7 +777,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -788,7 +788,7 @@ class TestGeneratedCases(unittest.TestCase): } TARGET(OP2) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP2; (void)(opcode); #endif @@ -812,7 +812,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -827,7 +827,7 @@ class TestGeneratedCases(unittest.TestCase): below = stack_pointer[-2 - oparg*2]; SPAM(values, oparg); stack_pointer += -2 - oparg*2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -843,7 +843,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -860,7 +860,7 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer[-2] = below; stack_pointer[-1 + oparg*3] = above; stack_pointer += oparg*3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -875,7 +875,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -889,7 +889,7 @@ class TestGeneratedCases(unittest.TestCase): above = 0; stack_pointer[0] = above; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -905,7 +905,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -918,11 +918,11 @@ class TestGeneratedCases(unittest.TestCase): extra = stack_pointer[-1 - oparg]; if (oparg == 0) { stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -940,7 +940,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(M) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = M; (void)(opcode); #endif @@ -960,7 +960,7 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer[0] = val1; stack_pointer[1] = val2; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -977,7 +977,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1002,7 +1002,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(M) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = M; (void)(opcode); #endif @@ -1023,7 +1023,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1045,7 +1045,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(M) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = M; (void)(opcode); #endif @@ -1086,7 +1086,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1128,7 +1128,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(INST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INST; (void)(opcode); #endif @@ -1158,7 +1158,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(TEST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TEST; (void)(opcode); #endif @@ -1202,7 +1202,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(TEST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TEST; (void)(opcode); #endif @@ -1245,7 +1245,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(TEST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TEST; (void)(opcode); #endif @@ -1263,13 +1263,13 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer[0] = a; stack_pointer[1] = b; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); // SECOND { USE(a, b); } stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -1297,7 +1297,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(TEST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TEST; (void)(opcode); #endif @@ -1325,7 +1325,7 @@ class TestGeneratedCases(unittest.TestCase): } } stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -1348,7 +1348,7 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(TEST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TEST; (void)(opcode); #endif @@ -1368,14 +1368,14 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer[0] = a; stack_pointer[1] = b; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } } stack_pointer[0] = a; stack_pointer[1] = b; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -1393,7 +1393,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP1; (void)(opcode); #endif @@ -1404,7 +1404,7 @@ class TestGeneratedCases(unittest.TestCase): } TARGET(OP2) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP2; (void)(opcode); #endif @@ -1466,7 +1466,7 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(BALANCED) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BALANCED; (void)(opcode); #endif @@ -1492,7 +1492,7 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(BALANCED) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BALANCED; (void)(opcode); #endif @@ -1514,7 +1514,7 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(BALANCED) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BALANCED; (void)(opcode); #endif @@ -1539,7 +1539,7 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(BALANCED) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BALANCED; (void)(opcode); #endif @@ -1565,14 +1565,14 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(OP); - frame->return_offset = 1 ; + frame->return_offset = 1u ; DISPATCH(); } """ @@ -1604,7 +1604,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1642,7 +1642,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1661,7 +1661,7 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer[0] = out1; stack_pointer[1] = out2; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } """ @@ -1840,7 +1840,7 @@ class TestGeneratedCases(unittest.TestCase): output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1867,7 +1867,7 @@ class TestGeneratedCases(unittest.TestCase): """ output = """ TARGET(OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = OP; (void)(opcode); #endif @@ -1881,7 +1881,7 @@ class TestGeneratedCases(unittest.TestCase): stack_pointer = _PyFrame_GetStackPointer(frame); in = temp; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(in); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2115,8 +2115,9 @@ class TestGeneratedAbstractCases(unittest.TestCase): """ output = """ case OP: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } """ @@ -2132,8 +2133,9 @@ class TestGeneratedAbstractCases(unittest.TestCase): """ output = """ case OP: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } """ @@ -2153,9 +2155,10 @@ class TestGeneratedAbstractCases(unittest.TestCase): case OP: { JitOptRef foo; foo = NULL; + CHECK_STACK_BOUNDS(1); stack_pointer[0] = foo; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } """ @@ -2172,8 +2175,9 @@ class TestGeneratedAbstractCases(unittest.TestCase): """ output = """ case OP: { + CHECK_STACK_BOUNDS(1); stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } """ diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 3e41c7b9663..6643c396edf 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -134,6 +134,18 @@ class FinalizationTest(unittest.TestCase): self.assertEqual(len(resurrected), 1) self.assertIsInstance(resurrected[0].gi_code, types.CodeType) + def test_exhausted_generator_frame_cycle(self): + def g(): + yield + + generator = g() + frame = generator.gi_frame + self.assertIsNone(frame.f_back) + next(generator) + self.assertIsNone(frame.f_back) + next(generator, None) + self.assertIsNone(frame.f_back) + class GeneratorTest(unittest.TestCase): @@ -290,6 +302,33 @@ class GeneratorTest(unittest.TestCase): self.assertEqual([1,2], list(i for i in C())) + def test_close_clears_frame(self): + # gh-142766: Test that closing a generator clears its frame + class DetectDelete: + def __init__(self): + DetectDelete.deleted = False + + def __del__(self): + DetectDelete.deleted = True + + def generator(arg): + yield + + # Test a freshly created generator (not suspended) + g = generator(DetectDelete()) + g.close() + self.assertTrue(DetectDelete.deleted) + + # Test a suspended generator + g = generator(DetectDelete()) + next(g) + g.close() + self.assertTrue(DetectDelete.deleted) + + # Clear via gi_frame.clear() + g = generator(DetectDelete()) + g.gi_frame.clear() + self.assertTrue(DetectDelete.deleted) class ModifyUnderlyingIterableTest(unittest.TestCase): iterables = [ diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 7601cb00ff6..9df9296e26a 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -17,7 +17,7 @@ from dataclasses import Field from functools import partial, partialmethod, cached_property from graphlib import TopologicalSorter from logging import LoggerAdapter, StreamHandler -from mailbox import Mailbox, _PartialFile +from mailbox import Mailbox try: import ctypes except ImportError: @@ -117,7 +117,7 @@ class BaseTest(unittest.TestCase): Iterable, Iterator, Reversible, Container, Collection, - Mailbox, _PartialFile, + Mailbox, ContextVar, Token, Field, Set, MutableSet, @@ -402,7 +402,10 @@ class BaseTest(unittest.TestCase): aliases = [ GenericAlias(list, T), GenericAlias(deque, T), - GenericAlias(X, T) + GenericAlias(X, T), + X[T], + list[T], + deque[T], ] + _UNPACKED_TUPLES for alias in aliases: with self.subTest(alias=alias): @@ -432,10 +435,26 @@ class BaseTest(unittest.TestCase): self.assertEqual(a.__parameters__, (T,)) def test_dir(self): - dir_of_gen_alias = set(dir(list[int])) + ga = list[int] + dir_of_gen_alias = set(dir(ga)) self.assertTrue(dir_of_gen_alias.issuperset(dir(list))) - for generic_alias_property in ("__origin__", "__args__", "__parameters__"): - self.assertIn(generic_alias_property, dir_of_gen_alias) + for generic_alias_property in ( + "__origin__", "__args__", "__parameters__", + "__unpacked__", + ): + with self.subTest(generic_alias_property=generic_alias_property): + self.assertIn(generic_alias_property, dir_of_gen_alias) + for blocked in ( + "__bases__", + "__copy__", + "__deepcopy__", + ): + with self.subTest(blocked=blocked): + self.assertNotIn(blocked, dir_of_gen_alias) + + for entry in dir_of_gen_alias: + with self.subTest(entry=entry): + getattr(ga, entry) # must not raise `AttributeError` def test_weakref(self): for t in self.generic_types: diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index 71d92c0e45f..dfc0817da45 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -9,9 +9,9 @@ import pickle import sys import unittest import warnings -from test.support import ( - is_apple, os_helper, warnings_helper -) +from test import support +from test.support import os_helper +from test.support import warnings_helper from test.support.script_helper import assert_python_ok from test.support.os_helper import FakePath @@ -462,6 +462,19 @@ class CommonTest(GenericTest): os.fsencode('$bar%s bar' % nonascii)) check(b'$spam}bar', os.fsencode('%s}bar' % nonascii)) + @support.requires_resource('cpu') + def test_expandvars_large(self): + expandvars = self.pathmodule.expandvars + with os_helper.EnvironmentVarGuard() as env: + env.clear() + env["A"] = "B" + n = 100_000 + self.assertEqual(expandvars('$A'*n), 'B'*n) + self.assertEqual(expandvars('${A}'*n), 'B'*n) + self.assertEqual(expandvars('$A!'*n), 'B!'*n) + self.assertEqual(expandvars('${A}A'*n), 'BA'*n) + self.assertEqual(expandvars('${'*10*n), '${'*10*n) + def test_abspath(self): self.assertIn("foo", self.pathmodule.abspath("foo")) with warnings.catch_warnings(): @@ -519,7 +532,7 @@ class CommonTest(GenericTest): # directory (when the bytes name is used). and sys.platform not in { "win32", "emscripten", "wasi" - } and not is_apple + } and not support.is_apple ): name = os_helper.TESTFN_UNDECODABLE elif os_helper.TESTFN_NONASCII: diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index ab36535a1cf..9c3def2c3be 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -201,5 +201,41 @@ class UnixGetpassTest(unittest.TestCase): self.assertEqual('Password: *******\x08 \x08', mock_output.getvalue()) +class GetpassEchoCharTest(unittest.TestCase): + + def test_accept_none(self): + getpass._check_echo_char(None) + + @support.subTests('echo_char', ["*", "A", " "]) + def test_accept_single_printable_ascii(self, echo_char): + getpass._check_echo_char(echo_char) + + def test_reject_empty_string(self): + self.assertRaises(ValueError, getpass.getpass, echo_char="") + + @support.subTests('echo_char', ["***", "AA", "aA*!"]) + def test_reject_multi_character_strings(self, echo_char): + self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char) + + @support.subTests('echo_char', [ + '\N{LATIN CAPITAL LETTER AE}', # non-ASCII single character + '\N{HEAVY BLACK HEART}', # non-ASCII multibyte character + ]) + def test_reject_non_ascii(self, echo_char): + self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char) + + @support.subTests('echo_char', [ + ch for ch in map(chr, range(0, 128)) + if not ch.isprintable() + ]) + def test_reject_non_printable_characters(self, echo_char): + self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char) + + # TypeError Rejection + @support.subTests('echo_char', [b"*", 0, 0.0, [], {}]) + def test_reject_non_string(self, echo_char): + self.assertRaises(TypeError, getpass.getpass, echo_char=echo_char) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 7f5d48b9c63..cfb24a5c457 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -1554,6 +1554,8 @@ class GrammarTests(unittest.TestCase): check('[None [i, j]]') check('[True [i, j]]') check('[... [i, j]]') + check('[t"{x}" [i, j]]') + check('[t"x={x}" [i, j]]') msg=r'indices must be integers or slices, not tuple; perhaps you missed a comma\?' check('[(1, 2) [i, j]]') @@ -1564,8 +1566,6 @@ class GrammarTests(unittest.TestCase): check('[f"x={x}" [i, j]]') check('["abc" [i, j]]') check('[b"abc" [i, j]]') - check('[t"{x}" [i, j]]') - check('[t"x={x}" [i, j]]') msg=r'indices must be integers or slices, not tuple;' check('[[1, 2] [3, 4]]') @@ -1586,6 +1586,7 @@ class GrammarTests(unittest.TestCase): check('[[1, 2] [f"{x}"]]') check('[[1, 2] [f"x={x}"]]') check('[[1, 2] ["abc"]]') + msg=r'indices must be integers or slices, not string.templatelib.Template;' check('[[1, 2] [t"{x}"]]') check('[[1, 2] [t"x={x}"]]') msg=r'indices must be integers or slices, not' diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index 9a2e1dd248f..442d30fc970 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -11,7 +11,7 @@ import sys import unittest from subprocess import PIPE, Popen from test.support import catch_unraisable_exception -from test.support import import_helper +from test.support import force_not_colorized_test_class, import_helper from test.support import os_helper from test.support import _4G, bigmemtest, requires_subprocess from test.support.script_helper import assert_python_ok, assert_python_failure @@ -639,7 +639,7 @@ class TestGzip(BaseTest): with open(self.filename, mode) as f: with gzip.GzipFile(fileobj=f) as g: self.assertEqual(g.mode, gzip.READ) - for mode in "wb", "ab", "xb": + for mode in "wb", "ab", "xb", "wb+", "ab+", "xb+": if "x" in mode: os_helper.unlink(self.filename) with open(self.filename, mode) as f: @@ -1057,6 +1057,7 @@ def create_and_remove_directory(directory): return decorator +@force_not_colorized_test_class class TestCommandLine(unittest.TestCase): data = b'This is a simple test with gzip' diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 33845d8a9e2..489bb049d2f 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -40,12 +40,15 @@ else: openssl_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) try: - from _hashlib import HASH, HASHXOF, openssl_md_meth_names, get_fips_mode + import _hashlib except ImportError: - HASH = None - HASHXOF = None - openssl_md_meth_names = frozenset() - + _hashlib = None +# The extension module may exist but only define some of these. gh-141907 +HASH = getattr(_hashlib, 'HASH', None) +HASHXOF = getattr(_hashlib, 'HASHXOF', None) +openssl_md_meth_names = getattr(_hashlib, 'openssl_md_meth_names', frozenset()) +get_fips_mode = getattr(_hashlib, 'get_fips_mode', None) +if not get_fips_mode: def get_fips_mode(): return 0 @@ -631,9 +634,14 @@ class HashLibTestCase(unittest.TestCase): constructors = self.constructors_to_test[name] for hash_object_constructor in constructors: m = hash_object_constructor() - if HASH is not None and isinstance(m, HASH): - # _hashopenssl's variant does not have extra SHA3 attributes - continue + if name.startswith('shake_'): + if HASHXOF is not None and isinstance(m, HASHXOF): + # _hashopenssl's variant does not have extra SHA3 attributes + continue + else: + if HASH is not None and isinstance(m, HASH): + # _hashopenssl's variant does not have extra SHA3 attributes + continue self.assertEqual(capacity + rate, 1600) self.assertEqual(m._capacity_bits, capacity) self.assertEqual(m._rate_bits, rate) @@ -1156,7 +1164,8 @@ class HashLibTestCase(unittest.TestCase): def test_hash_disallow_instantiation(self): # internal types like _hashlib.HASH are not constructable support.check_disallow_instantiation(self, HASH) - support.check_disallow_instantiation(self, HASHXOF) + if HASHXOF is not None: + support.check_disallow_instantiation(self, HASHXOF) def test_readonly_types(self): for algorithm, constructors in self.constructors_to_test.items(): diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index 5c29369d10b..17888a9f286 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -161,7 +161,7 @@ class ThroughModuleAPIMixin(ModuleMixin, CreatorMixin, DigestMixin): return _call_digest_func(self.hmac.digest, key, msg, digestmod) -@hashlib_helper.requires_hashlib() +@hashlib_helper.requires_openssl_hashlib() class ThroughOpenSSLAPIMixin(CreatorMixin, DigestMixin): """Mixin delegating to _hashlib.hmac_new() and _hashlib.hmac_digest().""" @@ -1076,6 +1076,15 @@ class SanityTestCaseMixin(CreatorMixin): self.assertEqual(h.digest_size, self.digest_size) self.assertEqual(h.block_size, self.block_size) + def test_copy(self): + # Test a generic copy() and the attributes it exposes. + # See https://github.com/python/cpython/issues/142451. + h1 = self.hmac_new(b"my secret key", digestmod=self.digestname) + h2 = h1.copy() + self.assertEqual(h1.name, h2.name) + self.assertEqual(h1.digest_size, h2.digest_size) + self.assertEqual(h1.block_size, h2.block_size) + def test_repr(self): # HMAC object representation may differ across implementations raise NotImplementedError @@ -1431,7 +1440,7 @@ class HMACCompareDigestTestCase(CompareDigestMixin, unittest.TestCase): self.assertIs(self.compare_digest, operator_compare_digest) -@hashlib_helper.requires_hashlib() +@hashlib_helper.requires_openssl_hashlib() class OpenSSLCompareDigestTestCase(CompareDigestMixin, unittest.TestCase): compare_digest = openssl_compare_digest @@ -1509,7 +1518,7 @@ class PyMiscellaneousTests(unittest.TestCase): hmac = import_fresh_module("hmac", blocked=["_hmac"]) self.do_test_hmac_digest_overflow_error_switch_to_slow(hmac, size) - @hashlib_helper.requires_builtin_hashdigest("_md5", "md5") + @hashlib_helper.requires_builtin_hashdigest("md5") @bigmemtest(size=_4G + 5, memuse=2, dry_run=False) def test_hmac_digest_overflow_error_builtin_only(self, size): hmac = import_fresh_module("hmac", blocked=["_hashlib"]) diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py index 6a1d69335a0..e4eff1ea17a 100644 --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -8,6 +8,18 @@ from unittest.mock import patch from test import support +SAMPLE_RCDATA = ( + '' + "" + '' + '' + '' + '\u2603' +) + +SAMPLE_RAWTEXT = SAMPLE_RCDATA + '&☺' + + class EventCollector(html.parser.HTMLParser): def __init__(self, *args, autocdata=False, **kw): @@ -97,12 +109,13 @@ class EventCollectorNoNormalize(EventCollector): class TestCaseBase(unittest.TestCase): - def get_collector(self): - return EventCollector(convert_charrefs=False) + def get_collector(self, convert_charrefs=False): + return EventCollector(convert_charrefs=convert_charrefs) - def _run_check(self, source, expected_events, collector=None): + def _run_check(self, source, expected_events, + *, collector=None, convert_charrefs=False): if collector is None: - collector = self.get_collector() + collector = self.get_collector(convert_charrefs=convert_charrefs) parser = collector for s in source: parser.feed(s) @@ -116,7 +129,7 @@ class TestCaseBase(unittest.TestCase): def _run_check_extra(self, source, events): self._run_check(source, events, - EventCollectorExtra(convert_charrefs=False)) + collector=EventCollectorExtra(convert_charrefs=False)) class HTMLParserTestCase(TestCaseBase): @@ -175,10 +188,87 @@ text ]) def test_unclosed_entityref(self): - self._run_check("&entityref foo", [ - ("entityref", "entityref"), - ("data", " foo"), - ]) + self._run_check('> <', [('entityref', 'gt'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('> <', [('data', '> <')], convert_charrefs=True) + + self._run_check('&undefined <', + [('entityref', 'undefined'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('&undefined <', [('data', '&undefined <')], + convert_charrefs=True) + + self._run_check('>undefined <', + [('entityref', 'gtundefined'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('>undefined <', [('data', '>undefined <')], + convert_charrefs=True) + + self._run_check('& <', [('data', '& '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('& <', [('data', '& <')], convert_charrefs=True) + + def test_eof_in_entityref(self): + self._run_check('>', [('entityref', 'gt')], convert_charrefs=False) + self._run_check('>', [('data', '>')], convert_charrefs=True) + + self._run_check('&g', [('entityref', 'g')], convert_charrefs=False) + self._run_check('&g', [('data', '&g')], convert_charrefs=True) + + self._run_check('&undefined', [('entityref', 'undefined')], + convert_charrefs=False) + self._run_check('&undefined', [('data', '&undefined')], + convert_charrefs=True) + + self._run_check('>undefined', [('entityref', 'gtundefined')], + convert_charrefs=False) + self._run_check('>undefined', [('data', '>undefined')], + convert_charrefs=True) + + self._run_check('&', [('data', '&')], convert_charrefs=False) + self._run_check('&', [('data', '&')], convert_charrefs=True) + + def test_unclosed_charref(self): + self._run_check('{ <', [('charref', '123'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('{ <', [('data', '{ <')], convert_charrefs=True) + self._run_check('« <', [('charref', 'xab'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('« <', [('data', '\xab <')], convert_charrefs=True) + + self._run_check('� <', + [('charref', '123456789'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('� <', [('data', '\ufffd <')], + convert_charrefs=True) + self._run_check('� <', + [('charref', 'x123456789'), ('data', ' '), ('entityref', 'lt')], + convert_charrefs=False) + self._run_check('� <', [('data', '\ufffd <')], + convert_charrefs=True) + + self._run_check('&# <', [('data', '&# '), ('entityref', 'lt')], convert_charrefs=False) + self._run_check('&# <', [('data', '&# <')], convert_charrefs=True) + self._run_check('&#x <', [('data', '&#x '), ('entityref', 'lt')], convert_charrefs=False) + self._run_check('&#x <', [('data', '&#x <')], convert_charrefs=True) + + def test_eof_in_charref(self): + self._run_check('{', [('charref', '123')], convert_charrefs=False) + self._run_check('{', [('data', '{')], convert_charrefs=True) + self._run_check('«', [('charref', 'xab')], convert_charrefs=False) + self._run_check('«', [('data', '\xab')], convert_charrefs=True) + + self._run_check('�', [('charref', '123456789')], + convert_charrefs=False) + self._run_check('�', [('data', '\ufffd')], convert_charrefs=True) + self._run_check('�', [('charref', 'x123456789')], + convert_charrefs=False) + self._run_check('�', [('data', '\ufffd')], convert_charrefs=True) + + self._run_check('&#', [('data', '&#')], convert_charrefs=False) + self._run_check('&#', [('data', '&#')], convert_charrefs=True) + self._run_check('&#x', [('data', '&#x')], convert_charrefs=False) + self._run_check('&#x', [('data', '&#x')], convert_charrefs=True) def test_bad_nesting(self): # Strangely, this *is* supposed to test that overlapping @@ -293,30 +383,20 @@ text 'Date().getTime()+\'"><\\/s\'+\'cript>\');\n//]]>'), '\n\n', '', - 'foo = ""', - 'foo = ""', - 'foo = ""', - 'foo = ""', - 'foo = ""', - 'foo = ""', ]) def test_script_content(self, content): s = f'' - self._run_check(s, [("starttag", "script", []), - ("data", content), - ("endtag", "script")]) + self._run_check(s, [ + ("starttag", "script", []), + ("data", content), + ("endtag", "script"), + ]) @support.subTests('content', [ 'a::before { content: ""; }', 'a::before { content: "¬-an-entity-ref;"; }', 'a::before { content: ""; }', 'a::before { content: "\u2603"; }', - 'a::before { content: "< /style>"; }', - 'a::before { content: ""; }', - 'a::before { content: ""; }', - 'a::before { content: ""; }', - 'a::before { content: ""; }', - 'a::before { content: ""; }', ]) def test_style_content(self, content): s = f'' @@ -324,47 +404,59 @@ text ("data", content), ("endtag", "style")]) - @support.subTests('content', [ - '', - "", - '', - '', - '', - '\u2603', - '< /title>', - '', - '', - '', - '', - '', - ]) - def test_title_content(self, content): - source = f"{content}" + @support.subTests('tag', ['title', 'textarea']) + def test_rcdata_content(self, tag): + source = f"<{tag}>{SAMPLE_RCDATA}" self._run_check(source, [ - ("starttag", "title", []), - ("data", content), - ("endtag", "title"), + ("starttag", tag, []), + ("data", SAMPLE_RCDATA), + ("endtag", tag), + ]) + source = f"<{tag}>&" + self._run_check(source, [ + ("starttag", tag, []), + ('entityref', 'amp'), + ("endtag", tag), ]) - @support.subTests('content', [ - '', - "", - '', - '', - '', - '\u2603', - '< /textarea>', - '', - '', - '', - '', - ]) - def test_textarea_content(self, content): - source = f"" + @support.subTests('tag', + ['style', 'xmp', 'iframe', 'noembed', 'noframes', 'script']) + def test_rawtext_content(self, tag): + source = f"<{tag}>{SAMPLE_RAWTEXT}" self._run_check(source, [ - ("starttag", "textarea", []), + ("starttag", tag, []), + ("data", SAMPLE_RAWTEXT), + ("endtag", tag), + ]) + + def test_noscript_content(self): + source = f"" + # scripting=False -- normal mode + self._run_check(source, [ + ('starttag', 'noscript', []), + ('comment', ' not a comment '), + ('starttag', 'not', [('a', 'start tag')]), + ('unknown decl', 'CDATA[not a cdata'), + ('comment', 'not a bogus comment'), + ('endtag', 'not'), + ('data', '☃'), + ('entityref', 'amp'), + ('charref', '9786'), + ('endtag', 'noscript'), + ]) + # scripting=True -- RAWTEXT mode + self._run_check(source, [ + ("starttag", "noscript", []), + ("data", SAMPLE_RAWTEXT), + ("endtag", "noscript"), + ], collector=EventCollector(scripting=True)) + + def test_plaintext_content(self): + content = SAMPLE_RAWTEXT + '' # not closing + source = f"{content}" + self._run_check(source, [ + ("starttag", "plaintext", []), ("data", content), - ("endtag", "textarea"), ]) @support.subTests('endtag', ['script', 'SCRIPT', 'script ', 'script\n', @@ -381,52 +473,65 @@ text ("endtag", "script")], collector=EventCollectorNoNormalize(convert_charrefs=False)) - @support.subTests('endtag', ['style', 'STYLE', 'style ', 'style\n', - 'style/', 'style foo=bar', 'style foo=">"']) - def test_style_closing_tag(self, endtag): - content = """ - b::before { content: "<!-- not a comment -->"; } - p::before { content: "&not-an-entity-ref;"; } - a::before { content: "<i>"; } - a::after { content: "</i>"; } - """ - s = f'<StyLE>{content}</{endtag}>' - self._run_check(s, [("starttag", "style", []), - ("data", content), - ("endtag", "style")], - collector=EventCollectorNoNormalize(convert_charrefs=False)) + @support.subTests('tag', [ + 'script', 'style', 'xmp', 'iframe', 'noembed', 'noframes', + 'textarea', 'title', 'noscript', + ]) + def test_closing_tag(self, tag): + for endtag in [tag, tag.upper(), f'{tag} ', f'{tag}\n', + f'{tag}/', f'{tag} foo=bar', f'{tag} foo=">"']: + content = "<!-- not a comment --><i>Spam</i>" + s = f'<{tag.upper()}>{content}</{endtag}>' + self._run_check(s, [ + ("starttag", tag, []), + ('data', content), + ("endtag", tag), + ], collector=EventCollectorNoNormalize(convert_charrefs=False, scripting=True)) - @support.subTests('endtag', ['title', 'TITLE', 'title ', 'title\n', - 'title/', 'title foo=bar', 'title foo=">"']) - def test_title_closing_tag(self, endtag): - content = "<!-- not a comment --><i>Egg &amp; Spam</i>" - s = f'<TitLe>{content}</{endtag}>' - self._run_check(s, [("starttag", "title", []), - ('data', '<!-- not a comment --><i>Egg & Spam</i>'), - ("endtag", "title")], - collector=EventCollectorNoNormalize(convert_charrefs=True)) - self._run_check(s, [("starttag", "title", []), - ('data', '<!-- not a comment --><i>Egg '), - ('entityref', 'amp'), - ('data', ' Spam</i>'), - ("endtag", "title")], - collector=EventCollectorNoNormalize(convert_charrefs=False)) + @support.subTests('tag', [ + 'script', 'style', 'xmp', 'iframe', 'noembed', 'noframes', + 'textarea', 'title', 'noscript', + ]) + def test_invalid_closing_tag(self, tag): + content = ( + f'< /{tag}>' + f'</ {tag}>' + f'</{tag}x>' + f'</{tag}\v>' + f'</{tag}\xa0>' + ) + source = f"<{tag}>{content}</{tag}>" + self._run_check(source, [ + ("starttag", tag, []), + ("data", content), + ("endtag", tag), + ], collector=EventCollector(convert_charrefs=False, scripting=True)) - @support.subTests('endtag', ['textarea', 'TEXTAREA', 'textarea ', 'textarea\n', - 'textarea/', 'textarea foo=bar', 'textarea foo=">"']) - def test_textarea_closing_tag(self, endtag): - content = "<!-- not a comment --><i>Egg &amp; Spam</i>" - s = f'<TexTarEa>{content}</{endtag}>' - self._run_check(s, [("starttag", "textarea", []), - ('data', '<!-- not a comment --><i>Egg & Spam</i>'), - ("endtag", "textarea")], - collector=EventCollectorNoNormalize(convert_charrefs=True)) - self._run_check(s, [("starttag", "textarea", []), - ('data', '<!-- not a comment --><i>Egg '), - ('entityref', 'amp'), - ('data', ' Spam</i>'), - ("endtag", "textarea")], - collector=EventCollectorNoNormalize(convert_charrefs=False)) + @support.subTests('tag,endtag', [ + ('title', 'tıtle'), + ('style', 'ſtyle'), + ('style', 'ſtyle'), + ('style', 'style'), + ('iframe', 'ıframe'), + ('noframes', 'noframeſ'), + ('noscript', 'noſcript'), + ('noscript', 'noscrıpt'), + ('script', 'ſcript'), + ('script', 'scrıpt'), + ]) + def test_invalid_nonascii_closing_tag(self, tag, endtag): + content = f"<br></{endtag}>" + source = f"<{tag}>{content}" + self._run_check(source, [ + ("starttag", tag, []), + ("data", content), + ], collector=EventCollector(convert_charrefs=False, scripting=True)) + source = f"<{tag}>{content}</{tag}>" + self._run_check(source, [ + ("starttag", tag, []), + ("data", content), + ("endtag", tag), + ], collector=EventCollector(convert_charrefs=False, scripting=True)) @support.subTests('tail,end', [ ('', False), @@ -735,20 +840,6 @@ text ] self._run_check(html, expected) - def test_EOF_in_charref(self): - # see #17802 - # This test checks that the UnboundLocalError reported in the issue - # is not raised, however I'm not sure the returned values are correct. - # Maybe HTMLParser should use self.unescape for these - data = [ - ('a&', [('data', 'a&')]), - ('a&b', [('data', 'ab')]), - ('a&b ', [('data', 'a'), ('entityref', 'b'), ('data', ' ')]), - ('a&b;', [('data', 'a'), ('entityref', 'b')]), - ] - for html, expected in data: - self._run_check(html, expected) - def test_eof_in_comments(self): data = [ ('<!--', [('comment', '')]), diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 47e3914d1dd..44044d0385c 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1511,6 +1511,72 @@ class BasicTest(TestCase): thread.join() self.assertEqual(result, b"proxied data\n") + def test_large_content_length(self): + serv = socket.create_server((HOST, 0)) + self.addCleanup(serv.close) + + def run_server(): + [conn, address] = serv.accept() + with conn: + while conn.recv(1024): + conn.sendall( + b"HTTP/1.1 200 Ok\r\n" + b"Content-Length: %d\r\n" + b"\r\n" % size) + conn.sendall(b'A' * (size//3)) + conn.sendall(b'B' * (size - size//3)) + + thread = threading.Thread(target=run_server) + thread.start() + self.addCleanup(thread.join, 1.0) + + conn = client.HTTPConnection(*serv.getsockname()) + try: + for w in range(15, 27): + size = 1 << w + conn.request("GET", "/") + with conn.getresponse() as response: + self.assertEqual(len(response.read()), size) + finally: + conn.close() + thread.join(1.0) + + def test_large_content_length_truncated(self): + serv = socket.create_server((HOST, 0)) + self.addCleanup(serv.close) + + def run_server(): + while True: + [conn, address] = serv.accept() + with conn: + conn.recv(1024) + if not size: + break + conn.sendall( + b"HTTP/1.1 200 Ok\r\n" + b"Content-Length: %d\r\n" + b"\r\n" + b"Text" % size) + + thread = threading.Thread(target=run_server) + thread.start() + self.addCleanup(thread.join, 1.0) + + conn = client.HTTPConnection(*serv.getsockname()) + try: + for w in range(18, 65): + size = 1 << w + conn.request("GET", "/") + with conn.getresponse() as response: + self.assertRaises(client.IncompleteRead, response.read) + conn.close() + finally: + conn.close() + size = 0 + conn.request("GET", "/") + conn.close() + thread.join(1.0) + def test_putrequest_override_domain_validation(self): """ It should be possible to override the default validation diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 2548a7c5f29..0dc5c9dbaed 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -362,6 +362,44 @@ class BaseHTTPServerTestCase(BaseTestCase): self.assertEqual(b'', data) +class HTTP09ServerTestCase(BaseTestCase): + + class request_handler(NoLogRequestHandler, BaseHTTPRequestHandler): + """Request handler for HTTP/0.9 server.""" + + def do_GET(self): + self.wfile.write(f'OK: here is {self.path}\r\n'.encode()) + + def setUp(self): + super().setUp() + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock = self.enterContext(self.sock) + self.sock.connect((self.HOST, self.PORT)) + + def test_simple_get(self): + self.sock.send(b'GET /index.html\r\n') + res = self.sock.recv(1024) + self.assertEqual(res, b"OK: here is /index.html\r\n") + + def test_invalid_request(self): + self.sock.send(b'POST /index.html\r\n') + res = self.sock.recv(1024) + self.assertIn(b"Bad HTTP/0.9 request type ('POST')", res) + + def test_single_request(self): + self.sock.send(b'GET /foo.html\r\n') + res = self.sock.recv(1024) + self.assertEqual(res, b"OK: here is /foo.html\r\n") + + # Ignore errors if the connection is already closed, + # as this is the expected behavior of HTTP/0.9. + with contextlib.suppress(OSError): + self.sock.send(b'GET /bar.html\r\n') + res = self.sock.recv(1024) + # The server should not process our request. + self.assertEqual(res, b'') + + def certdata_file(*path): return os.path.join(os.path.dirname(__file__), "certdata", *path) @@ -1522,6 +1560,16 @@ class CommandLineRunTimeTestCase(unittest.TestCase): self.assertEqual(res, self.served_data) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(http.server, "__version__") + self.assertEqual(cm.filename, __file__) + + def setUpModule(): unittest.addModuleCleanup(os.chdir, os.getcwd()) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 3507fc83b6a..430fa71fa29 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -372,7 +372,11 @@ class NewIMAPTestsMixin: self._send_tagged(tag, 'OK', 'FAKEAUTH successful') def cmd_APPEND(self, tag, args): self._send_textline('+') - self.server.response = yield + self.server.response = args + literal = yield + self.server.response.append(literal) + literal = yield + self.server.response.append(literal) self._send_tagged(tag, 'OK', 'okay') client, server = self._setup(UTF8AppendServer) self.assertEqual(client._encoding, 'ascii') @@ -383,10 +387,13 @@ class NewIMAPTestsMixin: self.assertEqual(code, 'OK') self.assertEqual(client._encoding, 'utf-8') msg_string = 'Subject: üñí©öðé' - typ, data = client.append(None, None, None, msg_string.encode('utf-8')) + typ, data = client.append( + None, None, None, (msg_string + '\n').encode('utf-8')) self.assertEqual(typ, 'OK') self.assertEqual(server.response, - ('UTF8 (%s)\r\n' % msg_string).encode('utf-8')) + ['INBOX', 'UTF8', + '(~{25}', ('%s\r\n' % msg_string).encode('utf-8'), + b')\r\n' ]) def test_search_disallows_charset_in_utf8_mode(self): class UTF8Server(SimpleIMAPHandler): @@ -881,7 +888,11 @@ class ThreadedNetworkedTests(unittest.TestCase): class UTF8AppendServer(self.UTF8Server): def cmd_APPEND(self, tag, args): self._send_textline('+') - self.server.response = yield + self.server.response = args + literal = yield + self.server.response.append(literal) + literal = yield + self.server.response.append(literal) self._send_tagged(tag, 'OK', 'okay') with self.reaped_pair(UTF8AppendServer) as (server, client): @@ -895,12 +906,12 @@ class ThreadedNetworkedTests(unittest.TestCase): self.assertEqual(client._encoding, 'utf-8') msg_string = 'Subject: üñí©öðé' typ, data = client.append( - None, None, None, msg_string.encode('utf-8')) + None, None, None, (msg_string + '\n').encode('utf-8')) self.assertEqual(typ, 'OK') - self.assertEqual( - server.response, - ('UTF8 (%s)\r\n' % msg_string).encode('utf-8') - ) + self.assertEqual(server.response, + ['INBOX', 'UTF8', + '(~{25}', ('%s\r\n' % msg_string).encode('utf-8'), + b')\r\n' ]) # XXX also need a test that makes sure that the Literal and Untagged_status # regexes uses unicode in UTF8 mode instead of the default ASCII. @@ -1106,5 +1117,15 @@ class ThreadedNetworkedTestsSSL(ThreadedNetworkedTests): client.shutdown() +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(imaplib, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index abbd5f1ed5f..59c6dc4587c 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -15,6 +15,7 @@ import marshal import os import py_compile import random +import re import shutil import stat import subprocess @@ -23,6 +24,7 @@ import textwrap import threading import time import types +import warnings import unittest from unittest import mock import _imp @@ -51,7 +53,7 @@ from test.support.os_helper import ( TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE) from test.support import script_helper from test.support import threading_helper -from test.test_importlib.util import uncache +from test.test_importlib.util import uncache, temporary_pycache_prefix from types import ModuleType try: import _testsinglephase @@ -63,8 +65,10 @@ except ImportError: _testmultiphase = None try: import _interpreters + import concurrent.interpreters except ModuleNotFoundError: _interpreters = None + concurrent = None try: import _testinternalcapi except ImportError: @@ -412,7 +416,6 @@ class ImportTests(unittest.TestCase): self.assertIsNotNone(cm.exception) def test_from_import_star_invalid_type(self): - import re with ready_to_import() as (name, path): with open(path, 'w', encoding='utf-8') as f: f.write("__all__ = [b'invalid_type']") @@ -1187,6 +1190,7 @@ except ImportError as e: @unittest.skipIf(sys.platform == 'win32', 'Cannot delete cwd on Windows') @unittest.skipIf(sys.platform == 'sunos5', 'Cannot delete cwd on Solaris/Illumos') + @unittest.skipIf(sys.platform.startswith('aix'), 'Cannot delete cwd on AIX') def test_script_shadowing_stdlib_cwd_failure(self): with os_helper.temp_dir() as tmp: subtmp = os.path.join(tmp, "subtmp") @@ -1249,6 +1253,44 @@ os.does_not_exist origin = "a\x00b" _imp.create_dynamic(Spec2()) + def test_create_builtin(self): + class Spec: + pass + spec = Spec() + + spec.name = "sys" + self.assertIs(_imp.create_builtin(spec), sys) + + spec.name = None + with self.assertRaisesRegex(TypeError, 'name must be string, not NoneType'): + _imp.create_builtin(spec) + + # gh-142029 + spec.name = "nonexistent_lib" + with self.assertRaises(ModuleNotFoundError): + _imp.create_builtin(spec) + + # gh-142029 + spec.name = "" + with self.assertRaisesRegex(ValueError, 'name must not be empty'): + _imp.create_builtin(spec) + + def test_filter_syntax_warnings_by_module(self): + module_re = r'test\.test_import\.data\.syntax_warnings\z' + unload('test.test_import.data.syntax_warnings') + with (os_helper.temp_dir() as tmpdir, + temporary_pycache_prefix(tmpdir), + warnings.catch_warnings(record=True) as wlog): + warnings.simplefilter('error') + warnings.filterwarnings('always', module=module_re) + warnings.filterwarnings('error', module='syntax_warnings') + import test.test_import.data.syntax_warnings + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + filename = test.test_import.data.syntax_warnings.__file__ + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + @skip_if_dont_write_bytecode class FilePermissionTests(unittest.TestCase): @@ -1679,78 +1721,6 @@ class PycacheTests(unittest.TestCase): finally: os.remove(pyc_file) - def test___cached__(self): - # Modules now also have an __cached__ that points to the pyc file. - m = __import__(TESTFN) - pyc_file = importlib.util.cache_from_source(TESTFN + '.py') - self.assertEqual(m.__cached__, os.path.join(os.getcwd(), pyc_file)) - - @skip_if_dont_write_bytecode - def test___cached___legacy_pyc(self): - # Like test___cached__() except that for backward compatibility, - # when the pyc file lives where the py file would have been (and named - # without the tag), it is importable. The __cached__ of the imported - # module is the pyc location. - __import__(TESTFN) - # pyc_file gets removed in _clean() via tearDown(). - pyc_file = make_legacy_pyc(self.source) - os.remove(self.source) - unload(TESTFN) - importlib.invalidate_caches() - m = __import__(TESTFN) - self.assertEqual(m.__cached__, - os.path.join(os.getcwd(), os.path.relpath(pyc_file))) - - @skip_if_dont_write_bytecode - def test_package___cached__(self): - # Like test___cached__ but for packages. - def cleanup(): - rmtree('pep3147') - unload('pep3147.foo') - unload('pep3147') - os.mkdir('pep3147') - self.addCleanup(cleanup) - # Touch the __init__.py - with open(os.path.join('pep3147', '__init__.py'), 'wb'): - pass - with open(os.path.join('pep3147', 'foo.py'), 'wb'): - pass - importlib.invalidate_caches() - m = __import__('pep3147.foo') - init_pyc = importlib.util.cache_from_source( - os.path.join('pep3147', '__init__.py')) - self.assertEqual(m.__cached__, os.path.join(os.getcwd(), init_pyc)) - foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py')) - self.assertEqual(sys.modules['pep3147.foo'].__cached__, - os.path.join(os.getcwd(), foo_pyc)) - - def test_package___cached___from_pyc(self): - # Like test___cached__ but ensuring __cached__ when imported from a - # PEP 3147 pyc file. - def cleanup(): - rmtree('pep3147') - unload('pep3147.foo') - unload('pep3147') - os.mkdir('pep3147') - self.addCleanup(cleanup) - # Touch the __init__.py - with open(os.path.join('pep3147', '__init__.py'), 'wb'): - pass - with open(os.path.join('pep3147', 'foo.py'), 'wb'): - pass - importlib.invalidate_caches() - m = __import__('pep3147.foo') - unload('pep3147.foo') - unload('pep3147') - importlib.invalidate_caches() - m = __import__('pep3147.foo') - init_pyc = importlib.util.cache_from_source( - os.path.join('pep3147', '__init__.py')) - self.assertEqual(m.__cached__, os.path.join(os.getcwd(), init_pyc)) - foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py')) - self.assertEqual(sys.modules['pep3147.foo'].__cached__, - os.path.join(os.getcwd(), foo_pyc)) - def test_recompute_pyc_same_second(self): # Even when the source file doesn't change timestamp, a change in # source size is enough to trigger recomputation of the pyc file. @@ -2019,10 +1989,6 @@ class ImportTracebackTests(unittest.TestCase): # away from the traceback. self.create_module("foo", "") importlib = sys.modules['_frozen_importlib_external'] - if 'load_module' in vars(importlib.SourceLoader): - old_exec_module = importlib.SourceLoader.exec_module - else: - old_exec_module = None try: def exec_module(*args): 1/0 @@ -2035,10 +2001,7 @@ class ImportTracebackTests(unittest.TestCase): self.fail("ZeroDivisionError should have been raised") self.assert_traceback(tb, [__file__, '<frozen importlib', __file__]) finally: - if old_exec_module is None: - del importlib.SourceLoader.exec_module - else: - importlib.SourceLoader.exec_module = old_exec_module + del importlib.SourceLoader.exec_module @unittest.skipUnless(TESTFN_UNENCODABLE, 'need TESTFN_UNENCODABLE') def test_unencodable_filename(self): @@ -2466,6 +2429,21 @@ class SubinterpImportTests(unittest.TestCase): self.check_compatible_here( modname, filename, strict=False, isolated=False) + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + def test_testmultiphase_exec_multiple(self): + modname = '_testmultiphase_exec_multiple' + filename = _testmultiphase.__file__ + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + # All three exec's were called. + self.assertEqual(module.a, 1) + self.assertEqual(module.b, 2) + self.assertEqual(module.c, 3) + # They were called in order. + keys = list(module.__dict__) + self.assertLess(keys.index('a'), keys.index('b')) + self.assertLess(keys.index('b'), keys.index('c')) + @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") def test_python_compat(self): module = 'threading' @@ -2743,9 +2721,6 @@ class SinglephaseInitTests(unittest.TestCase): # This is essentially copied from the old imp module. from importlib._bootstrap import _load loader = self.LOADER(name, path) - - # Issue bpo-24748: Skip the sys.modules check in _load_module_shim; - # always load new extension. spec = importlib.util.spec_from_file_location(name, path, loader=loader) return _load(spec) @@ -3159,6 +3134,7 @@ class SinglephaseInitTests(unittest.TestCase): # Also, we test with a single-phase module that has global state, # which is shared by all interpreters. + @no_rerun(reason="module state is not cleared (see gh-140657)") @requires_subinterpreters def test_basic_multiple_interpreters_main_no_reset(self): # without resetting; already loaded in main interpreter @@ -3227,6 +3203,7 @@ class SinglephaseInitTests(unittest.TestCase): # * m_copy was copied from interp2 (was from interp1) # * module's global state was updated, not reset + @unittest.skip("gh-131229: This is suddenly very flaky") @no_rerun(reason="rerun not possible; module state is never cleared (see gh-102251)") @requires_subinterpreters def test_basic_multiple_interpreters_deleted_no_reset(self): @@ -3362,6 +3339,150 @@ class SinglephaseInitTests(unittest.TestCase): # * module's global state was initialized, not reset +@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") +class ModexportTests(unittest.TestCase): + def test_from_modexport(self): + modname = '_test_from_modexport' + filename = _testmultiphase.__file__ + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + + self.assertEqual(module.__name__, modname) + + @requires_subinterpreters + def test_from_modexport_gil_used(self): + # Test that a module with Py_MOD_GIL_USED (re-)enables the GIL. + # Do this in a new interpreter to avoid interfering with global state. + modname = '_test_from_modexport_gil_used' + filename = _testmultiphase.__file__ + interp = concurrent.interpreters.create() + self.addCleanup(interp.close) + queue = concurrent.interpreters.create_queue() + interp.prepare_main( + modname=modname, + filename=filename, + queue=queue, + ) + enabled_before = sys._is_gil_enabled() + interp.exec(f"""if True: + import sys + from test.support.warnings_helper import check_warnings + from {__name__} import import_extension_from_file + with check_warnings((".*GIL..has been enabled.*", RuntimeWarning), + quiet=True): + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + queue.put(module.__name__) + queue.put(sys._is_gil_enabled()) + """) + + self.assertEqual(queue.get(), modname) + self.assertEqual(queue.get(), True) + self.assertTrue(queue.empty()) + + self.assertEqual(enabled_before, sys._is_gil_enabled()) + + def test_from_modexport_null(self): + modname = '_test_from_modexport_null' + filename = _testmultiphase.__file__ + with self.assertRaises(SystemError): + import_extension_from_file(modname, filename, + put_in_sys_modules=False) + + def test_from_modexport_exception(self): + modname = '_test_from_modexport_exception' + filename = _testmultiphase.__file__ + with self.assertRaises(ValueError): + import_extension_from_file(modname, filename, + put_in_sys_modules=False) + + def test_from_modexport_create_nonmodule(self): + modname = '_test_from_modexport_create_nonmodule' + filename = _testmultiphase.__file__ + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + self.assertIsInstance(module, str) + + @requires_subinterpreters + def test_from_modexport_create_nonmodule_gil_used(self): + # Test that a module with Py_MOD_GIL_USED (re-)enables the GIL. + # Do this in a new interpreter to avoid interfering with global state. + modname = '_test_from_modexport_create_nonmodule_gil_used' + filename = _testmultiphase.__file__ + interp = concurrent.interpreters.create() + self.addCleanup(interp.close) + queue = concurrent.interpreters.create_queue() + interp.prepare_main( + modname=modname, + filename=filename, + queue=queue, + ) + enabled_before = sys._is_gil_enabled() + interp.exec(f"""if True: + import sys + from test.support.warnings_helper import check_warnings + from {__name__} import import_extension_from_file + with check_warnings((".*GIL..has been enabled.*", RuntimeWarning), + quiet=True): + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + queue.put(module) + queue.put(sys._is_gil_enabled()) + """) + + self.assertIsInstance(queue.get(), str) + self.assertEqual(queue.get(), True) + self.assertTrue(queue.empty()) + + self.assertEqual(enabled_before, sys._is_gil_enabled()) + + def test_from_modexport_smoke(self): + # General positive test for sundry features + # (PyModule_FromSlotsAndSpec tests exercise these more carefully) + modname = '_test_from_modexport_smoke' + filename = _testmultiphase.__file__ + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + self.assertEqual(module.__doc__, "the expected docstring") + self.assertEqual(module.number, 147) + self.assertEqual(module.get_state_int(), 258) + self.assertGreater(module.get_test_token(), 0) + + def test_from_modexport_smoke_token(self): + _testcapi = import_module("_testcapi") + + modname = '_test_from_modexport_smoke' + filename = _testmultiphase.__file__ + module = import_extension_from_file(modname, filename, + put_in_sys_modules=False) + token = module.get_test_token() + self.assertEqual(_testcapi.pymodule_get_token(module), token) + + tp = module.Example + self.assertEqual(_testcapi.pytype_getmodulebytoken(tp, token), module) + class Sub(tp): + pass + self.assertEqual(_testcapi.pytype_getmodulebytoken(Sub, token), module) + + @requires_gil_enabled("empty slots re-enable GIL") + def test_from_modexport_empty_slots(self): + # Module to test that: + # - no slots are mandatory for PyModExport + # - the slots array is used as the default token + modname = '_test_from_modexport_empty_slots' + filename = _testmultiphase.__file__ + module = import_extension_from_file( + modname, filename, put_in_sys_modules=False) + + self.assertEqual(module.__name__, modname) + self.assertEqual(module.__doc__, None) + + _testcapi = import_module("_testcapi") + smoke_mod = import_extension_from_file( + '_test_from_modexport_smoke', filename, put_in_sys_modules=False) + self.assertEqual(_testcapi.pymodule_get_token(module), + smoke_mod.get_modexport_empty_slots()) + @cpython_only class TestMagicNumber(unittest.TestCase): def test_magic_number_endianness(self): diff --git a/Lib/test/test_import/data/syntax_warnings.py b/Lib/test/test_import/data/syntax_warnings.py new file mode 100644 index 00000000000..103f07b6187 --- /dev/null +++ b/Lib/test/test_import/data/syntax_warnings.py @@ -0,0 +1,21 @@ +# Syntax warnings emitted in different parts of the Python compiler. + +# Parser/lexer/lexer.c +x = 1or 0 # line 4 + +# Parser/tokenizer/helpers.c +'\z' # line 7 + +# Parser/string_parser.c +'\400' # line 10 + +# _PyCompile_Warn() in Python/codegen.c +assert(x, 'message') # line 13 +x is 1 # line 14 + +# _PyErr_EmitSyntaxWarning() in Python/ast_preprocess.c +def f(): + try: + pass + finally: + return 42 # line 21 diff --git a/Lib/test/test_import/data/unwritable/__init__.py b/Lib/test/test_import/data/unwritable/__init__.py index da4ddb3d027..1d61ff348d8 100644 --- a/Lib/test/test_import/data/unwritable/__init__.py +++ b/Lib/test/test_import/data/unwritable/__init__.py @@ -1,9 +1,9 @@ import sys class MyMod(object): - __slots__ = ['__builtins__', '__cached__', '__doc__', - '__file__', '__loader__', '__name__', - '__package__', '__path__', '__spec__'] + __slots__ = ['__builtins__', '__doc__', '__file__', + '__loader__', '__name__', '__package__', + '__path__', '__spec__'] def __init__(self): for attr in self.__slots__: setattr(self, attr, globals()[attr]) diff --git a/Lib/test/test_importlib/abc.py b/Lib/test/test_importlib/abc.py index 5d4b9587676..0da98e0c99e 100644 --- a/Lib/test/test_importlib/abc.py +++ b/Lib/test/test_importlib/abc.py @@ -40,22 +40,6 @@ class FinderTests(metaclass=abc.ABCMeta): class LoaderTests(metaclass=abc.ABCMeta): - @abc.abstractmethod - def test_module(self): - """A module should load without issue. - - After the loader returns the module should be in sys.modules. - - Attributes to verify: - - * __file__ - * __loader__ - * __name__ - * No __path__ - - """ - pass - @abc.abstractmethod def test_package(self): """Loading a package should work. diff --git a/Lib/test/test_importlib/builtin/test_loader.py b/Lib/test/test_importlib/builtin/test_loader.py index 7e9d1b1960f..2a5c2a8f39e 100644 --- a/Lib/test/test_importlib/builtin/test_loader.py +++ b/Lib/test/test_importlib/builtin/test_loader.py @@ -7,70 +7,6 @@ import types import unittest import warnings -@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') -class LoaderTests(abc.LoaderTests): - - """Test load_module() for built-in modules.""" - - def setUp(self): - self.verification = {'__name__': 'errno', '__package__': '', - '__loader__': self.machinery.BuiltinImporter} - - def verify(self, module): - """Verify that the module matches against what it should have.""" - self.assertIsInstance(module, types.ModuleType) - for attr, value in self.verification.items(): - self.assertEqual(getattr(module, attr), value) - self.assertIn(module.__name__, sys.modules) - - def load_module(self, name): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return self.machinery.BuiltinImporter.load_module(name) - - def test_module(self): - # Common case. - with util.uncache(util.BUILTINS.good_name): - module = self.load_module(util.BUILTINS.good_name) - self.verify(module) - - # Built-in modules cannot be a package. - test_package = test_lacking_parent = None - - # No way to force an import failure. - test_state_after_failure = None - - def test_module_reuse(self): - # Test that the same module is used in a reload. - with util.uncache(util.BUILTINS.good_name): - module1 = self.load_module(util.BUILTINS.good_name) - module2 = self.load_module(util.BUILTINS.good_name) - self.assertIs(module1, module2) - - def test_unloadable(self): - name = 'dssdsdfff' - assert name not in sys.builtin_module_names - with self.assertRaises(ImportError) as cm: - self.load_module(name) - self.assertEqual(cm.exception.name, name) - - def test_already_imported(self): - # Using the name of a module already imported but not a built-in should - # still fail. - module_name = 'builtin_reload_test' - assert module_name not in sys.builtin_module_names - with util.uncache(module_name): - module = types.ModuleType(module_name) - sys.modules[module_name] = module - with self.assertRaises(ImportError) as cm: - self.load_module(module_name) - self.assertEqual(cm.exception.name, module_name) - - -(Frozen_LoaderTests, - Source_LoaderTests - ) = util.test_both(LoaderTests, machinery=machinery) - @unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') class InspectLoaderTests: diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 0dd21e079eb..15d5a7d4752 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -35,11 +35,6 @@ class LoaderTests: self.loader = self.LoaderClass(util.EXTENSIONS.name, util.EXTENSIONS.file_path) - def load_module(self, fullname): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return self.loader.load_module(fullname) - def test_equality(self): other = self.LoaderClass(util.EXTENSIONS.name, util.EXTENSIONS.file_path) self.assertEqual(self.loader, other) @@ -48,25 +43,6 @@ class LoaderTests: other = self.LoaderClass('_' + util.EXTENSIONS.name, util.EXTENSIONS.file_path) self.assertNotEqual(self.loader, other) - def test_load_module_API(self): - # Test the default argument for load_module(). - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - self.loader.load_module() - self.loader.load_module(None) - with self.assertRaises(ImportError): - self.load_module('XXX') - - def test_module(self): - with util.uncache(util.EXTENSIONS.name): - module = self.load_module(util.EXTENSIONS.name) - for attr, value in [('__name__', util.EXTENSIONS.name), - ('__file__', util.EXTENSIONS.file_path), - ('__package__', '')]: - self.assertEqual(getattr(module, attr), value) - self.assertIn(util.EXTENSIONS.name, sys.modules) - self.assertIsInstance(module.__loader__, self.LoaderClass) - # No extension module as __init__ available for testing. test_package = None @@ -76,18 +52,6 @@ class LoaderTests: # No easy way to trigger a failure after a successful import. test_state_after_failure = None - def test_unloadable(self): - name = 'asdfjkl;' - with self.assertRaises(ImportError) as cm: - self.load_module(name) - self.assertEqual(cm.exception.name, name) - - def test_module_reuse(self): - with util.uncache(util.EXTENSIONS.name): - module1 = self.load_module(util.EXTENSIONS.name) - module2 = self.load_module(util.EXTENSIONS.name) - self.assertIs(module1, module2) - def test_is_package(self): self.assertFalse(self.loader.is_package(util.EXTENSIONS.name)) for suffix in self.machinery.EXTENSION_SUFFIXES: @@ -126,11 +90,6 @@ class SinglePhaseExtensionModuleTests(abc.LoaderTests): self.loader = self.LoaderClass(self.name, self.spec.origin) - def load_module(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return self.loader.load_module(self.name) - def load_module_by_name(self, fullname): # Load a module from the test extension by name. origin = self.spec.origin @@ -140,19 +99,6 @@ class SinglePhaseExtensionModuleTests(abc.LoaderTests): loader.exec_module(module) return module - def test_module(self): - # Test loading an extension module. - with util.uncache(self.name): - module = self.load_module() - for attr, value in [('__name__', self.name), - ('__file__', self.spec.origin), - ('__package__', '')]: - self.assertEqual(getattr(module, attr), value) - with self.assertRaises(AttributeError): - module.__path__ - self.assertIs(module, sys.modules[self.name]) - self.assertIsInstance(module.__loader__, self.LoaderClass) - # No extension module as __init__ available for testing. test_package = None @@ -213,12 +159,6 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests): assert self.spec self.loader = self.LoaderClass(self.name, self.spec.origin) - def load_module(self): - # Load the module from the test extension. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return self.loader.load_module(self.name) - def load_module_by_name(self, fullname): # Load a module from the test extension by name. origin = self.spec.origin @@ -237,60 +177,6 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests): # Handling failure on reload is the up to the module. test_state_after_failure = None - def test_module(self): - # Test loading an extension module. - with util.uncache(self.name): - module = self.load_module() - for attr, value in [('__name__', self.name), - ('__file__', self.spec.origin), - ('__package__', '')]: - self.assertEqual(getattr(module, attr), value) - with self.assertRaises(AttributeError): - module.__path__ - self.assertIs(module, sys.modules[self.name]) - self.assertIsInstance(module.__loader__, self.LoaderClass) - - def test_functionality(self): - # Test basic functionality of stuff defined in an extension module. - with util.uncache(self.name): - module = self.load_module() - self.assertIsInstance(module, types.ModuleType) - ex = module.Example() - self.assertEqual(ex.demo('abcd'), 'abcd') - self.assertEqual(ex.demo(), None) - with self.assertRaises(AttributeError): - ex.abc - ex.abc = 0 - self.assertEqual(ex.abc, 0) - self.assertEqual(module.foo(9, 9), 18) - self.assertIsInstance(module.Str(), str) - self.assertEqual(module.Str(1) + '23', '123') - with self.assertRaises(module.error): - raise module.error() - self.assertEqual(module.int_const, 1969) - self.assertEqual(module.str_const, 'something different') - - def test_reload(self): - # Test that reload didn't re-set the module's attributes. - with util.uncache(self.name): - module = self.load_module() - ex_class = module.Example - importlib.reload(module) - self.assertIs(ex_class, module.Example) - - def test_try_registration(self): - # Assert that the PyState_{Find,Add,Remove}Module C API doesn't work. - with util.uncache(self.name): - module = self.load_module() - with self.subTest('PyState_FindModule'): - self.assertEqual(module.call_state_registration_func(0), None) - with self.subTest('PyState_AddModule'): - with self.assertRaises(SystemError): - module.call_state_registration_func(1) - with self.subTest('PyState_RemoveModule'): - with self.assertRaises(SystemError): - module.call_state_registration_func(2) - def test_load_submodule(self): # Test loading a simulated submodule. module = self.load_module_by_name('pkg.' + self.name) diff --git a/Lib/test/test_importlib/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py index d6ad590b3d4..ea1e29a4e5f 100644 --- a/Lib/test/test_importlib/import_/test_api.py +++ b/Lib/test/test_importlib/import_/test_api.py @@ -27,13 +27,6 @@ class BadSpecFinderLoader: raise ImportError('I cannot be loaded!') -class BadLoaderFinder: - @classmethod - def load_module(cls, fullname): - if fullname == SUBMOD_NAME: - raise ImportError('I cannot be loaded!') - - class APITest: """Test API-specific details for __import__ (e.g. raising the right @@ -93,45 +86,6 @@ class APITest: self.assertEqual(cm.exception.name, SUBMOD_NAME) -class OldAPITests(APITest): - bad_finder_loader = BadLoaderFinder - - def test_raises_ModuleNotFoundError(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_raises_ModuleNotFoundError() - - def test_name_requires_rparition(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_name_requires_rparition() - - def test_negative_level(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_negative_level() - - def test_nonexistent_fromlist_entry(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_nonexistent_fromlist_entry() - - def test_fromlist_load_error_propagates(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_fromlist_load_error_propagates - - def test_blocked_fromlist(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_blocked_fromlist() - - -(Frozen_OldAPITests, - Source_OldAPITests - ) = util.test_both(OldAPITests, __import__=util.__import__) - - class SpecAPITests(APITest): bad_finder_loader = BadSpecFinderLoader diff --git a/Lib/test/test_importlib/import_/test_helpers.py b/Lib/test/test_importlib/import_/test_helpers.py index 550f88d1d7a..7587276a41e 100644 --- a/Lib/test/test_importlib/import_/test_helpers.py +++ b/Lib/test/test_importlib/import_/test_helpers.py @@ -19,8 +19,7 @@ class FixUpModuleTests: ns = {"__spec__": spec} _bootstrap_external._fix_up_module(ns, name, path) - expected = {"__spec__": spec, "__loader__": loader, "__file__": path, - "__cached__": None} + expected = {"__spec__": spec, "__loader__": loader, "__file__": path} self.assertEqual(ns, expected) def test_no_loader_no_spec_but_sourceless(self): @@ -29,7 +28,7 @@ class FixUpModuleTests: ns = {} _bootstrap_external._fix_up_module(ns, name, path, path) - expected = {"__file__": path, "__cached__": path} + expected = {"__file__": path} for key, val in expected.items(): with self.subTest(f"{key}: {val}"): @@ -51,7 +50,7 @@ class FixUpModuleTests: ns = {} _bootstrap_external._fix_up_module(ns, name, path) - expected = {"__file__": path, "__cached__": None} + expected = {"__file__": path} for key, val in expected.items(): with self.subTest(f"{key}: {val}"): diff --git a/Lib/test/test_importlib/metadata/_path.py b/Lib/test/test_importlib/metadata/_path.py index b3cfb9cd549..e63d889f96b 100644 --- a/Lib/test/test_importlib/metadata/_path.py +++ b/Lib/test/test_importlib/metadata/_path.py @@ -1,9 +1,14 @@ -# from jaraco.path 3.7 +# from jaraco.path 3.7.2 + +from __future__ import annotations import functools import pathlib -from typing import Dict, Protocol, Union -from typing import runtime_checkable +from collections.abc import Mapping +from typing import TYPE_CHECKING, Protocol, Union, runtime_checkable + +if TYPE_CHECKING: + from typing_extensions import Self class Symlink(str): @@ -12,29 +17,25 @@ class Symlink(str): """ -FilesSpec = Dict[str, Union[str, bytes, Symlink, 'FilesSpec']] # type: ignore +FilesSpec = Mapping[str, Union[str, bytes, Symlink, 'FilesSpec']] @runtime_checkable class TreeMaker(Protocol): - def __truediv__(self, *args, **kwargs): ... # pragma: no cover - - def mkdir(self, **kwargs): ... # pragma: no cover - - def write_text(self, content, **kwargs): ... # pragma: no cover - - def write_bytes(self, content): ... # pragma: no cover - - def symlink_to(self, target): ... # pragma: no cover + def __truediv__(self, other, /) -> Self: ... + def mkdir(self, *, exist_ok) -> object: ... + def write_text(self, content, /, *, encoding) -> object: ... + def write_bytes(self, content, /) -> object: ... + def symlink_to(self, target, /) -> object: ... -def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: - return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore +def _ensure_tree_maker(obj: str | TreeMaker) -> TreeMaker: + return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) def build( spec: FilesSpec, - prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore + prefix: str | TreeMaker = pathlib.Path(), ): """ Build a set of files/directories, as described by the spec. @@ -66,23 +67,24 @@ def build( @functools.singledispatch -def create(content: Union[str, bytes, FilesSpec], path): +def create(content: str | bytes | FilesSpec, path: TreeMaker) -> None: path.mkdir(exist_ok=True) - build(content, prefix=path) # type: ignore + # Mypy only looks at the signature of the main singledispatch method. So it must contain the complete Union + build(content, prefix=path) # type: ignore[arg-type] # python/mypy#11727 @create.register -def _(content: bytes, path): +def _(content: bytes, path: TreeMaker) -> None: path.write_bytes(content) @create.register -def _(content: str, path): +def _(content: str, path: TreeMaker) -> None: path.write_text(content, encoding='utf-8') @create.register -def _(content: Symlink, path): +def _(content: Symlink, path: TreeMaker) -> None: path.symlink_to(content) diff --git a/Lib/test/test_importlib/metadata/fixtures.py b/Lib/test/test_importlib/metadata/fixtures.py index 826b1b3259b..ad0ab42e089 100644 --- a/Lib/test/test_importlib/metadata/fixtures.py +++ b/Lib/test/test_importlib/metadata/fixtures.py @@ -1,11 +1,11 @@ -import sys -import copy -import json -import shutil -import pathlib -import textwrap -import functools import contextlib +import copy +import functools +import json +import pathlib +import shutil +import sys +import textwrap from test.support import import_helper from test.support import os_helper @@ -14,14 +14,10 @@ from test.support import requires_zlib from . import _path from ._path import FilesSpec - -try: - from importlib import resources # type: ignore - - getattr(resources, 'files') - getattr(resources, 'as_file') -except (ImportError, AttributeError): - import importlib_resources as resources # type: ignore +if sys.version_info >= (3, 9): + from importlib import resources +else: + import importlib_resources as resources @contextlib.contextmanager @@ -378,6 +374,8 @@ class ZipFixtures: # Add self.zip_name to the front of sys.path. self.resources = contextlib.ExitStack() self.addCleanup(self.resources.close) + # workaround for #138313 + self.addCleanup(lambda: None) def parameterize(*args_set): diff --git a/Lib/test/test_importlib/metadata/test_api.py b/Lib/test/test_importlib/metadata/test_api.py index 813febf2695..9f6e12c87e8 100644 --- a/Lib/test/test_importlib/metadata/test_api.py +++ b/Lib/test/test_importlib/metadata/test_api.py @@ -1,9 +1,8 @@ +import importlib import re import textwrap import unittest -import importlib -from . import fixtures from importlib.metadata import ( Distribution, PackageNotFoundError, @@ -15,6 +14,8 @@ from importlib.metadata import ( version, ) +from . import fixtures + class APITests( fixtures.EggInfoPkg, diff --git a/Lib/test/test_importlib/metadata/test_main.py b/Lib/test/test_importlib/metadata/test_main.py index a0bc8222d5b..83b686babfd 100644 --- a/Lib/test/test_importlib/metadata/test_main.py +++ b/Lib/test/test_importlib/metadata/test_main.py @@ -1,8 +1,7 @@ -import re -import pickle -import unittest import importlib -import importlib.metadata +import pickle +import re +import unittest from test.support import os_helper try: @@ -10,8 +9,6 @@ try: except ImportError: from .stubs import fake_filesystem_unittest as ffs -from . import fixtures -from ._path import Symlink from importlib.metadata import ( Distribution, EntryPoint, @@ -24,6 +21,9 @@ from importlib.metadata import ( version, ) +from . import fixtures +from ._path import Symlink + class BasicTests(fixtures.DistInfoPkg, unittest.TestCase): version_pattern = r'\d+\.\d+(\.\d)?' @@ -157,6 +157,16 @@ class InvalidMetadataTests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCa dist = Distribution.from_name('foo') assert dist.version == "1.0" + def test_missing_metadata(self): + """ + Dists with a missing metadata file should return None. + + Ref python/importlib_metadata#493. + """ + fixtures.build_files(self.make_pkg('foo-4.3', files={}), self.site_dir) + assert Distribution.from_name('foo').metadata is None + assert metadata('foo') is None + class NonASCIITests(fixtures.OnSysPath, fixtures.SiteDir, unittest.TestCase): @staticmethod diff --git a/Lib/test/test_importlib/metadata/test_zip.py b/Lib/test/test_importlib/metadata/test_zip.py index 276f6288c91..fcb649f3736 100644 --- a/Lib/test/test_importlib/metadata/test_zip.py +++ b/Lib/test/test_importlib/metadata/test_zip.py @@ -1,7 +1,6 @@ import sys import unittest -from . import fixtures from importlib.metadata import ( PackageNotFoundError, distribution, @@ -11,6 +10,8 @@ from importlib.metadata import ( version, ) +from . import fixtures + class TestZip(fixtures.ZipFixtures, unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_importlib/namespace_pkgs/foo/README.md b/Lib/test/test_importlib/namespace_pkgs/foo/README.md new file mode 100644 index 00000000000..9f6bc74941d --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/foo/README.md @@ -0,0 +1,2 @@ +This directory should not be a package, but should share a name with an +unrelated subpackage. diff --git a/Lib/test/test_importlib/resources/test_files.py b/Lib/test/test_importlib/resources/test_files.py index 3ce44999f98..c935b1e10ac 100644 --- a/Lib/test/test_importlib/resources/test_files.py +++ b/Lib/test/test_importlib/resources/test_files.py @@ -38,14 +38,6 @@ class FilesTests: binfile = files.joinpath('subdirectory', 'binary.file') self.assertTrue(binfile.is_file()) - def test_old_parameter(self): - """ - Files used to take a 'package' parameter. Make sure anyone - passing by name is still supported. - """ - with suppress_known_deprecation(): - resources.files(package=self.data) - class OpenDiskTests(FilesTests, util.DiskSetup, unittest.TestCase): pass diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py index f35adec1a8e..5d5d4722171 100644 --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -22,7 +22,7 @@ from test.test_py_compile import without_source_date_epoch from test.test_py_compile import SourceDateEpochTestMeta -class SimpleTest(abc.LoaderTests): +class SimpleTest: """Should have no issue importing a source module [basic]. And if there is a syntax error, it should raise a SyntaxError [syntax error]. @@ -34,17 +34,6 @@ class SimpleTest(abc.LoaderTests): self.filepath = os.path.join('ham', self.name + '.py') self.loader = self.machinery.SourceFileLoader(self.name, self.filepath) - def test_load_module_API(self): - class Tester(self.abc.FileLoader): - def get_source(self, _): return 'attr = 42' - def is_package(self, _): return False - - loader = Tester('blah', 'blah.py') - self.addCleanup(unload, 'blah') - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module() # Should not raise an exception. - def test_get_filename_API(self): # If fullname is not set then assume self.path is desired. class Tester(self.abc.FileLoader): @@ -69,173 +58,11 @@ class SimpleTest(abc.LoaderTests): other = self.machinery.SourceFileLoader('_' + self.name, self.filepath) self.assertNotEqual(self.loader, other) - # [basic] - def test_module(self): - with util.create_modules('_temp') as mapping: - loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module('_temp') - self.assertIn('_temp', sys.modules) - check = {'__name__': '_temp', '__file__': mapping['_temp'], - '__package__': ''} - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) - - def test_package(self): - with util.create_modules('_pkg.__init__') as mapping: - loader = self.machinery.SourceFileLoader('_pkg', - mapping['_pkg.__init__']) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module('_pkg') - self.assertIn('_pkg', sys.modules) - check = {'__name__': '_pkg', '__file__': mapping['_pkg.__init__'], - '__path__': [os.path.dirname(mapping['_pkg.__init__'])], - '__package__': '_pkg'} - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) - - - def test_lacking_parent(self): - with util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: - loader = self.machinery.SourceFileLoader('_pkg.mod', - mapping['_pkg.mod']) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module('_pkg.mod') - self.assertIn('_pkg.mod', sys.modules) - check = {'__name__': '_pkg.mod', '__file__': mapping['_pkg.mod'], - '__package__': '_pkg'} - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) def fake_mtime(self, fxn): """Fake mtime to always be higher than expected.""" return lambda name: fxn(name) + 1 - def test_module_reuse(self): - with util.create_modules('_temp') as mapping: - loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module('_temp') - module_id = id(module) - module_dict_id = id(module.__dict__) - with open(mapping['_temp'], 'w', encoding='utf-8') as file: - file.write("testing_var = 42\n") - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module('_temp') - self.assertIn('testing_var', module.__dict__, - "'testing_var' not in " - "{0}".format(list(module.__dict__.keys()))) - self.assertEqual(module, sys.modules['_temp']) - self.assertEqual(id(module), module_id) - self.assertEqual(id(module.__dict__), module_dict_id) - - def test_state_after_failure(self): - # A failed reload should leave the original module intact. - attributes = ('__file__', '__path__', '__package__') - value = '<test>' - name = '_temp' - with util.create_modules(name) as mapping: - orig_module = types.ModuleType(name) - for attr in attributes: - setattr(orig_module, attr, value) - with open(mapping[name], 'w', encoding='utf-8') as file: - file.write('+++ bad syntax +++') - loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - with self.assertRaises(SyntaxError): - loader.exec_module(orig_module) - for attr in attributes: - self.assertEqual(getattr(orig_module, attr), value) - with self.assertRaises(SyntaxError): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - loader.load_module(name) - for attr in attributes: - self.assertEqual(getattr(orig_module, attr), value) - - # [syntax error] - def test_bad_syntax(self): - with util.create_modules('_temp') as mapping: - with open(mapping['_temp'], 'w', encoding='utf-8') as file: - file.write('=') - loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - with self.assertRaises(SyntaxError): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - loader.load_module('_temp') - self.assertNotIn('_temp', sys.modules) - - def test_file_from_empty_string_dir(self): - # Loading a module found from an empty string entry on sys.path should - # not only work, but keep all attributes relative. - file_path = '_temp.py' - with open(file_path, 'w', encoding='utf-8') as file: - file.write("# test file for importlib") - try: - with util.uncache('_temp'): - loader = self.machinery.SourceFileLoader('_temp', file_path) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - mod = loader.load_module('_temp') - self.assertEqual(file_path, mod.__file__) - self.assertEqual(self.util.cache_from_source(file_path), - mod.__cached__) - finally: - os.unlink(file_path) - pycache = os.path.dirname(self.util.cache_from_source(file_path)) - if os.path.exists(pycache): - shutil.rmtree(pycache) - - @util.writes_bytecode_files - def test_timestamp_overflow(self): - # When a modification timestamp is larger than 2**32, it should be - # truncated rather than raise an OverflowError. - with util.create_modules('_temp') as mapping: - source = mapping['_temp'] - compiled = self.util.cache_from_source(source) - with open(source, 'w', encoding='utf-8') as f: - f.write("x = 5") - try: - os.utime(source, (2 ** 33 - 5, 2 ** 33 - 5)) - except OverflowError: - self.skipTest("cannot set modification time to large integer") - except OSError as e: - if e.errno != getattr(errno, 'EOVERFLOW', None): - raise - self.skipTest("cannot set modification time to large integer ({})".format(e)) - loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - # PEP 451 - module = types.ModuleType('_temp') - module.__spec__ = self.util.spec_from_loader('_temp', loader) - loader.exec_module(module) - self.assertEqual(module.x, 5) - self.assertTrue(os.path.exists(compiled)) - os.unlink(compiled) - # PEP 302 - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - mod = loader.load_module('_temp') - # Sanity checks. - self.assertEqual(mod.__cached__, compiled) - self.assertEqual(mod.x, 5) - # The pyc file was created. - self.assertTrue(os.path.exists(compiled)) - - def test_unloadable(self): - loader = self.machinery.SourceFileLoader('good name', {}) - module = types.ModuleType('bad name') - module.__spec__ = self.machinery.ModuleSpec('bad name', loader) - with self.assertRaises(ImportError): - loader.exec_module(module) - with self.assertRaises(ImportError): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - loader.load_module('bad name') - @util.writes_bytecode_files def test_checked_hash_based_pyc(self): with util.create_modules('_temp') as mapping: @@ -511,16 +338,6 @@ class BadBytecodeTestPEP451(BadBytecodeTest): loader.exec_module(module) -class BadBytecodeTestPEP302(BadBytecodeTest): - - def import_(self, file, module_name): - loader = self.loader(module_name, file) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = loader.load_module(module_name) - self.assertIn(module_name, sys.modules) - - class SourceLoaderBadBytecodeTest: @classmethod @@ -681,18 +498,6 @@ class SourceLoaderBadBytecodeTestPEP451( util=importlib_util) -class SourceLoaderBadBytecodeTestPEP302( - SourceLoaderBadBytecodeTest, BadBytecodeTestPEP302): - pass - - -(Frozen_SourceBadBytecodePEP302, - Source_SourceBadBytecodePEP302 - ) = util.test_both(SourceLoaderBadBytecodeTestPEP302, importlib=importlib, - machinery=machinery, abc=importlib_abc, - util=importlib_util) - - class SourcelessLoaderBadBytecodeTest: @classmethod @@ -779,17 +584,5 @@ class SourcelessLoaderBadBytecodeTestPEP451(SourcelessLoaderBadBytecodeTest, util=importlib_util) -class SourcelessLoaderBadBytecodeTestPEP302(SourcelessLoaderBadBytecodeTest, - BadBytecodeTestPEP302): - pass - - -(Frozen_SourcelessBadBytecodePEP302, - Source_SourcelessBadBytecodePEP302 - ) = util.test_both(SourcelessLoaderBadBytecodeTestPEP302, importlib=importlib, - machinery=machinery, abc=importlib_abc, - util=importlib_util) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py index 4de736a6bf3..c33e90232b3 100644 --- a/Lib/test/test_importlib/source/test_finder.py +++ b/Lib/test/test_importlib/source/test_finder.py @@ -73,7 +73,7 @@ class FinderTests(abc.FinderTests): if error.errno != errno.ENOENT: raise loader = self.import_(mapping['.root'], test) - self.assertHasAttr(loader, 'load_module') + self.assertHasAttr(loader, 'exec_module') return loader def test_module(self): @@ -100,7 +100,7 @@ class FinderTests(abc.FinderTests): with util.create_modules('pkg.__init__', 'pkg.sub') as mapping: pkg_dir = os.path.dirname(mapping['pkg.__init__']) loader = self.import_(pkg_dir, 'pkg.sub') - self.assertHasAttr(loader, 'load_module') + self.assertHasAttr(loader, 'exec_module') # [sub package] def test_package_in_package(self): @@ -108,7 +108,7 @@ class FinderTests(abc.FinderTests): with context as mapping: pkg_dir = os.path.dirname(mapping['pkg.__init__']) loader = self.import_(pkg_dir, 'pkg.sub') - self.assertHasAttr(loader, 'load_module') + self.assertHasAttr(loader, 'exec_module') # [package over modules] def test_package_over_module(self): @@ -129,7 +129,7 @@ class FinderTests(abc.FinderTests): file.write("# test file for importlib") try: loader = self._find(finder, 'mod', loader_only=True) - self.assertHasAttr(loader, 'load_module') + self.assertHasAttr(loader, 'exec_module') finally: os.unlink('mod.py') diff --git a/Lib/test/test_importlib/source/test_source_encoding.py b/Lib/test/test_importlib/source/test_source_encoding.py index c09c9aa12b8..fada07877fc 100644 --- a/Lib/test/test_importlib/source/test_source_encoding.py +++ b/Lib/test/test_importlib/source/test_source_encoding.py @@ -102,19 +102,6 @@ class EncodingTestPEP451(EncodingTest): ) = util.test_both(EncodingTestPEP451, machinery=machinery) -class EncodingTestPEP302(EncodingTest): - - def load(self, loader): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - return loader.load_module(self.module_name) - - -(Frozen_EncodingTestPEP302, - Source_EncodingTestPEP302 - ) = util.test_both(EncodingTestPEP302, machinery=machinery) - - class LineEndingTest: r"""Source written with the three types of line endings (\n, \r\n, \r) @@ -158,18 +145,5 @@ class LineEndingTestPEP451(LineEndingTest): ) = util.test_both(LineEndingTestPEP451, machinery=machinery) -class LineEndingTestPEP302(LineEndingTest): - - def load(self, loader, module_name): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - return loader.load_module(module_name) - - -(Frozen_LineEndingTestPEP302, - Source_LineEndingTestPEP302 - ) = util.test_both(LineEndingTestPEP302, machinery=machinery) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index dd943210ffc..7c146ea853b 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -194,10 +194,6 @@ class LoaderDefaultsTests(ABCTestHarness): spec = 'a spec' self.assertIsNone(self.ins.create_module(spec)) - def test_load_module(self): - with self.assertRaises(ImportError): - self.ins.load_module('something') - def test_module_repr(self): mod = types.ModuleType('blah') with warnings.catch_warnings(): @@ -358,38 +354,6 @@ class LoaderLoadModuleTests: return SpecLoader() - def test_fresh(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.loader() - name = 'blah' - with test_util.uncache(name): - loader.load_module(name) - module = loader.found - self.assertIs(sys.modules[name], module) - self.assertEqual(loader, module.__loader__) - self.assertEqual(loader, module.__spec__.loader) - self.assertEqual(name, module.__name__) - self.assertEqual(name, module.__spec__.name) - self.assertIsNotNone(module.__path__) - self.assertIsNotNone(module.__path__, - module.__spec__.submodule_search_locations) - - def test_reload(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - name = 'blah' - loader = self.loader() - module = types.ModuleType(name) - module.__spec__ = self.util.spec_from_loader(name, loader) - module.__loader__ = loader - with test_util.uncache(name): - sys.modules[name] = module - loader.load_module(name) - found = loader.found - self.assertIs(found, sys.modules[name]) - self.assertIs(module, sys.modules[name]) - (Frozen_LoaderLoadModuleTests, Source_LoaderLoadModuleTests @@ -478,59 +442,6 @@ class InspectLoaderGetCodeTests: InspectLoaderSubclass=SPLIT_IL) -class InspectLoaderLoadModuleTests: - - """Test InspectLoader.load_module().""" - - module_name = 'blah' - - def setUp(self): - import_helper.unload(self.module_name) - self.addCleanup(import_helper.unload, self.module_name) - - def load(self, loader): - spec = self.util.spec_from_loader(self.module_name, loader) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - return self.init._bootstrap._load_unlocked(spec) - - def mock_get_code(self): - return mock.patch.object(self.InspectLoaderSubclass, 'get_code') - - def test_get_code_ImportError(self): - # If get_code() raises ImportError, it should propagate. - with self.mock_get_code() as mocked_get_code: - mocked_get_code.side_effect = ImportError - with self.assertRaises(ImportError): - loader = self.InspectLoaderSubclass() - self.load(loader) - - def test_get_code_None(self): - # If get_code() returns None, raise ImportError. - with self.mock_get_code() as mocked_get_code: - mocked_get_code.return_value = None - with self.assertRaises(ImportError): - loader = self.InspectLoaderSubclass() - self.load(loader) - - def test_module_returned(self): - # The loaded module should be returned. - code = compile('attr = 42', '<string>', 'exec') - with self.mock_get_code() as mocked_get_code: - mocked_get_code.return_value = code - loader = self.InspectLoaderSubclass() - module = self.load(loader) - self.assertEqual(module, sys.modules[self.module_name]) - - -(Frozen_ILLoadModuleTests, - Source_ILLoadModuleTests - ) = test_util.test_both(InspectLoaderLoadModuleTests, - InspectLoaderSubclass=SPLIT_IL, - init=init, - util=util) - - ##### ExecutionLoader concrete methods ######################################### class ExecutionLoaderGetCodeTests: @@ -599,8 +510,7 @@ class ExecutionLoaderGetCodeTests: class SourceOnlyLoader: # Globals that should be defined for all modules. - source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " - b"repr(__loader__)])") + source = (b"_ = '::'.join([__name__, __file__, __package__, repr(__loader__)])") def __init__(self, path): self.path = path @@ -675,20 +585,17 @@ class SourceLoaderTestHarness: def verify_module(self, module): self.assertEqual(module.__name__, self.name) self.assertEqual(module.__file__, self.path) - self.assertEqual(module.__cached__, self.cached) self.assertEqual(module.__package__, self.package) self.assertEqual(module.__loader__, self.loader) values = module._.split('::') self.assertEqual(values[0], self.name) self.assertEqual(values[1], self.path) - self.assertEqual(values[2], self.cached) - self.assertEqual(values[3], self.package) - self.assertEqual(values[4], repr(self.loader)) + self.assertEqual(values[2], self.package) + self.assertEqual(values[3], repr(self.loader)) def verify_code(self, code_object): module = types.ModuleType(self.name) module.__file__ = self.path - module.__cached__ = self.cached module.__package__ = self.package module.__loader__ = self.loader module.__path__ = [] @@ -729,34 +636,6 @@ class SourceOnlyLoaderTests(SourceLoaderTestHarness): code = self.loader.source_to_code(self.loader.source, self.path) self.verify_code(code) - def test_load_module(self): - # Loading a module should set __name__, __loader__, __package__, - # __path__ (for packages), __file__, and __cached__. - # The module should also be put into sys.modules. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - with test_util.uncache(self.name): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertEqual(module.__path__, [os.path.dirname(self.path)]) - self.assertIn(self.name, sys.modules) - - def test_package_settings(self): - # __package__ needs to be set, while __path__ is set on if the module - # is a package. - # Testing the values for a package are covered by test_load_module. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.setUp(is_package=False) - with test_util.uncache(self.name): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertNotHasAttr(module, '__path__') - def test_get_source_encoding(self): # Source is considered encoded in UTF-8 by default unless otherwise # specified by an encoding line. @@ -904,7 +783,7 @@ class SourceLoaderGetSourceTests: mock = self.SourceOnlyLoaderMock('mod.file') source = "x = 42\r\ny = -13\r\n" mock.source = source.encode('utf-8') - expect = io.IncrementalNewlineDecoder(None, True).decode(source) + expect = io.StringIO(source, newline=None).getvalue() self.assertEqual(mock.get_source(name), expect) diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 1bc531a2fe3..4de0cf029a8 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -235,7 +235,6 @@ class ReloadTests: expected = {'__name__': name, '__package__': '', '__file__': path, - '__cached__': cached, '__doc__': None, } os_helper.create_empty_file(path) @@ -256,7 +255,6 @@ class ReloadTests: expected = {'__name__': name, '__package__': name, '__file__': init_path, - '__cached__': cached, '__path__': [os.path.dirname(init_path)], '__doc__': None, } @@ -316,7 +314,6 @@ class ReloadTests: expected = {'__name__': name, '__package__': name, '__file__': init_path, - '__cached__': cached, '__path__': [os.path.dirname(init_path)], '__doc__': None, 'eggs': None, diff --git a/Lib/test/test_importlib/test_lazy.py b/Lib/test/test_importlib/test_lazy.py index e48fad8898f..c6b26ad75b9 100644 --- a/Lib/test/test_importlib/test_lazy.py +++ b/Lib/test/test_importlib/test_lazy.py @@ -10,6 +10,9 @@ import unittest from test.support import threading_helper from test.test_importlib import util as test_util +# Make sure sys.modules[util] is in sync with the import. +# That is needed as other tests may reload util. +sys.modules['importlib.util'] = util class CollectInit: @@ -192,7 +195,7 @@ class LazyLoaderTests(unittest.TestCase): sys.modules['json'] = module loader.exec_module(module) - # Trigger load with attribute lookup, ensure expected behavior + # Trigger load with attribute lookup, ensure expected behavior. test_load = module.loads('{}') self.assertEqual(test_load, {}) @@ -224,6 +227,26 @@ sys.modules[__name__].__class__ = ImmutableModule with self.assertRaises(AttributeError): del module.CONSTANT + def test_reload(self): + # Reloading a lazy module that hasn't been materialized is a no-op. + module = self.new_module() + sys.modules[TestingImporter.module_name] = module + + # Change the source code to add a new attribute. + TestingImporter.source_code = 'attr = 42\nnew_attr = 123\n__name__ = {!r}'.format(TestingImporter.mutated_name) + self.assertIsInstance(module, util._LazyModule) + + # Reload the module (should be a no-op since not materialized). + reloaded = importlib.reload(module) + self.assertIs(reloaded, module) + self.assertIsInstance(module, util._LazyModule) + + # Access the new attribute (should trigger materialization, and new_attr should exist). + self.assertEqual(module.attr, 42) + self.assertNotIsInstance(module, util._LazyModule) + self.assertTrue(hasattr(module, 'new_attr')) + self.assertEqual(module.new_attr, 123) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/test_namespace_pkgs.py b/Lib/test/test_importlib/test_namespace_pkgs.py index 6ca0978f9bc..522ed9fa43f 100644 --- a/Lib/test/test_importlib/test_namespace_pkgs.py +++ b/Lib/test/test_importlib/test_namespace_pkgs.py @@ -318,6 +318,17 @@ class ModuleAndNamespacePackageInSameDir(NamespacePackageTest): self.assertEqual(a_test.attr, 'in module') +class NamespaceSubpackageSameName(NamespacePackageTest): + paths = [''] + + def test_namespace_subpackage_shares_name_with_directory(self): + submodule_path = 'project4.foo' + with self.assertRaises(ModuleNotFoundError) as cm: + importlib.machinery.PathFinder.find_spec(submodule_path) + + self.assertEqual(cm.exception.name, 'project4') + + class ReloadTests(NamespacePackageTest): paths = ['portion1'] diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index aebeabaf83f..b48d0a101ca 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -287,20 +287,6 @@ class ModuleSpecMethodsTests: loaded = self.bootstrap._load(self.spec) self.assertNotIn(self.spec.name, sys.modules) - def test_load_legacy_attributes_immutable(self): - module = object() - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - class ImmutableLoader(TestLoader): - def load_module(self, name): - sys.modules[name] = module - return module - self.spec.loader = ImmutableLoader() - with CleanImport(self.spec.name): - loaded = self.bootstrap._load(self.spec) - - self.assertIs(sys.modules[self.spec.name], module) - # reload() def test_reload(self): @@ -350,7 +336,6 @@ class ModuleSpecMethodsTests: self.assertIs(loaded.__spec__, self.spec) self.assertNotHasAttr(loaded, '__path__') self.assertNotHasAttr(loaded, '__file__') - self.assertNotHasAttr(loaded, '__cached__') (Frozen_ModuleSpecMethodsTests, diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index a77ce234dee..17a211f10fa 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -124,12 +124,6 @@ class ModuleFromSpecTests: module = self.util.module_from_spec(spec) self.assertEqual(module.__file__, spec.origin) - def test___cached__(self): - spec = self.machinery.ModuleSpec('test', object()) - spec.cached = 'some/path' - spec.has_location = True - module = self.util.module_from_spec(spec) - self.assertEqual(module.__cached__, spec.cached) (Frozen_ModuleFromSpecTests, Source_ModuleFromSpecTests @@ -359,47 +353,12 @@ class PEP3147Tests: self.assertEqual(self.util.cache_from_source(path, optimization=''), expect) - def test_cache_from_source_debug_override(self): - # Given the path to a .py file, return the path to its PEP 3147/PEP 488 - # defined .pyc file (i.e. under __pycache__). - path = os.path.join('foo', 'bar', 'baz', 'qux.py') - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - self.assertEqual(self.util.cache_from_source(path, False), - self.util.cache_from_source(path, optimization=1)) - self.assertEqual(self.util.cache_from_source(path, True), - self.util.cache_from_source(path, optimization='')) - with warnings.catch_warnings(): - warnings.simplefilter('error') - with self.assertRaises(DeprecationWarning): - self.util.cache_from_source(path, False) - with self.assertRaises(DeprecationWarning): - self.util.cache_from_source(path, True) - def test_cache_from_source_cwd(self): path = 'foo.py' expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag)) self.assertEqual(self.util.cache_from_source(path, optimization=''), expect) - def test_cache_from_source_override(self): - # When debug_override is not None, it can be any true-ish or false-ish - # value. - path = os.path.join('foo', 'bar', 'baz.py') - # However if the bool-ishness can't be determined, the exception - # propagates. - class Bearish: - def __bool__(self): raise RuntimeError - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - self.assertEqual(self.util.cache_from_source(path, []), - self.util.cache_from_source(path, optimization=1)) - self.assertEqual(self.util.cache_from_source(path, [17]), - self.util.cache_from_source(path, optimization='')) - with self.assertRaises(RuntimeError): - self.util.cache_from_source('/foo/bar/baz.py', Bearish()) - - def test_cache_from_source_optimization_empty_string(self): # Setting 'optimization' to '' leads to no optimization tag (PEP 488). path = 'foo.py' @@ -788,31 +747,70 @@ class IncompatibleExtensionModuleRestrictionsTests(unittest.TestCase): self.run_with_own_gil(script) -class MiscTests(unittest.TestCase): - def test_atomic_write_should_notice_incomplete_writes(self): +class PatchAtomicWrites: + def __init__(self, truncate_at_length, never_complete=False): + self.truncate_at_length = truncate_at_length + self.never_complete = never_complete + self.seen_write = False + self._children = [] + + def __enter__(self): import _pyio oldwrite = os.write - seen_write = False - - truncate_at_length = 100 # Emulate an os.write that only writes partial data. def write(fd, data): - nonlocal seen_write - seen_write = True - return oldwrite(fd, data[:truncate_at_length]) + if self.seen_write and self.never_complete: + return None + self.seen_write = True + return oldwrite(fd, data[:self.truncate_at_length]) # Need to patch _io to be _pyio, so that io.FileIO is affected by the # os.write patch. - with (support.swap_attr(_bootstrap_external, '_io', _pyio), - support.swap_attr(os, 'write', write)): - with self.assertRaises(OSError): - # Make sure we write something longer than the point where we - # truncate. - content = b'x' * (truncate_at_length * 2) - _bootstrap_external._write_atomic(os_helper.TESTFN, content) - assert seen_write + self.children = [ + support.swap_attr(_bootstrap_external, '_io', _pyio), + support.swap_attr(os, 'write', write) + ] + for child in self.children: + child.__enter__() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + for child in self.children: + child.__exit__(exc_type, exc_val, exc_tb) + + +class MiscTests(unittest.TestCase): + + def test_atomic_write_retries_incomplete_writes(self): + truncate_at_length = 100 + length = truncate_at_length * 2 + + with PatchAtomicWrites(truncate_at_length=truncate_at_length) as cm: + # Make sure we write something longer than the point where we + # truncate. + content = b'x' * length + _bootstrap_external._write_atomic(os_helper.TESTFN, content) + self.assertTrue(cm.seen_write) + + self.assertEqual(os.stat(support.os_helper.TESTFN).st_size, length) + os.unlink(support.os_helper.TESTFN) + + def test_atomic_write_errors_if_unable_to_complete(self): + truncate_at_length = 100 + + with ( + PatchAtomicWrites( + truncate_at_length=truncate_at_length, never_complete=True, + ) as cm, + self.assertRaises(OSError) + ): + # Make sure we write something longer than the point where we + # truncate. + content = b'x' * (truncate_at_length * 2) + _bootstrap_external._write_atomic(os_helper.TESTFN, content) + self.assertTrue(cm.seen_write) with self.assertRaises(OSError): os.stat(support.os_helper.TESTFN) # Check that the file did not get written. diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index edbe78545a2..efbec667317 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -15,7 +15,8 @@ import sys import tempfile import types -_testsinglephase = import_helper.import_module("_testsinglephase") +# gh-116303: Skip test module dependent tests if test modules are unavailable +import_helper.import_module("_testmultiphase") BUILTINS = types.SimpleNamespace() diff --git a/Lib/test/test_inspect/inspect_fodder2.py b/Lib/test/test_inspect/inspect_fodder2.py index 1de283f672d..157e12167b5 100644 --- a/Lib/test/test_inspect/inspect_fodder2.py +++ b/Lib/test/test_inspect/inspect_fodder2.py @@ -388,4 +388,16 @@ def func383(): ) return ge385 +# line 391 +@decorator +# comment +def func394(): + return 395 + +# line 397 +@decorator + +def func400(): + return 401 + pass # end of file diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py new file mode 100644 index 00000000000..ea2481edf93 --- /dev/null +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -0,0 +1,39 @@ +from functools import cached_property + +# docstring in parent, inherited in child +class ParentInheritDoc: + @cached_property + def foo(self): + """docstring for foo defined in parent""" + +class ChildInheritDoc(ParentInheritDoc): + pass + +class ChildInheritDefineDoc(ParentInheritDoc): + @cached_property + def foo(self): + pass + +# Redefine foo as something other than cached_property +class ChildPropertyFoo(ParentInheritDoc): + @property + def foo(self): + """docstring for the property foo""" + +class ChildMethodFoo(ParentInheritDoc): + def foo(self): + """docstring for the method foo""" + +# docstring in child but not parent +class ParentNoDoc: + @cached_property + def foo(self): + pass + +class ChildNoDoc(ParentNoDoc): + pass + +class ChildDefineDoc(ParentNoDoc): + @cached_property + def foo(self): + """docstring for foo defined in child""" diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 88fa4b7460c..075e1802beb 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -46,6 +46,7 @@ from test import support from test.test_inspect import inspect_fodder as mod from test.test_inspect import inspect_fodder2 as mod2 +from test.test_inspect import inspect_fodder3 as mod3 from test.test_inspect import inspect_stringized_annotations from test.test_inspect import inspect_deferred_annotations @@ -688,10 +689,56 @@ class TestRetrievingSourceCode(GetSourceBase): self.assertEqual(inspect.getdoc(mod.FesteringGob.contradiction), 'The automatic gainsaying.') + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_getdoc_inherited_class_doc(self): + class A: + """Common base class""" + class B(A): + pass + + a = A() + self.assertEqual(inspect.getdoc(A), 'Common base class') + self.assertEqual(inspect.getdoc(A, inherit_class_doc=False), + 'Common base class') + self.assertEqual(inspect.getdoc(a), 'Common base class') + self.assertIsNone(inspect.getdoc(a, fallback_to_class_doc=False)) + a.__doc__ = 'Instance' + self.assertEqual(inspect.getdoc(a, fallback_to_class_doc=False), + 'Instance') + + b = B() + self.assertEqual(inspect.getdoc(B), 'Common base class') + self.assertIsNone(inspect.getdoc(B, inherit_class_doc=False)) + self.assertIsNone(inspect.getdoc(b)) + self.assertIsNone(inspect.getdoc(b, fallback_to_class_doc=False)) + b.__doc__ = 'Instance' + self.assertEqual(inspect.getdoc(b, fallback_to_class_doc=False), 'Instance') + + def test_getdoc_inherited_cached_property(self): + doc = inspect.getdoc(mod3.ParentInheritDoc.foo) + self.assertEqual(doc, 'docstring for foo defined in parent') + self.assertEqual(inspect.getdoc(mod3.ChildInheritDoc.foo), doc) + self.assertEqual(inspect.getdoc(mod3.ChildInheritDefineDoc.foo), doc) + + def test_getdoc_redefine_cached_property_as_other(self): + self.assertEqual(inspect.getdoc(mod3.ChildPropertyFoo.foo), + 'docstring for the property foo') + self.assertEqual(inspect.getdoc(mod3.ChildMethodFoo.foo), + 'docstring for the method foo') + + def test_getdoc_define_cached_property(self): + self.assertEqual(inspect.getdoc(mod3.ChildDefineDoc.foo), + 'docstring for foo defined in child') + + def test_getdoc_nodoc_inherited(self): + self.assertIsNone(inspect.getdoc(mod3.ChildNoDoc.foo)) + @unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings") def test_finddoc(self): finddoc = inspect._finddoc self.assertEqual(finddoc(int), int.__doc__) + self.assertIsNone(finddoc(int, search_in_class=False)) self.assertEqual(finddoc(int.to_bytes), int.to_bytes.__doc__) self.assertEqual(finddoc(int().to_bytes), int.to_bytes.__doc__) self.assertEqual(finddoc(int.from_bytes), int.from_bytes.__doc__) @@ -1223,6 +1270,10 @@ class TestBuggyCases(GetSourceBase): self.assertSourceEqual(next(mod2.ge377), 377, 380) self.assertSourceEqual(next(mod2.func383()), 385, 388) + def test_comment_or_empty_line_after_decorator(self): + self.assertSourceEqual(mod2.func394, 392, 395) + self.assertSourceEqual(mod2.func400, 398, 401) + class TestNoEOL(GetSourceBase): def setUp(self): @@ -1778,14 +1829,55 @@ class TestClassesAndFunctions(unittest.TestCase): class TestFormatAnnotation(unittest.TestCase): def test_typing_replacement(self): - from test.typinganndata.ann_module9 import ann, ann1 + from test.typinganndata.ann_module9 import A, ann, ann1 self.assertEqual(inspect.formatannotation(ann), 'List[str] | int') self.assertEqual(inspect.formatannotation(ann1), 'List[testModule.typing.A] | int') + self.assertEqual(inspect.formatannotation(A, 'testModule.typing'), 'A') + self.assertEqual(inspect.formatannotation(A, 'other'), 'testModule.typing.A') + self.assertEqual( + inspect.formatannotation(ann1, 'testModule.typing'), + 'List[testModule.typing.A] | int', + ) + def test_forwardref(self): fwdref = ForwardRef('fwdref') self.assertEqual(inspect.formatannotation(fwdref), 'fwdref') + def test_formatannotationrelativeto(self): + from test.typinganndata.ann_module9 import A, ann1 + + # Builtin types: + self.assertEqual( + inspect.formatannotationrelativeto(object)(type), + 'type', + ) + + # Custom types: + self.assertEqual( + inspect.formatannotationrelativeto(None)(A), + 'testModule.typing.A', + ) + + class B: ... + B.__module__ = 'testModule.typing' + + self.assertEqual( + inspect.formatannotationrelativeto(B)(A), + 'A', + ) + + self.assertEqual( + inspect.formatannotationrelativeto(object)(A), + 'testModule.typing.A', + ) + + # Not an instance of "type": + self.assertEqual( + inspect.formatannotationrelativeto(A)(ann1), + 'List[testModule.typing.A] | int', + ) + class TestIsMethodDescriptor(unittest.TestCase): @@ -4220,8 +4312,14 @@ class TestSignatureObject(unittest.TestCase): self.assertEqual(self.signature(C, follow_wrapped=False), varargs_signature) - self.assertEqual(self.signature(C.__new__, follow_wrapped=False), - varargs_signature) + if support.MISSING_C_DOCSTRINGS: + self.assertRaisesRegex( + ValueError, "no signature found", + self.signature, C.__new__, follow_wrapped=False, + ) + else: + self.assertEqual(self.signature(C.__new__, follow_wrapped=False), + varargs_signature) def test_signature_on_class_with_wrapped_new(self): with self.subTest('FunctionType'): @@ -6396,13 +6494,12 @@ class TestMain(unittest.TestCase): rc, out, err = assert_python_ok(*args, '-m', 'inspect', 'unittest', '--details') output = out.decode() - # Just a quick sanity check on the output + # Just a quick safety check on the output self.assertIn(module.__spec__.name, output) self.assertIn(module.__name__, output) self.assertIn(module.__spec__.origin, output) self.assertIn(module.__file__, output) self.assertIn(module.__spec__.cached, output) - self.assertIn(module.__cached__, output) self.assertEqual(err, b'') diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py index 7a7cb73f673..fa675f626cb 100644 --- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -778,6 +778,18 @@ class PyLongModuleTests(unittest.TestCase): a, b = divmod(n*3 + 1, n) assert a == 3 and b == 1 + @support.cpython_only # tests implementation details of CPython. + @unittest.skipUnless(_pylong, "_pylong module required") + def test_pylong_int_divmod_crash(self): + # Regression test for https://github.com/python/cpython/issues/142554. + bad_int_divmod = lambda a, b: (1,) + # 'k' chosen such that divmod(2**(2*k), 2**k) uses _pylong.int_divmod() + k = 10_000 + a, b = (1 << (2 * k)), (1 << k) + with mock.patch.object(_pylong, "int_divmod", wraps=bad_int_divmod): + msg = r"tuple of length 2 is required from int_divmod\(\)" + self.assertRaisesRegex(ValueError, msg, divmod, a, b) + def test_pylong_str_to_int(self): v1 = 1 << 100_000 s = str(v1) diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py index c2da7949a9b..13d23af5ace 100644 --- a/Lib/test/test_interpreters/test_api.py +++ b/Lib/test/test_interpreters/test_api.py @@ -1,6 +1,7 @@ import contextlib import os import pickle +import signal import sys from textwrap import dedent import threading @@ -11,6 +12,7 @@ from test import support from test.support import os_helper from test.support import script_helper from test.support import import_helper +from test.support.script_helper import assert_python_ok, spawn_python # Raise SkipTest if subinterpreters not supported. _interpreters = import_helper.import_module('_interpreters') from concurrent import interpreters @@ -418,6 +420,52 @@ class InterpreterObjectTests(TestBase): unpickled = pickle.loads(data) self.assertEqual(unpickled, interp) + @support.requires_subprocess() + @force_not_colorized + def test_cleanup_in_repl(self): + # GH-135729: Using a subinterpreter in the REPL would lead to an unraisable + # exception during finalization + repl = script_helper.spawn_python("-i") + script = b"""if True: + from concurrent import interpreters + interpreters.create() + exit()""" + stdout, stderr = repl.communicate(script) + self.assertIsNone(stderr) + self.assertIn(b"Interpreter.close()", stdout) + self.assertNotIn(b"Traceback", stdout) + + @support.requires_subprocess() + @unittest.skipIf(os.name == 'nt', "signals don't work well on windows") + def test_keyboard_interrupt_in_thread_running_interp(self): + import subprocess + source = f"""if True: + from concurrent import interpreters + from threading import Thread + + def test(): + import time + print('a', flush=True, end='') + time.sleep(10) + + interp = interpreters.create() + interp.call_in_thread(test) + """ + + with spawn_python("-c", source, stderr=subprocess.PIPE) as proc: + self.assertEqual(proc.stdout.read(1), b'a') + proc.send_signal(signal.SIGINT) + proc.stderr.flush() + error = proc.stderr.read() + self.assertIn(b"KeyboardInterrupt", error) + retcode = proc.wait() + # Sometimes we send the SIGINT after the subthread yields the GIL to + # the main thread, which results in the main thread getting the + # KeyboardInterrupt before finalization is reached. There's not + # any great way to protect against that, so we just allow a -2 + # return code as well. + self.assertIn(retcode, (0, -signal.SIGINT)) + class TestInterpreterIsRunning(TestBase): @@ -707,6 +755,68 @@ class TestInterpreterClose(TestBase): self.interp_exists(interpid)) + def test_remaining_threads(self): + r_interp, w_interp = self.pipe() + + FINISHED = b'F' + + # It's unlikely, but technically speaking, it's possible + # that the thread could've finished before interp.close() is + # reached, so this test might not properly exercise the case. + # However, it's quite unlikely and probably not worth bothering about. + interp = interpreters.create() + interp.exec(f"""if True: + import os + import threading + import time + + def task(): + time.sleep(1) + os.write({w_interp}, {FINISHED!r}) + + threads = (threading.Thread(target=task) for _ in range(3)) + for t in threads: + t.start() + """) + interp.close() + + self.assertEqual(os.read(r_interp, 1), FINISHED) + + def test_remaining_daemon_threads(self): + # Daemon threads leak reference by nature, because they hang threads + # without allowing them to do cleanup (i.e., release refs). + # To prevent that from messing up the refleak hunter and whatnot, we + # run this in a subprocess. + code = '''if True: + import _interpreters + import types + interp = _interpreters.create( + types.SimpleNamespace( + use_main_obmalloc=False, + allow_fork=False, + allow_exec=False, + allow_threads=True, + allow_daemon_threads=True, + check_multi_interp_extensions=True, + gil='own', + ) + ) + _interpreters.exec(interp, f"""if True: + import threading + import time + + def task(): + time.sleep(3) + + threads = (threading.Thread(target=task, daemon=True) for _ in range(3)) + for t in threads: + t.start() + """) + _interpreters.destroy(interp) + ''' + assert_python_ok('-c', code) + + class TestInterpreterPrepareMain(TestBase): def test_empty(self): @@ -815,7 +925,10 @@ class TestInterpreterExec(TestBase): spam.eggs() interp = interpreters.create() - interp.exec(script) + try: + interp.exec(script) + finally: + interp.close() """) stdout, stderr = self.assert_python_failure(scriptfile) @@ -824,7 +937,7 @@ class TestInterpreterExec(TestBase): # File "{interpreters.__file__}", line 179, in exec self.assertEqual(stderr, dedent(f"""\ Traceback (most recent call last): - File "{scriptfile}", line 9, in <module> + File "{scriptfile}", line 10, in <module> interp.exec(script) ~~~~~~~~~~~^^^^^^^^ {interpmod_line.strip()} @@ -2204,6 +2317,16 @@ class LowLevelTests(TestBase): whence = eval(text) self.assertEqual(whence, _interpreters.WHENCE_LEGACY_CAPI) + def test_contextvars_missing(self): + script = f""" + import contextvars + print(getattr(contextvars.Token, "MISSING", "'doesn't exist'")) + """ + + orig = _interpreters.create() + text = self.run_and_capture(orig, script) + self.assertEqual(text.strip(), "<Token.MISSING>") + def test_is_running(self): def check(interpid, expected): with self.assertRaisesRegex(InterpreterError, 'unrecognized'): diff --git a/Lib/test/test_interpreters/test_lifecycle.py b/Lib/test/test_interpreters/test_lifecycle.py index 15537ac6cc8..39c1441b67c 100644 --- a/Lib/test/test_interpreters/test_lifecycle.py +++ b/Lib/test/test_interpreters/test_lifecycle.py @@ -132,6 +132,7 @@ class StartupTests(TestBase): 'sub': sys.path[0], }}, indent=4), flush=True) """) + interp.close() ''' # <tmp>/ # pkg/ @@ -172,7 +173,10 @@ class FinalizationTests(TestBase): argv = [sys.executable, '-c', '''if True: from concurrent import interpreters interp = interpreters.create() - raise Exception + try: + raise Exception + finally: + interp.close() '''] proc = subprocess.run(argv, capture_output=True, text=True) self.assertIn('Traceback', proc.stderr) diff --git a/Lib/test/test_interpreters/test_queues.py b/Lib/test/test_interpreters/test_queues.py index 5451c6654ac..77334aea383 100644 --- a/Lib/test/test_interpreters/test_queues.py +++ b/Lib/test/test_interpreters/test_queues.py @@ -11,7 +11,7 @@ from concurrent import interpreters from concurrent.interpreters import _queues as queues, _crossinterp from .utils import _run_output, TestBase as _TestBase - +HUGE_TIMEOUT = 3600 REPLACE = _crossinterp._UNBOUND_CONSTANT_TO_FLAG[_crossinterp.UNBOUND] @@ -306,6 +306,8 @@ class TestQueueOps(TestBase): queue.put(None) with self.assertRaises(queues.QueueFull): queue.put(None, timeout=0.1) + with self.assertRaises(queues.QueueFull): + queue.put(None, HUGE_TIMEOUT, 0.1) queue.get() queue.put(None) @@ -315,6 +317,10 @@ class TestQueueOps(TestBase): queue.put_nowait(None) with self.assertRaises(queues.QueueFull): queue.put_nowait(None) + with self.assertRaises(queues.QueueFull): + queue.put(None, False) + with self.assertRaises(queues.QueueFull): + queue.put(None, False, timeout=HUGE_TIMEOUT) queue.get() queue.put_nowait(None) @@ -345,11 +351,17 @@ class TestQueueOps(TestBase): queue = queues.create() with self.assertRaises(queues.QueueEmpty): queue.get(timeout=0.1) + with self.assertRaises(queues.QueueEmpty): + queue.get(HUGE_TIMEOUT, 0.1) def test_get_nowait(self): queue = queues.create() with self.assertRaises(queues.QueueEmpty): queue.get_nowait() + with self.assertRaises(queues.QueueEmpty): + queue.get(False) + with self.assertRaises(queues.QueueEmpty): + queue.get(False, timeout=HUGE_TIMEOUT) def test_put_get_full_fallback(self): expected = list(range(20)) diff --git a/Lib/test/test_interpreters/test_stress.py b/Lib/test/test_interpreters/test_stress.py index e25e67a0d4f..6b40a536bd3 100644 --- a/Lib/test/test_interpreters/test_stress.py +++ b/Lib/test/test_interpreters/test_stress.py @@ -7,6 +7,7 @@ from test.support import threading_helper # Raise SkipTest if subinterpreters not supported. import_helper.import_module('_interpreters') from concurrent import interpreters +from concurrent.interpreters import InterpreterError from .utils import TestBase @@ -74,6 +75,14 @@ class StressTests(TestBase): start.set() support.gc_collect() + def test_create_interpreter_no_memory(self): + import _interpreters + _testcapi = import_helper.import_module("_testcapi") + + with self.assertRaises(InterpreterError): + _testcapi.set_nomemory(0, 1) + _interpreters.create() + if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py deleted file mode 100644 index 92be2763e5e..00000000000 --- a/Lib/test/test_io.py +++ /dev/null @@ -1,5080 +0,0 @@ -"""Unit tests for the io module.""" - -# Tests of io are scattered over the test suite: -# * test_bufio - tests file buffering -# * test_memoryio - tests BytesIO and StringIO -# * test_fileio - tests FileIO -# * test_file - tests the file interface -# * test_io - tests everything else in the io module -# * test_univnewlines - tests universal newline support -# * test_largefile - tests operations on a file greater than 2**32 bytes -# (only enabled with -ulargefile) -# * test_free_threading/test_io - tests thread safety of io objects - -################################################################################ -# ATTENTION TEST WRITERS!!! -################################################################################ -# When writing tests for io, it's important to test both the C and Python -# implementations. This is usually done by writing a base test that refers to -# the type it is testing as an attribute. Then it provides custom subclasses to -# test both implementations. This file has lots of examples. -################################################################################ - -import abc -import array -import errno -import locale -import os -import pickle -import random -import signal -import sys -import textwrap -import threading -import time -import unittest -import warnings -import weakref -from collections import deque, UserList -from itertools import cycle, count -from test import support -from test.support.script_helper import ( - assert_python_ok, assert_python_failure, run_python_until_end) -from test.support import ( - import_helper, is_apple, os_helper, threading_helper, warnings_helper, -) -from test.support.os_helper import FakePath - -import codecs -import io # C implementation of io -import _pyio as pyio # Python implementation of io - -try: - import ctypes -except ImportError: - def byteslike(*pos, **kw): - return array.array("b", bytes(*pos, **kw)) -else: - def byteslike(*pos, **kw): - """Create a bytes-like object having no string or sequence methods""" - data = bytes(*pos, **kw) - obj = EmptyStruct() - ctypes.resize(obj, len(data)) - memoryview(obj).cast("B")[:] = data - return obj - class EmptyStruct(ctypes.Structure): - pass - - -def _default_chunk_size(): - """Get the default TextIOWrapper chunk size""" - with open(__file__, "r", encoding="latin-1") as f: - return f._CHUNK_SIZE - -requires_alarm = unittest.skipUnless( - hasattr(signal, "alarm"), "test requires signal.alarm()" -) - - -class BadIndex: - def __index__(self): - 1/0 - -class MockRawIOWithoutRead: - """A RawIO implementation without read(), so as to exercise the default - RawIO.read() which calls readinto().""" - - def __init__(self, read_stack=()): - self._read_stack = list(read_stack) - self._write_stack = [] - self._reads = 0 - self._extraneous_reads = 0 - - def write(self, b): - self._write_stack.append(bytes(b)) - return len(b) - - def writable(self): - return True - - def fileno(self): - return 42 - - def readable(self): - return True - - def seekable(self): - return True - - def seek(self, pos, whence): - return 0 # wrong but we gotta return something - - def tell(self): - return 0 # same comment as above - - def readinto(self, buf): - self._reads += 1 - max_len = len(buf) - try: - data = self._read_stack[0] - except IndexError: - self._extraneous_reads += 1 - return 0 - if data is None: - del self._read_stack[0] - return None - n = len(data) - if len(data) <= max_len: - del self._read_stack[0] - buf[:n] = data - return n - else: - buf[:] = data[:max_len] - self._read_stack[0] = data[max_len:] - return max_len - - def truncate(self, pos=None): - return pos - -class CMockRawIOWithoutRead(MockRawIOWithoutRead, io.RawIOBase): - pass - -class PyMockRawIOWithoutRead(MockRawIOWithoutRead, pyio.RawIOBase): - pass - - -class MockRawIO(MockRawIOWithoutRead): - - def read(self, n=None): - self._reads += 1 - try: - return self._read_stack.pop(0) - except: - self._extraneous_reads += 1 - return b"" - -class CMockRawIO(MockRawIO, io.RawIOBase): - pass - -class PyMockRawIO(MockRawIO, pyio.RawIOBase): - pass - - -class MisbehavedRawIO(MockRawIO): - def write(self, b): - return super().write(b) * 2 - - def read(self, n=None): - return super().read(n) * 2 - - def seek(self, pos, whence): - return -123 - - def tell(self): - return -456 - - def readinto(self, buf): - super().readinto(buf) - return len(buf) * 5 - -class CMisbehavedRawIO(MisbehavedRawIO, io.RawIOBase): - pass - -class PyMisbehavedRawIO(MisbehavedRawIO, pyio.RawIOBase): - pass - - -class SlowFlushRawIO(MockRawIO): - def __init__(self): - super().__init__() - self.in_flush = threading.Event() - - def flush(self): - self.in_flush.set() - time.sleep(0.25) - -class CSlowFlushRawIO(SlowFlushRawIO, io.RawIOBase): - pass - -class PySlowFlushRawIO(SlowFlushRawIO, pyio.RawIOBase): - pass - - -class CloseFailureIO(MockRawIO): - closed = 0 - - def close(self): - if not self.closed: - self.closed = 1 - raise OSError - -class CCloseFailureIO(CloseFailureIO, io.RawIOBase): - pass - -class PyCloseFailureIO(CloseFailureIO, pyio.RawIOBase): - pass - - -class MockFileIO: - - def __init__(self, data): - self.read_history = [] - super().__init__(data) - - def read(self, n=None): - res = super().read(n) - self.read_history.append(None if res is None else len(res)) - return res - - def readinto(self, b): - res = super().readinto(b) - self.read_history.append(res) - return res - -class CMockFileIO(MockFileIO, io.BytesIO): - pass - -class PyMockFileIO(MockFileIO, pyio.BytesIO): - pass - - -class MockUnseekableIO: - def seekable(self): - return False - - def seek(self, *args): - raise self.UnsupportedOperation("not seekable") - - def tell(self, *args): - raise self.UnsupportedOperation("not seekable") - - def truncate(self, *args): - raise self.UnsupportedOperation("not seekable") - -class CMockUnseekableIO(MockUnseekableIO, io.BytesIO): - UnsupportedOperation = io.UnsupportedOperation - -class PyMockUnseekableIO(MockUnseekableIO, pyio.BytesIO): - UnsupportedOperation = pyio.UnsupportedOperation - - -class MockCharPseudoDevFileIO(MockFileIO): - # GH-95782 - # ftruncate() does not work on these special files (and CPython then raises - # appropriate exceptions), so truncate() does not have to be accounted for - # here. - def __init__(self, data): - super().__init__(data) - - def seek(self, *args): - return 0 - - def tell(self, *args): - return 0 - -class CMockCharPseudoDevFileIO(MockCharPseudoDevFileIO, io.BytesIO): - pass - -class PyMockCharPseudoDevFileIO(MockCharPseudoDevFileIO, pyio.BytesIO): - pass - - -class MockNonBlockWriterIO: - - def __init__(self): - self._write_stack = [] - self._blocker_char = None - - def pop_written(self): - s = b"".join(self._write_stack) - self._write_stack[:] = [] - return s - - def block_on(self, char): - """Block when a given char is encountered.""" - self._blocker_char = char - - def readable(self): - return True - - def seekable(self): - return True - - def seek(self, pos, whence=0): - # naive implementation, enough for tests - return 0 - - def writable(self): - return True - - def write(self, b): - b = bytes(b) - n = -1 - if self._blocker_char: - try: - n = b.index(self._blocker_char) - except ValueError: - pass - else: - if n > 0: - # write data up to the first blocker - self._write_stack.append(b[:n]) - return n - else: - # cancel blocker and indicate would block - self._blocker_char = None - return None - self._write_stack.append(b) - return len(b) - -class CMockNonBlockWriterIO(MockNonBlockWriterIO, io.RawIOBase): - BlockingIOError = io.BlockingIOError - -class PyMockNonBlockWriterIO(MockNonBlockWriterIO, pyio.RawIOBase): - BlockingIOError = pyio.BlockingIOError - - -class IOTest(unittest.TestCase): - - def setUp(self): - os_helper.unlink(os_helper.TESTFN) - - def tearDown(self): - os_helper.unlink(os_helper.TESTFN) - - def write_ops(self, f): - self.assertEqual(f.write(b"blah."), 5) - f.truncate(0) - self.assertEqual(f.tell(), 5) - f.seek(0) - - self.assertEqual(f.write(b"blah."), 5) - self.assertEqual(f.seek(0), 0) - self.assertEqual(f.write(b"Hello."), 6) - self.assertEqual(f.tell(), 6) - self.assertEqual(f.seek(-1, 1), 5) - self.assertEqual(f.tell(), 5) - buffer = bytearray(b" world\n\n\n") - self.assertEqual(f.write(buffer), 9) - buffer[:] = b"*" * 9 # Overwrite our copy of the data - self.assertEqual(f.seek(0), 0) - self.assertEqual(f.write(b"h"), 1) - self.assertEqual(f.seek(-1, 2), 13) - self.assertEqual(f.tell(), 13) - - self.assertEqual(f.truncate(12), 12) - self.assertEqual(f.tell(), 13) - self.assertRaises(TypeError, f.seek, 0.0) - - def read_ops(self, f, buffered=False): - data = f.read(5) - self.assertEqual(data, b"hello") - data = byteslike(data) - self.assertEqual(f.readinto(data), 5) - self.assertEqual(bytes(data), b" worl") - data = bytearray(5) - self.assertEqual(f.readinto(data), 2) - self.assertEqual(len(data), 5) - self.assertEqual(data[:2], b"d\n") - self.assertEqual(f.seek(0), 0) - self.assertEqual(f.read(20), b"hello world\n") - self.assertEqual(f.read(1), b"") - self.assertEqual(f.readinto(byteslike(b"x")), 0) - self.assertEqual(f.seek(-6, 2), 6) - self.assertEqual(f.read(5), b"world") - self.assertEqual(f.read(0), b"") - self.assertEqual(f.readinto(byteslike()), 0) - self.assertEqual(f.seek(-6, 1), 5) - self.assertEqual(f.read(5), b" worl") - self.assertEqual(f.tell(), 10) - self.assertRaises(TypeError, f.seek, 0.0) - if buffered: - f.seek(0) - self.assertEqual(f.read(), b"hello world\n") - f.seek(6) - self.assertEqual(f.read(), b"world\n") - self.assertEqual(f.read(), b"") - f.seek(0) - data = byteslike(5) - self.assertEqual(f.readinto1(data), 5) - self.assertEqual(bytes(data), b"hello") - - LARGE = 2**31 - - def large_file_ops(self, f): - assert f.readable() - assert f.writable() - try: - self.assertEqual(f.seek(self.LARGE), self.LARGE) - except (OverflowError, ValueError): - self.skipTest("no largefile support") - self.assertEqual(f.tell(), self.LARGE) - self.assertEqual(f.write(b"xxx"), 3) - self.assertEqual(f.tell(), self.LARGE + 3) - self.assertEqual(f.seek(-1, 1), self.LARGE + 2) - self.assertEqual(f.truncate(), self.LARGE + 2) - self.assertEqual(f.tell(), self.LARGE + 2) - self.assertEqual(f.seek(0, 2), self.LARGE + 2) - self.assertEqual(f.truncate(self.LARGE + 1), self.LARGE + 1) - self.assertEqual(f.tell(), self.LARGE + 2) - self.assertEqual(f.seek(0, 2), self.LARGE + 1) - self.assertEqual(f.seek(-1, 2), self.LARGE) - self.assertEqual(f.read(2), b"x") - - def test_invalid_operations(self): - # Try writing on a file opened in read mode and vice-versa. - exc = self.UnsupportedOperation - with self.open(os_helper.TESTFN, "w", encoding="utf-8") as fp: - self.assertRaises(exc, fp.read) - self.assertRaises(exc, fp.readline) - with self.open(os_helper.TESTFN, "wb") as fp: - self.assertRaises(exc, fp.read) - self.assertRaises(exc, fp.readline) - with self.open(os_helper.TESTFN, "wb", buffering=0) as fp: - self.assertRaises(exc, fp.read) - self.assertRaises(exc, fp.readline) - with self.open(os_helper.TESTFN, "rb", buffering=0) as fp: - self.assertRaises(exc, fp.write, b"blah") - self.assertRaises(exc, fp.writelines, [b"blah\n"]) - with self.open(os_helper.TESTFN, "rb") as fp: - self.assertRaises(exc, fp.write, b"blah") - self.assertRaises(exc, fp.writelines, [b"blah\n"]) - with self.open(os_helper.TESTFN, "r", encoding="utf-8") as fp: - self.assertRaises(exc, fp.write, "blah") - self.assertRaises(exc, fp.writelines, ["blah\n"]) - # Non-zero seeking from current or end pos - self.assertRaises(exc, fp.seek, 1, self.SEEK_CUR) - self.assertRaises(exc, fp.seek, -1, self.SEEK_END) - - @support.cpython_only - def test_startup_optimization(self): - # gh-132952: Test that `io` is not imported at startup and that the - # __module__ of UnsupportedOperation is set to "io". - assert_python_ok("-S", "-c", textwrap.dedent( - """ - import sys - assert "io" not in sys.modules - try: - sys.stdin.truncate() - except Exception as e: - typ = type(e) - assert typ.__module__ == "io", (typ, typ.__module__) - assert typ.__name__ == "UnsupportedOperation", (typ, typ.__name__) - else: - raise AssertionError("Expected UnsupportedOperation") - """ - )) - - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_optional_abilities(self): - # Test for OSError when optional APIs are not supported - # The purpose of this test is to try fileno(), reading, writing and - # seeking operations with various objects that indicate they do not - # support these operations. - - def pipe_reader(): - [r, w] = os.pipe() - os.close(w) # So that read() is harmless - return self.FileIO(r, "r") - - def pipe_writer(): - [r, w] = os.pipe() - self.addCleanup(os.close, r) - # Guarantee that we can write into the pipe without blocking - thread = threading.Thread(target=os.read, args=(r, 100)) - thread.start() - self.addCleanup(thread.join) - return self.FileIO(w, "w") - - def buffered_reader(): - return self.BufferedReader(self.MockUnseekableIO()) - - def buffered_writer(): - return self.BufferedWriter(self.MockUnseekableIO()) - - def buffered_random(): - return self.BufferedRandom(self.BytesIO()) - - def buffered_rw_pair(): - return self.BufferedRWPair(self.MockUnseekableIO(), - self.MockUnseekableIO()) - - def text_reader(): - class UnseekableReader(self.MockUnseekableIO): - writable = self.BufferedIOBase.writable - write = self.BufferedIOBase.write - return self.TextIOWrapper(UnseekableReader(), "ascii") - - def text_writer(): - class UnseekableWriter(self.MockUnseekableIO): - readable = self.BufferedIOBase.readable - read = self.BufferedIOBase.read - return self.TextIOWrapper(UnseekableWriter(), "ascii") - - tests = ( - (pipe_reader, "fr"), (pipe_writer, "fw"), - (buffered_reader, "r"), (buffered_writer, "w"), - (buffered_random, "rws"), (buffered_rw_pair, "rw"), - (text_reader, "r"), (text_writer, "w"), - (self.BytesIO, "rws"), (self.StringIO, "rws"), - ) - - def do_test(test, obj, abilities): - readable = "r" in abilities - self.assertEqual(obj.readable(), readable) - writable = "w" in abilities - self.assertEqual(obj.writable(), writable) - - if isinstance(obj, self.TextIOBase): - data = "3" - elif isinstance(obj, (self.BufferedIOBase, self.RawIOBase)): - data = b"3" - else: - self.fail("Unknown base class") - - if "f" in abilities: - obj.fileno() - else: - self.assertRaises(OSError, obj.fileno) - - if readable: - obj.read(1) - obj.read() - else: - self.assertRaises(OSError, obj.read, 1) - self.assertRaises(OSError, obj.read) - - if writable: - obj.write(data) - else: - self.assertRaises(OSError, obj.write, data) - - if sys.platform.startswith("win") and test in ( - pipe_reader, pipe_writer): - # Pipes seem to appear as seekable on Windows - return - seekable = "s" in abilities - self.assertEqual(obj.seekable(), seekable) - - if seekable: - obj.tell() - obj.seek(0) - else: - self.assertRaises(OSError, obj.tell) - self.assertRaises(OSError, obj.seek, 0) - - if writable and seekable: - obj.truncate() - obj.truncate(0) - else: - self.assertRaises(OSError, obj.truncate) - self.assertRaises(OSError, obj.truncate, 0) - - for [test, abilities] in tests: - with self.subTest(test): - if test == pipe_writer and not threading_helper.can_start_thread: - self.skipTest("Need threads") - with test() as obj: - do_test(test, obj, abilities) - - - def test_open_handles_NUL_chars(self): - fn_with_NUL = 'foo\0bar' - self.assertRaises(ValueError, self.open, fn_with_NUL, 'w', encoding="utf-8") - - bytes_fn = bytes(fn_with_NUL, 'ascii') - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - self.assertRaises(ValueError, self.open, bytes_fn, 'w', encoding="utf-8") - - def test_raw_file_io(self): - with self.open(os_helper.TESTFN, "wb", buffering=0) as f: - self.assertEqual(f.readable(), False) - self.assertEqual(f.writable(), True) - self.assertEqual(f.seekable(), True) - self.write_ops(f) - with self.open(os_helper.TESTFN, "rb", buffering=0) as f: - self.assertEqual(f.readable(), True) - self.assertEqual(f.writable(), False) - self.assertEqual(f.seekable(), True) - self.read_ops(f) - - def test_buffered_file_io(self): - with self.open(os_helper.TESTFN, "wb") as f: - self.assertEqual(f.readable(), False) - self.assertEqual(f.writable(), True) - self.assertEqual(f.seekable(), True) - self.write_ops(f) - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.readable(), True) - self.assertEqual(f.writable(), False) - self.assertEqual(f.seekable(), True) - self.read_ops(f, True) - - def test_readline(self): - with self.open(os_helper.TESTFN, "wb") as f: - f.write(b"abc\ndef\nxyzzy\nfoo\x00bar\nanother line") - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.readline(), b"abc\n") - self.assertEqual(f.readline(10), b"def\n") - self.assertEqual(f.readline(2), b"xy") - self.assertEqual(f.readline(4), b"zzy\n") - self.assertEqual(f.readline(), b"foo\x00bar\n") - self.assertEqual(f.readline(None), b"another line") - self.assertRaises(TypeError, f.readline, 5.3) - with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: - self.assertRaises(TypeError, f.readline, 5.3) - - def test_readline_nonsizeable(self): - # Issue #30061 - # Crash when readline() returns an object without __len__ - class R(self.IOBase): - def readline(self): - return None - self.assertRaises((TypeError, StopIteration), next, R()) - - def test_next_nonsizeable(self): - # Issue #30061 - # Crash when __next__() returns an object without __len__ - class R(self.IOBase): - def __next__(self): - return None - self.assertRaises(TypeError, R().readlines, 1) - - def test_raw_bytes_io(self): - f = self.BytesIO() - self.write_ops(f) - data = f.getvalue() - self.assertEqual(data, b"hello world\n") - f = self.BytesIO(data) - self.read_ops(f, True) - - def test_large_file_ops(self): - # On Windows and Apple platforms this test consumes large resources; It - # takes a long time to build the >2 GiB file and takes >2 GiB of disk - # space therefore the resource must be enabled to run this test. - if sys.platform[:3] == 'win' or is_apple: - support.requires( - 'largefile', - 'test requires %s bytes and a long time to run' % self.LARGE) - with self.open(os_helper.TESTFN, "w+b", 0) as f: - self.large_file_ops(f) - with self.open(os_helper.TESTFN, "w+b") as f: - self.large_file_ops(f) - - def test_with_open(self): - for bufsize in (0, 100): - with self.open(os_helper.TESTFN, "wb", bufsize) as f: - f.write(b"xxx") - self.assertEqual(f.closed, True) - try: - with self.open(os_helper.TESTFN, "wb", bufsize) as f: - 1/0 - except ZeroDivisionError: - self.assertEqual(f.closed, True) - else: - self.fail("1/0 didn't raise an exception") - - # issue 5008 - def test_append_mode_tell(self): - with self.open(os_helper.TESTFN, "wb") as f: - f.write(b"xxx") - with self.open(os_helper.TESTFN, "ab", buffering=0) as f: - self.assertEqual(f.tell(), 3) - with self.open(os_helper.TESTFN, "ab") as f: - self.assertEqual(f.tell(), 3) - with self.open(os_helper.TESTFN, "a", encoding="utf-8") as f: - self.assertGreater(f.tell(), 0) - - def test_destructor(self): - record = [] - class MyFileIO(self.FileIO): - def __del__(self): - record.append(1) - try: - f = super().__del__ - except AttributeError: - pass - else: - f() - def close(self): - record.append(2) - super().close() - def flush(self): - record.append(3) - super().flush() - with warnings_helper.check_warnings(('', ResourceWarning)): - f = MyFileIO(os_helper.TESTFN, "wb") - f.write(b"xxx") - del f - support.gc_collect() - self.assertEqual(record, [1, 2, 3]) - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.read(), b"xxx") - - def _check_base_destructor(self, base): - record = [] - class MyIO(base): - def __init__(self): - # This exercises the availability of attributes on object - # destruction. - # (in the C version, close() is called by the tp_dealloc - # function, not by __del__) - self.on_del = 1 - self.on_close = 2 - self.on_flush = 3 - def __del__(self): - record.append(self.on_del) - try: - f = super().__del__ - except AttributeError: - pass - else: - f() - def close(self): - record.append(self.on_close) - super().close() - def flush(self): - record.append(self.on_flush) - super().flush() - f = MyIO() - del f - support.gc_collect() - self.assertEqual(record, [1, 2, 3]) - - def test_IOBase_destructor(self): - self._check_base_destructor(self.IOBase) - - def test_RawIOBase_destructor(self): - self._check_base_destructor(self.RawIOBase) - - def test_BufferedIOBase_destructor(self): - self._check_base_destructor(self.BufferedIOBase) - - def test_TextIOBase_destructor(self): - self._check_base_destructor(self.TextIOBase) - - def test_close_flushes(self): - with self.open(os_helper.TESTFN, "wb") as f: - f.write(b"xxx") - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.read(), b"xxx") - - def test_array_writes(self): - a = array.array('i', range(10)) - n = len(a.tobytes()) - def check(f): - with f: - self.assertEqual(f.write(a), n) - f.writelines((a,)) - check(self.BytesIO()) - check(self.FileIO(os_helper.TESTFN, "w")) - check(self.BufferedWriter(self.MockRawIO())) - check(self.BufferedRandom(self.MockRawIO())) - check(self.BufferedRWPair(self.MockRawIO(), self.MockRawIO())) - - def test_closefd(self): - self.assertRaises(ValueError, self.open, os_helper.TESTFN, 'w', - encoding="utf-8", closefd=False) - - def test_read_closed(self): - with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: - f.write("egg\n") - with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: - file = self.open(f.fileno(), "r", encoding="utf-8", closefd=False) - self.assertEqual(file.read(), "egg\n") - file.seek(0) - file.close() - self.assertRaises(ValueError, file.read) - with self.open(os_helper.TESTFN, "rb") as f: - file = self.open(f.fileno(), "rb", closefd=False) - self.assertEqual(file.read()[:3], b"egg") - file.close() - self.assertRaises(ValueError, file.readinto, bytearray(1)) - - def test_no_closefd_with_filename(self): - # can't use closefd in combination with a file name - self.assertRaises(ValueError, self.open, os_helper.TESTFN, "r", - encoding="utf-8", closefd=False) - - def test_closefd_attr(self): - with self.open(os_helper.TESTFN, "wb") as f: - f.write(b"egg\n") - with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: - self.assertEqual(f.buffer.raw.closefd, True) - file = self.open(f.fileno(), "r", encoding="utf-8", closefd=False) - self.assertEqual(file.buffer.raw.closefd, False) - - def test_garbage_collection(self): - # FileIO objects are collected, and collecting them flushes - # all data to disk. - # - # Note that using warnings_helper.check_warnings() will keep the - # file alive due to the `source` argument to warn(). So, use - # catch_warnings() instead. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ResourceWarning) - f = self.FileIO(os_helper.TESTFN, "wb") - f.write(b"abcxxx") - f.f = f - wr = weakref.ref(f) - del f - support.gc_collect() - self.assertIsNone(wr(), wr) - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.read(), b"abcxxx") - - def test_unbounded_file(self): - # Issue #1174606: reading from an unbounded stream such as /dev/zero. - zero = "/dev/zero" - if not os.path.exists(zero): - self.skipTest("{0} does not exist".format(zero)) - if sys.maxsize > 0x7FFFFFFF: - self.skipTest("test can only run in a 32-bit address space") - if support.real_max_memuse < support._2G: - self.skipTest("test requires at least 2 GiB of memory") - with self.open(zero, "rb", buffering=0) as f: - self.assertRaises(OverflowError, f.read) - with self.open(zero, "rb") as f: - self.assertRaises(OverflowError, f.read) - with self.open(zero, "r") as f: - self.assertRaises(OverflowError, f.read) - - def check_flush_error_on_close(self, *args, **kwargs): - # Test that the file is closed despite failed flush - # and that flush() is called before file closed. - f = self.open(*args, **kwargs) - closed = [] - def bad_flush(): - closed[:] = [f.closed] - raise OSError() - f.flush = bad_flush - self.assertRaises(OSError, f.close) # exception not swallowed - self.assertTrue(f.closed) - self.assertTrue(closed) # flush() called - self.assertFalse(closed[0]) # flush() called before file closed - f.flush = lambda: None # break reference loop - - def test_flush_error_on_close(self): - # raw file - # Issue #5700: io.FileIO calls flush() after file closed - self.check_flush_error_on_close(os_helper.TESTFN, 'wb', buffering=0) - fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) - self.check_flush_error_on_close(fd, 'wb', buffering=0) - fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) - self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) - os.close(fd) - # buffered io - self.check_flush_error_on_close(os_helper.TESTFN, 'wb') - fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) - self.check_flush_error_on_close(fd, 'wb') - fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) - self.check_flush_error_on_close(fd, 'wb', closefd=False) - os.close(fd) - # text io - self.check_flush_error_on_close(os_helper.TESTFN, 'w', encoding="utf-8") - fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) - self.check_flush_error_on_close(fd, 'w', encoding="utf-8") - fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) - self.check_flush_error_on_close(fd, 'w', encoding="utf-8", closefd=False) - os.close(fd) - - def test_multi_close(self): - f = self.open(os_helper.TESTFN, "wb", buffering=0) - f.close() - f.close() - f.close() - self.assertRaises(ValueError, f.flush) - - def test_RawIOBase_read(self): - # Exercise the default limited RawIOBase.read(n) implementation (which - # calls readinto() internally). - rawio = self.MockRawIOWithoutRead((b"abc", b"d", None, b"efg", None)) - self.assertEqual(rawio.read(2), b"ab") - self.assertEqual(rawio.read(2), b"c") - self.assertEqual(rawio.read(2), b"d") - self.assertEqual(rawio.read(2), None) - self.assertEqual(rawio.read(2), b"ef") - self.assertEqual(rawio.read(2), b"g") - self.assertEqual(rawio.read(2), None) - self.assertEqual(rawio.read(2), b"") - - def test_types_have_dict(self): - test = ( - self.IOBase(), - self.RawIOBase(), - self.TextIOBase(), - self.StringIO(), - self.BytesIO() - ) - for obj in test: - self.assertHasAttr(obj, "__dict__") - - def test_opener(self): - with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: - f.write("egg\n") - fd = os.open(os_helper.TESTFN, os.O_RDONLY) - def opener(path, flags): - return fd - with self.open("non-existent", "r", encoding="utf-8", opener=opener) as f: - self.assertEqual(f.read(), "egg\n") - - def test_bad_opener_negative_1(self): - # Issue #27066. - def badopener(fname, flags): - return -1 - with self.assertRaises(ValueError) as cm: - self.open('non-existent', 'r', opener=badopener) - self.assertEqual(str(cm.exception), 'opener returned -1') - - def test_bad_opener_other_negative(self): - # Issue #27066. - def badopener(fname, flags): - return -2 - with self.assertRaises(ValueError) as cm: - self.open('non-existent', 'r', opener=badopener) - self.assertEqual(str(cm.exception), 'opener returned -2') - - def test_opener_invalid_fd(self): - # Check that OSError is raised with error code EBADF if the - # opener returns an invalid file descriptor (see gh-82212). - fd = os_helper.make_bad_fd() - with self.assertRaises(OSError) as cm: - self.open('foo', opener=lambda name, flags: fd) - self.assertEqual(cm.exception.errno, errno.EBADF) - - def test_fileio_closefd(self): - # Issue #4841 - with self.open(__file__, 'rb') as f1, \ - self.open(__file__, 'rb') as f2: - fileio = self.FileIO(f1.fileno(), closefd=False) - # .__init__() must not close f1 - fileio.__init__(f2.fileno(), closefd=False) - f1.readline() - # .close() must not close f2 - fileio.close() - f2.readline() - - def test_nonbuffered_textio(self): - with warnings_helper.check_no_resource_warning(self): - with self.assertRaises(ValueError): - self.open(os_helper.TESTFN, 'w', encoding="utf-8", buffering=0) - - def test_invalid_newline(self): - with warnings_helper.check_no_resource_warning(self): - with self.assertRaises(ValueError): - self.open(os_helper.TESTFN, 'w', encoding="utf-8", newline='invalid') - - def test_buffered_readinto_mixin(self): - # Test the implementation provided by BufferedIOBase - class Stream(self.BufferedIOBase): - def read(self, size): - return b"12345" - read1 = read - stream = Stream() - for method in ("readinto", "readinto1"): - with self.subTest(method): - buffer = byteslike(5) - self.assertEqual(getattr(stream, method)(buffer), 5) - self.assertEqual(bytes(buffer), b"12345") - - def test_fspath_support(self): - def check_path_succeeds(path): - with self.open(path, "w", encoding="utf-8") as f: - f.write("egg\n") - - with self.open(path, "r", encoding="utf-8") as f: - self.assertEqual(f.read(), "egg\n") - - check_path_succeeds(FakePath(os_helper.TESTFN)) - check_path_succeeds(FakePath(os.fsencode(os_helper.TESTFN))) - - with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: - bad_path = FakePath(f.fileno()) - with self.assertRaises(TypeError): - self.open(bad_path, 'w', encoding="utf-8") - - bad_path = FakePath(None) - with self.assertRaises(TypeError): - self.open(bad_path, 'w', encoding="utf-8") - - bad_path = FakePath(FloatingPointError) - with self.assertRaises(FloatingPointError): - self.open(bad_path, 'w', encoding="utf-8") - - # ensure that refcounting is correct with some error conditions - with self.assertRaisesRegex(ValueError, 'read/write/append mode'): - self.open(FakePath(os_helper.TESTFN), 'rwxa', encoding="utf-8") - - def test_RawIOBase_readall(self): - # Exercise the default unlimited RawIOBase.read() and readall() - # implementations. - rawio = self.MockRawIOWithoutRead((b"abc", b"d", b"efg")) - self.assertEqual(rawio.read(), b"abcdefg") - rawio = self.MockRawIOWithoutRead((b"abc", b"d", b"efg")) - self.assertEqual(rawio.readall(), b"abcdefg") - - def test_BufferedIOBase_readinto(self): - # Exercise the default BufferedIOBase.readinto() and readinto1() - # implementations (which call read() or read1() internally). - class Reader(self.BufferedIOBase): - def __init__(self, avail): - self.avail = avail - def read(self, size): - result = self.avail[:size] - self.avail = self.avail[size:] - return result - def read1(self, size): - """Returns no more than 5 bytes at once""" - return self.read(min(size, 5)) - tests = ( - # (test method, total data available, read buffer size, expected - # read size) - ("readinto", 10, 5, 5), - ("readinto", 10, 6, 6), # More than read1() can return - ("readinto", 5, 6, 5), # Buffer larger than total available - ("readinto", 6, 7, 6), - ("readinto", 10, 0, 0), # Empty buffer - ("readinto1", 10, 5, 5), # Result limited to single read1() call - ("readinto1", 10, 6, 5), # Buffer larger than read1() can return - ("readinto1", 5, 6, 5), # Buffer larger than total available - ("readinto1", 6, 7, 5), - ("readinto1", 10, 0, 0), # Empty buffer - ) - UNUSED_BYTE = 0x81 - for test in tests: - with self.subTest(test): - method, avail, request, result = test - reader = Reader(bytes(range(avail))) - buffer = bytearray((UNUSED_BYTE,) * request) - method = getattr(reader, method) - self.assertEqual(method(buffer), result) - self.assertEqual(len(buffer), request) - self.assertSequenceEqual(buffer[:result], range(result)) - unused = (UNUSED_BYTE,) * (request - result) - self.assertSequenceEqual(buffer[result:], unused) - self.assertEqual(len(reader.avail), avail - result) - - def test_close_assert(self): - class R(self.IOBase): - def __setattr__(self, name, value): - pass - def flush(self): - raise OSError() - f = R() - # This would cause an assertion failure. - self.assertRaises(OSError, f.close) - - # Silence destructor error - R.flush = lambda self: None - - @threading_helper.requires_working_threading() - def test_write_readline_races(self): - # gh-134908: Concurrent iteration over a file caused races - thread_count = 2 - write_count = 100 - read_count = 100 - - def writer(file, barrier): - barrier.wait() - for _ in range(write_count): - file.write("x") - - def reader(file, barrier): - barrier.wait() - for _ in range(read_count): - for line in file: - self.assertEqual(line, "") - - with self.open(os_helper.TESTFN, "w+") as f: - barrier = threading.Barrier(thread_count + 1) - reader = threading.Thread(target=reader, args=(f, barrier)) - writers = [threading.Thread(target=writer, args=(f, barrier)) - for _ in range(thread_count)] - with threading_helper.catch_threading_exception() as cm: - with threading_helper.start_threads(writers + [reader]): - pass - self.assertIsNone(cm.exc_type) - - self.assertEqual(os.stat(os_helper.TESTFN).st_size, - write_count * thread_count) - - -class CIOTest(IOTest): - - def test_IOBase_finalize(self): - # Issue #12149: segmentation fault on _PyIOBase_finalize when both a - # class which inherits IOBase and an object of this class are caught - # in a reference cycle and close() is already in the method cache. - class MyIO(self.IOBase): - def close(self): - pass - - # create an instance to populate the method cache - MyIO() - obj = MyIO() - obj.obj = obj - wr = weakref.ref(obj) - del MyIO - del obj - support.gc_collect() - self.assertIsNone(wr(), wr) - -@support.cpython_only -class TestIOCTypes(unittest.TestCase): - def setUp(self): - _io = import_helper.import_module("_io") - self.types = [ - _io.BufferedRWPair, - _io.BufferedRandom, - _io.BufferedReader, - _io.BufferedWriter, - _io.BytesIO, - _io.FileIO, - _io.IncrementalNewlineDecoder, - _io.StringIO, - _io.TextIOWrapper, - _io._BufferedIOBase, - _io._BytesIOBuffer, - _io._IOBase, - _io._RawIOBase, - _io._TextIOBase, - ] - if sys.platform == "win32": - self.types.append(_io._WindowsConsoleIO) - self._io = _io - - def test_immutable_types(self): - for tp in self.types: - with self.subTest(tp=tp): - with self.assertRaisesRegex(TypeError, "immutable"): - tp.foo = "bar" - - def test_class_hierarchy(self): - def check_subs(types, base): - for tp in types: - with self.subTest(tp=tp, base=base): - self.assertIsSubclass(tp, base) - - def recursive_check(d): - for k, v in d.items(): - if isinstance(v, dict): - recursive_check(v) - elif isinstance(v, set): - check_subs(v, k) - else: - self.fail("corrupt test dataset") - - _io = self._io - hierarchy = { - _io._IOBase: { - _io._BufferedIOBase: { - _io.BufferedRWPair, - _io.BufferedRandom, - _io.BufferedReader, - _io.BufferedWriter, - _io.BytesIO, - }, - _io._RawIOBase: { - _io.FileIO, - }, - _io._TextIOBase: { - _io.StringIO, - _io.TextIOWrapper, - }, - }, - } - if sys.platform == "win32": - hierarchy[_io._IOBase][_io._RawIOBase].add(_io._WindowsConsoleIO) - - recursive_check(hierarchy) - - def test_subclassing(self): - _io = self._io - dataset = {k: True for k in self.types} - dataset[_io._BytesIOBuffer] = False - - for tp, is_basetype in dataset.items(): - with self.subTest(tp=tp, is_basetype=is_basetype): - name = f"{tp.__name__}_subclass" - bases = (tp,) - if is_basetype: - _ = type(name, bases, {}) - else: - msg = "not an acceptable base type" - with self.assertRaisesRegex(TypeError, msg): - _ = type(name, bases, {}) - - def test_disallow_instantiation(self): - _io = self._io - support.check_disallow_instantiation(self, _io._BytesIOBuffer) - - def test_stringio_setstate(self): - # gh-127182: Calling __setstate__() with invalid arguments must not crash - obj = self._io.StringIO() - with self.assertRaisesRegex( - TypeError, - 'initial_value must be str or None, not int', - ): - obj.__setstate__((1, '', 0, {})) - - obj.__setstate__((None, '', 0, {})) # should not crash - self.assertEqual(obj.getvalue(), '') - - obj.__setstate__(('', '', 0, {})) - self.assertEqual(obj.getvalue(), '') - -class PyIOTest(IOTest): - pass - - -@support.cpython_only -class APIMismatchTest(unittest.TestCase): - - def test_RawIOBase_io_in_pyio_match(self): - """Test that pyio RawIOBase class has all c RawIOBase methods""" - mismatch = support.detect_api_mismatch(pyio.RawIOBase, io.RawIOBase, - ignore=('__weakref__', '__static_attributes__')) - self.assertEqual(mismatch, set(), msg='Python RawIOBase does not have all C RawIOBase methods') - - def test_RawIOBase_pyio_in_io_match(self): - """Test that c RawIOBase class has all pyio RawIOBase methods""" - mismatch = support.detect_api_mismatch(io.RawIOBase, pyio.RawIOBase) - self.assertEqual(mismatch, set(), msg='C RawIOBase does not have all Python RawIOBase methods') - - -class CommonBufferedTests: - # Tests common to BufferedReader, BufferedWriter and BufferedRandom - - def test_detach(self): - raw = self.MockRawIO() - buf = self.tp(raw) - self.assertIs(buf.detach(), raw) - self.assertRaises(ValueError, buf.detach) - - repr(buf) # Should still work - - def test_fileno(self): - rawio = self.MockRawIO() - bufio = self.tp(rawio) - - self.assertEqual(42, bufio.fileno()) - - def test_invalid_args(self): - rawio = self.MockRawIO() - bufio = self.tp(rawio) - # Invalid whence - self.assertRaises(ValueError, bufio.seek, 0, -1) - self.assertRaises(ValueError, bufio.seek, 0, 9) - - def test_override_destructor(self): - tp = self.tp - record = [] - class MyBufferedIO(tp): - def __del__(self): - record.append(1) - try: - f = super().__del__ - except AttributeError: - pass - else: - f() - def close(self): - record.append(2) - super().close() - def flush(self): - record.append(3) - super().flush() - rawio = self.MockRawIO() - bufio = MyBufferedIO(rawio) - del bufio - support.gc_collect() - self.assertEqual(record, [1, 2, 3]) - - def test_context_manager(self): - # Test usability as a context manager - rawio = self.MockRawIO() - bufio = self.tp(rawio) - def _with(): - with bufio: - pass - _with() - # bufio should now be closed, and using it a second time should raise - # a ValueError. - self.assertRaises(ValueError, _with) - - def test_error_through_destructor(self): - # Test that the exception state is not modified by a destructor, - # even if close() fails. - rawio = self.CloseFailureIO() - with support.catch_unraisable_exception() as cm: - with self.assertRaises(AttributeError): - self.tp(rawio).xyzzy - - self.assertEqual(cm.unraisable.exc_type, OSError) - - def test_repr(self): - raw = self.MockRawIO() - b = self.tp(raw) - clsname = r"(%s\.)?%s" % (self.tp.__module__, self.tp.__qualname__) - self.assertRegex(repr(b), "<%s>" % clsname) - raw.name = "dummy" - self.assertRegex(repr(b), "<%s name='dummy'>" % clsname) - raw.name = b"dummy" - self.assertRegex(repr(b), "<%s name=b'dummy'>" % clsname) - - def test_recursive_repr(self): - # Issue #25455 - raw = self.MockRawIO() - b = self.tp(raw) - with support.swap_attr(raw, 'name', b), support.infinite_recursion(25): - with self.assertRaises(RuntimeError): - repr(b) # Should not crash - - def test_flush_error_on_close(self): - # Test that buffered file is closed despite failed flush - # and that flush() is called before file closed. - raw = self.MockRawIO() - closed = [] - def bad_flush(): - closed[:] = [b.closed, raw.closed] - raise OSError() - raw.flush = bad_flush - b = self.tp(raw) - self.assertRaises(OSError, b.close) # exception not swallowed - self.assertTrue(b.closed) - self.assertTrue(raw.closed) - self.assertTrue(closed) # flush() called - self.assertFalse(closed[0]) # flush() called before file closed - self.assertFalse(closed[1]) - raw.flush = lambda: None # break reference loop - - def test_close_error_on_close(self): - raw = self.MockRawIO() - def bad_flush(): - raise OSError('flush') - def bad_close(): - raise OSError('close') - raw.close = bad_close - b = self.tp(raw) - b.flush = bad_flush - with self.assertRaises(OSError) as err: # exception not swallowed - b.close() - self.assertEqual(err.exception.args, ('close',)) - self.assertIsInstance(err.exception.__context__, OSError) - self.assertEqual(err.exception.__context__.args, ('flush',)) - self.assertFalse(b.closed) - - # Silence destructor error - raw.close = lambda: None - b.flush = lambda: None - - def test_nonnormalized_close_error_on_close(self): - # Issue #21677 - raw = self.MockRawIO() - def bad_flush(): - raise non_existing_flush - def bad_close(): - raise non_existing_close - raw.close = bad_close - b = self.tp(raw) - b.flush = bad_flush - with self.assertRaises(NameError) as err: # exception not swallowed - b.close() - self.assertIn('non_existing_close', str(err.exception)) - self.assertIsInstance(err.exception.__context__, NameError) - self.assertIn('non_existing_flush', str(err.exception.__context__)) - self.assertFalse(b.closed) - - # Silence destructor error - b.flush = lambda: None - raw.close = lambda: None - - def test_multi_close(self): - raw = self.MockRawIO() - b = self.tp(raw) - b.close() - b.close() - b.close() - self.assertRaises(ValueError, b.flush) - - def test_unseekable(self): - bufio = self.tp(self.MockUnseekableIO(b"A" * 10)) - self.assertRaises(self.UnsupportedOperation, bufio.tell) - self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) - - def test_readonly_attributes(self): - raw = self.MockRawIO() - buf = self.tp(raw) - x = self.MockRawIO() - with self.assertRaises(AttributeError): - buf.raw = x - - def test_pickling_subclass(self): - global MyBufferedIO - class MyBufferedIO(self.tp): - def __init__(self, raw, tag): - super().__init__(raw) - self.tag = tag - def __getstate__(self): - return self.tag, self.raw.getvalue() - def __setstate__(slf, state): - tag, value = state - slf.__init__(self.BytesIO(value), tag) - - raw = self.BytesIO(b'data') - buf = MyBufferedIO(raw, tag='ham') - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - with self.subTest(protocol=proto): - pickled = pickle.dumps(buf, proto) - newbuf = pickle.loads(pickled) - self.assertEqual(newbuf.raw.getvalue(), b'data') - self.assertEqual(newbuf.tag, 'ham') - del MyBufferedIO - - -class SizeofTest: - - @support.cpython_only - def test_sizeof(self): - bufsize1 = 4096 - bufsize2 = 8192 - rawio = self.MockRawIO() - bufio = self.tp(rawio, buffer_size=bufsize1) - size = sys.getsizeof(bufio) - bufsize1 - rawio = self.MockRawIO() - bufio = self.tp(rawio, buffer_size=bufsize2) - self.assertEqual(sys.getsizeof(bufio), size + bufsize2) - - @support.cpython_only - def test_buffer_freeing(self) : - bufsize = 4096 - rawio = self.MockRawIO() - bufio = self.tp(rawio, buffer_size=bufsize) - size = sys.getsizeof(bufio) - bufsize - bufio.close() - self.assertEqual(sys.getsizeof(bufio), size) - -class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): - read_mode = "rb" - - def test_constructor(self): - rawio = self.MockRawIO([b"abc"]) - bufio = self.tp(rawio) - bufio.__init__(rawio) - bufio.__init__(rawio, buffer_size=1024) - bufio.__init__(rawio, buffer_size=16) - self.assertEqual(b"abc", bufio.read()) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) - rawio = self.MockRawIO([b"abc"]) - bufio.__init__(rawio) - self.assertEqual(b"abc", bufio.read()) - - def test_uninitialized(self): - bufio = self.tp.__new__(self.tp) - del bufio - bufio = self.tp.__new__(self.tp) - self.assertRaisesRegex((ValueError, AttributeError), - 'uninitialized|has no attribute', - bufio.read, 0) - bufio.__init__(self.MockRawIO()) - self.assertEqual(bufio.read(0), b'') - - def test_read(self): - for arg in (None, 7): - rawio = self.MockRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - self.assertEqual(b"abcdefg", bufio.read(arg)) - # Invalid args - self.assertRaises(ValueError, bufio.read, -2) - - def test_read1(self): - rawio = self.MockRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - self.assertEqual(b"a", bufio.read(1)) - self.assertEqual(b"b", bufio.read1(1)) - self.assertEqual(rawio._reads, 1) - self.assertEqual(b"", bufio.read1(0)) - self.assertEqual(b"c", bufio.read1(100)) - self.assertEqual(rawio._reads, 1) - self.assertEqual(b"d", bufio.read1(100)) - self.assertEqual(rawio._reads, 2) - self.assertEqual(b"efg", bufio.read1(100)) - self.assertEqual(rawio._reads, 3) - self.assertEqual(b"", bufio.read1(100)) - self.assertEqual(rawio._reads, 4) - - def test_read1_arbitrary(self): - rawio = self.MockRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - self.assertEqual(b"a", bufio.read(1)) - self.assertEqual(b"bc", bufio.read1()) - self.assertEqual(b"d", bufio.read1()) - self.assertEqual(b"efg", bufio.read1(-1)) - self.assertEqual(rawio._reads, 3) - self.assertEqual(b"", bufio.read1()) - self.assertEqual(rawio._reads, 4) - - def test_readinto(self): - rawio = self.MockRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - b = bytearray(2) - self.assertEqual(bufio.readinto(b), 2) - self.assertEqual(b, b"ab") - self.assertEqual(bufio.readinto(b), 2) - self.assertEqual(b, b"cd") - self.assertEqual(bufio.readinto(b), 2) - self.assertEqual(b, b"ef") - self.assertEqual(bufio.readinto(b), 1) - self.assertEqual(b, b"gf") - self.assertEqual(bufio.readinto(b), 0) - self.assertEqual(b, b"gf") - rawio = self.MockRawIO((b"abc", None)) - bufio = self.tp(rawio) - self.assertEqual(bufio.readinto(b), 2) - self.assertEqual(b, b"ab") - self.assertEqual(bufio.readinto(b), 1) - self.assertEqual(b, b"cb") - - def test_readinto1(self): - buffer_size = 10 - rawio = self.MockRawIO((b"abc", b"de", b"fgh", b"jkl")) - bufio = self.tp(rawio, buffer_size=buffer_size) - b = bytearray(2) - self.assertEqual(bufio.peek(3), b'abc') - self.assertEqual(rawio._reads, 1) - self.assertEqual(bufio.readinto1(b), 2) - self.assertEqual(b, b"ab") - self.assertEqual(rawio._reads, 1) - self.assertEqual(bufio.readinto1(b), 1) - self.assertEqual(b[:1], b"c") - self.assertEqual(rawio._reads, 1) - self.assertEqual(bufio.readinto1(b), 2) - self.assertEqual(b, b"de") - self.assertEqual(rawio._reads, 2) - b = bytearray(2*buffer_size) - self.assertEqual(bufio.peek(3), b'fgh') - self.assertEqual(rawio._reads, 3) - self.assertEqual(bufio.readinto1(b), 6) - self.assertEqual(b[:6], b"fghjkl") - self.assertEqual(rawio._reads, 4) - - def test_readinto_array(self): - buffer_size = 60 - data = b"a" * 26 - rawio = self.MockRawIO((data,)) - bufio = self.tp(rawio, buffer_size=buffer_size) - - # Create an array with element size > 1 byte - b = array.array('i', b'x' * 32) - assert len(b) != 16 - - # Read into it. We should get as many *bytes* as we can fit into b - # (which is more than the number of elements) - n = bufio.readinto(b) - self.assertGreater(n, len(b)) - - # Check that old contents of b are preserved - bm = memoryview(b).cast('B') - self.assertLess(n, len(bm)) - self.assertEqual(bm[:n], data[:n]) - self.assertEqual(bm[n:], b'x' * (len(bm[n:]))) - - def test_readinto1_array(self): - buffer_size = 60 - data = b"a" * 26 - rawio = self.MockRawIO((data,)) - bufio = self.tp(rawio, buffer_size=buffer_size) - - # Create an array with element size > 1 byte - b = array.array('i', b'x' * 32) - assert len(b) != 16 - - # Read into it. We should get as many *bytes* as we can fit into b - # (which is more than the number of elements) - n = bufio.readinto1(b) - self.assertGreater(n, len(b)) - - # Check that old contents of b are preserved - bm = memoryview(b).cast('B') - self.assertLess(n, len(bm)) - self.assertEqual(bm[:n], data[:n]) - self.assertEqual(bm[n:], b'x' * (len(bm[n:]))) - - def test_readlines(self): - def bufio(): - rawio = self.MockRawIO((b"abc\n", b"d\n", b"ef")) - return self.tp(rawio) - self.assertEqual(bufio().readlines(), [b"abc\n", b"d\n", b"ef"]) - self.assertEqual(bufio().readlines(5), [b"abc\n", b"d\n"]) - self.assertEqual(bufio().readlines(None), [b"abc\n", b"d\n", b"ef"]) - - def test_buffering(self): - data = b"abcdefghi" - dlen = len(data) - - tests = [ - [ 100, [ 3, 1, 4, 8 ], [ dlen, 0 ] ], - [ 100, [ 3, 3, 3], [ dlen ] ], - [ 4, [ 1, 2, 4, 2 ], [ 4, 4, 1 ] ], - ] - - for bufsize, buf_read_sizes, raw_read_sizes in tests: - rawio = self.MockFileIO(data) - bufio = self.tp(rawio, buffer_size=bufsize) - pos = 0 - for nbytes in buf_read_sizes: - self.assertEqual(bufio.read(nbytes), data[pos:pos+nbytes]) - pos += nbytes - # this is mildly implementation-dependent - self.assertEqual(rawio.read_history, raw_read_sizes) - - def test_read_non_blocking(self): - # Inject some None's in there to simulate EWOULDBLOCK - rawio = self.MockRawIO((b"abc", b"d", None, b"efg", None, None, None)) - bufio = self.tp(rawio) - self.assertEqual(b"abcd", bufio.read(6)) - self.assertEqual(b"e", bufio.read(1)) - self.assertEqual(b"fg", bufio.read()) - self.assertEqual(b"", bufio.peek(1)) - self.assertIsNone(bufio.read()) - self.assertEqual(b"", bufio.read()) - - rawio = self.MockRawIO((b"a", None, None)) - self.assertEqual(b"a", rawio.readall()) - self.assertIsNone(rawio.readall()) - - def test_read_past_eof(self): - rawio = self.MockRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - - self.assertEqual(b"abcdefg", bufio.read(9000)) - - def test_read_all(self): - rawio = self.MockRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - - self.assertEqual(b"abcdefg", bufio.read()) - - @threading_helper.requires_working_threading() - @support.requires_resource('cpu') - def test_threads(self): - try: - # Write out many bytes with exactly the same number of 0's, - # 1's... 255's. This will help us check that concurrent reading - # doesn't duplicate or forget contents. - N = 1000 - l = list(range(256)) * N - random.shuffle(l) - s = bytes(bytearray(l)) - with self.open(os_helper.TESTFN, "wb") as f: - f.write(s) - with self.open(os_helper.TESTFN, self.read_mode, buffering=0) as raw: - bufio = self.tp(raw, 8) - errors = [] - results = [] - def f(): - try: - # Intra-buffer read then buffer-flushing read - for n in cycle([1, 19]): - s = bufio.read(n) - if not s: - break - # list.append() is atomic - results.append(s) - except Exception as e: - errors.append(e) - raise - threads = [threading.Thread(target=f) for x in range(20)] - with threading_helper.start_threads(threads): - time.sleep(0.02) # yield - self.assertFalse(errors, - "the following exceptions were caught: %r" % errors) - s = b''.join(results) - for i in range(256): - c = bytes(bytearray([i])) - self.assertEqual(s.count(c), N) - finally: - os_helper.unlink(os_helper.TESTFN) - - def test_unseekable(self): - bufio = self.tp(self.MockUnseekableIO(b"A" * 10)) - self.assertRaises(self.UnsupportedOperation, bufio.tell) - self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) - bufio.read(1) - self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) - self.assertRaises(self.UnsupportedOperation, bufio.tell) - - def test_misbehaved_io(self): - rawio = self.MisbehavedRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - self.assertRaises(OSError, bufio.seek, 0) - self.assertRaises(OSError, bufio.tell) - - # Silence destructor error - bufio.close = lambda: None - - def test_no_extraneous_read(self): - # Issue #9550; when the raw IO object has satisfied the read request, - # we should not issue any additional reads, otherwise it may block - # (e.g. socket). - bufsize = 16 - for n in (2, bufsize - 1, bufsize, bufsize + 1, bufsize * 2): - rawio = self.MockRawIO([b"x" * n]) - bufio = self.tp(rawio, bufsize) - self.assertEqual(bufio.read(n), b"x" * n) - # Simple case: one raw read is enough to satisfy the request. - self.assertEqual(rawio._extraneous_reads, 0, - "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) - # A more complex case where two raw reads are needed to satisfy - # the request. - rawio = self.MockRawIO([b"x" * (n - 1), b"x"]) - bufio = self.tp(rawio, bufsize) - self.assertEqual(bufio.read(n), b"x" * n) - self.assertEqual(rawio._extraneous_reads, 0, - "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) - - def test_read_on_closed(self): - # Issue #23796 - b = self.BufferedReader(self.BytesIO(b"12")) - b.read(1) - b.close() - with self.subTest('peek'): - self.assertRaises(ValueError, b.peek) - with self.subTest('read1'): - self.assertRaises(ValueError, b.read1, 1) - with self.subTest('read'): - self.assertRaises(ValueError, b.read) - with self.subTest('readinto'): - self.assertRaises(ValueError, b.readinto, bytearray()) - with self.subTest('readinto1'): - self.assertRaises(ValueError, b.readinto1, bytearray()) - with self.subTest('flush'): - self.assertRaises(ValueError, b.flush) - with self.subTest('truncate'): - self.assertRaises(ValueError, b.truncate) - with self.subTest('seek'): - self.assertRaises(ValueError, b.seek, 0) - - def test_truncate_on_read_only(self): - rawio = self.MockFileIO(b"abc") - bufio = self.tp(rawio) - self.assertFalse(bufio.writable()) - self.assertRaises(self.UnsupportedOperation, bufio.truncate) - self.assertRaises(self.UnsupportedOperation, bufio.truncate, 0) - - def test_tell_character_device_file(self): - # GH-95782 - # For the (former) bug in BufferedIO to manifest, the wrapped IO obj - # must be able to produce at least 2 bytes. - raw = self.MockCharPseudoDevFileIO(b"12") - buf = self.tp(raw) - self.assertEqual(buf.tell(), 0) - self.assertEqual(buf.read(1), b"1") - self.assertEqual(buf.tell(), 0) - - def test_seek_character_device_file(self): - raw = self.MockCharPseudoDevFileIO(b"12") - buf = self.tp(raw) - self.assertEqual(buf.seek(0, io.SEEK_CUR), 0) - self.assertEqual(buf.seek(1, io.SEEK_SET), 0) - self.assertEqual(buf.seek(0, io.SEEK_CUR), 0) - self.assertEqual(buf.read(1), b"1") - - # In the C implementation, tell() sets the BufferedIO's abs_pos to 0, - # which means that the next seek() could return a negative offset if it - # does not sanity-check: - self.assertEqual(buf.tell(), 0) - self.assertEqual(buf.seek(0, io.SEEK_CUR), 0) - - -class CBufferedReaderTest(BufferedReaderTest, SizeofTest): - tp = io.BufferedReader - - def test_initialization(self): - rawio = self.MockRawIO([b"abc"]) - bufio = self.tp(rawio) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) - self.assertRaises(ValueError, bufio.read) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) - self.assertRaises(ValueError, bufio.read) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) - self.assertRaises(ValueError, bufio.read) - - def test_misbehaved_io_read(self): - rawio = self.MisbehavedRawIO((b"abc", b"d", b"efg")) - bufio = self.tp(rawio) - # _pyio.BufferedReader seems to implement reading different, so that - # checking this is not so easy. - self.assertRaises(OSError, bufio.read, 10) - - def test_garbage_collection(self): - # C BufferedReader objects are collected. - # The Python version has __del__, so it ends into gc.garbage instead - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - # Note that using warnings_helper.check_warnings() will keep the - # file alive due to the `source` argument to warn(). So, use - # catch_warnings() instead. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ResourceWarning) - rawio = self.FileIO(os_helper.TESTFN, "w+b") - f = self.tp(rawio) - f.f = f - wr = weakref.ref(f) - del f - support.gc_collect() - self.assertIsNone(wr(), wr) - - def test_args_error(self): - # Issue #17275 - with self.assertRaisesRegex(TypeError, "BufferedReader"): - self.tp(self.BytesIO(), 1024, 1024, 1024) - - def test_bad_readinto_value(self): - rawio = self.tp(self.BytesIO(b"12")) - rawio.readinto = lambda buf: -1 - bufio = self.tp(rawio) - with self.assertRaises(OSError) as cm: - bufio.readline() - self.assertIsNone(cm.exception.__cause__) - - def test_bad_readinto_type(self): - rawio = self.tp(self.BytesIO(b"12")) - rawio.readinto = lambda buf: b'' - bufio = self.tp(rawio) - with self.assertRaises(OSError) as cm: - bufio.readline() - self.assertIsInstance(cm.exception.__cause__, TypeError) - - -class PyBufferedReaderTest(BufferedReaderTest): - tp = pyio.BufferedReader - - -class BufferedWriterTest(unittest.TestCase, CommonBufferedTests): - write_mode = "wb" - - def test_constructor(self): - rawio = self.MockRawIO() - bufio = self.tp(rawio) - bufio.__init__(rawio) - bufio.__init__(rawio, buffer_size=1024) - bufio.__init__(rawio, buffer_size=16) - self.assertEqual(3, bufio.write(b"abc")) - bufio.flush() - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) - bufio.__init__(rawio) - self.assertEqual(3, bufio.write(b"ghi")) - bufio.flush() - self.assertEqual(b"".join(rawio._write_stack), b"abcghi") - - def test_uninitialized(self): - bufio = self.tp.__new__(self.tp) - del bufio - bufio = self.tp.__new__(self.tp) - self.assertRaisesRegex((ValueError, AttributeError), - 'uninitialized|has no attribute', - bufio.write, b'') - bufio.__init__(self.MockRawIO()) - self.assertEqual(bufio.write(b''), 0) - - def test_detach_flush(self): - raw = self.MockRawIO() - buf = self.tp(raw) - buf.write(b"howdy!") - self.assertFalse(raw._write_stack) - buf.detach() - self.assertEqual(raw._write_stack, [b"howdy!"]) - - def test_write(self): - # Write to the buffered IO but don't overflow the buffer. - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - bufio.write(b"abc") - self.assertFalse(writer._write_stack) - buffer = bytearray(b"def") - bufio.write(buffer) - buffer[:] = b"***" # Overwrite our copy of the data - bufio.flush() - self.assertEqual(b"".join(writer._write_stack), b"abcdef") - - def test_write_overflow(self): - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - contents = b"abcdefghijklmnop" - for n in range(0, len(contents), 3): - bufio.write(contents[n:n+3]) - flushed = b"".join(writer._write_stack) - # At least (total - 8) bytes were implicitly flushed, perhaps more - # depending on the implementation. - self.assertStartsWith(flushed, contents[:-8]) - - def check_writes(self, intermediate_func): - # Lots of writes, test the flushed output is as expected. - contents = bytes(range(256)) * 1000 - n = 0 - writer = self.MockRawIO() - bufio = self.tp(writer, 13) - # Generator of write sizes: repeat each N 15 times then proceed to N+1 - def gen_sizes(): - for size in count(1): - for i in range(15): - yield size - sizes = gen_sizes() - while n < len(contents): - size = min(next(sizes), len(contents) - n) - self.assertEqual(bufio.write(contents[n:n+size]), size) - intermediate_func(bufio) - n += size - bufio.flush() - self.assertEqual(contents, b"".join(writer._write_stack)) - - def test_writes(self): - self.check_writes(lambda bufio: None) - - def test_writes_and_flushes(self): - self.check_writes(lambda bufio: bufio.flush()) - - def test_writes_and_seeks(self): - def _seekabs(bufio): - pos = bufio.tell() - bufio.seek(pos + 1, 0) - bufio.seek(pos - 1, 0) - bufio.seek(pos, 0) - self.check_writes(_seekabs) - def _seekrel(bufio): - pos = bufio.seek(0, 1) - bufio.seek(+1, 1) - bufio.seek(-1, 1) - bufio.seek(pos, 0) - self.check_writes(_seekrel) - - def test_writes_and_truncates(self): - self.check_writes(lambda bufio: bufio.truncate(bufio.tell())) - - def test_write_non_blocking(self): - raw = self.MockNonBlockWriterIO() - bufio = self.tp(raw, 8) - - self.assertEqual(bufio.write(b"abcd"), 4) - self.assertEqual(bufio.write(b"efghi"), 5) - # 1 byte will be written, the rest will be buffered - raw.block_on(b"k") - self.assertEqual(bufio.write(b"jklmn"), 5) - - # 8 bytes will be written, 8 will be buffered and the rest will be lost - raw.block_on(b"0") - try: - bufio.write(b"opqrwxyz0123456789") - except self.BlockingIOError as e: - written = e.characters_written - else: - self.fail("BlockingIOError should have been raised") - self.assertEqual(written, 16) - self.assertEqual(raw.pop_written(), - b"abcdefghijklmnopqrwxyz") - - self.assertEqual(bufio.write(b"ABCDEFGHI"), 9) - s = raw.pop_written() - # Previously buffered bytes were flushed - self.assertStartsWith(s, b"01234567A") - - def test_write_and_rewind(self): - raw = self.BytesIO() - bufio = self.tp(raw, 4) - self.assertEqual(bufio.write(b"abcdef"), 6) - self.assertEqual(bufio.tell(), 6) - bufio.seek(0, 0) - self.assertEqual(bufio.write(b"XY"), 2) - bufio.seek(6, 0) - self.assertEqual(raw.getvalue(), b"XYcdef") - self.assertEqual(bufio.write(b"123456"), 6) - bufio.flush() - self.assertEqual(raw.getvalue(), b"XYcdef123456") - - def test_flush(self): - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - bufio.write(b"abc") - bufio.flush() - self.assertEqual(b"abc", writer._write_stack[0]) - - def test_writelines(self): - l = [b'ab', b'cd', b'ef'] - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - bufio.writelines(l) - bufio.flush() - self.assertEqual(b''.join(writer._write_stack), b'abcdef') - - def test_writelines_userlist(self): - l = UserList([b'ab', b'cd', b'ef']) - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - bufio.writelines(l) - bufio.flush() - self.assertEqual(b''.join(writer._write_stack), b'abcdef') - - def test_writelines_error(self): - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - self.assertRaises(TypeError, bufio.writelines, [1, 2, 3]) - self.assertRaises(TypeError, bufio.writelines, None) - self.assertRaises(TypeError, bufio.writelines, 'abc') - - def test_destructor(self): - writer = self.MockRawIO() - bufio = self.tp(writer, 8) - bufio.write(b"abc") - del bufio - support.gc_collect() - self.assertEqual(b"abc", writer._write_stack[0]) - - def test_truncate(self): - # Truncate implicitly flushes the buffer. - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - with self.open(os_helper.TESTFN, self.write_mode, buffering=0) as raw: - bufio = self.tp(raw, 8) - bufio.write(b"abcdef") - self.assertEqual(bufio.truncate(3), 3) - self.assertEqual(bufio.tell(), 6) - with self.open(os_helper.TESTFN, "rb", buffering=0) as f: - self.assertEqual(f.read(), b"abc") - - def test_truncate_after_write(self): - # Ensure that truncate preserves the file position after - # writes longer than the buffer size. - # Issue: https://bugs.python.org/issue32228 - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - with self.open(os_helper.TESTFN, "wb") as f: - # Fill with some buffer - f.write(b'\x00' * 10000) - buffer_sizes = [8192, 4096, 200] - for buffer_size in buffer_sizes: - with self.open(os_helper.TESTFN, "r+b", buffering=buffer_size) as f: - f.write(b'\x00' * (buffer_size + 1)) - # After write write_pos and write_end are set to 0 - f.read(1) - # read operation makes sure that pos != raw_pos - f.truncate() - self.assertEqual(f.tell(), buffer_size + 2) - - @threading_helper.requires_working_threading() - @support.requires_resource('cpu') - def test_threads(self): - try: - # Write out many bytes from many threads and test they were - # all flushed. - N = 1000 - contents = bytes(range(256)) * N - sizes = cycle([1, 19]) - n = 0 - queue = deque() - while n < len(contents): - size = next(sizes) - queue.append(contents[n:n+size]) - n += size - del contents - # We use a real file object because it allows us to - # exercise situations where the GIL is released before - # writing the buffer to the raw streams. This is in addition - # to concurrency issues due to switching threads in the middle - # of Python code. - with self.open(os_helper.TESTFN, self.write_mode, buffering=0) as raw: - bufio = self.tp(raw, 8) - errors = [] - def f(): - try: - while True: - try: - s = queue.popleft() - except IndexError: - return - bufio.write(s) - except Exception as e: - errors.append(e) - raise - threads = [threading.Thread(target=f) for x in range(20)] - with threading_helper.start_threads(threads): - time.sleep(0.02) # yield - self.assertFalse(errors, - "the following exceptions were caught: %r" % errors) - bufio.close() - with self.open(os_helper.TESTFN, "rb") as f: - s = f.read() - for i in range(256): - self.assertEqual(s.count(bytes([i])), N) - finally: - os_helper.unlink(os_helper.TESTFN) - - def test_misbehaved_io(self): - rawio = self.MisbehavedRawIO() - bufio = self.tp(rawio, 5) - self.assertRaises(OSError, bufio.seek, 0) - self.assertRaises(OSError, bufio.tell) - self.assertRaises(OSError, bufio.write, b"abcdef") - - # Silence destructor error - bufio.close = lambda: None - - def test_max_buffer_size_removal(self): - with self.assertRaises(TypeError): - self.tp(self.MockRawIO(), 8, 12) - - def test_write_error_on_close(self): - raw = self.MockRawIO() - def bad_write(b): - raise OSError() - raw.write = bad_write - b = self.tp(raw) - b.write(b'spam') - self.assertRaises(OSError, b.close) # exception not swallowed - self.assertTrue(b.closed) - - @threading_helper.requires_working_threading() - def test_slow_close_from_thread(self): - # Issue #31976 - rawio = self.SlowFlushRawIO() - bufio = self.tp(rawio, 8) - t = threading.Thread(target=bufio.close) - t.start() - rawio.in_flush.wait() - self.assertRaises(ValueError, bufio.write, b'spam') - self.assertTrue(bufio.closed) - t.join() - - - -class CBufferedWriterTest(BufferedWriterTest, SizeofTest): - tp = io.BufferedWriter - - def test_initialization(self): - rawio = self.MockRawIO() - bufio = self.tp(rawio) - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) - self.assertRaises(ValueError, bufio.write, b"def") - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) - self.assertRaises(ValueError, bufio.write, b"def") - self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) - self.assertRaises(ValueError, bufio.write, b"def") - - def test_garbage_collection(self): - # C BufferedWriter objects are collected, and collecting them flushes - # all data to disk. - # The Python version has __del__, so it ends into gc.garbage instead - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - # Note that using warnings_helper.check_warnings() will keep the - # file alive due to the `source` argument to warn(). So, use - # catch_warnings() instead. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ResourceWarning) - rawio = self.FileIO(os_helper.TESTFN, "w+b") - f = self.tp(rawio) - f.write(b"123xxx") - f.x = f - wr = weakref.ref(f) - del f - support.gc_collect() - self.assertIsNone(wr(), wr) - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.read(), b"123xxx") - - def test_args_error(self): - # Issue #17275 - with self.assertRaisesRegex(TypeError, "BufferedWriter"): - self.tp(self.BytesIO(), 1024, 1024, 1024) - - -class PyBufferedWriterTest(BufferedWriterTest): - tp = pyio.BufferedWriter - -class BufferedRWPairTest(unittest.TestCase): - - def test_constructor(self): - pair = self.tp(self.MockRawIO(), self.MockRawIO()) - self.assertFalse(pair.closed) - - def test_uninitialized(self): - pair = self.tp.__new__(self.tp) - del pair - pair = self.tp.__new__(self.tp) - self.assertRaisesRegex((ValueError, AttributeError), - 'uninitialized|has no attribute', - pair.read, 0) - self.assertRaisesRegex((ValueError, AttributeError), - 'uninitialized|has no attribute', - pair.write, b'') - pair.__init__(self.MockRawIO(), self.MockRawIO()) - self.assertEqual(pair.read(0), b'') - self.assertEqual(pair.write(b''), 0) - - def test_detach(self): - pair = self.tp(self.MockRawIO(), self.MockRawIO()) - self.assertRaises(self.UnsupportedOperation, pair.detach) - - def test_constructor_max_buffer_size_removal(self): - with self.assertRaises(TypeError): - self.tp(self.MockRawIO(), self.MockRawIO(), 8, 12) - - def test_constructor_with_not_readable(self): - class NotReadable(MockRawIO): - def readable(self): - return False - - self.assertRaises(OSError, self.tp, NotReadable(), self.MockRawIO()) - - def test_constructor_with_not_writeable(self): - class NotWriteable(MockRawIO): - def writable(self): - return False - - self.assertRaises(OSError, self.tp, self.MockRawIO(), NotWriteable()) - - def test_read(self): - pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) - - self.assertEqual(pair.read(3), b"abc") - self.assertEqual(pair.read(1), b"d") - self.assertEqual(pair.read(), b"ef") - pair = self.tp(self.BytesIO(b"abc"), self.MockRawIO()) - self.assertEqual(pair.read(None), b"abc") - - def test_readlines(self): - pair = lambda: self.tp(self.BytesIO(b"abc\ndef\nh"), self.MockRawIO()) - self.assertEqual(pair().readlines(), [b"abc\n", b"def\n", b"h"]) - self.assertEqual(pair().readlines(), [b"abc\n", b"def\n", b"h"]) - self.assertEqual(pair().readlines(5), [b"abc\n", b"def\n"]) - - def test_read1(self): - # .read1() is delegated to the underlying reader object, so this test - # can be shallow. - pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) - - self.assertEqual(pair.read1(3), b"abc") - self.assertEqual(pair.read1(), b"def") - - def test_readinto(self): - for method in ("readinto", "readinto1"): - with self.subTest(method): - pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) - - data = byteslike(b'\0' * 5) - self.assertEqual(getattr(pair, method)(data), 5) - self.assertEqual(bytes(data), b"abcde") - - def test_write(self): - w = self.MockRawIO() - pair = self.tp(self.MockRawIO(), w) - - pair.write(b"abc") - pair.flush() - buffer = bytearray(b"def") - pair.write(buffer) - buffer[:] = b"***" # Overwrite our copy of the data - pair.flush() - self.assertEqual(w._write_stack, [b"abc", b"def"]) - - def test_peek(self): - pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) - - self.assertStartsWith(pair.peek(3), b"abc") - self.assertEqual(pair.read(3), b"abc") - - def test_readable(self): - pair = self.tp(self.MockRawIO(), self.MockRawIO()) - self.assertTrue(pair.readable()) - - def test_writeable(self): - pair = self.tp(self.MockRawIO(), self.MockRawIO()) - self.assertTrue(pair.writable()) - - def test_seekable(self): - # BufferedRWPairs are never seekable, even if their readers and writers - # are. - pair = self.tp(self.MockRawIO(), self.MockRawIO()) - self.assertFalse(pair.seekable()) - - # .flush() is delegated to the underlying writer object and has been - # tested in the test_write method. - - def test_close_and_closed(self): - pair = self.tp(self.MockRawIO(), self.MockRawIO()) - self.assertFalse(pair.closed) - pair.close() - self.assertTrue(pair.closed) - - def test_reader_close_error_on_close(self): - def reader_close(): - reader_non_existing - reader = self.MockRawIO() - reader.close = reader_close - writer = self.MockRawIO() - pair = self.tp(reader, writer) - with self.assertRaises(NameError) as err: - pair.close() - self.assertIn('reader_non_existing', str(err.exception)) - self.assertTrue(pair.closed) - self.assertFalse(reader.closed) - self.assertTrue(writer.closed) - - # Silence destructor error - reader.close = lambda: None - - def test_writer_close_error_on_close(self): - def writer_close(): - writer_non_existing - reader = self.MockRawIO() - writer = self.MockRawIO() - writer.close = writer_close - pair = self.tp(reader, writer) - with self.assertRaises(NameError) as err: - pair.close() - self.assertIn('writer_non_existing', str(err.exception)) - self.assertFalse(pair.closed) - self.assertTrue(reader.closed) - self.assertFalse(writer.closed) - - # Silence destructor error - writer.close = lambda: None - writer = None - - # Ignore BufferedWriter (of the BufferedRWPair) unraisable exception - with support.catch_unraisable_exception(): - # Ignore BufferedRWPair unraisable exception - with support.catch_unraisable_exception(): - pair = None - support.gc_collect() - support.gc_collect() - - def test_reader_writer_close_error_on_close(self): - def reader_close(): - reader_non_existing - def writer_close(): - writer_non_existing - reader = self.MockRawIO() - reader.close = reader_close - writer = self.MockRawIO() - writer.close = writer_close - pair = self.tp(reader, writer) - with self.assertRaises(NameError) as err: - pair.close() - self.assertIn('reader_non_existing', str(err.exception)) - self.assertIsInstance(err.exception.__context__, NameError) - self.assertIn('writer_non_existing', str(err.exception.__context__)) - self.assertFalse(pair.closed) - self.assertFalse(reader.closed) - self.assertFalse(writer.closed) - - # Silence destructor error - reader.close = lambda: None - writer.close = lambda: None - - def test_isatty(self): - class SelectableIsAtty(MockRawIO): - def __init__(self, isatty): - MockRawIO.__init__(self) - self._isatty = isatty - - def isatty(self): - return self._isatty - - pair = self.tp(SelectableIsAtty(False), SelectableIsAtty(False)) - self.assertFalse(pair.isatty()) - - pair = self.tp(SelectableIsAtty(True), SelectableIsAtty(False)) - self.assertTrue(pair.isatty()) - - pair = self.tp(SelectableIsAtty(False), SelectableIsAtty(True)) - self.assertTrue(pair.isatty()) - - pair = self.tp(SelectableIsAtty(True), SelectableIsAtty(True)) - self.assertTrue(pair.isatty()) - - def test_weakref_clearing(self): - brw = self.tp(self.MockRawIO(), self.MockRawIO()) - ref = weakref.ref(brw) - brw = None - ref = None # Shouldn't segfault. - -class CBufferedRWPairTest(BufferedRWPairTest): - tp = io.BufferedRWPair - -class PyBufferedRWPairTest(BufferedRWPairTest): - tp = pyio.BufferedRWPair - - -class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest): - read_mode = "rb+" - write_mode = "wb+" - - def test_constructor(self): - BufferedReaderTest.test_constructor(self) - BufferedWriterTest.test_constructor(self) - - def test_uninitialized(self): - BufferedReaderTest.test_uninitialized(self) - BufferedWriterTest.test_uninitialized(self) - - def test_read_and_write(self): - raw = self.MockRawIO((b"asdf", b"ghjk")) - rw = self.tp(raw, 8) - - self.assertEqual(b"as", rw.read(2)) - rw.write(b"ddd") - rw.write(b"eee") - self.assertFalse(raw._write_stack) # Buffer writes - self.assertEqual(b"ghjk", rw.read()) - self.assertEqual(b"dddeee", raw._write_stack[0]) - - def test_seek_and_tell(self): - raw = self.BytesIO(b"asdfghjkl") - rw = self.tp(raw) - - self.assertEqual(b"as", rw.read(2)) - self.assertEqual(2, rw.tell()) - rw.seek(0, 0) - self.assertEqual(b"asdf", rw.read(4)) - - rw.write(b"123f") - rw.seek(0, 0) - self.assertEqual(b"asdf123fl", rw.read()) - self.assertEqual(9, rw.tell()) - rw.seek(-4, 2) - self.assertEqual(5, rw.tell()) - rw.seek(2, 1) - self.assertEqual(7, rw.tell()) - self.assertEqual(b"fl", rw.read(11)) - rw.flush() - self.assertEqual(b"asdf123fl", raw.getvalue()) - - self.assertRaises(TypeError, rw.seek, 0.0) - - def check_flush_and_read(self, read_func): - raw = self.BytesIO(b"abcdefghi") - bufio = self.tp(raw) - - self.assertEqual(b"ab", read_func(bufio, 2)) - bufio.write(b"12") - self.assertEqual(b"ef", read_func(bufio, 2)) - self.assertEqual(6, bufio.tell()) - bufio.flush() - self.assertEqual(6, bufio.tell()) - self.assertEqual(b"ghi", read_func(bufio)) - raw.seek(0, 0) - raw.write(b"XYZ") - # flush() resets the read buffer - bufio.flush() - bufio.seek(0, 0) - self.assertEqual(b"XYZ", read_func(bufio, 3)) - - def test_flush_and_read(self): - self.check_flush_and_read(lambda bufio, *args: bufio.read(*args)) - - def test_flush_and_readinto(self): - def _readinto(bufio, n=-1): - b = bytearray(n if n >= 0 else 9999) - n = bufio.readinto(b) - return bytes(b[:n]) - self.check_flush_and_read(_readinto) - - def test_flush_and_peek(self): - def _peek(bufio, n=-1): - # This relies on the fact that the buffer can contain the whole - # raw stream, otherwise peek() can return less. - b = bufio.peek(n) - if n != -1: - b = b[:n] - bufio.seek(len(b), 1) - return b - self.check_flush_and_read(_peek) - - def test_flush_and_write(self): - raw = self.BytesIO(b"abcdefghi") - bufio = self.tp(raw) - - bufio.write(b"123") - bufio.flush() - bufio.write(b"45") - bufio.flush() - bufio.seek(0, 0) - self.assertEqual(b"12345fghi", raw.getvalue()) - self.assertEqual(b"12345fghi", bufio.read()) - - def test_threads(self): - BufferedReaderTest.test_threads(self) - BufferedWriterTest.test_threads(self) - - def test_writes_and_peek(self): - def _peek(bufio): - bufio.peek(1) - self.check_writes(_peek) - def _peek(bufio): - pos = bufio.tell() - bufio.seek(-1, 1) - bufio.peek(1) - bufio.seek(pos, 0) - self.check_writes(_peek) - - def test_writes_and_reads(self): - def _read(bufio): - bufio.seek(-1, 1) - bufio.read(1) - self.check_writes(_read) - - def test_writes_and_read1s(self): - def _read1(bufio): - bufio.seek(-1, 1) - bufio.read1(1) - self.check_writes(_read1) - - def test_writes_and_readintos(self): - def _read(bufio): - bufio.seek(-1, 1) - bufio.readinto(bytearray(1)) - self.check_writes(_read) - - def test_write_after_readahead(self): - # Issue #6629: writing after the buffer was filled by readahead should - # first rewind the raw stream. - for overwrite_size in [1, 5]: - raw = self.BytesIO(b"A" * 10) - bufio = self.tp(raw, 4) - # Trigger readahead - self.assertEqual(bufio.read(1), b"A") - self.assertEqual(bufio.tell(), 1) - # Overwriting should rewind the raw stream if it needs so - bufio.write(b"B" * overwrite_size) - self.assertEqual(bufio.tell(), overwrite_size + 1) - # If the write size was smaller than the buffer size, flush() and - # check that rewind happens. - bufio.flush() - self.assertEqual(bufio.tell(), overwrite_size + 1) - s = raw.getvalue() - self.assertEqual(s, - b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) - - def test_write_rewind_write(self): - # Various combinations of reading / writing / seeking backwards / writing again - def mutate(bufio, pos1, pos2): - assert pos2 >= pos1 - # Fill the buffer - bufio.seek(pos1) - bufio.read(pos2 - pos1) - bufio.write(b'\x02') - # This writes earlier than the previous write, but still inside - # the buffer. - bufio.seek(pos1) - bufio.write(b'\x01') - - b = b"\x80\x81\x82\x83\x84" - for i in range(0, len(b)): - for j in range(i, len(b)): - raw = self.BytesIO(b) - bufio = self.tp(raw, 100) - mutate(bufio, i, j) - bufio.flush() - expected = bytearray(b) - expected[j] = 2 - expected[i] = 1 - self.assertEqual(raw.getvalue(), expected, - "failed result for i=%d, j=%d" % (i, j)) - - def test_truncate_after_read_or_write(self): - raw = self.BytesIO(b"A" * 10) - bufio = self.tp(raw, 100) - self.assertEqual(bufio.read(2), b"AA") # the read buffer gets filled - self.assertEqual(bufio.truncate(), 2) - self.assertEqual(bufio.write(b"BB"), 2) # the write buffer increases - self.assertEqual(bufio.truncate(), 4) - - def test_misbehaved_io(self): - BufferedReaderTest.test_misbehaved_io(self) - BufferedWriterTest.test_misbehaved_io(self) - - def test_interleaved_read_write(self): - # Test for issue #12213 - with self.BytesIO(b'abcdefgh') as raw: - with self.tp(raw, 100) as f: - f.write(b"1") - self.assertEqual(f.read(1), b'b') - f.write(b'2') - self.assertEqual(f.read1(1), b'd') - f.write(b'3') - buf = bytearray(1) - f.readinto(buf) - self.assertEqual(buf, b'f') - f.write(b'4') - self.assertEqual(f.peek(1), b'h') - f.flush() - self.assertEqual(raw.getvalue(), b'1b2d3f4h') - - with self.BytesIO(b'abc') as raw: - with self.tp(raw, 100) as f: - self.assertEqual(f.read(1), b'a') - f.write(b"2") - self.assertEqual(f.read(1), b'c') - f.flush() - self.assertEqual(raw.getvalue(), b'a2c') - - def test_read1_after_write(self): - with self.BytesIO(b'abcdef') as raw: - with self.tp(raw, 3) as f: - f.write(b"1") - self.assertEqual(f.read1(1), b'b') - f.flush() - self.assertEqual(raw.getvalue(), b'1bcdef') - with self.BytesIO(b'abcdef') as raw: - with self.tp(raw, 3) as f: - f.write(b"1") - self.assertEqual(f.read1(), b'bcd') - f.flush() - self.assertEqual(raw.getvalue(), b'1bcdef') - with self.BytesIO(b'abcdef') as raw: - with self.tp(raw, 3) as f: - f.write(b"1") - # XXX: read(100) returns different numbers of bytes - # in Python and C implementations. - self.assertEqual(f.read1(100)[:3], b'bcd') - f.flush() - self.assertEqual(raw.getvalue(), b'1bcdef') - - def test_interleaved_readline_write(self): - with self.BytesIO(b'ab\ncdef\ng\n') as raw: - with self.tp(raw) as f: - f.write(b'1') - self.assertEqual(f.readline(), b'b\n') - f.write(b'2') - self.assertEqual(f.readline(), b'def\n') - f.write(b'3') - self.assertEqual(f.readline(), b'\n') - f.flush() - self.assertEqual(raw.getvalue(), b'1b\n2def\n3\n') - - # You can't construct a BufferedRandom over a non-seekable stream. - test_unseekable = None - - # writable() returns True, so there's no point to test it over - # a writable stream. - test_truncate_on_read_only = None - - -class CBufferedRandomTest(BufferedRandomTest, SizeofTest): - tp = io.BufferedRandom - - def test_garbage_collection(self): - CBufferedReaderTest.test_garbage_collection(self) - CBufferedWriterTest.test_garbage_collection(self) - - def test_args_error(self): - # Issue #17275 - with self.assertRaisesRegex(TypeError, "BufferedRandom"): - self.tp(self.BytesIO(), 1024, 1024, 1024) - - -class PyBufferedRandomTest(BufferedRandomTest): - tp = pyio.BufferedRandom - - -# To fully exercise seek/tell, the StatefulIncrementalDecoder has these -# properties: -# - A single output character can correspond to many bytes of input. -# - The number of input bytes to complete the character can be -# undetermined until the last input byte is received. -# - The number of input bytes can vary depending on previous input. -# - A single input byte can correspond to many characters of output. -# - The number of output characters can be undetermined until the -# last input byte is received. -# - The number of output characters can vary depending on previous input. - -class StatefulIncrementalDecoder(codecs.IncrementalDecoder): - """ - For testing seek/tell behavior with a stateful, buffering decoder. - - Input is a sequence of words. Words may be fixed-length (length set - by input) or variable-length (period-terminated). In variable-length - mode, extra periods are ignored. Possible words are: - - 'i' followed by a number sets the input length, I (maximum 99). - When I is set to 0, words are space-terminated. - - 'o' followed by a number sets the output length, O (maximum 99). - - Any other word is converted into a word followed by a period on - the output. The output word consists of the input word truncated - or padded out with hyphens to make its length equal to O. If O - is 0, the word is output verbatim without truncating or padding. - I and O are initially set to 1. When I changes, any buffered input is - re-scanned according to the new I. EOF also terminates the last word. - """ - - def __init__(self, errors='strict'): - codecs.IncrementalDecoder.__init__(self, errors) - self.reset() - - def __repr__(self): - return '<SID %x>' % id(self) - - def reset(self): - self.i = 1 - self.o = 1 - self.buffer = bytearray() - - def getstate(self): - i, o = self.i ^ 1, self.o ^ 1 # so that flags = 0 after reset() - return bytes(self.buffer), i*100 + o - - def setstate(self, state): - buffer, io = state - self.buffer = bytearray(buffer) - i, o = divmod(io, 100) - self.i, self.o = i ^ 1, o ^ 1 - - def decode(self, input, final=False): - output = '' - for b in input: - if self.i == 0: # variable-length, terminated with period - if b == ord('.'): - if self.buffer: - output += self.process_word() - else: - self.buffer.append(b) - else: # fixed-length, terminate after self.i bytes - self.buffer.append(b) - if len(self.buffer) == self.i: - output += self.process_word() - if final and self.buffer: # EOF terminates the last word - output += self.process_word() - return output - - def process_word(self): - output = '' - if self.buffer[0] == ord('i'): - self.i = min(99, int(self.buffer[1:] or 0)) # set input length - elif self.buffer[0] == ord('o'): - self.o = min(99, int(self.buffer[1:] or 0)) # set output length - else: - output = self.buffer.decode('ascii') - if len(output) < self.o: - output += '-'*self.o # pad out with hyphens - if self.o: - output = output[:self.o] # truncate to output length - output += '.' - self.buffer = bytearray() - return output - - codecEnabled = False - - -# bpo-41919: This method is separated from StatefulIncrementalDecoder to avoid a resource leak -# when registering codecs and cleanup functions. -def lookupTestDecoder(name): - if StatefulIncrementalDecoder.codecEnabled and name == 'test_decoder': - latin1 = codecs.lookup('latin-1') - return codecs.CodecInfo( - name='test_decoder', encode=latin1.encode, decode=None, - incrementalencoder=None, - streamreader=None, streamwriter=None, - incrementaldecoder=StatefulIncrementalDecoder) - - -class StatefulIncrementalDecoderTest(unittest.TestCase): - """ - Make sure the StatefulIncrementalDecoder actually works. - """ - - test_cases = [ - # I=1, O=1 (fixed-length input == fixed-length output) - (b'abcd', False, 'a.b.c.d.'), - # I=0, O=0 (variable-length input, variable-length output) - (b'oiabcd', True, 'abcd.'), - # I=0, O=0 (should ignore extra periods) - (b'oi...abcd...', True, 'abcd.'), - # I=0, O=6 (variable-length input, fixed-length output) - (b'i.o6.x.xyz.toolongtofit.', False, 'x-----.xyz---.toolon.'), - # I=2, O=6 (fixed-length input < fixed-length output) - (b'i.i2.o6xyz', True, 'xy----.z-----.'), - # I=6, O=3 (fixed-length input > fixed-length output) - (b'i.o3.i6.abcdefghijklmnop', True, 'abc.ghi.mno.'), - # I=0, then 3; O=29, then 15 (with longer output) - (b'i.o29.a.b.cde.o15.abcdefghijabcdefghij.i3.a.b.c.d.ei00k.l.m', True, - 'a----------------------------.' + - 'b----------------------------.' + - 'cde--------------------------.' + - 'abcdefghijabcde.' + - 'a.b------------.' + - '.c.------------.' + - 'd.e------------.' + - 'k--------------.' + - 'l--------------.' + - 'm--------------.') - ] - - def test_decoder(self): - # Try a few one-shot test cases. - for input, eof, output in self.test_cases: - d = StatefulIncrementalDecoder() - self.assertEqual(d.decode(input, eof), output) - - # Also test an unfinished decode, followed by forcing EOF. - d = StatefulIncrementalDecoder() - self.assertEqual(d.decode(b'oiabcd'), '') - self.assertEqual(d.decode(b'', 1), 'abcd.') - -class TextIOWrapperTest(unittest.TestCase): - - def setUp(self): - self.testdata = b"AAA\r\nBBB\rCCC\r\nDDD\nEEE\r\n" - self.normalized = b"AAA\nBBB\nCCC\nDDD\nEEE\n".decode("ascii") - os_helper.unlink(os_helper.TESTFN) - codecs.register(lookupTestDecoder) - self.addCleanup(codecs.unregister, lookupTestDecoder) - - def tearDown(self): - os_helper.unlink(os_helper.TESTFN) - - def test_constructor(self): - r = self.BytesIO(b"\xc3\xa9\n\n") - b = self.BufferedReader(r, 1000) - t = self.TextIOWrapper(b, encoding="utf-8") - t.__init__(b, encoding="latin-1", newline="\r\n") - self.assertEqual(t.encoding, "latin-1") - self.assertEqual(t.line_buffering, False) - t.__init__(b, encoding="utf-8", line_buffering=True) - self.assertEqual(t.encoding, "utf-8") - self.assertEqual(t.line_buffering, True) - self.assertEqual("\xe9\n", t.readline()) - invalid_type = TypeError if self.is_C else ValueError - with self.assertRaises(invalid_type): - t.__init__(b, encoding=42) - with self.assertRaises(UnicodeEncodeError): - t.__init__(b, encoding='\udcfe') - with self.assertRaises(ValueError): - t.__init__(b, encoding='utf-8\0') - with self.assertRaises(invalid_type): - t.__init__(b, encoding="utf-8", errors=42) - if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: - with self.assertRaises(UnicodeEncodeError): - t.__init__(b, encoding="utf-8", errors='\udcfe') - if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: - with self.assertRaises(ValueError): - t.__init__(b, encoding="utf-8", errors='replace\0') - with self.assertRaises(TypeError): - t.__init__(b, encoding="utf-8", newline=42) - with self.assertRaises(ValueError): - t.__init__(b, encoding="utf-8", newline='\udcfe') - with self.assertRaises(ValueError): - t.__init__(b, encoding="utf-8", newline='\n\0') - with self.assertRaises(ValueError): - t.__init__(b, encoding="utf-8", newline='xyzzy') - - def test_uninitialized(self): - t = self.TextIOWrapper.__new__(self.TextIOWrapper) - del t - t = self.TextIOWrapper.__new__(self.TextIOWrapper) - self.assertRaises(Exception, repr, t) - self.assertRaisesRegex((ValueError, AttributeError), - 'uninitialized|has no attribute', - t.read, 0) - t.__init__(self.MockRawIO(), encoding="utf-8") - self.assertEqual(t.read(0), '') - - def test_non_text_encoding_codecs_are_rejected(self): - # Ensure the constructor complains if passed a codec that isn't - # marked as a text encoding - # http://bugs.python.org/issue20404 - r = self.BytesIO() - b = self.BufferedWriter(r) - with self.assertRaisesRegex(LookupError, "is not a text encoding"): - self.TextIOWrapper(b, encoding="hex") - - def test_detach(self): - r = self.BytesIO() - b = self.BufferedWriter(r) - t = self.TextIOWrapper(b, encoding="ascii") - self.assertIs(t.detach(), b) - - t = self.TextIOWrapper(b, encoding="ascii") - t.write("howdy") - self.assertFalse(r.getvalue()) - t.detach() - self.assertEqual(r.getvalue(), b"howdy") - self.assertRaises(ValueError, t.detach) - - # Operations independent of the detached stream should still work - repr(t) - self.assertEqual(t.encoding, "ascii") - self.assertEqual(t.errors, "strict") - self.assertFalse(t.line_buffering) - self.assertFalse(t.write_through) - - def test_repr(self): - raw = self.BytesIO("hello".encode("utf-8")) - b = self.BufferedReader(raw) - t = self.TextIOWrapper(b, encoding="utf-8") - modname = self.TextIOWrapper.__module__ - self.assertRegex(repr(t), - r"<(%s\.)?TextIOWrapper encoding='utf-8'>" % modname) - raw.name = "dummy" - self.assertRegex(repr(t), - r"<(%s\.)?TextIOWrapper name='dummy' encoding='utf-8'>" % modname) - t.mode = "r" - self.assertRegex(repr(t), - r"<(%s\.)?TextIOWrapper name='dummy' mode='r' encoding='utf-8'>" % modname) - raw.name = b"dummy" - self.assertRegex(repr(t), - r"<(%s\.)?TextIOWrapper name=b'dummy' mode='r' encoding='utf-8'>" % modname) - - t.buffer.detach() - repr(t) # Should not raise an exception - - def test_recursive_repr(self): - # Issue #25455 - raw = self.BytesIO() - t = self.TextIOWrapper(raw, encoding="utf-8") - with support.swap_attr(raw, 'name', t), support.infinite_recursion(25): - with self.assertRaises(RuntimeError): - repr(t) # Should not crash - - def test_subclass_repr(self): - class TestSubclass(self.TextIOWrapper): - pass - - f = TestSubclass(self.StringIO()) - self.assertIn(TestSubclass.__name__, repr(f)) - - def test_line_buffering(self): - r = self.BytesIO() - b = self.BufferedWriter(r, 1000) - t = self.TextIOWrapper(b, encoding="utf-8", newline="\n", line_buffering=True) - t.write("X") - self.assertEqual(r.getvalue(), b"") # No flush happened - t.write("Y\nZ") - self.assertEqual(r.getvalue(), b"XY\nZ") # All got flushed - t.write("A\rB") - self.assertEqual(r.getvalue(), b"XY\nZA\rB") - - def test_reconfigure_line_buffering(self): - r = self.BytesIO() - b = self.BufferedWriter(r, 1000) - t = self.TextIOWrapper(b, encoding="utf-8", newline="\n", line_buffering=False) - t.write("AB\nC") - self.assertEqual(r.getvalue(), b"") - - t.reconfigure(line_buffering=True) # implicit flush - self.assertEqual(r.getvalue(), b"AB\nC") - t.write("DEF\nG") - self.assertEqual(r.getvalue(), b"AB\nCDEF\nG") - t.write("H") - self.assertEqual(r.getvalue(), b"AB\nCDEF\nG") - t.reconfigure(line_buffering=False) # implicit flush - self.assertEqual(r.getvalue(), b"AB\nCDEF\nGH") - t.write("IJ") - self.assertEqual(r.getvalue(), b"AB\nCDEF\nGH") - - # Keeping default value - t.reconfigure() - t.reconfigure(line_buffering=None) - self.assertEqual(t.line_buffering, False) - t.reconfigure(line_buffering=True) - t.reconfigure() - t.reconfigure(line_buffering=None) - self.assertEqual(t.line_buffering, True) - - @unittest.skipIf(sys.flags.utf8_mode, "utf-8 mode is enabled") - def test_default_encoding(self): - with os_helper.EnvironmentVarGuard() as env: - # try to get a user preferred encoding different than the current - # locale encoding to check that TextIOWrapper() uses the current - # locale encoding and not the user preferred encoding - env.unset('LC_ALL', 'LANG', 'LC_CTYPE') - - current_locale_encoding = locale.getencoding() - b = self.BytesIO() - with warnings.catch_warnings(): - warnings.simplefilter("ignore", EncodingWarning) - t = self.TextIOWrapper(b) - self.assertEqual(t.encoding, current_locale_encoding) - - def test_encoding(self): - # Check the encoding attribute is always set, and valid - b = self.BytesIO() - t = self.TextIOWrapper(b, encoding="utf-8") - self.assertEqual(t.encoding, "utf-8") - with warnings.catch_warnings(): - warnings.simplefilter("ignore", EncodingWarning) - t = self.TextIOWrapper(b) - self.assertIsNotNone(t.encoding) - codecs.lookup(t.encoding) - - def test_encoding_errors_reading(self): - # (1) default - b = self.BytesIO(b"abc\n\xff\n") - t = self.TextIOWrapper(b, encoding="ascii") - self.assertRaises(UnicodeError, t.read) - # (2) explicit strict - b = self.BytesIO(b"abc\n\xff\n") - t = self.TextIOWrapper(b, encoding="ascii", errors="strict") - self.assertRaises(UnicodeError, t.read) - # (3) ignore - b = self.BytesIO(b"abc\n\xff\n") - t = self.TextIOWrapper(b, encoding="ascii", errors="ignore") - self.assertEqual(t.read(), "abc\n\n") - # (4) replace - b = self.BytesIO(b"abc\n\xff\n") - t = self.TextIOWrapper(b, encoding="ascii", errors="replace") - self.assertEqual(t.read(), "abc\n\ufffd\n") - - def test_encoding_errors_writing(self): - # (1) default - b = self.BytesIO() - t = self.TextIOWrapper(b, encoding="ascii") - self.assertRaises(UnicodeError, t.write, "\xff") - # (2) explicit strict - b = self.BytesIO() - t = self.TextIOWrapper(b, encoding="ascii", errors="strict") - self.assertRaises(UnicodeError, t.write, "\xff") - # (3) ignore - b = self.BytesIO() - t = self.TextIOWrapper(b, encoding="ascii", errors="ignore", - newline="\n") - t.write("abc\xffdef\n") - t.flush() - self.assertEqual(b.getvalue(), b"abcdef\n") - # (4) replace - b = self.BytesIO() - t = self.TextIOWrapper(b, encoding="ascii", errors="replace", - newline="\n") - t.write("abc\xffdef\n") - t.flush() - self.assertEqual(b.getvalue(), b"abc?def\n") - - def test_newlines(self): - input_lines = [ "unix\n", "windows\r\n", "os9\r", "last\n", "nonl" ] - - tests = [ - [ None, [ 'unix\n', 'windows\n', 'os9\n', 'last\n', 'nonl' ] ], - [ '', input_lines ], - [ '\n', [ "unix\n", "windows\r\n", "os9\rlast\n", "nonl" ] ], - [ '\r\n', [ "unix\nwindows\r\n", "os9\rlast\nnonl" ] ], - [ '\r', [ "unix\nwindows\r", "\nos9\r", "last\nnonl" ] ], - ] - encodings = ( - 'utf-8', 'latin-1', - 'utf-16', 'utf-16-le', 'utf-16-be', - 'utf-32', 'utf-32-le', 'utf-32-be', - ) - - # Try a range of buffer sizes to test the case where \r is the last - # character in TextIOWrapper._pending_line. - for encoding in encodings: - # XXX: str.encode() should return bytes - data = bytes(''.join(input_lines).encode(encoding)) - for do_reads in (False, True): - for bufsize in range(1, 10): - for newline, exp_lines in tests: - bufio = self.BufferedReader(self.BytesIO(data), bufsize) - textio = self.TextIOWrapper(bufio, newline=newline, - encoding=encoding) - if do_reads: - got_lines = [] - while True: - c2 = textio.read(2) - if c2 == '': - break - self.assertEqual(len(c2), 2) - got_lines.append(c2 + textio.readline()) - else: - got_lines = list(textio) - - for got_line, exp_line in zip(got_lines, exp_lines): - self.assertEqual(got_line, exp_line) - self.assertEqual(len(got_lines), len(exp_lines)) - - def test_newlines_input(self): - testdata = b"AAA\nBB\x00B\nCCC\rDDD\rEEE\r\nFFF\r\nGGG" - normalized = testdata.replace(b"\r\n", b"\n").replace(b"\r", b"\n") - for newline, expected in [ - (None, normalized.decode("ascii").splitlines(keepends=True)), - ("", testdata.decode("ascii").splitlines(keepends=True)), - ("\n", ["AAA\n", "BB\x00B\n", "CCC\rDDD\rEEE\r\n", "FFF\r\n", "GGG"]), - ("\r\n", ["AAA\nBB\x00B\nCCC\rDDD\rEEE\r\n", "FFF\r\n", "GGG"]), - ("\r", ["AAA\nBB\x00B\nCCC\r", "DDD\r", "EEE\r", "\nFFF\r", "\nGGG"]), - ]: - buf = self.BytesIO(testdata) - txt = self.TextIOWrapper(buf, encoding="ascii", newline=newline) - self.assertEqual(txt.readlines(), expected) - txt.seek(0) - self.assertEqual(txt.read(), "".join(expected)) - - def test_newlines_output(self): - testdict = { - "": b"AAA\nBBB\nCCC\nX\rY\r\nZ", - "\n": b"AAA\nBBB\nCCC\nX\rY\r\nZ", - "\r": b"AAA\rBBB\rCCC\rX\rY\r\rZ", - "\r\n": b"AAA\r\nBBB\r\nCCC\r\nX\rY\r\r\nZ", - } - tests = [(None, testdict[os.linesep])] + sorted(testdict.items()) - for newline, expected in tests: - buf = self.BytesIO() - txt = self.TextIOWrapper(buf, encoding="ascii", newline=newline) - txt.write("AAA\nB") - txt.write("BB\nCCC\n") - txt.write("X\rY\r\nZ") - txt.flush() - self.assertEqual(buf.closed, False) - self.assertEqual(buf.getvalue(), expected) - - def test_destructor(self): - l = [] - base = self.BytesIO - class MyBytesIO(base): - def close(self): - l.append(self.getvalue()) - base.close(self) - b = MyBytesIO() - t = self.TextIOWrapper(b, encoding="ascii") - t.write("abc") - del t - support.gc_collect() - self.assertEqual([b"abc"], l) - - def test_override_destructor(self): - record = [] - class MyTextIO(self.TextIOWrapper): - def __del__(self): - record.append(1) - try: - f = super().__del__ - except AttributeError: - pass - else: - f() - def close(self): - record.append(2) - super().close() - def flush(self): - record.append(3) - super().flush() - b = self.BytesIO() - t = MyTextIO(b, encoding="ascii") - del t - support.gc_collect() - self.assertEqual(record, [1, 2, 3]) - - def test_error_through_destructor(self): - # Test that the exception state is not modified by a destructor, - # even if close() fails. - rawio = self.CloseFailureIO() - with support.catch_unraisable_exception() as cm: - with self.assertRaises(AttributeError): - self.TextIOWrapper(rawio, encoding="utf-8").xyzzy - - self.assertEqual(cm.unraisable.exc_type, OSError) - - # Systematic tests of the text I/O API - - def test_basic_io(self): - for chunksize in (1, 2, 3, 4, 5, 15, 16, 17, 31, 32, 33, 63, 64, 65): - for enc in "ascii", "latin-1", "utf-8" :# , "utf-16-be", "utf-16-le": - f = self.open(os_helper.TESTFN, "w+", encoding=enc) - f._CHUNK_SIZE = chunksize - self.assertEqual(f.write("abc"), 3) - f.close() - f = self.open(os_helper.TESTFN, "r+", encoding=enc) - f._CHUNK_SIZE = chunksize - self.assertEqual(f.tell(), 0) - self.assertEqual(f.read(), "abc") - cookie = f.tell() - self.assertEqual(f.seek(0), 0) - self.assertEqual(f.read(None), "abc") - f.seek(0) - self.assertEqual(f.read(2), "ab") - self.assertEqual(f.read(1), "c") - self.assertEqual(f.read(1), "") - self.assertEqual(f.read(), "") - self.assertEqual(f.tell(), cookie) - self.assertEqual(f.seek(0), 0) - self.assertEqual(f.seek(0, 2), cookie) - self.assertEqual(f.write("def"), 3) - self.assertEqual(f.seek(cookie), cookie) - self.assertEqual(f.read(), "def") - if enc.startswith("utf"): - self.multi_line_test(f, enc) - f.close() - - def multi_line_test(self, f, enc): - f.seek(0) - f.truncate() - sample = "s\xff\u0fff\uffff" - wlines = [] - for size in (0, 1, 2, 3, 4, 5, 30, 31, 32, 33, 62, 63, 64, 65, 1000): - chars = [] - for i in range(size): - chars.append(sample[i % len(sample)]) - line = "".join(chars) + "\n" - wlines.append((f.tell(), line)) - f.write(line) - f.seek(0) - rlines = [] - while True: - pos = f.tell() - line = f.readline() - if not line: - break - rlines.append((pos, line)) - self.assertEqual(rlines, wlines) - - def test_telling(self): - f = self.open(os_helper.TESTFN, "w+", encoding="utf-8") - p0 = f.tell() - f.write("\xff\n") - p1 = f.tell() - f.write("\xff\n") - p2 = f.tell() - f.seek(0) - self.assertEqual(f.tell(), p0) - self.assertEqual(f.readline(), "\xff\n") - self.assertEqual(f.tell(), p1) - self.assertEqual(f.readline(), "\xff\n") - self.assertEqual(f.tell(), p2) - f.seek(0) - for line in f: - self.assertEqual(line, "\xff\n") - self.assertRaises(OSError, f.tell) - self.assertEqual(f.tell(), p2) - f.close() - - def test_seeking(self): - chunk_size = _default_chunk_size() - prefix_size = chunk_size - 2 - u_prefix = "a" * prefix_size - prefix = bytes(u_prefix.encode("utf-8")) - self.assertEqual(len(u_prefix), len(prefix)) - u_suffix = "\u8888\n" - suffix = bytes(u_suffix.encode("utf-8")) - line = prefix + suffix - with self.open(os_helper.TESTFN, "wb") as f: - f.write(line*2) - with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: - s = f.read(prefix_size) - self.assertEqual(s, str(prefix, "ascii")) - self.assertEqual(f.tell(), prefix_size) - self.assertEqual(f.readline(), u_suffix) - - def test_seeking_too(self): - # Regression test for a specific bug - data = b'\xe0\xbf\xbf\n' - with self.open(os_helper.TESTFN, "wb") as f: - f.write(data) - with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: - f._CHUNK_SIZE # Just test that it exists - f._CHUNK_SIZE = 2 - f.readline() - f.tell() - - def test_seek_and_tell(self): - #Test seek/tell using the StatefulIncrementalDecoder. - # Make test faster by doing smaller seeks - CHUNK_SIZE = 128 - - def test_seek_and_tell_with_data(data, min_pos=0): - """Tell/seek to various points within a data stream and ensure - that the decoded data returned by read() is consistent.""" - f = self.open(os_helper.TESTFN, 'wb') - f.write(data) - f.close() - f = self.open(os_helper.TESTFN, encoding='test_decoder') - f._CHUNK_SIZE = CHUNK_SIZE - decoded = f.read() - f.close() - - for i in range(min_pos, len(decoded) + 1): # seek positions - for j in [1, 5, len(decoded) - i]: # read lengths - f = self.open(os_helper.TESTFN, encoding='test_decoder') - self.assertEqual(f.read(i), decoded[:i]) - cookie = f.tell() - self.assertEqual(f.read(j), decoded[i:i + j]) - f.seek(cookie) - self.assertEqual(f.read(), decoded[i:]) - f.close() - - # Enable the test decoder. - StatefulIncrementalDecoder.codecEnabled = 1 - - # Run the tests. - try: - # Try each test case. - for input, _, _ in StatefulIncrementalDecoderTest.test_cases: - test_seek_and_tell_with_data(input) - - # Position each test case so that it crosses a chunk boundary. - for input, _, _ in StatefulIncrementalDecoderTest.test_cases: - offset = CHUNK_SIZE - len(input)//2 - prefix = b'.'*offset - # Don't bother seeking into the prefix (takes too long). - min_pos = offset*2 - test_seek_and_tell_with_data(prefix + input, min_pos) - - # Ensure our test decoder won't interfere with subsequent tests. - finally: - StatefulIncrementalDecoder.codecEnabled = 0 - - def test_multibyte_seek_and_tell(self): - f = self.open(os_helper.TESTFN, "w", encoding="euc_jp") - f.write("AB\n\u3046\u3048\n") - f.close() - - f = self.open(os_helper.TESTFN, "r", encoding="euc_jp") - self.assertEqual(f.readline(), "AB\n") - p0 = f.tell() - self.assertEqual(f.readline(), "\u3046\u3048\n") - p1 = f.tell() - f.seek(p0) - self.assertEqual(f.readline(), "\u3046\u3048\n") - self.assertEqual(f.tell(), p1) - f.close() - - def test_seek_with_encoder_state(self): - f = self.open(os_helper.TESTFN, "w", encoding="euc_jis_2004") - f.write("\u00e6\u0300") - p0 = f.tell() - f.write("\u00e6") - f.seek(p0) - f.write("\u0300") - f.close() - - f = self.open(os_helper.TESTFN, "r", encoding="euc_jis_2004") - self.assertEqual(f.readline(), "\u00e6\u0300\u0300") - f.close() - - def test_encoded_writes(self): - data = "1234567890" - tests = ("utf-16", - "utf-16-le", - "utf-16-be", - "utf-32", - "utf-32-le", - "utf-32-be") - for encoding in tests: - buf = self.BytesIO() - f = self.TextIOWrapper(buf, encoding=encoding) - # Check if the BOM is written only once (see issue1753). - f.write(data) - f.write(data) - f.seek(0) - self.assertEqual(f.read(), data * 2) - f.seek(0) - self.assertEqual(f.read(), data * 2) - self.assertEqual(buf.getvalue(), (data * 2).encode(encoding)) - - def test_unreadable(self): - class UnReadable(self.BytesIO): - def readable(self): - return False - txt = self.TextIOWrapper(UnReadable(), encoding="utf-8") - self.assertRaises(OSError, txt.read) - - def test_read_one_by_one(self): - txt = self.TextIOWrapper(self.BytesIO(b"AA\r\nBB"), encoding="utf-8") - reads = "" - while True: - c = txt.read(1) - if not c: - break - reads += c - self.assertEqual(reads, "AA\nBB") - - def test_readlines(self): - txt = self.TextIOWrapper(self.BytesIO(b"AA\nBB\nCC"), encoding="utf-8") - self.assertEqual(txt.readlines(), ["AA\n", "BB\n", "CC"]) - txt.seek(0) - self.assertEqual(txt.readlines(None), ["AA\n", "BB\n", "CC"]) - txt.seek(0) - self.assertEqual(txt.readlines(5), ["AA\n", "BB\n"]) - - # read in amounts equal to TextIOWrapper._CHUNK_SIZE which is 128. - def test_read_by_chunk(self): - # make sure "\r\n" straddles 128 char boundary. - txt = self.TextIOWrapper(self.BytesIO(b"A" * 127 + b"\r\nB"), encoding="utf-8") - reads = "" - while True: - c = txt.read(128) - if not c: - break - reads += c - self.assertEqual(reads, "A"*127+"\nB") - - def test_writelines(self): - l = ['ab', 'cd', 'ef'] - buf = self.BytesIO() - txt = self.TextIOWrapper(buf, encoding="utf-8") - txt.writelines(l) - txt.flush() - self.assertEqual(buf.getvalue(), b'abcdef') - - def test_writelines_userlist(self): - l = UserList(['ab', 'cd', 'ef']) - buf = self.BytesIO() - txt = self.TextIOWrapper(buf, encoding="utf-8") - txt.writelines(l) - txt.flush() - self.assertEqual(buf.getvalue(), b'abcdef') - - def test_writelines_error(self): - txt = self.TextIOWrapper(self.BytesIO(), encoding="utf-8") - self.assertRaises(TypeError, txt.writelines, [1, 2, 3]) - self.assertRaises(TypeError, txt.writelines, None) - self.assertRaises(TypeError, txt.writelines, b'abc') - - def test_issue1395_1(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - - # read one char at a time - reads = "" - while True: - c = txt.read(1) - if not c: - break - reads += c - self.assertEqual(reads, self.normalized) - - def test_issue1395_2(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - txt._CHUNK_SIZE = 4 - - reads = "" - while True: - c = txt.read(4) - if not c: - break - reads += c - self.assertEqual(reads, self.normalized) - - def test_issue1395_3(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - txt._CHUNK_SIZE = 4 - - reads = txt.read(4) - reads += txt.read(4) - reads += txt.readline() - reads += txt.readline() - reads += txt.readline() - self.assertEqual(reads, self.normalized) - - def test_issue1395_4(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - txt._CHUNK_SIZE = 4 - - reads = txt.read(4) - reads += txt.read() - self.assertEqual(reads, self.normalized) - - def test_issue1395_5(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - txt._CHUNK_SIZE = 4 - - reads = txt.read(4) - pos = txt.tell() - txt.seek(0) - txt.seek(pos) - self.assertEqual(txt.read(4), "BBB\n") - - def test_issue2282(self): - buffer = self.BytesIO(self.testdata) - txt = self.TextIOWrapper(buffer, encoding="ascii") - - self.assertEqual(buffer.seekable(), txt.seekable()) - - def test_append_bom(self): - # The BOM is not written again when appending to a non-empty file - filename = os_helper.TESTFN - for charset in ('utf-8-sig', 'utf-16', 'utf-32'): - with self.open(filename, 'w', encoding=charset) as f: - f.write('aaa') - pos = f.tell() - with self.open(filename, 'rb') as f: - self.assertEqual(f.read(), 'aaa'.encode(charset)) - - with self.open(filename, 'a', encoding=charset) as f: - f.write('xxx') - with self.open(filename, 'rb') as f: - self.assertEqual(f.read(), 'aaaxxx'.encode(charset)) - - def test_seek_bom(self): - # Same test, but when seeking manually - filename = os_helper.TESTFN - for charset in ('utf-8-sig', 'utf-16', 'utf-32'): - with self.open(filename, 'w', encoding=charset) as f: - f.write('aaa') - pos = f.tell() - with self.open(filename, 'r+', encoding=charset) as f: - f.seek(pos) - f.write('zzz') - f.seek(0) - f.write('bbb') - with self.open(filename, 'rb') as f: - self.assertEqual(f.read(), 'bbbzzz'.encode(charset)) - - def test_seek_append_bom(self): - # Same test, but first seek to the start and then to the end - filename = os_helper.TESTFN - for charset in ('utf-8-sig', 'utf-16', 'utf-32'): - with self.open(filename, 'w', encoding=charset) as f: - f.write('aaa') - with self.open(filename, 'a', encoding=charset) as f: - f.seek(0) - f.seek(0, self.SEEK_END) - f.write('xxx') - with self.open(filename, 'rb') as f: - self.assertEqual(f.read(), 'aaaxxx'.encode(charset)) - - def test_errors_property(self): - with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: - self.assertEqual(f.errors, "strict") - with self.open(os_helper.TESTFN, "w", encoding="utf-8", errors="replace") as f: - self.assertEqual(f.errors, "replace") - - @support.no_tracing - @threading_helper.requires_working_threading() - def test_threads_write(self): - # Issue6750: concurrent writes could duplicate data - event = threading.Event() - with self.open(os_helper.TESTFN, "w", encoding="utf-8", buffering=1) as f: - def run(n): - text = "Thread%03d\n" % n - event.wait() - f.write(text) - threads = [threading.Thread(target=run, args=(x,)) - for x in range(20)] - with threading_helper.start_threads(threads, event.set): - time.sleep(0.02) - with self.open(os_helper.TESTFN, encoding="utf-8") as f: - content = f.read() - for n in range(20): - self.assertEqual(content.count("Thread%03d\n" % n), 1) - - def test_flush_error_on_close(self): - # Test that text file is closed despite failed flush - # and that flush() is called before file closed. - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - closed = [] - def bad_flush(): - closed[:] = [txt.closed, txt.buffer.closed] - raise OSError() - txt.flush = bad_flush - self.assertRaises(OSError, txt.close) # exception not swallowed - self.assertTrue(txt.closed) - self.assertTrue(txt.buffer.closed) - self.assertTrue(closed) # flush() called - self.assertFalse(closed[0]) # flush() called before file closed - self.assertFalse(closed[1]) - txt.flush = lambda: None # break reference loop - - def test_close_error_on_close(self): - buffer = self.BytesIO(self.testdata) - def bad_flush(): - raise OSError('flush') - def bad_close(): - raise OSError('close') - buffer.close = bad_close - txt = self.TextIOWrapper(buffer, encoding="ascii") - txt.flush = bad_flush - with self.assertRaises(OSError) as err: # exception not swallowed - txt.close() - self.assertEqual(err.exception.args, ('close',)) - self.assertIsInstance(err.exception.__context__, OSError) - self.assertEqual(err.exception.__context__.args, ('flush',)) - self.assertFalse(txt.closed) - - # Silence destructor error - buffer.close = lambda: None - txt.flush = lambda: None - - def test_nonnormalized_close_error_on_close(self): - # Issue #21677 - buffer = self.BytesIO(self.testdata) - def bad_flush(): - raise non_existing_flush - def bad_close(): - raise non_existing_close - buffer.close = bad_close - txt = self.TextIOWrapper(buffer, encoding="ascii") - txt.flush = bad_flush - with self.assertRaises(NameError) as err: # exception not swallowed - txt.close() - self.assertIn('non_existing_close', str(err.exception)) - self.assertIsInstance(err.exception.__context__, NameError) - self.assertIn('non_existing_flush', str(err.exception.__context__)) - self.assertFalse(txt.closed) - - # Silence destructor error - buffer.close = lambda: None - txt.flush = lambda: None - - def test_multi_close(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - txt.close() - txt.close() - txt.close() - self.assertRaises(ValueError, txt.flush) - - def test_unseekable(self): - txt = self.TextIOWrapper(self.MockUnseekableIO(self.testdata), encoding="utf-8") - self.assertRaises(self.UnsupportedOperation, txt.tell) - self.assertRaises(self.UnsupportedOperation, txt.seek, 0) - - def test_readonly_attributes(self): - txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") - buf = self.BytesIO(self.testdata) - with self.assertRaises(AttributeError): - txt.buffer = buf - - def test_rawio(self): - # Issue #12591: TextIOWrapper must work with raw I/O objects, so - # that subprocess.Popen() can have the required unbuffered - # semantics with universal_newlines=True. - raw = self.MockRawIO([b'abc', b'def', b'ghi\njkl\nopq\n']) - txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') - # Reads - self.assertEqual(txt.read(4), 'abcd') - self.assertEqual(txt.readline(), 'efghi\n') - self.assertEqual(list(txt), ['jkl\n', 'opq\n']) - - def test_rawio_write_through(self): - # Issue #12591: with write_through=True, writes don't need a flush - raw = self.MockRawIO([b'abc', b'def', b'ghi\njkl\nopq\n']) - txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n', - write_through=True) - txt.write('1') - txt.write('23\n4') - txt.write('5') - self.assertEqual(b''.join(raw._write_stack), b'123\n45') - - def test_bufio_write_through(self): - # Issue #21396: write_through=True doesn't force a flush() - # on the underlying binary buffered object. - flush_called, write_called = [], [] - class BufferedWriter(self.BufferedWriter): - def flush(self, *args, **kwargs): - flush_called.append(True) - return super().flush(*args, **kwargs) - def write(self, *args, **kwargs): - write_called.append(True) - return super().write(*args, **kwargs) - - rawio = self.BytesIO() - data = b"a" - bufio = BufferedWriter(rawio, len(data)*2) - textio = self.TextIOWrapper(bufio, encoding='ascii', - write_through=True) - # write to the buffered io but don't overflow the buffer - text = data.decode('ascii') - textio.write(text) - - # buffer.flush is not called with write_through=True - self.assertFalse(flush_called) - # buffer.write *is* called with write_through=True - self.assertTrue(write_called) - self.assertEqual(rawio.getvalue(), b"") # no flush - - write_called = [] # reset - textio.write(text * 10) # total content is larger than bufio buffer - self.assertTrue(write_called) - self.assertEqual(rawio.getvalue(), data * 11) # all flushed - - def test_reconfigure_write_through(self): - raw = self.MockRawIO([]) - t = self.TextIOWrapper(raw, encoding='ascii', newline='\n') - t.write('1') - t.reconfigure(write_through=True) # implied flush - self.assertEqual(t.write_through, True) - self.assertEqual(b''.join(raw._write_stack), b'1') - t.write('23') - self.assertEqual(b''.join(raw._write_stack), b'123') - t.reconfigure(write_through=False) - self.assertEqual(t.write_through, False) - t.write('45') - t.flush() - self.assertEqual(b''.join(raw._write_stack), b'12345') - # Keeping default value - t.reconfigure() - t.reconfigure(write_through=None) - self.assertEqual(t.write_through, False) - t.reconfigure(write_through=True) - t.reconfigure() - t.reconfigure(write_through=None) - self.assertEqual(t.write_through, True) - - def test_read_nonbytes(self): - # Issue #17106 - # Crash when underlying read() returns non-bytes - t = self.TextIOWrapper(self.StringIO('a'), encoding="utf-8") - self.assertRaises(TypeError, t.read, 1) - t = self.TextIOWrapper(self.StringIO('a'), encoding="utf-8") - self.assertRaises(TypeError, t.readline) - t = self.TextIOWrapper(self.StringIO('a'), encoding="utf-8") - self.assertRaises(TypeError, t.read) - - def test_illegal_encoder(self): - # Issue 31271: Calling write() while the return value of encoder's - # encode() is invalid shouldn't cause an assertion failure. - rot13 = codecs.lookup("rot13") - with support.swap_attr(rot13, '_is_text_encoding', True): - t = self.TextIOWrapper(self.BytesIO(b'foo'), encoding="rot13") - self.assertRaises(TypeError, t.write, 'bar') - - def test_illegal_decoder(self): - # Issue #17106 - # Bypass the early encoding check added in issue 20404 - def _make_illegal_wrapper(): - quopri = codecs.lookup("quopri") - quopri._is_text_encoding = True - try: - t = self.TextIOWrapper(self.BytesIO(b'aaaaaa'), - newline='\n', encoding="quopri") - finally: - quopri._is_text_encoding = False - return t - # Crash when decoder returns non-string - t = _make_illegal_wrapper() - self.assertRaises(TypeError, t.read, 1) - t = _make_illegal_wrapper() - self.assertRaises(TypeError, t.readline) - t = _make_illegal_wrapper() - self.assertRaises(TypeError, t.read) - - # Issue 31243: calling read() while the return value of decoder's - # getstate() is invalid should neither crash the interpreter nor - # raise a SystemError. - def _make_very_illegal_wrapper(getstate_ret_val): - class BadDecoder: - def getstate(self): - return getstate_ret_val - def _get_bad_decoder(dummy): - return BadDecoder() - quopri = codecs.lookup("quopri") - with support.swap_attr(quopri, 'incrementaldecoder', - _get_bad_decoder): - return _make_illegal_wrapper() - t = _make_very_illegal_wrapper(42) - self.assertRaises(TypeError, t.read, 42) - t = _make_very_illegal_wrapper(()) - self.assertRaises(TypeError, t.read, 42) - t = _make_very_illegal_wrapper((1, 2)) - self.assertRaises(TypeError, t.read, 42) - - def _check_create_at_shutdown(self, **kwargs): - # Issue #20037: creating a TextIOWrapper at shutdown - # shouldn't crash the interpreter. - iomod = self.io.__name__ - code = """if 1: - import codecs - import {iomod} as io - - # Avoid looking up codecs at shutdown - codecs.lookup('utf-8') - - class C: - def __del__(self): - io.TextIOWrapper(io.BytesIO(), **{kwargs}) - print("ok") - c = C() - """.format(iomod=iomod, kwargs=kwargs) - return assert_python_ok("-c", code) - - def test_create_at_shutdown_without_encoding(self): - rc, out, err = self._check_create_at_shutdown() - if err: - # Can error out with a RuntimeError if the module state - # isn't found. - self.assertIn(self.shutdown_error, err.decode()) - else: - self.assertEqual("ok", out.decode().strip()) - - def test_create_at_shutdown_with_encoding(self): - rc, out, err = self._check_create_at_shutdown(encoding='utf-8', - errors='strict') - self.assertFalse(err) - self.assertEqual("ok", out.decode().strip()) - - def test_read_byteslike(self): - r = MemviewBytesIO(b'Just some random string\n') - t = self.TextIOWrapper(r, 'utf-8') - - # TextIOwrapper will not read the full string, because - # we truncate it to a multiple of the native int size - # so that we can construct a more complex memoryview. - bytes_val = _to_memoryview(r.getvalue()).tobytes() - - self.assertEqual(t.read(200), bytes_val.decode('utf-8')) - - def test_issue22849(self): - class F(object): - def readable(self): return True - def writable(self): return True - def seekable(self): return True - - for i in range(10): - try: - self.TextIOWrapper(F(), encoding='utf-8') - except Exception: - pass - - F.tell = lambda x: 0 - t = self.TextIOWrapper(F(), encoding='utf-8') - - def test_reconfigure_locale(self): - wrapper = self.TextIOWrapper(self.BytesIO(b"test")) - wrapper.reconfigure(encoding="locale") - - def test_reconfigure_encoding_read(self): - # latin1 -> utf8 - # (latin1 can decode utf-8 encoded string) - data = 'abc\xe9\n'.encode('latin1') + 'd\xe9f\n'.encode('utf8') - raw = self.BytesIO(data) - txt = self.TextIOWrapper(raw, encoding='latin1', newline='\n') - self.assertEqual(txt.readline(), 'abc\xe9\n') - with self.assertRaises(self.UnsupportedOperation): - txt.reconfigure(encoding='utf-8') - with self.assertRaises(self.UnsupportedOperation): - txt.reconfigure(newline=None) - - def test_reconfigure_write_fromascii(self): - # ascii has a specific encodefunc in the C implementation, - # but utf-8-sig has not. Make sure that we get rid of the - # cached encodefunc when we switch encoders. - raw = self.BytesIO() - txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') - txt.write('foo\n') - txt.reconfigure(encoding='utf-8-sig') - txt.write('\xe9\n') - txt.flush() - self.assertEqual(raw.getvalue(), b'foo\n\xc3\xa9\n') - - def test_reconfigure_write(self): - # latin -> utf8 - raw = self.BytesIO() - txt = self.TextIOWrapper(raw, encoding='latin1', newline='\n') - txt.write('abc\xe9\n') - txt.reconfigure(encoding='utf-8') - self.assertEqual(raw.getvalue(), b'abc\xe9\n') - txt.write('d\xe9f\n') - txt.flush() - self.assertEqual(raw.getvalue(), b'abc\xe9\nd\xc3\xa9f\n') - - # ascii -> utf-8-sig: ensure that no BOM is written in the middle of - # the file - raw = self.BytesIO() - txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') - txt.write('abc\n') - txt.reconfigure(encoding='utf-8-sig') - txt.write('d\xe9f\n') - txt.flush() - self.assertEqual(raw.getvalue(), b'abc\nd\xc3\xa9f\n') - - def test_reconfigure_write_non_seekable(self): - raw = self.BytesIO() - raw.seekable = lambda: False - raw.seek = None - txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') - txt.write('abc\n') - txt.reconfigure(encoding='utf-8-sig') - txt.write('d\xe9f\n') - txt.flush() - - # If the raw stream is not seekable, there'll be a BOM - self.assertEqual(raw.getvalue(), b'abc\n\xef\xbb\xbfd\xc3\xa9f\n') - - def test_reconfigure_defaults(self): - txt = self.TextIOWrapper(self.BytesIO(), 'ascii', 'replace', '\n') - txt.reconfigure(encoding=None) - self.assertEqual(txt.encoding, 'ascii') - self.assertEqual(txt.errors, 'replace') - txt.write('LF\n') - - txt.reconfigure(newline='\r\n') - self.assertEqual(txt.encoding, 'ascii') - self.assertEqual(txt.errors, 'replace') - - txt.reconfigure(errors='ignore') - self.assertEqual(txt.encoding, 'ascii') - self.assertEqual(txt.errors, 'ignore') - txt.write('CRLF\n') - - txt.reconfigure(encoding='utf-8', newline=None) - self.assertEqual(txt.errors, 'strict') - txt.seek(0) - self.assertEqual(txt.read(), 'LF\nCRLF\n') - - self.assertEqual(txt.detach().getvalue(), b'LF\nCRLF\r\n') - - def test_reconfigure_errors(self): - txt = self.TextIOWrapper(self.BytesIO(), 'ascii', 'replace', '\r') - with self.assertRaises(TypeError): # there was a crash - txt.reconfigure(encoding=42) - if self.is_C: - with self.assertRaises(UnicodeEncodeError): - txt.reconfigure(encoding='\udcfe') - with self.assertRaises(LookupError): - txt.reconfigure(encoding='locale\0') - # TODO: txt.reconfigure(encoding='utf-8\0') - # TODO: txt.reconfigure(encoding='nonexisting') - with self.assertRaises(TypeError): - txt.reconfigure(errors=42) - if self.is_C: - with self.assertRaises(UnicodeEncodeError): - txt.reconfigure(errors='\udcfe') - # TODO: txt.reconfigure(errors='ignore\0') - # TODO: txt.reconfigure(errors='nonexisting') - with self.assertRaises(TypeError): - txt.reconfigure(newline=42) - with self.assertRaises(ValueError): - txt.reconfigure(newline='\udcfe') - with self.assertRaises(ValueError): - txt.reconfigure(newline='xyz') - if not self.is_C: - # TODO: Should fail in C too. - with self.assertRaises(ValueError): - txt.reconfigure(newline='\n\0') - if self.is_C: - # TODO: Use __bool__(), not __index__(). - with self.assertRaises(ZeroDivisionError): - txt.reconfigure(line_buffering=BadIndex()) - with self.assertRaises(OverflowError): - txt.reconfigure(line_buffering=2**1000) - with self.assertRaises(ZeroDivisionError): - txt.reconfigure(write_through=BadIndex()) - with self.assertRaises(OverflowError): - txt.reconfigure(write_through=2**1000) - with self.assertRaises(ZeroDivisionError): # there was a crash - txt.reconfigure(line_buffering=BadIndex(), - write_through=BadIndex()) - self.assertEqual(txt.encoding, 'ascii') - self.assertEqual(txt.errors, 'replace') - self.assertIs(txt.line_buffering, False) - self.assertIs(txt.write_through, False) - - txt.reconfigure(encoding='latin1', errors='ignore', newline='\r\n', - line_buffering=True, write_through=True) - self.assertEqual(txt.encoding, 'latin1') - self.assertEqual(txt.errors, 'ignore') - self.assertIs(txt.line_buffering, True) - self.assertIs(txt.write_through, True) - - def test_reconfigure_newline(self): - raw = self.BytesIO(b'CR\rEOF') - txt = self.TextIOWrapper(raw, 'ascii', newline='\n') - txt.reconfigure(newline=None) - self.assertEqual(txt.readline(), 'CR\n') - raw = self.BytesIO(b'CR\rEOF') - txt = self.TextIOWrapper(raw, 'ascii', newline='\n') - txt.reconfigure(newline='') - self.assertEqual(txt.readline(), 'CR\r') - raw = self.BytesIO(b'CR\rLF\nEOF') - txt = self.TextIOWrapper(raw, 'ascii', newline='\r') - txt.reconfigure(newline='\n') - self.assertEqual(txt.readline(), 'CR\rLF\n') - raw = self.BytesIO(b'LF\nCR\rEOF') - txt = self.TextIOWrapper(raw, 'ascii', newline='\n') - txt.reconfigure(newline='\r') - self.assertEqual(txt.readline(), 'LF\nCR\r') - raw = self.BytesIO(b'CR\rCRLF\r\nEOF') - txt = self.TextIOWrapper(raw, 'ascii', newline='\r') - txt.reconfigure(newline='\r\n') - self.assertEqual(txt.readline(), 'CR\rCRLF\r\n') - - txt = self.TextIOWrapper(self.BytesIO(), 'ascii', newline='\r') - txt.reconfigure(newline=None) - txt.write('linesep\n') - txt.reconfigure(newline='') - txt.write('LF\n') - txt.reconfigure(newline='\n') - txt.write('LF\n') - txt.reconfigure(newline='\r') - txt.write('CR\n') - txt.reconfigure(newline='\r\n') - txt.write('CRLF\n') - expected = 'linesep' + os.linesep + 'LF\nLF\nCR\rCRLF\r\n' - self.assertEqual(txt.detach().getvalue().decode('ascii'), expected) - - def test_issue25862(self): - # Assertion failures occurred in tell() after read() and write(). - t = self.TextIOWrapper(self.BytesIO(b'test'), encoding='ascii') - t.read(1) - t.read() - t.tell() - t = self.TextIOWrapper(self.BytesIO(b'test'), encoding='ascii') - t.read(1) - t.write('x') - t.tell() - - def test_issue35928(self): - p = self.BufferedRWPair(self.BytesIO(b'foo\nbar\n'), self.BytesIO()) - f = self.TextIOWrapper(p) - res = f.readline() - self.assertEqual(res, 'foo\n') - f.write(res) - self.assertEqual(res + f.readline(), 'foo\nbar\n') - - def test_pickling_subclass(self): - global MyTextIO - class MyTextIO(self.TextIOWrapper): - def __init__(self, raw, tag): - super().__init__(raw) - self.tag = tag - def __getstate__(self): - return self.tag, self.buffer.getvalue() - def __setstate__(slf, state): - tag, value = state - slf.__init__(self.BytesIO(value), tag) - - raw = self.BytesIO(b'data') - txt = MyTextIO(raw, 'ham') - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - with self.subTest(protocol=proto): - pickled = pickle.dumps(txt, proto) - newtxt = pickle.loads(pickled) - self.assertEqual(newtxt.buffer.getvalue(), b'data') - self.assertEqual(newtxt.tag, 'ham') - del MyTextIO - - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_read_non_blocking(self): - import os - r, w = os.pipe() - try: - os.set_blocking(r, False) - with self.io.open(r, 'rt') as textfile: - r = None - # Nothing has been written so a non-blocking read raises a BlockingIOError exception. - with self.assertRaises(BlockingIOError): - textfile.read() - finally: - if r is not None: - os.close(r) - os.close(w) - - -class MemviewBytesIO(io.BytesIO): - '''A BytesIO object whose read method returns memoryviews - rather than bytes''' - - def read1(self, len_): - return _to_memoryview(super().read1(len_)) - - def read(self, len_): - return _to_memoryview(super().read(len_)) - -def _to_memoryview(buf): - '''Convert bytes-object *buf* to a non-trivial memoryview''' - - arr = array.array('i') - idx = len(buf) - len(buf) % arr.itemsize - arr.frombytes(buf[:idx]) - return memoryview(arr) - - -class CTextIOWrapperTest(TextIOWrapperTest): - io = io - shutdown_error = "LookupError: unknown encoding: ascii" - - def test_initialization(self): - r = self.BytesIO(b"\xc3\xa9\n\n") - b = self.BufferedReader(r, 1000) - t = self.TextIOWrapper(b, encoding="utf-8") - self.assertRaises(ValueError, t.__init__, b, encoding="utf-8", newline='xyzzy') - self.assertRaises(ValueError, t.read) - - t = self.TextIOWrapper.__new__(self.TextIOWrapper) - self.assertRaises(Exception, repr, t) - - def test_garbage_collection(self): - # C TextIOWrapper objects are collected, and collecting them flushes - # all data to disk. - # The Python version has __del__, so it ends in gc.garbage instead. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ResourceWarning) - rawio = self.FileIO(os_helper.TESTFN, "wb") - b = self.BufferedWriter(rawio) - t = self.TextIOWrapper(b, encoding="ascii") - t.write("456def") - t.x = t - wr = weakref.ref(t) - del t - support.gc_collect() - self.assertIsNone(wr(), wr) - with self.open(os_helper.TESTFN, "rb") as f: - self.assertEqual(f.read(), b"456def") - - def test_rwpair_cleared_before_textio(self): - # Issue 13070: TextIOWrapper's finalization would crash when called - # after the reference to the underlying BufferedRWPair's writer got - # cleared by the GC. - for i in range(1000): - b1 = self.BufferedRWPair(self.MockRawIO(), self.MockRawIO()) - t1 = self.TextIOWrapper(b1, encoding="ascii") - b2 = self.BufferedRWPair(self.MockRawIO(), self.MockRawIO()) - t2 = self.TextIOWrapper(b2, encoding="ascii") - # circular references - t1.buddy = t2 - t2.buddy = t1 - support.gc_collect() - - def test_del__CHUNK_SIZE_SystemError(self): - t = self.TextIOWrapper(self.BytesIO(), encoding='ascii') - with self.assertRaises(AttributeError): - del t._CHUNK_SIZE - - def test_internal_buffer_size(self): - # bpo-43260: TextIOWrapper's internal buffer should not store - # data larger than chunk size. - chunk_size = 8192 # default chunk size, updated later - - class MockIO(self.MockRawIO): - def write(self, data): - if len(data) > chunk_size: - raise RuntimeError - return super().write(data) - - buf = MockIO() - t = self.TextIOWrapper(buf, encoding="ascii") - chunk_size = t._CHUNK_SIZE - t.write("abc") - t.write("def") - # default chunk size is 8192 bytes so t don't write data to buf. - self.assertEqual([], buf._write_stack) - - with self.assertRaises(RuntimeError): - t.write("x"*(chunk_size+1)) - - self.assertEqual([b"abcdef"], buf._write_stack) - t.write("ghi") - t.write("x"*chunk_size) - self.assertEqual([b"abcdef", b"ghi", b"x"*chunk_size], buf._write_stack) - - def test_issue119506(self): - chunk_size = 8192 - - class MockIO(self.MockRawIO): - written = False - def write(self, data): - if not self.written: - self.written = True - t.write("middle") - return super().write(data) - - buf = MockIO() - t = self.TextIOWrapper(buf) - t.write("abc") - t.write("def") - # writing data which size >= chunk_size cause flushing buffer before write. - t.write("g" * chunk_size) - t.flush() - - self.assertEqual([b"abcdef", b"middle", b"g"*chunk_size], - buf._write_stack) - - -class PyTextIOWrapperTest(TextIOWrapperTest): - io = pyio - shutdown_error = "LookupError: unknown encoding: ascii" - - -class IncrementalNewlineDecoderTest(unittest.TestCase): - - def check_newline_decoding_utf8(self, decoder): - # UTF-8 specific tests for a newline decoder - def _check_decode(b, s, **kwargs): - # We exercise getstate() / setstate() as well as decode() - state = decoder.getstate() - self.assertEqual(decoder.decode(b, **kwargs), s) - decoder.setstate(state) - self.assertEqual(decoder.decode(b, **kwargs), s) - - _check_decode(b'\xe8\xa2\x88', "\u8888") - - _check_decode(b'\xe8', "") - _check_decode(b'\xa2', "") - _check_decode(b'\x88', "\u8888") - - _check_decode(b'\xe8', "") - _check_decode(b'\xa2', "") - _check_decode(b'\x88', "\u8888") - - _check_decode(b'\xe8', "") - self.assertRaises(UnicodeDecodeError, decoder.decode, b'', final=True) - - decoder.reset() - _check_decode(b'\n', "\n") - _check_decode(b'\r', "") - _check_decode(b'', "\n", final=True) - _check_decode(b'\r', "\n", final=True) - - _check_decode(b'\r', "") - _check_decode(b'a', "\na") - - _check_decode(b'\r\r\n', "\n\n") - _check_decode(b'\r', "") - _check_decode(b'\r', "\n") - _check_decode(b'\na', "\na") - - _check_decode(b'\xe8\xa2\x88\r\n', "\u8888\n") - _check_decode(b'\xe8\xa2\x88', "\u8888") - _check_decode(b'\n', "\n") - _check_decode(b'\xe8\xa2\x88\r', "\u8888") - _check_decode(b'\n', "\n") - - def check_newline_decoding(self, decoder, encoding): - result = [] - if encoding is not None: - encoder = codecs.getincrementalencoder(encoding)() - def _decode_bytewise(s): - # Decode one byte at a time - for b in encoder.encode(s): - result.append(decoder.decode(bytes([b]))) - else: - encoder = None - def _decode_bytewise(s): - # Decode one char at a time - for c in s: - result.append(decoder.decode(c)) - self.assertEqual(decoder.newlines, None) - _decode_bytewise("abc\n\r") - self.assertEqual(decoder.newlines, '\n') - _decode_bytewise("\nabc") - self.assertEqual(decoder.newlines, ('\n', '\r\n')) - _decode_bytewise("abc\r") - self.assertEqual(decoder.newlines, ('\n', '\r\n')) - _decode_bytewise("abc") - self.assertEqual(decoder.newlines, ('\r', '\n', '\r\n')) - _decode_bytewise("abc\r") - self.assertEqual("".join(result), "abc\n\nabcabc\nabcabc") - decoder.reset() - input = "abc" - if encoder is not None: - encoder.reset() - input = encoder.encode(input) - self.assertEqual(decoder.decode(input), "abc") - self.assertEqual(decoder.newlines, None) - - def test_newline_decoder(self): - encodings = ( - # None meaning the IncrementalNewlineDecoder takes unicode input - # rather than bytes input - None, 'utf-8', 'latin-1', - 'utf-16', 'utf-16-le', 'utf-16-be', - 'utf-32', 'utf-32-le', 'utf-32-be', - ) - for enc in encodings: - decoder = enc and codecs.getincrementaldecoder(enc)() - decoder = self.IncrementalNewlineDecoder(decoder, translate=True) - self.check_newline_decoding(decoder, enc) - decoder = codecs.getincrementaldecoder("utf-8")() - decoder = self.IncrementalNewlineDecoder(decoder, translate=True) - self.check_newline_decoding_utf8(decoder) - self.assertRaises(TypeError, decoder.setstate, 42) - - def test_newline_bytes(self): - # Issue 5433: Excessive optimization in IncrementalNewlineDecoder - def _check(dec): - self.assertEqual(dec.newlines, None) - self.assertEqual(dec.decode("\u0D00"), "\u0D00") - self.assertEqual(dec.newlines, None) - self.assertEqual(dec.decode("\u0A00"), "\u0A00") - self.assertEqual(dec.newlines, None) - dec = self.IncrementalNewlineDecoder(None, translate=False) - _check(dec) - dec = self.IncrementalNewlineDecoder(None, translate=True) - _check(dec) - - def test_translate(self): - # issue 35062 - for translate in (-2, -1, 1, 2): - decoder = codecs.getincrementaldecoder("utf-8")() - decoder = self.IncrementalNewlineDecoder(decoder, translate) - self.check_newline_decoding_utf8(decoder) - decoder = codecs.getincrementaldecoder("utf-8")() - decoder = self.IncrementalNewlineDecoder(decoder, translate=0) - self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n") - -class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest): - @support.cpython_only - def test_uninitialized(self): - uninitialized = self.IncrementalNewlineDecoder.__new__( - self.IncrementalNewlineDecoder) - self.assertRaises(ValueError, uninitialized.decode, b'bar') - self.assertRaises(ValueError, uninitialized.getstate) - self.assertRaises(ValueError, uninitialized.setstate, (b'foo', 0)) - self.assertRaises(ValueError, uninitialized.reset) - - -class PyIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest): - pass - - -# XXX Tests for open() - -class MiscIOTest(unittest.TestCase): - - # for test__all__, actual values are set in subclasses - name_of_module = None - extra_exported = () - not_exported = () - - def tearDown(self): - os_helper.unlink(os_helper.TESTFN) - - def test___all__(self): - support.check__all__(self, self.io, self.name_of_module, - extra=self.extra_exported, - not_exported=self.not_exported) - - def test_attributes(self): - f = self.open(os_helper.TESTFN, "wb", buffering=0) - self.assertEqual(f.mode, "wb") - f.close() - - f = self.open(os_helper.TESTFN, "w+", encoding="utf-8") - self.assertEqual(f.mode, "w+") - self.assertEqual(f.buffer.mode, "rb+") # Does it really matter? - self.assertEqual(f.buffer.raw.mode, "rb+") - - g = self.open(f.fileno(), "wb", closefd=False) - self.assertEqual(g.mode, "wb") - self.assertEqual(g.raw.mode, "wb") - self.assertEqual(g.name, f.fileno()) - self.assertEqual(g.raw.name, f.fileno()) - f.close() - g.close() - - def test_removed_u_mode(self): - # bpo-37330: The "U" mode has been removed in Python 3.11 - for mode in ("U", "rU", "r+U"): - with self.assertRaises(ValueError) as cm: - self.open(os_helper.TESTFN, mode) - self.assertIn('invalid mode', str(cm.exception)) - - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_open_pipe_with_append(self): - # bpo-27805: Ignore ESPIPE from lseek() in open(). - r, w = os.pipe() - self.addCleanup(os.close, r) - f = self.open(w, 'a', encoding="utf-8") - self.addCleanup(f.close) - # Check that the file is marked non-seekable. On Windows, however, lseek - # somehow succeeds on pipes. - if sys.platform != 'win32': - self.assertFalse(f.seekable()) - - def test_io_after_close(self): - for kwargs in [ - {"mode": "w"}, - {"mode": "wb"}, - {"mode": "w", "buffering": 1}, - {"mode": "w", "buffering": 2}, - {"mode": "wb", "buffering": 0}, - {"mode": "r"}, - {"mode": "rb"}, - {"mode": "r", "buffering": 1}, - {"mode": "r", "buffering": 2}, - {"mode": "rb", "buffering": 0}, - {"mode": "w+"}, - {"mode": "w+b"}, - {"mode": "w+", "buffering": 1}, - {"mode": "w+", "buffering": 2}, - {"mode": "w+b", "buffering": 0}, - ]: - if "b" not in kwargs["mode"]: - kwargs["encoding"] = "utf-8" - f = self.open(os_helper.TESTFN, **kwargs) - f.close() - self.assertRaises(ValueError, f.flush) - self.assertRaises(ValueError, f.fileno) - self.assertRaises(ValueError, f.isatty) - self.assertRaises(ValueError, f.__iter__) - if hasattr(f, "peek"): - self.assertRaises(ValueError, f.peek, 1) - self.assertRaises(ValueError, f.read) - if hasattr(f, "read1"): - self.assertRaises(ValueError, f.read1, 1024) - self.assertRaises(ValueError, f.read1) - if hasattr(f, "readall"): - self.assertRaises(ValueError, f.readall) - if hasattr(f, "readinto"): - self.assertRaises(ValueError, f.readinto, bytearray(1024)) - if hasattr(f, "readinto1"): - self.assertRaises(ValueError, f.readinto1, bytearray(1024)) - self.assertRaises(ValueError, f.readline) - self.assertRaises(ValueError, f.readlines) - self.assertRaises(ValueError, f.readlines, 1) - self.assertRaises(ValueError, f.seek, 0) - self.assertRaises(ValueError, f.tell) - self.assertRaises(ValueError, f.truncate) - self.assertRaises(ValueError, f.write, - b"" if "b" in kwargs['mode'] else "") - self.assertRaises(ValueError, f.writelines, []) - self.assertRaises(ValueError, next, f) - - def test_blockingioerror(self): - # Various BlockingIOError issues - class C(str): - pass - c = C("") - b = self.BlockingIOError(1, c) - c.b = b - b.c = c - wr = weakref.ref(c) - del c, b - support.gc_collect() - self.assertIsNone(wr(), wr) - - def test_abcs(self): - # Test the visible base classes are ABCs. - self.assertIsInstance(self.IOBase, abc.ABCMeta) - self.assertIsInstance(self.RawIOBase, abc.ABCMeta) - self.assertIsInstance(self.BufferedIOBase, abc.ABCMeta) - self.assertIsInstance(self.TextIOBase, abc.ABCMeta) - - def _check_abc_inheritance(self, abcmodule): - with self.open(os_helper.TESTFN, "wb", buffering=0) as f: - self.assertIsInstance(f, abcmodule.IOBase) - self.assertIsInstance(f, abcmodule.RawIOBase) - self.assertNotIsInstance(f, abcmodule.BufferedIOBase) - self.assertNotIsInstance(f, abcmodule.TextIOBase) - with self.open(os_helper.TESTFN, "wb") as f: - self.assertIsInstance(f, abcmodule.IOBase) - self.assertNotIsInstance(f, abcmodule.RawIOBase) - self.assertIsInstance(f, abcmodule.BufferedIOBase) - self.assertNotIsInstance(f, abcmodule.TextIOBase) - with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: - self.assertIsInstance(f, abcmodule.IOBase) - self.assertNotIsInstance(f, abcmodule.RawIOBase) - self.assertNotIsInstance(f, abcmodule.BufferedIOBase) - self.assertIsInstance(f, abcmodule.TextIOBase) - - def test_abc_inheritance(self): - # Test implementations inherit from their respective ABCs - self._check_abc_inheritance(self) - - def test_abc_inheritance_official(self): - # Test implementations inherit from the official ABCs of the - # baseline "io" module. - self._check_abc_inheritance(io) - - def _check_warn_on_dealloc(self, *args, **kwargs): - f = self.open(*args, **kwargs) - r = repr(f) - with self.assertWarns(ResourceWarning) as cm: - f = None - support.gc_collect() - self.assertIn(r, str(cm.warning.args[0])) - - def test_warn_on_dealloc(self): - self._check_warn_on_dealloc(os_helper.TESTFN, "wb", buffering=0) - self._check_warn_on_dealloc(os_helper.TESTFN, "wb") - self._check_warn_on_dealloc(os_helper.TESTFN, "w", encoding="utf-8") - - def _check_warn_on_dealloc_fd(self, *args, **kwargs): - fds = [] - def cleanup_fds(): - for fd in fds: - try: - os.close(fd) - except OSError as e: - if e.errno != errno.EBADF: - raise - self.addCleanup(cleanup_fds) - r, w = os.pipe() - fds += r, w - self._check_warn_on_dealloc(r, *args, **kwargs) - # When using closefd=False, there's no warning - r, w = os.pipe() - fds += r, w - with warnings_helper.check_no_resource_warning(self): - self.open(r, *args, closefd=False, **kwargs) - - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_warn_on_dealloc_fd(self): - self._check_warn_on_dealloc_fd("rb", buffering=0) - self._check_warn_on_dealloc_fd("rb") - self._check_warn_on_dealloc_fd("r", encoding="utf-8") - - - def test_pickling(self): - # Pickling file objects is forbidden - msg = "cannot pickle" - for kwargs in [ - {"mode": "w"}, - {"mode": "wb"}, - {"mode": "wb", "buffering": 0}, - {"mode": "r"}, - {"mode": "rb"}, - {"mode": "rb", "buffering": 0}, - {"mode": "w+"}, - {"mode": "w+b"}, - {"mode": "w+b", "buffering": 0}, - ]: - if "b" not in kwargs["mode"]: - kwargs["encoding"] = "utf-8" - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - with self.subTest(protocol=protocol, kwargs=kwargs): - with self.open(os_helper.TESTFN, **kwargs) as f: - with self.assertRaisesRegex(TypeError, msg): - pickle.dumps(f, protocol) - - @unittest.skipIf(support.is_emscripten, "Emscripten corrupts memory when writing to nonblocking fd") - def test_nonblock_pipe_write_bigbuf(self): - self._test_nonblock_pipe_write(16*1024) - - @unittest.skipIf(support.is_emscripten, "Emscripten corrupts memory when writing to nonblocking fd") - def test_nonblock_pipe_write_smallbuf(self): - self._test_nonblock_pipe_write(1024) - - @unittest.skipUnless(hasattr(os, 'set_blocking'), - 'os.set_blocking() required for this test') - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def _test_nonblock_pipe_write(self, bufsize): - sent = [] - received = [] - r, w = os.pipe() - os.set_blocking(r, False) - os.set_blocking(w, False) - - # To exercise all code paths in the C implementation we need - # to play with buffer sizes. For instance, if we choose a - # buffer size less than or equal to _PIPE_BUF (4096 on Linux) - # then we will never get a partial write of the buffer. - rf = self.open(r, mode='rb', closefd=True, buffering=bufsize) - wf = self.open(w, mode='wb', closefd=True, buffering=bufsize) - - with rf, wf: - for N in 9999, 73, 7574: - try: - i = 0 - while True: - msg = bytes([i % 26 + 97]) * N - sent.append(msg) - wf.write(msg) - i += 1 - - except self.BlockingIOError as e: - self.assertEqual(e.args[0], errno.EAGAIN) - self.assertEqual(e.args[2], e.characters_written) - sent[-1] = sent[-1][:e.characters_written] - received.append(rf.read()) - msg = b'BLOCKED' - wf.write(msg) - sent.append(msg) - - while True: - try: - wf.flush() - break - except self.BlockingIOError as e: - self.assertEqual(e.args[0], errno.EAGAIN) - self.assertEqual(e.args[2], e.characters_written) - self.assertEqual(e.characters_written, 0) - received.append(rf.read()) - - received += iter(rf.read, None) - - sent, received = b''.join(sent), b''.join(received) - self.assertEqual(sent, received) - self.assertTrue(wf.closed) - self.assertTrue(rf.closed) - - def test_create_fail(self): - # 'x' mode fails if file is existing - with self.open(os_helper.TESTFN, 'w', encoding="utf-8"): - pass - self.assertRaises(FileExistsError, self.open, os_helper.TESTFN, 'x', encoding="utf-8") - - def test_create_writes(self): - # 'x' mode opens for writing - with self.open(os_helper.TESTFN, 'xb') as f: - f.write(b"spam") - with self.open(os_helper.TESTFN, 'rb') as f: - self.assertEqual(b"spam", f.read()) - - def test_open_allargs(self): - # there used to be a buffer overflow in the parser for rawmode - self.assertRaises(ValueError, self.open, os_helper.TESTFN, 'rwax+', encoding="utf-8") - - def test_check_encoding_errors(self): - # bpo-37388: open() and TextIOWrapper must check encoding and errors - # arguments in dev mode - mod = self.io.__name__ - filename = __file__ - invalid = 'Boom, Shaka Laka, Boom!' - code = textwrap.dedent(f''' - import sys - from {mod} import open, TextIOWrapper - - try: - open({filename!r}, encoding={invalid!r}) - except LookupError: - pass - else: - sys.exit(21) - - try: - open({filename!r}, errors={invalid!r}) - except LookupError: - pass - else: - sys.exit(22) - - fp = open({filename!r}, "rb") - with fp: - try: - TextIOWrapper(fp, encoding={invalid!r}) - except LookupError: - pass - else: - sys.exit(23) - - try: - TextIOWrapper(fp, errors={invalid!r}) - except LookupError: - pass - else: - sys.exit(24) - - sys.exit(10) - ''') - proc = assert_python_failure('-X', 'dev', '-c', code) - self.assertEqual(proc.rc, 10, proc) - - def test_check_encoding_warning(self): - # PEP 597: Raise warning when encoding is not specified - # and sys.flags.warn_default_encoding is set. - mod = self.io.__name__ - filename = __file__ - code = textwrap.dedent(f'''\ - import sys - from {mod} import open, TextIOWrapper - import pathlib - - with open({filename!r}) as f: # line 5 - pass - - pathlib.Path({filename!r}).read_text() # line 8 - ''') - proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code) - warnings = proc.err.splitlines() - self.assertEqual(len(warnings), 2) - self.assertStartsWith(warnings[0], b"<string>:5: EncodingWarning: ") - self.assertStartsWith(warnings[1], b"<string>:8: EncodingWarning: ") - - def test_text_encoding(self): - # PEP 597, bpo-47000. io.text_encoding() returns "locale" or "utf-8" - # based on sys.flags.utf8_mode - code = "import io; print(io.text_encoding(None))" - - proc = assert_python_ok('-X', 'utf8=0', '-c', code) - self.assertEqual(b"locale", proc.out.strip()) - - proc = assert_python_ok('-X', 'utf8=1', '-c', code) - self.assertEqual(b"utf-8", proc.out.strip()) - - -class CMiscIOTest(MiscIOTest): - io = io - name_of_module = "io", "_io" - extra_exported = "BlockingIOError", - - def test_readinto_buffer_overflow(self): - # Issue #18025 - class BadReader(self.io.BufferedIOBase): - def read(self, n=-1): - return b'x' * 10**6 - bufio = BadReader() - b = bytearray(2) - self.assertRaises(ValueError, bufio.readinto, b) - - def check_daemon_threads_shutdown_deadlock(self, stream_name): - # Issue #23309: deadlocks at shutdown should be avoided when a - # daemon thread and the main thread both write to a file. - code = """if 1: - import sys - import time - import threading - from test.support import SuppressCrashReport - - file = sys.{stream_name} - - def run(): - while True: - file.write('.') - file.flush() - - crash = SuppressCrashReport() - crash.__enter__() - # don't call __exit__(): the crash occurs at Python shutdown - - thread = threading.Thread(target=run) - thread.daemon = True - thread.start() - - time.sleep(0.5) - file.write('!') - file.flush() - """.format_map(locals()) - res, _ = run_python_until_end("-c", code) - err = res.err.decode() - if res.rc != 0: - # Failure: should be a fatal error - pattern = (r"Fatal Python error: _enter_buffered_busy: " - r"could not acquire lock " - r"for <(_io\.)?BufferedWriter name='<{stream_name}>'> " - r"at interpreter shutdown, possibly due to " - r"daemon threads".format_map(locals())) - self.assertRegex(err, pattern) - else: - self.assertFalse(err.strip('.!')) - - @threading_helper.requires_working_threading() - @support.requires_resource('walltime') - def test_daemon_threads_shutdown_stdout_deadlock(self): - self.check_daemon_threads_shutdown_deadlock('stdout') - - @threading_helper.requires_working_threading() - @support.requires_resource('walltime') - def test_daemon_threads_shutdown_stderr_deadlock(self): - self.check_daemon_threads_shutdown_deadlock('stderr') - - -class PyMiscIOTest(MiscIOTest): - io = pyio - name_of_module = "_pyio", "io" - extra_exported = "BlockingIOError", "open_code", - not_exported = "valid_seek_flags", - - -@unittest.skipIf(os.name == 'nt', 'POSIX signals required for this test.') -class SignalsTest(unittest.TestCase): - - def setUp(self): - self.oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt) - - def tearDown(self): - signal.signal(signal.SIGALRM, self.oldalrm) - - def alarm_interrupt(self, sig, frame): - 1/0 - - def check_interrupted_write(self, item, bytes, **fdopen_kwargs): - """Check that a partial write, when it gets interrupted, properly - invokes the signal handler, and bubbles up the exception raised - in the latter.""" - - # XXX This test has three flaws that appear when objects are - # XXX not reference counted. - - # - if wio.write() happens to trigger a garbage collection, - # the signal exception may be raised when some __del__ - # method is running; it will not reach the assertRaises() - # call. - - # - more subtle, if the wio object is not destroyed at once - # and survives this function, the next opened file is likely - # to have the same fileno (since the file descriptor was - # actively closed). When wio.__del__ is finally called, it - # will close the other's test file... To trigger this with - # CPython, try adding "global wio" in this function. - - # - This happens only for streams created by the _pyio module, - # because a wio.close() that fails still consider that the - # file needs to be closed again. You can try adding an - # "assert wio.closed" at the end of the function. - - # Fortunately, a little gc.collect() seems to be enough to - # work around all these issues. - support.gc_collect() # For PyPy or other GCs. - - read_results = [] - def _read(): - s = os.read(r, 1) - read_results.append(s) - - t = threading.Thread(target=_read) - t.daemon = True - r, w = os.pipe() - fdopen_kwargs["closefd"] = False - large_data = item * (support.PIPE_MAX_SIZE // len(item) + 1) - try: - wio = self.io.open(w, **fdopen_kwargs) - if hasattr(signal, 'pthread_sigmask'): - # create the thread with SIGALRM signal blocked - signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGALRM]) - t.start() - signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGALRM]) - else: - t.start() - - # Fill the pipe enough that the write will be blocking. - # It will be interrupted by the timer armed above. Since the - # other thread has read one byte, the low-level write will - # return with a successful (partial) result rather than an EINTR. - # The buffered IO layer must check for pending signal - # handlers, which in this case will invoke alarm_interrupt(). - signal.alarm(1) - try: - self.assertRaises(ZeroDivisionError, wio.write, large_data) - finally: - signal.alarm(0) - t.join() - # We got one byte, get another one and check that it isn't a - # repeat of the first one. - read_results.append(os.read(r, 1)) - self.assertEqual(read_results, [bytes[0:1], bytes[1:2]]) - finally: - os.close(w) - os.close(r) - # This is deliberate. If we didn't close the file descriptor - # before closing wio, wio would try to flush its internal - # buffer, and block again. - try: - wio.close() - except OSError as e: - if e.errno != errno.EBADF: - raise - - @requires_alarm - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_interrupted_write_unbuffered(self): - self.check_interrupted_write(b"xy", b"xy", mode="wb", buffering=0) - - @requires_alarm - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_interrupted_write_buffered(self): - self.check_interrupted_write(b"xy", b"xy", mode="wb") - - @requires_alarm - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_interrupted_write_text(self): - self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii") - - @support.no_tracing - def check_reentrant_write(self, data, **fdopen_kwargs): - def on_alarm(*args): - # Will be called reentrantly from the same thread - wio.write(data) - 1/0 - signal.signal(signal.SIGALRM, on_alarm) - r, w = os.pipe() - wio = self.io.open(w, **fdopen_kwargs) - try: - signal.alarm(1) - # Either the reentrant call to wio.write() fails with RuntimeError, - # or the signal handler raises ZeroDivisionError. - with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: - while 1: - for i in range(100): - wio.write(data) - wio.flush() - # Make sure the buffer doesn't fill up and block further writes - os.read(r, len(data) * 100) - exc = cm.exception - if isinstance(exc, RuntimeError): - self.assertStartsWith(str(exc), "reentrant call") - finally: - signal.alarm(0) - wio.close() - os.close(r) - - @requires_alarm - def test_reentrant_write_buffered(self): - self.check_reentrant_write(b"xy", mode="wb") - - @requires_alarm - def test_reentrant_write_text(self): - self.check_reentrant_write("xy", mode="w", encoding="ascii") - - def check_interrupted_read_retry(self, decode, **fdopen_kwargs): - """Check that a buffered read, when it gets interrupted (either - returning a partial result or EINTR), properly invokes the signal - handler and retries if the latter returned successfully.""" - r, w = os.pipe() - fdopen_kwargs["closefd"] = False - def alarm_handler(sig, frame): - os.write(w, b"bar") - signal.signal(signal.SIGALRM, alarm_handler) - try: - rio = self.io.open(r, **fdopen_kwargs) - os.write(w, b"foo") - signal.alarm(1) - # Expected behaviour: - # - first raw read() returns partial b"foo" - # - second raw read() returns EINTR - # - third raw read() returns b"bar" - self.assertEqual(decode(rio.read(6)), "foobar") - finally: - signal.alarm(0) - rio.close() - os.close(w) - os.close(r) - - @requires_alarm - @support.requires_resource('walltime') - def test_interrupted_read_retry_buffered(self): - self.check_interrupted_read_retry(lambda x: x.decode('latin1'), - mode="rb") - - @requires_alarm - @support.requires_resource('walltime') - def test_interrupted_read_retry_text(self): - self.check_interrupted_read_retry(lambda x: x, - mode="r", encoding="latin1") - - def check_interrupted_write_retry(self, item, **fdopen_kwargs): - """Check that a buffered write, when it gets interrupted (either - returning a partial result or EINTR), properly invokes the signal - handler and retries if the latter returned successfully.""" - select = import_helper.import_module("select") - - # A quantity that exceeds the buffer size of an anonymous pipe's - # write end. - N = support.PIPE_MAX_SIZE - r, w = os.pipe() - fdopen_kwargs["closefd"] = False - - # We need a separate thread to read from the pipe and allow the - # write() to finish. This thread is started after the SIGALRM is - # received (forcing a first EINTR in write()). - read_results = [] - write_finished = False - error = None - def _read(): - try: - while not write_finished: - while r in select.select([r], [], [], 1.0)[0]: - s = os.read(r, 1024) - read_results.append(s) - except BaseException as exc: - nonlocal error - error = exc - t = threading.Thread(target=_read) - t.daemon = True - def alarm1(sig, frame): - signal.signal(signal.SIGALRM, alarm2) - signal.alarm(1) - def alarm2(sig, frame): - t.start() - - large_data = item * N - signal.signal(signal.SIGALRM, alarm1) - try: - wio = self.io.open(w, **fdopen_kwargs) - signal.alarm(1) - # Expected behaviour: - # - first raw write() is partial (because of the limited pipe buffer - # and the first alarm) - # - second raw write() returns EINTR (because of the second alarm) - # - subsequent write()s are successful (either partial or complete) - written = wio.write(large_data) - self.assertEqual(N, written) - - wio.flush() - write_finished = True - t.join() - - self.assertIsNone(error) - self.assertEqual(N, sum(len(x) for x in read_results)) - finally: - signal.alarm(0) - write_finished = True - os.close(w) - os.close(r) - # This is deliberate. If we didn't close the file descriptor - # before closing wio, wio would try to flush its internal - # buffer, and could block (in case of failure). - try: - wio.close() - except OSError as e: - if e.errno != errno.EBADF: - raise - - @requires_alarm - @support.requires_resource('walltime') - def test_interrupted_write_retry_buffered(self): - self.check_interrupted_write_retry(b"x", mode="wb") - - @requires_alarm - @support.requires_resource('walltime') - def test_interrupted_write_retry_text(self): - self.check_interrupted_write_retry("x", mode="w", encoding="latin1") - - -class CSignalsTest(SignalsTest): - io = io - -class PySignalsTest(SignalsTest): - io = pyio - - # Handling reentrancy issues would slow down _pyio even more, so the - # tests are disabled. - test_reentrant_write_buffered = None - test_reentrant_write_text = None - - -class ProtocolsTest(unittest.TestCase): - class MyReader: - def read(self, sz=-1): - return b"" - - class MyWriter: - def write(self, b: bytes): - pass - - def test_reader_subclass(self): - self.assertIsSubclass(MyReader, io.Reader[bytes]) - self.assertNotIsSubclass(str, io.Reader[bytes]) - - def test_writer_subclass(self): - self.assertIsSubclass(MyWriter, io.Writer[bytes]) - self.assertNotIsSubclass(str, io.Writer[bytes]) - - -def load_tests(loader, tests, pattern): - tests = (CIOTest, PyIOTest, APIMismatchTest, - CBufferedReaderTest, PyBufferedReaderTest, - CBufferedWriterTest, PyBufferedWriterTest, - CBufferedRWPairTest, PyBufferedRWPairTest, - CBufferedRandomTest, PyBufferedRandomTest, - StatefulIncrementalDecoderTest, - CIncrementalNewlineDecoderTest, PyIncrementalNewlineDecoderTest, - CTextIOWrapperTest, PyTextIOWrapperTest, - CMiscIOTest, PyMiscIOTest, - CSignalsTest, PySignalsTest, TestIOCTypes, - ) - - # Put the namespaces of the IO module we are testing and some useful mock - # classes in the __dict__ of each test. - mocks = (MockRawIO, MisbehavedRawIO, MockFileIO, CloseFailureIO, - MockNonBlockWriterIO, MockUnseekableIO, MockRawIOWithoutRead, - SlowFlushRawIO, MockCharPseudoDevFileIO) - all_members = io.__all__ - c_io_ns = {name : getattr(io, name) for name in all_members} - py_io_ns = {name : getattr(pyio, name) for name in all_members} - globs = globals() - c_io_ns.update((x.__name__, globs["C" + x.__name__]) for x in mocks) - py_io_ns.update((x.__name__, globs["Py" + x.__name__]) for x in mocks) - for test in tests: - if test.__name__.startswith("C"): - for name, obj in c_io_ns.items(): - setattr(test, name, obj) - test.is_C = True - elif test.__name__.startswith("Py"): - for name, obj in py_io_ns.items(): - setattr(test, name, obj) - test.is_C = False - - suite = loader.suiteClass() - for test in tests: - suite.addTest(loader.loadTestsFromTestCase(test)) - return suite - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_io/__init__.py b/Lib/test/test_io/__init__.py new file mode 100644 index 00000000000..c94fad3e779 --- /dev/null +++ b/Lib/test/test_io/__init__.py @@ -0,0 +1,28 @@ +"""Tests for the io module and its implementations (_io and _pyio) + +Tests are split across multiple files to increase +parallelism and focus on specific implementation pieces. + +* test_io + * test_bufferedio - tests file buffering + * test_memoryio - tests BytesIO and StringIO + * test_fileio - tests FileIO + * test_file - tests the file interface + * test_general - tests everything else in the io module + * test_univnewlines - tests universal newline support + * test_largefile - tests operations on a file greater than 2**32 bytes + (only enabled with -ulargefile) +* test_free_threading/test_io - tests thread safety of io objects + +.. attention:: + When writing tests for io, it's important to test both the C and Python + implementations. This is usually done by writing a base test that refers to + the type it is testing as an attribute. Then it provides custom subclasses to + test both implementations. This directory contains lots of examples. +""" + +import os +from test.support import load_package_tests + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_io/__main__.py b/Lib/test/test_io/__main__.py new file mode 100644 index 00000000000..40a23a297ec --- /dev/null +++ b/Lib/test/test_io/__main__.py @@ -0,0 +1,4 @@ +from . import load_tests +import unittest + +unittest.main() diff --git a/Lib/test/test_io/test_bufferedio.py b/Lib/test/test_io/test_bufferedio.py new file mode 100644 index 00000000000..3278665bdc9 --- /dev/null +++ b/Lib/test/test_io/test_bufferedio.py @@ -0,0 +1,1548 @@ +import array +import pickle +import random +import sys +import threading +import time +import unittest +import warnings +import weakref +from collections import deque, UserList +from itertools import cycle, count +from test import support +from test.support import os_helper, threading_helper +from .utils import byteslike, CTestCase, PyTestCase + + +import io # C implementation. +import _pyio as pyio # Python implementation. + + +class CommonBufferedTests: + # Tests common to BufferedReader, BufferedWriter and BufferedRandom + + def test_detach(self): + raw = self.MockRawIO() + buf = self.tp(raw) + self.assertIs(buf.detach(), raw) + self.assertRaises(ValueError, buf.detach) + + repr(buf) # Should still work + + def test_fileno(self): + rawio = self.MockRawIO() + bufio = self.tp(rawio) + + self.assertEqual(42, bufio.fileno()) + + def test_invalid_args(self): + rawio = self.MockRawIO() + bufio = self.tp(rawio) + # Invalid whence + self.assertRaises(ValueError, bufio.seek, 0, -1) + self.assertRaises(ValueError, bufio.seek, 0, 9) + + def test_override_destructor(self): + tp = self.tp + record = [] + class MyBufferedIO(tp): + def __del__(self): + record.append(1) + try: + f = super().__del__ + except AttributeError: + pass + else: + f() + def close(self): + record.append(2) + super().close() + def flush(self): + record.append(3) + super().flush() + rawio = self.MockRawIO() + bufio = MyBufferedIO(rawio) + del bufio + support.gc_collect() + self.assertEqual(record, [1, 2, 3]) + + def test_context_manager(self): + # Test usability as a context manager + rawio = self.MockRawIO() + bufio = self.tp(rawio) + def _with(): + with bufio: + pass + _with() + # bufio should now be closed, and using it a second time should raise + # a ValueError. + self.assertRaises(ValueError, _with) + + def test_error_through_destructor(self): + # Test that the exception state is not modified by a destructor, + # even if close() fails. + rawio = self.CloseFailureIO() + with support.catch_unraisable_exception() as cm: + with self.assertRaises(AttributeError): + self.tp(rawio).xyzzy + + self.assertEqual(cm.unraisable.exc_type, OSError) + + def test_repr(self): + raw = self.MockRawIO() + b = self.tp(raw) + clsname = r"(%s\.)?%s" % (self.tp.__module__, self.tp.__qualname__) + self.assertRegex(repr(b), "<%s>" % clsname) + raw.name = "dummy" + self.assertRegex(repr(b), "<%s name='dummy'>" % clsname) + raw.name = b"dummy" + self.assertRegex(repr(b), "<%s name=b'dummy'>" % clsname) + + def test_recursive_repr(self): + # Issue #25455 + raw = self.MockRawIO() + b = self.tp(raw) + with support.swap_attr(raw, 'name', b), support.infinite_recursion(25): + with self.assertRaises(RuntimeError): + repr(b) # Should not crash + + def test_flush_error_on_close(self): + # Test that buffered file is closed despite failed flush + # and that flush() is called before file closed. + raw = self.MockRawIO() + closed = [] + def bad_flush(): + closed[:] = [b.closed, raw.closed] + raise OSError() + raw.flush = bad_flush + b = self.tp(raw) + self.assertRaises(OSError, b.close) # exception not swallowed + self.assertTrue(b.closed) + self.assertTrue(raw.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) + raw.flush = lambda: None # break reference loop + + def test_close_error_on_close(self): + raw = self.MockRawIO() + def bad_flush(): + raise OSError('flush') + def bad_close(): + raise OSError('close') + raw.close = bad_close + b = self.tp(raw) + b.flush = bad_flush + with self.assertRaises(OSError) as err: # exception not swallowed + b.close() + self.assertEqual(err.exception.args, ('close',)) + self.assertIsInstance(err.exception.__context__, OSError) + self.assertEqual(err.exception.__context__.args, ('flush',)) + self.assertFalse(b.closed) + + # Silence destructor error + raw.close = lambda: None + b.flush = lambda: None + + def test_nonnormalized_close_error_on_close(self): + # Issue #21677 + raw = self.MockRawIO() + def bad_flush(): + raise non_existing_flush + def bad_close(): + raise non_existing_close + raw.close = bad_close + b = self.tp(raw) + b.flush = bad_flush + with self.assertRaises(NameError) as err: # exception not swallowed + b.close() + self.assertIn('non_existing_close', str(err.exception)) + self.assertIsInstance(err.exception.__context__, NameError) + self.assertIn('non_existing_flush', str(err.exception.__context__)) + self.assertFalse(b.closed) + + # Silence destructor error + b.flush = lambda: None + raw.close = lambda: None + + def test_multi_close(self): + raw = self.MockRawIO() + b = self.tp(raw) + b.close() + b.close() + b.close() + self.assertRaises(ValueError, b.flush) + + def test_unseekable(self): + bufio = self.tp(self.MockUnseekableIO(b"A" * 10)) + self.assertRaises(self.UnsupportedOperation, bufio.tell) + self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) + + def test_readonly_attributes(self): + raw = self.MockRawIO() + buf = self.tp(raw) + x = self.MockRawIO() + with self.assertRaises(AttributeError): + buf.raw = x + + def test_pickling_subclass(self): + global MyBufferedIO + class MyBufferedIO(self.tp): + def __init__(self, raw, tag): + super().__init__(raw) + self.tag = tag + def __getstate__(self): + return self.tag, self.raw.getvalue() + def __setstate__(slf, state): + tag, value = state + slf.__init__(self.BytesIO(value), tag) + + raw = self.BytesIO(b'data') + buf = MyBufferedIO(raw, tag='ham') + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + pickled = pickle.dumps(buf, proto) + newbuf = pickle.loads(pickled) + self.assertEqual(newbuf.raw.getvalue(), b'data') + self.assertEqual(newbuf.tag, 'ham') + del MyBufferedIO + + +class SizeofTest: + + @support.cpython_only + def test_sizeof(self): + bufsize1 = 4096 + bufsize2 = 8192 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize1) + size = sys.getsizeof(bufio) - bufsize1 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize2) + self.assertEqual(sys.getsizeof(bufio), size + bufsize2) + + @support.cpython_only + def test_buffer_freeing(self) : + bufsize = 4096 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize) + size = sys.getsizeof(bufio) - bufsize + bufio.close() + self.assertEqual(sys.getsizeof(bufio), size) + +class BufferedReaderTest(CommonBufferedTests): + read_mode = "rb" + + def test_constructor(self): + rawio = self.MockRawIO([b"abc"]) + bufio = self.tp(rawio) + bufio.__init__(rawio) + bufio.__init__(rawio, buffer_size=1024) + bufio.__init__(rawio, buffer_size=16) + self.assertEqual(b"abc", bufio.read()) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) + rawio = self.MockRawIO([b"abc"]) + bufio.__init__(rawio) + self.assertEqual(b"abc", bufio.read()) + + def test_uninitialized(self): + bufio = self.tp.__new__(self.tp) + del bufio + bufio = self.tp.__new__(self.tp) + self.assertRaisesRegex((ValueError, AttributeError), + 'uninitialized|has no attribute', + bufio.read, 0) + bufio.__init__(self.MockRawIO()) + self.assertEqual(bufio.read(0), b'') + + def test_read(self): + for arg in (None, 7): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + self.assertEqual(b"abcdefg", bufio.read(arg)) + # Invalid args + self.assertRaises(ValueError, bufio.read, -2) + + def test_read1(self): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + self.assertEqual(b"a", bufio.read(1)) + self.assertEqual(b"b", bufio.read1(1)) + self.assertEqual(rawio._reads, 1) + self.assertEqual(b"", bufio.read1(0)) + self.assertEqual(b"c", bufio.read1(100)) + self.assertEqual(rawio._reads, 1) + self.assertEqual(b"d", bufio.read1(100)) + self.assertEqual(rawio._reads, 2) + self.assertEqual(b"efg", bufio.read1(100)) + self.assertEqual(rawio._reads, 3) + self.assertEqual(b"", bufio.read1(100)) + self.assertEqual(rawio._reads, 4) + + def test_read1_arbitrary(self): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + self.assertEqual(b"a", bufio.read(1)) + self.assertEqual(b"bc", bufio.read1()) + self.assertEqual(b"d", bufio.read1()) + self.assertEqual(b"efg", bufio.read1(-1)) + self.assertEqual(rawio._reads, 3) + self.assertEqual(b"", bufio.read1()) + self.assertEqual(rawio._reads, 4) + + def test_readinto(self): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + b = bytearray(2) + self.assertEqual(bufio.readinto(b), 2) + self.assertEqual(b, b"ab") + self.assertEqual(bufio.readinto(b), 2) + self.assertEqual(b, b"cd") + self.assertEqual(bufio.readinto(b), 2) + self.assertEqual(b, b"ef") + self.assertEqual(bufio.readinto(b), 1) + self.assertEqual(b, b"gf") + self.assertEqual(bufio.readinto(b), 0) + self.assertEqual(b, b"gf") + rawio = self.MockRawIO((b"abc", None)) + bufio = self.tp(rawio) + self.assertEqual(bufio.readinto(b), 2) + self.assertEqual(b, b"ab") + self.assertEqual(bufio.readinto(b), 1) + self.assertEqual(b, b"cb") + + def test_readinto1(self): + buffer_size = 10 + rawio = self.MockRawIO((b"abc", b"de", b"fgh", b"jkl")) + bufio = self.tp(rawio, buffer_size=buffer_size) + b = bytearray(2) + self.assertEqual(bufio.peek(3), b'abc') + self.assertEqual(rawio._reads, 1) + self.assertEqual(bufio.readinto1(b), 2) + self.assertEqual(b, b"ab") + self.assertEqual(rawio._reads, 1) + self.assertEqual(bufio.readinto1(b), 1) + self.assertEqual(b[:1], b"c") + self.assertEqual(rawio._reads, 1) + self.assertEqual(bufio.readinto1(b), 2) + self.assertEqual(b, b"de") + self.assertEqual(rawio._reads, 2) + b = bytearray(2*buffer_size) + self.assertEqual(bufio.peek(3), b'fgh') + self.assertEqual(rawio._reads, 3) + self.assertEqual(bufio.readinto1(b), 6) + self.assertEqual(b[:6], b"fghjkl") + self.assertEqual(rawio._reads, 4) + + def test_readinto_array(self): + buffer_size = 60 + data = b"a" * 26 + rawio = self.MockRawIO((data,)) + bufio = self.tp(rawio, buffer_size=buffer_size) + + # Create an array with element size > 1 byte + b = array.array('i', b'x' * 32) + assert len(b) != 16 + + # Read into it. We should get as many *bytes* as we can fit into b + # (which is more than the number of elements) + n = bufio.readinto(b) + self.assertGreater(n, len(b)) + + # Check that old contents of b are preserved + bm = memoryview(b).cast('B') + self.assertLess(n, len(bm)) + self.assertEqual(bm[:n], data[:n]) + self.assertEqual(bm[n:], b'x' * (len(bm[n:]))) + + def test_readinto1_array(self): + buffer_size = 60 + data = b"a" * 26 + rawio = self.MockRawIO((data,)) + bufio = self.tp(rawio, buffer_size=buffer_size) + + # Create an array with element size > 1 byte + b = array.array('i', b'x' * 32) + assert len(b) != 16 + + # Read into it. We should get as many *bytes* as we can fit into b + # (which is more than the number of elements) + n = bufio.readinto1(b) + self.assertGreater(n, len(b)) + + # Check that old contents of b are preserved + bm = memoryview(b).cast('B') + self.assertLess(n, len(bm)) + self.assertEqual(bm[:n], data[:n]) + self.assertEqual(bm[n:], b'x' * (len(bm[n:]))) + + def test_readlines(self): + def bufio(): + rawio = self.MockRawIO((b"abc\n", b"d\n", b"ef")) + return self.tp(rawio) + self.assertEqual(bufio().readlines(), [b"abc\n", b"d\n", b"ef"]) + self.assertEqual(bufio().readlines(5), [b"abc\n", b"d\n"]) + self.assertEqual(bufio().readlines(None), [b"abc\n", b"d\n", b"ef"]) + + def test_buffering(self): + data = b"abcdefghi" + dlen = len(data) + + tests = [ + [ 100, [ 3, 1, 4, 8 ], [ dlen, 0 ] ], + [ 100, [ 3, 3, 3], [ dlen ] ], + [ 4, [ 1, 2, 4, 2 ], [ 4, 4, 1 ] ], + ] + + for bufsize, buf_read_sizes, raw_read_sizes in tests: + rawio = self.MockFileIO(data) + bufio = self.tp(rawio, buffer_size=bufsize) + pos = 0 + for nbytes in buf_read_sizes: + self.assertEqual(bufio.read(nbytes), data[pos:pos+nbytes]) + pos += nbytes + # this is mildly implementation-dependent + self.assertEqual(rawio.read_history, raw_read_sizes) + + def test_read_non_blocking(self): + # Inject some None's in there to simulate EWOULDBLOCK + rawio = self.MockRawIO((b"abc", b"d", None, b"efg", None, None, None)) + bufio = self.tp(rawio) + self.assertEqual(b"abcd", bufio.read(6)) + self.assertEqual(b"e", bufio.read(1)) + self.assertEqual(b"fg", bufio.read()) + self.assertEqual(b"", bufio.peek(1)) + self.assertIsNone(bufio.read()) + self.assertEqual(b"", bufio.read()) + + rawio = self.MockRawIO((b"a", None, None)) + self.assertEqual(b"a", rawio.readall()) + self.assertIsNone(rawio.readall()) + + def test_read_past_eof(self): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + + self.assertEqual(b"abcdefg", bufio.read(9000)) + + def test_read_all(self): + rawio = self.MockRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + + self.assertEqual(b"abcdefg", bufio.read()) + + @threading_helper.requires_working_threading() + @support.requires_resource('cpu') + def test_threads(self): + try: + # Write out many bytes with exactly the same number of 0's, + # 1's... 255's. This will help us check that concurrent reading + # doesn't duplicate or forget contents. + N = 1000 + l = list(range(256)) * N + random.shuffle(l) + s = bytes(bytearray(l)) + with self.open(os_helper.TESTFN, "wb") as f: + f.write(s) + with self.open(os_helper.TESTFN, self.read_mode, buffering=0) as raw: + bufio = self.tp(raw, 8) + errors = [] + results = [] + def f(): + try: + # Intra-buffer read then buffer-flushing read + for n in cycle([1, 19]): + s = bufio.read(n) + if not s: + break + # list.append() is atomic + results.append(s) + except Exception as e: + errors.append(e) + raise + threads = [threading.Thread(target=f) for x in range(20)] + with threading_helper.start_threads(threads): + time.sleep(0.02) # yield + self.assertFalse(errors, + "the following exceptions were caught: %r" % errors) + s = b''.join(results) + for i in range(256): + c = bytes(bytearray([i])) + self.assertEqual(s.count(c), N) + finally: + os_helper.unlink(os_helper.TESTFN) + + def test_unseekable(self): + bufio = self.tp(self.MockUnseekableIO(b"A" * 10)) + self.assertRaises(self.UnsupportedOperation, bufio.tell) + self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) + bufio.read(1) + self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) + self.assertRaises(self.UnsupportedOperation, bufio.tell) + + def test_misbehaved_io(self): + rawio = self.MisbehavedRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + self.assertRaises(OSError, bufio.seek, 0) + self.assertRaises(OSError, bufio.tell) + + # Silence destructor error + bufio.close = lambda: None + + def test_no_extraneous_read(self): + # Issue #9550; when the raw IO object has satisfied the read request, + # we should not issue any additional reads, otherwise it may block + # (e.g. socket). + bufsize = 16 + for n in (2, bufsize - 1, bufsize, bufsize + 1, bufsize * 2): + rawio = self.MockRawIO([b"x" * n]) + bufio = self.tp(rawio, bufsize) + self.assertEqual(bufio.read(n), b"x" * n) + # Simple case: one raw read is enough to satisfy the request. + self.assertEqual(rawio._extraneous_reads, 0, + "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) + # A more complex case where two raw reads are needed to satisfy + # the request. + rawio = self.MockRawIO([b"x" * (n - 1), b"x"]) + bufio = self.tp(rawio, bufsize) + self.assertEqual(bufio.read(n), b"x" * n) + self.assertEqual(rawio._extraneous_reads, 0, + "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) + + def test_read_on_closed(self): + # Issue #23796 + b = self.BufferedReader(self.BytesIO(b"12")) + b.read(1) + b.close() + with self.subTest('peek'): + self.assertRaises(ValueError, b.peek) + with self.subTest('read1'): + self.assertRaises(ValueError, b.read1, 1) + with self.subTest('read'): + self.assertRaises(ValueError, b.read) + with self.subTest('readinto'): + self.assertRaises(ValueError, b.readinto, bytearray()) + with self.subTest('readinto1'): + self.assertRaises(ValueError, b.readinto1, bytearray()) + with self.subTest('flush'): + self.assertRaises(ValueError, b.flush) + with self.subTest('truncate'): + self.assertRaises(ValueError, b.truncate) + with self.subTest('seek'): + self.assertRaises(ValueError, b.seek, 0) + + def test_truncate_on_read_only(self): + rawio = self.MockFileIO(b"abc") + bufio = self.tp(rawio) + self.assertFalse(bufio.writable()) + self.assertRaises(self.UnsupportedOperation, bufio.truncate) + self.assertRaises(self.UnsupportedOperation, bufio.truncate, 0) + + def test_tell_character_device_file(self): + # GH-95782 + # For the (former) bug in BufferedIO to manifest, the wrapped IO obj + # must be able to produce at least 2 bytes. + raw = self.MockCharPseudoDevFileIO(b"12") + buf = self.tp(raw) + self.assertEqual(buf.tell(), 0) + self.assertEqual(buf.read(1), b"1") + self.assertEqual(buf.tell(), 0) + + def test_seek_character_device_file(self): + raw = self.MockCharPseudoDevFileIO(b"12") + buf = self.tp(raw) + self.assertEqual(buf.seek(0, io.SEEK_CUR), 0) + self.assertEqual(buf.seek(1, io.SEEK_SET), 0) + self.assertEqual(buf.seek(0, io.SEEK_CUR), 0) + self.assertEqual(buf.read(1), b"1") + + # In the C implementation, tell() sets the BufferedIO's abs_pos to 0, + # which means that the next seek() could return a negative offset if it + # does not sanity-check: + self.assertEqual(buf.tell(), 0) + self.assertEqual(buf.seek(0, io.SEEK_CUR), 0) + + +class CBufferedReaderTest(BufferedReaderTest, SizeofTest, CTestCase): + tp = io.BufferedReader + + def test_initialization(self): + rawio = self.MockRawIO([b"abc"]) + bufio = self.tp(rawio) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) + self.assertRaises(ValueError, bufio.read) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) + self.assertRaises(ValueError, bufio.read) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) + self.assertRaises(ValueError, bufio.read) + + def test_misbehaved_io_read(self): + rawio = self.MisbehavedRawIO((b"abc", b"d", b"efg")) + bufio = self.tp(rawio) + # _pyio.BufferedReader seems to implement reading different, so that + # checking this is not so easy. + self.assertRaises(OSError, bufio.read, 10) + + def test_garbage_collection(self): + # C BufferedReader objects are collected. + # The Python version has __del__, so it ends into gc.garbage instead + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + # Note that using warnings_helper.check_warnings() will keep the + # file alive due to the `source` argument to warn(). So, use + # catch_warnings() instead. + with warnings.catch_warnings(): + warnings.simplefilter("ignore", ResourceWarning) + rawio = self.FileIO(os_helper.TESTFN, "w+b") + f = self.tp(rawio) + f.f = f + wr = weakref.ref(f) + del f + support.gc_collect() + self.assertIsNone(wr(), wr) + + def test_args_error(self): + # Issue #17275 + with self.assertRaisesRegex(TypeError, "BufferedReader"): + self.tp(self.BytesIO(), 1024, 1024, 1024) + + def test_bad_readinto_value(self): + rawio = self.tp(self.BytesIO(b"12")) + rawio.readinto = lambda buf: -1 + bufio = self.tp(rawio) + with self.assertRaises(OSError) as cm: + bufio.readline() + self.assertIsNone(cm.exception.__cause__) + + def test_bad_readinto_type(self): + rawio = self.tp(self.BytesIO(b"12")) + rawio.readinto = lambda buf: b'' + bufio = self.tp(rawio) + with self.assertRaises(OSError) as cm: + bufio.readline() + self.assertIsInstance(cm.exception.__cause__, TypeError) + + +class PyBufferedReaderTest(BufferedReaderTest, PyTestCase): + tp = pyio.BufferedReader + + +class BufferedWriterTest(CommonBufferedTests): + write_mode = "wb" + + def test_constructor(self): + rawio = self.MockRawIO() + bufio = self.tp(rawio) + bufio.__init__(rawio) + bufio.__init__(rawio, buffer_size=1024) + bufio.__init__(rawio, buffer_size=16) + self.assertEqual(3, bufio.write(b"abc")) + bufio.flush() + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) + bufio.__init__(rawio) + self.assertEqual(3, bufio.write(b"ghi")) + bufio.flush() + self.assertEqual(b"".join(rawio._write_stack), b"abcghi") + + def test_uninitialized(self): + bufio = self.tp.__new__(self.tp) + del bufio + bufio = self.tp.__new__(self.tp) + self.assertRaisesRegex((ValueError, AttributeError), + 'uninitialized|has no attribute', + bufio.write, b'') + bufio.__init__(self.MockRawIO()) + self.assertEqual(bufio.write(b''), 0) + + def test_detach_flush(self): + raw = self.MockRawIO() + buf = self.tp(raw) + buf.write(b"howdy!") + self.assertFalse(raw._write_stack) + buf.detach() + self.assertEqual(raw._write_stack, [b"howdy!"]) + + def test_write(self): + # Write to the buffered IO but don't overflow the buffer. + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + bufio.write(b"abc") + self.assertFalse(writer._write_stack) + buffer = bytearray(b"def") + bufio.write(buffer) + buffer[:] = b"***" # Overwrite our copy of the data + bufio.flush() + self.assertEqual(b"".join(writer._write_stack), b"abcdef") + + def test_write_overflow(self): + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + contents = b"abcdefghijklmnop" + for n in range(0, len(contents), 3): + bufio.write(contents[n:n+3]) + flushed = b"".join(writer._write_stack) + # At least (total - 8) bytes were implicitly flushed, perhaps more + # depending on the implementation. + self.assertStartsWith(flushed, contents[:-8]) + + def check_writes(self, intermediate_func): + # Lots of writes, test the flushed output is as expected. + contents = bytes(range(256)) * 1000 + n = 0 + writer = self.MockRawIO() + bufio = self.tp(writer, 13) + # Generator of write sizes: repeat each N 15 times then proceed to N+1 + def gen_sizes(): + for size in count(1): + for i in range(15): + yield size + sizes = gen_sizes() + while n < len(contents): + size = min(next(sizes), len(contents) - n) + self.assertEqual(bufio.write(contents[n:n+size]), size) + intermediate_func(bufio) + n += size + bufio.flush() + self.assertEqual(contents, b"".join(writer._write_stack)) + + def test_writes(self): + self.check_writes(lambda bufio: None) + + def test_writes_and_flushes(self): + self.check_writes(lambda bufio: bufio.flush()) + + def test_writes_and_seeks(self): + def _seekabs(bufio): + pos = bufio.tell() + bufio.seek(pos + 1, 0) + bufio.seek(pos - 1, 0) + bufio.seek(pos, 0) + self.check_writes(_seekabs) + def _seekrel(bufio): + pos = bufio.seek(0, 1) + bufio.seek(+1, 1) + bufio.seek(-1, 1) + bufio.seek(pos, 0) + self.check_writes(_seekrel) + + def test_writes_and_truncates(self): + self.check_writes(lambda bufio: bufio.truncate(bufio.tell())) + + def test_write_non_blocking(self): + raw = self.MockNonBlockWriterIO() + bufio = self.tp(raw, 8) + + self.assertEqual(bufio.write(b"abcd"), 4) + self.assertEqual(bufio.write(b"efghi"), 5) + # 1 byte will be written, the rest will be buffered + raw.block_on(b"k") + self.assertEqual(bufio.write(b"jklmn"), 5) + + # 8 bytes will be written, 8 will be buffered and the rest will be lost + raw.block_on(b"0") + try: + bufio.write(b"opqrwxyz0123456789") + except self.BlockingIOError as e: + written = e.characters_written + else: + self.fail("BlockingIOError should have been raised") + self.assertEqual(written, 16) + self.assertEqual(raw.pop_written(), + b"abcdefghijklmnopqrwxyz") + + self.assertEqual(bufio.write(b"ABCDEFGHI"), 9) + s = raw.pop_written() + # Previously buffered bytes were flushed + self.assertStartsWith(s, b"01234567A") + + def test_write_and_rewind(self): + raw = self.BytesIO() + bufio = self.tp(raw, 4) + self.assertEqual(bufio.write(b"abcdef"), 6) + self.assertEqual(bufio.tell(), 6) + bufio.seek(0, 0) + self.assertEqual(bufio.write(b"XY"), 2) + bufio.seek(6, 0) + self.assertEqual(raw.getvalue(), b"XYcdef") + self.assertEqual(bufio.write(b"123456"), 6) + bufio.flush() + self.assertEqual(raw.getvalue(), b"XYcdef123456") + + def test_flush(self): + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + bufio.write(b"abc") + bufio.flush() + self.assertEqual(b"abc", writer._write_stack[0]) + + def test_writelines(self): + l = [b'ab', b'cd', b'ef'] + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + bufio.writelines(l) + bufio.flush() + self.assertEqual(b''.join(writer._write_stack), b'abcdef') + + def test_writelines_userlist(self): + l = UserList([b'ab', b'cd', b'ef']) + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + bufio.writelines(l) + bufio.flush() + self.assertEqual(b''.join(writer._write_stack), b'abcdef') + + def test_writelines_error(self): + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + self.assertRaises(TypeError, bufio.writelines, [1, 2, 3]) + self.assertRaises(TypeError, bufio.writelines, None) + self.assertRaises(TypeError, bufio.writelines, 'abc') + + def test_destructor(self): + writer = self.MockRawIO() + bufio = self.tp(writer, 8) + bufio.write(b"abc") + del bufio + support.gc_collect() + self.assertEqual(b"abc", writer._write_stack[0]) + + def test_truncate(self): + # Truncate implicitly flushes the buffer. + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with self.open(os_helper.TESTFN, self.write_mode, buffering=0) as raw: + bufio = self.tp(raw, 8) + bufio.write(b"abcdef") + self.assertEqual(bufio.truncate(3), 3) + self.assertEqual(bufio.tell(), 6) + with self.open(os_helper.TESTFN, "rb", buffering=0) as f: + self.assertEqual(f.read(), b"abc") + + def test_truncate_after_write(self): + # Ensure that truncate preserves the file position after + # writes longer than the buffer size. + # Issue: https://bugs.python.org/issue32228 + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with self.open(os_helper.TESTFN, "wb") as f: + # Fill with some buffer + f.write(b'\x00' * 10000) + buffer_sizes = [8192, 4096, 200] + for buffer_size in buffer_sizes: + with self.open(os_helper.TESTFN, "r+b", buffering=buffer_size) as f: + f.write(b'\x00' * (buffer_size + 1)) + # After write write_pos and write_end are set to 0 + f.read(1) + # read operation makes sure that pos != raw_pos + f.truncate() + self.assertEqual(f.tell(), buffer_size + 2) + + @threading_helper.requires_working_threading() + @support.requires_resource('cpu') + def test_threads(self): + try: + # Write out many bytes from many threads and test they were + # all flushed. + N = 1000 + contents = bytes(range(256)) * N + sizes = cycle([1, 19]) + n = 0 + queue = deque() + while n < len(contents): + size = next(sizes) + queue.append(contents[n:n+size]) + n += size + del contents + # We use a real file object because it allows us to + # exercise situations where the GIL is released before + # writing the buffer to the raw streams. This is in addition + # to concurrency issues due to switching threads in the middle + # of Python code. + with self.open(os_helper.TESTFN, self.write_mode, buffering=0) as raw: + bufio = self.tp(raw, 8) + errors = [] + def f(): + try: + while True: + try: + s = queue.popleft() + except IndexError: + return + bufio.write(s) + except Exception as e: + errors.append(e) + raise + threads = [threading.Thread(target=f) for x in range(20)] + with threading_helper.start_threads(threads): + time.sleep(0.02) # yield + self.assertFalse(errors, + "the following exceptions were caught: %r" % errors) + bufio.close() + with self.open(os_helper.TESTFN, "rb") as f: + s = f.read() + for i in range(256): + self.assertEqual(s.count(bytes([i])), N) + finally: + os_helper.unlink(os_helper.TESTFN) + + def test_misbehaved_io(self): + rawio = self.MisbehavedRawIO() + bufio = self.tp(rawio, 5) + self.assertRaises(OSError, bufio.seek, 0) + self.assertRaises(OSError, bufio.tell) + self.assertRaises(OSError, bufio.write, b"abcdef") + + # Silence destructor error + bufio.close = lambda: None + + def test_max_buffer_size_removal(self): + with self.assertRaises(TypeError): + self.tp(self.MockRawIO(), 8, 12) + + def test_write_error_on_close(self): + raw = self.MockRawIO() + def bad_write(b): + raise OSError() + raw.write = bad_write + b = self.tp(raw) + b.write(b'spam') + self.assertRaises(OSError, b.close) # exception not swallowed + self.assertTrue(b.closed) + + @threading_helper.requires_working_threading() + def test_slow_close_from_thread(self): + # Issue #31976 + rawio = self.SlowFlushRawIO() + bufio = self.tp(rawio, 8) + t = threading.Thread(target=bufio.close) + t.start() + rawio.in_flush.wait() + self.assertRaises(ValueError, bufio.write, b'spam') + self.assertTrue(bufio.closed) + t.join() + + +class CBufferedWriterTest(BufferedWriterTest, SizeofTest, CTestCase): + tp = io.BufferedWriter + + def test_initialization(self): + rawio = self.MockRawIO() + bufio = self.tp(rawio) + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=0) + self.assertRaises(ValueError, bufio.write, b"def") + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-16) + self.assertRaises(ValueError, bufio.write, b"def") + self.assertRaises(ValueError, bufio.__init__, rawio, buffer_size=-1) + self.assertRaises(ValueError, bufio.write, b"def") + + def test_garbage_collection(self): + # C BufferedWriter objects are collected, and collecting them flushes + # all data to disk. + # The Python version has __del__, so it ends into gc.garbage instead + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + # Note that using warnings_helper.check_warnings() will keep the + # file alive due to the `source` argument to warn(). So, use + # catch_warnings() instead. + with warnings.catch_warnings(): + warnings.simplefilter("ignore", ResourceWarning) + rawio = self.FileIO(os_helper.TESTFN, "w+b") + f = self.tp(rawio) + f.write(b"123xxx") + f.x = f + wr = weakref.ref(f) + del f + support.gc_collect() + self.assertIsNone(wr(), wr) + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"123xxx") + + def test_args_error(self): + # Issue #17275 + with self.assertRaisesRegex(TypeError, "BufferedWriter"): + self.tp(self.BytesIO(), 1024, 1024, 1024) + + def test_non_boolean_closed_attr(self): + # gh-140650: check TypeError is raised + class MockRawIOWithoutClosed(self.MockRawIO): + closed = NotImplemented + + bufio = self.tp(MockRawIOWithoutClosed()) + self.assertRaises(TypeError, bufio.write, b"") + self.assertRaises(TypeError, bufio.flush) + self.assertRaises(TypeError, bufio.close) + + def test_closed_attr_raises(self): + class MockRawIOClosedRaises(self.MockRawIO): + @property + def closed(self): + raise ValueError("test") + + bufio = self.tp(MockRawIOClosedRaises()) + self.assertRaisesRegex(ValueError, "test", bufio.write, b"") + self.assertRaisesRegex(ValueError, "test", bufio.flush) + self.assertRaisesRegex(ValueError, "test", bufio.close) + + +class PyBufferedWriterTest(BufferedWriterTest, PyTestCase): + tp = pyio.BufferedWriter + +class BufferedRWPairTest: + + def test_constructor(self): + pair = self.tp(self.MockRawIO(), self.MockRawIO()) + self.assertFalse(pair.closed) + + def test_uninitialized(self): + pair = self.tp.__new__(self.tp) + del pair + pair = self.tp.__new__(self.tp) + self.assertRaisesRegex((ValueError, AttributeError), + 'uninitialized|has no attribute', + pair.read, 0) + self.assertRaisesRegex((ValueError, AttributeError), + 'uninitialized|has no attribute', + pair.write, b'') + pair.__init__(self.MockRawIO(), self.MockRawIO()) + self.assertEqual(pair.read(0), b'') + self.assertEqual(pair.write(b''), 0) + + def test_detach(self): + pair = self.tp(self.MockRawIO(), self.MockRawIO()) + self.assertRaises(self.UnsupportedOperation, pair.detach) + + def test_constructor_max_buffer_size_removal(self): + with self.assertRaises(TypeError): + self.tp(self.MockRawIO(), self.MockRawIO(), 8, 12) + + def test_constructor_with_not_readable(self): + class NotReadable(self.MockRawIO): + def readable(self): + return False + + self.assertRaises(OSError, self.tp, NotReadable(), self.MockRawIO()) + + def test_constructor_with_not_writeable(self): + class NotWriteable(self.MockRawIO): + def writable(self): + return False + + self.assertRaises(OSError, self.tp, self.MockRawIO(), NotWriteable()) + + def test_read(self): + pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) + + self.assertEqual(pair.read(3), b"abc") + self.assertEqual(pair.read(1), b"d") + self.assertEqual(pair.read(), b"ef") + pair = self.tp(self.BytesIO(b"abc"), self.MockRawIO()) + self.assertEqual(pair.read(None), b"abc") + + def test_readlines(self): + pair = lambda: self.tp(self.BytesIO(b"abc\ndef\nh"), self.MockRawIO()) + self.assertEqual(pair().readlines(), [b"abc\n", b"def\n", b"h"]) + self.assertEqual(pair().readlines(), [b"abc\n", b"def\n", b"h"]) + self.assertEqual(pair().readlines(5), [b"abc\n", b"def\n"]) + + def test_read1(self): + # .read1() is delegated to the underlying reader object, so this test + # can be shallow. + pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) + + self.assertEqual(pair.read1(3), b"abc") + self.assertEqual(pair.read1(), b"def") + + def test_readinto(self): + for method in ("readinto", "readinto1"): + with self.subTest(method): + pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) + + data = byteslike(b'\0' * 5) + self.assertEqual(getattr(pair, method)(data), 5) + self.assertEqual(bytes(data), b"abcde") + + # gh-138720: C BufferedRWPair would destruct in a bad order resulting in + # an unraisable exception. + support.gc_collect() + + def test_write(self): + w = self.MockRawIO() + pair = self.tp(self.MockRawIO(), w) + + pair.write(b"abc") + pair.flush() + buffer = bytearray(b"def") + pair.write(buffer) + buffer[:] = b"***" # Overwrite our copy of the data + pair.flush() + self.assertEqual(w._write_stack, [b"abc", b"def"]) + + def test_peek(self): + pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) + + self.assertStartsWith(pair.peek(3), b"abc") + self.assertEqual(pair.read(3), b"abc") + + def test_readable(self): + pair = self.tp(self.MockRawIO(), self.MockRawIO()) + self.assertTrue(pair.readable()) + + def test_writeable(self): + pair = self.tp(self.MockRawIO(), self.MockRawIO()) + self.assertTrue(pair.writable()) + + def test_seekable(self): + # BufferedRWPairs are never seekable, even if their readers and writers + # are. + pair = self.tp(self.MockRawIO(), self.MockRawIO()) + self.assertFalse(pair.seekable()) + + # .flush() is delegated to the underlying writer object and has been + # tested in the test_write method. + + def test_close_and_closed(self): + pair = self.tp(self.MockRawIO(), self.MockRawIO()) + self.assertFalse(pair.closed) + pair.close() + self.assertTrue(pair.closed) + + def test_reader_close_error_on_close(self): + def reader_close(): + reader_non_existing + reader = self.MockRawIO() + reader.close = reader_close + writer = self.MockRawIO() + pair = self.tp(reader, writer) + with self.assertRaises(NameError) as err: + pair.close() + self.assertIn('reader_non_existing', str(err.exception)) + self.assertTrue(pair.closed) + self.assertFalse(reader.closed) + self.assertTrue(writer.closed) + + # Silence destructor error + reader.close = lambda: None + + def test_writer_close_error_on_close(self): + def writer_close(): + writer_non_existing + reader = self.MockRawIO() + writer = self.MockRawIO() + writer.close = writer_close + pair = self.tp(reader, writer) + with self.assertRaises(NameError) as err: + pair.close() + self.assertIn('writer_non_existing', str(err.exception)) + self.assertFalse(pair.closed) + self.assertTrue(reader.closed) + self.assertFalse(writer.closed) + + # Silence destructor error + writer.close = lambda: None + writer = None + + # Ignore BufferedWriter (of the BufferedRWPair) unraisable exception + with support.catch_unraisable_exception(): + # Ignore BufferedRWPair unraisable exception + with support.catch_unraisable_exception(): + pair = None + support.gc_collect() + support.gc_collect() + + def test_reader_writer_close_error_on_close(self): + def reader_close(): + reader_non_existing + def writer_close(): + writer_non_existing + reader = self.MockRawIO() + reader.close = reader_close + writer = self.MockRawIO() + writer.close = writer_close + pair = self.tp(reader, writer) + with self.assertRaises(NameError) as err: + pair.close() + self.assertIn('reader_non_existing', str(err.exception)) + self.assertIsInstance(err.exception.__context__, NameError) + self.assertIn('writer_non_existing', str(err.exception.__context__)) + self.assertFalse(pair.closed) + self.assertFalse(reader.closed) + self.assertFalse(writer.closed) + + # Silence destructor error + reader.close = lambda: None + writer.close = lambda: None + + def test_isatty(self): + class SelectableIsAtty(self.MockRawIO): + def __init__(self, isatty): + super().__init__() + self._isatty = isatty + + def isatty(self): + return self._isatty + + pair = self.tp(SelectableIsAtty(False), SelectableIsAtty(False)) + self.assertFalse(pair.isatty()) + + pair = self.tp(SelectableIsAtty(True), SelectableIsAtty(False)) + self.assertTrue(pair.isatty()) + + pair = self.tp(SelectableIsAtty(False), SelectableIsAtty(True)) + self.assertTrue(pair.isatty()) + + pair = self.tp(SelectableIsAtty(True), SelectableIsAtty(True)) + self.assertTrue(pair.isatty()) + + def test_weakref_clearing(self): + brw = self.tp(self.MockRawIO(), self.MockRawIO()) + ref = weakref.ref(brw) + brw = None + ref = None # Shouldn't segfault. + +class CBufferedRWPairTest(BufferedRWPairTest, CTestCase): + tp = io.BufferedRWPair + +class PyBufferedRWPairTest(BufferedRWPairTest, PyTestCase): + tp = pyio.BufferedRWPair + + +class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest): + read_mode = "rb+" + write_mode = "wb+" + + def test_constructor(self): + BufferedReaderTest.test_constructor(self) + BufferedWriterTest.test_constructor(self) + + def test_uninitialized(self): + BufferedReaderTest.test_uninitialized(self) + BufferedWriterTest.test_uninitialized(self) + + def test_read_and_write(self): + raw = self.MockRawIO((b"asdf", b"ghjk")) + rw = self.tp(raw, 8) + + self.assertEqual(b"as", rw.read(2)) + rw.write(b"ddd") + rw.write(b"eee") + self.assertFalse(raw._write_stack) # Buffer writes + self.assertEqual(b"ghjk", rw.read()) + self.assertEqual(b"dddeee", raw._write_stack[0]) + + def test_seek_and_tell(self): + raw = self.BytesIO(b"asdfghjkl") + rw = self.tp(raw) + + self.assertEqual(b"as", rw.read(2)) + self.assertEqual(2, rw.tell()) + rw.seek(0, 0) + self.assertEqual(b"asdf", rw.read(4)) + + rw.write(b"123f") + rw.seek(0, 0) + self.assertEqual(b"asdf123fl", rw.read()) + self.assertEqual(9, rw.tell()) + rw.seek(-4, 2) + self.assertEqual(5, rw.tell()) + rw.seek(2, 1) + self.assertEqual(7, rw.tell()) + self.assertEqual(b"fl", rw.read(11)) + rw.flush() + self.assertEqual(b"asdf123fl", raw.getvalue()) + + self.assertRaises(TypeError, rw.seek, 0.0) + + def check_flush_and_read(self, read_func): + raw = self.BytesIO(b"abcdefghi") + bufio = self.tp(raw) + + self.assertEqual(b"ab", read_func(bufio, 2)) + bufio.write(b"12") + self.assertEqual(b"ef", read_func(bufio, 2)) + self.assertEqual(6, bufio.tell()) + bufio.flush() + self.assertEqual(6, bufio.tell()) + self.assertEqual(b"ghi", read_func(bufio)) + raw.seek(0, 0) + raw.write(b"XYZ") + # flush() resets the read buffer + bufio.flush() + bufio.seek(0, 0) + self.assertEqual(b"XYZ", read_func(bufio, 3)) + + def test_flush_and_read(self): + self.check_flush_and_read(lambda bufio, *args: bufio.read(*args)) + + def test_flush_and_readinto(self): + def _readinto(bufio, n=-1): + b = bytearray(n if n >= 0 else 9999) + n = bufio.readinto(b) + b.resize(n) + return b.take_bytes() + self.check_flush_and_read(_readinto) + + def test_flush_and_peek(self): + def _peek(bufio, n=-1): + # This relies on the fact that the buffer can contain the whole + # raw stream, otherwise peek() can return less. + b = bufio.peek(n) + if n != -1: + b = b[:n] + bufio.seek(len(b), 1) + return b + self.check_flush_and_read(_peek) + + def test_flush_and_write(self): + raw = self.BytesIO(b"abcdefghi") + bufio = self.tp(raw) + + bufio.write(b"123") + bufio.flush() + bufio.write(b"45") + bufio.flush() + bufio.seek(0, 0) + self.assertEqual(b"12345fghi", raw.getvalue()) + self.assertEqual(b"12345fghi", bufio.read()) + + def test_threads(self): + BufferedReaderTest.test_threads(self) + BufferedWriterTest.test_threads(self) + + def test_writes_and_peek(self): + def _peek(bufio): + bufio.peek(1) + self.check_writes(_peek) + def _peek(bufio): + pos = bufio.tell() + bufio.seek(-1, 1) + bufio.peek(1) + bufio.seek(pos, 0) + self.check_writes(_peek) + + def test_writes_and_reads(self): + def _read(bufio): + bufio.seek(-1, 1) + bufio.read(1) + self.check_writes(_read) + + def test_writes_and_read1s(self): + def _read1(bufio): + bufio.seek(-1, 1) + bufio.read1(1) + self.check_writes(_read1) + + def test_writes_and_readintos(self): + def _read(bufio): + bufio.seek(-1, 1) + bufio.readinto(bytearray(1)) + self.check_writes(_read) + + def test_write_after_readahead(self): + # Issue #6629: writing after the buffer was filled by readahead should + # first rewind the raw stream. + for overwrite_size in [1, 5]: + raw = self.BytesIO(b"A" * 10) + bufio = self.tp(raw, 4) + # Trigger readahead + self.assertEqual(bufio.read(1), b"A") + self.assertEqual(bufio.tell(), 1) + # Overwriting should rewind the raw stream if it needs so + bufio.write(b"B" * overwrite_size) + self.assertEqual(bufio.tell(), overwrite_size + 1) + # If the write size was smaller than the buffer size, flush() and + # check that rewind happens. + bufio.flush() + self.assertEqual(bufio.tell(), overwrite_size + 1) + s = raw.getvalue() + self.assertEqual(s, + b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) + + def test_write_rewind_write(self): + # Various combinations of reading / writing / seeking backwards / writing again + def mutate(bufio, pos1, pos2): + assert pos2 >= pos1 + # Fill the buffer + bufio.seek(pos1) + bufio.read(pos2 - pos1) + bufio.write(b'\x02') + # This writes earlier than the previous write, but still inside + # the buffer. + bufio.seek(pos1) + bufio.write(b'\x01') + + b = b"\x80\x81\x82\x83\x84" + for i in range(0, len(b)): + for j in range(i, len(b)): + raw = self.BytesIO(b) + bufio = self.tp(raw, 100) + mutate(bufio, i, j) + bufio.flush() + expected = bytearray(b) + expected[j] = 2 + expected[i] = 1 + self.assertEqual(raw.getvalue(), expected, + "failed result for i=%d, j=%d" % (i, j)) + + def test_truncate_after_read_or_write(self): + raw = self.BytesIO(b"A" * 10) + bufio = self.tp(raw, 100) + self.assertEqual(bufio.read(2), b"AA") # the read buffer gets filled + self.assertEqual(bufio.truncate(), 2) + self.assertEqual(bufio.write(b"BB"), 2) # the write buffer increases + self.assertEqual(bufio.truncate(), 4) + + def test_misbehaved_io(self): + BufferedReaderTest.test_misbehaved_io(self) + BufferedWriterTest.test_misbehaved_io(self) + + def test_interleaved_read_write(self): + # Test for issue #12213 + with self.BytesIO(b'abcdefgh') as raw: + with self.tp(raw, 100) as f: + f.write(b"1") + self.assertEqual(f.read(1), b'b') + f.write(b'2') + self.assertEqual(f.read1(1), b'd') + f.write(b'3') + buf = bytearray(1) + f.readinto(buf) + self.assertEqual(buf, b'f') + f.write(b'4') + self.assertEqual(f.peek(1), b'h') + f.flush() + self.assertEqual(raw.getvalue(), b'1b2d3f4h') + + with self.BytesIO(b'abc') as raw: + with self.tp(raw, 100) as f: + self.assertEqual(f.read(1), b'a') + f.write(b"2") + self.assertEqual(f.read(1), b'c') + f.flush() + self.assertEqual(raw.getvalue(), b'a2c') + + def test_read1_after_write(self): + with self.BytesIO(b'abcdef') as raw: + with self.tp(raw, 3) as f: + f.write(b"1") + self.assertEqual(f.read1(1), b'b') + f.flush() + self.assertEqual(raw.getvalue(), b'1bcdef') + with self.BytesIO(b'abcdef') as raw: + with self.tp(raw, 3) as f: + f.write(b"1") + self.assertEqual(f.read1(), b'bcd') + f.flush() + self.assertEqual(raw.getvalue(), b'1bcdef') + with self.BytesIO(b'abcdef') as raw: + with self.tp(raw, 3) as f: + f.write(b"1") + # XXX: read(100) returns different numbers of bytes + # in Python and C implementations. + self.assertEqual(f.read1(100)[:3], b'bcd') + f.flush() + self.assertEqual(raw.getvalue(), b'1bcdef') + + def test_interleaved_readline_write(self): + with self.BytesIO(b'ab\ncdef\ng\n') as raw: + with self.tp(raw) as f: + f.write(b'1') + self.assertEqual(f.readline(), b'b\n') + f.write(b'2') + self.assertEqual(f.readline(), b'def\n') + f.write(b'3') + self.assertEqual(f.readline(), b'\n') + f.flush() + self.assertEqual(raw.getvalue(), b'1b\n2def\n3\n') + + # You can't construct a BufferedRandom over a non-seekable stream. + test_unseekable = None + + # writable() returns True, so there's no point to test it over + # a writable stream. + test_truncate_on_read_only = None + + +class CBufferedRandomTest(BufferedRandomTest, SizeofTest, CTestCase): + tp = io.BufferedRandom + + def test_garbage_collection(self): + CBufferedReaderTest.test_garbage_collection(self) + CBufferedWriterTest.test_garbage_collection(self) + + def test_args_error(self): + # Issue #17275 + with self.assertRaisesRegex(TypeError, "BufferedRandom"): + self.tp(self.BytesIO(), 1024, 1024, 1024) + + +class PyBufferedRandomTest(BufferedRandomTest, PyTestCase): + tp = pyio.BufferedRandom + + +# Simple test to ensure that optimizations in the IO library deliver the +# expected results. For best testing, run this under a debug-build Python too +# (to exercise asserts in the C code). + +lengths = list(range(1, 257)) + [512, 1000, 1024, 2048, 4096, 8192, 10000, + 16384, 32768, 65536, 1000000] + +class BufferSizeTest: + def try_one(self, s): + # Write s + "\n" + s to file, then open it and ensure that successive + # .readline()s deliver what we wrote. + + # Ensure we can open TESTFN for writing. + os_helper.unlink(os_helper.TESTFN) + + # Since C doesn't guarantee we can write/read arbitrary bytes in text + # files, use binary mode. + f = self.open(os_helper.TESTFN, "wb") + try: + # write once with \n and once without + f.write(s) + f.write(b"\n") + f.write(s) + f.close() + f = self.open(os_helper.TESTFN, "rb") + line = f.readline() + self.assertEqual(line, s + b"\n") + line = f.readline() + self.assertEqual(line, s) + line = f.readline() + self.assertFalse(line) # Must be at EOF + f.close() + finally: + os_helper.unlink(os_helper.TESTFN) + + def drive_one(self, pattern): + for length in lengths: + # Repeat string 'pattern' as often as needed to reach total length + # 'length'. Then call try_one with that string, a string one larger + # than that, and a string one smaller than that. Try this with all + # small sizes and various powers of 2, so we exercise all likely + # stdio buffer sizes, and "off by one" errors on both sides. + q, r = divmod(length, len(pattern)) + teststring = pattern * q + pattern[:r] + self.assertEqual(len(teststring), length) + self.try_one(teststring) + self.try_one(teststring + b"x") + self.try_one(teststring[:-1]) + + def test_primepat(self): + # A pattern with prime length, to avoid simple relationships with + # stdio buffer sizes. + self.drive_one(b"1234567890\00\01\02\03\04\05\06") + + def test_nullpat(self): + self.drive_one(b'\0' * 1000) + + +class CBufferSizeTest(BufferSizeTest, unittest.TestCase): + open = io.open + +class PyBufferSizeTest(BufferSizeTest, unittest.TestCase): + open = staticmethod(pyio.open) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_file.py b/Lib/test/test_io/test_file.py similarity index 100% rename from Lib/test/test_file.py rename to Lib/test/test_io/test_file.py diff --git a/Lib/test/test_fileio.py b/Lib/test/test_io/test_fileio.py similarity index 99% rename from Lib/test/test_fileio.py rename to Lib/test/test_io/test_fileio.py index e3d54f6315a..e53c4749f58 100644 --- a/Lib/test/test_fileio.py +++ b/Lib/test/test_io/test_fileio.py @@ -567,8 +567,8 @@ class OtherFileTests: # test that the mode attribute is correct for various mode strings # given as init args try: - for modes in [('w', 'wb'), ('wb', 'wb'), ('wb+', 'rb+'), - ('w+b', 'rb+'), ('a', 'ab'), ('ab', 'ab'), + for modes in [('w', 'wb'), ('wb', 'wb'), ('wb+', 'wb+'), + ('w+b', 'wb+'), ('a', 'ab'), ('ab', 'ab'), ('ab+', 'ab+'), ('a+b', 'ab+'), ('r', 'rb'), ('rb', 'rb'), ('rb+', 'rb+'), ('r+b', 'rb+')]: # read modes are last so that TESTFN will exist first diff --git a/Lib/test/test_io/test_general.py b/Lib/test/test_io/test_general.py new file mode 100644 index 00000000000..085ed3ea6a9 --- /dev/null +++ b/Lib/test/test_io/test_general.py @@ -0,0 +1,1431 @@ +"""General tests for the io module. + +New tests should go in more specific modules; see test_io/__init__.py +""" + +import abc +import array +import errno +import os +import pickle +import sys +import textwrap +import threading +import unittest +import warnings +import weakref +from test import support +from test.support.script_helper import ( + assert_python_ok, assert_python_failure, run_python_until_end) +from test.support import ( + import_helper, is_apple, os_helper, threading_helper, warnings_helper, +) +from test.support.os_helper import FakePath +from .utils import byteslike, CTestCase, PyTestCase + +import io # C implementation of io +import _pyio as pyio # Python implementation of io + + +class IOTest: + + def setUp(self): + os_helper.unlink(os_helper.TESTFN) + + def tearDown(self): + os_helper.unlink(os_helper.TESTFN) + + def write_ops(self, f): + self.assertEqual(f.write(b"blah."), 5) + f.truncate(0) + self.assertEqual(f.tell(), 5) + f.seek(0) + + self.assertEqual(f.write(b"blah."), 5) + self.assertEqual(f.seek(0), 0) + self.assertEqual(f.write(b"Hello."), 6) + self.assertEqual(f.tell(), 6) + self.assertEqual(f.seek(-1, 1), 5) + self.assertEqual(f.tell(), 5) + buffer = bytearray(b" world\n\n\n") + self.assertEqual(f.write(buffer), 9) + buffer[:] = b"*" * 9 # Overwrite our copy of the data + self.assertEqual(f.seek(0), 0) + self.assertEqual(f.write(b"h"), 1) + self.assertEqual(f.seek(-1, 2), 13) + self.assertEqual(f.tell(), 13) + + self.assertEqual(f.truncate(12), 12) + self.assertEqual(f.tell(), 13) + self.assertRaises(TypeError, f.seek, 0.0) + + def read_ops(self, f, buffered=False): + data = f.read(5) + self.assertEqual(data, b"hello") + data = byteslike(data) + self.assertEqual(f.readinto(data), 5) + self.assertEqual(bytes(data), b" worl") + data = bytearray(5) + self.assertEqual(f.readinto(data), 2) + self.assertEqual(len(data), 5) + self.assertEqual(data[:2], b"d\n") + self.assertEqual(f.seek(0), 0) + self.assertEqual(f.read(20), b"hello world\n") + self.assertEqual(f.read(1), b"") + self.assertEqual(f.readinto(byteslike(b"x")), 0) + self.assertEqual(f.seek(-6, 2), 6) + self.assertEqual(f.read(5), b"world") + self.assertEqual(f.read(0), b"") + self.assertEqual(f.readinto(byteslike()), 0) + self.assertEqual(f.seek(-6, 1), 5) + self.assertEqual(f.read(5), b" worl") + self.assertEqual(f.tell(), 10) + self.assertRaises(TypeError, f.seek, 0.0) + if buffered: + f.seek(0) + self.assertEqual(f.read(), b"hello world\n") + f.seek(6) + self.assertEqual(f.read(), b"world\n") + self.assertEqual(f.read(), b"") + f.seek(0) + data = byteslike(5) + self.assertEqual(f.readinto1(data), 5) + self.assertEqual(bytes(data), b"hello") + + LARGE = 2**31 + + def large_file_ops(self, f): + assert f.readable() + assert f.writable() + try: + self.assertEqual(f.seek(self.LARGE), self.LARGE) + except (OverflowError, ValueError): + self.skipTest("no largefile support") + self.assertEqual(f.tell(), self.LARGE) + self.assertEqual(f.write(b"xxx"), 3) + self.assertEqual(f.tell(), self.LARGE + 3) + self.assertEqual(f.seek(-1, 1), self.LARGE + 2) + self.assertEqual(f.truncate(), self.LARGE + 2) + self.assertEqual(f.tell(), self.LARGE + 2) + self.assertEqual(f.seek(0, 2), self.LARGE + 2) + self.assertEqual(f.truncate(self.LARGE + 1), self.LARGE + 1) + self.assertEqual(f.tell(), self.LARGE + 2) + self.assertEqual(f.seek(0, 2), self.LARGE + 1) + self.assertEqual(f.seek(-1, 2), self.LARGE) + self.assertEqual(f.read(2), b"x") + + def test_invalid_operations(self): + # Try writing on a file opened in read mode and vice-versa. + exc = self.UnsupportedOperation + with self.open(os_helper.TESTFN, "w", encoding="utf-8") as fp: + self.assertRaises(exc, fp.read) + self.assertRaises(exc, fp.readline) + with self.open(os_helper.TESTFN, "wb") as fp: + self.assertRaises(exc, fp.read) + self.assertRaises(exc, fp.readline) + with self.open(os_helper.TESTFN, "wb", buffering=0) as fp: + self.assertRaises(exc, fp.read) + self.assertRaises(exc, fp.readall) + self.assertRaises(exc, fp.readline) + with self.open(os_helper.TESTFN, "rb", buffering=0) as fp: + self.assertRaises(exc, fp.write, b"blah") + self.assertRaises(exc, fp.writelines, [b"blah\n"]) + with self.open(os_helper.TESTFN, "rb") as fp: + self.assertRaises(exc, fp.write, b"blah") + self.assertRaises(exc, fp.writelines, [b"blah\n"]) + with self.open(os_helper.TESTFN, "r", encoding="utf-8") as fp: + self.assertRaises(exc, fp.write, "blah") + self.assertRaises(exc, fp.writelines, ["blah\n"]) + # Non-zero seeking from current or end pos + self.assertRaises(exc, fp.seek, 1, self.SEEK_CUR) + self.assertRaises(exc, fp.seek, -1, self.SEEK_END) + + @support.cpython_only + def test_startup_optimization(self): + # gh-132952: Test that `io` is not imported at startup and that the + # __module__ of UnsupportedOperation is set to "io". + assert_python_ok("-S", "-c", textwrap.dedent( + """ + import sys + assert "io" not in sys.modules + try: + sys.stdin.truncate() + except Exception as e: + typ = type(e) + assert typ.__module__ == "io", (typ, typ.__module__) + assert typ.__name__ == "UnsupportedOperation", (typ, typ.__name__) + else: + raise AssertionError("Expected UnsupportedOperation") + """ + )) + + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_optional_abilities(self): + # Test for OSError when optional APIs are not supported + # The purpose of this test is to try fileno(), reading, writing and + # seeking operations with various objects that indicate they do not + # support these operations. + + def pipe_reader(): + [r, w] = os.pipe() + os.close(w) # So that read() is harmless + return self.FileIO(r, "r") + + def pipe_writer(): + [r, w] = os.pipe() + self.addCleanup(os.close, r) + # Guarantee that we can write into the pipe without blocking + thread = threading.Thread(target=os.read, args=(r, 100)) + thread.start() + self.addCleanup(thread.join) + return self.FileIO(w, "w") + + def buffered_reader(): + return self.BufferedReader(self.MockUnseekableIO()) + + def buffered_writer(): + return self.BufferedWriter(self.MockUnseekableIO()) + + def buffered_random(): + return self.BufferedRandom(self.BytesIO()) + + def buffered_rw_pair(): + return self.BufferedRWPair(self.MockUnseekableIO(), + self.MockUnseekableIO()) + + def text_reader(): + class UnseekableReader(self.MockUnseekableIO): + writable = self.BufferedIOBase.writable + write = self.BufferedIOBase.write + return self.TextIOWrapper(UnseekableReader(), "ascii") + + def text_writer(): + class UnseekableWriter(self.MockUnseekableIO): + readable = self.BufferedIOBase.readable + read = self.BufferedIOBase.read + return self.TextIOWrapper(UnseekableWriter(), "ascii") + + tests = ( + (pipe_reader, "fr"), (pipe_writer, "fw"), + (buffered_reader, "r"), (buffered_writer, "w"), + (buffered_random, "rws"), (buffered_rw_pair, "rw"), + (text_reader, "r"), (text_writer, "w"), + (self.BytesIO, "rws"), (self.StringIO, "rws"), + ) + + def do_test(test, obj, abilities): + readable = "r" in abilities + self.assertEqual(obj.readable(), readable) + writable = "w" in abilities + self.assertEqual(obj.writable(), writable) + + if isinstance(obj, self.TextIOBase): + data = "3" + elif isinstance(obj, (self.BufferedIOBase, self.RawIOBase)): + data = b"3" + else: + self.fail("Unknown base class") + + if "f" in abilities: + obj.fileno() + else: + self.assertRaises(OSError, obj.fileno) + + if readable: + obj.read(1) + obj.read() + else: + self.assertRaises(OSError, obj.read, 1) + self.assertRaises(OSError, obj.read) + + if writable: + obj.write(data) + else: + self.assertRaises(OSError, obj.write, data) + + if sys.platform.startswith("win") and test in ( + pipe_reader, pipe_writer): + # Pipes seem to appear as seekable on Windows + return + seekable = "s" in abilities + self.assertEqual(obj.seekable(), seekable) + + if seekable: + obj.tell() + obj.seek(0) + else: + self.assertRaises(OSError, obj.tell) + self.assertRaises(OSError, obj.seek, 0) + + if writable and seekable: + obj.truncate() + obj.truncate(0) + else: + self.assertRaises(OSError, obj.truncate) + self.assertRaises(OSError, obj.truncate, 0) + + for [test, abilities] in tests: + with self.subTest(test): + if test == pipe_writer and not threading_helper.can_start_thread: + self.skipTest("Need threads") + with test() as obj: + do_test(test, obj, abilities) + + + def test_open_handles_NUL_chars(self): + fn_with_NUL = 'foo\0bar' + self.assertRaises(ValueError, self.open, fn_with_NUL, 'w', encoding="utf-8") + + bytes_fn = bytes(fn_with_NUL, 'ascii') + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + self.assertRaises(ValueError, self.open, bytes_fn, 'w', encoding="utf-8") + + def test_raw_file_io(self): + with self.open(os_helper.TESTFN, "wb", buffering=0) as f: + self.assertEqual(f.readable(), False) + self.assertEqual(f.writable(), True) + self.assertEqual(f.seekable(), True) + self.write_ops(f) + with self.open(os_helper.TESTFN, "rb", buffering=0) as f: + self.assertEqual(f.readable(), True) + self.assertEqual(f.writable(), False) + self.assertEqual(f.seekable(), True) + self.read_ops(f) + + def test_buffered_file_io(self): + with self.open(os_helper.TESTFN, "wb") as f: + self.assertEqual(f.readable(), False) + self.assertEqual(f.writable(), True) + self.assertEqual(f.seekable(), True) + self.write_ops(f) + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.readable(), True) + self.assertEqual(f.writable(), False) + self.assertEqual(f.seekable(), True) + self.read_ops(f, True) + + def test_readline(self): + with self.open(os_helper.TESTFN, "wb") as f: + f.write(b"abc\ndef\nxyzzy\nfoo\x00bar\nanother line") + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.readline(), b"abc\n") + self.assertEqual(f.readline(10), b"def\n") + self.assertEqual(f.readline(2), b"xy") + self.assertEqual(f.readline(4), b"zzy\n") + self.assertEqual(f.readline(), b"foo\x00bar\n") + self.assertEqual(f.readline(None), b"another line") + self.assertRaises(TypeError, f.readline, 5.3) + with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: + self.assertRaises(TypeError, f.readline, 5.3) + + def test_readline_nonsizeable(self): + # Issue #30061 + # Crash when readline() returns an object without __len__ + class R(self.IOBase): + def readline(self): + return None + self.assertRaises((TypeError, StopIteration), next, R()) + + def test_next_nonsizeable(self): + # Issue #30061 + # Crash when __next__() returns an object without __len__ + class R(self.IOBase): + def __next__(self): + return None + self.assertRaises(TypeError, R().readlines, 1) + + def test_raw_bytes_io(self): + f = self.BytesIO() + self.write_ops(f) + data = f.getvalue() + self.assertEqual(data, b"hello world\n") + f = self.BytesIO(data) + self.read_ops(f, True) + + def test_large_file_ops(self): + # On Windows and Apple platforms this test consumes large resources; It + # takes a long time to build the >2 GiB file and takes >2 GiB of disk + # space therefore the resource must be enabled to run this test. + if sys.platform[:3] == 'win' or is_apple: + support.requires( + 'largefile', + 'test requires %s bytes and a long time to run' % self.LARGE) + with self.open(os_helper.TESTFN, "w+b", 0) as f: + self.large_file_ops(f) + with self.open(os_helper.TESTFN, "w+b") as f: + self.large_file_ops(f) + + def test_with_open(self): + for bufsize in (0, 100): + with self.open(os_helper.TESTFN, "wb", bufsize) as f: + f.write(b"xxx") + self.assertEqual(f.closed, True) + try: + with self.open(os_helper.TESTFN, "wb", bufsize) as f: + 1/0 + except ZeroDivisionError: + self.assertEqual(f.closed, True) + else: + self.fail("1/0 didn't raise an exception") + + # issue 5008 + def test_append_mode_tell(self): + with self.open(os_helper.TESTFN, "wb") as f: + f.write(b"xxx") + with self.open(os_helper.TESTFN, "ab", buffering=0) as f: + self.assertEqual(f.tell(), 3) + with self.open(os_helper.TESTFN, "ab") as f: + self.assertEqual(f.tell(), 3) + with self.open(os_helper.TESTFN, "a", encoding="utf-8") as f: + self.assertGreater(f.tell(), 0) + + def test_destructor(self): + record = [] + class MyFileIO(self.FileIO): + def __del__(self): + record.append(1) + try: + f = super().__del__ + except AttributeError: + pass + else: + f() + def close(self): + record.append(2) + super().close() + def flush(self): + record.append(3) + super().flush() + with warnings_helper.check_warnings(('', ResourceWarning)): + f = MyFileIO(os_helper.TESTFN, "wb") + f.write(b"xxx") + del f + support.gc_collect() + self.assertEqual(record, [1, 2, 3]) + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"xxx") + + def _check_base_destructor(self, base): + record = [] + class MyIO(base): + def __init__(self): + # This exercises the availability of attributes on object + # destruction. + # (in the C version, close() is called by the tp_dealloc + # function, not by __del__) + self.on_del = 1 + self.on_close = 2 + self.on_flush = 3 + def __del__(self): + record.append(self.on_del) + try: + f = super().__del__ + except AttributeError: + pass + else: + f() + def close(self): + record.append(self.on_close) + super().close() + def flush(self): + record.append(self.on_flush) + super().flush() + f = MyIO() + del f + support.gc_collect() + self.assertEqual(record, [1, 2, 3]) + + def test_IOBase_destructor(self): + self._check_base_destructor(self.IOBase) + + def test_RawIOBase_destructor(self): + self._check_base_destructor(self.RawIOBase) + + def test_BufferedIOBase_destructor(self): + self._check_base_destructor(self.BufferedIOBase) + + def test_TextIOBase_destructor(self): + self._check_base_destructor(self.TextIOBase) + + def test_close_flushes(self): + with self.open(os_helper.TESTFN, "wb") as f: + f.write(b"xxx") + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"xxx") + + def test_array_writes(self): + a = array.array('i', range(10)) + n = len(a.tobytes()) + def check(f): + with f: + self.assertEqual(f.write(a), n) + f.writelines((a,)) + check(self.BytesIO()) + check(self.FileIO(os_helper.TESTFN, "w")) + check(self.BufferedWriter(self.MockRawIO())) + check(self.BufferedRandom(self.MockRawIO())) + check(self.BufferedRWPair(self.MockRawIO(), self.MockRawIO())) + + def test_closefd(self): + self.assertRaises(ValueError, self.open, os_helper.TESTFN, 'w', + encoding="utf-8", closefd=False) + + def test_read_closed(self): + with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: + f.write("egg\n") + with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: + file = self.open(f.fileno(), "r", encoding="utf-8", closefd=False) + self.assertEqual(file.read(), "egg\n") + file.seek(0) + file.close() + self.assertRaises(ValueError, file.read) + with self.open(os_helper.TESTFN, "rb") as f: + file = self.open(f.fileno(), "rb", closefd=False) + self.assertEqual(file.read()[:3], b"egg") + file.close() + self.assertRaises(ValueError, file.readinto, bytearray(1)) + + def test_no_closefd_with_filename(self): + # can't use closefd in combination with a file name + self.assertRaises(ValueError, self.open, os_helper.TESTFN, "r", + encoding="utf-8", closefd=False) + + def test_closefd_attr(self): + with self.open(os_helper.TESTFN, "wb") as f: + f.write(b"egg\n") + with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: + self.assertEqual(f.buffer.raw.closefd, True) + file = self.open(f.fileno(), "r", encoding="utf-8", closefd=False) + self.assertEqual(file.buffer.raw.closefd, False) + + def test_garbage_collection(self): + # FileIO objects are collected, and collecting them flushes + # all data to disk. + # + # Note that using warnings_helper.check_warnings() will keep the + # file alive due to the `source` argument to warn(). So, use + # catch_warnings() instead. + with warnings.catch_warnings(): + warnings.simplefilter("ignore", ResourceWarning) + f = self.FileIO(os_helper.TESTFN, "wb") + f.write(b"abcxxx") + f.f = f + wr = weakref.ref(f) + del f + support.gc_collect() + self.assertIsNone(wr(), wr) + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"abcxxx") + + def test_unbounded_file(self): + # Issue #1174606: reading from an unbounded stream such as /dev/zero. + zero = "/dev/zero" + if not os.path.exists(zero): + self.skipTest("{0} does not exist".format(zero)) + if sys.maxsize > 0x7FFFFFFF: + self.skipTest("test can only run in a 32-bit address space") + if support.real_max_memuse < support._2G: + self.skipTest("test requires at least 2 GiB of memory") + with self.open(zero, "rb", buffering=0) as f: + self.assertRaises(OverflowError, f.read) + with self.open(zero, "rb") as f: + self.assertRaises(OverflowError, f.read) + with self.open(zero, "r") as f: + self.assertRaises(OverflowError, f.read) + + def check_flush_error_on_close(self, *args, **kwargs): + # Test that the file is closed despite failed flush + # and that flush() is called before file closed. + f = self.open(*args, **kwargs) + closed = [] + def bad_flush(): + closed[:] = [f.closed] + raise OSError() + f.flush = bad_flush + self.assertRaises(OSError, f.close) # exception not swallowed + self.assertTrue(f.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + f.flush = lambda: None # break reference loop + + def test_flush_error_on_close(self): + # raw file + # Issue #5700: io.FileIO calls flush() after file closed + self.check_flush_error_on_close(os_helper.TESTFN, 'wb', buffering=0) + fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0) + fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) + os.close(fd) + # buffered io + self.check_flush_error_on_close(os_helper.TESTFN, 'wb') + fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb') + fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', closefd=False) + os.close(fd) + # text io + self.check_flush_error_on_close(os_helper.TESTFN, 'w', encoding="utf-8") + fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', encoding="utf-8") + fd = os.open(os_helper.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', encoding="utf-8", closefd=False) + os.close(fd) + + def test_multi_close(self): + f = self.open(os_helper.TESTFN, "wb", buffering=0) + f.close() + f.close() + f.close() + self.assertRaises(ValueError, f.flush) + + def test_RawIOBase_read(self): + # Exercise the default limited RawIOBase.read(n) implementation (which + # calls readinto() internally). + rawio = self.MockRawIOWithoutRead((b"abc", b"d", None, b"efg", None)) + self.assertEqual(rawio.read(2), b"ab") + self.assertEqual(rawio.read(2), b"c") + self.assertEqual(rawio.read(2), b"d") + self.assertEqual(rawio.read(2), None) + self.assertEqual(rawio.read(2), b"ef") + self.assertEqual(rawio.read(2), b"g") + self.assertEqual(rawio.read(2), None) + self.assertEqual(rawio.read(2), b"") + + def test_RawIOBase_read_bounds_checking(self): + # Make sure a `.readinto` call which returns a value outside + # (0, len(buffer)) raises. + class Misbehaved(self.io.RawIOBase): + def __init__(self, readinto_return) -> None: + self._readinto_return = readinto_return + def readinto(self, b): + return self._readinto_return + + with self.assertRaises(ValueError) as cm: + Misbehaved(2).read(1) + self.assertEqual(str(cm.exception), "readinto returned 2 outside buffer size 1") + for bad_size in (2147483647, sys.maxsize, -1, -1000): + with self.assertRaises(ValueError): + Misbehaved(bad_size).read() + + def test_RawIOBase_read_gh60107(self): + # gh-60107: Ensure a "Raw I/O" which keeps a reference to the + # mutable memory doesn't allow making a mutable bytes. + class RawIOKeepsReference(self.MockRawIOWithoutRead): + def __init__(self, *args, **kwargs): + self.buf = None + super().__init__(*args, **kwargs) + + def readinto(self, buf): + # buf is the bytearray so keeping a reference to it doesn't keep + # the memory alive; a memoryview does. + self.buf = memoryview(buf) + buf[0:4] = self._read_stack.pop() + return 3 + + with self.assertRaises(BufferError): + rawio = RawIOKeepsReference([b"1234"]) + rawio.read(4) + + def test_types_have_dict(self): + test = ( + self.IOBase(), + self.RawIOBase(), + self.TextIOBase(), + self.StringIO(), + self.BytesIO() + ) + for obj in test: + self.assertHasAttr(obj, "__dict__") + + def test_opener(self): + with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: + f.write("egg\n") + fd = os.open(os_helper.TESTFN, os.O_RDONLY) + def opener(path, flags): + return fd + with self.open("non-existent", "r", encoding="utf-8", opener=opener) as f: + self.assertEqual(f.read(), "egg\n") + + def test_bad_opener_negative_1(self): + # Issue #27066. + def badopener(fname, flags): + return -1 + with self.assertRaises(ValueError) as cm: + self.open('non-existent', 'r', opener=badopener) + self.assertEqual(str(cm.exception), 'opener returned -1') + + def test_bad_opener_other_negative(self): + # Issue #27066. + def badopener(fname, flags): + return -2 + with self.assertRaises(ValueError) as cm: + self.open('non-existent', 'r', opener=badopener) + self.assertEqual(str(cm.exception), 'opener returned -2') + + def test_opener_invalid_fd(self): + # Check that OSError is raised with error code EBADF if the + # opener returns an invalid file descriptor (see gh-82212). + fd = os_helper.make_bad_fd() + with self.assertRaises(OSError) as cm: + self.open('foo', opener=lambda name, flags: fd) + self.assertEqual(cm.exception.errno, errno.EBADF) + + def test_fileio_closefd(self): + # Issue #4841 + with self.open(__file__, 'rb') as f1, \ + self.open(__file__, 'rb') as f2: + fileio = self.FileIO(f1.fileno(), closefd=False) + # .__init__() must not close f1 + fileio.__init__(f2.fileno(), closefd=False) + f1.readline() + # .close() must not close f2 + fileio.close() + f2.readline() + + def test_nonbuffered_textio(self): + with warnings_helper.check_no_resource_warning(self): + with self.assertRaises(ValueError): + self.open(os_helper.TESTFN, 'w', encoding="utf-8", buffering=0) + + def test_invalid_newline(self): + with warnings_helper.check_no_resource_warning(self): + with self.assertRaises(ValueError): + self.open(os_helper.TESTFN, 'w', encoding="utf-8", newline='invalid') + + def test_buffered_readinto_mixin(self): + # Test the implementation provided by BufferedIOBase + class Stream(self.BufferedIOBase): + def read(self, size): + return b"12345" + read1 = read + stream = Stream() + for method in ("readinto", "readinto1"): + with self.subTest(method): + buffer = byteslike(5) + self.assertEqual(getattr(stream, method)(buffer), 5) + self.assertEqual(bytes(buffer), b"12345") + + def test_fspath_support(self): + def check_path_succeeds(path): + with self.open(path, "w", encoding="utf-8") as f: + f.write("egg\n") + + with self.open(path, "r", encoding="utf-8") as f: + self.assertEqual(f.read(), "egg\n") + + check_path_succeeds(FakePath(os_helper.TESTFN)) + check_path_succeeds(FakePath(os.fsencode(os_helper.TESTFN))) + + with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: + bad_path = FakePath(f.fileno()) + with self.assertRaises(TypeError): + self.open(bad_path, 'w', encoding="utf-8") + + bad_path = FakePath(None) + with self.assertRaises(TypeError): + self.open(bad_path, 'w', encoding="utf-8") + + bad_path = FakePath(FloatingPointError) + with self.assertRaises(FloatingPointError): + self.open(bad_path, 'w', encoding="utf-8") + + # ensure that refcounting is correct with some error conditions + with self.assertRaisesRegex(ValueError, 'read/write/append mode'): + self.open(FakePath(os_helper.TESTFN), 'rwxa', encoding="utf-8") + + def test_RawIOBase_readall(self): + # Exercise the default unlimited RawIOBase.read() and readall() + # implementations. + rawio = self.MockRawIOWithoutRead((b"abc", b"d", b"efg")) + self.assertEqual(rawio.read(), b"abcdefg") + rawio = self.MockRawIOWithoutRead((b"abc", b"d", b"efg")) + self.assertEqual(rawio.readall(), b"abcdefg") + + def test_BufferedIOBase_readinto(self): + # Exercise the default BufferedIOBase.readinto() and readinto1() + # implementations (which call read() or read1() internally). + class Reader(self.BufferedIOBase): + def __init__(self, avail): + self.avail = avail + def read(self, size): + result = self.avail[:size] + self.avail = self.avail[size:] + return result + def read1(self, size): + """Returns no more than 5 bytes at once""" + return self.read(min(size, 5)) + tests = ( + # (test method, total data available, read buffer size, expected + # read size) + ("readinto", 10, 5, 5), + ("readinto", 10, 6, 6), # More than read1() can return + ("readinto", 5, 6, 5), # Buffer larger than total available + ("readinto", 6, 7, 6), + ("readinto", 10, 0, 0), # Empty buffer + ("readinto1", 10, 5, 5), # Result limited to single read1() call + ("readinto1", 10, 6, 5), # Buffer larger than read1() can return + ("readinto1", 5, 6, 5), # Buffer larger than total available + ("readinto1", 6, 7, 5), + ("readinto1", 10, 0, 0), # Empty buffer + ) + UNUSED_BYTE = 0x81 + for test in tests: + with self.subTest(test): + method, avail, request, result = test + reader = Reader(bytes(range(avail))) + buffer = bytearray((UNUSED_BYTE,) * request) + method = getattr(reader, method) + self.assertEqual(method(buffer), result) + self.assertEqual(len(buffer), request) + self.assertSequenceEqual(buffer[:result], range(result)) + unused = (UNUSED_BYTE,) * (request - result) + self.assertSequenceEqual(buffer[result:], unused) + self.assertEqual(len(reader.avail), avail - result) + + def test_close_assert(self): + class R(self.IOBase): + def __setattr__(self, name, value): + pass + def flush(self): + raise OSError() + f = R() + # This would cause an assertion failure. + self.assertRaises(OSError, f.close) + + # Silence destructor error + R.flush = lambda self: None + + @threading_helper.requires_working_threading() + def test_write_readline_races(self): + # gh-134908: Concurrent iteration over a file caused races + thread_count = 2 + write_count = 100 + read_count = 100 + + def writer(file, barrier): + barrier.wait() + for _ in range(write_count): + file.write("x") + + def reader(file, barrier): + barrier.wait() + for _ in range(read_count): + for line in file: + self.assertEqual(line, "") + + with self.open(os_helper.TESTFN, "w+") as f: + barrier = threading.Barrier(thread_count + 1) + reader = threading.Thread(target=reader, args=(f, barrier)) + writers = [threading.Thread(target=writer, args=(f, barrier)) + for _ in range(thread_count)] + with threading_helper.catch_threading_exception() as cm: + with threading_helper.start_threads(writers + [reader]): + pass + self.assertIsNone(cm.exc_type) + + self.assertEqual(os.stat(os_helper.TESTFN).st_size, + write_count * thread_count) + + +class CIOTest(IOTest, CTestCase): + + def test_IOBase_finalize(self): + # Issue #12149: segmentation fault on _PyIOBase_finalize when both a + # class which inherits IOBase and an object of this class are caught + # in a reference cycle and close() is already in the method cache. + class MyIO(self.IOBase): + def close(self): + pass + + # create an instance to populate the method cache + MyIO() + obj = MyIO() + obj.obj = obj + wr = weakref.ref(obj) + del MyIO + del obj + support.gc_collect() + self.assertIsNone(wr(), wr) + +@support.cpython_only +class TestIOCTypes(unittest.TestCase): + def setUp(self): + _io = import_helper.import_module("_io") + self.types = [ + _io.BufferedRWPair, + _io.BufferedRandom, + _io.BufferedReader, + _io.BufferedWriter, + _io.BytesIO, + _io.FileIO, + _io.IncrementalNewlineDecoder, + _io.StringIO, + _io.TextIOWrapper, + _io._BufferedIOBase, + _io._BytesIOBuffer, + _io._IOBase, + _io._RawIOBase, + _io._TextIOBase, + ] + if sys.platform == "win32": + self.types.append(_io._WindowsConsoleIO) + self._io = _io + + def test_immutable_types(self): + for tp in self.types: + with self.subTest(tp=tp): + with self.assertRaisesRegex(TypeError, "immutable"): + tp.foo = "bar" + + def test_class_hierarchy(self): + def check_subs(types, base): + for tp in types: + with self.subTest(tp=tp, base=base): + self.assertIsSubclass(tp, base) + + def recursive_check(d): + for k, v in d.items(): + if isinstance(v, dict): + recursive_check(v) + elif isinstance(v, set): + check_subs(v, k) + else: + self.fail("corrupt test dataset") + + _io = self._io + hierarchy = { + _io._IOBase: { + _io._BufferedIOBase: { + _io.BufferedRWPair, + _io.BufferedRandom, + _io.BufferedReader, + _io.BufferedWriter, + _io.BytesIO, + }, + _io._RawIOBase: { + _io.FileIO, + }, + _io._TextIOBase: { + _io.StringIO, + _io.TextIOWrapper, + }, + }, + } + if sys.platform == "win32": + hierarchy[_io._IOBase][_io._RawIOBase].add(_io._WindowsConsoleIO) + + recursive_check(hierarchy) + + def test_subclassing(self): + _io = self._io + dataset = {k: True for k in self.types} + dataset[_io._BytesIOBuffer] = False + + for tp, is_basetype in dataset.items(): + with self.subTest(tp=tp, is_basetype=is_basetype): + name = f"{tp.__name__}_subclass" + bases = (tp,) + if is_basetype: + _ = type(name, bases, {}) + else: + msg = "not an acceptable base type" + with self.assertRaisesRegex(TypeError, msg): + _ = type(name, bases, {}) + + def test_disallow_instantiation(self): + _io = self._io + support.check_disallow_instantiation(self, _io._BytesIOBuffer) + + def test_stringio_setstate(self): + # gh-127182: Calling __setstate__() with invalid arguments must not crash + obj = self._io.StringIO() + with self.assertRaisesRegex( + TypeError, + 'initial_value must be str or None, not int', + ): + obj.__setstate__((1, '', 0, {})) + + obj.__setstate__((None, '', 0, {})) # should not crash + self.assertEqual(obj.getvalue(), '') + + obj.__setstate__(('', '', 0, {})) + self.assertEqual(obj.getvalue(), '') + +class PyIOTest(IOTest, PyTestCase): + pass + + +@support.cpython_only +class APIMismatchTest(unittest.TestCase): + + def test_RawIOBase_io_in_pyio_match(self): + """Test that pyio RawIOBase class has all c RawIOBase methods""" + mismatch = support.detect_api_mismatch(pyio.RawIOBase, io.RawIOBase, + ignore=('__weakref__', '__static_attributes__')) + self.assertEqual(mismatch, set(), msg='Python RawIOBase does not have all C RawIOBase methods') + + def test_RawIOBase_pyio_in_io_match(self): + """Test that c RawIOBase class has all pyio RawIOBase methods""" + mismatch = support.detect_api_mismatch(io.RawIOBase, pyio.RawIOBase) + self.assertEqual(mismatch, set(), msg='C RawIOBase does not have all Python RawIOBase methods') + + +# XXX Tests for open() + +class MiscIOTest: + + # for test__all__, actual values are set in subclasses + name_of_module = None + extra_exported = () + not_exported = () + + def tearDown(self): + os_helper.unlink(os_helper.TESTFN) + + def test___all__(self): + support.check__all__(self, self.io, self.name_of_module, + extra=self.extra_exported, + not_exported=self.not_exported) + + def test_attributes(self): + f = self.open(os_helper.TESTFN, "wb", buffering=0) + self.assertEqual(f.mode, "wb") + f.close() + + f = self.open(os_helper.TESTFN, "w+", encoding="utf-8") + self.assertEqual(f.mode, "w+") + self.assertEqual(f.buffer.mode, "wb+") + self.assertEqual(f.buffer.raw.mode, "wb+") + + g = self.open(f.fileno(), "wb", closefd=False) + self.assertEqual(g.mode, "wb") + self.assertEqual(g.raw.mode, "wb") + self.assertEqual(g.name, f.fileno()) + self.assertEqual(g.raw.name, f.fileno()) + f.close() + g.close() + + def test_removed_u_mode(self): + # bpo-37330: The "U" mode has been removed in Python 3.11 + for mode in ("U", "rU", "r+U"): + with self.assertRaises(ValueError) as cm: + self.open(os_helper.TESTFN, mode) + self.assertIn('invalid mode', str(cm.exception)) + + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_open_pipe_with_append(self): + # bpo-27805: Ignore ESPIPE from lseek() in open(). + r, w = os.pipe() + self.addCleanup(os.close, r) + f = self.open(w, 'a', encoding="utf-8") + self.addCleanup(f.close) + # Check that the file is marked non-seekable. On Windows, however, lseek + # somehow succeeds on pipes. + if sys.platform != 'win32': + self.assertFalse(f.seekable()) + + def test_io_after_close(self): + for kwargs in [ + {"mode": "w"}, + {"mode": "wb"}, + {"mode": "w", "buffering": 1}, + {"mode": "w", "buffering": 2}, + {"mode": "wb", "buffering": 0}, + {"mode": "r"}, + {"mode": "rb"}, + {"mode": "r", "buffering": 1}, + {"mode": "r", "buffering": 2}, + {"mode": "rb", "buffering": 0}, + {"mode": "w+"}, + {"mode": "w+b"}, + {"mode": "w+", "buffering": 1}, + {"mode": "w+", "buffering": 2}, + {"mode": "w+b", "buffering": 0}, + ]: + if "b" not in kwargs["mode"]: + kwargs["encoding"] = "utf-8" + f = self.open(os_helper.TESTFN, **kwargs) + f.close() + self.assertRaises(ValueError, f.flush) + self.assertRaises(ValueError, f.fileno) + self.assertRaises(ValueError, f.isatty) + self.assertRaises(ValueError, f.__iter__) + if hasattr(f, "peek"): + self.assertRaises(ValueError, f.peek, 1) + self.assertRaises(ValueError, f.read) + if hasattr(f, "read1"): + self.assertRaises(ValueError, f.read1, 1024) + self.assertRaises(ValueError, f.read1) + if hasattr(f, "readall"): + self.assertRaises(ValueError, f.readall) + if hasattr(f, "readinto"): + self.assertRaises(ValueError, f.readinto, bytearray(1024)) + if hasattr(f, "readinto1"): + self.assertRaises(ValueError, f.readinto1, bytearray(1024)) + self.assertRaises(ValueError, f.readline) + self.assertRaises(ValueError, f.readlines) + self.assertRaises(ValueError, f.readlines, 1) + self.assertRaises(ValueError, f.seek, 0) + self.assertRaises(ValueError, f.tell) + self.assertRaises(ValueError, f.truncate) + self.assertRaises(ValueError, f.write, + b"" if "b" in kwargs['mode'] else "") + self.assertRaises(ValueError, f.writelines, []) + self.assertRaises(ValueError, next, f) + + def test_blockingioerror(self): + # Various BlockingIOError issues + class C(str): + pass + c = C("") + b = self.BlockingIOError(1, c) + c.b = b + b.c = c + wr = weakref.ref(c) + del c, b + support.gc_collect() + self.assertIsNone(wr(), wr) + + def test_abcs(self): + # Test the visible base classes are ABCs. + self.assertIsInstance(self.IOBase, abc.ABCMeta) + self.assertIsInstance(self.RawIOBase, abc.ABCMeta) + self.assertIsInstance(self.BufferedIOBase, abc.ABCMeta) + self.assertIsInstance(self.TextIOBase, abc.ABCMeta) + + def _check_abc_inheritance(self, abcmodule): + with self.open(os_helper.TESTFN, "wb", buffering=0) as f: + self.assertIsInstance(f, abcmodule.IOBase) + self.assertIsInstance(f, abcmodule.RawIOBase) + self.assertNotIsInstance(f, abcmodule.BufferedIOBase) + self.assertNotIsInstance(f, abcmodule.TextIOBase) + with self.open(os_helper.TESTFN, "wb") as f: + self.assertIsInstance(f, abcmodule.IOBase) + self.assertNotIsInstance(f, abcmodule.RawIOBase) + self.assertIsInstance(f, abcmodule.BufferedIOBase) + self.assertNotIsInstance(f, abcmodule.TextIOBase) + with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: + self.assertIsInstance(f, abcmodule.IOBase) + self.assertNotIsInstance(f, abcmodule.RawIOBase) + self.assertNotIsInstance(f, abcmodule.BufferedIOBase) + self.assertIsInstance(f, abcmodule.TextIOBase) + + def test_abc_inheritance(self): + # Test implementations inherit from their respective ABCs + self._check_abc_inheritance(self) + + def test_abc_inheritance_official(self): + # Test implementations inherit from the official ABCs of the + # baseline "io" module. + self._check_abc_inheritance(io) + + def _check_warn_on_dealloc(self, *args, **kwargs): + f = self.open(*args, **kwargs) + r = repr(f) + with self.assertWarns(ResourceWarning) as cm: + f = None + support.gc_collect() + self.assertIn(r, str(cm.warning.args[0])) + + def test_warn_on_dealloc(self): + self._check_warn_on_dealloc(os_helper.TESTFN, "wb", buffering=0) + self._check_warn_on_dealloc(os_helper.TESTFN, "wb") + self._check_warn_on_dealloc(os_helper.TESTFN, "w", encoding="utf-8") + + def _check_warn_on_dealloc_fd(self, *args, **kwargs): + fds = [] + def cleanup_fds(): + for fd in fds: + try: + os.close(fd) + except OSError as e: + if e.errno != errno.EBADF: + raise + self.addCleanup(cleanup_fds) + r, w = os.pipe() + fds += r, w + self._check_warn_on_dealloc(r, *args, **kwargs) + # When using closefd=False, there's no warning + r, w = os.pipe() + fds += r, w + with warnings_helper.check_no_resource_warning(self): + self.open(r, *args, closefd=False, **kwargs) + + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_warn_on_dealloc_fd(self): + self._check_warn_on_dealloc_fd("rb", buffering=0) + self._check_warn_on_dealloc_fd("rb") + self._check_warn_on_dealloc_fd("r", encoding="utf-8") + + + def test_pickling(self): + # Pickling file objects is forbidden + msg = "cannot pickle" + for kwargs in [ + {"mode": "w"}, + {"mode": "wb"}, + {"mode": "wb", "buffering": 0}, + {"mode": "r"}, + {"mode": "rb"}, + {"mode": "rb", "buffering": 0}, + {"mode": "w+"}, + {"mode": "w+b"}, + {"mode": "w+b", "buffering": 0}, + ]: + if "b" not in kwargs["mode"]: + kwargs["encoding"] = "utf-8" + for protocol in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=protocol, kwargs=kwargs): + with self.open(os_helper.TESTFN, **kwargs) as f: + with self.assertRaisesRegex(TypeError, msg): + pickle.dumps(f, protocol) + + @unittest.skipIf(support.is_emscripten, "Emscripten corrupts memory when writing to nonblocking fd") + def test_nonblock_pipe_write_bigbuf(self): + self._test_nonblock_pipe_write(16*1024) + + @unittest.skipIf(support.is_emscripten, "Emscripten corrupts memory when writing to nonblocking fd") + def test_nonblock_pipe_write_smallbuf(self): + self._test_nonblock_pipe_write(1024) + + @unittest.skipUnless(hasattr(os, 'set_blocking'), + 'os.set_blocking() required for this test') + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def _test_nonblock_pipe_write(self, bufsize): + sent = [] + received = [] + r, w = os.pipe() + os.set_blocking(r, False) + os.set_blocking(w, False) + + # To exercise all code paths in the C implementation we need + # to play with buffer sizes. For instance, if we choose a + # buffer size less than or equal to _PIPE_BUF (4096 on Linux) + # then we will never get a partial write of the buffer. + rf = self.open(r, mode='rb', closefd=True, buffering=bufsize) + wf = self.open(w, mode='wb', closefd=True, buffering=bufsize) + + with rf, wf: + for N in 9999, 73, 7574: + try: + i = 0 + while True: + msg = bytes([i % 26 + 97]) * N + sent.append(msg) + wf.write(msg) + i += 1 + + except self.BlockingIOError as e: + self.assertEqual(e.args[0], errno.EAGAIN) + self.assertEqual(e.args[2], e.characters_written) + sent[-1] = sent[-1][:e.characters_written] + received.append(rf.read()) + msg = b'BLOCKED' + wf.write(msg) + sent.append(msg) + + while True: + try: + wf.flush() + break + except self.BlockingIOError as e: + self.assertEqual(e.args[0], errno.EAGAIN) + self.assertEqual(e.args[2], e.characters_written) + self.assertEqual(e.characters_written, 0) + received.append(rf.read()) + + received += iter(rf.read, None) + + sent, received = b''.join(sent), b''.join(received) + self.assertEqual(sent, received) + self.assertTrue(wf.closed) + self.assertTrue(rf.closed) + + def test_create_fail(self): + # 'x' mode fails if file is existing + with self.open(os_helper.TESTFN, 'w', encoding="utf-8"): + pass + self.assertRaises(FileExistsError, self.open, os_helper.TESTFN, 'x', encoding="utf-8") + + def test_create_writes(self): + # 'x' mode opens for writing + with self.open(os_helper.TESTFN, 'xb') as f: + f.write(b"spam") + with self.open(os_helper.TESTFN, 'rb') as f: + self.assertEqual(b"spam", f.read()) + + def test_open_allargs(self): + # there used to be a buffer overflow in the parser for rawmode + self.assertRaises(ValueError, self.open, os_helper.TESTFN, 'rwax+', encoding="utf-8") + + def test_check_encoding_errors(self): + # bpo-37388: open() and TextIOWrapper must check encoding and errors + # arguments in dev mode + mod = self.io.__name__ + filename = __file__ + invalid = 'Boom, Shaka Laka, Boom!' + code = textwrap.dedent(f''' + import sys + from {mod} import open, TextIOWrapper + + try: + open({filename!r}, encoding={invalid!r}) + except LookupError: + pass + else: + sys.exit(21) + + try: + open({filename!r}, errors={invalid!r}) + except LookupError: + pass + else: + sys.exit(22) + + fp = open({filename!r}, "rb") + with fp: + try: + TextIOWrapper(fp, encoding={invalid!r}) + except LookupError: + pass + else: + sys.exit(23) + + try: + TextIOWrapper(fp, errors={invalid!r}) + except LookupError: + pass + else: + sys.exit(24) + + sys.exit(10) + ''') + proc = assert_python_failure('-X', 'dev', '-c', code) + self.assertEqual(proc.rc, 10, proc) + + def test_check_encoding_warning(self): + # PEP 597: Raise warning when encoding is not specified + # and sys.flags.warn_default_encoding is set. + mod = self.io.__name__ + filename = __file__ + code = textwrap.dedent(f'''\ + import sys + from {mod} import open, TextIOWrapper + import pathlib + + with open({filename!r}) as f: # line 5 + pass + + pathlib.Path({filename!r}).read_text() # line 8 + ''') + proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code) + warnings = proc.err.splitlines() + self.assertEqual(len(warnings), 2) + self.assertStartsWith(warnings[0], b"<string>:5: EncodingWarning: ") + self.assertStartsWith(warnings[1], b"<string>:8: EncodingWarning: ") + + def test_text_encoding(self): + # PEP 597, bpo-47000. io.text_encoding() returns "locale" or "utf-8" + # based on sys.flags.utf8_mode + code = "import io; print(io.text_encoding(None))" + + proc = assert_python_ok('-X', 'utf8=0', '-c', code) + self.assertEqual(b"locale", proc.out.strip()) + + proc = assert_python_ok('-X', 'utf8=1', '-c', code) + self.assertEqual(b"utf-8", proc.out.strip()) + + +class CMiscIOTest(MiscIOTest, CTestCase): + name_of_module = "io", "_io" + extra_exported = "BlockingIOError", + + def test_readinto_buffer_overflow(self): + # Issue #18025 + class BadReader(self.io.BufferedIOBase): + def read(self, n=-1): + return b'x' * 10**6 + bufio = BadReader() + b = bytearray(2) + self.assertRaises(ValueError, bufio.readinto, b) + + def check_daemon_threads_shutdown_deadlock(self, stream_name): + # Issue #23309: deadlocks at shutdown should be avoided when a + # daemon thread and the main thread both write to a file. + code = """if 1: + import sys + import time + import threading + from test.support import SuppressCrashReport + + file = sys.{stream_name} + + def run(): + while True: + file.write('.') + file.flush() + + crash = SuppressCrashReport() + crash.__enter__() + # don't call __exit__(): the crash occurs at Python shutdown + + thread = threading.Thread(target=run) + thread.daemon = True + thread.start() + + time.sleep(0.5) + file.write('!') + file.flush() + """.format_map(locals()) + res, _ = run_python_until_end("-c", code) + err = res.err.decode() + if res.rc != 0: + # Failure: should be a fatal error + pattern = (r"Fatal Python error: _enter_buffered_busy: " + r"could not acquire lock " + r"for <(_io\.)?BufferedWriter name='<{stream_name}>'> " + r"at interpreter shutdown, possibly due to " + r"daemon threads".format_map(locals())) + self.assertRegex(err, pattern) + else: + self.assertFalse(err.strip('.!')) + + @threading_helper.requires_working_threading() + @support.requires_resource('walltime') + def test_daemon_threads_shutdown_stdout_deadlock(self): + self.check_daemon_threads_shutdown_deadlock('stdout') + + @threading_helper.requires_working_threading() + @support.requires_resource('walltime') + def test_daemon_threads_shutdown_stderr_deadlock(self): + self.check_daemon_threads_shutdown_deadlock('stderr') + + +class PyMiscIOTest(MiscIOTest, PyTestCase): + name_of_module = "_pyio", "io" + extra_exported = "BlockingIOError", "open_code", + not_exported = "valid_seek_flags", + + +class ProtocolsTest(unittest.TestCase): + class MyReader: + def read(self, sz=-1): + return b"" + + class MyWriter: + def write(self, b: bytes): + pass + + def test_reader_subclass(self): + self.assertIsSubclass(self.MyReader, io.Reader) + self.assertNotIsSubclass(str, io.Reader) + + def test_writer_subclass(self): + self.assertIsSubclass(self.MyWriter, io.Writer) + self.assertNotIsSubclass(str, io.Writer) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_largefile.py b/Lib/test/test_io/test_largefile.py similarity index 98% rename from Lib/test/test_largefile.py rename to Lib/test/test_io/test_largefile.py index 41f7b70e5cf..438a90a92ed 100644 --- a/Lib/test/test_largefile.py +++ b/Lib/test/test_io/test_largefile.py @@ -56,9 +56,7 @@ class TestFileMethods(LargeFileTest): (i.e. > 2 GiB) files. """ - # _pyio.FileIO.readall() uses a temporary bytearray then casted to bytes, - # so memuse=2 is needed - @bigmemtest(size=size, memuse=2, dry_run=False) + @bigmemtest(size=size, memuse=1, dry_run=False) def test_large_read(self, _size): # bpo-24658: Test that a read greater than 2GB does not fail. with self.open(TESTFN, "rb") as f: @@ -154,7 +152,7 @@ class TestFileMethods(LargeFileTest): f.seek(pos) self.assertTrue(f.seekable()) - @bigmemtest(size=size, memuse=2, dry_run=False) + @bigmemtest(size=size, memuse=1, dry_run=False) def test_seek_readall(self, _size): # Seek which doesn't change position should readall successfully. with self.open(TESTFN, 'rb') as f: diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_io/test_memoryio.py similarity index 98% rename from Lib/test/test_memoryio.py rename to Lib/test/test_io/test_memoryio.py index 63998a86c45..bb023735e21 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -54,6 +54,12 @@ class MemorySeekTestMixin: self.assertEqual(buf[3:], bytesIo.read()) self.assertRaises(TypeError, bytesIo.seek, 0.0) + self.assertEqual(sys.maxsize, bytesIo.seek(sys.maxsize)) + self.assertEqual(self.EOF, bytesIo.read(4)) + + self.assertEqual(sys.maxsize - 2, bytesIo.seek(sys.maxsize - 2)) + self.assertEqual(self.EOF, bytesIo.read(4)) + def testTell(self): buf = self.buftype("1234567890") bytesIo = self.ioclass(buf) @@ -552,6 +558,14 @@ class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase): memio.seek(1, 1) self.assertEqual(memio.read(), buf[1:]) + def test_issue141311(self): + memio = self.ioclass() + # Seek allows PY_SSIZE_T_MAX, read should handle that. + # Past end of buffer read should always return 0 (EOF). + self.assertEqual(sys.maxsize, memio.seek(sys.maxsize)) + buf = bytearray(2) + self.assertEqual(0, memio.readinto(buf)) + def test_unicode(self): memio = self.ioclass() diff --git a/Lib/test/test_io/test_signals.py b/Lib/test/test_io/test_signals.py new file mode 100644 index 00000000000..03f1da1eb1c --- /dev/null +++ b/Lib/test/test_io/test_signals.py @@ -0,0 +1,280 @@ +import errno +import os +import signal +import threading +import unittest +from test import support +from test.support import import_helper +from .utils import PyTestCase, CTestCase + + +requires_alarm = unittest.skipUnless( + hasattr(signal, "alarm"), "test requires signal.alarm()" +) + + +@unittest.skipIf(os.name == 'nt', 'POSIX signals required for this test.') +class SignalsTest: + + def setUp(self): + self.oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt) + + def tearDown(self): + signal.signal(signal.SIGALRM, self.oldalrm) + + def alarm_interrupt(self, sig, frame): + 1/0 + + def check_interrupted_write(self, item, bytes, **fdopen_kwargs): + """Check that a partial write, when it gets interrupted, properly + invokes the signal handler, and bubbles up the exception raised + in the latter.""" + + # XXX This test has three flaws that appear when objects are + # XXX not reference counted. + + # - if wio.write() happens to trigger a garbage collection, + # the signal exception may be raised when some __del__ + # method is running; it will not reach the assertRaises() + # call. + + # - more subtle, if the wio object is not destroyed at once + # and survives this function, the next opened file is likely + # to have the same fileno (since the file descriptor was + # actively closed). When wio.__del__ is finally called, it + # will close the other's test file... To trigger this with + # CPython, try adding "global wio" in this function. + + # - This happens only for streams created by the _pyio module, + # because a wio.close() that fails still consider that the + # file needs to be closed again. You can try adding an + # "assert wio.closed" at the end of the function. + + # Fortunately, a little gc.collect() seems to be enough to + # work around all these issues. + support.gc_collect() # For PyPy or other GCs. + + read_results = [] + def _read(): + s = os.read(r, 1) + read_results.append(s) + + t = threading.Thread(target=_read) + t.daemon = True + r, w = os.pipe() + fdopen_kwargs["closefd"] = False + large_data = item * (support.PIPE_MAX_SIZE // len(item) + 1) + try: + wio = self.io.open(w, **fdopen_kwargs) + if hasattr(signal, 'pthread_sigmask'): + # create the thread with SIGALRM signal blocked + signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGALRM]) + t.start() + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGALRM]) + else: + t.start() + + # Fill the pipe enough that the write will be blocking. + # It will be interrupted by the timer armed above. Since the + # other thread has read one byte, the low-level write will + # return with a successful (partial) result rather than an EINTR. + # The buffered IO layer must check for pending signal + # handlers, which in this case will invoke alarm_interrupt(). + signal.alarm(1) + try: + self.assertRaises(ZeroDivisionError, wio.write, large_data) + finally: + signal.alarm(0) + t.join() + # We got one byte, get another one and check that it isn't a + # repeat of the first one. + read_results.append(os.read(r, 1)) + self.assertEqual(read_results, [bytes[0:1], bytes[1:2]]) + finally: + os.close(w) + os.close(r) + # This is deliberate. If we didn't close the file descriptor + # before closing wio, wio would try to flush its internal + # buffer, and block again. + try: + wio.close() + except OSError as e: + if e.errno != errno.EBADF: + raise + + @requires_alarm + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_interrupted_write_unbuffered(self): + self.check_interrupted_write(b"xy", b"xy", mode="wb", buffering=0) + + @requires_alarm + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_interrupted_write_buffered(self): + self.check_interrupted_write(b"xy", b"xy", mode="wb") + + @requires_alarm + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_interrupted_write_text(self): + self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii") + + @support.no_tracing + def check_reentrant_write(self, data, **fdopen_kwargs): + def on_alarm(*args): + # Will be called reentrantly from the same thread + wio.write(data) + 1/0 + signal.signal(signal.SIGALRM, on_alarm) + r, w = os.pipe() + wio = self.io.open(w, **fdopen_kwargs) + try: + signal.alarm(1) + # Either the reentrant call to wio.write() fails with RuntimeError, + # or the signal handler raises ZeroDivisionError. + with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: + while 1: + for i in range(100): + wio.write(data) + wio.flush() + # Make sure the buffer doesn't fill up and block further writes + os.read(r, len(data) * 100) + exc = cm.exception + if isinstance(exc, RuntimeError): + self.assertStartsWith(str(exc), "reentrant call") + finally: + signal.alarm(0) + wio.close() + os.close(r) + + @requires_alarm + def test_reentrant_write_buffered(self): + self.check_reentrant_write(b"xy", mode="wb") + + @requires_alarm + def test_reentrant_write_text(self): + self.check_reentrant_write("xy", mode="w", encoding="ascii") + + def check_interrupted_read_retry(self, decode, **fdopen_kwargs): + """Check that a buffered read, when it gets interrupted (either + returning a partial result or EINTR), properly invokes the signal + handler and retries if the latter returned successfully.""" + r, w = os.pipe() + fdopen_kwargs["closefd"] = False + def alarm_handler(sig, frame): + os.write(w, b"bar") + signal.signal(signal.SIGALRM, alarm_handler) + try: + rio = self.io.open(r, **fdopen_kwargs) + os.write(w, b"foo") + signal.alarm(1) + # Expected behaviour: + # - first raw read() returns partial b"foo" + # - second raw read() returns EINTR + # - third raw read() returns b"bar" + self.assertEqual(decode(rio.read(6)), "foobar") + finally: + signal.alarm(0) + rio.close() + os.close(w) + os.close(r) + + @requires_alarm + @support.requires_resource('walltime') + def test_interrupted_read_retry_buffered(self): + self.check_interrupted_read_retry(lambda x: x.decode('latin1'), + mode="rb") + + @requires_alarm + @support.requires_resource('walltime') + def test_interrupted_read_retry_text(self): + self.check_interrupted_read_retry(lambda x: x, + mode="r", encoding="latin1") + + def check_interrupted_write_retry(self, item, **fdopen_kwargs): + """Check that a buffered write, when it gets interrupted (either + returning a partial result or EINTR), properly invokes the signal + handler and retries if the latter returned successfully.""" + select = import_helper.import_module("select") + + # A quantity that exceeds the buffer size of an anonymous pipe's + # write end. + N = support.PIPE_MAX_SIZE + r, w = os.pipe() + fdopen_kwargs["closefd"] = False + + # We need a separate thread to read from the pipe and allow the + # write() to finish. This thread is started after the SIGALRM is + # received (forcing a first EINTR in write()). + read_results = [] + write_finished = False + error = None + def _read(): + try: + while not write_finished: + while r in select.select([r], [], [], 1.0)[0]: + s = os.read(r, 1024) + read_results.append(s) + except BaseException as exc: + nonlocal error + error = exc + t = threading.Thread(target=_read) + t.daemon = True + def alarm1(sig, frame): + signal.signal(signal.SIGALRM, alarm2) + signal.alarm(1) + def alarm2(sig, frame): + t.start() + + large_data = item * N + signal.signal(signal.SIGALRM, alarm1) + try: + wio = self.io.open(w, **fdopen_kwargs) + signal.alarm(1) + # Expected behaviour: + # - first raw write() is partial (because of the limited pipe buffer + # and the first alarm) + # - second raw write() returns EINTR (because of the second alarm) + # - subsequent write()s are successful (either partial or complete) + written = wio.write(large_data) + self.assertEqual(N, written) + + wio.flush() + write_finished = True + t.join() + + self.assertIsNone(error) + self.assertEqual(N, sum(len(x) for x in read_results)) + finally: + signal.alarm(0) + write_finished = True + os.close(w) + os.close(r) + # This is deliberate. If we didn't close the file descriptor + # before closing wio, wio would try to flush its internal + # buffer, and could block (in case of failure). + try: + wio.close() + except OSError as e: + if e.errno != errno.EBADF: + raise + + @requires_alarm + @support.requires_resource('walltime') + def test_interrupted_write_retry_buffered(self): + self.check_interrupted_write_retry(b"x", mode="wb") + + @requires_alarm + @support.requires_resource('walltime') + def test_interrupted_write_retry_text(self): + self.check_interrupted_write_retry("x", mode="w", encoding="latin1") + + +class CSignalsTest(SignalsTest, CTestCase): + pass + +class PySignalsTest(SignalsTest, PyTestCase): + pass + + # Handling reentrancy issues would slow down _pyio even more, so the + # tests are disabled. + test_reentrant_write_buffered = None + test_reentrant_write_text = None diff --git a/Lib/test/test_io/test_textio.py b/Lib/test/test_io/test_textio.py new file mode 100644 index 00000000000..d725f9212ce --- /dev/null +++ b/Lib/test/test_io/test_textio.py @@ -0,0 +1,1699 @@ +import array +import codecs +import locale +import os +import pickle +import sys +import threading +import time +import unittest +import warnings +import weakref +from collections import UserList +from test import support +from test.support import os_helper, threading_helper +from test.support.script_helper import assert_python_ok +from .utils import CTestCase, PyTestCase + +import io # C implementation of io +import _pyio as pyio # Python implementation of io + + +def _default_chunk_size(): + """Get the default TextIOWrapper chunk size""" + with open(__file__, "r", encoding="latin-1") as f: + return f._CHUNK_SIZE + + +class BadIndex: + def __index__(self): + 1/0 + + +# To fully exercise seek/tell, the StatefulIncrementalDecoder has these +# properties: +# - A single output character can correspond to many bytes of input. +# - The number of input bytes to complete the character can be +# undetermined until the last input byte is received. +# - The number of input bytes can vary depending on previous input. +# - A single input byte can correspond to many characters of output. +# - The number of output characters can be undetermined until the +# last input byte is received. +# - The number of output characters can vary depending on previous input. + +class StatefulIncrementalDecoder(codecs.IncrementalDecoder): + """ + For testing seek/tell behavior with a stateful, buffering decoder. + + Input is a sequence of words. Words may be fixed-length (length set + by input) or variable-length (period-terminated). In variable-length + mode, extra periods are ignored. Possible words are: + - 'i' followed by a number sets the input length, I (maximum 99). + When I is set to 0, words are space-terminated. + - 'o' followed by a number sets the output length, O (maximum 99). + - Any other word is converted into a word followed by a period on + the output. The output word consists of the input word truncated + or padded out with hyphens to make its length equal to O. If O + is 0, the word is output verbatim without truncating or padding. + I and O are initially set to 1. When I changes, any buffered input is + re-scanned according to the new I. EOF also terminates the last word. + """ + + def __init__(self, errors='strict'): + codecs.IncrementalDecoder.__init__(self, errors) + self.reset() + + def __repr__(self): + return '<SID %x>' % id(self) + + def reset(self): + self.i = 1 + self.o = 1 + self.buffer = bytearray() + + def getstate(self): + i, o = self.i ^ 1, self.o ^ 1 # so that flags = 0 after reset() + return bytes(self.buffer), i*100 + o + + def setstate(self, state): + buffer, io = state + self.buffer = bytearray(buffer) + i, o = divmod(io, 100) + self.i, self.o = i ^ 1, o ^ 1 + + def decode(self, input, final=False): + output = '' + for b in input: + if self.i == 0: # variable-length, terminated with period + if b == ord('.'): + if self.buffer: + output += self.process_word() + else: + self.buffer.append(b) + else: # fixed-length, terminate after self.i bytes + self.buffer.append(b) + if len(self.buffer) == self.i: + output += self.process_word() + if final and self.buffer: # EOF terminates the last word + output += self.process_word() + return output + + def process_word(self): + output = '' + if self.buffer[0] == ord('i'): + self.i = min(99, int(self.buffer[1:] or 0)) # set input length + elif self.buffer[0] == ord('o'): + self.o = min(99, int(self.buffer[1:] or 0)) # set output length + else: + output = self.buffer.decode('ascii') + if len(output) < self.o: + output += '-'*self.o # pad out with hyphens + if self.o: + output = output[:self.o] # truncate to output length + output += '.' + self.buffer = bytearray() + return output + + codecEnabled = False + + +# bpo-41919: This method is separated from StatefulIncrementalDecoder to avoid a resource leak +# when registering codecs and cleanup functions. +def lookupTestDecoder(name): + if StatefulIncrementalDecoder.codecEnabled and name == 'test_decoder': + latin1 = codecs.lookup('latin-1') + return codecs.CodecInfo( + name='test_decoder', encode=latin1.encode, decode=None, + incrementalencoder=None, + streamreader=None, streamwriter=None, + incrementaldecoder=StatefulIncrementalDecoder) + + +class StatefulIncrementalDecoderTest(unittest.TestCase): + """ + Make sure the StatefulIncrementalDecoder actually works. + """ + + test_cases = [ + # I=1, O=1 (fixed-length input == fixed-length output) + (b'abcd', False, 'a.b.c.d.'), + # I=0, O=0 (variable-length input, variable-length output) + (b'oiabcd', True, 'abcd.'), + # I=0, O=0 (should ignore extra periods) + (b'oi...abcd...', True, 'abcd.'), + # I=0, O=6 (variable-length input, fixed-length output) + (b'i.o6.x.xyz.toolongtofit.', False, 'x-----.xyz---.toolon.'), + # I=2, O=6 (fixed-length input < fixed-length output) + (b'i.i2.o6xyz', True, 'xy----.z-----.'), + # I=6, O=3 (fixed-length input > fixed-length output) + (b'i.o3.i6.abcdefghijklmnop', True, 'abc.ghi.mno.'), + # I=0, then 3; O=29, then 15 (with longer output) + (b'i.o29.a.b.cde.o15.abcdefghijabcdefghij.i3.a.b.c.d.ei00k.l.m', True, + 'a----------------------------.' + + 'b----------------------------.' + + 'cde--------------------------.' + + 'abcdefghijabcde.' + + 'a.b------------.' + + '.c.------------.' + + 'd.e------------.' + + 'k--------------.' + + 'l--------------.' + + 'm--------------.') + ] + + def test_decoder(self): + # Try a few one-shot test cases. + for input, eof, output in self.test_cases: + d = StatefulIncrementalDecoder() + self.assertEqual(d.decode(input, eof), output) + + # Also test an unfinished decode, followed by forcing EOF. + d = StatefulIncrementalDecoder() + self.assertEqual(d.decode(b'oiabcd'), '') + self.assertEqual(d.decode(b'', 1), 'abcd.') + +class TextIOWrapperTest: + + def setUp(self): + self.testdata = b"AAA\r\nBBB\rCCC\r\nDDD\nEEE\r\n" + self.normalized = b"AAA\nBBB\nCCC\nDDD\nEEE\n".decode("ascii") + os_helper.unlink(os_helper.TESTFN) + codecs.register(lookupTestDecoder) + self.addCleanup(codecs.unregister, lookupTestDecoder) + + def tearDown(self): + os_helper.unlink(os_helper.TESTFN) + + def test_constructor(self): + r = self.BytesIO(b"\xc3\xa9\n\n") + b = self.BufferedReader(r, 1000) + t = self.TextIOWrapper(b, encoding="utf-8") + t.__init__(b, encoding="latin-1", newline="\r\n") + self.assertEqual(t.encoding, "latin-1") + self.assertEqual(t.line_buffering, False) + t.__init__(b, encoding="utf-8", line_buffering=True) + self.assertEqual(t.encoding, "utf-8") + self.assertEqual(t.line_buffering, True) + self.assertEqual("\xe9\n", t.readline()) + invalid_type = TypeError if self.is_C else ValueError + with self.assertRaises(invalid_type): + t.__init__(b, encoding=42) + with self.assertRaises(UnicodeEncodeError): + t.__init__(b, encoding='\udcfe') + with self.assertRaises(ValueError): + t.__init__(b, encoding='utf-8\0') + with self.assertRaises(invalid_type): + t.__init__(b, encoding="utf-8", errors=42) + if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: + with self.assertRaises(UnicodeEncodeError): + t.__init__(b, encoding="utf-8", errors='\udcfe') + if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", errors='replace\0') + with self.assertRaises(TypeError): + t.__init__(b, encoding="utf-8", newline=42) + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", newline='\udcfe') + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", newline='\n\0') + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", newline='xyzzy') + + def test_uninitialized(self): + t = self.TextIOWrapper.__new__(self.TextIOWrapper) + del t + t = self.TextIOWrapper.__new__(self.TextIOWrapper) + self.assertRaises(Exception, repr, t) + self.assertRaisesRegex((ValueError, AttributeError), + 'uninitialized|has no attribute', + t.read, 0) + t.__init__(self.MockRawIO(), encoding="utf-8") + self.assertEqual(t.read(0), '') + + def test_non_text_encoding_codecs_are_rejected(self): + # Ensure the constructor complains if passed a codec that isn't + # marked as a text encoding + # http://bugs.python.org/issue20404 + r = self.BytesIO() + b = self.BufferedWriter(r) + with self.assertRaisesRegex(LookupError, "is not a text encoding"): + self.TextIOWrapper(b, encoding="hex") + + def test_detach(self): + r = self.BytesIO() + b = self.BufferedWriter(r) + t = self.TextIOWrapper(b, encoding="ascii") + self.assertIs(t.detach(), b) + + t = self.TextIOWrapper(b, encoding="ascii") + t.write("howdy") + self.assertFalse(r.getvalue()) + t.detach() + self.assertEqual(r.getvalue(), b"howdy") + self.assertRaises(ValueError, t.detach) + + # Operations independent of the detached stream should still work + repr(t) + self.assertEqual(t.encoding, "ascii") + self.assertEqual(t.errors, "strict") + self.assertFalse(t.line_buffering) + self.assertFalse(t.write_through) + + def test_repr(self): + raw = self.BytesIO("hello".encode("utf-8")) + b = self.BufferedReader(raw) + t = self.TextIOWrapper(b, encoding="utf-8") + modname = self.TextIOWrapper.__module__ + self.assertRegex(repr(t), + r"<(%s\.)?TextIOWrapper encoding='utf-8'>" % modname) + raw.name = "dummy" + self.assertRegex(repr(t), + r"<(%s\.)?TextIOWrapper name='dummy' encoding='utf-8'>" % modname) + t.mode = "r" + self.assertRegex(repr(t), + r"<(%s\.)?TextIOWrapper name='dummy' mode='r' encoding='utf-8'>" % modname) + raw.name = b"dummy" + self.assertRegex(repr(t), + r"<(%s\.)?TextIOWrapper name=b'dummy' mode='r' encoding='utf-8'>" % modname) + + t.buffer.detach() + repr(t) # Should not raise an exception + + def test_recursive_repr(self): + # Issue #25455 + raw = self.BytesIO() + t = self.TextIOWrapper(raw, encoding="utf-8") + with support.swap_attr(raw, 'name', t), support.infinite_recursion(25): + with self.assertRaises(RuntimeError): + repr(t) # Should not crash + + def test_subclass_repr(self): + class TestSubclass(self.TextIOWrapper): + pass + + f = TestSubclass(self.StringIO()) + self.assertIn(TestSubclass.__name__, repr(f)) + + def test_line_buffering(self): + r = self.BytesIO() + b = self.BufferedWriter(r, 1000) + t = self.TextIOWrapper(b, encoding="utf-8", newline="\n", line_buffering=True) + t.write("X") + self.assertEqual(r.getvalue(), b"") # No flush happened + t.write("Y\nZ") + self.assertEqual(r.getvalue(), b"XY\nZ") # All got flushed + t.write("A\rB") + self.assertEqual(r.getvalue(), b"XY\nZA\rB") + + def test_reconfigure_line_buffering(self): + r = self.BytesIO() + b = self.BufferedWriter(r, 1000) + t = self.TextIOWrapper(b, encoding="utf-8", newline="\n", line_buffering=False) + t.write("AB\nC") + self.assertEqual(r.getvalue(), b"") + + t.reconfigure(line_buffering=True) # implicit flush + self.assertEqual(r.getvalue(), b"AB\nC") + t.write("DEF\nG") + self.assertEqual(r.getvalue(), b"AB\nCDEF\nG") + t.write("H") + self.assertEqual(r.getvalue(), b"AB\nCDEF\nG") + t.reconfigure(line_buffering=False) # implicit flush + self.assertEqual(r.getvalue(), b"AB\nCDEF\nGH") + t.write("IJ") + self.assertEqual(r.getvalue(), b"AB\nCDEF\nGH") + + # Keeping default value + t.reconfigure() + t.reconfigure(line_buffering=None) + self.assertEqual(t.line_buffering, False) + t.reconfigure(line_buffering=True) + t.reconfigure() + t.reconfigure(line_buffering=None) + self.assertEqual(t.line_buffering, True) + + @unittest.skipIf(sys.flags.utf8_mode, "utf-8 mode is enabled") + def test_default_encoding(self): + with os_helper.EnvironmentVarGuard() as env: + # try to get a user preferred encoding different than the current + # locale encoding to check that TextIOWrapper() uses the current + # locale encoding and not the user preferred encoding + env.unset('LC_ALL', 'LANG', 'LC_CTYPE') + + current_locale_encoding = locale.getencoding() + b = self.BytesIO() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", EncodingWarning) + t = self.TextIOWrapper(b) + self.assertEqual(t.encoding, current_locale_encoding) + + def test_encoding(self): + # Check the encoding attribute is always set, and valid + b = self.BytesIO() + t = self.TextIOWrapper(b, encoding="utf-8") + self.assertEqual(t.encoding, "utf-8") + with warnings.catch_warnings(): + warnings.simplefilter("ignore", EncodingWarning) + t = self.TextIOWrapper(b) + self.assertIsNotNone(t.encoding) + codecs.lookup(t.encoding) + + def test_encoding_errors_reading(self): + # (1) default + b = self.BytesIO(b"abc\n\xff\n") + t = self.TextIOWrapper(b, encoding="ascii") + self.assertRaises(UnicodeError, t.read) + # (2) explicit strict + b = self.BytesIO(b"abc\n\xff\n") + t = self.TextIOWrapper(b, encoding="ascii", errors="strict") + self.assertRaises(UnicodeError, t.read) + # (3) ignore + b = self.BytesIO(b"abc\n\xff\n") + t = self.TextIOWrapper(b, encoding="ascii", errors="ignore") + self.assertEqual(t.read(), "abc\n\n") + # (4) replace + b = self.BytesIO(b"abc\n\xff\n") + t = self.TextIOWrapper(b, encoding="ascii", errors="replace") + self.assertEqual(t.read(), "abc\n\ufffd\n") + + def test_encoding_errors_writing(self): + # (1) default + b = self.BytesIO() + t = self.TextIOWrapper(b, encoding="ascii") + self.assertRaises(UnicodeError, t.write, "\xff") + # (2) explicit strict + b = self.BytesIO() + t = self.TextIOWrapper(b, encoding="ascii", errors="strict") + self.assertRaises(UnicodeError, t.write, "\xff") + # (3) ignore + b = self.BytesIO() + t = self.TextIOWrapper(b, encoding="ascii", errors="ignore", + newline="\n") + t.write("abc\xffdef\n") + t.flush() + self.assertEqual(b.getvalue(), b"abcdef\n") + # (4) replace + b = self.BytesIO() + t = self.TextIOWrapper(b, encoding="ascii", errors="replace", + newline="\n") + t.write("abc\xffdef\n") + t.flush() + self.assertEqual(b.getvalue(), b"abc?def\n") + + def test_newlines(self): + input_lines = [ "unix\n", "windows\r\n", "os9\r", "last\n", "nonl" ] + + tests = [ + [ None, [ 'unix\n', 'windows\n', 'os9\n', 'last\n', 'nonl' ] ], + [ '', input_lines ], + [ '\n', [ "unix\n", "windows\r\n", "os9\rlast\n", "nonl" ] ], + [ '\r\n', [ "unix\nwindows\r\n", "os9\rlast\nnonl" ] ], + [ '\r', [ "unix\nwindows\r", "\nos9\r", "last\nnonl" ] ], + ] + encodings = ( + 'utf-8', 'latin-1', + 'utf-16', 'utf-16-le', 'utf-16-be', + 'utf-32', 'utf-32-le', 'utf-32-be', + ) + + # Try a range of buffer sizes to test the case where \r is the last + # character in TextIOWrapper._pending_line. + for encoding in encodings: + # XXX: str.encode() should return bytes + data = bytes(''.join(input_lines).encode(encoding)) + for do_reads in (False, True): + for bufsize in range(1, 10): + for newline, exp_lines in tests: + bufio = self.BufferedReader(self.BytesIO(data), bufsize) + textio = self.TextIOWrapper(bufio, newline=newline, + encoding=encoding) + if do_reads: + got_lines = [] + while True: + c2 = textio.read(2) + if c2 == '': + break + self.assertEqual(len(c2), 2) + got_lines.append(c2 + textio.readline()) + else: + got_lines = list(textio) + + for got_line, exp_line in zip(got_lines, exp_lines): + self.assertEqual(got_line, exp_line) + self.assertEqual(len(got_lines), len(exp_lines)) + + def test_newlines_input(self): + testdata = b"AAA\nBB\x00B\nCCC\rDDD\rEEE\r\nFFF\r\nGGG" + normalized = testdata.replace(b"\r\n", b"\n").replace(b"\r", b"\n") + for newline, expected in [ + (None, normalized.decode("ascii").splitlines(keepends=True)), + ("", testdata.decode("ascii").splitlines(keepends=True)), + ("\n", ["AAA\n", "BB\x00B\n", "CCC\rDDD\rEEE\r\n", "FFF\r\n", "GGG"]), + ("\r\n", ["AAA\nBB\x00B\nCCC\rDDD\rEEE\r\n", "FFF\r\n", "GGG"]), + ("\r", ["AAA\nBB\x00B\nCCC\r", "DDD\r", "EEE\r", "\nFFF\r", "\nGGG"]), + ]: + buf = self.BytesIO(testdata) + txt = self.TextIOWrapper(buf, encoding="ascii", newline=newline) + self.assertEqual(txt.readlines(), expected) + txt.seek(0) + self.assertEqual(txt.read(), "".join(expected)) + + def test_newlines_output(self): + testdict = { + "": b"AAA\nBBB\nCCC\nX\rY\r\nZ", + "\n": b"AAA\nBBB\nCCC\nX\rY\r\nZ", + "\r": b"AAA\rBBB\rCCC\rX\rY\r\rZ", + "\r\n": b"AAA\r\nBBB\r\nCCC\r\nX\rY\r\r\nZ", + } + tests = [(None, testdict[os.linesep])] + sorted(testdict.items()) + for newline, expected in tests: + buf = self.BytesIO() + txt = self.TextIOWrapper(buf, encoding="ascii", newline=newline) + txt.write("AAA\nB") + txt.write("BB\nCCC\n") + txt.write("X\rY\r\nZ") + txt.flush() + self.assertEqual(buf.closed, False) + self.assertEqual(buf.getvalue(), expected) + + def test_destructor(self): + l = [] + base = self.BytesIO + class MyBytesIO(base): + def close(self): + l.append(self.getvalue()) + base.close(self) + b = MyBytesIO() + t = self.TextIOWrapper(b, encoding="ascii") + t.write("abc") + del t + support.gc_collect() + self.assertEqual([b"abc"], l) + + def test_override_destructor(self): + record = [] + class MyTextIO(self.TextIOWrapper): + def __del__(self): + record.append(1) + try: + f = super().__del__ + except AttributeError: + pass + else: + f() + def close(self): + record.append(2) + super().close() + def flush(self): + record.append(3) + super().flush() + b = self.BytesIO() + t = MyTextIO(b, encoding="ascii") + del t + support.gc_collect() + self.assertEqual(record, [1, 2, 3]) + + def test_error_through_destructor(self): + # Test that the exception state is not modified by a destructor, + # even if close() fails. + rawio = self.CloseFailureIO() + with support.catch_unraisable_exception() as cm: + with self.assertRaises(AttributeError): + self.TextIOWrapper(rawio, encoding="utf-8").xyzzy + + self.assertEqual(cm.unraisable.exc_type, OSError) + + # Systematic tests of the text I/O API + + def test_basic_io(self): + for chunksize in (1, 2, 3, 4, 5, 15, 16, 17, 31, 32, 33, 63, 64, 65): + for enc in "ascii", "latin-1", "utf-8" :# , "utf-16-be", "utf-16-le": + f = self.open(os_helper.TESTFN, "w+", encoding=enc) + f._CHUNK_SIZE = chunksize + self.assertEqual(f.write("abc"), 3) + f.close() + f = self.open(os_helper.TESTFN, "r+", encoding=enc) + f._CHUNK_SIZE = chunksize + self.assertEqual(f.tell(), 0) + self.assertEqual(f.read(), "abc") + cookie = f.tell() + self.assertEqual(f.seek(0), 0) + self.assertEqual(f.read(None), "abc") + f.seek(0) + self.assertEqual(f.read(2), "ab") + self.assertEqual(f.read(1), "c") + self.assertEqual(f.read(1), "") + self.assertEqual(f.read(), "") + self.assertEqual(f.tell(), cookie) + self.assertEqual(f.seek(0), 0) + self.assertEqual(f.seek(0, 2), cookie) + self.assertEqual(f.write("def"), 3) + self.assertEqual(f.seek(cookie), cookie) + self.assertEqual(f.read(), "def") + if enc.startswith("utf"): + self.multi_line_test(f, enc) + f.close() + + def multi_line_test(self, f, enc): + f.seek(0) + f.truncate() + sample = "s\xff\u0fff\uffff" + wlines = [] + for size in (0, 1, 2, 3, 4, 5, 30, 31, 32, 33, 62, 63, 64, 65, 1000): + chars = [] + for i in range(size): + chars.append(sample[i % len(sample)]) + line = "".join(chars) + "\n" + wlines.append((f.tell(), line)) + f.write(line) + f.seek(0) + rlines = [] + while True: + pos = f.tell() + line = f.readline() + if not line: + break + rlines.append((pos, line)) + self.assertEqual(rlines, wlines) + + def test_telling(self): + f = self.open(os_helper.TESTFN, "w+", encoding="utf-8") + p0 = f.tell() + f.write("\xff\n") + p1 = f.tell() + f.write("\xff\n") + p2 = f.tell() + f.seek(0) + self.assertEqual(f.tell(), p0) + self.assertEqual(f.readline(), "\xff\n") + self.assertEqual(f.tell(), p1) + self.assertEqual(f.readline(), "\xff\n") + self.assertEqual(f.tell(), p2) + f.seek(0) + for line in f: + self.assertEqual(line, "\xff\n") + self.assertRaises(OSError, f.tell) + self.assertEqual(f.tell(), p2) + f.close() + + def test_seeking(self): + chunk_size = _default_chunk_size() + prefix_size = chunk_size - 2 + u_prefix = "a" * prefix_size + prefix = bytes(u_prefix.encode("utf-8")) + self.assertEqual(len(u_prefix), len(prefix)) + u_suffix = "\u8888\n" + suffix = bytes(u_suffix.encode("utf-8")) + line = prefix + suffix + with self.open(os_helper.TESTFN, "wb") as f: + f.write(line*2) + with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: + s = f.read(prefix_size) + self.assertEqual(s, str(prefix, "ascii")) + self.assertEqual(f.tell(), prefix_size) + self.assertEqual(f.readline(), u_suffix) + + def test_seeking_too(self): + # Regression test for a specific bug + data = b'\xe0\xbf\xbf\n' + with self.open(os_helper.TESTFN, "wb") as f: + f.write(data) + with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f: + f._CHUNK_SIZE # Just test that it exists + f._CHUNK_SIZE = 2 + f.readline() + f.tell() + + def test_seek_and_tell(self): + #Test seek/tell using the StatefulIncrementalDecoder. + # Make test faster by doing smaller seeks + CHUNK_SIZE = 128 + + def test_seek_and_tell_with_data(data, min_pos=0): + """Tell/seek to various points within a data stream and ensure + that the decoded data returned by read() is consistent.""" + f = self.open(os_helper.TESTFN, 'wb') + f.write(data) + f.close() + f = self.open(os_helper.TESTFN, encoding='test_decoder') + f._CHUNK_SIZE = CHUNK_SIZE + decoded = f.read() + f.close() + + for i in range(min_pos, len(decoded) + 1): # seek positions + for j in [1, 5, len(decoded) - i]: # read lengths + f = self.open(os_helper.TESTFN, encoding='test_decoder') + self.assertEqual(f.read(i), decoded[:i]) + cookie = f.tell() + self.assertEqual(f.read(j), decoded[i:i + j]) + f.seek(cookie) + self.assertEqual(f.read(), decoded[i:]) + f.close() + + # Enable the test decoder. + StatefulIncrementalDecoder.codecEnabled = 1 + + # Run the tests. + try: + # Try each test case. + for input, _, _ in StatefulIncrementalDecoderTest.test_cases: + test_seek_and_tell_with_data(input) + + # Position each test case so that it crosses a chunk boundary. + for input, _, _ in StatefulIncrementalDecoderTest.test_cases: + offset = CHUNK_SIZE - len(input)//2 + prefix = b'.'*offset + # Don't bother seeking into the prefix (takes too long). + min_pos = offset*2 + test_seek_and_tell_with_data(prefix + input, min_pos) + + # Ensure our test decoder won't interfere with subsequent tests. + finally: + StatefulIncrementalDecoder.codecEnabled = 0 + + def test_multibyte_seek_and_tell(self): + f = self.open(os_helper.TESTFN, "w", encoding="euc_jp") + f.write("AB\n\u3046\u3048\n") + f.close() + + f = self.open(os_helper.TESTFN, "r", encoding="euc_jp") + self.assertEqual(f.readline(), "AB\n") + p0 = f.tell() + self.assertEqual(f.readline(), "\u3046\u3048\n") + p1 = f.tell() + f.seek(p0) + self.assertEqual(f.readline(), "\u3046\u3048\n") + self.assertEqual(f.tell(), p1) + f.close() + + def test_tell_after_readline_with_cr(self): + # Test for gh-141314: TextIOWrapper.tell() assertion failure + # when dealing with standalone carriage returns + data = b'line1\r' + with self.open(os_helper.TESTFN, "wb") as f: + f.write(data) + + with self.open(os_helper.TESTFN, "r") as f: + # Read line that ends with \r + line = f.readline() + self.assertEqual(line, "line1\n") + # This should not cause an assertion failure + pos = f.tell() + # Verify we can seek back to this position + f.seek(pos) + remaining = f.read() + self.assertEqual(remaining, "") + + + def test_seek_with_encoder_state(self): + f = self.open(os_helper.TESTFN, "w", encoding="euc_jis_2004") + f.write("\u00e6\u0300") + p0 = f.tell() + f.write("\u00e6") + f.seek(p0) + f.write("\u0300") + f.close() + + f = self.open(os_helper.TESTFN, "r", encoding="euc_jis_2004") + self.assertEqual(f.readline(), "\u00e6\u0300\u0300") + f.close() + + def test_encoded_writes(self): + data = "1234567890" + tests = ("utf-16", + "utf-16-le", + "utf-16-be", + "utf-32", + "utf-32-le", + "utf-32-be") + for encoding in tests: + buf = self.BytesIO() + f = self.TextIOWrapper(buf, encoding=encoding) + # Check if the BOM is written only once (see issue1753). + f.write(data) + f.write(data) + f.seek(0) + self.assertEqual(f.read(), data * 2) + f.seek(0) + self.assertEqual(f.read(), data * 2) + self.assertEqual(buf.getvalue(), (data * 2).encode(encoding)) + + def test_unreadable(self): + class UnReadable(self.BytesIO): + def readable(self): + return False + txt = self.TextIOWrapper(UnReadable(), encoding="utf-8") + self.assertRaises(OSError, txt.read) + + def test_read_one_by_one(self): + txt = self.TextIOWrapper(self.BytesIO(b"AA\r\nBB"), encoding="utf-8") + reads = "" + while True: + c = txt.read(1) + if not c: + break + reads += c + self.assertEqual(reads, "AA\nBB") + + def test_readlines(self): + txt = self.TextIOWrapper(self.BytesIO(b"AA\nBB\nCC"), encoding="utf-8") + self.assertEqual(txt.readlines(), ["AA\n", "BB\n", "CC"]) + txt.seek(0) + self.assertEqual(txt.readlines(None), ["AA\n", "BB\n", "CC"]) + txt.seek(0) + self.assertEqual(txt.readlines(5), ["AA\n", "BB\n"]) + + # read in amounts equal to TextIOWrapper._CHUNK_SIZE which is 128. + def test_read_by_chunk(self): + # make sure "\r\n" straddles 128 char boundary. + txt = self.TextIOWrapper(self.BytesIO(b"A" * 127 + b"\r\nB"), encoding="utf-8") + reads = "" + while True: + c = txt.read(128) + if not c: + break + reads += c + self.assertEqual(reads, "A"*127+"\nB") + + def test_writelines(self): + l = ['ab', 'cd', 'ef'] + buf = self.BytesIO() + txt = self.TextIOWrapper(buf, encoding="utf-8") + txt.writelines(l) + txt.flush() + self.assertEqual(buf.getvalue(), b'abcdef') + + def test_writelines_userlist(self): + l = UserList(['ab', 'cd', 'ef']) + buf = self.BytesIO() + txt = self.TextIOWrapper(buf, encoding="utf-8") + txt.writelines(l) + txt.flush() + self.assertEqual(buf.getvalue(), b'abcdef') + + def test_writelines_error(self): + txt = self.TextIOWrapper(self.BytesIO(), encoding="utf-8") + self.assertRaises(TypeError, txt.writelines, [1, 2, 3]) + self.assertRaises(TypeError, txt.writelines, None) + self.assertRaises(TypeError, txt.writelines, b'abc') + + def test_issue1395_1(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + + # read one char at a time + reads = "" + while True: + c = txt.read(1) + if not c: + break + reads += c + self.assertEqual(reads, self.normalized) + + def test_issue1395_2(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + txt._CHUNK_SIZE = 4 + + reads = "" + while True: + c = txt.read(4) + if not c: + break + reads += c + self.assertEqual(reads, self.normalized) + + def test_issue1395_3(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + txt._CHUNK_SIZE = 4 + + reads = txt.read(4) + reads += txt.read(4) + reads += txt.readline() + reads += txt.readline() + reads += txt.readline() + self.assertEqual(reads, self.normalized) + + def test_issue1395_4(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + txt._CHUNK_SIZE = 4 + + reads = txt.read(4) + reads += txt.read() + self.assertEqual(reads, self.normalized) + + def test_issue1395_5(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + txt._CHUNK_SIZE = 4 + + reads = txt.read(4) + pos = txt.tell() + txt.seek(0) + txt.seek(pos) + self.assertEqual(txt.read(4), "BBB\n") + + def test_issue2282(self): + buffer = self.BytesIO(self.testdata) + txt = self.TextIOWrapper(buffer, encoding="ascii") + + self.assertEqual(buffer.seekable(), txt.seekable()) + + def test_append_bom(self): + # The BOM is not written again when appending to a non-empty file + filename = os_helper.TESTFN + for charset in ('utf-8-sig', 'utf-16', 'utf-32'): + with self.open(filename, 'w', encoding=charset) as f: + f.write('aaa') + pos = f.tell() + with self.open(filename, 'rb') as f: + self.assertEqual(f.read(), 'aaa'.encode(charset)) + + with self.open(filename, 'a', encoding=charset) as f: + f.write('xxx') + with self.open(filename, 'rb') as f: + self.assertEqual(f.read(), 'aaaxxx'.encode(charset)) + + def test_seek_bom(self): + # Same test, but when seeking manually + filename = os_helper.TESTFN + for charset in ('utf-8-sig', 'utf-16', 'utf-32'): + with self.open(filename, 'w', encoding=charset) as f: + f.write('aaa') + pos = f.tell() + with self.open(filename, 'r+', encoding=charset) as f: + f.seek(pos) + f.write('zzz') + f.seek(0) + f.write('bbb') + with self.open(filename, 'rb') as f: + self.assertEqual(f.read(), 'bbbzzz'.encode(charset)) + + def test_seek_append_bom(self): + # Same test, but first seek to the start and then to the end + filename = os_helper.TESTFN + for charset in ('utf-8-sig', 'utf-16', 'utf-32'): + with self.open(filename, 'w', encoding=charset) as f: + f.write('aaa') + with self.open(filename, 'a', encoding=charset) as f: + f.seek(0) + f.seek(0, self.SEEK_END) + f.write('xxx') + with self.open(filename, 'rb') as f: + self.assertEqual(f.read(), 'aaaxxx'.encode(charset)) + + def test_errors_property(self): + with self.open(os_helper.TESTFN, "w", encoding="utf-8") as f: + self.assertEqual(f.errors, "strict") + with self.open(os_helper.TESTFN, "w", encoding="utf-8", errors="replace") as f: + self.assertEqual(f.errors, "replace") + + @support.no_tracing + @threading_helper.requires_working_threading() + def test_threads_write(self): + # Issue6750: concurrent writes could duplicate data + event = threading.Event() + with self.open(os_helper.TESTFN, "w", encoding="utf-8", buffering=1) as f: + def run(n): + text = "Thread%03d\n" % n + event.wait() + f.write(text) + threads = [threading.Thread(target=run, args=(x,)) + for x in range(20)] + with threading_helper.start_threads(threads, event.set): + time.sleep(0.02) + with self.open(os_helper.TESTFN, encoding="utf-8") as f: + content = f.read() + for n in range(20): + self.assertEqual(content.count("Thread%03d\n" % n), 1) + + def test_flush_error_on_close(self): + # Test that text file is closed despite failed flush + # and that flush() is called before file closed. + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + closed = [] + def bad_flush(): + closed[:] = [txt.closed, txt.buffer.closed] + raise OSError() + txt.flush = bad_flush + self.assertRaises(OSError, txt.close) # exception not swallowed + self.assertTrue(txt.closed) + self.assertTrue(txt.buffer.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) + txt.flush = lambda: None # break reference loop + + def test_close_error_on_close(self): + buffer = self.BytesIO(self.testdata) + def bad_flush(): + raise OSError('flush') + def bad_close(): + raise OSError('close') + buffer.close = bad_close + txt = self.TextIOWrapper(buffer, encoding="ascii") + txt.flush = bad_flush + with self.assertRaises(OSError) as err: # exception not swallowed + txt.close() + self.assertEqual(err.exception.args, ('close',)) + self.assertIsInstance(err.exception.__context__, OSError) + self.assertEqual(err.exception.__context__.args, ('flush',)) + self.assertFalse(txt.closed) + + # Silence destructor error + buffer.close = lambda: None + txt.flush = lambda: None + + def test_nonnormalized_close_error_on_close(self): + # Issue #21677 + buffer = self.BytesIO(self.testdata) + def bad_flush(): + raise non_existing_flush + def bad_close(): + raise non_existing_close + buffer.close = bad_close + txt = self.TextIOWrapper(buffer, encoding="ascii") + txt.flush = bad_flush + with self.assertRaises(NameError) as err: # exception not swallowed + txt.close() + self.assertIn('non_existing_close', str(err.exception)) + self.assertIsInstance(err.exception.__context__, NameError) + self.assertIn('non_existing_flush', str(err.exception.__context__)) + self.assertFalse(txt.closed) + + # Silence destructor error + buffer.close = lambda: None + txt.flush = lambda: None + + def test_multi_close(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + txt.close() + txt.close() + txt.close() + self.assertRaises(ValueError, txt.flush) + + def test_unseekable(self): + txt = self.TextIOWrapper(self.MockUnseekableIO(self.testdata), encoding="utf-8") + self.assertRaises(self.UnsupportedOperation, txt.tell) + self.assertRaises(self.UnsupportedOperation, txt.seek, 0) + + def test_readonly_attributes(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + buf = self.BytesIO(self.testdata) + with self.assertRaises(AttributeError): + txt.buffer = buf + + def test_rawio(self): + # Issue #12591: TextIOWrapper must work with raw I/O objects, so + # that subprocess.Popen() can have the required unbuffered + # semantics with universal_newlines=True. + raw = self.MockRawIO([b'abc', b'def', b'ghi\njkl\nopq\n']) + txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') + # Reads + self.assertEqual(txt.read(4), 'abcd') + self.assertEqual(txt.readline(), 'efghi\n') + self.assertEqual(list(txt), ['jkl\n', 'opq\n']) + + def test_rawio_write_through(self): + # Issue #12591: with write_through=True, writes don't need a flush + raw = self.MockRawIO([b'abc', b'def', b'ghi\njkl\nopq\n']) + txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n', + write_through=True) + txt.write('1') + txt.write('23\n4') + txt.write('5') + self.assertEqual(b''.join(raw._write_stack), b'123\n45') + + def test_bufio_write_through(self): + # Issue #21396: write_through=True doesn't force a flush() + # on the underlying binary buffered object. + flush_called, write_called = [], [] + class BufferedWriter(self.BufferedWriter): + def flush(self, *args, **kwargs): + flush_called.append(True) + return super().flush(*args, **kwargs) + def write(self, *args, **kwargs): + write_called.append(True) + return super().write(*args, **kwargs) + + rawio = self.BytesIO() + data = b"a" + bufio = BufferedWriter(rawio, len(data)*2) + textio = self.TextIOWrapper(bufio, encoding='ascii', + write_through=True) + # write to the buffered io but don't overflow the buffer + text = data.decode('ascii') + textio.write(text) + + # buffer.flush is not called with write_through=True + self.assertFalse(flush_called) + # buffer.write *is* called with write_through=True + self.assertTrue(write_called) + self.assertEqual(rawio.getvalue(), b"") # no flush + + write_called = [] # reset + textio.write(text * 10) # total content is larger than bufio buffer + self.assertTrue(write_called) + self.assertEqual(rawio.getvalue(), data * 11) # all flushed + + def test_reconfigure_write_through(self): + raw = self.MockRawIO([]) + t = self.TextIOWrapper(raw, encoding='ascii', newline='\n') + t.write('1') + t.reconfigure(write_through=True) # implied flush + self.assertEqual(t.write_through, True) + self.assertEqual(b''.join(raw._write_stack), b'1') + t.write('23') + self.assertEqual(b''.join(raw._write_stack), b'123') + t.reconfigure(write_through=False) + self.assertEqual(t.write_through, False) + t.write('45') + t.flush() + self.assertEqual(b''.join(raw._write_stack), b'12345') + # Keeping default value + t.reconfigure() + t.reconfigure(write_through=None) + self.assertEqual(t.write_through, False) + t.reconfigure(write_through=True) + t.reconfigure() + t.reconfigure(write_through=None) + self.assertEqual(t.write_through, True) + + def test_read_nonbytes(self): + # Issue #17106 + # Crash when underlying read() returns non-bytes + t = self.TextIOWrapper(self.StringIO('a'), encoding="utf-8") + self.assertRaises(TypeError, t.read, 1) + t = self.TextIOWrapper(self.StringIO('a'), encoding="utf-8") + self.assertRaises(TypeError, t.readline) + t = self.TextIOWrapper(self.StringIO('a'), encoding="utf-8") + self.assertRaises(TypeError, t.read) + + def test_illegal_encoder(self): + # Issue 31271: Calling write() while the return value of encoder's + # encode() is invalid shouldn't cause an assertion failure. + rot13 = codecs.lookup("rot13") + with support.swap_attr(rot13, '_is_text_encoding', True): + t = self.TextIOWrapper(self.BytesIO(b'foo'), encoding="rot13") + self.assertRaises(TypeError, t.write, 'bar') + + def test_illegal_decoder(self): + # Issue #17106 + # Bypass the early encoding check added in issue 20404 + def _make_illegal_wrapper(): + quopri = codecs.lookup("quopri") + quopri._is_text_encoding = True + try: + t = self.TextIOWrapper(self.BytesIO(b'aaaaaa'), + newline='\n', encoding="quopri") + finally: + quopri._is_text_encoding = False + return t + # Crash when decoder returns non-string + t = _make_illegal_wrapper() + self.assertRaises(TypeError, t.read, 1) + t = _make_illegal_wrapper() + self.assertRaises(TypeError, t.readline) + t = _make_illegal_wrapper() + self.assertRaises(TypeError, t.read) + + # Issue 31243: calling read() while the return value of decoder's + # getstate() is invalid should neither crash the interpreter nor + # raise a SystemError. + def _make_very_illegal_wrapper(getstate_ret_val): + class BadDecoder: + def getstate(self): + return getstate_ret_val + def _get_bad_decoder(dummy): + return BadDecoder() + quopri = codecs.lookup("quopri") + with support.swap_attr(quopri, 'incrementaldecoder', + _get_bad_decoder): + return _make_illegal_wrapper() + t = _make_very_illegal_wrapper(42) + self.assertRaises(TypeError, t.read, 42) + t = _make_very_illegal_wrapper(()) + self.assertRaises(TypeError, t.read, 42) + t = _make_very_illegal_wrapper((1, 2)) + self.assertRaises(TypeError, t.read, 42) + + def _check_create_at_shutdown(self, **kwargs): + # Issue #20037: creating a TextIOWrapper at shutdown + # shouldn't crash the interpreter. + iomod = self.io.__name__ + code = """if 1: + import codecs + import {iomod} as io + + # Avoid looking up codecs at shutdown + codecs.lookup('utf-8') + + class C: + def __del__(self): + io.TextIOWrapper(io.BytesIO(), **{kwargs}) + print("ok") + c = C() + """.format(iomod=iomod, kwargs=kwargs) + return assert_python_ok("-c", code) + + def test_create_at_shutdown_without_encoding(self): + rc, out, err = self._check_create_at_shutdown() + if err: + # Can error out with a RuntimeError if the module state + # isn't found. + self.assertIn(self.shutdown_error, err.decode()) + else: + self.assertEqual("ok", out.decode().strip()) + + def test_create_at_shutdown_with_encoding(self): + rc, out, err = self._check_create_at_shutdown(encoding='utf-8', + errors='strict') + self.assertFalse(err) + self.assertEqual("ok", out.decode().strip()) + + def test_read_byteslike(self): + r = MemviewBytesIO(b'Just some random string\n') + t = self.TextIOWrapper(r, 'utf-8') + + # TextIOwrapper will not read the full string, because + # we truncate it to a multiple of the native int size + # so that we can construct a more complex memoryview. + bytes_val = _to_memoryview(r.getvalue()).tobytes() + + self.assertEqual(t.read(200), bytes_val.decode('utf-8')) + + def test_issue22849(self): + class F(object): + def readable(self): return True + def writable(self): return True + def seekable(self): return True + + for i in range(10): + try: + self.TextIOWrapper(F(), encoding='utf-8') + except Exception: + pass + + F.tell = lambda x: 0 + t = self.TextIOWrapper(F(), encoding='utf-8') + + def test_reconfigure_locale(self): + wrapper = self.TextIOWrapper(self.BytesIO(b"test")) + wrapper.reconfigure(encoding="locale") + + def test_reconfigure_encoding_read(self): + # latin1 -> utf8 + # (latin1 can decode utf-8 encoded string) + data = 'abc\xe9\n'.encode('latin1') + 'd\xe9f\n'.encode('utf8') + raw = self.BytesIO(data) + txt = self.TextIOWrapper(raw, encoding='latin1', newline='\n') + self.assertEqual(txt.readline(), 'abc\xe9\n') + with self.assertRaises(self.UnsupportedOperation): + txt.reconfigure(encoding='utf-8') + with self.assertRaises(self.UnsupportedOperation): + txt.reconfigure(newline=None) + + def test_reconfigure_write_fromascii(self): + # ascii has a specific encodefunc in the C implementation, + # but utf-8-sig has not. Make sure that we get rid of the + # cached encodefunc when we switch encoders. + raw = self.BytesIO() + txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') + txt.write('foo\n') + txt.reconfigure(encoding='utf-8-sig') + txt.write('\xe9\n') + txt.flush() + self.assertEqual(raw.getvalue(), b'foo\n\xc3\xa9\n') + + def test_reconfigure_write(self): + # latin -> utf8 + raw = self.BytesIO() + txt = self.TextIOWrapper(raw, encoding='latin1', newline='\n') + txt.write('abc\xe9\n') + txt.reconfigure(encoding='utf-8') + self.assertEqual(raw.getvalue(), b'abc\xe9\n') + txt.write('d\xe9f\n') + txt.flush() + self.assertEqual(raw.getvalue(), b'abc\xe9\nd\xc3\xa9f\n') + + # ascii -> utf-8-sig: ensure that no BOM is written in the middle of + # the file + raw = self.BytesIO() + txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') + txt.write('abc\n') + txt.reconfigure(encoding='utf-8-sig') + txt.write('d\xe9f\n') + txt.flush() + self.assertEqual(raw.getvalue(), b'abc\nd\xc3\xa9f\n') + + def test_reconfigure_write_non_seekable(self): + raw = self.BytesIO() + raw.seekable = lambda: False + raw.seek = None + txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') + txt.write('abc\n') + txt.reconfigure(encoding='utf-8-sig') + txt.write('d\xe9f\n') + txt.flush() + + # If the raw stream is not seekable, there'll be a BOM + self.assertEqual(raw.getvalue(), b'abc\n\xef\xbb\xbfd\xc3\xa9f\n') + + def test_reconfigure_defaults(self): + txt = self.TextIOWrapper(self.BytesIO(), 'ascii', 'replace', '\n') + txt.reconfigure(encoding=None) + self.assertEqual(txt.encoding, 'ascii') + self.assertEqual(txt.errors, 'replace') + txt.write('LF\n') + + txt.reconfigure(newline='\r\n') + self.assertEqual(txt.encoding, 'ascii') + self.assertEqual(txt.errors, 'replace') + + txt.reconfigure(errors='ignore') + self.assertEqual(txt.encoding, 'ascii') + self.assertEqual(txt.errors, 'ignore') + txt.write('CRLF\n') + + txt.reconfigure(encoding='utf-8', newline=None) + self.assertEqual(txt.errors, 'strict') + txt.seek(0) + self.assertEqual(txt.read(), 'LF\nCRLF\n') + + self.assertEqual(txt.detach().getvalue(), b'LF\nCRLF\r\n') + + def test_reconfigure_errors(self): + txt = self.TextIOWrapper(self.BytesIO(), 'ascii', 'replace', '\r') + with self.assertRaises(TypeError): # there was a crash + txt.reconfigure(encoding=42) + if self.is_C: + with self.assertRaises(UnicodeEncodeError): + txt.reconfigure(encoding='\udcfe') + with self.assertRaises(LookupError): + txt.reconfigure(encoding='locale\0') + # TODO: txt.reconfigure(encoding='utf-8\0') + # TODO: txt.reconfigure(encoding='nonexisting') + with self.assertRaises(TypeError): + txt.reconfigure(errors=42) + if self.is_C: + with self.assertRaises(UnicodeEncodeError): + txt.reconfigure(errors='\udcfe') + # TODO: txt.reconfigure(errors='ignore\0') + # TODO: txt.reconfigure(errors='nonexisting') + with self.assertRaises(TypeError): + txt.reconfigure(newline=42) + with self.assertRaises(ValueError): + txt.reconfigure(newline='\udcfe') + with self.assertRaises(ValueError): + txt.reconfigure(newline='xyz') + if not self.is_C: + # TODO: Should fail in C too. + with self.assertRaises(ValueError): + txt.reconfigure(newline='\n\0') + if self.is_C: + # TODO: Use __bool__(), not __index__(). + with self.assertRaises(ZeroDivisionError): + txt.reconfigure(line_buffering=BadIndex()) + with self.assertRaises(OverflowError): + txt.reconfigure(line_buffering=2**1000) + with self.assertRaises(ZeroDivisionError): + txt.reconfigure(write_through=BadIndex()) + with self.assertRaises(OverflowError): + txt.reconfigure(write_through=2**1000) + with self.assertRaises(ZeroDivisionError): # there was a crash + txt.reconfigure(line_buffering=BadIndex(), + write_through=BadIndex()) + self.assertEqual(txt.encoding, 'ascii') + self.assertEqual(txt.errors, 'replace') + self.assertIs(txt.line_buffering, False) + self.assertIs(txt.write_through, False) + + txt.reconfigure(encoding='latin1', errors='ignore', newline='\r\n', + line_buffering=True, write_through=True) + self.assertEqual(txt.encoding, 'latin1') + self.assertEqual(txt.errors, 'ignore') + self.assertIs(txt.line_buffering, True) + self.assertIs(txt.write_through, True) + + def test_reconfigure_newline(self): + raw = self.BytesIO(b'CR\rEOF') + txt = self.TextIOWrapper(raw, 'ascii', newline='\n') + txt.reconfigure(newline=None) + self.assertEqual(txt.readline(), 'CR\n') + raw = self.BytesIO(b'CR\rEOF') + txt = self.TextIOWrapper(raw, 'ascii', newline='\n') + txt.reconfigure(newline='') + self.assertEqual(txt.readline(), 'CR\r') + raw = self.BytesIO(b'CR\rLF\nEOF') + txt = self.TextIOWrapper(raw, 'ascii', newline='\r') + txt.reconfigure(newline='\n') + self.assertEqual(txt.readline(), 'CR\rLF\n') + raw = self.BytesIO(b'LF\nCR\rEOF') + txt = self.TextIOWrapper(raw, 'ascii', newline='\n') + txt.reconfigure(newline='\r') + self.assertEqual(txt.readline(), 'LF\nCR\r') + raw = self.BytesIO(b'CR\rCRLF\r\nEOF') + txt = self.TextIOWrapper(raw, 'ascii', newline='\r') + txt.reconfigure(newline='\r\n') + self.assertEqual(txt.readline(), 'CR\rCRLF\r\n') + + txt = self.TextIOWrapper(self.BytesIO(), 'ascii', newline='\r') + txt.reconfigure(newline=None) + txt.write('linesep\n') + txt.reconfigure(newline='') + txt.write('LF\n') + txt.reconfigure(newline='\n') + txt.write('LF\n') + txt.reconfigure(newline='\r') + txt.write('CR\n') + txt.reconfigure(newline='\r\n') + txt.write('CRLF\n') + expected = 'linesep' + os.linesep + 'LF\nLF\nCR\rCRLF\r\n' + self.assertEqual(txt.detach().getvalue().decode('ascii'), expected) + + def test_issue25862(self): + # Assertion failures occurred in tell() after read() and write(). + t = self.TextIOWrapper(self.BytesIO(b'test'), encoding='ascii') + t.read(1) + t.read() + t.tell() + t = self.TextIOWrapper(self.BytesIO(b'test'), encoding='ascii') + t.read(1) + t.write('x') + t.tell() + + def test_issue35928(self): + p = self.BufferedRWPair(self.BytesIO(b'foo\nbar\n'), self.BytesIO()) + f = self.TextIOWrapper(p) + res = f.readline() + self.assertEqual(res, 'foo\n') + f.write(res) + self.assertEqual(res + f.readline(), 'foo\nbar\n') + + def test_pickling_subclass(self): + global MyTextIO + class MyTextIO(self.TextIOWrapper): + def __init__(self, raw, tag): + super().__init__(raw) + self.tag = tag + def __getstate__(self): + return self.tag, self.buffer.getvalue() + def __setstate__(slf, state): + tag, value = state + slf.__init__(self.BytesIO(value), tag) + + raw = self.BytesIO(b'data') + txt = MyTextIO(raw, 'ham') + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + pickled = pickle.dumps(txt, proto) + newtxt = pickle.loads(pickled) + self.assertEqual(newtxt.buffer.getvalue(), b'data') + self.assertEqual(newtxt.tag, 'ham') + del MyTextIO + + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_read_non_blocking(self): + import os + r, w = os.pipe() + try: + os.set_blocking(r, False) + with self.io.open(r, 'rt') as textfile: + r = None + # Nothing has been written so a non-blocking read raises a BlockingIOError exception. + with self.assertRaises(BlockingIOError): + textfile.read() + finally: + if r is not None: + os.close(r) + os.close(w) + + +class MemviewBytesIO(io.BytesIO): + '''A BytesIO object whose read method returns memoryviews + rather than bytes''' + + def read1(self, len_): + return _to_memoryview(super().read1(len_)) + + def read(self, len_): + return _to_memoryview(super().read(len_)) + +def _to_memoryview(buf): + '''Convert bytes-object *buf* to a non-trivial memoryview''' + + arr = array.array('i') + idx = len(buf) - len(buf) % arr.itemsize + arr.frombytes(buf[:idx]) + return memoryview(arr) + + +class CTextIOWrapperTest(TextIOWrapperTest, CTestCase): + shutdown_error = "LookupError: unknown encoding: ascii" + + def test_initialization(self): + r = self.BytesIO(b"\xc3\xa9\n\n") + b = self.BufferedReader(r, 1000) + t = self.TextIOWrapper(b, encoding="utf-8") + self.assertRaises(ValueError, t.__init__, b, encoding="utf-8", newline='xyzzy') + self.assertRaises(ValueError, t.read) + + t = self.TextIOWrapper.__new__(self.TextIOWrapper) + self.assertRaises(Exception, repr, t) + + def test_garbage_collection(self): + # C TextIOWrapper objects are collected, and collecting them flushes + # all data to disk. + # The Python version has __del__, so it ends in gc.garbage instead. + with warnings.catch_warnings(): + warnings.simplefilter("ignore", ResourceWarning) + rawio = self.FileIO(os_helper.TESTFN, "wb") + b = self.BufferedWriter(rawio) + t = self.TextIOWrapper(b, encoding="ascii") + t.write("456def") + t.x = t + wr = weakref.ref(t) + del t + support.gc_collect() + self.assertIsNone(wr(), wr) + with self.open(os_helper.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"456def") + + def test_rwpair_cleared_before_textio(self): + # Issue 13070: TextIOWrapper's finalization would crash when called + # after the reference to the underlying BufferedRWPair's writer got + # cleared by the GC. + for i in range(1000): + b1 = self.BufferedRWPair(self.MockRawIO(), self.MockRawIO()) + t1 = self.TextIOWrapper(b1, encoding="ascii") + b2 = self.BufferedRWPair(self.MockRawIO(), self.MockRawIO()) + t2 = self.TextIOWrapper(b2, encoding="ascii") + # circular references + t1.buddy = t2 + t2.buddy = t1 + support.gc_collect() + + def test_del__CHUNK_SIZE_SystemError(self): + t = self.TextIOWrapper(self.BytesIO(), encoding='ascii') + with self.assertRaises(AttributeError): + del t._CHUNK_SIZE + + def test_internal_buffer_size(self): + # bpo-43260: TextIOWrapper's internal buffer should not store + # data larger than chunk size. + chunk_size = 8192 # default chunk size, updated later + + class MockIO(self.MockRawIO): + def write(self, data): + if len(data) > chunk_size: + raise RuntimeError + return super().write(data) + + buf = MockIO() + t = self.TextIOWrapper(buf, encoding="ascii") + chunk_size = t._CHUNK_SIZE + t.write("abc") + t.write("def") + # default chunk size is 8192 bytes so t don't write data to buf. + self.assertEqual([], buf._write_stack) + + with self.assertRaises(RuntimeError): + t.write("x"*(chunk_size+1)) + + self.assertEqual([b"abcdef"], buf._write_stack) + t.write("ghi") + t.write("x"*chunk_size) + self.assertEqual([b"abcdef", b"ghi", b"x"*chunk_size], buf._write_stack) + + def test_issue119506(self): + chunk_size = 8192 + + class MockIO(self.MockRawIO): + written = False + def write(self, data): + if not self.written: + self.written = True + t.write("middle") + return super().write(data) + + buf = MockIO() + t = self.TextIOWrapper(buf) + t.write("abc") + t.write("def") + # writing data which size >= chunk_size cause flushing buffer before write. + t.write("g" * chunk_size) + t.flush() + + self.assertEqual([b"abcdef", b"middle", b"g"*chunk_size], + buf._write_stack) + + def test_issue142594(self): + wrapper = None + detached = False + class ReentrantRawIO(self.RawIOBase): + @property + def closed(self): + nonlocal detached + if wrapper is not None and not detached: + detached = True + wrapper.detach() + return False + + raw = ReentrantRawIO() + wrapper = self.TextIOWrapper(raw) + wrapper.close() # should not crash + + +class PyTextIOWrapperTest(TextIOWrapperTest, PyTestCase): + shutdown_error = "LookupError: unknown encoding: ascii" + + +class IncrementalNewlineDecoderTest: + + def check_newline_decoding_utf8(self, decoder): + # UTF-8 specific tests for a newline decoder + def _check_decode(b, s, **kwargs): + # We exercise getstate() / setstate() as well as decode() + state = decoder.getstate() + self.assertEqual(decoder.decode(b, **kwargs), s) + decoder.setstate(state) + self.assertEqual(decoder.decode(b, **kwargs), s) + + _check_decode(b'\xe8\xa2\x88', "\u8888") + + _check_decode(b'\xe8', "") + _check_decode(b'\xa2', "") + _check_decode(b'\x88', "\u8888") + + _check_decode(b'\xe8', "") + _check_decode(b'\xa2', "") + _check_decode(b'\x88', "\u8888") + + _check_decode(b'\xe8', "") + self.assertRaises(UnicodeDecodeError, decoder.decode, b'', final=True) + + decoder.reset() + _check_decode(b'\n', "\n") + _check_decode(b'\r', "") + _check_decode(b'', "\n", final=True) + _check_decode(b'\r', "\n", final=True) + + _check_decode(b'\r', "") + _check_decode(b'a', "\na") + + _check_decode(b'\r\r\n', "\n\n") + _check_decode(b'\r', "") + _check_decode(b'\r', "\n") + _check_decode(b'\na', "\na") + + _check_decode(b'\xe8\xa2\x88\r\n', "\u8888\n") + _check_decode(b'\xe8\xa2\x88', "\u8888") + _check_decode(b'\n', "\n") + _check_decode(b'\xe8\xa2\x88\r', "\u8888") + _check_decode(b'\n', "\n") + + def check_newline_decoding(self, decoder, encoding): + result = [] + if encoding is not None: + encoder = codecs.getincrementalencoder(encoding)() + def _decode_bytewise(s): + # Decode one byte at a time + for b in encoder.encode(s): + result.append(decoder.decode(bytes([b]))) + else: + encoder = None + def _decode_bytewise(s): + # Decode one char at a time + for c in s: + result.append(decoder.decode(c)) + self.assertEqual(decoder.newlines, None) + _decode_bytewise("abc\n\r") + self.assertEqual(decoder.newlines, '\n') + _decode_bytewise("\nabc") + self.assertEqual(decoder.newlines, ('\n', '\r\n')) + _decode_bytewise("abc\r") + self.assertEqual(decoder.newlines, ('\n', '\r\n')) + _decode_bytewise("abc") + self.assertEqual(decoder.newlines, ('\r', '\n', '\r\n')) + _decode_bytewise("abc\r") + self.assertEqual("".join(result), "abc\n\nabcabc\nabcabc") + decoder.reset() + input = "abc" + if encoder is not None: + encoder.reset() + input = encoder.encode(input) + self.assertEqual(decoder.decode(input), "abc") + self.assertEqual(decoder.newlines, None) + + def test_newline_decoder(self): + encodings = ( + # None meaning the IncrementalNewlineDecoder takes unicode input + # rather than bytes input + None, 'utf-8', 'latin-1', + 'utf-16', 'utf-16-le', 'utf-16-be', + 'utf-32', 'utf-32-le', 'utf-32-be', + ) + for enc in encodings: + decoder = enc and codecs.getincrementaldecoder(enc)() + decoder = self.IncrementalNewlineDecoder(decoder, translate=True) + self.check_newline_decoding(decoder, enc) + decoder = codecs.getincrementaldecoder("utf-8")() + decoder = self.IncrementalNewlineDecoder(decoder, translate=True) + self.check_newline_decoding_utf8(decoder) + self.assertRaises(TypeError, decoder.setstate, 42) + + def test_newline_bytes(self): + # Issue 5433: Excessive optimization in IncrementalNewlineDecoder + def _check(dec): + self.assertEqual(dec.newlines, None) + self.assertEqual(dec.decode("\u0D00"), "\u0D00") + self.assertEqual(dec.newlines, None) + self.assertEqual(dec.decode("\u0A00"), "\u0A00") + self.assertEqual(dec.newlines, None) + dec = self.IncrementalNewlineDecoder(None, translate=False) + _check(dec) + dec = self.IncrementalNewlineDecoder(None, translate=True) + _check(dec) + + def test_translate(self): + # issue 35062 + for translate in (-2, -1, 1, 2): + decoder = codecs.getincrementaldecoder("utf-8")() + decoder = self.IncrementalNewlineDecoder(decoder, translate) + self.check_newline_decoding_utf8(decoder) + decoder = codecs.getincrementaldecoder("utf-8")() + decoder = self.IncrementalNewlineDecoder(decoder, translate=0) + self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n") + +class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest, unittest.TestCase): + IncrementalNewlineDecoder = io.IncrementalNewlineDecoder + + @support.cpython_only + def test_uninitialized(self): + uninitialized = self.IncrementalNewlineDecoder.__new__( + self.IncrementalNewlineDecoder) + self.assertRaises(ValueError, uninitialized.decode, b'bar') + self.assertRaises(ValueError, uninitialized.getstate) + self.assertRaises(ValueError, uninitialized.setstate, (b'foo', 0)) + self.assertRaises(ValueError, uninitialized.reset) + + +class PyIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest, unittest.TestCase): + IncrementalNewlineDecoder = pyio.IncrementalNewlineDecoder diff --git a/Lib/test/test_univnewlines.py b/Lib/test/test_io/test_univnewlines.py similarity index 100% rename from Lib/test/test_univnewlines.py rename to Lib/test/test_io/test_univnewlines.py diff --git a/Lib/test/test_io/utils.py b/Lib/test/test_io/utils.py new file mode 100644 index 00000000000..3b1faec2140 --- /dev/null +++ b/Lib/test/test_io/utils.py @@ -0,0 +1,318 @@ +import array +import threading +import time +import unittest + +import io # C implementation of io +import _pyio as pyio # Python implementation of io + + +try: + import ctypes +except ImportError: + def byteslike(*pos, **kw): + return array.array("b", bytes(*pos, **kw)) +else: + class EmptyStruct(ctypes.Structure): + pass + + def byteslike(*pos, **kw): + """Create a bytes-like object having no string or sequence methods""" + data = bytes(*pos, **kw) + obj = EmptyStruct() + ctypes.resize(obj, len(data)) + memoryview(obj).cast("B")[:] = data + return obj + + +class MockRawIOWithoutRead: + """A RawIO implementation without read(), so as to exercise the default + RawIO.read() which calls readinto().""" + + def __init__(self, read_stack=()): + self._read_stack = list(read_stack) + self._write_stack = [] + self._reads = 0 + self._extraneous_reads = 0 + + def write(self, b): + self._write_stack.append(bytes(b)) + return len(b) + + def writable(self): + return True + + def fileno(self): + return 42 + + def readable(self): + return True + + def seekable(self): + return True + + def seek(self, pos, whence): + return 0 # wrong but we gotta return something + + def tell(self): + return 0 # same comment as above + + def readinto(self, buf): + self._reads += 1 + max_len = len(buf) + try: + data = self._read_stack[0] + except IndexError: + self._extraneous_reads += 1 + return 0 + if data is None: + del self._read_stack[0] + return None + n = len(data) + if len(data) <= max_len: + del self._read_stack[0] + buf[:n] = data + return n + else: + buf[:] = data[:max_len] + self._read_stack[0] = data[max_len:] + return max_len + + def truncate(self, pos=None): + return pos + +class CMockRawIOWithoutRead(MockRawIOWithoutRead, io.RawIOBase): + pass + +class PyMockRawIOWithoutRead(MockRawIOWithoutRead, pyio.RawIOBase): + pass + + +class MockRawIO(MockRawIOWithoutRead): + + def read(self, n=None): + self._reads += 1 + try: + return self._read_stack.pop(0) + except: + self._extraneous_reads += 1 + return b"" + +class CMockRawIO(MockRawIO, io.RawIOBase): + pass + +class PyMockRawIO(MockRawIO, pyio.RawIOBase): + pass + + +class MisbehavedRawIO(MockRawIO): + def write(self, b): + return super().write(b) * 2 + + def read(self, n=None): + return super().read(n) * 2 + + def seek(self, pos, whence): + return -123 + + def tell(self): + return -456 + + def readinto(self, buf): + super().readinto(buf) + return len(buf) * 5 + +class CMisbehavedRawIO(MisbehavedRawIO, io.RawIOBase): + pass + +class PyMisbehavedRawIO(MisbehavedRawIO, pyio.RawIOBase): + pass + + +class SlowFlushRawIO(MockRawIO): + def __init__(self): + super().__init__() + self.in_flush = threading.Event() + + def flush(self): + self.in_flush.set() + time.sleep(0.25) + +class CSlowFlushRawIO(SlowFlushRawIO, io.RawIOBase): + pass + +class PySlowFlushRawIO(SlowFlushRawIO, pyio.RawIOBase): + pass + + +class CloseFailureIO(MockRawIO): + closed = 0 + + def close(self): + if not self.closed: + self.closed = 1 + raise OSError + +class CCloseFailureIO(CloseFailureIO, io.RawIOBase): + pass + +class PyCloseFailureIO(CloseFailureIO, pyio.RawIOBase): + pass + + +class MockFileIO: + + def __init__(self, data): + self.read_history = [] + super().__init__(data) + + def read(self, n=None): + res = super().read(n) + self.read_history.append(None if res is None else len(res)) + return res + + def readinto(self, b): + res = super().readinto(b) + self.read_history.append(res) + return res + +class CMockFileIO(MockFileIO, io.BytesIO): + pass + +class PyMockFileIO(MockFileIO, pyio.BytesIO): + pass + + +class MockUnseekableIO: + def seekable(self): + return False + + def seek(self, *args): + raise self.UnsupportedOperation("not seekable") + + def tell(self, *args): + raise self.UnsupportedOperation("not seekable") + + def truncate(self, *args): + raise self.UnsupportedOperation("not seekable") + +class CMockUnseekableIO(MockUnseekableIO, io.BytesIO): + UnsupportedOperation = io.UnsupportedOperation + +class PyMockUnseekableIO(MockUnseekableIO, pyio.BytesIO): + UnsupportedOperation = pyio.UnsupportedOperation + + +class MockCharPseudoDevFileIO(MockFileIO): + # GH-95782 + # ftruncate() does not work on these special files (and CPython then raises + # appropriate exceptions), so truncate() does not have to be accounted for + # here. + def __init__(self, data): + super().__init__(data) + + def seek(self, *args): + return 0 + + def tell(self, *args): + return 0 + +class CMockCharPseudoDevFileIO(MockCharPseudoDevFileIO, io.BytesIO): + pass + +class PyMockCharPseudoDevFileIO(MockCharPseudoDevFileIO, pyio.BytesIO): + pass + + +class MockNonBlockWriterIO: + + def __init__(self): + self._write_stack = [] + self._blocker_char = None + + def pop_written(self): + s = b"".join(self._write_stack) + self._write_stack[:] = [] + return s + + def block_on(self, char): + """Block when a given char is encountered.""" + self._blocker_char = char + + def readable(self): + return True + + def seekable(self): + return True + + def seek(self, pos, whence=0): + # naive implementation, enough for tests + return 0 + + def writable(self): + return True + + def write(self, b): + b = bytes(b) + n = -1 + if self._blocker_char: + try: + n = b.index(self._blocker_char) + except ValueError: + pass + else: + if n > 0: + # write data up to the first blocker + self._write_stack.append(b[:n]) + return n + else: + # cancel blocker and indicate would block + self._blocker_char = None + return None + self._write_stack.append(b) + return len(b) + +class CMockNonBlockWriterIO(MockNonBlockWriterIO, io.RawIOBase): + BlockingIOError = io.BlockingIOError + +class PyMockNonBlockWriterIO(MockNonBlockWriterIO, pyio.RawIOBase): + BlockingIOError = pyio.BlockingIOError + + +# Build classes which point to all the right mocks per io implementation +class CTestCase(unittest.TestCase): + io = io + is_C = True + + MockRawIO = CMockRawIO + MisbehavedRawIO = CMisbehavedRawIO + MockFileIO = CMockFileIO + CloseFailureIO = CCloseFailureIO + MockNonBlockWriterIO = CMockNonBlockWriterIO + MockUnseekableIO = CMockUnseekableIO + MockRawIOWithoutRead = CMockRawIOWithoutRead + SlowFlushRawIO = CSlowFlushRawIO + MockCharPseudoDevFileIO = CMockCharPseudoDevFileIO + + # Use the class as a proxy to the io module members. + def __getattr__(self, name): + return getattr(io, name) + + +class PyTestCase(unittest.TestCase): + io = pyio + is_C = False + + MockRawIO = PyMockRawIO + MisbehavedRawIO = PyMisbehavedRawIO + MockFileIO = PyMockFileIO + CloseFailureIO = PyCloseFailureIO + MockNonBlockWriterIO = PyMockNonBlockWriterIO + MockUnseekableIO = PyMockUnseekableIO + MockRawIOWithoutRead = PyMockRawIOWithoutRead + SlowFlushRawIO = PySlowFlushRawIO + MockCharPseudoDevFileIO = PyMockCharPseudoDevFileIO + + # Use the class as a proxy to the _pyio module members. + def __getattr__(self, name): + return getattr(pyio, name) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 62929f9dd68..3f017b97dc2 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -12,6 +12,7 @@ import operator import pickle import ipaddress import weakref +from collections.abc import Iterator from test.support import LARGEST, SMALLEST @@ -1472,18 +1473,27 @@ class IpaddrUnitTest(unittest.TestCase): self.ipv6_scoped_network.supernet(new_prefix=62)) def testHosts(self): + hosts = self.ipv4_network.hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(ipaddress.IPv4Address('1.2.3.1'), next(hosts)) hosts = list(self.ipv4_network.hosts()) self.assertEqual(254, len(hosts)) self.assertEqual(ipaddress.IPv4Address('1.2.3.1'), hosts[0]) self.assertEqual(ipaddress.IPv4Address('1.2.3.254'), hosts[-1]) ipv6_network = ipaddress.IPv6Network('2001:658:22a:cafe::/120') + hosts = ipv6_network.hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(ipaddress.IPv6Address('2001:658:22a:cafe::1'), next(hosts)) hosts = list(ipv6_network.hosts()) self.assertEqual(255, len(hosts)) self.assertEqual(ipaddress.IPv6Address('2001:658:22a:cafe::1'), hosts[0]) self.assertEqual(ipaddress.IPv6Address('2001:658:22a:cafe::ff'), hosts[-1]) ipv6_scoped_network = ipaddress.IPv6Network('2001:658:22a:cafe::%scope/120') + hosts = ipv6_scoped_network.hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual((ipaddress.IPv6Address('2001:658:22a:cafe::1')), next(hosts)) hosts = list(ipv6_scoped_network.hosts()) self.assertEqual(255, len(hosts)) self.assertEqual(ipaddress.IPv6Address('2001:658:22a:cafe::1'), hosts[0]) @@ -1494,6 +1504,12 @@ class IpaddrUnitTest(unittest.TestCase): ipaddress.IPv4Address('2.0.0.1')] str_args = '2.0.0.0/31' tpl_args = ('2.0.0.0', 31) + hosts = ipaddress.ip_network(str_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) + hosts = ipaddress.ip_network(tpl_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts())) self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts())) self.assertEqual(list(ipaddress.ip_network(str_args).hosts()), @@ -1503,6 +1519,12 @@ class IpaddrUnitTest(unittest.TestCase): addrs = [ipaddress.IPv4Address('1.2.3.4')] str_args = '1.2.3.4/32' tpl_args = ('1.2.3.4', 32) + hosts = ipaddress.ip_network(str_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) + hosts = ipaddress.ip_network(tpl_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts())) self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts())) self.assertEqual(list(ipaddress.ip_network(str_args).hosts()), @@ -1512,6 +1534,12 @@ class IpaddrUnitTest(unittest.TestCase): ipaddress.IPv6Address('2001:658:22a:cafe::1')] str_args = '2001:658:22a:cafe::/127' tpl_args = ('2001:658:22a:cafe::', 127) + hosts = ipaddress.ip_network(str_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) + hosts = ipaddress.ip_network(tpl_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts())) self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts())) self.assertEqual(list(ipaddress.ip_network(str_args).hosts()), @@ -1520,6 +1548,12 @@ class IpaddrUnitTest(unittest.TestCase): addrs = [ipaddress.IPv6Address('2001:658:22a:cafe::1'), ] str_args = '2001:658:22a:cafe::1/128' tpl_args = ('2001:658:22a:cafe::1', 128) + hosts = ipaddress.ip_network(str_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) + hosts = ipaddress.ip_network(tpl_args).hosts() + self.assertIsInstance(hosts, Iterator) + self.assertEqual(next(hosts), addrs[0]) self.assertEqual(addrs, list(ipaddress.ip_network(str_args).hosts())) self.assertEqual(addrs, list(ipaddress.ip_network(tpl_args).hosts())) self.assertEqual(list(ipaddress.ip_network(str_args).hosts()), @@ -2821,5 +2855,15 @@ class IpaddrUnitTest(unittest.TestCase): ) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(ipaddress, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_json/__init__.py b/Lib/test/test_json/__init__.py index 74b64ed86a3..e58fbee41af 100644 --- a/Lib/test/test_json/__init__.py +++ b/Lib/test/test_json/__init__.py @@ -47,6 +47,16 @@ class TestCTest(CTest): '_json') +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(json, "__version__") + self.assertEqual(cm.filename, __file__) + + def load_tests(loader, _, pattern): suite = unittest.TestSuite() for mod in (json, json.encoder, json.decoder): diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py index 6a39b72a09d..c90d3e968e5 100644 --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -8,13 +8,12 @@ CASES = [ ('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ('controls', '"controls"'), ('\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'), + ('\x00\x1f\x7f', '"\\u0000\\u001f\\u007f"'), ('{"object with 1 member":["array with 1 element"]}', '"{\\"object with 1 member\\":[\\"array with 1 element\\"]}"'), (' s p a c e d ', '" s p a c e d "'), ('\U0001d120', '"\\ud834\\udd20"'), ('\u03b1\u03a9', '"\\u03b1\\u03a9"'), ("`1~!@#$%^&*()_+-={':[,]}|;.</>?", '"`1~!@#$%^&*()_+-={\':[,]}|;.</>?"'), - ('\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'), - ('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), ] class TestEncodeBasestringAscii: diff --git a/Lib/test/test_json/test_enum.py b/Lib/test/test_json/test_enum.py index 10f414898b8..196229897bd 100644 --- a/Lib/test/test_json/test_enum.py +++ b/Lib/test/test_json/test_enum.py @@ -26,7 +26,7 @@ INF = float('inf') NEG_INF = float('-inf') NAN = float('nan') -class WierdNum(float, Enum): +class WeirdNum(float, Enum): inf = INF neg_inf = NEG_INF nan = NAN @@ -40,7 +40,7 @@ class TestEnum: self.assertEqual(self.loads(self.dumps(enum)), enum) def test_weird_floats(self): - for enum, expected in zip(WierdNum, ('Infinity', '-Infinity', 'NaN')): + for enum, expected in zip(WeirdNum, ('Infinity', '-Infinity', 'NaN')): self.assertEqual(self.dumps(enum), expected) if not isnan(enum): self.assertEqual(float(self.dumps(enum)), enum) @@ -64,16 +64,16 @@ class TestEnum: str([E, PI, TAU])) self.assertEqual(self.loads(self.dumps(list(FloatNum))), list(FloatNum)) - self.assertEqual(self.dumps(list(WierdNum)), + self.assertEqual(self.dumps(list(WeirdNum)), '[Infinity, -Infinity, NaN]') - self.assertEqual(self.loads(self.dumps(list(WierdNum)))[:2], - list(WierdNum)[:2]) - self.assertTrue(isnan(self.loads(self.dumps(list(WierdNum)))[2])) + self.assertEqual(self.loads(self.dumps(list(WeirdNum)))[:2], + list(WeirdNum)[:2]) + self.assertTrue(isnan(self.loads(self.dumps(list(WeirdNum)))[2])) def test_dict_keys(self): s, b, h, r = BigNum e, p, t = FloatNum - i, j, n = WierdNum + i, j, n = WeirdNum d = { s:'tiny', b:'large', h:'larger', r:'largest', e:"Euler's number", p:'pi', t:'tau', @@ -100,9 +100,9 @@ class TestEnum: e=FloatNum.e, pi=FloatNum.pi, tau=FloatNum.tau, - i=WierdNum.inf, - j=WierdNum.neg_inf, - n=WierdNum.nan, + i=WeirdNum.inf, + j=WeirdNum.neg_inf, + n=WeirdNum.nan, ) nd = self.loads(self.dumps(d)) self.assertEqual(nd['tiny'], SMALL) diff --git a/Lib/test/test_json/test_recursion.py b/Lib/test/test_json/test_recursion.py index 5d7b56ff9ad..40a0baa53f0 100644 --- a/Lib/test/test_json/test_recursion.py +++ b/Lib/test/test_json/test_recursion.py @@ -71,7 +71,7 @@ class TestRecursion: @support.skip_emscripten_stack_overflow() @support.skip_wasi_stack_overflow() def test_highly_nested_objects_decoding(self): - very_deep = 200000 + very_deep = 500_000 # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with self.assertRaises(RecursionError): @@ -90,7 +90,7 @@ class TestRecursion: def test_highly_nested_objects_encoding(self): # See #12051 l, d = [], {} - for x in range(200_000): + for x in range(500_000): l, d = [l], {'k':d} with self.assertRaises(RecursionError): with support.infinite_recursion(5000): diff --git a/Lib/test/test_json/test_scanstring.py b/Lib/test/test_json/test_scanstring.py index cca556a3b95..9a6cdfe12d2 100644 --- a/Lib/test/test_json/test_scanstring.py +++ b/Lib/test/test_json/test_scanstring.py @@ -144,7 +144,7 @@ class TestScanstring: def test_overflow(self): with self.assertRaises(OverflowError): - self.json.decoder.scanstring(b"xxx", sys.maxsize+1) + self.json.decoder.scanstring("xxx", sys.maxsize+1) class TestPyScanstring(TestScanstring, PyTest): pass diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 30f9bb33316..7b5d217a215 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -13,6 +13,7 @@ from _colorize import get_theme @support.requires_subprocess() +@support.skip_if_pgo_task class TestMain(unittest.TestCase): data = """ @@ -319,6 +320,7 @@ class TestMain(unittest.TestCase): @support.requires_subprocess() +@support.skip_if_pgo_task class TestTool(TestMain): module = 'json.tool' diff --git a/Lib/test/test_json/test_unicode.py b/Lib/test/test_json/test_unicode.py index 68629cceeb9..1aa9546dc46 100644 --- a/Lib/test/test_json/test_unicode.py +++ b/Lib/test/test_json/test_unicode.py @@ -32,6 +32,29 @@ class TestUnicode: j = self.dumps(u + "\n", ensure_ascii=False) self.assertEqual(j, f'"{u}\\n"') + def test_ascii_non_printable_encode(self): + u = '\b\t\n\f\r\x00\x1f\x7f' + self.assertEqual(self.dumps(u), + '"\\b\\t\\n\\f\\r\\u0000\\u001f\\u007f"') + self.assertEqual(self.dumps(u, ensure_ascii=False), + '"\\b\\t\\n\\f\\r\\u0000\\u001f\x7f"') + + def test_ascii_non_printable_decode(self): + self.assertEqual(self.loads('"\\b\\t\\n\\f\\r"'), + '\b\t\n\f\r') + s = ''.join(map(chr, range(32))) + for c in s: + self.assertRaises(self.JSONDecodeError, self.loads, f'"{c}"') + self.assertEqual(self.loads(f'"{s}"', strict=False), s) + self.assertEqual(self.loads('"\x7f"'), '\x7f') + + def test_escaped_decode(self): + self.assertEqual(self.loads('"\\b\\t\\n\\f\\r"'), '\b\t\n\f\r') + self.assertEqual(self.loads('"\\"\\\\\\/"'), '"\\/') + for c in set(map(chr, range(0x100))) - set('"\\/bfnrt'): + self.assertRaises(self.JSONDecodeError, self.loads, f'"\\{c}"') + self.assertRaises(self.JSONDecodeError, self.loads, f'"\\{c}"', strict=False) + def test_big_unicode_encode(self): u = '\U0001d120' self.assertEqual(self.dumps(u), '"\\ud834\\udd20"') @@ -48,6 +71,18 @@ class TestUnicode: s = f'"\\u{i:04x}"' self.assertEqual(self.loads(s), u) + def test_single_surrogate_encode(self): + self.assertEqual(self.dumps('\uD83D'), '"\\ud83d"') + self.assertEqual(self.dumps('\uD83D', ensure_ascii=False), '"\ud83d"') + self.assertEqual(self.dumps('\uDC0D'), '"\\udc0d"') + self.assertEqual(self.dumps('\uDC0D', ensure_ascii=False), '"\udc0d"') + + def test_single_surrogate_decode(self): + self.assertEqual(self.loads('"\uD83D"'), '\ud83d') + self.assertEqual(self.loads('"\\uD83D"'), '\ud83d') + self.assertEqual(self.loads('"\udc0d"'), '\udc0d') + self.assertEqual(self.loads('"\\udc0d"'), '\udc0d') + def test_unicode_preservation(self): self.assertEqual(type(self.loads('""')), str) self.assertEqual(type(self.loads('"a"')), str) diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py index 02f65338428..fcd94edc611 100644 --- a/Lib/test/test_linecache.py +++ b/Lib/test/test_linecache.py @@ -259,22 +259,44 @@ class LineCacheTests(unittest.TestCase): def test_loader(self): filename = 'scheme://path' - for loader in (None, object(), NoSourceLoader()): + linecache.clearcache() + module_globals = {'__name__': 'a.b.c', '__loader__': None} + self.assertEqual(linecache.getlines(filename, module_globals), []) + + for loader in object(), NoSourceLoader(): linecache.clearcache() module_globals = {'__name__': 'a.b.c', '__loader__': loader} - self.assertEqual(linecache.getlines(filename, module_globals), []) + with self.assertWarns(DeprecationWarning) as w: + self.assertEqual(linecache.getlines(filename, module_globals), []) + self.assertEqual(str(w.warning), + 'Module globals is missing a __spec__.loader') linecache.clearcache() module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader()} - self.assertEqual(linecache.getlines(filename, module_globals), - ['source for a.b.c\n']) + with self.assertWarns(DeprecationWarning) as w: + self.assertEqual(linecache.getlines(filename, module_globals), + ['source for a.b.c\n']) + self.assertEqual(str(w.warning), + 'Module globals is missing a __spec__.loader') - for spec in (None, object(), ModuleSpec('', FakeLoader())): + for spec in None, object(): linecache.clearcache() module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(), '__spec__': spec} + with self.assertWarns(DeprecationWarning) as w: + self.assertEqual(linecache.getlines(filename, module_globals), + ['source for a.b.c\n']) + self.assertEqual(str(w.warning), + 'Module globals is missing a __spec__.loader') + + linecache.clearcache() + module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(), + '__spec__': ModuleSpec('', FakeLoader())} + with self.assertWarns(DeprecationWarning) as w: self.assertEqual(linecache.getlines(filename, module_globals), ['source for a.b.c\n']) + self.assertEqual(str(w.warning), + 'Module globals; __loader__ != __spec__.loader') linecache.clearcache() spec = ModuleSpec('x.y.z', FakeLoader()) diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 223f34fb696..642b54d3484 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -349,10 +349,12 @@ class ListTest(list_tests.CommonTest): # gh-132011: it used to crash, because # of `CALL_LIST_APPEND` specialization failure. code = textwrap.dedent(""" + import _testinternalcapi + l = [] def lappend(l, x, y): l.append((x, y)) - for x in range(3): + for x in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): lappend(l, None, None) try: lappend(list, None, None) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py index 01b1e754d04..d49f78c91da 100644 --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -351,8 +351,7 @@ class TestEnUSCollation(BaseLocalizedTest, TestCollation): enc = codecs.lookup(locale.getencoding() or 'ascii').name if enc not in ('utf-8', 'iso8859-1', 'cp1252'): raise unittest.SkipTest('encoding not suitable') - if enc != 'iso8859-1' and (sys.platform == 'darwin' or is_android or - sys.platform.startswith('freebsd')): + if enc != 'iso8859-1' and is_android: raise unittest.SkipTest('wcscoll/wcsxfrm have known bugs') BaseLocalizedTest.setUp(self) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 7a08f9ec9de..8815426fc99 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -5826,7 +5826,7 @@ class LoggerAdapterTest(unittest.TestCase): self.addCleanup(cleanup) self.addCleanup(logging.shutdown) - self.adapter = logging.LoggerAdapter(logger=self.logger, extra=None) + self.adapter = logging.LoggerAdapter(logger=self.logger) def test_exception(self): msg = 'testing exception: %r' @@ -5997,6 +5997,18 @@ class LoggerAdapterTest(unittest.TestCase): self.assertEqual(record.foo, '1') self.assertEqual(record.bar, '2') + self.adapter.critical('no extra') # should not fail + self.assertEqual(len(self.recording.records), 2) + record = self.recording.records[-1] + self.assertEqual(record.foo, '1') + self.assertNotHasAttr(record, 'bar') + + self.adapter.critical('none extra', extra=None) # should not fail + self.assertEqual(len(self.recording.records), 3) + record = self.recording.records[-1] + self.assertEqual(record.foo, '1') + self.assertNotHasAttr(record, 'bar') + def test_extra_merged_log_call_has_precedence(self): self.adapter = logging.LoggerAdapter(logger=self.logger, extra={'foo': '1'}, @@ -6008,6 +6020,25 @@ class LoggerAdapterTest(unittest.TestCase): self.assertHasAttr(record, 'foo') self.assertEqual(record.foo, '2') + def test_extra_merged_without_extra(self): + self.adapter = logging.LoggerAdapter(logger=self.logger, + merge_extra=True) + + self.adapter.critical('foo should be here', extra={'foo': '1'}) + self.assertEqual(len(self.recording.records), 1) + record = self.recording.records[-1] + self.assertEqual(record.foo, '1') + + self.adapter.critical('no extra') # should not fail + self.assertEqual(len(self.recording.records), 2) + record = self.recording.records[-1] + self.assertNotHasAttr(record, 'foo') + + self.adapter.critical('none extra', extra=None) # should not fail + self.assertEqual(len(self.recording.records), 3) + record = self.recording.records[-1] + self.assertNotHasAttr(record, 'foo') + class PrefixAdapter(logging.LoggerAdapter): prefix = 'Adapter' @@ -7236,6 +7267,16 @@ class MiscTestCase(unittest.TestCase): support.check__all__(self, logging, not_exported=not_exported) +class TestModule(unittest.TestCase): + def test_deprecated__version__and__date__(self): + msg = "is deprecated and slated for removal in Python 3.20" + for attr in ("__version__", "__date__"): + with self.subTest(attr=attr): + with self.assertWarnsRegex(DeprecationWarning, msg) as cm: + getattr(logging, attr) + self.assertEqual(cm.filename, __file__) + + # Set the locale to the platform-dependent default. I have no idea # why the test does this, but in any case we save the current locale # first and restore it at the end. diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index f336d49fa4f..b48a8812a1a 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1374,17 +1374,22 @@ class LongTest(unittest.TestCase): check(tests4, 'little', signed=False) self.assertRaises(OverflowError, (256).to_bytes, 1, 'big', signed=False) - self.assertRaises(OverflowError, (256).to_bytes, 1, 'big', signed=True) self.assertRaises(OverflowError, (256).to_bytes, 1, 'little', signed=False) - self.assertRaises(OverflowError, (256).to_bytes, 1, 'little', signed=True) + self.assertRaises(OverflowError, (128).to_bytes, 1, 'big', signed=True) + self.assertRaises(OverflowError, (128).to_bytes, 1, 'little', signed=True) + self.assertRaises(OverflowError, (-129).to_bytes, 1, 'big', signed=True) + self.assertRaises(OverflowError, (-129).to_bytes, 1, 'little', signed=True) self.assertRaises(OverflowError, (-1).to_bytes, 2, 'big', signed=False) self.assertRaises(OverflowError, (-1).to_bytes, 2, 'little', signed=False) self.assertEqual((0).to_bytes(0, 'big'), b'') + self.assertEqual((0).to_bytes(0, 'big', signed=True), b'') self.assertEqual((1).to_bytes(5, 'big'), b'\x00\x00\x00\x00\x01') self.assertEqual((0).to_bytes(5, 'big'), b'\x00\x00\x00\x00\x00') self.assertEqual((-1).to_bytes(5, 'big', signed=True), b'\xff\xff\xff\xff\xff') self.assertRaises(OverflowError, (1).to_bytes, 0, 'big') + self.assertRaises(OverflowError, (-1).to_bytes, 0, 'big', signed=True) + self.assertRaises(OverflowError, (-1).to_bytes, 0, 'little', signed=True) # gh-98783 class SubStr(str): @@ -1693,5 +1698,21 @@ class LongTest(unittest.TestCase): # GH-117195 -- This shouldn't crash object.__sizeof__(1) + def test_hash(self): + # gh-136599 + self.assertEqual(hash(-1), -2) + self.assertEqual(hash(0), 0) + self.assertEqual(hash(10), 10) + + self.assertEqual(hash(sys.hash_info.modulus - 2), sys.hash_info.modulus - 2) + self.assertEqual(hash(sys.hash_info.modulus - 1), sys.hash_info.modulus - 1) + self.assertEqual(hash(sys.hash_info.modulus), 0) + self.assertEqual(hash(sys.hash_info.modulus + 1), 1) + + self.assertEqual(hash(-sys.hash_info.modulus - 2), -2) + self.assertEqual(hash(-sys.hash_info.modulus - 1), -2) + self.assertEqual(hash(-sys.hash_info.modulus), 0) + self.assertEqual(hash(-sys.hash_info.modulus + 1), -sys.hash_info.modulus + 1) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 8b1fb0eba1f..662bdfccc79 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -43,6 +43,11 @@ class IntTestCase(unittest.TestCase, HelperMixin): for expected in (-n, n): self.helper(expected) n = n >> 1 + n = 1 << 100 + while n: + for expected in (-n, -n+1, n-1, n): + self.helper(expected) + n = n >> 1 def test_int64(self): # Simulate int marshaling with TYPE_INT64. diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index e3b0d4fa9ee..68f41a2e620 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -55,56 +55,6 @@ def to_ulps(x): return n -# Here's a pure Python version of the math.factorial algorithm, for -# documentation and comparison purposes. -# -# Formula: -# -# factorial(n) = factorial_odd_part(n) << (n - count_set_bits(n)) -# -# where -# -# factorial_odd_part(n) = product_{i >= 0} product_{0 < j <= n >> i; j odd} j -# -# The outer product above is an infinite product, but once i >= n.bit_length, -# (n >> i) < 1 and the corresponding term of the product is empty. So only the -# finitely many terms for 0 <= i < n.bit_length() contribute anything. -# -# We iterate downwards from i == n.bit_length() - 1 to i == 0. The inner -# product in the formula above starts at 1 for i == n.bit_length(); for each i -# < n.bit_length() we get the inner product for i from that for i + 1 by -# multiplying by all j in {n >> i+1 < j <= n >> i; j odd}. In Python terms, -# this set is range((n >> i+1) + 1 | 1, (n >> i) + 1 | 1, 2). - -def count_set_bits(n): - """Number of '1' bits in binary expansion of a nonnnegative integer.""" - return 1 + count_set_bits(n & n - 1) if n else 0 - -def partial_product(start, stop): - """Product of integers in range(start, stop, 2), computed recursively. - start and stop should both be odd, with start <= stop. - - """ - numfactors = (stop - start) >> 1 - if not numfactors: - return 1 - elif numfactors == 1: - return start - else: - mid = (start + numfactors) | 1 - return partial_product(start, mid) * partial_product(mid, stop) - -def py_factorial(n): - """Factorial of nonnegative integer n, via "Binary Split Factorial Formula" - described at http://www.luschny.de/math/factorial/binarysplitfact.html - - """ - inner = outer = 1 - for i in reversed(range(n.bit_length())): - inner *= partial_product((n >> i + 1) + 1 | 1, (n >> i) + 1 | 1) - outer *= inner - return outer << (n - count_set_bits(n)) - def ulp_abs_check(expected, got, ulp_tol, abs_tol): """Given finite floats `expected` and `got`, check that they're approximately equal to within the given number of ulps or the @@ -239,6 +189,22 @@ class MyIndexable(object): def __index__(self): return self.value +class IndexableFloatLike: + def __init__(self, float_value, index_value): + self.float_value = float_value + self.index_value = index_value + + def __float__(self): + if isinstance(self.float_value, BaseException): + raise self.float_value + return self.float_value + + def __index__(self): + if isinstance(self.index_value, BaseException): + raise self.index_value + return self.index_value + + class BadDescr: def __get__(self, obj, objtype=None): raise ValueError @@ -547,33 +513,6 @@ class MathTests(unittest.TestCase): self.ftest('fabs(0)', math.fabs(0), 0) self.ftest('fabs(1)', math.fabs(1), 1) - def testFactorial(self): - self.assertEqual(math.factorial(0), 1) - total = 1 - for i in range(1, 1000): - total *= i - self.assertEqual(math.factorial(i), total) - self.assertEqual(math.factorial(i), py_factorial(i)) - self.assertRaises(ValueError, math.factorial, -1) - self.assertRaises(ValueError, math.factorial, -10**100) - - def testFactorialNonIntegers(self): - self.assertRaises(TypeError, math.factorial, 5.0) - self.assertRaises(TypeError, math.factorial, 5.2) - self.assertRaises(TypeError, math.factorial, -1.0) - self.assertRaises(TypeError, math.factorial, -1e100) - self.assertRaises(TypeError, math.factorial, decimal.Decimal('5')) - self.assertRaises(TypeError, math.factorial, decimal.Decimal('5.2')) - self.assertRaises(TypeError, math.factorial, "5") - - # Other implementations may place different upper bounds. - @support.cpython_only - def testFactorialHugeInputs(self): - # Currently raises OverflowError for inputs that are too large - # to fit into a C long. - self.assertRaises(OverflowError, math.factorial, 10**100) - self.assertRaises(TypeError, math.factorial, 1e100) - def testFloor(self): self.assertRaises(TypeError, math.floor) self.assertEqual(int, type(math.floor(0.5))) @@ -1175,68 +1114,6 @@ class MathTests(unittest.TestCase): with self.assertRaises(ValueError): math.dist([1, 2], [3, 4, 5]) - def testIsqrt(self): - # Test a variety of inputs, large and small. - test_values = ( - list(range(1000)) - + list(range(10**6 - 1000, 10**6 + 1000)) - + [2**e + i for e in range(60, 200) for i in range(-40, 40)] - + [3**9999, 10**5001] - ) - - for value in test_values: - with self.subTest(value=value): - s = math.isqrt(value) - self.assertIs(type(s), int) - self.assertLessEqual(s*s, value) - self.assertLess(value, (s+1)*(s+1)) - - # Negative values - with self.assertRaises(ValueError): - math.isqrt(-1) - - # Integer-like things - s = math.isqrt(True) - self.assertIs(type(s), int) - self.assertEqual(s, 1) - - s = math.isqrt(False) - self.assertIs(type(s), int) - self.assertEqual(s, 0) - - class IntegerLike(object): - def __init__(self, value): - self.value = value - - def __index__(self): - return self.value - - s = math.isqrt(IntegerLike(1729)) - self.assertIs(type(s), int) - self.assertEqual(s, 41) - - with self.assertRaises(ValueError): - math.isqrt(IntegerLike(-3)) - - # Non-integer-like things - bad_values = [ - 3.5, "a string", decimal.Decimal("3.5"), 3.5j, - 100.0, -4.0, - ] - for value in bad_values: - with self.subTest(value=value): - with self.assertRaises(TypeError): - math.isqrt(value) - - @support.bigmemtest(2**32, memuse=0.85) - def test_isqrt_huge(self, size): - if size & 1: - size += 1 - v = 1 << size - w = math.isqrt(v) - self.assertEqual(w.bit_length(), size // 2 + 1) - self.assertEqual(w.bit_count(), 1) - def test_lcm(self): lcm = math.lcm self.assertEqual(lcm(0, 0), 0) @@ -1331,13 +1208,32 @@ class MathTests(unittest.TestCase): self.ftest('log(10**40, 10**20)', math.log(10**40, 10**20), 2) self.ftest('log(10**1000)', math.log(10**1000), 2302.5850929940457) + self.ftest('log(10**2000, 10**1000)', math.log(10**2000, 10**1000), 2) + self.ftest('log(MyIndexable(32), MyIndexable(2))', + math.log(MyIndexable(32), MyIndexable(2)), 5) + self.ftest('log(MyIndexable(10**1000))', + math.log(MyIndexable(10**1000)), + 2302.5850929940457) + self.ftest('log(MyIndexable(10**2000), MyIndexable(10**1000))', + math.log(MyIndexable(10**2000), MyIndexable(10**1000)), + 2) + self.assertRaises(ValueError, math.log, 0.0) + self.assertRaises(ValueError, math.log, 0) + self.assertRaises(ValueError, math.log, MyIndexable(0)) self.assertRaises(ValueError, math.log, -1.5) + self.assertRaises(ValueError, math.log, -1) + self.assertRaises(ValueError, math.log, MyIndexable(-1)) self.assertRaises(ValueError, math.log, -10**1000) + self.assertRaises(ValueError, math.log, MyIndexable(-10**1000)) self.assertRaises(ValueError, math.log, 10, -10) self.assertRaises(ValueError, math.log, NINF) self.assertEqual(math.log(INF), INF) self.assertTrue(math.isnan(math.log(NAN))) + self.assertEqual(math.log(IndexableFloatLike(math.e, 10**1000)), 1.0) + self.assertAlmostEqual(math.log(IndexableFloatLike(OverflowError(), 10**1000)), + 2302.5850929940457) + def testLog1p(self): self.assertRaises(TypeError, math.log1p) for n in [2, 2**90, 2**300]: @@ -1353,16 +1249,28 @@ class MathTests(unittest.TestCase): self.assertEqual(math.log2(1), 0.0) self.assertEqual(math.log2(2), 1.0) self.assertEqual(math.log2(4), 2.0) + self.assertEqual(math.log2(MyIndexable(4)), 2.0) # Large integer values self.assertEqual(math.log2(2**1023), 1023.0) self.assertEqual(math.log2(2**1024), 1024.0) self.assertEqual(math.log2(2**2000), 2000.0) + self.assertEqual(math.log2(MyIndexable(2**2000)), 2000.0) + self.assertRaises(ValueError, math.log2, 0.0) + self.assertRaises(ValueError, math.log2, 0) + self.assertRaises(ValueError, math.log2, MyIndexable(0)) self.assertRaises(ValueError, math.log2, -1.5) + self.assertRaises(ValueError, math.log2, -1) + self.assertRaises(ValueError, math.log2, MyIndexable(-1)) + self.assertRaises(ValueError, math.log2, -2**2000) + self.assertRaises(ValueError, math.log2, MyIndexable(-2**2000)) self.assertRaises(ValueError, math.log2, NINF) self.assertTrue(math.isnan(math.log2(NAN))) + self.assertEqual(math.log2(IndexableFloatLike(8.0, 2**2000)), 3.0) + self.assertEqual(math.log2(IndexableFloatLike(OverflowError(), 2**2000)), 2000.0) + @requires_IEEE_754 # log2() is not accurate enough on Mac OS X Tiger (10.4) @support.requires_mac_ver(10, 5) @@ -1378,12 +1286,24 @@ class MathTests(unittest.TestCase): self.ftest('log10(1)', math.log10(1), 0) self.ftest('log10(10)', math.log10(10), 1) self.ftest('log10(10**1000)', math.log10(10**1000), 1000.0) + self.ftest('log10(MyIndexable(10))', math.log10(MyIndexable(10)), 1) + self.ftest('log10(MyIndexable(10**1000))', + math.log10(MyIndexable(10**1000)), 1000.0) + self.assertRaises(ValueError, math.log10, 0.0) + self.assertRaises(ValueError, math.log10, 0) + self.assertRaises(ValueError, math.log10, MyIndexable(0)) self.assertRaises(ValueError, math.log10, -1.5) + self.assertRaises(ValueError, math.log10, -1) + self.assertRaises(ValueError, math.log10, MyIndexable(-1)) self.assertRaises(ValueError, math.log10, -10**1000) + self.assertRaises(ValueError, math.log10, MyIndexable(-10**1000)) self.assertRaises(ValueError, math.log10, NINF) self.assertEqual(math.log(INF), INF) self.assertTrue(math.isnan(math.log10(NAN))) + self.assertEqual(math.log10(IndexableFloatLike(100.0, 10**1000)), 2.0) + self.assertEqual(math.log10(IndexableFloatLike(OverflowError(), 10**1000)), 1000.0) + @support.bigmemtest(2**32, memuse=0.2) def test_log_huge_integer(self, size): v = 1 << size @@ -2392,140 +2312,6 @@ class MathTests(unittest.TestCase): self.assertEqual(type(prod([1, decimal.Decimal(2.0), 3, 4, 5, 6])), decimal.Decimal) - def testPerm(self): - perm = math.perm - factorial = math.factorial - # Test if factorial definition is satisfied - for n in range(500): - for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)): - self.assertEqual(perm(n, k), - factorial(n) // factorial(n - k)) - - # Test for Pascal's identity - for n in range(1, 100): - for k in range(1, n): - self.assertEqual(perm(n, k), perm(n - 1, k - 1) * k + perm(n - 1, k)) - - # Test corner cases - for n in range(1, 100): - self.assertEqual(perm(n, 0), 1) - self.assertEqual(perm(n, 1), n) - self.assertEqual(perm(n, n), factorial(n)) - - # Test one argument form - for n in range(20): - self.assertEqual(perm(n), factorial(n)) - self.assertEqual(perm(n, None), factorial(n)) - - # Raises TypeError if any argument is non-integer or argument count is - # not 1 or 2 - self.assertRaises(TypeError, perm, 10, 1.0) - self.assertRaises(TypeError, perm, 10, decimal.Decimal(1.0)) - self.assertRaises(TypeError, perm, 10, "1") - self.assertRaises(TypeError, perm, 10.0, 1) - self.assertRaises(TypeError, perm, decimal.Decimal(10.0), 1) - self.assertRaises(TypeError, perm, "10", 1) - - self.assertRaises(TypeError, perm) - self.assertRaises(TypeError, perm, 10, 1, 3) - self.assertRaises(TypeError, perm) - - # Raises Value error if not k or n are negative numbers - self.assertRaises(ValueError, perm, -1, 1) - self.assertRaises(ValueError, perm, -2**1000, 1) - self.assertRaises(ValueError, perm, 1, -1) - self.assertRaises(ValueError, perm, 1, -2**1000) - - # Returns zero if k is greater than n - self.assertEqual(perm(1, 2), 0) - self.assertEqual(perm(1, 2**1000), 0) - - n = 2**1000 - self.assertEqual(perm(n, 0), 1) - self.assertEqual(perm(n, 1), n) - self.assertEqual(perm(n, 2), n * (n-1)) - if support.check_impl_detail(cpython=True): - self.assertRaises(OverflowError, perm, n, n) - - for n, k in (True, True), (True, False), (False, False): - self.assertEqual(perm(n, k), 1) - self.assertIs(type(perm(n, k)), int) - self.assertEqual(perm(IntSubclass(5), IntSubclass(2)), 20) - self.assertEqual(perm(MyIndexable(5), MyIndexable(2)), 20) - for k in range(3): - self.assertIs(type(perm(IntSubclass(5), IntSubclass(k))), int) - self.assertIs(type(perm(MyIndexable(5), MyIndexable(k))), int) - - def testComb(self): - comb = math.comb - factorial = math.factorial - # Test if factorial definition is satisfied - for n in range(500): - for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)): - self.assertEqual(comb(n, k), factorial(n) - // (factorial(k) * factorial(n - k))) - - # Test for Pascal's identity - for n in range(1, 100): - for k in range(1, n): - self.assertEqual(comb(n, k), comb(n - 1, k - 1) + comb(n - 1, k)) - - # Test corner cases - for n in range(100): - self.assertEqual(comb(n, 0), 1) - self.assertEqual(comb(n, n), 1) - - for n in range(1, 100): - self.assertEqual(comb(n, 1), n) - self.assertEqual(comb(n, n - 1), n) - - # Test Symmetry - for n in range(100): - for k in range(n // 2): - self.assertEqual(comb(n, k), comb(n, n - k)) - - # Raises TypeError if any argument is non-integer or argument count is - # not 2 - self.assertRaises(TypeError, comb, 10, 1.0) - self.assertRaises(TypeError, comb, 10, decimal.Decimal(1.0)) - self.assertRaises(TypeError, comb, 10, "1") - self.assertRaises(TypeError, comb, 10.0, 1) - self.assertRaises(TypeError, comb, decimal.Decimal(10.0), 1) - self.assertRaises(TypeError, comb, "10", 1) - - self.assertRaises(TypeError, comb, 10) - self.assertRaises(TypeError, comb, 10, 1, 3) - self.assertRaises(TypeError, comb) - - # Raises Value error if not k or n are negative numbers - self.assertRaises(ValueError, comb, -1, 1) - self.assertRaises(ValueError, comb, -2**1000, 1) - self.assertRaises(ValueError, comb, 1, -1) - self.assertRaises(ValueError, comb, 1, -2**1000) - - # Returns zero if k is greater than n - self.assertEqual(comb(1, 2), 0) - self.assertEqual(comb(1, 2**1000), 0) - - n = 2**1000 - self.assertEqual(comb(n, 0), 1) - self.assertEqual(comb(n, 1), n) - self.assertEqual(comb(n, 2), n * (n-1) // 2) - self.assertEqual(comb(n, n), 1) - self.assertEqual(comb(n, n-1), n) - self.assertEqual(comb(n, n-2), n * (n-1) // 2) - if support.check_impl_detail(cpython=True): - self.assertRaises(OverflowError, comb, n, n//2) - - for n, k in (True, True), (True, False), (False, False): - self.assertEqual(comb(n, k), 1) - self.assertIs(type(comb(n, k)), int) - self.assertEqual(comb(IntSubclass(5), IntSubclass(2)), 10) - self.assertEqual(comb(MyIndexable(5), MyIndexable(2)), 10) - for k in range(3): - self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int) - self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int) - @requires_IEEE_754 def test_nextafter(self): # around 2^52 and 2^63 diff --git a/Lib/test/test_math_integer.py b/Lib/test/test_math_integer.py new file mode 100644 index 00000000000..09a98d93bd6 --- /dev/null +++ b/Lib/test/test_math_integer.py @@ -0,0 +1,403 @@ +from decimal import Decimal +from fractions import Fraction +import unittest +from test import support + + +class IntSubclass(int): + pass + +# Class providing an __index__ method. +class MyIndexable(object): + def __init__(self, value): + self.value = value + + def __index__(self): + return self.value + +# Here's a pure Python version of the math.integer.factorial algorithm, for +# documentation and comparison purposes. +# +# Formula: +# +# factorial(n) = factorial_odd_part(n) << (n - count_set_bits(n)) +# +# where +# +# factorial_odd_part(n) = product_{i >= 0} product_{0 < j <= n >> i; j odd} j +# +# The outer product above is an infinite product, but once i >= n.bit_length, +# (n >> i) < 1 and the corresponding term of the product is empty. So only the +# finitely many terms for 0 <= i < n.bit_length() contribute anything. +# +# We iterate downwards from i == n.bit_length() - 1 to i == 0. The inner +# product in the formula above starts at 1 for i == n.bit_length(); for each i +# < n.bit_length() we get the inner product for i from that for i + 1 by +# multiplying by all j in {n >> i+1 < j <= n >> i; j odd}. In Python terms, +# this set is range((n >> i+1) + 1 | 1, (n >> i) + 1 | 1, 2). + +def count_set_bits(n): + """Number of '1' bits in binary expansion of a nonnnegative integer.""" + return 1 + count_set_bits(n & n - 1) if n else 0 + +def partial_product(start, stop): + """Product of integers in range(start, stop, 2), computed recursively. + start and stop should both be odd, with start <= stop. + + """ + numfactors = (stop - start) >> 1 + if not numfactors: + return 1 + elif numfactors == 1: + return start + else: + mid = (start + numfactors) | 1 + return partial_product(start, mid) * partial_product(mid, stop) + +def py_factorial(n): + """Factorial of nonnegative integer n, via "Binary Split Factorial Formula" + described at http://www.luschny.de/math/factorial/binarysplitfact.html + + """ + inner = outer = 1 + for i in reversed(range(n.bit_length())): + inner *= partial_product((n >> i + 1) + 1 | 1, (n >> i) + 1 | 1) + outer *= inner + return outer << (n - count_set_bits(n)) + + +class IntMathTests(unittest.TestCase): + import math.integer as module + + def assertIntEqual(self, actual, expected): + self.assertEqual(actual, expected) + self.assertIs(type(actual), int) + + def test_factorial(self): + factorial = self.module.factorial + self.assertEqual(factorial(0), 1) + total = 1 + for i in range(1, 1000): + total *= i + self.assertEqual(factorial(i), total) + self.assertEqual(factorial(i), py_factorial(i)) + + self.assertIntEqual(factorial(False), 1) + self.assertIntEqual(factorial(True), 1) + for i in range(3): + expected = factorial(i) + self.assertIntEqual(factorial(IntSubclass(i)), expected) + self.assertIntEqual(factorial(MyIndexable(i)), expected) + + self.assertRaises(ValueError, factorial, -1) + self.assertRaises(ValueError, factorial, -10**1000) + + def test_factorial_non_integers(self): + factorial = self.module.factorial + self.assertRaises(TypeError, factorial, 5.0) + self.assertRaises(TypeError, factorial, 5.2) + self.assertRaises(TypeError, factorial, -1.0) + self.assertRaises(TypeError, factorial, -1e100) + self.assertRaises(TypeError, factorial, Decimal('5')) + self.assertRaises(TypeError, factorial, Decimal('5.2')) + self.assertRaises(TypeError, factorial, Fraction(5, 1)) + self.assertRaises(TypeError, factorial, "5") + + # Other implementations may place different upper bounds. + @support.cpython_only + def test_factorial_huge_inputs(self): + factorial = self.module.factorial + # Currently raises OverflowError for inputs that are too large + # to fit into a C long. + self.assertRaises(OverflowError, factorial, 10**100) + self.assertRaises(TypeError, factorial, 1e100) + + def test_gcd(self): + gcd = self.module.gcd + self.assertEqual(gcd(0, 0), 0) + self.assertEqual(gcd(1, 0), 1) + self.assertEqual(gcd(-1, 0), 1) + self.assertEqual(gcd(0, 1), 1) + self.assertEqual(gcd(0, -1), 1) + self.assertEqual(gcd(7, 1), 1) + self.assertEqual(gcd(7, -1), 1) + self.assertEqual(gcd(-23, 15), 1) + self.assertEqual(gcd(120, 84), 12) + self.assertEqual(gcd(84, -120), 12) + self.assertEqual(gcd(1216342683557601535506311712, + 436522681849110124616458784), 32) + c = 652560 + x = 434610456570399902378880679233098819019853229470286994367836600566 + y = 1064502245825115327754847244914921553977 + a = x * c + b = y * c + self.assertEqual(gcd(a, b), c) + self.assertEqual(gcd(b, a), c) + self.assertEqual(gcd(-a, b), c) + self.assertEqual(gcd(b, -a), c) + self.assertEqual(gcd(a, -b), c) + self.assertEqual(gcd(-b, a), c) + self.assertEqual(gcd(-a, -b), c) + self.assertEqual(gcd(-b, -a), c) + c = 576559230871654959816130551884856912003141446781646602790216406874 + a = x * c + b = y * c + self.assertEqual(gcd(a, b), c) + self.assertEqual(gcd(b, a), c) + self.assertEqual(gcd(-a, b), c) + self.assertEqual(gcd(b, -a), c) + self.assertEqual(gcd(a, -b), c) + self.assertEqual(gcd(-b, a), c) + self.assertEqual(gcd(-a, -b), c) + self.assertEqual(gcd(-b, -a), c) + + self.assertRaises(TypeError, gcd, 120.0, 84) + self.assertRaises(TypeError, gcd, 120, 84.0) + self.assertIntEqual(gcd(IntSubclass(120), IntSubclass(84)), 12) + self.assertIntEqual(gcd(MyIndexable(120), MyIndexable(84)), 12) + + def test_lcm(self): + lcm = self.module.lcm + self.assertEqual(lcm(0, 0), 0) + self.assertEqual(lcm(1, 0), 0) + self.assertEqual(lcm(-1, 0), 0) + self.assertEqual(lcm(0, 1), 0) + self.assertEqual(lcm(0, -1), 0) + self.assertEqual(lcm(7, 1), 7) + self.assertEqual(lcm(7, -1), 7) + self.assertEqual(lcm(-23, 15), 345) + self.assertEqual(lcm(120, 84), 840) + self.assertEqual(lcm(84, -120), 840) + self.assertEqual(lcm(1216342683557601535506311712, + 436522681849110124616458784), + 16592536571065866494401400422922201534178938447014944) + + x = 43461045657039990237 + y = 10645022458251153277 + for c in (652560, + 57655923087165495981): + a = x * c + b = y * c + d = x * y * c + self.assertEqual(lcm(a, b), d) + self.assertEqual(lcm(b, a), d) + self.assertEqual(lcm(-a, b), d) + self.assertEqual(lcm(b, -a), d) + self.assertEqual(lcm(a, -b), d) + self.assertEqual(lcm(-b, a), d) + self.assertEqual(lcm(-a, -b), d) + self.assertEqual(lcm(-b, -a), d) + + self.assertEqual(lcm(), 1) + self.assertEqual(lcm(120), 120) + self.assertEqual(lcm(-120), 120) + self.assertEqual(lcm(120, 84, 102), 14280) + self.assertEqual(lcm(120, 0, 84), 0) + + self.assertRaises(TypeError, lcm, 120.0) + self.assertRaises(TypeError, lcm, 120.0, 84) + self.assertRaises(TypeError, lcm, 120, 84.0) + self.assertRaises(TypeError, lcm, 120, 0, 84.0) + self.assertEqual(lcm(MyIndexable(120), MyIndexable(84)), 840) + + def test_isqrt(self): + isqrt = self.module.isqrt + # Test a variety of inputs, large and small. + test_values = ( + list(range(1000)) + + list(range(10**6 - 1000, 10**6 + 1000)) + + [2**e + i for e in range(60, 200) for i in range(-40, 40)] + + [3**9999, 10**5001] + ) + + for value in test_values: + with self.subTest(value=value): + s = isqrt(value) + self.assertIs(type(s), int) + self.assertLessEqual(s*s, value) + self.assertLess(value, (s+1)*(s+1)) + + # Negative values + with self.assertRaises(ValueError): + isqrt(-1) + + # Integer-like things + self.assertIntEqual(isqrt(True), 1) + self.assertIntEqual(isqrt(False), 0) + self.assertIntEqual(isqrt(MyIndexable(1729)), 41) + + with self.assertRaises(ValueError): + isqrt(MyIndexable(-3)) + + # Non-integer-like things + bad_values = [ + 3.5, "a string", Decimal("3.5"), 3.5j, + 100.0, -4.0, + ] + for value in bad_values: + with self.subTest(value=value): + with self.assertRaises(TypeError): + isqrt(value) + + @support.bigmemtest(2**32, memuse=0.85) + def test_isqrt_huge(self, size): + isqrt = self.module.isqrt + if size & 1: + size += 1 + v = 1 << size + w = isqrt(v) + self.assertEqual(w.bit_length(), size // 2 + 1) + self.assertEqual(w.bit_count(), 1) + + def test_perm(self): + perm = self.module.perm + factorial = self.module.factorial + # Test if factorial definition is satisfied + for n in range(500): + for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)): + self.assertEqual(perm(n, k), + factorial(n) // factorial(n - k)) + + # Test for Pascal's identity + for n in range(1, 100): + for k in range(1, n): + self.assertEqual(perm(n, k), perm(n - 1, k - 1) * k + perm(n - 1, k)) + + # Test corner cases + for n in range(1, 100): + self.assertEqual(perm(n, 0), 1) + self.assertEqual(perm(n, 1), n) + self.assertEqual(perm(n, n), factorial(n)) + + # Test one argument form + for n in range(20): + self.assertEqual(perm(n), factorial(n)) + self.assertEqual(perm(n, None), factorial(n)) + + # Raises TypeError if any argument is non-integer or argument count is + # not 1 or 2 + self.assertRaises(TypeError, perm, 10, 1.0) + self.assertRaises(TypeError, perm, 10, Decimal(1.0)) + self.assertRaises(TypeError, perm, 10, Fraction(1, 1)) + self.assertRaises(TypeError, perm, 10, "1") + self.assertRaises(TypeError, perm, 10.0, 1) + self.assertRaises(TypeError, perm, Decimal(10.0), 1) + self.assertRaises(TypeError, perm, Fraction(10, 1), 1) + self.assertRaises(TypeError, perm, "10", 1) + + self.assertRaises(TypeError, perm) + self.assertRaises(TypeError, perm, 10, 1, 3) + self.assertRaises(TypeError, perm) + + # Raises Value error if not k or n are negative numbers + self.assertRaises(ValueError, perm, -1, 1) + self.assertRaises(ValueError, perm, -2**1000, 1) + self.assertRaises(ValueError, perm, 1, -1) + self.assertRaises(ValueError, perm, 1, -2**1000) + + # Returns zero if k is greater than n + self.assertEqual(perm(1, 2), 0) + self.assertEqual(perm(1, 2**1000), 0) + + n = 2**1000 + self.assertEqual(perm(n, 0), 1) + self.assertEqual(perm(n, 1), n) + self.assertEqual(perm(n, 2), n * (n-1)) + if support.check_impl_detail(cpython=True): + self.assertRaises(OverflowError, perm, n, n) + + for n, k in (True, True), (True, False), (False, False): + self.assertIntEqual(perm(n, k), 1) + self.assertEqual(perm(IntSubclass(5), IntSubclass(2)), 20) + self.assertEqual(perm(MyIndexable(5), MyIndexable(2)), 20) + for k in range(3): + self.assertIs(type(perm(IntSubclass(5), IntSubclass(k))), int) + self.assertIs(type(perm(MyIndexable(5), MyIndexable(k))), int) + + def test_comb(self): + comb = self.module.comb + factorial = self.module.factorial + # Test if factorial definition is satisfied + for n in range(500): + for k in (range(n + 1) if n < 100 else range(30) if n < 200 else range(10)): + self.assertEqual(comb(n, k), factorial(n) + // (factorial(k) * factorial(n - k))) + + # Test for Pascal's identity + for n in range(1, 100): + for k in range(1, n): + self.assertEqual(comb(n, k), comb(n - 1, k - 1) + comb(n - 1, k)) + + # Test corner cases + for n in range(100): + self.assertEqual(comb(n, 0), 1) + self.assertEqual(comb(n, n), 1) + + for n in range(1, 100): + self.assertEqual(comb(n, 1), n) + self.assertEqual(comb(n, n - 1), n) + + # Test Symmetry + for n in range(100): + for k in range(n // 2): + self.assertEqual(comb(n, k), comb(n, n - k)) + + # Raises TypeError if any argument is non-integer or argument count is + # not 2 + self.assertRaises(TypeError, comb, 10, 1.0) + self.assertRaises(TypeError, comb, 10, Decimal(1.0)) + self.assertRaises(TypeError, comb, 10, "1") + self.assertRaises(TypeError, comb, 10.0, 1) + self.assertRaises(TypeError, comb, Decimal(10.0), 1) + self.assertRaises(TypeError, comb, "10", 1) + + self.assertRaises(TypeError, comb, 10) + self.assertRaises(TypeError, comb, 10, 1, 3) + self.assertRaises(TypeError, comb) + + # Raises Value error if not k or n are negative numbers + self.assertRaises(ValueError, comb, -1, 1) + self.assertRaises(ValueError, comb, -2**1000, 1) + self.assertRaises(ValueError, comb, 1, -1) + self.assertRaises(ValueError, comb, 1, -2**1000) + + # Returns zero if k is greater than n + self.assertEqual(comb(1, 2), 0) + self.assertEqual(comb(1, 2**1000), 0) + + n = 2**1000 + self.assertEqual(comb(n, 0), 1) + self.assertEqual(comb(n, 1), n) + self.assertEqual(comb(n, 2), n * (n-1) // 2) + self.assertEqual(comb(n, n), 1) + self.assertEqual(comb(n, n-1), n) + self.assertEqual(comb(n, n-2), n * (n-1) // 2) + if support.check_impl_detail(cpython=True): + self.assertRaises(OverflowError, comb, n, n//2) + + for n, k in (True, True), (True, False), (False, False): + self.assertIntEqual(comb(n, k), 1) + self.assertEqual(comb(IntSubclass(5), IntSubclass(2)), 10) + self.assertEqual(comb(MyIndexable(5), MyIndexable(2)), 10) + for k in range(3): + self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int) + self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int) + + +class MathTests(IntMathTests): + import math as module + + +class MiscTests(unittest.TestCase): + + def test_module_name(self): + import math.integer + self.assertEqual(math.integer.__name__, 'math.integer') + for name in dir(math.integer): + if not name.startswith('_'): + obj = getattr(math.integer, name) + self.assertEqual(obj.__module__, 'math.integer') + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 64f440f180b..1bd58eb6408 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -600,6 +600,25 @@ class OtherTest(unittest.TestCase): m2 = m1[::-1] self.assertEqual(m2.hex(), '30' * 200000) + def test_memoryview_hex_separator(self): + x = bytes(range(97, 102)) + m1 = memoryview(x) + m2 = m1[::-1] + self.assertEqual(m2.hex(':'), '65:64:63:62:61') + self.assertEqual(m2.hex(':', 2), '65:6463:6261') + self.assertEqual(m2.hex(':', -2), '6564:6362:61') + self.assertEqual(m2.hex(sep=':', bytes_per_sep=2), '65:6463:6261') + self.assertEqual(m2.hex(sep=':', bytes_per_sep=-2), '6564:6362:61') + for bytes_per_sep in 5, -5, 2**31-1, -(2**31-1): + with self.subTest(bytes_per_sep=bytes_per_sep): + self.assertEqual(m2.hex(':', bytes_per_sep), '6564636261') + for bytes_per_sep in 2**31, -2**31, 2**1000, -2**1000: + with self.subTest(bytes_per_sep=bytes_per_sep): + try: + self.assertEqual(m2.hex(':', bytes_per_sep), '6564636261') + except OverflowError: + pass + def test_copy(self): m = memoryview(b'abc') with self.assertRaises(TypeError): diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index c1806b1c133..0f29640bc1c 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -112,13 +112,12 @@ class MimeTypesTestCase(unittest.TestCase): eq = self.assertEqual # First try strict eq(self.db.guess_file_type('foo.xul', strict=True), (None, None)) - eq(self.db.guess_extension('image/jpg', strict=True), None) # And then non-strict eq(self.db.guess_file_type('foo.xul', strict=False), ('text/xul', None)) eq(self.db.guess_file_type('foo.XUL', strict=False), ('text/xul', None)) eq(self.db.guess_file_type('foo.invalid', strict=False), (None, None)) - eq(self.db.guess_extension('image/jpg', strict=False), '.jpg') - eq(self.db.guess_extension('image/JPG', strict=False), '.jpg') + eq(self.db.guess_extension('image/jpeg', strict=False), '.jpg') + eq(self.db.guess_extension('image/JPEG', strict=False), '.jpg') def test_filename_with_url_delimiters(self): # bpo-38449: URL delimiters cases should be handled also. @@ -179,8 +178,8 @@ class MimeTypesTestCase(unittest.TestCase): self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'}) self.assertEqual(len(set(all)), len(all)) # no duplicates # And now non-strict - all = self.db.guess_all_extensions('image/jpg', strict=False) - self.assertEqual(all, ['.jpg']) + all = self.db.guess_all_extensions('image/jpeg', strict=False) + self.assertEqual(all, ['.jpg', '.jpe', '.jpeg']) # And now for no hits all = self.db.guess_all_extensions('image/jpg', strict=True) self.assertEqual(all, []) @@ -229,7 +228,11 @@ class MimeTypesTestCase(unittest.TestCase): ("application/octet-stream", ".bin"), ("application/gzip", ".gz"), ("application/ogg", ".ogx"), + ("application/pdf", ".pdf"), ("application/postscript", ".ps"), + ("application/rtf", ".rtf"), + ("application/texinfo", ".texi"), + ("application/toml", ".toml"), ("application/vnd.apple.mpegurl", ".m3u"), ("application/vnd.ms-excel", ".xls"), ("application/vnd.ms-fontobject", ".eot"), @@ -246,7 +249,6 @@ class MimeTypesTestCase(unittest.TestCase): ("application/x-debian-package", ".deb"), ("application/x-httpd-php", ".php"), ("application/x-rpm", ".rpm"), - ("application/x-texinfo", ".texi"), ("application/x-troff", ".roff"), ("application/xml", ".xsl"), ("application/yaml", ".yaml"), @@ -279,7 +281,6 @@ class MimeTypesTestCase(unittest.TestCase): ("model/stl", ".stl"), ("text/html", ".html"), ("text/plain", ".txt"), - ("text/rtf", ".rtf"), ("text/x-rst", ".rst"), ("video/matroska", ".mkv"), ("video/matroska-3d", ".mk3d"), @@ -370,9 +371,7 @@ class MimeTypesTestCase(unittest.TestCase): self.assertEqual(self.db.guess_type( url="scheme:foo.html", strict=True), ("text/html", None)) self.assertEqual(self.db.guess_all_extensions( - type='image/jpg', strict=True), []) - self.assertEqual(self.db.guess_extension( - type='image/jpg', strict=False), '.jpg') + type='image/jpeg', strict=True), ['.jpg', '.jpe', '.jpeg']) def test_added_types_are_used(self): mimetypes.add_type('testing/default-type', '') @@ -450,15 +449,15 @@ class CommandLineTest(unittest.TestCase): args, help_text = mimetypes._parse_args("--invalid") self.assertTrue(help_text.startswith("usage: ")) - args, _ = mimetypes._parse_args(shlex.split("-l -e image/jpg")) + args, _ = mimetypes._parse_args(shlex.split("-l -e image/jpeg")) self.assertTrue(args.extension) self.assertTrue(args.lenient) - self.assertEqual(args.type, ["image/jpg"]) + self.assertEqual(args.type, ["image/jpeg"]) - args, _ = mimetypes._parse_args(shlex.split("-e image/jpg")) + args, _ = mimetypes._parse_args(shlex.split("-e image/jpeg")) self.assertTrue(args.extension) self.assertFalse(args.lenient) - self.assertEqual(args.type, ["image/jpg"]) + self.assertEqual(args.type, ["image/jpeg"]) args, _ = mimetypes._parse_args(shlex.split("-l foo.webp")) self.assertFalse(args.extension) @@ -489,7 +488,6 @@ class CommandLineTest(unittest.TestCase): def test_invocation(self): for command, expected in [ - ("-l -e image/jpg", ".jpg"), ("-e image/jpeg", ".jpg"), ("-l foo.webp", "type: image/webp encoding: None"), ]: diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index 4f25e9c2a03..7717a98583f 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -2,13 +2,14 @@ import copy import pickle +import time import io from test import support import unittest import xml.dom.minidom -from xml.dom.minidom import parse, Attr, Node, Document, parseString +from xml.dom.minidom import parse, Attr, Node, Document, Element, parseString from xml.dom.minidom import getDOMImplementation from xml.parsers.expat import ExpatError @@ -173,6 +174,31 @@ class MinidomTest(unittest.TestCase): self.assertEqual(dom.documentElement.childNodes[-1].data, "Hello") dom.unlink() + def testAppendChildNoQuadraticComplexity(self): + impl = getDOMImplementation() + + newdoc = impl.createDocument(None, "some_tag", None) + top_element = newdoc.documentElement + children = [newdoc.createElement(f"child-{i}") for i in range(1, 2 ** 15 + 1)] + element = top_element + + start = time.time() + for child in children: + element.appendChild(child) + element = child + end = time.time() + + # This example used to take at least 30 seconds. + self.assertLess(end - start, 1) + + def testSetAttributeNodeWithoutOwnerDocument(self): + # regression test for gh-142754 + elem = Element("test") + attr = Attr("id") + attr.value = "test-id" + elem.setAttributeNode(attr) + self.assertEqual(elem.getAttribute("id"), "test-id") + def testAppendChildFragment(self): dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes() dom.documentElement.appendChild(frag) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index b2a299ed172..368af0cf89c 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1,3 +1,4 @@ +from test import support from test.support import ( requires, _2G, _4G, gc_collect, cpython_only, is_emscripten, is_apple, in_systemd_nspawn_sync_suppressed, @@ -6,7 +7,6 @@ from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok import unittest -import errno import os import re import itertools @@ -57,6 +57,7 @@ class MmapTests(unittest.TestCase): f.write(b'\0'* (PAGESIZE-3) ) f.flush() m = mmap.mmap(f.fileno(), 2 * PAGESIZE) + self.addCleanup(m.close) finally: f.close() @@ -114,31 +115,28 @@ class MmapTests(unittest.TestCase): # Try to seek to negative position... self.assertRaises(ValueError, m.seek, -len(m)-1, 2) + @unittest.skipUnless(hasattr(mmap.mmap, 'resize'), 'requires mmap.resize') + def test_resize(self): + # Create a file to be mmap'ed. + with open(TESTFN, 'bw+') as f: + # Write 2 pages worth of data to the file + f.write(b'\0'* 2 * PAGESIZE) + f.flush() + m = mmap.mmap(f.fileno(), 2 * PAGESIZE) + self.addCleanup(m.close) + # Try resizing map - try: - m.resize(512) - except SystemError: - # resize() not supported - # No messages are printed, since the output of this test suite - # would then be different across platforms. - pass - else: - # resize() is supported - self.assertEqual(len(m), 512) - # Check that we can no longer seek beyond the new size. - self.assertRaises(ValueError, m.seek, 513, 0) + m.resize(512) + self.assertEqual(len(m), 512) + # Check that we can no longer seek beyond the new size. + self.assertRaises(ValueError, m.seek, 513, 0) - # Check that the underlying file is truncated too - # (bug #728515) - f = open(TESTFN, 'rb') - try: - f.seek(0, 2) - self.assertEqual(f.tell(), 512) - finally: - f.close() - self.assertEqual(m.size(), 512) - - m.close() + # Check that the underlying file is truncated too + # (bug #728515) + with open(TESTFN, 'rb') as f: + f.seek(0, 2) + self.assertEqual(f.tell(), 512) + self.assertEqual(m.size(), 512) def test_access_parameter(self): # Test for "access" keyword parameter @@ -183,15 +181,10 @@ class MmapTests(unittest.TestCase): else: self.fail("Able to write to readonly memory map") - # Ensuring that readonly mmap can't be resized - try: - m.resize(2*mapsize) - except SystemError: # resize is not universally supported - pass - except TypeError: - pass - else: - self.fail("Able to resize readonly memory map") + if hasattr(m, 'resize'): + # Ensuring that readonly mmap can't be resized + with self.assertRaises(TypeError): + m.resize(2 * mapsize) with open(TESTFN, "rb") as fp: self.assertEqual(fp.read(), b'a'*mapsize, "Readonly memory map data file was modified") @@ -242,8 +235,9 @@ class MmapTests(unittest.TestCase): with open(TESTFN, "rb") as fp: self.assertEqual(fp.read(), b'c'*mapsize, "Copy-on-write test data file should not be modified.") - # Ensuring copy-on-write maps cannot be resized - self.assertRaises(TypeError, m.resize, 2*mapsize) + if hasattr(m, 'resize'): + # Ensuring copy-on-write maps cannot be resized + self.assertRaises(TypeError, m.resize, 2 * mapsize) m.close() # Ensuring invalid access parameter raises exception @@ -270,62 +264,57 @@ class MmapTests(unittest.TestCase): self.assertRaises(TypeError, m.write_byte, 0) m.close() - @unittest.skipIf(os.name == 'nt', 'trackfd not present on Windows') - def test_trackfd_parameter(self): + @support.subTests('close_original_fd', (True, False)) + def test_trackfd_parameter(self, close_original_fd): size = 64 with open(TESTFN, "wb") as f: f.write(b"a"*size) - for close_original_fd in True, False: - with self.subTest(close_original_fd=close_original_fd): - with open(TESTFN, "r+b") as f: - with mmap.mmap(f.fileno(), size, trackfd=False) as m: - if close_original_fd: - f.close() - self.assertEqual(len(m), size) - with self.assertRaises(OSError) as err_cm: - m.size() - self.assertEqual(err_cm.exception.errno, errno.EBADF) - with self.assertRaises(ValueError): - m.resize(size * 2) - with self.assertRaises(ValueError): - m.resize(size // 2) - self.assertEqual(m.closed, False) + with open(TESTFN, "r+b") as f: + with mmap.mmap(f.fileno(), size, trackfd=False) as m: + if close_original_fd: + f.close() + self.assertEqual(len(m), size) + with self.assertRaises(ValueError): + m.size() + if hasattr(m, 'resize'): + with self.assertRaises(ValueError): + m.resize(size * 2) + with self.assertRaises(ValueError): + m.resize(size // 2) + self.assertIs(m.closed, False) - # Smoke-test other API - m.write_byte(ord('X')) - m[2] = ord('Y') - m.flush() - with open(TESTFN, "rb") as f: - self.assertEqual(f.read(4), b'XaYa') - self.assertEqual(m.tell(), 1) - m.seek(0) - self.assertEqual(m.tell(), 0) - self.assertEqual(m.read_byte(), ord('X')) + # Smoke-test other API + m.write_byte(ord('X')) + m[2] = ord('Y') + m.flush() + with open(TESTFN, "rb") as f: + self.assertEqual(f.read(4), b'XaYa') + self.assertEqual(m.tell(), 1) + m.seek(0) + self.assertEqual(m.tell(), 0) + self.assertEqual(m.read_byte(), ord('X')) - self.assertEqual(m.closed, True) - self.assertEqual(os.stat(TESTFN).st_size, size) + if os.name == 'nt' and not close_original_fd: + self.assertRaises(PermissionError, os.rename, TESTFN, TESTFN+'1') + else: + os.rename(TESTFN, TESTFN+'1') + os.rename(TESTFN+'1', TESTFN) + + self.assertIs(m.closed, True) + self.assertEqual(os.stat(TESTFN).st_size, size) - @unittest.skipIf(os.name == 'nt', 'trackfd not present on Windows') def test_trackfd_neg1(self): size = 64 with mmap.mmap(-1, size, trackfd=False) as m: - with self.assertRaises(OSError): - m.size() with self.assertRaises(ValueError): - m.resize(size // 2) + m.size() + if hasattr(m, 'resize'): + with self.assertRaises(ValueError): + m.resize(size // 2) self.assertEqual(len(m), size) m[0] = ord('a') assert m[0] == ord('a') - @unittest.skipIf(os.name != 'nt', 'trackfd only fails on Windows') - def test_no_trackfd_parameter_on_windows(self): - # 'trackffd' is an invalid keyword argument for this function - size = 64 - with self.assertRaises(TypeError): - mmap.mmap(-1, size, trackfd=True) - with self.assertRaises(TypeError): - mmap.mmap(-1, size, trackfd=False) - def test_bad_file_desc(self): # Try opening a bad file descriptor... self.assertRaises(OSError, mmap.mmap, -2, 4096) @@ -505,6 +494,7 @@ class MmapTests(unittest.TestCase): b = x & 0xff m[x] = b self.assertEqual(m[x], b) + self.assertEqual(m.size(), PAGESIZE) def test_read_all(self): m = mmap.mmap(-1, 16) @@ -614,13 +604,9 @@ class MmapTests(unittest.TestCase): self.assertEqual(m[0:3], b'foo') f.close() - # Try resizing map - try: + if hasattr(m, 'resize'): + # Try resizing map m.resize(512) - except SystemError: - pass - else: - # resize() is supported self.assertEqual(len(m), 512) # Check that we can no longer seek beyond the new size. self.assertRaises(ValueError, m.seek, 513, 0) @@ -812,14 +798,12 @@ class MmapTests(unittest.TestCase): self.assertEqual(mm.write(b"yz"), 2) self.assertEqual(mm.write(b"python"), 6) + @unittest.skipUnless(hasattr(mmap.mmap, 'resize'), 'requires mmap.resize') def test_resize_past_pos(self): m = mmap.mmap(-1, 8192) self.addCleanup(m.close) m.read(5000) - try: - m.resize(4096) - except SystemError: - self.skipTest("resizing not supported") + m.resize(4096) self.assertEqual(m.read(14), b'') self.assertRaises(ValueError, m.read_byte) self.assertRaises(ValueError, m.write_byte, 42) @@ -887,6 +871,10 @@ class MmapTests(unittest.TestCase): size = 2 * PAGESIZE m = mmap.mmap(-1, size) + class Number: + def __index__(self): + return 2 + with self.assertRaisesRegex(ValueError, "madvise start out of bounds"): m.madvise(mmap.MADV_NORMAL, size) with self.assertRaisesRegex(ValueError, "madvise start out of bounds"): @@ -895,41 +883,70 @@ class MmapTests(unittest.TestCase): m.madvise(mmap.MADV_NORMAL, 0, -1) with self.assertRaisesRegex(OverflowError, "madvise length too large"): m.madvise(mmap.MADV_NORMAL, PAGESIZE, sys.maxsize) + with self.assertRaisesRegex( + TypeError, "'str' object cannot be interpreted as an integer"): + m.madvise(mmap.MADV_NORMAL, PAGESIZE, "Not a Number") self.assertEqual(m.madvise(mmap.MADV_NORMAL), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, PAGESIZE), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, PAGESIZE, size), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, 2), None) + self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, Number()), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, size), None) - @unittest.skipUnless(os.name == 'nt', 'requires Windows') - def test_resize_up_when_mapped_to_pagefile(self): + @unittest.skipUnless(hasattr(mmap.mmap, 'resize'), 'requires mmap.resize') + def test_resize_up_anonymous_mapping(self): """If the mmap is backed by the pagefile ensure a resize up can happen and that the original data is still in place """ start_size = PAGESIZE new_size = 2 * start_size - data = bytes(random.getrandbits(8) for _ in range(start_size)) + data = random.randbytes(start_size) - m = mmap.mmap(-1, start_size) - m[:] = data - m.resize(new_size) - self.assertEqual(len(m), new_size) - self.assertEqual(m[:start_size], data[:start_size]) + with mmap.mmap(-1, start_size) as m: + m[:] = data + if sys.platform.startswith(('linux', 'android')): + # Can't expand a shared anonymous mapping on Linux. + # See https://bugzilla.kernel.org/show_bug.cgi?id=8691 + with self.assertRaises(ValueError): + m.resize(new_size) + else: + m.resize(new_size) + self.assertEqual(len(m), new_size) + self.assertEqual(m[:start_size], data) + self.assertEqual(m[start_size:], b'\0' * (new_size - start_size)) - @unittest.skipUnless(os.name == 'nt', 'requires Windows') - def test_resize_down_when_mapped_to_pagefile(self): + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + @unittest.skipUnless(hasattr(mmap.mmap, 'resize'), 'requires mmap.resize') + def test_resize_up_private_anonymous_mapping(self): + start_size = PAGESIZE + new_size = 2 * start_size + data = random.randbytes(start_size) + + with mmap.mmap(-1, start_size, flags=mmap.MAP_PRIVATE) as m: + m[:] = data + m.resize(new_size) + self.assertEqual(len(m), new_size) + self.assertEqual(m[:start_size], data) + self.assertEqual(m[start_size:], b'\0' * (new_size - start_size)) + + @unittest.skipUnless(hasattr(mmap.mmap, 'resize'), 'requires mmap.resize') + def test_resize_down_anonymous_mapping(self): """If the mmap is backed by the pagefile ensure a resize down up can happen and that a truncated form of the original data is still in place """ - start_size = PAGESIZE + start_size = 2 * PAGESIZE new_size = start_size // 2 - data = bytes(random.getrandbits(8) for _ in range(start_size)) + data = random.randbytes(start_size) - m = mmap.mmap(-1, start_size) - m[:] = data - m.resize(new_size) - self.assertEqual(len(m), new_size) - self.assertEqual(m[:new_size], data[:new_size]) + with mmap.mmap(-1, start_size) as m: + m[:] = data + m.resize(new_size) + self.assertEqual(len(m), new_size) + self.assertEqual(m[:], data[:new_size]) + if sys.platform.startswith(('linux', 'android')): + # Can't expand to its original size. + with self.assertRaises(ValueError): + m.resize(start_size) @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_resize_fails_if_mapping_held_elsewhere(self): @@ -1136,6 +1153,18 @@ class MmapTests(unittest.TestCase): self.assertEqual(stdout.strip(), b'') self.assertEqual(stderr.strip(), b'') + def test_flush_parameters(self): + with open(TESTFN, 'wb+') as f: + f.write(b'x' * PAGESIZE * 3) + f.flush() + + m = mmap.mmap(f.fileno(), PAGESIZE * 3) + self.addCleanup(m.close) + + m.flush() + m.flush(PAGESIZE) + m.flush(PAGESIZE, PAGESIZE) + class LargeMmapTests(unittest.TestCase): diff --git a/Lib/test/test_modulefinder.py b/Lib/test/test_modulefinder.py index b64e684f805..703bfbf94d7 100644 --- a/Lib/test/test_modulefinder.py +++ b/Lib/test/test_modulefinder.py @@ -76,6 +76,18 @@ a/c.py from sys import version_info """] +namespace_package_test = [ + "module", + ["a", "module"], + ["a.c", "blahblah"], [], + """\ +module.py + import a + import a.c + import blahblah +a/b.py +"""] + absolute_import_test = [ "a.module", ["a", "a.module", @@ -353,6 +365,9 @@ class ModuleFinderTest(unittest.TestCase): def test_package(self): self._do_test(package_test) + def test_namespace_package(self): + self._do_test(namespace_package_test) + def test_maybe(self): self._do_test(maybe_test) diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 4122f786a9a..83bf510ceea 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -12,10 +12,10 @@ import types import unittest import test.support -from test.support import requires_specialization_ft, script_helper +from test.support import import_helper, requires_specialization_ft, script_helper -_testcapi = test.support.import_helper.import_module("_testcapi") -_testinternalcapi = test.support.import_helper.import_module("_testinternalcapi") +_testcapi = import_helper.import_module("_testcapi") +_testinternalcapi = import_helper.import_module("_testinternalcapi") PAIR = (0,1) @@ -1079,6 +1079,25 @@ class ExceptionMonitoringTest(CheckEvents): self.assertEqual(events, expected) + # gh-140373 + def test_gen_unwind(self): + def gen(): + yield 1 + + def f(): + g = gen() + next(g) + g.close() + + recorders = ( + UnwindRecorder, + ) + events = self.get_events(f, TEST_TOOL, recorders) + expected = [ + ("unwind", GeneratorExit, "gen"), + ] + self.assertEqual(events, expected) + class LineRecorder: event_type = E.LINE diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index b9cd75a3b8a..3a3c60dea13 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -9,7 +9,7 @@ import unittest import warnings from ntpath import ALL_BUT_LAST, ALLOW_MISSING from test import support -from test.support import TestFailed, cpython_only, os_helper +from test.support import os_helper from test.support.os_helper import FakePath from test import test_genericpath from tempfile import TemporaryFile @@ -59,7 +59,7 @@ def tester(fn, wantResult): fn = fn.replace("\\", "\\\\") gotResult = eval(fn) if wantResult != gotResult and _norm(wantResult) != _norm(gotResult): - raise TestFailed("%s should return: %s but returned: %s" \ + raise support.TestFailed("%s should return: %s but returned: %s" \ %(str(fn), str(wantResult), str(gotResult))) # then with bytes @@ -75,7 +75,7 @@ def tester(fn, wantResult): warnings.simplefilter("ignore", DeprecationWarning) gotResult = eval(fn) if _norm(wantResult) != _norm(gotResult): - raise TestFailed("%s should return: %s but returned: %s" \ + raise support.TestFailed("%s should return: %s but returned: %s" \ %(str(fn), str(wantResult), repr(gotResult))) @@ -1133,6 +1133,19 @@ class TestNtpath(NtpathTestCase): check('%spam%bar', '%sbar' % nonascii) check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii) + @support.requires_resource('cpu') + def test_expandvars_large(self): + expandvars = ntpath.expandvars + with os_helper.EnvironmentVarGuard() as env: + env.clear() + env["A"] = "B" + n = 100_000 + self.assertEqual(expandvars('%A%'*n), 'B'*n) + self.assertEqual(expandvars('%A%A'*n), 'BA'*n) + self.assertEqual(expandvars("''"*n + '%%'), "''"*n + '%') + self.assertEqual(expandvars("%%"*n), "%"*n) + self.assertEqual(expandvars("$$"*n), "$"*n) + def test_expanduser(self): tester('ntpath.expanduser("test")', 'test') @@ -1550,7 +1563,7 @@ class TestNtpath(NtpathTestCase): self.assertTrue(os.path.exists(r"\\.\CON")) @unittest.skipIf(sys.platform != 'win32', "Fast paths are only for win32") - @cpython_only + @support.cpython_only def test_fast_paths_in_use(self): # There are fast paths of these functions implemented in posixmodule.c. # Confirm that they are being used, and not the Python fallbacks in diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 30baa090486..4113b79ef5c 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -567,6 +567,14 @@ class TestCallCache(TestBase): with self.assertRaises(RecursionError): test() + def test_dont_specialize_custom_vectorcall(self): + def f(): + raise Exception("no way") + + _testinternalcapi.set_vectorcall_nop(f) + for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + f() + def make_deferred_ref_count_obj(): """Create an object that uses deferred reference counting. @@ -582,7 +590,7 @@ def make_deferred_ref_count_obj(): class TestRacesDoNotCrash(TestBase): # Careful with these. Bigger numbers have a higher chance of catching bugs, # but you can also burn through a *ton* of type/dict/function versions: - ITEMS = 1000 + ITEMS = 1400 LOOPS = 4 WRITERS = 2 @@ -1333,6 +1341,21 @@ class TestSpecializer(TestBase): self.assert_specialized(binary_op_add_int, "BINARY_OP_ADD_INT") self.assert_no_opcode(binary_op_add_int, "BINARY_OP") + def binary_op_int_non_compact(): + for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = 10000000000, 1 + c = a + b + self.assertEqual(c, 10000000001) + c = a - b + self.assertEqual(c, 9999999999) + c = a * b + self.assertEqual(c, 10000000000) + + binary_op_int_non_compact() + self.assert_no_opcode(binary_op_int_non_compact, "BINARY_OP_ADD_INT") + self.assert_no_opcode(binary_op_int_non_compact, "BINARY_OP_SUBTRACT_INT") + self.assert_no_opcode(binary_op_int_non_compact, "BINARY_OP_MULTIPLY_INT") + def binary_op_add_unicode(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): a, b = "foo", "bar" @@ -1849,6 +1872,33 @@ class TestSpecializer(TestBase): self.assert_specialized(for_iter_generator, "FOR_ITER_GEN") self.assert_no_opcode(for_iter_generator, "FOR_ITER") + @cpython_only + @requires_specialization_ft + def test_call_list_append(self): + # gh-141367: only exact lists should use + # CALL_LIST_APPEND instruction after specialization. + + r = range(_testinternalcapi.SPECIALIZATION_THRESHOLD) + + def list_append(l): + for _ in r: + l.append(1) + + list_append([]) + self.assert_specialized(list_append, "CALL_LIST_APPEND") + self.assert_no_opcode(list_append, "CALL_METHOD_DESCRIPTOR_O") + self.assert_no_opcode(list_append, "CALL") + + def my_list_append(l): + for _ in r: + l.append(1) + + class MyList(list): pass + my_list_append(MyList()) + self.assert_specialized(my_list_append, "CALL_METHOD_DESCRIPTOR_O") + self.assert_no_opcode(my_list_append, "CALL_LIST_APPEND") + self.assert_no_opcode(my_list_append, "CALL") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py index e476e472780..fc8ef9520b3 100644 --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -1666,6 +1666,16 @@ class TestTranslations(TestTranslationsBase): self.assertMsgidsEqual(optparse) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(optparse, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == '__main__': # To regenerate translation snapshots if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update': diff --git a/Lib/test/test_os/__init__.py b/Lib/test/test_os/__init__.py new file mode 100644 index 00000000000..bc502ef32d2 --- /dev/null +++ b/Lib/test/test_os/__init__.py @@ -0,0 +1,6 @@ +import os.path +from test.support import load_package_tests + + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_os.py b/Lib/test/test_os/test_os.py similarity index 88% rename from Lib/test/test_os.py rename to Lib/test/test_os/test_os.py index 9827a7f12ea..ddb8a63095b 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -7,7 +7,6 @@ import codecs import contextlib import decimal import errno -import fnmatch import fractions import itertools import locale @@ -31,12 +30,12 @@ import unittest import uuid import warnings from test import support -from test.support import import_helper from test.support import os_helper from test.support import socket_helper from test.support import infinite_recursion from test.support import warnings_helper from platform import win32_is_iot +from .utils import create_file try: import resource @@ -46,10 +45,6 @@ try: import fcntl except ImportError: fcntl = None -try: - import _winapi -except ImportError: - _winapi = None try: import pwd all_users = [u.pw_uid for u in pwd.getpwall()] @@ -93,11 +88,6 @@ def requires_os_func(name): return unittest.skipUnless(hasattr(os, name), 'requires os.%s' % name) -def create_file(filename, content=b'content'): - with open(filename, "xb", 0) as fp: - fp.write(content) - - # bpo-41625: On AIX, splice() only works with a socket, not with a pipe. requires_splice_pipe = unittest.skipIf(sys.platform.startswith("aix"), 'on AIX, splice() only accepts sockets') @@ -174,6 +164,20 @@ class MiscTests(unittest.TestCase): self.assertIsInstance(cwd, bytes) self.assertEqual(os.fsdecode(cwd), os.getcwd()) + def test_type_fqdn(self): + def fqdn(obj): + return (obj.__module__, obj.__qualname__) + + native = os.name + self.assertEqual(fqdn(os.stat_result), ("os", "stat_result")) + self.assertEqual(fqdn(os.times_result), (native, "times_result")) + if hasattr(os, "statvfs_result"): + self.assertEqual(fqdn(os.statvfs_result), ("os", "statvfs_result")) + if hasattr(os, "sched_param"): + self.assertEqual(fqdn(os.sched_param), (native, "sched_param")) + if hasattr(os, "waitid_result"): + self.assertEqual(fqdn(os.waitid_result), (native, "waitid_result")) + # Tests creating TESTFN class FileTests(unittest.TestCase): @@ -640,6 +644,15 @@ class StatAttributeTests(unittest.TestCase): self.addCleanup(os_helper.unlink, self.fname) create_file(self.fname, b"ABC") + def check_timestamp_agreement(self, result, names): + # Make sure that the st_?time and st_?time_ns fields roughly agree + # (they should always agree up to around tens-of-microseconds) + for name in names: + with self.subTest(name=name): + floaty = int(getattr(result, name) * 100_000) + nanosecondy = getattr(result, name + "_ns") // 10_000 + self.assertAlmostEqual(floaty, nanosecondy, delta=2, msg=name) + def check_stat_attributes(self, fname): result = os.stat(fname) @@ -660,21 +673,15 @@ class StatAttributeTests(unittest.TestCase): result[getattr(stat, name)]) self.assertIn(attr, members) - # Make sure that the st_?time and st_?time_ns fields roughly agree - # (they should always agree up to around tens-of-microseconds) - for name in 'st_atime st_mtime st_ctime'.split(): - floaty = int(getattr(result, name) * 100000) - nanosecondy = getattr(result, name + "_ns") // 10000 - self.assertAlmostEqual(floaty, nanosecondy, delta=2) - - # Ensure both birthtime and birthtime_ns roughly agree, if present + time_attributes = ['st_atime', 'st_mtime', 'st_ctime'] try: - floaty = int(result.st_birthtime * 100000) - nanosecondy = result.st_birthtime_ns // 10000 + result.st_birthtime + result.st_birthtime_ns except AttributeError: pass else: - self.assertAlmostEqual(floaty, nanosecondy, delta=2) + time_attributes.append('st_birthtime') + self.check_timestamp_agreement(result, time_attributes) try: result[200] @@ -735,6 +742,160 @@ class StatAttributeTests(unittest.TestCase): unpickled = pickle.loads(p) self.assertEqual(result, unpickled) + def check_statx_attributes(self, filename): + maximal_mask = 0 + for name in dir(os): + if name.startswith('STATX_'): + maximal_mask |= getattr(os, name) + result = os.statx(filename, maximal_mask) + stat_result = os.stat(filename) + + time_attributes = ('stx_atime', 'stx_btime', 'stx_ctime', 'stx_mtime') + # gh-83714: stx_btime can be None on tmpfs even if STATX_BTIME mask + # is used + time_attributes = [name for name in time_attributes + if getattr(result, name) is not None] + self.check_timestamp_agreement(result, time_attributes) + + def getmask(name): + return getattr(os, name, 0) + + requirements = ( + ('stx_atime', os.STATX_ATIME), + ('stx_atime_ns', os.STATX_ATIME), + ('stx_atomic_write_segments_max', getmask('STATX_WRITE_ATOMIC')), + ('stx_atomic_write_unit_max', getmask('STATX_WRITE_ATOMIC')), + ('stx_atomic_write_unit_max_opt', getmask('STATX_WRITE_ATOMIC')), + ('stx_atomic_write_unit_min', getmask('STATX_WRITE_ATOMIC')), + ('stx_attributes', 0), + ('stx_attributes_mask', 0), + ('stx_blksize', 0), + ('stx_blocks', os.STATX_BLOCKS), + ('stx_btime', os.STATX_BTIME), + ('stx_btime_ns', os.STATX_BTIME), + ('stx_ctime', os.STATX_CTIME), + ('stx_ctime_ns', os.STATX_CTIME), + ('stx_dev', 0), + ('stx_dev_major', 0), + ('stx_dev_minor', 0), + ('stx_dio_mem_align', getmask('STATX_DIOALIGN')), + ('stx_dio_offset_align', getmask('STATX_DIOALIGN')), + ('stx_dio_read_offset_align', getmask('STATX_DIO_READ_ALIGN')), + ('stx_gid', os.STATX_GID), + ('stx_ino', os.STATX_INO), + ('stx_mask', 0), + ('stx_mnt_id', getmask('STATX_MNT_ID')), + ('stx_mode', os.STATX_TYPE | os.STATX_MODE), + ('stx_mtime', os.STATX_MTIME), + ('stx_mtime_ns', os.STATX_MTIME), + ('stx_nlink', os.STATX_NLINK), + ('stx_rdev', 0), + ('stx_rdev_major', 0), + ('stx_rdev_minor', 0), + ('stx_size', os.STATX_SIZE), + ('stx_subvol', getmask('STATX_SUBVOL')), + ('stx_uid', os.STATX_UID), + ) + optional_members = { + 'stx_atomic_write_segments_max', + 'stx_atomic_write_unit_max', + 'stx_atomic_write_unit_max_opt', + 'stx_atomic_write_unit_min', + 'stx_dio_mem_align', + 'stx_dio_offset_align', + 'stx_dio_read_offset_align', + 'stx_mnt_id', + 'stx_subvol', + } + float_type = { + 'stx_atime', + 'stx_btime', + 'stx_ctime', + 'stx_mtime', + } + + members = set(name for name in dir(result) + if name.startswith('stx_')) + tested = set(name for name, mask in requirements) + if members - tested: + raise ValueError(f"statx members not tested: {members - tested}") + + for name, mask in requirements: + with self.subTest(name=name): + try: + x = getattr(result, name) + except AttributeError: + if name in optional_members: + continue + else: + raise + + if not(result.stx_mask & mask == mask): + self.assertIsNone(x) + continue + + if name in float_type: + self.assertIsInstance(x, float) + else: + self.assertIsInstance(x, int) + + # Compare with stat_result + try: + b = getattr(stat_result, "st_" + name[4:]) + except AttributeError: + pass + else: + self.assertEqual(type(x), type(b)) + if isinstance(x, float): + self.assertAlmostEqual(x, b) + else: + self.assertEqual(x, b) + + self.assertEqual(result.stx_rdev_major, os.major(result.stx_rdev)) + self.assertEqual(result.stx_rdev_minor, os.minor(result.stx_rdev)) + self.assertEqual(result.stx_dev_major, os.major(result.stx_dev)) + self.assertEqual(result.stx_dev_minor, os.minor(result.stx_dev)) + + self.assertEqual(result.stx_attributes & result.stx_attributes_mask, + result.stx_attributes) + + @unittest.skipUnless(hasattr(os, 'statx'), 'test needs os.statx()') + def test_statx_attributes(self): + self.check_statx_attributes(self.fname) + + @unittest.skipUnless(hasattr(os, 'statx'), 'test needs os.statx()') + def test_statx_attributes_bytes(self): + try: + fname = self.fname.encode(sys.getfilesystemencoding()) + except UnicodeEncodeError: + self.skipTest("cannot encode %a for the filesystem" % self.fname) + self.check_statx_attributes(fname) + + @unittest.skipUnless(hasattr(os, 'statx'), 'test needs os.statx()') + def test_statx_attributes_pathlike(self): + self.check_statx_attributes(FakePath(self.fname)) + + @unittest.skipUnless(hasattr(os, 'statx'), 'test needs os.statx()') + def test_statx_result(self): + result = os.statx(self.fname, os.STATX_BASIC_STATS) + + # Check that attributes are read-only + members = [name for name in dir(result) + if name.startswith('stx_')] + for name in members: + try: + setattr(result, name, 1) + except AttributeError: + pass + else: + self.fail("No exception raised") + + # statx_result is not a tuple or tuple-like object. + with self.assertRaisesRegex(TypeError, 'not subscriptable'): + result[0] + with self.assertRaisesRegex(TypeError, 'cannot unpack'): + _, _ = result + @unittest.skipUnless(hasattr(os, 'statvfs'), 'test needs os.statvfs()') def test_statvfs_attributes(self): result = os.statvfs(self.fname) @@ -948,6 +1109,20 @@ class UtimeTests(unittest.TestCase): # issue, os.utime() rounds towards minus infinity. return (ns * 1e-9) + 0.5e-9 + @staticmethod + def ns_to_sec_decimal(ns): + # Convert a number of nanosecond (int) to a number of seconds (Decimal). + # Round towards infinity by adding 0.5 nanosecond to avoid rounding + # issue, os.utime() rounds towards minus infinity. + return decimal.Decimal('1e-9') * ns + decimal.Decimal('0.5e-9') + + @staticmethod + def ns_to_sec_fraction(ns): + # Convert a number of nanosecond (int) to a number of seconds (Fraction). + # Round towards infinity by adding 0.5 nanosecond to avoid rounding + # issue, os.utime() rounds towards minus infinity. + return fractions.Fraction(ns, 10**9) + fractions.Fraction(1, 2*10**9) + def test_utime_by_indexed(self): # pass times as floating-point seconds as the second indexed parameter def set_time(filename, ns): @@ -968,6 +1143,24 @@ class UtimeTests(unittest.TestCase): os.utime(filename, times=(atime, mtime)) self._test_utime(set_time) + def test_utime_decimal(self): + # pass times as Decimal seconds + def set_time(filename, ns): + atime_ns, mtime_ns = ns + atime = self.ns_to_sec_decimal(atime_ns) + mtime = self.ns_to_sec_decimal(mtime_ns) + os.utime(filename, (atime, mtime)) + self._test_utime(set_time) + + def test_utime_fraction(self): + # pass times as Fraction seconds + def set_time(filename, ns): + atime_ns, mtime_ns = ns + atime = self.ns_to_sec_fraction(atime_ns) + mtime = self.ns_to_sec_fraction(mtime_ns) + os.utime(filename, (atime, mtime)) + self._test_utime(set_time) + @unittest.skipUnless(os.utime in os.supports_follow_symlinks, "follow_symlinks support for utime required " "for this test.") @@ -1064,9 +1257,15 @@ class UtimeTests(unittest.TestCase): if self.get_file_system(self.dirname) != "NTFS": self.skipTest("requires NTFS") - large = 5000000000 # some day in 2128 - os.utime(self.fname, (large, large)) - self.assertEqual(os.stat(self.fname).st_mtime, large) + times = ( + 5000000000, # some day in 2128 + # boundaries of the fast path cutoff in posixmodule.c:fill_time + -9223372037, -9223372036, 9223372035, 9223372036, + ) + for large in times: + with self.subTest(large=large): + os.utime(self.fname, (large, large)) + self.assertEqual(os.stat(self.fname).st_mtime, large) def test_utime_invalid_arguments(self): # seconds and nanoseconds parameters are mutually exclusive @@ -1466,6 +1665,14 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol): self.assertNotIn(b'test_env', os.environb) self.assertNotIn('test_env', os.environ) + def test_clearenv(self): + os.environ['REMOVEME'] = '1' + os.environ.clear() + self.assertEqual(os.environ, {}) + + self.assertRaises(TypeError, os.environ.clear, None) + + class WalkTests(unittest.TestCase): """Tests for os.walk().""" is_fwalk = False @@ -2428,42 +2635,6 @@ class ExecTests(unittest.TestCase): self.fail('No OSError raised') -@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") -class Win32ErrorTests(unittest.TestCase): - def setUp(self): - try: - os.stat(os_helper.TESTFN) - except FileNotFoundError: - exists = False - except OSError as exc: - exists = True - self.fail("file %s must not exist; os.stat failed with %s" - % (os_helper.TESTFN, exc)) - else: - self.fail("file %s must not exist" % os_helper.TESTFN) - - def test_rename(self): - self.assertRaises(OSError, os.rename, os_helper.TESTFN, os_helper.TESTFN+".bak") - - def test_remove(self): - self.assertRaises(OSError, os.remove, os_helper.TESTFN) - - def test_chdir(self): - self.assertRaises(OSError, os.chdir, os_helper.TESTFN) - - def test_mkdir(self): - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - - with open(os_helper.TESTFN, "x") as f: - self.assertRaises(OSError, os.mkdir, os_helper.TESTFN) - - def test_utime(self): - self.assertRaises(OSError, os.utime, os_helper.TESTFN, None) - - def test_chmod(self): - self.assertRaises(OSError, os.chmod, os_helper.TESTFN, 0) - - @unittest.skipIf(support.is_wasi, "Cannot create invalid FD on WASI.") class TestInvalidFD(unittest.TestCase): singles = ["fchdir", "dup", "fstat", "fstatvfs", "tcgetpgrp", "ttyname"] @@ -2798,224 +2969,6 @@ class Pep383Tests(unittest.TestCase): for fn in self.unicodefn: os.stat(os.path.join(self.dir, fn)) -@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") -class Win32KillTests(unittest.TestCase): - def _kill(self, sig): - # Start sys.executable as a subprocess and communicate from the - # subprocess to the parent that the interpreter is ready. When it - # becomes ready, send *sig* via os.kill to the subprocess and check - # that the return code is equal to *sig*. - import ctypes - from ctypes import wintypes - import msvcrt - - # Since we can't access the contents of the process' stdout until the - # process has exited, use PeekNamedPipe to see what's inside stdout - # without waiting. This is done so we can tell that the interpreter - # is started and running at a point where it could handle a signal. - PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe - PeekNamedPipe.restype = wintypes.BOOL - PeekNamedPipe.argtypes = (wintypes.HANDLE, # Pipe handle - ctypes.POINTER(ctypes.c_char), # stdout buf - wintypes.DWORD, # Buffer size - ctypes.POINTER(wintypes.DWORD), # bytes read - ctypes.POINTER(wintypes.DWORD), # bytes avail - ctypes.POINTER(wintypes.DWORD)) # bytes left - msg = "running" - proc = subprocess.Popen([sys.executable, "-c", - "import sys;" - "sys.stdout.write('{}');" - "sys.stdout.flush();" - "input()".format(msg)], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE) - self.addCleanup(proc.stdout.close) - self.addCleanup(proc.stderr.close) - self.addCleanup(proc.stdin.close) - - count, max = 0, 100 - while count < max and proc.poll() is None: - # Create a string buffer to store the result of stdout from the pipe - buf = ctypes.create_string_buffer(len(msg)) - # Obtain the text currently in proc.stdout - # Bytes read/avail/left are left as NULL and unused - rslt = PeekNamedPipe(msvcrt.get_osfhandle(proc.stdout.fileno()), - buf, ctypes.sizeof(buf), None, None, None) - self.assertNotEqual(rslt, 0, "PeekNamedPipe failed") - if buf.value: - self.assertEqual(msg, buf.value.decode()) - break - time.sleep(0.1) - count += 1 - else: - self.fail("Did not receive communication from the subprocess") - - os.kill(proc.pid, sig) - self.assertEqual(proc.wait(), sig) - - def test_kill_sigterm(self): - # SIGTERM doesn't mean anything special, but make sure it works - self._kill(signal.SIGTERM) - - def test_kill_int(self): - # os.kill on Windows can take an int which gets set as the exit code - self._kill(100) - - @unittest.skipIf(mmap is None, "requires mmap") - def _kill_with_event(self, event, name): - tagname = "test_os_%s" % uuid.uuid1() - m = mmap.mmap(-1, 1, tagname) - m[0] = 0 - - # Run a script which has console control handling enabled. - script = os.path.join(os.path.dirname(__file__), - "win_console_handler.py") - cmd = [sys.executable, script, tagname] - proc = subprocess.Popen(cmd, - creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) - - with proc: - # Let the interpreter startup before we send signals. See #3137. - for _ in support.sleeping_retry(support.SHORT_TIMEOUT): - if proc.poll() is None: - break - else: - # Forcefully kill the process if we weren't able to signal it. - proc.kill() - self.fail("Subprocess didn't finish initialization") - - os.kill(proc.pid, event) - - try: - # proc.send_signal(event) could also be done here. - # Allow time for the signal to be passed and the process to exit. - proc.wait(timeout=support.SHORT_TIMEOUT) - except subprocess.TimeoutExpired: - # Forcefully kill the process if we weren't able to signal it. - proc.kill() - self.fail("subprocess did not stop on {}".format(name)) - - @unittest.skip("subprocesses aren't inheriting Ctrl+C property") - @support.requires_subprocess() - def test_CTRL_C_EVENT(self): - from ctypes import wintypes - import ctypes - - # Make a NULL value by creating a pointer with no argument. - NULL = ctypes.POINTER(ctypes.c_int)() - SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler - SetConsoleCtrlHandler.argtypes = (ctypes.POINTER(ctypes.c_int), - wintypes.BOOL) - SetConsoleCtrlHandler.restype = wintypes.BOOL - - # Calling this with NULL and FALSE causes the calling process to - # handle Ctrl+C, rather than ignore it. This property is inherited - # by subprocesses. - SetConsoleCtrlHandler(NULL, 0) - - self._kill_with_event(signal.CTRL_C_EVENT, "CTRL_C_EVENT") - - @support.requires_subprocess() - def test_CTRL_BREAK_EVENT(self): - self._kill_with_event(signal.CTRL_BREAK_EVENT, "CTRL_BREAK_EVENT") - - -@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") -class Win32ListdirTests(unittest.TestCase): - """Test listdir on Windows.""" - - def setUp(self): - self.created_paths = [] - for i in range(2): - dir_name = 'SUB%d' % i - dir_path = os.path.join(os_helper.TESTFN, dir_name) - file_name = 'FILE%d' % i - file_path = os.path.join(os_helper.TESTFN, file_name) - os.makedirs(dir_path) - with open(file_path, 'w', encoding='utf-8') as f: - f.write("I'm %s and proud of it. Blame test_os.\n" % file_path) - self.created_paths.extend([dir_name, file_name]) - self.created_paths.sort() - - def tearDown(self): - shutil.rmtree(os_helper.TESTFN) - - def test_listdir_no_extended_path(self): - """Test when the path is not an "extended" path.""" - # unicode - self.assertEqual( - sorted(os.listdir(os_helper.TESTFN)), - self.created_paths) - - # bytes - self.assertEqual( - sorted(os.listdir(os.fsencode(os_helper.TESTFN))), - [os.fsencode(path) for path in self.created_paths]) - - def test_listdir_extended_path(self): - """Test when the path starts with '\\\\?\\'.""" - # See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath - # unicode - path = '\\\\?\\' + os.path.abspath(os_helper.TESTFN) - self.assertEqual( - sorted(os.listdir(path)), - self.created_paths) - - # bytes - path = b'\\\\?\\' + os.fsencode(os.path.abspath(os_helper.TESTFN)) - self.assertEqual( - sorted(os.listdir(path)), - [os.fsencode(path) for path in self.created_paths]) - - -@unittest.skipUnless(os.name == "nt", "NT specific tests") -class Win32ListdriveTests(unittest.TestCase): - """Test listdrive, listmounts and listvolume on Windows.""" - - def setUp(self): - # Get drives and volumes from fsutil - out = subprocess.check_output( - ["fsutil.exe", "volume", "list"], - cwd=os.path.join(os.getenv("SystemRoot", "\\Windows"), "System32"), - encoding="mbcs", - errors="ignore", - ) - lines = out.splitlines() - self.known_volumes = {l for l in lines if l.startswith('\\\\?\\')} - self.known_drives = {l for l in lines if l[1:] == ':\\'} - self.known_mounts = {l for l in lines if l[1:3] == ':\\'} - - def test_listdrives(self): - drives = os.listdrives() - self.assertIsInstance(drives, list) - self.assertSetEqual( - self.known_drives, - self.known_drives & set(drives), - ) - - def test_listvolumes(self): - volumes = os.listvolumes() - self.assertIsInstance(volumes, list) - self.assertSetEqual( - self.known_volumes, - self.known_volumes & set(volumes), - ) - - def test_listmounts(self): - for volume in os.listvolumes(): - try: - mounts = os.listmounts(volume) - except OSError as ex: - if support.verbose: - print("Skipping", volume, "because of", ex) - else: - self.assertIsInstance(mounts, list) - self.assertSetEqual( - set(mounts), - self.known_mounts & set(mounts), - ) - @unittest.skipUnless(hasattr(os, 'readlink'), 'needs os.readlink()') class ReadlinkTests(unittest.TestCase): @@ -3078,370 +3031,6 @@ class ReadlinkTests(unittest.TestCase): self.assertIsInstance(path, bytes) -@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") -@os_helper.skip_unless_symlink -class Win32SymlinkTests(unittest.TestCase): - filelink = 'filelinktest' - filelink_target = os.path.abspath(__file__) - dirlink = 'dirlinktest' - dirlink_target = os.path.dirname(filelink_target) - missing_link = 'missing link' - - def setUp(self): - assert os.path.exists(self.dirlink_target) - assert os.path.exists(self.filelink_target) - assert not os.path.exists(self.dirlink) - assert not os.path.exists(self.filelink) - assert not os.path.exists(self.missing_link) - - def tearDown(self): - if os.path.exists(self.filelink): - os.remove(self.filelink) - if os.path.exists(self.dirlink): - os.rmdir(self.dirlink) - if os.path.lexists(self.missing_link): - os.remove(self.missing_link) - - def test_directory_link(self): - os.symlink(self.dirlink_target, self.dirlink) - self.assertTrue(os.path.exists(self.dirlink)) - self.assertTrue(os.path.isdir(self.dirlink)) - self.assertTrue(os.path.islink(self.dirlink)) - self.check_stat(self.dirlink, self.dirlink_target) - - def test_file_link(self): - os.symlink(self.filelink_target, self.filelink) - self.assertTrue(os.path.exists(self.filelink)) - self.assertTrue(os.path.isfile(self.filelink)) - self.assertTrue(os.path.islink(self.filelink)) - self.check_stat(self.filelink, self.filelink_target) - - def _create_missing_dir_link(self): - 'Create a "directory" link to a non-existent target' - linkname = self.missing_link - if os.path.lexists(linkname): - os.remove(linkname) - target = r'c:\\target does not exist.29r3c740' - assert not os.path.exists(target) - target_is_dir = True - os.symlink(target, linkname, target_is_dir) - - def test_remove_directory_link_to_missing_target(self): - self._create_missing_dir_link() - # For compatibility with Unix, os.remove will check the - # directory status and call RemoveDirectory if the symlink - # was created with target_is_dir==True. - os.remove(self.missing_link) - - def test_isdir_on_directory_link_to_missing_target(self): - self._create_missing_dir_link() - self.assertFalse(os.path.isdir(self.missing_link)) - - def test_rmdir_on_directory_link_to_missing_target(self): - self._create_missing_dir_link() - os.rmdir(self.missing_link) - - def check_stat(self, link, target): - self.assertEqual(os.stat(link), os.stat(target)) - self.assertNotEqual(os.lstat(link), os.stat(link)) - - bytes_link = os.fsencode(link) - self.assertEqual(os.stat(bytes_link), os.stat(target)) - self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link)) - - def test_12084(self): - level1 = os.path.abspath(os_helper.TESTFN) - level2 = os.path.join(level1, "level2") - level3 = os.path.join(level2, "level3") - self.addCleanup(os_helper.rmtree, level1) - - os.mkdir(level1) - os.mkdir(level2) - os.mkdir(level3) - - file1 = os.path.abspath(os.path.join(level1, "file1")) - create_file(file1) - - orig_dir = os.getcwd() - try: - os.chdir(level2) - link = os.path.join(level2, "link") - os.symlink(os.path.relpath(file1), "link") - self.assertIn("link", os.listdir(os.getcwd())) - - # Check os.stat calls from the same dir as the link - self.assertEqual(os.stat(file1), os.stat("link")) - - # Check os.stat calls from a dir below the link - os.chdir(level1) - self.assertEqual(os.stat(file1), - os.stat(os.path.relpath(link))) - - # Check os.stat calls from a dir above the link - os.chdir(level3) - self.assertEqual(os.stat(file1), - os.stat(os.path.relpath(link))) - finally: - os.chdir(orig_dir) - - @unittest.skipUnless(os.path.lexists(r'C:\Users\All Users') - and os.path.exists(r'C:\ProgramData'), - 'Test directories not found') - def test_29248(self): - # os.symlink() calls CreateSymbolicLink, which creates - # the reparse data buffer with the print name stored - # first, so the offset is always 0. CreateSymbolicLink - # stores the "PrintName" DOS path (e.g. "C:\") first, - # with an offset of 0, followed by the "SubstituteName" - # NT path (e.g. "\??\C:\"). The "All Users" link, on - # the other hand, seems to have been created manually - # with an inverted order. - target = os.readlink(r'C:\Users\All Users') - self.assertTrue(os.path.samefile(target, r'C:\ProgramData')) - - def test_buffer_overflow(self): - # Older versions would have a buffer overflow when detecting - # whether a link source was a directory. This test ensures we - # no longer crash, but does not otherwise validate the behavior - segment = 'X' * 27 - path = os.path.join(*[segment] * 10) - test_cases = [ - # overflow with absolute src - ('\\' + path, segment), - # overflow dest with relative src - (segment, path), - # overflow when joining src - (path[:180], path[:180]), - ] - for src, dest in test_cases: - try: - os.symlink(src, dest) - except FileNotFoundError: - pass - else: - try: - os.remove(dest) - except OSError: - pass - # Also test with bytes, since that is a separate code path. - try: - os.symlink(os.fsencode(src), os.fsencode(dest)) - except FileNotFoundError: - pass - else: - try: - os.remove(dest) - except OSError: - pass - - def test_appexeclink(self): - root = os.path.expandvars(r'%LOCALAPPDATA%\Microsoft\WindowsApps') - if not os.path.isdir(root): - self.skipTest("test requires a WindowsApps directory") - - aliases = [os.path.join(root, a) - for a in fnmatch.filter(os.listdir(root), '*.exe')] - - for alias in aliases: - if support.verbose: - print() - print("Testing with", alias) - st = os.lstat(alias) - self.assertEqual(st, os.stat(alias)) - self.assertFalse(stat.S_ISLNK(st.st_mode)) - self.assertEqual(st.st_reparse_tag, stat.IO_REPARSE_TAG_APPEXECLINK) - self.assertTrue(os.path.isfile(alias)) - # testing the first one we see is sufficient - break - else: - self.skipTest("test requires an app execution alias") - -@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") -class Win32JunctionTests(unittest.TestCase): - junction = 'junctiontest' - junction_target = os.path.dirname(os.path.abspath(__file__)) - - def setUp(self): - assert os.path.exists(self.junction_target) - assert not os.path.lexists(self.junction) - - def tearDown(self): - if os.path.lexists(self.junction): - os.unlink(self.junction) - - def test_create_junction(self): - _winapi.CreateJunction(self.junction_target, self.junction) - self.assertTrue(os.path.lexists(self.junction)) - self.assertTrue(os.path.exists(self.junction)) - self.assertTrue(os.path.isdir(self.junction)) - self.assertNotEqual(os.stat(self.junction), os.lstat(self.junction)) - self.assertEqual(os.stat(self.junction), os.stat(self.junction_target)) - - # bpo-37834: Junctions are not recognized as links. - self.assertFalse(os.path.islink(self.junction)) - self.assertEqual(os.path.normcase("\\\\?\\" + self.junction_target), - os.path.normcase(os.readlink(self.junction))) - - def test_unlink_removes_junction(self): - _winapi.CreateJunction(self.junction_target, self.junction) - self.assertTrue(os.path.exists(self.junction)) - self.assertTrue(os.path.lexists(self.junction)) - - os.unlink(self.junction) - self.assertFalse(os.path.exists(self.junction)) - -@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") -class Win32NtTests(unittest.TestCase): - def test_getfinalpathname_handles(self): - nt = import_helper.import_module('nt') - ctypes = import_helper.import_module('ctypes') - # Ruff false positive -- it thinks we're redefining `ctypes` here - import ctypes.wintypes # noqa: F811 - - kernel = ctypes.WinDLL('Kernel32.dll', use_last_error=True) - kernel.GetCurrentProcess.restype = ctypes.wintypes.HANDLE - - kernel.GetProcessHandleCount.restype = ctypes.wintypes.BOOL - kernel.GetProcessHandleCount.argtypes = (ctypes.wintypes.HANDLE, - ctypes.wintypes.LPDWORD) - - # This is a pseudo-handle that doesn't need to be closed - hproc = kernel.GetCurrentProcess() - - handle_count = ctypes.wintypes.DWORD() - ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count)) - self.assertEqual(1, ok) - - before_count = handle_count.value - - # The first two test the error path, __file__ tests the success path - filenames = [ - r'\\?\C:', - r'\\?\NUL', - r'\\?\CONIN', - __file__, - ] - - for _ in range(10): - for name in filenames: - try: - nt._getfinalpathname(name) - except Exception: - # Failure is expected - pass - try: - os.stat(name) - except Exception: - pass - - ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count)) - self.assertEqual(1, ok) - - handle_delta = handle_count.value - before_count - - self.assertEqual(0, handle_delta) - - @support.requires_subprocess() - def test_stat_unlink_race(self): - # bpo-46785: the implementation of os.stat() falls back to reading - # the parent directory if CreateFileW() fails with a permission - # error. If reading the parent directory fails because the file or - # directory are subsequently unlinked, or because the volume or - # share are no longer available, then the original permission error - # should not be restored. - filename = os_helper.TESTFN - self.addCleanup(os_helper.unlink, filename) - deadline = time.time() + 5 - command = textwrap.dedent("""\ - import os - import sys - import time - - filename = sys.argv[1] - deadline = float(sys.argv[2]) - - while time.time() < deadline: - try: - with open(filename, "w") as f: - pass - except OSError: - pass - try: - os.remove(filename) - except OSError: - pass - """) - - with subprocess.Popen([sys.executable, '-c', command, filename, str(deadline)]) as proc: - while time.time() < deadline: - try: - os.stat(filename) - except FileNotFoundError as e: - assert e.winerror == 2 # ERROR_FILE_NOT_FOUND - try: - proc.wait(1) - except subprocess.TimeoutExpired: - proc.terminate() - - @support.requires_subprocess() - def test_stat_inaccessible_file(self): - filename = os_helper.TESTFN - ICACLS = os.path.expandvars(r"%SystemRoot%\System32\icacls.exe") - - with open(filename, "wb") as f: - f.write(b'Test data') - - stat1 = os.stat(filename) - - try: - # Remove all permissions from the file - subprocess.check_output([ICACLS, filename, "/inheritance:r"], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as ex: - if support.verbose: - print(ICACLS, filename, "/inheritance:r", "failed.") - print(ex.stdout.decode("oem", "replace").rstrip()) - try: - os.unlink(filename) - except OSError: - pass - self.skipTest("Unable to create inaccessible file") - - def cleanup(): - # Give delete permission to the owner (us) - subprocess.check_output([ICACLS, filename, "/grant", "*WD:(D)"], - stderr=subprocess.STDOUT) - os.unlink(filename) - - self.addCleanup(cleanup) - - if support.verbose: - print("File:", filename) - print("stat with access:", stat1) - - # First test - we shouldn't raise here, because we still have access to - # the directory and can extract enough information from its metadata. - stat2 = os.stat(filename) - - if support.verbose: - print(" without access:", stat2) - - # We may not get st_dev/st_ino, so ensure those are 0 or match - self.assertIn(stat2.st_dev, (0, stat1.st_dev)) - self.assertIn(stat2.st_ino, (0, stat1.st_ino)) - - # st_mode and st_size should match (for a normal file, at least) - self.assertEqual(stat1.st_mode, stat2.st_mode) - self.assertEqual(stat1.st_size, stat2.st_size) - - # st_ctime and st_mtime should be the same - self.assertEqual(stat1.st_ctime, stat2.st_ctime) - self.assertEqual(stat1.st_mtime, stat2.st_mtime) - - # st_atime should be the same or later - self.assertGreaterEqual(stat1.st_atime, stat2.st_atime) - - @os_helper.skip_unless_symlink class NonLocalSymlinkTests(unittest.TestCase): @@ -3787,13 +3376,17 @@ class SpawnTests(unittest.TestCase): self._test_invalid_env(os.spawnvpe) -# The introduction of this TestCase caused at least two different errors on -# *nix buildbots. Temporarily skip this to let the buildbots move along. -@unittest.skip("Skip due to platform/environment differences on *NIX buildbots") @unittest.skipUnless(hasattr(os, 'getlogin'), "test needs os.getlogin") class LoginTests(unittest.TestCase): def test_getlogin(self): - user_name = os.getlogin() + try: + user_name = os.getlogin() + except OSError as exc: + # See https://man7.org/linux/man-pages/man3/getlogin.3.html#ERRORS. + if exc.errno in (errno.ENXIO, errno.ENOENT, errno.ENOTTY): + self.skipTest(str(exc)) + else: + raise self.assertNotEqual(len(user_name), 0) @@ -3957,6 +3550,11 @@ class TestSendfile(unittest.IsolatedAsyncioTestCase): await self.async_sendfile(self.sockno, self.fileno, -1, 4096) self.assertEqual(cm.exception.errno, errno.EINVAL) + async def test_invalid_count(self): + with self.assertRaises(ValueError, msg="count cannot be negative"): + await self.sendfile_wrapper(self.sockno, self.fileno, offset=0, + count=-1) + async def test_keywords(self): # Keyword arguments should be supported await self.async_sendfile(out_fd=self.sockno, in_fd=self.fileno, @@ -4665,6 +4263,7 @@ class OSErrorTests(unittest.TestCase): (self.filenames, os.listdir,), (self.filenames, os.rename, "dst"), (self.filenames, os.replace, "dst"), + (self.filenames, os.utime, None), ] if os_helper.can_chmod(): funcs.append((self.filenames, os.chmod, 0o777)) @@ -4705,6 +4304,19 @@ class OSErrorTests(unittest.TestCase): else: self.fail(f"No exception thrown by {func}") + def test_mkdir(self): + filename = os_helper.TESTFN + subdir = os.path.join(filename, 'subdir') + self.assertRaises(FileNotFoundError, os.mkdir, subdir) + + self.addCleanup(os_helper.unlink, filename) + create_file(filename) + self.assertRaises(FileExistsError, os.mkdir, filename) + + self.assertRaises((NotADirectoryError, FileNotFoundError), + os.mkdir, subdir) + + class CPUCountTests(unittest.TestCase): def check_cpu_count(self, cpus): if cpus is None: diff --git a/Lib/test/test_posix.py b/Lib/test/test_os/test_posix.py similarity index 95% rename from Lib/test/test_posix.py rename to Lib/test/test_os/test_posix.py index 628920e34b5..37da293a441 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -668,22 +668,65 @@ class PosixTester(unittest.TestCase): finally: fp.close() - def test_stat(self): - self.assertTrue(posix.stat(os_helper.TESTFN)) - self.assertTrue(posix.stat(os.fsencode(os_helper.TESTFN))) + def check_statlike_path(self, func): + self.assertTrue(func(os_helper.TESTFN)) + self.assertTrue(func(os.fsencode(os_helper.TESTFN))) + self.assertTrue(func(os_helper.FakePath(os_helper.TESTFN))) self.assertRaisesRegex(TypeError, 'should be string, bytes, os.PathLike or integer, not', - posix.stat, bytearray(os.fsencode(os_helper.TESTFN))) + func, bytearray(os.fsencode(os_helper.TESTFN))) self.assertRaisesRegex(TypeError, 'should be string, bytes, os.PathLike or integer, not', - posix.stat, None) + func, None) self.assertRaisesRegex(TypeError, 'should be string, bytes, os.PathLike or integer, not', - posix.stat, list(os_helper.TESTFN)) + func, list(os_helper.TESTFN)) self.assertRaisesRegex(TypeError, 'should be string, bytes, os.PathLike or integer, not', - posix.stat, list(os.fsencode(os_helper.TESTFN))) + func, list(os.fsencode(os_helper.TESTFN))) + + def test_stat(self): + self.check_statlike_path(posix.stat) + + @unittest.skipUnless(hasattr(posix, 'statx'), 'test needs posix.statx()') + def test_statx(self): + def func(path, **kwargs): + return posix.statx(path, posix.STATX_BASIC_STATS, **kwargs) + self.check_statlike_path(func) + + @unittest.skipUnless(hasattr(posix, 'statx'), 'test needs posix.statx()') + def test_statx_flags(self): + # glibc's fallback implementation of statx via the stat family fails + # with EINVAL on the (nonzero) sync flags. If you see this failure, + # update your kernel and/or seccomp syscall filter. + valid_flag_names = ('AT_NO_AUTOMOUNT', 'AT_STATX_SYNC_AS_STAT', + 'AT_STATX_FORCE_SYNC', 'AT_STATX_DONT_SYNC') + for flag_name in valid_flag_names: + flag = getattr(posix, flag_name) + with self.subTest(msg=flag_name, flags=flag): + posix.statx(os_helper.TESTFN, posix.STATX_BASIC_STATS, + flags=flag) + + # These flags are not exposed to Python because their functionality is + # implemented via kwargs instead. + kwarg_equivalent_flags = ( + (0x0100, 'AT_SYMLINK_NOFOLLOW', 'follow_symlinks'), + (0x0400, 'AT_SYMLINK_FOLLOW', 'follow_symlinks'), + (0x1000, 'AT_EMPTY_PATH', 'dir_fd'), + ) + for flag, flag_name, kwarg_name in kwarg_equivalent_flags: + with self.subTest(msg=flag_name, flags=flag): + with self.assertRaisesRegex(ValueError, kwarg_name): + posix.statx(os_helper.TESTFN, posix.STATX_BASIC_STATS, + flags=flag) + + with self.subTest(msg="AT_STATX_FORCE_SYNC | AT_STATX_DONT_SYNC"): + with self.assertRaises(OSError) as ctx: + flags = posix.AT_STATX_FORCE_SYNC | posix.AT_STATX_DONT_SYNC + posix.statx(os_helper.TESTFN, posix.STATX_BASIC_STATS, + flags=flags) + self.assertEqual(ctx.exception.errno, errno.EINVAL) @unittest.skipUnless(hasattr(posix, 'mkfifo'), "don't have mkfifo()") def test_mkfifo(self): @@ -757,12 +800,30 @@ class PosixTester(unittest.TestCase): self.assertRaises((ValueError, OverflowError), posix.makedev, x, minor) self.assertRaises((ValueError, OverflowError), posix.makedev, major, x) - if sys.platform == 'linux': - NODEV = -1 + # The following tests are needed to test functions accepting or + # returning the special value NODEV (if it is defined). major(), minor() + # and makefile() are the only easily reproducible examples, but that + # behavior is platform specific -- on some platforms their code has + # a special case for NODEV, on others this is just an implementation + # artifact. + if (hasattr(posix, 'NODEV') and + sys.platform.startswith(('linux', 'macos', 'freebsd', 'dragonfly', + 'sunos'))): + NODEV = posix.NODEV self.assertEqual(posix.major(NODEV), NODEV) self.assertEqual(posix.minor(NODEV), NODEV) self.assertEqual(posix.makedev(NODEV, NODEV), NODEV) + def test_nodev(self): + # NODEV is not a part of Posix, but is defined on many systems. + if (not hasattr(posix, 'NODEV') + and (not sys.platform.startswith(('linux', 'macos', 'freebsd', + 'dragonfly', 'netbsd', 'openbsd', + 'sunos')) + or support.linked_to_musl())): + self.skipTest('not defined on this platform') + self.assertHasAttr(posix, 'NODEV') + def _test_all_chown_common(self, chown_func, first_param, stat_func): """Common code for chown, fchown and lchown tests.""" def check_stat(uid, gid): @@ -1366,6 +1427,14 @@ class PosixTester(unittest.TestCase): self.assertNotEqual(newparam, param) self.assertEqual(newparam.sched_priority, 0) + @requires_sched + def test_bug_140634(self): + sched_priority = float('inf') # any new reference + param = posix.sched_param(sched_priority) + param.__reduce__() + del sched_priority, param # should not crash + support.gc_collect() # just to be sure + @unittest.skipUnless(hasattr(posix, "sched_rr_get_interval"), "no function") def test_sched_rr_get_interval(self): try: @@ -1611,33 +1680,47 @@ class TestPosixDirFd(unittest.TestCase): with self.prepare_file() as (dir_fd, name, fullname): posix.chown(name, os.getuid(), os.getgid(), dir_fd=dir_fd) - @unittest.skipUnless(os.stat in os.supports_dir_fd, "test needs dir_fd support in os.stat()") - def test_stat_dir_fd(self): + def check_statlike_dir_fd(self, func, prefix): with self.prepare() as (dir_fd, name, fullname): with open(fullname, 'w') as outfile: outfile.write("testline\n") self.addCleanup(posix.unlink, fullname) - s1 = posix.stat(fullname) - s2 = posix.stat(name, dir_fd=dir_fd) - self.assertEqual(s1, s2) - s2 = posix.stat(fullname, dir_fd=None) - self.assertEqual(s1, s2) + def get(result, attr): + return getattr(result, prefix + attr) + + s1 = func(fullname) + s2 = func(name, dir_fd=dir_fd) + self.assertEqual((get(s1, "dev"), get(s1, "ino")), + (get(s2, "dev"), get(s2, "ino"))) + s2 = func(fullname, dir_fd=None) + self.assertEqual((get(s1, "dev"), get(s1, "ino")), + (get(s2, "dev"), get(s2, "ino"))) self.assertRaisesRegex(TypeError, 'should be integer or None, not', - posix.stat, name, dir_fd=posix.getcwd()) + func, name, dir_fd=posix.getcwd()) self.assertRaisesRegex(TypeError, 'should be integer or None, not', - posix.stat, name, dir_fd=float(dir_fd)) + func, name, dir_fd=float(dir_fd)) self.assertRaises(OverflowError, - posix.stat, name, dir_fd=10**20) + func, name, dir_fd=10**20) for fd in False, True: with self.assertWarnsRegex(RuntimeWarning, 'bool is used as a file descriptor') as cm: with self.assertRaises(OSError): - posix.stat('nonexisting', dir_fd=fd) + func('nonexisting', dir_fd=fd) self.assertEqual(cm.filename, __file__) + @unittest.skipUnless(os.stat in os.supports_dir_fd, "test needs dir_fd support in os.stat()") + def test_stat_dir_fd(self): + self.check_statlike_dir_fd(posix.stat, prefix="st_") + + @unittest.skipUnless(hasattr(posix, 'statx'), "test needs os.statx()") + def test_statx_dir_fd(self): + def func(path, **kwargs): + return posix.statx(path, os.STATX_INO, **kwargs) + self.check_statlike_dir_fd(func, prefix="stx_") + @unittest.skipUnless(os.utime in os.supports_dir_fd, "test needs dir_fd support in os.utime()") def test_utime_dir_fd(self): with self.prepare_file() as (dir_fd, name, fullname): @@ -2036,6 +2119,12 @@ class _PosixSpawnMixin: @requires_sched @unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')), "bpo-34685: test can fail on BSD") + @unittest.skipIf(platform.libc_ver()[0] == 'glibc' and + os.sched_getscheduler(0) in [ + os.SCHED_BATCH, + os.SCHED_IDLE, + os.SCHED_DEADLINE], + "Skip test due to glibc posix_spawn policy") def test_setscheduler_with_policy(self): policy = os.sched_getscheduler(0) priority = os.sched_get_priority_min(policy) diff --git a/Lib/test/test_os/test_windows.py b/Lib/test/test_os/test_windows.py new file mode 100644 index 00000000000..f1c6283f60d --- /dev/null +++ b/Lib/test/test_os/test_windows.py @@ -0,0 +1,605 @@ +import sys +import unittest + +if sys.platform != "win32": + raise unittest.SkipTest("Win32 specific tests") + +import _winapi +import fnmatch +import mmap +import os +import shutil +import signal +import stat +import subprocess +import textwrap +import time +import uuid +from test import support +from test.support import import_helper +from test.support import os_helper +from .utils import create_file + + +class Win32KillTests(unittest.TestCase): + def _kill(self, sig): + # Start sys.executable as a subprocess and communicate from the + # subprocess to the parent that the interpreter is ready. When it + # becomes ready, send *sig* via os.kill to the subprocess and check + # that the return code is equal to *sig*. + import ctypes + from ctypes import wintypes + import msvcrt + + # Since we can't access the contents of the process' stdout until the + # process has exited, use PeekNamedPipe to see what's inside stdout + # without waiting. This is done so we can tell that the interpreter + # is started and running at a point where it could handle a signal. + PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe + PeekNamedPipe.restype = wintypes.BOOL + PeekNamedPipe.argtypes = (wintypes.HANDLE, # Pipe handle + ctypes.POINTER(ctypes.c_char), # stdout buf + wintypes.DWORD, # Buffer size + ctypes.POINTER(wintypes.DWORD), # bytes read + ctypes.POINTER(wintypes.DWORD), # bytes avail + ctypes.POINTER(wintypes.DWORD)) # bytes left + msg = "running" + proc = subprocess.Popen([sys.executable, "-c", + "import sys;" + "sys.stdout.write('{}');" + "sys.stdout.flush();" + "input()".format(msg)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE) + self.addCleanup(proc.stdout.close) + self.addCleanup(proc.stderr.close) + self.addCleanup(proc.stdin.close) + + count, max = 0, 100 + while count < max and proc.poll() is None: + # Create a string buffer to store the result of stdout from the pipe + buf = ctypes.create_string_buffer(len(msg)) + # Obtain the text currently in proc.stdout + # Bytes read/avail/left are left as NULL and unused + rslt = PeekNamedPipe(msvcrt.get_osfhandle(proc.stdout.fileno()), + buf, ctypes.sizeof(buf), None, None, None) + self.assertNotEqual(rslt, 0, "PeekNamedPipe failed") + if buf.value: + self.assertEqual(msg, buf.value.decode()) + break + time.sleep(0.1) + count += 1 + else: + self.fail("Did not receive communication from the subprocess") + + os.kill(proc.pid, sig) + self.assertEqual(proc.wait(), sig) + + def test_kill_sigterm(self): + # SIGTERM doesn't mean anything special, but make sure it works + self._kill(signal.SIGTERM) + + def test_kill_int(self): + # os.kill on Windows can take an int which gets set as the exit code + self._kill(100) + + @unittest.skipIf(mmap is None, "requires mmap") + def _kill_with_event(self, event, name): + tagname = "test_os_%s" % uuid.uuid1() + m = mmap.mmap(-1, 1, tagname) + m[0] = 0 + + # Run a script which has console control handling enabled. + script = os.path.join(os.path.dirname(__file__), + "win_console_handler.py") + cmd = [sys.executable, script, tagname] + proc = subprocess.Popen(cmd, + creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) + + with proc: + # Let the interpreter startup before we send signals. See #3137. + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if proc.poll() is None: + break + else: + # Forcefully kill the process if we weren't able to signal it. + proc.kill() + self.fail("Subprocess didn't finish initialization") + + os.kill(proc.pid, event) + + try: + # proc.send_signal(event) could also be done here. + # Allow time for the signal to be passed and the process to exit. + proc.wait(timeout=support.SHORT_TIMEOUT) + except subprocess.TimeoutExpired: + # Forcefully kill the process if we weren't able to signal it. + proc.kill() + self.fail("subprocess did not stop on {}".format(name)) + + @unittest.skip("subprocesses aren't inheriting Ctrl+C property") + @support.requires_subprocess() + def test_CTRL_C_EVENT(self): + from ctypes import wintypes + import ctypes + + # Make a NULL value by creating a pointer with no argument. + NULL = ctypes.POINTER(ctypes.c_int)() + SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler + SetConsoleCtrlHandler.argtypes = (ctypes.POINTER(ctypes.c_int), + wintypes.BOOL) + SetConsoleCtrlHandler.restype = wintypes.BOOL + + # Calling this with NULL and FALSE causes the calling process to + # handle Ctrl+C, rather than ignore it. This property is inherited + # by subprocesses. + SetConsoleCtrlHandler(NULL, 0) + + self._kill_with_event(signal.CTRL_C_EVENT, "CTRL_C_EVENT") + + @support.requires_subprocess() + def test_CTRL_BREAK_EVENT(self): + self._kill_with_event(signal.CTRL_BREAK_EVENT, "CTRL_BREAK_EVENT") + + +class Win32ListdirTests(unittest.TestCase): + """Test listdir on Windows.""" + + def setUp(self): + self.created_paths = [] + for i in range(2): + dir_name = 'SUB%d' % i + dir_path = os.path.join(os_helper.TESTFN, dir_name) + file_name = 'FILE%d' % i + file_path = os.path.join(os_helper.TESTFN, file_name) + os.makedirs(dir_path) + with open(file_path, 'w', encoding='utf-8') as f: + f.write("I'm %s and proud of it. Blame test_os.\n" % file_path) + self.created_paths.extend([dir_name, file_name]) + self.created_paths.sort() + + def tearDown(self): + shutil.rmtree(os_helper.TESTFN) + + def test_listdir_no_extended_path(self): + """Test when the path is not an "extended" path.""" + # unicode + self.assertEqual( + sorted(os.listdir(os_helper.TESTFN)), + self.created_paths) + + # bytes + self.assertEqual( + sorted(os.listdir(os.fsencode(os_helper.TESTFN))), + [os.fsencode(path) for path in self.created_paths]) + + def test_listdir_extended_path(self): + """Test when the path starts with '\\\\?\\'.""" + # See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath + # unicode + path = '\\\\?\\' + os.path.abspath(os_helper.TESTFN) + self.assertEqual( + sorted(os.listdir(path)), + self.created_paths) + + # bytes + path = b'\\\\?\\' + os.fsencode(os.path.abspath(os_helper.TESTFN)) + self.assertEqual( + sorted(os.listdir(path)), + [os.fsencode(path) for path in self.created_paths]) + + +@unittest.skipUnless(os.name == "nt", "NT specific tests") +class Win32ListdriveTests(unittest.TestCase): + """Test listdrive, listmounts and listvolume on Windows.""" + + def setUp(self): + # Get drives and volumes from fsutil + out = subprocess.check_output( + ["fsutil.exe", "volume", "list"], + cwd=os.path.join(os.getenv("SystemRoot", "\\Windows"), "System32"), + encoding="mbcs", + errors="ignore", + ) + lines = out.splitlines() + self.known_volumes = {l for l in lines if l.startswith('\\\\?\\')} + self.known_drives = {l for l in lines if l[1:] == ':\\'} + self.known_mounts = {l for l in lines if l[1:3] == ':\\'} + + def test_listdrives(self): + drives = os.listdrives() + self.assertIsInstance(drives, list) + self.assertSetEqual( + self.known_drives, + self.known_drives & set(drives), + ) + + def test_listvolumes(self): + volumes = os.listvolumes() + self.assertIsInstance(volumes, list) + self.assertSetEqual( + self.known_volumes, + self.known_volumes & set(volumes), + ) + + def test_listmounts(self): + for volume in os.listvolumes(): + try: + mounts = os.listmounts(volume) + except OSError as ex: + if support.verbose: + print("Skipping", volume, "because of", ex) + else: + self.assertIsInstance(mounts, list) + self.assertSetEqual( + set(mounts), + self.known_mounts & set(mounts), + ) + + +@os_helper.skip_unless_symlink +class Win32SymlinkTests(unittest.TestCase): + filelink = 'filelinktest' + filelink_target = os.path.abspath(__file__) + dirlink = 'dirlinktest' + dirlink_target = os.path.dirname(filelink_target) + missing_link = 'missing link' + + def setUp(self): + assert os.path.exists(self.dirlink_target) + assert os.path.exists(self.filelink_target) + assert not os.path.exists(self.dirlink) + assert not os.path.exists(self.filelink) + assert not os.path.exists(self.missing_link) + + def tearDown(self): + if os.path.exists(self.filelink): + os.remove(self.filelink) + if os.path.exists(self.dirlink): + os.rmdir(self.dirlink) + if os.path.lexists(self.missing_link): + os.remove(self.missing_link) + + def test_directory_link(self): + os.symlink(self.dirlink_target, self.dirlink) + self.assertTrue(os.path.exists(self.dirlink)) + self.assertTrue(os.path.isdir(self.dirlink)) + self.assertTrue(os.path.islink(self.dirlink)) + self.check_stat(self.dirlink, self.dirlink_target) + + def test_file_link(self): + os.symlink(self.filelink_target, self.filelink) + self.assertTrue(os.path.exists(self.filelink)) + self.assertTrue(os.path.isfile(self.filelink)) + self.assertTrue(os.path.islink(self.filelink)) + self.check_stat(self.filelink, self.filelink_target) + + def _create_missing_dir_link(self): + 'Create a "directory" link to a non-existent target' + linkname = self.missing_link + if os.path.lexists(linkname): + os.remove(linkname) + target = r'c:\\target does not exist.29r3c740' + assert not os.path.exists(target) + target_is_dir = True + os.symlink(target, linkname, target_is_dir) + + def test_remove_directory_link_to_missing_target(self): + self._create_missing_dir_link() + # For compatibility with Unix, os.remove will check the + # directory status and call RemoveDirectory if the symlink + # was created with target_is_dir==True. + os.remove(self.missing_link) + + def test_isdir_on_directory_link_to_missing_target(self): + self._create_missing_dir_link() + self.assertFalse(os.path.isdir(self.missing_link)) + + def test_rmdir_on_directory_link_to_missing_target(self): + self._create_missing_dir_link() + os.rmdir(self.missing_link) + + def check_stat(self, link, target): + self.assertEqual(os.stat(link), os.stat(target)) + self.assertNotEqual(os.lstat(link), os.stat(link)) + + bytes_link = os.fsencode(link) + self.assertEqual(os.stat(bytes_link), os.stat(target)) + self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link)) + + def test_12084(self): + level1 = os.path.abspath(os_helper.TESTFN) + level2 = os.path.join(level1, "level2") + level3 = os.path.join(level2, "level3") + self.addCleanup(os_helper.rmtree, level1) + + os.mkdir(level1) + os.mkdir(level2) + os.mkdir(level3) + + file1 = os.path.abspath(os.path.join(level1, "file1")) + create_file(file1) + + orig_dir = os.getcwd() + try: + os.chdir(level2) + link = os.path.join(level2, "link") + os.symlink(os.path.relpath(file1), "link") + self.assertIn("link", os.listdir(os.getcwd())) + + # Check os.stat calls from the same dir as the link + self.assertEqual(os.stat(file1), os.stat("link")) + + # Check os.stat calls from a dir below the link + os.chdir(level1) + self.assertEqual(os.stat(file1), + os.stat(os.path.relpath(link))) + + # Check os.stat calls from a dir above the link + os.chdir(level3) + self.assertEqual(os.stat(file1), + os.stat(os.path.relpath(link))) + finally: + os.chdir(orig_dir) + + @unittest.skipUnless(os.path.lexists(r'C:\Users\All Users') + and os.path.exists(r'C:\ProgramData'), + 'Test directories not found') + def test_29248(self): + # os.symlink() calls CreateSymbolicLink, which creates + # the reparse data buffer with the print name stored + # first, so the offset is always 0. CreateSymbolicLink + # stores the "PrintName" DOS path (e.g. "C:\") first, + # with an offset of 0, followed by the "SubstituteName" + # NT path (e.g. "\??\C:\"). The "All Users" link, on + # the other hand, seems to have been created manually + # with an inverted order. + target = os.readlink(r'C:\Users\All Users') + self.assertTrue(os.path.samefile(target, r'C:\ProgramData')) + + def test_buffer_overflow(self): + # Older versions would have a buffer overflow when detecting + # whether a link source was a directory. This test ensures we + # no longer crash, but does not otherwise validate the behavior + segment = 'X' * 27 + path = os.path.join(*[segment] * 10) + test_cases = [ + # overflow with absolute src + ('\\' + path, segment), + # overflow dest with relative src + (segment, path), + # overflow when joining src + (path[:180], path[:180]), + ] + for src, dest in test_cases: + try: + os.symlink(src, dest) + except FileNotFoundError: + pass + else: + try: + os.remove(dest) + except OSError: + pass + # Also test with bytes, since that is a separate code path. + try: + os.symlink(os.fsencode(src), os.fsencode(dest)) + except FileNotFoundError: + pass + else: + try: + os.remove(dest) + except OSError: + pass + + def test_appexeclink(self): + root = os.path.expandvars(r'%LOCALAPPDATA%\Microsoft\WindowsApps') + if not os.path.isdir(root): + self.skipTest("test requires a WindowsApps directory") + + aliases = [os.path.join(root, a) + for a in fnmatch.filter(os.listdir(root), '*.exe')] + + for alias in aliases: + if support.verbose: + print() + print("Testing with", alias) + st = os.lstat(alias) + self.assertEqual(st, os.stat(alias)) + self.assertFalse(stat.S_ISLNK(st.st_mode)) + self.assertEqual(st.st_reparse_tag, stat.IO_REPARSE_TAG_APPEXECLINK) + self.assertTrue(os.path.isfile(alias)) + # testing the first one we see is sufficient + break + else: + self.skipTest("test requires an app execution alias") + + +class Win32JunctionTests(unittest.TestCase): + junction = 'junctiontest' + junction_target = os.path.dirname(os.path.abspath(__file__)) + + def setUp(self): + assert os.path.exists(self.junction_target) + assert not os.path.lexists(self.junction) + + def tearDown(self): + if os.path.lexists(self.junction): + os.unlink(self.junction) + + def test_create_junction(self): + _winapi.CreateJunction(self.junction_target, self.junction) + self.assertTrue(os.path.lexists(self.junction)) + self.assertTrue(os.path.exists(self.junction)) + self.assertTrue(os.path.isdir(self.junction)) + self.assertNotEqual(os.stat(self.junction), os.lstat(self.junction)) + self.assertEqual(os.stat(self.junction), os.stat(self.junction_target)) + + # bpo-37834: Junctions are not recognized as links. + self.assertFalse(os.path.islink(self.junction)) + self.assertEqual(os.path.normcase("\\\\?\\" + self.junction_target), + os.path.normcase(os.readlink(self.junction))) + + def test_unlink_removes_junction(self): + _winapi.CreateJunction(self.junction_target, self.junction) + self.assertTrue(os.path.exists(self.junction)) + self.assertTrue(os.path.lexists(self.junction)) + + os.unlink(self.junction) + self.assertFalse(os.path.exists(self.junction)) + + +class Win32NtTests(unittest.TestCase): + def test_getfinalpathname_handles(self): + nt = import_helper.import_module('nt') + ctypes = import_helper.import_module('ctypes') + # Ruff false positive -- it thinks we're redefining `ctypes` here + import ctypes.wintypes # noqa: F811 + + kernel = ctypes.WinDLL('Kernel32.dll', use_last_error=True) + kernel.GetCurrentProcess.restype = ctypes.wintypes.HANDLE + + kernel.GetProcessHandleCount.restype = ctypes.wintypes.BOOL + kernel.GetProcessHandleCount.argtypes = (ctypes.wintypes.HANDLE, + ctypes.wintypes.LPDWORD) + + # This is a pseudo-handle that doesn't need to be closed + hproc = kernel.GetCurrentProcess() + + handle_count = ctypes.wintypes.DWORD() + ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count)) + self.assertEqual(1, ok) + + before_count = handle_count.value + + # The first two test the error path, __file__ tests the success path + filenames = [ + r'\\?\C:', + r'\\?\NUL', + r'\\?\CONIN', + __file__, + ] + + for _ in range(10): + for name in filenames: + try: + nt._getfinalpathname(name) + except Exception: + # Failure is expected + pass + try: + os.stat(name) + except Exception: + pass + + ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count)) + self.assertEqual(1, ok) + + handle_delta = handle_count.value - before_count + + self.assertEqual(0, handle_delta) + + @support.requires_subprocess() + def test_stat_unlink_race(self): + # bpo-46785: the implementation of os.stat() falls back to reading + # the parent directory if CreateFileW() fails with a permission + # error. If reading the parent directory fails because the file or + # directory are subsequently unlinked, or because the volume or + # share are no longer available, then the original permission error + # should not be restored. + filename = os_helper.TESTFN + self.addCleanup(os_helper.unlink, filename) + deadline = time.time() + 5 + command = textwrap.dedent("""\ + import os + import sys + import time + + filename = sys.argv[1] + deadline = float(sys.argv[2]) + + while time.time() < deadline: + try: + with open(filename, "w") as f: + pass + except OSError: + pass + try: + os.remove(filename) + except OSError: + pass + """) + + with subprocess.Popen([sys.executable, '-c', command, filename, str(deadline)]) as proc: + while time.time() < deadline: + try: + os.stat(filename) + except FileNotFoundError as e: + assert e.winerror == 2 # ERROR_FILE_NOT_FOUND + try: + proc.wait(1) + except subprocess.TimeoutExpired: + proc.terminate() + + @support.requires_subprocess() + def test_stat_inaccessible_file(self): + filename = os_helper.TESTFN + ICACLS = os.path.expandvars(r"%SystemRoot%\System32\icacls.exe") + + with open(filename, "wb") as f: + f.write(b'Test data') + + stat1 = os.stat(filename) + + try: + # Remove all permissions from the file + subprocess.check_output([ICACLS, filename, "/inheritance:r"], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as ex: + if support.verbose: + print(ICACLS, filename, "/inheritance:r", "failed.") + print(ex.stdout.decode("oem", "replace").rstrip()) + try: + os.unlink(filename) + except OSError: + pass + self.skipTest("Unable to create inaccessible file") + + def cleanup(): + # Give delete permission to the owner (us) + subprocess.check_output([ICACLS, filename, "/grant", "*WD:(D)"], + stderr=subprocess.STDOUT) + os.unlink(filename) + + self.addCleanup(cleanup) + + if support.verbose: + print("File:", filename) + print("stat with access:", stat1) + + # First test - we shouldn't raise here, because we still have access to + # the directory and can extract enough information from its metadata. + stat2 = os.stat(filename) + + if support.verbose: + print(" without access:", stat2) + + # We may not get st_dev/st_ino, so ensure those are 0 or match + self.assertIn(stat2.st_dev, (0, stat1.st_dev)) + self.assertIn(stat2.st_ino, (0, stat1.st_ino)) + + # st_mode and st_size should match (for a normal file, at least) + self.assertEqual(stat1.st_mode, stat2.st_mode) + self.assertEqual(stat1.st_size, stat2.st_size) + + # st_ctime and st_mtime should be the same + self.assertEqual(stat1.st_ctime, stat2.st_ctime) + self.assertEqual(stat1.st_mtime, stat2.st_mtime) + + # st_atime should be the same or later + self.assertGreaterEqual(stat1.st_atime, stat2.st_atime) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_os/utils.py b/Lib/test/test_os/utils.py new file mode 100644 index 00000000000..e0c39598c31 --- /dev/null +++ b/Lib/test/test_os/utils.py @@ -0,0 +1,3 @@ +def create_file(filename, content=b'content'): + with open(filename, "xb", 0) as fp: + fp.write(content) diff --git a/Lib/test/test_pathlib/support/local_path.py b/Lib/test/test_pathlib/support/local_path.py index c1423c545bf..ddfd6fd4195 100644 --- a/Lib/test/test_pathlib/support/local_path.py +++ b/Lib/test/test_pathlib/support/local_path.py @@ -145,7 +145,7 @@ class ReadableLocalPath(_ReadablePath, LexicalPath): super().__init__(*pathsegments) self.info = LocalPathInfo(self) - def __open_rb__(self, buffering=-1): + def __open_reader__(self): return open(self, 'rb') def iterdir(self): @@ -163,8 +163,8 @@ class WritableLocalPath(_WritablePath, LexicalPath): __slots__ = () __fspath__ = LexicalPath.__vfspath__ - def __open_wb__(self, buffering=-1): - return open(self, 'wb') + def __open_writer__(self, mode): + return open(self, f'{mode}b') def mkdir(self, mode=0o777): os.mkdir(self, mode) diff --git a/Lib/test/test_pathlib/support/zip_path.py b/Lib/test/test_pathlib/support/zip_path.py index 2bfe89b3659..90b939b6a59 100644 --- a/Lib/test/test_pathlib/support/zip_path.py +++ b/Lib/test/test_pathlib/support/zip_path.py @@ -264,13 +264,13 @@ class ReadableZipPath(_ReadablePath): tree = self.zip_file.filelist.tree return tree.resolve(vfspath(self), follow_symlinks=False) - def __open_rb__(self, buffering=-1): + def __open_reader__(self): info = self.info.resolve() if not info.exists(): raise FileNotFoundError(errno.ENOENT, "File not found", self) elif info.is_dir(): raise IsADirectoryError(errno.EISDIR, "Is a directory", self) - return self.zip_file.open(info.zip_info, 'r') + return self.zip_file.open(info.zip_info) def iterdir(self): info = self.info.resolve() @@ -320,8 +320,8 @@ class WritableZipPath(_WritablePath): def with_segments(self, *pathsegments): return type(self)(*pathsegments, zip_file=self.zip_file) - def __open_wb__(self, buffering=-1): - return self.zip_file.open(vfspath(self), 'w') + def __open_writer__(self, mode): + return self.zip_file.open(vfspath(self), mode) def mkdir(self, mode=0o777): zinfo = zipfile.ZipInfo(vfspath(self) + '/') diff --git a/Lib/test/test_pathlib/test_join.py b/Lib/test/test_pathlib/test_join.py index f1a24204b4c..4630210e492 100644 --- a/Lib/test/test_pathlib/test_join.py +++ b/Lib/test/test_pathlib/test_join.py @@ -3,6 +3,8 @@ Tests for pathlib.types._JoinablePath """ import unittest +import threading +from test.support import threading_helper from .support import is_pypi from .support.lexical_path import LexicalPath @@ -158,6 +160,26 @@ class JoinTestBase: parts = p.parts self.assertEqual(parts, (sep, 'a', 'b')) + @threading_helper.requires_working_threading() + def test_parts_multithreaded(self): + P = self.cls + + NUM_THREADS = 10 + NUM_ITERS = 10 + + for _ in range(NUM_ITERS): + b = threading.Barrier(NUM_THREADS) + path = P('a') / 'b' / 'c' / 'd' / 'e' + expected = ('a', 'b', 'c', 'd', 'e') + + def check_parts(): + b.wait() + self.assertEqual(path.parts, expected) + + threads = [threading.Thread(target=check_parts) for _ in range(NUM_THREADS)] + with threading_helper.start_threads(threads): + pass + def test_parent(self): # Relative P = self.cls @@ -354,6 +376,61 @@ class JoinTestBase: self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.') self.assertRaises(TypeError, P('a/b').with_suffix, None) + def test_relative_to(self): + P = self.cls + p = P('a/b') + self.assertEqual(p.relative_to(P('')), P('a', 'b')) + self.assertEqual(p.relative_to(P('a')), P('b')) + self.assertEqual(p.relative_to(P('a/b')), P('')) + self.assertEqual(p.relative_to(P(''), walk_up=True), P('a', 'b')) + self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) + self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P('')) + self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('..', 'b')) + self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) + self.assertEqual(p.relative_to(P('c'), walk_up=True), P('..', 'a', 'b')) + self.assertRaises(ValueError, p.relative_to, P('c')) + self.assertRaises(ValueError, p.relative_to, P('a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('a/c')) + self.assertRaises(ValueError, p.relative_to, P('/a')) + self.assertRaises(ValueError, p.relative_to, P('../a')) + self.assertRaises(ValueError, p.relative_to, P('a/..')) + self.assertRaises(ValueError, p.relative_to, P('/a/..')) + self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('../a'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('a/..'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P('/a/..'), walk_up=True) + class Q(self.cls): + __eq__ = object.__eq__ + __hash__ = object.__hash__ + q = Q('a/b') + self.assertTrue(q.relative_to(q)) + self.assertRaises(ValueError, q.relative_to, Q('')) + self.assertRaises(ValueError, q.relative_to, Q('a')) + self.assertRaises(ValueError, q.relative_to, Q('a'), walk_up=True) + self.assertRaises(ValueError, q.relative_to, Q('a/b')) + self.assertRaises(ValueError, q.relative_to, Q('c')) + + def test_is_relative_to(self): + P = self.cls + p = P('a/b') + self.assertTrue(p.is_relative_to(P(''))) + self.assertTrue(p.is_relative_to(P('a'))) + self.assertTrue(p.is_relative_to(P('a/b'))) + self.assertFalse(p.is_relative_to(P('c'))) + self.assertFalse(p.is_relative_to(P('a/b/c'))) + self.assertFalse(p.is_relative_to(P('a/c'))) + self.assertFalse(p.is_relative_to(P('/a'))) + class Q(self.cls): + __eq__ = object.__eq__ + __hash__ = object.__hash__ + q = Q('a/b') + self.assertTrue(q.is_relative_to(q)) + self.assertFalse(q.is_relative_to(Q(''))) + self.assertFalse(q.is_relative_to(Q('a'))) + self.assertFalse(q.is_relative_to(Q('a/b'))) + self.assertFalse(q.is_relative_to(Q('c'))) + class LexicalPathJoinTest(JoinTestBase, unittest.TestCase): cls = LexicalPath diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index a1105aae635..ef9ea0d11d0 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -293,6 +293,12 @@ class PurePathTest(unittest.TestCase): self.assertEqual(hash(pp), hash(p)) self.assertEqual(str(pp), str(p)) + def test_unpicking_3_13(self): + data = (b"\x80\x04\x95'\x00\x00\x00\x00\x00\x00\x00\x8c\x0e" + b"pathlib._local\x94\x8c\rPurePosixPath\x94\x93\x94)R\x94.") + p = pickle.loads(data) + self.assertIsInstance(p, pathlib.PurePosixPath) + def test_repr_common(self): for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): with self.subTest(pathstr=pathstr): diff --git a/Lib/test/test_pathlib/test_read.py b/Lib/test/test_pathlib/test_read.py index 482203c290a..16fb555b2ae 100644 --- a/Lib/test/test_pathlib/test_read.py +++ b/Lib/test/test_pathlib/test_read.py @@ -13,10 +13,10 @@ from .support.zip_path import ReadableZipPath, ZipPathGround if is_pypi: from pathlib_abc import PathInfo, _ReadablePath - from pathlib_abc._os import magic_open + from pathlib_abc._os import vfsopen else: from pathlib.types import PathInfo, _ReadablePath - from pathlib._os import magic_open + from pathlib._os import vfsopen class ReadTestBase: @@ -32,10 +32,16 @@ class ReadTestBase: def test_open_r(self): p = self.root / 'fileA' - with magic_open(p, 'r', encoding='utf-8') as f: + with vfsopen(p, 'r', encoding='utf-8') as f: self.assertIsInstance(f, io.TextIOBase) self.assertEqual(f.read(), 'this is file A\n') + def test_open_r_buffering_error(self): + p = self.root / 'fileA' + self.assertRaises(ValueError, vfsopen, p, 'r', buffering=0) + self.assertRaises(ValueError, vfsopen, p, 'r', buffering=1) + self.assertRaises(ValueError, vfsopen, p, 'r', buffering=1024) + @unittest.skipIf( not getattr(sys.flags, 'warn_default_encoding', 0), "Requires warn_default_encoding", @@ -43,17 +49,17 @@ class ReadTestBase: def test_open_r_encoding_warning(self): p = self.root / 'fileA' with self.assertWarns(EncodingWarning) as wc: - with magic_open(p, 'r'): + with vfsopen(p, 'r'): pass self.assertEqual(wc.filename, __file__) def test_open_rb(self): p = self.root / 'fileA' - with magic_open(p, 'rb') as f: + with vfsopen(p, 'rb') as f: self.assertEqual(f.read(), b'this is file A\n') - self.assertRaises(ValueError, magic_open, p, 'rb', encoding='utf8') - self.assertRaises(ValueError, magic_open, p, 'rb', errors='strict') - self.assertRaises(ValueError, magic_open, p, 'rb', newline='') + self.assertRaises(ValueError, vfsopen, p, 'rb', encoding='utf8') + self.assertRaises(ValueError, vfsopen, p, 'rb', errors='strict') + self.assertRaises(ValueError, vfsopen, p, 'rb', newline='') def test_read_bytes(self): p = self.root / 'fileA' diff --git a/Lib/test/test_pathlib/test_write.py b/Lib/test/test_pathlib/test_write.py index b958490d0a8..c9c1d64656c 100644 --- a/Lib/test/test_pathlib/test_write.py +++ b/Lib/test/test_pathlib/test_write.py @@ -13,10 +13,10 @@ from .support.zip_path import WritableZipPath, ZipPathGround if is_pypi: from pathlib_abc import _WritablePath - from pathlib_abc._os import magic_open + from pathlib_abc._os import vfsopen else: from pathlib.types import _WritablePath - from pathlib._os import magic_open + from pathlib._os import vfsopen class WriteTestBase: @@ -31,11 +31,17 @@ class WriteTestBase: def test_open_w(self): p = self.root / 'fileA' - with magic_open(p, 'w', encoding='utf-8') as f: + with vfsopen(p, 'w', encoding='utf-8') as f: self.assertIsInstance(f, io.TextIOBase) f.write('this is file A\n') self.assertEqual(self.ground.readtext(p), 'this is file A\n') + def test_open_w_buffering_error(self): + p = self.root / 'fileA' + self.assertRaises(ValueError, vfsopen, p, 'w', buffering=0) + self.assertRaises(ValueError, vfsopen, p, 'w', buffering=1) + self.assertRaises(ValueError, vfsopen, p, 'w', buffering=1024) + @unittest.skipIf( not getattr(sys.flags, 'warn_default_encoding', 0), "Requires warn_default_encoding", @@ -43,19 +49,19 @@ class WriteTestBase: def test_open_w_encoding_warning(self): p = self.root / 'fileA' with self.assertWarns(EncodingWarning) as wc: - with magic_open(p, 'w'): + with vfsopen(p, 'w'): pass self.assertEqual(wc.filename, __file__) def test_open_wb(self): p = self.root / 'fileA' - with magic_open(p, 'wb') as f: + with vfsopen(p, 'wb') as f: #self.assertIsInstance(f, io.BufferedWriter) f.write(b'this is file A\n') self.assertEqual(self.ground.readbytes(p), b'this is file A\n') - self.assertRaises(ValueError, magic_open, p, 'wb', encoding='utf8') - self.assertRaises(ValueError, magic_open, p, 'wb', errors='strict') - self.assertRaises(ValueError, magic_open, p, 'wb', newline='') + self.assertRaises(ValueError, vfsopen, p, 'wb', encoding='utf8') + self.assertRaises(ValueError, vfsopen, p, 'wb', errors='strict') + self.assertRaises(ValueError, vfsopen, p, 'wb', newline='') def test_write_bytes(self): p = self.root / 'fileA' diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 6b74e21ad73..5cba34ff8ba 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3232,6 +3232,37 @@ def test_pdb_issue_gh_127321(): """ +def test_pdb_issue_gh_136057(): + """See GH-136057 + "step" and "next" commands should be able to get over list comprehensions + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... lst = [i for i in range(10)] + ... for i in lst: pass + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'next', + ... 'next', + ... 'step', + ... 'continue', + ... ]): + ... test_function() + > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(2)test_function() + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) next + > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(3)test_function() + -> lst = [i for i in range(10)] + (Pdb) next + > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(4)test_function() + -> for i in lst: pass + (Pdb) step + --Return-- + > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(4)test_function()->None + -> for i in lst: pass + (Pdb) continue + """ + + def test_pdb_issue_gh_80731(): """See GH-80731 @@ -3530,6 +3561,35 @@ class PdbTestCase(unittest.TestCase): self.assertEqual( expected, pdb.find_function(func_name, os_helper.TESTFN)) + def _fd_dir_for_pipe_targets(self): + """Return a directory exposing live file descriptors, if any.""" + return self._proc_fd_dir() or self._dev_fd_dir() + + def _proc_fd_dir(self): + """Return /proc-backed fd dir when it can be used for pipes.""" + # GH-142836: Opening /proc/self/fd entries for pipes raises EACCES on + # Solaris, so prefer other mechanisms there. + if sys.platform.startswith("sunos"): + return None + + proc_fd = "/proc/self/fd" + if os.path.isdir(proc_fd) and os.path.exists(os.path.join(proc_fd, '0')): + return proc_fd + return None + + def _dev_fd_dir(self): + """Return /dev-backed fd dir when usable.""" + dev_fd = "/dev/fd" + if os.path.isdir(dev_fd) and os.path.exists(os.path.join(dev_fd, '0')): + if sys.platform.startswith("freebsd"): + try: + if os.stat("/dev").st_dev == os.stat(dev_fd).st_dev: + return None + except FileNotFoundError: + return None + return dev_fd + return None + def test_find_function_empty_file(self): self._assert_find_function(b'', 'foo', None) @@ -3549,6 +3609,20 @@ def quux(): ('bœr', 5), ) + def test_print_stack_entry_uses_dynamic_line_prefix(self): + """Test that pdb.line_prefix binding is dynamic (gh-141781).""" + stdout = io.StringIO() + p = pdb.Pdb(stdout=stdout) + + # Get the current frame to use for printing + frame = sys._getframe() + + with support.swap_attr(pdb, 'line_prefix', 'CUSTOM_PREFIX> '): + p.print_stack_entry((frame, frame.f_lineno)) + + # Check if the custom prefix appeared in the output + self.assertIn('CUSTOM_PREFIX> ', stdout.getvalue()) + def test_find_function_found_with_encoding_cookie(self): self._assert_find_function( """\ @@ -3588,6 +3662,47 @@ def bœr(): stdout, _ = self.run_pdb_script(script, commands) self.assertIn('None', stdout) + def test_script_target_anonymous_pipe(self): + """ + _ScriptTarget doesn't fail on an anonymous pipe. + + GH-142315 + """ + fd_dir = self._fd_dir_for_pipe_targets() + if fd_dir is None: + self.skipTest('anonymous pipe targets require /proc/self/fd or /dev/fd') + + read_fd, write_fd = os.pipe() + + def safe_close(fd): + try: + os.close(fd) + except OSError: + pass + + self.addCleanup(safe_close, read_fd) + self.addCleanup(safe_close, write_fd) + + pipe_path = os.path.join(fd_dir, str(read_fd)) + if not os.path.exists(pipe_path): + self.skipTest('fd directory does not expose anonymous pipes') + + script_source = 'marker = "via_pipe"\n' + os.write(write_fd, script_source.encode('utf-8')) + os.close(write_fd) + + original_path0 = sys.path[0] + self.addCleanup(sys.path.__setitem__, 0, original_path0) + + target = pdb._ScriptTarget(pipe_path) + code_text = target.code + namespace = target.namespace + exec(code_text, namespace) + + self.assertEqual(namespace['marker'], 'via_pipe') + self.assertEqual(namespace['__file__'], target.filename) + self.assertIsNone(namespace['__spec__']) + def test_find_function_first_executable_line(self): code = textwrap.dedent("""\ def foo(): pass @@ -3974,7 +4089,10 @@ def bœr(): commands = """ continue """ - self._run_pdb(["calendar", "-m"], commands, expected_returncode=2) + self._run_pdb(["calendar", "-m"], commands, expected_returncode=1) + + _, stderr = self._run_pdb(["-m", "calendar", "-p", "1"], commands) + self.assertIn("unrecognized arguments: -p", stderr) stdout, _ = self._run_pdb(["-m", "calendar", "1"], commands) self.assertIn("December", stdout) @@ -4539,6 +4657,41 @@ def bœr(): ])) self.assertIn('break in bar', stdout) + @unittest.skipIf(SKIP_CORO_TESTS, "Coroutine tests are skipped") + def test_async_break(self): + script = """ + import asyncio + + async def main(): + pass + + asyncio.run(main()) + """ + commands = """ + break main + continue + quit + """ + stdout, stderr = self.run_pdb_script(script, commands) + self.assertRegex(stdout, r"Breakpoint 1 at .*main\.py:5") + self.assertIn("pass", stdout) + + def test_issue_59000(self): + script = """ + def foo(): + pass + + class C: + def foo(self): + pass + """ + commands = """ + break C.foo + quit + """ + stdout, stderr = self.run_pdb_script(script, commands) + self.assertIn("The specified object 'C.foo' is not a function", stdout) + class ChecklineTests(unittest.TestCase): def setUp(self): @@ -4688,6 +4841,41 @@ class PdbTestInline(unittest.TestCase): stdout, _ = self._run_script(script, commands) self.assertIn("42", stdout) + def test_readline_not_imported(self): + """GH-138860 + Directly or indirectly importing readline might deadlock a subprocess + if it's launched with process_group=0 or preexec_fn=setpgrp + + It's also a pattern that readline is never imported with just import pdb. + + This test is to ensure that readline is not imported for import pdb. + It's possible that we have a good reason to do that in the future. + """ + + script = textwrap.dedent(""" + import sys + import pdb + if "readline" in sys.modules: + print("readline imported") + """) + commands = "" + stdout, stderr = self._run_script(script, commands) + self.assertNotIn("readline imported", stdout) + self.assertEqual(stderr, "") + + def test_alternate_stdin(self): + script = textwrap.dedent(""" + import pdb + import io + + input_data = io.StringIO("p 40 + 2\\nc\\n") + pdb.Pdb(stdin=input_data).set_trace() + """) + commands = "" + stdout, stderr = self._run_script(script, commands) + self.assertIn("42", stdout) + self.assertEqual(stderr, "") + @support.force_colorized_test_class class PdbTestColorize(unittest.TestCase): diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 98629df4574..1caf6de4a14 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -1116,6 +1116,13 @@ class TestMarkingVariablesAsUnKnown(BytecodeTestCase): self.assertInBytecode(f, "LOAD_FAST_BORROW") self.assertNotInBytecode(f, "LOAD_FAST_CHECK") + def test_import_from_doesnt_clobber_load_fast_borrow(self): + def f(self): + if x: pass + self.x + from shutil import ExecError + print(ExecError) + self.assertInBytecode(f, "LOAD_FAST_BORROW", "self") class DirectCfgOptimizerTests(CfgOptimizationTestCase): diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index aa01a9b8f7e..395f15b9a62 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -100,11 +100,15 @@ class TestCParser(unittest.TestCase): with contextlib.ExitStack() as stack: python_exe = stack.enter_context(support.setup_venv_with_pip_setuptools("venv")) - sitepackages = subprocess.check_output( + platlib_path = subprocess.check_output( [python_exe, "-c", "import sysconfig; print(sysconfig.get_path('platlib'))"], text=True, ).strip() - stack.enter_context(import_helper.DirsOnSysPath(sitepackages)) + purelib_path = subprocess.check_output( + [python_exe, "-c", "import sysconfig; print(sysconfig.get_path('purelib'))"], + text=True, + ).strip() + stack.enter_context(import_helper.DirsOnSysPath(platlib_path, purelib_path)) cls.addClassCleanup(stack.pop_all().close) @support.requires_venv_with_pip() diff --git a/Lib/test/test_peg_generator/test_pegen.py b/Lib/test/test_peg_generator/test_pegen.py index d912c558123..d03ba07975a 100644 --- a/Lib/test/test_peg_generator/test_pegen.py +++ b/Lib/test/test_peg_generator/test_pegen.py @@ -1106,3 +1106,53 @@ class TestGrammarVisualizer(unittest.TestCase): ) self.assertEqual(output, expected_output) + + def test_rule_flags(self) -> None: + """Test the new rule flags syntax that accepts arbitrary lists of flags.""" + # Test grammar with various flag combinations + grammar_source = """ + start: simple_rule + + simple_rule (memo): + | "hello" + + multi_flag_rule (memo, custom, test): + | "world" + + single_custom_flag (custom): + | "test" + + no_flags_rule: + | "plain" + """ + + grammar: Grammar = parse_string(grammar_source, GrammarParser) + rules = grammar.rules + + # Test memo-only rule + simple_rule = rules['simple_rule'] + self.assertTrue('memo' in simple_rule.flags, + "simple_rule should have memo") + self.assertEqual(simple_rule.flags, frozenset(['memo']), + f"simple_rule flags should be {'memo'}, got {simple_rule.flags}") + + # Test multi-flag rule + multi_flag_rule = rules['multi_flag_rule'] + self.assertTrue('memo' in simple_rule.flags, + "multi_flag_rule should have memo") + self.assertEqual(multi_flag_rule.flags, frozenset({'memo', 'custom', 'test'}), + f"multi_flag_rule flags should contain memo, custom, test, got {multi_flag_rule.flags}") + + # Test single custom flag rule + single_custom_rule = rules['single_custom_flag'] + self.assertFalse('memo' not in simple_rule.flags, + "single_custom_flag should not have memo") + self.assertEqual(single_custom_rule.flags, frozenset(['custom']), + f"single_custom_flag flags should be {'custom'}, got {single_custom_rule.flags}") + + # Test no flags rule + no_flags_rule = rules['no_flags_rule'] + self.assertFalse('memo' not in simple_rule.flags, + "no_flags_rule should not have memo") + self.assertEqual(no_flags_rule.flags, frozenset(), + f"no_flags_rule flags should be the empty set, got {no_flags_rule.flags}") diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 13424991639..66348619073 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -160,6 +160,16 @@ class TestPerfTrampoline(unittest.TestCase): self.assertIn(f"py::bar_fork:{script}", child_perf_file_contents) self.assertIn(f"py::baz_fork:{script}", child_perf_file_contents) + # The parent's map should not contain the child's symbols. + self.assertNotIn(f"py::foo_fork:{script}", perf_file_contents) + self.assertNotIn(f"py::bar_fork:{script}", perf_file_contents) + self.assertNotIn(f"py::baz_fork:{script}", perf_file_contents) + + # The child's map should not contain the parent's symbols. + self.assertNotIn(f"py::foo:{script}", child_perf_file_contents) + self.assertNotIn(f"py::bar:{script}", child_perf_file_contents) + self.assertNotIn(f"py::baz:{script}", child_perf_file_contents) + @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_sys_api(self): for define_eval_hook in (False, True): @@ -238,6 +248,24 @@ class TestPerfTrampoline(unittest.TestCase): """ assert_python_ok("-c", code, PYTHON_JIT="0") + def test_sys_api_perf_jit_backend(self): + code = """if 1: + import sys + sys.activate_stack_trampoline("perf_jit") + assert sys.is_stack_trampoline_active() is True + sys.deactivate_stack_trampoline() + assert sys.is_stack_trampoline_active() is False + """ + assert_python_ok("-c", code, PYTHON_JIT="0") + + def test_sys_api_with_existing_perf_jit_trampoline(self): + code = """if 1: + import sys + sys.activate_stack_trampoline("perf_jit") + sys.activate_stack_trampoline("perf_jit") + """ + assert_python_ok("-c", code, PYTHON_JIT="0") + def is_unwinding_reliable_with_frame_pointers(): cflags = sysconfig.get_config_var("PY_CORE_CFLAGS") diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index e2384b33345..22c70327fb0 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -59,6 +59,8 @@ class PyUnpicklerTests(AbstractUnpickleTests, unittest.TestCase): truncated_errors = (pickle.UnpicklingError, EOFError, AttributeError, ValueError, struct.error, IndexError, ImportError) + truncated_data_error = (EOFError, '') + size_overflow_error = (pickle.UnpicklingError, 'exceeds') def loads(self, buf, **kwds): f = io.BytesIO(buf) @@ -103,6 +105,8 @@ class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests, truncated_errors = (pickle.UnpicklingError, EOFError, AttributeError, ValueError, struct.error, IndexError, ImportError) + truncated_data_error = ((pickle.UnpicklingError, EOFError), '') + size_overflow_error = ((OverflowError, pickle.UnpicklingError), 'exceeds') def dumps(self, arg, protocol=None, **kwargs): return pickle.dumps(arg, protocol, **kwargs) @@ -375,6 +379,8 @@ if has_c_implementation: unpickler = _pickle.Unpickler bad_stack_errors = (pickle.UnpicklingError,) truncated_errors = (pickle.UnpicklingError,) + truncated_data_error = (pickle.UnpicklingError, 'truncated') + size_overflow_error = (OverflowError, 'exceeds') class CPicklingErrorTests(PyPicklingErrorTests): pickler = _pickle.Pickler @@ -478,7 +484,7 @@ if has_c_implementation: 0) # Write buffer is cleared after every dump(). def test_unpickler(self): - basesize = support.calcobjsize('2P2n2P 2P2n2i5P 2P3n8P2n2i') + basesize = support.calcobjsize('2P2n3P 2P2n2i5P 2P3n8P2n2i') unpickler = _pickle.Unpickler P = struct.calcsize('P') # Size of memo table entry. n = struct.calcsize('n') # Size of mark table entry. diff --git a/Lib/test/test_pickletools.py b/Lib/test/test_pickletools.py index a178d3353ee..57285ddf6eb 100644 --- a/Lib/test/test_pickletools.py +++ b/Lib/test/test_pickletools.py @@ -1,7 +1,11 @@ import io +import itertools import pickle import pickletools +import tempfile +import textwrap from test import support +from test.support import os_helper from test.pickletester import AbstractPickleTests import doctest import unittest @@ -384,13 +388,13 @@ highest protocol among opcodes = 0 self.check_dis_error(b'Sabc"\n.', '', "no string quotes around b'abc\"'") self.check_dis_error(b"S'abc\n.", '', - '''strinq quote b"'" not found at both ends of b"'abc"''') + '''string quote b"'" not found at both ends of b"'abc"''') self.check_dis_error(b'S"abc\n.', '', - r"""strinq quote b'"' not found at both ends of b'"abc'""") + r"""string quote b'"' not found at both ends of b'"abc'""") self.check_dis_error(b"S'abc\"\n.", '', - r"""strinq quote b"'" not found at both ends of b'\\'abc"'""") + r"""string quote b"'" not found at both ends of b'\\'abc"'""") self.check_dis_error(b"S\"abc'\n.", '', - r"""strinq quote b'"' not found at both ends of b'"abc\\''""") + r"""string quote b'"' not found at both ends of b'"abc\\''""") def test_binstring(self): self.check_dis(b"T\x03\x00\x00\x00abc.", '''\ @@ -514,6 +518,170 @@ class MiscTestCase(unittest.TestCase): support.check__all__(self, pickletools, not_exported=not_exported) +class CommandLineTest(unittest.TestCase): + def setUp(self): + self.filename = tempfile.mktemp() + self.addCleanup(os_helper.unlink, self.filename) + + @staticmethod + def text_normalize(string): + return textwrap.dedent(string).strip() + + def set_pickle_data(self, data): + with open(self.filename, 'wb') as f: + pickle.dump(data, f) + + def invoke_pickletools(self, *flags): + with ( + support.captured_stdout() as stdout, + support.captured_stderr() as stderr, + ): + pickletools._main(args=[*flags, self.filename]) + self.assertEqual(stderr.getvalue(), '') + return self.text_normalize(stdout.getvalue()) + + def check_output(self, data, expect, *flags): + with self.subTest(data=data, flags=flags): + self.set_pickle_data(data) + res = self.invoke_pickletools(*flags) + expect = self.text_normalize(expect) + self.assertListEqual(res.splitlines(), expect.splitlines()) + + def test_invocation(self): + # test various combinations of parameters + output_file = tempfile.mktemp() + self.addCleanup(os_helper.unlink, output_file) + base_flags = [ + (f'-o={output_file}', f'--output={output_file}'), + ('-m', '--memo'), + ('-l=2', '--indentlevel=2'), + ('-a', '--annotate'), + ('-p="Another:"', '--preamble="Another:"'), + ] + data = { 'a', 'b', 'c' } + + self.set_pickle_data(data) + + for r in range(1, len(base_flags) + 1): + for choices in itertools.combinations(base_flags, r=r): + for args in itertools.product(*choices): + with self.subTest(args=args[1:]): + self.invoke_pickletools(*args) + + def test_unknown_flag(self): + with self.assertRaises(SystemExit): + with support.captured_stderr() as stderr: + pickletools._main(args=['--unknown']) + self.assertStartsWith(stderr.getvalue(), 'usage: ') + + def test_output_flag(self): + # test 'python -m pickletools -o/--output' + output_file = tempfile.mktemp() + self.addCleanup(os_helper.unlink, output_file) + data = ('fake_data',) + expect = r''' + 0: \x80 PROTO 5 + 2: \x95 FRAME 15 + 11: \x8c SHORT_BINUNICODE 'fake_data' + 22: \x94 MEMOIZE (as 0) + 23: \x85 TUPLE1 + 24: \x94 MEMOIZE (as 1) + 25: . STOP + highest protocol among opcodes = 4 + ''' + for flag in [f'-o={output_file}', f'--output={output_file}']: + with self.subTest(data=data, flags=flag): + self.set_pickle_data(data) + res = self.invoke_pickletools(flag) + with open(output_file, 'r') as f: + res_from_file = self.text_normalize(f.read()) + expect = self.text_normalize(expect) + + self.assertListEqual(res.splitlines(), []) + self.assertListEqual(res_from_file.splitlines(), + expect.splitlines()) + + def test_memo_flag(self): + # test 'python -m pickletools -m/--memo' + data = ('fake_data',) + expect = r''' + 0: \x80 PROTO 5 + 2: \x95 FRAME 15 + 11: \x8c SHORT_BINUNICODE 'fake_data' + 22: \x94 MEMOIZE (as 0) + 23: \x85 TUPLE1 + 24: \x94 MEMOIZE (as 1) + 25: . STOP + highest protocol among opcodes = 4 + ''' + for flag in ['-m', '--memo']: + self.check_output(data, expect, flag) + + def test_indentlevel_flag(self): + # test 'python -m pickletools -l/--indentlevel' + data = ('fake_data',) + expect = r''' + 0: \x80 PROTO 5 + 2: \x95 FRAME 15 + 11: \x8c SHORT_BINUNICODE 'fake_data' + 22: \x94 MEMOIZE (as 0) + 23: \x85 TUPLE1 + 24: \x94 MEMOIZE (as 1) + 25: . STOP + highest protocol among opcodes = 4 + ''' + for flag in ['-l=2', '--indentlevel=2']: + self.check_output(data, expect, flag) + + def test_annotate_flag(self): + # test 'python -m pickletools -a/--annotate' + data = ('fake_data',) + expect = r''' + 0: \x80 PROTO 5 Protocol version indicator. + 2: \x95 FRAME 15 Indicate the beginning of a new frame. + 11: \x8c SHORT_BINUNICODE 'fake_data' Push a Python Unicode string object. + 22: \x94 MEMOIZE (as 0) Store the stack top into the memo. The stack is not popped. + 23: \x85 TUPLE1 Build a one-tuple out of the topmost item on the stack. + 24: \x94 MEMOIZE (as 1) Store the stack top into the memo. The stack is not popped. + 25: . STOP Stop the unpickling machine. + highest protocol among opcodes = 4 + ''' + for flag in ['-a', '--annotate']: + self.check_output(data, expect, flag) + + def test_preamble_flag(self): + # test 'python -m pickletools -p/--preamble' + data = ('fake_data',) + expect = r''' + Another: + 0: \x80 PROTO 5 + 2: \x95 FRAME 15 + 11: \x8c SHORT_BINUNICODE 'fake_data' + 22: \x94 MEMOIZE (as 0) + 23: \x85 TUPLE1 + 24: \x94 MEMOIZE (as 1) + 25: . STOP + highest protocol among opcodes = 4 + Another: + 0: \x80 PROTO 5 + 2: \x95 FRAME 15 + 11: \x8c SHORT_BINUNICODE 'fake_data' + 22: \x94 MEMOIZE (as 0) + 23: \x85 TUPLE1 + 24: \x94 MEMOIZE (as 1) + 25: . STOP + highest protocol among opcodes = 4 + ''' + for flag in ['-p=Another:', '--preamble=Another:']: + with self.subTest(data=data, flags=flag): + self.set_pickle_data(data) + with support.captured_stdout() as stdout: + pickletools._main(args=[flag, self.filename, self.filename]) + res = self.text_normalize(stdout.getvalue()) + expect = self.text_normalize(expect) + self.assertListEqual(res.splitlines(), expect.splitlines()) + + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite(pickletools)) return tests diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py index d2b724db40d..0a366e2a5bb 100644 --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -198,15 +198,15 @@ class TestPkg(unittest.TestCase): import t5 self.assertEqual(fixdir(dir(t5)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__', - 'foo', 'string', 't5']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__', 'foo', + 'string', 't5']) self.assertEqual(fixdir(dir(t5.foo)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', 'string']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__spec__', 'string']) self.assertEqual(fixdir(dir(t5.string)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', 'spam']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__spec__', 'spam']) def test_6(self): hier = [ @@ -221,14 +221,13 @@ class TestPkg(unittest.TestCase): import t6 self.assertEqual(fixdir(dir(t6)), - ['__all__', '__cached__', '__doc__', '__file__', - '__loader__', '__name__', '__package__', '__path__', - '__spec__']) + ['__all__', '__doc__', '__file__', '__loader__', + '__name__', '__package__', '__path__', '__spec__']) s = """ import t6 from t6 import * self.assertEqual(fixdir(dir(t6)), - ['__all__', '__cached__', '__doc__', '__file__', + ['__all__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'eggs', 'ham', 'spam']) self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6']) @@ -256,20 +255,19 @@ class TestPkg(unittest.TestCase): t7, sub, subsub = None, None, None import t7 as tas self.assertEqual(fixdir(dir(tas)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__']) self.assertFalse(t7) from t7 import sub as subpar self.assertEqual(fixdir(dir(subpar)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__']) self.assertFalse(t7) self.assertFalse(sub) from t7.sub import subsub as subsubsub self.assertEqual(fixdir(dir(subsubsub)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__', - 'spam']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__', 'spam']) self.assertFalse(t7) self.assertFalse(sub) self.assertFalse(subsub) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 2e26134bae8..9ee97b922ad 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -532,8 +532,10 @@ class PlatformTest(unittest.TestCase): self.assertEqual(override.model, "Whiz") self.assertTrue(override.is_simulator) - @unittest.skipIf(support.is_emscripten, "Does not apply to Emscripten") def test_libc_ver(self): + if support.is_emscripten: + assert platform.libc_ver() == ("emscripten", "4.0.12") + return # check that libc_ver(executable) doesn't raise an exception if os.path.isdir(sys.executable) and \ os.path.exists(sys.executable+'.exe'): @@ -565,6 +567,10 @@ class PlatformTest(unittest.TestCase): # musl uses semver, but we accept some variations anyway: (b'/aports/main/musl/src/musl-12.5', ('musl', '12.5')), (b'/aports/main/musl/src/musl-1.2.5.7', ('musl', '1.2.5.7')), + (b'libc.musl.so.1', ('musl', '1')), + (b'libc.musl-x86_64.so.1.2.5', ('musl', '1.2.5')), + (b'ld-musl.so.1', ('musl', '1')), + (b'ld-musl-x86_64.so.1.2.5', ('musl', '1.2.5')), (b'', ('', '')), ): with open(filename, 'wb') as fp: @@ -583,6 +589,14 @@ class PlatformTest(unittest.TestCase): (b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0', ('glibc', '1.23.4')), (b'libc.so.2.4\0libc.so.9\0libc.so.23.1\0', ('libc', '23.1')), (b'musl-1.4.1\0musl-2.1.1\0musl-2.0.1\0', ('musl', '2.1.1')), + ( + b'libc.musl-x86_64.so.1.4.1\0libc.musl-x86_64.so.2.1.1\0libc.musl-x86_64.so.2.0.1', + ('musl', '2.1.1'), + ), + ( + b'ld-musl-x86_64.so.1.4.1\0ld-musl-x86_64.so.2.1.1\0ld-musl-x86_64.so.2.0.1', + ('musl', '2.1.1'), + ), (b'no match here, so defaults are used', ('test', '100.1.0')), ): with open(filename, 'wb') as f: @@ -762,13 +776,14 @@ class CommandLineTest(unittest.TestCase): platform._main(args=flags) return output.getvalue() + @support.force_not_colorized def test_unknown_flag(self): + output = io.StringIO() with self.assertRaises(SystemExit): - output = io.StringIO() # suppress argparse error message with contextlib.redirect_stderr(output): _ = self.invoke_platform('--unknown') - self.assertStartsWith(output, "usage: ") + self.assertStartsWith(output.getvalue(), "usage: ") def test_invocation(self): flags = ( diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index a0c76e5dec5..de2a2fd1fc3 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -903,8 +903,7 @@ class TestPlistlib(unittest.TestCase): class TestBinaryPlistlib(unittest.TestCase): - @staticmethod - def decode(*objects, offset_size=1, ref_size=1): + def build(self, *objects, offset_size=1, ref_size=1): data = [b'bplist00'] offset = 8 offsets = [] @@ -916,7 +915,11 @@ class TestBinaryPlistlib(unittest.TestCase): len(objects), 0, offset) data.extend(offsets) data.append(tail) - return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY) + return b''.join(data) + + def decode(self, *objects, offset_size=1, ref_size=1): + data = self.build(*objects, offset_size=offset_size, ref_size=ref_size) + return plistlib.loads(data, fmt=plistlib.FMT_BINARY) def test_nonstandard_refs_size(self): # Issue #21538: Refs and offsets are 24-bit integers @@ -1024,6 +1027,34 @@ class TestBinaryPlistlib(unittest.TestCase): with self.assertRaises(plistlib.InvalidFileException): plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY) + def test_truncated_large_data(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + def check(data): + with open(os_helper.TESTFN, 'wb') as f: + f.write(data) + # buffered file + with open(os_helper.TESTFN, 'rb') as f: + with self.assertRaises(plistlib.InvalidFileException): + plistlib.load(f, fmt=plistlib.FMT_BINARY) + # unbuffered file + with open(os_helper.TESTFN, 'rb', buffering=0) as f: + with self.assertRaises(plistlib.InvalidFileException): + plistlib.load(f, fmt=plistlib.FMT_BINARY) + for w in range(20, 64): + s = 1 << w + # data + check(self.build(b'\x4f\x13' + s.to_bytes(8, 'big'))) + # ascii string + check(self.build(b'\x5f\x13' + s.to_bytes(8, 'big'))) + # unicode string + check(self.build(b'\x6f\x13' + s.to_bytes(8, 'big'))) + # array + check(self.build(b'\xaf\x13' + s.to_bytes(8, 'big'))) + # dict + check(self.build(b'\xdf\x13' + s.to_bytes(8, 'big'))) + # number of objects + check(b'bplist00' + struct.pack('>6xBBQQQ', 1, 1, s, 0, 8)) + def test_load_aware_datetime(self): data = (b'bplist003B\x04>\xd0d\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00' b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00' diff --git a/Lib/test/test_profiling/test_heatmap.py b/Lib/test/test_profiling/test_heatmap.py new file mode 100644 index 00000000000..b1bfdf868b0 --- /dev/null +++ b/Lib/test/test_profiling/test_heatmap.py @@ -0,0 +1,757 @@ +"""Tests for the heatmap collector (profiling.sampling).""" + +import os +import shutil +import tempfile +import unittest +from collections import namedtuple +from pathlib import Path + +# Matches the C structseq LocationInfo from _remote_debugging +LocationInfo = namedtuple('LocationInfo', ['lineno', 'end_lineno', 'col_offset', 'end_col_offset']) + +from profiling.sampling.heatmap_collector import ( + HeatmapCollector, + get_python_path_info, + extract_module_name, +) + +from test.support import captured_stdout, captured_stderr + + +# ============================================================================= +# Unit Tests for Public Helper Functions +# ============================================================================= + +class TestPathInfoFunctions(unittest.TestCase): + """Test public helper functions for path information.""" + + def test_get_python_path_info_returns_dict(self): + """Test that get_python_path_info returns a dictionary with expected keys.""" + path_info = get_python_path_info() + + self.assertIsInstance(path_info, dict) + self.assertIn('stdlib', path_info) + self.assertIn('site_packages', path_info) + self.assertIn('sys_path', path_info) + + def test_get_python_path_info_stdlib_is_path_or_none(self): + """Test that stdlib is either a Path object or None.""" + path_info = get_python_path_info() + + if path_info['stdlib'] is not None: + self.assertIsInstance(path_info['stdlib'], Path) + + def test_get_python_path_info_site_packages_is_list(self): + """Test that site_packages is a list.""" + path_info = get_python_path_info() + + self.assertIsInstance(path_info['site_packages'], list) + for item in path_info['site_packages']: + self.assertIsInstance(item, Path) + + def test_get_python_path_info_sys_path_is_list(self): + """Test that sys_path is a list of Path objects.""" + path_info = get_python_path_info() + + self.assertIsInstance(path_info['sys_path'], list) + for item in path_info['sys_path']: + self.assertIsInstance(item, Path) + + def test_extract_module_name_with_none(self): + """Test extract_module_name with None filename.""" + path_info = get_python_path_info() + module_name, module_type = extract_module_name(None, path_info) + + self.assertEqual(module_name, 'unknown') + self.assertEqual(module_type, 'other') + + def test_extract_module_name_with_empty_string(self): + """Test extract_module_name with empty filename.""" + path_info = get_python_path_info() + module_name, module_type = extract_module_name('', path_info) + + self.assertEqual(module_name, 'unknown') + self.assertEqual(module_type, 'other') + + def test_extract_module_name_with_stdlib_file(self): + """Test extract_module_name with a standard library file.""" + path_info = get_python_path_info() + + # Use os module as a known stdlib file + if path_info['stdlib']: + stdlib_file = str(path_info['stdlib'] / 'os.py') + module_name, module_type = extract_module_name(stdlib_file, path_info) + + self.assertEqual(module_type, 'stdlib') + self.assertIn('os', module_name) + + def test_extract_module_name_with_project_file(self): + """Test extract_module_name with a project file.""" + path_info = get_python_path_info() + + # Create a mock project file path + if path_info['sys_path']: + # Use current directory as project path + project_file = '/some/project/path/mymodule.py' + module_name, module_type = extract_module_name(project_file, path_info) + + # Should classify as 'other' if not in sys.path + self.assertIn(module_type, ['project', 'other']) + + def test_extract_module_name_removes_py_extension(self): + """Test that .py extension is removed from module names.""" + path_info = get_python_path_info() + + # Test with a simple .py file + module_name, module_type = extract_module_name('/path/to/test.py', path_info) + + # Module name should not contain .py + self.assertNotIn('.py', module_name) + + def test_extract_module_name_with_special_files(self): + """Test extract_module_name with special filenames like <string>.""" + path_info = get_python_path_info() + + special_files = ['<string>', '<stdin>', '[eval]'] + for special_file in special_files: + module_name, module_type = extract_module_name(special_file, path_info) + self.assertEqual(module_type, 'other') + + +# ============================================================================= +# Unit Tests for HeatmapCollector Public API +# ============================================================================= + +class TestHeatmapCollectorInit(unittest.TestCase): + """Test HeatmapCollector initialization.""" + + def test_init_creates_empty_data_structures(self): + """Test that __init__ creates empty data structures.""" + collector = HeatmapCollector(sample_interval_usec=100) + + # Check that data structures are initialized + self.assertIsInstance(collector.line_samples, dict) + self.assertIsInstance(collector.file_samples, dict) + self.assertIsInstance(collector.line_self_samples, dict) + self.assertIsInstance(collector.file_self_samples, dict) + self.assertIsInstance(collector.call_graph, dict) + self.assertIsInstance(collector.callers_graph, dict) + self.assertIsInstance(collector.function_definitions, dict) + self.assertIsInstance(collector.edge_samples, dict) + + # Check that they're empty + self.assertEqual(len(collector.line_samples), 0) + self.assertEqual(len(collector.file_samples), 0) + self.assertEqual(len(collector.line_self_samples), 0) + self.assertEqual(len(collector.file_self_samples), 0) + + def test_init_sets_total_samples_to_zero(self): + """Test that total samples starts at zero.""" + collector = HeatmapCollector(sample_interval_usec=100) + self.assertEqual(collector._total_samples, 0) + + def test_init_gets_path_info(self): + """Test that path info is retrieved during init.""" + collector = HeatmapCollector(sample_interval_usec=100) + self.assertIsNotNone(collector._path_info) + self.assertIn('stdlib', collector._path_info) + + +class TestHeatmapCollectorSetStats(unittest.TestCase): + """Test HeatmapCollector.set_stats() method.""" + + def test_set_stats_stores_all_parameters(self): + """Test that set_stats stores all provided parameters.""" + collector = HeatmapCollector(sample_interval_usec=100) + + collector.set_stats( + sample_interval_usec=500, + duration_sec=10.5, + sample_rate=99.5, + error_rate=0.5 + ) + + self.assertEqual(collector.stats['sample_interval_usec'], 500) + self.assertEqual(collector.stats['duration_sec'], 10.5) + self.assertEqual(collector.stats['sample_rate'], 99.5) + self.assertEqual(collector.stats['error_rate'], 0.5) + + def test_set_stats_includes_system_info(self): + """Test that set_stats includes Python and platform info.""" + collector = HeatmapCollector(sample_interval_usec=100) + collector.set_stats(sample_interval_usec=100, duration_sec=1.0, sample_rate=100.0) + + self.assertIn('python_version', collector.stats) + self.assertIn('python_implementation', collector.stats) + self.assertIn('platform', collector.stats) + + def test_set_stats_accepts_kwargs(self): + """Test that set_stats accepts additional kwargs.""" + collector = HeatmapCollector(sample_interval_usec=100) + + collector.set_stats( + sample_interval_usec=100, + duration_sec=1.0, + sample_rate=100.0, + custom_key='custom_value', + another_key=42 + ) + + self.assertEqual(collector.stats['custom_key'], 'custom_value') + self.assertEqual(collector.stats['another_key'], 42) + + def test_set_stats_with_none_error_rate(self): + """Test set_stats with error_rate=None.""" + collector = HeatmapCollector(sample_interval_usec=100) + collector.set_stats(sample_interval_usec=100, duration_sec=1.0, sample_rate=100.0) + + self.assertIn('error_rate', collector.stats) + self.assertIsNone(collector.stats['error_rate']) + + +class TestHeatmapCollectorProcessFrames(unittest.TestCase): + """Test HeatmapCollector.process_frames() method.""" + + def test_process_frames_increments_total_samples(self): + """Test that process_frames increments total samples count.""" + collector = HeatmapCollector(sample_interval_usec=100) + + initial_count = collector._total_samples + frames = [('file.py', (10, 10, -1, -1), 'func', None)] + collector.process_frames(frames, thread_id=1) + + self.assertEqual(collector._total_samples, initial_count + 1) + + def test_process_frames_records_line_samples(self): + """Test that process_frames records line samples.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('test.py', (5, 5, -1, -1), 'test_func', None)] + collector.process_frames(frames, thread_id=1) + + # Check that line was recorded + self.assertIn(('test.py', 5), collector.line_samples) + self.assertEqual(collector.line_samples[('test.py', 5)], 1) + + def test_process_frames_records_multiple_lines_in_stack(self): + """Test that process_frames records all lines in a stack.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [ + ('file1.py', (10, 10, -1, -1), 'func1', None), + ('file2.py', (20, 20, -1, -1), 'func2', None), + ('file3.py', (30, 30, -1, -1), 'func3', None) + ] + collector.process_frames(frames, thread_id=1) + + # All frames should be recorded + self.assertIn(('file1.py', 10), collector.line_samples) + self.assertIn(('file2.py', 20), collector.line_samples) + self.assertIn(('file3.py', 30), collector.line_samples) + + def test_process_frames_distinguishes_self_samples(self): + """Test that process_frames distinguishes self (leaf) samples.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [ + ('leaf.py', (5, 5, -1, -1), 'leaf_func', None), # This is the leaf (top of stack) + ('caller.py', (10, 10, -1, -1), 'caller_func', None) + ] + collector.process_frames(frames, thread_id=1) + + # Leaf should have self sample + self.assertIn(('leaf.py', 5), collector.line_self_samples) + self.assertEqual(collector.line_self_samples[('leaf.py', 5)], 1) + + # Caller should NOT have self sample + self.assertNotIn(('caller.py', 10), collector.line_self_samples) + + def test_process_frames_accumulates_samples(self): + """Test that multiple calls accumulate samples.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('file.py', (10, 10, -1, -1), 'func', None)] + + collector.process_frames(frames, thread_id=1) + collector.process_frames(frames, thread_id=1) + collector.process_frames(frames, thread_id=1) + + self.assertEqual(collector.line_samples[('file.py', 10)], 3) + self.assertEqual(collector._total_samples, 3) + + def test_process_frames_ignores_invalid_frames(self): + """Test that process_frames ignores invalid frames.""" + collector = HeatmapCollector(sample_interval_usec=100) + + # These should be ignored + invalid_frames = [ + ('<string>', (1, 1, -1, -1), 'test', None), + ('[eval]', (1, 1, -1, -1), 'test', None), + ('', (1, 1, -1, -1), 'test', None), + (None, (1, 1, -1, -1), 'test', None), + ('__init__', (0, 0, -1, -1), 'test', None), # Special invalid frame + ] + + for frame in invalid_frames: + collector.process_frames([frame], thread_id=1) + + # Should not record these invalid frames + for frame in invalid_frames: + if frame[0]: + self.assertNotIn((frame[0], frame[1][0]), collector.line_samples) + + def test_process_frames_builds_call_graph(self): + """Test that process_frames builds call graph relationships.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [ + ('callee.py', (5, 5, -1, -1), 'callee_func', None), + ('caller.py', (10, 10, -1, -1), 'caller_func', None) + ] + collector.process_frames(frames, thread_id=1) + + # Check that call relationship was recorded + caller_key = ('caller.py', 10) + self.assertIn(caller_key, collector.call_graph) + + # Check callers graph + callee_key = ('callee.py', 5) + self.assertIn(callee_key, collector.callers_graph) + + def test_process_frames_records_function_definitions(self): + """Test that process_frames records function definition locations.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('module.py', (42, 42, -1, -1), 'my_function', None)] + collector.process_frames(frames, thread_id=1) + + self.assertIn(('module.py', 'my_function'), collector.function_definitions) + self.assertEqual(collector.function_definitions[('module.py', 'my_function')], 42) + + def test_process_frames_tracks_edge_samples(self): + """Test that process_frames tracks edge sample counts.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [ + ('callee.py', (5, 5, -1, -1), 'callee', None), + ('caller.py', (10, 10, -1, -1), 'caller', None) + ] + + # Process same call stack multiple times + collector.process_frames(frames, thread_id=1) + collector.process_frames(frames, thread_id=1) + + # Check that edge count is tracked + self.assertGreater(len(collector.edge_samples), 0) + + def test_process_frames_handles_empty_frames(self): + """Test that process_frames handles empty frame list.""" + collector = HeatmapCollector(sample_interval_usec=100) + + initial_count = collector._total_samples + collector.process_frames([], thread_id=1) + + # Should still increment total samples + self.assertEqual(collector._total_samples, initial_count + 1) + + def test_process_frames_with_file_samples_dict(self): + """Test that file_samples dict is properly populated.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('test.py', (10, 10, -1, -1), 'func', None)] + collector.process_frames(frames, thread_id=1) + + self.assertIn('test.py', collector.file_samples) + self.assertIn(10, collector.file_samples['test.py']) + self.assertEqual(collector.file_samples['test.py'][10], 1) + + +class TestHeatmapCollectorExport(unittest.TestCase): + """Test HeatmapCollector.export() method.""" + + def setUp(self): + """Set up test directory.""" + self.test_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, self.test_dir) + + def test_export_creates_output_directory(self): + """Test that export creates the output directory.""" + collector = HeatmapCollector(sample_interval_usec=100) + + # Add some data + frames = [('test.py', (10, 10, -1, -1), 'func', None)] + collector.process_frames(frames, thread_id=1) + + output_path = os.path.join(self.test_dir, 'heatmap_output') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + self.assertTrue(os.path.exists(output_path)) + self.assertTrue(os.path.isdir(output_path)) + + def test_export_creates_index_html(self): + """Test that export creates index.html.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('test.py', (10, 10, -1, -1), 'func', None)] + collector.process_frames(frames, thread_id=1) + + output_path = os.path.join(self.test_dir, 'heatmap_output') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + index_path = os.path.join(output_path, 'index.html') + self.assertTrue(os.path.exists(index_path)) + + def test_export_creates_file_htmls(self): + """Test that export creates individual file HTMLs.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('test.py', (10, 10, -1, -1), 'func', None)] + collector.process_frames(frames, thread_id=1) + + output_path = os.path.join(self.test_dir, 'heatmap_output') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + # Check for file_XXXX.html files + html_files = [f for f in os.listdir(output_path) + if f.startswith('file_') and f.endswith('.html')] + self.assertGreater(len(html_files), 0) + + def test_export_with_empty_data(self): + """Test export with no data collected.""" + collector = HeatmapCollector(sample_interval_usec=100) + + output_path = os.path.join(self.test_dir, 'empty_output') + + # Should handle empty data gracefully + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + def test_export_handles_html_suffix(self): + """Test that export handles .html suffix in output path.""" + collector = HeatmapCollector(sample_interval_usec=100) + + frames = [('test.py', (10, 10, -1, -1), 'func', None)] + collector.process_frames(frames, thread_id=1) + + # Path with .html suffix should be stripped + output_path = os.path.join(self.test_dir, 'output.html') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + # Should create directory without .html + expected_dir = os.path.join(self.test_dir, 'output') + self.assertTrue(os.path.exists(expected_dir)) + + def test_export_with_multiple_files(self): + """Test export with multiple files.""" + collector = HeatmapCollector(sample_interval_usec=100) + + # Add samples for multiple files + collector.process_frames([('file1.py', (10, 10, -1, -1), 'func1', None)], thread_id=1) + collector.process_frames([('file2.py', (20, 20, -1, -1), 'func2', None)], thread_id=1) + collector.process_frames([('file3.py', (30, 30, -1, -1), 'func3', None)], thread_id=1) + + output_path = os.path.join(self.test_dir, 'multi_file') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + # Should create HTML for each file + html_files = [f for f in os.listdir(output_path) + if f.startswith('file_') and f.endswith('.html')] + self.assertGreaterEqual(len(html_files), 3) + + def test_export_index_contains_file_references(self): + """Test that index.html contains references to profiled files.""" + collector = HeatmapCollector(sample_interval_usec=100) + collector.set_stats(sample_interval_usec=100, duration_sec=1.0, sample_rate=100.0) + + frames = [('mytest.py', (10, 10, -1, -1), 'my_func', None)] + collector.process_frames(frames, thread_id=1) + + output_path = os.path.join(self.test_dir, 'test_output') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + index_path = os.path.join(output_path, 'index.html') + with open(index_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Should contain reference to the file + self.assertIn('mytest', content) + + def test_export_file_html_has_line_numbers(self): + """Test that exported file HTML contains line numbers.""" + collector = HeatmapCollector(sample_interval_usec=100) + + # Create a temporary Python file + temp_file = os.path.join(self.test_dir, 'temp_source.py') + with open(temp_file, 'w') as f: + f.write('def test():\n pass\n') + + frames = [(temp_file, (1, 1, -1, -1), 'test', None)] + collector.process_frames(frames, thread_id=1) + + output_path = os.path.join(self.test_dir, 'line_test') + + with captured_stdout(), captured_stderr(): + collector.export(output_path) + + # Find the generated file HTML + html_files = [f for f in os.listdir(output_path) + if f.startswith('file_') and f.endswith('.html')] + + if html_files: + with open(os.path.join(output_path, html_files[0]), 'r', encoding='utf-8') as f: + content = f.read() + + # Should have line-related content + self.assertIn('line-', content) + + +class MockFrameInfo: + """Mock FrameInfo for testing. + + Frame format: (filename, location, funcname, opcode) where: + - location is a tuple (lineno, end_lineno, col_offset, end_col_offset) + - opcode is an int or None + """ + + def __init__(self, filename, lineno, funcname, opcode=None): + self.filename = filename + self.funcname = funcname + self.opcode = opcode + self.location = (lineno, lineno, -1, -1) + + def __iter__(self): + return iter((self.filename, self.location, self.funcname, self.opcode)) + + def __getitem__(self, index): + return (self.filename, self.location, self.funcname, self.opcode)[index] + + def __len__(self): + return 4 + + def __repr__(self): + return f"MockFrameInfo('{self.filename}', {self.location}, '{self.funcname}', {self.opcode})" + + +class MockThreadInfo: + """Mock ThreadInfo for testing since the real one isn't accessible.""" + + def __init__(self, thread_id, frame_info, status=0): + self.thread_id = thread_id + self.frame_info = frame_info + self.status = status # Thread status flags + + def __repr__(self): + return f"MockThreadInfo(thread_id={self.thread_id}, frame_info={self.frame_info})" + + +class MockInterpreterInfo: + """Mock InterpreterInfo for testing since the real one isn't accessible.""" + + def __init__(self, interpreter_id, threads): + self.interpreter_id = interpreter_id + self.threads = threads + + def __repr__(self): + return f"MockInterpreterInfo(interpreter_id={self.interpreter_id}, threads={self.threads})" + + +class TestHeatmapCollector(unittest.TestCase): + """Tests for HeatmapCollector functionality.""" + + def test_heatmap_collector_basic(self): + """Test basic HeatmapCollector functionality.""" + collector = HeatmapCollector(sample_interval_usec=100) + + # Test empty state + self.assertEqual(len(collector.file_samples), 0) + self.assertEqual(len(collector.line_samples), 0) + + # Test collecting sample data - frames are 4-tuples: (filename, location, funcname, opcode) + test_frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo( + 1, + [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")], + )] + ) + ] + collector.collect(test_frames) + + # Should have recorded samples for the file + self.assertGreater(len(collector.line_samples), 0) + self.assertIn("file.py", collector.file_samples) + + # Check that line samples were recorded + file_data = collector.file_samples["file.py"] + self.assertGreater(len(file_data), 0) + + def test_heatmap_collector_export(self): + """Test heatmap HTML export functionality.""" + heatmap_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, heatmap_dir) + + collector = HeatmapCollector(sample_interval_usec=100) + + # Create test data with multiple files using MockFrameInfo + test_frames1 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")])], + ) + ] + test_frames2 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")])], + ) + ] # Same stack + test_frames3 = [ + MockInterpreterInfo(0, [MockThreadInfo(1, [MockFrameInfo("other.py", 5, "other_func")])]) + ] + + collector.collect(test_frames1) + collector.collect(test_frames2) + collector.collect(test_frames3) + + # Export heatmap + with (captured_stdout(), captured_stderr()): + collector.export(heatmap_dir) + + # Verify index.html was created + index_path = os.path.join(heatmap_dir, "index.html") + self.assertTrue(os.path.exists(index_path)) + self.assertGreater(os.path.getsize(index_path), 0) + + # Check index contains HTML content + with open(index_path, "r", encoding="utf-8") as f: + content = f.read() + + # Should be valid HTML + self.assertIn("<!doctype html>", content.lower()) + self.assertIn("<html", content) + self.assertIn("Tachyon Profiler", content) + + # Should contain file references + self.assertIn("file.py", content) + self.assertIn("other.py", content) + + # Verify individual file HTMLs were created + file_htmls = [f for f in os.listdir(heatmap_dir) if f.startswith("file_") and f.endswith(".html")] + self.assertGreater(len(file_htmls), 0) + + # Check one of the file HTMLs + file_html_path = os.path.join(heatmap_dir, file_htmls[0]) + with open(file_html_path, "r", encoding="utf-8") as f: + file_content = f.read() + + # Should contain heatmap styling and JavaScript + self.assertIn("line-sample", file_content) + self.assertIn("nav-btn", file_content) + + +class TestHeatmapCollectorLocation(unittest.TestCase): + """Tests for HeatmapCollector location handling.""" + + def test_heatmap_with_full_location_info(self): + """Test HeatmapCollector uses full location tuple.""" + collector = HeatmapCollector(sample_interval_usec=1000) + + # Frame with full location: (lineno, end_lineno, col_offset, end_col_offset) + frame = MockFrameInfo("test.py", 10, "func") + # Override with full location info + frame.location = LocationInfo(10, 15, 4, 20) + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame])] + ) + ] + collector.collect(frames) + + # Verify data was collected with location info + # HeatmapCollector uses file_samples dict with filename -> Counter of linenos + self.assertIn("test.py", collector.file_samples) + # Line 10 should have samples + self.assertIn(10, collector.file_samples["test.py"]) + + def test_heatmap_with_none_location(self): + """Test HeatmapCollector handles None location gracefully.""" + collector = HeatmapCollector(sample_interval_usec=1000) + + # Synthetic frame with None location + frame = MockFrameInfo("~", 0, "<native>") + frame.location = None + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame])] + ) + ] + # Should not raise + collector.collect(frames) + + def test_heatmap_export_with_location_data(self): + """Test HeatmapCollector export includes location info.""" + tmp_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, tmp_dir) + + collector = HeatmapCollector(sample_interval_usec=1000) + + frame = MockFrameInfo("test.py", 10, "process") + frame.location = LocationInfo(10, 12, 0, 30) + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame])] + ) + ] + collector.collect(frames) + + # Export should work + with (captured_stdout(), captured_stderr()): + collector.export(tmp_dir) + self.assertTrue(os.path.exists(os.path.join(tmp_dir, "index.html"))) + + def test_heatmap_collector_frame_format(self): + """Test HeatmapCollector with 4-element frame format.""" + collector = HeatmapCollector(sample_interval_usec=1000) + + frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("app.py", 100, "main", opcode=90), + MockFrameInfo("utils.py", 50, "helper", opcode=100), + MockFrameInfo("lib.py", 25, "process", opcode=None), + ], + ) + ], + ) + ] + collector.collect(frames) + + # Should have recorded data for the files + self.assertIn("app.py", collector.file_samples) + self.assertIn("utils.py", collector.file_samples) + self.assertIn("lib.py", collector.file_samples) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler.py b/Lib/test/test_profiling/test_sampling_profiler.py deleted file mode 100644 index 02ed2abc2b9..00000000000 --- a/Lib/test/test_profiling/test_sampling_profiler.py +++ /dev/null @@ -1,2248 +0,0 @@ -"""Tests for the sampling profiler (profiling.sampling).""" - -import contextlib -import io -import marshal -import os -import shutil -import socket -import subprocess -import sys -import tempfile -import unittest -from unittest import mock - -from profiling.sampling.pstats_collector import PstatsCollector -from profiling.sampling.stack_collector import ( - CollapsedStackCollector, -) - -from test.support.os_helper import unlink -from test.support import force_not_colorized_test_class, SHORT_TIMEOUT -from test.support.socket_helper import find_unused_port -from test.support import requires_subprocess, is_emscripten - -PROCESS_VM_READV_SUPPORTED = False - -try: - from _remote_debugging import PROCESS_VM_READV_SUPPORTED - import _remote_debugging -except ImportError: - raise unittest.SkipTest( - "Test only runs when _remote_debugging is available" - ) -else: - import profiling.sampling - from profiling.sampling.sample import SampleProfiler - - - -class MockFrameInfo: - """Mock FrameInfo for testing since the real one isn't accessible.""" - - def __init__(self, filename, lineno, funcname): - self.filename = filename - self.lineno = lineno - self.funcname = funcname - - def __repr__(self): - return f"MockFrameInfo(filename='{self.filename}', lineno={self.lineno}, funcname='{self.funcname}')" - - -skip_if_not_supported = unittest.skipIf( - ( - sys.platform != "darwin" - and sys.platform != "linux" - and sys.platform != "win32" - ), - "Test only runs on Linux, Windows and MacOS", -) - - -@contextlib.contextmanager -def test_subprocess(script): - # Find an unused port for socket communication - port = find_unused_port() - - # Inject socket connection code at the beginning of the script - socket_code = f''' -import socket -_test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -_test_sock.connect(('localhost', {port})) -_test_sock.sendall(b"ready") -''' - - # Combine socket code with user script - full_script = socket_code + script - - # Create server socket to wait for process to be ready - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(("localhost", port)) - server_socket.settimeout(SHORT_TIMEOUT) - server_socket.listen(1) - - proc = subprocess.Popen( - [sys.executable, "-c", full_script], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - - client_socket = None - try: - # Wait for process to connect and send ready signal - client_socket, _ = server_socket.accept() - server_socket.close() - response = client_socket.recv(1024) - if response != b"ready": - raise RuntimeError(f"Unexpected response from subprocess: {response}") - - yield proc - finally: - if client_socket is not None: - client_socket.close() - if proc.poll() is None: - proc.kill() - proc.wait() - - -def close_and_unlink(file): - file.close() - unlink(file.name) - - -class TestSampleProfilerComponents(unittest.TestCase): - """Unit tests for individual profiler components.""" - - def test_mock_frame_info_with_empty_and_unicode_values(self): - """Test MockFrameInfo handles empty strings, unicode characters, and very long names correctly.""" - # Test with empty strings - frame = MockFrameInfo("", 0, "") - self.assertEqual(frame.filename, "") - self.assertEqual(frame.lineno, 0) - self.assertEqual(frame.funcname, "") - self.assertIn("filename=''", repr(frame)) - - # Test with unicode characters - frame = MockFrameInfo("文件.py", 42, "函数名") - self.assertEqual(frame.filename, "文件.py") - self.assertEqual(frame.funcname, "函数名") - - # Test with very long names - long_filename = "x" * 1000 + ".py" - long_funcname = "func_" + "x" * 1000 - frame = MockFrameInfo(long_filename, 999999, long_funcname) - self.assertEqual(frame.filename, long_filename) - self.assertEqual(frame.lineno, 999999) - self.assertEqual(frame.funcname, long_funcname) - - def test_pstats_collector_with_extreme_intervals_and_empty_data(self): - """Test PstatsCollector handles zero/large intervals, empty frames, None thread IDs, and duplicate frames.""" - # Test with zero interval - collector = PstatsCollector(sample_interval_usec=0) - self.assertEqual(collector.sample_interval_usec, 0) - - # Test with very large interval - collector = PstatsCollector(sample_interval_usec=1000000000) - self.assertEqual(collector.sample_interval_usec, 1000000000) - - # Test collecting empty frames list - collector = PstatsCollector(sample_interval_usec=1000) - collector.collect([]) - self.assertEqual(len(collector.result), 0) - - # Test collecting frames with None thread id - test_frames = [(None, [MockFrameInfo("file.py", 10, "func")])] - collector.collect(test_frames) - # Should still process the frames - self.assertEqual(len(collector.result), 1) - - # Test collecting duplicate frames in same sample - test_frames = [ - ( - 1, - [ - MockFrameInfo("file.py", 10, "func1"), - MockFrameInfo("file.py", 10, "func1"), # Duplicate - ], - ) - ] - collector = PstatsCollector(sample_interval_usec=1000) - collector.collect(test_frames) - # Should count both occurrences - self.assertEqual( - collector.result[("file.py", 10, "func1")]["cumulative_calls"], 2 - ) - - def test_pstats_collector_single_frame_stacks(self): - """Test PstatsCollector with single-frame call stacks to trigger len(frames) <= 1 branch.""" - collector = PstatsCollector(sample_interval_usec=1000) - - # Test with exactly one frame (should trigger the <= 1 condition) - single_frame = [(1, [MockFrameInfo("single.py", 10, "single_func")])] - collector.collect(single_frame) - - # Should record the single frame with inline call - self.assertEqual(len(collector.result), 1) - single_key = ("single.py", 10, "single_func") - self.assertIn(single_key, collector.result) - self.assertEqual(collector.result[single_key]["direct_calls"], 1) - self.assertEqual(collector.result[single_key]["cumulative_calls"], 1) - - # Test with empty frames (should also trigger <= 1 condition) - empty_frames = [(1, [])] - collector.collect(empty_frames) - - # Should not add any new entries - self.assertEqual( - len(collector.result), 1 - ) # Still just the single frame - - # Test mixed single and multi-frame stacks - mixed_frames = [ - ( - 1, - [MockFrameInfo("single2.py", 20, "single_func2")], - ), # Single frame - ( - 2, - [ # Multi-frame stack - MockFrameInfo("multi.py", 30, "multi_func1"), - MockFrameInfo("multi.py", 40, "multi_func2"), - ], - ), - ] - collector.collect(mixed_frames) - - # Should have recorded all functions - self.assertEqual( - len(collector.result), 4 - ) # single + single2 + multi1 + multi2 - - # Verify single frame handling - single2_key = ("single2.py", 20, "single_func2") - self.assertIn(single2_key, collector.result) - self.assertEqual(collector.result[single2_key]["direct_calls"], 1) - self.assertEqual(collector.result[single2_key]["cumulative_calls"], 1) - - # Verify multi-frame handling still works - multi1_key = ("multi.py", 30, "multi_func1") - multi2_key = ("multi.py", 40, "multi_func2") - self.assertIn(multi1_key, collector.result) - self.assertIn(multi2_key, collector.result) - self.assertEqual(collector.result[multi1_key]["direct_calls"], 1) - self.assertEqual( - collector.result[multi2_key]["cumulative_calls"], 1 - ) # Called from multi1 - - def test_collapsed_stack_collector_with_empty_and_deep_stacks(self): - """Test CollapsedStackCollector handles empty frames, single-frame stacks, and very deep call stacks.""" - collector = CollapsedStackCollector() - - # Test with empty frames - collector.collect([]) - self.assertEqual(len(collector.call_trees), 0) - - # Test with single frame stack - test_frames = [(1, [("file.py", 10, "func")])] - collector.collect(test_frames) - self.assertEqual(len(collector.call_trees), 1) - self.assertEqual(collector.call_trees[0], [("file.py", 10, "func")]) - - # Test with very deep stack - deep_stack = [(f"file{i}.py", i, f"func{i}") for i in range(100)] - test_frames = [(1, deep_stack)] - collector = CollapsedStackCollector() - collector.collect(test_frames) - self.assertEqual(len(collector.call_trees[0]), 100) - # Check it's properly reversed - self.assertEqual( - collector.call_trees[0][0], ("file99.py", 99, "func99") - ) - self.assertEqual(collector.call_trees[0][-1], ("file0.py", 0, "func0")) - - def test_pstats_collector_basic(self): - """Test basic PstatsCollector functionality.""" - collector = PstatsCollector(sample_interval_usec=1000) - - # Test empty state - self.assertEqual(len(collector.result), 0) - self.assertEqual(len(collector.stats), 0) - - # Test collecting sample data - test_frames = [ - ( - 1, - [ - MockFrameInfo("file.py", 10, "func1"), - MockFrameInfo("file.py", 20, "func2"), - ], - ) - ] - collector.collect(test_frames) - - # Should have recorded calls for both functions - self.assertEqual(len(collector.result), 2) - self.assertIn(("file.py", 10, "func1"), collector.result) - self.assertIn(("file.py", 20, "func2"), collector.result) - - # Top-level function should have direct call - self.assertEqual( - collector.result[("file.py", 10, "func1")]["direct_calls"], 1 - ) - self.assertEqual( - collector.result[("file.py", 10, "func1")]["cumulative_calls"], 1 - ) - - # Calling function should have cumulative call but no direct calls - self.assertEqual( - collector.result[("file.py", 20, "func2")]["cumulative_calls"], 1 - ) - self.assertEqual( - collector.result[("file.py", 20, "func2")]["direct_calls"], 0 - ) - - def test_pstats_collector_create_stats(self): - """Test PstatsCollector stats creation.""" - collector = PstatsCollector( - sample_interval_usec=1000000 - ) # 1 second intervals - - test_frames = [ - ( - 1, - [ - MockFrameInfo("file.py", 10, "func1"), - MockFrameInfo("file.py", 20, "func2"), - ], - ) - ] - collector.collect(test_frames) - collector.collect(test_frames) # Collect twice - - collector.create_stats() - - # Check stats format: (direct_calls, cumulative_calls, tt, ct, callers) - func1_stats = collector.stats[("file.py", 10, "func1")] - self.assertEqual(func1_stats[0], 2) # direct_calls (top of stack) - self.assertEqual(func1_stats[1], 2) # cumulative_calls - self.assertEqual( - func1_stats[2], 2.0 - ) # tt (total time - 2 samples * 1 sec) - self.assertEqual(func1_stats[3], 2.0) # ct (cumulative time) - - func2_stats = collector.stats[("file.py", 20, "func2")] - self.assertEqual( - func2_stats[0], 0 - ) # direct_calls (never top of stack) - self.assertEqual( - func2_stats[1], 2 - ) # cumulative_calls (appears in stack) - self.assertEqual(func2_stats[2], 0.0) # tt (no direct calls) - self.assertEqual(func2_stats[3], 2.0) # ct (cumulative time) - - def test_collapsed_stack_collector_basic(self): - collector = CollapsedStackCollector() - - # Test empty state - self.assertEqual(len(collector.call_trees), 0) - self.assertEqual(len(collector.function_samples), 0) - - # Test collecting sample data - test_frames = [ - (1, [("file.py", 10, "func1"), ("file.py", 20, "func2")]) - ] - collector.collect(test_frames) - - # Should store call tree (reversed) - self.assertEqual(len(collector.call_trees), 1) - expected_tree = [("file.py", 20, "func2"), ("file.py", 10, "func1")] - self.assertEqual(collector.call_trees[0], expected_tree) - - # Should count function samples - self.assertEqual( - collector.function_samples[("file.py", 10, "func1")], 1 - ) - self.assertEqual( - collector.function_samples[("file.py", 20, "func2")], 1 - ) - - def test_collapsed_stack_collector_export(self): - collapsed_out = tempfile.NamedTemporaryFile(delete=False) - self.addCleanup(close_and_unlink, collapsed_out) - - collector = CollapsedStackCollector() - - test_frames1 = [ - (1, [("file.py", 10, "func1"), ("file.py", 20, "func2")]) - ] - test_frames2 = [ - (1, [("file.py", 10, "func1"), ("file.py", 20, "func2")]) - ] # Same stack - test_frames3 = [(1, [("other.py", 5, "other_func")])] - - collector.collect(test_frames1) - collector.collect(test_frames2) - collector.collect(test_frames3) - - collector.export(collapsed_out.name) - # Check file contents - with open(collapsed_out.name, "r") as f: - content = f.read() - - lines = content.strip().split("\n") - self.assertEqual(len(lines), 2) # Two unique stacks - - # Check collapsed format: file:func:line;file:func:line count - stack1_expected = "file.py:func2:20;file.py:func1:10 2" - stack2_expected = "other.py:other_func:5 1" - - self.assertIn(stack1_expected, lines) - self.assertIn(stack2_expected, lines) - - def test_pstats_collector_export(self): - collector = PstatsCollector( - sample_interval_usec=1000000 - ) # 1 second intervals - - test_frames1 = [ - ( - 1, - [ - MockFrameInfo("file.py", 10, "func1"), - MockFrameInfo("file.py", 20, "func2"), - ], - ) - ] - test_frames2 = [ - ( - 1, - [ - MockFrameInfo("file.py", 10, "func1"), - MockFrameInfo("file.py", 20, "func2"), - ], - ) - ] # Same stack - test_frames3 = [(1, [MockFrameInfo("other.py", 5, "other_func")])] - - collector.collect(test_frames1) - collector.collect(test_frames2) - collector.collect(test_frames3) - - pstats_out = tempfile.NamedTemporaryFile( - suffix=".pstats", delete=False - ) - self.addCleanup(close_and_unlink, pstats_out) - collector.export(pstats_out.name) - - # Check file can be loaded with marshal - with open(pstats_out.name, "rb") as f: - stats_data = marshal.load(f) - - # Should be a dictionary with the sampled marker - self.assertIsInstance(stats_data, dict) - self.assertIn(("__sampled__",), stats_data) - self.assertTrue(stats_data[("__sampled__",)]) - - # Should have function data - function_entries = [ - k for k in stats_data.keys() if k != ("__sampled__",) - ] - self.assertGreater(len(function_entries), 0) - - # Check specific function stats format: (cc, nc, tt, ct, callers) - func1_key = ("file.py", 10, "func1") - func2_key = ("file.py", 20, "func2") - other_key = ("other.py", 5, "other_func") - - self.assertIn(func1_key, stats_data) - self.assertIn(func2_key, stats_data) - self.assertIn(other_key, stats_data) - - # Check func1 stats (should have 2 samples) - func1_stats = stats_data[func1_key] - self.assertEqual(func1_stats[0], 2) # total_calls - self.assertEqual(func1_stats[1], 2) # nc (non-recursive calls) - self.assertEqual(func1_stats[2], 2.0) # tt (total time) - self.assertEqual(func1_stats[3], 2.0) # ct (cumulative time) - - -class TestSampleProfiler(unittest.TestCase): - """Test the SampleProfiler class.""" - - def test_sample_profiler_initialization(self): - """Test SampleProfiler initialization with various parameters.""" - from profiling.sampling.sample import SampleProfiler - - # Mock RemoteUnwinder to avoid permission issues - with mock.patch( - "_remote_debugging.RemoteUnwinder" - ) as mock_unwinder_class: - mock_unwinder_class.return_value = mock.MagicMock() - - # Test basic initialization - profiler = SampleProfiler( - pid=12345, sample_interval_usec=1000, all_threads=False - ) - self.assertEqual(profiler.pid, 12345) - self.assertEqual(profiler.sample_interval_usec, 1000) - self.assertEqual(profiler.all_threads, False) - - # Test with all_threads=True - profiler = SampleProfiler( - pid=54321, sample_interval_usec=5000, all_threads=True - ) - self.assertEqual(profiler.pid, 54321) - self.assertEqual(profiler.sample_interval_usec, 5000) - self.assertEqual(profiler.all_threads, True) - - def test_sample_profiler_sample_method_timing(self): - """Test that the sample method respects duration and handles timing correctly.""" - from profiling.sampling.sample import SampleProfiler - - # Mock the unwinder to avoid needing a real process - mock_unwinder = mock.MagicMock() - mock_unwinder.get_stack_trace.return_value = [ - ( - 1, - [ - mock.MagicMock( - filename="test.py", lineno=10, funcname="test_func" - ) - ], - ) - ] - - with mock.patch( - "_remote_debugging.RemoteUnwinder" - ) as mock_unwinder_class: - mock_unwinder_class.return_value = mock_unwinder - - profiler = SampleProfiler( - pid=12345, sample_interval_usec=100000, all_threads=False - ) # 100ms interval - - # Mock collector - mock_collector = mock.MagicMock() - - # Mock time to control the sampling loop - start_time = 1000.0 - times = [ - start_time + i * 0.1 for i in range(12) - ] # 0, 0.1, 0.2, ..., 1.1 seconds - - with mock.patch("time.perf_counter", side_effect=times): - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - profiler.sample(mock_collector, duration_sec=1) - - result = output.getvalue() - - # Should have captured approximately 10 samples (1 second / 0.1 second interval) - self.assertIn("Captured", result) - self.assertIn("samples", result) - - # Verify collector was called multiple times - self.assertGreaterEqual(mock_collector.collect.call_count, 5) - self.assertLessEqual(mock_collector.collect.call_count, 11) - - def test_sample_profiler_error_handling(self): - """Test that the sample method handles errors gracefully.""" - from profiling.sampling.sample import SampleProfiler - - # Mock unwinder that raises errors - mock_unwinder = mock.MagicMock() - error_sequence = [ - RuntimeError("Process died"), - [ - ( - 1, - [ - mock.MagicMock( - filename="test.py", lineno=10, funcname="test_func" - ) - ], - ) - ], - UnicodeDecodeError("utf-8", b"", 0, 1, "invalid"), - [ - ( - 1, - [ - mock.MagicMock( - filename="test.py", - lineno=20, - funcname="test_func2", - ) - ], - ) - ], - OSError("Permission denied"), - ] - mock_unwinder.get_stack_trace.side_effect = error_sequence - - with mock.patch( - "_remote_debugging.RemoteUnwinder" - ) as mock_unwinder_class: - mock_unwinder_class.return_value = mock_unwinder - - profiler = SampleProfiler( - pid=12345, sample_interval_usec=10000, all_threads=False - ) - - mock_collector = mock.MagicMock() - - # Control timing to run exactly 5 samples - times = [0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06] - - with mock.patch("time.perf_counter", side_effect=times): - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - profiler.sample(mock_collector, duration_sec=0.05) - - result = output.getvalue() - - # Should report error rate - self.assertIn("Error rate:", result) - self.assertIn("%", result) - - # Collector should have been called only for successful samples (should be > 0) - self.assertGreater(mock_collector.collect.call_count, 0) - self.assertLessEqual(mock_collector.collect.call_count, 3) - - def test_sample_profiler_missed_samples_warning(self): - """Test that the profiler warns about missed samples when sampling is too slow.""" - from profiling.sampling.sample import SampleProfiler - - mock_unwinder = mock.MagicMock() - mock_unwinder.get_stack_trace.return_value = [ - ( - 1, - [ - mock.MagicMock( - filename="test.py", lineno=10, funcname="test_func" - ) - ], - ) - ] - - with mock.patch( - "_remote_debugging.RemoteUnwinder" - ) as mock_unwinder_class: - mock_unwinder_class.return_value = mock_unwinder - - # Use very short interval that we'll miss - profiler = SampleProfiler( - pid=12345, sample_interval_usec=1000, all_threads=False - ) # 1ms interval - - mock_collector = mock.MagicMock() - - # Simulate slow sampling where we miss many samples - times = [ - 0.0, - 0.1, - 0.2, - 0.3, - 0.4, - 0.5, - 0.6, - 0.7, - ] # Extra time points to avoid StopIteration - - with mock.patch("time.perf_counter", side_effect=times): - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - profiler.sample(mock_collector, duration_sec=0.5) - - result = output.getvalue() - - # Should warn about missed samples - self.assertIn("Warning: missed", result) - self.assertIn("samples from the expected total", result) - - -@force_not_colorized_test_class -class TestPrintSampledStats(unittest.TestCase): - """Test the print_sampled_stats function.""" - - def setUp(self): - """Set up test data.""" - # Mock stats data - self.mock_stats = mock.MagicMock() - self.mock_stats.stats = { - ("file1.py", 10, "func1"): ( - 100, - 100, - 0.5, - 0.5, - {}, - ), # cc, nc, tt, ct, callers - ("file2.py", 20, "func2"): (50, 50, 0.25, 0.3, {}), - ("file3.py", 30, "func3"): (200, 200, 1.5, 2.0, {}), - ("file4.py", 40, "func4"): ( - 10, - 10, - 0.001, - 0.001, - {}, - ), # millisecond range - ("file5.py", 50, "func5"): ( - 5, - 5, - 0.000001, - 0.000002, - {}, - ), # microsecond range - } - - def test_print_sampled_stats_basic(self): - """Test basic print_sampled_stats functionality.""" - from profiling.sampling.sample import print_sampled_stats - - # Capture output - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats(self.mock_stats, sample_interval_usec=100) - - result = output.getvalue() - - # Check header is present - self.assertIn("Profile Stats:", result) - self.assertIn("nsamples", result) - self.assertIn("tottime", result) - self.assertIn("cumtime", result) - - # Check functions are present - self.assertIn("func1", result) - self.assertIn("func2", result) - self.assertIn("func3", result) - - def test_print_sampled_stats_sorting(self): - """Test different sorting options.""" - from profiling.sampling.sample import print_sampled_stats - - # Test sort by calls - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, sort=0, sample_interval_usec=100 - ) - - result = output.getvalue() - lines = result.strip().split("\n") - - # Find the data lines (skip header) - data_lines = [l for l in lines if "file" in l and ".py" in l] - # func3 should be first (200 calls) - self.assertIn("func3", data_lines[0]) - - # Test sort by time - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, sort=1, sample_interval_usec=100 - ) - - result = output.getvalue() - lines = result.strip().split("\n") - - data_lines = [l for l in lines if "file" in l and ".py" in l] - # func3 should be first (1.5s time) - self.assertIn("func3", data_lines[0]) - - def test_print_sampled_stats_limit(self): - """Test limiting output rows.""" - from profiling.sampling.sample import print_sampled_stats - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, limit=2, sample_interval_usec=100 - ) - - result = output.getvalue() - - # Count function entries in the main stats section (not in summary) - lines = result.split("\n") - # Find where the main stats section ends (before summary) - main_section_lines = [] - for line in lines: - if "Summary of Interesting Functions:" in line: - break - main_section_lines.append(line) - - # Count function entries only in main section - func_count = sum( - 1 - for line in main_section_lines - if "func" in line and ".py" in line - ) - self.assertEqual(func_count, 2) - - def test_print_sampled_stats_time_units(self): - """Test proper time unit selection.""" - from profiling.sampling.sample import print_sampled_stats - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats(self.mock_stats, sample_interval_usec=100) - - result = output.getvalue() - - # Should use seconds for the header since max time is > 1s - self.assertIn("tottime (s)", result) - self.assertIn("cumtime (s)", result) - - # Test with only microsecond-range times - micro_stats = mock.MagicMock() - micro_stats.stats = { - ("file1.py", 10, "func1"): (100, 100, 0.000005, 0.000010, {}), - } - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats(micro_stats, sample_interval_usec=100) - - result = output.getvalue() - - # Should use microseconds - self.assertIn("tottime (μs)", result) - self.assertIn("cumtime (μs)", result) - - def test_print_sampled_stats_summary(self): - """Test summary section generation.""" - from profiling.sampling.sample import print_sampled_stats - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, - show_summary=True, - sample_interval_usec=100, - ) - - result = output.getvalue() - - # Check summary sections are present - self.assertIn("Summary of Interesting Functions:", result) - self.assertIn( - "Functions with Highest Direct/Cumulative Ratio (Hot Spots):", - result, - ) - self.assertIn( - "Functions with Highest Call Frequency (Indirect Calls):", result - ) - self.assertIn( - "Functions with Highest Call Magnification (Cumulative/Direct):", - result, - ) - - def test_print_sampled_stats_no_summary(self): - """Test disabling summary output.""" - from profiling.sampling.sample import print_sampled_stats - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, - show_summary=False, - sample_interval_usec=100, - ) - - result = output.getvalue() - - # Summary should not be present - self.assertNotIn("Summary of Interesting Functions:", result) - - def test_print_sampled_stats_empty_stats(self): - """Test with empty stats.""" - from profiling.sampling.sample import print_sampled_stats - - empty_stats = mock.MagicMock() - empty_stats.stats = {} - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats(empty_stats, sample_interval_usec=100) - - result = output.getvalue() - - # Should still print header - self.assertIn("Profile Stats:", result) - - def test_print_sampled_stats_sample_percentage_sorting(self): - """Test sample percentage sorting options.""" - from profiling.sampling.sample import print_sampled_stats - - # Add a function with high sample percentage (more direct calls than func3's 200) - self.mock_stats.stats[("expensive.py", 60, "expensive_func")] = ( - 300, # direct calls (higher than func3's 200) - 300, # cumulative calls - 1.0, # total time - 1.0, # cumulative time - {}, - ) - - # Test sort by sample percentage - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, sort=3, sample_interval_usec=100 - ) # sample percentage - - result = output.getvalue() - lines = result.strip().split("\n") - - data_lines = [l for l in lines if ".py" in l and "func" in l] - # expensive_func should be first (highest sample percentage) - self.assertIn("expensive_func", data_lines[0]) - - def test_print_sampled_stats_with_recursive_calls(self): - """Test print_sampled_stats with recursive calls where nc != cc.""" - from profiling.sampling.sample import print_sampled_stats - - # Create stats with recursive calls (nc != cc) - recursive_stats = mock.MagicMock() - recursive_stats.stats = { - # (direct_calls, cumulative_calls, tt, ct, callers) - recursive function - ("recursive.py", 10, "factorial"): ( - 5, # direct_calls - 10, # cumulative_calls (appears more times in stack due to recursion) - 0.5, - 0.6, - {}, - ), - ("normal.py", 20, "normal_func"): ( - 3, # direct_calls - 3, # cumulative_calls (same as direct for non-recursive) - 0.2, - 0.2, - {}, - ), - } - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats(recursive_stats, sample_interval_usec=100) - - result = output.getvalue() - - # Should display recursive calls as "5/10" format - self.assertIn("5/10", result) # nc/cc format for recursive calls - self.assertIn("3", result) # just nc for non-recursive calls - self.assertIn("factorial", result) - self.assertIn("normal_func", result) - - def test_print_sampled_stats_with_zero_call_counts(self): - """Test print_sampled_stats with zero call counts to trigger division protection.""" - from profiling.sampling.sample import print_sampled_stats - - # Create stats with zero call counts - zero_stats = mock.MagicMock() - zero_stats.stats = { - ("file.py", 10, "zero_calls"): (0, 0, 0.0, 0.0, {}), # Zero calls - ("file.py", 20, "normal_func"): ( - 5, - 5, - 0.1, - 0.1, - {}, - ), # Normal function - } - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats(zero_stats, sample_interval_usec=100) - - result = output.getvalue() - - # Should handle zero call counts gracefully - self.assertIn("zero_calls", result) - self.assertIn("zero_calls", result) - self.assertIn("normal_func", result) - - def test_print_sampled_stats_sort_by_name(self): - """Test sort by function name option.""" - from profiling.sampling.sample import print_sampled_stats - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - self.mock_stats, sort=-1, sample_interval_usec=100 - ) # sort by name - - result = output.getvalue() - lines = result.strip().split("\n") - - # Find the data lines (skip header and summary) - # Data lines start with whitespace and numbers, and contain filename:lineno(function) - data_lines = [] - for line in lines: - # Skip header lines and summary sections - if ( - line.startswith(" ") - and "(" in line - and ")" in line - and not line.startswith( - " 1." - ) # Skip summary lines that start with times - and not line.startswith( - " 0." - ) # Skip summary lines that start with times - and not "per call" in line # Skip summary lines - and not "calls" in line # Skip summary lines - and not "total time" in line # Skip summary lines - and not "cumulative time" in line - ): # Skip summary lines - data_lines.append(line) - - # Extract just the function names for comparison - func_names = [] - import re - - for line in data_lines: - # Function name is between the last ( and ), accounting for ANSI color codes - match = re.search(r"\(([^)]+)\)$", line) - if match: - func_name = match.group(1) - # Remove ANSI color codes - func_name = re.sub(r"\x1b\[[0-9;]*m", "", func_name) - func_names.append(func_name) - - # Verify we extracted function names and they are sorted - self.assertGreater( - len(func_names), 0, "Should have extracted some function names" - ) - self.assertEqual( - func_names, - sorted(func_names), - f"Function names {func_names} should be sorted alphabetically", - ) - - def test_print_sampled_stats_with_zero_time_functions(self): - """Test summary sections with functions that have zero time.""" - from profiling.sampling.sample import print_sampled_stats - - # Create stats with zero-time functions - zero_time_stats = mock.MagicMock() - zero_time_stats.stats = { - ("file1.py", 10, "zero_time_func"): ( - 5, - 5, - 0.0, - 0.0, - {}, - ), # Zero time - ("file2.py", 20, "normal_func"): ( - 3, - 3, - 0.1, - 0.1, - {}, - ), # Normal time - } - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - zero_time_stats, - show_summary=True, - sample_interval_usec=100, - ) - - result = output.getvalue() - - # Should handle zero-time functions gracefully in summary - self.assertIn("Summary of Interesting Functions:", result) - self.assertIn("zero_time_func", result) - self.assertIn("normal_func", result) - - def test_print_sampled_stats_with_malformed_qualified_names(self): - """Test summary generation with function names that don't contain colons.""" - from profiling.sampling.sample import print_sampled_stats - - # Create stats with function names that would create malformed qualified names - malformed_stats = mock.MagicMock() - malformed_stats.stats = { - # Function name without clear module separation - ("no_colon_func", 10, "func"): (3, 3, 0.1, 0.1, {}), - ("", 20, "empty_filename_func"): (2, 2, 0.05, 0.05, {}), - ("normal.py", 30, "normal_func"): (5, 5, 0.2, 0.2, {}), - } - - with io.StringIO() as output: - with mock.patch("sys.stdout", output): - print_sampled_stats( - malformed_stats, - show_summary=True, - sample_interval_usec=100, - ) - - result = output.getvalue() - - # Should handle malformed names gracefully in summary aggregation - self.assertIn("Summary of Interesting Functions:", result) - # All function names should appear somewhere in the output - self.assertIn("func", result) - self.assertIn("empty_filename_func", result) - self.assertIn("normal_func", result) - - def test_print_sampled_stats_with_recursive_call_stats_creation(self): - """Test create_stats with recursive call data to trigger total_rec_calls branch.""" - collector = PstatsCollector(sample_interval_usec=1000000) # 1 second - - # Simulate recursive function data where total_rec_calls would be set - # We need to manually manipulate the collector result to test this branch - collector.result = { - ("recursive.py", 10, "factorial"): { - "total_rec_calls": 3, # Non-zero recursive calls - "direct_calls": 5, - "cumulative_calls": 10, - }, - ("normal.py", 20, "normal_func"): { - "total_rec_calls": 0, # Zero recursive calls - "direct_calls": 2, - "cumulative_calls": 5, - }, - } - - collector.create_stats() - - # Check that recursive calls are handled differently from non-recursive - factorial_stats = collector.stats[("recursive.py", 10, "factorial")] - normal_stats = collector.stats[("normal.py", 20, "normal_func")] - - # factorial should use cumulative_calls (10) as nc - self.assertEqual( - factorial_stats[1], 10 - ) # nc should be cumulative_calls - self.assertEqual(factorial_stats[0], 5) # cc should be direct_calls - - # normal_func should use cumulative_calls as nc - self.assertEqual(normal_stats[1], 5) # nc should be cumulative_calls - self.assertEqual(normal_stats[0], 2) # cc should be direct_calls - - -@skip_if_not_supported -@unittest.skipIf( - sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, - "Test only runs on Linux with process_vm_readv support", -) -class TestRecursiveFunctionProfiling(unittest.TestCase): - """Test profiling of recursive functions and complex call patterns.""" - - def test_recursive_function_call_counting(self): - """Test that recursive function calls are counted correctly.""" - collector = PstatsCollector(sample_interval_usec=1000) - - # Simulate a recursive call pattern: fibonacci(5) calling itself - recursive_frames = [ - ( - 1, - [ # First sample: deep in recursion - MockFrameInfo("fib.py", 10, "fibonacci"), - MockFrameInfo("fib.py", 10, "fibonacci"), # recursive call - MockFrameInfo( - "fib.py", 10, "fibonacci" - ), # deeper recursion - MockFrameInfo("fib.py", 10, "fibonacci"), # even deeper - MockFrameInfo("main.py", 5, "main"), # main caller - ], - ), - ( - 1, - [ # Second sample: different recursion depth - MockFrameInfo("fib.py", 10, "fibonacci"), - MockFrameInfo("fib.py", 10, "fibonacci"), # recursive call - MockFrameInfo("main.py", 5, "main"), # main caller - ], - ), - ( - 1, - [ # Third sample: back to deeper recursion - MockFrameInfo("fib.py", 10, "fibonacci"), - MockFrameInfo("fib.py", 10, "fibonacci"), - MockFrameInfo("fib.py", 10, "fibonacci"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - ] - - for frames in recursive_frames: - collector.collect([frames]) - - collector.create_stats() - - # Check that recursive calls are counted properly - fib_key = ("fib.py", 10, "fibonacci") - main_key = ("main.py", 5, "main") - - self.assertIn(fib_key, collector.stats) - self.assertIn(main_key, collector.stats) - - # Fibonacci should have many calls due to recursion - fib_stats = collector.stats[fib_key] - direct_calls, cumulative_calls, tt, ct, callers = fib_stats - - # Should have recorded multiple calls (9 total appearances in samples) - self.assertEqual(cumulative_calls, 9) - self.assertGreater(tt, 0) # Should have some total time - self.assertGreater(ct, 0) # Should have some cumulative time - - # Main should have fewer calls - main_stats = collector.stats[main_key] - main_direct_calls, main_cumulative_calls = main_stats[0], main_stats[1] - self.assertEqual(main_direct_calls, 0) # Never directly executing - self.assertEqual(main_cumulative_calls, 3) # Appears in all 3 samples - - def test_nested_function_hierarchy(self): - """Test profiling of deeply nested function calls.""" - collector = PstatsCollector(sample_interval_usec=1000) - - # Simulate a deep call hierarchy - deep_call_frames = [ - ( - 1, - [ - MockFrameInfo("level1.py", 10, "level1_func"), - MockFrameInfo("level2.py", 20, "level2_func"), - MockFrameInfo("level3.py", 30, "level3_func"), - MockFrameInfo("level4.py", 40, "level4_func"), - MockFrameInfo("level5.py", 50, "level5_func"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - ( - 1, - [ # Same hierarchy sampled again - MockFrameInfo("level1.py", 10, "level1_func"), - MockFrameInfo("level2.py", 20, "level2_func"), - MockFrameInfo("level3.py", 30, "level3_func"), - MockFrameInfo("level4.py", 40, "level4_func"), - MockFrameInfo("level5.py", 50, "level5_func"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - ] - - for frames in deep_call_frames: - collector.collect([frames]) - - collector.create_stats() - - # All levels should be recorded - for level in range(1, 6): - key = (f"level{level}.py", level * 10, f"level{level}_func") - self.assertIn(key, collector.stats) - - stats = collector.stats[key] - direct_calls, cumulative_calls, tt, ct, callers = stats - - # Each level should appear in stack twice (2 samples) - self.assertEqual(cumulative_calls, 2) - - # Only level1 (deepest) should have direct calls - if level == 1: - self.assertEqual(direct_calls, 2) - else: - self.assertEqual(direct_calls, 0) - - # Deeper levels should have lower cumulative time than higher levels - # (since they don't include time from functions they call) - if level == 1: # Deepest level with most time - self.assertGreater(ct, 0) - - def test_alternating_call_patterns(self): - """Test profiling with alternating call patterns.""" - collector = PstatsCollector(sample_interval_usec=1000) - - # Simulate alternating execution paths - pattern_frames = [ - # Pattern A: path through func_a - ( - 1, - [ - MockFrameInfo("module.py", 10, "func_a"), - MockFrameInfo("module.py", 30, "shared_func"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - # Pattern B: path through func_b - ( - 1, - [ - MockFrameInfo("module.py", 20, "func_b"), - MockFrameInfo("module.py", 30, "shared_func"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - # Pattern A again - ( - 1, - [ - MockFrameInfo("module.py", 10, "func_a"), - MockFrameInfo("module.py", 30, "shared_func"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - # Pattern B again - ( - 1, - [ - MockFrameInfo("module.py", 20, "func_b"), - MockFrameInfo("module.py", 30, "shared_func"), - MockFrameInfo("main.py", 5, "main"), - ], - ), - ] - - for frames in pattern_frames: - collector.collect([frames]) - - collector.create_stats() - - # Check that both paths are recorded equally - func_a_key = ("module.py", 10, "func_a") - func_b_key = ("module.py", 20, "func_b") - shared_key = ("module.py", 30, "shared_func") - main_key = ("main.py", 5, "main") - - # func_a and func_b should each be directly executing twice - self.assertEqual(collector.stats[func_a_key][0], 2) # direct_calls - self.assertEqual(collector.stats[func_a_key][1], 2) # cumulative_calls - self.assertEqual(collector.stats[func_b_key][0], 2) # direct_calls - self.assertEqual(collector.stats[func_b_key][1], 2) # cumulative_calls - - # shared_func should appear in all samples (4 times) but never directly executing - self.assertEqual(collector.stats[shared_key][0], 0) # direct_calls - self.assertEqual(collector.stats[shared_key][1], 4) # cumulative_calls - - # main should appear in all samples but never directly executing - self.assertEqual(collector.stats[main_key][0], 0) # direct_calls - self.assertEqual(collector.stats[main_key][1], 4) # cumulative_calls - - def test_collapsed_stack_with_recursion(self): - """Test collapsed stack collector with recursive patterns.""" - collector = CollapsedStackCollector() - - # Recursive call pattern - recursive_frames = [ - ( - 1, - [ - ("factorial.py", 10, "factorial"), - ("factorial.py", 10, "factorial"), # recursive - ("factorial.py", 10, "factorial"), # deeper - ("main.py", 5, "main"), - ], - ), - ( - 1, - [ - ("factorial.py", 10, "factorial"), - ("factorial.py", 10, "factorial"), # different depth - ("main.py", 5, "main"), - ], - ), - ] - - for frames in recursive_frames: - collector.collect([frames]) - - # Should capture both call trees - self.assertEqual(len(collector.call_trees), 2) - - # First tree should be longer (deeper recursion) - tree1 = collector.call_trees[0] - tree2 = collector.call_trees[1] - - # Trees should be different lengths due to different recursion depths - self.assertNotEqual(len(tree1), len(tree2)) - - # Both should contain factorial calls - self.assertTrue(any("factorial" in str(frame) for frame in tree1)) - self.assertTrue(any("factorial" in str(frame) for frame in tree2)) - - # Function samples should count all occurrences - factorial_key = ("factorial.py", 10, "factorial") - main_key = ("main.py", 5, "main") - - # factorial appears 5 times total (3 + 2) - self.assertEqual(collector.function_samples[factorial_key], 5) - # main appears 2 times total - self.assertEqual(collector.function_samples[main_key], 2) - - -@requires_subprocess() -@skip_if_not_supported -class TestSampleProfilerIntegration(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.test_script = ''' -import time -import os - -def slow_fibonacci(n): - """Recursive fibonacci - should show up prominently in profiler.""" - if n <= 1: - return n - return slow_fibonacci(n-1) + slow_fibonacci(n-2) - -def cpu_intensive_work(): - """CPU intensive work that should show in profiler.""" - result = 0 - for i in range(10000): - result += i * i - if i % 100 == 0: - result = result % 1000000 - return result - -def medium_computation(): - """Medium complexity function.""" - result = 0 - for i in range(100): - result += i * i - return result - -def fast_loop(): - """Fast simple loop.""" - total = 0 - for i in range(50): - total += i - return total - -def nested_calls(): - """Test nested function calls.""" - def level1(): - def level2(): - return medium_computation() - return level2() - return level1() - -def main_loop(): - """Main test loop with different execution paths.""" - iteration = 0 - - while True: - iteration += 1 - - # Different execution paths - focus on CPU intensive work - if iteration % 3 == 0: - # Very CPU intensive - result = cpu_intensive_work() - elif iteration % 5 == 0: - # Expensive recursive operation - result = slow_fibonacci(12) - else: - # Medium operation - result = nested_calls() - - # No sleep - keep CPU busy - -if __name__ == "__main__": - main_loop() -''' - - def test_sampling_basic_functionality(self): - with ( - test_subprocess(self.test_script) as proc, - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - ): - try: - profiling.sampling.sample.sample( - proc.pid, - duration_sec=2, - sample_interval_usec=1000, # 1ms - show_summary=False, - ) - except PermissionError: - self.skipTest("Insufficient permissions for remote profiling") - - output = captured_output.getvalue() - - # Basic checks on output - self.assertIn("Captured", output) - self.assertIn("samples", output) - self.assertIn("Profile Stats", output) - - # Should see some of our test functions - self.assertIn("slow_fibonacci", output) - - def test_sampling_with_pstats_export(self): - pstats_out = tempfile.NamedTemporaryFile( - suffix=".pstats", delete=False - ) - self.addCleanup(close_and_unlink, pstats_out) - - with test_subprocess(self.test_script) as proc: - # Suppress profiler output when testing file export - with ( - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - ): - try: - profiling.sampling.sample.sample( - proc.pid, - duration_sec=1, - filename=pstats_out.name, - sample_interval_usec=10000, - ) - except PermissionError: - self.skipTest( - "Insufficient permissions for remote profiling" - ) - - # Verify file was created and contains valid data - self.assertTrue(os.path.exists(pstats_out.name)) - self.assertGreater(os.path.getsize(pstats_out.name), 0) - - # Try to load the stats file - with open(pstats_out.name, "rb") as f: - stats_data = marshal.load(f) - - # Should be a dictionary with the sampled marker - self.assertIsInstance(stats_data, dict) - self.assertIn(("__sampled__",), stats_data) - self.assertTrue(stats_data[("__sampled__",)]) - - # Should have some function data - function_entries = [ - k for k in stats_data.keys() if k != ("__sampled__",) - ] - self.assertGreater(len(function_entries), 0) - - def test_sampling_with_collapsed_export(self): - collapsed_file = tempfile.NamedTemporaryFile( - suffix=".txt", delete=False - ) - self.addCleanup(close_and_unlink, collapsed_file) - - with ( - test_subprocess(self.test_script) as proc, - ): - # Suppress profiler output when testing file export - with ( - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - ): - try: - profiling.sampling.sample.sample( - proc.pid, - duration_sec=1, - filename=collapsed_file.name, - output_format="collapsed", - sample_interval_usec=10000, - ) - except PermissionError: - self.skipTest( - "Insufficient permissions for remote profiling" - ) - - # Verify file was created and contains valid data - self.assertTrue(os.path.exists(collapsed_file.name)) - self.assertGreater(os.path.getsize(collapsed_file.name), 0) - - # Check file format - with open(collapsed_file.name, "r") as f: - content = f.read() - - lines = content.strip().split("\n") - self.assertGreater(len(lines), 0) - - # Each line should have format: stack_trace count - for line in lines: - parts = line.rsplit(" ", 1) - self.assertEqual(len(parts), 2) - - stack_trace, count_str = parts - self.assertGreater(len(stack_trace), 0) - self.assertTrue(count_str.isdigit()) - self.assertGreater(int(count_str), 0) - - # Stack trace should contain semicolon-separated entries - if ";" in stack_trace: - stack_parts = stack_trace.split(";") - for part in stack_parts: - # Each part should be file:function:line - self.assertIn(":", part) - - def test_sampling_all_threads(self): - with ( - test_subprocess(self.test_script) as proc, - # Suppress profiler output - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - ): - try: - profiling.sampling.sample.sample( - proc.pid, - duration_sec=1, - all_threads=True, - sample_interval_usec=10000, - show_summary=False, - ) - except PermissionError: - self.skipTest("Insufficient permissions for remote profiling") - - # Just verify that sampling completed without error - # We're not testing output format here - - def test_sample_target_script(self): - script_file = tempfile.NamedTemporaryFile(delete=False) - script_file.write(self.test_script.encode("utf-8")) - script_file.flush() - self.addCleanup(close_and_unlink, script_file) - - test_args = ["profiling.sampling.sample", "-d", "1", script_file.name] - - with ( - mock.patch("sys.argv", test_args), - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - ): - try: - profiling.sampling.sample.main() - except PermissionError: - self.skipTest("Insufficient permissions for remote profiling") - - output = captured_output.getvalue() - - # Basic checks on output - self.assertIn("Captured", output) - self.assertIn("samples", output) - self.assertIn("Profile Stats", output) - - # Should see some of our test functions - self.assertIn("slow_fibonacci", output) - - - def test_sample_target_module(self): - tempdir = tempfile.TemporaryDirectory(delete=False) - self.addCleanup(lambda x: shutil.rmtree(x), tempdir.name) - - module_path = os.path.join(tempdir.name, "test_module.py") - - with open(module_path, "w") as f: - f.write(self.test_script) - - test_args = ["profiling.sampling.sample", "-d", "1", "-m", "test_module"] - - with ( - mock.patch("sys.argv", test_args), - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - # Change to temp directory so subprocess can find the module - contextlib.chdir(tempdir.name), - ): - try: - profiling.sampling.sample.main() - except PermissionError: - self.skipTest("Insufficient permissions for remote profiling") - - output = captured_output.getvalue() - - # Basic checks on output - self.assertIn("Captured", output) - self.assertIn("samples", output) - self.assertIn("Profile Stats", output) - - # Should see some of our test functions - self.assertIn("slow_fibonacci", output) - - -@skip_if_not_supported -@unittest.skipIf( - sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, - "Test only runs on Linux with process_vm_readv support", -) -class TestSampleProfilerErrorHandling(unittest.TestCase): - def test_invalid_pid(self): - with self.assertRaises((OSError, RuntimeError)): - profiling.sampling.sample.sample(-1, duration_sec=1) - - def test_process_dies_during_sampling(self): - with test_subprocess("import time; time.sleep(0.5); exit()") as proc: - with ( - io.StringIO() as captured_output, - mock.patch("sys.stdout", captured_output), - ): - try: - profiling.sampling.sample.sample( - proc.pid, - duration_sec=2, # Longer than process lifetime - sample_interval_usec=50000, - ) - except PermissionError: - self.skipTest( - "Insufficient permissions for remote profiling" - ) - - output = captured_output.getvalue() - - self.assertIn("Error rate", output) - - def test_invalid_output_format(self): - with self.assertRaises(ValueError): - profiling.sampling.sample.sample( - os.getpid(), - duration_sec=1, - output_format="invalid_format", - ) - - def test_invalid_output_format_with_mocked_profiler(self): - """Test invalid output format with proper mocking to avoid permission issues.""" - with mock.patch( - "profiling.sampling.sample.SampleProfiler" - ) as mock_profiler_class: - mock_profiler = mock.MagicMock() - mock_profiler_class.return_value = mock_profiler - - with self.assertRaises(ValueError) as cm: - profiling.sampling.sample.sample( - 12345, - duration_sec=1, - output_format="unknown_format", - ) - - # Should raise ValueError with the invalid format name - self.assertIn( - "Invalid output format: unknown_format", str(cm.exception) - ) - - def test_is_process_running(self): - with test_subprocess("import time; time.sleep(1000)") as proc: - try: - profiler = SampleProfiler(pid=proc.pid, sample_interval_usec=1000, all_threads=False) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) - self.assertTrue(profiler._is_process_running()) - self.assertIsNotNone(profiler.unwinder.get_stack_trace()) - proc.kill() - proc.wait() - self.assertRaises(ProcessLookupError, profiler.unwinder.get_stack_trace) - - # Exit the context manager to ensure the process is terminated - self.assertFalse(profiler._is_process_running()) - self.assertRaises(ProcessLookupError, profiler.unwinder.get_stack_trace) - - @unittest.skipUnless(sys.platform == "linux", "Only valid on Linux") - def test_esrch_signal_handling(self): - with test_subprocess("import time; time.sleep(1000)") as proc: - try: - unwinder = _remote_debugging.RemoteUnwinder(proc.pid) - except PermissionError: - self.skipTest( - "Insufficient permissions to read the stack trace" - ) - initial_trace = unwinder.get_stack_trace() - self.assertIsNotNone(initial_trace) - - proc.kill() - - # Wait for the process to die and try to get another trace - proc.wait() - - with self.assertRaises(ProcessLookupError): - unwinder.get_stack_trace() - - - -class TestSampleProfilerCLI(unittest.TestCase): - def _setup_sync_mocks(self, mock_socket, mock_popen): - """Helper to set up socket and process mocks for coordinator tests.""" - # Mock the sync socket with context manager support - mock_sock_instance = mock.MagicMock() - mock_sock_instance.getsockname.return_value = ("127.0.0.1", 12345) - - # Mock the connection with context manager support - mock_conn = mock.MagicMock() - mock_conn.recv.return_value = b"ready" - mock_conn.__enter__.return_value = mock_conn - mock_conn.__exit__.return_value = None - - # Mock accept() to return (connection, address) and support indexing - mock_accept_result = mock.MagicMock() - mock_accept_result.__getitem__.return_value = mock_conn # [0] returns the connection - mock_sock_instance.accept.return_value = mock_accept_result - - # Mock socket with context manager support - mock_sock_instance.__enter__.return_value = mock_sock_instance - mock_sock_instance.__exit__.return_value = None - mock_socket.return_value = mock_sock_instance - - # Mock the subprocess - mock_process = mock.MagicMock() - mock_process.pid = 12345 - mock_process.poll.return_value = None - mock_popen.return_value = mock_process - return mock_process - - def _verify_coordinator_command(self, mock_popen, expected_target_args): - """Helper to verify the coordinator command was called correctly.""" - args, kwargs = mock_popen.call_args - coordinator_cmd = args[0] - self.assertEqual(coordinator_cmd[0], sys.executable) - self.assertEqual(coordinator_cmd[1], "-m") - self.assertEqual(coordinator_cmd[2], "profiling.sampling._sync_coordinator") - self.assertEqual(coordinator_cmd[3], "12345") # port - # cwd is coordinator_cmd[4] - self.assertEqual(coordinator_cmd[5:], expected_target_args) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_module_argument_parsing(self): - test_args = ["profiling.sampling.sample", "-m", "mymodule"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - self._setup_sync_mocks(mock_socket, mock_popen) - profiling.sampling.sample.main() - - self._verify_coordinator_command(mock_popen, ("-m", "mymodule")) - mock_sample.assert_called_once_with( - 12345, - sort=2, # default sort (sort_value from args.sort) - sample_interval_usec=100, - duration_sec=10, - filename=None, - all_threads=False, - limit=15, - show_summary=True, - output_format="pstats", - realtime_stats=False, - ) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_module_with_arguments(self): - test_args = ["profiling.sampling.sample", "-m", "mymodule", "arg1", "arg2", "--flag"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - self._setup_sync_mocks(mock_socket, mock_popen) - profiling.sampling.sample.main() - - self._verify_coordinator_command(mock_popen, ("-m", "mymodule", "arg1", "arg2", "--flag")) - mock_sample.assert_called_once_with( - 12345, - sort=2, - sample_interval_usec=100, - duration_sec=10, - filename=None, - all_threads=False, - limit=15, - show_summary=True, - output_format="pstats", - realtime_stats=False, - ) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_script_argument_parsing(self): - test_args = ["profiling.sampling.sample", "myscript.py"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - self._setup_sync_mocks(mock_socket, mock_popen) - profiling.sampling.sample.main() - - self._verify_coordinator_command(mock_popen, ("myscript.py",)) - mock_sample.assert_called_once_with( - 12345, - sort=2, - sample_interval_usec=100, - duration_sec=10, - filename=None, - all_threads=False, - limit=15, - show_summary=True, - output_format="pstats", - realtime_stats=False, - ) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_script_with_arguments(self): - test_args = ["profiling.sampling.sample", "myscript.py", "arg1", "arg2", "--flag"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - # Use the helper to set up mocks consistently - mock_process = self._setup_sync_mocks(mock_socket, mock_popen) - # Override specific behavior for this test - mock_process.wait.side_effect = [subprocess.TimeoutExpired(test_args, 0.1), None] - - profiling.sampling.sample.main() - - # Verify the coordinator command was called - args, kwargs = mock_popen.call_args - coordinator_cmd = args[0] - self.assertEqual(coordinator_cmd[0], sys.executable) - self.assertEqual(coordinator_cmd[1], "-m") - self.assertEqual(coordinator_cmd[2], "profiling.sampling._sync_coordinator") - self.assertEqual(coordinator_cmd[3], "12345") # port - # cwd is coordinator_cmd[4] - self.assertEqual(coordinator_cmd[5:], ("myscript.py", "arg1", "arg2", "--flag")) - - def test_cli_mutually_exclusive_pid_module(self): - test_args = ["profiling.sampling.sample", "-p", "12345", "-m", "mymodule"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("sys.stderr", io.StringIO()) as mock_stderr, - self.assertRaises(SystemExit) as cm, - ): - profiling.sampling.sample.main() - - self.assertEqual(cm.exception.code, 2) # argparse error - error_msg = mock_stderr.getvalue() - self.assertIn("not allowed with argument", error_msg) - - def test_cli_mutually_exclusive_pid_script(self): - test_args = ["profiling.sampling.sample", "-p", "12345", "myscript.py"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("sys.stderr", io.StringIO()) as mock_stderr, - self.assertRaises(SystemExit) as cm, - ): - profiling.sampling.sample.main() - - self.assertEqual(cm.exception.code, 2) # argparse error - error_msg = mock_stderr.getvalue() - self.assertIn("only one target type can be specified", error_msg) - - def test_cli_no_target_specified(self): - test_args = ["profiling.sampling.sample", "-d", "5"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("sys.stderr", io.StringIO()) as mock_stderr, - self.assertRaises(SystemExit) as cm, - ): - profiling.sampling.sample.main() - - self.assertEqual(cm.exception.code, 2) # argparse error - error_msg = mock_stderr.getvalue() - self.assertIn("one of the arguments", error_msg) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_module_with_profiler_options(self): - test_args = [ - "profiling.sampling.sample", "-i", "1000", "-d", "30", "-a", - "--sort-tottime", "-l", "20", "-m", "mymodule", - ] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - self._setup_sync_mocks(mock_socket, mock_popen) - profiling.sampling.sample.main() - - self._verify_coordinator_command(mock_popen, ("-m", "mymodule")) - mock_sample.assert_called_once_with( - 12345, - sort=1, # sort-tottime - sample_interval_usec=1000, - duration_sec=30, - filename=None, - all_threads=True, - limit=20, - show_summary=True, - output_format="pstats", - realtime_stats=False, - ) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_script_with_profiler_options(self): - """Test script with various profiler options.""" - test_args = [ - "profiling.sampling.sample", "-i", "2000", "-d", "60", - "--collapsed", "-o", "output.txt", - "myscript.py", "scriptarg", - ] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - self._setup_sync_mocks(mock_socket, mock_popen) - profiling.sampling.sample.main() - - self._verify_coordinator_command(mock_popen, ("myscript.py", "scriptarg")) - # Verify profiler options were passed correctly - mock_sample.assert_called_once_with( - 12345, - sort=2, # default sort - sample_interval_usec=2000, - duration_sec=60, - filename="output.txt", - all_threads=False, - limit=15, - show_summary=True, - output_format="collapsed", - realtime_stats=False, - ) - - def test_cli_empty_module_name(self): - test_args = ["profiling.sampling.sample", "-m"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("sys.stderr", io.StringIO()) as mock_stderr, - self.assertRaises(SystemExit) as cm, - ): - profiling.sampling.sample.main() - - self.assertEqual(cm.exception.code, 2) # argparse error - error_msg = mock_stderr.getvalue() - self.assertIn("argument -m/--module: expected one argument", error_msg) - - @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") - def test_cli_long_module_option(self): - test_args = ["profiling.sampling.sample", "--module", "mymodule", "arg1"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("subprocess.Popen") as mock_popen, - mock.patch("socket.socket") as mock_socket, - ): - self._setup_sync_mocks(mock_socket, mock_popen) - profiling.sampling.sample.main() - - self._verify_coordinator_command(mock_popen, ("-m", "mymodule", "arg1")) - - def test_cli_complex_script_arguments(self): - test_args = [ - "profiling.sampling.sample", "script.py", - "--input", "file.txt", "-v", "--output=/tmp/out", "positional" - ] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - mock.patch("profiling.sampling.sample._run_with_sync") as mock_run_with_sync, - ): - mock_process = mock.MagicMock() - mock_process.pid = 12345 - mock_process.wait.side_effect = [subprocess.TimeoutExpired(test_args, 0.1), None] - mock_process.poll.return_value = None - mock_run_with_sync.return_value = mock_process - - profiling.sampling.sample.main() - - mock_run_with_sync.assert_called_once_with(( - sys.executable, "script.py", - "--input", "file.txt", "-v", "--output=/tmp/out", "positional", - )) - - def test_cli_collapsed_format_validation(self): - """Test that CLI properly validates incompatible options with collapsed format.""" - test_cases = [ - # Test sort options are invalid with collapsed - ( - ["profiling.sampling.sample", "--collapsed", "--sort-nsamples", "-p", "12345"], - "sort", - ), - ( - ["profiling.sampling.sample", "--collapsed", "--sort-tottime", "-p", "12345"], - "sort", - ), - ( - [ - "profiling.sampling.sample", - "--collapsed", - "--sort-cumtime", - "-p", - "12345", - ], - "sort", - ), - ( - [ - "profiling.sampling.sample", - "--collapsed", - "--sort-sample-pct", - "-p", - "12345", - ], - "sort", - ), - ( - [ - "profiling.sampling.sample", - "--collapsed", - "--sort-cumul-pct", - "-p", - "12345", - ], - "sort", - ), - ( - ["profiling.sampling.sample", "--collapsed", "--sort-name", "-p", "12345"], - "sort", - ), - # Test limit option is invalid with collapsed - (["profiling.sampling.sample", "--collapsed", "-l", "20", "-p", "12345"], "limit"), - ( - ["profiling.sampling.sample", "--collapsed", "--limit", "20", "-p", "12345"], - "limit", - ), - # Test no-summary option is invalid with collapsed - ( - ["profiling.sampling.sample", "--collapsed", "--no-summary", "-p", "12345"], - "summary", - ), - ] - - for test_args, expected_error_keyword in test_cases: - with ( - mock.patch("sys.argv", test_args), - mock.patch("sys.stderr", io.StringIO()) as mock_stderr, - self.assertRaises(SystemExit) as cm, - ): - profiling.sampling.sample.main() - - self.assertEqual(cm.exception.code, 2) # argparse error code - error_msg = mock_stderr.getvalue() - self.assertIn("error:", error_msg) - self.assertIn("--pstats format", error_msg) - - def test_cli_default_collapsed_filename(self): - """Test that collapsed format gets a default filename when not specified.""" - test_args = ["profiling.sampling.sample", "--collapsed", "-p", "12345"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - ): - profiling.sampling.sample.main() - - # Check that filename was set to default collapsed format - mock_sample.assert_called_once() - call_args = mock_sample.call_args[1] - self.assertEqual(call_args["output_format"], "collapsed") - self.assertEqual(call_args["filename"], "collapsed.12345.txt") - - def test_cli_custom_output_filenames(self): - """Test custom output filenames for both formats.""" - test_cases = [ - ( - ["profiling.sampling.sample", "--pstats", "-o", "custom.pstats", "-p", "12345"], - "custom.pstats", - "pstats", - ), - ( - ["profiling.sampling.sample", "--collapsed", "-o", "custom.txt", "-p", "12345"], - "custom.txt", - "collapsed", - ), - ] - - for test_args, expected_filename, expected_format in test_cases: - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - ): - profiling.sampling.sample.main() - - mock_sample.assert_called_once() - call_args = mock_sample.call_args[1] - self.assertEqual(call_args["filename"], expected_filename) - self.assertEqual(call_args["output_format"], expected_format) - - def test_cli_missing_required_arguments(self): - """Test that CLI requires PID argument.""" - with ( - mock.patch("sys.argv", ["profiling.sampling.sample"]), - mock.patch("sys.stderr", io.StringIO()), - ): - with self.assertRaises(SystemExit): - profiling.sampling.sample.main() - - def test_cli_mutually_exclusive_format_options(self): - """Test that pstats and collapsed options are mutually exclusive.""" - with ( - mock.patch( - "sys.argv", - ["profiling.sampling.sample", "--pstats", "--collapsed", "-p", "12345"], - ), - mock.patch("sys.stderr", io.StringIO()), - ): - with self.assertRaises(SystemExit): - profiling.sampling.sample.main() - - def test_argument_parsing_basic(self): - test_args = ["profiling.sampling.sample", "-p", "12345"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - ): - profiling.sampling.sample.main() - - mock_sample.assert_called_once_with( - 12345, - sample_interval_usec=100, - duration_sec=10, - filename=None, - all_threads=False, - limit=15, - sort=2, - show_summary=True, - output_format="pstats", - realtime_stats=False, - ) - - def test_sort_options(self): - sort_options = [ - ("--sort-nsamples", 0), - ("--sort-tottime", 1), - ("--sort-cumtime", 2), - ("--sort-sample-pct", 3), - ("--sort-cumul-pct", 4), - ("--sort-name", -1), - ] - - for option, expected_sort_value in sort_options: - test_args = ["profiling.sampling.sample", option, "-p", "12345"] - - with ( - mock.patch("sys.argv", test_args), - mock.patch("profiling.sampling.sample.sample") as mock_sample, - ): - profiling.sampling.sample.main() - - mock_sample.assert_called_once() - call_args = mock_sample.call_args[1] - self.assertEqual( - call_args["sort"], - expected_sort_value, - ) - mock_sample.reset_mock() - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/__init__.py b/Lib/test/test_profiling/test_sampling_profiler/__init__.py new file mode 100644 index 00000000000..616ae5b49f0 --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/__init__.py @@ -0,0 +1,9 @@ +"""Tests for the sampling profiler (profiling.sampling).""" + +import os +from test.support import load_package_tests + + +def load_tests(*args): + """Load all tests from this subpackage.""" + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_profiling/test_sampling_profiler/_live_collector_helpers.py b/Lib/test/test_profiling/test_sampling_profiler/_live_collector_helpers.py new file mode 100644 index 00000000000..2c672895099 --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/_live_collector_helpers.py @@ -0,0 +1,62 @@ +"""Common test helpers and mocks for live collector tests.""" + +from collections import namedtuple + +from profiling.sampling.constants import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, +) + + +# Matches the C structseq LocationInfo from _remote_debugging +LocationInfo = namedtuple('LocationInfo', ['lineno', 'end_lineno', 'col_offset', 'end_col_offset']) + + +class MockFrameInfo: + """Mock FrameInfo for testing. + + Frame format: (filename, location, funcname, opcode) where: + - location is a tuple (lineno, end_lineno, col_offset, end_col_offset) + - opcode is an int or None + """ + + def __init__(self, filename, lineno, funcname, opcode=None): + self.filename = filename + self.funcname = funcname + self.opcode = opcode + self.location = LocationInfo(lineno, lineno, -1, -1) + + def __iter__(self): + return iter((self.filename, self.location, self.funcname, self.opcode)) + + def __getitem__(self, index): + return (self.filename, self.location, self.funcname, self.opcode)[index] + + def __len__(self): + return 4 + + def __repr__(self): + return f"MockFrameInfo('{self.filename}', {self.location}, '{self.funcname}', {self.opcode})" + + +class MockThreadInfo: + """Mock ThreadInfo for testing.""" + + def __init__(self, thread_id, frame_info, status=THREAD_STATUS_HAS_GIL | THREAD_STATUS_ON_CPU): + self.thread_id = thread_id + self.frame_info = frame_info + self.status = status + + def __repr__(self): + return f"MockThreadInfo(thread_id={self.thread_id}, frame_info={self.frame_info}, status={self.status})" + + +class MockInterpreterInfo: + """Mock InterpreterInfo for testing.""" + + def __init__(self, interpreter_id, threads): + self.interpreter_id = interpreter_id + self.threads = threads + + def __repr__(self): + return f"MockInterpreterInfo(interpreter_id={self.interpreter_id}, threads={self.threads})" diff --git a/Lib/test/test_profiling/test_sampling_profiler/helpers.py b/Lib/test/test_profiling/test_sampling_profiler/helpers.py new file mode 100644 index 00000000000..0e32d8dd9ea --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/helpers.py @@ -0,0 +1,176 @@ +"""Helper utilities for sampling profiler tests.""" + +import contextlib +import socket +import subprocess +import sys +import unittest +from collections import namedtuple + +from test.support import SHORT_TIMEOUT +from test.support.socket_helper import find_unused_port +from test.support.os_helper import unlink + + +PROCESS_VM_READV_SUPPORTED = False + +try: + from _remote_debugging import PROCESS_VM_READV_SUPPORTED # noqa: F401 + import _remote_debugging # noqa: F401 +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) +else: + import profiling.sampling # noqa: F401 + from profiling.sampling.sample import SampleProfiler # noqa: F401 + + +skip_if_not_supported = unittest.skipIf( + ( + sys.platform != "darwin" + and sys.platform != "linux" + and sys.platform != "win32" + ), + "Test only runs on Linux, Windows and MacOS", +) + +SubprocessInfo = namedtuple("SubprocessInfo", ["process", "socket"]) + + +def _wait_for_signal(sock, expected_signals, timeout=SHORT_TIMEOUT): + """ + Wait for expected signal(s) from a socket with proper timeout and EOF handling. + + Args: + sock: Connected socket to read from + expected_signals: Single bytes object or list of bytes objects to wait for + timeout: Socket timeout in seconds + + Returns: + bytes: Complete accumulated response buffer + + Raises: + RuntimeError: If connection closed before signal received or timeout + """ + if isinstance(expected_signals, bytes): + expected_signals = [expected_signals] + + sock.settimeout(timeout) + buffer = b"" + + while True: + # Check if all expected signals are in buffer + if all(sig in buffer for sig in expected_signals): + return buffer + + try: + chunk = sock.recv(4096) + if not chunk: + raise RuntimeError( + f"Connection closed before receiving expected signals. " + f"Expected: {expected_signals}, Got: {buffer[-200:]!r}" + ) + buffer += chunk + except socket.timeout: + raise RuntimeError( + f"Timeout waiting for signals. " + f"Expected: {expected_signals}, Got: {buffer[-200:]!r}" + ) from None + except OSError as e: + raise RuntimeError( + f"Socket error while waiting for signals: {e}. " + f"Expected: {expected_signals}, Got: {buffer[-200:]!r}" + ) from None + + +def _cleanup_sockets(*sockets): + """Safely close multiple sockets, ignoring errors.""" + for sock in sockets: + if sock is not None: + try: + sock.close() + except OSError: + pass + + +def _cleanup_process(proc, timeout=SHORT_TIMEOUT): + """Terminate a process gracefully, escalating to kill if needed.""" + if proc.poll() is not None: + return + proc.terminate() + try: + proc.wait(timeout=timeout) + return + except subprocess.TimeoutExpired: + pass + proc.kill() + try: + proc.wait(timeout=timeout) + except subprocess.TimeoutExpired: + pass # Process refuses to die, nothing more we can do + + +@contextlib.contextmanager +def test_subprocess(script, wait_for_working=False): + """Context manager to create a test subprocess with socket synchronization. + + Args: + script: Python code to execute in the subprocess. If wait_for_working + is True, script should send b"working" after starting work. + wait_for_working: If True, wait for both "ready" and "working" signals. + Default False for backward compatibility. + + Yields: + SubprocessInfo: Named tuple with process and socket objects + """ + # Find an unused port for socket communication + port = find_unused_port() + + # Inject socket connection code at the beginning of the script + socket_code = f""" +import socket +_test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +_test_sock.connect(('localhost', {port})) +_test_sock.sendall(b"ready") +""" + + # Combine socket code with user script + full_script = socket_code + script + + # Create server socket to wait for process to be ready + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_socket.bind(("localhost", port)) + server_socket.settimeout(SHORT_TIMEOUT) + server_socket.listen(1) + + proc = subprocess.Popen( + [sys.executable, "-c", full_script], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + client_socket = None + try: + # Wait for process to connect and send ready signal + client_socket, _ = server_socket.accept() + server_socket.close() + server_socket = None + + # Wait for ready signal, and optionally working signal + if wait_for_working: + _wait_for_signal(client_socket, [b"ready", b"working"]) + else: + _wait_for_signal(client_socket, b"ready") + + yield SubprocessInfo(proc, client_socket) + finally: + _cleanup_sockets(client_socket, server_socket) + _cleanup_process(proc) + + +def close_and_unlink(file): + """Close a file and unlink it from the filesystem.""" + file.close() + unlink(file.name) diff --git a/Lib/test/test_profiling/test_sampling_profiler/mocks.py b/Lib/test/test_profiling/test_sampling_profiler/mocks.py new file mode 100644 index 00000000000..4e0f7a87c6d --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/mocks.py @@ -0,0 +1,93 @@ +"""Mock classes for sampling profiler tests.""" + +from collections import namedtuple + +# Matches the C structseq LocationInfo from _remote_debugging +LocationInfo = namedtuple('LocationInfo', ['lineno', 'end_lineno', 'col_offset', 'end_col_offset']) + + +class MockFrameInfo: + """Mock FrameInfo for testing. + + Frame format: (filename, location, funcname, opcode) where: + - location is a tuple (lineno, end_lineno, col_offset, end_col_offset) + - opcode is an int or None + """ + + def __init__(self, filename, lineno, funcname, opcode=None): + self.filename = filename + self.funcname = funcname + self.opcode = opcode + self.location = LocationInfo(lineno, lineno, -1, -1) + + def __iter__(self): + return iter((self.filename, self.location, self.funcname, self.opcode)) + + def __getitem__(self, index): + return (self.filename, self.location, self.funcname, self.opcode)[index] + + def __len__(self): + return 4 + + def __repr__(self): + return f"MockFrameInfo('{self.filename}', {self.location}, '{self.funcname}', {self.opcode})" + + +class MockThreadInfo: + """Mock ThreadInfo for testing since the real one isn't accessible.""" + + def __init__( + self, thread_id, frame_info, status=0 + ): # Default to THREAD_STATE_RUNNING (0) + self.thread_id = thread_id + self.frame_info = frame_info + self.status = status + + def __repr__(self): + return f"MockThreadInfo(thread_id={self.thread_id}, frame_info={self.frame_info}, status={self.status})" + + +class MockInterpreterInfo: + """Mock InterpreterInfo for testing since the real one isn't accessible.""" + + def __init__(self, interpreter_id, threads): + self.interpreter_id = interpreter_id + self.threads = threads + + def __repr__(self): + return f"MockInterpreterInfo(interpreter_id={self.interpreter_id}, threads={self.threads})" + + +class MockCoroInfo: + """Mock CoroInfo for testing async tasks.""" + + def __init__(self, task_name, call_stack): + self.task_name = task_name # In reality, this is the parent task ID + self.call_stack = call_stack + + def __repr__(self): + return f"MockCoroInfo(task_name={self.task_name}, call_stack={self.call_stack})" + + +class MockTaskInfo: + """Mock TaskInfo for testing async tasks.""" + + def __init__(self, task_id, task_name, coroutine_stack, awaited_by=None): + self.task_id = task_id + self.task_name = task_name + self.coroutine_stack = coroutine_stack # List of CoroInfo objects + self.awaited_by = awaited_by or [] # List of CoroInfo objects (parents) + + def __repr__(self): + return f"MockTaskInfo(task_id={self.task_id}, task_name={self.task_name})" + + +class MockAwaitedInfo: + """Mock AwaitedInfo for testing async tasks.""" + + def __init__(self, thread_id, awaited_by): + self.thread_id = thread_id + self.awaited_by = awaited_by # List of TaskInfo objects + + def __repr__(self): + return f"MockAwaitedInfo(thread_id={self.thread_id}, awaited_by={len(self.awaited_by)} tasks)" diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py b/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py new file mode 100644 index 00000000000..ef9ea64b67a --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py @@ -0,0 +1,238 @@ +"""Tests for advanced sampling profiler features (GC tracking, native frames, ProcessPoolExecutor support).""" + +import io +import os +import subprocess +import tempfile +import unittest +from unittest import mock + +try: + import _remote_debugging # noqa: F401 + import profiling.sampling + import profiling.sampling.sample +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from test.support import ( + SHORT_TIMEOUT, + SuppressCrashReport, + os_helper, + requires_remote_subprocess_debugging, + script_helper, +) + +from .helpers import close_and_unlink, test_subprocess + + +@requires_remote_subprocess_debugging() +class TestGCFrameTracking(unittest.TestCase): + """Tests for GC frame tracking in the sampling profiler.""" + + @classmethod + def setUpClass(cls): + """Create a static test script with GC frames and CPU-intensive work.""" + cls.gc_test_script = ''' +import gc + +class ExpensiveGarbage: + def __init__(self): + self.cycle = self + + def __del__(self): + result = 0 + for i in range(100000): + result += i * i + if i % 1000 == 0: + result = result % 1000000 + +_test_sock.sendall(b"working") +while True: + ExpensiveGarbage() + gc.collect() +''' + + def test_gc_frames_enabled(self): + """Test that GC frames appear when gc tracking is enabled.""" + with ( + test_subprocess(self.gc_test_script, wait_for_working=True) as subproc, + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + from profiling.sampling.pstats_collector import PstatsCollector + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=1, + native=False, + gc=True, + ) + collector.print_stats(show_summary=False) + + output = captured_output.getvalue() + + # Should capture samples + self.assertIn("Captured", output) + self.assertIn("samples", output) + + # GC frames should be present + self.assertIn("<GC>", output) + + def test_gc_frames_disabled(self): + """Test that GC frames do not appear when gc tracking is disabled.""" + with ( + test_subprocess(self.gc_test_script, wait_for_working=True) as subproc, + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + from profiling.sampling.pstats_collector import PstatsCollector + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=1, + native=False, + gc=False, + ) + collector.print_stats(show_summary=False) + + output = captured_output.getvalue() + + # Should capture samples + self.assertIn("Captured", output) + self.assertIn("samples", output) + + # GC frames should NOT be present + self.assertNotIn("<GC>", output) + + +@requires_remote_subprocess_debugging() +class TestNativeFrameTracking(unittest.TestCase): + """Tests for native frame tracking in the sampling profiler.""" + + @classmethod + def setUpClass(cls): + """Create a static test script with native frames and CPU-intensive work.""" + cls.native_test_script = """ +import operator + +def inner(): + for _ in range(1_000_0000): + pass + +_test_sock.sendall(b"working") +while True: + operator.call(inner) +""" + + def test_native_frames_enabled(self): + """Test that native frames appear when native tracking is enabled.""" + collapsed_file = tempfile.NamedTemporaryFile( + suffix=".txt", delete=False + ) + self.addCleanup(close_and_unlink, collapsed_file) + + with test_subprocess(self.native_test_script, wait_for_working=True) as subproc: + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + from profiling.sampling.stack_collector import CollapsedStackCollector + collector = CollapsedStackCollector(1000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=1, + native=True, + ) + collector.export(collapsed_file.name) + + # Verify file was created and contains valid data + self.assertTrue(os.path.exists(collapsed_file.name)) + self.assertGreater(os.path.getsize(collapsed_file.name), 0) + + # Check file format + with open(collapsed_file.name, "r") as f: + content = f.read() + + lines = content.strip().split("\n") + self.assertGreater(len(lines), 0) + + stacks = [line.rsplit(" ", 1)[0] for line in lines] + + # Most samples should have native code in the middle of the stack: + self.assertTrue(any(";<native>;" in stack for stack in stacks)) + + # No samples should have native code at the top of the stack: + self.assertFalse(any(stack.endswith(";<native>") for stack in stacks)) + + def test_native_frames_disabled(self): + """Test that native frames do not appear when native tracking is disabled.""" + with ( + test_subprocess(self.native_test_script, wait_for_working=True) as subproc, + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + from profiling.sampling.pstats_collector import PstatsCollector + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=1, + ) + collector.print_stats(show_summary=False) + output = captured_output.getvalue() + # Native frames should NOT be present: + self.assertNotIn("<native>", output) + + +@requires_remote_subprocess_debugging() +class TestProcessPoolExecutorSupport(unittest.TestCase): + """ + Test that ProcessPoolExecutor works correctly with profiling.sampling. + """ + + def test_process_pool_executor_pickle(self): + # gh-140729: test use ProcessPoolExecutor.map() can sampling + test_script = """ +import concurrent.futures + +def worker(x): + return x * 2 + +if __name__ == "__main__": + with concurrent.futures.ProcessPoolExecutor() as executor: + results = list(executor.map(worker, [1, 2, 3])) + print(f"Results: {results}") +""" + with os_helper.temp_dir() as temp_dir: + script = script_helper.make_script( + temp_dir, "test_process_pool_executor_pickle", test_script + ) + with SuppressCrashReport(): + with script_helper.spawn_python( + "-m", + "profiling.sampling", + "run", + "-d", + "5", + "-i", + "100000", + script, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) as proc: + try: + stdout, stderr = proc.communicate( + timeout=SHORT_TIMEOUT + ) + except subprocess.TimeoutExpired: + proc.kill() + stdout, stderr = proc.communicate() + + self.assertIn("Results: [2, 4, 6]", stdout) + self.assertNotIn("Can't pickle", stderr) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_async.py b/Lib/test/test_profiling/test_sampling_profiler/test_async.py new file mode 100644 index 00000000000..d8ca86c996b --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_async.py @@ -0,0 +1,799 @@ +"""Tests for async stack reconstruction in the sampling profiler. + +Each test covers a distinct algorithm path or edge case: +1. Graph building: _build_task_graph() +2. Leaf identification: _find_leaf_tasks() +3. Stack traversal: _build_linear_stacks() with BFS +""" + +import unittest + +try: + import _remote_debugging # noqa: F401 + from profiling.sampling.pstats_collector import PstatsCollector +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from .mocks import MockFrameInfo, MockCoroInfo, MockTaskInfo, MockAwaitedInfo + + +class TestAsyncStackReconstruction(unittest.TestCase): + """Test async task tree linear stack reconstruction algorithm.""" + + def test_empty_input(self): + """Test _build_task_graph with empty awaited_info_list.""" + collector = PstatsCollector(sample_interval_usec=1000) + stacks = list(collector._iter_async_frames([])) + self.assertEqual(len(stacks), 0) + + def test_single_root_task(self): + """Test _find_leaf_tasks: root task with no parents is its own leaf.""" + collector = PstatsCollector(sample_interval_usec=1000) + + root = MockTaskInfo( + task_id=123, + task_name="Task-1", + coroutine_stack=[ + MockCoroInfo( + task_name="Task-1", + call_stack=[MockFrameInfo("main.py", 10, "main")] + ) + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=100, awaited_by=[root])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Single root is both leaf and root + self.assertEqual(len(stacks), 1) + frames, thread_id, leaf_id = stacks[0] + self.assertEqual(leaf_id, 123) + self.assertEqual(thread_id, 100) + + def test_parent_child_chain(self): + """Test _build_linear_stacks: BFS follows parent links from leaf to root. + + Task graph: + + Parent (id=1) + | + Child (id=2) + """ + collector = PstatsCollector(sample_interval_usec=1000) + + child = MockTaskInfo( + task_id=2, + task_name="Child", + coroutine_stack=[ + MockCoroInfo(task_name="Child", call_stack=[MockFrameInfo("c.py", 5, "child_fn")]) + ], + awaited_by=[ + MockCoroInfo(task_name=1, call_stack=[MockFrameInfo("p.py", 10, "parent_await")]) + ] + ) + + parent = MockTaskInfo( + task_id=1, + task_name="Parent", + coroutine_stack=[ + MockCoroInfo(task_name="Parent", call_stack=[MockFrameInfo("p.py", 15, "parent_fn")]) + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=200, awaited_by=[child, parent])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Leaf is child, traverses to parent + self.assertEqual(len(stacks), 1) + frames, thread_id, leaf_id = stacks[0] + self.assertEqual(leaf_id, 2) + + # Verify both child and parent frames present + func_names = [f.funcname for f in frames] + self.assertIn("child_fn", func_names) + self.assertIn("parent_fn", func_names) + + def test_multiple_leaf_tasks(self): + """Test _find_leaf_tasks: identifies multiple leaves correctly. + + Task graph (fan-out from root): + + Root (id=1) + / \ + Leaf1 (id=10) Leaf2 (id=20) + + Expected: 2 stacks (one for each leaf). + """ + collector = PstatsCollector(sample_interval_usec=1000) + leaf1 = MockTaskInfo( + task_id=10, + task_name="Leaf1", + coroutine_stack=[MockCoroInfo(task_name="Leaf1", call_stack=[MockFrameInfo("l1.py", 1, "f1")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[MockFrameInfo("r.py", 5, "root")])] + ) + + leaf2 = MockTaskInfo( + task_id=20, + task_name="Leaf2", + coroutine_stack=[MockCoroInfo(task_name="Leaf2", call_stack=[MockFrameInfo("l2.py", 2, "f2")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[MockFrameInfo("r.py", 5, "root")])] + ) + + root = MockTaskInfo( + task_id=1, + task_name="Root", + coroutine_stack=[MockCoroInfo(task_name="Root", call_stack=[MockFrameInfo("r.py", 10, "main")])], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=300, awaited_by=[leaf1, leaf2, root])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Two leaves = two stacks + self.assertEqual(len(stacks), 2) + leaf_ids = {leaf_id for _, _, leaf_id in stacks} + self.assertEqual(leaf_ids, {10, 20}) + + def test_cycle_detection(self): + """Test _build_linear_stacks: cycle detection prevents infinite loops. + + Task graph (cyclic dependency): + + A (id=1) <---> B (id=2) + + Neither task is a leaf (both have parents), so no stacks are produced. + """ + collector = PstatsCollector(sample_interval_usec=1000) + task_a = MockTaskInfo( + task_id=1, + task_name="A", + coroutine_stack=[MockCoroInfo(task_name="A", call_stack=[MockFrameInfo("a.py", 1, "a")])], + awaited_by=[MockCoroInfo(task_name=2, call_stack=[MockFrameInfo("b.py", 5, "b")])] + ) + + task_b = MockTaskInfo( + task_id=2, + task_name="B", + coroutine_stack=[MockCoroInfo(task_name="B", call_stack=[MockFrameInfo("b.py", 10, "b")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[MockFrameInfo("a.py", 15, "a")])] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=400, awaited_by=[task_a, task_b])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # No leaves (both have parents), should return empty + self.assertEqual(len(stacks), 0) + + def test_orphaned_parent_reference(self): + """Test _build_linear_stacks: handles parent ID not in task_map.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Task references non-existent parent + orphan = MockTaskInfo( + task_id=5, + task_name="Orphan", + coroutine_stack=[MockCoroInfo(task_name="Orphan", call_stack=[MockFrameInfo("o.py", 1, "orphan")])], + awaited_by=[MockCoroInfo(task_name=999, call_stack=[])] # 999 doesn't exist + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=500, awaited_by=[orphan])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Stops at missing parent, yields what it has + self.assertEqual(len(stacks), 1) + frames, _, leaf_id = stacks[0] + self.assertEqual(leaf_id, 5) + + def test_multiple_coroutines_per_task(self): + """Test _build_linear_stacks: collects frames from all coroutines in task.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Task with multiple coroutines (e.g., nested async generators) + task = MockTaskInfo( + task_id=7, + task_name="Multi", + coroutine_stack=[ + MockCoroInfo(task_name="Multi", call_stack=[MockFrameInfo("g.py", 5, "gen1")]), + MockCoroInfo(task_name="Multi", call_stack=[MockFrameInfo("g.py", 10, "gen2")]), + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=600, awaited_by=[task])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + self.assertEqual(len(stacks), 1) + frames, _, _ = stacks[0] + + # Both coroutine frames should be present + func_names = [f.funcname for f in frames] + self.assertIn("gen1", func_names) + self.assertIn("gen2", func_names) + + def test_multiple_threads(self): + """Test _build_task_graph: handles multiple AwaitedInfo (different threads).""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Two threads with separate task trees + thread1_task = MockTaskInfo( + task_id=100, + task_name="T1", + coroutine_stack=[MockCoroInfo(task_name="T1", call_stack=[MockFrameInfo("t1.py", 1, "t1")])], + awaited_by=[] + ) + + thread2_task = MockTaskInfo( + task_id=200, + task_name="T2", + coroutine_stack=[MockCoroInfo(task_name="T2", call_stack=[MockFrameInfo("t2.py", 1, "t2")])], + awaited_by=[] + ) + + awaited_info_list = [ + MockAwaitedInfo(thread_id=1, awaited_by=[thread1_task]), + MockAwaitedInfo(thread_id=2, awaited_by=[thread2_task]), + ] + + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Two threads = two stacks + self.assertEqual(len(stacks), 2) + + # Verify thread IDs preserved + thread_ids = {thread_id for _, thread_id, _ in stacks} + self.assertEqual(thread_ids, {1, 2}) + + def test_collect_public_interface(self): + """Test collect() method correctly routes to async frame processing.""" + collector = PstatsCollector(sample_interval_usec=1000) + + child = MockTaskInfo( + task_id=50, + task_name="Child", + coroutine_stack=[MockCoroInfo(task_name="Child", call_stack=[MockFrameInfo("c.py", 1, "child")])], + awaited_by=[MockCoroInfo(task_name=51, call_stack=[])] + ) + + parent = MockTaskInfo( + task_id=51, + task_name="Parent", + coroutine_stack=[MockCoroInfo(task_name="Parent", call_stack=[MockFrameInfo("p.py", 1, "parent")])], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=999, awaited_by=[child, parent])] + + # Public interface: collect() + collector.collect(awaited_info_list) + + # Verify stats collected + self.assertGreater(len(collector.result), 0) + func_names = [loc[2] for loc in collector.result.keys()] + self.assertIn("child", func_names) + self.assertIn("parent", func_names) + + def test_diamond_pattern_multiple_parents(self): + """Test _build_linear_stacks: task with 2+ parents picks one deterministically. + + CRITICAL: Tests that when a task has multiple parents, we pick one parent + deterministically (sorted, first one) and annotate the task name with parent count. + """ + collector = PstatsCollector(sample_interval_usec=1000) + + # Diamond pattern: Root spawns A and B, both await Child + # + # Root (id=1) + # / \ + # A (id=2) B (id=3) + # \ / + # Child (id=4) + # + + child = MockTaskInfo( + task_id=4, + task_name="Child", + coroutine_stack=[MockCoroInfo(task_name="Child", call_stack=[MockFrameInfo("c.py", 1, "child_work")])], + awaited_by=[ + MockCoroInfo(task_name=2, call_stack=[MockFrameInfo("a.py", 5, "a_await")]), # Parent A + MockCoroInfo(task_name=3, call_stack=[MockFrameInfo("b.py", 5, "b_await")]), # Parent B + ] + ) + + parent_a = MockTaskInfo( + task_id=2, + task_name="A", + coroutine_stack=[MockCoroInfo(task_name="A", call_stack=[MockFrameInfo("a.py", 10, "a_work")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[MockFrameInfo("root.py", 5, "root_spawn")])] + ) + + parent_b = MockTaskInfo( + task_id=3, + task_name="B", + coroutine_stack=[MockCoroInfo(task_name="B", call_stack=[MockFrameInfo("b.py", 10, "b_work")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[MockFrameInfo("root.py", 5, "root_spawn")])] + ) + + root = MockTaskInfo( + task_id=1, + task_name="Root", + coroutine_stack=[MockCoroInfo(task_name="Root", call_stack=[MockFrameInfo("root.py", 20, "main")])], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=777, awaited_by=[child, parent_a, parent_b, root])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Should get 1 stack: Child->A->Root (picks parent with lowest ID: 2) + self.assertEqual(len(stacks), 1, "Diamond should create only 1 path, picking first sorted parent") + + # Verify the single stack + frames, thread_id, leaf_id = stacks[0] + self.assertEqual(leaf_id, 4) + self.assertEqual(thread_id, 777) + + func_names = [f.funcname for f in frames] + # Stack should contain child, parent A (id=2, first when sorted), and root + self.assertIn("child_work", func_names) + self.assertIn("a_work", func_names, "Should use parent A (id=2, first when sorted)") + self.assertNotIn("b_work", func_names, "Should not include parent B") + self.assertIn("main", func_names) + + # Verify Child task is annotated with parent count + self.assertIn("Child (2 parents)", func_names, "Child task should be annotated with parent count") + + def test_empty_coroutine_stack(self): + """Test _build_linear_stacks: handles empty coroutine_stack (line 109 condition false).""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Task with no coroutine_stack + task = MockTaskInfo( + task_id=99, + task_name="EmptyStack", + coroutine_stack=[], # Empty! + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=111, awaited_by=[task])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + self.assertEqual(len(stacks), 1) + frames, _, _ = stacks[0] + + # Should only have task marker, no function frames + func_names = [f.funcname for f in frames] + self.assertEqual(len(func_names), 1, "Should only have task marker") + self.assertIn("EmptyStack", func_names) + + def test_orphaned_parent_with_no_frames_collected(self): + """Test _build_linear_stacks: orphaned parent at start with empty frames (line 94-96).""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Leaf that doesn't exist in task_map (should not happen normally, but test robustness) + # We'll create a scenario where the leaf_id is present but empty + + # Task references non-existent parent, and has no coroutine_stack + orphan = MockTaskInfo( + task_id=88, + task_name="Orphan", + coroutine_stack=[], # No frames + awaited_by=[MockCoroInfo(task_name=999, call_stack=[])] # Parent doesn't exist + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=222, awaited_by=[orphan])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # Should yield because we have the task marker even with no function frames + self.assertEqual(len(stacks), 1) + frames, _, leaf_id = stacks[0] + self.assertEqual(leaf_id, 88) + # Has task marker but no function frames + self.assertGreater(len(frames), 0, "Should have at least task marker") + + def test_frame_ordering(self): + """Test _build_linear_stacks: frames are collected in correct order (leaf->root). + + Task graph (3-level chain): + + Root (id=1) <- root_bottom, root_top + | + Middle (id=2) <- mid_bottom, mid_top + | + Leaf (id=3) <- leaf_bottom, leaf_top + + Expected frame order: leaf_bottom, leaf_top, mid_bottom, mid_top, root_bottom, root_top + (stack is built bottom-up: leaf frames first, then parent frames). + """ + collector = PstatsCollector(sample_interval_usec=1000) + leaf = MockTaskInfo( + task_id=3, + task_name="Leaf", + coroutine_stack=[ + MockCoroInfo(task_name="Leaf", call_stack=[ + MockFrameInfo("leaf.py", 1, "leaf_bottom"), + MockFrameInfo("leaf.py", 2, "leaf_top"), + ]) + ], + awaited_by=[MockCoroInfo(task_name=2, call_stack=[])] + ) + + middle = MockTaskInfo( + task_id=2, + task_name="Middle", + coroutine_stack=[ + MockCoroInfo(task_name="Middle", call_stack=[ + MockFrameInfo("mid.py", 1, "mid_bottom"), + MockFrameInfo("mid.py", 2, "mid_top"), + ]) + ], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[])] + ) + + root = MockTaskInfo( + task_id=1, + task_name="Root", + coroutine_stack=[ + MockCoroInfo(task_name="Root", call_stack=[ + MockFrameInfo("root.py", 1, "root_bottom"), + MockFrameInfo("root.py", 2, "root_top"), + ]) + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=333, awaited_by=[leaf, middle, root])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + self.assertEqual(len(stacks), 1) + frames, _, _ = stacks[0] + + func_names = [f.funcname for f in frames] + + # Order should be: leaf frames, leaf marker, middle frames, middle marker, root frames, root marker + leaf_bottom_idx = func_names.index("leaf_bottom") + leaf_top_idx = func_names.index("leaf_top") + mid_bottom_idx = func_names.index("mid_bottom") + root_bottom_idx = func_names.index("root_bottom") + + # Verify leaf comes before middle comes before root + self.assertLess(leaf_bottom_idx, leaf_top_idx, "Leaf frames in order") + self.assertLess(leaf_top_idx, mid_bottom_idx, "Leaf before middle") + self.assertLess(mid_bottom_idx, root_bottom_idx, "Middle before root") + + def test_complex_multi_parent_convergence(self): + """Test _build_linear_stacks: multiple leaves with same parents pick deterministically. + + Tests that when multiple leaves have multiple parents, each leaf picks the same + parent (sorted, first one) and all leaves are annotated with parent count. + + Task graph structure (both leaves awaited by both A and B):: + + Root (id=1) + / \\ + A (id=2) B (id=3) + | \\ / | + | \\ / | + | \\/ | + | /\\ | + | / \\ | + LeafX (id=4) LeafY (id=5) + + Expected behavior: Both leaves pick parent A (lowest id=2) for their stack path. + Result: 2 stacks, both going through A -> Root (B is skipped). + """ + collector = PstatsCollector(sample_interval_usec=1000) + + leaf_x = MockTaskInfo( + task_id=4, + task_name="LeafX", + coroutine_stack=[MockCoroInfo(task_name="LeafX", call_stack=[MockFrameInfo("x.py", 1, "x")])], + awaited_by=[ + MockCoroInfo(task_name=2, call_stack=[]), + MockCoroInfo(task_name=3, call_stack=[]), + ] + ) + + leaf_y = MockTaskInfo( + task_id=5, + task_name="LeafY", + coroutine_stack=[MockCoroInfo(task_name="LeafY", call_stack=[MockFrameInfo("y.py", 1, "y")])], + awaited_by=[ + MockCoroInfo(task_name=2, call_stack=[]), + MockCoroInfo(task_name=3, call_stack=[]), + ] + ) + + parent_a = MockTaskInfo( + task_id=2, + task_name="A", + coroutine_stack=[MockCoroInfo(task_name="A", call_stack=[MockFrameInfo("a.py", 1, "a")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[])] + ) + + parent_b = MockTaskInfo( + task_id=3, + task_name="B", + coroutine_stack=[MockCoroInfo(task_name="B", call_stack=[MockFrameInfo("b.py", 1, "b")])], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[])] + ) + + root = MockTaskInfo( + task_id=1, + task_name="Root", + coroutine_stack=[MockCoroInfo(task_name="Root", call_stack=[MockFrameInfo("r.py", 1, "root")])], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=444, awaited_by=[leaf_x, leaf_y, parent_a, parent_b, root])] + stacks = list(collector._iter_async_frames(awaited_info_list)) + + # 2 leaves, each picks same parent (A, id=2) = 2 paths + self.assertEqual(len(stacks), 2, "Should create 2 paths: X->A->Root, Y->A->Root") + + # Verify both leaves pick parent A (id=2, first when sorted) + leaf_ids_seen = set() + for frames, _, leaf_id in stacks: + leaf_ids_seen.add(leaf_id) + func_names = [f.funcname for f in frames] + + # Both stacks should go through parent A only + self.assertIn("a", func_names, "Should use parent A (id=2, first when sorted)") + self.assertNotIn("b", func_names, "Should not include parent B") + self.assertIn("root", func_names, "Should reach root") + + # Check for parent count annotation on the leaf + if leaf_id == 4: + self.assertIn("x", func_names) + self.assertIn("LeafX (2 parents)", func_names, "LeafX should be annotated with parent count") + elif leaf_id == 5: + self.assertIn("y", func_names) + self.assertIn("LeafY (2 parents)", func_names, "LeafY should be annotated with parent count") + + # Both leaves should be represented + self.assertEqual(leaf_ids_seen, {4, 5}, "Both LeafX and LeafY should have paths") + + +class TestFlamegraphCollectorAsync(unittest.TestCase): + """Test FlamegraphCollector with async frames.""" + + def test_flamegraph_with_async_frames(self): + """Test FlamegraphCollector correctly processes async task frames.""" + from profiling.sampling.stack_collector import FlamegraphCollector + + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Build async task tree: Root -> Child + child = MockTaskInfo( + task_id=2, + task_name="ChildTask", + coroutine_stack=[ + MockCoroInfo( + task_name="ChildTask", + call_stack=[MockFrameInfo("child.py", 10, "child_work")] + ) + ], + awaited_by=[MockCoroInfo(task_name=1, call_stack=[])] + ) + + root = MockTaskInfo( + task_id=1, + task_name="RootTask", + coroutine_stack=[ + MockCoroInfo( + task_name="RootTask", + call_stack=[MockFrameInfo("root.py", 20, "root_work")] + ) + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=100, awaited_by=[child, root])] + + # Collect async frames + collector.collect(awaited_info_list) + + # Verify samples were collected + self.assertGreater(collector._total_samples, 0) + + # Verify the flamegraph tree structure contains our functions + root_node = collector._root + self.assertGreater(root_node["samples"], 0) + + # Check that thread ID was tracked + self.assertIn(100, collector._all_threads) + + def test_flamegraph_with_task_markers(self): + """Test FlamegraphCollector includes <task> boundary markers.""" + from profiling.sampling.stack_collector import FlamegraphCollector + + collector = FlamegraphCollector(sample_interval_usec=1000) + + task = MockTaskInfo( + task_id=42, + task_name="MyTask", + coroutine_stack=[ + MockCoroInfo( + task_name="MyTask", + call_stack=[MockFrameInfo("work.py", 5, "do_work")] + ) + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=200, awaited_by=[task])] + collector.collect(awaited_info_list) + + # Find <task> marker in the tree + def find_task_marker(node, depth=0): + for func, child in node.get("children", {}).items(): + if func[0] == "<task>": + return func + result = find_task_marker(child, depth + 1) + if result: + return result + return None + + task_marker = find_task_marker(collector._root) + self.assertIsNotNone(task_marker, "Should have <task> marker in tree") + self.assertEqual(task_marker[0], "<task>") + self.assertIn("MyTask", task_marker[2]) + + def test_flamegraph_multiple_async_samples(self): + """Test FlamegraphCollector aggregates multiple async samples correctly.""" + from profiling.sampling.stack_collector import FlamegraphCollector + + collector = FlamegraphCollector(sample_interval_usec=1000) + + task = MockTaskInfo( + task_id=1, + task_name="Task", + coroutine_stack=[ + MockCoroInfo( + task_name="Task", + call_stack=[MockFrameInfo("work.py", 10, "work")] + ) + ], + awaited_by=[] + ) + + awaited_info_list = [MockAwaitedInfo(thread_id=300, awaited_by=[task])] + + # Collect multiple samples + for _ in range(5): + collector.collect(awaited_info_list) + + # Verify sample count + self.assertEqual(collector._sample_count, 5) + self.assertEqual(collector._total_samples, 5) + + +class TestAsyncAwareParameterFlow(unittest.TestCase): + """Integration tests for async_aware parameter flow from CLI to unwinder.""" + + def test_sample_function_accepts_async_aware(self): + """Test that sample() function accepts async_aware parameter.""" + from profiling.sampling.sample import sample + import inspect + + sig = inspect.signature(sample) + self.assertIn("async_aware", sig.parameters) + + def test_sample_live_function_accepts_async_aware(self): + """Test that sample_live() function accepts async_aware parameter.""" + from profiling.sampling.sample import sample_live + import inspect + + sig = inspect.signature(sample_live) + self.assertIn("async_aware", sig.parameters) + + def test_sample_profiler_sample_accepts_async_aware(self): + """Test that SampleProfiler.sample() accepts async_aware parameter.""" + from profiling.sampling.sample import SampleProfiler + import inspect + + sig = inspect.signature(SampleProfiler.sample) + self.assertIn("async_aware", sig.parameters) + + def test_async_aware_all_sees_sleeping_and_running_tasks(self): + """Test async_aware='all' captures both sleeping and CPU-running tasks.""" + # Sleeping task (awaiting) + sleeping_task = MockTaskInfo( + task_id=1, + task_name="SleepingTask", + coroutine_stack=[ + MockCoroInfo( + task_name="SleepingTask", + call_stack=[MockFrameInfo("sleeper.py", 10, "sleep_work")] + ) + ], + awaited_by=[] + ) + + # CPU-running task (active) + running_task = MockTaskInfo( + task_id=2, + task_name="RunningTask", + coroutine_stack=[ + MockCoroInfo( + task_name="RunningTask", + call_stack=[MockFrameInfo("runner.py", 20, "cpu_work")] + ) + ], + awaited_by=[] + ) + + # Both tasks returned by get_all_awaited_by + awaited_info_list = [MockAwaitedInfo(thread_id=100, awaited_by=[sleeping_task, running_task])] + + collector = PstatsCollector(sample_interval_usec=1000) + collector.collect(awaited_info_list) + collector.create_stats() + + # Both tasks should be visible + sleeping_key = ("sleeper.py", 10, "sleep_work") + running_key = ("runner.py", 20, "cpu_work") + + self.assertIn(sleeping_key, collector.stats) + self.assertIn(running_key, collector.stats) + + # Task markers should also be present + task_keys = [k for k in collector.stats if k[0] == "<task>"] + self.assertGreater(len(task_keys), 0, "Should have <task> markers in stats") + + # Verify task names are in the markers + task_names = [k[2] for k in task_keys] + self.assertTrue( + any("SleepingTask" in name for name in task_names), + "SleepingTask should be in task markers" + ) + self.assertTrue( + any("RunningTask" in name for name in task_names), + "RunningTask should be in task markers" + ) + + def test_async_aware_running_sees_only_running_task(self): + """Test async_aware='running' only shows the currently running task stack.""" + # Only the running task's stack is returned by get_async_stack_trace + running_task = MockTaskInfo( + task_id=2, + task_name="RunningTask", + coroutine_stack=[ + MockCoroInfo( + task_name="RunningTask", + call_stack=[MockFrameInfo("runner.py", 20, "cpu_work")] + ) + ], + awaited_by=[] + ) + + # get_async_stack_trace only returns the running task + awaited_info_list = [MockAwaitedInfo(thread_id=100, awaited_by=[running_task])] + + collector = PstatsCollector(sample_interval_usec=1000) + collector.collect(awaited_info_list) + collector.create_stats() + + # Only running task should be visible + running_key = ("runner.py", 20, "cpu_work") + self.assertIn(running_key, collector.stats) + + # Verify we don't see the sleeping task (it wasn't in the input) + sleeping_key = ("sleeper.py", 10, "sleep_work") + self.assertNotIn(sleeping_key, collector.stats) + + # Task marker for running task should be present + task_keys = [k for k in collector.stats if k[0] == "<task>"] + self.assertGreater(len(task_keys), 0, "Should have <task> markers in stats") + + task_names = [k[2] for k in task_keys] + self.assertTrue( + any("RunningTask" in name for name in task_names), + "RunningTask should be in task markers" + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_children.py b/Lib/test/test_profiling/test_sampling_profiler/test_children.py new file mode 100644 index 00000000000..9b4c741727a --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_children.py @@ -0,0 +1,1065 @@ +"""Tests for --subprocesses subprocess profiling support.""" + +import argparse +import io +import os +import signal +import subprocess +import sys +import tempfile +import threading +import time +import unittest + +from test.support import ( + SHORT_TIMEOUT, + reap_children, + requires_remote_subprocess_debugging, +) + +from .helpers import _cleanup_process + +# String to check for in stderr when profiler lacks permissions (e.g., macOS) +_PERMISSION_ERROR_MSG = "Permission Error" + + +def _readline_with_timeout(file_obj, timeout): + # Thread-based readline with timeout - works across all platforms + # including Windows where select() doesn't work with pipes. + # Returns the line read, or None if timeout occurred. + result = [None] + exception = [None] + + def reader(): + try: + result[0] = file_obj.readline() + except Exception as e: + exception[0] = e + + thread = threading.Thread(target=reader, daemon=True) + thread.start() + thread.join(timeout=timeout) + + if thread.is_alive(): + return None + + if exception[0] is not None: + raise exception[0] + + return result[0] + + +def _wait_for_process_ready(proc, timeout): + # Wait for a subprocess to be ready using polling instead of fixed sleep. + # Returns True if process is ready, False if it exited or timeout. + deadline = time.time() + timeout + poll_interval = 0.01 + + while time.time() < deadline: + if proc.poll() is not None: + return False + + try: + if sys.platform == "linux": + if os.path.exists(f"/proc/{proc.pid}/exe"): + return True + else: + return True + except OSError: + pass + + time.sleep(poll_interval) + poll_interval = min(poll_interval * 2, 0.1) + + return proc.poll() is None + + +@requires_remote_subprocess_debugging() +class TestGetChildPids(unittest.TestCase): + """Tests for the get_child_pids function.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_get_child_pids_from_remote_debugging(self): + """Test get_child_pids from _remote_debugging module.""" + try: + import _remote_debugging + + # Test that the function exists + self.assertTrue(hasattr(_remote_debugging, "get_child_pids")) + + # Test with current process (should return empty or have children if any) + result = _remote_debugging.get_child_pids(os.getpid()) + self.assertIsInstance(result, list) + except (ImportError, AttributeError): + self.skipTest("_remote_debugging.get_child_pids not available") + + def test_get_child_pids_fallback(self): + """Test the fallback implementation for get_child_pids.""" + from profiling.sampling._child_monitor import get_child_pids + + # Test with current process + result = get_child_pids(os.getpid()) + self.assertIsInstance(result, list) + + @unittest.skipUnless(sys.platform == "linux", "Linux only") + def test_discover_child_process_linux(self): + """Test that we can discover child processes on Linux.""" + from profiling.sampling._child_monitor import get_child_pids + + # Create a child process + proc = subprocess.Popen( + [sys.executable, "-c", "import time; time.sleep(10)"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + try: + # Poll until child appears + deadline = time.time() + SHORT_TIMEOUT + children = [] + while time.time() < deadline: + children = get_child_pids(os.getpid()) + if proc.pid in children: + break + time.sleep(0.05) + + self.assertIn( + proc.pid, + children, + f"Child PID {proc.pid} not discovered within {SHORT_TIMEOUT}s. " + f"Found PIDs: {children}", + ) + finally: + _cleanup_process(proc) + + def test_recursive_child_discovery(self): + """Test that recursive=True finds grandchildren.""" + from profiling.sampling._child_monitor import get_child_pids + + # Create a child that spawns a grandchild and keeps a reference to it + # so we can clean it up via the child process + code = """ +import subprocess +import sys +import threading +grandchild = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)']) +print(grandchild.pid, flush=True) +# Wait for parent to send signal byte (cross-platform) +# Using threading with timeout so test doesn't hang if something goes wrong +# Timeout is 60s (2x test timeout) to ensure child outlives test in worst case +def wait_for_signal(): + try: + sys.stdin.buffer.read(1) + except: + pass +t = threading.Thread(target=wait_for_signal, daemon=True) +t.start() +t.join(timeout=60) +# Clean up grandchild before exiting +if grandchild.poll() is None: + grandchild.terminate() + try: + grandchild.wait(timeout=2) + except subprocess.TimeoutExpired: + grandchild.kill() + try: + grandchild.wait(timeout=2) + except subprocess.TimeoutExpired: + grandchild.wait() +""" + proc = subprocess.Popen( + [sys.executable, "-c", code], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + ) + + grandchild_pid = None + try: + # Read grandchild PID with thread-based timeout + # This prevents indefinite blocking on all platforms + grandchild_pid_line = _readline_with_timeout( + proc.stdout, SHORT_TIMEOUT + ) + if grandchild_pid_line is None: + self.fail( + f"Timeout waiting for grandchild PID from child process " + f"(child PID: {proc.pid})" + ) + if not grandchild_pid_line: + self.fail( + f"Child process {proc.pid} closed stdout without printing " + f"grandchild PID" + ) + grandchild_pid = int(grandchild_pid_line.strip()) + + # Poll until grandchild is visible + deadline = time.time() + SHORT_TIMEOUT + pids_recursive = [] + while time.time() < deadline: + pids_recursive = get_child_pids(os.getpid(), recursive=True) + if grandchild_pid in pids_recursive: + break + time.sleep(0.05) + + self.assertIn( + proc.pid, + pids_recursive, + f"Child PID {proc.pid} not found in recursive discovery. " + f"Found: {pids_recursive}", + ) + self.assertIn( + grandchild_pid, + pids_recursive, + f"Grandchild PID {grandchild_pid} not found in recursive discovery. " + f"Found: {pids_recursive}", + ) + + # Non-recursive should find only direct child + pids_direct = get_child_pids(os.getpid(), recursive=False) + self.assertIn( + proc.pid, + pids_direct, + f"Child PID {proc.pid} not found in non-recursive discovery. " + f"Found: {pids_direct}", + ) + self.assertNotIn( + grandchild_pid, + pids_direct, + f"Grandchild PID {grandchild_pid} should NOT be in non-recursive " + f"discovery. Found: {pids_direct}", + ) + finally: + # Send signal byte to child to trigger cleanup, then close stdin + try: + proc.stdin.write(b"x") + proc.stdin.flush() + proc.stdin.close() + except OSError: + pass + proc.stdout.close() + _cleanup_process(proc) + # The grandchild may not have been cleaned up by the child process + # (e.g., if the child was killed). Explicitly terminate the + # grandchild to prevent PermissionError on Windows when removing + # temp directories. + if grandchild_pid is not None: + try: + os.kill(grandchild_pid, signal.SIGTERM) + except (OSError, ProcessLookupError): + pass # Process already exited + + def test_nonexistent_pid_returns_empty(self): + """Test that nonexistent PID returns empty list.""" + from profiling.sampling._child_monitor import get_child_pids + + # Use a very high PID that's unlikely to exist + result = get_child_pids(999999999) + self.assertEqual(result, []) + + +@requires_remote_subprocess_debugging() +class TestChildProcessMonitor(unittest.TestCase): + """Tests for the ChildProcessMonitor class.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_monitor_creation(self): + """Test that ChildProcessMonitor can be created.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), + cli_args=["-i", "100", "-d", "5"], + output_pattern="test_{pid}.pstats", + ) + self.assertEqual(monitor.parent_pid, os.getpid()) + self.assertEqual(monitor.cli_args, ["-i", "100", "-d", "5"]) + self.assertEqual(monitor.output_pattern, "test_{pid}.pstats") + + def test_monitor_lifecycle(self): + """Test monitor lifecycle via context manager.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) + + # Before entering context, thread should not exist + self.assertIsNone(monitor._monitor_thread) + + with monitor: + # Inside context, thread should be running + self.assertIsNotNone(monitor._monitor_thread) + self.assertTrue(monitor._monitor_thread.is_alive()) + + # After exiting context, thread should be stopped + self.assertFalse(monitor._monitor_thread.is_alive()) + + def test_spawned_profilers_property(self): + """Test that spawned_profilers returns a copy of the list.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) + + # Should return empty list initially + profilers = monitor.spawned_profilers + self.assertEqual(profilers, []) + self.assertIsNot(profilers, monitor._spawned_profilers) + + def test_context_manager(self): + """Test that ChildProcessMonitor works as a context manager.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + with ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) as monitor: + self.assertIsNotNone(monitor._monitor_thread) + self.assertTrue(monitor._monitor_thread.is_alive()) + + # After exiting context, thread should be stopped + self.assertFalse(monitor._monitor_thread.is_alive()) + + +@requires_remote_subprocess_debugging() +class TestCLIChildrenFlag(unittest.TestCase): + """Tests for the --subprocesses CLI flag.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_subprocesses_flag_parsed(self): + """Test that --subprocesses flag is recognized.""" + from profiling.sampling.cli import _add_sampling_options + + parser = argparse.ArgumentParser() + _add_sampling_options(parser) + + # Parse with --subprocesses + args = parser.parse_args(["--subprocesses"]) + self.assertTrue(args.subprocesses) + + # Parse without --subprocesses + args = parser.parse_args([]) + self.assertFalse(args.subprocesses) + + def test_subprocesses_incompatible_with_live(self): + """Test that --subprocesses is incompatible with --live.""" + from profiling.sampling.cli import _validate_args + + # Create mock args with both subprocesses and live + args = argparse.Namespace( + subprocesses=True, + live=True, + async_aware=False, + format="pstats", + mode="wall", + sort=None, + limit=None, + no_summary=False, + opcodes=False, + ) + + parser = argparse.ArgumentParser() + + with self.assertRaises(SystemExit): + _validate_args(args, parser) + + def test_build_child_profiler_args(self): + """Test building CLI args for child profilers.""" + from profiling.sampling.cli import _build_child_profiler_args + + args = argparse.Namespace( + interval=200, + duration=15, + all_threads=True, + realtime_stats=False, + native=True, + gc=True, + opcodes=False, + async_aware=False, + mode="cpu", + format="flamegraph", + ) + + child_args = _build_child_profiler_args(args) + + # Verify flag-value pairs are correctly paired (flag followed by value) + def assert_flag_value_pair(flag, value): + self.assertIn( + flag, + child_args, + f"Flag '{flag}' not found in args: {child_args}", + ) + flag_index = child_args.index(flag) + self.assertGreater( + len(child_args), + flag_index + 1, + f"No value after flag '{flag}' in args: {child_args}", + ) + self.assertEqual( + child_args[flag_index + 1], + str(value), + f"Flag '{flag}' should be followed by '{value}', got " + f"'{child_args[flag_index + 1]}' in args: {child_args}", + ) + + assert_flag_value_pair("-i", 200) + assert_flag_value_pair("-d", 15) + assert_flag_value_pair("--mode", "cpu") + + # Verify standalone flags are present + self.assertIn( + "-a", child_args, f"Flag '-a' not found in args: {child_args}" + ) + self.assertIn( + "--native", + child_args, + f"Flag '--native' not found in args: {child_args}", + ) + self.assertIn( + "--flamegraph", + child_args, + f"Flag '--flamegraph' not found in args: {child_args}", + ) + + def test_build_child_profiler_args_no_gc(self): + """Test building CLI args with --no-gc.""" + from profiling.sampling.cli import _build_child_profiler_args + + args = argparse.Namespace( + interval=100, + duration=5, + all_threads=False, + realtime_stats=False, + native=False, + gc=False, # Explicitly disabled + opcodes=False, + async_aware=False, + mode="wall", + format="pstats", + ) + + child_args = _build_child_profiler_args(args) + + self.assertIn( + "--no-gc", + child_args, + f"Flag '--no-gc' not found when gc=False. Args: {child_args}", + ) + + def test_build_output_pattern_with_outfile(self): + """Test output pattern generation with user-specified output.""" + from profiling.sampling.cli import _build_output_pattern + + # With extension + args = argparse.Namespace(outfile="output.html", format="flamegraph") + pattern = _build_output_pattern(args) + self.assertEqual(pattern, "output_{pid}.html") + + # Without extension + args = argparse.Namespace(outfile="output", format="pstats") + pattern = _build_output_pattern(args) + self.assertEqual(pattern, "output_{pid}") + + def test_build_output_pattern_default(self): + """Test output pattern generation with default output.""" + from profiling.sampling.cli import _build_output_pattern + + # Flamegraph format + args = argparse.Namespace(outfile=None, format="flamegraph") + pattern = _build_output_pattern(args) + self.assertIn("{pid}", pattern) + self.assertIn("flamegraph", pattern) + self.assertTrue(pattern.endswith(".html")) + + # Heatmap format + args = argparse.Namespace(outfile=None, format="heatmap") + pattern = _build_output_pattern(args) + self.assertEqual(pattern, "heatmap_{pid}") + + +@requires_remote_subprocess_debugging() +class TestChildrenIntegration(unittest.TestCase): + """Integration tests for --subprocesses functionality.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_setup_child_monitor(self): + """Test setting up a child monitor from args.""" + from profiling.sampling.cli import _setup_child_monitor + + args = argparse.Namespace( + interval=100, + duration=5, + all_threads=False, + realtime_stats=False, + native=False, + gc=True, + opcodes=False, + async_aware=False, + mode="wall", + format="pstats", + outfile=None, + ) + + monitor = _setup_child_monitor(args, os.getpid()) + # Use addCleanup to ensure monitor is properly cleaned up even if + # assertions fail + self.addCleanup(monitor.__exit__, None, None, None) + + self.assertIsNotNone(monitor) + self.assertEqual( + monitor.parent_pid, + os.getpid(), + f"Monitor parent_pid should be {os.getpid()}, got {monitor.parent_pid}", + ) + + +@requires_remote_subprocess_debugging() +class TestIsPythonProcess(unittest.TestCase): + """Tests for the is_python_process function.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_is_python_process_current_process(self): + """Test that current process is detected as Python.""" + from profiling.sampling._child_monitor import is_python_process + + # Current process should be Python + result = is_python_process(os.getpid()) + self.assertTrue( + result, + f"Current process (PID {os.getpid()}) should be detected as Python", + ) + + def test_is_python_process_python_subprocess(self): + """Test that a Python subprocess is detected as Python.""" + from profiling.sampling._child_monitor import is_python_process + + # Start a Python subprocess + proc = subprocess.Popen( + [sys.executable, "-c", "import time; time.sleep(10)"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + try: + # Poll until Python runtime structures are initialized + # (is_python_process probes for runtime structures which take + # time to initialize after process start) + deadline = time.time() + SHORT_TIMEOUT + detected = False + while time.time() < deadline: + if proc.poll() is not None: + self.fail(f"Process {proc.pid} exited unexpectedly") + if is_python_process(proc.pid): + detected = True + break + time.sleep(0.05) + + self.assertTrue( + detected, + f"Python subprocess (PID {proc.pid}) should be detected as Python " + f"within {SHORT_TIMEOUT}s", + ) + finally: + _cleanup_process(proc) + + @unittest.skipUnless(sys.platform == "linux", "Linux only test") + def test_is_python_process_non_python_subprocess(self): + """Test that a non-Python subprocess is not detected as Python.""" + from profiling.sampling._child_monitor import is_python_process + + # Start a non-Python subprocess (sleep command) + proc = subprocess.Popen( + ["sleep", "10"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + try: + # Wait for process to be ready using polling + self.assertTrue( + _wait_for_process_ready(proc, SHORT_TIMEOUT), + f"Process {proc.pid} should be ready within {SHORT_TIMEOUT}s", + ) + + self.assertFalse( + is_python_process(proc.pid), + f"Non-Python subprocess 'sleep' (PID {proc.pid}) should NOT be " + f"detected as Python", + ) + finally: + _cleanup_process(proc) + + def test_is_python_process_nonexistent_pid(self): + """Test that nonexistent PID returns False.""" + from profiling.sampling._child_monitor import is_python_process + + # Use a very high PID that's unlikely to exist + result = is_python_process(999999999) + self.assertFalse( + result, + "Nonexistent PID 999999999 should return False", + ) + + def test_is_python_process_exited_process(self): + """Test handling of a process that exits quickly.""" + from profiling.sampling._child_monitor import is_python_process + + # Start a process that exits immediately + proc = subprocess.Popen( + [sys.executable, "-c", "pass"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + # Wait for it to exit + proc.wait(timeout=SHORT_TIMEOUT) + + # Should return False for exited process (not raise) + result = is_python_process(proc.pid) + self.assertFalse( + result, f"Exited process (PID {proc.pid}) should return False" + ) + + +@requires_remote_subprocess_debugging() +class TestMaxChildProfilersLimit(unittest.TestCase): + """Tests for the _MAX_CHILD_PROFILERS limit.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_max_profilers_constant_exists(self): + """Test that _MAX_CHILD_PROFILERS constant is defined.""" + from profiling.sampling._child_monitor import _MAX_CHILD_PROFILERS + + self.assertEqual( + _MAX_CHILD_PROFILERS, + 100, + f"_MAX_CHILD_PROFILERS should be 100, got {_MAX_CHILD_PROFILERS}", + ) + + def test_cleanup_interval_constant_exists(self): + """Test that _CLEANUP_INTERVAL_CYCLES constant is defined.""" + from profiling.sampling._child_monitor import _CLEANUP_INTERVAL_CYCLES + + self.assertEqual( + _CLEANUP_INTERVAL_CYCLES, + 10, + f"_CLEANUP_INTERVAL_CYCLES should be 10, got {_CLEANUP_INTERVAL_CYCLES}", + ) + + def test_monitor_respects_max_limit(self): + """Test that monitor refuses to spawn more than _MAX_CHILD_PROFILERS.""" + from profiling.sampling._child_monitor import ( + ChildProcessMonitor, + _MAX_CHILD_PROFILERS, + ) + from unittest.mock import MagicMock, patch + + # Create a monitor + monitor = ChildProcessMonitor( + pid=os.getpid(), + cli_args=["-i", "100", "-d", "5"], + output_pattern="test_{pid}.pstats", + ) + + # Manually fill up the profilers list to the limit + mock_profilers = [MagicMock() for _ in range(_MAX_CHILD_PROFILERS)] + for mock_proc in mock_profilers: + mock_proc.poll.return_value = None # Simulate running process + monitor._spawned_profilers = mock_profilers + + # Try to spawn another profiler - should be rejected + stderr_capture = io.StringIO() + with patch("sys.stderr", stderr_capture): + monitor._spawn_profiler_for_child(99999) + + # Verify warning was printed + stderr_output = stderr_capture.getvalue() + self.assertIn( + "Max child profilers", + stderr_output, + f"Expected warning about max profilers, got: {stderr_output}", + ) + self.assertIn( + str(_MAX_CHILD_PROFILERS), + stderr_output, + f"Warning should mention limit ({_MAX_CHILD_PROFILERS}): {stderr_output}", + ) + + # Verify no new profiler was added + self.assertEqual( + len(monitor._spawned_profilers), + _MAX_CHILD_PROFILERS, + f"Should still have {_MAX_CHILD_PROFILERS} profilers, got " + f"{len(monitor._spawned_profilers)}", + ) + + +@requires_remote_subprocess_debugging() +class TestWaitForProfilers(unittest.TestCase): + """Tests for the wait_for_profilers method.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_wait_for_profilers_empty_list(self): + """Test that wait_for_profilers returns immediately with no profilers.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) + + # Should return immediately without printing anything + stderr_capture = io.StringIO() + with unittest.mock.patch("sys.stderr", stderr_capture): + start = time.time() + monitor.wait_for_profilers(timeout=10.0) + elapsed = time.time() - start + + # Should complete very quickly (less than 1 second) + self.assertLess( + elapsed, + 1.0, + f"wait_for_profilers with empty list took {elapsed:.2f}s, expected < 1s", + ) + # No "Waiting for..." message should be printed + self.assertNotIn( + "Waiting for", + stderr_capture.getvalue(), + "Should not print waiting message when no profilers", + ) + + def test_wait_for_profilers_with_completed_process(self): + """Test waiting for profilers that complete quickly.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) + + # Start a process that exits quickly + proc = subprocess.Popen( + [sys.executable, "-c", "pass"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + # Add to spawned profilers + monitor._spawned_profilers.append(proc) + + try: + stderr_capture = io.StringIO() + with unittest.mock.patch("sys.stderr", stderr_capture): + start = time.time() + monitor.wait_for_profilers(timeout=SHORT_TIMEOUT) + elapsed = time.time() - start + + # Should complete quickly since process exits fast + self.assertLess( + elapsed, + 5.0, + f"wait_for_profilers took {elapsed:.2f}s for quick process", + ) + # Should print waiting message + self.assertIn( + "Waiting for 1 child profiler", + stderr_capture.getvalue(), + "Should print waiting message", + ) + finally: + _cleanup_process(proc) + + def test_wait_for_profilers_timeout(self): + """Test that wait_for_profilers respects timeout.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) + + # Start a process that runs for a long time + proc = subprocess.Popen( + [sys.executable, "-c", "import time; time.sleep(60)"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + # Add to spawned profilers + monitor._spawned_profilers.append(proc) + + try: + stderr_capture = io.StringIO() + with unittest.mock.patch("sys.stderr", stderr_capture): + start = time.time() + # Use short timeout + monitor.wait_for_profilers(timeout=0.5) + elapsed = time.time() - start + + # Should timeout after approximately 0.5 seconds + self.assertGreater( + elapsed, + 0.4, + f"wait_for_profilers returned too quickly ({elapsed:.2f}s)", + ) + self.assertLess( + elapsed, + 2.0, + f"wait_for_profilers took too long ({elapsed:.2f}s), timeout not respected", + ) + finally: + _cleanup_process(proc) + + def test_wait_for_profilers_multiple(self): + """Test waiting for multiple profilers.""" + from profiling.sampling._child_monitor import ChildProcessMonitor + + monitor = ChildProcessMonitor( + pid=os.getpid(), cli_args=[], output_pattern=None + ) + + # Start multiple processes + procs = [] + for _ in range(3): + proc = subprocess.Popen( + [sys.executable, "-c", "import time; time.sleep(0.1)"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + procs.append(proc) + monitor._spawned_profilers.append(proc) + + try: + stderr_capture = io.StringIO() + with unittest.mock.patch("sys.stderr", stderr_capture): + monitor.wait_for_profilers(timeout=SHORT_TIMEOUT) + + # Should report correct count + self.assertIn( + "Waiting for 3 child profiler", + stderr_capture.getvalue(), + "Should report correct profiler count", + ) + finally: + for proc in procs: + _cleanup_process(proc) + + +@requires_remote_subprocess_debugging() +class TestEndToEndChildrenCLI(unittest.TestCase): + """End-to-end tests for --subprocesses CLI flag.""" + + def setUp(self): + reap_children() + + def tearDown(self): + reap_children() + + def test_subprocesses_flag_spawns_child_and_creates_output(self): + """Test that --subprocesses flag works end-to-end with actual subprocesses.""" + # Create a temporary directory for output files + with tempfile.TemporaryDirectory() as tmpdir: + # Create a script that spawns a child Python process + parent_script = f""" +import subprocess +import sys +import time + +# Spawn a child that does some work +child = subprocess.Popen([ + sys.executable, '-c', + 'import time; [i**2 for i in range(1000)]; time.sleep(2)' +]) +# Do some work in parent +for i in range(1000): + _ = i ** 2 +time.sleep(2) +child.wait() +""" + script_file = os.path.join(tmpdir, "parent_script.py") + with open(script_file, "w") as f: + f.write(parent_script) + + output_file = os.path.join(tmpdir, "profile.pstats") + + # Run the profiler with --subprocesses flag + result = subprocess.run( + [ + sys.executable, + "-m", + "profiling.sampling", + "run", + "--subprocesses", + "-d", + "3", + "-i", + "10000", + "-o", + output_file, + script_file, + ], + capture_output=True, + text=True, + timeout=SHORT_TIMEOUT, + ) + + # Check that parent output file was created + self.assertTrue( + os.path.exists(output_file), + f"Parent profile output not created. " + f"stdout: {result.stdout}, stderr: {result.stderr}", + ) + + # Check for child profiler output files (pattern: profile_{pid}.pstats) + output_files = os.listdir(tmpdir) + child_profiles = [ + f + for f in output_files + if f.startswith("profile_") and f.endswith(".pstats") + ] + + # Note: Child profiling is best-effort; the child may exit before + # profiler attaches, or the process may not be detected as Python. + # We just verify the mechanism doesn't crash. + if result.returncode != 0: + self.fail( + f"Profiler exited with code {result.returncode}. " + f"stdout: {result.stdout}, stderr: {result.stderr}" + ) + + def test_subprocesses_flag_with_flamegraph_output(self): + """Test --subprocesses with flamegraph output format.""" + with tempfile.TemporaryDirectory() as tmpdir: + # Simple parent that spawns a child + parent_script = f""" +import subprocess +import sys +import time +child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(1)']) +time.sleep(1) +child.wait() +""" + script_file = os.path.join(tmpdir, "parent.py") + with open(script_file, "w") as f: + f.write(parent_script) + + output_file = os.path.join(tmpdir, "flame.html") + + result = subprocess.run( + [ + sys.executable, + "-m", + "profiling.sampling", + "run", + "--subprocesses", + "-d", + "2", + "-i", + "10000", + "--flamegraph", + "-o", + output_file, + script_file, + ], + capture_output=True, + text=True, + timeout=SHORT_TIMEOUT, + ) + + self.assertTrue( + os.path.exists(output_file), + f"Flamegraph output not created. stderr: {result.stderr}", + ) + + # Verify it's valid HTML + with open(output_file, "r") as f: + content = f.read() + self.assertIn( + "<html", + content.lower(), + "Flamegraph output should be HTML", + ) + + def test_subprocesses_flag_no_crash_on_quick_child(self): + """Test that --subprocesses doesn't crash when child exits quickly.""" + with tempfile.TemporaryDirectory() as tmpdir: + # Parent spawns a child that exits immediately + parent_script = f""" +import subprocess +import sys +import time +# Child exits immediately +child = subprocess.Popen([sys.executable, '-c', 'pass']) +child.wait() +time.sleep(1) +""" + script_file = os.path.join(tmpdir, "parent.py") + with open(script_file, "w") as f: + f.write(parent_script) + + output_file = os.path.join(tmpdir, "profile.pstats") + + result = subprocess.run( + [ + sys.executable, + "-m", + "profiling.sampling", + "run", + "--subprocesses", + "-d", + "2", + "-i", + "10000", + "-o", + output_file, + script_file, + ], + capture_output=True, + text=True, + timeout=SHORT_TIMEOUT, + ) + + # Should not crash - exit code 0 + self.assertEqual( + result.returncode, + 0, + f"Profiler crashed with quick-exit child. " + f"stderr: {result.stderr}", + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py new file mode 100644 index 00000000000..9b2b16d6e19 --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py @@ -0,0 +1,724 @@ +"""Tests for sampling profiler CLI argument parsing and functionality.""" + +import io +import subprocess +import sys +import unittest +from unittest import mock + +try: + import _remote_debugging # noqa: F401 +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from test.support import is_emscripten, requires_remote_subprocess_debugging + +from profiling.sampling.cli import main +from profiling.sampling.errors import SamplingScriptNotFoundError, SamplingModuleNotFoundError, SamplingUnknownProcessError + + +class TestSampleProfilerCLI(unittest.TestCase): + def _setup_sync_mocks(self, mock_socket, mock_popen): + """Helper to set up socket and process mocks for coordinator tests.""" + # Mock the sync socket with context manager support + mock_sock_instance = mock.MagicMock() + mock_sock_instance.getsockname.return_value = ("127.0.0.1", 12345) + + # Mock the connection with context manager support + mock_conn = mock.MagicMock() + mock_conn.recv.return_value = b"ready" + mock_conn.__enter__.return_value = mock_conn + mock_conn.__exit__.return_value = None + + # Mock accept() to return (connection, address) and support indexing + mock_accept_result = mock.MagicMock() + mock_accept_result.__getitem__.return_value = ( + mock_conn # [0] returns the connection + ) + mock_sock_instance.accept.return_value = mock_accept_result + + # Mock socket with context manager support + mock_sock_instance.__enter__.return_value = mock_sock_instance + mock_sock_instance.__exit__.return_value = None + mock_socket.return_value = mock_sock_instance + + # Mock the subprocess + mock_process = mock.MagicMock() + mock_process.pid = 12345 + mock_process.poll.return_value = None + mock_popen.return_value = mock_process + return mock_process + + def _verify_coordinator_command(self, mock_popen, expected_target_args): + """Helper to verify the coordinator command was called correctly.""" + args, kwargs = mock_popen.call_args + coordinator_cmd = args[0] + self.assertEqual(coordinator_cmd[0], sys.executable) + self.assertEqual(coordinator_cmd[1], "-m") + self.assertEqual( + coordinator_cmd[2], "profiling.sampling._sync_coordinator" + ) + self.assertEqual(coordinator_cmd[3], "12345") # port + # cwd is coordinator_cmd[4] + self.assertEqual(coordinator_cmd[5:], expected_target_args) + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + @requires_remote_subprocess_debugging() + def test_cli_module_argument_parsing(self): + test_args = ["profiling.sampling.cli", "run", "-m", "mymodule"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("importlib.util.find_spec", return_value=True), + ): + self._setup_sync_mocks(mock_socket, mock_popen) + main() + + self._verify_coordinator_command(mock_popen, ("-m", "mymodule")) + # Verify sample was called once (exact arguments will vary with the new API) + mock_sample.assert_called_once() + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + @requires_remote_subprocess_debugging() + def test_cli_module_with_arguments(self): + test_args = [ + "profiling.sampling.cli", + "run", + "-m", + "mymodule", + "arg1", + "arg2", + "--flag", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("importlib.util.find_spec", return_value=True), + ): + self._setup_sync_mocks(mock_socket, mock_popen) + main() + + self._verify_coordinator_command( + mock_popen, ("-m", "mymodule", "arg1", "arg2", "--flag") + ) + mock_sample.assert_called_once() + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + def test_cli_script_argument_parsing(self): + test_args = ["profiling.sampling.cli", "run", "myscript.py"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("os.path.exists", return_value=True), + ): + self._setup_sync_mocks(mock_socket, mock_popen) + main() + + self._verify_coordinator_command(mock_popen, ("myscript.py",)) + mock_sample.assert_called_once() + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + def test_cli_script_with_arguments(self): + test_args = [ + "profiling.sampling.cli", + "run", + "myscript.py", + "arg1", + "arg2", + "--flag", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("os.path.exists", return_value=True), + ): + # Use the helper to set up mocks consistently + mock_process = self._setup_sync_mocks(mock_socket, mock_popen) + # Override specific behavior for this test + mock_process.wait.side_effect = [ + subprocess.TimeoutExpired(test_args, 0.1), + None, + ] + + main() + + # Verify the coordinator command was called + args, kwargs = mock_popen.call_args + coordinator_cmd = args[0] + self.assertEqual(coordinator_cmd[0], sys.executable) + self.assertEqual(coordinator_cmd[1], "-m") + self.assertEqual( + coordinator_cmd[2], "profiling.sampling._sync_coordinator" + ) + self.assertEqual(coordinator_cmd[3], "12345") # port + # cwd is coordinator_cmd[4] + self.assertEqual( + coordinator_cmd[5:], ("myscript.py", "arg1", "arg2", "--flag") + ) + + def test_cli_mutually_exclusive_pid_module(self): + # In new CLI, attach and run are separate subcommands, so this test + # verifies that mixing them causes an error + test_args = [ + "profiling.sampling.cli", + "attach", # attach subcommand uses PID + "12345", + "-m", # -m is only for run subcommand + "mymodule", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("unrecognized arguments", error_msg) + + def test_cli_mutually_exclusive_pid_script(self): + # In new CLI, you can't mix attach (PID) with run (script) + # This would be caught by providing a PID to run subcommand + test_args = ["profiling.sampling.cli", "run", "12345"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SamplingScriptNotFoundError) as cm, + ): + main() + + # Verify the error is about the non-existent script + self.assertIn("12345", str(cm.exception)) + + def test_cli_no_target_specified(self): + # In new CLI, must specify a subcommand + test_args = ["profiling.sampling.cli", "-d", "5"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("invalid choice", error_msg) + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + @requires_remote_subprocess_debugging() + def test_cli_module_with_profiler_options(self): + test_args = [ + "profiling.sampling.cli", + "run", + "-i", + "1000", + "-d", + "30", + "-a", + "--sort", + "tottime", + "-l", + "20", + "-m", + "mymodule", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("importlib.util.find_spec", return_value=True), + ): + self._setup_sync_mocks(mock_socket, mock_popen) + main() + + self._verify_coordinator_command(mock_popen, ("-m", "mymodule")) + mock_sample.assert_called_once() + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + def test_cli_script_with_profiler_options(self): + """Test script with various profiler options.""" + test_args = [ + "profiling.sampling.cli", + "run", + "-i", + "2000", + "-d", + "60", + "--collapsed", + "-o", + "output.txt", + "myscript.py", + "scriptarg", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("os.path.exists", return_value=True), + ): + self._setup_sync_mocks(mock_socket, mock_popen) + main() + + self._verify_coordinator_command( + mock_popen, ("myscript.py", "scriptarg") + ) + # Verify profiler was called + mock_sample.assert_called_once() + + def test_cli_empty_module_name(self): + test_args = ["profiling.sampling.cli", "run", "-m"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("required: target", error_msg) # argparse error for missing positional arg + + @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist") + @requires_remote_subprocess_debugging() + def test_cli_long_module_option(self): + test_args = [ + "profiling.sampling.cli", + "run", + "-m", + "mymodule", + "arg1", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch("subprocess.Popen") as mock_popen, + mock.patch("socket.socket") as mock_socket, + mock.patch("profiling.sampling.cli._wait_for_ready_signal"), + mock.patch("importlib.util.find_spec", return_value=True), + ): + self._setup_sync_mocks(mock_socket, mock_popen) + main() + + self._verify_coordinator_command( + mock_popen, ("-m", "mymodule", "arg1") + ) + + def test_cli_complex_script_arguments(self): + test_args = [ + "profiling.sampling.cli", + "run", + "script.py", + "--input", + "file.txt", + "-v", + "--output=/tmp/out", + "positional", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + mock.patch( + "profiling.sampling.cli._run_with_sync" + ) as mock_run_with_sync, + mock.patch("os.path.exists", return_value=True), + ): + mock_process = mock.MagicMock() + mock_process.pid = 12345 + mock_process.wait.side_effect = [ + subprocess.TimeoutExpired(test_args, 0.1), + None, + ] + mock_process.poll.return_value = None + mock_run_with_sync.return_value = mock_process + + main() + + mock_run_with_sync.assert_called_once_with( + ( + sys.executable, + "script.py", + "--input", + "file.txt", + "-v", + "--output=/tmp/out", + "positional", + ), + suppress_output=False + ) + + def test_cli_collapsed_format_validation(self): + """Test that CLI properly validates incompatible options with collapsed format.""" + test_cases = [ + # Test sort option is invalid with collapsed + ( + [ + "profiling.sampling.cli", + "attach", + "12345", + "--collapsed", + "--sort", + "tottime", # Changed from nsamples (default) to trigger validation + ], + "sort", + ), + # Test limit option is invalid with collapsed + ( + [ + "profiling.sampling.cli", + "attach", + "12345", + "--collapsed", + "-l", + "20", + ], + "limit", + ), + # Test no-summary option is invalid with collapsed + ( + [ + "profiling.sampling.cli", + "attach", + "12345", + "--collapsed", + "--no-summary", + ], + "summary", + ), + ] + + for test_args, expected_error_keyword in test_cases: + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + mock.patch("profiling.sampling.cli.sample"), # Prevent actual profiling + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error code + error_msg = mock_stderr.getvalue() + self.assertIn("error:", error_msg) + self.assertIn("only valid with --pstats", error_msg) + + def test_cli_default_collapsed_filename(self): + """Test that collapsed format gets a default filename when not specified.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--collapsed"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + # Check that sample was called (exact filename depends on implementation) + mock_sample.assert_called_once() + + def test_cli_custom_output_filenames(self): + """Test custom output filenames for both formats.""" + test_cases = [ + ( + [ + "profiling.sampling.cli", + "attach", + "12345", + "--pstats", + "-o", + "custom.pstats", + ], + "custom.pstats", + "pstats", + ), + ( + [ + "profiling.sampling.cli", + "attach", + "12345", + "--collapsed", + "-o", + "custom.txt", + ], + "custom.txt", + "collapsed", + ), + ] + + for test_args, expected_filename, expected_format in test_cases: + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + mock_sample.assert_called_once() + + def test_cli_missing_required_arguments(self): + """Test that CLI requires subcommand.""" + with ( + mock.patch("sys.argv", ["profiling.sampling.cli"]), + mock.patch("sys.stderr", io.StringIO()), + ): + with self.assertRaises(SystemExit): + main() + + def test_cli_mutually_exclusive_format_options(self): + """Test that pstats and collapsed options are mutually exclusive.""" + with ( + mock.patch( + "sys.argv", + [ + "profiling.sampling.cli", + "attach", + "12345", + "--pstats", + "--collapsed", + ], + ), + mock.patch("sys.stderr", io.StringIO()), + ): + with self.assertRaises(SystemExit): + main() + + def test_argument_parsing_basic(self): + test_args = ["profiling.sampling.cli", "attach", "12345"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + mock_sample.assert_called_once() + + def test_sort_options(self): + sort_options = [ + ("nsamples", 0), + ("tottime", 1), + ("cumtime", 2), + ("sample-pct", 3), + ("cumul-pct", 4), + ("name", -1), + ] + + for option, expected_sort_value in sort_options: + test_args = ["profiling.sampling.cli", "attach", "12345", "--sort", option] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + mock_sample.assert_called_once() + mock_sample.reset_mock() + + def test_async_aware_flag_defaults_to_running(self): + """Test --async-aware flag enables async profiling with default 'running' mode.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + mock_sample.assert_called_once() + # Verify async_aware was passed with default "running" mode + call_kwargs = mock_sample.call_args[1] + self.assertEqual(call_kwargs.get("async_aware"), "running") + + def test_async_aware_with_async_mode_all(self): + """Test --async-aware with --async-mode all.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--async-mode", "all"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + mock_sample.assert_called_once() + call_kwargs = mock_sample.call_args[1] + self.assertEqual(call_kwargs.get("async_aware"), "all") + + def test_async_aware_default_is_none(self): + """Test async_aware defaults to None when --async-aware not specified.""" + test_args = ["profiling.sampling.cli", "attach", "12345"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + main() + + mock_sample.assert_called_once() + call_kwargs = mock_sample.call_args[1] + self.assertIsNone(call_kwargs.get("async_aware")) + + def test_async_mode_invalid_choice(self): + """Test --async-mode with invalid choice raises error.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--async-mode", "invalid"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()), + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + + def test_async_mode_requires_async_aware(self): + """Test --async-mode without --async-aware raises error.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-mode", "all"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--async-mode requires --async-aware", error_msg) + + def test_async_aware_incompatible_with_native(self): + """Test --async-aware is incompatible with --native.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--native"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--native", error_msg) + self.assertIn("incompatible with --async-aware", error_msg) + + def test_async_aware_incompatible_with_no_gc(self): + """Test --async-aware is incompatible with --no-gc.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--no-gc"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--no-gc", error_msg) + self.assertIn("incompatible with --async-aware", error_msg) + + def test_async_aware_incompatible_with_both_native_and_no_gc(self): + """Test --async-aware is incompatible with both --native and --no-gc.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--native", "--no-gc"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--native", error_msg) + self.assertIn("--no-gc", error_msg) + self.assertIn("incompatible with --async-aware", error_msg) + + def test_async_aware_incompatible_with_mode(self): + """Test --async-aware is incompatible with --mode (non-wall).""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--mode", "cpu"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--mode=cpu", error_msg) + self.assertIn("incompatible with --async-aware", error_msg) + + def test_async_aware_incompatible_with_all_threads(self): + """Test --async-aware is incompatible with --all-threads.""" + test_args = ["profiling.sampling.cli", "attach", "12345", "--async-aware", "--all-threads"] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("--all-threads", error_msg) + self.assertIn("incompatible with --async-aware", error_msg) + + @unittest.skipIf(is_emscripten, "subprocess not available") + def test_run_nonexistent_script_exits_cleanly(self): + """Test that running a non-existent script exits with a clean error.""" + with mock.patch("sys.argv", ["profiling.sampling.cli", "run", "/nonexistent/script.py"]): + with self.assertRaisesRegex(SamplingScriptNotFoundError, "Script '[\\w/.]+' not found."): + main() + + @unittest.skipIf(is_emscripten, "subprocess not available") + def test_run_nonexistent_module_exits_cleanly(self): + """Test that running a non-existent module exits with a clean error.""" + with mock.patch("sys.argv", ["profiling.sampling.cli", "run", "-m", "nonexistent_module_xyz"]): + with self.assertRaisesRegex(SamplingModuleNotFoundError, "Module '[\\w/.]+' not found."): + main() + + def test_cli_attach_nonexistent_pid(self): + fake_pid = "99999" + with mock.patch("sys.argv", ["profiling.sampling.cli", "attach", fake_pid]): + with self.assertRaises(SamplingUnknownProcessError) as cm: + main() + + self.assertIn(fake_pid, str(cm.exception)) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py new file mode 100644 index 00000000000..30615a7d31d --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_collectors.py @@ -0,0 +1,1827 @@ +"""Tests for sampling profiler collector components.""" + +import json +import marshal +import os +import tempfile +import unittest + +try: + import _remote_debugging # noqa: F401 + from profiling.sampling.pstats_collector import PstatsCollector + from profiling.sampling.stack_collector import ( + CollapsedStackCollector, + FlamegraphCollector, + ) + from profiling.sampling.gecko_collector import GeckoCollector + from profiling.sampling.collector import extract_lineno, normalize_location + from profiling.sampling.opcode_utils import get_opcode_info, format_opcode + from profiling.sampling.constants import ( + PROFILING_MODE_WALL, + PROFILING_MODE_CPU, + DEFAULT_LOCATION, + ) + from _remote_debugging import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, + THREAD_STATUS_GIL_REQUESTED, + ) +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from test.support import captured_stdout, captured_stderr + +from .mocks import MockFrameInfo, MockThreadInfo, MockInterpreterInfo, LocationInfo +from .helpers import close_and_unlink + + +class TestSampleProfilerComponents(unittest.TestCase): + """Unit tests for individual profiler components.""" + + def test_mock_frame_info_with_empty_and_unicode_values(self): + """Test MockFrameInfo handles empty strings, unicode characters, and very long names correctly.""" + # Test with empty strings + frame = MockFrameInfo("", 0, "") + self.assertEqual(frame.filename, "") + self.assertEqual(frame.location.lineno, 0) + self.assertEqual(frame.funcname, "") + + # Test with unicode characters + frame = MockFrameInfo("文件.py", 42, "函数名") + self.assertEqual(frame.filename, "文件.py") + self.assertEqual(frame.funcname, "函数名") + + # Test with very long names + long_filename = "x" * 1000 + ".py" + long_funcname = "func_" + "x" * 1000 + frame = MockFrameInfo(long_filename, 999999, long_funcname) + self.assertEqual(frame.filename, long_filename) + self.assertEqual(frame.location.lineno, 999999) + self.assertEqual(frame.funcname, long_funcname) + + def test_pstats_collector_with_extreme_intervals_and_empty_data(self): + """Test PstatsCollector handles zero/large intervals, empty frames, None thread IDs, and duplicate frames.""" + # Test with zero interval + collector = PstatsCollector(sample_interval_usec=0) + self.assertEqual(collector.sample_interval_usec, 0) + + # Test with very large interval + collector = PstatsCollector(sample_interval_usec=1000000000) + self.assertEqual(collector.sample_interval_usec, 1000000000) + + # Test collecting empty frames list + collector = PstatsCollector(sample_interval_usec=1000) + collector.collect([]) + self.assertEqual(len(collector.result), 0) + + # Test collecting frames with None thread id + test_frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(None, [MockFrameInfo("file.py", 10, "func", None)])], + ) + ] + collector.collect(test_frames) + # Should still process the frames + self.assertEqual(len(collector.result), 1) + + # Test collecting duplicate frames in same sample (recursive function) + test_frames = [ + MockInterpreterInfo( + 0, # interpreter_id + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("file.py", 10, "func1"), + MockFrameInfo("file.py", 10, "func1"), # Duplicate (recursion) + ], + ) + ], + ) + ] + collector = PstatsCollector(sample_interval_usec=1000) + collector.collect(test_frames) + # Should count only once per sample to avoid over-counting recursive functions + self.assertEqual( + collector.result[("file.py", 10, "func1")]["cumulative_calls"], 1 + ) + + def test_pstats_collector_single_frame_stacks(self): + """Test PstatsCollector with single-frame call stacks to trigger len(frames) <= 1 branch.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Test with exactly one frame (should trigger the <= 1 condition) + single_frame = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("single.py", 10, "single_func")] + ) + ], + ) + ] + collector.collect(single_frame) + + # Should record the single frame with inline call + self.assertEqual(len(collector.result), 1) + single_key = ("single.py", 10, "single_func") + self.assertIn(single_key, collector.result) + self.assertEqual(collector.result[single_key]["direct_calls"], 1) + self.assertEqual(collector.result[single_key]["cumulative_calls"], 1) + + # Test with empty frames (should also trigger <= 1 condition) + empty_frames = [MockInterpreterInfo(0, [MockThreadInfo(1, [])])] + collector.collect(empty_frames) + + # Should not add any new entries + self.assertEqual( + len(collector.result), 1 + ) # Still just the single frame + + # Test mixed single and multi-frame stacks + mixed_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("single2.py", 20, "single_func2")], + ), # Single frame + MockThreadInfo( + 2, + [ # Multi-frame stack + MockFrameInfo("multi.py", 30, "multi_func1"), + MockFrameInfo("multi.py", 40, "multi_func2"), + ], + ), + ], + ), + ] + collector.collect(mixed_frames) + + # Should have recorded all functions + self.assertEqual( + len(collector.result), 4 + ) # single + single2 + multi1 + multi2 + + # Verify single frame handling + single2_key = ("single2.py", 20, "single_func2") + self.assertIn(single2_key, collector.result) + self.assertEqual(collector.result[single2_key]["direct_calls"], 1) + self.assertEqual(collector.result[single2_key]["cumulative_calls"], 1) + + # Verify multi-frame handling still works + multi1_key = ("multi.py", 30, "multi_func1") + multi2_key = ("multi.py", 40, "multi_func2") + self.assertIn(multi1_key, collector.result) + self.assertIn(multi2_key, collector.result) + self.assertEqual(collector.result[multi1_key]["direct_calls"], 1) + self.assertEqual( + collector.result[multi2_key]["cumulative_calls"], 1 + ) # Called from multi1 + + def test_collapsed_stack_collector_with_empty_and_deep_stacks(self): + """Test CollapsedStackCollector handles empty frames, single-frame stacks, and very deep call stacks.""" + collector = CollapsedStackCollector(1000) + + # Test with empty frames + collector.collect([]) + self.assertEqual(len(collector.stack_counter), 0) + + # Test with single frame stack + test_frames = [ + MockInterpreterInfo( + 0, [MockThreadInfo(1, [MockFrameInfo("file.py", 10, "func")])] + ) + ] + collector.collect(test_frames) + self.assertEqual(len(collector.stack_counter), 1) + (((path, thread_id), count),) = collector.stack_counter.items() + self.assertEqual(path, (("file.py", 10, "func"),)) + self.assertEqual(thread_id, 1) + self.assertEqual(count, 1) + + # Test with very deep stack + deep_stack = [MockFrameInfo(f"file{i}.py", i, f"func{i}") for i in range(100)] + test_frames = [MockInterpreterInfo(0, [MockThreadInfo(1, deep_stack)])] + collector = CollapsedStackCollector(1000) + collector.collect(test_frames) + # One aggregated path with 100 frames (reversed) + (((path_tuple, thread_id),),) = (collector.stack_counter.keys(),) + self.assertEqual(len(path_tuple), 100) + self.assertEqual(path_tuple[0], ("file99.py", 99, "func99")) + self.assertEqual(path_tuple[-1], ("file0.py", 0, "func0")) + self.assertEqual(thread_id, 1) + + def test_pstats_collector_basic(self): + """Test basic PstatsCollector functionality.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Test empty state + self.assertEqual(len(collector.result), 0) + self.assertEqual(len(collector.stats), 0) + + # Test collecting sample data + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("file.py", 10, "func1"), + MockFrameInfo("file.py", 20, "func2"), + ], + ) + ], + ) + ] + collector.collect(test_frames) + + # Should have recorded calls for both functions + self.assertEqual(len(collector.result), 2) + self.assertIn(("file.py", 10, "func1"), collector.result) + self.assertIn(("file.py", 20, "func2"), collector.result) + + # Top-level function should have direct call + self.assertEqual( + collector.result[("file.py", 10, "func1")]["direct_calls"], 1 + ) + self.assertEqual( + collector.result[("file.py", 10, "func1")]["cumulative_calls"], 1 + ) + + # Calling function should have cumulative call but no direct calls + self.assertEqual( + collector.result[("file.py", 20, "func2")]["cumulative_calls"], 1 + ) + self.assertEqual( + collector.result[("file.py", 20, "func2")]["direct_calls"], 0 + ) + + def test_pstats_collector_create_stats(self): + """Test PstatsCollector stats creation.""" + collector = PstatsCollector( + sample_interval_usec=1000000 + ) # 1 second intervals + + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("file.py", 10, "func1"), + MockFrameInfo("file.py", 20, "func2"), + ], + ) + ], + ) + ] + collector.collect(test_frames) + collector.collect(test_frames) # Collect twice + + collector.create_stats() + + # Check stats format: (direct_calls, cumulative_calls, tt, ct, callers) + func1_stats = collector.stats[("file.py", 10, "func1")] + self.assertEqual(func1_stats[0], 2) # direct_calls (top of stack) + self.assertEqual(func1_stats[1], 2) # cumulative_calls + self.assertEqual( + func1_stats[2], 2.0 + ) # tt (total time - 2 samples * 1 sec) + self.assertEqual(func1_stats[3], 2.0) # ct (cumulative time) + + func2_stats = collector.stats[("file.py", 20, "func2")] + self.assertEqual( + func2_stats[0], 0 + ) # direct_calls (never top of stack) + self.assertEqual( + func2_stats[1], 2 + ) # cumulative_calls (appears in stack) + self.assertEqual(func2_stats[2], 0.0) # tt (no direct calls) + self.assertEqual(func2_stats[3], 2.0) # ct (cumulative time) + + def test_collapsed_stack_collector_basic(self): + collector = CollapsedStackCollector(1000) + + # Test empty state + self.assertEqual(len(collector.stack_counter), 0) + + # Test collecting sample data + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] + collector.collect(test_frames) + + # Should store one reversed path + self.assertEqual(len(collector.stack_counter), 1) + (((path, thread_id), count),) = collector.stack_counter.items() + expected_tree = (("file.py", 20, "func2"), ("file.py", 10, "func1")) + self.assertEqual(path, expected_tree) + self.assertEqual(thread_id, 1) + self.assertEqual(count, 1) + + def test_collapsed_stack_collector_export(self): + collapsed_out = tempfile.NamedTemporaryFile(delete=False) + self.addCleanup(close_and_unlink, collapsed_out) + + collector = CollapsedStackCollector(1000) + + test_frames1 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] + test_frames2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] # Same stack + test_frames3 = [ + MockInterpreterInfo( + 0, [MockThreadInfo(1, [MockFrameInfo("other.py", 5, "other_func")])] + ) + ] + + collector.collect(test_frames1) + collector.collect(test_frames2) + collector.collect(test_frames3) + + with captured_stdout(), captured_stderr(): + collector.export(collapsed_out.name) + # Check file contents + with open(collapsed_out.name, "r") as f: + content = f.read() + + lines = content.strip().split("\n") + self.assertEqual(len(lines), 2) # Two unique stacks + + # Check collapsed format: tid:X;file:func:line;file:func:line count + stack1_expected = "tid:1;file.py:func2:20;file.py:func1:10 2" + stack2_expected = "tid:1;other.py:other_func:5 1" + + self.assertIn(stack1_expected, lines) + self.assertIn(stack2_expected, lines) + + def test_flamegraph_collector_basic(self): + """Test basic FlamegraphCollector functionality.""" + collector = FlamegraphCollector(1000) + + # Empty collector should produce 'No Data' + data = collector._convert_to_flamegraph_format() + # With string table, name is now an index - resolve it using the strings array + strings = data.get("strings", []) + name_index = data.get("name", 0) + resolved_name = ( + strings[name_index] + if isinstance(name_index, int) and 0 <= name_index < len(strings) + else str(name_index) + ) + self.assertIn(resolved_name, ("No Data", "No significant data")) + + # Test collecting sample data + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] + collector.collect(test_frames) + + # Convert and verify structure: func2 -> func1 with counts = 1 + data = collector._convert_to_flamegraph_format() + # Expect promotion: root is the single child (func2), with func1 as its only child + strings = data.get("strings", []) + name_index = data.get("name", 0) + name = ( + strings[name_index] + if isinstance(name_index, int) and 0 <= name_index < len(strings) + else str(name_index) + ) + self.assertIsInstance(name, str) + self.assertTrue(name.startswith("Program Root: ")) + self.assertIn("func2 (file.py:20)", name) # formatted name + children = data.get("children", []) + self.assertEqual(len(children), 1) + child = children[0] + child_name_index = child.get("name", 0) + child_name = ( + strings[child_name_index] + if isinstance(child_name_index, int) + and 0 <= child_name_index < len(strings) + else str(child_name_index) + ) + self.assertIn("func1 (file.py:10)", child_name) # formatted name + self.assertEqual(child["value"], 1) + + def test_flamegraph_collector_export(self): + """Test flamegraph HTML export functionality.""" + flamegraph_out = tempfile.NamedTemporaryFile( + suffix=".html", delete=False + ) + self.addCleanup(close_and_unlink, flamegraph_out) + + collector = FlamegraphCollector(1000) + + # Create some test data (use Interpreter/Thread objects like runtime) + test_frames1 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] + test_frames2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] # Same stack + test_frames3 = [ + MockInterpreterInfo( + 0, [MockThreadInfo(1, [MockFrameInfo("other.py", 5, "other_func")])] + ) + ] + + collector.collect(test_frames1) + collector.collect(test_frames2) + collector.collect(test_frames3) + + # Export flamegraph + with captured_stdout(), captured_stderr(): + collector.export(flamegraph_out.name) + + # Verify file was created and contains valid data + self.assertTrue(os.path.exists(flamegraph_out.name)) + self.assertGreater(os.path.getsize(flamegraph_out.name), 0) + + # Check file contains HTML content + with open(flamegraph_out.name, "r", encoding="utf-8") as f: + content = f.read() + + # Should be valid HTML + self.assertIn("<!doctype html>", content.lower()) + self.assertIn("<html", content) + self.assertIn("Tachyon Profiler - Flamegraph", content) + self.assertIn("d3-flame-graph", content) + + # Should contain the data + self.assertIn('"name":', content) + self.assertIn('"value":', content) + self.assertIn('"children":', content) + + def test_gecko_collector_basic(self): + """Test basic GeckoCollector functionality.""" + collector = GeckoCollector(1000) + + # Test empty state + self.assertEqual(len(collector.threads), 0) + self.assertEqual(collector.sample_count, 0) + self.assertEqual(len(collector.global_strings), 1) # "(root)" + + # Test collecting sample data + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")], + ) + ], + ) + ] + collector.collect(test_frames) + + # Should have recorded one thread and one sample + self.assertEqual(len(collector.threads), 1) + self.assertEqual(collector.sample_count, 1) + self.assertIn(1, collector.threads) + + profile_data = collector._build_profile() + + # Verify profile structure + self.assertIn("meta", profile_data) + self.assertIn("threads", profile_data) + self.assertIn("shared", profile_data) + + # Check shared string table + shared = profile_data["shared"] + self.assertIn("stringArray", shared) + string_array = shared["stringArray"] + self.assertGreater(len(string_array), 0) + + # Should contain our functions in the string array + self.assertIn("func1", string_array) + self.assertIn("func2", string_array) + + # Check thread data structure + threads = profile_data["threads"] + self.assertEqual(len(threads), 1) + thread_data = threads[0] + + # Verify thread structure + self.assertIn("samples", thread_data) + self.assertIn("funcTable", thread_data) + self.assertIn("frameTable", thread_data) + self.assertIn("stackTable", thread_data) + + # Verify samples + samples = thread_data["samples"] + self.assertEqual(len(samples["stack"]), 1) + self.assertEqual(len(samples["time"]), 1) + self.assertEqual(samples["length"], 1) + + # Verify function table structure and content + func_table = thread_data["funcTable"] + self.assertIn("name", func_table) + self.assertIn("fileName", func_table) + self.assertIn("lineNumber", func_table) + self.assertEqual(func_table["length"], 2) # Should have 2 functions + + # Verify actual function content through string array indices + func_names = [] + for idx in func_table["name"]: + func_name = ( + string_array[idx] + if isinstance(idx, int) and 0 <= idx < len(string_array) + else str(idx) + ) + func_names.append(func_name) + + self.assertIn("func1", func_names, f"func1 not found in {func_names}") + self.assertIn("func2", func_names, f"func2 not found in {func_names}") + + # Verify frame table + frame_table = thread_data["frameTable"] + self.assertEqual( + frame_table["length"], 2 + ) # Should have frames for both functions + self.assertEqual(len(frame_table["func"]), 2) + + # Verify stack structure + stack_table = thread_data["stackTable"] + self.assertGreater(stack_table["length"], 0) + self.assertGreater(len(stack_table["frame"]), 0) + + def test_gecko_collector_export(self): + """Test Gecko profile export functionality.""" + gecko_out = tempfile.NamedTemporaryFile(suffix=".json", delete=False) + self.addCleanup(close_and_unlink, gecko_out) + + collector = GeckoCollector(1000) + + test_frames1 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] + test_frames2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("file.py", 10, "func1"), MockFrameInfo("file.py", 20, "func2")] + ) + ], + ) + ] # Same stack + test_frames3 = [ + MockInterpreterInfo( + 0, [MockThreadInfo(1, [MockFrameInfo("other.py", 5, "other_func")])] + ) + ] + + collector.collect(test_frames1) + collector.collect(test_frames2) + collector.collect(test_frames3) + + # Export gecko profile + with captured_stdout(), captured_stderr(): + collector.export(gecko_out.name) + + # Verify file was created and contains valid data + self.assertTrue(os.path.exists(gecko_out.name)) + self.assertGreater(os.path.getsize(gecko_out.name), 0) + + # Check file contains valid JSON + with open(gecko_out.name, "r") as f: + profile_data = json.load(f) + + # Should be valid Gecko profile format + self.assertIn("meta", profile_data) + self.assertIn("threads", profile_data) + self.assertIn("shared", profile_data) + + # Check meta information + self.assertIn("categories", profile_data["meta"]) + self.assertIn("interval", profile_data["meta"]) + + # Check shared string table + self.assertIn("stringArray", profile_data["shared"]) + self.assertGreater(len(profile_data["shared"]["stringArray"]), 0) + + # Should contain our functions + string_array = profile_data["shared"]["stringArray"] + self.assertIn("func1", string_array) + self.assertIn("func2", string_array) + self.assertIn("other_func", string_array) + + def test_gecko_collector_markers(self): + """Test Gecko profile markers for GIL and CPU state tracking.""" + collector = GeckoCollector(1000) + + # Status combinations for different thread states + HAS_GIL_ON_CPU = ( + THREAD_STATUS_HAS_GIL | THREAD_STATUS_ON_CPU + ) # Running Python code + NO_GIL_ON_CPU = THREAD_STATUS_ON_CPU # Running native code + WAITING_FOR_GIL = THREAD_STATUS_GIL_REQUESTED # Waiting for GIL + + # Simulate thread state transitions + collector.collect( + [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("test.py", 10, "python_func")], + status=HAS_GIL_ON_CPU, + ) + ], + ) + ] + ) + + collector.collect( + [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("test.py", 15, "wait_func")], + status=WAITING_FOR_GIL, + ) + ], + ) + ] + ) + + collector.collect( + [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("test.py", 20, "python_func2")], + status=HAS_GIL_ON_CPU, + ) + ], + ) + ] + ) + + collector.collect( + [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("native.c", 100, "native_func")], + status=NO_GIL_ON_CPU, + ) + ], + ) + ] + ) + + profile_data = collector._build_profile() + + # Verify we have threads with markers + self.assertIn("threads", profile_data) + self.assertEqual(len(profile_data["threads"]), 1) + thread_data = profile_data["threads"][0] + + # Check markers exist + self.assertIn("markers", thread_data) + markers = thread_data["markers"] + + # Should have marker arrays + self.assertIn("name", markers) + self.assertIn("startTime", markers) + self.assertIn("endTime", markers) + self.assertIn("category", markers) + self.assertGreater( + markers["length"], 0, "Should have generated markers" + ) + + # Get marker names from string table + string_array = profile_data["shared"]["stringArray"] + marker_names = [string_array[idx] for idx in markers["name"]] + + # Verify we have different marker types + marker_name_set = set(marker_names) + + # Should have "Has GIL" markers (when thread had GIL) + self.assertIn( + "Has GIL", marker_name_set, "Should have 'Has GIL' markers" + ) + + # Should have "No GIL" markers (when thread didn't have GIL) + self.assertIn( + "No GIL", marker_name_set, "Should have 'No GIL' markers" + ) + + # Should have "On CPU" markers (when thread was on CPU) + self.assertIn( + "On CPU", marker_name_set, "Should have 'On CPU' markers" + ) + + # Should have "Waiting for GIL" markers (when thread was waiting) + self.assertIn( + "Waiting for GIL", + marker_name_set, + "Should have 'Waiting for GIL' markers", + ) + + # Verify marker structure + for i in range(markers["length"]): + # All markers should be interval markers (phase = 1) + self.assertEqual( + markers["phase"][i], 1, f"Marker {i} should be interval marker" + ) + + # All markers should have valid time range + start_time = markers["startTime"][i] + end_time = markers["endTime"][i] + self.assertLessEqual( + start_time, + end_time, + f"Marker {i} should have valid time range", + ) + + # All markers should have valid category + self.assertGreaterEqual( + markers["category"][i], + 0, + f"Marker {i} should have valid category", + ) + + def test_pstats_collector_export(self): + collector = PstatsCollector( + sample_interval_usec=1000000 + ) # 1 second intervals + + test_frames1 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("file.py", 10, "func1"), + MockFrameInfo("file.py", 20, "func2"), + ], + ) + ], + ) + ] + test_frames2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("file.py", 10, "func1"), + MockFrameInfo("file.py", 20, "func2"), + ], + ) + ], + ) + ] # Same stack + test_frames3 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, [MockFrameInfo("other.py", 5, "other_func")] + ) + ], + ) + ] + + collector.collect(test_frames1) + collector.collect(test_frames2) + collector.collect(test_frames3) + + pstats_out = tempfile.NamedTemporaryFile( + suffix=".pstats", delete=False + ) + self.addCleanup(close_and_unlink, pstats_out) + collector.export(pstats_out.name) + + # Check file can be loaded with marshal + with open(pstats_out.name, "rb") as f: + stats_data = marshal.load(f) + + # Should be a dictionary with the sampled marker + self.assertIsInstance(stats_data, dict) + self.assertIn(("__sampled__",), stats_data) + self.assertTrue(stats_data[("__sampled__",)]) + + # Should have function data + function_entries = [ + k for k in stats_data.keys() if k != ("__sampled__",) + ] + self.assertGreater(len(function_entries), 0) + + # Check specific function stats format: (cc, nc, tt, ct, callers) + func1_key = ("file.py", 10, "func1") + func2_key = ("file.py", 20, "func2") + other_key = ("other.py", 5, "other_func") + + self.assertIn(func1_key, stats_data) + self.assertIn(func2_key, stats_data) + self.assertIn(other_key, stats_data) + + # Check func1 stats (should have 2 samples) + func1_stats = stats_data[func1_key] + self.assertEqual(func1_stats[0], 2) # total_calls + self.assertEqual(func1_stats[1], 2) # nc (non-recursive calls) + self.assertEqual(func1_stats[2], 2.0) # tt (total time) + self.assertEqual(func1_stats[3], 2.0) # ct (cumulative time) + + def test_flamegraph_collector_stats_accumulation(self): + """Test that FlamegraphCollector accumulates stats across samples.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # First sample + stack_frames_1 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func_a")], status=THREAD_STATUS_HAS_GIL), + MockThreadInfo(2, [MockFrameInfo("b.py", 2, "func_b")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + collector.collect(stack_frames_1) + self.assertEqual(collector.thread_status_counts["has_gil"], 1) + self.assertEqual(collector.thread_status_counts["on_cpu"], 1) + self.assertEqual(collector.thread_status_counts["total"], 2) + + # Second sample + stack_frames_2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func_a")], status=THREAD_STATUS_GIL_REQUESTED), + MockThreadInfo(2, [MockFrameInfo("b.py", 2, "func_b")], status=THREAD_STATUS_HAS_GIL), + MockThreadInfo(3, [MockFrameInfo("c.py", 3, "func_c")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + collector.collect(stack_frames_2) + + # Should accumulate + self.assertEqual(collector.thread_status_counts["has_gil"], 2) # 1 + 1 + self.assertEqual(collector.thread_status_counts["on_cpu"], 2) # 1 + 1 + self.assertEqual(collector.thread_status_counts["gil_requested"], 1) # 0 + 1 + self.assertEqual(collector.thread_status_counts["total"], 5) # 2 + 3 + + # Test GC sample tracking + stack_frames_gc = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("~", 0, "<GC>")], status=THREAD_STATUS_HAS_GIL), + ], + ) + ] + collector.collect(stack_frames_gc) + self.assertEqual(collector.samples_with_gc_frames, 1) + + # Another sample without GC + collector.collect(stack_frames_1) + self.assertEqual(collector.samples_with_gc_frames, 1) # Still 1 + + # Another GC sample + collector.collect(stack_frames_gc) + self.assertEqual(collector.samples_with_gc_frames, 2) + + def test_flamegraph_collector_per_thread_stats(self): + """Test per-thread statistics tracking in FlamegraphCollector.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Multiple threads with different states + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func_a")], status=THREAD_STATUS_HAS_GIL), + MockThreadInfo(2, [MockFrameInfo("b.py", 2, "func_b")], status=THREAD_STATUS_ON_CPU), + MockThreadInfo(3, [MockFrameInfo("c.py", 3, "func_c")], status=THREAD_STATUS_GIL_REQUESTED), + ], + ) + ] + collector.collect(stack_frames) + + # Check per-thread stats + self.assertIn(1, collector.per_thread_stats) + self.assertIn(2, collector.per_thread_stats) + self.assertIn(3, collector.per_thread_stats) + + # Thread 1: has GIL + self.assertEqual(collector.per_thread_stats[1]["has_gil"], 1) + self.assertEqual(collector.per_thread_stats[1]["on_cpu"], 0) + self.assertEqual(collector.per_thread_stats[1]["total"], 1) + + # Thread 2: on CPU + self.assertEqual(collector.per_thread_stats[2]["has_gil"], 0) + self.assertEqual(collector.per_thread_stats[2]["on_cpu"], 1) + self.assertEqual(collector.per_thread_stats[2]["total"], 1) + + # Thread 3: waiting + self.assertEqual(collector.per_thread_stats[3]["gil_requested"], 1) + self.assertEqual(collector.per_thread_stats[3]["total"], 1) + + # Test accumulation across samples + stack_frames_2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 2, "func_b")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + collector.collect(stack_frames_2) + + self.assertEqual(collector.per_thread_stats[1]["has_gil"], 1) + self.assertEqual(collector.per_thread_stats[1]["on_cpu"], 1) + self.assertEqual(collector.per_thread_stats[1]["total"], 2) + + def test_flamegraph_collector_percentage_calculations(self): + """Test that percentage calculations are correct in exported data.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Create scenario: 60% GIL held, 40% not held + for i in range(6): + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func")], status=THREAD_STATUS_HAS_GIL), + ], + ) + ] + collector.collect(stack_frames) + + for i in range(4): + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + collector.collect(stack_frames) + + # Export to get calculated percentages + data = collector._convert_to_flamegraph_format() + thread_stats = data["stats"]["thread_stats"] + + self.assertAlmostEqual(thread_stats["has_gil_pct"], 60.0, places=1) + self.assertAlmostEqual(thread_stats["on_cpu_pct"], 40.0, places=1) + self.assertEqual(thread_stats["total"], 10) + + def test_flamegraph_collector_mode_handling(self): + """Test that profiling mode is correctly passed through to exported data.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Collect some data + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func")], status=THREAD_STATUS_HAS_GIL), + ], + ) + ] + collector.collect(stack_frames) + + # Set stats with mode + collector.set_stats( + sample_interval_usec=1000, + duration_sec=1.0, + sample_rate=1000.0, + mode=PROFILING_MODE_CPU + ) + + data = collector._convert_to_flamegraph_format() + self.assertEqual(data["stats"]["mode"], PROFILING_MODE_CPU) + + def test_flamegraph_collector_zero_samples_edge_case(self): + """Test that collector handles zero samples gracefully.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Export without collecting any samples + data = collector._convert_to_flamegraph_format() + + # Should return a valid structure with no data + self.assertIn("name", data) + self.assertEqual(data["value"], 0) + self.assertIn("children", data) + self.assertEqual(len(data["children"]), 0) + + def test_flamegraph_collector_json_structure_includes_stats(self): + """Test that exported JSON includes thread_stats and per_thread_stats.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Collect some data with multiple threads + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func_a")], status=THREAD_STATUS_HAS_GIL), + MockThreadInfo(2, [MockFrameInfo("b.py", 2, "func_b")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + collector.collect(stack_frames) + + # Set stats + collector.set_stats( + sample_interval_usec=1000, + duration_sec=1.0, + sample_rate=1000.0, + mode=PROFILING_MODE_WALL + ) + + # Export and verify structure + data = collector._convert_to_flamegraph_format() + + # Check that stats object exists and contains expected fields + self.assertIn("stats", data) + stats = data["stats"] + + # Verify thread_stats exists and has expected structure + self.assertIn("thread_stats", stats) + thread_stats = stats["thread_stats"] + self.assertIn("has_gil_pct", thread_stats) + self.assertIn("on_cpu_pct", thread_stats) + self.assertIn("gil_requested_pct", thread_stats) + self.assertIn("gc_pct", thread_stats) + self.assertIn("total", thread_stats) + + # Verify per_thread_stats exists and has data for both threads + self.assertIn("per_thread_stats", stats) + per_thread_stats = stats["per_thread_stats"] + self.assertIn(1, per_thread_stats) + self.assertIn(2, per_thread_stats) + + # Check per-thread structure + for thread_id in [1, 2]: + thread_data = per_thread_stats[thread_id] + self.assertIn("has_gil_pct", thread_data) + self.assertIn("on_cpu_pct", thread_data) + self.assertIn("gil_requested_pct", thread_data) + self.assertIn("gc_pct", thread_data) + self.assertIn("total", thread_data) + + def test_flamegraph_collector_per_thread_gc_percentage(self): + """Test that per-thread GC percentage uses total samples as denominator.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + # Create 10 samples total: + # - Thread 1 appears in all 10 samples, has GC in 2 of them + # - Thread 2 appears in only 5 samples, has GC in 1 of them + + # First 5 samples: both threads, thread 1 has GC in 2 + for i in range(5): + has_gc = i < 2 # First 2 samples have GC for thread 1 + frames_1 = [MockFrameInfo("~", 0, "<GC>")] if has_gc else [MockFrameInfo("a.py", 1, "func_a")] + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, frames_1, status=THREAD_STATUS_HAS_GIL), + MockThreadInfo(2, [MockFrameInfo("b.py", 2, "func_b")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + collector.collect(stack_frames) + + # Next 5 samples: only thread 1, thread 2 appears in first of these with GC + for i in range(5): + if i == 0: + # Thread 2 appears in this sample with GC + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func_a")], status=THREAD_STATUS_HAS_GIL), + MockThreadInfo(2, [MockFrameInfo("~", 0, "<GC>")], status=THREAD_STATUS_ON_CPU), + ], + ) + ] + else: + # Only thread 1 + stack_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo(1, [MockFrameInfo("a.py", 1, "func_a")], status=THREAD_STATUS_HAS_GIL), + ], + ) + ] + collector.collect(stack_frames) + + # Set stats and export + collector.set_stats( + sample_interval_usec=1000, + duration_sec=1.0, + sample_rate=1000.0, + mode=PROFILING_MODE_WALL + ) + + data = collector._convert_to_flamegraph_format() + per_thread_stats = data["stats"]["per_thread_stats"] + + # Thread 1: appeared in 10 samples, had GC in 2 + # GC percentage should be 2/10 = 20% (using total samples, not thread appearances) + self.assertEqual(collector.per_thread_stats[1]["gc_samples"], 2) + self.assertEqual(collector.per_thread_stats[1]["total"], 10) + self.assertAlmostEqual(per_thread_stats[1]["gc_pct"], 20.0, places=1) + + # Thread 2: appeared in 6 samples, had GC in 1 + # GC percentage should be 1/10 = 10% (using total samples, not thread appearances) + self.assertEqual(collector.per_thread_stats[2]["gc_samples"], 1) + self.assertEqual(collector.per_thread_stats[2]["total"], 6) + self.assertAlmostEqual(per_thread_stats[2]["gc_pct"], 10.0, places=1) + + +class TestRecursiveFunctionHandling(unittest.TestCase): + """Tests for correct handling of recursive functions in cumulative stats.""" + + def test_pstats_collector_recursive_function_single_sample(self): + """Test that recursive functions are counted once per sample, not per occurrence.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Simulate a recursive function appearing 5 times in one sample + recursive_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ], + ) + ], + ) + ] + collector.collect(recursive_frames) + + location = ("test.py", 10, "recursive_func") + # Should count as 1 cumulative call (present in 1 sample), not 5 + self.assertEqual(collector.result[location]["cumulative_calls"], 1) + # Direct calls should be 1 (top of stack) + self.assertEqual(collector.result[location]["direct_calls"], 1) + + def test_pstats_collector_recursive_function_multiple_samples(self): + """Test cumulative counting across multiple samples with recursion.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Sample 1: recursive function at depth 3 + sample1 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ], + ) + ], + ) + ] + # Sample 2: recursive function at depth 2 + sample2 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ], + ) + ], + ) + ] + # Sample 3: recursive function at depth 4 + sample3 = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ], + ) + ], + ) + ] + + collector.collect(sample1) + collector.collect(sample2) + collector.collect(sample3) + + location = ("test.py", 10, "recursive_func") + # Should count as 3 cumulative calls (present in 3 samples) + # Not 3+2+4=9 which would be the buggy behavior + self.assertEqual(collector.result[location]["cumulative_calls"], 3) + self.assertEqual(collector.result[location]["direct_calls"], 3) + + def test_pstats_collector_mixed_recursive_and_nonrecursive(self): + """Test a call stack with both recursive and non-recursive functions.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Stack: main -> foo (recursive x3) -> bar + frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("test.py", 50, "bar"), # top of stack + MockFrameInfo("test.py", 20, "foo"), # recursive + MockFrameInfo("test.py", 20, "foo"), # recursive + MockFrameInfo("test.py", 20, "foo"), # recursive + MockFrameInfo("test.py", 10, "main"), # bottom + ], + ) + ], + ) + ] + collector.collect(frames) + + # bar: 1 cumulative (in stack), 1 direct (top) + self.assertEqual(collector.result[("test.py", 50, "bar")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 50, "bar")]["direct_calls"], 1) + + # foo: 1 cumulative (counted once despite 3 occurrences), 0 direct + self.assertEqual(collector.result[("test.py", 20, "foo")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 20, "foo")]["direct_calls"], 0) + + # main: 1 cumulative, 0 direct + self.assertEqual(collector.result[("test.py", 10, "main")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 10, "main")]["direct_calls"], 0) + + def test_pstats_collector_cumulative_percentage_cannot_exceed_100(self): + """Test that cumulative percentage stays <= 100% even with deep recursion.""" + collector = PstatsCollector(sample_interval_usec=1000000) # 1 second for easy math + + # Collect 10 samples, each with recursive function at depth 100 + for _ in range(10): + frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [MockFrameInfo("test.py", 10, "deep_recursive")] * 100, + ) + ], + ) + ] + collector.collect(frames) + + location = ("test.py", 10, "deep_recursive") + # Cumulative calls should be 10 (number of samples), not 1000 + self.assertEqual(collector.result[location]["cumulative_calls"], 10) + + # Verify stats calculation gives correct percentage + collector.create_stats() + stats = collector.stats[location] + # stats format: (direct_calls, cumulative_calls, total_time, cumulative_time, callers) + cumulative_calls = stats[1] + self.assertEqual(cumulative_calls, 10) + + def test_pstats_collector_different_lines_same_function_counted_separately(self): + """Test that different line numbers in same function are tracked separately.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Function with multiple line numbers (e.g., different call sites within recursion) + frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("test.py", 15, "func"), # line 15 + MockFrameInfo("test.py", 12, "func"), # line 12 + MockFrameInfo("test.py", 15, "func"), # line 15 again + MockFrameInfo("test.py", 10, "func"), # line 10 + ], + ) + ], + ) + ] + collector.collect(frames) + + # Each unique (file, line, func) should be counted once + self.assertEqual(collector.result[("test.py", 15, "func")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 12, "func")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 10, "func")]["cumulative_calls"], 1) + + +class TestLocationHelpers(unittest.TestCase): + """Tests for location handling helper functions.""" + + def test_extract_lineno_from_location_info(self): + """Test extracting lineno from LocationInfo namedtuple.""" + loc = LocationInfo(42, 45, 0, 10) + self.assertEqual(extract_lineno(loc), 42) + + def test_extract_lineno_from_tuple(self): + """Test extracting lineno from plain tuple.""" + loc = (100, 105, 5, 20) + self.assertEqual(extract_lineno(loc), 100) + + def test_extract_lineno_from_none(self): + """Test extracting lineno from None (synthetic frames).""" + self.assertEqual(extract_lineno(None), 0) + + def test_normalize_location_with_location_info(self): + """Test normalize_location passes through LocationInfo.""" + loc = LocationInfo(10, 15, 0, 5) + result = normalize_location(loc) + self.assertEqual(result, loc) + + def test_normalize_location_with_tuple(self): + """Test normalize_location passes through tuple.""" + loc = (10, 15, 0, 5) + result = normalize_location(loc) + self.assertEqual(result, loc) + + def test_normalize_location_with_none(self): + """Test normalize_location returns DEFAULT_LOCATION for None.""" + result = normalize_location(None) + self.assertEqual(result, DEFAULT_LOCATION) + self.assertEqual(result, (0, 0, -1, -1)) + + +class TestOpcodeFormatting(unittest.TestCase): + """Tests for opcode formatting utilities.""" + + def test_get_opcode_info_standard_opcode(self): + """Test get_opcode_info for a standard opcode.""" + import opcode + # LOAD_CONST is a standard opcode + load_const = opcode.opmap.get('LOAD_CONST') + if load_const is not None: + info = get_opcode_info(load_const) + self.assertEqual(info['opname'], 'LOAD_CONST') + self.assertEqual(info['base_opname'], 'LOAD_CONST') + self.assertFalse(info['is_specialized']) + + def test_get_opcode_info_unknown_opcode(self): + """Test get_opcode_info for an unknown opcode.""" + info = get_opcode_info(999) + self.assertEqual(info['opname'], '<999>') + self.assertEqual(info['base_opname'], '<999>') + self.assertFalse(info['is_specialized']) + + def test_format_opcode_standard(self): + """Test format_opcode for a standard opcode.""" + import opcode + load_const = opcode.opmap.get('LOAD_CONST') + if load_const is not None: + formatted = format_opcode(load_const) + self.assertEqual(formatted, 'LOAD_CONST') + + def test_format_opcode_specialized(self): + """Test format_opcode for a specialized opcode shows base in parens.""" + import opcode + if not hasattr(opcode, '_specialized_opmap'): + self.skipTest("No specialized opcodes in this Python version") + if not hasattr(opcode, '_specializations'): + self.skipTest("No specialization info in this Python version") + + # Find any specialized opcode to test + for base_name, variants in opcode._specializations.items(): + if not variants: + continue + variant_name = variants[0] + variant_opcode = opcode._specialized_opmap.get(variant_name) + if variant_opcode is None: + continue + formatted = format_opcode(variant_opcode) + # Should show: VARIANT_NAME (BASE_NAME) + self.assertIn(variant_name, formatted) + self.assertIn(f'({base_name})', formatted) + return + + self.skipTest("No specialized opcodes found") + + def test_format_opcode_unknown(self): + """Test format_opcode for an unknown opcode.""" + formatted = format_opcode(999) + self.assertEqual(formatted, '<999>') + + +class TestLocationInCollectors(unittest.TestCase): + """Tests for location tuple handling in each collector.""" + + def _make_frames_with_location(self, location, opcode=None): + """Create test frames with a specific location.""" + frame = MockFrameInfo("test.py", 0, "test_func", opcode) + # Override the location + frame.location = location + return [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame], status=THREAD_STATUS_HAS_GIL)] + ) + ] + + def test_pstats_collector_with_location_info(self): + """Test PstatsCollector handles LocationInfo properly.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Frame with LocationInfo + frame = MockFrameInfo("test.py", 42, "my_function") + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames) + + # Should extract lineno from location + key = ("test.py", 42, "my_function") + self.assertIn(key, collector.result) + self.assertEqual(collector.result[key]["direct_calls"], 1) + + def test_pstats_collector_with_none_location(self): + """Test PstatsCollector handles None location (synthetic frames).""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Create frame with None location (like GC frame) + frame = MockFrameInfo("~", 0, "<GC>") + frame.location = None # Synthetic frame has no location + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames) + + # Should use lineno=0 for None location + key = ("~", 0, "<GC>") + self.assertIn(key, collector.result) + + def test_collapsed_stack_with_location_info(self): + """Test CollapsedStackCollector handles LocationInfo properly.""" + collector = CollapsedStackCollector(1000) + + frame1 = MockFrameInfo("main.py", 10, "main") + frame2 = MockFrameInfo("utils.py", 25, "helper") + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame1, frame2], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames) + + # Check that linenos were extracted correctly + self.assertEqual(len(collector.stack_counter), 1) + (path, _), count = list(collector.stack_counter.items())[0] + # Reversed order: helper at top, main at bottom + self.assertEqual(path[0], ("utils.py", 25, "helper")) + self.assertEqual(path[1], ("main.py", 10, "main")) + + def test_flamegraph_collector_with_location_info(self): + """Test FlamegraphCollector handles LocationInfo properly.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + + frame = MockFrameInfo("app.py", 100, "process_data") + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames) + + data = collector._convert_to_flamegraph_format() + # Verify the function name includes lineno from location + strings = data.get("strings", []) + name_found = any("process_data" in s and "100" in s for s in strings if isinstance(s, str)) + self.assertTrue(name_found, f"Expected to find 'process_data' with line 100 in {strings}") + + def test_gecko_collector_with_location_info(self): + """Test GeckoCollector handles LocationInfo properly.""" + collector = GeckoCollector(sample_interval_usec=1000) + + frame = MockFrameInfo("server.py", 50, "handle_request") + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames) + + profile = collector._build_profile() + # Check that the function was recorded + self.assertEqual(len(profile["threads"]), 1) + thread_data = profile["threads"][0] + string_array = profile["shared"]["stringArray"] + + # Verify function name is in string table + self.assertIn("handle_request", string_array) + + +class TestOpcodeHandling(unittest.TestCase): + """Tests for opcode field handling in collectors.""" + + def test_frame_with_opcode(self): + """Test MockFrameInfo properly stores opcode.""" + frame = MockFrameInfo("test.py", 10, "my_func", opcode=90) + self.assertEqual(frame.opcode, 90) + # Verify tuple representation includes opcode + self.assertEqual(frame[3], 90) + self.assertEqual(len(frame), 4) + + def test_frame_without_opcode(self): + """Test MockFrameInfo with no opcode defaults to None.""" + frame = MockFrameInfo("test.py", 10, "my_func") + self.assertIsNone(frame.opcode) + self.assertIsNone(frame[3]) + + def test_collectors_ignore_opcode_for_key_generation(self): + """Test that collectors use (filename, lineno, funcname) as key, not opcode.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Same function, different opcodes + frame1 = MockFrameInfo("test.py", 10, "func", opcode=90) + frame2 = MockFrameInfo("test.py", 10, "func", opcode=100) + + frames1 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame1], status=THREAD_STATUS_HAS_GIL)] + ) + ] + frames2 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame2], status=THREAD_STATUS_HAS_GIL)] + ) + ] + + collector.collect(frames1) + collector.collect(frames2) + + # Should be counted as same function (opcode not in key) + key = ("test.py", 10, "func") + self.assertIn(key, collector.result) + self.assertEqual(collector.result[key]["direct_calls"], 2) + + +class TestGeckoOpcodeMarkers(unittest.TestCase): + """Tests for GeckoCollector opcode interval markers.""" + + def test_gecko_collector_opcodes_disabled_by_default(self): + """Test that opcode tracking is disabled by default.""" + collector = GeckoCollector(sample_interval_usec=1000) + self.assertFalse(collector.opcodes_enabled) + + def test_gecko_collector_opcodes_enabled(self): + """Test that opcode tracking can be enabled.""" + collector = GeckoCollector(sample_interval_usec=1000, opcodes=True) + self.assertTrue(collector.opcodes_enabled) + + def test_gecko_opcode_state_tracking(self): + """Test that GeckoCollector tracks opcode state changes.""" + collector = GeckoCollector(sample_interval_usec=1000, opcodes=True) + + # First sample with opcode 90 (RAISE_VARARGS) + frame1 = MockFrameInfo("test.py", 10, "func", opcode=90) + frames1 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame1], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames1) + + # Should start tracking this opcode state + self.assertIn(1, collector.opcode_state) + state = collector.opcode_state[1] + self.assertEqual(state[0], 90) # opcode + self.assertEqual(state[1], 10) # lineno + self.assertEqual(state[3], "func") # funcname + + def test_gecko_opcode_state_change_emits_marker(self): + """Test that opcode state change emits an interval marker.""" + collector = GeckoCollector(sample_interval_usec=1000, opcodes=True) + + # First sample: opcode 90 + frame1 = MockFrameInfo("test.py", 10, "func", opcode=90) + frames1 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame1], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames1) + + # Second sample: different opcode 100 + frame2 = MockFrameInfo("test.py", 10, "func", opcode=100) + frames2 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame2], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames2) + + # Should have emitted a marker for the first opcode + thread_data = collector.threads[1] + markers = thread_data["markers"] + # At least one marker should have been added + self.assertGreater(len(markers["name"]), 0) + + def test_gecko_opcode_markers_not_emitted_when_disabled(self): + """Test that no opcode markers when opcodes=False.""" + collector = GeckoCollector(sample_interval_usec=1000, opcodes=False) + + frame1 = MockFrameInfo("test.py", 10, "func", opcode=90) + frames1 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame1], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames1) + + frame2 = MockFrameInfo("test.py", 10, "func", opcode=100) + frames2 = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame2], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames2) + + # opcode_state should not be tracked + self.assertEqual(len(collector.opcode_state), 0) + + def test_gecko_opcode_with_none_opcode(self): + """Test that None opcode doesn't cause issues.""" + collector = GeckoCollector(sample_interval_usec=1000, opcodes=True) + + # Frame with no opcode (None) + frame = MockFrameInfo("test.py", 10, "func", opcode=None) + frames = [ + MockInterpreterInfo( + 0, + [MockThreadInfo(1, [frame], status=THREAD_STATUS_HAS_GIL)] + ) + ] + collector.collect(frames) + + # Should track the state but opcode is None + self.assertIn(1, collector.opcode_state) + self.assertIsNone(collector.opcode_state[1][0]) + + +class TestCollectorFrameFormat(unittest.TestCase): + """Tests verifying all collectors handle the 4-element frame format.""" + + def _make_sample_frames(self): + """Create sample frames with full format: (filename, location, funcname, opcode).""" + return [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("app.py", 100, "main", opcode=90), + MockFrameInfo("utils.py", 50, "helper", opcode=100), + MockFrameInfo("lib.py", 25, "process", opcode=None), + ], + status=THREAD_STATUS_HAS_GIL, + ) + ], + ) + ] + + def test_pstats_collector_frame_format(self): + """Test PstatsCollector with 4-element frame format.""" + collector = PstatsCollector(sample_interval_usec=1000) + collector.collect(self._make_sample_frames()) + + # All three functions should be recorded + self.assertEqual(len(collector.result), 3) + self.assertIn(("app.py", 100, "main"), collector.result) + self.assertIn(("utils.py", 50, "helper"), collector.result) + self.assertIn(("lib.py", 25, "process"), collector.result) + + def test_collapsed_stack_frame_format(self): + """Test CollapsedStackCollector with 4-element frame format.""" + collector = CollapsedStackCollector(sample_interval_usec=1000) + collector.collect(self._make_sample_frames()) + + self.assertEqual(len(collector.stack_counter), 1) + (path, _), _ = list(collector.stack_counter.items())[0] + # 3 frames in the path (reversed order) + self.assertEqual(len(path), 3) + + def test_flamegraph_collector_frame_format(self): + """Test FlamegraphCollector with 4-element frame format.""" + collector = FlamegraphCollector(sample_interval_usec=1000) + collector.collect(self._make_sample_frames()) + + data = collector._convert_to_flamegraph_format() + # Should have processed the frames + self.assertIn("children", data) + + def test_gecko_collector_frame_format(self): + """Test GeckoCollector with 4-element frame format.""" + collector = GeckoCollector(sample_interval_usec=1000) + collector.collect(self._make_sample_frames()) + + profile = collector._build_profile() + # Should have one thread with the frames + self.assertEqual(len(profile["threads"]), 1) + thread = profile["threads"][0] + # Should have recorded 3 functions + self.assertEqual(thread["funcTable"]["length"], 3) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_integration.py b/Lib/test/test_profiling/test_sampling_profiler/test_integration.py new file mode 100644 index 00000000000..b82474858dd --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_integration.py @@ -0,0 +1,960 @@ +"""Tests for sampling profiler integration and error handling.""" + +import contextlib +import io +import marshal +import os +import shutil +import subprocess +import sys +import tempfile +import unittest +from unittest import mock + +try: + import _remote_debugging + import profiling.sampling + import profiling.sampling.sample + from profiling.sampling.pstats_collector import PstatsCollector + from profiling.sampling.stack_collector import CollapsedStackCollector + from profiling.sampling.sample import SampleProfiler, _is_process_running +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from test.support import ( + requires_remote_subprocess_debugging, + SHORT_TIMEOUT, +) + +from .helpers import ( + test_subprocess, + close_and_unlink, +) +from .mocks import MockFrameInfo, MockThreadInfo, MockInterpreterInfo + +# Duration for profiling tests - long enough for process to complete naturally +PROFILING_TIMEOUT = str(int(SHORT_TIMEOUT)) + +# Duration for profiling in tests - short enough to complete quickly +PROFILING_DURATION_SEC = 2 + + +@requires_remote_subprocess_debugging() +class TestRecursiveFunctionProfiling(unittest.TestCase): + """Test profiling of recursive functions and complex call patterns.""" + + def test_recursive_function_call_counting(self): + """Test that recursive function calls are counted correctly.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Simulate a recursive call pattern: fibonacci(5) calling itself + recursive_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ # First sample: deep in recursion + MockFrameInfo("fib.py", 10, "fibonacci"), + MockFrameInfo( + "fib.py", 10, "fibonacci" + ), # recursive call + MockFrameInfo( + "fib.py", 10, "fibonacci" + ), # deeper recursion + MockFrameInfo( + "fib.py", 10, "fibonacci" + ), # even deeper + MockFrameInfo("main.py", 5, "main"), # main caller + ], + ) + ], + ), + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ # Second sample: different recursion depth + MockFrameInfo("fib.py", 10, "fibonacci"), + MockFrameInfo( + "fib.py", 10, "fibonacci" + ), # recursive call + MockFrameInfo("main.py", 5, "main"), # main caller + ], + ) + ], + ), + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ # Third sample: back to deeper recursion + MockFrameInfo("fib.py", 10, "fibonacci"), + MockFrameInfo("fib.py", 10, "fibonacci"), + MockFrameInfo("fib.py", 10, "fibonacci"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + ] + + for frames in recursive_frames: + collector.collect([frames]) + + collector.create_stats() + + # Check that recursive calls are counted properly + fib_key = ("fib.py", 10, "fibonacci") + main_key = ("main.py", 5, "main") + + self.assertIn(fib_key, collector.stats) + self.assertIn(main_key, collector.stats) + + # Fibonacci: counted once per sample, not per occurrence + fib_stats = collector.stats[fib_key] + direct_calls, cumulative_calls, tt, ct, callers = fib_stats + + # Should count 3 (present in 3 samples), not 9 (total occurrences) + self.assertEqual(cumulative_calls, 3) + self.assertEqual(direct_calls, 3) # Top of stack in all samples + self.assertGreater(tt, 0) + self.assertGreater(ct, 0) + + # Main should also have 3 cumulative calls (in all 3 samples) + main_stats = collector.stats[main_key] + main_direct_calls, main_cumulative_calls = main_stats[0], main_stats[1] + self.assertEqual(main_direct_calls, 0) # Never directly executing + self.assertEqual(main_cumulative_calls, 3) # Appears in all 3 samples + + def test_nested_function_hierarchy(self): + """Test profiling of deeply nested function calls.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Simulate a deep call hierarchy + deep_call_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("level1.py", 10, "level1_func"), + MockFrameInfo("level2.py", 20, "level2_func"), + MockFrameInfo("level3.py", 30, "level3_func"), + MockFrameInfo("level4.py", 40, "level4_func"), + MockFrameInfo("level5.py", 50, "level5_func"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ # Same hierarchy sampled again + MockFrameInfo("level1.py", 10, "level1_func"), + MockFrameInfo("level2.py", 20, "level2_func"), + MockFrameInfo("level3.py", 30, "level3_func"), + MockFrameInfo("level4.py", 40, "level4_func"), + MockFrameInfo("level5.py", 50, "level5_func"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + ] + + for frames in deep_call_frames: + collector.collect([frames]) + + collector.create_stats() + + # All levels should be recorded + for level in range(1, 6): + key = (f"level{level}.py", level * 10, f"level{level}_func") + self.assertIn(key, collector.stats) + + stats = collector.stats[key] + direct_calls, cumulative_calls, tt, ct, callers = stats + + # Each level should appear in stack twice (2 samples) + self.assertEqual(cumulative_calls, 2) + + # Only level1 (deepest) should have direct calls + if level == 1: + self.assertEqual(direct_calls, 2) + else: + self.assertEqual(direct_calls, 0) + + # Deeper levels should have lower cumulative time than higher levels + # (since they don't include time from functions they call) + if level == 1: # Deepest level with most time + self.assertGreater(ct, 0) + + def test_alternating_call_patterns(self): + """Test profiling with alternating call patterns.""" + collector = PstatsCollector(sample_interval_usec=1000) + + # Simulate alternating execution paths + pattern_frames = [ + # Pattern A: path through func_a + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("module.py", 10, "func_a"), + MockFrameInfo("module.py", 30, "shared_func"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + # Pattern B: path through func_b + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("module.py", 20, "func_b"), + MockFrameInfo("module.py", 30, "shared_func"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + # Pattern A again + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("module.py", 10, "func_a"), + MockFrameInfo("module.py", 30, "shared_func"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + # Pattern B again + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("module.py", 20, "func_b"), + MockFrameInfo("module.py", 30, "shared_func"), + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + ] + + for frames in pattern_frames: + collector.collect([frames]) + + collector.create_stats() + + # Check that both paths are recorded equally + func_a_key = ("module.py", 10, "func_a") + func_b_key = ("module.py", 20, "func_b") + shared_key = ("module.py", 30, "shared_func") + main_key = ("main.py", 5, "main") + + # func_a and func_b should each be directly executing twice + self.assertEqual(collector.stats[func_a_key][0], 2) # direct_calls + self.assertEqual(collector.stats[func_a_key][1], 2) # cumulative_calls + self.assertEqual(collector.stats[func_b_key][0], 2) # direct_calls + self.assertEqual(collector.stats[func_b_key][1], 2) # cumulative_calls + + # shared_func should appear in all samples (4 times) but never directly executing + self.assertEqual(collector.stats[shared_key][0], 0) # direct_calls + self.assertEqual(collector.stats[shared_key][1], 4) # cumulative_calls + + # main should appear in all samples but never directly executing + self.assertEqual(collector.stats[main_key][0], 0) # direct_calls + self.assertEqual(collector.stats[main_key][1], 4) # cumulative_calls + + def test_collapsed_stack_with_recursion(self): + """Test collapsed stack collector with recursive patterns.""" + collector = CollapsedStackCollector(1000) + + # Recursive call pattern + recursive_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("factorial.py", 10, "factorial"), + MockFrameInfo("factorial.py", 10, "factorial"), # recursive + MockFrameInfo("factorial.py", 10, "factorial"), # deeper + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + MockInterpreterInfo( + 0, + [ + MockThreadInfo( + 1, + [ + MockFrameInfo("factorial.py", 10, "factorial"), + MockFrameInfo("factorial.py", 10, "factorial"), # different depth + MockFrameInfo("main.py", 5, "main"), + ], + ) + ], + ), + ] + + for frames in recursive_frames: + collector.collect([frames]) + + # Should capture both call paths + self.assertEqual(len(collector.stack_counter), 2) + + # First path should be longer (deeper recursion) than the second + path_tuples = list(collector.stack_counter.keys()) + paths = [p[0] for p in path_tuples] # Extract just the call paths + lengths = [len(p) for p in paths] + self.assertNotEqual(lengths[0], lengths[1]) + + # Both should contain factorial calls + self.assertTrue( + any(any(f[2] == "factorial" for f in p) for p in paths) + ) + + # Verify total occurrences via aggregation + factorial_key = ("factorial.py", 10, "factorial") + main_key = ("main.py", 5, "main") + + def total_occurrences(func): + total = 0 + for (path, thread_id), count in collector.stack_counter.items(): + total += sum(1 for f in path if f == func) * count + return total + + self.assertEqual(total_occurrences(factorial_key), 5) + self.assertEqual(total_occurrences(main_key), 2) + + +# Shared workload functions for test scripts +_WORKLOAD_FUNCTIONS = ''' +def slow_fibonacci(n): + if n <= 1: + return n + return slow_fibonacci(n-1) + slow_fibonacci(n-2) + +def cpu_intensive_work(): + result = 0 + for i in range(10000): + result += i * i + if i % 100 == 0: + result = result % 1000000 + return result + +def do_work(): + iteration = 0 + while True: + if iteration % 2 == 0: + slow_fibonacci(15) + else: + cpu_intensive_work() + iteration += 1 +''' + + +@requires_remote_subprocess_debugging() +class TestSampleProfilerIntegration(unittest.TestCase): + @classmethod + def setUpClass(cls): + # Test script for use with test_subprocess() - signals when work starts + cls.test_script = _WORKLOAD_FUNCTIONS + ''' +_test_sock.sendall(b"working") +do_work() +''' + # CLI test script - runs for fixed duration (no socket sync) + cls.cli_test_script = ''' +import time +''' + _WORKLOAD_FUNCTIONS.replace( + 'while True:', 'end_time = time.time() + 30\n while time.time() < end_time:' +) + ''' +do_work() +''' + + def test_sampling_basic_functionality(self): + with ( + test_subprocess(self.test_script, wait_for_working=True) as subproc, + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=1000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=PROFILING_DURATION_SEC, + ) + collector.print_stats(show_summary=False) + + output = captured_output.getvalue() + + # Basic checks on output + self.assertIn("Captured", output) + self.assertIn("samples", output) + self.assertIn("Profile Stats", output) + + # Should see some of our test functions + self.assertIn("slow_fibonacci", output) + + def test_sampling_with_pstats_export(self): + pstats_out = tempfile.NamedTemporaryFile( + suffix=".pstats", delete=False + ) + self.addCleanup(close_and_unlink, pstats_out) + + with test_subprocess(self.test_script, wait_for_working=True) as subproc: + # Suppress profiler output when testing file export + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=10000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=PROFILING_DURATION_SEC, + ) + collector.export(pstats_out.name) + + # Verify file was created and contains valid data + self.assertTrue(os.path.exists(pstats_out.name)) + self.assertGreater(os.path.getsize(pstats_out.name), 0) + + # Try to load the stats file + with open(pstats_out.name, "rb") as f: + stats_data = marshal.load(f) + + # Should be a dictionary with the sampled marker + self.assertIsInstance(stats_data, dict) + self.assertIn(("__sampled__",), stats_data) + self.assertTrue(stats_data[("__sampled__",)]) + + # Should have some function data + function_entries = [ + k for k in stats_data.keys() if k != ("__sampled__",) + ] + self.assertGreater(len(function_entries), 0) + + def test_sampling_with_collapsed_export(self): + collapsed_file = tempfile.NamedTemporaryFile( + suffix=".txt", delete=False + ) + self.addCleanup(close_and_unlink, collapsed_file) + + with ( + test_subprocess(self.test_script, wait_for_working=True) as subproc, + ): + # Suppress profiler output when testing file export + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = CollapsedStackCollector(1000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=PROFILING_DURATION_SEC, + ) + collector.export(collapsed_file.name) + + # Verify file was created and contains valid data + self.assertTrue(os.path.exists(collapsed_file.name)) + self.assertGreater(os.path.getsize(collapsed_file.name), 0) + + # Check file format + with open(collapsed_file.name, "r") as f: + content = f.read() + + lines = content.strip().split("\n") + self.assertGreater(len(lines), 0) + + # Each line should have format: stack_trace count + for line in lines: + parts = line.rsplit(" ", 1) + self.assertEqual(len(parts), 2) + + stack_trace, count_str = parts + self.assertGreater(len(stack_trace), 0) + self.assertTrue(count_str.isdigit()) + self.assertGreater(int(count_str), 0) + + # Stack trace should contain semicolon-separated entries + if ";" in stack_trace: + stack_parts = stack_trace.split(";") + for part in stack_parts: + # Each part should be file:function:line + self.assertIn(":", part) + + def test_sampling_all_threads(self): + with ( + test_subprocess(self.test_script, wait_for_working=True) as subproc, + # Suppress profiler output + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=10000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=PROFILING_DURATION_SEC, + all_threads=True, + ) + collector.print_stats(show_summary=False) + + # Just verify that sampling completed without error + # We're not testing output format here + + def test_sample_target_script(self): + script_file = tempfile.NamedTemporaryFile(delete=False) + script_file.write(self.cli_test_script.encode("utf-8")) + script_file.flush() + self.addCleanup(close_and_unlink, script_file) + + # Sample for PROFILING_DURATION_SEC seconds + test_args = [ + "profiling.sampling.sample", "run", + "-d", str(PROFILING_DURATION_SEC), + script_file.name + ] + + with ( + mock.patch("sys.argv", test_args), + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + from profiling.sampling.cli import main + main() + + output = captured_output.getvalue() + + # Basic checks on output + self.assertIn("Captured", output) + self.assertIn("samples", output) + self.assertIn("Profile Stats", output) + + # Should see some of our test functions + self.assertIn("slow_fibonacci", output) + + def test_sample_target_module(self): + tempdir = tempfile.TemporaryDirectory(delete=False) + self.addCleanup(lambda x: shutil.rmtree(x), tempdir.name) + + module_path = os.path.join(tempdir.name, "test_module.py") + + with open(module_path, "w") as f: + f.write(self.cli_test_script) + + test_args = [ + "profiling.sampling.cli", + "run", + "-d", + str(PROFILING_DURATION_SEC), + "-m", + "test_module", + ] + + with ( + mock.patch("sys.argv", test_args), + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + # Change to temp directory so subprocess can find the module + contextlib.chdir(tempdir.name), + ): + from profiling.sampling.cli import main + main() + + output = captured_output.getvalue() + + # Basic checks on output + self.assertIn("Captured", output) + self.assertIn("samples", output) + self.assertIn("Profile Stats", output) + + # Should see some of our test functions + self.assertIn("slow_fibonacci", output) + + +@requires_remote_subprocess_debugging() +class TestSampleProfilerErrorHandling(unittest.TestCase): + def test_invalid_pid(self): + with self.assertRaises((SystemExit, PermissionError)): + collector = PstatsCollector(sample_interval_usec=100, skip_idle=False) + profiling.sampling.sample.sample(-1, collector, duration_sec=1) + + def test_process_dies_during_sampling(self): + # Use wait_for_working=False since this simple script doesn't send "working" + with test_subprocess( + "import time; time.sleep(0.5); exit()", + wait_for_working=False + ) as subproc: + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=50000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2, # Longer than process lifetime + ) + + output = captured_output.getvalue() + + self.assertIn("Error rate", output) + + def test_is_process_running(self): + # Use wait_for_working=False since this simple script doesn't send "working" + with test_subprocess( + "import time; time.sleep(1000)", + wait_for_working=False + ) as subproc: + profiler = SampleProfiler( + pid=subproc.process.pid, + sample_interval_usec=1000, + all_threads=False, + ) + self.assertTrue(_is_process_running(profiler.pid)) + self.assertIsNotNone(profiler.unwinder.get_stack_trace()) + subproc.process.kill() + subproc.process.wait() + self.assertRaises( + ProcessLookupError, profiler.unwinder.get_stack_trace + ) + + # Exit the context manager to ensure the process is terminated + self.assertFalse(_is_process_running(profiler.pid)) + self.assertRaises( + ProcessLookupError, profiler.unwinder.get_stack_trace + ) + + @unittest.skipUnless(sys.platform == "linux", "Only valid on Linux") + def test_esrch_signal_handling(self): + # Use wait_for_working=False since this simple script doesn't send "working" + with test_subprocess( + "import time; time.sleep(1000)", + wait_for_working=False + ) as subproc: + unwinder = _remote_debugging.RemoteUnwinder( + subproc.process.pid + ) + initial_trace = unwinder.get_stack_trace() + self.assertIsNotNone(initial_trace) + + subproc.process.kill() + + # Wait for the process to die and try to get another trace + subproc.process.wait() + + with self.assertRaises(ProcessLookupError): + unwinder.get_stack_trace() + + def test_script_error_treatment(self): + script_file = tempfile.NamedTemporaryFile( + "w", delete=False, suffix=".py" + ) + script_file.write("open('nonexistent_file.txt')\n") + script_file.close() + self.addCleanup(os.unlink, script_file.name) + + result = subprocess.run( + [ + sys.executable, + "-m", + "profiling.sampling.cli", + "run", + "-d", + "1", + script_file.name, + ], + capture_output=True, + text=True, + ) + output = result.stdout + result.stderr + + self.assertNotIn("Script file not found", output) + self.assertIn( + "No such file or directory: 'nonexistent_file.txt'", output + ) + + def test_live_incompatible_with_pstats_options(self): + """Test that --live is incompatible with individual pstats options.""" + test_cases = [ + (["--sort", "tottime"], "--sort"), + (["--limit", "30"], "--limit"), + (["--no-summary"], "--no-summary"), + ] + + for args, expected_flag in test_cases: + with self.subTest(args=args): + test_args = ["profiling.sampling.cli", "run", "--live"] + args + ["test.py"] + with mock.patch("sys.argv", test_args): + with self.assertRaises(SystemExit) as cm: + from profiling.sampling.cli import main + main() + self.assertNotEqual(cm.exception.code, 0) + + def test_live_incompatible_with_multiple_pstats_options(self): + """Test that --live is incompatible with multiple pstats options.""" + test_args = [ + "profiling.sampling.cli", "run", "--live", + "--sort", "cumtime", "--limit", "25", "--no-summary", "test.py" + ] + + with mock.patch("sys.argv", test_args): + with self.assertRaises(SystemExit) as cm: + from profiling.sampling.cli import main + main() + self.assertNotEqual(cm.exception.code, 0) + + def test_live_incompatible_with_pstats_default_values(self): + """Test that --live blocks pstats options even with default values.""" + # Test with --sort=nsamples (the default value) + test_args = ["profiling.sampling.cli", "run", "--live", "--sort=nsamples", "test.py"] + + with mock.patch("sys.argv", test_args): + with self.assertRaises(SystemExit) as cm: + from profiling.sampling.cli import main + main() + self.assertNotEqual(cm.exception.code, 0) + + # Test with --limit=15 (the default value) + test_args = ["profiling.sampling.cli", "run", "--live", "--limit=15", "test.py"] + + with mock.patch("sys.argv", test_args): + with self.assertRaises(SystemExit) as cm: + from profiling.sampling.cli import main + main() + self.assertNotEqual(cm.exception.code, 0) + + +@requires_remote_subprocess_debugging() +class TestAsyncAwareProfilingIntegration(unittest.TestCase): + """Integration tests for async-aware profiling mode.""" + + @classmethod + def setUpClass(cls): + # Async test script that runs indefinitely until killed. + # Sends "working" signal AFTER tasks are created and scheduled. + cls.async_script = ''' +import asyncio + +async def sleeping_leaf(): + while True: + await asyncio.sleep(0.02) + +async def cpu_leaf(): + total = 0 + while True: + for i in range(10000): + total += i * i + await asyncio.sleep(0) + +async def supervisor(): + tasks = [ + asyncio.create_task(sleeping_leaf(), name="Sleeper-0"), + asyncio.create_task(sleeping_leaf(), name="Sleeper-1"), + asyncio.create_task(sleeping_leaf(), name="Sleeper-2"), + asyncio.create_task(cpu_leaf(), name="Worker"), + ] + await asyncio.sleep(0) # Let tasks get scheduled + _test_sock.sendall(b"working") + await asyncio.gather(*tasks) + +asyncio.run(supervisor()) +''' + + def _collect_async_samples(self, async_aware_mode): + """Helper to collect samples and count function occurrences. + + Returns a dict mapping function names to their sample counts. + """ + with test_subprocess(self.async_script, wait_for_working=True) as subproc: + collector = CollapsedStackCollector(1000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=PROFILING_DURATION_SEC, + async_aware=async_aware_mode, + ) + + # Count samples per function from collapsed stacks + # stack_counter keys are (call_tree, thread_id) where call_tree + # is a tuple of (file, line, func) tuples + func_samples = {} + total = 0 + for (call_tree, _thread_id), count in collector.stack_counter.items(): + total += count + for _file, _line, func in call_tree: + func_samples[func] = func_samples.get(func, 0) + count + + func_samples["_total"] = total + return func_samples + + def test_async_aware_all_sees_sleeping_and_running_tasks(self): + """Test that async_aware='all' captures both sleeping and CPU-running tasks. + + Task tree structure: + main + └── supervisor + ├── Sleeper-0 (sleeping_leaf) + ├── Sleeper-1 (sleeping_leaf) + ├── Sleeper-2 (sleeping_leaf) + └── Worker (cpu_leaf) + + async_aware='all' should see ALL 4 leaf tasks in the output. + """ + samples = self._collect_async_samples("all") + + self.assertGreater(samples["_total"], 0, "Should have collected samples") + self.assertIn("sleeping_leaf", samples) + self.assertIn("cpu_leaf", samples) + self.assertIn("supervisor", samples) + + def test_async_aware_running_sees_only_cpu_task(self): + """Test that async_aware='running' only captures the actively running task. + + Task tree structure: + main + └── supervisor + ├── Sleeper-0 (sleeping_leaf) - NOT visible in 'running' + ├── Sleeper-1 (sleeping_leaf) - NOT visible in 'running' + ├── Sleeper-2 (sleeping_leaf) - NOT visible in 'running' + └── Worker (cpu_leaf) - VISIBLE in 'running' + + async_aware='running' should only see the Worker task doing CPU work. + """ + samples = self._collect_async_samples("running") + + total = samples["_total"] + cpu_leaf_samples = samples.get("cpu_leaf", 0) + + self.assertGreater(total, 0, "Should have collected some samples") + self.assertGreater(cpu_leaf_samples, 0, "cpu_leaf should appear in samples") + + # cpu_leaf should have at least 90% of samples (typically 99%+) + # sleeping_leaf may occasionally appear with very few samples (< 1%) + # when tasks briefly wake up to check sleep timers + cpu_percentage = (cpu_leaf_samples / total) * 100 + self.assertGreater(cpu_percentage, 90.0, + f"cpu_leaf should dominate samples in 'running' mode, " + f"got {cpu_percentage:.1f}% ({cpu_leaf_samples}/{total})") + + +def _generate_deep_generators_script(chain_depth=20, recurse_depth=150): + """Generate a script with deep nested generators for stress testing.""" + lines = [ + 'import sys', + 'sys.setrecursionlimit(5000)', + '', + ] + # Generate chain of yield-from functions + for i in range(chain_depth - 1): + lines.extend([ + f'def deep_yield_chain_{i}(n):', + f' yield ("L{i}", n)', + f' yield from deep_yield_chain_{i + 1}(n)', + '', + ]) + # Last chain function calls recursive_diver + lines.extend([ + f'def deep_yield_chain_{chain_depth - 1}(n):', + f' yield ("L{chain_depth - 1}", n)', + f' yield from recursive_diver(n, {chain_depth})', + '', + 'def recursive_diver(n, depth):', + ' yield (f"DIVE_{depth}", n)', + f' if depth < {recurse_depth}:', + ' yield from recursive_diver(n, depth + 1)', + ' else:', + ' for i in range(5):', + ' yield (f"BOTTOM_{depth}", i)', + '', + 'def oscillating_generator(iterations=1000):', + ' for i in range(iterations):', + ' yield ("OSCILLATE", i)', + ' yield from deep_yield_chain_0(i)', + '', + 'def run_forever():', + ' while True:', + ' for _ in oscillating_generator(10):', + ' pass', + '', + '_test_sock.sendall(b"working")', + 'run_forever()', + ]) + return '\n'.join(lines) + + +@requires_remote_subprocess_debugging() +class TestDeepGeneratorFrameCache(unittest.TestCase): + """Test frame cache consistency with deep oscillating generator stacks.""" + + def test_all_stacks_share_same_base_frame(self): + """Verify all sampled stacks reach the entry point function. + + When profiling deep generators that oscillate up and down the call + stack, every sample should include the entry point function + (run_forever) in its call chain. If the frame cache stores + incomplete stacks, some samples will be missing this base function, + causing broken flamegraphs. + """ + script = _generate_deep_generators_script() + with test_subprocess(script, wait_for_working=True) as subproc: + collector = CollapsedStackCollector(sample_interval_usec=1, skip_idle=False) + + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2, + ) + + samples_with_entry_point = 0 + samples_without_entry_point = 0 + total_samples = 0 + + for (call_tree, _thread_id), count in collector.stack_counter.items(): + total_samples += count + if call_tree: + has_entry_point = call_tree and call_tree[0][2] == "<module>" + if has_entry_point: + samples_with_entry_point += count + else: + samples_without_entry_point += count + + self.assertGreater(total_samples, 100, + f"Expected at least 100 samples, got {total_samples}") + + self.assertEqual(samples_without_entry_point, 0, + f"Found {samples_without_entry_point}/{total_samples} samples " + f"missing the entry point function 'run_forever'. This indicates " + f"incomplete stacks are being returned, likely due to frame cache " + f"storing partial stack traces.") diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_core.py b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_core.py new file mode 100644 index 00000000000..f67a900822c --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_core.py @@ -0,0 +1,698 @@ +"""Core functionality tests for LiveStatsCollector. + +Tests for path simplification, frame processing, collect method, +statistics building, sorting, and formatting. +""" + +import os +import unittest +from test.support import requires +from test.support.import_helper import import_module + +# Only run these tests if curses is available +requires("curses") +curses = import_module("curses") + +from profiling.sampling.live_collector import LiveStatsCollector, MockDisplay +from profiling.sampling.constants import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, +) +from ._live_collector_helpers import ( + MockFrameInfo, + MockThreadInfo, + MockInterpreterInfo, +) + + +class TestLiveStatsCollectorPathSimplification(unittest.TestCase): + """Tests for path simplification functionality.""" + + def test_simplify_stdlib_path(self): + """Test simplification of standard library paths.""" + collector = LiveStatsCollector(1000) + # Get actual os module path + os_file = os.__file__ + if os_file: + stdlib_dir = os.path.dirname(os.path.abspath(os_file)) + test_path = os.path.join(stdlib_dir, "json", "decoder.py") + simplified = collector.simplify_path(test_path) + # Should remove the stdlib prefix + self.assertNotIn(stdlib_dir, simplified) + self.assertIn("json", simplified) + + def test_simplify_unknown_path(self): + """Test that unknown paths are returned unchanged.""" + collector = LiveStatsCollector(1000) + test_path = "/some/unknown/path/file.py" + simplified = collector.simplify_path(test_path) + self.assertEqual(simplified, test_path) + + +class TestLiveStatsCollectorFrameProcessing(unittest.TestCase): + """Tests for frame processing functionality.""" + + def test_process_single_frame(self): + """Test processing a single frame.""" + collector = LiveStatsCollector(1000) + frames = [MockFrameInfo("test.py", 10, "test_func")] + collector.process_frames(frames) + + location = ("test.py", 10, "test_func") + self.assertEqual(collector.result[location]["direct_calls"], 1) + self.assertEqual(collector.result[location]["cumulative_calls"], 1) + + def test_process_multiple_frames(self): + """Test processing a stack of multiple frames.""" + collector = LiveStatsCollector(1000) + frames = [ + MockFrameInfo("test.py", 10, "inner_func"), + MockFrameInfo("test.py", 20, "middle_func"), + MockFrameInfo("test.py", 30, "outer_func"), + ] + collector.process_frames(frames) + + # Top frame (inner_func) should have both direct and cumulative + inner_loc = ("test.py", 10, "inner_func") + self.assertEqual(collector.result[inner_loc]["direct_calls"], 1) + self.assertEqual(collector.result[inner_loc]["cumulative_calls"], 1) + + # Other frames should only have cumulative + middle_loc = ("test.py", 20, "middle_func") + self.assertEqual(collector.result[middle_loc]["direct_calls"], 0) + self.assertEqual(collector.result[middle_loc]["cumulative_calls"], 1) + + outer_loc = ("test.py", 30, "outer_func") + self.assertEqual(collector.result[outer_loc]["direct_calls"], 0) + self.assertEqual(collector.result[outer_loc]["cumulative_calls"], 1) + + def test_process_empty_frames(self): + """Test processing empty frames list.""" + collector = LiveStatsCollector(1000) + collector.process_frames([]) + # Should not raise an error and result should remain empty + self.assertEqual(len(collector.result), 0) + + def test_process_frames_accumulation(self): + """Test that multiple calls accumulate correctly.""" + collector = LiveStatsCollector(1000) + frames = [MockFrameInfo("test.py", 10, "test_func")] + + collector.process_frames(frames) + collector.process_frames(frames) + collector.process_frames(frames) + + location = ("test.py", 10, "test_func") + self.assertEqual(collector.result[location]["direct_calls"], 3) + self.assertEqual(collector.result[location]["cumulative_calls"], 3) + + def test_process_frames_with_thread_id(self): + """Test processing frames with per-thread tracking.""" + collector = LiveStatsCollector(1000) + frames = [MockFrameInfo("test.py", 10, "test_func")] + + # Process frames with thread_id + collector.process_frames(frames, thread_id=123) + + # Check aggregated result + location = ("test.py", 10, "test_func") + self.assertEqual(collector.result[location]["direct_calls"], 1) + self.assertEqual(collector.result[location]["cumulative_calls"], 1) + + # Check per-thread result + self.assertIn(123, collector.per_thread_data) + self.assertEqual( + collector.per_thread_data[123].result[location]["direct_calls"], 1 + ) + self.assertEqual( + collector.per_thread_data[123].result[location]["cumulative_calls"], 1 + ) + + def test_process_frames_multiple_threads(self): + """Test processing frames from multiple threads.""" + collector = LiveStatsCollector(1000) + frames1 = [MockFrameInfo("test.py", 10, "test_func")] + frames2 = [MockFrameInfo("test.py", 20, "other_func")] + + # Process frames from different threads + collector.process_frames(frames1, thread_id=123) + collector.process_frames(frames2, thread_id=456) + + # Check that both threads have their own data + self.assertIn(123, collector.per_thread_data) + self.assertIn(456, collector.per_thread_data) + + loc1 = ("test.py", 10, "test_func") + loc2 = ("test.py", 20, "other_func") + + # Thread 123 should only have func1 + self.assertEqual( + collector.per_thread_data[123].result[loc1]["direct_calls"], 1 + ) + self.assertNotIn(loc2, collector.per_thread_data[123].result) + + # Thread 456 should only have func2 + self.assertEqual( + collector.per_thread_data[456].result[loc2]["direct_calls"], 1 + ) + self.assertNotIn(loc1, collector.per_thread_data[456].result) + + def test_process_recursive_frames_counted_once(self): + """Test that recursive functions are counted once per sample.""" + collector = LiveStatsCollector(1000) + # Simulate recursive function appearing 5 times in stack + frames = [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ] + collector.process_frames(frames) + + location = ("test.py", 10, "recursive_func") + # Should count as 1 cumulative (present in 1 sample), not 5 + self.assertEqual(collector.result[location]["cumulative_calls"], 1) + self.assertEqual(collector.result[location]["direct_calls"], 1) + + def test_process_recursive_frames_multiple_samples(self): + """Test cumulative counting across multiple samples with recursion.""" + collector = LiveStatsCollector(1000) + + # Sample 1: depth 3 + frames1 = [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ] + # Sample 2: depth 2 + frames2 = [ + MockFrameInfo("test.py", 10, "recursive_func"), + MockFrameInfo("test.py", 10, "recursive_func"), + ] + + collector.process_frames(frames1) + collector.process_frames(frames2) + + location = ("test.py", 10, "recursive_func") + # Should count as 2 (present in 2 samples), not 5 + self.assertEqual(collector.result[location]["cumulative_calls"], 2) + self.assertEqual(collector.result[location]["direct_calls"], 2) + + def test_process_mixed_recursive_nonrecursive(self): + """Test stack with both recursive and non-recursive functions.""" + collector = LiveStatsCollector(1000) + + # Stack: main -> foo (recursive x3) -> bar + frames = [ + MockFrameInfo("test.py", 50, "bar"), + MockFrameInfo("test.py", 20, "foo"), + MockFrameInfo("test.py", 20, "foo"), + MockFrameInfo("test.py", 20, "foo"), + MockFrameInfo("test.py", 10, "main"), + ] + collector.process_frames(frames) + + # foo: 1 cumulative despite 3 occurrences + self.assertEqual(collector.result[("test.py", 20, "foo")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 20, "foo")]["direct_calls"], 0) + + # bar and main: 1 cumulative each + self.assertEqual(collector.result[("test.py", 50, "bar")]["cumulative_calls"], 1) + self.assertEqual(collector.result[("test.py", 10, "main")]["cumulative_calls"], 1) + + +class TestLiveStatsCollectorCollect(unittest.TestCase): + """Tests for the collect method.""" + + def test_collect_initializes_start_time(self): + """Test that collect initializes start_time on first call.""" + collector = LiveStatsCollector(1000) + self.assertIsNone(collector.start_time) + + # Create mock stack frames + thread_info = MockThreadInfo(123, []) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + + collector.collect(stack_frames) + self.assertIsNotNone(collector.start_time) + + def test_collect_increments_sample_count(self): + """Test that collect increments total_samples.""" + collector = LiveStatsCollector(1000) + thread_info = MockThreadInfo(123, []) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + + self.assertEqual(collector.total_samples, 0) + collector.collect(stack_frames) + self.assertEqual(collector.total_samples, 1) + collector.collect(stack_frames) + self.assertEqual(collector.total_samples, 2) + + def test_collect_with_frames(self): + """Test collect with actual frame data.""" + collector = LiveStatsCollector(1000) + frames = [MockFrameInfo("test.py", 10, "test_func")] + thread_info = MockThreadInfo(123, frames) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + + collector.collect(stack_frames) + + location = ("test.py", 10, "test_func") + self.assertEqual(collector.result[location]["direct_calls"], 1) + self.assertEqual(collector.successful_samples, 1) + self.assertEqual(collector.failed_samples, 0) + + def test_collect_with_empty_frames(self): + """Test collect with empty frames counts as successful. + + A sample is considered successful if the profiler could read from the + target process, even if no frames matched the current filter (e.g., + --mode exception when no thread has an active exception). The sample + itself worked; it just didn't produce frame data. + """ + collector = LiveStatsCollector(1000) + thread_info = MockThreadInfo(123, []) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + + collector.collect(stack_frames) + + # Empty frames still count as successful - the sample worked even + # though no frames matched the filter + self.assertEqual(collector.successful_samples, 1) + self.assertEqual(collector.total_samples, 1) + self.assertEqual(collector.failed_samples, 0) + + def test_sample_counts_invariant(self): + """Test that total_samples == successful_samples + failed_samples. + + Empty frame data (e.g., from --mode exception with no active exception) + still counts as successful since the profiler could read process state. + """ + collector = LiveStatsCollector(1000) + + # Mix of samples with and without frame data + frames = [MockFrameInfo("test.py", 10, "func")] + thread_with_frames = MockThreadInfo(123, frames) + thread_empty = MockThreadInfo(456, []) + interp_with_frames = MockInterpreterInfo(0, [thread_with_frames]) + interp_empty = MockInterpreterInfo(0, [thread_empty]) + + # Collect various samples + collector.collect([interp_with_frames]) # Has frames + collector.collect([interp_empty]) # No frames (filtered) + collector.collect([interp_with_frames]) # Has frames + collector.collect([interp_empty]) # No frames (filtered) + collector.collect([interp_empty]) # No frames (filtered) + + # All 5 samples are successful (profiler could read process state) + self.assertEqual(collector.total_samples, 5) + self.assertEqual(collector.successful_samples, 5) + self.assertEqual(collector.failed_samples, 0) + + # Invariant must hold + self.assertEqual( + collector.total_samples, + collector.successful_samples + collector.failed_samples + ) + + def test_collect_skip_idle_threads(self): + """Test that idle threads are skipped when skip_idle=True.""" + collector = LiveStatsCollector(1000, skip_idle=True) + + frames = [MockFrameInfo("test.py", 10, "test_func")] + running_thread = MockThreadInfo( + 123, frames, status=THREAD_STATUS_HAS_GIL | THREAD_STATUS_ON_CPU + ) + idle_thread = MockThreadInfo(124, frames, status=0) # No flags = idle + interpreter_info = MockInterpreterInfo( + 0, [running_thread, idle_thread] + ) + stack_frames = [interpreter_info] + + collector.collect(stack_frames) + + # Only one thread should be processed + location = ("test.py", 10, "test_func") + self.assertEqual(collector.result[location]["direct_calls"], 1) + + def test_collect_multiple_threads(self): + """Test collect with multiple threads.""" + collector = LiveStatsCollector(1000) + + frames1 = [MockFrameInfo("test1.py", 10, "func1")] + frames2 = [MockFrameInfo("test2.py", 20, "func2")] + thread1 = MockThreadInfo(123, frames1) + thread2 = MockThreadInfo(124, frames2) + interpreter_info = MockInterpreterInfo(0, [thread1, thread2]) + stack_frames = [interpreter_info] + + collector.collect(stack_frames) + + loc1 = ("test1.py", 10, "func1") + loc2 = ("test2.py", 20, "func2") + self.assertEqual(collector.result[loc1]["direct_calls"], 1) + self.assertEqual(collector.result[loc2]["direct_calls"], 1) + + # Check thread IDs are tracked + self.assertIn(123, collector.thread_ids) + self.assertIn(124, collector.thread_ids) + + def test_collect_filtered_mode_percentage_calculation(self): + """Test that percentages use successful_samples, not total_samples. + + With the current behavior, all samples are considered successful + (the profiler could read from the process), even when filters result + in no frame data. This means percentages are relative to all sampling + attempts that succeeded in reading process state. + """ + collector = LiveStatsCollector(1000) + + # Simulate 10 samples where only 2 had matching data (e.g., exception mode) + frames_with_data = [MockFrameInfo("test.py", 10, "exception_handler")] + thread_with_data = MockThreadInfo(123, frames_with_data) + interpreter_with_data = MockInterpreterInfo(0, [thread_with_data]) + + # Empty thread simulates filtered-out data at C level + thread_empty = MockThreadInfo(456, []) + interpreter_empty = MockInterpreterInfo(0, [thread_empty]) + + # 2 samples with data + collector.collect([interpreter_with_data]) + collector.collect([interpreter_with_data]) + + # 8 samples without data (filtered out at C level, but sample still succeeded) + for _ in range(8): + collector.collect([interpreter_empty]) + + # All 10 samples are successful - the profiler could read from the process + self.assertEqual(collector.total_samples, 10) + self.assertEqual(collector.successful_samples, 10) + + # Build stats and check percentage + stats_list = collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + + # The function appeared in 2 out of 10 successful samples = 20% + location = ("test.py", 10, "exception_handler") + self.assertEqual(collector.result[location]["direct_calls"], 2) + + def test_percentage_values_use_successful_samples(self): + """Test that percentages are calculated from successful_samples. + + This verifies the fix where percentages use successful_samples (samples with + frame data) instead of total_samples (all sampling attempts). Critical for + filtered modes like --mode exception. + """ + collector = LiveStatsCollector(1000) + + # Simulate scenario: 100 total samples, only 20 had frame data + collector.total_samples = 100 + collector.successful_samples = 20 + + # Function appeared in 10 out of 20 successful samples + collector.result[("test.py", 10, "handler")] = { + "direct_calls": 10, + "cumulative_calls": 15, + "total_rec_calls": 0, + } + + stats_list = collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + + stat = stats_list[0] + # Calculate expected percentages using successful_samples + expected_sample_pct = stat["direct_calls"] / collector.successful_samples * 100 + expected_cumul_pct = stat["cumulative_calls"] / collector.successful_samples * 100 + + # Percentage should be 10/20 * 100 = 50%, NOT 10/100 * 100 = 10% + self.assertAlmostEqual(expected_sample_pct, 50.0) + # Cumulative percentage should be 15/20 * 100 = 75%, NOT 15/100 * 100 = 15% + self.assertAlmostEqual(expected_cumul_pct, 75.0) + + # Verify sorting by percentage works correctly + collector.result[("test.py", 20, "other")] = { + "direct_calls": 5, # 25% of successful samples + "cumulative_calls": 8, + "total_rec_calls": 0, + } + collector.sort_by = "sample_pct" + stats_list = collector.build_stats_list() + # handler (50%) should come before other (25%) + self.assertEqual(stats_list[0]["func"][2], "handler") + self.assertEqual(stats_list[1]["func"][2], "other") + + def test_build_stats_list_zero_successful_samples(self): + """Test build_stats_list handles zero successful_samples without division by zero. + + When all samples are filtered out (e.g., exception mode with no exceptions), + percentage calculations should return 0 without raising ZeroDivisionError. + """ + collector = LiveStatsCollector(1000) + + # Edge case: data exists but no successful samples + collector.result[("test.py", 10, "func")] = { + "direct_calls": 10, + "cumulative_calls": 10, + "total_rec_calls": 0, + } + collector.total_samples = 100 + collector.successful_samples = 0 # All samples filtered out + + # Should not raise ZeroDivisionError + stats_list = collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + + # Verify percentage-based sorting also works with zero successful_samples + collector.sort_by = "sample_pct" + stats_list = collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + + collector.sort_by = "cumul_pct" + stats_list = collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + + +class TestLiveStatsCollectorStatisticsBuilding(unittest.TestCase): + """Tests for statistics building and sorting.""" + + def setUp(self): + """Set up test fixtures.""" + self.collector = LiveStatsCollector(1000) + # Add some test data + self.collector.result[("file1.py", 10, "func1")] = { + "direct_calls": 100, + "cumulative_calls": 150, + "total_rec_calls": 0, + } + self.collector.result[("file2.py", 20, "func2")] = { + "direct_calls": 50, + "cumulative_calls": 200, + "total_rec_calls": 0, + } + self.collector.result[("file3.py", 30, "func3")] = { + "direct_calls": 75, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + self.collector.total_samples = 300 + # successful_samples is used for percentage calculations + self.collector.successful_samples = 300 + + def test_build_stats_list(self): + """Test that stats list is built correctly.""" + stats_list = self.collector.build_stats_list() + self.assertEqual(len(stats_list), 3) + + # Check that all expected keys are present + for stat in stats_list: + self.assertIn("func", stat) + self.assertIn("direct_calls", stat) + self.assertIn("cumulative_calls", stat) + self.assertIn("total_time", stat) + self.assertIn("cumulative_time", stat) + + def test_sort_by_nsamples(self): + """Test sorting by number of samples.""" + self.collector.sort_by = "nsamples" + stats_list = self.collector.build_stats_list() + + # Should be sorted by direct_calls descending + self.assertEqual(stats_list[0]["func"][2], "func1") # 100 samples + self.assertEqual(stats_list[1]["func"][2], "func3") # 75 samples + self.assertEqual(stats_list[2]["func"][2], "func2") # 50 samples + + def test_sort_by_tottime(self): + """Test sorting by total time.""" + self.collector.sort_by = "tottime" + stats_list = self.collector.build_stats_list() + + # Should be sorted by total_time descending + # total_time = direct_calls * sample_interval_sec + self.assertEqual(stats_list[0]["func"][2], "func1") + self.assertEqual(stats_list[1]["func"][2], "func3") + self.assertEqual(stats_list[2]["func"][2], "func2") + + def test_sort_by_cumtime(self): + """Test sorting by cumulative time.""" + self.collector.sort_by = "cumtime" + stats_list = self.collector.build_stats_list() + + # Should be sorted by cumulative_time descending + self.assertEqual(stats_list[0]["func"][2], "func2") # 200 cumulative + self.assertEqual(stats_list[1]["func"][2], "func1") # 150 cumulative + self.assertEqual(stats_list[2]["func"][2], "func3") # 75 cumulative + + def test_sort_by_sample_pct(self): + """Test sorting by sample percentage.""" + self.collector.sort_by = "sample_pct" + stats_list = self.collector.build_stats_list() + + # Should be sorted by percentage of direct_calls + self.assertEqual(stats_list[0]["func"][2], "func1") # 33.3% + self.assertEqual(stats_list[1]["func"][2], "func3") # 25% + self.assertEqual(stats_list[2]["func"][2], "func2") # 16.7% + + def test_sort_by_cumul_pct(self): + """Test sorting by cumulative percentage.""" + self.collector.sort_by = "cumul_pct" + stats_list = self.collector.build_stats_list() + + # Should be sorted by percentage of cumulative_calls + self.assertEqual(stats_list[0]["func"][2], "func2") # 66.7% + self.assertEqual(stats_list[1]["func"][2], "func1") # 50% + self.assertEqual(stats_list[2]["func"][2], "func3") # 25% + + +class TestLiveStatsCollectorSortCycle(unittest.TestCase): + """Tests for sort mode cycling.""" + + def test_cycle_sort_from_nsamples(self): + """Test cycling from nsamples.""" + collector = LiveStatsCollector(1000, sort_by="nsamples") + collector._cycle_sort() + self.assertEqual(collector.sort_by, "sample_pct") + + def test_cycle_sort_from_sample_pct(self): + """Test cycling from sample_pct.""" + collector = LiveStatsCollector(1000, sort_by="sample_pct") + collector._cycle_sort() + self.assertEqual(collector.sort_by, "tottime") + + def test_cycle_sort_from_tottime(self): + """Test cycling from tottime.""" + collector = LiveStatsCollector(1000, sort_by="tottime") + collector._cycle_sort() + self.assertEqual(collector.sort_by, "cumul_pct") + + def test_cycle_sort_from_cumul_pct(self): + """Test cycling from cumul_pct.""" + collector = LiveStatsCollector(1000, sort_by="cumul_pct") + collector._cycle_sort() + self.assertEqual(collector.sort_by, "cumtime") + + def test_cycle_sort_from_cumtime(self): + """Test cycling from cumtime back to nsamples.""" + collector = LiveStatsCollector(1000, sort_by="cumtime") + collector._cycle_sort() + self.assertEqual(collector.sort_by, "nsamples") + + def test_cycle_sort_invalid_mode(self): + """Test cycling from invalid mode resets to nsamples.""" + collector = LiveStatsCollector(1000) + collector.sort_by = "invalid_mode" + collector._cycle_sort() + self.assertEqual(collector.sort_by, "nsamples") + + def test_cycle_sort_backward_from_nsamples(self): + """Test cycling backward from nsamples goes to cumtime.""" + collector = LiveStatsCollector(1000, sort_by="nsamples") + collector._cycle_sort(reverse=True) + self.assertEqual(collector.sort_by, "cumtime") + + def test_cycle_sort_backward_from_cumtime(self): + """Test cycling backward from cumtime goes to cumul_pct.""" + collector = LiveStatsCollector(1000, sort_by="cumtime") + collector._cycle_sort(reverse=True) + self.assertEqual(collector.sort_by, "cumul_pct") + + def test_cycle_sort_backward_from_sample_pct(self): + """Test cycling backward from sample_pct goes to nsamples.""" + collector = LiveStatsCollector(1000, sort_by="sample_pct") + collector._cycle_sort(reverse=True) + self.assertEqual(collector.sort_by, "nsamples") + + def test_input_lowercase_s_cycles_forward(self): + """Test that lowercase 's' cycles forward.""" + display = MockDisplay() + collector = LiveStatsCollector( + 1000, sort_by="nsamples", display=display + ) + + display.simulate_input(ord("s")) + collector._handle_input() + + self.assertEqual(collector.sort_by, "sample_pct") + + def test_input_uppercase_s_cycles_backward(self): + """Test that uppercase 'S' cycles backward.""" + display = MockDisplay() + collector = LiveStatsCollector( + 1000, sort_by="nsamples", display=display + ) + + display.simulate_input(ord("S")) + collector._handle_input() + + self.assertEqual(collector.sort_by, "cumtime") + + +class TestLiveStatsCollectorFormatting(unittest.TestCase): + """Tests for formatting methods.""" + + def test_format_uptime_seconds(self): + """Test uptime formatting for seconds only.""" + collector = LiveStatsCollector(1000, display=MockDisplay()) + colors = collector._setup_colors() + collector._initialize_widgets(colors) + self.assertEqual(collector.header_widget.format_uptime(45), "0m45s") + + def test_format_uptime_minutes(self): + """Test uptime formatting for minutes.""" + collector = LiveStatsCollector(1000, display=MockDisplay()) + colors = collector._setup_colors() + collector._initialize_widgets(colors) + self.assertEqual(collector.header_widget.format_uptime(125), "2m05s") + + def test_format_uptime_hours(self): + """Test uptime formatting for hours.""" + collector = LiveStatsCollector(1000, display=MockDisplay()) + colors = collector._setup_colors() + collector._initialize_widgets(colors) + self.assertEqual( + collector.header_widget.format_uptime(3661), "1h01m01s" + ) + + def test_format_uptime_large_values(self): + """Test uptime formatting for large time values.""" + collector = LiveStatsCollector(1000, display=MockDisplay()) + colors = collector._setup_colors() + collector._initialize_widgets(colors) + self.assertEqual( + collector.header_widget.format_uptime(86400), "24h00m00s" + ) + + def test_format_uptime_zero(self): + """Test uptime formatting for zero.""" + collector = LiveStatsCollector(1000, display=MockDisplay()) + colors = collector._setup_colors() + collector._initialize_widgets(colors) + self.assertEqual(collector.header_widget.format_uptime(0), "0m00s") + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py new file mode 100644 index 00000000000..a5870366552 --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py @@ -0,0 +1,1238 @@ +"""Interactive controls tests for LiveStatsCollector. + +Tests for interactive controls, filtering, filter input, and thread navigation. +""" + +import time +import unittest +from test.support import requires +from test.support.import_helper import import_module + +# Only run these tests if curses is available +requires("curses") +curses = import_module("curses") + +from profiling.sampling.live_collector import LiveStatsCollector, MockDisplay +from profiling.sampling.constants import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, +) +from ._live_collector_helpers import ( + MockFrameInfo, + MockThreadInfo, + MockInterpreterInfo, +) + + +class TestLiveCollectorInteractiveControls(unittest.TestCase): + """Tests for interactive control features.""" + + def setUp(self): + """Set up collector with mock display.""" + self.display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.display + ) + self.collector.start_time = time.perf_counter() + # Set a consistent display update interval for tests + self.collector.display_update_interval = 0.1 + + def tearDown(self): + """Clean up after test.""" + pass + + def test_pause_functionality(self): + """Test pause/resume functionality.""" + self.assertFalse(self.collector.paused) + + # Simulate 'p' key press + self.display.simulate_input(ord("p")) + self.collector._handle_input() + + self.assertTrue(self.collector.paused) + + # Press 'p' again to resume + self.display.simulate_input(ord("p")) + self.collector._handle_input() + + self.assertFalse(self.collector.paused) + + def test_pause_stops_ui_updates(self): + """Test that pausing stops UI updates but profiling continues.""" + # Add some data + self.collector.total_samples = 10 + self.collector.result[("test.py", 1, "func")] = { + "direct_calls": 5, + "cumulative_calls": 10, + "total_rec_calls": 0, + } + + # Pause + self.collector.paused = True + + # Simulate a collect call (profiling continues) + thread_info = MockThreadInfo(123, []) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + + initial_samples = self.collector.total_samples + self.collector.collect(stack_frames) + + # Samples should still increment + self.assertEqual(self.collector.total_samples, initial_samples + 1) + + # But display should not have been updated (buffer stays clear) + self.display.cleared = False + self.collector.collect(stack_frames) + self.assertFalse( + self.display.cleared, "Display should not update when paused" + ) + + def test_reset_stats(self): + """Test reset statistics functionality.""" + # Add some stats + self.collector.total_samples = 100 + self.collector.successful_samples = 90 + self.collector.failed_samples = 10 + self.collector.result[("test.py", 1, "func")] = { + "direct_calls": 50, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + + # Reset + self.collector.reset_stats() + + self.assertEqual(self.collector.total_samples, 0) + self.assertEqual(self.collector.successful_samples, 0) + self.assertEqual(self.collector.failed_samples, 0) + self.assertEqual(len(self.collector.result), 0) + + def test_increase_refresh_rate(self): + """Test increasing refresh rate (faster updates).""" + initial_interval = self.collector.display_update_interval + + # Simulate '+' key press (faster = smaller interval) + self.display.simulate_input(ord("+")) + self.collector._handle_input() + + self.assertLess(self.collector.display_update_interval, initial_interval) + + def test_decrease_refresh_rate(self): + """Test decreasing refresh rate (slower updates).""" + initial_interval = self.collector.display_update_interval + + # Simulate '-' key press (slower = larger interval) + self.display.simulate_input(ord("-")) + self.collector._handle_input() + + self.assertGreater(self.collector.display_update_interval, initial_interval) + + def test_refresh_rate_minimum(self): + """Test that refresh rate has a minimum (max speed).""" + self.collector.display_update_interval = 0.05 # Set to minimum + + # Try to go faster + self.display.simulate_input(ord("+")) + self.collector._handle_input() + + # Should stay at minimum + self.assertEqual(self.collector.display_update_interval, 0.05) + + def test_refresh_rate_maximum(self): + """Test that refresh rate has a maximum (min speed).""" + self.collector.display_update_interval = 1.0 # Set to maximum + + # Try to go slower + self.display.simulate_input(ord("-")) + self.collector._handle_input() + + # Should stay at maximum + self.assertEqual(self.collector.display_update_interval, 1.0) + + def test_help_toggle(self): + """Test help screen toggle.""" + self.assertFalse(self.collector.show_help) + + # Show help + self.display.simulate_input(ord("h")) + self.collector._handle_input() + + self.assertTrue(self.collector.show_help) + + # Pressing any key closes help + self.display.simulate_input(ord("x")) + self.collector._handle_input() + + self.assertFalse(self.collector.show_help) + + def test_help_with_question_mark(self): + """Test help screen with '?' key.""" + self.display.simulate_input(ord("?")) + self.collector._handle_input() + + self.assertTrue(self.collector.show_help) + + def test_help_dismiss_with_q_does_not_quit(self): + """Test that pressing 'q' while help is shown only closes help, not quit""" + self.assertFalse(self.collector.show_help) + self.display.simulate_input(ord("h")) + self.collector._handle_input() + self.assertTrue(self.collector.show_help) + + self.display.simulate_input(ord("q")) + self.collector._handle_input() + + self.assertFalse(self.collector.show_help) + self.assertTrue(self.collector.running) + + def test_filter_clear(self): + """Test clearing filter.""" + self.collector.filter_pattern = "test" + + # Clear filter + self.display.simulate_input(ord("c")) + self.collector._handle_input() + + self.assertIsNone(self.collector.filter_pattern) + + def test_filter_clear_when_none(self): + """Test clearing filter when no filter is set.""" + self.assertIsNone(self.collector.filter_pattern) + + # Should not crash + self.display.simulate_input(ord("c")) + self.collector._handle_input() + + self.assertIsNone(self.collector.filter_pattern) + + def test_paused_status_in_footer(self): + """Test that paused status appears in footer.""" + self.collector.total_samples = 10 + self.collector.paused = True + + self.collector._update_display() + + # Check that PAUSED appears in display + self.assertTrue(self.display.contains_text("PAUSED")) + + def test_filter_status_in_footer(self): + """Test that filter status appears in footer.""" + self.collector.total_samples = 10 + self.collector.filter_pattern = "mytest" + + self.collector._update_display() + + # Check that filter info appears + self.assertTrue(self.display.contains_text("Filter")) + + def test_help_screen_display(self): + """Test that help screen is displayed.""" + self.collector.show_help = True + + self.collector._update_display() + + # Check for help content + self.assertTrue(self.display.contains_text("Interactive Commands")) + + def test_pause_uppercase(self): + """Test pause with uppercase 'P' key.""" + self.assertFalse(self.collector.paused) + + self.display.simulate_input(ord("P")) + self.collector._handle_input() + + self.assertTrue(self.collector.paused) + + def test_help_uppercase(self): + """Test help with uppercase 'H' key.""" + self.assertFalse(self.collector.show_help) + + self.display.simulate_input(ord("H")) + self.collector._handle_input() + + self.assertTrue(self.collector.show_help) + + def test_reset_lowercase(self): + """Test reset with lowercase 'r' key.""" + # Add some stats + self.collector.total_samples = 100 + self.collector.result[("test.py", 1, "func")] = { + "direct_calls": 50, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + + self.display.simulate_input(ord("r")) + self.collector._handle_input() + + self.assertEqual(self.collector.total_samples, 0) + self.assertEqual(len(self.collector.result), 0) + + def test_reset_uppercase(self): + """Test reset with uppercase 'R' key.""" + self.collector.total_samples = 100 + + self.display.simulate_input(ord("R")) + self.collector._handle_input() + + self.assertEqual(self.collector.total_samples, 0) + + def test_filter_clear_uppercase(self): + """Test clearing filter with uppercase 'C' key.""" + self.collector.filter_pattern = "test" + + self.display.simulate_input(ord("C")) + self.collector._handle_input() + + self.assertIsNone(self.collector.filter_pattern) + + def test_increase_refresh_rate_with_equals(self): + """Test increasing refresh rate with '=' key.""" + initial_interval = self.collector.display_update_interval + + # Simulate '=' key press (alternative to '+') + self.display.simulate_input(ord("=")) + self.collector._handle_input() + + self.assertLess(self.collector.display_update_interval, initial_interval) + + def test_decrease_refresh_rate_with_underscore(self): + """Test decreasing refresh rate with '_' key.""" + initial_interval = self.collector.display_update_interval + + # Simulate '_' key press (alternative to '-') + self.display.simulate_input(ord("_")) + self.collector._handle_input() + + self.assertGreater(self.collector.display_update_interval, initial_interval) + + def test_finished_state_displays_banner(self): + """Test that finished state shows prominent banner.""" + # Add some sample data + thread_info = MockThreadInfo( + 123, + [ + MockFrameInfo("test.py", 10, "work"), + MockFrameInfo("test.py", 20, "main"), + ], + ) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + self.collector.collect(stack_frames) + + # Mark as finished + self.collector.mark_finished() + + # Check that finished flag is set + self.assertTrue(self.collector.finished) + + # Check that the banner message is displayed + self.assertTrue(self.display.contains_text("PROFILING COMPLETE")) + self.assertTrue(self.display.contains_text("Press 'q' to Quit")) + + def test_finished_state_allows_ui_controls(self): + """Test that finished state allows UI controls but prioritizes quit.""" + self.collector.finished = True + self.collector.running = True + + # Try pressing 's' (sort) - should work and trigger display update + original_sort = self.collector.sort_by + self.display.simulate_input(ord("s")) + self.collector._handle_input() + self.assertTrue(self.collector.running) # Still running + self.assertNotEqual(self.collector.sort_by, original_sort) # Sort changed + + # Try pressing 'p' (pause) - should work + self.display.simulate_input(ord("p")) + self.collector._handle_input() + self.assertTrue(self.collector.running) # Still running + self.assertTrue(self.collector.paused) # Now paused + + # Try pressing 'r' (reset) - should be ignored when finished + self.collector.total_samples = 100 + self.display.simulate_input(ord("r")) + self.collector._handle_input() + self.assertTrue(self.collector.running) # Still running + self.assertEqual(self.collector.total_samples, 100) # NOT reset when finished + + # Press 'q' - should stop + self.display.simulate_input(ord("q")) + self.collector._handle_input() + self.assertFalse(self.collector.running) # Stopped + + def test_finished_state_footer_message(self): + """Test that footer shows appropriate message when finished.""" + # Add some sample data + thread_info = MockThreadInfo( + 123, + [ + MockFrameInfo("test.py", 10, "work"), + MockFrameInfo("test.py", 20, "main"), + ], + ) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + self.collector.collect(stack_frames) + + # Mark as finished + self.collector.mark_finished() + + # Check that footer contains finished message + self.assertTrue(self.display.contains_text("PROFILING FINISHED")) + + def test_finished_state_freezes_time(self): + """Test that time displays are frozen when finished.""" + import time as time_module + + # Set up collector with known start time + self.collector.start_time = time_module.perf_counter() - 10.0 # 10 seconds ago + + # Mark as finished - this should freeze the time + self.collector.mark_finished() + + # Get the frozen elapsed time + frozen_elapsed = self.collector.elapsed_time + frozen_time_display = self.collector.current_time_display + + # Wait a bit to ensure time would advance + time_module.sleep(0.1) + + # Time should remain frozen + self.assertEqual(self.collector.elapsed_time, frozen_elapsed) + self.assertEqual(self.collector.current_time_display, frozen_time_display) + + # Verify finish timestamp was set + self.assertIsNotNone(self.collector.finish_timestamp) + + # Reset should clear the frozen state + self.collector.reset_stats() + self.assertFalse(self.collector.finished) + self.assertIsNone(self.collector.finish_timestamp) + + +class TestLiveCollectorFiltering(unittest.TestCase): + """Tests for filtering functionality.""" + + def setUp(self): + """Set up collector with test data.""" + self.display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.display + ) + self.collector.start_time = time.perf_counter() + self.collector.total_samples = 100 + + # Add test data + self.collector.result[("app/models.py", 10, "save")] = { + "direct_calls": 50, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + self.collector.result[("app/views.py", 20, "render")] = { + "direct_calls": 30, + "cumulative_calls": 40, + "total_rec_calls": 0, + } + self.collector.result[("lib/utils.py", 30, "helper")] = { + "direct_calls": 20, + "cumulative_calls": 25, + "total_rec_calls": 0, + } + + def test_filter_by_filename(self): + """Test filtering by filename pattern.""" + self.collector.filter_pattern = "models" + + stats_list = self.collector.build_stats_list() + + # Only models.py should be included + self.assertEqual(len(stats_list), 1) + self.assertIn("models.py", stats_list[0]["func"][0]) + + def test_filter_by_function_name(self): + """Test filtering by function name.""" + self.collector.filter_pattern = "render" + + stats_list = self.collector.build_stats_list() + + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "render") + + def test_filter_case_insensitive(self): + """Test that filtering is case-insensitive.""" + self.collector.filter_pattern = "MODELS" + + stats_list = self.collector.build_stats_list() + + # Should still match models.py + self.assertEqual(len(stats_list), 1) + + def test_filter_substring_matching(self): + """Test substring filtering.""" + self.collector.filter_pattern = "app/" + + stats_list = self.collector.build_stats_list() + + # Should match both app files + self.assertEqual(len(stats_list), 2) + + def test_no_filter(self): + """Test with no filter applied.""" + self.collector.filter_pattern = None + + stats_list = self.collector.build_stats_list() + + # All items should be included + self.assertEqual(len(stats_list), 3) + + def test_filter_partial_function_name(self): + """Test filtering by partial function name.""" + self.collector.filter_pattern = "save" + + stats_list = self.collector.build_stats_list() + + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "save") + + def test_filter_combined_filename_funcname(self): + """Test filtering matches filename:funcname pattern.""" + self.collector.filter_pattern = "views.py:render" + + stats_list = self.collector.build_stats_list() + + # Should match the combined pattern + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "render") + + def test_filter_no_matches(self): + """Test filter that matches nothing.""" + self.collector.filter_pattern = "nonexistent" + + stats_list = self.collector.build_stats_list() + + self.assertEqual(len(stats_list), 0) + + +class TestLiveCollectorFilterInput(unittest.TestCase): + """Tests for filter input mode.""" + + def setUp(self): + """Set up collector with mock display.""" + self.display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.display + ) + self.collector.start_time = time.perf_counter() + + def test_enter_filter_mode(self): + """Test entering filter input mode.""" + self.assertFalse(self.collector.filter_input_mode) + + # Press '/' to enter filter mode + self.display.simulate_input(ord("/")) + self.collector._handle_input() + + self.assertTrue(self.collector.filter_input_mode) + + def test_filter_input_typing(self): + """Test typing characters in filter input mode.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "" + + # Type 't', 'e', 's', 't' + for ch in "test": + self.display.simulate_input(ord(ch)) + self.collector._handle_input() + + self.assertEqual(self.collector.filter_input_buffer, "test") + + def test_filter_input_backspace(self): + """Test backspace in filter input mode.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "test" + + # Press backspace (127) + self.display.simulate_input(127) + self.collector._handle_input() + + self.assertEqual(self.collector.filter_input_buffer, "tes") + + def test_filter_input_backspace_alt(self): + """Test alternative backspace key (263) in filter input mode.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "test" + + # Press backspace (263) + self.display.simulate_input(263) + self.collector._handle_input() + + self.assertEqual(self.collector.filter_input_buffer, "tes") + + def test_filter_input_backspace_empty(self): + """Test backspace on empty buffer.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "" + + # Press backspace - should not crash + self.display.simulate_input(127) + self.collector._handle_input() + + self.assertEqual(self.collector.filter_input_buffer, "") + + def test_filter_input_enter_applies_filter(self): + """Test pressing Enter applies the filter.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "myfilter" + + # Press Enter (10) + self.display.simulate_input(10) + self.collector._handle_input() + + self.assertFalse(self.collector.filter_input_mode) + self.assertEqual(self.collector.filter_pattern, "myfilter") + self.assertEqual(self.collector.filter_input_buffer, "") + + def test_filter_input_enter_alt(self): + """Test alternative Enter key (13) applies filter.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "myfilter" + + # Press Enter (13) + self.display.simulate_input(13) + self.collector._handle_input() + + self.assertFalse(self.collector.filter_input_mode) + self.assertEqual(self.collector.filter_pattern, "myfilter") + + def test_filter_input_enter_empty_clears_filter(self): + """Test pressing Enter with empty buffer clears filter.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "" + self.collector.filter_pattern = "oldfilter" + + # Press Enter + self.display.simulate_input(10) + self.collector._handle_input() + + self.assertFalse(self.collector.filter_input_mode) + self.assertIsNone(self.collector.filter_pattern) + + def test_filter_input_escape_cancels(self): + """Test pressing ESC cancels filter input.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "newfilter" + self.collector.filter_pattern = "oldfilter" + + # Press ESC (27) + self.display.simulate_input(27) + self.collector._handle_input() + + self.assertFalse(self.collector.filter_input_mode) + self.assertEqual( + self.collector.filter_pattern, "oldfilter" + ) # Unchanged + self.assertEqual(self.collector.filter_input_buffer, "") + + def test_filter_input_start_with_existing_filter(self): + """Test entering filter mode with existing filter pre-fills buffer.""" + self.collector.filter_pattern = "existing" + + # Enter filter mode + self.display.simulate_input(ord("/")) + self.collector._handle_input() + + # Buffer should be pre-filled with existing pattern + self.assertEqual(self.collector.filter_input_buffer, "existing") + + def test_filter_input_start_without_filter(self): + """Test entering filter mode with no existing filter.""" + self.collector.filter_pattern = None + + # Enter filter mode + self.display.simulate_input(ord("/")) + self.collector._handle_input() + + # Buffer should be empty + self.assertEqual(self.collector.filter_input_buffer, "") + + def test_filter_input_mode_blocks_other_commands(self): + """Test that filter input mode blocks other commands.""" + self.collector.filter_input_mode = True + initial_sort = self.collector.sort_by + + # Try to press 's' (sort) - should be captured as input + self.display.simulate_input(ord("s")) + self.collector._handle_input() + + # Sort should not change, 's' should be in buffer + self.assertEqual(self.collector.sort_by, initial_sort) + self.assertEqual(self.collector.filter_input_buffer, "s") + + def test_filter_input_non_printable_ignored(self): + """Test that non-printable characters are ignored.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "test" + + # Try to input a control character (< 32) + self.display.simulate_input(1) # Ctrl-A + self.collector._handle_input() + + # Buffer should be unchanged + self.assertEqual(self.collector.filter_input_buffer, "test") + + def test_filter_input_high_ascii_ignored(self): + """Test that high ASCII characters (>= 127, except backspace) are ignored.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "test" + + # Try to input high ASCII (128) + self.display.simulate_input(128) + self.collector._handle_input() + + # Buffer should be unchanged + self.assertEqual(self.collector.filter_input_buffer, "test") + + def test_filter_prompt_displayed(self): + """Test that filter prompt is displayed when in input mode.""" + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "myfilter" + self.collector.total_samples = 10 + + self.collector._update_display() + + # Should show the filter prompt + self.assertTrue(self.display.contains_text("Function filter")) + self.assertTrue(self.display.contains_text("myfilter")) + + +if __name__ == "__main__": + unittest.main() + + +class TestLiveCollectorThreadNavigation(unittest.TestCase): + """Tests for thread navigation functionality.""" + + def setUp(self): + """Set up collector with mock display and multiple threads.""" + self.mock_display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.mock_display + ) + self.collector.start_time = time.perf_counter() + + # Simulate data from multiple threads + frames1 = [MockFrameInfo("file1.py", 10, "func1")] + frames2 = [MockFrameInfo("file2.py", 20, "func2")] + frames3 = [MockFrameInfo("file3.py", 30, "func3")] + + thread1 = MockThreadInfo(111, frames1) + thread2 = MockThreadInfo(222, frames2) + thread3 = MockThreadInfo(333, frames3) + + interpreter_info = MockInterpreterInfo(0, [thread1, thread2, thread3]) + stack_frames = [interpreter_info] + + # Collect data to populate thread IDs + self.collector.collect(stack_frames) + + def test_initial_view_mode_is_all(self): + """Test that collector starts in ALL mode.""" + self.assertEqual(self.collector.view_mode, "ALL") + self.assertEqual(self.collector.current_thread_index, 0) + + def test_thread_ids_are_tracked(self): + """Test that thread IDs are tracked during collection.""" + self.assertIn(111, self.collector.thread_ids) + self.assertIn(222, self.collector.thread_ids) + self.assertIn(333, self.collector.thread_ids) + self.assertEqual(len(self.collector.thread_ids), 3) + + def test_toggle_to_per_thread_mode(self): + """Test toggling from ALL to PER_THREAD mode with 't' key.""" + self.assertEqual(self.collector.view_mode, "ALL") + + self.mock_display.simulate_input(ord("t")) + self.collector._handle_input() + + self.assertEqual(self.collector.view_mode, "PER_THREAD") + self.assertEqual(self.collector.current_thread_index, 0) + + def test_toggle_back_to_all_mode(self): + """Test toggling back from PER_THREAD to ALL mode.""" + # Switch to PER_THREAD + self.mock_display.simulate_input(ord("t")) + self.collector._handle_input() + self.assertEqual(self.collector.view_mode, "PER_THREAD") + + # Switch back to ALL + self.mock_display.simulate_input(ord("T")) + self.collector._handle_input() + self.assertEqual(self.collector.view_mode, "ALL") + + def test_arrow_right_navigates_threads_in_per_thread_mode(self): + """Test that arrow keys navigate threads in PER_THREAD mode.""" + # Switch to PER_THREAD mode + self.mock_display.simulate_input(ord("t")) + self.collector._handle_input() + + # Navigate forward + self.assertEqual(self.collector.current_thread_index, 0) + + self.mock_display.simulate_input(curses.KEY_RIGHT) + self.collector._handle_input() + self.assertEqual(self.collector.current_thread_index, 1) + + self.mock_display.simulate_input(curses.KEY_RIGHT) + self.collector._handle_input() + self.assertEqual(self.collector.current_thread_index, 2) + + def test_arrow_left_navigates_threads_backward(self): + """Test that left arrow navigates threads backward.""" + # Switch to PER_THREAD mode + self.mock_display.simulate_input(ord("t")) + self.collector._handle_input() + + # Navigate backward (should wrap around) + self.mock_display.simulate_input(curses.KEY_LEFT) + self.collector._handle_input() + self.assertEqual( + self.collector.current_thread_index, 2 + ) # Wrapped to last + + self.mock_display.simulate_input(curses.KEY_LEFT) + self.collector._handle_input() + self.assertEqual(self.collector.current_thread_index, 1) + + def test_arrow_down_navigates_like_right(self): + """Test that down arrow works like right arrow.""" + # Switch to PER_THREAD mode + self.mock_display.simulate_input(ord("t")) + self.collector._handle_input() + + self.mock_display.simulate_input(curses.KEY_DOWN) + self.collector._handle_input() + self.assertEqual(self.collector.current_thread_index, 1) + + def test_arrow_up_navigates_like_left(self): + """Test that up arrow works like left arrow.""" + # Switch to PER_THREAD mode + self.mock_display.simulate_input(ord("t")) + self.collector._handle_input() + + self.mock_display.simulate_input(curses.KEY_UP) + self.collector._handle_input() + self.assertEqual(self.collector.current_thread_index, 2) # Wrapped + + def test_arrow_keys_switch_to_per_thread_mode(self): + """Test that arrow keys switch from ALL mode to PER_THREAD mode.""" + self.assertEqual(self.collector.view_mode, "ALL") + + self.mock_display.simulate_input(curses.KEY_RIGHT) + self.collector._handle_input() + self.assertEqual(self.collector.view_mode, "PER_THREAD") + self.assertEqual(self.collector.current_thread_index, 0) + + def test_stats_list_in_all_mode(self): + """Test that stats list uses aggregated data in ALL mode.""" + stats_list = self.collector.build_stats_list() + + # Should have all 3 functions + self.assertEqual(len(stats_list), 3) + func_names = {stat["func"][2] for stat in stats_list} + self.assertEqual(func_names, {"func1", "func2", "func3"}) + + def test_stats_list_in_per_thread_mode(self): + """Test that stats list filters by thread in PER_THREAD mode.""" + # Switch to PER_THREAD mode + self.collector.view_mode = "PER_THREAD" + self.collector.current_thread_index = 0 # First thread (111) + + stats_list = self.collector.build_stats_list() + + # Should only have func1 from thread 111 + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "func1") + + def test_stats_list_switches_with_thread_navigation(self): + """Test that stats list updates when navigating threads.""" + self.collector.view_mode = "PER_THREAD" + + # Thread 0 (111) -> func1 + self.collector.current_thread_index = 0 + stats_list = self.collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "func1") + + # Thread 1 (222) -> func2 + self.collector.current_thread_index = 1 + stats_list = self.collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "func2") + + # Thread 2 (333) -> func3 + self.collector.current_thread_index = 2 + stats_list = self.collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], "func3") + + def test_reset_stats_clears_thread_data(self): + """Test that reset_stats clears thread tracking data.""" + self.assertGreater(len(self.collector.thread_ids), 0) + self.assertGreater(len(self.collector.per_thread_data), 0) + + self.collector.reset_stats() + + self.assertEqual(len(self.collector.thread_ids), 0) + self.assertEqual(len(self.collector.per_thread_data), 0) + self.assertEqual(self.collector.view_mode, "ALL") + self.assertEqual(self.collector.current_thread_index, 0) + + def test_toggle_with_no_threads_stays_in_all_mode(self): + """Test that toggle does nothing when no threads exist.""" + collector = LiveStatsCollector(1000, display=MockDisplay()) + self.assertEqual(len(collector.thread_ids), 0) + + collector.display.simulate_input(ord("t")) + collector._handle_input() + + # Should remain in ALL mode since no threads + self.assertEqual(collector.view_mode, "ALL") + + def test_per_thread_data_isolation(self): + """Test that per-thread data is properly isolated.""" + # Check that each thread has its own isolated data + self.assertIn(111, self.collector.per_thread_data) + self.assertIn(222, self.collector.per_thread_data) + self.assertIn(333, self.collector.per_thread_data) + + # Thread 111 should only have func1 + thread1_funcs = list(self.collector.per_thread_data[111].result.keys()) + self.assertEqual(len(thread1_funcs), 1) + self.assertEqual(thread1_funcs[0][2], "func1") + + # Thread 222 should only have func2 + thread2_funcs = list(self.collector.per_thread_data[222].result.keys()) + self.assertEqual(len(thread2_funcs), 1) + self.assertEqual(thread2_funcs[0][2], "func2") + + def test_aggregated_data_sums_all_threads(self): + """Test that ALL mode shows aggregated data from all threads.""" + # All three functions should be in the aggregated result + self.assertEqual(len(self.collector.result), 3) + + # Each function should have 1 direct call + for func_location, counts in self.collector.result.items(): + self.assertEqual(counts["direct_calls"], 1) + + def test_per_thread_status_tracking(self): + """Test that per-thread status statistics are tracked.""" + # Each thread should have status counts + self.assertIn(111, self.collector.per_thread_data) + self.assertIn(222, self.collector.per_thread_data) + self.assertIn(333, self.collector.per_thread_data) + + # Each thread should have the expected attributes + for thread_id in [111, 222, 333]: + thread_data = self.collector.per_thread_data[thread_id] + self.assertIsNotNone(thread_data.has_gil) + self.assertIsNotNone(thread_data.on_cpu) + self.assertIsNotNone(thread_data.gil_requested) + self.assertIsNotNone(thread_data.unknown) + self.assertIsNotNone(thread_data.total) + # Each thread was sampled once + self.assertEqual(thread_data.total, 1) + + def test_reset_stats_clears_thread_status(self): + """Test that reset_stats clears per-thread status data.""" + self.assertGreater(len(self.collector.per_thread_data), 0) + + self.collector.reset_stats() + + self.assertEqual(len(self.collector.per_thread_data), 0) + + def test_per_thread_sample_counts(self): + """Test that per-thread sample counts are tracked correctly.""" + # Each thread should have exactly 1 sample (we collected once) + for thread_id in [111, 222, 333]: + self.assertIn(thread_id, self.collector.per_thread_data) + self.assertEqual(self.collector.per_thread_data[thread_id].sample_count, 1) + + def test_per_thread_gc_samples(self): + """Test that per-thread GC samples are tracked correctly.""" + # Initially no threads have GC frames + for thread_id in [111, 222, 333]: + self.assertIn(thread_id, self.collector.per_thread_data) + self.assertEqual( + self.collector.per_thread_data[thread_id].gc_frame_samples, 0 + ) + + # Now collect a sample with a GC frame in thread 222 + gc_frames = [MockFrameInfo("gc.py", 100, "gc_collect")] + thread_with_gc = MockThreadInfo(222, gc_frames) + interpreter_info = MockInterpreterInfo(0, [thread_with_gc]) + stack_frames = [interpreter_info] + + self.collector.collect(stack_frames) + + # Thread 222 should now have 1 GC sample + self.assertEqual(self.collector.per_thread_data[222].gc_frame_samples, 1) + # Other threads should still have 0 + self.assertEqual(self.collector.per_thread_data[111].gc_frame_samples, 0) + self.assertEqual(self.collector.per_thread_data[333].gc_frame_samples, 0) + + def test_only_threads_with_frames_are_tracked(self): + """Test that only threads with actual frame data are added to thread_ids.""" + # Create a new collector + collector = LiveStatsCollector(1000, display=MockDisplay()) + + # Create threads: one with frames, one without + frames = [MockFrameInfo("test.py", 10, "test_func")] + thread_with_frames = MockThreadInfo(111, frames) + thread_without_frames = MockThreadInfo(222, None) # No frames + interpreter_info = MockInterpreterInfo( + 0, [thread_with_frames, thread_without_frames] + ) + stack_frames = [interpreter_info] + + collector.collect(stack_frames) + + # Only thread 111 should be tracked (it has frames) + self.assertIn(111, collector.thread_ids) + self.assertNotIn(222, collector.thread_ids) + + def test_per_thread_status_isolation(self): + """Test that per-thread status counts are isolated per thread.""" + # Create threads with different status flags + + frames1 = [MockFrameInfo("file1.py", 10, "func1")] + frames2 = [MockFrameInfo("file2.py", 20, "func2")] + + # Thread 444: has GIL but not on CPU + thread1 = MockThreadInfo(444, frames1, status=THREAD_STATUS_HAS_GIL) + # Thread 555: on CPU but not has GIL + thread2 = MockThreadInfo(555, frames2, status=THREAD_STATUS_ON_CPU) + + interpreter_info = MockInterpreterInfo(0, [thread1, thread2]) + stack_frames = [interpreter_info] + + collector = LiveStatsCollector(1000, display=MockDisplay()) + collector.collect(stack_frames) + + # Check thread 444 status + self.assertEqual(collector.per_thread_data[444].has_gil, 1) + self.assertEqual(collector.per_thread_data[444].on_cpu, 0) + + # Check thread 555 status + self.assertEqual(collector.per_thread_data[555].has_gil, 0) + self.assertEqual(collector.per_thread_data[555].on_cpu, 1) + + def test_display_uses_per_thread_stats_in_per_thread_mode(self): + """Test that display widget uses per-thread stats when in PER_THREAD mode.""" + + # Create collector with mock display + collector = LiveStatsCollector(1000, display=MockDisplay()) + collector.start_time = time.perf_counter() + + # Create 2 threads with different characteristics + # Thread 111: always has GIL (10 samples) + # Thread 222: never has GIL (10 samples) + for _ in range(10): + frames1 = [MockFrameInfo("file1.py", 10, "func1")] + frames2 = [MockFrameInfo("file2.py", 20, "func2")] + thread1 = MockThreadInfo( + 111, frames1, status=THREAD_STATUS_HAS_GIL + ) + thread2 = MockThreadInfo(222, frames2, status=0) # No flags + interpreter_info = MockInterpreterInfo(0, [thread1, thread2]) + collector.collect([interpreter_info]) + + # In ALL mode, should show mixed stats (50% on GIL, 50% off GIL) + self.assertEqual(collector.view_mode, "ALL") + total_has_gil = collector.thread_status_counts["has_gil"] + total_threads = collector.thread_status_counts["total"] + self.assertEqual(total_has_gil, 10) # Only thread 111 has GIL + self.assertEqual(total_threads, 20) # 10 samples * 2 threads + + # Switch to PER_THREAD mode and select thread 111 + collector.view_mode = "PER_THREAD" + collector.current_thread_index = 0 # Thread 111 + + # Thread 111 should show 100% on GIL + thread_111_data = collector.per_thread_data[111] + self.assertEqual(thread_111_data.has_gil, 10) + self.assertEqual(thread_111_data.total, 10) + + # Switch to thread 222 + collector.current_thread_index = 1 # Thread 222 + + # Thread 222 should show 0% on GIL + thread_222_data = collector.per_thread_data[222] + self.assertEqual(thread_222_data.has_gil, 0) + self.assertEqual(thread_222_data.total, 10) + + def test_display_uses_per_thread_gc_stats_in_per_thread_mode(self): + """Test that GC percentage uses per-thread data in PER_THREAD mode.""" + # Create collector with mock display + collector = LiveStatsCollector(1000, display=MockDisplay()) + collector.start_time = time.perf_counter() + + # Thread 111: 5 samples, 2 with GC + # Thread 222: 5 samples, 0 with GC + for i in range(5): + if i < 2: + # First 2 samples for thread 111 have GC + frames1 = [MockFrameInfo("gc.py", 100, "gc_collect")] + else: + frames1 = [MockFrameInfo("file1.py", 10, "func1")] + + frames2 = [MockFrameInfo("file2.py", 20, "func2")] # No GC + + thread1 = MockThreadInfo(111, frames1) + thread2 = MockThreadInfo(222, frames2) + interpreter_info = MockInterpreterInfo(0, [thread1, thread2]) + collector.collect([interpreter_info]) + + # Check aggregated GC stats (ALL mode) + # 2 GC samples out of 10 total = 20% + self.assertEqual(collector.gc_frame_samples, 2) + self.assertEqual(collector.total_samples, 5) # 5 collect() calls + + # Check per-thread GC stats + # Thread 111: 2 GC samples out of 5 = 40% + self.assertEqual(collector.per_thread_data[111].gc_frame_samples, 2) + self.assertEqual(collector.per_thread_data[111].sample_count, 5) + + # Thread 222: 0 GC samples out of 5 = 0% + self.assertEqual(collector.per_thread_data[222].gc_frame_samples, 0) + self.assertEqual(collector.per_thread_data[222].sample_count, 5) + + # Now verify the display would use the correct stats + collector.view_mode = "PER_THREAD" + + # For thread 111 + collector.current_thread_index = 0 + thread_id = collector.thread_ids[0] + self.assertEqual(thread_id, 111) + thread_gc_pct = ( + collector.per_thread_data[111].gc_frame_samples + / collector.per_thread_data[111].sample_count + ) * 100 + self.assertEqual(thread_gc_pct, 40.0) + + # For thread 222 + collector.current_thread_index = 1 + thread_id = collector.thread_ids[1] + self.assertEqual(thread_id, 222) + thread_gc_pct = ( + collector.per_thread_data[222].gc_frame_samples + / collector.per_thread_data[222].sample_count + ) * 100 + self.assertEqual(thread_gc_pct, 0.0) + + def test_function_counts_are_per_thread_in_per_thread_mode(self): + """Test that function counts (total/exec/stack) are per-thread in PER_THREAD mode.""" + # Create collector with mock display + collector = LiveStatsCollector(1000, display=MockDisplay()) + collector.start_time = time.perf_counter() + + # Thread 111: calls func1, func2, func3 (3 functions) + # Thread 222: calls func4, func5 (2 functions) + frames1 = [ + MockFrameInfo("file1.py", 10, "func1"), + MockFrameInfo("file1.py", 20, "func2"), + MockFrameInfo("file1.py", 30, "func3"), + ] + frames2 = [ + MockFrameInfo("file2.py", 40, "func4"), + MockFrameInfo("file2.py", 50, "func5"), + ] + + thread1 = MockThreadInfo(111, frames1) + thread2 = MockThreadInfo(222, frames2) + interpreter_info = MockInterpreterInfo(0, [thread1, thread2]) + collector.collect([interpreter_info]) + + # In ALL mode, should have 5 total functions + self.assertEqual(len(collector.result), 5) + + # In PER_THREAD mode for thread 111, should have 3 functions + collector.view_mode = "PER_THREAD" + collector.current_thread_index = 0 # Thread 111 + thread_111_result = collector.per_thread_data[111].result + self.assertEqual(len(thread_111_result), 3) + + # Verify the functions are the right ones + thread_111_funcs = {loc[2] for loc in thread_111_result.keys()} + self.assertEqual(thread_111_funcs, {"func1", "func2", "func3"}) + + # In PER_THREAD mode for thread 222, should have 2 functions + collector.current_thread_index = 1 # Thread 222 + thread_222_result = collector.per_thread_data[222].result + self.assertEqual(len(thread_222_result), 2) + + # Verify the functions are the right ones + thread_222_funcs = {loc[2] for loc in thread_222_result.keys()} + self.assertEqual(thread_222_funcs, {"func4", "func5"}) + + +class TestLiveCollectorNewFeatures(unittest.TestCase): + """Tests for new features added to live collector.""" + + def setUp(self): + """Set up test fixtures.""" + self.display = MockDisplay() + self.collector = LiveStatsCollector(1000, display=self.display) + self.collector.start_time = time.perf_counter() + + def test_filter_input_takes_precedence_over_commands(self): + """Test that filter input mode blocks command keys like 'h' and 'p'.""" + # Enter filter input mode + self.collector.filter_input_mode = True + self.collector.filter_input_buffer = "" + + # Press 'h' - should add to filter buffer, not show help + self.display.simulate_input(ord("h")) + self.collector._handle_input() + + self.assertFalse(self.collector.show_help) # Help not triggered + self.assertEqual(self.collector.filter_input_buffer, "h") # Added to filter + self.assertTrue(self.collector.filter_input_mode) # Still in filter mode + + def test_reset_blocked_when_finished(self): + """Test that reset command is blocked when profiling is finished.""" + # Set up some sample data and mark as finished + self.collector.total_samples = 100 + self.collector.finished = True + + # Press 'r' for reset + self.display.simulate_input(ord("r")) + self.collector._handle_input() + + # Should NOT have been reset + self.assertEqual(self.collector.total_samples, 100) + self.assertTrue(self.collector.finished) + + def test_time_display_fix_when_finished(self): + """Test that time display shows correct frozen time when finished.""" + import time as time_module + + # Mark as finished to freeze time + self.collector.mark_finished() + + # Should have set both timestamps correctly + self.assertIsNotNone(self.collector.finish_timestamp) + self.assertIsNotNone(self.collector.finish_wall_time) + + # Get the frozen time display + frozen_time = self.collector.current_time_display + + # Wait a bit + time_module.sleep(0.1) + + # Should still show the same frozen time (not jump to wrong time) + self.assertEqual(self.collector.current_time_display, frozen_time) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py new file mode 100644 index 00000000000..2ed9d82a4a4 --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py @@ -0,0 +1,820 @@ +"""UI and display tests for LiveStatsCollector. + +Tests for MockDisplay, curses integration, display methods, +edge cases, update display, and display helpers. +""" + +import sys +import time +import unittest +from unittest import mock +from test.support import requires +from test.support.import_helper import import_module + +# Only run these tests if curses is available +requires("curses") +curses = import_module("curses") + +from profiling.sampling.live_collector import LiveStatsCollector, MockDisplay +from ._live_collector_helpers import ( + MockThreadInfo, + MockInterpreterInfo, +) + + +class TestLiveStatsCollectorWithMockDisplay(unittest.TestCase): + """Tests for display functionality using MockDisplay.""" + + def setUp(self): + """Set up collector with mock display.""" + self.mock_display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.mock_display + ) + self.collector.start_time = time.perf_counter() + + def test_update_display_with_mock(self): + """Test that update_display works with MockDisplay.""" + self.collector.total_samples = 100 + self.collector.result[("test.py", 10, "test_func")] = { + "direct_calls": 50, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + + self.collector._update_display() + + # Verify display operations were called + self.assertTrue(self.mock_display.cleared) + self.assertTrue(self.mock_display.refreshed) + self.assertTrue(self.mock_display.redrawn) + + # Verify some content was written + self.assertGreater(len(self.mock_display.buffer), 0) + + def test_handle_input_quit(self): + """Test that 'q' input stops the collector.""" + self.mock_display.simulate_input(ord("q")) + self.collector._handle_input() + self.assertFalse(self.collector.running) + + def test_handle_input_sort_cycle(self): + """Test that 's' input cycles sort mode.""" + self.collector.sort_by = "tottime" + self.mock_display.simulate_input(ord("s")) + self.collector._handle_input() + self.assertEqual(self.collector.sort_by, "cumul_pct") + + def test_draw_methods_with_mock_display(self): + """Test that draw methods write to mock display.""" + self.collector.total_samples = 500 + self.collector.successful_samples = 450 + self.collector.failed_samples = 50 + + colors = self.collector._setup_colors() + self.collector._initialize_widgets(colors) + + # Test individual widget methods + line = self.collector.header_widget.draw_header_info(0, 160, 100.5) + self.assertEqual(line, 2) # Title + header info line + self.assertGreater(len(self.mock_display.buffer), 0) + + # Clear buffer and test next method + self.mock_display.buffer.clear() + line = self.collector.header_widget.draw_sample_stats(0, 160, 10.0) + self.assertEqual(line, 1) + self.assertGreater(len(self.mock_display.buffer), 0) + + def test_terminal_too_small_message(self): + """Test terminal too small warning.""" + small_display = MockDisplay(height=10, width=50) + self.collector.display = small_display + + self.collector._show_terminal_too_small(10, 50) + + # Should have written warning message + text = small_display.get_text_at(3, 15) # Approximate center + self.assertIsNotNone(text) + + def test_full_display_rendering_with_data(self): + """Test complete display rendering with realistic data.""" + # Add multiple functions with different call counts + self.collector.total_samples = 1000 + self.collector.successful_samples = 950 + self.collector.failed_samples = 50 + + self.collector.result[("app.py", 10, "main")] = { + "direct_calls": 100, + "cumulative_calls": 500, + "total_rec_calls": 0, + } + self.collector.result[("utils.py", 20, "helper")] = { + "direct_calls": 300, + "cumulative_calls": 400, + "total_rec_calls": 0, + } + self.collector.result[("db.py", 30, "query")] = { + "direct_calls": 50, + "cumulative_calls": 100, + "total_rec_calls": 0, + } + + self.collector._update_display() + + # Verify the display has content + self.assertGreater(len(self.mock_display.buffer), 10) + + # Verify PID is shown + found_pid = False + for (line, col), (text, attr) in self.mock_display.buffer.items(): + if "12345" in text: + found_pid = True + break + self.assertTrue(found_pid, "PID should be displayed") + + def test_efficiency_bar_visualization(self): + """Test that efficiency bar shows correct proportions.""" + self.collector.total_samples = 100 + self.collector.successful_samples = 75 + self.collector.failed_samples = 25 + + colors = self.collector._setup_colors() + self.collector._initialize_widgets(colors) + self.collector.header_widget.draw_efficiency_bar(0, 160) + + # Check that something was drawn to the display + self.assertGreater(len(self.mock_display.buffer), 0) + + def test_stats_display_with_different_sort_modes(self): + """Test that stats are displayed correctly with different sort modes.""" + self.collector.total_samples = 100 + self.collector.successful_samples = 100 # For percentage calculations + self.collector.result[("a.py", 1, "func_a")] = { + "direct_calls": 10, + "cumulative_calls": 20, + "total_rec_calls": 0, + } + self.collector.result[("b.py", 2, "func_b")] = { + "direct_calls": 30, + "cumulative_calls": 40, + "total_rec_calls": 0, + } + + # Test each sort mode + for sort_mode in [ + "nsamples", + "tottime", + "cumtime", + "sample_pct", + "cumul_pct", + ]: + self.mock_display.buffer.clear() + self.collector.sort_by = sort_mode + + stats_list = self.collector.build_stats_list() + self.assertEqual(len(stats_list), 2) + + # Verify sorting worked (func_b should be first for most modes) + if sort_mode in ["nsamples", "tottime", "sample_pct"]: + self.assertEqual(stats_list[0]["func"][2], "func_b") + + def test_narrow_terminal_column_hiding(self): + """Test that columns are hidden on narrow terminals.""" + narrow_display = MockDisplay(height=40, width=70) + collector = LiveStatsCollector(1000, pid=12345, display=narrow_display) + collector.start_time = time.perf_counter() + + colors = collector._setup_colors() + collector._initialize_widgets(colors) + line, show_sample_pct, show_tottime, show_cumul_pct, show_cumtime = ( + collector.table_widget.draw_column_headers(0, 70) + ) + + # On narrow terminal, some columns should be hidden + self.assertFalse( + show_cumul_pct or show_cumtime, + "Some columns should be hidden on narrow terminal", + ) + + def test_very_narrow_terminal_minimal_columns(self): + """Test minimal display on very narrow terminal.""" + very_narrow = MockDisplay(height=40, width=60) + collector = LiveStatsCollector(1000, pid=12345, display=very_narrow) + collector.start_time = time.perf_counter() + + colors = collector._setup_colors() + collector._initialize_widgets(colors) + line, show_sample_pct, show_tottime, show_cumul_pct, show_cumtime = ( + collector.table_widget.draw_column_headers(0, 60) + ) + + # Very narrow should hide even more columns + self.assertFalse( + show_sample_pct, + "Sample % should be hidden on very narrow terminal", + ) + + def test_display_updates_only_at_interval(self): + """Test that display updates respect the update interval.""" + # Create collector with display + collector = LiveStatsCollector(1000, display=self.mock_display) + + # Simulate multiple rapid collections + thread_info = MockThreadInfo(123, []) + interpreter_info = MockInterpreterInfo(0, [thread_info]) + stack_frames = [interpreter_info] + + # First collect should update display + collector.collect(stack_frames) + first_cleared = self.mock_display.cleared + + # Reset flags + self.mock_display.cleared = False + self.mock_display.refreshed = False + + # Immediate second collect should NOT update display (too soon) + collector.collect(stack_frames) + self.assertFalse( + self.mock_display.cleared, + "Display should not update too frequently", + ) + + def test_top_functions_display(self): + """Test that top functions are highlighted correctly.""" + self.collector.total_samples = 1000 + + # Create functions with different sample counts + for i in range(10): + self.collector.result[(f"file{i}.py", i * 10, f"func{i}")] = { + "direct_calls": (10 - i) * 10, # Decreasing counts + "cumulative_calls": (10 - i) * 20, + "total_rec_calls": 0, + } + + colors = self.collector._setup_colors() + self.collector._initialize_widgets(colors) + stats_list = self.collector.build_stats_list() + + self.collector.header_widget.draw_top_functions(0, 160, stats_list) + + # Top functions section should have written something + self.assertGreater(len(self.mock_display.buffer), 0) + + +class TestLiveStatsCollectorCursesIntegration(unittest.TestCase): + """Tests for curses-related functionality using mocks.""" + + def setUp(self): + """Set up mock curses screen.""" + self.mock_stdscr = mock.MagicMock() + self.mock_stdscr.getmaxyx.return_value = (40, 160) # height, width + self.mock_stdscr.getch.return_value = -1 # No input + # Save original stdout/stderr + self._orig_stdout = sys.stdout + self._orig_stderr = sys.stderr + + def tearDown(self): + """Restore stdout/stderr if changed.""" + sys.stdout = self._orig_stdout + sys.stderr = self._orig_stderr + + def test_init_curses(self): + """Test curses initialization.""" + collector = LiveStatsCollector(1000) + + with ( + mock.patch("curses.curs_set"), + mock.patch("curses.has_colors", return_value=True), + mock.patch("curses.start_color"), + mock.patch("curses.use_default_colors"), + mock.patch("builtins.open", mock.mock_open()) as mock_open_func, + ): + collector.init_curses(self.mock_stdscr) + + self.assertIsNotNone(collector.stdscr) + self.mock_stdscr.nodelay.assert_called_with(True) + self.mock_stdscr.scrollok.assert_called_with(False) + + # Clean up properly + if collector._devnull: + collector._devnull.close() + collector._saved_stdout = None + collector._saved_stderr = None + + def test_cleanup_curses(self): + """Test curses cleanup.""" + mock_display = MockDisplay() + collector = LiveStatsCollector(1000, display=mock_display) + collector.stdscr = self.mock_stdscr + + # Mock devnull file to avoid resource warnings + mock_devnull = mock.MagicMock() + mock_saved_stdout = mock.MagicMock() + mock_saved_stderr = mock.MagicMock() + + collector._devnull = mock_devnull + collector._saved_stdout = mock_saved_stdout + collector._saved_stderr = mock_saved_stderr + + with mock.patch("curses.curs_set"): + collector.cleanup_curses() + + mock_devnull.close.assert_called_once() + # Verify stdout/stderr were set back to the saved values + self.assertEqual(sys.stdout, mock_saved_stdout) + self.assertEqual(sys.stderr, mock_saved_stderr) + # Verify the saved values were cleared + self.assertIsNone(collector._saved_stdout) + self.assertIsNone(collector._saved_stderr) + self.assertIsNone(collector._devnull) + + def test_add_str_with_mock_display(self): + """Test safe_addstr with MockDisplay.""" + mock_display = MockDisplay(height=40, width=160) + collector = LiveStatsCollector(1000, display=mock_display) + colors = collector._setup_colors() + collector._initialize_widgets(colors) + + collector.header_widget.add_str(5, 10, "Test", 0) + # Verify it was added to the buffer + self.assertIn((5, 10), mock_display.buffer) + + def test_setup_colors_with_color_support(self): + """Test color setup when colors are supported.""" + mock_display = MockDisplay(height=40, width=160) + mock_display.colors_supported = True + collector = LiveStatsCollector(1000, display=mock_display) + + colors = collector._setup_colors() + + self.assertIn("header", colors) + self.assertIn("cyan", colors) + self.assertIn("yellow", colors) + self.assertIn("green", colors) + self.assertIn("magenta", colors) + self.assertIn("red", colors) + + def test_setup_colors_without_color_support(self): + """Test color setup when colors are not supported.""" + mock_display = MockDisplay(height=40, width=160) + mock_display.colors_supported = False + collector = LiveStatsCollector(1000, display=mock_display) + + colors = collector._setup_colors() + + # Should still have all keys but with fallback values + self.assertIn("header", colors) + self.assertIn("cyan", colors) + + def test_handle_input_quit(self): + """Test handling 'q' key to quit.""" + mock_display = MockDisplay() + mock_display.simulate_input(ord("q")) + collector = LiveStatsCollector(1000, display=mock_display) + + self.assertTrue(collector.running) + collector._handle_input() + self.assertFalse(collector.running) + + def test_handle_input_quit_uppercase(self): + """Test handling 'Q' key to quit.""" + mock_display = MockDisplay() + mock_display.simulate_input(ord("Q")) + collector = LiveStatsCollector(1000, display=mock_display) + + self.assertTrue(collector.running) + collector._handle_input() + self.assertFalse(collector.running) + + def test_handle_input_cycle_sort(self): + """Test handling 's' key to cycle sort.""" + mock_display = MockDisplay() + mock_display.simulate_input(ord("s")) + collector = LiveStatsCollector( + 1000, sort_by="nsamples", display=mock_display + ) + + collector._handle_input() + self.assertEqual(collector.sort_by, "sample_pct") + + def test_handle_input_cycle_sort_uppercase(self): + """Test handling 'S' key to cycle sort backward.""" + mock_display = MockDisplay() + mock_display.simulate_input(ord("S")) + collector = LiveStatsCollector( + 1000, sort_by="nsamples", display=mock_display + ) + + collector._handle_input() + self.assertEqual(collector.sort_by, "cumtime") + + def test_handle_input_no_key(self): + """Test handling when no key is pressed.""" + mock_display = MockDisplay() + collector = LiveStatsCollector(1000, display=mock_display) + + collector._handle_input() + # Should not change state + self.assertTrue(collector.running) + + +class TestLiveStatsCollectorDisplayMethods(unittest.TestCase): + """Tests for display-related methods.""" + + def setUp(self): + """Set up collector with mock display.""" + self.mock_display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.mock_display + ) + self.collector.start_time = time.perf_counter() + + def test_show_terminal_too_small(self): + """Test terminal too small message display.""" + self.collector._show_terminal_too_small(10, 50) + # Should have written some content to the display buffer + self.assertGreater(len(self.mock_display.buffer), 0) + + def test_draw_header_info(self): + """Test drawing header information.""" + colors = { + "cyan": curses.A_BOLD, + "green": curses.A_BOLD, + "yellow": curses.A_BOLD, + "magenta": curses.A_BOLD, + } + self.collector._initialize_widgets(colors) + + line = self.collector.header_widget.draw_header_info(0, 160, 100.5) + self.assertEqual(line, 2) # Title + header info line + + def test_draw_sample_stats(self): + """Test drawing sample statistics.""" + self.collector.total_samples = 1000 + colors = {"cyan": curses.A_BOLD, "green": curses.A_BOLD} + self.collector._initialize_widgets(colors) + + line = self.collector.header_widget.draw_sample_stats(0, 160, 10.0) + self.assertEqual(line, 1) + self.assertGreater(self.collector.max_sample_rate, 0) + + def test_progress_bar_uses_target_rate(self): + """Test that progress bar uses target rate instead of max rate.""" + # Set up collector with specific sampling interval + collector = LiveStatsCollector( + 10000, pid=12345, display=self.mock_display + ) # 10ms = 100Hz target + collector.start_time = time.perf_counter() + collector.total_samples = 500 + collector.max_sample_rate = ( + 150 # Higher than target to test we don't use this + ) + + colors = {"cyan": curses.A_BOLD, "green": curses.A_BOLD} + collector._initialize_widgets(colors) + + # Clear the display buffer to capture only our progress bar content + self.mock_display.buffer.clear() + + # Draw sample stats with a known elapsed time that gives us a specific sample rate + elapsed = 10.0 # 500 samples in 10 seconds = 50 samples/second + line = collector.header_widget.draw_sample_stats(0, 160, elapsed) + + # Verify display was updated + self.assertEqual(line, 1) + self.assertGreater(len(self.mock_display.buffer), 0) + + # Verify the label shows current/target format with units instead of "max" + found_current_target_label = False + found_max_label = False + for (line_num, col), (text, attr) in self.mock_display.buffer.items(): + # Should show "50.0Hz/100.0Hz (50.0%)" since we're at 50% of target (50/100) + if "50.0Hz/100.0Hz" in text and "50.0%" in text: + found_current_target_label = True + if "max:" in text: + found_max_label = True + + self.assertTrue( + found_current_target_label, + "Should display current/target rate with percentage", + ) + self.assertFalse(found_max_label, "Should not display max rate label") + + def test_progress_bar_different_intervals(self): + """Test that progress bar adapts to different sampling intervals.""" + test_cases = [ + ( + 1000, + "1.0KHz", + "100.0Hz", + ), # 1ms interval -> 1000Hz target (1.0KHz), 100Hz current + ( + 5000, + "200.0Hz", + "100.0Hz", + ), # 5ms interval -> 200Hz target, 100Hz current + ( + 20000, + "50.0Hz", + "100.0Hz", + ), # 20ms interval -> 50Hz target, 100Hz current + ( + 100000, + "10.0Hz", + "100.0Hz", + ), # 100ms interval -> 10Hz target, 100Hz current + ] + + for ( + interval_usec, + expected_target_formatted, + expected_current_formatted, + ) in test_cases: + with self.subTest(interval=interval_usec): + collector = LiveStatsCollector( + interval_usec, display=MockDisplay() + ) + collector.start_time = time.perf_counter() + collector.total_samples = 100 + + colors = {"cyan": curses.A_BOLD, "green": curses.A_BOLD} + collector._initialize_widgets(colors) + + # Clear buffer + collector.display.buffer.clear() + + # Draw with 1 second elapsed time (gives us current rate of 100Hz) + collector.header_widget.draw_sample_stats(0, 160, 1.0) + + # Check that the current/target format appears in the display with proper units + found_current_target_format = False + for (line_num, col), ( + text, + attr, + ) in collector.display.buffer.items(): + # Looking for format like "100.0Hz/1.0KHz" or "100.0Hz/200.0Hz" + expected_format = f"{expected_current_formatted}/{expected_target_formatted}" + if expected_format in text and "%" in text: + found_current_target_format = True + break + + self.assertTrue( + found_current_target_format, + f"Should display current/target rate format with units for {interval_usec}µs interval", + ) + + def test_draw_efficiency_bar(self): + """Test drawing efficiency bar.""" + self.collector.successful_samples = 900 + self.collector.failed_samples = 100 + self.collector.total_samples = 1000 + colors = {"green": curses.A_BOLD, "red": curses.A_BOLD} + self.collector._initialize_widgets(colors) + + line = self.collector.header_widget.draw_efficiency_bar(0, 160) + self.assertEqual(line, 1) + + def test_draw_function_stats(self): + """Test drawing function statistics.""" + self.collector.result[("test.py", 10, "func1")] = { + "direct_calls": 100, + "cumulative_calls": 150, + "total_rec_calls": 0, + } + self.collector.result[("test.py", 20, "func2")] = { + "direct_calls": 0, + "cumulative_calls": 50, + "total_rec_calls": 0, + } + + stats_list = self.collector.build_stats_list() + colors = { + "cyan": curses.A_BOLD, + "green": curses.A_BOLD, + "yellow": curses.A_BOLD, + "magenta": curses.A_BOLD, + } + self.collector._initialize_widgets(colors) + + line = self.collector.header_widget.draw_function_stats( + 0, 160, stats_list + ) + self.assertEqual(line, 1) + + def test_draw_top_functions(self): + """Test drawing top functions.""" + self.collector.total_samples = 300 + self.collector.result[("test.py", 10, "hot_func")] = { + "direct_calls": 100, + "cumulative_calls": 150, + "total_rec_calls": 0, + } + + stats_list = self.collector.build_stats_list() + colors = { + "red": curses.A_BOLD, + "yellow": curses.A_BOLD, + "green": curses.A_BOLD, + } + self.collector._initialize_widgets(colors) + + line = self.collector.header_widget.draw_top_functions( + 0, 160, stats_list + ) + self.assertEqual(line, 1) + + def test_draw_column_headers(self): + """Test drawing column headers.""" + colors = { + "sorted_header": curses.A_BOLD, + "normal_header": curses.A_NORMAL, + } + self.collector._initialize_widgets(colors) + + ( + line, + show_sample_pct, + show_tottime, + show_cumul_pct, + show_cumtime, + ) = self.collector.table_widget.draw_column_headers(0, 160) + self.assertEqual(line, 1) + self.assertTrue(show_sample_pct) + self.assertTrue(show_tottime) + self.assertTrue(show_cumul_pct) + self.assertTrue(show_cumtime) + + def test_draw_column_headers_narrow_terminal(self): + """Test column headers adapt to narrow terminal.""" + colors = { + "sorted_header": curses.A_BOLD, + "normal_header": curses.A_NORMAL, + } + self.collector._initialize_widgets(colors) + + ( + line, + show_sample_pct, + show_tottime, + show_cumul_pct, + show_cumtime, + ) = self.collector.table_widget.draw_column_headers(0, 70) + self.assertEqual(line, 1) + # Some columns should be hidden on narrow terminal + self.assertFalse(show_cumul_pct) + + def test_draw_footer(self): + """Test drawing footer.""" + colors = self.collector._setup_colors() + self.collector._initialize_widgets(colors) + self.collector.footer_widget.render(38, 160) + # Should have written some content to the display buffer + self.assertGreater(len(self.mock_display.buffer), 0) + + def test_draw_progress_bar(self): + """Test progress bar drawing.""" + colors = self.collector._setup_colors() + self.collector._initialize_widgets(colors) + bar, length = self.collector.header_widget.progress_bar.render_bar( + 50, 100, 30 + ) + + self.assertIn("[", bar) + self.assertIn("]", bar) + self.assertGreater(length, 0) + # Should be roughly 50% filled + self.assertIn("█", bar) + self.assertIn("░", bar) + + +class TestLiveStatsCollectorEdgeCases(unittest.TestCase): + """Tests for edge cases and error handling.""" + + def test_very_long_function_name(self): + """Test handling of very long function names.""" + collector = LiveStatsCollector(1000) + long_name = "x" * 200 + collector.result[("test.py", 10, long_name)] = { + "direct_calls": 10, + "cumulative_calls": 20, + "total_rec_calls": 0, + } + + stats_list = collector.build_stats_list() + self.assertEqual(len(stats_list), 1) + self.assertEqual(stats_list[0]["func"][2], long_name) + + +class TestLiveStatsCollectorUpdateDisplay(unittest.TestCase): + """Tests for the _update_display method.""" + + def setUp(self): + """Set up collector with mock display.""" + self.mock_display = MockDisplay(height=40, width=160) + self.collector = LiveStatsCollector( + 1000, pid=12345, display=self.mock_display + ) + self.collector.start_time = time.perf_counter() + + def test_update_display_terminal_too_small(self): + """Test update_display when terminal is too small.""" + small_display = MockDisplay(height=10, width=50) + self.collector.display = small_display + + with mock.patch.object( + self.collector, "_show_terminal_too_small" + ) as mock_show: + self.collector._update_display() + mock_show.assert_called_once() + + def test_update_display_normal(self): + """Test normal update_display operation.""" + self.collector.total_samples = 100 + self.collector.successful_samples = 90 + self.collector.failed_samples = 10 + self.collector.result[("test.py", 10, "func")] = { + "direct_calls": 50, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + + self.collector._update_display() + + self.assertTrue(self.mock_display.cleared) + self.assertTrue(self.mock_display.refreshed) + + def test_update_display_handles_exception(self): + """Test that update_display handles exceptions gracefully.""" + # Make one of the methods raise an exception + with mock.patch.object( + self.collector, + "_prepare_display_data", + side_effect=Exception("Test error"), + ): + # Should not raise an exception (it catches and logs via trace_exception) + try: + self.collector._update_display() + except Exception: + self.fail( + "_update_display should handle exceptions gracefully" + ) + + +class TestLiveCollectorWithMockDisplayHelpers(unittest.TestCase): + """Tests using the new MockDisplay helper methods.""" + + def test_verify_pid_display_with_contains(self): + """Test verifying PID is displayed using contains_text helper.""" + display = MockDisplay(height=40, width=160) + collector = LiveStatsCollector(1000, pid=99999, display=display) + collector.start_time = time.perf_counter() + collector.total_samples = 10 + + collector._update_display() + + # Use the helper method + self.assertTrue( + display.contains_text("99999"), "PID should be visible in display" + ) + + def test_verify_function_names_displayed(self): + """Test verifying function names appear in display.""" + display = MockDisplay(height=40, width=160) + collector = LiveStatsCollector(1000, pid=12345, display=display) + collector.start_time = time.perf_counter() + + collector.total_samples = 100 + collector.result[("mymodule.py", 42, "my_special_function")] = { + "direct_calls": 50, + "cumulative_calls": 75, + "total_rec_calls": 0, + } + + collector._update_display() + + # Verify function name appears + self.assertTrue( + display.contains_text("my_special_function"), + "Function name should be visible", + ) + + def test_get_all_lines_full_display(self): + """Test getting all lines from a full display render.""" + display = MockDisplay(height=40, width=160) + collector = LiveStatsCollector(1000, pid=12345, display=display) + collector.start_time = time.perf_counter() + collector.total_samples = 100 + + collector._update_display() + + lines = display.get_all_lines() + + # Should have multiple lines of content + self.assertGreater(len(lines), 5) + + # Should have header content + self.assertTrue(any("PID" in line for line in lines)) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_modes.py b/Lib/test/test_profiling/test_sampling_profiler/test_modes.py new file mode 100644 index 00000000000..247416389da --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_modes.py @@ -0,0 +1,598 @@ +"""Tests for sampling profiler mode filtering (CPU and GIL modes).""" + +import io +import unittest +from unittest import mock + +try: + import _remote_debugging # noqa: F401 + import profiling.sampling + import profiling.sampling.sample + from profiling.sampling.pstats_collector import PstatsCollector +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from test.support import requires_remote_subprocess_debugging + +from .helpers import test_subprocess +from .mocks import MockFrameInfo, MockInterpreterInfo + + +@requires_remote_subprocess_debugging() +class TestCpuModeFiltering(unittest.TestCase): + """Test CPU mode filtering functionality (--mode=cpu).""" + + def test_mode_validation(self): + """Test that CLI validates mode choices correctly.""" + # Invalid mode choice should raise SystemExit + test_args = [ + "profiling.sampling.cli", + "attach", + "12345", + "--mode", + "invalid", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("sys.stderr", io.StringIO()) as mock_stderr, + self.assertRaises(SystemExit) as cm, + ): + from profiling.sampling.cli import main + main() + + self.assertEqual(cm.exception.code, 2) # argparse error + error_msg = mock_stderr.getvalue() + self.assertIn("invalid choice", error_msg) + + def test_frames_filtered_with_skip_idle(self): + """Test that frames are actually filtered when skip_idle=True.""" + # Import thread status flags + try: + from _remote_debugging import ( + THREAD_STATUS_HAS_GIL, + THREAD_STATUS_ON_CPU, + ) + except ImportError: + THREAD_STATUS_HAS_GIL = 1 << 0 + THREAD_STATUS_ON_CPU = 1 << 1 + + # Create mock frames with different thread statuses + class MockThreadInfoWithStatus: + def __init__(self, thread_id, frame_info, status): + self.thread_id = thread_id + self.frame_info = frame_info + self.status = status + + # Create test data: active thread (HAS_GIL | ON_CPU), idle thread (neither), and another active thread + ACTIVE_STATUS = ( + THREAD_STATUS_HAS_GIL | THREAD_STATUS_ON_CPU + ) # Has GIL and on CPU + IDLE_STATUS = 0 # Neither has GIL nor on CPU + + test_frames = [ + MockInterpreterInfo( + 0, + [ + MockThreadInfoWithStatus( + 1, + [MockFrameInfo("active1.py", 10, "active_func1")], + ACTIVE_STATUS, + ), + MockThreadInfoWithStatus( + 2, + [MockFrameInfo("idle.py", 20, "idle_func")], + IDLE_STATUS, + ), + MockThreadInfoWithStatus( + 3, + [MockFrameInfo("active2.py", 30, "active_func2")], + ACTIVE_STATUS, + ), + ], + ) + ] + + # Test with skip_idle=True - should only process running threads + collector_skip = PstatsCollector( + sample_interval_usec=1000, skip_idle=True + ) + collector_skip.collect(test_frames) + + # Should only have functions from running threads (status 0) + active1_key = ("active1.py", 10, "active_func1") + active2_key = ("active2.py", 30, "active_func2") + idle_key = ("idle.py", 20, "idle_func") + + self.assertIn(active1_key, collector_skip.result) + self.assertIn(active2_key, collector_skip.result) + self.assertNotIn( + idle_key, collector_skip.result + ) # Idle thread should be filtered out + + # Test with skip_idle=False - should process all threads + collector_no_skip = PstatsCollector( + sample_interval_usec=1000, skip_idle=False + ) + collector_no_skip.collect(test_frames) + + # Should have functions from all threads + self.assertIn(active1_key, collector_no_skip.result) + self.assertIn(active2_key, collector_no_skip.result) + self.assertIn( + idle_key, collector_no_skip.result + ) # Idle thread should be included + + def test_cpu_mode_integration_filtering(self): + """Integration test: CPU mode should only capture active threads, not idle ones.""" + # Script with one mostly-idle thread and one CPU-active thread + cpu_vs_idle_script = """ +import time +import threading + +cpu_ready = threading.Event() + +def idle_worker(): + time.sleep(999999) + +def cpu_active_worker(): + cpu_ready.set() + x = 1 + while True: + x += 1 + +idle_thread = threading.Thread(target=idle_worker) +cpu_thread = threading.Thread(target=cpu_active_worker) +idle_thread.start() +cpu_thread.start() +cpu_ready.wait() +_test_sock.sendall(b"working") +idle_thread.join() +cpu_thread.join() +""" + with test_subprocess(cpu_vs_idle_script, wait_for_working=True) as subproc: + + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=True) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2.0, + mode=1, # CPU mode + all_threads=True, + ) + collector.print_stats(show_summary=False, mode=1) + + cpu_mode_output = captured_output.getvalue() + + # Test wall-clock mode (mode=0) - should capture both functions + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2.0, + mode=0, # Wall-clock mode + all_threads=True, + ) + collector.print_stats(show_summary=False) + + wall_mode_output = captured_output.getvalue() + + # Verify both modes captured samples + self.assertIn("Captured", cpu_mode_output) + self.assertIn("samples", cpu_mode_output) + self.assertIn("Captured", wall_mode_output) + self.assertIn("samples", wall_mode_output) + + # CPU mode should strongly favor cpu_active_worker over mostly_idle_worker + self.assertIn("cpu_active_worker", cpu_mode_output) + self.assertNotIn("idle_worker", cpu_mode_output) + + # Wall-clock mode should capture both types of work + self.assertIn("cpu_active_worker", wall_mode_output) + self.assertIn("idle_worker", wall_mode_output) + + def test_cpu_mode_with_no_samples(self): + """Test that CPU mode handles no samples gracefully when no samples are collected.""" + # Mock a collector that returns empty stats + mock_collector = PstatsCollector(sample_interval_usec=5000, skip_idle=True) + mock_collector.stats = {} + + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + mock.patch( + "profiling.sampling.sample.SampleProfiler" + ) as mock_profiler_class, + ): + mock_profiler = mock.MagicMock() + mock_profiler_class.return_value = mock_profiler + + profiling.sampling.sample.sample( + 12345, # dummy PID + mock_collector, + duration_sec=0.5, + mode=1, # CPU mode + all_threads=True, + ) + + mock_collector.print_stats(show_summary=False, mode=1) + + output = captured_output.getvalue() + + # Should see the "No samples were collected" message + self.assertIn("No samples were collected", output) + self.assertIn("CPU mode", output) + + +@requires_remote_subprocess_debugging() +class TestGilModeFiltering(unittest.TestCase): + """Test GIL mode filtering functionality (--mode=gil).""" + + def test_gil_mode_validation(self): + """Test that CLI accepts gil mode choice correctly.""" + from profiling.sampling.cli import main + + test_args = [ + "profiling.sampling.cli", + "attach", + "12345", + "--mode", + "gil", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + try: + main() + except (SystemExit, OSError, RuntimeError): + pass # Expected due to invalid PID + + # Should have attempted to call sample with mode=2 (GIL mode) + mock_sample.assert_called_once() + call_args = mock_sample.call_args + # Check the mode parameter (should be in kwargs) + self.assertEqual(call_args.kwargs.get("mode"), 2) # PROFILING_MODE_GIL + + def test_gil_mode_sample_function_call(self): + """Test that sample() function correctly uses GIL mode.""" + with ( + mock.patch( + "profiling.sampling.sample.SampleProfiler" + ) as mock_profiler, + ): + # Mock the profiler instance + mock_instance = mock.Mock() + mock_profiler.return_value = mock_instance + + # Create a real collector instance + collector = PstatsCollector(sample_interval_usec=1000, skip_idle=True) + + # Call sample with GIL mode + profiling.sampling.sample.sample( + 12345, + collector, + mode=2, # PROFILING_MODE_GIL + duration_sec=1, + ) + + # Verify SampleProfiler was created with correct mode + mock_profiler.assert_called_once() + call_args = mock_profiler.call_args + self.assertEqual(call_args[1]["mode"], 2) # mode parameter + + # Verify profiler.sample was called + mock_instance.sample.assert_called_once() + + def test_gil_mode_cli_argument_parsing(self): + """Test CLI argument parsing for GIL mode with various options.""" + from profiling.sampling.cli import main + + test_args = [ + "profiling.sampling.cli", + "attach", + "12345", + "--mode", + "gil", + "-i", + "500", + "-d", + "5", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + try: + main() + except (SystemExit, OSError, RuntimeError): + pass # Expected due to invalid PID + + # Verify all arguments were parsed correctly + mock_sample.assert_called_once() + call_args = mock_sample.call_args + self.assertEqual(call_args.kwargs.get("mode"), 2) # GIL mode + self.assertEqual(call_args.kwargs.get("duration_sec"), 5) + + def test_gil_mode_integration_behavior(self): + """Integration test: GIL mode should capture GIL-holding threads.""" + # Create a test script with GIL-releasing operations + gil_test_script = """ +import time +import threading + +gil_ready = threading.Event() + +def gil_releasing_work(): + time.sleep(999999) + +def gil_holding_work(): + gil_ready.set() + x = 1 + while True: + x += 1 + +idle_thread = threading.Thread(target=gil_releasing_work) +cpu_thread = threading.Thread(target=gil_holding_work) +idle_thread.start() +cpu_thread.start() +gil_ready.wait() +_test_sock.sendall(b"working") +idle_thread.join() +cpu_thread.join() +""" + with test_subprocess(gil_test_script, wait_for_working=True) as subproc: + + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=True) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2.0, + mode=2, # GIL mode + all_threads=True, + ) + collector.print_stats(show_summary=False) + + gil_mode_output = captured_output.getvalue() + + # Test wall-clock mode for comparison + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=0.5, + mode=0, # Wall-clock mode + all_threads=True, + ) + collector.print_stats(show_summary=False) + + wall_mode_output = captured_output.getvalue() + + # GIL mode should primarily capture GIL-holding work + # (Note: actual behavior depends on threading implementation) + self.assertIn("gil_holding_work", gil_mode_output) + + # Wall-clock mode should capture both types of work + self.assertIn("gil_holding_work", wall_mode_output) + + def test_mode_constants_are_defined(self): + """Test that all profiling mode constants are properly defined.""" + self.assertEqual(profiling.sampling.sample.PROFILING_MODE_WALL, 0) + self.assertEqual(profiling.sampling.sample.PROFILING_MODE_CPU, 1) + self.assertEqual(profiling.sampling.sample.PROFILING_MODE_GIL, 2) + + def test_parse_mode_function(self): + """Test the _parse_mode function with all valid modes.""" + from profiling.sampling.cli import _parse_mode + self.assertEqual(_parse_mode("wall"), 0) + self.assertEqual(_parse_mode("cpu"), 1) + self.assertEqual(_parse_mode("gil"), 2) + self.assertEqual(_parse_mode("exception"), 4) + + # Test invalid mode raises KeyError + with self.assertRaises(KeyError): + _parse_mode("invalid") + + +@requires_remote_subprocess_debugging() +class TestExceptionModeFiltering(unittest.TestCase): + """Test exception mode filtering functionality (--mode=exception).""" + + def test_exception_mode_validation(self): + """Test that CLI accepts exception mode choice correctly.""" + from profiling.sampling.cli import main + + test_args = [ + "profiling.sampling.cli", + "attach", + "12345", + "--mode", + "exception", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + try: + main() + except (SystemExit, OSError, RuntimeError): + pass # Expected due to invalid PID + + # Should have attempted to call sample with mode=4 (exception mode) + mock_sample.assert_called_once() + call_args = mock_sample.call_args + # Check the mode parameter (should be in kwargs) + self.assertEqual(call_args.kwargs.get("mode"), 4) # PROFILING_MODE_EXCEPTION + + def test_exception_mode_sample_function_call(self): + """Test that sample() function correctly uses exception mode.""" + with ( + mock.patch( + "profiling.sampling.sample.SampleProfiler" + ) as mock_profiler, + ): + # Mock the profiler instance + mock_instance = mock.Mock() + mock_profiler.return_value = mock_instance + + # Create a real collector instance + collector = PstatsCollector(sample_interval_usec=1000, skip_idle=True) + + # Call sample with exception mode + profiling.sampling.sample.sample( + 12345, + collector, + mode=4, # PROFILING_MODE_EXCEPTION + duration_sec=1, + ) + + # Verify SampleProfiler was created with correct mode + mock_profiler.assert_called_once() + call_args = mock_profiler.call_args + self.assertEqual(call_args[1]["mode"], 4) # mode parameter + + # Verify profiler.sample was called + mock_instance.sample.assert_called_once() + + def test_exception_mode_cli_argument_parsing(self): + """Test CLI argument parsing for exception mode with various options.""" + from profiling.sampling.cli import main + + test_args = [ + "profiling.sampling.cli", + "attach", + "12345", + "--mode", + "exception", + "-i", + "500", + "-d", + "5", + ] + + with ( + mock.patch("sys.argv", test_args), + mock.patch("profiling.sampling.cli._is_process_running", return_value=True), + mock.patch("profiling.sampling.cli.sample") as mock_sample, + ): + try: + main() + except (SystemExit, OSError, RuntimeError): + pass # Expected due to invalid PID + + # Verify all arguments were parsed correctly + mock_sample.assert_called_once() + call_args = mock_sample.call_args + self.assertEqual(call_args.kwargs.get("mode"), 4) # exception mode + self.assertEqual(call_args.kwargs.get("duration_sec"), 5) + + def test_exception_mode_constants_are_defined(self): + """Test that exception mode constant is properly defined.""" + from profiling.sampling.constants import PROFILING_MODE_EXCEPTION + self.assertEqual(PROFILING_MODE_EXCEPTION, 4) + + def test_exception_mode_integration_filtering(self): + """Integration test: Exception mode should only capture threads with active exceptions.""" + # Script with one thread handling an exception and one normal thread + exception_vs_normal_script = """ +import time +import threading + +exception_ready = threading.Event() + +def normal_worker(): + x = 0 + while True: + x += 1 + +def exception_handling_worker(): + try: + raise ValueError("test exception") + except ValueError: + # Signal AFTER entering except block, then do CPU work + exception_ready.set() + x = 0 + while True: + x += 1 + +normal_thread = threading.Thread(target=normal_worker) +exception_thread = threading.Thread(target=exception_handling_worker) +normal_thread.start() +exception_thread.start() +exception_ready.wait() +_test_sock.sendall(b"working") +normal_thread.join() +exception_thread.join() +""" + with test_subprocess(exception_vs_normal_script, wait_for_working=True) as subproc: + + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=True) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2.0, + mode=4, # Exception mode + all_threads=True, + ) + collector.print_stats(show_summary=False, mode=4) + + exception_mode_output = captured_output.getvalue() + + # Test wall-clock mode (mode=0) - should capture both functions + with ( + io.StringIO() as captured_output, + mock.patch("sys.stdout", captured_output), + ): + collector = PstatsCollector(sample_interval_usec=5000, skip_idle=False) + profiling.sampling.sample.sample( + subproc.process.pid, + collector, + duration_sec=2.0, + mode=0, # Wall-clock mode + all_threads=True, + ) + collector.print_stats(show_summary=False) + + wall_mode_output = captured_output.getvalue() + + # Verify both modes captured samples + self.assertIn("Captured", exception_mode_output) + self.assertIn("samples", exception_mode_output) + self.assertIn("Captured", wall_mode_output) + self.assertIn("samples", wall_mode_output) + + # Exception mode should strongly favor exception_handling_worker over normal_worker + self.assertIn("exception_handling_worker", exception_mode_output) + self.assertNotIn("normal_worker", exception_mode_output) + + # Wall-clock mode should capture both types of work + self.assertIn("exception_handling_worker", wall_mode_output) + self.assertIn("normal_worker", wall_mode_output) diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py b/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py new file mode 100644 index 00000000000..822f559561e --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_profiler.py @@ -0,0 +1,714 @@ +"""Tests for sampling profiler core functionality.""" + +import io +from unittest import mock +import unittest + +try: + import _remote_debugging # noqa: F401 + from profiling.sampling.sample import SampleProfiler + from profiling.sampling.pstats_collector import PstatsCollector +except ImportError: + raise unittest.SkipTest( + "Test only runs when _remote_debugging is available" + ) + +from test.support import force_not_colorized_test_class + + +def print_sampled_stats(stats, sort=-1, limit=None, show_summary=True, sample_interval_usec=100): + """Helper function to maintain compatibility with old test API. + + This wraps the new PstatsCollector.print_stats() API to work with the + existing test infrastructure. + """ + # Create a mock collector that populates stats correctly + collector = PstatsCollector(sample_interval_usec=sample_interval_usec) + + # Override create_stats to populate self.stats with the provided stats + def mock_create_stats(): + collector.stats = stats.stats + collector.create_stats = mock_create_stats + + # Call the new print_stats method + collector.print_stats(sort=sort, limit=limit, show_summary=show_summary) + + +class TestSampleProfiler(unittest.TestCase): + """Test the SampleProfiler class.""" + + def test_sample_profiler_initialization(self): + """Test SampleProfiler initialization with various parameters.""" + + # Mock RemoteUnwinder to avoid permission issues + with mock.patch( + "_remote_debugging.RemoteUnwinder" + ) as mock_unwinder_class: + mock_unwinder_class.return_value = mock.MagicMock() + + # Test basic initialization + profiler = SampleProfiler( + pid=12345, sample_interval_usec=1000, all_threads=False + ) + self.assertEqual(profiler.pid, 12345) + self.assertEqual(profiler.sample_interval_usec, 1000) + self.assertEqual(profiler.all_threads, False) + + # Test with all_threads=True + profiler = SampleProfiler( + pid=54321, sample_interval_usec=5000, all_threads=True + ) + self.assertEqual(profiler.pid, 54321) + self.assertEqual(profiler.sample_interval_usec, 5000) + self.assertEqual(profiler.all_threads, True) + + def test_sample_profiler_sample_method_timing(self): + """Test that the sample method respects duration and handles timing correctly.""" + + # Mock the unwinder to avoid needing a real process + mock_unwinder = mock.MagicMock() + mock_unwinder.get_stack_trace.return_value = [ + ( + 1, + [ + mock.MagicMock( + filename="test.py", lineno=10, funcname="test_func" + ) + ], + ) + ] + + with mock.patch( + "_remote_debugging.RemoteUnwinder" + ) as mock_unwinder_class: + mock_unwinder_class.return_value = mock_unwinder + + profiler = SampleProfiler( + pid=12345, sample_interval_usec=100000, all_threads=False + ) # 100ms interval + + # Mock collector + mock_collector = mock.MagicMock() + + # Mock time to control the sampling loop + start_time = 1000.0 + times = [ + start_time + i * 0.1 for i in range(12) + ] # 0, 0.1, 0.2, ..., 1.1 seconds + + with mock.patch("time.perf_counter", side_effect=times): + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + profiler.sample(mock_collector, duration_sec=1) + + result = output.getvalue() + + # Should have captured approximately 10 samples (1 second / 0.1 second interval) + self.assertIn("Captured", result) + self.assertIn("samples", result) + + # Verify collector was called multiple times + self.assertGreaterEqual(mock_collector.collect.call_count, 5) + self.assertLessEqual(mock_collector.collect.call_count, 11) + + def test_sample_profiler_error_handling(self): + """Test that the sample method handles errors gracefully.""" + + # Mock unwinder that raises errors + mock_unwinder = mock.MagicMock() + error_sequence = [ + RuntimeError("Process died"), + [ + ( + 1, + [ + mock.MagicMock( + filename="test.py", lineno=10, funcname="test_func" + ) + ], + ) + ], + UnicodeDecodeError("utf-8", b"", 0, 1, "invalid"), + [ + ( + 1, + [ + mock.MagicMock( + filename="test.py", + lineno=20, + funcname="test_func2", + ) + ], + ) + ], + OSError("Permission denied"), + ] + mock_unwinder.get_stack_trace.side_effect = error_sequence + + with mock.patch( + "_remote_debugging.RemoteUnwinder" + ) as mock_unwinder_class: + mock_unwinder_class.return_value = mock_unwinder + + profiler = SampleProfiler( + pid=12345, sample_interval_usec=10000, all_threads=False + ) + + mock_collector = mock.MagicMock() + + # Control timing to run exactly 5 samples + times = [0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06] + + with mock.patch("time.perf_counter", side_effect=times): + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + profiler.sample(mock_collector, duration_sec=0.05) + + result = output.getvalue() + + # Should report error rate + self.assertIn("Error rate:", result) + self.assertIn("%", result) + + # Collector should have been called only for successful samples (should be > 0) + self.assertGreater(mock_collector.collect.call_count, 0) + self.assertLessEqual(mock_collector.collect.call_count, 3) + + def test_sample_profiler_missed_samples_warning(self): + """Test that the profiler warns about missed samples when sampling is too slow.""" + + mock_unwinder = mock.MagicMock() + mock_unwinder.get_stack_trace.return_value = [ + ( + 1, + [ + mock.MagicMock( + filename="test.py", lineno=10, funcname="test_func" + ) + ], + ) + ] + + with mock.patch( + "_remote_debugging.RemoteUnwinder" + ) as mock_unwinder_class: + mock_unwinder_class.return_value = mock_unwinder + + # Use very short interval that we'll miss + profiler = SampleProfiler( + pid=12345, sample_interval_usec=1000, all_threads=False + ) # 1ms interval + + mock_collector = mock.MagicMock() + + # Simulate slow sampling where we miss many samples + times = [ + 0.0, + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + ] # Extra time points to avoid StopIteration + + with mock.patch("time.perf_counter", side_effect=times): + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + profiler.sample(mock_collector, duration_sec=0.5) + + result = output.getvalue() + + # Should warn about missed samples + self.assertIn("Warning: missed", result) + self.assertIn("samples from the expected total", result) + + def test_sample_profiler_keyboard_interrupt(self): + mock_unwinder = mock.MagicMock() + mock_unwinder.get_stack_trace.side_effect = [ + [ + ( + 1, + [ + mock.MagicMock( + filename="test.py", lineno=10, funcname="test_func" + ) + ], + ) + ], + KeyboardInterrupt(), + ] + + with mock.patch( + "_remote_debugging.RemoteUnwinder" + ) as mock_unwinder_class: + mock_unwinder_class.return_value = mock_unwinder + profiler = SampleProfiler( + pid=12345, sample_interval_usec=10000, all_threads=False + ) + mock_collector = mock.MagicMock() + times = [0.0, 0.01, 0.02, 0.03, 0.04] + with mock.patch("time.perf_counter", side_effect=times): + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + try: + profiler.sample(mock_collector, duration_sec=1.0) + except KeyboardInterrupt: + self.fail( + "KeyboardInterrupt was not handled by the profiler" + ) + result = output.getvalue() + self.assertIn("Interrupted by user.", result) + self.assertIn("Captured", result) + self.assertIn("samples", result) + self.assertNotIn("Warning: missed", result) + + +@force_not_colorized_test_class +class TestPrintSampledStats(unittest.TestCase): + """Test the print_sampled_stats function.""" + + def setUp(self): + """Set up test data.""" + # Mock stats data + self.mock_stats = mock.MagicMock() + self.mock_stats.stats = { + ("file1.py", 10, "func1"): ( + 100, + 100, + 0.5, + 0.5, + {}, + ), # cc, nc, tt, ct, callers + ("file2.py", 20, "func2"): (50, 50, 0.25, 0.3, {}), + ("file3.py", 30, "func3"): (200, 200, 1.5, 2.0, {}), + ("file4.py", 40, "func4"): ( + 10, + 10, + 0.001, + 0.001, + {}, + ), # millisecond range + ("file5.py", 50, "func5"): ( + 5, + 5, + 0.000001, + 0.000002, + {}, + ), # microsecond range + } + + def test_print_sampled_stats_basic(self): + """Test basic print_sampled_stats functionality.""" + + # Capture output + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats(self.mock_stats, sample_interval_usec=100) + + result = output.getvalue() + + # Check header is present + self.assertIn("Profile Stats:", result) + self.assertIn("nsamples", result) + self.assertIn("tottime", result) + self.assertIn("cumtime", result) + + # Check functions are present + self.assertIn("func1", result) + self.assertIn("func2", result) + self.assertIn("func3", result) + + def test_print_sampled_stats_sorting(self): + """Test different sorting options.""" + + # Test sort by calls + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, sort=0, sample_interval_usec=100 + ) + + result = output.getvalue() + lines = result.strip().split("\n") + + # Find the data lines (skip header) + data_lines = [l for l in lines if "file" in l and ".py" in l] + # func3 should be first (200 calls) + self.assertIn("func3", data_lines[0]) + + # Test sort by time + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, sort=1, sample_interval_usec=100 + ) + + result = output.getvalue() + lines = result.strip().split("\n") + + data_lines = [l for l in lines if "file" in l and ".py" in l] + # func3 should be first (1.5s time) + self.assertIn("func3", data_lines[0]) + + def test_print_sampled_stats_limit(self): + """Test limiting output rows.""" + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, limit=2, sample_interval_usec=100 + ) + + result = output.getvalue() + + # Count function entries in the main stats section (not in summary) + lines = result.split("\n") + # Find where the main stats section ends (before summary) + main_section_lines = [] + for line in lines: + if "Summary of Interesting Functions:" in line: + break + main_section_lines.append(line) + + # Count function entries only in main section + func_count = sum( + 1 + for line in main_section_lines + if "func" in line and ".py" in line + ) + self.assertEqual(func_count, 2) + + def test_print_sampled_stats_time_units(self): + """Test proper time unit selection.""" + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats(self.mock_stats, sample_interval_usec=100) + + result = output.getvalue() + + # Should use seconds for the header since max time is > 1s + self.assertIn("tottime (s)", result) + self.assertIn("cumtime (s)", result) + + # Test with only microsecond-range times + micro_stats = mock.MagicMock() + micro_stats.stats = { + ("file1.py", 10, "func1"): (100, 100, 0.000005, 0.000010, {}), + } + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats(micro_stats, sample_interval_usec=100) + + result = output.getvalue() + + # Should use microseconds + self.assertIn("tottime (μs)", result) + self.assertIn("cumtime (μs)", result) + + def test_print_sampled_stats_summary(self): + """Test summary section generation.""" + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, + show_summary=True, + sample_interval_usec=100, + ) + + result = output.getvalue() + + # Check summary sections are present + self.assertIn("Summary of Interesting Functions:", result) + self.assertIn( + "Functions with Highest Direct/Cumulative Ratio (Hot Spots):", + result, + ) + self.assertIn( + "Functions with Highest Call Frequency (Indirect Calls):", result + ) + self.assertIn( + "Functions with Highest Call Magnification (Cumulative/Direct):", + result, + ) + + def test_print_sampled_stats_no_summary(self): + """Test disabling summary output.""" + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, + show_summary=False, + sample_interval_usec=100, + ) + + result = output.getvalue() + + # Summary should not be present + self.assertNotIn("Summary of Interesting Functions:", result) + + def test_print_sampled_stats_empty_stats(self): + """Test with empty stats.""" + + empty_stats = mock.MagicMock() + empty_stats.stats = {} + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats(empty_stats, sample_interval_usec=100) + + result = output.getvalue() + + # Should print message about no samples + self.assertIn("No samples were collected.", result) + + def test_print_sampled_stats_sample_percentage_sorting(self): + """Test sample percentage sorting options.""" + + # Add a function with high sample percentage (more direct calls than func3's 200) + self.mock_stats.stats[("expensive.py", 60, "expensive_func")] = ( + 300, # direct calls (higher than func3's 200) + 300, # cumulative calls + 1.0, # total time + 1.0, # cumulative time + {}, + ) + + # Test sort by sample percentage + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, sort=3, sample_interval_usec=100 + ) # sample percentage + + result = output.getvalue() + lines = result.strip().split("\n") + + data_lines = [l for l in lines if ".py" in l and "func" in l] + # expensive_func should be first (highest sample percentage) + self.assertIn("expensive_func", data_lines[0]) + + def test_print_sampled_stats_with_recursive_calls(self): + """Test print_sampled_stats with recursive calls where nc != cc.""" + + # Create stats with recursive calls (nc != cc) + recursive_stats = mock.MagicMock() + recursive_stats.stats = { + # (direct_calls, cumulative_calls, tt, ct, callers) - recursive function + ("recursive.py", 10, "factorial"): ( + 5, # direct_calls + 10, # cumulative_calls (appears more times in stack due to recursion) + 0.5, + 0.6, + {}, + ), + ("normal.py", 20, "normal_func"): ( + 3, # direct_calls + 3, # cumulative_calls (same as direct for non-recursive) + 0.2, + 0.2, + {}, + ), + } + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats(recursive_stats, sample_interval_usec=100) + + result = output.getvalue() + + # Should display recursive calls as "5/10" format + self.assertIn("5/10", result) # nc/cc format for recursive calls + self.assertIn("3", result) # just nc for non-recursive calls + self.assertIn("factorial", result) + self.assertIn("normal_func", result) + + def test_print_sampled_stats_with_zero_call_counts(self): + """Test print_sampled_stats with zero call counts to trigger division protection.""" + + # Create stats with zero call counts + zero_stats = mock.MagicMock() + zero_stats.stats = { + ("file.py", 10, "zero_calls"): (0, 0, 0.0, 0.0, {}), # Zero calls + ("file.py", 20, "normal_func"): ( + 5, + 5, + 0.1, + 0.1, + {}, + ), # Normal function + } + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats(zero_stats, sample_interval_usec=100) + + result = output.getvalue() + + # Should handle zero call counts gracefully + self.assertIn("zero_calls", result) + self.assertIn("zero_calls", result) + self.assertIn("normal_func", result) + + def test_print_sampled_stats_sort_by_name(self): + """Test sort by function name option.""" + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + self.mock_stats, sort=-1, sample_interval_usec=100 + ) # sort by name + + result = output.getvalue() + lines = result.strip().split("\n") + + # Find the data lines (skip header and summary) + # Data lines start with whitespace and numbers, and contain filename:lineno(function) + data_lines = [] + for line in lines: + # Skip header lines and summary sections + if ( + line.startswith(" ") + and "(" in line + and ")" in line + and not line.startswith( + " 1." + ) # Skip summary lines that start with times + and not line.startswith( + " 0." + ) # Skip summary lines that start with times + and not "per call" in line # Skip summary lines + and not "calls" in line # Skip summary lines + and not "total time" in line # Skip summary lines + and not "cumulative time" in line + ): # Skip summary lines + data_lines.append(line) + + # Extract just the function names for comparison + func_names = [] + import re + + for line in data_lines: + # Function name is between the last ( and ), accounting for ANSI color codes + match = re.search(r"\(([^)]+)\)$", line) + if match: + func_name = match.group(1) + # Remove ANSI color codes + func_name = re.sub(r"\x1b\[[0-9;]*m", "", func_name) + func_names.append(func_name) + + # Verify we extracted function names and they are sorted + self.assertGreater( + len(func_names), 0, "Should have extracted some function names" + ) + self.assertEqual( + func_names, + sorted(func_names), + f"Function names {func_names} should be sorted alphabetically", + ) + + def test_print_sampled_stats_with_zero_time_functions(self): + """Test summary sections with functions that have zero time.""" + + # Create stats with zero-time functions + zero_time_stats = mock.MagicMock() + zero_time_stats.stats = { + ("file1.py", 10, "zero_time_func"): ( + 5, + 5, + 0.0, + 0.0, + {}, + ), # Zero time + ("file2.py", 20, "normal_func"): ( + 3, + 3, + 0.1, + 0.1, + {}, + ), # Normal time + } + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + zero_time_stats, + show_summary=True, + sample_interval_usec=100, + ) + + result = output.getvalue() + + # Should handle zero-time functions gracefully in summary + self.assertIn("Summary of Interesting Functions:", result) + self.assertIn("zero_time_func", result) + self.assertIn("normal_func", result) + + def test_print_sampled_stats_with_malformed_qualified_names(self): + """Test summary generation with function names that don't contain colons.""" + + # Create stats with function names that would create malformed qualified names + malformed_stats = mock.MagicMock() + malformed_stats.stats = { + # Function name without clear module separation + ("no_colon_func", 10, "func"): (3, 3, 0.1, 0.1, {}), + ("", 20, "empty_filename_func"): (2, 2, 0.05, 0.05, {}), + ("normal.py", 30, "normal_func"): (5, 5, 0.2, 0.2, {}), + } + + with io.StringIO() as output: + with mock.patch("sys.stdout", output): + print_sampled_stats( + malformed_stats, + show_summary=True, + sample_interval_usec=100, + ) + + result = output.getvalue() + + # Should handle malformed names gracefully in summary aggregation + self.assertIn("Summary of Interesting Functions:", result) + # All function names should appear somewhere in the output + self.assertIn("func", result) + self.assertIn("empty_filename_func", result) + self.assertIn("normal_func", result) + + def test_print_sampled_stats_with_recursive_call_stats_creation(self): + """Test create_stats with recursive call data to trigger total_rec_calls branch.""" + collector = PstatsCollector(sample_interval_usec=1000000) # 1 second + + # Simulate recursive function data where total_rec_calls would be set + # We need to manually manipulate the collector result to test this branch + collector.result = { + ("recursive.py", 10, "factorial"): { + "total_rec_calls": 3, # Non-zero recursive calls + "direct_calls": 5, + "cumulative_calls": 10, + }, + ("normal.py", 20, "normal_func"): { + "total_rec_calls": 0, # Zero recursive calls + "direct_calls": 2, + "cumulative_calls": 5, + }, + } + + collector.create_stats() + + # Check that recursive calls are handled differently from non-recursive + factorial_stats = collector.stats[("recursive.py", 10, "factorial")] + normal_stats = collector.stats[("normal.py", 20, "normal_func")] + + # factorial should use cumulative_calls (10) as nc + self.assertEqual( + factorial_stats[1], 10 + ) # nc should be cumulative_calls + self.assertEqual(factorial_stats[0], 5) # cc should be direct_calls + + # normal_func should use cumulative_calls as nc + self.assertEqual(normal_stats[1], 5) # nc should be cumulative_calls + self.assertEqual(normal_stats[0], 2) # cc should be direct_calls diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_trend_tracker.py b/Lib/test/test_profiling/test_sampling_profiler/test_trend_tracker.py new file mode 100644 index 00000000000..43b23be0fe3 --- /dev/null +++ b/Lib/test/test_profiling/test_sampling_profiler/test_trend_tracker.py @@ -0,0 +1,97 @@ +"""Simple unit tests for TrendTracker.""" + +import unittest +from test.support import requires +from test.support.import_helper import import_module + +# Only run these tests if curses is available +requires("curses") +curses = import_module("curses") + +from profiling.sampling.live_collector.trend_tracker import TrendTracker + + +class TestTrendTracker(unittest.TestCase): + """Tests for TrendTracker class.""" + + def setUp(self): + """Set up test fixtures.""" + self.colors = { + "trend_up": curses.A_BOLD, + "trend_down": curses.A_REVERSE, + "trend_stable": curses.A_NORMAL, + } + + def test_basic_trend_detection(self): + """Test basic up/down/stable trend detection.""" + tracker = TrendTracker(self.colors, enabled=True) + + # First value is always stable + self.assertEqual(tracker.update("func1", "nsamples", 10), "stable") + + # Increasing value + self.assertEqual(tracker.update("func1", "nsamples", 20), "up") + + # Decreasing value + self.assertEqual(tracker.update("func1", "nsamples", 15), "down") + + # Small change (within threshold) is stable + self.assertEqual(tracker.update("func1", "nsamples", 15.0001), "stable") + + def test_multiple_metrics(self): + """Test tracking multiple metrics simultaneously.""" + tracker = TrendTracker(self.colors, enabled=True) + + trends = tracker.update_metrics("func1", { + "nsamples": 10, + "tottime": 5.0, + }) + + self.assertEqual(trends["nsamples"], "stable") + self.assertEqual(trends["tottime"], "stable") + + # Update with changes + trends = tracker.update_metrics("func1", { + "nsamples": 15, + "tottime": 3.0, + }) + + self.assertEqual(trends["nsamples"], "up") + self.assertEqual(trends["tottime"], "down") + + def test_toggle_enabled(self): + """Test enable/disable toggle.""" + tracker = TrendTracker(self.colors, enabled=True) + self.assertTrue(tracker.enabled) + + tracker.toggle() + self.assertFalse(tracker.enabled) + + # When disabled, should return A_NORMAL + self.assertEqual(tracker.get_color("up"), curses.A_NORMAL) + + def test_get_color(self): + """Test color selection for trends.""" + tracker = TrendTracker(self.colors, enabled=True) + + self.assertEqual(tracker.get_color("up"), curses.A_BOLD) + self.assertEqual(tracker.get_color("down"), curses.A_REVERSE) + self.assertEqual(tracker.get_color("stable"), curses.A_NORMAL) + + def test_clear(self): + """Test clearing tracked values.""" + tracker = TrendTracker(self.colors, enabled=True) + + # Add some data + tracker.update("func1", "nsamples", 10) + tracker.update("func1", "nsamples", 20) + + # Clear + tracker.clear() + + # After clear, first update should be stable + self.assertEqual(tracker.update("func1", "nsamples", 30), "stable") + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index fbba7025ac4..7e4f4828ce0 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -3,7 +3,6 @@ from test.support import ( is_android, is_apple_mobile, is_wasm32, reap_children, verbose, warnings_helper ) from test.support.import_helper import import_module -from test.support.os_helper import TESTFN, unlink # Skip these tests if termios is not available import_module('termios') @@ -230,6 +229,7 @@ class PtyTest(unittest.TestCase): os._exit(2) os._exit(4) else: + self.assertFalse(os.get_inheritable(master_fd)) debug("Waiting for child (%d) to finish." % pid) # In verbose mode, we have to consume the debug output from the # child or the child will block, causing this test to hang in the @@ -298,26 +298,27 @@ class PtyTest(unittest.TestCase): @warnings_helper.ignore_fork_in_thread_deprecation_warnings() def test_spawn_doesnt_hang(self): - self.addCleanup(unlink, TESTFN) - with open(TESTFN, 'wb') as f: - STDOUT_FILENO = 1 - dup_stdout = os.dup(STDOUT_FILENO) - os.dup2(f.fileno(), STDOUT_FILENO) - buf = b'' - def master_read(fd): - nonlocal buf - data = os.read(fd, 1024) - buf += data - return data + # gh-140482: Do the test in a pty.fork() child to avoid messing + # with the interactive test runner's terminal settings. + pid, fd = pty.fork() + if pid == pty.CHILD: + pty.spawn([sys.executable, '-c', 'print("hi there")']) + os._exit(0) + + try: + buf = bytearray() try: - pty.spawn([sys.executable, '-c', 'print("hi there")'], - master_read) - finally: - os.dup2(dup_stdout, STDOUT_FILENO) - os.close(dup_stdout) - self.assertEqual(buf, b'hi there\r\n') - with open(TESTFN, 'rb') as f: - self.assertEqual(f.read(), b'hi there\r\n') + while (data := os.read(fd, 1024)) != b'': + buf.extend(data) + except OSError as e: + if e.errno != errno.EIO: + raise + + (pid, status) = os.waitpid(pid, 0) + self.assertEqual(status, 0) + self.assertEqual(buf.take_bytes(), b"hi there\r\n") + finally: + os.close(fd) class SmallPtyTests(unittest.TestCase): """These tests don't spawn children or hang.""" diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index bce68e6cd7a..79ef178f380 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -250,7 +250,7 @@ class PyclbrTest(TestCase): 'pdb', # pyclbr does not handle elegantly `typing` or properties ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'curframe_locals', - '_InteractState'), + '_InteractState', 'rlcompleter'), ) cm('pydoc', ignore=('input', 'output',)) # properties diff --git a/Lib/test/test_pydoc/pydocfodder.py b/Lib/test/test_pydoc/pydocfodder.py index 3cc2d5bd57f..412aa3743e4 100644 --- a/Lib/test/test_pydoc/pydocfodder.py +++ b/Lib/test/test_pydoc/pydocfodder.py @@ -87,6 +87,8 @@ class B(A): object_repr = object.__repr__ get = {}.get # same name dict_get = {}.get + from math import sin + B.B_classmethod_ref = B.B_classmethod @@ -186,3 +188,4 @@ __repr__ = object.__repr__ # same name object_repr = object.__repr__ get = {}.get # same name dict_get = {}.get +from math import sin # noqa: F401 diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 3b50ead00bd..89480423d32 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -11,7 +11,6 @@ import keyword import _pickle import pkgutil import re -import stat import tempfile import test.support import time @@ -1300,27 +1299,16 @@ class PydocImportTest(PydocBaseTest): self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), '') - @os_helper.skip_unless_working_chmod def test_apropos_empty_doc(self): pkgdir = os.path.join(TESTFN, 'walkpkg') - if support.is_emscripten: - # Emscripten's readdir implementation is buggy on directories - # with read permission but no execute permission. - old_umask = os.umask(0) - self.addCleanup(os.umask, old_umask) os.mkdir(pkgdir) self.addCleanup(rmtree, pkgdir) init_path = os.path.join(pkgdir, '__init__.py') with open(init_path, 'w') as fobj: fobj.write("foo = 1") - current_mode = stat.S_IMODE(os.stat(pkgdir).st_mode) - try: - os.chmod(pkgdir, current_mode & ~stat.S_IEXEC) - with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout: - pydoc.apropos('') - self.assertIn('walkpkg', stdout.getvalue()) - finally: - os.chmod(pkgdir, current_mode) + with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout: + pydoc.apropos('') + self.assertIn('walkpkg', stdout.getvalue()) def test_url_search_package_error(self): # URL handler search should cope with packages that raise exceptions @@ -1346,47 +1334,6 @@ class PydocImportTest(PydocBaseTest): finally: sys.path[:] = saved_paths - @unittest.skip('causes undesirable side-effects (#20128)') - def test_modules(self): - # See Helper.listmodules(). - num_header_lines = 2 - num_module_lines_min = 5 # Playing it safe. - num_footer_lines = 3 - expected = num_header_lines + num_module_lines_min + num_footer_lines - - output = StringIO() - helper = pydoc.Helper(output=output) - helper('modules') - result = output.getvalue().strip() - num_lines = len(result.splitlines()) - - self.assertGreaterEqual(num_lines, expected) - - @unittest.skip('causes undesirable side-effects (#20128)') - def test_modules_search(self): - # See Helper.listmodules(). - expected = 'pydoc - ' - - output = StringIO() - helper = pydoc.Helper(output=output) - with captured_stdout() as help_io: - helper('modules pydoc') - result = help_io.getvalue() - - self.assertIn(expected, result) - - @unittest.skip('some buildbots are not cooperating (#20128)') - def test_modules_search_builtin(self): - expected = 'gc - ' - - output = StringIO() - helper = pydoc.Helper(output=output) - with captured_stdout() as help_io: - helper('modules garbage') - result = help_io.getvalue() - - self.assertStartsWith(result, expected) - def test_importfile(self): try: loaded_pydoc = pydoc.importfile(pydoc.__file__) @@ -1466,7 +1413,7 @@ class TestDescriptions(unittest.TestCase): self.assertIn('NoReturn = typing.NoReturn', doc) self.assertIn(typing.NoReturn.__doc__.strip().splitlines()[0], doc) else: - self.assertIn('NoReturn = class _SpecialForm(_Final)', doc) + self.assertIn('NoReturn = class _SpecialForm(_Final, _NotIterable)', doc) def test_typing_pydoc(self): def foo(data: typing.List[typing.Any], @@ -1951,9 +1898,11 @@ class PydocFodderTest(unittest.TestCase): if not support.MISSING_C_DOCSTRINGS: self.assertIn(' | get(key, default=None, /) method of builtins.dict instance', lines) self.assertIn(' | dict_get = get(key, default=None, /) method of builtins.dict instance', lines) + self.assertIn(' | sin(x, /)', lines) else: self.assertIn(' | get(...) method of builtins.dict instance', lines) self.assertIn(' | dict_get = get(...) method of builtins.dict instance', lines) + self.assertIn(' | sin(object, /)', lines) lines = self.getsection(result, f' | Class methods {where}:', ' | ' + '-'*70) self.assertIn(' | B_classmethod(x)', lines) @@ -2039,6 +1988,11 @@ class PydocFodderTest(unittest.TestCase): self.assertIn(' __repr__(...) unbound builtins.object method', lines) self.assertIn(' object_repr = __repr__(...) unbound builtins.object method', lines) + # builtin functions + if not support.MISSING_C_DOCSTRINGS: + self.assertIn(' sin(x, /)', lines) + else: + self.assertIn(' sin(object, /)', lines) def test_html_doc_routines_in_module(self): doc = pydoc.HTMLDoc() @@ -2079,6 +2033,12 @@ class PydocFodderTest(unittest.TestCase): self.assertIn(' __repr__(...) unbound builtins.object method', lines) self.assertIn(' object_repr = __repr__(...) unbound builtins.object method', lines) + # builtin functions + if not support.MISSING_C_DOCSTRINGS: + self.assertIn(' sin(x, /)', lines) + else: + self.assertIn(' sin(object, /)', lines) + @unittest.skipIf( is_wasm32, @@ -2345,6 +2305,32 @@ class TestInternalUtilities(unittest.TestCase): trailing_argv0dir = trailing_curdir + [self.argv0dir] self.assertIsNone(self._get_revised_path(trailing_argv0dir)) + def test__get_version(self): + import json + import warnings + + class MyModule: + __name__ = 'my_module' + + @property + def __version__(self): + warnings._deprecated("__version__", remove=(3, 20)) + return "1.2.3" + + module = MyModule() + doc = pydoc.Doc() + with warnings.catch_warnings(record=True) as w: # TODO: remove in 3.20 + warnings.simplefilter("always") + version = doc._get_version(json) + self.assertEqual(version, "2.0.9") + self.assertEqual(len(w), 0) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + version = doc._get_version(module) + self.assertEqual(version, "1.2.3") + self.assertEqual(len(w), 1) + def setUpModule(): thread_info = threading_helper.threading_setup() diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index d4b4f60be98..74a75458289 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -1,14 +1,18 @@ # XXX TypeErrors on calling handlers, or on bad return values from a # handler, are obscure and unhelpful. +import abc +import functools import os +import re import sys import sysconfig +import textwrap import unittest import traceback from io import BytesIO from test import support -from test.support import os_helper +from test.support import import_helper, os_helper from test.support import sortdict from unittest import mock from xml.parsers import expat @@ -680,6 +684,23 @@ class ChardataBufferTest(unittest.TestCase): parser.Parse(xml2, True) self.assertEqual(self.n, 4) +class ElementDeclHandlerTest(unittest.TestCase): + def test_trigger_leak(self): + # Unfixed, this test would leak the memory of the so-called + # "content model" in function ``my_ElementDeclHandler`` of pyexpat. + # See https://github.com/python/cpython/issues/140593. + data = textwrap.dedent('''\ + <!DOCTYPE quotations SYSTEM "quotations.dtd" [ + <!ELEMENT root ANY> + ]> + <root/> + ''').encode('UTF-8') + + parser = expat.ParserCreate() + parser.NotStandaloneHandler = lambda: 1.234 # arbitrary float + parser.ElementDeclHandler = lambda _1, _2: None + self.assertRaises(TypeError, parser.Parse, data, True) + class MalformedInputTest(unittest.TestCase): def test1(self): xml = b"\0\r\n" @@ -767,6 +788,42 @@ class ForeignDTDTests(unittest.TestCase): self.assertEqual(handler_call_args, [("bar", "baz")]) +class ParentParserLifetimeTest(unittest.TestCase): + """ + Subparsers make use of their parent XML_Parser inside of Expat. + As a result, parent parsers need to outlive subparsers. + + See https://github.com/python/cpython/issues/139400. + """ + + def test_parent_parser_outlives_its_subparsers__single(self): + parser = expat.ParserCreate() + subparser = parser.ExternalEntityParserCreate(None) + + # Now try to cause garbage collection of the parent parser + # while it's still being referenced by a related subparser. + del parser + + def test_parent_parser_outlives_its_subparsers__multiple(self): + parser = expat.ParserCreate() + subparser_one = parser.ExternalEntityParserCreate(None) + subparser_two = parser.ExternalEntityParserCreate(None) + + # Now try to cause garbage collection of the parent parser + # while it's still being referenced by a related subparser. + del parser + + def test_parent_parser_outlives_its_subparsers__chain(self): + parser = expat.ParserCreate() + subparser = parser.ExternalEntityParserCreate(None) + subsubparser = subparser.ExternalEntityParserCreate(None) + + # Now try to cause garbage collection of the parent parsers + # while they are still being referenced by a related subparser. + del parser + del subparser + + class ReparseDeferralTest(unittest.TestCase): def test_getter_setter_round_trip(self): parser = expat.ParserCreate() @@ -821,5 +878,257 @@ class ReparseDeferralTest(unittest.TestCase): self.assertEqual(started, ['doc']) +class AttackProtectionTestBase(abc.ABC): + """ + Base class for testing protections against XML payloads with + disproportionate amplification. + + The protections being tested should detect and prevent attacks + that leverage disproportionate amplification from small inputs. + """ + + @staticmethod + def exponential_expansion_payload(*, nrows, ncols, text='.'): + """Create a billion laughs attack payload. + + Be careful: the number of total items is pow(n, k), thereby + requiring at least pow(ncols, nrows) * sizeof(text) memory! + """ + template = textwrap.dedent(f"""\ + <?xml version="1.0"?> + <!DOCTYPE doc [ + <!ENTITY row0 "{text}"> + <!ELEMENT doc (#PCDATA)> + {{body}} + ]> + <doc>&row{nrows};</doc> + """).rstrip() + + body = '\n'.join( + f'<!ENTITY row{i + 1} "{f"&row{i};" * ncols}">' + for i in range(nrows) + ) + body = textwrap.indent(body, ' ' * 4) + return template.format(body=body) + + def test_payload_generation(self): + # self-test for exponential_expansion_payload() + payload = self.exponential_expansion_payload(nrows=2, ncols=3) + self.assertEqual(payload, textwrap.dedent("""\ + <?xml version="1.0"?> + <!DOCTYPE doc [ + <!ENTITY row0 "."> + <!ELEMENT doc (#PCDATA)> + <!ENTITY row1 "&row0;&row0;&row0;"> + <!ENTITY row2 "&row1;&row1;&row1;"> + ]> + <doc>&row2;</doc> + """).rstrip()) + + def assert_root_parser_failure(self, func, /, *args, **kwargs): + """Check that func(*args, **kwargs) is invalid for a sub-parser.""" + msg = "parser must be a root parser" + self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs) + + @abc.abstractmethod + def assert_rejected(self, func, /, *args, **kwargs): + """Assert that func(*args, **kwargs) triggers the attack protection. + + Note: this method must ensure that the attack protection being tested + is the one that is actually triggered at runtime, e.g., by matching + the exact error message. + """ + + @abc.abstractmethod + def set_activation_threshold(self, parser, threshold): + """Set the activation threshold for the tested protection.""" + + @abc.abstractmethod + def set_maximum_amplification(self, parser, max_factor): + """Set the maximum amplification factor for the tested protection.""" + + @abc.abstractmethod + def test_set_activation_threshold__threshold_reached(self): + """Test when the activation threshold is exceeded.""" + + @abc.abstractmethod + def test_set_activation_threshold__threshold_not_reached(self): + """Test when the activation threshold is not exceeded.""" + + def test_set_activation_threshold__invalid_threshold_type(self): + parser = expat.ParserCreate() + setter = functools.partial(self.set_activation_threshold, parser) + + self.assertRaises(TypeError, setter, 1.0) + self.assertRaises(TypeError, setter, -1.5) + self.assertRaises(ValueError, setter, -5) + + def test_set_activation_threshold__invalid_threshold_range(self): + _testcapi = import_helper.import_module("_testcapi") + parser = expat.ParserCreate() + setter = functools.partial(self.set_activation_threshold, parser) + + self.assertRaises(OverflowError, setter, _testcapi.ULLONG_MAX + 1) + + def test_set_activation_threshold__fail_for_subparser(self): + parser = expat.ParserCreate() + subparser = parser.ExternalEntityParserCreate(None) + setter = functools.partial(self.set_activation_threshold, subparser) + self.assert_root_parser_failure(setter, 12345) + + @abc.abstractmethod + def test_set_maximum_amplification__amplification_exceeded(self): + """Test when the amplification factor is exceeded.""" + + @abc.abstractmethod + def test_set_maximum_amplification__amplification_not_exceeded(self): + """Test when the amplification factor is not exceeded.""" + + def test_set_maximum_amplification__infinity(self): + inf = float('inf') # an 'inf' threshold is allowed by Expat + parser = expat.ParserCreate() + self.assertIsNone(self.set_maximum_amplification(parser, inf)) + + def test_set_maximum_amplification__invalid_max_factor_type(self): + parser = expat.ParserCreate() + setter = functools.partial(self.set_maximum_amplification, parser) + + self.assertRaises(TypeError, setter, None) + self.assertRaises(TypeError, setter, 'abc') + + def test_set_maximum_amplification__invalid_max_factor_range(self): + parser = expat.ParserCreate() + setter = functools.partial(self.set_maximum_amplification, parser) + + msg = re.escape("'max_factor' must be at least 1.0") + self.assertRaisesRegex(expat.ExpatError, msg, setter, float('nan')) + self.assertRaisesRegex(expat.ExpatError, msg, setter, 0.99) + + def test_set_maximum_amplification__fail_for_subparser(self): + parser = expat.ParserCreate() + subparser = parser.ExternalEntityParserCreate(None) + setter = functools.partial(self.set_maximum_amplification, subparser) + self.assert_root_parser_failure(setter, 123.45) + + +@unittest.skipIf(expat.version_info < (2, 4, 0), "requires Expat >= 2.4.0") +class ExpansionProtectionTest(AttackProtectionTestBase, unittest.TestCase): + + def assert_rejected(self, func, /, *args, **kwargs): + """Check that func(*args, **kwargs) hits the allocation limit.""" + msg = ( + r"limit on input amplification factor \(from DTD and entities\) " + r"breached: line \d+, column \d+" + ) + self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs) + + def set_activation_threshold(self, parser, threshold): + return parser.SetBillionLaughsAttackProtectionActivationThreshold(threshold) + + def set_maximum_amplification(self, parser, max_factor): + return parser.SetBillionLaughsAttackProtectionMaximumAmplification(max_factor) + + def test_set_activation_threshold__threshold_reached(self): + parser = expat.ParserCreate() + # Choose a threshold expected to be always reached. + self.set_activation_threshold(parser, 3) + # Check that the threshold is reached by choosing a small factor + # and a payload whose peak amplification factor exceeds it. + self.assertIsNone(self.set_maximum_amplification(parser, 1.0)) + payload = self.exponential_expansion_payload(ncols=10, nrows=4) + self.assert_rejected(parser.Parse, payload, True) + + def test_set_activation_threshold__threshold_not_reached(self): + parser = expat.ParserCreate() + # Choose a threshold expected to be never reached. + self.set_activation_threshold(parser, pow(10, 5)) + # Check that the threshold is reached by choosing a small factor + # and a payload whose peak amplification factor exceeds it. + self.assertIsNone(self.set_maximum_amplification(parser, 1.0)) + payload = self.exponential_expansion_payload(ncols=10, nrows=4) + self.assertIsNotNone(parser.Parse(payload, True)) + + def test_set_maximum_amplification__amplification_exceeded(self): + parser = expat.ParserCreate() + # Unconditionally enable maximum activation factor. + self.set_activation_threshold(parser, 0) + # Choose a max amplification factor expected to always be exceeded. + self.assertIsNone(self.set_maximum_amplification(parser, 1.0)) + # Craft a payload for which the peak amplification factor is > 1.0. + payload = self.exponential_expansion_payload(ncols=1, nrows=2) + self.assert_rejected(parser.Parse, payload, True) + + def test_set_maximum_amplification__amplification_not_exceeded(self): + parser = expat.ParserCreate() + # Unconditionally enable maximum activation factor. + self.set_activation_threshold(parser, 0) + # Choose a max amplification factor expected to never be exceeded. + self.assertIsNone(self.set_maximum_amplification(parser, 1e4)) + # Craft a payload for which the peak amplification factor is < 1e4. + payload = self.exponential_expansion_payload(ncols=1, nrows=2) + self.assertIsNotNone(parser.Parse(payload, True)) + + +@unittest.skipIf(expat.version_info < (2, 7, 2), "requires Expat >= 2.7.2") +class MemoryProtectionTest(AttackProtectionTestBase, unittest.TestCase): + + # NOTE: with the default Expat configuration, the billion laughs protection + # may hit before the allocation limiter if exponential_expansion_payload() + # is not carefully parametrized. As such, the payloads should be chosen so + # that either the allocation limiter is hit before other protections are + # triggered or no protection at all is triggered. + + def assert_rejected(self, func, /, *args, **kwargs): + """Check that func(*args, **kwargs) hits the allocation limit.""" + msg = r"out of memory: line \d+, column \d+" + self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs) + + def set_activation_threshold(self, parser, threshold): + return parser.SetAllocTrackerActivationThreshold(threshold) + + def set_maximum_amplification(self, parser, max_factor): + return parser.SetAllocTrackerMaximumAmplification(max_factor) + + def test_set_activation_threshold__threshold_reached(self): + parser = expat.ParserCreate() + # Choose a threshold expected to be always reached. + self.set_activation_threshold(parser, 3) + # Check that the threshold is reached by choosing a small factor + # and a payload whose peak amplification factor exceeds it. + self.assertIsNone(self.set_maximum_amplification(parser, 1.0)) + payload = self.exponential_expansion_payload(ncols=10, nrows=4) + self.assert_rejected(parser.Parse, payload, True) + + def test_set_activation_threshold__threshold_not_reached(self): + parser = expat.ParserCreate() + # Choose a threshold expected to be never reached. + self.set_activation_threshold(parser, pow(10, 5)) + # Check that the threshold is reached by choosing a small factor + # and a payload whose peak amplification factor exceeds it. + self.assertIsNone(self.set_maximum_amplification(parser, 1.0)) + payload = self.exponential_expansion_payload(ncols=10, nrows=4) + self.assertIsNotNone(parser.Parse(payload, True)) + + def test_set_maximum_amplification__amplification_exceeded(self): + parser = expat.ParserCreate() + # Unconditionally enable maximum activation factor. + self.set_activation_threshold(parser, 0) + # Choose a max amplification factor expected to always be exceeded. + self.assertIsNone(self.set_maximum_amplification(parser, 1.0)) + # Craft a payload for which the peak amplification factor is > 1.0. + payload = self.exponential_expansion_payload(ncols=1, nrows=2) + self.assert_rejected(parser.Parse, payload, True) + + def test_set_maximum_amplification__amplification_not_exceeded(self): + parser = expat.ParserCreate() + # Unconditionally enable maximum activation factor. + self.set_activation_threshold(parser, 0) + # Choose a max amplification factor expected to never be exceeded. + self.assertIsNone(self.set_maximum_amplification(parser, 1e4)) + # Craft a payload for which the peak amplification factor is < 1e4. + payload = self.exponential_expansion_payload(ncols=1, nrows=2) + self.assertIsNotNone(parser.Parse(payload, True)) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_pyrepl/__init__.py b/Lib/test/test_pyrepl/__init__.py index 8ef472eb0cf..2f37bff6df8 100644 --- a/Lib/test/test_pyrepl/__init__.py +++ b/Lib/test/test_pyrepl/__init__.py @@ -1,14 +1,10 @@ import os -from test.support import load_package_tests -import unittest +import sys +from test.support import import_helper, load_package_tests -try: - import termios -except ImportError: - raise unittest.SkipTest("termios required") -else: - del termios +if sys.platform != "win32": + import_helper.import_module("termios") def load_tests(*args): diff --git a/Lib/test/test_pyrepl/eio_test_script.py b/Lib/test/test_pyrepl/eio_test_script.py new file mode 100644 index 00000000000..e3ea6caef58 --- /dev/null +++ b/Lib/test/test_pyrepl/eio_test_script.py @@ -0,0 +1,94 @@ +import errno +import fcntl +import os +import pty +import signal +import sys +import termios + + +def handler(sig, f): + pass + + +def create_eio_condition(): + # SIGINT handler used to produce an EIO. + # See https://github.com/python/cpython/issues/135329. + try: + master_fd, slave_fd = pty.openpty() + child_pid = os.fork() + if child_pid == 0: + try: + os.setsid() + fcntl.ioctl(slave_fd, termios.TIOCSCTTY, 0) + child_process_group_id = os.getpgrp() + grandchild_pid = os.fork() + if grandchild_pid == 0: + os.setpgid(0, 0) # set process group for grandchild + os.dup2(slave_fd, 0) # redirect stdin + if slave_fd > 2: + os.close(slave_fd) + # Fork grandchild for terminal control manipulation + if os.fork() == 0: + sys.exit(0) # exit the child process that was just obtained + else: + try: + os.tcsetpgrp(0, child_process_group_id) + except OSError: + pass + sys.exit(0) + else: + # Back to child + try: + os.setpgid(grandchild_pid, grandchild_pid) + except ProcessLookupError: + pass + os.tcsetpgrp(slave_fd, grandchild_pid) + if slave_fd > 2: + os.close(slave_fd) + os.waitpid(grandchild_pid, 0) + # Manipulate terminal control to create EIO condition + os.tcsetpgrp(master_fd, child_process_group_id) + # Now try to read from master - this might cause EIO + try: + os.read(master_fd, 1) + except OSError as e: + if e.errno == errno.EIO: + print(f"Setup created EIO condition: {e}", file=sys.stderr) + sys.exit(0) + except Exception as setup_e: + print(f"Setup error: {setup_e}", file=sys.stderr) + sys.exit(1) + else: + # Parent process + os.close(slave_fd) + os.waitpid(child_pid, 0) + # Now replace stdin with master_fd and try to read + os.dup2(master_fd, 0) + os.close(master_fd) + # This should now trigger EIO + print(f"Unexpectedly got input: {input()!r}", file=sys.stderr) + sys.exit(0) + except OSError as e: + if e.errno == errno.EIO: + print(f"Got EIO: {e}", file=sys.stderr) + sys.exit(1) + elif e.errno == errno.ENXIO: + print(f"Got ENXIO (no such device): {e}", file=sys.stderr) + sys.exit(1) # Treat ENXIO as success too + else: + print(f"Got other OSError: errno={e.errno} {e}", file=sys.stderr) + sys.exit(2) + except EOFError as e: + print(f"Got EOFError: {e}", file=sys.stderr) + sys.exit(3) + except Exception as e: + print(f"Got unexpected error: {type(e).__name__}: {e}", file=sys.stderr) + sys.exit(4) + + +if __name__ == "__main__": + # Set up signal handler for coordination + signal.signal(signal.SIGUSR1, lambda *a: create_eio_condition()) + print("READY", flush=True) + signal.pause() diff --git a/Lib/test/test_pyrepl/test_interact.py b/Lib/test/test_pyrepl/test_interact.py index 8c0eeab6dca..fd4530ebc00 100644 --- a/Lib/test/test_pyrepl/test_interact.py +++ b/Lib/test/test_pyrepl/test_interact.py @@ -1,7 +1,7 @@ import contextlib import io -import unittest import warnings +import unittest from unittest.mock import patch from textwrap import dedent @@ -293,7 +293,7 @@ class TestWarnings(unittest.TestCase): """) with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("default") + warnings.simplefilter("always") console.runsource(code) count = sum("'return' in a 'finally' block" in str(w.message) diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 8e4450fdf99..ddcaafc9b7d 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -1,3 +1,4 @@ +import importlib import io import itertools import os @@ -26,9 +27,16 @@ from .support import ( code_to_events, ) from _pyrepl.console import Event -from _pyrepl._module_completer import ImportParser, ModuleCompleter -from _pyrepl.readline import (ReadlineAlikeReader, ReadlineConfig, - _ReadlineWrapper) +from _pyrepl._module_completer import ( + ImportParser, + ModuleCompleter, + HARDCODED_SUBMODULES, +) +from _pyrepl.readline import ( + ReadlineAlikeReader, + ReadlineConfig, + _ReadlineWrapper, +) from _pyrepl.readline import multiline_input as readline_multiline_input try: @@ -930,7 +938,6 @@ class TestPyReplCompleter(TestCase): class TestPyReplModuleCompleter(TestCase): def setUp(self): - import importlib # Make iter_modules() search only the standard library. # This makes the test more reliable in case there are # other user packages/scripts on PYTHONPATH which can @@ -1013,14 +1020,6 @@ class TestPyReplModuleCompleter(TestCase): self.assertEqual(output, expected) def test_builtin_completion_top_level(self): - import importlib - # Make iter_modules() search only the standard library. - # This makes the test more reliable in case there are - # other user packages/scripts on PYTHONPATH which can - # intefere with the completions. - lib_path = os.path.dirname(importlib.__path__[0]) - sys.path = [lib_path] - cases = ( ("import bui\t\n", "import builtins"), ("from bui\t\n", "from builtins"), @@ -1076,6 +1075,32 @@ class TestPyReplModuleCompleter(TestCase): output = reader.readline() self.assertEqual(output, expected) + def test_hardcoded_stdlib_submodules(self): + cases = ( + ("import collections.\t\n", "import collections.abc"), + ("from os import \t\n", "from os import path"), + ("import xml.parsers.expat.\t\te\t\n\n", "import xml.parsers.expat.errors"), + ("from xml.parsers.expat import \t\tm\t\n\n", "from xml.parsers.expat import model"), + ) + for code, expected in cases: + with self.subTest(code=code): + events = code_to_events(code) + reader = self.prepare_reader(events, namespace={}) + output = reader.readline() + self.assertEqual(output, expected) + + def test_hardcoded_stdlib_submodules_not_proposed_if_local_import(self): + with tempfile.TemporaryDirectory() as _dir: + dir = pathlib.Path(_dir) + (dir / "collections").mkdir() + (dir / "collections" / "__init__.py").touch() + (dir / "collections" / "foo.py").touch() + with patch.object(sys, "path", [dir, *sys.path]): + events = code_to_events("import collections.\t\n") + reader = self.prepare_reader(events, namespace={}) + output = reader.readline() + self.assertEqual(output, "import collections.foo") + def test_get_path_and_prefix(self): cases = ( ('', ('', '')), @@ -1204,6 +1229,19 @@ class TestPyReplModuleCompleter(TestCase): with self.subTest(code=code): self.assertEqual(actual, None) + +class TestHardcodedSubmodules(TestCase): + def test_hardcoded_stdlib_submodules_are_importable(self): + for parent_path, submodules in HARDCODED_SUBMODULES.items(): + for module_name in submodules: + path = f"{parent_path}.{module_name}" + with self.subTest(path=path): + # We can't use importlib.util.find_spec here, + # since some hardcoded submodules parents are + # not proper packages + importlib.import_module(path) + + class TestPasteEvent(TestCase): def prepare_reader(self, events): console = FakeConsole(events) @@ -1368,6 +1406,9 @@ class TestDumbTerminal(ReplTestCase): def test_dumb_terminal_exits_cleanly(self): env = os.environ.copy() env.pop('PYTHON_BASIC_REPL', None) + # Ignore PYTHONSTARTUP to not pollute the output + # with an unrelated traceback. See GH-137568. + env.pop('PYTHONSTARTUP', None) env.update({"TERM": "dumb"}) output, exit_code = self.run_repl("exit()\n", env=env) self.assertEqual(exit_code, 0) @@ -1402,10 +1443,10 @@ class TestMain(ReplTestCase): case2 = f"{pre}, '__doc__', '__file__', {post}" in output # if `__main__` is a cached .pyc file and the .py source exists - case3 = f"{pre}, '__cached__', '__doc__', '__file__', {post}" in output + case3 = f"{pre}, '__doc__', '__file__', {post}" in output # if `__main__` is a cached .pyc file but there's no .py source file - case4 = f"{pre}, '__cached__', '__doc__', {post}" in output + case4 = f"{pre}, '__doc__', {post}" in output self.assertTrue(case1 or case2 or case3 or case4, output) @@ -1787,3 +1828,86 @@ class TestMain(ReplTestCase): " outside of the Python REPL" ) self.assertIn(hint, output) + +class TestPyReplCtrlD(TestCase): + """Test Ctrl+D behavior in _pyrepl to match old pre-3.13 REPL behavior. + + Ctrl+D should: + - Exit on empty buffer (raises EOFError) + - Delete character when cursor is in middle of line + - Perform no operation when cursor is at end of line without newline + - Exit multiline mode when cursor is at end with trailing newline + - Run code up to that point when pressed on blank line with preceding lines + """ + def prepare_reader(self, events): + console = FakeConsole(events) + config = ReadlineConfig(readline_completer=None) + reader = ReadlineAlikeReader(console=console, config=config) + return reader + + def test_ctrl_d_empty_line(self): + """Test that pressing Ctrl+D on empty line exits the program""" + events = [ + Event(evt="key", data="\x04", raw=bytearray(b"\x04")), # Ctrl+D + ] + reader = self.prepare_reader(events) + with self.assertRaises(EOFError): + multiline_input(reader) + + def test_ctrl_d_multiline_with_new_line(self): + """Test that pressing Ctrl+D in multiline mode with trailing newline exits multiline mode""" + events = itertools.chain( + code_to_events("def f():\n pass\n"), # Enter multiline mode with trailing newline + [ + Event(evt="key", data="\x04", raw=bytearray(b"\x04")), # Ctrl+D + ], + ) + reader, _ = handle_all_events(events) + self.assertTrue(reader.finished) + self.assertEqual("def f():\n pass\n", "".join(reader.buffer)) + + def test_ctrl_d_multiline_middle_of_line(self): + """Test that pressing Ctrl+D in multiline mode with cursor in middle deletes character""" + events = itertools.chain( + code_to_events("def f():\n hello world"), # Enter multiline mode + [ + Event(evt="key", data="left", raw=bytearray(b"\x1bOD")) + ] * 5, # move cursor to 'w' in "world" + [ + Event(evt="key", data="\x04", raw=bytearray(b"\x04")) + ], # Ctrl+D should delete 'w' + ) + reader, _ = handle_all_events(events) + self.assertFalse(reader.finished) + self.assertEqual("def f():\n hello orld", "".join(reader.buffer)) + + def test_ctrl_d_multiline_end_of_line_no_newline(self): + """Test that pressing Ctrl+D at end of line without newline performs no operation""" + events = itertools.chain( + code_to_events("def f():\n hello"), # Enter multiline mode, no trailing newline + [ + Event(evt="key", data="\x04", raw=bytearray(b"\x04")) + ], # Ctrl+D should be no-op + ) + reader, _ = handle_all_events(events) + self.assertFalse(reader.finished) + self.assertEqual("def f():\n hello", "".join(reader.buffer)) + + def test_ctrl_d_single_line_middle_of_line(self): + """Test that pressing Ctrl+D in single line mode deletes current character""" + events = itertools.chain( + code_to_events("hello"), + [Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))], # move left + [Event(evt="key", data="\x04", raw=bytearray(b"\x04"))], # Ctrl+D + ) + reader, _ = handle_all_events(events) + self.assertEqual("hell", "".join(reader.buffer)) + + def test_ctrl_d_single_line_end_no_newline(self): + """Test that pressing Ctrl+D at end of single line without newline does nothing""" + events = itertools.chain( + code_to_events("hello"), # cursor at end of line + [Event(evt="key", data="\x04", raw=bytearray(b"\x04"))], # Ctrl+D + ) + reader, _ = handle_all_events(events) + self.assertEqual("hello", "".join(reader.buffer)) diff --git a/Lib/test/test_pyrepl/test_reader.py b/Lib/test/test_pyrepl/test_reader.py index 9a02dff7387..b1b6ae16a1e 100644 --- a/Lib/test/test_pyrepl/test_reader.py +++ b/Lib/test/test_pyrepl/test_reader.py @@ -378,6 +378,7 @@ class TestReaderInColor(ScreenEqualMixin, TestCase): case "ios" | "android": print("on the phone") case _: print('arms around', match.group(1)) + type type = type[type] """ ) expected = dedent( @@ -397,6 +398,7 @@ class TestReaderInColor(ScreenEqualMixin, TestCase): {K}case{z} {s}"ios"{z} {o}|{z} {s}"android"{z}{o}:{z} {b}print{z}{o}({z}{s}"on the phone"{z}{o}){z} {K}case{z} {K}_{z}{o}:{z} {b}print{z}{o}({z}{s}'arms around'{z}{o},{z} match{o}.{z}group{o}({z}{n}1{z}{o}){z}{o}){z} + {K}type{z} {b}type{z} {o}={z} {b}type{z}{o}[{z}{b}type{z}{o}]{z} """ ) expected_sync = expected.format(a="", **colors) @@ -404,14 +406,14 @@ class TestReaderInColor(ScreenEqualMixin, TestCase): reader, _ = handle_all_events(events) self.assert_screen_equal(reader, code, clean=True) self.assert_screen_equal(reader, expected_sync) - self.assertEqual(reader.pos, 396) - self.assertEqual(reader.cxy, (0, 15)) + self.assertEqual(reader.pos, 419) + self.assertEqual(reader.cxy, (0, 16)) async_msg = "{k}async{z} ".format(**colors) expected_async = expected.format(a=async_msg, **colors) more_events = itertools.chain( code_to_events(code), - [Event(evt="key", data="up", raw=bytearray(b"\x1bOA"))] * 14, + [Event(evt="key", data="up", raw=bytearray(b"\x1bOA"))] * 15, code_to_events("async "), ) reader, _ = handle_all_events(more_events) diff --git a/Lib/test/test_pyrepl/test_unix_console.py b/Lib/test/test_pyrepl/test_unix_console.py index ab1236768cf..f4fb9237ffd 100644 --- a/Lib/test/test_pyrepl/test_unix_console.py +++ b/Lib/test/test_pyrepl/test_unix_console.py @@ -1,12 +1,18 @@ +import errno import itertools import os +import signal +import subprocess import sys +import threading import unittest from functools import partial +from test import support from test.support import os_helper, force_not_colorized_test_class +from test.support import script_helper, threading_helper from unittest import TestCase -from unittest.mock import MagicMock, call, patch, ANY +from unittest.mock import MagicMock, call, patch, ANY, Mock from .support import handle_all_events, code_to_events @@ -303,3 +309,80 @@ class TestConsole(TestCase): self.assertIsInstance(console.getheightwidth(), tuple) os.environ = [] self.assertIsInstance(console.getheightwidth(), tuple) + + @unittest.skipUnless(sys.platform == "darwin", "requires macOS") + def test_restore_with_invalid_environ_on_macos(self, _os_write): + # gh-128636 for macOS + console = UnixConsole(term="xterm") + with os_helper.EnvironmentVarGuard(): + os.environ = [] + console.prepare() # needed to call restore() + console.restore() # this should succeed + + @threading_helper.reap_threads + @threading_helper.requires_working_threading() + def test_restore_in_thread(self, _os_write): + # gh-139391: ensure that console.restore() silently suppresses + # exceptions when calling signal.signal() from a non-main thread. + console = unix_console([]) + console.old_sigwinch = signal.SIG_DFL + thread = threading.Thread(target=console.restore) + thread.start() + thread.join() # this should not raise + + +@unittest.skipIf(sys.platform == "win32", "No Unix console on Windows") +class TestUnixConsoleEIOHandling(TestCase): + + @patch('_pyrepl.unix_console.tcsetattr') + @patch('_pyrepl.unix_console.tcgetattr') + def test_eio_error_handling_in_restore(self, mock_tcgetattr, mock_tcsetattr): + + import termios + mock_termios = Mock() + mock_termios.iflag = 0 + mock_termios.oflag = 0 + mock_termios.cflag = 0 + mock_termios.lflag = 0 + mock_termios.cc = [0] * 32 + mock_termios.copy.return_value = mock_termios + mock_tcgetattr.return_value = mock_termios + + console = UnixConsole(term="xterm") + console.prepare() + + mock_tcsetattr.side_effect = termios.error(errno.EIO, "Input/output error") + + # EIO error should be handled gracefully in restore() + console.restore() + + @unittest.skipUnless(sys.platform == "linux", "Only valid on Linux") + def test_repl_eio(self): + # Use the pty-based approach to simulate EIO error + script_path = os.path.join(os.path.dirname(__file__), "eio_test_script.py") + + proc = script_helper.spawn_python( + "-S", script_path, + stderr=subprocess.PIPE, + text=True + ) + + ready_line = proc.stdout.readline().strip() + if ready_line != "READY" or proc.poll() is not None: + self.fail("Child process failed to start properly") + + os.kill(proc.pid, signal.SIGUSR1) + # sleep for pty to settle + _, err = proc.communicate(timeout=support.LONG_TIMEOUT) + self.assertEqual( + proc.returncode, + 1, + f"Expected EIO/ENXIO error, got return code {proc.returncode}", + ) + self.assertTrue( + ( + "Got EIO:" in err + or "Got ENXIO:" in err + ), + f"Expected EIO/ENXIO error message in stderr: {err}", + ) diff --git a/Lib/test/test_pyrepl/test_utils.py b/Lib/test/test_pyrepl/test_utils.py index 8ce1e537138..656a1e441e0 100644 --- a/Lib/test/test_pyrepl/test_utils.py +++ b/Lib/test/test_pyrepl/test_utils.py @@ -1,14 +1,33 @@ from unittest import TestCase -from _pyrepl.utils import str_width, wlen, prev_next_window +from _pyrepl.utils import str_width, wlen, prev_next_window, gen_colors class TestUtils(TestCase): def test_str_width(self): - characters = ['a', '1', '_', '!', '\x1a', '\u263A', '\uffb9'] + characters = [ + 'a', + '1', + '_', + '!', + '\x1a', + '\u263A', + '\uffb9', + '\N{LATIN SMALL LETTER E WITH ACUTE}', # é + '\N{LATIN SMALL LETTER E WITH CEDILLA}', # ȩ + '\u00ad', + ] for c in characters: self.assertEqual(str_width(c), 1) + zero_width_characters = [ + '\N{COMBINING ACUTE ACCENT}', + '\N{ZERO WIDTH JOINER}', + ] + for c in zero_width_characters: + with self.subTest(character=c): + self.assertEqual(str_width(c), 0) + characters = [chr(99989), chr(99999)] for c in characters: self.assertEqual(str_width(c), 2) @@ -25,6 +44,8 @@ class TestUtils(TestCase): self.assertEqual(wlen('hello'), 5) self.assertEqual(wlen('hello' + '\x1a'), 7) + self.assertEqual(wlen('e\N{COMBINING ACUTE ACCENT}'), 1) + self.assertEqual(wlen('a\N{ZERO WIDTH JOINER}b'), 2) def test_prev_next_window(self): def gen_normal(): @@ -60,3 +81,25 @@ class TestUtils(TestCase): self.assertEqual(next(pnw), (3, 4, None)) with self.assertRaises(ZeroDivisionError): next(pnw) + + def test_gen_colors_keyword_highlighting(self): + cases = [ + # no highlights + ("a.set", [(".", "op")]), + ("obj.list", [(".", "op")]), + ("obj.match", [(".", "op")]), + ("b. \\\n format", [(".", "op")]), + # highlights + ("set", [("set", "builtin")]), + ("list", [("list", "builtin")]), + (" \n dict", [("dict", "builtin")]), + ] + for code, expected_highlights in cases: + with self.subTest(code=code): + colors = list(gen_colors(code)) + # Extract (text, tag) pairs for comparison + actual_highlights = [] + for color in colors: + span_text = code[color.span.start:color.span.end + 1] + actual_highlights.append((span_text, color.tag)) + self.assertEqual(actual_highlights, expected_highlights) diff --git a/Lib/test/test_pystats.py b/Lib/test/test_pystats.py new file mode 100644 index 00000000000..c50cecfcfdd --- /dev/null +++ b/Lib/test/test_pystats.py @@ -0,0 +1,215 @@ +import sys +import textwrap +import unittest +from test.support import script_helper + +# This function is available for the --enable-pystats config. +HAVE_PYSTATS = hasattr(sys, '_stats_on') + +TEST_TEMPLATE = """ + import sys + import threading + import time + + THREADS = 2 + + class A: + pass + + class B: + pass + + def modify_class(): + # This is used as a rare event we can assume doesn't happen unless we do it. + # It increments the "Rare event (set_class)" count. + a = A() + a.__class__ = B + + TURNED_ON = False + def stats_on(): + global TURNED_ON + sys._stats_on() + TURNED_ON = True + + TURNED_OFF = False + def stats_off(): + global TURNED_OFF + sys._stats_off() + TURNED_OFF = True + + CLEARED = False + def stats_clear(): + global CLEARED + sys._stats_clear() + CLEARED = True + + def func_start(): + pass + + def func_end(): + pass + + def func_test(thread_id): + pass + + _TEST_CODE_ + + func_start() + threads = [] + for i in range(THREADS): + t = threading.Thread(target=func_test, args=(i,)) + threads.append(t) + t.start() + for t in threads: + t.join() + func_end() + """ + + +def run_test_code( + test_code, + args=[], + env_vars=None, +): + """Run test code and return the value of the "set_class" stats counter. + """ + code = textwrap.dedent(TEST_TEMPLATE) + code = code.replace('_TEST_CODE_', textwrap.dedent(test_code)) + script_args = args + ['-c', code] + env_vars = env_vars or {} + res, _ = script_helper.run_python_until_end(*script_args, **env_vars) + stderr = res.err.decode("ascii", "backslashreplace") + for line in stderr.split('\n'): + if 'Rare event (set_class)' in line: + label, _, value = line.partition(':') + return value.strip() + return '' + + +@unittest.skipUnless(HAVE_PYSTATS, "requires pystats build option") +class TestPyStats(unittest.TestCase): + """Tests for pystats functionality (requires --enable-pystats build + option). + """ + + def test_stats_toggle_on(self): + """Check the toggle on functionality. + """ + code = """ + def func_start(): + modify_class() + """ + + # If turned on with command line flag, should get one count. + stat_count = run_test_code(code, args=['-X', 'pystats']) + self.assertEqual(stat_count, '1') + + # If turned on with env var, should get one count. + stat_count = run_test_code(code, env_vars={'PYTHONSTATS': '1'}) + self.assertEqual(stat_count, '1') + + # If not turned on, should be no counts. + stat_count = run_test_code(code) + self.assertEqual(stat_count, '') + + code = """ + def func_start(): + modify_class() + sys._stats_on() + modify_class() + """ + # Not initially turned on but enabled by sys._stats_on(), should get + # one count. + stat_count = run_test_code(code) + self.assertEqual(stat_count, '1') + + def test_stats_toggle_on_thread(self): + """Check the toggle on functionality when threads are used. + """ + code = """ + def func_test(thread_id): + if thread_id == 0: + modify_class() + stats_on() + modify_class() + else: + while not TURNED_ON: + pass + modify_class() + """ + # Turning on in one thread will count in other thread. + stat_count = run_test_code(code) + self.assertEqual(stat_count, '2') + + code = """ + def func_test(thread_id): + if thread_id == 0: + modify_class() + stats_off() + modify_class() + else: + while not TURNED_OFF: + pass + modify_class() + """ + # Turning off in one thread will not count in other threads. + stat_count = run_test_code(code, args=['-X', 'pystats']) + self.assertEqual(stat_count, '1') + + def test_thread_exit_merge(self): + """Check that per-thread stats (when free-threading enabled) are merged. + """ + code = """ + def func_test(thread_id): + modify_class() + if thread_id == 0: + raise SystemExit + """ + # Stats from a thread exiting early should still be counted. + stat_count = run_test_code(code, args=['-X', 'pystats']) + self.assertEqual(stat_count, '2') + + def test_stats_dump(self): + """Check that sys._stats_dump() works. + """ + code = """ + def func_test(thread_id): + if thread_id == 0: + stats_on() + else: + while not TURNED_ON: + pass + modify_class() + sys._stats_dump() + stats_off() + """ + # Stats from a thread exiting early should still be counted. + stat_count = run_test_code(code) + self.assertEqual(stat_count, '1') + + def test_stats_clear(self): + """Check that sys._stats_clear() works. + """ + code = """ + ready = False + def func_test(thread_id): + global ready + if thread_id == 0: + stats_on() + modify_class() + while not ready: + pass # wait until other thread has called modify_class() + stats_clear() # clears stats for all threads + else: + while not TURNED_ON: + pass + modify_class() + ready = True + """ + # Clearing stats will clear for all threads + stat_count = run_test_code(code) + self.assertEqual(stat_count, '0') + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_raise.py b/Lib/test/test_raise.py index dcf0753bc82..645ef291a58 100644 --- a/Lib/test/test_raise.py +++ b/Lib/test/test_raise.py @@ -186,18 +186,14 @@ class TestCause(unittest.TestCase): self.fail("No exception raised") def test_class_cause_nonexception_result(self): - class ConstructsNone(BaseException): - @classmethod + # See https://github.com/python/cpython/issues/140530. + class ConstructMortal(BaseException): def __new__(*args, **kwargs): - return None - try: - raise IndexError from ConstructsNone - except TypeError as e: - self.assertIn("should have returned an instance of BaseException", str(e)) - except IndexError: - self.fail("Wrong kind of exception raised") - else: - self.fail("No exception raised") + return ["mortal value"] + + msg = ".*should have returned an instance of BaseException.*" + with self.assertRaisesRegex(TypeError, msg): + raise IndexError from ConstructMortal def test_instance_cause(self): cause = KeyError() diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py index 3870b153688..2c9c290e890 100644 --- a/Lib/test/test_range.py +++ b/Lib/test/test_range.py @@ -470,6 +470,16 @@ class RangeTest(unittest.TestCase): it.__setstate__(2**64 - 7) self.assertEqual(list(it), [12, 10]) + def test_iterator_invalid_setstate(self): + for invalid_value in (1.0, ""): + ranges = (('rangeiter', range(10, 100, 2)), + ('longrangeiter', range(10, 2**65, 2))) + for rng_name, rng in ranges: + with self.subTest(invalid_value=invalid_value, range=rng_name): + it = iter(rng) + with self.assertRaises(TypeError): + it.__setstate__(invalid_value) + def test_odd_bug(self): # This used to raise a "SystemError: NULL result without error" # because the range validation step was eating the exception diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 993652d2e88..9f6f04bf6b8 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -5,6 +5,7 @@ from test.support import (gc_collect, bigmemtest, _2G, import locale import re import string +import sys import unittest import warnings from re import Scanner @@ -1638,6 +1639,24 @@ class ReTests(unittest.TestCase): (['sum', 'op=', 3, 'op*', 'foo', 'op+', 312.5, 'op+', 'bar'], '')) + def test_bug_gh140797(self): + # gh140797: Capturing groups are not allowed in re.Scanner + + msg = r"Cannot use capturing groups in re\.Scanner" + # Capturing group throws an error + with self.assertRaisesRegex(ValueError, msg): + Scanner([("(a)b", None)]) + + # Named Group + with self.assertRaisesRegex(ValueError, msg): + Scanner([("(?P<name>a)", None)]) + + # Non-capturing groups should pass normally + s = Scanner([("(?:a)b", lambda scanner, token: token)]) + result, rem = s.scan("ab") + self.assertEqual(result,['ab']) + self.assertEqual(rem,'') + def test_bug_448951(self): # bug 448951 (similar to 429357, but with single char match) # (Also test greedy matches.) @@ -2177,6 +2196,8 @@ class ReTests(unittest.TestCase): self.assertEqual(re.fullmatch('[a-c]+', 'ABC', re.I).span(), (0, 3)) @unittest.skipIf(linked_to_musl(), "musl libc issue, bpo-46390") + @unittest.skipIf(sys.platform.startswith("sunos"), + "test doesn't work on Solaris, gh-91214") def test_locale_caching(self): # Issue #22410 oldlocale = locale.setlocale(locale.LC_CTYPE) @@ -2214,6 +2235,8 @@ class ReTests(unittest.TestCase): self.assertIsNone(re.match(b'(?Li)\xe5', b'\xc5')) @unittest.skipIf(linked_to_musl(), "musl libc issue, bpo-46390") + @unittest.skipIf(sys.platform.startswith("sunos"), + "test doesn't work on Solaris, gh-91214") def test_locale_compiled(self): oldlocale = locale.setlocale(locale.LC_CTYPE) self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale) @@ -3111,5 +3134,15 @@ class ExternalTests(unittest.TestCase): self.assertTrue(obj.search(s)) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(re, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index 45192fe5082..3982686dd10 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -413,6 +413,24 @@ readline.write_history_file(history_file) # So, we've only tested that the read did not fail. # See TestHistoryManipulation for the full test. + @unittest.skipUnless(hasattr(readline, "get_pre_input_hook"), + "get_pre_input_hook not available") + def test_get_pre_input_hook(self): + # Save and restore the original hook to avoid side effects + original_hook = readline.get_pre_input_hook() + self.addCleanup(readline.set_pre_input_hook, original_hook) + + # Test that get_pre_input_hook returns None when no hook is set + readline.set_pre_input_hook(None) + self.assertIsNone(readline.get_pre_input_hook()) + + # Set a hook and verify we can retrieve it + def my_hook(): + pass + + readline.set_pre_input_hook(my_hook) + self.assertIs(readline.get_pre_input_hook(), my_hook) + @unittest.skipUnless(support.Py_GIL_DISABLED, 'these tests can only possibly fail with GIL disabled') class FreeThreadingTest(unittest.TestCase): diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 5bc3c5924b0..c27b3c86292 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -182,6 +182,22 @@ class ParseArgsTestCase(unittest.TestCase): self.assertTrue(regrtest.randomize) self.assertIsInstance(regrtest.random_seed, int) + def test_no_randomize(self): + ns = self.parse_args([]) + self.assertIs(ns.randomize, False) + + ns = self.parse_args(["--randomize"]) + self.assertIs(ns.randomize, True) + + ns = self.parse_args(["--no-randomize"]) + self.assertIs(ns.randomize, False) + + ns = self.parse_args(["--randomize", "--no-randomize"]) + self.assertIs(ns.randomize, False) + + ns = self.parse_args(["--no-randomize", "--randomize"]) + self.assertIs(ns.randomize, False) + def test_randseed(self): ns = self.parse_args(['--randseed', '12345']) self.assertEqual(ns.random_seed, 12345) @@ -189,6 +205,10 @@ class ParseArgsTestCase(unittest.TestCase): self.checkError(['--randseed'], 'expected one argument') self.checkError(['--randseed', 'foo'], 'invalid int value') + ns = self.parse_args(['--randseed', '12345', '--no-randomize']) + self.assertEqual(ns.random_seed, 12345) + self.assertFalse(ns.randomize) + def test_fromfile(self): for opt in '-f', '--fromfile': with self.subTest(opt=opt): @@ -428,15 +448,17 @@ class ParseArgsTestCase(unittest.TestCase): return regrtest - def check_ci_mode(self, args, use_resources, rerun=True): + def check_ci_mode(self, args, use_resources, + *, rerun=True, randomize=True, output_on_failure=True): regrtest = self.create_regrtest(args) self.assertEqual(regrtest.num_workers, -1) self.assertEqual(regrtest.want_rerun, rerun) - self.assertTrue(regrtest.randomize) + self.assertEqual(regrtest.fail_rerun, False) + self.assertEqual(regrtest.randomize, randomize) self.assertIsInstance(regrtest.random_seed, int) self.assertTrue(regrtest.fail_env_changed) self.assertTrue(regrtest.print_slowest) - self.assertTrue(regrtest.output_on_failure) + self.assertEqual(regrtest.output_on_failure, output_on_failure) self.assertEqual(sorted(regrtest.use_resources), sorted(use_resources)) return regrtest @@ -463,12 +485,29 @@ class ParseArgsTestCase(unittest.TestCase): use_resources.remove('network') self.check_ci_mode(args, use_resources) + def test_fast_ci_verbose(self): + args = ['--fast-ci', '--verbose'] + use_resources = sorted(cmdline.ALL_RESOURCES) + use_resources.remove('cpu') + regrtest = self.check_ci_mode(args, use_resources, + output_on_failure=False) + self.assertEqual(regrtest.verbose, True) + def test_slow_ci(self): args = ['--slow-ci'] use_resources = sorted(cmdline.ALL_RESOURCES) regrtest = self.check_ci_mode(args, use_resources) self.assertEqual(regrtest.timeout, 20 * 60) + def test_ci_no_randomize(self): + all_resources = set(cmdline.ALL_RESOURCES) + self.check_ci_mode( + ["--slow-ci", "--no-randomize"], all_resources, randomize=False + ) + self.check_ci_mode( + ["--fast-ci", "--no-randomize"], all_resources - {'cpu'}, randomize=False + ) + def test_dont_add_python_opts(self): args = ['--dont-add-python-opts'] ns = cmdline._parse_args(args) diff --git a/Lib/test/test_remote_pdb.py b/Lib/test/test_remote_pdb.py index 280e2444ef7..ede99de9819 100644 --- a/Lib/test/test_remote_pdb.py +++ b/Lib/test/test_remote_pdb.py @@ -1539,6 +1539,9 @@ class PdbAttachTestCase(unittest.TestCase): redirect_stdout(client_stdout), redirect_stderr(client_stderr), unittest.mock.patch("sys.argv", ["pdb", "-p", str(process.pid)]), + unittest.mock.patch( + "pdb.exit_with_permission_help_text", side_effect=PermissionError + ), ): try: pdb.main() @@ -1587,5 +1590,17 @@ class PdbAttachTestCase(unittest.TestCase): self.assertNotIn("while x == 1", output["client"]["stdout"]) self.assertIn("while x == 1", re.sub("\x1b[^m]*m", "", output["client"]["stdout"])) + def test_attach_to_non_existent_process(self): + with force_color(False): + result = subprocess.run([sys.executable, "-m", "pdb", "-p", "999999"], text=True, capture_output=True) + self.assertNotEqual(result.returncode, 0) + if sys.platform == "darwin": + # On MacOS, attaching to a non-existent process gives PermissionError + error = "The specified process cannot be attached to due to insufficient permissions" + else: + error = "Cannot attach to pid 999999, please make sure that the process exists" + self.assertIn(error, result.stdout) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 54e69277282..042aa84b35d 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -5,6 +5,7 @@ import select import subprocess import sys import unittest +from functools import partial from textwrap import dedent from test import support from test.support import ( @@ -27,7 +28,7 @@ if not has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") -def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): +def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, custom=False, **kw): """Run the Python REPL with the given arguments. kw is extra keyword args to pass to subprocess.Popen. Returns a Popen @@ -41,7 +42,11 @@ def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): # path may be used by PyConfig_Get("module_search_paths") to build the # default module search path. stdin_fname = os.path.join(os.path.dirname(sys.executable), "<stdin>") - cmd_line = [stdin_fname, '-I', '-i'] + cmd_line = [stdin_fname, '-I'] + # Don't re-run the built-in REPL from interactive mode + # if we're testing a custom REPL (such as the asyncio REPL). + if not custom: + cmd_line.append('-i') cmd_line.extend(args) # Set TERM=vt100, for the rationale see the comments in spawn_python() of @@ -55,6 +60,10 @@ def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): stdout=stdout, stderr=stderr, **kw) + +spawn_asyncio_repl = partial(spawn_repl, "-m", "asyncio", custom=True) + + def run_on_interactive_mode(source): """Spawn a new Python interpreter, pass the given input source code from the stdin and return the @@ -359,7 +368,7 @@ class TestInteractiveModeSyntaxErrors(unittest.TestCase): class TestAsyncioREPL(unittest.TestCase): def test_multiple_statements_fail_early(self): user_input = "1 / 0; print(f'afterwards: {1+1}')" - p = spawn_repl("-m", "asyncio") + p = spawn_asyncio_repl() p.stdin.write(user_input) output = kill_python(p) self.assertIn("ZeroDivisionError", output) @@ -371,7 +380,7 @@ class TestAsyncioREPL(unittest.TestCase): var = ContextVar("var", default="failed") var.set("ok") """) - p = spawn_repl("-m", "asyncio") + p = spawn_asyncio_repl() p.stdin.write(user_input) user_input2 = dedent(""" print(f"toplevel contextvar test: {var.get()}") @@ -387,7 +396,7 @@ class TestAsyncioREPL(unittest.TestCase): from contextvars import ContextVar var = ContextVar('var', default='failed') """) - p = spawn_repl("-m", "asyncio") + p = spawn_asyncio_repl() p.stdin.write(user_input) user_input2 = "async def set_var(): var.set('ok')\n" p.stdin.write(user_input2) diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py index 8d89e2a8224..e33723cc70c 100644 --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -16,6 +16,14 @@ class BaseRobotTest: bad = [] site_maps = None + def __init_subclass__(cls): + super().__init_subclass__() + # Remove tests that do nothing. + if not cls.good: + cls.test_good_urls = None + if not cls.bad: + cls.test_bad_urls = None + def setUp(self): lines = io.StringIO(self.robots_txt).readlines() self.parser = urllib.robotparser.RobotFileParser() @@ -231,9 +239,16 @@ class DisallowQueryStringTest(BaseRobotTest, unittest.TestCase): robots_txt = """\ User-agent: * Disallow: /some/path?name=value +Disallow: /another/path? +Disallow: /yet/one/path?name=value&more """ - good = ['/some/path'] - bad = ['/some/path?name=value'] + good = ['/some/path', '/some/path?', + '/some/path%3Fname=value', '/some/path?name%3Dvalue', + '/another/path', '/another/path%3F', + '/yet/one/path?name=value%26more'] + bad = ['/some/path?name=value' + '/another/path?', '/another/path?name=value', + '/yet/one/path?name=value&more'] class UseFirstUserAgentWildcardTest(BaseRobotTest, unittest.TestCase): @@ -249,15 +264,79 @@ Disallow: /another/path bad = ['/some/path'] -class EmptyQueryStringTest(BaseRobotTest, unittest.TestCase): - # normalize the URL first (#17403) +class PercentEncodingTest(BaseRobotTest, unittest.TestCase): robots_txt = """\ User-agent: * -Allow: /some/path? -Disallow: /another/path? - """ - good = ['/some/path?'] - bad = ['/another/path?'] +Disallow: /a1/Z-._~ # unreserved characters +Disallow: /a2/%5A%2D%2E%5F%7E # percent-encoded unreserved characters +Disallow: /u1/%F0%9F%90%8D # percent-encoded ASCII Unicode character +Disallow: /u2/%f0%9f%90%8d +Disallow: /u3/\U0001f40d # raw non-ASCII Unicode character +Disallow: /v1/%F0 # percent-encoded non-ASCII octet +Disallow: /v2/%f0 +Disallow: /v3/\udcf0 # raw non-ASCII octet +Disallow: /p1%xy # raw percent +Disallow: /p2% +Disallow: /p3%25xy # percent-encoded percent +Disallow: /p4%2525xy # double percent-encoded percent +Disallow: /john%20smith # space +Disallow: /john doe +Disallow: /trailingspace%20 +Disallow: /question%3Fq=v # not query +Disallow: /hash%23f # not fragment +Disallow: /dollar%24 +Disallow: /asterisk%2A +Disallow: /sub/dir +Disallow: /slash%2F +Disallow: /query/question?q=%3F +Disallow: /query/raw/question?q=? +Disallow: /query/eq?q%3Dv +Disallow: /query/amp?q=v%26a +""" + good = [ + '/u1/%F0', '/u1/%f0', + '/u2/%F0', '/u2/%f0', + '/u3/%F0', '/u3/%f0', + '/p1%2525xy', '/p2%f0', '/p3%2525xy', '/p4%xy', '/p4%25xy', + '/question?q=v', + '/dollar', '/asterisk', + '/query/eq?q=v', + '/query/amp?q=v&a', + ] + bad = [ + '/a1/Z-._~', '/a1/%5A%2D%2E%5F%7E', + '/a2/Z-._~', '/a2/%5A%2D%2E%5F%7E', + '/u1/%F0%9F%90%8D', '/u1/%f0%9f%90%8d', '/u1/\U0001f40d', + '/u2/%F0%9F%90%8D', '/u2/%f0%9f%90%8d', '/u2/\U0001f40d', + '/u3/%F0%9F%90%8D', '/u3/%f0%9f%90%8d', '/u3/\U0001f40d', + '/v1/%F0', '/v1/%f0', '/v1/\udcf0', '/v1/\U0001f40d', + '/v2/%F0', '/v2/%f0', '/v2/\udcf0', '/v2/\U0001f40d', + '/v3/%F0', '/v3/%f0', '/v3/\udcf0', '/v3/\U0001f40d', + '/p1%xy', '/p1%25xy', + '/p2%', '/p2%25', '/p2%2525', '/p2%xy', + '/p3%xy', '/p3%25xy', + '/p4%2525xy', + '/john%20smith', '/john smith', + '/john%20doe', '/john doe', + '/trailingspace%20', '/trailingspace ', + '/question%3Fq=v', + '/hash#f', '/hash%23f', + '/dollar$', '/dollar%24', + '/asterisk*', '/asterisk%2A', + '/sub/dir', '/sub%2Fdir', + '/slash%2F', '/slash/', + '/query/question?q=?', '/query/question?q=%3F', + '/query/raw/question?q=?', '/query/raw/question?q=%3F', + '/query/eq?q%3Dv', + '/query/amp?q=v%26a', + ] + # other reserved characters + for c in ":/#[]@!$&'()*+,;=": + robots_txt += f'Disallow: /raw{c}\nDisallow: /pc%{ord(c):02X}\n' + bad.append(f'/raw{c}') + bad.append(f'/raw%{ord(c):02X}') + bad.append(f'/pc{c}') + bad.append(f'/pc%{ord(c):02X}') class DefaultEntryTest(BaseRequestRateTest, unittest.TestCase): @@ -299,26 +378,17 @@ Disallow: /cyberworld/map/\ self.assertEqual(str(self.parser), self.expected_output) -class RobotHandler(BaseHTTPRequestHandler): - - def do_GET(self): - self.send_error(403, "Forbidden access") - - def log_message(self, format, *args): - pass - - @unittest.skipUnless( support.has_socket_support, "Socket server requires working socket." ) -class PasswordProtectedSiteTestCase(unittest.TestCase): +class BaseLocalNetworkTestCase: def setUp(self): # clear _opener global variable self.addCleanup(urllib.request.urlcleanup) - self.server = HTTPServer((socket_helper.HOST, 0), RobotHandler) + self.server = HTTPServer((socket_helper.HOST, 0), self.RobotHandler) self.t = threading.Thread( name='HTTPServer serving', @@ -335,6 +405,57 @@ class PasswordProtectedSiteTestCase(unittest.TestCase): self.t.join() self.server.server_close() + +SAMPLE_ROBOTS_TXT = b'''\ +User-agent: test_robotparser +Disallow: /utf8/\xf0\x9f\x90\x8d +Disallow: /non-utf8/\xf0 +Disallow: //[spam]/path +''' + + +class LocalNetworkTestCase(BaseLocalNetworkTestCase, unittest.TestCase): + class RobotHandler(BaseHTTPRequestHandler): + + def do_GET(self): + self.send_response(200) + self.end_headers() + self.wfile.write(SAMPLE_ROBOTS_TXT) + + def log_message(self, format, *args): + pass + + @threading_helper.reap_threads + def testRead(self): + # Test that reading a weird robots.txt doesn't fail. + addr = self.server.server_address + url = f'http://{socket_helper.HOST}:{addr[1]}' + robots_url = url + '/robots.txt' + parser = urllib.robotparser.RobotFileParser() + parser.set_url(robots_url) + parser.read() + # And it can even interpret the weird paths in some reasonable way. + agent = 'test_robotparser' + self.assertTrue(parser.can_fetch(agent, robots_url)) + self.assertTrue(parser.can_fetch(agent, url + '/utf8/')) + self.assertFalse(parser.can_fetch(agent, url + '/utf8/\U0001f40d')) + self.assertFalse(parser.can_fetch(agent, url + '/utf8/%F0%9F%90%8D')) + self.assertFalse(parser.can_fetch(agent, url + '/utf8/\U0001f40d')) + self.assertTrue(parser.can_fetch(agent, url + '/non-utf8/')) + self.assertFalse(parser.can_fetch(agent, url + '/non-utf8/%F0')) + self.assertFalse(parser.can_fetch(agent, url + '/non-utf8/\U0001f40d')) + self.assertFalse(parser.can_fetch(agent, url + '/%2F[spam]/path')) + + +class PasswordProtectedSiteTestCase(BaseLocalNetworkTestCase, unittest.TestCase): + class RobotHandler(BaseHTTPRequestHandler): + + def do_GET(self): + self.send_error(403, "Forbidden access") + + def log_message(self, format, *args): + pass + @threading_helper.reap_threads def testPasswordProtectedSite(self): addr = self.server.server_address diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index a2a07c04f58..254a009a697 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -20,9 +20,11 @@ from test.support import ( requires_subprocess, verbose, ) +from test import support from test.support.import_helper import forget, make_legacy_pyc, unload from test.support.os_helper import create_empty_file, temp_dir, FakePath from test.support.script_helper import make_script, make_zip_script +from test.test_importlib.util import temporary_pycache_prefix import runpy @@ -55,7 +57,6 @@ nested = runpy._run_module_code('x=1\\n', mod_name='<run>') implicit_namespace = { "__name__": None, "__file__": None, - "__cached__": None, "__package__": None, "__doc__": None, "__spec__": None @@ -284,7 +285,6 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): def _fix_ns_for_legacy_pyc(self, ns, alter_sys): char_to_add = "c" ns["__file__"] += char_to_add - ns["__cached__"] = ns["__file__"] spec = ns["__spec__"] new_spec = importlib.util.spec_from_file_location(spec.name, ns["__file__"]) @@ -304,7 +304,6 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): expected_ns.update({ "__name__": mod_name, "__file__": mod_fname, - "__cached__": mod_spec.cached, "__package__": mod_name.rpartition(".")[0], "__spec__": mod_spec, }) @@ -345,7 +344,6 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): expected_ns.update({ "__name__": mod_name, "__file__": mod_fname, - "__cached__": importlib.util.cache_from_source(mod_fname), "__package__": pkg_name, "__spec__": mod_spec, }) @@ -550,7 +548,6 @@ from ..uncle.cousin import nephew expected_ns.update({ "__name__": run_name, "__file__": mod_fname, - "__cached__": importlib.util.cache_from_source(mod_fname), "__package__": mod_name.rpartition(".")[0], "__spec__": mod_spec, }) @@ -630,7 +627,6 @@ class RunPathTestCase(unittest.TestCase, CodeExecutionMixin): expected_ns.update({ "__name__": expected_name, "__file__": expected_file, - "__cached__": mod_cached, "__package__": "", "__spec__": mod_spec, "run_argv0": expected_argv0, @@ -763,6 +759,47 @@ s = "non-ASCII: h\xe9" result = run_path(filename) self.assertEqual(result['s'], "non-ASCII: h\xe9") + def test_run_module_filter_syntax_warnings_by_module(self): + module_re = r'test\.test_import\.data\.syntax_warnings\z' + with (temp_dir() as tmpdir, + temporary_pycache_prefix(tmpdir), + warnings.catch_warnings(record=True) as wlog): + warnings.simplefilter('error') + warnings.filterwarnings('always', module=module_re) + warnings.filterwarnings('error', module='syntax_warnings') + ns = run_module('test.test_import.data.syntax_warnings') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + filename = ns['__file__'] + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + + def test_run_path_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'<run_path>\z') + warnings.filterwarnings('error', module='test') + warnings.filterwarnings('error', module='syntax_warnings') + warnings.filterwarnings('error', + module=r'test\.test_import\.data\.syntax_warnings') + run_path(filename) + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'package\.script\z') + warnings.filterwarnings('error', module='<run_path>') + warnings.filterwarnings('error', module='test') + warnings.filterwarnings('error', module='syntax_warnings') + warnings.filterwarnings('error', + module=r'test\.test_import\.data\.syntax_warnings') + run_path(filename, run_name='package.script') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + @force_not_colorized_test_class class TestExit(unittest.TestCase): diff --git a/Lib/test/test_shlex.py b/Lib/test/test_shlex.py index a13ddcb76b7..2a355abdeeb 100644 --- a/Lib/test/test_shlex.py +++ b/Lib/test/test_shlex.py @@ -330,6 +330,7 @@ class ShlexTest(unittest.TestCase): unsafe = '"`$\\!' + unicode_sample self.assertEqual(shlex.quote(''), "''") + self.assertEqual(shlex.quote(None), "''") self.assertEqual(shlex.quote(safeunquoted), safeunquoted) self.assertEqual(shlex.quote('test file name'), "'test file name'") for u in unsafe: @@ -338,6 +339,8 @@ class ShlexTest(unittest.TestCase): for u in unsafe: self.assertEqual(shlex.quote("test%s'name'" % u), "'test%s'\"'\"'name'\"'\"''" % u) + self.assertRaises(TypeError, shlex.quote, 42) + self.assertRaises(TypeError, shlex.quote, b"abc") def testJoin(self): for split_command, command in [ diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 32fcf3162e8..e7dc5e2611c 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -466,17 +466,6 @@ class ImportSideEffectTests(unittest.TestCase): """Restore sys.path""" sys.path[:] = self.sys_path - def test_abs_paths_cached_None(self): - """Test for __cached__ is None. - - Regarding to PEP 3147, __cached__ can be None. - - See also: https://bugs.python.org/issue30167 - """ - sys.modules['test'].__cached__ = None - site.abs_paths() - self.assertIsNone(sys.modules['test'].__cached__) - def test_no_duplicate_paths(self): # No duplicate paths should exist in sys.path # Handled by removeduppaths() @@ -855,12 +844,15 @@ class CommandLineTests(unittest.TestCase): return 10, None def invoke_command_line(self, *args): - args = ["-m", "site", *args] + cmd_args = [] + if sys.flags.no_user_site: + cmd_args.append("-s") + cmd_args.extend(["-m", "site", *args]) with EnvironmentVarGuard() as env: env["PYTHONUTF8"] = "1" env["PYTHONIOENCODING"] = "utf-8" - proc = spawn_python(*args, text=True, env=env, + proc = spawn_python(*cmd_args, text=True, env=env, encoding='utf-8', errors='replace') output = kill_python(proc) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 76fd33c7dc8..934b7137096 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -8,7 +8,9 @@ from test.support.import_helper import ensure_lazy_imports import _thread as thread import array import contextlib +import decimal import errno +import fractions import gc import io import itertools @@ -52,6 +54,7 @@ MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') VSOCKPORT = 1234 AIX = platform.system() == "AIX" +SOLARIS = sys.platform.startswith("sunos") WSL = "microsoft-standard-WSL" in platform.release() try: @@ -1173,7 +1176,10 @@ class GeneralModuleTests(unittest.TestCase): 'socket.if_indextoname() not available.') @support.skip_android_selinux('if_indextoname') def testInvalidInterfaceIndexToName(self): - self.assertRaises(OSError, socket.if_indextoname, 0) + with self.assertRaises(OSError) as cm: + socket.if_indextoname(0) + self.assertIsNotNone(cm.exception.errno) + self.assertRaises(ValueError, socket.if_indextoname, -1) self.assertRaises(OverflowError, socket.if_indextoname, 2**1000) self.assertRaises(TypeError, socket.if_indextoname, '_DEADBEEF') @@ -1193,8 +1199,11 @@ class GeneralModuleTests(unittest.TestCase): 'socket.if_nametoindex() not available.') @support.skip_android_selinux('if_nametoindex') def testInvalidInterfaceNameToIndex(self): + with self.assertRaises(OSError) as cm: + socket.if_nametoindex("_DEADBEEF") + self.assertIsNotNone(cm.exception.errno) + self.assertRaises(TypeError, socket.if_nametoindex, 0) - self.assertRaises(OSError, socket.if_nametoindex, '_DEADBEEF') @unittest.skipUnless(hasattr(sys, 'getrefcount'), 'test needs sys.getrefcount()') @@ -1309,10 +1318,20 @@ class GeneralModuleTests(unittest.TestCase): self.assertEqual(s.gettimeout(), None) # Set the default timeout to 10, and see if it propagates - with socket_setdefaulttimeout(10): - self.assertEqual(socket.getdefaulttimeout(), 10) + with socket_setdefaulttimeout(10.125): + self.assertEqual(socket.getdefaulttimeout(), 10.125) with socket.socket() as sock: - self.assertEqual(sock.gettimeout(), 10) + self.assertEqual(sock.gettimeout(), 10.125) + + socket.setdefaulttimeout(decimal.Decimal('11.125')) + self.assertEqual(socket.getdefaulttimeout(), 11.125) + with socket.socket() as sock: + self.assertEqual(sock.gettimeout(), 11.125) + + socket.setdefaulttimeout(fractions.Fraction(97, 8)) + self.assertEqual(socket.getdefaulttimeout(), 12.125) + with socket.socket() as sock: + self.assertEqual(sock.gettimeout(), 12.125) # Reset the default timeout to None, and see if it propagates socket.setdefaulttimeout(None) @@ -2392,6 +2411,45 @@ class ISOTPTest(unittest.TestCase): socket.CAN_ISOTP socket.SOCK_DGRAM + @unittest.skipUnless(hasattr(socket, "SOL_CAN_ISOTP"), + "missing <linux/can/isotp.h>") + def testISOTP(self): + socket.SOL_CAN_ISOTP + + socket.CAN_ISOTP_OPTS + socket.CAN_ISOTP_RECV_FC + + socket.CAN_ISOTP_TX_STMIN + socket.CAN_ISOTP_RX_STMIN + socket.CAN_ISOTP_LL_OPTS + + socket.CAN_ISOTP_LISTEN_MODE + socket.CAN_ISOTP_EXTEND_ADDR + socket.CAN_ISOTP_TX_PADDING + socket.CAN_ISOTP_RX_PADDING + socket.CAN_ISOTP_CHK_PAD_LEN + socket.CAN_ISOTP_CHK_PAD_DATA + socket.CAN_ISOTP_HALF_DUPLEX + socket.CAN_ISOTP_FORCE_TXSTMIN + socket.CAN_ISOTP_FORCE_RXSTMIN + socket.CAN_ISOTP_RX_EXT_ADDR + socket.CAN_ISOTP_WAIT_TX_DONE + # This constant is not always available + # socket.CAN_ISOTP_SF_BROADCAST + + socket.CAN_ISOTP_DEFAULT_FLAGS + socket.CAN_ISOTP_DEFAULT_EXT_ADDRESS + socket.CAN_ISOTP_DEFAULT_PAD_CONTENT + socket.CAN_ISOTP_DEFAULT_FRAME_TXTIME + socket.CAN_ISOTP_DEFAULT_RECV_BS + socket.CAN_ISOTP_DEFAULT_EXT_ADDRESS + socket.CAN_ISOTP_DEFAULT_RECV_STMIN + socket.CAN_ISOTP_DEFAULT_RECV_WFTMAX + + socket.CAN_ISOTP_DEFAULT_LL_MTU + socket.CAN_ISOTP_DEFAULT_LL_TX_DL + socket.CAN_ISOTP_DEFAULT_LL_TX_FLAGS + def testCreateSocket(self): with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s: pass @@ -3922,6 +3980,10 @@ class CmsgMacroTests(unittest.TestCase): # Test CMSG_SPACE() with various valid and invalid values, # checking the assumptions used by sendmsg(). toobig = self.socklen_t_limit - socket.CMSG_SPACE(1) + 1 + if SOLARIS and platform.processor() == "sparc": + # On Solaris SPARC, number of bytes returned by socket.CMSG_SPACE + # increases at different lengths; see gh-91214. + toobig -= 3 values = list(range(257)) + list(range(toobig - 257, toobig)) last = socket.CMSG_SPACE(0) @@ -4068,6 +4130,7 @@ class SCMRightsTest(SendrecvmsgServerTimeoutBase): self.createAndSendFDs(1) @unittest.skipIf(is_apple, "skipping, see issue #12958") + @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparate(self): @@ -4079,6 +4142,7 @@ class SCMRightsTest(SendrecvmsgServerTimeoutBase): @testFDPassSeparate.client_skip @unittest.skipIf(is_apple, "skipping, see issue #12958") + @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") def _testFDPassSeparate(self): fd0, fd1 = self.newFDs(2) @@ -4092,6 +4156,7 @@ class SCMRightsTest(SendrecvmsgServerTimeoutBase): len(MSG)) @unittest.skipIf(is_apple, "skipping, see issue #12958") + @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparateMinSpace(self): @@ -4106,6 +4171,7 @@ class SCMRightsTest(SendrecvmsgServerTimeoutBase): @testFDPassSeparateMinSpace.client_skip @unittest.skipIf(is_apple, "skipping, see issue #12958") + @unittest.skipIf(SOLARIS, "skipping, see gh-91214") @unittest.skipIf(AIX, "skipping, see issue #22397") def _testFDPassSeparateMinSpace(self): fd0, fd1 = self.newFDs(2) @@ -7079,8 +7145,14 @@ class LinuxKernelCryptoAPI(unittest.TestCase): self.assertEqual(len(dec), msglen * multiplier) self.assertEqual(dec, msg * multiplier) - @support.requires_linux_version(4, 9) # see issue29324 + @support.requires_linux_version(4, 9) # see gh-73510 def test_aead_aes_gcm(self): + kernel_version = support._get_kernel_version("Linux") + if kernel_version is not None: + if kernel_version >= (6, 16) and kernel_version < (6, 18): + # See https://github.com/python/cpython/issues/139310. + self.skipTest("upstream Linux kernel issue") + key = bytes.fromhex('c939cc13397c1d37de6ae0e1cb7c423c') iv = bytes.fromhex('b3d8cc017cbb89b39e0f67e2') plain = bytes.fromhex('c3b3c41f113a31b73d9a5cd432103069') diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py index 893372cbbd0..ca33a9a6dac 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -223,12 +223,16 @@ class SocketServerTest(unittest.TestCase): self.dgram_examine) @requires_unix_sockets + @unittest.skipIf(test.support.is_apple_mobile and test.support.on_github_actions, + "gh-140702: Test fails regularly on iOS simulator on GitHub Actions") def test_UnixDatagramServer(self): self.run_server(socketserver.UnixDatagramServer, socketserver.DatagramRequestHandler, self.dgram_examine) @requires_unix_sockets + @unittest.skipIf(test.support.is_apple_mobile and test.support.on_github_actions, + "gh-140702: Test fails regularly on iOS simulator on GitHub Actions") def test_ThreadingUnixDatagramServer(self): self.run_server(socketserver.ThreadingUnixDatagramServer, socketserver.DatagramRequestHandler, @@ -511,5 +515,15 @@ class MiscTestCase(unittest.TestCase): server.server_close() +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(socketserver, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_source_encoding.py b/Lib/test/test_source_encoding.py index 1399f3fcd2d..46b291192df 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- import unittest -from test.support import script_helper, captured_stdout, requires_subprocess, requires_resource +from test import support +from test.support import script_helper from test.support.os_helper import TESTFN, unlink, rmtree from test.support.import_helper import unload import importlib @@ -64,7 +65,7 @@ class MiscSourceEncodingTest(unittest.TestCase): # two bytes in common with the UTF-8 BOM self.assertRaises(SyntaxError, eval, b'\xef\xbb\x20') - @requires_subprocess() + @support.requires_subprocess() def test_20731(self): sub = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), @@ -172,6 +173,8 @@ class MiscSourceEncodingTest(unittest.TestCase): os.unlink(TESTFN) +BUFSIZ = 2**13 + class AbstractSourceEncodingTest: def test_default_coding(self): @@ -184,14 +187,20 @@ class AbstractSourceEncodingTest: self.check_script_output(src, br"'\xc3\u20ac'") def test_second_coding_line(self): - src = (b'#\n' + src = (b'#!/usr/bin/python\n' + b'#coding:iso8859-15\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xc3\u20ac'") + + def test_second_coding_line_empty_first_line(self): + src = (b'\n' b'#coding:iso8859-15\n' b'print(ascii("\xc3\xa4"))\n') self.check_script_output(src, br"'\xc3\u20ac'") def test_third_coding_line(self): # Only first two lines are tested for a magic comment. - src = (b'#\n' + src = (b'#!/usr/bin/python\n' b'#\n' b'#coding:iso8859-15\n' b'print(ascii("\xc3\xa4"))\n') @@ -209,48 +218,197 @@ class AbstractSourceEncodingTest: b'print(ascii("\xc3\xa4"))\n') self.check_script_output(src, br"'\xc3\u20ac'") + def test_double_coding_utf8(self): + src = (b'#coding:utf-8\n' + b'#coding:latin1\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xe4'") + + def test_long_first_coding_line(self): + src = (b'#' + b' '*BUFSIZ + b'coding:iso8859-15\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xc3\u20ac'") + + def test_long_second_coding_line(self): + src = (b'#!/usr/bin/python\n' + b'#' + b' '*BUFSIZ + b'coding:iso8859-15\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xc3\u20ac'") + + def test_long_coding_line(self): + src = (b'#coding:iso-8859-15' + b' '*BUFSIZ + b'\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xc3\u20ac'") + + def test_long_coding_name(self): + src = (b'#coding:iso-8859-1-' + b'x'*BUFSIZ + b'\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xc3\xa4'") + + def test_long_first_utf8_line(self): + src = b'#' + b'\xc3\xa4'*(BUFSIZ//2) + b'\n' + self.check_script_output(src, b'') + src = b'# ' + b'\xc3\xa4'*(BUFSIZ//2) + b'\n' + self.check_script_output(src, b'') + + def test_long_second_utf8_line(self): + src = b'\n#' + b'\xc3\xa4'*(BUFSIZ//2) + b'\n' + self.check_script_output(src, b'') + src = b'\n# ' + b'\xc3\xa4'*(BUFSIZ//2) + b'\n' + self.check_script_output(src, b'') + def test_first_non_utf8_coding_line(self): src = (b'#coding:iso-8859-15 \xa4\n' b'print(ascii("\xc3\xa4"))\n') self.check_script_output(src, br"'\xc3\u20ac'") def test_second_non_utf8_coding_line(self): - src = (b'\n' + src = (b'#!/usr/bin/python\n' b'#coding:iso-8859-15 \xa4\n' b'print(ascii("\xc3\xa4"))\n') self.check_script_output(src, br"'\xc3\u20ac'") + def test_first_utf8_coding_line_error(self): + src = (b'#coding:ascii \xc3\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, br"(\(unicode error\) )?'ascii' codec can't decode byte") + + def test_second_utf8_coding_line_error(self): + src = (b'#!/usr/bin/python\n' + b'#coding:ascii \xc3\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, br"(\(unicode error\) )?'ascii' codec can't decode byte") + def test_utf8_bom(self): src = (b'\xef\xbb\xbfprint(ascii("\xc3\xa4"))\n') self.check_script_output(src, br"'\xe4'") + def test_utf8_bom_utf8_comments(self): + src = (b'\xef\xbb\xbf#\xc3\xa4\n' + b'#\xc3\xa4\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xe4'") + def test_utf8_bom_and_utf8_coding_line(self): src = (b'\xef\xbb\xbf#coding:utf-8\n' b'print(ascii("\xc3\xa4"))\n') self.check_script_output(src, br"'\xe4'") + def test_utf8_bom_and_non_utf8_first_coding_line(self): + src = (b'\xef\xbb\xbf#coding:iso-8859-15\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"encoding problem: iso-8859-15 with BOM", + lineno=1) + + def test_utf8_bom_and_non_utf8_second_coding_line(self): + src = (b'\xef\xbb\xbf#first\n' + b'#coding:iso-8859-15\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"encoding problem: iso-8859-15 with BOM", + lineno=2) + + def test_non_utf8_shebang(self): + src = (b'#!/home/\xa4/bin/python\n' + b'#coding:iso-8859-15\n' + b'print(ascii("\xc3\xa4"))\n') + self.check_script_output(src, br"'\xc3\u20ac'") + + def test_utf8_shebang_error(self): + src = (b'#!/home/\xc3\xa4/bin/python\n' + b'#coding:ascii\n' + b'raise RuntimeError\n') + self.check_script_error(src, br"(\(unicode error\) )?'ascii' codec can't decode byte") + + def test_non_utf8_shebang_error(self): + src = (b'#!/home/\xa4/bin/python\n' + b'raise RuntimeError\n') + self.check_script_error(src, br"Non-UTF-8 code starting with .* on line 1", + lineno=1) + + def test_non_utf8_second_line_error(self): + src = (b'#first\n' + b'#second\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"Non-UTF-8 code starting with .* on line 2", + lineno=2) + + def test_non_utf8_third_line_error(self): + src = (b'#first\n' + b'#second\n' + b'#third\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"Non-UTF-8 code starting with .* on line 3", + lineno=3) + + def test_utf8_bom_non_utf8_third_line_error(self): + src = (b'\xef\xbb\xbf#first\n' + b'#second\n' + b'#third\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"Non-UTF-8 code starting with .* on line 3|" + br"'utf-8' codec can't decode byte", + lineno=3) + + def test_utf_8_non_utf8_third_line_error(self): + src = (b'#coding: utf-8\n' + b'#second\n' + b'#third\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"Non-UTF-8 code starting with .* on line 3|" + br"'utf-8' codec can't decode byte", + lineno=3) + + def test_utf8_non_utf8_third_line_error(self): + src = (b'#coding: utf8\n' + b'#second\n' + b'#third\xa4\n' + b'raise RuntimeError\n') + self.check_script_error(src, + br"'utf-8' codec can't decode byte|" + br"encoding problem: utf8") + def test_crlf(self): src = (b'print(ascii("""\r\n"""))\n') - out = self.check_script_output(src, br"'\n'") + self.check_script_output(src, br"'\n'") def test_crcrlf(self): src = (b'print(ascii("""\r\r\n"""))\n') - out = self.check_script_output(src, br"'\n\n'") + self.check_script_output(src, br"'\n\n'") def test_crcrcrlf(self): src = (b'print(ascii("""\r\r\r\n"""))\n') - out = self.check_script_output(src, br"'\n\n\n'") + self.check_script_output(src, br"'\n\n\n'") def test_crcrcrlf2(self): src = (b'#coding:iso-8859-1\n' b'print(ascii("""\r\r\r\n"""))\n') - out = self.check_script_output(src, br"'\n\n\n'") + self.check_script_output(src, br"'\n\n\n'") + + def test_nul_in_first_coding_line(self): + src = (b'#coding:iso8859-15\x00\n' + b'\n' + b'\n' + b'raise RuntimeError\n') + self.check_script_error(src, br"source code (string )?cannot contain null bytes") + + def test_nul_in_second_coding_line(self): + src = (b'#!/usr/bin/python\n' + b'#coding:iso8859-15\x00\n' + b'\n' + b'raise RuntimeError\n') + self.check_script_error(src, br"source code (string )?cannot contain null bytes") class UTF8ValidatorTest(unittest.TestCase): @unittest.skipIf(not sys.platform.startswith("linux"), "Too slow to run on non-Linux platforms") - @requires_resource('cpu') + @support.requires_resource('cpu') def test_invalid_utf8(self): # This is a port of test_utf8_decode_invalid_sequences in # test_unicode.py to exercise the separate utf8 validator in @@ -316,15 +474,29 @@ class UTF8ValidatorTest(unittest.TestCase): check(b'\xF4'+cb+b'\xBF\xBF') +@support.force_not_colorized_test_class class BytesSourceEncodingTest(AbstractSourceEncodingTest, unittest.TestCase): def check_script_output(self, src, expected): - with captured_stdout() as stdout: + with support.captured_stdout() as stdout: exec(src) out = stdout.getvalue().encode('latin1') self.assertEqual(out.rstrip(), expected) + def check_script_error(self, src, expected, lineno=...): + with self.assertRaises(SyntaxError) as cm: + exec(src) + exc = cm.exception + self.assertRegex(str(exc), expected.decode()) + if lineno is not ...: + self.assertEqual(exc.lineno, lineno) + line = src.splitlines()[lineno-1].decode(errors='replace') + if lineno == 1: + line = line.removeprefix('\ufeff') + self.assertEqual(line, exc.text) + +@support.force_not_colorized_test_class class FileSourceEncodingTest(AbstractSourceEncodingTest, unittest.TestCase): def check_script_output(self, src, expected): @@ -335,6 +507,23 @@ class FileSourceEncodingTest(AbstractSourceEncodingTest, unittest.TestCase): res = script_helper.assert_python_ok(fn) self.assertEqual(res.out.rstrip(), expected) + def check_script_error(self, src, expected, lineno=...): + with tempfile.TemporaryDirectory() as tmpd: + fn = os.path.join(tmpd, 'test.py') + with open(fn, 'wb') as fp: + fp.write(src) + res = script_helper.assert_python_failure(fn) + err = res.err.rstrip() + self.assertRegex(err.splitlines()[-1], b'SyntaxError: ' + expected) + if lineno is not ...: + self.assertIn(f', line {lineno}\n'.encode(), + err.replace(os.linesep.encode(), b'\n')) + line = src.splitlines()[lineno-1].decode(errors='replace') + if lineno == 1: + line = line.removeprefix('\ufeff') + self.assertIn(line.encode(), err) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_sqlite3/__init__.py b/Lib/test/test_sqlite3/__init__.py index d777fca82da..145f3b80024 100644 --- a/Lib/test/test_sqlite3/__init__.py +++ b/Lib/test/test_sqlite3/__init__.py @@ -6,10 +6,14 @@ import_helper.import_module('_sqlite3') import os import sqlite3 -# Implement the unittest "load tests" protocol. -def load_tests(*args): - pkg_dir = os.path.dirname(__file__) - return load_package_tests(pkg_dir, *args) +# make sure only print once +_printed_version = False -if verbose: - print(f"test_sqlite3: testing with SQLite version {sqlite3.sqlite_version}") +# Implement the unittest "load tests" protocol. +def load_tests(loader, tests, pattern): + global _printed_version + if verbose and not _printed_version: + print(f"test_sqlite3: testing with SQLite version {sqlite3.sqlite_version}") + _printed_version = True + pkg_dir = os.path.dirname(__file__) + return load_package_tests(pkg_dir, loader, tests, pattern) diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 5926cec0569..98aadaa829a 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -216,10 +216,6 @@ class Completion(unittest.TestCase): @classmethod def setUpClass(cls): - _sqlite3 = import_module("_sqlite3") - if not hasattr(_sqlite3, "SQLITE_KEYWORDS"): - raise unittest.SkipTest("unable to determine SQLite keywords") - readline = import_module("readline") if readline.backend == "editline": raise unittest.SkipTest("libedit readline is not supported") @@ -229,12 +225,24 @@ class Completion(unittest.TestCase): import readline from sqlite3.__main__ import main + # Configure readline to ...: + # - hide control sequences surrounding each candidate + # - hide "Display all xxx possibilities? (y or n)" + # - show candidates one per line readline.parse_and_bind("set colored-completion-prefix off") + readline.parse_and_bind("set completion-query-items 0") + readline.parse_and_bind("set page-completions off") + readline.parse_and_bind("set completion-display-width 0") + main() """) return run_pty(script, input_, env) def test_complete_sql_keywords(self): + _sqlite3 = import_module("_sqlite3") + if not hasattr(_sqlite3, "SQLITE_KEYWORDS"): + raise unittest.SkipTest("unable to determine SQLite keywords") + # List candidates starting with 'S', there should be multiple matches. input_ = b"S\t\tEL\t 1;\n.quit\n" output = self.write_input(input_) @@ -254,6 +262,118 @@ class Completion(unittest.TestCase): output = self.write_input(input_) self.assertIn(b".version", output) + def test_complete_table_indexes_triggers_views(self): + input_ = textwrap.dedent("""\ + CREATE TABLE _Table (id); + CREATE INDEX _Index ON _table (id); + CREATE TRIGGER _Trigger BEFORE INSERT + ON _Table BEGIN SELECT 1; END; + CREATE VIEW _View AS SELECT 1; + + CREATE TEMP TABLE _Temp_table (id); + CREATE INDEX temp._Temp_index ON _Temp_table (id); + CREATE TEMP TRIGGER _Temp_trigger BEFORE INSERT + ON _Table BEGIN SELECT 1; END; + CREATE TEMP VIEW _Temp_view AS SELECT 1; + + ATTACH ':memory:' AS attached; + CREATE TABLE attached._Attached_table (id); + CREATE INDEX attached._Attached_index ON _Attached_table (id); + CREATE TRIGGER attached._Attached_trigger BEFORE INSERT + ON _Attached_table BEGIN SELECT 1; END; + CREATE VIEW attached._Attached_view AS SELECT 1; + + SELECT id FROM _\t\tta\t; + .quit\n""").encode() + output = self.write_input(input_) + lines = output.decode().splitlines() + indices = [i for i, line in enumerate(lines) + if line.startswith(self.PS1)] + start, end = indices[-3], indices[-2] + candidates = [l.strip() for l in lines[start+1:end]] + self.assertEqual(candidates, + [ + "_Attached_index", + "_Attached_table", + "_Attached_trigger", + "_Attached_view", + "_Index", + "_Table", + "_Temp_index", + "_Temp_table", + "_Temp_trigger", + "_Temp_view", + "_Trigger", + "_View", + ], + ) + start, end = indices[-2], indices[-1] + # direct match with '_Table' completed, no candidates displayed + candidates = [l.strip() for l in lines[start+1:end]] + self.assertEqual(len(candidates), 0) + + @unittest.skipIf(sqlite3.sqlite_version_info < (3, 16, 0), + "PRAGMA table-valued function is not available until " + "SQLite 3.16.0") + def test_complete_columns(self): + input_ = textwrap.dedent("""\ + CREATE TABLE _table (_col_table); + CREATE TEMP TABLE _temp_table (_col_temp); + ATTACH ':memory:' AS attached; + CREATE TABLE attached._attached_table (_col_attached); + + SELECT _col_\t\tta\tFROM _table; + .quit\n""").encode() + output = self.write_input(input_) + lines = output.decode().splitlines() + indices = [ + i for i, line in enumerate(lines) if line.startswith(self.PS1) + ] + start, end = indices[-3], indices[-2] + candidates = [l.strip() for l in lines[start+1:end]] + + self.assertEqual( + candidates, ["_col_attached", "_col_table", "_col_temp"] + ) + + @unittest.skipIf(sqlite3.sqlite_version_info < (3, 30, 0), + "PRAGMA function_list is not available until " + "SQLite 3.30.0") + def test_complete_functions(self): + input_ = b"SELECT AV\t1);\n.quit\n" + output = self.write_input(input_) + self.assertIn(b"AVG(1);", output) + self.assertIn(b"(1.0,)", output) + + # Functions are completed in upper case for even lower case user input. + input_ = b"SELECT av\t1);\n.quit\n" + output = self.write_input(input_) + self.assertIn(b"AVG(1);", output) + self.assertIn(b"(1.0,)", output) + + def test_complete_schemata(self): + input_ = textwrap.dedent("""\ + ATTACH ':memory:' AS MixedCase; + -- Test '_' is escaped in Like pattern filtering + ATTACH ':memory:' AS _underscore; + -- Let database_list pragma have a 'temp' schema entry + CREATE TEMP TABLE _table (id); + + SELECT * FROM \t\tmIX\t.sqlite_master; + SELECT * FROM _und\t.sqlite_master; + .quit\n""").encode() + output = self.write_input(input_) + lines = output.decode().splitlines() + indices = [ + i for i, line in enumerate(lines) if line.startswith(self.PS1) + ] + start, end = indices[-4], indices[-3] + candidates = [l.strip() for l in lines[start+1:end]] + self.assertIn("MixedCase", candidates) + self.assertIn("_underscore", candidates) + self.assertIn("main", candidates) + self.assertIn("temp", candidates) + @unittest.skipIf(sys.platform.startswith("freebsd"), "Two actual tabs are inserted when there are no matching" " completions in the pseudo-terminal opened by run_pty()" @@ -274,8 +394,6 @@ class Completion(unittest.TestCase): self.assertEqual(line_num, len(lines)) def test_complete_no_input(self): - from _sqlite3 import SQLITE_KEYWORDS - script = textwrap.dedent(""" import readline from sqlite3.__main__ import main @@ -306,7 +424,7 @@ class Completion(unittest.TestCase): self.assertEqual(len(indices), 2) start, end = indices candidates = [l.strip() for l in lines[start+1:end]] - self.assertEqual(candidates, sorted(SQLITE_KEYWORDS)) + self.assertEqual(candidates, sorted(candidates)) except: if verbose: print(' PTY output: '.center(30, '-')) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 74a511ba7c8..20e39f61e4d 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -21,6 +21,7 @@ # 3. This notice may not be removed or altered from any source distribution. import contextlib +import functools import os import sqlite3 as sqlite import subprocess @@ -1060,7 +1061,7 @@ class CursorTests(unittest.TestCase): # now set to 2 self.cu.arraysize = 2 - # now make the query return 3 rows + # now make the query return 2 rows from a table of 3 rows self.cu.execute("delete from test") self.cu.execute("insert into test(name) values ('A')") self.cu.execute("insert into test(name) values ('B')") @@ -1070,13 +1071,50 @@ class CursorTests(unittest.TestCase): self.assertEqual(len(res), 2) + def test_invalid_array_size(self): + UINT32_MAX = (1 << 32) - 1 + setter = functools.partial(setattr, self.cu, 'arraysize') + + self.assertRaises(TypeError, setter, 1.0) + self.assertRaises(ValueError, setter, -3) + self.assertRaises(OverflowError, setter, UINT32_MAX + 1) + def test_fetchmany(self): + # no active SQL statement + res = self.cu.fetchmany() + self.assertEqual(res, []) + res = self.cu.fetchmany(1000) + self.assertEqual(res, []) + + # test default parameter + self.cu.execute("select name from test") + res = self.cu.fetchmany() + self.assertEqual(len(res), 1) + + # test when the number of requested rows exceeds the actual count self.cu.execute("select name from test") res = self.cu.fetchmany(100) self.assertEqual(len(res), 1) res = self.cu.fetchmany(100) self.assertEqual(res, []) + # test when size = 0 + self.cu.execute("select name from test") + res = self.cu.fetchmany(0) + self.assertEqual(res, []) + res = self.cu.fetchmany(100) + self.assertEqual(len(res), 1) + res = self.cu.fetchmany(100) + self.assertEqual(res, []) + + def test_invalid_fetchmany(self): + UINT32_MAX = (1 << 32) - 1 + fetchmany = self.cu.fetchmany + + self.assertRaises(TypeError, fetchmany, 1.0) + self.assertRaises(ValueError, fetchmany, -3) + self.assertRaises(OverflowError, fetchmany, UINT32_MAX + 1) + def test_fetchmany_kw_arg(self): """Checks if fetchmany works with keyword arguments""" self.cu.execute("select name from test") diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 7d1eb564930..ebdf5455163 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -51,6 +51,10 @@ IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0) CAN_GET_SELECTED_OPENSSL_GROUP = ssl.OPENSSL_VERSION_INFO >= (3, 2) CAN_IGNORE_UNKNOWN_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 3) CAN_GET_AVAILABLE_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 5) +CAN_GET_AVAILABLE_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 4) +CAN_SET_CLIENT_SIGALGS = "AWS-LC" not in ssl.OPENSSL_VERSION +CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 3) +CAN_GET_SELECTED_OPENSSL_SIGALG = ssl.OPENSSL_VERSION_INFO >= (3, 5) PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS') PROTOCOL_TO_TLS_VERSION = {} @@ -263,7 +267,9 @@ ignore_deprecation = warnings_helper.ignore_warnings( def test_wrap_socket(sock, *, cert_reqs=ssl.CERT_NONE, ca_certs=None, - ciphers=None, certfile=None, keyfile=None, + ciphers=None, ciphersuites=None, + min_version=None, max_version=None, + certfile=None, keyfile=None, **kwargs): if not kwargs.get("server_side"): kwargs["server_hostname"] = SIGNED_CERTFILE_HOSTNAME @@ -280,13 +286,20 @@ def test_wrap_socket(sock, *, context.load_cert_chain(certfile, keyfile) if ciphers is not None: context.set_ciphers(ciphers) + if ciphersuites is not None: + context.set_ciphersuites(ciphersuites) + if min_version is not None: + context.minimum_version = min_version + if max_version is not None: + context.maximum_version = max_version return context.wrap_socket(sock, **kwargs) USE_SAME_TEST_CONTEXT = False _TEST_CONTEXT = None -def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True): +def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True, + client_cert=None): """Create context client_context, server_context, hostname = testing_context() @@ -313,6 +326,10 @@ def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True): if server_chain: server_context.load_verify_locations(SIGNING_CA) + if client_cert: + client_context.load_cert_chain(client_cert) + server_context.verify_mode = ssl.CERT_REQUIRED + if USE_SAME_TEST_CONTEXT: if _TEST_CONTEXT is not None: _TEST_CONTEXT = client_context, server_context, hostname @@ -982,6 +999,37 @@ class ContextTests(unittest.TestCase): self.assertNotIn('P-256', ctx.get_groups()) self.assertIn('P-256', ctx.get_groups(include_aliases=True)) + @unittest.skipUnless(CAN_GET_AVAILABLE_OPENSSL_SIGALGS, + "SSL library doesn't support getting sigalgs") + def test_get_sigalgs(self): + self.assertIn('rsa_pss_rsae_sha256', ssl.get_sigalgs()) + + @unittest.skipUnless(CAN_SET_CLIENT_SIGALGS, + "SSL library doesn't support setting client sigalgs") + def test_set_client_sigalgs(self): + ctx = ssl.create_default_context() + + self.assertIsNone(ctx.set_client_sigalgs('rsa_pss_rsae_sha256')) + + self.assertRaises(ssl.SSLError, ctx.set_client_sigalgs, + 'rsa_pss_rsae_sha256:foo') + + # Ignoring unknown sigalgs is only supported since OpenSSL 3.3. + if CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS: + self.assertIsNone(ctx.set_client_sigalgs('rsa_pss_rsae_sha256:?foo')) + + def test_set_server_sigalgs(self): + ctx = ssl.create_default_context() + + self.assertIsNone(ctx.set_server_sigalgs('rsa_pss_rsae_sha256')) + + self.assertRaises(ssl.SSLError, ctx.set_server_sigalgs, + 'rsa_pss_rsae_sha256:foo') + + # Ignoring unknown sigalgs is only supported since OpenSSL 3.3. + if CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS: + self.assertIsNone(ctx.set_server_sigalgs('rsa_pss_rsae_sha256:?foo')) + def test_options(self): # Test default SSLContext options ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) @@ -2238,6 +2286,68 @@ class SimpleBackgroundTests(unittest.TestCase): self.assertRaises(ssl.SSLEOFError, sslobj.read) +@unittest.skipUnless(has_tls_version('TLSv1_3'), "TLS 1.3 is not available") +class SimpleBackgroundTestsTLS_1_3(unittest.TestCase): + """Tests that connect to a simple server running in the background.""" + + def setUp(self): + server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ciphers = [cipher['name'] for cipher in server_ctx.get_ciphers() + if cipher['protocol'] == 'TLSv1.3'] + + if not ciphers: + self.skipTest("No cipher supports TLSv1.3") + + self.matching_cipher = ciphers[0] + # Some tests need at least two ciphers, and are responsible + # to skip themselves if matching_cipher == mismatched_cipher. + self.mismatched_cipher = ciphers[-1] + + server_ctx.set_ciphersuites(self.matching_cipher) + server_ctx.load_cert_chain(SIGNED_CERTFILE) + server = ThreadedEchoServer(context=server_ctx) + self.enterContext(server) + self.server_addr = (HOST, server.port) + + def test_ciphersuites(self): + # Test unrecognized TLS 1.3 cipher suite name + with ( + socket.socket(socket.AF_INET) as sock, + self.assertRaisesRegex(ssl.SSLError, + "No cipher suite can be selected") + ): + test_wrap_socket(sock, cert_reqs=ssl.CERT_NONE, + ciphersuites="XXX", + min_version=ssl.TLSVersion.TLSv1_3) + + # Test successful TLS 1.3 handshake + with test_wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_NONE, + ciphersuites=self.matching_cipher, + min_version=ssl.TLSVersion.TLSv1_3) as s: + s.connect(self.server_addr) + self.assertEqual(s.cipher()[0], self.matching_cipher) + + def test_ciphersuite_downgrade(self): + with test_wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_NONE, + ciphersuites=self.matching_cipher, + min_version=ssl.TLSVersion.TLSv1_2, + max_version=ssl.TLSVersion.TLSv1_2) as s: + s.connect(self.server_addr) + self.assertEqual(s.cipher()[1], 'TLSv1.2') + + def test_ciphersuite_mismatch(self): + if self.matching_cipher == self.mismatched_cipher: + self.skipTest("Multiple TLS 1.3 ciphers are not available") + + with test_wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_NONE, + ciphersuites=self.mismatched_cipher, + min_version=ssl.TLSVersion.TLSv1_3) as s: + self.assertRaises(ssl.SSLError, s.connect, self.server_addr) + + @support.requires_resource('network') class NetworkedTests(unittest.TestCase): @@ -2744,6 +2854,9 @@ def server_params_test(client_context, server_context, indata=b"FOO\n", }) if CAN_GET_SELECTED_OPENSSL_GROUP: stats.update({'group': s.group()}) + if CAN_GET_SELECTED_OPENSSL_SIGALG: + stats.update({'client_sigalg': s.client_sigalg()}) + stats.update({'server_sigalg': s.server_sigalg()}) s.close() stats['server_alpn_protocols'] = server.selected_alpn_protocols stats['server_shared_ciphers'] = server.shared_ciphers @@ -4203,6 +4316,77 @@ class ThreadedTests(unittest.TestCase): chatty=True, connectionchatty=True, sni_name=hostname) + @unittest.skipUnless(CAN_SET_CLIENT_SIGALGS, + "SSL library doesn't support setting client sigalgs") + def test_client_sigalgs(self): + # no mutual auth, so cient_sigalg should be None + client_context, server_context, hostname = testing_context() + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + if CAN_GET_SELECTED_OPENSSL_SIGALG: + self.assertIsNone(stats['client_sigalg']) + + # server auto, client rsa_pss_rsae_sha384 + sigalg = "rsa_pss_rsae_sha384" + client_context, server_context, hostname = \ + testing_context(client_cert=SIGNED_CERTFILE) + client_context.set_client_sigalgs(sigalg) + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + if CAN_GET_SELECTED_OPENSSL_SIGALG: + self.assertEqual(stats['client_sigalg'], sigalg) + + @unittest.skipUnless(CAN_SET_CLIENT_SIGALGS, + "SSL library doesn't support setting client sigalgs") + def test_client_sigalgs_mismatch(self): + client_context, server_context, hostname = \ + testing_context(client_cert=SIGNED_CERTFILE) + client_context.set_client_sigalgs("rsa_pss_rsae_sha256") + server_context.set_client_sigalgs("rsa_pss_rsae_sha384") + + with self.assertRaises(( + ssl.SSLError, + # On handshake failures, some systems raise a ConnectionResetError. + ConnectionResetError, + # On handshake failures, macOS may raise a BrokenPipeError. + # See https://github.com/python/cpython/issues/139504. + BrokenPipeError, + )): + server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + + def test_server_sigalgs(self): + # server rsa_pss_rsae_sha384, client auto + sigalg = "rsa_pss_rsae_sha384" + client_context, server_context, hostname = testing_context() + server_context.set_server_sigalgs(sigalg) + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + if CAN_GET_SELECTED_OPENSSL_SIGALG: + self.assertEqual(stats['server_sigalg'], sigalg) + + # server auto, client rsa_pss_rsae_sha384 + client_context, server_context, hostname = testing_context() + client_context.set_server_sigalgs(sigalg) + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + if CAN_GET_SELECTED_OPENSSL_SIGALG: + self.assertEqual(stats['server_sigalg'], sigalg) + + def test_server_sigalgs_mismatch(self): + client_context, server_context, hostname = testing_context() + client_context.set_server_sigalgs("rsa_pss_rsae_sha256") + server_context.set_server_sigalgs("rsa_pss_rsae_sha384") + with self.assertRaises(ssl.SSLError): + server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + def test_selected_alpn_protocol(self): # selected_alpn_protocol() is None unless ALPN is used. client_context, server_context, hostname = testing_context() @@ -5429,7 +5613,7 @@ class TestEnumerations(unittest.TestCase): class Checked_TLSAlertType(enum.IntEnum): """Alert types for TLSContentType.ALERT messages - See RFC 8466, section B.2 + See RFC 8446, section B.2 """ CLOSE_NOTIFY = 0 UNEXPECTED_MESSAGE = 10 diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 5a6ba9de337..2e93ac08f82 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -45,6 +45,7 @@ class TestStableABIAvailability(unittest.TestCase): SYMBOL_NAMES = ( + "PyABIInfo_Check", "PyAIter_Check", "PyArg_Parse", "PyArg_ParseTuple", @@ -164,6 +165,7 @@ SYMBOL_NAMES = ( "PyDict_MergeFromSeq2", "PyDict_New", "PyDict_Next", + "PyDict_SetDefaultRef", "PyDict_SetItem", "PyDict_SetItemString", "PyDict_Size", @@ -468,8 +470,10 @@ SYMBOL_NAMES = ( "PyModule_AddStringConstant", "PyModule_AddType", "PyModule_Create2", + "PyModule_Exec", "PyModule_ExecDef", "PyModule_FromDefAndSpec2", + "PyModule_FromSlotsAndSpec", "PyModule_GetDef", "PyModule_GetDict", "PyModule_GetFilename", @@ -477,6 +481,8 @@ SYMBOL_NAMES = ( "PyModule_GetName", "PyModule_GetNameObject", "PyModule_GetState", + "PyModule_GetStateSize", + "PyModule_GetToken", "PyModule_New", "PyModule_NewObject", "PyModule_SetDocString", @@ -732,6 +738,7 @@ SYMBOL_NAMES = ( "PyType_GetFullyQualifiedName", "PyType_GetModule", "PyType_GetModuleByDef", + "PyType_GetModuleByToken", "PyType_GetModuleName", "PyType_GetModuleState", "PyType_GetName", @@ -894,6 +901,7 @@ SYMBOL_NAMES = ( "Py_GetRecursionLimit", "Py_GetVersion", "Py_HasFileSystemDefaultEncoding", + "Py_IS_TYPE", "Py_IncRef", "Py_Initialize", "Py_InitializeEx", @@ -913,6 +921,8 @@ SYMBOL_NAMES = ( "Py_REFCNT", "Py_ReprEnter", "Py_ReprLeave", + "Py_SET_SIZE", + "Py_SIZE", "Py_SetPath", "Py_SetProgramName", "Py_SetPythonHome", diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 8250b0aef09..677a87b51b9 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -2005,7 +2005,6 @@ class VarianceStdevMixin(UnivariateCommonMixin): expected = self.func(data) self.assertEqual(self.func(iter(data)), expected) - class TestPVariance(VarianceStdevMixin, NumericTestCase, UnivariateTypeMixin): # Tests for population variance. def setUp(self): @@ -2113,6 +2112,14 @@ class TestPStdev(VarianceStdevMixin, NumericTestCase): self.assertEqual(self.func(data), 2.5) self.assertEqual(self.func(data, mu=0.5), 6.5) + def test_gh_140938(self): + # Inputs with inf/nan should raise a ValueError + with self.assertRaises(ValueError): + self.func([1.0, math.inf]) + with self.assertRaises(ValueError): + self.func([1.0, math.nan]) + + class TestSqrtHelpers(unittest.TestCase): def test_integer_sqrt_of_frac_rto(self): diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 0241e543cd7..40e114aada6 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -406,37 +406,50 @@ class StrptimeTests(unittest.TestCase): (*_, offset), _, offset_fraction = _strptime._strptime("-013030.000001", "%z") self.assertEqual(offset, -(one_hour + half_hour + half_minute)) self.assertEqual(offset_fraction, -1) - (*_, offset), _, offset_fraction = _strptime._strptime("+01:00", "%z") - self.assertEqual(offset, one_hour) - self.assertEqual(offset_fraction, 0) - (*_, offset), _, offset_fraction = _strptime._strptime("-01:30", "%z") - self.assertEqual(offset, -(one_hour + half_hour)) - self.assertEqual(offset_fraction, 0) - (*_, offset), _, offset_fraction = _strptime._strptime("-01:30:30", "%z") - self.assertEqual(offset, -(one_hour + half_hour + half_minute)) - self.assertEqual(offset_fraction, 0) - (*_, offset), _, offset_fraction = _strptime._strptime("-01:30:30.000001", "%z") - self.assertEqual(offset, -(one_hour + half_hour + half_minute)) - self.assertEqual(offset_fraction, -1) - (*_, offset), _, offset_fraction = _strptime._strptime("+01:30:30.001", "%z") - self.assertEqual(offset, one_hour + half_hour + half_minute) - self.assertEqual(offset_fraction, 1000) - (*_, offset), _, offset_fraction = _strptime._strptime("Z", "%z") - self.assertEqual(offset, 0) - self.assertEqual(offset_fraction, 0) + + cases = [ + ("+01:00", one_hour, 0), + ("-01:30", -(one_hour + half_hour), 0), + ("-01:30:30", -(one_hour + half_hour + half_minute), 0), + ("-01:30:30.000001", -(one_hour + half_hour + half_minute), -1), + ("+01:30:30.001", +(one_hour + half_hour + half_minute), 1000), + ("Z", 0, 0), + ] + for directive in ("%z", "%:z"): + for offset_str, expected_offset, expected_fraction in cases: + with self.subTest(offset_str=offset_str, directive=directive): + (*_, offset), _, offset_fraction = _strptime._strptime( + offset_str, directive + ) + self.assertEqual(offset, expected_offset) + self.assertEqual(offset_fraction, expected_fraction) def test_bad_offset(self): - with self.assertRaises(ValueError): - _strptime._strptime("-01:30:30.", "%z") - with self.assertRaises(ValueError): - _strptime._strptime("-0130:30", "%z") - with self.assertRaises(ValueError): - _strptime._strptime("-01:30:30.1234567", "%z") - with self.assertRaises(ValueError): - _strptime._strptime("-01:30:30:123456", "%z") + error_cases_any_z = [ + "-01:30:30.", # Decimal point not followed with digits + "-01:30:30.1234567", # Too many digits after decimal point + "-01:30:30:123456", # Colon as decimal separator + "-0130:30", # Incorrect use of colons + ] + for directive in ("%z", "%:z"): + for timestr in error_cases_any_z: + with self.subTest(timestr=timestr, directive=directive): + with self.assertRaises(ValueError): + _strptime._strptime(timestr, directive) + + required_colons_cases = ["-013030", "+0130", "-01:3030.123456"] + for timestr in required_colons_cases: + with self.subTest(timestr=timestr): + with self.assertRaises(ValueError): + _strptime._strptime(timestr, "%:z") + with self.assertRaises(ValueError) as err: _strptime._strptime("-01:3030", "%z") self.assertEqual("Inconsistent use of : in -01:3030", str(err.exception)) + with self.assertRaises(ValueError) as err: + _strptime._strptime("-01:3030", "%:z") + self.assertEqual("Missing colon in %:z before '30', got '-01:3030'", + str(err.exception)) @skip_if_buggy_ucrt_strfptime def test_timezone(self): @@ -557,7 +570,7 @@ class StrptimeTests(unittest.TestCase): def test_date_locale2(self): # Test %x directive loc = locale.getlocale(locale.LC_TIME)[0] - if sys.platform.startswith('sunos'): + if sys.platform.startswith(('sunos', 'aix')): if loc in ('en_US', 'de_DE', 'ar_AE'): self.skipTest(f'locale {loc!r} may not work on this platform') self.roundtrip('%x', slice(0, 3), (1900, 1, 1, 0, 0, 0, 0, 1, 0)) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 7df01f28f09..cceecdd526c 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -5,6 +5,7 @@ import gc import math import operator import unittest +import platform import struct import sys import weakref @@ -799,6 +800,23 @@ class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase): round_trip = struct.unpack(f, struct.pack(f, z))[0] self.assertComplexesAreIdentical(z, round_trip) + @unittest.skipIf( + support.is_android or support.is_apple_mobile, + "Subinterpreters are not supported on Android and iOS" + ) + def test_endian_table_init_subinterpreters(self): + # Verify that the _struct extension module can be initialized + # concurrently in subinterpreters (gh-140260). + try: + from concurrent.futures import InterpreterPoolExecutor + except ImportError: + raise unittest.SkipTest("InterpreterPoolExecutor not available") + + code = "import struct" + with InterpreterPoolExecutor(max_workers=5) as executor: + results = executor.map(exec, [code] * 5) + self.assertListEqual(list(results), [None] * 5) + class UnpackIteratorTest(unittest.TestCase): """ @@ -917,10 +935,17 @@ class UnpackIteratorTest(unittest.TestCase): # Check that packing produces a bit pattern representing a quiet NaN: # all exponent bits and the msb of the fraction should all be 1. + if platform.machine().startswith('parisc'): + # HP PA RISC uses 0 for quiet, see: + # https://en.wikipedia.org/wiki/NaN#Encoding + expected = 0x7c + else: + expected = 0x7e + packed = struct.pack('<e', math.nan) - self.assertEqual(packed[1] & 0x7e, 0x7e) + self.assertEqual(packed[1] & 0x7e, expected) packed = struct.pack('<e', -math.nan) - self.assertEqual(packed[1] & 0x7e, 0x7e) + self.assertEqual(packed[1] & 0x7e, expected) # Checks for round-to-even behavior format_bits_float__rounding_list = [ diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index f0e350c71f6..806a1e3fa30 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -957,6 +957,48 @@ class ProcessTestCase(BaseTestCase): self.assertEqual(stdout, b"banana") self.assertEqual(stderr, b"pineapple") + def test_communicate_memoryview_input(self): + # Test memoryview input with byte elements + test_data = b"Hello, memoryview!" + mv = memoryview(test_data) + p = subprocess.Popen([sys.executable, "-c", + 'import sys; sys.stdout.write(sys.stdin.read())'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stdin.close) + (stdout, stderr) = p.communicate(mv) + self.assertEqual(stdout, test_data) + self.assertIsNone(stderr) + + def test_communicate_memoryview_input_nonbyte(self): + # Test memoryview input with non-byte elements (e.g., int32) + # This tests the fix for gh-134453 where non-byte memoryviews + # had incorrect length tracking on POSIX + import array + # Create an array of 32-bit integers that's large enough to trigger + # the chunked writing behavior (> PIPE_BUF) + pipe_buf = getattr(select, 'PIPE_BUF', 512) + # Each 'i' element is 4 bytes, so we need more than pipe_buf/4 elements + # Add some extra to ensure we exceed the buffer size + num_elements = pipe_buf + 1 + test_array = array.array('i', [0x64306f66 for _ in range(num_elements)]) + expected_bytes = test_array.tobytes() + mv = memoryview(test_array) + + p = subprocess.Popen([sys.executable, "-c", + 'import sys; ' + 'data = sys.stdin.buffer.read(); ' + 'sys.stdout.buffer.write(data)'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stdin.close) + (stdout, stderr) = p.communicate(mv) + self.assertEqual(stdout, expected_bytes, + msg=f"{len(stdout)=} =? {len(expected_bytes)=}") + self.assertIsNone(stderr) + def test_communicate_timeout(self): p = subprocess.Popen([sys.executable, "-c", 'import sys,os,time;' @@ -992,6 +1034,62 @@ class ProcessTestCase(BaseTestCase): (stdout, _) = p.communicate() self.assertEqual(len(stdout), 4 * 64 * 1024) + def test_communicate_timeout_large_input(self): + # Test that timeout is enforced when writing large input to a + # slow-to-read subprocess, and that partial input is preserved + # for continuation after timeout (gh-141473). + # + # This is a regression test for Windows matching POSIX behavior. + # On POSIX, select() is used to multiplex I/O with timeout checking. + # On Windows, stdin writing must also honor the timeout rather than + # blocking indefinitely when the pipe buffer fills. + + # Input larger than typical pipe buffer (4-64KB on Windows) + input_data = b"x" * (128 * 1024) + + p = subprocess.Popen( + [sys.executable, "-c", + "import sys, time; " + "time.sleep(30); " # Don't read stdin for a long time + "sys.stdout.buffer.write(sys.stdin.buffer.read())"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + try: + timeout = 0.2 + start = time.monotonic() + try: + p.communicate(input_data, timeout=timeout) + # If we get here without TimeoutExpired, the timeout was ignored + elapsed = time.monotonic() - start + self.fail( + f"TimeoutExpired not raised. communicate() completed in " + f"{elapsed:.2f}s, but subprocess sleeps for 30s. " + "Stdin writing blocked without enforcing timeout.") + except subprocess.TimeoutExpired: + elapsed = time.monotonic() - start + + # Timeout should occur close to the specified timeout value, + # not after waiting for the subprocess to finish sleeping. + # Allow generous margin for slow CI, but must be well under + # the subprocess sleep time. + self.assertLess(elapsed, 5.0, + f"TimeoutExpired raised after {elapsed:.2f}s; expected ~{timeout}s. " + "Stdin writing blocked without checking timeout.") + + # After timeout, continue communication. The remaining input + # should be sent and we should receive all data back. + stdout, stderr = p.communicate() + + # Verify all input was eventually received by the subprocess + self.assertEqual(len(stdout), len(input_data), + f"Expected {len(input_data)} bytes output but got {len(stdout)}") + self.assertEqual(stdout, input_data) + finally: + p.kill() + p.wait() + # Test for the fd leak reported in http://bugs.python.org/issue2791. def test_communicate_pipe_fd_leak(self): for stdin_pipe in (False, True): @@ -1062,6 +1160,19 @@ class ProcessTestCase(BaseTestCase): self.assertEqual(stdout, b"bananasplit") self.assertEqual(stderr, b"") + def test_communicate_stdin_closed_before_call(self): + # gh-70560, gh-74389: stdin.close() before communicate() + # should not raise ValueError from stdin.flush() + with subprocess.Popen([sys.executable, "-c", + 'import sys; sys.exit(0)'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) as p: + p.stdin.close() # Close stdin before communicate + # This should not raise ValueError + (stdout, stderr) = p.communicate() + self.assertEqual(p.returncode, 0) + def test_universal_newlines_and_text(self): args = [ sys.executable, "-c", @@ -1643,6 +1754,40 @@ class ProcessTestCase(BaseTestCase): self.assertEqual(proc.wait(), 0) + def test_post_timeout_communicate_sends_input(self): + """GH-141473 regression test; the stdin pipe must close""" + with subprocess.Popen( + [sys.executable, "-uc", """\ +import sys +while c := sys.stdin.read(512): + sys.stdout.write(c) +print() +"""], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) as proc: + try: + data = f"spam{'#'*4096}beans" + proc.communicate( + input=data, + timeout=0, + ) + except subprocess.TimeoutExpired as exc: + pass + # Prior to the bugfix, this would hang as the stdin + # pipe to the child had not been closed. + try: + stdout, stderr = proc.communicate(timeout=15) + except subprocess.TimeoutExpired as exc: + self.fail("communicate() hung waiting on child process that should have seen its stdin pipe close and exit") + self.assertEqual( + proc.returncode, 0, + msg=f"STDERR:\n{stderr}\nSTDOUT:\n{stdout}") + self.assertStartsWith(stdout, "spam") + self.assertIn("beans", stdout) + class RunFuncTestCase(BaseTestCase): def run_python(self, code, **kwargs): diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 12361aa4e51..667fcc81d8e 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -96,9 +96,15 @@ class TestSupport(unittest.TestCase): self.test_get_attribute) self.assertRaises(unittest.SkipTest, support.get_attribute, self, "foo") - @unittest.skip("failing buildbots") + @unittest.skipIf(support.is_android or support.is_apple_mobile, + 'Mobile platforms redirect stdout to system log') def test_get_original_stdout(self): - self.assertEqual(support.get_original_stdout(), sys.stdout) + if isinstance(sys.stdout, io.StringIO): + # gh-55258: When --junit-xml is used, stdout is a StringIO: + # use sys.__stdout__ in this case. + self.assertEqual(support.get_original_stdout(), sys.__stdout__) + else: + self.assertEqual(support.get_original_stdout(), sys.stdout) def test_unload(self): import sched # noqa: F401 @@ -792,10 +798,10 @@ class TestSupport(unittest.TestCase): self.assertTrue(linked) # The value is cached, so make sure it returns the same value again. self.assertIs(linked, support.linked_to_musl()) - # The unlike libc, the musl version is a triple. + # The musl version is either triple or just a major version number. if linked: self.assertIsInstance(linked, tuple) - self.assertEqual(3, len(linked)) + self.assertIn(len(linked), (1, 3)) for v in linked: self.assertIsInstance(v, int) @@ -866,22 +872,22 @@ class TestHashlibSupport(unittest.TestCase): return default def fetch_hash_function(self, name, implementation): - info = hashlib_helper.get_hash_info(name) - match implementation: - case "hashlib": - assert info.hashlib is not None, info - return getattr(self.hashlib, info.hashlib) - case "openssl": - try: - return getattr(self._hashlib, info.openssl, None) - except TypeError: - return None - fullname = info.fullname(implementation) + info = hashlib_helper.get_hash_func_info(name) + match hashlib_helper.Implementation(implementation): + case hashlib_helper.Implementation.hashlib: + method_name = info.hashlib.member_name + assert isinstance(method_name, str), method_name + return getattr(self.hashlib, method_name) + case hashlib_helper.Implementation.openssl: + method_name = info.openssl.member_name + assert isinstance(method_name, str | None), method_name + return getattr(self._hashlib, method_name or "", None) + fullname = info[implementation].fullname return self.try_import_attribute(fullname) def fetch_hmac_function(self, name): - fullname = hashlib_helper._EXPLICIT_HMAC_CONSTRUCTORS[name] - return self.try_import_attribute(fullname) + target = hashlib_helper.get_hmac_item_info(name) + return target.import_member() def check_openssl_hash(self, name, *, disabled=True): """Check that OpenSSL HASH interface is enabled/disabled.""" diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index 26c75fcbc2b..094ab8f573e 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -5,6 +5,7 @@ Test the API of the symtable module. import re import textwrap import symtable +import warnings import unittest from test import support @@ -579,6 +580,37 @@ class SymtableTest(unittest.TestCase): self.assertEqual(sorted(st.get_identifiers()), [".0", "y"]) self.assertEqual(st.get_children(), []) + def test__symtable_refleak(self): + # Regression test for reference leak in PyUnicode_FSDecoder. + # See https://github.com/python/cpython/issues/139748. + mortal_str = 'this is a mortal string' + # check error path when 'compile_type' AC conversion failed + self.assertRaises(TypeError, symtable.symtable, '', mortal_str, 1) + + def test_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with open(filename, 'rb') as f: + source = f.read() + module_re = r'test\.test_import\.data\.syntax_warnings\z' + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=module_re) + symtable.symtable(source, filename, 'exec') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'package\.module\z') + warnings.filterwarnings('error', module=module_re) + symtable.symtable(source, filename, 'exec', module='package.module') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + class ComprehensionTests(unittest.TestCase): def get_identifiers_recursive(self, st, res): diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index c52d2421941..93f0b98de71 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -370,18 +370,48 @@ SyntaxError: invalid syntax Traceback (most recent call last): SyntaxError: invalid syntax ->>> match ...: -... case {**rest, "key": value}: -... ... -Traceback (most recent call last): -SyntaxError: invalid syntax - >>> match ...: ... case {**_}: ... ... Traceback (most recent call last): SyntaxError: invalid syntax +# Check incorrect "case" placement with specialized error messages + +>>> case "pattern": ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> case 1 | 2: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> case klass(attr=1) | {}: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> case [] if x > 1: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> case match: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> case case: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> if some: +... case 1: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + +>>> case some: +... case 1: ... +Traceback (most recent call last): +SyntaxError: case statement must be inside match statement + # But prefixes of soft keywords should # still raise specialized errors @@ -2133,6 +2163,25 @@ SyntaxError: cannot use subscript as import target Traceback (most recent call last): SyntaxError: cannot use subscript as import target +# Check that we don't raise a "cannot use name as import target" error +# if there is an error in an unrelated statement after ';' + +>>> import a as b; None = 1 +Traceback (most recent call last): +SyntaxError: cannot assign to None + +>>> import a, b as c; d = 1; None = 1 +Traceback (most recent call last): +SyntaxError: cannot assign to None + +>>> from a import b as c; None = 1 +Traceback (most recent call last): +SyntaxError: cannot assign to None + +>>> from a import b, c as d; e = 1; None = 1 +Traceback (most recent call last): +SyntaxError: cannot assign to None + # Check that we dont raise the "trailing comma" error if there is more # input to the left of the valid part that we parsed. @@ -2240,7 +2289,7 @@ Corner-cases that used to crash: Traceback (most recent call last): SyntaxError: invalid character '£' (U+00A3) - Invalid pattern matching constructs: +Invalid pattern matching constructs: >>> match ...: ... case 42 as _: @@ -2302,6 +2351,24 @@ Corner-cases that used to crash: Traceback (most recent call last): SyntaxError: positional patterns follow keyword patterns + >>> match ...: + ... case {**double_star, "spam": "eggs"}: + ... ... + Traceback (most recent call last): + SyntaxError: double star pattern must be the last (right-most) subpattern in the mapping pattern + + >>> match ...: + ... case {"foo": 1, **double_star, "spam": "eggs"}: + ... ... + Traceback (most recent call last): + SyntaxError: double star pattern must be the last (right-most) subpattern in the mapping pattern + + >>> match ...: + ... case {"spam": "eggs", "b": {**d, "ham": "bacon"}}: + ... ... + Traceback (most recent call last): + SyntaxError: double star pattern must be the last (right-most) subpattern in the mapping pattern + Uses of the star operator which should fail: A[:*b] @@ -2686,6 +2753,76 @@ Invalid expressions in type scopes: >>> f(x = 5, *:) Traceback (most recent call last): SyntaxError: Invalid star expression + +Asserts: + + >>> assert (a := 1) # ok + >>> assert 1, (a := 1) # ok + + >>> assert a := 1 + Traceback (most recent call last): + SyntaxError: cannot use named expression without parentheses here + + >>> assert 1, a := 1 + Traceback (most recent call last): + SyntaxError: cannot use named expression without parentheses here + + >>> assert 1 = 2 = 3 + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + + >>> assert 1 = 2 + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + + >>> assert (1 = 2) + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + + >>> assert 'a' = a + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + + >>> assert x[0] = 1 + Traceback (most recent call last): + SyntaxError: cannot assign to subscript here. Maybe you meant '==' instead of '='? + + >>> assert (yield a) = 2 + Traceback (most recent call last): + SyntaxError: cannot assign to yield expression here. Maybe you meant '==' instead of '='? + + >>> assert a = 2 + Traceback (most recent call last): + SyntaxError: cannot assign to name here. Maybe you meant '==' instead of '='? + + >>> assert (a = 2) + Traceback (most recent call last): + SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='? + + >>> assert a = b + Traceback (most recent call last): + SyntaxError: cannot assign to name here. Maybe you meant '==' instead of '='? + + >>> assert 1, 1 = b + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + + >>> assert 1, (1 = b) + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + + >>> assert 1, a = 1 + Traceback (most recent call last): + SyntaxError: cannot assign to name here. Maybe you meant '==' instead of '='? + + >>> assert 1, (a = 1) + Traceback (most recent call last): + SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='? + + >>> assert 1 = a, a = 1 + Traceback (most recent call last): + SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='? + """ import re @@ -3199,6 +3336,20 @@ case(34) lineno=3 ) + def test_multiline_string_concat_missing_comma_points_to_last_string(self): + # gh-142236: For multi-line string concatenations with a missing comma, + # the error should point to the last string, not the first. + self._check_error( + "print(\n" + ' "line1"\n' + ' "line2"\n' + ' "line3"\n' + " x=1\n" + ")", + "Perhaps you forgot a comma", + lineno=4, # Points to "line3", the last string + ) + @support.cpython_only def test_syntax_error_on_deeply_nested_blocks(self): # This raises a SyntaxError, it used to raise a SystemError. Context diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f89237931b7..04018e9603f 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -730,14 +730,24 @@ class SysModuleTest(unittest.TestCase): self.assertEqual(len(info), 3) self.assertIn(info.name, ('nt', 'pthread', 'pthread-stubs', 'solaris', None)) self.assertIn(info.lock, ('pymutex', None)) - if sys.platform.startswith(("linux", "android", "freebsd")): + if sys.platform.startswith(("linux", "android", "freebsd", "wasi")): self.assertEqual(info.name, "pthread") elif sys.platform == "win32": self.assertEqual(info.name, "nt") elif sys.platform == "emscripten": self.assertIn(info.name, {"pthread", "pthread-stubs"}) - elif sys.platform == "wasi": - self.assertEqual(info.name, "pthread-stubs") + + def test_abi_info(self): + info = sys.abi_info + info_keys = {'pointer_bits', 'free_threaded', 'debug', 'byteorder'} + self.assertEqual(set(vars(info)), info_keys) + pointer_bits = 64 if sys.maxsize > 2**32 else 32 + self.assertEqual(info.pointer_bits, pointer_bits) + self.assertEqual(info.free_threaded, + bool(sysconfig.get_config_var('Py_GIL_DISABLED'))) + self.assertEqual(info.debug, + bool(sysconfig.get_config_var('Py_DEBUG'))) + self.assertEqual(info.byteorder, sys.byteorder) @unittest.skipUnless(support.is_emscripten, "only available on Emscripten") def test_emscripten_info(self): @@ -1571,7 +1581,7 @@ class SizeofTest(unittest.TestCase): samples = [b'', b'u'*100000] for sample in samples: x = bytearray(sample) - check(x, vsize('n2Pi') + x.__alloc__()) + check(x, vsize('n2PiP') + x.__alloc__()) # bytearray_iterator check(iter(bytearray()), size('nP')) # bytes @@ -1713,9 +1723,10 @@ class SizeofTest(unittest.TestCase): check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) # module if support.Py_GIL_DISABLED: - check(unittest, size('PPPPPP')) + md_gil = '?' else: - check(unittest, size('PPPPP')) + md_gil = '' + check(unittest, size('PPPP?' + md_gil + 'NPPPPP')) # None check(None, size('')) # NotImplementedType @@ -2240,9 +2251,10 @@ class TestSysJIT(unittest.TestCase): def frame_3_jit() -> None: # JITs just before the last loop: - for i in range(_testinternalcapi.TIER2_THRESHOLD + 1): + # 1 extra iteration for tracing. + for i in range(_testinternalcapi.TIER2_THRESHOLD + 2): # Careful, doing this in the reverse order breaks tracing: - expected = {enabled} and i == _testinternalcapi.TIER2_THRESHOLD + expected = {enabled} and i >= _testinternalcapi.TIER2_THRESHOLD assert sys._jit.is_active() is expected frame_2_jit(expected) assert sys._jit.is_active() is expected diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index 345c022bd23..a22b728b569 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -272,6 +272,8 @@ class ProfileHookTestCase(TestCaseBase): self.check_events(g, [(1, 'call', g_ident, None), (2, 'call', f_ident, None), (2, 'return', f_ident, 0), + (2, 'call', f_ident, None), + (2, 'return', f_ident, None), (1, 'return', g_ident, None), ], check_args=True) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index b3685a91c57..199a9087dfe 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -360,6 +360,8 @@ class TraceTestCase(unittest.TestCase): # Disable gc collection when tracing, otherwise the # deallocators may be traced as well. def setUp(self): + if os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0': + self.skipTest("Line tracing behavior differs when JIT optimizer is disabled") self.using_gc = gc.isenabled() gc.disable() self.addCleanup(sys.settrace, sys.gettrace()) diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index 4aaef5b1429..502103ce629 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -20,7 +20,7 @@ from test.support import ( ) from test.support.import_helper import import_module from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, - change_cwd) + change_cwd, EnvironmentVarGuard) from test.support.venv import VirtualEnvironmentMixin import sysconfig @@ -352,6 +352,13 @@ class TestSysConfig(unittest.TestCase, VirtualEnvironmentMixin): self.assertEqual(get_platform(), 'macosx-10.4-%s' % arch) + for macver in range(11, 16): + _osx_support._remove_original_values(get_config_vars()) + get_config_vars()['CFLAGS'] = ('-fno-strict-overflow -Wsign-compare -Wunreachable-code' + '-arch arm64 -fno-common -dynamic -DNDEBUG -g -O3 -Wall') + get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = f"{macver}.0" + self.assertEqual(get_platform(), 'macosx-%d.0-arm64' % macver) + # linux debian sarge os.name = 'posix' sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' @@ -757,8 +764,13 @@ class MakefileTests(unittest.TestCase): print("var3=42", file=makefile) print("var4=$/invalid", file=makefile) print("var5=dollar$$5", file=makefile) - print("var6=${var3}/lib/python3.5/config-$(VAR2)$(var5)" + print("var6=${var7}/lib/python3.5/config-$(VAR2)$(var5)" "-x86_64-linux-gnu", file=makefile) + print("var7=${var3}", file=makefile) + print("var8=$$(var3)", file=makefile) + print("var9=$(var10)(var3)", file=makefile) + print("var10=$$", file=makefile) + print("var11=$${ORIGIN}${var5}", file=makefile) vars = _parse_makefile(TESTFN) self.assertEqual(vars, { 'var1': 'ab42', @@ -767,6 +779,74 @@ class MakefileTests(unittest.TestCase): 'var4': '$/invalid', 'var5': 'dollar$5', 'var6': '42/lib/python3.5/config-b42dollar$5-x86_64-linux-gnu', + 'var7': 42, + 'var8': '$(var3)', + 'var9': '$(var3)', + 'var10': '$', + 'var11': '${ORIGIN}dollar$5', + }) + + def _test_parse_makefile_recursion(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, "w") as makefile: + print("var1=var1=$(var1)", file=makefile) + print("var2=var3=$(var3)", file=makefile) + print("var3=var2=$(var2)", file=makefile) + vars = _parse_makefile(TESTFN) + self.assertEqual(vars, { + 'var1': 'var1=', + 'var2': 'var3=var2=', + 'var3': 'var2=', + }) + + def test_parse_makefile_renamed_vars(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, "w") as makefile: + print("var1=$(CFLAGS)", file=makefile) + print("PY_CFLAGS=-Wall $(CPPFLAGS)", file=makefile) + print("PY_LDFLAGS=-lm", file=makefile) + print("var2=$(LDFLAGS)", file=makefile) + print("var3=$(CPPFLAGS)", file=makefile) + with EnvironmentVarGuard() as env: + env.clear() + vars = _parse_makefile(TESTFN) + self.assertEqual(vars, { + 'var1': '-Wall', + 'CFLAGS': '-Wall', + 'PY_CFLAGS': '-Wall', + 'LDFLAGS': '-lm', + 'PY_LDFLAGS': '-lm', + 'var2': '-lm', + 'var3': '', + }) + + def test_parse_makefile_keep_unresolved(self): + self.addCleanup(unlink, TESTFN) + with open(TESTFN, "w") as makefile: + print("var1=value", file=makefile) + print("var2=$/", file=makefile) + print("var3=$/$(var1)", file=makefile) + print("var4=var5=$(var5)", file=makefile) + print("var5=$/$(var1)", file=makefile) + print("var6=$(var1)$/", file=makefile) + print("var7=var8=$(var8)", file=makefile) + print("var8=$(var1)$/", file=makefile) + vars = _parse_makefile(TESTFN) + self.assertEqual(vars, { + 'var1': 'value', + 'var2': '$/', + 'var3': '$/value', + 'var4': 'var5=$/value', + 'var5': '$/value', + 'var6': 'value$/', + 'var7': 'var8=value$/', + 'var8': 'value$/', + }) + vars = _parse_makefile(TESTFN, keep_unresolved=False) + self.assertEqual(vars, { + 'var1': 'value', + 'var4': 'var5=', + 'var7': 'var8=', }) diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index 30dcb3e3c4f..e575aac037e 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -3,7 +3,8 @@ Glossary: * errored : Whitespace related problems present in file. """ -from unittest import TestCase, mock + +from unittest import TestCase, main, mock import errno import os import tabnanny @@ -352,3 +353,17 @@ class TestCommandLine(TestCase): "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-vv", path, stdout=stdout, partial=True) + + +class TestModule(TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(tabnanny, "__version__") + self.assertEqual(cm.filename, __file__) + + +if __name__ == "__main__": + main() diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 860413b88eb..9892005787c 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -2777,7 +2777,7 @@ class MiscTest(unittest.TestCase): str(excinfo.exception), ) - @unittest.skipUnless(os_helper.can_symlink(), 'requires symlink support') + @os_helper.skip_unless_symlink @unittest.skipUnless(hasattr(os, 'chmod'), "missing os.chmod") @unittest.mock.patch('os.chmod') def test_deferred_directory_attributes_update(self, mock_chmod): @@ -3663,6 +3663,39 @@ class TestExtractionFilters(unittest.TestCase): # The destination for the extraction, within `outerdir` destdir = outerdir / 'dest' + @classmethod + def setUpClass(cls): + # Posix and Windows have different pathname resolution: + # either symlink or a '..' component resolve first. + # Let's see which we are on. + if os_helper.can_symlink(): + testpath = os.path.join(TEMPDIR, 'resolution_test') + os.mkdir(testpath) + + # testpath/current links to `.` which is all of: + # - `testpath` + # - `testpath/current` + # - `testpath/current/current` + # - etc. + os.symlink('.', os.path.join(testpath, 'current')) + + # we'll test where `testpath/current/../file` ends up + with open(os.path.join(testpath, 'current', '..', 'file'), 'w'): + pass + + if os.path.exists(os.path.join(testpath, 'file')): + # Windows collapses 'current\..' to '.' first, leaving + # 'testpath\file' + cls.dotdot_resolves_early = True + elif os.path.exists(os.path.join(testpath, '..', 'file')): + # Posix resolves 'current' to '.' first, leaving + # 'testpath/../file' + cls.dotdot_resolves_early = False + else: + raise AssertionError('Could not determine link resolution') + else: + cls.dotdot_resolves_early = False + @contextmanager def check_context(self, tar, filter, *, check_flag=True): """Extracts `tar` to `self.destdir` and allows checking the result @@ -3809,23 +3842,21 @@ class TestExtractionFilters(unittest.TestCase): arc.add('current', symlink_to='.') # effectively points to ./../ - arc.add('parent', symlink_to='current/..') + if self.dotdot_resolves_early and os_helper.can_symlink(): + arc.add('parent', symlink_to='current/../..') + else: + arc.add('parent', symlink_to='current/..') arc.add('parent/evil') if os_helper.can_symlink(): with self.check_context(arc.open(), 'fully_trusted'): - if self.raised_exception is not None: - # Windows will refuse to create a file that's a symlink to itself - # (and tarfile doesn't swallow that exception) - self.expect_exception(FileExistsError) - # The other cases will fail with this error too. - # Skip the rest of this test. - return + self.expect_file('current', symlink_to='.') + if self.dotdot_resolves_early: + self.expect_file('parent', symlink_to='current/../..') else: - self.expect_file('current', symlink_to='.') self.expect_file('parent', symlink_to='current/..') - self.expect_file('../evil') + self.expect_file('../evil') with self.check_context(arc.open(), 'tar'): self.expect_exception( @@ -3927,35 +3958,6 @@ class TestExtractionFilters(unittest.TestCase): # Test interplaying symlinks # Inspired by 'dirsymlink2b' in jwilk/traversal-archives - # Posix and Windows have different pathname resolution: - # either symlink or a '..' component resolve first. - # Let's see which we are on. - if os_helper.can_symlink(): - testpath = os.path.join(TEMPDIR, 'resolution_test') - os.mkdir(testpath) - - # testpath/current links to `.` which is all of: - # - `testpath` - # - `testpath/current` - # - `testpath/current/current` - # - etc. - os.symlink('.', os.path.join(testpath, 'current')) - - # we'll test where `testpath/current/../file` ends up - with open(os.path.join(testpath, 'current', '..', 'file'), 'w'): - pass - - if os.path.exists(os.path.join(testpath, 'file')): - # Windows collapses 'current\..' to '.' first, leaving - # 'testpath\file' - dotdot_resolves_early = True - elif os.path.exists(os.path.join(testpath, '..', 'file')): - # Posix resolves 'current' to '.' first, leaving - # 'testpath/../file' - dotdot_resolves_early = False - else: - raise AssertionError('Could not determine link resolution') - with ArchiveMaker() as arc: # `current` links to `.` which is both the destination directory @@ -3991,7 +3993,7 @@ class TestExtractionFilters(unittest.TestCase): with self.check_context(arc.open(), 'data'): if os_helper.can_symlink(): - if dotdot_resolves_early: + if self.dotdot_resolves_early: # Fail when extracting a file outside destination self.expect_exception( tarfile.OutsideDestinationError, @@ -4039,6 +4041,21 @@ class TestExtractionFilters(unittest.TestCase): tarfile.AbsoluteLinkError, "'parent' is a link to an absolute path") + @symlink_test + @os_helper.skip_unless_symlink + def test_symlink_target_seperator_rewrite_on_windows(self): + with ArchiveMaker() as arc: + arc.add('link', symlink_to="relative/test/path") + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('link', type=tarfile.SYMTYPE) + link_path = os.path.normpath(self.destdir / "link") + link_target = os.readlink(link_path) + if os.name == "nt": + self.assertEqual(link_target, "relative\\test\\path") + else: + self.assertEqual(link_target, "relative/test/path") + def test_absolute_hardlink(self): # Test hardlink to an absolute path # Inspired by 'dirsymlink' in https://github.com/jwilk/traversal-archives diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 52b13b98cbc..7eec34f2f29 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1386,7 +1386,7 @@ class TestSpooledTemporaryFile(BaseTestCase): f.write(b'x') self.assertTrue(f._rolled) - self.assertEqual(f.mode, 'rb+') + self.assertEqual(f.mode, 'wb+') self.assertIsNotNone(f.name) with self.assertRaises(AttributeError): f.newlines diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py index cbd383ea4e2..aca1f427656 100644 --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -605,7 +605,7 @@ How *do* you spell that odd word, anyways? # bug 1146. Prevent a long word to be wrongly wrapped when the # preceding word is exactly one character shorter than the width self.check_wrap(self.text, 12, - ['Did you say ', + ['Did you say', '"supercalifr', 'agilisticexp', 'ialidocious?', @@ -633,7 +633,7 @@ How *do* you spell that odd word, anyways? def test_max_lines_long(self): self.check_wrap(self.text, 12, - ['Did you say ', + ['Did you say', '"supercalifr', 'agilisticexp', '[...]'], diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 0ba78b9a180..efd69a1f4fe 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -6,7 +6,7 @@ import test.support from test.support import threading_helper, requires_subprocess, requires_gil_enabled from test.support import verbose, cpython_only, os_helper from test.support.import_helper import ensure_lazy_imports, import_module -from test.support.script_helper import assert_python_ok, assert_python_failure +from test.support.script_helper import assert_python_ok, assert_python_failure, spawn_python from test.support import force_not_colorized import random @@ -1430,6 +1430,33 @@ class ThreadTests(BaseTestCase): self.assertEqual(len(native_ids), 2) self.assertNotEqual(native_ids[0], native_ids[1]) + def test_stop_the_world_during_finalization(self): + # gh-137433: Test functions that trigger a stop-the-world in the free + # threading build concurrent with interpreter finalization. + script = """if True: + import gc + import sys + import threading + NUM_THREADS = 5 + b = threading.Barrier(NUM_THREADS + 1) + def run_in_bg(): + b.wait() + while True: + sys.setprofile(None) + gc.collect() + + for _ in range(NUM_THREADS): + t = threading.Thread(target=run_in_bg, daemon=True) + t.start() + + b.wait() + print("Exiting...") + """ + rc, out, err = assert_python_ok('-c', script) + self.assertEqual(rc, 0) + self.assertEqual(err, b"") + self.assertEqual(out.strip(), b"Exiting...") + class ThreadJoinOnShutdown(BaseTestCase): def _run_and_join(self, script): @@ -1749,6 +1776,7 @@ class SubinterpThreadingTests(BaseTestCase): self.assertEqual(os.read(r_interp, 1), DONE) @cpython_only + @support.skip_if_sanitizer(thread=True, memory=True) def test_daemon_threads_fatal_error(self): import_module("_testcapi") subinterp_code = f"""if 1: @@ -1767,10 +1795,7 @@ class SubinterpThreadingTests(BaseTestCase): _testcapi.run_in_subinterp(%r) """ % (subinterp_code,) - with test.support.SuppressCrashReport(): - rc, out, err = assert_python_failure("-c", script) - self.assertIn("Fatal Python error: Py_EndInterpreter: " - "not the last thread", err.decode()) + assert_python_ok("-c", script) def _check_allowed(self, before_start='', *, allowed=True, @@ -2059,6 +2084,32 @@ class ThreadingExceptionTests(BaseTestCase): self.assertEqual(out, b"") self.assertEqual(err, b"") + @requires_subprocess() + @unittest.skipIf(os.name == 'nt', "signals don't work well on windows") + def test_keyboard_interrupt_during_threading_shutdown(self): + import subprocess + source = f""" + from threading import Thread + import time + import os + + + def test(): + print('a', flush=True, end='') + time.sleep(10) + + + for _ in range(3): + Thread(target=test).start() + """ + + with spawn_python("-c", source, stderr=subprocess.PIPE) as proc: + self.assertEqual(proc.stdout.read(3), b'aaa') + proc.send_signal(signal.SIGINT) + proc.stderr.flush() + error = proc.stderr.read() + self.assertIn(b"KeyboardInterrupt", error) + class ThreadRunFail(threading.Thread): def run(self): @@ -2281,6 +2332,9 @@ class MiscTestCase(unittest.TestCase): @unittest.skipUnless(hasattr(_thread, 'set_name'), "missing _thread.set_name") @unittest.skipUnless(hasattr(_thread, '_get_name'), "missing _thread._get_name") def test_set_name(self): + # Ensure main thread name is restored after test + self.addCleanup(_thread.set_name, _thread._get_name()) + # set_name() limit in bytes truncate = getattr(_thread, "_NAME_MAXLEN", None) limit = truncate or 100 @@ -2320,7 +2374,8 @@ class MiscTestCase(unittest.TestCase): tests.append(os_helper.TESTFN_UNENCODABLE) if sys.platform.startswith("sunos"): - encoding = "utf-8" + # Use ASCII encoding on Solaris/Illumos/OpenIndiana + encoding = "ascii" else: encoding = sys.getfilesystemencoding() @@ -2336,7 +2391,7 @@ class MiscTestCase(unittest.TestCase): if truncate is not None: encoded = encoded[:truncate] if sys.platform.startswith("sunos"): - expected = encoded.decode("utf-8", "surrogateescape") + expected = encoded.decode("ascii", "surrogateescape") else: expected = os.fsdecode(encoded) else: @@ -2355,7 +2410,11 @@ class MiscTestCase(unittest.TestCase): if '\0' in expected: expected = expected.split('\0', 1)[0] - with self.subTest(name=name, expected=expected): + with self.subTest(name=name, expected=expected, thread="main"): + _thread.set_name(name) + self.assertEqual(_thread._get_name(), expected) + + with self.subTest(name=name, expected=expected, thread="worker"): work_name = None thread = threading.Thread(target=work, name=name) thread.start() diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 5312faa5077..c7e81fff6f7 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -2,6 +2,7 @@ from test import support from test.support import warnings_helper import decimal import enum +import fractions import math import platform import sys @@ -170,10 +171,12 @@ class TimeTestCase(unittest.TestCase): # Improved exception #81267 with self.assertRaises(TypeError) as errmsg: time.sleep([]) - self.assertIn("integer or float", str(errmsg.exception)) + self.assertIn("real number", str(errmsg.exception)) def test_sleep(self): - for value in [-0.0, 0, 0.0, 1e-100, 1e-9, 1e-6, 1, 1.2]: + for value in [-0.0, 0, 0.0, 1e-100, 1e-9, 1e-6, 1, 1.2, + decimal.Decimal('0.02'), + fractions.Fraction(1, 50)]: with self.subTest(value=value): time.sleep(value) @@ -756,7 +759,6 @@ class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear, unittest.TestCase): class TestPytime(unittest.TestCase): @skip_if_buggy_ucrt_strfptime - @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") def test_localtime_timezone(self): # Get the localtime and examine it for the offset and zone. @@ -791,14 +793,12 @@ class TestPytime(unittest.TestCase): self.assertEqual(new_lt.tm_gmtoff, lt.tm_gmtoff) self.assertEqual(new_lt9.tm_zone, lt.tm_zone) - @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") def test_strptime_timezone(self): t = time.strptime("UTC", "%Z") self.assertEqual(t.tm_zone, 'UTC') t = time.strptime("+0500", "%z") self.assertEqual(t.tm_gmtoff, 5 * 3600) - @unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support") def test_short_times(self): import pickle diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py index 2aeebea9f93..f8bc306b455 100644 --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -4,8 +4,9 @@ import sys import io from textwrap import dedent -from test.support import captured_stdout -from test.support import captured_stderr +from test.support import ( + captured_stdout, captured_stderr, force_not_colorized, +) # timeit's default number of iterations. DEFAULT_NUMBER = 1000000 @@ -351,11 +352,13 @@ class TestTimeit(unittest.TestCase): self.assertEqual(error_stringio.getvalue(), "Unrecognized unit. Please select nsec, usec, msec, or sec.\n") + @force_not_colorized def test_main_exception(self): with captured_stderr() as error_stringio: s = self.run_main(switches=['1/0']) self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError') + @force_not_colorized def test_main_exception_fixed_reps(self): with captured_stderr() as error_stringio: s = self.run_main(switches=['-n1', '1/0']) diff --git a/Lib/test/test_tkinter/test_font.py b/Lib/test/test_tkinter/test_font.py index 563707ddd2f..fc50f9fdbb5 100644 --- a/Lib/test/test_tkinter/test_font.py +++ b/Lib/test/test_tkinter/test_font.py @@ -1,3 +1,4 @@ +import collections.abc import unittest import tkinter from tkinter import font @@ -118,6 +119,16 @@ class FontTest(AbstractTkTest, unittest.TestCase): repr(self.font), f'<tkinter.font.Font object {fontname!r}>' ) + def test_iterable_protocol(self): + self.assertNotIsSubclass(font.Font, collections.abc.Iterable) + self.assertNotIsSubclass(font.Font, collections.abc.Container) + self.assertNotIsInstance(self.font, collections.abc.Iterable) + self.assertNotIsInstance(self.font, collections.abc.Container) + with self.assertRaisesRegex(TypeError, 'is not iterable'): + iter(self.font) + with self.assertRaisesRegex(TypeError, 'is not a container or iterable'): + self.font in self.font + class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): @@ -159,5 +170,15 @@ class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): self.assertRaises(RuntimeError, font.nametofont, fontname) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(font, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index 38371fe00d6..358a18beee2 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -1,3 +1,4 @@ +import collections.abc import unittest import tkinter from test import support @@ -61,7 +62,33 @@ class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): self.assertRaises(RuntimeError, tkinter.PhotoImage) -class BitmapImageTest(AbstractTkTest, unittest.TestCase): +class BaseImageTest: + def create(self): + return self.image_class('::img::test', master=self.root, + file=self.testfile) + + def test_bug_100814(self): + # gh-100814: Passing a callable option value causes AttributeError. + with self.assertRaises(tkinter.TclError): + self.image_class('::img::test', master=self.root, spam=print) + image = self.image_class('::img::test', master=self.root) + with self.assertRaises(tkinter.TclError): + image.configure(spam=print) + + def test_iterable_protocol(self): + image = self.create() + self.assertNotIsSubclass(self.image_class, collections.abc.Iterable) + self.assertNotIsSubclass(self.image_class, collections.abc.Container) + self.assertNotIsInstance(image, collections.abc.Iterable) + self.assertNotIsInstance(image, collections.abc.Container) + with self.assertRaisesRegex(TypeError, 'is not iterable'): + iter(image) + with self.assertRaisesRegex(TypeError, 'is not a container or iterable'): + image in image + + +class BitmapImageTest(BaseImageTest, AbstractTkTest, unittest.TestCase): + image_class = tkinter.BitmapImage @classmethod def setUpClass(cls): @@ -144,26 +171,15 @@ class BitmapImageTest(AbstractTkTest, unittest.TestCase): self.assertEqual(image['foreground'], '-foreground {} {} #000000 yellow') - def test_bug_100814(self): - # gh-100814: Passing a callable option value causes AttributeError. - with self.assertRaises(tkinter.TclError): - tkinter.BitmapImage('::img::test', master=self.root, spam=print) - image = tkinter.BitmapImage('::img::test', master=self.root) - with self.assertRaises(tkinter.TclError): - image.configure(spam=print) - -class PhotoImageTest(AbstractTkTest, unittest.TestCase): +class PhotoImageTest(BaseImageTest, AbstractTkTest, unittest.TestCase): + image_class = tkinter.PhotoImage @classmethod def setUpClass(cls): AbstractTkTest.setUpClass.__func__(cls) cls.testfile = support.findfile('python.gif', subdir='tkinterdata') - def create(self): - return tkinter.PhotoImage('::img::test', master=self.root, - file=self.testfile) - def colorlist(self, *args): if tkinter.TkVersion >= 8.6 and self.wantobjects: return args @@ -282,14 +298,6 @@ class PhotoImageTest(AbstractTkTest, unittest.TestCase): image.configure(palette='3/4/2') self.assertEqual(image['palette'], '3/4/2') - def test_bug_100814(self): - # gh-100814: Passing a callable option value causes AttributeError. - with self.assertRaises(tkinter.TclError): - tkinter.PhotoImage('::img::test', master=self.root, spam=print) - image = tkinter.PhotoImage('::img::test', master=self.root) - with self.assertRaises(tkinter.TclError): - image.configure(spam=print) - def test_blank(self): image = self.create() image.blank() diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index 0c76e07066f..32e2329506e 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -1,3 +1,4 @@ +import collections.abc import functools import unittest import tkinter @@ -508,6 +509,17 @@ class MiscTest(AbstractTkTest, unittest.TestCase): widget.selection_range(0, 'end') self.assertEqual(widget.selection_get(), '\u20ac\0abc\x00def') + def test_iterable_protocol(self): + widget = tkinter.Entry(self.root) + self.assertNotIsSubclass(tkinter.Entry, collections.abc.Iterable) + self.assertNotIsSubclass(tkinter.Entry, collections.abc.Container) + self.assertNotIsInstance(widget, collections.abc.Iterable) + self.assertNotIsInstance(widget, collections.abc.Container) + with self.assertRaisesRegex(TypeError, 'is not iterable'): + iter(widget) + with self.assertRaisesRegex(TypeError, 'is not a container or iterable'): + widget in widget + class WmTest(AbstractTkTest, unittest.TestCase): diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index b26956930d3..d579cca95ee 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -34,12 +34,116 @@ class TextTest(AbstractTkTest, unittest.TestCase): # Invalid text index. self.assertRaises(tkinter.TclError, text.search, '', 0) + self.assertRaises(tkinter.TclError, text.search, '', '') + self.assertRaises(tkinter.TclError, text.search, '', 'invalid') + self.assertRaises(tkinter.TclError, text.search, '', '1.0', 0) + self.assertRaises(tkinter.TclError, text.search, '', '1.0', '') + self.assertRaises(tkinter.TclError, text.search, '', '1.0', 'invalid') - # Check if we are getting the indices as strings -- you are likely - # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. - text.insert('1.0', 'hi-test') - self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') - self.assertEqual(text.search('test', '1.0', 'end'), '1.3') + text.insert('1.0', + 'This is a test. This is only a test.\n' + 'Another line.\n' + 'Yet another line.\n' + '64-bit') + + self.assertEqual(text.search('test', '1.0'), '1.10') + self.assertEqual(text.search('test', '1.0', 'end'), '1.10') + self.assertEqual(text.search('test', '1.0', '1.10'), '') + self.assertEqual(text.search('test', '1.11'), '1.31') + self.assertEqual(text.search('test', '1.32', 'end'), '') + self.assertEqual(text.search('test', '1.32'), '1.10') + + self.assertEqual(text.search('', '1.0'), '1.0') # empty pattern + self.assertEqual(text.search('nonexistent', '1.0'), '') + self.assertEqual(text.search('-bit', '1.0'), '4.2') # starts with a hyphen + + self.assertEqual(text.search('line', '3.0'), '3.12') + self.assertEqual(text.search('line', '3.0', forwards=True), '3.12') + self.assertEqual(text.search('line', '3.0', backwards=True), '2.8') + self.assertEqual(text.search('line', '3.0', forwards=True, backwards=True), '2.8') + + self.assertEqual(text.search('t.', '1.0'), '1.13') + self.assertEqual(text.search('t.', '1.0', exact=True), '1.13') + self.assertEqual(text.search('t.', '1.0', regexp=True), '1.10') + self.assertEqual(text.search('t.', '1.0', exact=True, regexp=True), '1.10') + + self.assertEqual(text.search('TEST', '1.0'), '') + self.assertEqual(text.search('TEST', '1.0', nocase=True), '1.10') + + self.assertEqual(text.search('.*line', '1.0', regexp=True), '2.0') + self.assertEqual(text.search('.*line', '1.0', regexp=True, nolinestop=True), '1.0') + + self.assertEqual(text.search('test', '1.0', '1.13'), '1.10') + self.assertEqual(text.search('test', '1.0', '1.13', strictlimits=True), '') + self.assertEqual(text.search('test', '1.0', '1.14', strictlimits=True), '1.10') + + var = tkinter.Variable(self.root) + self.assertEqual(text.search('test', '1.0', count=var), '1.10') + self.assertEqual(var.get(), 4 if self.wantobjects else '4') + + # TODO: Add test for elide=True + + def test_search_all(self): + text = self.text + + # pattern and index are obligatory arguments. + self.assertRaises(tkinter.TclError, text.search_all, None, '1.0') + self.assertRaises(tkinter.TclError, text.search_all, 'a', None) + self.assertRaises(tkinter.TclError, text.search_all, None, None) + + # Keyword-only arguments + self.assertRaises(TypeError, text.search_all, 'a', '1.0', 'end', None) + + # Invalid text index. + self.assertRaises(tkinter.TclError, text.search_all, '', 0) + self.assertRaises(tkinter.TclError, text.search_all, '', '') + self.assertRaises(tkinter.TclError, text.search_all, '', 'invalid') + self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', 0) + self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', '') + self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', 'invalid') + + def eq(res, expected): + self.assertIsInstance(res, tuple) + self.assertEqual([str(i) for i in res], expected) + + text.insert('1.0', 'ababa\naba\n64-bit') + + eq(text.search_all('aba', '1.0'), ['1.0', '2.0']) + eq(text.search_all('aba', '1.0', 'end'), ['1.0', '2.0']) + eq(text.search_all('aba', '1.1', 'end'), ['1.2', '2.0']) + eq(text.search_all('aba', '1.1'), ['1.2', '2.0', '1.0']) + + res = text.search_all('', '1.0') # empty pattern + eq(res[:5], ['1.0', '1.1', '1.2', '1.3', '1.4']) + eq(res[-5:], ['3.2', '3.3', '3.4', '3.5', '3.6']) + eq(text.search_all('nonexistent', '1.0'), []) + eq(text.search_all('-bit', '1.0'), ['3.2']) # starts with a hyphen + + eq(text.search_all('aba', '1.0', 'end', forwards=True), ['1.0', '2.0']) + eq(text.search_all('aba', 'end', '1.0', backwards=True), ['2.0', '1.2']) + + eq(text.search_all('aba', '1.0', overlap=True), ['1.0', '1.2', '2.0']) + eq(text.search_all('aba', 'end', '1.0', overlap=True, backwards=True), ['2.0', '1.2', '1.0']) + + eq(text.search_all('aba', '1.0', exact=True), ['1.0', '2.0']) + eq(text.search_all('a.a', '1.0', exact=True), []) + eq(text.search_all('a.a', '1.0', regexp=True), ['1.0', '2.0']) + + eq(text.search_all('ABA', '1.0'), []) + eq(text.search_all('ABA', '1.0', nocase=True), ['1.0', '2.0']) + + eq(text.search_all('a.a', '1.0', regexp=True), ['1.0', '2.0']) + eq(text.search_all('a.a', '1.0', regexp=True, nolinestop=True), ['1.0', '1.4']) + + eq(text.search_all('aba', '1.0', '2.2'), ['1.0', '2.0']) + eq(text.search_all('aba', '1.0', '2.2', strictlimits=True), ['1.0']) + eq(text.search_all('aba', '1.0', '2.3', strictlimits=True), ['1.0', '2.0']) + + var = tkinter.Variable(self.root) + eq(text.search_all('aba', '1.0', count=var), ['1.0', '2.0']) + self.assertEqual(var.get(), (3, 3) if self.wantobjects else '3 3') + + # TODO: Add test for elide=True def test_count(self): text = self.text diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index ff3f92e9b5e..20e385ad0b6 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -315,7 +315,10 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): def test_configure_height(self): widget = self.create() - self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) + if tk_version < (9, 0): + self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) + else: + self.checkIntegerParam(widget, 'height', 0, -100, 0) def test_configure_image(self): widget = self.create() @@ -342,7 +345,10 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): def test_configure_width(self): widget = self.create() - self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) + if tk_version < (9, 0): + self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) + else: + self.checkIntegerParam(widget, 'width', 402, 0, 0) class OptionMenuTest(MenubuttonTest, unittest.TestCase): @@ -391,8 +397,12 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase): def test_configure_insertborderwidth(self): widget = self.create(insertwidth=100) - self.checkPixelsParam(widget, 'insertborderwidth', - 0, 1.3, 2.6, 6, '10p') + if tk_version < (9, 0): + self.checkPixelsParam(widget, 'insertborderwidth', + 0, 1.3, 2.6, 6, '10p') + else: + self.checkPixelsParam(widget, 'insertborderwidth', + 0, 1.3, 3, 6, '10p') self.checkParam(widget, 'insertborderwidth', -2) # insertborderwidth is bounded above by a half of insertwidth. expected = 100 // 2 if tk_version < (9, 0) else 60 @@ -551,11 +561,22 @@ class SpinboxTest(EntryTest, unittest.TestCase): # XXX widget = self.create() self.assertEqual(widget['values'], '') - self.checkParam(widget, 'values', 'mon tue wed thur') + if tk_version < (9, 0): + expected = 'mon tue wed thur' + else: + expected = ('mon', 'tue', 'wed', 'thur') + self.checkParam(widget, 'values', 'mon tue wed thur', + expected=expected) self.checkParam(widget, 'values', ('mon', 'tue', 'wed', 'thur'), - expected='mon tue wed thur') + expected=expected) + + if tk_version < (9, 0): + expected = '42 3.14 {} {any string}' + else: + expected = (42, 3.14, '', 'any string') self.checkParam(widget, 'values', (42, 3.14, '', 'any string'), - expected='42 3.14 {} {any string}') + expected=expected) + self.checkParam(widget, 'values', '') def test_configure_wrap(self): @@ -649,10 +670,9 @@ class TextTest(AbstractWidgetTest, unittest.TestCase): def test_configure_height(self): widget = self.create() self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c') - self.checkParam(widget, 'height', -100, - expected=1 if tk_version < (9, 0) else -100) - self.checkParam(widget, 'height', 0, - expected=1 if tk_version < (9, 0) else 0 ) + expected = 1 if tk_version < (9, 0) else 0 + self.checkParam(widget, 'height', -100, expected=expected) + self.checkParam(widget, 'height', 0, expected=expected) def test_configure_maxundo(self): widget = self.create() @@ -670,8 +690,9 @@ class TextTest(AbstractWidgetTest, unittest.TestCase): def test_configure_selectborderwidth(self): widget = self.create() + value = -2 if tk_version < (9, 0) else 0 self.checkPixelsParam(widget, 'selectborderwidth', - 1.3, 2.6, -2, '10p', conv=False) + 1.3, 2.6, value, '10p', conv=False) def test_configure_spacing1(self): widget = self.create() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index f518925e994..dd2d7c4da45 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -247,7 +247,11 @@ class PixelOptionsTests: widget = self.create() self.checkPixelsParam(widget, 'borderwidth', 0, 1.3, 2.6, 6, '10p') - self.checkParam(widget, 'borderwidth', -2) + if tk_version < (9, 0): + self.checkParam(widget, 'borderwidth', -2) + else: + self.checkParam(widget, 'borderwidth', 0) + if 'bd' in self.OPTIONS: self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, '10p') self.checkParam(widget, 'bd', -2, expected=expected) @@ -260,27 +264,46 @@ class PixelOptionsTests: def test_configure_insertborderwidth(self): widget = self.create() - self.checkPixelsParam(widget, 'insertborderwidth', - 0, 1.3, 2.6, 6, '10p') - self.checkParam(widget, 'insertborderwidth', -2) + if tk_version < (9, 0): + values = (0, 1.3, 2.6, 6, -2, '10p') + value = -2 + else: + values = (0, 1, 3, 6, 13) + value = 0 + self.checkPixelsParam(widget, 'insertborderwidth', *values) + self.checkParam(widget, 'insertborderwidth', value) def test_configure_insertwidth(self): widget = self.create() - self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p') + if tk_version < (9, 0): + self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p') + else: + self.checkPixelsParam(widget, 'insertwidth', 1, 3, 0, 13) def test_configure_padx(self): widget = self.create() self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'padx', -2) + if tk_version < (9, 0): + self.checkParam(widget, 'padx', -2) + else: + self.checkParam(widget, 'padx', 0) def test_configure_pady(self): widget = self.create() self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'pady', -2) + if tk_version < (9, 0): + self.checkParam(widget, 'pady', -2) + else: + self.checkParam(widget, 'pady', 0) def test_configure_selectborderwidth(self): widget = self.create() - self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p') + if tk_version < (9, 0): + values = (1.3, 2.6, -2, '10p') + else: + values = (1, 3, 0, 13) + self.checkPixelsParam(widget, 'selectborderwidth', *values) + class StandardOptionsTests(PixelOptionsTests): @@ -546,22 +569,34 @@ class IntegerSizeTests: """ Tests widgets which only accept integral width and height.""" def test_configure_height(self): widget = self.create() - self.checkIntegerParam(widget, 'height', 100, -100, 0) + if tk_version < (9, 0): + self.checkIntegerParam(widget, 'height', 100, -100, 0) + else: + self.checkIntegerParam(widget, 'height', 100, 0, 0) def test_configure_width(self): widget = self.create() - self.checkIntegerParam(widget, 'width', 402, -402, 0) + if tk_version < (9, 0): + self.checkIntegerParam(widget, 'width', 402, -402, 0) + else: + self.checkIntegerParam(widget, 'width', 402, 0, 0) class PixelSizeTests: """ Tests widgets which accept screen distances for width and height.""" def test_configure_height(self): widget = self.create() - self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c') + value = -100 if tk_version < (9, 0) else 0 + self.checkPixelsParam( + widget, 'height', 100, 101.2, 102.6, value, 0, '3c' + ) def test_configure_width(self): widget = self.create() - self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i') + value = -402 if tk_version < (9, 0) else 0 + self.checkPixelsParam( + widget, 'width', 402, 403.4, 404.6, value, 0, '5i' + ) def add_configure_tests(*source_classes): diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 865e0c5b40d..ca67e381958 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1216,6 +1216,23 @@ f''' FSTRING_END "\'\'\'" (3, 1) (3, 4) """) + # gh-139516, the '\n' is explicit to ensure no trailing whitespace which would invalidate the test + self.check_tokenize('''f"{f(a=lambda: 'à'\n)}"''', """\ + FSTRING_START \'f"\' (1, 0) (1, 2) + OP '{' (1, 2) (1, 3) + NAME 'f' (1, 3) (1, 4) + OP '(' (1, 4) (1, 5) + NAME 'a' (1, 5) (1, 6) + OP '=' (1, 6) (1, 7) + NAME 'lambda' (1, 7) (1, 13) + OP ':' (1, 13) (1, 14) + STRING "\'à\'" (1, 15) (1, 18) + NL '\\n' (1, 18) (1, 19) + OP ')' (2, 0) (2, 1) + OP '}' (2, 1) (2, 2) + FSTRING_END \'"\' (2, 2) (2, 3) + """) + class GenerateTokensTest(TokenizeTest): def check_tokenize(self, s, expected): # Format the tokens in s in a table format. @@ -1346,7 +1363,8 @@ class TestDetectEncoding(TestCase): def test_no_bom_no_encoding_cookie(self): lines = ( - b'# something\n', + b'#!/home/\xc3\xa4/bin/python\n', + b'# something \xe2\x82\xac\n', b'print(something)\n', b'do_something(else)\n' ) @@ -1354,16 +1372,54 @@ class TestDetectEncoding(TestCase): self.assertEqual(encoding, 'utf-8') self.assertEqual(consumed_lines, list(lines[:2])) + def test_no_bom_no_encoding_cookie_first_line_error(self): + lines = ( + b'#!/home/\xa4/bin/python\n\n', + b'print(something)\n', + b'do_something(else)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) + + def test_no_bom_no_encoding_cookie_second_line_error(self): + lines = ( + b'#!/usr/bin/python\n', + b'# something \xe2\n', + b'print(something)\n', + b'do_something(else)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) + def test_bom_no_cookie(self): lines = ( - b'\xef\xbb\xbf# something\n', + b'\xef\xbb\xbf#!/home/\xc3\xa4/bin/python\n', b'print(something)\n', b'do_something(else)\n' ) encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'utf-8-sig') self.assertEqual(consumed_lines, - [b'# something\n', b'print(something)\n']) + [b'#!/home/\xc3\xa4/bin/python\n', b'print(something)\n']) + + def test_bom_no_cookie_first_line_error(self): + lines = ( + b'\xef\xbb\xbf#!/home/\xa4/bin/python\n', + b'print(something)\n', + b'do_something(else)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) + + def test_bom_no_cookie_second_line_error(self): + lines = ( + b'\xef\xbb\xbf#!/usr/bin/python\n', + b'# something \xe2\n', + b'print(something)\n', + b'do_something(else)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) def test_cookie_first_line_no_bom(self): lines = ( @@ -1439,16 +1495,60 @@ class TestDetectEncoding(TestCase): expected = [b"print('\xc2\xa3')\n"] self.assertEqual(consumed_lines, expected) - def test_cookie_second_line_commented_first_line(self): + def test_first_non_utf8_coding_line(self): lines = ( - b"#print('\xc2\xa3')\n", - b'# vim: set fileencoding=iso8859-15 :\n', - b"print('\xe2\x82\xac')\n" + b'#coding:iso-8859-15 \xa4\n', + b'print(something)\n' ) encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) - self.assertEqual(encoding, 'iso8859-15') - expected = [b"#print('\xc2\xa3')\n", b'# vim: set fileencoding=iso8859-15 :\n'] - self.assertEqual(consumed_lines, expected) + self.assertEqual(encoding, 'iso-8859-15') + self.assertEqual(consumed_lines, list(lines[:1])) + + def test_first_utf8_coding_line_error(self): + lines = ( + b'#coding:ascii \xc3\xa4\n', + b'print(something)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) + + def test_second_non_utf8_coding_line(self): + lines = ( + b'#!/usr/bin/python\n', + b'#coding:iso-8859-15 \xa4\n', + b'print(something)\n' + ) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso-8859-15') + self.assertEqual(consumed_lines, list(lines[:2])) + + def test_second_utf8_coding_line_error(self): + lines = ( + b'#!/usr/bin/python\n', + b'#coding:ascii \xc3\xa4\n', + b'print(something)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) + + def test_non_utf8_shebang(self): + lines = ( + b'#!/home/\xa4/bin/python\n', + b'#coding:iso-8859-15\n', + b'print(something)\n' + ) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso-8859-15') + self.assertEqual(consumed_lines, list(lines[:2])) + + def test_utf8_shebang_error(self): + lines = ( + b'#!/home/\xc3\xa4/bin/python\n', + b'#coding:ascii\n', + b'print(something)\n' + ) + with self.assertRaises(SyntaxError): + tokenize.detect_encoding(self.get_readline(lines)) def test_cookie_second_line_empty_first_line(self): lines = ( @@ -1461,6 +1561,70 @@ class TestDetectEncoding(TestCase): expected = [b'\n', b'# vim: set fileencoding=iso8859-15 :\n'] self.assertEqual(consumed_lines, expected) + def test_cookie_third_line(self): + lines = ( + b'#!/home/\xc3\xa4/bin/python\n', + b'# something\n', + b'# vim: set fileencoding=ascii :\n', + b'print(something)\n', + b'do_something(else)\n' + ) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'utf-8') + self.assertEqual(consumed_lines, list(lines[:2])) + + def test_double_coding_line(self): + # If the first line matches the second line is ignored. + lines = ( + b'#coding:iso8859-15\n', + b'#coding:latin1\n', + b'print(something)\n' + ) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso8859-15') + self.assertEqual(consumed_lines, list(lines[:1])) + + def test_double_coding_same_line(self): + lines = ( + b'#coding:iso8859-15 coding:latin1\n', + b'print(something)\n' + ) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso8859-15') + self.assertEqual(consumed_lines, list(lines[:1])) + + def test_double_coding_utf8(self): + lines = ( + b'#coding:utf-8\n', + b'#coding:latin1\n', + b'print(something)\n' + ) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'utf-8') + self.assertEqual(consumed_lines, list(lines[:1])) + + def test_nul_in_first_coding_line(self): + lines = ( + b'#coding:iso8859-15\x00\n', + b'\n', + b'\n', + b'print(something)\n' + ) + with self.assertRaisesRegex(SyntaxError, + "source code cannot contain null bytes"): + tokenize.detect_encoding(self.get_readline(lines)) + + def test_nul_in_second_coding_line(self): + lines = ( + b'#!/usr/bin/python\n', + b'#coding:iso8859-15\x00\n', + b'\n', + b'print(something)\n' + ) + with self.assertRaisesRegex(SyntaxError, + "source code cannot contain null bytes"): + tokenize.detect_encoding(self.get_readline(lines)) + def test_latin1_normalization(self): # See get_normal_name() in Parser/tokenizer/helpers.c. encodings = ("latin-1", "iso-8859-1", "iso-latin-1", "latin-1-unix", @@ -1485,7 +1649,6 @@ class TestDetectEncoding(TestCase): readline = self.get_readline(lines) self.assertRaises(SyntaxError, tokenize.detect_encoding, readline) - def test_utf8_normalization(self): # See get_normal_name() in Parser/tokenizer/helpers.c. encodings = ("utf-8", "utf-8-mac", "utf-8-unix") @@ -3020,6 +3183,7 @@ async def f(): f'__{ x:d }__'""", + " a\n\x00", ]: with self.subTest(case=case): self.assertRaises(tokenize.TokenError, get_tokens, case) diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index bf54c999537..19eee19bdea 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -142,6 +142,8 @@ class TestLineCounts(unittest.TestCase): self.assertEqual(self.tracer.results().counts, expected) + @unittest.skipIf(os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0', + "Line counts differ when JIT optimizer is disabled") def test_traced_func_loop(self): self.tracer.runfunc(traced_func_loop, 2, 3) @@ -166,6 +168,8 @@ class TestLineCounts(unittest.TestCase): self.assertEqual(self.tracer.results().counts, expected) + @unittest.skipIf(os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0', + "Line counts differ when JIT optimizer is disabled") def test_trace_func_generator(self): self.tracer.runfunc(traced_func_calling_generator) @@ -236,6 +240,8 @@ class TestRunExecCounts(unittest.TestCase): self.my_py_filename = fix_ext_py(__file__) self.addCleanup(sys.settrace, sys.gettrace()) + @unittest.skipIf(os.environ.get('PYTHON_UOPS_OPTIMIZE') == '0', + "Line counts differ when JIT optimizer is disabled") def test_exec_counts(self): self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0) code = r'''traced_func_loop(2, 5)''' diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index bd3ecfd9a38..96510eeec54 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -18,7 +18,7 @@ import shutil from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, requires_debug_ranges, has_no_debug_ranges, requires_subprocess) -from test.support.os_helper import TESTFN, unlink +from test.support.os_helper import TESTFN, temp_dir, unlink from test.support.script_helper import assert_python_ok, assert_python_failure, make_script from test.support.import_helper import forget from test.support import force_not_colorized, force_not_colorized_test_class @@ -88,6 +88,12 @@ class TracebackCases(unittest.TestCase): def tokenizer_error_with_caret_range(self): compile("blech ( ", "?", "exec") + def syntax_error_with_caret_wide_char(self): + compile("女女女=1; 女女女/", "?", "exec") + + def syntax_error_with_caret_wide_char_range(self): + compile("f(x, 女女女 for 女女女 in range(30), z)", "?", "exec") + def test_caret(self): err = self.get_exception_format(self.syntax_error_with_caret, SyntaxError) @@ -125,6 +131,20 @@ class TracebackCases(unittest.TestCase): self.assertEqual(err[1].find("("), err[2].find("^")) # in the right place self.assertEqual(err[2].count("^"), 1) + def test_caret_wide_char(self): + err = self.get_exception_format(self.syntax_error_with_caret_wide_char, + SyntaxError) + self.assertIn("^", err[2]) + # "女女女=1; 女女女/" has display width 17 + self.assertEqual(err[2].find("^"), 4 + 17) + + err = self.get_exception_format(self.syntax_error_with_caret_wide_char_range, + SyntaxError) + self.assertIn("^", err[2]) + self.assertEqual(err[2].find("^"), 4 + 5) + # "女女女 for 女女女 in range(30)" has display width 30 + self.assertEqual(err[2].count("^"), 30) + def test_nocaret(self): exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) err = traceback.format_exception_only(SyntaxError, exc) @@ -504,6 +524,33 @@ class TracebackCases(unittest.TestCase): b'ZeroDivisionError: division by zero'] self.assertEqual(stderr.splitlines(), expected) + @cpython_only + def test_lost_io_open(self): + # GH-142737: Display the traceback even if io.open is lost + crasher = textwrap.dedent("""\ + import io + import traceback + # Trigger fallback mode + traceback._print_exception_bltin = None + del io.open + raise RuntimeError("should not crash") + """) + + # Create a temporary script to exercise _Py_FindSourceFile + with temp_dir() as script_dir: + script = make_script( + script_dir=script_dir, + script_basename='tb_test_no_io_open', + source=crasher) + rc, stdout, stderr = assert_python_failure(script) + + self.assertEqual(rc, 1) # Make sure it's not a crash + + expected = [b'Traceback (most recent call last):', + f' File "{script}", line 6, in <module>'.encode(), + b'RuntimeError: should not crash'] + self.assertEqual(stderr.splitlines(), expected) + def test_print_exception(self): output = StringIO() traceback.print_exception( @@ -1784,6 +1831,23 @@ class TestKeywordTypoSuggestions(unittest.TestCase): stderr_text = stderr.decode('utf-8') self.assertIn(f"Did you mean '{expected_kw}'", stderr_text) + def test_no_keyword_suggestion_for_comma_errors(self): + # When the parser identifies a missing comma, don't suggest + # bogus keyword replacements like 'print' -> 'not' + code = '''\ +import sys +print( + "line1" + "line2" + file=sys.stderr +) +''' + source = textwrap.dedent(code).strip() + rc, stdout, stderr = assert_python_failure('-c', source) + stderr_text = stderr.decode('utf-8') + self.assertIn("Perhaps you forgot a comma", stderr_text) + self.assertNotIn("Did you mean", stderr_text) + @requires_debug_ranges() @force_not_colorized_test_class class PurePythonTracebackErrorCaretTests( @@ -5034,7 +5098,8 @@ class MiscTest(unittest.TestCase): self.assertIn( (b"Site initialization is disabled, did you forget to " - b"add the site-packages directory to sys.path?"), stderr + b"add the site-packages directory to sys.path " + b"or to enable your virtual environment?"), stderr ) code = """ @@ -5046,9 +5111,41 @@ class MiscTest(unittest.TestCase): self.assertNotIn( (b"Site initialization is disabled, did you forget to " - b"add the site-packages directory to sys.path?"), stderr + b"add the site-packages directory to sys.path " + b"or to enable your virtual environment?"), stderr ) + def test_missing_stdlib_module(self): + code = """ + import sys + sys.stdlib_module_names |= {'spam'} + import spam + """ + _, _, stderr = assert_python_failure('-S', '-c', code) + + self.assertIn(b"Standard library module 'spam' was not found", stderr) + + code = """ + import sys + import traceback + traceback._MISSING_STDLIB_MODULE_MESSAGES = {'spam': "Install 'spam4life' for 'spam'"} + sys.stdlib_module_names |= {'spam'} + import spam + """ + _, _, stderr = assert_python_failure('-S', '-c', code) + + self.assertIn(b"Install 'spam4life' for 'spam'", stderr) + + @unittest.skipIf(sys.platform == "win32", "Non-Windows test") + def test_windows_only_module_error(self): + try: + import msvcrt # noqa: F401 + except ModuleNotFoundError: + formatted = traceback.format_exc() + self.assertIn("Unsupported platform for Windows-only standard library module 'msvcrt'", formatted) + else: + self.fail("ModuleNotFoundError was not raised") + class TestColorizedTraceback(unittest.TestCase): maxDiff = None diff --git a/Lib/test/test_ttk/__init__.py b/Lib/test/test_ttk/__init__.py index 7ee7ffbd6d7..4a077a0f966 100644 --- a/Lib/test/test_ttk/__init__.py +++ b/Lib/test/test_ttk/__init__.py @@ -19,6 +19,16 @@ from _tkinter import TclError from tkinter import ttk +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(ttk, "__version__") + self.assertEqual(cm.filename, __file__) + + def setUpModule(): root = None try: diff --git a/Lib/test/test_tuple.py b/Lib/test/test_tuple.py index 9ce80c5e8ea..e533392b8ca 100644 --- a/Lib/test/test_tuple.py +++ b/Lib/test/test_tuple.py @@ -290,12 +290,18 @@ class TupleTest(seq_tests.CommonTest): self.assertEqual(repr(a0), "()") self.assertEqual(repr(a2), "(0, 1, 2)") + # Checks that t is not tracked without any GC collections. + def _not_tracked_instantly(self, t): + self.assertFalse(gc.is_tracked(t), t) + + # Checks that t is not tracked after GC collection. def _not_tracked(self, t): # Nested tuples can take several collections to untrack gc.collect() gc.collect() self.assertFalse(gc.is_tracked(t), t) + # Checks that t continues to be tracked even after GC collection. def _tracked(self, t): self.assertTrue(gc.is_tracked(t), t) gc.collect() @@ -307,13 +313,19 @@ class TupleTest(seq_tests.CommonTest): # Test GC-optimization of tuple literals x, y, z = 1.5, "a", [] - self._not_tracked(()) - self._not_tracked((1,)) - self._not_tracked((1, 2)) - self._not_tracked((1, 2, "a")) - self._not_tracked((1, 2, (None, True, False, ()), int)) - self._not_tracked((object(),)) + # We check that those objects aren't tracked at all. + # It's essential for the GC performance, see gh-139951. + self._not_tracked_instantly(()) + self._not_tracked_instantly((1,)) + self._not_tracked_instantly((1, 2)) + self._not_tracked_instantly((1, 2, "a")) + self._not_tracked_instantly((1, 2) * 5) + self._not_tracked_instantly((12, 10**10, 'a_' * 100)) + self._not_tracked_instantly((object(),)) + self._not_tracked(((1, x), y, (2, 3))) + self._not_tracked((1, 2, (None, True, False, ()), int)) + self._not_tracked((object(), ())) # Tuples with mutable elements are always tracked, even if those # elements are not tracked right now. @@ -343,6 +355,12 @@ class TupleTest(seq_tests.CommonTest): self._tracked(tp(tuple([obj]) for obj in [x, y, z])) self._tracked(tuple(tp([obj]) for obj in [x, y, z])) + t = tp([1, x, y, z]) + self.assertEqual(type(t), tp) + self._tracked(t) + self.assertEqual(type(t[:]), tuple) + self._tracked(t[:]) + @support.cpython_only def test_track_dynamic(self): # Test GC-optimization of dynamically constructed tuples. diff --git a/Lib/test/test_turtle.py b/Lib/test/test_turtle.py index d02cac284a9..12d2eed8741 100644 --- a/Lib/test/test_turtle.py +++ b/Lib/test/test_turtle.py @@ -60,12 +60,25 @@ def patch_screen(): We must patch the _Screen class itself instead of the _Screen instance because instantiating it requires a display. """ + # Create a mock screen that delegates color validation to the real TurtleScreen methods + mock_screen = unittest.mock.MagicMock() + mock_screen.__class__ = turtle._Screen + mock_screen.mode.return_value = "standard" + mock_screen._colormode = 1.0 + + def mock_iscolorstring(color): + valid_colors = {'red', 'green', 'blue', 'black', 'white', 'yellow', + 'orange', 'purple', 'pink', 'brown', 'gray', 'grey', + 'cyan', 'magenta'} + + return color in valid_colors or (isinstance(color, str) and color.startswith('#')) + + mock_screen._iscolorstring = mock_iscolorstring + mock_screen._colorstr = turtle._Screen._colorstr.__get__(mock_screen) + return unittest.mock.patch( "turtle._Screen.__new__", - **{ - "return_value.__class__": turtle._Screen, - "return_value.mode.return_value": "standard", - }, + return_value=mock_screen ) @@ -635,6 +648,28 @@ class TestTurtle(unittest.TestCase): self.assertTrue(self.turtle._creatingPoly) self.assertFalse(self.turtle._creatingPoly) + def test_dot_signature(self): + self.turtle.dot() + self.turtle.dot(10) + self.turtle.dot(size=10) + self.turtle.dot((0, 0, 0)) + self.turtle.dot(size=(0, 0, 0)) + self.turtle.dot("blue") + self.turtle.dot("") + self.turtle.dot(size="blue") + self.turtle.dot(20, "blue") + self.turtle.dot(20, "blue") + self.turtle.dot(20, (0, 0, 0)) + self.turtle.dot(20, 0, 0, 0) + with self.assertRaises(TypeError): + self.turtle.dot(color="blue") + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, "_not_a_color_") + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, 0, (0, 0, 0, 0)) + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, 0, 0, 0, 0, 0) + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, 0, (-1, 0, 0)) + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, 0, -1, 0, 0) + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, 0, (0, 257, 0)) + self.assertRaises(turtle.TurtleGraphicsError, self.turtle.dot, 0, 0, 257, 0) class TestModuleLevel(unittest.TestCase): def test_all_signatures(self): diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index ee1791bc1d0..9ceee565764 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -8,6 +8,11 @@ from typing import ( Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, Unpack, get_args, ) +type GlobalTypeAlias = int + +def get_type_alias(): + type TypeAliasInFunc = str + return TypeAliasInFunc class TypeParamsInvalidTest(unittest.TestCase): def test_name_collisions(self): @@ -70,6 +75,8 @@ class TypeParamsAccessTest(unittest.TestCase): class TypeParamsAliasValueTest(unittest.TestCase): + type TypeAliasInClass = dict + def test_alias_value_01(self): type TA1 = int @@ -142,33 +149,67 @@ class TypeParamsAliasValueTest(unittest.TestCase): self.assertIs(specialized2.__origin__, VeryGeneric) self.assertEqual(specialized2.__args__, (int, str, float, [bool, range])) + def test___name__(self): + type TypeAliasLocal = GlobalTypeAlias + + self.assertEqual(GlobalTypeAlias.__name__, 'GlobalTypeAlias') + self.assertEqual(get_type_alias().__name__, 'TypeAliasInFunc') + self.assertEqual(self.TypeAliasInClass.__name__, 'TypeAliasInClass') + self.assertEqual(TypeAliasLocal.__name__, 'TypeAliasLocal') + + with self.assertRaisesRegex( + AttributeError, + "readonly attribute", + ): + setattr(TypeAliasLocal, '__name__', 'TA') + + def test___qualname__(self): + type TypeAliasLocal = GlobalTypeAlias + + self.assertEqual(GlobalTypeAlias.__qualname__, + 'GlobalTypeAlias') + self.assertEqual(get_type_alias().__qualname__, + 'get_type_alias.<locals>.TypeAliasInFunc') + self.assertEqual(self.TypeAliasInClass.__qualname__, + 'TypeParamsAliasValueTest.TypeAliasInClass') + self.assertEqual(TypeAliasLocal.__qualname__, + 'TypeParamsAliasValueTest.test___qualname__.<locals>.TypeAliasLocal') + + with self.assertRaisesRegex( + AttributeError, + "readonly attribute", + ): + setattr(TypeAliasLocal, '__qualname__', 'TA') + def test_repr(self): type Simple = int - type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] + self.assertEqual(repr(Simple), Simple.__qualname__) - self.assertEqual(repr(Simple), "Simple") - self.assertEqual(repr(VeryGeneric), "VeryGeneric") + type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] + self.assertEqual(repr(VeryGeneric), VeryGeneric.__qualname__) + fullname = f"{VeryGeneric.__module__}.{VeryGeneric.__qualname__}" self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]), - "VeryGeneric[int, bytes, str, [float, object]]") + f"{fullname}[int, bytes, str, [float, object]]") self.assertEqual(repr(VeryGeneric[int, []]), - "VeryGeneric[int, []]") + f"{fullname}[int, []]") self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]), - "VeryGeneric[int, [VeryGeneric[int], list[str]]]") + f"{fullname}[int, [{fullname}[int], list[str]]]") def test_recursive_repr(self): type Recursive = Recursive - self.assertEqual(repr(Recursive), "Recursive") + self.assertEqual(repr(Recursive), Recursive.__qualname__) type X = list[Y] type Y = list[X] - self.assertEqual(repr(X), "X") - self.assertEqual(repr(Y), "Y") + self.assertEqual(repr(X), X.__qualname__) + self.assertEqual(repr(Y), Y.__qualname__) type GenericRecursive[X] = list[X | GenericRecursive[X]] - self.assertEqual(repr(GenericRecursive), "GenericRecursive") - self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]") + self.assertEqual(repr(GenericRecursive), GenericRecursive.__qualname__) + fullname = f"{GenericRecursive.__module__}.{GenericRecursive.__qualname__}" + self.assertEqual(repr(GenericRecursive[int]), f"{fullname}[int]") self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]), - "GenericRecursive[GenericRecursive[int]]") + f"{fullname}[{fullname}[int]]") def test_raising(self): type MissingName = list[_My_X] @@ -193,15 +234,25 @@ class TypeAliasConstructorTest(unittest.TestCase): def test_basic(self): TA = TypeAliasType("TA", int) self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__qualname__, "TA") self.assertIs(TA.__value__, int) self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__module__, __name__) + def test_with_qualname(self): + TA = TypeAliasType("TA", str, qualname="Class.TA") + self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__qualname__, "Class.TA") + self.assertIs(TA.__value__, str) + self.assertEqual(TA.__type_params__, ()) + self.assertEqual(TA.__module__, __name__) + def test_attributes_with_exec(self): ns = {} exec("type TA = int", ns, ns) TA = ns["TA"] self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__qualname__, "TA") self.assertIs(TA.__value__, int) self.assertEqual(TA.__type_params__, ()) self.assertIs(TA.__module__, None) @@ -210,6 +261,7 @@ class TypeAliasConstructorTest(unittest.TestCase): T = TypeVar("T") TA = TypeAliasType("TA", list[T], type_params=(T,)) self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__qualname__, "TA") self.assertEqual(TA.__value__, list[T]) self.assertEqual(TA.__type_params__, (T,)) self.assertEqual(TA.__module__, __name__) @@ -218,6 +270,7 @@ class TypeAliasConstructorTest(unittest.TestCase): def test_not_generic(self): TA = TypeAliasType("TA", list[int], type_params=()) self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__qualname__, "TA") self.assertEqual(TA.__value__, list[int]) self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__module__, __name__) @@ -268,8 +321,9 @@ class TypeAliasConstructorTest(unittest.TestCase): TypeAliasType("A", int, type_params=(T, 2)) def test_keywords(self): - TA = TypeAliasType(name="TA", value=int) + TA = TypeAliasType(name="TA", value=int, type_params=(), qualname=None) self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__qualname__, "TA") self.assertIs(TA.__value__, int) self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__module__, __name__) @@ -283,6 +337,8 @@ class TypeAliasConstructorTest(unittest.TestCase): TypeAliasType("TA", list, ()) with self.assertRaises(TypeError): TypeAliasType("TA", list, type_params=42) + with self.assertRaises(TypeError): + TypeAliasType("TA", list, qualname=range(5)) class TypeAliasTypeTest(unittest.TestCase): diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 1415bbca227..d40eb382c53 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -835,3 +835,40 @@ class RegressionTests(unittest.TestCase): genexp = annos["unique_name_2"][0] lamb = list(genexp)[0] self.assertEqual(lamb(), 42) + + # gh-138349 + def test_module_level_annotation_plus_listcomp(self): + cases = [ + """ + def report_error(): + pass + try: + [0 for name_2 in unique_name_0 if (lambda: name_2)] + except: + pass + annotated_name: 0 + """, + """ + class Generic: + pass + try: + [0 for name_2 in unique_name_0 if (0 for unique_name_1 in unique_name_2 for unique_name_3 in name_2)] + except: + pass + annotated_name: 0 + """, + """ + class Generic: + pass + annotated_name: 0 + try: + [0 for name_2 in [[0]] for unique_name_1 in unique_name_2 if (lambda: name_2)] + except: + pass + """, + ] + for code in cases: + with self.subTest(code=code): + mod = build_module(code) + annos = mod.__annotations__ + self.assertEqual(annos, {"annotated_name": 0}) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 9b0ae709d79..4595e7e5d3e 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -714,7 +714,10 @@ class TypesTests(unittest.TestCase): def test_frame_locals_proxy_type(self): self.assertIsInstance(types.FrameLocalsProxyType, type) - self.assertIsInstance(types.FrameLocalsProxyType.__doc__, str) + if MISSING_C_DOCSTRINGS: + self.assertIsNone(types.FrameLocalsProxyType.__doc__) + else: + self.assertIsInstance(types.FrameLocalsProxyType.__doc__, str) self.assertEqual(types.FrameLocalsProxyType.__module__, 'builtins') self.assertEqual(types.FrameLocalsProxyType.__name__, 'FrameLocalsProxy') diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 6317d465761..e896df51844 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -13,6 +13,7 @@ import os import pickle import re import sys +import warnings from unittest import TestCase, main, skip from unittest.mock import patch from copy import copy, deepcopy @@ -32,9 +33,9 @@ from typing import override from typing import is_typeddict, is_protocol from typing import reveal_type from typing import dataclass_transform -from typing import no_type_check, no_type_check_decorator +from typing import no_type_check from typing import Type -from typing import NamedTuple, NotRequired, Required, ReadOnly, TypedDict +from typing import NamedTuple, NotRequired, Required, ReadOnly, TypedDict, NoExtraItems from typing import IO, TextIO, BinaryIO from typing import Pattern, Match from typing import Annotated, ForwardRef @@ -761,6 +762,16 @@ class TypeParameterDefaultsTests(BaseTestCase): self.assertEqual(A[float, [range]].__args__, (float, (range,), float)) self.assertEqual(A[float, [range], int].__args__, (float, (range,), int)) + def test_paramspec_and_typevar_specialization_2(self): + T = TypeVar("T") + P = ParamSpec('P', default=...) + U = TypeVar("U", default=float) + self.assertEqual(P.__default__, ...) + class A(Generic[T, P, U]): ... + self.assertEqual(A[float].__args__, (float, ..., float)) + self.assertEqual(A[float, [range]].__args__, (float, (range,), float)) + self.assertEqual(A[float, [range], int].__args__, (float, (range,), int)) + def test_typevartuple_none(self): U = TypeVarTuple('U') U_None = TypeVarTuple('U_None', default=None) @@ -2272,6 +2283,15 @@ class UnionTests(BaseTestCase): self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__, (Literal[1], Literal[Ints.B], Literal[True])) + def test_allow_non_types_in_or(self): + # gh-140348: Test that using | with a Union object allows things that are + # not allowed by is_unionable(). + U1 = Union[int, str] + self.assertEqual(U1 | float, Union[int, str, float]) + self.assertEqual(U1 | "float", Union[int, str, "float"]) + self.assertEqual(float | U1, Union[float, int, str]) + self.assertEqual("float" | U1, Union["float", int, str]) + class TupleTests(BaseTestCase): @@ -4721,6 +4741,34 @@ class GenericTests(BaseTestCase): with self.assertRaises(TypeError): D[()] + def test_generic_init_subclass_not_called_error(self): + notes = ["Note: this exception may have been caused by " + r"'GenericTests.test_generic_init_subclass_not_called_error.<locals>.Base.__init_subclass__' " + "(or the '__init_subclass__' method on a superclass) not calling 'super().__init_subclass__()'"] + + class Base: + def __init_subclass__(cls) -> None: + # Oops, I forgot super().__init_subclass__()! + pass + + with self.subTest(): + class Sub(Base, Generic[T]): + pass + + with self.assertRaises(AttributeError) as cm: + Sub[int] + + self.assertEqual(cm.exception.__notes__, notes) + + with self.subTest(): + class Sub[U](Base): + pass + + with self.assertRaises(AttributeError) as cm: + Sub[int] + + self.assertEqual(cm.exception.__notes__, notes) + def test_generic_subclass_checks(self): for typ in [list[int], List[int], tuple[int, str], Tuple[int, str], @@ -5844,6 +5892,23 @@ class GenericTests(BaseTestCase): with self.assertRaises(TypeError): a[int] + def test_return_non_tuple_while_unpacking(self): + # GH-138497: GenericAlias objects didn't ensure that __typing_subst__ actually + # returned a tuple + class EvilTypeVar: + __typing_is_unpacked_typevartuple__ = True + def __typing_prepare_subst__(*_): + return None # any value + def __typing_subst__(*_): + return 42 # not tuple + + evil = EvilTypeVar() + # Create a dummy TypeAlias that will be given the evil generic from + # above. + type type_alias[*_] = 0 + with self.assertRaisesRegex(TypeError, ".+__typing_subst__.+tuple.+int.*"): + type_alias[evil][0] + class ClassVarTests(BaseTestCase): @@ -6320,35 +6385,6 @@ class NoTypeCheckTests(BaseTestCase): for clazz in [C, D, E, F]: self.assertEqual(get_type_hints(clazz), expected_result) - def test_meta_no_type_check(self): - depr_msg = ( - "'typing.no_type_check_decorator' is deprecated " - "and slated for removal in Python 3.15" - ) - with self.assertWarnsRegex(DeprecationWarning, depr_msg): - @no_type_check_decorator - def magic_decorator(func): - return func - - self.assertEqual(magic_decorator.__name__, 'magic_decorator') - - @magic_decorator - def foo(a: 'whatevers') -> {}: - pass - - @magic_decorator - class C: - def foo(a: 'whatevers') -> {}: - pass - - self.assertEqual(foo.__name__, 'foo') - th = get_type_hints(foo) - self.assertEqual(th, {}) - cth = get_type_hints(C.foo) - self.assertEqual(cth, {}) - ith = get_type_hints(C().foo) - self.assertEqual(ith, {}) - class InternalsTests(BaseTestCase): def test_collect_parameters(self): @@ -7155,6 +7191,19 @@ class GetTypeHintsTests(BaseTestCase): assert isinstance(get_type_hints(func)['x'], MyAlias) assert isinstance(get_type_hints(func)['y'], MyAlias) + def test_stringified_typeddict(self): + ns = run_code( + """ + from __future__ import annotations + from typing import TypedDict + class TD[UniqueT](TypedDict): + a: UniqueT + """ + ) + TD = ns['TD'] + self.assertEqual(TD.__annotations__, {'a': EqualToForwardRef('UniqueT', owner=TD, module=TD.__module__)}) + self.assertEqual(get_type_hints(TD), {'a': TD.__type_params__[0]}) + class GetUtilitiesTestCase(TestCase): def test_get_origin(self): @@ -7469,6 +7518,25 @@ class CollectionsAbcTests(BaseTestCase): self.assertIsInstance([], typing.MutableSequence) self.assertNotIsInstance((), typing.MutableSequence) + def test_bytestring(self): + previous_typing_module = sys.modules.pop("typing", None) + self.addCleanup(sys.modules.__setitem__, "typing", previous_typing_module) + + with self.assertWarns(DeprecationWarning): + from typing import ByteString + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(b'', ByteString) + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(bytearray(b''), ByteString) + with self.assertWarns(DeprecationWarning): + self.assertIsSubclass(bytes, ByteString) + with self.assertWarns(DeprecationWarning): + self.assertIsSubclass(bytearray, ByteString) + with self.assertWarns(DeprecationWarning): + class Foo(ByteString): ... + with self.assertWarns(DeprecationWarning): + class Bar(ByteString, typing.Awaitable): ... + def test_list(self): self.assertIsSubclass(list, typing.List) @@ -8640,8 +8708,8 @@ class TypedDictTests(BaseTestCase): child = _make_td( child_future, "Child", {"child": "int"}, "Base", {"Base": base} ) - base_anno = ForwardRef("int", module="builtins") if base_future else int - child_anno = ForwardRef("int", module="builtins") if child_future else int + base_anno = ForwardRef("int", module="builtins", owner=base) if base_future else int + child_anno = ForwardRef("int", module="builtins", owner=child) if child_future else int self.assertEqual(base.__annotations__, {'base': base_anno}) self.assertEqual( child.__annotations__, {'child': child_anno, 'base': base_anno} @@ -8770,6 +8838,32 @@ class TypedDictTests(BaseTestCase): class Wrong(*bases): pass + def test_closed_values(self): + class Implicit(TypedDict): ... + class ExplicitTrue(TypedDict, closed=True): ... + class ExplicitFalse(TypedDict, closed=False): ... + + self.assertIsNone(Implicit.__closed__) + self.assertIs(ExplicitTrue.__closed__, True) + self.assertIs(ExplicitFalse.__closed__, False) + + def test_extra_items_class_arg(self): + class TD(TypedDict, extra_items=int): + a: str + + self.assertIs(TD.__extra_items__, int) + self.assertEqual(TD.__annotations__, {'a': str}) + self.assertEqual(TD.__required_keys__, frozenset({'a'})) + self.assertEqual(TD.__optional_keys__, frozenset()) + + class NoExtra(TypedDict): + a: str + + self.assertIs(NoExtra.__extra_items__, NoExtraItems) + self.assertEqual(NoExtra.__annotations__, {'a': str}) + self.assertEqual(NoExtra.__required_keys__, frozenset({'a'})) + self.assertEqual(NoExtra.__optional_keys__, frozenset()) + def test_is_typeddict(self): self.assertIs(is_typeddict(Point2D), True) self.assertIs(is_typeddict(Union[str, int]), False) @@ -9097,6 +9191,71 @@ class TypedDictTests(BaseTestCase): }, ) + def test_closed_inheritance(self): + class Base(TypedDict, extra_items=ReadOnly[Union[str, None]]): + a: int + + self.assertEqual(Base.__required_keys__, frozenset({"a"})) + self.assertEqual(Base.__optional_keys__, frozenset({})) + self.assertEqual(Base.__readonly_keys__, frozenset({})) + self.assertEqual(Base.__mutable_keys__, frozenset({"a"})) + self.assertEqual(Base.__annotations__, {"a": int}) + self.assertEqual(Base.__extra_items__, ReadOnly[Union[str, None]]) + self.assertIsNone(Base.__closed__) + + class Child(Base, extra_items=int): + a: str + + self.assertEqual(Child.__required_keys__, frozenset({'a'})) + self.assertEqual(Child.__optional_keys__, frozenset({})) + self.assertEqual(Child.__readonly_keys__, frozenset({})) + self.assertEqual(Child.__mutable_keys__, frozenset({'a'})) + self.assertEqual(Child.__annotations__, {"a": str}) + self.assertIs(Child.__extra_items__, int) + self.assertIsNone(Child.__closed__) + + class GrandChild(Child, closed=True): + a: float + + self.assertEqual(GrandChild.__required_keys__, frozenset({'a'})) + self.assertEqual(GrandChild.__optional_keys__, frozenset({})) + self.assertEqual(GrandChild.__readonly_keys__, frozenset({})) + self.assertEqual(GrandChild.__mutable_keys__, frozenset({'a'})) + self.assertEqual(GrandChild.__annotations__, {"a": float}) + self.assertIs(GrandChild.__extra_items__, NoExtraItems) + self.assertIs(GrandChild.__closed__, True) + + class GrandGrandChild(GrandChild): + ... + self.assertEqual(GrandGrandChild.__required_keys__, frozenset({'a'})) + self.assertEqual(GrandGrandChild.__optional_keys__, frozenset({})) + self.assertEqual(GrandGrandChild.__readonly_keys__, frozenset({})) + self.assertEqual(GrandGrandChild.__mutable_keys__, frozenset({'a'})) + self.assertEqual(GrandGrandChild.__annotations__, {"a": float}) + self.assertIs(GrandGrandChild.__extra_items__, NoExtraItems) + self.assertIsNone(GrandGrandChild.__closed__) + + def test_implicit_extra_items(self): + class Base(TypedDict): + a: int + + self.assertIs(Base.__extra_items__, NoExtraItems) + self.assertIsNone(Base.__closed__) + + class ChildA(Base, closed=True): + ... + + self.assertEqual(ChildA.__extra_items__, NoExtraItems) + self.assertIs(ChildA.__closed__, True) + + def test_cannot_combine_closed_and_extra_items(self): + with self.assertRaisesRegex( + TypeError, + "Cannot combine closed=True and extra_items" + ): + class TD(TypedDict, closed=True, extra_items=range): + x: str + def test_annotations(self): # _type_check is applied with self.assertRaisesRegex(TypeError, "Plain typing.Final is not valid as type argument"): @@ -9326,6 +9485,12 @@ class RETests(BaseTestCase): class B(typing.Pattern): pass + def test_typed_dict_signature(self): + self.assertListEqual( + list(inspect.signature(TypedDict).parameters), + ['typename', 'fields', 'total', 'closed', 'extra_items'] + ) + class AnnotatedTests(BaseTestCase): @@ -9788,6 +9953,19 @@ class AnnotatedTests(BaseTestCase): self.assertIs(type(field_c2.__metadata__[0]), float) self.assertIs(type(field_c3.__metadata__[0]), bool) + def test_forwardref_partial_evaluation(self): + # Test that Annotated partially evaluates if it contains a ForwardRef + # See: https://github.com/python/cpython/issues/137706 + def f(x: Annotated[undefined, '']): pass + + ann = annotationlib.get_annotations(f, format=annotationlib.Format.FORWARDREF) + + # Test that the attributes are retrievable from the partially evaluated annotation + x_ann = ann['x'] + self.assertIs(get_origin(x_ann), Annotated) + self.assertEqual(x_ann.__origin__, EqualToForwardRef('undefined', owner=f)) + self.assertEqual(x_ann.__metadata__, ('',)) + class TypeAliasTests(BaseTestCase): def test_canonical_usage_with_variable_annotation(self): @@ -10402,6 +10580,10 @@ SpecialAttrsT = typing.TypeVar('SpecialAttrsT', int, float, complex) class SpecialAttrsTests(BaseTestCase): def test_special_attrs(self): + with warnings.catch_warnings( + action='ignore', category=DeprecationWarning + ): + typing_ByteString = typing.ByteString cls_to_check = { # ABC classes typing.AbstractSet: 'AbstractSet', @@ -10410,6 +10592,7 @@ class SpecialAttrsTests(BaseTestCase): typing.AsyncIterable: 'AsyncIterable', typing.AsyncIterator: 'AsyncIterator', typing.Awaitable: 'Awaitable', + typing_ByteString: 'ByteString', typing.Callable: 'Callable', typing.ChainMap: 'ChainMap', typing.Collection: 'Collection', @@ -10762,7 +10945,8 @@ class AllTests(BaseTestCase): # there's a few types and metaclasses that aren't exported not k.endswith(('Meta', '_contra', '_co')) and not k.upper() == k and - # but export all things that have __module__ == 'typing' + k not in {"ByteString"} and + # but export all other things that have __module__ == 'typing' getattr(v, '__module__', None) == typing.__name__ ) } diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 8e3fef6b6fe..f5ab25c602a 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -6,6 +6,7 @@ """ +from functools import partial import hashlib from http.client import HTTPException import sys @@ -18,20 +19,31 @@ from test.support import ( cpython_only, check_disallow_instantiation, force_not_colorized, + is_resource_enabled, + findfile, ) +quicktest = not is_resource_enabled('cpu') + +def iterallchars(): + maxunicode = 0xffff if quicktest else sys.maxunicode + return map(chr, range(maxunicode + 1)) + class UnicodeMethodsTest(unittest.TestCase): # update this, if the database changes - expectedchecksum = '9e43ee3929471739680c0e705482b4ae1c4122e4' + expectedchecksum = ('47a99fa654ef1f50e89d2e9697b7b041fccb5a05' + if quicktest else + '8b2615a9fc627676cbc0b6fac0191177df97ef5f') - @requires_resource('cpu') def test_method_checksum(self): h = hashlib.sha1() - for i in range(sys.maxunicode + 1): - char = chr(i) - data = [ + for char in iterallchars(): + s1 = char + 'abc' + s2 = char + 'ABC' + s3 = char + '123' + data = ( # Predicates (single char) "01"[char.isalnum()], "01"[char.isalpha()], @@ -44,15 +56,15 @@ class UnicodeMethodsTest(unittest.TestCase): "01"[char.isupper()], # Predicates (multiple chars) - "01"[(char + 'abc').isalnum()], - "01"[(char + 'abc').isalpha()], - "01"[(char + '123').isdecimal()], - "01"[(char + '123').isdigit()], - "01"[(char + 'abc').islower()], - "01"[(char + '123').isnumeric()], + "01"[s1.isalnum()], + "01"[s1.isalpha()], + "01"[s3.isdecimal()], + "01"[s3.isdigit()], + "01"[s1.islower()], + "01"[s3.isnumeric()], "01"[(char + ' \t').isspace()], - "01"[(char + 'abc').istitle()], - "01"[(char + 'ABC').isupper()], + "01"[s1.istitle()], + "01"[s2.isupper()], # Mappings (single char) char.lower(), @@ -60,54 +72,54 @@ class UnicodeMethodsTest(unittest.TestCase): char.title(), # Mappings (multiple chars) - (char + 'abc').lower(), - (char + 'ABC').upper(), - (char + 'abc').title(), - (char + 'ABC').title(), + s1.lower(), + s2.upper(), + s1.title(), + s2.title(), - ] + ) h.update(''.join(data).encode('utf-8', 'surrogatepass')) result = h.hexdigest() self.assertEqual(result, self.expectedchecksum) -class UnicodeDatabaseTest(unittest.TestCase): - db = unicodedata -class UnicodeFunctionsTest(UnicodeDatabaseTest): +class UnicodeFunctionsTest(unittest.TestCase): + db = unicodedata + old = False # Update this if the database changes. Make sure to do a full rebuild # (e.g. 'make distclean && make') to get the correct checksum. - expectedchecksum = '23ab09ed4abdf93db23b97359108ed630dd8311d' + expectedchecksum = ('83cc43a2fbb779185832b4c049217d80b05bf349' + if quicktest else + '65670ae03a324c5f9e826a4de3e25bae4d73c9b7') - @requires_resource('cpu') def test_function_checksum(self): + db = self.db data = [] h = hashlib.sha1() - for i in range(sys.maxunicode + 1): - char = chr(i) - data = [ + for char in iterallchars(): + data = "%.12g%.12g%.12g%s%s%s%s%s%s%s" % ( # Properties - format(self.db.digit(char, -1), '.12g'), - format(self.db.numeric(char, -1), '.12g'), - format(self.db.decimal(char, -1), '.12g'), - self.db.category(char), - self.db.bidirectional(char), - self.db.decomposition(char), - str(self.db.mirrored(char)), - str(self.db.combining(char)), - unicodedata.east_asian_width(char), - self.db.name(char, ""), - ] - h.update(''.join(data).encode("ascii")) + db.digit(char, -1), + db.numeric(char, -1), + db.decimal(char, -1), + db.category(char), + db.bidirectional(char), + db.decomposition(char), + db.mirrored(char), + db.combining(char), + db.east_asian_width(char), + db.name(char, ""), + ) + h.update(data.encode("ascii")) result = h.hexdigest() self.assertEqual(result, self.expectedchecksum) - @requires_resource('cpu') def test_name_inverse_lookup(self): - for i in range(sys.maxunicode + 1): - char = chr(i) - if looked_name := self.db.name(char, None): + for char in iterallchars(): + looked_name = self.db.name(char, None) + if looked_name is not None: self.assertEqual(self.db.lookup(looked_name), char) def test_no_names_in_pua(self): @@ -138,6 +150,13 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.digit('\U00020000', None), None) self.assertEqual(self.db.digit('\U0001D7FD'), 7) + # New in 13.0.0 + self.assertEqual(self.db.digit('\U0001fbf9', None), 9) + # New in 14.0.0 + self.assertEqual(self.db.digit('\U00016ac9', None), 9) + # New in 15.0.0 + self.assertEqual(self.db.digit('\U0001e4f9', None), 9) + self.assertRaises(TypeError, self.db.digit) self.assertRaises(TypeError, self.db.digit, 'xx') self.assertRaises(ValueError, self.db.digit, 'x') @@ -147,9 +166,24 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.numeric('9'), 9) self.assertEqual(self.db.numeric('\u215b'), 0.125) self.assertEqual(self.db.numeric('\u2468'), 9.0) - self.assertEqual(self.db.numeric('\ua627'), 7.0) self.assertEqual(self.db.numeric('\U00020000', None), None) - self.assertEqual(self.db.numeric('\U0001012A'), 9000) + + # New in 4.1.0 + self.assertEqual(self.db.numeric('\U0001012A', None), None if self.old else 9000) + # New in 5.0.0 + self.assertEqual(self.db.numeric('\u07c0', None), None if self.old else 0.0) + # New in 5.1.0 + self.assertEqual(self.db.numeric('\ua627', None), None if self.old else 7.0) + # New in 6.0.0 + self.assertEqual(self.db.numeric('\u0b72', None), None if self.old else 0.25) + # New in 12.0.0 + self.assertEqual(self.db.numeric('\U0001ed3c', None), None if self.old else 0.5) + # New in 13.0.0 + self.assertEqual(self.db.numeric('\U0001fbf9', None), None if self.old else 9) + # New in 14.0.0 + self.assertEqual(self.db.numeric('\U00016ac9', None), None if self.old else 9) + # New in 15.0.0 + self.assertEqual(self.db.numeric('\U0001e4f9', None), None if self.old else 9) self.assertRaises(TypeError, self.db.numeric) self.assertRaises(TypeError, self.db.numeric, 'xx') @@ -163,6 +197,18 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.decimal('\U00020000', None), None) self.assertEqual(self.db.decimal('\U0001D7FD'), 7) + # New in 4.1.0 + self.assertEqual(self.db.decimal('\xb2', None), 2 if self.old else None) + self.assertEqual(self.db.decimal('\u1369', None), 1 if self.old else None) + # New in 5.0.0 + self.assertEqual(self.db.decimal('\u07c0', None), None if self.old else 0) + # New in 13.0.0 + self.assertEqual(self.db.decimal('\U0001fbf9', None), None if self.old else 9) + # New in 14.0.0 + self.assertEqual(self.db.decimal('\U00016ac9', None), None if self.old else 9) + # New in 15.0.0 + self.assertEqual(self.db.decimal('\U0001e4f9', None), None if self.old else 9) + self.assertRaises(TypeError, self.db.decimal) self.assertRaises(TypeError, self.db.decimal, 'xx') self.assertRaises(ValueError, self.db.decimal, 'x') @@ -172,7 +218,21 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.category('a'), 'Ll') self.assertEqual(self.db.category('A'), 'Lu') self.assertEqual(self.db.category('\U00020000'), 'Lo') - self.assertEqual(self.db.category('\U0001012A'), 'No') + + # New in 4.1.0 + self.assertEqual(self.db.category('\U0001012A'), 'Cn' if self.old else 'No') + self.assertEqual(self.db.category('\U000e01ef'), 'Cn' if self.old else 'Mn') + # New in 5.1.0 + self.assertEqual(self.db.category('\u0374'), 'Sk' if self.old else 'Lm') + # Changed in 13.0.0 + self.assertEqual(self.db.category('\u0b55'), 'Cn' if self.old else 'Mn') + self.assertEqual(self.db.category('\U0003134a'), 'Cn' if self.old else 'Lo') + # Changed in 14.0.0 + self.assertEqual(self.db.category('\u061d'), 'Cn' if self.old else 'Po') + self.assertEqual(self.db.category('\U0002b738'), 'Cn' if self.old else 'Lo') + # Changed in 15.0.0 + self.assertEqual(self.db.category('\u0cf3'), 'Cn' if self.old else 'Mc') + self.assertEqual(self.db.category('\U000323af'), 'Cn' if self.old else 'Lo') self.assertRaises(TypeError, self.db.category) self.assertRaises(TypeError, self.db.category, 'xx') @@ -183,6 +243,26 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.bidirectional('A'), 'L') self.assertEqual(self.db.bidirectional('\U00020000'), 'L') + # New in 4.1.0 + self.assertEqual(self.db.bidirectional('+'), 'ET' if self.old else 'ES') + self.assertEqual(self.db.bidirectional('\u0221'), '' if self.old else 'L') + self.assertEqual(self.db.bidirectional('\U000e01ef'), '' if self.old else 'NSM') + # New in 13.0.0 + self.assertEqual(self.db.bidirectional('\u0b55'), '' if self.old else 'NSM') + self.assertEqual(self.db.bidirectional('\U0003134a'), '' if self.old else 'L') + # New in 14.0.0 + self.assertEqual(self.db.bidirectional('\u061d'), '' if self.old else 'AL') + self.assertEqual(self.db.bidirectional('\U0002b738'), '' if self.old else 'L') + # New in 15.0.0 + self.assertEqual(self.db.bidirectional('\u0cf3'), '' if self.old else 'L') + self.assertEqual(self.db.bidirectional('\U000323af'), '' if self.old else 'L') + # New in 16.0.0 + self.assertEqual(self.db.bidirectional('\u0897'), '' if self.old else 'NSM') + self.assertEqual(self.db.bidirectional('\U0001fbef'), '' if self.old else 'ON') + # New in 17.0.0 + self.assertEqual(self.db.bidirectional('\u088f'), '' if self.old else 'AL') + self.assertEqual(self.db.bidirectional('\U0001fbfa'), '' if self.old else 'ON') + self.assertRaises(TypeError, self.db.bidirectional) self.assertRaises(TypeError, self.db.bidirectional, 'xx') @@ -190,6 +270,22 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.decomposition('\uFFFE'),'') self.assertEqual(self.db.decomposition('\u00bc'), '<fraction> 0031 2044 0034') + # New in 4.1.0 + self.assertEqual(self.db.decomposition('\u03f9'), '' if self.old else '<compat> 03A3') + # New in 13.0.0 + self.assertEqual(self.db.decomposition('\uab69'), '' if self.old else '<super> 028D') + self.assertEqual(self.db.decomposition('\U00011938'), '' if self.old else '11935 11930') + self.assertEqual(self.db.decomposition('\U0001fbf9'), '' if self.old else '<font> 0039') + # New in 14.0.0 + self.assertEqual(self.db.decomposition('\ua7f2'), '' if self.old else '<super> 0043') + self.assertEqual(self.db.decomposition('\U000107ba'), '' if self.old else '<super> 1DF1E') + # New in 15.0.0 + self.assertEqual(self.db.decomposition('\U0001e06d'), '' if self.old else '<super> 04B1') + # New in 16.0.0 + self.assertEqual(self.db.decomposition('\U0001CCD6'), '' if self.old else '<font> 0041') + # New in 17.0.0 + self.assertEqual(self.db.decomposition('\uA7F1'), '' if self.old else '<super> 0053') + self.assertRaises(TypeError, self.db.decomposition) self.assertRaises(TypeError, self.db.decomposition, 'xx') @@ -199,6 +295,16 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.mirrored('\u2201'), 1) self.assertEqual(self.db.mirrored('\U00020000'), 0) + # New in 5.0.0 + self.assertEqual(self.db.mirrored('\u0f3a'), 0 if self.old else 1) + self.assertEqual(self.db.mirrored('\U0001d7c3'), 0 if self.old else 1) + # New in 11.0.0 + self.assertEqual(self.db.mirrored('\u29a1'), 1 if self.old else 0) + # New in 14.0.0 + self.assertEqual(self.db.mirrored('\u2e5c'), 0 if self.old else 1) + # New in 16.0.0 + self.assertEqual(self.db.mirrored('\u226D'), 0 if self.old else 1) + self.assertRaises(TypeError, self.db.mirrored) self.assertRaises(TypeError, self.db.mirrored, 'xx') @@ -208,9 +314,189 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(self.db.combining('\u20e1'), 230) self.assertEqual(self.db.combining('\U00020000'), 0) + # New in 4.1.0 + self.assertEqual(self.db.combining('\u0350'), 0 if self.old else 230) + # New in 9.0.0 + self.assertEqual(self.db.combining('\U0001e94a'), 0 if self.old else 7) + # New in 13.0.0 + self.assertEqual(self.db.combining('\u1abf'), 0 if self.old else 220) + self.assertEqual(self.db.combining('\U00016ff1'), 0 if self.old else 6) + # New in 14.0.0 + self.assertEqual(self.db.combining('\u0c3c'), 0 if self.old else 7) + self.assertEqual(self.db.combining('\U0001e2ae'), 0 if self.old else 230) + # New in 15.0.0 + self.assertEqual(self.db.combining('\U00010efd'), 0 if self.old else 220) + # New in 16.0.0 + self.assertEqual(self.db.combining('\u0897'), 0 if self.old else 230) + # New in 17.0.0 + self.assertEqual(self.db.combining('\u1ACF'), 0 if self.old else 230) + self.assertRaises(TypeError, self.db.combining) self.assertRaises(TypeError, self.db.combining, 'xx') + def test_normalization(self): + # Test normalize() and is_normalized() + def check(ch, expected): + if isinstance(expected, str): + expected = [expected]*4 + forms = ('NFC', 'NFD', 'NFKC', 'NFKD') + result = [self.db.normalize(form, ch) for form in forms] + self.assertEqual(ascii(result), ascii(list(expected))) + self.assertEqual([self.db.is_normalized(form, ch) for form in forms], + [ch == y for x, y in zip(result, expected)]) + + check('', '') + check('A', 'A') + check(' ', ' ') + check('\U0010ffff', '\U0010ffff') + check('abc', 'abc') + # Broken in 4.0.0 + check('\u0340', '\u0300') + check('\u0300', '\u0300') + check('\U0002fa1d', '\U0002a600') + check('\U0002a600', '\U0002a600') + check('\u0344', '\u0308\u0301') + check('\u0308\u0301', '\u0308\u0301') + # Broken in 4.0.0 and 4.0.1 + check('\U0001d1bc', '\U0001d1ba\U0001d165') + check('\U0001d1ba\U0001d165', '\U0001d1ba\U0001d165') + check('\ufb2c', '\u05e9\u05bc\u05c1') + check('\u05e9\u05bc\u05c1', '\u05e9\u05bc\u05c1') + check('\U0001d1c0', '\U0001d1ba\U0001d165\U0001d16f') + check('\U0001d1ba\U0001d165\U0001d16f', '\U0001d1ba\U0001d165\U0001d16f') + + # Broken in 4.0.0 + check('\xa0', ['\xa0', '\xa0', ' ', ' ']) + check('\u2003', ['\u2003', '\u2003', ' ', ' ']) + check('\U0001d7ff', ['\U0001d7ff', '\U0001d7ff', '9', '9']) + + check('\xa8', ['\xa8', '\xa8', ' \u0308', ' \u0308']) + check(' \u0308', ' \u0308') + + check('\xc0', ['\xc0', 'A\u0300']*2) + check('A\u0300', ['\xc0', 'A\u0300']*2) + + check('\ud7a3', ['\ud7a3', '\u1112\u1175\u11c2']*2) + check('\u1112\u1175\u11c2', ['\ud7a3', '\u1112\u1175\u11c2']*2) + + check('\xb4', ['\xb4', '\xb4', ' \u0301', ' \u0301']) + check('\u1ffd', ['\xb4', '\xb4', ' \u0301', ' \u0301']) + check(' \u0301', ' \u0301') + + check('\xc5', ['\xc5', 'A\u030a']*2) + check('\u212b', ['\xc5', 'A\u030a']*2) + check('A\u030a', ['\xc5', 'A\u030a']*2) + + check('\u1f71', ['\u03ac', '\u03b1\u0301']*2) + check('\u03ac', ['\u03ac', '\u03b1\u0301']*2) + check('\u03b1\u0301', ['\u03ac', '\u03b1\u0301']*2) + + check('\u01c4', ['\u01c4', '\u01c4', 'D\u017d', 'DZ\u030c']) + check('D\u017d', ['D\u017d', 'DZ\u030c']*2) + check('DZ\u030c', ['D\u017d', 'DZ\u030c']*2) + + check('\u1fed', ['\u1fed', '\xa8\u0300', ' \u0308\u0300', ' \u0308\u0300']) + check('\xa8\u0300', ['\u1fed', '\xa8\u0300', ' \u0308\u0300', ' \u0308\u0300']) + check(' \u0308\u0300', ' \u0308\u0300') + + check('\u326e', ['\u326e', '\u326e', '\uac00', '\u1100\u1161']) + check('\u320e', ['\u320e', '\u320e', '(\uac00)', '(\u1100\u1161)']) + check('(\uac00)', ['(\uac00)', '(\u1100\u1161)']*2) + check('(\u1100\u1161)', ['(\uac00)', '(\u1100\u1161)']*2) + + check('\u0385', ['\u0385', '\xa8\u0301', ' \u0308\u0301', ' \u0308\u0301']) + check('\u1fee', ['\u0385', '\xa8\u0301', ' \u0308\u0301', ' \u0308\u0301']) + check('\xa8\u0301', ['\u0385', '\xa8\u0301', ' \u0308\u0301', ' \u0308\u0301']) + check(' \u0308\u0301', ' \u0308\u0301') + + check('\u1fdf', ['\u1fdf', '\u1ffe\u0342', ' \u0314\u0342', ' \u0314\u0342']) + check('\u1ffe\u0342', ['\u1fdf', '\u1ffe\u0342', ' \u0314\u0342', ' \u0314\u0342']) + check('\u1ffe', ['\u1ffe', '\u1ffe', ' \u0314', ' \u0314']) + check(' \u0314\u0342', ' \u0314\u0342') + + check('\u03d3', ['\u03d3', '\u03d2\u0301', '\u038e', '\u03a5\u0301']) + check('\u03d2\u0301', ['\u03d3', '\u03d2\u0301', '\u038e', '\u03a5\u0301']) + check('\u038e', ['\u038e', '\u03a5\u0301']*2) + check('\u1feb', ['\u038e', '\u03a5\u0301']*2) + check('\u03a5\u0301', ['\u038e', '\u03a5\u0301']*2) + + check('\u0626', ['\u0626', '\u064a\u0654']*2) + check('\u064a\u0654', ['\u0626', '\u064a\u0654']*2) + check('\ufe89', ['\ufe89', '\ufe89', '\u0626', '\u064a\u0654']) + check('\ufe8a', ['\ufe8a', '\ufe8a', '\u0626', '\u064a\u0654']) + check('\ufe8b', ['\ufe8b', '\ufe8b', '\u0626', '\u064a\u0654']) + check('\ufe8c', ['\ufe8c', '\ufe8c', '\u0626', '\u064a\u0654']) + + check('\ufef9', ['\ufef9', '\ufef9', '\u0644\u0625', '\u0644\u0627\u0655']) + check('\ufefa', ['\ufefa', '\ufefa', '\u0644\u0625', '\u0644\u0627\u0655']) + check('\ufefb', ['\ufefb', '\ufefb', '\u0644\u0627', '\u0644\u0627']) + check('\ufefc', ['\ufefc', '\ufefc', '\u0644\u0627', '\u0644\u0627']) + check('\u0644\u0625', ['\u0644\u0625', '\u0644\u0627\u0655']*2) + check('\u0644\u0627\u0655', ['\u0644\u0625', '\u0644\u0627\u0655']*2) + check('\u0644\u0627', '\u0644\u0627') + + # Broken in 4.0.0 + check('\u327c', '\u327c' if self.old else + ['\u327c', '\u327c', '\ucc38\uace0', '\u110e\u1161\u11b7\u1100\u1169']) + check('\ucc38\uace0', ['\ucc38\uace0', '\u110e\u1161\u11b7\u1100\u1169']*2) + check('\ucc38', ['\ucc38', '\u110e\u1161\u11b7']*2) + check('\u110e\u1161\u11b7\u1100\u1169', + ['\ucc38\uace0', '\u110e\u1161\u11b7\u1100\u1169']*2) + check('\u110e\u1161\u11b7\u1100', + ['\ucc38\u1100', '\u110e\u1161\u11b7\u1100']*2) + check('\u110e\u1161\u11b7', + ['\ucc38', '\u110e\u1161\u11b7']*2) + check('\u110e\u1161', + ['\ucc28', '\u110e\u1161']*2) + check('\u110e', '\u110e') + # Broken in 4.0.0-12.0.0 + check('\U00011938', '\U00011938' if self.old else + ['\U00011938', '\U00011935\U00011930']*2) + check('\U00011935\U00011930', ['\U00011938', '\U00011935\U00011930']*2) + # New in 4.0.1 + check('\u321d', '\u321d' if self.old else + ['\u321d', '\u321d', '(\uc624\uc804)', '(\u110b\u1169\u110c\u1165\u11ab)']) + check('(\uc624\uc804)', + ['(\uc624\uc804)', '(\u110b\u1169\u110c\u1165\u11ab)']*2) + check('(\u110b\u1169\u110c\u1165\u11ab)', + ['(\uc624\uc804)', '(\u110b\u1169\u110c\u1165\u11ab)']*2) + check('\u4d57', '\u4d57') + check('\u45d7', '\u45d7' if self.old else '\u45d7') + check('\U0002f9bf', '\u4d57' if self.old else '\u45d7') + # New in 4.1.0 + check('\u03a3', '\u03a3') + check('\u03f9', '\u03f9' if self.old else + ['\u03f9', '\u03f9', '\u03a3', '\u03a3']) + # New in 5.0.0 + check('\u1b06', '\u1b06' if self.old else ['\u1b06', '\u1b05\u1b35']*2) + # New in 5.2.0 + check('\U0001f213', '\U0001f213' if self.old else + ['\U0001f213', '\U0001f213', '\u30c7', '\u30c6\u3099']) + # New in 6.1.0 + check('\ufa2e', '\ufa2e' if self.old else '\u90de') + # New in 13.0.0 + check('\U00011938', '\U00011938' if self.old else + ['\U00011938', '\U00011935\U00011930', '\U00011938', '\U00011935\U00011930']) + check('\U0001fbf9', '\U0001fbf9' if self.old else + ['\U0001fbf9', '\U0001fbf9', '9', '9']) + # New in 14.0.0 + check('\U000107ba', '\U000107ba' if self.old else + ['\U000107ba', '\U000107ba', '\U0001df1e', '\U0001df1e']) + # New in 15.0.0 + check('\U0001e06d', '\U0001e06d' if self.old else + ['\U0001e06d', '\U0001e06d', '\u04b1', '\u04b1']) + # New in 16.0.0 + check('\U0001ccd6', '\U0001ccd6' if self.old else + ['\U0001ccd6', '\U0001ccd6', 'A', 'A']) + + self.assertRaises(TypeError, self.db.normalize) + self.assertRaises(TypeError, self.db.normalize, 'NFC') + self.assertRaises(ValueError, self.db.normalize, 'SPAM', 'A') + + self.assertRaises(TypeError, self.db.is_normalized) + self.assertRaises(TypeError, self.db.is_normalized, 'NFC') + self.assertRaises(ValueError, self.db.is_normalized, 'SPAM', 'A') + def test_pr29(self): # https://www.unicode.org/review/pr-29.html # See issues #1054943 and #10254. @@ -225,6 +511,7 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): def test_issue10254(self): # Crash reported in #10254 + # New in 4.1.0 a = 'C\u0338' * 20 + 'C\u0327' b = 'C\u0338' * 20 + '\xC7' self.assertEqual(self.db.normalize('NFC', a), b) @@ -238,6 +525,7 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): u11c3_str_a = '\u1100\u1175\u11c3' u11c3_str_b = '\uae30\u11c3' self.assertEqual(self.db.normalize('NFC', u1176_str_a), u1176_str_b) + # New in 4.1.0 self.assertEqual(self.db.normalize('NFC', u11a7_str_a), u11a7_str_b) self.assertEqual(self.db.normalize('NFC', u11c3_str_a), u11c3_str_b) @@ -255,6 +543,34 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(eaw('\u2010'), 'A') self.assertEqual(eaw('\U00020000'), 'W') + # New in 4.1.0 + self.assertEqual(eaw('\u0350'), 'N' if self.old else 'A') + self.assertEqual(eaw('\U000e01ef'), 'N' if self.old else 'A') + # New in 5.2.0 + self.assertEqual(eaw('\u115a'), 'N' if self.old else 'W') + # New in 9.0.0 + self.assertEqual(eaw('\u231a'), 'N' if self.old else 'W') + self.assertEqual(eaw('\u2614'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0001f19a'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0001f991'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0001f9c0'), 'N' if self.old else 'W') + # New in 12.0.0 + self.assertEqual(eaw('\u32ff'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0001fa95'), 'N' if self.old else 'W') + # New in 13.0.0 + self.assertEqual(eaw('\u31bb'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0003134a'), 'N' if self.old else 'W') + # New in 14.0.0 + self.assertEqual(eaw('\u9ffd'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0002b738'), 'N' if self.old else 'W') + # New in 15.0.0 + self.assertEqual(eaw('\U000323af'), 'N' if self.old else 'W') + # New in 16.0.0 + self.assertEqual(eaw('\u2630'), 'N' if self.old else 'W') + self.assertEqual(eaw('\U0001FAE9'), 'N' if self.old else 'W') + # New in 17.0.0 + self.assertEqual(eaw('\U00016FF2'), 'N' if self.old else 'W') + def test_east_asian_width_unassigned(self): eaw = self.db.east_asian_width # unassigned @@ -263,7 +579,8 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertIs(self.db.name(char, None), None) # unassigned but reserved for CJK - for char in '\uFA6E\uFADA\U0002A6E0\U0002FA20\U0003134B\U0003FFFD': + for char in ('\U0002A6E0\U0002FA20\U0003134B\U0003FFFD' + '\uFA6E\uFADA'): # New in 5.2.0 self.assertEqual(eaw(char), 'W') self.assertIs(self.db.name(char, None), None) @@ -272,11 +589,44 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): self.assertEqual(eaw(char), 'A') self.assertIs(self.db.name(char, None), None) - def test_east_asian_width_9_0_changes(self): - self.assertEqual(self.db.ucd_3_2_0.east_asian_width('\u231a'), 'N') - self.assertEqual(self.db.east_asian_width('\u231a'), 'W') + def test_isxidstart(self): + self.assertTrue(self.db.isxidstart('S')) + self.assertTrue(self.db.isxidstart('\u0AD0')) # GUJARATI OM + self.assertTrue(self.db.isxidstart('\u0EC6')) # LAO KO LA + self.assertTrue(self.db.isxidstart('\u17DC')) # KHMER SIGN AVAKRAHASANYA + self.assertTrue(self.db.isxidstart('\uA015')) # YI SYLLABLE WU + self.assertTrue(self.db.isxidstart('\uFE7B')) # ARABIC KASRA MEDIAL FORM -class UnicodeMiscTest(UnicodeDatabaseTest): + self.assertFalse(self.db.isxidstart(' ')) + self.assertFalse(self.db.isxidstart('0')) + self.assertRaises(TypeError, self.db.isxidstart) + self.assertRaises(TypeError, self.db.isxidstart, 'xx') + + def test_isxidcontinue(self): + self.assertTrue(self.db.isxidcontinue('S')) + self.assertTrue(self.db.isxidcontinue('_')) + self.assertTrue(self.db.isxidcontinue('0')) + self.assertTrue(self.db.isxidcontinue('\u00BA')) # MASCULINE ORDINAL INDICATOR + self.assertTrue(self.db.isxidcontinue('\u0640')) # ARABIC TATWEEL + self.assertTrue(self.db.isxidcontinue('\u0710')) # SYRIAC LETTER ALAPH + self.assertTrue(self.db.isxidcontinue('\u0B3E')) # ORIYA VOWEL SIGN AA + self.assertTrue(self.db.isxidcontinue('\u17D7')) # KHMER SIGN LEK TOO + + self.assertFalse(self.db.isxidcontinue(' ')) + self.assertRaises(TypeError, self.db.isxidcontinue) + self.assertRaises(TypeError, self.db.isxidcontinue, 'xx') + + +class Unicode_3_2_0_FunctionsTest(UnicodeFunctionsTest): + db = unicodedata.ucd_3_2_0 + old = True + expectedchecksum = ('f4526159891a4b766dd48045646547178737ba09' + if quicktest else + 'f217b8688d7bdff31db4207e078a96702f091597') + + +class UnicodeMiscTest(unittest.TestCase): + db = unicodedata @cpython_only def test_disallow_instantiation(self): @@ -305,32 +655,39 @@ class UnicodeMiscTest(UnicodeDatabaseTest): # i.e. if a character has a decimal value, # its numeric value should be the same. count = 0 - for i in range(0x10000): - c = chr(i) + for c in iterallchars(): dec = self.db.decimal(c, -1) if dec != -1: self.assertEqual(dec, self.db.numeric(c)) count += 1 - self.assertTrue(count >= 10) # should have tested at least the ASCII digits + self.assertTrue(count >= 10, count) # should have tested at least the ASCII digits def test_digit_numeric_consistent(self): # Test that digit and numeric are consistent, # i.e. if a character has a digit value, # its numeric value should be the same. count = 0 - for i in range(0x10000): - c = chr(i) + for c in iterallchars(): dec = self.db.digit(c, -1) if dec != -1: self.assertEqual(dec, self.db.numeric(c)) count += 1 - self.assertTrue(count >= 10) # should have tested at least the ASCII digits + self.assertTrue(count >= 10, count) # should have tested at least the ASCII digits + + def test_normalize_consistent(self): + allchars = list(iterallchars()) + for form in ('NFC', 'NFD', 'NFKC', 'NFKD'): + for c in allchars: + norm = self.db.normalize(form, c) + self.assertEqual(self.db.is_normalized(form, c), norm == c) + if norm != c: + self.assertEqual(self.db.normalize(form, norm), norm) + self.assertTrue(self.db.is_normalized(form, norm)) def test_bug_1704793(self): self.assertEqual(self.db.lookup("GOTHIC LETTER FAIHU"), '\U00010346') def test_ucd_510(self): - import unicodedata # In UCD 5.1.0, a mirrored property changed wrt. UCD 3.2.0 self.assertTrue(unicodedata.mirrored("\u0f3a")) self.assertTrue(not unicodedata.ucd_3_2_0.mirrored("\u0f3a")) @@ -346,10 +703,10 @@ class UnicodeMiscTest(UnicodeDatabaseTest): # Only U+0000 should have U+0000 as its upper/lower/titlecase variant self.assertEqual( [ - c for c in range(sys.maxunicode+1) - if "\x00" in chr(c).lower()+chr(c).upper()+chr(c).title() + c for c in iterallchars() + if "\x00" in (c.lower(), c.upper(), c.title()) ], - [0] + ["\x00"] ) def test_bug_4971(self): @@ -359,15 +716,16 @@ class UnicodeMiscTest(UnicodeDatabaseTest): self.assertEqual("\u01c6".title(), "\u01c5") def test_linebreak_7643(self): - for i in range(0x10000): - lines = (chr(i) + 'A').splitlines() - if i in (0x0a, 0x0b, 0x0c, 0x0d, 0x85, - 0x1c, 0x1d, 0x1e, 0x2028, 0x2029): + for c in iterallchars(): + lines = (c + 'A').splitlines() + if c in ('\x0a', '\x0b', '\x0c', '\x0d', '\x85', + '\x1c', '\x1d', '\x1e', '\u2028', '\u2029'): self.assertEqual(len(lines), 2, - r"\u%.4x should be a linebreak" % i) + r"%a should be a linebreak" % c) else: self.assertEqual(len(lines), 1, - r"\u%.4x should not be a linebreak" % i) + r"%a should not be a linebreak" % c) + class NormalizationTest(unittest.TestCase): @staticmethod @@ -397,23 +755,23 @@ class NormalizationTest(unittest.TestCase): self.skipTest(f"Failed to download {TESTDATAURL}: {exc}") with testdata: - self.run_normalization_tests(testdata) + self.run_normalization_tests(testdata, unicodedata) - def run_normalization_tests(self, testdata): + @requires_resource('cpu') + def test_normalization_3_2_0(self): + testdatafile = findfile('NormalizationTest-3.2.0.txt', 'data') + with open(testdatafile, encoding='utf-8') as testdata: + self.run_normalization_tests(testdata, unicodedata.ucd_3_2_0) + + def run_normalization_tests(self, testdata, ucd): part = None - part1_data = {} + part1_data = set() - def NFC(str): - return unicodedata.normalize("NFC", str) - - def NFKC(str): - return unicodedata.normalize("NFKC", str) - - def NFD(str): - return unicodedata.normalize("NFD", str) - - def NFKD(str): - return unicodedata.normalize("NFKD", str) + NFC = partial(ucd.normalize, "NFC") + NFKC = partial(ucd.normalize, "NFKC") + NFD = partial(ucd.normalize, "NFD") + NFKD = partial(ucd.normalize, "NFKD") + is_normalized = ucd.is_normalized for line in testdata: if '#' in line: @@ -438,25 +796,24 @@ class NormalizationTest(unittest.TestCase): NFKD(c3) == NFKD(c4) == NFKD(c5), line) - self.assertTrue(unicodedata.is_normalized("NFC", c2)) - self.assertTrue(unicodedata.is_normalized("NFC", c4)) + self.assertTrue(is_normalized("NFC", c2)) + self.assertTrue(is_normalized("NFC", c4)) - self.assertTrue(unicodedata.is_normalized("NFD", c3)) - self.assertTrue(unicodedata.is_normalized("NFD", c5)) + self.assertTrue(is_normalized("NFD", c3)) + self.assertTrue(is_normalized("NFD", c5)) - self.assertTrue(unicodedata.is_normalized("NFKC", c4)) - self.assertTrue(unicodedata.is_normalized("NFKD", c5)) + self.assertTrue(is_normalized("NFKC", c4)) + self.assertTrue(is_normalized("NFKD", c5)) # Record part 1 data if part == "@Part1": - part1_data[c1] = 1 + part1_data.add(c1) # Perform tests for all other data - for c in range(sys.maxunicode+1): - X = chr(c) + for X in iterallchars(): if X in part1_data: continue - self.assertTrue(X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X), c) + self.assertTrue(X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X), ord(X)) def test_edge_cases(self): self.assertRaises(TypeError, unicodedata.normalize) diff --git a/Lib/test/test_unittest/test_program.py b/Lib/test/test_unittest/test_program.py index 6092ed292d8..8ed92373e5e 100644 --- a/Lib/test/test_unittest/test_program.py +++ b/Lib/test/test_unittest/test_program.py @@ -75,6 +75,14 @@ class Test_TestProgram(unittest.TestCase): class Empty(unittest.TestCase): pass + class SetUpClassFailure(unittest.TestCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + raise Exception + def testPass(self): + pass + class TestLoader(unittest.TestLoader): """Test loader that returns a suite containing the supplied testcase.""" @@ -191,6 +199,18 @@ class Test_TestProgram(unittest.TestCase): out = stream.getvalue() self.assertIn('\nNO TESTS RAN\n', out) + def test_ExitSetUpClassFailureSuite(self): + stream = BufferedWriter() + with self.assertRaises(SystemExit) as cm: + unittest.main( + argv=["setup_class_failure"], + testRunner=unittest.TextTestRunner(stream=stream), + testLoader=self.TestLoader(self.SetUpClassFailure)) + self.assertEqual(cm.exception.code, 1) + out = stream.getvalue() + self.assertIn("ERROR: setUpClass", out) + self.assertIn("SetUpClassFailure", out) + class InitialisableProgram(unittest.TestProgram): exit = False diff --git a/Lib/test/test_unittest/testmock/testthreadingmock.py b/Lib/test/test_unittest/testmock/testthreadingmock.py index a02b532ed44..dda4916434e 100644 --- a/Lib/test/test_unittest/testmock/testthreadingmock.py +++ b/Lib/test/test_unittest/testmock/testthreadingmock.py @@ -1,8 +1,10 @@ +import sys import time import unittest +import threading import concurrent.futures -from test.support import threading_helper +from test.support import setswitchinterval, threading_helper from unittest.mock import patch, ThreadingMock @@ -196,6 +198,102 @@ class TestThreadingMock(unittest.TestCase): m.wait_until_any_call_with() m.assert_called_once() + def test_call_count_thread_safe(self): + # See https://github.com/python/cpython/issues/142651. + m = ThreadingMock() + LOOPS = 100 + THREADS = 10 + def test_function(): + for _ in range(LOOPS): + m() + + oldswitchinterval = sys.getswitchinterval() + setswitchinterval(1e-6) + try: + threads = [threading.Thread(target=test_function) for _ in range(THREADS)] + with threading_helper.start_threads(threads): + pass + finally: + sys.setswitchinterval(oldswitchinterval) + + self.assertEqual(m.call_count, LOOPS * THREADS) + + + def test_call_args_thread_safe(self): + m = ThreadingMock() + LOOPS = 100 + THREADS = 10 + def test_function(thread_id): + for i in range(LOOPS): + m(thread_id, i) + + oldswitchinterval = sys.getswitchinterval() + setswitchinterval(1e-6) + try: + threads = [ + threading.Thread(target=test_function, args=(thread_id,)) + for thread_id in range(THREADS) + ] + with threading_helper.start_threads(threads): + pass + finally: + sys.setswitchinterval(oldswitchinterval) + expected_calls = { + (thread_id, i) + for thread_id in range(THREADS) + for i in range(LOOPS) + } + self.assertSetEqual({call.args for call in m.call_args_list}, expected_calls) + + def test_method_calls_thread_safe(self): + m = ThreadingMock() + LOOPS = 100 + THREADS = 10 + def test_function(thread_id): + for i in range(LOOPS): + getattr(m, f"method_{thread_id}")(i) + + oldswitchinterval = sys.getswitchinterval() + setswitchinterval(1e-6) + try: + threads = [ + threading.Thread(target=test_function, args=(thread_id,)) + for thread_id in range(THREADS) + ] + with threading_helper.start_threads(threads): + pass + finally: + sys.setswitchinterval(oldswitchinterval) + for thread_id in range(THREADS): + self.assertEqual(getattr(m, f"method_{thread_id}").call_count, LOOPS) + self.assertEqual({call.args for call in getattr(m, f"method_{thread_id}").call_args_list}, + {(i,) for i in range(LOOPS)}) + + def test_mock_calls_thread_safe(self): + m = ThreadingMock() + LOOPS = 100 + THREADS = 10 + def test_function(thread_id): + for i in range(LOOPS): + m(thread_id, i) + + oldswitchinterval = sys.getswitchinterval() + setswitchinterval(1e-6) + try: + threads = [ + threading.Thread(target=test_function, args=(thread_id,)) + for thread_id in range(THREADS) + ] + with threading_helper.start_threads(threads): + pass + finally: + sys.setswitchinterval(oldswitchinterval) + expected_calls = { + (thread_id, i) + for thread_id in range(THREADS) + for i in range(LOOPS) + } + self.assertSetEqual({call.args for call in m.mock_calls}, expected_calls) if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 0d6b05bc660..35e4652a87b 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -206,6 +206,97 @@ class UnparseTestCase(ASTTestCase): self.check_ast_roundtrip("t'foo'") self.check_ast_roundtrip("t'foo {bar}'") self.check_ast_roundtrip("t'foo {bar!s:.2f}'") + self.check_ast_roundtrip("t'{a + b}'") + self.check_ast_roundtrip("t'{a + b:x}'") + self.check_ast_roundtrip("t'{a + b!s}'") + self.check_ast_roundtrip("t'{ {a}}'") + self.check_ast_roundtrip("t'{ {a}=}'") + self.check_ast_roundtrip("t'{{a}}'") + self.check_ast_roundtrip("t''") + self.check_ast_roundtrip('t""') + self.check_ast_roundtrip("t'{(lambda x: x)}'") + self.check_ast_roundtrip("t'{t'{x}'}'") + + def test_tstring_with_nonsensical_str_field(self): + # `value` suggests that the original code is `t'{test1}`, but `str` suggests otherwise + self.assertEqual( + ast.unparse( + ast.TemplateStr( + values=[ + ast.Interpolation( + value=ast.Name(id="test1", ctx=ast.Load()), str="test2", conversion=-1 + ) + ] + ) + ), + "t'{test2}'", + ) + + def test_tstring_with_none_str_field(self): + self.assertEqual( + ast.unparse( + ast.TemplateStr( + [ast.Interpolation(value=ast.Name(id="test1"), str=None, conversion=-1)] + ) + ), + "t'{test1}'", + ) + self.assertEqual( + ast.unparse( + ast.TemplateStr( + [ + ast.Interpolation( + value=ast.Lambda( + args=ast.arguments(args=[ast.arg(arg="x")]), + body=ast.Name(id="x"), + ), + str=None, + conversion=-1, + ) + ] + ) + ), + "t'{(lambda x: x)}'", + ) + self.assertEqual( + ast.unparse( + ast.TemplateStr( + values=[ + ast.Interpolation( + value=ast.TemplateStr( + # `str` field kept here + [ast.Interpolation(value=ast.Name(id="x"), str="y", conversion=-1)] + ), + str=None, + conversion=-1, + ) + ] + ) + ), + '''t"{t'{y}'}"''', + ) + self.assertEqual( + ast.unparse( + ast.TemplateStr( + values=[ + ast.Interpolation( + value=ast.TemplateStr( + [ast.Interpolation(value=ast.Name(id="x"), str=None, conversion=-1)] + ), + str=None, + conversion=-1, + ) + ] + ) + ), + '''t"{t'{x}'}"''', + ) + self.assertEqual( + ast.unparse(ast.TemplateStr( + [ast.Interpolation(value=ast.Constant(value="foo"), str=None, conversion=114)] + )), + '''t"{'foo'!r}"''', + ) def test_strings(self): self.check_ast_roundtrip("u'foo'") @@ -813,15 +904,6 @@ class CosmeticTestCase(ASTTestCase): self.check_ast_roundtrip("def f[T: int = int, **P = int, *Ts = *int]():\n pass") self.check_ast_roundtrip("class C[T: int = int, **P = int, *Ts = *int]():\n pass") - def test_tstr(self): - self.check_ast_roundtrip("t'{a + b}'") - self.check_ast_roundtrip("t'{a + b:x}'") - self.check_ast_roundtrip("t'{a + b!s}'") - self.check_ast_roundtrip("t'{ {a}}'") - self.check_ast_roundtrip("t'{ {a}=}'") - self.check_ast_roundtrip("t'{{a}}'") - self.check_ast_roundtrip("t''") - class ManualASTCreationTestCase(unittest.TestCase): """Test that AST nodes created without a type_params field unparse correctly.""" diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 7d7f2fa00d3..3a77b9e5ab7 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -577,6 +577,23 @@ class OpenerDirectorTests(unittest.TestCase): self.assertRaises(TypeError, OpenerDirector().add_handler, NonHandler()) + def test_no_protocol_methods(self): + # test the case that methods starts with handler type without the protocol + # like open*() or _open*(). + # These methods should be ignored + + o = OpenerDirector() + meth_spec = [ + ["open"], + ["_open"], + ["error"] + ] + + add_ordered_mock_handlers(o, meth_spec) + + self.assertEqual(len(o.handle_open), 0) + self.assertEqual(len(o.handle_error), 0) + def test_badly_named_methods(self): # test work-around for three methods that accidentally follow the # naming conventions for handler methods diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index e6a18476908..17db686942f 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -1,9 +1,13 @@ +import contextlib import errno +import sysconfig import unittest +from unittest import mock from test import support from test.support import os_helper from test.support import socket_helper from test.support import ResourceDenied +from test.support.warnings_helper import check_no_resource_warning import os import socket @@ -143,6 +147,43 @@ class OtherNetworkTests(unittest.TestCase): ] self._test_urls(urls, self._extra_handlers()) + @support.requires_resource('walltime') + @unittest.skipIf(sysconfig.get_platform() == 'linux-ppc64le', + 'leaks on PPC64LE (gh-140691)') + def test_ftp_no_leak(self): + # gh-140691: When the data connection (but not control connection) + # cannot be made established, we shouldn't leave an open socket object. + + class MockError(OSError): + pass + + orig_create_connection = socket.create_connection + def patched_create_connection(address, *args, **kwargs): + """Simulate REJECTing connections to ports other than 21""" + host, port = address + if port != 21: + raise MockError() + return orig_create_connection(address, *args, **kwargs) + + url = 'ftp://www.pythontest.net/README' + entry = url, None, urllib.error.URLError + no_cache_handlers = [urllib.request.FTPHandler()] + cache_handlers = self._extra_handlers() + with mock.patch('socket.create_connection', patched_create_connection): + with check_no_resource_warning(self): + # Try without CacheFTPHandler + self._test_urls([entry], handlers=no_cache_handlers, + retry=False) + with check_no_resource_warning(self): + # Try with CacheFTPHandler (uncached) + self._test_urls([entry], cache_handlers, retry=False) + with check_no_resource_warning(self): + # Try with CacheFTPHandler (cached) + self._test_urls([entry], cache_handlers, retry=False) + # Try without the mock: the handler should not use a closed connection + with check_no_resource_warning(self): + self._test_urls([url], cache_handlers, retry=False) + def test_file(self): TESTFN = os_helper.TESTFN f = open(TESTFN, 'w') @@ -218,27 +259,6 @@ class OtherNetworkTests(unittest.TestCase): opener.open(request) self.assertEqual(request.get_header('User-agent'),'Test-Agent') - @unittest.skip('XXX: http://www.imdb.com is gone') - def test_sites_no_connection_close(self): - # Some sites do not send Connection: close header. - # Verify that those work properly. (#issue12576) - - URL = 'http://www.imdb.com' # mangles Connection:close - - with socket_helper.transient_internet(URL): - try: - with urllib.request.urlopen(URL) as res: - pass - except ValueError: - self.fail("urlopen failed for site not sending \ - Connection:close") - else: - self.assertTrue(res) - - req = urllib.request.urlopen(URL) - res = req.read() - self.assertTrue(res) - def _test_urls(self, urls, handlers, retry=True): import time import logging @@ -255,18 +275,16 @@ class OtherNetworkTests(unittest.TestCase): else: req = expected_err = None + if expected_err: + context = self.assertRaises(expected_err) + else: + context = contextlib.nullcontext() + with socket_helper.transient_internet(url): - try: + f = None + with context: f = urlopen(url, req, support.INTERNET_TIMEOUT) - # urllib.error.URLError is a subclass of OSError - except OSError as err: - if expected_err: - msg = ("Didn't get expected error(s) %s for %s %s, got %s: %s" % - (expected_err, url, req, type(err), err)) - self.assertIsInstance(err, expected_err, msg) - else: - raise - else: + if f is not None: try: with time_out, \ socket_peer_reset, \ diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index edce504fc4b..5f9ab048cde 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -13,7 +13,7 @@ from itertools import product from unittest import mock from test import support -from test.support import import_helper, warnings_helper +from test.support import force_not_colorized_test_class, import_helper, warnings_helper from test.support.script_helper import assert_python_ok py_uuid = import_helper.import_fresh_module('uuid', blocked=['_uuid']) @@ -590,6 +590,7 @@ class BaseTestUUID: # dependent on the underlying platform support. At least it cannot be # unknown (unless I suppose the platform is buggy). self.assertNotEqual(u.is_safe, self.uuid.SafeUUID.unknown) + self.assertEqual(u.version, 1) @contextlib.contextmanager def mock_generate_time_safe(self, safe_value): @@ -612,24 +613,28 @@ class BaseTestUUID: with self.mock_generate_time_safe(None): u = self.uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown) + self.assertEqual(u.version, 1) @unittest.skipUnless(os.name == 'posix', 'POSIX-only test') def test_uuid1_is_safe(self): with self.mock_generate_time_safe(0): u = self.uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.safe) + self.assertEqual(u.version, 1) @unittest.skipUnless(os.name == 'posix', 'POSIX-only test') def test_uuid1_is_unsafe(self): with self.mock_generate_time_safe(-1): u = self.uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unsafe) + self.assertEqual(u.version, 1) @unittest.skipUnless(os.name == 'posix', 'POSIX-only test') def test_uuid1_bogus_return_value(self): with self.mock_generate_time_safe(3): u = self.uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown) + self.assertEqual(u.version, 1) def test_uuid1_time(self): with mock.patch.object(self.uuid, '_generate_time_safe', None), \ @@ -1245,10 +1250,12 @@ class CommandLineTestCases: self.do_test_standalone_uuid(8) +@force_not_colorized_test_class class TestUUIDWithoutExtModule(CommandLineTestCases, BaseTestUUID, unittest.TestCase): uuid = py_uuid +@force_not_colorized_test_class @unittest.skipUnless(c_uuid, 'requires the C _uuid module') class TestUUIDWithExtModule(CommandLineTestCases, BaseTestUUID, unittest.TestCase): uuid = c_uuid diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 3c18c9c2900..68bcf535ead 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -12,7 +12,6 @@ import os.path import pathlib import re import shutil -import struct import subprocess import sys import sysconfig @@ -138,14 +137,9 @@ class BasicTest(BaseTest): self.isdir(self.bindir) self.isdir(self.include) self.isdir(*self.lib) - # Issue 21197 p = self.get_env_file('lib64') - conditions = ((struct.calcsize('P') == 8) and (os.name == 'posix') and - (sys.platform != 'darwin')) - if conditions: - self.assertTrue(os.path.islink(p)) - else: - self.assertFalse(os.path.exists(p)) + if os.path.exists(p): + self.assertFalse(os.path.islink(p)) data = self.get_text_file_contents('pyvenv.cfg') executable = sys._base_executable path = os.path.dirname(executable) @@ -522,6 +516,8 @@ class BasicTest(BaseTest): # gh-124651: test quoted strings @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') + @unittest.skipIf(sys.platform.startswith('netbsd'), + "NetBSD csh fails with quoted special chars; see gh-139308") def test_special_chars_csh(self): """ Test that the template strings are quoted properly (csh) diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 694cfc97064..a6af5057cc8 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -241,6 +241,96 @@ class FilterTests(BaseTest): 42) self.assertEqual(len(w), 0) + def test_filter_module(self): + MS_WINDOWS = (sys.platform == 'win32') + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'package\.module\z') + self.module.warn_explicit('msg', UserWarning, 'filename', 42, + module='package.module') + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42) + self.assertEqual(len(w), 2) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42) + self.assertEqual(len(w), 3) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module/__init__.py', 42) + self.assertEqual(len(w), 4) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module/__init__', 42) + if MS_WINDOWS: + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42) + self.assertEqual(len(w), 5) + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__INIT__.PY', 42) + self.assertEqual(len(w), 6) + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PYW', 42) + self.assertEqual(len(w), 7) + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__INIT__.PYW', 42) + self.assertEqual(len(w), 8) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module='package') + self.module.warn_explicit('msg', UserWarning, 'filename', 42, + module='package.module') + self.assertEqual(len(w), 1) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, 'filename', 42, + module='other.package.module') + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/path/to/otherpackage/module.py', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'/path/to/package/module\z') + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42) + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42) + self.assertEqual(len(w), 2) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, '/PATH/TO/PACKAGE/MODULE', 42) + if MS_WINDOWS: + self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42) + self.assertEqual(len(w), 3) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module/__init__.py', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.pyw', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'\path\to\package\module', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'/path/to/package/__init__\z') + self.module.warn_explicit('msg', UserWarning, '/path/to/package/__init__.py', 42) + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, '/path/to/package/__init__', 42) + self.assertEqual(len(w), 2) + + if MS_WINDOWS: + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'C:\\path\\to\\package\\module\z') + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module', 42) + self.assertEqual(len(w), 1) + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.py', 42) + self.assertEqual(len(w), 2) + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42) + self.assertEqual(len(w), 3) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.pyw', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:\PATH\TO\PACKAGE\MODULE', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:/path/to/package/module', 42) + with self.assertRaises(UserWarning): + self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__init__.py', 42) + + with self.module.catch_warnings(record=True) as w: + self.module.simplefilter('error') + self.module.filterwarnings('always', module=r'<unknown>\z') + self.module.warn_explicit('msg', UserWarning, '', 42) + self.assertEqual(len(w), 1) + def test_module_globals(self): with self.module.catch_warnings(record=True) as w: self.module.simplefilter("always", UserWarning) @@ -320,7 +410,7 @@ class FilterTests(BaseTest): def test_mutate_filter_list(self): class X: - def match(self, a): + def match(self, a, start=0): L[:] = [] L = [("default",X(),UserWarning,X(),0) for i in range(2)] @@ -637,7 +727,7 @@ class WarnTests(BaseTest): def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError): if self.module is py_warnings: - self.check_module_globals(module_globals) + self.check_module_globals_deprecated(module_globals, errmsg) return with self.module.catch_warnings(record=True) as w: self.module.filterwarnings('always') @@ -648,9 +738,6 @@ class WarnTests(BaseTest): self.assertEqual(len(w), 0) def check_module_globals_deprecated(self, module_globals, msg): - if self.module is py_warnings: - self.check_module_globals(module_globals) - return with self.module.catch_warnings(record=True) as w: self.module.filterwarnings('always') self.module.warn_explicit( @@ -755,6 +842,10 @@ class WCmdLineTests(BaseTest): self.module._setoption('ignore::===') with self.assertRaisesRegex(self.module._OptionError, 'Wärning'): self.module._setoption('ignore::Wärning') + with self.assertRaisesRegex(self.module._OptionError, 'message'): + self.module._setoption('ignore:/?/:Warning') + with self.assertRaisesRegex(self.module._OptionError, 'module'): + self.module._setoption('ignore::Warning:/?/') self.module._setoption('error::Warning::0') self.assertRaises(UserWarning, self.module.warn, 'convert to error') @@ -769,6 +860,31 @@ class WCmdLineTests(BaseTest): with self.assertRaises(TestWarning): self.module.warn('test warning', TestWarning) + def test_message(self): + # Match prefix, case-insensitive. + with self.module.catch_warnings(): + self.module._setoption('error:TEST WARN:UserWarning') + with self.assertRaises(UserWarning): + self.module.warn('Test Warning') + with self.module.catch_warnings(): + self.module._setoption(r'error:/TE.*WARN/:UserWarning') + with self.assertRaises(UserWarning): + self.module.warn('Test Warning') + + def test_module(self): + with self.module.catch_warnings(): + self.module._setoption(f'error::UserWarning:{__name__}') + with self.assertRaises(UserWarning): + self.module.warn('test warning') + # Only full match. + self.module._setoption(f'ignore::UserWarning:{__name__[:-2]}') + with self.assertRaises(UserWarning): + self.module.warn('test warning') + with self.module.catch_warnings(): + self.module._setoption(f'error::UserWarning:/{re.escape(__name__[:-2])}./') + with self.assertRaises(UserWarning): + self.module.warn('test warning') + class CWCmdLineTests(WCmdLineTests, unittest.TestCase): module = c_warnings @@ -1863,6 +1979,25 @@ class DeprecatedTests(PyPublicAPITests): self.assertEqual(D.inited, 3) + def test_existing_init_subclass_in_sibling_base(self): + @deprecated("A will go away soon") + class A: + pass + class B: + def __init_subclass__(cls, x): + super().__init_subclass__() + cls.inited = x + + with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"): + class C(A, B, x=42): + pass + self.assertEqual(C.inited, 42) + + with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"): + class D(B, A, x=42): + pass + self.assertEqual(D.inited, 42) + def test_init_subclass_has_correct_cls(self): init_subclass_saw = None diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 226b1aa84bd..4c21f165537 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -1,9 +1,11 @@ import unittest from test import audiotests from test import support +from test.support.os_helper import FakePath import io import os import struct +import tempfile import sys import wave @@ -206,5 +208,25 @@ class WaveLowLevelTest(unittest.TestCase): self.assertIsNone(cm.unraisable) +class WaveOpen(unittest.TestCase): + def test_open_pathlike(self): + """It is possible to use `wave.read` and `wave.write` with a path-like object""" + with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: + cases = ( + FakePath(fp.name), + FakePath(os.fsencode(fp.name)), + os.fsencode(fp.name), + ) + for fake_path in cases: + with self.subTest(fake_path): + with wave.open(fake_path, 'wb') as f: + f.setnchannels(1) + f.setsampwidth(2) + f.setframerate(44100) + + with wave.open(fake_path, 'rb') as f: + pass + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py index 6b577ae100e..20d347168b3 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -7,6 +7,7 @@ import sys import unittest import webbrowser from test import support +from test.support import force_not_colorized_test_class from test.support import import_helper from test.support import is_apple_mobile from test.support import os_helper @@ -503,6 +504,7 @@ class ImportTest(unittest.TestCase): self.assertEqual(webbrowser.get().name, sys.executable) +@force_not_colorized_test_class class CliTest(unittest.TestCase): def test_parse_args(self): for command, url, new_win in [ diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 924a962781a..fc0533c6e15 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -3,6 +3,7 @@ import gc import os, sys, errno +import itertools import threading import unittest from platform import machine, win32_edition @@ -209,6 +210,33 @@ class BaseWinregTests(unittest.TestCase): access=KEY_ALL_ACCESS) as okey: self.assertTrue(okey.handle != 0) + def test_hkey_comparison(self): + """Test HKEY comparison by handle value rather than object identity.""" + key1 = OpenKey(HKEY_CURRENT_USER, None) + key2 = OpenKey(HKEY_CURRENT_USER, None) + key3 = OpenKey(HKEY_LOCAL_MACHINE, None) + + self.addCleanup(CloseKey, key1) + self.addCleanup(CloseKey, key2) + self.addCleanup(CloseKey, key3) + + self.assertEqual(key1.handle, key2.handle) + self.assertTrue(key1 == key2) + self.assertFalse(key1 != key2) + + self.assertTrue(key1 != key3) + self.assertFalse(key1 == key3) + + # Closed keys should be equal (all have handle=0) + CloseKey(key1) + CloseKey(key2) + CloseKey(key3) + + self.assertEqual(key1.handle, 0) + self.assertEqual(key2.handle, 0) + self.assertEqual(key3.handle, 0) + self.assertEqual(key2, key3) + class LocalWinregTests(BaseWinregTests): @@ -291,6 +319,37 @@ class LocalWinregTests(BaseWinregTests): DeleteKey(HKEY_CURRENT_USER, test_key_name+'\\changing_value') DeleteKey(HKEY_CURRENT_USER, test_key_name) + def test_queryvalueex_race_condition(self): + # gh-142282: QueryValueEx could read garbage buffer under race + # condition when another thread changes the value size + done = False + ready = threading.Event() + values = [b'ham', b'spam'] + + class WriterThread(threading.Thread): + def run(self): + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: + values_iter = itertools.cycle(values) + while not done: + val = next(values_iter) + SetValueEx(key, 'test_value', 0, REG_BINARY, val) + ready.set() + + thread = WriterThread() + thread.start() + try: + ready.wait() + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: + for _ in range(1000): + result, typ = QueryValueEx(key, 'test_value') + # The result must be one of the written values, + # not garbage data from uninitialized buffer + self.assertIn(result, values) + finally: + done = True + thread.join() + DeleteKey(HKEY_CURRENT_USER, test_key_name) + def test_long_key(self): # Issue2810, in 2.6 and 3.1 when the key name was exactly 256 # characters, EnumKey raised "WindowsError: More data is @@ -517,6 +576,21 @@ class Win64WinregTests(BaseWinregTests): with self.assertRaises(FileNotFoundError) as ctx: QueryValue(HKEY_CLASSES_ROOT, 'some_value_that_does_not_exist') + def test_delete_tree(self): + with CreateKey(HKEY_CURRENT_USER, test_key_name) as main_key: + with CreateKey(main_key, "subkey1") as subkey1: + SetValueEx(subkey1, "value1", 0, REG_SZ, "test_value1") + with CreateKey(subkey1, "subsubkey1") as subsubkey1: + SetValueEx(subsubkey1, "value2", 0, REG_DWORD, 42) + + with CreateKey(main_key, "subkey2") as subkey2: + SetValueEx(subkey2, "value3", 0, REG_SZ, "test_value3") + + DeleteTree(HKEY_CURRENT_USER, test_key_name) + + with self.assertRaises(OSError): + OpenKey(HKEY_CURRENT_USER, test_key_name) + if __name__ == "__main__": if not REMOTE_NAME: diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py index e04a4d2c221..a8f71c636f9 100644 --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -109,7 +109,7 @@ class IntegrationTests(TestCase): sys.version.split()[0]) self.assertEqual(out, ("HTTP/1.0 200 OK\r\n" - "Server: WSGIServer/0.2 " + pyver +"\r\n" + "Server: WSGIServer " + pyver + "\r\n" "Content-Type: text/plain\r\n" "Date: Mon, 05 Jun 2006 18:49:54 GMT\r\n" + (has_length and "Content-Length: 13\r\n" or "") + @@ -206,7 +206,7 @@ class IntegrationTests(TestCase): pyver = py + b"/" + ver self.assertEqual( b"HTTP/1.0 200 OK\r\n" - b"Server: WSGIServer/0.2 "+ pyver + b"\r\n" + b"Server: WSGIServer " + pyver + b"\r\n" b"Content-Type: text/plain; charset=utf-8\r\n" b"Date: Wed, 24 Dec 2008 13:29:32 GMT\r\n" b"\r\n" @@ -840,5 +840,17 @@ class HandlerTests(TestCase): self.assertIsNotNone(h.environ) +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + from wsgiref import simple_server + + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(simple_server, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index bf6d5074fde..87811199706 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -574,208 +574,6 @@ class ElementTreeTest(unittest.TestCase): self.assertEqual(len(ids), 1) self.assertEqual(ids["body"].tag, 'body') - def test_iterparse(self): - # Test iterparse interface. - - iterparse = ET.iterparse - - context = iterparse(SIMPLE_XMLFILE) - self.assertIsNone(context.root) - action, elem = next(context) - self.assertIsNone(context.root) - self.assertEqual((action, elem.tag), ('end', 'element')) - self.assertEqual([(action, elem.tag) for action, elem in context], [ - ('end', 'element'), - ('end', 'empty-element'), - ('end', 'root'), - ]) - self.assertEqual(context.root.tag, 'root') - - context = iterparse(SIMPLE_NS_XMLFILE) - self.assertEqual([(action, elem.tag) for action, elem in context], [ - ('end', '{namespace}element'), - ('end', '{namespace}element'), - ('end', '{namespace}empty-element'), - ('end', '{namespace}root'), - ]) - - with open(SIMPLE_XMLFILE, 'rb') as source: - context = iterparse(source) - action, elem = next(context) - self.assertEqual((action, elem.tag), ('end', 'element')) - self.assertEqual([(action, elem.tag) for action, elem in context], [ - ('end', 'element'), - ('end', 'empty-element'), - ('end', 'root'), - ]) - self.assertEqual(context.root.tag, 'root') - - events = () - context = iterparse(SIMPLE_XMLFILE, events) - self.assertEqual([(action, elem.tag) for action, elem in context], []) - - events = () - context = iterparse(SIMPLE_XMLFILE, events=events) - self.assertEqual([(action, elem.tag) for action, elem in context], []) - - events = ("start", "end") - context = iterparse(SIMPLE_XMLFILE, events) - self.assertEqual([(action, elem.tag) for action, elem in context], [ - ('start', 'root'), - ('start', 'element'), - ('end', 'element'), - ('start', 'element'), - ('end', 'element'), - ('start', 'empty-element'), - ('end', 'empty-element'), - ('end', 'root'), - ]) - - events = ("start", "end", "start-ns", "end-ns") - context = iterparse(SIMPLE_NS_XMLFILE, events) - self.assertEqual([(action, elem.tag) if action in ("start", "end") - else (action, elem) - for action, elem in context], [ - ('start-ns', ('', 'namespace')), - ('start', '{namespace}root'), - ('start', '{namespace}element'), - ('end', '{namespace}element'), - ('start', '{namespace}element'), - ('end', '{namespace}element'), - ('start', '{namespace}empty-element'), - ('end', '{namespace}empty-element'), - ('end', '{namespace}root'), - ('end-ns', None), - ]) - - events = ('start-ns', 'end-ns') - context = iterparse(io.StringIO(r"<root xmlns=''/>"), events) - res = [action for action, elem in context] - self.assertEqual(res, ['start-ns', 'end-ns']) - - events = ("start", "end", "bogus") - with open(SIMPLE_XMLFILE, "rb") as f: - with self.assertRaises(ValueError) as cm: - iterparse(f, events) - self.assertFalse(f.closed) - self.assertEqual(str(cm.exception), "unknown event 'bogus'") - - with warnings_helper.check_no_resource_warning(self): - with self.assertRaises(ValueError) as cm: - iterparse(SIMPLE_XMLFILE, events) - self.assertEqual(str(cm.exception), "unknown event 'bogus'") - del cm - - source = io.BytesIO( - b"<?xml version='1.0' encoding='iso-8859-1'?>\n" - b"<body xmlns='http://&#233;ffbot.org/ns'\n" - b" xmlns:cl\xe9='http://effbot.org/ns'>text</body>\n") - events = ("start-ns",) - context = iterparse(source, events) - self.assertEqual([(action, elem) for action, elem in context], [ - ('start-ns', ('', 'http://\xe9ffbot.org/ns')), - ('start-ns', ('cl\xe9', 'http://effbot.org/ns')), - ]) - - source = io.StringIO("<document />junk") - it = iterparse(source) - action, elem = next(it) - self.assertEqual((action, elem.tag), ('end', 'document')) - with self.assertRaises(ET.ParseError) as cm: - next(it) - self.assertEqual(str(cm.exception), - 'junk after document element: line 1, column 12') - - self.addCleanup(os_helper.unlink, TESTFN) - with open(TESTFN, "wb") as f: - f.write(b"<document />junk") - it = iterparse(TESTFN) - action, elem = next(it) - self.assertEqual((action, elem.tag), ('end', 'document')) - with warnings_helper.check_no_resource_warning(self): - with self.assertRaises(ET.ParseError) as cm: - next(it) - self.assertEqual(str(cm.exception), - 'junk after document element: line 1, column 12') - del cm, it - - # Not exhausting the iterator still closes the resource (bpo-43292) - with warnings_helper.check_no_resource_warning(self): - it = iterparse(SIMPLE_XMLFILE) - del it - - with warnings_helper.check_no_resource_warning(self): - it = iterparse(SIMPLE_XMLFILE) - it.close() - del it - - with warnings_helper.check_no_resource_warning(self): - it = iterparse(SIMPLE_XMLFILE) - action, elem = next(it) - self.assertEqual((action, elem.tag), ('end', 'element')) - del it, elem - - with warnings_helper.check_no_resource_warning(self): - it = iterparse(SIMPLE_XMLFILE) - action, elem = next(it) - it.close() - self.assertEqual((action, elem.tag), ('end', 'element')) - del it, elem - - with self.assertRaises(FileNotFoundError): - iterparse("nonexistent") - - def test_iterparse_close(self): - iterparse = ET.iterparse - - it = iterparse(SIMPLE_XMLFILE) - it.close() - with self.assertRaises(StopIteration): - next(it) - it.close() # idempotent - - with open(SIMPLE_XMLFILE, 'rb') as source: - it = iterparse(source) - it.close() - self.assertFalse(source.closed) - with self.assertRaises(StopIteration): - next(it) - it.close() # idempotent - - it = iterparse(SIMPLE_XMLFILE) - action, elem = next(it) - self.assertEqual((action, elem.tag), ('end', 'element')) - it.close() - with self.assertRaises(StopIteration): - next(it) - it.close() # idempotent - - with open(SIMPLE_XMLFILE, 'rb') as source: - it = iterparse(source) - action, elem = next(it) - self.assertEqual((action, elem.tag), ('end', 'element')) - it.close() - self.assertFalse(source.closed) - with self.assertRaises(StopIteration): - next(it) - it.close() # idempotent - - it = iterparse(SIMPLE_XMLFILE) - list(it) - it.close() - with self.assertRaises(StopIteration): - next(it) - it.close() # idempotent - - with open(SIMPLE_XMLFILE, 'rb') as source: - it = iterparse(source) - list(it) - it.close() - self.assertFalse(source.closed) - with self.assertRaises(StopIteration): - next(it) - it.close() # idempotent - def test_writefile(self): elem = ET.Element("tag") elem.text = "text" @@ -1499,6 +1297,281 @@ class ElementTreeTest(unittest.TestCase): {'{http://www.w3.org/XML/1998/namespace}lang': 'eng'}) +class IterparseTest(unittest.TestCase): + # Test iterparse interface. + + def test_basic(self): + iterparse = ET.iterparse + + it = iterparse(SIMPLE_XMLFILE) + self.assertIsNone(it.root) + action, elem = next(it) + self.assertIsNone(it.root) + self.assertEqual((action, elem.tag), ('end', 'element')) + self.assertEqual([(action, elem.tag) for action, elem in it], [ + ('end', 'element'), + ('end', 'empty-element'), + ('end', 'root'), + ]) + self.assertEqual(it.root.tag, 'root') + it.close() + + it = iterparse(SIMPLE_NS_XMLFILE) + self.assertEqual([(action, elem.tag) for action, elem in it], [ + ('end', '{namespace}element'), + ('end', '{namespace}element'), + ('end', '{namespace}empty-element'), + ('end', '{namespace}root'), + ]) + it.close() + + def test_external_file(self): + with open(SIMPLE_XMLFILE, 'rb') as source: + it = ET.iterparse(source) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'element')) + self.assertEqual([(action, elem.tag) for action, elem in it], [ + ('end', 'element'), + ('end', 'empty-element'), + ('end', 'root'), + ]) + self.assertEqual(it.root.tag, 'root') + + def test_events(self): + iterparse = ET.iterparse + + events = () + it = iterparse(SIMPLE_XMLFILE, events) + self.assertEqual([(action, elem.tag) for action, elem in it], []) + it.close() + + events = () + it = iterparse(SIMPLE_XMLFILE, events=events) + self.assertEqual([(action, elem.tag) for action, elem in it], []) + it.close() + + events = ("start", "end") + it = iterparse(SIMPLE_XMLFILE, events) + self.assertEqual([(action, elem.tag) for action, elem in it], [ + ('start', 'root'), + ('start', 'element'), + ('end', 'element'), + ('start', 'element'), + ('end', 'element'), + ('start', 'empty-element'), + ('end', 'empty-element'), + ('end', 'root'), + ]) + it.close() + + def test_namespace_events(self): + iterparse = ET.iterparse + + events = ("start", "end", "start-ns", "end-ns") + it = iterparse(SIMPLE_NS_XMLFILE, events) + self.assertEqual([(action, elem.tag) if action in ("start", "end") + else (action, elem) + for action, elem in it], [ + ('start-ns', ('', 'namespace')), + ('start', '{namespace}root'), + ('start', '{namespace}element'), + ('end', '{namespace}element'), + ('start', '{namespace}element'), + ('end', '{namespace}element'), + ('start', '{namespace}empty-element'), + ('end', '{namespace}empty-element'), + ('end', '{namespace}root'), + ('end-ns', None), + ]) + it.close() + + events = ('start-ns', 'end-ns') + it = iterparse(io.BytesIO(br"<root xmlns=''/>"), events) + res = [action for action, elem in it] + self.assertEqual(res, ['start-ns', 'end-ns']) + it.close() + + def test_unknown_events(self): + iterparse = ET.iterparse + + events = ("start", "end", "bogus") + with open(SIMPLE_XMLFILE, "rb") as f: + with self.assertRaises(ValueError) as cm: + iterparse(f, events) + self.assertFalse(f.closed) + self.assertEqual(str(cm.exception), "unknown event 'bogus'") + + with warnings_helper.check_no_resource_warning(self): + with self.assertRaises(ValueError) as cm: + iterparse(SIMPLE_XMLFILE, events) + self.assertEqual(str(cm.exception), "unknown event 'bogus'") + del cm + gc_collect() + + def test_non_utf8(self): + source = io.BytesIO( + b"<?xml version='1.0' encoding='iso-8859-1'?>\n" + b"<body xmlns='http://&#233;ffbot.org/ns'\n" + b" xmlns:cl\xe9='http://effbot.org/ns'>text</body>\n") + events = ("start-ns",) + it = ET.iterparse(source, events) + self.assertEqual([(action, elem) for action, elem in it], [ + ('start-ns', ('', 'http://\xe9ffbot.org/ns')), + ('start-ns', ('cl\xe9', 'http://effbot.org/ns')), + ]) + + def test_parsing_error(self): + source = io.BytesIO(b"<document />junk") + it = ET.iterparse(source) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'document')) + with self.assertRaises(ET.ParseError) as cm: + next(it) + self.assertEqual(str(cm.exception), + 'junk after document element: line 1, column 12') + + def test_nonexistent_file(self): + with self.assertRaises(FileNotFoundError): + ET.iterparse("nonexistent") + + def test_resource_warnings_not_exhausted(self): + # Not exhausting the iterator still closes the underlying file (bpo-43292) + # Not closing before del should emit ResourceWarning + it = ET.iterparse(SIMPLE_XMLFILE) + with warnings_helper.check_no_resource_warning(self): + it.close() + del it + gc_collect() + + it = ET.iterparse(SIMPLE_XMLFILE) + with self.assertWarns(ResourceWarning) as wm: + del it + gc_collect() + # Not 'unclosed file'. + self.assertIn('unclosed iterparse iterator', str(wm.warning)) + self.assertIn(repr(SIMPLE_XMLFILE), str(wm.warning)) + self.assertEqual(wm.filename, __file__) + + it = ET.iterparse(SIMPLE_XMLFILE) + with warnings_helper.check_no_resource_warning(self): + action, elem = next(it) + it.close() + self.assertEqual((action, elem.tag), ('end', 'element')) + del it, elem + gc_collect() + + it = ET.iterparse(SIMPLE_XMLFILE) + with self.assertWarns(ResourceWarning) as wm: + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'element')) + del it, elem + gc_collect() + self.assertIn('unclosed iterparse iterator', str(wm.warning)) + self.assertIn(repr(SIMPLE_XMLFILE), str(wm.warning)) + self.assertEqual(wm.filename, __file__) + + def test_resource_warnings_failed_iteration(self): + self.addCleanup(os_helper.unlink, TESTFN) + with open(TESTFN, "wb") as f: + f.write(b"<document />junk") + + it = ET.iterparse(TESTFN) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'document')) + with warnings_helper.check_no_resource_warning(self): + with self.assertRaises(ET.ParseError) as cm: + next(it) + self.assertEqual(str(cm.exception), + 'junk after document element: line 1, column 12') + it.close() + del cm, it + gc_collect() + + it = ET.iterparse(TESTFN) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'document')) + with self.assertWarns(ResourceWarning) as wm: + with self.assertRaises(ET.ParseError) as cm: + next(it) + self.assertEqual(str(cm.exception), + 'junk after document element: line 1, column 12') + del cm, it + gc_collect() + self.assertIn('unclosed iterparse iterator', str(wm.warning)) + self.assertIn(repr(TESTFN), str(wm.warning)) + self.assertEqual(wm.filename, __file__) + + def test_resource_warnings_exhausted(self): + it = ET.iterparse(SIMPLE_XMLFILE) + with warnings_helper.check_no_resource_warning(self): + list(it) + it.close() + del it + gc_collect() + + it = ET.iterparse(SIMPLE_XMLFILE) + with self.assertWarns(ResourceWarning) as wm: + list(it) + del it + gc_collect() + self.assertIn('unclosed iterparse iterator', str(wm.warning)) + self.assertIn(repr(SIMPLE_XMLFILE), str(wm.warning)) + self.assertEqual(wm.filename, __file__) + + def test_close_not_exhausted(self): + iterparse = ET.iterparse + + it = iterparse(SIMPLE_XMLFILE) + it.close() + with self.assertRaises(StopIteration): + next(it) + it.close() # idempotent + + with open(SIMPLE_XMLFILE, 'rb') as source: + it = iterparse(source) + it.close() + self.assertFalse(source.closed) + with self.assertRaises(StopIteration): + next(it) + it.close() # idempotent + + it = iterparse(SIMPLE_XMLFILE) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'element')) + it.close() + with self.assertRaises(StopIteration): + next(it) + it.close() # idempotent + + with open(SIMPLE_XMLFILE, 'rb') as source: + it = iterparse(source) + action, elem = next(it) + self.assertEqual((action, elem.tag), ('end', 'element')) + it.close() + self.assertFalse(source.closed) + with self.assertRaises(StopIteration): + next(it) + it.close() # idempotent + + def test_close_exhausted(self): + iterparse = ET.iterparse + it = iterparse(SIMPLE_XMLFILE) + list(it) + it.close() + with self.assertRaises(StopIteration): + next(it) + it.close() # idempotent + + with open(SIMPLE_XMLFILE, 'rb') as source: + it = iterparse(source) + list(it) + it.close() + self.assertFalse(source.closed) + with self.assertRaises(StopIteration): + next(it) + it.close() # idempotent + + class XMLPullParserTest(unittest.TestCase): def _feed(self, parser, data, chunk_size=None, flush=False): @@ -1749,6 +1822,8 @@ class XMLPullParserTest(unittest.TestCase): def test_unknown_event(self): with self.assertRaises(ValueError): ET.XMLPullParser(events=('start', 'end', 'bogus')) + with self.assertRaisesRegex(ValueError, "unknown event 'bogus'"): + ET.XMLPullParser(events=(x.decode() for x in (b'start', b'end', b'bogus'))) @unittest.skipIf(pyexpat.version_info < (2, 6, 0), f'Expat {pyexpat.version_info} does not ' diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py index 958a586b0dc..e7931b6f394 100644 --- a/Lib/test/test_zipfile/_path/test_path.py +++ b/Lib/test/test_zipfile/_path/test_path.py @@ -274,7 +274,8 @@ class TestPath(unittest.TestCase): """ zipfile_ondisk = self.zipfile_ondisk(alpharep) pathlike = FakePath(str(zipfile_ondisk)) - zipfile.Path(pathlike) + root = zipfile.Path(pathlike) + root.root.close() @pass_alpharep def test_traverse_pathlike(self, alpharep): @@ -373,6 +374,7 @@ class TestPath(unittest.TestCase): root = zipfile.Path(self.zipfile_ondisk(alpharep)) assert root.name == 'alpharep.zip' == root.filename.name assert root.stem == 'alpharep' == root.filename.stem + root.root.close() @pass_alpharep def test_suffix(self, alpharep): @@ -574,11 +576,13 @@ class TestPath(unittest.TestCase): ) def test_pickle(self, alpharep, path_type, subpath): zipfile_ondisk = path_type(str(self.zipfile_ondisk(alpharep))) - - saved_1 = pickle.dumps(zipfile.Path(zipfile_ondisk, at=subpath)) + root = zipfile.Path(zipfile_ondisk, at=subpath) + saved_1 = pickle.dumps(root) + root.root.close() restored_1 = pickle.loads(saved_1) first, *rest = restored_1.iterdir() assert first.read_text(encoding='utf-8').startswith('content of ') + restored_1.root.close() @pass_alpharep def test_extract_orig_with_implied_dirs(self, alpharep): @@ -590,6 +594,7 @@ class TestPath(unittest.TestCase): # wrap the zipfile for its side effect zipfile.Path(zf) zf.extractall(source_path.parent) + zf.close() @pass_alpharep def test_getinfo_missing(self, alpharep): diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index c033059a515..6887a5e5cc4 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -312,26 +312,26 @@ class AbstractTestsWithSourceFile: self.assertEqual(openobj.read(1), b'2') def test_writestr_compression(self): - zipfp = zipfile.ZipFile(TESTFN2, "w") - zipfp.writestr("b.txt", "hello world", compress_type=self.compression) - info = zipfp.getinfo('b.txt') - self.assertEqual(info.compress_type, self.compression) + with zipfile.ZipFile(TESTFN2, "w") as zipfp: + zipfp.writestr("b.txt", "hello world", compress_type=self.compression) + info = zipfp.getinfo('b.txt') + self.assertEqual(info.compress_type, self.compression) def test_writestr_compresslevel(self): - zipfp = zipfile.ZipFile(TESTFN2, "w", compresslevel=1) - zipfp.writestr("a.txt", "hello world", compress_type=self.compression) - zipfp.writestr("b.txt", "hello world", compress_type=self.compression, - compresslevel=2) + with zipfile.ZipFile(TESTFN2, "w", compresslevel=1) as zipfp: + zipfp.writestr("a.txt", "hello world", compress_type=self.compression) + zipfp.writestr("b.txt", "hello world", compress_type=self.compression, + compresslevel=2) - # Compression level follows the constructor. - a_info = zipfp.getinfo('a.txt') - self.assertEqual(a_info.compress_type, self.compression) - self.assertEqual(a_info.compress_level, 1) + # Compression level follows the constructor. + a_info = zipfp.getinfo('a.txt') + self.assertEqual(a_info.compress_type, self.compression) + self.assertEqual(a_info.compress_level, 1) - # Compression level is overridden. - b_info = zipfp.getinfo('b.txt') - self.assertEqual(b_info.compress_type, self.compression) - self.assertEqual(b_info._compresslevel, 2) + # Compression level is overridden. + b_info = zipfp.getinfo('b.txt') + self.assertEqual(b_info.compress_type, self.compression) + self.assertEqual(b_info._compresslevel, 2) def test_read_return_size(self): # Issue #9837: ZipExtFile.read() shouldn't return more bytes @@ -898,6 +898,8 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, self, file_size_64_set=False, file_size_extra=False, compress_size_64_set=False, compress_size_extra=False, header_offset_64_set=False, header_offset_extra=False, + extensible_data=b'', + end_of_central_dir_size=None, offset_to_end_of_central_dir=None, ): """Generate bytes sequence for a zip with (incomplete) zip64 data. @@ -951,6 +953,12 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields)) offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields)) + if end_of_central_dir_size is None: + end_of_central_dir_size = 44 + len(extensible_data) + if offset_to_end_of_central_dir is None: + offset_to_end_of_central_dir = (108 + + 8 * len(local_zip64_fields) + + 8 * len(central_zip64_fields)) local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields)) central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields)) @@ -979,14 +987,17 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + filename + central_extra # Zip64 end of central directory - + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-" - + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00" + + b"PK\x06\x06" + + struct.pack('<Q', end_of_central_dir_size) + + b"-\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00" + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" + central_dir_size + offset_to_central_dir + + extensible_data # Zip64 end of central directory locator - + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01" - + b"\x00\x00\x00" + + b"PK\x06\x07\x00\x00\x00\x00" + + struct.pack('<Q', offset_to_end_of_central_dir) + + b"\x01\x00\x00\x00" # end of central directory + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00" + b"\x00\x00\x00\x00" @@ -1017,6 +1028,7 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_file_size_extra)) self.assertIn('file size', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_file_size_extra))) # zip64 file size present, zip64 compress size present, one field in # extra, expecting two, equals missing compress size. @@ -1028,6 +1040,7 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_compress_size_extra)) self.assertIn('compress size', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra))) # zip64 compress size present, no fields in extra, expecting one, # equals missing compress size. @@ -1037,6 +1050,7 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_compress_size_extra)) self.assertIn('compress size', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra))) # zip64 file size present, zip64 compress size present, zip64 header # offset present, two fields in extra, expecting three, equals missing @@ -1051,6 +1065,7 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_header_offset_extra)) self.assertIn('header offset', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra))) # zip64 compress size present, zip64 header offset present, one field # in extra, expecting two, equals missing header offset @@ -1063,6 +1078,7 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_header_offset_extra)) self.assertIn('header offset', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra))) # zip64 file size present, zip64 header offset present, one field in # extra, expecting two, equals missing header offset @@ -1075,6 +1091,7 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_header_offset_extra)) self.assertIn('header offset', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra))) # zip64 header offset present, no fields in extra, expecting one, # equals missing header offset @@ -1086,6 +1103,63 @@ class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, with self.assertRaises(zipfile.BadZipFile) as e: zipfile.ZipFile(io.BytesIO(missing_header_offset_extra)) self.assertIn('header offset', str(e.exception).lower()) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra))) + + def test_bad_zip64_end_of_central_dir(self): + zipdata = self.make_zip64_file(end_of_central_dir_size=0) + with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'): + zipfile.ZipFile(io.BytesIO(zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata))) + + zipdata = self.make_zip64_file(end_of_central_dir_size=100) + with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'): + zipfile.ZipFile(io.BytesIO(zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata))) + + zipdata = self.make_zip64_file(offset_to_end_of_central_dir=0) + with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'): + zipfile.ZipFile(io.BytesIO(zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata))) + + zipdata = self.make_zip64_file(offset_to_end_of_central_dir=1000) + with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*locator'): + zipfile.ZipFile(io.BytesIO(zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata))) + + def test_zip64_end_of_central_dir_record_not_found(self): + zipdata = self.make_zip64_file() + zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4) + with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'): + zipfile.ZipFile(io.BytesIO(zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata))) + + zipdata = self.make_zip64_file( + extensible_data=b'\xca\xfe\x04\x00\x00\x00data') + zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4) + with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'): + zipfile.ZipFile(io.BytesIO(zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata))) + + def test_zip64_extensible_data(self): + # These values are what is set in the make_zip64_file method. + expected_file_size = 8 + expected_compress_size = 8 + expected_header_offset = 0 + expected_content = b"test1234" + + zipdata = self.make_zip64_file( + extensible_data=b'\xca\xfe\x04\x00\x00\x00data') + with zipfile.ZipFile(io.BytesIO(zipdata)) as zf: + zinfo = zf.infolist()[0] + self.assertEqual(zinfo.file_size, expected_file_size) + self.assertEqual(zinfo.compress_size, expected_compress_size) + self.assertEqual(zinfo.header_offset, expected_header_offset) + self.assertEqual(zf.read(zinfo), expected_content) + self.assertTrue(zipfile.is_zipfile(io.BytesIO(zipdata))) + + with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'): + zipfile.ZipFile(io.BytesIO(b'prepended' + zipdata)) + self.assertFalse(zipfile.is_zipfile(io.BytesIO(b'prepended' + zipdata))) def test_generated_valid_zip64_extra(self): # These values are what is set in the make_zip64_file method. @@ -2256,6 +2330,7 @@ class OtherTests(unittest.TestCase): zipf = zipfile.ZipFile(TESTFN, mode="r") except zipfile.BadZipFile: self.fail("Unable to create empty ZIP file in 'w' mode") + zipf.close() zipf = zipfile.ZipFile(TESTFN, mode="a") zipf.close() @@ -2263,6 +2338,7 @@ class OtherTests(unittest.TestCase): zipf = zipfile.ZipFile(TESTFN, mode="r") except: self.fail("Unable to create empty ZIP file in 'a' mode") + zipf.close() def test_open_empty_file(self): # Issue 1710703: Check that opening a file with less than 22 bytes @@ -2455,6 +2531,10 @@ class OtherTests(unittest.TestCase): @requires_zlib() def test_full_overlap_different_names(self): + # The ZIP file contains two central directory entries with + # different names which refer to the same local header. + # The name of the local header matches the name of the first + # central directory entry. data = ( b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e' b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00b\xed' @@ -2484,6 +2564,10 @@ class OtherTests(unittest.TestCase): @requires_zlib() def test_full_overlap_different_names2(self): + # The ZIP file contains two central directory entries with + # different names which refer to the same local header. + # The name of the local header matches the name of the second + # central directory entry. data = ( b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e' b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00a\xed' @@ -2515,6 +2599,8 @@ class OtherTests(unittest.TestCase): @requires_zlib() def test_full_overlap_same_name(self): + # The ZIP file contains two central directory entries with + # the same name which refer to the same local header. data = ( b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e' b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00a\xed' @@ -2547,6 +2633,8 @@ class OtherTests(unittest.TestCase): @requires_zlib() def test_quoted_overlap(self): + # The ZIP file contains two files. The second local header + # is contained in the range of the first file. data = ( b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05Y\xfc' b'8\x044\x00\x00\x00(\x04\x00\x00\x01\x00\x00\x00a\x00' @@ -2578,6 +2666,7 @@ class OtherTests(unittest.TestCase): @requires_zlib() def test_overlap_with_central_dir(self): + # The local header offset is equal to the central directory offset. data = ( b'PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00G_|Z' b'\xe2\x1e8\xbb\x0b\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00' @@ -2592,11 +2681,15 @@ class OtherTests(unittest.TestCase): self.assertEqual(zi.header_offset, 0) self.assertEqual(zi.compress_size, 11) self.assertEqual(zi.file_size, 1033) + # Found central directory signature PK\x01\x02 instead of + # local header signature PK\x03\x04. with self.assertRaisesRegex(zipfile.BadZipFile, 'Bad magic number'): zipf.read('a') @requires_zlib() def test_overlap_with_archive_comment(self): + # The local header is written after the central directory, + # in the archive comment. data = ( b'PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00G_|Z' b'\xe2\x1e8\xbb\x0b\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00' diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index b5b4acf5f85..dce3e1d9d38 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -9,13 +9,12 @@ import struct import time import unittest import unittest.mock -import warnings from test import support from test.support import import_helper from test.support import os_helper -from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED, ZIP_ZSTANDARD import zipimport import linecache @@ -194,19 +193,38 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): # occur in that case (builtin modules are always found first), # so we'll simply skip it then. Bug #765456. # - if "zlib" in sys.builtin_module_names: - self.skipTest('zlib is a builtin module') - if "zlib" in sys.modules: - del sys.modules["zlib"] - files = {"zlib.py": test_src} - try: - self.doTest(".py", files, "zlib") - except ImportError: - if self.compression != ZIP_DEFLATED: - self.fail("expected test to not raise ImportError") + if self.compression == ZIP_DEFLATED: + mod_name = "zlib" + if zipimport._zlib_decompress: # validate attr name + # reset the cached import to avoid test order dependencies + zipimport._zlib_decompress = None # reset cache + elif self.compression == ZIP_ZSTANDARD: + mod_name = "_zstd" + if zipimport._zstd_decompressor_class: # validate attr name + # reset the cached import to avoid test order dependencies + zipimport._zstd_decompressor_class = None else: + mod_name = "zlib" # the ZIP_STORED case below + + if mod_name in sys.builtin_module_names: + self.skipTest(f"{mod_name} is a builtin module") + if mod_name in sys.modules: + del sys.modules[mod_name] + files = {f"{mod_name}.py": test_src} + try: + self.doTest(".py", files, mod_name) + except ImportError: if self.compression != ZIP_STORED: - self.fail("expected test to raise ImportError") + # Expected - fake compression module can't decompress + pass + else: + self.fail("expected test to not raise ImportError for uncompressed") + else: + if self.compression == ZIP_STORED: + # Expected - no compression needed, so fake module works + pass + else: + self.fail("expected test to raise ImportError for compressed zip with fake compression module") def testPy(self): files = {TESTMOD + ".py": test_src} @@ -556,13 +574,6 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): self.assertEqual(zi.archive, TEMP_ZIP) self.assertTrue(zi.is_package(TESTPACK)) - # PEP 302 - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - - mod = zi.load_module(TESTPACK) - self.assertEqual(zi.get_filename(TESTPACK), mod.__file__) - # PEP 451 spec = zi.find_spec('spam') self.assertIsNotNone(spec) @@ -577,6 +588,8 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): spec.loader.exec_module(mod) self.assertEqual(zi.get_filename(TESTPACK), mod.__file__) + sys.path.insert(0, TEMP_ZIP) + existing_pack_path = importlib.import_module(TESTPACK).__path__[0] expected_path_path = os.path.join(TEMP_ZIP, TESTPACK) self.assertEqual(existing_pack_path, expected_path_path) @@ -675,11 +688,6 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): self.assertEqual(zi.archive, TEMP_ZIP) self.assertEqual(zi.prefix, packdir) self.assertTrue(zi.is_package(TESTPACK2)) - # PEP 302 - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - mod = zi.load_module(TESTPACK2) - self.assertEqual(zi.get_filename(TESTPACK2), mod.__file__) # PEP 451 spec = zi.find_spec(TESTPACK2) mod = importlib.util.module_from_spec(spec) @@ -702,9 +710,12 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): self.assertEqual( spec.loader.get_filename(TESTMOD), load_mod.__file__) + sys.path.insert(0, TEMP_ZIP + os.sep + TESTPACK) + mod_path = TESTPACK2 + os.sep + TESTMOD mod_name = module_path_to_dotted_name(mod_path) mod = importlib.import_module(mod_name) + self.assertTrue(mod_name in sys.modules) self.assertIsNone(zi.get_source(TESTPACK2)) self.assertIsNone(zi.get_source(mod_path)) @@ -1008,10 +1019,15 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): @support.requires_zlib() -class CompressedZipImportTestCase(UncompressedZipImportTestCase): +class DeflateCompressedZipImportTestCase(UncompressedZipImportTestCase): compression = ZIP_DEFLATED +@support.requires_zstd() +class ZStdCompressedZipImportTestCase(UncompressedZipImportTestCase): + compression = ZIP_ZSTANDARD + + class BadFileZipImportTestCase(unittest.TestCase): def assertZipFailure(self, filename): self.assertRaises(zipimport.ZipImportError, @@ -1069,9 +1085,6 @@ class BadFileZipImportTestCase(unittest.TestCase): z = zipimport.zipimporter(TESTMOD) try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - self.assertRaises(TypeError, z.load_module, None) self.assertRaises(TypeError, z.find_module, None) self.assertRaises(TypeError, z.find_spec, None) self.assertRaises(TypeError, z.exec_module, None) @@ -1082,10 +1095,6 @@ class BadFileZipImportTestCase(unittest.TestCase): error = zipimport.ZipImportError self.assertIsNone(z.find_spec('abc')) - - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - self.assertRaises(error, z.load_module, 'abc') self.assertRaises(error, z.get_code, 'abc') self.assertRaises(OSError, z.get_data, 'abc') self.assertRaises(error, z.get_source, 'abc') diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py index ae8a8c99762..2b28f46149b 100644 --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -13,9 +13,12 @@ import doctest import inspect import linecache import unittest +import warnings +from test import support from test.support import os_helper from test.support.script_helper import (spawn_python, kill_python, assert_python_ok, make_script, make_zip_script) +from test.support import import_helper verbose = test.support.verbose @@ -236,6 +239,26 @@ class ZipSupportTests(unittest.TestCase): # bdb/pdb applies normcase to its filename before displaying self.assertIn(os.path.normcase(run_name.encode('utf-8')), data) + def test_import_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with (os_helper.temp_dir() as tmpdir, + import_helper.DirsOnSysPath()): + zip_name, _ = make_zip_script(tmpdir, "test_zip", + filename, 'test_pkg/test_mod.py') + sys.path.insert(0, zip_name) + import_helper.unload('test_pkg.test_mod') + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'test_pkg\.test_mod\z') + warnings.filterwarnings('error', module='test_mod') + import test_pkg.test_mod + self.assertEqual(sorted(wm.lineno for wm in wlog), + sorted([4, 7, 10, 13, 14, 21]*2)) + filename = test_pkg.test_mod.__file__ + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + def tearDownModule(): test.support.reap_children() diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index c57ab51eca1..ed9d8540815 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -1222,5 +1222,15 @@ class CustomInt: return 100 +class TestModule(unittest.TestCase): + def test_deprecated__version__(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(zlib, "__version__") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_zoneinfo/data/update_test_data.py b/Lib/test/test_zoneinfo/data/update_test_data.py index f531ab316a1..cf1b1eff4fe 100644 --- a/Lib/test/test_zoneinfo/data/update_test_data.py +++ b/Lib/test/test_zoneinfo/data/update_test_data.py @@ -120,3 +120,6 @@ def update_test_data(fname: str = "zoneinfo_data.json") -> None: if __name__ == "__main__": update_test_data() + + print("Remember to update the HAS_TZDATA_PKG version requirement in " + "test_zoneinfo.py!") diff --git a/Lib/test/test_zoneinfo/data/zoneinfo_data.json b/Lib/test/test_zoneinfo/data/zoneinfo_data.json index ec4414a0cde..6c9bf09e12f 100644 --- a/Lib/test/test_zoneinfo/data/zoneinfo_data.json +++ b/Lib/test/test_zoneinfo/data/zoneinfo_data.json @@ -1,190 +1,218 @@ { "data": { "Africa/Abidjan": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j-~f{VGF<>F7KxBg5R*{Ksocg8-YYVul=v7vZzaHN", - "uC=da5UI2rH18c!OnjV{y4u(+A!!VBKmY&$ORw>7UO^(500B;v0RR91bXh%WvBYQl0ssI2", - "00dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j-~f{VGF<>F7KxBg5R*{Ksocg8-", + "YYVul=v7vZzaHNuC=da5UI2rH18c!OnjV{y4u(+A!!VBKmY&$ORw>7UO^(500B;v0RR91b", + "Xh%WvBYQl0ssI200dcD" ], "Africa/Casablanca": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0b&Kz+C_;7KxBg5R*{N&yjMUR~;C-fDaSOU;q-~", - "FqW+4{YBjbcw}`a!dW>b)R2-0a+uwf`P3{_Y@HuCz}S$J$ZJ>R_V<~|Fk>sgX4=%0vUrh-", - "lt@YP^Wrus;j?`Th#xRPzf<<~Hp4DH^gZX>d{+WOp~HNu8!{uWu}&XphAd{j1;rB4|9?R!", - "pqruAFUMt8#*WcrVS{;kLlY(cJRV$w?d2car%R<ALOSO?^`4;ZZtI)%f^^G^>s>q9BgTU4", - "Ht-tQKZ7Z`9QqOb?R#b%z?rk>!CkH7jy3wja4NG2q)H}fNRKg8v{);Em;K3Cncf4C6&Oaj", - "V+DbX%o4+)CV3+e!Lm6dutu(0BQpH1T?W(~cQtKV*^_Pdx!LirjpTs?Bmt@vktjLq4;)O!", - "rrly=c*rwTwMJFd0I57`hgkc?=nyI4RZf9W$6DCWugmf&)wk^tWH17owj=#PGH7Xv-?9$j", - "njwDlkOE+BFNR9YXEmBpO;rqEw=e2IR-8^(W;8ma?M3JVd($2T>IW+0tk|Gm8>ftukRQ9J", - "8k3brzqMnVyjsLI-CKneFa)Lxvp_a<CkQEd#(pMA^rr}rBNElGA=*!M)puBdoErR9{kWL@", - "w=svMc6eZ^-(vQZrV<u^PY#nOIUDJ8%A&;BUVlY9=;@i2j2J1_`P>q40f}0J3VVoWL5rox", - "`Kptivcp}o5xA^@>qNI%?zo=Yj4AMV?kbAA)j(1%)+Pp)bSn+7Yk`M{oE}L-Z!G6<Dgq&*", - "(C-mFJfbEGDH5M^vBr65rcnsx*~|Em_GeU#B)(+T!|MG-nxj0@IPbp-nHejH3~>OMr5G+h", - "p)$3Lg{ono{4cN>Vr&>L4kXH;_VnBL5U!LgzqE%P7QQ*<E!guRW2SE@ayq@)G2nXqA2tGo", - "QIgc6>tue}O`3(TZ0`aKn&~8trOQ-rBXCp)f@P6RMO4l0+;b|5-pk9_ryNh}Zc*v%mvz_#", - "yd<xXt%~gT90dn4e{Ac<baL-)Y{L7&5G($I$>6fjB0g9{MmMnu8bG%#C~ugXK^S^k@?ab#", - "O|aE>dDTt4s4n69(~@t~!wniV%g<uWQat_i6>7khFx~I*4>Y|V$4j5%KPF*-FyKIi@!Ho&", - "x8QQsksYt8)D+W)Ni!=G`ogSu^vLL-l#7A7=iIAKL2SuZk9F}NfNk86VI)9WZE?%2wC-ya", - "F~z#Qsq)LH0|_D8^5fU8X%GeQ4TB>R-dlziA&tZe&1ada208!$nk`7bOFO2S00G<w{Sp8G", - "{cR_IvBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0b&Kz+C_;7KxBg5R*{N&yjMUR~;C-fDaSOU;q-", + "~FqW+4{YBjbcw}`a!dW>b)R2-", + "0a+uwf`P3{_Y@HuCz}S$J$ZJ>R_V<~|Fk>sgX4=%0vUrh-lt@YP^Wrus;j?`Th#xRPzf<<", + "~Hp4DH^gZX>d{+WOp~HNu8!{uWu}&XphAd{j1;rB4|9?R!pqruAFUMt8#*WcrVS{;kLlY(", + "cJRV$w?d2car%R<ALOSO?^`4;ZZtI)%f^^G^>s>q9BgTU4Ht-tQKZ7Z`9QqOb?R#b%z?rk", + ">!CkH7jy3wja4NG2q)H}fNRKg8v{);Em;K3Cncf4C6&OajV+DbX%o4+)CV3+e!Lm6dutu(", + "0BQpH1T?W(~cQtKV*^_Pdx!LirjpTs?Bmt@vktjLq4;)O!rrly=c*rwTwMJFd0I57`hgkc", + "?=nyI4RZf9W$6DCWugmf&)wk^tWH17owj=#PGH7Xv-", + "?9$jnjwDlkOE+BFNR9YXEmBpO;rqEw=e2IR-", + "8^(W;8ma?M3JVd($2T>IW+0tk|Gm8>ftukRQ9J8k3brzqMnVyjsLI-CKneFa)Lxvp_a<Ck", + "QEd#(pMA^rr}rBNElGA=*!M)puBdoErR9{kWL@w=svMc6eZ^-", + "(vQZrV<u^PY#nOIUDJ8%A&;BUVlY9=;@i2j2J1_`P>q40f}0J3VVoWL5rox`Kptivcp}o5", + "xA^@>qNI%?zo=Yj4AMV?kbAA)j(1%)+Pp)bSn+7Yk`M{oE}L-Z!G6<Dgq&*(C-", + "mFJfbEGDH5M^vBr65rcnsx*~|Em_GeU#B)(+T!|MG-nxj0@IPbp-nHejH3~>OMr5G+hp)$", + "3Lg{ono{4cN>Vr&>L4kXH;_VnBL5U!LgzqE%P7QQ*<E!guRW2SE@ayq@)G2nXqA2tGoQIg", + "c6>tue}O`3(TZ0`aKn&~8trOQ-rBXCp)f@P6RMO4l0+;b|5-", + "pk9_ryNh}Zc*v%mvz_#yd<xXt%~gT90dn4e{Ac<baL-", + ")Y{L7&5G($I$>6fjB0g9{MmMnu8bG%#C~ugXK^S^k@?ab#O|aE>dDTt4s4n69(~@t~!wni", + "V%g<uWQat_i6>7khFx~I*4>Y|V$4j5%KPF*-", + "FyKIi@!Ho&x8QQsksYt8)D+W)Ni!=G`ogSu^vLL-", + "l#7A7=iIAKL2SuZk9F}NfNk86VI)9WZE?%2wC-yaF~z#Qsq)LH0|_D8^5fU8X%GeQ4TB>R", + "-dlziA&tZe&1ada208!$nk`7bOFO2S00G<w{Sp8G{cR_IvBYQl0ssI200dcD" ], "America/Los_Angeles": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0qH3OkDsf7KxBg5R*;z{h&-RlhRYu$%jt%!jv+I", + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0q%JPh9{i7KxBg5R*;#4G>H)lhRYu$%jt%!jv+I", "JxhE=%W1?wYb!37Rb?(rgwFIAQI{L#8r*zy!$TMtER_1(vn(Zix^{AVB1(jwr$iL6h0Z!2", "8Gb~UW@0~e512{Z%8}Qzdnjl~wJ1{c2>`Z@1A~t&lyL{p{eM{5)QGf7Mo5FW9==mlyXJt2", - "UwpntR7H0eSq!(aYq#aqUz&RM*tvuMI)AsM?K3-dV3-TT{t)!Iy#JTo=tXkzAM9~j2YbiO", - "ls3(H8Dc>Y|D1aqL51vjLbpYG;GvGTQB4bXuJ%mA;(B4eUpu$$@zv2vVcq-Y)VKbzp^tei", - "uzy}R{Luv<C;_cPe*n$Z<jeC9ogWF9=1mvvUYXS>DjpuVb`79O+CBmg{Wx!bvx$eu4zRE&", - "PehMb=&G<9$>iZ|bFE)0=4I?KLFGBC0I(0_svgw0%FiMsT%koo*!nEYc6GY@QnU}&4Isg;", - "l=|khi(!VaiSE2=Ny`&&tpi~~;{$u<GHlsr3Ze!iYsU205RFKsLnrXwOL?Mq08xffgS{6h", - "E|figx+&N%wbO}re@|}$l;g_6J-Wl%j|qev8A<T?NJ)`;2neGi_DHE4ET*W!c*ggPAgU+L", - "E9=bH7;maCUikw^R)UM;TdVvNkQ;FGgN=yQER`SZ1nOgPXr0LCebLety&}kVdmVmB=8eSg", - "td!1%p=a2wooIL!Da}OPXvKBfRo?YxqS>N}%f|7mBhAy;<Er2&_LfND#qXN~Mkgf!@4VFA", - "Hr%$c)wrKA2cJYWK2>s3YT^sy!$eG~?`9mNJC9@4Bac_p^BZh)Yd_rWW5qh-?tKY(>5VHO", - "L*iT8P@wCavLj^yYbnDR+4ukhS+xPrpl)iqB?u)bj9a2aW==g6G3lCJd>(+Blf<d4CF%7u", - "tlBUDki}J-!_Dy}5S(MrxSXy~$Z+hgH3P^<<w7D72L7I-R%H3(xm&q_DXxkp$owLTS6Wzk", - "hc3nn;laROa3)6hl&gH#)2Lif8fZe$@CdeJ-Zn&*>r)~^40F4f>cRZ^UF;RibfZ>0m73hR", - "C{$vTfC(STN`g7(B<=Z2556{}0`?p&|Akkst!4Xy4OT;A@c$XTUI3FRRjy*KA7uC56FD)z", - "^X{WV*sr(w!c$W357o!&eLO2wTDNOyw@gf(&R<<LF_3URI4=Ei`-%dM3T66j#9!aG7&b_@", - "g1-9vo?DzXZ5vGaf~w__p_@_X?OdvQ_r5bvy2hpESTf+{p?jL+!~!{g8-<-5$@d8EZV&-5", - "@a|;^1gB*R-~{EHFA-td_G2bt;~Y}>t;=-Tu1TV{>%8ZVATC9tjD8|(&`$9YHvZ9bVe#>w", - "|8c;Tg|xE&)`*}LwM*E}q}q8^Qja%p`_U)*5DdLI9O@!e=3jFjOCrCq28b_bb;s>%D#iJB", - "CWJi{JH!Js;6nfayos$kq^OEX00HO-lokL0!mqm{vBYQl0ssI200dcD" + "UwpntR7H0eSq!(aYq#aqUz&RM*tvuMI)AsM?K3-dV3-", + "TT{t)!Iy#JTo=tXkzAM9~j2YbiOls3(H8Dc>Y|D1aqL51vjLbpYG;GvGTQB4bXuJ%mA;(B", + "4eUpu$$@zv2vVcq-", + "Y)VKbzp^teiuzy}R{Luv<C;_cPe*n$Z<jeC9ogWF9=1mvvUYXS>DjpuVb`79O+CBmg{Wx!", + "bvx$eu4zRE&PehMb=&G<9$>iZ|bFE)0=4I?KLFGBC0I(0_svgw0%FiMsT%koo*!nEYc6GY", + "@QnU}&4Isg;l=|khi(!VaiSE2=Ny`&&tpi~~;{$u<GHlsr3Ze!iYsU205RFKsLnrXwOL?M", + "q08xffgS{6hE|figx+&N%wbO}re@|}$l;g_6J-", + "Wl%j|qev8A<T?NJ)`;2neGi@^_$pxs;>M<D!I{tC-j+T1~*cwYttg9!+Q#-", + "3v6Saj3h8^~MB$h|*(;kAscyJKINq{Cf5mX^-&hWdY!FT=0og-vvZbyAQtkOs7Q$E{N_AV", + "!!c1+D7Ub{;^)2(>iozmmC;M)^ZwTGGtj|3E=aVrD5Bqa^;RV?wWs=hsohk2ql1XcqaOW|", + "E4urOCR0a_;Id)cJ-GU5w3iJ10Aox!FH|8SHoiD_{JMEEOV0O?MDsDaI;Y>v=$rgN_q~t`", + ";bL0p0cr+3oR<~L*q!A1N=YxYRoqaQo%ua#07hqE;U_X@B)L3Jd;2oN%<UMR&=A0TqSiEB", + "wgSrE^0emfRx6XBw90Y7S-{?+qA5<Lkx|CXym1<j0It$``e-", + "X+>}66Gz+0zO^<`*Jt_si5v;Qg-", + "3q})ae)#%Dl>20mc9;6%A4(VObs;0JpQAGD7ADLJ?<x`z`b)-", + "OhP%tJ&2xIc5Yafu_9A(Mj>Rqiv#V5ZljDomsklGi_^8gtLkmRF>EstlBz)cI_>MG*?Z%S", + "T;72Q8^Ku7t$MI_A1{5SEE>mII;1T8kfJf_FgrXNwx!AelhM`I@+>J+gg!uCyW&Vjnd0r~", + "xZpKPsHdS4@$h%w6Eq6>tdfnmQLWvk`|e2>DM-E4Qm9Nc-", + "(V_Gh@)x^Nj3H9p`fLm1IA_eaBVtRg`l1J@5pcFi$-", + "31XWMxJ!;}xqC^I};&9=Az*&VH*lfN0M|Gx-9!ypV67!-KSwt=VI-*jej4FC~WiMTU+-", + "L<2+d_ew|{n~!VJuGlSJ0d_=`@?_jC3h)r_?|J_;aJ|`U^>F6N?3pcY069b8yy#(^>pP8L", + "*@Vg?IIMosq$u-00HX=q!s`G%_Rg?vBYQl0ssI200dcD" ], "America/Santiago": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0fRZ<6QtM7KxBg84(fsEAUJ$J{f-TXlPEUec5Ee", - "n+hsD4lC(QYax=JdSpoyje8%VM`GW}<Unz6IOY4=y66tfqG2X4E8xIJQ(~?r{`L~T!sI~o", - "VBl7Ao!R1A76Y8P6Y<TfwVHf@sl@S-D4OuAy5mq0MKJZ>{bJ8@y$A8O&*$pw{(f~Os#}2w", - "eX6^Rgi$IT%n^V^85L>$_c7{cB^#ogV=rHBJGiz-RQNFGK?gdPi|q)j`&8)}KJ{qo6dixa", - "9@yYyVg+%lo0nO+Tw0-w2hJ%mafy<Co(;L+24CYl&?rN0mrh90nxG?%1&Ed@za`Yd>WL)|", - ")<o0dZL-*?RFtH7dAv%G*O%l?qvq!0F5C?K#_ZoT{P$77IMoj3&8w3f&n36zquu~s`s0T)", - ";>?W6Bi%FWuGPA1Dru$XR4SZANsAthU2EoKH<MU4wYvUTlZGcLIDR+hSik>F6oEtKq`rwP", - "(VNegnI_NI%;ma$)wj{k!@KFB30Yo)IOr<QX7IQ@TBq9d;e3QAtYU?$PS-WoaiqwFrg4PR", - "A->l>)$)D|+(5h&+%2vuwGuy^@S8FT^s21V5};>VA9Iu;?8bHz#r<;JtfZDI1(FT@edh0#", - "MYW$A1qkMGIwTZqqdYNE3gl#zp&NbL9Mp=voqN|;?gqR&4$)1`znddtEyuKS*^nMMD=0^>", - "7^z6-C4P67UWOXuMBubP>j6i~03aR@jD^-Y`JSYu#Yp0P8dLLJ0QOPE8=BoiuRX59YW7xg", - "WiexjHX%&0?`ZQCdxCdL^qd1v@kOjQKaWo2Y1++~LcA%FTq?5o<?(jL(_Uo}I}k_Fwflcr", - "aovwSR_(ILA6li<iBLPQ0#rEet;W-*54kj#sZEGK*tAF{)HNkn#&Hc5`#eaRF;N#$<xQU?", - "E%zm?2+b5Ho>%}fX1-RIvlB)1#iTNomGnUL=nM!>Ix|AGtON7!F1O?53kqlC2o-`ZGw*+s", - "NM$^9znsIJMwlgscE`|O3|;BRgsQMYm~`uv+nvuv`nigRa}X=BX=A5Sw$)WEklF7&c>_~$", - "zJ(m--bqXgiN^w-U=BJH9C0Qro(x90zo@rK;&TJ$nI@&k$ORgOb2<MjjIhYfr;pFUGdMd!", - "0d&bOvyq3AZPCez8E(XSg2hBu2A&^k?w|1u8v3JE>s%gWbc}ok_27)Eoku~Fq|B-Ps+4J_", - "HPJMLJ2^_)cOU$p&3kNAlrV!)%~6r$BJ>OOi~=-<6byle{?zd4J{NG}o8tw|+#ZNLcpNwk", - "TuPE~sbJB8_RZb2DopStO+Wwux~F#S59zm%00I98;S&G=b(j+6vBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0e+L++6@F7KxBg84(fsEAUJ$9Yj;p>Mq3>*@-", + "8>razI(EFyOtYzTyCY`3kVX~k`hSJt^$bT@V;iGRbT`JI3V)lBnui#lA$wIsfE8sL=RFVi", + "Wi5>;Y=+h5(#B8hW33CV<Q;A#rKAP&WQAy#{Hgd}k5cfcABuYPC#AID{sCG^k7cV;Yjn{S", + "|8$i(c-", + "ZWn+h)T(*sa4gX}q{a%>CYO92<z+UyE(W(N=OBKTA!5FCM+4etR}Gx{Khjr_hfVM-", + "3bY_3-f(4kMdWkgjQjaFM1%?zB^dnmPD^*OEjG@|L4T9oM==J-", + "1~cwbTkO+{<rZ1j%y$A#;`~jj_5>MtE<w1^%V}&!W~^`U#G#Kclvxg2eSK@Sb_pe)d8JOq", + "iIv8N?HvCOAa(Pe)%y{uRZ=iSffMAb29m~K3V!5$(+5c4`<&%}YBXxa{Nmro^{EpwXUg(M", + "d=g45)b1lm^o9O|j=$7W0%Fg!1vvZpZsS3gq(aYGRPC6r&`5zc<D8jH3uj3*Twj>mXQtd@", + "E+3y)$%o~XozOC|QgFl*-mp9+(`s0w4O4a$v!xt`G&ZI1uE4c`JE-t5WW%1*91J-", + "tr^_>U@@l^R_i@%gJ)q{kYX|w-", + "m{DbN=Z+Zey_(<=ZlU4e**~fkShDtX&9_W<ytT83B=B(s`~GrFf60my*fRSlCwvb~u-", + "3SYP<jcj2q)<&>>qj>RuJZ-ko&-nY}Eq_?SFX8N<9wT-TH*xbF0XT;L+siI1gPQrnKc|85", + "UZaq6@7JAVeu%)Aa6I>6D;F*N)|f6jhs01q_UU%gc_Ek#>SbTrf6i;OsAQ>8&urTeX|Ier", + "uSV{o||MjbXV?)AHzh1+v~odHV<_+-", + "M0v=QR6~y%&K00{%grZ=+5)JNlFg!9Q}2rv{$OC*D{_yiUd$SL!S)f@K#pe<#CBb&}BH0p", + "%w(SzGJjGX`q+ybM!e4GEP>b&S_4lnbBR!*5>ZIxYP?QK2DIny}eL_od7Ll|WdneS(sbh~", + "!}|r_VlzIOB|lsf+rf*<iF2;5mq&ws+~(vXucW*o<B(-B;$$S+_(`@_xgEw=t_P_S=K-", + "2*4@GPK8pEDecQUL_<_<IfI`6dpUo@#J|q(HK=)fN2`##&}B&C<HKnv-Zo68>B~wqYWzu*", + "k-", + "19B1stj0gO@Kd^97k>cVnNvEEaMwZ6=ObszLNnyDGMW0?9>PhVq$r$BCx^ZdJ#fO^fC1JG", + "oW>FS5oC!pr7=y}O@ecL6T+R$E20#GvlwVfswl?qnCEe|@!hI*Ooyk8~vfN}h@~NGp9$00", + "H<1(-Qyy=a@C3vBYQl0ssI200dcD" ], "Asia/Tokyo": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j-~luMgIxeB7KxBg5R*;y?l4Rl4neXH3cv!OtfK@h", - "KZzauI)S!FSDREPhhBS6Fb$&Vv#7%;?Te|>pF^0HBr&z_Tk<%vMW_QqjevRZOp8XVFgP<8", - "TkT#`9H&0Ua;gT1#rZLV0HqbAKK;_z@nO;6t0L<i8TZ+%T<;ci2bYSG1u!mUSO5S3XcbN8", - "dIxbZ00Ex?wE_SDJu@vkvBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j-", + "~luMgIxeB7KxBg5R*;y?l4Rl4neXH3cv!OtfK@hKZzauI)S!FSDREPhhBS6Fb$&Vv#7%;?", + "Te|>pF^0HBr&z_Tk<%vMW_QqjevRZOp8XVFgP<8TkT#`9H&0Ua;gT1#rZLV0HqbAKK;_z@", + "nO;6t0L<i8TZ+%T<;ci2bYSG1u!mUSO5S3XcbN8dIxbZ00Ex?wE_SDJu@vkvBYQl0ssI20", + "0dcD" ], "Australia/Sydney": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0T)o7+nA=7KxBg5R*_t6jS5T`_Ull(nK1_YY;k%", - ";_YdTuU3*!K)eKg@^kzjAtbo@Jd|KGai=Q%%sX5FI?*?LG!|m9cKH5~IEwI=PAr_Yc}w35", - ">}hOdk<>TdUa07R(LPI6@!GU$ty4=mwqHG-XVe*n(Yvgdlr+FqIU18!osi)48t~eWX8)&L", - "G)Ud^0zz@*AF+2r7E}N<P$kOfo*88g)_bOO?7N1Jr|HJyg+HXc7f4}?%Dur3w|~JU?<x4K", - "%RRC~q_D87;UyN{nLRu!fEqKeRR*U$vs>f9Y72K~o-T%}D&z%}#7g<qim`EbfhF7ntyAiP", - "%LFNc&!$@Kv)Olyf&Y9%(#SkM+%yI}S%b+@ZM2dH7DpmndGMIda<(`#E9q|?H(HzClx+l;", - "M?IEz1eF}r?}ay!V9?9rKD^-ayjE@wUMD$2kC!iwH`n=eVrJPmJyNKaW`LdJ68&u;2nF1K", - "kZjKCY_A<>2br?oH6ZiYH^%>J3D)TPKV(JY*bwjuw5=DsPB@~CrR<E_U_fJTF9ufU%!cXK", - "_4uM#!%%Q1e1G~{E}~vGVE0{Kxecm^NjtJM`c8EFHFTiUIVl@YUD8F+s!u8jz~6hte@oa|", - "qayb*^Lwd(etNmBro;aXQjkY8g(*`_JQ0%{V3QP2l!GGQ7D+v&k_PK0F(?f{GziU5>OZeN", - "x>A*H&CHrWt0`EP`m!F%waepl#|w#&`XgVc?~2M3uw$fGX~tf_Il!q#Aa<*8xlzQ2+7r6Z", - "^;Laa9F(WB_O&Dy2r>~@kSi16W{=6+i5GV=Uq~KX*~&HUN4oz7*O(gXIr}sDVcD`Ikgw#|", - "50ssal8s)Qy;?YGCf;*UKKKN!T4!Kqy_G;7<gSrPK{)5#a>PfQapugqvVBKy12v3TVH^L2", - "0?#5*VP~MOYfe$h`*L!7@tiW|_^X1N%<}`7YahiUYtMu5XwmOf3?dr+@zXHwW`z}ZDqZlT", - "<2Cs(<1%M!i6o&VK89BY0J7HPIo;O62s=|IbV^@y$N&#<x=a876<(U>=>i^F00FcHoDl#3", - "Mdv&xvBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0TQa5M2N&7KxBg5R*_t3)o}P`_Ull(nK1~U=~g{", + "!2#v7ta-VPM|>+w;XP~5#XzS!mmq>y(@${PQsHdkBYiJixTuCQ2N?55>HhxKTEufgeVl}_", + "Sq_FUIXFF$kI6!-", + "eKVzudw1Zyg8;a%MynCz&_3Cl@%Zs*_JRo#I#Ss92V)!~{AwVung!|wK?4JFyFv#=nfhNI", + "6Czr|3VjINV7V6#eFr=Gl1UDdL9MQRWZ`RiZET+f<B?psO04A!^T@|OjD(g9%6r^uKWL~*", + "l5l((#kszU!MR&R^KmhB+uQG;V@@lt4iky54!7C3s3sgfut6UfX5na|U#Q8$>l#=kxZ_-", + "G@=#VCQEvCZVdj9;e?rY8ynpo&34D<xf3gdy0mso_&ACxT<X@=iK)(!)Cf=UJXS@mJ>Pa3", + "KI_Sc_0#?r^44F}Rzb_ChM7PPrq3@FkqqjWqgvOzPq+vkb;DT&2YMC|tC3lu6Ihz2prrFP", + "vOU@6I3$XU@68kFFWx8fx?jt@frXW`;AZso*plI73>*wENVoc+2cm`jgoe6(B`w`{Bdx<i", + "@MbN&WNDIQhD$&B-", + "uG<$!*}1d++*d~BtG=}tp$n^wQ7tVUh5HXx%pYRBr8eErtbe5x3d1_@!5Dfbr?|~LLM#@T", + "Jp{TC>VOWD1rqV<x%ZP)Pc1Wb+mhO{S8(-", + "3ndm1jWw?3!z_VRO<>TCN+Y4kRvHLYXlr)vU4G7S$p~Ia_n|G>=3N5dDB8cS6IGd-ckfc7", + "8#^71HtN_BO2#F%&%Ll+IhR1DlEUG@+#_Yl8AKa1US?{&+yOwA=WA=!z-", + "B9t2>Tn9Wu2*8Ydrbage(I4dkD_vcP(|c-", + "LhGRkSn{W*nk?RJQN!j1RSZ}L6e<&UGMisk>nLH5JiLNgOSC7c&Mn1+Pit*Gz;s=M?_q!v", + "DZ@dJctlzl2>W(rvs{(CERM)RT0xuqDAl{)$*ztEhe=?|;3u&!6O1c88W}SFHDBBHh%rrh", + "U6=f6kjYt!N19xk*s_9IpbeS;(cPoTPX!vr00FE9ju8L=r}(KdvBYQl0ssI200dcD" ], "Europe/Dublin": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0>b$_+0=h7KxBg5R*;&J77#T_U2R5sleVWFDmK~", - "Kzj5oh@`<njquRZ&tJIS(cXp1>QKHvW^6V{jU-w>qg1tSt0c^vh;?qAqA0%t?;#S~6U8Qi", - "v&f1s9IH#g$m1k1a#3+lylw4mwT4QnEUUQdwg+xnEcBlgu31bAVabn41OMZVLGz6NDwG%X", - "uQar!b>GI{qSahE`AG}$kRWbuI~JCt;38)Xwbb~Qggs55t+MAHIxgDxzTJ;2xXx99+qCy4", - "45kC#v_l8fx|G&jlVvaciR<-wwf22l%4(t@S6tnX39#_K(4S0fu$FUs$isu<UOJYm|4)2i", - "aEpsajn@}B#rnY=Cg_TXsm-A)*adXV&$klNTn3n{XXlaquu}6m{k%oRmY0Yyhlj*<W{D5m", - "22}OiqnwHT!tnK`wPqx?wiF%v{ipTrOkcJ5P@7OC4(-l`*&SB$Wd4Vf8gn?>d<i@%mP*e*", - "ttDj`9M1;9$YV@dhT)DVcwdq(Ly~KDm_&KL?{_mFwwYtJqRZBk)i1FVQy!40w_KyAg?hIA", - "=_{(3#S0eWsF8f%_4Zza$4@$lSmov+Huyn$vP^zJ|8-<C3#q#0kEs9cNg^xUR(m?wEWt-D", - "GctAh2nIo~fz%$m$I41=b_WuJ6M9g#A9_Epwqw{d0B|vzmg#_y<=_>9IKzCXB<o`d)**5V", - "6g!<<Jw1n5TrN-$)aYz4cLsTmpsUf-6L7ix+kk>78NkARYq@9Dc0TGkhz);NtM_SSzEffN", - "l{2^*CKGdp52h!52A)6q9fUSltXF{T*Ehc9Q7u8!W7pE(Fv$D$cKUAt6wY=DA1mGgxC*VX", - "q_If3G#FY6-Voj`fIKk`0}Cc72_SD{v>468LV{pyBI33^p0E?}RwDA6Pkq--C~0jF&Z@Pv", - "!dx_1SN_)jwz@P$(oK%P!Tk9?fRjK88yxhxlcFtTjjZ$DYssSsa#ufYrR+}}nKS+r384o~", - "!Uw$nwTbF~qgRsgr0N#d@KIinx%<pnyQ!|>hQB(SJyjJtDtIy(%mDm}ZBGN}dV6K~om|=U", - "VGkbciQ=^$_14|gT21!YQ)@y*Rd0i_lS6gtPBE9+ah%WIJPwzUTjIr+J1XckkmA!6WE16%", - "CVAl{Dn&-)=G$Bjh?bh0$Xt1UDcgXJjXzzojuw0>paV~?Sa`VN3FysqF<S*L0RYSAY3jt(", - "8wCD04RfyEcP(RNT%x7k(7m-9H3{zuQ`RZy-Rz%*&dldDVFF+TwSAPO1wRX^5W5@xJ9{vW", - "w?rc^NH({%Ie<rxKqSVy!Le-_`U&@W_(D+>xTzfKVAu*ucq#+m=|KSSMvp_#@-lwd+q*ue", - "FQ^5<D+|jLr?k{O39i8AX2Qb^zi9A<7XD1y!-W2|0Hk8JVkN;gl><|<0R-u4qYMbRqzSn&", - "Q7jSuvc%b+EZc%>nI(+&0Tl1Y>a6v4`uNFD-7$QrhHgS7Wnv~rDgfH;rQw3+m`LJxoM4v#", - "gK@?|B{RHJ*VxZgk#!p<_&-sjxOda0YaiJ1UnG41VPv(Et%ElzKRMcO$AfgU+Xnwg5p2_+", - "NrnZ1WfEj^fmHd^sx@%JWKkh#zaK0ox%rdP)zUmGZZnqmZ_9L=%6R8ibJH0bOT$AGhDo6{", - "fJ?;_U;D|^>5by2ul@i4Zf()InfFN}00EQ=q#FPL>RM>svBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0>b$_gw%g7KxBg5R*;&J77#T_U2R5sleVWFDmK~", + "Kzj5oh@`<njquRZ&tJIS(cXp1>QKHvW^6V{jU-", + "w>qg1tSt0c^vh;?qAqA0%t?;#S~6U8Qiv&f1s9IH#g$m1k1a#3+lylw4mwT4QnEUUQdwg+", + "xnEcBlgu31bAVabn41OMZVLGz6NDwG%XuQar!b>GI{qSahE`AG}$kRWbuI~JCt;38)Xwbb", + "~Qggs55t+MAHIxgDxzTJ;2xXx99+qCy445kC#v_l8fx|G&jlVvaciR<-", + "wwf22l%4(t@S6tnX39#_K(4S0fu$FUs$isu<UOJYm|4)2iaEpsajn@}B#rnY=Cg_TXsm-", + "A)*adXV&$klNTn3n{XXlaquu}6m{k%oRmY0Yyhlj*<W{D5m22}OiqnwHT!tnK`wPqx?wiF", + "%v{ipTrOkcJ5P@7OC4(-", + "l`*&SB$Wd4Vf8gn?>d<i@%mP*e*ttDj`9M1;9$YV@dhT)DVcwdq(Ly~KDm_&KL?{_mFwwY", + "tJqRZBk)i1FVQy!40w_KyAg?hIA=_{(3#S0eWsF8f%_4Zza$4@$lSmov+Huyn$vP^zJ|8-", + "<C3#q#0kEs9cNg^xUR(m?wEWt-DGctAh2nIo~fz%$m$I41=b_WuJ6M9g#A9_Epwqw{d0B|", + "vzmg#_y<=_>9IKzCXB<o`d)**5V6g!<<Jw1n5TrN-$)aYz4cLsTmpsUf-", + "6L7ix+kk>78NkARYq@9Dc0TGkhz);NtM_SSzEffNl{2^*CKGdp52h!52A)6q9fUSltXF{T", + "*Ehc9Q7u8!W7pE(Fv$D$cKUAt6wY=DA1mGgxC*VXq_If3G#FY6-", + "Voj`fIKk`0}Cc72_SD{v>468LV{pyBI33^p0E?}RwDA6Pkq--C~0jF&Z@Pv!dx_1SN_)jw", + "z@P$(oK%P!Tk9?fRjK88yxhxlcFtTjjZ$DYssSsa#ufYrR+}}nKS+r384o~!Uw$nwTbF~q", + "gRsgr0N#d@KIinx%<pnyQ!|>hQB(SJyjJtDtIy(%mDm}ZBGN}dV6K~om|=UVGkbciQ=^$_", + "14|gT21!YQ)@y*Rd0i_lS6gtPBE9+ah%WIJPwzUTjIr+J1XckkmA!6WE16%CVAl{Dj@)nt", + "QW>5WCgG;uYjCg(j>qCs(*}h9<Z8uh9!SSPmJ9Us;ag{DE^LB{a>IWV8w>LXsNq+C>vLWc", + ">tZt7asixk*XDd^+o!O=O52B7aPqt&HfgmRCd4-+ky?P-", + "XP?5Np6dxH29G;c3@torNWCs!ufT_DK<~j-", + "UgqAdf5G4ZdP`bECDkw8*?qvrtnMfoJT^Wq|8_~4;n!EAt=*dv)-", + "0yF8uKXAiZ~3d|7Z>ZO|t~YD2@;`6Qg{xlf8Q&;*xB-Ys_R2Cp{y((HBw7kN@@CtfA<<$B", + "fGc2BhK{XBpaQiJGWmO!j9XN7n0YhjD8vjw0{?{0zZm5js?lNS*8*{rU&d|`Rl_i(p2n<E", + "2E*;E@{_pkawrja2!Gd<d7B3gss7z!RY?4jLVEtA|Zd9xtHrRH@!`4#&7dlz(EmqJ50R7o", + "WFfxIQ=*$MQ;FXMyzYE7tuZ8vWD!}Q(QFk)FlkhmB%|FGo4d;`{0trwc>Hf}VB&&P+m6k^", + "y|9Wu}iApF2OdyoJC2VV0^9?>qd00EN<q#FPLQfh6$vBYQl0ssI200dcD" ], "Europe/Lisbon": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0=rf*IfWA7KxBg5R*;*X|PN+G3LqthM?xgkNUN_", - ")gCt1Sc%YT6^TTomk4yVHXeyvQj8}l<;q&s7K}#Vnc8lII1?)AHh$*>OKUU4S;*h>v*ep0", - "xTi1cK2{aY*|2D*-~K<;-{_W+r@NvZ7-|NZv($ek_C%VfP0xjWeZP#CPXD`IKkakjh(kUd", - "&H)m;^Q(jGjIyiyrcUMtOP)u3A>sw6ux;Bmp3x$4QvQKMx5TrCx_!$srWQuXNs&`9=^IY1", - "yc&C31!sQh7P=Mk*#6x8Z@5^%ehR8UW<EvzdWer9z;R6PrdUaWab3G>$OWw0KMw}P1ycI^", - "4eh12oBUOV?S>n*d!+EM@>x#9PZD12iD=zaC;7`8dTfkU_6d}OZvSFSbGgXeKw}XyX@D=(", - ")D0!^DBGr8pXWBT$S-yhLP>Z3ys^VW<kSQr?{jhl<+{Fki;mTI=&Stgy$rttN?ulQM$lDr", - "G7))C7Dx=J6V-e^(Qk|r;f~TvIw1KqRIC{8f^jPy#blstV{-&2a}ZJe!Zr2c_R4NT)L@bs", - "+gRRm6Wn)VWVNHeK*TEV=f#2KZqu%y?mTx#EfRiK0)TG7$$~=LGxx@0D|lS2up|oCON{YQ", - "oN5-H$!_n-Kx2*=RO!epEX>3}RQ6{NGGVJG6vf*MH93vvNW6yLjie1;{4tVhg-KnSf|G`!", - "Z;j$7gJ1ows~RD=@n7I6aFd8rOR_7Y?E-$clI%1o5gA@O!KPa^(8^iFFeFykI-+z>E$mvp", - "E_h`vbHPjqkLs`Dn-0FV`R@z|h!S(Lb;M&|Exr<u8#s-T(>!biY`%bfp$6`hK;GDhdP|^Q", - "*Ty*}1d41K>H2B{jrjE9aFK>yAQJBX9CD%-384S;0fw`PlprHGS`^b$oS-`I4VH7ji8ou-", - "g|060jfb1XcxiInT0oO<S+<vh^)XY;lr@|IeXj}%k;}|kSlDGaYidk^zB|gEYaet~F%QYd", - "f7pbnQKLZ0o7=kso86doS;J@aQ>oeR7#%e5Ug5#KW)nV<Rc;|LjUDdhk8*dYJQwYN?hzH%", - "0<XB$!(rpf2nxaL22M`L4pKx>SRvLHNe$SQHM@2)`S9L7>RL@<XAlxVQfb2=%lcu!h+Um0", - "Q+Z=itevTFy}-Jl<g5crK55BF`VsoPH~qP3QrG%YtrD#s{=gA7p)QI<i=EwY(cel8`B=#u", - "Yq<K;4T(QBF_GvrYueSk*}gfrCSg22+YH-1N<WYkp|DA-P-&va<Xu<}^yafJKlzezB-lS{", - "a++P_^gYmgrc9FO-K3s~`jAcqVV!k?NV2IFV^86`cr>Qx%fmm7?3u7P5TywFQ}C@S(pq}|", - "eLPT{C^{<0Q?uU&kSVd%!~8q3;Z0s3OqzF`$HRkePL5Ywgiwn{R(<RY8ut&RJ;$?J*w*n)", - ">zi+jmOBFrVpW;)@UsU#%$8BcV#h@}m$#!Fglo&bwb78aYqOG_W7h{eb(+39&-mk4EIXq_", - "_`30=8sfA3=!3TO_TyS5X22~?6nKngZ|bq=grdq=9X)3xAkA42L!~rmS)n3w-~;lgz%Fhn", - "(?rXdp2ho~9?wmVs2JwVt~?@FVD%`tN69{(i3oQa;O0<Hp#T5?$WIy3h`IlL00Hv}jT-;}", - "Z2tpNvBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0?wE>|FpV7KxBg5R*;+c_2(RlxFoAjepiN+t(&A", + "khpF;7sO(r>4o7M4zZVa$XY~v@-", + "@YI68ej+V4yBoGpi5ZYu;Zw>N;+Vkw)1TIVA4;Vn*JV=%f`o+fC9=H@gz8U6N-", + "<zlQBNWwuXloIY|=>M+jj4KAFBq5|dk<~RQE?jJV`tG;f@gAn7I{P&H39;;isJ!fMa`+wG", + "KkWXbi?P7&ivzm}BJ9guJ&D1=Ci_?iEC=T+}Ht)wPz7a<P1u#Hd12~xVtoKNVZZ9bK!~Gf", + ";7HSY!7IC}gsZ4-", + "I$jT1i`pR(J9#tXon~s<`_^d}&`qr^@i)SF`Bb~U?H>zBV$vs`Fg0TYba5j@iBgmJ}w{Wg", + "C;WaVQ5{ZjAIYY-lC8|yfnqplNF0_6r6Jo}h*-", + "^e6n7IHY9#^nyJM($bLr;XKyoo4e=k4E_rXAXU|8;BGkQ^kNAtK@OYtPw+AVo@wAk+F{Xd", + "YfNlG<<-FnlW4;LdIej=F0WFr~-c^-", + "M)7hP!$diHGAim;v4<LV)m{cX4!QE}&4=e0*`q#JM6ECR9=km919W`%;z(u&c4)$k#`^5Q", + "%<auc|-%@#^72gOa!BcLl_-", + ";@{3;XMzp%%Z(_TQo{SP(u0)+V(>c$Ui^z<`A!+F8RhS5DX<Qkb`v1Ppx<w)pQ`Oe9w2z$", + "W;R3APa$u$7+V=T0vX6Bq+}~Oi`T<CxP?En5_AWCA+WOr6Ba&T8?i(2iuLXc?c0Eb0#8fx", + "0;z)Qdw{&iu1p_}NcXrEZj<UU?o^>aZomO|PHR8B%eNWlI^Y;%XH23*BQ9Pv<U}>!0dNOS", + "JW<Ev&&4jcJ|ItzHY*}vkh#@p?GI~Z@92UqgCTvtS*M+R6>;D6iM<TKxRt(MO)fK0B`f-", + "Tgh%d%!X%ul%RzqJ&<cgV@U9}77Km>}OHVD9S;=_E<kAo67wo+uzcCI2-", + ">GP=j^CP6mQ~WcEd%i!wnK!|`afKPHZ{nSFK{L!7$MM299!v3kGuq;oa;+;@@n1r@0<Jpc", + "%OKHC*qZY)V7YMh$GJ7uZJ*pknb#4Lndxc5t*p~=j{8%jTcs@J`sWW0;gyRp=j6{m!9jg8", + "yBY-uv0ppo?(LlG%MXywQB)0kk7!saH~{t8ok=ap8ckC*S;vkAK<RzcLxv+K_UDp%n=;eQ", + "$32d2IQTOvm&n1x4gxS+SH)m=#|D9u~O6QLYUFTM@z@V2^Z*27`WQlTcSk<fG)JHRfF0un", + "`wvtDD^{B6fp60>Kc%yl18x$nR#Kzi@<EMdmds2!rvB-", + "%G=Qs8_PTjcEFU+5%TqHsrny=`4g%T<w?<?*L7vocihTo#Uf$}3PtSt59Gp?gp!2>?+E(y", + "7o2rS3FClOOT`Amt}UyGfYZ7QWYqqCA(t;kD}FGa+vi>Zi)j}a2lrvx_};$<>-", + "h&pt_ePq>W5KHZPr_P0CVzjF(&G-", + "bL>Xi>@Jv$b)=hLcP>(ngUOdeI5{4_W6pSrkv%rnFAW~Xq0%BpP=^5An)E2@X9`)$o<{(F", + "VhGYMIW)@T&B7JZ06+RhK~>g?V;J{)+)M6xch^XnnI^Q0TC;zLSj(LMJ&sOV*Qj&~gGAP}", + "&ujCT8Fj?*_GQ!H)<ip+T(TLY1KvvUUC&|zS0?)a81xs}-pb-", + ">00D>!#~T0u=fLlPvBYQl0ssI200dcD" ], "Europe/London": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0`|pJ6!-O7KxBg5R*;$9DqzW!kQs3DZt(=0_!m1", - "4wvE`6N%Vj#u6PS_3S?~(2)&xn8}2}3Wr#kG8n2!x8>$E$lF&~Y#_H6bu6(BiwblJ>;-Fs", - "gA$Y$*?=X)n1pFkKn}F~`>=4)+LLQk?L*P!bhAm0;`N~z3QbUIyVrm%kOZ(n1JJsm0pyb8", - "!GV{d*C!9KXv;4v<seWRpo=ZZxGf)-5Qsn$3dw`uhF)+6#mgUoNF-Y2jN73pVhdTs*p0`Z", - "AbnT1puEtudB{Nul>D4Q>-k#+x(!V5L@w5M>v2V5<gcLskF+p`aGTSn{sY8^@MUc;2o{&V", - "R!$180N}BtfYKS)i9w=!<~&l?1Cv^PWs!&a9{s(35^yqGU$72DKX|IkRtDblB>a`B>t(|B", - "|Fqr4^-{S*%Ep~ojUtx_CRbSQ(uFwu2=KH)Q@EBs@ZqRXn4mU;B!68;;IQs3Ub=n&UU%*m", - "k&zwD36&JSwsN(%k&x?H+tN^6)23c`I0=5^N_R0~1>tsFZ`^`3z~rXSXT&qcwa#n!%+Z#P", - "PG}(D^_CCILXnF|GKwabBh*xFS?4rwGo2vtJUwzrbv_$5PO+`?$l{H-jGB@X%S!OAhw;D4", - "XFycN3!XqQ&EorJOD3>~^U%Luw!jF<;6_q-f-S|6<EHry?%{@fuyH`_+D%uTA@g0$5e!Yi", - "P1vQuevyS;jE(-R>{cQDfZ2(4Xf1MMLr1=SA=MwVf2%Pp%VP;jn)|5Tf!-DbUGn%I-r<KG", - "4jJ(Y#L-fJUpUb$yNfvhX*iqWZoG7T*WUfE6iQD9_^EWqExH`rc&jJ<o^E8-mM10WrZ_Vv", - "xx9nj<vMlEt*KfP*pyth!c_AKnrKtQTACX08#{pioAFnDq!53+h*hO^f*yrWjg0u2pUcgv", - "UlpEZ9G_dlhlW1J^h@gTt7{KPL2mRal;1juJ3Q8-!GXO#IPzT4ciJ-nB+nkphssM}Q7IAT", - "pM}AT%y(J!78F?>kYaH7?$$O!t)wwClAisr3eUoeB^~T=U*_P~Y2*KdnO87>B!19sV=xZ5", - "yApq26RxgqA|*tmsvtL#OhcF(C<0EGWHP)BF<g*iSWicU6k1<Ps?BQ$IWg-#s2uF-qXgJ_", - "!H_mZIMx*L%&a*_6;_trMCULk0ZYM<hfJlYBddHwRyYUDu3!C_lJZWTQ?c-R&@9054pj0k", - "kQ{Xi{A$&)&b#^G*}8w^qE5i<@aDxaJQs2E$W)AIqUXO{gQ;U8|FA%BD~sORzq44)AntUu", - "QHBO{{Pi<EpK!$x4(~7w)la!dN=M@L_j};6|5G&QfuO~2?Q7996z)78fqW<D#8tKNV(*qc", - "mfA>l?h)_*7!{LoJiv%RsOs!q->n+DcV%9~B@Rb<ISu%16c5H-7zQIq+SuS+s<lQOWK5+C", - "d*>C_1G_1g6`Yd~8|%-=2l~oGN!~TVv2Bnk>7wW8L@^?vX$f3AiT)(4nrCuTm9%(XC6Nai", - "E(;}7&=YZagjAN$O-cN;1u{dTkElmB0GT$|Wa)QMmKrx<|LCJ9qlUoFsUbD^H^6_8(w<0{", - "ftj&O1~p_%lh5z;zNV&sP<T$*OgK)_0B#JDtXOkhC;Bo7h)#RUy;vBiVLN-T$*7t*t9@ey", - "3Woa&24QZ_z38BQ@A(A<(9n@%R?}B`7%w2wowt~UU;bAlqCzr(H$M5t==jGIqMqCsE=Jwa", - "$3P+3^&|~i28@=d_u6Cgthe(Lq(wxKpdSDL|7X6Un<nrt00Gwuz#ISo`BbmvvBYQl0ssI2", - "00dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j;0{j(Ib8rM7KxBg5R*;%EAUJ=!kQs3DZt(=0_!m1", + "4wvE`6N%Vj#u6PS_3S?~(2)&xn8}2}3Wr#kG8n2!x8>$E$lF&~Y#_H6bu6(BiwblJ>;-", + "FsgA$Y$*?=X)n1pFkKn}F~`>=4)+LLQk?L*P!bhAm0;`N~z3QbUIyVrm%kOZ(n1JJsm0py", + "b8!GV{d*C!9KXv;4v<seWRpo=ZZxGf)-5Qsn$3dw`uhF)+6#mgUoNF-", + "Y2jN73pVhdTs*p0`ZAbnT1puEtudB{Nul>D4Q>-", + "k#+x(!V5L@w5M>v2V5<gcLskF+p`aGTSn{sY8^@MUc;2o{&VR!$180N}BtfYKS)i9w=!<~", + "&l?1Cv^PWs!&a9{s(35^yqGU$72DKX|IkRtDblB>a`B>t(|B|Fqr4^-", + "{S*%Ep~ojUtx_CRbSQ(uFwu2=KH)Q@EBs@ZqRXn4mU;B!68;;IQs3Ub=n&UU%*mk&zwD36", + "&JSwsN(%k&x?H+tN^6)23c`I0=5^N_R0~1>tsFZ`^`3z~rXSXT&qcwa#n#k^5sFT7HKtyC", + "9A0oluNf^P4yk-d_|mUd;T0;~y@2Cu@Xd;<hk`=GfF)t3<(W;^;#vS*2CIM0}lIP!ER~kM", + "z)8{sshyiGGP5>IRT#++Y*Z6*0%M4`z`3a2vnHc-", + "B(#xp*94c8t_y=lV~#Q=Whn&p<+Qzs`pL<^`L`BrF9ohSDa^SnosMt{zpFXpUjqumClb$D", + "^}s!&5JM`)L?H!Gzj6q@G0mVG?P#xu;u<zZ1><E)+3E=(_l2Q};6M&`<X7b>1DMoWN$14T", + "b>^F1?&ymdJ4TS`!aAO1#Myz0fU6<#?jJoc&X-", + "z&$D#Zj!Dg3w*<XVS=jFmPAR!(5h?6II3@of1!~K^$-", + "QX2G2lXMyPJhkXLlU>*{JNc(J;D0DrI1K1-", + "iv3~i7vFT?5yqP3rSI@jsz*k!0bE*<fCU<^XircA9v4*(~nJ^>~Pkn+g>u6Z;Se-", + ")c$&;tI=8t;#10nr-)VFCx@^bf}Ak2a$g+MN&Pv7{W+wBYjvrBy)wwx-", + "|SlQynn<W$^Ik*J>=O3ULjr$jM*QQAezq5|DqO6<QT_YD!R$)!*RZ}#4L0{;;YiF!ta_vA", + "o_bRQz(yXVh(Pb?c@M0_Nw`OAh0wRSk&G;NwrYbla>3Zf+jql$4rQ2m|lPqGyA<>cV6bIA", + "o~*{`bgCh=A>WU}#b$t&5MPj$~|esT>8<kEOj;^~h1CXH8G(W#9e08Kd-", + "*F5|4A*&rbM;en?xL6l&Z{Ykm8CiF^r3y(3DvVoFpAb+ntAMvjr$pycbsU+9;c4roZ<eo^", + "PLSCW&pf@n2Q`ntKP;qNmw&SoHqbu1VHpCiJ*}hcmd((^642U>v-", + "C$_n!^iqI5;Q?X=YtG#wS0iS@Z+K+>Pw@;#vN~2NVaNcNiR~iPI$HEp0CZblbg!9944qJf", + "e^U%kyd74NW@4bR+8mK^RfSa}|2+8EsMDCnO<b%-", + "jeynUWspF(vCb3E!h#H}EYTD5FrIeRGbKg14?|O~2$j2xm;!0<!;WzH+-", + "i5d5tFbg7<Iby5Fk8J(*7&9_w84$GKMDrVHz;kCbn5G~;w8;xL!HKZvT=em^K46pU{o{_|", + "j^aXaZYS0#rN7ZS$)7F+7L39lWib5ukEMe<bXdIuFkbGR!az9hn%Ce>SZ@D)kcJx`Cx~hD", + "N7PV9xa~1y#{E$Hy#KX4zE=~k$7%Vm?00000LN&_Vg>>9w00Gqs&>R2&ZK8hovBYQl0ssI", + "200dcD" ], "Pacific/Kiritimati": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j-~jCaVO;<!7KxBg5R*{K!`A|q%C5j6({{dSEy5>+", - "NF2>iK{8KMUf+)<-)VxXbLxD(alL}N$AT-ogNbJSMMYeX+Z{jS)b8TK^PB=FxyBxzfmFto", - "eo0R`a(%NO?#aEH9|?Cv00000NIsFh6BW2800DjO0RR918Pu^`vBYQl0ssI200dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j-~itMU0nbw7KxBg5R*{Ky3@w34e-", + "emlEe%!1&HoVz@2)g91$Qvf%e=}%J+k5^yTOu{Q*OrV;`agAU{YYC1>Bq#Lo)Ct}OFqAaP", + "SYvN>0#bjna^XrQl~da<70IbZ?+00000VC(mK^UzXX00DX60RR91ZYU6cvBYQl0ssI200d", + "cD" ], "UTC": [ - "{Wp48S^xk9=GL@E0stWa761SMbT8$j-~e#|9bEt_7KxBg5R*|3h1|xhHLji!C57qW6L*|H", - "pEErm00000ygu;I+>V)?00B92fhY-(AGY&-0RR9100dcD" + "{Wp48S^xk9=GL@E0stWa761SMbT8$j-", + "~e#|9bEt_7KxBg5R*|3h1|xhHLji!C57qW6L*|HpEErm00000ygu;I+>V)?00B92fhY-", + "(AGY&-0RR9100dcD" ] }, "metadata": { - "version": "2020a" + "version": "2025b" } } \ No newline at end of file diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index addc905af5e..8f3ca59c9ef 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -18,7 +18,7 @@ from datetime import date, datetime, time, timedelta, timezone from functools import cached_property from test.support import MISSING_C_DOCSTRINGS -from test.support.os_helper import EnvironmentVarGuard +from test.support.os_helper import EnvironmentVarGuard, FakePath from test.test_zoneinfo import _support as test_support from test.test_zoneinfo._support import TZPATH_TEST_LOCK, ZoneInfoTestBase from test.support.import_helper import import_module, CleanImport @@ -29,7 +29,7 @@ py_zoneinfo, c_zoneinfo = test_support.get_modules() try: importlib.metadata.metadata("tzdata") - HAS_TZDATA_PKG = True + HAS_TZDATA_PKG = (importlib.metadata.version("tzdata") == "2025.3") except importlib.metadata.PackageNotFoundError: HAS_TZDATA_PKG = False @@ -1551,6 +1551,26 @@ class ZoneInfoCacheTest(TzPathUserMixin, ZoneInfoTestBase): except CustomError: pass + def test_weak_cache_descriptor_use_after_free(self): + class BombDescriptor: + def __get__(self, obj, owner): + return {} + + class EvilZoneInfo(self.klass): + pass + + # Must be set after the class creation. + EvilZoneInfo._weak_cache = BombDescriptor() + + key = "America/Los_Angeles" + zone1 = EvilZoneInfo(key) + self.assertEqual(str(zone1), key) + + EvilZoneInfo.clear_cache() + zone2 = EvilZoneInfo(key) + self.assertEqual(str(zone2), key) + self.assertIsNot(zone2, zone1) + class CZoneInfoCacheTest(ZoneInfoCacheTest): module = c_zoneinfo @@ -1784,6 +1804,7 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): ("/usr/share/zoneinfo", "../relative/path",), ("path/to/somewhere", "../relative/path",), ("/usr/share/zoneinfo", "path/to/somewhere", "../relative/path",), + (FakePath("path/to/somewhere"),) ] for input_paths in bad_values: with self.subTest(input_paths=input_paths): @@ -1795,6 +1816,9 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): "/etc/zoneinfo:/usr/share/zoneinfo", b"/etc/zoneinfo:/usr/share/zoneinfo", 0, + (b"/bytes/path", "/valid/path"), + (FakePath(b"/bytes/path"),), + (0,), ] for bad_value in bad_values: @@ -1805,6 +1829,7 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): def test_tzpath_attribute(self): tzpath_0 = [f"{DRIVE}/one", f"{DRIVE}/two"] tzpath_1 = [f"{DRIVE}/three"] + tzpath_pathlike = (FakePath(f"{DRIVE}/usr/share/zoneinfo"),) with self.tzpath_context(tzpath_0): query_0 = self.module.TZPATH @@ -1812,8 +1837,12 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): with self.tzpath_context(tzpath_1): query_1 = self.module.TZPATH + with self.tzpath_context(tzpath_pathlike): + query_pathlike = self.module.TZPATH + self.assertSequenceEqual(tzpath_0, query_0) self.assertSequenceEqual(tzpath_1, query_1) + self.assertSequenceEqual(tuple([os.fspath(p) for p in tzpath_pathlike]), query_pathlike) class CTzPathTest(TzPathTest): @@ -1942,6 +1971,21 @@ class TestModule(ZoneInfoTestBase): actual = self.module.available_timezones() self.assertEqual(actual, expected) + def test_exclude_localtime(self): + expected = { + "America/New_York", + "Europe/London", + } + + tree = list(expected) + ["localtime"] + + with tempfile.TemporaryDirectory() as td: + for key in tree: + self.touch_zone(key, td) + + with self.tzpath_context([td]): + actual = self.module.available_timezones() + self.assertEqual(actual, expected) class CTestModule(TestModule): module = c_zoneinfo @@ -2183,8 +2227,8 @@ class ZoneDumpData: ] def _America_Santiago(): - LMT = ZoneOffset("LMT", timedelta(seconds=-16966), ZERO) - SMT = ZoneOffset("SMT", timedelta(seconds=-16966), ZERO) + LMT = ZoneOffset("LMT", timedelta(seconds=-16965), ZERO) + SMT = ZoneOffset("SMT", timedelta(seconds=-16965), ZERO) N05 = ZoneOffset("-05", timedelta(seconds=-18000), ZERO) N04 = ZoneOffset("-04", timedelta(seconds=-14400), ZERO) N03 = ZoneOffset("-03", timedelta(seconds=-10800), ONE_H) @@ -2219,8 +2263,8 @@ class ZoneDumpData: return [ ZoneTransition(datetime(1895, 2, 1), LMT, AEST), - ZoneTransition(datetime(1917, 1, 1, 0, 1), AEST, AEDT), - ZoneTransition(datetime(1917, 3, 25, 2), AEDT, AEST), + ZoneTransition(datetime(1917, 1, 1, 2), AEST, AEDT), + ZoneTransition(datetime(1917, 3, 25, 3), AEDT, AEST), ZoneTransition(datetime(2012, 4, 1, 3), AEDT, AEST), ZoneTransition(datetime(2012, 10, 7, 2), AEST, AEDT), ZoneTransition(datetime(2040, 4, 1, 3), AEDT, AEST), @@ -2228,7 +2272,7 @@ class ZoneDumpData: ] def _Europe_Dublin(): - LMT = ZoneOffset("LMT", timedelta(seconds=-1500), ZERO) + LMT = ZoneOffset("LMT", timedelta(seconds=-1521), ZERO) DMT = ZoneOffset("DMT", timedelta(seconds=-1521), ZERO) IST_0 = ZoneOffset("IST", timedelta(seconds=2079), ONE_H) GMT_0 = ZoneOffset("GMT", ZERO, ZERO) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 5ae439f5cd3..41366fbf443 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -211,7 +211,7 @@ class TextWrapper: # If we're allowed to break long words, then do so: put as much # of the next chunk onto the current line as will fit. - if self.break_long_words: + if self.break_long_words and space_left > 0: end = space_left chunk = reversed_chunks[-1] if self.break_on_hyphens and len(chunk) > space_left: diff --git a/Lib/threading.py b/Lib/threading.py index b3e24fe7dda..4ebceae7029 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -653,7 +653,8 @@ class Event: (or fractions thereof). This method returns the internal flag on exit, so it will always return - True except if a timeout is given and the operation times out. + ``True`` except if a timeout is given and the operation times out, when + it will return ``False``. """ with self._cond: @@ -1557,8 +1558,9 @@ def _shutdown(): # normally - that won't happen until the interpreter is nearly dead. So # mark it done here. if _main_thread._os_thread_handle.is_done() and _is_main_interpreter(): - # _shutdown() was already called - return + # _shutdown() was already called, but threads might have started + # in the meantime. + return _thread_shutdown() global _SHUTTING_DOWN _SHUTTING_DOWN = True diff --git a/Lib/timeit.py b/Lib/timeit.py index e767f018782..80791acdeca 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -133,7 +133,7 @@ class Timer: exec(code, global_ns, local_ns) self.inner = local_ns["inner"] - def print_exc(self, file=None): + def print_exc(self, file=None, **kwargs): """Helper to print a traceback from the timed code. Typical use: @@ -149,6 +149,11 @@ class Timer: The optional file argument directs where the traceback is sent; it defaults to sys.stderr. + + The optional colorize keyword argument controls whether the + traceback is colorized; it defaults to False for programmatic + usage. When used from the command line, this is automatically + set based on terminal capabilities. """ import linecache, traceback if self.src is not None: @@ -158,7 +163,8 @@ class Timer: dummy_src_name) # else the source is already stored somewhere else - traceback.print_exc(file=file) + kwargs['colorize'] = kwargs.get('colorize', False) + traceback.print_exc(file=file, **kwargs) def timeit(self, number=default_number): """Time 'number' executions of the main statement. @@ -257,9 +263,12 @@ def main(args=None, *, _wrap_timer=None): is not None, it must be a callable that accepts a timer function and returns another timer function (used for unit testing). """ + import getopt if args is None: args = sys.argv[1:] - import getopt + import _colorize + colorize = _colorize.can_colorize() + try: opts, args = getopt.getopt(args, "n:u:s:r:pvh", ["number=", "setup=", "repeat=", @@ -326,7 +335,7 @@ def main(args=None, *, _wrap_timer=None): try: number, _ = t.autorange(callback) except: - t.print_exc() + t.print_exc(colorize=colorize) return 1 if verbose: @@ -335,7 +344,7 @@ def main(args=None, *, _wrap_timer=None): try: raw_timings = t.repeat(repeat, number) except: - t.print_exc() + t.print_exc(colorize=colorize) return 1 def format_time(dt): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 9526d8b949f..737583a42c6 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1848,6 +1848,7 @@ class Misc: return self.tk.call(self._w, 'cget', '-' + key) __getitem__ = cget + __iter__ = None # prevent using __getitem__ for iteration def __setitem__(self, key, value): self.configure({key: value}) @@ -4048,8 +4049,9 @@ class Text(Widget, XView, YView): self.tk.call(self._w, 'scan', 'dragto', x, y) def search(self, pattern, index, stopindex=None, - forwards=None, backwards=None, exact=None, - regexp=None, nocase=None, count=None, elide=None): + forwards=None, backwards=None, exact=None, + regexp=None, nocase=None, count=None, + elide=None, *, nolinestop=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. Return the index of the first character of a match or an empty string.""" @@ -4061,12 +4063,39 @@ class Text(Widget, XView, YView): if nocase: args.append('-nocase') if elide: args.append('-elide') if count: args.append('-count'); args.append(count) + if nolinestop: args.append('-nolinestop') + if strictlimits: args.append('-strictlimits') if pattern and pattern[0] == '-': args.append('--') args.append(pattern) args.append(index) - if stopindex: args.append(stopindex) + if stopindex is not None: args.append(stopindex) return str(self.tk.call(tuple(args))) + def search_all(self, pattern, index, stopindex=None, *, + forwards=None, backwards=None, exact=None, + regexp=None, nocase=None, count=None, + elide=None, nolinestop=None, overlap=None, + strictlimits=None): + """Search all occurrences of PATTERN from INDEX to STOPINDEX. + Return a tuple of indices where matches begin.""" + args = [self._w, 'search', '-all'] + if forwards: args.append('-forwards') + if backwards: args.append('-backwards') + if exact: args.append('-exact') + if regexp: args.append('-regexp') + if nocase: args.append('-nocase') + if elide: args.append('-elide') + if count: args.append('-count'); args.append(count) + if nolinestop: args.append('-nolinestop') + if overlap: args.append('-overlap') + if strictlimits: args.append('-strictlimits') + if pattern and pattern[0] == '-': args.append('--') + args.append(pattern) + args.append(index) + if stopindex is not None: args.append(stopindex) + result = self.tk.call(tuple(args)) + return self.tk.splitlist(result) + def see(self, index): """Scroll such that the character at INDEX is visible.""" self.tk.call(self._w, 'see', index) @@ -4280,6 +4309,8 @@ class Image: def __getitem__(self, key): return self.tk.call(self.name, 'configure', '-'+key) + __iter__ = None # prevent using __getitem__ for iteration + def configure(self, **kw): """Configure the image.""" res = () diff --git a/Lib/tkinter/font.py b/Lib/tkinter/font.py index 3e24e28ef58..896e910d69f 100644 --- a/Lib/tkinter/font.py +++ b/Lib/tkinter/font.py @@ -6,7 +6,6 @@ import itertools import tkinter -__version__ = "0.9" __all__ = ["NORMAL", "ROMAN", "BOLD", "ITALIC", "nametofont", "Font", "families", "names"] @@ -115,6 +114,8 @@ class Font: def __setitem__(self, key, value): self.configure(**{key: value}) + __iter__ = None # prevent using __getitem__ for iteration + def __del__(self): try: if self.delete_font: @@ -198,6 +199,15 @@ def names(root=None): return root.tk.splitlist(root.tk.call("font", "names")) +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "0.9" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + # -------------------------------------------------------------------- # test stuff diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py index 6e5b025a9f9..4f9eb44f034 100644 --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -23,9 +23,12 @@ askfloat -- get a float from the user askstring -- get a string from the user """ -from tkinter import * +from tkinter import Button, Entry, Frame, Label, Message, Tk, Toplevel from tkinter import _get_temp_root, _destroy_temp_root from tkinter import messagebox +from tkinter.constants import ACTIVE, BOTH, END, LEFT, RIDGE, W, E + +__all__ = ["SimpleDialog", "Dialog", "askinteger", "askfloat", "askstring"] class SimpleDialog: diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index ef2b91dfbb6..5c5ef11ae05 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -12,8 +12,6 @@ maintaining the widget state and invoking callbacks, all aspects of the widgets appearance lies at Themes. """ -__version__ = "0.3.1" - __author__ = "Guilherme Polo <ggpolo@gmail.com>" __all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label", @@ -1648,3 +1646,12 @@ class OptionMenu(Menubutton): except AttributeError: pass super().destroy() + + +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "0.3.1" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 7e71755068e..11c134482db 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -36,7 +36,7 @@ from token import * from token import EXACT_TOKEN_TYPES import _tokenize -cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII) +cookie_re = re.compile(br'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII) blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) import token @@ -385,24 +385,25 @@ def detect_encoding(readline): except StopIteration: return b'' - def find_cookie(line): + def check(line, encoding): + # Check if the line matches the encoding. + if 0 in line: + raise SyntaxError("source code cannot contain null bytes") try: - # Decode as UTF-8. Either the line is an encoding declaration, - # in which case it should be pure ASCII, or it must be UTF-8 - # per default encoding. - line_string = line.decode('utf-8') + line.decode(encoding) except UnicodeDecodeError: msg = "invalid or missing encoding declaration" if filename is not None: msg = '{} for {!r}'.format(msg, filename) raise SyntaxError(msg) - match = cookie_re.match(line_string) + def find_cookie(line): + match = cookie_re.match(line) if not match: return None - encoding = _get_normal_name(match.group(1)) + encoding = _get_normal_name(match.group(1).decode()) try: - codec = lookup(encoding) + lookup(encoding) except LookupError: # This behaviour mimics the Python interpreter if filename is None: @@ -433,18 +434,23 @@ def detect_encoding(readline): encoding = find_cookie(first) if encoding: + check(first, encoding) return encoding, [first] if not blank_re.match(first): + check(first, default) return default, [first] second = read_or_stop() if not second: + check(first, default) return default, [first] encoding = find_cookie(second) if encoding: + check(first + second, encoding) return encoding, [first, second] + check(first + second, default) return default, [first, second] diff --git a/Lib/trace.py b/Lib/trace.py index cf8817f4383..cd3a6d30661 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -721,7 +721,6 @@ def main(): '__package__': mod_spec.parent, '__loader__': mod_spec.loader, '__spec__': mod_spec, - '__cached__': None, } else: sys.argv = [opts.progname, *opts.arguments] @@ -734,7 +733,6 @@ def main(): '__file__': opts.progname, '__name__': '__main__', '__package__': None, - '__cached__': None, } t.runctx(code, globs, globs) except OSError as err: diff --git a/Lib/traceback.py b/Lib/traceback.py index 8e2d8d72a0a..f95d6bdbd01 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -14,6 +14,11 @@ import _colorize from contextlib import suppress +try: + from _missing_stdlib_info import _MISSING_STDLIB_MODULE_MESSAGES +except ImportError: + _MISSING_STDLIB_MODULE_MESSAGES = {} + __all__ = ['extract_stack', 'extract_tb', 'format_exception', 'format_exception_only', 'format_list', 'format_stack', 'format_tb', 'print_exc', 'format_exc', 'print_exception', @@ -206,9 +211,9 @@ def _safe_string(value, what, func=str): # -- -def print_exc(limit=None, file=None, chain=True): +def print_exc(limit=None, file=None, chain=True, **kwargs): """Shorthand for 'print_exception(sys.exception(), limit=limit, file=file, chain=chain)'.""" - print_exception(sys.exception(), limit=limit, file=file, chain=chain) + print_exception(sys.exception(), limit=limit, file=file, chain=chain, **kwargs) def format_exc(limit=None, chain=True): """Like print_exc() but return a string.""" @@ -1107,11 +1112,18 @@ class TracebackException: suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) if suggestion: self._str += f". Did you mean: '{suggestion}'?" - elif exc_type and issubclass(exc_type, ModuleNotFoundError) and \ - sys.flags.no_site and \ - getattr(exc_value, "name", None) not in sys.stdlib_module_names: - self._str += (". Site initialization is disabled, did you forget to " - + "add the site-packages directory to sys.path?") + elif exc_type and issubclass(exc_type, ModuleNotFoundError): + module_name = getattr(exc_value, "name", None) + if module_name in sys.stdlib_module_names: + message = _MISSING_STDLIB_MODULE_MESSAGES.get( + module_name, + f"Standard library module {module_name!r} was not found" + ) + self._str = message + elif sys.flags.no_site: + self._str += (". Site initialization is disabled, did you forget to " + + "add the site-packages directory to sys.path " + + "or to enable your virtual environment?") elif exc_type and issubclass(exc_type, (NameError, AttributeError)) and \ getattr(exc_value, "name", None) is not None: wrong_name = getattr(exc_value, "name", None) @@ -1328,6 +1340,15 @@ class TracebackException: if len(error_code) > 1024: return + # If the original code doesn't raise SyntaxError, we can't validate + # that a keyword replacement actually fixes anything + try: + codeop.compile_command(error_code, symbol="exec", flags=codeop.PyCF_ONLY_AST) + except SyntaxError: + pass # Good - the original code has a syntax error we might fix + else: + return # Original code compiles or is incomplete - can't validate fixes + error_lines = error_code.splitlines() tokens = tokenize.generate_tokens(io.StringIO(error_code).readline) tokens_left_to_process = 10 @@ -1443,10 +1464,11 @@ class TracebackException: # Convert 1-based column offset to 0-based index into stripped text colno = offset - 1 - spaces end_colno = end_offset - 1 - spaces - caretspace = ' ' if colno >= 0: - # non-space whitespace (likes tabs) must be kept for alignment - caretspace = ((c if c.isspace() else ' ') for c in ltext[:colno]) + # Calculate display width to account for wide characters + dp_colno = _display_width(ltext, colno) + highlighted = ltext[colno:end_colno] + caret_count = _display_width(highlighted) if highlighted else (end_colno - colno) start_color = end_color = "" if colorize: # colorize from colno to end_colno @@ -1459,9 +1481,9 @@ class TracebackException: end_color = theme.reset yield ' {}\n'.format(ltext) yield ' {}{}{}{}\n'.format( - "".join(caretspace), + ' ' * dp_colno, start_color, - ('^' * (end_colno - colno)), + '^' * caret_count, end_color, ) else: diff --git a/Lib/turtle.py b/Lib/turtle.py index e88981d298a..b52d681b3af 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -565,7 +565,7 @@ class TurtleScreenBase(object): """Check if the string color is a legal Tkinter color string. """ try: - rgb = self.cv.winfo_rgb(color) + self.cv.winfo_rgb(color) ok = True except TK.TclError: ok = False @@ -1214,16 +1214,32 @@ class TurtleScreen(TurtleScreenBase): def bgcolor(self, *args): """Set or return backgroundcolor of the TurtleScreen. - Arguments (if given): a color string or three numbers - in the range 0..colormode or a 3-tuple of such numbers. + Four input formats are allowed: + - bgcolor() + Return the current background color as color specification + string or as a tuple (see example). May be used as input + to another color/pencolor/fillcolor/bgcolor call. + - bgcolor(colorstring) + Set the background color to colorstring, which is a Tk color + specification string, such as "red", "yellow", or "#33cc8c". + - bgcolor((r, g, b)) + Set the background color to the RGB color represented by + the tuple of r, g, and b. Each of r, g, and b must be in + the range 0..colormode, where colormode is either 1.0 or 255 + (see colormode()). + - bgcolor(r, g, b) + Set the background color to the RGB color represented by + r, g, and b. Each of r, g, and b must be in the range + 0..colormode. Example (for a TurtleScreen instance named screen): >>> screen.bgcolor("orange") >>> screen.bgcolor() 'orange' - >>> screen.bgcolor(0.5,0,0.5) + >>> colormode(255) + >>> screen.bgcolor('#800080') >>> screen.bgcolor() - '#800080' + (128.0, 0.0, 128.0) """ if args: color = self._colorstr(args) @@ -1678,7 +1694,7 @@ class TNavigator(object): Example (for a Turtle instance named turtle): >>> turtle.position() - (0.00, 0.00) + (0.00,0.00) >>> turtle.forward(25) >>> turtle.position() (25.00,0.00) @@ -1701,10 +1717,10 @@ class TNavigator(object): Example (for a Turtle instance named turtle): >>> turtle.position() - (0.00, 0.00) + (0.00,0.00) >>> turtle.backward(30) >>> turtle.position() - (-30.00, 0.00) + (-30.00,0.00) """ self._go(-distance) @@ -1811,7 +1827,7 @@ class TNavigator(object): Example (for a Turtle instance named turtle): >>> tp = turtle.pos() >>> tp - (0.00, 0.00) + (0.00,0.00) >>> turtle.setpos(60,30) >>> turtle.pos() (60.00,30.00) @@ -1891,7 +1907,7 @@ class TNavigator(object): Example (for a Turtle instance named turtle): >>> turtle.pos() - (0.00, 0.00) + (0.00,0.00) >>> turtle.distance(30,40) 50.0 >>> pen = Turtle() @@ -2230,19 +2246,17 @@ class TPen(object): Arguments: Several input formats are allowed. - They use 0, 1, 2, or 3 arguments as follows: - - color() - Return the current pencolor and the current fillcolor - as a pair of color specification strings as are returned - by pencolor and fillcolor. - color(colorstring), color((r,g,b)), color(r,g,b) - inputs as in pencolor, set both, fillcolor and pencolor, + They use 0 to 3 arguments as follows: + - color() + Return the current pencolor and the current fillcolor as + a pair of color specification strings or tuples as returned + by pencolor() and fillcolor(). + - color(colorstring), color((r,g,b)), color(r,g,b) + Inputs as in pencolor(), set both, fillcolor and pencolor, to the given value. - color(colorstring1, colorstring2), - color((r1,g1,b1), (r2,g2,b2)) - equivalent to pencolor(colorstring1) and fillcolor(colorstring2) - and analogously, if the other input format is used. + - color(colorstring1, colorstring2), color((r1,g1,b1), (r2,g2,b2)) + Equivalent to pencolor(colorstring1) and fillcolor(colorstring2) + and analogously if the other input format is used. If turtleshape is a polygon, outline and interior of that polygon is drawn with the newly set colors. @@ -2253,9 +2267,9 @@ class TPen(object): >>> turtle.color() ('red', 'green') >>> colormode(255) - >>> color((40, 80, 120), (160, 200, 240)) + >>> color(('#285078', '#a0c8f0')) >>> color() - ('#285078', '#a0c8f0') + ((40.0, 80.0, 120.0), (160.0, 200.0, 240.0)) """ if args: l = len(args) @@ -2277,28 +2291,32 @@ class TPen(object): Arguments: Four input formats are allowed: - pencolor() - Return the current pencolor as color specification string, - possibly in hex-number format (see example). - May be used as input to another color/pencolor/fillcolor call. + Return the current pencolor as color specification string or + as a tuple (see example). May be used as input to another + color/pencolor/fillcolor/bgcolor call. - pencolor(colorstring) - s is a Tk color specification string, such as "red" or "yellow" + Set pencolor to colorstring, which is a Tk color + specification string, such as "red", "yellow", or "#33cc8c". - pencolor((r, g, b)) - *a tuple* of r, g, and b, which represent, an RGB color, - and each of r, g, and b are in the range 0..colormode, - where colormode is either 1.0 or 255 + Set pencolor to the RGB color represented by the tuple of + r, g, and b. Each of r, g, and b must be in the range + 0..colormode, where colormode is either 1.0 or 255 (see + colormode()). - pencolor(r, g, b) - r, g, and b represent an RGB color, and each of r, g, and b - are in the range 0..colormode + Set pencolor to the RGB color represented by r, g, and b. + Each of r, g, and b must be in the range 0..colormode. If turtleshape is a polygon, the outline of that polygon is drawn with the newly set pencolor. Example (for a Turtle instance named turtle): >>> turtle.pencolor('brown') - >>> tup = (0.2, 0.8, 0.55) - >>> turtle.pencolor(tup) >>> turtle.pencolor() - '#33cc8c' + 'brown' + >>> colormode(255) + >>> turtle.pencolor('#32c18f') + >>> turtle.pencolor() + (50.0, 193.0, 143.0) """ if args: color = self._colorstr(args) @@ -2315,26 +2333,31 @@ class TPen(object): Four input formats are allowed: - fillcolor() Return the current fillcolor as color specification string, - possibly in hex-number format (see example). - May be used as input to another color/pencolor/fillcolor call. + possibly in tuple format (see example). May be used as + input to another color/pencolor/fillcolor/bgcolor call. - fillcolor(colorstring) - s is a Tk color specification string, such as "red" or "yellow" + Set fillcolor to colorstring, which is a Tk color + specification string, such as "red", "yellow", or "#33cc8c". - fillcolor((r, g, b)) - *a tuple* of r, g, and b, which represent, an RGB color, - and each of r, g, and b are in the range 0..colormode, - where colormode is either 1.0 or 255 + Set fillcolor to the RGB color represented by the tuple of + r, g, and b. Each of r, g, and b must be in the range + 0..colormode, where colormode is either 1.0 or 255 (see + colormode()). - fillcolor(r, g, b) - r, g, and b represent an RGB color, and each of r, g, and b - are in the range 0..colormode + Set fillcolor to the RGB color represented by r, g, and b. + Each of r, g, and b must be in the range 0..colormode. If turtleshape is a polygon, the interior of that polygon is drawn with the newly set fillcolor. Example (for a Turtle instance named turtle): >>> turtle.fillcolor('violet') - >>> col = turtle.pencolor() - >>> turtle.fillcolor(col) - >>> turtle.fillcolor(0, .5, 0) + >>> turtle.fillcolor() + 'violet' + >>> colormode(255) + >>> turtle.fillcolor('#ffffff') + >>> turtle.fillcolor() + (255.0, 255.0, 255.0) """ if args: color = self._colorstr(args) @@ -3724,7 +3747,7 @@ class RawTurtle(TPen, TNavigator): if action == "rot": angle, degPAU = data self._rotate(-angle*degPAU/self._degreesPerAU) - dummy = self.undobuffer.pop() + self.undobuffer.pop() elif action == "stamp": stitem = data[0] self.clearstamp(stitem) diff --git a/Lib/typing.py b/Lib/typing.py index ea25e3832bd..eb0519986a8 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -139,8 +139,8 @@ __all__ = [ 'Never', 'NewType', 'no_type_check', - 'no_type_check_decorator', 'NoDefault', + 'NoExtraItems', 'NoReturn', 'NotRequired', 'overload', @@ -171,16 +171,16 @@ class _LazyAnnotationLib: _lazy_annotationlib = _LazyAnnotationLib() -def _type_convert(arg, module=None, *, allow_special_forms=False): +def _type_convert(arg, module=None, *, allow_special_forms=False, owner=None): """For converting None to type(None), and strings to ForwardRef.""" if arg is None: return type(None) if isinstance(arg, str): - return _make_forward_ref(arg, module=module, is_class=allow_special_forms) + return _make_forward_ref(arg, module=module, is_class=allow_special_forms, owner=owner) return arg -def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False): +def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False, owner=None): """Check that the argument is a type, and return it (internal helper). As a special case, accept None and return type(None) instead. Also wrap strings @@ -198,7 +198,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms= if is_argument: invalid_generic_forms += (Final,) - arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms) + arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms, owner=owner) if (isinstance(arg, _GenericAlias) and arg.__origin__ in invalid_generic_forms): raise TypeError(f"{arg} is not valid as type argument") @@ -454,7 +454,7 @@ def _deprecation_warning_for_no_type_params_passed(funcname: str) -> None: def _eval_type(t, globalns, localns, type_params, *, recursive_guard=frozenset(), - format=None, owner=None, parent_fwdref=None): + format=None, owner=None, parent_fwdref=None, prefer_fwd_module=False): """Evaluate all forward references in the given type t. For use of globalns and localns see the docstring for get_type_hints(). @@ -464,8 +464,20 @@ def _eval_type(t, globalns, localns, type_params, *, recursive_guard=frozenset() if isinstance(t, _lazy_annotationlib.ForwardRef): # If the forward_ref has __forward_module__ set, evaluate() infers the globals # from the module, and it will probably pick better than the globals we have here. - if t.__forward_module__ is not None: + # We do this only for calls from get_type_hints() (which opts in through the + # prefer_fwd_module flag), so that the default behavior remains more straightforward. + if prefer_fwd_module and t.__forward_module__ is not None: globalns = None + # If there are type params on the owner, we need to add them back, because + # annotationlib won't. + if owner_type_params := getattr(owner, "__type_params__", None): + globalns = getattr( + sys.modules.get(t.__forward_module__, None), "__dict__", None + ) + if globalns is not None: + globalns = dict(globalns) + for type_param in owner_type_params: + globalns[type_param.__name__] = type_param return evaluate_forward_ref(t, globals=globalns, locals=localns, type_params=type_params, owner=owner, _recursive_guard=recursive_guard, format=format) @@ -481,7 +493,7 @@ def _eval_type(t, globalns, localns, type_params, *, recursive_guard=frozenset() ev_args = tuple( _eval_type( a, globalns, localns, type_params, recursive_guard=recursive_guard, - format=format, owner=owner, + format=format, owner=owner, prefer_fwd_module=prefer_fwd_module, ) for a in args ) @@ -1027,8 +1039,10 @@ def evaluate_forward_ref( def _is_unpacked_typevartuple(x: Any) -> bool: + # Need to check 'is True' here + # See: https://github.com/python/cpython/issues/137706 return ((not isinstance(x, type)) and - getattr(x, '__typing_is_unpacked_typevartuple__', False)) + getattr(x, '__typing_is_unpacked_typevartuple__', False) is True) def _is_typevar_like(x: Any) -> bool: @@ -1098,7 +1112,7 @@ def _paramspec_prepare_subst(self, alias, args): params = alias.__parameters__ i = params.index(self) if i == len(args) and self.has_default(): - args = [*args, self.__default__] + args = (*args, self.__default__) if i >= len(args): raise TypeError(f"Too few arguments for {alias}") # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. @@ -1143,14 +1157,26 @@ def _generic_class_getitem(cls, args): f"Parameters to {cls.__name__}[...] must all be unique") else: # Subscripting a regular Generic subclass. - for param in cls.__parameters__: + try: + parameters = cls.__parameters__ + except AttributeError as e: + init_subclass = getattr(cls, '__init_subclass__', None) + if init_subclass not in {None, Generic.__init_subclass__}: + e.add_note( + f"Note: this exception may have been caused by " + f"{init_subclass.__qualname__!r} (or the " + f"'__init_subclass__' method on a superclass) not " + f"calling 'super().__init_subclass__()'" + ) + raise + for param in parameters: prepare = getattr(param, '__typing_prepare_subst__', None) if prepare is not None: args = prepare(cls, args) _check_generic_specialization(cls, args) new_args = [] - for param, new_arg in zip(cls.__parameters__, args): + for param, new_arg in zip(parameters, args): if isinstance(param, TypeVarTuple): new_args.extend(new_arg) else: @@ -2367,7 +2393,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False, if isinstance(value, str): value = _make_forward_ref(value, is_argument=False, is_class=True) value = _eval_type(value, base_globals, base_locals, (), - format=format, owner=obj) + format=format, owner=obj, prefer_fwd_module=True) if value is None: value = type(None) hints[name] = value @@ -2412,7 +2438,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False, is_argument=not isinstance(obj, types.ModuleType), is_class=False, ) - value = _eval_type(value, globalns, localns, (), format=format, owner=obj) + value = _eval_type(value, globalns, localns, (), format=format, owner=obj, prefer_fwd_module=True) if value is None: value = type(None) hints[name] = value @@ -2596,23 +2622,6 @@ def no_type_check(arg): return arg -def no_type_check_decorator(decorator): - """Decorator to give another decorator the @no_type_check effect. - - This wraps the decorator with something that wraps the decorated - function in @no_type_check. - """ - import warnings - warnings._deprecated("typing.no_type_check_decorator", remove=(3, 15)) - @functools.wraps(decorator) - def wrapped_decorator(*args, **kwds): - func = decorator(*args, **kwds) - func = no_type_check(func) - return func - - return wrapped_decorator - - def _overload_dummy(*args, **kwds): """Helper for @overload to raise when called.""" raise NotImplementedError( @@ -3049,6 +3058,33 @@ def _namedtuple_mro_entries(bases): NamedTuple.__mro_entries__ = _namedtuple_mro_entries +class _SingletonMeta(type): + def __setattr__(cls, attr, value): + # TypeError is consistent with the behavior of NoneType + raise TypeError( + f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}" + ) + + +class _NoExtraItemsType(metaclass=_SingletonMeta): + """The type of the NoExtraItems singleton.""" + + __slots__ = () + + def __new__(cls): + return globals().get("NoExtraItems") or object.__new__(cls) + + def __repr__(self): + return 'typing.NoExtraItems' + + def __reduce__(self): + return 'NoExtraItems' + +NoExtraItems = _NoExtraItemsType() +del _NoExtraItemsType +del _SingletonMeta + + def _get_typeddict_qualifiers(annotation_type): while True: annotation_origin = get_origin(annotation_type) @@ -3072,7 +3108,8 @@ def _get_typeddict_qualifiers(annotation_type): class _TypedDictMeta(type): - def __new__(cls, name, bases, ns, total=True): + def __new__(cls, name, bases, ns, total=True, closed=None, + extra_items=NoExtraItems): """Create a new typed dict class object. This method is called when TypedDict is subclassed, @@ -3084,6 +3121,8 @@ class _TypedDictMeta(type): if type(base) is not _TypedDictMeta and base is not Generic: raise TypeError('cannot inherit from both a TypedDict type ' 'and a non-TypedDict base class') + if closed is not None and extra_items is not NoExtraItems: + raise TypeError(f"Cannot combine closed={closed!r} and extra_items") if any(issubclass(b, Generic) for b in bases): generic_base = (Generic,) @@ -3109,7 +3148,7 @@ class _TypedDictMeta(type): own_annotations = {} msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" own_checked_annotations = { - n: _type_check(tp, msg, module=tp_dict.__module__) + n: _type_check(tp, msg, owner=tp_dict, module=tp_dict.__module__) for n, tp in own_annotations.items() } required_keys = set() @@ -3195,6 +3234,8 @@ class _TypedDictMeta(type): tp_dict.__readonly_keys__ = frozenset(readonly_keys) tp_dict.__mutable_keys__ = frozenset(mutable_keys) tp_dict.__total__ = total + tp_dict.__closed__ = closed + tp_dict.__extra_items__ = extra_items return tp_dict __call__ = dict # static method @@ -3206,7 +3247,8 @@ class _TypedDictMeta(type): __instancecheck__ = __subclasscheck__ -def TypedDict(typename, fields, /, *, total=True): +def TypedDict(typename, fields, /, *, total=True, closed=None, + extra_items=NoExtraItems): """A simple typed namespace. At runtime it is equivalent to a plain dict. TypedDict creates a dictionary type such that a type checker will expect all @@ -3260,6 +3302,32 @@ def TypedDict(typename, fields, /, *, total=True): id: ReadOnly[int] # the "id" key must not be modified username: str # the "username" key can be changed + The closed argument controls whether the TypedDict allows additional + non-required items during inheritance and assignability checks. + If closed=True, the TypedDict does not allow additional items:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int}, closed=True) + class Point3D(Point2D): + z: int # Type checker error + + Passing closed=False explicitly requests TypedDict's default open behavior. + If closed is not provided, the behavior is inherited from the superclass. + A type checker is only expected to support a literal False or True as the + value of the closed argument. + + The extra_items argument can instead be used to specify the assignable type + of unknown non-required keys:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int}, extra_items=int) + class Point3D(Point2D): + z: int # OK + label: str # Type checker error + + The extra_items argument is also inherited through subclassing. It is unset + by default, and it may not be used with the closed argument at the same + time. + + See PEP 728 for more information about closed and extra_items. """ ns = {'__annotations__': dict(fields)} module = _caller() @@ -3267,7 +3335,8 @@ def TypedDict(typename, fields, /, *, total=True): # Setting correct module is necessary to make typed dict classes pickleable. ns['__module__'] = module - td = _TypedDictMeta(typename, (), ns, total=total) + td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, + extra_items=extra_items) td.__orig_bases__ = (TypedDict,) return td @@ -3766,6 +3835,48 @@ def __getattr__(attr): ) warnings.warn(depr_message, category=DeprecationWarning, stacklevel=2) obj = _collect_type_parameters + elif attr == "ByteString": + import warnings + + warnings._deprecated( + "typing.ByteString", + message=( + "{name!r} and 'collections.abc.ByteString' are deprecated " + "and slated for removal in Python {remove}" + ), + remove=(3, 17) + ) + + class _DeprecatedGenericAlias(_SpecialGenericAlias, _root=True): + def __init__( + self, origin, nparams, *, removal_version, inst=True, name=None + ): + super().__init__(origin, nparams, inst=inst, name=name) + self._removal_version = removal_version + + def __instancecheck__(self, inst): + import warnings + warnings._deprecated( + f"{self.__module__}.{self._name}", remove=self._removal_version + ) + return super().__instancecheck__(inst) + + def __subclasscheck__(self, cls): + import warnings + warnings._deprecated( + f"{self.__module__}.{self._name}", remove=self._removal_version + ) + return super().__subclasscheck__(cls) + + with warnings.catch_warnings( + action="ignore", category=DeprecationWarning + ): + # Not generic + ByteString = globals()["ByteString"] = _DeprecatedGenericAlias( + collections.abc.ByteString, 0, removal_version=(3, 17) + ) + + return ByteString else: raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") globals()[attr] = obj diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py index 6fd949581f3..be99d93c78c 100644 --- a/Lib/unittest/main.py +++ b/Lib/unittest/main.py @@ -269,12 +269,12 @@ class TestProgram(object): testRunner = self.testRunner self.result = testRunner.run(self.test) if self.exit: - if self.result.testsRun == 0 and len(self.result.skipped) == 0: - sys.exit(_NO_TESTS_EXITCODE) - elif self.result.wasSuccessful(): - sys.exit(0) - else: + if not self.result.wasSuccessful(): sys.exit(1) + elif self.result.testsRun == 0 and len(self.result.skipped) == 0: + sys.exit(_NO_TESTS_EXITCODE) + else: + sys.exit(0) main = TestProgram diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 0bb67506553..34fd49bf56f 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1180,7 +1180,6 @@ class CallableMixin(Base): def _increment_mock_call(self, /, *args, **kwargs): self.called = True - self.call_count += 1 # handle call_args # needs to be set here so assertions on call arguments pass before @@ -1188,6 +1187,7 @@ class CallableMixin(Base): _call = _Call((args, kwargs), two=True) self.call_args = _call self.call_args_list.append(_call) + self.call_count = len(self.call_args_list) # initial stuff for method_calls: do_method_calls = self._mock_parent is not None diff --git a/Lib/urllib/error.py b/Lib/urllib/error.py index a9cd1ecadd6..beb32d0df48 100644 --- a/Lib/urllib/error.py +++ b/Lib/urllib/error.py @@ -18,7 +18,7 @@ __all__ = ['URLError', 'HTTPError', 'ContentTooShortError'] class URLError(OSError): # URLError is a sub-type of OSError, but it doesn't share any of - # the implementation. need to override __init__ and __str__. + # the implementation. It overrides __init__ and __str__. # It sets self.args for compatibility with other OSError # subclasses, but args doesn't have the typical format with errno in # slot 0 and strerror in slot 1. This may be better than nothing. diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 67d9bbea0d3..79fd6abaa1c 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -97,11 +97,9 @@ def clear_cache(): _byte_quoter_factory.cache_clear() # Helpers for bytes handling -# For 3.2, we deliberately require applications that -# handle improperly quoted URLs to do their own -# decoding and encoding. If valid use cases are -# presented, we may relax this by using latin-1 -# decoding internally for 3.3 +# We deliberately require applications that +# handle improperly quoted URLs to do their +# own decoding and encoding. _implicit_encoding = 'ascii' _implicit_errors = 'strict' @@ -1064,7 +1062,7 @@ def urlencode(query, doseq=False, safe='', encoding=None, errors=None, else: try: # Is this a sufficient test for sequence-ness? - x = len(v) + len(v) except TypeError: # not a sequence v = quote_via(str(v), safe, encoding, errors) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index af93d4cd75d..f32de189b13 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -415,6 +415,8 @@ class OpenerDirector: continue i = meth.find("_") + if i < 1: + continue protocol = meth[:i] condition = meth[i+1:] @@ -1535,6 +1537,7 @@ class FTPHandler(BaseHandler): dirs, file = dirs[:-1], dirs[-1] if dirs and not dirs[0]: dirs = dirs[1:] + fw = None try: fw = self.connect_ftp(user, passwd, host, port, dirs, req.timeout) type = file and 'I' or 'D' @@ -1552,8 +1555,12 @@ class FTPHandler(BaseHandler): headers += "Content-length: %d\n" % retrlen headers = email.message_from_string(headers) return addinfourl(fp, headers, req.full_url) - except ftplib.all_errors as exp: - raise URLError(f"ftp error: {exp}") from exp + except Exception as exp: + if fw is not None and not fw.keepalive: + fw.close() + if isinstance(exp, ftplib.all_errors): + raise URLError(f"ftp error: {exp}") from exp + raise def connect_ftp(self, user, passwd, host, port, dirs, timeout): return ftpwrapper(user, passwd, host, port, dirs, timeout, @@ -1577,14 +1584,15 @@ class CacheFTPHandler(FTPHandler): def connect_ftp(self, user, passwd, host, port, dirs, timeout): key = user, host, port, '/'.join(dirs), timeout - if key in self.cache: - self.timeout[key] = time.time() + self.delay - else: - self.cache[key] = ftpwrapper(user, passwd, host, port, - dirs, timeout) - self.timeout[key] = time.time() + self.delay + conn = self.cache.get(key) + if conn is None or not conn.keepalive: + if conn is not None: + conn.close() + conn = self.cache[key] = ftpwrapper(user, passwd, host, port, + dirs, timeout) + self.timeout[key] = time.time() + self.delay self.check_cache() - return self.cache[key] + return conn def check_cache(self): # first check for old ones diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py index 409f2b2e48d..4009fd6b58f 100644 --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -11,6 +11,7 @@ """ import collections +import re import urllib.error import urllib.parse import urllib.request @@ -20,6 +21,19 @@ __all__ = ["RobotFileParser"] RequestRate = collections.namedtuple("RequestRate", "requests seconds") +def normalize(path): + unquoted = urllib.parse.unquote(path, errors='surrogateescape') + return urllib.parse.quote(unquoted, errors='surrogateescape') + +def normalize_path(path): + path, sep, query = path.partition('?') + path = normalize(path) + if sep: + query = re.sub(r'[^=&]+', lambda m: normalize(m[0]), query) + path += '?' + query + return path + + class RobotFileParser: """ This class provides a set of methods to read, parse and answer questions about a single robots.txt file. @@ -55,7 +69,7 @@ class RobotFileParser: def set_url(self, url): """Sets the URL referring to a robots.txt file.""" self.url = url - self.host, self.path = urllib.parse.urlparse(url)[1:3] + self.host, self.path = urllib.parse.urlsplit(url)[1:3] def read(self): """Reads the robots.txt URL and feeds it to the parser.""" @@ -69,7 +83,7 @@ class RobotFileParser: err.close() else: raw = f.read() - self.parse(raw.decode("utf-8").splitlines()) + self.parse(raw.decode("utf-8", "surrogateescape").splitlines()) def _add_entry(self, entry): if "*" in entry.useragents: @@ -113,7 +127,7 @@ class RobotFileParser: line = line.split(':', 1) if len(line) == 2: line[0] = line[0].strip().lower() - line[1] = urllib.parse.unquote(line[1].strip()) + line[1] = line[1].strip() if line[0] == "user-agent": if state == 2: self._add_entry(entry) @@ -167,10 +181,11 @@ class RobotFileParser: return False # search for given user agent matches # the first match counts - parsed_url = urllib.parse.urlparse(urllib.parse.unquote(url)) - url = urllib.parse.urlunparse(('','',parsed_url.path, - parsed_url.params,parsed_url.query, parsed_url.fragment)) - url = urllib.parse.quote(url) + # TODO: The private API is used in order to preserve an empty query. + # This is temporary until the public API starts supporting this feature. + parsed_url = urllib.parse._urlsplit(url, '') + url = urllib.parse._urlunsplit(None, None, *parsed_url[2:]) + url = normalize_path(url) if not url: url = "/" for entry in self.entries: @@ -213,7 +228,6 @@ class RobotFileParser: entries = entries + [self.default_entry] return '\n\n'.join(map(str, entries)) - class RuleLine: """A rule line is a single "Allow:" (allowance==True) or "Disallow:" (allowance==False) followed by a path.""" @@ -221,8 +235,7 @@ class RuleLine: if path == '' and not allowance: # an empty value means allow all allowance = True - path = urllib.parse.urlunparse(urllib.parse.urlparse(path)) - self.path = urllib.parse.quote(path) + self.path = normalize_path(path) self.allowance = allowance def applies_to(self, filename): @@ -268,7 +281,7 @@ class Entry: def allowance(self, filename): """Preconditions: - our agent applies to this entry - - filename is URL decoded""" + - filename is URL encoded""" for line in self.rulelines: if line.applies_to(filename): return line.allowance diff --git a/Lib/uuid.py b/Lib/uuid.py index 313f2fc46cb..c0150a59d7c 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -737,6 +737,7 @@ def uuid1(node=None, clock_seq=None): is_safe = SafeUUID(safely_generated) except ValueError: is_safe = SafeUUID.unknown + # The version field is assumed to be handled by _generate_time_safe(). return UUID(bytes=uuid_time, is_safe=is_safe) global _last_timestamp diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index dc9c5991df7..19eddde700b 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -174,6 +174,7 @@ class EnvBuilder: context.python_exe = exename binpath = self._venv_path(env_dir, 'scripts') libpath = self._venv_path(env_dir, 'purelib') + platlibpath = self._venv_path(env_dir, 'platlib') # PEP 405 says venvs should create a local include directory. # See https://peps.python.org/pep-0405/#include-files @@ -191,12 +192,8 @@ class EnvBuilder: create_if_needed(incpath) context.lib_path = libpath create_if_needed(libpath) - # Issue 21197: create lib64 as a symlink to lib on 64-bit non-OS X POSIX - if ((sys.maxsize > 2**32) and (os.name == 'posix') and - (sys.platform != 'darwin')): - link_path = os.path.join(env_dir, 'lib64') - if not os.path.exists(link_path): # Issue #21643 - os.symlink('lib', link_path) + context.platlib_path = platlibpath + create_if_needed(platlibpath) context.bin_path = binpath context.bin_name = os.path.relpath(binpath, env_dir) context.env_exe = os.path.join(binpath, exename) @@ -309,7 +306,6 @@ class EnvBuilder: binpath = context.bin_path path = context.env_exe copier = self.symlink_or_copy - dirname = context.python_dir copier(context.executable, path) if not os.path.islink(path): os.chmod(path, 0o755) diff --git a/Lib/wave.py b/Lib/wave.py index 5af745e2217..25ca9ef168e 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -69,6 +69,7 @@ is destroyed. from collections import namedtuple import builtins +import os import struct import sys @@ -96,7 +97,7 @@ def _byteswap(data, width): for j in range(width): swapped_data[i + width - 1 - j] = data[i + j] - return bytes(swapped_data) + return swapped_data.take_bytes() class _Chunk: @@ -274,7 +275,7 @@ class Wave_read: def __init__(self, f): self._i_opened_the_file = None - if isinstance(f, str): + if isinstance(f, (bytes, str, os.PathLike)): f = builtins.open(f, 'rb') self._i_opened_the_file = f # else, assume it is an open file object already @@ -431,7 +432,7 @@ class Wave_write: def __init__(self, f): self._i_opened_the_file = None - if isinstance(f, str): + if isinstance(f, (bytes, str, os.PathLike)): f = builtins.open(f, 'wb') self._i_opened_the_file = f try: diff --git a/Lib/wsgiref/simple_server.py b/Lib/wsgiref/simple_server.py index a0f2397fcf0..31efd8c9bae 100644 --- a/Lib/wsgiref/simple_server.py +++ b/Lib/wsgiref/simple_server.py @@ -16,11 +16,10 @@ import urllib.parse from wsgiref.handlers import SimpleHandler from platform import python_implementation -__version__ = "0.2" __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server'] -server_version = "WSGIServer/" + __version__ +server_version = "WSGIServer" sys_version = python_implementation() + "/" + sys.version.split()[0] software_version = server_version + ' ' + sys_version @@ -70,7 +69,7 @@ class WSGIServer(HTTPServer): class WSGIRequestHandler(BaseHTTPRequestHandler): - server_version = "WSGIServer/" + __version__ + server_version = "WSGIServer" def get_environ(self): env = self.server.base_environ.copy() @@ -152,6 +151,15 @@ def make_server( return server +def __getattr__(name): + if name == "__version__": + from warnings import _deprecated + + _deprecated("__version__", remove=(3, 20)) + return "0.2" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + if __name__ == '__main__': with make_server('', 8000, demo_app) as httpd: sa = httpd.socket.getsockname() diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py index db51f350ea0..16b33b90184 100644 --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -292,13 +292,6 @@ def _append_child(self, node): childNodes.append(node) node.parentNode = self -def _in_document(node): - # return True iff node is part of a document tree - while node is not None: - if node.nodeType == Node.DOCUMENT_NODE: - return True - node = node.parentNode - return False def _write_data(writer, text, attr): "Writes datachars to writer." @@ -371,6 +364,7 @@ class Attr(Node): def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None, prefix=None): self.ownerElement = None + self.ownerDocument = None self._name = qName self.namespaceURI = namespaceURI self._prefix = prefix @@ -696,6 +690,7 @@ class Element(Node): def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None, localName=None): + self.ownerDocument = None self.parentNode = None self.tagName = self.nodeName = tagName self.prefix = prefix @@ -1555,7 +1550,7 @@ def _clear_id_cache(node): if node.nodeType == Node.DOCUMENT_NODE: node._id_cache.clear() node._id_search_stack = None - elif _in_document(node): + elif node.ownerDocument: node.ownerDocument._id_cache.clear() node.ownerDocument._id_search_stack= None diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index dafe5b1b8a0..d8c0b1b6216 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1261,16 +1261,20 @@ def iterparse(source, events=None, parser=None): gen = iterator(source) class IterParseIterator(collections.abc.Iterator): __next__ = gen.__next__ + def close(self): + nonlocal close_source if close_source: source.close() + close_source = False gen.close() - def __del__(self): - # TODO: Emit a ResourceWarning if it was not explicitly closed. - # (When the close() method will be supported in all maintained Python versions.) + def __del__(self, _warn=warnings.warn): if close_source: - source.close() + try: + _warn(f"unclosed iterparse iterator {source.name!r}", ResourceWarning, stacklevel=2) + finally: + source.close() it = IterParseIterator() it.root = None diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 2969f735e8a..ac2332e5846 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -265,7 +265,7 @@ def is_zipfile(filename): else: with open(filename, "rb") as fp: result = _check_zipfile(fp) - except OSError: + except (OSError, BadZipFile): pass return result @@ -275,9 +275,6 @@ def _handle_prepended_data(endrec, debug=0): # "concat" is zero, unless zip was concatenated to another file concat = endrec[_ECD_LOCATION] - size_cd - offset_cd - if endrec[_ECD_SIGNATURE] == stringEndArchive64: - # If Zip64 extension structures are present, account for them - concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator) if debug > 2: inferred = concat + offset_cd @@ -289,16 +286,15 @@ def _EndRecData64(fpin, offset, endrec): """ Read the ZIP64 end-of-archive records and use that to update endrec """ - try: - fpin.seek(offset - sizeEndCentDir64Locator, 2) - except OSError: - # If the seek fails, the file is not large enough to contain a ZIP64 + offset -= sizeEndCentDir64Locator + if offset < 0: + # The file is not large enough to contain a ZIP64 # end-of-archive record, so just return the end record we were given. return endrec - + fpin.seek(offset) data = fpin.read(sizeEndCentDir64Locator) if len(data) != sizeEndCentDir64Locator: - return endrec + raise OSError("Unknown I/O error") sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data) if sig != stringEndArchive64Locator: return endrec @@ -306,16 +302,33 @@ def _EndRecData64(fpin, offset, endrec): if diskno != 0 or disks > 1: raise BadZipFile("zipfiles that span multiple disks are not supported") - # Assume no 'zip64 extensible data' - fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2) + offset -= sizeEndCentDir64 + if reloff > offset: + raise BadZipFile("Corrupt zip64 end of central directory locator") + # First, check the assumption that there is no prepended data. + fpin.seek(reloff) + extrasz = offset - reloff data = fpin.read(sizeEndCentDir64) if len(data) != sizeEndCentDir64: - return endrec + raise OSError("Unknown I/O error") + if not data.startswith(stringEndArchive64) and reloff != offset: + # Since we already have seen the Zip64 EOCD Locator, it's + # possible we got here because there is prepended data. + # Assume no 'zip64 extensible data' + fpin.seek(offset) + extrasz = 0 + data = fpin.read(sizeEndCentDir64) + if len(data) != sizeEndCentDir64: + raise OSError("Unknown I/O error") + if not data.startswith(stringEndArchive64): + raise BadZipFile("Zip64 end of central directory record not found") + sig, sz, create_version, read_version, disk_num, disk_dir, \ dircount, dircount2, dirsize, diroffset = \ struct.unpack(structEndArchive64, data) - if sig != stringEndArchive64: - return endrec + if (diroffset + dirsize != reloff or + sz + 12 != sizeEndCentDir64 + extrasz): + raise BadZipFile("Corrupt zip64 end of central directory record") # Update the original endrec using data from the ZIP64 record endrec[_ECD_SIGNATURE] = sig @@ -325,6 +338,7 @@ def _EndRecData64(fpin, offset, endrec): endrec[_ECD_ENTRIES_TOTAL] = dircount2 endrec[_ECD_SIZE] = dirsize endrec[_ECD_OFFSET] = diroffset + endrec[_ECD_LOCATION] = offset - extrasz return endrec @@ -358,7 +372,7 @@ def _EndRecData(fpin): endrec.append(filesize - sizeEndCentDir) # Try to read the "Zip64 end of central directory" structure - return _EndRecData64(fpin, -sizeEndCentDir, endrec) + return _EndRecData64(fpin, filesize - sizeEndCentDir, endrec) # Either this is not a ZIP file, or it is a ZIP file with an archive # comment. Search the end of the file for the "end of central directory" @@ -382,8 +396,7 @@ def _EndRecData(fpin): endrec.append(maxCommentStart + start) # Try to read the "Zip64 end of central directory" structure - return _EndRecData64(fpin, maxCommentStart + start - filesize, - endrec) + return _EndRecData64(fpin, maxCommentStart + start, endrec) # Unable to find a valid end of central directory structure return None @@ -2142,7 +2155,7 @@ class ZipFile: " would require ZIP64 extensions") zip64endrec = struct.pack( structEndArchive64, stringEndArchive64, - 44, 45, 45, 0, 0, centDirCount, centDirCount, + sizeEndCentDir64 - 12, 45, 45, 0, 0, centDirCount, centDirCount, centDirSize, centDirOffset) self.fp.write(zip64endrec) diff --git a/Lib/zipimport.py b/Lib/zipimport.py index 444c9dd11d8..19279d1c2be 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -10,15 +10,12 @@ used by the builtin import mechanism for sys.path items that are paths to Zip archives. """ -#from importlib import _bootstrap_external -#from importlib import _bootstrap # for _verbose_message import _frozen_importlib_external as _bootstrap_external from _frozen_importlib_external import _unpack_uint16, _unpack_uint32, _unpack_uint64 import _frozen_importlib as _bootstrap # for _verbose_message import _imp # for check_hash_based_pycs import _io # for open import marshal # for loads -import sys # for modules import time # for mktime __all__ = ['ZipImportError', 'zipimporter'] @@ -34,8 +31,6 @@ class ZipImportError(ImportError): # _read_directory() cache _zip_directory_cache = {} -_module_type = type(sys) - END_CENTRAL_DIR_SIZE = 22 END_CENTRAL_DIR_SIZE_64 = 56 END_CENTRAL_DIR_LOCATOR_SIZE_64 = 20 @@ -210,52 +205,6 @@ class zipimporter(_bootstrap_external._LoaderBasics): return mi - # Load and return the module named by 'fullname'. - def load_module(self, fullname): - """load_module(fullname) -> module. - - Load the module specified by 'fullname'. 'fullname' must be the - fully qualified (dotted) module name. It returns the imported - module, or raises ZipImportError if it could not be imported. - - Deprecated since Python 3.10. Use exec_module() instead. - """ - import warnings - warnings._deprecated("zipimport.zipimporter.load_module", - f"{warnings._DEPRECATED_MSG}; " - "use zipimport.zipimporter.exec_module() instead", - remove=(3, 15)) - code, ispackage, modpath = _get_module_code(self, fullname) - mod = sys.modules.get(fullname) - if mod is None or not isinstance(mod, _module_type): - mod = _module_type(fullname) - sys.modules[fullname] = mod - mod.__loader__ = self - - try: - if ispackage: - # add __path__ to the module *before* the code gets - # executed - path = _get_module_path(self, fullname) - fullpath = _bootstrap_external._path_join(self.archive, path) - mod.__path__ = [fullpath] - - if not hasattr(mod, '__builtins__'): - mod.__builtins__ = __builtins__ - _bootstrap_external._fix_up_module(mod.__dict__, fullname, modpath) - exec(code, mod.__dict__) - except: - del sys.modules[fullname] - raise - - try: - mod = sys.modules[fullname] - except KeyError: - raise ImportError(f'Loaded module {fullname!r} not found in sys.modules') - _bootstrap._verbose_message('import {} # loaded from Zip {}', fullname, modpath) - return mod - - def get_resource_reader(self, fullname): """Return the ResourceReader for a module in a zip file.""" from importlib.readers import ZipReader @@ -603,11 +552,16 @@ cp437_table = ( ) _importing_zlib = False +_zlib_decompress = None # Return the zlib.decompress function object, or NULL if zlib couldn't # be imported. The function is cached when found, so subsequent calls # don't import zlib again. -def _get_decompress_func(): +def _get_zlib_decompress_func(): + global _zlib_decompress + if _zlib_decompress: + return _zlib_decompress + global _importing_zlib if _importing_zlib: # Someone has a zlib.py[co] in their Zip file @@ -617,7 +571,7 @@ def _get_decompress_func(): _importing_zlib = True try: - from zlib import decompress + from zlib import decompress as _zlib_decompress except Exception: _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE') raise ZipImportError("can't decompress data; zlib not available") @@ -625,7 +579,54 @@ def _get_decompress_func(): _importing_zlib = False _bootstrap._verbose_message('zipimport: zlib available') - return decompress + return _zlib_decompress + + +_importing_zstd = False +_zstd_decompressor_class = None + +# Return the _zstd.ZstdDecompressor function object, or NULL if _zstd couldn't +# be imported. The result is cached when found. +def _get_zstd_decompressor_class(): + global _zstd_decompressor_class + if _zstd_decompressor_class: + return _zstd_decompressor_class + + global _importing_zstd + if _importing_zstd: + # Someone has a _zstd.py[co] in their Zip file + # let's avoid a stack overflow. + _bootstrap._verbose_message("zipimport: zstd UNAVAILABLE") + raise ZipImportError("can't decompress data; zstd not available") + + _importing_zstd = True + try: + from _zstd import ZstdDecompressor as _zstd_decompressor_class + except Exception: + _bootstrap._verbose_message("zipimport: zstd UNAVAILABLE") + raise ZipImportError("can't decompress data; zstd not available") + finally: + _importing_zstd = False + + _bootstrap._verbose_message("zipimport: zstd available") + return _zstd_decompressor_class + + +def _zstd_decompress(data): + # A simple version of compression.zstd.decompress() as we cannot import + # that here as the stdlib itself could be being zipimported. + results = [] + while True: + decomp = _get_zstd_decompressor_class()() + results.append(decomp.decompress(data)) + if not decomp.eof: + raise ZipImportError("zipimport: zstd compressed data ended before " + "the end-of-stream marker") + data = decomp.unused_data + if not data: + break + return b"".join(results) + # Given a path to a Zip file and a toc_entry, return the (uncompressed) data. def _get_data(archive, toc_entry): @@ -659,16 +660,23 @@ def _get_data(archive, toc_entry): if len(raw_data) != data_size: raise OSError("zipimport: can't read data") - if compress == 0: - # data is not compressed - return raw_data - - # Decompress with zlib - try: - decompress = _get_decompress_func() - except Exception: - raise ZipImportError("can't decompress data; zlib not available") - return decompress(raw_data, -15) + match compress: + case 0: # stored + return raw_data + case 8: # deflate aka zlib + try: + decompress = _get_zlib_decompress_func() + except Exception: + raise ZipImportError("can't decompress data; zlib not available") + return decompress(raw_data, -15) + case 93: # zstd + try: + return _zstd_decompress(raw_data) + except Exception: + raise ZipImportError("could not decompress zstd data") + # bz2 and lzma could be added, but are largely obsolete. + case _: + raise ZipImportError(f"zipimport: unsupported compression {compress}") # Lenient date/time comparison function. The precision of the mtime @@ -734,9 +742,9 @@ def _normalize_line_endings(source): # Given a string buffer containing Python source code, compile it # and return a code object. -def _compile_source(pathname, source): +def _compile_source(pathname, source, module): source = _normalize_line_endings(source) - return compile(source, pathname, 'exec', dont_inherit=True) + return compile(source, pathname, 'exec', dont_inherit=True, module=module) # Convert the date/time values found in the Zip archive to a value # that's compatible with the time stamp stored in .pyc files. @@ -807,7 +815,7 @@ def _get_module_code(self, fullname): except ImportError as exc: import_error = exc else: - code = _compile_source(modpath, data) + code = _compile_source(modpath, data, fullname) if code is None: # bad magic number or non-matching mtime # in byte code, try next diff --git a/Lib/zoneinfo/_tzpath.py b/Lib/zoneinfo/_tzpath.py index 78fa6f00a85..3661c837daa 100644 --- a/Lib/zoneinfo/_tzpath.py +++ b/Lib/zoneinfo/_tzpath.py @@ -13,6 +13,13 @@ def _reset_tzpath(to=None, stacklevel=4): + f"not {type(tzpaths)}: {tzpaths!r}" ) + tzpaths = [os.fspath(p) for p in tzpaths] + if not all(isinstance(p, str) for p in tzpaths): + raise TypeError( + "All elements of a tzpath sequence must be strings or " + "os.PathLike objects which convert to strings." + ) + if not all(map(os.path.isabs, tzpaths)): raise ValueError(_get_invalid_paths_message(tzpaths)) base_tzpath = tzpaths @@ -170,6 +177,10 @@ def available_timezones(): # posixrules is a special symlink-only time zone where it exists, it # should not be included in the output valid_zones.remove("posixrules") + if "localtime" in valid_zones: + # localtime is a special symlink-only time zone where it exists, it + # should not be included in the output + valid_zones.remove("localtime") return valid_zones diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 4da6d924848..1852397ed6f 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 3.0.16", - url="https://github.com/openssl/openssl/releases/download/openssl-3.0.16/openssl-3.0.16.tar.gz", - checksum='57e03c50feab5d31b152af2b764f10379aecd8ee92f16c985983ce4a99f7ef86', + name="OpenSSL 3.5.4", + url="https://github.com/openssl/openssl/releases/download/openssl-3.5.4/openssl-3.5.4.tar.gz", + checksum="967311f84955316969bdb1d8d4b983718ef42338639c621ec4c34fddef355e99", buildrecipe=build_universal_openssl, configure=None, install=None, @@ -264,10 +264,10 @@ def library_recipes(): tk_patches = ['backport_gh71383_fix.patch', 'tk868_on_10_8_10_9.patch', 'backport_gh110950_fix.patch'] else: - tcl_tk_ver='8.6.16' - tcl_checksum='91cb8fa61771c63c262efb553059b7c7ad6757afa5857af6265e4b0bdc2a14a5' + tcl_tk_ver='9.0.2' + tcl_checksum='e074c6a8d9ba2cddf914ba97b6677a552d7a52a3ca102924389a05ccb249b520' - tk_checksum='be9f94d3575d4b3099d84bc3c10de8994df2d7aa405208173c709cc404a7e5fe' + tk_checksum='76fb852b2f167592fe8b41aa6549ce4e486dbf3b259a269646600e3894517c76' tk_patches = [] @@ -378,9 +378,9 @@ def library_recipes(): install=f"make && ranlib libsqlite3.a && make install DESTDIR={shellQuote(os.path.join(WORKDIR, 'libraries'))}", ), dict( - name="libmpdec 4.0.0", - url="https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-4.0.0.tar.gz", - checksum="942445c3245b22730fd41a67a7c5c231d11cb1b9936b9c0f76334fb7d0b4468c", + name="libmpdec 4.0.1", + url="https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-4.0.1.tar.gz", + checksum="96d33abb4bb0070c7be0fed4246cd38416188325f820468214471938545b1ac8", configure_pre=[ "--disable-cxx", "MACHINE=universal", diff --git a/Makefile.pre.in b/Makefile.pre.in index 9ce6ec65f14..a6beb96d12a 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -166,7 +166,7 @@ WHEEL_PKG_DIR= @WHEEL_PKG_DIR@ # Detailed destination directories BINLIBDEST= @BINLIBDEST@ -LIBDEST= $(SCRIPTDIR)/python$(VERSION)$(ABI_THREAD) +LIBDEST= @LIBDEST@ INCLUDEPY= $(INCLUDEDIR)/python$(LDVERSION) CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(LDVERSION) @@ -483,6 +483,7 @@ PYTHON_OBJS= \ Python/pylifecycle.o \ Python/pymath.o \ Python/pystate.o \ + Python/pystats.o \ Python/pythonrun.o \ Python/pytime.o \ Python/qsbr.o \ @@ -501,7 +502,6 @@ PYTHON_OBJS= \ Python/pystrtod.o \ Python/pystrhex.o \ Python/dtoa.o \ - Python/formatter_unicode.o \ Python/fileutils.o \ Python/suggestions.o \ Python/perf_trampoline.o \ @@ -558,8 +558,11 @@ OBJECT_OBJS= \ Objects/tupleobject.o \ Objects/typeobject.o \ Objects/typevarobject.o \ - Objects/unicodeobject.o \ + Objects/unicode_format.o \ + Objects/unicode_formatter.o \ + Objects/unicode_writer.o \ Objects/unicodectype.o \ + Objects/unicodeobject.o \ Objects/unionobject.o \ Objects/weakrefobject.o \ @PERF_TRAMPOLINE_OBJ@ @@ -801,7 +804,7 @@ build_all: check-clean-src check-app-store-compliance $(BUILDPYTHON) platform sh .PHONY: build_wasm build_wasm: check-clean-src $(BUILDPYTHON) platform sharedmods \ - python-config checksharedmods + python-config checksharedmods build-details.json .PHONY: build_emscripten build_emscripten: build_wasm web_example web_example_pyrepl_jspi @@ -834,7 +837,7 @@ check-app-store-compliance: # Profile generation build must start from a clean tree. profile-clean-stamp: - $(MAKE) clean + $(MAKE) clean-profile touch $@ # Compile with profile generation enabled. @@ -1191,14 +1194,12 @@ PYTHON_HEADERS= \ $(srcdir)/Include/intrcheck.h \ $(srcdir)/Include/iterobject.h \ $(srcdir)/Include/listobject.h \ - $(srcdir)/Include/pylock.h \ $(srcdir)/Include/longobject.h \ $(srcdir)/Include/marshal.h \ $(srcdir)/Include/memoryobject.h \ $(srcdir)/Include/methodobject.h \ $(srcdir)/Include/modsupport.h \ $(srcdir)/Include/moduleobject.h \ - $(srcdir)/Include/monitoring.h \ $(srcdir)/Include/object.h \ $(srcdir)/Include/objimpl.h \ $(srcdir)/Include/opcode.h \ @@ -1271,6 +1272,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/pylock.h \ $(srcdir)/Include/cpython/longintrepr.h \ $(srcdir)/Include/cpython/longobject.h \ + $(srcdir)/Include/cpython/marshal.h \ $(srcdir)/Include/cpython/memoryobject.h \ $(srcdir)/Include/cpython/methodobject.h \ $(srcdir)/Include/cpython/modsupport.h \ @@ -1296,6 +1298,8 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/pythonrun.h \ $(srcdir)/Include/cpython/pythread.h \ $(srcdir)/Include/cpython/setobject.h \ + $(srcdir)/Include/cpython/sliceobject.h \ + $(srcdir)/Include/cpython/structseq.h \ $(srcdir)/Include/cpython/traceback.h \ $(srcdir)/Include/cpython/tracemalloc.h \ $(srcdir)/Include/cpython/tupleobject.h \ @@ -1374,6 +1378,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_long.h \ $(srcdir)/Include/internal/pycore_memoryobject.h \ $(srcdir)/Include/internal/pycore_mimalloc.h \ + $(srcdir)/Include/internal/pycore_mmap.h \ $(srcdir)/Include/internal/pycore_modsupport.h \ $(srcdir)/Include/internal/pycore_moduleobject.h \ $(srcdir)/Include/internal/pycore_namespace.h \ @@ -1431,10 +1436,12 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_typeobject.h \ $(srcdir)/Include/internal/pycore_typevarobject.h \ $(srcdir)/Include/internal/pycore_ucnhash.h \ + $(srcdir)/Include/internal/pycore_unicodectype.h \ $(srcdir)/Include/internal/pycore_unicodeobject.h \ $(srcdir)/Include/internal/pycore_unicodeobject_generated.h \ $(srcdir)/Include/internal/pycore_unionobject.h \ $(srcdir)/Include/internal/pycore_uniqueid.h \ + $(srcdir)/Include/internal/pycore_uop.h \ $(srcdir)/Include/internal/pycore_uop_ids.h \ $(srcdir)/Include/internal/pycore_uop_metadata.h \ $(srcdir)/Include/internal/pycore_warnings.h \ @@ -1598,6 +1605,11 @@ sharedmods: $(SHAREDMODS) pybuilddir.txt # dependency on BUILDPYTHON ensures that the target is run last .PHONY: checksharedmods checksharedmods: sharedmods $(PYTHON_FOR_BUILD_DEPS) $(BUILDPYTHON) + @if [ -n "@MISSING_STDLIB_CONFIG@" ]; then \ + $(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/check_extension_modules.py --generate-missing-stdlib-info --with-missing-stdlib-config="@MISSING_STDLIB_CONFIG@"; \ + else \ + $(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/check_extension_modules.py --generate-missing-stdlib-info; \ + fi @$(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/check_extension_modules.py .PHONY: rundsymutil @@ -2089,7 +2101,6 @@ UNICODE_DEPS = \ $(srcdir)/Objects/stringlib/fastsearch.h \ $(srcdir)/Objects/stringlib/find.h \ $(srcdir)/Objects/stringlib/find_max_char.h \ - $(srcdir)/Objects/stringlib/localeutil.h \ $(srcdir)/Objects/stringlib/partition.h \ $(srcdir)/Objects/stringlib/replace.h \ $(srcdir)/Objects/stringlib/repr.h \ @@ -2104,6 +2115,7 @@ Objects/bytes_methods.o: $(srcdir)/Objects/bytes_methods.c $(BYTESTR_DEPS) Objects/bytesobject.o: $(srcdir)/Objects/bytesobject.c $(BYTESTR_DEPS) Objects/bytearrayobject.o: $(srcdir)/Objects/bytearrayobject.c $(BYTESTR_DEPS) +Objects/unicode_format.o: $(srcdir)/Objects/unicode_format.c $(UNICODE_DEPS) Objects/unicodeobject.o: $(srcdir)/Objects/unicodeobject.c $(UNICODE_DEPS) Objects/dictobject.o: $(srcdir)/Objects/stringlib/eq.h @@ -2319,7 +2331,7 @@ testios: fi # Clone the testbed project into the XCFOLDER - $(PYTHON_FOR_BUILD) $(srcdir)/iOS/testbed clone --framework $(PYTHONFRAMEWORKPREFIX) "$(XCFOLDER)" + $(PYTHON_FOR_BUILD) $(srcdir)/Apple/testbed clone --framework $(PYTHONFRAMEWORKPREFIX) "$(XCFOLDER)" # Run the testbed project $(PYTHON_FOR_BUILD) "$(XCFOLDER)" run --verbose -- test -uall --single-process --rerun -W @@ -2362,8 +2374,10 @@ multissltest: all # prevent race conditions with PGO builds. PGO builds use recursive make, # which can lead to two parallel `./python setup.py build` processes that # step on each others toes. +# Only the main install gets a build-details.json. .PHONY: install install: @FRAMEWORKINSTALLFIRST@ @INSTALLTARGETS@ @FRAMEWORKINSTALLLAST@ + $(INSTALL_DATA) `cat pybuilddir.txt`/build-details.json $(DESTDIR)$(LIBDEST); \ if test "x$(ENSUREPIP)" != "xno" ; then \ case $(ENSUREPIP) in \ upgrade) ensurepip="--upgrade" ;; \ @@ -2566,6 +2580,13 @@ LIBSUBDIRS= asyncio \ pathlib \ profile \ profiling profiling/sampling profiling/tracing \ + profiling/sampling/_assets \ + profiling/sampling/_heatmap_assets \ + profiling/sampling/_flamegraph_assets \ + profiling/sampling/_shared_assets \ + profiling/sampling/live_collector \ + profiling/sampling/_vendor/d3/7.8.5 \ + profiling/sampling/_vendor/d3-flame-graph/4.1.3 \ pydoc_data \ re \ site-packages \ @@ -2590,6 +2611,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_ast \ test/test_ast/data \ test/archivetestdata \ + test/audit_test_data \ test/audiodata \ test/certdata \ test/certdata/capath \ @@ -2648,6 +2670,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_importlib/namespace_pkgs \ test/test_importlib/namespace_pkgs/both_portions \ test/test_importlib/namespace_pkgs/both_portions/foo \ + test/test_importlib/namespace_pkgs/foo \ test/test_importlib/namespace_pkgs/module_and_namespace_package \ test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test \ test/test_importlib/namespace_pkgs/not_a_namespace_pkg \ @@ -2670,15 +2693,18 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_importlib/source \ test/test_inspect \ test/test_interpreters \ + test/test_io \ test/test_json \ test/test_module \ test/test_multiprocessing_fork \ test/test_multiprocessing_forkserver \ test/test_multiprocessing_spawn \ + test/test_os \ test/test_pathlib \ test/test_pathlib/support \ test/test_peg_generator \ test/test_profiling \ + test/test_profiling/test_sampling_profiler \ test/test_pydoc \ test/test_pyrepl \ test/test_string \ @@ -2804,7 +2830,7 @@ libinstall: all $(srcdir)/Modules/xxmodule.c done $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py $(DESTDIR)$(LIBDEST); \ $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfig_vars_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).json $(DESTDIR)$(LIBDEST); \ - $(INSTALL_DATA) `cat pybuilddir.txt`/build-details.json $(DESTDIR)$(LIBDEST); \ + $(INSTALL_DATA) `cat pybuilddir.txt`/_missing_stdlib_info.py $(DESTDIR)$(LIBDEST); \ $(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt @ # If app store compliance has been configured, apply the patch to the @ # installed library code. The patch has been previously validated against @@ -3036,6 +3062,9 @@ frameworkinstallunversionedstructure: $(LDLIBRARY) $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR) sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Info.plist $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY) + $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(LIBDIR) + $(LN) -fs "../$(LDLIBRARY)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" + $(LN) -fs "../$(LDLIBRARY)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(BINDIR) for file in $(srcdir)/$(RESSRCDIR)/bin/* ; do \ $(INSTALL) -m $(EXEMODE) $$file $(DESTDIR)$(BINDIR); \ @@ -3108,6 +3137,12 @@ config.status: $(srcdir)/configure Python/asm_trampoline.o: $(srcdir)/Python/asm_trampoline.S $(CC) -c $(PY_CORE_CFLAGS) -o $@ $< +Python/emscripten_trampoline_inner.wasm: $(srcdir)/Python/emscripten_trampoline_inner.c + # emcc has a path that ends with emsdk/upstream/emscripten/emcc, we're looking for emsdk/upstream/bin/clang. + $$(dirname $$(dirname $(CC)))/bin/clang -o $@ $< -mgc -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib + +Python/emscripten_trampoline_wasm.c: Python/emscripten_trampoline_inner.wasm + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/wasm/emscripten/prepare_external_wasm.py $< $@ getWasmTrampolineModule JIT_DEPS = \ $(srcdir)/Tools/jit/*.c \ @@ -3115,7 +3150,7 @@ JIT_DEPS = \ $(srcdir)/Python/executor_cases.c.h \ pyconfig.h -jit_stencils.h: $(JIT_DEPS) +jit_stencils.h @JIT_STENCILS_H@: $(JIT_DEPS) @REGEN_JIT_COMMAND@ Python/jit.o: $(srcdir)/Python/jit.c @JIT_STENCILS_H@ @@ -3216,14 +3251,13 @@ clean-retain-profile: pycremoval -rm -rf Python/deepfreeze -rm -f Python/frozen_modules/*.h -rm -f Python/frozen_modules/MANIFEST - -rm -f jit_stencils.h -find build -type f -a ! -name '*.gc??' -exec rm -f {} ';' -rm -f Include/pydtrace_probes.h -rm -f profile-gen-stamp - -rm -rf iOS/testbed/Python.xcframework/ios-*/bin - -rm -rf iOS/testbed/Python.xcframework/ios-*/lib - -rm -rf iOS/testbed/Python.xcframework/ios-*/include - -rm -rf iOS/testbed/Python.xcframework/ios-*/Python.framework + -rm -rf Apple/iOS/testbed/Python.xcframework/ios-*/bin + -rm -rf Apple/iOS/testbed/Python.xcframework/ios-*/lib + -rm -rf Apple/iOS/testbed/Python.xcframework/ios-*/include + -rm -rf Apple/iOS/testbed/Python.xcframework/ios-*/Python.framework .PHONY: profile-removal profile-removal: @@ -3235,13 +3269,21 @@ profile-removal: rm -f profile-run-stamp rm -f profile-bolt-stamp -.PHONY: clean -clean: clean-retain-profile clean-bolt +.PHONY: clean-profile +clean-profile: clean-retain-profile clean-bolt @if test @DEF_MAKE_ALL_RULE@ = profile-opt -o @DEF_MAKE_ALL_RULE@ = bolt-opt; then \ rm -f profile-gen-stamp profile-clean-stamp; \ $(MAKE) profile-removal; \ fi +# gh-141808: The JIT stencils are deliberately kept in clean-profile +.PHONY: clean-jit-stencils +clean-jit-stencils: + -rm -f jit_stencils*.h + +.PHONY: clean +clean: clean-profile clean-jit-stencils + .PHONY: clobber clobber: clean -rm -f $(BUILDPYTHON) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ @@ -3249,7 +3291,7 @@ clobber: clean config.cache config.log pyconfig.h Modules/config.c -rm -rf build platform -rm -rf $(PYTHONFRAMEWORKDIR) - -rm -rf iOS/Frameworks + -rm -rf Apple/iOS/Frameworks -rm -rf iOSTestbed.* -rm -f python-config.py python-config -rm -rf cross-build @@ -3289,6 +3331,11 @@ check-c-globals: --format summary \ --traceback +# Check for undocumented C APIs. +.PHONY: check-c-api-docs +check-c-api-docs: + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/check-c-api-docs/main.py + # Find files with funny names .PHONY: funny funny: @@ -3361,6 +3408,7 @@ MODULE__DECIMAL_DEPS=@LIBMPDEC_INTERNAL@ MODULE__ELEMENTTREE_DEPS=$(srcdir)/Modules/pyexpat.c @LIBEXPAT_INTERNAL@ MODULE__HASHLIB_DEPS=$(srcdir)/Modules/hashlib.h MODULE__IO_DEPS=$(srcdir)/Modules/_io/_iomodule.h +MODULE__REMOTE_DEBUGGING_DEPS=$(srcdir)/Modules/_remote_debugging/_remote_debugging.h # HACL*-based cryptographic primitives MODULE__MD5_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_MD5_HEADERS) $(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@) diff --git a/Misc/ACKS b/Misc/ACKS index dc28ccf8f57..a14089a39cc 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -210,6 +210,7 @@ Médéric Boquien Matias Bordese Jonas Borgström Jurjen Bos +Jeffrey Bosboom Peter Bosch Dan Boswell Eric Bouck @@ -483,6 +484,7 @@ Weilin Du John DuBois Paul Dubois Jacques Ducasse +Jadon Duff Andrei Dorian Duma Graham Dumpleton Quinn Dunkan @@ -621,6 +623,7 @@ Soumendra Ganguly (गङ्गोपाध्याय) Fred Gansevles Paul Ganssle Tian Gao +Katie Gardner Lars Marius Garshol Jake Garver Dan Gass @@ -905,6 +908,8 @@ Jim Jewett Pedro Diaz Jimenez Orjan Johansen Fredrik Johansson +Benjamin Johnson +Benjamin K. Johnson Gregory K. Johnson Kent Johnson Michael Johnson @@ -923,6 +928,7 @@ Kristján Valur Jónsson Jens B. Jorgensen John Jorgensen Sijin Joseph +Paresh Joshi Andreas Jung Tattoo Mabonzo K. Sarah K. @@ -1677,6 +1683,7 @@ David Scherer Wolfgang Scherer Felix Scherz Hynek Schlawack +Jakob Schluse Bob Schmertz Gregor Schmid Ralf Schmitt @@ -1916,6 +1923,7 @@ Tim Tisdall Jason Tishler Christian Tismer Jim Tittsler +Abhishek Tiwari Frank J. Tobin James Tocknell Bennett Todd @@ -2112,6 +2120,7 @@ Xiang Zhang Robert Xiao Florent Xicluna Yanbo, Xie +Kaisheng Xu Xinhang Xu Arnon Yaari Alakshendra Yadav diff --git a/Misc/NEWS.d/3.10.0a1.rst b/Misc/NEWS.d/3.10.0a1.rst index f09842f1e77..473e7c7ac0f 100644 --- a/Misc/NEWS.d/3.10.0a1.rst +++ b/Misc/NEWS.d/3.10.0a1.rst @@ -3275,8 +3275,8 @@ Types created with :c:func:`PyType_FromSpec` now make any signature in their .. nonce: u6Xfr2 .. section: C API -Fix bug in PyOS_mystrnicmp and PyOS_mystricmp that incremented pointers -beyond the end of a string. +Fix bug in :c:func:`PyOS_mystrnicmp` and :c:func:`PyOS_mystricmp` that +incremented pointers beyond the end of a string. .. diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index 3e82de9ef26..263b8cb9762 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -593,7 +593,7 @@ of treating them as a match. .. nonce: ONk9Na .. section: Library -Fix ``--outfile`` for :mod:`cProfile` / :mod:`profile` not writing the +Fix ``--outfile`` for :mod:`!cProfile` / :mod:`!profile` not writing the output file in the original directory when the program being profiled changes the working directory. PR by Anthony Sottile. diff --git a/Misc/NEWS.d/3.10.0a5.rst b/Misc/NEWS.d/3.10.0a5.rst index a85ea1ff1c2..d2bac5d13e9 100644 --- a/Misc/NEWS.d/3.10.0a5.rst +++ b/Misc/NEWS.d/3.10.0a5.rst @@ -426,7 +426,7 @@ specified using a relative path and the current directory changed. .. nonce: Jq6Az- .. section: Library -Fix CLI of :mod:`cProfile` and :mod:`profile` to catch +Fix CLI of :mod:`!cProfile` and :mod:`!profile` to catch :exc:`BrokenPipeError`. .. diff --git a/Misc/NEWS.d/3.10.0b1.rst b/Misc/NEWS.d/3.10.0b1.rst index 406a5d7853e..5bc78b9007a 100644 --- a/Misc/NEWS.d/3.10.0b1.rst +++ b/Misc/NEWS.d/3.10.0b1.rst @@ -402,8 +402,8 @@ the heap. Should speed up dispatch in the interpreter. .. nonce: eUn4p5 .. section: Core and Builtins -Static methods (:func:`@staticmethod <staticmethod>`) and class methods -(:func:`@classmethod <classmethod>`) now inherit the method attributes +Static methods (:deco:`staticmethod`) and class methods +(:deco:`classmethod`) now inherit the method attributes (``__module__``, ``__name__``, ``__qualname__``, ``__doc__``, ``__annotations__``) and have a new ``__wrapped__`` attribute. Patch by Victor Stinner. @@ -454,7 +454,7 @@ file locations. .. nonce: VSF3vg .. section: Core and Builtins -Static methods (:func:`@staticmethod <staticmethod>`) are now callable as +Static methods (:deco:`staticmethod`) are now callable as regular functions. Patch by Victor Stinner. .. diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index 2c8e349d3c8..10ef2968db2 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -2953,7 +2953,7 @@ support for Metadata 2.2. .. nonce: xTUyyX .. section: Library -Remove the :func:`@asyncio.coroutine <asyncio.coroutine>` :term:`decorator` +Remove the :deco:`asyncio.coroutine` :term:`decorator` enabling legacy generator-based coroutines to be compatible with async/await code; remove :class:`asyncio.coroutines.CoroWrapper` used for wrapping legacy coroutine objects in the debug mode. The decorator has been diff --git a/Misc/NEWS.d/3.11.0a2.rst b/Misc/NEWS.d/3.11.0a2.rst index 48cf2c1e428..12e03b46db0 100644 --- a/Misc/NEWS.d/3.11.0a2.rst +++ b/Misc/NEWS.d/3.11.0a2.rst @@ -1188,7 +1188,7 @@ context objects can now be disabled. .. nonce: Z0Zk_m .. section: C API -Exclude :c:func:`PyWeakref_GET_OBJECT` from the limited C API. It never +Exclude :c:func:`!PyWeakref_GET_OBJECT` from the limited C API. It never worked since the :c:type:`!PyWeakReference` structure is opaque in the limited C API. diff --git a/Misc/NEWS.d/3.11.0b1.rst b/Misc/NEWS.d/3.11.0b1.rst index c3a1942b881..7b8b983ebf9 100644 --- a/Misc/NEWS.d/3.11.0b1.rst +++ b/Misc/NEWS.d/3.11.0b1.rst @@ -664,7 +664,7 @@ for :func:`os.fcopyfile` available in macOs. .. nonce: l1p7CJ .. section: Library -For :func:`@dataclass <dataclasses.dataclass>`, add *weakref_slot*. +For :deco:`~dataclasses.dataclass`, add *weakref_slot*. The new parameter defaults to ``False``. If true, and if ``slots=True``, add a slot named ``"__weakref__"``, which will allow instances to be weakref'd. Contributed by Eric V. Smith diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index f2668e99a62..0da7cdde1b2 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -4330,7 +4330,7 @@ and ``sendfile`` inside ``IocpProactor``. .. nonce: GsBL9- .. section: Library -Fixed :meth:`collections.UserDict.get` to not call :meth:`__missing__` when +Fixed :meth:`collections.UserDict.get` to not call :meth:`~object.__missing__` when a value is not found. This matches the behavior of :class:`dict`. Patch by Bar Harel. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index bc028f30636..20e27c0d92f 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -35,11 +35,11 @@ Update bundled libexpat to 2.5.0 .. nonce: ik4iOv .. section: Core and Builtins -The docs clearly say that ``PyImport_Inittab``, +The docs clearly say that :c:data:`PyImport_Inittab`, :c:func:`PyImport_AppendInittab`, and :c:func:`PyImport_ExtendInittab` should not be used after :c:func:`Py_Initialize` has been called. We now enforce this for the two functions. Additionally, the runtime now uses an -internal copy of ``PyImport_Inittab``, to guard against modification. +internal copy of :c:data:`PyImport_Inittab`, to guard against modification. .. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index 3a3870ac9fe..b867a4f6230 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -1257,7 +1257,7 @@ defined by any build system or documented for manual use. .. nonce: n_AfcS .. section: Library -Update :mod:`cProfile` to use PEP 669 API +Update :mod:`!cProfile` to use PEP 669 API .. diff --git a/Misc/NEWS.d/3.13.0a1.rst b/Misc/NEWS.d/3.13.0a1.rst index 0741eab4eca..0b7b69bbcb2 100644 --- a/Misc/NEWS.d/3.13.0a1.rst +++ b/Misc/NEWS.d/3.13.0a1.rst @@ -3426,7 +3426,7 @@ This bug was introduced in Python 3.12.0 beta 1. .. nonce: hSlB17 .. section: Library -Deprecate :func:`typing.no_type_check_decorator`. No major type checker ever +Deprecate :func:`!typing.no_type_check_decorator`. No major type checker ever added support for this decorator. Patch by Alex Waygood. .. @@ -3476,7 +3476,7 @@ Fix rare concurrency bug in lock acquisition by the logging package. .. nonce: ya5jBT .. section: Library -Added PY_THROW event hook for :mod:`cProfile` for generators +Added PY_THROW event hook for :mod:`!cProfile` for generators .. @@ -6458,8 +6458,8 @@ Victor Stinner. .. nonce: GRxZtI .. section: C API -Deprecate the :c:func:`PyWeakref_GetObject` and -:c:func:`PyWeakref_GET_OBJECT` functions: use the new +Deprecate the :c:func:`!PyWeakref_GetObject` and +:c:func:`!PyWeakref_GET_OBJECT` functions: use the new :c:func:`PyWeakref_GetRef` function instead. Patch by Victor Stinner. .. @@ -6470,7 +6470,7 @@ Deprecate the :c:func:`PyWeakref_GetObject` and .. section: C API Add :c:func:`PyWeakref_GetRef` function: similar to -:c:func:`PyWeakref_GetObject` but returns a :term:`strong reference`, or +:c:func:`!PyWeakref_GetObject` but returns a :term:`strong reference`, or ``NULL`` if the referent is no longer live. Patch by Victor Stinner. .. @@ -6592,7 +6592,7 @@ functions, deprecated in Python 3.9. Patch by Victor Stinner. Deprecate old Python initialization functions: -* :c:func:`PySys_ResetWarnOptions` +* :c:func:`!PySys_ResetWarnOptions` * :c:func:`!Py_GetExecPrefix` * :c:func:`!Py_GetPath` * :c:func:`!Py_GetPrefix` diff --git a/Misc/NEWS.d/3.13.0a5.rst b/Misc/NEWS.d/3.13.0a5.rst index d56b1542b01..19ba16bc8c8 100644 --- a/Misc/NEWS.d/3.13.0a5.rst +++ b/Misc/NEWS.d/3.13.0a5.rst @@ -742,8 +742,8 @@ Add ``windows_31j`` to aliases for ``cp932`` codec .. nonce: fv35wU .. section: Library -:func:`functools.partial`s of :func:`repr` has been improved to include the -:term:`module` name. Patched by Furkan Onder and Anilyka Barry. +Always include the :term:`module` name in the :func:`repr` of +:func:`functools.partial` objects. Patch by Furkan Onder and Anilyka Barry. .. diff --git a/Misc/NEWS.d/3.13.0a6.rst b/Misc/NEWS.d/3.13.0a6.rst index 2740b4f0d96..ad6622d23bf 100644 --- a/Misc/NEWS.d/3.13.0a6.rst +++ b/Misc/NEWS.d/3.13.0a6.rst @@ -264,7 +264,8 @@ Improve performance of :func:`os.path.join` and :func:`os.path.expanduser`. .. nonce: hqk9Hn .. section: Library -Raise :exc:`TypeError` for non-paths in :func:`posixpath.relpath`. +Raise :exc:`TypeError` for non-paths in :func:`posixpath.relpath +<os.path.relpath>`. .. @@ -273,7 +274,8 @@ Raise :exc:`TypeError` for non-paths in :func:`posixpath.relpath`. .. nonce: l6rWlj .. section: Library -Preserve mailbox ownership when rewriting in :func:`mailbox.mbox.flush`. +Preserve mailbox ownership when rewriting in :func:`mailbox.mbox.flush +<mailbox.Mailbox.flush>`. Patch by Tony Mountifield. .. diff --git a/Misc/NEWS.d/3.14.0a1.rst b/Misc/NEWS.d/3.14.0a1.rst index 67451a7e008..5303bd89eff 100644 --- a/Misc/NEWS.d/3.14.0a1.rst +++ b/Misc/NEWS.d/3.14.0a1.rst @@ -1999,7 +1999,7 @@ with an escape character. .. nonce: vi2bP- .. section: Library -:func:`@warnings.deprecated <warnings.deprecated>` now copies the coroutine +:deco:`warnings.deprecated` now copies the coroutine status of functions and methods so that :func:`inspect.iscoroutinefunction` returns the correct result. @@ -2623,7 +2623,7 @@ Fix :func:`unittest.mock.patch` to not read attributes of the target when .. nonce: s4HXR0 .. section: Library -Fixed the use-after-free issue in :mod:`cProfile` by disallowing +Fixed the use-after-free issue in :mod:`!cProfile` by disallowing ``disable()`` and ``clear()`` in external timers. .. @@ -4016,7 +4016,7 @@ Make ``this_instr`` and ``prev_instr`` const in cases generator. .. date: 2024-10-05-23-53-06 .. gh-issue: 125008 .. nonce: ETANpd -.. section: Core and Builtins +.. section: Library Fix :func:`tokenize.untokenize` producing invalid syntax for double braces preceded by certain escape characters. @@ -4275,7 +4275,7 @@ devdanzin .. date: 2024-09-02-20-39-10 .. gh-issue: 123614 .. nonce: 26TMHp -.. section: Core and Builtins +.. section: Library Add :func:`turtle.save` to easily save Turtle drawings as PostScript files. Patch by Marie Roald and Yngve Mardal Moe. @@ -4761,7 +4761,7 @@ enabled (yet). .. date: 2024-07-18-21-19-04 .. gh-issue: 121999 .. nonce: 8IBbTK -.. section: Core and Builtins +.. section: Library The default extraction filter for the :mod:`tarfile` module is now set to :func:`'data' <tarfile.data_filter>`. @@ -4913,11 +4913,11 @@ Allow tuples of length 20 in the freelist to be reused. .. nonce: lYKYYP .. section: Core and Builtins -:exc:`ValueError` messages for :meth:`!list.index`, :meth:`!range.index`, +:exc:`ValueError` messages for :meth:`list.index`, :meth:`range.index`, :meth:`!deque.index`, :meth:`!deque.remove` and :meth:`!ShareableList.index` no longer contain the repr of the searched value (which can be arbitrary -large) and are consistent with error messages for other :meth:`!index` and -:meth:`!remove` methods. +large) and are consistent with error messages for other :meth:`~sequence.index` and +:meth:`~sequence.remove` methods. .. @@ -4955,7 +4955,7 @@ Galindo .. date: 2024-06-28-23-17-22 .. gh-issue: 121381 .. nonce: i2xL7P -.. section: Core and Builtins +.. section: Library Remove ``subprocess._USE_VFORK`` escape hatch code and documentation. It was added just in case, and doesn't have any known cases that require it. @@ -5115,7 +5115,7 @@ and identities of :class:`str` objects. .. date: 2024-06-14-07-52-00 .. gh-issue: 120485 .. nonce: yy4K4b -.. section: Core and Builtins +.. section: Library Add an override of ``allow_reuse_port`` on classes subclassing ``socketserver.TCPServer`` where ``allow_reuse_address`` is also overridden. @@ -5147,7 +5147,7 @@ after exception handlers are moved to the end of the code. .. date: 2024-06-12-18-23-15 .. gh-issue: 120380 .. nonce: edtqjq -.. section: Core and Builtins +.. section: Library Fix Python implementation of :class:`pickle.Pickler` for :class:`bytes` and :class:`bytearray` objects when using protocol version 5. Patch by Bénédikt @@ -5604,7 +5604,7 @@ Using :data:`NotImplemented` in a boolean context now raises .. nonce: wNMKVd .. section: Core and Builtins -Fix race condition in free-threaded build where :meth:`!list.extend` could +Fix race condition in free-threaded build where :meth:`list.extend` could expose uninitialised memory to concurrent readers. .. @@ -5625,7 +5625,7 @@ in the future. .. date: 2024-04-27-18-36-46 .. gh-issue: 115801 .. nonce: SVeHSy -.. section: Core and Builtins +.. section: Library Raise ``TypeError`` when passing a string to :func:`difflib.unified_diff` and :func:`difflib.context_diff`. @@ -6092,7 +6092,7 @@ Patch by Victor Stinner. .. nonce: qOr9GF .. section: C API -Soft deprecate the :c:macro:`!Py_MEMCPY` macro: use directly ``memcpy()`` +Soft deprecate the :c:macro:`Py_MEMCPY` macro: use directly ``memcpy()`` instead. Patch by Victor Stinner. .. diff --git a/Misc/NEWS.d/3.14.0a2.rst b/Misc/NEWS.d/3.14.0a2.rst index 7405a1344a9..2fd86dbe72a 100644 --- a/Misc/NEWS.d/3.14.0a2.rst +++ b/Misc/NEWS.d/3.14.0a2.rst @@ -1253,7 +1253,7 @@ including SerenityOS. .. date: 2024-11-09-16-10-22 .. gh-issue: 126066 .. nonce: 9zs4m4 -.. section: Core and Builtins +.. section: Library Fix :mod:`importlib` to not write an incomplete .pyc files when a ulimit or some other operating system mechanism is preventing the write to go through @@ -1285,7 +1285,7 @@ its ``__iter__``. .. date: 2024-11-02-18-01-31 .. gh-issue: 126209 .. nonce: 2ZIhrS -.. section: Core and Builtins +.. section: Library Fix an issue with ``skip_file_prefixes`` parameter which resulted in an inconsistent behaviour between the C and Python implementations of @@ -1400,7 +1400,7 @@ The :class:`memoryview` type now supports subscription, making it a .. nonce: KlCdgD .. section: Core and Builtins -Adds :opcode:`LOAD_SMALL_INT` and :opcode:`LOAD_CONST_IMMORTAL` +Adds :opcode:`LOAD_SMALL_INT` and :opcode:`!LOAD_CONST_IMMORTAL` instructions. ``LOAD_SMALL_INT`` pushes a small integer equal to the ``oparg`` to the stack. ``LOAD_CONST_IMMORTAL`` does the same as ``LOAD_CONST`` but is more efficient for immortal objects. Removes @@ -1567,7 +1567,7 @@ Wannes Boeykens. .. date: 2024-05-12-03-10-36 .. gh-issue: 118950 .. nonce: 5Wc4vp -.. section: Core and Builtins +.. section: Library Fix bug where SSLProtocol.connection_lost wasn't getting called when OSError was thrown on writing to socket. @@ -1577,7 +1577,7 @@ was thrown on writing to socket. .. date: 2023-12-30-00-21-45 .. gh-issue: 113570 .. nonce: _XQgsW -.. section: Core and Builtins +.. section: Library Fixed a bug in ``reprlib.repr`` where it incorrectly called the repr method on shadowed Python built-in types. diff --git a/Misc/NEWS.d/3.14.0a3.rst b/Misc/NEWS.d/3.14.0a3.rst index 8393be8909f..b4264335a2d 100644 --- a/Misc/NEWS.d/3.14.0a3.rst +++ b/Misc/NEWS.d/3.14.0a3.rst @@ -820,7 +820,7 @@ Fix possible undefined behavior division by zero in :class:`complex`'s .. date: 2024-11-23-04-54-42 .. gh-issue: 127133 .. nonce: WMoJjF -.. section: Core and Builtins +.. section: Library Calling :meth:`argparse.ArgumentParser.add_argument_group` on an argument group, and calling :meth:`argparse.ArgumentParser.add_argument_group` or diff --git a/Misc/NEWS.d/3.14.0a4.rst b/Misc/NEWS.d/3.14.0a4.rst index 176ba72da65..94350556093 100644 --- a/Misc/NEWS.d/3.14.0a4.rst +++ b/Misc/NEWS.d/3.14.0a4.rst @@ -548,7 +548,7 @@ atomic operation. Patch by Donghee Na. .. date: 2024-12-23-11-14-07 .. gh-issue: 128192 .. nonce: 02mEhD -.. section: Core and Builtins +.. section: Library Upgrade HTTP digest authentication algorithm for :mod:`urllib.request` by supporting SHA-256 digest authentication as specified in :rfc:`7616`. @@ -613,7 +613,7 @@ object when importing a non-existent symbol from a non-module object. .. date: 2024-12-17-18-20-37 .. gh-issue: 128035 .. nonce: JwqHdB -.. section: Core and Builtins +.. section: Library Indicate through :data:`ssl.HAS_PHA` whether the :mod:`ssl` module supports TLSv1.3 post-handshake client authentication (PHA). Patch by Will diff --git a/Misc/NEWS.d/3.14.0a5.rst b/Misc/NEWS.d/3.14.0a5.rst index a3548d0a7b0..6242fce823c 100644 --- a/Misc/NEWS.d/3.14.0a5.rst +++ b/Misc/NEWS.d/3.14.0a5.rst @@ -944,7 +944,7 @@ It is always ``'freebsd'``, instead of ``'freebsd13'`` or ``'freebsd14'``. .. date: 2025-01-28-06-23-59 .. gh-issue: 129345 .. nonce: uOjkML -.. section: Core and Builtins +.. section: Library Fix null pointer dereference in :func:`syslog.openlog` when an audit hook raises an exception. @@ -1197,7 +1197,7 @@ generator. Patch by Mikhail Efimov. .. date: 2024-11-03-06-05-16 .. gh-issue: 126349 .. nonce: 7YwWsI -.. section: Core and Builtins +.. section: Library Add :func:`turtle.fill`, :func:`turtle.poly` and :func:`turtle.no_animation` context managers. Patch by Marie Roald and Yngve Mardal Moe. @@ -1218,7 +1218,7 @@ Willmer. .. date: 2023-12-04-15-53-25 .. gh-issue: 112713 .. nonce: Zrhv77 -.. section: Core and Builtins +.. section: Library Added support for the ``Partitioned`` cookie flag in :mod:`http.cookies`. diff --git a/Misc/NEWS.d/3.14.0a6.rst b/Misc/NEWS.d/3.14.0a6.rst index d8840b6f283..5fb5306eeae 100644 --- a/Misc/NEWS.d/3.14.0a6.rst +++ b/Misc/NEWS.d/3.14.0a6.rst @@ -621,7 +621,7 @@ Andrew Svetlov. .. nonce: jQ0CvW .. section: Library -Update the deprecation warning of :meth:`importlib.abc.Loader.load_module`. +Update the deprecation warning of ``importlib.abc.Loader.load_module``. .. @@ -758,7 +758,7 @@ Patch by Semyon Moroz. .. nonce: wDLTay .. section: Library -Delay deprecated :meth:`zipimport.zipimporter.load_module` removal time to +Delay deprecated :meth:`!zipimport.zipimporter.load_module` removal time to 3.15. Use :meth:`zipimport.zipimporter.exec_module` instead. .. @@ -1187,7 +1187,7 @@ Improve the experimental JIT's handling of returns to unknown callers. .. date: 2025-02-11-20-38-37 .. gh-issue: 129983 .. nonce: _1Fujo -.. section: Core and Builtins +.. section: Library Fix data race in compile_template in :file:`sre.c`. @@ -1335,7 +1335,7 @@ interpreter state. .. date: 2022-12-21-14-28-01 .. gh-issue: 100388 .. nonce: vne8ky -.. section: Core and Builtins +.. section: Library Fix the ``platform._sys_version()`` method when ``__DATE__`` is undefined at buildtime by changing default buildtime datetime string to the UNIX epoch. diff --git a/Misc/NEWS.d/3.14.0a7.rst b/Misc/NEWS.d/3.14.0a7.rst index 35b96d33da4..752d8be8dc8 100644 --- a/Misc/NEWS.d/3.14.0a7.rst +++ b/Misc/NEWS.d/3.14.0a7.rst @@ -192,7 +192,7 @@ The :class:`ctypes.py_object` type now supports subscription, making it a .. nonce: cX4yTn .. section: Library -Add the :attr:`zipfile.ZipFile.data_offset` attribute, which stores the +Add the :attr:`!zipfile.ZipFile.data_offset` attribute, which stores the offset to the beginning of ZIP data in a file when available. When the :class:`zipfile.ZipFile` is opened in either mode ``'w'`` or ``'x'`` and the underlying file does not support ``tell()``, the value will be ``None`` @@ -671,7 +671,7 @@ Allow the JIT to remove an extra ``_TO_BOOL_BOOL`` instruction after .. nonce: dNh64H .. section: Core and Builtins -Fix crash when calling :meth:`!list.append` as an unbound method. +Fix crash when calling :meth:`list.append` as an unbound method. .. @@ -880,7 +880,7 @@ Fix an issue with thread identifiers being sign-extended on some platforms. .. date: 2025-02-15-14-36-32 .. gh-issue: 99108 .. nonce: u6CfmK -.. section: Core and Builtins +.. section: Library Add support for built-in implementation of HMAC (:rfc:`2104`) based on HACL*. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/3.14.0b1.rst b/Misc/NEWS.d/3.14.0b1.rst index 5d03d429f9e..045c47ce5ad 100644 --- a/Misc/NEWS.d/3.14.0b1.rst +++ b/Misc/NEWS.d/3.14.0b1.rst @@ -747,7 +747,7 @@ caches. .. nonce: APBFCw .. section: Library -Fixed the :exc:`SystemError` in :mod:`cProfile` when locating the actual C +Fixed the :exc:`SystemError` in :mod:`!cProfile` when locating the actual C function of a method raises an exception. .. @@ -1325,7 +1325,7 @@ Add new utilities of observing JIT compilation: .. date: 2025-04-30-13-09-20 .. gh-issue: 133194 .. nonce: 25_G5c -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse new :pep:`758` syntax with older *feature_version* passed. @@ -1498,7 +1498,7 @@ helpful fix suggestion for the typo. Contributed by Pablo Galindo Salgado. .. date: 2025-04-19-18-07-34 .. gh-issue: 132737 .. nonce: 9mW1il -.. section: Core and Builtins +.. section: Library Support profiling code that requires ``__main__``, such as :mod:`pickle`. @@ -1891,7 +1891,7 @@ Steven Sun) .. date: 2022-12-29-19-10-36 .. gh-issue: 89562 .. nonce: g8m8RC -.. section: Core and Builtins +.. section: Library Remove ``hostflags`` member from ``PySSLContext`` struct. diff --git a/Misc/NEWS.d/3.15.0a1.rst b/Misc/NEWS.d/3.15.0a1.rst new file mode 100644 index 00000000000..f6c78879890 --- /dev/null +++ b/Misc/NEWS.d/3.15.0a1.rst @@ -0,0 +1,6438 @@ +.. date: 2025-10-14-00-17-48 +.. gh-issue: 115119 +.. nonce: 470I1N +.. release date: 2025-10-14 +.. section: macOS + +Update macOS installer to use libmpdecimal 4.0.1. + +.. + +.. date: 2025-10-14-00-08-16 +.. gh-issue: 124111 +.. nonce: 7-j-DQ +.. section: macOS + +Update macOS installer to use Tcl/Tk 9.0.2. + +.. + +.. date: 2025-10-13-23-46-12 +.. gh-issue: 132339 +.. nonce: kAp603 +.. section: macOS + +Update macOS installer version of OpenSSL to 3.5.4. + +.. + +.. date: 2025-08-06-06-29-12 +.. gh-issue: 137450 +.. nonce: JZypb7 +.. section: macOS + +macOS installer shell path management improvements: separate the installer +``Shell profile updater`` postinstall script from the ``Update Shell +Profile.command`` to enable more robust error handling. + +.. + +.. date: 2025-07-27-02-17-40 +.. gh-issue: 137134 +.. nonce: pjgITs +.. section: macOS + +Update macOS installer to ship with SQLite version 3.50.4. + +.. + +.. date: 2025-10-08-22-54-38 +.. gh-issue: 139810 +.. nonce: LAaemi +.. section: Windows + +Installing with ``py install 3[.x]-dev`` will now select final versions as +well as prereleases. + +.. + +.. date: 2025-10-04-12-18-45 +.. gh-issue: 139573 +.. nonce: EO9kVB +.. section: Windows + +Updated bundled version of OpenSSL to 3.0.18. + +.. + +.. date: 2025-09-15-15-34-29 +.. gh-issue: 138896 +.. nonce: lkiF_7 +.. section: Windows + +Fix error installing C runtime on non-updated Windows machines + +.. + +.. date: 2025-09-03-01-07-44 +.. gh-issue: 138314 +.. nonce: IeWQ2i +.. section: Windows + +Add :func:`winreg.DeleteTree`. + +.. + +.. date: 2025-07-27-14-25-11 +.. gh-issue: 137136 +.. nonce: xNthFT +.. section: Windows + +Suppress build warnings when build on Windows with +``--experimental-jit-interpreter``. + +.. + +.. date: 2025-07-27-02-16-53 +.. gh-issue: 137134 +.. nonce: W0WpDF +.. section: Windows + +Update Windows installer to ship with SQLite 3.50.4. + +.. + +.. date: 2025-06-03-18-26-54 +.. gh-issue: 135099 +.. nonce: Q9usKm +.. section: Windows + +Fix a crash that could occur on Windows when a background thread waits on a +:c:type:`PyMutex` while the main thread is shutting down the interpreter. + +.. + +.. date: 2025-05-20-21-43-20 +.. gh-issue: 130727 +.. nonce: -69t4D +.. section: Windows + +Fix a race in internal calls into WMI that can result in an "invalid handle" +exception under high load. Patch by Chris Eibl. + +.. + +.. date: 2025-05-19-03-02-04 +.. gh-issue: 76023 +.. nonce: vHOf6M +.. section: Windows + +Make :func:`os.path.realpath` ignore Windows error 1005 when in non-strict +mode. + +.. + +.. date: 2025-05-13-13-25-27 +.. gh-issue: 133779 +.. nonce: -YcTBz +.. section: Windows + +Reverts the change to generate different :file:`pyconfig.h` files based on +compiler settings, as it was frequently causing extension builds to break. +In particular, the ``Py_GIL_DISABLED`` preprocessor variable must now always +be defined explicitly when compiling for the experimental free-threaded +runtime. The :func:`sysconfig.get_config_var` function can be used to +determine whether the current runtime was compiled with that flag or not. + +.. + +.. date: 2025-05-08-19-07-26 +.. gh-issue: 133626 +.. nonce: yFTKYK +.. section: Windows + +Ensures packages are not accidentally bundled into the traditional +installer. + +.. + +.. date: 2025-05-07-13-04-22 +.. gh-issue: 133580 +.. nonce: jBMujJ +.. section: Windows + +Fix :func:`sys.getwindowsversion` failing without setting an exception when +called on some WinAPI partitions. + +.. + +.. date: 2025-05-07-11-45-30 +.. gh-issue: 133572 +.. nonce: Xc2zxH +.. section: Windows + +Avoid LsaNtStatus to WinError conversion on unsupported WinAPI partitions. + +.. + +.. date: 2025-05-07-11-25-29 +.. gh-issue: 133568 +.. nonce: oYV0d8 +.. section: Windows + +Fix compile error when using a WinAPI partition that doesn't support the RPC +runtime library. + +.. + +.. date: 2025-05-07-09-02-19 +.. gh-issue: 133562 +.. nonce: lqqNW1 +.. section: Windows + +Disable handling of security descriptors by :func:`os.mkdir` with mode +``0o700`` on WinAPI partitions that do not support it. This only affects +custom builds for specialized targets. + +.. + +.. date: 2025-05-07-08-19-15 +.. gh-issue: 133537 +.. nonce: yzf963 +.. section: Windows + +Avoid using console I/O in WinAPI partitions that don’t support it + +.. + +.. date: 2025-03-31-15-37-57 +.. gh-issue: 131942 +.. nonce: jip_aL +.. section: Windows + +Use the Python-specific :c:macro:`Py_DEBUG` macro rather than +:c:macro:`!_DEBUG` in Windows-related C code. Patch by Xuehai Pan. + +.. + +.. date: 2025-09-25-10-31-02 +.. gh-issue: 139330 +.. nonce: 5WWkY0 +.. section: Tools/Demos + +SBOM generation tool didn't cross-check the version and checksum values +against the ``Modules/expat/refresh.sh`` script, leading to the values +becoming out-of-date during routine updates. + +.. + +.. date: 2025-08-28-06-22-26 +.. gh-issue: 132006 +.. nonce: eZQmc6 +.. section: Tools/Demos + +XCframeworks now include privacy manifests to satisfy Apple App Store +submission requirements. + +.. + +.. date: 2025-08-27-11-14-53 +.. gh-issue: 138171 +.. nonce: Suz8ob +.. section: Tools/Demos + +A script for building an iOS XCframework was added. As part of this change, +the top level ``iOS`` folder has been moved to be a subdirectory of the +``Apple`` folder. + +.. + +.. date: 2025-08-21-14-04-50 +.. gh-issue: 137873 +.. nonce: qxffLt +.. section: Tools/Demos + +The iOS test runner has been simplified, resolving some issues that have +been observed using the runner in GitHub Actions and Azure Pipelines test +environments. + +.. + +.. date: 2025-08-06-11-54-55 +.. gh-issue: 137484 +.. nonce: 8iFAQs +.. section: Tools/Demos + +Have ``Tools/wasm/wasi`` put the build Python into a directory named after +the build triple instead of "build". + +.. + +.. date: 2025-08-01-13-27-43 +.. gh-issue: 137025 +.. nonce: ubuhQC +.. section: Tools/Demos + +The ``wasm_build.py`` script has been removed. ``Tools/wasm/emscripten`` +and ``Tools/wasm/wasi`` should be used instead, as described in the `Dev +Guide <https://devguide.python.org/contrib/workflows/compile/>`__. + +.. + +.. date: 2025-07-30-11-15-47 +.. gh-issue: 137248 +.. nonce: 8IxwY3 +.. section: Tools/Demos + +Add a ``--logdir`` option to ``Tools/wasm/wasi`` for specifying where to +write log files. + +.. + +.. date: 2025-07-30-10-28-35 +.. gh-issue: 137243 +.. nonce: NkdUqH +.. section: Tools/Demos + +Have Tools/wasm/wasi detect a WASI SDK install in /opt when it was directly +extracted from a release tarball. + +.. + +.. date: 2025-07-05-15-10-42 +.. gh-issue: 136251 +.. nonce: GRM6o8 +.. section: Tools/Demos + +Fixes and usability improvements for ``Tools/wasm/emscripten/web_example`` + +.. + +.. date: 2025-06-26-15-58-13 +.. gh-issue: 135968 +.. nonce: C4v_-W +.. section: Tools/Demos + +Stubs for ``strip`` are now provided as part of an iOS install. + +.. + +.. date: 2025-06-11-12-14-06 +.. gh-issue: 135379 +.. nonce: 25ttXq +.. section: Tools/Demos + +The cases generator no longer accepts type annotations on stack items. +Conversions to non-default types are now done explicitly in bytecodes.c and +optimizer_bytecodes.c. This will simplify code generation for top-of-stack +caching and other future features. + +.. + +.. date: 2025-05-19-14-57-46 +.. gh-issue: 134215 +.. nonce: sbdDK6 +.. section: Tools/Demos + +:term:`REPL` import autocomplete only suggests private modules when +explicitly specified. + +.. + +.. date: 2025-09-22-15-40-09 +.. gh-issue: 139208 +.. nonce: Tc13dl +.. section: Tests + +Fix regrtest ``--fast-ci --verbose``: don't ignore the ``--verbose`` option +anymore. Patch by Victor Stinner. + +.. + +.. date: 2025-09-21-16-00-30 +.. gh-issue: 138313 +.. nonce: lBx2en +.. section: Tests + +Restore skipped test and add janky workaround to prevent select buildbots +from failing with a ResourceWarning. + +.. + +.. date: 2025-06-26-15-15-35 +.. gh-issue: 135966 +.. nonce: EBpF8Y +.. section: Tests + +The iOS testbed now handles the ``app_packages`` folder as a site directory. + +.. + +.. date: 2025-06-19-15-29-38 +.. gh-issue: 135494 +.. nonce: FVl9a0 +.. section: Tests + +Fix regrtest to support excluding tests from ``--pgo`` tests. Patch by +Victor Stinner. + +.. + +.. date: 2025-06-17-08-48-08 +.. gh-issue: 132815 +.. nonce: CY1Esu +.. section: Tests + +Fix test__opcode: add ``JUMP_BACKWARD`` to specialization stats. + +.. + +.. date: 2025-06-14-13-20-17 +.. gh-issue: 135489 +.. nonce: Uh0yVO +.. section: Tests + +Show verbose output for failing tests during PGO profiling step with +--enable-optimizations. + +.. + +.. date: 2025-06-11-16-52-49 +.. gh-issue: 135401 +.. nonce: ccMXmL +.. section: Tests + +Add a new GitHub CI job to test the :mod:`ssl` module with `AWS-LC +<https://github.com/aws/aws-lc>`_ as the backing cryptography and TLS +library. + +.. + +.. date: 2025-06-04-13-07-44 +.. gh-issue: 135120 +.. nonce: NapnZT +.. section: Tests + +Add :func:`!test.support.subTests`. + +.. + +.. date: 2025-05-23-09-19-52 +.. gh-issue: 134567 +.. nonce: hwEIMb +.. section: Tests + +Expose log formatter to users in TestCase.assertLogs. +:func:`unittest.TestCase.assertLogs` will now optionally accept a formatter +that will be used to format the strings in output if provided. + +.. + +.. date: 2025-05-09-14-54-48 +.. gh-issue: 133744 +.. nonce: LCquu0 +.. section: Tests + +Fix multiprocessing interrupt test. Add an event to synchronize the parent +process with the child process: wait until the child process starts +sleeping. Patch by Victor Stinner. + +.. + +.. date: 2025-05-09-04-11-06 +.. gh-issue: 133682 +.. nonce: -_lwo3 +.. section: Tests + +Fixed test case ``test.test_annotationlib.TestStringFormat.test_displays`` +which ensures proper handling of complex data structures (lists, sets, +dictionaries, and tuples) in string annotations. + +.. + +.. date: 2025-05-08-15-06-01 +.. gh-issue: 133639 +.. nonce: 50-kbV +.. section: Tests + +Fix ``TestPyReplAutoindent.test_auto_indent_default()`` doesn't run +``input_code``. + +.. + +.. date: 2025-10-07-19-31-34 +.. gh-issue: 139700 +.. nonce: vNHU1O +.. section: Security + +Check consistency of the zip64 end of central directory record. Support +records with "zip64 extensible data" if there are no bytes prepended to the +ZIP file. + +.. + +.. date: 2025-09-29-00-01-28 +.. gh-issue: 139400 +.. nonce: X2T-jO +.. section: Security + +:mod:`xml.parsers.expat`: Make sure that parent Expat parsers are only +garbage-collected once they are no longer referenced by subparsers created +by :meth:`~xml.parsers.expat.xmlparser.ExternalEntityParserCreate`. Patch by +Sebastian Pipping. + +.. + +.. date: 2025-09-24-13-39-56 +.. gh-issue: 139283 +.. nonce: jODz_q +.. section: Security + +:mod:`sqlite3`: correctly handle maximum number of rows to fetch in +:meth:`Cursor.fetchmany <sqlite3.Cursor.fetchmany>` and reject negative +values for :attr:`Cursor.arraysize <sqlite3.Cursor.arraysize>`. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-06-27-21-23-19 +.. gh-issue: 136053 +.. nonce: QZxcee +.. section: Security + +:mod:`marshal`: fix a possible crash when deserializing :class:`slice` +objects. + +.. + +.. date: 2025-06-25-14-13-39 +.. gh-issue: 135661 +.. nonce: idjQ0B +.. section: Security + +Fix parsing start and end tags in :class:`html.parser.HTMLParser` according +to the HTML5 standard. + +* Whitespaces no longer accepted between ``</`` and the tag name. + E.g. ``</ script>`` does not end the script section. + +* Vertical tabulation (``\v``) and non-ASCII whitespaces no longer recognized + as whitespaces. The only whitespaces are ``\t\n\r\f`` and space. + +* Null character (U+0000) no longer ends the tag name. + +* Attributes and slashes after the tag name in end tags are now ignored, + instead of terminating after the first ``>`` in quoted attribute value. + E.g. ``</script/foo=">"/>``. + +* Multiple slashes and whitespaces between the last attribute and closing ``>`` + are now ignored in both start and end tags. E.g. ``<a foo=bar/ //>``. + +* Multiple ``=`` between attribute name and value are no longer collapsed. + E.g. ``<a foo==bar>`` produces attribute "foo" with value "=bar". + +.. + +.. date: 2025-06-18-13-34-55 +.. gh-issue: 135661 +.. nonce: NZlpWf +.. section: Security + +Fix CDATA section parsing in :class:`html.parser.HTMLParser` according to +the HTML5 standard: ``] ]>`` and ``]] >`` no longer end the CDATA section. +Add private method ``_set_support_cdata()`` which can be used to specify how +to parse ``<[CDATA[`` --- as a CDATA section in foreign content (SVG or +MathML) or as a bogus comment in the HTML namespace. + +.. + +.. date: 2025-06-18-13-28-08 +.. gh-issue: 102555 +.. nonce: nADrzJ +.. section: Security + +Fix comment parsing in :class:`html.parser.HTMLParser` according to the +HTML5 standard. ``--!>`` now ends the comment. ``-- >`` no longer ends the +comment. Support abnormally ended empty comments ``<-->`` and ``<--->``. + +.. + +.. date: 2025-06-13-15-55-22 +.. gh-issue: 135462 +.. nonce: KBeJpc +.. section: Security + +Fix quadratic complexity in processing specially crafted input in +:class:`html.parser.HTMLParser`. End-of-file errors are now handled +according to the HTML5 specs -- comments and declarations are automatically +closed, tags are ignored. + +.. + +.. date: 2025-06-09-20-38-25 +.. gh-issue: 118350 +.. nonce: KgWCcP +.. section: Security + +Fix support of escapable raw text mode (elements "textarea" and "title") in +:class:`html.parser.HTMLParser`. + +.. + +.. date: 2025-06-02-11-32-23 +.. gh-issue: 135034 +.. nonce: RLGjbp +.. section: Security + +Fixes multiple issues that allowed ``tarfile`` extraction filters +(``filter="data"`` and ``filter="tar"``) to be bypassed using crafted +symlinks and hard links. + +Addresses :cve:`2024-12718`, :cve:`2025-4138`, :cve:`2025-4330`, and +:cve:`2025-4517`. + +.. + +.. date: 2025-05-09-20-22-54 +.. gh-issue: 133767 +.. nonce: kN2i3Q +.. section: Security + +Fix use-after-free in the "unicode-escape" decoder with a non-"strict" error +handler. + +.. + +.. date: 2025-05-07-22-49-27 +.. gh-issue: 133623 +.. nonce: fgWkBm +.. section: Security + +Indicate through :data:`ssl.HAS_PSK_TLS13` whether the :mod:`ssl` module +supports "External PSKs" in TLSv1.3, as described in RFC 9258. Patch by Will +Childs-Klein. + +.. + +.. date: 2025-01-14-11-19-07 +.. gh-issue: 128840 +.. nonce: M1doZW +.. section: Security + +Short-circuit the processing of long IPv6 addresses early in +:mod:`ipaddress` to prevent excessive memory consumption and a minor +denial-of-service. + +.. + +.. date: 2025-10-11-20-03-13 +.. gh-issue: 139482 +.. nonce: du2Stg +.. section: Library + +Optimize :data:`os.environ.clear() <os.environ>` by calling +:manpage:`clearenv(3)` when this function is available. Patch by Victor +Stinner. + +.. + +.. date: 2025-10-11-17-41-26 +.. gh-issue: 139958 +.. nonce: AnCakj +.. section: Library + +The ``application/toml`` mime type is now supported by :mod:`mimetypes`. +Patch by Gil Forcada. + +.. + +.. date: 2025-10-11-14-37-42 +.. gh-issue: 139823 +.. nonce: uGF4oh +.. section: Library + +:mod:`ensurepip` now fails with a nicer error message when the :mod:`zlib` +module is not available. + +.. + +.. date: 2025-10-11-10-02-56 +.. gh-issue: 139905 +.. nonce: UyJIR_ +.. section: Library + +Add suggestion to error message for :class:`typing.Generic` subclasses when +``cls.__parameters__`` is missing due to a parent class failing to call +:meth:`super().__init_subclass__() <object.__init_subclass__>` in its +``__init_subclass__``. + +.. + +.. date: 2025-10-10-11-22-50 +.. gh-issue: 139894 +.. nonce: ECAXqj +.. section: Library + +Fix incorrect sharing of current task with the child process while forking +in :mod:`asyncio`. Patch by Kumar Aditya. + +.. + +.. date: 2025-10-09-21-37-20 +.. gh-issue: 139845 +.. nonce: dzx5UP +.. section: Library + +Fix to not print KeyboardInterrupt twice in default asyncio REPL. + +.. + +.. date: 2025-10-09-13-48-28 +.. gh-issue: 139783 +.. nonce: __NUgo +.. section: Library + +Fix :func:`inspect.getsourcelines` for the case when a decorator is followed +by a comment or an empty line. + +.. + +.. date: 2025-10-09-03-06-19 +.. gh-issue: 139809 +.. nonce: lzHJNu +.. section: Library + +Prevent premature colorization of subparser ``prog`` in +:meth:`argparse.ArgumentParser.add_subparsers` to respect color environment +variable changes after parser creation. + +.. + +.. date: 2025-10-08-00-06-30 +.. gh-issue: 139736 +.. nonce: baPeBd +.. section: Library + +Fix excessive indentation in the default :mod:`argparse` +:class:`!HelpFormatter`. Patch by Alexander Edland. + +.. + +.. date: 2025-10-02-17-40-10 +.. gh-issue: 70765 +.. nonce: zVlLZn +.. section: Library + +:mod:`http.server`: fix default handling of HTTP/0.9 requests in +:class:`~http.server.BaseHTTPRequestHandler`. Previously, +:meth:`!BaseHTTPRequestHandler.parse_request` incorrectly waited for headers +in the request although those are not supported in HTTP/0.9. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-10-02-15-45-08 +.. gh-issue: 139322 +.. nonce: rouPGj +.. section: Library + +Fix :func:`os.getlogin` error handling: fix the error number. Patch by +Victor Stinner. + +.. + +.. date: 2025-10-01-20-30-03 +.. gh-issue: 135953 +.. nonce: NAofJl +.. section: Library + +Add a Gecko format output to the tachyon profiler via ``--gecko``. + +.. + +.. date: 2025-09-29-14-15-20 +.. gh-issue: 139184 +.. nonce: dNl9O4 +.. section: Library + +:func:`os.forkpty` does now make the returned file descriptor +non-inheritable. + +.. + +.. date: 2025-09-28-16-34-11 +.. gh-issue: 139391 +.. nonce: nRFnmx +.. section: Library + +Fix an issue when, on non-Windows platforms, it was not possible to +gracefully exit a ``python -m asyncio`` process suspended by Ctrl+Z and +later resumed by :manpage:`fg` other than with :manpage:`kill`. + +.. + +.. date: 2025-09-27-08-26-31 +.. gh-issue: 139374 +.. nonce: hfh-dl +.. section: Library + +:mod:`timeit`: Add color to error tracebacks. + +.. + +.. date: 2025-09-26-18-04-28 +.. gh-issue: 90949 +.. nonce: YHjSzX +.. section: Library + +Add +:meth:`~xml.parsers.expat.xmlparser.SetBillionLaughsAttackProtectionActivationThreshold` +and +:meth:`~xml.parsers.expat.xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification` +to :ref:`xmlparser <xmlparser-objects>` objects to tune protections against +`billion laughs <https://en.wikipedia.org/wiki/Billion_laughs_attack>`_ +attacks. Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-25-07-33-43 +.. gh-issue: 139312 +.. nonce: ygE8AC +.. section: Library + +Upgrade bundled libexpat to 2.7.3 + +.. + +.. date: 2025-09-24-14-17-34 +.. gh-issue: 139289 +.. nonce: Vmk25k +.. section: Library + +Do a real lazy-import on :mod:`rlcompleter` in :mod:`pdb` and restore the +existing completer after importing :mod:`rlcompleter`. + +.. + +.. date: 2025-09-22-14-40-11 +.. gh-issue: 90949 +.. nonce: UM35nb +.. section: Library + +Add :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerActivationThreshold` +and :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerMaximumAmplification` +to :ref:`xmlparser <xmlparser-objects>` objects to tune protections against +disproportional amounts of dynamic memory usage from within an Expat parser. +Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-22-11-30-45 +.. gh-issue: 67795 +.. nonce: fROoZt +.. section: Library + +Functions that take timestamp or timeout arguments now accept any real +numbers (such as :class:`~decimal.Decimal` and +:class:`~fractions.Fraction`), not only integers or floats, although this +does not improve precision. + +.. + +.. date: 2025-09-22-11-19-05 +.. gh-issue: 95953 +.. nonce: 7oLoag +.. section: Library + +A CSS class, ``diff_changed``, was added to the changed lines in the +``make_table`` output of :class:`difflib.HtmlDiff`. Patch by Katie Gardner. + +.. + +.. date: 2025-09-21-15-58-57 +.. gh-issue: 139210 +.. nonce: HGbMvz +.. section: Library + +Fix use-after-free when reporting unknown event in +:func:`xml.etree.ElementTree.iterparse`. Patch by Ken Jin. + +.. + +.. date: 2025-09-20-17-50-31 +.. gh-issue: 138860 +.. nonce: Y9JXap +.. section: Library + +Lazy import :mod:`rlcompleter` in :mod:`pdb` to avoid deadlock in +subprocess. + +.. + +.. date: 2025-09-19-09-36-42 +.. gh-issue: 112729 +.. nonce: mmty0_ +.. section: Library + +Fix crash when calling :func:`concurrent.interpreters.create` when the +process is out of memory. + +.. + +.. date: 2025-09-19-07-41-52 +.. gh-issue: 126016 +.. nonce: Uz9W6h +.. section: Library + +Fix an assertion failure when sending :exc:`KeyboardInterrupt` to a Python +process running a subinterpreter in a separate thread. + +.. + +.. date: 2025-09-18-14-21-57 +.. gh-issue: 118803 +.. nonce: 2JPbto +.. section: Library + +:class:`collections.abc.ByteString` has been removed from +``collections.abc.__all__``, and :class:`typing.ByteString` has been removed +from ``typing.__all__``. The former has been deprecated since Python 3.12, +and the latter has been deprecated since Python 3.9. Both classes are +scheduled for removal in Python 3.17. + +Additionally, the following statements now cause ``DeprecationWarning``\ s +to be emitted at runtime: ``from collections.abc import ByteString``, ``from +typing import ByteString``, ``import collections.abc; +collections.abc.ByteString`` and ``import typing; typing.ByteString``. Both +classes already caused ``DeprecationWarning``\ s to be emitted if they were +subclassed or used as the second argument to ``isinstance()`` or +``issubclass()``, but they did not previously lead to +``DeprecationWarning``\ s if they were merely imported or accessed from +their respective modules. + +.. + +.. date: 2025-09-18-05-32-18 +.. gh-issue: 135729 +.. nonce: 8AmMza +.. section: Library + +Fix unraisable exception during finalization when using +:mod:`concurrent.interpreters` in the REPL. + +.. + +.. date: 2025-09-17-21-54-53 +.. gh-issue: 139076 +.. nonce: 2eX9lG +.. section: Library + +Fix a bug in the :mod:`pydoc` module that was hiding functions in a Python +module if they were implemented in an extension module and the module did +not have ``__all__``. + +.. + +.. date: 2025-09-17-21-52-30 +.. gh-issue: 139090 +.. nonce: W7vbhF +.. section: Library + +Add :data:`os.RWF_DONTCACHE` constant for Linux 6.14+. + +.. + +.. date: 2025-09-17-19-08-34 +.. gh-issue: 139065 +.. nonce: Hu8fM5 +.. section: Library + +Fix trailing space before a wrapped long word if the line length is exactly +*width* in :mod:`textwrap`. + +.. + +.. date: 2025-09-17-12-07-21 +.. gh-issue: 139001 +.. nonce: O6tseN +.. section: Library + +Fix race condition in :class:`pathlib.Path` on the internal ``_raw_paths`` +field. + +.. + +.. date: 2025-09-17-08-32-43 +.. gh-issue: 138813 +.. nonce: LHkHjX +.. section: Library + +:class:`!multiprocessing.BaseProcess` defaults ``kwargs`` to ``None`` +instead of a shared dictionary. + +.. + +.. date: 2025-09-16-19-05-29 +.. gh-issue: 138998 +.. nonce: URl0Y_ +.. section: Library + +Update bundled libexpat to 2.7.2 + +.. + +.. date: 2025-09-16-16-46-58 +.. gh-issue: 138993 +.. nonce: -8s8_T +.. section: Library + +Dedent :data:`credits` text. + +.. + +.. date: 2025-09-16-15-56-29 +.. gh-issue: 118803 +.. nonce: aOPtmL +.. section: Library + +Add back :class:`collections.abc.ByteString` and :class:`typing.ByteString`. +Both had been removed in prior alpha, beta and release candidates for Python +3.14, but their removal has now been postponed to Python 3.17. + +.. + +.. date: 2025-09-15-19-29-12 +.. gh-issue: 130567 +.. nonce: shDEnT +.. section: Library + +Fix possible crash in :func:`locale.strxfrm` due to a platform bug on macOS. + +.. + +.. date: 2025-09-15-13-09-19 +.. gh-issue: 137226 +.. nonce: HH3_ik +.. section: Library + +Fix :func:`typing.get_type_hints` calls on generic :class:`typing.TypedDict` +classes defined with string annotations. + +.. + +.. date: 2025-09-15-08-57-39 +.. gh-issue: 138899 +.. nonce: Uh6fvY +.. section: Library + +Executing ``quit`` command in :mod:`pdb` will raise :exc:`bdb.BdbQuit` when +:mod:`pdb` is started from an asyncio console using :func:`breakpoint` or +:func:`pdb.set_trace`. + +.. + +.. date: 2025-09-12-01-01-05 +.. gh-issue: 138804 +.. nonce: 46ZukT +.. section: Library + +Raise :exc:`TypeError` instead of :exc:`AttributeError` when an argument of +incorrect type is passed to :func:`shlex.quote`. This restores the behavior +of the function prior to 3.14. + +.. + +.. date: 2025-09-11-11-09-28 +.. gh-issue: 138779 +.. nonce: TNZnLr +.. section: Library + +Support device numbers larger than ``2**63-1`` for the +:attr:`~os.stat_result.st_rdev` field of the :class:`os.stat_result` +structure. + +.. + +.. date: 2025-09-10-13-32-25 +.. gh-issue: 138682 +.. nonce: iExqx1 +.. section: Library + +Added symmetric difference support to :class:`collections.Counter` objects. + +.. + +.. date: 2025-09-10-10-11-59 +.. gh-issue: 138712 +.. nonce: avrPG5 +.. section: Library + +Add :const:`os.NODEV`. + +.. + +.. date: 2025-09-10-10-02-59 +.. gh-issue: 128636 +.. nonce: ldRKGZ +.. section: Library + +Fix crash in PyREPL when os.environ is overwritten with an invalid value for +mac + +.. + +.. date: 2025-09-09-17-57-49 +.. gh-issue: 138720 +.. nonce: hAtsm- +.. section: Library + +Fix an issue where :class:`io.BufferedWriter` and :class:`io.BufferedRandom` +had different definitions of "closed" for :meth:`~io.IOBase.close` and +:meth:`~io.IOBase.flush` which resulted in an exception when close called +flush but flush thought the file was already closed. + +.. + +.. date: 2025-09-09-10-48-26 +.. gh-issue: 138706 +.. nonce: xB--LX +.. section: Library + +Update :mod:`unicodedata` database to Unicode 17.0.0. + +.. + +.. date: 2025-09-08-17-32-02 +.. gh-issue: 76007 +.. nonce: peEgcr +.. section: Library + +Deprecate ``__version__`` from a number of standard library modules. Patch +by Hugo van Kemenade. + +.. + +.. date: 2025-09-06-20-09-32 +.. gh-issue: 138535 +.. nonce: mlntEe +.. section: Library + +Speed up :func:`os.stat` for files with reasonable timestamps. Contributed +by Jeffrey Bosboom. + +.. + +.. date: 2025-09-06-14-56-40 +.. gh-issue: 116946 +.. nonce: GGIeyO +.. section: Library + +:mod:`curses.panel`: the type of :func:`curses.panel.new_panel` is now +immutable. Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-06-14-54-01 +.. gh-issue: 116946 +.. nonce: hzQEWI +.. section: Library + +:mod:`zlib`: the types of :func:`zlib.compressobj` and +:func:`zlib.decompressobj` are now immutable. Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-06-14-53-19 +.. gh-issue: 116946 +.. nonce: c-npxd +.. section: Library + +:mod:`os`: the :class:`os.DirEntry` type and the type of :func:`os.scandir` +are now immutable. Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-06-14-47-23 +.. gh-issue: 116946 +.. nonce: hj_u1t +.. section: Library + +:mod:`tkinter`: the types :class:`!_tkinter.Tcl_Obj` (wrapper for Tcl +objects), :class:`!_tkinter.tktimertoken` (obtained by calling +``createtimerhandler()`` on a :attr:`Tk <tkinter.Tk.tk>` application) and +:class:`!_tkinter.tkapp` (the runtime type of Tk applications) are now +immutable. Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-06-11-26-21 +.. gh-issue: 138514 +.. nonce: 66ltOb +.. section: Library + +Raise :exc:`ValueError` when a multi-character string is passed to the +*echo_char* parameter of :func:`getpass.getpass`. Patch by Benjamin Johnson. + +.. + +.. date: 2025-09-05-21-10-24 +.. gh-issue: 137706 +.. nonce: 0EztiJ +.. section: Library + +Fix the partial evaluation of annotations that use ``typing.Annotated[T, +x]`` where ``T`` is a forward reference. + +.. + +.. date: 2025-09-05-15-35-59 +.. gh-issue: 88375 +.. nonce: dC491a +.. section: Library + +Fix normalization of the ``robots.txt`` rules and URLs in the +:mod:`urllib.robotparser` module. No longer ignore trailing ``?``. +Distinguish raw special characters ``?``, ``=`` and ``&`` from the +percent-encoded ones. + +.. + +.. date: 2025-09-05-07-50-18 +.. gh-issue: 138515 +.. nonce: E3M-pu +.. section: Library + +:mod:`email` is added to Emscripten build. + +.. + +.. date: 2025-09-05-05-53-43 +.. gh-issue: 99948 +.. nonce: KMSlG6 +.. section: Library + +:func:`ctypes.util.find_library` now works in Emscripten build. + +.. + +.. date: 2025-09-04-15-18-11 +.. gh-issue: 111788 +.. nonce: tuTEM5 +.. section: Library + +Fix parsing errors in the :mod:`urllib.robotparser` module. Don't fail +trying to parse weird paths. Don't fail trying to decode non-UTF-8 +``robots.txt`` files. + +.. + +.. date: 2025-09-03-15-20-10 +.. gh-issue: 138432 +.. nonce: RMc7UX +.. section: Library + +:meth:`zoneinfo.reset_tzpath` will now convert any :class:`os.PathLike` +objects it receives into strings before adding them to ``TZPATH``. It will +raise ``TypeError`` if anything other than a string is found after this +conversion. If given an :class:`os.PathLike` object that represents a +relative path, it will now raise ``ValueError`` instead of ``TypeError``, +and present a more informative error message. + +.. + +.. date: 2025-09-03-09-03-11 +.. gh-issue: 132657 +.. nonce: cbAIDh +.. section: Library + +Improve the scaling of :func:`copy.copy` and :func:`copy.deepcopy` in the +free-threading build. + +.. + +.. date: 2025-09-02-10-27-21 +.. gh-issue: 116946 +.. nonce: VxXNGD +.. section: Library + +The types of :func:`select.poll` and :func:`select.epoll` objects are now +immutable. Patch by Bénédikt Tran. + +.. + +.. date: 2025-09-02-10-23-09 +.. gh-issue: 116946 +.. nonce: U6RpwK +.. section: Library + +The :class:`!_random.Random` C type is now immutable. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-08-31-22-10-22 +.. gh-issue: 57911 +.. nonce: N_Ixtv +.. section: Library + +When extracting tar files on Windows, slashes in symlink targets will be +replaced by backslashes to prevent corrupted links. + +.. + +.. date: 2025-08-31-12-34-02 +.. gh-issue: 138205 +.. nonce: iHXb1z +.. section: Library + +Removed the :meth:`~mmap.mmap.resize` method on platforms that don't support +the underlying syscall, instead of raising a :exc:`SystemError`. + +.. + +.. date: 2025-08-31-09-06-49 +.. gh-issue: 138008 +.. nonce: heOvsU +.. section: Library + +Fix segmentation faults in the :mod:`ctypes` module due to invalid +:attr:`~ctypes._CFuncPtr.argtypes`. Patch by Dung Nguyen. + +.. + +.. date: 2025-08-30-17-58-04 +.. gh-issue: 138252 +.. nonce: CDiEby +.. section: Library + +:mod:`ssl`: :class:`~ssl.SSLContext` objects can now set client and server +TLS signature algorithms. If Python has been built with OpenSSL 3.5 or +later, :class:`~ssl.SSLSocket` objects can return the signature algorithms +selected on a connection. + +.. + +.. date: 2025-08-30-10-58-15 +.. gh-issue: 138253 +.. nonce: 9Ehj-N +.. section: Library + +Add the *block* parameter in the :meth:`!put` and :meth:`!get` methods of +the :mod:`concurrent.interpreters` queues for compatibility with the +:class:`queue.Queue` interface. + +.. + +.. date: 2025-08-30-10-04-28 +.. gh-issue: 60462 +.. nonce: yh_vDc +.. section: Library + +Fix :func:`locale.strxfrm` on Solaris (and possibly other platforms). + +.. + +.. date: 2025-08-29-12-56-55 +.. gh-issue: 138239 +.. nonce: uthZFI +.. section: Library + +The REPL now highlights :keyword:`type` as a soft keyword in :ref:`type +statements <type>`. + +.. + +.. date: 2025-08-29-12-05-33 +.. gh-issue: 78502 +.. nonce: VpIMxg +.. section: Library + +:class:`mmap.mmap` now has a *trackfd* parameter on Windows; if it is +``False``, the file handle corresponding to *fileno* will not be duplicated. + +.. + +.. date: 2025-08-28-13-20-09 +.. gh-issue: 138204 +.. nonce: 8oLOud +.. section: Library + +Forbid expansion of shared anonymous :mod:`memory maps <mmap>` on Linux, +which caused a bus error. + +.. + +.. date: 2025-08-27-17-05-36 +.. gh-issue: 138010 +.. nonce: ZZJmPL +.. section: Library + +Fix an issue where defining a class with a +:deco:`warnings.deprecated`-decorated base class may not invoke the correct +:meth:`~object.__init_subclass__` method in cases involving multiple +inheritance. Patch by Brian Schubert. + +.. + +.. date: 2025-08-25-22-38-03 +.. gh-issue: 134716 +.. nonce: kyYKeX +.. section: Library + +Add support of regular expressions in the :option:`-W` option and the +:envvar:`PYTHONWARNINGS` environment variable. + +.. + +.. date: 2025-08-25-18-06-04 +.. gh-issue: 138133 +.. nonce: Zh9rGo +.. section: Library + +Prevent infinite traceback loop when sending CTRL^C to Python through +``strace``. + +.. + +.. date: 2025-08-25-16-22-32 +.. gh-issue: 138122 +.. nonce: eMNDZ1 +.. section: Library + +Implement :pep:`799` -- A dedicated profiling package for organizing Python +profiling tools. Patch by Pablo Galindo. + +.. + +.. date: 2025-08-24-02-04-32 +.. gh-issue: 138092 +.. nonce: V4-wTO +.. section: Library + +Fixed a bug in :meth:`mmap.mmap.flush` where calling with only an offset +parameter would fail. + +.. + +.. date: 2025-08-22-12-48-14 +.. gh-issue: 138044 +.. nonce: lEQULC +.. section: Library + +Remove compatibility shim for deprecated parameter *package* in +:func:`importlib.resources.files`. Patch by Semyon Moroz. + +.. + +.. date: 2025-08-22-09-53-45 +.. gh-issue: 86819 +.. nonce: ECxvwx +.. section: Library + +:mod:`socket`: Add missing constants for ISO-TP sockets. + +.. + +.. date: 2025-08-19-00-12-57 +.. gh-issue: 137884 +.. nonce: 4faCA_ +.. section: Library + +Add :func:`threading.get_native_id` support for Illumos/Solaris. Patch by +Yüce Tekol. + +.. + +.. date: 2025-08-18-16-02-51 +.. gh-issue: 134869 +.. nonce: GnAjnU +.. section: Library + +Fix an issue where pressing Ctrl+C during tab completion in the REPL would +leave the autocompletion menu in a corrupted state. + +.. + +.. date: 2025-08-18-07-10-55 +.. gh-issue: 137840 +.. nonce: 9b7AnG +.. section: Library + +:class:`typing.TypedDict` now supports the ``closed`` and ``extra_items`` +keyword arguments (as described in :pep:`728`) to control whether additional +non-required keys are allowed and to specify their value type. + +.. + +.. date: 2025-08-17-10-22-31 +.. gh-issue: 132947 +.. nonce: XR4MJ8 +.. section: Library + +Applied changes to ``importlib.metadata`` from `importlib_metadata 8.7 +<https://importlib-metadata.readthedocs.io/en/latest/history.html#v8-7-0>`_, +including ``dist`` now disallowed for ``EntryPoints.select``; deferred +imports for faster import times; added support for metadata with newlines +(python/cpython#119650); and ``metadata()`` function now returns ``None`` +when a metadata directory is present but no metadata is present. + +.. + +.. date: 2025-08-16-18-11-41 +.. gh-issue: 90548 +.. nonce: q3aJUK +.. section: Library + +Fix ``musl`` detection for :func:`platform.libc_ver` on Alpine Linux if +compiled with --strip-all. + +.. + +.. date: 2025-08-16-16-04-15 +.. gh-issue: 137317 +.. nonce: Dl13B5 +.. section: Library + +:func:`inspect.signature` now correctly handles classes that use a +descriptor on a wrapped :meth:`!__init__` or :meth:`!__new__` method. +Contributed by Yongyu Yan. + +.. + +.. date: 2025-08-16-09-02-11 +.. gh-issue: 137754 +.. nonce: mCev1Y +.. section: Library + +Fix import of the :mod:`zoneinfo` module if the C implementation of the +:mod:`datetime` module is not available. + +.. + +.. date: 2025-08-14-10-27-07 +.. gh-issue: 125854 +.. nonce: vDzFcZ +.. section: Library + +Improve error messages for invalid category in :func:`warnings.warn`. + +.. + +.. date: 2025-08-14-00-00-12 +.. gh-issue: 137729 +.. nonce: i9NSKP +.. section: Library + +:func:`locale.setlocale` now supports language codes with ``@``-modifiers. +``@``-modifier are no longer silently removed in :func:`locale.getlocale`, +but included in the language code. + +.. + +.. date: 2025-08-13-10-50-22 +.. gh-issue: 73487 +.. nonce: DUHbBq +.. section: Library + +Speedup processing arguments (up to 1.5x) in the :mod:`decimal` module +methods, that now using :c:macro:`METH_FASTCALL` calling convention. Patch +by Sergey B Kirpichev. + +.. + +.. date: 2025-08-11-14-18-32 +.. gh-issue: 137634 +.. nonce: M7iBG6 +.. section: Library + +Calendar pages generated by the :class:`calendar.HTMLCalendar` class now +support dark mode and have been migrated to the HTML5 standard for improved +accessibility. + +.. + +.. date: 2025-08-11-05-05-08 +.. gh-issue: 137630 +.. nonce: 9lmqyc +.. section: Library + +The :mod:`!_interpreters` module now uses Argument Clinic to parse +arguments. Patch by Adam Turner. + +.. + +.. date: 2025-08-09-08-53-32 +.. gh-issue: 137583 +.. nonce: s6OZud +.. section: Library + +Fix a deadlock introduced in 3.13.6 when a call to :meth:`ssl.SSLSocket.recv +<socket.socket.recv>` was blocked in one thread, and then another method on +the object (such as :meth:`ssl.SSLSocket.send <socket.socket.send>`) was +subsequently called in another thread. + +.. + +.. date: 2025-08-08-21-20-14 +.. gh-issue: 92936 +.. nonce: rOgG1S +.. section: Library + +Update regex used by ``http.cookies.SimpleCookie`` to handle values +containing double quotes. + +.. + +.. date: 2025-08-08-15-00-38 +.. gh-issue: 137426 +.. nonce: lW-Rk2 +.. section: Library + +Remove the code deprecation of ``importlib.abc.ResourceLoader``. It is +documented as deprecated, but left for backwards compatibility with other +classes in ``importlib.abc``. + +.. + +.. date: 2025-08-07-17-18-57 +.. gh-issue: 137490 +.. nonce: s89ieZ +.. section: Library + +Handle :data:`~errno.ECANCELED` in the same way as :data:`~errno.EINTR` in +:func:`signal.sigwaitinfo` on NetBSD. + +.. + +.. date: 2025-08-07-15-07-44 +.. gh-issue: 137512 +.. nonce: j2or5h +.. section: Library + +Add new constants in the :mod:`resource` module: +:data:`~resource.RLIMIT_NTHR`, :data:`~resource.RLIMIT_UMTXP`, +:data:`~resource.RLIMIT_PIPEBUF`, :data:`~resource.RLIMIT_THREADS`, +:data:`~resource.RLIM_SAVED_CUR`, and :data:`~resource.RLIM_SAVED_MAX`. + +.. + +.. date: 2025-08-07-12-32-23 +.. gh-issue: 137044 +.. nonce: abNoIy +.. section: Library + +:data:`resource.RLIM_INFINITY` is now always a positive integer. On all +supported platforms, it is larger than any limited resource value, which +simplifies comparison of the resource values. Previously, it could be +negative, such as -1 or -3, depending on platform. + +.. + +.. date: 2025-08-06-23-16-42 +.. gh-issue: 137477 +.. nonce: bk6BDV +.. section: Library + +Fix :func:`!inspect.getblock`, :func:`inspect.getsourcelines` and +:func:`inspect.getsource` for generator expressions. + +.. + +.. date: 2025-08-06-16-54-22 +.. gh-issue: 137481 +.. nonce: eSTkK0 +.. section: Library + +Calendar uses the lengths of the locale's weekdays to decide if the width +requires abbreviation. + +.. + +.. date: 2025-08-06-16-13-47 +.. gh-issue: 137466 +.. nonce: Whv0-A +.. section: Library + +Remove undocumented :func:`!glob.glob0` and :func:`!glob.glob1` functions, +which have been deprecated since Python 3.13. Use :func:`glob.glob` and pass +a directory to its *root_dir* argument instead. + +.. + +.. date: 2025-08-03-13-16-39 +.. gh-issue: 137044 +.. nonce: 0hPVL_ +.. section: Library + +Return large limit values as positive integers instead of negative integers +in :func:`resource.getrlimit`. Accept large values and reject negative +values (except :data:`~resource.RLIM_INFINITY`) for limits in +:func:`resource.setrlimit`. + +.. + +.. date: 2025-08-03-00-36-57 +.. gh-issue: 115766 +.. nonce: nJCFkW +.. section: Library + +Fix :attr:`!ipaddress.IPv4Interface.is_unspecified`. + +.. + +.. date: 2025-08-01-23-52-49 +.. gh-issue: 75989 +.. nonce: 5aYXNJ +.. section: Library + +:func:`tarfile.TarFile.extractall` and :func:`tarfile.TarFile.extract` now +overwrite symlinks when extracting hardlinks. (Contributed by Alexander +Enrique Urieles Nieto in :gh:`75989`.) + +.. + +.. date: 2025-08-01-23-11-25 +.. gh-issue: 137017 +.. nonce: 0yGcNc +.. section: Library + +Fix :obj:`threading.Thread.is_alive` to remain ``True`` until the underlying +OS thread is fully cleaned up. This avoids false negatives in edge cases +involving thread monitoring or premature :obj:`threading.Thread.is_alive` +calls. + +.. + +.. date: 2025-08-01-15-07-59 +.. gh-issue: 137273 +.. nonce: 4V8Xmv +.. section: Library + +Fix debug assertion failure in :func:`locale.setlocale` on Windows. + +.. + +.. date: 2025-07-31-16-43-16 +.. gh-issue: 137191 +.. nonce: FIogE8 +.. section: Library + +Fix how type parameters are collected, when :class:`typing.Protocol` are +specified with explicit parameters. Now, :class:`typing.Generic` and +:class:`typing.Protocol` always dictate the parameter number and parameter +ordering of types. Previous behavior was a bug. + +.. + +.. date: 2025-07-31-10-31-56 +.. gh-issue: 137282 +.. nonce: GOCwIC +.. section: Library + +Fix tab completion and :func:`dir` on :mod:`concurrent.futures`. + +.. + +.. date: 2025-07-30-18-07-33 +.. gh-issue: 137257 +.. nonce: XBtzf2 +.. section: Library + +Bump the version of pip bundled in ensurepip to version 25.2 + +.. + +.. date: 2025-07-30-17-42-36 +.. gh-issue: 137239 +.. nonce: qSpj32 +.. section: Library + +:mod:`heapq`: Update :data:`!heapq.__all__` with ``*_max`` functions. + +.. + +.. date: 2025-07-30-11-12-22 +.. gh-issue: 124503 +.. nonce: d4hc7b +.. section: Library + +:func:`ast.literal_eval` is 10-20% faster for small inputs. + +.. + +.. date: 2025-07-29-21-18-31 +.. gh-issue: 137226 +.. nonce: B_4lpu +.. section: Library + +Fix behavior of :meth:`annotationlib.ForwardRef.evaluate` when the +*type_params* parameter is passed and the name of a type param is also +present in an enclosing scope. + +.. + +.. date: 2025-07-29-05-12-50 +.. gh-issue: 137197 +.. nonce: bMK3sO +.. section: Library + +:class:`~ssl.SSLContext` objects can now set TLS 1.3 cipher suites via +:meth:`~ssl.SSLContext.set_ciphersuites`. + +.. + +.. date: 2025-07-28-23-11-29 +.. gh-issue: 81325 +.. nonce: jMJFBe +.. section: Library + +:class:`tarfile.TarFile` now accepts a :term:`path-like <path-like object>` +when working on a tar archive. (Contributed by Alexander Enrique Urieles +Nieto in :gh:`81325`.) + +.. + +.. date: 2025-07-28-20-48-32 +.. gh-issue: 137185 +.. nonce: fgI7-B +.. section: Library + +Fix a potential async-signal-safety issue in :mod:`faulthandler` when +printing C stack traces. + +.. + +.. date: 2025-07-27-17-03-17 +.. gh-issue: 133951 +.. nonce: 7kwt78 +.. section: Library + +Remove lib64-lib symlink creation when creating new virtual environments in +:mod:`venv` module + +.. + +.. date: 2025-07-25-09-21-56 +.. gh-issue: 130522 +.. nonce: Crwq68 +.. section: Library + +Fix unraisable :exc:`TypeError` raised during :term:`interpreter shutdown` +in the :mod:`threading` module. + +.. + +.. date: 2025-07-24-00-38-07 +.. gh-issue: 137059 +.. nonce: fr64oW +.. section: Library + +Fix handling of file URLs with a Windows drive letter in the URL authority +by :func:`urllib.request.url2pathname`. This fixes a regression in earlier +pre-releases of Python 3.14. + +.. + +.. date: 2025-07-23-11-59-48 +.. gh-issue: 136980 +.. nonce: BIJzkB +.. section: Library + +Remove unused C tracing code in bdb for event type ``c_call``, ``c_return`` +and ``c_exception`` + +.. + +.. date: 2025-07-23-00-35-29 +.. gh-issue: 130577 +.. nonce: c7EITy +.. section: Library + +:mod:`tarfile` now validates archives to ensure member offsets are +non-negative. (Contributed by Alexander Enrique Urieles Nieto in +:gh:`130577`.) + +.. + +.. date: 2025-07-21-22-35-50 +.. gh-issue: 136170 +.. nonce: QUlc78 +.. section: Library + +Removed the unreleased ``zipfile.ZipFile.data_offset`` property added in +3.14.0a7 as it wasn't fully clear which behavior it should have in some +situations so the result was not always what a user might expect. + +.. + +.. date: 2025-07-21-20-00-42 +.. gh-issue: 121237 +.. nonce: DyxNqo +.. section: Library + +Support ``%:z`` directive for :meth:`datetime.datetime.strptime`, +:meth:`datetime.time.strptime` and :func:`time.strptime`. Patch by Lucas +Esposito and Semyon Moroz. + +.. + +.. date: 2025-07-21-16-13-20 +.. gh-issue: 136929 +.. nonce: obKZ2S +.. section: Library + +Ensure that hash functions guaranteed to be always *available* exist as +attributes of :mod:`hashlib` even if they will not work at runtime due to +missing backend implementations. For instance, ``hashlib.md5`` will no +longer raise :exc:`AttributeError` if OpenSSL is not available and Python +has been built without MD5 support. Patch by Bénédikt Tran. + +.. + +.. date: 2025-07-21-16-10-24 +.. gh-issue: 124621 +.. nonce: wyoWc1 +.. section: Library + +pyrepl now works in Emscripten. + +.. + +.. date: 2025-07-21-15-40-00 +.. gh-issue: 136914 +.. nonce: -GNG-d +.. section: Library + +Fix retrieval of :attr:`doctest.DocTest.lineno` for objects decorated with +:func:`functools.cache` or :class:`functools.cached_property`. + +.. + +.. date: 2025-07-21-11-56-47 +.. gh-issue: 136912 +.. nonce: zWosAL +.. section: Library + +:func:`hmac.digest` now properly handles large keys and messages by falling +back to the pure Python implementation when necessary. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-07-21-01-16-32 +.. gh-issue: 83424 +.. nonce: Y3tEV4 +.. section: Library + +Allows creating a :class:`ctypes.CDLL` without name when passing a handle as +an argument. + +.. + +.. date: 2025-07-20-16-56-55 +.. gh-issue: 135228 +.. nonce: n_XIao +.. section: Library + +When :mod:`dataclasses` replaces a class with a slotted dataclass, the +original class can now be garbage collected again. Earlier changes in Python +3.14 caused this class to always remain in existence together with the +replacement class synthesized by :mod:`dataclasses`. + +.. + +.. date: 2025-07-20-16-02-00 +.. gh-issue: 136874 +.. nonce: cLC3o1 +.. section: Library + +Discard URL query and fragment in :func:`urllib.request.url2pathname`. + +.. + +.. date: 2025-07-20-10-21-49 +.. gh-issue: 136787 +.. nonce: _0Rbp_ +.. section: Library + +:mod:`hashlib`: improve exception messages when a hash algorithm is not +recognized, blocked by the current security policy or incompatible with the +desired operation (for instance, using HMAC with SHAKE). Patch by Bénédikt +Tran. + +.. + +.. date: 2025-07-19-16-20-54 +.. gh-issue: 130645 +.. nonce: O-dYcN +.. section: Library + +Enable color help by default in :mod:`argparse`. + +.. + +.. date: 2025-07-19-15-40-47 +.. gh-issue: 131724 +.. nonce: LS59nA +.. section: Library + +In :mod:`http.client`, a new *max_response_headers* keyword-only parameter +has been added to :class:`~http.client.HTTPConnection` and +:class:`~http.client.HTTPSConnection` constructors. This parameter sets the +maximum number of allowed response headers, helping to prevent +denial-of-service attacks. + +.. + +.. date: 2025-07-19-11-53-19 +.. gh-issue: 135427 +.. nonce: iJM_X2 +.. section: Library + +With :option:`-Werror <-W>`, the DeprecationWarning emitted by +:py:func:`os.fork` and :py:func:`os.forkpty` in mutli-threaded processes is +now raised as an exception. Previously it was silently ignored. Patch by +Rani Pinchuk. + +.. + +.. date: 2025-07-17-16-12-23 +.. gh-issue: 136234 +.. nonce: VmTxtj +.. section: Library + +Fix :meth:`asyncio.WriteTransport.writelines` to be robust to connection +failure, by using the same behavior as +:meth:`~asyncio.WriteTransport.write`. + +.. + +.. date: 2025-07-16-09-45-58 +.. gh-issue: 53144 +.. nonce: mrKwMW +.. section: Library + +:mod:`!encodings.aliases`: Add ``latin_N`` aliases + +.. + +.. date: 2025-07-15-16-37-34 +.. gh-issue: 136669 +.. nonce: Yexwah +.. section: Library + +:mod:`!_asyncio` is now statically linked for improved performance. + +.. + +.. date: 2025-07-13-13-31-22 +.. gh-issue: 136134 +.. nonce: mh6VjS +.. section: Library + +:meth:`!SMTP.auth_cram_md5` now raises an :exc:`~smtplib.SMTPException` +instead of a :exc:`ValueError` if Python has been built without MD5 support. +In particular, :class:`~smtplib.SMTP` clients will not attempt to use this +method even if the remote server is assumed to support it. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-07-13-11-20-05 +.. gh-issue: 136134 +.. nonce: xhh0Kq +.. section: Library + +:meth:`IMAP4.login_cram_md5 <imaplib.IMAP4.login_cram_md5>` now raises an +:exc:`IMAP4.error <imaplib.IMAP4.error>` if CRAM-MD5 authentication is not +supported. Patch by Bénédikt Tran. + +.. + +.. date: 2025-07-12-18-05-37 +.. gh-issue: 136591 +.. nonce: ujXmSN +.. section: Library + +:mod:`!_hashlib`: avoid using deprecated functions +:manpage:`ERR_func_error_string` and :manpage:`EVP_MD_CTX_md` when using +OpenSSL 3.0 and later. Patch by Bénédikt Tran. + +.. + +.. date: 2025-07-12-14-15-47 +.. gh-issue: 136571 +.. nonce: muHmBv +.. section: Library + +:meth:`datetime.date.fromisocalendar` can now raise OverflowError for out of +range arguments. + +.. + +.. date: 2025-07-11-23-04-39 +.. gh-issue: 136549 +.. nonce: oAi8u4 +.. section: Library + +Fix signature of :func:`threading.excepthook`. + +.. + +.. date: 2025-07-11-10-23-44 +.. gh-issue: 136492 +.. nonce: BVi5h0 +.. section: Library + +Expose :pep:`667`'s :data:`~types.FrameLocalsProxyType` in the :mod:`types` +module. + +.. + +.. date: 2025-07-11-08-15-17 +.. gh-issue: 83336 +.. nonce: ptpmq7 +.. section: Library + +``utf8_sig`` is now aliased to :mod:`encodings.utf_8_sig` + +.. + +.. date: 2025-07-11-03-39-15 +.. gh-issue: 136523 +.. nonce: s7caKL +.. section: Library + +Fix :class:`wave.Wave_write` emitting an unraisable when open raises. + +.. + +.. date: 2025-07-10-21-02-43 +.. gh-issue: 136507 +.. nonce: pnEuGS +.. section: Library + +Fix mimetypes CLI to handle multiple file parameters. + +.. + +.. date: 2025-07-10-10-18-19 +.. gh-issue: 52876 +.. nonce: 9Vjrd8 +.. section: Library + +Add missing ``keepends`` (default ``True``) parameter to +:meth:`!codecs.StreamReaderWriter.readline` and +:meth:`!codecs.StreamReaderWriter.readlines`. + +.. + +.. date: 2025-07-10-00-47-37 +.. gh-issue: 136470 +.. nonce: KlUEUG +.. section: Library + +Correct :class:`concurrent.futures.InterpreterPoolExecutor`'s default thread +name. + +.. + +.. date: 2025-07-09-20-29-30 +.. gh-issue: 136476 +.. nonce: HyLLzh +.. section: Library + +Fix a bug that was causing the ``get_async_stack_trace`` function to miss +some frames in the stack trace. + +.. + +.. date: 2025-07-08-20-58-01 +.. gh-issue: 136434 +.. nonce: uuJsjS +.. section: Library + +Fix docs generation of ``UnboundItem`` in :mod:`concurrent.interpreters` +when running with :option:`-OO`. + +.. + +.. date: 2025-07-07-22-12-32 +.. gh-issue: 136380 +.. nonce: 1b_nXl +.. section: Library + +Raises :exc:`AttributeError` when accessing +:class:`concurrent.futures.InterpreterPoolExecutor` and subinterpreters are +not available. + +.. + +.. date: 2025-07-07-16-46-55 +.. gh-issue: 72327 +.. nonce: wLvRuj +.. section: Library + +Suggest using the system command prompt when ``pip install`` is typed into +the REPL. Patch by Tom Viner, Richard Si, and Brian Schubert. + +.. + +.. date: 2025-07-06-18-38-10 +.. gh-issue: 135953 +.. nonce: Z29DCz +.. section: Library + +Implement a new high-frequency runtime profiler that leverages the existing +remote debugging functionality to collect detailed execution statistics from +running Python processes. This tool is exposed in the ``profile.sample`` +module and enables non-intrusive observation of production applications by +attaching to already-running processes without requiring any code +modifications, restarts, or special startup flags. The observer can perform +extremely high-frequency sampling of stack traces and interpreter state, +providing detailed runtime execution analysis of live applications. + +.. + +.. date: 2025-07-06-10-18-48 +.. gh-issue: 136021 +.. nonce: f-FJYT +.. section: Library + +Make ``type_params`` parameter required in :func:`!typing._eval_type` after +a deprecation period for not providing this parameter. Also remove the +:exc:`DeprecationWarning` for the old behavior. + +.. + +.. date: 2025-07-05-09-45-04 +.. gh-issue: 136286 +.. nonce: N67Amr +.. section: Library + +Fix pickling failures for protocols 0 and 1 for many objects related to +subinterpreters. + +.. + +.. date: 2025-07-05-06-59-46 +.. gh-issue: 136047 +.. nonce: qWvycf +.. section: Library + +Fix issues with :mod:`typing` when the C implementation of :mod:`abc` is not +available. + +.. + +.. date: 2025-07-05-06-56-16 +.. gh-issue: 136316 +.. nonce: 3zj_Do +.. section: Library + +Improve support for evaluating nested forward references in +:func:`typing.evaluate_forward_ref`. + +.. + +.. date: 2025-07-04-23-45-00 +.. gh-issue: 136306 +.. nonce: O1YLIU +.. section: Library + +:mod:`ssl` can now get and set groups used for key agreement. + +.. + +.. date: 2025-07-04-12-53-02 +.. gh-issue: 136156 +.. nonce: OYlXoz +.. section: Library + +:func:`tempfile.TemporaryFile` no longer uses :data:`os.O_EXCL` with +:data:`os.O_TMPFILE`, so it's possible to use ``linkat()`` on the file +descriptor. Patch by Victor Stinner. + +.. + +.. date: 2025-07-02-18-41-45 +.. gh-issue: 133982 +.. nonce: 7qqAn6 +.. section: Library + +Update Python implementation of :class:`io.BytesIO` to be thread safe. + +.. + +.. date: 2025-07-02-10-48-21 +.. gh-issue: 136193 +.. nonce: xfvras +.. section: Library + +Improve :exc:`TypeError` error message, when richcomparing two +:class:`types.SimpleNamespace` objects. + +.. + +.. date: 2025-07-01-14-44-03 +.. gh-issue: 136097 +.. nonce: bI1n14 +.. section: Library + +Fix potential infinite recursion and KeyError in ``sysconfig +--generate-posix-vars``. + +.. + +.. date: 2025-06-30-11-12-24 +.. gh-issue: 85702 +.. nonce: 0Lrbwu +.. section: Library + +If ``zoneinfo._common.load_tzdata`` is given a package without a resource a +:exc:`zoneinfo.ZoneInfoNotFoundError` is raised rather than a +:exc:`PermissionError`. Patch by Victor Stinner. + +.. + +.. date: 2025-06-29-15-22-13 +.. gh-issue: 90733 +.. nonce: NiquaA +.. section: Library + +Improve error messages when reporting invalid parameters in +:func:`hashlib.scrypt`. Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-28-11-32-57 +.. gh-issue: 134759 +.. nonce: AjjKcG +.. section: Library + +Fix :exc:`UnboundLocalError` in :func:`email.message.Message.get_payload` +when the payload to decode is a :class:`bytes` object. Patch by Kliment +Lamonov. + +.. + +.. date: 2025-06-27-13-34-28 +.. gh-issue: 136028 +.. nonce: RY727g +.. section: Library + +Fix parsing month names containing "İ" (U+0130, LATIN CAPITAL LETTER I WITH +DOT ABOVE) in :func:`time.strptime`. This affects locales az_AZ, ber_DZ, +ber_MA and crh_UA. + +.. + +.. date: 2025-06-27-09-26-04 +.. gh-issue: 87135 +.. nonce: 33z0UW +.. section: Library + +Acquiring a :class:`threading.Lock` or :class:`threading.RLock` at +interpreter shutdown will raise :exc:`PythonFinalizationError` if Python can +determine that it would otherwise deadlock. + +.. + +.. date: 2025-06-26-17-28-49 +.. gh-issue: 135995 +.. nonce: pPrDCt +.. section: Library + +In the palmos encoding, make byte ``0x9b`` decode to ``›`` (U+203A - SINGLE +RIGHT-POINTING ANGLE QUOTATION MARK). + +.. + +.. date: 2025-06-26-17-19-36 +.. gh-issue: 105456 +.. nonce: eR9oHB +.. section: Library + +Removed :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` +modules. + +.. + +.. date: 2025-06-26-11-52-40 +.. gh-issue: 53203 +.. nonce: TMigBr +.. section: Library + +Fix :func:`time.strptime` for ``%c`` and ``%x`` formats on locales byn_ER, +wal_ET and lzh_TW, and for ``%X`` format on locales ar_SA, bg_BG and lzh_TW. + +.. + +.. date: 2025-06-24-14-43-24 +.. gh-issue: 135878 +.. nonce: Db4roX +.. section: Library + +Fixes a crash of :class:`types.SimpleNamespace` on :term:`free threading` +builds, when several threads were calling its :meth:`~object.__repr__` +method at the same time. + +.. + +.. date: 2025-06-24-13-30-47 +.. gh-issue: 135853 +.. nonce: 7ejTvK +.. section: Library + +Add :func:`math.fmax` and :func:`math.fmin` to get the larger and smaller of +two floating-point values. Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-24-10-52-35 +.. gh-issue: 135836 +.. nonce: s37351 +.. section: Library + +Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could +occur when non-\ :exc:`OSError` exception is raised during connection and +socket's ``close()`` raises :exc:`!OSError`. + +.. + +.. date: 2025-06-24-10-23-37 +.. gh-issue: 135853 +.. nonce: 6xDNOG +.. section: Library + +:mod:`math`: expose C99 :func:`~math.signbit` function to determine whether +the sign bit of a floating-point value is set. Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-23-13-02-08 +.. gh-issue: 134531 +.. nonce: yUmj07 +.. section: Library + +:mod:`hmac`: use the :manpage:`EVP_MAC(3ssl)` interface for HMAC when Python +is built with OpenSSL 3.0 and later instead of the deprecated +:manpage:`HMAC_CTX(3ssl) <hmac(3)>` interface. Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-23-11-04-25 +.. gh-issue: 135836 +.. nonce: -C-c4v +.. section: Library + +Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could +occur when the Happy Eyeballs algorithm resulted in an empty exceptions list +during connection attempts. + +.. + +.. date: 2025-06-23-10-19-11 +.. gh-issue: 135855 +.. nonce: -J0AGF +.. section: Library + +Raise :exc:`TypeError` instead of :exc:`SystemError` when +:func:`!_interpreters.set___main___attrs` is passed a non-dict object. Patch +by Brian Schubert. + +.. + +.. date: 2025-06-22-22-03-06 +.. gh-issue: 135823 +.. nonce: iDBg97 +.. section: Library + +:mod:`netrc`: improve the error message when the security check for the +ownership of the default configuration file ``~/.netrc`` fails. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-06-22-16-23-44 +.. gh-issue: 135815 +.. nonce: 0DandH +.. section: Library + +:mod:`netrc`: skip security checks if :func:`os.getuid` is missing. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-06-22-02-16-17 +.. gh-issue: 135640 +.. nonce: FXyFL6 +.. section: Library + +Address bug where it was possible to call +:func:`xml.etree.ElementTree.ElementTree.write` on an ElementTree object +with an invalid root element. This behavior blanked the file passed to +``write`` if it already existed. + +.. + +.. date: 2025-06-20-17-06-59 +.. gh-issue: 90117 +.. nonce: GYWVrn +.. section: Library + +Speed up :mod:`pprint` for :class:`list` and :class:`tuple`. + +.. + +.. date: 2025-06-20-16-28-47 +.. gh-issue: 135759 +.. nonce: jne0Zi +.. section: Library + +:mod:`hashlib`: reject negative digest lengths in OpenSSL-based SHAKE +objects by raising a :exc:`ValueError`. Previously, negative lengths were +implicitly rejected by raising a :exc:`MemoryError` or a :exc:`SystemError`. +Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-18-19-25-32 +.. gh-issue: 123471 +.. nonce: lx1Xbt +.. section: Library + +Make concurrent iterations over :class:`itertools.chain` safe under +:term:`free threading`. + +.. + +.. date: 2025-06-18-13-58-13 +.. gh-issue: 135645 +.. nonce: 109nff +.. section: Library + +Added ``supports_isolated_interpreters`` field to +:data:`sys.implementation`. + +.. + +.. date: 2025-06-18-11-43-17 +.. gh-issue: 135646 +.. nonce: r7ekEn +.. section: Library + +Raise consistent :exc:`NameError` exceptions in +:func:`annotationlib.ForwardRef.evaluate` + +.. + +.. date: 2025-06-17-23-13-56 +.. gh-issue: 135557 +.. nonce: Bfcy4v +.. section: Library + +Fix races on :mod:`heapq` updates and :class:`list` reads on the :term:`free +threaded <free threading>` build. + +.. + +.. date: 2025-06-17-22-44-19 +.. gh-issue: 119180 +.. nonce: Ogv8Nj +.. section: Library + +Only fetch globals and locals if necessary in +:func:`annotationlib.get_annotations` + +.. + +.. date: 2025-06-16-15-03-03 +.. gh-issue: 135561 +.. nonce: mJCN8D +.. section: Library + +Fix a crash on DEBUG builds when an HACL* HMAC routine fails. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-06-16-15-00-13 +.. gh-issue: 135386 +.. nonce: lNrxLc +.. section: Library + +Fix opening a :mod:`dbm.sqlite3` database for reading from read-only file or +directory. + +.. + +.. date: 2025-06-16-12-37-02 +.. gh-issue: 135444 +.. nonce: An2eeA +.. section: Library + +Fix :meth:`asyncio.DatagramTransport.sendto` to account for datagram header +size when data cannot be sent. + +.. + +.. date: 2025-06-15-03-03-22 +.. gh-issue: 65697 +.. nonce: COdwZd +.. section: Library + +:class:`configparser`'s error message when attempting to write an invalid +key is now more helpful. + +.. + +.. date: 2025-06-14-14-19-13 +.. gh-issue: 135497 +.. nonce: 1pzwdA +.. section: Library + +Fix :func:`os.getlogin` failing for longer usernames on BSD-based platforms. + +.. + +.. date: 2025-06-14-12-06-55 +.. gh-issue: 135487 +.. nonce: KdVFff +.. section: Library + +Fix :meth:`!reprlib.Repr.repr_int` when given integers with more than +:func:`sys.get_int_max_str_digits` digits. Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-12-18-15-31 +.. gh-issue: 135429 +.. nonce: mch75_ +.. section: Library + +Fix the argument mismatch in ``_lsprof`` for ``PY_THROW`` event. + +.. + +.. date: 2025-06-12-10-45-02 +.. gh-issue: 135368 +.. nonce: OjWVHL +.. section: Library + +Fix :class:`unittest.mock.Mock` generation on :func:`dataclasses.dataclass` +objects. Now all special attributes are set as it was before :gh:`124429`. + +.. + +.. date: 2025-06-11-15-08-02 +.. gh-issue: 135336 +.. nonce: 6Gq6MI +.. section: Library + +:mod:`json` now encodes strings up to 2.2x faster if they consist solely of +characters that don’t require escaping. + +.. + +.. date: 2025-06-10-21-42-04 +.. gh-issue: 135335 +.. nonce: WnUqb_ +.. section: Library + +:mod:`multiprocessing`: Flush ``stdout`` and ``stderr`` after preloading +modules in the ``forkserver``. + +.. + +.. date: 2025-06-10-21-00-48 +.. gh-issue: 126631 +.. nonce: eITVJd +.. section: Library + +Fix :mod:`multiprocessing` ``forkserver`` bug which prevented ``__main__`` +from being preloaded. + +.. + +.. date: 2025-06-10-16-11-00 +.. gh-issue: 133967 +.. nonce: P0c24q +.. section: Library + +Do not normalize :mod:`locale` name 'C.UTF-8' to 'en_US.UTF-8'. + +.. + +.. date: 2025-06-10-10-22-18 +.. gh-issue: 130870 +.. nonce: JipqbO +.. section: Library + +Preserve :class:`types.GenericAlias` subclasses in +:func:`typing.get_type_hints` + +.. + +.. date: 2025-06-10-00-42-30 +.. gh-issue: 135321 +.. nonce: UHh9jT +.. section: Library + +Raise a correct exception for values greater than 0x7fffffff for the +``BINSTRING`` opcode in the C implementation of :mod:`pickle`. + +.. + +.. date: 2025-06-09-10-16-55 +.. gh-issue: 121914 +.. nonce: G6Avkq +.. section: Library + +Changed the names of the symbol tables for lambda expressions and generator +expressions to "<lambda>" and "<genexpr>" respectively to avoid conflicts +with user-defined names. + +.. + +.. date: 2025-06-08-14-50-34 +.. gh-issue: 135276 +.. nonce: ZLUhV1 +.. section: Library + +Synchronized zipfile.Path with zipp 3.23, including improved performance of +:meth:`zipfile.Path.open` for non-reading modes, rely on +:func:`functools.cached_property` to cache values on the instance. Rely on +``save_method_args`` to save the initialization method arguments. Fixed +``.name``, ``.stem`` and other basename-based properties on Windows when +working with a zipfile on disk. + +.. + +.. date: 2025-06-08-11-11-07 +.. gh-issue: 135234 +.. nonce: wJCdh0 +.. section: Library + +:mod:`hashlib`: improve exception messages when an OpenSSL function failed. +When memory allocation fails on OpenSSL's side, a :exc:`MemoryError` is +raised instead of a :exc:`ValueError`. Patch by Bénédikt Tran. + +.. + +.. date: 2025-06-08-10-22-22 +.. gh-issue: 135244 +.. nonce: Y2SOTJ +.. section: Library + +:mod:`uuid`: when the MAC address cannot be determined, the 48-bit node ID +is now generated with a cryptographically-secure pseudo-random number +generator (CSPRNG) as per :rfc:`RFC 9562, §6.10.3 <9562#section-6.10-3>`. +This affects :func:`~uuid.uuid1` and :func:`~uuid.uuid6`. + +.. + +.. date: 2025-06-08-01-10-34 +.. gh-issue: 135241 +.. nonce: 5j18IW +.. section: Library + +The :code:`INT` opcode of the C accelerator :mod:`!_pickle` module was +updated to look only for "00" and "01" to push booleans onto the stack, +aligning with the Python :mod:`pickle` module. + +.. + +.. date: 2025-06-06-17-34-18 +.. gh-issue: 133934 +.. nonce: yT1r68 +.. section: Library + +Improve :mod:`sqlite3` CLI's ``.help`` message. + +.. + +.. date: 2025-06-03-12-59-17 +.. gh-issue: 135069 +.. nonce: xop30V +.. section: Library + +Fix the "Invalid error handling" exception in +:class:`!encodings.idna.IncrementalDecoder` to correctly replace the +'errors' parameter. + +.. + +.. date: 2025-06-02-14-36-28 +.. gh-issue: 130662 +.. nonce: Gpr2GB +.. section: Library + ++Accept leading zeros in precision and width fields for ++:class:`~decimal.Decimal` formatting, for example ``format(Decimal(1.25), +'.016f')``. + +.. + +.. date: 2025-06-02-14-28-30 +.. gh-issue: 130662 +.. nonce: EIgIR8 +.. section: Library + +Accept leading zeros in precision and width fields for +:class:`~fractions.Fraction` formatting, for example ``format(Fraction(1, +3), '.016f')``. + +.. + +.. date: 2025-06-01-14-18-48 +.. gh-issue: 135004 +.. nonce: cq3-fp +.. section: Library + +Rewrite and cleanup the internal :mod:`!_blake2` module. Some exception +messages were changed but their types were left untouched. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-06-01-11-14-00 +.. gh-issue: 134953 +.. nonce: ashdfs +.. section: Library + +Expand ``_colorize`` theme with ``keyword_constant`` and implement in +:term:`repl`. + +.. + +.. date: 2025-05-31-15-49-46 +.. gh-issue: 134978 +.. nonce: mXXuvW +.. section: Library + +:mod:`hashlib`: Supporting the ``string`` keyword parameter in hash function +constructors such as :func:`~hashlib.new` or the direct hash-named +constructors such as :func:`~hashlib.md5` and :func:`~hashlib.sha256` is now +deprecated and slated for removal in Python 3.19. Prefer passing the initial +data as a positional argument for maximum backwards compatibility. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-05-31-12-08-12 +.. gh-issue: 134970 +.. nonce: lgSaxq +.. section: Library + +Fix the "unknown action" exception in +:meth:`argparse.ArgumentParser.add_argument_group` to correctly replace the +action class. + +.. + +.. date: 2025-05-30-18-13-48 +.. gh-issue: 134718 +.. nonce: 5FEspx +.. section: Library + +By default, omit optional ``Load()`` values in :func:`ast.dump`. + +.. + +.. date: 2025-05-30-13-07-29 +.. gh-issue: 134718 +.. nonce: 9Qvhxn +.. section: Library + +:func:`ast.dump` now only omits ``None`` and ``[]`` values if they are +default values. + +.. + +.. date: 2025-05-30-09-46-21 +.. gh-issue: 134939 +.. nonce: Pu3nnm +.. section: Library + +Add the :mod:`concurrent.interpreters` module. See :pep:`734`. + +.. + +.. date: 2025-05-29-17-39-13 +.. gh-issue: 108885 +.. nonce: MegCRA +.. section: Library + +Run each example as a subtest in unit tests synthesized by +:func:`doctest.DocFileSuite` and :func:`doctest.DocTestSuite`. Add the +:meth:`doctest.DocTestRunner.report_skip` method. + +.. + +.. date: 2025-05-29-06-53-40 +.. gh-issue: 134885 +.. nonce: -_L22o +.. section: Library + +Fix possible crash in the :mod:`compression.zstd` module related to setting +parameter types. Patch by Jelle Zijlstra. + +.. + +.. date: 2025-05-28-20-49-29 +.. gh-issue: 134857 +.. nonce: dVYXVO +.. section: Library + +Improve error report for :mod:`doctest`\ s run with :mod:`unittest`. Remove +:mod:`!doctest` module frames from tracebacks and redundant newline +character from a failure message. + +.. + +.. date: 2025-05-28-15-53-27 +.. gh-issue: 128840 +.. nonce: Nur2pB +.. section: Library + +Fix parsing long IPv6 addresses with embedded IPv4 address. + +.. + +.. date: 2025-05-27-11-24-38 +.. gh-issue: 133579 +.. nonce: WGPUC1 +.. section: Library + +:mod:`curses`: Consistently report failures of curses C API calls in +module-level methods by raising a :exc:`curses.error`. This affects +:func:`~curses.assume_default_colors`, :func:`~curses.baudrate`, +:func:`~curses.cbreak`, :func:`~curses.echo`, :func:`~curses.longname`, +:func:`~curses.initscr`, :func:`~curses.nl`, :func:`~curses.raw`, +:func:`~curses.termattrs`, :func:`~curses.termname` and +:func:`~curses.unctrl`. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-27-11-18-13 +.. gh-issue: 133579 +.. nonce: ohtgdC +.. section: Library + +:meth:`curses.window.refresh` and :meth:`curses.window.noutrefresh` now +raise a :exc:`TypeError` instead of :exc:`curses.error` when called with an +incorrect number of arguments for :ref:`pads <windows-and-pads>`. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-05-27-11-13-51 +.. gh-issue: 133579 +.. nonce: KY9M6S +.. section: Library + +:ref:`curses.window <curses-window-objects>`: Consistently report failures +of curses C API calls in Window methods by raising a :exc:`curses.error`. +This affects :meth:`~curses.window.addch`, :meth:`~curses.window.addnstr`, +:meth:`~curses.window.addstr`, :meth:`~curses.window.border`, +:meth:`~curses.window.box`, :meth:`~curses.window.chgat`, +:meth:`~curses.window.getbkgd`, :meth:`~curses.window.inch`, +:meth:`~curses.window.insstr` and :meth:`~curses.window.insnstr`. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-05-26-22-18-32 +.. gh-issue: 134771 +.. nonce: RKXpLT +.. section: Library + +The ``time_clockid_converter()`` function now selects correct type for +``clockid_t`` on Cygwin which fixes a build error. + +.. + +.. date: 2025-05-26-17-06-40 +.. gh-issue: 134637 +.. nonce: 9-3zRL +.. section: Library + +Fix performance regression in calling a :mod:`ctypes` function pointer in +:term:`free threading`. + +.. + +.. date: 2025-05-26-14-04-39 +.. gh-issue: 134696 +.. nonce: P04xUa +.. section: Library + +Built-in HACL* and OpenSSL implementations of hash function constructors now +correctly accept the same *documented* named arguments. For instance, +:func:`~hashlib.md5` could be previously invoked as ``md5(data=data)`` or +``md5(string=string)`` depending on the underlying implementation but these +calls were not compatible. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-26-12-31-08 +.. gh-issue: 132710 +.. nonce: ApU3TZ +.. section: Library + +If possible, ensure that :func:`uuid.getnode` returns the same result even +across different processes. Previously, the result was constant only within +the same process. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-26-11-01-54 +.. gh-issue: 134531 +.. nonce: my1Fzt +.. section: Library + +:mod:`!_hashlib`: Rename internal C functions for :class:`!_hashlib.HASH` +and :class:`!_hashlib.HASHXOF` objects. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-26-10-52-27 +.. gh-issue: 134698 +.. nonce: aJ1mZ1 +.. section: Library + +Fix a crash when calling methods of :class:`ssl.SSLContext` or +:class:`ssl.SSLSocket` across multiple threads. + +.. + +.. date: 2025-05-25-23-23-05 +.. gh-issue: 134151 +.. nonce: 13Wwsb +.. section: Library + +:mod:`email`: Fix :exc:`TypeError` in :func:`email.utils.decode_params` when +sorting :rfc:`2231` continuations that contain an unnumbered section. + +.. + +.. date: 2025-05-25-13-46-37 +.. gh-issue: 134635 +.. nonce: ZlPrlX +.. section: Library + +:mod:`zlib`: Allow to combine Adler-32 and CRC-32 checksums via +:func:`~zlib.adler32_combine` and :func:`~zlib.crc32_combine`. Patch by +Callum Attryde and Bénédikt Tran. + +.. + +.. date: 2025-05-25-11-02-05 +.. gh-issue: 134657 +.. nonce: 3YFhR9 +.. section: Library + +:mod:`asyncio`: Remove some private names from ``asyncio.__all__``. + +.. + +.. date: 2025-05-24-13-10-35 +.. gh-issue: 134210 +.. nonce: 0IuMY2 +.. section: Library + +:func:`curses.window.getch` now correctly handles signals. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-05-24-03-10-36 +.. gh-issue: 80334 +.. nonce: z21cMa +.. section: Library + +:func:`multiprocessing.freeze_support` now checks for work on any "spawn" +start method platform rather than only on Windows. + +.. + +.. date: 2025-05-23-23-43-39 +.. gh-issue: 134582 +.. nonce: 9POq3l +.. section: Library + +Fix tokenize.untokenize() round-trip errors related to t-strings braces +escaping + +.. + +.. date: 2025-05-23-20-01-52 +.. gh-issue: 134580 +.. nonce: xnaJ70 +.. section: Library + +Improved the styling of HTML diff pages generated by the +:class:`difflib.HtmlDiff` class, and migrated the output to the HTML5 +standard. + +.. + +.. date: 2025-05-23-10-15-36 +.. gh-issue: 134565 +.. nonce: zmb66C +.. section: Library + +:func:`unittest.doModuleCleanups` no longer swallows all but first exception +raised in the cleanup code, but raises a :exc:`ExceptionGroup` if multiple +errors occurred. + +.. + +.. date: 2025-05-22-18-14-13 +.. gh-issue: 134546 +.. nonce: fjLVzK +.. section: Library + +Ensure :mod:`pdb` remote debugging script is readable by remote Python +process. + +.. + +.. date: 2025-05-22-14-12-53 +.. gh-issue: 134451 +.. nonce: M1rD-j +.. section: Library + +Converted ``asyncio.tools.CycleFoundException`` from dataclass to a regular +exception type. + +.. + +.. date: 2025-05-22-13-10-32 +.. gh-issue: 114177 +.. nonce: 3TYUJ3 +.. section: Library + +Fix :mod:`asyncio` to not close subprocess pipes which would otherwise error +out when the event loop is already closed. + +.. + +.. date: 2025-05-20-21-45-58 +.. gh-issue: 90871 +.. nonce: Gkvtp6 +.. section: Library + +Fixed an off by one error concerning the backlog parameter in +:meth:`~asyncio.loop.create_unix_server`. Contributed by Christian Harries. + +.. + +.. date: 2025-05-20-19-16-30 +.. gh-issue: 134323 +.. nonce: ZQZGvw +.. section: Library + +Fix the :meth:`threading.RLock.locked` method. + +.. + +.. date: 2025-05-20-15-13-43 +.. gh-issue: 86802 +.. nonce: trF7TM +.. section: Library + +Fixed asyncio memory leak in cancelled shield tasks. For shielded tasks +where the shield was cancelled, log potential exceptions through the +exception handler. Contributed by Christian Harries. + +.. + +.. date: 2025-05-20-11-51-17 +.. gh-issue: 71189 +.. nonce: 0LpTB1 +.. section: Library + +Add support of the all-but-last mode in :func:`os.path.realpath`. + +.. + +.. date: 2025-05-20-11-35-08 +.. gh-issue: 72902 +.. nonce: jzEI-E +.. section: Library + +Improve speed (x1.1-1.8) of the :class:`~fractions.Fraction` constructor for +typical inputs (:class:`float`'s, :class:`~decimal.Decimal`'s or strings). + +.. + +.. date: 2025-05-19-20-59-06 +.. gh-issue: 134209 +.. nonce: anhTcF +.. section: Library + +:mod:`curses`: The :meth:`curses.window.instr` and +:meth:`curses.window.getstr` methods now allocate their internal buffer on +the heap instead of the stack; in addition, the max buffer size is increased +from 1023 to 2047. + +.. + +.. date: 2025-05-19-18-12-42 +.. gh-issue: 88994 +.. nonce: 7avvVu +.. section: Library + +Change :func:`datetime.datetime.now` to half-even rounding for consistency +with :func:`datetime.datetime.fromtimestamp`. Patch by John Keith Hohm. + +.. + +.. date: 2025-05-19-17-27-21 +.. gh-issue: 80184 +.. nonce: LOkbaw +.. section: Library + +The default queue size is now ``socket.SOMAXCONN`` for +:class:`socketserver.TCPServer`. + +.. + +.. date: 2025-05-19-15-30-00 +.. gh-issue: 132983 +.. nonce: asdsfs +.. section: Library + +Add :mod:`!compression.zstd` version information to ``test.pythoninfo``. + +.. + +.. date: 2025-05-19-15-05-24 +.. gh-issue: 134235 +.. nonce: pz9PwV +.. section: Library + +Updated tab completion on REPL to include builtin modules. Contributed by +Tom Wang, Hunter Young + +.. + +.. date: 2025-05-19-10-32-11 +.. gh-issue: 134152 +.. nonce: INJC2j +.. section: Library + +Fixed :exc:`UnboundLocalError` that could occur during :mod:`email` header +parsing if an expected trailing delimiter is missing in some contexts. + +.. + +.. date: 2025-05-18-23-46-21 +.. gh-issue: 134152 +.. nonce: 30HwbX +.. section: Library + +:mod:`email`: Fix parsing of email message ID with invalid domain. + +.. + +.. date: 2025-05-18-13-23-29 +.. gh-issue: 134168 +.. nonce: hgx3Xg +.. section: Library + +:mod:`http.server`: Fix IPv6 address binding and :option:`--directory +<http.server --directory>` handling when using HTTPS. + +.. + +.. date: 2025-05-18-12-48-39 +.. gh-issue: 62184 +.. nonce: y11l10 +.. section: Library + +Remove import of C implementation of :class:`io.FileIO` from Python +implementation which has its own implementation + +.. + +.. date: 2025-05-18-12-23-07 +.. gh-issue: 134087 +.. nonce: HilZWl +.. section: Library + +Remove support for arbitrary positional or keyword arguments in the C +implementation of :class:`threading.RLock` objects. This was deprecated +since Python 3.14. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-18-07-25-15 +.. gh-issue: 134173 +.. nonce: 53oOoF +.. section: Library + +Speed up :mod:`asyncio` performance of transferring state from thread pool +:class:`concurrent.futures.Future` by up to 4.4x. Patch by J. Nick Koston. + +.. + +.. date: 2025-05-17-20-23-57 +.. gh-issue: 133982 +.. nonce: smS7au +.. section: Library + +Emit :exc:`RuntimeWarning` in the Python implementation of :mod:`io` when +the :term:`file-like object <file object>` is not closed explicitly in the +presence of multiple I/O layers. + +.. + +.. date: 2025-05-17-18-08-35 +.. gh-issue: 133890 +.. nonce: onn9_X +.. section: Library + +The :mod:`tarfile` module now handles :exc:`UnicodeEncodeError` in the same +way as :exc:`OSError` when cannot extract a member. + +.. + +.. date: 2025-05-17-13-46-20 +.. gh-issue: 134097 +.. nonce: fgkjE1 +.. section: Library + +Fix interaction of the new :term:`REPL` and :option:`-X showrefcount <-X>` +command line option. + +.. + +.. date: 2025-05-17-12-40-12 +.. gh-issue: 133889 +.. nonce: Eh-zO4 +.. section: Library + +The generated directory listing page in +:class:`http.server.SimpleHTTPRequestHandler` now only shows the decoded +path component of the requested URL, and not the query and fragment. + +.. + +.. date: 2025-05-16-20-10-25 +.. gh-issue: 134098 +.. nonce: YyTkKr +.. section: Library + +Fix handling paths that end with a percent-encoded slash (``%2f`` or +``%2F``) in :class:`http.server.SimpleHTTPRequestHandler`. + +.. + +.. date: 2025-05-16-12-40-37 +.. gh-issue: 132124 +.. nonce: T_5Odx +.. section: Library + +On POSIX-compliant systems, :func:`!multiprocessing.util.get_temp_dir` now +ignores :envvar:`TMPDIR` (and similar environment variables) if the path +length of ``AF_UNIX`` socket files exceeds the platform-specific maximum +length when using the :ref:`forkserver +<multiprocessing-start-method-forkserver>` start method. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-05-15-14-27-01 +.. gh-issue: 134062 +.. nonce: fRbJet +.. section: Library + +:mod:`ipaddress`: fix collisions in :meth:`~object.__hash__` for +:class:`~ipaddress.IPv4Network` and :class:`~ipaddress.IPv6Network` objects. + +.. + +.. date: 2025-05-15-00-27-09 +.. gh-issue: 134004 +.. nonce: e8k4-R +.. section: Library + +:mod:`shelve` as well as underlying :mod:`!dbm.dumb` and :mod:`!dbm.sqlite` +now have :meth:`!reorganize` methods to recover unused free space previously +occupied by deleted entries. + +.. + +.. date: 2025-05-13-18-54-56 +.. gh-issue: 133970 +.. nonce: 6G-Oi6 +.. section: Library + +Make :class:`!string.templatelib.Template` and +:class:`!string.templatelib.Interpolation` generic. + +.. + +.. date: 2025-05-13-18-21-59 +.. gh-issue: 71253 +.. nonce: -3Sf_K +.. section: Library + +Raise :exc:`ValueError` in :func:`open` if *opener* returns a negative +file-descriptor in the Python implementation of :mod:`io` to match the C +implementation. + +.. + +.. date: 2025-05-12-20-38-57 +.. gh-issue: 133960 +.. nonce: Aee79f +.. section: Library + +Simplify and improve :func:`typing.evaluate_forward_ref`. It now no longer +raises errors on certain invalid types. In several situations, it is now +able to evaluate forward references that were previously unsupported. + +.. + +.. date: 2025-05-12-06-52-10 +.. gh-issue: 133925 +.. nonce: elInBY +.. section: Library + +Make the private class ``typing._UnionGenericAlias`` hashable. + +.. + +.. date: 2025-05-11-12-56-52 +.. gh-issue: 133604 +.. nonce: kFxhc8 +.. section: Library + +Remove :func:`!platform.java_ver` which was deprecated since Python 3.13. + +.. + +.. date: 2025-05-11-11-39-05 +.. gh-issue: 133875 +.. nonce: pUar3l +.. section: Library + +Removed deprecated :meth:`!pathlib.PurePath.is_reserved`. Use +:func:`os.path.isreserved` to detect reserved paths on Windows. + +.. + +.. date: 2025-05-11-10-28-11 +.. gh-issue: 133873 +.. nonce: H03nov +.. section: Library + +Remove the deprecated ``getmark()``, ``setmark()`` and ``getmarkers()`` +methods of the :class:`~wave.Wave_read` and :class:`~wave.Wave_write` +classes, which were deprecated since Python 3.13. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-11-10-01-48 +.. gh-issue: 133866 +.. nonce: g3dHP_ +.. section: Library + +Remove the undocumented function :func:`!ctypes.SetPointerType`, which has +been deprecated since Python 3.13. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-11-08-48-55 +.. gh-issue: 133823 +.. nonce: F8udQy +.. section: Library + +Remove support for ``TD = TypedDict("TD")`` and ``TD = TypedDict("TD", +None)`` calls for constructing :class:`typing.TypedDict` objects with zero +field. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-10-17-42-03 +.. gh-issue: 125996 +.. nonce: vaQp0- +.. section: Library + +Fix thread safety of :class:`collections.OrderedDict`. Patch by Kumar +Aditya. + +.. + +.. date: 2025-05-10-12-07-54 +.. gh-issue: 133817 +.. nonce: 4GMtKV +.. section: Library + +Remove support for creating :class:`~typing.NamedTuple` classes via the +undocumented keyword argument syntax. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-10-12-06-55 +.. gh-issue: 133653 +.. nonce: Gb2aG4 +.. section: Library + +Fix :class:`argparse.ArgumentParser` with the *formatter_class* argument. +Fix TypeError when *formatter_class* is a custom subclass of +:class:`!HelpFormatter`. Fix TypeError when *formatter_class* is not a +subclass of :class:`!HelpFormatter` and non-standard *prefix_char* is used. +Fix support of colorizing when *formatter_class* is not a subclass of +:class:`!HelpFormatter`. + +.. + +.. date: 2025-05-10-11-04-47 +.. gh-issue: 133810 +.. nonce: 03WhnK +.. section: Library + +Remove :class:`!http.server.CGIHTTPRequestHandler` and ``--cgi`` flag from +the :program:`python -m http.server` command-line interface. They were +deprecated in Python 3.13. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-09-20-59-24 +.. gh-issue: 132641 +.. nonce: 3qTw44 +.. section: Library + +Fixed a race in :func:`functools.lru_cache` under free-threading. + +.. + +.. date: 2025-05-09-19-05-24 +.. gh-issue: 133783 +.. nonce: 1voCnR +.. section: Library + +Fix bug with applying :func:`copy.replace` to :mod:`ast` objects. Attributes +that default to ``None`` were incorrectly treated as required for manually +created AST nodes. + +.. + +.. date: 2025-05-09-18-29-25 +.. gh-issue: 133684 +.. nonce: Y1DFSt +.. section: Library + +Fix bug where :func:`annotationlib.get_annotations` would return the wrong +result for certain classes that are part of a class hierarchy where ``from +__future__ import annotations`` is used. + +.. + +.. date: 2025-05-09-15-50-00 +.. gh-issue: 77057 +.. nonce: fV8SU- +.. section: Library + +Fix handling of invalid markup declarations in +:class:`html.parser.HTMLParser`. + +.. + +.. date: 2025-05-09-09-10-34 +.. gh-issue: 130328 +.. nonce: s9h4By +.. section: Library + +Speedup pasting in ``PyREPL`` on Windows in a legacy console. Patch by Chris +Eibl. + +.. + +.. date: 2025-05-09-08-49-03 +.. gh-issue: 133701 +.. nonce: KI8tGz +.. section: Library + +Fix bug where :class:`typing.TypedDict` classes defined under ``from +__future__ import annotations`` and inheriting from another ``TypedDict`` +had an incorrect ``__annotations__`` attribute. + +.. + +.. date: 2025-05-08-20-45-35 +.. gh-issue: 133656 +.. nonce: cxZODA +.. section: Library + +Remove deprecated :meth:`!zipimport.zipimporter.load_module`. Use +:meth:`zipimport.zipimporter.exec_module` instead. + +.. + +.. date: 2025-05-08-20-03-20 +.. gh-issue: 133722 +.. nonce: 1-B82a +.. section: Library + +Added a *color* option to :func:`difflib.unified_diff` that colors output +similar to :program:`git diff`. + +.. + +.. date: 2025-05-08-13-43-19 +.. gh-issue: 133489 +.. nonce: 9eGS1Z +.. section: Library + +:func:`random.getrandbits` can now generate more that 2\ :sup:`31` bits. +:func:`random.randbytes` can now generate more that 256 MiB. + +.. + +.. date: 2025-05-07-22-15-15 +.. gh-issue: 133595 +.. nonce: c3U88r +.. section: Library + +Clean up :class:`sqlite3.Connection` APIs. All parameters of +:func:`sqlite3.connect` except *database* are now keyword-only. The first +three parameters of methods :meth:`~sqlite3.Connection.create_function` and +:meth:`~sqlite3.Connection.create_aggregate` are now positional-only. The +first parameter of methods :meth:`~sqlite3.Connection.set_authorizer`, +:meth:`~sqlite3.Connection.set_progress_handler` and +:meth:`~sqlite3.Connection.set_trace_callback` is now positional-only. + +.. + +.. date: 2025-05-07-19-16-41 +.. gh-issue: 133581 +.. nonce: kERUCJ +.. section: Library + +Improve unparsing of t-strings in :func:`ast.unparse` and ``from __future__ +import annotations``. Empty t-strings now round-trip correctly and +formatting in interpolations is preserved. Patch by Jelle Zijlstra. + +.. + +.. date: 2025-05-07-14-36-30 +.. gh-issue: 133577 +.. nonce: BggPk9 +.. section: Library + +Add parameter ``formatter`` to :func:`logging.basicConfig`. + +.. + +.. date: 2025-05-07-13-31-06 +.. gh-issue: 92897 +.. nonce: ubeqGE +.. section: Library + +Removed the ``check_home`` parameter from :func:`sysconfig.is_python_build`, +deprecated since Python 3.12. + +.. + +.. date: 2025-05-06-22-54-37 +.. gh-issue: 133551 +.. nonce: rfy1tJ +.. section: Library + +Support t-strings (:pep:`750`) in :mod:`annotationlib`. Patch by Jelle +Zijlstra. + +.. + +.. date: 2025-05-06-14-44-55 +.. gh-issue: 133517 +.. nonce: Ca6NgW +.. section: Library + +Remove :func:`os.listdrives`, :func:`os.listvolumes` and +:func:`os.listmounts` in non Windows desktop builds since the underlying +functionality is missing. + +.. + +.. date: 2025-05-05-22-11-24 +.. gh-issue: 133439 +.. nonce: LpmyFz +.. section: Library + +Fix dot commands with trailing spaces are mistaken for multi-line SQL +statements in the sqlite3 command-line interface. + +.. + +.. date: 2025-05-05-18-50-00 +.. gh-issue: 133447 +.. nonce: ajshdb +.. section: Library + +Add basic color to :mod:`sqlite3` CLI interface. + +.. + +.. date: 2025-05-05-10-41-41 +.. gh-issue: 133253 +.. nonce: J5-xDD +.. section: Library + +Fix thread-safety issues in :mod:`linecache`. + +.. + +.. date: 2025-05-05-03-14-08 +.. gh-issue: 133390 +.. nonce: AuTggn +.. section: Library + +Support keyword completion in the :mod:`sqlite3` command-line interface and +add :data:`sqlite3.SQLITE_KEYWORDS` constant. + +.. + +.. date: 2025-05-04-17-04-55 +.. gh-issue: 132493 +.. nonce: huirKi +.. section: Library + +Avoid accessing ``__annotations__`` unnecessarily in +:func:`inspect.signature`. + +.. + +.. date: 2025-05-01-16-03-11 +.. gh-issue: 133017 +.. nonce: k7RLQp +.. section: Library + +Improve the error message of :func:`multiprocessing.sharedctypes.Array`, +:func:`multiprocessing.sharedctypes.RawArray`, +:func:`multiprocessing.sharedctypes.Value` and +:func:`multiprocessing.sharedctypes.RawValue` when an invalid typecode is +passed. Patch by Tomas Roun + +.. + +.. date: 2025-05-01-10-56-44 +.. gh-issue: 132813 +.. nonce: rKurvp +.. section: Library + +Improve error messages for incorrect types and values of +:class:`csv.Dialect` attributes. + +.. + +.. date: 2025-04-30-19-32-18 +.. gh-issue: 132969 +.. nonce: EagQ3G +.. section: Library + +Prevent the :class:`~concurrent.futures.ProcessPoolExecutor` executor +thread, which remains running when :meth:`shutdown(wait=False) +<concurrent.futures.Executor.shutdown>`, from attempting to adjust the +pool's worker processes after the object state has already been reset during +shutdown. A combination of conditions, including a worker process having +terminated abormally, resulted in an exception and a potential hang when the +still-running executor thread attempted to replace dead workers within the +pool. + +.. + +.. date: 2025-04-29-11-48-46 +.. gh-issue: 132876 +.. nonce: lyTQGZ +.. section: Library + +``ldexp()`` on Windows doesn't round subnormal results before Windows 11, +but should. Python's :func:`math.ldexp` wrapper now does round them, so +results may change slightly, in rare cases of very small results, on Windows +versions before 11. + +.. + +.. date: 2025-04-26-15-50-12 +.. gh-issue: 133009 +.. nonce: etBuz5 +.. section: Library + +:mod:`xml.etree.ElementTree`: Fix a crash in :meth:`Element.__deepcopy__ +<object.__deepcopy__>` when the element is concurrently mutated. Patch by +Bénédikt Tran. + +.. + +.. date: 2025-04-25-16-06-53 +.. gh-issue: 132908 +.. nonce: wV5rja +.. section: Library + +Add :func:`math.isnormal` and :func:`math.issubnormal` functions. Patch by +Sergey B Kirpichev. + +.. + +.. date: 2025-04-25-11-53-37 +.. gh-issue: 95380 +.. nonce: 7dvPe- +.. section: Library + +:func:`fcntl.fcntl` and :func:`fcntl.ioctl`: Remove the 1024 bytes limit on +the size of not mutated bytes-like argument. + +.. + +.. date: 2025-04-25-11-48-00 +.. gh-issue: 122781 +.. nonce: ajsdns +.. section: Library + +Fix ``%z`` directive in :func:`datetime.datetime.strptime` to allow for no +provided offset as was documented. + +.. + +.. date: 2025-04-22-21-00-23 +.. gh-issue: 123471 +.. nonce: asOLA2 +.. section: Library + +Make concurrent iterations over :class:`itertools.combinations` and +:class:`itertools.product` safe under free-threading. + +.. + +.. date: 2025-04-21-01-05-14 +.. gh-issue: 127081 +.. nonce: Egrpq7 +.. section: Library + +Fix libc thread safety issues with :mod:`dbm` by performing stateful +operations in critical sections. + +.. + +.. date: 2025-04-21-01-03-15 +.. gh-issue: 127081 +.. nonce: WXRliX +.. section: Library + +Fix libc thread safety issues with :mod:`os` by replacing ``getlogin`` with +``getlogin_r`` re-entrant version. + +.. + +.. date: 2025-04-21-00-58-04 +.. gh-issue: 127081 +.. nonce: 3DCl92 +.. section: Library + +Fix libc thread safety issues with :mod:`pwd` by locking access to +``getpwall``. + +.. + +.. date: 2025-04-16-21-02-57 +.. gh-issue: 132551 +.. nonce: Psa7pL +.. section: Library + +Make :class:`io.BytesIO` safe in :term:`free-threaded <free threading>` +build. + +.. + +.. date: 2025-04-08-07-25-10 +.. gh-issue: 107583 +.. nonce: JGfbhq +.. section: Library + +Fix :class:`!Flag` inversion when flag set has missing values +(:class:`!IntFlag` still flips all bits); fix negative assigned values +during flag creation (both :class:`!Flag` and :class:`!IntFlag` ignore +missing values). + +.. + +.. date: 2025-04-07-10-20-16 +.. gh-issue: 87790 +.. nonce: X2SjJe +.. section: Library + +Support underscore and comma as thousands separators in the fractional part +for :class:`~fractions.Fraction`'s formatting. Patch by Sergey B Kirpichev. + +.. + +.. date: 2025-04-07-09-53-54 +.. gh-issue: 87790 +.. nonce: 6nj3zQ +.. section: Library + +Support underscore and comma as thousands separators in the fractional part +for :class:`~decimal.Decimal`'s formatting. Patch by Sergey B Kirpichev. + +.. + +.. date: 2025-04-07-06-41-54 +.. gh-issue: 131884 +.. nonce: ym9BJN +.. section: Library + +Fix formatting issues in :func:`json.dump` when both *indent* and *skipkeys* +are used. + +.. + +.. date: 2025-03-27-08-13-32 +.. gh-issue: 131788 +.. nonce: 0RWiFc +.. section: Library + +Make ``ResourceTracker.send`` from :mod:`multiprocessing` re-entrant safe + +.. + +.. date: 2025-03-19-12-41-42 +.. gh-issue: 91349 +.. nonce: 8eTOCP +.. section: Library + +Adjust default ``compressionlevel=`` to 6 (down from 9) in :mod:`gzip` and +:mod:`tarfile`. It is the default level used by most compression tools and a +better tradeoff between speed and performance. + +.. + +.. date: 2025-03-17-21-21-06 +.. gh-issue: 131146 +.. nonce: A5Obgv +.. section: Library + +Fix :class:`calendar.TextCalendar`, :class:`calendar.HTMLCalendar`, and the +:mod:`calendar` CLI to display month names in the nominative case by adding +:data:`calendar.standalone_month_name` and +:data:`calendar.standalone_month_abbr`, which provide month names and +abbreviations in the grammatical form used when a month name stands by +itself, if the locale supports it. + +.. + +.. date: 2025-03-13-20-48-58 +.. gh-issue: 123471 +.. nonce: cM4w4f +.. section: Library + +Make concurrent iterations over :class:`itertools.cycle` safe under +free-threading. + +.. + +.. date: 2025-03-11-05-24-14 +.. gh-issue: 130664 +.. nonce: g0yNMm +.. section: Library + +Handle corner-case for :class:`~fractions.Fraction`'s formatting: treat +zero-padding (preceding the width field by a zero (``'0'``) character) as an +equivalent to a fill character of ``'0'`` with an alignment type of ``'='``, +just as in case of :class:`float`'s. + +.. + +.. date: 2025-03-09-03-13-41 +.. gh-issue: 130999 +.. nonce: tBRBVB +.. section: Library + +Avoid exiting the new REPL and offer suggestions even if there are +non-string candidates when errors occur. + +.. + +.. date: 2025-03-08-17-07-00 +.. gh-issue: 88473 +.. nonce: qg23g8 +.. section: Library + +Implement a fast path for :class:`datetime.date` objects in +:func:`datetime.date.today` which results in a 5x performance gain while +proper subclasses retain their previous performance. + +.. + +.. date: 2024-11-25-10-22-08 +.. gh-issue: 126883 +.. nonce: MAEF7g +.. section: Library + +Add check that timezone fields are in range for +:meth:`datetime.datetime.fromisoformat` and +:meth:`datetime.time.fromisoformat`. Patch by Semyon Moroz. + +.. + +.. date: 2024-10-28-06-54-22 +.. gh-issue: 125028 +.. nonce: GEY8Ws +.. section: Library + +:data:`functools.Placeholder` cannot be passed to :func:`functools.partial` +as a keyword argument. + +.. + +.. date: 2024-10-22-16-21-55 +.. gh-issue: 125843 +.. nonce: 2ttzYo +.. section: Library + +If possible, indicate which :mod:`curses` C function or macro is responsible +for raising a :exc:`curses.error` exception. Patch by Bénédikt Tran. + +.. + +.. date: 2024-10-17-01-12-22 +.. gh-issue: 119109 +.. nonce: u4hcvb +.. section: Library + +:func:`functools.partial` calls are now faster when keyword arguments are +used. + +.. + +.. date: 2024-09-13-09-48-25 +.. gh-issue: 124033 +.. nonce: WNudS0 +.. section: Library + +``SimplePath`` is now presented in ``importlib.metadata.__all__``. + +.. + +.. date: 2024-09-13-09-46-47 +.. gh-issue: 91216 +.. nonce: LuOsF4 +.. section: Library + +``importlib.metadata`` now raises a ``KeyError`` instead of returning +``None`` when a key is missing from the metadata. + +.. + +.. date: 2024-09-13-09-43-15 +.. gh-issue: 120492 +.. nonce: Mm6CJ6 +.. section: Library + +``importlib.metadata`` now prioritizes valid dists to invalid dists when +retrieving by name. + +.. + +.. date: 2024-07-16-00-01-04 +.. gh-issue: 99631 +.. nonce: GWD4fD +.. section: Library + +The :mod:`shelve` module now accepts custom serialization and +deserialization functions. + +.. + +.. date: 2024-07-06-14-32-30 +.. gh-issue: 119186 +.. nonce: E5B1HQ +.. section: Library + +Slightly speed up :func:`os.walk` by calling :func:`os.path.join` less +often. + +.. + +.. date: 2024-06-06-17-49-07 +.. gh-issue: 120170 +.. nonce: DUxhmT +.. section: Library + +Fix an issue in the :mod:`!_pickle` extension module in which importing +:mod:`multiprocessing` could change how pickle identifies which module an +object belongs to, potentially breaking the unpickling of those objects. + +.. + +.. date: 2024-05-13-09-50-31 +.. gh-issue: 118981 +.. nonce: zgOQPv +.. section: Library + +Fix potential hang in ``multiprocessing.popen_spawn_posix`` that can happen +when the child proc dies early by closing the child fds right away. + +.. + +.. date: 2023-07-05-14-34-10 +.. gh-issue: 105497 +.. nonce: HU5u89 +.. section: Library + +Fix flag mask inversion when unnamed flags exist. + +.. + +.. date: 2023-03-13-22-51-40 +.. gh-issue: 99813 +.. nonce: 40TV02 +.. section: Library + +:mod:`ssl` now uses ``SSL_sendfile`` internally when it is possible (see +:data:`~ssl.OP_ENABLE_KTLS`). The function sends a file more efficiently +because it performs TLS encryption in the kernel to avoid additional context +switches. Patch by Illia Volochii. + +.. + +.. date: 2023-02-13-21-56-38 +.. gh-issue: 62824 +.. nonce: CBZzX3 +.. section: Library + +Fix aliases for ``iso8859_8`` encoding. Patch by Dave Goncalves. + +.. + +.. date: 2023-02-13-21-41-34 +.. gh-issue: 86155 +.. nonce: ppIGSC +.. section: Library + +:meth:`html.parser.HTMLParser.close` no longer loses data when the +``<script>`` tag is not closed. Patch by Waylan Limberg. + +.. + +.. date: 2023-02-13-20-34-52 +.. gh-issue: 78319 +.. nonce: V1zzed +.. section: Library + +UTF8 support for the IMAP APPEND command has been made RFC compliant. + +.. + +.. date: 2022-10-08-14-56-07 +.. gh-issue: 93334 +.. nonce: 0KUm8d +.. section: Library + +Reraise :exc:`KeyError` as :exc:`ModuleNotFoundError` when +:meth:`importlib.machinery.PathFinder.find_spec` is called on a submodule +without importing the parent (and without a ``path`` argument). + +.. + +.. date: 2022-07-24-20-56-32 +.. gh-issue: 69426 +.. nonce: unccw7 +.. section: Library + +Fix :class:`html.parser.HTMLParser` to not unescape character entities in +attribute values if they are followed by an ASCII alphanumeric or an equals +sign. + +.. + +.. bpo: 38735 +.. date: 2022-01-07-16-56-57 +.. nonce: NFfJX6 +.. section: Library + +Fix failure when importing a module from the root directory on unix-like +platforms with sys.pycache_prefix set. + +.. + +.. bpo: 45959 +.. date: 2021-12-18-12-46-20 +.. nonce: vPlr3P +.. section: Library + +:mod:`pprint` can now pretty-print dict views. + +.. + +.. date: 2021-09-21-17-17-29 +.. gh-issue: 84683 +.. nonce: wDSRsG +.. section: Library + +:mod:`zoneinfo`: Check in ``<prefix>/share/zoneinfo`` for data files on +Windows + +.. + +.. bpo: 43429 +.. date: 2021-03-07-16-31-36 +.. nonce: Koa0mf +.. section: Library + +The :meth:`~mmap.mmap.size` method of the :class:`mmap.mmap` class now +returns the size of an anonymous mapping on both Unix and Windows. +Previously, the size would be returned on Windows and an :exc:`OSError` +would be raised on Unix. :exc:`ValueError` is now raised instead of +:exc:`OSError` when ``trackfd=False``. + +.. + +.. bpo: 41839 +.. date: 2020-09-23-11-54-17 +.. nonce: kU5Ywl +.. section: Library + +Allow negative priority values from :func:`os.sched_get_priority_min` and +:func:`os.sched_get_priority_max` functions. + +.. + +.. bpo: 28494 +.. date: 2017-12-30-18-21-00 +.. nonce: Dt_Wks +.. section: Library + +Improve Zip file validation false positive rate in +:func:`zipfile.is_zipfile`. + +.. + +.. date: 2025-10-09-12-53-47 +.. gh-issue: 96491 +.. nonce: 4YKxvy +.. section: IDLE + +Deduplicate version number in IDLE shell title bar after saving to a file. + +.. + +.. date: 2025-10-08-08-35-50 +.. gh-issue: 139742 +.. nonce: B3fZLg +.. section: IDLE + +Colorize t-string prefixes for template strings in IDLE, as done for +f-string prefixes. + +.. + +.. date: 2025-07-01-23-00-58 +.. gh-issue: 136155 +.. nonce: 4siQQO +.. section: Documentation + +We are now checking for fatal errors in EPUB builds in CI. + +.. + +.. date: 2025-06-10-17-02-06 +.. gh-issue: 135171 +.. nonce: quHvts +.. section: Documentation + +Document that the :term:`iterator` for the leftmost :keyword:`!for` clause +in the generator expression is created immediately. + +.. + +.. bpo: 45210 +.. date: 2021-09-15-13-07-25 +.. nonce: RtGk7i +.. section: Documentation + +Document that error indicator may be set in tp_dealloc, and how to avoid +clobbering it. + +.. + +.. date: 2025-10-13-17-56-23 +.. gh-issue: 140000 +.. nonce: tLhn3e +.. section: Core and Builtins + +Fix potential memory leak when a reference cycle exists between an instance +of :class:`typing.TypeAliasType`, :class:`typing.TypeVar`, +:class:`typing.ParamSpec`, or :class:`typing.TypeVarTuple` and its +``__name__`` attribute. Patch by Mikhail Efimov. + +.. + +.. date: 2025-10-12-18-54-06 +.. gh-issue: 140009 +.. nonce: -MbFh_ +.. section: Core and Builtins + +Improve performance of list extension by dictionary items. + +.. + +.. date: 2025-10-12-11-00-06 +.. gh-issue: 139988 +.. nonce: 4wi51t +.. section: Core and Builtins + +Fix a memory leak when failing to create a :class:`~typing.Union` type. +Patch by Bénédikt Tran. + +.. + +.. date: 2025-10-08-13-52-00 +.. gh-issue: 139748 +.. nonce: jq0yFJ +.. section: Core and Builtins + +Fix reference leaks in error branches of functions accepting path strings or +bytes such as :func:`compile` and :func:`os.system`. Patch by Bénédikt Tran. + +.. + +.. date: 2025-10-06-13-15-26 +.. gh-issue: 139516 +.. nonce: d9Pkur +.. section: Core and Builtins + +Fix lambda colon erroneously start format spec in f-string in tokenizer. + +.. + +.. date: 2025-10-01-18-21-19 +.. gh-issue: 63161 +.. nonce: ef1S6N +.. section: Core and Builtins + +Support non-UTF-8 shebang and comments in Python source files if non-UTF-8 +encoding is specified. Detect decoding error in comments for default (UTF-8) +encoding. Show the line and position of decoding error for default encoding +in a traceback. Show the line containing the coding cookie when it conflicts +with the BOM in a traceback. + +.. + +.. date: 2025-09-30-14-57-19 +.. gh-issue: 139116 +.. nonce: nlVf40 +.. section: Core and Builtins + +Prevent a deadlock when multiple threads start, stop and use +:mod:`tracemalloc` simultaneously. + +.. + +.. date: 2025-09-24-17-32-52 +.. gh-issue: 139275 +.. nonce: novrqf +.. section: Core and Builtins + +Fix compilation problems in ``_remote_debugging_module.c`` when the system +doesn't have ``process_vm_readv``. Patch by Pablo Galindo + +.. + +.. date: 2025-09-24-17-08-42 +.. gh-issue: 133059 +.. nonce: EXvxb7 +.. section: Core and Builtins + +Increased the number of cached small positive integers from 256 to 1024. + +.. + +.. date: 2025-09-22-15-21-49 +.. gh-issue: 74857 +.. nonce: 5XRQaA +.. section: Core and Builtins + +:pep:`538`: Coerce the POSIX locale to a UTF-8 based locale. Patch by Victor +Stinner. + +.. + +.. date: 2025-09-21-14-33-17 +.. gh-issue: 116738 +.. nonce: vNaI4h +.. section: Library + +Make :mod:`mmap` thread-safe on the :term:`free threaded <free threading>` +build. + +.. + +.. date: 2025-09-17-17-17-21 +.. gh-issue: 138558 +.. nonce: 0VbzCH +.. section: Core and Builtins + +Fix handling of unusual t-string annotations in annotationlib. Patch by Dave +Peck. + +.. + +.. date: 2025-09-15-14-04-56 +.. gh-issue: 134466 +.. nonce: yR4fYW +.. section: Core and Builtins + +Don't run PyREPL in a degraded environment where setting termios attributes +is not allowed. + +.. + +.. date: 2025-09-11-15-56-18 +.. gh-issue: 138794 +.. nonce: nrOn1K +.. section: Core and Builtins + +When a new tracing function is registered with +:c:func:`PyRefTracer_SetTracer`, replacing the current a call to the trace +function will be made with the object set to **NULL** and **event** set to +:c:data:`PyRefTracer_TRACKER_REMOVED`. This will happen just before the new +function is registered. Patch by Pablo Galindo + +.. + +.. date: 2025-09-10-14-53-59 +.. gh-issue: 71810 +.. nonce: ppf0J- +.. section: Core and Builtins + +Raise :exc:`OverflowError` for ``(-1).to_bytes()`` for signed conversions +when bytes count is zero. Patch by Sergey B Kirpichev. + +.. + +.. date: 2025-09-09-23-59-13 +.. gh-issue: 138716 +.. nonce: UawDY0 +.. section: Core and Builtins + +Improve :exc:`SyntaxError` message for :keyword:`assert` in cases like +``assert a := b``. + +.. + +.. date: 2025-09-06-13-53-33 +.. gh-issue: 105487 +.. nonce: a43YaY +.. section: Core and Builtins + +Remove non-existent :meth:`~object.__copy__`, :meth:`~object.__deepcopy__`, +and :attr:`~type.__bases__` from the :meth:`~object.__dir__` entries of +:class:`types.GenericAlias`. + +.. + +.. date: 2025-09-05-01-19-04 +.. gh-issue: 138192 +.. nonce: erluq5 +.. section: Core and Builtins + +Fix :mod:`contextvars` initialization so that all subinterpreters are +assigned the :attr:`~contextvars.Token.MISSING` value. + +.. + +.. date: 2025-09-03-17-00-30 +.. gh-issue: 138479 +.. nonce: qUxgWs +.. section: Core and Builtins + +Fix a crash when a generic object's ``__typing_subst__`` returns an object +that isn't a :class:`tuple`. + +.. + +.. date: 2025-09-03-15-35-34 +.. gh-issue: 138431 +.. nonce: EUsrtA +.. section: Core and Builtins + +Fix a bug in the JIT optimizer when round-tripping strings and tuples. + +.. + +.. date: 2025-09-03-10-16-09 +.. gh-issue: 138378 +.. nonce: r6BQxV +.. section: Core and Builtins + +Move the globals-to-const JIT optimizer pass into to the main JIT optimizer +pass + +.. + +.. date: 2025-09-02-22-17-55 +.. gh-issue: 138401 +.. nonce: uTRvue +.. section: Library + +Add missing validation of argument ``count`` in :func:`os.sendfile` to be +non-negative. + +.. + +.. date: 2025-09-02-09-10-06 +.. gh-issue: 138372 +.. nonce: h1Xk4- +.. section: Core and Builtins + +Fix :exc:`SyntaxWarning` emitted for erroneous subscript expressions +involving :ref:`template string literals <t-strings>`. Patch by Brian +Schubert. + +.. + +.. date: 2025-09-01-21-52-54 +.. gh-issue: 138302 +.. nonce: -ez47B +.. section: Core and Builtins + +``BINARY_OP`` now specializes to ``BINARY_OP_ADD_INT``, +``BINARY_OP_SUBTRACT_INT`` or ``BINARY_OP_MULTIPLY_INT`` if operands are +compact ints. + +.. + +.. date: 2025-09-01-16-09-02 +.. gh-issue: 138318 +.. nonce: t-WEN5 +.. section: Core and Builtins + +The default REPL now avoids highlighting built-in names (for instance +:class:`set` or :func:`format`) when they are used as attribute names (for +instance in ``value.set`` or ``text.format``). + +.. + +.. date: 2025-09-01-13-54-43 +.. gh-issue: 138349 +.. nonce: 0fGmAi +.. section: Core and Builtins + +Fix crash in certain cases where a module contains both a module-level +annotation and a comprehension. + +.. + +.. date: 2025-08-30-17-15-05 +.. gh-issue: 69605 +.. nonce: KjBk99 +.. section: Core and Builtins + +Fix some standard library submodules missing from the :term:`REPL` +auto-completion of imports. + +.. + +.. date: 2025-08-30-00-55-35 +.. gh-issue: 61206 +.. nonce: HeFLvl +.. section: Core and Builtins + +:mod:`zipimport` now supports zstandard compressed zip file entries. + +.. + +.. date: 2025-08-28-09-29-46 +.. gh-issue: 116738 +.. nonce: yLZJpV +.. section: Library + +Make :mod:`!cProfile` thread-safe on the :term:`free threaded <free +threading>` build. + +.. + +.. date: 2025-08-27-17-51-38 +.. gh-issue: 137838 +.. nonce: lK6T0j +.. section: Core and Builtins + +Fix JIT trace buffer overrun by increasing possible exit stubs. Patch by +Donghee Na. + +.. + +.. date: 2025-08-27-13-11-47 +.. gh-issue: 71679 +.. nonce: V0yFeT +.. section: Core and Builtins + +Use the same quoting algorithm for the repr of bytearrays as for bytes +objects and strings -- use double quotes for quoting if the bytearray +contains single quotes and does not contain double quotes. + +.. + +.. date: 2025-08-22-11-39-40 +.. gh-issue: 137384 +.. nonce: j4b_in +.. section: Core and Builtins + +Fix a crash when using the :mod:`warnings` module in a finalizer at +shutdown. Patch by Kumar Aditya. + +.. + +.. date: 2025-08-21-06-31-42 +.. gh-issue: 138004 +.. nonce: FH2Hre +.. section: Library + +On Solaris/Illumos platforms, thread names are now encoded as ASCII to avoid +errors on systems (e.g. OpenIndiana) that don't support non-ASCII names. + +.. + +.. date: 2025-08-21-01-46-39 +.. gh-issue: 137976 +.. nonce: p4sb4x +.. section: Library + +Removed ``localtime`` from the list of reported system timezones. + +.. + +.. date: 2025-08-20-14-17-47 +.. gh-issue: 137992 +.. nonce: fcL3SK +.. section: Core and Builtins + +Ensure that :c:func:`PyRefTracer_SetTracer` sync with all existing threads +when called to avoid races in the free threaded build. Patch by Pablo +Galindo + +.. + +.. date: 2025-08-19-18-52-22 +.. gh-issue: 137967 +.. nonce: uw67Ys +.. section: Core and Builtins + +Show error suggestions on nested attribute access. Patch by Pablo Galindo + +.. + +.. date: 2025-08-19-16-07-07 +.. gh-issue: 137959 +.. nonce: EWj0RZ +.. section: Core and Builtins + +Replace the shim code added to every piece of jitted code with a single +trampoline function. + +.. + +.. date: 2025-08-17-13-36-53 +.. gh-issue: 137883 +.. nonce: 55VDCN +.. section: Core and Builtins + +Fix runaway recursion when calling a function with keyword arguments. + +.. + +.. date: 2025-08-15-15-45-26 +.. gh-issue: 137079 +.. nonce: YEow69 +.. section: Core and Builtins + +Fix keyword typo recognition when parsing files. Patch by Pablo Galindo. + +.. + +.. date: 2025-08-14-14-18-29 +.. gh-issue: 137728 +.. nonce: HdYS9R +.. section: Core and Builtins + +Fix the JIT's handling of many local variables. This previously caused a +segfault. + +.. + +.. date: 2025-08-13-16-58-58 +.. gh-issue: 137716 +.. nonce: ZcZSyi +.. section: Core and Builtins + +Fix double period in :exc:`AttributeError` message for invalid mock +assertions + +.. + +.. date: 2025-08-13-13-39-02 +.. gh-issue: 137433 +.. nonce: g6Atfz +.. section: Core and Builtins + +Fix a potential deadlock in the :term:`free threading` build when daemon +threads enable or disable profiling or tracing while the main thread is +shutting down the interpreter. + +.. + +.. date: 2025-08-10-21-34-12 +.. gh-issue: 137576 +.. nonce: 0ZicS- +.. section: Core and Builtins + +Fix for incorrect source code being shown in tracebacks from the Basic REPL +when :envvar:`PYTHONSTARTUP` is given. Patch by Adam Hartz. + +.. + +.. date: 2025-08-09-11-38-37 +.. gh-issue: 37817 +.. nonce: Y5Fhde +.. section: Core and Builtins + +Allow assignment to :attr:`~type.__bases__` of direct subclasses of builtin +classes. + +.. + +.. date: 2025-08-09-04-07-05 +.. gh-issue: 132732 +.. nonce: 8BiIVJ +.. section: Core and Builtins + +Optimize ``_COMPARE_OP``, ``_CONTAINS_OP``, ``_UNARY_NEGATIVE``, +``_UNARY_NOT``, and ``_UNARY_INVERT`` in JIT builds with constant-loading +uops (``_POP_TWO_LOAD_CONST_INLINE_BORROW`` and +``_POP_TOP_LOAD_CONST_INLINE_BORROW``), and then remove both to reduce +instruction count. + +.. + +.. date: 2025-08-07-09-52-19 +.. gh-issue: 137400 +.. nonce: AK1dy- +.. section: Core and Builtins + +Fix a crash in the :term:`free threading` build when disabling profiling or +tracing across all threads with :c:func:`PyEval_SetProfileAllThreads` or +:c:func:`PyEval_SetTraceAllThreads` or their Python equivalents +:func:`threading.settrace_all_threads` and +:func:`threading.setprofile_all_threads`. + +.. + +.. date: 2025-08-06-16-55-44 +.. gh-issue: 133143 +.. nonce: l7CI9v +.. section: Core and Builtins + +Add :data:`sys.abi_info` object to make ABI information more easily +accessible. + +.. + +.. date: 2025-08-06-15-39-54 +.. gh-issue: 137400 +.. nonce: xIw0zs +.. section: Core and Builtins + +Fix a crash in the :term:`free threading` build when disabling profiling or +tracing across all threads with :c:func:`PyEval_SetProfileAllThreads` or +:c:func:`PyEval_SetTraceAllThreads` or their Python equivalents +:func:`threading.settrace_all_threads` and +:func:`threading.setprofile_all_threads`. + +.. + +.. date: 2025-08-05-20-24-12 +.. gh-issue: 120037 +.. nonce: MB7MmI +.. section: Core and Builtins + +Disable user site packages directory when a ``._pth`` file is used, even if +it contains ``import site``. + +.. + +.. date: 2025-08-05-17-22-24 +.. gh-issue: 58124 +.. nonce: q1__53 +.. section: Core and Builtins + +Fix name of the Python encoding in Unicode errors of the code page codec: +use "cp65000" and "cp65001" instead of "CP_UTF7" and "CP_UTF8" which are not +valid Python code names. Patch by Victor Stinner. + +.. + +.. date: 2025-08-05-10-22-15 +.. gh-issue: 136966 +.. nonce: J5lrE0 +.. section: Core and Builtins + +The :attr:`object.__dict__` and :attr:`!__weakref__` descriptors now use a +single descriptor instance per interpreter, shared across all types that +need them. This speeds up class creation, and helps avoid reference cycles. + +.. + +.. date: 2025-08-02-23-04-57 +.. gh-issue: 137314 +.. nonce: wjEdzD +.. section: Core and Builtins + +Fixed a regression where raw f-strings incorrectly interpreted escape +sequences in format specifications. Raw f-strings now properly preserve +literal backslashes in format specs, matching the behavior from Python 3.11. +For example, ``rf"{obj:\xFF}"`` now correctly produces ``'\\xFF'`` instead +of ``'ÿ'``. Patch by Pablo Galindo. + +.. + +.. date: 2025-08-02-10-27-53 +.. gh-issue: 137308 +.. nonce: at05p_ +.. section: Core and Builtins + +A standalone docstring in a node body is optimized as a :keyword:`pass` +statement to ensure that the node's body is never empty. There was a +:exc:`ValueError` in :func:`compile` otherwise. + +.. + +.. date: 2025-08-01-18-54-31 +.. gh-issue: 137288 +.. nonce: FhE7ku +.. section: Core and Builtins + +Fix bug where some bytecode instructions of a boolean expression are not +associated with the correct exception handler. + +.. + +.. date: 2025-07-31-23-02-02 +.. gh-issue: 137291 +.. nonce: kIxVZd +.. section: Core and Builtins + +The perf profiler can now be used if a previous frame evaluation API has +been provided. + +.. + +.. date: 2025-07-28-19-11-34 +.. gh-issue: 134291 +.. nonce: IiB9Id +.. section: Core and Builtins + +Remove some newer macOS API usage from the JIT compiler in order to restore +compatibility with older OSX 10.15 deployment targets. + +.. + +.. date: 2025-07-28-17-01-05 +.. gh-issue: 88886 +.. nonce: g4XFPb +.. section: Core and Builtins + +The codecs lookup function now again performs only minimal normalization of +the encoding name before passing it to the search functions: all ASCII +letters are converted to lower case, spaces are replaced with hyphens. This +restores the pre-Python 3.9 behavior. + +.. + +.. date: 2025-07-25-22-31-52 +.. gh-issue: 131338 +.. nonce: zJDCMp +.. section: Core and Builtins + +Disable computed stack limit checks on non-glibc linux platforms to fix +crashes on deep recursion. + +.. + +.. date: 2025-07-24-17-30-58 +.. gh-issue: 136870 +.. nonce: ncx82J +.. section: Core and Builtins + +Fix data races while de-instrumenting bytecode of code objects running +concurrently in threads. + +.. + +.. date: 2025-07-24-02-13-59 +.. gh-issue: 132732 +.. nonce: p77xkb +.. section: Core and Builtins + +Optimize constant comparison for ``_COMPARE_OP_INT``, ``_COMPARE_OP_FLOAT`` +and ``_COMPARE_OP_STR`` in JIT builds + +.. + +.. date: 2025-07-19-17-08-09 +.. gh-issue: 127598 +.. nonce: Mx8S-y +.. section: Core and Builtins + +Improve :exc:`ModuleNotFoundError` by adding flavour text to the exception +when the :option:`-S` option is passed. Patch by Andrea Mattei. + +.. + +.. date: 2025-07-19-12-37-05 +.. gh-issue: 136801 +.. nonce: XU_tF2 +.. section: Core and Builtins + +Fix PyREPL syntax highlighting on match cases after multi-line case. +Contributed by Olga Matoula. + +.. + +.. date: 2025-07-19-10-35-31 +.. gh-issue: 74185 +.. nonce: 7hPCA5 +.. section: Core and Builtins + +The :meth:`~object.__repr__` of :class:`ImportError` and +:class:`ModuleNotFoundError` now shows "name" and "path" as ``name=<name>`` +and ``path=<path>`` if they were given as keyword arguments at construction +time. Patch by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir + +.. + +.. date: 2025-07-18-08-43-35 +.. gh-issue: 116738 +.. nonce: i0HWtP +.. section: Library + +Make functions in :mod:`syslog` thread-safe on the :term:`free threaded +<free threading>` build. + +.. + +.. date: 2025-07-15-10-03-57 +.. gh-issue: 116738 +.. nonce: oFttKl +.. section: Library + +Make functions in :mod:`pwd` thread-safe on the :term:`free threaded <free +threading>` build. + +.. + +.. date: 2025-07-14-17-01-23 +.. gh-issue: 136616 +.. nonce: FQjXE_ +.. section: Core and Builtins + +Improve :exc:`SyntaxError` error messages for invalid :keyword:`assert` +usages. + +.. + +.. date: 2025-07-13-21-21-17 +.. gh-issue: 136599 +.. nonce: sLhm2O +.. section: Core and Builtins + +Improve performance of :class:`int` hash calculations. + +.. + +.. date: 2025-07-12-09-59-14 +.. gh-issue: 136421 +.. nonce: ZD1rNj +.. section: Library + +Fix crash when initializing :mod:`datetime` concurrently. + +.. + +.. date: 2025-07-11-13-45-48 +.. gh-issue: 136541 +.. nonce: uZ_-Ju +.. section: Core and Builtins + +Fix some issues with the perf trampolines on x86-64 and aarch64. The +trampolines were not being generated correctly for some cases, which could +lead to the perf integration not working correctly. Patch by Pablo Galindo. + +.. + +.. date: 2025-07-11-12-29-09 +.. gh-issue: 107545 +.. nonce: ipfl7U +.. section: Library + +Improve the error messages that may be raised by +:meth:`~socket.socket.setsockopt`. + +.. + +.. date: 2025-07-10-23-23-50 +.. gh-issue: 136517 +.. nonce: _NHJyv +.. section: Core and Builtins + +Fixed a typo that prevented printing of uncollectable objects when the +:const:`gc.DEBUG_UNCOLLECTABLE` mode was set. + +.. + +.. date: 2025-07-10-15-53-16 +.. gh-issue: 136525 +.. nonce: xAko0e +.. section: Core and Builtins + +Fix issue where per-thread bytecode was not instrumented for newly created +threads. + +.. + +.. date: 2025-07-09-21-27-14 +.. gh-issue: 132657 +.. nonce: kSA8R3 +.. section: Core and Builtins + +Improve performance of :class:`frozenset` by removing locks in the +free-threading build. + +.. + +.. date: 2025-07-09-11-15-42 +.. gh-issue: 136459 +.. nonce: m4Udh8 +.. section: Core and Builtins + +Add support for perf trampoline on macOS, to allow profilers wit JIT map +support to read Python calls. While profiling, ``PYTHONPERFSUPPORT=1`` can +be appended to enable the trampoline. + +.. + +.. date: 2025-07-08-23-53-51 +.. gh-issue: 132661 +.. nonce: B84iYt +.. section: Core and Builtins + +``Interpolation.expression`` now has a default, the empty string. + +.. + +.. date: 2025-07-08-23-22-08 +.. gh-issue: 132661 +.. nonce: 34ftJl +.. section: Core and Builtins + +Reflect recent :pep:`750` change. + +Disallow concatenation of ``string.templatelib.Template`` and :class:`str`. +Also, disallow implicit concatenation of t-string literals with string or +f-string literals. + +.. + +.. date: 2025-07-07-17-26-06 +.. gh-issue: 91636 +.. nonce: GyHU72 +.. section: Core and Builtins + +While performing garbage collection, clear weakrefs to unreachable objects +that are created during running of finalizers. If those weakrefs were are +not cleared, they could reveal unreachable objects. + +.. + +.. date: 2025-07-07-12-24-00 +.. gh-issue: 136355 +.. nonce: MTcA8j +.. section: Core and Builtins + +Deprecate :option:`-b` and :option:`!-bb` command line options and schedule +them to become no-op in Python 3.17. + +.. + +.. date: 2025-07-06-14-53-19 +.. gh-issue: 109700 +.. nonce: KVNQQi +.. section: Core and Builtins + +Fix memory error handling in :c:func:`PyDict_SetDefault`. + +.. + +.. date: 2025-07-03-06-04-42 +.. gh-issue: 135552 +.. nonce: CbBQof +.. section: Core and Builtins + +Fix a bug caused by the garbage collector clearing weakrefs too early. The +weakrefs in the ``tp_subclasses`` dictionary are needed in order to +correctly invalidate type caches (for example, by calling +``PyType_Modified()``). Clearing weakrefs before calling finalizers causes +the caches to not be correctly invalidated. That can cause crashes since +the caches can refer to invalid objects. Defer the clearing of weakrefs +without callbacks until after finalizers are executed. + +.. + +.. date: 2025-07-02-15-18-41 +.. gh-issue: 136203 +.. nonce: Y934sC +.. section: Core and Builtins + +Improve :exc:`TypeError` error message, when richcomparing two +:class:`types.MappingProxyType` objects. + +.. + +.. date: 2025-06-26-18-44-34 +.. gh-issue: 136003 +.. nonce: sln51d +.. section: Core and Builtins + +Fix :class:`threading.Thread` objects becoming incorrectly daemon when +created from an :mod:`atexit` callback or a pending call +(:c:func:`Py_AddPendingCall`). + +.. + +.. date: 2025-06-26-15-25-51 +.. gh-issue: 78465 +.. nonce: MbDN8X +.. section: Core and Builtins + +Fix error message for ``cls.__new__(cls, ...)`` where ``cls`` is not +instantiable builtin or extension type (with ``tp_new`` set to ``NULL``). + +.. + +.. date: 2025-06-24-16-46-34 +.. gh-issue: 135904 +.. nonce: 78xfon +.. section: Core and Builtins + +Perform more aggressive control-flow optimizations on the machine code +templates emitted by the experimental JIT compiler. + +.. + +.. date: 2025-06-24-06-41-47 +.. gh-issue: 129958 +.. nonce: EaJuS0 +.. section: Core and Builtins + +Differentiate between t-strings and f-strings in syntax error for newlines +in format specifiers of single-quoted interpolated strings. + +.. + +.. date: 2025-06-23-18-08-32 +.. gh-issue: 135871 +.. nonce: 50C528 +.. section: Core and Builtins + +Non-blocking mutex lock attempts now return immediately when the lock is +busy instead of briefly spinning in the :term:`free threading` build. + +.. + +.. date: 2025-06-20-14-50-44 +.. gh-issue: 134584 +.. nonce: 3CJdAI +.. section: Core and Builtins + +Specialize :opcode:`POP_TOP` in the JIT compiler by specializing for +reference lifetime and type. This will also enable easier top of stack +caching in the JIT compiler. + +.. + +.. date: 2025-06-18-16-45-36 +.. gh-issue: 135106 +.. nonce: cpl6Aq +.. section: Core and Builtins + +Restrict the trashcan mechanism to GC'ed objects and untrack them while in +the trashcan to prevent the GC and trashcan mechanisms conflicting. + +.. + +.. date: 2025-06-18-12-19-13 +.. gh-issue: 135379 +.. nonce: TCvGpj +.. section: Core and Builtins + +Changes specialization of ``BINARY_OP`` for ints to only specialize for +"compact" ints. This streamlines the fast path at the cost of fewer +specializations when very large integers are used. + +.. + +.. date: 2025-06-17-22-34-58 +.. gh-issue: 135607 +.. nonce: ucsLVu +.. section: Core and Builtins + +Fix potential :mod:`weakref` races in an object's destructor on the +:term:`free threaded <free threading>` build. + +.. + +.. date: 2025-06-17-12-50-48 +.. gh-issue: 135608 +.. nonce: PnHckD +.. section: Core and Builtins + +Fix a crash in the JIT involving attributes of modules. + +.. + +.. date: 2025-06-17-08-37-45 +.. gh-issue: 82088 +.. nonce: TgPvLg +.. section: Core and Builtins + +Improve performance of ``PyLongObject`` conversion functions +``PyLong_AsLongAndOverflow()``, ``PyLong_AsSsize_t()``, +``PyLong_AsUnsignedLong()``, ``PyLong_AsSize_t()``, +``PyLong_AsUnsignedLongMask()``, ``PyLong_AsUnsignedLongLongMask()``, +``PyLong_AsLongLongAndOverflow()`` for integers larger than 2**30 up to 30%. + +.. + +.. date: 2025-06-16-03-56-15 +.. gh-issue: 135551 +.. nonce: hRTQO- +.. section: Core and Builtins + +Sorting randomly ordered lists will often run a bit faster, thanks to a new +scheme for picking minimum run lengths from Stefan Pochmann, which arranges +for the merge tree to be as evenly balanced as is possible. + +.. + +.. date: 2025-06-16-02-31-42 +.. gh-issue: 135543 +.. nonce: 6b0HOF +.. section: Core and Builtins + +Emit ``sys.remote_exec`` audit event when :func:`sys.remote_exec` is called +and migrate ``remote_debugger_script`` to +``cpython.remote_debugger_script``. + +.. + +.. date: 2025-06-14-01-01-14 +.. gh-issue: 135496 +.. nonce: ER0Me3 +.. section: Core and Builtins + +Fix typo in the f-string conversion type error ("exclamanation" -> +"exclamation"). + +.. + +.. date: 2025-06-13-16-05-24 +.. gh-issue: 135474 +.. nonce: 67nOl3 +.. section: Core and Builtins + +Specialize integer operations only on compact integers. This is a CPython +internal change. + +.. + +.. date: 2025-06-12-18-12-42 +.. gh-issue: 135371 +.. nonce: R_YUtR +.. section: Core and Builtins + +Fixed :mod:`asyncio` debugging tools to properly display internal coroutine +call stacks alongside external task dependencies. The ``python -m asyncio +ps`` and ``python -m asyncio pstree`` commands now show complete execution +context. Patch by Pablo Galindo. + +.. + +.. date: 2025-06-12-11-19-52 +.. gh-issue: 135422 +.. nonce: F6yQi6 +.. section: Core and Builtins + +Fix regression in :exc:`SyntaxError` messages after :gh:`134036`. + +.. + +.. date: 2025-06-12-00-03-34 +.. gh-issue: 116738 +.. nonce: iBBAdo +.. section: Library + +Make functions in :mod:`grp` thread-safe on the :term:`free threaded <free +threading>` build. + +.. + +.. date: 2025-06-11-15-08-10 +.. gh-issue: 127319 +.. nonce: OVGFSZ +.. section: Library + +Set the ``allow_reuse_port`` class variable to ``False`` on the XMLRPC, +logging, and HTTP servers. This matches the behavior in prior Python +releases, which is to not allow port reuse. + +.. + +.. date: 2025-06-09-23-57-37 +.. gh-issue: 130077 +.. nonce: MHknDB +.. section: Core and Builtins + +Properly raise custom syntax errors when incorrect syntax containing names +that are prefixes of soft keywords is encountered. Patch by Pablo Galindo. + +.. + +.. date: 2025-06-08-14-24-29 +.. gh-issue: 131798 +.. nonce: qfw91T +.. section: Core and Builtins + +Optimize _CALL_LEN in the JIT when the length is known. Patch by Tomas Roun + +.. + +.. date: 2025-06-06-19-17-22 +.. gh-issue: 131798 +.. nonce: XoV8Eb +.. section: Core and Builtins + +Optimize ``_UNARY_NEGATIVE`` in JIT-compiled code. + +.. + +.. date: 2025-06-06-02-24-42 +.. gh-issue: 135148 +.. nonce: r-t2sC +.. section: Core and Builtins + +Fixed a bug where f-string debug expressions (using =) would incorrectly +strip out parts of strings containing escaped quotes and # characters. Patch +by Pablo Galindo. + +.. + +.. date: 2025-06-06-01-09-44 +.. gh-issue: 131798 +.. nonce: 1SuxO9 +.. section: Core and Builtins + +Optimize ``_UNARY_INVERT`` in JIT-compiled code. + +.. + +.. date: 2025-06-05-21-58-30 +.. gh-issue: 131798 +.. nonce: nt5Ab7 +.. section: Core and Builtins + +Optimize away ``_CALL_TYPE_1`` in the JIT when the return type is known. +Patch by Tomas Roun + +.. + +.. date: 2025-06-03-21-06-22 +.. gh-issue: 133136 +.. nonce: Usnvri +.. section: Core and Builtins + +Limit excess memory usage in the :term:`free threading` build when a large +dictionary or list is resized and accessed by multiple threads. + +.. + +.. date: 2025-06-02-20-13-37 +.. gh-issue: 131798 +.. nonce: JQRFvR +.. section: Core and Builtins + +Optimize ``_CHECK_METHOD_VERSION`` into ``_CHECK_FUNCTION_VERSION_INLINE`` +in JIT-compiled code. + +.. + +.. date: 2025-06-02-13-57-40 +.. gh-issue: 116738 +.. nonce: ycJsL8 +.. section: Library + +Make methods in :mod:`heapq` thread-safe on the :term:`free threaded <free +threading>` build. + +.. + +.. date: 2025-05-31-19-24-54 +.. gh-issue: 134280 +.. nonce: NDVbzY +.. section: Core and Builtins + +Disable constant folding for ``~`` with a boolean argument. This moves the +deprecation warning from compile time to runtime. + +.. + +.. date: 2025-05-31-10-26-46 +.. gh-issue: 134876 +.. nonce: 8mBGJI +.. section: Core and Builtins + +Add support to :pep:`768` remote debugging for Linux kernels which don't +have CONFIG_CROSS_MEMORY_ATTACH configured. + +.. + +.. date: 2025-05-30-18-09-54 +.. gh-issue: 134889 +.. nonce: Ic9UM- +.. section: Core and Builtins + +Fix handling of a few opcodes that leave operands on the stack when +optimizing ``LOAD_FAST``. + +.. + +.. date: 2025-05-30-15-56-19 +.. gh-issue: 134908 +.. nonce: 3a7PxM +.. section: Library + +Fix crash when iterating over lines in a text file on the :term:`free +threaded <free threading>` build. + +.. + +.. date: 2025-05-28-23-58-50 +.. gh-issue: 117852 +.. nonce: BO9g7z +.. section: Core and Builtins + +Fix argument checking of :meth:`~agen.athrow`. + +.. + +.. date: 2025-05-27-20-29-00 +.. gh-issue: 132617 +.. nonce: EmUfQQ +.. section: Core and Builtins + +Fix :meth:`dict.update` modification check that could incorrectly raise a +"dict mutated during update" error when a different dictionary was modified +that happens to share the same underlying keys object. + +.. + +.. date: 2025-05-27-20-21-34 +.. gh-issue: 131798 +.. nonce: b32zkl +.. section: Core and Builtins + +Allow the JIT to remove unnecessary ``_ITER_CHECK_TUPLE`` ops. + +.. + +.. date: 2025-05-27-18-59-54 +.. gh-issue: 134679 +.. nonce: FWPBu6 +.. section: Core and Builtins + +Fix crash in the :term:`free threading` build's QSBR code that could occur +when changing an object's ``__dict__`` attribute. + +.. + +.. date: 2025-05-26-15-55-50 +.. gh-issue: 133912 +.. nonce: -xAguL +.. section: Core and Builtins + +Fix the C API function ``PyObject_GenericSetDict`` to handle extension +classes with inline values. + +.. + +.. date: 2025-05-25-19-32-15 +.. gh-issue: 131798 +.. nonce: f5h8aI +.. section: Core and Builtins + +Make the JIT optimizer understand that slicing a string/list/tuple returns +the same type. + +.. + +.. date: 2025-05-23-14-54-07 +.. gh-issue: 134584 +.. nonce: y-WDjf +.. section: Core and Builtins + +Add a reference count elimination pass to the JIT compiler. Patch by Ken +Jin. + +.. + +.. date: 2025-05-22-17-49-39 +.. gh-issue: 131798 +.. nonce: U6ZmFm +.. section: Core and Builtins + +Optimize ``_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW``. + +.. + +.. date: 2025-05-22-14-48-19 +.. gh-issue: 134381 +.. nonce: 2BXhth +.. section: Library + +Fix :exc:`RuntimeError` when using a not-started :class:`threading.Thread` +after calling :func:`os.fork` + +.. + +.. date: 2025-05-21-18-02-56 +.. gh-issue: 127960 +.. nonce: W3J_2X +.. section: Core and Builtins + +PyREPL interactive shell no longer starts with ``__package__`` and +``__file__`` global names set to ``_pyrepl`` package internals. Contributed +by Yuichiro Tachibana. + +.. + +.. date: 2025-05-21-15-14-32 +.. gh-issue: 130397 +.. nonce: aG6EON +.. section: Core and Builtins + +Remove special-casing for C stack depth limits for WASI. Due to +WebAssembly's built-in stack protection this does not pose a security +concern. + +.. + +.. date: 2025-05-21-13-57-26 +.. gh-issue: 131798 +.. nonce: QwS5Bb +.. section: Core and Builtins + +JIT: replace ``_LOAD_SMALL_INT`` with ``_LOAD_CONST_INLINE_BORROW`` + +.. + +.. date: 2025-05-20-23-32-11 +.. gh-issue: 131798 +.. nonce: G9ZQZw +.. section: Core and Builtins + +Improve the JIT's ability to optimize away cached class attribute and method +loads. + +.. + +.. date: 2025-05-20-14-41-50 +.. gh-issue: 128066 +.. nonce: qzzGfv +.. section: Core and Builtins + +Fixes an edge case where PyREPL improperly threw an error when Python is +invoked on a read only filesystem while trying to write history file +entries. + +.. + +.. date: 2025-05-20-13-58-18 +.. gh-issue: 131798 +.. nonce: hG8xBw +.. section: Core and Builtins + +Improve the JIT's ability to narrow unknown classes to constant values. + +.. + +.. date: 2025-05-19-20-52-53 +.. gh-issue: 134268 +.. nonce: HPKX1e +.. section: Core and Builtins + +Add ``_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW`` and use it to further +optimize ``CALL_ISINSTANCE``. + +.. + +.. date: 2025-05-19-15-15-58 +.. gh-issue: 131798 +.. nonce: PCP71j +.. section: Core and Builtins + +Split ``CALL_LIST_APPEND`` into several uops. Patch by Diego Russo. + +.. + +.. date: 2025-05-18-14-33-23 +.. gh-issue: 69605 +.. nonce: ZMO49F +.. section: Core and Builtins + +When auto-completing an import in the :term:`REPL`, finding no candidates +now issues no suggestion, rather than suggestions from the current +namespace. + +.. + +.. date: 2025-05-18-10-50-46 +.. gh-issue: 134170 +.. nonce: J0Hvmi +.. section: Core and Builtins + +Add colorization to :func:`sys.unraisablehook` by default. + +.. + +.. date: 2025-05-17-20-56-05 +.. gh-issue: 91153 +.. nonce: afgtG2 +.. section: Core and Builtins + +Fix a crash when a :class:`bytearray` is concurrently mutated during item +assignment. + +.. + +.. date: 2025-05-17-20-44-51 +.. gh-issue: 134158 +.. nonce: ewLNLp +.. section: Core and Builtins + +Fix coloring of double braces in f-strings and t-strings in the +:term:`REPL`. + +.. + +.. date: 2025-05-16-20-59-12 +.. gh-issue: 134119 +.. nonce: w8expI +.. section: Core and Builtins + +Fix crash when calling :func:`next` on an exhausted template string +iterator. Patch by Jelle Zijlstra. + +.. + +.. date: 2025-05-16-17-25-52 +.. gh-issue: 134100 +.. nonce: 5-FbLK +.. section: Core and Builtins + +Fix a use-after-free bug that occurs when an imported module isn't in +:data:`sys.modules` after its initial import. Patch by Nico-Posada. + +.. + +.. date: 2025-05-16-09-06-38 +.. gh-issue: 134036 +.. nonce: st2e-B +.. section: Core and Builtins + +Improve :exc:`SyntaxError` message when using invalid :keyword:`raise` +statements. + +.. + +.. date: 2025-05-15-11-38-16 +.. gh-issue: 133999 +.. nonce: uBZ8uS +.. section: Core and Builtins + +Fix :exc:`SyntaxError` regression in :keyword:`except` parsing after +:gh:`123440`. + +.. + +.. date: 2025-05-11-13-40-42 +.. gh-issue: 133886 +.. nonce: ryBAyo +.. section: Core and Builtins + +Fix :func:`sys.remote_exec` for non-ASCII paths in non-UTF-8 locales and +non-UTF-8 paths in UTF-8 locales. + +.. + +.. date: 2025-05-11-09-40-19 +.. gh-issue: 133400 +.. nonce: zkWla8 +.. section: Core and Builtins + +Fixed Ctrl+D (^D) behavior in _pyrepl module to match old pre-3.13 REPL +behavior. + +.. + +.. date: 2025-05-10-17-12-27 +.. gh-issue: 133703 +.. nonce: bVM-re +.. section: Core and Builtins + +Fix hashtable in dict can be bigger than intended in some situations. + +.. + +.. date: 2025-05-09-18-11-21 +.. gh-issue: 133778 +.. nonce: pWEV3t +.. section: Core and Builtins + +Fix bug where assigning to the :attr:`~type.__annotations__` attributes of +classes defined under ``from __future__ import annotations`` had no effect. + +.. + +.. date: 2025-05-08-22-19-10 +.. gh-issue: 133711 +.. nonce: e91wUy +.. section: Core and Builtins + +Implement :pep:`686`: Enable :ref:`Python UTF-8 Mode <utf8-mode>` by +default. Patch by Adam Turner. + +.. + +.. date: 2025-05-08-13-48-02 +.. gh-issue: 132762 +.. nonce: tKbygC +.. section: Core and Builtins + +:meth:`~dict.fromkeys` no longer loops forever when adding a small set of +keys to a large base dict. Patch by Angela Liss. + +.. + +.. date: 2025-05-07-23-26-53 +.. gh-issue: 133541 +.. nonce: bHIC55 +.. section: Core and Builtins + +Inconsistent indentation in user input crashed the new REPL when syntax +highlighting was active. This is now fixed. + +.. + +.. date: 2025-05-06-15-01-41 +.. gh-issue: 133516 +.. nonce: RqWVf2 +.. section: Core and Builtins + +Raise :exc:`ValueError` when constants ``True``, ``False`` or ``None`` are +used as an identifier after NFKC normalization. + +.. + +.. date: 2025-05-03-22-31-53 +.. gh-issue: 131798 +.. nonce: fQ0ato +.. section: Core and Builtins + +Allow the JIT to remove int guards after ``_GET_LEN`` by setting the return +type to int. + +.. + +.. date: 2025-05-03-13-36-01 +.. gh-issue: 131798 +.. nonce: U4_QEJ +.. section: Core and Builtins + +Split ``CALL_ISINSTANCE`` into several uops, allowing the JIT to remove some +of them. + +.. + +.. date: 2025-04-30-14-13-01 +.. gh-issue: 132554 +.. nonce: GqQaUp +.. section: Core and Builtins + +Change iteration to use "virtual iterators" for sequences. Instead of +creating an iterator, a tagged integer representing the next index is pushed +to the stack above the iterable. For non-sequence iterators, ``NULL`` is +pushed. + +.. + +.. date: 2025-04-28-18-59-11 +.. gh-issue: 130821 +.. nonce: B11LU1 +.. section: Core and Builtins + +Enhance wrong type error messages and make them more consistent. Patch by +Semyon Moroz. + +.. + +.. date: 2025-04-26-17-50-01 +.. gh-issue: 131798 +.. nonce: XiOgw5 +.. section: Core and Builtins + +Narrow the return type and constant-evaluate ``CALL_ISINSTANCE`` for a +subset of known values in the JIT. Patch by Tomas Roun + +.. + +.. date: 2025-04-19-17-16-46 +.. gh-issue: 132542 +.. nonce: 7T_TY_ +.. section: Core and Builtins + +Update :attr:`Thread.native_id <threading.Thread.native_id>` after +:manpage:`fork(2)` to ensure accuracy. Patch by Noam Cohen. + +.. + +.. date: 2025-04-19-16-22-47 +.. gh-issue: 132732 +.. nonce: jgqhlF +.. section: Library + +Automatically constant evaluate bytecode operations marked as pure in the +JIT optimizer. + +.. + +.. date: 2025-04-16-12-01-13 +.. gh-issue: 127971 +.. nonce: pMDOQ0 +.. section: Core and Builtins + +Fix off-by-one read beyond the end of a string in string search. + +.. + +.. date: 2025-04-10-01-52-42 +.. gh-issue: 132042 +.. nonce: fePwlj +.. section: Core and Builtins + +Improve class creation times by up to 12% by pre-computing type slots just +once. Patch by Sergey Miryanov. + +.. + +.. date: 2025-04-04-16-41-00 +.. gh-issue: 133379 +.. nonce: asdjhjdf +.. section: Core and Builtins + +Correct usage of *arguments* in error messages. + +.. + +.. date: 2025-03-14-13-08-20 +.. gh-issue: 127266 +.. nonce: _tyfBp +.. section: Core and Builtins + +In the free-threaded build, avoid data races caused by updating type slots +or type flags after the type was initially created. For those (typically +rare) cases, use the stop-the-world mechanism. Remove the use of atomics +when reading or writing type flags. The use of atomics is not sufficient to +avoid races (since flags are sometimes read without a lock and without +atomics) and are no longer required. + +.. + +.. date: 2025-02-22-01-23-23 +.. gh-issue: 130425 +.. nonce: x5SNQ8 +.. section: Core and Builtins + +Add ``"Did you mean: 'attr'?"`` suggestion when using ``del obj.attr`` if +``attr`` does not exist. + +.. + +.. date: 2025-01-08-12-52-47 +.. gh-issue: 128640 +.. nonce: 9nbh9z +.. section: Core and Builtins + +Fix a crash when using threads inside of a subinterpreter. + +.. + +.. date: 2024-06-04-20-26-21 +.. gh-issue: 116738 +.. nonce: q_hPYq +.. section: Library + +Make the module :mod:`json` safe to use under the free-threading build. + +.. + +.. date: 2024-05-24-07-02-47 +.. gh-issue: 119494 +.. nonce: x3KUMC +.. section: Core and Builtins + +Exception text when trying to delete attributes of types was clarified. + +.. + +.. date: 2025-10-10-20-59-07 +.. gh-issue: 139924 +.. nonce: ALByCb +.. section: C API + +Function watchers can now receive a PyFunction_PYFUNC_EVENT_MODIFY_QUALNAME +event when a watched functions qualname is changed. + +.. + +.. date: 2025-10-07-12-51-32 +.. gh-issue: 111489 +.. nonce: LCKKlg +.. section: C API + +Add :c:func:`PyTuple_FromArray` to create a :class:`tuple` from an array. +Patch by Victor Stinner. + +.. + +.. date: 2025-09-14-14-44-24 +.. gh-issue: 136355 +.. nonce: LCaYyC +.. section: C API + +Deprecate :c:member:`PyConfig.bytes_warning` field and schedule its removal +in 3.17. + +.. + +.. date: 2025-09-14-13-09-47 +.. gh-issue: 138886 +.. nonce: dlcTXL +.. section: C API + +Remove deprecated :c:func:`!PySys_ResetWarnOptions` C-API function. + +.. + +.. date: 2025-09-12-13-05-20 +.. gh-issue: 129813 +.. nonce: dJZpME +.. section: C API + +Implement :pep:`782`, the :c:type:`PyBytesWriter` API. Add functions: + +* :c:func:`PyBytesWriter_Create` +* :c:func:`PyBytesWriter_Discard` +* :c:func:`PyBytesWriter_FinishWithPointer` +* :c:func:`PyBytesWriter_FinishWithSize` +* :c:func:`PyBytesWriter_Finish` +* :c:func:`PyBytesWriter_Format` +* :c:func:`PyBytesWriter_GetData` +* :c:func:`PyBytesWriter_GetSize` +* :c:func:`PyBytesWriter_GrowAndUpdatePointer` +* :c:func:`PyBytesWriter_Grow` +* :c:func:`PyBytesWriter_Resize` +* :c:func:`PyBytesWriter_WriteBytes` + +Patch by Victor Stinner. + +.. + +.. date: 2025-08-19-15-31-36 +.. gh-issue: 137956 +.. nonce: P4TK1d +.. section: C API + +Display and raise an exception if an extension compiled for +non-free-threaded Python is loaded in a free-threaded interpreter. + +.. + +.. date: 2025-08-13-13-41-04 +.. gh-issue: 137573 +.. nonce: r6uwRf +.. section: C API + +Mark ``_PyOptimizer_Optimize`` as :c:macro:`Py_NO_INLINE` to prevent stack +overflow crashes on macOS. + +.. + +.. date: 2025-07-31-04-30-42 +.. gh-issue: 128813 +.. nonce: opL-Pv +.. section: C API + +Functions :c:func:`_Py_c_sum`, :c:func:`_Py_c_diff`, :c:func:`_Py_c_neg`, +:c:func:`_Py_c_prod`, :c:func:`_Py_c_quot`, :c:func:`_Py_c_pow` and +previously undocumented :c:func:`_Py_c_abs` are :term:`soft deprecated`. +Deprecate also :c:member:`~PyComplexObject.cval` field of the +:c:type:`PyComplexObject` type. Patch by Sergey B Kirpichev. + +.. + +.. date: 2025-07-29-18-00-22 +.. gh-issue: 137210 +.. nonce: DD4VEm +.. section: C API + +Add API for checking an extension module's ABI compatibility: +:c:data:`Py_mod_abi`, :c:func:`PyABIInfo_Check`, :c:macro:`PyABIInfo_VAR` +and :c:data:`Py_mod_abi`. + +.. + +.. date: 2025-07-23-22-30-23 +.. gh-issue: 136759 +.. nonce: ffB4wO +.. section: C API + +Rename ``lock.h`` to ``pylock.h`` to avoid potential include conflicts. + +.. + +.. date: 2025-07-22-15-18-08 +.. gh-issue: 112068 +.. nonce: 4WvT-8 +.. section: C API + +Revert support of nullable arguments in :c:func:`PyArg_Parse`. + +.. + +.. date: 2025-07-08-22-07-54 +.. gh-issue: 136006 +.. nonce: XRU5w4 +.. section: C API + +On Solaris, the :c:macro:`!Py_NAN` macro now expands to a :c:type:`!double` +instead of a function address. Patch by Bénédikt Tran. + +.. + +.. date: 2025-07-01-16-22-39 +.. gh-issue: 135075 +.. nonce: angu3J +.. section: C API + +Make :c:func:`PyObject_SetAttr` and :c:func:`PyObject_SetAttrString` fail if +called with ``NULL`` value and an exception set. Patch by Victor Stinner. + +.. + +.. date: 2025-06-25-01-03-10 +.. gh-issue: 135906 +.. nonce: UBrCWq +.. section: C API + +Fix compilation errors when compiling the internal headers with a C++ +compiler. + +.. + +.. date: 2025-06-24-11-10-01 +.. gh-issue: 133296 +.. nonce: lIEuVJ +.. section: C API + +New variants for the critical section API that accept one or two +:c:type:`PyMutex` pointers rather than :c:type:`PyObject` instances are now +public in the non-limited C API. + +.. + +.. date: 2025-06-19-12-47-18 +.. gh-issue: 133157 +.. nonce: 1WA85f +.. section: C API + +Remove the private, undocumented macro +:c:macro:`!_Py_NO_SANITIZE_UNDEFINED`. + +.. + +.. date: 2025-06-05-11-06-07 +.. gh-issue: 134989 +.. nonce: 74p4ud +.. section: C API + +Fix ``Py_RETURN_NONE``, ``Py_RETURN_TRUE`` and ``Py_RETURN_FALSE`` macros in +the limited C API 3.11 and older: don't treat ``Py_None``, ``Py_True`` and +``Py_False`` as immortal. Patch by Victor Stinner. + +.. + +.. date: 2025-06-02-13-19-22 +.. gh-issue: 134989 +.. nonce: sDDyBN +.. section: C API + +Implement :c:func:`PyObject_DelAttr` and :c:func:`PyObject_DelAttrString` as +macros in the limited C API 3.12 and older. Patch by Victor Stinner. + +.. + +.. date: 2025-05-30-11-33-17 +.. gh-issue: 134745 +.. nonce: GN-zk2 +.. section: C API + +Change :c:func:`!PyThread_allocate_lock` implementation to ``PyMutex``. On +Windows, :c:func:`!PyThread_acquire_lock_timed` now supports the *intr_flag* +parameter: it can be interrupted. Patch by Victor Stinner. + +.. + +.. date: 2025-05-29-16-56-23 +.. gh-issue: 134891 +.. nonce: 7eKO8U +.. section: C API + +Add :c:type:`PyUnstable_Unicode_GET_CACHED_HASH` to get the cached hash of a +string. + +.. + +.. date: 2025-05-20-17-13-51 +.. gh-issue: 134009 +.. nonce: CpCmry +.. section: C API + +Expose :c:func:`PyMutex_IsLocked` as part of the public C API. + +.. + +.. date: 2025-05-17-14-41-21 +.. gh-issue: 134144 +.. nonce: xVpZik +.. section: C API + +Fix crash when calling :c:func:`Py_EndInterpreter` with a :term:`thread +state` that isn't the initial thread for the interpreter. + +.. + +.. date: 2025-05-13-16-06-46 +.. gh-issue: 133968 +.. nonce: 6alWst +.. section: C API + +Add :c:func:`PyUnicodeWriter_WriteASCII` function to write an ASCII string +into a :c:type:`PyUnicodeWriter`. The function is faster than +:c:func:`PyUnicodeWriter_WriteUTF8`, but has an undefined behavior if the +input string contains non-ASCII characters. Patch by Victor Stinner. + +.. + +.. date: 2025-05-08-13-14-45 +.. gh-issue: 133644 +.. nonce: J8_KZ2 +.. section: C API + +Remove deprecated Python initialization getter functions ``Py_Get*``. Patch +by Bénédikt Tran. + +.. + +.. date: 2025-05-08-12-40-59 +.. gh-issue: 133644 +.. nonce: FNexLJ +.. section: C API + +Remove deprecated function :c:func:`!PyWeakref_GetObject` and macro +:c:macro:`!PyWeakref_GET_OBJECT`. Use :c:func:`PyWeakref_GetRef` instead. +Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-08-12-25-47 +.. gh-issue: 133644 +.. nonce: Yb86Rm +.. section: C API + +Remove deprecated alias :c:func:`!PyImport_ImportModuleNoBlock` of +:c:func:`PyImport_ImportModule`. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-07-21-18-00 +.. gh-issue: 133610 +.. nonce: asdfjs +.. section: C API + +Remove deprecated functions :c:func:`!PyUnicode_AsDecodedObject`, +:c:func:`!PyUnicode_AsDecodedUnicode`, :c:func:`!PyUnicode_AsEncodedObject`, +and :c:func:`!PyUnicode_AsEncodedUnicode`. + +.. + +.. date: 2025-04-17-12-37-27 +.. gh-issue: 132629 +.. nonce: 01ArwX +.. section: C API + +For unsigned integer formats in :c:func:`PyArg_ParseTuple`, accepting Python +integers with value that is larger than the maximal value for the C type or +less than the minimal value for the corresponding signed integer type of the +same size is now deprecated. + +.. + +.. date: 2025-04-14-07-41-28 +.. gh-issue: 131185 +.. nonce: ZCjMHD +.. section: C API + +:c:func:`PyGILState_Ensure` no longer crashes when called after interpreter +finalization. + +.. + +.. date: 2023-10-18-14-36-35 +.. gh-issue: 108512 +.. nonce: fMZLfr +.. section: C API + +Add functions :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`, +:c:func:`PySys_GetOptionalAttr` and :c:func:`PySys_GetOptionalAttrString`. + +.. + +.. date: 2025-09-24-13-59-26 +.. gh-issue: 138489 +.. nonce: 1AcuZM +.. section: Build + +When cross-compiling for WASI by ``build_wasm`` or ``build_emscripten``, the +``build-details.json`` step is now included in the build process, just like +with native builds. + +This fixes the ``libinstall`` task which requires the ``build-details.json`` +file during the process. + +.. + +.. date: 2025-09-04-12-16-31 +.. gh-issue: 138497 +.. nonce: Y_5YXh +.. section: Build + +The LLVM version used by the JIT at build time can now be modified using the +``LLVM_VERSION`` environment variable. Use this at your own risk, as there +is only one officially supported LLVM version. For more information, please +check ``Tools/jit/README.md``. + +.. + +.. date: 2025-08-27-11-32-02 +.. gh-issue: 95952 +.. nonce: KSymc7 +.. section: Build + +When cross-compiling for WASI, require that the HOSTRUNNER environment +variable be explicitly set. + +This was needed as macOS lacks the appropriate CLI tools to set a reasonable +default. + +.. + +.. date: 2025-08-27-09-52-45 +.. gh-issue: 138061 +.. nonce: fMVS9w +.. section: Build + +Ensure reproducible builds by making JIT stencil header generation +deterministic. + +.. + +.. date: 2025-08-26-21-18-32 +.. gh-issue: 128042 +.. nonce: 5voC8H +.. section: Build + +``./configure`` now warns when ``--enable-optimizations`` and ``CFLAGS=-O0`` +are both set, suggesting removing ``-O0`` from ``CFLAGS`` for optimal +performance. Patch by Taegyun Kim. + +.. + +.. date: 2025-08-13-12-10-12 +.. gh-issue: 132339 +.. nonce: 3Czz5y +.. section: Build + +Add support for OpenSSL 3.5. + +.. + +.. date: 2025-07-18-17-15-00 +.. gh-issue: 135621 +.. nonce: 9cyCNb +.. section: Build + +PyREPL no longer depends on the :mod:`curses` standard library. Contributed +by Łukasz Langa. + +.. + +.. date: 2025-06-25-13-27-14 +.. gh-issue: 135927 +.. nonce: iCNPQc +.. section: Build + +Fix building with MSVC when passing option ``/std:clatest``. + +.. + +.. date: 2025-06-16-07-20-28 +.. gh-issue: 119132 +.. nonce: fcI8s7 +.. section: Build + +Remove "experimental" tag from the CPython free-threading build. + +.. + +.. date: 2025-06-14-10-32-11 +.. gh-issue: 135497 +.. nonce: ajlV4F +.. section: Build + +Fix the detection of ``MAXLOGNAME`` in the ``configure.ac`` script. + +.. + +.. date: 2025-05-30-11-02-30 +.. gh-issue: 134923 +.. nonce: gBkRg4 +.. section: Build + +Windows builds with profile-guided optimization enabled now use +``/GENPROFILE`` and ``/USEPROFILE`` instead of deprecated ``/LTCG:`` +options. + +.. + +.. date: 2025-05-24-16-59-20 +.. gh-issue: 134632 +.. nonce: i0W2hc +.. section: Build + +Fixed ``build-details.json`` generation to use ``INCLUDEPY``, in order to +reference the ``pythonX.Y`` subdirectory of the include directory, as +required in :pep:`739`, instead of the top-level include directory. + +.. + +.. date: 2025-05-21-22-13-30 +.. gh-issue: 134486 +.. nonce: yvdL6f +.. section: Build + +The :mod:`ctypes` module now performs a more portable test for the +definition of :manpage:`alloca(3)`, fixing a compilation failure on NetBSD. + +.. + +.. date: 2025-05-21-19-46-28 +.. gh-issue: 134455 +.. nonce: vdwlrq +.. section: Build + +Fixed ``build-details.json`` generation to use the correct ``c_api.headers`` +as defined in :pep:`739`, instead of ``c_api.include``. + +.. + +.. date: 2025-05-19-18-09-20 +.. gh-issue: 134273 +.. nonce: ZAliyy +.. section: Build + +Add support for configuring compiler flags for the JIT with ``CFLAGS_JIT`` + +.. + +.. date: 2025-05-16-07-46-06 +.. gh-issue: 115119 +.. nonce: ALBgS_ +.. section: Build + +Removed implicit fallback to the bundled copy of the ``libmpdec`` library. +Now this should be explicitly enabled via :option:`--with-system-libmpdec` +set to ``no`` or :option:`!--without-system-libmpdec`. Patch by Sergey B +Kirpichev. + +.. + +.. date: 2025-05-14-09-43-48 +.. gh-issue: 131769 +.. nonce: H0oy5x +.. section: Build + +Fix detecting when the build Python in a cross-build is a pydebug build. + +.. + +.. date: 2025-04-16-09-38-48 +.. gh-issue: 117088 +.. nonce: EFt_5c +.. section: Build + +AIX linker don't support -h option, so avoid it through platform check + +.. + +.. date: 2025-01-03-13-02-06 +.. gh-issue: 123681 +.. nonce: gQ67nK +.. section: Build + +Check the ``strftime()`` behavior at runtime instead of at the compile time +to support cross-compiling. Remove the internal macro +``_Py_NORMALIZE_CENTURY``. + +.. + +.. date: 2024-12-04-10-00-35 +.. gh-issue: 127545 +.. nonce: t0THjE +.. section: Build + +Fix crash when building on Linux/m68k. diff --git a/Misc/NEWS.d/3.15.0a2.rst b/Misc/NEWS.d/3.15.0a2.rst new file mode 100644 index 00000000000..852bce71ebd --- /dev/null +++ b/Misc/NEWS.d/3.15.0a2.rst @@ -0,0 +1,1746 @@ +.. date: 2025-11-04-19-20-05 +.. gh-issue: 140849 +.. nonce: YjB2ZZ +.. release date: 2025-11-18 +.. section: Windows + +Update bundled liblzma to version 5.8.1. + +.. + +.. date: 2025-11-12-12-54-28 +.. gh-issue: 141442 +.. nonce: 50dS3P +.. section: Tools/Demos + +The iOS testbed now correctly handles test arguments that contain spaces. + +.. + +.. date: 2025-10-29-15-20-19 +.. gh-issue: 140702 +.. nonce: ZXtW8h +.. section: Tools/Demos + +The iOS testbed app will now expose the ``GITHUB_ACTIONS`` environment +variable to iOS apps being tested. + +.. + +.. date: 2025-09-21-10-30-08 +.. gh-issue: 139198 +.. nonce: Fm7NfU +.. section: Tools/Demos + +Remove ``Tools/scripts/checkpip.py`` script. + +.. + +.. date: 2025-09-20-20-31-54 +.. gh-issue: 139188 +.. nonce: zfcxkW +.. section: Tools/Demos + +Remove ``Tools/tz/zdump.py`` script. + +.. + +.. date: 2025-10-23-16-39-49 +.. gh-issue: 140482 +.. nonce: ZMtyeD +.. section: Tests + +Preserve and restore the state of ``stty echo`` as part of the test +environment. + +.. + +.. date: 2025-10-15-00-52-12 +.. gh-issue: 140082 +.. nonce: fpET50 +.. section: Tests + +Update ``python -m test`` to set ``FORCE_COLOR=1`` when being run with color +enabled so that :mod:`unittest` which is run by it with redirected output +will output in color. + +.. + +.. date: 2025-07-09-21-45-51 +.. gh-issue: 136442 +.. nonce: jlbklP +.. section: Tests + +Use exitcode ``1`` instead of ``5`` if :func:`unittest.TestCase.setUpClass` +raises an exception + +.. + +.. date: 2025-08-15-23-08-44 +.. gh-issue: 137836 +.. nonce: b55rhh +.. section: Security + +Add support of the "plaintext" element, RAWTEXT elements "xmp", "iframe", +"noembed" and "noframes", and optionally RAWTEXT element "noscript" in +:class:`html.parser.HTMLParser`. + +.. + +.. date: 2025-06-28-13-23-53 +.. gh-issue: 136063 +.. nonce: aGk0Jv +.. section: Security + +:mod:`email.message`: ensure linear complexity for legacy HTTP parameters +parsing. Patch by Bénédikt Tran. + +.. + +.. date: 2025-05-30-22-33-27 +.. gh-issue: 136065 +.. nonce: bu337o +.. section: Security + +Fix quadratic complexity in :func:`os.path.expandvars`. + +.. + +.. date: 2025-11-14-16-24-20 +.. gh-issue: 141497 +.. nonce: L_CxDJ +.. section: Library + +:mod:`ipaddress`: ensure that the methods :meth:`IPv4Network.hosts() +<ipaddress.IPv4Network.hosts>` and :meth:`IPv6Network.hosts() +<ipaddress.IPv6Network.hosts>` always return an iterator. + +.. + +.. date: 2025-11-13-14-51-30 +.. gh-issue: 140938 +.. nonce: kXsHHv +.. section: Library + +The :func:`statistics.stdev` and :func:`statistics.pstdev` functions now +raise a :exc:`ValueError` when the input contains an infinity or a NaN. + +.. + +.. date: 2025-11-12-15-42-47 +.. gh-issue: 124111 +.. nonce: hTw4OE +.. section: Library + +Updated Tcl threading configuration in :mod:`_tkinter` to assume that +threads are always available in Tcl 9 and later. + +.. + +.. date: 2025-11-12-01-49-03 +.. gh-issue: 137109 +.. nonce: D6sq2B +.. section: Library + +The :mod:`os.fork` and related forking APIs will no longer warn in the +common case where Linux or macOS platform APIs return the number of threads +in a process and find the answer to be 1 even when a +:func:`os.register_at_fork` ``after_in_parent=`` callback (re)starts a +thread. + +.. + +.. date: 2025-11-10-01-47-18 +.. gh-issue: 141314 +.. nonce: baaa28 +.. section: Library + +Fix assertion failure in :meth:`io.TextIOWrapper.tell` when reading files +with standalone carriage return (``\r``) line endings. + +.. + +.. date: 2025-11-09-18-55-13 +.. gh-issue: 141311 +.. nonce: qZ3swc +.. section: Library + +Fix assertion failure in :func:`!io.BytesIO.readinto` and undefined behavior +arising when read position is above capcity in :class:`io.BytesIO`. + +.. + +.. date: 2025-11-08-13-03-10 +.. gh-issue: 87710 +.. nonce: XJeZlP +.. section: Library + +:mod:`mimetypes`: Update mime type for ``.ai`` files to ``application/pdf``. + +.. + +.. date: 2025-11-07-12-25-46 +.. gh-issue: 85524 +.. nonce: 9SWFIC +.. section: Library + +Update ``io.FileIO.readall``, an implementation of +:meth:`io.RawIOBase.readall`, to follow :class:`io.IOBase` guidelines and +raise :exc:`io.UnsupportedOperation` when a file is in "w" mode rather than +:exc:`OSError` + +.. + +.. date: 2025-11-06-15-11-50 +.. gh-issue: 141141 +.. nonce: tgIfgH +.. section: Library + +Fix a thread safety issue with :func:`base64.b85decode`. Contributed by +Benel Tayar. + +.. + +.. date: 2025-11-04-20-08-41 +.. gh-issue: 141018 +.. nonce: d_oyOI +.. section: Library + +:mod:`mimetypes`: Update ``.exe``, ``.dll``, ``.rtf`` and (when +``strict=False``) ``.jpg`` to their correct IANA mime type. + +.. + +.. date: 2025-11-04-15-40-35 +.. gh-issue: 137969 +.. nonce: 9VZQVt +.. section: Library + +Fix :meth:`annotationlib.ForwardRef.evaluate` returning +:class:`~annotationlib.ForwardRef` objects which don't update with new +globals. + +.. + +.. date: 2025-11-04-12-16-13 +.. gh-issue: 75593 +.. nonce: EFVhKR +.. section: Library + +Add support of :term:`path-like objects <path-like object>` and +:term:`bytes-like objects <bytes-like object>` in :func:`wave.open`. + +.. + +.. date: 2025-11-03-16-23-54 +.. gh-issue: 140797 +.. nonce: DuFEeR +.. section: Library + +The undocumented :class:`!re.Scanner` class now forbids regular expressions +containing capturing groups in its lexicon patterns. Patterns using +capturing groups could previously lead to crashes with segmentation fault. +Use non-capturing groups (?:...) instead. + +.. + +.. date: 2025-11-03-05-38-31 +.. gh-issue: 125115 +.. nonce: jGS8MN +.. section: Library + +Refactor the :mod:`pdb` parsing issue so positional arguments can pass +through intuitively. + +.. + +.. date: 2025-11-02-19-23-32 +.. gh-issue: 140815 +.. nonce: McEG-T +.. section: Library + +:mod:`faulthandler` now detects if a frame or a code object is invalid or +freed. Patch by Victor Stinner. + +.. + +.. date: 2025-11-02-11-46-00 +.. gh-issue: 100218 +.. nonce: 9Ezfdq +.. section: Library + +Correctly set :attr:`~OSError.errno` when :func:`socket.if_nametoindex` or +:func:`socket.if_indextoname` raise an :exc:`OSError`. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-11-02-09-37-22 +.. gh-issue: 140734 +.. nonce: f8gST9 +.. section: Library + +:mod:`multiprocessing`: fix off-by-one error when checking the length of a +temporary socket file path. Patch by Bénédikt Tran. + +.. + +.. date: 2025-11-01-14-44-09 +.. gh-issue: 140873 +.. nonce: kfuc9B +.. section: Library + +Add support of non-:term:`descriptor` callables in +:func:`functools.singledispatchmethod`. + +.. + +.. date: 2025-11-01-00-36-14 +.. gh-issue: 140874 +.. nonce: eAWt3K +.. section: Library + +Bump the version of pip bundled in ensurepip to version 25.3 + +.. + +.. date: 2025-11-01-00-34-53 +.. gh-issue: 140826 +.. nonce: JEDd7U +.. section: Library + +Now :class:`!winreg.HKEYType` objects are compared by their underlying +Windows registry handle value instead of their object identity. + +.. + +.. date: 2025-10-31-16-25-13 +.. gh-issue: 140808 +.. nonce: XBiQ4j +.. section: Library + +The internal class ``mailbox._ProxyFile`` is no longer a parameterized +generic. + +.. + +.. date: 2025-10-31-15-06-26 +.. gh-issue: 140691 +.. nonce: JzHGtg +.. section: Library + +In :mod:`urllib.request`, when opening a FTP URL fails because a data +connection cannot be made, the control connection's socket is now closed to +avoid a :exc:`ResourceWarning`. + +.. + +.. date: 2025-10-31-13-57-55 +.. gh-issue: 103847 +.. nonce: VM7TnW +.. section: Library + +Fix hang when cancelling process created by +:func:`asyncio.create_subprocess_exec` or +:func:`asyncio.create_subprocess_shell`. Patch by Kumar Aditya. + +.. + +.. date: 2025-10-30-15-33-07 +.. gh-issue: 137821 +.. nonce: 8_Iavt +.. section: Library + +Convert ``_json`` module to use Argument Clinic. Patched by Yoonho Hann. + +.. + +.. date: 2025-10-30-12-36-19 +.. gh-issue: 140790 +.. nonce: _3T6-N +.. section: Library + +Initialize all Pdb's instance variables in ``__init__``, remove some +hasattr/getattr + +.. + +.. date: 2025-10-29-16-53-00 +.. gh-issue: 140766 +.. nonce: CNagKF +.. section: Library + +Add :func:`enum.show_flag_values` and ``enum.bin`` to ``enum.__all__``. + +.. + +.. date: 2025-10-29-16-12-41 +.. gh-issue: 120057 +.. nonce: qGj5Dl +.. section: Library + +Add :func:`os.reload_environ` to ``os.__all__``. + +.. + +.. date: 2025-10-29-09-40-10 +.. gh-issue: 140741 +.. nonce: L13UCV +.. section: Library + +Fix ``profiling.sampling.sample()`` incorrectly handling a +:exc:`FileNotFoundError` or :exc:`PermissionError`. + +.. + +.. date: 2025-10-28-17-43-51 +.. gh-issue: 140228 +.. nonce: 8kfHhO +.. section: Library + +Avoid making unnecessary filesystem calls for frozen modules in +:mod:`linecache` when the global module cache is not present. + +.. + +.. date: 2025-10-28-02-46-56 +.. gh-issue: 139946 +.. nonce: aN3_uY +.. section: Library + +Error and warning keywords in ``argparse.ArgumentParser`` messages are now +colorized when color output is enabled, fixing a visual inconsistency in +which they remained plain text while other output was colorized. + +.. + +.. date: 2025-10-27-18-29-42 +.. gh-issue: 140590 +.. nonce: LT9HHn +.. section: Library + +Fix arguments checking for the :meth:`!functools.partial.__setstate__` that +may lead to internal state corruption and crash. Patch by Sergey Miryanov. + +.. + +.. date: 2025-10-27-16-01-41 +.. gh-issue: 125434 +.. nonce: qy0uRA +.. section: Library + +Display thread name in :mod:`faulthandler` on Windows. Patch by Victor +Stinner. + +.. + +.. date: 2025-10-27-13-49-31 +.. gh-issue: 140634 +.. nonce: ULng9G +.. section: Library + +Fix a reference counting bug in :meth:`!os.sched_param.__reduce__`. + +.. + +.. date: 2025-10-27-00-40-49 +.. gh-issue: 140650 +.. nonce: DYJPJ9 +.. section: Library + +Fix an issue where closing :class:`io.BufferedWriter` could crash if the +closed attribute raised an exception on access or could not be converted to +a boolean. + +.. + +.. date: 2025-10-26-16-24-12 +.. gh-issue: 140633 +.. nonce: ioayC1 +.. section: Library + +Ignore :exc:`AttributeError` when setting a module's ``__file__`` attribute +when loading an extension module packaged as Apple Framework. + +.. + +.. date: 2025-10-25-22-55-07 +.. gh-issue: 140601 +.. nonce: In3MlS +.. section: Library + +:func:`xml.etree.ElementTree.iterparse` now emits a :exc:`ResourceWarning` +when the iterator is not explicitly closed and was opened with a filename. +This helps developers identify and fix resource leaks. Patch by Osama +Abdelkader. + +.. + +.. date: 2025-10-25-21-26-16 +.. gh-issue: 140593 +.. nonce: OxlLc9 +.. section: Library + +:mod:`xml.parsers.expat`: Fix a memory leak that could affect users with +:meth:`~xml.parsers.expat.xmlparser.ElementDeclHandler` set to a custom +element declaration handler. Patch by Sebastian Pipping. + +.. + +.. date: 2025-10-25-21-04-00 +.. gh-issue: 140607 +.. nonce: oOZGxS +.. section: Library + +Inside :meth:`io.RawIOBase.read`, validate that the count of bytes returned +by :meth:`io.RawIOBase.readinto` is valid (inside the provided buffer). + +.. + +.. date: 2025-10-23-19-39-16 +.. gh-issue: 138162 +.. nonce: Znw5DN +.. section: Library + +Fix :class:`logging.LoggerAdapter` with ``merge_extra=True`` and without the +*extra* argument. + +.. + +.. date: 2025-10-23-13-42-15 +.. gh-issue: 140481 +.. nonce: XKxWpq +.. section: Library + +Improve error message when trying to iterate a Tk widget, image or font. + +.. + +.. date: 2025-10-23-12-12-22 +.. gh-issue: 138774 +.. nonce: mnh2gU +.. section: Library + +:func:`ast.unparse` now generates full source code when handling +:class:`ast.Interpolation` nodes that do not have a specified source. + +.. + +.. date: 2025-10-22-20-52-13 +.. gh-issue: 140474 +.. nonce: xIWlip +.. section: Library + +Fix memory leak in :class:`array.array` when creating arrays from an empty +:class:`str` and the ``u`` type code. + +.. + +.. date: 2025-10-22-12-56-57 +.. gh-issue: 140448 +.. nonce: GsEkXD +.. section: Library + +Change the default of ``suggest_on_error`` to ``True`` in +``argparse.ArgumentParser``. + +.. + +.. date: 2025-10-21-15-54-13 +.. gh-issue: 137530 +.. nonce: ZyIVUH +.. section: Library + +:mod:`dataclasses` Fix annotations for generated ``__init__`` methods by +replacing the annotations that were in-line in the generated source code +with ``__annotate__`` functions attached to the methods. + +.. + +.. date: 2025-10-20-12-33-49 +.. gh-issue: 140348 +.. nonce: SAKnQZ +.. section: Library + +Fix regression in Python 3.14.0 where using the ``|`` operator on a +:class:`typing.Union` object combined with an object that is not a type +would raise an error. + +.. + +.. date: 2025-10-18-15-20-25 +.. gh-issue: 76007 +.. nonce: SNUzRq +.. section: Library + +:mod:`decimal`: Deprecate ``__version__`` and replace with +:data:`decimal.SPEC_VERSION`. + +.. + +.. date: 2025-10-18-14-30-21 +.. gh-issue: 76007 +.. nonce: peEgcr +.. section: Library + +Deprecate ``__version__`` from :mod:`imaplib`. Patch by Hugo van Kemenade. + +.. + +.. date: 2025-10-17-23-58-11 +.. gh-issue: 140272 +.. nonce: lhY8uS +.. section: Library + +Fix memory leak in the :meth:`!clear` method of the :mod:`dbm.gnu` database. + +.. + +.. date: 2025-10-17-20-42-38 +.. gh-issue: 129117 +.. nonce: X9jr4p +.. section: Library + +:mod:`unicodedata`: Add :func:`~unicodedata.isxidstart` and +:func:`~unicodedata.isxidcontinue` functions to check whether a character +can start or continue a `Unicode Standard Annex #31 +<https://www.unicode.org/reports/tr31/>`_ identifier. + +.. + +.. date: 2025-10-17-12-33-01 +.. gh-issue: 140251 +.. nonce: esM-OX +.. section: Library + +Colorize the default import statement ``import asyncio`` in asyncio REPL. + +.. + +.. date: 2025-10-16-22-49-16 +.. gh-issue: 140212 +.. nonce: llBNd0 +.. section: Library + +Calendar's HTML formatting now accepts year and month as options. +Previously, running ``python -m calendar -t html 2025 10`` would result in +an error message. It now generates an HTML document displaying the calendar +for the specified month. Contributed by Pål Grønås Drange. + +.. + +.. date: 2025-10-16-17-17-20 +.. gh-issue: 135801 +.. nonce: faH3fa +.. section: Library + +Improve filtering by module in :func:`warnings.warn_explicit` if no *module* +argument is passed. It now tests the module regular expression in the +warnings filter not only against the filename with ``.py`` stripped, but +also against module names constructed starting from different parent +directories of the filename (with ``/__init__.py``, ``.py`` and, on Windows, +``.pyw`` stripped). + +.. + +.. date: 2025-10-16-16-10-11 +.. gh-issue: 139707 +.. nonce: zR6Qtn +.. section: Library + +Improve :exc:`ModuleNotFoundError` error message when a :term:`standard +library` module is missing. + +.. + +.. date: 2025-10-15-21-42-13 +.. gh-issue: 140041 +.. nonce: _Fka2j +.. section: Library + +Fix import of :mod:`ctypes` on Android and Cygwin when ABI flags are +present. + +.. + +.. date: 2025-10-15-20-47-04 +.. gh-issue: 140120 +.. nonce: 3gffZq +.. section: Library + +Fixed a memory leak in :mod:`hmac` when it was using the hacl-star backend. +Discovered by ``@ashm-dev`` using AddressSanitizer. + +.. + +.. date: 2025-10-15-17-23-51 +.. gh-issue: 140141 +.. nonce: j2mUDB +.. section: Library + +The :py:class:`importlib.metadata.PackageNotFoundError` traceback raised +when ``importlib.metadata.Distribution.from_name`` cannot discover a +distribution no longer includes a transient :exc:`StopIteration` exception +trace. + +Contributed by Bartosz Sławecki in :gh:`140142`. + +.. + +.. date: 2025-10-15-15-10-34 +.. gh-issue: 140166 +.. nonce: NtxRez +.. section: Library + +:mod:`mimetypes`: Per the `IANA assignment +<https://www.iana.org/assignments/media-types/application/texinfo>`_, update +the MIME type for the ``.texi`` and ``.texinfo`` file formats to +``application/texinfo``, instead of ``application/x-texinfo``. + +.. + +.. date: 2025-10-15-02-26-50 +.. gh-issue: 140135 +.. nonce: 54JYfM +.. section: Library + +Speed up :meth:`io.RawIOBase.readall` by using PyBytesWriter API (about 4x +faster) + +.. + +.. date: 2025-10-14-20-27-06 +.. gh-issue: 76007 +.. nonce: 2NcUbo +.. section: Library + +:mod:`zlib`: Deprecate ``__version__`` and schedule for removal in Python +3.20. + +.. + +.. date: 2025-10-13-11-25-41 +.. gh-issue: 136702 +.. nonce: uvLGK1 +.. section: Library + +:mod:`encodings`: Deprecate passing a non-ascii *encoding* name to +:func:`encodings.normalize_encoding` and schedule removal of support for +Python 3.17. + +.. + +.. date: 2025-10-11-09-07-06 +.. gh-issue: 139940 +.. nonce: g54efZ +.. section: Library + +Print clearer error message when using ``pdb`` to attach to a non-existing +process. + +.. + +.. date: 2025-10-02-22-29-00 +.. gh-issue: 139462 +.. nonce: VZXUHe +.. section: Library + +When a child process in a :class:`concurrent.futures.ProcessPoolExecutor` +terminates abruptly, the resulting traceback will now tell you the PID and +exit code of the terminated process. Contributed by Jonathan Berg. + +.. + +.. date: 2025-09-30-12-52-54 +.. gh-issue: 63161 +.. nonce: mECM1A +.. section: Library + +Fix :func:`tokenize.detect_encoding`. Support non-UTF-8 shebang and comments +if non-UTF-8 encoding is specified. Detect decoding error for non-UTF-8 +encoding. Detect null bytes in source code. + +.. + +.. date: 2025-09-25-20-16-10 +.. gh-issue: 101828 +.. nonce: yTxJlJ +.. section: Library + +Fix ``'shift_jisx0213'``, ``'shift_jis_2004'``, ``'euc_jisx0213'`` and +``'euc_jis_2004'`` codecs truncating null chars as they were treated as part +of multi-character sequences. + +.. + +.. date: 2025-09-23-09-46-46 +.. gh-issue: 139246 +.. nonce: pzfM-w +.. section: Library + +fix: paste zero-width in default repl width is wrong. + +.. + +.. date: 2025-09-18-21-25-41 +.. gh-issue: 83714 +.. nonce: TQjDWZ +.. section: Library + +Implement :func:`os.statx` on Linux kernel versions 4.11 and later with +glibc versions 2.28 and later. Contributed by Jeffrey Bosboom and Victor +Stinner. + +.. + +.. date: 2025-09-15-21-03-11 +.. gh-issue: 138891 +.. nonce: oZFdtR +.. section: Library + +Fix ``SyntaxError`` when ``inspect.get_annotations(f, eval_str=True)`` is +called on a function annotated with a :pep:`646` ``star_expression`` + +.. + +.. date: 2025-09-13-12-19-17 +.. gh-issue: 138859 +.. nonce: PxjIoN +.. section: Library + +Fix generic type parameterization raising a :exc:`TypeError` when omitting a +:class:`ParamSpec` that has a default which is not a list of types. + +.. + +.. date: 2025-09-12-09-34-37 +.. gh-issue: 138764 +.. nonce: mokHoY +.. section: Library + +Prevent :func:`annotationlib.call_annotate_function` from calling +``__annotate__`` functions that don't support ``VALUE_WITH_FAKE_GLOBALS`` in +a fake globals namespace with empty globals. + +Make ``FORWARDREF`` and ``STRING`` annotations fall back to using ``VALUE`` +annotations in the case that neither their own format, nor +``VALUE_WITH_FAKE_GLOBALS`` are supported. + +.. + +.. date: 2025-09-11-15-03-37 +.. gh-issue: 138775 +.. nonce: w7rnSx +.. section: Library + +Use of ``python -m`` with :mod:`base64` has been fixed to detect input from +a terminal so that it properly notices EOF. + +.. + +.. date: 2025-09-03-20-18-39 +.. gh-issue: 98896 +.. nonce: tjez89 +.. section: Library + +Fix a failure in multiprocessing resource_tracker when SharedMemory names +contain colons. Patch by Rani Pinchuk. + +.. + +.. date: 2025-09-03-18-26-07 +.. gh-issue: 138425 +.. nonce: cVE9Ho +.. section: Library + +Fix partial evaluation of :class:`annotationlib.ForwardRef` objects which +rely on names defined as globals. + +.. + +.. date: 2025-08-26-08-17-56 +.. gh-issue: 138151 +.. nonce: I6CdAk +.. section: Library + +In :mod:`annotationlib`, improve evaluation of forward references to +nonlocal variables that are not yet defined when the annotations are +initially evaluated. + +.. + +.. date: 2025-08-15-20-35-30 +.. gh-issue: 69528 +.. nonce: qc-Eh_ +.. section: Library + +The :attr:`~io.FileIO.mode` attribute of files opened in the ``'wb+'`` mode +is now ``'wb+'`` instead of ``'rb+'``. + +.. + +.. date: 2025-08-11-04-52-18 +.. gh-issue: 137627 +.. nonce: Ku5Yi2 +.. section: Library + +Speed up :meth:`csv.Sniffer.sniff` delimiter detection by up to 1.6x. + +.. + +.. date: 2025-07-14-09-33-17 +.. gh-issue: 55531 +.. nonce: Gt2e12 +.. section: Library + +:mod:`encodings`: Improve :func:`~encodings.normalize_encoding` performance +by implementing the function in C using the private +``_Py_normalize_encoding`` which has been modified to make lowercase +conversion optional. + +.. + +.. date: 2025-07-01-04-57-57 +.. gh-issue: 136057 +.. nonce: 4-t596 +.. section: Library + +Fixed the bug in :mod:`pdb` and :mod:`bdb` where ``next`` and ``step`` can't +go over the line if a loop exists in the line. + +.. + +.. date: 2025-06-29-22-01-00 +.. gh-issue: 133390 +.. nonce: I1DW_3 +.. section: Library + +Support table, index, trigger, view, column, function, and schema completion +for :mod:`sqlite3`'s :ref:`command-line interface <sqlite3-cli>`. + +.. + +.. date: 2025-06-10-18-02-29 +.. gh-issue: 135307 +.. nonce: fXGrcK +.. section: Library + +:mod:`email`: Fix exception in ``set_content()`` when encoding text and +max_line_length is set to ``0`` or ``None`` (unlimited). + +.. + +.. date: 2025-05-10-15-10-54 +.. gh-issue: 133789 +.. nonce: I-ZlUX +.. section: Library + +Fix unpickling of :mod:`pathlib` objects that were pickled in Python 3.13. + +.. + +.. date: 2025-05-07-22-09-28 +.. gh-issue: 133601 +.. nonce: 9kUL3P +.. section: Library + +Remove deprecated :func:`!typing.no_type_check_decorator`. + +.. + +.. date: 2025-04-18-18-08-05 +.. gh-issue: 132686 +.. nonce: 6kV_Gs +.. section: Library + +Add parameters *inherit_class_doc* and *fallback_to_class_doc* for +:func:`inspect.getdoc`. + +.. + +.. date: 2025-03-12-18-57-10 +.. gh-issue: 131116 +.. nonce: uTpwXZ +.. section: Library + +:func:`inspect.getdoc` now correctly returns an inherited docstring on +:class:`~functools.cached_property` objects if none is given in a subclass. + +.. + +.. date: 2025-03-04-17-19-26 +.. gh-issue: 130693 +.. nonce: Kv01r8 +.. section: Library + +Add support for ``-nolinestop``, and ``-strictlimits`` options to +:meth:`!tkinter.Text.search`. Also add the :meth:`!tkinter.Text.search_all` +method for ``-all`` and ``-overlap`` options. + +.. + +.. date: 2024-08-08-12-39-36 +.. gh-issue: 122255 +.. nonce: J_gU8Y +.. section: Library + +In the :mod:`linecache` module and in the Python implementation of the +:mod:`warnings` module, a ``DeprecationWarning`` is issued when +``mod.__loader__`` differs from ``mod.__spec__.loader`` (like in the C +implementation of the :mod:`!warnings` module). + +.. + +.. date: 2024-06-26-16-16-43 +.. gh-issue: 121011 +.. nonce: qW54eh +.. section: Library + +:func:`math.log` now supports arbitrary large integer-like arguments in the +same way as arbitrary large integer arguments. + +.. + +.. date: 2024-05-28-17-14-30 +.. gh-issue: 119668 +.. nonce: RrIGpn +.. section: Library + +Publicly expose and document :class:`importlib.machinery.NamespacePath`. + +.. + +.. date: 2023-03-21-10-59-40 +.. gh-issue: 102431 +.. nonce: eUDnf4 +.. section: Library + +Clarify constraints for "logical" arguments in methods of +:class:`decimal.Context`. + +.. + +.. date: 2019-06-02-13-56-16 +.. gh-issue: 81313 +.. nonce: axawSH +.. section: Library + +Add the :mod:`math.integer` module (:pep:`791`). + +.. + +.. date: 2025-11-15-01-21-00 +.. gh-issue: 141579 +.. nonce: aB7cD9 +.. section: Core and Builtins + +Fix :func:`sys.activate_stack_trampoline` to properly support the +``perf_jit`` backend. Patch by Pablo Galindo. + +.. + +.. date: 2025-11-14-16-25-15 +.. gh-issue: 114203 +.. nonce: n3tlQO +.. section: Core and Builtins + +Skip locking if object is already locked by two-mutex critical section. + +.. + +.. date: 2025-11-14-00-19-45 +.. gh-issue: 141528 +.. nonce: VWdax1 +.. section: Core and Builtins + +Suggest using :meth:`concurrent.interpreters.Interpreter.close` instead of +the private ``_interpreters.destroy`` function when warning about remaining +subinterpreters. Patch by Sergey Miryanov. + +.. + +.. date: 2025-11-11-13-40-45 +.. gh-issue: 141367 +.. nonce: I5KY7F +.. section: Core and Builtins + +Specialize ``CALL_LIST_APPEND`` instruction only for lists, not for list +subclasses, to avoid unnecessary deopt. Patch by Mikhail Efimov. + +.. + +.. date: 2025-11-10-23-07-06 +.. gh-issue: 141312 +.. nonce: H-58GB +.. section: Core and Builtins + +Fix the assertion failure in the ``__setstate__`` method of the range +iterator when a non-integer argument is passed. Patch by Sergey Miryanov. + +.. + +.. date: 2025-11-05-19-50-37 +.. gh-issue: 140643 +.. nonce: QCEOqG +.. section: Core and Builtins + +Add support for ``<GC>`` and ``<native>`` frames to +:mod:`!profiling.sampling` output to denote active garbage collection and +calls to native code. + +.. + +.. date: 2025-11-04-12-18-06 +.. gh-issue: 140942 +.. nonce: GYns6n +.. section: Library + +Add ``.cjs`` to :mod:`mimetypes` to give CommonJS modules a MIME type of +``application/node``. + +.. + +.. date: 2025-11-04-04-57-24 +.. gh-issue: 140479 +.. nonce: lwQ2v2 +.. section: Core and Builtins + +Update JIT compilation to use LLVM 21 at build time. + +.. + +.. date: 2025-11-03-17-21-38 +.. gh-issue: 140939 +.. nonce: FVboAw +.. section: Core and Builtins + +Fix memory leak when :class:`bytearray` or :class:`bytes` is formated with +the ``%*b`` format with a large width that results in a :exc:`MemoryError`. + +.. + +.. date: 2025-11-02-15-28-33 +.. gh-issue: 140260 +.. nonce: JNzlGz +.. section: Library + +Fix :mod:`struct` data race in endian table initialization with +subinterpreters. Patch by Shamil Abdulaev. + +.. + +.. date: 2025-11-02-12-47-38 +.. gh-issue: 140530 +.. nonce: S934bp +.. section: Core and Builtins + +Fix a reference leak when ``raise exc from cause`` fails. Patch by Bénédikt +Tran. + +.. + +.. date: 2025-10-31-14-03-42 +.. gh-issue: 90344 +.. nonce: gvZigO +.. section: Library + +Replace :class:`io.IncrementalNewlineDecoder` with non incremental newline +decoders in codebase where :meth:`!io.IncrementalNewlineDecoder.decode` was +being called once. + +.. + +.. date: 2025-10-29-20-59-10 +.. gh-issue: 140373 +.. nonce: -uoaPP +.. section: Core and Builtins + +Correctly emit ``PY_UNWIND`` event when generator object is closed. Patch by +Mikhail Efimov. + +.. + +.. date: 2025-10-29-11-31-59 +.. gh-issue: 140729 +.. nonce: t9JsNt +.. section: Core and Builtins + +Fix pickling error in the sampling profiler when using +``concurrent.futures.ProcessPoolExecutor`` script can not be properly +pickled and executed in worker processes. + +.. + +.. date: 2025-10-25-21-31-43 +.. gh-issue: 131527 +.. nonce: V-JVNP +.. section: Core and Builtins + +Dynamic borrow checking for stackrefs is added to ``Py_STACKREF_DEBUG`` +mode. Patch by Mikhail Efimov. + +.. + +.. date: 2025-10-25-17-36-46 +.. gh-issue: 140576 +.. nonce: kj0SCY +.. section: Core and Builtins + +Fixed crash in :func:`tokenize.generate_tokens` in case of specific +incorrect input. Patch by Mikhail Efimov. + +.. + +.. date: 2025-10-25-07-25-52 +.. gh-issue: 140544 +.. nonce: lwjtQe +.. section: Core and Builtins + +Speed up accessing interpreter state by caching it in a thread local +variable. Patch by Kumar Aditya. + +.. + +.. date: 2025-10-24-20-42-33 +.. gh-issue: 140551 +.. nonce: -9swrl +.. section: Core and Builtins + +Fixed crash in :class:`dict` if :meth:`dict.clear` is called at the lookup +stage. Patch by Mikhail Efimov and Inada Naoki. + +.. + +.. date: 2025-10-24-20-16-42 +.. gh-issue: 140517 +.. nonce: cqun-K +.. section: Core and Builtins + +Fixed a reference leak when iterating over the result of :func:`map` with +``strict=True`` when the input iterables have different lengths. Patch by +Mikhail Efimov. + +.. + +.. date: 2025-10-24-14-29-12 +.. gh-issue: 133467 +.. nonce: A5d6TM +.. section: Core and Builtins + +Fix race when updating :attr:`!type.__bases__` that could allow a read of +:attr:`!type.__base__` to observe an inconsistent value on the free threaded +build. + +.. + +.. date: 2025-10-23-16-05-50 +.. gh-issue: 140471 +.. nonce: Ax_aXn +.. section: Core and Builtins + +Fix potential buffer overflow in :class:`ast.AST` node initialization when +encountering malformed :attr:`~ast.AST._fields` containing non-:class:`str`. + +.. + +.. date: 2025-10-22-23-26-37 +.. gh-issue: 140443 +.. nonce: wT5i1A +.. section: Library + +The logarithm functions (such as :func:`math.log10` and :func:`math.log`) +may now produce slightly different results for extremely large integers that +cannot be converted to floats without overflow. These results are generally +more accurate, with reduced worst-case error and a tighter overall error +distribution. + +.. + +.. date: 2025-10-22-17-22-22 +.. gh-issue: 140431 +.. nonce: m8D_A- +.. section: Core and Builtins + +Fix a crash in Python's :term:`garbage collector <garbage collection>` due +to partially initialized :term:`coroutine` objects when coroutine origin +tracking depth is enabled (:func:`sys.set_coroutine_origin_tracking_depth`). + +.. + +.. date: 2025-10-22-12-48-05 +.. gh-issue: 140476 +.. nonce: F3-d1P +.. section: Core and Builtins + +Optimize :c:func:`PySet_Add` for :class:`frozenset` in :term:`free threaded +<free threading>` build. + +.. + +.. date: 2025-10-22-11-30-16 +.. gh-issue: 135904 +.. nonce: 3WE5oW +.. section: Core and Builtins + +Add special labels to the assembly created during stencil creation to +support relocations that the native object file format does not support. +Specifically, 19 bit branches for AArch64 in Mach-O object files. + +.. + +.. date: 2025-10-21-09-20-03 +.. gh-issue: 140398 +.. nonce: SoABwJ +.. section: Library + +Fix memory leaks in :mod:`readline` functions +:func:`~readline.read_init_file`, :func:`~readline.read_history_file`, +:func:`~readline.write_history_file`, and +:func:`~readline.append_history_file` when :c:func:`PySys_Audit` fails. + +.. + +.. date: 2025-10-21-06-51-50 +.. gh-issue: 140406 +.. nonce: 0gJs8M +.. section: Core and Builtins + +Fix memory leak when an object's :meth:`~object.__hash__` method returns an +object that isn't an :class:`int`. + +.. + +.. date: 2025-10-20-11-24-36 +.. gh-issue: 140358 +.. nonce: UQuKdV +.. section: Core and Builtins + +Restore elapsed time and unreachable object count in GC debug output. These +were inadvertently removed during a refactor of ``gc.c``. The debug log now +again reports elapsed collection time and the number of unreachable objects. +Contributed by Pål Grønås Drange. + +.. + +.. date: 2025-10-19-10-32-28 +.. gh-issue: 136895 +.. nonce: HfsEh0 +.. section: Core and Builtins + +Update JIT compilation to use LLVM 20 at build time. + +.. + +.. date: 2025-10-18-21-50-44 +.. gh-issue: 139109 +.. nonce: 9QQOzN +.. section: Core and Builtins + +A new tracing frontend for the JIT compiler has been implemented. Patch by +Ken Jin. Design for CPython by Ken Jin, Mark Shannon and Brandt Bucher. + +.. + +.. date: 2025-10-18-21-29-45 +.. gh-issue: 140306 +.. nonce: xS5CcS +.. section: Core and Builtins + +Fix memory leaks in cross-interpreter channel operations and shared +namespace handling. + +.. + +.. date: 2025-10-18-19-52-20 +.. gh-issue: 116738 +.. nonce: NLJW0L +.. section: Core and Builtins + +Make _suggestions module thread-safe on the :term:`free threaded <free +threading>` build. + +.. + +.. date: 2025-10-18-18-08-36 +.. gh-issue: 140301 +.. nonce: m-2HxC +.. section: Core and Builtins + +Fix memory leak of ``PyConfig`` in subinterpreters. + +.. + +.. date: 2025-10-17-20-23-19 +.. gh-issue: 140257 +.. nonce: 8Txmem +.. section: Core and Builtins + +Fix data race between interpreter_clear() and take_gil() on eval_breaker +during finalization with daemon threads. + +.. + +.. date: 2025-10-17-18-03-12 +.. gh-issue: 139951 +.. nonce: IdwM2O +.. section: Core and Builtins + +Fixes a regression in GC performance for a growing heap composed mostly of +small tuples. + +* Counts number of actually tracked objects, instead of trackable objects. + This ensures that untracking tuples has the desired effect of reducing GC overhead. +* Does not track most untrackable tuples during creation. + This prevents large numbers of small tuples causing excessive GCs. + +.. + +.. date: 2025-10-17-14-38-10 +.. gh-issue: 140253 +.. nonce: gCqFaL +.. section: Core and Builtins + +Wrong placement of a double-star pattern inside a mapping pattern now throws +a specialized syntax error. Contributed by Bartosz Sławecki in :gh:`140253`. + +.. + +.. date: 2025-10-16-21-47-00 +.. gh-issue: 140104 +.. nonce: A8SQIm +.. section: Core and Builtins + +Fix a bug with exception handling in the JIT. Patch by Ken Jin. Bug reported +by Daniel Diniz. + +.. + +.. date: 2025-10-15-17-12-32 +.. gh-issue: 140149 +.. nonce: cy1m3d +.. section: Core and Builtins + +Speed up parsing bytes literals concatenation by using PyBytesWriter API and +a single memory allocation (about 3x faster). + +.. + +.. date: 2025-10-15-00-21-40 +.. gh-issue: 140061 +.. nonce: J0XeDV +.. section: Core and Builtins + +Fixing the checking of whether an object is uniquely referenced to ensure +free-threaded compatibility. Patch by Sergey Miryanov. + +.. + +.. date: 2025-10-14-20-18-31 +.. gh-issue: 140080 +.. nonce: 8ROjxW +.. section: Core and Builtins + +Fix hang during finalization when attempting to call :mod:`atexit` handlers +under no memory. + +.. + +.. date: 2025-10-14-18-24-16 +.. gh-issue: 139871 +.. nonce: SWtuUz +.. section: Core and Builtins + +Update :class:`bytearray` to use a :class:`bytes` under the hood as its +buffer and add :meth:`bytearray.take_bytes` to take it out. + +.. + +.. date: 2025-10-14-17-07-37 +.. gh-issue: 140067 +.. nonce: ID2gOm +.. section: Core and Builtins + +Fix memory leak in sub-interpreter creation. + +.. + +.. date: 2025-10-13-13-54-19 +.. gh-issue: 139914 +.. nonce: M-y_3E +.. section: Core and Builtins + +Restore support for HP PA-RISC, which has an upwards-growing stack. + +.. + +.. date: 2025-10-12-01-12-12 +.. gh-issue: 139817 +.. nonce: PAn-8Z +.. section: Core and Builtins + +Attribute ``__qualname__`` is added to :class:`typing.TypeAliasType`. Patch +by Mikhail Efimov. + +.. + +.. date: 2025-10-06-14-19-47 +.. gh-issue: 135801 +.. nonce: OhxEZS +.. section: Core and Builtins + +Many functions related to compiling or parsing Python code, such as +:func:`compile`, :func:`ast.parse`, :func:`symtable.symtable`, and +:func:`importlib.abc.InspectLoader.source_to_code` now allow to specify the +module name. It is needed to unambiguous :ref:`filter <warning-filter>` +syntax warnings by module name. + +.. + +.. date: 2025-10-06-10-03-37 +.. gh-issue: 139640 +.. nonce: gY5oTb2 +.. section: Core and Builtins + +:func:`ast.parse` no longer emits syntax warnings for +``return``/``break``/``continue`` in ``finally`` (see :pep:`765`) -- they +are only emitted during compilation. + +.. + +.. date: 2025-10-06-10-03-37 +.. gh-issue: 139640 +.. nonce: gY5oTb +.. section: Core and Builtins + +Fix swallowing some syntax warnings in different modules if they +accidentally have the same message and are emitted from the same line. Fix +duplicated warnings in the ``finally`` block. + +.. + +.. date: 2025-10-03-17-51-43 +.. gh-issue: 139475 +.. nonce: _684ED +.. section: Core and Builtins + +Changes in stackref debugging mode when ``Py_STACKREF_DEBUG`` is set. We use +the same pattern of refcounting for stackrefs as in production build. + +.. + +.. date: 2025-09-23-21-01-12 +.. gh-issue: 139269 +.. nonce: 1rIaxy +.. section: Core and Builtins + +Fix undefined behavior when using unaligned store in JIT's ``patch_*`` +functions. + +.. + +.. date: 2025-09-15-13-06-11 +.. gh-issue: 138944 +.. nonce: PeCgLb +.. section: Core and Builtins + +Fix :exc:`SyntaxError` message when invalid syntax appears on the same line +as a valid ``import ... as ...`` or ``from ... import ... as ...`` +statement. Patch by Brian Schubert. + +.. + +.. date: 2025-09-13-01-23-25 +.. gh-issue: 138857 +.. nonce: YQ5gdc +.. section: Core and Builtins + +Improve :exc:`SyntaxError` message for ``case`` keyword placed outside +:keyword:`match` body. + +.. + +.. date: 2025-07-29-17-51-14 +.. gh-issue: 131253 +.. nonce: GpRjWy +.. section: Core and Builtins + +Support the ``--enable-pystats`` build option for the free-threaded build. + +.. + +.. date: 2025-07-08-00-41-46 +.. gh-issue: 136327 +.. nonce: 7AiTb_ +.. section: Core and Builtins + +Errors when calling functions with invalid values after ``*`` and ``**`` now +do not include the function name. Patch by Ilia Solin. + +.. + +.. date: 2025-06-24-13-12-58 +.. gh-issue: 134786 +.. nonce: MF0VVk +.. section: Core and Builtins + +If :c:macro:`Py_TPFLAGS_MANAGED_DICT` and +:c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` are used, then +:c:macro:`Py_TPFLAGS_HAVE_GC` must be used as well. + +.. + +.. date: 2025-11-10-11-26-26 +.. gh-issue: 141341 +.. nonce: OsO6-y +.. section: C API + +On Windows, rename the ``COMPILER`` macro to ``_Py_COMPILER`` to avoid name +conflicts. Patch by Victor Stinner. + +.. + +.. date: 2025-11-08-10-51-50 +.. gh-issue: 116146 +.. nonce: pCmx6L +.. section: C API + +Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C-API for creating a +module from a *spec* and *initfunc*. Patch by Itamar Oren. + +.. + +.. date: 2025-11-06-06-28-14 +.. gh-issue: 141042 +.. nonce: brOioJ +.. section: C API + +Make qNaN in :c:func:`PyFloat_Pack2` and :c:func:`PyFloat_Pack4`, if while +conversion to a narrower precision floating-point format --- the remaining +after truncation payload will be zero. Patch by Sergey B Kirpichev. + +.. + +.. date: 2025-11-05-05-45-49 +.. gh-issue: 141004 +.. nonce: N9Ooh9 +.. section: C API + +:c:macro:`!Py_MATH_El` and :c:macro:`!Py_MATH_PIl` are deprecated. + +.. + +.. date: 2025-11-05-04-38-16 +.. gh-issue: 141004 +.. nonce: rJL43P +.. section: C API + +The :c:macro:`!Py_INFINITY` macro is :term:`soft deprecated`. + +.. + +.. date: 2025-10-26-16-45-28 +.. gh-issue: 140556 +.. nonce: s__Dae +.. section: C API + +:pep:`793`: Add a new entry point for C extension modules, +``PyModExport_<modulename>``. + +.. + +.. date: 2025-10-26-16-45-06 +.. gh-issue: 140487 +.. nonce: fGOqss +.. section: C API + +Fix :c:macro:`Py_RETURN_NOTIMPLEMENTED` in limited C API 3.11 and older: +don't treat ``Py_NotImplemented`` as immortal. Patch by Victor Stinner. + +.. + +.. date: 2025-10-15-15-59-59 +.. gh-issue: 140153 +.. nonce: BO7sH4 +.. section: C API + +Fix :c:func:`Py_REFCNT` definition on limited C API 3.11-3.13. Patch by +Victor Stinner. + +.. + +.. date: 2025-10-06-22-17-47 +.. gh-issue: 139653 +.. nonce: 6-1MOd +.. section: C API + +Add :c:func:`PyUnstable_ThreadState_SetStackProtection` and +:c:func:`PyUnstable_ThreadState_ResetStackProtection` functions to set the +stack protection base address and stack protection size of a Python thread +state. Patch by Victor Stinner. + +.. + +.. date: 2025-10-31-13-20-16 +.. gh-issue: 140454 +.. nonce: gF6dCe +.. section: Build + +When building the JIT, match the jit_stencils filename expectations in +Makefile with the generator script. This avoid needless JIT recompilation +during ``make install``. + +.. + +.. date: 2025-10-29-12-30-38 +.. gh-issue: 140768 +.. nonce: ITYrzw +.. section: Build + +Warn when the WASI SDK version doesn't match what's supported. + +.. + +.. date: 2025-10-25-08-07-06 +.. gh-issue: 140513 +.. nonce: 6OhLTs +.. section: Build + +Generate a clear compilation error when ``_Py_TAIL_CALL_INTERP`` is enabled +but either ``preserve_none`` or ``musttail`` is not supported. + +.. + +.. date: 2025-10-22-12-44-07 +.. gh-issue: 140475 +.. nonce: OhzQbR +.. section: Build + +Support WASI SDK 25. + +.. + +.. date: 2025-10-17-11-33-45 +.. gh-issue: 140239 +.. nonce: _k-GgW +.. section: Build + +Check ``statx`` availability only on Linux (including Android). + +.. + +.. date: 2025-10-16-11-30-53 +.. gh-issue: 140189 +.. nonce: YCrUyt +.. section: Build + +iOS builds were added to CI. + +.. + +.. date: 2025-08-10-22-28-06 +.. gh-issue: 137618 +.. nonce: FdNvIE +.. section: Build + +``PYTHON_FOR_REGEN`` now requires Python 3.10 to Python 3.15. Patch by Adam +Turner. diff --git a/Misc/NEWS.d/3.15.0a3.rst b/Misc/NEWS.d/3.15.0a3.rst new file mode 100644 index 00000000000..7d52b3d0c80 --- /dev/null +++ b/Misc/NEWS.d/3.15.0a3.rst @@ -0,0 +1,1605 @@ +.. date: 2025-11-18-13-55-47 +.. gh-issue: 141692 +.. nonce: tud9if +.. release date: 2025-12-16 +.. section: Tools/Demos + +Each slice of an iOS XCframework now contains a ``lib`` folder that contains +a symlink to the libpython dylib. This allows binary modules to be compiled +for iOS using dynamic libreary linking, rather than Framework linking. + +.. + +.. date: 2025-10-27-15-53-47 +.. gh-issue: 140381 +.. nonce: N5o3pa +.. section: Tests + +Fix flaky test_profiling tests on i686 and s390x architectures by increasing +slow_fibonacci call frequency from every 5th iteration to every 2nd +iteration. + +.. + +.. date: 2025-10-16-15-08-58 +.. gh-issue: 140210 +.. nonce: P9vUP8 +.. section: Tests + +Make ``test_sysconfig.test_parse_makefile_renamed_vars`` less fragile by +clearing the environment variables before parsing the Makefile. + +.. + +.. date: 2025-12-01-09-36-45 +.. gh-issue: 142145 +.. nonce: tcAUhg +.. section: Security + +Remove quadratic behavior in ``xml.minidom`` node ID cache clearing. + +.. + +.. date: 2025-11-13-22-31-56 +.. gh-issue: 42400 +.. nonce: pqB5Kq +.. section: Security + +Fix buffer overflow in ``_Py_wrealpath()`` for paths exceeding +``MAXPATHLEN`` bytes by using dynamic memory allocation instead of +fixed-size buffer. Patch by Shamil Abdulaev. + +.. + +.. date: 2024-05-23-11-47-48 +.. gh-issue: 119451 +.. nonce: qkJe9- +.. section: Security + +Fix a potential memory denial of service in the :mod:`http.client` module. +When connecting to a malicious server, it could cause an arbitrary amount of +memory to be allocated. This could have led to symptoms including a +:exc:`MemoryError`, swapping, out of memory (OOM) killed processes or +containers, or even system crashes. + +.. + +.. date: 2024-05-21-22-11-31 +.. gh-issue: 119342 +.. nonce: BTFj4Z +.. section: Security + +Fix a potential memory denial of service in the :mod:`plistlib` module. When +reading a Plist file received from untrusted source, it could cause an +arbitrary amount of memory to be allocated. This could have led to symptoms +including a :exc:`MemoryError`, swapping, out of memory (OOM) killed +processes or containers, or even system crashes. + +.. + +.. date: 2025-12-16-11-55-55 +.. gh-issue: 142754 +.. nonce: xuCrt3 +.. section: Library + +Add the *ownerDocument* attribute to :mod:`xml.dom.minidom` elements and +attributes created by directly instantiating the ``Element`` or ``Attr`` +class. Note that this way of creating nodes is not supported; creator +functions like :py:meth:`xml.dom.Document.documentElement` should be used +instead. + +.. + +.. date: 2025-12-14-18-30-48 +.. gh-issue: 142594 +.. nonce: belDmD +.. section: Library + +Fix crash in ``TextIOWrapper.close()`` when the underlying buffer's +``closed`` property calls :meth:`~io.TextIOBase.detach`. + +.. + +.. date: 2025-12-13-21-19-28 +.. gh-issue: 76007 +.. nonce: 6fs_gT +.. section: Library + +Deprecate ``__version__`` from :mod:`ctypes`. Patch by Hugo van Kemenade. + +.. + +.. date: 2025-12-13-19-17-01 +.. gh-issue: 76007 +.. nonce: -OSQU3 +.. section: Library + +Deprecate ``__version__`` from :mod:`wsgiref.simple_server`. Patch by Hugo +van Kemenade. + +.. + +.. date: 2025-12-13-06-17-44 +.. gh-issue: 142651 +.. nonce: ZRtBu4 +.. section: Library + +:mod:`unittest.mock`: fix a thread safety issue where :attr:`Mock.call_count +<unittest.mock.Mock.call_count>` may return inaccurate values when the mock +is called concurrently from multiple threads. + +.. + +.. date: 2025-12-13-00-09-09 +.. gh-issue: 76007 +.. nonce: Xg1xCO +.. section: Library + +Deprecate ``__version__`` from :mod:`http.server`. Patch by Hugo van +Kemenade. + +.. + +.. date: 2025-12-12-15-14-03 +.. gh-issue: 138122 +.. nonce: m3EF9E +.. section: Library + +Add ``--subprocesses`` flag to :mod:`profiling.sampling` CLI to +automatically profile subprocesses spawned by the target. When enabled, the +profiler monitors for new Python subprocesses and profiles each one +separately, writing results to individual output files. This is useful for +profiling applications that use :mod:`multiprocessing`, +:class:`~concurrent.futures.ProcessPoolExecutor`, or other subprocess-based +parallelism. Patch by Pablo Galindo. + +.. + +.. date: 2025-12-12-02-56-26 +.. gh-issue: 142595 +.. nonce: wHvTqq +.. section: Library + +Added type check during initialization of the :mod:`decimal` module to +prevent a crash in case of broken stdlib. Patch by Sergey B Kirpichev. + +.. + +.. date: 2025-12-11-09-03-07 +.. gh-issue: 142556 +.. nonce: RuiBte +.. section: Library + +Fix crash when a task gets re-registered during finalization in +:mod:`asyncio`. Patch by Kumar Aditya. + +.. + +.. date: 2025-12-11-04-18-49 +.. gh-issue: 138122 +.. nonce: m3EF9E +.. section: Library + +Add ``--mode=exception`` to the sampling profiler to capture samples only +from threads with an active exception, useful for analyzing exception +handling overhead. Patch by Pablo Galindo. + +.. + +.. date: 2025-12-10-21-19-10 +.. gh-issue: 142539 +.. nonce: _8Vzr0 +.. section: Library + +:mod:`traceback`: Fix location of carets in :exc:`SyntaxError`\s when the +source contains wide characters. + +.. + +.. date: 2025-12-10-11-20-05 +.. gh-issue: 123241 +.. nonce: oYg2n7 +.. section: Library + +Avoid reference count operations in garbage collection of :mod:`ctypes` +objects. + +.. + +.. date: 2025-12-10-11-02-53 +.. gh-issue: 142451 +.. nonce: eCLvhG +.. section: Library + +:mod:`hmac`: correctly copy :class:`~hmac.HMAC` attributes for objects +copied through :meth:`HMAC.copy() <hmac.HMAC.copy>`. Patch by Bénédikt Tran. + +.. + +.. date: 2025-12-09-22-11-59 +.. gh-issue: 138122 +.. nonce: CsoBEo +.. section: Library + +The ``profiling.sampling`` flamegraph profiler now supports inverted +flamegraph view that aggregates all leaf nodes. In a standard flamegraph, if +a hot function is called from multiple locations, it appears multiple times +as separate leaf nodes. In the inverted flamegraph, all occurrences of the +same leaf function are merged into a single aggregated node at the root, +showing the total hotness of that function in one place. The children of +each aggregated node represent its callers, making it easier to identify +which functions consume the most CPU time and where they are called from. + +.. + +.. date: 2025-12-09-14-40-45 +.. gh-issue: 112527 +.. nonce: Tvf5Zk +.. section: Library + +The help text for required options in :mod:`argparse` no longer extended +with " (default: None)". + +.. + +.. date: 2025-12-08-18-12-44 +.. gh-issue: 142438 +.. nonce: UF_0nd +.. section: Library + +Fixed a possible leaked GIL in _PySSL_keylog_callback. + +.. + +.. date: 2025-12-07-23-21-13 +.. gh-issue: 138122 +.. nonce: m3EF9E +.. section: Library + +Add bytecode-level instruction profiling to the sampling profiler via the +new ``--opcodes`` flag. When enabled, the profiler captures which bytecode +opcode is executing at each sample, including Python 3.11+ adaptive +specializations, and visualizes this data in the heatmap, flamegraph, gecko, +and live output formats. Patch by Pablo Galindo + +.. + +.. date: 2025-12-07-22-13-28 +.. gh-issue: 142389 +.. nonce: J9v904 +.. section: Library + +Add backtick markup support in :mod:`argparse` description and epilog text +to highlight inline code when color output is enabled. + +.. + +.. date: 2025-12-07-17-30-05 +.. gh-issue: 142346 +.. nonce: okcAAp +.. section: Library + +Fix usage formatting for mutually exclusive groups in :mod:`argparse` when +they are preceded by positional arguments or followed or intermixed with +other optional arguments. + +.. + +.. date: 2025-12-07-13-37-18 +.. gh-issue: 142374 +.. nonce: m3EF9E +.. section: Library + +Fix cumulative percentage calculation for recursive functions in the new +sampling profiler. When profiling recursive functions, cumulative statistics +(cumul%, cumtime) could exceed 100% because each recursive frame in a stack +was counted separately. For example, a function recursing 500 times in every +sample would show 50000% cumulative presence. The fix deduplicates locations +within each sample so cumulative stats correctly represent "percentage of +samples where this function was on the stack". Patch by Pablo Galindo. + +.. + +.. date: 2025-12-07-02-36-24 +.. gh-issue: 142315 +.. nonce: 02o5E_ +.. section: Library + +Pdb can now run scripts from anonymous pipes used in process substitution. +Patch by Bartosz Sławecki. + +.. + +.. date: 2025-12-06-16-45-34 +.. gh-issue: 64532 +.. nonce: 4OXZpF +.. section: Library + +Subparser help now includes required optional arguments from the parent +parser in the usage, making it clearer what arguments are needed to run a +subcommand. Patch by Savannah Ostrowski. + +.. + +.. date: 2025-12-06-13-19-43 +.. gh-issue: 142207 +.. nonce: x_X9oH +.. section: Library + +Fix: profiling.sampling may cause assertion ``!(has_gil && gil_requested)`` + +.. + +.. date: 2025-12-06-13-02-13 +.. gh-issue: 142332 +.. nonce: PNvXCV +.. section: Library + +Fix usage formatting for positional arguments in mutually exclusive groups +in :mod:`argparse`. in :mod:`argparse`. + +.. + +.. date: 2025-12-05-18-26-50 +.. gh-issue: 142282 +.. nonce: g6RQUN +.. section: Library + +Fix :func:`winreg.QueryValueEx` to not accidentally read garbage buffer +under race condition. + +.. + +.. date: 2025-12-05-18-25-29 +.. gh-issue: 142318 +.. nonce: EzcQ3N +.. section: Library + +Fix typing ``'q'`` at the help of the interactive tachyon profiler exiting +the profiler. + +.. + +.. date: 2025-12-05-16-39-17 +.. gh-issue: 75949 +.. nonce: pHxW98 +.. section: Library + +Fix :mod:`argparse` to preserve ``|`` separators in mutually exclusive +groups when the usage line wraps due to length. + +.. + +.. date: 2025-12-04-23-26-12 +.. gh-issue: 142267 +.. nonce: yOM6fP +.. section: Library + +Improve :mod:`argparse` performance by caching the formatter used for +argument validation. + +.. + +.. date: 2025-12-04-23-24-24 +.. gh-issue: 139862 +.. nonce: NBfsD4 +.. section: Library + +Remove ``color`` parameter from :class:`!argparse.HelpFormatter` +constructor. Color is controlled by :class:`~argparse.ArgumentParser`. + +.. + +.. date: 2025-12-04-09-22-31 +.. gh-issue: 68552 +.. nonce: I_v-xB +.. section: Library + +``MisplacedEnvelopeHeaderDefect`` and ``Missing header name`` defects are +now correctly passed to the ``handle_defect`` method of ``policy`` in +:class:`~email.parser.FeedParser`. + +.. + +.. date: 2025-12-03-09-36-29 +.. gh-issue: 142206 +.. nonce: ilwegH +.. section: Library + +The resource tracker in the :mod:`multiprocessing` module can now understand +messages from older versions of itself. This avoids issues with upgrading +Python while it is running. (Note that such 'in-place' upgrades are not +tested.) + +.. + +.. date: 2025-12-03-06-12-39 +.. gh-issue: 142214 +.. nonce: appYNZ +.. section: Library + +Fix two regressions in :mod:`dataclasses` in Python 3.14.1 related to +annotations. + +* An exception is no longer raised if ``slots=True`` is used and the + ``__init__`` method does not have an ``__annotate__`` attribute + (likely because ``init=False`` was used). + +* An exception is no longer raised if annotations are requested on the + ``__init__`` method and one of the fields is not present in the class + annotations. This can occur in certain dynamic scenarios. + +Patch by Jelle Zijlstra. + +.. + +.. date: 2025-12-02-14-52-51 +.. gh-issue: 142203 +.. nonce: ofWOvV +.. section: Library + +Remove the *debug_override* parameter from +:func:`importlib.util.cache_from_source` which has been deprecated since +Python 3.5. + +.. + +.. date: 2025-12-01-14-43-58 +.. gh-issue: 138122 +.. nonce: nRm3ic +.. section: Library + +The ``_remote_debugging`` module now implements frame caching in the +``RemoteUnwinder`` class to reduce memory reads when profiling remote +processes. When ``cache_frames=True``, unchanged portions of the call stack +are reused from previous samples, significantly improving profiling +performance for deep call stacks. + +.. + +.. date: 2025-12-01-10-03-08 +.. gh-issue: 116738 +.. nonce: 972YsG +.. section: Library + +Fix :mod:`cmath` data race when initializing trigonometric tables with +subinterpreters. + +.. + +.. date: 2025-11-30-04-28-30 +.. gh-issue: 141982 +.. nonce: pxZct9 +.. section: Library + +Allow :mod:`pdb` to set breakpoints on async functions with function names. + +.. + +.. date: 2025-11-29-04-20-44 +.. gh-issue: 74389 +.. nonce: pW3URj +.. section: Library + +When the stdin being used by a :class:`subprocess.Popen` instance is closed, +this is now ignored in :meth:`subprocess.Popen.communicate` instead of +leaving the class in an inconsistent state. + +.. + +.. date: 2025-11-29-03-02-45 +.. gh-issue: 87512 +.. nonce: bn4xbm +.. section: Library + +Fix :func:`subprocess.Popen.communicate` timeout handling on Windows when +writing large input. Previously, the timeout was ignored during stdin +writing, causing the method to block indefinitely if the child process did +not consume input quickly. The stdin write is now performed in a background +thread, allowing the timeout to be properly enforced. + +.. + +.. date: 2025-11-28-08-25-19 +.. gh-issue: 141939 +.. nonce: BXPnFj +.. section: Library + +Add color to all interpolated values in :mod:`argparse` help, like +``%(default)s`` or ``%(choices)s``. Patch by Alex Prengère. + +.. + +.. date: 2025-11-27-20-16-38 +.. gh-issue: 141473 +.. nonce: Wq4xVN +.. section: Library + +When :meth:`subprocess.Popen.communicate` was called with *input* and a +*timeout* and is called for a second time after a +:exc:`~subprocess.TimeoutExpired` exception before the process has died, it +should no longer hang. + +.. + +.. date: 2025-11-27-11-39-50 +.. gh-issue: 141999 +.. nonce: _FKGlu +.. section: Library + +Correctly allow :exc:`KeyboardInterrupt` to stop the process when using +:mod:`!profiling.sampling`. + +.. + +.. date: 2025-11-27-10-49-13 +.. gh-issue: 142006 +.. nonce: nzJDG5 +.. section: Library + +Fix a bug in the :mod:`email.policy.default` folding algorithm which +incorrectly resulted in a doubled newline when a line ending at exactly +max_line_length was followed by an unfoldable token. + +.. + +.. date: 2025-11-26-14-20-10 +.. gh-issue: 141968 +.. nonce: W139Pv +.. section: Library + +Remove data copy from :mod:`re` compilation of regexes with large charsets +by using :meth:`bytearray.take_bytes`. + +.. + +.. date: 2025-11-25-23-35-07 +.. gh-issue: 141968 +.. nonce: b3Gscp +.. section: Library + +Remove data copy from :mod:`encodings.idna` :meth:`~codecs.Codec.encode` and +:meth:`~codecs.IncrementalEncoder.encode` by using +:meth:`bytearray.take_bytes`. + +.. + +.. date: 2025-11-25-23-29-08 +.. gh-issue: 141968 +.. nonce: 0JnjXf +.. section: Library + +Remove data copy from :mod:`codecs` ``punycode`` encoding by using +:meth:`bytearray.take_bytes`. + +.. + +.. date: 2025-11-25-23-22-46 +.. gh-issue: 141968 +.. nonce: R1sHnJ +.. section: Library + +Remove data copy from :func:`wave.Wave_read.readframes` and +:func:`wave.Wave_write.writeframes` by using :meth:`bytearray.take_bytes`. + +.. + +.. date: 2025-11-25-22-54-07 +.. gh-issue: 141968 +.. nonce: vg3AMJ +.. section: Library + +Remove a data copy from :func:`base64.b32decode` and +:func:`base64.b32encode` by using :meth:`bytearray.take_bytes`. + +.. + +.. date: 2025-11-25-16-00-29 +.. gh-issue: 59000 +.. nonce: YtOyJy +.. section: Library + +Fix :mod:`pdb` breakpoint resolution for class methods when the module +defining the class is not imported. + +.. + +.. date: 2025-11-25-13-13-34 +.. gh-issue: 116738 +.. nonce: MnZRdV +.. section: Library + +Fix thread safety issue with :mod:`re` scanner objects in free-threaded +builds. + +.. + +.. date: 2025-11-24-14-05-52 +.. gh-issue: 138122 +.. nonce: 2bbGA8 +.. section: Library + +The ``profiling.sampling`` flamegraph profiler now displays thread status +statistics showing the percentage of time threads spend holding the GIL, +running without the GIL, waiting for the GIL, and performing garbage +collection. These statistics help identify GIL contention and thread +behavior patterns. When filtering by thread, the display shows per-thread +metrics. + +.. + +.. date: 2025-11-24-06-44-45 +.. gh-issue: 141781 +.. nonce: MsK27r +.. section: Library + +Fixed an issue where pdb.line_prefix assignment was ignored if assigned +after the module was imported. + +.. + +.. date: 2025-11-22-16-33-48 +.. gh-issue: 141863 +.. nonce: 4PLhnv +.. section: Library + +Update :ref:`asyncio-streams` to use :meth:`bytearray.take_bytes` for a over +10% performance improvement on pyperformance asyncio_tcp benchmark. + +.. + +.. date: 2025-11-21-21-14-10 +.. gh-issue: 141817 +.. nonce: _v5LdB +.. section: Library + +Add :data:`!socket.IPV6_HDRINCL` constant. + +.. + +.. date: 2025-11-18-15-48-13 +.. gh-issue: 105836 +.. nonce: sbUw24 +.. section: Library + +Fix :meth:`asyncio.run_coroutine_threadsafe` leaving underlying cancelled +asyncio task running. + +.. + +.. date: 2025-11-18-14-39-31 +.. gh-issue: 141570 +.. nonce: q3n984 +.. section: Library + +Support :term:`file-like object` raising :exc:`OSError` from +:meth:`~io.IOBase.fileno` in color detection (``_colorize.can_colorize()``). +This can occur when ``sys.stdout`` is redirected. + +.. + +.. date: 2025-11-17-21-41-58 +.. gh-issue: 141679 +.. nonce: fs7zLJ +.. section: Library + +Add colour to defaults in :mod:`argparse` help. Patch by Hugo van Kemenade. + +.. + +.. date: 2025-11-17-16-53-49 +.. gh-issue: 141686 +.. nonce: V-xaoI +.. section: Library + +Break reference cycles created by each call to :func:`json.dump` or +:meth:`json.JSONEncoder.iterencode`. + +.. + +.. date: 2025-11-17-08-16-30 +.. gh-issue: 141659 +.. nonce: QNi9Aj +.. section: Library + +Fix bad file descriptor errors from ``_posixsubprocess`` on AIX. + +.. + +.. date: 2025-11-17-00-53-51 +.. gh-issue: 141645 +.. nonce: TC3TL3 +.. section: Library + +Add a new ``--live`` mode to the tachyon profiler in +:mod:`!profiling.sampling` module. This mode consist of a live TUI that +displays real-time profiling statistics as the target application runs, +similar to ``top``. Patch by Pablo Galindo + +.. + +.. date: 2025-11-16-06-08-46 +.. gh-issue: 141615 +.. nonce: --6EK3 +.. section: Library + +Check ``stdin`` instead of ``stdout`` for ``use_rawinput`` in :mod:`pdb`. + +.. + +.. date: 2025-11-16-04-40-06 +.. gh-issue: 69113 +.. nonce: Xy7Fmn +.. section: Library + +Fix :mod:`doctest` to correctly report line numbers for doctests in +``__test__`` dictionary when formatted as triple-quoted strings by finding +unique lines in the string and matching them in the source file. + +.. + +.. date: 2025-11-15-14-58-12 +.. gh-issue: 141600 +.. nonce: XY2BXg +.. section: Library + +Fix musl version detection on Void Linux. + +.. + +.. date: 2025-11-15-11-10-16 +.. gh-issue: 48752 +.. nonce: aB3xYz +.. section: Library + +Add :func:`readline.get_pre_input_hook` function to retrieve the current +pre-input hook. This allows applications to save and restore the hook +without overwriting user settings. Patch by Sanyam Khurana. + +.. + +.. date: 2025-11-14-18-00-41 +.. gh-issue: 141565 +.. nonce: Ap2bhJ +.. section: Library + +Add async-aware profiling to the Tachyon sampling profiler. The profiler now +reconstructs and displays async task hierarchies in flamegraphs, making the +output more actionable for users. Patch by Savannah Ostrowski and Pablo +Galindo Salgado. + +.. + +.. date: 2025-11-13-13-11-02 +.. gh-issue: 60107 +.. nonce: LZq3QF +.. section: Library + +Remove a copy from :meth:`io.RawIOBase.read`. If the underlying I/O class +keeps a reference to the mutable memory, raise a :exc:`BufferError`. + +.. + +.. date: 2025-11-10-00-14-20 +.. gh-issue: 116738 +.. nonce: IxliC_ +.. section: Library + +Make csv module thread-safe on the :term:`free threaded <free threading>` +build. + +.. + +.. date: 2025-11-03-17-13-00 +.. gh-issue: 140911 +.. nonce: 7KFvSQ +.. section: Library + +:mod:`collections`: Ensure that the methods ``UserString.rindex()`` and +``UserString.index()`` accept :class:`collections.UserString` instances as +the sub argument. + +.. + +.. date: 2025-11-02-10-44-23 +.. gh-issue: 140875 +.. nonce: wt6B37 +.. section: Library + +Fix handling of unclosed character references (named and numerical) followed +by the end of file in :class:`html.parser.HTMLParser` with +``convert_charrefs=False``. + +.. + +.. date: 2025-10-27-17-00-11 +.. gh-issue: 140677 +.. nonce: hM9pTq +.. section: Library + +Add heatmap visualization mode to the Tachyon sampling profiler. The new +``--heatmap`` output format provides a line-by-line view showing execution +intensity with color-coded samples, inline statistics, and interactive call +graph navigation between callers and callees. + +.. + +.. date: 2025-10-23-06-38-35 +.. gh-issue: 139946 +.. nonce: HZa5hu +.. section: Library + +Distinguish stdout and stderr when colorizing output in argparse module. + +.. + +.. date: 2025-10-12-12-43-56 +.. gh-issue: 76007 +.. nonce: PyGM14 +.. section: Library + +:mod:`pydoc`: Fix :exc:`DeprecationWarning` being raised when generating doc +for :term:`stdlib` modules. + +.. + +.. date: 2025-10-09-15-46-18 +.. gh-issue: 139686 +.. nonce: XwIZB2 +.. section: Library + +Make importlib.reload no-op for lazy modules. + +.. + +.. date: 2025-09-09-13-00-42 +.. gh-issue: 138697 +.. nonce: QVwJw_ +.. section: Library + +Fix inferring *dest* from a single-dash long option in :mod:`argparse`. If a +short option and a single-dash long option are passed to +:meth:`!add_argument`, *dest* is now inferred from the single-dash long +option. + +.. + +.. date: 2025-09-09-10-13-24 +.. gh-issue: 138525 +.. nonce: hDTaAM +.. section: Library + +Add support for single-dash long options and alternate prefix characters in +:class:`argparse.BooleanOptionalAction`. + +.. + +.. date: 2025-07-29-11-37-22 +.. gh-issue: 79986 +.. nonce: fnJbE_ +.. section: Library + +Add parsing for ``References`` and ``In-Reply-To`` headers to the +:mod:`email` library that parses the header content as lists of message id +tokens. This prevents them from being folded incorrectly. + +.. + +.. date: 2025-07-10-18-40-11 +.. gh-issue: 135559 +.. nonce: BMDtYn +.. section: Library + +Flag: a ``dir()`` on a ``Flag`` enumeration now shows non-canonical members. +(i.e. aliases). + +.. + +.. date: 2025-05-30-18-37-44 +.. gh-issue: 134453 +.. nonce: kxkA-o +.. section: Library + +Fixed :func:`subprocess.Popen.communicate` ``input=`` handling of +:class:`memoryview` instances that were non-byte shaped on POSIX platforms. +Those are now properly cast to a byte shaped view instead of truncating the +input. Windows platforms did not have this bug. + +.. + +.. date: 2024-12-14-19-51-39 +.. gh-issue: 127930 +.. nonce: WsGnh9 +.. section: Library + +Add ``__all__`` to :mod:`tkinter.simpledialog`. + +.. + +.. date: 2024-05-20-12-35-52 +.. gh-issue: 115952 +.. nonce: J6n_Kf +.. section: Library + +Fix a potential memory denial of service in the :mod:`pickle` module. When +reading a pickled data received from untrusted source, it could cause an +arbitrary amount of memory to be allocated, even if the code that is allowed +to execute is restricted by overriding the +:meth:`~pickle.Unpickler.find_class` method. This could have led to symptoms +including a :exc:`MemoryError`, swapping, out of memory (OOM) killed +processes or containers, or even system crashes. + +.. + +.. bpo: 40350 +.. date: 2021-10-23-22-12-13 +.. nonce: t0dQMY +.. section: Library + +Fix support for namespace packages in :mod:`modulefinder`. + +.. + +.. date: 2025-11-26-23-30-09 +.. gh-issue: 141994 +.. nonce: arBEG6 +.. section: Documentation + +:mod:`xml.sax.handler`: Make Documentation of +:data:`xml.sax.handler.feature_external_ges` warn of opening up to `external +entity attacks <https://en.wikipedia.org/wiki/XML_external_entity_attack>`_. +Patch by Sebastian Pipping. + +.. + +.. date: 2025-12-16-01-17-21 +.. gh-issue: 134584 +.. nonce: tsxYYw +.. section: Core and Builtins + +Eliminate redundant refcounting from ``_STORE_ATTR_INSTANCE_VALUE``. + +.. + +.. date: 2025-12-15-15-07-40 +.. gh-issue: 142718 +.. nonce: zjiGjS +.. section: Core and Builtins + +JIT: Fix segfault caused by not flushing the stack to memory at side exits. + +.. + +.. date: 2025-12-15-15-01-21 +.. gh-issue: 142737 +.. nonce: xYXzeB +.. section: Core and Builtins + +Tracebacks will be displayed in fallback mode even if :func:`io.open` is +lost. Previously, this would crash the interpreter. Patch by Bartosz +Sławecki. + +.. + +.. date: 2025-12-15-03-20-24 +.. gh-issue: 116738 +.. nonce: NNHiTK +.. section: Core and Builtins + +Make the attributes in :mod:`bz2` thread-safe on the :term:`free threaded +<free threading>` build. + +.. + +.. date: 2025-12-14-21-46-07 +.. gh-issue: 134584 +.. nonce: vyec2h +.. section: Core and Builtins + +Eliminate redundant refcounting from ``_CALL_LIST_APPEND``. + +.. + +.. date: 2025-12-13-17-20-38 +.. gh-issue: 142554 +.. nonce: wNtEFF +.. section: Core and Builtins + +Fix a crash in :func:`divmod` when :func:`!_pylong.int_divmod` does not +return a tuple of length two exactly. Patch by Bénédikt Tran. + +.. + +.. date: 2025-12-10-23-03-10 +.. gh-issue: 142531 +.. nonce: NUEa1T +.. section: Core and Builtins + +Fix a free-threaded GC performance regression. If there are many untracked +tuples, the GC will run too often, resulting in poor performance. The fix +is to include untracked tuples in the "long lived" object count. The number +of frozen objects is also now included since the free-threaded GC must scan +those too. + +.. + +.. date: 2025-12-08-17-34-57 +.. gh-issue: 142402 +.. nonce: iV0ON3 +.. section: Core and Builtins + +Fix reference counting when adjacent literal parts are merged while +constructing :class:`string.templatelib.Template`, preventing the displaced +string object from leaking. + +.. + +.. date: 2025-12-08-14-14-40 +.. gh-issue: 116738 +.. nonce: x7aaBF +.. section: Core and Builtins + +Make the attributes in :mod:`zlib` thread-safe on the :term:`free threaded +<free threading>` build. + +.. + +.. date: 2025-12-08-13-04-37 +.. gh-issue: 142343 +.. nonce: BTAyML +.. section: Core and Builtins + +Fix SIGILL crash on m68k due to incorrect assembly constraint. + +.. + +.. date: 2025-12-06-00-38-37 +.. gh-issue: 142236 +.. nonce: m3EF9E +.. section: Core and Builtins + +Improve the "Perhaps you forgot a comma?" syntax error for multi-line string +concatenations to point to the last string instead of the first, making it +easier to locate where the comma is missing. Patch by Pablo Galindo. + +.. + +.. date: 2025-12-06-00-16-43 +.. gh-issue: 142236 +.. nonce: m3EF9E +.. section: Core and Builtins + +Fix incorrect keyword suggestions for syntax errors in :mod:`traceback`. The +keyword typo suggestion mechanism would incorrectly suggest replacements +when the extracted source code was incomplete rather than containing an +actual typo. Patch by Pablo Galindo. + +.. + +.. date: 2025-12-05-17-24-34 +.. gh-issue: 142305 +.. nonce: ybXvtr +.. section: Core and Builtins + +Decrease the size of the generated stencils and the runtime JIT code. Patch +by Diego Russo. + +.. + +.. date: 2025-12-05-15-59-03 +.. gh-issue: 135379 +.. nonce: lDXbKO +.. section: Core and Builtins + +Implement a limited form of register allocation known as "top of stack +caching" in the JIT. It works by keeping 0-3 of the top items in the stack +in registers. The code generator generates multiple versions of those uops +that do not escape and are relatively small. During JIT compilation, the +copy that produces the least memory traffic is selected, spilling or +reloading values when needed. + +.. + +.. date: 2025-12-05-14-33-54 +.. gh-issue: 142276 +.. nonce: H4j8hP +.. section: Core and Builtins + +Fix missing type watcher when promoting attribute loads to constants in the +JIT. Patch by Ken Jin. Reproducer by Yuancheng Jiang. + +.. + +.. date: 2025-12-03-11-03-35 +.. gh-issue: 142218 +.. nonce: 44Fq_J +.. section: Core and Builtins + +Fix crash when inserting into a split table dictionary with a non +:class:`str` key that matches an existing key. + +.. + +.. date: 2025-12-02-21-11-46 +.. gh-issue: 141976 +.. nonce: yu7pDV +.. section: Core and Builtins + +Check against abstract stack overflow in the JIT optimizer. + +.. + +.. date: 2025-12-02-15-39-16 +.. gh-issue: 97850 +.. nonce: H6QKwl +.. section: Core and Builtins + +Remove all ``*.load_module()`` usage and definitions from the import system +and importlib. The method has been deprecated in favor of +``importlib.abc.Loader.exec_module()`` since Python 3.4. + +.. + +.. date: 2025-12-01-20-41-26 +.. gh-issue: 142048 +.. nonce: c2YosX +.. section: Core and Builtins + +Fix quadratically increasing garbage collection delays in free-threaded +build. + +.. + +.. date: 2025-12-01-15-22-54 +.. gh-issue: 65961 +.. nonce: hCJvRB +.. section: Core and Builtins + +Stop setting ``__cached__`` on modules. + +.. + +.. date: 2025-11-29-18-14-28 +.. gh-issue: 141770 +.. nonce: JURnvg +.. section: Core and Builtins + +Annotate anonymous mmap usage only when supported by the Linux kernel and if +``-X dev`` is used or Python is built in debug mode. Patch by Donghee Na. + +.. + +.. date: 2025-11-29-08-51-56 +.. gh-issue: 142029 +.. nonce: rUpcmt +.. section: Core and Builtins + +Raise :exc:`ModuleNotFoundError` instead of crashing when a nonexistent +module is used as a name in ``_imp.create_builtin()``. + +.. + +.. date: 2025-11-28-16-45-07 +.. gh-issue: 142029 +.. nonce: JuXiKu +.. section: Core and Builtins + +Raise :exc:`ValueError` instead of crashing when empty string is used as a +name in ``_imp.create_builtin()``. + +.. + +.. date: 2025-11-26-20-01-07 +.. gh-issue: 141976 +.. nonce: K8NDmR +.. section: Core and Builtins + +Protect against specialization failures in the tracing JIT compiler for +performance reasons. + +.. + +.. date: 2025-11-25-02-23-31 +.. gh-issue: 141861 +.. nonce: QcMdcM +.. section: Core and Builtins + +Fix invalid memory read in the ``ENTER_EXECUTOR`` instruction. + +.. + +.. date: 2025-11-24-21-09-30 +.. gh-issue: 141930 +.. nonce: hIIzSd +.. section: Core and Builtins + +When importing a module, use Python's regular file object to ensure that +writes to ``.pyc`` files are complete or an appropriate error is raised. + +.. + +.. date: 2025-11-24-16-07-57 +.. gh-issue: 138122 +.. nonce: m3EF9E +.. section: Core and Builtins + +Add incomplete sample detection to prevent corrupted profiling data. Each +thread state now contains an embedded base frame (sentinel at the bottom of +the frame stack) with owner type ``FRAME_OWNED_BY_INTERPRETER``. The +profiler validates that stack unwinding terminates at this sentinel frame. +Samples that fail to reach the base frame (due to race conditions, memory +corruption, or other errors) are now rejected rather than being included as +spurious data. + +.. + +.. date: 2025-11-22-10-43-26 +.. gh-issue: 120158 +.. nonce: 41_rXd +.. section: Core and Builtins + +Fix inconsistent state when enabling or disabling monitoring events too many +times. + +.. + +.. date: 2025-11-20-22-09-22 +.. gh-issue: 140638 +.. nonce: f6btj0 +.. section: Core and Builtins + +Expose a ``"candidates"`` stat in :func:`gc.get_stats` and +:data:`gc.callbacks`. + +.. + +.. date: 2025-11-20-13-18-57 +.. gh-issue: 141780 +.. nonce: xDrVNr +.. section: Core and Builtins + +Fix :c:macro:`Py_mod_gil` with API added in :pep:`793`: +:c:func:`!PyModule_FromSlotsAndSpec` and ``PyModExport`` hooks + +.. + +.. date: 2025-11-19-16-40-24 +.. gh-issue: 141732 +.. nonce: PTetqp +.. section: Core and Builtins + +Ensure the :meth:`~object.__repr__` for :exc:`ExceptionGroup` and +:exc:`BaseExceptionGroup` does not change when the exception sequence that +was original passed in to its constructor is subsequently mutated. + +.. + +.. date: 2025-11-18-07-45-37 +.. gh-issue: 140638 +.. nonce: i06qxD +.. section: Core and Builtins + +Expose a ``"duration"`` stat in :func:`gc.get_stats` and +:data:`gc.callbacks`. + +.. + +.. date: 2025-11-17-14-40-45 +.. gh-issue: 139653 +.. nonce: LzOy1M +.. section: Core and Builtins + +Only raise a ``RecursionError`` or trigger a fatal error if the stack +pointer is both below the limit pointer *and* above the stack base. If +outside of these bounds assume that it is OK. This prevents false positives +when user-space threads swap stacks. + +.. + +.. date: 2025-11-16-21-14-48 +.. gh-issue: 41779 +.. nonce: rXIj5h +.. section: Core and Builtins + +Allowed defining the *__dict__* and *__weakref__* :ref:`__slots__ <slots>` +for any class. + +.. + +.. date: 2025-11-15-23-58-23 +.. gh-issue: 139103 +.. nonce: 9cVYJ0 +.. section: Core and Builtins + +Improve multithreaded scaling of dataclasses on the free-threaded build. + +.. + +.. date: 2025-11-15-14-04-35 +.. gh-issue: 141589 +.. nonce: VfdMDD +.. section: Core and Builtins + +Change ``backoff counter`` to use prime numbers instead of powers of 2. Use +only 3 bits for ``counter`` and 13 bits for ``value``. This allows to +support values up to 8191. Patch by Mikhail Efimov. + +.. + +.. date: 2025-07-22-16-20-06 +.. gh-issue: 137007 +.. nonce: 1oPvvK +.. section: Core and Builtins + +Fix a bug during JIT compilation failure which caused garbage collection +debug assertions to fail. + +.. + +.. date: 2025-07-11-19-57-27 +.. gh-issue: 132657 +.. nonce: vwDuO2 +.. section: Core and Builtins + +For the free-threaded build, avoid locking the :class:`set` object for the +``__contains__`` method. + +.. + +.. date: 2025-06-28-17-54-27 +.. gh-issue: 134584 +.. nonce: EXgPub +.. section: Core and Builtins + +Eliminate redundant refcounting from ``_CALL_STR_1``. + +.. + +.. date: 2025-06-28-04-32-38 +.. gh-issue: 134584 +.. nonce: eZogqn +.. section: Core and Builtins + +Eliminate redundant refcounting from ``_CALL_BUILTIN_O``. + +.. + +.. date: 2025-06-23-22-52-20 +.. gh-issue: 134584 +.. nonce: qbiQfG +.. section: Core and Builtins + +Eliminate redundant refcounting from ``_CALL_TUPLE_1``. Patch by Noam Cohen + +.. + +.. date: 2025-12-11-13-01-49 +.. gh-issue: 142589 +.. nonce: nNAqgw +.. section: C API + +Fix :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()` handling of +tagged ints on the interpreter stack. + +.. + +.. date: 2025-12-11-09-06-36 +.. gh-issue: 142571 +.. nonce: Csdxnn +.. section: C API + +:c:func:`!PyUnstable_CopyPerfMapFile` now checks that opening the file +succeeded before flushing. + +.. + +.. date: 2025-12-03-16-35-24 +.. gh-issue: 142225 +.. nonce: vmCJoo +.. section: C API + +Fixed the :c:macro:`PyABIInfo_VAR` macro. + +.. + +.. date: 2025-12-03-14-41-07 +.. gh-issue: 141049 +.. nonce: VuAUe2 +.. section: C API + +:c:func:`!_PyObject_CallMethodId`, :c:func:`!_PyObject_GetAttrId` and +:c:func:`!_PyUnicode_FromId` are deprecated since 3.15 and will be removed +in 3.20. Instead, use :c:func:`PyUnicode_InternFromString()` and cache the +result in the module state, then call :c:func:`PyObject_CallMethod` or +:c:func:`PyObject_GetAttr`. Patch by Victor Stinner. + +.. + +.. date: 2025-12-01-18-17-16 +.. gh-issue: 142163 +.. nonce: 2HiX5A +.. section: C API + +Fix the ``HAVE_THREAD_LOCAL`` macro being defined without the +``Py_BUILD_CORE`` macro set after including :file:`Python.h`. + +.. + +.. date: 2025-11-21-10-34-00 +.. gh-issue: 137422 +.. nonce: tzZKLi +.. section: C API + +Fix :term:`free threading` race condition in +:c:func:`PyImport_AddModuleRef`. It was previously possible for two calls to +the function return two different objects, only one of which was stored in +:data:`sys.modules`. + +.. + +.. date: 2025-11-18-18-36-15 +.. gh-issue: 141726 +.. nonce: ILrhyK +.. section: C API + +Add :c:func:`PyDict_SetDefaultRef` to the Stable ABI. + +.. + +.. date: 2025-11-18-04-16-09 +.. gh-issue: 140042 +.. nonce: S1C7id +.. section: C API + +Removed the sqlite3_shutdown call that could cause closing connections for +sqlite when used with multiple sub interpreters. + +.. + +.. date: 2025-11-05-21-48-31 +.. gh-issue: 141070 +.. nonce: mkrhjQ +.. section: C API + +Add :c:func:`PyUnstable_Object_Dump` to dump an object to ``stderr``. It +should only be used for debugging. Patch by Victor Stinner. + +.. + +.. date: 2025-09-22-16-32-00 +.. gh-issue: 139165 +.. nonce: 6Czn7S +.. section: C API + +Expose the functions :c:func:`Py_SIZE`, :c:func:`Py_IS_TYPE` and +:c:func:`Py_SET_SIZE` in the Stable ABI. + +.. + +.. date: 2025-12-09-14-23-51 +.. gh-issue: 131372 +.. nonce: 2TAEyz +.. section: Build + +Add ``LDVERSION`` and ``EXE`` to the ``base_interpreter`` value of +``build-details.json``. + +.. + +.. date: 2025-12-09-13-33-46 +.. gh-issue: 142454 +.. nonce: cqUxzQ +.. section: Build + +When calculating the digest of the JIT stencils input, sort the hashed files +by filenames before adding their content to the hasher. This ensures +deterministic hash input and hence deterministic hash, independent on +filesystem order. + +.. + +.. date: 2025-12-04-20-57-15 +.. gh-issue: 131372 +.. nonce: o397g7 +.. section: Build + +``build-details.py`` will only be installed as part of the main install +(``make install``). ``make altinstall`` will no longer include it. + +.. + +.. date: 2025-12-03-10-44-42 +.. gh-issue: 142234 +.. nonce: i1kaFb +.. section: Build + +Allow ``--enable-wasm-dynamic-linking`` for WASI. While CPython doesn't +directly support it so external/downstream users do not have to patch in +support for the flag. + +.. + +.. date: 2025-11-28-21-43-07 +.. gh-issue: 142050 +.. nonce: PFi4tv +.. section: Build + +Fixed a bug where JIT stencils produced on Windows contained debug data. +Patch by Chris Eibl. + +.. + +.. date: 2025-11-28-19-49-01 +.. gh-issue: 141808 +.. nonce: cV5K12 +.. section: Build + +Do not generate the jit stencils twice in case of PGO builds on Windows. + +.. + +.. date: 2025-11-25-13-17-47 +.. gh-issue: 141926 +.. nonce: KmuM2h +.. section: Build + +``RUNSHARED`` is no longer cleared when cross-compiling. Previously, +``RUNSHARED`` was cleared when cross-compiling, which breaks PGO when using +``--enabled-shared`` on systems where the cross-compiled CPython is +otherwise executable (e.g., via transparent emulation). + +.. + +.. date: 2025-11-20-23-15-39 +.. gh-issue: 141808 +.. nonce: NEewZC +.. section: Build + +When running ``make clean-retain-profile``, keep the generated JIT stencils. +That way, the stencils are not generated twice when Profile-guided +optimization (PGO) is used. It also allows distributors to supply their own +pre-built JIT stencils. + +.. + +.. date: 2025-11-20-17-01-05 +.. gh-issue: 141784 +.. nonce: LkYI2n +.. section: Build + +Fix ``_remote_debugging_module.c`` compilation on 32-bit Linux. Include +Python.h before system headers to make sure that +``_remote_debugging_module.c`` uses the same types (ABI) than Python. Patch +by Victor Stinner. + +.. + +.. date: 2025-11-19-09-21-17 +.. gh-issue: 141172 +.. nonce: cYWc4x +.. section: Build + +Update to WASI SDK 29. + +.. + +.. date: 2025-10-30-10-36-15 +.. gh-issue: 139707 +.. nonce: QJ1FfJ +.. section: Build + +Add configure option :option:`--with-missing-stdlib-config=FILE` allows +which distributors to pass a `JSON <https://www.json.org/json-en.html>`_ +configuration file containing custom error messages for missing +:term:`standard library` modules. + +.. + +.. date: 2025-04-29-18-25-34 +.. gh-issue: 108819 +.. nonce: qMUTRB +.. section: Build + +Honor :option:`--with-platlibdir` in the pure-Python standard library +installation path, if ``PLATLIBDIR`` doesn't match the value used in +``LIBDIR``. diff --git a/Misc/NEWS.d/3.7.0a1.rst b/Misc/NEWS.d/3.7.0a1.rst index fd6ba07b53a..69a0c09bda4 100644 --- a/Misc/NEWS.d/3.7.0a1.rst +++ b/Misc/NEWS.d/3.7.0a1.rst @@ -1042,8 +1042,8 @@ method of other descriptors. Remove the ``PyEval_GetCallStats()`` function and deprecate the untested and undocumented ``sys.callstats()`` function. Remove the ``CALL_PROFILE`` -special build: use the :func:`sys.setprofile` function, :mod:`cProfile` or -:mod:`profile` to profile function calls. +special build: use the :func:`sys.setprofile` function, :mod:`!cProfile` or +:mod:`!profile` to profile function calls. .. diff --git a/Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst b/Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst deleted file mode 100644 index 3667e2778b7..00000000000 --- a/Misc/NEWS.d/next/Build/2024-12-04-10-00-35.gh-issue-127545.t0THjE.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when building on Linux/m68k. diff --git a/Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst b/Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst deleted file mode 100644 index a60b4607456..00000000000 --- a/Misc/NEWS.d/next/Build/2025-01-03-13-02-06.gh-issue-123681.gQ67nK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Check the ``strftime()`` behavior at runtime instead of at the compile time -to support cross-compiling. -Remove the internal macro ``_Py_NORMALIZE_CENTURY``. diff --git a/Misc/NEWS.d/next/Build/2025-04-16-09-38-48.gh-issue-117088.EFt_5c.rst b/Misc/NEWS.d/next/Build/2025-04-16-09-38-48.gh-issue-117088.EFt_5c.rst deleted file mode 100644 index 0845b055139..00000000000 --- a/Misc/NEWS.d/next/Build/2025-04-16-09-38-48.gh-issue-117088.EFt_5c.rst +++ /dev/null @@ -1 +0,0 @@ -AIX linker don't support -h option, so avoid it through platform check diff --git a/Misc/NEWS.d/next/Build/2025-05-14-09-43-48.gh-issue-131769.H0oy5x.rst b/Misc/NEWS.d/next/Build/2025-05-14-09-43-48.gh-issue-131769.H0oy5x.rst deleted file mode 100644 index 834b0d9f7e1..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-14-09-43-48.gh-issue-131769.H0oy5x.rst +++ /dev/null @@ -1 +0,0 @@ -Fix detecting when the build Python in a cross-build is a pydebug build. diff --git a/Misc/NEWS.d/next/Build/2025-05-16-07-46-06.gh-issue-115119.ALBgS_.rst b/Misc/NEWS.d/next/Build/2025-05-16-07-46-06.gh-issue-115119.ALBgS_.rst deleted file mode 100644 index 8c2d15a3228..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-16-07-46-06.gh-issue-115119.ALBgS_.rst +++ /dev/null @@ -1,4 +0,0 @@ -Removed implicit fallback to the bundled copy of the ``libmpdec`` library. -Now this should be explicitly enabled via :option:`--with-system-libmpdec` -set to ``no`` or :option:`!--without-system-libmpdec`. Patch by Sergey -B Kirpichev. diff --git a/Misc/NEWS.d/next/Build/2025-05-19-18-09-20.gh-issue-134273.ZAliyy.rst b/Misc/NEWS.d/next/Build/2025-05-19-18-09-20.gh-issue-134273.ZAliyy.rst deleted file mode 100644 index 3eb13cefbe6..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-19-18-09-20.gh-issue-134273.ZAliyy.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for configuring compiler flags for the JIT with ``CFLAGS_JIT`` diff --git a/Misc/NEWS.d/next/Build/2025-05-21-19-46-28.gh-issue-134455.vdwlrq.rst b/Misc/NEWS.d/next/Build/2025-05-21-19-46-28.gh-issue-134455.vdwlrq.rst deleted file mode 100644 index 08833b3344f..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-21-19-46-28.gh-issue-134455.vdwlrq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed ``build-details.json`` generation to use the correct ``c_api.headers`` -as defined in :pep:`739`, instead of ``c_api.include``. diff --git a/Misc/NEWS.d/next/Build/2025-05-21-22-13-30.gh-issue-134486.yvdL6f.rst b/Misc/NEWS.d/next/Build/2025-05-21-22-13-30.gh-issue-134486.yvdL6f.rst deleted file mode 100644 index 2754e61f018..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-21-22-13-30.gh-issue-134486.yvdL6f.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :mod:`ctypes` module now performs a more portable test for the -definition of :manpage:`alloca(3)`, fixing a compilation failure on -NetBSD. diff --git a/Misc/NEWS.d/next/Build/2025-05-24-16-59-20.gh-issue-134632.i0W2hc.rst b/Misc/NEWS.d/next/Build/2025-05-24-16-59-20.gh-issue-134632.i0W2hc.rst deleted file mode 100644 index f41c8744b8a..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-24-16-59-20.gh-issue-134632.i0W2hc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed ``build-details.json`` generation to use ``INCLUDEPY``, in order to -reference the ``pythonX.Y`` subdirectory of the include directory, as -required in :pep:`739`, instead of the top-level include directory. diff --git a/Misc/NEWS.d/next/Build/2025-05-30-11-02-30.gh-issue-134923.gBkRg4.rst b/Misc/NEWS.d/next/Build/2025-05-30-11-02-30.gh-issue-134923.gBkRg4.rst deleted file mode 100644 index a742a6add8a..00000000000 --- a/Misc/NEWS.d/next/Build/2025-05-30-11-02-30.gh-issue-134923.gBkRg4.rst +++ /dev/null @@ -1,3 +0,0 @@ -Windows builds with profile-guided optimization enabled now use -``/GENPROFILE`` and ``/USEPROFILE`` instead of deprecated ``/LTCG:`` -options. diff --git a/Misc/NEWS.d/next/Build/2025-06-14-10-32-11.gh-issue-135497.ajlV4F.rst b/Misc/NEWS.d/next/Build/2025-06-14-10-32-11.gh-issue-135497.ajlV4F.rst deleted file mode 100644 index c84663b1466..00000000000 --- a/Misc/NEWS.d/next/Build/2025-06-14-10-32-11.gh-issue-135497.ajlV4F.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the detection of ``MAXLOGNAME`` in the ``configure.ac`` script. diff --git a/Misc/NEWS.d/next/Build/2025-06-16-07-20-28.gh-issue-119132.fcI8s7.rst b/Misc/NEWS.d/next/Build/2025-06-16-07-20-28.gh-issue-119132.fcI8s7.rst deleted file mode 100644 index 3eb0805b9ce..00000000000 --- a/Misc/NEWS.d/next/Build/2025-06-16-07-20-28.gh-issue-119132.fcI8s7.rst +++ /dev/null @@ -1 +0,0 @@ -Remove "experimental" tag from the CPython free-threading build. diff --git a/Misc/NEWS.d/next/Build/2025-06-25-13-27-14.gh-issue-135927.iCNPQc.rst b/Misc/NEWS.d/next/Build/2025-06-25-13-27-14.gh-issue-135927.iCNPQc.rst deleted file mode 100644 index 21a2c87d344..00000000000 --- a/Misc/NEWS.d/next/Build/2025-06-25-13-27-14.gh-issue-135927.iCNPQc.rst +++ /dev/null @@ -1 +0,0 @@ -Fix building with MSVC when passing option ``/std:clatest``. diff --git a/Misc/NEWS.d/next/Build/2025-07-18-17-15-00.gh-issue-135621.9cyCNb.rst b/Misc/NEWS.d/next/Build/2025-07-18-17-15-00.gh-issue-135621.9cyCNb.rst deleted file mode 100644 index fe7f962ccbb..00000000000 --- a/Misc/NEWS.d/next/Build/2025-07-18-17-15-00.gh-issue-135621.9cyCNb.rst +++ /dev/null @@ -1,2 +0,0 @@ -PyREPL no longer depends on the :mod:`curses` standard library. Contributed -by Łukasz Langa. diff --git a/Misc/NEWS.d/next/Build/2025-08-13-12-10-12.gh-issue-132339.3Czz5y.rst b/Misc/NEWS.d/next/Build/2025-08-13-12-10-12.gh-issue-132339.3Czz5y.rst deleted file mode 100644 index 493be0ca2da..00000000000 --- a/Misc/NEWS.d/next/Build/2025-08-13-12-10-12.gh-issue-132339.3Czz5y.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for OpenSSL 3.5. diff --git a/Misc/NEWS.d/next/Build/2025-08-26-21-18-32.gh-issue-128042.5voC8H.rst b/Misc/NEWS.d/next/Build/2025-08-26-21-18-32.gh-issue-128042.5voC8H.rst deleted file mode 100644 index fd85e0fee21..00000000000 --- a/Misc/NEWS.d/next/Build/2025-08-26-21-18-32.gh-issue-128042.5voC8H.rst +++ /dev/null @@ -1 +0,0 @@ -``./configure`` now warns when ``--enable-optimizations`` and ``CFLAGS=-O0`` are both set, suggesting removing ``-O0`` from ``CFLAGS`` for optimal performance. Patch by Taegyun Kim. diff --git a/Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst b/Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst deleted file mode 100644 index 279e588f3ad..00000000000 --- a/Misc/NEWS.d/next/C_API/2023-10-18-14-36-35.gh-issue-108512.fMZLfr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add functions :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`, -:c:func:`PySys_GetOptionalAttr` and :c:func:`PySys_GetOptionalAttrString`. diff --git a/Misc/NEWS.d/next/C_API/2025-04-14-07-41-28.gh-issue-131185.ZCjMHD.rst b/Misc/NEWS.d/next/C_API/2025-04-14-07-41-28.gh-issue-131185.ZCjMHD.rst deleted file mode 100644 index aa0e8bca93b..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-04-14-07-41-28.gh-issue-131185.ZCjMHD.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:func:`PyGILState_Ensure` no longer crashes when called after interpreter -finalization. diff --git a/Misc/NEWS.d/next/C_API/2025-04-17-12-37-27.gh-issue-132629.01ArwX.rst b/Misc/NEWS.d/next/C_API/2025-04-17-12-37-27.gh-issue-132629.01ArwX.rst deleted file mode 100644 index 38b7a0a493e..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-04-17-12-37-27.gh-issue-132629.01ArwX.rst +++ /dev/null @@ -1,4 +0,0 @@ -For unsigned integer formats in :c:func:`PyArg_ParseTuple`, accepting Python -integers with value that is larger than the maximal value for the C type or -less than the minimal value for the corresponding signed integer type -of the same size is now deprecated. diff --git a/Misc/NEWS.d/next/C_API/2025-05-07-21-18-00.gh-issue-133610.asdfjs.rst b/Misc/NEWS.d/next/C_API/2025-05-07-21-18-00.gh-issue-133610.asdfjs.rst deleted file mode 100644 index bdc53331f6a..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-07-21-18-00.gh-issue-133610.asdfjs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove deprecated functions :c:func:`!PyUnicode_AsDecodedObject`, -:c:func:`!PyUnicode_AsDecodedUnicode`, :c:func:`!PyUnicode_AsEncodedObject`, -and :c:func:`!PyUnicode_AsEncodedUnicode`. diff --git a/Misc/NEWS.d/next/C_API/2025-05-08-12-25-47.gh-issue-133644.Yb86Rm.rst b/Misc/NEWS.d/next/C_API/2025-05-08-12-25-47.gh-issue-133644.Yb86Rm.rst deleted file mode 100644 index 9569456eb76..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-08-12-25-47.gh-issue-133644.Yb86Rm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove deprecated alias :c:func:`!PyImport_ImportModuleNoBlock` of -:c:func:`PyImport_ImportModule`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/C_API/2025-05-08-13-14-45.gh-issue-133644.J8_KZ2.rst b/Misc/NEWS.d/next/C_API/2025-05-08-13-14-45.gh-issue-133644.J8_KZ2.rst deleted file mode 100644 index a9275e81112..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-08-13-14-45.gh-issue-133644.J8_KZ2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove deprecated Python initialization getter functions ``Py_Get*``. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/C_API/2025-05-13-16-06-46.gh-issue-133968.6alWst.rst b/Misc/NEWS.d/next/C_API/2025-05-13-16-06-46.gh-issue-133968.6alWst.rst deleted file mode 100644 index 47d5a3bda39..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-13-16-06-46.gh-issue-133968.6alWst.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add :c:func:`PyUnicodeWriter_WriteASCII` function to write an ASCII string -into a :c:type:`PyUnicodeWriter`. The function is faster than -:c:func:`PyUnicodeWriter_WriteUTF8`, but has an undefined behavior if the -input string contains non-ASCII characters. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2025-05-17-14-41-21.gh-issue-134144.xVpZik.rst b/Misc/NEWS.d/next/C_API/2025-05-17-14-41-21.gh-issue-134144.xVpZik.rst deleted file mode 100644 index 11c7bd59a4d..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-17-14-41-21.gh-issue-134144.xVpZik.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when calling :c:func:`Py_EndInterpreter` with a :term:`thread state` that isn't the initial thread for the interpreter. diff --git a/Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst b/Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst deleted file mode 100644 index f060f09de19..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-20-17-13-51.gh-issue-134009.CpCmry.rst +++ /dev/null @@ -1 +0,0 @@ -Expose :c:func:`PyMutex_IsLocked` as part of the public C API. diff --git a/Misc/NEWS.d/next/C_API/2025-05-29-16-56-23.gh-issue-134891.7eKO8U.rst b/Misc/NEWS.d/next/C_API/2025-05-29-16-56-23.gh-issue-134891.7eKO8U.rst deleted file mode 100644 index db30d5e9a94..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-29-16-56-23.gh-issue-134891.7eKO8U.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:type:`PyUnstable_Unicode_GET_CACHED_HASH` to get the cached hash of a -string. diff --git a/Misc/NEWS.d/next/C_API/2025-05-30-11-33-17.gh-issue-134745.GN-zk2.rst b/Misc/NEWS.d/next/C_API/2025-05-30-11-33-17.gh-issue-134745.GN-zk2.rst deleted file mode 100644 index a85d2e90576..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-05-30-11-33-17.gh-issue-134745.GN-zk2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Change :c:func:`!PyThread_allocate_lock` implementation to ``PyMutex``. -On Windows, :c:func:`!PyThread_acquire_lock_timed` now supports the *intr_flag* -parameter: it can be interrupted. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2025-06-02-13-19-22.gh-issue-134989.sDDyBN.rst b/Misc/NEWS.d/next/C_API/2025-06-02-13-19-22.gh-issue-134989.sDDyBN.rst deleted file mode 100644 index e49f7651065..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-06-02-13-19-22.gh-issue-134989.sDDyBN.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implement :c:func:`PyObject_DelAttr` and :c:func:`PyObject_DelAttrString` as -macros in the limited C API 3.12 and older. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2025-06-05-11-06-07.gh-issue-134989.74p4ud.rst b/Misc/NEWS.d/next/C_API/2025-06-05-11-06-07.gh-issue-134989.74p4ud.rst deleted file mode 100644 index 844e9a66664..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-06-05-11-06-07.gh-issue-134989.74p4ud.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``Py_RETURN_NONE``, ``Py_RETURN_TRUE`` and ``Py_RETURN_FALSE`` macros in -the limited C API 3.11 and older: don't treat ``Py_None``, ``Py_True`` and -``Py_False`` as immortal. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2025-06-19-12-47-18.gh-issue-133157.1WA85f.rst b/Misc/NEWS.d/next/C_API/2025-06-19-12-47-18.gh-issue-133157.1WA85f.rst deleted file mode 100644 index 1b37d884e57..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-06-19-12-47-18.gh-issue-133157.1WA85f.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the private, undocumented macro :c:macro:`!_Py_NO_SANITIZE_UNDEFINED`. diff --git a/Misc/NEWS.d/next/C_API/2025-06-24-11-10-01.gh-issue-133296.lIEuVJ.rst b/Misc/NEWS.d/next/C_API/2025-06-24-11-10-01.gh-issue-133296.lIEuVJ.rst deleted file mode 100644 index 41401911a6b..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-06-24-11-10-01.gh-issue-133296.lIEuVJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -New variants for the critical section API that accept one or two -:c:type:`PyMutex` pointers rather than :c:type:`PyObject` instances are now -public in the non-limited C API. diff --git a/Misc/NEWS.d/next/C_API/2025-06-25-01-03-10.gh-issue-135906.UBrCWq.rst b/Misc/NEWS.d/next/C_API/2025-06-25-01-03-10.gh-issue-135906.UBrCWq.rst deleted file mode 100644 index 7852759a702..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-06-25-01-03-10.gh-issue-135906.UBrCWq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix compilation errors when compiling the internal headers with a C++ compiler. diff --git a/Misc/NEWS.d/next/C_API/2025-07-01-16-22-39.gh-issue-135075.angu3J.rst b/Misc/NEWS.d/next/C_API/2025-07-01-16-22-39.gh-issue-135075.angu3J.rst deleted file mode 100644 index 88e0fa65f45..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-07-01-16-22-39.gh-issue-135075.angu3J.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make :c:func:`PyObject_SetAttr` and :c:func:`PyObject_SetAttrString` fail if -called with ``NULL`` value and an exception set. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2025-07-22-15-18-08.gh-issue-112068.4WvT-8.rst b/Misc/NEWS.d/next/C_API/2025-07-22-15-18-08.gh-issue-112068.4WvT-8.rst deleted file mode 100644 index 018c5c7880c..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-07-22-15-18-08.gh-issue-112068.4WvT-8.rst +++ /dev/null @@ -1 +0,0 @@ -Revert support of nullable arguments in :c:func:`PyArg_Parse`. diff --git a/Misc/NEWS.d/next/C_API/2025-07-23-22-30-23.gh-issue-136759.ffB4wO.rst b/Misc/NEWS.d/next/C_API/2025-07-23-22-30-23.gh-issue-136759.ffB4wO.rst deleted file mode 100644 index 79819b4735f..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-07-23-22-30-23.gh-issue-136759.ffB4wO.rst +++ /dev/null @@ -1 +0,0 @@ -Rename ``lock.h`` to ``pylock.h`` to avoid potential include conflicts. diff --git a/Misc/NEWS.d/next/C_API/2025-07-31-04-30-42.gh-issue-128813.opL-Pv.rst b/Misc/NEWS.d/next/C_API/2025-07-31-04-30-42.gh-issue-128813.opL-Pv.rst deleted file mode 100644 index caa8f3e9c98..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-07-31-04-30-42.gh-issue-128813.opL-Pv.rst +++ /dev/null @@ -1,5 +0,0 @@ -Functions :c:func:`_Py_c_sum`, :c:func:`_Py_c_diff`, :c:func:`_Py_c_neg`, -:c:func:`_Py_c_prod`, :c:func:`_Py_c_quot`, :c:func:`_Py_c_pow` and previously -undocumented :c:func:`_Py_c_abs` are :term:`soft deprecated`. Deprecate also -:c:member:`~PyComplexObject.cval` field of the :c:type:`PyComplexObject` type. -Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/C_API/2025-08-13-13-41-04.gh-issue-137573.r6uwRf.rst b/Misc/NEWS.d/next/C_API/2025-08-13-13-41-04.gh-issue-137573.r6uwRf.rst deleted file mode 100644 index dcf0e643dc1..00000000000 --- a/Misc/NEWS.d/next/C_API/2025-08-13-13-41-04.gh-issue-137573.r6uwRf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Mark ``_PyOptimizer_Optimize`` as :c:macro:`Py_NO_INLINE` to -prevent stack overflow crashes on macOS. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-22-01-23-23.gh-issue-130425.x5SNQ8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-22-01-23-23.gh-issue-130425.x5SNQ8.rst deleted file mode 100644 index a655cf2f2a7..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-22-01-23-23.gh-issue-130425.x5SNQ8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``"Did you mean: 'attr'?"`` suggestion when using ``del obj.attr`` if ``attr`` -does not exist. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-03-14-13-08-20.gh-issue-127266._tyfBp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-03-14-13-08-20.gh-issue-127266._tyfBp.rst deleted file mode 100644 index b26977628de..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-03-14-13-08-20.gh-issue-127266._tyfBp.rst +++ /dev/null @@ -1,6 +0,0 @@ -In the free-threaded build, avoid data races caused by updating type slots -or type flags after the type was initially created. For those (typically -rare) cases, use the stop-the-world mechanism. Remove the use of atomics -when reading or writing type flags. The use of atomics is not sufficient to -avoid races (since flags are sometimes read without a lock and without -atomics) and are no longer required. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-04-16-41-00.gh-issue-133379.asdjhjdf.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-04-16-41-00.gh-issue-133379.asdjhjdf.rst deleted file mode 100644 index cf2e1e4eaff..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-04-16-41-00.gh-issue-133379.asdjhjdf.rst +++ /dev/null @@ -1 +0,0 @@ -Correct usage of *arguments* in error messages. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-16-12-01-13.gh-issue-127971.pMDOQ0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-16-12-01-13.gh-issue-127971.pMDOQ0.rst deleted file mode 100644 index ced7a9c9fd3..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-16-12-01-13.gh-issue-127971.pMDOQ0.rst +++ /dev/null @@ -1 +0,0 @@ -Fix off-by-one read beyond the end of a string in string search. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-16-22-47.gh-issue-132732.jgqhlF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-16-22-47.gh-issue-132732.jgqhlF.rst deleted file mode 100644 index aadaf2169fd..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-16-22-47.gh-issue-132732.jgqhlF.rst +++ /dev/null @@ -1 +0,0 @@ -Automatically constant evaluate bytecode operations marked as pure in the JIT optimizer. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst deleted file mode 100644 index c69ce5efded..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update :attr:`Thread.native_id <threading.Thread.native_id>` after -:manpage:`fork(2)` to ensure accuracy. Patch by Noam Cohen. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-17-50-01.gh-issue-131798.XiOgw5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-17-50-01.gh-issue-131798.XiOgw5.rst deleted file mode 100644 index 45ab1bea6b1..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-26-17-50-01.gh-issue-131798.XiOgw5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Narrow the return type and constant-evaluate ``CALL_ISINSTANCE`` for a -subset of known values in the JIT. Patch by Tomas Roun diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst deleted file mode 100644 index 09ffaf80a6d..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enhance wrong type error messages and make them more consistent. Patch by -Semyon Moroz. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-14-13-01.gh-issue-132554.GqQaUp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-14-13-01.gh-issue-132554.GqQaUp.rst deleted file mode 100644 index bfe2d633309..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-14-13-01.gh-issue-132554.GqQaUp.rst +++ /dev/null @@ -1,4 +0,0 @@ -Change iteration to use "virtual iterators" for sequences. Instead of -creating an iterator, a tagged integer representing the next index is pushed -to the stack above the iterable. For non-sequence iterators, ``NULL`` is -pushed. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-13-36-01.gh-issue-131798.U4_QEJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-13-36-01.gh-issue-131798.U4_QEJ.rst deleted file mode 100644 index ca8eb999ae5..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-13-36-01.gh-issue-131798.U4_QEJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Split ``CALL_ISINSTANCE`` into several uops, allowing the JIT to remove some -of them. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-22-31-53.gh-issue-131798.fQ0ato.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-22-31-53.gh-issue-131798.fQ0ato.rst deleted file mode 100644 index f322d43b30a..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-22-31-53.gh-issue-131798.fQ0ato.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow the JIT to remove int guards after ``_GET_LEN`` by setting the return -type to int. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-06-15-01-41.gh-issue-133516.RqWVf2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-06-15-01-41.gh-issue-133516.RqWVf2.rst deleted file mode 100644 index b93ba11f932..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-06-15-01-41.gh-issue-133516.RqWVf2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Raise :exc:`ValueError` when constants ``True``, ``False`` or ``None`` are -used as an identifier after NFKC normalization. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-23-26-53.gh-issue-133541.bHIC55.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-23-26-53.gh-issue-133541.bHIC55.rst deleted file mode 100644 index 4f4cd847fa5..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-23-26-53.gh-issue-133541.bHIC55.rst +++ /dev/null @@ -1,2 +0,0 @@ -Inconsistent indentation in user input crashed the new REPL when syntax -highlighting was active. This is now fixed. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-13-48-02.gh-issue-132762.tKbygC.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-13-48-02.gh-issue-132762.tKbygC.rst deleted file mode 100644 index 80b830ebd78..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-13-48-02.gh-issue-132762.tKbygC.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`~dict.fromkeys` no longer loops forever when adding a small set of keys to a large base dict. Patch by Angela Liss. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-22-19-10.gh-issue-133711.e91wUy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-22-19-10.gh-issue-133711.e91wUy.rst deleted file mode 100644 index c8d3d62763d..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-22-19-10.gh-issue-133711.e91wUy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implement :pep:`686`: Enable :ref:`Python UTF-8 Mode <utf8-mode>` by -default. Patch by Adam Turner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-09-18-11-21.gh-issue-133778.pWEV3t.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-09-18-11-21.gh-issue-133778.pWEV3t.rst deleted file mode 100644 index 6eb6881213c..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-09-18-11-21.gh-issue-133778.pWEV3t.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where assigning to the :attr:`~type.__annotations__` attributes of -classes defined under ``from __future__ import annotations`` had no effect. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-10-17-12-27.gh-issue-133703.bVM-re.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-10-17-12-27.gh-issue-133703.bVM-re.rst deleted file mode 100644 index 05bf6103314..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-10-17-12-27.gh-issue-133703.bVM-re.rst +++ /dev/null @@ -1 +0,0 @@ -Fix hashtable in dict can be bigger than intended in some situations. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-13-40-42.gh-issue-133886.ryBAyo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-13-40-42.gh-issue-133886.ryBAyo.rst deleted file mode 100644 index fd1020f05d6..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-13-40-42.gh-issue-133886.ryBAyo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`sys.remote_exec` for non-ASCII paths in non-UTF-8 locales and -non-UTF-8 paths in UTF-8 locales. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-15-11-38-16.gh-issue-133999.uBZ8uS.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-15-11-38-16.gh-issue-133999.uBZ8uS.rst deleted file mode 100644 index 7d9c49688c3..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-15-11-38-16.gh-issue-133999.uBZ8uS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :exc:`SyntaxError` regression in :keyword:`except` parsing after -:gh:`123440`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-09-06-38.gh-issue-134036.st2e-B.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-09-06-38.gh-issue-134036.st2e-B.rst deleted file mode 100644 index 176aab1c93a..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-09-06-38.gh-issue-134036.st2e-B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve :exc:`SyntaxError` message when using invalid :keyword:`raise` -statements. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-17-25-52.gh-issue-134100.5-FbLK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-17-25-52.gh-issue-134100.5-FbLK.rst deleted file mode 100644 index d672347f9ad..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-17-25-52.gh-issue-134100.5-FbLK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a use-after-free bug that occurs when an imported module isn't -in :data:`sys.modules` after its initial import. Patch by Nico-Posada. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-20-59-12.gh-issue-134119.w8expI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-20-59-12.gh-issue-134119.w8expI.rst deleted file mode 100644 index 754e8166285..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-16-20-59-12.gh-issue-134119.w8expI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash when calling :func:`next` on an exhausted template string iterator. -Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst deleted file mode 100644 index 7b8bab739c3..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst +++ /dev/null @@ -1 +0,0 @@ -Fix coloring of double braces in f-strings and t-strings in the :term:`REPL`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-56-05.gh-issue-91153.afgtG2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-56-05.gh-issue-91153.afgtG2.rst deleted file mode 100644 index dc2f1e22ba5..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-56-05.gh-issue-91153.afgtG2.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash when a :class:`bytearray` is concurrently mutated during item assignment. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-10-50-46.gh-issue-134170.J0Hvmi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-10-50-46.gh-issue-134170.J0Hvmi.rst deleted file mode 100644 index f33a30c7e12..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-10-50-46.gh-issue-134170.J0Hvmi.rst +++ /dev/null @@ -1 +0,0 @@ -Add colorization to :func:`sys.unraisablehook` by default. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-14-33-23.gh-issue-69605.ZMO49F.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-14-33-23.gh-issue-69605.ZMO49F.rst deleted file mode 100644 index 7b7275fee69..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-18-14-33-23.gh-issue-69605.ZMO49F.rst +++ /dev/null @@ -1,2 +0,0 @@ -When auto-completing an import in the :term:`REPL`, finding no candidates -now issues no suggestion, rather than suggestions from the current namespace. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-15-15-58.gh-issue-131798.PCP71j.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-15-15-58.gh-issue-131798.PCP71j.rst deleted file mode 100644 index c816a0afad4..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-15-15-58.gh-issue-131798.PCP71j.rst +++ /dev/null @@ -1 +0,0 @@ -Split ``CALL_LIST_APPEND`` into several uops. Patch by Diego Russo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-20-52-53.gh-issue-134268.HPKX1e.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-20-52-53.gh-issue-134268.HPKX1e.rst deleted file mode 100644 index 98d770cf054..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-20-52-53.gh-issue-134268.HPKX1e.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW`` and use it to further -optimize ``CALL_ISINSTANCE``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-13-58-18.gh-issue-131798.hG8xBw.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-13-58-18.gh-issue-131798.hG8xBw.rst deleted file mode 100644 index c490ecf1560..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-13-58-18.gh-issue-131798.hG8xBw.rst +++ /dev/null @@ -1 +0,0 @@ -Improve the JIT's ability to narrow unknown classes to constant values. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-14-41-50.gh-issue-128066.qzzGfv.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-14-41-50.gh-issue-128066.qzzGfv.rst deleted file mode 100644 index f7819027685..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-14-41-50.gh-issue-128066.qzzGfv.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixes an edge case where PyREPL improperly threw an error when Python is -invoked on a read only filesystem while trying to write history file -entries. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-23-32-11.gh-issue-131798.G9ZQZw.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-23-32-11.gh-issue-131798.G9ZQZw.rst deleted file mode 100644 index 8eb8782037a..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-20-23-32-11.gh-issue-131798.G9ZQZw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the JIT's ability to optimize away cached class attribute and method -loads. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst deleted file mode 100644 index f873bbfb4dc..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-13-57-26.gh-issue-131798.QwS5Bb.rst +++ /dev/null @@ -1 +0,0 @@ -JIT: replace ``_LOAD_SMALL_INT`` with ``_LOAD_CONST_INLINE_BORROW`` diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-15-14-32.gh-issue-130397.aG6EON.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-15-14-32.gh-issue-130397.aG6EON.rst deleted file mode 100644 index 34a2f4d1278..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-15-14-32.gh-issue-130397.aG6EON.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove special-casing for C stack depth limits for WASI. Due to -WebAssembly's built-in stack protection this does not pose a security -concern. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-18-02-56.gh-issue-127960.W3J_2X.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-18-02-56.gh-issue-127960.W3J_2X.rst deleted file mode 100644 index 730d8a5af51..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-21-18-02-56.gh-issue-127960.W3J_2X.rst +++ /dev/null @@ -1,3 +0,0 @@ -PyREPL interactive shell no longer starts with ``__package__`` and -``__file__`` global names set to ``_pyrepl`` package internals. Contributed -by Yuichiro Tachibana. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst deleted file mode 100644 index aa8900296ae..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :exc:`RuntimeError` when using a not-started :class:`threading.Thread` after calling :func:`os.fork` diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-17-49-39.gh-issue-131798.U6ZmFm.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-17-49-39.gh-issue-131798.U6ZmFm.rst deleted file mode 100644 index fdb6a2fe0b3..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-17-49-39.gh-issue-131798.U6ZmFm.rst +++ /dev/null @@ -1 +0,0 @@ -Optimize ``_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-23-14-54-07.gh-issue-134584.y-WDjf.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-23-14-54-07.gh-issue-134584.y-WDjf.rst deleted file mode 100644 index 5f9e1553ae7..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-23-14-54-07.gh-issue-134584.y-WDjf.rst +++ /dev/null @@ -1 +0,0 @@ -Add a reference count elimination pass to the JIT compiler. Patch by Ken Jin. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-25-19-32-15.gh-issue-131798.f5h8aI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-25-19-32-15.gh-issue-131798.f5h8aI.rst deleted file mode 100644 index 6ecbfb8d9cf..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-25-19-32-15.gh-issue-131798.f5h8aI.rst +++ /dev/null @@ -1 +0,0 @@ -Make the JIT optimizer understand that slicing a string/list/tuple returns the same type. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-26-15-55-50.gh-issue-133912.-xAguL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-26-15-55-50.gh-issue-133912.-xAguL.rst deleted file mode 100644 index 2118f3d0c35..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-26-15-55-50.gh-issue-133912.-xAguL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the C API function ``PyObject_GenericSetDict`` to handle extension -classes with inline values. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-18-59-54.gh-issue-134679.FWPBu6.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-18-59-54.gh-issue-134679.FWPBu6.rst deleted file mode 100644 index 22f1282fea1..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-18-59-54.gh-issue-134679.FWPBu6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash in the :term:`free threading` build's QSBR code that could occur -when changing an object's ``__dict__`` attribute. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-20-21-34.gh-issue-131798.b32zkl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-20-21-34.gh-issue-131798.b32zkl.rst deleted file mode 100644 index ed4b31bd7be..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-20-21-34.gh-issue-131798.b32zkl.rst +++ /dev/null @@ -1 +0,0 @@ -Allow the JIT to remove unnecessary ``_ITER_CHECK_TUPLE`` ops. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst deleted file mode 100644 index 53aef541e64..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-27-20-29-00.gh-issue-132617.EmUfQQ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :meth:`dict.update` modification check that could incorrectly raise a -"dict mutated during update" error when a different dictionary was modified -that happens to share the same underlying keys object. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-28-23-58-50.gh-issue-117852.BO9g7z.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-28-23-58-50.gh-issue-117852.BO9g7z.rst deleted file mode 100644 index fc71cd21a36..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-28-23-58-50.gh-issue-117852.BO9g7z.rst +++ /dev/null @@ -1 +0,0 @@ -Fix argument checking of :meth:`~agen.athrow`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-30-15-56-19.gh-issue-134908.3a7PxM.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-30-15-56-19.gh-issue-134908.3a7PxM.rst deleted file mode 100644 index 3178f0aaf88..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-30-15-56-19.gh-issue-134908.3a7PxM.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when iterating over lines in a text file on the :term:`free threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-30-18-09-54.gh-issue-134889.Ic9UM-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-30-18-09-54.gh-issue-134889.Ic9UM-.rst deleted file mode 100644 index 3b86134bf16..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-30-18-09-54.gh-issue-134889.Ic9UM-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling of a few opcodes that leave operands on the stack when -optimizing ``LOAD_FAST``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-31-10-26-46.gh-issue-134876.8mBGJI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-31-10-26-46.gh-issue-134876.8mBGJI.rst deleted file mode 100644 index 1da76561469..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-31-10-26-46.gh-issue-134876.8mBGJI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add support to :pep:`768` remote debugging for Linux kernels which don't -have CONFIG_CROSS_MEMORY_ATTACH configured. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-31-19-24-54.gh-issue-134280.NDVbzY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-31-19-24-54.gh-issue-134280.NDVbzY.rst deleted file mode 100644 index f8227216909..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-31-19-24-54.gh-issue-134280.NDVbzY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disable constant folding for ``~`` with a boolean argument. -This moves the deprecation warning from compile time to runtime. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-02-13-57-40.gh-issue-116738.ycJsL8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-02-13-57-40.gh-issue-116738.ycJsL8.rst deleted file mode 100644 index 506eefdb21a..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-02-13-57-40.gh-issue-116738.ycJsL8.rst +++ /dev/null @@ -1 +0,0 @@ -Make methods in :mod:`heapq` thread-safe on the :term:`free threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-02-20-13-37.gh-issue-131798.JQRFvR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-02-20-13-37.gh-issue-131798.JQRFvR.rst deleted file mode 100644 index 0e68c793e5e..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-02-20-13-37.gh-issue-131798.JQRFvR.rst +++ /dev/null @@ -1 +0,0 @@ -Optimize ``_CHECK_METHOD_VERSION`` into ``_CHECK_FUNCTION_VERSION_INLINE`` in JIT-compiled code. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-06-22.gh-issue-133136.Usnvri.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-06-22.gh-issue-133136.Usnvri.rst deleted file mode 100644 index a9501c13c95..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-06-22.gh-issue-133136.Usnvri.rst +++ /dev/null @@ -1,2 +0,0 @@ -Limit excess memory usage in the :term:`free threading` build when a -large dictionary or list is resized and accessed by multiple threads. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-05-21-58-30.gh-issue-131798.nt5Ab7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-05-21-58-30.gh-issue-131798.nt5Ab7.rst deleted file mode 100644 index e4b5f610353..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-05-21-58-30.gh-issue-131798.nt5Ab7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimize away ``_CALL_TYPE_1`` in the JIT when the return type is known. -Patch by Tomas Roun diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst deleted file mode 100644 index a3775262306..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-01-09-44.gh-issue-131798.1SuxO9.rst +++ /dev/null @@ -1 +0,0 @@ -Optimize ``_UNARY_INVERT`` in JIT-compiled code. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-02-24-42.gh-issue-135148.r-t2sC.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-02-24-42.gh-issue-135148.r-t2sC.rst deleted file mode 100644 index 9b1f62433b4..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-02-24-42.gh-issue-135148.r-t2sC.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed a bug where f-string debug expressions (using =) would incorrectly -strip out parts of strings containing escaped quotes and # characters. Patch -by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-19-17-22.gh-issue-131798.XoV8Eb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-19-17-22.gh-issue-131798.XoV8Eb.rst deleted file mode 100644 index 6a9d9c683f9..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-06-19-17-22.gh-issue-131798.XoV8Eb.rst +++ /dev/null @@ -1 +0,0 @@ -Optimize ``_UNARY_NEGATIVE`` in JIT-compiled code. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-08-14-24-29.gh-issue-131798.qfw91T.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-08-14-24-29.gh-issue-131798.qfw91T.rst deleted file mode 100644 index 7965169d46e..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-08-14-24-29.gh-issue-131798.qfw91T.rst +++ /dev/null @@ -1 +0,0 @@ -Optimize _CALL_LEN in the JIT when the length is known. Patch by Tomas Roun diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-09-23-57-37.gh-issue-130077.MHknDB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-09-23-57-37.gh-issue-130077.MHknDB.rst deleted file mode 100644 index a7d02426b6f..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-09-23-57-37.gh-issue-130077.MHknDB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Properly raise custom syntax errors when incorrect syntax containing names -that are prefixes of soft keywords is encountered. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-15-08-10.gh-issue-127319.OVGFSZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-15-08-10.gh-issue-127319.OVGFSZ.rst deleted file mode 100644 index d90153c9684..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-15-08-10.gh-issue-127319.OVGFSZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Set the ``allow_reuse_port`` class variable to ``False`` on the XMLRPC, -logging, and HTTP servers. This matches the behavior in prior Python -releases, which is to not allow port reuse. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-00-03-34.gh-issue-116738.iBBAdo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-00-03-34.gh-issue-116738.iBBAdo.rst deleted file mode 100644 index 2a1ed2944d8..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-00-03-34.gh-issue-116738.iBBAdo.rst +++ /dev/null @@ -1 +0,0 @@ -Make functions in :mod:`grp` thread-safe on the :term:`free threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-11-19-52.gh-issue-135422.F6yQi6.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-11-19-52.gh-issue-135422.F6yQi6.rst deleted file mode 100644 index bb0f178f91a..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-11-19-52.gh-issue-135422.F6yQi6.rst +++ /dev/null @@ -1 +0,0 @@ -Fix regression in :exc:`SyntaxError` messages after :gh:`134036`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-18-12-42.gh-issue-135371.R_YUtR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-18-12-42.gh-issue-135371.R_YUtR.rst deleted file mode 100644 index 9f2e825e57b..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-12-18-12-42.gh-issue-135371.R_YUtR.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixed :mod:`asyncio` debugging tools to properly display internal coroutine -call stacks alongside external task dependencies. The ``python -m asyncio -ps`` and ``python -m asyncio pstree`` commands now show complete execution -context. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-13-16-05-24.gh-issue-135474.67nOl3.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-13-16-05-24.gh-issue-135474.67nOl3.rst deleted file mode 100644 index 716d9b78748..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-13-16-05-24.gh-issue-135474.67nOl3.rst +++ /dev/null @@ -1 +0,0 @@ -Specialize integer operations only on compact integers. This is a CPython internal change. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-14-01-01-14.gh-issue-135496.ER0Me3.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-14-01-01-14.gh-issue-135496.ER0Me3.rst deleted file mode 100644 index 03b1f4590c5..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-14-01-01-14.gh-issue-135496.ER0Me3.rst +++ /dev/null @@ -1 +0,0 @@ -Fix typo in the f-string conversion type error ("exclamanation" -> "exclamation"). diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst deleted file mode 100644 index 6efe2a47bac..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Emit ``sys.remote_exec`` audit event when :func:`sys.remote_exec` is called -and migrate ``remote_debugger_script`` to ``cpython.remote_debugger_script``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-03-56-15.gh-issue-135551.hRTQO-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-03-56-15.gh-issue-135551.hRTQO-.rst deleted file mode 100644 index 22dda2a3e97..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-03-56-15.gh-issue-135551.hRTQO-.rst +++ /dev/null @@ -1 +0,0 @@ -Sorting randomly ordered lists will often run a bit faster, thanks to a new scheme for picking minimum run lengths from Stefan Pochmann, which arranges for the merge tree to be as evenly balanced as is possible. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-08-37-45.gh-issue-82088.TgPvLg.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-08-37-45.gh-issue-82088.TgPvLg.rst deleted file mode 100644 index 74bd182c199..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-08-37-45.gh-issue-82088.TgPvLg.rst +++ /dev/null @@ -1,5 +0,0 @@ -Improve performance of ``PyLongObject`` conversion functions -``PyLong_AsLongAndOverflow()``, ``PyLong_AsSsize_t()``, ``PyLong_AsUnsignedLong()``, ``PyLong_AsSize_t()``, -``PyLong_AsUnsignedLongMask()``, ``PyLong_AsUnsignedLongLongMask()``, ``PyLong_AsLongLongAndOverflow()`` -for integers larger than 2**30 up to 30%. - diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-12-50-48.gh-issue-135608.PnHckD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-12-50-48.gh-issue-135608.PnHckD.rst deleted file mode 100644 index a65a0c85fa6..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-12-50-48.gh-issue-135608.PnHckD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash in the JIT involving attributes of modules. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-22-34-58.gh-issue-135607.ucsLVu.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-22-34-58.gh-issue-135607.ucsLVu.rst deleted file mode 100644 index 859259a9ace..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-17-22-34-58.gh-issue-135607.ucsLVu.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix potential :mod:`weakref` races in an object's destructor on the :term:`free threaded <free -threading>` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-18-12-19-13.gh-issue-135379.TCvGpj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-18-12-19-13.gh-issue-135379.TCvGpj.rst deleted file mode 100644 index 089d00c77da..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-18-12-19-13.gh-issue-135379.TCvGpj.rst +++ /dev/null @@ -1,3 +0,0 @@ -Changes specialization of ``BINARY_OP`` for ints to only specialize for -"compact" ints. This streamlines the fast path at the cost of fewer -specializations when very large integers are used. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-18-16-45-36.gh-issue-135106.cpl6Aq.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-18-16-45-36.gh-issue-135106.cpl6Aq.rst deleted file mode 100644 index b6e953a7719..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-18-16-45-36.gh-issue-135106.cpl6Aq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Restrict the trashcan mechanism to GC'ed objects and untrack them while in -the trashcan to prevent the GC and trashcan mechanisms conflicting. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-20-14-50-44.gh-issue-134584.3CJdAI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-20-14-50-44.gh-issue-134584.3CJdAI.rst deleted file mode 100644 index 715ac7dc925..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-20-14-50-44.gh-issue-134584.3CJdAI.rst +++ /dev/null @@ -1 +0,0 @@ -Specialize :opcode:`POP_TOP` in the JIT compiler by specializing for reference lifetime and type. This will also enable easier top of stack caching in the JIT compiler. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-18-08-32.gh-issue-135871.50C528.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-18-08-32.gh-issue-135871.50C528.rst deleted file mode 100644 index ce29ddecefe..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-18-08-32.gh-issue-135871.50C528.rst +++ /dev/null @@ -1,2 +0,0 @@ -Non-blocking mutex lock attempts now return immediately when the lock is busy -instead of briefly spinning in the :term:`free threading` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-06-41-47.gh-issue-129958.EaJuS0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-06-41-47.gh-issue-129958.EaJuS0.rst deleted file mode 100644 index 70b3e99425d..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-06-41-47.gh-issue-129958.EaJuS0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Differentiate between t-strings and f-strings in syntax error for newlines -in format specifiers of single-quoted interpolated strings. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-16-46-34.gh-issue-135904.78xfon.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-16-46-34.gh-issue-135904.78xfon.rst deleted file mode 100644 index ecbd8fda9a5..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-16-46-34.gh-issue-135904.78xfon.rst +++ /dev/null @@ -1,2 +0,0 @@ -Perform more aggressive control-flow optimizations on the machine code -templates emitted by the experimental JIT compiler. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-26-15-25-51.gh-issue-78465.MbDN8X.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-26-15-25-51.gh-issue-78465.MbDN8X.rst deleted file mode 100644 index 99734d63c5d..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-26-15-25-51.gh-issue-78465.MbDN8X.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix error message for ``cls.__new__(cls, ...)`` where ``cls`` is not -instantiable builtin or extension type (with ``tp_new`` set to ``NULL``). diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-02-15-18-41.gh-issue-136203.Y934sC.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-02-15-18-41.gh-issue-136203.Y934sC.rst deleted file mode 100644 index 5a622bab8b8..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-02-15-18-41.gh-issue-136203.Y934sC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve :exc:`TypeError` error message, when richcomparing two -:class:`types.MappingProxyType` objects. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-03-06-04-42.gh-issue-135552.CbBQof.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-03-06-04-42.gh-issue-135552.CbBQof.rst deleted file mode 100644 index ea30a43fc25..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-03-06-04-42.gh-issue-135552.CbBQof.rst +++ /dev/null @@ -1,7 +0,0 @@ -Fix a bug caused by the garbage collector clearing weakrefs too early. The -weakrefs in the ``tp_subclasses`` dictionary are needed in order to correctly -invalidate type caches (for example, by calling ``PyType_Modified()``). -Clearing weakrefs before calling finalizers causes the caches to not be -correctly invalidated. That can cause crashes since the caches can refer to -invalid objects. Defer the clearing of weakrefs without callbacks until after -finalizers are executed. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst deleted file mode 100644 index a37f4a51050..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst +++ /dev/null @@ -1 +0,0 @@ -Fix memory error handling in :c:func:`PyDict_SetDefault`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-07-17-26-06.gh-issue-91636.GyHU72.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-07-17-26-06.gh-issue-91636.GyHU72.rst deleted file mode 100644 index 09c192f9c56..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-07-17-26-06.gh-issue-91636.GyHU72.rst +++ /dev/null @@ -1,3 +0,0 @@ -While performing garbage collection, clear weakrefs to unreachable objects -that are created during running of finalizers. If those weakrefs were are -not cleared, they could reveal unreachable objects. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-08-23-22-08.gh-issue-132661.34ftJl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-08-23-22-08.gh-issue-132661.34ftJl.rst deleted file mode 100644 index 5d59e024389..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-08-23-22-08.gh-issue-132661.34ftJl.rst +++ /dev/null @@ -1,5 +0,0 @@ -Reflect recent :pep:`750` change. - -Disallow concatenation of ``string.templatelib.Template`` and :class:`str`. -Also, disallow implicit concatenation of t-string literals with string or -f-string literals. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-08-23-53-51.gh-issue-132661.B84iYt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-08-23-53-51.gh-issue-132661.B84iYt.rst deleted file mode 100644 index 9930413b53c..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-08-23-53-51.gh-issue-132661.B84iYt.rst +++ /dev/null @@ -1 +0,0 @@ -``Interpolation.expression`` now has a default, the empty string. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-09-11-15-42.gh-issue-136459.m4Udh8.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-09-11-15-42.gh-issue-136459.m4Udh8.rst deleted file mode 100644 index 470f3311526..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-09-11-15-42.gh-issue-136459.m4Udh8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add support for perf trampoline on macOS, to allow profilers wit JIT map -support to read Python calls. While profiling, ``PYTHONPERFSUPPORT=1`` can -be appended to enable the trampoline. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-10-15-53-16.gh-issue-136525.xAko0e.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-10-15-53-16.gh-issue-136525.xAko0e.rst deleted file mode 100644 index f28eb2ca3b7..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-10-15-53-16.gh-issue-136525.xAko0e.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issue where per-thread bytecode was not instrumented for newly created -threads. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-10-23-23-50.gh-issue-136517._NHJyv.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-10-23-23-50.gh-issue-136517._NHJyv.rst deleted file mode 100644 index bf26c4eb0e4..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-10-23-23-50.gh-issue-136517._NHJyv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a typo that prevented printing of uncollectable objects when the -:const:`gc.DEBUG_UNCOLLECTABLE` mode was set. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst deleted file mode 100644 index 23122415e8a..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the error messages that may be raised by -:meth:`~socket.socket.setsockopt`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-13-45-48.gh-issue-136541.uZ_-Ju.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-13-45-48.gh-issue-136541.uZ_-Ju.rst deleted file mode 100644 index af9b94ad061..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-13-45-48.gh-issue-136541.uZ_-Ju.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix some issues with the perf trampolines on x86-64 and aarch64. The -trampolines were not being generated correctly for some cases, which could -lead to the perf integration not working correctly. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-12-09-59-14.gh-issue-136421.ZD1rNj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-12-09-59-14.gh-issue-136421.ZD1rNj.rst deleted file mode 100644 index dcc73267a78..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-12-09-59-14.gh-issue-136421.ZD1rNj.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when initializing :mod:`datetime` concurrently. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-15-10-03-57.gh-issue-116738.oFttKl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-15-10-03-57.gh-issue-116738.oFttKl.rst deleted file mode 100644 index 07d8b45fb7f..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-15-10-03-57.gh-issue-116738.oFttKl.rst +++ /dev/null @@ -1 +0,0 @@ -Make functions in :mod:`pwd` thread-safe on the :term:`free threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst deleted file mode 100644 index 77dca4074b7..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make functions in :mod:`syslog` thread-safe on the :term:`free threaded -<free threading>` build. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst deleted file mode 100644 index d149e7b2878..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-10-35-31.gh-issue-74185.7hPCA5.rst +++ /dev/null @@ -1,4 +0,0 @@ -The :meth:`~object.__repr__` of :class:`ImportError` and :class:`ModuleNotFoundError` -now shows "name" and "path" as ``name=<name>`` and ``path=<path>`` if they were given -as keyword arguments at construction time. -Patch by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-12-37-05.gh-issue-136801.XU_tF2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-12-37-05.gh-issue-136801.XU_tF2.rst deleted file mode 100644 index 767d7b97726..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-12-37-05.gh-issue-136801.XU_tF2.rst +++ /dev/null @@ -1 +0,0 @@ -Fix PyREPL syntax highlighting on match cases after multi-line case. Contributed by Olga Matoula. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-17-08-09.gh-issue-127598.Mx8S-y.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-17-08-09.gh-issue-127598.Mx8S-y.rst deleted file mode 100644 index aff047bbef0..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-19-17-08-09.gh-issue-127598.Mx8S-y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve :exc:`ModuleNotFoundError` by adding flavour text to the exception when the -:option:`-S` option is passed. Patch by Andrea Mattei. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-02-13-59.gh-issue-132732.p77xkb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-02-13-59.gh-issue-132732.p77xkb.rst deleted file mode 100644 index df77fe6715d..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-02-13-59.gh-issue-132732.p77xkb.rst +++ /dev/null @@ -1 +0,0 @@ -Optimize constant comparison for ``_COMPARE_OP_INT``, ``_COMPARE_OP_FLOAT`` and ``_COMPARE_OP_STR`` in JIT builds diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-17-30-58.gh-issue-136870.ncx82J.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-17-30-58.gh-issue-136870.ncx82J.rst deleted file mode 100644 index 7552dc69169..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-17-30-58.gh-issue-136870.ncx82J.rst +++ /dev/null @@ -1 +0,0 @@ -Fix data races while de-instrumenting bytecode of code objects running concurrently in threads. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-25-22-31-52.gh-issue-131338.zJDCMp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-25-22-31-52.gh-issue-131338.zJDCMp.rst deleted file mode 100644 index 6c064e8f4a0..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-25-22-31-52.gh-issue-131338.zJDCMp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disable computed stack limit checks on non-glibc linux platforms to fix -crashes on deep recursion. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-28-19-11-34.gh-issue-134291.IiB9Id.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-28-19-11-34.gh-issue-134291.IiB9Id.rst deleted file mode 100644 index 1605bcc3574..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-28-19-11-34.gh-issue-134291.IiB9Id.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove some newer macOS API usage from the JIT compiler in order to restore -compatibility with older OSX 10.15 deployment targets. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-31-23-02-02.gh-issue-137291.kIxVZd.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-31-23-02-02.gh-issue-137291.kIxVZd.rst deleted file mode 100644 index 0995e3b4644..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-31-23-02-02.gh-issue-137291.kIxVZd.rst +++ /dev/null @@ -1 +0,0 @@ -The perf profiler can now be used if a previous frame evaluation API has been provided. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-01-18-54-31.gh-issue-137288.FhE7ku.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-01-18-54-31.gh-issue-137288.FhE7ku.rst deleted file mode 100644 index 37c143f18e7..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-01-18-54-31.gh-issue-137288.FhE7ku.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where some bytecode instructions of a boolean expression are not -associated with the correct exception handler. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-10-27-53.gh-issue-137308.at05p_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-10-27-53.gh-issue-137308.at05p_.rst deleted file mode 100644 index 8003de422b2..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-10-27-53.gh-issue-137308.at05p_.rst +++ /dev/null @@ -1,3 +0,0 @@ -A standalone docstring in a node body is optimized as a :keyword:`pass` -statement to ensure that the node's body is never empty. There was a -:exc:`ValueError` in :func:`compile` otherwise. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst deleted file mode 100644 index 09d0c3e68fc..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-02-23-04-57.gh-issue-137314.wjEdzD.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fixed a regression where raw f-strings incorrectly interpreted -escape sequences in format specifications. Raw f-strings now properly preserve -literal backslashes in format specs, matching the behavior from Python 3.11. -For example, ``rf"{obj:\xFF}"`` now correctly produces ``'\\xFF'`` instead of -``'ÿ'``. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-10-22-15.gh-issue-136966.J5lrE0.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-10-22-15.gh-issue-136966.J5lrE0.rst deleted file mode 100644 index aafd9ca4db4..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-10-22-15.gh-issue-136966.J5lrE0.rst +++ /dev/null @@ -1,4 +0,0 @@ -The :attr:`object.__dict__` and :attr:`!__weakref__` descriptors now use a -single descriptor instance per interpreter, shared across all types that -need them. -This speeds up class creation, and helps avoid reference cycles. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-17-22-24.gh-issue-58124.q1__53.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-17-22-24.gh-issue-58124.q1__53.rst deleted file mode 100644 index f875d4c5e78..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-17-22-24.gh-issue-58124.q1__53.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix name of the Python encoding in Unicode errors of the code page codec: -use "cp65000" and "cp65001" instead of "CP_UTF7" and "CP_UTF8" which are not -valid Python code names. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-20-24-12.gh-issue-120037.MB7MmI.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-20-24-12.gh-issue-120037.MB7MmI.rst deleted file mode 100644 index 15b8b8f3648..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-05-20-24-12.gh-issue-120037.MB7MmI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disable user site packages directory when a ``._pth`` file is used, even if -it contains ``import site``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-15-39-54.gh-issue-137400.xIw0zs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-15-39-54.gh-issue-137400.xIw0zs.rst deleted file mode 100644 index a464cf48948..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-06-15-39-54.gh-issue-137400.xIw0zs.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a crash in the :term:`free threading` build when disabling profiling or tracing -across all threads with :c:func:`PyEval_SetProfileAllThreads` or -:c:func:`PyEval_SetTraceAllThreads` or their Python equivalents -:func:`threading.settrace_all_threads` and :func:`threading.setprofile_all_threads`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-07-09-52-19.gh-issue-137400.AK1dy-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-07-09-52-19.gh-issue-137400.AK1dy-.rst deleted file mode 100644 index 406d6528840..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-07-09-52-19.gh-issue-137400.AK1dy-.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a crash in the :term:`free threading` build when disabling profiling or -tracing across all threads with :c:func:`PyEval_SetProfileAllThreads` or -:c:func:`PyEval_SetTraceAllThreads` or their Python equivalents -:func:`threading.settrace_all_threads` and -:func:`threading.setprofile_all_threads`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-10-21-34-12.gh-issue-137576.0ZicS-.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-10-21-34-12.gh-issue-137576.0ZicS-.rst deleted file mode 100644 index 19e0f3bf10e..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-10-21-34-12.gh-issue-137576.0ZicS-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix for incorrect source code being shown in tracebacks from the Basic REPL -when :envvar:`PYTHONSTARTUP` is given. Patch by Adam Hartz. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-13-16-58-58.gh-issue-137716.ZcZSyi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-13-16-58-58.gh-issue-137716.ZcZSyi.rst deleted file mode 100644 index 82d8e157790..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-13-16-58-58.gh-issue-137716.ZcZSyi.rst +++ /dev/null @@ -1 +0,0 @@ -Fix double period in :exc:`AttributeError` message for invalid mock assertions diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-14-14-18-29.gh-issue-137728.HdYS9R.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-14-14-18-29.gh-issue-137728.HdYS9R.rst deleted file mode 100644 index cc4a55ddf38..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-14-14-18-29.gh-issue-137728.HdYS9R.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the JIT's handling of many local variables. This previously caused a segfault. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-15-45-26.gh-issue-137079.YEow69.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-15-45-26.gh-issue-137079.YEow69.rst deleted file mode 100644 index 5f01a234845..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-15-45-26.gh-issue-137079.YEow69.rst +++ /dev/null @@ -1 +0,0 @@ -Fix keyword typo recognition when parsing files. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-17-13-36-53.gh-issue-137883.55VDCN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-17-13-36-53.gh-issue-137883.55VDCN.rst deleted file mode 100644 index 0bdb2638c86..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-17-13-36-53.gh-issue-137883.55VDCN.rst +++ /dev/null @@ -1 +0,0 @@ -Fix runaway recursion when calling a function with keyword arguments. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-19-16-07-07.gh-issue-137959.EWj0RZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-19-16-07-07.gh-issue-137959.EWj0RZ.rst deleted file mode 100644 index d1b2650fee6..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-19-16-07-07.gh-issue-137959.EWj0RZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Replace the shim code added to every piece of jitted code with a single -trampoline function. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-19-18-52-22.gh-issue-137967.uw67Ys.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-19-18-52-22.gh-issue-137967.uw67Ys.rst deleted file mode 100644 index 717cdecdfcc..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-19-18-52-22.gh-issue-137967.uw67Ys.rst +++ /dev/null @@ -1 +0,0 @@ -Show error suggestions on nested attribute access. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-22-11-39-40.gh-issue-137384.j4b_in.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-22-11-39-40.gh-issue-137384.j4b_in.rst deleted file mode 100644 index 583d751a460..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-22-11-39-40.gh-issue-137384.j4b_in.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a crash when using the :mod:`warnings` module in a finalizer at shutdown. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst new file mode 100644 index 00000000000..7c554cf8dda --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-06-05-21-25.gh-issue-100964.TxPf1b.rst @@ -0,0 +1 @@ +Fix reference cycle in exhausted generator frames. Patch by Savannah Ostrowski. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-05-24-24.gh-issue-134584.tJ1usH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-05-24-24.gh-issue-134584.tJ1usH.rst new file mode 100644 index 00000000000..aa096fc827d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-05-24-24.gh-issue-134584.tJ1usH.rst @@ -0,0 +1 @@ +Eliminate redundant refcounting from ``_STORE_ATTR_WITH_HINT``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-05-52-37.gh-issue-134584.VsfOQR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-05-52-37.gh-issue-134584.VsfOQR.rst new file mode 100644 index 00000000000..d92f2c166c5 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-05-52-37.gh-issue-134584.VsfOQR.rst @@ -0,0 +1 @@ +Eliminate redundant refcounting from ``_LOAD_ATTR_INSTANCE_VALUE``. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-11-56-20.gh-issue-142766.Uy2HTm.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-11-56-20.gh-issue-142766.Uy2HTm.rst new file mode 100644 index 00000000000..6a14976a6dc --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-11-56-20.gh-issue-142766.Uy2HTm.rst @@ -0,0 +1 @@ +Clear the frame of a generator when :meth:`generator.close` is called. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-23-26-41.gh-issue-142543.wJKjBs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-23-26-41.gh-issue-142543.wJKjBs.rst new file mode 100644 index 00000000000..0897127fec7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-16-23-26-41.gh-issue-142543.wJKjBs.rst @@ -0,0 +1 @@ +Fix a stack overflow on Clang JIT build configurations with full LTO. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-20-31-09.gh-issue-139757.6DWxeQ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-20-31-09.gh-issue-139757.6DWxeQ.rst new file mode 100644 index 00000000000..3c476d3eaea --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-20-31-09.gh-issue-139757.6DWxeQ.rst @@ -0,0 +1 @@ +Fix building JIT stencils on free-threaded builds. diff --git a/Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst b/Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst deleted file mode 100644 index ce3eba154ba..00000000000 --- a/Misc/NEWS.d/next/Documentation/2021-09-15-13-07-25.bpo-45210.RtGk7i.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document that error indicator may be set in tp_dealloc, and how to avoid -clobbering it. diff --git a/Misc/NEWS.d/next/Documentation/2025-06-10-17-02-06.gh-issue-135171.quHvts.rst b/Misc/NEWS.d/next/Documentation/2025-06-10-17-02-06.gh-issue-135171.quHvts.rst deleted file mode 100644 index 129ff74189b..00000000000 --- a/Misc/NEWS.d/next/Documentation/2025-06-10-17-02-06.gh-issue-135171.quHvts.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document that the :term:`iterator` for the leftmost :keyword:`!for` clause -in the generator expression is created immediately. diff --git a/Misc/NEWS.d/next/Documentation/2025-07-01-23-00-58.gh-issue-136155.4siQQO.rst b/Misc/NEWS.d/next/Documentation/2025-07-01-23-00-58.gh-issue-136155.4siQQO.rst deleted file mode 100644 index 70f54936c80..00000000000 --- a/Misc/NEWS.d/next/Documentation/2025-07-01-23-00-58.gh-issue-136155.4siQQO.rst +++ /dev/null @@ -1 +0,0 @@ -We are now checking for fatal errors in EPUB builds in CI. diff --git a/Misc/NEWS.d/next/Library/2017-12-30-18-21-00.bpo-28494.Dt_Wks.rst b/Misc/NEWS.d/next/Library/2017-12-30-18-21-00.bpo-28494.Dt_Wks.rst deleted file mode 100644 index 0c518983770..00000000000 --- a/Misc/NEWS.d/next/Library/2017-12-30-18-21-00.bpo-28494.Dt_Wks.rst +++ /dev/null @@ -1 +0,0 @@ -Improve Zip file validation false positive rate in :func:`zipfile.is_zipfile`. diff --git a/Misc/NEWS.d/next/Library/2020-09-23-11-54-17.bpo-41839.kU5Ywl.rst b/Misc/NEWS.d/next/Library/2020-09-23-11-54-17.bpo-41839.kU5Ywl.rst deleted file mode 100644 index 76066040810..00000000000 --- a/Misc/NEWS.d/next/Library/2020-09-23-11-54-17.bpo-41839.kU5Ywl.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow negative priority values from :func:`os.sched_get_priority_min` and -:func:`os.sched_get_priority_max` functions. diff --git a/Misc/NEWS.d/next/Library/2021-09-21-17-17-29.gh-issue-84683.wDSRsG.rst b/Misc/NEWS.d/next/Library/2021-09-21-17-17-29.gh-issue-84683.wDSRsG.rst deleted file mode 100644 index 66f76bda6ad..00000000000 --- a/Misc/NEWS.d/next/Library/2021-09-21-17-17-29.gh-issue-84683.wDSRsG.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`zoneinfo`: Check in ``<prefix>/share/zoneinfo`` for data files on Windows diff --git a/Misc/NEWS.d/next/Library/2021-12-18-12-46-20.bpo-45959.vPlr3P.rst b/Misc/NEWS.d/next/Library/2021-12-18-12-46-20.bpo-45959.vPlr3P.rst deleted file mode 100644 index bcafa64d263..00000000000 --- a/Misc/NEWS.d/next/Library/2021-12-18-12-46-20.bpo-45959.vPlr3P.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`pprint` can now pretty-print dict views. diff --git a/Misc/NEWS.d/next/Library/2022-01-07-16-56-57.bpo-38735.NFfJX6.rst b/Misc/NEWS.d/next/Library/2022-01-07-16-56-57.bpo-38735.NFfJX6.rst deleted file mode 100644 index 7f4ea04284e..00000000000 --- a/Misc/NEWS.d/next/Library/2022-01-07-16-56-57.bpo-38735.NFfJX6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix failure when importing a module from the root directory on unix-like -platforms with sys.pycache_prefix set. diff --git a/Misc/NEWS.d/next/Library/2022-07-24-20-56-32.gh-issue-69426.unccw7.rst b/Misc/NEWS.d/next/Library/2022-07-24-20-56-32.gh-issue-69426.unccw7.rst deleted file mode 100644 index d8c081390d0..00000000000 --- a/Misc/NEWS.d/next/Library/2022-07-24-20-56-32.gh-issue-69426.unccw7.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :class:`html.parser.HTMLParser` to not unescape character entities in -attribute values if they are followed by an ASCII alphanumeric or an equals -sign. diff --git a/Misc/NEWS.d/next/Library/2023-02-13-21-41-34.gh-issue-86155.ppIGSC.rst b/Misc/NEWS.d/next/Library/2023-02-13-21-41-34.gh-issue-86155.ppIGSC.rst deleted file mode 100644 index bb85481b229..00000000000 --- a/Misc/NEWS.d/next/Library/2023-02-13-21-41-34.gh-issue-86155.ppIGSC.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`html.parser.HTMLParser.close` no longer loses data when the -``<script>`` tag is not closed. Patch by Waylan Limberg. diff --git a/Misc/NEWS.d/next/Library/2023-02-13-21-56-38.gh-issue-62824.CBZzX3.rst b/Misc/NEWS.d/next/Library/2023-02-13-21-56-38.gh-issue-62824.CBZzX3.rst deleted file mode 100644 index 1fe4e47c9ec..00000000000 --- a/Misc/NEWS.d/next/Library/2023-02-13-21-56-38.gh-issue-62824.CBZzX3.rst +++ /dev/null @@ -1 +0,0 @@ -Fix aliases for ``iso8859_8`` encoding. Patch by Dave Goncalves. diff --git a/Misc/NEWS.d/next/Library/2023-03-13-22-51-40.gh-issue-99813.40TV02.rst b/Misc/NEWS.d/next/Library/2023-03-13-22-51-40.gh-issue-99813.40TV02.rst deleted file mode 100644 index c511c630214..00000000000 --- a/Misc/NEWS.d/next/Library/2023-03-13-22-51-40.gh-issue-99813.40TV02.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`ssl` now uses ``SSL_sendfile`` internally when it is possible (see -:data:`~ssl.OP_ENABLE_KTLS`). The function sends a file more efficiently -because it performs TLS encryption in the kernel to avoid additional context -switches. Patch by Illia Volochii. diff --git a/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst b/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst deleted file mode 100644 index f4f2db08f73..00000000000 --- a/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst +++ /dev/null @@ -1 +0,0 @@ -Fix flag mask inversion when unnamed flags exist. diff --git a/Misc/NEWS.d/next/Library/2024-06-06-17-49-07.gh-issue-120170.DUxhmT.rst b/Misc/NEWS.d/next/Library/2024-06-06-17-49-07.gh-issue-120170.DUxhmT.rst deleted file mode 100644 index ce7d874aa20..00000000000 --- a/Misc/NEWS.d/next/Library/2024-06-06-17-49-07.gh-issue-120170.DUxhmT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an issue in the :mod:`!_pickle` extension module in which importing -:mod:`multiprocessing` could change how pickle identifies which module an -object belongs to, potentially breaking the unpickling of those objects. diff --git a/Misc/NEWS.d/next/Library/2024-07-16-00-01-04.gh-issue-99631.GWD4fD.rst b/Misc/NEWS.d/next/Library/2024-07-16-00-01-04.gh-issue-99631.GWD4fD.rst deleted file mode 100644 index 735249b4dae..00000000000 --- a/Misc/NEWS.d/next/Library/2024-07-16-00-01-04.gh-issue-99631.GWD4fD.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`shelve` module now accepts custom serialization -and deserialization functions. diff --git a/Misc/NEWS.d/next/Library/2024-09-13-09-43-15.gh-issue-120492.Mm6CJ6.rst b/Misc/NEWS.d/next/Library/2024-09-13-09-43-15.gh-issue-120492.Mm6CJ6.rst deleted file mode 100644 index a9652b9fcfc..00000000000 --- a/Misc/NEWS.d/next/Library/2024-09-13-09-43-15.gh-issue-120492.Mm6CJ6.rst +++ /dev/null @@ -1,2 +0,0 @@ -``importlib.metadata`` now prioritizes valid dists to invalid dists when -retrieving by name. diff --git a/Misc/NEWS.d/next/Library/2024-09-13-09-46-47.gh-issue-91216.LuOsF4.rst b/Misc/NEWS.d/next/Library/2024-09-13-09-46-47.gh-issue-91216.LuOsF4.rst deleted file mode 100644 index bb90588b2e7..00000000000 --- a/Misc/NEWS.d/next/Library/2024-09-13-09-46-47.gh-issue-91216.LuOsF4.rst +++ /dev/null @@ -1,2 +0,0 @@ -``importlib.metadata`` now raises a ``KeyError`` instead of returning -``None`` when a key is missing from the metadata. diff --git a/Misc/NEWS.d/next/Library/2024-09-13-09-48-25.gh-issue-124033.WNudS0.rst b/Misc/NEWS.d/next/Library/2024-09-13-09-48-25.gh-issue-124033.WNudS0.rst deleted file mode 100644 index f422ab01a5f..00000000000 --- a/Misc/NEWS.d/next/Library/2024-09-13-09-48-25.gh-issue-124033.WNudS0.rst +++ /dev/null @@ -1 +0,0 @@ -``SimplePath`` is now presented in ``importlib.metadata.__all__``. diff --git a/Misc/NEWS.d/next/Library/2024-10-17-01-12-22.gh-issue-119109.u4hcvb.rst b/Misc/NEWS.d/next/Library/2024-10-17-01-12-22.gh-issue-119109.u4hcvb.rst deleted file mode 100644 index 782b2eb8d74..00000000000 --- a/Misc/NEWS.d/next/Library/2024-10-17-01-12-22.gh-issue-119109.u4hcvb.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`functools.partial` calls are now faster when keyword arguments are used. diff --git a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst b/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst deleted file mode 100644 index ec8f3a75006..00000000000 --- a/Misc/NEWS.d/next/Library/2024-10-22-16-21-55.gh-issue-125843.2ttzYo.rst +++ /dev/null @@ -1,2 +0,0 @@ -If possible, indicate which :mod:`curses` C function or macro is responsible -for raising a :exc:`curses.error` exception. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2024-10-28-06-54-22.gh-issue-125028.GEY8Ws.rst b/Misc/NEWS.d/next/Library/2024-10-28-06-54-22.gh-issue-125028.GEY8Ws.rst deleted file mode 100644 index 09ebee4d41b..00000000000 --- a/Misc/NEWS.d/next/Library/2024-10-28-06-54-22.gh-issue-125028.GEY8Ws.rst +++ /dev/null @@ -1 +0,0 @@ -:data:`functools.Placeholder` cannot be passed to :func:`functools.partial` as a keyword argument. diff --git a/Misc/NEWS.d/next/Library/2024-11-25-10-22-08.gh-issue-126883.MAEF7g.rst b/Misc/NEWS.d/next/Library/2024-11-25-10-22-08.gh-issue-126883.MAEF7g.rst deleted file mode 100644 index 5e3fa39acf1..00000000000 --- a/Misc/NEWS.d/next/Library/2024-11-25-10-22-08.gh-issue-126883.MAEF7g.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add check that timezone fields are in range for -:meth:`datetime.datetime.fromisoformat` and -:meth:`datetime.time.fromisoformat`. Patch by Semyon Moroz. diff --git a/Misc/NEWS.d/next/Library/2025-03-09-03-13-41.gh-issue-130999.tBRBVB.rst b/Misc/NEWS.d/next/Library/2025-03-09-03-13-41.gh-issue-130999.tBRBVB.rst deleted file mode 100644 index 157522f9aab..00000000000 --- a/Misc/NEWS.d/next/Library/2025-03-09-03-13-41.gh-issue-130999.tBRBVB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid exiting the new REPL and offer suggestions even if there are non-string -candidates when errors occur. diff --git a/Misc/NEWS.d/next/Library/2025-03-11-05-24-14.gh-issue-130664.g0yNMm.rst b/Misc/NEWS.d/next/Library/2025-03-11-05-24-14.gh-issue-130664.g0yNMm.rst deleted file mode 100644 index dbe783a2a99..00000000000 --- a/Misc/NEWS.d/next/Library/2025-03-11-05-24-14.gh-issue-130664.g0yNMm.rst +++ /dev/null @@ -1,4 +0,0 @@ -Handle corner-case for :class:`~fractions.Fraction`'s formatting: treat -zero-padding (preceding the width field by a zero (``'0'``) character) as an -equivalent to a fill character of ``'0'`` with an alignment type of ``'='``, -just as in case of :class:`float`'s. diff --git a/Misc/NEWS.d/next/Library/2025-03-13-20-48-58.gh-issue-123471.cM4w4f.rst b/Misc/NEWS.d/next/Library/2025-03-13-20-48-58.gh-issue-123471.cM4w4f.rst deleted file mode 100644 index cfc783900de..00000000000 --- a/Misc/NEWS.d/next/Library/2025-03-13-20-48-58.gh-issue-123471.cM4w4f.rst +++ /dev/null @@ -1 +0,0 @@ -Make concurrent iterations over :class:`itertools.cycle` safe under free-threading. diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst deleted file mode 100644 index 6d8bc0959ae..00000000000 --- a/Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst +++ /dev/null @@ -1,6 +0,0 @@ -Fix :class:`calendar.TextCalendar`, :class:`calendar.HTMLCalendar`, -and the :mod:`calendar` CLI to display month names in the nominative -case by adding :data:`calendar.standalone_month_name` and -:data:`calendar.standalone_month_abbr`, which provide month names and -abbreviations in the grammatical form used when a month name stands by -itself, if the locale supports it. diff --git a/Misc/NEWS.d/next/Library/2025-03-19-12-41-42.gh-issue-91349.8eTOCP.rst b/Misc/NEWS.d/next/Library/2025-03-19-12-41-42.gh-issue-91349.8eTOCP.rst deleted file mode 100644 index 0e866fa4ef6..00000000000 --- a/Misc/NEWS.d/next/Library/2025-03-19-12-41-42.gh-issue-91349.8eTOCP.rst +++ /dev/null @@ -1,3 +0,0 @@ -Adjust default ``compressionlevel=`` to 6 (down from 9) in :mod:`gzip` and :mod:`tarfile`. -It is the default level used by most compression tools and a better -tradeoff between speed and performance. diff --git a/Misc/NEWS.d/next/Library/2025-03-27-08-13-32.gh-issue-131788.0RWiFc.rst b/Misc/NEWS.d/next/Library/2025-03-27-08-13-32.gh-issue-131788.0RWiFc.rst deleted file mode 100644 index 525802405bd..00000000000 --- a/Misc/NEWS.d/next/Library/2025-03-27-08-13-32.gh-issue-131788.0RWiFc.rst +++ /dev/null @@ -1 +0,0 @@ -Make ``ResourceTracker.send`` from :mod:`multiprocessing` re-entrant safe diff --git a/Misc/NEWS.d/next/Library/2025-04-07-06-41-54.gh-issue-131884.ym9BJN.rst b/Misc/NEWS.d/next/Library/2025-04-07-06-41-54.gh-issue-131884.ym9BJN.rst deleted file mode 100644 index d9e2eae02dc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-07-06-41-54.gh-issue-131884.ym9BJN.rst +++ /dev/null @@ -1 +0,0 @@ -Fix formatting issues in :func:`json.dump` when both *indent* and *skipkeys* are used. diff --git a/Misc/NEWS.d/next/Library/2025-04-07-09-53-54.gh-issue-87790.6nj3zQ.rst b/Misc/NEWS.d/next/Library/2025-04-07-09-53-54.gh-issue-87790.6nj3zQ.rst deleted file mode 100644 index cf80c71271b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-07-09-53-54.gh-issue-87790.6nj3zQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support underscore and comma as thousands separators in the fractional part -for :class:`~decimal.Decimal`'s formatting. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2025-04-07-10-20-16.gh-issue-87790.X2SjJe.rst b/Misc/NEWS.d/next/Library/2025-04-07-10-20-16.gh-issue-87790.X2SjJe.rst deleted file mode 100644 index be2a30d69ca..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-07-10-20-16.gh-issue-87790.X2SjJe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support underscore and comma as thousands separators in the fractional part -for :class:`~fractions.Fraction`'s formatting. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2025-04-08-07-25-10.gh-issue-107583.JGfbhq.rst b/Misc/NEWS.d/next/Library/2025-04-08-07-25-10.gh-issue-107583.JGfbhq.rst deleted file mode 100644 index 42356126273..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-08-07-25-10.gh-issue-107583.JGfbhq.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix :class:`!Flag` inversion when flag set has missing values -(:class:`!IntFlag` still flips all bits); fix negative assigned values -during flag creation (both :class:`!Flag` and :class:`!IntFlag` ignore -missing values). diff --git a/Misc/NEWS.d/next/Library/2025-04-16-21-02-57.gh-issue-132551.Psa7pL.rst b/Misc/NEWS.d/next/Library/2025-04-16-21-02-57.gh-issue-132551.Psa7pL.rst deleted file mode 100644 index c8743d49ca0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-16-21-02-57.gh-issue-132551.Psa7pL.rst +++ /dev/null @@ -1 +0,0 @@ -Make :class:`io.BytesIO` safe in :term:`free-threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst b/Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst deleted file mode 100644 index a99669a1bc0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix libc thread safety issues with :mod:`pwd` by locking access to -``getpwall``. diff --git a/Misc/NEWS.d/next/Library/2025-04-21-01-03-15.gh-issue-127081.WXRliX.rst b/Misc/NEWS.d/next/Library/2025-04-21-01-03-15.gh-issue-127081.WXRliX.rst deleted file mode 100644 index 63fed60ced0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-21-01-03-15.gh-issue-127081.WXRliX.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix libc thread safety issues with :mod:`os` by replacing ``getlogin`` with -``getlogin_r`` re-entrant version. diff --git a/Misc/NEWS.d/next/Library/2025-04-21-01-05-14.gh-issue-127081.Egrpq7.rst b/Misc/NEWS.d/next/Library/2025-04-21-01-05-14.gh-issue-127081.Egrpq7.rst deleted file mode 100644 index 30643673bf9..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-21-01-05-14.gh-issue-127081.Egrpq7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix libc thread safety issues with :mod:`dbm` by performing stateful -operations in critical sections. diff --git a/Misc/NEWS.d/next/Library/2025-04-22-21-00-23.gh-issue-123471.asOLA2.rst b/Misc/NEWS.d/next/Library/2025-04-22-21-00-23.gh-issue-123471.asOLA2.rst deleted file mode 100644 index a4b4b6d2c23..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-22-21-00-23.gh-issue-123471.asOLA2.rst +++ /dev/null @@ -1 +0,0 @@ -Make concurrent iterations over :class:`itertools.combinations` and :class:`itertools.product` safe under free-threading. diff --git a/Misc/NEWS.d/next/Library/2025-04-25-11-48-00.gh-issue-122781.ajsdns.rst b/Misc/NEWS.d/next/Library/2025-04-25-11-48-00.gh-issue-122781.ajsdns.rst deleted file mode 100644 index 5a9a0cdf798..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-25-11-48-00.gh-issue-122781.ajsdns.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``%z`` directive in :func:`datetime.datetime.strptime` to allow for no provided -offset as was documented. diff --git a/Misc/NEWS.d/next/Library/2025-04-25-11-53-37.gh-issue-95380.7dvPe-.rst b/Misc/NEWS.d/next/Library/2025-04-25-11-53-37.gh-issue-95380.7dvPe-.rst deleted file mode 100644 index 8dcc6190cfd..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-25-11-53-37.gh-issue-95380.7dvPe-.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`fcntl.fcntl` and :func:`fcntl.ioctl`: Remove the 1024 bytes limit -on the size of not mutated bytes-like argument. diff --git a/Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst b/Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst deleted file mode 100644 index e33b061bb9b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :func:`math.isnormal` and :func:`math.issubnormal` functions. Patch by -Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2025-04-26-15-50-12.gh-issue-133009.etBuz5.rst b/Misc/NEWS.d/next/Library/2025-04-26-15-50-12.gh-issue-133009.etBuz5.rst deleted file mode 100644 index 1f7155c6a40..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-26-15-50-12.gh-issue-133009.etBuz5.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`xml.etree.ElementTree`: Fix a crash in :meth:`Element.__deepcopy__ -<object.__deepcopy__>` when the element is concurrently mutated. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-04-29-11-48-46.gh-issue-132876.lyTQGZ.rst b/Misc/NEWS.d/next/Library/2025-04-29-11-48-46.gh-issue-132876.lyTQGZ.rst deleted file mode 100644 index cb3ca3321e3..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-29-11-48-46.gh-issue-132876.lyTQGZ.rst +++ /dev/null @@ -1,4 +0,0 @@ -``ldexp()`` on Windows doesn't round subnormal results before Windows 11, -but should. Python's :func:`math.ldexp` wrapper now does round them, so -results may change slightly, in rare cases of very small results, on -Windows versions before 11. diff --git a/Misc/NEWS.d/next/Library/2025-04-30-19-32-18.gh-issue-132969.EagQ3G.rst b/Misc/NEWS.d/next/Library/2025-04-30-19-32-18.gh-issue-132969.EagQ3G.rst deleted file mode 100644 index 7364c425941..00000000000 --- a/Misc/NEWS.d/next/Library/2025-04-30-19-32-18.gh-issue-132969.EagQ3G.rst +++ /dev/null @@ -1,7 +0,0 @@ -Prevent the :class:`~concurrent.futures.ProcessPoolExecutor` executor thread, -which remains running when :meth:`shutdown(wait=False) -<concurrent.futures.Executor.shutdown>`, from -attempting to adjust the pool's worker processes after the object state has already been reset during shutdown. -A combination of conditions, including a worker process having terminated abormally, -resulted in an exception and a potential hang when the still-running executor thread -attempted to replace dead workers within the pool. diff --git a/Misc/NEWS.d/next/Library/2025-05-01-10-56-44.gh-issue-132813.rKurvp.rst b/Misc/NEWS.d/next/Library/2025-05-01-10-56-44.gh-issue-132813.rKurvp.rst deleted file mode 100644 index 55608528a45..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-01-10-56-44.gh-issue-132813.rKurvp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error messages for incorrect types and values of :class:`csv.Dialect` -attributes. diff --git a/Misc/NEWS.d/next/Library/2025-05-01-16-03-11.gh-issue-133017.k7RLQp.rst b/Misc/NEWS.d/next/Library/2025-05-01-16-03-11.gh-issue-133017.k7RLQp.rst deleted file mode 100644 index 1b5bf74fb47..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-01-16-03-11.gh-issue-133017.k7RLQp.rst +++ /dev/null @@ -1,4 +0,0 @@ -Improve the error message of :func:`multiprocessing.sharedctypes.Array`, -:func:`multiprocessing.sharedctypes.RawArray`, :func:`multiprocessing.sharedctypes.Value` and -:func:`multiprocessing.sharedctypes.RawValue` when an invalid typecode is passed. Patch -by Tomas Roun diff --git a/Misc/NEWS.d/next/Library/2025-05-04-17-04-55.gh-issue-132493.huirKi.rst b/Misc/NEWS.d/next/Library/2025-05-04-17-04-55.gh-issue-132493.huirKi.rst deleted file mode 100644 index ad06ee6b7a2..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-04-17-04-55.gh-issue-132493.huirKi.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid accessing ``__annotations__`` unnecessarily in -:func:`inspect.signature`. diff --git a/Misc/NEWS.d/next/Library/2025-05-05-03-14-08.gh-issue-133390.AuTggn.rst b/Misc/NEWS.d/next/Library/2025-05-05-03-14-08.gh-issue-133390.AuTggn.rst deleted file mode 100644 index 943e4addebc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-05-03-14-08.gh-issue-133390.AuTggn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support keyword completion in the :mod:`sqlite3` command-line interface and add -:data:`sqlite3.SQLITE_KEYWORDS` constant. diff --git a/Misc/NEWS.d/next/Library/2025-05-05-10-41-41.gh-issue-133253.J5-xDD.rst b/Misc/NEWS.d/next/Library/2025-05-05-10-41-41.gh-issue-133253.J5-xDD.rst deleted file mode 100644 index 7009ca258bc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-05-10-41-41.gh-issue-133253.J5-xDD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix thread-safety issues in :mod:`linecache`. diff --git a/Misc/NEWS.d/next/Library/2025-05-05-18-50-00.gh-issue-133447.ajshdb.rst b/Misc/NEWS.d/next/Library/2025-05-05-18-50-00.gh-issue-133447.ajshdb.rst deleted file mode 100644 index f453690cab2..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-05-18-50-00.gh-issue-133447.ajshdb.rst +++ /dev/null @@ -1 +0,0 @@ -Add basic color to :mod:`sqlite3` CLI interface. diff --git a/Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst b/Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst deleted file mode 100644 index e0a3ce98bf7..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix dot commands with trailing spaces are mistaken for multi-line SQL -statements in the sqlite3 command-line interface. diff --git a/Misc/NEWS.d/next/Library/2025-05-06-14-44-55.gh-issue-133517.Ca6NgW.rst b/Misc/NEWS.d/next/Library/2025-05-06-14-44-55.gh-issue-133517.Ca6NgW.rst deleted file mode 100644 index 7c53fc484a8..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-06-14-44-55.gh-issue-133517.Ca6NgW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove :func:`os.listdrives`, :func:`os.listvolumes` and :func:`os.listmounts` -in non Windows desktop builds since the underlying functionality is missing. diff --git a/Misc/NEWS.d/next/Library/2025-05-06-22-54-37.gh-issue-133551.rfy1tJ.rst b/Misc/NEWS.d/next/Library/2025-05-06-22-54-37.gh-issue-133551.rfy1tJ.rst deleted file mode 100644 index 7fedc0818dc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-06-22-54-37.gh-issue-133551.rfy1tJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support t-strings (:pep:`750`) in :mod:`annotationlib`. Patch by Jelle -Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2025-05-07-13-31-06.gh-issue-92897.ubeqGE.rst b/Misc/NEWS.d/next/Library/2025-05-07-13-31-06.gh-issue-92897.ubeqGE.rst deleted file mode 100644 index 647166bfcf8..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-07-13-31-06.gh-issue-92897.ubeqGE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed the ``check_home`` parameter from :func:`sysconfig.is_python_build`, -deprecated since Python 3.12. diff --git a/Misc/NEWS.d/next/Library/2025-05-07-14-36-30.gh-issue-133577.BggPk9.rst b/Misc/NEWS.d/next/Library/2025-05-07-14-36-30.gh-issue-133577.BggPk9.rst deleted file mode 100644 index 9d056983439..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-07-14-36-30.gh-issue-133577.BggPk9.rst +++ /dev/null @@ -1 +0,0 @@ -Add parameter ``formatter`` to :func:`logging.basicConfig`. diff --git a/Misc/NEWS.d/next/Library/2025-05-07-19-16-41.gh-issue-133581.kERUCJ.rst b/Misc/NEWS.d/next/Library/2025-05-07-19-16-41.gh-issue-133581.kERUCJ.rst deleted file mode 100644 index 3749904cd9b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-07-19-16-41.gh-issue-133581.kERUCJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -Improve unparsing of t-strings in :func:`ast.unparse` and ``from __future__ -import annotations``. Empty t-strings now round-trip correctly and -formatting in interpolations is preserved. -Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2025-05-07-22-15-15.gh-issue-133595.c3U88r.rst b/Misc/NEWS.d/next/Library/2025-05-07-22-15-15.gh-issue-133595.c3U88r.rst deleted file mode 100644 index a61c4bf1913..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-07-22-15-15.gh-issue-133595.c3U88r.rst +++ /dev/null @@ -1,7 +0,0 @@ -Clean up :class:`sqlite3.Connection` APIs. All parameters of -:func:`sqlite3.connect` except *database* are now keyword-only. The first -three parameters of methods :meth:`~sqlite3.Connection.create_function` and -:meth:`~sqlite3.Connection.create_aggregate` are now positional-only. The -first parameter of methods :meth:`~sqlite3.Connection.set_authorizer`, -:meth:`~sqlite3.Connection.set_progress_handler` and -:meth:`~sqlite3.Connection.set_trace_callback` is now positional-only. diff --git a/Misc/NEWS.d/next/Library/2025-05-08-13-43-19.gh-issue-133489.9eGS1Z.rst b/Misc/NEWS.d/next/Library/2025-05-08-13-43-19.gh-issue-133489.9eGS1Z.rst deleted file mode 100644 index 0c07beb7693..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-08-13-43-19.gh-issue-133489.9eGS1Z.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`random.getrandbits` can now generate more that 2\ :sup:`31` bits. -:func:`random.randbytes` can now generate more that 256 MiB. diff --git a/Misc/NEWS.d/next/Library/2025-05-08-20-03-20.gh-issue-133722.1-B82a.rst b/Misc/NEWS.d/next/Library/2025-05-08-20-03-20.gh-issue-133722.1-B82a.rst deleted file mode 100644 index 86f24441249..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-08-20-03-20.gh-issue-133722.1-B82a.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added a *color* option to :func:`difflib.unified_diff` that colors output -similar to :program:`git diff`. diff --git a/Misc/NEWS.d/next/Library/2025-05-09-08-49-03.gh-issue-133701.KI8tGz.rst b/Misc/NEWS.d/next/Library/2025-05-09-08-49-03.gh-issue-133701.KI8tGz.rst deleted file mode 100644 index 163d9b331d1..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-09-08-49-03.gh-issue-133701.KI8tGz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bug where :class:`typing.TypedDict` classes defined under ``from -__future__ import annotations`` and inheriting from another ``TypedDict`` -had an incorrect ``__annotations__`` attribute. diff --git a/Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst b/Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst deleted file mode 100644 index 00b556c6a33..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst +++ /dev/null @@ -1,2 +0,0 @@ -Speedup pasting in ``PyREPL`` on Windows in a legacy console. Patch by Chris -Eibl. diff --git a/Misc/NEWS.d/next/Library/2025-05-09-15-50-00.gh-issue-77057.fV8SU-.rst b/Misc/NEWS.d/next/Library/2025-05-09-15-50-00.gh-issue-77057.fV8SU-.rst deleted file mode 100644 index 42107de75c7..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-09-15-50-00.gh-issue-77057.fV8SU-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling of invalid markup declarations in -:class:`html.parser.HTMLParser`. diff --git a/Misc/NEWS.d/next/Library/2025-05-09-18-29-25.gh-issue-133684.Y1DFSt.rst b/Misc/NEWS.d/next/Library/2025-05-09-18-29-25.gh-issue-133684.Y1DFSt.rst deleted file mode 100644 index 0cb1bc237a1..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-09-18-29-25.gh-issue-133684.Y1DFSt.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bug where :func:`annotationlib.get_annotations` would return the wrong -result for certain classes that are part of a class hierarchy where ``from -__future__ import annotations`` is used. diff --git a/Misc/NEWS.d/next/Library/2025-05-09-19-05-24.gh-issue-133783.1voCnR.rst b/Misc/NEWS.d/next/Library/2025-05-09-19-05-24.gh-issue-133783.1voCnR.rst deleted file mode 100644 index 62e742df179..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-09-19-05-24.gh-issue-133783.1voCnR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bug with applying :func:`copy.replace` to :mod:`ast` objects. Attributes -that default to ``None`` were incorrectly treated as required for manually -created AST nodes. diff --git a/Misc/NEWS.d/next/Library/2025-05-09-20-59-24.gh-issue-132641.3qTw44.rst b/Misc/NEWS.d/next/Library/2025-05-09-20-59-24.gh-issue-132641.3qTw44.rst deleted file mode 100644 index 419ff19d9c0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-09-20-59-24.gh-issue-132641.3qTw44.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a race in :func:`functools.lru_cache` under free-threading. diff --git a/Misc/NEWS.d/next/Library/2025-05-10-11-04-47.gh-issue-133810.03WhnK.rst b/Misc/NEWS.d/next/Library/2025-05-10-11-04-47.gh-issue-133810.03WhnK.rst deleted file mode 100644 index 4073974e364..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-10-11-04-47.gh-issue-133810.03WhnK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove :class:`!http.server.CGIHTTPRequestHandler` and ``--cgi`` flag from the -:program:`python -m http.server` command-line interface. They were -deprecated in Python 3.13. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-10-12-06-55.gh-issue-133653.Gb2aG4.rst b/Misc/NEWS.d/next/Library/2025-05-10-12-06-55.gh-issue-133653.Gb2aG4.rst deleted file mode 100644 index 56fb1dc31dc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-10-12-06-55.gh-issue-133653.Gb2aG4.rst +++ /dev/null @@ -1,7 +0,0 @@ -Fix :class:`argparse.ArgumentParser` with the *formatter_class* argument. -Fix TypeError when *formatter_class* is a custom subclass of -:class:`!HelpFormatter`. -Fix TypeError when *formatter_class* is not a subclass of -:class:`!HelpFormatter` and non-standard *prefix_char* is used. -Fix support of colorizing when *formatter_class* is not a subclass of -:class:`!HelpFormatter`. diff --git a/Misc/NEWS.d/next/Library/2025-05-10-12-07-54.gh-issue-133817.4GMtKV.rst b/Misc/NEWS.d/next/Library/2025-05-10-12-07-54.gh-issue-133817.4GMtKV.rst deleted file mode 100644 index 326e767de5f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-10-12-07-54.gh-issue-133817.4GMtKV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove support for creating :class:`~typing.NamedTuple` classes via the -undocumented keyword argument syntax. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-11-08-48-55.gh-issue-133823.F8udQy.rst b/Misc/NEWS.d/next/Library/2025-05-11-08-48-55.gh-issue-133823.F8udQy.rst deleted file mode 100644 index 67b44ac3ef3..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-11-08-48-55.gh-issue-133823.F8udQy.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove support for ``TD = TypedDict("TD")`` and ``TD = TypedDict("TD", None)`` -calls for constructing :class:`typing.TypedDict` objects with zero field. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-11-10-01-48.gh-issue-133866.g3dHP_.rst b/Misc/NEWS.d/next/Library/2025-05-11-10-01-48.gh-issue-133866.g3dHP_.rst deleted file mode 100644 index 00f13c9a305..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-11-10-01-48.gh-issue-133866.g3dHP_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the undocumented function :func:`!ctypes.SetPointerType`, -which has been deprecated since Python 3.13. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-11-10-28-11.gh-issue-133873.H03nov.rst b/Misc/NEWS.d/next/Library/2025-05-11-10-28-11.gh-issue-133873.H03nov.rst deleted file mode 100644 index 79f630b2418..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-11-10-28-11.gh-issue-133873.H03nov.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the deprecated ``getmark()``, ``setmark()`` and ``getmarkers()`` -methods of the :class:`~wave.Wave_read` and :class:`~wave.Wave_write` -classes, which were deprecated since Python 3.13. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-11-11-39-05.gh-issue-133875.pUar3l.rst b/Misc/NEWS.d/next/Library/2025-05-11-11-39-05.gh-issue-133875.pUar3l.rst deleted file mode 100644 index b4a2b033637..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-11-11-39-05.gh-issue-133875.pUar3l.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed deprecated :meth:`!pathlib.PurePath.is_reserved`. Use -:func:`os.path.isreserved` to detect reserved paths on Windows. diff --git a/Misc/NEWS.d/next/Library/2025-05-11-12-56-52.gh-issue-133604.kFxhc8.rst b/Misc/NEWS.d/next/Library/2025-05-11-12-56-52.gh-issue-133604.kFxhc8.rst deleted file mode 100644 index 526ac38f09b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-11-12-56-52.gh-issue-133604.kFxhc8.rst +++ /dev/null @@ -1 +0,0 @@ -Remove :func:`!platform.java_ver` which was deprecated since Python 3.13. diff --git a/Misc/NEWS.d/next/Library/2025-05-12-06-52-10.gh-issue-133925.elInBY.rst b/Misc/NEWS.d/next/Library/2025-05-12-06-52-10.gh-issue-133925.elInBY.rst deleted file mode 100644 index 328e28abc3b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-12-06-52-10.gh-issue-133925.elInBY.rst +++ /dev/null @@ -1 +0,0 @@ -Make the private class ``typing._UnionGenericAlias`` hashable. diff --git a/Misc/NEWS.d/next/Library/2025-05-12-20-38-57.gh-issue-133960.Aee79f.rst b/Misc/NEWS.d/next/Library/2025-05-12-20-38-57.gh-issue-133960.Aee79f.rst deleted file mode 100644 index 66e8483b25b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-12-20-38-57.gh-issue-133960.Aee79f.rst +++ /dev/null @@ -1,3 +0,0 @@ -Simplify and improve :func:`typing.evaluate_forward_ref`. It now no longer -raises errors on certain invalid types. In several situations, it is now -able to evaluate forward references that were previously unsupported. diff --git a/Misc/NEWS.d/next/Library/2025-05-13-18-21-59.gh-issue-71253.-3Sf_K.rst b/Misc/NEWS.d/next/Library/2025-05-13-18-21-59.gh-issue-71253.-3Sf_K.rst deleted file mode 100644 index 714d707f488..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-13-18-21-59.gh-issue-71253.-3Sf_K.rst +++ /dev/null @@ -1,3 +0,0 @@ -Raise :exc:`ValueError` in :func:`open` if *opener* returns a negative -file-descriptor in the Python implementation of :mod:`io` to match the -C implementation. diff --git a/Misc/NEWS.d/next/Library/2025-05-13-18-54-56.gh-issue-133970.6G-Oi6.rst b/Misc/NEWS.d/next/Library/2025-05-13-18-54-56.gh-issue-133970.6G-Oi6.rst deleted file mode 100644 index ddf456d3939..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-13-18-54-56.gh-issue-133970.6G-Oi6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make :class:`!string.templatelib.Template` and -:class:`!string.templatelib.Interpolation` generic. diff --git a/Misc/NEWS.d/next/Library/2025-05-15-00-27-09.gh-issue-134004.e8k4-R.rst b/Misc/NEWS.d/next/Library/2025-05-15-00-27-09.gh-issue-134004.e8k4-R.rst deleted file mode 100644 index a9a56d9239b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-15-00-27-09.gh-issue-134004.e8k4-R.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`shelve` as well as underlying :mod:`!dbm.dumb` and :mod:`!dbm.sqlite` now have :meth:`!reorganize` methods to -recover unused free space previously occupied by deleted entries. diff --git a/Misc/NEWS.d/next/Library/2025-05-15-14-27-01.gh-issue-134062.fRbJet.rst b/Misc/NEWS.d/next/Library/2025-05-15-14-27-01.gh-issue-134062.fRbJet.rst deleted file mode 100644 index f62a3ec4801..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-15-14-27-01.gh-issue-134062.fRbJet.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`ipaddress`: fix collisions in :meth:`~object.__hash__` for -:class:`~ipaddress.IPv4Network` and :class:`~ipaddress.IPv6Network` -objects. diff --git a/Misc/NEWS.d/next/Library/2025-05-16-12-40-37.gh-issue-132124.T_5Odx.rst b/Misc/NEWS.d/next/Library/2025-05-16-12-40-37.gh-issue-132124.T_5Odx.rst deleted file mode 100644 index acf3577ece4..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-16-12-40-37.gh-issue-132124.T_5Odx.rst +++ /dev/null @@ -1,6 +0,0 @@ -On POSIX-compliant systems, :func:`!multiprocessing.util.get_temp_dir` now -ignores :envvar:`TMPDIR` (and similar environment variables) if the path -length of ``AF_UNIX`` socket files exceeds the platform-specific maximum -length when using the :ref:`forkserver -<multiprocessing-start-method-forkserver>` start method. Patch by Bénédikt -Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-16-20-10-25.gh-issue-134098.YyTkKr.rst b/Misc/NEWS.d/next/Library/2025-05-16-20-10-25.gh-issue-134098.YyTkKr.rst deleted file mode 100644 index 32eff5371c4..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-16-20-10-25.gh-issue-134098.YyTkKr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling paths that end with a percent-encoded slash (``%2f`` or -``%2F``) in :class:`http.server.SimpleHTTPRequestHandler`. diff --git a/Misc/NEWS.d/next/Library/2025-05-17-12-40-12.gh-issue-133889.Eh-zO4.rst b/Misc/NEWS.d/next/Library/2025-05-17-12-40-12.gh-issue-133889.Eh-zO4.rst deleted file mode 100644 index 58b213e29f9..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-17-12-40-12.gh-issue-133889.Eh-zO4.rst +++ /dev/null @@ -1,3 +0,0 @@ -The generated directory listing page in -:class:`http.server.SimpleHTTPRequestHandler` now only shows the decoded -path component of the requested URL, and not the query and fragment. diff --git a/Misc/NEWS.d/next/Library/2025-05-17-13-46-20.gh-issue-134097.fgkjE1.rst b/Misc/NEWS.d/next/Library/2025-05-17-13-46-20.gh-issue-134097.fgkjE1.rst deleted file mode 100644 index 0b388d9db38..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-17-13-46-20.gh-issue-134097.fgkjE1.rst +++ /dev/null @@ -1 +0,0 @@ -Fix interaction of the new :term:`REPL` and :option:`-X showrefcount <-X>` command line option. diff --git a/Misc/NEWS.d/next/Library/2025-05-17-18-08-35.gh-issue-133890.onn9_X.rst b/Misc/NEWS.d/next/Library/2025-05-17-18-08-35.gh-issue-133890.onn9_X.rst deleted file mode 100644 index 44565a5424e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-17-18-08-35.gh-issue-133890.onn9_X.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`tarfile` module now handles :exc:`UnicodeEncodeError` in the same -way as :exc:`OSError` when cannot extract a member. diff --git a/Misc/NEWS.d/next/Library/2025-05-17-20-23-57.gh-issue-133982.smS7au.rst b/Misc/NEWS.d/next/Library/2025-05-17-20-23-57.gh-issue-133982.smS7au.rst deleted file mode 100644 index a6753145981..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-17-20-23-57.gh-issue-133982.smS7au.rst +++ /dev/null @@ -1,3 +0,0 @@ -Emit :exc:`RuntimeWarning` in the Python implementation of :mod:`io` when -the :term:`file-like object <file object>` is not closed explicitly in the -presence of multiple I/O layers. diff --git a/Misc/NEWS.d/next/Library/2025-05-18-07-25-15.gh-issue-134173.53oOoF.rst b/Misc/NEWS.d/next/Library/2025-05-18-07-25-15.gh-issue-134173.53oOoF.rst deleted file mode 100644 index 57fba5e21a3..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-18-07-25-15.gh-issue-134173.53oOoF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Speed up :mod:`asyncio` performance of transferring state from thread -pool :class:`concurrent.futures.Future` by up to 4.4x. Patch by J. Nick -Koston. diff --git a/Misc/NEWS.d/next/Library/2025-05-18-12-23-07.gh-issue-134087.HilZWl.rst b/Misc/NEWS.d/next/Library/2025-05-18-12-23-07.gh-issue-134087.HilZWl.rst deleted file mode 100644 index c4a05965f73..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-18-12-23-07.gh-issue-134087.HilZWl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove support for arbitrary positional or keyword arguments in the C -implementation of :class:`threading.RLock` objects. This was deprecated -since Python 3.14. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-18-12-48-39.gh-issue-62184.y11l10.rst b/Misc/NEWS.d/next/Library/2025-05-18-12-48-39.gh-issue-62184.y11l10.rst deleted file mode 100644 index 7bc994e57fb..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-18-12-48-39.gh-issue-62184.y11l10.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove import of C implementation of :class:`io.FileIO` from Python -implementation which has its own implementation diff --git a/Misc/NEWS.d/next/Library/2025-05-18-13-23-29.gh-issue-134168.hgx3Xg.rst b/Misc/NEWS.d/next/Library/2025-05-18-13-23-29.gh-issue-134168.hgx3Xg.rst deleted file mode 100644 index 5a0e20005db..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-18-13-23-29.gh-issue-134168.hgx3Xg.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`http.server`: Fix IPv6 address binding and -:option:`--directory <http.server --directory>` handling when using HTTPS. diff --git a/Misc/NEWS.d/next/Library/2025-05-18-23-46-21.gh-issue-134152.30HwbX.rst b/Misc/NEWS.d/next/Library/2025-05-18-23-46-21.gh-issue-134152.30HwbX.rst deleted file mode 100644 index 911a4a59ea6..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-18-23-46-21.gh-issue-134152.30HwbX.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`email`: Fix parsing of email message ID with invalid domain. diff --git a/Misc/NEWS.d/next/Library/2025-05-19-10-32-11.gh-issue-134152.INJC2j.rst b/Misc/NEWS.d/next/Library/2025-05-19-10-32-11.gh-issue-134152.INJC2j.rst deleted file mode 100644 index 6da3d4147dd..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-10-32-11.gh-issue-134152.INJC2j.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed :exc:`UnboundLocalError` that could occur during :mod:`email` header -parsing if an expected trailing delimiter is missing in some contexts. diff --git a/Misc/NEWS.d/next/Library/2025-05-19-15-05-24.gh-issue-134235.pz9PwV.rst b/Misc/NEWS.d/next/Library/2025-05-19-15-05-24.gh-issue-134235.pz9PwV.rst deleted file mode 100644 index a65df886919..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-15-05-24.gh-issue-134235.pz9PwV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Updated tab completion on REPL to include builtin modules. Contributed by -Tom Wang, Hunter Young diff --git a/Misc/NEWS.d/next/Library/2025-05-19-15-30-00.gh-issue-132983.asdsfs.rst b/Misc/NEWS.d/next/Library/2025-05-19-15-30-00.gh-issue-132983.asdsfs.rst deleted file mode 100644 index 3893eeafa9c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-15-30-00.gh-issue-132983.asdsfs.rst +++ /dev/null @@ -1 +0,0 @@ -Add :mod:`!compression.zstd` version information to ``test.pythoninfo``. diff --git a/Misc/NEWS.d/next/Library/2025-05-19-17-27-21.gh-issue-80184.LOkbaw.rst b/Misc/NEWS.d/next/Library/2025-05-19-17-27-21.gh-issue-80184.LOkbaw.rst deleted file mode 100644 index 089268dc4c3..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-17-27-21.gh-issue-80184.LOkbaw.rst +++ /dev/null @@ -1 +0,0 @@ -The default queue size is now ``socket.SOMAXCONN`` for :class:`socketserver.TCPServer`. diff --git a/Misc/NEWS.d/next/Library/2025-05-19-18-12-42.gh-issue-88994.7avvVu.rst b/Misc/NEWS.d/next/Library/2025-05-19-18-12-42.gh-issue-88994.7avvVu.rst deleted file mode 100644 index 554a0c3bcb2..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-18-12-42.gh-issue-88994.7avvVu.rst +++ /dev/null @@ -1,3 +0,0 @@ -Change :func:`datetime.datetime.now` to half-even rounding for -consistency with :func:`datetime.datetime.fromtimestamp`. Patch by -John Keith Hohm. diff --git a/Misc/NEWS.d/next/Library/2025-05-19-20-59-06.gh-issue-134209.anhTcF.rst b/Misc/NEWS.d/next/Library/2025-05-19-20-59-06.gh-issue-134209.anhTcF.rst deleted file mode 100644 index f985872f3c9..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-19-20-59-06.gh-issue-134209.anhTcF.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`curses`: The :meth:`curses.window.instr` and :meth:`curses.window.getstr` -methods now allocate their internal buffer on the heap instead of the stack; -in addition, the max buffer size is increased from 1023 to 2047. diff --git a/Misc/NEWS.d/next/Library/2025-05-20-11-35-08.gh-issue-72902.jzEI-E.rst b/Misc/NEWS.d/next/Library/2025-05-20-11-35-08.gh-issue-72902.jzEI-E.rst deleted file mode 100644 index 932e751a32a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-20-11-35-08.gh-issue-72902.jzEI-E.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve speed (x1.1-1.8) of the :class:`~fractions.Fraction` constructor for -typical inputs (:class:`float`'s, :class:`~decimal.Decimal`'s or strings). diff --git a/Misc/NEWS.d/next/Library/2025-05-20-11-51-17.gh-issue-71189.0LpTB1.rst b/Misc/NEWS.d/next/Library/2025-05-20-11-51-17.gh-issue-71189.0LpTB1.rst deleted file mode 100644 index b46ddcba59c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-20-11-51-17.gh-issue-71189.0LpTB1.rst +++ /dev/null @@ -1 +0,0 @@ -Add support of the all-but-last mode in :func:`os.path.realpath`. diff --git a/Misc/NEWS.d/next/Library/2025-05-20-15-13-43.gh-issue-86802.trF7TM.rst b/Misc/NEWS.d/next/Library/2025-05-20-15-13-43.gh-issue-86802.trF7TM.rst deleted file mode 100644 index d3117b16f04..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-20-15-13-43.gh-issue-86802.trF7TM.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed asyncio memory leak in cancelled shield tasks. For shielded tasks -where the shield was cancelled, log potential exceptions through the -exception handler. Contributed by Christian Harries. diff --git a/Misc/NEWS.d/next/Library/2025-05-20-19-16-30.gh-issue-134323.ZQZGvw.rst b/Misc/NEWS.d/next/Library/2025-05-20-19-16-30.gh-issue-134323.ZQZGvw.rst deleted file mode 100644 index 7982b52f77a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-20-19-16-30.gh-issue-134323.ZQZGvw.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the :meth:`threading.RLock.locked` method. diff --git a/Misc/NEWS.d/next/Library/2025-05-20-21-45-58.gh-issue-90871.Gkvtp6.rst b/Misc/NEWS.d/next/Library/2025-05-20-21-45-58.gh-issue-90871.Gkvtp6.rst deleted file mode 100644 index 49397c9705e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-20-21-45-58.gh-issue-90871.Gkvtp6.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed an off by one error concerning the backlog parameter in -:meth:`~asyncio.loop.create_unix_server`. Contributed by Christian Harries. diff --git a/Misc/NEWS.d/next/Library/2025-05-22-13-10-32.gh-issue-114177.3TYUJ3.rst b/Misc/NEWS.d/next/Library/2025-05-22-13-10-32.gh-issue-114177.3TYUJ3.rst deleted file mode 100644 index c98fde5fb04..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-22-13-10-32.gh-issue-114177.3TYUJ3.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :mod:`asyncio` to not close subprocess pipes which would otherwise error out when the event loop is already closed. diff --git a/Misc/NEWS.d/next/Library/2025-05-22-14-12-53.gh-issue-134451.M1rD-j.rst b/Misc/NEWS.d/next/Library/2025-05-22-14-12-53.gh-issue-134451.M1rD-j.rst deleted file mode 100644 index 3c8339f8842..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-22-14-12-53.gh-issue-134451.M1rD-j.rst +++ /dev/null @@ -1 +0,0 @@ -Converted ``asyncio.tools.CycleFoundException`` from dataclass to a regular exception type. diff --git a/Misc/NEWS.d/next/Library/2025-05-22-18-14-13.gh-issue-134546.fjLVzK.rst b/Misc/NEWS.d/next/Library/2025-05-22-18-14-13.gh-issue-134546.fjLVzK.rst deleted file mode 100644 index eea897f5918..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-22-18-14-13.gh-issue-134546.fjLVzK.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure :mod:`pdb` remote debugging script is readable by remote Python process. diff --git a/Misc/NEWS.d/next/Library/2025-05-23-10-15-36.gh-issue-134565.zmb66C.rst b/Misc/NEWS.d/next/Library/2025-05-23-10-15-36.gh-issue-134565.zmb66C.rst deleted file mode 100644 index 17d2b23b62d..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-23-10-15-36.gh-issue-134565.zmb66C.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`unittest.doModuleCleanups` no longer swallows all but first exception -raised in the cleanup code, but raises a :exc:`ExceptionGroup` if multiple -errors occurred. diff --git a/Misc/NEWS.d/next/Library/2025-05-23-20-01-52.gh-issue-134580.xnaJ70.rst b/Misc/NEWS.d/next/Library/2025-05-23-20-01-52.gh-issue-134580.xnaJ70.rst deleted file mode 100644 index 979d310d3ce..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-23-20-01-52.gh-issue-134580.xnaJ70.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improved the styling of HTML diff pages generated by the -:class:`difflib.HtmlDiff` class, and migrated the output to the HTML5 -standard. diff --git a/Misc/NEWS.d/next/Library/2025-05-23-23-43-39.gh-issue-134582.9POq3l.rst b/Misc/NEWS.d/next/Library/2025-05-23-23-43-39.gh-issue-134582.9POq3l.rst deleted file mode 100644 index 23e1d5891b6..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-23-23-43-39.gh-issue-134582.9POq3l.rst +++ /dev/null @@ -1 +0,0 @@ -Fix tokenize.untokenize() round-trip errors related to t-strings braces escaping diff --git a/Misc/NEWS.d/next/Library/2025-05-24-03-10-36.gh-issue-80334.z21cMa.rst b/Misc/NEWS.d/next/Library/2025-05-24-03-10-36.gh-issue-80334.z21cMa.rst deleted file mode 100644 index 228429516db..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-24-03-10-36.gh-issue-80334.z21cMa.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`multiprocessing.freeze_support` now checks for work on any "spawn" -start method platform rather than only on Windows. diff --git a/Misc/NEWS.d/next/Library/2025-05-24-13-10-35.gh-issue-134210.0IuMY2.rst b/Misc/NEWS.d/next/Library/2025-05-24-13-10-35.gh-issue-134210.0IuMY2.rst deleted file mode 100644 index b440e8308db..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-24-13-10-35.gh-issue-134210.0IuMY2.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`curses.window.getch` now correctly handles signals. Patch by Bénédikt -Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-25-11-02-05.gh-issue-134657.3YFhR9.rst b/Misc/NEWS.d/next/Library/2025-05-25-11-02-05.gh-issue-134657.3YFhR9.rst deleted file mode 100644 index 1bf8ee504ef..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-25-11-02-05.gh-issue-134657.3YFhR9.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`asyncio`: Remove some private names from ``asyncio.__all__``. diff --git a/Misc/NEWS.d/next/Library/2025-05-25-13-46-37.gh-issue-134635.ZlPrlX.rst b/Misc/NEWS.d/next/Library/2025-05-25-13-46-37.gh-issue-134635.ZlPrlX.rst deleted file mode 100644 index 4cabbf2f896..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-25-13-46-37.gh-issue-134635.ZlPrlX.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`zlib`: Allow to combine Adler-32 and CRC-32 checksums via -:func:`~zlib.adler32_combine` and :func:`~zlib.crc32_combine`. Patch by -Callum Attryde and Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-25-23-23-05.gh-issue-134151.13Wwsb.rst b/Misc/NEWS.d/next/Library/2025-05-25-23-23-05.gh-issue-134151.13Wwsb.rst deleted file mode 100644 index ecdde240b4a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-25-23-23-05.gh-issue-134151.13Wwsb.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`email`: Fix :exc:`TypeError` in :func:`email.utils.decode_params` -when sorting :rfc:`2231` continuations that contain an unnumbered section. diff --git a/Misc/NEWS.d/next/Library/2025-05-26-10-52-27.gh-issue-134698.aJ1mZ1.rst b/Misc/NEWS.d/next/Library/2025-05-26-10-52-27.gh-issue-134698.aJ1mZ1.rst deleted file mode 100644 index cf3901aba34..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-26-10-52-27.gh-issue-134698.aJ1mZ1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash when calling methods of :class:`ssl.SSLContext` or -:class:`ssl.SSLSocket` across multiple threads. diff --git a/Misc/NEWS.d/next/Library/2025-05-26-11-01-54.gh-issue-134531.my1Fzt.rst b/Misc/NEWS.d/next/Library/2025-05-26-11-01-54.gh-issue-134531.my1Fzt.rst deleted file mode 100644 index ee5690df5c4..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-26-11-01-54.gh-issue-134531.my1Fzt.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`!_hashlib`: Rename internal C functions for :class:`!_hashlib.HASH` -and :class:`!_hashlib.HASHXOF` objects. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-26-12-31-08.gh-issue-132710.ApU3TZ.rst b/Misc/NEWS.d/next/Library/2025-05-26-12-31-08.gh-issue-132710.ApU3TZ.rst deleted file mode 100644 index b7011517aa9..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-26-12-31-08.gh-issue-132710.ApU3TZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -If possible, ensure that :func:`uuid.getnode` returns the same result even -across different processes. Previously, the result was constant only within -the same process. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-26-14-04-39.gh-issue-134696.P04xUa.rst b/Misc/NEWS.d/next/Library/2025-05-26-14-04-39.gh-issue-134696.P04xUa.rst deleted file mode 100644 index 282eb088b89..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-26-14-04-39.gh-issue-134696.P04xUa.rst +++ /dev/null @@ -1,5 +0,0 @@ -Built-in HACL* and OpenSSL implementations of hash function constructors -now correctly accept the same *documented* named arguments. For instance, -:func:`~hashlib.md5` could be previously invoked as ``md5(data=data)`` -or ``md5(string=string)`` depending on the underlying implementation -but these calls were not compatible. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-26-17-06-40.gh-issue-134637.9-3zRL.rst b/Misc/NEWS.d/next/Library/2025-05-26-17-06-40.gh-issue-134637.9-3zRL.rst deleted file mode 100644 index 2a4d8725210..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-26-17-06-40.gh-issue-134637.9-3zRL.rst +++ /dev/null @@ -1 +0,0 @@ -Fix performance regression in calling a :mod:`ctypes` function pointer in :term:`free threading`. diff --git a/Misc/NEWS.d/next/Library/2025-05-26-22-18-32.gh-issue-134771.RKXpLT.rst b/Misc/NEWS.d/next/Library/2025-05-26-22-18-32.gh-issue-134771.RKXpLT.rst deleted file mode 100644 index 4b70c6ef398..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-26-22-18-32.gh-issue-134771.RKXpLT.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``time_clockid_converter()`` function now selects correct type for -``clockid_t`` on Cygwin which fixes a build error. diff --git a/Misc/NEWS.d/next/Library/2025-05-27-11-13-51.gh-issue-133579.KY9M6S.rst b/Misc/NEWS.d/next/Library/2025-05-27-11-13-51.gh-issue-133579.KY9M6S.rst deleted file mode 100644 index 129d5d98425..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-27-11-13-51.gh-issue-133579.KY9M6S.rst +++ /dev/null @@ -1,8 +0,0 @@ -:ref:`curses.window <curses-window-objects>`: Consistently report failures -of curses C API calls in Window methods by raising a :exc:`curses.error`. -This affects :meth:`~curses.window.addch`, :meth:`~curses.window.addnstr`, -:meth:`~curses.window.addstr`, :meth:`~curses.window.border`, -:meth:`~curses.window.box`, :meth:`~curses.window.chgat`, -:meth:`~curses.window.getbkgd`, :meth:`~curses.window.inch`, -:meth:`~curses.window.insstr` and :meth:`~curses.window.insnstr`. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-27-11-18-13.gh-issue-133579.ohtgdC.rst b/Misc/NEWS.d/next/Library/2025-05-27-11-18-13.gh-issue-133579.ohtgdC.rst deleted file mode 100644 index e0ef959f125..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-27-11-18-13.gh-issue-133579.ohtgdC.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`curses.window.refresh` and :meth:`curses.window.noutrefresh` now raise -a :exc:`TypeError` instead of :exc:`curses.error` when called with an incorrect -number of arguments for :ref:`pads <windows-and-pads>`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-27-11-24-38.gh-issue-133579.WGPUC1.rst b/Misc/NEWS.d/next/Library/2025-05-27-11-24-38.gh-issue-133579.WGPUC1.rst deleted file mode 100644 index 552b7ca1a71..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-27-11-24-38.gh-issue-133579.WGPUC1.rst +++ /dev/null @@ -1,7 +0,0 @@ -:mod:`curses`: Consistently report failures of curses C API calls in -module-level methods by raising a :exc:`curses.error`. This affects -:func:`~curses.assume_default_colors`, :func:`~curses.baudrate`, -:func:`~curses.cbreak`, :func:`~curses.echo`, :func:`~curses.longname`, -:func:`~curses.initscr`, :func:`~curses.nl`, :func:`~curses.raw`, -:func:`~curses.termattrs`, :func:`~curses.termname` and :func:`~curses.unctrl`. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst b/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst deleted file mode 100644 index faff433aa4b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst +++ /dev/null @@ -1 +0,0 @@ -Fix parsing long IPv6 addresses with embedded IPv4 address. diff --git a/Misc/NEWS.d/next/Library/2025-05-28-20-49-29.gh-issue-134857.dVYXVO.rst b/Misc/NEWS.d/next/Library/2025-05-28-20-49-29.gh-issue-134857.dVYXVO.rst deleted file mode 100644 index 92e38c0bb5a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-28-20-49-29.gh-issue-134857.dVYXVO.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve error report for :mod:`doctest`\ s run with :mod:`unittest`. Remove -:mod:`!doctest` module frames from tracebacks and redundant newline -character from a failure message. diff --git a/Misc/NEWS.d/next/Library/2025-05-29-06-53-40.gh-issue-134885.-_L22o.rst b/Misc/NEWS.d/next/Library/2025-05-29-06-53-40.gh-issue-134885.-_L22o.rst deleted file mode 100644 index 4b05d42c109..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-29-06-53-40.gh-issue-134885.-_L22o.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible crash in the :mod:`compression.zstd` module related to setting -parameter types. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2025-05-29-17-39-13.gh-issue-108885.MegCRA.rst b/Misc/NEWS.d/next/Library/2025-05-29-17-39-13.gh-issue-108885.MegCRA.rst deleted file mode 100644 index e37cf121f5f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-29-17-39-13.gh-issue-108885.MegCRA.rst +++ /dev/null @@ -1,3 +0,0 @@ -Run each example as a subtest in unit tests synthesized by -:func:`doctest.DocFileSuite` and :func:`doctest.DocTestSuite`. -Add the :meth:`doctest.DocTestRunner.report_skip` method. diff --git a/Misc/NEWS.d/next/Library/2025-05-29-19-00-37.gh-issue-134861.y2-fu-.rst b/Misc/NEWS.d/next/Library/2025-05-29-19-00-37.gh-issue-134861.y2-fu-.rst deleted file mode 100644 index 07e4c61b404..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-29-19-00-37.gh-issue-134861.y2-fu-.rst +++ /dev/null @@ -1 +0,0 @@ -Add CSV as an output format for :program:`python -m asyncio ps`. diff --git a/Misc/NEWS.d/next/Library/2025-05-30-09-46-21.gh-issue-134939.Pu3nnm.rst b/Misc/NEWS.d/next/Library/2025-05-30-09-46-21.gh-issue-134939.Pu3nnm.rst deleted file mode 100644 index 2bda69bff52..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-30-09-46-21.gh-issue-134939.Pu3nnm.rst +++ /dev/null @@ -1 +0,0 @@ -Add the :mod:`concurrent.interpreters` module. See :pep:`734`. diff --git a/Misc/NEWS.d/next/Library/2025-05-30-13-07-29.gh-issue-134718.9Qvhxn.rst b/Misc/NEWS.d/next/Library/2025-05-30-13-07-29.gh-issue-134718.9Qvhxn.rst deleted file mode 100644 index 922ab168fdd..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-30-13-07-29.gh-issue-134718.9Qvhxn.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`ast.dump` now only omits ``None`` and ``[]`` values if they are -default values. diff --git a/Misc/NEWS.d/next/Library/2025-05-30-18-13-48.gh-issue-134718.5FEspx.rst b/Misc/NEWS.d/next/Library/2025-05-30-18-13-48.gh-issue-134718.5FEspx.rst deleted file mode 100644 index 06c1d5583be..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-30-18-13-48.gh-issue-134718.5FEspx.rst +++ /dev/null @@ -1 +0,0 @@ -By default, omit optional ``Load()`` values in :func:`ast.dump`. diff --git a/Misc/NEWS.d/next/Library/2025-05-31-12-08-12.gh-issue-134970.lgSaxq.rst b/Misc/NEWS.d/next/Library/2025-05-31-12-08-12.gh-issue-134970.lgSaxq.rst deleted file mode 100644 index 20f53569ef4..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-31-12-08-12.gh-issue-134970.lgSaxq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the "unknown action" exception in -:meth:`argparse.ArgumentParser.add_argument_group` to correctly replace the -action class. diff --git a/Misc/NEWS.d/next/Library/2025-05-31-15-49-46.gh-issue-134978.mXXuvW.rst b/Misc/NEWS.d/next/Library/2025-05-31-15-49-46.gh-issue-134978.mXXuvW.rst deleted file mode 100644 index e75ce1622d6..00000000000 --- a/Misc/NEWS.d/next/Library/2025-05-31-15-49-46.gh-issue-134978.mXXuvW.rst +++ /dev/null @@ -1,7 +0,0 @@ -:mod:`hashlib`: Supporting the ``string`` keyword parameter in hash function -constructors such as :func:`~hashlib.new` or the direct hash-named constructors -such as :func:`~hashlib.md5` and :func:`~hashlib.sha256` is now deprecated and -slated for removal in Python 3.19. -Prefer passing the initial data as a positional argument for maximum backwards -compatibility. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-01-14-18-48.gh-issue-135004.cq3-fp.rst b/Misc/NEWS.d/next/Library/2025-06-01-14-18-48.gh-issue-135004.cq3-fp.rst deleted file mode 100644 index 4c59b0f8e19..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-01-14-18-48.gh-issue-135004.cq3-fp.rst +++ /dev/null @@ -1,3 +0,0 @@ -Rewrite and cleanup the internal :mod:`!_blake2` module. Some exception -messages were changed but their types were left untouched. Patch by Bénédikt -Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-01-15-13-07.gh-issue-66234.Jw7OdC.rst b/Misc/NEWS.d/next/Library/2025-06-01-15-13-07.gh-issue-66234.Jw7OdC.rst deleted file mode 100644 index 1defb9a72e0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-01-15-13-07.gh-issue-66234.Jw7OdC.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add the ``'m'`` flag for :func:`dbm.gnu.open` which allows to disable the -use of :manpage:`mmap(2)`. This may harm performance, but improve crash -tolerance. diff --git a/Misc/NEWS.d/next/Library/2025-06-02-14-28-30.gh-issue-130662.EIgIR8.rst b/Misc/NEWS.d/next/Library/2025-06-02-14-28-30.gh-issue-130662.EIgIR8.rst deleted file mode 100644 index e07200f9a3f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-02-14-28-30.gh-issue-130662.EIgIR8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Accept leading zeros in precision and width fields for -:class:`~fractions.Fraction` formatting, for example ``format(Fraction(1, -3), '.016f')``. diff --git a/Misc/NEWS.d/next/Library/2025-06-02-14-36-28.gh-issue-130662.Gpr2GB.rst b/Misc/NEWS.d/next/Library/2025-06-02-14-36-28.gh-issue-130662.Gpr2GB.rst deleted file mode 100644 index d97d937376a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-02-14-36-28.gh-issue-130662.Gpr2GB.rst +++ /dev/null @@ -1,3 +0,0 @@ -+Accept leading zeros in precision and width fields for -+:class:`~decimal.Decimal` formatting, for example ``format(Decimal(1.25), -'.016f')``. diff --git a/Misc/NEWS.d/next/Library/2025-06-03-12-59-17.gh-issue-135069.xop30V.rst b/Misc/NEWS.d/next/Library/2025-06-03-12-59-17.gh-issue-135069.xop30V.rst deleted file mode 100644 index 1affb5e2aad..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-03-12-59-17.gh-issue-135069.xop30V.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix the "Invalid error handling" exception in -:class:`!encodings.idna.IncrementalDecoder` to correctly replace the -'errors' parameter. diff --git a/Misc/NEWS.d/next/Library/2025-06-06-17-34-18.gh-issue-133934.yT1r68.rst b/Misc/NEWS.d/next/Library/2025-06-06-17-34-18.gh-issue-133934.yT1r68.rst deleted file mode 100644 index 4de7b4cceca..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-06-17-34-18.gh-issue-133934.yT1r68.rst +++ /dev/null @@ -1 +0,0 @@ -Improve :mod:`sqlite3` CLI's ``.help`` message. diff --git a/Misc/NEWS.d/next/Library/2025-06-08-01-10-34.gh-issue-135241.5j18IW.rst b/Misc/NEWS.d/next/Library/2025-06-08-01-10-34.gh-issue-135241.5j18IW.rst deleted file mode 100644 index 058ef11083e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-08-01-10-34.gh-issue-135241.5j18IW.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :code:`INT` opcode of the C accelerator :mod:`!_pickle` module was updated -to look only for "00" and "01" to push booleans onto the stack, aligning with -the Python :mod:`pickle` module. diff --git a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst deleted file mode 100644 index 1f70358e64e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`uuid`: when the MAC address cannot be determined, the 48-bit node -ID is now generated with a cryptographically-secure pseudo-random number -generator (CSPRNG) as per :rfc:`RFC 9562, §6.10.3 <9562#section-6.10-3>`. -This affects :func:`~uuid.uuid1` and :func:`~uuid.uuid6`. diff --git a/Misc/NEWS.d/next/Library/2025-06-08-11-11-07.gh-issue-135234.wJCdh0.rst b/Misc/NEWS.d/next/Library/2025-06-08-11-11-07.gh-issue-135234.wJCdh0.rst deleted file mode 100644 index e1c11e46735..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-08-11-11-07.gh-issue-135234.wJCdh0.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`hashlib`: improve exception messages when an OpenSSL function failed. -When memory allocation fails on OpenSSL's side, a :exc:`MemoryError` is -raised instead of a :exc:`ValueError`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-08-14-50-34.gh-issue-135276.ZLUhV1.rst b/Misc/NEWS.d/next/Library/2025-06-08-14-50-34.gh-issue-135276.ZLUhV1.rst deleted file mode 100644 index a8fbd48d08a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-08-14-50-34.gh-issue-135276.ZLUhV1.rst +++ /dev/null @@ -1,6 +0,0 @@ -Synchronized zipfile.Path with zipp 3.23, including improved performance of -:meth:`zipfile.Path.open` for non-reading modes, rely on -:func:`functools.cached_property` to cache values on the instance. Rely on -``save_method_args`` to save the initialization method arguments. Fixed -``.name``, ``.stem`` and other basename-based properties on Windows when -working with a zipfile on disk. diff --git a/Misc/NEWS.d/next/Library/2025-06-09-10-16-55.gh-issue-121914.G6Avkq.rst b/Misc/NEWS.d/next/Library/2025-06-09-10-16-55.gh-issue-121914.G6Avkq.rst deleted file mode 100644 index a1314a9cb7f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-09-10-16-55.gh-issue-121914.G6Avkq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Changed the names of the symbol tables for lambda expressions and generator -expressions to "<lambda>" and "<genexpr>" respectively to avoid conflicts -with user-defined names. diff --git a/Misc/NEWS.d/next/Library/2025-06-10-00-42-30.gh-issue-135321.UHh9jT.rst b/Misc/NEWS.d/next/Library/2025-06-10-00-42-30.gh-issue-135321.UHh9jT.rst deleted file mode 100644 index 9e63d8e28b7..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-10-00-42-30.gh-issue-135321.UHh9jT.rst +++ /dev/null @@ -1 +0,0 @@ -Raise a correct exception for values greater than 0x7fffffff for the ``BINSTRING`` opcode in the C implementation of :mod:`pickle`. diff --git a/Misc/NEWS.d/next/Library/2025-06-10-10-22-18.gh-issue-130870.JipqbO.rst b/Misc/NEWS.d/next/Library/2025-06-10-10-22-18.gh-issue-130870.JipqbO.rst deleted file mode 100644 index 64173285e08..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-10-10-22-18.gh-issue-130870.JipqbO.rst +++ /dev/null @@ -1,2 +0,0 @@ -Preserve :class:`types.GenericAlias` subclasses in -:func:`typing.get_type_hints` diff --git a/Misc/NEWS.d/next/Library/2025-06-10-16-11-00.gh-issue-133967.P0c24q.rst b/Misc/NEWS.d/next/Library/2025-06-10-16-11-00.gh-issue-133967.P0c24q.rst deleted file mode 100644 index 1976981727e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-10-16-11-00.gh-issue-133967.P0c24q.rst +++ /dev/null @@ -1 +0,0 @@ -Do not normalize :mod:`locale` name 'C.UTF-8' to 'en_US.UTF-8'. diff --git a/Misc/NEWS.d/next/Library/2025-06-10-21-42-04.gh-issue-135335.WnUqb_.rst b/Misc/NEWS.d/next/Library/2025-06-10-21-42-04.gh-issue-135335.WnUqb_.rst deleted file mode 100644 index 466ba0d232c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-10-21-42-04.gh-issue-135335.WnUqb_.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`multiprocessing`: Flush ``stdout`` and ``stderr`` after preloading -modules in the ``forkserver``. diff --git a/Misc/NEWS.d/next/Library/2025-06-11-15-08-02.gh-issue-135336.6Gq6MI.rst b/Misc/NEWS.d/next/Library/2025-06-11-15-08-02.gh-issue-135336.6Gq6MI.rst deleted file mode 100644 index 8a1d492ff08..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-11-15-08-02.gh-issue-135336.6Gq6MI.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`json` now encodes strings up to 2.2x faster if they consist solely of characters that don’t require escaping. diff --git a/Misc/NEWS.d/next/Library/2025-06-12-10-45-02.gh-issue-135368.OjWVHL.rst b/Misc/NEWS.d/next/Library/2025-06-12-10-45-02.gh-issue-135368.OjWVHL.rst deleted file mode 100644 index b9973d88a85..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-12-10-45-02.gh-issue-135368.OjWVHL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :class:`unittest.mock.Mock` generation on :func:`dataclasses.dataclass` -objects. Now all special attributes are set as it was before :gh:`124429`. diff --git a/Misc/NEWS.d/next/Library/2025-06-12-18-15-31.gh-issue-135429.mch75_.rst b/Misc/NEWS.d/next/Library/2025-06-12-18-15-31.gh-issue-135429.mch75_.rst deleted file mode 100644 index b5213520a95..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-12-18-15-31.gh-issue-135429.mch75_.rst +++ /dev/null @@ -1 +0,0 @@ -Fix the argument mismatch in ``_lsprof`` for ``PY_THROW`` event. diff --git a/Misc/NEWS.d/next/Library/2025-06-14-12-06-55.gh-issue-135487.KdVFff.rst b/Misc/NEWS.d/next/Library/2025-06-14-12-06-55.gh-issue-135487.KdVFff.rst deleted file mode 100644 index 3ef51fa31df..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-14-12-06-55.gh-issue-135487.KdVFff.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`!reprlib.Repr.repr_int` when given integers with more than -:func:`sys.get_int_max_str_digits` digits. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-14-14-19-13.gh-issue-135497.1pzwdA.rst b/Misc/NEWS.d/next/Library/2025-06-14-14-19-13.gh-issue-135497.1pzwdA.rst deleted file mode 100644 index d3e81de9dbf..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-14-14-19-13.gh-issue-135497.1pzwdA.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`os.getlogin` failing for longer usernames on BSD-based platforms. diff --git a/Misc/NEWS.d/next/Library/2025-06-15-03-03-22.gh-issue-65697.COdwZd.rst b/Misc/NEWS.d/next/Library/2025-06-15-03-03-22.gh-issue-65697.COdwZd.rst deleted file mode 100644 index d374220d02f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-15-03-03-22.gh-issue-65697.COdwZd.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`configparser`'s error message when attempting to write an invalid key is now more helpful. diff --git a/Misc/NEWS.d/next/Library/2025-06-16-12-37-02.gh-issue-135444.An2eeA.rst b/Misc/NEWS.d/next/Library/2025-06-16-12-37-02.gh-issue-135444.An2eeA.rst deleted file mode 100644 index e1182f56eb3..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-16-12-37-02.gh-issue-135444.An2eeA.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`asyncio.DatagramTransport.sendto` to account for datagram header size when -data cannot be sent. diff --git a/Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst b/Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst deleted file mode 100644 index dbf1f452509..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix opening a :mod:`dbm.sqlite3` database for reading from read-only file -or directory. diff --git a/Misc/NEWS.d/next/Library/2025-06-16-15-03-03.gh-issue-135561.mJCN8D.rst b/Misc/NEWS.d/next/Library/2025-06-16-15-03-03.gh-issue-135561.mJCN8D.rst deleted file mode 100644 index ee743f16113..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-16-15-03-03.gh-issue-135561.mJCN8D.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash on DEBUG builds when an HACL* HMAC routine fails. Patch by -Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-17-22-44-19.gh-issue-119180.Ogv8Nj.rst b/Misc/NEWS.d/next/Library/2025-06-17-22-44-19.gh-issue-119180.Ogv8Nj.rst deleted file mode 100644 index c5e5d5b4f8d..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-17-22-44-19.gh-issue-119180.Ogv8Nj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Only fetch globals and locals if necessary in -:func:`annotationlib.get_annotations` diff --git a/Misc/NEWS.d/next/Library/2025-06-17-23-13-56.gh-issue-135557.Bfcy4v.rst b/Misc/NEWS.d/next/Library/2025-06-17-23-13-56.gh-issue-135557.Bfcy4v.rst deleted file mode 100644 index eabf5ea4aaa..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-17-23-13-56.gh-issue-135557.Bfcy4v.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix races on :mod:`heapq` updates and :class:`list` reads on the :term:`free threaded <free threading>` -build. diff --git a/Misc/NEWS.d/next/Library/2025-06-18-11-43-17.gh-issue-135646.r7ekEn.rst b/Misc/NEWS.d/next/Library/2025-06-18-11-43-17.gh-issue-135646.r7ekEn.rst deleted file mode 100644 index 5fbd751467d..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-18-11-43-17.gh-issue-135646.r7ekEn.rst +++ /dev/null @@ -1 +0,0 @@ -Raise consistent :exc:`NameError` exceptions in :func:`annotationlib.ForwardRef.evaluate` diff --git a/Misc/NEWS.d/next/Library/2025-06-18-13-58-13.gh-issue-135645.109nff.rst b/Misc/NEWS.d/next/Library/2025-06-18-13-58-13.gh-issue-135645.109nff.rst deleted file mode 100644 index a7764a0105b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-18-13-58-13.gh-issue-135645.109nff.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added ``supports_isolated_interpreters`` field to -:data:`sys.implementation`. diff --git a/Misc/NEWS.d/next/Library/2025-06-18-19-25-32.gh-issue-123471.lx1Xbt.rst b/Misc/NEWS.d/next/Library/2025-06-18-19-25-32.gh-issue-123471.lx1Xbt.rst deleted file mode 100644 index 6f395024a9e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-18-19-25-32.gh-issue-123471.lx1Xbt.rst +++ /dev/null @@ -1 +0,0 @@ -Make concurrent iterations over :class:`itertools.chain` safe under :term:`free threading`. diff --git a/Misc/NEWS.d/next/Library/2025-06-20-16-28-47.gh-issue-135759.jne0Zi.rst b/Misc/NEWS.d/next/Library/2025-06-20-16-28-47.gh-issue-135759.jne0Zi.rst deleted file mode 100644 index 268d7eccdab..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-20-16-28-47.gh-issue-135759.jne0Zi.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`hashlib`: reject negative digest lengths in OpenSSL-based SHAKE objects -by raising a :exc:`ValueError`. Previously, negative lengths were implicitly -rejected by raising a :exc:`MemoryError` or a :exc:`SystemError`. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-20-17-06-59.gh-issue-90117.GYWVrn.rst b/Misc/NEWS.d/next/Library/2025-06-20-17-06-59.gh-issue-90117.GYWVrn.rst deleted file mode 100644 index 2bb15cb6d9c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-20-17-06-59.gh-issue-90117.GYWVrn.rst +++ /dev/null @@ -1 +0,0 @@ -Speed up :mod:`pprint` for :class:`list` and :class:`tuple`. diff --git a/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst b/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst deleted file mode 100644 index ad217b57b4b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst +++ /dev/null @@ -1,4 +0,0 @@ -Address bug where it was possible to call -:func:`xml.etree.ElementTree.ElementTree.write` on an ElementTree object with -an invalid root element. This behavior blanked the file passed to ``write`` -if it already existed. diff --git a/Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst b/Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst deleted file mode 100644 index 0f4a68bf745..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`netrc`: skip security checks if :func:`os.getuid` is missing. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-22-22-03-06.gh-issue-135823.iDBg97.rst b/Misc/NEWS.d/next/Library/2025-06-22-22-03-06.gh-issue-135823.iDBg97.rst deleted file mode 100644 index 5b9d89caae7..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-22-22-03-06.gh-issue-135823.iDBg97.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`netrc`: improve the error message when the security check for the -ownership of the default configuration file ``~/.netrc`` fails. Patch by -Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst b/Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst deleted file mode 100644 index fcf495bdceb..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Raise :exc:`TypeError` instead of :exc:`SystemError` when -:func:`!_interpreters.set___main___attrs` is passed a non-dict object. -Patch by Brian Schubert. diff --git a/Misc/NEWS.d/next/Library/2025-06-23-11-04-25.gh-issue-135836.-C-c4v.rst b/Misc/NEWS.d/next/Library/2025-06-23-11-04-25.gh-issue-135836.-C-c4v.rst deleted file mode 100644 index f93c9faee58..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-23-11-04-25.gh-issue-135836.-C-c4v.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could occur when the Happy Eyeballs algorithm resulted in an empty exceptions list during connection attempts. diff --git a/Misc/NEWS.d/next/Library/2025-06-24-10-23-37.gh-issue-135853.6xDNOG.rst b/Misc/NEWS.d/next/Library/2025-06-24-10-23-37.gh-issue-135853.6xDNOG.rst deleted file mode 100644 index 3fea3bc3e7c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-24-10-23-37.gh-issue-135853.6xDNOG.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`math`: expose C99 :func:`~math.signbit` function to determine whether -the sign bit of a floating-point value is set. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-24-10-52-35.gh-issue-135836.s37351.rst b/Misc/NEWS.d/next/Library/2025-06-24-10-52-35.gh-issue-135836.s37351.rst deleted file mode 100644 index 1d1e7a2298c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-24-10-52-35.gh-issue-135836.s37351.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could -occur when non-\ :exc:`OSError` exception is raised during connection and -socket's ``close()`` raises :exc:`!OSError`. diff --git a/Misc/NEWS.d/next/Library/2025-06-24-13-30-47.gh-issue-135853.7ejTvK.rst b/Misc/NEWS.d/next/Library/2025-06-24-13-30-47.gh-issue-135853.7ejTvK.rst deleted file mode 100644 index 240ea72c69f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-24-13-30-47.gh-issue-135853.7ejTvK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :func:`math.fmax` and :func:`math.fmin` to get the larger and smaller of -two floating-point values. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-24-14-43-24.gh-issue-135878.Db4roX.rst b/Misc/NEWS.d/next/Library/2025-06-24-14-43-24.gh-issue-135878.Db4roX.rst deleted file mode 100644 index 969cf2dfa40..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-24-14-43-24.gh-issue-135878.Db4roX.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixes a crash of :class:`types.SimpleNamespace` on :term:`free threading` builds, -when several threads were calling its :meth:`~object.__repr__` method at the -same time. diff --git a/Misc/NEWS.d/next/Library/2025-06-26-11-52-40.gh-issue-53203.TMigBr.rst b/Misc/NEWS.d/next/Library/2025-06-26-11-52-40.gh-issue-53203.TMigBr.rst deleted file mode 100644 index ba2fae49fdc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-26-11-52-40.gh-issue-53203.TMigBr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`time.strptime` for ``%c`` and ``%x`` formats on locales byn_ER, -wal_ET and lzh_TW, and for ``%X`` format on locales ar_SA, bg_BG and lzh_TW. diff --git a/Misc/NEWS.d/next/Library/2025-06-26-17-19-36.gh-issue-105456.eR9oHB.rst b/Misc/NEWS.d/next/Library/2025-06-26-17-19-36.gh-issue-105456.eR9oHB.rst deleted file mode 100644 index 772403a240a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-26-17-19-36.gh-issue-105456.eR9oHB.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` -modules. diff --git a/Misc/NEWS.d/next/Library/2025-06-26-17-28-49.gh-issue-135995.pPrDCt.rst b/Misc/NEWS.d/next/Library/2025-06-26-17-28-49.gh-issue-135995.pPrDCt.rst deleted file mode 100644 index 998b3cd85b1..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-26-17-28-49.gh-issue-135995.pPrDCt.rst +++ /dev/null @@ -1 +0,0 @@ -In the palmos encoding, make byte ``0x9b`` decode to ``›`` (U+203A - SINGLE RIGHT-POINTING ANGLE QUOTATION MARK). diff --git a/Misc/NEWS.d/next/Library/2025-06-27-09-26-04.gh-issue-87135.33z0UW.rst b/Misc/NEWS.d/next/Library/2025-06-27-09-26-04.gh-issue-87135.33z0UW.rst deleted file mode 100644 index 4b6bc74cad8..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-27-09-26-04.gh-issue-87135.33z0UW.rst +++ /dev/null @@ -1,3 +0,0 @@ -Acquiring a :class:`threading.Lock` or :class:`threading.RLock` at interpreter -shutdown will raise :exc:`PythonFinalizationError` if Python can determine -that it would otherwise deadlock. diff --git a/Misc/NEWS.d/next/Library/2025-06-27-13-34-28.gh-issue-136028.RY727g.rst b/Misc/NEWS.d/next/Library/2025-06-27-13-34-28.gh-issue-136028.RY727g.rst deleted file mode 100644 index 9859df7cf6a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-27-13-34-28.gh-issue-136028.RY727g.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix parsing month names containing "İ" (U+0130, LATIN CAPITAL LETTER I WITH -DOT ABOVE) in :func:`time.strptime`. This affects locales az_AZ, ber_DZ, -ber_MA and crh_UA. diff --git a/Misc/NEWS.d/next/Library/2025-06-28-11-32-57.gh-issue-134759.AjjKcG.rst b/Misc/NEWS.d/next/Library/2025-06-28-11-32-57.gh-issue-134759.AjjKcG.rst deleted file mode 100644 index 79b85320926..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-28-11-32-57.gh-issue-134759.AjjKcG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :exc:`UnboundLocalError` in :func:`email.message.Message.get_payload` when -the payload to decode is a :class:`bytes` object. Patch by Kliment Lamonov. diff --git a/Misc/NEWS.d/next/Library/2025-06-29-15-22-13.gh-issue-90733.NiquaA.rst b/Misc/NEWS.d/next/Library/2025-06-29-15-22-13.gh-issue-90733.NiquaA.rst deleted file mode 100644 index cba930c5860..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-29-15-22-13.gh-issue-90733.NiquaA.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error messages when reporting invalid parameters in -:func:`hashlib.scrypt`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-06-30-11-12-24.gh-issue-85702.0Lrbwu.rst b/Misc/NEWS.d/next/Library/2025-06-30-11-12-24.gh-issue-85702.0Lrbwu.rst deleted file mode 100644 index fc13eb1d9e0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-06-30-11-12-24.gh-issue-85702.0Lrbwu.rst +++ /dev/null @@ -1,3 +0,0 @@ -If ``zoneinfo._common.load_tzdata`` is given a package without a resource a -:exc:`zoneinfo.ZoneInfoNotFoundError` is raised rather than a :exc:`PermissionError`. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2025-07-02-10-48-21.gh-issue-136193.xfvras.rst b/Misc/NEWS.d/next/Library/2025-07-02-10-48-21.gh-issue-136193.xfvras.rst deleted file mode 100644 index 801115202d0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-02-10-48-21.gh-issue-136193.xfvras.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve :exc:`TypeError` error message, when richcomparing two -:class:`types.SimpleNamespace` objects. diff --git a/Misc/NEWS.d/next/Library/2025-07-02-18-41-45.gh-issue-133982.7qqAn6.rst b/Misc/NEWS.d/next/Library/2025-07-02-18-41-45.gh-issue-133982.7qqAn6.rst deleted file mode 100644 index a2d0810cebe..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-02-18-41-45.gh-issue-133982.7qqAn6.rst +++ /dev/null @@ -1 +0,0 @@ -Update Python implementation of :class:`io.BytesIO` to be thread safe. diff --git a/Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst b/Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst deleted file mode 100644 index 95606790e99..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-04-12-53-02.gh-issue-136156.OYlXoz.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`tempfile.TemporaryFile` no longer uses :data:`os.O_EXCL` with -:data:`os.O_TMPFILE`, so it's possible to use ``linkat()`` on the file -descriptor. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Library/2025-07-04-23-45-00.gh-issue-136306.O1YLIU.rst b/Misc/NEWS.d/next/Library/2025-07-04-23-45-00.gh-issue-136306.O1YLIU.rst deleted file mode 100644 index 5556c512681..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-04-23-45-00.gh-issue-136306.O1YLIU.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`ssl` can now get and set groups used for key agreement. diff --git a/Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst b/Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst deleted file mode 100644 index dd5cecdf3a1..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-05-06-56-16.gh-issue-136316.3zj_Do.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve support for evaluating nested forward references in -:func:`typing.evaluate_forward_ref`. diff --git a/Misc/NEWS.d/next/Library/2025-07-05-06-59-46.gh-issue-136047.qWvycf.rst b/Misc/NEWS.d/next/Library/2025-07-05-06-59-46.gh-issue-136047.qWvycf.rst deleted file mode 100644 index 1a381860914..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-05-06-59-46.gh-issue-136047.qWvycf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issues with :mod:`typing` when the C implementation of :mod:`abc` is not -available. diff --git a/Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst b/Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst deleted file mode 100644 index ddc2310392f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix pickling failures for protocols 0 and 1 for many objects related to -subinterpreters. diff --git a/Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst b/Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst deleted file mode 100644 index 39a848c11eb..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make ``type_params`` parameter required in :func:`!typing._eval_type` after -a deprecation period for not providing this parameter. Also remove the -:exc:`DeprecationWarning` for the old behavior. diff --git a/Misc/NEWS.d/next/Library/2025-07-06-18-38-10.gh-issue-135953.Z29DCz.rst b/Misc/NEWS.d/next/Library/2025-07-06-18-38-10.gh-issue-135953.Z29DCz.rst deleted file mode 100644 index 7e32388ed79..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-06-18-38-10.gh-issue-135953.Z29DCz.rst +++ /dev/null @@ -1,9 +0,0 @@ -Implement a new high-frequency runtime profiler that leverages the existing -remote debugging functionality to collect detailed execution statistics -from running Python processes. This tool is exposed in the -``profile.sample`` module and enables non-intrusive observation of -production applications by attaching to already-running processes without -requiring any code modifications, restarts, or special startup flags. The -observer can perform extremely high-frequency sampling of stack traces and -interpreter state, providing detailed runtime execution analysis of live -applications. diff --git a/Misc/NEWS.d/next/Library/2025-07-07-16-46-55.gh-issue-72327.wLvRuj.rst b/Misc/NEWS.d/next/Library/2025-07-07-16-46-55.gh-issue-72327.wLvRuj.rst deleted file mode 100644 index f305abb655a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-07-16-46-55.gh-issue-72327.wLvRuj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Suggest using the system command prompt when ``pip install`` is typed into -the REPL. Patch by Tom Viner, Richard Si, and Brian Schubert. diff --git a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst deleted file mode 100644 index 4ac04b9c0a6..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Raises :exc:`AttributeError` when accessing -:class:`concurrent.futures.InterpreterPoolExecutor` and subinterpreters are -not available. diff --git a/Misc/NEWS.d/next/Library/2025-07-08-20-58-01.gh-issue-136434.uuJsjS.rst b/Misc/NEWS.d/next/Library/2025-07-08-20-58-01.gh-issue-136434.uuJsjS.rst deleted file mode 100644 index 951f57100b6..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-08-20-58-01.gh-issue-136434.uuJsjS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix docs generation of ``UnboundItem`` in :mod:`concurrent.interpreters` -when running with :option:`-OO`. diff --git a/Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst b/Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst deleted file mode 100644 index 7634bd3be93..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug that was causing the ``get_async_stack_trace`` function to miss -some frames in the stack trace. diff --git a/Misc/NEWS.d/next/Library/2025-07-10-00-47-37.gh-issue-136470.KlUEUG.rst b/Misc/NEWS.d/next/Library/2025-07-10-00-47-37.gh-issue-136470.KlUEUG.rst deleted file mode 100644 index 5a0429cae07..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-10-00-47-37.gh-issue-136470.KlUEUG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correct :class:`concurrent.futures.InterpreterPoolExecutor`'s default thread -name. diff --git a/Misc/NEWS.d/next/Library/2025-07-10-10-18-19.gh-issue-52876.9Vjrd8.rst b/Misc/NEWS.d/next/Library/2025-07-10-10-18-19.gh-issue-52876.9Vjrd8.rst deleted file mode 100644 index a835306868d..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-10-10-18-19.gh-issue-52876.9Vjrd8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add missing ``keepends`` (default ``True``) parameter to -:meth:`!codecs.StreamReaderWriter.readline` and -:meth:`!codecs.StreamReaderWriter.readlines`. diff --git a/Misc/NEWS.d/next/Library/2025-07-10-21-02-43.gh-issue-136507.pnEuGS.rst b/Misc/NEWS.d/next/Library/2025-07-10-21-02-43.gh-issue-136507.pnEuGS.rst deleted file mode 100644 index b72fd26b38a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-10-21-02-43.gh-issue-136507.pnEuGS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix mimetypes CLI to handle multiple file parameters. diff --git a/Misc/NEWS.d/next/Library/2025-07-11-03-39-15.gh-issue-136523.s7caKL.rst b/Misc/NEWS.d/next/Library/2025-07-11-03-39-15.gh-issue-136523.s7caKL.rst deleted file mode 100644 index 71ec66a37ef..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-11-03-39-15.gh-issue-136523.s7caKL.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :class:`wave.Wave_write` emitting an unraisable when open raises. diff --git a/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst b/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst deleted file mode 100644 index 7ab5b068a7f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-11-10-23-44.gh-issue-136492.BVi5h0.rst +++ /dev/null @@ -1 +0,0 @@ -Expose :pep:`667`'s :data:`~types.FrameLocalsProxyType` in the :mod:`types` module. diff --git a/Misc/NEWS.d/next/Library/2025-07-11-23-04-39.gh-issue-136549.oAi8u4.rst b/Misc/NEWS.d/next/Library/2025-07-11-23-04-39.gh-issue-136549.oAi8u4.rst deleted file mode 100644 index f3050ad5d5a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-11-23-04-39.gh-issue-136549.oAi8u4.rst +++ /dev/null @@ -1 +0,0 @@ -Fix signature of :func:`threading.excepthook`. diff --git a/Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst b/Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst deleted file mode 100644 index 37f535f5648..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-12-14-15-47.gh-issue-136571.muHmBv.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`datetime.date.fromisocalendar` can now raise OverflowError for out of -range arguments. diff --git a/Misc/NEWS.d/next/Library/2025-07-12-18-05-37.gh-issue-136591.ujXmSN.rst b/Misc/NEWS.d/next/Library/2025-07-12-18-05-37.gh-issue-136591.ujXmSN.rst deleted file mode 100644 index ccd5bf11f04..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-12-18-05-37.gh-issue-136591.ujXmSN.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`!_hashlib`: avoid using deprecated functions -:manpage:`ERR_func_error_string` and :manpage:`EVP_MD_CTX_md` when using -OpenSSL 3.0 and later. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-07-13-11-20-05.gh-issue-136134.xhh0Kq.rst b/Misc/NEWS.d/next/Library/2025-07-13-11-20-05.gh-issue-136134.xhh0Kq.rst deleted file mode 100644 index 619526ab12b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-13-11-20-05.gh-issue-136134.xhh0Kq.rst +++ /dev/null @@ -1,3 +0,0 @@ -:meth:`IMAP4.login_cram_md5 <imaplib.IMAP4.login_cram_md5>` now raises an -:exc:`IMAP4.error <imaplib.IMAP4.error>` if CRAM-MD5 authentication is not -supported. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-07-13-13-31-22.gh-issue-136134.mh6VjS.rst b/Misc/NEWS.d/next/Library/2025-07-13-13-31-22.gh-issue-136134.mh6VjS.rst deleted file mode 100644 index f0290be9ba1..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-13-13-31-22.gh-issue-136134.mh6VjS.rst +++ /dev/null @@ -1,5 +0,0 @@ -:meth:`!SMTP.auth_cram_md5` now raises an :exc:`~smtplib.SMTPException` -instead of a :exc:`ValueError` if Python has been built without MD5 support. -In particular, :class:`~smtplib.SMTP` clients will not attempt to use this -method even if the remote server is assumed to support it. Patch by Bénédikt -Tran. diff --git a/Misc/NEWS.d/next/Library/2025-07-15-16-37-34.gh-issue-136669.Yexwah.rst b/Misc/NEWS.d/next/Library/2025-07-15-16-37-34.gh-issue-136669.Yexwah.rst deleted file mode 100644 index 0d93397ff35..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-15-16-37-34.gh-issue-136669.Yexwah.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`!_asyncio` is now statically linked for improved performance. diff --git a/Misc/NEWS.d/next/Library/2025-07-19-11-53-19.gh-issue-135427.iJM_X2.rst b/Misc/NEWS.d/next/Library/2025-07-19-11-53-19.gh-issue-135427.iJM_X2.rst deleted file mode 100644 index a14aa844c01..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-19-11-53-19.gh-issue-135427.iJM_X2.rst +++ /dev/null @@ -1,4 +0,0 @@ -With :option:`-Werror <-W>`, the DeprecationWarning emitted by :py:func:`os.fork` -and :py:func:`os.forkpty` in mutli-threaded processes is now raised as an exception. -Previously it was silently ignored. -Patch by Rani Pinchuk. diff --git a/Misc/NEWS.d/next/Library/2025-07-19-15-40-47.gh-issue-131724.LS59nA.rst b/Misc/NEWS.d/next/Library/2025-07-19-15-40-47.gh-issue-131724.LS59nA.rst deleted file mode 100644 index 71a991aa2c5..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-19-15-40-47.gh-issue-131724.LS59nA.rst +++ /dev/null @@ -1,4 +0,0 @@ -In :mod:`http.client`, a new *max_response_headers* keyword-only parameter has been -added to :class:`~http.client.HTTPConnection` and :class:`~http.client.HTTPSConnection` -constructors. This parameter sets the maximum number of allowed response headers, -helping to prevent denial-of-service attacks. diff --git a/Misc/NEWS.d/next/Library/2025-07-19-16-20-54.gh-issue-130645.O-dYcN.rst b/Misc/NEWS.d/next/Library/2025-07-19-16-20-54.gh-issue-130645.O-dYcN.rst deleted file mode 100644 index 96e076dfe5b..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-19-16-20-54.gh-issue-130645.O-dYcN.rst +++ /dev/null @@ -1 +0,0 @@ -Enable color help by default in :mod:`argparse`. diff --git a/Misc/NEWS.d/next/Library/2025-07-20-10-21-49.gh-issue-136787._0Rbp_.rst b/Misc/NEWS.d/next/Library/2025-07-20-10-21-49.gh-issue-136787._0Rbp_.rst deleted file mode 100644 index c6a8088e5da..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-20-10-21-49.gh-issue-136787._0Rbp_.rst +++ /dev/null @@ -1,4 +0,0 @@ -:mod:`hashlib`: improve exception messages when a hash algorithm is not -recognized, blocked by the current security policy or incompatible with -the desired operation (for instance, using HMAC with SHAKE). -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst b/Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst new file mode 100644 index 00000000000..236b37d268e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst @@ -0,0 +1,4 @@ +Fix issue where methods in handlers that lacked the protocol name but +matched a valid base handler method (e.g., ``_open()`` or ``error()``) +were incorrectly added to :class:`urllib.request.OpenerDirector`'s +handlers. Contributed by Andrea Mattei. diff --git a/Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst b/Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst deleted file mode 100644 index 9a71eb8ef1a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst +++ /dev/null @@ -1 +0,0 @@ -Discard URL query and fragment in :func:`urllib.request.url2pathname`. diff --git a/Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst b/Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst deleted file mode 100644 index 517a37feb37..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-20-16-56-55.gh-issue-135228.n_XIao.rst +++ /dev/null @@ -1,4 +0,0 @@ -When :mod:`dataclasses` replaces a class with a slotted dataclass, the -original class can now be garbage collected again. Earlier changes in Python -3.14 caused this class to always remain in existence together with the replacement -class synthesized by :mod:`dataclasses`. diff --git a/Misc/NEWS.d/next/Library/2025-07-21-11-56-47.gh-issue-136912.zWosAL.rst b/Misc/NEWS.d/next/Library/2025-07-21-11-56-47.gh-issue-136912.zWosAL.rst deleted file mode 100644 index 6c5f31145f7..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-21-11-56-47.gh-issue-136912.zWosAL.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`hmac.digest` now properly handles large keys and messages -by falling back to the pure Python implementation when necessary. -Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-07-21-15-40-00.gh-issue-136914.-GNG-d.rst b/Misc/NEWS.d/next/Library/2025-07-21-15-40-00.gh-issue-136914.-GNG-d.rst deleted file mode 100644 index 78ec8025fbc..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-21-15-40-00.gh-issue-136914.-GNG-d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix retrieval of :attr:`doctest.DocTest.lineno` for objects decorated with -:func:`functools.cache` or :class:`functools.cached_property`. diff --git a/Misc/NEWS.d/next/Library/2025-07-21-16-10-24.gh-issue-124621.wyoWc1.rst b/Misc/NEWS.d/next/Library/2025-07-21-16-10-24.gh-issue-124621.wyoWc1.rst deleted file mode 100644 index 34049183649..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-21-16-10-24.gh-issue-124621.wyoWc1.rst +++ /dev/null @@ -1 +0,0 @@ -pyrepl now works in Emscripten. diff --git a/Misc/NEWS.d/next/Library/2025-07-21-16-13-20.gh-issue-136929.obKZ2S.rst b/Misc/NEWS.d/next/Library/2025-07-21-16-13-20.gh-issue-136929.obKZ2S.rst deleted file mode 100644 index 31b8563f9d8..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-21-16-13-20.gh-issue-136929.obKZ2S.rst +++ /dev/null @@ -1,5 +0,0 @@ -Ensure that hash functions guaranteed to be always *available* exist as -attributes of :mod:`hashlib` even if they will not work at runtime due to -missing backend implementations. For instance, ``hashlib.md5`` will no -longer raise :exc:`AttributeError` if OpenSSL is not available and Python -has been built without MD5 support. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Library/2025-07-21-22-35-50.gh-issue-136170.QUlc78.rst b/Misc/NEWS.d/next/Library/2025-07-21-22-35-50.gh-issue-136170.QUlc78.rst deleted file mode 100644 index fd30fe156a1..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-21-22-35-50.gh-issue-136170.QUlc78.rst +++ /dev/null @@ -1,3 +0,0 @@ -Removed the unreleased ``zipfile.ZipFile.data_offset`` property added in 3.14.0a7 -as it wasn't fully clear which behavior it should have in some situations so -the result was not always what a user might expect. diff --git a/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst b/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst deleted file mode 100644 index 342cabbc865..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst +++ /dev/null @@ -1,3 +0,0 @@ -:mod:`tarfile` now validates archives to ensure member offsets are -non-negative. (Contributed by Alexander Enrique Urieles Nieto in -:gh:`130577`.) diff --git a/Misc/NEWS.d/next/Library/2025-07-23-11-59-48.gh-issue-136980.BIJzkB.rst b/Misc/NEWS.d/next/Library/2025-07-23-11-59-48.gh-issue-136980.BIJzkB.rst deleted file mode 100644 index a7111dd2b86..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-23-11-59-48.gh-issue-136980.BIJzkB.rst +++ /dev/null @@ -1 +0,0 @@ -Remove unused C tracing code in bdb for event type ``c_call``, ``c_return`` and ``c_exception`` diff --git a/Misc/NEWS.d/next/Library/2025-07-24-00-38-07.gh-issue-137059.fr64oW.rst b/Misc/NEWS.d/next/Library/2025-07-24-00-38-07.gh-issue-137059.fr64oW.rst deleted file mode 100644 index 8c63c1f1af8..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-24-00-38-07.gh-issue-137059.fr64oW.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix handling of file URLs with a Windows drive letter in the URL authority -by :func:`urllib.request.url2pathname`. This fixes a regression in earlier -pre-releases of Python 3.14. diff --git a/Misc/NEWS.d/next/Library/2025-07-25-09-21-56.gh-issue-130522.Crwq68.rst b/Misc/NEWS.d/next/Library/2025-07-25-09-21-56.gh-issue-130522.Crwq68.rst deleted file mode 100644 index 6c2246631dd..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-25-09-21-56.gh-issue-130522.Crwq68.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix unraisable :exc:`TypeError` raised during :term:`interpreter shutdown` -in the :mod:`threading` module. diff --git a/Misc/NEWS.d/next/Library/2025-07-28-20-48-32.gh-issue-137185.fgI7-B.rst b/Misc/NEWS.d/next/Library/2025-07-28-20-48-32.gh-issue-137185.fgI7-B.rst deleted file mode 100644 index 89398dff147..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-28-20-48-32.gh-issue-137185.fgI7-B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a potential async-signal-safety issue in :mod:`faulthandler` when -printing C stack traces. diff --git a/Misc/NEWS.d/next/Library/2025-07-28-23-11-29.gh-issue-81325.jMJFBe.rst b/Misc/NEWS.d/next/Library/2025-07-28-23-11-29.gh-issue-81325.jMJFBe.rst deleted file mode 100644 index 3d89b6eb92a..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-28-23-11-29.gh-issue-81325.jMJFBe.rst +++ /dev/null @@ -1,2 +0,0 @@ -:class:`tarfile.TarFile` now accepts a :term:`path-like <path-like object>` when working on a tar archive. -(Contributed by Alexander Enrique Urieles Nieto in :gh:`81325`.) diff --git a/Misc/NEWS.d/next/Library/2025-07-29-21-18-31.gh-issue-137226.B_4lpu.rst b/Misc/NEWS.d/next/Library/2025-07-29-21-18-31.gh-issue-137226.B_4lpu.rst deleted file mode 100644 index 522943cdd37..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-29-21-18-31.gh-issue-137226.B_4lpu.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix behavior of :meth:`annotationlib.ForwardRef.evaluate` when the -*type_params* parameter is passed and the name of a type param is also -present in an enclosing scope. diff --git a/Misc/NEWS.d/next/Library/2025-07-30-11-12-22.gh-issue-124503.d4hc7b.rst b/Misc/NEWS.d/next/Library/2025-07-30-11-12-22.gh-issue-124503.d4hc7b.rst deleted file mode 100644 index c04eba932a0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-30-11-12-22.gh-issue-124503.d4hc7b.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`ast.literal_eval` is 10-20% faster for small inputs. diff --git a/Misc/NEWS.d/next/Library/2025-07-30-17-42-36.gh-issue-137239.qSpj32.rst b/Misc/NEWS.d/next/Library/2025-07-30-17-42-36.gh-issue-137239.qSpj32.rst deleted file mode 100644 index 3be583ee937..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-30-17-42-36.gh-issue-137239.qSpj32.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`heapq`: Update :data:`!heapq.__all__` with ``*_max`` functions. diff --git a/Misc/NEWS.d/next/Library/2025-07-30-18-07-33.gh-issue-137257.XBtzf2.rst b/Misc/NEWS.d/next/Library/2025-07-30-18-07-33.gh-issue-137257.XBtzf2.rst deleted file mode 100644 index fad60985402..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-30-18-07-33.gh-issue-137257.XBtzf2.rst +++ /dev/null @@ -1 +0,0 @@ -Bump the version of pip bundled in ensurepip to version 25.2 diff --git a/Misc/NEWS.d/next/Library/2025-07-31-10-31-56.gh-issue-137282.GOCwIC.rst b/Misc/NEWS.d/next/Library/2025-07-31-10-31-56.gh-issue-137282.GOCwIC.rst deleted file mode 100644 index 78f169ea029..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-31-10-31-56.gh-issue-137282.GOCwIC.rst +++ /dev/null @@ -1 +0,0 @@ -Fix tab completion and :func:`dir` on :mod:`concurrent.futures`. diff --git a/Misc/NEWS.d/next/Library/2025-07-31-16-43-16.gh-issue-137191.FIogE8.rst b/Misc/NEWS.d/next/Library/2025-07-31-16-43-16.gh-issue-137191.FIogE8.rst deleted file mode 100644 index b2dba81251e..00000000000 --- a/Misc/NEWS.d/next/Library/2025-07-31-16-43-16.gh-issue-137191.FIogE8.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix how type parameters are collected, when :class:`typing.Protocol` are -specified with explicit parameters. Now, :class:`typing.Generic` and -:class:`typing.Protocol` always dictate the parameter number -and parameter ordering of types. Previous behavior was a bug. diff --git a/Misc/NEWS.d/next/Library/2025-08-01-15-07-59.gh-issue-137273.4V8Xmv.rst b/Misc/NEWS.d/next/Library/2025-08-01-15-07-59.gh-issue-137273.4V8Xmv.rst deleted file mode 100644 index f344877955f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-01-15-07-59.gh-issue-137273.4V8Xmv.rst +++ /dev/null @@ -1 +0,0 @@ -Fix debug assertion failure in :func:`locale.setlocale` on Windows. diff --git a/Misc/NEWS.d/next/Library/2025-08-01-23-52-49.gh-issue-75989.5aYXNJ.rst b/Misc/NEWS.d/next/Library/2025-08-01-23-52-49.gh-issue-75989.5aYXNJ.rst deleted file mode 100644 index 00b15503b50..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-01-23-52-49.gh-issue-75989.5aYXNJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`tarfile.TarFile.extractall` and :func:`tarfile.TarFile.extract` now -overwrite symlinks when extracting hardlinks. -(Contributed by Alexander Enrique Urieles Nieto in :gh:`75989`.) diff --git a/Misc/NEWS.d/next/Library/2025-08-03-00-36-57.gh-issue-115766.nJCFkW.rst b/Misc/NEWS.d/next/Library/2025-08-03-00-36-57.gh-issue-115766.nJCFkW.rst deleted file mode 100644 index d8d2203847c..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-03-00-36-57.gh-issue-115766.nJCFkW.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :attr:`!ipaddress.IPv4Interface.is_unspecified`. diff --git a/Misc/NEWS.d/next/Library/2025-08-03-13-16-39.gh-issue-137044.0hPVL_.rst b/Misc/NEWS.d/next/Library/2025-08-03-13-16-39.gh-issue-137044.0hPVL_.rst deleted file mode 100644 index f5f96263823..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-03-13-16-39.gh-issue-137044.0hPVL_.rst +++ /dev/null @@ -1,4 +0,0 @@ -Return large limit values as positive integers instead of negative integers -in :func:`resource.getrlimit`. Accept large values and reject negative -values (except :data:`~resource.RLIM_INFINITY`) for limits in -:func:`resource.setrlimit`. diff --git a/Misc/NEWS.d/next/Library/2025-08-06-16-13-47.gh-issue-137466.Whv0-A.rst b/Misc/NEWS.d/next/Library/2025-08-06-16-13-47.gh-issue-137466.Whv0-A.rst deleted file mode 100644 index 918019aa8c0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-06-16-13-47.gh-issue-137466.Whv0-A.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove undocumented :func:`!glob.glob0` and :func:`!glob.glob1` functions, -which have been deprecated since Python 3.13. Use :func:`glob.glob` and pass -a directory to its *root_dir* argument instead. diff --git a/Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst b/Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst deleted file mode 100644 index 57d8d0521e3..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Calendar uses the lengths of the locale's weekdays to decide if the width -requires abbreviation. diff --git a/Misc/NEWS.d/next/Library/2025-08-06-23-16-42.gh-issue-137477.bk6BDV.rst b/Misc/NEWS.d/next/Library/2025-08-06-23-16-42.gh-issue-137477.bk6BDV.rst deleted file mode 100644 index a6e097ea026..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-06-23-16-42.gh-issue-137477.bk6BDV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`!inspect.getblock`, :func:`inspect.getsourcelines` and -:func:`inspect.getsource` for generator expressions. diff --git a/Misc/NEWS.d/next/Library/2025-08-07-12-32-23.gh-issue-137044.abNoIy.rst b/Misc/NEWS.d/next/Library/2025-08-07-12-32-23.gh-issue-137044.abNoIy.rst deleted file mode 100644 index 5a87d3c7dd0..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-07-12-32-23.gh-issue-137044.abNoIy.rst +++ /dev/null @@ -1,4 +0,0 @@ -:data:`resource.RLIM_INFINITY` is now always a positive integer. -On all supported platforms, it is larger than any limited resource value, -which simplifies comparison of the resource values. -Previously, it could be negative, such as -1 or -3, depending on platform. diff --git a/Misc/NEWS.d/next/Library/2025-08-07-15-07-44.gh-issue-137512.j2or5h.rst b/Misc/NEWS.d/next/Library/2025-08-07-15-07-44.gh-issue-137512.j2or5h.rst deleted file mode 100644 index fc67913b7e9..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-07-15-07-44.gh-issue-137512.j2or5h.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add new constants in the :mod:`resource` module: -:data:`~resource.RLIMIT_NTHR`, :data:`~resource.RLIMIT_UMTXP`, -:data:`~resource.RLIMIT_PIPEBUF`, :data:`~resource.RLIMIT_THREADS`, -:data:`~resource.RLIM_SAVED_CUR`, and :data:`~resource.RLIM_SAVED_MAX`. diff --git a/Misc/NEWS.d/next/Library/2025-08-08-15-00-38.gh-issue-137426.lW-Rk2.rst b/Misc/NEWS.d/next/Library/2025-08-08-15-00-38.gh-issue-137426.lW-Rk2.rst deleted file mode 100644 index 6d05c8a3bf4..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-08-15-00-38.gh-issue-137426.lW-Rk2.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove the code deprecation of ``importlib.abc.ResourceLoader``. It is -documented as deprecated, but left for backwards compatibility with other -classes in ``importlib.abc``. diff --git a/Misc/NEWS.d/next/Library/2025-08-08-21-20-14.gh-issue-92936.rOgG1S.rst b/Misc/NEWS.d/next/Library/2025-08-08-21-20-14.gh-issue-92936.rOgG1S.rst deleted file mode 100644 index 906c442b64f..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-08-21-20-14.gh-issue-92936.rOgG1S.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update regex used by ``http.cookies.SimpleCookie`` to handle values containing -double quotes. diff --git a/Misc/NEWS.d/next/Library/2025-08-09-08-53-32.gh-issue-137583.s6OZud.rst b/Misc/NEWS.d/next/Library/2025-08-09-08-53-32.gh-issue-137583.s6OZud.rst deleted file mode 100644 index 3843cc7c8c5..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-09-08-53-32.gh-issue-137583.s6OZud.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a deadlock introduced in 3.13.6 when a call to -:meth:`ssl.SSLSocket.recv <socket.socket.recv>` was blocked in one thread, -and then another method on the object (such as :meth:`ssl.SSLSocket.send <socket.socket.send>`) -was subsequently called in another thread. diff --git a/Misc/NEWS.d/next/Library/2025-08-11-05-05-08.gh-issue-137630.9lmqyc.rst b/Misc/NEWS.d/next/Library/2025-08-11-05-05-08.gh-issue-137630.9lmqyc.rst deleted file mode 100644 index 94d836c1783..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-11-05-05-08.gh-issue-137630.9lmqyc.rst +++ /dev/null @@ -1,2 +0,0 @@ -The :mod:`!_interpreters` module now uses Argument Clinic to parse arguments. -Patch by Adam Turner. diff --git a/Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst b/Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst deleted file mode 100644 index 8cca50d91cd..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-13-10-50-22.gh-issue-73487.DUHbBq.rst +++ /dev/null @@ -1,3 +0,0 @@ -Speedup processing arguments (up to 1.5x) in the :mod:`decimal` module -methods, that now using :c:macro:`METH_FASTCALL` calling convention. Patch -by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/Library/2025-08-14-00-00-12.gh-issue-137729.i9NSKP.rst b/Misc/NEWS.d/next/Library/2025-08-14-00-00-12.gh-issue-137729.i9NSKP.rst deleted file mode 100644 index b324a42c7f8..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-14-00-00-12.gh-issue-137729.i9NSKP.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`locale.setlocale` now supports language codes with ``@``-modifiers. -``@``-modifier are no longer silently removed in :func:`locale.getlocale`, -but included in the language code. diff --git a/Misc/NEWS.d/next/Library/2025-08-14-10-27-07.gh-issue-125854.vDzFcZ.rst b/Misc/NEWS.d/next/Library/2025-08-14-10-27-07.gh-issue-125854.vDzFcZ.rst deleted file mode 100644 index 40925a4ab19..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-14-10-27-07.gh-issue-125854.vDzFcZ.rst +++ /dev/null @@ -1 +0,0 @@ -Improve error messages for invalid category in :func:`warnings.warn`. diff --git a/Misc/NEWS.d/next/Library/2025-08-16-09-02-11.gh-issue-137754.mCev1Y.rst b/Misc/NEWS.d/next/Library/2025-08-16-09-02-11.gh-issue-137754.mCev1Y.rst deleted file mode 100644 index 323870afd97..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-16-09-02-11.gh-issue-137754.mCev1Y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix import of the :mod:`zoneinfo` module if the C implementation of the -:mod:`datetime` module is not available. diff --git a/Misc/NEWS.d/next/Library/2025-08-16-16-04-15.gh-issue-137317.Dl13B5.rst b/Misc/NEWS.d/next/Library/2025-08-16-16-04-15.gh-issue-137317.Dl13B5.rst deleted file mode 100644 index 026cc320455..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-16-16-04-15.gh-issue-137317.Dl13B5.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`inspect.signature` now correctly handles classes that use a descriptor -on a wrapped :meth:`!__init__` or :meth:`!__new__` method. -Contributed by Yongyu Yan. diff --git a/Misc/NEWS.d/next/Library/2025-08-18-16-02-51.gh-issue-134869.GnAjnU.rst b/Misc/NEWS.d/next/Library/2025-08-18-16-02-51.gh-issue-134869.GnAjnU.rst deleted file mode 100644 index abb3579aa91..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-18-16-02-51.gh-issue-134869.GnAjnU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix an issue where pressing Ctrl+C during tab completion in the REPL would leave the autocompletion menu in a corrupted state. diff --git a/Misc/NEWS.d/next/Library/2025-08-19-00-12-57.gh-issue-137884.4faCA_.rst b/Misc/NEWS.d/next/Library/2025-08-19-00-12-57.gh-issue-137884.4faCA_.rst deleted file mode 100644 index c28f62ba3ce..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-19-00-12-57.gh-issue-137884.4faCA_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :func:`threading.get_native_id` support for Illumos/Solaris. Patch by -Yüce Tekol. diff --git a/Misc/NEWS.d/next/Library/2025-08-25-16-22-32.gh-issue-138122.eMNDZ1.rst b/Misc/NEWS.d/next/Library/2025-08-25-16-22-32.gh-issue-138122.eMNDZ1.rst deleted file mode 100644 index 41ca22c7828..00000000000 --- a/Misc/NEWS.d/next/Library/2025-08-25-16-22-32.gh-issue-138122.eMNDZ1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implement :pep:`799` -- A dedicated profiling package for organizing Python -profiling tools. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Library/2025-12-13-10-34-59.gh-issue-142654.fmm974.rst b/Misc/NEWS.d/next/Library/2025-12-13-10-34-59.gh-issue-142654.fmm974.rst new file mode 100644 index 00000000000..7bb14cb499d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-13-10-34-59.gh-issue-142654.fmm974.rst @@ -0,0 +1,2 @@ +Show the clearer error message when using ``profiling.sampling`` on an +unknown PID. diff --git a/Misc/NEWS.d/next/Library/2025-12-13-23-26-42.gh-issue-142495.I88Uv_.rst b/Misc/NEWS.d/next/Library/2025-12-13-23-26-42.gh-issue-142495.I88Uv_.rst new file mode 100644 index 00000000000..3e1a624fe56 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-13-23-26-42.gh-issue-142495.I88Uv_.rst @@ -0,0 +1,4 @@ +:class:`collections.defaultdict` now prioritizes :meth:`~object.__setitem__` +when inserting default values from ``default_factory``. This prevents race +conditions where a default value would overwrite a value set before +``default_factory`` returns. diff --git a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst new file mode 100644 index 00000000000..92a723cbc29 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst @@ -0,0 +1,3 @@ +The :mod:`asyncio` REPL now properly closes the loop upon the end of interactive session. +Previously, it could cause surprising warnings. +Contributed by Bartosz Sławecki. diff --git a/Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst b/Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst new file mode 100644 index 00000000000..f014771ae9a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst @@ -0,0 +1 @@ +Fix zoneinfo use-after-free with descriptor _weak_cache. a descriptor as _weak_cache could cause crashes during object creation. The fix ensures proper reference counting for descriptor-provided objects. diff --git a/Misc/NEWS.d/next/Library/2025-12-17-03-03-12.gh-issue-138122.m3EF9E.rst b/Misc/NEWS.d/next/Library/2025-12-17-03-03-12.gh-issue-138122.m3EF9E.rst new file mode 100644 index 00000000000..e33a761aa61 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-17-03-03-12.gh-issue-138122.m3EF9E.rst @@ -0,0 +1,4 @@ +Fix incomplete stack traces in the Tachyon profiler's frame cache when +profiling code with deeply nested generators. The frame cache now validates +that stack traces reach the base frame before caching, preventing broken +flamegraphs. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Library/2025-12-17-14-41-09.gh-issue-112127.13OHQk.rst b/Misc/NEWS.d/next/Library/2025-12-17-14-41-09.gh-issue-112127.13OHQk.rst new file mode 100644 index 00000000000..c983683ebd5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-17-14-41-09.gh-issue-112127.13OHQk.rst @@ -0,0 +1,2 @@ +Fix possible use-after-free in :func:`atexit.unregister` when the callback +is unregistered during comparison. diff --git a/Misc/NEWS.d/next/Security/2025-01-14-11-19-07.gh-issue-128840.M1doZW.rst b/Misc/NEWS.d/next/Security/2025-01-14-11-19-07.gh-issue-128840.M1doZW.rst deleted file mode 100644 index b57ec3e70dc..00000000000 --- a/Misc/NEWS.d/next/Security/2025-01-14-11-19-07.gh-issue-128840.M1doZW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Short-circuit the processing of long IPv6 addresses early in :mod:`ipaddress` to prevent excessive -memory consumption and a minor denial-of-service. diff --git a/Misc/NEWS.d/next/Security/2025-05-07-22-49-27.gh-issue-133623.fgWkBm.rst b/Misc/NEWS.d/next/Security/2025-05-07-22-49-27.gh-issue-133623.fgWkBm.rst deleted file mode 100644 index 09279bbfb4f..00000000000 --- a/Misc/NEWS.d/next/Security/2025-05-07-22-49-27.gh-issue-133623.fgWkBm.rst +++ /dev/null @@ -1 +0,0 @@ -Indicate through :data:`ssl.HAS_PSK_TLS13` whether the :mod:`ssl` module supports "External PSKs" in TLSv1.3, as described in RFC 9258. Patch by Will Childs-Klein. diff --git a/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst b/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst deleted file mode 100644 index 39d2f1e1a89..00000000000 --- a/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix use-after-free in the "unicode-escape" decoder with a non-"strict" error -handler. diff --git a/Misc/NEWS.d/next/Security/2025-06-02-11-32-23.gh-issue-135034.RLGjbp.rst b/Misc/NEWS.d/next/Security/2025-06-02-11-32-23.gh-issue-135034.RLGjbp.rst deleted file mode 100644 index 08a0087e203..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-02-11-32-23.gh-issue-135034.RLGjbp.rst +++ /dev/null @@ -1,6 +0,0 @@ -Fixes multiple issues that allowed ``tarfile`` extraction filters -(``filter="data"`` and ``filter="tar"``) to be bypassed using crafted -symlinks and hard links. - -Addresses :cve:`2024-12718`, :cve:`2025-4138`, :cve:`2025-4330`, and :cve:`2025-4517`. - diff --git a/Misc/NEWS.d/next/Security/2025-06-09-20-38-25.gh-issue-118350.KgWCcP.rst b/Misc/NEWS.d/next/Security/2025-06-09-20-38-25.gh-issue-118350.KgWCcP.rst deleted file mode 100644 index 6ad3caf33b2..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-09-20-38-25.gh-issue-118350.KgWCcP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix support of escapable raw text mode (elements "textarea" and "title") -in :class:`html.parser.HTMLParser`. diff --git a/Misc/NEWS.d/next/Security/2025-06-13-15-55-22.gh-issue-135462.KBeJpc.rst b/Misc/NEWS.d/next/Security/2025-06-13-15-55-22.gh-issue-135462.KBeJpc.rst deleted file mode 100644 index cf9aa8dbdf2..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-13-15-55-22.gh-issue-135462.KBeJpc.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix quadratic complexity in processing specially crafted input in -:class:`html.parser.HTMLParser`. End-of-file errors are now handled according -to the HTML5 specs -- comments and declarations are automatically closed, -tags are ignored. diff --git a/Misc/NEWS.d/next/Security/2025-06-18-13-28-08.gh-issue-102555.nADrzJ.rst b/Misc/NEWS.d/next/Security/2025-06-18-13-28-08.gh-issue-102555.nADrzJ.rst deleted file mode 100644 index 71d15ee0852..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-18-13-28-08.gh-issue-102555.nADrzJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix comment parsing in :class:`html.parser.HTMLParser` according to the -HTML5 standard. ``--!>`` now ends the comment. ``-- >`` no longer ends the -comment. Support abnormally ended empty comments ``<-->`` and ``<--->``. diff --git a/Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst b/Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst deleted file mode 100644 index fe000d936aa..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix CDATA section parsing in :class:`html.parser.HTMLParser` according to -the HTML5 standard: ``] ]>`` and ``]] >`` no longer end the CDATA section. -Add private method ``_set_support_cdata()`` which can be used to specify -how to parse ``<[CDATA[`` --- as a CDATA section in foreign content -(SVG or MathML) or as a bogus comment in the HTML namespace. diff --git a/Misc/NEWS.d/next/Security/2025-06-25-14-13-39.gh-issue-135661.idjQ0B.rst b/Misc/NEWS.d/next/Security/2025-06-25-14-13-39.gh-issue-135661.idjQ0B.rst deleted file mode 100644 index 27e886abdb5..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-25-14-13-39.gh-issue-135661.idjQ0B.rst +++ /dev/null @@ -1,20 +0,0 @@ -Fix parsing start and end tags in :class:`html.parser.HTMLParser` -according to the HTML5 standard. - -* Whitespaces no longer accepted between ``</`` and the tag name. - E.g. ``</ script>`` does not end the script section. - -* Vertical tabulation (``\v``) and non-ASCII whitespaces no longer recognized - as whitespaces. The only whitespaces are ``\t\n\r\f`` and space. - -* Null character (U+0000) no longer ends the tag name. - -* Attributes and slashes after the tag name in end tags are now ignored, - instead of terminating after the first ``>`` in quoted attribute value. - E.g. ``</script/foo=">"/>``. - -* Multiple slashes and whitespaces between the last attribute and closing ``>`` - are now ignored in both start and end tags. E.g. ``<a foo=bar/ //>``. - -* Multiple ``=`` between attribute name and value are no longer collapsed. - E.g. ``<a foo==bar>`` produces attribute "foo" with value "=bar". diff --git a/Misc/NEWS.d/next/Security/2025-06-27-21-23-19.gh-issue-136053.QZxcee.rst b/Misc/NEWS.d/next/Security/2025-06-27-21-23-19.gh-issue-136053.QZxcee.rst deleted file mode 100644 index 93caed3aa3b..00000000000 --- a/Misc/NEWS.d/next/Security/2025-06-27-21-23-19.gh-issue-136053.QZxcee.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`marshal`: fix a possible crash when deserializing :class:`slice` objects. diff --git a/Misc/NEWS.d/next/Tests/2025-05-08-15-06-01.gh-issue-133639.50-kbV.rst b/Misc/NEWS.d/next/Tests/2025-05-08-15-06-01.gh-issue-133639.50-kbV.rst deleted file mode 100644 index 68826cd95fa..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-05-08-15-06-01.gh-issue-133639.50-kbV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``TestPyReplAutoindent.test_auto_indent_default()`` doesn't run -``input_code``. diff --git a/Misc/NEWS.d/next/Tests/2025-05-09-04-11-06.gh-issue-133682.-_lwo3.rst b/Misc/NEWS.d/next/Tests/2025-05-09-04-11-06.gh-issue-133682.-_lwo3.rst deleted file mode 100644 index ebd17f73ca5..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-05-09-04-11-06.gh-issue-133682.-_lwo3.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed test case ``test.test_annotationlib.TestStringFormat.test_displays`` which ensures proper handling of complex data structures (lists, sets, dictionaries, and tuples) in string annotations. diff --git a/Misc/NEWS.d/next/Tests/2025-05-09-14-54-48.gh-issue-133744.LCquu0.rst b/Misc/NEWS.d/next/Tests/2025-05-09-14-54-48.gh-issue-133744.LCquu0.rst deleted file mode 100644 index f19186db1ad..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-05-09-14-54-48.gh-issue-133744.LCquu0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix multiprocessing interrupt test. Add an event to synchronize the parent -process with the child process: wait until the child process starts -sleeping. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2025-05-23-09-19-52.gh-issue-134567.hwEIMb.rst b/Misc/NEWS.d/next/Tests/2025-05-23-09-19-52.gh-issue-134567.hwEIMb.rst deleted file mode 100644 index 42e4a01c0cc..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-05-23-09-19-52.gh-issue-134567.hwEIMb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Expose log formatter to users in TestCase.assertLogs. -:func:`unittest.TestCase.assertLogs` will now optionally accept a formatter that will be used to format the strings in output if provided. diff --git a/Misc/NEWS.d/next/Tests/2025-06-04-13-07-44.gh-issue-135120.NapnZT.rst b/Misc/NEWS.d/next/Tests/2025-06-04-13-07-44.gh-issue-135120.NapnZT.rst deleted file mode 100644 index 772173774b1..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-06-04-13-07-44.gh-issue-135120.NapnZT.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`!test.support.subTests`. diff --git a/Misc/NEWS.d/next/Tests/2025-06-11-16-52-49.gh-issue-135401.ccMXmL.rst b/Misc/NEWS.d/next/Tests/2025-06-11-16-52-49.gh-issue-135401.ccMXmL.rst deleted file mode 100644 index 6885fba30db..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-06-11-16-52-49.gh-issue-135401.ccMXmL.rst +++ /dev/null @@ -1 +0,0 @@ -Add a new GitHub CI job to test the :mod:`ssl` module with `AWS-LC <https://github.com/aws/aws-lc>`_ as the backing cryptography and TLS library. diff --git a/Misc/NEWS.d/next/Tests/2025-06-14-13-20-17.gh-issue-135489.Uh0yVO.rst b/Misc/NEWS.d/next/Tests/2025-06-14-13-20-17.gh-issue-135489.Uh0yVO.rst deleted file mode 100644 index 2c9ecc51829..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-06-14-13-20-17.gh-issue-135489.Uh0yVO.rst +++ /dev/null @@ -1 +0,0 @@ -Show verbose output for failing tests during PGO profiling step with --enable-optimizations. diff --git a/Misc/NEWS.d/next/Tests/2025-06-17-08-48-08.gh-issue-132815.CY1Esu.rst b/Misc/NEWS.d/next/Tests/2025-06-17-08-48-08.gh-issue-132815.CY1Esu.rst deleted file mode 100644 index 5b7485ce2d6..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-06-17-08-48-08.gh-issue-132815.CY1Esu.rst +++ /dev/null @@ -1 +0,0 @@ -Fix test__opcode: add ``JUMP_BACKWARD`` to specialization stats. diff --git a/Misc/NEWS.d/next/Tests/2025-06-19-15-29-38.gh-issue-135494.FVl9a0.rst b/Misc/NEWS.d/next/Tests/2025-06-19-15-29-38.gh-issue-135494.FVl9a0.rst deleted file mode 100644 index 832d1fe033e..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-06-19-15-29-38.gh-issue-135494.FVl9a0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix regrtest to support excluding tests from ``--pgo`` tests. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2025-06-26-15-15-35.gh-issue-135966.EBpF8Y.rst b/Misc/NEWS.d/next/Tests/2025-06-26-15-15-35.gh-issue-135966.EBpF8Y.rst deleted file mode 100644 index 8dc007431f3..00000000000 --- a/Misc/NEWS.d/next/Tests/2025-06-26-15-15-35.gh-issue-135966.EBpF8Y.rst +++ /dev/null @@ -1 +0,0 @@ -The iOS testbed now handles the ``app_packages`` folder as a site directory. diff --git a/Misc/NEWS.d/next/Tests/2025-12-17-02-02-57.gh-issue-142836.mR-fvK.rst b/Misc/NEWS.d/next/Tests/2025-12-17-02-02-57.gh-issue-142836.mR-fvK.rst new file mode 100644 index 00000000000..dd84ce9839f --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2025-12-17-02-02-57.gh-issue-142836.mR-fvK.rst @@ -0,0 +1 @@ +Accommodated Solaris in ``test_pdb.test_script_target_anonymous_pipe``. diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-05-19-14-57-46.gh-issue-134215.sbdDK6.rst b/Misc/NEWS.d/next/Tools-Demos/2025-05-19-14-57-46.gh-issue-134215.sbdDK6.rst deleted file mode 100644 index 546ed2a56b6..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-05-19-14-57-46.gh-issue-134215.sbdDK6.rst +++ /dev/null @@ -1 +0,0 @@ -:term:`REPL` import autocomplete only suggests private modules when explicitly specified. diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-06-11-12-14-06.gh-issue-135379.25ttXq.rst b/Misc/NEWS.d/next/Tools-Demos/2025-06-11-12-14-06.gh-issue-135379.25ttXq.rst deleted file mode 100644 index ebe3ab0e7d1..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-06-11-12-14-06.gh-issue-135379.25ttXq.rst +++ /dev/null @@ -1,4 +0,0 @@ -The cases generator no longer accepts type annotations on stack items. -Conversions to non-default types are now done explicitly in bytecodes.c and -optimizer_bytecodes.c. This will simplify code generation for top-of-stack -caching and other future features. diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-06-26-15-58-13.gh-issue-135968.C4v_-W.rst b/Misc/NEWS.d/next/Tools-Demos/2025-06-26-15-58-13.gh-issue-135968.C4v_-W.rst deleted file mode 100644 index 1c0b3825c71..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-06-26-15-58-13.gh-issue-135968.C4v_-W.rst +++ /dev/null @@ -1 +0,0 @@ -Stubs for ``strip`` are now provided as part of an iOS install. diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-07-05-15-10-42.gh-issue-136251.GRM6o8.rst b/Misc/NEWS.d/next/Tools-Demos/2025-07-05-15-10-42.gh-issue-136251.GRM6o8.rst deleted file mode 100644 index 6a35afe15e3..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-07-05-15-10-42.gh-issue-136251.GRM6o8.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes and usability improvements for ``Tools/wasm/emscripten/web_example`` diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-07-30-10-28-35.gh-issue-137243.NkdUqH.rst b/Misc/NEWS.d/next/Tools-Demos/2025-07-30-10-28-35.gh-issue-137243.NkdUqH.rst deleted file mode 100644 index c9c6c2ca287..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-07-30-10-28-35.gh-issue-137243.NkdUqH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Have Tools/wasm/wasi detect a WASI SDK install in /opt when it was directly -extracted from a release tarball. diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-07-30-11-15-47.gh-issue-137248.8IxwY3.rst b/Misc/NEWS.d/next/Tools-Demos/2025-07-30-11-15-47.gh-issue-137248.8IxwY3.rst deleted file mode 100644 index 311ade0c8f3..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-07-30-11-15-47.gh-issue-137248.8IxwY3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a ``--logdir`` option to ``Tools/wasm/wasi`` for specifying where to -write log files. diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-08-06-11-54-55.gh-issue-137484.8iFAQs.rst b/Misc/NEWS.d/next/Tools-Demos/2025-08-06-11-54-55.gh-issue-137484.8iFAQs.rst deleted file mode 100644 index bd7bc0984ec..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-08-06-11-54-55.gh-issue-137484.8iFAQs.rst +++ /dev/null @@ -1,2 +0,0 @@ -Have ``Tools/wasm/wasi`` put the build Python into a directory named after -the build triple instead of "build". diff --git a/Misc/NEWS.d/next/Tools-Demos/2025-08-21-14-04-50.gh-issue-137873.qxffLt.rst b/Misc/NEWS.d/next/Tools-Demos/2025-08-21-14-04-50.gh-issue-137873.qxffLt.rst deleted file mode 100644 index 5b75858560c..00000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2025-08-21-14-04-50.gh-issue-137873.qxffLt.rst +++ /dev/null @@ -1,3 +0,0 @@ -The iOS test runner has been simplified, resolving some issues that have -been observed using the runner in GitHub Actions and Azure Pipelines test -environments. diff --git a/Misc/NEWS.d/next/Windows/2025-03-31-15-37-57.gh-issue-131942.jip_aL.rst b/Misc/NEWS.d/next/Windows/2025-03-31-15-37-57.gh-issue-131942.jip_aL.rst deleted file mode 100644 index 837f7265bba..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-03-31-15-37-57.gh-issue-131942.jip_aL.rst +++ /dev/null @@ -1 +0,0 @@ -Use the Python-specific :c:macro:`Py_DEBUG` macro rather than :c:macro:`!_DEBUG` in Windows-related C code. Patch by Xuehai Pan. diff --git a/Misc/NEWS.d/next/Windows/2025-05-07-08-19-15.gh-issue-133537.yzf963.rst b/Misc/NEWS.d/next/Windows/2025-05-07-08-19-15.gh-issue-133537.yzf963.rst deleted file mode 100644 index 94e45f9d8ee..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-07-08-19-15.gh-issue-133537.yzf963.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid using console I/O in WinAPI partitions that don’t support it diff --git a/Misc/NEWS.d/next/Windows/2025-05-07-09-02-19.gh-issue-133562.lqqNW1.rst b/Misc/NEWS.d/next/Windows/2025-05-07-09-02-19.gh-issue-133562.lqqNW1.rst deleted file mode 100644 index 884425b839a..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-07-09-02-19.gh-issue-133562.lqqNW1.rst +++ /dev/null @@ -1 +0,0 @@ -Disable handling of security descriptors by :func:`os.mkdir` with mode ``0o700`` on WinAPI partitions that do not support it. This only affects custom builds for specialized targets. diff --git a/Misc/NEWS.d/next/Windows/2025-05-07-11-25-29.gh-issue-133568.oYV0d8.rst b/Misc/NEWS.d/next/Windows/2025-05-07-11-25-29.gh-issue-133568.oYV0d8.rst deleted file mode 100644 index 1e2a5b582cb..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-07-11-25-29.gh-issue-133568.oYV0d8.rst +++ /dev/null @@ -1 +0,0 @@ -Fix compile error when using a WinAPI partition that doesn't support the RPC runtime library. diff --git a/Misc/NEWS.d/next/Windows/2025-05-07-11-45-30.gh-issue-133572.Xc2zxH.rst b/Misc/NEWS.d/next/Windows/2025-05-07-11-45-30.gh-issue-133572.Xc2zxH.rst deleted file mode 100644 index 993eceab0b7..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-07-11-45-30.gh-issue-133572.Xc2zxH.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid LsaNtStatus to WinError conversion on unsupported WinAPI partitions. diff --git a/Misc/NEWS.d/next/Windows/2025-05-07-13-04-22.gh-issue-133580.jBMujJ.rst b/Misc/NEWS.d/next/Windows/2025-05-07-13-04-22.gh-issue-133580.jBMujJ.rst deleted file mode 100644 index 414a6f87e65..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-07-13-04-22.gh-issue-133580.jBMujJ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`sys.getwindowsversion` failing without setting an exception when called on some WinAPI partitions. diff --git a/Misc/NEWS.d/next/Windows/2025-05-08-19-07-26.gh-issue-133626.yFTKYK.rst b/Misc/NEWS.d/next/Windows/2025-05-08-19-07-26.gh-issue-133626.yFTKYK.rst deleted file mode 100644 index 6c80d96bb83..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-08-19-07-26.gh-issue-133626.yFTKYK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensures packages are not accidentally bundled into the traditional -installer. diff --git a/Misc/NEWS.d/next/Windows/2025-05-13-13-25-27.gh-issue-133779.-YcTBz.rst b/Misc/NEWS.d/next/Windows/2025-05-13-13-25-27.gh-issue-133779.-YcTBz.rst deleted file mode 100644 index 550600d5eeb..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-13-13-25-27.gh-issue-133779.-YcTBz.rst +++ /dev/null @@ -1,6 +0,0 @@ -Reverts the change to generate different :file:`pyconfig.h` files based on -compiler settings, as it was frequently causing extension builds to break. -In particular, the ``Py_GIL_DISABLED`` preprocessor variable must now always -be defined explicitly when compiling for the experimental free-threaded -runtime. The :func:`sysconfig.get_config_var` function can be used to -determine whether the current runtime was compiled with that flag or not. diff --git a/Misc/NEWS.d/next/Windows/2025-05-19-03-02-04.gh-issue-76023.vHOf6M.rst b/Misc/NEWS.d/next/Windows/2025-05-19-03-02-04.gh-issue-76023.vHOf6M.rst deleted file mode 100644 index 958f4f4a440..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-19-03-02-04.gh-issue-76023.vHOf6M.rst +++ /dev/null @@ -1 +0,0 @@ -Make :func:`os.path.realpath` ignore Windows error 1005 when in non-strict mode. diff --git a/Misc/NEWS.d/next/Windows/2025-05-20-21-43-20.gh-issue-130727.-69t4D.rst b/Misc/NEWS.d/next/Windows/2025-05-20-21-43-20.gh-issue-130727.-69t4D.rst deleted file mode 100644 index dc10b3e62c8..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-05-20-21-43-20.gh-issue-130727.-69t4D.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a race in internal calls into WMI that can result in an "invalid handle" -exception under high load. Patch by Chris Eibl. diff --git a/Misc/NEWS.d/next/Windows/2025-06-03-18-26-54.gh-issue-135099.Q9usKm.rst b/Misc/NEWS.d/next/Windows/2025-06-03-18-26-54.gh-issue-135099.Q9usKm.rst deleted file mode 100644 index 36e70b1c0d8..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-06-03-18-26-54.gh-issue-135099.Q9usKm.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a crash that could occur on Windows when a background thread waits on a -:c:type:`PyMutex` while the main thread is shutting down the interpreter. diff --git a/Misc/NEWS.d/next/Windows/2025-07-27-02-16-53.gh-issue-137134.W0WpDF.rst b/Misc/NEWS.d/next/Windows/2025-07-27-02-16-53.gh-issue-137134.W0WpDF.rst deleted file mode 100644 index ddccf95b7d0..00000000000 --- a/Misc/NEWS.d/next/Windows/2025-07-27-02-16-53.gh-issue-137134.W0WpDF.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to ship with SQLite 3.50.4. diff --git a/Misc/NEWS.d/next/macOS/2025-07-27-02-17-40.gh-issue-137134.pjgITs.rst b/Misc/NEWS.d/next/macOS/2025-07-27-02-17-40.gh-issue-137134.pjgITs.rst deleted file mode 100644 index 957270f5aba..00000000000 --- a/Misc/NEWS.d/next/macOS/2025-07-27-02-17-40.gh-issue-137134.pjgITs.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to ship with SQLite version 3.50.4. diff --git a/Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst b/Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst deleted file mode 100644 index 5efd74660c9..00000000000 --- a/Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst +++ /dev/null @@ -1,3 +0,0 @@ -macOS installer shell path management improvements: separate the installer -``Shell profile updater`` postinstall script from the -``Update Shell Profile.command`` to enable more robust error handling. diff --git a/Misc/externals.spdx.json b/Misc/externals.spdx.json index a87af7f9173..dba01de8352 100644 --- a/Misc/externals.spdx.json +++ b/Misc/externals.spdx.json @@ -70,21 +70,21 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "6bb739ecddbd2cfb6d255eb5898437a9b5739277dee931338d3275bac5d96ba2" + "checksumValue": "9b07560b6c1afa666bd78b8d3aa5c83fdda02149afdf048596d5b0e0dac1ee55" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/openssl-3.0.16.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/openssl-3.0.18.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:openssl:openssl:3.0.16:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:openssl:openssl:3.0.18:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "openssl", "primaryPackagePurpose": "SOURCE", - "versionInfo": "3.0.16" + "versionInfo": "3.0.18" }, { "SPDXID": "SPDXRef-PACKAGE-sqlite", @@ -154,21 +154,21 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "a15c168e39e87d750c3dc766edc7f19bdda57dacf01e509678467eace91ad282" + "checksumValue": "1bfaba0ccacc6681d3ba85335cc7f49c24cf6f9d16f848cbd153b896d8a7d631" } ], - "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/xz-5.2.5.tar.gz", + "downloadLocation": "https://github.com/python/cpython-source-deps/archive/refs/tags/xz-5.8.1.1.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:tukaani:xz:5.2.5:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:tukaani:xz:5.8.1.1:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], "licenseConcluded": "NOASSERTION", "name": "xz", "primaryPackagePurpose": "SOURCE", - "versionInfo": "5.2.5" + "versionInfo": "5.8.1.1" }, { "SPDXID": "SPDXRef-PACKAGE-zlib-ng", diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index 738b3390885..e9554bf7837 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -48,11 +48,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "6984055af7b4e01429d8ebc910fe2be900d8ee9c" + "checksumValue": "a4395dd0589a97aab0904f7a5f5dc5781a086aa2" }, { "algorithm": "SHA256", - "checksumValue": "7c16a5cf0eea844ae579db083b8d75f23a71859cac77e3c4cb7a8fa3b7621685" + "checksumValue": "610b844bbfa3ec955772cc825db4d4db470827d57adcb214ad372d0eaf00e591" } ], "fileName": "Modules/expat/expat.h" @@ -62,11 +62,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "9e615c6e5c3ba00670f674a6b071bb855b0b563d" + "checksumValue": "c22196e3d8bee88fcdda715623b3b9d2119d2fb3" }, { "algorithm": "SHA256", - "checksumValue": "3d90a4b65c40a3f848c36100f4d73b933a015c7b7cd85c28e4331a6b845c1ad0" + "checksumValue": "f2c2283ba03b057e92beefc7f81ba901ebb6dfc1a45b036c8a7d65808eb77a84" } ], "fileName": "Modules/expat/expat_external.h" @@ -90,11 +90,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "60b0ee8b4a93ef0276193ed1051c15ecab73c02e" + "checksumValue": "7dce7d98943c5db33ae05e54801dcafb4547b9dd" }, { "algorithm": "SHA256", - "checksumValue": "6af6e8fbf5c83c1431464a2811b10ea2d1ff64c0eabfd9f18b1d4e53bf400c35" + "checksumValue": "6bfe307d52e7e4c71dbc30d3bd902a4905cdd83bbe4226a7e8dfa8e4c462a157" } ], "fileName": "Modules/expat/internal.h" @@ -174,11 +174,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "3db0435d69e5eb904c9c88400a5ab073a81049bc" + "checksumValue": "4c81a1f04fc653877c63c834145c18f93cd95f3e" }, { "algorithm": "SHA256", - "checksumValue": "633b272fa893dfbef539edbba35f1b11ecf09a13b89189105b0dfa6c7ecfc3bf" + "checksumValue": "04a379615f476d55f95ca1853107e20627b48ca4afe8d0fd5981ac77188bf0a6" } ], "fileName": "Modules/expat/xmlparse.c" @@ -202,11 +202,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "c961fb1a80f7b0601a63e69fba793fe5f6dff157" + "checksumValue": "ac2964cca107f62dd133bfd4736a9a17defbc401" }, { "algorithm": "SHA256", - "checksumValue": "228470eb9181a9a7575b63137edcb61b817ee4e0923faffdbeba29e07c939713" + "checksumValue": "92e41f373b67f6e0dcd7735faef3c3f1e2c17fe59e007e6b74beef6a2e70fa88" } ], "fileName": "Modules/expat/xmlrole.h" @@ -216,11 +216,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "8394790c0199c8f88108542ad78f23095d28a3fe" + "checksumValue": "1e2d35d90a1c269217f83d3bdf3c71cc22cb4c3f" }, { "algorithm": "SHA256", - "checksumValue": "5b16c671ccc42496374762768e4bf48f614aecfd2025a07925b8d94244aec645" + "checksumValue": "98d0fc735041956cc2e7bbbe2fb8f03130859410e0aee5e8015f406a37c02a3c" } ], "fileName": "Modules/expat/xmltok.c" @@ -230,11 +230,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7d2943a0128094455004b1a98007b98734221bae" + "checksumValue": "d126831eaa5158cff187a8c93f4bc1c8118f3b17" }, { "algorithm": "SHA256", - "checksumValue": "6b8919dc951606dc6f2b0175f8955a9ced901ce8bd08db47f291b6c04227ae7f" + "checksumValue": "91bf003a725a675761ea8d92cebc299a76fd28c3a950572f41bc7ce5327ee7b5" } ], "fileName": "Modules/expat/xmltok.h" @@ -300,11 +300,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "de7179fe6970e2b5d281dfed977ed91be635b8d2" + "checksumValue": "a57d53c35aa916ce0cd1567c8f10dcea58270321" }, { "algorithm": "SHA256", - "checksumValue": "c0ba888d87775c7d7f7d8a08dac7b3988fed81e11bb52396d90f762a8e90a7eb" + "checksumValue": "d68209032703137326f9aadd9abac8fe4a5c92d391e2f43b0414fa63087adc6b" } ], "fileName": "Modules/_hacl/Hacl_HMAC.h" @@ -328,11 +328,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7c66ac004a1dcf3fee0ab9aa62d61972f029de3a" + "checksumValue": "4d767388a34e2a2000e0cbd31f06cf36af1ae10d" }, { "algorithm": "SHA256", - "checksumValue": "9a7239a01a4ee8defbe3ebd9f0d12c873a1dd8e0659070380b2eab3ab0177333" + "checksumValue": "fac493e96af252abcf5705f0ab4eec59c1f3bc8244e105d75a57c43552dd1569" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2b.h" @@ -356,11 +356,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7f273d26942233e5dcdfb4c1a16ff2486b15f899" + "checksumValue": "280fd03ee23e13ecf90711d2be8230035d957343" }, { "algorithm": "SHA256", - "checksumValue": "dbc0dacc68ed52dbf1b7d6fba2c87870317998bc046e65f6deaaa150625432f8" + "checksumValue": "817dcd05d06d804587fce7d8f2f3f42a6fcf6818d2419a3551ef0df70cb7125a" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2b_Simd256.h" @@ -398,11 +398,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "2120c8c467aeebcc7c8b9678c15e79648433b91a" + "checksumValue": "79f47ab5458d88bce0f210a566aa117ce2125049" }, { "algorithm": "SHA256", - "checksumValue": "45735f7fe2dbbad7656d07854e9ec8176ad26c79f90dcc0fec0b9a59a6311ba7" + "checksumValue": "5cc96313f8c066f055c2819e473c79aeff086ba91a1449d54aa569127cd8601e" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2s.h" @@ -426,11 +426,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "9028e24c9876d9d16b2435ec29240c6b57bfe2a0" + "checksumValue": "c98890b6193baa3dbd472cfb67f22aea3dd0d3e1" }, { "algorithm": "SHA256", - "checksumValue": "062e3b856acac4f929c1e04b8264a754cad21ca6580215f7094a3f0a04edb912" + "checksumValue": "fe3f17bf237166f872ba88c8204333c4f64bdc4bb29c265448581c7bfea4b151" } ], "fileName": "Modules/_hacl/Hacl_Hash_Blake2s_Simd128.h" @@ -468,11 +468,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "e67a9bc18358c57afaeff3a174893ddfdb52dfc6" + "checksumValue": "2ed70f612a998ef6c04d62f9487a1b2534e6d76a" }, { "algorithm": "SHA256", - "checksumValue": "16e982081f6c2fd03ea751fcc64f5a835c94652841836e231fe562b9e287f4bc" + "checksumValue": "a34534ef36bc8428ac1169ca5f4f1c17a0817507ebae388e3dd825d1a331f28d" } ], "fileName": "Modules/_hacl/Hacl_Hash_MD5.h" @@ -496,11 +496,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "f1ca21f1ee8b15ad9ccfbda72165b9d86912166c" + "checksumValue": "a3f9bdc9e73f80eb4a586dc180246cfb8267ffc0" }, { "algorithm": "SHA256", - "checksumValue": "4b2ad9ea93fdd9c2fdc521fc4e14e02550666c2717a23b85819db2e07ea555f3" + "checksumValue": "2d5cae94382f5473cf6d2654760375ff1ee9cebdb8d4506b63ba33f488de1559" } ], "fileName": "Modules/_hacl/Hacl_Hash_SHA1.h" @@ -524,11 +524,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "f38cebeeca40a83aeb2cf5dfce578ffefe176d84" + "checksumValue": "68b35d0c573f7301ba4d6919b1680d55675a0d98" }, { "algorithm": "SHA256", - "checksumValue": "ee03bf9368d1a3a3c70cfd4e9391b2485466404db4a60bfc5319630cc314b590" + "checksumValue": "442d8997d2bcda20ddf628665e2e69945400e1ab3019bc14fc7c8e20db20c320" } ], "fileName": "Modules/_hacl/Hacl_Hash_SHA2.h" @@ -552,11 +552,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "01717207aef77174e328186d48c27517f6644c15" + "checksumValue": "db1008095b64b2f8ee2a4ce72fa7cfc4a622a108" }, { "algorithm": "SHA256", - "checksumValue": "620dded172e94cb3f25f9904b44977d91f2cc9573e41b38f19e929d083ae0308" + "checksumValue": "961a686186b76a1cd6a64bcfd06afdc8657b1f901bac991166f498ed16f9349a" } ], "fileName": "Modules/_hacl/Hacl_Hash_SHA3.h" @@ -566,11 +566,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "417e68ac8498cb2f93a06a19003ea1cc3f0f6753" + "checksumValue": "eb224e26bc0503a48c88c837e28bbc7a9878ba5c" }, { "algorithm": "SHA256", - "checksumValue": "843db4bba78a476d4d53dabe4eed5c9235f490ccc9fdaf19e22af488af858920" + "checksumValue": "29fcf948a3715e09cbbd434cebb6105f276236a6e4947d237b7bf06634bf2432" } ], "fileName": "Modules/_hacl/Hacl_Streaming_HMAC.c" @@ -580,11 +580,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "49523144583a15d96ba1646af02dc292e633bf8f" + "checksumValue": "2d6c600024275c780e8313e0a5ab506e025bb4d6" }, { "algorithm": "SHA256", - "checksumValue": "78345519bf6789264f6792b809ee97a9ecf7cb5829c674c61e2d99bfdfdc36fc" + "checksumValue": "6450aef92f507fb0a8a3086b1d2792e7fca07121580c24fdaedd1b32e9ad0a76" } ], "fileName": "Modules/_hacl/Hacl_Streaming_HMAC.h" @@ -594,11 +594,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "372448599774a98e5c5d083e91f301ed1c4b822e" + "checksumValue": "ed283b95ebb772b05bdf802b70dbb301ece84e91" }, { "algorithm": "SHA256", - "checksumValue": "95d8e70ca4bc6aa98f6d2435ceb6410ead299b1f700fae1f5c603ec3f57ea551" + "checksumValue": "efc7bd11460744768425aedf4e004d3ad3397a5489752b80044ae785f30b78d4" } ], "fileName": "Modules/_hacl/Hacl_Streaming_Types.h" @@ -622,11 +622,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "911c97a0f24067635b164fbca49da76055f192cd" + "checksumValue": "ae06c415ae7e0e1e85558863f29d1b9013e46e9b" }, { "algorithm": "SHA256", - "checksumValue": "972b5111ebada8e11dd60df3119da1af505fd3e0b6c782ead6cab7f1daf134f1" + "checksumValue": "69dc2e78411e9b271100eb0d2a2d8dc39dd2348afc26f8b4cfba14c025102c7f" } ], "fileName": "Modules/_hacl/include/krml/FStar_UInt128_Verified.h" @@ -636,11 +636,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "41ee1e34ede7ef5b24b87d4ca816fd6d9fac8010" + "checksumValue": "edefe48ced707327fd6cdf3f18b3ca42dda9a9f7" }, { "algorithm": "SHA256", - "checksumValue": "d48ed03e504cb87793a310a9552fb3ba2ebd6fe90127b7d642c8740fba1b9748" + "checksumValue": "f01e3f0892935f3f659019875f580445b9ea23482afbe11ffbe7cdbd22dbd4d2" } ], "fileName": "Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h" @@ -678,11 +678,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "e01d7d493fbaceeedc4b1c6451d8240bcb9c903a" + "checksumValue": "7a943fbb8f55729a960f9b426e9ff2794453aca9" }, { "algorithm": "SHA256", - "checksumValue": "c2f0a43884771f24d7cb744b79818b160020d2739b2881b2054cfc97fb2e7b4a" + "checksumValue": "08bb43ef5626a8450f985da0af345b6658ac8bcc4585f77271decd0e41fc02e0" } ], "fileName": "Modules/_hacl/include/krml/internal/target.h" @@ -692,11 +692,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "3f66313d16891f43b21c1a736081c2c6d46bf370" + "checksumValue": "b4e6c5fc5e17864cc2bf452db2688be733d6df72" }, { "algorithm": "SHA256", - "checksumValue": "78e9bff9124968108e1699e1c6388e3d4ec9bd72dd8adff49734a69ab380ee5c" + "checksumValue": "404691cf9b2269ecc754ceca27bb8f8f029f1c8deaa4d967990dcf5ce08cd016" } ], "fileName": "Modules/_hacl/include/krml/internal/types.h" @@ -706,11 +706,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "e18efc9239a5df0f222b5f7b0a65f72509d7e304" + "checksumValue": "8c3e09e00459951e060ad469c1fa31eeb9b6b9cb" }, { "algorithm": "SHA256", - "checksumValue": "47dd5a7d21b5302255f9fff28884f65d3056fc3f54471ed62ec85fa1904f8aa5" + "checksumValue": "6d1a350ec272c83761f1789611d8f60947a4d69fed3d23d8eee38709a0ad2c0a" } ], "fileName": "Modules/_hacl/include/krml/lowstar_endianness.h" @@ -720,11 +720,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "aaa656e25a92ba83655e1398a97efa6981f60fc4" + "checksumValue": "c9517c43046de129f02da8b74e454bade4872c00" }, { "algorithm": "SHA256", - "checksumValue": "a59abc6e9b3019cb18976a15e634f5146bd965fc9babf4ccbf2b531164a34f85" + "checksumValue": "96c2a973bc01b1295f7af67c7de3839facfeee36c8848d7d88c62695de98ab21" } ], "fileName": "Modules/_hacl/internal/Hacl_HMAC.h" @@ -734,11 +734,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "0741cb8497309d648428be1e7b5944b1fc167187" + "checksumValue": "1c5eeb5d1866acb6bc8b4e5a01a107e3a87f5694" }, { "algorithm": "SHA256", - "checksumValue": "f9b923a566d62de047c753637143d439ca1c25221c08352ddc1738ff4a6ac721" + "checksumValue": "f262738390f56e8e9692acadecd1434c688075047d788283e1fb45d920ea6956" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_Blake2b.h" @@ -748,11 +748,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "878ae284c93824b80b1763e8b3e6be3c410777a8" + "checksumValue": "b600c1b5eafc34b29a778186737d8a51e2342d85" }, { "algorithm": "SHA256", - "checksumValue": "49df6223f6403daf503a1af1a3d2f943d30b5889fe7ed20299c3df24c1e3853d" + "checksumValue": "f22e088ad9c2eb739aefc3685ef3ab1ccaab3c5ef2e5d06cc846ad9f8e3d2669" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_Blake2b_Simd256.h" @@ -762,11 +762,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "25552d8cbf8aa345907635b38f284eec9075301e" + "checksumValue": "eb618ecc6ca2830066448f5f6d4df84a5c09f0f4" }, { "algorithm": "SHA256", - "checksumValue": "a3424cf4c5518654908086bbbf5d465715ec3b23625ef0cadc29492d1f90366c" + "checksumValue": "a4728e43deb0a9d8213b8ddcbda68a63bc73a12fb99aad54b7d28b314776a0d4" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_Blake2s.h" @@ -776,11 +776,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "54a712fc3ed5a817288351cbac5b7d9afa7e379f" + "checksumValue": "5441b6a97cc053c332b29477238d70fa011c74ac" }, { "algorithm": "SHA256", - "checksumValue": "c6abae648b8a1e9d5631c0a959620cad1f7e92ce522e07c3416199fe51debef6" + "checksumValue": "dad568d256a2ccbbbcdd419fe0543ea7137d8065a713a5f009aa52521c0f7f6a" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_Blake2s_Simd128.h" @@ -790,11 +790,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "c15c5f83bbb9f62611c49f0f8f723eaab1a27488" + "checksumValue": "7081b58f28568f600d4624dd5bd6f735191e068b" }, { "algorithm": "SHA256", - "checksumValue": "95cd5d91c4a9217901d0b3395dcd8881e62e2055d723b532ec5176386a636d22" + "checksumValue": "305af1422213ed97e8e5d3d8a9dfee4f21cb2fcd2acf65ee7303ce00b2b4bd2a" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_MD5.h" @@ -804,11 +804,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7b8717e3a24e7e16a34b251d0d02da6f68439695" + "checksumValue": "b6fb6219cb40d039e789666e34b43461e3b5c82a" }, { "algorithm": "SHA256", - "checksumValue": "9473d8bc9506fe0053d7d98c225d4873011329863f1c4a8e93e43fc71bd1f314" + "checksumValue": "63c58363ff95e8146d5628dab2da25bc2fd0e8b590fd4823b512c33f843355bb" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_SHA1.h" @@ -818,11 +818,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "e319c949f5a2dd765be2c8c7ff77bfe52ee6c7da" + "checksumValue": "bcc71e702df1070cb0081cb983aec7683e036719" }, { "algorithm": "SHA256", - "checksumValue": "75261448e51c3eb1ba441e973b193e23570b167f67743942ee2ee57417491c9f" + "checksumValue": "709c6272f77e2368f6cc0bf36527e3b16dd5d5f3dc26a2afdef8238200af8770" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_SHA2.h" @@ -832,11 +832,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "dbd92415c31606804102b79d5ba3d1752fe03887" + "checksumValue": "e3b5e6add5357760554b032b818992ce9bc211e0" }, { "algorithm": "SHA256", - "checksumValue": "5d74a76a0ac3659a1ae1276c3ca55521f09e83d2f0039f5c519a76f8f3c76a8e" + "checksumValue": "cf49d536a5663379fb4517018b4b3f8a232f8d4c7ddc7edfd60163d13f98a530" } ], "fileName": "Modules/_hacl/internal/Hacl_Hash_SHA3.h" @@ -846,11 +846,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "ad788265f8e1b078c4d1cb6e90b8c031590e6baf" + "checksumValue": "09a0ea364fb073f5f622a763f1351fbf4bac4627" }, { "algorithm": "SHA256", - "checksumValue": "d8354a9b75e2470085fa7e538493130e81fa23a804a6a69d34da8fdcc941c038" + "checksumValue": "916d54d7217517f0360edea920dc21585fbe6d1c2458eac86826182e12c82ec2" } ], "fileName": "Modules/_hacl/internal/Hacl_Impl_Blake2_Constants.h" @@ -860,11 +860,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "2048f3cd61dbda2df862a2982ebaf24b6815ed51" + "checksumValue": "b082645b43f8841db5e9e57c0b9a3825fa7e52f5" }, { "algorithm": "SHA256", - "checksumValue": "b0f5a79c98525b0cb1659238e095641328b7da16a94cb57a0793e635d1da3653" + "checksumValue": "059cf0d31427abf84c626797a97c140630a1a6ead578005162f46fad46663389" } ], "fileName": "Modules/_hacl/internal/Hacl_Streaming_HMAC.h" @@ -874,11 +874,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "4e6b098e89fd447bd03f47b55208208456b20966" + "checksumValue": "1f85ed69e395829b3ac5af9e2d049af7708cb9cb" }, { "algorithm": "SHA256", - "checksumValue": "d54d947968ca125978d61fea844711b990f0a18ab0fbca87e41029004d9d04b6" + "checksumValue": "76997c7069a347ac78b65d26354a0324d54add4ca7a02e7be36d6d5e1c9702e0" } ], "fileName": "Modules/_hacl/internal/Hacl_Streaming_Types.h" @@ -944,11 +944,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "0fbc026a9771d9675e7094790b5b945334d3cb53" + "checksumValue": "0d83ed429ede0a2c6617cd2f24490be16d8393f4" }, { "algorithm": "SHA256", - "checksumValue": "1e77c01eec8f167ed10b754f153c0c743c8e5196ae9c81dffc08f129ab56dbfd" + "checksumValue": "876f4486d08d3eac3581a8681d7fb3cec2fe5b823d1bef27cca15e755510365c" } ], "fileName": "Lib/ctypes/macholib/__init__.py" @@ -1730,14 +1730,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "17aa6cfc5c4c219c09287abfc10bc13f0c06f30bb654b28bfe6f567ca646eb79" + "checksumValue": "821ac9710d2c073eaf13e1b1895a9c9aa66c1157a99635c639fbff65cdbdd732" } ], - "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_6_3/expat-2.6.3.tar.gz", + "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_7_3/expat-2.7.3.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.6.3:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.7.3:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1745,21 +1745,21 @@ "name": "expat", "originator": "Organization: Expat development team", "primaryPackagePurpose": "SOURCE", - "versionInfo": "2.6.3" + "versionInfo": "2.7.3" }, { "SPDXID": "SPDXRef-PACKAGE-hacl-star", "checksums": [ { "algorithm": "SHA256", - "checksumValue": "39f6fd4f2fe98aecc995a2fd980fae0e0835cef6e563ebbf25f69d3d3102bafd" + "checksumValue": "61e48893f37cb2280d106cefacf6fb5afe84edf625fec39572d0ee94e1018f26" } ], - "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/4ef25b547b377dcef855db4289c6a00580e7221c.zip", + "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/8ba599b2f6c9701b3dc961db895b0856a2210f76.zip", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:4ef25b547b377dcef855db4289c6a00580e7221c:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:8ba599b2f6c9701b3dc961db895b0856a2210f76:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1767,7 +1767,7 @@ "name": "hacl-star", "originator": "Organization: HACL* Developers", "primaryPackagePurpose": "SOURCE", - "versionInfo": "4ef25b547b377dcef855db4289c6a00580e7221c" + "versionInfo": "8ba599b2f6c9701b3dc961db895b0856a2210f76" }, { "SPDXID": "SPDXRef-PACKAGE-macholib", diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 1f323cc0397..31d22e64b84 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -1335,6 +1335,7 @@ abi_only = true [function.PySys_ResetWarnOptions] added = '3.2' + abi_only = true [function.PySys_SetArgv] added = '3.2' [function.PySys_SetArgvEx] @@ -1599,6 +1600,7 @@ added = '3.2' [function.PyWeakref_GetObject] added = '3.2' + abi_only = true [function.PyWeakref_NewProxy] added = '3.2' [function.PyWeakref_NewRef] @@ -1900,6 +1902,13 @@ added = '3.5' [data.PyModuleDef_Type] added = '3.5' +[const.Py_mod_create] + added = '3.5' +[const.Py_mod_exec] + added = '3.5' +[struct.PyModuleDef_Slot] + added = '3.5' + struct_abi_kind = 'full-abi' # New slots in 3.5: # d51374ed78a3e3145911a16cdf3b9b84b3ba7d15 - Matrix multiplication (PEP 465) @@ -2304,6 +2313,10 @@ added = '3.11' [function.PyMemoryView_FromBuffer] added = '3.11' +[const.Py_bf_getbuffer] + added = '3.11' +[const.Py_bf_releasebuffer] + added = '3.11' # Constants for Py_buffer API added to this list in Python 3.11.1 (https://github.com/python/cpython/issues/98680) # (they were available with 3.11.0) @@ -2438,6 +2451,9 @@ added = '3.12' [const.Py_TPFLAGS_ITEMS_AT_END] added = '3.12' +[const.Py_mod_multiple_interpreters] + added = '3.12' + [function.PyImport_AddModuleRef] added = '3.13' [function.PyWeakref_GetRef] @@ -2516,10 +2532,14 @@ added = '3.13' [function.PyEval_GetFrameLocals] added = '3.13' +[const.Py_mod_gil] + added = '3.13' [function.Py_TYPE] + # Before 3.14, this was a macro that accessed the PyObject member added = '3.14' [function.Py_REFCNT] + # Before 3.14, this was a macro that accessed the PyObject member added = '3.14' [function.PyIter_NextItem] added = '3.14' @@ -2575,6 +2595,7 @@ added = '3.14' [function.Py_PACK_VERSION] added = '3.14' + [function.PySys_GetAttr] added = '3.15' [function.PySys_GetAttrString] @@ -2583,3 +2604,63 @@ added = '3.15' [function.PySys_GetOptionalAttrString] added = '3.15' +[function.PyABIInfo_Check] + added = '3.15' +[macro.PyABIInfo_VAR] + added = '3.15' +[struct.PyABIInfo] + added = '3.15' + struct_abi_kind = 'full-abi' +[const.Py_mod_abi] + added = '3.15' +[const.PyABIInfo_DEFAULT_ABI_VERSION] + added = '3.15' +[const.PyABIInfo_DEFAULT_FLAGS] + added = '3.15' +[const.PyABIInfo_STABLE] + added = '3.15' +[const.PyABIInfo_FREETHREADED] + added = '3.15' +[const.PyABIInfo_GIL] + added = '3.15' +[const.PyABIInfo_FREETHREADING_AGNOSTIC] + added = '3.15' +[function.PyModule_FromSlotsAndSpec] + added = '3.15' +[function.PyModule_Exec] + added = '3.15' +[function.PyModule_GetToken] + added = '3.15' +[function.PyType_GetModuleByToken] + added = '3.15' +[function.PyModule_GetStateSize] + added = '3.15' +[macro.PyMODEXPORT_FUNC] + added = '3.15' +[const.Py_mod_name] + added = '3.15' +[const.Py_mod_doc] + added = '3.15' +[const.Py_mod_state_size] + added = '3.15' +[const.Py_mod_methods] + added = '3.15' +[const.Py_mod_state_traverse] + added = '3.15' +[const.Py_mod_state_clear] + added = '3.15' +[const.Py_mod_state_free] + added = '3.15' +[const.Py_mod_token] + added = '3.15' +[function.PyDict_SetDefaultRef] + added = '3.15' +[function.Py_SIZE] + # Before 3.15, this was a macro that accessed the PyObject member + added = '3.15' +[function.Py_IS_TYPE] + # Before 3.15, this was a macro that accessed the PyObject member + added = '3.15' +[function.Py_SET_SIZE] + # Before 3.15, this was a macro that accessed the PyObject member + added = '3.15' diff --git a/Modules/Setup b/Modules/Setup index a066982df1a..7d816ead843 100644 --- a/Modules/Setup +++ b/Modules/Setup @@ -156,6 +156,7 @@ PYTHONPATH=$(COREPYTHONPATH) #binascii binascii.c #cmath cmathmodule.c #math mathmodule.c +#_math_integer mathintegermodule.c #mmap mmapmodule.c #select selectmodule.c #_sysconfig _sysconfig.c @@ -284,7 +285,7 @@ PYTHONPATH=$(COREPYTHONPATH) #*shared* #_ctypes_test _ctypes/_ctypes_test.c -#_remote_debugging _remote_debugging_module.c +#_remote_debugging _remote_debugging/module.c _remote_debugging/object_reading.c _remote_debugging/code_objects.c _remote_debugging/frames.c _remote_debugging/threads.c _remote_debugging/asyncio.c #_testcapi _testcapimodule.c #_testimportmultiple _testimportmultiple.c #_testmultiphase _testmultiphase.c diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 7f4c4a80673..acb08400e24 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -37,10 +37,11 @@ @MODULE__HEAPQ_TRUE@_heapq _heapqmodule.c @MODULE__JSON_TRUE@_json _json.c @MODULE__LSPROF_TRUE@_lsprof _lsprof.c rotatingtree.c +@MODULE__MATH_INTEGER_TRUE@_math_integer mathintegermodule.c @MODULE__PICKLE_TRUE@_pickle _pickle.c @MODULE__QUEUE_TRUE@_queue _queuemodule.c @MODULE__RANDOM_TRUE@_random _randommodule.c -@MODULE__REMOTE_DEBUGGING_TRUE@_remote_debugging _remote_debugging_module.c +@MODULE__REMOTE_DEBUGGING_TRUE@_remote_debugging _remote_debugging/module.c _remote_debugging/object_reading.c _remote_debugging/code_objects.c _remote_debugging/frames.c _remote_debugging/frame_cache.c _remote_debugging/threads.c _remote_debugging/asyncio.c _remote_debugging/subprocess.c @MODULE__STRUCT_TRUE@_struct _struct.c # build supports subinterpreters @@ -174,7 +175,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c @MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c @MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 99408e60721..0b2a5d7093e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -119,7 +119,7 @@ typedef struct _Py_AsyncioModuleDebugOffsets { } asyncio_thread_state; } Py_AsyncioModuleDebugOffsets; -GENERATE_DEBUG_SECTION(AsyncioDebug, Py_AsyncioModuleDebugOffsets _AsyncioDebug) +GENERATE_DEBUG_SECTION(AsyncioDebug, Py_AsyncioModuleDebugOffsets _Py_AsyncioDebug) = {.asyncio_task_object = { .size = sizeof(TaskObj), .task_name = offsetof(TaskObj, task_name), @@ -2076,8 +2076,8 @@ class _asyncio.Task "TaskObj *" "&Task_Type" static int task_call_step_soon(asyncio_state *state, TaskObj *, PyObject *); static PyObject *task_wakeup(PyObject *op, PyObject *arg); -static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *); -static int task_eager_start(asyncio_state *state, TaskObj *task); +static PyObject *task_step(asyncio_state *, TaskObj *, PyObject *); +static int task_eager_start(_PyThreadStateImpl *ts, asyncio_state *state, TaskObj *task); /* ----- Task._step wrapper */ @@ -2195,15 +2195,14 @@ static PyMethodDef TaskWakeupDef = { /* ----- Task introspection helpers */ static void -register_task(TaskObj *task) +register_task(_PyThreadStateImpl *ts, TaskObj *task) { if (task->task_node.next != NULL) { // already registered assert(task->task_node.prev != NULL); return; } - _PyThreadStateImpl *tstate = (_PyThreadStateImpl *) _PyThreadState_GET(); - struct llist_node *head = &tstate->asyncio_tasks_head; + struct llist_node *head = &ts->asyncio_tasks_head; llist_insert_tail(head, &task->task_node); } @@ -2241,10 +2240,8 @@ unregister_task(TaskObj *task) } static int -enter_task(PyObject *loop, PyObject *task) +enter_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task) { - _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); - if (ts->asyncio_running_loop != loop) { PyErr_Format(PyExc_RuntimeError, "loop %R is not the running loop", loop); return -1; @@ -2264,10 +2261,8 @@ enter_task(PyObject *loop, PyObject *task) } static int -leave_task(PyObject *loop, PyObject *task) +leave_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task) { - _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); - if (ts->asyncio_running_loop != loop) { PyErr_Format(PyExc_RuntimeError, "loop %R is not the running loop", loop); return -1; @@ -2286,10 +2281,8 @@ leave_task(PyObject *loop, PyObject *task) } static PyObject * -swap_current_task(PyObject *loop, PyObject *task) +swap_current_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task) { - _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); - if (ts->asyncio_running_loop != loop) { PyErr_Format(PyExc_RuntimeError, "loop %R is not the running loop", loop); return NULL; @@ -2384,7 +2377,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, if (self->task_name == NULL) { return -1; } - + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); if (eager_start) { PyObject *res = PyObject_CallMethodNoArgs(loop, &_Py_ID(is_running)); if (res == NULL) { @@ -2393,7 +2386,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, int is_loop_running = Py_IsTrue(res); Py_DECREF(res); if (is_loop_running) { - if (task_eager_start(state, self)) { + if (task_eager_start(ts, state, self)) { return -1; } return 0; @@ -2408,7 +2401,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, // works correctly in non-owning threads. _PyObject_SetMaybeWeakref((PyObject *)self); #endif - register_task(self); + register_task(ts, self); return 0; } @@ -2990,16 +2983,12 @@ static PyType_Spec Task_spec = { static void TaskObj_dealloc(PyObject *self) { - _PyObject_ResurrectStart(self); - // Unregister the task here so that even if any subclass of Task - // which doesn't end up calling TaskObj_finalize not crashes. - unregister_task((TaskObj *)self); - - PyObject_CallFinalizer(self); - - if (_PyObject_ResurrectEnd(self)) { - return; + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + return; // resurrected } + // unregister the task after finalization so that + // if the task gets resurrected, it remains registered + unregister_task((TaskObj *)self); PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); @@ -3456,7 +3445,9 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc) { PyObject *res; - if (enter_task(task->task_loop, (PyObject*)task) < 0) { + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + + if (enter_task(ts, task->task_loop, (PyObject*)task) < 0) { return NULL; } @@ -3464,12 +3455,12 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc) if (res == NULL) { PyObject *exc = PyErr_GetRaisedException(); - leave_task(task->task_loop, (PyObject*)task); + leave_task(ts, task->task_loop, (PyObject*)task); _PyErr_ChainExceptions1(exc); return NULL; } else { - if (leave_task(task->task_loop, (PyObject*)task) < 0) { + if (leave_task(ts, task->task_loop, (PyObject*)task) < 0) { Py_DECREF(res); return NULL; } @@ -3480,10 +3471,10 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc) } static int -task_eager_start(asyncio_state *state, TaskObj *task) +task_eager_start(_PyThreadStateImpl *ts, asyncio_state *state, TaskObj *task) { assert(task != NULL); - PyObject *prevtask = swap_current_task(task->task_loop, (PyObject *)task); + PyObject *prevtask = swap_current_task(ts, task->task_loop, (PyObject *)task); if (prevtask == NULL) { return -1; } @@ -3491,9 +3482,9 @@ task_eager_start(asyncio_state *state, TaskObj *task) // if the task completes eagerly (without suspending) then it will unregister itself // in future_schedule_callbacks when done, otherwise // it will continue as a regular (non-eager) asyncio task - register_task(task); + register_task(ts, task); - if (PyContext_Enter(task->task_context) == -1) { + if (_PyContext_Enter(&ts->base, task->task_context) == -1) { Py_DECREF(prevtask); return -1; } @@ -3512,7 +3503,7 @@ task_eager_start(asyncio_state *state, TaskObj *task) Py_DECREF(stepres); } - PyObject *curtask = swap_current_task(task->task_loop, prevtask); + PyObject *curtask = swap_current_task(ts, task->task_loop, prevtask); Py_DECREF(prevtask); if (curtask == NULL) { retval = -1; @@ -3521,7 +3512,7 @@ task_eager_start(asyncio_state *state, TaskObj *task) Py_DECREF(curtask); } - if (PyContext_Exit(task->task_context) == -1) { + if (_PyContext_Exit(&ts->base, task->task_context) == -1) { retval = -1; } @@ -3716,7 +3707,8 @@ _asyncio__register_task_impl(PyObject *module, PyObject *task) if (Task_Check(state, task)) { // task is an asyncio.Task instance or subclass, use efficient // linked-list implementation. - register_task((TaskObj *)task); + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + register_task(ts, (TaskObj *)task); Py_RETURN_NONE; } // As task does not inherit from asyncio.Task, fallback to less efficient @@ -3749,7 +3741,8 @@ _asyncio__register_eager_task_impl(PyObject *module, PyObject *task) if (Task_Check(state, task)) { // task is an asyncio.Task instance or subclass, use efficient // linked-list implementation. - register_task((TaskObj *)task); + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + register_task(ts, (TaskObj *)task); Py_RETURN_NONE; } @@ -3836,7 +3829,8 @@ static PyObject * _asyncio__enter_task_impl(PyObject *module, PyObject *loop, PyObject *task) /*[clinic end generated code: output=a22611c858035b73 input=de1b06dca70d8737]*/ { - if (enter_task(loop, task) < 0) { + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + if (enter_task(ts, loop, task) < 0) { return NULL; } Py_RETURN_NONE; @@ -3860,7 +3854,8 @@ static PyObject * _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task) /*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/ { - if (leave_task(loop, task) < 0) { + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + if (leave_task(ts, loop, task) < 0) { return NULL; } Py_RETURN_NONE; @@ -3884,7 +3879,8 @@ _asyncio__swap_current_task_impl(PyObject *module, PyObject *loop, PyObject *task) /*[clinic end generated code: output=9f88de958df74c7e input=c9c72208d3d38b6c]*/ { - return swap_current_task(loop, task); + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + return swap_current_task(ts, loop, task); } @@ -4079,30 +4075,44 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop) return NULL; } - PyInterpreterState *interp = PyInterpreterState_Get(); - // Stop the world and traverse the per-thread linked list - // of asyncio tasks for every thread, as well as the - // interpreter's linked list, and add them to `tasks`. - // The interpreter linked list is used for any lingering tasks - // whose thread state has been deallocated while the task was - // still alive. This can happen if a task is referenced by - // a different thread, in which case the task is moved to - // the interpreter's linked list from the thread's linked - // list before deallocation. See PyThreadState_Clear. - // - // The stop-the-world pause is required so that no thread - // modifies its linked list while being iterated here - // in parallel. This design allows for lock-free - // register_task/unregister_task for loops running in parallel - // in different threads (the general case). - _PyEval_StopTheWorld(interp); - int ret = add_tasks_interp(interp, (PyListObject *)tasks); - _PyEval_StartTheWorld(interp); - if (ret < 0) { - // call any escaping calls after starting the world to avoid any deadlocks. - Py_DECREF(tasks); - Py_DECREF(loop); - return NULL; + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); + if (ts->asyncio_running_loop == loop) { + // Fast path for the current running loop of current thread + // no locking or stop the world pause is required + struct llist_node *head = &ts->asyncio_tasks_head; + if (add_tasks_llist(head, (PyListObject *)tasks) < 0) { + Py_DECREF(tasks); + Py_DECREF(loop); + return NULL; + } + } + else { + // Slow path for loop running in different thread + PyInterpreterState *interp = ts->base.interp; + // Stop the world and traverse the per-thread linked list + // of asyncio tasks for every thread, as well as the + // interpreter's linked list, and add them to `tasks`. + // The interpreter linked list is used for any lingering tasks + // whose thread state has been deallocated while the task was + // still alive. This can happen if a task is referenced by + // a different thread, in which case the task is moved to + // the interpreter's linked list from the thread's linked + // list before deallocation. See PyThreadState_Clear. + // + // The stop-the-world pause is required so that no thread + // modifies its linked list while being iterated here + // in parallel. This design allows for lock-free + // register_task/unregister_task for loops running in parallel + // in different threads (the general case). + _PyEval_StopTheWorld(interp); + int ret = add_tasks_interp(interp, (PyListObject *)tasks); + _PyEval_StartTheWorld(interp); + if (ret < 0) { + // call any escaping calls after starting the world to avoid any deadlocks. + Py_DECREF(tasks); + Py_DECREF(loop); + return NULL; + } } // All the tasks are now in the list, now filter the tasks which are done @@ -4324,7 +4334,7 @@ module_init(asyncio_state *state) goto fail; } - state->debug_offsets = &_AsyncioDebug; + state->debug_offsets = &_Py_AsyncioDebug; Py_DECREF(module); return 0; diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 9b146265445..3a1491e5b96 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -57,10 +57,6 @@ internal_bisect_right(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t Py_ssize_t mid; int res; - if (lo < 0) { - PyErr_SetString(PyExc_ValueError, "lo must be non-negative"); - return -1; - } if (hi == -1) { hi = PySequence_Size(list); if (hi < 0) @@ -153,7 +149,7 @@ _bisect.bisect_right -> Py_ssize_t a: object x: object - lo: Py_ssize_t = 0 + lo: Py_ssize_t(allow_negative=False) = 0 hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None * key: object = None @@ -173,7 +169,7 @@ A custom key function can be supplied to customize the sort order. static Py_ssize_t _bisect_bisect_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=3a4bc09cc7c8a73d input=43071869772dd53a]*/ +/*[clinic end generated code: output=3a4bc09cc7c8a73d input=b476bc45667273ac]*/ { return internal_bisect_right(a, x, lo, hi, key); } @@ -183,7 +179,7 @@ _bisect.insort_right a: object x: object - lo: Py_ssize_t = 0 + lo: Py_ssize_t(allow_negative=False) = 0 hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None * key: object = None @@ -201,7 +197,7 @@ A custom key function can be supplied to customize the sort order. static PyObject * _bisect_insort_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=ac3bf26d07aedda2 input=f60777d2b6ddb239]*/ +/*[clinic end generated code: output=ac3bf26d07aedda2 input=f2caa8abec0763e8]*/ { PyObject *result, *key_x; Py_ssize_t index; @@ -241,10 +237,6 @@ internal_bisect_left(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t h Py_ssize_t mid; int res; - if (lo < 0) { - PyErr_SetString(PyExc_ValueError, "lo must be non-negative"); - return -1; - } if (hi == -1) { hi = PySequence_Size(list); if (hi < 0) @@ -338,7 +330,7 @@ _bisect.bisect_left -> Py_ssize_t a: object x: object - lo: Py_ssize_t = 0 + lo: Py_ssize_t(allow_negative=False) = 0 hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None * key: object = None @@ -358,7 +350,7 @@ A custom key function can be supplied to customize the sort order. static Py_ssize_t _bisect_bisect_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=70749d6e5cae9284 input=f29c4fe7f9b797c7]*/ +/*[clinic end generated code: output=70749d6e5cae9284 input=9b4d49b5ddecfad7]*/ { return internal_bisect_left(a, x, lo, hi, key); } @@ -369,7 +361,7 @@ _bisect.insort_left a: object x: object - lo: Py_ssize_t = 0 + lo: Py_ssize_t(allow_negative=False) = 0 hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None * key: object = None @@ -387,7 +379,7 @@ A custom key function can be supplied to customize the sort order. static PyObject * _bisect_insort_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=b1d33e5e7ffff11e input=0a700a82edbd472c]*/ +/*[clinic end generated code: output=b1d33e5e7ffff11e input=ff85a79826e22f31]*/ { PyObject *result, *key_x; Py_ssize_t index; diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 91417268415..f3457a13c96 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -12,6 +12,7 @@ // Blocks output buffer wrappers #include "pycore_blocks_output_buffer.h" +#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_CHAR_RELAXED #if OUTPUT_BUFFER_MAX_BLOCK_SIZE > UINT32_MAX #error "The maximum block size accepted by libbzip2 is UINT32_MAX." @@ -97,20 +98,11 @@ OutputBuffer_OnError(_BlocksOutputBuffer *buffer) #endif /* ! BZ_CONFIG_ERROR */ -#define ACQUIRE_LOCK(obj) do { \ - if (!PyThread_acquire_lock((obj)->lock, 0)) { \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock((obj)->lock, 1); \ - Py_END_ALLOW_THREADS \ - } } while (0) -#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock) - - typedef struct { PyObject_HEAD bz_stream bzs; int flushed; - PyThread_type_lock lock; + PyMutex mutex; } BZ2Compressor; typedef struct { @@ -126,7 +118,7 @@ typedef struct { separately. Conversion and looping is encapsulated in decompress_buf() */ size_t bzs_avail_in_real; - PyThread_type_lock lock; + PyMutex mutex; } BZ2Decompressor; #define _BZ2Compressor_CAST(op) ((BZ2Compressor *)(op)) @@ -190,7 +182,7 @@ static PyObject * compress(BZ2Compressor *c, char *data, size_t len, int action) { PyObject *result; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; if (OutputBuffer_InitAndGrow(&buffer, -1, &c->bzs.next_out, &c->bzs.avail_out) < 0) { goto error; @@ -271,12 +263,12 @@ _bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data) { PyObject *result = NULL; - ACQUIRE_LOCK(self); + PyMutex_Lock(&self->mutex); if (self->flushed) PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); else result = compress(self, data->buf, data->len, BZ_RUN); - RELEASE_LOCK(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -296,14 +288,14 @@ _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) { PyObject *result = NULL; - ACQUIRE_LOCK(self); + PyMutex_Lock(&self->mutex); if (self->flushed) PyErr_SetString(PyExc_ValueError, "Repeated call to flush()"); else { self->flushed = 1; result = compress(self, NULL, 0, BZ_FINISH); } - RELEASE_LOCK(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -357,13 +349,7 @@ _bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel) return NULL; } - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - Py_DECREF(self); - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return NULL; - } - + self->mutex = (PyMutex){0}; self->bzs.opaque = NULL; self->bzs.bzalloc = BZ2_Malloc; self->bzs.bzfree = BZ2_Free; @@ -382,22 +368,13 @@ static void BZ2Compressor_dealloc(PyObject *op) { BZ2Compressor *self = _BZ2Compressor_CAST(op); + assert(!PyMutex_IsLocked(&self->mutex)); BZ2_bzCompressEnd(&self->bzs); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); - } PyTypeObject *tp = Py_TYPE(self); tp->tp_free((PyObject *)self); Py_DECREF(tp); } -static int -BZ2Compressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef BZ2Compressor_methods[] = { _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF @@ -409,7 +386,6 @@ static PyType_Slot bz2_compressor_type_slots[] = { {Py_tp_methods, BZ2Compressor_methods}, {Py_tp_new, _bz2_BZ2Compressor}, {Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__}, - {Py_tp_traverse, BZ2Compressor_traverse}, {0, 0} }; @@ -437,7 +413,7 @@ decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length) compare against max_length and PyBytes_GET_SIZE we declare it as signed */ PyObject *result; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; bz_stream *bzs = &d->bzs; if (OutputBuffer_InitAndGrow(&buffer, max_length, &bzs->next_out, &bzs->avail_out) < 0) { @@ -462,7 +438,7 @@ decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length) if (catch_bz2_error(bzret)) goto error; if (bzret == BZ_STREAM_END) { - d->eof = 1; + FT_ATOMIC_STORE_CHAR_RELAXED(d->eof, 1); break; } else if (d->bzs_avail_in_real == 0) { break; @@ -546,7 +522,7 @@ decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) } if (d->eof) { - d->needs_input = 0; + FT_ATOMIC_STORE_CHAR_RELAXED(d->needs_input, 0); if (d->bzs_avail_in_real > 0) { Py_XSETREF(d->unused_data, PyBytes_FromStringAndSize(bzs->next_in, d->bzs_avail_in_real)); @@ -556,10 +532,10 @@ decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) } else if (d->bzs_avail_in_real == 0) { bzs->next_in = NULL; - d->needs_input = 1; + FT_ATOMIC_STORE_CHAR_RELAXED(d->needs_input, 1); } else { - d->needs_input = 0; + FT_ATOMIC_STORE_CHAR_RELAXED(d->needs_input, 0); /* If we did not use the input buffer, we now have to copy the tail from the caller's buffer into the @@ -627,12 +603,12 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, { PyObject *result = NULL; - ACQUIRE_LOCK(self); + PyMutex_Lock(&self->mutex); if (self->eof) PyErr_SetString(PyExc_EOFError, "End of stream already reached"); else result = decompress(self, data->buf, data->len, max_length); - RELEASE_LOCK(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -658,20 +634,12 @@ _bz2_BZ2Decompressor_impl(PyTypeObject *type) return NULL; } - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - Py_DECREF(self); - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return NULL; - } - + self->mutex = (PyMutex){0}; self->needs_input = 1; self->bzs_avail_in_real = 0; self->input_buffer = NULL; self->input_buffer_size = 0; - self->unused_data = PyBytes_FromStringAndSize(NULL, 0); - if (self->unused_data == NULL) - goto error; + self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); if (catch_bz2_error(bzerror)) @@ -688,28 +656,19 @@ static void BZ2Decompressor_dealloc(PyObject *op) { BZ2Decompressor *self = _BZ2Decompressor_CAST(op); + assert(!PyMutex_IsLocked(&self->mutex)); if(self->input_buffer != NULL) { PyMem_Free(self->input_buffer); } BZ2_bzDecompressEnd(&self->bzs); Py_CLEAR(self->unused_data); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); - } PyTypeObject *tp = Py_TYPE(self); tp->tp_free((PyObject *)self); Py_DECREF(tp); } -static int -BZ2Decompressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef BZ2Decompressor_methods[] = { _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF {NULL} @@ -724,11 +683,28 @@ PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__, PyDoc_STRVAR(BZ2Decompressor_needs_input_doc, "True if more input is needed before more decompressed data can be produced."); +static PyObject * +BZ2Decompressor_unused_data_get(PyObject *op, void *Py_UNUSED(ignored)) +{ + BZ2Decompressor *self = _BZ2Decompressor_CAST(op); + PyMutex_Lock(&self->mutex); + PyObject *result = Py_XNewRef(self->unused_data); + PyMutex_Unlock(&self->mutex); + if (result == NULL) { + PyErr_SetString(PyExc_AttributeError, "unused_data"); + } + return result; +} + +static PyGetSetDef BZ2Decompressor_getset[] = { + {"unused_data", BZ2Decompressor_unused_data_get, NULL, + BZ2Decompressor_unused_data__doc__}, + {NULL}, +}; + static PyMemberDef BZ2Decompressor_members[] = { {"eof", Py_T_BOOL, offsetof(BZ2Decompressor, eof), Py_READONLY, BZ2Decompressor_eof__doc__}, - {"unused_data", Py_T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data), - Py_READONLY, BZ2Decompressor_unused_data__doc__}, {"needs_input", Py_T_BOOL, offsetof(BZ2Decompressor, needs_input), Py_READONLY, BZ2Decompressor_needs_input_doc}, {NULL} @@ -739,8 +715,8 @@ static PyType_Slot bz2_decompressor_type_slots[] = { {Py_tp_methods, BZ2Decompressor_methods}, {Py_tp_doc, (char *)_bz2_BZ2Decompressor__doc__}, {Py_tp_members, BZ2Decompressor_members}, + {Py_tp_getset, BZ2Decompressor_getset}, {Py_tp_new, _bz2_BZ2Decompressor}, - {Py_tp_traverse, BZ2Decompressor_traverse}, {0, 0} }; diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index 82a46ec1e70..2f2edbb05ab 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -202,55 +202,50 @@ _codecs_escape_encode_impl(PyObject *module, PyObject *data, const char *errors) /*[clinic end generated code: output=4af1d477834bab34 input=8f4b144799a94245]*/ { - Py_ssize_t size; - Py_ssize_t newsize; - PyObject *v; - - size = PyBytes_GET_SIZE(data); + Py_ssize_t size = PyBytes_GET_SIZE(data); if (size > PY_SSIZE_T_MAX / 4) { PyErr_SetString(PyExc_OverflowError, "string is too large to encode"); return NULL; } - newsize = 4*size; - v = PyBytes_FromStringAndSize(NULL, newsize); + Py_ssize_t newsize = 4*size; - if (v == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(newsize); + if (writer == NULL) { return NULL; } - else { - Py_ssize_t i; - char c; - char *p = PyBytes_AS_STRING(v); + char *p = PyBytesWriter_GetData(writer); - for (i = 0; i < size; i++) { - /* There's at least enough room for a hex escape */ - assert(newsize - (p - PyBytes_AS_STRING(v)) >= 4); - c = PyBytes_AS_STRING(data)[i]; - if (c == '\'' || c == '\\') - *p++ = '\\', *p++ = c; - else if (c == '\t') - *p++ = '\\', *p++ = 't'; - else if (c == '\n') - *p++ = '\\', *p++ = 'n'; - else if (c == '\r') - *p++ = '\\', *p++ = 'r'; - else if (c < ' ' || c >= 0x7f) { - *p++ = '\\'; - *p++ = 'x'; - *p++ = Py_hexdigits[(c & 0xf0) >> 4]; - *p++ = Py_hexdigits[c & 0xf]; - } - else - *p++ = c; + for (Py_ssize_t i = 0; i < size; i++) { + /* There's at least enough room for a hex escape */ + assert(newsize - (p - (char*)PyBytesWriter_GetData(writer)) >= 4); + + char c = PyBytes_AS_STRING(data)[i]; + if (c == '\'' || c == '\\') { + *p++ = '\\'; *p++ = c; } - *p = '\0'; - if (_PyBytes_Resize(&v, (p - PyBytes_AS_STRING(v)))) { - return NULL; + else if (c == '\t') { + *p++ = '\\'; *p++ = 't'; + } + else if (c == '\n') { + *p++ = '\\'; *p++ = 'n'; + } + else if (c == '\r') { + *p++ = '\\'; *p++ = 'r'; + } + else if (c < ' ' || c >= 0x7f) { + *p++ = '\\'; + *p++ = 'x'; + *p++ = Py_hexdigits[(c & 0xf0) >> 4]; + *p++ = Py_hexdigits[c & 0xf]; + } + else { + *p++ = c; } } - return codec_tuple(v, size); + PyObject *decoded = PyBytesWriter_FinishWithPointer(writer, p); + return codec_tuple(decoded, size); } /* --- Decoder ------------------------------------------------------------ */ @@ -676,7 +671,7 @@ _codecs_utf_7_encode_impl(PyObject *module, PyObject *str, const char *errors) /*[clinic end generated code: output=0feda21ffc921bc8 input=2546dbbb3fa53114]*/ { - return codec_tuple(_PyUnicode_EncodeUTF7(str, 0, 0, errors), + return codec_tuple(_PyUnicode_EncodeUTF7(str, errors), PyUnicode_GET_LENGTH(str)); } @@ -1023,6 +1018,47 @@ _codecs_lookup_error_impl(PyObject *module, const char *name) return PyCodec_LookupError(name); } +extern int _Py_normalize_encoding(const char *, char *, size_t, int); + +/*[clinic input] +_codecs._normalize_encoding + encoding: unicode + +Normalize an encoding name *encoding*. + +Used for encodings.normalize_encoding. Does not convert to lower case. +[clinic start generated code]*/ + +static PyObject * +_codecs__normalize_encoding_impl(PyObject *module, PyObject *encoding) +/*[clinic end generated code: output=d27465d81e361f8e input=3ff3f4d64995b988]*/ +{ + Py_ssize_t len; + const char *cstr = PyUnicode_AsUTF8AndSize(encoding, &len); + if (cstr == NULL) { + return NULL; + } + + if (len > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, "encoding is too large"); + return NULL; + } + + char *normalized = PyMem_Malloc(len + 1); + if (normalized == NULL) { + return PyErr_NoMemory(); + } + + if (!_Py_normalize_encoding(cstr, normalized, len + 1, 0)) { + PyMem_Free(normalized); + return NULL; + } + + PyObject *result = PyUnicode_FromString(normalized); + PyMem_Free(normalized); + return result; +} + /* --- Module API --------------------------------------------------------- */ static PyMethodDef _codecs_functions[] = { @@ -1072,6 +1108,7 @@ static PyMethodDef _codecs_functions[] = { _CODECS_REGISTER_ERROR_METHODDEF _CODECS__UNREGISTER_ERROR_METHODDEF _CODECS_LOOKUP_ERROR_METHODDEF + _CODECS__NORMALIZE_ENCODING_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 3ba48d5d9d3..3b14a21fa84 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2231,11 +2231,11 @@ defdict_missing(PyObject *op, PyObject *key) value = _PyObject_CallNoArgs(factory); if (value == NULL) return value; - if (PyObject_SetItem(op, key, value) < 0) { - Py_DECREF(value); - return NULL; - } - return value; + PyObject *result = NULL; + (void)PyDict_SetDefaultRef(op, key, value, &result); + // 'result' is NULL, or a strong reference to 'value' or 'op[key]' + Py_DECREF(value); + return result; } static inline PyObject* diff --git a/Modules/_csv.c b/Modules/_csv.c index 87be7a8f1fb..1f41976e95f 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -918,7 +918,7 @@ parse_reset(ReaderObj *self) } static PyObject * -Reader_iternext(PyObject *op) +Reader_iternext_lock_held(PyObject *op) { ReaderObj *self = _ReaderObj_CAST(op); @@ -985,6 +985,16 @@ err: return fields; } +static PyObject * +Reader_iternext(PyObject *op) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = Reader_iternext_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + static void Reader_dealloc(PyObject *op) { @@ -1303,15 +1313,8 @@ join_append_lineterminator(WriterObj *self) return 1; } -PyDoc_STRVAR(csv_writerow_doc, -"writerow($self, row, /)\n" -"--\n\n" -"Construct and write a CSV record from an iterable of fields.\n" -"\n" -"Non-string elements will be converted to string."); - static PyObject * -csv_writerow(PyObject *op, PyObject *seq) +csv_writerow_lock_held(PyObject *op, PyObject *seq) { WriterObj *self = _WriterObj_CAST(op); DialectObj *dialect = self->dialect; @@ -1414,6 +1417,23 @@ csv_writerow(PyObject *op, PyObject *seq) return result; } +PyDoc_STRVAR(csv_writerow_doc, +"writerow($self, row, /)\n" +"--\n\n" +"Construct and write a CSV record from an iterable of fields.\n" +"\n" +"Non-string elements will be converted to string."); + +static PyObject * +csv_writerow(PyObject *op, PyObject *seq) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = csv_writerow_lock_held(op, seq); + Py_END_CRITICAL_SECTION(); + return result; +} + PyDoc_STRVAR(csv_writerows_doc, "writerows($self, rows, /)\n" "--\n\n" diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 4bd3e380b3b..774ac71ce9e 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -859,7 +859,7 @@ _ctypes.CDataType.from_buffer as CDataType_from_buffer type: self cls: defining_class obj: object - offset: Py_ssize_t = 0 + offset: Py_ssize_t(allow_negative=False) = 0 / C.from_buffer(object, offset=0) -> C instance @@ -870,7 +870,7 @@ Create a C instance from a writeable buffer. static PyObject * CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj, Py_ssize_t offset) -/*[clinic end generated code: output=57604e99635abd31 input=0f36cedd105ca28d]*/ +/*[clinic end generated code: output=57604e99635abd31 input=8f43e6bc44373180]*/ { PyObject *mv; PyObject *result; @@ -906,13 +906,6 @@ CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj, return NULL; } - if (offset < 0) { - PyErr_SetString(PyExc_ValueError, - "offset cannot be negative"); - Py_DECREF(mv); - return NULL; - } - if (info->size > buffer->len - offset) { PyErr_Format(PyExc_ValueError, "Buffer size too small " @@ -955,7 +948,7 @@ _ctypes.CDataType.from_buffer_copy as CDataType_from_buffer_copy type: self cls: defining_class buffer: Py_buffer - offset: Py_ssize_t = 0 + offset: Py_ssize_t(allow_negative=False) = 0 / C.from_buffer_copy(object, offset=0) -> C instance @@ -966,7 +959,7 @@ Create a C instance from a readable buffer. static PyObject * CDataType_from_buffer_copy_impl(PyObject *type, PyTypeObject *cls, Py_buffer *buffer, Py_ssize_t offset) -/*[clinic end generated code: output=c8fc62b03e5cc6fa input=2a81e11b765a6253]*/ +/*[clinic end generated code: output=c8fc62b03e5cc6fa input=41f97f512295ceec]*/ { PyObject *result; @@ -980,12 +973,6 @@ CDataType_from_buffer_copy_impl(PyObject *type, PyTypeObject *cls, return NULL; } - if (offset < 0) { - PyErr_SetString(PyExc_ValueError, - "offset cannot be negative"); - return NULL; - } - if (info->size > buffer->len - offset) { PyErr_Format(PyExc_ValueError, "Buffer size too small (%zd instead of at least %zd bytes)", @@ -3647,6 +3634,9 @@ atomic_xgetref(PyObject *obj, PyObject **field) #endif } +static int +_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes); + /*[clinic input] @@ -3760,16 +3750,22 @@ static int _ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value) /*[clinic end generated code: output=596a36e2ae89d7d1 input=c4627573e980aa8b]*/ { - PyObject *converters; - if (value == NULL || value == Py_None) { atomic_xsetref(&self->argtypes, NULL); atomic_xsetref(&self->converters, NULL); } else { - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - converters = converters_from_argtypes(st, value); + PyTypeObject *type = Py_TYPE(self); + ctypes_state *st = get_module_state_by_def(Py_TYPE(type)); + + PyObject *converters = converters_from_argtypes(st, value); if (!converters) return -1; + + /* Verify paramflags again due to constraints with argtypes */ + if (!_validate_paramflags(st, type, self->paramflags, value)) { + Py_DECREF(converters); + return -1; + } atomic_xsetref(&self->converters, converters); Py_INCREF(value); atomic_xsetref(&self->argtypes, value); @@ -3899,10 +3895,9 @@ _check_outarg_type(ctypes_state *st, PyObject *arg, Py_ssize_t index) /* Returns 1 on success, 0 on error */ static int -_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags) +_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes) { Py_ssize_t i, len; - PyObject *argtypes; StgInfo *info; if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) { @@ -3913,10 +3908,13 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags) "abstract class"); return 0; } - argtypes = info->argtypes; + if (argtypes == NULL) { + argtypes = info->argtypes; + } - if (paramflags == NULL || info->argtypes == NULL) + if (paramflags == NULL || argtypes == NULL) { return 1; + } if (!PyTuple_Check(paramflags)) { PyErr_SetString(PyExc_TypeError, @@ -3925,7 +3923,7 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags) } len = PyTuple_GET_SIZE(paramflags); - if (len != PyTuple_GET_SIZE(info->argtypes)) { + if (len != PyTuple_GET_SIZE(argtypes)) { PyErr_SetString(PyExc_ValueError, "paramflags must have the same length as argtypes"); return 0; @@ -4101,7 +4099,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds) #endif #undef USE_DLERROR ctypes_state *st = get_module_state_by_def(Py_TYPE(type)); - if (!_validate_paramflags(st, type, paramflags)) { + if (!_validate_paramflags(st, type, paramflags, NULL)) { Py_DECREF(ftuple); return NULL; } @@ -4145,7 +4143,7 @@ PyCFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds) paramflags = NULL; ctypes_state *st = get_module_state_by_def(Py_TYPE(type)); - if (!_validate_paramflags(st, type, paramflags)) { + if (!_validate_paramflags(st, type, paramflags, NULL)) { return NULL; } self = (PyCFuncPtrObject *)generic_pycdata_new(st, type, args, kwds); @@ -6336,7 +6334,6 @@ _ctypes_add_objects(PyObject *mod) MOD_ADD("FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO)); MOD_ADD("FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR)); MOD_ADD("FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI)); - MOD_ADD("__version__", PyUnicode_FromString("1.1.0")); MOD_ADD("_memmove_addr", PyLong_FromVoidPtr(memmove)); MOD_ADD("_memset_addr", PyLong_FromVoidPtr(memset)); diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 66338805007..a0c9d8b70fe 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -989,13 +989,10 @@ EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, { case 0: return ar; - break; case 1: return dr; - break; case 2: return gr; - break; } return ar; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index a8c16547e4b..9a1c1ff8bb9 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1990,8 +1990,32 @@ buffer_info(PyObject *self, PyObject *arg) } +static PyObject * +_ctypes_getattr(PyObject *Py_UNUSED(self), PyObject *args) +{ + PyObject *name; + if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)) { + return NULL; + } + + if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "'__version__' is deprecated and slated for " + "removal in Python 3.20", + 1) < 0) { + return NULL; + } + return PyUnicode_FromString("1.1.0"); // Do not change + } + + PyErr_Format(PyExc_AttributeError, + "module '_ctypes' has no attribute %R", name); + return NULL; +} + PyMethodDef _ctypes_module_methods[] = { + {"__getattr__", _ctypes_getattr, METH_VARARGS}, {"get_errno", get_errno, METH_NOARGS}, {"set_errno", set_errno, METH_VARARGS}, {"_unpickle", unpickle, METH_VARARGS }, diff --git a/Modules/_ctypes/clinic/_ctypes.c.h b/Modules/_ctypes/clinic/_ctypes.c.h index cf2e3fa2107..529872f0f17 100644 --- a/Modules/_ctypes/clinic/_ctypes.c.h +++ b/Modules/_ctypes/clinic/_ctypes.c.h @@ -176,6 +176,11 @@ CDataType_from_buffer(PyObject *type, PyTypeObject *cls, PyObject *const *args, goto exit; } offset = ival; + if (offset < 0) { + PyErr_SetString(PyExc_ValueError, + "offset cannot be negative"); + goto exit; + } } skip_optional_posonly: return_value = CDataType_from_buffer_impl(type, cls, obj, offset); @@ -242,6 +247,11 @@ CDataType_from_buffer_copy(PyObject *type, PyTypeObject *cls, PyObject *const *a goto exit; } offset = ival; + if (offset < 0) { + PyErr_SetString(PyExc_ValueError, + "offset cannot be negative"); + goto exit; + } } skip_optional_posonly: return_value = CDataType_from_buffer_copy_impl(type, cls, &buffer, offset); @@ -1042,4 +1052,4 @@ Simple_from_outparm(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py } return Simple_from_outparm_impl(self, cls); } -/*[clinic end generated code: output=536c9bcf4e05913e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=22105663d71237ca input=a9049054013a1b77]*/ diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 9f995bf2408..478daecad55 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -608,7 +608,8 @@ PyStgInfo_FromAny(ctypes_state *state, PyObject *obj, StgInfo **result) return _stginfo_from_type(state, Py_TYPE(obj), result); } -/* A variant of PyStgInfo_FromType that doesn't need the state, +/* A variant of PyStgInfo_FromType that doesn't need the state + * and doesn't modify any refcounts, * so it can be called from finalization functions when the module * state is torn down. */ @@ -616,17 +617,12 @@ static inline StgInfo * _PyStgInfo_FromType_NoState(PyObject *type) { PyTypeObject *PyCType_Type; - if (PyType_GetBaseByToken(Py_TYPE(type), &pyctype_type_spec, &PyCType_Type) < 0) { - return NULL; - } - if (PyCType_Type == NULL) { - PyErr_Format(PyExc_TypeError, "expected a ctypes type, got '%N'", type); + if (_PyType_GetBaseByToken_Borrow(Py_TYPE(type), &pyctype_type_spec, &PyCType_Type) < 0 || + PyCType_Type == NULL) { return NULL; } - StgInfo *info = PyObject_GetTypeData(type, PyCType_Type); - Py_DECREF(PyCType_Type); - return info; + return PyObject_GetTypeData(type, PyCType_Type); } // Initialize StgInfo on a newly created type diff --git a/Modules/_ctypes/malloc_closure.c b/Modules/_ctypes/malloc_closure.c index db405acf872..62c7aa5d6af 100644 --- a/Modules/_ctypes/malloc_closure.c +++ b/Modules/_ctypes/malloc_closure.c @@ -14,6 +14,7 @@ # endif #endif #include "ctypes.h" +#include "pycore_mmap.h" // _PyAnnotateMemoryMap() /* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory overhead, but allocate less blocks from the system. It may be that some @@ -74,14 +75,16 @@ static void more_core(void) if (item == NULL) return; #else + size_t mem_size = count * sizeof(ITEM); item = (ITEM *)mmap(NULL, - count * sizeof(ITEM), + mem_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (item == (void *)MAP_FAILED) return; + _PyAnnotateMemoryMap(item, mem_size, "cpython:ctypes"); #endif #ifdef MALLOC_CLOSURE_DEBUG diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 3408a505575..3b46fdf838b 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -410,8 +410,11 @@ static PyObject * PyCursesPanel_New(_curses_panel_state *state, PANEL *pan, PyCursesWindowObject *wo) { - PyCursesPanelObject *po = PyObject_New(PyCursesPanelObject, - state->PyCursesPanel_Type); + assert(state != NULL); + PyTypeObject *type = state->PyCursesPanel_Type; + assert(type != NULL); + assert(type->tp_alloc != NULL); + PyCursesPanelObject *po = (PyCursesPanelObject *)type->tp_alloc(type, 0); if (po == NULL) { return NULL; } @@ -426,20 +429,31 @@ PyCursesPanel_New(_curses_panel_state *state, PANEL *pan, return (PyObject *)po; } +static int +PyCursesPanel_Clear(PyObject *op) +{ + PyCursesPanelObject *self = _PyCursesPanelObject_CAST(op); + PyObject *extra = (PyObject *)panel_userptr(self->pan); + if (extra != NULL) { + Py_DECREF(extra); + if (set_panel_userptr(self->pan, NULL) == ERR) { + curses_panel_panel_set_error(self, "set_panel_userptr", NULL); + return -1; + } + } + // self->wo should not be cleared because an associated WINDOW may exist + return 0; +} + static void PyCursesPanel_Dealloc(PyObject *self) { - PyObject *tp, *obj; - PyCursesPanelObject *po = _PyCursesPanelObject_CAST(self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); - tp = (PyObject *) Py_TYPE(po); - obj = (PyObject *) panel_userptr(po->pan); - if (obj) { - Py_DECREF(obj); - if (set_panel_userptr(po->pan, NULL) == ERR) { - curses_panel_panel_set_error(po, "set_panel_userptr", "__del__"); - PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()"); - } + PyCursesPanelObject *po = _PyCursesPanelObject_CAST(self); + if (PyCursesPanel_Clear(self) < 0) { + PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()"); } if (del_panel(po->pan) == ERR && !PyErr_Occurred()) { curses_panel_panel_set_error(po, "del_panel", "__del__"); @@ -452,10 +466,20 @@ PyCursesPanel_Dealloc(PyObject *self) PyErr_FormatUnraisable("Exception ignored in PyCursesPanel_Dealloc()"); } } - PyObject_Free(po); + tp->tp_free(po); Py_DECREF(tp); } +static int +PyCursesPanel_Traverse(PyObject *op, visitproc visit, void *arg) +{ + PyCursesPanelObject *self = _PyCursesPanelObject_CAST(op); + Py_VISIT(Py_TYPE(op)); + Py_VISIT(panel_userptr(self->pan)); + Py_VISIT(self->wo); + return 0; +} + /* panel_above(NULL) returns the bottom panel in the stack. To get this behaviour we use curses.panel.bottom_panel(). */ /*[clinic input] @@ -647,7 +671,9 @@ static PyMethodDef PyCursesPanel_Methods[] = { /* -------------------------------------------------------*/ static PyType_Slot PyCursesPanel_Type_slots[] = { + {Py_tp_clear, PyCursesPanel_Clear}, {Py_tp_dealloc, PyCursesPanel_Dealloc}, + {Py_tp_traverse, PyCursesPanel_Traverse}, {Py_tp_methods, PyCursesPanel_Methods}, {0, 0}, }; @@ -655,7 +681,12 @@ static PyType_Slot PyCursesPanel_Type_slots[] = { static PyType_Spec PyCursesPanel_Type_spec = { .name = "_curses_panel.panel", .basicsize = sizeof(PyCursesPanelObject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HAVE_GC + ), .slots = PyCursesPanel_Type_slots }; diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 232dbcace9a..61464348d6f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1932,7 +1932,6 @@ PyCursesWindow_getstr(PyObject *op, PyObject *args) int rtn, use_xy = 0, y = 0, x = 0; unsigned int max_buf_size = 2048; unsigned int n = max_buf_size - 1; - PyObject *res; if (!curses_clinic_parse_optional_xy_n(args, &y, &x, &n, &use_xy, "_curses.window.instr")) @@ -1941,11 +1940,11 @@ PyCursesWindow_getstr(PyObject *op, PyObject *args) } n = Py_MIN(n, max_buf_size - 1); - res = PyBytes_FromStringAndSize(NULL, n + 1); - if (res == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(n + 1); + if (writer == NULL) { return NULL; } - char *buf = PyBytes_AS_STRING(res); + char *buf = PyBytesWriter_GetData(writer); if (use_xy) { Py_BEGIN_ALLOW_THREADS @@ -1965,11 +1964,10 @@ PyCursesWindow_getstr(PyObject *op, PyObject *args) } if (rtn == ERR) { - Py_DECREF(res); + PyBytesWriter_Discard(writer); return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - _PyBytes_Resize(&res, strlen(buf)); // 'res' is set to NULL on failure - return res; + return PyBytesWriter_FinishWithSize(writer, strlen(buf)); } /*[clinic input] @@ -2130,7 +2128,6 @@ PyCursesWindow_instr(PyObject *op, PyObject *args) int rtn, use_xy = 0, y = 0, x = 0; unsigned int max_buf_size = 2048; unsigned int n = max_buf_size - 1; - PyObject *res; if (!curses_clinic_parse_optional_xy_n(args, &y, &x, &n, &use_xy, "_curses.window.instr")) @@ -2139,11 +2136,11 @@ PyCursesWindow_instr(PyObject *op, PyObject *args) } n = Py_MIN(n, max_buf_size - 1); - res = PyBytes_FromStringAndSize(NULL, n + 1); - if (res == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(n + 1); + if (writer == NULL) { return NULL; } - char *buf = PyBytes_AS_STRING(res); + char *buf = PyBytesWriter_GetData(writer); if (use_xy) { rtn = mvwinnstr(self->win, y, x, buf, n); @@ -2153,11 +2150,10 @@ PyCursesWindow_instr(PyObject *op, PyObject *args) } if (rtn == ERR) { - Py_DECREF(res); + PyBytesWriter_Discard(writer); return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - _PyBytes_Resize(&res, strlen(buf)); // 'res' is set to NULL on failure - return res; + return PyBytesWriter_FinishWithSize(writer, strlen(buf)); } /*[clinic input] diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index eb52eb72614..46c4f57984b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -15,6 +15,7 @@ #include "pycore_time.h" // _PyTime_ObjectToTime_t() #include "pycore_unicodeobject.h" // _PyUnicode_Copy() #include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_pyatomic_ft_wrappers.h" #include "datetime.h" @@ -2540,14 +2541,16 @@ static Py_hash_t delta_hash(PyObject *op) { PyDateTime_Delta *self = PyDelta_CAST(op); - if (self->hashcode == -1) { + Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->hashcode); + if (hash == -1) { PyObject *temp = delta_getstate(self); if (temp != NULL) { - self->hashcode = PyObject_Hash(temp); + hash = PyObject_Hash(temp); + FT_ATOMIC_STORE_SSIZE_RELAXED(self->hashcode, hash); Py_DECREF(temp); } } - return self->hashcode; + return hash; } static PyObject * @@ -3291,19 +3294,31 @@ static PyObject * datetime_date_today_impl(PyTypeObject *type) /*[clinic end generated code: output=d5474697df6b251c input=21688afa289c0a06]*/ { - PyObject *time; - PyObject *result; - time = time_time(); - if (time == NULL) - return NULL; + /* Use C implementation to boost performance for date type */ + if (type == &PyDateTime_DateType) { + struct tm tm; + time_t t; + time(&t); - /* Note well: today() is a class method, so this may not call - * date.fromtimestamp. For example, it may call - * datetime.fromtimestamp. That's why we need all the accuracy - * time.time() delivers; if someone were gonzo about optimization, - * date.today() could get away with plain C time(). + if (_PyTime_localtime(t, &tm) != 0) { + return NULL; + } + + return new_date_ex(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + type); + } + + PyObject *time = time_time(); + if (time == NULL) { + return NULL; + } + + /* Note well: since today() is a class method, it may not call + * date.fromtimestamp, e.g., it may call datetime.fromtimestamp. */ - result = PyObject_CallMethodOneArg((PyObject*)type, &_Py_ID(fromtimestamp), time); + PyObject *result = PyObject_CallMethodOneArg((PyObject*)type, &_Py_ID(fromtimestamp), time); Py_DECREF(time); return result; } @@ -3468,12 +3483,15 @@ datetime.date.strptime / Parse string according to the given date format (like time.strptime()). + +For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes [clinic start generated code]*/ static PyObject * datetime_date_strptime_impl(PyTypeObject *type, PyObject *string, PyObject *format) -/*[clinic end generated code: output=454d473bee2d5161 input=001904ab34f594a1]*/ +/*[clinic end generated code: output=454d473bee2d5161 input=31d57bb789433e99]*/ { PyObject *result; @@ -3608,11 +3626,14 @@ datetime.date.strftime Format using strftime(). Example: "%d/%m/%Y, %H:%M:%S". + +For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes [clinic start generated code]*/ static PyObject * datetime_date_strftime_impl(PyObject *self, PyObject *format) -/*[clinic end generated code: output=6529b70095e16778 input=72af55077e606ed8]*/ +/*[clinic end generated code: output=6529b70095e16778 input=b6fd4a2ded27b557]*/ { /* This method can be inherited, and needs to call the * timetuple() method appropriate to self's class. @@ -3903,12 +3924,14 @@ static Py_hash_t date_hash(PyObject *op) { PyDateTime_Date *self = PyDate_CAST(op); - if (self->hashcode == -1) { - self->hashcode = generic_hash( + Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->hashcode); + if (hash == -1) { + hash = generic_hash( (unsigned char *)self->data, _PyDateTime_DATE_DATASIZE); + FT_ATOMIC_STORE_SSIZE_RELAXED(self->hashcode, hash); } - return self->hashcode; + return hash; } static PyObject * @@ -4711,12 +4734,15 @@ datetime.time.strptime / Parse string according to the given time format (like time.strptime()). + +For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes [clinic start generated code]*/ static PyObject * datetime_time_strptime_impl(PyTypeObject *type, PyObject *string, PyObject *format) -/*[clinic end generated code: output=ae05a9bc0241d3bf input=6d0f263a5f94d78d]*/ +/*[clinic end generated code: output=ae05a9bc0241d3bf input=82ba425ecacc54aa]*/ { PyObject *result; @@ -4891,11 +4917,14 @@ datetime.time.strftime Format using strftime(). The date part of the timestamp passed to underlying strftime should not be used. + +For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes [clinic start generated code]*/ static PyObject * datetime_time_strftime_impl(PyDateTime_Time *self, PyObject *format) -/*[clinic end generated code: output=10f65af20e2a78c7 input=541934a2860f7db5]*/ +/*[clinic end generated code: output=10f65af20e2a78c7 input=c4a5bbecd798654b]*/ { PyObject *result; PyObject *tuple; @@ -5019,7 +5048,8 @@ static Py_hash_t time_hash(PyObject *op) { PyDateTime_Time *self = PyTime_CAST(op); - if (self->hashcode == -1) { + Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->hashcode); + if (hash == -1) { PyObject *offset, *self0; if (TIME_GET_FOLD(self)) { self0 = new_time_ex2(TIME_GET_HOUR(self), @@ -5041,10 +5071,11 @@ time_hash(PyObject *op) return -1; /* Reduce this to a hash of another object. */ - if (offset == Py_None) - self->hashcode = generic_hash( + if (offset == Py_None) { + hash = generic_hash( (unsigned char *)self->data, _PyDateTime_TIME_DATASIZE); - else { + FT_ATOMIC_STORE_SSIZE_RELAXED(self->hashcode, hash); + } else { PyObject *temp1, *temp2; int seconds, microseconds; assert(HASTZINFO(self)); @@ -5063,12 +5094,13 @@ time_hash(PyObject *op) Py_DECREF(offset); return -1; } - self->hashcode = PyObject_Hash(temp2); + hash = PyObject_Hash(temp2); + FT_ATOMIC_STORE_SSIZE_RELAXED(self->hashcode, hash); Py_DECREF(temp2); } Py_DECREF(offset); } - return self->hashcode; + return hash; } /*[clinic input] @@ -5787,12 +5819,15 @@ datetime.datetime.strptime / Parse string according to the given date and time format (like time.strptime()). + +For a list of supported format codes, see the documentation: + https://docs.python.org/3/library/datetime.html#format-codes [clinic start generated code]*/ static PyObject * datetime_datetime_strptime_impl(PyTypeObject *type, PyObject *string, PyObject *format) -/*[clinic end generated code: output=af2c2d024f3203f5 input=d7597c7f5327117b]*/ +/*[clinic end generated code: output=af2c2d024f3203f5 input=ef7807589f1d50e7]*/ { PyObject *result; @@ -6600,7 +6635,8 @@ static Py_hash_t datetime_hash(PyObject *op) { PyDateTime_DateTime *self = PyDateTime_CAST(op); - if (self->hashcode == -1) { + Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->hashcode); + if (hash == -1) { PyObject *offset, *self0; if (DATE_GET_FOLD(self)) { self0 = new_datetime_ex2(GET_YEAR(self), @@ -6625,10 +6661,11 @@ datetime_hash(PyObject *op) return -1; /* Reduce this to a hash of another object. */ - if (offset == Py_None) - self->hashcode = generic_hash( + if (offset == Py_None) { + hash = generic_hash( (unsigned char *)self->data, _PyDateTime_DATETIME_DATASIZE); - else { + FT_ATOMIC_STORE_SSIZE_RELAXED(self->hashcode, hash); + } else { PyObject *temp1, *temp2; int days, seconds; @@ -6652,12 +6689,13 @@ datetime_hash(PyObject *op) Py_DECREF(offset); return -1; } - self->hashcode = PyObject_Hash(temp2); + hash = PyObject_Hash(temp2); + FT_ATOMIC_STORE_SSIZE_RELAXED(self->hashcode, hash); Py_DECREF(temp2); } Py_DECREF(offset); } - return self->hashcode; + return hash; } /*[clinic input] @@ -7616,6 +7654,7 @@ finally: } static PyModuleDef_Slot module_slots[] = { + _Py_INTERNAL_ABI_SLOT, {Py_mod_exec, _datetime_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 0cd0f043de4..f88861fa244 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -8,6 +8,7 @@ #endif #include "Python.h" +#include "pycore_object.h" // _PyObject_VisitType() #include <sys/types.h> #include <sys/stat.h> @@ -96,12 +97,6 @@ newdbmobject(_dbm_state *state, const char *file, int flags, int mode) } /* Methods */ -static int -dbm_traverse(PyObject *dp, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(dp)); - return 0; -} static void dbm_dealloc(PyObject *self) @@ -456,10 +451,7 @@ _dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key, return PyBytes_FromStringAndSize(val.dptr, val.dsize); } if (default_value == NULL) { - default_value = PyBytes_FromStringAndSize(NULL, 0); - if (default_value == NULL) { - return NULL; - } + default_value = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); val.dptr = NULL; val.dsize = 0; } @@ -523,8 +515,12 @@ dbm__enter__(PyObject *self, PyObject *Py_UNUSED(dummy)) static PyObject * dbm__exit__(PyObject *self, PyObject *Py_UNUSED(args)) { + PyObject *result; dbmobject *dp = dbmobject_CAST(self); - return _dbm_dbm_close_impl(dp); + Py_BEGIN_CRITICAL_SECTION(self); + result = _dbm_dbm_close_impl(dp); + Py_END_CRITICAL_SECTION(); + return result; } static PyMethodDef dbm_methods[] = { @@ -540,7 +536,7 @@ static PyMethodDef dbm_methods[] = { static PyType_Slot dbmtype_spec_slots[] = { {Py_tp_dealloc, dbm_dealloc}, - {Py_tp_traverse, dbm_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_methods, dbm_methods}, {Py_sq_contains, dbm_contains}, {Py_mp_length, dbm_length}, diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index de7200af8c1..e183c70653b 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -30,9 +30,9 @@ #endif #include <Python.h> +#include "pycore_object.h" // _PyObject_VisitType() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_typeobject.h" -#include "complexobject.h" #include <mpdecimal.h> @@ -58,6 +58,9 @@ #include "clinic/_decimal.c.h" +#define MPD_SPEC_VERSION "1.70" // Highest version of the spec this complies with + // See https://speleotrove.com/decimal/decarith.html + /*[clinic input] module _decimal class _decimal.Decimal "PyObject *" "&dec_spec" @@ -746,13 +749,6 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) return 0; } -static int -signaldict_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void signaldict_dealloc(PyObject *self) { @@ -845,7 +841,7 @@ static PyMethodDef signaldict_methods[] = { static PyType_Slot signaldict_slots[] = { {Py_tp_dealloc, signaldict_dealloc}, - {Py_tp_traverse, signaldict_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_repr, signaldict_repr}, {Py_tp_hash, PyObject_HashNotImplemented}, {Py_tp_getattro, PyObject_GenericGetAttr}, @@ -1014,16 +1010,19 @@ context_setemax(PyObject *self, PyObject *value, void *Py_UNUSED(closure)) } #ifdef CONFIG_32 +/*[clinic input] +_decimal.Context._unsafe_setprec + + x: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -context_unsafe_setprec(PyObject *self, PyObject *value) +_decimal_Context__unsafe_setprec_impl(PyObject *self, Py_ssize_t x) +/*[clinic end generated code: output=dd838edf08e12dd9 input=23a1b19ceb1569be]*/ { mpd_context_t *ctx = CTX(self); - mpd_ssize_t x; - - x = PyLong_AsSsize_t(value); - if (x == -1 && PyErr_Occurred()) { - return NULL; - } if (x < 1 || x > 1070000000L) { return value_error_ptr( @@ -1034,16 +1033,19 @@ context_unsafe_setprec(PyObject *self, PyObject *value) Py_RETURN_NONE; } +/*[clinic input] +_decimal.Context._unsafe_setemin + + x: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -context_unsafe_setemin(PyObject *self, PyObject *value) +_decimal_Context__unsafe_setemin_impl(PyObject *self, Py_ssize_t x) +/*[clinic end generated code: output=0c49cafee8a65846 input=652f1ecacca7e0ce]*/ { mpd_context_t *ctx = CTX(self); - mpd_ssize_t x; - - x = PyLong_AsSsize_t(value); - if (x == -1 && PyErr_Occurred()) { - return NULL; - } if (x < -1070000000L || x > 0) { return value_error_ptr( @@ -1054,16 +1056,19 @@ context_unsafe_setemin(PyObject *self, PyObject *value) Py_RETURN_NONE; } +/*[clinic input] +_decimal.Context._unsafe_setemax + + x: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -context_unsafe_setemax(PyObject *self, PyObject *value) +_decimal_Context__unsafe_setemax_impl(PyObject *self, Py_ssize_t x) +/*[clinic end generated code: output=776563e0377a00e8 input=b2a32a9a2750e7a8]*/ { mpd_context_t *ctx = CTX(self); - mpd_ssize_t x; - - x = PyLong_AsSsize_t(value); - if (x == -1 && PyErr_Occurred()) { - return NULL; - } if (x < 0 || x > 1070000000L) { return value_error_ptr( @@ -1648,45 +1653,68 @@ error: return NULL; } +static PyObject * +context_copy(decimal_state *state, PyObject *v) +{ + PyObject *copy = + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); + + if (copy == NULL) { + return NULL; + } + + *CTX(copy) = *CTX(v); + CTX(copy)->newtrap = 0; + CtxCaps(copy) = CtxCaps(v); + + return copy; +} + /*[clinic input] _decimal.Context.copy + cls: defining_class + Return a duplicate of the context with all flags cleared. [clinic start generated code]*/ static PyObject * -_decimal_Context_copy_impl(PyObject *self) -/*[clinic end generated code: output=f99649a60a9c10f8 input=2589aa46b77cbc28]*/ +_decimal_Context_copy_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=31c9c8eeb0c0cf77 input=aef1c0bddabdf8f0]*/ { - PyObject *copy; + decimal_state *state = PyType_GetModuleState(cls); - decimal_state *state = get_module_state_from_ctx(self); - copy = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); - if (copy == NULL) { - return NULL; - } - - *CTX(copy) = *CTX(self); - CTX(copy)->newtrap = 0; - CtxCaps(copy) = CtxCaps(self); - - return copy; + return context_copy(state, self); } -static PyObject * -context_copy(PyObject *self, PyObject *Py_UNUSED(dummy)) -{ - return _decimal_Context_copy_impl(self); -} +/*[clinic input] +_decimal.Context.__copy__ = _decimal.Context.copy + +[clinic start generated code]*/ static PyObject * -context_reduce(PyObject *self, PyObject *Py_UNUSED(dummy)) +_decimal_Context___copy___impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=93552486e5fb0ab4 input=4a55dd22f6d31bcc]*/ +{ + decimal_state *state = PyType_GetModuleState(cls); + + return context_copy(state, self); +} + +/*[clinic input] +_decimal.Context.__reduce__ = _decimal.Context.copy + +[clinic start generated code]*/ + +static PyObject * +_decimal_Context___reduce___impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=4e77de55efdbb56a input=787683f13d047ce8]*/ { PyObject *flags; PyObject *traps; PyObject *ret; mpd_context_t *ctx; - decimal_state *state = get_module_state_from_ctx(self); + decimal_state *state = PyType_GetModuleState(cls); ctx = CTX(self); @@ -1789,7 +1817,7 @@ current_context_from_dict(decimal_state *modstate) } /* Set up a new thread local context. */ - tl_context = context_copy(modstate->default_context_template, NULL); + tl_context = context_copy(modstate, modstate->default_context_template); if (tl_context == NULL) { return NULL; } @@ -1865,7 +1893,7 @@ PyDec_SetCurrentContext(PyObject *self, PyObject *v) if (v == state->default_context_template || v == state->basic_context_template || v == state->extended_context_template) { - v = context_copy(v, NULL); + v = context_copy(state, v); if (v == NULL) { return NULL; } @@ -1888,7 +1916,7 @@ PyDec_SetCurrentContext(PyObject *self, PyObject *v) static PyObject * init_current_context(decimal_state *state) { - PyObject *tl_context = context_copy(state->default_context_template, NULL); + PyObject *tl_context = context_copy(state, state->default_context_template); if (tl_context == NULL) { return NULL; } @@ -1949,7 +1977,7 @@ PyDec_SetCurrentContext(PyObject *self, PyObject *v) if (v == state->default_context_template || v == state->basic_context_template || v == state->extended_context_template) { - v = context_copy(v, NULL); + v = context_copy(state, v); if (v == NULL) { return NULL; } @@ -2046,7 +2074,7 @@ _decimal_localcontext_impl(PyObject *module, PyObject *local, PyObject *prec, return NULL; } - PyObject *local_copy = context_copy(local, NULL); + PyObject *local_copy = context_copy(state, local); if (local_copy == NULL) { return NULL; } @@ -2194,13 +2222,6 @@ PyDecType_New(decimal_state *state, PyTypeObject *type) } #define dec_alloc(st) PyDecType_New(st, (st)->PyDec_Type) -static int -dec_traverse(PyObject *dec, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(dec)); - return 0; -} - static void dec_dealloc(PyObject *dec) { @@ -2978,6 +2999,7 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, @classmethod _decimal.Decimal.from_float + cls: defining_class f as pyfloat: object / @@ -2997,13 +3019,14 @@ Decimal.from_float(0.1) is not the same as Decimal('0.1'). [clinic start generated code]*/ static PyObject * -_decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat) -/*[clinic end generated code: output=e62775271ac469e6 input=052036648342f8c8]*/ +_decimal_Decimal_from_float_impl(PyTypeObject *type, PyTypeObject *cls, + PyObject *pyfloat) +/*[clinic end generated code: output=fcb7d55d2f9dc790 input=03bc8dbe963e52ca]*/ { PyObject *context; PyObject *result; - decimal_state *state = get_module_state_by_def(type); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); if (type != state->PyDec_Type && result != NULL) { @@ -3018,9 +3041,10 @@ _decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat) an exact conversion. If the result does not meet the restrictions for an mpd_t, fail with InvalidOperation. */ static PyObject * -PyDecType_FromNumberExact(PyTypeObject *type, PyObject *v, PyObject *context) +PyDecType_FromNumberExact(PyTypeObject *type, PyTypeObject *cls, + PyObject *v, PyObject *context) { - decimal_state *state = get_module_state_by_def(type); + decimal_state *state = PyType_GetModuleState(cls); assert(v != NULL); if (PyDec_Check(state, v)) { return PyDecType_FromDecimalExact(type, v, context); @@ -3046,6 +3070,7 @@ PyDecType_FromNumberExact(PyTypeObject *type, PyObject *v, PyObject *context) @classmethod _decimal.Decimal.from_number + cls: defining_class number: object / @@ -3060,15 +3085,16 @@ Class method that converts a real number to a decimal number, exactly. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_from_number_impl(PyTypeObject *type, PyObject *number) -/*[clinic end generated code: output=41885304e5beea0a input=c58b678e8916f66b]*/ +_decimal_Decimal_from_number_impl(PyTypeObject *type, PyTypeObject *cls, + PyObject *number) +/*[clinic end generated code: output=4d3ec722b7acfd8b input=271cb4feb3148804]*/ { PyObject *context; PyObject *result; - decimal_state *state = get_module_state_by_def(type); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); - result = PyDecType_FromNumberExact(state->PyDec_Type, number, context); + result = PyDecType_FromNumberExact(state->PyDec_Type, cls, number, context); if (type != state->PyDec_Type && result != NULL) { Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, result, NULL)); @@ -3083,6 +3109,7 @@ _decimal_Decimal_from_number_impl(PyTypeObject *type, PyObject *number) _decimal.Context.create_decimal_from_float self as context: self + cls: defining_class f: object / @@ -3093,10 +3120,12 @@ the context limits. [clinic start generated code]*/ static PyObject * -_decimal_Context_create_decimal_from_float(PyObject *context, PyObject *f) -/*[clinic end generated code: output=c660c343f6f7158b input=05a8c54b7a5b457b]*/ +_decimal_Context_create_decimal_from_float_impl(PyObject *context, + PyTypeObject *cls, + PyObject *f) +/*[clinic end generated code: output=a5548f5140fa0870 input=8c66eeb22b01ddd4]*/ { - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); return PyDec_FromFloat(state, f, context); } @@ -3702,6 +3731,7 @@ pydec_format(PyObject *dec, PyObject *context, PyObject *fmt, decimal_state *sta _decimal.Decimal.__format__ self as dec: self + cls: defining_class format_spec as fmtarg: unicode override: object = NULL / @@ -3710,9 +3740,9 @@ Formats the Decimal according to format_spec. [clinic start generated code]*/ static PyObject * -_decimal_Decimal___format___impl(PyObject *dec, PyObject *fmtarg, - PyObject *override) -/*[clinic end generated code: output=4b3640b7f0c8b6a5 input=e53488e49a0fff00]*/ +_decimal_Decimal___format___impl(PyObject *dec, PyTypeObject *cls, + PyObject *fmtarg, PyObject *override) +/*[clinic end generated code: output=6d95f91bbb28b3ed input=2dbfaa0cbe243e9e]*/ { PyObject *result = NULL; PyObject *dot = NULL; @@ -3725,7 +3755,7 @@ _decimal_Decimal___format___impl(PyObject *dec, PyObject *fmtarg, uint32_t status = 0; int replace_fillchar = 0; Py_ssize_t size; - decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); fmt = (char *)PyUnicode_AsUTF8AndSize(fmtarg, &size); if (fmt == NULL) { @@ -3929,6 +3959,8 @@ dec_as_long(PyObject *dec, PyObject *context, int round) /*[clinic input] _decimal.Decimal.as_integer_ratio + cls: defining_class + Return a pair of integers whose ratio is exactly equal to the original. The ratio is in lowest terms and with a positive denominator. @@ -3936,8 +3968,8 @@ Raise OverflowError on infinities and a ValueError on NaNs. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_as_integer_ratio_impl(PyObject *self) -/*[clinic end generated code: output=c5d88e900080c264 input=7861cb643f01525a]*/ +_decimal_Decimal_as_integer_ratio_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=eb49c512701f844b input=07e33d8852184761]*/ { PyObject *numerator = NULL; PyObject *denominator = NULL; @@ -3960,7 +3992,7 @@ _decimal_Decimal_as_integer_ratio_impl(PyObject *self) return NULL; } - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); tmp = dec_alloc(state); @@ -4042,6 +4074,7 @@ error: /*[clinic input] _decimal.Decimal.to_integral_value + cls: defining_class rounding: object = None context: object = None @@ -4053,15 +4086,16 @@ rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyTypeObject *cls, + PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=7301465765f48b6b input=04e2312d5ed19f77]*/ +/*[clinic end generated code: output=23047d848ef84db1 input=85aa9499a21ea8d7]*/ { PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4099,11 +4133,12 @@ versions. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, - PyObject *context) -/*[clinic end generated code: output=a0c7188686ee7f5c input=709b54618ecd0d8b]*/ +_decimal_Decimal_to_integral_impl(PyObject *self, PyTypeObject *cls, + PyObject *rounding, PyObject *context) +/*[clinic end generated code: output=5dac8f54c2a3ed26 input=709b54618ecd0d8b]*/ { - return _decimal_Decimal_to_integral_value_impl(self, rounding, context); + return _decimal_Decimal_to_integral_value_impl(self, cls, rounding, + context); } /*[clinic input] @@ -4118,15 +4153,16 @@ given, then the rounding mode of the current default context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyTypeObject *cls, + PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=8b004f9b45ac7746 input=fabce7a744b8087c]*/ +/*[clinic end generated code: output=543a39a02eea9917 input=fabce7a744b8087c]*/ { PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -4189,6 +4225,7 @@ PyDec_AsFloat(PyObject *dec) /*[clinic input] _decimal.Decimal.__round__ + cls: defining_class ndigits: object = NULL / @@ -4196,13 +4233,14 @@ Return the Integral closest to self, rounding half toward even. [clinic start generated code]*/ static PyObject * -_decimal_Decimal___round___impl(PyObject *self, PyObject *ndigits) -/*[clinic end generated code: output=ca6b3570a8df0c91 input=dc72084114f59380]*/ +_decimal_Decimal___round___impl(PyObject *self, PyTypeObject *cls, + PyObject *ndigits) +/*[clinic end generated code: output=790c2c6bd57890e6 input=d69e7178a58a66b1]*/ { PyObject *result; uint32_t status = 0; PyObject *context; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); if (ndigits) { mpd_uint_t dq[1] = {1}; @@ -4241,12 +4279,14 @@ _decimal_Decimal___round___impl(PyObject *self, PyObject *ndigits) /*[clinic input] _decimal.Decimal.as_tuple + cls: defining_class + Return a tuple representation of the number. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_as_tuple_impl(PyObject *self) -/*[clinic end generated code: output=c6e8e2420c515eca input=e26f2151d78ff59d]*/ +_decimal_Decimal_as_tuple_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=d68b967becee8ab9 input=bfa86d640224d9f5]*/ { PyObject *result = NULL; PyObject *sign = NULL; @@ -4326,7 +4366,7 @@ _decimal_Decimal_as_tuple_impl(PyObject *self) } } - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); @@ -4378,7 +4418,7 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ PyObject *context; \ uint32_t status = 0; \ \ - decimal_state *state = find_state_left_or_right(self, other); \ + decimal_state *state = find_state_left_or_right(self, other); \ CURRENT_CONTEXT(state, context) ; \ CONVERT_BINOP(&a, &b, self, other, context); \ \ @@ -4408,25 +4448,26 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ } /* Boolean function with an optional context arg. - Argument Clinic provides PyObject *self, PyObject *context + Argument Clinic provides PyObject *self, PyTypeObject *cls, + PyObject *context */ #define Dec_BoolFuncVA(MPDFUNC) \ { \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = PyType_GetModuleState(cls); \ CONTEXT_CHECK_VA(state, context); \ \ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ } /* Unary function with an optional context arg. - Argument Clinic provides PyObject *self, PyObject *context + Argument Clinic provides PyObject *self, PyTypeObject *cls, + PyObject *context */ #define Dec_UnaryFuncVA(MPDFUNC) \ { \ PyObject *result; \ uint32_t status = 0; \ - decimal_state *state = \ - get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = PyType_GetModuleState(cls); \ CONTEXT_CHECK_VA(state, context); \ \ if ((result = dec_alloc(state)) == NULL) { \ @@ -4443,15 +4484,15 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ } /* Binary function with an optional context arg. - Argument Clinic provides PyObject *self, PyObject *other, PyObject *context + Argument Clinic provides PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context */ #define Dec_BinaryFuncVA(MPDFUNC) \ { \ PyObject *a, *b; \ PyObject *result; \ uint32_t status = 0; \ - decimal_state *state = \ - get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = PyType_GetModuleState(cls); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ @@ -4476,14 +4517,14 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ NOT take a context. The context is used to record InvalidOperation if the second operand cannot be converted exactly. - Argument Clinic provides PyObject *self, PyObject *other, PyObject *context + Argument Clinic provides PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context */ #define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ { \ PyObject *a, *b; \ PyObject *result; \ - decimal_state *state = \ - get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = PyType_GetModuleState(cls); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ @@ -4501,7 +4542,8 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ } /* Ternary function with an optional context arg. - Argument Clinic provides PyObject *self, PyObject *other, PyObject *third, + Argument Clinic provides PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *third, PyObject *context */ #define Dec_TernaryFuncVA(MPDFUNC) \ @@ -4509,7 +4551,7 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ PyObject *a, *b, *c; \ PyObject *result; \ uint32_t status = 0; \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = PyType_GetModuleState(cls); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ @@ -4662,6 +4704,7 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) /*[clinic input] _decimal.Decimal.exp + cls: defining_class context: object = None Return the value of the (natural) exponential function e**x. @@ -4671,8 +4714,9 @@ correctly rounded. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_exp_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=c0833b6e9b8c836f input=274784af925e60c9]*/ +_decimal_Decimal_exp_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=40317012aedbaeac input=84919aad3dabda08]*/ Dec_UnaryFuncVA(mpd_qexp) /*[clinic input] @@ -4685,8 +4729,9 @@ correctly rounded. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_ln_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=5191f4ef739b04b0 input=d353c51ec00d1cff]*/ +_decimal_Decimal_ln_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=e8f9e81cac38e5dc input=d353c51ec00d1cff]*/ Dec_UnaryFuncVA(mpd_qln) /*[clinic input] @@ -4699,8 +4744,9 @@ correctly rounded. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_log10_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=d5da63df75900275 input=48a6be60154c0b46]*/ +_decimal_Decimal_log10_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=00b3255648135c95 input=48a6be60154c0b46]*/ Dec_UnaryFuncVA(mpd_qlog10) /*[clinic input] @@ -4710,8 +4756,9 @@ Returns the largest representable number smaller than itself. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_next_minus_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=aacbd758399f883f input=666b348f71e6c090]*/ +_decimal_Decimal_next_minus_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=a187a55e6976b572 input=666b348f71e6c090]*/ Dec_UnaryFuncVA(mpd_qnext_minus) /*[clinic input] @@ -4721,8 +4768,9 @@ Returns the smallest representable number larger than itself. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_next_plus_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=f3a7029a213c553c input=04e105060ad1fa15]*/ +_decimal_Decimal_next_plus_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=13737d41714e320e input=04e105060ad1fa15]*/ Dec_UnaryFuncVA(mpd_qnext_plus) /*[clinic input] @@ -4737,8 +4785,9 @@ the equivalent value Decimal('32.1'). [clinic start generated code]*/ static PyObject * -_decimal_Decimal_normalize_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=db2c8b3c8eccff36 input=d5ee63acd904d4de]*/ +_decimal_Decimal_normalize_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=32c4c0d13fe33fb9 input=d5ee63acd904d4de]*/ Dec_UnaryFuncVA(mpd_qreduce) /*[clinic input] @@ -4750,8 +4799,9 @@ The result is correctly rounded using the ROUND_HALF_EVEN rounding mode. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_sqrt_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=420722a199dd9c2b input=3a76afbd39dc20b9]*/ +_decimal_Decimal_sqrt_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=deb1280077b5e586 input=3a76afbd39dc20b9]*/ Dec_UnaryFuncVA(mpd_qsqrt) /* Binary arithmetic functions, optional context arg */ @@ -4759,6 +4809,7 @@ Dec_UnaryFuncVA(mpd_qsqrt) /*[clinic input] _decimal.Decimal.compare + cls: defining_class other: object context: object = None @@ -4773,9 +4824,9 @@ Return a decimal value: [clinic start generated code]*/ static PyObject * -_decimal_Decimal_compare_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=d6967aa3578b9d48 input=1b7b75a2a154e520]*/ +_decimal_Decimal_compare_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=a4a1d383ec192cfa input=d18a02bb8083e92a]*/ Dec_BinaryFuncVA(mpd_qcompare) /*[clinic input] @@ -4785,9 +4836,9 @@ Identical to compare, except that all NaNs signal. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_compare_signal_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=0b8d0ff43f6c8a95 input=a52a39d1c6fc369d]*/ +_decimal_Decimal_compare_signal_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=22f757371fd4167b input=a52a39d1c6fc369d]*/ Dec_BinaryFuncVA(mpd_qcompare_signal) /*[clinic input] @@ -4800,8 +4851,9 @@ operand is returned. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_max_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=f3a5c5d76761c9ff input=2ae2582f551296d8]*/ +_decimal_Decimal_max_impl(PyObject *self, PyTypeObject *cls, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=d3d12db9815869e5 input=2ae2582f551296d8]*/ Dec_BinaryFuncVA(mpd_qmax) /*[clinic input] @@ -4811,9 +4863,9 @@ As the max() method, but compares the absolute values of the operands. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_max_mag_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=52b0451987bac65f input=88b105e66cf138c5]*/ +_decimal_Decimal_max_mag_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=f71f2c27d9bc7cac input=88b105e66cf138c5]*/ Dec_BinaryFuncVA(mpd_qmax_mag) /*[clinic input] @@ -4826,8 +4878,9 @@ operand is returned. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_min_impl(PyObject *self, PyObject *other, PyObject *context) -/*[clinic end generated code: output=d2f38ecb9d6f0493 input=2a70f2c087c418c9]*/ +_decimal_Decimal_min_impl(PyObject *self, PyTypeObject *cls, PyObject *other, + PyObject *context) +/*[clinic end generated code: output=c5620344ae5f3dd1 input=2a70f2c087c418c9]*/ Dec_BinaryFuncVA(mpd_qmin) /*[clinic input] @@ -4837,9 +4890,9 @@ As the min() method, but compares the absolute values of the operands. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_min_mag_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=aa3391935f6c8fc9 input=351fa3c0e592746a]*/ +_decimal_Decimal_min_mag_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=018562ad1c22aae3 input=351fa3c0e592746a]*/ Dec_BinaryFuncVA(mpd_qmin_mag) /*[clinic input] @@ -4854,9 +4907,9 @@ to be the same as the sign of the second operand. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_next_toward_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=edb933755644af69 input=fdf0091ea6e9e416]*/ +_decimal_Decimal_next_toward_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=71d879bca8bc1019 input=fdf0091ea6e9e416]*/ Dec_BinaryFuncVA(mpd_qnext_toward) /*[clinic input] @@ -4874,9 +4927,9 @@ If the result is zero then its sign will be the sign of self. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_remainder_near_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=6ce0fb3b0faff2f9 input=eb5a8dfe3470b794]*/ +_decimal_Decimal_remainder_near_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=d3fbb4985f2077fa input=eb5a8dfe3470b794]*/ Dec_BinaryFuncVA(mpd_qrem_near) /* Ternary arithmetic functions, optional context arg */ @@ -4884,6 +4937,7 @@ Dec_BinaryFuncVA(mpd_qrem_near) /*[clinic input] _decimal.Decimal.fma + cls: defining_class other: object third: object context: object = None @@ -4898,9 +4952,9 @@ self*other. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_fma_impl(PyObject *self, PyObject *other, PyObject *third, - PyObject *context) -/*[clinic end generated code: output=74a82b984e227b69 input=48f9aec6f389227a]*/ +_decimal_Decimal_fma_impl(PyObject *self, PyTypeObject *cls, PyObject *other, + PyObject *third, PyObject *context) +/*[clinic end generated code: output=db49a777e85b71e4 input=2104c001f6077c35]*/ Dec_TernaryFuncVA(mpd_qfma) /* Boolean functions, no context arg */ @@ -5009,8 +5063,9 @@ Normal number is a finite nonzero number, which is not subnormal. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_is_normal_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=40cc429d388eb464 input=9afe43b9db9f4818]*/ +_decimal_Decimal_is_normal_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=92a3878e293758d4 input=9afe43b9db9f4818]*/ Dec_BoolFuncVA(mpd_isnormal) /*[clinic input] @@ -5023,8 +5078,9 @@ exponent less than Emin. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_is_subnormal_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=6f7d422b1f387d7f input=11839c122c185b8b]*/ +_decimal_Decimal_is_subnormal_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=1404c04d980ebc07 input=11839c122c185b8b]*/ Dec_BoolFuncVA(mpd_issubnormal) /* Unary functions, no context arg */ @@ -5097,6 +5153,8 @@ _dec_mpd_radix(decimal_state *state) /*[clinic input] _decimal.Decimal.radix + cls: defining_class + Return Decimal(10). This is the radix (base) in which the Decimal class does @@ -5104,16 +5162,18 @@ all its arithmetic. Included for compatibility with the specification. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_radix_impl(PyObject *self) -/*[clinic end generated code: output=6b1db4c3fcdb5ee1 input=18b72393549ca8fd]*/ +_decimal_Decimal_radix_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=40a3bc7ec3d99228 input=b0d4cb9f870bbac1]*/ { - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); return _dec_mpd_radix(state); } /*[clinic input] _decimal.Decimal.copy_abs + cls: defining_class + Return the absolute value of the argument. This operation is unaffected by context and is quiet: no flags are @@ -5121,13 +5181,13 @@ changed and no rounding is performed. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_copy_abs_impl(PyObject *self) -/*[clinic end generated code: output=fff53742cca94d70 input=a263c2e71d421f1b]*/ +_decimal_Decimal_copy_abs_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=081cb7fb4230676e input=676d7c62b1795512]*/ { PyObject *result; uint32_t status = 0; + decimal_state *state = PyType_GetModuleState(cls); - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -5143,7 +5203,7 @@ _decimal_Decimal_copy_abs_impl(PyObject *self) } /*[clinic input] -_decimal.Decimal.copy_negate +_decimal.Decimal.copy_negate = _decimal.Decimal.copy_abs Return the negation of the argument. @@ -5152,13 +5212,13 @@ changed and no rounding is performed. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_copy_negate_impl(PyObject *self) -/*[clinic end generated code: output=8551bc26dbc5d01d input=13d47ed3a5d228b1]*/ +_decimal_Decimal_copy_negate_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=04fed82c17d4e28b input=23f41ee8899f3891]*/ { PyObject *result; uint32_t status = 0; + decimal_state *state = PyType_GetModuleState(cls); - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -5178,12 +5238,15 @@ _decimal_Decimal_copy_negate_impl(PyObject *self) /*[clinic input] _decimal.Decimal.logical_invert = _decimal.Decimal.exp -Return the digit-wise inversion of the (logical) operand. +Invert all its digits. + +The self must be logical number. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_logical_invert_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=59beb9b1b51b9f34 input=3531dac8b9548dad]*/ +_decimal_Decimal_logical_invert_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=c626ed4b104a97b7 input=7158d5b525417955]*/ Dec_UnaryFuncVA(mpd_qinvert) /*[clinic input] @@ -5197,8 +5260,9 @@ Decimal('Infinity') is returned. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_logb_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=f278db20b47f301c input=a8df027d1b8a2b17]*/ +_decimal_Decimal_logb_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=36b0bda09e934245 input=a8df027d1b8a2b17]*/ Dec_UnaryFuncVA(mpd_qlogb) /*[clinic input] @@ -5225,12 +5289,13 @@ The returned value is one of the following ten strings: [clinic start generated code]*/ static PyObject * -_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=3044cd45966b4949 input=447095d2677fa0ca]*/ +_decimal_Decimal_number_class_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=1ac82412e0849c52 input=447095d2677fa0ca]*/ { const char *cp; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); cp = mpd_class(MPD(self), CTX(context)); @@ -5252,14 +5317,15 @@ operation. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context) -/*[clinic end generated code: output=d386194c25ffffa7 input=b2cb7e01e268e45d]*/ +_decimal_Decimal_to_eng_string_impl(PyObject *self, PyTypeObject *cls, + PyObject *context) +/*[clinic end generated code: output=901f128d437ae5c0 input=b2cb7e01e268e45d]*/ { PyObject *result; mpd_ssize_t size; char *s; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); @@ -5303,9 +5369,9 @@ exactly. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_compare_total_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=dca119b5e881a83e input=6f3111ec5fdbf3c1]*/ +_decimal_Decimal_compare_total_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=83649010bad7815f input=6f3111ec5fdbf3c1]*/ Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) /*[clinic input] @@ -5323,9 +5389,9 @@ exactly. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=6bf1b3419112d0dd input=eba17c4c24eb2833]*/ +_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=b99c924cafb5f0e3 input=eba17c4c24eb2833]*/ Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) /*[clinic input] @@ -5345,15 +5411,15 @@ exactly. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=72c62177763e012e input=51ed9e4691e2249e]*/ +_decimal_Decimal_copy_sign_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=e4c8f884f4d75801 input=51ed9e4691e2249e]*/ { PyObject *a, *b; PyObject *result; uint32_t status = 0; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); @@ -5387,14 +5453,14 @@ exactly. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=c0a3a046c662a7e2 input=8339415fa359e7df]*/ +_decimal_Decimal_same_quantum_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=7c757edb0c263721 input=8339415fa359e7df]*/ { PyObject *a, *b; PyObject *result; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); @@ -5410,37 +5476,43 @@ _decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, /*[clinic input] _decimal.Decimal.logical_and = _decimal.Decimal.compare -Return the digit-wise 'and' of the two (logical) operands. +Applies an 'and' operation between self and other's digits. + +Both self and other must be logical numbers. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_logical_and_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=1526a357f97eaf71 input=2b319baee8970929]*/ +_decimal_Decimal_logical_and_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=9a4cbb74c180b0bb input=f22460f1285782d2]*/ Dec_BinaryFuncVA(mpd_qand) /*[clinic input] _decimal.Decimal.logical_or = _decimal.Decimal.compare -Return the digit-wise 'or' of the two (logical) operands. +Applies an 'or' operation between self and other's digits. + +Both self and other must be logical numbers. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_logical_or_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=e57a72acf0982f56 input=75e0e1d4dd373b90]*/ +_decimal_Decimal_logical_or_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=063c4de18dc41ecb input=b5afa1e1fdebdfce]*/ Dec_BinaryFuncVA(mpd_qor) /*[clinic input] _decimal.Decimal.logical_xor = _decimal.Decimal.compare -Return the digit-wise 'xor' of the two (logical) operands. +Applies an 'xor' operation between self and other's digits. + +Both self and other must be logical numbers. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_logical_xor_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=ae3a7aeddde5a1a8 input=a1ed8d6ac38c1c9e]*/ +_decimal_Decimal_logical_xor_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=829b09cb49926ad7 input=84d722ada08a2da7]*/ Dec_BinaryFuncVA(mpd_qxor) /*[clinic input] @@ -5457,9 +5529,9 @@ necessary. The sign and exponent of the first operand are unchanged. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_rotate_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=e59e757e70a8416a input=cde7b032eac43f0b]*/ +_decimal_Decimal_rotate_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=09f2737082882b83 input=cde7b032eac43f0b]*/ Dec_BinaryFuncVA(mpd_qrotate) /*[clinic input] @@ -5472,9 +5544,9 @@ second operand must be an integer. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_scaleb_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=f01e99600eda34d7 input=7f29f83278d05f83]*/ +_decimal_Decimal_scaleb_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=ae8730536c9f2d30 input=7f29f83278d05f83]*/ Dec_BinaryFuncVA(mpd_qscaleb) /*[clinic input] @@ -5491,14 +5563,15 @@ operand are unchanged. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_shift_impl(PyObject *self, PyObject *other, - PyObject *context) -/*[clinic end generated code: output=f79ff9ce6d5b05ed input=501759c2522cb78e]*/ +_decimal_Decimal_shift_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context) +/*[clinic end generated code: output=82e061a0d9ecc4f5 input=501759c2522cb78e]*/ Dec_BinaryFuncVA(mpd_qshift) /*[clinic input] _decimal.Decimal.quantize + cls: defining_class exp as w: object rounding: object = None context: object = None @@ -5528,16 +5601,17 @@ current thread's context is used. [clinic start generated code]*/ static PyObject * -_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, - PyObject *rounding, PyObject *context) -/*[clinic end generated code: output=5e84581f96dc685c input=4c7d28d36948e9aa]*/ +_decimal_Decimal_quantize_impl(PyObject *self, PyTypeObject *cls, + PyObject *w, PyObject *rounding, + PyObject *context) +/*[clinic end generated code: output=fc51edf458559913 input=1166e6311e047b74]*/ { PyObject *a, *b; PyObject *result; uint32_t status = 0; mpd_context_t workctx; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); @@ -5634,16 +5708,18 @@ dec_richcompare(PyObject *v, PyObject *w, int op) /*[clinic input] _decimal.Decimal.__ceil__ + cls: defining_class + Return the ceiling as an Integral. [clinic start generated code]*/ static PyObject * -_decimal_Decimal___ceil___impl(PyObject *self) -/*[clinic end generated code: output=e755a6fb7bceac19 input=4a18ef307ac57da0]*/ +_decimal_Decimal___ceil___impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=d986ebf9aadbf9fe input=a8e0b87897706816]*/ { PyObject *context; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_CEILING); } @@ -5703,18 +5779,18 @@ _decimal_Decimal___deepcopy__(PyObject *self, PyObject *memo) } /*[clinic input] -_decimal.Decimal.__floor__ +_decimal.Decimal.__floor__ = _decimal.Decimal.__ceil__ Return the floor as an Integral. [clinic start generated code]*/ static PyObject * -_decimal_Decimal___floor___impl(PyObject *self) -/*[clinic end generated code: output=56767050ac1a1d5a input=cabcc5618564548b]*/ +_decimal_Decimal___floor___impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=e239a2f7f6514c12 input=dcc37aeceb0efb8d]*/ { PyObject *context; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_FLOOR); } @@ -5723,7 +5799,7 @@ _decimal_Decimal___floor___impl(PyObject *self) static Py_hash_t _dec_hash(PyDecObject *v) { -#if defined(CONFIG_64) && _PyHASH_BITS == 61 +#if defined(CONFIG_64) && PyHASH_BITS == 61 /* 2**61 - 1 */ mpd_uint_t p_data[1] = {2305843009213693951ULL}; mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 19, 1, 1, p_data}; @@ -5731,7 +5807,7 @@ _dec_hash(PyDecObject *v) mpd_uint_t inv10_p_data[1] = {2075258708292324556ULL}; mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 19, 1, 1, inv10_p_data}; -#elif defined(CONFIG_32) && _PyHASH_BITS == 31 +#elif defined(CONFIG_32) && PyHASH_BITS == 31 /* 2**31 - 1 */ mpd_uint_t p_data[2] = {147483647UL, 2}; mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 10, 2, 2, p_data}; @@ -5740,7 +5816,7 @@ _dec_hash(PyDecObject *v) mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 10, 2, 2, inv10_p_data}; #else - #error "No valid combination of CONFIG_64, CONFIG_32 and _PyHASH_BITS" + #error "No valid combination of CONFIG_64, CONFIG_32 and PyHASH_BITS" #endif const Py_hash_t py_hash_inf = 314159; mpd_uint_t ten_data[1] = {10}; @@ -5889,18 +5965,18 @@ _decimal_Decimal___sizeof___impl(PyObject *v) } /*[clinic input] -_decimal.Decimal.__trunc__ +_decimal.Decimal.__trunc__ = _decimal.Decimal.__ceil__ Return the Integral closest to x between 0 and x. [clinic start generated code]*/ static PyObject * -_decimal_Decimal___trunc___impl(PyObject *self) -/*[clinic end generated code: output=9ef59578960f80c0 input=a965a61096dcefeb]*/ +_decimal_Decimal___trunc___impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=7b3decc4b636ce32 input=9b3a3a85f63b0515]*/ { PyObject *context; - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + decimal_state *state = PyType_GetModuleState(cls); CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_DOWN); } @@ -6032,7 +6108,7 @@ static PyType_Slot dec_slots[] = { {Py_tp_token, Py_TP_USE_SPEC}, {Py_tp_dealloc, dec_dealloc}, {Py_tp_getattro, PyObject_GenericGetAttr}, - {Py_tp_traverse, dec_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_repr, dec_repr}, {Py_tp_hash, dec_hash}, {Py_tp_str, dec_str}, @@ -6110,7 +6186,8 @@ static PyType_Spec dec_spec = { } /* Unary context method. - Argument Clinic provides PyObject *context, PyObject *x + Argument Clinic provides PyObject *context, + PyTypeObject *cls, PyObject *x */ #define DecCtx_UnaryFunc(MPDFUNC) \ { \ @@ -6118,8 +6195,7 @@ static PyType_Spec dec_spec = { uint32_t status = 0; \ \ CONVERT_OP_RAISE(&a, x, context); \ - decimal_state *state = \ - get_module_state_from_ctx(context); \ + decimal_state *state = PyType_GetModuleState(cls); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ return NULL; \ @@ -6136,7 +6212,8 @@ static PyType_Spec dec_spec = { } /* Binary context method. - Argument Clinic provides PyObject *context, PyObject *x, PyObject *y + Argument Clinic provides PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y */ #define DecCtx_BinaryFunc(MPDFUNC) \ { \ @@ -6145,8 +6222,7 @@ static PyType_Spec dec_spec = { uint32_t status = 0; \ \ CONVERT_BINOP_RAISE(&a, &b, x, y, context); \ - decimal_state *state = \ - get_module_state_from_ctx(context); \ + decimal_state *state = PyType_GetModuleState(cls); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -6167,7 +6243,8 @@ static PyType_Spec dec_spec = { /* * Binary context method. The context is only used for conversion. * The actual MPDFUNC does NOT take a context arg. - * Argument Clinic provides PyObject *context, PyObject *x, PyObject *y + * Argument Clinic provides PyObject *context, PyTypeObject *cls, + * PyObject *x, PyObject *y */ #define DecCtx_BinaryFunc_NO_CTX(MPDFUNC) \ { \ @@ -6176,7 +6253,7 @@ static PyType_Spec dec_spec = { \ CONVERT_BINOP_RAISE(&a, &b, x, y, context); \ decimal_state *state = \ - get_module_state_from_ctx(context); \ + PyType_GetModuleState(cls); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -6191,8 +6268,8 @@ static PyType_Spec dec_spec = { } /* Ternary context method. - Argument Clinic provides PyObject *context, PyObject *x, PyObject *y, - PyObject *z + Argument Clinic provides PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y, PyObject *z */ #define DecCtx_TernaryFunc(MPDFUNC) \ { \ @@ -6201,7 +6278,7 @@ static PyType_Spec dec_spec = { uint32_t status = 0; \ \ CONVERT_TERNOP_RAISE(&a, &b, &c, x, y, z, context); \ - decimal_state *state = get_module_state_from_ctx(context); \ + decimal_state *state = PyType_GetModuleState(cls); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -6228,6 +6305,7 @@ static PyType_Spec dec_spec = { _decimal.Context.abs self as context: self + cls: defining_class x: object / @@ -6235,8 +6313,8 @@ Return the absolute value of x. [clinic start generated code]*/ static PyObject * -_decimal_Context_abs(PyObject *context, PyObject *x) -/*[clinic end generated code: output=5cafb5edf96df9e4 input=8384b327e52d6723]*/ +_decimal_Context_abs_impl(PyObject *context, PyTypeObject *cls, PyObject *x) +/*[clinic end generated code: output=fe080467d32e229c input=00a33f9c68463bb0]*/ DecCtx_UnaryFunc(mpd_qabs) /*[clinic input] @@ -6246,8 +6324,8 @@ Return e ** x. [clinic start generated code]*/ static PyObject * -_decimal_Context_exp(PyObject *context, PyObject *x) -/*[clinic end generated code: output=787085815e6a9aa4 input=5b443c4ab153dd2e]*/ +_decimal_Context_exp_impl(PyObject *context, PyTypeObject *cls, PyObject *x) +/*[clinic end generated code: output=c7477a67010ccc5f input=5b443c4ab153dd2e]*/ DecCtx_UnaryFunc(mpd_qexp) /*[clinic input] @@ -6257,8 +6335,8 @@ Return the natural (base e) logarithm of x. [clinic start generated code]*/ static PyObject * -_decimal_Context_ln(PyObject *context, PyObject *x) -/*[clinic end generated code: output=9ecce76097f16bbe input=cf43cd98a0fe7425]*/ +_decimal_Context_ln_impl(PyObject *context, PyTypeObject *cls, PyObject *x) +/*[clinic end generated code: output=63e691b0680bffc7 input=cf43cd98a0fe7425]*/ DecCtx_UnaryFunc(mpd_qln) /*[clinic input] @@ -6268,8 +6346,9 @@ Return the base 10 logarithm of x. [clinic start generated code]*/ static PyObject * -_decimal_Context_log10(PyObject *context, PyObject *x) -/*[clinic end generated code: output=08080765645630e4 input=309e57faf42c257d]*/ +_decimal_Context_log10_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=e0d9fc928570304d input=309e57faf42c257d]*/ DecCtx_UnaryFunc(mpd_qlog10) /*[clinic input] @@ -6281,8 +6360,9 @@ This operation applies the context to the result. [clinic start generated code]*/ static PyObject * -_decimal_Context_minus(PyObject *context, PyObject *x) -/*[clinic end generated code: output=49c1a0d59f4585b6 input=63be4c419d1d554b]*/ +_decimal_Context_minus_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=f06c409b6aef1aad input=63be4c419d1d554b]*/ DecCtx_UnaryFunc(mpd_qminus) /*[clinic input] @@ -6292,8 +6372,9 @@ Return the largest representable number smaller than x. [clinic start generated code]*/ static PyObject * -_decimal_Context_next_minus(PyObject *context, PyObject *x) -/*[clinic end generated code: output=0c11a0d5fa9103d2 input=969f4d24dfcd5e85]*/ +_decimal_Context_next_minus_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=8dd168f08bec9547 input=969f4d24dfcd5e85]*/ DecCtx_UnaryFunc(mpd_qnext_minus) /*[clinic input] @@ -6303,8 +6384,9 @@ Return the smallest representable number larger than x. [clinic start generated code]*/ static PyObject * -_decimal_Context_next_plus(PyObject *context, PyObject *x) -/*[clinic end generated code: output=fd834e8c58b76031 input=af1a85ee59b56a3c]*/ +_decimal_Context_next_plus_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=2a50586ad2f7c108 input=af1a85ee59b56a3c]*/ DecCtx_UnaryFunc(mpd_qnext_plus) /*[clinic input] @@ -6314,8 +6396,9 @@ Reduce x to its simplest form. Alias for reduce(x). [clinic start generated code]*/ static PyObject * -_decimal_Context_normalize(PyObject *context, PyObject *x) -/*[clinic end generated code: output=492c6ca375bcf020 input=a65bc39c81a654a9]*/ +_decimal_Context_normalize_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=9a9510f442ba2852 input=a65bc39c81a654a9]*/ DecCtx_UnaryFunc(mpd_qreduce) /*[clinic input] @@ -6327,8 +6410,8 @@ This operation applies the context to the result. [clinic start generated code]*/ static PyObject * -_decimal_Context_plus(PyObject *context, PyObject *x) -/*[clinic end generated code: output=ee089d734941936e input=5d8a75702d20e2f9]*/ +_decimal_Context_plus_impl(PyObject *context, PyTypeObject *cls, PyObject *x) +/*[clinic end generated code: output=c37d29f58a47f93a input=5d8a75702d20e2f9]*/ DecCtx_UnaryFunc(mpd_qplus) /*[clinic input] @@ -6338,8 +6421,9 @@ Round to an integer. [clinic start generated code]*/ static PyObject * -_decimal_Context_to_integral_value(PyObject *context, PyObject *x) -/*[clinic end generated code: output=ffc6470421c1439b input=3103e147cb9de9ed]*/ +_decimal_Context_to_integral_value_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=e3d9ad000bc06036 input=3103e147cb9de9ed]*/ DecCtx_UnaryFunc(mpd_qround_to_int) /*[clinic input] @@ -6349,8 +6433,9 @@ Round to an integer. Signal if the result is rounded or inexact. [clinic start generated code]*/ static PyObject * -_decimal_Context_to_integral_exact(PyObject *context, PyObject *x) -/*[clinic end generated code: output=7fac8eca35da9290 input=677dc4b915907b68]*/ +_decimal_Context_to_integral_exact_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=680b796dfae8e2ef input=677dc4b915907b68]*/ DecCtx_UnaryFunc(mpd_qround_to_intx) /*[clinic input] @@ -6360,8 +6445,9 @@ Identical to to_integral_value(x). [clinic start generated code]*/ static PyObject * -_decimal_Context_to_integral(PyObject *context, PyObject *x) -/*[clinic end generated code: output=2741701ed141df91 input=89d4a4b15495b8c9]*/ +_decimal_Context_to_integral_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=09f4823b90b2cf17 input=89d4a4b15495b8c9]*/ DecCtx_UnaryFunc(mpd_qround_to_int) /*[clinic input] @@ -6371,8 +6457,8 @@ Square root of a non-negative number to context precision. [clinic start generated code]*/ static PyObject * -_decimal_Context_sqrt(PyObject *context, PyObject *x) -/*[clinic end generated code: output=5595ae901120606c input=90bd954b0b8076fb]*/ +_decimal_Context_sqrt_impl(PyObject *context, PyTypeObject *cls, PyObject *x) +/*[clinic end generated code: output=2b9c16c6f5ceead0 input=90bd954b0b8076fb]*/ DecCtx_UnaryFunc(mpd_qsqrt) /* Binary arithmetic functions */ @@ -6381,6 +6467,7 @@ DecCtx_UnaryFunc(mpd_qsqrt) _decimal.Context.add self as context: self + cls: defining_class x: object y: object / @@ -6389,8 +6476,9 @@ Return the sum of x and y. [clinic start generated code]*/ static PyObject * -_decimal_Context_add_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=9957850af48fe295 input=8b8eac286bdf6cb4]*/ +_decimal_Context_add_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=ab4f0fb841e6a867 input=f2c74f6a845f62e9]*/ DecCtx_BinaryFunc(mpd_qadd) /*[clinic input] @@ -6400,8 +6488,9 @@ Compare x and y numerically. [clinic start generated code]*/ static PyObject * -_decimal_Context_compare_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=646ab96420b9aad7 input=f701cb179c966ec1]*/ +_decimal_Context_compare_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=56efd1faf653f1d7 input=f701cb179c966ec1]*/ DecCtx_BinaryFunc(mpd_qcompare) /*[clinic input] @@ -6411,9 +6500,9 @@ Compare x and y numerically. All NaNs signal. [clinic start generated code]*/ static PyObject * -_decimal_Context_compare_signal_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=dd56e9e6c3d12216 input=32a1bcef7bbc5179]*/ +_decimal_Context_compare_signal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=7c1a9a9f6ae4e5cd input=32a1bcef7bbc5179]*/ DecCtx_BinaryFunc(mpd_qcompare_signal) /*[clinic input] @@ -6423,8 +6512,9 @@ Return x divided by y. [clinic start generated code]*/ static PyObject * -_decimal_Context_divide_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=0a07a5e718fe4a2c input=00cd9bc2ba2a1786]*/ +_decimal_Context_divide_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=1a7924b20e24a528 input=00cd9bc2ba2a1786]*/ DecCtx_BinaryFunc(mpd_qdiv) /*[clinic input] @@ -6434,8 +6524,9 @@ Return x divided by y, truncated to an integer. [clinic start generated code]*/ static PyObject * -_decimal_Context_divide_int_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=8c2d505d4339f4ef input=e80ada2f50d9719d]*/ +_decimal_Context_divide_int_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=7a1d8948625105f0 input=e80ada2f50d9719d]*/ DecCtx_BinaryFunc(mpd_qdivint) /*[clinic input] @@ -6445,8 +6536,9 @@ Compare the values numerically and return the maximum. [clinic start generated code]*/ static PyObject * -_decimal_Context_max_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=c8545b7718414761 input=22008ab898c86a8b]*/ +_decimal_Context_max_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=cd54af10a51c11fc input=22008ab898c86a8b]*/ DecCtx_BinaryFunc(mpd_qmax) /*[clinic input] @@ -6456,8 +6548,9 @@ Compare the values numerically with their sign ignored. [clinic start generated code]*/ static PyObject * -_decimal_Context_max_mag_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=3cd67457cbc4d961 input=f7ce42ef82a7c52e]*/ +_decimal_Context_max_mag_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=1c812e73bcb7827f input=f7ce42ef82a7c52e]*/ DecCtx_BinaryFunc(mpd_qmax_mag) /*[clinic input] @@ -6467,8 +6560,9 @@ Compare the values numerically and return the minimum. [clinic start generated code]*/ static PyObject * -_decimal_Context_min_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=c1bc3852a7c09707 input=2aeec1167638c5ef]*/ +_decimal_Context_min_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y) +/*[clinic end generated code: output=aa494e95b88107b3 input=2aeec1167638c5ef]*/ DecCtx_BinaryFunc(mpd_qmin) /*[clinic input] @@ -6478,8 +6572,9 @@ Compare the values numerically with their sign ignored. [clinic start generated code]*/ static PyObject * -_decimal_Context_min_mag_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=f662c9d1b49abfd2 input=19d158c29e4fc140]*/ +_decimal_Context_min_mag_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=ee0b69c1d9a14185 input=19d158c29e4fc140]*/ DecCtx_BinaryFunc(mpd_qmin_mag) /*[clinic input] @@ -6489,8 +6584,9 @@ Return the product of x and y. [clinic start generated code]*/ static PyObject * -_decimal_Context_multiply_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=970be645784d70ad input=2fdd01acdbeef8ba]*/ +_decimal_Context_multiply_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=45f33b805afa01a8 input=2fdd01acdbeef8ba]*/ DecCtx_BinaryFunc(mpd_qmul) /*[clinic input] @@ -6500,9 +6596,9 @@ Return the number closest to x, in the direction towards y. [clinic start generated code]*/ static PyObject * -_decimal_Context_next_toward_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=938f2b4034e83618 input=aac775298e02b68c]*/ +_decimal_Context_next_toward_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=436afff6f43edec2 input=aac775298e02b68c]*/ DecCtx_BinaryFunc(mpd_qnext_toward) /*[clinic input] @@ -6512,8 +6608,9 @@ Return a value equal to x (rounded), having the exponent of y. [clinic start generated code]*/ static PyObject * -_decimal_Context_quantize_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=38ae7ac037d093d0 input=43d67a696ab6d895]*/ +_decimal_Context_quantize_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=fcf8cd32b7d628c9 input=43d67a696ab6d895]*/ DecCtx_BinaryFunc(mpd_qquantize) /*[clinic input] @@ -6526,8 +6623,9 @@ original dividend. [clinic start generated code]*/ static PyObject * -_decimal_Context_remainder_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=eb158964831b5ca4 input=36d0eb2b392c1215]*/ +_decimal_Context_remainder_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=e0f96c834abbfbd2 input=36d0eb2b392c1215]*/ DecCtx_BinaryFunc(mpd_qrem) /*[clinic input] @@ -6540,9 +6638,9 @@ is 0 then its sign will be the sign of x). [clinic start generated code]*/ static PyObject * -_decimal_Context_remainder_near_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=2bcbd9bb031d0d13 input=bafb6327bb314c5c]*/ +_decimal_Context_remainder_near_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=7f18c535a12cf8ac input=bafb6327bb314c5c]*/ DecCtx_BinaryFunc(mpd_qrem_near) /*[clinic input] @@ -6552,8 +6650,9 @@ Return the difference between x and y. [clinic start generated code]*/ static PyObject * -_decimal_Context_subtract_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=fa8847e07b7c2bcc input=6767683ec68f7a1a]*/ +_decimal_Context_subtract_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=3d764a8a87e79401 input=6767683ec68f7a1a]*/ DecCtx_BinaryFunc(mpd_qsub) /*[clinic input] @@ -6613,6 +6712,7 @@ _decimal_Context_divmod_impl(PyObject *context, PyObject *x, PyObject *y) _decimal.Context.power self as context: self + cls: defining_class a as base: object b as exp: object modulo as mod: object = None @@ -6635,9 +6735,9 @@ restrictions hold: [clinic start generated code]*/ static PyObject * -_decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, - PyObject *mod) -/*[clinic end generated code: output=d2e68694ec545245 input=e9aef844813de243]*/ +_decimal_Context_power_impl(PyObject *context, PyTypeObject *cls, + PyObject *base, PyObject *exp, PyObject *mod) +/*[clinic end generated code: output=d06d40c37cdd69dc input=2a70edd03317c666]*/ { PyObject *a, *b, *c = NULL; PyObject *result; @@ -6653,7 +6753,7 @@ _decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, } } - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -6687,6 +6787,7 @@ _decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, _decimal.Context.fma self as context: self + cls: defining_class x: object y: object z: object @@ -6696,9 +6797,9 @@ Return x multiplied by y, plus z. [clinic start generated code]*/ static PyObject * -_decimal_Context_fma_impl(PyObject *context, PyObject *x, PyObject *y, - PyObject *z) -/*[clinic end generated code: output=2d6174716faaf4e1 input=80479612da3333d1]*/ +_decimal_Context_fma_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y, PyObject *z) +/*[clinic end generated code: output=08ec3cefc59d71a9 input=da3963b1a1da83b9]*/ DecCtx_TernaryFunc(mpd_qfma) /* No argument */ @@ -6707,15 +6808,16 @@ DecCtx_TernaryFunc(mpd_qfma) _decimal.Context.radix self as context: self + cls: defining_class Return 10. [clinic start generated code]*/ static PyObject * -_decimal_Context_radix_impl(PyObject *context) -/*[clinic end generated code: output=9218fa309e0fcaa1 input=faeaa5b71f838c38]*/ +_decimal_Context_radix_impl(PyObject *context, PyTypeObject *cls) +/*[clinic end generated code: output=674b88b7cd0c264d input=e1e4f8c0abf86825]*/ { - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); return _dec_mpd_radix(state); } @@ -6725,6 +6827,7 @@ _decimal_Context_radix_impl(PyObject *context) _decimal.Context.is_normal self as context: self + cls: defining_class x: object / @@ -6732,8 +6835,9 @@ Return True if x is a normal number, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_normal(PyObject *context, PyObject *x) -/*[clinic end generated code: output=fed613aed8b286de input=1e7ff3f560842b8d]*/ +_decimal_Context_is_normal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=089c5609db60bf57 input=7c90b825a517ef7e]*/ DecCtx_BoolFunc(mpd_isnormal) /*[clinic input] @@ -6743,8 +6847,9 @@ Return True if x is subnormal, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_subnormal(PyObject *context, PyObject *x) -/*[clinic end generated code: output=834450c602d58759 input=73f1bd9367b913a4]*/ +_decimal_Context_is_subnormal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=f58c45a288aadeda input=73f1bd9367b913a4]*/ DecCtx_BoolFunc(mpd_issubnormal) /*[clinic input] @@ -6754,8 +6859,9 @@ Return True if x is finite, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_finite(PyObject *context, PyObject *x) -/*[clinic end generated code: output=45606d2f56874fef input=abff92a8a6bb85e6]*/ +_decimal_Context_is_finite_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=dfb00f1b5589b9f0 input=abff92a8a6bb85e6]*/ DecCtx_BoolFunc_NO_CTX(mpd_isfinite) /*[clinic input] @@ -6765,8 +6871,9 @@ Return True if x is infinite, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_infinite(PyObject *context, PyObject *x) -/*[clinic end generated code: output=35c480cd0a2c3cf9 input=591242ae9a1e60e6]*/ +_decimal_Context_is_infinite_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=1c28517500811d01 input=591242ae9a1e60e6]*/ DecCtx_BoolFunc_NO_CTX(mpd_isinfinite) /*[clinic input] @@ -6776,8 +6883,9 @@ Return True if x is a qNaN or sNaN, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_nan(PyObject *context, PyObject *x) -/*[clinic end generated code: output=cb529f55bf3106b3 input=520218376d5eec5e]*/ +_decimal_Context_is_nan_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=9dc15463ee19864a input=520218376d5eec5e]*/ DecCtx_BoolFunc_NO_CTX(mpd_isnan) /*[clinic input] @@ -6787,8 +6895,9 @@ Return True if x is a quiet NaN, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_qnan(PyObject *context, PyObject *x) -/*[clinic end generated code: output=3e2e750eb643db1d input=97d06a14ab3360d1]*/ +_decimal_Context_is_qnan_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=4caa672e03703b6d input=97d06a14ab3360d1]*/ DecCtx_BoolFunc_NO_CTX(mpd_isqnan) /*[clinic input] @@ -6798,8 +6907,9 @@ Return True if x is a signaling NaN, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_snan(PyObject *context, PyObject *x) -/*[clinic end generated code: output=a7ead03a2dfa15e4 input=0059fe4e9c3b25a8]*/ +_decimal_Context_is_snan_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=a8caa929d9f82ecd input=0059fe4e9c3b25a8]*/ DecCtx_BoolFunc_NO_CTX(mpd_issnan) /*[clinic input] @@ -6809,8 +6919,9 @@ Return True if x is negative, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_signed(PyObject *context, PyObject *x) -/*[clinic end generated code: output=c85cc15479d5ed47 input=b950cd697721ab8b]*/ +_decimal_Context_is_signed_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=42c450c99d4fe7db input=b950cd697721ab8b]*/ DecCtx_BoolFunc_NO_CTX(mpd_issigned) /*[clinic input] @@ -6820,8 +6931,9 @@ Return True if x is a zero, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_zero(PyObject *context, PyObject *x) -/*[clinic end generated code: output=24150f3c2422ebf8 input=bf08197d142a8027]*/ +_decimal_Context_is_zero_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=e6c55359b7241d9e input=bf08197d142a8027]*/ DecCtx_BoolFunc_NO_CTX(mpd_iszero) /*[clinic input] @@ -6831,10 +6943,11 @@ Return True if x is canonical, False otherwise. [clinic start generated code]*/ static PyObject * -_decimal_Context_is_canonical(PyObject *context, PyObject *x) -/*[clinic end generated code: output=b5b522b930a41186 input=1bf2129808e55eb9]*/ +_decimal_Context_is_canonical_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=18ee249d9aec957c input=1bf2129808e55eb9]*/ { - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); if (!PyDec_Check(state, x)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); @@ -6852,8 +6965,9 @@ Apply self to Decimal x. [clinic start generated code]*/ static PyObject * -_decimal_Context__apply(PyObject *context, PyObject *x) -/*[clinic end generated code: output=8db39d294602492e input=12b34468ca4a4c30]*/ +_decimal_Context__apply_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=c6b542f4e8114b97 input=12b34468ca4a4c30]*/ { PyObject *result, *a; @@ -6872,8 +6986,9 @@ Apply self to Decimal x. [clinic start generated code]*/ static PyObject * -_decimal_Context_apply(PyObject *context, PyObject *x) -/*[clinic end generated code: output=4d39653645a6df44 input=388e66ca82733516]*/ +_decimal_Context_apply_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=f8a7142d47ad4ff3 input=388e66ca82733516]*/ { return _decimal_Context__apply(context, v); } @@ -6886,10 +7001,11 @@ Return a new instance of x. [clinic start generated code]*/ static PyObject * -_decimal_Context_canonical(PyObject *context, PyObject *x) -/*[clinic end generated code: output=28fa845499e5d485 input=025ecb106ac15bff]*/ +_decimal_Context_canonical_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=f213e433e2032e5e input=025ecb106ac15bff]*/ { - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); if (!PyDec_Check(state, x)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); @@ -6906,14 +7022,15 @@ Return a copy of x with the sign set to 0. [clinic start generated code]*/ static PyObject * -_decimal_Context_copy_abs(PyObject *context, PyObject *x) -/*[clinic end generated code: output=a9035e6606261b30 input=4aa2f612625f0f73]*/ +_decimal_Context_copy_abs_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=a141ad4b9afe2deb input=4aa2f612625f0f73]*/ { PyObject *result, *a; uint32_t status = 0; CONVERT_OP_RAISE(&a, x, context); - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -6937,8 +7054,9 @@ Return a copy of Decimal x. [clinic start generated code]*/ static PyObject * -_decimal_Context_copy_decimal(PyObject *context, PyObject *x) -/*[clinic end generated code: output=b9ec251a2a568a14 input=4db4f942f45fb7c9]*/ +_decimal_Context_copy_decimal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=639a82e1193d31f6 input=4db4f942f45fb7c9]*/ { PyObject *result; @@ -6953,14 +7071,15 @@ Return a copy of x with the sign inverted. [clinic start generated code]*/ static PyObject * -_decimal_Context_copy_negate(PyObject *context, PyObject *x) -/*[clinic end generated code: output=5fe136d7bac13391 input=2e6e213e2ed0efda]*/ +_decimal_Context_copy_negate_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=e49d013489dc252b input=2e6e213e2ed0efda]*/ { PyObject *result, *a; uint32_t status = 0; CONVERT_OP_RAISE(&a, x, context); - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -6984,19 +7103,33 @@ Return the exponent of the magnitude of the operand's MSD. [clinic start generated code]*/ static PyObject * -_decimal_Context_logb(PyObject *context, PyObject *x) -/*[clinic end generated code: output=d2d8469f828daa41 input=28d1cd1a8a906b9a]*/ +_decimal_Context_logb_impl(PyObject *context, PyTypeObject *cls, PyObject *x) +/*[clinic end generated code: output=9b9697e1eb68093f input=28d1cd1a8a906b9a]*/ DecCtx_UnaryFunc(mpd_qlogb) /*[clinic input] _decimal.Context.logical_invert = _decimal.Context.abs -Invert all digits of x. +Invert all the digits in the operand. + +The operand must be a logical number. + + >>> ExtendedContext.logical_invert(Decimal('0')) + Decimal('111111111') + >>> ExtendedContext.logical_invert(Decimal('1')) + Decimal('111111110') + >>> ExtendedContext.logical_invert(Decimal('111111111')) + Decimal('0') + >>> ExtendedContext.logical_invert(Decimal('101010101')) + Decimal('10101010') + >>> ExtendedContext.logical_invert(1101) + Decimal('111110010') [clinic start generated code]*/ static PyObject * -_decimal_Context_logical_invert(PyObject *context, PyObject *x) -/*[clinic end generated code: output=b863a5cdb986f684 input=1fa8dcc59c557fcc]*/ +_decimal_Context_logical_invert_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=97760277a958e2b0 input=8e568f4c745ab596]*/ DecCtx_UnaryFunc(mpd_qinvert) /*[clinic input] @@ -7006,8 +7139,9 @@ Return an indication of the class of x. [clinic start generated code]*/ static PyObject * -_decimal_Context_number_class(PyObject *context, PyObject *x) -/*[clinic end generated code: output=2b39fa98dd723c6f input=1ead8462f1800e4e]*/ +_decimal_Context_number_class_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=c1592a23e25ba5ee input=1ead8462f1800e4e]*/ { PyObject *a; const char *cp; @@ -7027,8 +7161,9 @@ Convert a number to a string using scientific notation. [clinic start generated code]*/ static PyObject * -_decimal_Context_to_sci_string(PyObject *context, PyObject *x) -/*[clinic end generated code: output=7d461d24824c6f15 input=ed442677c66d342d]*/ +_decimal_Context_to_sci_string_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=092dcdef999d72da input=ed442677c66d342d]*/ { PyObject *result; PyObject *a; @@ -7057,8 +7192,9 @@ Convert a number to a string, using engineering notation. [clinic start generated code]*/ static PyObject * -_decimal_Context_to_eng_string(PyObject *context, PyObject *x) -/*[clinic end generated code: output=3a54b9de0b01708f input=a574385e2e3e3bc0]*/ +_decimal_Context_to_eng_string_impl(PyObject *context, PyTypeObject *cls, + PyObject *x) +/*[clinic end generated code: output=7fc53216c208f487 input=a574385e2e3e3bc0]*/ { PyObject *result; PyObject *a; @@ -7086,6 +7222,7 @@ _decimal_Context_to_eng_string(PyObject *context, PyObject *x) _decimal.Context.compare_total self as context: self + cls: defining_class x: object y: object / @@ -7094,9 +7231,9 @@ Compare x and y using their abstract representation. [clinic start generated code]*/ static PyObject * -_decimal_Context_compare_total_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=a9299ef125fb2245 input=020b30c9bc2ea2c6]*/ +_decimal_Context_compare_total_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=f79177b27fe930e3 input=2bfc677a841e297a]*/ DecCtx_BinaryFunc_NO_CTX(mpd_compare_total) /*[clinic input] @@ -7106,9 +7243,9 @@ Compare x and y using their abstract representation, ignoring sign. [clinic start generated code]*/ static PyObject * -_decimal_Context_compare_total_mag_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=7c376de9f94feeaf input=2b982e69f932dcb2]*/ +_decimal_Context_compare_total_mag_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=2528c669ccd6d6ff input=2b982e69f932dcb2]*/ DecCtx_BinaryFunc_NO_CTX(mpd_compare_total_mag) /*[clinic input] @@ -7118,15 +7255,16 @@ Copy the sign from y to x. [clinic start generated code]*/ static PyObject * -_decimal_Context_copy_sign_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=fff3c5c474acf78e input=c0682aeaffc7cfdf]*/ +_decimal_Context_copy_sign_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=77d23b6f4e42120c input=c0682aeaffc7cfdf]*/ { PyObject *a, *b; PyObject *result; uint32_t status = 0; CONVERT_BINOP_RAISE(&a, &b, x, y, context); - decimal_state *state = get_module_state_from_ctx(context); + decimal_state *state = PyType_GetModuleState(cls); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -7148,36 +7286,100 @@ _decimal_Context_copy_sign_impl(PyObject *context, PyObject *x, PyObject *y) /*[clinic input] _decimal.Context.logical_and = _decimal.Context.add -Digit-wise and of x and y. +Applies the logical operation 'and' between each operand's digits. + +The operands must be both logical numbers. + + >>> ExtendedContext.logical_and(Decimal('0'), Decimal('0')) + Decimal('0') + >>> ExtendedContext.logical_and(Decimal('0'), Decimal('1')) + Decimal('0') + >>> ExtendedContext.logical_and(Decimal('1'), Decimal('0')) + Decimal('0') + >>> ExtendedContext.logical_and(Decimal('1'), Decimal('1')) + Decimal('1') + >>> ExtendedContext.logical_and(Decimal('1100'), Decimal('1010')) + Decimal('1000') + >>> ExtendedContext.logical_and(Decimal('1111'), Decimal('10')) + Decimal('10') + >>> ExtendedContext.logical_and(110, 1101) + Decimal('100') + >>> ExtendedContext.logical_and(Decimal(110), 1101) + Decimal('100') + >>> ExtendedContext.logical_and(110, Decimal(1101)) + Decimal('100') [clinic start generated code]*/ static PyObject * -_decimal_Context_logical_and_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=f1e9bf7844a395fc input=30ee33b5b365fd80]*/ +_decimal_Context_logical_and_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=009dfa08ecaa2ac8 input=bcb7d3d6ab7530de]*/ DecCtx_BinaryFunc(mpd_qand) /*[clinic input] _decimal.Context.logical_or = _decimal.Context.add -Digit-wise or of x and y. +Applies the logical operation 'or' between each operand's digits. + +The operands must be both logical numbers. + + >>> ExtendedContext.logical_or(Decimal('0'), Decimal('0')) + Decimal('0') + >>> ExtendedContext.logical_or(Decimal('0'), Decimal('1')) + Decimal('1') + >>> ExtendedContext.logical_or(Decimal('1'), Decimal('0')) + Decimal('1') + >>> ExtendedContext.logical_or(Decimal('1'), Decimal('1')) + Decimal('1') + >>> ExtendedContext.logical_or(Decimal('1100'), Decimal('1010')) + Decimal('1110') + >>> ExtendedContext.logical_or(Decimal('1110'), Decimal('10')) + Decimal('1110') + >>> ExtendedContext.logical_or(110, 1101) + Decimal('1111') + >>> ExtendedContext.logical_or(Decimal(110), 1101) + Decimal('1111') + >>> ExtendedContext.logical_or(110, Decimal(1101)) + Decimal('1111') [clinic start generated code]*/ static PyObject * -_decimal_Context_logical_or_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=28f7ecd1af3262f0 input=3b1a6725d0262fb9]*/ +_decimal_Context_logical_or_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=eb38617e8d31bf12 input=47b45d296fb90846]*/ DecCtx_BinaryFunc(mpd_qor) /*[clinic input] _decimal.Context.logical_xor = _decimal.Context.add -Digit-wise xor of x and y. +Applies the logical operation 'xor' between each operand's digits. + +The operands must be both logical numbers. + + >>> ExtendedContext.logical_xor(Decimal('0'), Decimal('0')) + Decimal('0') + >>> ExtendedContext.logical_xor(Decimal('0'), Decimal('1')) + Decimal('1') + >>> ExtendedContext.logical_xor(Decimal('1'), Decimal('0')) + Decimal('1') + >>> ExtendedContext.logical_xor(Decimal('1'), Decimal('1')) + Decimal('0') + >>> ExtendedContext.logical_xor(Decimal('1100'), Decimal('1010')) + Decimal('110') + >>> ExtendedContext.logical_xor(Decimal('1111'), Decimal('10')) + Decimal('1101') + >>> ExtendedContext.logical_xor(110, 1101) + Decimal('1011') + >>> ExtendedContext.logical_xor(Decimal(110), 1101) + Decimal('1011') + >>> ExtendedContext.logical_xor(110, Decimal(1101)) + Decimal('1011') [clinic start generated code]*/ static PyObject * -_decimal_Context_logical_xor_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=7d8461ace42d1871 input=5ebbbe8bb35da380]*/ +_decimal_Context_logical_xor_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=23cd81fdcd865d5a input=fcaaf828c1d2d089]*/ DecCtx_BinaryFunc(mpd_qxor) /*[clinic input] @@ -7187,8 +7389,9 @@ Return a copy of x, rotated by y places. [clinic start generated code]*/ static PyObject * -_decimal_Context_rotate_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=6d8b718f218712a2 input=7ad91845c909eb0a]*/ +_decimal_Context_rotate_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=3d5b3cfcb4659432 input=7ad91845c909eb0a]*/ DecCtx_BinaryFunc(mpd_qrotate) /*[clinic input] @@ -7198,8 +7401,9 @@ Return the first operand after adding the second value to its exp. [clinic start generated code]*/ static PyObject * -_decimal_Context_scaleb_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=3c9cb117027c7722 input=c5d2ee7a57f65f8c]*/ +_decimal_Context_scaleb_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=795ac61bcbe61c67 input=c5d2ee7a57f65f8c]*/ DecCtx_BinaryFunc(mpd_qscaleb) /*[clinic input] @@ -7209,8 +7413,9 @@ Return a copy of x, shifted by y places. [clinic start generated code]*/ static PyObject * -_decimal_Context_shift_impl(PyObject *context, PyObject *x, PyObject *y) -/*[clinic end generated code: output=78625878a264b3e5 input=1ab44ff0854420ce]*/ +_decimal_Context_shift_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=43d69615f0271c81 input=1ab44ff0854420ce]*/ DecCtx_BinaryFunc(mpd_qshift) /*[clinic input] @@ -7220,9 +7425,9 @@ Return True if the two operands have the same exponent. [clinic start generated code]*/ static PyObject * -_decimal_Context_same_quantum_impl(PyObject *context, PyObject *x, - PyObject *y) -/*[clinic end generated code: output=137acab27ece605c input=194cd156e398eaf9]*/ +_decimal_Context_same_quantum_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y) +/*[clinic end generated code: output=91a4d8325f98d9e9 input=194cd156e398eaf9]*/ { PyObject *a, *b; PyObject *result; @@ -7324,16 +7529,14 @@ static PyMethodDef context_methods [] = _DECIMAL_CONTEXT_CLEAR_FLAGS_METHODDEF _DECIMAL_CONTEXT_CLEAR_TRAPS_METHODDEF -#ifdef CONFIG_32 /* Unsafe set functions with relaxed range checks */ - { "_unsafe_setprec", context_unsafe_setprec, METH_O, NULL }, - { "_unsafe_setemin", context_unsafe_setemin, METH_O, NULL }, - { "_unsafe_setemax", context_unsafe_setemax, METH_O, NULL }, -#endif + _DECIMAL_CONTEXT__UNSAFE_SETPREC_METHODDEF + _DECIMAL_CONTEXT__UNSAFE_SETEMIN_METHODDEF + _DECIMAL_CONTEXT__UNSAFE_SETEMAX_METHODDEF /* Miscellaneous */ - { "__copy__", context_copy, METH_NOARGS, NULL }, - { "__reduce__", context_reduce, METH_NOARGS, NULL }, + _DECIMAL_CONTEXT___COPY___METHODDEF + _DECIMAL_CONTEXT___REDUCE___METHODDEF _DECIMAL_CONTEXT_COPY_METHODDEF _DECIMAL_CONTEXT_CREATE_DECIMAL_METHODDEF _DECIMAL_CONTEXT_CREATE_DECIMAL_FROM_FLOAT_METHODDEF @@ -7366,12 +7569,35 @@ static PyType_Spec context_spec = { }; +static PyObject * +decimal_getattr(PyObject *self, PyObject *args) +{ + PyObject *name; + if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)) { + return NULL; + } + + if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + 1) < 0) { + return NULL; + } + return PyUnicode_FromString(MPD_SPEC_VERSION); + } + + PyErr_Format(PyExc_AttributeError, "module 'decimal' has no attribute %R", name); + return NULL; +} + + static PyMethodDef _decimal_methods [] = { _DECIMAL_GETCONTEXT_METHODDEF _DECIMAL_SETCONTEXT_METHODDEF _DECIMAL_LOCALCONTEXT_METHODDEF _DECIMAL_IEEECONTEXT_METHODDEF + {"__getattr__", decimal_getattr, METH_VARARGS, "Module __getattr__"}, { NULL, NULL, 1, NULL } }; @@ -7527,10 +7753,15 @@ _decimal_exec(PyObject *m) /* DecimalTuple */ ASSIGN_PTR(collections, PyImport_ImportModule("collections")); - ASSIGN_PTR(state->DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, - "namedtuple", "(ss)", "DecimalTuple", - "sign digits exponent")); - + ASSIGN_PTR(obj, PyObject_CallMethod(collections, "namedtuple", "(ss)", + "DecimalTuple", + "sign digits exponent")); + if (!PyType_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "type is expected from namedtuple call"); + goto error; + } + ASSIGN_PTR(state->DecimalTuple, (PyTypeObject *)obj); ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); CHECK_INT(PyDict_SetItemString(state->DecimalTuple->tp_dict, "__module__", obj)); Py_CLEAR(obj); @@ -7691,7 +7922,7 @@ _decimal_exec(PyObject *m) } /* Add specification version number */ - CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70")); + CHECK_INT(PyModule_AddStringConstant(m, "SPEC_VERSION", MPD_SPEC_VERSION)); CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version())); return 0; diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 0f7a7f78cd7..b09200845d1 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -51,6 +51,123 @@ _decimal_Context_Etop(PyObject *self, PyObject *Py_UNUSED(ignored)) return _decimal_Context_Etop_impl(self); } +#if defined(CONFIG_32) + +PyDoc_STRVAR(_decimal_Context__unsafe_setprec__doc__, +"_unsafe_setprec($self, x, /)\n" +"--\n" +"\n"); + +#define _DECIMAL_CONTEXT__UNSAFE_SETPREC_METHODDEF \ + {"_unsafe_setprec", (PyCFunction)_decimal_Context__unsafe_setprec, METH_O, _decimal_Context__unsafe_setprec__doc__}, + +static PyObject * +_decimal_Context__unsafe_setprec_impl(PyObject *self, Py_ssize_t x); + +static PyObject * +_decimal_Context__unsafe_setprec(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t x; + + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + x = ival; + } + return_value = _decimal_Context__unsafe_setprec_impl(self, x); + +exit: + return return_value; +} + +#endif /* defined(CONFIG_32) */ + +#if defined(CONFIG_32) + +PyDoc_STRVAR(_decimal_Context__unsafe_setemin__doc__, +"_unsafe_setemin($self, x, /)\n" +"--\n" +"\n"); + +#define _DECIMAL_CONTEXT__UNSAFE_SETEMIN_METHODDEF \ + {"_unsafe_setemin", (PyCFunction)_decimal_Context__unsafe_setemin, METH_O, _decimal_Context__unsafe_setemin__doc__}, + +static PyObject * +_decimal_Context__unsafe_setemin_impl(PyObject *self, Py_ssize_t x); + +static PyObject * +_decimal_Context__unsafe_setemin(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t x; + + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + x = ival; + } + return_value = _decimal_Context__unsafe_setemin_impl(self, x); + +exit: + return return_value; +} + +#endif /* defined(CONFIG_32) */ + +#if defined(CONFIG_32) + +PyDoc_STRVAR(_decimal_Context__unsafe_setemax__doc__, +"_unsafe_setemax($self, x, /)\n" +"--\n" +"\n"); + +#define _DECIMAL_CONTEXT__UNSAFE_SETEMAX_METHODDEF \ + {"_unsafe_setemax", (PyCFunction)_decimal_Context__unsafe_setemax, METH_O, _decimal_Context__unsafe_setemax__doc__}, + +static PyObject * +_decimal_Context__unsafe_setemax_impl(PyObject *self, Py_ssize_t x); + +static PyObject * +_decimal_Context__unsafe_setemax(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t x; + + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + x = ival; + } + return_value = _decimal_Context__unsafe_setemax_impl(self, x); + +exit: + return return_value; +} + +#endif /* defined(CONFIG_32) */ + PyDoc_STRVAR(_decimal_Context_clear_traps__doc__, "clear_traps($self, /)\n" "--\n" @@ -257,15 +374,61 @@ PyDoc_STRVAR(_decimal_Context_copy__doc__, "Return a duplicate of the context with all flags cleared."); #define _DECIMAL_CONTEXT_COPY_METHODDEF \ - {"copy", (PyCFunction)_decimal_Context_copy, METH_NOARGS, _decimal_Context_copy__doc__}, + {"copy", _PyCFunction_CAST(_decimal_Context_copy), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_copy__doc__}, static PyObject * -_decimal_Context_copy_impl(PyObject *self); +_decimal_Context_copy_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Context_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Context_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Context_copy_impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } + return _decimal_Context_copy_impl(self, cls); +} + +PyDoc_STRVAR(_decimal_Context___copy____doc__, +"__copy__($self, /)\n" +"--\n" +"\n"); + +#define _DECIMAL_CONTEXT___COPY___METHODDEF \ + {"__copy__", _PyCFunction_CAST(_decimal_Context___copy__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context___copy____doc__}, + +static PyObject * +_decimal_Context___copy___impl(PyObject *self, PyTypeObject *cls); + +static PyObject * +_decimal_Context___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); + return NULL; + } + return _decimal_Context___copy___impl(self, cls); +} + +PyDoc_STRVAR(_decimal_Context___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define _DECIMAL_CONTEXT___REDUCE___METHODDEF \ + {"__reduce__", _PyCFunction_CAST(_decimal_Context___reduce__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context___reduce____doc__}, + +static PyObject * +_decimal_Context___reduce___impl(PyObject *self, PyTypeObject *cls); + +static PyObject * +_decimal_Context___reduce__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__reduce__() takes no arguments"); + return NULL; + } + return _decimal_Context___reduce___impl(self, cls); } PyDoc_STRVAR(_decimal_getcontext__doc__, @@ -445,18 +608,41 @@ PyDoc_STRVAR(_decimal_Decimal_from_float__doc__, " Decimal(\'-Infinity\')"); #define _DECIMAL_DECIMAL_FROM_FLOAT_METHODDEF \ - {"from_float", (PyCFunction)_decimal_Decimal_from_float, METH_O|METH_CLASS, _decimal_Decimal_from_float__doc__}, + {"from_float", _PyCFunction_CAST(_decimal_Decimal_from_float), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, _decimal_Decimal_from_float__doc__}, static PyObject * -_decimal_Decimal_from_float_impl(PyTypeObject *type, PyObject *pyfloat); +_decimal_Decimal_from_float_impl(PyTypeObject *type, PyTypeObject *cls, + PyObject *pyfloat); static PyObject * -_decimal_Decimal_from_float(PyObject *type, PyObject *pyfloat) +_decimal_Decimal_from_float(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif - return_value = _decimal_Decimal_from_float_impl((PyTypeObject *)type, pyfloat); + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "from_float", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *pyfloat; + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + pyfloat = args[0]; + return_value = _decimal_Decimal_from_float_impl((PyTypeObject *)type, cls, pyfloat); + +exit: return return_value; } @@ -474,18 +660,41 @@ PyDoc_STRVAR(_decimal_Decimal_from_number__doc__, " Decimal(\'3.14\')"); #define _DECIMAL_DECIMAL_FROM_NUMBER_METHODDEF \ - {"from_number", (PyCFunction)_decimal_Decimal_from_number, METH_O|METH_CLASS, _decimal_Decimal_from_number__doc__}, + {"from_number", _PyCFunction_CAST(_decimal_Decimal_from_number), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, _decimal_Decimal_from_number__doc__}, static PyObject * -_decimal_Decimal_from_number_impl(PyTypeObject *type, PyObject *number); +_decimal_Decimal_from_number_impl(PyTypeObject *type, PyTypeObject *cls, + PyObject *number); static PyObject * -_decimal_Decimal_from_number(PyObject *type, PyObject *number) +_decimal_Decimal_from_number(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif - return_value = _decimal_Decimal_from_number_impl((PyTypeObject *)type, number); + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "from_number", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *number; + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + number = args[0]; + return_value = _decimal_Decimal_from_number_impl((PyTypeObject *)type, cls, number); + +exit: return return_value; } @@ -499,7 +708,44 @@ PyDoc_STRVAR(_decimal_Context_create_decimal_from_float__doc__, "the context limits."); #define _DECIMAL_CONTEXT_CREATE_DECIMAL_FROM_FLOAT_METHODDEF \ - {"create_decimal_from_float", (PyCFunction)_decimal_Context_create_decimal_from_float, METH_O, _decimal_Context_create_decimal_from_float__doc__}, + {"create_decimal_from_float", _PyCFunction_CAST(_decimal_Context_create_decimal_from_float), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_create_decimal_from_float__doc__}, + +static PyObject * +_decimal_Context_create_decimal_from_float_impl(PyObject *context, + PyTypeObject *cls, + PyObject *f); + +static PyObject * +_decimal_Context_create_decimal_from_float(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create_decimal_from_float", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *f; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + f = args[0]; + return_value = _decimal_Context_create_decimal_from_float_impl(context, cls, f); + +exit: + return return_value; +} PyDoc_STRVAR(dec_new__doc__, "Decimal(value=\'0\', context=None)\n" @@ -617,20 +863,36 @@ PyDoc_STRVAR(_decimal_Decimal___format____doc__, "Formats the Decimal according to format_spec."); #define _DECIMAL_DECIMAL___FORMAT___METHODDEF \ - {"__format__", _PyCFunction_CAST(_decimal_Decimal___format__), METH_FASTCALL, _decimal_Decimal___format____doc__}, + {"__format__", _PyCFunction_CAST(_decimal_Decimal___format__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal___format____doc__}, static PyObject * -_decimal_Decimal___format___impl(PyObject *dec, PyObject *fmtarg, - PyObject *override); +_decimal_Decimal___format___impl(PyObject *dec, PyTypeObject *cls, + PyObject *fmtarg, PyObject *override); static PyObject * -_decimal_Decimal___format__(PyObject *dec, PyObject *const *args, Py_ssize_t nargs) +_decimal_Decimal___format__(PyObject *dec, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__format__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *fmtarg; PyObject *override = NULL; - if (!_PyArg_CheckPositional("__format__", nargs, 1, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } if (!PyUnicode_Check(args[0])) { @@ -639,11 +901,11 @@ _decimal_Decimal___format__(PyObject *dec, PyObject *const *args, Py_ssize_t nar } fmtarg = args[0]; if (nargs < 2) { - goto skip_optional; + goto skip_optional_posonly; } override = args[1]; -skip_optional: - return_value = _decimal_Decimal___format___impl(dec, fmtarg, override); +skip_optional_posonly: + return_value = _decimal_Decimal___format___impl(dec, cls, fmtarg, override); exit: return return_value; @@ -659,15 +921,19 @@ PyDoc_STRVAR(_decimal_Decimal_as_integer_ratio__doc__, "Raise OverflowError on infinities and a ValueError on NaNs."); #define _DECIMAL_DECIMAL_AS_INTEGER_RATIO_METHODDEF \ - {"as_integer_ratio", (PyCFunction)_decimal_Decimal_as_integer_ratio, METH_NOARGS, _decimal_Decimal_as_integer_ratio__doc__}, + {"as_integer_ratio", _PyCFunction_CAST(_decimal_Decimal_as_integer_ratio), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_as_integer_ratio__doc__}, static PyObject * -_decimal_Decimal_as_integer_ratio_impl(PyObject *self); +_decimal_Decimal_as_integer_ratio_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_as_integer_ratio(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_as_integer_ratio_impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "as_integer_ratio() takes no arguments"); + return NULL; + } + return _decimal_Decimal_as_integer_ratio_impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, @@ -681,14 +947,15 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_value__doc__, "rounding mode of the current default context is used."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_VALUE_METHODDEF \ - {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, + {"to_integral_value", _PyCFunction_CAST(_decimal_Decimal_to_integral_value), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_value__doc__}, static PyObject * -_decimal_Decimal_to_integral_value_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_value_impl(PyObject *self, PyTypeObject *cls, + PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_value(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -739,7 +1006,7 @@ _decimal_Decimal_to_integral_value(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_value_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_value_impl(self, cls, rounding, context); exit: return return_value; @@ -755,14 +1022,14 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral__doc__, "versions."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_METHODDEF \ - {"to_integral", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral__doc__}, + {"to_integral", _PyCFunction_CAST(_decimal_Decimal_to_integral), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral__doc__}, static PyObject * -_decimal_Decimal_to_integral_impl(PyObject *self, PyObject *rounding, - PyObject *context); +_decimal_Decimal_to_integral_impl(PyObject *self, PyTypeObject *cls, + PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -813,7 +1080,7 @@ _decimal_Decimal_to_integral(PyObject *self, PyObject *const *args, Py_ssize_t n } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_impl(self, cls, rounding, context); exit: return return_value; @@ -831,14 +1098,15 @@ PyDoc_STRVAR(_decimal_Decimal_to_integral_exact__doc__, "given, then the rounding mode of the current default context is used."); #define _DECIMAL_DECIMAL_TO_INTEGRAL_EXACT_METHODDEF \ - {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, + {"to_integral_exact", _PyCFunction_CAST(_decimal_Decimal_to_integral_exact), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_integral_exact__doc__}, static PyObject * -_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyObject *rounding, +_decimal_Decimal_to_integral_exact_impl(PyObject *self, PyTypeObject *cls, + PyObject *rounding, PyObject *context); static PyObject * -_decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_integral_exact(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -889,7 +1157,7 @@ _decimal_Decimal_to_integral_exact(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_to_integral_exact_impl(self, rounding, context); + return_value = _decimal_Decimal_to_integral_exact_impl(self, cls, rounding, context); exit: return return_value; @@ -902,26 +1170,43 @@ PyDoc_STRVAR(_decimal_Decimal___round____doc__, "Return the Integral closest to self, rounding half toward even."); #define _DECIMAL_DECIMAL___ROUND___METHODDEF \ - {"__round__", _PyCFunction_CAST(_decimal_Decimal___round__), METH_FASTCALL, _decimal_Decimal___round____doc__}, + {"__round__", _PyCFunction_CAST(_decimal_Decimal___round__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal___round____doc__}, static PyObject * -_decimal_Decimal___round___impl(PyObject *self, PyObject *ndigits); +_decimal_Decimal___round___impl(PyObject *self, PyTypeObject *cls, + PyObject *ndigits); static PyObject * -_decimal_Decimal___round__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +_decimal_Decimal___round__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__round__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyObject *ndigits = NULL; - if (!_PyArg_CheckPositional("__round__", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } ndigits = args[0]; -skip_optional: - return_value = _decimal_Decimal___round___impl(self, ndigits); +skip_optional_posonly: + return_value = _decimal_Decimal___round___impl(self, cls, ndigits); exit: return return_value; @@ -934,15 +1219,19 @@ PyDoc_STRVAR(_decimal_Decimal_as_tuple__doc__, "Return a tuple representation of the number."); #define _DECIMAL_DECIMAL_AS_TUPLE_METHODDEF \ - {"as_tuple", (PyCFunction)_decimal_Decimal_as_tuple, METH_NOARGS, _decimal_Decimal_as_tuple__doc__}, + {"as_tuple", _PyCFunction_CAST(_decimal_Decimal_as_tuple), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_as_tuple__doc__}, static PyObject * -_decimal_Decimal_as_tuple_impl(PyObject *self); +_decimal_Decimal_as_tuple_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal_as_tuple(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_as_tuple(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_as_tuple_impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "as_tuple() takes no arguments"); + return NULL; + } + return _decimal_Decimal_as_tuple_impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal_exp__doc__, @@ -955,13 +1244,14 @@ PyDoc_STRVAR(_decimal_Decimal_exp__doc__, "correctly rounded."); #define _DECIMAL_DECIMAL_EXP_METHODDEF \ - {"exp", _PyCFunction_CAST(_decimal_Decimal_exp), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_exp__doc__}, + {"exp", _PyCFunction_CAST(_decimal_Decimal_exp), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_exp__doc__}, static PyObject * -_decimal_Decimal_exp_impl(PyObject *self, PyObject *context); +_decimal_Decimal_exp_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_exp(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_exp(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1005,7 +1295,7 @@ _decimal_Decimal_exp(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_exp_impl(self, context); + return_value = _decimal_Decimal_exp_impl(self, cls, context); exit: return return_value; @@ -1021,13 +1311,14 @@ PyDoc_STRVAR(_decimal_Decimal_ln__doc__, "correctly rounded."); #define _DECIMAL_DECIMAL_LN_METHODDEF \ - {"ln", _PyCFunction_CAST(_decimal_Decimal_ln), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_ln__doc__}, + {"ln", _PyCFunction_CAST(_decimal_Decimal_ln), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_ln__doc__}, static PyObject * -_decimal_Decimal_ln_impl(PyObject *self, PyObject *context); +_decimal_Decimal_ln_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_ln(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_ln(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1071,7 +1362,7 @@ _decimal_Decimal_ln(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyO } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_ln_impl(self, context); + return_value = _decimal_Decimal_ln_impl(self, cls, context); exit: return return_value; @@ -1087,13 +1378,14 @@ PyDoc_STRVAR(_decimal_Decimal_log10__doc__, "correctly rounded."); #define _DECIMAL_DECIMAL_LOG10_METHODDEF \ - {"log10", _PyCFunction_CAST(_decimal_Decimal_log10), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_log10__doc__}, + {"log10", _PyCFunction_CAST(_decimal_Decimal_log10), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_log10__doc__}, static PyObject * -_decimal_Decimal_log10_impl(PyObject *self, PyObject *context); +_decimal_Decimal_log10_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_log10(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_log10(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1137,7 +1429,7 @@ _decimal_Decimal_log10(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_log10_impl(self, context); + return_value = _decimal_Decimal_log10_impl(self, cls, context); exit: return return_value; @@ -1150,13 +1442,14 @@ PyDoc_STRVAR(_decimal_Decimal_next_minus__doc__, "Returns the largest representable number smaller than itself."); #define _DECIMAL_DECIMAL_NEXT_MINUS_METHODDEF \ - {"next_minus", _PyCFunction_CAST(_decimal_Decimal_next_minus), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_minus__doc__}, + {"next_minus", _PyCFunction_CAST(_decimal_Decimal_next_minus), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_minus__doc__}, static PyObject * -_decimal_Decimal_next_minus_impl(PyObject *self, PyObject *context); +_decimal_Decimal_next_minus_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_next_minus(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_next_minus(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1200,7 +1493,7 @@ _decimal_Decimal_next_minus(PyObject *self, PyObject *const *args, Py_ssize_t na } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_next_minus_impl(self, context); + return_value = _decimal_Decimal_next_minus_impl(self, cls, context); exit: return return_value; @@ -1213,13 +1506,14 @@ PyDoc_STRVAR(_decimal_Decimal_next_plus__doc__, "Returns the smallest representable number larger than itself."); #define _DECIMAL_DECIMAL_NEXT_PLUS_METHODDEF \ - {"next_plus", _PyCFunction_CAST(_decimal_Decimal_next_plus), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_plus__doc__}, + {"next_plus", _PyCFunction_CAST(_decimal_Decimal_next_plus), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_plus__doc__}, static PyObject * -_decimal_Decimal_next_plus_impl(PyObject *self, PyObject *context); +_decimal_Decimal_next_plus_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_next_plus(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_next_plus(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1263,7 +1557,7 @@ _decimal_Decimal_next_plus(PyObject *self, PyObject *const *args, Py_ssize_t nar } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_next_plus_impl(self, context); + return_value = _decimal_Decimal_next_plus_impl(self, cls, context); exit: return return_value; @@ -1281,13 +1575,14 @@ PyDoc_STRVAR(_decimal_Decimal_normalize__doc__, "the equivalent value Decimal(\'32.1\')."); #define _DECIMAL_DECIMAL_NORMALIZE_METHODDEF \ - {"normalize", _PyCFunction_CAST(_decimal_Decimal_normalize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_normalize__doc__}, + {"normalize", _PyCFunction_CAST(_decimal_Decimal_normalize), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_normalize__doc__}, static PyObject * -_decimal_Decimal_normalize_impl(PyObject *self, PyObject *context); +_decimal_Decimal_normalize_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_normalize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_normalize(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1331,7 +1626,7 @@ _decimal_Decimal_normalize(PyObject *self, PyObject *const *args, Py_ssize_t nar } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_normalize_impl(self, context); + return_value = _decimal_Decimal_normalize_impl(self, cls, context); exit: return return_value; @@ -1346,13 +1641,14 @@ PyDoc_STRVAR(_decimal_Decimal_sqrt__doc__, "The result is correctly rounded using the ROUND_HALF_EVEN rounding mode."); #define _DECIMAL_DECIMAL_SQRT_METHODDEF \ - {"sqrt", _PyCFunction_CAST(_decimal_Decimal_sqrt), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_sqrt__doc__}, + {"sqrt", _PyCFunction_CAST(_decimal_Decimal_sqrt), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_sqrt__doc__}, static PyObject * -_decimal_Decimal_sqrt_impl(PyObject *self, PyObject *context); +_decimal_Decimal_sqrt_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_sqrt(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_sqrt(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1396,7 +1692,7 @@ _decimal_Decimal_sqrt(PyObject *self, PyObject *const *args, Py_ssize_t nargs, P } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_sqrt_impl(self, context); + return_value = _decimal_Decimal_sqrt_impl(self, cls, context); exit: return return_value; @@ -1416,14 +1712,14 @@ PyDoc_STRVAR(_decimal_Decimal_compare__doc__, " a > b ==> Decimal(\'1\')"); #define _DECIMAL_DECIMAL_COMPARE_METHODDEF \ - {"compare", _PyCFunction_CAST(_decimal_Decimal_compare), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare__doc__}, + {"compare", _PyCFunction_CAST(_decimal_Decimal_compare), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare__doc__}, static PyObject * -_decimal_Decimal_compare_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_compare_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_compare(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_compare(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1469,7 +1765,7 @@ _decimal_Decimal_compare(PyObject *self, PyObject *const *args, Py_ssize_t nargs } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_compare_impl(self, other, context); + return_value = _decimal_Decimal_compare_impl(self, cls, other, context); exit: return return_value; @@ -1482,14 +1778,14 @@ PyDoc_STRVAR(_decimal_Decimal_compare_signal__doc__, "Identical to compare, except that all NaNs signal."); #define _DECIMAL_DECIMAL_COMPARE_SIGNAL_METHODDEF \ - {"compare_signal", _PyCFunction_CAST(_decimal_Decimal_compare_signal), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_signal__doc__}, + {"compare_signal", _PyCFunction_CAST(_decimal_Decimal_compare_signal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_signal__doc__}, static PyObject * -_decimal_Decimal_compare_signal_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_compare_signal_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_compare_signal(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_compare_signal(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1535,7 +1831,7 @@ _decimal_Decimal_compare_signal(PyObject *self, PyObject *const *args, Py_ssize_ } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_compare_signal_impl(self, other, context); + return_value = _decimal_Decimal_compare_signal_impl(self, cls, other, context); exit: return return_value; @@ -1551,13 +1847,14 @@ PyDoc_STRVAR(_decimal_Decimal_max__doc__, "operand is returned."); #define _DECIMAL_DECIMAL_MAX_METHODDEF \ - {"max", _PyCFunction_CAST(_decimal_Decimal_max), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max__doc__}, + {"max", _PyCFunction_CAST(_decimal_Decimal_max), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max__doc__}, static PyObject * -_decimal_Decimal_max_impl(PyObject *self, PyObject *other, PyObject *context); +_decimal_Decimal_max_impl(PyObject *self, PyTypeObject *cls, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_max(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1603,7 +1900,7 @@ _decimal_Decimal_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_max_impl(self, other, context); + return_value = _decimal_Decimal_max_impl(self, cls, other, context); exit: return return_value; @@ -1616,14 +1913,14 @@ PyDoc_STRVAR(_decimal_Decimal_max_mag__doc__, "As the max() method, but compares the absolute values of the operands."); #define _DECIMAL_DECIMAL_MAX_MAG_METHODDEF \ - {"max_mag", _PyCFunction_CAST(_decimal_Decimal_max_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max_mag__doc__}, + {"max_mag", _PyCFunction_CAST(_decimal_Decimal_max_mag), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_max_mag__doc__}, static PyObject * -_decimal_Decimal_max_mag_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_max_mag_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_max_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_max_mag(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1669,7 +1966,7 @@ _decimal_Decimal_max_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_max_mag_impl(self, other, context); + return_value = _decimal_Decimal_max_mag_impl(self, cls, other, context); exit: return return_value; @@ -1685,13 +1982,14 @@ PyDoc_STRVAR(_decimal_Decimal_min__doc__, "operand is returned."); #define _DECIMAL_DECIMAL_MIN_METHODDEF \ - {"min", _PyCFunction_CAST(_decimal_Decimal_min), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min__doc__}, + {"min", _PyCFunction_CAST(_decimal_Decimal_min), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min__doc__}, static PyObject * -_decimal_Decimal_min_impl(PyObject *self, PyObject *other, PyObject *context); +_decimal_Decimal_min_impl(PyObject *self, PyTypeObject *cls, PyObject *other, + PyObject *context); static PyObject * -_decimal_Decimal_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_min(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1737,7 +2035,7 @@ _decimal_Decimal_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_min_impl(self, other, context); + return_value = _decimal_Decimal_min_impl(self, cls, other, context); exit: return return_value; @@ -1750,14 +2048,14 @@ PyDoc_STRVAR(_decimal_Decimal_min_mag__doc__, "As the min() method, but compares the absolute values of the operands."); #define _DECIMAL_DECIMAL_MIN_MAG_METHODDEF \ - {"min_mag", _PyCFunction_CAST(_decimal_Decimal_min_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min_mag__doc__}, + {"min_mag", _PyCFunction_CAST(_decimal_Decimal_min_mag), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_min_mag__doc__}, static PyObject * -_decimal_Decimal_min_mag_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_min_mag_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_min_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_min_mag(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1803,7 +2101,7 @@ _decimal_Decimal_min_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_min_mag_impl(self, other, context); + return_value = _decimal_Decimal_min_mag_impl(self, cls, other, context); exit: return return_value; @@ -1821,14 +2119,14 @@ PyDoc_STRVAR(_decimal_Decimal_next_toward__doc__, "to be the same as the sign of the second operand."); #define _DECIMAL_DECIMAL_NEXT_TOWARD_METHODDEF \ - {"next_toward", _PyCFunction_CAST(_decimal_Decimal_next_toward), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_toward__doc__}, + {"next_toward", _PyCFunction_CAST(_decimal_Decimal_next_toward), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_next_toward__doc__}, static PyObject * -_decimal_Decimal_next_toward_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_next_toward_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_next_toward(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_next_toward(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1874,7 +2172,7 @@ _decimal_Decimal_next_toward(PyObject *self, PyObject *const *args, Py_ssize_t n } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_next_toward_impl(self, other, context); + return_value = _decimal_Decimal_next_toward_impl(self, cls, other, context); exit: return return_value; @@ -1895,14 +2193,14 @@ PyDoc_STRVAR(_decimal_Decimal_remainder_near__doc__, "If the result is zero then its sign will be the sign of self."); #define _DECIMAL_DECIMAL_REMAINDER_NEAR_METHODDEF \ - {"remainder_near", _PyCFunction_CAST(_decimal_Decimal_remainder_near), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_remainder_near__doc__}, + {"remainder_near", _PyCFunction_CAST(_decimal_Decimal_remainder_near), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_remainder_near__doc__}, static PyObject * -_decimal_Decimal_remainder_near_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_remainder_near_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_remainder_near(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_remainder_near(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -1948,7 +2246,7 @@ _decimal_Decimal_remainder_near(PyObject *self, PyObject *const *args, Py_ssize_ } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_remainder_near_impl(self, other, context); + return_value = _decimal_Decimal_remainder_near_impl(self, cls, other, context); exit: return return_value; @@ -1967,14 +2265,14 @@ PyDoc_STRVAR(_decimal_Decimal_fma__doc__, " Decimal(\'11\')"); #define _DECIMAL_DECIMAL_FMA_METHODDEF \ - {"fma", _PyCFunction_CAST(_decimal_Decimal_fma), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_fma__doc__}, + {"fma", _PyCFunction_CAST(_decimal_Decimal_fma), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_fma__doc__}, static PyObject * -_decimal_Decimal_fma_impl(PyObject *self, PyObject *other, PyObject *third, - PyObject *context); +_decimal_Decimal_fma_impl(PyObject *self, PyTypeObject *cls, PyObject *other, + PyObject *third, PyObject *context); static PyObject * -_decimal_Decimal_fma(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_fma(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2022,7 +2320,7 @@ _decimal_Decimal_fma(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py } context = args[2]; skip_optional_pos: - return_value = _decimal_Decimal_fma_impl(self, other, third, context); + return_value = _decimal_Decimal_fma_impl(self, cls, other, third, context); exit: return return_value; @@ -2186,13 +2484,14 @@ PyDoc_STRVAR(_decimal_Decimal_is_normal__doc__, "Normal number is a finite nonzero number, which is not subnormal."); #define _DECIMAL_DECIMAL_IS_NORMAL_METHODDEF \ - {"is_normal", _PyCFunction_CAST(_decimal_Decimal_is_normal), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_is_normal__doc__}, + {"is_normal", _PyCFunction_CAST(_decimal_Decimal_is_normal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_is_normal__doc__}, static PyObject * -_decimal_Decimal_is_normal_impl(PyObject *self, PyObject *context); +_decimal_Decimal_is_normal_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_is_normal(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_is_normal(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2236,7 +2535,7 @@ _decimal_Decimal_is_normal(PyObject *self, PyObject *const *args, Py_ssize_t nar } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_is_normal_impl(self, context); + return_value = _decimal_Decimal_is_normal_impl(self, cls, context); exit: return return_value; @@ -2252,13 +2551,14 @@ PyDoc_STRVAR(_decimal_Decimal_is_subnormal__doc__, "exponent less than Emin."); #define _DECIMAL_DECIMAL_IS_SUBNORMAL_METHODDEF \ - {"is_subnormal", _PyCFunction_CAST(_decimal_Decimal_is_subnormal), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_is_subnormal__doc__}, + {"is_subnormal", _PyCFunction_CAST(_decimal_Decimal_is_subnormal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_is_subnormal__doc__}, static PyObject * -_decimal_Decimal_is_subnormal_impl(PyObject *self, PyObject *context); +_decimal_Decimal_is_subnormal_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_is_subnormal(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_is_subnormal(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2302,7 +2602,7 @@ _decimal_Decimal_is_subnormal(PyObject *self, PyObject *const *args, Py_ssize_t } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_is_subnormal_impl(self, context); + return_value = _decimal_Decimal_is_subnormal_impl(self, cls, context); exit: return return_value; @@ -2375,15 +2675,19 @@ PyDoc_STRVAR(_decimal_Decimal_radix__doc__, "all its arithmetic. Included for compatibility with the specification."); #define _DECIMAL_DECIMAL_RADIX_METHODDEF \ - {"radix", (PyCFunction)_decimal_Decimal_radix, METH_NOARGS, _decimal_Decimal_radix__doc__}, + {"radix", _PyCFunction_CAST(_decimal_Decimal_radix), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_radix__doc__}, static PyObject * -_decimal_Decimal_radix_impl(PyObject *self); +_decimal_Decimal_radix_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal_radix(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_radix(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_radix_impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "radix() takes no arguments"); + return NULL; + } + return _decimal_Decimal_radix_impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, @@ -2396,15 +2700,19 @@ PyDoc_STRVAR(_decimal_Decimal_copy_abs__doc__, "changed and no rounding is performed."); #define _DECIMAL_DECIMAL_COPY_ABS_METHODDEF \ - {"copy_abs", (PyCFunction)_decimal_Decimal_copy_abs, METH_NOARGS, _decimal_Decimal_copy_abs__doc__}, + {"copy_abs", _PyCFunction_CAST(_decimal_Decimal_copy_abs), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_abs__doc__}, static PyObject * -_decimal_Decimal_copy_abs_impl(PyObject *self); +_decimal_Decimal_copy_abs_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal_copy_abs(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_copy_abs(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_copy_abs_impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy_abs() takes no arguments"); + return NULL; + } + return _decimal_Decimal_copy_abs_impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, @@ -2417,31 +2725,38 @@ PyDoc_STRVAR(_decimal_Decimal_copy_negate__doc__, "changed and no rounding is performed."); #define _DECIMAL_DECIMAL_COPY_NEGATE_METHODDEF \ - {"copy_negate", (PyCFunction)_decimal_Decimal_copy_negate, METH_NOARGS, _decimal_Decimal_copy_negate__doc__}, + {"copy_negate", _PyCFunction_CAST(_decimal_Decimal_copy_negate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_negate__doc__}, static PyObject * -_decimal_Decimal_copy_negate_impl(PyObject *self); +_decimal_Decimal_copy_negate_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal_copy_negate(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal_copy_negate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal_copy_negate_impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy_negate() takes no arguments"); + return NULL; + } + return _decimal_Decimal_copy_negate_impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal_logical_invert__doc__, "logical_invert($self, /, context=None)\n" "--\n" "\n" -"Return the digit-wise inversion of the (logical) operand."); +"Invert all its digits.\n" +"\n" +"The self must be logical number."); #define _DECIMAL_DECIMAL_LOGICAL_INVERT_METHODDEF \ - {"logical_invert", _PyCFunction_CAST(_decimal_Decimal_logical_invert), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_invert__doc__}, + {"logical_invert", _PyCFunction_CAST(_decimal_Decimal_logical_invert), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_invert__doc__}, static PyObject * -_decimal_Decimal_logical_invert_impl(PyObject *self, PyObject *context); +_decimal_Decimal_logical_invert_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_logical_invert(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_logical_invert(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2485,7 +2800,7 @@ _decimal_Decimal_logical_invert(PyObject *self, PyObject *const *args, Py_ssize_ } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_logical_invert_impl(self, context); + return_value = _decimal_Decimal_logical_invert_impl(self, cls, context); exit: return return_value; @@ -2502,13 +2817,14 @@ PyDoc_STRVAR(_decimal_Decimal_logb__doc__, "Decimal(\'Infinity\') is returned."); #define _DECIMAL_DECIMAL_LOGB_METHODDEF \ - {"logb", _PyCFunction_CAST(_decimal_Decimal_logb), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logb__doc__}, + {"logb", _PyCFunction_CAST(_decimal_Decimal_logb), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logb__doc__}, static PyObject * -_decimal_Decimal_logb_impl(PyObject *self, PyObject *context); +_decimal_Decimal_logb_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_logb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_logb(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2552,7 +2868,7 @@ _decimal_Decimal_logb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, P } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_logb_impl(self, context); + return_value = _decimal_Decimal_logb_impl(self, cls, context); exit: return return_value; @@ -2582,13 +2898,14 @@ PyDoc_STRVAR(_decimal_Decimal_number_class__doc__, " * \'sNaN\', indicating that the operand is a signaling NaN."); #define _DECIMAL_DECIMAL_NUMBER_CLASS_METHODDEF \ - {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, + {"number_class", _PyCFunction_CAST(_decimal_Decimal_number_class), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_number_class__doc__}, static PyObject * -_decimal_Decimal_number_class_impl(PyObject *self, PyObject *context); +_decimal_Decimal_number_class_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_number_class(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2632,7 +2949,7 @@ _decimal_Decimal_number_class(PyObject *self, PyObject *const *args, Py_ssize_t } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_number_class_impl(self, context); + return_value = _decimal_Decimal_number_class_impl(self, cls, context); exit: return return_value; @@ -2653,13 +2970,14 @@ PyDoc_STRVAR(_decimal_Decimal_to_eng_string__doc__, "operation."); #define _DECIMAL_DECIMAL_TO_ENG_STRING_METHODDEF \ - {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, + {"to_eng_string", _PyCFunction_CAST(_decimal_Decimal_to_eng_string), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_to_eng_string__doc__}, static PyObject * -_decimal_Decimal_to_eng_string_impl(PyObject *self, PyObject *context); +_decimal_Decimal_to_eng_string_impl(PyObject *self, PyTypeObject *cls, + PyObject *context); static PyObject * -_decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_to_eng_string(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2703,7 +3021,7 @@ _decimal_Decimal_to_eng_string(PyObject *self, PyObject *const *args, Py_ssize_t } context = args[0]; skip_optional_pos: - return_value = _decimal_Decimal_to_eng_string_impl(self, context); + return_value = _decimal_Decimal_to_eng_string_impl(self, cls, context); exit: return return_value; @@ -2736,14 +3054,14 @@ PyDoc_STRVAR(_decimal_Decimal_compare_total__doc__, "exactly."); #define _DECIMAL_DECIMAL_COMPARE_TOTAL_METHODDEF \ - {"compare_total", _PyCFunction_CAST(_decimal_Decimal_compare_total), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total__doc__}, + {"compare_total", _PyCFunction_CAST(_decimal_Decimal_compare_total), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total__doc__}, static PyObject * -_decimal_Decimal_compare_total_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_compare_total_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_compare_total(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_compare_total(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2789,7 +3107,7 @@ _decimal_Decimal_compare_total(PyObject *self, PyObject *const *args, Py_ssize_t } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_compare_total_impl(self, other, context); + return_value = _decimal_Decimal_compare_total_impl(self, cls, other, context); exit: return return_value; @@ -2810,14 +3128,14 @@ PyDoc_STRVAR(_decimal_Decimal_compare_total_mag__doc__, "exactly."); #define _DECIMAL_DECIMAL_COMPARE_TOTAL_MAG_METHODDEF \ - {"compare_total_mag", _PyCFunction_CAST(_decimal_Decimal_compare_total_mag), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total_mag__doc__}, + {"compare_total_mag", _PyCFunction_CAST(_decimal_Decimal_compare_total_mag), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_compare_total_mag__doc__}, static PyObject * -_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_compare_total_mag_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_compare_total_mag(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_compare_total_mag(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2863,7 +3181,7 @@ _decimal_Decimal_compare_total_mag(PyObject *self, PyObject *const *args, Py_ssi } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_compare_total_mag_impl(self, other, context); + return_value = _decimal_Decimal_compare_total_mag_impl(self, cls, other, context); exit: return return_value; @@ -2886,14 +3204,14 @@ PyDoc_STRVAR(_decimal_Decimal_copy_sign__doc__, "exactly."); #define _DECIMAL_DECIMAL_COPY_SIGN_METHODDEF \ - {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, + {"copy_sign", _PyCFunction_CAST(_decimal_Decimal_copy_sign), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_copy_sign__doc__}, static PyObject * -_decimal_Decimal_copy_sign_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_copy_sign_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_copy_sign(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -2939,7 +3257,7 @@ _decimal_Decimal_copy_sign(PyObject *self, PyObject *const *args, Py_ssize_t nar } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_copy_sign_impl(self, other, context); + return_value = _decimal_Decimal_copy_sign_impl(self, cls, other, context); exit: return return_value; @@ -2957,14 +3275,14 @@ PyDoc_STRVAR(_decimal_Decimal_same_quantum__doc__, "exactly."); #define _DECIMAL_DECIMAL_SAME_QUANTUM_METHODDEF \ - {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, + {"same_quantum", _PyCFunction_CAST(_decimal_Decimal_same_quantum), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_same_quantum__doc__}, static PyObject * -_decimal_Decimal_same_quantum_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_same_quantum_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_same_quantum(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3010,7 +3328,7 @@ _decimal_Decimal_same_quantum(PyObject *self, PyObject *const *args, Py_ssize_t } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_same_quantum_impl(self, other, context); + return_value = _decimal_Decimal_same_quantum_impl(self, cls, other, context); exit: return return_value; @@ -3020,17 +3338,19 @@ PyDoc_STRVAR(_decimal_Decimal_logical_and__doc__, "logical_and($self, /, other, context=None)\n" "--\n" "\n" -"Return the digit-wise \'and\' of the two (logical) operands."); +"Applies an \'and\' operation between self and other\'s digits.\n" +"\n" +"Both self and other must be logical numbers."); #define _DECIMAL_DECIMAL_LOGICAL_AND_METHODDEF \ - {"logical_and", _PyCFunction_CAST(_decimal_Decimal_logical_and), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_and__doc__}, + {"logical_and", _PyCFunction_CAST(_decimal_Decimal_logical_and), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_and__doc__}, static PyObject * -_decimal_Decimal_logical_and_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_logical_and_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_logical_and(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_logical_and(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3076,7 +3396,7 @@ _decimal_Decimal_logical_and(PyObject *self, PyObject *const *args, Py_ssize_t n } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_logical_and_impl(self, other, context); + return_value = _decimal_Decimal_logical_and_impl(self, cls, other, context); exit: return return_value; @@ -3086,17 +3406,19 @@ PyDoc_STRVAR(_decimal_Decimal_logical_or__doc__, "logical_or($self, /, other, context=None)\n" "--\n" "\n" -"Return the digit-wise \'or\' of the two (logical) operands."); +"Applies an \'or\' operation between self and other\'s digits.\n" +"\n" +"Both self and other must be logical numbers."); #define _DECIMAL_DECIMAL_LOGICAL_OR_METHODDEF \ - {"logical_or", _PyCFunction_CAST(_decimal_Decimal_logical_or), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_or__doc__}, + {"logical_or", _PyCFunction_CAST(_decimal_Decimal_logical_or), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_or__doc__}, static PyObject * -_decimal_Decimal_logical_or_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_logical_or_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_logical_or(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_logical_or(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3142,7 +3464,7 @@ _decimal_Decimal_logical_or(PyObject *self, PyObject *const *args, Py_ssize_t na } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_logical_or_impl(self, other, context); + return_value = _decimal_Decimal_logical_or_impl(self, cls, other, context); exit: return return_value; @@ -3152,17 +3474,19 @@ PyDoc_STRVAR(_decimal_Decimal_logical_xor__doc__, "logical_xor($self, /, other, context=None)\n" "--\n" "\n" -"Return the digit-wise \'xor\' of the two (logical) operands."); +"Applies an \'xor\' operation between self and other\'s digits.\n" +"\n" +"Both self and other must be logical numbers."); #define _DECIMAL_DECIMAL_LOGICAL_XOR_METHODDEF \ - {"logical_xor", _PyCFunction_CAST(_decimal_Decimal_logical_xor), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_xor__doc__}, + {"logical_xor", _PyCFunction_CAST(_decimal_Decimal_logical_xor), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_logical_xor__doc__}, static PyObject * -_decimal_Decimal_logical_xor_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_logical_xor_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_logical_xor(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_logical_xor(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3208,7 +3532,7 @@ _decimal_Decimal_logical_xor(PyObject *self, PyObject *const *args, Py_ssize_t n } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_logical_xor_impl(self, other, context); + return_value = _decimal_Decimal_logical_xor_impl(self, cls, other, context); exit: return return_value; @@ -3228,14 +3552,14 @@ PyDoc_STRVAR(_decimal_Decimal_rotate__doc__, "necessary. The sign and exponent of the first operand are unchanged."); #define _DECIMAL_DECIMAL_ROTATE_METHODDEF \ - {"rotate", _PyCFunction_CAST(_decimal_Decimal_rotate), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_rotate__doc__}, + {"rotate", _PyCFunction_CAST(_decimal_Decimal_rotate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_rotate__doc__}, static PyObject * -_decimal_Decimal_rotate_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_rotate_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_rotate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_rotate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3281,7 +3605,7 @@ _decimal_Decimal_rotate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_rotate_impl(self, other, context); + return_value = _decimal_Decimal_rotate_impl(self, cls, other, context); exit: return return_value; @@ -3297,14 +3621,14 @@ PyDoc_STRVAR(_decimal_Decimal_scaleb__doc__, "second operand must be an integer."); #define _DECIMAL_DECIMAL_SCALEB_METHODDEF \ - {"scaleb", _PyCFunction_CAST(_decimal_Decimal_scaleb), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_scaleb__doc__}, + {"scaleb", _PyCFunction_CAST(_decimal_Decimal_scaleb), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_scaleb__doc__}, static PyObject * -_decimal_Decimal_scaleb_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_scaleb_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_scaleb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_scaleb(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3350,7 +3674,7 @@ _decimal_Decimal_scaleb(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_scaleb_impl(self, other, context); + return_value = _decimal_Decimal_scaleb_impl(self, cls, other, context); exit: return return_value; @@ -3370,14 +3694,14 @@ PyDoc_STRVAR(_decimal_Decimal_shift__doc__, "operand are unchanged."); #define _DECIMAL_DECIMAL_SHIFT_METHODDEF \ - {"shift", _PyCFunction_CAST(_decimal_Decimal_shift), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_shift__doc__}, + {"shift", _PyCFunction_CAST(_decimal_Decimal_shift), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_shift__doc__}, static PyObject * -_decimal_Decimal_shift_impl(PyObject *self, PyObject *other, - PyObject *context); +_decimal_Decimal_shift_impl(PyObject *self, PyTypeObject *cls, + PyObject *other, PyObject *context); static PyObject * -_decimal_Decimal_shift(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_shift(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3423,7 +3747,7 @@ _decimal_Decimal_shift(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } context = args[1]; skip_optional_pos: - return_value = _decimal_Decimal_shift_impl(self, other, context); + return_value = _decimal_Decimal_shift_impl(self, cls, other, context); exit: return return_value; @@ -3457,14 +3781,15 @@ PyDoc_STRVAR(_decimal_Decimal_quantize__doc__, "current thread\'s context is used."); #define _DECIMAL_DECIMAL_QUANTIZE_METHODDEF \ - {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, + {"quantize", _PyCFunction_CAST(_decimal_Decimal_quantize), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal_quantize__doc__}, static PyObject * -_decimal_Decimal_quantize_impl(PyObject *self, PyObject *w, - PyObject *rounding, PyObject *context); +_decimal_Decimal_quantize_impl(PyObject *self, PyTypeObject *cls, + PyObject *w, PyObject *rounding, + PyObject *context); static PyObject * -_decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Decimal_quantize(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -3517,7 +3842,7 @@ _decimal_Decimal_quantize(PyObject *self, PyObject *const *args, Py_ssize_t narg } context = args[2]; skip_optional_pos: - return_value = _decimal_Decimal_quantize_impl(self, w, rounding, context); + return_value = _decimal_Decimal_quantize_impl(self, cls, w, rounding, context); exit: return return_value; @@ -3530,15 +3855,19 @@ PyDoc_STRVAR(_decimal_Decimal___ceil____doc__, "Return the ceiling as an Integral."); #define _DECIMAL_DECIMAL___CEIL___METHODDEF \ - {"__ceil__", (PyCFunction)_decimal_Decimal___ceil__, METH_NOARGS, _decimal_Decimal___ceil____doc__}, + {"__ceil__", _PyCFunction_CAST(_decimal_Decimal___ceil__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal___ceil____doc__}, static PyObject * -_decimal_Decimal___ceil___impl(PyObject *self); +_decimal_Decimal___ceil___impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal___ceil__(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal___ceil__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal___ceil___impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__ceil__() takes no arguments"); + return NULL; + } + return _decimal_Decimal___ceil___impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal___complex____doc__, @@ -3591,15 +3920,19 @@ PyDoc_STRVAR(_decimal_Decimal___floor____doc__, "Return the floor as an Integral."); #define _DECIMAL_DECIMAL___FLOOR___METHODDEF \ - {"__floor__", (PyCFunction)_decimal_Decimal___floor__, METH_NOARGS, _decimal_Decimal___floor____doc__}, + {"__floor__", _PyCFunction_CAST(_decimal_Decimal___floor__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal___floor____doc__}, static PyObject * -_decimal_Decimal___floor___impl(PyObject *self); +_decimal_Decimal___floor___impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal___floor__(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal___floor__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal___floor___impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__floor__() takes no arguments"); + return NULL; + } + return _decimal_Decimal___floor___impl(self, cls); } PyDoc_STRVAR(_decimal_Decimal___reduce____doc__, @@ -3645,15 +3978,19 @@ PyDoc_STRVAR(_decimal_Decimal___trunc____doc__, "Return the Integral closest to x between 0 and x."); #define _DECIMAL_DECIMAL___TRUNC___METHODDEF \ - {"__trunc__", (PyCFunction)_decimal_Decimal___trunc__, METH_NOARGS, _decimal_Decimal___trunc____doc__}, + {"__trunc__", _PyCFunction_CAST(_decimal_Decimal___trunc__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Decimal___trunc____doc__}, static PyObject * -_decimal_Decimal___trunc___impl(PyObject *self); +_decimal_Decimal___trunc___impl(PyObject *self, PyTypeObject *cls); static PyObject * -_decimal_Decimal___trunc__(PyObject *self, PyObject *Py_UNUSED(ignored)) +_decimal_Decimal___trunc__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Decimal___trunc___impl(self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__trunc__() takes no arguments"); + return NULL; + } + return _decimal_Decimal___trunc___impl(self, cls); } PyDoc_STRVAR(_decimal_Context_abs__doc__, @@ -3663,7 +4000,42 @@ PyDoc_STRVAR(_decimal_Context_abs__doc__, "Return the absolute value of x."); #define _DECIMAL_CONTEXT_ABS_METHODDEF \ - {"abs", (PyCFunction)_decimal_Context_abs, METH_O, _decimal_Context_abs__doc__}, + {"abs", _PyCFunction_CAST(_decimal_Context_abs), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_abs__doc__}, + +static PyObject * +_decimal_Context_abs_impl(PyObject *context, PyTypeObject *cls, PyObject *x); + +static PyObject * +_decimal_Context_abs(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "abs", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_abs_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_exp__doc__, "exp($self, x, /)\n" @@ -3672,7 +4044,42 @@ PyDoc_STRVAR(_decimal_Context_exp__doc__, "Return e ** x."); #define _DECIMAL_CONTEXT_EXP_METHODDEF \ - {"exp", (PyCFunction)_decimal_Context_exp, METH_O, _decimal_Context_exp__doc__}, + {"exp", _PyCFunction_CAST(_decimal_Context_exp), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_exp__doc__}, + +static PyObject * +_decimal_Context_exp_impl(PyObject *context, PyTypeObject *cls, PyObject *x); + +static PyObject * +_decimal_Context_exp(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "exp", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_exp_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_ln__doc__, "ln($self, x, /)\n" @@ -3681,7 +4088,42 @@ PyDoc_STRVAR(_decimal_Context_ln__doc__, "Return the natural (base e) logarithm of x."); #define _DECIMAL_CONTEXT_LN_METHODDEF \ - {"ln", (PyCFunction)_decimal_Context_ln, METH_O, _decimal_Context_ln__doc__}, + {"ln", _PyCFunction_CAST(_decimal_Context_ln), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_ln__doc__}, + +static PyObject * +_decimal_Context_ln_impl(PyObject *context, PyTypeObject *cls, PyObject *x); + +static PyObject * +_decimal_Context_ln(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "ln", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_ln_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_log10__doc__, "log10($self, x, /)\n" @@ -3690,7 +4132,43 @@ PyDoc_STRVAR(_decimal_Context_log10__doc__, "Return the base 10 logarithm of x."); #define _DECIMAL_CONTEXT_LOG10_METHODDEF \ - {"log10", (PyCFunction)_decimal_Context_log10, METH_O, _decimal_Context_log10__doc__}, + {"log10", _PyCFunction_CAST(_decimal_Context_log10), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_log10__doc__}, + +static PyObject * +_decimal_Context_log10_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_log10(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "log10", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_log10_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_minus__doc__, "minus($self, x, /)\n" @@ -3701,7 +4179,43 @@ PyDoc_STRVAR(_decimal_Context_minus__doc__, "This operation applies the context to the result."); #define _DECIMAL_CONTEXT_MINUS_METHODDEF \ - {"minus", (PyCFunction)_decimal_Context_minus, METH_O, _decimal_Context_minus__doc__}, + {"minus", _PyCFunction_CAST(_decimal_Context_minus), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_minus__doc__}, + +static PyObject * +_decimal_Context_minus_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_minus(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "minus", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_minus_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_next_minus__doc__, "next_minus($self, x, /)\n" @@ -3710,7 +4224,43 @@ PyDoc_STRVAR(_decimal_Context_next_minus__doc__, "Return the largest representable number smaller than x."); #define _DECIMAL_CONTEXT_NEXT_MINUS_METHODDEF \ - {"next_minus", (PyCFunction)_decimal_Context_next_minus, METH_O, _decimal_Context_next_minus__doc__}, + {"next_minus", _PyCFunction_CAST(_decimal_Context_next_minus), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_next_minus__doc__}, + +static PyObject * +_decimal_Context_next_minus_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_next_minus(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "next_minus", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_next_minus_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_next_plus__doc__, "next_plus($self, x, /)\n" @@ -3719,7 +4269,43 @@ PyDoc_STRVAR(_decimal_Context_next_plus__doc__, "Return the smallest representable number larger than x."); #define _DECIMAL_CONTEXT_NEXT_PLUS_METHODDEF \ - {"next_plus", (PyCFunction)_decimal_Context_next_plus, METH_O, _decimal_Context_next_plus__doc__}, + {"next_plus", _PyCFunction_CAST(_decimal_Context_next_plus), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_next_plus__doc__}, + +static PyObject * +_decimal_Context_next_plus_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_next_plus(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "next_plus", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_next_plus_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_normalize__doc__, "normalize($self, x, /)\n" @@ -3728,7 +4314,43 @@ PyDoc_STRVAR(_decimal_Context_normalize__doc__, "Reduce x to its simplest form. Alias for reduce(x)."); #define _DECIMAL_CONTEXT_NORMALIZE_METHODDEF \ - {"normalize", (PyCFunction)_decimal_Context_normalize, METH_O, _decimal_Context_normalize__doc__}, + {"normalize", _PyCFunction_CAST(_decimal_Context_normalize), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_normalize__doc__}, + +static PyObject * +_decimal_Context_normalize_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_normalize(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "normalize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_normalize_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_plus__doc__, "plus($self, x, /)\n" @@ -3739,7 +4361,42 @@ PyDoc_STRVAR(_decimal_Context_plus__doc__, "This operation applies the context to the result."); #define _DECIMAL_CONTEXT_PLUS_METHODDEF \ - {"plus", (PyCFunction)_decimal_Context_plus, METH_O, _decimal_Context_plus__doc__}, + {"plus", _PyCFunction_CAST(_decimal_Context_plus), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_plus__doc__}, + +static PyObject * +_decimal_Context_plus_impl(PyObject *context, PyTypeObject *cls, PyObject *x); + +static PyObject * +_decimal_Context_plus(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "plus", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_plus_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_to_integral_value__doc__, "to_integral_value($self, x, /)\n" @@ -3748,7 +4405,43 @@ PyDoc_STRVAR(_decimal_Context_to_integral_value__doc__, "Round to an integer."); #define _DECIMAL_CONTEXT_TO_INTEGRAL_VALUE_METHODDEF \ - {"to_integral_value", (PyCFunction)_decimal_Context_to_integral_value, METH_O, _decimal_Context_to_integral_value__doc__}, + {"to_integral_value", _PyCFunction_CAST(_decimal_Context_to_integral_value), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_to_integral_value__doc__}, + +static PyObject * +_decimal_Context_to_integral_value_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_to_integral_value(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_integral_value", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_to_integral_value_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_to_integral_exact__doc__, "to_integral_exact($self, x, /)\n" @@ -3757,7 +4450,43 @@ PyDoc_STRVAR(_decimal_Context_to_integral_exact__doc__, "Round to an integer. Signal if the result is rounded or inexact."); #define _DECIMAL_CONTEXT_TO_INTEGRAL_EXACT_METHODDEF \ - {"to_integral_exact", (PyCFunction)_decimal_Context_to_integral_exact, METH_O, _decimal_Context_to_integral_exact__doc__}, + {"to_integral_exact", _PyCFunction_CAST(_decimal_Context_to_integral_exact), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_to_integral_exact__doc__}, + +static PyObject * +_decimal_Context_to_integral_exact_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_to_integral_exact(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_integral_exact", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_to_integral_exact_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_to_integral__doc__, "to_integral($self, x, /)\n" @@ -3766,7 +4495,43 @@ PyDoc_STRVAR(_decimal_Context_to_integral__doc__, "Identical to to_integral_value(x)."); #define _DECIMAL_CONTEXT_TO_INTEGRAL_METHODDEF \ - {"to_integral", (PyCFunction)_decimal_Context_to_integral, METH_O, _decimal_Context_to_integral__doc__}, + {"to_integral", _PyCFunction_CAST(_decimal_Context_to_integral), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_to_integral__doc__}, + +static PyObject * +_decimal_Context_to_integral_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_to_integral(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_integral", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_to_integral_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_sqrt__doc__, "sqrt($self, x, /)\n" @@ -3775,7 +4540,42 @@ PyDoc_STRVAR(_decimal_Context_sqrt__doc__, "Square root of a non-negative number to context precision."); #define _DECIMAL_CONTEXT_SQRT_METHODDEF \ - {"sqrt", (PyCFunction)_decimal_Context_sqrt, METH_O, _decimal_Context_sqrt__doc__}, + {"sqrt", _PyCFunction_CAST(_decimal_Context_sqrt), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_sqrt__doc__}, + +static PyObject * +_decimal_Context_sqrt_impl(PyObject *context, PyTypeObject *cls, PyObject *x); + +static PyObject * +_decimal_Context_sqrt(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "sqrt", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_sqrt_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_add__doc__, "add($self, x, y, /)\n" @@ -3784,24 +4584,41 @@ PyDoc_STRVAR(_decimal_Context_add__doc__, "Return the sum of x and y."); #define _DECIMAL_CONTEXT_ADD_METHODDEF \ - {"add", _PyCFunction_CAST(_decimal_Context_add), METH_FASTCALL, _decimal_Context_add__doc__}, + {"add", _PyCFunction_CAST(_decimal_Context_add), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_add__doc__}, static PyObject * -_decimal_Context_add_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_add_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y); static PyObject * -_decimal_Context_add(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_add(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "add", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("add", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_add_impl(context, x, y); + return_value = _decimal_Context_add_impl(context, cls, x, y); exit: return return_value; @@ -3814,24 +4631,41 @@ PyDoc_STRVAR(_decimal_Context_compare__doc__, "Compare x and y numerically."); #define _DECIMAL_CONTEXT_COMPARE_METHODDEF \ - {"compare", _PyCFunction_CAST(_decimal_Context_compare), METH_FASTCALL, _decimal_Context_compare__doc__}, + {"compare", _PyCFunction_CAST(_decimal_Context_compare), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_compare__doc__}, static PyObject * -_decimal_Context_compare_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_compare_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_compare(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_compare(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("compare", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_compare_impl(context, x, y); + return_value = _decimal_Context_compare_impl(context, cls, x, y); exit: return return_value; @@ -3844,25 +4678,41 @@ PyDoc_STRVAR(_decimal_Context_compare_signal__doc__, "Compare x and y numerically. All NaNs signal."); #define _DECIMAL_CONTEXT_COMPARE_SIGNAL_METHODDEF \ - {"compare_signal", _PyCFunction_CAST(_decimal_Context_compare_signal), METH_FASTCALL, _decimal_Context_compare_signal__doc__}, + {"compare_signal", _PyCFunction_CAST(_decimal_Context_compare_signal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_compare_signal__doc__}, static PyObject * -_decimal_Context_compare_signal_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_compare_signal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_compare_signal(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_compare_signal(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare_signal", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("compare_signal", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_compare_signal_impl(context, x, y); + return_value = _decimal_Context_compare_signal_impl(context, cls, x, y); exit: return return_value; @@ -3875,24 +4725,41 @@ PyDoc_STRVAR(_decimal_Context_divide__doc__, "Return x divided by y."); #define _DECIMAL_CONTEXT_DIVIDE_METHODDEF \ - {"divide", _PyCFunction_CAST(_decimal_Context_divide), METH_FASTCALL, _decimal_Context_divide__doc__}, + {"divide", _PyCFunction_CAST(_decimal_Context_divide), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_divide__doc__}, static PyObject * -_decimal_Context_divide_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_divide_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_divide(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_divide(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "divide", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("divide", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_divide_impl(context, x, y); + return_value = _decimal_Context_divide_impl(context, cls, x, y); exit: return return_value; @@ -3905,24 +4772,41 @@ PyDoc_STRVAR(_decimal_Context_divide_int__doc__, "Return x divided by y, truncated to an integer."); #define _DECIMAL_CONTEXT_DIVIDE_INT_METHODDEF \ - {"divide_int", _PyCFunction_CAST(_decimal_Context_divide_int), METH_FASTCALL, _decimal_Context_divide_int__doc__}, + {"divide_int", _PyCFunction_CAST(_decimal_Context_divide_int), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_divide_int__doc__}, static PyObject * -_decimal_Context_divide_int_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_divide_int_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_divide_int(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_divide_int(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "divide_int", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("divide_int", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_divide_int_impl(context, x, y); + return_value = _decimal_Context_divide_int_impl(context, cls, x, y); exit: return return_value; @@ -3935,24 +4819,41 @@ PyDoc_STRVAR(_decimal_Context_max__doc__, "Compare the values numerically and return the maximum."); #define _DECIMAL_CONTEXT_MAX_METHODDEF \ - {"max", _PyCFunction_CAST(_decimal_Context_max), METH_FASTCALL, _decimal_Context_max__doc__}, + {"max", _PyCFunction_CAST(_decimal_Context_max), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_max__doc__}, static PyObject * -_decimal_Context_max_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_max_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y); static PyObject * -_decimal_Context_max(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_max(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "max", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("max", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_max_impl(context, x, y); + return_value = _decimal_Context_max_impl(context, cls, x, y); exit: return return_value; @@ -3965,24 +4866,41 @@ PyDoc_STRVAR(_decimal_Context_max_mag__doc__, "Compare the values numerically with their sign ignored."); #define _DECIMAL_CONTEXT_MAX_MAG_METHODDEF \ - {"max_mag", _PyCFunction_CAST(_decimal_Context_max_mag), METH_FASTCALL, _decimal_Context_max_mag__doc__}, + {"max_mag", _PyCFunction_CAST(_decimal_Context_max_mag), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_max_mag__doc__}, static PyObject * -_decimal_Context_max_mag_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_max_mag_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_max_mag(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_max_mag(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "max_mag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("max_mag", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_max_mag_impl(context, x, y); + return_value = _decimal_Context_max_mag_impl(context, cls, x, y); exit: return return_value; @@ -3995,24 +4913,41 @@ PyDoc_STRVAR(_decimal_Context_min__doc__, "Compare the values numerically and return the minimum."); #define _DECIMAL_CONTEXT_MIN_METHODDEF \ - {"min", _PyCFunction_CAST(_decimal_Context_min), METH_FASTCALL, _decimal_Context_min__doc__}, + {"min", _PyCFunction_CAST(_decimal_Context_min), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_min__doc__}, static PyObject * -_decimal_Context_min_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_min_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y); static PyObject * -_decimal_Context_min(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_min(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "min", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("min", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_min_impl(context, x, y); + return_value = _decimal_Context_min_impl(context, cls, x, y); exit: return return_value; @@ -4025,24 +4960,41 @@ PyDoc_STRVAR(_decimal_Context_min_mag__doc__, "Compare the values numerically with their sign ignored."); #define _DECIMAL_CONTEXT_MIN_MAG_METHODDEF \ - {"min_mag", _PyCFunction_CAST(_decimal_Context_min_mag), METH_FASTCALL, _decimal_Context_min_mag__doc__}, + {"min_mag", _PyCFunction_CAST(_decimal_Context_min_mag), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_min_mag__doc__}, static PyObject * -_decimal_Context_min_mag_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_min_mag_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_min_mag(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_min_mag(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "min_mag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("min_mag", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_min_mag_impl(context, x, y); + return_value = _decimal_Context_min_mag_impl(context, cls, x, y); exit: return return_value; @@ -4055,24 +5007,41 @@ PyDoc_STRVAR(_decimal_Context_multiply__doc__, "Return the product of x and y."); #define _DECIMAL_CONTEXT_MULTIPLY_METHODDEF \ - {"multiply", _PyCFunction_CAST(_decimal_Context_multiply), METH_FASTCALL, _decimal_Context_multiply__doc__}, + {"multiply", _PyCFunction_CAST(_decimal_Context_multiply), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_multiply__doc__}, static PyObject * -_decimal_Context_multiply_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_multiply_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_multiply(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_multiply(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "multiply", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("multiply", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_multiply_impl(context, x, y); + return_value = _decimal_Context_multiply_impl(context, cls, x, y); exit: return return_value; @@ -4085,25 +5054,41 @@ PyDoc_STRVAR(_decimal_Context_next_toward__doc__, "Return the number closest to x, in the direction towards y."); #define _DECIMAL_CONTEXT_NEXT_TOWARD_METHODDEF \ - {"next_toward", _PyCFunction_CAST(_decimal_Context_next_toward), METH_FASTCALL, _decimal_Context_next_toward__doc__}, + {"next_toward", _PyCFunction_CAST(_decimal_Context_next_toward), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_next_toward__doc__}, static PyObject * -_decimal_Context_next_toward_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_next_toward_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_next_toward(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_next_toward(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "next_toward", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("next_toward", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_next_toward_impl(context, x, y); + return_value = _decimal_Context_next_toward_impl(context, cls, x, y); exit: return return_value; @@ -4116,24 +5101,41 @@ PyDoc_STRVAR(_decimal_Context_quantize__doc__, "Return a value equal to x (rounded), having the exponent of y."); #define _DECIMAL_CONTEXT_QUANTIZE_METHODDEF \ - {"quantize", _PyCFunction_CAST(_decimal_Context_quantize), METH_FASTCALL, _decimal_Context_quantize__doc__}, + {"quantize", _PyCFunction_CAST(_decimal_Context_quantize), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_quantize__doc__}, static PyObject * -_decimal_Context_quantize_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_quantize_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_quantize(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_quantize(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "quantize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("quantize", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_quantize_impl(context, x, y); + return_value = _decimal_Context_quantize_impl(context, cls, x, y); exit: return return_value; @@ -4149,24 +5151,41 @@ PyDoc_STRVAR(_decimal_Context_remainder__doc__, "original dividend."); #define _DECIMAL_CONTEXT_REMAINDER_METHODDEF \ - {"remainder", _PyCFunction_CAST(_decimal_Context_remainder), METH_FASTCALL, _decimal_Context_remainder__doc__}, + {"remainder", _PyCFunction_CAST(_decimal_Context_remainder), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_remainder__doc__}, static PyObject * -_decimal_Context_remainder_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_remainder_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_remainder(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_remainder(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "remainder", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("remainder", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_remainder_impl(context, x, y); + return_value = _decimal_Context_remainder_impl(context, cls, x, y); exit: return return_value; @@ -4182,25 +5201,41 @@ PyDoc_STRVAR(_decimal_Context_remainder_near__doc__, "is 0 then its sign will be the sign of x)."); #define _DECIMAL_CONTEXT_REMAINDER_NEAR_METHODDEF \ - {"remainder_near", _PyCFunction_CAST(_decimal_Context_remainder_near), METH_FASTCALL, _decimal_Context_remainder_near__doc__}, + {"remainder_near", _PyCFunction_CAST(_decimal_Context_remainder_near), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_remainder_near__doc__}, static PyObject * -_decimal_Context_remainder_near_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_remainder_near_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_remainder_near(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_remainder_near(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "remainder_near", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("remainder_near", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_remainder_near_impl(context, x, y); + return_value = _decimal_Context_remainder_near_impl(context, cls, x, y); exit: return return_value; @@ -4213,24 +5248,41 @@ PyDoc_STRVAR(_decimal_Context_subtract__doc__, "Return the difference between x and y."); #define _DECIMAL_CONTEXT_SUBTRACT_METHODDEF \ - {"subtract", _PyCFunction_CAST(_decimal_Context_subtract), METH_FASTCALL, _decimal_Context_subtract__doc__}, + {"subtract", _PyCFunction_CAST(_decimal_Context_subtract), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_subtract__doc__}, static PyObject * -_decimal_Context_subtract_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_subtract_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_subtract(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_subtract(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "subtract", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("subtract", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_subtract_impl(context, x, y); + return_value = _decimal_Context_subtract_impl(context, cls, x, y); exit: return return_value; @@ -4287,14 +5339,14 @@ PyDoc_STRVAR(_decimal_Context_power__doc__, " * modulo must be nonzero and less than 10**prec in absolute value"); #define _DECIMAL_CONTEXT_POWER_METHODDEF \ - {"power", _PyCFunction_CAST(_decimal_Context_power), METH_FASTCALL|METH_KEYWORDS, _decimal_Context_power__doc__}, + {"power", _PyCFunction_CAST(_decimal_Context_power), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_power__doc__}, static PyObject * -_decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp, - PyObject *mod); +_decimal_Context_power_impl(PyObject *context, PyTypeObject *cls, + PyObject *base, PyObject *exp, PyObject *mod); static PyObject * -_decimal_Context_power(PyObject *context, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_decimal_Context_power(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -4342,7 +5394,7 @@ _decimal_Context_power(PyObject *context, PyObject *const *args, Py_ssize_t narg } mod = args[2]; skip_optional_pos: - return_value = _decimal_Context_power_impl(context, base, exp, mod); + return_value = _decimal_Context_power_impl(context, cls, base, exp, mod); exit: return return_value; @@ -4355,27 +5407,43 @@ PyDoc_STRVAR(_decimal_Context_fma__doc__, "Return x multiplied by y, plus z."); #define _DECIMAL_CONTEXT_FMA_METHODDEF \ - {"fma", _PyCFunction_CAST(_decimal_Context_fma), METH_FASTCALL, _decimal_Context_fma__doc__}, + {"fma", _PyCFunction_CAST(_decimal_Context_fma), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_fma__doc__}, static PyObject * -_decimal_Context_fma_impl(PyObject *context, PyObject *x, PyObject *y, - PyObject *z); +_decimal_Context_fma_impl(PyObject *context, PyTypeObject *cls, PyObject *x, + PyObject *y, PyObject *z); static PyObject * -_decimal_Context_fma(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_fma(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fma", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; PyObject *x; PyObject *y; PyObject *z; - if (!_PyArg_CheckPositional("fma", nargs, 3, 3)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; z = args[2]; - return_value = _decimal_Context_fma_impl(context, x, y, z); + return_value = _decimal_Context_fma_impl(context, cls, x, y, z); exit: return return_value; @@ -4388,15 +5456,19 @@ PyDoc_STRVAR(_decimal_Context_radix__doc__, "Return 10."); #define _DECIMAL_CONTEXT_RADIX_METHODDEF \ - {"radix", (PyCFunction)_decimal_Context_radix, METH_NOARGS, _decimal_Context_radix__doc__}, + {"radix", _PyCFunction_CAST(_decimal_Context_radix), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_radix__doc__}, static PyObject * -_decimal_Context_radix_impl(PyObject *context); +_decimal_Context_radix_impl(PyObject *context, PyTypeObject *cls); static PyObject * -_decimal_Context_radix(PyObject *context, PyObject *Py_UNUSED(ignored)) +_decimal_Context_radix(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _decimal_Context_radix_impl(context); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "radix() takes no arguments"); + return NULL; + } + return _decimal_Context_radix_impl(context, cls); } PyDoc_STRVAR(_decimal_Context_is_normal__doc__, @@ -4406,7 +5478,43 @@ PyDoc_STRVAR(_decimal_Context_is_normal__doc__, "Return True if x is a normal number, False otherwise."); #define _DECIMAL_CONTEXT_IS_NORMAL_METHODDEF \ - {"is_normal", (PyCFunction)_decimal_Context_is_normal, METH_O, _decimal_Context_is_normal__doc__}, + {"is_normal", _PyCFunction_CAST(_decimal_Context_is_normal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_normal__doc__}, + +static PyObject * +_decimal_Context_is_normal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_normal(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_normal", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_normal_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_subnormal__doc__, "is_subnormal($self, x, /)\n" @@ -4415,7 +5523,43 @@ PyDoc_STRVAR(_decimal_Context_is_subnormal__doc__, "Return True if x is subnormal, False otherwise."); #define _DECIMAL_CONTEXT_IS_SUBNORMAL_METHODDEF \ - {"is_subnormal", (PyCFunction)_decimal_Context_is_subnormal, METH_O, _decimal_Context_is_subnormal__doc__}, + {"is_subnormal", _PyCFunction_CAST(_decimal_Context_is_subnormal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_subnormal__doc__}, + +static PyObject * +_decimal_Context_is_subnormal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_subnormal(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_subnormal", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_subnormal_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_finite__doc__, "is_finite($self, x, /)\n" @@ -4424,7 +5568,43 @@ PyDoc_STRVAR(_decimal_Context_is_finite__doc__, "Return True if x is finite, False otherwise."); #define _DECIMAL_CONTEXT_IS_FINITE_METHODDEF \ - {"is_finite", (PyCFunction)_decimal_Context_is_finite, METH_O, _decimal_Context_is_finite__doc__}, + {"is_finite", _PyCFunction_CAST(_decimal_Context_is_finite), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_finite__doc__}, + +static PyObject * +_decimal_Context_is_finite_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_finite(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_finite", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_finite_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_infinite__doc__, "is_infinite($self, x, /)\n" @@ -4433,7 +5613,43 @@ PyDoc_STRVAR(_decimal_Context_is_infinite__doc__, "Return True if x is infinite, False otherwise."); #define _DECIMAL_CONTEXT_IS_INFINITE_METHODDEF \ - {"is_infinite", (PyCFunction)_decimal_Context_is_infinite, METH_O, _decimal_Context_is_infinite__doc__}, + {"is_infinite", _PyCFunction_CAST(_decimal_Context_is_infinite), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_infinite__doc__}, + +static PyObject * +_decimal_Context_is_infinite_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_infinite(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_infinite", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_infinite_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_nan__doc__, "is_nan($self, x, /)\n" @@ -4442,7 +5658,43 @@ PyDoc_STRVAR(_decimal_Context_is_nan__doc__, "Return True if x is a qNaN or sNaN, False otherwise."); #define _DECIMAL_CONTEXT_IS_NAN_METHODDEF \ - {"is_nan", (PyCFunction)_decimal_Context_is_nan, METH_O, _decimal_Context_is_nan__doc__}, + {"is_nan", _PyCFunction_CAST(_decimal_Context_is_nan), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_nan__doc__}, + +static PyObject * +_decimal_Context_is_nan_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_nan(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_nan", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_nan_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_qnan__doc__, "is_qnan($self, x, /)\n" @@ -4451,7 +5703,43 @@ PyDoc_STRVAR(_decimal_Context_is_qnan__doc__, "Return True if x is a quiet NaN, False otherwise."); #define _DECIMAL_CONTEXT_IS_QNAN_METHODDEF \ - {"is_qnan", (PyCFunction)_decimal_Context_is_qnan, METH_O, _decimal_Context_is_qnan__doc__}, + {"is_qnan", _PyCFunction_CAST(_decimal_Context_is_qnan), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_qnan__doc__}, + +static PyObject * +_decimal_Context_is_qnan_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_qnan(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_qnan", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_qnan_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_snan__doc__, "is_snan($self, x, /)\n" @@ -4460,7 +5748,43 @@ PyDoc_STRVAR(_decimal_Context_is_snan__doc__, "Return True if x is a signaling NaN, False otherwise."); #define _DECIMAL_CONTEXT_IS_SNAN_METHODDEF \ - {"is_snan", (PyCFunction)_decimal_Context_is_snan, METH_O, _decimal_Context_is_snan__doc__}, + {"is_snan", _PyCFunction_CAST(_decimal_Context_is_snan), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_snan__doc__}, + +static PyObject * +_decimal_Context_is_snan_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_snan(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_snan", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_snan_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_signed__doc__, "is_signed($self, x, /)\n" @@ -4469,7 +5793,43 @@ PyDoc_STRVAR(_decimal_Context_is_signed__doc__, "Return True if x is negative, False otherwise."); #define _DECIMAL_CONTEXT_IS_SIGNED_METHODDEF \ - {"is_signed", (PyCFunction)_decimal_Context_is_signed, METH_O, _decimal_Context_is_signed__doc__}, + {"is_signed", _PyCFunction_CAST(_decimal_Context_is_signed), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_signed__doc__}, + +static PyObject * +_decimal_Context_is_signed_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_signed(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_signed", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_signed_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_zero__doc__, "is_zero($self, x, /)\n" @@ -4478,7 +5838,43 @@ PyDoc_STRVAR(_decimal_Context_is_zero__doc__, "Return True if x is a zero, False otherwise."); #define _DECIMAL_CONTEXT_IS_ZERO_METHODDEF \ - {"is_zero", (PyCFunction)_decimal_Context_is_zero, METH_O, _decimal_Context_is_zero__doc__}, + {"is_zero", _PyCFunction_CAST(_decimal_Context_is_zero), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_zero__doc__}, + +static PyObject * +_decimal_Context_is_zero_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_zero(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_zero", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_zero_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_is_canonical__doc__, "is_canonical($self, x, /)\n" @@ -4487,7 +5883,43 @@ PyDoc_STRVAR(_decimal_Context_is_canonical__doc__, "Return True if x is canonical, False otherwise."); #define _DECIMAL_CONTEXT_IS_CANONICAL_METHODDEF \ - {"is_canonical", (PyCFunction)_decimal_Context_is_canonical, METH_O, _decimal_Context_is_canonical__doc__}, + {"is_canonical", _PyCFunction_CAST(_decimal_Context_is_canonical), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_is_canonical__doc__}, + +static PyObject * +_decimal_Context_is_canonical_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_is_canonical(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_canonical", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_is_canonical_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context__apply__doc__, "_apply($self, x, /)\n" @@ -4496,7 +5928,43 @@ PyDoc_STRVAR(_decimal_Context__apply__doc__, "Apply self to Decimal x."); #define _DECIMAL_CONTEXT__APPLY_METHODDEF \ - {"_apply", (PyCFunction)_decimal_Context__apply, METH_O, _decimal_Context__apply__doc__}, + {"_apply", _PyCFunction_CAST(_decimal_Context__apply), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context__apply__doc__}, + +static PyObject * +_decimal_Context__apply_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context__apply(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_apply", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context__apply_impl(context, cls, x); + +exit: + return return_value; +} #if defined(EXTRA_FUNCTIONALITY) @@ -4507,7 +5975,43 @@ PyDoc_STRVAR(_decimal_Context_apply__doc__, "Apply self to Decimal x."); #define _DECIMAL_CONTEXT_APPLY_METHODDEF \ - {"apply", (PyCFunction)_decimal_Context_apply, METH_O, _decimal_Context_apply__doc__}, + {"apply", _PyCFunction_CAST(_decimal_Context_apply), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_apply__doc__}, + +static PyObject * +_decimal_Context_apply_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_apply(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "apply", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_apply_impl(context, cls, x); + +exit: + return return_value; +} #endif /* defined(EXTRA_FUNCTIONALITY) */ @@ -4518,7 +6022,43 @@ PyDoc_STRVAR(_decimal_Context_canonical__doc__, "Return a new instance of x."); #define _DECIMAL_CONTEXT_CANONICAL_METHODDEF \ - {"canonical", (PyCFunction)_decimal_Context_canonical, METH_O, _decimal_Context_canonical__doc__}, + {"canonical", _PyCFunction_CAST(_decimal_Context_canonical), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_canonical__doc__}, + +static PyObject * +_decimal_Context_canonical_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_canonical(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "canonical", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_canonical_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_copy_abs__doc__, "copy_abs($self, x, /)\n" @@ -4527,7 +6067,43 @@ PyDoc_STRVAR(_decimal_Context_copy_abs__doc__, "Return a copy of x with the sign set to 0."); #define _DECIMAL_CONTEXT_COPY_ABS_METHODDEF \ - {"copy_abs", (PyCFunction)_decimal_Context_copy_abs, METH_O, _decimal_Context_copy_abs__doc__}, + {"copy_abs", _PyCFunction_CAST(_decimal_Context_copy_abs), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_copy_abs__doc__}, + +static PyObject * +_decimal_Context_copy_abs_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_copy_abs(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "copy_abs", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_copy_abs_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_copy_decimal__doc__, "copy_decimal($self, x, /)\n" @@ -4536,7 +6112,43 @@ PyDoc_STRVAR(_decimal_Context_copy_decimal__doc__, "Return a copy of Decimal x."); #define _DECIMAL_CONTEXT_COPY_DECIMAL_METHODDEF \ - {"copy_decimal", (PyCFunction)_decimal_Context_copy_decimal, METH_O, _decimal_Context_copy_decimal__doc__}, + {"copy_decimal", _PyCFunction_CAST(_decimal_Context_copy_decimal), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_copy_decimal__doc__}, + +static PyObject * +_decimal_Context_copy_decimal_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_copy_decimal(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "copy_decimal", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_copy_decimal_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_copy_negate__doc__, "copy_negate($self, x, /)\n" @@ -4545,7 +6157,43 @@ PyDoc_STRVAR(_decimal_Context_copy_negate__doc__, "Return a copy of x with the sign inverted."); #define _DECIMAL_CONTEXT_COPY_NEGATE_METHODDEF \ - {"copy_negate", (PyCFunction)_decimal_Context_copy_negate, METH_O, _decimal_Context_copy_negate__doc__}, + {"copy_negate", _PyCFunction_CAST(_decimal_Context_copy_negate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_copy_negate__doc__}, + +static PyObject * +_decimal_Context_copy_negate_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_copy_negate(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "copy_negate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_copy_negate_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_logb__doc__, "logb($self, x, /)\n" @@ -4554,16 +6202,100 @@ PyDoc_STRVAR(_decimal_Context_logb__doc__, "Return the exponent of the magnitude of the operand\'s MSD."); #define _DECIMAL_CONTEXT_LOGB_METHODDEF \ - {"logb", (PyCFunction)_decimal_Context_logb, METH_O, _decimal_Context_logb__doc__}, + {"logb", _PyCFunction_CAST(_decimal_Context_logb), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_logb__doc__}, + +static PyObject * +_decimal_Context_logb_impl(PyObject *context, PyTypeObject *cls, PyObject *x); + +static PyObject * +_decimal_Context_logb(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logb", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_logb_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_logical_invert__doc__, "logical_invert($self, x, /)\n" "--\n" "\n" -"Invert all digits of x."); +"Invert all the digits in the operand.\n" +"\n" +"The operand must be a logical number.\n" +"\n" +" >>> ExtendedContext.logical_invert(Decimal(\'0\'))\n" +" Decimal(\'111111111\')\n" +" >>> ExtendedContext.logical_invert(Decimal(\'1\'))\n" +" Decimal(\'111111110\')\n" +" >>> ExtendedContext.logical_invert(Decimal(\'111111111\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_invert(Decimal(\'101010101\'))\n" +" Decimal(\'10101010\')\n" +" >>> ExtendedContext.logical_invert(1101)\n" +" Decimal(\'111110010\')"); #define _DECIMAL_CONTEXT_LOGICAL_INVERT_METHODDEF \ - {"logical_invert", (PyCFunction)_decimal_Context_logical_invert, METH_O, _decimal_Context_logical_invert__doc__}, + {"logical_invert", _PyCFunction_CAST(_decimal_Context_logical_invert), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_logical_invert__doc__}, + +static PyObject * +_decimal_Context_logical_invert_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_logical_invert(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_invert", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_logical_invert_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_number_class__doc__, "number_class($self, x, /)\n" @@ -4572,7 +6304,43 @@ PyDoc_STRVAR(_decimal_Context_number_class__doc__, "Return an indication of the class of x."); #define _DECIMAL_CONTEXT_NUMBER_CLASS_METHODDEF \ - {"number_class", (PyCFunction)_decimal_Context_number_class, METH_O, _decimal_Context_number_class__doc__}, + {"number_class", _PyCFunction_CAST(_decimal_Context_number_class), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_number_class__doc__}, + +static PyObject * +_decimal_Context_number_class_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_number_class(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "number_class", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_number_class_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_to_sci_string__doc__, "to_sci_string($self, x, /)\n" @@ -4581,7 +6349,43 @@ PyDoc_STRVAR(_decimal_Context_to_sci_string__doc__, "Convert a number to a string using scientific notation."); #define _DECIMAL_CONTEXT_TO_SCI_STRING_METHODDEF \ - {"to_sci_string", (PyCFunction)_decimal_Context_to_sci_string, METH_O, _decimal_Context_to_sci_string__doc__}, + {"to_sci_string", _PyCFunction_CAST(_decimal_Context_to_sci_string), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_to_sci_string__doc__}, + +static PyObject * +_decimal_Context_to_sci_string_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_to_sci_string(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_sci_string", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_to_sci_string_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_to_eng_string__doc__, "to_eng_string($self, x, /)\n" @@ -4590,7 +6394,43 @@ PyDoc_STRVAR(_decimal_Context_to_eng_string__doc__, "Convert a number to a string, using engineering notation."); #define _DECIMAL_CONTEXT_TO_ENG_STRING_METHODDEF \ - {"to_eng_string", (PyCFunction)_decimal_Context_to_eng_string, METH_O, _decimal_Context_to_eng_string__doc__}, + {"to_eng_string", _PyCFunction_CAST(_decimal_Context_to_eng_string), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_to_eng_string__doc__}, + +static PyObject * +_decimal_Context_to_eng_string_impl(PyObject *context, PyTypeObject *cls, + PyObject *x); + +static PyObject * +_decimal_Context_to_eng_string(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "to_eng_string", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *x; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + x = args[0]; + return_value = _decimal_Context_to_eng_string_impl(context, cls, x); + +exit: + return return_value; +} PyDoc_STRVAR(_decimal_Context_compare_total__doc__, "compare_total($self, x, y, /)\n" @@ -4599,25 +6439,41 @@ PyDoc_STRVAR(_decimal_Context_compare_total__doc__, "Compare x and y using their abstract representation."); #define _DECIMAL_CONTEXT_COMPARE_TOTAL_METHODDEF \ - {"compare_total", _PyCFunction_CAST(_decimal_Context_compare_total), METH_FASTCALL, _decimal_Context_compare_total__doc__}, + {"compare_total", _PyCFunction_CAST(_decimal_Context_compare_total), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_compare_total__doc__}, static PyObject * -_decimal_Context_compare_total_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_compare_total_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_compare_total(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_compare_total(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare_total", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("compare_total", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_compare_total_impl(context, x, y); + return_value = _decimal_Context_compare_total_impl(context, cls, x, y); exit: return return_value; @@ -4630,25 +6486,41 @@ PyDoc_STRVAR(_decimal_Context_compare_total_mag__doc__, "Compare x and y using their abstract representation, ignoring sign."); #define _DECIMAL_CONTEXT_COMPARE_TOTAL_MAG_METHODDEF \ - {"compare_total_mag", _PyCFunction_CAST(_decimal_Context_compare_total_mag), METH_FASTCALL, _decimal_Context_compare_total_mag__doc__}, + {"compare_total_mag", _PyCFunction_CAST(_decimal_Context_compare_total_mag), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_compare_total_mag__doc__}, static PyObject * -_decimal_Context_compare_total_mag_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_compare_total_mag_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_compare_total_mag(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_compare_total_mag(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compare_total_mag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("compare_total_mag", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_compare_total_mag_impl(context, x, y); + return_value = _decimal_Context_compare_total_mag_impl(context, cls, x, y); exit: return return_value; @@ -4661,24 +6533,41 @@ PyDoc_STRVAR(_decimal_Context_copy_sign__doc__, "Copy the sign from y to x."); #define _DECIMAL_CONTEXT_COPY_SIGN_METHODDEF \ - {"copy_sign", _PyCFunction_CAST(_decimal_Context_copy_sign), METH_FASTCALL, _decimal_Context_copy_sign__doc__}, + {"copy_sign", _PyCFunction_CAST(_decimal_Context_copy_sign), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_copy_sign__doc__}, static PyObject * -_decimal_Context_copy_sign_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_copy_sign_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_copy_sign(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_copy_sign(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "copy_sign", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("copy_sign", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_copy_sign_impl(context, x, y); + return_value = _decimal_Context_copy_sign_impl(context, cls, x, y); exit: return return_value; @@ -4688,28 +6577,65 @@ PyDoc_STRVAR(_decimal_Context_logical_and__doc__, "logical_and($self, x, y, /)\n" "--\n" "\n" -"Digit-wise and of x and y."); +"Applies the logical operation \'and\' between each operand\'s digits.\n" +"\n" +"The operands must be both logical numbers.\n" +"\n" +" >>> ExtendedContext.logical_and(Decimal(\'0\'), Decimal(\'0\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_and(Decimal(\'0\'), Decimal(\'1\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_and(Decimal(\'1\'), Decimal(\'0\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_and(Decimal(\'1\'), Decimal(\'1\'))\n" +" Decimal(\'1\')\n" +" >>> ExtendedContext.logical_and(Decimal(\'1100\'), Decimal(\'1010\'))\n" +" Decimal(\'1000\')\n" +" >>> ExtendedContext.logical_and(Decimal(\'1111\'), Decimal(\'10\'))\n" +" Decimal(\'10\')\n" +" >>> ExtendedContext.logical_and(110, 1101)\n" +" Decimal(\'100\')\n" +" >>> ExtendedContext.logical_and(Decimal(110), 1101)\n" +" Decimal(\'100\')\n" +" >>> ExtendedContext.logical_and(110, Decimal(1101))\n" +" Decimal(\'100\')"); #define _DECIMAL_CONTEXT_LOGICAL_AND_METHODDEF \ - {"logical_and", _PyCFunction_CAST(_decimal_Context_logical_and), METH_FASTCALL, _decimal_Context_logical_and__doc__}, + {"logical_and", _PyCFunction_CAST(_decimal_Context_logical_and), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_logical_and__doc__}, static PyObject * -_decimal_Context_logical_and_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_logical_and_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_logical_and(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_logical_and(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_and", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("logical_and", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_logical_and_impl(context, x, y); + return_value = _decimal_Context_logical_and_impl(context, cls, x, y); exit: return return_value; @@ -4719,27 +6645,65 @@ PyDoc_STRVAR(_decimal_Context_logical_or__doc__, "logical_or($self, x, y, /)\n" "--\n" "\n" -"Digit-wise or of x and y."); +"Applies the logical operation \'or\' between each operand\'s digits.\n" +"\n" +"The operands must be both logical numbers.\n" +"\n" +" >>> ExtendedContext.logical_or(Decimal(\'0\'), Decimal(\'0\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_or(Decimal(\'0\'), Decimal(\'1\'))\n" +" Decimal(\'1\')\n" +" >>> ExtendedContext.logical_or(Decimal(\'1\'), Decimal(\'0\'))\n" +" Decimal(\'1\')\n" +" >>> ExtendedContext.logical_or(Decimal(\'1\'), Decimal(\'1\'))\n" +" Decimal(\'1\')\n" +" >>> ExtendedContext.logical_or(Decimal(\'1100\'), Decimal(\'1010\'))\n" +" Decimal(\'1110\')\n" +" >>> ExtendedContext.logical_or(Decimal(\'1110\'), Decimal(\'10\'))\n" +" Decimal(\'1110\')\n" +" >>> ExtendedContext.logical_or(110, 1101)\n" +" Decimal(\'1111\')\n" +" >>> ExtendedContext.logical_or(Decimal(110), 1101)\n" +" Decimal(\'1111\')\n" +" >>> ExtendedContext.logical_or(110, Decimal(1101))\n" +" Decimal(\'1111\')"); #define _DECIMAL_CONTEXT_LOGICAL_OR_METHODDEF \ - {"logical_or", _PyCFunction_CAST(_decimal_Context_logical_or), METH_FASTCALL, _decimal_Context_logical_or__doc__}, + {"logical_or", _PyCFunction_CAST(_decimal_Context_logical_or), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_logical_or__doc__}, static PyObject * -_decimal_Context_logical_or_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_logical_or_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_logical_or(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_logical_or(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_or", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("logical_or", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_logical_or_impl(context, x, y); + return_value = _decimal_Context_logical_or_impl(context, cls, x, y); exit: return return_value; @@ -4749,28 +6713,65 @@ PyDoc_STRVAR(_decimal_Context_logical_xor__doc__, "logical_xor($self, x, y, /)\n" "--\n" "\n" -"Digit-wise xor of x and y."); +"Applies the logical operation \'xor\' between each operand\'s digits.\n" +"\n" +"The operands must be both logical numbers.\n" +"\n" +" >>> ExtendedContext.logical_xor(Decimal(\'0\'), Decimal(\'0\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_xor(Decimal(\'0\'), Decimal(\'1\'))\n" +" Decimal(\'1\')\n" +" >>> ExtendedContext.logical_xor(Decimal(\'1\'), Decimal(\'0\'))\n" +" Decimal(\'1\')\n" +" >>> ExtendedContext.logical_xor(Decimal(\'1\'), Decimal(\'1\'))\n" +" Decimal(\'0\')\n" +" >>> ExtendedContext.logical_xor(Decimal(\'1100\'), Decimal(\'1010\'))\n" +" Decimal(\'110\')\n" +" >>> ExtendedContext.logical_xor(Decimal(\'1111\'), Decimal(\'10\'))\n" +" Decimal(\'1101\')\n" +" >>> ExtendedContext.logical_xor(110, 1101)\n" +" Decimal(\'1011\')\n" +" >>> ExtendedContext.logical_xor(Decimal(110), 1101)\n" +" Decimal(\'1011\')\n" +" >>> ExtendedContext.logical_xor(110, Decimal(1101))\n" +" Decimal(\'1011\')"); #define _DECIMAL_CONTEXT_LOGICAL_XOR_METHODDEF \ - {"logical_xor", _PyCFunction_CAST(_decimal_Context_logical_xor), METH_FASTCALL, _decimal_Context_logical_xor__doc__}, + {"logical_xor", _PyCFunction_CAST(_decimal_Context_logical_xor), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_logical_xor__doc__}, static PyObject * -_decimal_Context_logical_xor_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_logical_xor_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_logical_xor(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_logical_xor(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "logical_xor", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("logical_xor", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_logical_xor_impl(context, x, y); + return_value = _decimal_Context_logical_xor_impl(context, cls, x, y); exit: return return_value; @@ -4783,24 +6784,41 @@ PyDoc_STRVAR(_decimal_Context_rotate__doc__, "Return a copy of x, rotated by y places."); #define _DECIMAL_CONTEXT_ROTATE_METHODDEF \ - {"rotate", _PyCFunction_CAST(_decimal_Context_rotate), METH_FASTCALL, _decimal_Context_rotate__doc__}, + {"rotate", _PyCFunction_CAST(_decimal_Context_rotate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_rotate__doc__}, static PyObject * -_decimal_Context_rotate_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_rotate_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_rotate(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_rotate(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "rotate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("rotate", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_rotate_impl(context, x, y); + return_value = _decimal_Context_rotate_impl(context, cls, x, y); exit: return return_value; @@ -4813,24 +6831,41 @@ PyDoc_STRVAR(_decimal_Context_scaleb__doc__, "Return the first operand after adding the second value to its exp."); #define _DECIMAL_CONTEXT_SCALEB_METHODDEF \ - {"scaleb", _PyCFunction_CAST(_decimal_Context_scaleb), METH_FASTCALL, _decimal_Context_scaleb__doc__}, + {"scaleb", _PyCFunction_CAST(_decimal_Context_scaleb), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_scaleb__doc__}, static PyObject * -_decimal_Context_scaleb_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_scaleb_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_scaleb(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_scaleb(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "scaleb", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("scaleb", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_scaleb_impl(context, x, y); + return_value = _decimal_Context_scaleb_impl(context, cls, x, y); exit: return return_value; @@ -4843,24 +6878,41 @@ PyDoc_STRVAR(_decimal_Context_shift__doc__, "Return a copy of x, shifted by y places."); #define _DECIMAL_CONTEXT_SHIFT_METHODDEF \ - {"shift", _PyCFunction_CAST(_decimal_Context_shift), METH_FASTCALL, _decimal_Context_shift__doc__}, + {"shift", _PyCFunction_CAST(_decimal_Context_shift), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_shift__doc__}, static PyObject * -_decimal_Context_shift_impl(PyObject *context, PyObject *x, PyObject *y); +_decimal_Context_shift_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_shift(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_shift(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "shift", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("shift", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_shift_impl(context, x, y); + return_value = _decimal_Context_shift_impl(context, cls, x, y); exit: return return_value; @@ -4873,31 +6925,59 @@ PyDoc_STRVAR(_decimal_Context_same_quantum__doc__, "Return True if the two operands have the same exponent."); #define _DECIMAL_CONTEXT_SAME_QUANTUM_METHODDEF \ - {"same_quantum", _PyCFunction_CAST(_decimal_Context_same_quantum), METH_FASTCALL, _decimal_Context_same_quantum__doc__}, + {"same_quantum", _PyCFunction_CAST(_decimal_Context_same_quantum), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _decimal_Context_same_quantum__doc__}, static PyObject * -_decimal_Context_same_quantum_impl(PyObject *context, PyObject *x, - PyObject *y); +_decimal_Context_same_quantum_impl(PyObject *context, PyTypeObject *cls, + PyObject *x, PyObject *y); static PyObject * -_decimal_Context_same_quantum(PyObject *context, PyObject *const *args, Py_ssize_t nargs) +_decimal_Context_same_quantum(PyObject *context, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "same_quantum", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *x; PyObject *y; - if (!_PyArg_CheckPositional("same_quantum", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } x = args[0]; y = args[1]; - return_value = _decimal_Context_same_quantum_impl(context, x, y); + return_value = _decimal_Context_same_quantum_impl(context, cls, x, y); exit: return return_value; } +#ifndef _DECIMAL_CONTEXT__UNSAFE_SETPREC_METHODDEF + #define _DECIMAL_CONTEXT__UNSAFE_SETPREC_METHODDEF +#endif /* !defined(_DECIMAL_CONTEXT__UNSAFE_SETPREC_METHODDEF) */ + +#ifndef _DECIMAL_CONTEXT__UNSAFE_SETEMIN_METHODDEF + #define _DECIMAL_CONTEXT__UNSAFE_SETEMIN_METHODDEF +#endif /* !defined(_DECIMAL_CONTEXT__UNSAFE_SETEMIN_METHODDEF) */ + +#ifndef _DECIMAL_CONTEXT__UNSAFE_SETEMAX_METHODDEF + #define _DECIMAL_CONTEXT__UNSAFE_SETEMAX_METHODDEF +#endif /* !defined(_DECIMAL_CONTEXT__UNSAFE_SETEMAX_METHODDEF) */ + #ifndef _DECIMAL_CONTEXT_APPLY_METHODDEF #define _DECIMAL_CONTEXT_APPLY_METHODDEF #endif /* !defined(_DECIMAL_CONTEXT_APPLY_METHODDEF) */ -/*[clinic end generated code: output=1e10ddd6610e17dc input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b288181c82fdc9f1 input=a9049054013a1b77]*/ diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index b9e12ab2026..3173b52afb3 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -912,7 +912,7 @@ deepcopy(elementtreestate *st, PyObject *object, PyObject *memo) return Py_NewRef(object); } - if (Py_REFCNT(object) == 1) { + if (_PyObject_IsUniquelyReferenced(object)) { if (PyDict_CheckExact(object)) { PyObject *key, *value; Py_ssize_t pos = 0; @@ -2794,8 +2794,9 @@ treebuilder_handle_data(TreeBuilderObject* self, PyObject* data) self->data = Py_NewRef(data); } else { /* more than one item; use a list to collect items */ - if (PyBytes_CheckExact(self->data) && Py_REFCNT(self->data) == 1 && - PyBytes_CheckExact(data) && PyBytes_GET_SIZE(data) == 1) { + if (PyBytes_CheckExact(self->data) + && _PyObject_IsUniquelyReferenced(self->data) + && PyBytes_CheckExact(data) && PyBytes_GET_SIZE(data) == 1) { /* XXX this code path unused in Python 3? */ /* expat often generates single character data sections; handle the most common case by resizing the existing string... */ @@ -4214,8 +4215,8 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self, (XML_ProcessingInstructionHandler) expat_pi_handler ); } else { - Py_DECREF(events_seq); PyErr_Format(PyExc_ValueError, "unknown event '%s'", event_name); + Py_DECREF(events_seq); return NULL; } } diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index f077a0ed329..5773083ff68 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -108,20 +108,13 @@ placeholder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return placeholder; } -static int -placeholder_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyType_Slot placeholder_type_slots[] = { {Py_tp_dealloc, placeholder_dealloc}, {Py_tp_repr, placeholder_repr}, {Py_tp_doc, (void *)placeholder_doc}, {Py_tp_methods, placeholder_methods}, {Py_tp_new, placeholder_new}, - {Py_tp_traverse, placeholder_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0} }; @@ -298,7 +291,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) if (kw == NULL) { pto->kw = PyDict_New(); } - else if (Py_REFCNT(kw) == 1) { + else if (_PyObject_IsUniquelyReferenced(kw)) { pto->kw = Py_NewRef(kw); } else { @@ -785,7 +778,8 @@ partial_setstate(PyObject *self, PyObject *state) if (!PyArg_ParseTuple(state, "OOOO", &fn, &fnargs, &kw, &dict) || !PyCallable_Check(fn) || !PyTuple_Check(fnargs) || - (kw != Py_None && !PyDict_Check(kw))) + (kw != Py_None && !PyDict_Check(kw)) || + (dict != Py_None && !PyDict_Check(dict))) { PyErr_SetString(PyExc_TypeError, "invalid partial state"); return NULL; @@ -1083,7 +1077,7 @@ _functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq, for (;;) { PyObject *op2; - if (Py_REFCNT(args) > 1) { + if (!_PyObject_IsUniquelyReferenced(args)) { Py_DECREF(args); if ((args = PyTuple_New(2)) == NULL) goto Fail; diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 76072ca60cf..72f568ceb06 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -8,11 +8,12 @@ #endif #include "Python.h" -#include "pycore_pyerrors.h" // _PyErr_SetLocaleString() +#include "pycore_object.h" // _PyObject_VisitType() +#include "pycore_pyerrors.h" // _PyErr_SetLocaleString() #include "gdbm.h" #include <fcntl.h> -#include <stdlib.h> // free() +#include <stdlib.h> // free() #include <sys/stat.h> #include <sys/types.h> @@ -122,13 +123,6 @@ newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode) } /* Methods */ -static int -gdbm_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} - static void gdbm_dealloc(PyObject *op) { @@ -679,8 +673,10 @@ _gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls) } if (gdbm_delete(self->di_dbm, key) < 0) { PyErr_SetString(state->gdbm_error, "cannot delete item from database"); + free(key.dptr); return NULL; } + free(key.dptr); } Py_RETURN_NONE; } @@ -694,7 +690,11 @@ gdbm__enter__(PyObject *self, PyObject *args) static PyObject * gdbm__exit__(PyObject *self, PyObject *args) { - return _gdbm_gdbm_close_impl((gdbmobject *)self); + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(self); + result = _gdbm_gdbm_close_impl((gdbmobject *)self); + Py_END_CRITICAL_SECTION(); + return result; } static PyMethodDef gdbm_methods[] = { @@ -714,7 +714,7 @@ static PyMethodDef gdbm_methods[] = { static PyType_Slot gdbmtype_spec_slots[] = { {Py_tp_dealloc, gdbm_dealloc}, - {Py_tp_traverse, gdbm_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_methods, gdbm_methods}, {Py_sq_contains, gdbm_contains}, {Py_mp_length, gdbm_length}, @@ -814,11 +814,6 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags, case 'u': iflags |= GDBM_NOLOCK; break; -#endif -#ifdef GDBM_NOMMAP - case 'm': - iflags |= GDBM_NOMMAP; - break; #endif default: PyErr_Format(state->gdbm_error, @@ -852,9 +847,6 @@ static const char gdbmmodule_open_flags[] = "rwcn" #endif #ifdef GDBM_NOLOCK "u" -#endif -#ifdef GDBM_NOMMAP - "m" #endif ; diff --git a/Modules/_hacl/Hacl_HMAC.h b/Modules/_hacl/Hacl_HMAC.h index 10ff15183f2..7dca53c9254 100644 --- a/Modules/_hacl/Hacl_HMAC.h +++ b/Modules/_hacl/Hacl_HMAC.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_HMAC_H -#define __Hacl_HMAC_H +#ifndef Hacl_HMAC_H +#define Hacl_HMAC_H #if defined(__cplusplus) extern "C" { @@ -220,5 +220,5 @@ Hacl_HMAC_compute_blake2b_32( } #endif -#define __Hacl_HMAC_H_DEFINED -#endif +#define Hacl_HMAC_H_DEFINED +#endif /* Hacl_HMAC_H */ diff --git a/Modules/_hacl/Hacl_Hash_Blake2b.h b/Modules/_hacl/Hacl_Hash_Blake2b.h index 3a73f358c98..b07893ba339 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2b.h +++ b/Modules/_hacl/Hacl_Hash_Blake2b.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_Blake2b_H -#define __Hacl_Hash_Blake2b_H +#ifndef Hacl_Hash_Blake2b_H +#define Hacl_Hash_Blake2b_H #if defined(__cplusplus) extern "C" { @@ -220,5 +220,5 @@ Hacl_Hash_Blake2b_hash_with_key_and_params( } #endif -#define __Hacl_Hash_Blake2b_H_DEFINED -#endif +#define Hacl_Hash_Blake2b_H_DEFINED +#endif /* Hacl_Hash_Blake2b_H */ diff --git a/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.h b/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.h index 0271ab8e024..8be8f32db62 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.h +++ b/Modules/_hacl/Hacl_Hash_Blake2b_Simd256.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_Blake2b_Simd256_H -#define __Hacl_Hash_Blake2b_Simd256_H +#ifndef Hacl_Hash_Blake2b_Simd256_H +#define Hacl_Hash_Blake2b_Simd256_H #if defined(__cplusplus) extern "C" { @@ -206,5 +206,5 @@ Hacl_Hash_Blake2b_Simd256_hash_with_key_and_params( } #endif -#define __Hacl_Hash_Blake2b_Simd256_H_DEFINED -#endif +#define Hacl_Hash_Blake2b_Simd256_H_DEFINED +#endif /* Hacl_Hash_Blake2b_Simd256_H */ diff --git a/Modules/_hacl/Hacl_Hash_Blake2s.h b/Modules/_hacl/Hacl_Hash_Blake2s.h index fbf8cff5cd1..2582a3d34e3 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2s.h +++ b/Modules/_hacl/Hacl_Hash_Blake2s.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_Blake2s_H -#define __Hacl_Hash_Blake2s_H +#ifndef Hacl_Hash_Blake2s_H +#define Hacl_Hash_Blake2s_H #if defined(__cplusplus) extern "C" { @@ -198,5 +198,5 @@ Hacl_Hash_Blake2s_hash_with_key_and_params( } #endif -#define __Hacl_Hash_Blake2s_H_DEFINED -#endif +#define Hacl_Hash_Blake2s_H_DEFINED +#endif /* Hacl_Hash_Blake2s_H */ diff --git a/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.h b/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.h index 56456e6fbb3..4b3b4e4fbb5 100644 --- a/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.h +++ b/Modules/_hacl/Hacl_Hash_Blake2s_Simd128.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_Blake2s_Simd128_H -#define __Hacl_Hash_Blake2s_Simd128_H +#ifndef Hacl_Hash_Blake2s_Simd128_H +#define Hacl_Hash_Blake2s_Simd128_H #if defined(__cplusplus) extern "C" { @@ -206,5 +206,5 @@ Hacl_Hash_Blake2s_Simd128_hash_with_key_and_params( } #endif -#define __Hacl_Hash_Blake2s_Simd128_H_DEFINED -#endif +#define Hacl_Hash_Blake2s_Simd128_H_DEFINED +#endif /* Hacl_Hash_Blake2s_Simd128_H */ diff --git a/Modules/_hacl/Hacl_Hash_MD5.h b/Modules/_hacl/Hacl_Hash_MD5.h index 521c2addc50..b220bbf6890 100644 --- a/Modules/_hacl/Hacl_Hash_MD5.h +++ b/Modules/_hacl/Hacl_Hash_MD5.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_MD5_H -#define __Hacl_Hash_MD5_H +#ifndef Hacl_Hash_MD5_H +#define Hacl_Hash_MD5_H #if defined(__cplusplus) extern "C" { @@ -62,5 +62,5 @@ void Hacl_Hash_MD5_hash(uint8_t *output, uint8_t *input, uint32_t input_len); } #endif -#define __Hacl_Hash_MD5_H_DEFINED -#endif +#define Hacl_Hash_MD5_H_DEFINED +#endif /* Hacl_Hash_MD5_H */ diff --git a/Modules/_hacl/Hacl_Hash_SHA1.h b/Modules/_hacl/Hacl_Hash_SHA1.h index 63ac83f9dce..7fc8c8cfd20 100644 --- a/Modules/_hacl/Hacl_Hash_SHA1.h +++ b/Modules/_hacl/Hacl_Hash_SHA1.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_SHA1_H -#define __Hacl_Hash_SHA1_H +#ifndef Hacl_Hash_SHA1_H +#define Hacl_Hash_SHA1_H #if defined(__cplusplus) extern "C" { @@ -62,5 +62,5 @@ void Hacl_Hash_SHA1_hash(uint8_t *output, uint8_t *input, uint32_t input_len); } #endif -#define __Hacl_Hash_SHA1_H_DEFINED -#endif +#define Hacl_Hash_SHA1_H_DEFINED +#endif /* Hacl_Hash_SHA1_H */ diff --git a/Modules/_hacl/Hacl_Hash_SHA2.h b/Modules/_hacl/Hacl_Hash_SHA2.h index a93138fb7ee..dd168b8aa1a 100644 --- a/Modules/_hacl/Hacl_Hash_SHA2.h +++ b/Modules/_hacl/Hacl_Hash_SHA2.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_SHA2_H -#define __Hacl_Hash_SHA2_H +#ifndef Hacl_Hash_SHA2_H +#define Hacl_Hash_SHA2_H #if defined(__cplusplus) extern "C" { @@ -199,5 +199,5 @@ void Hacl_Hash_SHA2_hash_384(uint8_t *output, uint8_t *input, uint32_t input_len } #endif -#define __Hacl_Hash_SHA2_H_DEFINED -#endif +#define Hacl_Hash_SHA2_H_DEFINED +#endif /* Hacl_Hash_SHA2_H */ diff --git a/Modules/_hacl/Hacl_Hash_SHA3.h b/Modules/_hacl/Hacl_Hash_SHA3.h index 65ec99ee3a3..df6ebe439e9 100644 --- a/Modules/_hacl/Hacl_Hash_SHA3.h +++ b/Modules/_hacl/Hacl_Hash_SHA3.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Hash_SHA3_H -#define __Hacl_Hash_SHA3_H +#ifndef Hacl_Hash_SHA3_H +#define Hacl_Hash_SHA3_H #if defined(__cplusplus) extern "C" { @@ -155,5 +155,5 @@ Hacl_Hash_SHA3_shake128_squeeze_nblocks( } #endif -#define __Hacl_Hash_SHA3_H_DEFINED -#endif +#define Hacl_Hash_SHA3_H_DEFINED +#endif /* Hacl_Hash_SHA3_H */ diff --git a/Modules/_hacl/Hacl_Streaming_HMAC.c b/Modules/_hacl/Hacl_Streaming_HMAC.c index 8dd7e2c0bf3..f89c00ee1ae 100644 --- a/Modules/_hacl/Hacl_Streaming_HMAC.c +++ b/Modules/_hacl/Hacl_Streaming_HMAC.c @@ -2375,9 +2375,13 @@ Hacl_Streaming_HMAC_digest( Hacl_Agile_Hash_state_s *s112 = tmp_block_state1.snd; update_multi(s112, prev_len, buf_multi, 0U); uint64_t prev_len_last = total_len - (uint64_t)r; - Hacl_Agile_Hash_state_s *s11 = tmp_block_state1.snd; - update_last(s11, prev_len_last, buf_last, r); + Hacl_Agile_Hash_state_s *s113 = tmp_block_state1.snd; + update_last(s113, prev_len_last, buf_last, r); finish0(tmp_block_state1, output); + Hacl_Agile_Hash_state_s *s210 = tmp_block_state1.thd; + Hacl_Agile_Hash_state_s *s11 = tmp_block_state1.snd; + free_(s11); + free_(s210); return Hacl_Streaming_Types_Success; } KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", diff --git a/Modules/_hacl/Hacl_Streaming_HMAC.h b/Modules/_hacl/Hacl_Streaming_HMAC.h index a0806c02d0b..6c302b1f92d 100644 --- a/Modules/_hacl/Hacl_Streaming_HMAC.h +++ b/Modules/_hacl/Hacl_Streaming_HMAC.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Streaming_HMAC_H -#define __Hacl_Streaming_HMAC_H +#ifndef Hacl_Streaming_HMAC_H +#define Hacl_Streaming_HMAC_H #if defined(__cplusplus) extern "C" { @@ -130,5 +130,5 @@ Hacl_Streaming_HMAC_agile_state } #endif -#define __Hacl_Streaming_HMAC_H_DEFINED -#endif +#define Hacl_Streaming_HMAC_H_DEFINED +#endif /* Hacl_Streaming_HMAC_H */ diff --git a/Modules/_hacl/Hacl_Streaming_Types.h b/Modules/_hacl/Hacl_Streaming_Types.h index 5c497750793..cce25eb7946 100644 --- a/Modules/_hacl/Hacl_Streaming_Types.h +++ b/Modules/_hacl/Hacl_Streaming_Types.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Streaming_Types_H -#define __Hacl_Streaming_Types_H +#ifndef Hacl_Streaming_Types_H +#define Hacl_Streaming_Types_H #if defined(__cplusplus) extern "C" { @@ -68,5 +68,5 @@ typedef struct Hacl_Streaming_MD_state_64_s Hacl_Streaming_MD_state_64; } #endif -#define __Hacl_Streaming_Types_H_DEFINED -#endif +#define Hacl_Streaming_Types_H_DEFINED +#endif /* Hacl_Streaming_Types_H */ diff --git a/Modules/_hacl/include/krml/FStar_UInt128_Verified.h b/Modules/_hacl/include/krml/FStar_UInt128_Verified.h index f85982f3373..7aa2a6d83f9 100644 --- a/Modules/_hacl/include/krml/FStar_UInt128_Verified.h +++ b/Modules/_hacl/include/krml/FStar_UInt128_Verified.h @@ -4,8 +4,8 @@ */ -#ifndef __FStar_UInt128_Verified_H -#define __FStar_UInt128_Verified_H +#ifndef FStar_UInt128_Verified_H +#define FStar_UInt128_Verified_H #include "FStar_UInt_8_16_32_64.h" #include <inttypes.h> @@ -331,5 +331,5 @@ static inline FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t } -#define __FStar_UInt128_Verified_H_DEFINED -#endif +#define FStar_UInt128_Verified_H_DEFINED +#endif /* FStar_UInt128_Verified_H */ diff --git a/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h b/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h index 00be8083657..2720348bbb7 100644 --- a/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h +++ b/Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h @@ -4,8 +4,8 @@ */ -#ifndef __FStar_UInt_8_16_32_64_H -#define __FStar_UInt_8_16_32_64_H +#ifndef FStar_UInt_8_16_32_64_H +#define FStar_UInt_8_16_32_64_H #include <inttypes.h> #include <stdbool.h> @@ -30,6 +30,8 @@ extern uint64_t FStar_UInt64_zero; extern uint64_t FStar_UInt64_one; +extern bool FStar_UInt64_ne(uint64_t a, uint64_t b); + extern uint64_t FStar_UInt64_minus(uint64_t a); extern uint32_t FStar_UInt64_n_minus_one; @@ -80,6 +82,8 @@ extern uint32_t FStar_UInt32_zero; extern uint32_t FStar_UInt32_one; +extern bool FStar_UInt32_ne(uint32_t a, uint32_t b); + extern uint32_t FStar_UInt32_minus(uint32_t a); extern uint32_t FStar_UInt32_n_minus_one; @@ -130,6 +134,8 @@ extern uint16_t FStar_UInt16_zero; extern uint16_t FStar_UInt16_one; +extern bool FStar_UInt16_ne(uint16_t a, uint16_t b); + extern uint16_t FStar_UInt16_minus(uint16_t a); extern uint32_t FStar_UInt16_n_minus_one; @@ -180,6 +186,8 @@ extern uint8_t FStar_UInt8_zero; extern uint8_t FStar_UInt8_one; +extern bool FStar_UInt8_ne(uint8_t a, uint8_t b); + extern uint8_t FStar_UInt8_minus(uint8_t a); extern uint32_t FStar_UInt8_n_minus_one; @@ -217,5 +225,5 @@ extern uint8_t FStar_UInt8_of_string(Prims_string uu___); typedef uint8_t FStar_UInt8_byte; -#define __FStar_UInt_8_16_32_64_H_DEFINED -#endif +#define FStar_UInt_8_16_32_64_H_DEFINED +#endif /* FStar_UInt_8_16_32_64_H */ diff --git a/Modules/_hacl/include/krml/internal/target.h b/Modules/_hacl/include/krml/internal/target.h index c592214634a..73555ab5ca1 100644 --- a/Modules/_hacl/include/krml/internal/target.h +++ b/Modules/_hacl/include/krml/internal/target.h @@ -1,8 +1,8 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 and MIT Licenses. */ -#ifndef __KRML_TARGET_H -#define __KRML_TARGET_H +#ifndef KRML_HEADER_TARGET_H +#define KRML_HEADER_TARGET_H #include <assert.h> #include <inttypes.h> @@ -12,6 +12,9 @@ #include <stdio.h> #include <stdlib.h> +typedef float float32_t; +typedef double float64_t; + /* Since KaRaMeL emits the inline keyword unconditionally, we follow the * guidelines at https://gcc.gnu.org/onlinedocs/gcc/Inline.html and make this * __inline__ to ensure the code compiles with -std=c90 and earlier. */ @@ -425,4 +428,4 @@ inline static int32_t krml_time(void) { #else # define KRML_MAYBE_FOR16(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif -#endif +#endif /* KRML_HEADER_TARGET_H */ diff --git a/Modules/_hacl/include/krml/internal/types.h b/Modules/_hacl/include/krml/internal/types.h index 2280dfad48d..d96ed19fcca 100644 --- a/Modules/_hacl/include/krml/internal/types.h +++ b/Modules/_hacl/include/krml/internal/types.h @@ -92,7 +92,7 @@ typedef FStar_UInt128_uint128 FStar_UInt128_t, uint128_t; /* Avoid a circular loop: if this header is included via FStar_UInt8_16_32_64, * then don't bring the uint128 definitions into scope. */ -#ifndef __FStar_UInt_8_16_32_64_H +#ifndef FStar_UInt_8_16_32_64_H #if !defined(KRML_VERIFIED_UINT128) && defined(IS_MSVC64) #include "fstar_uint128_msvc.h" diff --git a/Modules/_hacl/include/krml/lowstar_endianness.h b/Modules/_hacl/include/krml/lowstar_endianness.h index af6b882cf25..5f706fa51aa 100644 --- a/Modules/_hacl/include/krml/lowstar_endianness.h +++ b/Modules/_hacl/include/krml/lowstar_endianness.h @@ -1,8 +1,8 @@ /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 and MIT Licenses. */ -#ifndef __LOWSTAR_ENDIANNESS_H -#define __LOWSTAR_ENDIANNESS_H +#ifndef KRML_HEADER_LOWSTAR_ENDIANNESS_H +#define KRML_HEADER_LOWSTAR_ENDIANNESS_H #include <string.h> #include <inttypes.h> @@ -228,4 +228,4 @@ inline static void store64(uint8_t *b, uint64_t i) { #define load128_be0 load128_be #define store128_be0 store128_be -#endif +#endif /* KRML_HEADER_LOWSTAR_ENDIANNESS_H */ diff --git a/Modules/_hacl/internal/Hacl_HMAC.h b/Modules/_hacl/internal/Hacl_HMAC.h index ad29d50760c..ef9f25f5d42 100644 --- a/Modules/_hacl/internal/Hacl_HMAC.h +++ b/Modules/_hacl/internal/Hacl_HMAC.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_HMAC_H -#define __internal_Hacl_HMAC_H +#ifndef internal_Hacl_HMAC_H +#define internal_Hacl_HMAC_H #if defined(__cplusplus) extern "C" { @@ -48,5 +48,5 @@ K___uint32_t_uint32_t; } #endif -#define __internal_Hacl_HMAC_H_DEFINED -#endif +#define internal_Hacl_HMAC_H_DEFINED +#endif /* internal_Hacl_HMAC_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_Blake2b.h b/Modules/_hacl/internal/Hacl_Hash_Blake2b.h index e74c320e073..7ca8e10e34c 100644 --- a/Modules/_hacl/internal/Hacl_Hash_Blake2b.h +++ b/Modules/_hacl/internal/Hacl_Hash_Blake2b.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_Blake2b_H -#define __internal_Hacl_Hash_Blake2b_H +#ifndef internal_Hacl_Hash_Blake2b_H +#define internal_Hacl_Hash_Blake2b_H #if defined(__cplusplus) extern "C" { @@ -91,5 +91,5 @@ Hacl_Hash_Blake2b_state_t; } #endif -#define __internal_Hacl_Hash_Blake2b_H_DEFINED -#endif +#define internal_Hacl_Hash_Blake2b_H_DEFINED +#endif /* internal_Hacl_Hash_Blake2b_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_Blake2b_Simd256.h b/Modules/_hacl/internal/Hacl_Hash_Blake2b_Simd256.h index 27633f22b24..6507d287922 100644 --- a/Modules/_hacl/internal/Hacl_Hash_Blake2b_Simd256.h +++ b/Modules/_hacl/internal/Hacl_Hash_Blake2b_Simd256.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_Blake2b_Simd256_H -#define __internal_Hacl_Hash_Blake2b_Simd256_H +#ifndef internal_Hacl_Hash_Blake2b_Simd256_H +#define internal_Hacl_Hash_Blake2b_Simd256_H #if defined(__cplusplus) extern "C" { @@ -134,5 +134,5 @@ Hacl_Hash_Blake2b_Simd256_state_t; } #endif -#define __internal_Hacl_Hash_Blake2b_Simd256_H_DEFINED -#endif +#define internal_Hacl_Hash_Blake2b_Simd256_H_DEFINED +#endif /* internal_Hacl_Hash_Blake2b_Simd256_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_Blake2s.h b/Modules/_hacl/internal/Hacl_Hash_Blake2s.h index 0c5781df8ce..5fa5bb34efc 100644 --- a/Modules/_hacl/internal/Hacl_Hash_Blake2s.h +++ b/Modules/_hacl/internal/Hacl_Hash_Blake2s.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_Blake2s_H -#define __internal_Hacl_Hash_Blake2s_H +#ifndef internal_Hacl_Hash_Blake2s_H +#define internal_Hacl_Hash_Blake2s_H #if defined(__cplusplus) extern "C" { @@ -90,5 +90,5 @@ Hacl_Hash_Blake2s_state_t; } #endif -#define __internal_Hacl_Hash_Blake2s_H_DEFINED -#endif +#define internal_Hacl_Hash_Blake2s_H_DEFINED +#endif /* internal_Hacl_Hash_Blake2s_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_Blake2s_Simd128.h b/Modules/_hacl/internal/Hacl_Hash_Blake2s_Simd128.h index 0f5db552d6c..3220cddac30 100644 --- a/Modules/_hacl/internal/Hacl_Hash_Blake2s_Simd128.h +++ b/Modules/_hacl/internal/Hacl_Hash_Blake2s_Simd128.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_Blake2s_Simd128_H -#define __internal_Hacl_Hash_Blake2s_Simd128_H +#ifndef internal_Hacl_Hash_Blake2s_Simd128_H +#define internal_Hacl_Hash_Blake2s_Simd128_H #if defined(__cplusplus) extern "C" { @@ -134,5 +134,5 @@ Hacl_Hash_Blake2s_Simd128_state_t; } #endif -#define __internal_Hacl_Hash_Blake2s_Simd128_H_DEFINED -#endif +#define internal_Hacl_Hash_Blake2s_Simd128_H_DEFINED +#endif /* internal_Hacl_Hash_Blake2s_Simd128_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_MD5.h b/Modules/_hacl/internal/Hacl_Hash_MD5.h index 7fe71a49c6d..d8761de99f5 100644 --- a/Modules/_hacl/internal/Hacl_Hash_MD5.h +++ b/Modules/_hacl/internal/Hacl_Hash_MD5.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_MD5_H -#define __internal_Hacl_Hash_MD5_H +#ifndef internal_Hacl_Hash_MD5_H +#define internal_Hacl_Hash_MD5_H #if defined(__cplusplus) extern "C" { @@ -53,5 +53,5 @@ void Hacl_Hash_MD5_hash_oneshot(uint8_t *output, uint8_t *input, uint32_t input_ } #endif -#define __internal_Hacl_Hash_MD5_H_DEFINED -#endif +#define internal_Hacl_Hash_MD5_H_DEFINED +#endif /* internal_Hacl_Hash_MD5_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_SHA1.h b/Modules/_hacl/internal/Hacl_Hash_SHA1.h index ed53be559fe..0e9f1c911f6 100644 --- a/Modules/_hacl/internal/Hacl_Hash_SHA1.h +++ b/Modules/_hacl/internal/Hacl_Hash_SHA1.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_SHA1_H -#define __internal_Hacl_Hash_SHA1_H +#ifndef internal_Hacl_Hash_SHA1_H +#define internal_Hacl_Hash_SHA1_H #if defined(__cplusplus) extern "C" { @@ -52,5 +52,5 @@ void Hacl_Hash_SHA1_hash_oneshot(uint8_t *output, uint8_t *input, uint32_t input } #endif -#define __internal_Hacl_Hash_SHA1_H_DEFINED -#endif +#define internal_Hacl_Hash_SHA1_H_DEFINED +#endif /* internal_Hacl_Hash_SHA1_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_SHA2.h b/Modules/_hacl/internal/Hacl_Hash_SHA2.h index 98498ee9376..e6750207980 100644 --- a/Modules/_hacl/internal/Hacl_Hash_SHA2.h +++ b/Modules/_hacl/internal/Hacl_Hash_SHA2.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_SHA2_H -#define __internal_Hacl_Hash_SHA2_H +#ifndef internal_Hacl_Hash_SHA2_H +#define internal_Hacl_Hash_SHA2_H #if defined(__cplusplus) extern "C" { @@ -161,5 +161,5 @@ void Hacl_Hash_SHA2_sha384_finish(uint64_t *st, uint8_t *h); } #endif -#define __internal_Hacl_Hash_SHA2_H_DEFINED -#endif +#define internal_Hacl_Hash_SHA2_H_DEFINED +#endif /* internal_Hacl_Hash_SHA2_H */ diff --git a/Modules/_hacl/internal/Hacl_Hash_SHA3.h b/Modules/_hacl/internal/Hacl_Hash_SHA3.h index e653c73b1d0..c08a4e7858b 100644 --- a/Modules/_hacl/internal/Hacl_Hash_SHA3.h +++ b/Modules/_hacl/internal/Hacl_Hash_SHA3.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Hash_SHA3_H -#define __internal_Hacl_Hash_SHA3_H +#ifndef internal_Hacl_Hash_SHA3_H +#define internal_Hacl_Hash_SHA3_H #if defined(__cplusplus) extern "C" { @@ -81,5 +81,5 @@ Hacl_Hash_SHA3_state_t; } #endif -#define __internal_Hacl_Hash_SHA3_H_DEFINED -#endif +#define internal_Hacl_Hash_SHA3_H_DEFINED +#endif /* internal_Hacl_Hash_SHA3_H */ diff --git a/Modules/_hacl/internal/Hacl_Impl_Blake2_Constants.h b/Modules/_hacl/internal/Hacl_Impl_Blake2_Constants.h index fb3a045cd5c..2726cc48478 100644 --- a/Modules/_hacl/internal/Hacl_Impl_Blake2_Constants.h +++ b/Modules/_hacl/internal/Hacl_Impl_Blake2_Constants.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Impl_Blake2_Constants_H -#define __internal_Hacl_Impl_Blake2_Constants_H +#ifndef internal_Hacl_Impl_Blake2_Constants_H +#define internal_Hacl_Impl_Blake2_Constants_H #if defined(__cplusplus) extern "C" { @@ -69,5 +69,5 @@ Hacl_Hash_Blake2b_ivTable_B[8U] = } #endif -#define __internal_Hacl_Impl_Blake2_Constants_H_DEFINED -#endif +#define internal_Hacl_Impl_Blake2_Constants_H_DEFINED +#endif /* internal_Hacl_Impl_Blake2_Constants_H */ diff --git a/Modules/_hacl/internal/Hacl_Streaming_HMAC.h b/Modules/_hacl/internal/Hacl_Streaming_HMAC.h index acc4f399602..fb44f707463 100644 --- a/Modules/_hacl/internal/Hacl_Streaming_HMAC.h +++ b/Modules/_hacl/internal/Hacl_Streaming_HMAC.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Streaming_HMAC_H -#define __internal_Hacl_Streaming_HMAC_H +#ifndef internal_Hacl_Streaming_HMAC_H +#define internal_Hacl_Streaming_HMAC_H #if defined(__cplusplus) extern "C" { @@ -90,5 +90,5 @@ Hacl_Streaming_HMAC_agile_state; } #endif -#define __internal_Hacl_Streaming_HMAC_H_DEFINED -#endif +#define internal_Hacl_Streaming_HMAC_H_DEFINED +#endif /* internal_Hacl_Streaming_HMAC_H */ diff --git a/Modules/_hacl/internal/Hacl_Streaming_Types.h b/Modules/_hacl/internal/Hacl_Streaming_Types.h index fed3cbd4259..d6c4fc0d625 100644 --- a/Modules/_hacl/internal/Hacl_Streaming_Types.h +++ b/Modules/_hacl/internal/Hacl_Streaming_Types.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_Streaming_Types_H -#define __internal_Hacl_Streaming_Types_H +#ifndef internal_Hacl_Streaming_Types_H +#define internal_Hacl_Streaming_Types_H #if defined(__cplusplus) extern "C" { @@ -83,5 +83,5 @@ Hacl_Streaming_MD_state_64; } #endif -#define __internal_Hacl_Streaming_Types_H_DEFINED -#endif +#define internal_Hacl_Streaming_Types_H_DEFINED +#endif /* internal_Hacl_Streaming_Types_H */ diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh index a6776282423..72ceb27b7f7 100755 --- a/Modules/_hacl/refresh.sh +++ b/Modules/_hacl/refresh.sh @@ -22,7 +22,7 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. -expected_hacl_star_rev=4ef25b547b377dcef855db4289c6a00580e7221c +expected_hacl_star_rev=8ba599b2f6c9701b3dc961db895b0856a2210f76 hacl_dir="$(realpath "$1")" cd "$(dirname "$0")" diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index a6496d0f04f..77832a768e0 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -30,7 +30,6 @@ /* EVP is the preferred interface to hashing in OpenSSL */ #include <openssl/evp.h> -#include <openssl/hmac.h> #include <openssl/crypto.h> // FIPS_mode() /* We use the object interface to discover what hashes OpenSSL supports. */ #include <openssl/objects.h> @@ -40,6 +39,10 @@ #if OPENSSL_VERSION_NUMBER >= 0x30000000L # define Py_HAS_OPENSSL3_SUPPORT +# include <openssl/core_names.h> // OSSL_MAC_PARAM_DIGEST +# include <openssl/params.h> // OSSL_PARAM_*() +#else +# include <openssl/hmac.h> // HMAC() #endif #ifndef OPENSSL_THREADS @@ -65,6 +68,10 @@ #define PY_EVP_MD_free(md) EVP_MD_free(md) #define PY_EVP_MD_CTX_md(CTX) EVP_MD_CTX_get0_md(CTX) + +#define PY_HMAC_CTX_TYPE EVP_MAC_CTX +#define PY_HMAC_CTX_free EVP_MAC_CTX_free +#define PY_HMAC_update EVP_MAC_update #else #define PY_EVP_MD const EVP_MD #define PY_EVP_MD_fetch(algorithm, properties) EVP_get_digestbyname(algorithm) @@ -72,6 +79,10 @@ #define PY_EVP_MD_free(md) do {} while(0) #define PY_EVP_MD_CTX_md(CTX) EVP_MD_CTX_md(CTX) + +#define PY_HMAC_CTX_TYPE HMAC_CTX +#define PY_HMAC_CTX_free HMAC_CTX_free +#define PY_HMAC_update HMAC_Update #endif /* @@ -283,6 +294,9 @@ typedef struct { PyObject *constructs; PyObject *unsupported_digestmod_error; _Py_hashtable_t *hashtable; +#ifdef Py_HAS_OPENSSL3_SUPPORT + EVP_MAC *evp_hmac; +#endif } _hashlibstate; static inline _hashlibstate* @@ -304,7 +318,12 @@ typedef struct { typedef struct { HASHLIB_OBJECT_HEAD - HMAC_CTX *ctx; /* OpenSSL hmac context */ +#ifdef Py_HAS_OPENSSL3_SUPPORT + EVP_MAC_CTX *ctx; /* OpenSSL HMAC EVP-based context */ + int evp_md_nid; /* needed to find the message digest name */ +#else + HMAC_CTX *ctx; /* OpenSSL HMAC plain context */ +#endif } HMACobject; #define HMACobject_CAST(op) ((HMACobject *)(op)) @@ -587,9 +606,14 @@ get_asn1_utf8name_by_nid(int nid) { const char *name = OBJ_nid2ln(nid); if (name == NULL) { - // In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise. - assert(ERR_peek_last_error() != 0); - if (ERR_GET_REASON(ERR_peek_last_error()) != OBJ_R_UNKNOWN_NID) { + /* In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise. + * However, not all versions of OpenSSL set a last error, so we simply + * ignore the last error if none exists. + * + * See https://github.com/python/cpython/issues/142451. + */ + unsigned long errcode = ERR_peek_last_error(); + if (errcode && ERR_GET_REASON(errcode) != OBJ_R_UNKNOWN_NID) { goto error; } // fallback to short name and unconditionally propagate errors @@ -617,6 +641,20 @@ get_hashlib_utf8name_by_nid(int nid) return e ? e->py_name : get_asn1_utf8name_by_nid(nid); } +#ifdef Py_HAS_OPENSSL3_SUPPORT +/* + * Convert the NID to an OpenSSL "canonical" cached, SN_* or LN_* digest name. + * + * On error, set an exception and return NULL. + */ +static const char * +get_openssl_utf8name_by_nid(int nid) +{ + const py_hashentry_t *e = get_hashentry_by_nid(nid); + return e ? e->ossl_name : get_asn1_utf8name_by_nid(nid); +} +#endif + /* Same as get_hashlib_utf8name_by_nid() but using an EVP_MD object. */ static const char * get_hashlib_utf8name_by_evp_md(const EVP_MD *md) @@ -733,6 +771,47 @@ get_openssl_evp_md(_hashlibstate *state, PyObject *digestmod, Py_hash_type py_ht return get_openssl_evp_md_by_utf8name(state, name, py_ht); } +#ifdef Py_HAS_OPENSSL3_SUPPORT +/* + * Get the "canonical" name of an EVP_MD described by 'digestmod' and purpose. + * + * On error, set an exception and return NULL. + * + * This function should not be used to construct the exposed Python name, + * but rather to invoke OpenSSL EVP_* functions. + */ +static const char * +get_openssl_digest_name(_hashlibstate *state, + PyObject *digestmod, Py_hash_type py_ht, + EVP_MD **evp_md) +{ + PY_EVP_MD *md = get_openssl_evp_md(state, digestmod, py_ht); + if (md == NULL) { + if (evp_md != NULL) { + *evp_md = NULL; + } + return NULL; + } + int nid = EVP_MD_nid(md); + const char *name = get_openssl_utf8name_by_nid(nid); + if (name == NULL) { + if (evp_md != NULL) { + *evp_md = NULL; + } + PY_EVP_MD_free(md); + raise_unsupported_algorithm_error(state, digestmod); + return NULL; + } + if (evp_md != NULL) { + *evp_md = md; + } + else { + PY_EVP_MD_free(md); + } + return name; +} +#endif + // --- OpenSSL HASH wrappers -------------------------------------------------- /* Thin wrapper around EVP_MD_CTX_new() which sets an exception on failure. */ @@ -1017,35 +1096,29 @@ static PyType_Spec HASHobject_type_spec = { /*[clinic input] _hashlib.HASHXOF.digest - length: Py_ssize_t + length: Py_ssize_t(allow_negative=False) Return the digest value as a bytes object. [clinic start generated code]*/ static PyObject * _hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length) -/*[clinic end generated code: output=dcb09335dd2fe908 input=3eb034ce03c55b21]*/ +/*[clinic end generated code: output=dcb09335dd2fe908 input=224d047da2c12a42]*/ { EVP_MD_CTX *temp_ctx; - PyObject *retval; - - if (length < 0) { - PyErr_SetString(PyExc_ValueError, "negative digest length"); - return NULL; - } if (length == 0) { return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - retval = PyBytes_FromStringAndSize(NULL, length); - if (retval == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; } temp_ctx = py_wrapper_EVP_MD_CTX_new(); if (temp_ctx == NULL) { - Py_DECREF(retval); + PyBytesWriter_Discard(writer); return NULL; } @@ -1053,7 +1126,7 @@ _hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length) goto error; } if (!EVP_DigestFinalXOF(temp_ctx, - (unsigned char*)PyBytes_AS_STRING(retval), + (unsigned char*)PyBytesWriter_GetData(writer), length)) { notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinalXOF)); @@ -1061,10 +1134,10 @@ _hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length) } EVP_MD_CTX_free(temp_ctx); - return retval; + return PyBytesWriter_Finish(writer); error: - Py_DECREF(retval); + PyBytesWriter_Discard(writer); EVP_MD_CTX_free(temp_ctx); return NULL; } @@ -1072,24 +1145,19 @@ error: /*[clinic input] _hashlib.HASHXOF.hexdigest - length: Py_ssize_t + length: Py_ssize_t(allow_negative=False) Return the digest value as a string of hexadecimal digits. [clinic start generated code]*/ static PyObject * _hashlib_HASHXOF_hexdigest_impl(HASHobject *self, Py_ssize_t length) -/*[clinic end generated code: output=519431cafa014f39 input=0e58f7238adb7ab8]*/ +/*[clinic end generated code: output=519431cafa014f39 input=4a41b8ab5d3bfee2]*/ { unsigned char *digest; EVP_MD_CTX *temp_ctx; PyObject *retval; - if (length < 0) { - PyErr_SetString(PyExc_ValueError, "negative digest length"); - return NULL; - } - if (length == 0) { return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } @@ -1566,7 +1634,6 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name, { _hashlibstate *state = get_hashlib_state(module); PyObject *key_obj = NULL; - char *key; long dklen; int retval; @@ -1619,24 +1686,24 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name, goto end; } - key_obj = PyBytes_FromStringAndSize(NULL, dklen); - if (key_obj == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(dklen); + if (writer == NULL) { goto end; } - key = PyBytes_AS_STRING(key_obj); Py_BEGIN_ALLOW_THREADS retval = PKCS5_PBKDF2_HMAC((const char *)password->buf, (int)password->len, (const unsigned char *)salt->buf, (int)salt->len, iterations, digest, dklen, - (unsigned char *)key); + (unsigned char *)PyBytesWriter_GetData(writer)); Py_END_ALLOW_THREADS if (!retval) { - Py_CLEAR(key_obj); + PyBytesWriter_Discard(writer); notify_ssl_error_occurred_in(Py_STRINGIFY(PKCS5_PBKDF2_HMAC)); goto end; } + key_obj = PyBytesWriter_Finish(writer); end: if (digest != NULL) { @@ -1686,7 +1753,6 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt, long maxmem, long dklen) /*[clinic end generated code: output=d424bc3e8c6b9654 input=bdeac9628d07f7a1]*/ { - PyObject *key = NULL; int retval; if (password->len > INT_MAX) { @@ -1727,8 +1793,8 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt, return NULL; } - key = PyBytes_FromStringAndSize(NULL, dklen); - if (key == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(dklen); + if (writer == NULL) { return NULL; } @@ -1737,24 +1803,42 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt, (const char *)password->buf, (size_t)password->len, (const unsigned char *)salt->buf, (size_t)salt->len, (uint64_t)n, (uint64_t)r, (uint64_t)p, (uint64_t)maxmem, - (unsigned char *)PyBytes_AS_STRING(key), (size_t)dklen + (unsigned char *)PyBytesWriter_GetData(writer), (size_t)dklen ); Py_END_ALLOW_THREADS if (!retval) { - Py_DECREF(key); + PyBytesWriter_Discard(writer); notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_PBE_scrypt)); return NULL; } - return key; + return PyBytesWriter_Finish(writer); } #undef HASHLIB_SCRYPT_MAX_DKLEN #undef HASHLIB_SCRYPT_MAX_MAXMEM -/* Fast HMAC for hmac.digest() +// --- OpenSSL HMAC interface ------------------------------------------------- + +/* + * Functions prefixed by hashlib_openssl_HMAC_* are wrappers around OpenSSL + * and implement "atomic" operations (e.g., "free"). These functions are used + * by those prefixed by _hashlib_HMAC_* that are methods for HMAC objects, or + * other (local) helper functions prefixed by hashlib_HMAC_*. */ +#ifdef Py_HAS_OPENSSL3_SUPPORT +/* EVP_MAC_CTX array of parameters specifying the "digest" */ +#define HASHLIB_HMAC_OSSL_PARAMS(DIGEST) \ + (const OSSL_PARAM []) { \ + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, \ + (char *)DIGEST, strlen(DIGEST)), \ + OSSL_PARAM_END \ + } +#endif + +// --- One-shot HMAC interface ------------------------------------------------ + /*[clinic input] _hashlib.hmac_digest as _hashlib_hmac_singleshot @@ -1772,9 +1856,14 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, { _hashlibstate *state = get_hashlib_state(module); unsigned char md[EVP_MAX_MD_SIZE] = {0}; +#ifdef Py_HAS_OPENSSL3_SUPPORT + size_t md_len = 0; + const char *digest_name = NULL; +#else unsigned int md_len = 0; - unsigned char *result; - PY_EVP_MD *evp; +#endif + unsigned char *result = NULL; + PY_EVP_MD *evp = NULL; int is_xof; if (key->len > INT_MAX) { @@ -1788,13 +1877,34 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, return NULL; } +#ifdef Py_HAS_OPENSSL3_SUPPORT + digest_name = get_openssl_digest_name(state, digest, Py_ht_mac, &evp); + if (digest_name == NULL) { + assert(evp == NULL); + return NULL; + } + assert(evp != NULL); + is_xof = PY_EVP_MD_xof(evp); + + Py_BEGIN_ALLOW_THREADS + result = EVP_Q_mac( + NULL, OSSL_MAC_NAME_HMAC, NULL, NULL, + HASHLIB_HMAC_OSSL_PARAMS(digest_name), + (const void *)key->buf, (size_t)key->len, + (const unsigned char *)msg->buf, (size_t)msg->len, + md, sizeof(md), &md_len + ); + Py_END_ALLOW_THREADS + PY_EVP_MD_free(evp); + assert(md_len < (size_t)PY_SSIZE_T_MAX); +#else evp = get_openssl_evp_md(state, digest, Py_ht_mac); if (evp == NULL) { return NULL; } + is_xof = PY_EVP_MD_xof(evp); Py_BEGIN_ALLOW_THREADS - is_xof = PY_EVP_MD_xof(evp); result = HMAC( evp, (const void *)key->buf, (int)key->len, @@ -1803,23 +1913,27 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, ); Py_END_ALLOW_THREADS PY_EVP_MD_free(evp); - +#endif if (result == NULL) { if (is_xof) { /* use a better default error message if an XOF is used */ raise_unsupported_algorithm_error(state, digest); } else { +#ifdef Py_HAS_OPENSSL3_SUPPORT + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_Q_mac)); +#else notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC)); +#endif } return NULL; } return PyBytes_FromStringAndSize((const char*)md, md_len); } -/* OpenSSL-based HMAC implementation - */ +// --- HMAC Object ------------------------------------------------------------ +#ifndef Py_HAS_OPENSSL3_SUPPORT /* Thin wrapper around HMAC_CTX_new() which sets an exception on failure. */ static HMAC_CTX * py_openssl_wrapper_HMAC_CTX_new(void) @@ -1831,18 +1945,179 @@ py_openssl_wrapper_HMAC_CTX_new(void) } return ctx; } +#endif static int _hmac_update(HMACobject*, PyObject*); +#ifndef Py_HAS_OPENSSL3_SUPPORT static const EVP_MD * _hashlib_hmac_get_md(HMACobject *self) { + assert(self->ctx != NULL); const EVP_MD *md = HMAC_CTX_get_md(self->ctx); if (md == NULL) { notify_ssl_error_occurred("missing EVP_MD for HMAC context"); } return md; } +#endif + +static const char * +hashlib_HMAC_get_hashlib_digest_name(HMACobject *self) +{ +#ifdef Py_HAS_OPENSSL3_SUPPORT + return get_hashlib_utf8name_by_nid(self->evp_md_nid); +#else + const EVP_MD *md = _hashlib_hmac_get_md(self); + return md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md); +#endif +} + +static int +hashlib_openssl_HMAC_update_once(PY_HMAC_CTX_TYPE *ctx, const Py_buffer *v) +{ + if (!PY_HMAC_update(ctx, (const unsigned char *)v->buf, (size_t)v->len)) { + notify_smart_ssl_error_occurred_in(Py_STRINGIFY(PY_HMAC_update)); + return -1; + } + return 0; +} + +/* Thin wrapper around PY_HMAC_CTX_free that allows to pass a NULL 'ctx'. */ +static inline void +hashlib_openssl_HMAC_CTX_free(PY_HMAC_CTX_TYPE *ctx) +{ + /* The NULL check was not present in every OpenSSL versions. */ + if (ctx) { + PY_HMAC_CTX_free(ctx); + } +} + +static PY_HMAC_CTX_TYPE * +hashlib_openssl_HMAC_ctx_copy_with_lock(HMACobject *self) +{ + PY_HMAC_CTX_TYPE *ctx = NULL; +#ifdef Py_HAS_OPENSSL3_SUPPORT + HASHLIB_ACQUIRE_LOCK(self); + ctx = EVP_MAC_CTX_dup(self->ctx); + HASHLIB_RELEASE_LOCK(self); + if (ctx == NULL) { + notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_CTX_dup)); + goto error; + } +#else + int r; + ctx = py_openssl_wrapper_HMAC_CTX_new(); + if (ctx == NULL) { + return NULL; + } + HASHLIB_ACQUIRE_LOCK(self); + r = HMAC_CTX_copy(ctx, self->ctx); + HASHLIB_RELEASE_LOCK(self); + if (r == 0) { + notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy)); + goto error; + } +#endif + return ctx; + +error: + hashlib_openssl_HMAC_CTX_free(ctx); + return NULL; +} + +static PY_HMAC_CTX_TYPE * +hashlib_HMAC_CTX_new_from_digestmod(_hashlibstate *state, + Py_buffer *key, PyObject *digestmod, + int *nid) +{ + PY_HMAC_CTX_TYPE *ctx = NULL; + PY_EVP_MD *md = NULL; + int is_xof, r; +#ifdef Py_HAS_OPENSSL3_SUPPORT + const char *digest = NULL; +#endif + +#ifdef Py_HAS_OPENSSL3_SUPPORT + /* + * OpenSSL 3.0 does not provide a way to extract the NID from an EVP_MAC + * object and does not expose the underlying digest name. The reason is + * that OpenSSL 3.0 treats HMAC objects as being the "same", differing + * only by their *context* parameters. While it is *required* to set + * the digest name when constructing EVP_MAC_CTX objects, that name + * is unfortunately not recoverable through EVP_MAC_CTX_get_params(). + * + * On the other hand, the (deprecated) interface based on HMAC_CTX is + * based on EVP_MD, which allows to treat HMAC objects as if they were + * hash functions when querying the digest name. + * + * Since HMAC objects are constructed from DIGESTMOD values and since + * we have a way to map DIGESTMOD to EVP_MD objects, and then to NIDs, + * HMAC objects based on EVP_MAC will store the NID of the EVP_MD we + * used to deduce the digest name to pass to EVP_MAC_CTX_set_params(). + */ + assert(nid != NULL); + digest = get_openssl_digest_name(state, digestmod, Py_ht_mac, &md); + assert((digest == NULL && md == NULL) || (digest != NULL && md != NULL)); + if (digest == NULL) { + *nid = NID_undef; + return NULL; + } + *nid = EVP_MD_nid(md); + is_xof = PY_EVP_MD_xof(md); + PY_EVP_MD_free(md); + + /* + * OpenSSL is responsible for managing the EVP_MAC object's ref. count + * by calling EVP_MAC_up_ref() and EVP_MAC_free() in EVP_MAC_CTX_new() + * and EVP_MAC_CTX_free() respectively. + */ + ctx = EVP_MAC_CTX_new(state->evp_hmac); + if (ctx == NULL) { + /* EVP_MAC_CTX_new() may also set an ERR_R_EVP_LIB error */ + notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_CTX_new)); + return NULL; + } + + r = EVP_MAC_init( + ctx, + (const unsigned char *)key->buf, + (size_t)key->len, + HASHLIB_HMAC_OSSL_PARAMS(digest) + ); +#else + assert(nid == NULL); + md = get_openssl_evp_md(state, digestmod, Py_ht_mac); + if (md == NULL) { + return NULL; + } + is_xof = PY_EVP_MD_xof(md); + + ctx = py_openssl_wrapper_HMAC_CTX_new(); + if (ctx == NULL) { + PY_EVP_MD_free(md); + return NULL; + } + + r = HMAC_Init_ex(ctx, key->buf, (int)key->len, md, NULL /* impl */); + PY_EVP_MD_free(md); +#endif + if (r == 0) { + if (is_xof) { + /* use a better default error message if an XOF is used */ + raise_unsupported_algorithm_error(state, digestmod); + } + else { +#ifdef Py_HAS_OPENSSL3_SUPPORT + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_init)); +#else + notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Init_ex)); +#endif + } + return NULL; + } + return ctx; +} /*[clinic input] _hashlib.hmac_new @@ -1860,10 +2135,11 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, /*[clinic end generated code: output=c20d9e4d9ed6d219 input=5f4071dcc7f34362]*/ { _hashlibstate *state = get_hashlib_state(module); - PY_EVP_MD *digest; - HMAC_CTX *ctx = NULL; + PY_HMAC_CTX_TYPE *ctx = NULL; HMACobject *self = NULL; - int is_xof, r; +#ifdef Py_HAS_OPENSSL3_SUPPORT + int nid; +#endif if (key->len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, @@ -1877,29 +2153,15 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, return NULL; } - digest = get_openssl_evp_md(state, digestmod, Py_ht_mac); - if (digest == NULL) { - return NULL; - } +#ifdef Py_HAS_OPENSSL3_SUPPORT + ctx = hashlib_HMAC_CTX_new_from_digestmod(state, key, digestmod, &nid); +#else + ctx = hashlib_HMAC_CTX_new_from_digestmod(state, key, digestmod, NULL); +#endif - ctx = py_openssl_wrapper_HMAC_CTX_new(); if (ctx == NULL) { - PY_EVP_MD_free(digest); - goto error; - } - - is_xof = PY_EVP_MD_xof(digest); - r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */); - PY_EVP_MD_free(digest); - if (r == 0) { - if (is_xof) { - /* use a better default error message if an XOF is used */ - raise_unsupported_algorithm_error(state, digestmod); - } - else { - notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Init_ex)); - } - goto error; + assert(PyErr_Occurred()); + return NULL; } self = PyObject_New(HMACobject, state->HMAC_type); @@ -1909,36 +2171,27 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, self->ctx = ctx; ctx = NULL; // 'ctx' is now owned by 'self' +#ifdef Py_HAS_OPENSSL3_SUPPORT + assert(nid != NID_undef); + self->evp_md_nid = nid; +#endif HASHLIB_INIT_MUTEX(self); + /* feed initial data */ if ((msg_obj != NULL) && (msg_obj != Py_None)) { - if (!_hmac_update(self, msg_obj)) { + if (_hmac_update(self, msg_obj) < 0) { goto error; } } return (PyObject *)self; error: - if (ctx) HMAC_CTX_free(ctx); + hashlib_openssl_HMAC_CTX_free(ctx); Py_XDECREF(self); return NULL; } /* helper functions */ -static int -locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self) -{ - int result; - HASHLIB_ACQUIRE_LOCK(self); - result = HMAC_CTX_copy(new_ctx_p, self->ctx); - HASHLIB_RELEASE_LOCK(self); - if (result == 0) { - notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy)); - return -1; - } - return 0; -} - #define BAD_DIGEST_SIZE 0 /* @@ -1949,6 +2202,12 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self) static unsigned int _hashlib_hmac_digest_size(HMACobject *self) { + assert(EVP_MAX_MD_SIZE < INT_MAX); +#ifdef Py_HAS_OPENSSL3_SUPPORT + assert(self->ctx != NULL); + size_t digest_size = EVP_MAC_CTX_get_mac_size(self->ctx); + assert(digest_size <= (size_t)EVP_MAX_MD_SIZE); +#else const EVP_MD *md = _hashlib_hmac_get_md(self); if (md == NULL) { return BAD_DIGEST_SIZE; @@ -1957,6 +2216,7 @@ _hashlib_hmac_digest_size(HMACobject *self) /* digest_size < 0 iff EVP_MD context is NULL (which is impossible here) */ assert(digest_size >= 0); assert(digest_size <= (int)EVP_MAX_MD_SIZE); +#endif /* digest_size == 0 means that the context is not entirely initialized */ if (digest_size == 0) { raise_ssl_error(PyExc_ValueError, "missing digest size"); @@ -1970,21 +2230,13 @@ _hmac_update(HMACobject *self, PyObject *obj) { int r; Py_buffer view = {0}; - - GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0); + GET_BUFFER_VIEW_OR_ERROR(obj, &view, return -1); HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED( self, view.len, - r = HMAC_Update( - self->ctx, (const unsigned char *)view.buf, (size_t)view.len - ) + r = hashlib_openssl_HMAC_update_once(self->ctx, &view) ); PyBuffer_Release(&view); - - if (r == 0) { - notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Update)); - return 0; - } - return 1; + return r; } /*[clinic input] @@ -1998,24 +2250,20 @@ _hashlib_HMAC_copy_impl(HMACobject *self) /*[clinic end generated code: output=29aa28b452833127 input=e2fa6a05db61a4d6]*/ { HMACobject *retval; - - HMAC_CTX *ctx = py_openssl_wrapper_HMAC_CTX_new(); + PY_HMAC_CTX_TYPE *ctx = hashlib_openssl_HMAC_ctx_copy_with_lock(self); if (ctx == NULL) { return NULL; } - if (locked_HMAC_CTX_copy(ctx, self) < 0) { - HMAC_CTX_free(ctx); - return NULL; - } - retval = PyObject_New(HMACobject, Py_TYPE(self)); if (retval == NULL) { - HMAC_CTX_free(ctx); + PY_HMAC_CTX_free(ctx); return NULL; } retval->ctx = ctx; +#ifdef Py_HAS_OPENSSL3_SUPPORT + retval->evp_md_nid = self->evp_md_nid; +#endif HASHLIB_INIT_MUTEX(retval); - return (PyObject *)retval; } @@ -2025,7 +2273,7 @@ _hmac_dealloc(PyObject *op) HMACobject *self = HMACobject_CAST(op); PyTypeObject *tp = Py_TYPE(self); if (self->ctx != NULL) { - HMAC_CTX_free(self->ctx); + PY_HMAC_CTX_free(self->ctx); self->ctx = NULL; } PyObject_Free(self); @@ -2035,10 +2283,8 @@ _hmac_dealloc(PyObject *op) static PyObject * _hmac_repr(PyObject *op) { - const char *digest_name; HMACobject *self = HMACobject_CAST(op); - const EVP_MD *md = _hashlib_hmac_get_md(self); - digest_name = md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md); + const char *digest_name = hashlib_HMAC_get_hashlib_digest_name(self); if (digest_name == NULL) { assert(PyErr_Occurred()); return NULL; @@ -2057,7 +2303,7 @@ static PyObject * _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg) /*[clinic end generated code: output=f31f0ace8c625b00 input=1829173bb3cfd4e6]*/ { - if (!_hmac_update(self, msg)) { + if (_hmac_update(self, msg) < 0) { return NULL; } Py_RETURN_NONE; @@ -2066,7 +2312,7 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg) /* * Extract the MAC value to 'buf' and return the digest size. * - * The buffer 'buf' must have at least hashlib_openssl_HMAC_digest_size(self) + * The buffer 'buf' must have at least _hashlib_hmac_digest_size(self) * bytes. Smaller buffers lead to undefined behaviors. * * On error, set an exception and return -1. @@ -2080,18 +2326,22 @@ _hmac_digest(HMACobject *self, unsigned char *buf) assert(PyErr_Occurred()); return -1; } - HMAC_CTX *temp_ctx = py_openssl_wrapper_HMAC_CTX_new(); - if (temp_ctx == NULL) { + PY_HMAC_CTX_TYPE *ctx = hashlib_openssl_HMAC_ctx_copy_with_lock(self); + if (ctx == NULL) { return -1; } - if (locked_HMAC_CTX_copy(temp_ctx, self) < 0) { - HMAC_CTX_free(temp_ctx); - return -1; - } - int r = HMAC_Final(temp_ctx, buf, NULL); - HMAC_CTX_free(temp_ctx); +#ifdef Py_HAS_OPENSSL3_SUPPORT + int r = EVP_MAC_final(ctx, buf, NULL, digest_size); +#else + int r = HMAC_Final(ctx, buf, NULL); +#endif + PY_HMAC_CTX_free(ctx); if (r == 0) { +#ifdef Py_HAS_OPENSSL3_SUPPORT + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_final)); +#else notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Final)); +#endif return -1; } return digest_size; @@ -2143,19 +2393,20 @@ static PyObject * _hashlib_hmac_get_block_size(PyObject *op, void *Py_UNUSED(closure)) { HMACobject *self = HMACobject_CAST(op); +#ifdef Py_HAS_OPENSSL3_SUPPORT + assert(self->ctx != NULL); + return PyLong_FromSize_t(EVP_MAC_CTX_get_block_size(self->ctx)); +#else const EVP_MD *md = _hashlib_hmac_get_md(self); return md == NULL ? NULL : PyLong_FromLong(EVP_MD_block_size(md)); +#endif } static PyObject * _hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure)) { HMACobject *self = HMACobject_CAST(op); - const EVP_MD *md = _hashlib_hmac_get_md(self); - if (md == NULL) { - return NULL; - } - const char *digest_name = get_hashlib_utf8name_by_evp_md(md); + const char *digest_name = hashlib_HMAC_get_hashlib_digest_name(self); if (digest_name == NULL) { assert(PyErr_Occurred()); return NULL; @@ -2482,6 +2733,12 @@ hashlib_clear(PyObject *m) _Py_hashtable_destroy(state->hashtable); state->hashtable = NULL; } +#ifdef Py_HAS_OPENSSL3_SUPPORT + if (state->evp_hmac != NULL) { + EVP_MAC_free(state->evp_hmac); + state->evp_hmac = NULL; + } +#endif return 0; } @@ -2556,6 +2813,15 @@ hashlib_init_hmactype(PyObject *module) if (PyModule_AddType(module, state->HMAC_type) < 0) { return -1; } +#ifdef Py_HAS_OPENSSL3_SUPPORT + state->evp_hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (state->evp_hmac == NULL) { + ERR_clear_error(); + PyErr_SetString(PyExc_ImportError, "cannot initialize EVP_MAC HMAC"); + return -1; + } +#endif + return 0; } diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 9c1f8615161..ef9cf01ecbe 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -511,12 +511,12 @@ _waiting_release(_waiting_t *waiting, int received) assert(!waiting->received); waiting->status = WAITING_RELEASING; - PyThread_release_lock(waiting->mutex); if (waiting->received != received) { assert(received == 1); waiting->received = received; } waiting->status = WAITING_RELEASED; + PyThread_release_lock(waiting->mutex); } static void @@ -580,7 +580,7 @@ _channelitem_clear_data(_channelitem *item, int removed) { if (item->data != NULL) { // It was allocated in channel_send(). - (void)_release_xid_data(item->data, XID_IGNORE_EXC & XID_FREE); + (void)_release_xid_data(item->data, XID_IGNORE_EXC | XID_FREE); item->data = NULL; } diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c index 03ed081efba..417c5fbcee2 100644 --- a/Modules/_interpqueuesmodule.c +++ b/Modules/_interpqueuesmodule.c @@ -22,6 +22,11 @@ #define MODINIT_FUNC_NAME RESOLVE_MODINIT_FUNC_NAME(MODULE_NAME) +/*[clinic input] +module _interpqueues +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cb1313f77fab132b]*/ + #define GLOBAL_MALLOC(TYPE) \ PyMem_RawMalloc(sizeof(TYPE)) #define GLOBAL_FREE(VAR) \ @@ -431,7 +436,7 @@ _queueitem_clear_data(_queueitem *item) return; } // It was allocated in queue_put(). - (void)_release_xid_data(item->data, XID_IGNORE_EXC & XID_FREE); + (void)_release_xid_data(item->data, XID_IGNORE_EXC | XID_FREE); item->data = NULL; } @@ -1466,31 +1471,48 @@ clear_interpreter(void *data) } -typedef struct idarg_int64_converter_data qidarg_converter_data; +/*[python input] + +class qidarg_converter(CConverter): + type = 'int64_t' + converter = 'qidarg_converter' + +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=c64fbf36771164d6]*/ static int qidarg_converter(PyObject *arg, void *ptr) { - qidarg_converter_data *data = ptr; - if (data->label == NULL) { - data->label = "queue ID"; - } - return idarg_int64_converter(arg, ptr); + int64_t *qid_ptr = ptr; + struct idarg_int64_converter_data data = { + .label = "queue ID", + }; + int res = idarg_int64_converter(arg, &data); + *qid_ptr = data.id; + return res; } +#include "clinic/_interpqueuesmodule.c.h" + + +/*[clinic input] +_interpqueues.create + maxsize: Py_ssize_t + unboundop as unboundarg: int = -1 + fallback as fallbackarg: int = -1 + +Create a new cross-interpreter queue and return its unique generated ID. + +It is a new reference as though bind() had been called on the queue. +The caller is responsible for calling destroy() for the new queue +before the runtime is finalized. +[clinic start generated code]*/ static PyObject * -queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_create_impl(PyObject *module, Py_ssize_t maxsize, + int unboundarg, int fallbackarg) +/*[clinic end generated code: output=9a889b93773251eb input=4f79b710a87360e1]*/ { - static char *kwlist[] = {"maxsize", "unboundop", "fallback", NULL}; - Py_ssize_t maxsize; - int unboundarg = -1; - int fallbackarg = -1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "n|ii:create", kwlist, - &maxsize, &unboundarg, &fallbackarg)) - { - return NULL; - } struct _queuedefaults defaults = {0}; if (resolve_unboundop(unboundarg, UNBOUND_REPLACE, &defaults.unboundop) < 0) @@ -1505,7 +1527,7 @@ queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds) int64_t qid = queue_create(&_globals.queues, maxsize, defaults); if (qid < 0) { - (void)handle_queue_error((int)qid, self, qid); + (void)handle_queue_error((int)qid, module, qid); return NULL; } @@ -1513,7 +1535,7 @@ queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds) if (qidobj == NULL) { PyObject *exc = PyErr_GetRaisedException(); int err = queue_destroy(&_globals.queues, qid); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { // XXX issue a warning? PyErr_Clear(); } @@ -1524,41 +1546,37 @@ queuesmod_create(PyObject *self, PyObject *args, PyObject *kwds) return qidobj; } -PyDoc_STRVAR(queuesmod_create_doc, -"create(maxsize, unboundop, fallback) -> qid\n\ -\n\ -Create a new cross-interpreter queue and return its unique generated ID.\n\ -It is a new reference as though bind() had been called on the queue.\n\ -\n\ -The caller is responsible for calling destroy() for the new queue\n\ -before the runtime is finalized."); +/*[clinic input] +_interpqueues.destroy + qid: qidarg + +Clear and destroy the queue. + +Afterward attempts to use the queue will behave as though it never existed. +[clinic start generated code]*/ static PyObject * -queuesmod_destroy(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_destroy_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=46b35623f080cbff input=8632bba87f81e3e9]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:destroy", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - int err = queue_destroy(&_globals.queues, qid); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(queuesmod_destroy_doc, -"destroy(qid)\n\ -\n\ -Clear and destroy the queue. Afterward attempts to use the queue\n\ -will behave as though it never existed."); +/*[clinic input] +_interpqueues.list_all + +Return the list of ID triples for all queues. + +Each ID triple consists of (ID, default unbound op, default fallback). +[clinic start generated code]*/ static PyObject * -queuesmod_list_all(PyObject *self, PyObject *Py_UNUSED(ignored)) +_interpqueues_list_all_impl(PyObject *module) +/*[clinic end generated code: output=974280cb6442afdb input=19495f02cbb38b33]*/ { int64_t count = 0; struct queue_id_and_info *qids = _queues_list_all(&_globals.queues, &count); @@ -1589,31 +1607,25 @@ finally: return ids; } -PyDoc_STRVAR(queuesmod_list_all_doc, -"list_all() -> [(qid, unboundop, fallback)]\n\ -\n\ -Return the list of IDs for all queues.\n\ -Each corresponding default unbound op and fallback is also included."); +/*[clinic input] +_interpqueues.put + qid: qidarg + obj: object + unboundop as unboundarg: int = -1 + fallback as fallbackarg: int = -1 + +Add the object's data to the queue. +[clinic start generated code]*/ static PyObject * -queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_put_impl(PyObject *module, int64_t qid, PyObject *obj, + int unboundarg, int fallbackarg) +/*[clinic end generated code: output=2e0b31c6eaec29c9 input=4906550ab5c73be3]*/ { - static char *kwlist[] = {"qid", "obj", "unboundop", "fallback", NULL}; - qidarg_converter_data qidarg = {0}; - PyObject *obj; - int unboundarg = -1; - int fallbackarg = -1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O|ii:put", kwlist, - qidarg_converter, &qidarg, &obj, - &unboundarg, &fallbackarg)) - { - return NULL; - } - int64_t qid = qidarg.id; struct _queuedefaults defaults = {-1, -1}; if (unboundarg < 0 || fallbackarg < 0) { int err = queue_get_defaults(&_globals.queues, qid, &defaults); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } } @@ -1629,34 +1641,31 @@ queuesmod_put(PyObject *self, PyObject *args, PyObject *kwds) /* Queue up the object. */ int err = queue_put(&_globals.queues, qid, obj, unboundop, fallback); // This is the only place that raises QueueFull. - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(queuesmod_put_doc, -"put(qid, obj)\n\ -\n\ -Add the object's data to the queue."); +/*[clinic input] +_interpqueues.get + qid: qidarg + +Return the (object, unbound op) from the front of the queue. + +If there is nothing to receive then raise QueueEmpty. +[clinic start generated code]*/ static PyObject * -queuesmod_get(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_get_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=b0988a0e29194f05 input=c5bccbc409ad0190]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - PyObject *obj = NULL; int unboundop = 0; int err = queue_get(&_globals.queues, qid, &obj, &unboundop); // This is the only place that raises QueueEmpty. - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } @@ -1668,29 +1677,23 @@ queuesmod_get(PyObject *self, PyObject *args, PyObject *kwds) return res; } -PyDoc_STRVAR(queuesmod_get_doc, -"get(qid) -> (obj, unboundop)\n\ -\n\ -Return a new object from the data at the front of the queue.\n\ -The unbound op is also returned.\n\ -\n\ -If there is nothing to receive then raise QueueEmpty."); +/*[clinic input] +_interpqueues.bind + qid: qidarg + +Take a reference to the identified queue. + +The queue is not destroyed until there are no references left. +[clinic start generated code]*/ static PyObject * -queuesmod_bind(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_bind_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=02b515e203c3f926 input=b0efd1a6ce0e576e]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:bind", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - // XXX Check module state if bound already. int err = _queues_incref(&_globals.queues, qid); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } @@ -1699,82 +1702,65 @@ queuesmod_bind(PyObject *self, PyObject *args, PyObject *kwds) Py_RETURN_NONE; } -PyDoc_STRVAR(queuesmod_bind_doc, -"bind(qid)\n\ -\n\ -Take a reference to the identified queue.\n\ -The queue is not destroyed until there are no references left."); +/*[clinic input] +_interpqueues.release + qid: qidarg + +Release a reference to the queue. + +The queue is destroyed once there are no references left. +[clinic start generated code]*/ static PyObject * -queuesmod_release(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_release_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=a59545d7c61fc6ee input=664125cf0262ff6f]*/ { // Note that only the current interpreter is affected. - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:release", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; // XXX Check module state if bound already. // XXX Update module state. int err = _queues_decref(&_globals.queues, qid); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } Py_RETURN_NONE; } -PyDoc_STRVAR(queuesmod_release_doc, -"release(qid)\n\ -\n\ -Release a reference to the queue.\n\ -The queue is destroyed once there are no references left."); +/*[clinic input] +_interpqueues.get_maxsize + qid: qidarg + +Return the maximum number of items in the queue. +[clinic start generated code]*/ static PyObject * -queuesmod_get_maxsize(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_get_maxsize_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=074202b9c6dc37bf input=ef55def3496cc379]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:get_maxsize", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - Py_ssize_t maxsize = -1; int err = queue_get_maxsize(&_globals.queues, qid, &maxsize); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } return PyLong_FromLongLong(maxsize); } -PyDoc_STRVAR(queuesmod_get_maxsize_doc, -"get_maxsize(qid)\n\ -\n\ -Return the maximum number of items in the queue."); +/*[clinic input] +_interpqueues.get_queue_defaults + qid: qidarg + +Return the queue's default values, set when it was created. +[clinic start generated code]*/ static PyObject * -queuesmod_get_queue_defaults(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_get_queue_defaults_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=b1b8b8103834191a input=3102315a7bff77fc]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:get_queue_defaults", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - struct _queuedefaults defaults = {0}; int err = queue_get_defaults(&_globals.queues, qid, &defaults); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } @@ -1782,26 +1768,20 @@ queuesmod_get_queue_defaults(PyObject *self, PyObject *args, PyObject *kwds) return res; } -PyDoc_STRVAR(queuesmod_get_queue_defaults_doc, -"get_queue_defaults(qid)\n\ -\n\ -Return the queue's default values, set when it was created."); +/*[clinic input] +_interpqueues.is_full + qid: qidarg + +Return true if the queue has a maxsize and has reached it. +[clinic start generated code]*/ static PyObject * -queuesmod_is_full(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_is_full_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=47a6e18477cddfee input=25d86a327ed3a2e7]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:is_full", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - int is_full = 0; int err = queue_is_full(&_globals.queues, qid, &is_full); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } if (is_full) { @@ -1810,54 +1790,42 @@ queuesmod_is_full(PyObject *self, PyObject *args, PyObject *kwds) Py_RETURN_FALSE; } -PyDoc_STRVAR(queuesmod_is_full_doc, -"is_full(qid)\n\ -\n\ -Return true if the queue has a maxsize and has reached it."); +/*[clinic input] +_interpqueues.get_count + qid: qidarg + +Return the number of items in the queue. +[clinic start generated code]*/ static PyObject * -queuesmod_get_count(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues_get_count_impl(PyObject *module, int64_t qid) +/*[clinic end generated code: output=fb9e66e829cdd964 input=ce47690e7598884b]*/ { - static char *kwlist[] = {"qid", NULL}; - qidarg_converter_data qidarg = {0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "O&:get_count", kwlist, - qidarg_converter, &qidarg)) { - return NULL; - } - int64_t qid = qidarg.id; - Py_ssize_t count = -1; int err = queue_get_count(&_globals.queues, qid, &count); - if (handle_queue_error(err, self, qid)) { + if (handle_queue_error(err, module, qid)) { return NULL; } assert(count >= 0); return PyLong_FromSsize_t(count); } -PyDoc_STRVAR(queuesmod_get_count_doc, -"get_count(qid)\n\ -\n\ -Return the number of items in the queue."); +/*[clinic input] +_interpqueues._register_heap_types + queuetype: object(subclass_of='&PyType_Type', type='PyTypeObject *') + emptyerror: object + fullerror: object + +Return the number of items in the queue. +[clinic start generated code]*/ static PyObject * -queuesmod__register_heap_types(PyObject *self, PyObject *args, PyObject *kwds) +_interpqueues__register_heap_types_impl(PyObject *module, + PyTypeObject *queuetype, + PyObject *emptyerror, + PyObject *fullerror) +/*[clinic end generated code: output=f33f6e8b5af905cd input=57d24ae405eda521]*/ { - static char *kwlist[] = {"queuetype", "emptyerror", "fullerror", NULL}; - PyObject *queuetype; - PyObject *emptyerror; - PyObject *fullerror; - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OOO:_register_heap_types", kwlist, - &queuetype, &emptyerror, &fullerror)) { - return NULL; - } - if (!PyType_Check(queuetype)) { - PyErr_SetString(PyExc_TypeError, - "expected a type for 'queuetype'"); - return NULL; - } if (!PyExceptionClass_Check(emptyerror)) { PyErr_SetString(PyExc_TypeError, "expected an exception type for 'emptyerror'"); @@ -1869,9 +1837,9 @@ queuesmod__register_heap_types(PyObject *self, PyObject *args, PyObject *kwds) return NULL; } - module_state *state = get_module_state(self); + module_state *state = get_module_state(module); - if (set_external_queue_type(state, (PyTypeObject *)queuetype) < 0) { + if (set_external_queue_type(state, queuetype) < 0) { return NULL; } if (set_external_exc_types(state, emptyerror, fullerror) < 0) { @@ -1882,30 +1850,18 @@ queuesmod__register_heap_types(PyObject *self, PyObject *args, PyObject *kwds) } static PyMethodDef module_functions[] = { - {"create", _PyCFunction_CAST(queuesmod_create), - METH_VARARGS | METH_KEYWORDS, queuesmod_create_doc}, - {"destroy", _PyCFunction_CAST(queuesmod_destroy), - METH_VARARGS | METH_KEYWORDS, queuesmod_destroy_doc}, - {"list_all", queuesmod_list_all, - METH_NOARGS, queuesmod_list_all_doc}, - {"put", _PyCFunction_CAST(queuesmod_put), - METH_VARARGS | METH_KEYWORDS, queuesmod_put_doc}, - {"get", _PyCFunction_CAST(queuesmod_get), - METH_VARARGS | METH_KEYWORDS, queuesmod_get_doc}, - {"bind", _PyCFunction_CAST(queuesmod_bind), - METH_VARARGS | METH_KEYWORDS, queuesmod_bind_doc}, - {"release", _PyCFunction_CAST(queuesmod_release), - METH_VARARGS | METH_KEYWORDS, queuesmod_release_doc}, - {"get_maxsize", _PyCFunction_CAST(queuesmod_get_maxsize), - METH_VARARGS | METH_KEYWORDS, queuesmod_get_maxsize_doc}, - {"get_queue_defaults", _PyCFunction_CAST(queuesmod_get_queue_defaults), - METH_VARARGS | METH_KEYWORDS, queuesmod_get_queue_defaults_doc}, - {"is_full", _PyCFunction_CAST(queuesmod_is_full), - METH_VARARGS | METH_KEYWORDS, queuesmod_is_full_doc}, - {"get_count", _PyCFunction_CAST(queuesmod_get_count), - METH_VARARGS | METH_KEYWORDS, queuesmod_get_count_doc}, - {"_register_heap_types", _PyCFunction_CAST(queuesmod__register_heap_types), - METH_VARARGS | METH_KEYWORDS, NULL}, + _INTERPQUEUES_CREATE_METHODDEF + _INTERPQUEUES_DESTROY_METHODDEF + _INTERPQUEUES_LIST_ALL_METHODDEF + _INTERPQUEUES_PUT_METHODDEF + _INTERPQUEUES_GET_METHODDEF + _INTERPQUEUES_BIND_METHODDEF + _INTERPQUEUES_RELEASE_METHODDEF + _INTERPQUEUES_GET_MAXSIZE_METHODDEF + _INTERPQUEUES_GET_QUEUE_DEFAULTS_METHODDEF + _INTERPQUEUES_IS_FULL_METHODDEF + _INTERPQUEUES_GET_COUNT_METHODDEF + _INTERPQUEUES__REGISTER_HEAP_TYPES_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 27483494559..433d68d515c 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -681,40 +681,40 @@ iomodule_exec(PyObject *m) } // Base classes - ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); - ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); - ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL); + ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &_Py_nldecoder_spec, NULL); + ADD_TYPE(m, state->PyBytesIOBuffer_Type, &_Py_bytesiobuf_spec, NULL); + ADD_TYPE(m, state->PyIOBase_Type, &_Py_iobase_spec, NULL); // PyIOBase_Type subclasses - ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, + ADD_TYPE(m, state->PyTextIOBase_Type, &_Py_textiobase_spec, state->PyIOBase_Type); - ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec, + ADD_TYPE(m, state->PyBufferedIOBase_Type, &_Py_bufferediobase_spec, state->PyIOBase_Type); - ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec, + ADD_TYPE(m, state->PyRawIOBase_Type, &_Py_rawiobase_spec, state->PyIOBase_Type); // PyBufferedIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, + ADD_TYPE(m, state->PyBytesIO_Type, &_Py_bytesio_spec, state->PyBufferedIOBase_Type); + ADD_TYPE(m, state->PyBufferedWriter_Type, &_Py_bufferedwriter_spec, state->PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec, + ADD_TYPE(m, state->PyBufferedReader_Type, &_Py_bufferedreader_spec, state->PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec, + ADD_TYPE(m, state->PyBufferedRWPair_Type, &_Py_bufferedrwpair_spec, state->PyBufferedIOBase_Type); - ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, + ADD_TYPE(m, state->PyBufferedRandom_Type, &_Py_bufferedrandom_spec, state->PyBufferedIOBase_Type); // PyRawIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); + ADD_TYPE(m, state->PyFileIO_Type, &_Py_fileio_spec, state->PyRawIOBase_Type); #ifdef HAVE_WINDOWS_CONSOLE_IO - ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, + ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &_Py_winconsoleio_spec, state->PyRawIOBase_Type); #endif // PyTextIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, state->PyTextIOBase_Type); - ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, + ADD_TYPE(m, state->PyStringIO_Type, &_Py_stringio_spec, state->PyTextIOBase_Type); + ADD_TYPE(m, state->PyTextIOWrapper_Type, &_Py_textiowrapper_spec, state->PyTextIOBase_Type); #undef ADD_TYPE diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 18cf20edf26..4ae487c8e2a 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -9,23 +9,23 @@ #include "structmember.h" /* Type specs */ -extern PyType_Spec bufferediobase_spec; -extern PyType_Spec bufferedrandom_spec; -extern PyType_Spec bufferedreader_spec; -extern PyType_Spec bufferedrwpair_spec; -extern PyType_Spec bufferedwriter_spec; -extern PyType_Spec bytesio_spec; -extern PyType_Spec bytesiobuf_spec; -extern PyType_Spec fileio_spec; -extern PyType_Spec iobase_spec; -extern PyType_Spec nldecoder_spec; -extern PyType_Spec rawiobase_spec; -extern PyType_Spec stringio_spec; -extern PyType_Spec textiobase_spec; -extern PyType_Spec textiowrapper_spec; +extern PyType_Spec _Py_bufferediobase_spec; +extern PyType_Spec _Py_bufferedrandom_spec; +extern PyType_Spec _Py_bufferedreader_spec; +extern PyType_Spec _Py_bufferedrwpair_spec; +extern PyType_Spec _Py_bufferedwriter_spec; +extern PyType_Spec _Py_bytesio_spec; +extern PyType_Spec _Py_bytesiobuf_spec; +extern PyType_Spec _Py_fileio_spec; +extern PyType_Spec _Py_iobase_spec; +extern PyType_Spec _Py_nldecoder_spec; +extern PyType_Spec _Py_rawiobase_spec; +extern PyType_Spec _Py_stringio_spec; +extern PyType_Spec _Py_textiobase_spec; +extern PyType_Spec _Py_textiowrapper_spec; #ifdef HAVE_WINDOWS_CONSOLE_IO -extern PyType_Spec winconsoleio_spec; +extern PyType_Spec _Py_winconsoleio_spec; #endif /* These functions are used as METH_NOARGS methods, are normally called diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 25be21111b9..4602f2b42a6 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -362,16 +362,24 @@ _enter_buffered_busy(buffered *self) } #define IS_CLOSED(self) \ - (!self->buffer || \ + (!self->buffer ? 1 : \ (self->fast_closed_checks \ ? _PyFileIO_closed(self->raw) \ : buffered_closed(self))) #define CHECK_CLOSED(self, error_msg) \ - if (IS_CLOSED(self) && (Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t) == 0)) { \ - PyErr_SetString(PyExc_ValueError, error_msg); \ - return NULL; \ - } \ + do { \ + int _closed = IS_CLOSED(self); \ + if (_closed < 0) { \ + return NULL; \ + } \ + if (_closed && \ + (Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t) == 0)) \ + { \ + PyErr_SetString(PyExc_ValueError, error_msg); \ + return NULL; \ + } \ + } while (0); #define VALID_READ_BUFFER(self) \ (self->readable && self->read_end != -1) @@ -553,8 +561,8 @@ _io__Buffered_close_impl(buffered *self) if (!ENTER_BUFFERED(self)) { return NULL; } - - r = buffered_closed(self); + /* gh-138720: Use IS_CLOSED to match flush CHECK_CLOSED. */ + r = IS_CLOSED(self); if (r < 0) goto end; if (r > 0) { @@ -1026,9 +1034,6 @@ static PyObject * _io__Buffered_read1_impl(buffered *self, Py_ssize_t n) /*[clinic end generated code: output=bcc4fb4e54d103a3 input=3d0ad241aa52b36c]*/ { - Py_ssize_t have, r; - PyObject *res = NULL; - CHECK_INITIALIZED(self) if (n < 0) { n = self->buffer_size; @@ -1036,48 +1041,53 @@ _io__Buffered_read1_impl(buffered *self, Py_ssize_t n) CHECK_CLOSED(self, "read of closed file") - if (n == 0) - return PyBytes_FromStringAndSize(NULL, 0); + if (n == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } /* Return up to n bytes. If at least one byte is buffered, we only return buffered bytes. Otherwise, we do one raw read. */ - have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); + Py_ssize_t have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); if (have > 0) { n = Py_MIN(have, n); - res = _bufferedreader_read_fast(self, n); + PyObject *res = _bufferedreader_read_fast(self, n); assert(res != Py_None); return res; } - res = PyBytes_FromStringAndSize(NULL, n); - if (res == NULL) - return NULL; + if (!ENTER_BUFFERED(self)) { - Py_DECREF(res); return NULL; } + /* Flush the write buffer if necessary */ if (self->writable) { - PyObject *r = buffered_flush_and_rewind_unlocked(self); - if (r == NULL) { + PyObject *res = buffered_flush_and_rewind_unlocked(self); + if (res == NULL) { LEAVE_BUFFERED(self) - Py_DECREF(res); return NULL; } - Py_DECREF(r); + Py_DECREF(res); } _bufferedreader_reset_buf(self); - r = _bufferedreader_raw_read(self, PyBytes_AS_STRING(res), n); - LEAVE_BUFFERED(self) - if (r == -1) { - Py_DECREF(res); + + PyBytesWriter *writer = PyBytesWriter_Create(n); + if (writer == NULL) { return NULL; } - if (r == -2) + + Py_ssize_t r = _bufferedreader_raw_read(self, + PyBytesWriter_GetData(writer), n); + LEAVE_BUFFERED(self) + if (r == -1) { + PyBytesWriter_Discard(writer); + return NULL; + } + if (r == -2) { r = 0; - if (n > r) - _PyBytes_Resize(&res, r); - return res; + } + + return PyBytesWriter_FinishWithSize(writer, r); } static PyObject * @@ -1787,18 +1797,18 @@ _bufferedreader_read_fast(buffered *self, Py_ssize_t n) static PyObject * _bufferedreader_read_generic(buffered *self, Py_ssize_t n) { - PyObject *res = NULL; Py_ssize_t current_size, remaining, written; - char *out; current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); if (n <= current_size) return _bufferedreader_read_fast(self, n); - res = PyBytes_FromStringAndSize(NULL, n); - if (res == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(n); + if (writer == NULL) { goto error; - out = PyBytes_AS_STRING(res); + } + char *out = PyBytesWriter_GetData(writer); + remaining = n; written = 0; if (current_size > 0) { @@ -1827,11 +1837,9 @@ _bufferedreader_read_generic(buffered *self, Py_ssize_t n) if (r == 0 || r == -2) { /* EOF occurred or read() would block. */ if (r == 0 || written > 0) { - if (_PyBytes_Resize(&res, written)) - goto error; - return res; + return PyBytesWriter_FinishWithSize(writer, written); } - Py_DECREF(res); + PyBytesWriter_Discard(writer); Py_RETURN_NONE; } remaining -= r; @@ -1851,11 +1859,9 @@ _bufferedreader_read_generic(buffered *self, Py_ssize_t n) if (r == 0 || r == -2) { /* EOF occurred or read() would block. */ if (r == 0 || written > 0) { - if (_PyBytes_Resize(&res, written)) - goto error; - return res; + return PyBytesWriter_FinishWithSize(writer, written); } - Py_DECREF(res); + PyBytesWriter_Discard(writer); Py_RETURN_NONE; } if (remaining > r) { @@ -1874,10 +1880,10 @@ _bufferedreader_read_generic(buffered *self, Py_ssize_t n) break; } - return res; + return PyBytesWriter_Finish(writer); error: - Py_XDECREF(res); + PyBytesWriter_Discard(writer); return NULL; } @@ -2081,6 +2087,7 @@ _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer) PyObject *res = NULL; Py_ssize_t written, avail, remaining; Py_off_t offset; + int r; CHECK_INITIALIZED(self) @@ -2089,7 +2096,11 @@ _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer) /* Issue #31976: Check for closed file after acquiring the lock. Another thread could be holding the lock while closing the file. */ - if (IS_CLOSED(self)) { + r = IS_CLOSED(self); + if (r < 0) { + goto error; + } + if (r > 0) { PyErr_SetString(PyExc_ValueError, "write to closed file"); goto error; } @@ -2526,7 +2537,7 @@ static PyType_Slot bufferediobase_slots[] = { }; /* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ -PyType_Spec bufferediobase_spec = { +PyType_Spec _Py_bufferediobase_spec = { .name = "_io._BufferedIOBase", .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE), @@ -2589,7 +2600,7 @@ static PyType_Slot bufferedreader_slots[] = { {0, NULL}, }; -PyType_Spec bufferedreader_spec = { +PyType_Spec _Py_bufferedreader_spec = { .name = "_io.BufferedReader", .basicsize = sizeof(buffered), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -2647,7 +2658,7 @@ static PyType_Slot bufferedwriter_slots[] = { {0, NULL}, }; -PyType_Spec bufferedwriter_spec = { +PyType_Spec _Py_bufferedwriter_spec = { .name = "_io.BufferedWriter", .basicsize = sizeof(buffered), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -2697,7 +2708,7 @@ static PyType_Slot bufferedrwpair_slots[] = { {0, NULL}, }; -PyType_Spec bufferedrwpair_spec = { +PyType_Spec _Py_bufferedrwpair_spec = { .name = "_io.BufferedRWPair", .basicsize = sizeof(rwpair), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -2765,7 +2776,7 @@ static PyType_Slot bufferedrandom_slots[] = { {0, NULL}, }; -PyType_Spec bufferedrandom_spec = { +PyType_Spec _Py_bufferedrandom_spec = { .name = "_io.BufferedRandom", .basicsize = sizeof(buffered), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 30d61f9d68e..96611823ab6 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -436,6 +436,13 @@ read_bytes_lock_held(bytesio *self, Py_ssize_t size) return Py_NewRef(self->buf); } + /* gh-141311: Avoid undefined behavior when self->pos (limit PY_SSIZE_T_MAX) + is beyond the size of self->buf. Assert above validates size is always in + bounds. When self->pos is out of bounds calling code sets size to 0. */ + if (size == 0) { + return PyBytes_FromStringAndSize(NULL, 0); + } + output = PyBytes_AS_STRING(self->buf) + self->pos; self->pos += size; return PyBytes_FromStringAndSize(output, size); @@ -609,11 +616,14 @@ _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer) n = self->string_size - self->pos; if (len > n) { len = n; - if (len < 0) - len = 0; + if (len < 0) { + /* gh-141311: Avoid undefined behavior when self->pos (limit + PY_SSIZE_T_MAX) points beyond the size of self->buf. */ + return PyLong_FromSsize_t(0); + } } - assert(self->pos + len < PY_SSIZE_T_MAX); + assert(self->pos + len <= PY_SSIZE_T_MAX); assert(len >= 0); memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len); self->pos += len; @@ -1156,7 +1166,7 @@ static PyType_Slot bytesio_slots[] = { {0, NULL}, }; -PyType_Spec bytesio_spec = { +PyType_Spec _Py_bytesio_spec = { .name = "_io.BytesIO", .basicsize = sizeof(bytesio), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -1246,7 +1256,7 @@ static PyType_Slot bytesiobuf_slots[] = { {0, NULL}, }; -PyType_Spec bytesiobuf_spec = { +PyType_Spec _Py_bytesiobuf_spec = { .name = "_io._BytesIOBuffer", .basicsize = sizeof(bytesiobuf), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 04870b1c890..96c31ce8d6f 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -277,15 +277,19 @@ PyDoc_STRVAR(_io_FileIO_readall__doc__, "data is available (EAGAIN is returned before bytes are read) returns None."); #define _IO_FILEIO_READALL_METHODDEF \ - {"readall", (PyCFunction)_io_FileIO_readall, METH_NOARGS, _io_FileIO_readall__doc__}, + {"readall", _PyCFunction_CAST(_io_FileIO_readall), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_readall__doc__}, static PyObject * -_io_FileIO_readall_impl(fileio *self); +_io_FileIO_readall_impl(fileio *self, PyTypeObject *cls); static PyObject * -_io_FileIO_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) +_io_FileIO_readall(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io_FileIO_readall_impl((fileio *)self); + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "readall() takes no arguments"); + return NULL; + } + return _io_FileIO_readall_impl((fileio *)self, cls); } PyDoc_STRVAR(_io_FileIO_read__doc__, @@ -543,4 +547,4 @@ _io_FileIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=1902fac9e39358aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2e48f3df2f189170 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index c0b6c642518..5d7741fdd83 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -70,6 +70,7 @@ typedef struct { unsigned int writable : 1; unsigned int appending : 1; signed int seekable : 2; /* -1 means unknown */ + unsigned int truncate : 1; unsigned int closefd : 1; char finalizing; /* Stat result which was grabbed at file open, useful for optimizing common @@ -209,6 +210,7 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) self->writable = 0; self->appending = 0; self->seekable = -1; + self->truncate = 0; self->stat_atopen = NULL; self->closefd = 1; self->weakreflist = NULL; @@ -341,6 +343,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, goto bad_mode; rwa = 1; self->writable = 1; + self->truncate = 1; flags |= O_CREAT | O_TRUNC; break; case 'a': @@ -725,6 +728,9 @@ new_buffersize(fileio *self, size_t currentsize) @permit_long_docstring_body _io.FileIO.readall + cls: defining_class + / + Read all data from the file, returned as bytes. Reads until either there is an error or read() returns size 0 (indicates EOF). @@ -735,11 +741,11 @@ data is available (EAGAIN is returned before bytes are read) returns None. [clinic start generated code]*/ static PyObject * -_io_FileIO_readall_impl(fileio *self) -/*[clinic end generated code: output=faa0292b213b4022 input=10d8b2ec403302dc]*/ +_io_FileIO_readall_impl(fileio *self, PyTypeObject *cls) +/*[clinic end generated code: output=d546737ec895c462 input=cecda40bf9961299]*/ { Py_off_t pos, end; - PyObject *result; + PyBytesWriter *writer; Py_ssize_t bytes_read = 0; Py_ssize_t n; size_t bufsize; @@ -747,6 +753,10 @@ _io_FileIO_readall_impl(fileio *self) if (self->fd < 0) { return err_closed(); } + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } if (self->stat_atopen != NULL && self->stat_atopen->st_size < _PY_READ_MAX) { end = (Py_off_t)self->stat_atopen->st_size; @@ -794,10 +804,10 @@ _io_FileIO_readall_impl(fileio *self) } } - - result = PyBytes_FromStringAndSize(NULL, bufsize); - if (result == NULL) + writer = PyBytesWriter_Create(bufsize); + if (writer == NULL) { return NULL; + } while (1) { if (bytes_read >= (Py_ssize_t)bufsize) { @@ -806,18 +816,18 @@ _io_FileIO_readall_impl(fileio *self) PyErr_SetString(PyExc_OverflowError, "unbounded read returned more bytes " "than a Python bytes object can hold"); - Py_DECREF(result); + PyBytesWriter_Discard(writer); return NULL; } - if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) { - if (_PyBytes_Resize(&result, bufsize) < 0) + if (PyBytesWriter_GetSize(writer) < (Py_ssize_t)bufsize) { + if (PyBytesWriter_Resize(writer, bufsize) < 0) return NULL; } } n = _Py_read(self->fd, - PyBytes_AS_STRING(result) + bytes_read, + (char*)PyBytesWriter_GetData(writer) + bytes_read, bufsize - bytes_read); if (n == 0) @@ -827,20 +837,16 @@ _io_FileIO_readall_impl(fileio *self) PyErr_Clear(); if (bytes_read > 0) break; - Py_DECREF(result); + PyBytesWriter_Discard(writer); Py_RETURN_NONE; } - Py_DECREF(result); + PyBytesWriter_Discard(writer); return NULL; } bytes_read += n; } - if (PyBytes_GET_SIZE(result) > bytes_read) { - if (_PyBytes_Resize(&result, bytes_read) < 0) - return NULL; - } - return result; + return PyBytesWriter_FinishWithSize(writer, bytes_read); } /*[clinic input] @@ -866,10 +872,6 @@ static PyObject * _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) /*[clinic end generated code: output=bbd749c7c224143e input=752d1ad3db8564a5]*/ { - char *ptr; - Py_ssize_t n; - PyObject *bytes; - if (self->fd < 0) return err_closed(); if (!self->readable) { @@ -878,22 +880,23 @@ _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) } if (size < 0) - return _io_FileIO_readall_impl(self); + return _io_FileIO_readall_impl(self, cls); if (size > _PY_READ_MAX) { size = _PY_READ_MAX; } - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - ptr = PyBytes_AS_STRING(bytes); + } + char *ptr = PyBytesWriter_GetData(writer); - n = _Py_read(self->fd, ptr, size); + Py_ssize_t n = _Py_read(self->fd, ptr, size); if (n == -1) { - /* copy errno because Py_DECREF() can indirectly modify it */ + // copy errno because PyBytesWriter_Discard() can indirectly modify it int err = errno; - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); if (err == EAGAIN) { PyErr_Clear(); Py_RETURN_NONE; @@ -901,14 +904,7 @@ _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) return NULL; } - if (n != size) { - if (_PyBytes_Resize(&bytes, n) < 0) { - Py_CLEAR(bytes); - return NULL; - } - } - - return (PyObject *) bytes; + return PyBytesWriter_FinishWithSize(writer, n); } /*[clinic input] @@ -1159,10 +1155,17 @@ mode_string(fileio *self) return "ab"; } else if (self->readable) { - if (self->writable) - return "rb+"; - else + if (self->writable) { + if (self->truncate) { + return "wb+"; + } + else { + return "rb+"; + } + } + else { return "rb"; + } } else return "wb"; @@ -1333,7 +1336,7 @@ static PyType_Slot fileio_slots[] = { {0, NULL}, }; -PyType_Spec fileio_spec = { +PyType_Spec _Py_fileio_spec = { .name = "_io.FileIO", .basicsize = sizeof(fileio), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index aa373f6fdcb..f036ea503b1 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -885,7 +885,7 @@ static PyType_Slot iobase_slots[] = { {0, NULL}, }; -PyType_Spec iobase_spec = { +PyType_Spec _Py_iobase_spec = { .name = "_io._IOBase", .basicsize = sizeof(iobase), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -927,26 +927,33 @@ _io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n) return PyObject_CallMethodNoArgs(self, &_Py_ID(readall)); } - /* TODO: allocate a bytes object directly instead and manually construct - a writable memoryview pointing to it. */ b = PyByteArray_FromStringAndSize(NULL, n); - if (b == NULL) + if (b == NULL) { return NULL; + } res = PyObject_CallMethodObjArgs(self, &_Py_ID(readinto), b, NULL); if (res == NULL || res == Py_None) { - Py_DECREF(b); - return res; + goto cleanup; } - n = PyNumber_AsSsize_t(res, PyExc_ValueError); - Py_DECREF(res); - if (n == -1 && PyErr_Occurred()) { - Py_DECREF(b); - return NULL; + Py_ssize_t bytes_filled = PyNumber_AsSsize_t(res, PyExc_ValueError); + Py_CLEAR(res); + if (bytes_filled == -1 && PyErr_Occurred()) { + goto cleanup; } + if (bytes_filled < 0 || bytes_filled > n) { + PyErr_Format(PyExc_ValueError, + "readinto returned %zd outside buffer size %zd", + bytes_filled, n); + goto cleanup; + } + if (PyByteArray_Resize(b, bytes_filled) < 0) { + goto cleanup; + } + res = PyObject_CallMethodNoArgs(b, &_Py_ID(take_bytes)); - res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n); +cleanup: Py_DECREF(b); return res; } @@ -962,12 +969,10 @@ static PyObject * _io__RawIOBase_readall_impl(PyObject *self) /*[clinic end generated code: output=1987b9ce929425a0 input=688874141213622a]*/ { - int r; - PyObject *chunks = PyList_New(0); - PyObject *result; - - if (chunks == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(0); + if (writer == NULL) { return NULL; + } while (1) { PyObject *data = _PyObject_CallMethod(self, &_Py_ID(read), @@ -978,21 +983,21 @@ _io__RawIOBase_readall_impl(PyObject *self) if (_PyIO_trap_eintr()) { continue; } - Py_DECREF(chunks); + PyBytesWriter_Discard(writer); return NULL; } if (data == Py_None) { - if (PyList_GET_SIZE(chunks) == 0) { - Py_DECREF(chunks); + if (PyBytesWriter_GetSize(writer) == 0) { + PyBytesWriter_Discard(writer); return data; } Py_DECREF(data); break; } if (!PyBytes_Check(data)) { - Py_DECREF(chunks); Py_DECREF(data); PyErr_SetString(PyExc_TypeError, "read() should return bytes"); + PyBytesWriter_Discard(writer); return NULL; } if (PyBytes_GET_SIZE(data) == 0) { @@ -1000,16 +1005,16 @@ _io__RawIOBase_readall_impl(PyObject *self) Py_DECREF(data); break; } - r = PyList_Append(chunks, data); - Py_DECREF(data); - if (r < 0) { - Py_DECREF(chunks); + if (PyBytesWriter_WriteBytes(writer, + PyBytes_AS_STRING(data), + PyBytes_GET_SIZE(data)) < 0) { + Py_DECREF(data); + PyBytesWriter_Discard(writer); return NULL; } + Py_DECREF(data); } - result = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks); - Py_DECREF(chunks); - return result; + return PyBytesWriter_Finish(writer); } static PyObject * @@ -1041,7 +1046,7 @@ static PyType_Slot rawiobase_slots[] = { }; /* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ -PyType_Spec rawiobase_spec = { +PyType_Spec _Py_rawiobase_spec = { .name = "_io._RawIOBase", .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE), diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 20b7cfc0088..781ca4327f9 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1094,7 +1094,7 @@ static PyType_Slot stringio_slots[] = { {0, NULL}, }; -PyType_Spec stringio_spec = { +PyType_Spec _Py_stringio_spec = { .name = "_io.StringIO", .basicsize = sizeof(stringio), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index c462bd2ac57..f9881952561 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -208,7 +208,7 @@ static PyType_Slot textiobase_slots[] = { }; /* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ -PyType_Spec textiobase_spec = { +PyType_Spec _Py_textiobase_spec = { .name = "_io._TextIOBase", .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE), @@ -2845,7 +2845,7 @@ _io_TextIOWrapper_tell_impl(textio *self) current pos */ skip_bytes = (Py_ssize_t) (self->b2cratio * chars_to_skip); skip_back = 1; - assert(skip_back <= PyBytes_GET_SIZE(next_input)); + assert(skip_bytes <= PyBytes_GET_SIZE(next_input)); input = PyBytes_AS_STRING(next_input); while (skip_bytes > 0) { /* Decode up to temptative start point */ @@ -3150,6 +3150,9 @@ _io_TextIOWrapper_close_impl(textio *self) if (r > 0) { Py_RETURN_NONE; /* stream already closed */ } + if (self->detached) { + Py_RETURN_NONE; /* gh-142594 null pointer issue */ + } else { PyObject *exc = NULL; if (self->finalizing) { @@ -3352,7 +3355,7 @@ static PyType_Slot nldecoder_slots[] = { {0, NULL}, }; -PyType_Spec nldecoder_spec = { +PyType_Spec _Py_nldecoder_spec = { .name = "_io.IncrementalNewlineDecoder", .basicsize = sizeof(nldecoder_object), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -3404,7 +3407,7 @@ static PyGetSetDef textiowrapper_getset[] = { {NULL} }; -PyType_Slot textiowrapper_slots[] = { +static PyType_Slot textiowrapper_slots[] = { {Py_tp_dealloc, textiowrapper_dealloc}, {Py_tp_repr, textiowrapper_repr}, {Py_tp_doc, (void *)_io_TextIOWrapper___init____doc__}, @@ -3418,7 +3421,7 @@ PyType_Slot textiowrapper_slots[] = { {0, NULL}, }; -PyType_Spec textiowrapper_spec = { +PyType_Spec _Py_textiowrapper_spec = { .name = "_io.TextIOWrapper", .basicsize = sizeof(textio), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 950b7fe241c..677d7e85d4e 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -1253,7 +1253,7 @@ static PyType_Slot winconsoleio_slots[] = { {0, NULL}, }; -PyType_Spec winconsoleio_spec = { +PyType_Spec _Py_winconsoleio_spec = { .name = "_io._WindowsConsoleIO", .basicsize = sizeof(winconsoleio), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | diff --git a/Modules/_json.c b/Modules/_json.c index e1d6042cb78..14714d4b346 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -10,6 +10,7 @@ #include "Python.h" #include "pycore_ceval.h" // _Py_EnterRecursiveCall() +#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST() #include "pycore_global_strings.h" // _Py_ID() #include "pycore_pyerrors.h" // _PyErr_FormatNote #include "pycore_runtime.h" // _PyRuntime @@ -17,6 +18,12 @@ #include <stdbool.h> // bool +#include "clinic/_json.c.h" + +/*[clinic input] +module _json +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=549fa53592c925b2]*/ typedef struct _PyScannerObject { PyObject_HEAD @@ -636,89 +643,62 @@ bail: return NULL; } -PyDoc_STRVAR(pydoc_scanstring, - "scanstring(string, end, strict=True) -> (string, end)\n" - "\n" - "Scan the string s for a JSON string. End is the index of the\n" - "character in s after the quote that started the JSON string.\n" - "Unescapes all valid JSON string escape sequences and raises ValueError\n" - "on attempt to decode an invalid string. If strict is False then literal\n" - "control characters are allowed in the string.\n" - "\n" - "Returns a tuple of the decoded string and the index of the character in s\n" - "after the end quote." -); +/*[clinic input] +_json.scanstring as py_scanstring + pystr: unicode + end: Py_ssize_t + strict: bool = True + / + +Scan the string s for a JSON string. + +End is the index of the character in s after the quote that started the +JSON string. Unescapes all valid JSON string escape sequences and raises +ValueError on attempt to decode an invalid string. If strict is False +then literal control characters are allowed in the string. + +Returns a tuple of the decoded string and the index of the character in s +after the end quote. +[clinic start generated code]*/ static PyObject * -py_scanstring(PyObject* Py_UNUSED(self), PyObject *args) +py_scanstring_impl(PyObject *module, PyObject *pystr, Py_ssize_t end, + int strict) +/*[clinic end generated code: output=961740cfae07cdb3 input=cff59e47498f4d8e]*/ { - PyObject *pystr; - PyObject *rval; - Py_ssize_t end; Py_ssize_t next_end = -1; - int strict = 1; - if (!PyArg_ParseTuple(args, "On|p:scanstring", &pystr, &end, &strict)) { - return NULL; - } - if (PyUnicode_Check(pystr)) { - rval = scanstring_unicode(pystr, end, strict, &next_end); - } - else { - PyErr_Format(PyExc_TypeError, - "first argument must be a string, not %.80s", - Py_TYPE(pystr)->tp_name); - return NULL; - } + PyObject *rval = scanstring_unicode(pystr, end, strict, &next_end); return _build_rval_index_tuple(rval, next_end); } -PyDoc_STRVAR(pydoc_encode_basestring_ascii, - "encode_basestring_ascii(string) -> string\n" - "\n" - "Return an ASCII-only JSON representation of a Python string" -); +/*[clinic input] +_json.encode_basestring_ascii as py_encode_basestring_ascii + pystr: unicode + / + +Return an ASCII-only JSON representation of a Python string +[clinic start generated code]*/ static PyObject * -py_encode_basestring_ascii(PyObject* Py_UNUSED(self), PyObject *pystr) +py_encode_basestring_ascii_impl(PyObject *module, PyObject *pystr) +/*[clinic end generated code: output=7b3841287cf211df input=4f3609498aff2de5]*/ { - PyObject *rval; - /* Return an ASCII-only JSON representation of a Python string */ - /* METH_O */ - if (PyUnicode_Check(pystr)) { - rval = ascii_escape_unicode(pystr); - } - else { - PyErr_Format(PyExc_TypeError, - "first argument must be a string, not %.80s", - Py_TYPE(pystr)->tp_name); - return NULL; - } - return rval; + return ascii_escape_unicode(pystr); } +/*[clinic input] +_json.encode_basestring as py_encode_basestring + pystr: unicode + / -PyDoc_STRVAR(pydoc_encode_basestring, - "encode_basestring(string) -> string\n" - "\n" - "Return a JSON representation of a Python string" -); +Return a JSON representation of a Python string +[clinic start generated code]*/ static PyObject * -py_encode_basestring(PyObject* Py_UNUSED(self), PyObject *pystr) +py_encode_basestring_impl(PyObject *module, PyObject *pystr) +/*[clinic end generated code: output=900950f95df3f1c9 input=d42ef714b2c07386]*/ { - PyObject *rval; - /* Return a JSON representation of a Python string */ - /* METH_O */ - if (PyUnicode_Check(pystr)) { - rval = escape_unicode(pystr); - } - else { - PyErr_Format(PyExc_TypeError, - "first argument must be a string, not %.80s", - Py_TYPE(pystr)->tp_name); - return NULL; - } - return rval; + return escape_unicode(pystr); } static void @@ -1456,7 +1436,7 @@ write_newline_indent(PyUnicodeWriter *writer, static PyObject * encoder_call(PyObject *op, PyObject *args, PyObject *kwds) { - /* Python callable interface to encode_listencode_obj */ + /* Python callable interface to encoder_listencode_obj */ static char *kwlist[] = {"obj", "_current_indent_level", NULL}; PyObject *obj; Py_ssize_t indent_level; @@ -1743,15 +1723,84 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs return 0; } +static inline int +_encoder_iterate_mapping_lock_held(PyEncoderObject *s, PyUnicodeWriter *writer, + bool *first, PyObject *dct, PyObject *items, + Py_ssize_t indent_level, PyObject *indent_cache, + PyObject *separator) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(items); + PyObject *key, *value; + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(items); i++) { + PyObject *item = PyList_GET_ITEM(items, i); +#ifdef Py_GIL_DISABLED + // gh-119438: in the free-threading build the critical section on items can get suspended + Py_INCREF(item); +#endif + if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) { + PyErr_SetString(PyExc_ValueError, "items must return 2-tuples"); +#ifdef Py_GIL_DISABLED + Py_DECREF(item); +#endif + return -1; + } + + key = PyTuple_GET_ITEM(item, 0); + value = PyTuple_GET_ITEM(item, 1); + if (encoder_encode_key_value(s, writer, first, dct, key, value, + indent_level, indent_cache, + separator) < 0) { +#ifdef Py_GIL_DISABLED + Py_DECREF(item); +#endif + return -1; + } +#ifdef Py_GIL_DISABLED + Py_DECREF(item); +#endif + } + + return 0; +} + +static inline int +_encoder_iterate_dict_lock_held(PyEncoderObject *s, PyUnicodeWriter *writer, + bool *first, PyObject *dct, Py_ssize_t indent_level, + PyObject *indent_cache, PyObject *separator) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dct); + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(dct, &pos, &key, &value)) { +#ifdef Py_GIL_DISABLED + // gh-119438: in the free-threading build the critical section on dct can get suspended + Py_INCREF(key); + Py_INCREF(value); +#endif + if (encoder_encode_key_value(s, writer, first, dct, key, value, + indent_level, indent_cache, + separator) < 0) { +#ifdef Py_GIL_DISABLED + Py_DECREF(key); + Py_DECREF(value); +#endif + return -1; + } +#ifdef Py_GIL_DISABLED + Py_DECREF(key); + Py_DECREF(value); +#endif + } + return 0; +} + static int encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, - PyObject *dct, + PyObject *dct, Py_ssize_t indent_level, PyObject *indent_cache) { /* Encode Python dict dct a JSON term */ PyObject *ident = NULL; - PyObject *items = NULL; - PyObject *key, *value; bool first = true; if (PyDict_GET_SIZE(dct) == 0) { @@ -1788,34 +1837,30 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, } if (s->sort_keys || !PyDict_CheckExact(dct)) { - items = PyMapping_Items(dct); - if (items == NULL || (s->sort_keys && PyList_Sort(items) < 0)) + PyObject *items = PyMapping_Items(dct); + if (items == NULL || (s->sort_keys && PyList_Sort(items) < 0)) { + Py_XDECREF(items); + goto bail; + } + + int result; + Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST(items); + result = _encoder_iterate_mapping_lock_held(s, writer, &first, dct, + items, indent_level, indent_cache, separator); + Py_END_CRITICAL_SECTION_SEQUENCE_FAST(); + Py_DECREF(items); + if (result < 0) { goto bail; - - for (Py_ssize_t i = 0; i < PyList_GET_SIZE(items); i++) { - PyObject *item = PyList_GET_ITEM(items, i); - - if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) { - PyErr_SetString(PyExc_ValueError, "items must return 2-tuples"); - goto bail; - } - - key = PyTuple_GET_ITEM(item, 0); - value = PyTuple_GET_ITEM(item, 1); - if (encoder_encode_key_value(s, writer, &first, dct, key, value, - indent_level, indent_cache, - separator) < 0) - goto bail; } - Py_CLEAR(items); } else { - Py_ssize_t pos = 0; - while (PyDict_Next(dct, &pos, &key, &value)) { - if (encoder_encode_key_value(s, writer, &first, dct, key, value, - indent_level, indent_cache, - separator) < 0) - goto bail; + int result; + Py_BEGIN_CRITICAL_SECTION(dct); + result = _encoder_iterate_dict_lock_held(s, writer, &first, dct, + indent_level, indent_cache, separator); + Py_END_CRITICAL_SECTION(); + if (result < 0) { + goto bail; } } @@ -1837,11 +1882,43 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, return 0; bail: - Py_XDECREF(items); Py_XDECREF(ident); return -1; } +static inline int +_encoder_iterate_fast_seq_lock_held(PyEncoderObject *s, PyUnicodeWriter *writer, + PyObject *seq, PyObject *s_fast, + Py_ssize_t indent_level, PyObject *indent_cache, PyObject *separator) +{ + for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(s_fast); i++) { + PyObject *obj = PySequence_Fast_GET_ITEM(s_fast, i); +#ifdef Py_GIL_DISABLED + // gh-119438: in the free-threading build the critical section on s_fast can get suspended + Py_INCREF(obj); +#endif + if (i) { + if (PyUnicodeWriter_WriteStr(writer, separator) < 0) { +#ifdef Py_GIL_DISABLED + Py_DECREF(obj); +#endif + return -1; + } + } + if (encoder_listencode_obj(s, writer, obj, indent_level, indent_cache)) { + _PyErr_FormatNote("when serializing %T item %zd", seq, i); +#ifdef Py_GIL_DISABLED + Py_DECREF(obj); +#endif + return -1; + } +#ifdef Py_GIL_DISABLED + Py_DECREF(obj); +#endif + } + return 0; +} + static int encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *seq, @@ -1849,10 +1926,8 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, { PyObject *ident = NULL; PyObject *s_fast = NULL; - Py_ssize_t i; - ident = NULL; - s_fast = PySequence_Fast(seq, "_iterencode_list needs a sequence"); + s_fast = PySequence_Fast(seq, "encoder_listencode_list needs a sequence"); if (s_fast == NULL) return -1; if (PySequence_Fast_GET_SIZE(s_fast) == 0) { @@ -1890,16 +1965,13 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, goto bail; } } - for (i = 0; i < PySequence_Fast_GET_SIZE(s_fast); i++) { - PyObject *obj = PySequence_Fast_GET_ITEM(s_fast, i); - if (i) { - if (PyUnicodeWriter_WriteStr(writer, separator) < 0) - goto bail; - } - if (encoder_listencode_obj(s, writer, obj, indent_level, indent_cache)) { - _PyErr_FormatNote("when serializing %T item %zd", seq, i); - goto bail; - } + int result; + Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST(seq); + result = _encoder_iterate_fast_seq_lock_held(s, writer, seq, s_fast, + indent_level, indent_cache, separator); + Py_END_CRITICAL_SECTION_SEQUENCE_FAST(); + if (result < 0) { + goto bail; } if (ident != NULL) { if (PyDict_DelItem(s->markers, ident)) @@ -1987,18 +2059,9 @@ static PyType_Spec PyEncoderType_spec = { }; static PyMethodDef speedups_methods[] = { - {"encode_basestring_ascii", - py_encode_basestring_ascii, - METH_O, - pydoc_encode_basestring_ascii}, - {"encode_basestring", - py_encode_basestring, - METH_O, - pydoc_encode_basestring}, - {"scanstring", - py_scanstring, - METH_VARARGS, - pydoc_scanstring}, + PY_ENCODE_BASESTRING_ASCII_METHODDEF + PY_ENCODE_BASESTRING_METHODDEF + PY_SCANSTRING_METHODDEF {NULL, NULL, 0, NULL} }; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 17b5220fd6f..7174eebd0c9 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -455,35 +455,72 @@ _locale_strxfrm_impl(PyObject *module, PyObject *str) goto exit; } - /* assume no change in size, first */ - n1 = n1 + 1; - buf = PyMem_New(wchar_t, n1); - if (!buf) { - PyErr_NoMemory(); - goto exit; - } errno = 0; - n2 = wcsxfrm(buf, s, n1); + n2 = wcsxfrm(NULL, s, 0); if (errno && errno != ERANGE) { PyErr_SetFromErrno(PyExc_OSError); goto exit; } - if (n2 >= (size_t)n1) { - /* more space needed */ - wchar_t * new_buf = PyMem_Realloc(buf, (n2+1)*sizeof(wchar_t)); - if (!new_buf) { - PyErr_NoMemory(); - goto exit; + buf = PyMem_New(wchar_t, n2+1); + if (!buf) { + PyErr_NoMemory(); + goto exit; + } + + errno = 0; + n2 = wcsxfrm(buf, s, n2+1); + if (errno) { + PyErr_SetFromErrno(PyExc_OSError); + goto exit; + } + /* The result is just a sequence of integers, they are not necessary + Unicode code points, so PyUnicode_FromWideChar() cannot be used + here. For example, 0xD83D 0xDC0D should not be larger than 0xFF41. + */ +#if SIZEOF_WCHAR_T == 4 + { + /* Some codes can exceed the range of Unicode code points + (0 - 0x10FFFF), so they cannot be directly used in + PyUnicode_FromKindAndData(). They should be first encoded in + a way that preserves the lexicographical order. + + Codes in the range 0-0xFFFF represent themself. + Codes larger than 0xFFFF are encoded as a pair: + * 0x1xxxx -- the highest 16 bits + * 0x0xxxx -- the lowest 16 bits + */ + size_t n3 = 0; + for (size_t i = 0; i < n2; i++) { + if ((Py_UCS4)buf[i] > 0x10000u) { + n3++; + } } - buf = new_buf; - errno = 0; - n2 = wcsxfrm(buf, s, n2+1); - if (errno) { - PyErr_SetFromErrno(PyExc_OSError); + if (n3) { + n3 += n2; // no integer overflow + Py_UCS4 *buf2 = PyMem_New(Py_UCS4, n3); + if (buf2 == NULL) { + PyErr_NoMemory(); + goto exit; + } + size_t j = 0; + for (size_t i = 0; i < n2; i++) { + Py_UCS4 c = (Py_UCS4)buf[i]; + if (c > 0x10000u) { + buf2[j++] = (c >> 16) | 0x10000u; + buf2[j++] = c & 0xFFFFu; + } + else { + buf2[j++] = c; + } + } + assert(j == n3); + result = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf2, n3); + PyMem_Free(buf2); goto exit; } } - result = PyUnicode_FromWideChar(buf, n2); +#endif + result = PyUnicode_FromKindAndData(sizeof(wchar_t), buf, n2); exit: PyMem_Free(buf); PyMem_Free(s); diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index d0074b2a0d1..025a3fac46e 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -6,7 +6,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SetProfile() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_time.h" // _PyTime_FromLong() +#include "pycore_time.h" // _PyTime_FromSecondsObject() #include "pycore_typeobject.h" // _PyType_GetModuleState() #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() @@ -111,7 +111,7 @@ static PyTime_t CallExternalTimer(ProfilerObject *pObj) if (pObj->externalTimerUnit > 0.0) { /* interpret the result as an integer that will be scaled in profiler_getstats() */ - err = _PyTime_FromLong(&result, o); + err = PyLong_AsInt64(o, &result); } else { /* interpret the result as a double measured in seconds. @@ -534,6 +534,7 @@ static int statsForEntry(rotating_node_t *node, void *arg) } /*[clinic input] +@critical_section _lsprof.Profiler.getstats cls: defining_class @@ -565,7 +566,7 @@ profiler_subentry objects: static PyObject * _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls) -/*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/ +/*[clinic end generated code: output=1806ef720019ee03 input=3dc69eb85ed73d91]*/ { statscollector_t collect; collect.state = _PyType_GetModuleState(cls); @@ -613,6 +614,7 @@ setBuiltins(ProfilerObject *pObj, int nvalue) } /*[clinic input] +@critical_section _lsprof.Profiler._pystart_callback code: object @@ -624,7 +626,7 @@ _lsprof.Profiler._pystart_callback static PyObject * _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, PyObject *instruction_offset) -/*[clinic end generated code: output=5fec8b7ad5ed25e8 input=b166e6953c579cda]*/ +/*[clinic end generated code: output=5fec8b7ad5ed25e8 input=b61a0e79cf1f8499]*/ { ptrace_enter_call((PyObject*)self, (void *)code, code); @@ -632,6 +634,7 @@ _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, } /*[clinic input] +@critical_section _lsprof.Profiler._pythrow_callback code: object @@ -645,7 +648,7 @@ static PyObject * _lsprof_Profiler__pythrow_callback_impl(ProfilerObject *self, PyObject *code, PyObject *instruction_offset, PyObject *exception) -/*[clinic end generated code: output=0a32988919dfb94c input=fd728fc2c074f5e6]*/ +/*[clinic end generated code: output=0a32988919dfb94c input=60c7f272206d3758]*/ { ptrace_enter_call((PyObject*)self, (void *)code, code); @@ -653,6 +656,7 @@ _lsprof_Profiler__pythrow_callback_impl(ProfilerObject *self, PyObject *code, } /*[clinic input] +@critical_section _lsprof.Profiler._pyreturn_callback code: object @@ -667,7 +671,7 @@ _lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, PyObject *code, PyObject *instruction_offset, PyObject *retval) -/*[clinic end generated code: output=9e2f6fc1b882c51e input=667ffaeb2fa6fd1f]*/ +/*[clinic end generated code: output=9e2f6fc1b882c51e input=0ddcc1ec53faa928]*/ { ptrace_leave_call((PyObject*)self, (void *)code); @@ -703,6 +707,7 @@ PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObje } /*[clinic input] +@critical_section _lsprof.Profiler._ccall_callback code: object @@ -717,7 +722,7 @@ static PyObject * _lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, PyObject *instruction_offset, PyObject *callable, PyObject *self_arg) -/*[clinic end generated code: output=152db83cabd18cad input=0e66687cfb95c001]*/ +/*[clinic end generated code: output=152db83cabd18cad input=2fc1e0630ee5e32b]*/ { if (self->flags & POF_BUILTINS) { PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); @@ -733,6 +738,7 @@ _lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, } /*[clinic input] +@critical_section _lsprof.Profiler._creturn_callback code: object @@ -748,7 +754,7 @@ _lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, PyObject *code, PyObject *instruction_offset, PyObject *callable, PyObject *self_arg) -/*[clinic end generated code: output=1e886dde8fed8fb0 input=b18afe023746923a]*/ +/*[clinic end generated code: output=1e886dde8fed8fb0 input=bdc246d6b5b8714a]*/ { if (self->flags & POF_BUILTINS) { PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); @@ -780,6 +786,7 @@ static const struct { /*[clinic input] +@critical_section _lsprof.Profiler.enable subcalls: bool = True @@ -796,7 +803,7 @@ Start collecting profiling information. static PyObject * _lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, int builtins) -/*[clinic end generated code: output=1e747f9dc1edd571 input=9ab81405107ab7f1]*/ +/*[clinic end generated code: output=1e747f9dc1edd571 input=0b88115b1c796173]*/ { int all_events = 0; if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { @@ -869,6 +876,7 @@ flush_unmatched(ProfilerObject *pObj) /*[clinic input] +@critical_section _lsprof.Profiler.disable Stop collecting profiling information. @@ -876,7 +884,7 @@ Stop collecting profiling information. static PyObject * _lsprof_Profiler_disable_impl(ProfilerObject *self) -/*[clinic end generated code: output=838cffef7f651870 input=05700b3fc68d1f50]*/ +/*[clinic end generated code: output=838cffef7f651870 input=f7e4787cae20f7f6]*/ { if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, @@ -928,6 +936,7 @@ _lsprof_Profiler_disable_impl(ProfilerObject *self) } /*[clinic input] +@critical_section _lsprof.Profiler.clear Clear all profiling information collected so far. @@ -935,7 +944,7 @@ Clear all profiling information collected so far. static PyObject * _lsprof_Profiler_clear_impl(ProfilerObject *self) -/*[clinic end generated code: output=dd1c668fb84b1335 input=fbe1f88c28be4f98]*/ +/*[clinic end generated code: output=dd1c668fb84b1335 input=4aab219d5d7a9bec]*/ { if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 0b0b1bc765b..58766233998 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -72,13 +72,6 @@ OutputBuffer_OnError(_BlocksOutputBuffer *buffer) } -#define ACQUIRE_LOCK(obj) do { \ - if (!PyThread_acquire_lock((obj)->lock, 0)) { \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock((obj)->lock, 1); \ - Py_END_ALLOW_THREADS \ - } } while (0) -#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock) typedef struct { PyTypeObject *lzma_compressor_type; @@ -111,7 +104,7 @@ typedef struct { lzma_allocator alloc; lzma_stream lzs; int flushed; - PyThread_type_lock lock; + PyMutex mutex; } Compressor; typedef struct { @@ -124,7 +117,7 @@ typedef struct { char needs_input; uint8_t *input_buffer; size_t input_buffer_size; - PyThread_type_lock lock; + PyMutex mutex; } Decompressor; #define Compressor_CAST(op) ((Compressor *)(op)) @@ -554,7 +547,7 @@ static PyObject * compress(Compressor *c, uint8_t *data, size_t len, lzma_action action) { PyObject *result; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; _lzma_state *state = PyType_GetModuleState(Py_TYPE(c)); assert(state != NULL); @@ -617,14 +610,14 @@ _lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data) { PyObject *result = NULL; - ACQUIRE_LOCK(self); + PyMutex_Lock(&self->mutex); if (self->flushed) { PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); } else { result = compress(self, data->buf, data->len, LZMA_RUN); } - RELEASE_LOCK(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -644,14 +637,14 @@ _lzma_LZMACompressor_flush_impl(Compressor *self) { PyObject *result = NULL; - ACQUIRE_LOCK(self); + PyMutex_Lock(&self->mutex); if (self->flushed) { PyErr_SetString(PyExc_ValueError, "Repeated call to flush()"); } else { self->flushed = 1; result = compress(self, NULL, 0, LZMA_FINISH); } - RELEASE_LOCK(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -820,12 +813,7 @@ Compressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) self->alloc.free = PyLzma_Free; self->lzs.allocator = &self->alloc; - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - Py_DECREF(self); - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return NULL; - } + self->mutex = (PyMutex){0}; self->flushed = 0; switch (format) { @@ -867,10 +855,8 @@ static void Compressor_dealloc(PyObject *op) { Compressor *self = Compressor_CAST(op); + assert(!PyMutex_IsLocked(&self->mutex)); lzma_end(&self->lzs); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); - } PyTypeObject *tp = Py_TYPE(self); tp->tp_free(self); Py_DECREF(tp); @@ -882,13 +868,6 @@ static PyMethodDef Compressor_methods[] = { {NULL} }; -static int -Compressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - PyDoc_STRVAR(Compressor_doc, "LZMACompressor(format=FORMAT_XZ, check=-1, preset=None, filters=None)\n" "\n" @@ -922,7 +901,6 @@ static PyType_Slot lzma_compressor_type_slots[] = { {Py_tp_methods, Compressor_methods}, {Py_tp_new, Compressor_new}, {Py_tp_doc, (char *)Compressor_doc}, - {Py_tp_traverse, Compressor_traverse}, {0, 0} }; @@ -948,7 +926,7 @@ decompress_buf(Decompressor *d, Py_ssize_t max_length) { PyObject *result; lzma_stream *lzs = &d->lzs; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; _lzma_state *state = PyType_GetModuleState(Py_TYPE(d)); assert(state != NULL); @@ -1154,12 +1132,12 @@ _lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data, { PyObject *result = NULL; - ACQUIRE_LOCK(self); + PyMutex_Lock(&self->mutex); if (self->eof) PyErr_SetString(PyExc_EOFError, "Already at end of stream"); else result = decompress(self, data->buf, data->len, max_length); - RELEASE_LOCK(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -1252,21 +1230,13 @@ _lzma_LZMADecompressor_impl(PyTypeObject *type, int format, self->lzs.allocator = &self->alloc; self->lzs.next_in = NULL; - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - Py_DECREF(self); - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return NULL; - } + self->mutex = (PyMutex){0}; self->check = LZMA_CHECK_UNKNOWN; self->needs_input = 1; self->input_buffer = NULL; self->input_buffer_size = 0; - Py_XSETREF(self->unused_data, PyBytes_FromStringAndSize(NULL, 0)); - if (self->unused_data == NULL) { - goto error; - } + Py_XSETREF(self->unused_data, Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)); switch (format) { case FORMAT_AUTO: @@ -1315,26 +1285,18 @@ static void Decompressor_dealloc(PyObject *op) { Decompressor *self = Decompressor_CAST(op); + assert(!PyMutex_IsLocked(&self->mutex)); + if(self->input_buffer != NULL) PyMem_Free(self->input_buffer); lzma_end(&self->lzs); Py_CLEAR(self->unused_data); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); - } PyTypeObject *tp = Py_TYPE(self); tp->tp_free(self); Py_DECREF(tp); } -static int -Decompressor_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef Decompressor_methods[] = { _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF {NULL} @@ -1369,7 +1331,6 @@ static PyType_Slot lzma_decompressor_type_slots[] = { {Py_tp_methods, Decompressor_methods}, {Py_tp_new, _lzma_LZMADecompressor}, {Py_tp_doc, (char *)_lzma_LZMADecompressor__doc__}, - {Py_tp_traverse, Decompressor_traverse}, {Py_tp_members, Decompressor_members}, {0, 0} }; @@ -1445,7 +1406,7 @@ _lzma__encode_filter_properties_impl(PyObject *module, lzma_filter filter) { lzma_ret lzret; uint32_t encoded_size; - PyObject *result = NULL; + PyBytesWriter *writer = NULL; _lzma_state *state = get_lzma_state(module); assert(state != NULL); @@ -1453,20 +1414,20 @@ _lzma__encode_filter_properties_impl(PyObject *module, lzma_filter filter) if (catch_lzma_error(state, lzret)) goto error; - result = PyBytes_FromStringAndSize(NULL, encoded_size); - if (result == NULL) + writer = PyBytesWriter_Create(encoded_size); + if (writer == NULL) { goto error; + } - lzret = lzma_properties_encode( - &filter, (uint8_t *)PyBytes_AS_STRING(result)); + lzret = lzma_properties_encode(&filter, PyBytesWriter_GetData(writer)); if (catch_lzma_error(state, lzret)) { goto error; } - return result; + return PyBytesWriter_Finish(writer); error: - Py_XDECREF(result); + PyBytesWriter_Discard(writer); return NULL; } diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index cee8cf7b9a8..848784dedc1 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -109,23 +109,22 @@ static PyObject * _multiprocessing_recv_impl(PyObject *module, HANDLE handle, int size) /*[clinic end generated code: output=92322781ba9ff598 input=6a5b0834372cee5b]*/ { - int nread; - PyObject *buf; - - buf = PyBytes_FromStringAndSize(NULL, size); - if (!buf) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (!writer) { return NULL; + } + char *buf = PyBytesWriter_GetData(writer); + Py_ssize_t nread; Py_BEGIN_ALLOW_THREADS - nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0); + nread = recv((SOCKET) handle, buf, size, 0); Py_END_ALLOW_THREADS if (nread < 0) { - Py_DECREF(buf); + PyBytesWriter_Discard(writer); return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); } - _PyBytes_Resize(&buf, nread); - return buf; + return PyBytesWriter_FinishWithSize(writer, nread); } /*[clinic input] diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c index a4a2a866ccb..85cc0ac70a6 100644 --- a/Modules/_multiprocessing/semaphore.c +++ b/Modules/_multiprocessing/semaphore.c @@ -8,6 +8,7 @@ */ #include "multiprocessing.h" +#include "pycore_object.h" // _PyObject_VisitType() #ifdef HAVE_SYS_TIME_H # include <sys/time.h> // gettimeofday() @@ -720,13 +721,6 @@ _multiprocessing_SemLock___exit___impl(SemLockObject *self, return _multiprocessing_SemLock_release_impl(self); } -static int -semlock_traverse(PyObject *s, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(s)); - return 0; -} - /* * Semaphore methods */ @@ -773,7 +767,7 @@ static PyType_Slot _PyMp_SemLockType_slots[] = { {Py_tp_members, semlock_members}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, _multiprocessing_SemLock}, - {Py_tp_traverse, semlock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_free, PyObject_GC_Del}, {Py_tp_doc, (void *)PyDoc_STR("Semaphore/Mutex type")}, {0, 0}, diff --git a/Modules/_pickle.c b/Modules/_pickle.c index bc064787993..608598eb5a5 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -155,6 +155,9 @@ enum { /* Prefetch size when unpickling (disabled on unpeekable streams) */ PREFETCH = 8192 * 16, + /* Data larger that this will be read in chunks, to prevent extreme + overallocation. */ + MIN_READ_BUF_SIZE = 1 << 20, FRAME_SIZE_MIN = 4, FRAME_SIZE_TARGET = 64 * 1024, @@ -413,13 +416,6 @@ typedef struct { #define Pdata_CAST(op) ((Pdata *)(op)) -static int -Pdata_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void Pdata_dealloc(PyObject *op) { @@ -437,7 +433,7 @@ Pdata_dealloc(PyObject *op) static PyType_Slot pdata_slots[] = { {Py_tp_dealloc, Pdata_dealloc}, - {Py_tp_traverse, Pdata_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL}, }; @@ -654,10 +650,11 @@ typedef struct UnpicklerObject { Pdata *stack; /* Pickle data stack, store unpickled objects. */ /* The unpickler memo is just an array of PyObject *s. Using a dict - is unnecessary, since the keys are contiguous ints. */ + is unnecessary, since the keys usually are contiguous ints. */ PyObject **memo; size_t memo_size; /* Capacity of the memo array */ size_t memo_len; /* Number of objects in the memo */ + PyObject *memo_dict; /* The backup memo dict for non-continuous keys. */ PyObject *persistent_load; /* persistent_load() method, can be NULL. */ PyObject *persistent_load_attr; /* instance attribute, can be NULL. */ @@ -1254,141 +1251,13 @@ _Unpickler_SkipConsumed(UnpicklerObject *self) static const Py_ssize_t READ_WHOLE_LINE = -1; -/* If reading from a file, we need to only pull the bytes we need, since there - may be multiple pickle objects arranged contiguously in the same input - buffer. - - If `n` is READ_WHOLE_LINE, read a whole line. Otherwise, read up to `n` - bytes from the input stream/buffer. - - Update the unpickler's input buffer with the newly-read data. Returns -1 on - failure; on success, returns the number of bytes read from the file. - - On success, self->input_len will be 0; this is intentional so that when - unpickling from a file, the "we've run out of data" code paths will trigger, - causing the Unpickler to go back to the file for more data. Use the returned - size to tell you how much data you can process. */ +/* Don't call it directly: use _Unpickler_ReadInto() */ static Py_ssize_t -_Unpickler_ReadFromFile(UnpicklerObject *self, Py_ssize_t n) -{ - PyObject *data; - Py_ssize_t read_size; - - assert(self->read != NULL); - - if (_Unpickler_SkipConsumed(self) < 0) - return -1; - - if (n == READ_WHOLE_LINE) { - data = PyObject_CallNoArgs(self->readline); - } - else { - PyObject *len; - /* Prefetch some data without advancing the file pointer, if possible */ - if (self->peek && n < PREFETCH) { - len = PyLong_FromSsize_t(PREFETCH); - if (len == NULL) - return -1; - data = _Pickle_FastCall(self->peek, len); - if (data == NULL) { - if (!PyErr_ExceptionMatches(PyExc_NotImplementedError)) - return -1; - /* peek() is probably not supported by the given file object */ - PyErr_Clear(); - Py_CLEAR(self->peek); - } - else { - read_size = _Unpickler_SetStringInput(self, data); - Py_DECREF(data); - if (read_size < 0) { - return -1; - } - - self->prefetched_idx = 0; - if (n <= read_size) - return n; - } - } - len = PyLong_FromSsize_t(n); - if (len == NULL) - return -1; - data = _Pickle_FastCall(self->read, len); - } - if (data == NULL) - return -1; - - read_size = _Unpickler_SetStringInput(self, data); - Py_DECREF(data); - return read_size; -} - -/* Don't call it directly: use _Unpickler_Read() */ -static Py_ssize_t -_Unpickler_ReadImpl(UnpicklerObject *self, PickleState *st, char **s, Py_ssize_t n) -{ - Py_ssize_t num_read; - - *s = NULL; - if (self->next_read_idx > PY_SSIZE_T_MAX - n) { - PyErr_SetString(st->UnpicklingError, - "read would overflow (invalid bytecode)"); - return -1; - } - - /* This case is handled by the _Unpickler_Read() macro for efficiency */ - assert(self->next_read_idx + n > self->input_len); - - if (!self->read) - return bad_readline(st); - - /* Extend the buffer to satisfy desired size */ - num_read = _Unpickler_ReadFromFile(self, n); - if (num_read < 0) - return -1; - if (num_read < n) - return bad_readline(st); - *s = self->input_buffer; - self->next_read_idx = n; - return n; -} - -/* Read `n` bytes from the unpickler's data source, storing the result in `buf`. - * - * This should only be used for non-small data reads where potentially - * avoiding a copy is beneficial. This method does not try to prefetch - * more data into the input buffer. - * - * _Unpickler_Read() is recommended in most cases. - */ -static Py_ssize_t -_Unpickler_ReadInto(PickleState *state, UnpicklerObject *self, char *buf, - Py_ssize_t n) +_Unpickler_ReadIntoFromFile(PickleState *state, UnpicklerObject *self, char *buf, + Py_ssize_t n) { assert(n != READ_WHOLE_LINE); - /* Read from available buffer data, if any */ - Py_ssize_t in_buffer = self->input_len - self->next_read_idx; - if (in_buffer > 0) { - Py_ssize_t to_read = Py_MIN(in_buffer, n); - memcpy(buf, self->input_buffer + self->next_read_idx, to_read); - self->next_read_idx += to_read; - buf += to_read; - n -= to_read; - if (n == 0) { - /* Entire read was satisfied from buffer */ - return n; - } - } - - /* Read from file */ - if (!self->read) { - /* We're unpickling memory, this means the input is truncated */ - return bad_readline(state); - } - if (_Unpickler_SkipConsumed(self) < 0) { - return -1; - } - if (!self->readinto) { /* readinto() not supported on file-like object, fall back to read() * and copy into destination buffer (bpo-39681) */ @@ -1442,6 +1311,163 @@ _Unpickler_ReadInto(PickleState *state, UnpicklerObject *self, char *buf, return n; } +/* If reading from a file, we need to only pull the bytes we need, since there + may be multiple pickle objects arranged contiguously in the same input + buffer. + + If `n` is READ_WHOLE_LINE, read a whole line. Otherwise, read up to `n` + bytes from the input stream/buffer. + + Update the unpickler's input buffer with the newly-read data. Returns -1 on + failure; on success, returns the number of bytes read from the file. + + On success, self->input_len will be 0; this is intentional so that when + unpickling from a file, the "we've run out of data" code paths will trigger, + causing the Unpickler to go back to the file for more data. Use the returned + size to tell you how much data you can process. */ +static Py_ssize_t +_Unpickler_ReadFromFile(PickleState *state, UnpicklerObject *self, Py_ssize_t n) +{ + PyObject *data; + Py_ssize_t read_size; + + assert(self->read != NULL); + + if (_Unpickler_SkipConsumed(self) < 0) + return -1; + + if (n == READ_WHOLE_LINE) { + data = PyObject_CallNoArgs(self->readline); + if (data == NULL) { + return -1; + } + } + else { + PyObject *len; + /* Prefetch some data without advancing the file pointer, if possible */ + if (self->peek && n < PREFETCH) { + len = PyLong_FromSsize_t(PREFETCH); + if (len == NULL) + return -1; + data = _Pickle_FastCall(self->peek, len); + if (data == NULL) { + if (!PyErr_ExceptionMatches(PyExc_NotImplementedError)) + return -1; + /* peek() is probably not supported by the given file object */ + PyErr_Clear(); + Py_CLEAR(self->peek); + } + else { + read_size = _Unpickler_SetStringInput(self, data); + Py_DECREF(data); + if (read_size < 0) { + return -1; + } + + self->prefetched_idx = 0; + if (n <= read_size) + return n; + } + } + Py_ssize_t cursize = Py_MIN(n, MIN_READ_BUF_SIZE); + len = PyLong_FromSsize_t(cursize); + if (len == NULL) + return -1; + data = _Pickle_FastCall(self->read, len); + if (data == NULL) { + return -1; + } + while (cursize < n) { + Py_ssize_t prevsize = cursize; + // geometrically double the chunk size to avoid CPU DoS + cursize += Py_MIN(cursize, n - cursize); + if (_PyBytes_Resize(&data, cursize) < 0) { + return -1; + } + if (_Unpickler_ReadIntoFromFile(state, self, + PyBytes_AS_STRING(data) + prevsize, cursize - prevsize) < 0) + { + Py_DECREF(data); + return -1; + } + } + } + + read_size = _Unpickler_SetStringInput(self, data); + Py_DECREF(data); + return read_size; +} + +/* Don't call it directly: use _Unpickler_Read() */ +static Py_ssize_t +_Unpickler_ReadImpl(UnpicklerObject *self, PickleState *st, char **s, Py_ssize_t n) +{ + Py_ssize_t num_read; + + *s = NULL; + if (self->next_read_idx > PY_SSIZE_T_MAX - n) { + PyErr_SetString(st->UnpicklingError, + "read would overflow (invalid bytecode)"); + return -1; + } + + /* This case is handled by the _Unpickler_Read() macro for efficiency */ + assert(self->next_read_idx + n > self->input_len); + + if (!self->read) + return bad_readline(st); + + /* Extend the buffer to satisfy desired size */ + num_read = _Unpickler_ReadFromFile(st, self, n); + if (num_read < 0) + return -1; + if (num_read < n) + return bad_readline(st); + *s = self->input_buffer; + self->next_read_idx = n; + return n; +} + +/* Read `n` bytes from the unpickler's data source, storing the result in `buf`. + * + * This should only be used for non-small data reads where potentially + * avoiding a copy is beneficial. This method does not try to prefetch + * more data into the input buffer. + * + * _Unpickler_Read() is recommended in most cases. + */ +static Py_ssize_t +_Unpickler_ReadInto(PickleState *state, UnpicklerObject *self, char *buf, + Py_ssize_t n) +{ + assert(n != READ_WHOLE_LINE); + + /* Read from available buffer data, if any */ + Py_ssize_t in_buffer = self->input_len - self->next_read_idx; + if (in_buffer > 0) { + Py_ssize_t to_read = Py_MIN(in_buffer, n); + memcpy(buf, self->input_buffer + self->next_read_idx, to_read); + self->next_read_idx += to_read; + buf += to_read; + n -= to_read; + if (n == 0) { + /* Entire read was satisfied from buffer */ + return n; + } + } + + /* Read from file */ + if (!self->read) { + /* We're unpickling memory, this means the input is truncated */ + return bad_readline(state); + } + if (_Unpickler_SkipConsumed(self) < 0) { + return -1; + } + + return _Unpickler_ReadIntoFromFile(state, self, buf, n); +} + /* Read `n` bytes from the unpickler's data source, storing the result in `*s`. This should be used for all data reads, rather than accessing the unpickler's @@ -1499,7 +1525,7 @@ _Unpickler_Readline(PickleState *state, UnpicklerObject *self, char **result) if (!self->read) return bad_readline(state); - num_read = _Unpickler_ReadFromFile(self, READ_WHOLE_LINE); + num_read = _Unpickler_ReadFromFile(state, self, READ_WHOLE_LINE); if (num_read < 0) return -1; if (num_read == 0 || self->input_buffer[num_read - 1] != '\n') @@ -1532,12 +1558,35 @@ _Unpickler_ResizeMemoList(UnpicklerObject *self, size_t new_size) /* Returns NULL if idx is out of bounds. */ static PyObject * -_Unpickler_MemoGet(UnpicklerObject *self, size_t idx) +_Unpickler_MemoGet(PickleState *st, UnpicklerObject *self, size_t idx) { - if (idx >= self->memo_size) - return NULL; - - return self->memo[idx]; + PyObject *value; + if (idx < self->memo_size) { + value = self->memo[idx]; + if (value != NULL) { + return value; + } + } + if (self->memo_dict != NULL) { + PyObject *key = PyLong_FromSize_t(idx); + if (key == NULL) { + return NULL; + } + if (idx < self->memo_size) { + (void)PyDict_Pop(self->memo_dict, key, &value); + // Migrate dict entry to array for faster future access + self->memo[idx] = value; + } + else { + value = PyDict_GetItemWithError(self->memo_dict, key); + } + Py_DECREF(key); + if (value != NULL || PyErr_Occurred()) { + return value; + } + } + PyErr_Format(st->UnpicklingError, "Memo value not found at index %zd", idx); + return NULL; } /* Returns -1 (with an exception set) on failure, 0 on success. @@ -1548,6 +1597,27 @@ _Unpickler_MemoPut(UnpicklerObject *self, size_t idx, PyObject *value) PyObject *old_item; if (idx >= self->memo_size) { + if (idx > self->memo_len * 2) { + /* The memo keys are too sparse. Use a dict instead of + * a continuous array for the memo. */ + if (self->memo_dict == NULL) { + self->memo_dict = PyDict_New(); + if (self->memo_dict == NULL) { + return -1; + } + } + PyObject *key = PyLong_FromSize_t(idx); + if (key == NULL) { + return -1; + } + + if (PyDict_SetItem(self->memo_dict, key, value) < 0) { + Py_DECREF(key); + return -1; + } + Py_DECREF(key); + return 0; + } if (_Unpickler_ResizeMemoList(self, idx * 2) < 0) return -1; assert(idx < self->memo_size); @@ -1617,6 +1687,7 @@ _Unpickler_New(PyObject *module) self->memo = memo; self->memo_size = MEMO_SIZE; self->memo_len = 0; + self->memo_dict = NULL; self->persistent_load = NULL; self->persistent_load_attr = NULL; memset(&self->buffer, 0, sizeof(Py_buffer)); @@ -2619,31 +2690,26 @@ save_picklebuffer(PickleState *st, PicklerObject *self, PyObject *obj) static PyObject * raw_unicode_escape(PyObject *obj) { - char *p; - Py_ssize_t i, size; - const void *data; - int kind; - _PyBytesWriter writer; + Py_ssize_t size = PyUnicode_GET_LENGTH(obj); + const void *data = PyUnicode_DATA(obj); + int kind = PyUnicode_KIND(obj); - _PyBytesWriter_Init(&writer); + Py_ssize_t alloc = size; + PyBytesWriter *writer = PyBytesWriter_Create(alloc); + if (writer == NULL) { + return NULL; + } + char *p = PyBytesWriter_GetData(writer); - size = PyUnicode_GET_LENGTH(obj); - data = PyUnicode_DATA(obj); - kind = PyUnicode_KIND(obj); - - p = _PyBytesWriter_Alloc(&writer, size); - if (p == NULL) - goto error; - writer.overallocate = 1; - - for (i=0; i < size; i++) { + for (Py_ssize_t i=0; i < size; i++) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); /* Map 32-bit characters to '\Uxxxxxxxx' */ if (ch >= 0x10000) { /* -1: subtract 1 preallocated byte */ - p = _PyBytesWriter_Prepare(&writer, p, 10-1); - if (p == NULL) + p = PyBytesWriter_GrowAndUpdatePointer(writer, 10-1, p); + if (p == NULL) { goto error; + } *p++ = '\\'; *p++ = 'U'; @@ -2662,9 +2728,10 @@ raw_unicode_escape(PyObject *obj) ch == 0x1a) { /* -1: subtract 1 preallocated byte */ - p = _PyBytesWriter_Prepare(&writer, p, 6-1); - if (p == NULL) + p = PyBytesWriter_GrowAndUpdatePointer(writer, 6-1, p); + if (p == NULL) { goto error; + } *p++ = '\\'; *p++ = 'u'; @@ -2678,10 +2745,10 @@ raw_unicode_escape(PyObject *obj) *p++ = (char) ch; } - return _PyBytesWriter_Finish(&writer, p); + return PyBytesWriter_FinishWithPointer(writer, p); error: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } @@ -5593,13 +5660,28 @@ load_counted_binbytes(PickleState *state, UnpicklerObject *self, int nbytes) return -1; } - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) - return -1; - if (_Unpickler_ReadInto(state, self, PyBytes_AS_STRING(bytes), size) < 0) { - Py_DECREF(bytes); + Py_ssize_t cursize = Py_MIN(size, MIN_READ_BUF_SIZE); + Py_ssize_t prevsize = 0; + bytes = PyBytes_FromStringAndSize(NULL, cursize); + if (bytes == NULL) { return -1; } + while (1) { + if (_Unpickler_ReadInto(state, self, + PyBytes_AS_STRING(bytes) + prevsize, cursize - prevsize) < 0) + { + Py_DECREF(bytes); + return -1; + } + if (cursize >= size) { + break; + } + prevsize = cursize; + cursize += Py_MIN(cursize, size - cursize); + if (_PyBytes_Resize(&bytes, cursize) < 0) { + return -1; + } + } PDATA_PUSH(self->stack, bytes, -1); return 0; @@ -5624,14 +5706,27 @@ load_counted_bytearray(PickleState *state, UnpicklerObject *self) return -1; } - bytearray = PyByteArray_FromStringAndSize(NULL, size); + Py_ssize_t cursize = Py_MIN(size, MIN_READ_BUF_SIZE); + Py_ssize_t prevsize = 0; + bytearray = PyByteArray_FromStringAndSize(NULL, cursize); if (bytearray == NULL) { return -1; } - char *str = PyByteArray_AS_STRING(bytearray); - if (_Unpickler_ReadInto(state, self, str, size) < 0) { - Py_DECREF(bytearray); - return -1; + while (1) { + if (_Unpickler_ReadInto(state, self, + PyByteArray_AS_STRING(bytearray) + prevsize, + cursize - prevsize) < 0) { + Py_DECREF(bytearray); + return -1; + } + if (cursize >= size) { + break; + } + prevsize = cursize; + cursize += Py_MIN(cursize, size - cursize); + if (PyByteArray_Resize(bytearray, cursize) < 0) { + return -1; + } } PDATA_PUSH(self->stack, bytearray, -1); @@ -6233,20 +6328,15 @@ load_get(PickleState *st, UnpicklerObject *self) if (key == NULL) return -1; idx = PyLong_AsSsize_t(key); + Py_DECREF(key); if (idx == -1 && PyErr_Occurred()) { - Py_DECREF(key); return -1; } - value = _Unpickler_MemoGet(self, idx); + value = _Unpickler_MemoGet(st, self, idx); if (value == NULL) { - if (!PyErr_Occurred()) { - PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx); - } - Py_DECREF(key); return -1; } - Py_DECREF(key); PDATA_APPEND(self->stack, value, -1); return 0; @@ -6264,13 +6354,8 @@ load_binget(PickleState *st, UnpicklerObject *self) idx = Py_CHARMASK(s[0]); - value = _Unpickler_MemoGet(self, idx); + value = _Unpickler_MemoGet(st, self, idx); if (value == NULL) { - PyObject *key = PyLong_FromSsize_t(idx); - if (key != NULL) { - PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx); - Py_DECREF(key); - } return -1; } @@ -6290,13 +6375,8 @@ load_long_binget(PickleState *st, UnpicklerObject *self) idx = calc_binsize(s, 4); - value = _Unpickler_MemoGet(self, idx); + value = _Unpickler_MemoGet(st, self, idx); if (value == NULL) { - PyObject *key = PyLong_FromSsize_t(idx); - if (key != NULL) { - PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx); - Py_DECREF(key); - } return -1; } @@ -7261,6 +7341,7 @@ Unpickler_clear(PyObject *op) self->buffer.buf = NULL; } + Py_CLEAR(self->memo_dict); _Unpickler_MemoCleanup(self); PyMem_Free(self->marks); self->marks = NULL; @@ -7297,6 +7378,7 @@ Unpickler_traverse(PyObject *op, visitproc visit, void *arg) Py_VISIT(self->persistent_load); Py_VISIT(self->persistent_load_attr); Py_VISIT(self->buffers); + Py_VISIT(self->memo_dict); PyObject **memo = self->memo; if (memo) { Py_ssize_t i = self->memo_size; diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index bd78a46c8d7..6f0a6d1d4e3 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -514,7 +514,13 @@ _close_open_fds_maybe_unsafe(int start_fd, int *fds_to_keep, proc_fd_dir = NULL; else #endif +#if defined(_AIX) + char fd_path[PATH_MAX]; + snprintf(fd_path, sizeof(fd_path), "/proc/%ld/fd", (long)getpid()); + proc_fd_dir = opendir(fd_path); +#else proc_fd_dir = opendir(FD_DIR); +#endif if (!proc_fd_dir) { /* No way to get a list of open fds. */ _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len, @@ -630,7 +636,7 @@ reset_signal_handlers(const sigset_t *child_sigmask) * (v)fork to set things up and call exec(). * * All of the code in this function must only use async-signal-safe functions, - * listed at `man 7 signal` or + * listed at `man 7 signal-safety` or * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. * * This restriction is documented at diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 2f4f388ce11..544e636d18f 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -522,7 +522,7 @@ _random_Random_getrandbits_impl(RandomObject *self, uint64_t k) PyErr_NoMemory(); return NULL; } - words = (k - 1u) / 32u + 1u; + words = (Py_ssize_t)((k - 1u) / 32u + 1u); wordarray = (uint32_t *)PyMem_Malloc(words * 4); if (wordarray == NULL) { PyErr_NoMemory(); @@ -595,11 +595,14 @@ static PyType_Slot Random_Type_slots[] = { }; static PyType_Spec Random_Type_spec = { - "_random.Random", - sizeof(RandomObject), - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - Random_Type_slots + .name = "_random.Random", + .basicsize = sizeof(RandomObject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = Random_Type_slots }; PyDoc_STRVAR(module_doc, diff --git a/Modules/_remote_debugging/_remote_debugging.h b/Modules/_remote_debugging/_remote_debugging.h new file mode 100644 index 00000000000..cc8aeedba9c --- /dev/null +++ b/Modules/_remote_debugging/_remote_debugging.h @@ -0,0 +1,622 @@ +/****************************************************************************** + * Python Remote Debugging Module - Shared Header + * + * This header provides common declarations, types, and utilities shared + * across the remote debugging module implementation files. + ******************************************************************************/ + +#ifndef Py_REMOTE_DEBUGGING_H +#define Py_REMOTE_DEBUGGING_H + +/* _GNU_SOURCE must be defined before any system headers */ +#define _GNU_SOURCE + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + +#include "Python.h" +#include "internal/pycore_debug_offsets.h" // _Py_DebugOffsets +#include "internal/pycore_frame.h" // FRAME_SUSPENDED_YIELD_FROM +#include "internal/pycore_interpframe.h" // FRAME_OWNED_BY_INTERPRETER +#include "internal/pycore_llist.h" // struct llist_node +#include "internal/pycore_long.h" // _PyLong_GetZero +#include "internal/pycore_stackref.h" // Py_TAG_BITS +#include "../../Python/remote_debug.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef HAVE_PROCESS_VM_READV +# define HAVE_PROCESS_VM_READV 0 +#endif + +#if defined(__APPLE__) +#include <TargetConditionals.h> +# if !defined(TARGET_OS_OSX) + /* Older macOS SDKs do not define TARGET_OS_OSX */ +# define TARGET_OS_OSX 1 +# endif +# if TARGET_OS_OSX +# include <libproc.h> +# include <sys/types.h> +# define MAX_NATIVE_THREADS 4096 +# endif +#endif + +#ifdef MS_WINDOWS +#include <windows.h> +#include <winternl.h> +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +typedef enum _WIN32_THREADSTATE { + WIN32_THREADSTATE_INITIALIZED = 0, + WIN32_THREADSTATE_READY = 1, + WIN32_THREADSTATE_RUNNING = 2, + WIN32_THREADSTATE_STANDBY = 3, + WIN32_THREADSTATE_TERMINATED = 4, + WIN32_THREADSTATE_WAITING = 5, + WIN32_THREADSTATE_TRANSITION = 6, + WIN32_THREADSTATE_UNKNOWN = 7 +} WIN32_THREADSTATE; +#endif + +/* ============================================================================ + * MACROS AND CONSTANTS + * ============================================================================ */ + +#define GET_MEMBER(type, obj, offset) (*(type*)((char*)(obj) + (offset))) +#define CLEAR_PTR_TAG(ptr) (((uintptr_t)(ptr) & ~Py_TAG_BITS)) +#define GET_MEMBER_NO_TAG(type, obj, offset) (type)(CLEAR_PTR_TAG(*(type*)((char*)(obj) + (offset)))) + +/* Size macros for opaque buffers */ +#define SIZEOF_BYTES_OBJ sizeof(PyBytesObject) +#define SIZEOF_CODE_OBJ sizeof(PyCodeObject) +#define SIZEOF_GEN_OBJ sizeof(PyGenObject) +#define SIZEOF_INTERP_FRAME sizeof(_PyInterpreterFrame) +#define SIZEOF_LLIST_NODE sizeof(struct llist_node) +#define SIZEOF_PAGE_CACHE_ENTRY sizeof(page_cache_entry_t) +#define SIZEOF_PYOBJECT sizeof(PyObject) +#define SIZEOF_SET_OBJ sizeof(PySetObject) +#define SIZEOF_TASK_OBJ 4096 +#define SIZEOF_THREAD_STATE sizeof(PyThreadState) +#define SIZEOF_TYPE_OBJ sizeof(PyTypeObject) +#define SIZEOF_UNICODE_OBJ sizeof(PyUnicodeObject) +#define SIZEOF_LONG_OBJ sizeof(PyLongObject) +#define SIZEOF_GC_RUNTIME_STATE sizeof(struct _gc_runtime_state) +#define SIZEOF_INTERPRETER_STATE sizeof(PyInterpreterState) + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifdef Py_GIL_DISABLED +#define INTERP_STATE_MIN_SIZE MAX(MAX(MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \ + offsetof(PyInterpreterState, tlbc_indices.tlbc_generation) + sizeof(uint32_t)), \ + offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \ + offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*)), \ + offsetof(PyInterpreterState, gc.frame) + sizeof(_PyInterpreterFrame *)) +#else +#define INTERP_STATE_MIN_SIZE MAX(MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \ + offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \ + offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*)), \ + offsetof(PyInterpreterState, gc.frame) + sizeof(_PyInterpreterFrame *)) +#endif +#define INTERP_STATE_BUFFER_SIZE MAX(INTERP_STATE_MIN_SIZE, 256) + +#define MAX_TLBC_SIZE 2048 + +/* Thread status flags */ +#define THREAD_STATUS_HAS_GIL (1 << 0) +#define THREAD_STATUS_ON_CPU (1 << 1) +#define THREAD_STATUS_UNKNOWN (1 << 2) +#define THREAD_STATUS_GIL_REQUESTED (1 << 3) +#define THREAD_STATUS_HAS_EXCEPTION (1 << 4) + +/* Exception cause macro */ +#define set_exception_cause(unwinder, exc_type, message) \ + if (unwinder->debug) { \ + _set_debug_exception_cause(exc_type, message); \ + } + +/* ============================================================================ + * TYPE DEFINITIONS + * ============================================================================ */ + +struct _Py_AsyncioModuleDebugOffsets { + struct _asyncio_task_object { + uint64_t size; + uint64_t task_name; + uint64_t task_awaited_by; + uint64_t task_is_task; + uint64_t task_awaited_by_is_set; + uint64_t task_coro; + uint64_t task_node; + } asyncio_task_object; + struct _asyncio_interpreter_state { + uint64_t size; + uint64_t asyncio_tasks_head; + } asyncio_interpreter_state; + struct _asyncio_thread_state { + uint64_t size; + uint64_t asyncio_running_loop; + uint64_t asyncio_running_task; + uint64_t asyncio_tasks_head; + } asyncio_thread_state; +}; + +typedef struct { + PyObject *func_name; + PyObject *file_name; + int first_lineno; + PyObject *linetable; // bytes + uintptr_t addr_code_adaptive; +} CachedCodeMetadata; + +/* Frame cache constants and types */ +#define FRAME_CACHE_MAX_THREADS 32 +#define FRAME_CACHE_MAX_FRAMES 1024 + +typedef struct { + uint64_t thread_id; // 0 = empty slot + uintptr_t addrs[FRAME_CACHE_MAX_FRAMES]; + Py_ssize_t num_addrs; + PyObject *frame_list; // owned reference, NULL if empty +} FrameCacheEntry; + +/* Statistics for profiling performance analysis */ +typedef struct { + uint64_t total_samples; // Total number of get_stack_trace calls + uint64_t frame_cache_hits; // Full cache hits (entire stack unchanged) + uint64_t frame_cache_misses; // Cache misses requiring full walk + uint64_t frame_cache_partial_hits; // Partial hits (stopped at cached frame) + uint64_t frames_read_from_cache; // Total frames retrieved from cache + uint64_t frames_read_from_memory; // Total frames read from remote memory + uint64_t memory_reads; // Total remote memory read operations + uint64_t memory_bytes_read; // Total bytes read from remote memory + uint64_t code_object_cache_hits; // Code object cache hits + uint64_t code_object_cache_misses; // Code object cache misses + uint64_t stale_cache_invalidations; // Times stale entries were cleared +} UnwinderStats; + +/* Stats tracking macros - no-op when stats collection is disabled */ +#define STATS_INC(unwinder, field) \ + do { if ((unwinder)->collect_stats) (unwinder)->stats.field++; } while(0) + +#define STATS_ADD(unwinder, field, val) \ + do { if ((unwinder)->collect_stats) (unwinder)->stats.field += (val); } while(0) + +typedef struct { + PyTypeObject *RemoteDebugging_Type; + PyTypeObject *TaskInfo_Type; + PyTypeObject *LocationInfo_Type; + PyTypeObject *FrameInfo_Type; + PyTypeObject *CoroInfo_Type; + PyTypeObject *ThreadInfo_Type; + PyTypeObject *InterpreterInfo_Type; + PyTypeObject *AwaitedInfo_Type; +} RemoteDebuggingState; + +enum _ThreadState { + THREAD_STATE_RUNNING, + THREAD_STATE_IDLE, + THREAD_STATE_GIL_WAIT, + THREAD_STATE_UNKNOWN +}; + +enum _ProfilingMode { + PROFILING_MODE_WALL = 0, + PROFILING_MODE_CPU = 1, + PROFILING_MODE_GIL = 2, + PROFILING_MODE_ALL = 3, + PROFILING_MODE_EXCEPTION = 4 +}; + +typedef struct { + PyObject_HEAD + proc_handle_t handle; + uintptr_t runtime_start_address; + struct _Py_DebugOffsets debug_offsets; + int async_debug_offsets_available; + struct _Py_AsyncioModuleDebugOffsets async_debug_offsets; + uintptr_t interpreter_addr; + uintptr_t tstate_addr; + uint64_t code_object_generation; + _Py_hashtable_t *code_object_cache; + int debug; + int only_active_thread; + int mode; + int skip_non_matching_threads; + int native; + int gc; + int opcodes; + int cache_frames; + int collect_stats; // whether to collect statistics + uint32_t stale_invalidation_counter; // counter for throttling frame_cache_invalidate_stale + RemoteDebuggingState *cached_state; + FrameCacheEntry *frame_cache; // preallocated array of FRAME_CACHE_MAX_THREADS entries + UnwinderStats stats; // statistics for performance analysis +#ifdef Py_GIL_DISABLED + uint32_t tlbc_generation; + _Py_hashtable_t *tlbc_cache; +#endif +#ifdef __APPLE__ + uint64_t thread_id_offset; +#endif +#ifdef MS_WINDOWS + PVOID win_process_buffer; + ULONG win_process_buffer_size; +#endif +} RemoteUnwinderObject; + +#define RemoteUnwinder_CAST(op) ((RemoteUnwinderObject *)(op)) + +typedef struct { + int lineno; + int end_lineno; + int column; + int end_column; +} LocationInfo; + +typedef struct { + uintptr_t remote_addr; + size_t size; + void *local_copy; +} StackChunkInfo; + +typedef struct { + StackChunkInfo *chunks; + size_t count; +} StackChunkList; + +/* + * Context for frame chain traversal operations. + */ +typedef struct { + /* Inputs */ + uintptr_t frame_addr; // Starting frame address + uintptr_t base_frame_addr; // Sentinel at bottom (for validation) + uintptr_t gc_frame; // GC frame address (0 if not tracking) + uintptr_t last_profiled_frame; // Last cached frame (0 if no cache) + StackChunkList *chunks; // Pre-copied stack chunks + + /* Outputs */ + PyObject *frame_info; // List to append FrameInfo objects + uintptr_t *frame_addrs; // Array of visited frame addresses + Py_ssize_t num_addrs; // Count of addresses collected + Py_ssize_t max_addrs; // Capacity of frame_addrs array + uintptr_t last_frame_visited; // Last frame address visited + int stopped_at_cached_frame; // Whether we stopped at cached frame +} FrameWalkContext; + +/* + * Context for code object parsing. + */ +typedef struct { + uintptr_t code_addr; // Code object address in remote process + uintptr_t instruction_pointer; // Current instruction pointer + int32_t tlbc_index; // Thread-local bytecode index (free-threading) +} CodeObjectContext; + +/* Function pointer types for iteration callbacks */ +typedef int (*thread_processor_func)( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + unsigned long tid, + void *context +); + +typedef int (*set_entry_processor_func)( + RemoteUnwinderObject *unwinder, + uintptr_t key_addr, + void *context +); + +/* ============================================================================ + * STRUCTSEQ DESCRIPTORS (extern declarations) + * ============================================================================ */ + +extern PyStructSequence_Desc TaskInfo_desc; +extern PyStructSequence_Desc LocationInfo_desc; +extern PyStructSequence_Desc FrameInfo_desc; +extern PyStructSequence_Desc CoroInfo_desc; +extern PyStructSequence_Desc ThreadInfo_desc; +extern PyStructSequence_Desc InterpreterInfo_desc; +extern PyStructSequence_Desc AwaitedInfo_desc; + +/* ============================================================================ + * UTILITY FUNCTION DECLARATIONS + * ============================================================================ */ + +/* State access functions */ +extern RemoteDebuggingState *RemoteDebugging_GetState(PyObject *module); +extern RemoteDebuggingState *RemoteDebugging_GetStateFromType(PyTypeObject *type); +extern RemoteDebuggingState *RemoteDebugging_GetStateFromObject(PyObject *obj); +extern int RemoteDebugging_InitState(RemoteDebuggingState *st); + +/* Cache management */ +extern void cached_code_metadata_destroy(void *ptr); + +/* Validation */ +extern int is_prerelease_version(uint64_t version); +extern int validate_debug_offsets(struct _Py_DebugOffsets *debug_offsets); + +/* ============================================================================ + * MEMORY READING FUNCTION DECLARATIONS + * ============================================================================ */ + +extern int read_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *result); +extern int read_Py_ssize_t(RemoteUnwinderObject *unwinder, uintptr_t address, Py_ssize_t *result); +extern int read_char(RemoteUnwinderObject *unwinder, uintptr_t address, char *result); +extern int read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *ptr_addr); + +/* Python object reading */ +extern PyObject *read_py_str(RemoteUnwinderObject *unwinder, uintptr_t address, Py_ssize_t max_len); +extern PyObject *read_py_bytes(RemoteUnwinderObject *unwinder, uintptr_t address, Py_ssize_t max_len); +extern long read_py_long(RemoteUnwinderObject *unwinder, uintptr_t address); + +/* ============================================================================ + * CODE OBJECT FUNCTION DECLARATIONS + * ============================================================================ */ + +extern int parse_code_object( + RemoteUnwinderObject *unwinder, + PyObject **result, + const CodeObjectContext *ctx +); + +extern PyObject *make_location_info( + RemoteUnwinderObject *unwinder, + int lineno, + int end_lineno, + int col_offset, + int end_col_offset +); + +extern PyObject *make_frame_info( + RemoteUnwinderObject *unwinder, + PyObject *file, + PyObject *location, // LocationInfo structseq or None for synthetic frames + PyObject *func, + PyObject *opcode +); + +/* Line table parsing */ +extern bool parse_linetable( + const uintptr_t addrq, + const char* linetable, + int firstlineno, + LocationInfo* info +); + +/* TLBC cache (only for Py_GIL_DISABLED) */ +#ifdef Py_GIL_DISABLED +typedef struct { + void *tlbc_array; + Py_ssize_t tlbc_array_size; + uint32_t generation; +} TLBCCacheEntry; + +extern void tlbc_cache_entry_destroy(void *ptr); +extern TLBCCacheEntry *get_tlbc_cache_entry(RemoteUnwinderObject *self, uintptr_t code_addr, uint32_t current_generation); +extern int cache_tlbc_array(RemoteUnwinderObject *unwinder, uintptr_t code_addr, uintptr_t tlbc_array_addr, uint32_t generation); +#endif + +/* ============================================================================ + * FRAME FUNCTION DECLARATIONS + * ============================================================================ */ + +extern int is_frame_valid( + RemoteUnwinderObject *unwinder, + uintptr_t frame_addr, + uintptr_t code_object_addr +); + +extern int parse_frame_object( + RemoteUnwinderObject *unwinder, + PyObject** result, + uintptr_t address, + uintptr_t* address_of_code_object, + uintptr_t* previous_frame +); + +extern int parse_frame_from_chunks( + RemoteUnwinderObject *unwinder, + PyObject **result, + uintptr_t address, + uintptr_t *previous_frame, + uintptr_t *stackpointer, + StackChunkList *chunks +); + +/* Stack chunk management */ +extern void cleanup_stack_chunks(StackChunkList *chunks); +extern int copy_stack_chunks(RemoteUnwinderObject *unwinder, uintptr_t tstate_addr, StackChunkList *out_chunks); +extern void *find_frame_in_chunks(StackChunkList *chunks, uintptr_t remote_ptr); + +extern int process_frame_chain( + RemoteUnwinderObject *unwinder, + FrameWalkContext *ctx +); + +/* Frame cache functions */ +extern int frame_cache_init(RemoteUnwinderObject *unwinder); +extern void frame_cache_cleanup(RemoteUnwinderObject *unwinder); +extern FrameCacheEntry *frame_cache_find(RemoteUnwinderObject *unwinder, uint64_t thread_id); +extern int clear_last_profiled_frames(RemoteUnwinderObject *unwinder); +extern void frame_cache_invalidate_stale(RemoteUnwinderObject *unwinder, PyObject *result); +extern int frame_cache_lookup_and_extend( + RemoteUnwinderObject *unwinder, + uint64_t thread_id, + uintptr_t last_profiled_frame, + PyObject *frame_info, + uintptr_t *frame_addrs, + Py_ssize_t *num_addrs, + Py_ssize_t max_addrs); +// Returns: 1 = stored, 0 = not stored (graceful), -1 = error +// Only stores complete stacks that reach base_frame_addr +extern int frame_cache_store( + RemoteUnwinderObject *unwinder, + uint64_t thread_id, + PyObject *frame_list, + const uintptr_t *addrs, + Py_ssize_t num_addrs, + uintptr_t base_frame_addr, + uintptr_t last_frame_visited); + +extern int collect_frames_with_cache( + RemoteUnwinderObject *unwinder, + FrameWalkContext *ctx, + uint64_t thread_id); + +/* ============================================================================ + * THREAD FUNCTION DECLARATIONS + * ============================================================================ */ + +extern int iterate_threads( + RemoteUnwinderObject *unwinder, + thread_processor_func processor, + void *context +); + +extern int populate_initial_state_data( + int all_threads, + RemoteUnwinderObject *unwinder, + uintptr_t runtime_start_address, + uintptr_t *interpreter_state, + uintptr_t *tstate +); + +extern int find_running_frame( + RemoteUnwinderObject *unwinder, + uintptr_t address_of_thread, + uintptr_t *frame +); + +extern int get_thread_status(RemoteUnwinderObject *unwinder, uint64_t tid, uint64_t pthread_id); + +extern PyObject* unwind_stack_for_thread( + RemoteUnwinderObject *unwinder, + uintptr_t *current_tstate, + uintptr_t gil_holder_tstate, + uintptr_t gc_frame +); + +/* ============================================================================ + * ASYNCIO FUNCTION DECLARATIONS + * ============================================================================ */ + +extern uintptr_t _Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle); +extern int read_async_debug(RemoteUnwinderObject *unwinder); +extern int ensure_async_debug_offsets(RemoteUnwinderObject *unwinder); + +/* Task parsing */ +extern PyObject *parse_task_name(RemoteUnwinderObject *unwinder, uintptr_t task_address); + +extern int parse_task( + RemoteUnwinderObject *unwinder, + uintptr_t task_address, + PyObject *render_to +); + +extern int parse_coro_chain( + RemoteUnwinderObject *unwinder, + uintptr_t coro_address, + PyObject *render_to +); + +extern int parse_async_frame_chain( + RemoteUnwinderObject *unwinder, + PyObject *calls, + uintptr_t address_of_thread, + uintptr_t running_task_code_obj +); + +/* Set iteration */ +extern int iterate_set_entries( + RemoteUnwinderObject *unwinder, + uintptr_t set_addr, + set_entry_processor_func processor, + void *context +); + +/* Task awaited_by processing */ +extern int process_task_awaited_by( + RemoteUnwinderObject *unwinder, + uintptr_t task_address, + set_entry_processor_func processor, + void *context +); + +extern int process_single_task_node( + RemoteUnwinderObject *unwinder, + uintptr_t task_addr, + PyObject **task_info, + PyObject *result +); + +extern int process_task_and_waiters( + RemoteUnwinderObject *unwinder, + uintptr_t task_addr, + PyObject *result +); + +extern int find_running_task_in_thread( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + uintptr_t *running_task_addr +); + +extern int get_task_code_object( + RemoteUnwinderObject *unwinder, + uintptr_t task_addr, + uintptr_t *code_obj_addr +); + +extern int append_awaited_by( + RemoteUnwinderObject *unwinder, + unsigned long tid, + uintptr_t head_addr, + PyObject *result +); + +/* Thread processors for asyncio */ +extern int process_thread_for_awaited_by( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + unsigned long tid, + void *context +); + +extern int process_thread_for_async_stack_trace( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + unsigned long tid, + void *context +); + +/* ============================================================================ + * SUBPROCESS ENUMERATION FUNCTION DECLARATIONS + * ============================================================================ */ + +/* Get all child PIDs of a process. + * Returns a new Python list of PIDs, or NULL on error with exception set. + * If recursive is true, includes all descendants (children, grandchildren, etc.) + */ +extern PyObject *enumerate_child_pids(pid_t target_pid, int recursive); + +#ifdef __cplusplus +} +#endif + +#endif /* Py_REMOTE_DEBUGGING_H */ diff --git a/Modules/_remote_debugging/asyncio.c b/Modules/_remote_debugging/asyncio.c new file mode 100644 index 00000000000..7f91f16e3a2 --- /dev/null +++ b/Modules/_remote_debugging/asyncio.c @@ -0,0 +1,1014 @@ +/****************************************************************************** + * Remote Debugging Module - Asyncio Functions + * + * This file contains functions for parsing asyncio tasks, coroutines, + * and awaited_by relationships from remote process memory. + ******************************************************************************/ + +#include "_remote_debugging.h" + +/* ============================================================================ + * ASYNCIO DEBUG ADDRESS FUNCTIONS + * ============================================================================ */ + +uintptr_t +_Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle) +{ + uintptr_t address; + +#ifdef MS_WINDOWS + // On Windows, search for asyncio debug in executable or DLL + address = search_windows_map_for_section(handle, "AsyncioD", L"_asyncio"); + if (address == 0) { + // Error out: 'python' substring covers both executable and DLL + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); + _PyErr_ChainExceptions1(exc); + } +#elif defined(__linux__) && HAVE_PROCESS_VM_READV + // On Linux, search for asyncio debug in executable or DLL + address = search_linux_map_for_section(handle, "AsyncioDebug", "python"); + if (address == 0) { + // Error out: 'python' substring covers both executable and DLL + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); + _PyErr_ChainExceptions1(exc); + } +#elif defined(__APPLE__) && TARGET_OS_OSX + // On macOS, try libpython first, then fall back to python + address = search_map_for_section(handle, "AsyncioDebug", "libpython"); + if (address == 0) { + PyErr_Clear(); + address = search_map_for_section(handle, "AsyncioDebug", "python"); + } + if (address == 0) { + // Error out: 'python' substring covers both executable and DLL + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); + _PyErr_ChainExceptions1(exc); + } +#else + Py_UNREACHABLE(); +#endif + + return address; +} + +int +read_async_debug(RemoteUnwinderObject *unwinder) +{ + uintptr_t async_debug_addr = _Py_RemoteDebug_GetAsyncioDebugAddress(&unwinder->handle); + if (!async_debug_addr) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to get AsyncioDebug address"); + return -1; + } + + size_t size = sizeof(struct _Py_AsyncioModuleDebugOffsets); + int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, async_debug_addr, size, &unwinder->async_debug_offsets); + if (result < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read AsyncioDebug offsets"); + } + return result; +} + +int +ensure_async_debug_offsets(RemoteUnwinderObject *unwinder) +{ + // If already available, nothing to do + if (unwinder->async_debug_offsets_available) { + return 0; + } + + // Try to load async debug offsets (the target process may have + // loaded asyncio since we last checked) + if (read_async_debug(unwinder) < 0) { + PyErr_Clear(); + PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available"); + set_exception_cause(unwinder, PyExc_RuntimeError, + "AsyncioDebug section unavailable - asyncio module may not be loaded in target process"); + return -1; + } + + unwinder->async_debug_offsets_available = 1; + return 0; +} + +/* ============================================================================ + * SET ITERATION FUNCTIONS + * ============================================================================ */ + +int +iterate_set_entries( + RemoteUnwinderObject *unwinder, + uintptr_t set_addr, + set_entry_processor_func processor, + void *context +) { + char set_object[SIZEOF_SET_OBJ]; + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, set_addr, + SIZEOF_SET_OBJ, set_object) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set object"); + return -1; + } + + Py_ssize_t num_els = GET_MEMBER(Py_ssize_t, set_object, unwinder->debug_offsets.set_object.used); + Py_ssize_t set_len = GET_MEMBER(Py_ssize_t, set_object, unwinder->debug_offsets.set_object.mask) + 1; + uintptr_t table_ptr = GET_MEMBER(uintptr_t, set_object, unwinder->debug_offsets.set_object.table); + + Py_ssize_t i = 0; + Py_ssize_t els = 0; + while (i < set_len && els < num_els) { + uintptr_t key_addr; + if (read_py_ptr(unwinder, table_ptr, &key_addr) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set entry key"); + return -1; + } + + if ((void*)key_addr != NULL) { + Py_ssize_t ref_cnt; + if (read_Py_ssize_t(unwinder, table_ptr, &ref_cnt) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set entry ref count"); + return -1; + } + + if (ref_cnt) { + // Process this valid set entry + if (processor(unwinder, key_addr, context) < 0) { + return -1; + } + els++; + } + } + table_ptr += sizeof(void*) * 2; + i++; + } + + return 0; +} + +/* ============================================================================ + * TASK NAME PARSING + * ============================================================================ */ + +PyObject * +parse_task_name( + RemoteUnwinderObject *unwinder, + uintptr_t task_address +) { + // Read the entire TaskObj at once + char task_obj[SIZEOF_TASK_OBJ]; + int err = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + task_address, + (size_t)unwinder->async_debug_offsets.asyncio_task_object.size, + task_obj); + if (err < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object"); + return NULL; + } + + uintptr_t task_name_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_name); + + // The task name can be a long or a string so we need to check the type + char task_name_obj[SIZEOF_PYOBJECT]; + err = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + task_name_addr, + SIZEOF_PYOBJECT, + task_name_obj); + if (err < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task name object"); + return NULL; + } + + // Now read the type object to get the flags + char type_obj[SIZEOF_TYPE_OBJ]; + err = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + GET_MEMBER(uintptr_t, task_name_obj, unwinder->debug_offsets.pyobject.ob_type), + SIZEOF_TYPE_OBJ, + type_obj); + if (err < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task name type object"); + return NULL; + } + + if ((GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_LONG_SUBCLASS)) { + long res = read_py_long(unwinder, task_name_addr); + if (res == -1) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Task name PyLong parsing failed"); + return NULL; + } + return PyUnicode_FromFormat("Task-%d", res); + } + + if(!(GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_UNICODE_SUBCLASS)) { + PyErr_SetString(PyExc_RuntimeError, "Invalid task name object"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Task name object is neither long nor unicode"); + return NULL; + } + + return read_py_str( + unwinder, + task_name_addr, + 255 + ); +} + +/* ============================================================================ + * COROUTINE CHAIN PARSING + * ============================================================================ */ + +static int +handle_yield_from_frame( + RemoteUnwinderObject *unwinder, + uintptr_t gi_iframe_addr, + uintptr_t gen_type_addr, + PyObject *render_to +) { + // Read the entire interpreter frame at once + char iframe[SIZEOF_INTERP_FRAME]; + int err = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + gi_iframe_addr, + SIZEOF_INTERP_FRAME, + iframe); + if (err < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame in yield_from handler"); + return -1; + } + + if (GET_MEMBER(char, iframe, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR) { + PyErr_SetString( + PyExc_RuntimeError, + "generator doesn't own its frame \\_o_/"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Frame ownership mismatch in yield_from"); + return -1; + } + + uintptr_t stackpointer_addr = GET_MEMBER_NO_TAG(uintptr_t, iframe, unwinder->debug_offsets.interpreter_frame.stackpointer); + + if ((void*)stackpointer_addr != NULL) { + uintptr_t gi_await_addr; + err = read_py_ptr( + unwinder, + stackpointer_addr - sizeof(void*), + &gi_await_addr); + if (err) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read gi_await address"); + return -1; + } + + if ((void*)gi_await_addr != NULL) { + uintptr_t gi_await_addr_type_addr; + err = read_ptr( + unwinder, + gi_await_addr + (uintptr_t)unwinder->debug_offsets.pyobject.ob_type, + &gi_await_addr_type_addr); + if (err) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read gi_await type address"); + return -1; + } + + if (gen_type_addr == gi_await_addr_type_addr) { + /* This needs an explanation. We always start with parsing + native coroutine / generator frames. Ultimately they + are awaiting on something. That something can be + a native coroutine frame or... an iterator. + If it's the latter -- we can't continue building + our chain. So the condition to bail out of this is + to do that when the type of the current coroutine + doesn't match the type of whatever it points to + in its cr_await. + */ + err = parse_coro_chain(unwinder, gi_await_addr, render_to); + if (err) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain in yield_from"); + return -1; + } + } + } + } + + return 0; +} + +int +parse_coro_chain( + RemoteUnwinderObject *unwinder, + uintptr_t coro_address, + PyObject *render_to +) { + assert((void*)coro_address != NULL); + + // Read the entire generator object at once + char gen_object[SIZEOF_GEN_OBJ]; + int err = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + coro_address, + SIZEOF_GEN_OBJ, + gen_object); + if (err < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read generator object in coro chain"); + return -1; + } + + int8_t frame_state = GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state); + if (frame_state == FRAME_CLEARED) { + return 0; + } + + uintptr_t gen_type_addr = GET_MEMBER(uintptr_t, gen_object, unwinder->debug_offsets.pyobject.ob_type); + + PyObject* name = NULL; + + // Parse the previous frame using the gi_iframe from local copy + uintptr_t prev_frame; + uintptr_t gi_iframe_addr = coro_address + (uintptr_t)unwinder->debug_offsets.gen_object.gi_iframe; + uintptr_t address_of_code_object = 0; + if (parse_frame_object(unwinder, &name, gi_iframe_addr, &address_of_code_object, &prev_frame) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in coro chain"); + return -1; + } + + if (!name) { + return 0; + } + + if (PyList_Append(render_to, name)) { + Py_DECREF(name); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to coro chain"); + return -1; + } + Py_DECREF(name); + + if (frame_state == FRAME_SUSPENDED_YIELD_FROM) { + return handle_yield_from_frame(unwinder, gi_iframe_addr, gen_type_addr, render_to); + } + + return 0; +} + +/* ============================================================================ + * TASK PARSING FUNCTIONS + * ============================================================================ */ + +static PyObject* +create_task_result( + RemoteUnwinderObject *unwinder, + uintptr_t task_address +) { + PyObject* result = NULL; + PyObject *call_stack = NULL; + PyObject *tn = NULL; + char task_obj[SIZEOF_TASK_OBJ]; + uintptr_t coro_addr; + + // Create call_stack first since it's the first tuple element + call_stack = PyList_New(0); + if (call_stack == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create call stack list"); + goto error; + } + + // Create task name/address for second tuple element + tn = PyLong_FromUnsignedLongLong(task_address); + if (tn == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name/address"); + goto error; + } + + // Parse coroutine chain + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address, + (size_t)unwinder->async_debug_offsets.asyncio_task_object.size, + task_obj) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object for coro chain"); + goto error; + } + + coro_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_coro); + + if ((void*)coro_addr != NULL) { + if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain"); + goto error; + } + + if (PyList_Reverse(call_stack)) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reverse call stack"); + goto error; + } + } + + // Create final CoroInfo result + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + result = PyStructSequence_New(state->CoroInfo_Type); + if (result == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create CoroInfo"); + goto error; + } + + // PyStructSequence_SetItem steals references, so we don't need to DECREF on success + PyStructSequence_SetItem(result, 0, call_stack); // This steals the reference + PyStructSequence_SetItem(result, 1, tn); // This steals the reference + + return result; + +error: + Py_XDECREF(result); + Py_XDECREF(call_stack); + Py_XDECREF(tn); + return NULL; +} + +int +parse_task( + RemoteUnwinderObject *unwinder, + uintptr_t task_address, + PyObject *render_to +) { + char is_task; + PyObject* result = NULL; + int err; + + err = read_char( + unwinder, + task_address + (uintptr_t)unwinder->async_debug_offsets.asyncio_task_object.task_is_task, + &is_task); + if (err) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read is_task flag"); + goto error; + } + + if (is_task) { + result = create_task_result(unwinder, task_address); + if (!result) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task result"); + goto error; + } + } else { + // Create an empty CoroInfo for non-task objects + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + result = PyStructSequence_New(state->CoroInfo_Type); + if (result == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty CoroInfo"); + goto error; + } + PyObject *empty_list = PyList_New(0); + if (empty_list == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty list"); + goto error; + } + PyObject *task_name = PyLong_FromUnsignedLongLong(task_address); + if (task_name == NULL) { + Py_DECREF(empty_list); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name"); + goto error; + } + PyStructSequence_SetItem(result, 0, empty_list); // This steals the reference + PyStructSequence_SetItem(result, 1, task_name); // This steals the reference + } + if (PyList_Append(render_to, result)) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task result to render list"); + goto error; + } + + Py_DECREF(result); + return 0; + +error: + Py_XDECREF(result); + return -1; +} + +/* ============================================================================ + * TASK AWAITED_BY PROCESSING + * ============================================================================ */ + +// Forward declaration for mutual recursion +static int process_waiter_task(RemoteUnwinderObject *unwinder, uintptr_t key_addr, void *context); + +// Processor function for parsing tasks in sets +static int +process_task_parser( + RemoteUnwinderObject *unwinder, + uintptr_t key_addr, + void *context +) { + PyObject *awaited_by = (PyObject *)context; + return parse_task(unwinder, key_addr, awaited_by); +} + +static int +parse_task_awaited_by( + RemoteUnwinderObject *unwinder, + uintptr_t task_address, + PyObject *awaited_by +) { + return process_task_awaited_by(unwinder, task_address, process_task_parser, awaited_by); +} + +int +process_task_awaited_by( + RemoteUnwinderObject *unwinder, + uintptr_t task_address, + set_entry_processor_func processor, + void *context +) { + // Read the entire TaskObj at once + char task_obj[SIZEOF_TASK_OBJ]; + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address, + (size_t)unwinder->async_debug_offsets.asyncio_task_object.size, + task_obj) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object"); + return -1; + } + + uintptr_t task_ab_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by); + if ((void*)task_ab_addr == NULL) { + return 0; // No tasks waiting for this one + } + + char awaited_by_is_a_set = GET_MEMBER(char, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by_is_set); + + if (awaited_by_is_a_set) { + return iterate_set_entries(unwinder, task_ab_addr, processor, context); + } else { + // Single task waiting + return processor(unwinder, task_ab_addr, context); + } +} + +int +process_single_task_node( + RemoteUnwinderObject *unwinder, + uintptr_t task_addr, + PyObject **task_info, + PyObject *result +) { + PyObject *tn = NULL; + PyObject *current_awaited_by = NULL; + PyObject *task_id = NULL; + PyObject *result_item = NULL; + PyObject *coroutine_stack = NULL; + + tn = parse_task_name(unwinder, task_addr); + if (tn == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task name in single task node"); + goto error; + } + + current_awaited_by = PyList_New(0); + if (current_awaited_by == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by list in single task node"); + goto error; + } + + // Extract the coroutine stack for this task + coroutine_stack = PyList_New(0); + if (coroutine_stack == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coroutine stack list in single task node"); + goto error; + } + + if (parse_task(unwinder, task_addr, coroutine_stack) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task coroutine stack in single task node"); + goto error; + } + + task_id = PyLong_FromUnsignedLongLong(task_addr); + if (task_id == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task ID in single task node"); + goto error; + } + + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + result_item = PyStructSequence_New(state->TaskInfo_Type); + if (result_item == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create TaskInfo in single task node"); + goto error; + } + + PyStructSequence_SetItem(result_item, 0, task_id); // steals ref + PyStructSequence_SetItem(result_item, 1, tn); // steals ref + PyStructSequence_SetItem(result_item, 2, coroutine_stack); // steals ref + PyStructSequence_SetItem(result_item, 3, current_awaited_by); // steals ref + + // References transferred to tuple + task_id = NULL; + tn = NULL; + coroutine_stack = NULL; + current_awaited_by = NULL; + + if (PyList_Append(result, result_item)) { + Py_DECREF(result_item); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append result item in single task node"); + return -1; + } + if (task_info != NULL) { + *task_info = result_item; + } + Py_DECREF(result_item); + + // Get back current_awaited_by reference for parse_task_awaited_by + current_awaited_by = PyStructSequence_GetItem(result_item, 3); + if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse awaited_by in single task node"); + // No cleanup needed here since all references were transferred to result_item + // and result_item was already added to result list and decreffed + return -1; + } + + return 0; + +error: + Py_XDECREF(tn); + Py_XDECREF(current_awaited_by); + Py_XDECREF(task_id); + Py_XDECREF(result_item); + Py_XDECREF(coroutine_stack); + return -1; +} + +int +process_task_and_waiters( + RemoteUnwinderObject *unwinder, + uintptr_t task_addr, + PyObject *result +) { + // First, add this task to the result + if (process_single_task_node(unwinder, task_addr, NULL, result) < 0) { + return -1; + } + + // Now find all tasks that are waiting for this task and process them + return process_task_awaited_by(unwinder, task_addr, process_waiter_task, result); +} + +// Processor function for task waiters +static int +process_waiter_task( + RemoteUnwinderObject *unwinder, + uintptr_t key_addr, + void *context +) { + PyObject *result = (PyObject *)context; + return process_task_and_waiters(unwinder, key_addr, result); +} + +/* ============================================================================ + * RUNNING TASK FUNCTIONS + * ============================================================================ */ + +int +find_running_task_in_thread( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + uintptr_t *running_task_addr +) { + *running_task_addr = (uintptr_t)NULL; + + uintptr_t address_of_running_loop; + int bytes_read = read_py_ptr( + unwinder, + thread_state_addr + (uintptr_t)unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_loop, + &address_of_running_loop); + if (bytes_read == -1) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running loop address"); + return -1; + } + + // no asyncio loop is now running + if ((void*)address_of_running_loop == NULL) { + return 0; + } + + int err = read_ptr( + unwinder, + thread_state_addr + (uintptr_t)unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_task, + running_task_addr); + if (err) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running task address"); + return -1; + } + + return 0; +} + +int +get_task_code_object(RemoteUnwinderObject *unwinder, uintptr_t task_addr, uintptr_t *code_obj_addr) { + uintptr_t running_coro_addr = 0; + + if(read_py_ptr( + unwinder, + task_addr + (uintptr_t)unwinder->async_debug_offsets.asyncio_task_object.task_coro, + &running_coro_addr) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro read failed"); + return -1; + } + + if (running_coro_addr == 0) { + PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro address is NULL"); + return -1; + } + + // note: genobject's gi_iframe is an embedded struct so the address to + // the offset leads directly to its first field: f_executable + if (read_py_ptr( + unwinder, + running_coro_addr + (uintptr_t)unwinder->debug_offsets.gen_object.gi_iframe, code_obj_addr) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running task code object"); + return -1; + } + + if (*code_obj_addr == 0) { + PyErr_SetString(PyExc_RuntimeError, "Running task code object is NULL"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Running task code object address is NULL"); + return -1; + } + + return 0; +} + +/* ============================================================================ + * ASYNC FRAME CHAIN PARSING + * ============================================================================ */ + +int +parse_async_frame_chain( + RemoteUnwinderObject *unwinder, + PyObject *calls, + uintptr_t address_of_thread, + uintptr_t running_task_code_obj +) { + uintptr_t address_of_current_frame; + if (find_running_frame(unwinder, address_of_thread, &address_of_current_frame) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Running frame search failed in async chain"); + return -1; + } + + while ((void*)address_of_current_frame != NULL) { + PyObject* frame_info = NULL; + uintptr_t address_of_code_object; + int res = parse_frame_object( + unwinder, + &frame_info, + address_of_current_frame, + &address_of_code_object, + &address_of_current_frame + ); + + if (res < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Async frame object parsing failed in chain"); + return -1; + } + + if (!frame_info) { + continue; + } + + if (PyList_Append(calls, frame_info) == -1) { + Py_DECREF(frame_info); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame info to async chain"); + return -1; + } + + Py_DECREF(frame_info); + + if (address_of_code_object == running_task_code_obj) { + break; + } + } + + return 0; +} + +/* ============================================================================ + * AWAITED BY PARSING FUNCTIONS + * ============================================================================ */ + +static int +append_awaited_by_for_thread( + RemoteUnwinderObject *unwinder, + uintptr_t head_addr, + PyObject *result +) { + char task_node[SIZEOF_LLIST_NODE]; + + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, head_addr, + sizeof(task_node), task_node) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task node head"); + return -1; + } + + size_t iteration_count = 0; + const size_t MAX_ITERATIONS = 2 << 15; // A reasonable upper bound + + while (GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) != head_addr) { + if (++iteration_count > MAX_ITERATIONS) { + PyErr_SetString(PyExc_RuntimeError, "Task list appears corrupted"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Task list iteration limit exceeded"); + return -1; + } + + if (GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) == 0) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid linked list structure reading remote memory"); + set_exception_cause(unwinder, PyExc_RuntimeError, "NULL pointer in task linked list"); + return -1; + } + + uintptr_t task_addr = (uintptr_t)GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) + - (uintptr_t)unwinder->async_debug_offsets.asyncio_task_object.task_node; + + if (process_single_task_node(unwinder, task_addr, NULL, result) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process task node in awaited_by"); + return -1; + } + + // Read next node + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + (uintptr_t)GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next), + sizeof(task_node), + task_node) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read next task node in awaited_by"); + return -1; + } + } + + return 0; +} + +int +append_awaited_by( + RemoteUnwinderObject *unwinder, + unsigned long tid, + uintptr_t head_addr, + PyObject *result) +{ + PyObject *tid_py = PyLong_FromUnsignedLong(tid); + if (tid_py == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID object"); + return -1; + } + + PyObject* awaited_by_for_thread = PyList_New(0); + if (awaited_by_for_thread == NULL) { + Py_DECREF(tid_py); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by thread list"); + return -1; + } + + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + PyObject *result_item = PyStructSequence_New(state->AwaitedInfo_Type); + if (result_item == NULL) { + Py_DECREF(tid_py); + Py_DECREF(awaited_by_for_thread); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo"); + return -1; + } + + PyStructSequence_SetItem(result_item, 0, tid_py); // steals ref + PyStructSequence_SetItem(result_item, 1, awaited_by_for_thread); // steals ref + if (PyList_Append(result, result_item)) { + Py_DECREF(result_item); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by result item"); + return -1; + } + Py_DECREF(result_item); + + if (append_awaited_by_for_thread(unwinder, head_addr, awaited_by_for_thread)) + { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by for thread"); + return -1; + } + + return 0; +} + +/* ============================================================================ + * THREAD PROCESSOR FUNCTIONS FOR ASYNCIO + * ============================================================================ */ + +int +process_thread_for_awaited_by( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + unsigned long tid, + void *context +) { + PyObject *result = (PyObject *)context; + uintptr_t head_addr = thread_state_addr + (uintptr_t)unwinder->async_debug_offsets.asyncio_thread_state.asyncio_tasks_head; + return append_awaited_by(unwinder, tid, head_addr, result); +} + +static int +process_running_task_chain( + RemoteUnwinderObject *unwinder, + uintptr_t running_task_addr, + uintptr_t thread_state_addr, + PyObject *result +) { + uintptr_t running_task_code_obj = 0; + if(get_task_code_object(unwinder, running_task_addr, &running_task_code_obj) < 0) { + return -1; + } + + // First, add this task to the result + PyObject *task_info = NULL; + if (process_single_task_node(unwinder, running_task_addr, &task_info, result) < 0) { + return -1; + } + + // Get the chain from the current frame to this task + PyObject *coro_chain = PyStructSequence_GET_ITEM(task_info, 2); + assert(coro_chain != NULL); + if (PyList_GET_SIZE(coro_chain) != 1) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Coro chain is not a single item"); + return -1; + } + PyObject *coro_info = PyList_GET_ITEM(coro_chain, 0); + assert(coro_info != NULL); + PyObject *frame_chain = PyStructSequence_GET_ITEM(coro_info, 0); + assert(frame_chain != NULL); + + // Clear the coro_chain + if (PyList_Clear(frame_chain) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to clear coroutine chain"); + return -1; + } + + // Add the chain from the current frame to this task + if (parse_async_frame_chain(unwinder, frame_chain, thread_state_addr, running_task_code_obj) < 0) { + return -1; + } + + // Now find all tasks that are waiting for this task and process them + if (process_task_awaited_by(unwinder, running_task_addr, process_waiter_task, result) < 0) { + return -1; + } + + return 0; +} + +int +process_thread_for_async_stack_trace( + RemoteUnwinderObject *unwinder, + uintptr_t thread_state_addr, + unsigned long tid, + void *context +) { + PyObject *result = (PyObject *)context; + + // Find running task in this thread + uintptr_t running_task_addr; + if (find_running_task_in_thread(unwinder, thread_state_addr, &running_task_addr) < 0) { + return 0; + } + + // If we found a running task, process it and its waiters + if ((void*)running_task_addr != NULL) { + PyObject *task_list = PyList_New(0); + if (task_list == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create task list for thread"); + return -1; + } + + if (process_running_task_chain(unwinder, running_task_addr, thread_state_addr, task_list) < 0) { + Py_DECREF(task_list); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process running task chain"); + return -1; + } + + // Create AwaitedInfo structure for this thread + PyObject *tid_py = PyLong_FromUnsignedLong(tid); + if (tid_py == NULL) { + Py_DECREF(task_list); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID"); + return -1; + } + + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + PyObject *awaited_info = PyStructSequence_New(state->AwaitedInfo_Type); + if (awaited_info == NULL) { + Py_DECREF(tid_py); + Py_DECREF(task_list); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo"); + return -1; + } + + PyStructSequence_SetItem(awaited_info, 0, tid_py); // steals ref + PyStructSequence_SetItem(awaited_info, 1, task_list); // steals ref + + if (PyList_Append(result, awaited_info)) { + Py_DECREF(awaited_info); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append AwaitedInfo to result"); + return -1; + } + Py_DECREF(awaited_info); + } + + return 0; +} diff --git a/Modules/_remote_debugging/clinic/module.c.h b/Modules/_remote_debugging/clinic/module.c.h new file mode 100644 index 00000000000..5cbf64517af --- /dev/null +++ b/Modules/_remote_debugging/clinic/module.c.h @@ -0,0 +1,585 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + +PyDoc_STRVAR(_remote_debugging_RemoteUnwinder___init____doc__, +"RemoteUnwinder(pid, *, all_threads=False, only_active_thread=False,\n" +" mode=0, debug=False, skip_non_matching_threads=True,\n" +" native=False, gc=False, opcodes=False,\n" +" cache_frames=False, stats=False)\n" +"--\n" +"\n" +"Initialize a new RemoteUnwinder object for debugging a remote Python process.\n" +"\n" +"Args:\n" +" pid: Process ID of the target Python process to debug\n" +" all_threads: If True, initialize state for all threads in the process.\n" +" If False, only initialize for the main thread.\n" +" only_active_thread: If True, only sample the thread holding the GIL.\n" +" mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL (gil-time).\n" +" Cannot be used together with all_threads=True.\n" +" debug: If True, chain exceptions to explain the sequence of events that\n" +" lead to the exception.\n" +" skip_non_matching_threads: If True, skip threads that don\'t match the selected mode.\n" +" If False, include all threads regardless of mode.\n" +" native: If True, include artificial \"<native>\" frames to denote calls to\n" +" non-Python code.\n" +" gc: If True, include artificial \"<GC>\" frames to denote active garbage\n" +" collection.\n" +" opcodes: If True, gather bytecode opcode information for instruction-level\n" +" profiling.\n" +" cache_frames: If True, enable frame caching optimization to avoid re-reading\n" +" unchanged parent frames between samples.\n" +" stats: If True, collect statistics about cache hits, memory reads, etc.\n" +" Use get_stats() to retrieve the collected statistics.\n" +"\n" +"The RemoteUnwinder provides functionality to inspect and debug a running Python\n" +"process, including examining thread states, stack frames and other runtime data.\n" +"\n" +"Raises:\n" +" PermissionError: If access to the target process is denied\n" +" OSError: If unable to attach to the target process or access its memory\n" +" RuntimeError: If unable to read debug information from the target process\n" +" ValueError: If both all_threads and only_active_thread are True"); + +static int +_remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, + int pid, int all_threads, + int only_active_thread, + int mode, int debug, + int skip_non_matching_threads, + int native, int gc, + int opcodes, int cache_frames, + int stats); + +static int +_remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 11 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(pid), &_Py_ID(all_threads), &_Py_ID(only_active_thread), &_Py_ID(mode), &_Py_ID(debug), &_Py_ID(skip_non_matching_threads), &_Py_ID(native), &_Py_ID(gc), &_Py_ID(opcodes), &_Py_ID(cache_frames), &_Py_ID(stats), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"pid", "all_threads", "only_active_thread", "mode", "debug", "skip_non_matching_threads", "native", "gc", "opcodes", "cache_frames", "stats", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "RemoteUnwinder", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[11]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; + int pid; + int all_threads = 0; + int only_active_thread = 0; + int mode = 0; + int debug = 0; + int skip_non_matching_threads = 1; + int native = 0; + int gc = 0; + int opcodes = 0; + int cache_frames = 0; + int stats = 0; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + pid = PyLong_AsInt(fastargs[0]); + if (pid == -1 && PyErr_Occurred()) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + all_threads = PyObject_IsTrue(fastargs[1]); + if (all_threads < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[2]) { + only_active_thread = PyObject_IsTrue(fastargs[2]); + if (only_active_thread < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[3]) { + mode = PyLong_AsInt(fastargs[3]); + if (mode == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[4]) { + debug = PyObject_IsTrue(fastargs[4]); + if (debug < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[5]) { + skip_non_matching_threads = PyObject_IsTrue(fastargs[5]); + if (skip_non_matching_threads < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[6]) { + native = PyObject_IsTrue(fastargs[6]); + if (native < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[7]) { + gc = PyObject_IsTrue(fastargs[7]); + if (gc < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[8]) { + opcodes = PyObject_IsTrue(fastargs[8]); + if (opcodes < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[9]) { + cache_frames = PyObject_IsTrue(fastargs[9]); + if (cache_frames < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + stats = PyObject_IsTrue(fastargs[10]); + if (stats < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _remote_debugging_RemoteUnwinder___init___impl((RemoteUnwinderObject *)self, pid, all_threads, only_active_thread, mode, debug, skip_non_matching_threads, native, gc, opcodes, cache_frames, stats); + +exit: + return return_value; +} + +PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stack_trace__doc__, +"get_stack_trace($self, /)\n" +"--\n" +"\n" +"Returns stack traces for all interpreters and threads in process.\n" +"\n" +"Each element in the returned list is a tuple of (interpreter_id, thread_list), where:\n" +"- interpreter_id is the interpreter identifier\n" +"- thread_list is a list of tuples (thread_id, frame_list) for threads in that interpreter\n" +" - thread_id is the OS thread identifier\n" +" - frame_list is a list of tuples (function_name, filename, line_number) representing\n" +" the Python stack frames for that thread, ordered from most recent to oldest\n" +"\n" +"The threads returned depend on the initialization parameters:\n" +"- If only_active_thread was True: returns only the thread holding the GIL across all interpreters\n" +"- If all_threads was True: returns all threads across all interpreters\n" +"- Otherwise: returns only the main thread of each interpreter\n" +"\n" +"Example:\n" +" [\n" +" (0, [ # Main interpreter\n" +" (1234, [\n" +" (\'process_data\', \'worker.py\', 127),\n" +" (\'run_worker\', \'worker.py\', 45),\n" +" (\'main\', \'app.py\', 23)\n" +" ]),\n" +" (1235, [\n" +" (\'handle_request\', \'server.py\', 89),\n" +" (\'serve_forever\', \'server.py\', 52)\n" +" ])\n" +" ]),\n" +" (1, [ # Sub-interpreter\n" +" (1236, [\n" +" (\'sub_worker\', \'sub.py\', 15)\n" +" ])\n" +" ])\n" +" ]\n" +"\n" +"Raises:\n" +" RuntimeError: If there is an error copying memory from the target process\n" +" OSError: If there is an error accessing the target process\n" +" PermissionError: If access to the target process is denied\n" +" UnicodeDecodeError: If there is an error decoding strings from the target process"); + +#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STACK_TRACE_METHODDEF \ + {"get_stack_trace", (PyCFunction)_remote_debugging_RemoteUnwinder_get_stack_trace, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_stack_trace__doc__}, + +static PyObject * +_remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self); + +static PyObject * +_remote_debugging_RemoteUnwinder_get_stack_trace(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _remote_debugging_RemoteUnwinder_get_stack_trace_impl((RemoteUnwinderObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_all_awaited_by__doc__, +"get_all_awaited_by($self, /)\n" +"--\n" +"\n" +"Get all tasks and their awaited_by relationships from the remote process.\n" +"\n" +"This provides a tree structure showing which tasks are waiting for other tasks.\n" +"\n" +"For each task, returns:\n" +"1. The call stack frames leading to where the task is currently executing\n" +"2. The name of the task\n" +"3. A list of tasks that this task is waiting for, with their own frames/names/etc\n" +"\n" +"Returns a list of [frames, task_name, subtasks] where:\n" +"- frames: List of (func_name, filename, lineno) showing the call stack\n" +"- task_name: String identifier for the task\n" +"- subtasks: List of tasks being awaited by this task, in same format\n" +"\n" +"Raises:\n" +" RuntimeError: If AsyncioDebug section is not available in the remote process\n" +" MemoryError: If memory allocation fails\n" +" OSError: If reading from the remote process fails\n" +"\n" +"Example output:\n" +"[\n" +" [\n" +" [(\"c5\", \"script.py\", 10), (\"c4\", \"script.py\", 14)],\n" +" \"c2_root\",\n" +" [\n" +" [\n" +" [(\"c1\", \"script.py\", 23)],\n" +" \"sub_main_2\",\n" +" [...]\n" +" ],\n" +" [...]\n" +" ]\n" +" ]\n" +"]"); + +#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ALL_AWAITED_BY_METHODDEF \ + {"get_all_awaited_by", (PyCFunction)_remote_debugging_RemoteUnwinder_get_all_awaited_by, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_all_awaited_by__doc__}, + +static PyObject * +_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *self); + +static PyObject * +_remote_debugging_RemoteUnwinder_get_all_awaited_by(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl((RemoteUnwinderObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__, +"get_async_stack_trace($self, /)\n" +"--\n" +"\n" +"Get the currently running async tasks and their dependency graphs from the remote process.\n" +"\n" +"This returns information about running tasks and all tasks that are waiting for them,\n" +"forming a complete dependency graph for each thread\'s active task.\n" +"\n" +"For each thread with a running task, returns the running task plus all tasks that\n" +"transitively depend on it (tasks waiting for the running task, tasks waiting for\n" +"those tasks, etc.).\n" +"\n" +"Returns a list of per-thread results, where each thread result contains:\n" +"- Thread ID\n" +"- List of task information for the running task and all its waiters\n" +"\n" +"Each task info contains:\n" +"- Task ID (memory address)\n" +"- Task name\n" +"- Call stack frames: List of (func_name, filename, lineno)\n" +"- List of tasks waiting for this task (recursive structure)\n" +"\n" +"Raises:\n" +" RuntimeError: If AsyncioDebug section is not available in the target process\n" +" MemoryError: If memory allocation fails\n" +" OSError: If reading from the remote process fails\n" +"\n" +"Example output (similar structure to get_all_awaited_by but only for running tasks):\n" +"[\n" +" (140234, [\n" +" (4345585712, \'main_task\',\n" +" [(\"run_server\", \"server.py\", 127), (\"main\", \"app.py\", 23)],\n" +" [\n" +" (4345585800, \'worker_1\', [...], [...]),\n" +" (4345585900, \'worker_2\', [...], [...])\n" +" ])\n" +" ])\n" +"]"); + +#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ASYNC_STACK_TRACE_METHODDEF \ + {"get_async_stack_trace", (PyCFunction)_remote_debugging_RemoteUnwinder_get_async_stack_trace, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__}, + +static PyObject * +_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject *self); + +static PyObject * +_remote_debugging_RemoteUnwinder_get_async_stack_trace(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _remote_debugging_RemoteUnwinder_get_async_stack_trace_impl((RemoteUnwinderObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stats__doc__, +"get_stats($self, /)\n" +"--\n" +"\n" +"Get collected statistics about profiling performance.\n" +"\n" +"Returns a dictionary containing statistics about cache performance,\n" +"memory reads, and other profiling metrics. Only available if the\n" +"RemoteUnwinder was created with stats=True.\n" +"\n" +"Returns:\n" +" dict: A dictionary containing:\n" +" - total_samples: Total number of get_stack_trace calls\n" +" - frame_cache_hits: Full cache hits (entire stack unchanged)\n" +" - frame_cache_misses: Cache misses requiring full walk\n" +" - frame_cache_partial_hits: Partial hits (stopped at cached frame)\n" +" - frames_read_from_cache: Total frames retrieved from cache\n" +" - frames_read_from_memory: Total frames read from remote memory\n" +" - memory_reads: Total remote memory read operations\n" +" - memory_bytes_read: Total bytes read from remote memory\n" +" - code_object_cache_hits: Code object cache hits\n" +" - code_object_cache_misses: Code object cache misses\n" +" - stale_cache_invalidations: Times stale cache entries were cleared\n" +" - frame_cache_hit_rate: Percentage of samples that hit the cache\n" +" - code_object_cache_hit_rate: Percentage of code object lookups that hit cache\n" +"\n" +"Raises:\n" +" RuntimeError: If stats collection was not enabled (stats=False)"); + +#define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STATS_METHODDEF \ + {"get_stats", (PyCFunction)_remote_debugging_RemoteUnwinder_get_stats, METH_NOARGS, _remote_debugging_RemoteUnwinder_get_stats__doc__}, + +static PyObject * +_remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self); + +static PyObject * +_remote_debugging_RemoteUnwinder_get_stats(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _remote_debugging_RemoteUnwinder_get_stats_impl((RemoteUnwinderObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_remote_debugging_get_child_pids__doc__, +"get_child_pids($module, /, pid, *, recursive=True)\n" +"--\n" +"\n" +"Get all child process IDs of the given process.\n" +"\n" +" pid\n" +" Process ID of the parent process\n" +" recursive\n" +" If True, return all descendants (children, grandchildren, etc.).\n" +" If False, return only direct children.\n" +"\n" +"Returns a list of child process IDs. Returns an empty list if no children\n" +"are found.\n" +"\n" +"This function provides a snapshot of child processes at a moment in time.\n" +"Child processes may exit or new ones may be created after the list is returned.\n" +"\n" +"Raises:\n" +" OSError: If unable to enumerate processes\n" +" NotImplementedError: If not supported on this platform"); + +#define _REMOTE_DEBUGGING_GET_CHILD_PIDS_METHODDEF \ + {"get_child_pids", _PyCFunction_CAST(_remote_debugging_get_child_pids), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_get_child_pids__doc__}, + +static PyObject * +_remote_debugging_get_child_pids_impl(PyObject *module, int pid, + int recursive); + +static PyObject * +_remote_debugging_get_child_pids(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(pid), &_Py_ID(recursive), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"pid", "recursive", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_child_pids", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + int pid; + int recursive = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + pid = PyLong_AsInt(args[0]); + if (pid == -1 && PyErr_Occurred()) { + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + recursive = PyObject_IsTrue(args[1]); + if (recursive < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _remote_debugging_get_child_pids_impl(module, pid, recursive); + +exit: + return return_value; +} + +PyDoc_STRVAR(_remote_debugging_is_python_process__doc__, +"is_python_process($module, /, pid)\n" +"--\n" +"\n" +"Check if a process is a Python process."); + +#define _REMOTE_DEBUGGING_IS_PYTHON_PROCESS_METHODDEF \ + {"is_python_process", _PyCFunction_CAST(_remote_debugging_is_python_process), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_is_python_process__doc__}, + +static PyObject * +_remote_debugging_is_python_process_impl(PyObject *module, int pid); + +static PyObject * +_remote_debugging_is_python_process(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(pid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"pid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_python_process", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int pid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + pid = PyLong_AsInt(args[0]); + if (pid == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _remote_debugging_is_python_process_impl(module, pid); + +exit: + return return_value; +} +/*[clinic end generated code: output=dc0550ad3d6a409c input=a9049054013a1b77]*/ diff --git a/Modules/_remote_debugging/code_objects.c b/Modules/_remote_debugging/code_objects.c new file mode 100644 index 00000000000..ca6ffe7a00a --- /dev/null +++ b/Modules/_remote_debugging/code_objects.c @@ -0,0 +1,464 @@ +/****************************************************************************** + * Remote Debugging Module - Code Object Functions + * + * This file contains functions for parsing code objects and line tables + * from remote process memory. + ******************************************************************************/ + +#include "_remote_debugging.h" + +/* ============================================================================ + * TLBC CACHING FUNCTIONS (Py_GIL_DISABLED only) + * ============================================================================ */ + +#ifdef Py_GIL_DISABLED + +void +tlbc_cache_entry_destroy(void *ptr) +{ + TLBCCacheEntry *entry = (TLBCCacheEntry *)ptr; + if (entry->tlbc_array) { + PyMem_RawFree(entry->tlbc_array); + } + PyMem_RawFree(entry); +} + +TLBCCacheEntry * +get_tlbc_cache_entry(RemoteUnwinderObject *self, uintptr_t code_addr, uint32_t current_generation) +{ + void *key = (void *)code_addr; + TLBCCacheEntry *entry = _Py_hashtable_get(self->tlbc_cache, key); + + if (entry && entry->generation != current_generation) { + // Entry is stale, remove it by setting to NULL + _Py_hashtable_set(self->tlbc_cache, key, NULL); + entry = NULL; + } + + return entry; +} + +int +cache_tlbc_array(RemoteUnwinderObject *unwinder, uintptr_t code_addr, uintptr_t tlbc_array_addr, uint32_t generation) +{ + uintptr_t tlbc_array_ptr; + void *tlbc_array = NULL; + TLBCCacheEntry *entry = NULL; + + // Read the TLBC array pointer + if (read_ptr(unwinder, tlbc_array_addr, &tlbc_array_ptr) != 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to read TLBC array pointer"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array pointer"); + return 0; // Read error + } + + // Validate TLBC array pointer + if (tlbc_array_ptr == 0) { + PyErr_SetString(PyExc_RuntimeError, "TLBC array pointer is NULL"); + return 0; // No TLBC array + } + + // Read the TLBC array size + Py_ssize_t tlbc_size; + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(tlbc_size), &tlbc_size) != 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to read TLBC array size"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array size"); + return 0; // Read error + } + + // Validate TLBC array size + if (tlbc_size <= 0) { + PyErr_SetString(PyExc_RuntimeError, "Invalid TLBC array size"); + return 0; // Invalid size + } + + if (tlbc_size > MAX_TLBC_SIZE) { + PyErr_SetString(PyExc_RuntimeError, "TLBC array size exceeds maximum limit"); + return 0; // Invalid size + } + assert(tlbc_size > 0 && tlbc_size <= MAX_TLBC_SIZE); + + // Allocate and read the entire TLBC array + size_t array_data_size = tlbc_size * sizeof(void*); + tlbc_array = PyMem_RawMalloc(sizeof(Py_ssize_t) + array_data_size); + if (!tlbc_array) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate TLBC array"); + return 0; // Memory error + } + + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(Py_ssize_t) + array_data_size, tlbc_array) != 0) { + PyMem_RawFree(tlbc_array); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array data"); + return 0; // Read error + } + + // Create cache entry + entry = PyMem_RawMalloc(sizeof(TLBCCacheEntry)); + if (!entry) { + PyErr_NoMemory(); + PyMem_RawFree(tlbc_array); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate TLBC cache entry"); + return 0; // Memory error + } + + entry->tlbc_array = tlbc_array; + entry->tlbc_array_size = tlbc_size; + entry->generation = generation; + + // Store in cache + void *key = (void *)code_addr; + if (_Py_hashtable_set(unwinder->tlbc_cache, key, entry) < 0) { + tlbc_cache_entry_destroy(entry); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to store TLBC entry in cache"); + return 0; // Cache error + } + + return 1; // Success +} + +#endif + +/* ============================================================================ + * LINE TABLE PARSING FUNCTIONS + * ============================================================================ */ + +static int +scan_varint(const uint8_t **ptr) +{ + unsigned int read = **ptr; + *ptr = *ptr + 1; + unsigned int val = read & 63; + unsigned int shift = 0; + while (read & 64) { + read = **ptr; + *ptr = *ptr + 1; + shift += 6; + val |= (read & 63) << shift; + } + return val; +} + +static int +scan_signed_varint(const uint8_t **ptr) +{ + unsigned int uval = scan_varint(ptr); + if (uval & 1) { + return -(int)(uval >> 1); + } + else { + return uval >> 1; + } +} + +bool +parse_linetable(const uintptr_t addrq, const char* linetable, int firstlineno, LocationInfo* info) +{ + const uint8_t* ptr = (const uint8_t*)(linetable); + uintptr_t addr = 0; + int computed_line = firstlineno; // Running accumulator, separate from output + const size_t MAX_LINETABLE_ENTRIES = 65536; + size_t entry_count = 0; + + while (*ptr != '\0' && entry_count < MAX_LINETABLE_ENTRIES) { + entry_count++; + uint8_t first_byte = *(ptr++); + uint8_t code = (first_byte >> 3) & 15; + size_t length = (first_byte & 7) + 1; + uintptr_t end_addr = addr + length; + + switch (code) { + case PY_CODE_LOCATION_INFO_NONE: + info->lineno = info->end_lineno = -1; + info->column = info->end_column = -1; + break; + case PY_CODE_LOCATION_INFO_LONG: + computed_line += scan_signed_varint(&ptr); + info->lineno = computed_line; + info->end_lineno = computed_line + scan_varint(&ptr); + info->column = scan_varint(&ptr) - 1; + info->end_column = scan_varint(&ptr) - 1; + break; + case PY_CODE_LOCATION_INFO_NO_COLUMNS: + computed_line += scan_signed_varint(&ptr); + info->lineno = info->end_lineno = computed_line; + info->column = info->end_column = -1; + break; + case PY_CODE_LOCATION_INFO_ONE_LINE0: + case PY_CODE_LOCATION_INFO_ONE_LINE1: + case PY_CODE_LOCATION_INFO_ONE_LINE2: + computed_line += code - 10; + info->lineno = info->end_lineno = computed_line; + info->column = *(ptr++); + info->end_column = *(ptr++); + break; + default: { + uint8_t second_byte = *(ptr++); + if ((second_byte & 128) != 0) { + return false; + } + info->lineno = info->end_lineno = computed_line; + info->column = code << 3 | (second_byte >> 4); + info->end_column = info->column + (second_byte & 15); + break; + } + } + if (addr <= addrq && end_addr > addrq) { + return true; + } + addr = end_addr; + } + return false; +} + +/* ============================================================================ + * CODE OBJECT AND FRAME INFO FUNCTIONS + * ============================================================================ */ + +PyObject * +make_location_info(RemoteUnwinderObject *unwinder, int lineno, int end_lineno, + int col_offset, int end_col_offset) +{ + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + PyObject *info = PyStructSequence_New(state->LocationInfo_Type); + if (info == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create LocationInfo"); + return NULL; + } + + PyObject *py_lineno = PyLong_FromLong(lineno); + if (py_lineno == NULL) { + Py_DECREF(info); + return NULL; + } + PyStructSequence_SetItem(info, 0, py_lineno); // steals reference + + PyObject *py_end_lineno = PyLong_FromLong(end_lineno); + if (py_end_lineno == NULL) { + Py_DECREF(info); + return NULL; + } + PyStructSequence_SetItem(info, 1, py_end_lineno); // steals reference + + PyObject *py_col_offset = PyLong_FromLong(col_offset); + if (py_col_offset == NULL) { + Py_DECREF(info); + return NULL; + } + PyStructSequence_SetItem(info, 2, py_col_offset); // steals reference + + PyObject *py_end_col_offset = PyLong_FromLong(end_col_offset); + if (py_end_col_offset == NULL) { + Py_DECREF(info); + return NULL; + } + PyStructSequence_SetItem(info, 3, py_end_col_offset); // steals reference + + return info; +} + +PyObject * +make_frame_info(RemoteUnwinderObject *unwinder, PyObject *file, PyObject *location, + PyObject *func, PyObject *opcode) +{ + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + PyObject *info = PyStructSequence_New(state->FrameInfo_Type); + if (info == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create FrameInfo"); + return NULL; + } + Py_INCREF(file); + Py_INCREF(location); + Py_INCREF(func); + Py_INCREF(opcode); + PyStructSequence_SetItem(info, 0, file); + PyStructSequence_SetItem(info, 1, location); + PyStructSequence_SetItem(info, 2, func); + PyStructSequence_SetItem(info, 3, opcode); + return info; +} + +int +parse_code_object(RemoteUnwinderObject *unwinder, + PyObject **result, + const CodeObjectContext *ctx) +{ + void *key = (void *)ctx->code_addr; + CachedCodeMetadata *meta = NULL; + PyObject *func = NULL; + PyObject *file = NULL; + PyObject *linetable = NULL; + +#ifdef Py_GIL_DISABLED + // In free threading builds, code object addresses might have the low bit set + // as a flag, so we need to mask it off to get the real address + uintptr_t real_address = ctx->code_addr & (~1); +#else + uintptr_t real_address = ctx->code_addr; +#endif + + if (unwinder && unwinder->code_object_cache != NULL) { + meta = _Py_hashtable_get(unwinder->code_object_cache, key); + if (meta) { + STATS_INC(unwinder, code_object_cache_hits); + } else { + STATS_INC(unwinder, code_object_cache_misses); + } + } + + if (meta == NULL) { + char code_object[SIZEOF_CODE_OBJ]; + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, real_address, SIZEOF_CODE_OBJ, code_object) < 0) + { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read code object"); + goto error; + } + + func = read_py_str(unwinder, + GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.qualname), 1024); + if (!func) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read function name from code object"); + goto error; + } + + file = read_py_str(unwinder, + GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.filename), 1024); + if (!file) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read filename from code object"); + goto error; + } + + linetable = read_py_bytes(unwinder, + GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.linetable), 4096); + if (!linetable) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read linetable from code object"); + goto error; + } + + meta = PyMem_RawMalloc(sizeof(CachedCodeMetadata)); + if (!meta) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate cached code metadata"); + goto error; + } + + meta->func_name = func; + meta->file_name = file; + meta->linetable = linetable; + meta->first_lineno = GET_MEMBER(int, code_object, unwinder->debug_offsets.code_object.firstlineno); + meta->addr_code_adaptive = real_address + (uintptr_t)unwinder->debug_offsets.code_object.co_code_adaptive; + + if (unwinder && unwinder->code_object_cache && _Py_hashtable_set(unwinder->code_object_cache, key, meta) < 0) { + cached_code_metadata_destroy(meta); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to cache code metadata"); + goto error; + } + + // Ownership transferred to meta + func = NULL; + file = NULL; + linetable = NULL; + } + + uintptr_t ip = ctx->instruction_pointer; + ptrdiff_t addrq; + +#ifdef Py_GIL_DISABLED + // Handle thread-local bytecode (TLBC) in free threading builds + if (ctx->tlbc_index == 0 || unwinder->debug_offsets.code_object.co_tlbc == 0 || unwinder == NULL) { + // No TLBC or no unwinder - use main bytecode directly + addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; + goto done_tlbc; + } + + // Try to get TLBC data from cache (we'll get generation from the caller) + TLBCCacheEntry *tlbc_entry = get_tlbc_cache_entry(unwinder, real_address, unwinder->tlbc_generation); + + if (!tlbc_entry) { + // Cache miss - try to read and cache TLBC array + if (!cache_tlbc_array(unwinder, real_address, real_address + unwinder->debug_offsets.code_object.co_tlbc, unwinder->tlbc_generation)) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to cache TLBC array"); + goto error; + } + tlbc_entry = get_tlbc_cache_entry(unwinder, real_address, unwinder->tlbc_generation); + } + + if (tlbc_entry && ctx->tlbc_index < tlbc_entry->tlbc_array_size) { + assert(ctx->tlbc_index >= 0); + assert(tlbc_entry->tlbc_array_size > 0); + // Use cached TLBC data + uintptr_t *entries = (uintptr_t *)((char *)tlbc_entry->tlbc_array + sizeof(Py_ssize_t)); + uintptr_t tlbc_bytecode_addr = entries[ctx->tlbc_index]; + + if (tlbc_bytecode_addr != 0) { + // Calculate offset from TLBC bytecode + addrq = (uint16_t *)ip - (uint16_t *)tlbc_bytecode_addr; + goto done_tlbc; + } + } + + // Fall back to main bytecode + addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; + +done_tlbc: +#else + // Non-free-threaded build, always use the main bytecode + addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; +#endif + ; // Empty statement to avoid C23 extension warning + LocationInfo info = {0}; + bool ok = parse_linetable(addrq, PyBytes_AS_STRING(meta->linetable), + meta->first_lineno, &info); + if (!ok) { + info.lineno = -1; + info.end_lineno = -1; + info.column = -1; + info.end_column = -1; + } + + // Create the LocationInfo structseq: (lineno, end_lineno, col_offset, end_col_offset) + PyObject *location = make_location_info(unwinder, + info.lineno, + info.end_lineno, + info.column, + info.end_column); + if (!location) { + goto error; + } + + // Read the instruction opcode from target process if opcodes flag is set + PyObject *opcode_obj = NULL; + if (unwinder->opcodes) { + uint16_t instruction_word = 0; + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, ip, + sizeof(uint16_t), &instruction_word) == 0) { + opcode_obj = PyLong_FromLong(instruction_word & 0xFF); + if (!opcode_obj) { + Py_DECREF(location); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create opcode object"); + goto error; + } + } else { + // Opcode read failed - clear the exception since opcode is optional + PyErr_Clear(); + } + } + + PyObject *tuple = make_frame_info(unwinder, meta->file_name, location, + meta->func_name, opcode_obj ? opcode_obj : Py_None); + Py_DECREF(location); + Py_XDECREF(opcode_obj); + if (!tuple) { + goto error; + } + + *result = tuple; + return 0; + +error: + Py_XDECREF(func); + Py_XDECREF(file); + Py_XDECREF(linetable); + return -1; +} diff --git a/Modules/_remote_debugging/frame_cache.c b/Modules/_remote_debugging/frame_cache.c new file mode 100644 index 00000000000..e94f4d3d81c --- /dev/null +++ b/Modules/_remote_debugging/frame_cache.c @@ -0,0 +1,258 @@ +/****************************************************************************** + * Remote Debugging Module - Frame Cache + * + * This file contains functions for caching frame information to optimize + * repeated stack unwinding for profiling. + ******************************************************************************/ + +#include "_remote_debugging.h" + +/* ============================================================================ + * FRAME CACHE - stores (address, frame_info) pairs per thread + * Uses preallocated fixed-size arrays for efficiency and bounded memory. + * ============================================================================ */ + +int +frame_cache_init(RemoteUnwinderObject *unwinder) +{ + unwinder->frame_cache = PyMem_Calloc(FRAME_CACHE_MAX_THREADS, sizeof(FrameCacheEntry)); + if (!unwinder->frame_cache) { + PyErr_NoMemory(); + return -1; + } + return 0; +} + +void +frame_cache_cleanup(RemoteUnwinderObject *unwinder) +{ + if (!unwinder->frame_cache) { + return; + } + for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + Py_CLEAR(unwinder->frame_cache[i].frame_list); + } + PyMem_Free(unwinder->frame_cache); + unwinder->frame_cache = NULL; +} + +// Find cache entry by thread_id +FrameCacheEntry * +frame_cache_find(RemoteUnwinderObject *unwinder, uint64_t thread_id) +{ + if (!unwinder->frame_cache || thread_id == 0) { + return NULL; + } + for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + assert(i >= 0 && i < FRAME_CACHE_MAX_THREADS); + if (unwinder->frame_cache[i].thread_id == thread_id) { + assert(unwinder->frame_cache[i].num_addrs <= FRAME_CACHE_MAX_FRAMES); + return &unwinder->frame_cache[i]; + } + } + return NULL; +} + +// Allocate a cache slot for a thread +// Returns NULL if cache is full (graceful degradation) +static FrameCacheEntry * +frame_cache_alloc_slot(RemoteUnwinderObject *unwinder, uint64_t thread_id) +{ + if (!unwinder->frame_cache || thread_id == 0) { + return NULL; + } + // First check if thread already has an entry + for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + if (unwinder->frame_cache[i].thread_id == thread_id) { + return &unwinder->frame_cache[i]; + } + } + // Find empty slot + for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + if (unwinder->frame_cache[i].thread_id == 0) { + return &unwinder->frame_cache[i]; + } + } + // Cache full - graceful degradation + return NULL; +} + +// Remove cache entries for threads not seen in the result +// result structure: list of InterpreterInfo, where InterpreterInfo[1] is threads list, +// and ThreadInfo[0] is the thread_id +void +frame_cache_invalidate_stale(RemoteUnwinderObject *unwinder, PyObject *result) +{ + if (!unwinder->frame_cache || !result || !PyList_Check(result)) { + return; + } + + // Build array of seen thread IDs from result + uint64_t seen_threads[FRAME_CACHE_MAX_THREADS]; + int num_seen = 0; + + Py_ssize_t num_interps = PyList_GET_SIZE(result); + for (Py_ssize_t i = 0; i < num_interps && num_seen < FRAME_CACHE_MAX_THREADS; i++) { + PyObject *interp_info = PyList_GET_ITEM(result, i); + PyObject *threads = PyStructSequence_GetItem(interp_info, 1); + if (!threads || !PyList_Check(threads)) { + continue; + } + Py_ssize_t num_threads = PyList_GET_SIZE(threads); + for (Py_ssize_t j = 0; j < num_threads && num_seen < FRAME_CACHE_MAX_THREADS; j++) { + PyObject *thread_info = PyList_GET_ITEM(threads, j); + PyObject *tid_obj = PyStructSequence_GetItem(thread_info, 0); + if (tid_obj) { + uint64_t tid = PyLong_AsUnsignedLongLong(tid_obj); + if (!PyErr_Occurred()) { + seen_threads[num_seen++] = tid; + } else { + PyErr_Clear(); + } + } + } + } + + // Invalidate entries not in seen list + for (int i = 0; i < FRAME_CACHE_MAX_THREADS; i++) { + if (unwinder->frame_cache[i].thread_id == 0) { + continue; + } + int found = 0; + for (int j = 0; j < num_seen; j++) { + if (unwinder->frame_cache[i].thread_id == seen_threads[j]) { + found = 1; + break; + } + } + if (!found) { + // Clear this entry + Py_CLEAR(unwinder->frame_cache[i].frame_list); + unwinder->frame_cache[i].thread_id = 0; + unwinder->frame_cache[i].num_addrs = 0; + STATS_INC(unwinder, stale_cache_invalidations); + } + } +} + +// Find last_profiled_frame in cache and extend frame_info with cached continuation +// If frame_addrs is provided (not NULL), also extends it with cached addresses +int +frame_cache_lookup_and_extend( + RemoteUnwinderObject *unwinder, + uint64_t thread_id, + uintptr_t last_profiled_frame, + PyObject *frame_info, + uintptr_t *frame_addrs, + Py_ssize_t *num_addrs, + Py_ssize_t max_addrs) +{ + if (!unwinder->frame_cache || last_profiled_frame == 0) { + return 0; + } + + FrameCacheEntry *entry = frame_cache_find(unwinder, thread_id); + if (!entry || !entry->frame_list) { + return 0; + } + + assert(entry->num_addrs >= 0 && entry->num_addrs <= FRAME_CACHE_MAX_FRAMES); + + // Find the index where last_profiled_frame matches + Py_ssize_t start_idx = -1; + for (Py_ssize_t i = 0; i < entry->num_addrs; i++) { + if (entry->addrs[i] == last_profiled_frame) { + start_idx = i; + break; + } + } + + if (start_idx < 0) { + return 0; // Not found + } + assert(start_idx < entry->num_addrs); + + Py_ssize_t num_frames = PyList_GET_SIZE(entry->frame_list); + + // Extend frame_info with frames from start_idx onwards + PyObject *slice = PyList_GetSlice(entry->frame_list, start_idx, num_frames); + if (!slice) { + return -1; + } + + Py_ssize_t cur_size = PyList_GET_SIZE(frame_info); + int result = PyList_SetSlice(frame_info, cur_size, cur_size, slice); + Py_DECREF(slice); + + if (result < 0) { + return -1; + } + + // Also extend frame_addrs with cached addresses if provided + if (frame_addrs) { + for (Py_ssize_t i = start_idx; i < entry->num_addrs && *num_addrs < max_addrs; i++) { + frame_addrs[(*num_addrs)++] = entry->addrs[i]; + } + } + + return 1; +} + +// Store frame list with addresses in cache +// Only stores complete stacks that reach base_frame_addr (validation done internally) +// Returns: 1 = stored successfully, 0 = not stored (graceful degradation), -1 = error +int +frame_cache_store( + RemoteUnwinderObject *unwinder, + uint64_t thread_id, + PyObject *frame_list, + const uintptr_t *addrs, + Py_ssize_t num_addrs, + uintptr_t base_frame_addr, + uintptr_t last_frame_visited) +{ + if (!unwinder->frame_cache || thread_id == 0) { + return 0; + } + + // Validate we have a complete stack before caching. + // Only cache if last_frame_visited matches base_frame_addr (the sentinel + // at the bottom of the stack). Note: we use last_frame_visited rather than + // addrs[num_addrs-1] because the base frame is visited but not added to the + // addrs array (it returns frame==NULL from is_frame_valid due to + // owner==FRAME_OWNED_BY_INTERPRETER). + if (base_frame_addr != 0 && last_frame_visited != base_frame_addr) { + // Incomplete stack - don't cache (graceful degradation) + return 0; + } + + // Clamp to max frames + if (num_addrs > FRAME_CACHE_MAX_FRAMES) { + num_addrs = FRAME_CACHE_MAX_FRAMES; + } + assert(num_addrs >= 0 && num_addrs <= FRAME_CACHE_MAX_FRAMES); + + FrameCacheEntry *entry = frame_cache_alloc_slot(unwinder, thread_id); + if (!entry) { + // Cache full - graceful degradation + return 0; + } + + // Clear old frame_list if replacing + Py_CLEAR(entry->frame_list); + + // Store full frame list (don't truncate to num_addrs - frames beyond the + // address array limit are still valid and needed for full cache hits) + Py_ssize_t num_frames = PyList_GET_SIZE(frame_list); + entry->frame_list = PyList_GetSlice(frame_list, 0, num_frames); + if (!entry->frame_list) { + return -1; + } + entry->thread_id = thread_id; + memcpy(entry->addrs, addrs, num_addrs * sizeof(uintptr_t)); + entry->num_addrs = num_addrs; + assert(entry->num_addrs == num_addrs); + assert(entry->thread_id == thread_id); + + return 1; +} diff --git a/Modules/_remote_debugging/frames.c b/Modules/_remote_debugging/frames.c new file mode 100644 index 00000000000..8aebd40671c --- /dev/null +++ b/Modules/_remote_debugging/frames.c @@ -0,0 +1,590 @@ +/****************************************************************************** + * Remote Debugging Module - Frame Functions + * + * This file contains functions for parsing interpreter frames and + * managing stack chunks from remote process memory. + ******************************************************************************/ + +#include "_remote_debugging.h" + +/* ============================================================================ + * STACK CHUNK MANAGEMENT FUNCTIONS + * ============================================================================ */ + +void +cleanup_stack_chunks(StackChunkList *chunks) +{ + for (size_t i = 0; i < chunks->count; ++i) { + PyMem_RawFree(chunks->chunks[i].local_copy); + } + PyMem_RawFree(chunks->chunks); +} + +static int +process_single_stack_chunk( + RemoteUnwinderObject *unwinder, + uintptr_t chunk_addr, + StackChunkInfo *chunk_info +) { + // Start with default size assumption + size_t current_size = _PY_DATA_STACK_CHUNK_SIZE; + + char *this_chunk = PyMem_RawMalloc(current_size); + if (!this_chunk) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate stack chunk buffer"); + return -1; + } + + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, current_size, this_chunk) < 0) { + PyMem_RawFree(this_chunk); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read stack chunk"); + return -1; + } + + // Check actual size and reread if necessary + size_t actual_size = GET_MEMBER(size_t, this_chunk, offsetof(_PyStackChunk, size)); + if (actual_size != current_size) { + this_chunk = PyMem_RawRealloc(this_chunk, actual_size); + if (!this_chunk) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to reallocate stack chunk buffer"); + return -1; + } + + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, actual_size, this_chunk) < 0) { + PyMem_RawFree(this_chunk); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reread stack chunk with correct size"); + return -1; + } + current_size = actual_size; + } + + chunk_info->remote_addr = chunk_addr; + chunk_info->size = current_size; + chunk_info->local_copy = this_chunk; + return 0; +} + +int +copy_stack_chunks(RemoteUnwinderObject *unwinder, + uintptr_t tstate_addr, + StackChunkList *out_chunks) +{ + uintptr_t chunk_addr; + StackChunkInfo *chunks = NULL; + size_t count = 0; + size_t max_chunks = 16; + + if (read_ptr(unwinder, tstate_addr + (uintptr_t)unwinder->debug_offsets.thread_state.datastack_chunk, &chunk_addr)) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read initial stack chunk address"); + return -1; + } + + chunks = PyMem_RawMalloc(max_chunks * sizeof(StackChunkInfo)); + if (!chunks) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate stack chunks array"); + return -1; + } + + const size_t MAX_STACK_CHUNKS = 4096; + while (chunk_addr != 0 && count < MAX_STACK_CHUNKS) { + // Grow array if needed + if (count >= max_chunks) { + max_chunks *= 2; + StackChunkInfo *new_chunks = PyMem_RawRealloc(chunks, max_chunks * sizeof(StackChunkInfo)); + if (!new_chunks) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to grow stack chunks array"); + goto error; + } + chunks = new_chunks; + } + + // Process this chunk + if (process_single_stack_chunk(unwinder, chunk_addr, &chunks[count]) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process stack chunk"); + goto error; + } + + // Get next chunk address and increment count + chunk_addr = GET_MEMBER(uintptr_t, chunks[count].local_copy, offsetof(_PyStackChunk, previous)); + count++; + } + + out_chunks->chunks = chunks; + out_chunks->count = count; + return 0; + +error: + for (size_t i = 0; i < count; ++i) { + PyMem_RawFree(chunks[i].local_copy); + } + PyMem_RawFree(chunks); + return -1; +} + +void * +find_frame_in_chunks(StackChunkList *chunks, uintptr_t remote_ptr) +{ + for (size_t i = 0; i < chunks->count; ++i) { + assert(chunks->chunks[i].size > offsetof(_PyStackChunk, data)); + uintptr_t base = chunks->chunks[i].remote_addr + offsetof(_PyStackChunk, data); + size_t payload = chunks->chunks[i].size - offsetof(_PyStackChunk, data); + + if (remote_ptr >= base && remote_ptr < base + payload) { + return (char *)chunks->chunks[i].local_copy + (remote_ptr - chunks->chunks[i].remote_addr); + } + } + return NULL; +} + +/* ============================================================================ + * FRAME PARSING FUNCTIONS + * ============================================================================ */ + +int +is_frame_valid( + RemoteUnwinderObject *unwinder, + uintptr_t frame_addr, + uintptr_t code_object_addr +) { + if ((void*)code_object_addr == NULL) { + return 0; + } + + void* frame = (void*)frame_addr; + + char owner = GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner); + if (owner == FRAME_OWNED_BY_INTERPRETER) { + return 0; // C frame or sentinel base frame + } + + if (owner != FRAME_OWNED_BY_GENERATOR && owner != FRAME_OWNED_BY_THREAD) { + PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n", owner); + set_exception_cause(unwinder, PyExc_RuntimeError, "Unhandled frame owner type in async frame"); + return -1; + } + return 1; +} + +int +parse_frame_object( + RemoteUnwinderObject *unwinder, + PyObject** result, + uintptr_t address, + uintptr_t* address_of_code_object, + uintptr_t* previous_frame +) { + char frame[SIZEOF_INTERP_FRAME]; + *address_of_code_object = 0; + + Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + address, + SIZEOF_INTERP_FRAME, + frame + ); + if (bytes_read < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame"); + return -1; + } + STATS_INC(unwinder, memory_reads); + STATS_ADD(unwinder, memory_bytes_read, SIZEOF_INTERP_FRAME); + + *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous); + uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable); + int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object); + if (frame_valid != 1) { + return frame_valid; + } + + uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr); + + // Get tlbc_index for free threading builds + int32_t tlbc_index = 0; +#ifdef Py_GIL_DISABLED + if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) { + tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index); + } +#endif + + *address_of_code_object = code_object; + + CodeObjectContext code_ctx = { + .code_addr = code_object, + .instruction_pointer = instruction_pointer, + .tlbc_index = tlbc_index, + }; + return parse_code_object(unwinder, result, &code_ctx); +} + +int +parse_frame_from_chunks( + RemoteUnwinderObject *unwinder, + PyObject **result, + uintptr_t address, + uintptr_t *previous_frame, + uintptr_t *stackpointer, + StackChunkList *chunks +) { + void *frame_ptr = find_frame_in_chunks(chunks, address); + if (!frame_ptr) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Frame not found in stack chunks"); + return -1; + } + + char *frame = (char *)frame_ptr; + *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous); + *stackpointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.stackpointer); + uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame_ptr, unwinder->debug_offsets.interpreter_frame.executable); + int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object); + if (frame_valid != 1) { + return frame_valid; + } + + uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr); + + // Get tlbc_index for free threading builds + int32_t tlbc_index = 0; +#ifdef Py_GIL_DISABLED + if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) { + tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index); + } +#endif + + CodeObjectContext code_ctx = { + .code_addr = code_object, + .instruction_pointer = instruction_pointer, + .tlbc_index = tlbc_index, + }; + return parse_code_object(unwinder, result, &code_ctx); +} + +/* ============================================================================ + * FRAME CHAIN PROCESSING + * ============================================================================ */ + +int +process_frame_chain( + RemoteUnwinderObject *unwinder, + FrameWalkContext *ctx) +{ + uintptr_t frame_addr = ctx->frame_addr; + uintptr_t prev_frame_addr = 0; + uintptr_t last_frame_addr = 0; + const size_t MAX_FRAMES = 1024 + 512; + size_t frame_count = 0; + assert(MAX_FRAMES > 0 && MAX_FRAMES < 10000); + + ctx->stopped_at_cached_frame = 0; + ctx->last_frame_visited = 0; + + if (ctx->last_profiled_frame != 0 && ctx->frame_addr == ctx->last_profiled_frame) { + ctx->stopped_at_cached_frame = 1; + return 0; + } + + while ((void*)frame_addr != NULL) { + if (ctx->last_profiled_frame != 0 && frame_addr == ctx->last_profiled_frame) { + ctx->stopped_at_cached_frame = 1; + break; + } + PyObject *frame = NULL; + uintptr_t next_frame_addr = 0; + uintptr_t stackpointer = 0; + last_frame_addr = frame_addr; + + if (++frame_count > MAX_FRAMES) { + PyErr_SetString(PyExc_RuntimeError, "Too many stack frames (possible infinite loop)"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Frame chain iteration limit exceeded"); + return -1; + } + assert(frame_count <= MAX_FRAMES); + + if (parse_frame_from_chunks(unwinder, &frame, frame_addr, &next_frame_addr, &stackpointer, ctx->chunks) < 0) { + PyErr_Clear(); + uintptr_t address_of_code_object = 0; + if (parse_frame_object(unwinder, &frame, frame_addr, &address_of_code_object, &next_frame_addr) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in chain"); + return -1; + } + } + if (frame == NULL && PyList_GET_SIZE(ctx->frame_info) == 0) { + const char *e = "Failed to parse initial frame in chain"; + PyErr_SetString(PyExc_RuntimeError, e); + return -1; + } + PyObject *extra_frame = NULL; + if (unwinder->gc && frame_addr == ctx->gc_frame) { + _Py_DECLARE_STR(gc, "<GC>"); + extra_frame = &_Py_STR(gc); + } + else if (unwinder->native && + frame == NULL && + next_frame_addr && + !(unwinder->gc && next_frame_addr == ctx->gc_frame)) + { + _Py_DECLARE_STR(native, "<native>"); + extra_frame = &_Py_STR(native); + } + if (extra_frame) { + PyObject *extra_frame_info = make_frame_info( + unwinder, _Py_LATIN1_CHR('~'), Py_None, extra_frame, Py_None); + if (extra_frame_info == NULL) { + return -1; + } + if (PyList_Append(ctx->frame_info, extra_frame_info) < 0) { + Py_DECREF(extra_frame_info); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append extra frame"); + return -1; + } + if (ctx->frame_addrs && ctx->num_addrs < ctx->max_addrs) { + assert(ctx->num_addrs >= 0); + ctx->frame_addrs[ctx->num_addrs++] = 0; + } + Py_DECREF(extra_frame_info); + } + if (frame) { + if (prev_frame_addr && frame_addr != prev_frame_addr) { + const char *f = "Broken frame chain: expected frame at 0x%lx, got 0x%lx"; + PyErr_Format(PyExc_RuntimeError, f, prev_frame_addr, frame_addr); + Py_DECREF(frame); + set_exception_cause(unwinder, PyExc_RuntimeError, "Frame chain consistency check failed"); + return -1; + } + + if (PyList_Append(ctx->frame_info, frame) < 0) { + Py_DECREF(frame); + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame"); + return -1; + } + if (ctx->frame_addrs && ctx->num_addrs < ctx->max_addrs) { + assert(ctx->num_addrs >= 0); + ctx->frame_addrs[ctx->num_addrs++] = frame_addr; + } + Py_DECREF(frame); + } + + prev_frame_addr = next_frame_addr; + frame_addr = next_frame_addr; + } + + if (!ctx->stopped_at_cached_frame && ctx->base_frame_addr != 0 && last_frame_addr != ctx->base_frame_addr) { + PyErr_Format(PyExc_RuntimeError, + "Incomplete sample: did not reach base frame (expected 0x%lx, got 0x%lx)", + ctx->base_frame_addr, last_frame_addr); + return -1; + } + + ctx->last_frame_visited = last_frame_addr; + + return 0; +} + +// Clear last_profiled_frame for all threads in the target process. +// This must be called at the start of profiling to avoid stale values +// from previous profilers causing us to stop frame walking early. +int +clear_last_profiled_frames(RemoteUnwinderObject *unwinder) +{ + uintptr_t current_interp = unwinder->interpreter_addr; + uintptr_t zero = 0; + const size_t MAX_INTERPRETERS = 256; + size_t interp_count = 0; + + while (current_interp != 0 && interp_count < MAX_INTERPRETERS) { + interp_count++; + // Get first thread in this interpreter + uintptr_t tstate_addr; + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + current_interp + unwinder->debug_offsets.interpreter_state.threads_head, + sizeof(void*), + &tstate_addr) < 0) { + // Non-fatal: just skip clearing + PyErr_Clear(); + return 0; + } + + // Iterate all threads in this interpreter + const size_t MAX_THREADS_PER_INTERP = 8192; + size_t thread_count = 0; + while (tstate_addr != 0 && thread_count < MAX_THREADS_PER_INTERP) { + thread_count++; + // Clear last_profiled_frame + uintptr_t lpf_addr = tstate_addr + unwinder->debug_offsets.thread_state.last_profiled_frame; + if (_Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, + sizeof(uintptr_t), &zero) < 0) { + // Non-fatal: just continue + PyErr_Clear(); + } + + // Move to next thread + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + tstate_addr + unwinder->debug_offsets.thread_state.next, + sizeof(void*), + &tstate_addr) < 0) { + PyErr_Clear(); + break; + } + } + + // Move to next interpreter + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + current_interp + unwinder->debug_offsets.interpreter_state.next, + sizeof(void*), + &current_interp) < 0) { + PyErr_Clear(); + break; + } + } + + return 0; +} + +// Fast path: check if we have a full cache hit (parent stack unchanged) +// A "full hit" means current frame == last profiled frame, so we can reuse +// cached parent frames. We always read the current frame from memory to get +// updated line numbers (the line within a frame can change between samples). +// Returns: 1 if full hit (frame_info populated with current frame + cached parents), +// 0 if miss, -1 on error +static int +try_full_cache_hit( + RemoteUnwinderObject *unwinder, + const FrameWalkContext *ctx, + uint64_t thread_id) +{ + if (!unwinder->frame_cache || ctx->last_profiled_frame == 0) { + return 0; + } + if (ctx->frame_addr != ctx->last_profiled_frame) { + return 0; + } + + FrameCacheEntry *entry = frame_cache_find(unwinder, thread_id); + if (!entry || !entry->frame_list) { + return 0; + } + + if (entry->num_addrs == 0 || entry->addrs[0] != ctx->frame_addr) { + return 0; + } + + PyObject *current_frame = NULL; + uintptr_t code_object_addr = 0; + uintptr_t previous_frame = 0; + int parse_result = parse_frame_object(unwinder, &current_frame, ctx->frame_addr, + &code_object_addr, &previous_frame); + if (parse_result < 0) { + return -1; + } + + Py_ssize_t cached_size = PyList_GET_SIZE(entry->frame_list); + PyObject *parent_slice = NULL; + if (cached_size > 1) { + parent_slice = PyList_GetSlice(entry->frame_list, 1, cached_size); + if (!parent_slice) { + Py_XDECREF(current_frame); + return -1; + } + } + + if (current_frame != NULL) { + if (PyList_Append(ctx->frame_info, current_frame) < 0) { + Py_DECREF(current_frame); + Py_XDECREF(parent_slice); + return -1; + } + Py_DECREF(current_frame); + STATS_ADD(unwinder, frames_read_from_memory, 1); + } + + if (parent_slice) { + Py_ssize_t cur_size = PyList_GET_SIZE(ctx->frame_info); + int result = PyList_SetSlice(ctx->frame_info, cur_size, cur_size, parent_slice); + Py_DECREF(parent_slice); + if (result < 0) { + return -1; + } + STATS_ADD(unwinder, frames_read_from_cache, cached_size - 1); + } + + STATS_INC(unwinder, frame_cache_hits); + return 1; +} + +// High-level helper: collect frames with cache optimization +// Returns complete frame_info list, handling all cache logic internally +int +collect_frames_with_cache( + RemoteUnwinderObject *unwinder, + FrameWalkContext *ctx, + uint64_t thread_id) +{ + int full_hit = try_full_cache_hit(unwinder, ctx, thread_id); + if (full_hit != 0) { + return full_hit < 0 ? -1 : 0; + } + + Py_ssize_t frames_before = PyList_GET_SIZE(ctx->frame_info); + + if (process_frame_chain(unwinder, ctx) < 0) { + return -1; + } + + STATS_ADD(unwinder, frames_read_from_memory, PyList_GET_SIZE(ctx->frame_info) - frames_before); + + if (ctx->stopped_at_cached_frame) { + Py_ssize_t frames_before_cache = PyList_GET_SIZE(ctx->frame_info); + int cache_result = frame_cache_lookup_and_extend(unwinder, thread_id, ctx->last_profiled_frame, + ctx->frame_info, ctx->frame_addrs, &ctx->num_addrs, + ctx->max_addrs); + if (cache_result < 0) { + return -1; + } + if (cache_result == 0) { + STATS_INC(unwinder, frame_cache_misses); + Py_ssize_t frames_before_walk = PyList_GET_SIZE(ctx->frame_info); + + FrameWalkContext continue_ctx = { + .frame_addr = ctx->last_profiled_frame, + .base_frame_addr = ctx->base_frame_addr, + .gc_frame = ctx->gc_frame, + .last_profiled_frame = 0, + .chunks = ctx->chunks, + .frame_info = ctx->frame_info, + .frame_addrs = ctx->frame_addrs, + .num_addrs = ctx->num_addrs, + .max_addrs = ctx->max_addrs, + }; + if (process_frame_chain(unwinder, &continue_ctx) < 0) { + return -1; + } + ctx->num_addrs = continue_ctx.num_addrs; + ctx->last_frame_visited = continue_ctx.last_frame_visited; + + STATS_ADD(unwinder, frames_read_from_memory, PyList_GET_SIZE(ctx->frame_info) - frames_before_walk); + } else { + // Partial cache hit - cached stack was validated as complete when stored, + // so set last_frame_visited to base_frame_addr for validation in frame_cache_store + ctx->last_frame_visited = ctx->base_frame_addr; + STATS_INC(unwinder, frame_cache_partial_hits); + STATS_ADD(unwinder, frames_read_from_cache, PyList_GET_SIZE(ctx->frame_info) - frames_before_cache); + } + } else { + if (ctx->last_profiled_frame == 0) { + STATS_INC(unwinder, frame_cache_misses); + } + } + + if (frame_cache_store(unwinder, thread_id, ctx->frame_info, ctx->frame_addrs, ctx->num_addrs, + ctx->base_frame_addr, ctx->last_frame_visited) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c new file mode 100644 index 00000000000..fc58e2428b2 --- /dev/null +++ b/Modules/_remote_debugging/module.c @@ -0,0 +1,1211 @@ +/****************************************************************************** + * Remote Debugging Module - Main Module Implementation + * + * This file contains the main module initialization, the RemoteUnwinder + * class implementation, and utility functions. + ******************************************************************************/ + +#include "_remote_debugging.h" +#include "clinic/module.c.h" + +/* ============================================================================ + * STRUCTSEQ TYPE DEFINITIONS + * ============================================================================ */ + +// TaskInfo structseq type +static PyStructSequence_Field TaskInfo_fields[] = { + {"task_id", "Task ID (memory address)"}, + {"task_name", "Task name"}, + {"coroutine_stack", "Coroutine call stack"}, + {"awaited_by", "Tasks awaiting this task"}, + {NULL} +}; + +PyStructSequence_Desc TaskInfo_desc = { + "_remote_debugging.TaskInfo", + "Information about an asyncio task", + TaskInfo_fields, + 4 +}; + +// LocationInfo structseq type +static PyStructSequence_Field LocationInfo_fields[] = { + {"lineno", "Line number"}, + {"end_lineno", "End line number"}, + {"col_offset", "Column offset"}, + {"end_col_offset", "End column offset"}, + {NULL} +}; + +PyStructSequence_Desc LocationInfo_desc = { + "_remote_debugging.LocationInfo", + "Source location information: (lineno, end_lineno, col_offset, end_col_offset)", + LocationInfo_fields, + 4 +}; + +// FrameInfo structseq type +static PyStructSequence_Field FrameInfo_fields[] = { + {"filename", "Source code filename"}, + {"location", "LocationInfo structseq or None for synthetic frames"}, + {"funcname", "Function name"}, + {"opcode", "Opcode being executed (None if not gathered)"}, + {NULL} +}; + +PyStructSequence_Desc FrameInfo_desc = { + "_remote_debugging.FrameInfo", + "Information about a frame", + FrameInfo_fields, + 4 +}; + +// CoroInfo structseq type +static PyStructSequence_Field CoroInfo_fields[] = { + {"call_stack", "Coroutine call stack"}, + {"task_name", "Task name"}, + {NULL} +}; + +PyStructSequence_Desc CoroInfo_desc = { + "_remote_debugging.CoroInfo", + "Information about a coroutine", + CoroInfo_fields, + 2 +}; + +// ThreadInfo structseq type +static PyStructSequence_Field ThreadInfo_fields[] = { + {"thread_id", "Thread ID"}, + {"status", "Thread status (flags: HAS_GIL, ON_CPU, UNKNOWN or legacy enum)"}, + {"frame_info", "Frame information"}, + {NULL} +}; + +PyStructSequence_Desc ThreadInfo_desc = { + "_remote_debugging.ThreadInfo", + "Information about a thread", + ThreadInfo_fields, + 3 +}; + +// InterpreterInfo structseq type +static PyStructSequence_Field InterpreterInfo_fields[] = { + {"interpreter_id", "Interpreter ID"}, + {"threads", "List of threads in this interpreter"}, + {NULL} +}; + +PyStructSequence_Desc InterpreterInfo_desc = { + "_remote_debugging.InterpreterInfo", + "Information about an interpreter", + InterpreterInfo_fields, + 2 +}; + +// AwaitedInfo structseq type +static PyStructSequence_Field AwaitedInfo_fields[] = { + {"thread_id", "Thread ID"}, + {"awaited_by", "List of tasks awaited by this thread"}, + {NULL} +}; + +PyStructSequence_Desc AwaitedInfo_desc = { + "_remote_debugging.AwaitedInfo", + "Information about what a thread is awaiting", + AwaitedInfo_fields, + 2 +}; + +/* ============================================================================ + * UTILITY FUNCTIONS + * ============================================================================ */ + +void +cached_code_metadata_destroy(void *ptr) +{ + CachedCodeMetadata *meta = (CachedCodeMetadata *)ptr; + Py_DECREF(meta->func_name); + Py_DECREF(meta->file_name); + Py_DECREF(meta->linetable); + PyMem_RawFree(meta); +} + +RemoteDebuggingState * +RemoteDebugging_GetState(PyObject *module) +{ + void *state = _PyModule_GetState(module); + assert(state != NULL); + return (RemoteDebuggingState *)state; +} + +RemoteDebuggingState * +RemoteDebugging_GetStateFromType(PyTypeObject *type) +{ + PyObject *module = PyType_GetModule(type); + assert(module != NULL); + return RemoteDebugging_GetState(module); +} + +RemoteDebuggingState * +RemoteDebugging_GetStateFromObject(PyObject *obj) +{ + RemoteUnwinderObject *unwinder = (RemoteUnwinderObject *)obj; + if (unwinder->cached_state == NULL) { + unwinder->cached_state = RemoteDebugging_GetStateFromType(Py_TYPE(obj)); + } + return unwinder->cached_state; +} + +int +RemoteDebugging_InitState(RemoteDebuggingState *st) +{ + return 0; +} + +int +is_prerelease_version(uint64_t version) +{ + return (version & 0xF0) != 0xF0; +} + +int +validate_debug_offsets(struct _Py_DebugOffsets *debug_offsets) +{ + if (memcmp(debug_offsets->cookie, _Py_Debug_Cookie, sizeof(debug_offsets->cookie)) != 0) { + // The remote is probably running a Python version predating debug offsets. + PyErr_SetString( + PyExc_RuntimeError, + "Can't determine the Python version of the remote process"); + return -1; + } + + // Assume debug offsets could change from one pre-release version to another, + // or one minor version to another, but are stable across patch versions. + if (is_prerelease_version(Py_Version) && Py_Version != debug_offsets->version) { + PyErr_SetString( + PyExc_RuntimeError, + "Can't attach from a pre-release Python interpreter" + " to a process running a different Python version"); + return -1; + } + + if (is_prerelease_version(debug_offsets->version) && Py_Version != debug_offsets->version) { + PyErr_SetString( + PyExc_RuntimeError, + "Can't attach to a pre-release Python interpreter" + " from a process running a different Python version"); + return -1; + } + + unsigned int remote_major = (debug_offsets->version >> 24) & 0xFF; + unsigned int remote_minor = (debug_offsets->version >> 16) & 0xFF; + + if (PY_MAJOR_VERSION != remote_major || PY_MINOR_VERSION != remote_minor) { + PyErr_Format( + PyExc_RuntimeError, + "Can't attach from a Python %d.%d process to a Python %d.%d process", + PY_MAJOR_VERSION, PY_MINOR_VERSION, remote_major, remote_minor); + return -1; + } + + // The debug offsets differ between free threaded and non-free threaded builds. + if (_Py_Debug_Free_Threaded && !debug_offsets->free_threaded) { + PyErr_SetString( + PyExc_RuntimeError, + "Cannot attach from a free-threaded Python process" + " to a process running a non-free-threaded version"); + return -1; + } + + if (!_Py_Debug_Free_Threaded && debug_offsets->free_threaded) { + PyErr_SetString( + PyExc_RuntimeError, + "Cannot attach to a free-threaded Python process" + " from a process running a non-free-threaded version"); + return -1; + } + + return 0; +} + +/* ============================================================================ + * REMOTEUNWINDER CLASS IMPLEMENTATION + * ============================================================================ */ + +/*[clinic input] +module _remote_debugging +class _remote_debugging.RemoteUnwinder "RemoteUnwinderObject *" "&RemoteUnwinder_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=12b4dce200381115]*/ + +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +_remote_debugging.RemoteUnwinder.__init__ + pid: int + * + all_threads: bool = False + only_active_thread: bool = False + mode: int = 0 + debug: bool = False + skip_non_matching_threads: bool = True + native: bool = False + gc: bool = False + opcodes: bool = False + cache_frames: bool = False + stats: bool = False + +Initialize a new RemoteUnwinder object for debugging a remote Python process. + +Args: + pid: Process ID of the target Python process to debug + all_threads: If True, initialize state for all threads in the process. + If False, only initialize for the main thread. + only_active_thread: If True, only sample the thread holding the GIL. + mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL (gil-time). + Cannot be used together with all_threads=True. + debug: If True, chain exceptions to explain the sequence of events that + lead to the exception. + skip_non_matching_threads: If True, skip threads that don't match the selected mode. + If False, include all threads regardless of mode. + native: If True, include artificial "<native>" frames to denote calls to + non-Python code. + gc: If True, include artificial "<GC>" frames to denote active garbage + collection. + opcodes: If True, gather bytecode opcode information for instruction-level + profiling. + cache_frames: If True, enable frame caching optimization to avoid re-reading + unchanged parent frames between samples. + stats: If True, collect statistics about cache hits, memory reads, etc. + Use get_stats() to retrieve the collected statistics. + +The RemoteUnwinder provides functionality to inspect and debug a running Python +process, including examining thread states, stack frames and other runtime data. + +Raises: + PermissionError: If access to the target process is denied + OSError: If unable to attach to the target process or access its memory + RuntimeError: If unable to read debug information from the target process + ValueError: If both all_threads and only_active_thread are True +[clinic start generated code]*/ + +static int +_remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, + int pid, int all_threads, + int only_active_thread, + int mode, int debug, + int skip_non_matching_threads, + int native, int gc, + int opcodes, int cache_frames, + int stats) +/*[clinic end generated code: output=0031f743f4b9ad52 input=8fb61b24102dec6e]*/ +{ + // Validate that all_threads and only_active_thread are not both True + if (all_threads && only_active_thread) { + PyErr_SetString(PyExc_ValueError, + "all_threads and only_active_thread cannot both be True"); + return -1; + } + +#ifdef Py_GIL_DISABLED + if (only_active_thread) { + PyErr_SetString(PyExc_ValueError, + "only_active_thread is not supported in free-threaded builds"); + return -1; + } +#endif + + self->native = native; + self->gc = gc; + self->opcodes = opcodes; + self->cache_frames = cache_frames; + self->collect_stats = stats; + self->stale_invalidation_counter = 0; + self->debug = debug; + self->only_active_thread = only_active_thread; + self->mode = mode; + self->skip_non_matching_threads = skip_non_matching_threads; + self->cached_state = NULL; + self->frame_cache = NULL; + // Initialize stats to zero + memset(&self->stats, 0, sizeof(self->stats)); + if (_Py_RemoteDebug_InitProcHandle(&self->handle, pid) < 0) { + set_exception_cause(self, PyExc_RuntimeError, "Failed to initialize process handle"); + return -1; + } + + self->runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(&self->handle); + if (self->runtime_start_address == 0) { + set_exception_cause(self, PyExc_RuntimeError, "Failed to get Python runtime address"); + return -1; + } + + if (_Py_RemoteDebug_ReadDebugOffsets(&self->handle, + &self->runtime_start_address, + &self->debug_offsets) < 0) + { + set_exception_cause(self, PyExc_RuntimeError, "Failed to read debug offsets"); + return -1; + } + + // Validate that the debug offsets are valid + if (validate_debug_offsets(&self->debug_offsets) == -1) { + set_exception_cause(self, PyExc_RuntimeError, "Invalid debug offsets found"); + return -1; + } + + // Try to read async debug offsets, but don't fail if they're not available + self->async_debug_offsets_available = 1; + if (read_async_debug(self) < 0) { + PyErr_Clear(); + memset(&self->async_debug_offsets, 0, sizeof(self->async_debug_offsets)); + self->async_debug_offsets_available = 0; + } + + if (populate_initial_state_data(all_threads, self, self->runtime_start_address, + &self->interpreter_addr ,&self->tstate_addr) < 0) + { + set_exception_cause(self, PyExc_RuntimeError, "Failed to populate initial state data"); + return -1; + } + + self->code_object_cache = _Py_hashtable_new_full( + _Py_hashtable_hash_ptr, + _Py_hashtable_compare_direct, + NULL, // keys are stable pointers, don't destroy + cached_code_metadata_destroy, + NULL + ); + if (self->code_object_cache == NULL) { + PyErr_NoMemory(); + set_exception_cause(self, PyExc_MemoryError, "Failed to create code object cache"); + return -1; + } + +#ifdef Py_GIL_DISABLED + // Initialize TLBC cache + self->tlbc_generation = 0; + self->tlbc_cache = _Py_hashtable_new_full( + _Py_hashtable_hash_ptr, + _Py_hashtable_compare_direct, + NULL, // keys are stable pointers, don't destroy + tlbc_cache_entry_destroy, + NULL + ); + if (self->tlbc_cache == NULL) { + _Py_hashtable_destroy(self->code_object_cache); + PyErr_NoMemory(); + set_exception_cause(self, PyExc_MemoryError, "Failed to create TLBC cache"); + return -1; + } +#endif + +#if defined(__APPLE__) + self->thread_id_offset = 0; +#endif + +#ifdef MS_WINDOWS + self->win_process_buffer = NULL; + self->win_process_buffer_size = 0; +#endif + + if (cache_frames && frame_cache_init(self) < 0) { + return -1; + } + + // Clear stale last_profiled_frame values from previous profilers + // This prevents us from stopping frame walking early due to stale values + if (cache_frames) { + clear_last_profiled_frames(self); + } + + return 0; +} + +/*[clinic input] +@permit_long_docstring_body +@critical_section +_remote_debugging.RemoteUnwinder.get_stack_trace + +Returns stack traces for all interpreters and threads in process. + +Each element in the returned list is a tuple of (interpreter_id, thread_list), where: +- interpreter_id is the interpreter identifier +- thread_list is a list of tuples (thread_id, frame_list) for threads in that interpreter + - thread_id is the OS thread identifier + - frame_list is a list of tuples (function_name, filename, line_number) representing + the Python stack frames for that thread, ordered from most recent to oldest + +The threads returned depend on the initialization parameters: +- If only_active_thread was True: returns only the thread holding the GIL across all interpreters +- If all_threads was True: returns all threads across all interpreters +- Otherwise: returns only the main thread of each interpreter + +Example: + [ + (0, [ # Main interpreter + (1234, [ + ('process_data', 'worker.py', 127), + ('run_worker', 'worker.py', 45), + ('main', 'app.py', 23) + ]), + (1235, [ + ('handle_request', 'server.py', 89), + ('serve_forever', 'server.py', 52) + ]) + ]), + (1, [ # Sub-interpreter + (1236, [ + ('sub_worker', 'sub.py', 15) + ]) + ]) + ] + +Raises: + RuntimeError: If there is an error copying memory from the target process + OSError: If there is an error accessing the target process + PermissionError: If access to the target process is denied + UnicodeDecodeError: If there is an error decoding strings from the target process + +[clinic start generated code]*/ + +static PyObject * +_remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self) +/*[clinic end generated code: output=666192b90c69d567 input=bcff01c73cccc1c0]*/ +{ + STATS_INC(self, total_samples); + + PyObject* result = PyList_New(0); + if (!result) { + set_exception_cause(self, PyExc_MemoryError, "Failed to create stack trace result list"); + return NULL; + } + + // Iterate over all interpreters + uintptr_t current_interpreter = self->interpreter_addr; + while (current_interpreter != 0) { + // Read interpreter state to get the interpreter ID + char interp_state_buffer[INTERP_STATE_BUFFER_SIZE]; + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &self->handle, + current_interpreter, + INTERP_STATE_BUFFER_SIZE, + interp_state_buffer) < 0) { + set_exception_cause(self, PyExc_RuntimeError, "Failed to read interpreter state buffer"); + Py_CLEAR(result); + goto exit; + } + + uintptr_t gc_frame = 0; + if (self->gc) { + gc_frame = GET_MEMBER(uintptr_t, interp_state_buffer, + self->debug_offsets.interpreter_state.gc + + self->debug_offsets.gc.frame); + } + + int64_t interpreter_id = GET_MEMBER(int64_t, interp_state_buffer, + self->debug_offsets.interpreter_state.id); + + // Get code object generation from buffer + uint64_t code_object_generation = GET_MEMBER(uint64_t, interp_state_buffer, + self->debug_offsets.interpreter_state.code_object_generation); + + if (code_object_generation != self->code_object_generation) { + self->code_object_generation = code_object_generation; + _Py_hashtable_clear(self->code_object_cache); + } + +#ifdef Py_GIL_DISABLED + // Check TLBC generation and invalidate cache if needed + uint32_t current_tlbc_generation = GET_MEMBER(uint32_t, interp_state_buffer, + self->debug_offsets.interpreter_state.tlbc_generation); + if (current_tlbc_generation != self->tlbc_generation) { + self->tlbc_generation = current_tlbc_generation; + _Py_hashtable_clear(self->tlbc_cache); + } +#endif + + // Create a list to hold threads for this interpreter + PyObject *interpreter_threads = PyList_New(0); + if (!interpreter_threads) { + set_exception_cause(self, PyExc_MemoryError, "Failed to create interpreter threads list"); + Py_CLEAR(result); + goto exit; + } + + // Get the GIL holder for this interpreter (needed for GIL_WAIT logic) + uintptr_t gil_holder_tstate = 0; + int gil_locked = GET_MEMBER(int, interp_state_buffer, + self->debug_offsets.interpreter_state.gil_runtime_state_locked); + if (gil_locked) { + gil_holder_tstate = (uintptr_t)GET_MEMBER(PyThreadState*, interp_state_buffer, + self->debug_offsets.interpreter_state.gil_runtime_state_holder); + } + + uintptr_t current_tstate; + if (self->only_active_thread) { + // Find the GIL holder for THIS interpreter + if (!gil_locked) { + // This interpreter's GIL is not locked, skip it + Py_DECREF(interpreter_threads); + goto next_interpreter; + } + + current_tstate = gil_holder_tstate; + } else if (self->tstate_addr == 0) { + // Get all threads for this interpreter + current_tstate = GET_MEMBER(uintptr_t, interp_state_buffer, + self->debug_offsets.interpreter_state.threads_head); + } else { + // Target specific thread (only process first interpreter) + current_tstate = self->tstate_addr; + } + + while (current_tstate != 0) { + PyObject* frame_info = unwind_stack_for_thread(self, &current_tstate, + gil_holder_tstate, + gc_frame); + if (!frame_info) { + // Check if this was an intentional skip due to mode-based filtering + if ((self->mode == PROFILING_MODE_CPU || self->mode == PROFILING_MODE_GIL || + self->mode == PROFILING_MODE_EXCEPTION) && !PyErr_Occurred()) { + // Thread was skipped due to mode filtering, continue to next thread + continue; + } + // This was an actual error + Py_DECREF(interpreter_threads); + set_exception_cause(self, PyExc_RuntimeError, "Failed to unwind stack for thread"); + Py_CLEAR(result); + goto exit; + } + + if (PyList_Append(interpreter_threads, frame_info) == -1) { + Py_DECREF(frame_info); + Py_DECREF(interpreter_threads); + set_exception_cause(self, PyExc_RuntimeError, "Failed to append thread frame info"); + Py_CLEAR(result); + goto exit; + } + Py_DECREF(frame_info); + + // If targeting specific thread or only active thread, process just one + if (self->tstate_addr || self->only_active_thread) { + break; + } + } + + // Create the InterpreterInfo StructSequence + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)self); + PyObject *interpreter_info = PyStructSequence_New(state->InterpreterInfo_Type); + if (!interpreter_info) { + Py_DECREF(interpreter_threads); + set_exception_cause(self, PyExc_MemoryError, "Failed to create InterpreterInfo"); + Py_CLEAR(result); + goto exit; + } + + PyObject *interp_id = PyLong_FromLongLong(interpreter_id); + if (!interp_id) { + Py_DECREF(interpreter_threads); + Py_DECREF(interpreter_info); + set_exception_cause(self, PyExc_MemoryError, "Failed to create interpreter ID"); + Py_CLEAR(result); + goto exit; + } + + PyStructSequence_SetItem(interpreter_info, 0, interp_id); // steals reference + PyStructSequence_SetItem(interpreter_info, 1, interpreter_threads); // steals reference + + // Add this interpreter to the result list + if (PyList_Append(result, interpreter_info) == -1) { + Py_DECREF(interpreter_info); + set_exception_cause(self, PyExc_RuntimeError, "Failed to append interpreter info"); + Py_CLEAR(result); + goto exit; + } + Py_DECREF(interpreter_info); + +next_interpreter: + + // Get the next interpreter address + current_interpreter = GET_MEMBER(uintptr_t, interp_state_buffer, + self->debug_offsets.interpreter_state.next); + + // If we're targeting a specific thread, stop after first interpreter + if (self->tstate_addr != 0) { + break; + } + } + +exit: + // Invalidate cache entries for threads not seen in this sample. + // Only do this every 1024 iterations to avoid performance overhead. + if (self->cache_frames && result) { + if (++self->stale_invalidation_counter >= 1024) { + self->stale_invalidation_counter = 0; + frame_cache_invalidate_stale(self, result); + } + } + _Py_RemoteDebug_ClearCache(&self->handle); + return result; +} + +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +@critical_section +_remote_debugging.RemoteUnwinder.get_all_awaited_by + +Get all tasks and their awaited_by relationships from the remote process. + +This provides a tree structure showing which tasks are waiting for other tasks. + +For each task, returns: +1. The call stack frames leading to where the task is currently executing +2. The name of the task +3. A list of tasks that this task is waiting for, with their own frames/names/etc + +Returns a list of [frames, task_name, subtasks] where: +- frames: List of (func_name, filename, lineno) showing the call stack +- task_name: String identifier for the task +- subtasks: List of tasks being awaited by this task, in same format + +Raises: + RuntimeError: If AsyncioDebug section is not available in the remote process + MemoryError: If memory allocation fails + OSError: If reading from the remote process fails + +Example output: +[ + # Task c2_root waiting for two subtasks + [ + # Call stack of c2_root + [("c5", "script.py", 10), ("c4", "script.py", 14)], + "c2_root", + [ + # First subtask (sub_main_2) and what it's waiting for + [ + [("c1", "script.py", 23)], + "sub_main_2", + [...] + ], + # Second subtask and its waiters + [...] + ] + ] +] +[clinic start generated code]*/ + +static PyObject * +_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *self) +/*[clinic end generated code: output=6a49cd345e8aec53 input=307f754cbe38250c]*/ +{ + if (ensure_async_debug_offsets(self) < 0) { + return NULL; + } + + PyObject *result = PyList_New(0); + if (result == NULL) { + set_exception_cause(self, PyExc_MemoryError, "Failed to create awaited_by result list"); + goto result_err; + } + + // Process all threads + if (iterate_threads(self, process_thread_for_awaited_by, result) < 0) { + goto result_err; + } + + uintptr_t head_addr = self->interpreter_addr + + (uintptr_t)self->async_debug_offsets.asyncio_interpreter_state.asyncio_tasks_head; + + // On top of a per-thread task lists used by default by asyncio to avoid + // contention, there is also a fallback per-interpreter list of tasks; + // any tasks still pending when a thread is destroyed will be moved to the + // per-interpreter task list. It's unlikely we'll find anything here, but + // interesting for debugging. + if (append_awaited_by(self, 0, head_addr, result)) + { + set_exception_cause(self, PyExc_RuntimeError, "Failed to append interpreter awaited_by in get_all_awaited_by"); + goto result_err; + } + + _Py_RemoteDebug_ClearCache(&self->handle); + return result; + +result_err: + _Py_RemoteDebug_ClearCache(&self->handle); + Py_XDECREF(result); + return NULL; +} + +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +@critical_section +_remote_debugging.RemoteUnwinder.get_async_stack_trace + +Get the currently running async tasks and their dependency graphs from the remote process. + +This returns information about running tasks and all tasks that are waiting for them, +forming a complete dependency graph for each thread's active task. + +For each thread with a running task, returns the running task plus all tasks that +transitively depend on it (tasks waiting for the running task, tasks waiting for +those tasks, etc.). + +Returns a list of per-thread results, where each thread result contains: +- Thread ID +- List of task information for the running task and all its waiters + +Each task info contains: +- Task ID (memory address) +- Task name +- Call stack frames: List of (func_name, filename, lineno) +- List of tasks waiting for this task (recursive structure) + +Raises: + RuntimeError: If AsyncioDebug section is not available in the target process + MemoryError: If memory allocation fails + OSError: If reading from the remote process fails + +Example output (similar structure to get_all_awaited_by but only for running tasks): +[ + # Thread 140234 results + (140234, [ + # Running task and its complete waiter dependency graph + (4345585712, 'main_task', + [("run_server", "server.py", 127), ("main", "app.py", 23)], + [ + # Tasks waiting for main_task + (4345585800, 'worker_1', [...], [...]), + (4345585900, 'worker_2', [...], [...]) + ]) + ]) +] + +[clinic start generated code]*/ + +static PyObject * +_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject *self) +/*[clinic end generated code: output=6433d52b55e87bbe input=6129b7d509a887c9]*/ +{ + if (ensure_async_debug_offsets(self) < 0) { + return NULL; + } + + PyObject *result = PyList_New(0); + if (result == NULL) { + set_exception_cause(self, PyExc_MemoryError, "Failed to create result list in get_async_stack_trace"); + return NULL; + } + + // Process all threads + if (iterate_threads(self, process_thread_for_async_stack_trace, result) < 0) { + goto result_err; + } + + _Py_RemoteDebug_ClearCache(&self->handle); + return result; +result_err: + _Py_RemoteDebug_ClearCache(&self->handle); + Py_XDECREF(result); + return NULL; +} + +/*[clinic input] +@permit_long_docstring_body +@critical_section +_remote_debugging.RemoteUnwinder.get_stats + +Get collected statistics about profiling performance. + +Returns a dictionary containing statistics about cache performance, +memory reads, and other profiling metrics. Only available if the +RemoteUnwinder was created with stats=True. + +Returns: + dict: A dictionary containing: + - total_samples: Total number of get_stack_trace calls + - frame_cache_hits: Full cache hits (entire stack unchanged) + - frame_cache_misses: Cache misses requiring full walk + - frame_cache_partial_hits: Partial hits (stopped at cached frame) + - frames_read_from_cache: Total frames retrieved from cache + - frames_read_from_memory: Total frames read from remote memory + - memory_reads: Total remote memory read operations + - memory_bytes_read: Total bytes read from remote memory + - code_object_cache_hits: Code object cache hits + - code_object_cache_misses: Code object cache misses + - stale_cache_invalidations: Times stale cache entries were cleared + - frame_cache_hit_rate: Percentage of samples that hit the cache + - code_object_cache_hit_rate: Percentage of code object lookups that hit cache + +Raises: + RuntimeError: If stats collection was not enabled (stats=False) +[clinic start generated code]*/ + +static PyObject * +_remote_debugging_RemoteUnwinder_get_stats_impl(RemoteUnwinderObject *self) +/*[clinic end generated code: output=21e36477122be2a0 input=75fef4134c12a8c9]*/ +{ + if (!self->collect_stats) { + PyErr_SetString(PyExc_RuntimeError, + "Statistics collection was not enabled. " + "Create RemoteUnwinder with stats=True to collect statistics."); + return NULL; + } + + PyObject *result = PyDict_New(); + if (!result) { + return NULL; + } + +#define ADD_STAT(name) do { \ + PyObject *val = PyLong_FromUnsignedLongLong(self->stats.name); \ + if (!val || PyDict_SetItemString(result, #name, val) < 0) { \ + Py_XDECREF(val); \ + Py_DECREF(result); \ + return NULL; \ + } \ + Py_DECREF(val); \ +} while(0) + + ADD_STAT(total_samples); + ADD_STAT(frame_cache_hits); + ADD_STAT(frame_cache_misses); + ADD_STAT(frame_cache_partial_hits); + ADD_STAT(frames_read_from_cache); + ADD_STAT(frames_read_from_memory); + ADD_STAT(memory_reads); + ADD_STAT(memory_bytes_read); + ADD_STAT(code_object_cache_hits); + ADD_STAT(code_object_cache_misses); + ADD_STAT(stale_cache_invalidations); + +#undef ADD_STAT + + // Calculate and add derived statistics + // Hit rate is calculated as (hits + partial_hits) / total_cache_lookups + double frame_cache_hit_rate = 0.0; + uint64_t total_cache_lookups = self->stats.frame_cache_hits + self->stats.frame_cache_partial_hits + self->stats.frame_cache_misses; + if (total_cache_lookups > 0) { + frame_cache_hit_rate = 100.0 * (double)(self->stats.frame_cache_hits + self->stats.frame_cache_partial_hits) + / (double)total_cache_lookups; + } + PyObject *hit_rate = PyFloat_FromDouble(frame_cache_hit_rate); + if (!hit_rate || PyDict_SetItemString(result, "frame_cache_hit_rate", hit_rate) < 0) { + Py_XDECREF(hit_rate); + Py_DECREF(result); + return NULL; + } + Py_DECREF(hit_rate); + + double code_object_hit_rate = 0.0; + uint64_t total_code_lookups = self->stats.code_object_cache_hits + self->stats.code_object_cache_misses; + if (total_code_lookups > 0) { + code_object_hit_rate = 100.0 * (double)self->stats.code_object_cache_hits / (double)total_code_lookups; + } + PyObject *code_hit_rate = PyFloat_FromDouble(code_object_hit_rate); + if (!code_hit_rate || PyDict_SetItemString(result, "code_object_cache_hit_rate", code_hit_rate) < 0) { + Py_XDECREF(code_hit_rate); + Py_DECREF(result); + return NULL; + } + Py_DECREF(code_hit_rate); + + return result; +} + +static PyMethodDef RemoteUnwinder_methods[] = { + _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STACK_TRACE_METHODDEF + _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ALL_AWAITED_BY_METHODDEF + _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ASYNC_STACK_TRACE_METHODDEF + _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STATS_METHODDEF + {NULL, NULL} +}; + +static void +RemoteUnwinder_dealloc(PyObject *op) +{ + RemoteUnwinderObject *self = RemoteUnwinder_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + if (self->code_object_cache) { + _Py_hashtable_destroy(self->code_object_cache); + } +#ifdef MS_WINDOWS + if (self->win_process_buffer != NULL) { + PyMem_Free(self->win_process_buffer); + } +#endif + +#ifdef Py_GIL_DISABLED + if (self->tlbc_cache) { + _Py_hashtable_destroy(self->tlbc_cache); + } +#endif + if (self->handle.pid != 0) { + _Py_RemoteDebug_ClearCache(&self->handle); + _Py_RemoteDebug_CleanupProcHandle(&self->handle); + } + frame_cache_cleanup(self); + PyObject_Del(self); + Py_DECREF(tp); +} + +static PyType_Slot RemoteUnwinder_slots[] = { + {Py_tp_doc, (void *)"RemoteUnwinder(pid): Inspect stack of a remote Python process."}, + {Py_tp_methods, RemoteUnwinder_methods}, + {Py_tp_init, _remote_debugging_RemoteUnwinder___init__}, + {Py_tp_dealloc, RemoteUnwinder_dealloc}, + {0, NULL} +}; + +static PyType_Spec RemoteUnwinder_spec = { + .name = "_remote_debugging.RemoteUnwinder", + .basicsize = sizeof(RemoteUnwinderObject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = RemoteUnwinder_slots, +}; + +/* ============================================================================ + * MODULE INITIALIZATION + * ============================================================================ */ + +static int +_remote_debugging_exec(PyObject *m) +{ + RemoteDebuggingState *st = RemoteDebugging_GetState(m); +#define CREATE_TYPE(mod, type, spec) \ + do { \ + type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ + if (type == NULL) { \ + return -1; \ + } \ + } while (0) + + CREATE_TYPE(m, st->RemoteDebugging_Type, &RemoteUnwinder_spec); + + if (PyModule_AddType(m, st->RemoteDebugging_Type) < 0) { + return -1; + } + + // Initialize structseq types + st->TaskInfo_Type = PyStructSequence_NewType(&TaskInfo_desc); + if (st->TaskInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->TaskInfo_Type) < 0) { + return -1; + } + + st->LocationInfo_Type = PyStructSequence_NewType(&LocationInfo_desc); + if (st->LocationInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->LocationInfo_Type) < 0) { + return -1; + } + + st->FrameInfo_Type = PyStructSequence_NewType(&FrameInfo_desc); + if (st->FrameInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->FrameInfo_Type) < 0) { + return -1; + } + + st->CoroInfo_Type = PyStructSequence_NewType(&CoroInfo_desc); + if (st->CoroInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->CoroInfo_Type) < 0) { + return -1; + } + + st->ThreadInfo_Type = PyStructSequence_NewType(&ThreadInfo_desc); + if (st->ThreadInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->ThreadInfo_Type) < 0) { + return -1; + } + + st->InterpreterInfo_Type = PyStructSequence_NewType(&InterpreterInfo_desc); + if (st->InterpreterInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->InterpreterInfo_Type) < 0) { + return -1; + } + + st->AwaitedInfo_Type = PyStructSequence_NewType(&AwaitedInfo_desc); + if (st->AwaitedInfo_Type == NULL) { + return -1; + } + if (PyModule_AddType(m, st->AwaitedInfo_Type) < 0) { + return -1; + } +#ifdef Py_GIL_DISABLED + PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); +#endif + int rc = PyModule_AddIntConstant(m, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); + if (rc < 0) { + return -1; + } + + // Add thread status flag constants + if (PyModule_AddIntConstant(m, "THREAD_STATUS_HAS_GIL", THREAD_STATUS_HAS_GIL) < 0) { + return -1; + } + if (PyModule_AddIntConstant(m, "THREAD_STATUS_ON_CPU", THREAD_STATUS_ON_CPU) < 0) { + return -1; + } + if (PyModule_AddIntConstant(m, "THREAD_STATUS_UNKNOWN", THREAD_STATUS_UNKNOWN) < 0) { + return -1; + } + if (PyModule_AddIntConstant(m, "THREAD_STATUS_GIL_REQUESTED", THREAD_STATUS_GIL_REQUESTED) < 0) { + return -1; + } + if (PyModule_AddIntConstant(m, "THREAD_STATUS_HAS_EXCEPTION", THREAD_STATUS_HAS_EXCEPTION) < 0) { + return -1; + } + + if (RemoteDebugging_InitState(st) < 0) { + return -1; + } + return 0; +} + +static int +remote_debugging_traverse(PyObject *mod, visitproc visit, void *arg) +{ + RemoteDebuggingState *state = RemoteDebugging_GetState(mod); + Py_VISIT(state->RemoteDebugging_Type); + Py_VISIT(state->TaskInfo_Type); + Py_VISIT(state->LocationInfo_Type); + Py_VISIT(state->FrameInfo_Type); + Py_VISIT(state->CoroInfo_Type); + Py_VISIT(state->ThreadInfo_Type); + Py_VISIT(state->InterpreterInfo_Type); + Py_VISIT(state->AwaitedInfo_Type); + return 0; +} + +static int +remote_debugging_clear(PyObject *mod) +{ + RemoteDebuggingState *state = RemoteDebugging_GetState(mod); + Py_CLEAR(state->RemoteDebugging_Type); + Py_CLEAR(state->TaskInfo_Type); + Py_CLEAR(state->LocationInfo_Type); + Py_CLEAR(state->FrameInfo_Type); + Py_CLEAR(state->CoroInfo_Type); + Py_CLEAR(state->ThreadInfo_Type); + Py_CLEAR(state->InterpreterInfo_Type); + Py_CLEAR(state->AwaitedInfo_Type); + return 0; +} + +static void +remote_debugging_free(void *mod) +{ + (void)remote_debugging_clear((PyObject *)mod); +} + +static PyModuleDef_Slot remote_debugging_slots[] = { + {Py_mod_exec, _remote_debugging_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL}, +}; + +/* ============================================================================ + * MODULE-LEVEL FUNCTIONS + * ============================================================================ */ + +/*[clinic input] +_remote_debugging.get_child_pids + + pid: int + Process ID of the parent process + * + recursive: bool = True + If True, return all descendants (children, grandchildren, etc.). + If False, return only direct children. + +Get all child process IDs of the given process. + +Returns a list of child process IDs. Returns an empty list if no children +are found. + +This function provides a snapshot of child processes at a moment in time. +Child processes may exit or new ones may be created after the list is returned. + +Raises: + OSError: If unable to enumerate processes + NotImplementedError: If not supported on this platform +[clinic start generated code]*/ + +static PyObject * +_remote_debugging_get_child_pids_impl(PyObject *module, int pid, + int recursive) +/*[clinic end generated code: output=1ae2289c6b953e4b input=3395cbe7f17066c9]*/ +{ + return enumerate_child_pids((pid_t)pid, recursive); +} + +/*[clinic input] +_remote_debugging.is_python_process + + pid: int + +Check if a process is a Python process. +[clinic start generated code]*/ + +static PyObject * +_remote_debugging_is_python_process_impl(PyObject *module, int pid) +/*[clinic end generated code: output=22947dc8afcac362 input=13488e28c7295d84]*/ +{ + proc_handle_t handle; + + if (_Py_RemoteDebug_InitProcHandle(&handle, pid) < 0) { + PyErr_Clear(); + Py_RETURN_FALSE; + } + + uintptr_t runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(&handle); + _Py_RemoteDebug_CleanupProcHandle(&handle); + + if (runtime_start_address == 0) { + PyErr_Clear(); + Py_RETURN_FALSE; + } + + Py_RETURN_TRUE; +} + +static PyMethodDef remote_debugging_methods[] = { + _REMOTE_DEBUGGING_GET_CHILD_PIDS_METHODDEF + _REMOTE_DEBUGGING_IS_PYTHON_PROCESS_METHODDEF + {NULL, NULL, 0, NULL}, +}; + +static struct PyModuleDef remote_debugging_module = { + PyModuleDef_HEAD_INIT, + .m_name = "_remote_debugging", + .m_size = sizeof(RemoteDebuggingState), + .m_methods = remote_debugging_methods, + .m_slots = remote_debugging_slots, + .m_traverse = remote_debugging_traverse, + .m_clear = remote_debugging_clear, + .m_free = remote_debugging_free, +}; + +PyMODINIT_FUNC +PyInit__remote_debugging(void) +{ + return PyModuleDef_Init(&remote_debugging_module); +} diff --git a/Modules/_remote_debugging/object_reading.c b/Modules/_remote_debugging/object_reading.c new file mode 100644 index 00000000000..2f465ca0cac --- /dev/null +++ b/Modules/_remote_debugging/object_reading.c @@ -0,0 +1,247 @@ +/****************************************************************************** + * Remote Debugging Module - Object Reading Functions + * + * This file contains functions for reading Python objects from remote + * process memory, including strings, bytes, and integers. + ******************************************************************************/ + +#include "_remote_debugging.h" + +/* ============================================================================ + * MEMORY READING FUNCTIONS + * ============================================================================ */ + +#define DEFINE_MEMORY_READER(type_name, c_type, error_msg) \ +int \ +read_##type_name(RemoteUnwinderObject *unwinder, uintptr_t address, c_type *result) \ +{ \ + int res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address, sizeof(c_type), result); \ + if (res < 0) { \ + set_exception_cause(unwinder, PyExc_RuntimeError, error_msg); \ + return -1; \ + } \ + return 0; \ +} + +DEFINE_MEMORY_READER(ptr, uintptr_t, "Failed to read pointer from remote memory") +DEFINE_MEMORY_READER(Py_ssize_t, Py_ssize_t, "Failed to read Py_ssize_t from remote memory") +DEFINE_MEMORY_READER(char, char, "Failed to read char from remote memory") + +int +read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *ptr_addr) +{ + if (read_ptr(unwinder, address, ptr_addr)) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read Python pointer"); + return -1; + } + *ptr_addr &= ~Py_TAG_BITS; + return 0; +} + +/* ============================================================================ + * PYTHON OBJECT READING FUNCTIONS + * ============================================================================ */ + +PyObject * +read_py_str( + RemoteUnwinderObject *unwinder, + uintptr_t address, + Py_ssize_t max_len +) { + PyObject *result = NULL; + char *buf = NULL; + + // Read the entire PyUnicodeObject at once + char unicode_obj[SIZEOF_UNICODE_OBJ]; + int res = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + address, + SIZEOF_UNICODE_OBJ, + unicode_obj + ); + if (res < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyUnicodeObject"); + goto err; + } + + Py_ssize_t len = GET_MEMBER(Py_ssize_t, unicode_obj, unwinder->debug_offsets.unicode_object.length); + if (len < 0 || len > max_len) { + PyErr_Format(PyExc_RuntimeError, + "Invalid string length (%zd) at 0x%lx", len, address); + set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid string length in remote Unicode object"); + return NULL; + } + + buf = (char *)PyMem_RawMalloc(len+1); + if (buf == NULL) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate buffer for string reading"); + return NULL; + } + + size_t offset = (size_t)unwinder->debug_offsets.unicode_object.asciiobject_size; + res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address + offset, len, buf); + if (res < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read string data from remote memory"); + goto err; + } + buf[len] = '\0'; + + result = PyUnicode_FromStringAndSize(buf, len); + if (result == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create PyUnicode from remote string data"); + goto err; + } + + PyMem_RawFree(buf); + assert(result != NULL); + return result; + +err: + if (buf != NULL) { + PyMem_RawFree(buf); + } + return NULL; +} + +PyObject * +read_py_bytes( + RemoteUnwinderObject *unwinder, + uintptr_t address, + Py_ssize_t max_len +) { + PyObject *result = NULL; + char *buf = NULL; + + // Read the entire PyBytesObject at once + char bytes_obj[SIZEOF_BYTES_OBJ]; + int res = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + address, + SIZEOF_BYTES_OBJ, + bytes_obj + ); + if (res < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyBytesObject"); + goto err; + } + + Py_ssize_t len = GET_MEMBER(Py_ssize_t, bytes_obj, unwinder->debug_offsets.bytes_object.ob_size); + if (len < 0 || len > max_len) { + PyErr_Format(PyExc_RuntimeError, + "Invalid bytes length (%zd) at 0x%lx", len, address); + set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid bytes length in remote bytes object"); + return NULL; + } + + buf = (char *)PyMem_RawMalloc(len+1); + if (buf == NULL) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate buffer for bytes reading"); + return NULL; + } + + size_t offset = (size_t)unwinder->debug_offsets.bytes_object.ob_sval; + res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address + offset, len, buf); + if (res < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read bytes data from remote memory"); + goto err; + } + buf[len] = '\0'; + + result = PyBytes_FromStringAndSize(buf, len); + if (result == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create PyBytes from remote bytes data"); + goto err; + } + + PyMem_RawFree(buf); + assert(result != NULL); + return result; + +err: + if (buf != NULL) { + PyMem_RawFree(buf); + } + return NULL; +} + +long +read_py_long( + RemoteUnwinderObject *unwinder, + uintptr_t address +) +{ + unsigned int shift = PYLONG_BITS_IN_DIGIT; + + // Read the entire PyLongObject at once + char long_obj[SIZEOF_LONG_OBJ]; + int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + address, + (size_t)unwinder->debug_offsets.long_object.size, + long_obj); + if (bytes_read < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyLongObject"); + return -1; + } + + uintptr_t lv_tag = GET_MEMBER(uintptr_t, long_obj, unwinder->debug_offsets.long_object.lv_tag); + int negative = (lv_tag & 3) == 2; + Py_ssize_t size = lv_tag >> 3; + + if (size == 0) { + return 0; + } + + // If the long object has inline digits, use them directly + digit *digits; + if (size <= _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS) { + // For small integers, digits are inline in the long_value.ob_digit array + digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); + if (!digits) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for small PyLong"); + return -1; + } + memcpy(digits, long_obj + unwinder->debug_offsets.long_object.ob_digit, size * sizeof(digit)); + } else { + // For larger integers, we need to read the digits separately + digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); + if (!digits) { + PyErr_NoMemory(); + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for large PyLong"); + return -1; + } + + bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + address + (uintptr_t)unwinder->debug_offsets.long_object.ob_digit, + sizeof(digit) * size, + digits + ); + if (bytes_read < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyLong digits from remote memory"); + goto error; + } + } + + long long value = 0; + + // In theory this can overflow, but because of llvm/llvm-project#16778 + // we can't use __builtin_mul_overflow because it fails to link with + // __muloti4 on aarch64. In practice this is fine because all we're + // testing here are task numbers that would fit in a single byte. + for (Py_ssize_t i = 0; i < size; ++i) { + long long factor = digits[i] * (1UL << (Py_ssize_t)(shift * i)); + value += factor; + } + PyMem_RawFree(digits); + if (negative) { + value *= -1; + } + return (long)value; +error: + PyMem_RawFree(digits); + return -1; +} diff --git a/Modules/_remote_debugging/subprocess.c b/Modules/_remote_debugging/subprocess.c new file mode 100644 index 00000000000..2056217664a --- /dev/null +++ b/Modules/_remote_debugging/subprocess.c @@ -0,0 +1,459 @@ +/****************************************************************************** + * Remote Debugging Module - Subprocess Enumeration + * + * This file contains platform-specific functions for enumerating child + * processes of a given PID. + ******************************************************************************/ + +#include "_remote_debugging.h" + +#ifndef MS_WINDOWS +#include <unistd.h> +#include <dirent.h> +#endif + +#ifdef MS_WINDOWS +#include <tlhelp32.h> +#endif + +/* ============================================================================ + * INTERNAL DATA STRUCTURES + * ============================================================================ */ + +/* Simple dynamic array for collecting PIDs */ +typedef struct { + pid_t *pids; + size_t count; + size_t capacity; +} pid_array_t; + +static int +pid_array_init(pid_array_t *arr) +{ + arr->capacity = 64; + arr->count = 0; + arr->pids = (pid_t *)PyMem_Malloc(arr->capacity * sizeof(pid_t)); + if (arr->pids == NULL) { + PyErr_NoMemory(); + return -1; + } + return 0; +} + +static void +pid_array_cleanup(pid_array_t *arr) +{ + if (arr->pids != NULL) { + PyMem_Free(arr->pids); + arr->pids = NULL; + } + arr->count = 0; + arr->capacity = 0; +} + +static int +pid_array_append(pid_array_t *arr, pid_t pid) +{ + if (arr->count >= arr->capacity) { + /* Check for overflow before multiplication */ + if (arr->capacity > SIZE_MAX / 2) { + PyErr_SetString(PyExc_OverflowError, "PID array capacity overflow"); + return -1; + } + size_t new_capacity = arr->capacity * 2; + /* Check allocation size won't overflow */ + if (new_capacity > SIZE_MAX / sizeof(pid_t)) { + PyErr_SetString(PyExc_OverflowError, "PID array size overflow"); + return -1; + } + pid_t *new_pids = (pid_t *)PyMem_Realloc(arr->pids, new_capacity * sizeof(pid_t)); + if (new_pids == NULL) { + PyErr_NoMemory(); + return -1; + } + arr->pids = new_pids; + arr->capacity = new_capacity; + } + arr->pids[arr->count++] = pid; + return 0; +} + +static int +pid_array_contains(pid_array_t *arr, pid_t pid) +{ + for (size_t i = 0; i < arr->count; i++) { + if (arr->pids[i] == pid) { + return 1; + } + } + return 0; +} + +/* ============================================================================ + * SHARED BFS HELPER + * ============================================================================ */ + +/* Find child PIDs using BFS traversal of the pid->ppid mapping. + * all_pids and ppids must have the same count (parallel arrays). + * Returns 0 on success, -1 on error. */ +static int +find_children_bfs(pid_t target_pid, int recursive, + pid_t *all_pids, pid_t *ppids, size_t pid_count, + pid_array_t *result) +{ + int retval = -1; + pid_array_t to_process = {0}; + + if (pid_array_init(&to_process) < 0) { + goto done; + } + if (pid_array_append(&to_process, target_pid) < 0) { + goto done; + } + + size_t process_idx = 0; + while (process_idx < to_process.count) { + pid_t current_pid = to_process.pids[process_idx++]; + + for (size_t i = 0; i < pid_count; i++) { + if (ppids[i] != current_pid) { + continue; + } + pid_t child_pid = all_pids[i]; + if (pid_array_contains(result, child_pid)) { + continue; + } + if (pid_array_append(result, child_pid) < 0) { + goto done; + } + if (recursive && pid_array_append(&to_process, child_pid) < 0) { + goto done; + } + } + + if (!recursive) { + break; + } + } + + retval = 0; + +done: + pid_array_cleanup(&to_process); + return retval; +} + +/* ============================================================================ + * LINUX IMPLEMENTATION + * ============================================================================ */ + +#if defined(__linux__) + +/* Parse /proc/{pid}/stat to get parent PID */ +static pid_t +get_ppid_linux(pid_t pid) +{ + char stat_path[64]; + char buffer[2048]; + + snprintf(stat_path, sizeof(stat_path), "/proc/%d/stat", (int)pid); + + int fd = open(stat_path, O_RDONLY); + if (fd == -1) { + return -1; + } + + ssize_t n = read(fd, buffer, sizeof(buffer) - 1); + close(fd); + + if (n <= 0) { + return -1; + } + buffer[n] = '\0'; + + /* Find closing paren of comm field - stat format: pid (comm) state ppid ... */ + char *p = strrchr(buffer, ')'); + if (!p) { + return -1; + } + + /* Skip ") " with bounds checking */ + char *end = buffer + n; + p += 2; + if (p >= end) { + return -1; + } + if (*p == ' ') { + p++; + if (p >= end) { + return -1; + } + } + + /* Parse: state ppid */ + char state; + int ppid; + if (sscanf(p, "%c %d", &state, &ppid) != 2) { + return -1; + } + + return (pid_t)ppid; +} + +static int +get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) +{ + int retval = -1; + pid_array_t all_pids = {0}; + pid_array_t ppids = {0}; + DIR *proc_dir = NULL; + + if (pid_array_init(&all_pids) < 0) { + goto done; + } + + if (pid_array_init(&ppids) < 0) { + goto done; + } + + proc_dir = opendir("/proc"); + if (!proc_dir) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "/proc"); + goto done; + } + + /* Single pass: collect PIDs and their PPIDs together */ + struct dirent *entry; + while ((entry = readdir(proc_dir)) != NULL) { + /* Skip non-numeric entries (also skips . and ..) */ + if (entry->d_name[0] < '1' || entry->d_name[0] > '9') { + continue; + } + char *endptr; + long pid_long = strtol(entry->d_name, &endptr, 10); + if (*endptr != '\0' || pid_long <= 0) { + continue; + } + pid_t pid = (pid_t)pid_long; + pid_t ppid = get_ppid_linux(pid); + if (ppid < 0) { + continue; + } + if (pid_array_append(&all_pids, pid) < 0 || + pid_array_append(&ppids, ppid) < 0) { + goto done; + } + } + + closedir(proc_dir); + proc_dir = NULL; + + if (find_children_bfs(target_pid, recursive, + all_pids.pids, ppids.pids, all_pids.count, + result) < 0) { + goto done; + } + + retval = 0; + +done: + if (proc_dir) { + closedir(proc_dir); + } + pid_array_cleanup(&all_pids); + pid_array_cleanup(&ppids); + return retval; +} + +#endif /* __linux__ */ + +/* ============================================================================ + * MACOS IMPLEMENTATION + * ============================================================================ */ + +#if defined(__APPLE__) && TARGET_OS_OSX + +#include <sys/proc_info.h> + +static int +get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) +{ + int retval = -1; + pid_t *pid_list = NULL; + pid_t *ppids = NULL; + + /* Get count of all PIDs */ + int n_pids = proc_listallpids(NULL, 0); + if (n_pids <= 0) { + PyErr_SetString(PyExc_OSError, "Failed to get process count"); + goto done; + } + + /* Allocate buffer for PIDs (add some slack for new processes) */ + int buffer_size = n_pids + 64; + pid_list = (pid_t *)PyMem_Malloc(buffer_size * sizeof(pid_t)); + if (!pid_list) { + PyErr_NoMemory(); + goto done; + } + + /* Get actual PIDs */ + int actual = proc_listallpids(pid_list, buffer_size * sizeof(pid_t)); + if (actual <= 0) { + PyErr_SetString(PyExc_OSError, "Failed to list PIDs"); + goto done; + } + + /* Build pid -> ppid mapping */ + ppids = (pid_t *)PyMem_Malloc(actual * sizeof(pid_t)); + if (!ppids) { + PyErr_NoMemory(); + goto done; + } + + /* Get parent PIDs for each process */ + int valid_count = 0; + for (int i = 0; i < actual; i++) { + struct proc_bsdinfo proc_info; + int ret = proc_pidinfo(pid_list[i], PROC_PIDTBSDINFO, 0, + &proc_info, sizeof(proc_info)); + if (ret != sizeof(proc_info)) { + continue; + } + pid_list[valid_count] = pid_list[i]; + ppids[valid_count] = proc_info.pbi_ppid; + valid_count++; + } + + if (find_children_bfs(target_pid, recursive, + pid_list, ppids, valid_count, + result) < 0) { + goto done; + } + + retval = 0; + +done: + PyMem_Free(pid_list); + PyMem_Free(ppids); + return retval; +} + +#endif /* __APPLE__ && TARGET_OS_OSX */ + +/* ============================================================================ + * WINDOWS IMPLEMENTATION + * ============================================================================ */ + +#ifdef MS_WINDOWS + +static int +get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) +{ + int retval = -1; + pid_array_t all_pids = {0}; + pid_array_t ppids = {0}; + HANDLE snapshot = INVALID_HANDLE_VALUE; + + snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErr(0); + goto done; + } + + if (pid_array_init(&all_pids) < 0) { + goto done; + } + + if (pid_array_init(&ppids) < 0) { + goto done; + } + + /* Single pass: collect PIDs and PPIDs together */ + PROCESSENTRY32 pe; + pe.dwSize = sizeof(PROCESSENTRY32); + if (Process32First(snapshot, &pe)) { + do { + if (pid_array_append(&all_pids, (pid_t)pe.th32ProcessID) < 0 || + pid_array_append(&ppids, (pid_t)pe.th32ParentProcessID) < 0) { + goto done; + } + } while (Process32Next(snapshot, &pe)); + } + + CloseHandle(snapshot); + snapshot = INVALID_HANDLE_VALUE; + + if (find_children_bfs(target_pid, recursive, + all_pids.pids, ppids.pids, all_pids.count, + result) < 0) { + goto done; + } + + retval = 0; + +done: + if (snapshot != INVALID_HANDLE_VALUE) { + CloseHandle(snapshot); + } + pid_array_cleanup(&all_pids); + pid_array_cleanup(&ppids); + return retval; +} + +#endif /* MS_WINDOWS */ + +/* ============================================================================ + * UNSUPPORTED PLATFORM STUB + * ============================================================================ */ + +#if !defined(__linux__) && !(defined(__APPLE__) && TARGET_OS_OSX) && !defined(MS_WINDOWS) + +static int +get_child_pids_platform(pid_t target_pid, int recursive, pid_array_t *result) +{ + PyErr_SetString(PyExc_NotImplementedError, + "Subprocess enumeration not supported on this platform"); + return -1; +} + +#endif + +/* ============================================================================ + * PUBLIC API + * ============================================================================ */ + +PyObject * +enumerate_child_pids(pid_t target_pid, int recursive) +{ + pid_array_t result; + + if (pid_array_init(&result) < 0) { + return NULL; + } + + if (get_child_pids_platform(target_pid, recursive, &result) < 0) { + pid_array_cleanup(&result); + return NULL; + } + + /* Convert to Python list */ + PyObject *list = PyList_New(result.count); + if (list == NULL) { + pid_array_cleanup(&result); + return NULL; + } + + for (size_t i = 0; i < result.count; i++) { + PyObject *pid_obj = PyLong_FromLong((long)result.pids[i]); + if (pid_obj == NULL) { + Py_DECREF(list); + pid_array_cleanup(&result); + return NULL; + } + PyList_SET_ITEM(list, i, pid_obj); + } + + pid_array_cleanup(&result); + return list; +} diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c new file mode 100644 index 00000000000..3a5b8adb3f4 --- /dev/null +++ b/Modules/_remote_debugging/threads.c @@ -0,0 +1,503 @@ +/****************************************************************************** + * Remote Debugging Module - Thread Functions + * + * This file contains functions for iterating threads and determining + * thread status in remote process memory. + ******************************************************************************/ + +#include "_remote_debugging.h" + +#ifndef MS_WINDOWS +#include <unistd.h> +#endif + +/* ============================================================================ + * THREAD ITERATION FUNCTIONS + * ============================================================================ */ + +int +iterate_threads( + RemoteUnwinderObject *unwinder, + thread_processor_func processor, + void *context +) { + uintptr_t thread_state_addr; + unsigned long tid = 0; + const size_t MAX_THREADS = 8192; + size_t thread_count = 0; + + if (0 > _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + unwinder->interpreter_addr + (uintptr_t)unwinder->debug_offsets.interpreter_state.threads_main, + sizeof(void*), + &thread_state_addr)) + { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read main thread state"); + return -1; + } + + while (thread_state_addr != 0 && thread_count < MAX_THREADS) { + thread_count++; + if (0 > _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + thread_state_addr + (uintptr_t)unwinder->debug_offsets.thread_state.native_thread_id, + sizeof(tid), + &tid)) + { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread ID"); + return -1; + } + + // Call the processor function for this thread + if (processor(unwinder, thread_state_addr, tid, context) < 0) { + return -1; + } + + // Move to next thread + if (0 > _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + thread_state_addr + (uintptr_t)unwinder->debug_offsets.thread_state.next, + sizeof(void*), + &thread_state_addr)) + { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read next thread state"); + return -1; + } + } + + return 0; +} + +/* ============================================================================ + * INTERPRETER STATE AND THREAD DISCOVERY FUNCTIONS + * ============================================================================ */ + +int +populate_initial_state_data( + int all_threads, + RemoteUnwinderObject *unwinder, + uintptr_t runtime_start_address, + uintptr_t *interpreter_state, + uintptr_t *tstate +) { + uintptr_t interpreter_state_list_head = + (uintptr_t)unwinder->debug_offsets.runtime_state.interpreters_head; + + uintptr_t address_of_interpreter_state; + int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + runtime_start_address + interpreter_state_list_head, + sizeof(void*), + &address_of_interpreter_state); + if (bytes_read < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter state address"); + return -1; + } + + if (address_of_interpreter_state == 0) { + PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); + set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state is NULL"); + return -1; + } + + *interpreter_state = address_of_interpreter_state; + + if (all_threads) { + *tstate = 0; + return 0; + } + + uintptr_t address_of_thread = address_of_interpreter_state + + (uintptr_t)unwinder->debug_offsets.interpreter_state.threads_main; + + if (_Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, + address_of_thread, + sizeof(void*), + tstate) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read main thread state address"); + return -1; + } + + return 0; +} + +int +find_running_frame( + RemoteUnwinderObject *unwinder, + uintptr_t address_of_thread, + uintptr_t *frame +) { + if ((void*)address_of_thread != NULL) { + int err = read_ptr( + unwinder, + address_of_thread + (uintptr_t)unwinder->debug_offsets.thread_state.current_frame, + frame); + if (err) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read current frame pointer"); + return -1; + } + return 0; + } + + *frame = (uintptr_t)NULL; + return 0; +} + +/* ============================================================================ + * THREAD STATUS FUNCTIONS + * ============================================================================ */ + +int +get_thread_status(RemoteUnwinderObject *unwinder, uint64_t tid, uint64_t pthread_id) { +#if defined(__APPLE__) && TARGET_OS_OSX + if (unwinder->thread_id_offset == 0) { + uint64_t *tids = (uint64_t *)PyMem_Malloc(MAX_NATIVE_THREADS * sizeof(uint64_t)); + if (!tids) { + PyErr_NoMemory(); + return -1; + } + int n = proc_pidinfo(unwinder->handle.pid, PROC_PIDLISTTHREADS, 0, tids, MAX_NATIVE_THREADS * sizeof(uint64_t)) / sizeof(uint64_t); + if (n <= 0) { + PyMem_Free(tids); + return THREAD_STATE_UNKNOWN; + } + uint64_t min_offset = UINT64_MAX; + for (int i = 0; i < n; i++) { + uint64_t offset = tids[i] - pthread_id; + if (offset < min_offset) { + min_offset = offset; + } + } + unwinder->thread_id_offset = min_offset; + PyMem_Free(tids); + } + struct proc_threadinfo ti; + uint64_t tid_with_offset = pthread_id + unwinder->thread_id_offset; + if (proc_pidinfo(unwinder->handle.pid, PROC_PIDTHREADINFO, tid_with_offset, &ti, sizeof(ti)) != sizeof(ti)) { + return THREAD_STATE_UNKNOWN; + } + if (ti.pth_run_state == TH_STATE_RUNNING) { + return THREAD_STATE_RUNNING; + } + return THREAD_STATE_IDLE; +#elif defined(__linux__) + char stat_path[256]; + char buffer[2048] = ""; + + snprintf(stat_path, sizeof(stat_path), "/proc/%d/task/%lu/stat", unwinder->handle.pid, tid); + + int fd = open(stat_path, O_RDONLY); + if (fd == -1) { + return THREAD_STATE_UNKNOWN; + } + + if (read(fd, buffer, 2047) == 0) { + close(fd); + return THREAD_STATE_UNKNOWN; + } + close(fd); + + char *p = strchr(buffer, ')'); + if (!p) { + return THREAD_STATE_UNKNOWN; + } + + p += 2; // Skip ") " + if (*p == ' ') { + p++; + } + + switch (*p) { + case 'R': // Running + return THREAD_STATE_RUNNING; + case 'S': // Interruptible sleep + case 'D': // Uninterruptible sleep + case 'T': // Stopped + case 'Z': // Zombie + case 'I': // Idle kernel thread + return THREAD_STATE_IDLE; + default: + return THREAD_STATE_UNKNOWN; + } +#elif defined(MS_WINDOWS) + ULONG n; + NTSTATUS status = NtQuerySystemInformation( + SystemProcessInformation, + unwinder->win_process_buffer, + unwinder->win_process_buffer_size, + &n + ); + if (status == STATUS_INFO_LENGTH_MISMATCH) { + // Buffer was too small so we reallocate a larger one and try again. + unwinder->win_process_buffer_size = n; + PVOID new_buffer = PyMem_Realloc(unwinder->win_process_buffer, n); + if (!new_buffer) { + return -1; + } + unwinder->win_process_buffer = new_buffer; + return get_thread_status(unwinder, tid, pthread_id); + } + if (status != STATUS_SUCCESS) { + return -1; + } + + SYSTEM_PROCESS_INFORMATION *pi = (SYSTEM_PROCESS_INFORMATION *)unwinder->win_process_buffer; + while ((ULONG)(ULONG_PTR)pi->UniqueProcessId != unwinder->handle.pid) { + if (pi->NextEntryOffset == 0) { + // We didn't find the process + return -1; + } + pi = (SYSTEM_PROCESS_INFORMATION *)(((BYTE *)pi) + pi->NextEntryOffset); + } + + SYSTEM_THREAD_INFORMATION *ti = (SYSTEM_THREAD_INFORMATION *)((char *)pi + sizeof(SYSTEM_PROCESS_INFORMATION)); + for (size_t i = 0; i < pi->NumberOfThreads; i++, ti++) { + if (ti->ClientId.UniqueThread == (HANDLE)tid) { + return ti->ThreadState != WIN32_THREADSTATE_RUNNING ? THREAD_STATE_IDLE : THREAD_STATE_RUNNING; + } + } + + return -1; +#else + return THREAD_STATE_UNKNOWN; +#endif +} + +/* ============================================================================ + * STACK UNWINDING FUNCTIONS + * ============================================================================ */ + +typedef struct { + unsigned int initialized:1; + unsigned int bound:1; + unsigned int unbound:1; + unsigned int bound_gilstate:1; + unsigned int active:1; + unsigned int finalizing:1; + unsigned int cleared:1; + unsigned int finalized:1; + unsigned int :24; +} _thread_status; + +PyObject* +unwind_stack_for_thread( + RemoteUnwinderObject *unwinder, + uintptr_t *current_tstate, + uintptr_t gil_holder_tstate, + uintptr_t gc_frame +) { + PyObject *frame_info = NULL; + PyObject *thread_id = NULL; + PyObject *result = NULL; + StackChunkList chunks = {0}; + + char ts[SIZEOF_THREAD_STATE]; + int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( + &unwinder->handle, *current_tstate, (size_t)unwinder->debug_offsets.thread_state.size, ts); + if (bytes_read < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread state"); + goto error; + } + STATS_INC(unwinder, memory_reads); + STATS_ADD(unwinder, memory_bytes_read, unwinder->debug_offsets.thread_state.size); + + long tid = GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.native_thread_id); + + // Read GC collecting state from the interpreter (before any skip checks) + uintptr_t interp_addr = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.interp); + + // Read the GC runtime state from the interpreter state + uintptr_t gc_addr = interp_addr + unwinder->debug_offsets.interpreter_state.gc; + char gc_state[SIZEOF_GC_RUNTIME_STATE]; + if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, gc_addr, unwinder->debug_offsets.gc.size, gc_state) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read GC state"); + goto error; + } + STATS_INC(unwinder, memory_reads); + STATS_ADD(unwinder, memory_bytes_read, unwinder->debug_offsets.gc.size); + + // Calculate thread status using flags (always) + int status_flags = 0; + + // Check GIL status + int has_gil = 0; + int gil_requested = 0; +#ifdef Py_GIL_DISABLED + int active = GET_MEMBER(_thread_status, ts, unwinder->debug_offsets.thread_state.status).active; + has_gil = active; + (void)gil_requested; // unused +#else + // Read holds_gil directly from thread state + has_gil = GET_MEMBER(int, ts, unwinder->debug_offsets.thread_state.holds_gil); + + // Check if thread is actively requesting the GIL + if (unwinder->debug_offsets.thread_state.gil_requested != 0) { + gil_requested = GET_MEMBER(int, ts, unwinder->debug_offsets.thread_state.gil_requested); + } + + // Set GIL_REQUESTED flag if thread is waiting + if (!has_gil && gil_requested) { + status_flags |= THREAD_STATUS_GIL_REQUESTED; + } +#endif + if (has_gil) { + status_flags |= THREAD_STATUS_HAS_GIL; + // gh-142207 for remote debugging. + gil_requested = 0; + } + + // Check exception state (both raised and handled exceptions) + int has_exception = 0; + + // Check current_exception (exception being raised/propagated) + uintptr_t current_exception = GET_MEMBER(uintptr_t, ts, + unwinder->debug_offsets.thread_state.current_exception); + if (current_exception != 0) { + has_exception = 1; + } + + // Check exc_state.exc_value (exception being handled in except block) + // exc_state is embedded in PyThreadState, so we read it directly from + // the thread state buffer. This catches most cases; nested exception + // handlers where exc_info points elsewhere are rare. + if (!has_exception) { + uintptr_t exc_value = GET_MEMBER(uintptr_t, ts, + unwinder->debug_offsets.thread_state.exc_state + + unwinder->debug_offsets.err_stackitem.exc_value); + if (exc_value != 0) { + has_exception = 1; + } + } + + if (has_exception) { + status_flags |= THREAD_STATUS_HAS_EXCEPTION; + } + + // Check CPU status + long pthread_id = GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.thread_id); + + // Optimization: only check CPU status if needed by mode because it's expensive + int cpu_status = -1; + if (unwinder->mode == PROFILING_MODE_CPU || unwinder->mode == PROFILING_MODE_ALL) { + cpu_status = get_thread_status(unwinder, tid, pthread_id); + } + + if (cpu_status == -1) { + status_flags |= THREAD_STATUS_UNKNOWN; + } else if (cpu_status == THREAD_STATE_RUNNING) { + status_flags |= THREAD_STATUS_ON_CPU; + } + + // Check if we should skip this thread based on mode + int should_skip = 0; + if (unwinder->skip_non_matching_threads) { + if (unwinder->mode == PROFILING_MODE_CPU) { + // Skip if not on CPU + should_skip = !(status_flags & THREAD_STATUS_ON_CPU); + } else if (unwinder->mode == PROFILING_MODE_GIL) { + // Skip if doesn't have GIL + should_skip = !(status_flags & THREAD_STATUS_HAS_GIL); + } else if (unwinder->mode == PROFILING_MODE_EXCEPTION) { + // Skip if thread doesn't have an exception active + should_skip = !(status_flags & THREAD_STATUS_HAS_EXCEPTION); + } + // PROFILING_MODE_WALL and PROFILING_MODE_ALL never skip + } + + if (should_skip) { + // Advance to next thread and return NULL to skip processing + *current_tstate = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.next); + return NULL; + } + + uintptr_t frame_addr = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.current_frame); + uintptr_t base_frame_addr = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.base_frame); + + frame_info = PyList_New(0); + if (!frame_info) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create frame info list"); + goto error; + } + + // In cache mode, copying stack chunks is more expensive than direct memory reads + if (!unwinder->cache_frames) { + if (copy_stack_chunks(unwinder, *current_tstate, &chunks) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to copy stack chunks"); + goto error; + } + } + + uintptr_t addrs[FRAME_CACHE_MAX_FRAMES]; + FrameWalkContext ctx = { + .frame_addr = frame_addr, + .base_frame_addr = base_frame_addr, + .gc_frame = gc_frame, + .chunks = &chunks, + .frame_info = frame_info, + .frame_addrs = addrs, + .num_addrs = 0, + .max_addrs = FRAME_CACHE_MAX_FRAMES, + }; + assert(ctx.max_addrs == FRAME_CACHE_MAX_FRAMES); + + if (unwinder->cache_frames) { + // Use cache to avoid re-reading unchanged parent frames + ctx.last_profiled_frame = GET_MEMBER(uintptr_t, ts, + unwinder->debug_offsets.thread_state.last_profiled_frame); + if (collect_frames_with_cache(unwinder, &ctx, tid) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to collect frames"); + goto error; + } + // Update last_profiled_frame for next sample + uintptr_t lpf_addr = + *current_tstate + (uintptr_t)unwinder->debug_offsets.thread_state.last_profiled_frame; + if (_Py_RemoteDebug_WriteRemoteMemory(&unwinder->handle, lpf_addr, + sizeof(uintptr_t), &frame_addr) < 0) { + PyErr_Clear(); // Non-fatal + } + } else { + // No caching - process entire frame chain with base_frame validation + if (process_frame_chain(unwinder, &ctx) < 0) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process frame chain"); + goto error; + } + } + + *current_tstate = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.next); + + thread_id = PyLong_FromLongLong(tid); + if (thread_id == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID"); + goto error; + } + + RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); + result = PyStructSequence_New(state->ThreadInfo_Type); + if (result == NULL) { + set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create ThreadInfo"); + goto error; + } + + // Always use status_flags + PyObject *py_status = PyLong_FromLong(status_flags); + if (py_status == NULL) { + set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread status"); + goto error; + } + + // py_status contains status flags (bitfield) + PyStructSequence_SetItem(result, 0, thread_id); + PyStructSequence_SetItem(result, 1, py_status); // Steals reference + PyStructSequence_SetItem(result, 2, frame_info); // Steals reference + + cleanup_stack_chunks(&chunks); + return result; + +error: + Py_XDECREF(frame_info); + Py_XDECREF(thread_id); + Py_XDECREF(result); + cleanup_stack_chunks(&chunks); + return NULL; +} diff --git a/Modules/_remote_debugging_module.c b/Modules/_remote_debugging_module.c deleted file mode 100644 index d261f179952..00000000000 --- a/Modules/_remote_debugging_module.c +++ /dev/null @@ -1,3134 +0,0 @@ -/****************************************************************************** - * Python Remote Debugging Module - * - * This module provides functionality to debug Python processes remotely by - * reading their memory and reconstructing stack traces and asyncio task states. - ******************************************************************************/ - -#define _GNU_SOURCE - -/* ============================================================================ - * HEADERS AND INCLUDES - * ============================================================================ */ - -#include <errno.h> -#include <fcntl.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifndef Py_BUILD_CORE_BUILTIN -# define Py_BUILD_CORE_MODULE 1 -#endif -#include "Python.h" -#include <internal/pycore_debug_offsets.h> // _Py_DebugOffsets -#include <internal/pycore_frame.h> // FRAME_SUSPENDED_YIELD_FROM -#include <internal/pycore_interpframe.h> // FRAME_OWNED_BY_CSTACK -#include <internal/pycore_llist.h> // struct llist_node -#include <internal/pycore_stackref.h> // Py_TAG_BITS -#include "../Python/remote_debug.h" - -#ifndef HAVE_PROCESS_VM_READV -# define HAVE_PROCESS_VM_READV 0 -#endif - -/* ============================================================================ - * TYPE DEFINITIONS AND STRUCTURES - * ============================================================================ */ - -#define GET_MEMBER(type, obj, offset) (*(type*)((char*)(obj) + (offset))) -#define CLEAR_PTR_TAG(ptr) (((uintptr_t)(ptr) & ~Py_TAG_BITS)) -#define GET_MEMBER_NO_TAG(type, obj, offset) (type)(CLEAR_PTR_TAG(*(type*)((char*)(obj) + (offset)))) - -/* Size macros for opaque buffers */ -#define SIZEOF_BYTES_OBJ sizeof(PyBytesObject) -#define SIZEOF_CODE_OBJ sizeof(PyCodeObject) -#define SIZEOF_GEN_OBJ sizeof(PyGenObject) -#define SIZEOF_INTERP_FRAME sizeof(_PyInterpreterFrame) -#define SIZEOF_LLIST_NODE sizeof(struct llist_node) -#define SIZEOF_PAGE_CACHE_ENTRY sizeof(page_cache_entry_t) -#define SIZEOF_PYOBJECT sizeof(PyObject) -#define SIZEOF_SET_OBJ sizeof(PySetObject) -#define SIZEOF_TASK_OBJ 4096 -#define SIZEOF_THREAD_STATE sizeof(PyThreadState) -#define SIZEOF_TYPE_OBJ sizeof(PyTypeObject) -#define SIZEOF_UNICODE_OBJ sizeof(PyUnicodeObject) -#define SIZEOF_LONG_OBJ sizeof(PyLongObject) - -// Calculate the minimum buffer size needed to read interpreter state fields -// We need to read code_object_generation and potentially tlbc_generation -#ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif - -#ifdef Py_GIL_DISABLED -#define INTERP_STATE_MIN_SIZE MAX(MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \ - offsetof(PyInterpreterState, tlbc_indices.tlbc_generation) + sizeof(uint32_t)), \ - offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \ - offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*)) -#else -#define INTERP_STATE_MIN_SIZE MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \ - offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \ - offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*)) -#endif -#define INTERP_STATE_BUFFER_SIZE MAX(INTERP_STATE_MIN_SIZE, 256) - -#define MAX_TLBC_SIZE 2048 - -// Copied from Modules/_asynciomodule.c because it's not exported - -struct _Py_AsyncioModuleDebugOffsets { - struct _asyncio_task_object { - uint64_t size; - uint64_t task_name; - uint64_t task_awaited_by; - uint64_t task_is_task; - uint64_t task_awaited_by_is_set; - uint64_t task_coro; - uint64_t task_node; - } asyncio_task_object; - struct _asyncio_interpreter_state { - uint64_t size; - uint64_t asyncio_tasks_head; - } asyncio_interpreter_state; - struct _asyncio_thread_state { - uint64_t size; - uint64_t asyncio_running_loop; - uint64_t asyncio_running_task; - uint64_t asyncio_tasks_head; - } asyncio_thread_state; -}; - -/* ============================================================================ - * STRUCTSEQ TYPE DEFINITIONS - * ============================================================================ */ - -// TaskInfo structseq type - replaces 4-tuple (task_id, task_name, coroutine_stack, awaited_by) -static PyStructSequence_Field TaskInfo_fields[] = { - {"task_id", "Task ID (memory address)"}, - {"task_name", "Task name"}, - {"coroutine_stack", "Coroutine call stack"}, - {"awaited_by", "Tasks awaiting this task"}, - {NULL} -}; - -static PyStructSequence_Desc TaskInfo_desc = { - "_remote_debugging.TaskInfo", - "Information about an asyncio task", - TaskInfo_fields, - 4 -}; - -// FrameInfo structseq type - replaces 3-tuple (filename, lineno, funcname) -static PyStructSequence_Field FrameInfo_fields[] = { - {"filename", "Source code filename"}, - {"lineno", "Line number"}, - {"funcname", "Function name"}, - {NULL} -}; - -static PyStructSequence_Desc FrameInfo_desc = { - "_remote_debugging.FrameInfo", - "Information about a frame", - FrameInfo_fields, - 3 -}; - -// CoroInfo structseq type - replaces 2-tuple (call_stack, task_name) -static PyStructSequence_Field CoroInfo_fields[] = { - {"call_stack", "Coroutine call stack"}, - {"task_name", "Task name"}, - {NULL} -}; - -static PyStructSequence_Desc CoroInfo_desc = { - "_remote_debugging.CoroInfo", - "Information about a coroutine", - CoroInfo_fields, - 2 -}; - -// ThreadInfo structseq type - replaces 2-tuple (thread_id, frame_info) -static PyStructSequence_Field ThreadInfo_fields[] = { - {"thread_id", "Thread ID"}, - {"frame_info", "Frame information"}, - {NULL} -}; - -static PyStructSequence_Desc ThreadInfo_desc = { - "_remote_debugging.ThreadInfo", - "Information about a thread", - ThreadInfo_fields, - 2 -}; - -// AwaitedInfo structseq type - replaces 2-tuple (tid, awaited_by_list) -static PyStructSequence_Field AwaitedInfo_fields[] = { - {"thread_id", "Thread ID"}, - {"awaited_by", "List of tasks awaited by this thread"}, - {NULL} -}; - -static PyStructSequence_Desc AwaitedInfo_desc = { - "_remote_debugging.AwaitedInfo", - "Information about what a thread is awaiting", - AwaitedInfo_fields, - 2 -}; - -typedef struct { - PyObject *func_name; - PyObject *file_name; - int first_lineno; - PyObject *linetable; // bytes - uintptr_t addr_code_adaptive; -} CachedCodeMetadata; - -typedef struct { - /* Types */ - PyTypeObject *RemoteDebugging_Type; - PyTypeObject *TaskInfo_Type; - PyTypeObject *FrameInfo_Type; - PyTypeObject *CoroInfo_Type; - PyTypeObject *ThreadInfo_Type; - PyTypeObject *AwaitedInfo_Type; -} RemoteDebuggingState; - -typedef struct { - PyObject_HEAD - proc_handle_t handle; - uintptr_t runtime_start_address; - struct _Py_DebugOffsets debug_offsets; - int async_debug_offsets_available; - struct _Py_AsyncioModuleDebugOffsets async_debug_offsets; - uintptr_t interpreter_addr; - uintptr_t tstate_addr; - uint64_t code_object_generation; - _Py_hashtable_t *code_object_cache; - int debug; - int only_active_thread; - RemoteDebuggingState *cached_state; // Cached module state -#ifdef Py_GIL_DISABLED - // TLBC cache invalidation tracking - uint32_t tlbc_generation; // Track TLBC index pool changes - _Py_hashtable_t *tlbc_cache; // Cache of TLBC arrays by code object address -#endif -} RemoteUnwinderObject; - -#define RemoteUnwinder_CAST(op) ((RemoteUnwinderObject *)(op)) - -typedef struct -{ - int lineno; - int end_lineno; - int column; - int end_column; -} LocationInfo; - -typedef struct { - uintptr_t remote_addr; - size_t size; - void *local_copy; -} StackChunkInfo; - -typedef struct { - StackChunkInfo *chunks; - size_t count; -} StackChunkList; - -#include "clinic/_remote_debugging_module.c.h" - -/*[clinic input] -module _remote_debugging -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5f507d5b2e76a7f7]*/ - - -/* ============================================================================ - * FORWARD DECLARATIONS - * ============================================================================ */ - -static inline int -is_frame_valid( - RemoteUnwinderObject *unwinder, - uintptr_t frame_addr, - uintptr_t code_object_addr -); - -typedef int (*thread_processor_func)( - RemoteUnwinderObject *unwinder, - uintptr_t thread_state_addr, - unsigned long tid, - void *context -); - -typedef int (*set_entry_processor_func)( - RemoteUnwinderObject *unwinder, - uintptr_t key_addr, - void *context -); - - -static int -parse_task( - RemoteUnwinderObject *unwinder, - uintptr_t task_address, - PyObject *render_to -); - -static int -parse_coro_chain( - RemoteUnwinderObject *unwinder, - uintptr_t coro_address, - PyObject *render_to -); - -/* Forward declarations for task parsing functions */ -static int parse_frame_object( - RemoteUnwinderObject *unwinder, - PyObject** result, - uintptr_t address, - uintptr_t* address_of_code_object, - uintptr_t* previous_frame -); - -static int -parse_async_frame_chain( - RemoteUnwinderObject *unwinder, - PyObject *calls, - uintptr_t address_of_thread, - uintptr_t running_task_code_obj -); - -static int read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *ptr_addr); -static int read_Py_ssize_t(RemoteUnwinderObject *unwinder, uintptr_t address, Py_ssize_t *size); - -static int process_task_and_waiters(RemoteUnwinderObject *unwinder, uintptr_t task_addr, PyObject *result); -static int process_task_awaited_by(RemoteUnwinderObject *unwinder, uintptr_t task_address, set_entry_processor_func processor, void *context); -static int find_running_task_in_thread(RemoteUnwinderObject *unwinder, uintptr_t thread_state_addr, uintptr_t *running_task_addr); -static int get_task_code_object(RemoteUnwinderObject *unwinder, uintptr_t task_addr, uintptr_t *code_obj_addr); -static int append_awaited_by(RemoteUnwinderObject *unwinder, unsigned long tid, uintptr_t head_addr, PyObject *result); - -/* ============================================================================ - * UTILITY FUNCTIONS AND HELPERS - * ============================================================================ */ - -#define set_exception_cause(unwinder, exc_type, message) \ - if (unwinder->debug) { \ - _set_debug_exception_cause(exc_type, message); \ - } - -static void -cached_code_metadata_destroy(void *ptr) -{ - CachedCodeMetadata *meta = (CachedCodeMetadata *)ptr; - Py_DECREF(meta->func_name); - Py_DECREF(meta->file_name); - Py_DECREF(meta->linetable); - PyMem_RawFree(meta); -} - -static inline RemoteDebuggingState * -RemoteDebugging_GetState(PyObject *module) -{ - void *state = _PyModule_GetState(module); - assert(state != NULL); - return (RemoteDebuggingState *)state; -} - -static inline RemoteDebuggingState * -RemoteDebugging_GetStateFromType(PyTypeObject *type) -{ - PyObject *module = PyType_GetModule(type); - assert(module != NULL); - return RemoteDebugging_GetState(module); -} - -static inline RemoteDebuggingState * -RemoteDebugging_GetStateFromObject(PyObject *obj) -{ - RemoteUnwinderObject *unwinder = (RemoteUnwinderObject *)obj; - if (unwinder->cached_state == NULL) { - unwinder->cached_state = RemoteDebugging_GetStateFromType(Py_TYPE(obj)); - } - return unwinder->cached_state; -} - -static inline int -RemoteDebugging_InitState(RemoteDebuggingState *st) -{ - return 0; -} - -static int -is_prerelease_version(uint64_t version) -{ - return (version & 0xF0) != 0xF0; -} - -static inline int -validate_debug_offsets(struct _Py_DebugOffsets *debug_offsets) -{ - if (memcmp(debug_offsets->cookie, _Py_Debug_Cookie, sizeof(debug_offsets->cookie)) != 0) { - // The remote is probably running a Python version predating debug offsets. - PyErr_SetString( - PyExc_RuntimeError, - "Can't determine the Python version of the remote process"); - return -1; - } - - // Assume debug offsets could change from one pre-release version to another, - // or one minor version to another, but are stable across patch versions. - if (is_prerelease_version(Py_Version) && Py_Version != debug_offsets->version) { - PyErr_SetString( - PyExc_RuntimeError, - "Can't attach from a pre-release Python interpreter" - " to a process running a different Python version"); - return -1; - } - - if (is_prerelease_version(debug_offsets->version) && Py_Version != debug_offsets->version) { - PyErr_SetString( - PyExc_RuntimeError, - "Can't attach to a pre-release Python interpreter" - " from a process running a different Python version"); - return -1; - } - - unsigned int remote_major = (debug_offsets->version >> 24) & 0xFF; - unsigned int remote_minor = (debug_offsets->version >> 16) & 0xFF; - - if (PY_MAJOR_VERSION != remote_major || PY_MINOR_VERSION != remote_minor) { - PyErr_Format( - PyExc_RuntimeError, - "Can't attach from a Python %d.%d process to a Python %d.%d process", - PY_MAJOR_VERSION, PY_MINOR_VERSION, remote_major, remote_minor); - return -1; - } - - // The debug offsets differ between free threaded and non-free threaded builds. - if (_Py_Debug_Free_Threaded && !debug_offsets->free_threaded) { - PyErr_SetString( - PyExc_RuntimeError, - "Cannot attach from a free-threaded Python process" - " to a process running a non-free-threaded version"); - return -1; - } - - if (!_Py_Debug_Free_Threaded && debug_offsets->free_threaded) { - PyErr_SetString( - PyExc_RuntimeError, - "Cannot attach to a free-threaded Python process" - " from a process running a non-free-threaded version"); - return -1; - } - - return 0; -} - -// Generic function to iterate through all threads -static int -iterate_threads( - RemoteUnwinderObject *unwinder, - thread_processor_func processor, - void *context -) { - uintptr_t thread_state_addr; - unsigned long tid = 0; - - if (0 > _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - unwinder->interpreter_addr + unwinder->debug_offsets.interpreter_state.threads_main, - sizeof(void*), - &thread_state_addr)) - { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read main thread state"); - return -1; - } - - while (thread_state_addr != 0) { - if (0 > _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - thread_state_addr + unwinder->debug_offsets.thread_state.native_thread_id, - sizeof(tid), - &tid)) - { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread ID"); - return -1; - } - - // Call the processor function for this thread - if (processor(unwinder, thread_state_addr, tid, context) < 0) { - return -1; - } - - // Move to next thread - if (0 > _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - thread_state_addr + unwinder->debug_offsets.thread_state.next, - sizeof(void*), - &thread_state_addr)) - { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read next thread state"); - return -1; - } - } - - return 0; -} - -// Generic function to iterate through set entries -static int -iterate_set_entries( - RemoteUnwinderObject *unwinder, - uintptr_t set_addr, - set_entry_processor_func processor, - void *context -) { - char set_object[SIZEOF_SET_OBJ]; - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, set_addr, - SIZEOF_SET_OBJ, set_object) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set object"); - return -1; - } - - Py_ssize_t num_els = GET_MEMBER(Py_ssize_t, set_object, unwinder->debug_offsets.set_object.used); - Py_ssize_t set_len = GET_MEMBER(Py_ssize_t, set_object, unwinder->debug_offsets.set_object.mask) + 1; - uintptr_t table_ptr = GET_MEMBER(uintptr_t, set_object, unwinder->debug_offsets.set_object.table); - - Py_ssize_t i = 0; - Py_ssize_t els = 0; - while (i < set_len && els < num_els) { - uintptr_t key_addr; - if (read_py_ptr(unwinder, table_ptr, &key_addr) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set entry key"); - return -1; - } - - if ((void*)key_addr != NULL) { - Py_ssize_t ref_cnt; - if (read_Py_ssize_t(unwinder, table_ptr, &ref_cnt) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set entry ref count"); - return -1; - } - - if (ref_cnt) { - // Process this valid set entry - if (processor(unwinder, key_addr, context) < 0) { - return -1; - } - els++; - } - } - table_ptr += sizeof(void*) * 2; - i++; - } - - return 0; -} - -// Processor function for task waiters -static int -process_waiter_task( - RemoteUnwinderObject *unwinder, - uintptr_t key_addr, - void *context -) { - PyObject *result = (PyObject *)context; - return process_task_and_waiters(unwinder, key_addr, result); -} - -// Processor function for parsing tasks in sets -static int -process_task_parser( - RemoteUnwinderObject *unwinder, - uintptr_t key_addr, - void *context -) { - PyObject *awaited_by = (PyObject *)context; - return parse_task(unwinder, key_addr, awaited_by); -} - -/* ============================================================================ - * MEMORY READING FUNCTIONS - * ============================================================================ */ - -#define DEFINE_MEMORY_READER(type_name, c_type, error_msg) \ -static inline int \ -read_##type_name(RemoteUnwinderObject *unwinder, uintptr_t address, c_type *result) \ -{ \ - int res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address, sizeof(c_type), result); \ - if (res < 0) { \ - set_exception_cause(unwinder, PyExc_RuntimeError, error_msg); \ - return -1; \ - } \ - return 0; \ -} - -DEFINE_MEMORY_READER(ptr, uintptr_t, "Failed to read pointer from remote memory") -DEFINE_MEMORY_READER(Py_ssize_t, Py_ssize_t, "Failed to read Py_ssize_t from remote memory") -DEFINE_MEMORY_READER(char, char, "Failed to read char from remote memory") - -static int -read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t *ptr_addr) -{ - if (read_ptr(unwinder, address, ptr_addr)) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read Python pointer"); - return -1; - } - *ptr_addr &= ~Py_TAG_BITS; - return 0; -} - -/* ============================================================================ - * PYTHON OBJECT READING FUNCTIONS - * ============================================================================ */ - -static PyObject * -read_py_str( - RemoteUnwinderObject *unwinder, - uintptr_t address, - Py_ssize_t max_len -) { - PyObject *result = NULL; - char *buf = NULL; - - // Read the entire PyUnicodeObject at once - char unicode_obj[SIZEOF_UNICODE_OBJ]; - int res = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address, - SIZEOF_UNICODE_OBJ, - unicode_obj - ); - if (res < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyUnicodeObject"); - goto err; - } - - Py_ssize_t len = GET_MEMBER(Py_ssize_t, unicode_obj, unwinder->debug_offsets.unicode_object.length); - if (len < 0 || len > max_len) { - PyErr_Format(PyExc_RuntimeError, - "Invalid string length (%zd) at 0x%lx", len, address); - set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid string length in remote Unicode object"); - return NULL; - } - - buf = (char *)PyMem_RawMalloc(len+1); - if (buf == NULL) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate buffer for string reading"); - return NULL; - } - - size_t offset = unwinder->debug_offsets.unicode_object.asciiobject_size; - res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address + offset, len, buf); - if (res < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read string data from remote memory"); - goto err; - } - buf[len] = '\0'; - - result = PyUnicode_FromStringAndSize(buf, len); - if (result == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create PyUnicode from remote string data"); - goto err; - } - - PyMem_RawFree(buf); - assert(result != NULL); - return result; - -err: - if (buf != NULL) { - PyMem_RawFree(buf); - } - return NULL; -} - -static PyObject * -read_py_bytes( - RemoteUnwinderObject *unwinder, - uintptr_t address, - Py_ssize_t max_len -) { - PyObject *result = NULL; - char *buf = NULL; - - // Read the entire PyBytesObject at once - char bytes_obj[SIZEOF_BYTES_OBJ]; - int res = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address, - SIZEOF_BYTES_OBJ, - bytes_obj - ); - if (res < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyBytesObject"); - goto err; - } - - Py_ssize_t len = GET_MEMBER(Py_ssize_t, bytes_obj, unwinder->debug_offsets.bytes_object.ob_size); - if (len < 0 || len > max_len) { - PyErr_Format(PyExc_RuntimeError, - "Invalid bytes length (%zd) at 0x%lx", len, address); - set_exception_cause(unwinder, PyExc_RuntimeError, "Invalid bytes length in remote bytes object"); - return NULL; - } - - buf = (char *)PyMem_RawMalloc(len+1); - if (buf == NULL) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate buffer for bytes reading"); - return NULL; - } - - size_t offset = unwinder->debug_offsets.bytes_object.ob_sval; - res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, address + offset, len, buf); - if (res < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read bytes data from remote memory"); - goto err; - } - buf[len] = '\0'; - - result = PyBytes_FromStringAndSize(buf, len); - if (result == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create PyBytes from remote bytes data"); - goto err; - } - - PyMem_RawFree(buf); - assert(result != NULL); - return result; - -err: - if (buf != NULL) { - PyMem_RawFree(buf); - } - return NULL; -} - -static long -read_py_long( - RemoteUnwinderObject *unwinder, - uintptr_t address -) -{ - unsigned int shift = PYLONG_BITS_IN_DIGIT; - - // Read the entire PyLongObject at once - char long_obj[SIZEOF_LONG_OBJ]; - int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address, - unwinder->debug_offsets.long_object.size, - long_obj); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyLongObject"); - return -1; - } - - uintptr_t lv_tag = GET_MEMBER(uintptr_t, long_obj, unwinder->debug_offsets.long_object.lv_tag); - int negative = (lv_tag & 3) == 2; - Py_ssize_t size = lv_tag >> 3; - - if (size == 0) { - return 0; - } - - // If the long object has inline digits, use them directly - digit *digits; - if (size <= _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS) { - // For small integers, digits are inline in the long_value.ob_digit array - digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); - if (!digits) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for small PyLong"); - return -1; - } - memcpy(digits, long_obj + unwinder->debug_offsets.long_object.ob_digit, size * sizeof(digit)); - } else { - // For larger integers, we need to read the digits separately - digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); - if (!digits) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate digits for large PyLong"); - return -1; - } - - bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address + unwinder->debug_offsets.long_object.ob_digit, - sizeof(digit) * size, - digits - ); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read PyLong digits from remote memory"); - goto error; - } - } - - long long value = 0; - - // In theory this can overflow, but because of llvm/llvm-project#16778 - // we can't use __builtin_mul_overflow because it fails to link with - // __muloti4 on aarch64. In practice this is fine because all we're - // testing here are task numbers that would fit in a single byte. - for (Py_ssize_t i = 0; i < size; ++i) { - long long factor = digits[i] * (1UL << (Py_ssize_t)(shift * i)); - value += factor; - } - PyMem_RawFree(digits); - if (negative) { - value *= -1; - } - return (long)value; -error: - PyMem_RawFree(digits); - return -1; -} - -/* ============================================================================ - * ASYNCIO DEBUG FUNCTIONS - * ============================================================================ */ - -// Get the PyAsyncioDebug section address for any platform -static uintptr_t -_Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle) -{ - uintptr_t address; - -#ifdef MS_WINDOWS - // On Windows, search for asyncio debug in executable or DLL - address = search_windows_map_for_section(handle, "AsyncioD", L"_asyncio"); - if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); - _PyErr_ChainExceptions1(exc); - } -#elif defined(__linux__) - // On Linux, search for asyncio debug in executable or DLL - address = search_linux_map_for_section(handle, "AsyncioDebug", "python"); - if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); - _PyErr_ChainExceptions1(exc); - } -#elif defined(__APPLE__) && TARGET_OS_OSX - // On macOS, try libpython first, then fall back to python - address = search_map_for_section(handle, "AsyncioDebug", "libpython"); - if (address == 0) { - PyErr_Clear(); - address = search_map_for_section(handle, "AsyncioDebug", "python"); - } - if (address == 0) { - // Error out: 'python' substring covers both executable and DLL - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetString(PyExc_RuntimeError, "Failed to find the AsyncioDebug section in the process."); - _PyErr_ChainExceptions1(exc); - } -#else - Py_UNREACHABLE(); -#endif - - return address; -} - -static int -read_async_debug( - RemoteUnwinderObject *unwinder -) { - uintptr_t async_debug_addr = _Py_RemoteDebug_GetAsyncioDebugAddress(&unwinder->handle); - if (!async_debug_addr) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to get AsyncioDebug address"); - return -1; - } - - size_t size = sizeof(struct _Py_AsyncioModuleDebugOffsets); - int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, async_debug_addr, size, &unwinder->async_debug_offsets); - if (result < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read AsyncioDebug offsets"); - } - return result; -} - -/* ============================================================================ - * ASYNCIO TASK PARSING FUNCTIONS - * ============================================================================ */ - -static PyObject * -parse_task_name( - RemoteUnwinderObject *unwinder, - uintptr_t task_address -) { - // Read the entire TaskObj at once - char task_obj[SIZEOF_TASK_OBJ]; - int err = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - task_address, - unwinder->async_debug_offsets.asyncio_task_object.size, - task_obj); - if (err < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object"); - return NULL; - } - - uintptr_t task_name_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_name); - - // The task name can be a long or a string so we need to check the type - char task_name_obj[SIZEOF_PYOBJECT]; - err = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - task_name_addr, - SIZEOF_PYOBJECT, - task_name_obj); - if (err < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task name object"); - return NULL; - } - - // Now read the type object to get the flags - char type_obj[SIZEOF_TYPE_OBJ]; - err = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - GET_MEMBER(uintptr_t, task_name_obj, unwinder->debug_offsets.pyobject.ob_type), - SIZEOF_TYPE_OBJ, - type_obj); - if (err < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task name type object"); - return NULL; - } - - if ((GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_LONG_SUBCLASS)) { - long res = read_py_long(unwinder, task_name_addr); - if (res == -1) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Task name PyLong parsing failed"); - return NULL; - } - return PyUnicode_FromFormat("Task-%d", res); - } - - if(!(GET_MEMBER(unsigned long, type_obj, unwinder->debug_offsets.type_object.tp_flags) & Py_TPFLAGS_UNICODE_SUBCLASS)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid task name object"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Task name object is neither long nor unicode"); - return NULL; - } - - return read_py_str( - unwinder, - task_name_addr, - 255 - ); -} - -static int parse_task_awaited_by( - RemoteUnwinderObject *unwinder, - uintptr_t task_address, - PyObject *awaited_by -) { - return process_task_awaited_by(unwinder, task_address, process_task_parser, awaited_by); -} - -static int -handle_yield_from_frame( - RemoteUnwinderObject *unwinder, - uintptr_t gi_iframe_addr, - uintptr_t gen_type_addr, - PyObject *render_to -) { - // Read the entire interpreter frame at once - char iframe[SIZEOF_INTERP_FRAME]; - int err = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - gi_iframe_addr, - SIZEOF_INTERP_FRAME, - iframe); - if (err < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame in yield_from handler"); - return -1; - } - - if (GET_MEMBER(char, iframe, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR) { - PyErr_SetString( - PyExc_RuntimeError, - "generator doesn't own its frame \\_o_/"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Frame ownership mismatch in yield_from"); - return -1; - } - - uintptr_t stackpointer_addr = GET_MEMBER_NO_TAG(uintptr_t, iframe, unwinder->debug_offsets.interpreter_frame.stackpointer); - - if ((void*)stackpointer_addr != NULL) { - uintptr_t gi_await_addr; - err = read_py_ptr( - unwinder, - stackpointer_addr - sizeof(void*), - &gi_await_addr); - if (err) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read gi_await address"); - return -1; - } - - if ((void*)gi_await_addr != NULL) { - uintptr_t gi_await_addr_type_addr; - err = read_ptr( - unwinder, - gi_await_addr + unwinder->debug_offsets.pyobject.ob_type, - &gi_await_addr_type_addr); - if (err) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read gi_await type address"); - return -1; - } - - if (gen_type_addr == gi_await_addr_type_addr) { - /* This needs an explanation. We always start with parsing - native coroutine / generator frames. Ultimately they - are awaiting on something. That something can be - a native coroutine frame or... an iterator. - If it's the latter -- we can't continue building - our chain. So the condition to bail out of this is - to do that when the type of the current coroutine - doesn't match the type of whatever it points to - in its cr_await. - */ - err = parse_coro_chain(unwinder, gi_await_addr, render_to); - if (err) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain in yield_from"); - return -1; - } - } - } - } - - return 0; -} - -static int -parse_coro_chain( - RemoteUnwinderObject *unwinder, - uintptr_t coro_address, - PyObject *render_to -) { - assert((void*)coro_address != NULL); - - // Read the entire generator object at once - char gen_object[SIZEOF_GEN_OBJ]; - int err = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - coro_address, - SIZEOF_GEN_OBJ, - gen_object); - if (err < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read generator object in coro chain"); - return -1; - } - - int8_t frame_state = GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state); - if (frame_state == FRAME_CLEARED) { - return 0; - } - - uintptr_t gen_type_addr = GET_MEMBER(uintptr_t, gen_object, unwinder->debug_offsets.pyobject.ob_type); - - PyObject* name = NULL; - - // Parse the previous frame using the gi_iframe from local copy - uintptr_t prev_frame; - uintptr_t gi_iframe_addr = coro_address + unwinder->debug_offsets.gen_object.gi_iframe; - uintptr_t address_of_code_object = 0; - if (parse_frame_object(unwinder, &name, gi_iframe_addr, &address_of_code_object, &prev_frame) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in coro chain"); - return -1; - } - - if (!name) { - return 0; - } - - if (PyList_Append(render_to, name)) { - Py_DECREF(name); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to coro chain"); - return -1; - } - Py_DECREF(name); - - if (frame_state == FRAME_SUSPENDED_YIELD_FROM) { - return handle_yield_from_frame(unwinder, gi_iframe_addr, gen_type_addr, render_to); - } - - return 0; -} - -static PyObject* -create_task_result( - RemoteUnwinderObject *unwinder, - uintptr_t task_address -) { - PyObject* result = NULL; - PyObject *call_stack = NULL; - PyObject *tn = NULL; - char task_obj[SIZEOF_TASK_OBJ]; - uintptr_t coro_addr; - - // Create call_stack first since it's the first tuple element - call_stack = PyList_New(0); - if (call_stack == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create call stack list"); - goto error; - } - - // Create task name/address for second tuple element - tn = PyLong_FromUnsignedLongLong(task_address); - if (tn == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name/address"); - goto error; - } - - // Parse coroutine chain - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address, - unwinder->async_debug_offsets.asyncio_task_object.size, - task_obj) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object for coro chain"); - goto error; - } - - coro_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_coro); - - if ((void*)coro_addr != NULL) { - if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain"); - goto error; - } - - if (PyList_Reverse(call_stack)) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reverse call stack"); - goto error; - } - } - - // Create final CoroInfo result - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - result = PyStructSequence_New(state->CoroInfo_Type); - if (result == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create CoroInfo"); - goto error; - } - - // PyStructSequence_SetItem steals references, so we don't need to DECREF on success - PyStructSequence_SetItem(result, 0, call_stack); // This steals the reference - PyStructSequence_SetItem(result, 1, tn); // This steals the reference - - return result; - -error: - Py_XDECREF(result); - Py_XDECREF(call_stack); - Py_XDECREF(tn); - return NULL; -} - -static int -parse_task( - RemoteUnwinderObject *unwinder, - uintptr_t task_address, - PyObject *render_to -) { - char is_task; - PyObject* result = NULL; - int err; - - err = read_char( - unwinder, - task_address + unwinder->async_debug_offsets.asyncio_task_object.task_is_task, - &is_task); - if (err) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read is_task flag"); - goto error; - } - - if (is_task) { - result = create_task_result(unwinder, task_address); - if (!result) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task result"); - goto error; - } - } else { - // Create an empty CoroInfo for non-task objects - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - result = PyStructSequence_New(state->CoroInfo_Type); - if (result == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty CoroInfo"); - goto error; - } - PyObject *empty_list = PyList_New(0); - if (empty_list == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty list"); - goto error; - } - PyObject *task_name = PyLong_FromUnsignedLongLong(task_address); - if (task_name == NULL) { - Py_DECREF(empty_list); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name"); - goto error; - } - PyStructSequence_SetItem(result, 0, empty_list); // This steals the reference - PyStructSequence_SetItem(result, 1, task_name); // This steals the reference - } - if (PyList_Append(render_to, result)) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task result to render list"); - goto error; - } - - Py_DECREF(result); - return 0; - -error: - Py_XDECREF(result); - return -1; -} - -static int -process_single_task_node( - RemoteUnwinderObject *unwinder, - uintptr_t task_addr, - PyObject **task_info, - PyObject *result -) { - PyObject *tn = NULL; - PyObject *current_awaited_by = NULL; - PyObject *task_id = NULL; - PyObject *result_item = NULL; - PyObject *coroutine_stack = NULL; - - tn = parse_task_name(unwinder, task_addr); - if (tn == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task name in single task node"); - goto error; - } - - current_awaited_by = PyList_New(0); - if (current_awaited_by == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by list in single task node"); - goto error; - } - - // Extract the coroutine stack for this task - coroutine_stack = PyList_New(0); - if (coroutine_stack == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coroutine stack list in single task node"); - goto error; - } - - if (parse_task(unwinder, task_addr, coroutine_stack) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task coroutine stack in single task node"); - goto error; - } - - task_id = PyLong_FromUnsignedLongLong(task_addr); - if (task_id == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task ID in single task node"); - goto error; - } - - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - result_item = PyStructSequence_New(state->TaskInfo_Type); - if (result_item == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create TaskInfo in single task node"); - goto error; - } - - PyStructSequence_SetItem(result_item, 0, task_id); // steals ref - PyStructSequence_SetItem(result_item, 1, tn); // steals ref - PyStructSequence_SetItem(result_item, 2, coroutine_stack); // steals ref - PyStructSequence_SetItem(result_item, 3, current_awaited_by); // steals ref - - // References transferred to tuple - task_id = NULL; - tn = NULL; - coroutine_stack = NULL; - current_awaited_by = NULL; - - if (PyList_Append(result, result_item)) { - Py_DECREF(result_item); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append result item in single task node"); - return -1; - } - if (task_info != NULL) { - *task_info = result_item; - } - Py_DECREF(result_item); - - // Get back current_awaited_by reference for parse_task_awaited_by - current_awaited_by = PyStructSequence_GetItem(result_item, 3); - if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse awaited_by in single task node"); - // No cleanup needed here since all references were transferred to result_item - // and result_item was already added to result list and decreffed - return -1; - } - - return 0; - -error: - Py_XDECREF(tn); - Py_XDECREF(current_awaited_by); - Py_XDECREF(task_id); - Py_XDECREF(result_item); - Py_XDECREF(coroutine_stack); - return -1; -} - -// Thread processor for get_all_awaited_by -static int -process_thread_for_awaited_by( - RemoteUnwinderObject *unwinder, - uintptr_t thread_state_addr, - unsigned long tid, - void *context -) { - PyObject *result = (PyObject *)context; - uintptr_t head_addr = thread_state_addr + unwinder->async_debug_offsets.asyncio_thread_state.asyncio_tasks_head; - return append_awaited_by(unwinder, tid, head_addr, result); -} - -// Generic function to process task awaited_by -static int -process_task_awaited_by( - RemoteUnwinderObject *unwinder, - uintptr_t task_address, - set_entry_processor_func processor, - void *context -) { - // Read the entire TaskObj at once - char task_obj[SIZEOF_TASK_OBJ]; - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address, - unwinder->async_debug_offsets.asyncio_task_object.size, - task_obj) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task object"); - return -1; - } - - uintptr_t task_ab_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by); - if ((void*)task_ab_addr == NULL) { - return 0; // No tasks waiting for this one - } - - char awaited_by_is_a_set = GET_MEMBER(char, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by_is_set); - - if (awaited_by_is_a_set) { - return iterate_set_entries(unwinder, task_ab_addr, processor, context); - } else { - // Single task waiting - return processor(unwinder, task_ab_addr, context); - } -} - -static int -process_running_task_chain( - RemoteUnwinderObject *unwinder, - uintptr_t running_task_addr, - uintptr_t thread_state_addr, - PyObject *result -) { - uintptr_t running_task_code_obj = 0; - if(get_task_code_object(unwinder, running_task_addr, &running_task_code_obj) < 0) { - return -1; - } - - // First, add this task to the result - PyObject *task_info = NULL; - if (process_single_task_node(unwinder, running_task_addr, &task_info, result) < 0) { - return -1; - } - - // Get the chain from the current frame to this task - PyObject *coro_chain = PyStructSequence_GET_ITEM(task_info, 2); - assert(coro_chain != NULL); - if (PyList_GET_SIZE(coro_chain) != 1) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Coro chain is not a single item"); - return -1; - } - PyObject *coro_info = PyList_GET_ITEM(coro_chain, 0); - assert(coro_info != NULL); - PyObject *frame_chain = PyStructSequence_GET_ITEM(coro_info, 0); - assert(frame_chain != NULL); - - // Clear the coro_chain - if (PyList_Clear(frame_chain) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to clear coroutine chain"); - return -1; - } - - // Add the chain from the current frame to this task - if (parse_async_frame_chain(unwinder, frame_chain, thread_state_addr, running_task_code_obj) < 0) { - return -1; - } - - // Now find all tasks that are waiting for this task and process them - if (process_task_awaited_by(unwinder, running_task_addr, process_waiter_task, result) < 0) { - return -1; - } - - return 0; -} - -// Thread processor for get_async_stack_trace -static int -process_thread_for_async_stack_trace( - RemoteUnwinderObject *unwinder, - uintptr_t thread_state_addr, - unsigned long tid, - void *context -) { - PyObject *result = (PyObject *)context; - - // Find running task in this thread - uintptr_t running_task_addr; - if (find_running_task_in_thread(unwinder, thread_state_addr, &running_task_addr) < 0) { - return 0; - } - - // If we found a running task, process it and its waiters - if ((void*)running_task_addr != NULL) { - PyObject *task_list = PyList_New(0); - if (task_list == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create task list for thread"); - return -1; - } - - if (process_running_task_chain(unwinder, running_task_addr, thread_state_addr, task_list) < 0) { - Py_DECREF(task_list); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process running task chain"); - return -1; - } - - // Create AwaitedInfo structure for this thread - PyObject *tid_py = PyLong_FromUnsignedLong(tid); - if (tid_py == NULL) { - Py_DECREF(task_list); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID"); - return -1; - } - - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - PyObject *awaited_info = PyStructSequence_New(state->AwaitedInfo_Type); - if (awaited_info == NULL) { - Py_DECREF(tid_py); - Py_DECREF(task_list); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo"); - return -1; - } - - PyStructSequence_SetItem(awaited_info, 0, tid_py); // steals ref - PyStructSequence_SetItem(awaited_info, 1, task_list); // steals ref - - if (PyList_Append(result, awaited_info)) { - Py_DECREF(awaited_info); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append AwaitedInfo to result"); - return -1; - } - Py_DECREF(awaited_info); - } - - return 0; -} - -static int -process_task_and_waiters( - RemoteUnwinderObject *unwinder, - uintptr_t task_addr, - PyObject *result -) { - // First, add this task to the result - if (process_single_task_node(unwinder, task_addr, NULL, result) < 0) { - return -1; - } - - // Now find all tasks that are waiting for this task and process them - return process_task_awaited_by(unwinder, task_addr, process_waiter_task, result); -} - -static int -find_running_task_in_thread( - RemoteUnwinderObject *unwinder, - uintptr_t thread_state_addr, - uintptr_t *running_task_addr -) { - *running_task_addr = (uintptr_t)NULL; - - uintptr_t address_of_running_loop; - int bytes_read = read_py_ptr( - unwinder, - thread_state_addr + unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_loop, - &address_of_running_loop); - if (bytes_read == -1) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running loop address"); - return -1; - } - - // no asyncio loop is now running - if ((void*)address_of_running_loop == NULL) { - return 0; - } - - int err = read_ptr( - unwinder, - thread_state_addr + unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_task, - running_task_addr); - if (err) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running task address"); - return -1; - } - - return 0; -} - -static int -get_task_code_object(RemoteUnwinderObject *unwinder, uintptr_t task_addr, uintptr_t *code_obj_addr) { - uintptr_t running_coro_addr = 0; - - if(read_py_ptr( - unwinder, - task_addr + unwinder->async_debug_offsets.asyncio_task_object.task_coro, - &running_coro_addr) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro read failed"); - return -1; - } - - if (running_coro_addr == 0) { - PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro address is NULL"); - return -1; - } - - // note: genobject's gi_iframe is an embedded struct so the address to - // the offset leads directly to its first field: f_executable - if (read_py_ptr( - unwinder, - running_coro_addr + unwinder->debug_offsets.gen_object.gi_iframe, code_obj_addr) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read running task code object"); - return -1; - } - - if (*code_obj_addr == 0) { - PyErr_SetString(PyExc_RuntimeError, "Running task code object is NULL"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Running task code object address is NULL"); - return -1; - } - - return 0; -} - -/* ============================================================================ - * TLBC CACHING FUNCTIONS - * ============================================================================ */ - -#ifdef Py_GIL_DISABLED - -typedef struct { - void *tlbc_array; // Local copy of the TLBC array - Py_ssize_t tlbc_array_size; // Size of the TLBC array - uint32_t generation; // Generation when this was cached -} TLBCCacheEntry; - -static void -tlbc_cache_entry_destroy(void *ptr) -{ - TLBCCacheEntry *entry = (TLBCCacheEntry *)ptr; - if (entry->tlbc_array) { - PyMem_RawFree(entry->tlbc_array); - } - PyMem_RawFree(entry); -} - -static TLBCCacheEntry * -get_tlbc_cache_entry(RemoteUnwinderObject *self, uintptr_t code_addr, uint32_t current_generation) -{ - void *key = (void *)code_addr; - TLBCCacheEntry *entry = _Py_hashtable_get(self->tlbc_cache, key); - - if (entry && entry->generation != current_generation) { - // Entry is stale, remove it by setting to NULL - _Py_hashtable_set(self->tlbc_cache, key, NULL); - entry = NULL; - } - - return entry; -} - -static int -cache_tlbc_array(RemoteUnwinderObject *unwinder, uintptr_t code_addr, uintptr_t tlbc_array_addr, uint32_t generation) -{ - uintptr_t tlbc_array_ptr; - void *tlbc_array = NULL; - TLBCCacheEntry *entry = NULL; - - // Read the TLBC array pointer - if (read_ptr(unwinder, tlbc_array_addr, &tlbc_array_ptr) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to read TLBC array pointer"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array pointer"); - return 0; // Read error - } - - // Validate TLBC array pointer - if (tlbc_array_ptr == 0) { - PyErr_SetString(PyExc_RuntimeError, "TLBC array pointer is NULL"); - return 0; // No TLBC array - } - - // Read the TLBC array size - Py_ssize_t tlbc_size; - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(tlbc_size), &tlbc_size) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to read TLBC array size"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array size"); - return 0; // Read error - } - - // Validate TLBC array size - if (tlbc_size <= 0) { - PyErr_SetString(PyExc_RuntimeError, "Invalid TLBC array size"); - return 0; // Invalid size - } - - if (tlbc_size > MAX_TLBC_SIZE) { - PyErr_SetString(PyExc_RuntimeError, "TLBC array size exceeds maximum limit"); - return 0; // Invalid size - } - - // Allocate and read the entire TLBC array - size_t array_data_size = tlbc_size * sizeof(void*); - tlbc_array = PyMem_RawMalloc(sizeof(Py_ssize_t) + array_data_size); - if (!tlbc_array) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate TLBC array"); - return 0; // Memory error - } - - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, tlbc_array_ptr, sizeof(Py_ssize_t) + array_data_size, tlbc_array) != 0) { - PyMem_RawFree(tlbc_array); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read TLBC array data"); - return 0; // Read error - } - - // Create cache entry - entry = PyMem_RawMalloc(sizeof(TLBCCacheEntry)); - if (!entry) { - PyErr_NoMemory(); - PyMem_RawFree(tlbc_array); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate TLBC cache entry"); - return 0; // Memory error - } - - entry->tlbc_array = tlbc_array; - entry->tlbc_array_size = tlbc_size; - entry->generation = generation; - - // Store in cache - void *key = (void *)code_addr; - if (_Py_hashtable_set(unwinder->tlbc_cache, key, entry) < 0) { - tlbc_cache_entry_destroy(entry); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to store TLBC entry in cache"); - return 0; // Cache error - } - - return 1; // Success -} - - - -#endif - -/* ============================================================================ - * LINE TABLE PARSING FUNCTIONS - * ============================================================================ */ - -static int -scan_varint(const uint8_t **ptr) -{ - unsigned int read = **ptr; - *ptr = *ptr + 1; - unsigned int val = read & 63; - unsigned int shift = 0; - while (read & 64) { - read = **ptr; - *ptr = *ptr + 1; - shift += 6; - val |= (read & 63) << shift; - } - return val; -} - -static int -scan_signed_varint(const uint8_t **ptr) -{ - unsigned int uval = scan_varint(ptr); - if (uval & 1) { - return -(int)(uval >> 1); - } - else { - return uval >> 1; - } -} - -static bool -parse_linetable(const uintptr_t addrq, const char* linetable, int firstlineno, LocationInfo* info) -{ - const uint8_t* ptr = (const uint8_t*)(linetable); - uint64_t addr = 0; - info->lineno = firstlineno; - - while (*ptr != '\0') { - // See InternalDocs/code_objects.md for where these magic numbers are from - // and for the decoding algorithm. - uint8_t first_byte = *(ptr++); - uint8_t code = (first_byte >> 3) & 15; - size_t length = (first_byte & 7) + 1; - uintptr_t end_addr = addr + length; - switch (code) { - case PY_CODE_LOCATION_INFO_NONE: { - break; - } - case PY_CODE_LOCATION_INFO_LONG: { - int line_delta = scan_signed_varint(&ptr); - info->lineno += line_delta; - info->end_lineno = info->lineno + scan_varint(&ptr); - info->column = scan_varint(&ptr) - 1; - info->end_column = scan_varint(&ptr) - 1; - break; - } - case PY_CODE_LOCATION_INFO_NO_COLUMNS: { - int line_delta = scan_signed_varint(&ptr); - info->lineno += line_delta; - info->column = info->end_column = -1; - break; - } - case PY_CODE_LOCATION_INFO_ONE_LINE0: - case PY_CODE_LOCATION_INFO_ONE_LINE1: - case PY_CODE_LOCATION_INFO_ONE_LINE2: { - int line_delta = code - 10; - info->lineno += line_delta; - info->end_lineno = info->lineno; - info->column = *(ptr++); - info->end_column = *(ptr++); - break; - } - default: { - uint8_t second_byte = *(ptr++); - if ((second_byte & 128) != 0) { - return false; - } - info->column = code << 3 | (second_byte >> 4); - info->end_column = info->column + (second_byte & 15); - break; - } - } - if (addr <= addrq && end_addr > addrq) { - return true; - } - addr = end_addr; - } - return false; -} - -/* ============================================================================ - * CODE OBJECT AND FRAME PARSING FUNCTIONS - * ============================================================================ */ - -static int -parse_code_object(RemoteUnwinderObject *unwinder, - PyObject **result, - uintptr_t address, - uintptr_t instruction_pointer, - uintptr_t *previous_frame, - int32_t tlbc_index) -{ - void *key = (void *)address; - CachedCodeMetadata *meta = NULL; - PyObject *func = NULL; - PyObject *file = NULL; - PyObject *linetable = NULL; - PyObject *lineno = NULL; - PyObject *tuple = NULL; - -#ifdef Py_GIL_DISABLED - // In free threading builds, code object addresses might have the low bit set - // as a flag, so we need to mask it off to get the real address - uintptr_t real_address = address & (~1); -#else - uintptr_t real_address = address; -#endif - - if (unwinder && unwinder->code_object_cache != NULL) { - meta = _Py_hashtable_get(unwinder->code_object_cache, key); - } - - if (meta == NULL) { - char code_object[SIZEOF_CODE_OBJ]; - if (_Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, real_address, SIZEOF_CODE_OBJ, code_object) < 0) - { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read code object"); - goto error; - } - - func = read_py_str(unwinder, - GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.qualname), 1024); - if (!func) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read function name from code object"); - goto error; - } - - file = read_py_str(unwinder, - GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.filename), 1024); - if (!file) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read filename from code object"); - goto error; - } - - linetable = read_py_bytes(unwinder, - GET_MEMBER(uintptr_t, code_object, unwinder->debug_offsets.code_object.linetable), 4096); - if (!linetable) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read linetable from code object"); - goto error; - } - - meta = PyMem_RawMalloc(sizeof(CachedCodeMetadata)); - if (!meta) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate cached code metadata"); - goto error; - } - - meta->func_name = func; - meta->file_name = file; - meta->linetable = linetable; - meta->first_lineno = GET_MEMBER(int, code_object, unwinder->debug_offsets.code_object.firstlineno); - meta->addr_code_adaptive = real_address + unwinder->debug_offsets.code_object.co_code_adaptive; - - if (unwinder && unwinder->code_object_cache && _Py_hashtable_set(unwinder->code_object_cache, key, meta) < 0) { - cached_code_metadata_destroy(meta); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to cache code metadata"); - goto error; - } - - // Ownership transferred to meta - func = NULL; - file = NULL; - linetable = NULL; - } - - uintptr_t ip = instruction_pointer; - ptrdiff_t addrq; - -#ifdef Py_GIL_DISABLED - // Handle thread-local bytecode (TLBC) in free threading builds - if (tlbc_index == 0 || unwinder->debug_offsets.code_object.co_tlbc == 0 || unwinder == NULL) { - // No TLBC or no unwinder - use main bytecode directly - addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; - goto done_tlbc; - } - - // Try to get TLBC data from cache (we'll get generation from the caller) - TLBCCacheEntry *tlbc_entry = get_tlbc_cache_entry(unwinder, real_address, unwinder->tlbc_generation); - - if (!tlbc_entry) { - // Cache miss - try to read and cache TLBC array - if (!cache_tlbc_array(unwinder, real_address, real_address + unwinder->debug_offsets.code_object.co_tlbc, unwinder->tlbc_generation)) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to cache TLBC array"); - goto error; - } - tlbc_entry = get_tlbc_cache_entry(unwinder, real_address, unwinder->tlbc_generation); - } - - if (tlbc_entry && tlbc_index < tlbc_entry->tlbc_array_size) { - // Use cached TLBC data - uintptr_t *entries = (uintptr_t *)((char *)tlbc_entry->tlbc_array + sizeof(Py_ssize_t)); - uintptr_t tlbc_bytecode_addr = entries[tlbc_index]; - - if (tlbc_bytecode_addr != 0) { - // Calculate offset from TLBC bytecode - addrq = (uint16_t *)ip - (uint16_t *)tlbc_bytecode_addr; - goto done_tlbc; - } - } - - // Fall back to main bytecode - addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; - -done_tlbc: -#else - // Non-free-threaded build, always use the main bytecode - (void)tlbc_index; // Suppress unused parameter warning - (void)unwinder; // Suppress unused parameter warning - addrq = (uint16_t *)ip - (uint16_t *)meta->addr_code_adaptive; -#endif - ; // Empty statement to avoid C23 extension warning - LocationInfo info = {0}; - bool ok = parse_linetable(addrq, PyBytes_AS_STRING(meta->linetable), - meta->first_lineno, &info); - if (!ok) { - info.lineno = -1; - } - - lineno = PyLong_FromLong(info.lineno); - if (!lineno) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create line number object"); - goto error; - } - - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - tuple = PyStructSequence_New(state->FrameInfo_Type); - if (!tuple) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create FrameInfo for code object"); - goto error; - } - - Py_INCREF(meta->func_name); - Py_INCREF(meta->file_name); - PyStructSequence_SetItem(tuple, 0, meta->file_name); - PyStructSequence_SetItem(tuple, 1, lineno); - PyStructSequence_SetItem(tuple, 2, meta->func_name); - - *result = tuple; - return 0; - -error: - Py_XDECREF(func); - Py_XDECREF(file); - Py_XDECREF(linetable); - Py_XDECREF(lineno); - Py_XDECREF(tuple); - return -1; -} - -/* ============================================================================ - * STACK CHUNK MANAGEMENT FUNCTIONS - * ============================================================================ */ - -static void -cleanup_stack_chunks(StackChunkList *chunks) -{ - for (size_t i = 0; i < chunks->count; ++i) { - PyMem_RawFree(chunks->chunks[i].local_copy); - } - PyMem_RawFree(chunks->chunks); -} - -static int -process_single_stack_chunk( - RemoteUnwinderObject *unwinder, - uintptr_t chunk_addr, - StackChunkInfo *chunk_info -) { - // Start with default size assumption - size_t current_size = _PY_DATA_STACK_CHUNK_SIZE; - - char *this_chunk = PyMem_RawMalloc(current_size); - if (!this_chunk) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate stack chunk buffer"); - return -1; - } - - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, current_size, this_chunk) < 0) { - PyMem_RawFree(this_chunk); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read stack chunk"); - return -1; - } - - // Check actual size and reread if necessary - size_t actual_size = GET_MEMBER(size_t, this_chunk, offsetof(_PyStackChunk, size)); - if (actual_size != current_size) { - this_chunk = PyMem_RawRealloc(this_chunk, actual_size); - if (!this_chunk) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to reallocate stack chunk buffer"); - return -1; - } - - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, chunk_addr, actual_size, this_chunk) < 0) { - PyMem_RawFree(this_chunk); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reread stack chunk with correct size"); - return -1; - } - current_size = actual_size; - } - - chunk_info->remote_addr = chunk_addr; - chunk_info->size = current_size; - chunk_info->local_copy = this_chunk; - return 0; -} - -static int -copy_stack_chunks(RemoteUnwinderObject *unwinder, - uintptr_t tstate_addr, - StackChunkList *out_chunks) -{ - uintptr_t chunk_addr; - StackChunkInfo *chunks = NULL; - size_t count = 0; - size_t max_chunks = 16; - - if (read_ptr(unwinder, tstate_addr + unwinder->debug_offsets.thread_state.datastack_chunk, &chunk_addr)) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read initial stack chunk address"); - return -1; - } - - chunks = PyMem_RawMalloc(max_chunks * sizeof(StackChunkInfo)); - if (!chunks) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to allocate stack chunks array"); - return -1; - } - - while (chunk_addr != 0) { - // Grow array if needed - if (count >= max_chunks) { - max_chunks *= 2; - StackChunkInfo *new_chunks = PyMem_RawRealloc(chunks, max_chunks * sizeof(StackChunkInfo)); - if (!new_chunks) { - PyErr_NoMemory(); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to grow stack chunks array"); - goto error; - } - chunks = new_chunks; - } - - // Process this chunk - if (process_single_stack_chunk(unwinder, chunk_addr, &chunks[count]) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process stack chunk"); - goto error; - } - - // Get next chunk address and increment count - chunk_addr = GET_MEMBER(uintptr_t, chunks[count].local_copy, offsetof(_PyStackChunk, previous)); - count++; - } - - out_chunks->chunks = chunks; - out_chunks->count = count; - return 0; - -error: - for (size_t i = 0; i < count; ++i) { - PyMem_RawFree(chunks[i].local_copy); - } - PyMem_RawFree(chunks); - return -1; -} - -static void * -find_frame_in_chunks(StackChunkList *chunks, uintptr_t remote_ptr) -{ - for (size_t i = 0; i < chunks->count; ++i) { - uintptr_t base = chunks->chunks[i].remote_addr + offsetof(_PyStackChunk, data); - size_t payload = chunks->chunks[i].size - offsetof(_PyStackChunk, data); - - if (remote_ptr >= base && remote_ptr < base + payload) { - return (char *)chunks->chunks[i].local_copy + (remote_ptr - chunks->chunks[i].remote_addr); - } - } - return NULL; -} - -static int -parse_frame_from_chunks( - RemoteUnwinderObject *unwinder, - PyObject **result, - uintptr_t address, - uintptr_t *previous_frame, - StackChunkList *chunks -) { - void *frame_ptr = find_frame_in_chunks(chunks, address); - if (!frame_ptr) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Frame not found in stack chunks"); - return -1; - } - - char *frame = (char *)frame_ptr; - *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous); - uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame_ptr, unwinder->debug_offsets.interpreter_frame.executable); - int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object); - if (frame_valid != 1) { - return frame_valid; - } - - uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr); - - // Get tlbc_index for free threading builds - int32_t tlbc_index = 0; -#ifdef Py_GIL_DISABLED - if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) { - tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index); - } -#endif - - return parse_code_object(unwinder, result, code_object, instruction_pointer, previous_frame, tlbc_index); -} - -/* ============================================================================ - * INTERPRETER STATE AND THREAD DISCOVERY FUNCTIONS - * ============================================================================ */ - -static int -populate_initial_state_data( - int all_threads, - RemoteUnwinderObject *unwinder, - uintptr_t runtime_start_address, - uintptr_t *interpreter_state, - uintptr_t *tstate -) { - uint64_t interpreter_state_list_head = - unwinder->debug_offsets.runtime_state.interpreters_head; - - uintptr_t address_of_interpreter_state; - int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - runtime_start_address + interpreter_state_list_head, - sizeof(void*), - &address_of_interpreter_state); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter state address"); - return -1; - } - - if (address_of_interpreter_state == 0) { - PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state is NULL"); - return -1; - } - - *interpreter_state = address_of_interpreter_state; - - if (all_threads) { - *tstate = 0; - return 0; - } - - uintptr_t address_of_thread = address_of_interpreter_state + - unwinder->debug_offsets.interpreter_state.threads_main; - - if (_Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address_of_thread, - sizeof(void*), - tstate) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read main thread state address"); - return -1; - } - - return 0; -} - - -static int -find_running_frame( - RemoteUnwinderObject *unwinder, - uintptr_t address_of_thread, - uintptr_t *frame -) { - if ((void*)address_of_thread != NULL) { - int err = read_ptr( - unwinder, - address_of_thread + unwinder->debug_offsets.thread_state.current_frame, - frame); - if (err) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read current frame pointer"); - return -1; - } - return 0; - } - - *frame = (uintptr_t)NULL; - return 0; -} - -/* ============================================================================ - * FRAME PARSING FUNCTIONS - * ============================================================================ */ - -static inline int -is_frame_valid( - RemoteUnwinderObject *unwinder, - uintptr_t frame_addr, - uintptr_t code_object_addr -) { - if ((void*)code_object_addr == NULL) { - return 0; - } - - void* frame = (void*)frame_addr; - - if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_CSTACK || - GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_INTERPRETER) { - return 0; // C frame - } - - if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR - && GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_THREAD) { - PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n", - GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner)); - set_exception_cause(unwinder, PyExc_RuntimeError, "Unhandled frame owner type in async frame"); - return -1; - } - return 1; -} - -static int -parse_frame_object( - RemoteUnwinderObject *unwinder, - PyObject** result, - uintptr_t address, - uintptr_t* address_of_code_object, - uintptr_t* previous_frame -) { - char frame[SIZEOF_INTERP_FRAME]; - *address_of_code_object = 0; - - Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - address, - SIZEOF_INTERP_FRAME, - frame - ); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read interpreter frame"); - return -1; - } - - *previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous); - uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable); - int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object); - if (frame_valid != 1) { - return frame_valid; - } - - uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr); - - // Get tlbc_index for free threading builds - int32_t tlbc_index = 0; -#ifdef Py_GIL_DISABLED - if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) { - tlbc_index = GET_MEMBER(int32_t, frame, unwinder->debug_offsets.interpreter_frame.tlbc_index); - } -#endif - - *address_of_code_object = code_object; - return parse_code_object(unwinder, result, code_object, instruction_pointer, previous_frame, tlbc_index); -} - -static int - parse_async_frame_chain( - RemoteUnwinderObject *unwinder, - PyObject *calls, - uintptr_t address_of_thread, - uintptr_t running_task_code_obj -) { - uintptr_t address_of_current_frame; - if (find_running_frame(unwinder, address_of_thread, &address_of_current_frame) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Running frame search failed in async chain"); - return -1; - } - - while ((void*)address_of_current_frame != NULL) { - PyObject* frame_info = NULL; - uintptr_t address_of_code_object; - int res = parse_frame_object( - unwinder, - &frame_info, - address_of_current_frame, - &address_of_code_object, - &address_of_current_frame - ); - - if (res < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Async frame object parsing failed in chain"); - return -1; - } - - if (!frame_info) { - continue; - } - - if (PyList_Append(calls, frame_info) == -1) { - Py_DECREF(frame_info); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame info to async chain"); - return -1; - } - - Py_DECREF(frame_info); - - if (address_of_code_object == running_task_code_obj) { - break; - } - } - - return 0; -} - -/* ============================================================================ - * AWAITED BY PARSING FUNCTIONS - * ============================================================================ */ - -static int -append_awaited_by_for_thread( - RemoteUnwinderObject *unwinder, - uintptr_t head_addr, - PyObject *result -) { - char task_node[SIZEOF_LLIST_NODE]; - - if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, head_addr, - sizeof(task_node), task_node) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task node head"); - return -1; - } - - size_t iteration_count = 0; - const size_t MAX_ITERATIONS = 2 << 15; // A reasonable upper bound - - while (GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) != head_addr) { - if (++iteration_count > MAX_ITERATIONS) { - PyErr_SetString(PyExc_RuntimeError, "Task list appears corrupted"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Task list iteration limit exceeded"); - return -1; - } - - if (GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) == 0) { - PyErr_SetString(PyExc_RuntimeError, - "Invalid linked list structure reading remote memory"); - set_exception_cause(unwinder, PyExc_RuntimeError, "NULL pointer in task linked list"); - return -1; - } - - uintptr_t task_addr = (uintptr_t)GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next) - - unwinder->async_debug_offsets.asyncio_task_object.task_node; - - if (process_single_task_node(unwinder, task_addr, NULL, result) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process task node in awaited_by"); - return -1; - } - - // Read next node - if (_Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, - (uintptr_t)GET_MEMBER(uintptr_t, task_node, unwinder->debug_offsets.llist_node.next), - sizeof(task_node), - task_node) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read next task node in awaited_by"); - return -1; - } - } - - return 0; -} - -static int -append_awaited_by( - RemoteUnwinderObject *unwinder, - unsigned long tid, - uintptr_t head_addr, - PyObject *result) -{ - PyObject *tid_py = PyLong_FromUnsignedLong(tid); - if (tid_py == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID object"); - return -1; - } - - PyObject* awaited_by_for_thread = PyList_New(0); - if (awaited_by_for_thread == NULL) { - Py_DECREF(tid_py); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by thread list"); - return -1; - } - - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - PyObject *result_item = PyStructSequence_New(state->AwaitedInfo_Type); - if (result_item == NULL) { - Py_DECREF(tid_py); - Py_DECREF(awaited_by_for_thread); - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo"); - return -1; - } - - PyStructSequence_SetItem(result_item, 0, tid_py); // steals ref - PyStructSequence_SetItem(result_item, 1, awaited_by_for_thread); // steals ref - if (PyList_Append(result, result_item)) { - Py_DECREF(result_item); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by result item"); - return -1; - } - Py_DECREF(result_item); - - if (append_awaited_by_for_thread(unwinder, head_addr, awaited_by_for_thread)) - { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by for thread"); - return -1; - } - - return 0; -} - -/* ============================================================================ - * STACK UNWINDING FUNCTIONS - * ============================================================================ */ - -static int -process_frame_chain( - RemoteUnwinderObject *unwinder, - uintptr_t initial_frame_addr, - StackChunkList *chunks, - PyObject *frame_info -) { - uintptr_t frame_addr = initial_frame_addr; - uintptr_t prev_frame_addr = 0; - const size_t MAX_FRAMES = 1024; - size_t frame_count = 0; - - while ((void*)frame_addr != NULL) { - PyObject *frame = NULL; - uintptr_t next_frame_addr = 0; - - if (++frame_count > MAX_FRAMES) { - PyErr_SetString(PyExc_RuntimeError, "Too many stack frames (possible infinite loop)"); - set_exception_cause(unwinder, PyExc_RuntimeError, "Frame chain iteration limit exceeded"); - return -1; - } - - // Try chunks first, fallback to direct memory read - if (parse_frame_from_chunks(unwinder, &frame, frame_addr, &next_frame_addr, chunks) < 0) { - PyErr_Clear(); - uintptr_t address_of_code_object = 0; - if (parse_frame_object(unwinder, &frame, frame_addr, &address_of_code_object ,&next_frame_addr) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in chain"); - return -1; - } - } - - if (!frame) { - break; - } - - if (prev_frame_addr && frame_addr != prev_frame_addr) { - PyErr_Format(PyExc_RuntimeError, - "Broken frame chain: expected frame at 0x%lx, got 0x%lx", - prev_frame_addr, frame_addr); - Py_DECREF(frame); - set_exception_cause(unwinder, PyExc_RuntimeError, "Frame chain consistency check failed"); - return -1; - } - - if (PyList_Append(frame_info, frame) == -1) { - Py_DECREF(frame); - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to frame info list"); - return -1; - } - Py_DECREF(frame); - - prev_frame_addr = next_frame_addr; - frame_addr = next_frame_addr; - } - - return 0; -} - -static PyObject* -unwind_stack_for_thread( - RemoteUnwinderObject *unwinder, - uintptr_t *current_tstate -) { - PyObject *frame_info = NULL; - PyObject *thread_id = NULL; - PyObject *result = NULL; - StackChunkList chunks = {0}; - - char ts[SIZEOF_THREAD_STATE]; - int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory( - &unwinder->handle, *current_tstate, unwinder->debug_offsets.thread_state.size, ts); - if (bytes_read < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read thread state"); - goto error; - } - - uintptr_t frame_addr = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.current_frame); - - frame_info = PyList_New(0); - if (!frame_info) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create frame info list"); - goto error; - } - - if (copy_stack_chunks(unwinder, *current_tstate, &chunks) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to copy stack chunks"); - goto error; - } - - if (process_frame_chain(unwinder, frame_addr, &chunks, frame_info) < 0) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to process frame chain"); - goto error; - } - - *current_tstate = GET_MEMBER(uintptr_t, ts, unwinder->debug_offsets.thread_state.next); - - thread_id = PyLong_FromLongLong( - GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.native_thread_id)); - if (thread_id == NULL) { - set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create thread ID"); - goto error; - } - - RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder); - result = PyStructSequence_New(state->ThreadInfo_Type); - if (result == NULL) { - set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create ThreadInfo"); - goto error; - } - - PyStructSequence_SetItem(result, 0, thread_id); // Steals reference - PyStructSequence_SetItem(result, 1, frame_info); // Steals reference - - cleanup_stack_chunks(&chunks); - return result; - -error: - Py_XDECREF(frame_info); - Py_XDECREF(thread_id); - Py_XDECREF(result); - cleanup_stack_chunks(&chunks); - return NULL; -} - - -/* ============================================================================ - * REMOTEUNWINDER CLASS IMPLEMENTATION - * ============================================================================ */ - -/*[clinic input] -class _remote_debugging.RemoteUnwinder "RemoteUnwinderObject *" "&RemoteUnwinder_Type" -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=55f164d8803318be]*/ - -/*[clinic input] -@permit_long_summary -@permit_long_docstring_body -_remote_debugging.RemoteUnwinder.__init__ - pid: int - * - all_threads: bool = False - only_active_thread: bool = False - debug: bool = False - -Initialize a new RemoteUnwinder object for debugging a remote Python process. - -Args: - pid: Process ID of the target Python process to debug - all_threads: If True, initialize state for all threads in the process. - If False, only initialize for the main thread. - only_active_thread: If True, only sample the thread holding the GIL. - Cannot be used together with all_threads=True. - debug: If True, chain exceptions to explain the sequence of events that - lead to the exception. - -The RemoteUnwinder provides functionality to inspect and debug a running Python -process, including examining thread states, stack frames and other runtime data. - -Raises: - PermissionError: If access to the target process is denied - OSError: If unable to attach to the target process or access its memory - RuntimeError: If unable to read debug information from the target process - ValueError: If both all_threads and only_active_thread are True -[clinic start generated code]*/ - -static int -_remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, - int pid, int all_threads, - int only_active_thread, - int debug) -/*[clinic end generated code: output=13ba77598ecdcbe1 input=cfc21663fbe263c4]*/ -{ - // Validate that all_threads and only_active_thread are not both True - if (all_threads && only_active_thread) { - PyErr_SetString(PyExc_ValueError, - "all_threads and only_active_thread cannot both be True"); - return -1; - } - -#ifdef Py_GIL_DISABLED - if (only_active_thread) { - PyErr_SetString(PyExc_ValueError, - "only_active_thread is not supported when Py_GIL_DISABLED is not defined"); - return -1; - } -#endif - - self->debug = debug; - self->only_active_thread = only_active_thread; - self->cached_state = NULL; - if (_Py_RemoteDebug_InitProcHandle(&self->handle, pid) < 0) { - set_exception_cause(self, PyExc_RuntimeError, "Failed to initialize process handle"); - return -1; - } - - self->runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(&self->handle); - if (self->runtime_start_address == 0) { - set_exception_cause(self, PyExc_RuntimeError, "Failed to get Python runtime address"); - return -1; - } - - if (_Py_RemoteDebug_ReadDebugOffsets(&self->handle, - &self->runtime_start_address, - &self->debug_offsets) < 0) - { - set_exception_cause(self, PyExc_RuntimeError, "Failed to read debug offsets"); - return -1; - } - - // Validate that the debug offsets are valid - if(validate_debug_offsets(&self->debug_offsets) == -1) { - set_exception_cause(self, PyExc_RuntimeError, "Invalid debug offsets found"); - return -1; - } - - // Try to read async debug offsets, but don't fail if they're not available - self->async_debug_offsets_available = 1; - if (read_async_debug(self) < 0) { - PyErr_Clear(); - memset(&self->async_debug_offsets, 0, sizeof(self->async_debug_offsets)); - self->async_debug_offsets_available = 0; - } - - if (populate_initial_state_data(all_threads, self, self->runtime_start_address, - &self->interpreter_addr ,&self->tstate_addr) < 0) - { - set_exception_cause(self, PyExc_RuntimeError, "Failed to populate initial state data"); - return -1; - } - - self->code_object_cache = _Py_hashtable_new_full( - _Py_hashtable_hash_ptr, - _Py_hashtable_compare_direct, - NULL, // keys are stable pointers, don't destroy - cached_code_metadata_destroy, - NULL - ); - if (self->code_object_cache == NULL) { - PyErr_NoMemory(); - set_exception_cause(self, PyExc_MemoryError, "Failed to create code object cache"); - return -1; - } - -#ifdef Py_GIL_DISABLED - // Initialize TLBC cache - self->tlbc_generation = 0; - self->tlbc_cache = _Py_hashtable_new_full( - _Py_hashtable_hash_ptr, - _Py_hashtable_compare_direct, - NULL, // keys are stable pointers, don't destroy - tlbc_cache_entry_destroy, - NULL - ); - if (self->tlbc_cache == NULL) { - _Py_hashtable_destroy(self->code_object_cache); - PyErr_NoMemory(); - set_exception_cause(self, PyExc_MemoryError, "Failed to create TLBC cache"); - return -1; - } -#endif - - return 0; -} - -/*[clinic input] -@permit_long_docstring_body -@critical_section -_remote_debugging.RemoteUnwinder.get_stack_trace - -Returns a list of stack traces for threads in the target process. - -Each element in the returned list is a tuple of (thread_id, frame_list), where: -- thread_id is the OS thread identifier -- frame_list is a list of tuples (function_name, filename, line_number) representing - the Python stack frames for that thread, ordered from most recent to oldest - -The threads returned depend on the initialization parameters: -- If only_active_thread was True: returns only the thread holding the GIL -- If all_threads was True: returns all threads -- Otherwise: returns only the main thread - -Example: - [ - (1234, [ - ('process_data', 'worker.py', 127), - ('run_worker', 'worker.py', 45), - ('main', 'app.py', 23) - ]), - (1235, [ - ('handle_request', 'server.py', 89), - ('serve_forever', 'server.py', 52) - ]) - ] - -Raises: - RuntimeError: If there is an error copying memory from the target process - OSError: If there is an error accessing the target process - PermissionError: If access to the target process is denied - UnicodeDecodeError: If there is an error decoding strings from the target process - -[clinic start generated code]*/ - -static PyObject * -_remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=666192b90c69d567 input=c527a4b858601408]*/ -{ - PyObject* result = NULL; - // Read interpreter state into opaque buffer - char interp_state_buffer[INTERP_STATE_BUFFER_SIZE]; - if (_Py_RemoteDebug_PagedReadRemoteMemory( - &self->handle, - self->interpreter_addr, - INTERP_STATE_BUFFER_SIZE, - interp_state_buffer) < 0) { - set_exception_cause(self, PyExc_RuntimeError, "Failed to read interpreter state buffer"); - goto exit; - } - - // Get code object generation from buffer - uint64_t code_object_generation = GET_MEMBER(uint64_t, interp_state_buffer, - self->debug_offsets.interpreter_state.code_object_generation); - - if (code_object_generation != self->code_object_generation) { - self->code_object_generation = code_object_generation; - _Py_hashtable_clear(self->code_object_cache); - } - - // If only_active_thread is true, we need to determine which thread holds the GIL - PyThreadState* gil_holder = NULL; - if (self->only_active_thread) { - // The GIL state is already in interp_state_buffer, just read from there - // Check if GIL is locked - int gil_locked = GET_MEMBER(int, interp_state_buffer, - self->debug_offsets.interpreter_state.gil_runtime_state_locked); - - if (gil_locked) { - // Get the last holder (current holder when GIL is locked) - gil_holder = GET_MEMBER(PyThreadState*, interp_state_buffer, - self->debug_offsets.interpreter_state.gil_runtime_state_holder); - } else { - // GIL is not locked, return empty list - result = PyList_New(0); - if (!result) { - set_exception_cause(self, PyExc_MemoryError, "Failed to create empty result list"); - } - goto exit; - } - } - -#ifdef Py_GIL_DISABLED - // Check TLBC generation and invalidate cache if needed - uint32_t current_tlbc_generation = GET_MEMBER(uint32_t, interp_state_buffer, - self->debug_offsets.interpreter_state.tlbc_generation); - if (current_tlbc_generation != self->tlbc_generation) { - self->tlbc_generation = current_tlbc_generation; - _Py_hashtable_clear(self->tlbc_cache); - } -#endif - - uintptr_t current_tstate; - if (self->only_active_thread && gil_holder != NULL) { - // We have the GIL holder, process only that thread - current_tstate = (uintptr_t)gil_holder; - } else if (self->tstate_addr == 0) { - // Get threads head from buffer - current_tstate = GET_MEMBER(uintptr_t, interp_state_buffer, - self->debug_offsets.interpreter_state.threads_head); - } else { - current_tstate = self->tstate_addr; - } - - result = PyList_New(0); - if (!result) { - set_exception_cause(self, PyExc_MemoryError, "Failed to create stack trace result list"); - goto exit; - } - - while (current_tstate != 0) { - PyObject* frame_info = unwind_stack_for_thread(self, &current_tstate); - if (!frame_info) { - Py_CLEAR(result); - set_exception_cause(self, PyExc_RuntimeError, "Failed to unwind stack for thread"); - goto exit; - } - - if (PyList_Append(result, frame_info) == -1) { - Py_DECREF(frame_info); - Py_CLEAR(result); - set_exception_cause(self, PyExc_RuntimeError, "Failed to append thread frame info"); - goto exit; - } - Py_DECREF(frame_info); - - // We are targeting a single tstate, break here - if (self->tstate_addr) { - break; - } - - // If we're only processing the GIL holder, we're done after one iteration - if (self->only_active_thread && gil_holder != NULL) { - break; - } - } - -exit: - _Py_RemoteDebug_ClearCache(&self->handle); - return result; -} - -/*[clinic input] -@permit_long_summary -@permit_long_docstring_body -@critical_section -_remote_debugging.RemoteUnwinder.get_all_awaited_by - -Get all tasks and their awaited_by relationships from the remote process. - -This provides a tree structure showing which tasks are waiting for other tasks. - -For each task, returns: -1. The call stack frames leading to where the task is currently executing -2. The name of the task -3. A list of tasks that this task is waiting for, with their own frames/names/etc - -Returns a list of [frames, task_name, subtasks] where: -- frames: List of (func_name, filename, lineno) showing the call stack -- task_name: String identifier for the task -- subtasks: List of tasks being awaited by this task, in same format - -Raises: - RuntimeError: If AsyncioDebug section is not available in the remote process - MemoryError: If memory allocation fails - OSError: If reading from the remote process fails - -Example output: -[ - # Task c2_root waiting for two subtasks - [ - # Call stack of c2_root - [("c5", "script.py", 10), ("c4", "script.py", 14)], - "c2_root", - [ - # First subtask (sub_main_2) and what it's waiting for - [ - [("c1", "script.py", 23)], - "sub_main_2", - [...] - ], - # Second subtask and its waiters - [...] - ] - ] -] -[clinic start generated code]*/ - -static PyObject * -_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=6a49cd345e8aec53 input=307f754cbe38250c]*/ -{ - if (!self->async_debug_offsets_available) { - PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available"); - set_exception_cause(self, PyExc_RuntimeError, "AsyncioDebug section unavailable in get_all_awaited_by"); - return NULL; - } - - PyObject *result = PyList_New(0); - if (result == NULL) { - set_exception_cause(self, PyExc_MemoryError, "Failed to create awaited_by result list"); - goto result_err; - } - - // Process all threads - if (iterate_threads(self, process_thread_for_awaited_by, result) < 0) { - goto result_err; - } - - uintptr_t head_addr = self->interpreter_addr - + self->async_debug_offsets.asyncio_interpreter_state.asyncio_tasks_head; - - // On top of a per-thread task lists used by default by asyncio to avoid - // contention, there is also a fallback per-interpreter list of tasks; - // any tasks still pending when a thread is destroyed will be moved to the - // per-interpreter task list. It's unlikely we'll find anything here, but - // interesting for debugging. - if (append_awaited_by(self, 0, head_addr, result)) - { - set_exception_cause(self, PyExc_RuntimeError, "Failed to append interpreter awaited_by in get_all_awaited_by"); - goto result_err; - } - - _Py_RemoteDebug_ClearCache(&self->handle); - return result; - -result_err: - _Py_RemoteDebug_ClearCache(&self->handle); - Py_XDECREF(result); - return NULL; -} - -/*[clinic input] -@permit_long_summary -@permit_long_docstring_body -@critical_section -_remote_debugging.RemoteUnwinder.get_async_stack_trace - -Get the currently running async tasks and their dependency graphs from the remote process. - -This returns information about running tasks and all tasks that are waiting for them, -forming a complete dependency graph for each thread's active task. - -For each thread with a running task, returns the running task plus all tasks that -transitively depend on it (tasks waiting for the running task, tasks waiting for -those tasks, etc.). - -Returns a list of per-thread results, where each thread result contains: -- Thread ID -- List of task information for the running task and all its waiters - -Each task info contains: -- Task ID (memory address) -- Task name -- Call stack frames: List of (func_name, filename, lineno) -- List of tasks waiting for this task (recursive structure) - -Raises: - RuntimeError: If AsyncioDebug section is not available in the target process - MemoryError: If memory allocation fails - OSError: If reading from the remote process fails - -Example output (similar structure to get_all_awaited_by but only for running tasks): -[ - # Thread 140234 results - (140234, [ - # Running task and its complete waiter dependency graph - (4345585712, 'main_task', - [("run_server", "server.py", 127), ("main", "app.py", 23)], - [ - # Tasks waiting for main_task - (4345585800, 'worker_1', [...], [...]), - (4345585900, 'worker_2', [...], [...]) - ]) - ]) -] - -[clinic start generated code]*/ - -static PyObject * -_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject *self) -/*[clinic end generated code: output=6433d52b55e87bbe input=6129b7d509a887c9]*/ -{ - if (!self->async_debug_offsets_available) { - PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not available"); - set_exception_cause(self, PyExc_RuntimeError, "AsyncioDebug section unavailable in get_async_stack_trace"); - return NULL; - } - - PyObject *result = PyList_New(0); - if (result == NULL) { - set_exception_cause(self, PyExc_MemoryError, "Failed to create result list in get_async_stack_trace"); - return NULL; - } - - // Process all threads - if (iterate_threads(self, process_thread_for_async_stack_trace, result) < 0) { - goto result_err; - } - - _Py_RemoteDebug_ClearCache(&self->handle); - return result; -result_err: - _Py_RemoteDebug_ClearCache(&self->handle); - Py_XDECREF(result); - return NULL; -} - -static PyMethodDef RemoteUnwinder_methods[] = { - _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_STACK_TRACE_METHODDEF - _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ALL_AWAITED_BY_METHODDEF - _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ASYNC_STACK_TRACE_METHODDEF - {NULL, NULL} -}; - -static void -RemoteUnwinder_dealloc(PyObject *op) -{ - RemoteUnwinderObject *self = RemoteUnwinder_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - if (self->code_object_cache) { - _Py_hashtable_destroy(self->code_object_cache); - } -#ifdef Py_GIL_DISABLED - if (self->tlbc_cache) { - _Py_hashtable_destroy(self->tlbc_cache); - } -#endif - if (self->handle.pid != 0) { - _Py_RemoteDebug_ClearCache(&self->handle); - _Py_RemoteDebug_CleanupProcHandle(&self->handle); - } - PyObject_Del(self); - Py_DECREF(tp); -} - -static PyType_Slot RemoteUnwinder_slots[] = { - {Py_tp_doc, (void *)"RemoteUnwinder(pid): Inspect stack of a remote Python process."}, - {Py_tp_methods, RemoteUnwinder_methods}, - {Py_tp_init, _remote_debugging_RemoteUnwinder___init__}, - {Py_tp_dealloc, RemoteUnwinder_dealloc}, - {0, NULL} -}; - -static PyType_Spec RemoteUnwinder_spec = { - .name = "_remote_debugging.RemoteUnwinder", - .basicsize = sizeof(RemoteUnwinderObject), - .flags = Py_TPFLAGS_DEFAULT, - .slots = RemoteUnwinder_slots, -}; - -/* ============================================================================ - * MODULE INITIALIZATION - * ============================================================================ */ - -static int -_remote_debugging_exec(PyObject *m) -{ - RemoteDebuggingState *st = RemoteDebugging_GetState(m); -#define CREATE_TYPE(mod, type, spec) \ - do { \ - type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ - if (type == NULL) { \ - return -1; \ - } \ - } while (0) - - CREATE_TYPE(m, st->RemoteDebugging_Type, &RemoteUnwinder_spec); - - if (PyModule_AddType(m, st->RemoteDebugging_Type) < 0) { - return -1; - } - - // Initialize structseq types - st->TaskInfo_Type = PyStructSequence_NewType(&TaskInfo_desc); - if (st->TaskInfo_Type == NULL) { - return -1; - } - if (PyModule_AddType(m, st->TaskInfo_Type) < 0) { - return -1; - } - - st->FrameInfo_Type = PyStructSequence_NewType(&FrameInfo_desc); - if (st->FrameInfo_Type == NULL) { - return -1; - } - if (PyModule_AddType(m, st->FrameInfo_Type) < 0) { - return -1; - } - - st->CoroInfo_Type = PyStructSequence_NewType(&CoroInfo_desc); - if (st->CoroInfo_Type == NULL) { - return -1; - } - if (PyModule_AddType(m, st->CoroInfo_Type) < 0) { - return -1; - } - - st->ThreadInfo_Type = PyStructSequence_NewType(&ThreadInfo_desc); - if (st->ThreadInfo_Type == NULL) { - return -1; - } - if (PyModule_AddType(m, st->ThreadInfo_Type) < 0) { - return -1; - } - - st->AwaitedInfo_Type = PyStructSequence_NewType(&AwaitedInfo_desc); - if (st->AwaitedInfo_Type == NULL) { - return -1; - } - if (PyModule_AddType(m, st->AwaitedInfo_Type) < 0) { - return -1; - } -#ifdef Py_GIL_DISABLED - PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); -#endif - int rc = PyModule_AddIntConstant(m, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); - if (rc < 0) { - return -1; - } - if (RemoteDebugging_InitState(st) < 0) { - return -1; - } - return 0; -} - -static int -remote_debugging_traverse(PyObject *mod, visitproc visit, void *arg) -{ - RemoteDebuggingState *state = RemoteDebugging_GetState(mod); - Py_VISIT(state->RemoteDebugging_Type); - Py_VISIT(state->TaskInfo_Type); - Py_VISIT(state->FrameInfo_Type); - Py_VISIT(state->CoroInfo_Type); - Py_VISIT(state->ThreadInfo_Type); - Py_VISIT(state->AwaitedInfo_Type); - return 0; -} - -static int -remote_debugging_clear(PyObject *mod) -{ - RemoteDebuggingState *state = RemoteDebugging_GetState(mod); - Py_CLEAR(state->RemoteDebugging_Type); - Py_CLEAR(state->TaskInfo_Type); - Py_CLEAR(state->FrameInfo_Type); - Py_CLEAR(state->CoroInfo_Type); - Py_CLEAR(state->ThreadInfo_Type); - Py_CLEAR(state->AwaitedInfo_Type); - return 0; -} - -static void -remote_debugging_free(void *mod) -{ - (void)remote_debugging_clear((PyObject *)mod); -} - -static PyModuleDef_Slot remote_debugging_slots[] = { - {Py_mod_exec, _remote_debugging_exec}, - {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, - {Py_mod_gil, Py_MOD_GIL_NOT_USED}, - {0, NULL}, -}; - -static PyMethodDef remote_debugging_methods[] = { - {NULL, NULL, 0, NULL}, -}; - -static struct PyModuleDef remote_debugging_module = { - PyModuleDef_HEAD_INIT, - .m_name = "_remote_debugging", - .m_size = sizeof(RemoteDebuggingState), - .m_methods = remote_debugging_methods, - .m_slots = remote_debugging_slots, - .m_traverse = remote_debugging_traverse, - .m_clear = remote_debugging_clear, - .m_free = remote_debugging_free, -}; - -PyMODINIT_FUNC -PyInit__remote_debugging(void) -{ - return PyModuleDef_Init(&remote_debugging_module); -} diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c index b619a13b562..4a213f34888 100644 --- a/Modules/_sqlite/blob.c +++ b/Modules/_sqlite/blob.c @@ -118,7 +118,9 @@ static void blob_seterror(pysqlite_Blob *self, int rc) { assert(self->connection != NULL); - set_error_from_db(self->connection->state, self->connection->db); + assert(rc != SQLITE_OK); + set_error_from_code(self->connection->state, rc); + assert(PyErr_Occurred()); } static PyObject * @@ -143,23 +145,23 @@ read_multiple(pysqlite_Blob *self, Py_ssize_t length, Py_ssize_t offset) assert(length <= sqlite3_blob_bytes(self->blob)); assert(offset < sqlite3_blob_bytes(self->blob)); - PyObject *buffer = PyBytes_FromStringAndSize(NULL, length); - if (buffer == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; } + char *raw_buffer = PyBytesWriter_GetData(writer); - char *raw_buffer = PyBytes_AS_STRING(buffer); int rc; Py_BEGIN_ALLOW_THREADS rc = sqlite3_blob_read(self->blob, raw_buffer, (int)length, (int)offset); Py_END_ALLOW_THREADS if (rc != SQLITE_OK) { - Py_DECREF(buffer); + PyBytesWriter_Discard(writer); blob_seterror(self, rc); return NULL; } - return buffer; + return PyBytesWriter_Finish(writer); } @@ -196,7 +198,7 @@ blob_read_impl(pysqlite_Blob *self, int length) assert(length >= 0); if (length == 0) { - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } PyObject *buffer = read_multiple(self, length, self->offset); @@ -440,20 +442,25 @@ subscript_slice(pysqlite_Blob *self, PyObject *item) if (step == 1) { return read_multiple(self, len, start); } + PyObject *blob = read_multiple(self, stop - start, start); if (blob == NULL) { return NULL; } - PyObject *result = PyBytes_FromStringAndSize(NULL, len); - if (result != NULL) { - char *blob_buf = PyBytes_AS_STRING(blob); - char *res_buf = PyBytes_AS_STRING(result); - for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) { - res_buf[i] = blob_buf[j]; - } + + PyBytesWriter *writer = PyBytesWriter_Create(len); + if (writer == NULL) { Py_DECREF(blob); + return NULL; } - return result; + char *res_buf = PyBytesWriter_GetData(writer); + + char *blob_buf = PyBytes_AS_STRING(blob); + for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) { + res_buf[i] = blob_buf[j]; + } + Py_DECREF(blob); + return PyBytesWriter_Finish(writer); } static PyObject * diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index f0e9fdb8894..abb864eb030 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -209,7 +209,7 @@ exit: } PyDoc_STRVAR(blobopen__doc__, -"blobopen($self, table, column, row, /, *, readonly=False, name=\'main\')\n" +"blobopen($self, table, column, rowid, /, *, readonly=False, name=\'main\')\n" "--\n" "\n" "Open and return a BLOB object.\n" @@ -218,8 +218,8 @@ PyDoc_STRVAR(blobopen__doc__, " Table name.\n" " column\n" " Column name.\n" -" row\n" -" Row index.\n" +" rowid\n" +" Row id.\n" " readonly\n" " Open the BLOB without write permissions.\n" " name\n" @@ -1722,4 +1722,4 @@ exit: #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=6cb96e557133d553 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=16d44c1d8a45e622 input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/clinic/cursor.c.h b/Modules/_sqlite/clinic/cursor.c.h index 350577f488d..3cad9f3aef5 100644 --- a/Modules/_sqlite/clinic/cursor.c.h +++ b/Modules/_sqlite/clinic/cursor.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_long.h" // _PyLong_UInt32_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() static int @@ -181,7 +182,7 @@ PyDoc_STRVAR(pysqlite_cursor_fetchmany__doc__, {"fetchmany", _PyCFunction_CAST(pysqlite_cursor_fetchmany), METH_FASTCALL|METH_KEYWORDS, pysqlite_cursor_fetchmany__doc__}, static PyObject * -pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, int maxrows); +pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, uint32_t maxrows); static PyObject * pysqlite_cursor_fetchmany(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -216,7 +217,7 @@ pysqlite_cursor_fetchmany(PyObject *self, PyObject *const *args, Py_ssize_t narg #undef KWTUPLE PyObject *argsbuf[1]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - int maxrows = ((pysqlite_Cursor *)self)->arraysize; + uint32_t maxrows = ((pysqlite_Cursor *)self)->arraysize; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); @@ -226,8 +227,7 @@ pysqlite_cursor_fetchmany(PyObject *self, PyObject *const *args, Py_ssize_t narg if (!noptargs) { goto skip_optional_pos; } - maxrows = PyLong_AsInt(args[0]); - if (maxrows == -1 && PyErr_Occurred()) { + if (!_PyLong_UInt32_Converter(args[0], &maxrows)) { goto exit; } skip_optional_pos: @@ -329,4 +329,46 @@ pysqlite_cursor_close(PyObject *self, PyObject *Py_UNUSED(ignored)) { return pysqlite_cursor_close_impl((pysqlite_Cursor *)self); } -/*[clinic end generated code: output=d05c7cbbc8bcab26 input=a9049054013a1b77]*/ + +#if !defined(_sqlite3_Cursor_arraysize_DOCSTR) +# define _sqlite3_Cursor_arraysize_DOCSTR NULL +#endif +#if defined(_SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF) +# undef _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF +# define _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF {"arraysize", (getter)_sqlite3_Cursor_arraysize_get, (setter)_sqlite3_Cursor_arraysize_set, _sqlite3_Cursor_arraysize_DOCSTR}, +#else +# define _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF {"arraysize", (getter)_sqlite3_Cursor_arraysize_get, NULL, _sqlite3_Cursor_arraysize_DOCSTR}, +#endif + +static PyObject * +_sqlite3_Cursor_arraysize_get_impl(pysqlite_Cursor *self); + +static PyObject * +_sqlite3_Cursor_arraysize_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _sqlite3_Cursor_arraysize_get_impl((pysqlite_Cursor *)self); +} + +#if !defined(_sqlite3_Cursor_arraysize_DOCSTR) +# define _sqlite3_Cursor_arraysize_DOCSTR NULL +#endif +#if defined(_SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF) +# undef _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF +# define _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF {"arraysize", (getter)_sqlite3_Cursor_arraysize_get, (setter)_sqlite3_Cursor_arraysize_set, _sqlite3_Cursor_arraysize_DOCSTR}, +#else +# define _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF {"arraysize", NULL, (setter)_sqlite3_Cursor_arraysize_set, NULL}, +#endif + +static int +_sqlite3_Cursor_arraysize_set_impl(pysqlite_Cursor *self, PyObject *value); + +static int +_sqlite3_Cursor_arraysize_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) +{ + int return_value; + + return_value = _sqlite3_Cursor_arraysize_set_impl((pysqlite_Cursor *)self, value); + + return return_value; +} +/*[clinic end generated code: output=a0e3ebba9e4d0ece input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 208e3c18425..83ff8e60557 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -144,7 +144,7 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/ -static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); +static int _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); static void free_callback_context(callback_context *ctx); static void set_callback_context(callback_context **ctx_pp, callback_context *ctx); @@ -561,7 +561,10 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory) return NULL; } - _pysqlite_drop_unused_cursor_references(self); + if (_pysqlite_drop_unused_cursor_references(self) < 0) { + Py_DECREF(cursor); + return NULL; + } if (cursor && self->row_factory != Py_None) { Py_INCREF(self->row_factory); @@ -578,8 +581,8 @@ _sqlite3.Connection.blobopen as blobopen Table name. column as col: str Column name. - row: sqlite3_int64 - Row index. + rowid as row: sqlite3_int64 + Row id. / * readonly: bool = False @@ -593,7 +596,7 @@ Open and return a BLOB object. static PyObject * blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, sqlite3_int64 row, int readonly, const char *name) -/*[clinic end generated code: output=6a02d43efb885d1c input=23576bd1108d8774]*/ +/*[clinic end generated code: output=6a02d43efb885d1c input=cc3d4b47dac08401]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1060,32 +1063,36 @@ error: PyGILState_Release(threadstate); } -static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) +static int +_pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) { /* we only need to do this once in a while */ if (self->created_cursors++ < 200) { - return; + return 0; } self->created_cursors = 0; PyObject* new_list = PyList_New(0); if (!new_list) { - return; + return -1; } - for (Py_ssize_t i = 0; i < PyList_Size(self->cursors); i++) { - PyObject* weakref = PyList_GetItem(self->cursors, i); + assert(PyList_CheckExact(self->cursors)); + Py_ssize_t imax = PyList_GET_SIZE(self->cursors); + for (Py_ssize_t i = 0; i < imax; i++) { + PyObject* weakref = PyList_GET_ITEM(self->cursors, i); if (_PyWeakref_IsDead(weakref)) { continue; } if (PyList_Append(new_list, weakref) != 0) { Py_DECREF(new_list); - return; + return -1; } } Py_SETREF(self->cursors, new_list); + return 0; } /* Allocate a UDF/callback context structure. In order to ensure that the state diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 0c3f43d0e50..4611c9e5e3e 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -58,6 +58,41 @@ check_cursor_locked(pysqlite_Cursor *cur) return 1; } +static pysqlite_state * +get_module_state_by_cursor(pysqlite_Cursor *cursor) +{ + if (cursor->connection != NULL && cursor->connection->state != NULL) { + return cursor->connection->state; + } + return pysqlite_get_state_by_type(Py_TYPE(cursor)); +} + +static void +cursor_sqlite3_internal_error(pysqlite_Cursor *cursor, + const char *error_message, + int chain_exceptions) +{ + pysqlite_state *state = get_module_state_by_cursor(cursor); + if (chain_exceptions) { + assert(PyErr_Occurred()); + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(state->InternalError, error_message); + _PyErr_ChainExceptions1(exc); + } + else { + assert(!PyErr_Occurred()); + PyErr_SetString(state->InternalError, error_message); + } +} + +static void +cursor_cannot_reset_stmt_error(pysqlite_Cursor *cursor, int chain_exceptions) +{ + cursor_sqlite3_internal_error(cursor, + "cannot reset statement", + chain_exceptions); +} + /*[clinic input] module _sqlite3 class _sqlite3.Cursor "pysqlite_Cursor *" "clinic_state()->CursorType" @@ -173,8 +208,12 @@ cursor_clear(PyObject *op) Py_CLEAR(self->row_factory); if (self->statement) { /* Reset the statement if the user has not closed the cursor */ - stmt_reset(self->statement); + int rc = stmt_reset(self->statement); Py_CLEAR(self->statement); + if (rc != SQLITE_OK) { + cursor_cannot_reset_stmt_error(self, 0); + PyErr_FormatUnraisable("Exception ignored in cursor_clear()"); + } } return 0; @@ -471,6 +510,9 @@ static int check_cursor(pysqlite_Cursor* cur) return 0; } + assert(cur->connection != NULL); + assert(cur->connection->state != NULL); + if (cur->closed) { PyErr_SetString(cur->connection->state->ProgrammingError, "Cannot operate on a closed cursor."); @@ -567,43 +609,40 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos, switch (paramtype) { case TYPE_LONG: { sqlite_int64 value = _pysqlite_long_as_int64(parameter); - if (value == -1 && PyErr_Occurred()) - rc = -1; - else - rc = sqlite3_bind_int64(self->st, pos, value); + rc = (value == -1 && PyErr_Occurred()) + ? SQLITE_ERROR + : sqlite3_bind_int64(self->st, pos, value); break; } case TYPE_FLOAT: { double value = PyFloat_AsDouble(parameter); - if (value == -1 && PyErr_Occurred()) { - rc = -1; - } - else { - rc = sqlite3_bind_double(self->st, pos, value); - } + rc = (value == -1 && PyErr_Occurred()) + ? SQLITE_ERROR + : sqlite3_bind_double(self->st, pos, value); break; } case TYPE_UNICODE: string = PyUnicode_AsUTF8AndSize(parameter, &buflen); - if (string == NULL) - return -1; + if (string == NULL) { + return SQLITE_ERROR; + } if (buflen > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "string longer than INT_MAX bytes"); - return -1; + return SQLITE_ERROR; } rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT); break; case TYPE_BUFFER: { Py_buffer view; if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) { - return -1; + return SQLITE_ERROR; } if (view.len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "BLOB longer than INT_MAX bytes"); PyBuffer_Release(&view); - return -1; + return SQLITE_ERROR; } rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT); PyBuffer_Release(&view); @@ -613,7 +652,7 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos, PyErr_Format(state->ProgrammingError, "Error binding parameter %d: type '%s' is not supported", pos, Py_TYPE(parameter)->tp_name); - rc = -1; + rc = SQLITE_ERROR; } final: @@ -733,14 +772,17 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self, } binding_name++; /* skip first char (the colon) */ - PyObject *current_param; - (void)PyMapping_GetOptionalItemString(parameters, binding_name, &current_param); - if (!current_param) { - if (!PyErr_Occurred() || PyErr_ExceptionMatches(PyExc_LookupError)) { - PyErr_Format(state->ProgrammingError, - "You did not supply a value for binding " - "parameter :%s.", binding_name); - } + PyObject *current_param = NULL; + int found = PyMapping_GetOptionalItemString(parameters, + binding_name, + &current_param); + if (found == -1) { + return; + } + else if (found == 0) { + PyErr_Format(state->ProgrammingError, + "You did not supply a value for binding " + "parameter :%s.", binding_name); return; } @@ -834,7 +876,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation if (self->statement) { // Reset pending statements on this cursor. - (void)stmt_reset(self->statement); + if (stmt_reset(self->statement) != SQLITE_OK) { + goto reset_failure; + } } PyObject *stmt = get_statement_from_cache(self, operation); @@ -858,7 +902,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation } } - (void)stmt_reset(self->statement); + if (stmt_reset(self->statement) != SQLITE_OK) { + goto reset_failure; + } self->rowcount = self->statement->is_dml ? 0L : -1L; /* We start a transaction implicitly before a DML statement. @@ -940,7 +986,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation if (self->statement->is_dml) { self->rowcount += (long)sqlite3_changes(self->connection->db); } - stmt_reset(self->statement); + if (stmt_reset(self->statement) != SQLITE_OK) { + goto reset_failure; + } } Py_XDECREF(parameters); } @@ -965,8 +1013,15 @@ error: if (PyErr_Occurred()) { if (self->statement) { - (void)stmt_reset(self->statement); + sqlite3 *db = sqlite3_db_handle(self->statement->st); + int sqlite3_state = sqlite3_errcode(db); + // stmt_reset() may return a previously set exception, + // either triggered because of Python or sqlite3. + rc = stmt_reset(self->statement); Py_CLEAR(self->statement); + if (sqlite3_state == SQLITE_OK && rc != SQLITE_OK) { + cursor_cannot_reset_stmt_error(self, 1); + } } self->rowcount = -1L; return NULL; @@ -975,6 +1030,20 @@ error: Py_CLEAR(self->statement); } return Py_NewRef((PyObject *)self); + +reset_failure: + /* suite to execute when stmt_reset() failed and no exception is set */ + assert(!PyErr_Occurred()); + + Py_XDECREF(parameters); + Py_XDECREF(parameters_iter); + Py_XDECREF(parameters_list); + + self->locked = 0; + self->rowcount = -1L; + Py_CLEAR(self->statement); + cursor_cannot_reset_stmt_error(self, 0); + return NULL; } /*[clinic input] @@ -1117,14 +1186,20 @@ pysqlite_cursor_iternext(PyObject *op) if (self->statement->is_dml) { self->rowcount = (long)sqlite3_changes(self->connection->db); } - (void)stmt_reset(self->statement); + rc = stmt_reset(self->statement); Py_CLEAR(self->statement); + if (rc != SQLITE_OK) { + goto reset_failure; + } } else if (rc != SQLITE_ROW) { - set_error_from_db(self->connection->state, self->connection->db); - (void)stmt_reset(self->statement); + rc = set_error_from_db(self->connection->state, self->connection->db); + int reset_rc = stmt_reset(self->statement); Py_CLEAR(self->statement); Py_DECREF(row); + if (rc == SQLITE_OK && reset_rc != SQLITE_OK) { + goto reset_failure; + } return NULL; } if (!Py_IsNone(self->row_factory)) { @@ -1134,6 +1209,10 @@ pysqlite_cursor_iternext(PyObject *op) Py_SETREF(row, new_row); } return row; + +reset_failure: + cursor_cannot_reset_stmt_error(self, 0); + return NULL; } /*[clinic input] @@ -1159,35 +1238,31 @@ pysqlite_cursor_fetchone_impl(pysqlite_Cursor *self) /*[clinic input] _sqlite3.Cursor.fetchmany as pysqlite_cursor_fetchmany - size as maxrows: int(c_default='((pysqlite_Cursor *)self)->arraysize') = 1 + size as maxrows: uint32(c_default='((pysqlite_Cursor *)self)->arraysize') = 1 The default value is set by the Cursor.arraysize attribute. Fetches several rows from the resultset. [clinic start generated code]*/ static PyObject * -pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, int maxrows) -/*[clinic end generated code: output=a8ef31fea64d0906 input=035dbe44a1005bf2]*/ +pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, uint32_t maxrows) +/*[clinic end generated code: output=3325f2b477c71baf input=a509c412aa70b27e]*/ { PyObject* row; PyObject* list; - int counter = 0; list = PyList_New(0); if (!list) { return NULL; } - while ((row = pysqlite_cursor_iternext((PyObject *)self))) { - if (PyList_Append(list, row) < 0) { - Py_DECREF(row); - break; - } + while (maxrows > 0 && (row = pysqlite_cursor_iternext((PyObject *)self))) { + int rc = PyList_Append(list, row); Py_DECREF(row); - - if (++counter == maxrows) { + if (rc < 0) { break; } + maxrows--; } if (PyErr_Occurred()) { @@ -1292,8 +1367,15 @@ pysqlite_cursor_close_impl(pysqlite_Cursor *self) } if (self->statement) { - (void)stmt_reset(self->statement); + int rc = stmt_reset(self->statement); + // Force self->statement to be NULL even if stmt_reset() may have + // failed to avoid a possible double-free if someone calls close() + // twice as a leak here would be better than a double-free. Py_CLEAR(self->statement); + if (rc != SQLITE_OK) { + cursor_cannot_reset_stmt_error(self, 0); + return NULL; + } } self->closed = 1; @@ -1301,6 +1383,30 @@ pysqlite_cursor_close_impl(pysqlite_Cursor *self) Py_RETURN_NONE; } +/*[clinic input] +@getter +_sqlite3.Cursor.arraysize +[clinic start generated code]*/ + +static PyObject * +_sqlite3_Cursor_arraysize_get_impl(pysqlite_Cursor *self) +/*[clinic end generated code: output=e0919d97175e6c50 input=3278f8d3ecbd90e3]*/ +{ + return PyLong_FromUInt32(self->arraysize); +} + +/*[clinic input] +@setter +_sqlite3.Cursor.arraysize +[clinic start generated code]*/ + +static int +_sqlite3_Cursor_arraysize_set_impl(pysqlite_Cursor *self, PyObject *value) +/*[clinic end generated code: output=af59a6b09f8cce6e input=ace48cb114e26060]*/ +{ + return PyLong_AsUInt32(value, &self->arraysize); +} + static PyMethodDef cursor_methods[] = { PYSQLITE_CURSOR_CLOSE_METHODDEF PYSQLITE_CURSOR_EXECUTEMANY_METHODDEF @@ -1318,7 +1424,6 @@ static struct PyMemberDef cursor_members[] = { {"connection", _Py_T_OBJECT, offsetof(pysqlite_Cursor, connection), Py_READONLY}, {"description", _Py_T_OBJECT, offsetof(pysqlite_Cursor, description), Py_READONLY}, - {"arraysize", Py_T_INT, offsetof(pysqlite_Cursor, arraysize), 0}, {"lastrowid", _Py_T_OBJECT, offsetof(pysqlite_Cursor, lastrowid), Py_READONLY}, {"rowcount", Py_T_LONG, offsetof(pysqlite_Cursor, rowcount), Py_READONLY}, {"row_factory", _Py_T_OBJECT, offsetof(pysqlite_Cursor, row_factory), 0}, @@ -1326,6 +1431,11 @@ static struct PyMemberDef cursor_members[] = {NULL} }; +static struct PyGetSetDef cursor_getsets[] = { + _SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF + {NULL}, +}; + static const char cursor_doc[] = PyDoc_STR("SQLite database cursor class."); @@ -1336,6 +1446,7 @@ static PyType_Slot cursor_slots[] = { {Py_tp_iternext, pysqlite_cursor_iternext}, {Py_tp_methods, cursor_methods}, {Py_tp_members, cursor_members}, + {Py_tp_getset, cursor_getsets}, {Py_tp_init, pysqlite_cursor_init}, {Py_tp_traverse, cursor_traverse}, {Py_tp_clear, cursor_clear}, diff --git a/Modules/_sqlite/cursor.h b/Modules/_sqlite/cursor.h index 42f817af7c5..c840a3d7ed0 100644 --- a/Modules/_sqlite/cursor.h +++ b/Modules/_sqlite/cursor.h @@ -35,7 +35,7 @@ typedef struct pysqlite_Connection* connection; PyObject* description; PyObject* row_cast_map; - int arraysize; + uint32_t arraysize; PyObject* lastrowid; long rowcount; PyObject* row_factory; diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 5464fd1227a..831dd9219f7 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -774,7 +774,6 @@ module_exec(PyObject *module) return 0; error: - sqlite3_shutdown(); return -1; } diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c index 31092417cb4..0e2812e1e4f 100644 --- a/Modules/_sqlite/prepare_protocol.c +++ b/Modules/_sqlite/prepare_protocol.c @@ -21,21 +21,21 @@ * 3. This notice may not be removed or altered from any source distribution. */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "prepare_protocol.h" +#include "pycore_object.h" // _PyObject_VisitType() + + static int pysqlite_prepare_protocol_init(PyObject *self, PyObject *args, PyObject *kwargs) { return 0; } -static int -pysqlite_prepare_protocol_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void pysqlite_prepare_protocol_dealloc(PyObject *self) { @@ -50,7 +50,7 @@ PyDoc_STRVAR(doc, "PEP 246 style object adaption protocol type."); static PyType_Slot type_slots[] = { {Py_tp_dealloc, pysqlite_prepare_protocol_dealloc}, {Py_tp_init, pysqlite_prepare_protocol_init}, - {Py_tp_traverse, pysqlite_prepare_protocol_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_doc, (void *)doc}, {0, NULL}, }; diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c index 736e60fd778..f31c699482f 100644 --- a/Modules/_sqlite/statement.c +++ b/Modules/_sqlite/statement.c @@ -21,10 +21,17 @@ * 3. This notice may not be removed or altered from any source distribution. */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "connection.h" #include "statement.h" #include "util.h" +#include "pycore_object.h" // _PyObject_VisitType() + + #define _pysqlite_Statement_CAST(op) ((pysqlite_Statement *)(op)) /* prototypes */ @@ -96,7 +103,12 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql) return self; error: - (void)sqlite3_finalize(stmt); + assert(PyErr_Occurred()); + if (sqlite3_finalize(stmt) != SQLITE_OK) { + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetString(connection->InternalError, "cannot finalize statement"); + _PyErr_ChainExceptions1(exc); + } return NULL; } @@ -107,22 +119,21 @@ stmt_dealloc(PyObject *op) PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(op); if (self->st) { + int rc; Py_BEGIN_ALLOW_THREADS - sqlite3_finalize(self->st); + rc = sqlite3_finalize(self->st); Py_END_ALLOW_THREADS - self->st = 0; + self->st = NULL; + if (rc != SQLITE_OK) { + pysqlite_state *state = PyType_GetModuleState(Py_TYPE(op)); + PyErr_SetString(state->InternalError, "cannot finalize statement"); + PyErr_FormatUnraisable("Exception ignored in stmt_dealloc()"); + } } tp->tp_free(self); Py_DECREF(tp); } -static int -stmt_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - /* * Strip leading whitespace and comments from incoming SQL (null terminated C * string) and return a pointer to the first non-whitespace, non-comment @@ -183,7 +194,7 @@ lstrip_sql(const char *sql) static PyType_Slot stmt_slots[] = { {Py_tp_dealloc, stmt_dealloc}, - {Py_tp_traverse, stmt_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL}, }; diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 103248ff55a..177e0f668a0 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -135,14 +135,14 @@ set_error_from_code(pysqlite_state *state, int code) /** * Checks the SQLite error code and sets the appropriate DB-API exception. */ -void +int set_error_from_db(pysqlite_state *state, sqlite3 *db) { int errorcode = sqlite3_errcode(db); PyObject *exc_class = get_exception_class(state, errorcode); if (exc_class == NULL) { // No new exception need be raised. - return; + return SQLITE_OK; } /* Create and set the exception. */ @@ -150,6 +150,7 @@ set_error_from_db(pysqlite_state *state, sqlite3 *db) // sqlite3_errmsg() always returns an UTF-8 encoded message const char *errmsg = sqlite3_errmsg(db); raise_exception(exc_class, extended_errcode, errmsg); + return errorcode; } #ifdef WORDS_BIGENDIAN diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h index f8e45baffae..c00369496f9 100644 --- a/Modules/_sqlite/util.h +++ b/Modules/_sqlite/util.h @@ -31,7 +31,7 @@ /** * Checks the SQLite error code and sets the appropriate DB-API exception. */ -void set_error_from_db(pysqlite_state *state, sqlite3 *db); +int set_error_from_db(pysqlite_state *state, sqlite3 *db); void set_error_from_code(pysqlite_state *state, int code); sqlite_int64 _pysqlite_long_as_int64(PyObject * value); diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 49eb52b635b..59ff9078e6c 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -1946,7 +1946,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) sre_match() code is robust even if they don't, and the worst you can get is nonsensical match results. */ GET_ARG; - if (arg > 2 * (size_t)groups + 1) { + if (arg >= 2 * (size_t)groups) { VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)groups)); FAIL; } @@ -2359,7 +2359,7 @@ match_getindex(MatchObject* self, PyObject* index) } // Check that i*2 cannot overflow to make static analyzers happy - assert(i <= SRE_MAXGROUPS); + assert((size_t)i <= SRE_MAXGROUPS); return i; } @@ -2841,20 +2841,25 @@ scanner_dealloc(PyObject *self) static int scanner_begin(ScannerObject* self) { - if (self->executing) { +#ifdef Py_GIL_DISABLED + int was_executing = _Py_atomic_exchange_int(&self->executing, 1); +#else + int was_executing = self->executing; + self->executing = 1; +#endif + if (was_executing) { PyErr_SetString(PyExc_ValueError, "regular expression scanner already executing"); return 0; } - self->executing = 1; return 1; } static void scanner_end(ScannerObject* self) { - assert(self->executing); - self->executing = 0; + assert(FT_ATOMIC_LOAD_INT_RELAXED(self->executing)); + FT_ATOMIC_STORE_INT(self->executing, 0); } /*[clinic input] diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f215bb11308..25fcea6aaf1 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -148,7 +148,7 @@ static void _PySSLFixErrno(void) { #endif /* Include generated data (error codes) */ -/* See make_ssl_data.h for notes on adding a new version. */ +/* See Tools/ssl/make_ssl_data.py for notes on adding a new version. */ #if (OPENSSL_VERSION_NUMBER >= 0x30401000L) #include "_ssl_data_35.h" #elif (OPENSSL_VERSION_NUMBER >= 0x30100000L) @@ -937,7 +937,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, } /* bpo43522 and OpenSSL < 1.1.1l: copy hostflags manually */ -#if OPENSSL_VERSION < 0x101010cf +#if OPENSSL_VERSION_NUMBER < 0x101010cf X509_VERIFY_PARAM *ssl_verification_params = SSL_get0_param(self->ssl); X509_VERIFY_PARAM *ssl_ctx_verification_params = SSL_CTX_get0_param(ctx); @@ -1437,14 +1437,14 @@ _get_peer_alt_names (_sslmodulestate *state, X509 *certificate) { } PyTuple_SET_ITEM(t, 0, v); - if (name->d.ip->length == 4) { - unsigned char *p = name->d.ip->data; + if (ASN1_STRING_length(name->d.ip) == 4) { + const unsigned char *p = ASN1_STRING_get0_data(name->d.ip); v = PyUnicode_FromFormat( "%d.%d.%d.%d", p[0], p[1], p[2], p[3] ); - } else if (name->d.ip->length == 16) { - unsigned char *p = name->d.ip->data; + } else if (ASN1_STRING_length(name->d.ip) == 16) { + const unsigned char *p = ASN1_STRING_get0_data(name->d.ip); v = PyUnicode_FromFormat( "%X:%X:%X:%X:%X:%X:%X:%X", p[0] << 8 | p[1], @@ -1575,8 +1575,9 @@ _get_aia_uri(X509 *certificate, int nid) { continue; } uri = ad->location->d.uniformResourceIdentifier; - ostr = PyUnicode_FromStringAndSize((char *)uri->data, - uri->length); + ostr = PyUnicode_FromStringAndSize( + (const char *)ASN1_STRING_get0_data(uri), + ASN1_STRING_length(uri)); if (ostr == NULL) { goto fail; } @@ -1642,8 +1643,9 @@ _get_crl_dp(X509 *certificate) { continue; } uri = gn->d.uniformResourceIdentifier; - ouri = PyUnicode_FromStringAndSize((char *)uri->data, - uri->length); + ouri = PyUnicode_FromStringAndSize( + (const char *)ASN1_STRING_get0_data(uri), + ASN1_STRING_length(uri)); if (ouri == NULL) goto done; @@ -1858,14 +1860,14 @@ _certificate_to_der(_sslmodulestate *state, X509 *certificate) /*[clinic input] _ssl._test_decode_cert - path: object(converter="PyUnicode_FSConverter") + path: unicode_fs_encoded / [clinic start generated code]*/ static PyObject * _ssl__test_decode_cert_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=96becb9abb23c091 input=cdeaaf02d4346628]*/ +/*[clinic end generated code: output=96becb9abb23c091 input=cb4988d5e651a4f8]*/ { PyObject *retval = NULL; X509 *x=NULL; @@ -1895,7 +1897,6 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path) X509_free(x); fail0: - Py_DECREF(path); if (cert != NULL) BIO_free(cert); return retval; } @@ -2200,6 +2201,56 @@ _ssl__SSLSocket_group_impl(PySSLSocket *self) #endif } +static PyObject * +ssl_socket_signame_impl(PySSLSocket *socket, + enum py_ssl_server_or_client self_socket_type) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30500000L + int ret; + const char *sigalg; + + if (socket->ssl == NULL) { + Py_RETURN_NONE; + } + ret = (socket->socket_type == self_socket_type) + ? SSL_get0_signature_name(socket->ssl, &sigalg) + : SSL_get0_peer_signature_name(socket->ssl, &sigalg); + if (ret == 0) { + Py_RETURN_NONE; + } + assert(sigalg != NULL); + return PyUnicode_DecodeFSDefault(sigalg); +#else + PyErr_SetString(PyExc_NotImplementedError, + "Getting sig algorithms requires OpenSSL 3.5 or later."); + return NULL; +#endif +} + +/*[clinic input] +@critical_section +_ssl._SSLSocket.client_sigalg +[clinic start generated code]*/ + +static PyObject * +_ssl__SSLSocket_client_sigalg_impl(PySSLSocket *self) +/*[clinic end generated code: output=499dd7fbf021a47b input=a0d9696b5414c627]*/ +{ + return ssl_socket_signame_impl(self, PY_SSL_CLIENT); +} + +/*[clinic input] +@critical_section +_ssl._SSLSocket.server_sigalg +[clinic start generated code]*/ + +static PyObject * +_ssl__SSLSocket_server_sigalg_impl(PySSLSocket *self) +/*[clinic end generated code: output=c508a766a8e275dc input=9063e562a1e6b946]*/ +{ + return ssl_socket_signame_impl(self, PY_SSL_SERVER); +} + /*[clinic input] @critical_section _ssl._SSLSocket.version @@ -2841,7 +2892,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, int group_right_1, Py_buffer *buffer) /*[clinic end generated code: output=49b16e6406023734 input=80ed30436df01a71]*/ { - PyObject *dest = NULL; + PyBytesWriter *writer = NULL; char *mem; size_t count = 0; int retval; @@ -2868,14 +2919,16 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, } if (!group_right_1) { - dest = PyBytes_FromStringAndSize(NULL, len); - if (dest == NULL) - goto error; if (len == 0) { Py_XDECREF(sock); - return dest; + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - mem = PyBytes_AS_STRING(dest); + + writer = PyBytesWriter_Create(len); + if (writer == NULL) { + goto error; + } + mem = PyBytesWriter_GetData(writer); } else { mem = buffer->buf; @@ -2953,8 +3006,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, done: Py_XDECREF(sock); if (!group_right_1) { - _PyBytes_Resize(&dest, count); - return dest; + return PyBytesWriter_FinishWithSize(writer, count); } else { return PyLong_FromSize_t(count); @@ -2963,8 +3015,9 @@ done: error: PySSL_ChainExceptions(self); Py_XDECREF(sock); - if (!group_right_1) - Py_XDECREF(dest); + if (!group_right_1) { + PyBytesWriter_Discard(writer); + } return NULL; } @@ -3276,6 +3329,8 @@ static PyMethodDef PySSLMethods[] = { _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF _SSL__SSLSOCKET_CIPHER_METHODDEF _SSL__SSLSOCKET_GROUP_METHODDEF + _SSL__SSLSOCKET_CLIENT_SIGALG_METHODDEF + _SSL__SSLSOCKET_SERVER_SIGALG_METHODDEF _SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF _SSL__SSLSOCKET_VERSION_METHODDEF _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF @@ -3614,6 +3669,25 @@ _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist) Py_RETURN_NONE; } +/*[clinic input] +@critical_section +_ssl._SSLContext.set_ciphersuites + ciphersuites: str + / +[clinic start generated code]*/ + +static PyObject * +_ssl__SSLContext_set_ciphersuites_impl(PySSLContext *self, + const char *ciphersuites) +/*[clinic end generated code: output=9915bec58e54d76d input=2afcc3693392be41]*/ +{ + if (!SSL_CTX_set_ciphersuites(self->ctx, ciphersuites)) { + _setSSLError(get_state_ctx(self), "No cipher suite can be selected.", 0, __FILE__, __LINE__); + return NULL; + } + Py_RETURN_NONE; +} + /*[clinic input] @critical_section _ssl._SSLContext.get_ciphers @@ -3708,7 +3782,6 @@ _ssl__SSLContext_get_groups_impl(PySSLContext *self, int include_aliases) num = sk_OPENSSL_CSTRING_num(groups); result = PyList_New(num); if (result == NULL) { - _setSSLError(get_state_ctx(self), "Can't allocate list", 0, __FILE__, __LINE__); goto error; } @@ -3720,9 +3793,7 @@ _ssl__SSLContext_get_groups_impl(PySSLContext *self, int include_aliases) // Group names are plain ASCII, so there's no chance of a decoding // error here. However, an allocation failure could occur when // constructing the Unicode version of the names. - item = PyUnicode_DecodeASCII(group, strlen(group), "strict"); - if (item == NULL) { - _setSSLError(get_state_ctx(self), "Can't allocate group name", 0, __FILE__, __LINE__); + if ((item = PyUnicode_DecodeFSDefault(group)) == NULL) { goto error; } @@ -3742,6 +3813,49 @@ error: #endif } +/*[clinic input] +@critical_section +_ssl._SSLContext.set_client_sigalgs + sigalgslist: str + / +[clinic start generated code]*/ + +static PyObject * +_ssl__SSLContext_set_client_sigalgs_impl(PySSLContext *self, + const char *sigalgslist) +/*[clinic end generated code: output=f4f5be160a29c7d6 input=500d853ce9fd94ff]*/ +{ +#ifdef OPENSSL_IS_AWSLC + _setSSLError(get_state_ctx(self), "can't set client sigalgs on AWS-LC", 0, __FILE__, __LINE__); + return NULL; +#else + if (!SSL_CTX_set1_client_sigalgs_list(self->ctx, sigalgslist)) { + _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__); + return NULL; + } + Py_RETURN_NONE; +#endif +} + +/*[clinic input] +@critical_section +_ssl._SSLContext.set_server_sigalgs + sigalgslist: str + / +[clinic start generated code]*/ + +static PyObject * +_ssl__SSLContext_set_server_sigalgs_impl(PySSLContext *self, + const char *sigalgslist) +/*[clinic end generated code: output=31ecb1d310285644 input=653b752e4f8d801b]*/ +{ + if (!SSL_CTX_set1_sigalgs_list(self->ctx, sigalgslist)) { + _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__); + return NULL; + } + Py_RETURN_NONE; +} + static int do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen, const unsigned char *server_protocols, unsigned int server_protocols_len, @@ -5595,7 +5709,10 @@ static struct PyMethodDef context_methods[] = { _SSL__SSLCONTEXT__WRAP_SOCKET_METHODDEF _SSL__SSLCONTEXT__WRAP_BIO_METHODDEF _SSL__SSLCONTEXT_SET_CIPHERS_METHODDEF + _SSL__SSLCONTEXT_SET_CIPHERSUITES_METHODDEF _SSL__SSLCONTEXT_SET_GROUPS_METHODDEF + _SSL__SSLCONTEXT_SET_CLIENT_SIGALGS_METHODDEF + _SSL__SSLCONTEXT_SET_SERVER_SIGALGS_METHODDEF _SSL__SSLCONTEXT__SET_ALPN_PROTOCOLS_METHODDEF _SSL__SSLCONTEXT_LOAD_CERT_CHAIN_METHODDEF _SSL__SSLCONTEXT_LOAD_DH_PARAMS_METHODDEF @@ -5672,19 +5789,11 @@ _ssl_MemoryBIO_impl(PyTypeObject *type) return (PyObject *) self; } -static int -memory_bio_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void memory_bio_dealloc(PyObject *op) { PySSLMemoryBIO *self = PySSLMemoryBIO_CAST(op); PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); (void)BIO_free(self->bio); tp->tp_free(self); Py_DECREF(tp); @@ -5741,30 +5850,29 @@ _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len) /*[clinic end generated code: output=a657aa1e79cd01b3 input=21046f2d7dac3a90]*/ { int avail, nbytes; - PyObject *result; avail = (int)Py_MIN(BIO_ctrl_pending(self->bio), INT_MAX); if ((len < 0) || (len > avail)) len = avail; - result = PyBytes_FromStringAndSize(NULL, len); - if ((result == NULL) || (len == 0)) - return result; + if (len == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } - nbytes = BIO_read(self->bio, PyBytes_AS_STRING(result), len); + PyBytesWriter *writer = PyBytesWriter_Create(len); + if (writer == NULL) { + return NULL; + } + + nbytes = BIO_read(self->bio, PyBytesWriter_GetData(writer), len); if (nbytes < 0) { _sslmodulestate *state = get_state_mbio(self); - Py_DECREF(result); + PyBytesWriter_Discard(writer); _setSSLError(state, NULL, 0, __FILE__, __LINE__); return NULL; } - /* There should never be any short reads but check anyway. */ - if (nbytes < len) { - _PyBytes_Resize(&result, nbytes); - } - - return result; + return PyBytesWriter_FinishWithSize(writer, nbytes); } /*[clinic input] @@ -5849,15 +5957,13 @@ static PyType_Slot PySSLMemoryBIO_slots[] = { {Py_tp_getset, memory_bio_getsetlist}, {Py_tp_new, _ssl_MemoryBIO}, {Py_tp_dealloc, memory_bio_dealloc}, - {Py_tp_traverse, memory_bio_traverse}, {0, 0}, }; static PyType_Spec PySSLMemoryBIO_spec = { .name = "_ssl.MemoryBIO", .basicsize = sizeof(PySSLMemoryBIO), - .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | - Py_TPFLAGS_HAVE_GC), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), .slots = PySSLMemoryBIO_slots, }; @@ -6221,6 +6327,39 @@ _ssl_get_default_verify_paths_impl(PyObject *module) return NULL; } +/*[clinic input] +_ssl.get_sigalgs +[clinic start generated code]*/ + +static PyObject * +_ssl_get_sigalgs_impl(PyObject *module) +/*[clinic end generated code: output=ab0791b63856854b input=d96dd6cefec3f86b]*/ +{ +#if OPENSSL_VERSION_NUMBER >= 0x30400000L + const char *sigalgs; + PyObject *sigalgs_str, *sigalgs_list; + + if ((sigalgs = SSL_get1_builtin_sigalgs(NULL)) == NULL) { + PyErr_NoMemory(); + return NULL; + } + + if ((sigalgs_str = PyUnicode_DecodeFSDefault(sigalgs)) == NULL) { + OPENSSL_free((void *)sigalgs); + return NULL; + } + + OPENSSL_free((void *)sigalgs); + sigalgs_list = PyUnicode_Split(sigalgs_str, _Py_LATIN1_CHR(':'), -1); + Py_DECREF(sigalgs_str); + return sigalgs_list; +#else + PyErr_SetString(PyExc_NotImplementedError, + "Getting signature algorithms requires OpenSSL 3.4 or later."); + return NULL; +#endif +} + static PyObject* asn1obj2py(_sslmodulestate *state, ASN1_OBJECT *obj) { @@ -6624,6 +6763,7 @@ static PyMethodDef PySSL_methods[] = { _SSL_RAND_BYTES_METHODDEF _SSL_RAND_STATUS_METHODDEF _SSL_GET_DEFAULT_VERIFY_PATHS_METHODDEF + _SSL_GET_SIGALGS_METHODDEF _SSL_ENUM_CERTIFICATES_METHODDEF _SSL_ENUM_CRLS_METHODDEF _SSL_TXT2OBJ_METHODDEF diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index aee446d0ccb..866c172e499 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -131,7 +131,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) PyThread_type_lock lock = get_state_sock(ssl_obj)->keylog_lock; assert(lock != NULL); if (ssl_obj->ctx->keylog_bio == NULL) { - return; + goto done; } /* * The lock is neither released on exit nor on fork(). The lock is @@ -155,6 +155,8 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) ssl_obj->ctx->keylog_filename); ssl_obj->exc = PyErr_GetRaisedException(); } + +done: PyGILState_Release(threadstate); } diff --git a/Modules/_ssl_data_35.h b/Modules/_ssl_data_35.h index 9e69eaa910f..e4919b550e3 100644 --- a/Modules/_ssl_data_35.h +++ b/Modules/_ssl_data_35.h @@ -1,6 +1,6 @@ /* File generated by Tools/ssl/make_ssl_data.py */ -/* Generated on 2025-08-13T16:42:33.155822+00:00 */ -/* Generated from Git commit openssl-3.5.2-0-g0893a6235 */ +/* Generated on 2025-10-04T17:49:19.148321+00:00 */ +/* Generated from Git commit openssl-3.5.4-0-gc1eeb9406 */ /* generated from args.lib2errnum */ static struct py_ssl_library_code library_codes[] = { @@ -5338,6 +5338,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"FIPS_MODULE_ENTERING_ERROR_STATE", 57, 224}, #endif + #ifdef PROV_R_FIPS_MODULE_IMPORT_PCT_ERROR + {"FIPS_MODULE_IMPORT_PCT_ERROR", ERR_LIB_PROV, PROV_R_FIPS_MODULE_IMPORT_PCT_ERROR}, + #else + {"FIPS_MODULE_IMPORT_PCT_ERROR", 57, 253}, + #endif #ifdef PROV_R_FIPS_MODULE_IN_ERROR_STATE {"FIPS_MODULE_IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_IN_ERROR_STATE}, #else diff --git a/Modules/_struct.c b/Modules/_struct.c index 3fad35a8c94..2acb3df3a30 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -9,6 +9,7 @@ #include "Python.h" #include "pycore_bytesobject.h" // _PyBytesWriter +#include "pycore_lock.h" // _PyOnceFlag_CallOnce() #include "pycore_long.h" // _PyLong_AsByteArray() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() @@ -1505,6 +1506,53 @@ static formatdef lilendian_table[] = { {0} }; +/* Ensure endian table optimization happens exactly once across all interpreters */ +static _PyOnceFlag endian_tables_init_once = {0}; + +static int +init_endian_tables(void *Py_UNUSED(arg)) +{ + const formatdef *native = native_table; + formatdef *other, *ptr; +#if PY_LITTLE_ENDIAN + other = lilendian_table; +#else + other = bigendian_table; +#endif + /* Scan through the native table, find a matching + entry in the endian table and swap in the + native implementations whenever possible + (64-bit platforms may not have "standard" sizes) */ + while (native->format != '\0' && other->format != '\0') { + ptr = other; + while (ptr->format != '\0') { + if (ptr->format == native->format) { + /* Match faster when formats are + listed in the same order */ + if (ptr == other) + other++; + /* Only use the trick if the + size matches */ + if (ptr->size != native->size) + break; + /* Skip float and double, could be + "unknown" float format */ + if (ptr->format == 'd' || ptr->format == 'f') + break; + /* Skip _Bool, semantics are different for standard size */ + if (ptr->format == '?') + break; + ptr->pack = native->pack; + ptr->unpack = native->unpack; + break; + } + ptr++; + } + native++; + } + return 0; +} + static const formatdef * whichtable(const char **pfmt) @@ -2189,7 +2237,6 @@ strings."); static PyObject * s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - char *buf; PyStructObject *soself; _structmodulestate *state = get_struct_state_structinst(self); @@ -2205,21 +2252,19 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } /* Allocate a new string */ - _PyBytesWriter writer; - _PyBytesWriter_Init(&writer); - buf = _PyBytesWriter_Alloc(&writer, soself->s_size); - if (buf == NULL) { - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter *writer = PyBytesWriter_Create(soself->s_size); + if (writer == NULL) { return NULL; } + char *buf = PyBytesWriter_GetData(writer); /* Call the guts */ if ( s_pack_internal(soself, args, 0, buf, state) != 0 ) { - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } - return _PyBytesWriter_Finish(&writer, buf + soself->s_size); + return PyBytesWriter_FinishWithSize(writer, soself->s_size); } PyDoc_STRVAR(s_pack_into__doc__, @@ -2713,47 +2758,8 @@ _structmodule_exec(PyObject *m) return -1; } - /* Check endian and swap in faster functions */ - { - const formatdef *native = native_table; - formatdef *other, *ptr; -#if PY_LITTLE_ENDIAN - other = lilendian_table; -#else - other = bigendian_table; -#endif - /* Scan through the native table, find a matching - entry in the endian table and swap in the - native implementations whenever possible - (64-bit platforms may not have "standard" sizes) */ - while (native->format != '\0' && other->format != '\0') { - ptr = other; - while (ptr->format != '\0') { - if (ptr->format == native->format) { - /* Match faster when formats are - listed in the same order */ - if (ptr == other) - other++; - /* Only use the trick if the - size matches */ - if (ptr->size != native->size) - break; - /* Skip float and double, could be - "unknown" float format */ - if (ptr->format == 'd' || ptr->format == 'f') - break; - /* Skip _Bool, semantics are different for standard size */ - if (ptr->format == '?') - break; - ptr->pack = native->pack; - ptr->unpack = native->unpack; - break; - } - ptr++; - } - native++; - } - } + /* init cannot fail */ + (void)_PyOnceFlag_CallOnce(&endian_tables_init_once, init_endian_tables, NULL); /* Add some symbolic constants to the module */ state->StructError = PyErr_NewException("struct.error", NULL, NULL); diff --git a/Modules/_suggestions.c b/Modules/_suggestions.c index b8bc6db2477..fb588de7808 100644 --- a/Modules/_suggestions.c +++ b/Modules/_suggestions.c @@ -8,6 +8,7 @@ module _suggestions /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e58d81fafad5637b]*/ /*[clinic input] +@critical_section candidates _suggestions._generate_suggestions candidates: object item: unicode @@ -18,7 +19,7 @@ Returns the candidate in candidates that's closest to item static PyObject * _suggestions__generate_suggestions_impl(PyObject *module, PyObject *candidates, PyObject *item) -/*[clinic end generated code: output=79be7b653ae5e7ca input=ba2a8dddc654e33a]*/ +/*[clinic end generated code: output=79be7b653ae5e7ca input=92861a6c9bd8f667]*/ { // Check if dir is a list if (!PyList_CheckExact(candidates)) { @@ -29,7 +30,7 @@ _suggestions__generate_suggestions_impl(PyObject *module, // Check if all elements in the list are Unicode Py_ssize_t size = PyList_Size(candidates); for (Py_ssize_t i = 0; i < size; ++i) { - PyObject *elem = PyList_GetItem(candidates, i); + PyObject *elem = PyList_GET_ITEM(candidates, i); if (!PyUnicode_Check(elem)) { PyErr_SetString(PyExc_TypeError, "all elements in 'candidates' must be strings"); return NULL; diff --git a/Modules/_testcapi/bytes.c b/Modules/_testcapi/bytes.c index 33903de14ba..f12fc7f5f3a 100644 --- a/Modules/_testcapi/bytes.c +++ b/Modules/_testcapi/bytes.c @@ -1,6 +1,11 @@ +// Use pycore_bytes.h +#define PYTESTCAPI_NEED_INTERNAL_API + #include "parts.h" #include "util.h" +#include "pycore_bytesobject.h" // _PyBytesWriter_CreateByteArray() + /* Test _PyBytes_Resize() */ static PyObject * @@ -51,9 +56,307 @@ bytes_join(PyObject *Py_UNUSED(module), PyObject *args) } +// --- PyBytesWriter type --------------------------------------------------- + +typedef struct { + PyObject_HEAD + PyBytesWriter *writer; +} WriterObject; + + +static PyObject * +writer_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + WriterObject *self = (WriterObject *)type->tp_alloc(type, 0); + if (!self) { + return NULL; + } + self->writer = NULL; + return (PyObject*)self; +} + + +static int +writer_init(PyObject *self_raw, PyObject *args, PyObject *kwargs) +{ + if (kwargs && PyDict_GET_SIZE(kwargs)) { + PyErr_Format(PyExc_TypeError, + "PyBytesWriter() takes exactly no keyword arguments"); + return -1; + } + + Py_ssize_t alloc; + char *str; + Py_ssize_t str_size; + int use_bytearray; + if (!PyArg_ParseTuple(args, "ny#i", + &alloc, &str, &str_size, &use_bytearray)) { + return -1; + } + + WriterObject *self = (WriterObject *)self_raw; + if (self->writer) { + PyBytesWriter_Discard(self->writer); + } + if (use_bytearray) { + self->writer = _PyBytesWriter_CreateByteArray(alloc); + } + else { + self->writer = PyBytesWriter_Create(alloc); + } + if (self->writer == NULL) { + return -1; + } + + if (str_size) { + char *buf = PyBytesWriter_GetData(self->writer); + memcpy(buf, str, str_size); + } + + return 0; +} + + +static void +writer_dealloc(PyObject *self_raw) +{ + WriterObject *self = (WriterObject *)self_raw; + PyTypeObject *tp = Py_TYPE(self); + if (self->writer) { + PyBytesWriter_Discard(self->writer); + } + tp->tp_free(self); + Py_DECREF(tp); +} + + +static inline int +writer_check(WriterObject *self) +{ + if (self->writer == NULL) { + PyErr_SetString(PyExc_ValueError, "operation on finished writer"); + return -1; + } + return 0; +} + + +static PyObject* +writer_write_bytes(PyObject *self_raw, PyObject *args) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + char *bytes; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "yn", &bytes, &size)) { + return NULL; + } + + if (PyBytesWriter_WriteBytes(self->writer, bytes, size) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + +static PyObject* +writer_format_i(PyObject *self_raw, PyObject *args) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + char *format; + int value; + if (!PyArg_ParseTuple(args, "yi", &format, &value)) { + return NULL; + } + + if (PyBytesWriter_Format(self->writer, format, value) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + +static PyObject* +writer_resize(PyObject *self_raw, PyObject *args) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + Py_ssize_t size; + char *str; + Py_ssize_t str_size; + if (!PyArg_ParseTuple(args, + "ny#", + &size, &str, &str_size)) { + return NULL; + } + assert(size >= str_size); + + Py_ssize_t pos = PyBytesWriter_GetSize(self->writer); + if (PyBytesWriter_Resize(self->writer, size) < 0) { + return NULL; + } + + char *buf = PyBytesWriter_GetData(self->writer); + memcpy(buf + pos, str, str_size); + + Py_RETURN_NONE; +} + + +static PyObject* +writer_get_size(PyObject *self_raw, PyObject *Py_UNUSED(args)) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + Py_ssize_t alloc = PyBytesWriter_GetSize(self->writer); + return PyLong_FromSsize_t(alloc); +} + + +static PyObject* +writer_finish(PyObject *self_raw, PyObject *Py_UNUSED(args)) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + PyObject *str = PyBytesWriter_Finish(self->writer); + self->writer = NULL; + return str; +} + + +static PyObject* +writer_finish_with_size(PyObject *self_raw, PyObject *args) +{ + WriterObject *self = (WriterObject *)self_raw; + if (writer_check(self) < 0) { + return NULL; + } + + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "n", &size)) { + return NULL; + } + + PyObject *str = PyBytesWriter_FinishWithSize(self->writer, size); + self->writer = NULL; + return str; +} + + +static PyMethodDef writer_methods[] = { + {"write_bytes", _PyCFunction_CAST(writer_write_bytes), METH_VARARGS}, + {"format_i", _PyCFunction_CAST(writer_format_i), METH_VARARGS}, + {"resize", _PyCFunction_CAST(writer_resize), METH_VARARGS}, + {"get_size", _PyCFunction_CAST(writer_get_size), METH_NOARGS}, + {"finish", _PyCFunction_CAST(writer_finish), METH_NOARGS}, + {"finish_with_size", _PyCFunction_CAST(writer_finish_with_size), METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyType_Slot Writer_Type_slots[] = { + {Py_tp_new, writer_new}, + {Py_tp_init, writer_init}, + {Py_tp_dealloc, writer_dealloc}, + {Py_tp_methods, writer_methods}, + {0, 0}, /* sentinel */ +}; + +static PyType_Spec Writer_spec = { + .name = "_testcapi.PyBytesWriter", + .basicsize = sizeof(WriterObject), + .flags = Py_TPFLAGS_DEFAULT, + .slots = Writer_Type_slots, +}; + + +static PyObject * +byteswriter_abc(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + PyBytesWriter *writer = PyBytesWriter_Create(3); + if (writer == NULL) { + return NULL; + } + + char *str = PyBytesWriter_GetData(writer); + memcpy(str, "abc", 3); + + return PyBytesWriter_Finish(writer); +} + + +static PyObject * +byteswriter_resize(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + // Allocate 10 bytes + PyBytesWriter *writer = PyBytesWriter_Create(10); + if (writer == NULL) { + return NULL; + } + char *buf = PyBytesWriter_GetData(writer); + + // Write some bytes + memcpy(buf, "Hello ", strlen("Hello ")); + buf += strlen("Hello "); + + // Allocate 10 more bytes + buf = PyBytesWriter_GrowAndUpdatePointer(writer, 10, buf); + if (buf == NULL) { + PyBytesWriter_Discard(writer); + return NULL; + } + + // Write more bytes + memcpy(buf, "World", strlen("World")); + buf += strlen("World"); + + // Truncate to the exact size and create a bytes object + return PyBytesWriter_FinishWithPointer(writer, buf); +} + + +static PyObject * +byteswriter_highlevel(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + PyBytesWriter *writer = PyBytesWriter_Create(0); + if (writer == NULL) { + goto error; + } + if (PyBytesWriter_WriteBytes(writer, "Hello", -1) < 0) { + goto error; + } + if (PyBytesWriter_Format(writer, " %s!", "World") < 0) { + goto error; + } + return PyBytesWriter_Finish(writer); + +error: + PyBytesWriter_Discard(writer); + return NULL; +} + + static PyMethodDef test_methods[] = { {"bytes_resize", bytes_resize, METH_VARARGS}, {"bytes_join", bytes_join, METH_VARARGS}, + {"byteswriter_abc", byteswriter_abc, METH_NOARGS}, + {"byteswriter_resize", byteswriter_resize, METH_NOARGS}, + {"byteswriter_highlevel", byteswriter_highlevel, METH_NOARGS}, {NULL}, }; @@ -64,5 +367,15 @@ _PyTestCapi_Init_Bytes(PyObject *m) return -1; } + PyTypeObject *writer_type = (PyTypeObject *)PyType_FromSpec(&Writer_spec); + if (writer_type == NULL) { + return -1; + } + if (PyModule_AddType(m, writer_type) < 0) { + Py_DECREF(writer_type); + return -1; + } + Py_DECREF(writer_type); + return 0; } diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index 257e0256655..4fdcc850a33 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -528,6 +528,21 @@ pytype_getmodulebydef(PyObject *self, PyObject *type) return Py_XNewRef(mod); } +static PyObject * +pytype_getmodulebytoken(PyObject *self, PyObject *args) +{ + PyObject *type; + PyObject *py_token; + if (!PyArg_ParseTuple(args, "OO", &type, &py_token)) { + return NULL; + } + void *token = PyLong_AsVoidPtr(py_token); + if ((!token) && PyErr_Occurred()) { + return NULL; + } + return PyType_GetModuleByToken((PyTypeObject *)type, token); +} + static PyMethodDef TestMethods[] = { {"pytype_fromspec_meta", pytype_fromspec_meta, METH_O}, @@ -546,6 +561,7 @@ static PyMethodDef TestMethods[] = { {"get_tp_token", get_tp_token, METH_O}, {"pytype_getbasebytoken", pytype_getbasebytoken, METH_VARARGS}, {"pytype_getmodulebydef", pytype_getmodulebydef, METH_O}, + {"pytype_getmodulebytoken", pytype_getmodulebytoken, METH_VARARGS}, {NULL}, }; @@ -782,10 +798,7 @@ heapctypesubclasswithfinalizer_finalize(PyObject *self) /* Save the current exception, if any. */ PyObject *exc = PyErr_GetRaisedException(); - if (_testcapimodule == NULL) { - goto cleanup_finalize; - } - PyObject *m = PyState_FindModule(_testcapimodule); + PyObject *m = PyType_GetModule(Py_TYPE(self)); if (m == NULL) { goto cleanup_finalize; } @@ -1402,8 +1415,8 @@ _PyTestCapi_Init_Heaptype(PyObject *m) { if (subclass_with_finalizer_bases == NULL) { return -1; } - PyObject *HeapCTypeSubclassWithFinalizer = PyType_FromSpecWithBases( - &HeapCTypeSubclassWithFinalizer_spec, subclass_with_finalizer_bases); + PyObject *HeapCTypeSubclassWithFinalizer = PyType_FromModuleAndSpec( + m, &HeapCTypeSubclassWithFinalizer_spec, subclass_with_finalizer_bases); Py_DECREF(subclass_with_finalizer_bases); ADD("HeapCTypeSubclassWithFinalizer", HeapCTypeSubclassWithFinalizer); diff --git a/Modules/_testcapi/immortal.c b/Modules/_testcapi/immortal.c index 0663c3781d4..af510cab655 100644 --- a/Modules/_testcapi/immortal.c +++ b/Modules/_testcapi/immortal.c @@ -28,13 +28,13 @@ test_immortal_builtins(PyObject *self, PyObject *Py_UNUSED(ignored)) static PyObject * test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored)) { - for (int i = -5; i <= 256; i++) { + for (int i = -5; i <= 1024; i++) { PyObject *obj = PyLong_FromLong(i); assert(verify_immortality(obj)); int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; assert(has_int_immortal_bit); } - for (int i = 257; i <= 260; i++) { + for (int i = 1025; i <= 1030; i++) { PyObject *obj = PyLong_FromLong(i); assert(obj); int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; diff --git a/Modules/_testcapi/modsupport.c b/Modules/_testcapi/modsupport.c new file mode 100644 index 00000000000..6746eb9eb1e --- /dev/null +++ b/Modules/_testcapi/modsupport.c @@ -0,0 +1,55 @@ +#include "parts.h" + + + +static PyObject * +pyabiinfo_check(PyObject *Py_UNUSED(module), PyObject *args) +{ + const char *modname; + unsigned long maj, min, flags, buildver, abiver; + + if (!PyArg_ParseTuple(args, "zkkkkk", + &modname, &maj, &min, &flags, &buildver, &abiver)) + { + return NULL; + } + PyABIInfo info = { + .abiinfo_major_version = (uint8_t)maj, + .abiinfo_minor_version = (uint8_t)min, + .flags = (uint16_t)flags, + .build_version = (uint32_t)buildver, + .abi_version = (uint32_t)abiver}; + if (PyABIInfo_Check(&info, modname) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyMethodDef TestMethods[] = { + {"pyabiinfo_check", pyabiinfo_check, METH_VARARGS}, + {NULL}, +}; + +int +_PyTestCapi_Init_Modsupport(PyObject *m) +{ + if (PyModule_AddIntMacro(m, PyABIInfo_STABLE) < 0) { + return -1; + } + if (PyModule_AddIntMacro(m, PyABIInfo_INTERNAL) < 0) { + return -1; + } + if (PyModule_AddIntMacro(m, PyABIInfo_GIL) < 0) { + return -1; + } + if (PyModule_AddIntMacro(m, PyABIInfo_FREETHREADED) < 0) { + return -1; + } + if (PyModule_AddIntMacro(m, PyABIInfo_FREETHREADING_AGNOSTIC) < 0) { + return -1; + } + if (PyModule_AddFunctions(m, TestMethods) < 0) { + return -1; + } + return 0; +} diff --git a/Modules/_testcapi/module.c b/Modules/_testcapi/module.c new file mode 100644 index 00000000000..7b5861bc08e --- /dev/null +++ b/Modules/_testcapi/module.c @@ -0,0 +1,401 @@ +#include "parts.h" +#include "util.h" + +// Test PyModule_* API + +/* unittest Cases that use these functions are in: + * Lib/test/test_capi/test_module.py + */ + +static PyObject * +module_from_slots_empty(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + +static PyObject * +module_from_slots_null(PyObject *self, PyObject *spec) +{ + return PyModule_FromSlotsAndSpec(NULL, spec); +} + +static PyObject * +module_from_slots_name(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_name, "currently ignored..."}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + +static PyObject * +module_from_slots_doc(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_doc, "the docstring"}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + +static PyObject * +module_from_slots_size(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_state_size, (void*)123}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec); + if (!mod) { + return NULL; + } + return mod; +} + +static PyObject * +a_method(PyObject *self, PyObject *arg) +{ + return PyTuple_Pack(2, self, arg); +} + +static PyMethodDef a_methoddef_array[] = { + {"a_method", a_method, METH_O}, + {0}, +}; + +static PyObject * +module_from_slots_methods(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_methods, a_methoddef_array}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + +static int noop_traverse(PyObject *self, visitproc visit, void *arg) { + return 0; +} +static int noop_clear(PyObject *self) { return 0; } +static void noop_free(void *self) { } + +static PyObject * +module_from_slots_gc(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_state_traverse, noop_traverse}, + {Py_mod_state_clear, noop_clear}, + {Py_mod_state_free, noop_free}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec); + if (!mod) { + return NULL; + } + if (PyModule_Add(mod, "traverse", PyLong_FromVoidPtr(&noop_traverse)) < 0) { + Py_DECREF(mod); + return NULL; + } + if (PyModule_Add(mod, "clear", PyLong_FromVoidPtr(&noop_clear)) < 0) { + Py_DECREF(mod); + return NULL; + } + if (PyModule_Add(mod, "free", PyLong_FromVoidPtr(&noop_free)) < 0) { + Py_DECREF(mod); + return NULL; + } + return mod; +} + +static const char test_token; + +static PyObject * +module_from_slots_token(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_token, (void*)&test_token}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec); + if (!mod) { + return NULL; + } + void *got_token; + if (PyModule_GetToken(mod, &got_token) < 0) { + Py_DECREF(mod); + return NULL; + } + assert(got_token == &test_token); + return mod; +} + +static int +simple_exec(PyObject *module) +{ + return PyModule_AddIntConstant(module, "a_number", 456); +} + +static PyObject * +module_from_slots_exec(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_exec, simple_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + PyObject *mod = PyModule_FromSlotsAndSpec(slots, spec); + if (!mod) { + return NULL; + } + int res = PyObject_HasAttrStringWithError(mod, "a_number"); + if (res < 0) { + Py_DECREF(mod); + return NULL; + } + assert(res == 0); + if (PyModule_Exec(mod) < 0) { + Py_DECREF(mod); + return NULL; + } + return mod; +} + +static PyObject * +create_attr_from_spec(PyObject *spec, PyObject *def) +{ + assert(!def); + return PyObject_GetAttrString(spec, "_gimme_this"); +} + +static PyObject * +module_from_slots_create(PyObject *self, PyObject *spec) +{ + PyModuleDef_Slot slots[] = { + {Py_mod_create, create_attr_from_spec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + + +static int +slot_from_object(PyObject *obj) +{ + PyObject *slot_id_obj = PyObject_GetAttrString(obj, "_test_slot_id"); + if (slot_id_obj == NULL) { + return -1; + } + int slot_id = PyLong_AsInt(slot_id_obj); + if (PyErr_Occurred()) { + return -1; + } + return slot_id; +} + +static PyObject * +module_from_slots_repeat_slot(PyObject *self, PyObject *spec) +{ + int slot_id = slot_from_object(spec); + if (slot_id < 0) { + return NULL; + } + PyModuleDef_Slot slots[] = { + {slot_id, "anything"}, + {slot_id, "anything else"}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + +static PyObject * +module_from_slots_null_slot(PyObject *self, PyObject *spec) +{ + int slot_id = slot_from_object(spec); + if (slot_id < 0) { + return NULL; + } + PyModuleDef_Slot slots[] = { + {slot_id, NULL}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return PyModule_FromSlotsAndSpec(slots, spec); +} + +static PyObject * +module_from_def_slot(PyObject *self, PyObject *spec) +{ + int slot_id = slot_from_object(spec); + if (slot_id < 0) { + return NULL; + } + PyModuleDef_Slot slots[] = { + {slot_id, "anything"}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + PyModuleDef def = { + PyModuleDef_HEAD_INIT, + .m_name = "currently ignored", + .m_slots = slots, + }; + // PyModuleDef is normally static; the real requirement is that it + // must outlive its module. + // Here, module creation fails, so it's fine on the stack. + PyObject *result = PyModule_FromDefAndSpec(&def, spec); + assert(result == NULL); + return result; +} + +static int +another_exec(PyObject *module) +{ + /* Make sure simple_exec was called */ + assert(PyObject_HasAttrString(module, "a_number")); + + /* Add or negate a global called 'another_number' */ + PyObject *another_number; + if (PyObject_GetOptionalAttrString(module, "another_number", + &another_number) < 0) { + return -1; + } + if (!another_number) { + return PyModule_AddIntConstant(module, "another_number", 789); + } + PyObject *neg_number = PyNumber_Negative(another_number); + Py_DECREF(another_number); + if (!neg_number) { + return -1; + } + int result = PyObject_SetAttrString(module, "another_number", + neg_number); + Py_DECREF(neg_number); + return result; +} + +static PyObject * +module_from_def_multiple_exec(PyObject *self, PyObject *spec) +{ + static PyModuleDef_Slot slots[] = { + {Py_mod_exec, simple_exec}, + {Py_mod_exec, another_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + static PyModuleDef def = { + PyModuleDef_HEAD_INIT, + .m_name = "currently ignored", + .m_slots = slots, + }; + return PyModule_FromDefAndSpec(&def, spec); +} + +static PyObject * +pymodule_exec(PyObject *self, PyObject *module) +{ + if (PyModule_Exec(module) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +pymodule_get_token(PyObject *self, PyObject *module) +{ + void *token; + if (PyModule_GetToken(module, &token) < 0) { + return NULL; + } + return PyLong_FromVoidPtr(token); +} + +static PyObject * +pymodule_get_def(PyObject *self, PyObject *module) +{ + PyModuleDef *def = PyModule_GetDef(module); + if (!def && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromVoidPtr(def); +} + +static PyObject * +pymodule_get_state_size(PyObject *self, PyObject *module) +{ + Py_ssize_t size; + if (PyModule_GetStateSize(module, &size) < 0) { + return NULL; + } + return PyLong_FromSsize_t(size); +} + +static PyMethodDef test_methods[] = { + {"module_from_slots_empty", module_from_slots_empty, METH_O}, + {"module_from_slots_null", module_from_slots_null, METH_O}, + {"module_from_slots_name", module_from_slots_name, METH_O}, + {"module_from_slots_doc", module_from_slots_doc, METH_O}, + {"module_from_slots_size", module_from_slots_size, METH_O}, + {"module_from_slots_methods", module_from_slots_methods, METH_O}, + {"module_from_slots_gc", module_from_slots_gc, METH_O}, + {"module_from_slots_token", module_from_slots_token, METH_O}, + {"module_from_slots_exec", module_from_slots_exec, METH_O}, + {"module_from_slots_create", module_from_slots_create, METH_O}, + {"module_from_slots_repeat_slot", module_from_slots_repeat_slot, METH_O}, + {"module_from_slots_null_slot", module_from_slots_null_slot, METH_O}, + {"module_from_def_multiple_exec", module_from_def_multiple_exec, METH_O}, + {"module_from_def_slot", module_from_def_slot, METH_O}, + {"pymodule_get_token", pymodule_get_token, METH_O}, + {"pymodule_get_def", pymodule_get_def, METH_O}, + {"pymodule_get_state_size", pymodule_get_state_size, METH_O}, + {"pymodule_exec", pymodule_exec, METH_O}, + {NULL}, +}; + +int +_PyTestCapi_Init_Module(PyObject *m) +{ +#define ADD_INT_MACRO(C) if (PyModule_AddIntConstant(m, #C, C) < 0) return -1; + ADD_INT_MACRO(Py_mod_create); + ADD_INT_MACRO(Py_mod_exec); + ADD_INT_MACRO(Py_mod_multiple_interpreters); + ADD_INT_MACRO(Py_mod_gil); + ADD_INT_MACRO(Py_mod_name); + ADD_INT_MACRO(Py_mod_doc); + ADD_INT_MACRO(Py_mod_state_size); + ADD_INT_MACRO(Py_mod_methods); + ADD_INT_MACRO(Py_mod_state_traverse); + ADD_INT_MACRO(Py_mod_state_clear); + ADD_INT_MACRO(Py_mod_state_free); + ADD_INT_MACRO(Py_mod_token); +#undef ADD_INT_MACRO + if (PyModule_Add(m, "module_test_token", + PyLong_FromVoidPtr((void*)&test_token)) < 0) + { + return -1; + } + return PyModule_AddFunctions(m, test_methods); +} diff --git a/Modules/_testcapi/monitoring.c b/Modules/_testcapi/monitoring.c index e041943492d..3f99836c1eb 100644 --- a/Modules/_testcapi/monitoring.c +++ b/Modules/_testcapi/monitoring.c @@ -1,8 +1,6 @@ #include "parts.h" #include "util.h" -#include "monitoring.h" - #define Py_BUILD_CORE #include "internal/pycore_instruments.h" diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c index 798ef97c495..a4f76c409c6 100644 --- a/Modules/_testcapi/object.c +++ b/Modules/_testcapi/object.c @@ -138,6 +138,15 @@ pyobject_is_unique_temporary(PyObject *self, PyObject *obj) return PyLong_FromLong(result); } +static PyObject * +pyobject_is_unique_temporary_new_object(PyObject *self, PyObject *unused) +{ + PyObject *obj = PyList_New(0); + int result = PyUnstable_Object_IsUniqueReferencedTemporary(obj); + Py_DECREF(obj); + return PyLong_FromLong(result); +} + static int MyObject_dealloc_called = 0; static void @@ -485,6 +494,30 @@ is_uniquely_referenced(PyObject *self, PyObject *op) } +static PyObject * +pyobject_dump(PyObject *self, PyObject *args) +{ + PyObject *op; + int release_gil = 0; + + if (!PyArg_ParseTuple(args, "O|i", &op, &release_gil)) { + return NULL; + } + NULLABLE(op); + + if (release_gil) { + Py_BEGIN_ALLOW_THREADS + PyUnstable_Object_Dump(op); + Py_END_ALLOW_THREADS + + } + else { + PyUnstable_Object_Dump(op); + } + Py_RETURN_NONE; +} + + static PyMethodDef test_methods[] = { {"call_pyobject_print", call_pyobject_print, METH_VARARGS}, {"pyobject_print_null", pyobject_print_null, METH_VARARGS}, @@ -493,6 +526,7 @@ static PyMethodDef test_methods[] = { {"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O}, {"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O}, {"pyobject_is_unique_temporary", pyobject_is_unique_temporary, METH_O}, + {"pyobject_is_unique_temporary_new_object", pyobject_is_unique_temporary_new_object, METH_NOARGS}, {"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS}, {"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS}, {"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS}, @@ -511,6 +545,7 @@ static PyMethodDef test_methods[] = { {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS}, {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, {"is_uniquely_referenced", is_uniquely_referenced, METH_O}, + {"pyobject_dump", pyobject_dump, METH_VARARGS}, {NULL}, }; diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index af6400162da..a7feca5bd96 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -58,6 +58,7 @@ int _PyTestCapi_Init_Immortal(PyObject *module); int _PyTestCapi_Init_GC(PyObject *module); int _PyTestCapi_Init_Hash(PyObject *module); int _PyTestCapi_Init_Time(PyObject *module); +int _PyTestCapi_Init_Modsupport(PyObject *module); int _PyTestCapi_Init_Monitoring(PyObject *module); int _PyTestCapi_Init_Object(PyObject *module); int _PyTestCapi_Init_Config(PyObject *mod); @@ -65,5 +66,6 @@ int _PyTestCapi_Init_Import(PyObject *mod); int _PyTestCapi_Init_Frame(PyObject *mod); int _PyTestCapi_Init_Type(PyObject *mod); int _PyTestCapi_Init_Function(PyObject *mod); +int _PyTestCapi_Init_Module(PyObject *mod); #endif // Py_TESTCAPI_PARTS_H diff --git a/Modules/_testcapi/tuple.c b/Modules/_testcapi/tuple.c index d9c02ba0ff0..5de1c494c0a 100644 --- a/Modules/_testcapi/tuple.c +++ b/Modules/_testcapi/tuple.c @@ -104,12 +104,40 @@ _check_tuple_item_is_NULL(PyObject *Py_UNUSED(module), PyObject *args) } +static PyObject * +tuple_fromarray(PyObject* Py_UNUSED(module), PyObject *args) +{ + PyObject *src; + Py_ssize_t size = UNINITIALIZED_SIZE; + if (!PyArg_ParseTuple(args, "O|n", &src, &size)) { + return NULL; + } + if (src != Py_None && !PyTuple_Check(src)) { + PyErr_SetString(PyExc_TypeError, "expect a tuple"); + return NULL; + } + + PyObject **items; + if (src != Py_None) { + items = &PyTuple_GET_ITEM(src, 0); + if (size == UNINITIALIZED_SIZE) { + size = PyTuple_GET_SIZE(src); + } + } + else { + items = NULL; + } + return PyTuple_FromArray(items, size); +} + + static PyMethodDef test_methods[] = { {"tuple_get_size", tuple_get_size, METH_O}, {"tuple_get_item", tuple_get_item, METH_VARARGS}, {"tuple_set_item", tuple_set_item, METH_VARARGS}, {"_tuple_resize", _tuple_resize, METH_VARARGS}, {"_check_tuple_item_is_NULL", _check_tuple_item_is_NULL, METH_VARARGS}, + {"tuple_fromarray", tuple_fromarray, METH_VARARGS}, {NULL}, }; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index d0c0b45c20c..de6d3cbce54 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1583,9 +1583,9 @@ getitem_with_error(PyObject *self, PyObject *args) static PyObject * raise_SIGINT_then_send_None(PyObject *self, PyObject *args) { - PyGenObject *gen; + PyObject *gen; - if (!PyArg_ParseTuple(args, "O!", &PyGen_Type, &gen)) + if (!PyArg_ParseTuple(args, "O", &gen)) return NULL; /* This is used in a test to check what happens if a signal arrives just @@ -1599,7 +1599,7 @@ raise_SIGINT_then_send_None(PyObject *self, PyObject *args) because we check for signals before every bytecode operation. */ raise(SIGINT); - return PyObject_CallMethod((PyObject *)gen, "send", "O", Py_None); + return PyObject_CallMethod(gen, "send", "O", Py_None); } @@ -2206,9 +2206,8 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args)) static PyObject * test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) { - // Ignore PyWeakref_GetObject() deprecation, we test it on purpose - _Py_COMP_DIAG_PUSH - _Py_COMP_DIAG_IGNORE_DEPR_DECLS + // Get the function (removed in 3.15) from the stable ABI. + PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *); // Create a new heap type, create an instance of this type, and delete the // type. This object supports weak references. @@ -2249,19 +2248,12 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) ref = PyWeakref_GetObject(weakref); // borrowed ref assert(ref == obj); - // test PyWeakref_GET_OBJECT(), reference is alive - ref = PyWeakref_GET_OBJECT(weakref); // borrowed ref - assert(ref == obj); - // delete the referenced object: clear the weakref assert(Py_REFCNT(obj) == 1); Py_DECREF(obj); assert(PyWeakref_IsDead(weakref)); - // test PyWeakref_GET_OBJECT(), reference is dead - assert(PyWeakref_GET_OBJECT(weakref) == Py_None); - // test PyWeakref_GetRef(), reference is dead ref = UNINITIALIZED_PTR; assert(PyWeakref_GetRef(weakref, &ref) == 0); @@ -2312,13 +2304,12 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) Py_DECREF(weakref); Py_RETURN_NONE; - - _Py_COMP_DIAG_POP } struct simpletracer_data { int create_count; int destroy_count; + int tracker_removed; void* addresses[10]; }; @@ -2326,10 +2317,18 @@ static int _simpletracer(PyObject *obj, PyRefTracerEvent event, void* data) { struct simpletracer_data* the_data = (struct simpletracer_data*)data; assert(the_data->create_count + the_data->destroy_count < (int)Py_ARRAY_LENGTH(the_data->addresses)); the_data->addresses[the_data->create_count + the_data->destroy_count] = obj; - if (event == PyRefTracer_CREATE) { - the_data->create_count++; - } else { - the_data->destroy_count++; + switch (event) { + case PyRefTracer_CREATE: + the_data->create_count++; + break; + case PyRefTracer_DESTROY: + the_data->destroy_count++; + break; + case PyRefTracer_TRACKER_REMOVED: + the_data->tracker_removed++; + break; + default: + return -1; } return 0; } @@ -2393,6 +2392,10 @@ test_reftracer(PyObject *ob, PyObject *Py_UNUSED(ignored)) PyErr_SetString(PyExc_ValueError, "The object destruction was not correctly traced"); goto failed; } + if (tracer_data.tracker_removed != 1) { + PyErr_SetString(PyExc_ValueError, "The tracker removal was not correctly traced"); + goto failed; + } PyRefTracer_SetTracer(current_tracer, current_data); Py_RETURN_NONE; failed: @@ -2533,11 +2536,15 @@ code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf) static int _reftrace_printer(PyObject *obj, PyRefTracerEvent event, void *counter_data) { - if (event == PyRefTracer_CREATE) { - printf("CREATE %s\n", Py_TYPE(obj)->tp_name); - } - else { // PyRefTracer_DESTROY - printf("DESTROY %s\n", Py_TYPE(obj)->tp_name); + switch (event) { + case PyRefTracer_CREATE: + printf("CREATE %s\n", Py_TYPE(obj)->tp_name); + break; + case PyRefTracer_DESTROY: + printf("DESTROY %s\n", Py_TYPE(obj)->tp_name); + break; + case PyRefTracer_TRACKER_REMOVED: + return 0; } return 0; } @@ -2555,6 +2562,39 @@ toggle_reftrace_printer(PyObject *ob, PyObject *arg) Py_RETURN_NONE; } + +typedef struct { + PyObject_HEAD +} ManagedWeakrefNoGCObject; + +static void +ManagedWeakrefNoGC_dealloc(PyObject *self) +{ + PyObject_ClearWeakRefs(self); + PyTypeObject *tp = Py_TYPE(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot ManagedWeakrefNoGC_slots[] = { + {Py_tp_dealloc, ManagedWeakrefNoGC_dealloc}, + {0, 0} +}; + +static PyType_Spec ManagedWeakrefNoGC_spec = { + .name = "_testcapi.ManagedWeakrefNoGCType", + .basicsize = sizeof(ManagedWeakrefNoGCObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_MANAGED_WEAKREF), + .slots = ManagedWeakrefNoGC_slots, +}; + +static PyObject * +create_managed_weakref_nogc_type(PyObject *self, PyObject *Py_UNUSED(args)) +{ + return PyType_FromSpec(&ManagedWeakrefNoGC_spec); +} + + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -2649,6 +2689,8 @@ static PyMethodDef TestMethods[] = { {"test_atexit", test_atexit, METH_NOARGS}, {"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL}, {"toggle_reftrace_printer", toggle_reftrace_printer, METH_O}, + {"create_managed_weakref_nogc_type", + create_managed_weakref_nogc_type, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; @@ -3226,75 +3268,56 @@ create_managed_dict_type(void) return PyType_FromSpec(&ManagedDict_spec); } -static struct PyModuleDef _testcapimodule = { - PyModuleDef_HEAD_INIT, - .m_name = "_testcapi", - .m_size = sizeof(testcapistate_t), - .m_methods = TestMethods, -}; - -/* Per PEP 489, this module will not be converted to multi-phase initialization - */ - -PyMODINIT_FUNC -PyInit__testcapi(void) +static int +_testcapi_exec(PyObject *m) { - PyObject *m; - - m = PyModule_Create(&_testcapimodule); - if (m == NULL) - return NULL; -#ifdef Py_GIL_DISABLED - PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); -#endif - Py_SET_TYPE(&_HashInheritanceTester_Type, &PyType_Type); if (PyType_Ready(&_HashInheritanceTester_Type) < 0) { - return NULL; + return -1; } if (PyType_Ready(&matmulType) < 0) - return NULL; + return -1; Py_INCREF(&matmulType); PyModule_AddObject(m, "matmulType", (PyObject *)&matmulType); if (PyType_Ready(&ipowType) < 0) { - return NULL; + return -1; } Py_INCREF(&ipowType); PyModule_AddObject(m, "ipowType", (PyObject *)&ipowType); if (PyType_Ready(&awaitType) < 0) - return NULL; + return -1; Py_INCREF(&awaitType); PyModule_AddObject(m, "awaitType", (PyObject *)&awaitType); MyList_Type.tp_base = &PyList_Type; if (PyType_Ready(&MyList_Type) < 0) - return NULL; + return -1; Py_INCREF(&MyList_Type); PyModule_AddObject(m, "MyList", (PyObject *)&MyList_Type); if (PyType_Ready(&GenericAlias_Type) < 0) - return NULL; + return -1; Py_INCREF(&GenericAlias_Type); PyModule_AddObject(m, "GenericAlias", (PyObject *)&GenericAlias_Type); if (PyType_Ready(&Generic_Type) < 0) - return NULL; + return -1; Py_INCREF(&Generic_Type); PyModule_AddObject(m, "Generic", (PyObject *)&Generic_Type); if (PyType_Ready(&MethInstance_Type) < 0) - return NULL; + return -1; Py_INCREF(&MethInstance_Type); PyModule_AddObject(m, "MethInstance", (PyObject *)&MethInstance_Type); if (PyType_Ready(&MethClass_Type) < 0) - return NULL; + return -1; Py_INCREF(&MethClass_Type); PyModule_AddObject(m, "MethClass", (PyObject *)&MethClass_Type); if (PyType_Ready(&MethStatic_Type) < 0) - return NULL; + return -1; Py_INCREF(&MethStatic_Type); PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type); @@ -3336,14 +3359,18 @@ PyInit__testcapi(void) PyModule_AddObject(m, "INT64_MAX", PyLong_FromInt64(INT64_MAX)); PyModule_AddObject(m, "UINT64_MAX", PyLong_FromUInt64(UINT64_MAX)); + if (PyModule_AddIntMacro(m, _Py_STACK_GROWS_DOWN)) { + return -1; + } + if (PyModule_AddIntMacro(m, Py_single_input)) { - return NULL; + return -1; } if (PyModule_AddIntMacro(m, Py_file_input)) { - return NULL; + return -1; } if (PyModule_AddIntMacro(m, Py_eval_input)) { - return NULL; + return -1; } testcapistate_t *state = get_testcapi_state(m); @@ -3351,142 +3378,171 @@ PyInit__testcapi(void) PyModule_AddObject(m, "error", state->error); if (PyType_Ready(&ContainerNoGC_type) < 0) { - return NULL; + return -1; } Py_INCREF(&ContainerNoGC_type); if (PyModule_AddObject(m, "ContainerNoGC", (PyObject *) &ContainerNoGC_type) < 0) - return NULL; + return -1; PyObject *manual_heap_type = create_manual_heap_type(); if (manual_heap_type == NULL) { - return NULL; + return -1; } if (PyModule_Add(m, "ManualHeapType", manual_heap_type) < 0) { - return NULL; + return -1; } PyObject *managed_dict_type = create_managed_dict_type(); if (managed_dict_type == NULL) { - return NULL; + return -1; } if (PyModule_Add(m, "ManagedDictType", managed_dict_type) < 0) { - return NULL; + return -1; } /* Include tests from the _testcapi/ directory */ if (_PyTestCapi_Init_Vectorcall(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Heaptype(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Abstract(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Bytes(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Unicode(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_GetArgs(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_DateTime(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Docstring(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Mem(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Watchers(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Long(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Float(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Complex(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Numbers(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Dict(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Set(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_List(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Tuple(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Structmember(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Exceptions(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Code(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Buffer(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_File(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Codec(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Immortal(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_GC(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_PyAtomic(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Run(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Hash(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Time(m) < 0) { - return NULL; + return -1; + } + if (_PyTestCapi_Init_Modsupport(m) < 0) { + return -1; } if (_PyTestCapi_Init_Monitoring(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Object(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Config(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Import(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Frame(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Type(m) < 0) { - return NULL; + return -1; } if (_PyTestCapi_Init_Function(m) < 0) { - return NULL; + return -1; + } + if (_PyTestCapi_Init_Module(m) < 0) { + return -1; } - PyState_AddModule(m, &_testcapimodule); - return m; + return 0; +} + +PyABIInfo_VAR(abi_info); + +static PyModuleDef_Slot _testcapi_slots[] = { + {Py_mod_abi, &abi_info}, + {Py_mod_exec, _testcapi_exec}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; + +static struct PyModuleDef _testcapimodule = { + PyModuleDef_HEAD_INIT, + .m_name = "_testcapi", + .m_size = sizeof(testcapistate_t), + .m_methods = TestMethods, + .m_slots = _testcapi_slots +}; + +PyMODINIT_FUNC +PyInit__testcapi(void) +{ + return PyModuleDef_Init(&_testcapimodule); } diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index 3e903b6d87d..890f2201b46 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -63,7 +63,7 @@ pack_arguments_2pos_varpos(PyObject *a, PyObject *b, PyObject * const *args, Py_ssize_t args_length) /*[clinic end generated code: output=267032f41bd039cc input=86ee3064b7853e86]*/ { - PyObject *tuple = _PyTuple_FromArray(args, args_length); + PyObject *tuple = PyTuple_FromArray(args, args_length); if (tuple == NULL) { return NULL; } @@ -443,16 +443,21 @@ py_ssize_t_converter a: Py_ssize_t = 12 b: Py_ssize_t(accept={int}) = 34 c: Py_ssize_t(accept={int, NoneType}) = 56 + d: Py_ssize_t(accept={int}, allow_negative=False) = 78 + e: Py_ssize_t(accept={int, NoneType}, allow_negative=False) = 90 + f: Py_ssize_t(accept={int}, allow_negative=False) = -12 + g: Py_ssize_t(accept={int, NoneType}, py_default="-34", allow_negative=False) = -34 / [clinic start generated code]*/ static PyObject * py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b, - Py_ssize_t c) -/*[clinic end generated code: output=ce252143e0ed0372 input=76d0f342e9317a1f]*/ + Py_ssize_t c, Py_ssize_t d, Py_ssize_t e, + Py_ssize_t f, Py_ssize_t g) +/*[clinic end generated code: output=ecf8e1a4a9abc95e input=7b7fa954780c1cb0]*/ { - RETURN_PACKED_ARGS(3, PyLong_FromSsize_t, Py_ssize_t, a, b, c); + RETURN_PACKED_ARGS(7, PyLong_FromSsize_t, Py_ssize_t, a, b, c, d, e, f, g); } @@ -658,16 +663,16 @@ error: static PyObject * bytes_from_buffer(Py_buffer *buf) { - PyObject *bytes_obj = PyBytes_FromStringAndSize(NULL, buf->len); - if (!bytes_obj) { + PyBytesWriter *writer = PyBytesWriter_Create(buf->len); + if (writer == NULL) { return NULL; } - void *bytes_obj_buf = ((PyBytesObject *)bytes_obj)->ob_sval; - if (PyBuffer_ToContiguous(bytes_obj_buf, buf, buf->len, 'C') < 0) { - Py_DECREF(bytes_obj); + void *data = PyBytesWriter_GetData(writer); + if (PyBuffer_ToContiguous(data, buf, buf->len, 'C') < 0) { + PyBytesWriter_Discard(writer); return NULL; } - return bytes_obj; + return PyBytesWriter_Finish(writer); } /*[clinic input] @@ -1169,7 +1174,7 @@ varpos_array_impl(PyObject *module, PyObject * const *args, Py_ssize_t args_length) /*[clinic end generated code: output=a25f42f39c9b13ad input=97b8bdcf87e019c7]*/ { - return _PyTuple_FromArray(args, args_length); + return PyTuple_FromArray(args, args_length); } @@ -1605,7 +1610,7 @@ _testclinic_TestClass_varpos_array_no_fastcall_impl(PyTypeObject *type, Py_ssize_t args_length) /*[clinic end generated code: output=27c9da663e942617 input=9ba5ae1f1eb58777]*/ { - return _PyTuple_FromArray(args, args_length); + return PyTuple_FromArray(args, args_length); } @@ -2303,6 +2308,88 @@ depr_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, #undef _SAVED_PY_VERSION +/*[clinic input] +output pop +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e7c7c42daced52b0]*/ + + +/*[clinic input] +output push +destination kwarg new file '{dirname}/clinic/_testclinic_kwds.c.h' +output everything kwarg +output docstring_prototype suppress +output parser_prototype suppress +output impl_definition block +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=02965b54b3981cc4]*/ + +#include "clinic/_testclinic_kwds.c.h" + + +/*[clinic input] +lone_kwds + **kwds: dict +[clinic start generated code]*/ + +static PyObject * +lone_kwds_impl(PyObject *module, PyObject *kwds) +/*[clinic end generated code: output=572549c687a0432e input=6ef338b913ecae17]*/ +{ + return pack_arguments_newref(1, kwds); +} + + +/*[clinic input] +kwds_with_pos_only + a: object + b: object + / + **kwds: dict +[clinic start generated code]*/ + +static PyObject * +kwds_with_pos_only_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject *kwds) +/*[clinic end generated code: output=573096d3a7efcce5 input=da081a5d9ae8878a]*/ +{ + return pack_arguments_newref(3, a, b, kwds); +} + + +/*[clinic input] +kwds_with_stararg + *args: tuple + **kwds: dict +[clinic start generated code]*/ + +static PyObject * +kwds_with_stararg_impl(PyObject *module, PyObject *args, PyObject *kwds) +/*[clinic end generated code: output=d4b0064626a25208 input=1be404572d685859]*/ +{ + return pack_arguments_newref(2, args, kwds); +} + + +/*[clinic input] +kwds_with_pos_only_and_stararg + a: object + b: object + / + *args: tuple + **kwds: dict +[clinic start generated code]*/ + +static PyObject * +kwds_with_pos_only_and_stararg_impl(PyObject *module, PyObject *a, + PyObject *b, PyObject *args, + PyObject *kwds) +/*[clinic end generated code: output=af7df7640c792246 input=2fe330c7981f0829]*/ +{ + return pack_arguments_newref(4, a, b, args, kwds); +} + + /*[clinic input] output pop [clinic start generated code]*/ @@ -2399,6 +2486,12 @@ static PyMethodDef tester_methods[] = { DEPR_KWD_NOINLINE_METHODDEF DEPR_KWD_MULTI_METHODDEF DEPR_MULTI_METHODDEF + + LONE_KWDS_METHODDEF + KWDS_WITH_POS_ONLY_METHODDEF + KWDS_WITH_STARARG_METHODDEF + KWDS_WITH_POS_ONLY_AND_STARARG_METHODDEF + {NULL, NULL} }; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 243c7346576..a7fbb0f87b6 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -34,6 +34,7 @@ #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() #include "pycore_pylifecycle.h" // _PyInterpreterConfig_InitFromDict() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_runtime_structs.h" // _PY_NSMALLPOSINTS #include "pycore_unicodeobject.h" // _PyUnicode_TransformDecimalAndSpaceToASCII() #include "clinic/_testinternalcapi.c.h" @@ -125,6 +126,18 @@ get_c_recursion_remaining(PyObject *self, PyObject *Py_UNUSED(args)) return PyLong_FromLong(remaining); } +static PyObject* +get_stack_pointer(PyObject *self, PyObject *Py_UNUSED(args)) +{ + uintptr_t here_addr = _Py_get_machine_stack_pointer(); + return PyLong_FromSize_t(here_addr); +} + +static PyObject* +get_stack_margin(PyObject *self, PyObject *Py_UNUSED(args)) +{ + return PyLong_FromSize_t(_PyOS_STACK_MARGIN_BYTES); +} static PyObject* test_bswap(PyObject *self, PyObject *Py_UNUSED(args)) @@ -2237,6 +2250,13 @@ get_tlbc_id(PyObject *Py_UNUSED(module), PyObject *obj) } return PyLong_FromVoidPtr(bc); } + +static PyObject * +get_long_lived_total(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyLong_FromInt64(PyInterpreterState_Get()->gc.long_lived_total); +} + #endif static PyObject * @@ -2376,10 +2396,121 @@ emscripten_set_up_async_input_device(PyObject *self, PyObject *Py_UNUSED(ignored } #endif +static PyObject * +simple_pending_call(PyObject *self, PyObject *callable) +{ + if (_PyEval_AddPendingCall(_PyInterpreterState_GET(), _pending_callback, Py_NewRef(callable), 0) < 0) { + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +vectorcall_nop(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + Py_RETURN_NONE; +} + +static PyObject * +set_vectorcall_nop(PyObject *self, PyObject *func) +{ + if (!PyFunction_Check(func)) { + PyErr_SetString(PyExc_TypeError, "expected function"); + return NULL; + } + + ((PyFunctionObject*)func)->vectorcall = vectorcall_nop; + Py_RETURN_NONE; +} + +static PyObject * +module_get_gc_hooks(PyObject *self, PyObject *arg) +{ + PyModuleObject *mod = (PyModuleObject *)arg; + PyObject *traverse = NULL; + PyObject *clear = NULL; + PyObject *free = NULL; + PyObject *result = NULL; + traverse = PyLong_FromVoidPtr(mod->md_state_traverse); + if (!traverse) { + goto finally; + } + clear = PyLong_FromVoidPtr(mod->md_state_clear); + if (!clear) { + goto finally; + } + free = PyLong_FromVoidPtr(mod->md_state_free); + if (!free) { + goto finally; + } + result = PyTuple_FromArray((PyObject*[]){ traverse, clear, free }, 3); +finally: + Py_XDECREF(traverse); + Py_XDECREF(clear); + Py_XDECREF(free); + return result; +} + + +static void +check_threadstate_set_stack_protection(PyThreadState *tstate, + void *start, size_t size) +{ + assert(PyUnstable_ThreadState_SetStackProtection(tstate, start, size) == 0); + assert(!PyErr_Occurred()); + + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; + assert(ts->c_stack_top == (uintptr_t)start + size); + assert(ts->c_stack_hard_limit <= ts->c_stack_soft_limit); + assert(ts->c_stack_soft_limit < ts->c_stack_top); +} + + +static PyObject * +test_threadstate_set_stack_protection(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyThreadState *tstate = PyThreadState_GET(); + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; + assert(!PyErr_Occurred()); + + uintptr_t init_base = ts->c_stack_init_base; + size_t init_top = ts->c_stack_init_top; + + // Test the minimum stack size + size_t size = _PyOS_MIN_STACK_SIZE; + void *start = (void*)(_Py_get_machine_stack_pointer() - size); + check_threadstate_set_stack_protection(tstate, start, size); + + // Test a larger size + size = 7654321; + assert(size > _PyOS_MIN_STACK_SIZE); + start = (void*)(_Py_get_machine_stack_pointer() - size); + check_threadstate_set_stack_protection(tstate, start, size); + + // Test invalid size (too small) + size = 5; + start = (void*)(_Py_get_machine_stack_pointer() - size); + assert(PyUnstable_ThreadState_SetStackProtection(tstate, start, size) == -1); + assert(PyErr_ExceptionMatches(PyExc_ValueError)); + PyErr_Clear(); + + // Test PyUnstable_ThreadState_ResetStackProtection() + PyUnstable_ThreadState_ResetStackProtection(tstate); + assert(ts->c_stack_init_base == init_base); + assert(ts->c_stack_init_top == init_top); + + Py_RETURN_NONE; +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, {"get_c_recursion_remaining", get_c_recursion_remaining, METH_NOARGS}, + {"get_stack_pointer", get_stack_pointer, METH_NOARGS}, + {"get_stack_margin", get_stack_margin, METH_NOARGS}, {"test_bswap", test_bswap, METH_NOARGS}, {"test_popcount", test_popcount, METH_NOARGS}, {"test_bit_length", test_bit_length, METH_NOARGS}, @@ -2466,6 +2597,7 @@ static PyMethodDef module_functions[] = { {"py_thread_id", get_py_thread_id, METH_NOARGS}, {"get_tlbc", get_tlbc, METH_O, NULL}, {"get_tlbc_id", get_tlbc_id, METH_O, NULL}, + {"get_long_lived_total", get_long_lived_total, METH_NOARGS}, #endif #ifdef _Py_TIER2 {"uop_symbols_test", _Py_uop_symbols_test, METH_NOARGS}, @@ -2481,6 +2613,11 @@ static PyMethodDef module_functions[] = { #ifdef __EMSCRIPTEN__ {"emscripten_set_up_async_input_device", emscripten_set_up_async_input_device, METH_NOARGS}, #endif + {"simple_pending_call", simple_pending_call, METH_O}, + {"set_vectorcall_nop", set_vectorcall_nop, METH_O}, + {"module_get_gc_hooks", module_get_gc_hooks, METH_O}, + {"test_threadstate_set_stack_protection", + test_threadstate_set_stack_protection, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; @@ -2532,7 +2669,8 @@ module_exec(PyObject *module) } if (PyModule_Add(module, "TIER2_THRESHOLD", - PyLong_FromLong(JUMP_BACKWARD_INITIAL_VALUE + 1)) < 0) { + // + 1 more due to one loop spent on tracing. + PyLong_FromLong(JUMP_BACKWARD_INITIAL_VALUE + 2)) < 0) { return 1; } @@ -2551,10 +2689,17 @@ module_exec(PyObject *module) return 1; } + if (PyModule_AddIntMacro(module, _PY_NSMALLPOSINTS) < 0) { + return 1; + } + return 0; } +PyABIInfo_VAR(abi_info); + static struct PyModuleDef_Slot module_slots[] = { + {Py_mod_abi, &abi_info}, {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, diff --git a/Modules/_testinternalcapi/pytime.c b/Modules/_testinternalcapi/pytime.c index 2b0a205d158..7fb100c41a1 100644 --- a/Modules/_testinternalcapi/pytime.c +++ b/Modules/_testinternalcapi/pytime.c @@ -17,7 +17,7 @@ test_pytime_fromseconds(PyObject *self, PyObject *args) return NULL; } PyTime_t ts = _PyTime_FromSeconds(seconds); - return _PyTime_AsLong(ts); + return PyLong_FromInt64(ts); } static int @@ -49,7 +49,7 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args) if (_PyTime_FromSecondsObject(&ts, obj, round) == -1) { return NULL; } - return _PyTime_AsLong(ts); + return PyLong_FromInt64(ts); } static PyObject * @@ -64,7 +64,7 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args) return NULL; } PyTime_t t; - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } struct timeval tv; @@ -91,7 +91,7 @@ test_PyTime_AsTimeval_clamp(PyObject *self, PyObject *args) return NULL; } PyTime_t t; - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } struct timeval tv; @@ -113,7 +113,7 @@ test_PyTime_AsTimespec(PyObject *self, PyObject *args) return NULL; } PyTime_t t; - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } struct timespec ts; @@ -131,7 +131,7 @@ test_PyTime_AsTimespec_clamp(PyObject *self, PyObject *args) return NULL; } PyTime_t t; - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } struct timespec ts; @@ -149,14 +149,14 @@ test_PyTime_AsMilliseconds(PyObject *self, PyObject *args) return NULL; } PyTime_t t; - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } if (check_time_rounding(round) < 0) { return NULL; } PyTime_t ms = _PyTime_AsMilliseconds(t, round); - return _PyTime_AsLong(ms); + return PyLong_FromInt64(ms); } static PyObject * @@ -168,14 +168,14 @@ test_PyTime_AsMicroseconds(PyObject *self, PyObject *args) return NULL; } PyTime_t t; - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } if (check_time_rounding(round) < 0) { return NULL; } PyTime_t us = _PyTime_AsMicroseconds(t, round); - return _PyTime_AsLong(us); + return PyLong_FromInt64(us); } static PyObject * diff --git a/Modules/_testinternalcapi/test_critical_sections.c b/Modules/_testinternalcapi/test_critical_sections.c index e0ba37abcdd..e3b2fe716d4 100644 --- a/Modules/_testinternalcapi/test_critical_sections.c +++ b/Modules/_testinternalcapi/test_critical_sections.c @@ -284,10 +284,111 @@ test_critical_sections_gc(PyObject *self, PyObject *Py_UNUSED(args)) #endif +#ifdef Py_GIL_DISABLED + +static PyObject * +test_critical_section1_reacquisition(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *a = PyDict_New(); + assert(a != NULL); + + PyCriticalSection cs1, cs2; + // First acquisition of critical section on object locks it + PyCriticalSection_Begin(&cs1, a); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert(_PyThreadState_GET()->critical_section == (uintptr_t)&cs1); + // Attempting to re-acquire critical section on same object which + // is already locked by top-most critical section is a no-op. + PyCriticalSection_Begin(&cs2, a); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert(_PyThreadState_GET()->critical_section == (uintptr_t)&cs1); + // Releasing second critical section is a no-op. + PyCriticalSection_End(&cs2); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert(_PyThreadState_GET()->critical_section == (uintptr_t)&cs1); + // Releasing first critical section unlocks the object + PyCriticalSection_End(&cs1); + assert(!PyMutex_IsLocked(&a->ob_mutex)); + + Py_DECREF(a); + Py_RETURN_NONE; +} + +static PyObject * +test_critical_section2_reacquisition(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *a = PyDict_New(); + assert(a != NULL); + PyObject *b = PyDict_New(); + assert(b != NULL); + + PyCriticalSection2 cs; + // First acquisition of critical section on objects locks them + PyCriticalSection2_Begin(&cs, a, b); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(PyMutex_IsLocked(&b->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert((_PyThreadState_GET()->critical_section & + ~_Py_CRITICAL_SECTION_MASK) == (uintptr_t)&cs); + + // Attempting to re-acquire critical section on either of two + // objects already locked by top-most critical section is a no-op. + + // Check re-acquiring on first object + PyCriticalSection a_cs; + PyCriticalSection_Begin(&a_cs, a); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(PyMutex_IsLocked(&b->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert((_PyThreadState_GET()->critical_section & + ~_Py_CRITICAL_SECTION_MASK) == (uintptr_t)&cs); + // Releasing critical section on either object is a no-op. + PyCriticalSection_End(&a_cs); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(PyMutex_IsLocked(&b->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert((_PyThreadState_GET()->critical_section & + ~_Py_CRITICAL_SECTION_MASK) == (uintptr_t)&cs); + + // Check re-acquiring on second object + PyCriticalSection b_cs; + PyCriticalSection_Begin(&b_cs, b); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(PyMutex_IsLocked(&b->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert((_PyThreadState_GET()->critical_section & + ~_Py_CRITICAL_SECTION_MASK) == (uintptr_t)&cs); + // Releasing critical section on either object is a no-op. + PyCriticalSection_End(&b_cs); + assert(PyMutex_IsLocked(&a->ob_mutex)); + assert(PyMutex_IsLocked(&b->ob_mutex)); + assert(_PyCriticalSection_IsActive(PyThreadState_GET()->critical_section)); + assert((_PyThreadState_GET()->critical_section & + ~_Py_CRITICAL_SECTION_MASK) == (uintptr_t)&cs); + + // Releasing critical section on both objects unlocks them + PyCriticalSection2_End(&cs); + assert(!PyMutex_IsLocked(&a->ob_mutex)); + assert(!PyMutex_IsLocked(&b->ob_mutex)); + + Py_DECREF(a); + Py_DECREF(b); + Py_RETURN_NONE; +} + +#endif // Py_GIL_DISABLED + static PyMethodDef test_methods[] = { {"test_critical_sections", test_critical_sections, METH_NOARGS}, {"test_critical_sections_nest", test_critical_sections_nest, METH_NOARGS}, {"test_critical_sections_suspend", test_critical_sections_suspend, METH_NOARGS}, +#ifdef Py_GIL_DISABLED + {"test_critical_section1_reacquisition", test_critical_section1_reacquisition, METH_NOARGS}, + {"test_critical_section2_reacquisition", test_critical_section2_reacquisition, METH_NOARGS}, +#endif #ifdef Py_CAN_START_THREADS {"test_critical_sections_threads", test_critical_sections_threads, METH_NOARGS}, {"test_critical_sections_gc", test_critical_sections_gc, METH_NOARGS}, diff --git a/Modules/_testinternalcapi/test_lock.c b/Modules/_testinternalcapi/test_lock.c index 8d8cb992b0e..ded76ca9fe6 100644 --- a/Modules/_testinternalcapi/test_lock.c +++ b/Modules/_testinternalcapi/test_lock.c @@ -91,7 +91,8 @@ test_lock_two_threads(PyObject *self, PyObject *obj) } while (v != 3 && iters < 200); // both the "locked" and the "has parked" bits should be set - assert(test_data.m._bits == 3); + v = _Py_atomic_load_uint8_relaxed(&test_data.m._bits); + assert(v == 3); PyMutex_Unlock(&test_data.m); PyEvent_Wait(&test_data.done); diff --git a/Modules/_testlimitedcapi/set.c b/Modules/_testlimitedcapi/set.c index 35da5fa5f00..34ed6b1d60b 100644 --- a/Modules/_testlimitedcapi/set.c +++ b/Modules/_testlimitedcapi/set.c @@ -155,6 +155,51 @@ error: return NULL; } +static PyObject * +test_set_contains_does_not_convert_unhashable_key(PyObject *self, PyObject *Py_UNUSED(obj)) +{ + // See https://docs.python.org/3/c-api/set.html#c.PySet_Contains + PyObject *outer_set = PySet_New(NULL); + + PyObject *needle = PySet_New(NULL); + if (needle == NULL) { + Py_DECREF(outer_set); + return NULL; + } + + PyObject *num = PyLong_FromLong(42); + if (num == NULL) { + Py_DECREF(outer_set); + Py_DECREF(needle); + return NULL; + } + + if (PySet_Add(needle, num) < 0) { + Py_DECREF(outer_set); + Py_DECREF(needle); + Py_DECREF(num); + return NULL; + } + + int result = PySet_Contains(outer_set, needle); + + Py_DECREF(num); + Py_DECREF(needle); + Py_DECREF(outer_set); + + if (result < 0) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_RETURN_NONE; + } + return NULL; + } + + PyErr_SetString(PyExc_AssertionError, + "PySet_Contains should have raised TypeError for unhashable key"); + return NULL; +} + static PyMethodDef test_methods[] = { {"set_check", set_check, METH_O}, {"set_checkexact", set_checkexact, METH_O}, @@ -174,6 +219,8 @@ static PyMethodDef test_methods[] = { {"set_clear", set_clear, METH_O}, {"test_frozenset_add_in_capi", test_frozenset_add_in_capi, METH_NOARGS}, + {"test_set_contains_does_not_convert_unhashable_key", + test_set_contains_does_not_convert_unhashable_key, METH_NOARGS}, {NULL}, }; diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index bfec0678e2c..e286eaae820 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -850,6 +850,28 @@ PyInit__testmultiphase_exec_unreported_exception(void) return PyModuleDef_Init(&def_exec_unreported_exception); } +static int execfn_a1(PyObject*m) { return PyModule_AddIntConstant(m, "a", 1); } +static int execfn_b2(PyObject*m) { return PyModule_AddIntConstant(m, "b", 2); } +static int execfn_c3(PyObject*m) { return PyModule_AddIntConstant(m, "c", 3); } + +PyMODINIT_FUNC +PyInit__testmultiphase_exec_multiple(void) +{ + static PyModuleDef_Slot slots[] = { + {Py_mod_exec, execfn_a1}, + {Py_mod_exec, execfn_b2}, + {Py_mod_exec, execfn_c3}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0} + }; + static PyModuleDef def = { + PyModuleDef_HEAD_INIT, + .m_name="_testmultiphase_exec_multiple", + .m_slots=slots, + }; + return PyModuleDef_Init(&def); +} + static int meth_state_access_exec(PyObject *m) { @@ -993,3 +1015,188 @@ PyInit__test_no_multiple_interpreter_slot(void) { return PyModuleDef_Init(&no_multiple_interpreter_slot_def); } + + +/* PyModExport_* hooks */ + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport(void) +{ + static PyModuleDef_Slot slots[] = { + {Py_mod_name, "_test_from_modexport"}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return slots; +} + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_gil_used(void) +{ + static PyModuleDef_Slot slots[] = { + {Py_mod_name, "_test_from_modexport_gil_used"}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_USED}, + {0}, + }; + return slots; +} + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_null(void) +{ + return NULL; +} + +PyMODINIT_FUNC +PyModInit__test_from_modexport_null(void) +{ + // This is not called as fallback for failed PyModExport_* + assert(0); + PyErr_SetString(PyExc_AssertionError, "PyInit_ fallback called"); + return NULL; +} + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_exception(void) +{ + PyErr_SetString(PyExc_ValueError, "failed as requested"); + return NULL; +} + +PyMODINIT_FUNC +PyModInit__test_from_modexport_exception(void) +{ + // This is not called as fallback for failed PyModExport_* + assert(0); + PyErr_SetString(PyExc_AssertionError, "PyInit_ fallback called"); + return NULL; +} + +static PyObject * +modexport_create_string(PyObject *spec, PyModuleDef *def) +{ + assert(def == NULL); + return PyUnicode_FromString("is this \xf0\x9f\xa6\x8b... a module?"); +} + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_create_nonmodule(void) +{ + static PyModuleDef_Slot slots[] = { + {Py_mod_name, "_test_from_modexport_create_nonmodule"}, + {Py_mod_create, modexport_create_string}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return slots; +} + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_create_nonmodule_gil_used(void) +{ + static PyModuleDef_Slot slots[] = { + {Py_mod_name, "_test_from_modexport_create_nonmodule"}, + {Py_mod_create, modexport_create_string}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_USED}, + {0}, + }; + return slots; +} + +static PyModuleDef_Slot modexport_empty_slots[] = { + {0}, +}; + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_empty_slots(void) +{ + return modexport_empty_slots; +} + +static int +modexport_smoke_exec(PyObject *mod) +{ + // "magic" values 147 & 258 are expected in the test + if (PyModule_AddIntConstant(mod, "number", 147) < 0) { + return 0; + } + int *state = PyModule_GetState(mod); + if (!state) { + return -1; + } + *state = 258; + + PyObject *tp = PyType_FromModuleAndSpec(mod, &StateAccessType_spec, NULL); + if (PyModule_Add(mod, "Example", tp) < 0) { + return -1; + } + + return 0; +} + +static PyObject * +modexport_smoke_get_state_int(PyObject *mod, PyObject *arg) +{ + int *state = PyModule_GetState(mod); + if (!state) { + return NULL; + } + return PyLong_FromLong(*state); +} + +static const char modexport_smoke_test_token; + +static PyObject * +modexport_smoke_get_test_token(PyObject *mod, PyObject *arg) +{ + return PyLong_FromVoidPtr((void*)&modexport_smoke_test_token); +} + +static PyObject * +modexport_get_empty_slots(PyObject *mod, PyObject *arg) +{ + /* Get the address of modexport_empty_slots. + * This method would be in the `_test_from_modexport_empty_slots` module, + * if it had a methods slot. + */ + return PyLong_FromVoidPtr(&modexport_empty_slots); +} + +static void +modexport_smoke_free(void *op) +{ + PyObject *mod = (PyObject *)op; + int *state = PyModule_GetState(mod); + if (!state) { + PyErr_FormatUnraisable("Exception ignored in module %R free", mod); + } + assert(*state == 258); +} + +PyMODEXPORT_FUNC +PyModExport__test_from_modexport_smoke(void) +{ + static PyMethodDef methods[] = { + {"get_state_int", modexport_smoke_get_state_int, METH_NOARGS}, + {"get_test_token", modexport_smoke_get_test_token, METH_NOARGS}, + {"get_modexport_empty_slots", modexport_get_empty_slots, METH_NOARGS}, + {0}, + }; + static PyModuleDef_Slot slots[] = { + {Py_mod_name, "_test_from_modexport_smoke"}, + {Py_mod_doc, "the expected docstring"}, + {Py_mod_exec, modexport_smoke_exec}, + {Py_mod_state_size, (void*)sizeof(int)}, + {Py_mod_methods, methods}, + {Py_mod_state_free, modexport_smoke_free}, + {Py_mod_token, (void*)&modexport_smoke_test_token}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0}, + }; + return slots; +} diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index 2c59085d15b..ee38d61b43a 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -244,6 +244,8 @@ static inline module_state * get_module_state(PyObject *module) { PyModuleDef *def = PyModule_GetDef(module); + assert(def); + if (def->m_size == -1) { return &global_state.module; } diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 0a22907375b..cc8277c5783 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -429,7 +429,7 @@ force_done(void *arg) static int ThreadHandle_start(ThreadHandle *self, PyObject *func, PyObject *args, - PyObject *kwargs) + PyObject *kwargs, int daemon) { // Mark the handle as starting to prevent any other threads from doing so PyMutex_Lock(&self->mutex); @@ -453,7 +453,8 @@ ThreadHandle_start(ThreadHandle *self, PyObject *func, PyObject *args, goto start_failed; } PyInterpreterState *interp = _PyInterpreterState_GET(); - boot->tstate = _PyThreadState_New(interp, _PyThreadState_WHENCE_THREADING); + uint8_t whence = daemon ? _PyThreadState_WHENCE_THREADING_DAEMON : _PyThreadState_WHENCE_THREADING; + boot->tstate = _PyThreadState_New(interp, whence); if (boot->tstate == NULL) { PyMem_RawFree(boot); if (!PyErr_Occurred()) { @@ -655,13 +656,6 @@ PyThreadHandleObject_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)PyThreadHandleObject_new(type); } -static int -PyThreadHandleObject_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void PyThreadHandleObject_dealloc(PyObject *op) { @@ -718,6 +712,9 @@ PyThreadHandleObject_is_done(PyObject *op, PyObject *Py_UNUSED(dummy)) { PyThreadHandleObject *self = PyThreadHandleObject_CAST(op); if (_PyEvent_IsSet(&self->handle->thread_is_exiting)) { + if (_PyOnceFlag_CallOnce(&self->handle->once, join_thread, self->handle) == -1) { + return NULL; + } Py_RETURN_TRUE; } else { @@ -751,7 +748,7 @@ static PyType_Slot ThreadHandle_Type_slots[] = { {Py_tp_dealloc, PyThreadHandleObject_dealloc}, {Py_tp_repr, PyThreadHandleObject_repr}, {Py_tp_getset, ThreadHandle_getsetlist}, - {Py_tp_traverse, PyThreadHandleObject_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_methods, ThreadHandle_methods}, {Py_tp_new, PyThreadHandleObject_tp_new}, {0, 0} @@ -767,13 +764,6 @@ static PyType_Spec ThreadHandle_Type_spec = { /* Lock objects */ -static int -lock_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void lock_dealloc(PyObject *self) { @@ -1045,7 +1035,7 @@ static PyType_Slot lock_type_slots[] = { {Py_tp_repr, lock_repr}, {Py_tp_doc, (void *)lock_doc}, {Py_tp_methods, lock_methods}, - {Py_tp_traverse, lock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_new, lock_new}, {0, 0} }; @@ -1060,13 +1050,6 @@ static PyType_Spec lock_type_spec = { /* Recursive lock objects */ -static int -rlock_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static int rlock_locked_impl(rlockobject *self) { @@ -1359,7 +1342,7 @@ static PyType_Slot rlock_type_slots[] = { {Py_tp_methods, rlock_methods}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, rlock_new}, - {Py_tp_traverse, rlock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, 0}, }; @@ -1934,7 +1917,7 @@ do_start_new_thread(thread_module_state *state, PyObject *func, PyObject *args, add_to_shutdown_handles(state, handle); } - if (ThreadHandle_start(handle, func, args, kwargs) < 0) { + if (ThreadHandle_start(handle, func, args, kwargs, daemon) < 0) { if (!daemon) { remove_from_shutdown_handles(handle); } @@ -2446,10 +2429,8 @@ thread_shutdown(PyObject *self, PyObject *args) // Wait for the thread to finish. If we're interrupted, such // as by a ctrl-c we print the error and exit early. if (ThreadHandle_join(handle, -1) < 0) { - PyErr_FormatUnraisable("Exception ignored while joining a thread " - "in _thread._shutdown()"); ThreadHandle_decref(handle); - Py_RETURN_NONE; + return NULL; } ThreadHandle_decref(handle); @@ -2544,7 +2525,9 @@ _thread__get_name_impl(PyObject *module) } #ifdef __sun - return PyUnicode_DecodeUTF8(name, strlen(name), "surrogateescape"); + // gh-138004: Decode Solaris/Illumos (e.g. OpenIndiana) thread names + // from ASCII, since OpenIndiana only supports ASCII names. + return PyUnicode_DecodeASCII(name, strlen(name), "surrogateescape"); #else return PyUnicode_DecodeFSDefault(name); #endif @@ -2582,8 +2565,9 @@ _thread_set_name_impl(PyObject *module, PyObject *name_obj) { #ifndef MS_WINDOWS #ifdef __sun - // Solaris always uses UTF-8 - const char *encoding = "utf-8"; + // gh-138004: Encode Solaris/Illumos thread names to ASCII, + // since OpenIndiana does not support non-ASCII names. + const char *encoding = "ascii"; #else // Encode the thread name to the filesystem encoding using the "replace" // error handler diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index d921c46d645..8cea7b59fe7 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -82,33 +82,10 @@ typedef int Tcl_Size; #ifdef HAVE_CREATEFILEHANDLER -/* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere - with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */ -#ifndef TCL_UNIX_FD -# ifdef TCL_WIN_SOCKET -# define TCL_UNIX_FD (! TCL_WIN_SOCKET) -# else -# define TCL_UNIX_FD 1 -# endif -#endif - -/* Tcl_CreateFileHandler() changed several times; these macros deal with the - messiness. In Tcl 8.0 and later, it is not available on Windows (and on - Unix, only because Jack added it back); when available on Windows, it only - applies to sockets. */ - -#ifdef MS_WINDOWS -#define FHANDLETYPE TCL_WIN_SOCKET -#else -#define FHANDLETYPE TCL_UNIX_FD -#endif - /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine which uses this to handle Tcl events while the user is typing commands. */ -#if FHANDLETYPE == TCL_UNIX_FD #define WAIT_FOR_STDIN -#endif #endif /* HAVE_CREATEFILEHANDLER */ @@ -598,8 +575,12 @@ Tkapp_New(const char *screenName, const char *className, v->interp = Tcl_CreateInterp(); v->wantobjects = wantobjects; +#if TCL_MAJOR_VERSION >= 9 + v->threaded = 1; +#else v->threaded = Tcl_GetVar2Ex(v->interp, "tcl_platform", "threaded", TCL_GLOBAL_ONLY) != NULL; +#endif v->thread_id = Tcl_GetCurrentThread(); v->dispatching = 0; v->trace = NULL; @@ -906,11 +887,14 @@ static PyType_Slot PyTclObject_Type_slots[] = { }; static PyType_Spec PyTclObject_Type_spec = { - "_tkinter.Tcl_Obj", - sizeof(PyTclObject), - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, - PyTclObject_Type_slots, + .name = "_tkinter.Tcl_Obj", + .basicsize = sizeof(PyTclObject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = PyTclObject_Type_slots, }; @@ -3267,11 +3251,14 @@ static PyType_Slot Tktt_Type_slots[] = { }; static PyType_Spec Tktt_Type_spec = { - "_tkinter.tktimertoken", - sizeof(TkttObject), - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, - Tktt_Type_slots, + .name = "_tkinter.tktimertoken", + .basicsize = sizeof(TkttObject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = Tktt_Type_slots, }; @@ -3323,11 +3310,14 @@ static PyType_Slot Tkapp_Type_slots[] = { static PyType_Spec Tkapp_Type_spec = { - "_tkinter.tkapp", - sizeof(TkappObject), - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, - Tkapp_Type_slots, + .name = "_tkinter.tkapp", + .basicsize = sizeof(TkappObject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = Tkapp_Type_slots, }; static PyMethodDef moduleMethods[] = diff --git a/Modules/_winapi.c b/Modules/_winapi.c index b4cfbebcb1b..2aebe44c709 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1920,7 +1920,6 @@ static PyObject * _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size) /*[clinic end generated code: output=d0c3e29e49d323dd input=c7aa53bfbce69d70]*/ { - PyObject *buf = NULL; DWORD nread, navail, nleft; BOOL ret; @@ -1930,20 +1929,26 @@ _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size) } if (size) { - buf = PyBytes_FromStringAndSize(NULL, size); - if (!buf) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; + } + char *buf = PyBytesWriter_GetData(writer); + Py_BEGIN_ALLOW_THREADS - ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread, + ret = PeekNamedPipe(handle, buf, size, &nread, &navail, &nleft); Py_END_ALLOW_THREADS if (!ret) { - Py_DECREF(buf); + PyBytesWriter_Discard(writer); return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0); } - if (_PyBytes_Resize(&buf, nread)) + + PyObject *res = PyBytesWriter_FinishWithSize(writer, nread); + if (res == NULL) { return NULL; - return Py_BuildValue("NII", buf, navail, nleft); + } + return Py_BuildValue("NII", res, navail, nleft); } else { Py_BEGIN_ALLOW_THREADS diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index a04f1412eef..0cbe10c79ab 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -10,8 +10,8 @@ See the source code for LLVMFuzzerTestOneInput for details. */ -#ifndef Py_BUILD_CORE -# define Py_BUILD_CORE 1 +#ifndef Py_BUILD_CORE_MODULE +# define Py_BUILD_CORE_MODULE 1 #endif #include <Python.h> diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index b99be073db5..e07dfd19efa 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -292,16 +292,11 @@ static PyObject * get_weak_cache(zoneinfo_state *state, PyTypeObject *type) { if (type == state->ZoneInfoType) { + Py_INCREF(state->ZONEINFO_WEAK_CACHE); return state->ZONEINFO_WEAK_CACHE; } else { - PyObject *cache = - PyObject_GetAttrString((PyObject *)type, "_weak_cache"); - // We are assuming that the type lives at least as long as the function - // that calls get_weak_cache, and that it holds a reference to the - // cache, so we'll return a "borrowed reference". - Py_XDECREF(cache); - return cache; + return PyObject_GetAttrString((PyObject *)type, "_weak_cache"); } } @@ -328,6 +323,7 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key) PyObject *weak_cache = get_weak_cache(state, type); instance = PyObject_CallMethod(weak_cache, "get", "O", key, Py_None); if (instance == NULL) { + Py_DECREF(weak_cache); return NULL; } @@ -335,6 +331,7 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key) Py_DECREF(instance); PyObject *tmp = zoneinfo_new_instance(state, type, key); if (tmp == NULL) { + Py_DECREF(weak_cache); return NULL; } @@ -342,12 +339,14 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key) PyObject_CallMethod(weak_cache, "setdefault", "OO", key, tmp); Py_DECREF(tmp); if (instance == NULL) { + Py_DECREF(weak_cache); return NULL; } ((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE; } update_strong_cache(state, type, key, instance); + Py_DECREF(weak_cache); return instance; } @@ -510,12 +509,14 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls, PyObject *item = NULL; PyObject *pop = PyUnicode_FromString("pop"); if (pop == NULL) { + Py_DECREF(weak_cache); return NULL; } PyObject *iter = PyObject_GetIter(only_keys); if (iter == NULL) { Py_DECREF(pop); + Py_DECREF(weak_cache); return NULL; } @@ -540,6 +541,7 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls, Py_DECREF(pop); } + Py_DECREF(weak_cache); if (PyErr_Occurred()) { return NULL; } diff --git a/Modules/_zstd/buffer.h b/Modules/_zstd/buffer.h index 0ac7bcb4ddc..807c72c80dd 100644 --- a/Modules/_zstd/buffer.h +++ b/Modules/_zstd/buffer.h @@ -16,8 +16,8 @@ static inline int _OutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob, Py_ssize_t max_length) { - /* Ensure .list was set to NULL */ - assert(buffer->list == NULL); + /* Ensure .writer was set to NULL */ + assert(buffer->writer == NULL); Py_ssize_t res = _BlocksOutputBuffer_InitAndGrow(buffer, max_length, &ob->dst); @@ -39,8 +39,8 @@ _OutputBuffer_InitWithSize(_BlocksOutputBuffer *buffer, ZSTD_outBuffer *ob, { Py_ssize_t block_size; - /* Ensure .list was set to NULL */ - assert(buffer->list == NULL); + /* Ensure .writer was set to NULL */ + assert(buffer->writer == NULL); /* Get block size */ if (0 <= max_length && max_length < init_size) { diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c index 77cfd24050f..f90bc9c5ab5 100644 --- a/Modules/_zstd/compressor.c +++ b/Modules/_zstd/compressor.c @@ -446,7 +446,7 @@ compress_lock_held(ZstdCompressor *self, Py_buffer *data, assert(PyMutex_IsLocked(&self->lock)); ZSTD_inBuffer in; ZSTD_outBuffer out; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; size_t zstd_ret; PyObject *ret; @@ -527,7 +527,7 @@ compress_mt_continue_lock_held(ZstdCompressor *self, Py_buffer *data) assert(PyMutex_IsLocked(&self->lock)); ZSTD_inBuffer in; ZSTD_outBuffer out; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; size_t zstd_ret; PyObject *ret; @@ -716,7 +716,7 @@ _zstd_ZstdCompressor_set_pledged_input_size_impl(ZstdCompressor *self, unsigned long long size) /*[clinic end generated code: output=3a09e55cc0e3b4f9 input=b4c87bcbd5ce6111]*/ { - // Error occured while converting argument, should be unreachable + // Error occurred while converting argument, should be unreachable assert(size != ZSTD_CONTENTSIZE_ERROR); /* Thread-safe code */ diff --git a/Modules/_zstd/decompressor.c b/Modules/_zstd/decompressor.c index 6592cad6690..13071b7a2ba 100644 --- a/Modules/_zstd/decompressor.c +++ b/Modules/_zstd/decompressor.c @@ -216,7 +216,7 @@ decompress_lock_held(ZstdDecompressor *self, ZSTD_inBuffer *in, { size_t zstd_ret; ZSTD_outBuffer out; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; PyObject *ret; /* Initialize the output buffer */ diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 654e9445985..729e085c19f 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -714,14 +714,6 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v) } /* Methods */ - -static int -array_tp_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} - static void array_dealloc(PyObject *op) { @@ -1526,7 +1518,7 @@ array.array.fromfile cls: defining_class f: object - n: Py_ssize_t + n: Py_ssize_t(allow_negative=False) / Read n objects from the file object f and append them to the end of the array. @@ -1535,17 +1527,13 @@ Read n objects from the file object f and append them to the end of the array. static PyObject * array_array_fromfile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f, Py_ssize_t n) -/*[clinic end generated code: output=83a667080b345ebc input=b2b4bdfb7ad4d4ae]*/ +/*[clinic end generated code: output=83a667080b345ebc input=db46b06ac1b6de87]*/ { PyObject *b, *res; Py_ssize_t itemsize = self->ob_descr->itemsize; Py_ssize_t nbytes; int not_enough_bytes; - if (n < 0) { - PyErr_SetString(PyExc_ValueError, "negative count"); - return NULL; - } if (n > PY_SSIZE_T_MAX / itemsize) { PyErr_NoMemory(); return NULL; @@ -2845,6 +2833,9 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_SET_SIZE(self, n); self->allocated = n; } + else { + PyMem_Free(ustr); + } } else { // c == 'w' Py_ssize_t n = PyUnicode_GET_LENGTH(initial); @@ -2968,7 +2959,7 @@ static PyType_Slot array_slots[] = { {Py_tp_getset, array_getsets}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, array_new}, - {Py_tp_traverse, array_tp_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, /* as sequence */ {Py_sq_length, array_length}, diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c index 4b068967a6c..f81f0b57247 100644 --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -112,6 +112,7 @@ atexit_callfuncs(struct atexit_state *state) { PyErr_FormatUnraisable("Exception ignored while " "copying atexit callbacks"); + atexit_cleanup(state); return; } @@ -256,10 +257,11 @@ static int atexit_unregister_locked(PyObject *callbacks, PyObject *func) { for (Py_ssize_t i = 0; i < PyList_GET_SIZE(callbacks); ++i) { - PyObject *tuple = PyList_GET_ITEM(callbacks, i); + PyObject *tuple = Py_NewRef(PyList_GET_ITEM(callbacks, i)); assert(PyTuple_CheckExact(tuple)); PyObject *to_compare = PyTuple_GET_ITEM(tuple, 0); int cmp = PyObject_RichCompareBool(func, to_compare, Py_EQ); + Py_DECREF(tuple); if (cmp < 0) { return -1; diff --git a/Modules/binascii.c b/Modules/binascii.c index c70f9f88afe..13e4bc5be03 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -205,11 +205,9 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) /*[clinic end generated code: output=e027f8e0b0598742 input=7cafeaf73df63d1c]*/ { const unsigned char *ascii_data; - unsigned char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; - PyObject *rv; Py_ssize_t ascii_len, bin_len; binascii_state *state; @@ -223,9 +221,11 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) ascii_len--; /* Allocate the buffer */ - if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) + PyBytesWriter *writer = PyBytesWriter_Create(bin_len); + if (writer == NULL) { return NULL; - bin_data = (unsigned char *)PyBytes_AS_STRING(rv); + } + unsigned char *bin_data = PyBytesWriter_GetData(writer); for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) { /* XXX is it really best to add NULs if there's no more data */ @@ -245,11 +245,10 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) if ( this_ch < ' ' || this_ch > (' ' + 64)) { state = get_binascii_state(module); if (state == NULL) { - return NULL; + goto error; } PyErr_SetString(state->Error, "Illegal char"); - Py_DECREF(rv); - return NULL; + goto error; } this_ch = (this_ch - ' ') & 077; } @@ -277,14 +276,17 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) this_ch != '\n' && this_ch != '\r' ) { state = get_binascii_state(module); if (state == NULL) { - return NULL; + goto error; } PyErr_SetString(state->Error, "Trailing garbage"); - Py_DECREF(rv); - return NULL; + goto error; } } - return rv; + return PyBytesWriter_Finish(writer); + +error: + PyBytesWriter_Discard(writer); + return NULL; } /*[clinic input] @@ -302,16 +304,13 @@ static PyObject * binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) /*[clinic end generated code: output=b1b99de62d9bbeb8 input=beb27822241095cd]*/ { - unsigned char *ascii_data; const unsigned char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; binascii_state *state; - Py_ssize_t bin_len, out_len; - _PyBytesWriter writer; + Py_ssize_t bin_len; - _PyBytesWriter_Init(&writer); bin_data = data->buf; bin_len = data->len; if ( bin_len > 45 ) { @@ -325,10 +324,12 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) } /* We're lazy and allocate to much (fixed up later) */ - out_len = 2 + (bin_len + 2) / 3 * 4; - ascii_data = _PyBytesWriter_Alloc(&writer, out_len); - if (ascii_data == NULL) + Py_ssize_t out_len = 2 + (bin_len + 2) / 3 * 4; + PyBytesWriter *writer = PyBytesWriter_Create(out_len); + if (writer == NULL) { return NULL; + } + unsigned char *ascii_data = PyBytesWriter_GetData(writer); /* Store the length */ if (backtick && !bin_len) @@ -356,7 +357,7 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) } *ascii_data++ = '\n'; /* Append a courtesy newline */ - return _PyBytesWriter_Finish(&writer, ascii_data); + return PyBytesWriter_FinishWithPointer(writer, ascii_data); } /*[clinic input] @@ -388,12 +389,11 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) /* Allocate the buffer */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ - _PyBytesWriter writer; - _PyBytesWriter_Init(&writer); - unsigned char *bin_data = _PyBytesWriter_Alloc(&writer, bin_len); - if (bin_data == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(bin_len); + if (writer == NULL) { return NULL; - unsigned char *bin_data_start = bin_data; + } + unsigned char *bin_data = PyBytesWriter_GetData(writer); if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') { state = get_binascii_state(module); @@ -489,12 +489,14 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) state = get_binascii_state(module); if (state == NULL) { /* error already set, from get_binascii_state */ + assert(PyErr_Occurred()); } else if (quad_pos == 1) { /* ** There is exactly one extra valid, non-padding, base64 character. ** This is an invalid length, as there is no possible input that ** could encoded into such a base64 string. */ + unsigned char *bin_data_start = PyBytesWriter_GetData(writer); PyErr_Format(state->Error, "Invalid base64-encoded string: " "number of data characters (%zd) cannot be 1 more " @@ -503,13 +505,15 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) } else { PyErr_SetString(state->Error, "Incorrect padding"); } - error_end: - _PyBytesWriter_Dealloc(&writer); - return NULL; + goto error_end; } done: - return _PyBytesWriter_Finish(&writer, bin_data); + return PyBytesWriter_FinishWithPointer(writer, bin_data); + +error_end: + PyBytesWriter_Discard(writer); + return NULL; } @@ -528,18 +532,15 @@ static PyObject * binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) /*[clinic end generated code: output=4ad62c8e8485d3b3 input=0e20ff59c5f2e3e1]*/ { - unsigned char *ascii_data; const unsigned char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; - Py_ssize_t bin_len, out_len; - _PyBytesWriter writer; + Py_ssize_t bin_len; binascii_state *state; bin_data = data->buf; bin_len = data->len; - _PyBytesWriter_Init(&writer); assert(bin_len >= 0); @@ -555,12 +556,15 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) /* We're lazy and allocate too much (fixed up later). "+2" leaves room for up to two pad characters. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */ - out_len = bin_len*2 + 2; - if (newline) + Py_ssize_t out_len = bin_len*2 + 2; + if (newline) { out_len++; - ascii_data = _PyBytesWriter_Alloc(&writer, out_len); - if (ascii_data == NULL) + } + PyBytesWriter *writer = PyBytesWriter_Create(out_len); + if (writer == NULL) { return NULL; + } + unsigned char *ascii_data = PyBytesWriter_GetData(writer); for( ; bin_len > 0 ; bin_len--, bin_data++ ) { /* Shift the data into our buffer */ @@ -585,7 +589,7 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) if (newline) *ascii_data++ = '\n'; /* Append a courtesy newline */ - return _PyBytesWriter_Finish(&writer, ascii_data); + return PyBytesWriter_FinishWithPointer(writer, ascii_data); } @@ -887,8 +891,6 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr) { const char* argbuf; Py_ssize_t arglen; - PyObject *retval; - char* retbuf; Py_ssize_t i, j; binascii_state *state; @@ -910,10 +912,11 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr) return NULL; } - retval = PyBytes_FromStringAndSize(NULL, (arglen/2)); - if (!retval) + PyBytesWriter *writer = PyBytesWriter_Create(arglen/2); + if (writer == NULL) { return NULL; - retbuf = PyBytes_AS_STRING(retval); + } + char *retbuf = PyBytesWriter_GetData(writer); for (i=j=0; i < arglen; i += 2) { unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])]; @@ -921,18 +924,18 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr) if (top >= 16 || bot >= 16) { state = get_binascii_state(module); if (state == NULL) { - return NULL; + goto error; } PyErr_SetString(state->Error, "Non-hexadecimal digit found"); - goto finally; + goto error; } retbuf[j++] = (top << 4) + bot; } - return retval; + return PyBytesWriter_Finish(writer); - finally: - Py_DECREF(retval); +error: + PyBytesWriter_Discard(writer); return NULL; } diff --git a/Modules/blake2module.c b/Modules/blake2module.c index 163f238a426..89b0ebd516f 100644 --- a/Modules/blake2module.c +++ b/Modules/blake2module.c @@ -16,9 +16,10 @@ #include "Python.h" #include "hashlib.h" -#include "pycore_strhex.h" // _Py_strhex() -#include "pycore_typeobject.h" #include "pycore_moduleobject.h" +#include "pycore_object.h" // _PyObject_VisitType() +#include "pycore_strhex.h" // _Py_strhex() +#include "pycore_typeobject.h" // QUICK CPU AUTODETECTION // @@ -1008,17 +1009,10 @@ py_blake2_dealloc(PyObject *self) Py_DECREF(type); } -static int -py_blake2_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyType_Slot blake2b_type_slots[] = { {Py_tp_clear, py_blake2_clear}, {Py_tp_dealloc, py_blake2_dealloc}, - {Py_tp_traverse, py_blake2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_doc, (char *)py_blake2b_new__doc__}, {Py_tp_methods, py_blake2b_methods}, {Py_tp_getset, py_blake2b_getsetters}, @@ -1029,7 +1023,7 @@ static PyType_Slot blake2b_type_slots[] = { static PyType_Slot blake2s_type_slots[] = { {Py_tp_clear, py_blake2_clear}, {Py_tp_dealloc, py_blake2_dealloc}, - {Py_tp_traverse, py_blake2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_doc, (char *)py_blake2s_new__doc__}, {Py_tp_methods, py_blake2b_methods}, {Py_tp_getset, py_blake2b_getsetters}, diff --git a/Modules/cjkcodecs/_codecs_iso2022.c b/Modules/cjkcodecs/_codecs_iso2022.c index ef6faeb7127..b1984df2695 100644 --- a/Modules/cjkcodecs/_codecs_iso2022.c +++ b/Modules/cjkcodecs/_codecs_iso2022.c @@ -802,10 +802,13 @@ jisx0213_encoder(const MultibyteCodec *codec, const Py_UCS4 *data, return coded; case 2: /* second character of unicode pair */ - coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1], - jisx0213_pair_encmap, JISX0213_ENCPAIRS); - if (coded != DBCINV) - return coded; + if (data[1] != 0) { /* Don't consume null char as part of pair */ + coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1], + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded != DBCINV) { + return coded; + } + } _Py_FALLTHROUGH; case -1: /* flush unterminated */ diff --git a/Modules/cjkcodecs/_codecs_jp.c b/Modules/cjkcodecs/_codecs_jp.c index f7127487aa5..cd77888d551 100644 --- a/Modules/cjkcodecs/_codecs_jp.c +++ b/Modules/cjkcodecs/_codecs_jp.c @@ -192,8 +192,11 @@ ENCODER(euc_jis_2004) JISX0213_ENCPAIRS); if (code == DBCINV) return 1; - } else + } + else if (c2 != 0) { + /* Don't consume null char as part of pair */ insize = 2; + } } } } @@ -611,8 +614,10 @@ ENCODER(shift_jis_2004) if (code == DBCINV) return 1; } - else + else if (ch2 != 0) { + /* Don't consume null char as part of pair */ insize = 2; + } } } } diff --git a/Modules/clinic/_bisectmodule.c.h b/Modules/clinic/_bisectmodule.c.h index 314208bc41d..8f3492cd54b 100644 --- a/Modules/clinic/_bisectmodule.c.h +++ b/Modules/clinic/_bisectmodule.c.h @@ -93,6 +93,11 @@ _bisect_bisect_right(PyObject *module, PyObject *const *args, Py_ssize_t nargs, goto exit; } lo = ival; + if (lo < 0) { + PyErr_SetString(PyExc_ValueError, + "lo cannot be negative"); + goto exit; + } } if (!--noptargs) { goto skip_optional_pos; @@ -203,6 +208,11 @@ _bisect_insort_right(PyObject *module, PyObject *const *args, Py_ssize_t nargs, goto exit; } lo = ival; + if (lo < 0) { + PyErr_SetString(PyExc_ValueError, + "lo cannot be negative"); + goto exit; + } } if (!--noptargs) { goto skip_optional_pos; @@ -312,6 +322,11 @@ _bisect_bisect_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P goto exit; } lo = ival; + if (lo < 0) { + PyErr_SetString(PyExc_ValueError, + "lo cannot be negative"); + goto exit; + } } if (!--noptargs) { goto skip_optional_pos; @@ -422,6 +437,11 @@ _bisect_insort_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P goto exit; } lo = ival; + if (lo < 0) { + PyErr_SetString(PyExc_ValueError, + "lo cannot be negative"); + goto exit; + } } if (!--noptargs) { goto skip_optional_pos; @@ -446,4 +466,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=729385c6a23828ab input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a3c44ed440dd6d81 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_codecsmodule.c.h b/Modules/clinic/_codecsmodule.c.h index b0310325759..9e2a7950ebd 100644 --- a/Modules/clinic/_codecsmodule.c.h +++ b/Modules/clinic/_codecsmodule.c.h @@ -2779,6 +2779,70 @@ exit: return return_value; } +PyDoc_STRVAR(_codecs__normalize_encoding__doc__, +"_normalize_encoding($module, /, encoding)\n" +"--\n" +"\n" +"Normalize an encoding name *encoding*.\n" +"\n" +"Used for encodings.normalize_encoding. Does not convert to lower case."); + +#define _CODECS__NORMALIZE_ENCODING_METHODDEF \ + {"_normalize_encoding", _PyCFunction_CAST(_codecs__normalize_encoding), METH_FASTCALL|METH_KEYWORDS, _codecs__normalize_encoding__doc__}, + +static PyObject * +_codecs__normalize_encoding_impl(PyObject *module, PyObject *encoding); + +static PyObject * +_codecs__normalize_encoding(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(encoding), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"encoding", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_normalize_encoding", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *encoding; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("_normalize_encoding", "argument 'encoding'", "str", args[0]); + goto exit; + } + encoding = args[0]; + return_value = _codecs__normalize_encoding_impl(module, encoding); + +exit: + return return_value; +} + #ifndef _CODECS_MBCS_DECODE_METHODDEF #define _CODECS_MBCS_DECODE_METHODDEF #endif /* !defined(_CODECS_MBCS_DECODE_METHODDEF) */ @@ -2802,4 +2866,4 @@ exit: #ifndef _CODECS_CODE_PAGE_ENCODE_METHODDEF #define _CODECS_CODE_PAGE_ENCODE_METHODDEF #endif /* !defined(_CODECS_CODE_PAGE_ENCODE_METHODDEF) */ -/*[clinic end generated code: output=ed13f20dfb09e306 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a968c493bb28be3e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h index 7c4bd5503ed..ee621c150c3 100644 --- a/Modules/clinic/_datetimemodule.c.h +++ b/Modules/clinic/_datetimemodule.c.h @@ -371,7 +371,10 @@ PyDoc_STRVAR(datetime_date_strptime__doc__, "strptime($type, string, format, /)\n" "--\n" "\n" -"Parse string according to the given date format (like time.strptime())."); +"Parse string according to the given date format (like time.strptime()).\n" +"\n" +"For a list of supported format codes, see the documentation:\n" +" https://docs.python.org/3/library/datetime.html#format-codes"); #define DATETIME_DATE_STRPTIME_METHODDEF \ {"strptime", _PyCFunction_CAST(datetime_date_strptime), METH_FASTCALL|METH_CLASS, datetime_date_strptime__doc__}, @@ -412,7 +415,10 @@ PyDoc_STRVAR(datetime_date_strftime__doc__, "\n" "Format using strftime().\n" "\n" -"Example: \"%d/%m/%Y, %H:%M:%S\"."); +"Example: \"%d/%m/%Y, %H:%M:%S\".\n" +"\n" +"For a list of supported format codes, see the documentation:\n" +" https://docs.python.org/3/library/datetime.html#format-codes"); #define DATETIME_DATE_STRFTIME_METHODDEF \ {"strftime", _PyCFunction_CAST(datetime_date_strftime), METH_FASTCALL|METH_KEYWORDS, datetime_date_strftime__doc__}, @@ -847,7 +853,10 @@ PyDoc_STRVAR(datetime_time_strptime__doc__, "strptime($type, string, format, /)\n" "--\n" "\n" -"Parse string according to the given time format (like time.strptime())."); +"Parse string according to the given time format (like time.strptime()).\n" +"\n" +"For a list of supported format codes, see the documentation:\n" +" https://docs.python.org/3/library/datetime.html#format-codes"); #define DATETIME_TIME_STRPTIME_METHODDEF \ {"strptime", _PyCFunction_CAST(datetime_time_strptime), METH_FASTCALL|METH_CLASS, datetime_time_strptime__doc__}, @@ -970,7 +979,10 @@ PyDoc_STRVAR(datetime_time_strftime__doc__, "\n" "Format using strftime().\n" "\n" -"The date part of the timestamp passed to underlying strftime should not be used."); +"The date part of the timestamp passed to underlying strftime should not be used.\n" +"\n" +"For a list of supported format codes, see the documentation:\n" +" https://docs.python.org/3/library/datetime.html#format-codes"); #define DATETIME_TIME_STRFTIME_METHODDEF \ {"strftime", _PyCFunction_CAST(datetime_time_strftime), METH_FASTCALL|METH_KEYWORDS, datetime_time_strftime__doc__}, @@ -1569,7 +1581,10 @@ PyDoc_STRVAR(datetime_datetime_strptime__doc__, "strptime($type, string, format, /)\n" "--\n" "\n" -"Parse string according to the given date and time format (like time.strptime())."); +"Parse string according to the given date and time format (like time.strptime()).\n" +"\n" +"For a list of supported format codes, see the documentation:\n" +" https://docs.python.org/3/library/datetime.html#format-codes"); #define DATETIME_DATETIME_STRPTIME_METHODDEF \ {"strptime", _PyCFunction_CAST(datetime_datetime_strptime), METH_FASTCALL|METH_CLASS, datetime_datetime_strptime__doc__}, @@ -2075,4 +2090,4 @@ datetime_datetime___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) { return datetime_datetime___reduce___impl((PyDateTime_DateTime *)self); } -/*[clinic end generated code: output=0b8403bc58982e60 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=69658acff6a43ac4 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h index 3d81a6dcce1..7ae7be185ec 100644 --- a/Modules/clinic/_hashopenssl.c.h +++ b/Modules/clinic/_hashopenssl.c.h @@ -150,6 +150,11 @@ _hashlib_HASHXOF_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, goto exit; } length = ival; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length cannot be negative"); + goto exit; + } } return_value = _hashlib_HASHXOF_digest_impl((HASHobject *)self, length); @@ -223,6 +228,11 @@ _hashlib_HASHXOF_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nar goto exit; } length = ival; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length cannot be negative"); + goto exit; + } } return_value = _hashlib_HASHXOF_hexdigest_impl((HASHobject *)self, length); @@ -1976,4 +1986,4 @@ exit: #ifndef _HASHLIB_OPENSSL_SHAKE_256_METHODDEF #define _HASHLIB_OPENSSL_SHAKE_256_METHODDEF #endif /* !defined(_HASHLIB_OPENSSL_SHAKE_256_METHODDEF) */ -/*[clinic end generated code: output=cd5ff436f6dc2938 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9ba35fcc33795b1e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_interpqueuesmodule.c.h b/Modules/clinic/_interpqueuesmodule.c.h new file mode 100644 index 00000000000..3f08a0cb6d3 --- /dev/null +++ b/Modules/clinic/_interpqueuesmodule.c.h @@ -0,0 +1,765 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + +PyDoc_STRVAR(_interpqueues_create__doc__, +"create($module, /, maxsize, unboundop=-1, fallback=-1)\n" +"--\n" +"\n" +"Create a new cross-interpreter queue and return its unique generated ID.\n" +"\n" +"It is a new reference as though bind() had been called on the queue.\n" +"The caller is responsible for calling destroy() for the new queue\n" +"before the runtime is finalized."); + +#define _INTERPQUEUES_CREATE_METHODDEF \ + {"create", _PyCFunction_CAST(_interpqueues_create), METH_FASTCALL|METH_KEYWORDS, _interpqueues_create__doc__}, + +static PyObject * +_interpqueues_create_impl(PyObject *module, Py_ssize_t maxsize, + int unboundarg, int fallbackarg); + +static PyObject * +_interpqueues_create(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(maxsize), &_Py_ID(unboundop), &_Py_ID(fallback), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"maxsize", "unboundop", "fallback", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + Py_ssize_t maxsize; + int unboundarg = -1; + int fallbackarg = -1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + maxsize = ival; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + unboundarg = PyLong_AsInt(args[1]); + if (unboundarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + fallbackarg = PyLong_AsInt(args[2]); + if (fallbackarg == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = _interpqueues_create_impl(module, maxsize, unboundarg, fallbackarg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_destroy__doc__, +"destroy($module, /, qid)\n" +"--\n" +"\n" +"Clear and destroy the queue.\n" +"\n" +"Afterward attempts to use the queue will behave as though it never existed."); + +#define _INTERPQUEUES_DESTROY_METHODDEF \ + {"destroy", _PyCFunction_CAST(_interpqueues_destroy), METH_FASTCALL|METH_KEYWORDS, _interpqueues_destroy__doc__}, + +static PyObject * +_interpqueues_destroy_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_destroy(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "destroy", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_destroy_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_list_all__doc__, +"list_all($module, /)\n" +"--\n" +"\n" +"Return the list of ID triples for all queues.\n" +"\n" +"Each ID triple consists of (ID, default unbound op, default fallback)."); + +#define _INTERPQUEUES_LIST_ALL_METHODDEF \ + {"list_all", (PyCFunction)_interpqueues_list_all, METH_NOARGS, _interpqueues_list_all__doc__}, + +static PyObject * +_interpqueues_list_all_impl(PyObject *module); + +static PyObject * +_interpqueues_list_all(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _interpqueues_list_all_impl(module); +} + +PyDoc_STRVAR(_interpqueues_put__doc__, +"put($module, /, qid, obj, unboundop=-1, fallback=-1)\n" +"--\n" +"\n" +"Add the object\'s data to the queue."); + +#define _INTERPQUEUES_PUT_METHODDEF \ + {"put", _PyCFunction_CAST(_interpqueues_put), METH_FASTCALL|METH_KEYWORDS, _interpqueues_put__doc__}, + +static PyObject * +_interpqueues_put_impl(PyObject *module, int64_t qid, PyObject *obj, + int unboundarg, int fallbackarg); + +static PyObject * +_interpqueues_put(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), &_Py_ID(obj), &_Py_ID(unboundop), &_Py_ID(fallback), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", "obj", "unboundop", "fallback", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "put", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + int64_t qid; + PyObject *obj; + int unboundarg = -1; + int fallbackarg = -1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + obj = args[1]; + if (!noptargs) { + goto skip_optional_pos; + } + if (args[2]) { + unboundarg = PyLong_AsInt(args[2]); + if (unboundarg == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + fallbackarg = PyLong_AsInt(args[3]); + if (fallbackarg == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = _interpqueues_put_impl(module, qid, obj, unboundarg, fallbackarg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_get__doc__, +"get($module, /, qid)\n" +"--\n" +"\n" +"Return the (object, unbound op) from the front of the queue.\n" +"\n" +"If there is nothing to receive then raise QueueEmpty."); + +#define _INTERPQUEUES_GET_METHODDEF \ + {"get", _PyCFunction_CAST(_interpqueues_get), METH_FASTCALL|METH_KEYWORDS, _interpqueues_get__doc__}, + +static PyObject * +_interpqueues_get_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_get(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_get_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_bind__doc__, +"bind($module, /, qid)\n" +"--\n" +"\n" +"Take a reference to the identified queue.\n" +"\n" +"The queue is not destroyed until there are no references left."); + +#define _INTERPQUEUES_BIND_METHODDEF \ + {"bind", _PyCFunction_CAST(_interpqueues_bind), METH_FASTCALL|METH_KEYWORDS, _interpqueues_bind__doc__}, + +static PyObject * +_interpqueues_bind_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_bind(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "bind", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_bind_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_release__doc__, +"release($module, /, qid)\n" +"--\n" +"\n" +"Release a reference to the queue.\n" +"\n" +"The queue is destroyed once there are no references left."); + +#define _INTERPQUEUES_RELEASE_METHODDEF \ + {"release", _PyCFunction_CAST(_interpqueues_release), METH_FASTCALL|METH_KEYWORDS, _interpqueues_release__doc__}, + +static PyObject * +_interpqueues_release_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_release(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "release", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_release_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_get_maxsize__doc__, +"get_maxsize($module, /, qid)\n" +"--\n" +"\n" +"Return the maximum number of items in the queue."); + +#define _INTERPQUEUES_GET_MAXSIZE_METHODDEF \ + {"get_maxsize", _PyCFunction_CAST(_interpqueues_get_maxsize), METH_FASTCALL|METH_KEYWORDS, _interpqueues_get_maxsize__doc__}, + +static PyObject * +_interpqueues_get_maxsize_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_get_maxsize(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_maxsize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_get_maxsize_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_get_queue_defaults__doc__, +"get_queue_defaults($module, /, qid)\n" +"--\n" +"\n" +"Return the queue\'s default values, set when it was created."); + +#define _INTERPQUEUES_GET_QUEUE_DEFAULTS_METHODDEF \ + {"get_queue_defaults", _PyCFunction_CAST(_interpqueues_get_queue_defaults), METH_FASTCALL|METH_KEYWORDS, _interpqueues_get_queue_defaults__doc__}, + +static PyObject * +_interpqueues_get_queue_defaults_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_get_queue_defaults(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_queue_defaults", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_get_queue_defaults_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_is_full__doc__, +"is_full($module, /, qid)\n" +"--\n" +"\n" +"Return true if the queue has a maxsize and has reached it."); + +#define _INTERPQUEUES_IS_FULL_METHODDEF \ + {"is_full", _PyCFunction_CAST(_interpqueues_is_full), METH_FASTCALL|METH_KEYWORDS, _interpqueues_is_full__doc__}, + +static PyObject * +_interpqueues_is_full_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_is_full(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_full", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_is_full_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues_get_count__doc__, +"get_count($module, /, qid)\n" +"--\n" +"\n" +"Return the number of items in the queue."); + +#define _INTERPQUEUES_GET_COUNT_METHODDEF \ + {"get_count", _PyCFunction_CAST(_interpqueues_get_count), METH_FASTCALL|METH_KEYWORDS, _interpqueues_get_count__doc__}, + +static PyObject * +_interpqueues_get_count_impl(PyObject *module, int64_t qid); + +static PyObject * +_interpqueues_get_count(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(qid), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"qid", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "get_count", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int64_t qid; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!qidarg_converter(args[0], &qid)) { + goto exit; + } + return_value = _interpqueues_get_count_impl(module, qid); + +exit: + return return_value; +} + +PyDoc_STRVAR(_interpqueues__register_heap_types__doc__, +"_register_heap_types($module, /, queuetype, emptyerror, fullerror)\n" +"--\n" +"\n" +"Return the number of items in the queue."); + +#define _INTERPQUEUES__REGISTER_HEAP_TYPES_METHODDEF \ + {"_register_heap_types", _PyCFunction_CAST(_interpqueues__register_heap_types), METH_FASTCALL|METH_KEYWORDS, _interpqueues__register_heap_types__doc__}, + +static PyObject * +_interpqueues__register_heap_types_impl(PyObject *module, + PyTypeObject *queuetype, + PyObject *emptyerror, + PyObject *fullerror); + +static PyObject * +_interpqueues__register_heap_types(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(queuetype), &_Py_ID(emptyerror), &_Py_ID(fullerror), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"queuetype", "emptyerror", "fullerror", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_register_heap_types", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyTypeObject *queuetype; + PyObject *emptyerror; + PyObject *fullerror; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyObject_TypeCheck(args[0], &PyType_Type)) { + _PyArg_BadArgument("_register_heap_types", "argument 'queuetype'", (&PyType_Type)->tp_name, args[0]); + goto exit; + } + queuetype = (PyTypeObject *)args[0]; + emptyerror = args[1]; + fullerror = args[2]; + return_value = _interpqueues__register_heap_types_impl(module, queuetype, emptyerror, fullerror); + +exit: + return return_value; +} +/*[clinic end generated code: output=64cea8e1063429b6 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_json.c.h b/Modules/clinic/_json.c.h new file mode 100644 index 00000000000..cd37a236c76 --- /dev/null +++ b/Modules/clinic/_json.c.h @@ -0,0 +1,128 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(py_scanstring__doc__, +"scanstring($module, pystr, end, strict=True, /)\n" +"--\n" +"\n" +"Scan the string s for a JSON string.\n" +"\n" +"End is the index of the character in s after the quote that started the\n" +"JSON string. Unescapes all valid JSON string escape sequences and raises\n" +"ValueError on attempt to decode an invalid string. If strict is False\n" +"then literal control characters are allowed in the string.\n" +"\n" +"Returns a tuple of the decoded string and the index of the character in s\n" +"after the end quote."); + +#define PY_SCANSTRING_METHODDEF \ + {"scanstring", _PyCFunction_CAST(py_scanstring), METH_FASTCALL, py_scanstring__doc__}, + +static PyObject * +py_scanstring_impl(PyObject *module, PyObject *pystr, Py_ssize_t end, + int strict); + +static PyObject * +py_scanstring(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *pystr; + Py_ssize_t end; + int strict = 1; + + if (!_PyArg_CheckPositional("scanstring", nargs, 2, 3)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("scanstring", "argument 1", "str", args[0]); + goto exit; + } + pystr = args[0]; + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + end = ival; + } + if (nargs < 3) { + goto skip_optional; + } + strict = PyObject_IsTrue(args[2]); + if (strict < 0) { + goto exit; + } +skip_optional: + return_value = py_scanstring_impl(module, pystr, end, strict); + +exit: + return return_value; +} + +PyDoc_STRVAR(py_encode_basestring_ascii__doc__, +"encode_basestring_ascii($module, pystr, /)\n" +"--\n" +"\n" +"Return an ASCII-only JSON representation of a Python string"); + +#define PY_ENCODE_BASESTRING_ASCII_METHODDEF \ + {"encode_basestring_ascii", (PyCFunction)py_encode_basestring_ascii, METH_O, py_encode_basestring_ascii__doc__}, + +static PyObject * +py_encode_basestring_ascii_impl(PyObject *module, PyObject *pystr); + +static PyObject * +py_encode_basestring_ascii(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *pystr; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("encode_basestring_ascii", "argument", "str", arg); + goto exit; + } + pystr = arg; + return_value = py_encode_basestring_ascii_impl(module, pystr); + +exit: + return return_value; +} + +PyDoc_STRVAR(py_encode_basestring__doc__, +"encode_basestring($module, pystr, /)\n" +"--\n" +"\n" +"Return a JSON representation of a Python string"); + +#define PY_ENCODE_BASESTRING_METHODDEF \ + {"encode_basestring", (PyCFunction)py_encode_basestring, METH_O, py_encode_basestring__doc__}, + +static PyObject * +py_encode_basestring_impl(PyObject *module, PyObject *pystr); + +static PyObject * +py_encode_basestring(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *pystr; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("encode_basestring", "argument", "str", arg); + goto exit; + } + pystr = arg; + return_value = py_encode_basestring_impl(module, pystr); + +exit: + return return_value; +} +/*[clinic end generated code: output=5bdd16375c95a4d9 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index c426cd6fe02..acb4aaf27e3 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__, @@ -45,11 +46,18 @@ _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls); static PyObject * _lsprof_Profiler_getstats(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { + PyObject *return_value = NULL; + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { PyErr_SetString(PyExc_TypeError, "getstats() takes no arguments"); - return NULL; + goto exit; } - return _lsprof_Profiler_getstats_impl((ProfilerObject *)self, cls); + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _lsprof_Profiler_getstats_impl((ProfilerObject *)self, cls); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; } PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, @@ -76,7 +84,9 @@ _lsprof_Profiler__pystart_callback(PyObject *self, PyObject *const *args, Py_ssi } code = args[0]; instruction_offset = args[1]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _lsprof_Profiler__pystart_callback_impl((ProfilerObject *)self, code, instruction_offset); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -109,7 +119,9 @@ _lsprof_Profiler__pythrow_callback(PyObject *self, PyObject *const *args, Py_ssi code = args[0]; instruction_offset = args[1]; exception = args[2]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _lsprof_Profiler__pythrow_callback_impl((ProfilerObject *)self, code, instruction_offset, exception); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -143,7 +155,9 @@ _lsprof_Profiler__pyreturn_callback(PyObject *self, PyObject *const *args, Py_ss code = args[0]; instruction_offset = args[1]; retval = args[2]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _lsprof_Profiler__pyreturn_callback_impl((ProfilerObject *)self, code, instruction_offset, retval); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -178,7 +192,9 @@ _lsprof_Profiler__ccall_callback(PyObject *self, PyObject *const *args, Py_ssize instruction_offset = args[1]; callable = args[2]; self_arg = args[3]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _lsprof_Profiler__ccall_callback_impl((ProfilerObject *)self, code, instruction_offset, callable, self_arg); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -215,7 +231,9 @@ _lsprof_Profiler__creturn_callback(PyObject *self, PyObject *const *args, Py_ssi instruction_offset = args[1]; callable = args[2]; self_arg = args[3]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _lsprof_Profiler__creturn_callback_impl((ProfilerObject *)self, code, instruction_offset, callable, self_arg); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -299,7 +317,9 @@ _lsprof_Profiler_enable(PyObject *self, PyObject *const *args, Py_ssize_t nargs, goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _lsprof_Profiler_enable_impl((ProfilerObject *)self, subcalls, builtins); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -320,7 +340,13 @@ _lsprof_Profiler_disable_impl(ProfilerObject *self); static PyObject * _lsprof_Profiler_disable(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _lsprof_Profiler_disable_impl((ProfilerObject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _lsprof_Profiler_disable_impl((ProfilerObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_lsprof_Profiler_clear__doc__, @@ -338,7 +364,13 @@ _lsprof_Profiler_clear_impl(ProfilerObject *self); static PyObject * _lsprof_Profiler_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _lsprof_Profiler_clear_impl((ProfilerObject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _lsprof_Profiler_clear_impl((ProfilerObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(profiler_init__doc__, @@ -444,4 +476,4 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=9e46985561166c37 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=af26a0b0ddcc3351 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_remote_debugging_module.c.h b/Modules/clinic/_remote_debugging_module.c.h index f6a51cdba6b..60adb357e32 100644 --- a/Modules/clinic/_remote_debugging_module.c.h +++ b/Modules/clinic/_remote_debugging_module.c.h @@ -11,7 +11,8 @@ preserve PyDoc_STRVAR(_remote_debugging_RemoteUnwinder___init____doc__, "RemoteUnwinder(pid, *, all_threads=False, only_active_thread=False,\n" -" debug=False)\n" +" mode=0, debug=False, skip_non_matching_threads=True,\n" +" native=False, gc=False)\n" "--\n" "\n" "Initialize a new RemoteUnwinder object for debugging a remote Python process.\n" @@ -21,9 +22,16 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder___init____doc__, " all_threads: If True, initialize state for all threads in the process.\n" " If False, only initialize for the main thread.\n" " only_active_thread: If True, only sample the thread holding the GIL.\n" +" mode: Profiling mode: 0=WALL (wall-time), 1=CPU (cpu-time), 2=GIL (gil-time).\n" " Cannot be used together with all_threads=True.\n" " debug: If True, chain exceptions to explain the sequence of events that\n" " lead to the exception.\n" +" skip_non_matching_threads: If True, skip threads that don\'t match the selected mode.\n" +" If False, include all threads regardless of mode.\n" +" native: If True, include artificial \"<native>\" frames to denote calls to\n" +" non-Python code.\n" +" gc: If True, include artificial \"<GC>\" frames to denote active garbage\n" +" collection.\n" "\n" "The RemoteUnwinder provides functionality to inspect and debug a running Python\n" "process, including examining thread states, stack frames and other runtime data.\n" @@ -38,7 +46,9 @@ static int _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, int pid, int all_threads, int only_active_thread, - int debug); + int mode, int debug, + int skip_non_matching_threads, + int native, int gc); static int _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObject *kwargs) @@ -46,7 +56,7 @@ _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObje int return_value = -1; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 4 + #define NUM_KEYWORDS 8 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -55,7 +65,7 @@ _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObje } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(pid), &_Py_ID(all_threads), &_Py_ID(only_active_thread), &_Py_ID(debug), }, + .ob_item = { &_Py_ID(pid), &_Py_ID(all_threads), &_Py_ID(only_active_thread), &_Py_ID(mode), &_Py_ID(debug), &_Py_ID(skip_non_matching_threads), &_Py_ID(native), &_Py_ID(gc), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -64,21 +74,25 @@ _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObje # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"pid", "all_threads", "only_active_thread", "debug", NULL}; + static const char * const _keywords[] = {"pid", "all_threads", "only_active_thread", "mode", "debug", "skip_non_matching_threads", "native", "gc", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "RemoteUnwinder", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[8]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; int pid; int all_threads = 0; int only_active_thread = 0; + int mode = 0; int debug = 0; + int skip_non_matching_threads = 1; + int native = 0; + int gc = 0; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); @@ -110,12 +124,48 @@ _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObje goto skip_optional_kwonly; } } - debug = PyObject_IsTrue(fastargs[3]); - if (debug < 0) { + if (fastargs[3]) { + mode = PyLong_AsInt(fastargs[3]); + if (mode == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[4]) { + debug = PyObject_IsTrue(fastargs[4]); + if (debug < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[5]) { + skip_non_matching_threads = PyObject_IsTrue(fastargs[5]); + if (skip_non_matching_threads < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[6]) { + native = PyObject_IsTrue(fastargs[6]); + if (native < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + gc = PyObject_IsTrue(fastargs[7]); + if (gc < 0) { goto exit; } skip_optional_kwonly: - return_value = _remote_debugging_RemoteUnwinder___init___impl((RemoteUnwinderObject *)self, pid, all_threads, only_active_thread, debug); + return_value = _remote_debugging_RemoteUnwinder___init___impl((RemoteUnwinderObject *)self, pid, all_threads, only_active_thread, mode, debug, skip_non_matching_threads, native, gc); exit: return return_value; @@ -125,28 +175,37 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_stack_trace__doc__, "get_stack_trace($self, /)\n" "--\n" "\n" -"Returns a list of stack traces for threads in the target process.\n" +"Returns stack traces for all interpreters and threads in process.\n" "\n" -"Each element in the returned list is a tuple of (thread_id, frame_list), where:\n" -"- thread_id is the OS thread identifier\n" -"- frame_list is a list of tuples (function_name, filename, line_number) representing\n" -" the Python stack frames for that thread, ordered from most recent to oldest\n" +"Each element in the returned list is a tuple of (interpreter_id, thread_list), where:\n" +"- interpreter_id is the interpreter identifier\n" +"- thread_list is a list of tuples (thread_id, frame_list) for threads in that interpreter\n" +" - thread_id is the OS thread identifier\n" +" - frame_list is a list of tuples (function_name, filename, line_number) representing\n" +" the Python stack frames for that thread, ordered from most recent to oldest\n" "\n" "The threads returned depend on the initialization parameters:\n" -"- If only_active_thread was True: returns only the thread holding the GIL\n" -"- If all_threads was True: returns all threads\n" -"- Otherwise: returns only the main thread\n" +"- If only_active_thread was True: returns only the thread holding the GIL across all interpreters\n" +"- If all_threads was True: returns all threads across all interpreters\n" +"- Otherwise: returns only the main thread of each interpreter\n" "\n" "Example:\n" " [\n" -" (1234, [\n" -" (\'process_data\', \'worker.py\', 127),\n" -" (\'run_worker\', \'worker.py\', 45),\n" -" (\'main\', \'app.py\', 23)\n" +" (0, [ # Main interpreter\n" +" (1234, [\n" +" (\'process_data\', \'worker.py\', 127),\n" +" (\'run_worker\', \'worker.py\', 45),\n" +" (\'main\', \'app.py\', 23)\n" +" ]),\n" +" (1235, [\n" +" (\'handle_request\', \'server.py\', 89),\n" +" (\'serve_forever\', \'server.py\', 52)\n" +" ])\n" " ]),\n" -" (1235, [\n" -" (\'handle_request\', \'server.py\', 89),\n" -" (\'serve_forever\', \'server.py\', 52)\n" +" (1, [ # Sub-interpreter\n" +" (1236, [\n" +" (\'sub_worker\', \'sub.py\', 15)\n" +" ])\n" " ])\n" " ]\n" "\n" @@ -288,4 +347,4 @@ _remote_debugging_RemoteUnwinder_get_async_stack_trace(PyObject *self, PyObject return return_value; } -/*[clinic end generated code: output=0dd1e6e8bab2a8b1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=99fed5c94cf36881 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index 5b80fab0abb..d1fb024903e 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -48,7 +48,7 @@ static PyObject * _ssl__test_decode_cert(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - PyObject *path; + PyObject *path = NULL; if (!PyUnicode_FSConverter(arg, &path)) { goto exit; @@ -56,6 +56,9 @@ _ssl__test_decode_cert(PyObject *module, PyObject *arg) return_value = _ssl__test_decode_cert_impl(module, path); exit: + /* Cleanup for path */ + Py_XDECREF(path); + return return_value; } @@ -219,6 +222,52 @@ _ssl__SSLSocket_group(PyObject *self, PyObject *Py_UNUSED(ignored)) return return_value; } +PyDoc_STRVAR(_ssl__SSLSocket_client_sigalg__doc__, +"client_sigalg($self, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLSOCKET_CLIENT_SIGALG_METHODDEF \ + {"client_sigalg", (PyCFunction)_ssl__SSLSocket_client_sigalg, METH_NOARGS, _ssl__SSLSocket_client_sigalg__doc__}, + +static PyObject * +_ssl__SSLSocket_client_sigalg_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_client_sigalg(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_client_sigalg_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLSocket_server_sigalg__doc__, +"server_sigalg($self, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLSOCKET_SERVER_SIGALG_METHODDEF \ + {"server_sigalg", (PyCFunction)_ssl__SSLSocket_server_sigalg, METH_NOARGS, _ssl__SSLSocket_server_sigalg__doc__}, + +static PyObject * +_ssl__SSLSocket_server_sigalg_impl(PySSLSocket *self); + +static PyObject * +_ssl__SSLSocket_server_sigalg(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLSocket_server_sigalg_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_ssl__SSLSocket_version__doc__, "version($self, /)\n" "--\n" @@ -969,6 +1018,45 @@ exit: return return_value; } +PyDoc_STRVAR(_ssl__SSLContext_set_ciphersuites__doc__, +"set_ciphersuites($self, ciphersuites, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLCONTEXT_SET_CIPHERSUITES_METHODDEF \ + {"set_ciphersuites", (PyCFunction)_ssl__SSLContext_set_ciphersuites, METH_O, _ssl__SSLContext_set_ciphersuites__doc__}, + +static PyObject * +_ssl__SSLContext_set_ciphersuites_impl(PySSLContext *self, + const char *ciphersuites); + +static PyObject * +_ssl__SSLContext_set_ciphersuites(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + const char *ciphersuites; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("set_ciphersuites", "argument", "str", arg); + goto exit; + } + Py_ssize_t ciphersuites_length; + ciphersuites = PyUnicode_AsUTF8AndSize(arg, &ciphersuites_length); + if (ciphersuites == NULL) { + goto exit; + } + if (strlen(ciphersuites) != (size_t)ciphersuites_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_set_ciphersuites_impl((PySSLContext *)self, ciphersuites); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + PyDoc_STRVAR(_ssl__SSLContext_get_ciphers__doc__, "get_ciphers($self, /)\n" "--\n" @@ -1097,6 +1185,84 @@ exit: return return_value; } +PyDoc_STRVAR(_ssl__SSLContext_set_client_sigalgs__doc__, +"set_client_sigalgs($self, sigalgslist, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLCONTEXT_SET_CLIENT_SIGALGS_METHODDEF \ + {"set_client_sigalgs", (PyCFunction)_ssl__SSLContext_set_client_sigalgs, METH_O, _ssl__SSLContext_set_client_sigalgs__doc__}, + +static PyObject * +_ssl__SSLContext_set_client_sigalgs_impl(PySSLContext *self, + const char *sigalgslist); + +static PyObject * +_ssl__SSLContext_set_client_sigalgs(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + const char *sigalgslist; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("set_client_sigalgs", "argument", "str", arg); + goto exit; + } + Py_ssize_t sigalgslist_length; + sigalgslist = PyUnicode_AsUTF8AndSize(arg, &sigalgslist_length); + if (sigalgslist == NULL) { + goto exit; + } + if (strlen(sigalgslist) != (size_t)sigalgslist_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_set_client_sigalgs_impl((PySSLContext *)self, sigalgslist); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(_ssl__SSLContext_set_server_sigalgs__doc__, +"set_server_sigalgs($self, sigalgslist, /)\n" +"--\n" +"\n"); + +#define _SSL__SSLCONTEXT_SET_SERVER_SIGALGS_METHODDEF \ + {"set_server_sigalgs", (PyCFunction)_ssl__SSLContext_set_server_sigalgs, METH_O, _ssl__SSLContext_set_server_sigalgs__doc__}, + +static PyObject * +_ssl__SSLContext_set_server_sigalgs_impl(PySSLContext *self, + const char *sigalgslist); + +static PyObject * +_ssl__SSLContext_set_server_sigalgs(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + const char *sigalgslist; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("set_server_sigalgs", "argument", "str", arg); + goto exit; + } + Py_ssize_t sigalgslist_length; + sigalgslist = PyUnicode_AsUTF8AndSize(arg, &sigalgslist_length); + if (sigalgslist == NULL) { + goto exit; + } + if (strlen(sigalgslist) != (size_t)sigalgslist_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _ssl__SSLContext_set_server_sigalgs_impl((PySSLContext *)self, sigalgslist); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + PyDoc_STRVAR(_ssl__SSLContext__set_alpn_protocols__doc__, "_set_alpn_protocols($self, protos, /)\n" "--\n" @@ -2853,6 +3019,23 @@ _ssl_get_default_verify_paths(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +PyDoc_STRVAR(_ssl_get_sigalgs__doc__, +"get_sigalgs($module, /)\n" +"--\n" +"\n"); + +#define _SSL_GET_SIGALGS_METHODDEF \ + {"get_sigalgs", (PyCFunction)_ssl_get_sigalgs, METH_NOARGS, _ssl_get_sigalgs__doc__}, + +static PyObject * +_ssl_get_sigalgs_impl(PyObject *module); + +static PyObject * +_ssl_get_sigalgs(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _ssl_get_sigalgs_impl(module); +} + PyDoc_STRVAR(_ssl_txt2obj__doc__, "txt2obj($module, /, txt, name=False)\n" "--\n" @@ -3142,4 +3325,4 @@ exit: #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=c409bdf3c123b28b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3b6c9cbfc4660ecb input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_suggestions.c.h b/Modules/clinic/_suggestions.c.h index 51484b13d5a..3b3ed5056ac 100644 --- a/Modules/clinic/_suggestions.c.h +++ b/Modules/clinic/_suggestions.c.h @@ -2,6 +2,7 @@ preserve [clinic start generated code]*/ +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_suggestions__generate_suggestions__doc__, @@ -33,9 +34,11 @@ _suggestions__generate_suggestions(PyObject *module, PyObject *const *args, Py_s goto exit; } item = args[1]; + Py_BEGIN_CRITICAL_SECTION(candidates); return_value = _suggestions__generate_suggestions_impl(module, candidates, item); + Py_END_CRITICAL_SECTION(); exit: return return_value; } -/*[clinic end generated code: output=1d8e963cdae30b13 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1690dd15a464d19c input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 68c92a86226..9bcd0eeb008 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -9,7 +9,7 @@ preserve #include "pycore_long.h" // _PyLong_UnsignedShort_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_runtime.h" // _Py_ID() -#include "pycore_tuple.h" // _PyTuple_FromArray() +#include "pycore_tuple.h" // _PyTuple_ITEMS() PyDoc_STRVAR(test_empty_function__doc__, "test_empty_function($module, /)\n" @@ -1196,7 +1196,8 @@ exit: } PyDoc_STRVAR(py_ssize_t_converter__doc__, -"py_ssize_t_converter($module, a=12, b=34, c=56, /)\n" +"py_ssize_t_converter($module, a=12, b=34, c=56, d=78, e=90, f=-12,\n" +" g=-34, /)\n" "--\n" "\n"); @@ -1205,7 +1206,8 @@ PyDoc_STRVAR(py_ssize_t_converter__doc__, static PyObject * py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b, - Py_ssize_t c); + Py_ssize_t c, Py_ssize_t d, Py_ssize_t e, + Py_ssize_t f, Py_ssize_t g); static PyObject * py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) @@ -1214,8 +1216,12 @@ py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) Py_ssize_t a = 12; Py_ssize_t b = 34; Py_ssize_t c = 56; + Py_ssize_t d = 78; + Py_ssize_t e = 90; + Py_ssize_t f = -12; + Py_ssize_t g = -34; - if (!_PyArg_CheckPositional("py_ssize_t_converter", nargs, 0, 3)) { + if (!_PyArg_CheckPositional("py_ssize_t_converter", nargs, 0, 7)) { goto exit; } if (nargs < 1) { @@ -1254,8 +1260,60 @@ py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_Py_convert_optional_to_ssize_t(args[2], &c)) { goto exit; } + if (nargs < 4) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[3]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + d = ival; + if (d < 0) { + PyErr_SetString(PyExc_ValueError, + "d cannot be negative"); + goto exit; + } + } + if (nargs < 5) { + goto skip_optional; + } + if (!_Py_convert_optional_to_non_negative_ssize_t(args[4], &e)) { + goto exit; + } + if (nargs < 6) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[5]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + f = ival; + if (f < 0) { + PyErr_SetString(PyExc_ValueError, + "f cannot be negative"); + goto exit; + } + } + if (nargs < 7) { + goto skip_optional; + } + if (!_Py_convert_optional_to_non_negative_ssize_t(args[6], &g)) { + goto exit; + } skip_optional: - return_value = py_ssize_t_converter_impl(module, a, b, c); + return_value = py_ssize_t_converter_impl(module, a, b, c, d, e, f, g); exit: return return_value; @@ -2706,7 +2764,7 @@ varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; PyObject *__clinic_args = NULL; - __clinic_args = _PyTuple_FromArray(args, nargs); + __clinic_args = PyTuple_FromArray(args, nargs); if (__clinic_args == NULL) { goto exit; } @@ -2744,7 +2802,7 @@ posonly_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } a = args[0]; b = args[1]; - __clinic_args = _PyTuple_FromArray(args + 2, nargs - 2); + __clinic_args = PyTuple_FromArray(args + 2, nargs - 2); if (__clinic_args == NULL) { goto exit; } @@ -2787,7 +2845,7 @@ posonly_req_opt_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs b = args[1]; skip_optional: __clinic_args = nargs > 2 - ? _PyTuple_FromArray(args + 2, nargs - 2) + ? PyTuple_FromArray(args + 2, nargs - 2) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -2858,7 +2916,7 @@ posonly_poskw_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs, a = fastargs[0]; b = fastargs[1]; __clinic_args = nargs > 2 - ? _PyTuple_FromArray(args + 2, nargs - 2) + ? PyTuple_FromArray(args + 2, nargs - 2) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -2926,7 +2984,7 @@ poskw_varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject } a = fastargs[0]; __clinic_args = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -3005,7 +3063,7 @@ poskw_varpos_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t narg } skip_optional_kwonly: __clinic_args = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -3088,7 +3146,7 @@ poskw_varpos_kwonly_opt2(PyObject *module, PyObject *const *args, Py_ssize_t nar c = fastargs[2]; skip_optional_kwonly: __clinic_args = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -3160,7 +3218,7 @@ varpos_kwonly_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO } b = fastargs[0]; skip_optional_kwonly: - __clinic_args = _PyTuple_FromArray(args, nargs); + __clinic_args = PyTuple_FromArray(args, nargs); if (__clinic_args == NULL) { goto exit; } @@ -3241,7 +3299,7 @@ varpos_kwonly_req_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs, } c = fastargs[2]; skip_optional_kwonly: - __clinic_args = _PyTuple_FromArray(args, nargs); + __clinic_args = PyTuple_FromArray(args, nargs); if (__clinic_args == NULL) { goto exit; } @@ -3491,7 +3549,7 @@ gh_32092_oob(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject kw2 = fastargs[3]; skip_optional_kwonly: varargs = nargs > 2 - ? _PyTuple_FromArray(args + 2, nargs - 2) + ? PyTuple_FromArray(args + 2, nargs - 2) : PyTuple_New(0); if (varargs == NULL) { goto exit; @@ -3568,7 +3626,7 @@ gh_32092_kw_pass(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb kw = fastargs[1]; skip_optional_kwonly: __clinic_args = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (__clinic_args == NULL) { goto exit; @@ -3600,7 +3658,7 @@ gh_99233_refcount(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; PyObject *__clinic_args = NULL; - __clinic_args = _PyTuple_FromArray(args, nargs); + __clinic_args = PyTuple_FromArray(args, nargs); if (__clinic_args == NULL) { goto exit; } @@ -3713,7 +3771,7 @@ null_or_tuple_for_varargs(PyObject *module, PyObject *const *args, Py_ssize_t na } skip_optional_kwonly: constraints = nargs > 1 - ? _PyTuple_FromArray(args + 1, nargs - 1) + ? PyTuple_FromArray(args + 1, nargs - 1) : PyTuple_New(0); if (constraints == NULL) { goto exit; @@ -4116,7 +4174,7 @@ _testclinic_TestClass_defclass_varpos(PyObject *self, PyTypeObject *cls, PyObjec if (!fastargs) { goto exit; } - __clinic_args = _PyTuple_FromArray(args, nargs); + __clinic_args = PyTuple_FromArray(args, nargs); if (__clinic_args == NULL) { goto exit; } @@ -4173,7 +4231,7 @@ _testclinic_TestClass_defclass_posonly_varpos(PyObject *self, PyTypeObject *cls, } a = fastargs[0]; b = fastargs[1]; - __clinic_args = _PyTuple_FromArray(args + 2, nargs - 2); + __clinic_args = PyTuple_FromArray(args + 2, nargs - 2); if (__clinic_args == NULL) { goto exit; } @@ -4542,4 +4600,4 @@ _testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall(PyObject *type, PyO exit: return return_value; } -/*[clinic end generated code: output=6b04671afdafbecf input=a9049054013a1b77]*/ +/*[clinic end generated code: output=290d2e346ea7bfa1 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic_depr.c.h b/Modules/clinic/_testclinic_depr.c.h index a46d238801b..e2db4fd87ed 100644 --- a/Modules/clinic/_testclinic_depr.c.h +++ b/Modules/clinic/_testclinic_depr.c.h @@ -9,7 +9,7 @@ preserve #include "pycore_long.h" // _PyLong_UnsignedShort_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_runtime.h" // _Py_ID() -#include "pycore_tuple.h" // _PyTuple_FromArray() +#include "pycore_tuple.h" // _PyTuple_ITEMS() PyDoc_STRVAR(depr_star_new__doc__, "DeprStarNew(a=None)\n" @@ -2474,4 +2474,4 @@ depr_multi(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject * exit: return return_value; } -/*[clinic end generated code: output=4e60af44fd6b7b94 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2231bec0ed196830 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic_kwds.c.h b/Modules/clinic/_testclinic_kwds.c.h new file mode 100644 index 00000000000..86cad50c56c --- /dev/null +++ b/Modules/clinic/_testclinic_kwds.c.h @@ -0,0 +1,184 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +#endif +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_long.h" // _PyLong_UnsignedShort_Converter() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() +#include "pycore_runtime.h" // _Py_ID() +#include "pycore_tuple.h" // _PyTuple_ITEMS() + +PyDoc_STRVAR(lone_kwds__doc__, +"lone_kwds($module, /, **kwds)\n" +"--\n" +"\n"); + +#define LONE_KWDS_METHODDEF \ + {"lone_kwds", _PyCFunction_CAST(lone_kwds), METH_VARARGS|METH_KEYWORDS, lone_kwds__doc__}, + +static PyObject * +lone_kwds_impl(PyObject *module, PyObject *kwds); + +static PyObject * +lone_kwds(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_kwds = NULL; + + if (!_PyArg_NoPositional("lone_kwds", args)) { + goto exit; + } + if (kwargs == NULL) { + __clinic_kwds = PyDict_New(); + if (__clinic_kwds == NULL) { + goto exit; + } + } + else { + __clinic_kwds = Py_NewRef(kwargs); + } + return_value = lone_kwds_impl(module, __clinic_kwds); + +exit: + /* Cleanup for kwds */ + Py_XDECREF(__clinic_kwds); + + return return_value; +} + +PyDoc_STRVAR(kwds_with_pos_only__doc__, +"kwds_with_pos_only($module, a, b, /, **kwds)\n" +"--\n" +"\n"); + +#define KWDS_WITH_POS_ONLY_METHODDEF \ + {"kwds_with_pos_only", _PyCFunction_CAST(kwds_with_pos_only), METH_VARARGS|METH_KEYWORDS, kwds_with_pos_only__doc__}, + +static PyObject * +kwds_with_pos_only_impl(PyObject *module, PyObject *a, PyObject *b, + PyObject *kwds); + +static PyObject * +kwds_with_pos_only(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + PyObject *__clinic_kwds = NULL; + + if (!_PyArg_CheckPositional("kwds_with_pos_only", PyTuple_GET_SIZE(args), 2, 2)) { + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + b = PyTuple_GET_ITEM(args, 1); + if (kwargs == NULL) { + __clinic_kwds = PyDict_New(); + if (__clinic_kwds == NULL) { + goto exit; + } + } + else { + __clinic_kwds = Py_NewRef(kwargs); + } + return_value = kwds_with_pos_only_impl(module, a, b, __clinic_kwds); + +exit: + /* Cleanup for kwds */ + Py_XDECREF(__clinic_kwds); + + return return_value; +} + +PyDoc_STRVAR(kwds_with_stararg__doc__, +"kwds_with_stararg($module, /, *args, **kwds)\n" +"--\n" +"\n"); + +#define KWDS_WITH_STARARG_METHODDEF \ + {"kwds_with_stararg", _PyCFunction_CAST(kwds_with_stararg), METH_VARARGS|METH_KEYWORDS, kwds_with_stararg__doc__}, + +static PyObject * +kwds_with_stararg_impl(PyObject *module, PyObject *args, PyObject *kwds); + +static PyObject * +kwds_with_stararg(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + PyObject *__clinic_kwds = NULL; + + __clinic_args = Py_NewRef(args); + if (kwargs == NULL) { + __clinic_kwds = PyDict_New(); + if (__clinic_kwds == NULL) { + goto exit; + } + } + else { + __clinic_kwds = Py_NewRef(kwargs); + } + return_value = kwds_with_stararg_impl(module, __clinic_args, __clinic_kwds); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + /* Cleanup for kwds */ + Py_XDECREF(__clinic_kwds); + + return return_value; +} + +PyDoc_STRVAR(kwds_with_pos_only_and_stararg__doc__, +"kwds_with_pos_only_and_stararg($module, a, b, /, *args, **kwds)\n" +"--\n" +"\n"); + +#define KWDS_WITH_POS_ONLY_AND_STARARG_METHODDEF \ + {"kwds_with_pos_only_and_stararg", _PyCFunction_CAST(kwds_with_pos_only_and_stararg), METH_VARARGS|METH_KEYWORDS, kwds_with_pos_only_and_stararg__doc__}, + +static PyObject * +kwds_with_pos_only_and_stararg_impl(PyObject *module, PyObject *a, + PyObject *b, PyObject *args, + PyObject *kwds); + +static PyObject * +kwds_with_pos_only_and_stararg(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + PyObject *__clinic_args = NULL; + PyObject *__clinic_kwds = NULL; + + if (!_PyArg_CheckPositional("kwds_with_pos_only_and_stararg", PyTuple_GET_SIZE(args), 2, PY_SSIZE_T_MAX)) { + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + b = PyTuple_GET_ITEM(args, 1); + __clinic_args = PyTuple_GetSlice(args, 2, PY_SSIZE_T_MAX); + if (!__clinic_args) { + goto exit; + } + if (kwargs == NULL) { + __clinic_kwds = PyDict_New(); + if (__clinic_kwds == NULL) { + goto exit; + } + } + else { + __clinic_kwds = Py_NewRef(kwargs); + } + return_value = kwds_with_pos_only_and_stararg_impl(module, a, b, __clinic_args, __clinic_kwds); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + /* Cleanup for kwds */ + Py_XDECREF(__clinic_kwds); + + return return_value; +} +/*[clinic end generated code: output=3e5251b10aa44382 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 97e5ca771f3..2648583c654 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -419,6 +419,11 @@ array_array_fromfile(PyObject *self, PyTypeObject *cls, PyObject *const *args, P goto exit; } n = ival; + if (n < 0) { + PyErr_SetString(PyExc_ValueError, + "n cannot be negative"); + goto exit; + } } return_value = array_array_fromfile_impl((arrayobject *)self, cls, f, n); @@ -773,4 +778,4 @@ array_arrayiterator___setstate__(PyObject *self, PyObject *state) return return_value; } -/*[clinic end generated code: output=dd49451ac1cc3f39 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c993c3598085840e input=a9049054013a1b77]*/ diff --git a/Modules/clinic/fcntlmodule.c.h b/Modules/clinic/fcntlmodule.c.h index 005e9b9e12a..718f80bfe73 100644 --- a/Modules/clinic/fcntlmodule.c.h +++ b/Modules/clinic/fcntlmodule.c.h @@ -2,24 +2,31 @@ preserve [clinic start generated code]*/ +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + PyDoc_STRVAR(fcntl_fcntl__doc__, "fcntl($module, fd, cmd, arg=0, /)\n" "--\n" "\n" -"Perform the operation `cmd` on file descriptor fd.\n" +"Perform the operation cmd on file descriptor fd.\n" "\n" -"The values used for `cmd` are operating system dependent, and are available\n" -"as constants in the fcntl module, using the same names as used in\n" -"the relevant C header files. The argument arg is optional, and\n" -"defaults to 0; it may be an int or a string. If arg is given as a string,\n" -"the return value of fcntl is a string of that length, containing the\n" -"resulting value put in the arg buffer by the operating system. The length\n" -"of the arg string is not allowed to exceed 1024 bytes. If the arg given\n" -"is an integer or if none is specified, the result value is an integer\n" -"corresponding to the return value of the fcntl call in the C code."); +"The values used for cmd are operating system dependent, and are\n" +"available as constants in the fcntl module, using the same names as used\n" +"in the relevant C header files. The argument arg is optional, and\n" +"defaults to 0; it may be an integer, a bytes-like object or a string.\n" +"If arg is given as a string, it will be encoded to binary using the\n" +"UTF-8 encoding.\n" +"\n" +"If the arg given is an integer or if none is specified, the result value\n" +"is an integer corresponding to the return value of the fcntl() call in\n" +"the C code.\n" +"\n" +"If arg is given as a bytes-like object, the return value of fcntl() is a\n" +"bytes object of that length, containing the resulting value put in the\n" +"arg buffer by the operating system."); #define FCNTL_FCNTL_METHODDEF \ - {"fcntl", (PyCFunction)(void(*)(void))fcntl_fcntl, METH_FASTCALL, fcntl_fcntl__doc__}, + {"fcntl", _PyCFunction_CAST(fcntl_fcntl), METH_FASTCALL, fcntl_fcntl__doc__}, static PyObject * fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg); @@ -32,12 +39,7 @@ fcntl_fcntl(PyObject *module, PyObject *const *args, Py_ssize_t nargs) int code; PyObject *arg = NULL; - if (nargs < 2) { - PyErr_Format(PyExc_TypeError, "fcntl expected at least 2 arguments, got %zd", nargs); - goto exit; - } - if (nargs > 3) { - PyErr_Format(PyExc_TypeError, "fcntl expected at most 3 arguments, got %zd", nargs); + if (!_PyArg_CheckPositional("fcntl", nargs, 2, 3)) { goto exit; } fd = PyObject_AsFileDescriptor(args[0]); @@ -63,37 +65,36 @@ PyDoc_STRVAR(fcntl_ioctl__doc__, "ioctl($module, fd, request, arg=0, mutate_flag=True, /)\n" "--\n" "\n" -"Perform the operation `request` on file descriptor `fd`.\n" +"Perform the operation request on file descriptor fd.\n" "\n" -"The values used for `request` are operating system dependent, and are available\n" -"as constants in the fcntl or termios library modules, using the same names as\n" -"used in the relevant C header files.\n" +"The values used for request are operating system dependent, and are\n" +"available as constants in the fcntl or termios library modules, using\n" +"the same names as used in the relevant C header files.\n" "\n" -"The argument `arg` is optional, and defaults to 0; it may be an int or a\n" -"buffer containing character data (most likely a string or an array).\n" +"The argument arg is optional, and defaults to 0; it may be an integer, a\n" +"bytes-like object or a string. If arg is given as a string, it will be\n" +"encoded to binary using the UTF-8 encoding.\n" "\n" -"If the argument is a mutable buffer (such as an array) and if the\n" -"mutate_flag argument (which is only allowed in this case) is true then the\n" -"buffer is (in effect) passed to the operating system and changes made by\n" -"the OS will be reflected in the contents of the buffer after the call has\n" -"returned. The return value is the integer returned by the ioctl system\n" -"call.\n" +"If the arg given is an integer or if none is specified, the result value\n" +"is an integer corresponding to the return value of the ioctl() call in\n" +"the C code.\n" "\n" -"If the argument is a mutable buffer and the mutable_flag argument is false,\n" -"the behavior is as if a string had been passed.\n" +"If the argument is a mutable buffer (such as a bytearray) and the\n" +"mutate_flag argument is true (default) then the buffer is (in effect)\n" +"passed to the operating system and changes made by the OS will be\n" +"reflected in the contents of the buffer after the call has returned.\n" +"The return value is the integer returned by the ioctl() system call.\n" "\n" -"If the argument is an immutable buffer (most likely a string) then a copy\n" -"of the buffer is passed to the operating system and the return value is a\n" -"string of the same length containing whatever the operating system put in\n" -"the buffer. The length of the arg buffer in this case is not allowed to\n" -"exceed 1024 bytes.\n" +"If the argument is a mutable buffer and the mutable_flag argument is\n" +"false, the behavior is as if an immutable buffer had been passed.\n" "\n" -"If the arg given is an integer or if none is specified, the result value is\n" -"an integer corresponding to the return value of the ioctl call in the C\n" -"code."); +"If the argument is an immutable buffer then a copy of the buffer is\n" +"passed to the operating system and the return value is a bytes object of\n" +"the same length containing whatever the operating system put in the\n" +"buffer."); #define FCNTL_IOCTL_METHODDEF \ - {"ioctl", (PyCFunction)(void(*)(void))fcntl_ioctl, METH_FASTCALL, fcntl_ioctl__doc__}, + {"ioctl", _PyCFunction_CAST(fcntl_ioctl), METH_FASTCALL, fcntl_ioctl__doc__}, static PyObject * fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, @@ -108,12 +109,7 @@ fcntl_ioctl(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *arg = NULL; int mutate_arg = 1; - if (nargs < 2) { - PyErr_Format(PyExc_TypeError, "ioctl expected at least 2 arguments, got %zd", nargs); - goto exit; - } - if (nargs > 4) { - PyErr_Format(PyExc_TypeError, "ioctl expected at most 4 arguments, got %zd", nargs); + if (!_PyArg_CheckPositional("ioctl", nargs, 2, 4)) { goto exit; } fd = PyObject_AsFileDescriptor(args[0]); @@ -121,7 +117,7 @@ fcntl_ioctl(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (!PyIndex_Check(args[1])) { - PyErr_Format(PyExc_TypeError, "ioctl() argument 2 must be int, not %T", args[1]); + _PyArg_BadArgument("ioctl", "argument 2", "int", args[1]); goto exit; } { @@ -162,13 +158,13 @@ PyDoc_STRVAR(fcntl_flock__doc__, "flock($module, fd, operation, /)\n" "--\n" "\n" -"Perform the lock operation `operation` on file descriptor `fd`.\n" +"Perform the lock operation on file descriptor fd.\n" "\n" "See the Unix manual page for flock(2) for details (On some systems, this\n" "function is emulated using fcntl())."); #define FCNTL_FLOCK_METHODDEF \ - {"flock", (PyCFunction)(void(*)(void))fcntl_flock, METH_FASTCALL, fcntl_flock__doc__}, + {"flock", _PyCFunction_CAST(fcntl_flock), METH_FASTCALL, fcntl_flock__doc__}, static PyObject * fcntl_flock_impl(PyObject *module, int fd, int code); @@ -180,8 +176,7 @@ fcntl_flock(PyObject *module, PyObject *const *args, Py_ssize_t nargs) int fd; int code; - if (nargs != 2) { - PyErr_Format(PyExc_TypeError, "flock expected 2 arguments, got %zd", nargs); + if (!_PyArg_CheckPositional("flock", nargs, 2, 2)) { goto exit; } fd = PyObject_AsFileDescriptor(args[0]); @@ -204,29 +199,29 @@ PyDoc_STRVAR(fcntl_lockf__doc__, "\n" "A wrapper around the fcntl() locking calls.\n" "\n" -"`fd` is the file descriptor of the file to lock or unlock, and operation is one\n" -"of the following values:\n" +"fd is the file descriptor of the file to lock or unlock, and operation\n" +"is one of the following values:\n" "\n" " LOCK_UN - unlock\n" " LOCK_SH - acquire a shared lock\n" " LOCK_EX - acquire an exclusive lock\n" "\n" "When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n" -"LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n" -"lock cannot be acquired, an OSError will be raised and the exception will\n" -"have an errno attribute set to EACCES or EAGAIN (depending on the operating\n" -"system -- for portability, check for either value).\n" +"LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and\n" +"the lock cannot be acquired, an OSError will be raised and the exception\n" +"will have an errno attribute set to EACCES or EAGAIN (depending on the\n" +"operating system -- for portability, check for either value).\n" "\n" -"`len` is the number of bytes to lock, with the default meaning to lock to\n" -"EOF. `start` is the byte offset, relative to `whence`, to that the lock\n" -"starts. `whence` is as with fileobj.seek(), specifically:\n" +"len is the number of bytes to lock, with the default meaning to lock to\n" +"EOF. start is the byte offset, relative to whence, to that the lock\n" +"starts. whence is as with fileobj.seek(), specifically:\n" "\n" " 0 - relative to the start of the file (SEEK_SET)\n" " 1 - relative to the current buffer position (SEEK_CUR)\n" " 2 - relative to the end of the file (SEEK_END)"); #define FCNTL_LOCKF_METHODDEF \ - {"lockf", (PyCFunction)(void(*)(void))fcntl_lockf, METH_FASTCALL, fcntl_lockf__doc__}, + {"lockf", _PyCFunction_CAST(fcntl_lockf), METH_FASTCALL, fcntl_lockf__doc__}, static PyObject * fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj, @@ -242,12 +237,7 @@ fcntl_lockf(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *startobj = NULL; int whence = 0; - if (nargs < 2) { - PyErr_Format(PyExc_TypeError, "lockf expected at least 2 arguments, got %zd", nargs); - goto exit; - } - if (nargs > 5) { - PyErr_Format(PyExc_TypeError, "lockf expected at most 5 arguments, got %zd", nargs); + if (!_PyArg_CheckPositional("lockf", nargs, 2, 5)) { goto exit; } fd = PyObject_AsFileDescriptor(args[0]); @@ -279,4 +269,4 @@ skip_optional: exit: return return_value; } -/*[clinic end generated code: output=bf84289b741e7cf6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c782fcf9dd6690e0 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/gcmodule.c.h b/Modules/clinic/gcmodule.c.h index 53ff9e4faf8..08275e35413 100644 --- a/Modules/clinic/gcmodule.c.h +++ b/Modules/clinic/gcmodule.c.h @@ -8,7 +8,6 @@ preserve #endif #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() -#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(gc_enable__doc__, "enable($module, /)\n" @@ -324,7 +323,7 @@ gc_get_referrers(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; PyObject *objs = NULL; - objs = _PyTuple_FromArray(args, nargs); + objs = PyTuple_FromArray(args, nargs); if (objs == NULL) { goto exit; } @@ -355,7 +354,7 @@ gc_get_referents(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; PyObject *objs = NULL; - objs = _PyTuple_FromArray(args, nargs); + objs = PyTuple_FromArray(args, nargs); if (objs == NULL) { goto exit; } @@ -584,4 +583,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=96d057eac558e6ca input=a9049054013a1b77]*/ +/*[clinic end generated code: output=19738854607938db input=a9049054013a1b77]*/ diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h index 0af82e7eb05..49816bfcb42 100644 --- a/Modules/clinic/itertoolsmodule.c.h +++ b/Modules/clinic/itertoolsmodule.c.h @@ -345,6 +345,11 @@ itertools_tee(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } n = ival; + if (n < 0) { + PyErr_SetString(PyExc_ValueError, + "n cannot be negative"); + goto exit; + } } skip_optional: return_value = itertools_tee_impl(module, iterable, n); @@ -569,6 +574,11 @@ itertools_combinations(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto exit; } r = ival; + if (r < 0) { + PyErr_SetString(PyExc_ValueError, + "r cannot be negative"); + goto exit; + } } return_value = itertools_combinations_impl(type, iterable, r); @@ -643,6 +653,11 @@ itertools_combinations_with_replacement(PyTypeObject *type, PyObject *args, PyOb goto exit; } r = ival; + if (r < 0) { + PyErr_SetString(PyExc_ValueError, + "r cannot be negative"); + goto exit; + } } return_value = itertools_combinations_with_replacement_impl(type, iterable, r); @@ -965,4 +980,4 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=999758202a532e0a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7f385837b13edbeb input=a9049054013a1b77]*/ diff --git a/Modules/clinic/mathintegermodule.c.h b/Modules/clinic/mathintegermodule.c.h new file mode 100644 index 00000000000..29c2a0ac902 --- /dev/null +++ b/Modules/clinic/mathintegermodule.c.h @@ -0,0 +1,159 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(math_integer_gcd__doc__, +"gcd($module, /, *integers)\n" +"--\n" +"\n" +"Greatest Common Divisor."); + +#define MATH_INTEGER_GCD_METHODDEF \ + {"gcd", _PyCFunction_CAST(math_integer_gcd), METH_FASTCALL, math_integer_gcd__doc__}, + +static PyObject * +math_integer_gcd_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +math_integer_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + __clinic_args = args; + args_length = nargs; + return_value = math_integer_gcd_impl(module, __clinic_args, args_length); + + return return_value; +} + +PyDoc_STRVAR(math_integer_lcm__doc__, +"lcm($module, /, *integers)\n" +"--\n" +"\n" +"Least Common Multiple."); + +#define MATH_INTEGER_LCM_METHODDEF \ + {"lcm", _PyCFunction_CAST(math_integer_lcm), METH_FASTCALL, math_integer_lcm__doc__}, + +static PyObject * +math_integer_lcm_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +math_integer_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + __clinic_args = args; + args_length = nargs; + return_value = math_integer_lcm_impl(module, __clinic_args, args_length); + + return return_value; +} + +PyDoc_STRVAR(math_integer_isqrt__doc__, +"isqrt($module, n, /)\n" +"--\n" +"\n" +"Return the integer part of the square root of the input."); + +#define MATH_INTEGER_ISQRT_METHODDEF \ + {"isqrt", (PyCFunction)math_integer_isqrt, METH_O, math_integer_isqrt__doc__}, + +PyDoc_STRVAR(math_integer_factorial__doc__, +"factorial($module, n, /)\n" +"--\n" +"\n" +"Find n!."); + +#define MATH_INTEGER_FACTORIAL_METHODDEF \ + {"factorial", (PyCFunction)math_integer_factorial, METH_O, math_integer_factorial__doc__}, + +PyDoc_STRVAR(math_integer_perm__doc__, +"perm($module, n, k=None, /)\n" +"--\n" +"\n" +"Number of ways to choose k items from n items without repetition and with order.\n" +"\n" +"Evaluates to n! / (n - k)! when k <= n and evaluates\n" +"to zero when k > n.\n" +"\n" +"If k is not specified or is None, then k defaults to n\n" +"and the function returns n!.\n" +"\n" +"Raises ValueError if either of the arguments are negative."); + +#define MATH_INTEGER_PERM_METHODDEF \ + {"perm", _PyCFunction_CAST(math_integer_perm), METH_FASTCALL, math_integer_perm__doc__}, + +static PyObject * +math_integer_perm_impl(PyObject *module, PyObject *n, PyObject *k); + +static PyObject * +math_integer_perm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *n; + PyObject *k = Py_None; + + if (!_PyArg_CheckPositional("perm", nargs, 1, 2)) { + goto exit; + } + n = args[0]; + if (nargs < 2) { + goto skip_optional; + } + k = args[1]; +skip_optional: + return_value = math_integer_perm_impl(module, n, k); + +exit: + return return_value; +} + +PyDoc_STRVAR(math_integer_comb__doc__, +"comb($module, n, k, /)\n" +"--\n" +"\n" +"Number of ways to choose k items from n items without repetition and without order.\n" +"\n" +"Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates\n" +"to zero when k > n.\n" +"\n" +"Also called the binomial coefficient because it is equivalent\n" +"to the coefficient of k-th term in polynomial expansion of the\n" +"expression (1 + x)**n.\n" +"\n" +"Raises ValueError if either of the arguments are negative."); + +#define MATH_INTEGER_COMB_METHODDEF \ + {"comb", _PyCFunction_CAST(math_integer_comb), METH_FASTCALL, math_integer_comb__doc__}, + +static PyObject * +math_integer_comb_impl(PyObject *module, PyObject *n, PyObject *k); + +static PyObject * +math_integer_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *n; + PyObject *k; + + if (!_PyArg_CheckPositional("comb", nargs, 2, 2)) { + goto exit; + } + n = args[0]; + k = args[1]; + return_value = math_integer_comb_impl(module, n, k); + +exit: + return return_value; +} +/*[clinic end generated code: output=34697570c923a3af input=a9049054013a1b77]*/ diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index 246019f2206..b023299dd9c 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -8,60 +8,6 @@ preserve #endif #include "pycore_modsupport.h" // _PyArg_CheckPositional() -PyDoc_STRVAR(math_gcd__doc__, -"gcd($module, /, *integers)\n" -"--\n" -"\n" -"Greatest Common Divisor."); - -#define MATH_GCD_METHODDEF \ - {"gcd", _PyCFunction_CAST(math_gcd), METH_FASTCALL, math_gcd__doc__}, - -static PyObject * -math_gcd_impl(PyObject *module, PyObject * const *args, - Py_ssize_t args_length); - -static PyObject * -math_gcd(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - PyObject * const *__clinic_args; - Py_ssize_t args_length; - - __clinic_args = args; - args_length = nargs; - return_value = math_gcd_impl(module, __clinic_args, args_length); - - return return_value; -} - -PyDoc_STRVAR(math_lcm__doc__, -"lcm($module, /, *integers)\n" -"--\n" -"\n" -"Least Common Multiple."); - -#define MATH_LCM_METHODDEF \ - {"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm__doc__}, - -static PyObject * -math_lcm_impl(PyObject *module, PyObject * const *args, - Py_ssize_t args_length); - -static PyObject * -math_lcm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - PyObject * const *__clinic_args; - Py_ssize_t args_length; - - __clinic_args = args; - args_length = nargs; - return_value = math_lcm_impl(module, __clinic_args, args_length); - - return return_value; -} - PyDoc_STRVAR(math_ceil__doc__, "ceil($module, x, /)\n" "--\n" @@ -235,24 +181,6 @@ PyDoc_STRVAR(math_fsum__doc__, #define MATH_FSUM_METHODDEF \ {"fsum", (PyCFunction)math_fsum, METH_O, math_fsum__doc__}, -PyDoc_STRVAR(math_isqrt__doc__, -"isqrt($module, n, /)\n" -"--\n" -"\n" -"Return the integer part of the square root of the input."); - -#define MATH_ISQRT_METHODDEF \ - {"isqrt", (PyCFunction)math_isqrt, METH_O, math_isqrt__doc__}, - -PyDoc_STRVAR(math_factorial__doc__, -"factorial($module, n, /)\n" -"--\n" -"\n" -"Find n!."); - -#define MATH_FACTORIAL_METHODDEF \ - {"factorial", (PyCFunction)math_factorial, METH_O, math_factorial__doc__}, - PyDoc_STRVAR(math_trunc__doc__, "trunc($module, x, /)\n" "--\n" @@ -1107,89 +1035,6 @@ exit: return return_value; } -PyDoc_STRVAR(math_perm__doc__, -"perm($module, n, k=None, /)\n" -"--\n" -"\n" -"Number of ways to choose k items from n items without repetition and with order.\n" -"\n" -"Evaluates to n! / (n - k)! when k <= n and evaluates\n" -"to zero when k > n.\n" -"\n" -"If k is not specified or is None, then k defaults to n\n" -"and the function returns n!.\n" -"\n" -"Raises TypeError if either of the arguments are not integers.\n" -"Raises ValueError if either of the arguments are negative."); - -#define MATH_PERM_METHODDEF \ - {"perm", _PyCFunction_CAST(math_perm), METH_FASTCALL, math_perm__doc__}, - -static PyObject * -math_perm_impl(PyObject *module, PyObject *n, PyObject *k); - -static PyObject * -math_perm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - PyObject *n; - PyObject *k = Py_None; - - if (!_PyArg_CheckPositional("perm", nargs, 1, 2)) { - goto exit; - } - n = args[0]; - if (nargs < 2) { - goto skip_optional; - } - k = args[1]; -skip_optional: - return_value = math_perm_impl(module, n, k); - -exit: - return return_value; -} - -PyDoc_STRVAR(math_comb__doc__, -"comb($module, n, k, /)\n" -"--\n" -"\n" -"Number of ways to choose k items from n items without repetition and without order.\n" -"\n" -"Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates\n" -"to zero when k > n.\n" -"\n" -"Also called the binomial coefficient because it is equivalent\n" -"to the coefficient of k-th term in polynomial expansion of the\n" -"expression (1 + x)**n.\n" -"\n" -"Raises TypeError if either of the arguments are not integers.\n" -"Raises ValueError if either of the arguments are negative."); - -#define MATH_COMB_METHODDEF \ - {"comb", _PyCFunction_CAST(math_comb), METH_FASTCALL, math_comb__doc__}, - -static PyObject * -math_comb_impl(PyObject *module, PyObject *n, PyObject *k); - -static PyObject * -math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - PyObject *n; - PyObject *k; - - if (!_PyArg_CheckPositional("comb", nargs, 2, 2)) { - goto exit; - } - n = args[0]; - k = args[1]; - return_value = math_comb_impl(module, n, k); - -exit: - return return_value; -} - PyDoc_STRVAR(math_nextafter__doc__, "nextafter($module, x, y, /, *, steps=None)\n" "--\n" @@ -1318,4 +1163,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=4fb180d4c25ff8fa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=23b2453ba77453e5 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/mmapmodule.c.h b/Modules/clinic/mmapmodule.c.h new file mode 100644 index 00000000000..f7fc172b3af --- /dev/null +++ b/Modules/clinic/mmapmodule.c.h @@ -0,0 +1,799 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(mmap_mmap_close__doc__, +"close($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_CLOSE_METHODDEF \ + {"close", (PyCFunction)mmap_mmap_close, METH_NOARGS, mmap_mmap_close__doc__}, + +static PyObject * +mmap_mmap_close_impl(mmap_object *self); + +static PyObject * +mmap_mmap_close(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_close_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_read_byte__doc__, +"read_byte($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_READ_BYTE_METHODDEF \ + {"read_byte", (PyCFunction)mmap_mmap_read_byte, METH_NOARGS, mmap_mmap_read_byte__doc__}, + +static PyObject * +mmap_mmap_read_byte_impl(mmap_object *self); + +static PyObject * +mmap_mmap_read_byte(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_read_byte_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_readline__doc__, +"readline($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_READLINE_METHODDEF \ + {"readline", (PyCFunction)mmap_mmap_readline, METH_NOARGS, mmap_mmap_readline__doc__}, + +static PyObject * +mmap_mmap_readline_impl(mmap_object *self); + +static PyObject * +mmap_mmap_readline(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_readline_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_read__doc__, +"read($self, n=None, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_READ_METHODDEF \ + {"read", _PyCFunction_CAST(mmap_mmap_read), METH_FASTCALL, mmap_mmap_read__doc__}, + +static PyObject * +mmap_mmap_read_impl(mmap_object *self, Py_ssize_t num_bytes); + +static PyObject * +mmap_mmap_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t num_bytes = PY_SSIZE_T_MAX; + + if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + if (!_Py_convert_optional_to_ssize_t(args[0], &num_bytes)) { + goto exit; + } +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_read_impl((mmap_object *)self, num_bytes); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_find__doc__, +"find($self, view, start=None, end=None, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_FIND_METHODDEF \ + {"find", _PyCFunction_CAST(mmap_mmap_find), METH_FASTCALL, mmap_mmap_find__doc__}, + +static PyObject * +mmap_mmap_find_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end); + +static PyObject * +mmap_mmap_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_buffer view = {NULL, NULL}; + PyObject *start = Py_None; + PyObject *end = Py_None; + + if (!_PyArg_CheckPositional("find", nargs, 1, 3)) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &view, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + start = args[1]; + if (nargs < 3) { + goto skip_optional; + } + end = args[2]; +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_find_impl((mmap_object *)self, &view, start, end); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for view */ + if (view.obj) { + PyBuffer_Release(&view); + } + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_rfind__doc__, +"rfind($self, view, start=None, end=None, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_RFIND_METHODDEF \ + {"rfind", _PyCFunction_CAST(mmap_mmap_rfind), METH_FASTCALL, mmap_mmap_rfind__doc__}, + +static PyObject * +mmap_mmap_rfind_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end); + +static PyObject * +mmap_mmap_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_buffer view = {NULL, NULL}; + PyObject *start = Py_None; + PyObject *end = Py_None; + + if (!_PyArg_CheckPositional("rfind", nargs, 1, 3)) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &view, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + start = args[1]; + if (nargs < 3) { + goto skip_optional; + } + end = args[2]; +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_rfind_impl((mmap_object *)self, &view, start, end); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for view */ + if (view.obj) { + PyBuffer_Release(&view); + } + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_write__doc__, +"write($self, bytes, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_WRITE_METHODDEF \ + {"write", (PyCFunction)mmap_mmap_write, METH_O, mmap_mmap_write__doc__}, + +static PyObject * +mmap_mmap_write_impl(mmap_object *self, Py_buffer *data); + +static PyObject * +mmap_mmap_write(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_write_impl((mmap_object *)self, &data); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for data */ + if (data.obj) { + PyBuffer_Release(&data); + } + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_write_byte__doc__, +"write_byte($self, byte, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_WRITE_BYTE_METHODDEF \ + {"write_byte", (PyCFunction)mmap_mmap_write_byte, METH_O, mmap_mmap_write_byte__doc__}, + +static PyObject * +mmap_mmap_write_byte_impl(mmap_object *self, unsigned char value); + +static PyObject * +mmap_mmap_write_byte(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + unsigned char value; + + { + long ival = PyLong_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is less than minimum"); + goto exit; + } + else if (ival > UCHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is greater than maximum"); + goto exit; + } + else { + value = (unsigned char) ival; + } + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_write_byte_impl((mmap_object *)self, value); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_size__doc__, +"size($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SIZE_METHODDEF \ + {"size", (PyCFunction)mmap_mmap_size, METH_NOARGS, mmap_mmap_size__doc__}, + +static PyObject * +mmap_mmap_size_impl(mmap_object *self); + +static PyObject * +mmap_mmap_size(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_size_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if (defined(MS_WINDOWS) || defined(HAVE_MREMAP)) + +PyDoc_STRVAR(mmap_mmap_resize__doc__, +"resize($self, newsize, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_RESIZE_METHODDEF \ + {"resize", (PyCFunction)mmap_mmap_resize, METH_O, mmap_mmap_resize__doc__}, + +static PyObject * +mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size); + +static PyObject * +mmap_mmap_resize(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t new_size; + + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + new_size = ival; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_resize_impl((mmap_object *)self, new_size); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#endif /* (defined(MS_WINDOWS) || defined(HAVE_MREMAP)) */ + +PyDoc_STRVAR(mmap_mmap_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_TELL_METHODDEF \ + {"tell", (PyCFunction)mmap_mmap_tell, METH_NOARGS, mmap_mmap_tell__doc__}, + +static PyObject * +mmap_mmap_tell_impl(mmap_object *self); + +static PyObject * +mmap_mmap_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_tell_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_flush__doc__, +"flush($self, offset=0, size=-1, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_FLUSH_METHODDEF \ + {"flush", _PyCFunction_CAST(mmap_mmap_flush), METH_FASTCALL, mmap_mmap_flush__doc__}, + +static PyObject * +mmap_mmap_flush_impl(mmap_object *self, Py_ssize_t offset, Py_ssize_t size); + +static PyObject * +mmap_mmap_flush(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t offset = 0; + Py_ssize_t size = -1; + + if (!_PyArg_CheckPositional("flush", nargs, 0, 2)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + offset = ival; + } + if (nargs < 2) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + size = ival; + } +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_flush_impl((mmap_object *)self, offset, size); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_seek__doc__, +"seek($self, pos, whence=0, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SEEK_METHODDEF \ + {"seek", _PyCFunction_CAST(mmap_mmap_seek), METH_FASTCALL, mmap_mmap_seek__doc__}, + +static PyObject * +mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how); + +static PyObject * +mmap_mmap_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t dist; + int how = 0; + + if (!_PyArg_CheckPositional("seek", nargs, 1, 2)) { + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + dist = ival; + } + if (nargs < 2) { + goto skip_optional; + } + how = PyLong_AsInt(args[1]); + if (how == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_seek_impl((mmap_object *)self, dist, how); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)mmap_mmap_seekable, METH_NOARGS, mmap_mmap_seekable__doc__}, + +static PyObject * +mmap_mmap_seekable_impl(mmap_object *self); + +static PyObject * +mmap_mmap_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return mmap_mmap_seekable_impl((mmap_object *)self); +} + +PyDoc_STRVAR(mmap_mmap_move__doc__, +"move($self, dest, src, count, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_MOVE_METHODDEF \ + {"move", _PyCFunction_CAST(mmap_mmap_move), METH_FASTCALL, mmap_mmap_move__doc__}, + +static PyObject * +mmap_mmap_move_impl(mmap_object *self, Py_ssize_t dest, Py_ssize_t src, + Py_ssize_t cnt); + +static PyObject * +mmap_mmap_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t dest; + Py_ssize_t src; + Py_ssize_t cnt; + + if (!_PyArg_CheckPositional("move", nargs, 3, 3)) { + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + dest = ival; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + src = ival; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[2]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + cnt = ival; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_move_impl((mmap_object *)self, dest, src, cnt); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap___enter____doc__, +"__enter__($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP___ENTER___METHODDEF \ + {"__enter__", (PyCFunction)mmap_mmap___enter__, METH_NOARGS, mmap_mmap___enter____doc__}, + +static PyObject * +mmap_mmap___enter___impl(mmap_object *self); + +static PyObject * +mmap_mmap___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap___enter___impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap___exit____doc__, +"__exit__($self, exc_type, exc_value, traceback, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(mmap_mmap___exit__), METH_FASTCALL, mmap_mmap___exit____doc__}, + +static PyObject * +mmap_mmap___exit___impl(mmap_object *self, PyObject *exc_type, + PyObject *exc_value, PyObject *traceback); + +static PyObject * +mmap_mmap___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc_type; + PyObject *exc_value; + PyObject *traceback; + + if (!_PyArg_CheckPositional("__exit__", nargs, 3, 3)) { + goto exit; + } + exc_type = args[0]; + exc_value = args[1]; + traceback = args[2]; + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap___exit___impl((mmap_object *)self, exc_type, exc_value, traceback); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(mmap_mmap___sizeof____doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP___SIZEOF___METHODDEF \ + {"__sizeof__", (PyCFunction)mmap_mmap___sizeof__, METH_NOARGS, mmap_mmap___sizeof____doc__}, + +static PyObject * +mmap_mmap___sizeof___impl(mmap_object *self); + +static PyObject * +mmap_mmap___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap___sizeof___impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if (defined(MS_WINDOWS) && defined(Py_DEBUG)) + +PyDoc_STRVAR(mmap_mmap__protect__doc__, +"_protect($self, flNewProtect, start, length, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP__PROTECT_METHODDEF \ + {"_protect", _PyCFunction_CAST(mmap_mmap__protect), METH_FASTCALL, mmap_mmap__protect__doc__}, + +static PyObject * +mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, + Py_ssize_t start, Py_ssize_t length); + +static PyObject * +mmap_mmap__protect(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + unsigned int flNewProtect; + Py_ssize_t start; + Py_ssize_t length; + + if (!_PyArg_CheckPositional("_protect", nargs, 3, 3)) { + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[0], &flNewProtect, sizeof(unsigned int), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(unsigned int)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + start = ival; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[2]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + length = ival; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap__protect_impl((mmap_object *)self, flNewProtect, start, length); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#endif /* (defined(MS_WINDOWS) && defined(Py_DEBUG)) */ + +#if defined(HAVE_MADVISE) + +PyDoc_STRVAR(mmap_mmap_madvise__doc__, +"madvise($self, option, start=0, length=None, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_MADVISE_METHODDEF \ + {"madvise", _PyCFunction_CAST(mmap_mmap_madvise), METH_FASTCALL, mmap_mmap_madvise__doc__}, + +static PyObject * +mmap_mmap_madvise_impl(mmap_object *self, int option, Py_ssize_t start, + PyObject *length_obj); + +static PyObject * +mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int option; + Py_ssize_t start = 0; + PyObject *length_obj = Py_None; + + if (!_PyArg_CheckPositional("madvise", nargs, 1, 3)) { + goto exit; + } + option = PyLong_AsInt(args[0]); + if (option == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + start = ival; + } + if (nargs < 3) { + goto skip_optional; + } + length_obj = args[2]; +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_madvise_impl((mmap_object *)self, option, start, length_obj); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#endif /* defined(HAVE_MADVISE) */ + +#ifndef MMAP_MMAP_RESIZE_METHODDEF + #define MMAP_MMAP_RESIZE_METHODDEF +#endif /* !defined(MMAP_MMAP_RESIZE_METHODDEF) */ + +#ifndef MMAP_MMAP___SIZEOF___METHODDEF + #define MMAP_MMAP___SIZEOF___METHODDEF +#endif /* !defined(MMAP_MMAP___SIZEOF___METHODDEF) */ + +#ifndef MMAP_MMAP__PROTECT_METHODDEF + #define MMAP_MMAP__PROTECT_METHODDEF +#endif /* !defined(MMAP_MMAP__PROTECT_METHODDEF) */ + +#ifndef MMAP_MMAP_MADVISE_METHODDEF + #define MMAP_MMAP_MADVISE_METHODDEF +#endif /* !defined(MMAP_MMAP_MADVISE_METHODDEF) */ +/*[clinic end generated code: output=381f6cf4986ac867 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index df4f802ff0b..d880fc52bb3 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -186,6 +186,140 @@ exit: return return_value; } +#if defined(HAVE_STATX) + +PyDoc_STRVAR(os_statx__doc__, +"statx($module, /, path, mask, *, flags=0, dir_fd=None,\n" +" follow_symlinks=True)\n" +"--\n" +"\n" +"Perform a statx system call on the given path.\n" +"\n" +" path\n" +" Path to be examined; can be string, bytes, a path-like object or\n" +" open-file-descriptor int.\n" +" mask\n" +" A bitmask of STATX_* constants defining the requested information.\n" +" flags\n" +" A bitmask of AT_NO_AUTOMOUNT and/or AT_STATX_* flags.\n" +" dir_fd\n" +" If not None, it should be a file descriptor open to a directory,\n" +" and path should be a relative string; path will then be relative to\n" +" that directory.\n" +" follow_symlinks\n" +" If False, and the last element of the path is a symbolic link,\n" +" statx will examine the symbolic link itself instead of the file\n" +" the link points to.\n" +"\n" +"It\'s an error to use dir_fd or follow_symlinks when specifying path as\n" +" an open file descriptor."); + +#define OS_STATX_METHODDEF \ + {"statx", _PyCFunction_CAST(os_statx), METH_FASTCALL|METH_KEYWORDS, os_statx__doc__}, + +static PyObject * +os_statx_impl(PyObject *module, path_t *path, unsigned int mask, int flags, + int dir_fd, int follow_symlinks); + +static PyObject * +os_statx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 5 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(path), &_Py_ID(mask), &_Py_ID(flags), &_Py_ID(dir_fd), &_Py_ID(follow_symlinks), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", "mask", "flags", "dir_fd", "follow_symlinks", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "statx", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[5]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + path_t path = PATH_T_INITIALIZE_P("statx", "path", 0, 0, 0, 1); + unsigned int mask; + int flags = 0; + int dir_fd = DEFAULT_DIR_FD; + int follow_symlinks = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &mask, sizeof(unsigned int), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(unsigned int)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[2]) { + flags = PyLong_AsInt(args[2]); + if (flags == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (args[3]) { + if (!dir_fd_converter(args[3], &dir_fd)) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + follow_symlinks = PyObject_IsTrue(args[4]); + if (follow_symlinks < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = os_statx_impl(module, &path, mask, flags, dir_fd, follow_symlinks); + +exit: + /* Cleanup for path */ + path_cleanup(&path); + + return return_value; +} + +#endif /* defined(HAVE_STATX) */ + PyDoc_STRVAR(os_access__doc__, "access($module, /, path, mode, *, dir_fd=None, effective_ids=False,\n" " follow_symlinks=True)\n" @@ -5035,7 +5169,8 @@ PyDoc_STRVAR(os_forkpty__doc__, "Returns a tuple of (pid, master_fd).\n" "Like fork(), return pid of 0 to the child process,\n" "and pid of child to the parent process.\n" -"To both, return fd of newly opened pseudo-terminal."); +"To both, return fd of newly opened pseudo-terminal.\n" +"The master_fd is non-inheritable."); #define OS_FORKPTY_METHODDEF \ {"forkpty", (PyCFunction)os_forkpty, METH_NOARGS, os_forkpty__doc__}, @@ -7814,6 +7949,7 @@ PyDoc_STRVAR(os_preadv__doc__, "\n" "- RWF_HIPRI\n" "- RWF_NOWAIT\n" +"- RWF_DONTCACHE\n" "\n" "Using non-zero flags requires Linux 4.6 or newer."); @@ -8100,6 +8236,11 @@ os_sendfile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject goto exit; } count = ival; + if (count < 0) { + PyErr_SetString(PyExc_ValueError, + "count cannot be negative"); + goto exit; + } } if (!noptargs) { goto skip_optional_pos; @@ -8206,6 +8347,11 @@ os_sendfile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject goto exit; } count = ival; + if (count < 0) { + PyErr_SetString(PyExc_ValueError, + "count cannot be negative"); + goto exit; + } } return_value = os_sendfile_impl(module, out_fd, in_fd, offobj, count); @@ -8545,6 +8691,7 @@ PyDoc_STRVAR(os_pwritev__doc__, "- RWF_DSYNC\n" "- RWF_SYNC\n" "- RWF_APPEND\n" +"- RWF_DONTCACHE\n" "\n" "Using non-zero flags requires Linux 4.7 or newer."); @@ -8689,6 +8836,11 @@ os_copy_file_range(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py goto exit; } count = ival; + if (count < 0) { + PyErr_SetString(PyExc_ValueError, + "count cannot be negative"); + goto exit; + } } if (!noptargs) { goto skip_optional_pos; @@ -8807,6 +8959,11 @@ os_splice(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *k goto exit; } count = ival; + if (count < 0) { + PyErr_SetString(PyExc_ValueError, + "count cannot be negative"); + goto exit; + } } if (!noptargs) { goto skip_optional_pos; @@ -9516,6 +9673,27 @@ exit: #endif /* !defined(MS_WINDOWS) */ +#if defined(HAVE_CLEARENV) + +PyDoc_STRVAR(os__clearenv__doc__, +"_clearenv($module, /)\n" +"--\n" +"\n"); + +#define OS__CLEARENV_METHODDEF \ + {"_clearenv", (PyCFunction)os__clearenv, METH_NOARGS, os__clearenv__doc__}, + +static PyObject * +os__clearenv_impl(PyObject *module); + +static PyObject * +os__clearenv(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return os__clearenv_impl(module); +} + +#endif /* defined(HAVE_CLEARENV) */ + PyDoc_STRVAR(os_strerror__doc__, "strerror($module, code, /)\n" "--\n" @@ -11237,6 +11415,11 @@ os_urandom(PyObject *module, PyObject *arg) goto exit; } size = ival; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, + "size cannot be negative"); + goto exit; + } } return_value = os_urandom_impl(module, size); @@ -12598,7 +12781,7 @@ PyDoc_STRVAR(os__inputhook__doc__, "_inputhook($module, /)\n" "--\n" "\n" -"Calls PyOS_CallInputHook droppong the GIL first"); +"Calls PyOS_InputHook dropping the GIL first"); #define OS__INPUTHOOK_METHODDEF \ {"_inputhook", (PyCFunction)os__inputhook, METH_NOARGS, os__inputhook__doc__}, @@ -12616,7 +12799,7 @@ PyDoc_STRVAR(os__is_inputhook_installed__doc__, "_is_inputhook_installed($module, /)\n" "--\n" "\n" -"Checks if PyOS_CallInputHook is set"); +"Checks if PyOS_InputHook is set"); #define OS__IS_INPUTHOOK_INSTALLED_METHODDEF \ {"_is_inputhook_installed", (PyCFunction)os__is_inputhook_installed, METH_NOARGS, os__is_inputhook_installed__doc__}, @@ -12744,6 +12927,10 @@ exit: #endif /* defined(__EMSCRIPTEN__) */ +#ifndef OS_STATX_METHODDEF + #define OS_STATX_METHODDEF +#endif /* !defined(OS_STATX_METHODDEF) */ + #ifndef OS_TTYNAME_METHODDEF #define OS_TTYNAME_METHODDEF #endif /* !defined(OS_TTYNAME_METHODDEF) */ @@ -13264,6 +13451,10 @@ exit: #define OS_UNSETENV_METHODDEF #endif /* !defined(OS_UNSETENV_METHODDEF) */ +#ifndef OS__CLEARENV_METHODDEF + #define OS__CLEARENV_METHODDEF +#endif /* !defined(OS__CLEARENV_METHODDEF) */ + #ifndef OS_WCOREDUMP_METHODDEF #define OS_WCOREDUMP_METHODDEF #endif /* !defined(OS_WCOREDUMP_METHODDEF) */ @@ -13419,4 +13610,4 @@ exit: #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=23de5d098e2dd73f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=82f60940338c70e4 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/pyexpat.c.h b/Modules/clinic/pyexpat.c.h index 13210e3be0f..ff2e28269dc 100644 --- a/Modules/clinic/pyexpat.c.h +++ b/Modules/clinic/pyexpat.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_SINGLETON() #endif +#include "pycore_long.h" // _PyLong_UnsignedLongLong_Converter() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(pyexpat_xmlparser_SetReparseDeferralEnabled__doc__, @@ -408,6 +409,267 @@ exit: #endif /* (XML_COMBINED_VERSION >= 19505) */ +#if (XML_COMBINED_VERSION >= 20400) + +PyDoc_STRVAR(pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold__doc__, +"SetBillionLaughsAttackProtectionActivationThreshold($self, threshold, /)\n" +"--\n" +"\n" +"Sets the number of output bytes needed to activate protection against billion laughs attacks.\n" +"\n" +"The number of output bytes includes amplification from entity expansion\n" +"and reading DTD files.\n" +"\n" +"Parser objects usually have a protection activation threshold of 8 MiB,\n" +"but the actual default value depends on the underlying Expat library.\n" +"\n" +"Activation thresholds below 4 MiB are known to break support for DITA 1.3\n" +"payload and are hence not recommended."); + +#define PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONACTIVATIONTHRESHOLD_METHODDEF \ + {"SetBillionLaughsAttackProtectionActivationThreshold", _PyCFunction_CAST(pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold__doc__}, + +static PyObject * +pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold_impl(xmlparseobject *self, + PyTypeObject *cls, + unsigned long long threshold); + +static PyObject * +pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "SetBillionLaughsAttackProtectionActivationThreshold", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + unsigned long long threshold; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!_PyLong_UnsignedLongLong_Converter(args[0], &threshold)) { + goto exit; + } + return_value = pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold_impl((xmlparseobject *)self, cls, threshold); + +exit: + return return_value; +} + +#endif /* (XML_COMBINED_VERSION >= 20400) */ + +#if (XML_COMBINED_VERSION >= 20400) + +PyDoc_STRVAR(pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification__doc__, +"SetBillionLaughsAttackProtectionMaximumAmplification($self, max_factor,\n" +" /)\n" +"--\n" +"\n" +"Sets the maximum tolerated amplification factor for protection against billion laughs attacks.\n" +"\n" +"The amplification factor is calculated as \"(direct + indirect) / direct\"\n" +"while parsing, where \"direct\" is the number of bytes read from the primary\n" +"document in parsing and \"indirect\" is the number of bytes added by expanding\n" +"entities and reading external DTD files, combined.\n" +"\n" +"The \'max_factor\' value must be a non-NaN floating point value greater than\n" +"or equal to 1.0. Amplification factors greater than 30,000 can be observed\n" +"in the middle of parsing even with benign files in practice. In particular,\n" +"the activation threshold should be carefully chosen to avoid false positives.\n" +"\n" +"Parser objects usually have a maximum amplification factor of 100,\n" +"but the actual default value depends on the underlying Expat library."); + +#define PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONMAXIMUMAMPLIFICATION_METHODDEF \ + {"SetBillionLaughsAttackProtectionMaximumAmplification", _PyCFunction_CAST(pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification__doc__}, + +static PyObject * +pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification_impl(xmlparseobject *self, + PyTypeObject *cls, + float max_factor); + +static PyObject * +pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "SetBillionLaughsAttackProtectionMaximumAmplification", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + float max_factor; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (PyFloat_CheckExact(args[0])) { + max_factor = (float) (PyFloat_AS_DOUBLE(args[0])); + } + else + { + max_factor = (float) PyFloat_AsDouble(args[0]); + if (max_factor == -1.0 && PyErr_Occurred()) { + goto exit; + } + } + return_value = pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification_impl((xmlparseobject *)self, cls, max_factor); + +exit: + return return_value; +} + +#endif /* (XML_COMBINED_VERSION >= 20400) */ + +#if (XML_COMBINED_VERSION >= 20702) + +PyDoc_STRVAR(pyexpat_xmlparser_SetAllocTrackerActivationThreshold__doc__, +"SetAllocTrackerActivationThreshold($self, threshold, /)\n" +"--\n" +"\n" +"Sets the number of allocated bytes of dynamic memory needed to activate protection against disproportionate use of RAM.\n" +"\n" +"Parser objects usually have an allocation activation threshold of 64 MiB,\n" +"but the actual default value depends on the underlying Expat library."); + +#define PYEXPAT_XMLPARSER_SETALLOCTRACKERACTIVATIONTHRESHOLD_METHODDEF \ + {"SetAllocTrackerActivationThreshold", _PyCFunction_CAST(pyexpat_xmlparser_SetAllocTrackerActivationThreshold), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetAllocTrackerActivationThreshold__doc__}, + +static PyObject * +pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl(xmlparseobject *self, + PyTypeObject *cls, + unsigned long long threshold); + +static PyObject * +pyexpat_xmlparser_SetAllocTrackerActivationThreshold(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "SetAllocTrackerActivationThreshold", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + unsigned long long threshold; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!_PyLong_UnsignedLongLong_Converter(args[0], &threshold)) { + goto exit; + } + return_value = pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl((xmlparseobject *)self, cls, threshold); + +exit: + return return_value; +} + +#endif /* (XML_COMBINED_VERSION >= 20702) */ + +#if (XML_COMBINED_VERSION >= 20702) + +PyDoc_STRVAR(pyexpat_xmlparser_SetAllocTrackerMaximumAmplification__doc__, +"SetAllocTrackerMaximumAmplification($self, max_factor, /)\n" +"--\n" +"\n" +"Sets the maximum amplification factor between direct input and bytes of dynamic memory allocated.\n" +"\n" +"The amplification factor is calculated as \"allocated / direct\" while parsing,\n" +"where \"direct\" is the number of bytes read from the primary document in parsing\n" +"and \"allocated\" is the number of bytes of dynamic memory allocated in the parser\n" +"hierarchy.\n" +"\n" +"The \'max_factor\' value must be a non-NaN floating point value greater than\n" +"or equal to 1.0. Amplification factors greater than 100.0 can be observed\n" +"near the start of parsing even with benign files in practice. In particular,\n" +"the activation threshold should be carefully chosen to avoid false positives.\n" +"\n" +"Parser objects usually have a maximum amplification factor of 100,\n" +"but the actual default value depends on the underlying Expat library."); + +#define PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF \ + {"SetAllocTrackerMaximumAmplification", _PyCFunction_CAST(pyexpat_xmlparser_SetAllocTrackerMaximumAmplification), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pyexpat_xmlparser_SetAllocTrackerMaximumAmplification__doc__}, + +static PyObject * +pyexpat_xmlparser_SetAllocTrackerMaximumAmplification_impl(xmlparseobject *self, + PyTypeObject *cls, + float max_factor); + +static PyObject * +pyexpat_xmlparser_SetAllocTrackerMaximumAmplification(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "SetAllocTrackerMaximumAmplification", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + float max_factor; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (PyFloat_CheckExact(args[0])) { + max_factor = (float) (PyFloat_AS_DOUBLE(args[0])); + } + else + { + max_factor = (float) PyFloat_AsDouble(args[0]); + if (max_factor == -1.0 && PyErr_Occurred()) { + goto exit; + } + } + return_value = pyexpat_xmlparser_SetAllocTrackerMaximumAmplification_impl((xmlparseobject *)self, cls, max_factor); + +exit: + return return_value; +} + +#endif /* (XML_COMBINED_VERSION >= 20702) */ + PyDoc_STRVAR(pyexpat_ParserCreate__doc__, "ParserCreate($module, /, encoding=None, namespace_separator=None,\n" " intern=<unrepresentable>)\n" @@ -552,4 +814,20 @@ exit: #ifndef PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF #define PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF #endif /* !defined(PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF) */ -/*[clinic end generated code: output=4dbdc959c67dc2d5 input=a9049054013a1b77]*/ + +#ifndef PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONACTIVATIONTHRESHOLD_METHODDEF + #define PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONACTIVATIONTHRESHOLD_METHODDEF +#endif /* !defined(PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONACTIVATIONTHRESHOLD_METHODDEF) */ + +#ifndef PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONMAXIMUMAMPLIFICATION_METHODDEF + #define PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONMAXIMUMAMPLIFICATION_METHODDEF +#endif /* !defined(PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONMAXIMUMAMPLIFICATION_METHODDEF) */ + +#ifndef PYEXPAT_XMLPARSER_SETALLOCTRACKERACTIVATIONTHRESHOLD_METHODDEF + #define PYEXPAT_XMLPARSER_SETALLOCTRACKERACTIVATIONTHRESHOLD_METHODDEF +#endif /* !defined(PYEXPAT_XMLPARSER_SETALLOCTRACKERACTIVATIONTHRESHOLD_METHODDEF) */ + +#ifndef PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF + #define PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF +#endif /* !defined(PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF) */ +/*[clinic end generated code: output=81101a16a409daf6 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/readline.c.h b/Modules/clinic/readline.c.h index 696475f7d00..dc9381e4b97 100644 --- a/Modules/clinic/readline.c.h +++ b/Modules/clinic/readline.c.h @@ -349,6 +349,28 @@ exit: #endif /* defined(HAVE_RL_PRE_INPUT_HOOK) */ +#if defined(HAVE_RL_PRE_INPUT_HOOK) + +PyDoc_STRVAR(readline_get_pre_input_hook__doc__, +"get_pre_input_hook($module, /)\n" +"--\n" +"\n" +"Get the current pre-input hook function."); + +#define READLINE_GET_PRE_INPUT_HOOK_METHODDEF \ + {"get_pre_input_hook", (PyCFunction)readline_get_pre_input_hook, METH_NOARGS, readline_get_pre_input_hook__doc__}, + +static PyObject * +readline_get_pre_input_hook_impl(PyObject *module); + +static PyObject * +readline_get_pre_input_hook(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return readline_get_pre_input_hook_impl(module); +} + +#endif /* defined(HAVE_RL_PRE_INPUT_HOOK) */ + PyDoc_STRVAR(readline_get_completion_type__doc__, "get_completion_type($module, /)\n" "--\n" @@ -794,7 +816,11 @@ readline_redisplay(PyObject *module, PyObject *Py_UNUSED(ignored)) #define READLINE_SET_PRE_INPUT_HOOK_METHODDEF #endif /* !defined(READLINE_SET_PRE_INPUT_HOOK_METHODDEF) */ +#ifndef READLINE_GET_PRE_INPUT_HOOK_METHODDEF + #define READLINE_GET_PRE_INPUT_HOOK_METHODDEF +#endif /* !defined(READLINE_GET_PRE_INPUT_HOOK_METHODDEF) */ + #ifndef READLINE_CLEAR_HISTORY_METHODDEF #define READLINE_CLEAR_HISTORY_METHODDEF #endif /* !defined(READLINE_CLEAR_HISTORY_METHODDEF) */ -/*[clinic end generated code: output=88d9812b6caa2102 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4bd95070973cd0e2 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/selectmodule.c.h b/Modules/clinic/selectmodule.c.h index c0a5f678ad0..26ddc6ffba7 100644 --- a/Modules/clinic/selectmodule.c.h +++ b/Modules/clinic/selectmodule.c.h @@ -26,7 +26,7 @@ PyDoc_STRVAR(select_select__doc__, "gotten from a fileno() method call on one of those.\n" "\n" "The optional 4th argument specifies a timeout in seconds; it may be\n" -"a floating-point number to specify fractions of seconds. If it is absent\n" +"a non-integer to specify fractions of seconds. If it is absent\n" "or None, the call will never time out.\n" "\n" "The return value is a tuple of three lists corresponding to the first three\n" @@ -973,7 +973,7 @@ PyDoc_STRVAR(select_epoll_poll__doc__, "Wait for events on the epoll file descriptor.\n" "\n" " timeout\n" -" the maximum time to wait in seconds (as float);\n" +" the maximum time to wait in seconds (with fractions);\n" " a timeout of None or -1 makes poll wait indefinitely\n" " maxevents\n" " the maximum number of events returned; -1 means no limit\n" @@ -1262,7 +1262,7 @@ PyDoc_STRVAR(select_kqueue_control__doc__, " The maximum number of events that the kernel will return.\n" " timeout\n" " The maximum time to wait in seconds, or else None to wait forever.\n" -" This accepts floats for smaller timeouts, too."); +" This accepts non-integers for smaller timeouts, too."); #define SELECT_KQUEUE_CONTROL_METHODDEF \ {"control", _PyCFunction_CAST(select_kqueue_control), METH_FASTCALL, select_kqueue_control__doc__}, @@ -1399,4 +1399,4 @@ exit: #ifndef SELECT_KQUEUE_CONTROL_METHODDEF #define SELECT_KQUEUE_CONTROL_METHODDEF #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */ -/*[clinic end generated code: output=2a66dd831f22c696 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ae54d65938513132 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h index 1f631ff406e..7fdc707626c 100644 --- a/Modules/clinic/sha3module.c.h +++ b/Modules/clinic/sha3module.c.h @@ -235,6 +235,11 @@ _sha3_shake_128_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, goto exit; } length = ival; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length cannot be negative"); + goto exit; + } } return_value = _sha3_shake_128_digest_impl((SHA3object *)self, length); @@ -304,10 +309,15 @@ _sha3_shake_128_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t narg goto exit; } length = ival; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length cannot be negative"); + goto exit; + } } return_value = _sha3_shake_128_hexdigest_impl((SHA3object *)self, length); exit: return return_value; } -/*[clinic end generated code: output=48be77f8a31e8a3e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=78284adde71d590c input=a9049054013a1b77]*/ diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h index b0cd9e2e561..9fd24d15bf2 100644 --- a/Modules/clinic/signalmodule.c.h +++ b/Modules/clinic/signalmodule.c.h @@ -600,7 +600,7 @@ PyDoc_STRVAR(signal_sigtimedwait__doc__, "\n" "Like sigwaitinfo(), but with a timeout.\n" "\n" -"The timeout is specified in seconds, with floating-point numbers allowed."); +"The timeout is specified in seconds, rounded up to nanoseconds."); #define SIGNAL_SIGTIMEDWAIT_METHODDEF \ {"sigtimedwait", _PyCFunction_CAST(signal_sigtimedwait), METH_FASTCALL, signal_sigtimedwait__doc__}, @@ -794,4 +794,4 @@ exit: #ifndef SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF #define SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF #endif /* !defined(SIGNAL_PIDFD_SEND_SIGNAL_METHODDEF) */ -/*[clinic end generated code: output=37ae8ebeae4178fa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=42e20d118435d7fa input=a9049054013a1b77]*/ diff --git a/Modules/clinic/socketmodule.c.h b/Modules/clinic/socketmodule.c.h index 0cedab597db..e0cc1c50dcb 100644 --- a/Modules/clinic/socketmodule.c.h +++ b/Modules/clinic/socketmodule.c.h @@ -479,7 +479,7 @@ static PyObject * _socket_if_nametoindex(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; - PyObject *oname; + PyObject *oname = NULL; if (!PyUnicode_FSConverter(arg, &oname)) { goto exit; @@ -487,6 +487,9 @@ _socket_if_nametoindex(PyObject *module, PyObject *arg) return_value = _socket_if_nametoindex_impl(module, oname); exit: + /* Cleanup for oname */ + Py_XDECREF(oname); + return return_value; } @@ -538,4 +541,4 @@ exit: #ifndef _SOCKET_IF_INDEXTONAME_METHODDEF #define _SOCKET_IF_INDEXTONAME_METHODDEF #endif /* !defined(_SOCKET_IF_INDEXTONAME_METHODDEF) */ -/*[clinic end generated code: output=0376c46b76ae2bce input=a9049054013a1b77]*/ +/*[clinic end generated code: output=36051ebf6ad1e6f8 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/symtablemodule.c.h b/Modules/clinic/symtablemodule.c.h index 2ecd3afc00d..65352593f94 100644 --- a/Modules/clinic/symtablemodule.c.h +++ b/Modules/clinic/symtablemodule.c.h @@ -2,30 +2,67 @@ preserve [clinic start generated code]*/ -#include "pycore_modsupport.h" // _PyArg_CheckPositional() +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(_symtable_symtable__doc__, -"symtable($module, source, filename, startstr, /)\n" +"symtable($module, source, filename, startstr, /, *, module=None)\n" "--\n" "\n" "Return symbol and scope dictionaries used internally by compiler."); #define _SYMTABLE_SYMTABLE_METHODDEF \ - {"symtable", _PyCFunction_CAST(_symtable_symtable), METH_FASTCALL, _symtable_symtable__doc__}, + {"symtable", _PyCFunction_CAST(_symtable_symtable), METH_FASTCALL|METH_KEYWORDS, _symtable_symtable__doc__}, static PyObject * _symtable_symtable_impl(PyObject *module, PyObject *source, - PyObject *filename, const char *startstr); + PyObject *filename, const char *startstr, + PyObject *modname); static PyObject * -_symtable_symtable(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +_symtable_symtable(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; - PyObject *source; - PyObject *filename; - const char *startstr; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - if (!_PyArg_CheckPositional("symtable", nargs, 3, 3)) { + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(module), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "", "", "module", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "symtable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; + PyObject *source; + PyObject *filename = NULL; + const char *startstr; + PyObject *modname = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } source = args[0]; @@ -45,9 +82,17 @@ _symtable_symtable(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - return_value = _symtable_symtable_impl(module, source, filename, startstr); + if (!noptargs) { + goto skip_optional_kwonly; + } + modname = args[3]; +skip_optional_kwonly: + return_value = _symtable_symtable_impl(module, source, filename, startstr, modname); exit: + /* Cleanup for filename */ + Py_XDECREF(filename); + return return_value; } -/*[clinic end generated code: output=931964a76a72f850 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0137be60c487c841 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index 345440eeee8..5fcba083c2f 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -518,6 +518,78 @@ exit: return return_value; } +PyDoc_STRVAR(unicodedata_UCD_isxidstart__doc__, +"isxidstart($self, chr, /)\n" +"--\n" +"\n" +"Return True if the character has the XID_Start property, else False."); + +#define UNICODEDATA_UCD_ISXIDSTART_METHODDEF \ + {"isxidstart", (PyCFunction)unicodedata_UCD_isxidstart, METH_O, unicodedata_UCD_isxidstart__doc__}, + +static PyObject * +unicodedata_UCD_isxidstart_impl(PyObject *self, int chr); + +static PyObject * +unicodedata_UCD_isxidstart(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + int chr; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("isxidstart", "argument", "a unicode character", arg); + goto exit; + } + if (PyUnicode_GET_LENGTH(arg) != 1) { + PyErr_Format(PyExc_TypeError, + "isxidstart(): argument must be a unicode character, " + "not a string of length %zd", + PyUnicode_GET_LENGTH(arg)); + goto exit; + } + chr = PyUnicode_READ_CHAR(arg, 0); + return_value = unicodedata_UCD_isxidstart_impl(self, chr); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicodedata_UCD_isxidcontinue__doc__, +"isxidcontinue($self, chr, /)\n" +"--\n" +"\n" +"Return True if the character has the XID_Continue property, else False."); + +#define UNICODEDATA_UCD_ISXIDCONTINUE_METHODDEF \ + {"isxidcontinue", (PyCFunction)unicodedata_UCD_isxidcontinue, METH_O, unicodedata_UCD_isxidcontinue__doc__}, + +static PyObject * +unicodedata_UCD_isxidcontinue_impl(PyObject *self, int chr); + +static PyObject * +unicodedata_UCD_isxidcontinue(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + int chr; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("isxidcontinue", "argument", "a unicode character", arg); + goto exit; + } + if (PyUnicode_GET_LENGTH(arg) != 1) { + PyErr_Format(PyExc_TypeError, + "isxidcontinue(): argument must be a unicode character, " + "not a string of length %zd", + PyUnicode_GET_LENGTH(arg)); + goto exit; + } + chr = PyUnicode_READ_CHAR(arg, 0); + return_value = unicodedata_UCD_isxidcontinue_impl(self, chr); + +exit: + return return_value; +} + PyDoc_STRVAR(unicodedata_UCD_lookup__doc__, "lookup($self, name, /)\n" "--\n" @@ -549,4 +621,4 @@ unicodedata_UCD_lookup(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=8a59d430cee41058 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c5e56c8f6bb80f93 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h index 658cb1c2ac3..6fba75339b3 100644 --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -189,6 +189,11 @@ zlib_decompress(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj goto exit; } bufsize = ival; + if (bufsize < 0) { + PyErr_SetString(PyExc_ValueError, + "bufsize cannot be negative"); + goto exit; + } } skip_optional_pos: return_value = zlib_decompress_impl(module, &data, wbits, bufsize); @@ -567,6 +572,11 @@ zlib_Decompress_decompress(PyObject *self, PyTypeObject *cls, PyObject *const *a goto exit; } max_length = ival; + if (max_length < 0) { + PyErr_SetString(PyExc_ValueError, + "max_length cannot be negative"); + goto exit; + } } skip_optional_pos: return_value = zlib_Decompress_decompress_impl((compobject *)self, cls, &data, max_length); @@ -1392,4 +1402,4 @@ exit: #ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ -/*[clinic end generated code: output=59184b81fea41d3d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fa5fc356f3090cce input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index a4ea5557a6a..65fbcf5cdaa 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -150,7 +150,7 @@ special_type(double d) #define P14 0.25*Py_MATH_PI #define P12 0.5*Py_MATH_PI #define P34 0.75*Py_MATH_PI -#define INF Py_INFINITY +#define INF INFINITY #define N Py_NAN #define U -9.5426319407711027e33 /* unlikely value, used as placeholder */ @@ -163,8 +163,15 @@ special_type(double d) raised. */ -static Py_complex acos_special_values[7][7]; - +static Py_complex acos_special_values[7][7] = { + { {P34,INF}, {P,INF}, {P,INF}, {P,-INF}, {P,-INF}, {P34,-INF}, {N,INF} }, + { {P12,INF}, {U,U}, {U,U}, {U,U}, {U,U}, {P12,-INF}, {N,N} }, + { {P12,INF}, {U,U}, {P12,0.}, {P12,-0.}, {U,U}, {P12,-INF}, {P12,N} }, + { {P12,INF}, {U,U}, {P12,0.}, {P12,-0.}, {U,U}, {P12,-INF}, {P12,N} }, + { {P12,INF}, {U,U}, {U,U}, {U,U}, {U,U}, {P12,-INF}, {N,N} }, + { {P14,INF}, {0.,INF}, {0.,INF}, {0.,-INF}, {0.,-INF}, {P14,-INF}, {N,INF} }, + { {N,INF}, {N,N}, {N,N}, {N,N}, {N,N}, {N,-INF}, {N,N} } +}; /*[clinic input] cmath.acos -> Py_complex_protected @@ -202,7 +209,15 @@ cmath_acos_impl(PyObject *module, Py_complex z) } -static Py_complex acosh_special_values[7][7]; +static Py_complex acosh_special_values[7][7] = { + { {INF,-P34}, {INF,-P}, {INF,-P}, {INF,P}, {INF,P}, {INF,P34}, {INF,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {0.,-P12}, {0.,P12}, {U,U}, {INF,P12}, {N,P12} }, + { {INF,-P12}, {U,U}, {0.,-P12}, {0.,P12}, {U,U}, {INF,P12}, {N,P12} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P14}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,P14}, {INF,N} }, + { {INF,N}, {N,N}, {N,N}, {N,N}, {N,N}, {INF,N}, {N,N} } +}; /*[clinic input] cmath.acosh = cmath.acos @@ -257,7 +272,15 @@ cmath_asin_impl(PyObject *module, Py_complex z) } -static Py_complex asinh_special_values[7][7]; +static Py_complex asinh_special_values[7][7] = { + { {-INF,-P14}, {-INF,-0.}, {-INF,-0.}, {-INF,0.}, {-INF,0.}, {-INF,P14}, {-INF,N} }, + { {-INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {-INF,P12}, {N,N} }, + { {-INF,-P12}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P14}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,P14}, {INF,N} }, + { {INF,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {INF,N}, {N,N} } +}; /*[clinic input] cmath.asinh = cmath.acos @@ -318,7 +341,15 @@ cmath_atan_impl(PyObject *module, Py_complex z) } -static Py_complex atanh_special_values[7][7]; +static Py_complex atanh_special_values[7][7] = { + { {-0.,-P12}, {-0.,-P12}, {-0.,-P12}, {-0.,P12}, {-0.,P12}, {-0.,P12}, {-0.,N} }, + { {-0.,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {-0.,P12}, {N,N} }, + { {-0.,-P12}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-0.,P12}, {-0.,N} }, + { {0.,-P12}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,P12}, {0.,N} }, + { {0.,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {0.,P12}, {N,N} }, + { {0.,-P12}, {0.,-P12}, {0.,-P12}, {0.,P12}, {0.,P12}, {0.,P12}, {0.,N} }, + { {0.,-P12}, {N,N}, {N,N}, {N,N}, {N,N}, {0.,P12}, {N,N} } +}; /*[clinic input] cmath.atanh = cmath.acos @@ -391,7 +422,15 @@ cmath_cos_impl(PyObject *module, Py_complex z) /* cosh(infinity + i*y) needs to be dealt with specially */ -static Py_complex cosh_special_values[7][7]; +static Py_complex cosh_special_values[7][7] = { + { {INF,N}, {U,U}, {INF,0.}, {INF,-0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {N,0.}, {U,U}, {1.,0.}, {1.,-0.}, {U,U}, {N,0.}, {N,0.} }, + { {N,0.}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,0.}, {N,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.cosh = cmath.acos @@ -453,7 +492,15 @@ cmath_cosh_impl(PyObject *module, Py_complex z) /* exp(infinity + i*y) and exp(-infinity + i*y) need special treatment for finite y */ -static Py_complex exp_special_values[7][7]; +static Py_complex exp_special_values[7][7] = { + { {0.,0.}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,0.}, {0.,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {N,N}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,N}, {N,N} }, + { {N,N}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,N}, {N,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.exp = cmath.acos @@ -512,7 +559,15 @@ cmath_exp_impl(PyObject *module, Py_complex z) return r; } -static Py_complex log_special_values[7][7]; +static Py_complex log_special_values[7][7] = { + { {INF,-P34}, {INF,-P}, {INF,-P}, {INF,P}, {INF,P}, {INF,P34}, {INF,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {-INF,-P}, {-INF,P}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {-INF,-0.}, {-INF,0.}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P14}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,P14}, {INF,N} }, + { {INF,N}, {N,N}, {N,N}, {N,N}, {N,N}, {INF,N}, {N,N} } +}; static Py_complex c_log(Py_complex z) @@ -628,7 +683,15 @@ cmath_sin_impl(PyObject *module, Py_complex z) /* sinh(infinity + i*y) needs to be dealt with specially */ -static Py_complex sinh_special_values[7][7]; +static Py_complex sinh_special_values[7][7] = { + { {INF,N}, {U,U}, {-INF,-0.}, {-INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {0.,N}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {0.,N}, {0.,N} }, + { {0.,N}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,N}, {0.,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.sinh = cmath.acos @@ -687,7 +750,15 @@ cmath_sinh_impl(PyObject *module, Py_complex z) } -static Py_complex sqrt_special_values[7][7]; +static Py_complex sqrt_special_values[7][7] = { + { {INF,-INF}, {0.,-INF}, {0.,-INF}, {0.,INF}, {0.,INF}, {INF,INF}, {N,INF} }, + { {INF,-INF}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,INF}, {INF,N} }, + { {INF,-INF}, {N,N}, {N,N}, {N,N}, {N,N}, {INF,INF}, {N,N} } +}; /*[clinic input] cmath.sqrt = cmath.acos @@ -786,7 +857,15 @@ cmath_tan_impl(PyObject *module, Py_complex z) /* tanh(infinity + i*y) needs to be dealt with specially */ -static Py_complex tanh_special_values[7][7]; +static Py_complex tanh_special_values[7][7] = { + { {-1.,0.}, {U,U}, {-1.,-0.}, {-1.,0.}, {U,U}, {-1.,0.}, {-1.,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {-0.0,N}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-0.0,N}, {-0.,N} }, + { {0.0,N}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.0,N}, {0.,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {1.,0.}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {1.,0.}, {1.,0.} }, + { {N,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.tanh = cmath.acos @@ -969,7 +1048,15 @@ cmath_polar_impl(PyObject *module, Py_complex z) */ -static Py_complex rect_special_values[7][7]; +static Py_complex rect_special_values[7][7] = { + { {INF,N}, {U,U}, {-INF,0.}, {-INF,-0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {0.,0.}, {U,U}, {-0.,0.}, {-0.,-0.}, {U,U}, {0.,0.}, {0.,0.} }, + { {0.,0.}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,0.}, {0.,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.rect @@ -1186,11 +1273,11 @@ cmath_exec(PyObject *mod) if (PyModule_Add(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_Add(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { + if (PyModule_Add(mod, "inf", PyFloat_FromDouble(INFINITY)) < 0) { return -1; } - Py_complex infj = {0.0, Py_INFINITY}; + Py_complex infj = {0.0, INFINITY}; if (PyModule_Add(mod, "infj", PyComplex_FromCComplex(infj)) < 0) { return -1; } @@ -1202,120 +1289,6 @@ cmath_exec(PyObject *mod) return -1; } - /* initialize special value tables */ - -#define INIT_SPECIAL_VALUES(NAME, BODY) { Py_complex* p = (Py_complex*)NAME; BODY } -#define C(REAL, IMAG) p->real = REAL; p->imag = IMAG; ++p; - - INIT_SPECIAL_VALUES(acos_special_values, { - C(P34,INF) C(P,INF) C(P,INF) C(P,-INF) C(P,-INF) C(P34,-INF) C(N,INF) - C(P12,INF) C(U,U) C(U,U) C(U,U) C(U,U) C(P12,-INF) C(N,N) - C(P12,INF) C(U,U) C(P12,0.) C(P12,-0.) C(U,U) C(P12,-INF) C(P12,N) - C(P12,INF) C(U,U) C(P12,0.) C(P12,-0.) C(U,U) C(P12,-INF) C(P12,N) - C(P12,INF) C(U,U) C(U,U) C(U,U) C(U,U) C(P12,-INF) C(N,N) - C(P14,INF) C(0.,INF) C(0.,INF) C(0.,-INF) C(0.,-INF) C(P14,-INF) C(N,INF) - C(N,INF) C(N,N) C(N,N) C(N,N) C(N,N) C(N,-INF) C(N,N) - }) - - INIT_SPECIAL_VALUES(acosh_special_values, { - C(INF,-P34) C(INF,-P) C(INF,-P) C(INF,P) C(INF,P) C(INF,P34) C(INF,N) - C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) - C(INF,-P12) C(U,U) C(0.,-P12) C(0.,P12) C(U,U) C(INF,P12) C(N,P12) - C(INF,-P12) C(U,U) C(0.,-P12) C(0.,P12) C(U,U) C(INF,P12) C(N,P12) - C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) - C(INF,-P14) C(INF,-0.) C(INF,-0.) C(INF,0.) C(INF,0.) C(INF,P14) C(INF,N) - C(INF,N) C(N,N) C(N,N) C(N,N) C(N,N) C(INF,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(asinh_special_values, { - C(-INF,-P14) C(-INF,-0.) C(-INF,-0.) C(-INF,0.) C(-INF,0.) C(-INF,P14) C(-INF,N) - C(-INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(-INF,P12) C(N,N) - C(-INF,-P12) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(-INF,P12) C(N,N) - C(INF,-P12) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(INF,P12) C(N,N) - C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) - C(INF,-P14) C(INF,-0.) C(INF,-0.) C(INF,0.) C(INF,0.) C(INF,P14) C(INF,N) - C(INF,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(INF,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(atanh_special_values, { - C(-0.,-P12) C(-0.,-P12) C(-0.,-P12) C(-0.,P12) C(-0.,P12) C(-0.,P12) C(-0.,N) - C(-0.,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(-0.,P12) C(N,N) - C(-0.,-P12) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(-0.,P12) C(-0.,N) - C(0.,-P12) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(0.,P12) C(0.,N) - C(0.,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(0.,P12) C(N,N) - C(0.,-P12) C(0.,-P12) C(0.,-P12) C(0.,P12) C(0.,P12) C(0.,P12) C(0.,N) - C(0.,-P12) C(N,N) C(N,N) C(N,N) C(N,N) C(0.,P12) C(N,N) - }) - - INIT_SPECIAL_VALUES(cosh_special_values, { - C(INF,N) C(U,U) C(INF,0.) C(INF,-0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(N,0.) C(U,U) C(1.,0.) C(1.,-0.) C(U,U) C(N,0.) C(N,0.) - C(N,0.) C(U,U) C(1.,-0.) C(1.,0.) C(U,U) C(N,0.) C(N,0.) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(INF,N) C(U,U) C(INF,-0.) C(INF,0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(N,N) C(N,0.) C(N,0.) C(N,N) C(N,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(exp_special_values, { - C(0.,0.) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(0.,0.) C(0.,0.) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(N,N) C(U,U) C(1.,-0.) C(1.,0.) C(U,U) C(N,N) C(N,N) - C(N,N) C(U,U) C(1.,-0.) C(1.,0.) C(U,U) C(N,N) C(N,N) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(INF,N) C(U,U) C(INF,-0.) C(INF,0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(N,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(log_special_values, { - C(INF,-P34) C(INF,-P) C(INF,-P) C(INF,P) C(INF,P) C(INF,P34) C(INF,N) - C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) - C(INF,-P12) C(U,U) C(-INF,-P) C(-INF,P) C(U,U) C(INF,P12) C(N,N) - C(INF,-P12) C(U,U) C(-INF,-0.) C(-INF,0.) C(U,U) C(INF,P12) C(N,N) - C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) - C(INF,-P14) C(INF,-0.) C(INF,-0.) C(INF,0.) C(INF,0.) C(INF,P14) C(INF,N) - C(INF,N) C(N,N) C(N,N) C(N,N) C(N,N) C(INF,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(sinh_special_values, { - C(INF,N) C(U,U) C(-INF,-0.) C(-INF,0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(0.,N) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(0.,N) C(0.,N) - C(0.,N) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(0.,N) C(0.,N) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(INF,N) C(U,U) C(INF,-0.) C(INF,0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(N,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(sqrt_special_values, { - C(INF,-INF) C(0.,-INF) C(0.,-INF) C(0.,INF) C(0.,INF) C(INF,INF) C(N,INF) - C(INF,-INF) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,INF) C(N,N) - C(INF,-INF) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(INF,INF) C(N,N) - C(INF,-INF) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(INF,INF) C(N,N) - C(INF,-INF) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,INF) C(N,N) - C(INF,-INF) C(INF,-0.) C(INF,-0.) C(INF,0.) C(INF,0.) C(INF,INF) C(INF,N) - C(INF,-INF) C(N,N) C(N,N) C(N,N) C(N,N) C(INF,INF) C(N,N) - }) - - INIT_SPECIAL_VALUES(tanh_special_values, { - C(-1.,0.) C(U,U) C(-1.,-0.) C(-1.,0.) C(U,U) C(-1.,0.) C(-1.,0.) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(-0.0,N) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(-0.0,N) C(-0.,N) - C(0.0,N) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(0.0,N) C(0.,N) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(1.,0.) C(U,U) C(1.,-0.) C(1.,0.) C(U,U) C(1.,0.) C(1.,0.) - C(N,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(N,N) C(N,N) - }) - - INIT_SPECIAL_VALUES(rect_special_values, { - C(INF,N) C(U,U) C(-INF,0.) C(-INF,-0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(0.,0.) C(U,U) C(-0.,0.) C(-0.,-0.) C(U,U) C(0.,0.) C(0.,0.) - C(0.,0.) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(0.,0.) C(0.,0.) - C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) - C(INF,N) C(U,U) C(INF,-0.) C(INF,0.) C(U,U) C(INF,N) C(INF,N) - C(N,N) C(N,N) C(N,0.) C(N,0.) C(N,N) C(N,N) C(N,N) - }) return 0; } diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 610e1ddc0e9..290dfeb0f6d 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -19,6 +19,7 @@ Copyright (c) 2023 Hanno Böck <hanno@gentoo.org> Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com> Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> + Copyright (c) 2025 Matthew Fernandez <matthew.fernandez@gmail.com> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -42,21 +43,21 @@ */ #ifndef Expat_INCLUDED -#define Expat_INCLUDED 1 +# define Expat_INCLUDED 1 -#include <stdlib.h> -#include "expat_external.h" +# include <stdlib.h> +# include "expat_external.h" -#ifdef __cplusplus +# ifdef __cplusplus extern "C" { -#endif +# endif struct XML_ParserStruct; typedef struct XML_ParserStruct *XML_Parser; typedef unsigned char XML_Bool; -#define XML_TRUE ((XML_Bool)1) -#define XML_FALSE ((XML_Bool)0) +# define XML_TRUE ((XML_Bool)1) +# define XML_FALSE ((XML_Bool)0) /* The XML_Status enum gives the possible return values for several API functions. The preprocessor #defines are included so this @@ -73,11 +74,11 @@ typedef unsigned char XML_Bool; */ enum XML_Status { XML_STATUS_ERROR = 0, -#define XML_STATUS_ERROR XML_STATUS_ERROR +# define XML_STATUS_ERROR XML_STATUS_ERROR XML_STATUS_OK = 1, -#define XML_STATUS_OK XML_STATUS_OK +# define XML_STATUS_OK XML_STATUS_OK XML_STATUS_SUSPENDED = 2 -#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +# define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED }; enum XML_Error { @@ -276,7 +277,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, /* Prepare a parser object to be reused. This is particularly valuable when memory allocation overhead is disproportionately high, - such as when a large number of small documnents need to be parsed. + such as when a large number of small documents need to be parsed. All handlers are cleared from the parser, except for the unknownEncodingHandler. The parser's external state is re-initialized except for the values of ns and ns_triplets. @@ -680,7 +681,7 @@ XMLPARSEAPI(void) XML_SetUserData(XML_Parser parser, void *userData); /* Returns the last value set by XML_SetUserData or NULL. */ -#define XML_GetUserData(parser) (*(void **)(parser)) +# define XML_GetUserData(parser) (*(void **)(parser)) /* This is equivalent to supplying an encoding argument to XML_ParserCreate. On success XML_SetEncoding returns non-zero, @@ -752,7 +753,7 @@ XML_GetSpecifiedAttributeCount(XML_Parser parser); XMLPARSEAPI(int) XML_GetIdAttributeIndex(XML_Parser parser); -#ifdef XML_ATTR_INFO +# ifdef XML_ATTR_INFO /* Source file byte offsets for the start and end of attribute names and values. The value indices are exclusive of surrounding quotes; thus in a UTF-8 source file an attribute value of "blah" will yield: @@ -773,7 +774,7 @@ typedef struct { */ XMLPARSEAPI(const XML_AttrInfo *) XML_GetAttributeInfo(XML_Parser parser); -#endif +# endif /* Parses some input. Returns XML_STATUS_ERROR if a fatal error is detected. The last call to XML_Parse must have isFinal true; len @@ -970,9 +971,9 @@ XMLPARSEAPI(const char *) XML_GetInputContext(XML_Parser parser, int *offset, int *size); /* For backwards compatibility with previous versions. */ -#define XML_GetErrorLineNumber XML_GetCurrentLineNumber -#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber -#define XML_GetErrorByteIndex XML_GetCurrentByteIndex +# define XML_GetErrorLineNumber XML_GetCurrentLineNumber +# define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +# define XML_GetErrorByteIndex XML_GetCurrentByteIndex /* Frees the content model passed to the element declaration handler */ XMLPARSEAPI(void) @@ -1032,7 +1033,10 @@ enum XML_FeatureEnum { XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT, XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT, /* Added in Expat 2.6.0. */ - XML_FEATURE_GE + XML_FEATURE_GE, + /* Added in Expat 2.7.2. */ + XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT, + XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT, /* Additional features must be added to the end of this enum. */ }; @@ -1045,7 +1049,7 @@ typedef struct { XMLPARSEAPI(const XML_Feature *) XML_GetFeatureList(void); -#if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1) +# if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1) /* Added in Expat 2.4.0 for XML_DTD defined and * added in Expat 2.6.0 for XML_GE == 1. */ XMLPARSEAPI(XML_Bool) @@ -1057,7 +1061,17 @@ XML_SetBillionLaughsAttackProtectionMaximumAmplification( XMLPARSEAPI(XML_Bool) XML_SetBillionLaughsAttackProtectionActivationThreshold( XML_Parser parser, unsigned long long activationThresholdBytes); -#endif + +/* Added in Expat 2.7.2. */ +XMLPARSEAPI(XML_Bool) +XML_SetAllocTrackerMaximumAmplification(XML_Parser parser, + float maximumAmplificationFactor); + +/* Added in Expat 2.7.2. */ +XMLPARSEAPI(XML_Bool) +XML_SetAllocTrackerActivationThreshold( + XML_Parser parser, unsigned long long activationThresholdBytes); +# endif /* Added in Expat 2.6.0. */ XMLPARSEAPI(XML_Bool) @@ -1066,12 +1080,12 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); /* Expat follows the semantic versioning convention. See https://semver.org */ -#define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 7 -#define XML_MICRO_VERSION 1 +# define XML_MAJOR_VERSION 2 +# define XML_MINOR_VERSION 7 +# define XML_MICRO_VERSION 3 -#ifdef __cplusplus +# ifdef __cplusplus } -#endif +# endif #endif /* not Expat_INCLUDED */ diff --git a/Modules/expat/expat_external.h b/Modules/expat/expat_external.h index 567872b0983..0f01a05d0e9 100644 --- a/Modules/expat/expat_external.h +++ b/Modules/expat/expat_external.h @@ -38,8 +38,7 @@ */ #ifndef Expat_External_INCLUDED -#define Expat_External_INCLUDED 1 - +# define Expat_External_INCLUDED 1 /* Namespace external symbols to allow multiple libexpat version to co-exist. */ #include "pyexpatns.h" @@ -68,12 +67,12 @@ compiled with the cdecl calling convention as the default since system headers may assume the cdecl convention. */ -#ifndef XMLCALL -# if defined(_MSC_VER) -# define XMLCALL __cdecl -# elif defined(__GNUC__) && defined(__i386) && ! defined(__INTEL_COMPILER) -# define XMLCALL __attribute__((cdecl)) -# else +# ifndef XMLCALL +# if defined(_MSC_VER) +# define XMLCALL __cdecl +# elif defined(__GNUC__) && defined(__i386) && ! defined(__INTEL_COMPILER) +# define XMLCALL __attribute__((cdecl)) +# else /* For any platform which uses this definition and supports more than one calling convention, we need to extend this definition to declare the convention used on that platform, if it's possible to @@ -84,86 +83,87 @@ pre-processor and how to specify the same calling convention as the platform's malloc() implementation. */ -# define XMLCALL -# endif -#endif /* not defined XMLCALL */ +# define XMLCALL +# endif +# endif /* not defined XMLCALL */ -#if ! defined(XML_STATIC) && ! defined(XMLIMPORT) -# ifndef XML_BUILDING_EXPAT +# if ! defined(XML_STATIC) && ! defined(XMLIMPORT) +# ifndef XML_BUILDING_EXPAT /* using Expat from an application */ -# if defined(_MSC_EXTENSIONS) && ! defined(__BEOS__) && ! defined(__CYGWIN__) -# define XMLIMPORT __declspec(dllimport) +# if defined(_MSC_EXTENSIONS) && ! defined(__BEOS__) \ + && ! defined(__CYGWIN__) +# define XMLIMPORT __declspec(dllimport) +# endif + # endif +# endif /* not defined XML_STATIC */ +# ifndef XML_ENABLE_VISIBILITY +# define XML_ENABLE_VISIBILITY 0 # endif -#endif /* not defined XML_STATIC */ -#ifndef XML_ENABLE_VISIBILITY -# define XML_ENABLE_VISIBILITY 0 -#endif - -#if ! defined(XMLIMPORT) && XML_ENABLE_VISIBILITY -# define XMLIMPORT __attribute__((visibility("default"))) -#endif +# if ! defined(XMLIMPORT) && XML_ENABLE_VISIBILITY +# define XMLIMPORT __attribute__((visibility("default"))) +# endif /* If we didn't define it above, define it away: */ -#ifndef XMLIMPORT -# define XMLIMPORT -#endif +# ifndef XMLIMPORT +# define XMLIMPORT +# endif -#if defined(__GNUC__) \ - && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) -# define XML_ATTR_MALLOC __attribute__((__malloc__)) -#else -# define XML_ATTR_MALLOC -#endif +# if defined(__GNUC__) \ + && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) +# define XML_ATTR_MALLOC __attribute__((__malloc__)) +# else +# define XML_ATTR_MALLOC +# endif -#if defined(__GNUC__) \ - && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) -# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) -#else -# define XML_ATTR_ALLOC_SIZE(x) -#endif +# if defined(__GNUC__) \ + && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) +# else +# define XML_ATTR_ALLOC_SIZE(x) +# endif -#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL +# define XMLPARSEAPI(type) XMLIMPORT type XMLCALL -#ifdef __cplusplus +# ifdef __cplusplus extern "C" { -#endif - -#ifdef XML_UNICODE_WCHAR_T -# ifndef XML_UNICODE -# define XML_UNICODE # endif -# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2) -# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc" -# endif -#endif -#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ # ifdef XML_UNICODE_WCHAR_T +# ifndef XML_UNICODE +# define XML_UNICODE +# endif +# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2) +# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc" +# endif +# endif + +# ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +# ifdef XML_UNICODE_WCHAR_T typedef wchar_t XML_Char; typedef wchar_t XML_LChar; -# else +# else typedef unsigned short XML_Char; typedef char XML_LChar; -# endif /* XML_UNICODE_WCHAR_T */ -#else /* Information is UTF-8 encoded. */ +# endif /* XML_UNICODE_WCHAR_T */ +# else /* Information is UTF-8 encoded. */ typedef char XML_Char; typedef char XML_LChar; -#endif /* XML_UNICODE */ +# endif /* XML_UNICODE */ -#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ +# ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ typedef long long XML_Index; typedef unsigned long long XML_Size; -#else +# else typedef long XML_Index; typedef unsigned long XML_Size; -#endif /* XML_LARGE_SIZE */ +# endif /* XML_LARGE_SIZE */ -#ifdef __cplusplus +# ifdef __cplusplus } -#endif +# endif #endif /* not Expat_External_INCLUDED */ diff --git a/Modules/expat/internal.h b/Modules/expat/internal.h index 6bde6ae6b31..8f5edf48ef7 100644 --- a/Modules/expat/internal.h +++ b/Modules/expat/internal.h @@ -108,6 +108,7 @@ #endif #include <limits.h> // ULONG_MAX +#include <stddef.h> // size_t #if defined(_WIN32) \ && (! defined(__USE_MINGW_ANSI_STDIO) \ @@ -148,6 +149,16 @@ 100.0f #define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \ 8388608 // 8 MiB, 2^23 + +#define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f +#define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \ + 67108864 // 64 MiB, 2^26 + +// NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would +// have to take sizeof(long double) into account +#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member +#define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t)) + /* NOTE END */ #include "expat.h" // so we can use type XML_Parser below @@ -171,6 +182,9 @@ extern #endif XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c #if defined(XML_TESTING) +void *expat_malloc(XML_Parser parser, size_t size, int sourceLine); +void expat_free(XML_Parser parser, void *ptr, int sourceLine); +void *expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine); extern unsigned int g_bytesScanned; // used for testing only #endif diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h index 8ee03ef0792..fc6b482d587 100644 --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -82,6 +82,8 @@ #define XmlPrologStateInit PyExpat_XmlPrologStateInit #define XmlPrologStateInitExternalEntity PyExpat_XmlPrologStateInitExternalEntity #define XML_ResumeParser PyExpat_XML_ResumeParser +#define XML_SetAllocTrackerActivationThreshold PyExpat_XML_SetAllocTrackerActivationThreshold +#define XML_SetAllocTrackerMaximumAmplification PyExpat_XML_SetAllocTrackerMaximumAmplification #define XML_SetAttlistDeclHandler PyExpat_XML_SetAttlistDeclHandler #define XML_SetBase PyExpat_XML_SetBase #define XML_SetBillionLaughsAttackProtectionActivationThreshold PyExpat_XML_SetBillionLaughsAttackProtectionActivationThreshold diff --git a/Modules/expat/refresh.sh b/Modules/expat/refresh.sh index 3904fc8afd6..d1bf5d19afa 100755 --- a/Modules/expat/refresh.sh +++ b/Modules/expat/refresh.sh @@ -12,9 +12,9 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. These values are used for verifying the SBOM, too. -expected_libexpat_tag="R_2_7_1" -expected_libexpat_version="2.7.1" -expected_libexpat_sha256="0cce2e6e69b327fc607b8ff264f4b66bdf71ead55a87ffd5f3143f535f15cfa2" +expected_libexpat_tag="R_2_7_3" +expected_libexpat_version="2.7.3" +expected_libexpat_sha256="821ac9710d2c073eaf13e1b1895a9c9aa66c1157a99635c639fbff65cdbdd732" expat_dir="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" cd ${expat_dir} @@ -52,7 +52,14 @@ done rm libexpat.tar.gz # Step 3: Add the namespacing include to expat_external.h -sed -i 's/#define Expat_External_INCLUDED 1/&\n\n\/* Namespace external symbols to allow multiple libexpat version to\n co-exist. \*\/\n#include "pyexpatns.h"/' expat_external.h +sed -i 's/# define Expat_External_INCLUDED 1/&\n\/* Namespace external symbols to allow multiple libexpat version to\n co-exist. \*\/\n#include "pyexpatns.h"/' expat_external.h + +if ! grep -q '#include "pyexpatns\.h"' expat_external.h; then + echo " +Error: namespacing include not found in expat_external.h; +This may be due to source changes and will require updating this script" >&2 + exit 1 +fi echo " Updated! next steps: diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index 38a2d9657b6..a187a3a18f1 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* d19ae032c224863c1527ba44d228cc34b99192c3a4c5a27af1f4e054d45ee031 (2.7.1+) +/* 28bcd8b1ba7eb595d82822908257fd9c3589b4243e3c922d0369f35bfcd7b506 (2.7.3+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -41,6 +41,7 @@ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com> Copyright (c) 2024-2025 Berkay Eren Ürün <berkay.ueruen@siemens.com> Copyright (c) 2024 Hanno Böck <hanno@gentoo.org> + Copyright (c) 2025 Matthew Fernandez <matthew.fernandez@gmail.com> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -97,7 +98,7 @@ #include <stddef.h> #include <string.h> /* memset(), memcpy() */ #include <assert.h> -#include <limits.h> /* UINT_MAX */ +#include <limits.h> /* INT_MAX, UINT_MAX */ #include <stdio.h> /* fprintf */ #include <stdlib.h> /* getenv, rand_s */ #include <stdint.h> /* uintptr_t */ @@ -234,7 +235,7 @@ typedef struct { unsigned char power; size_t size; size_t used; - const XML_Memory_Handling_Suite *mem; + XML_Parser parser; } HASH_TABLE; static size_t keylen(KEY s); @@ -357,7 +358,7 @@ typedef struct { const XML_Char *end; XML_Char *ptr; XML_Char *start; - const XML_Memory_Handling_Suite *mem; + XML_Parser parser; } STRING_POOL; /* The XML_Char before the name is used to determine whether @@ -452,6 +453,14 @@ typedef struct accounting { unsigned long long activationThresholdBytes; } ACCOUNTING; +typedef struct MALLOC_TRACKER { + XmlBigCount bytesAllocated; + XmlBigCount peakBytesAllocated; // updated live only for debug level >=2 + unsigned long debugLevel; + float maximumAmplificationFactor; // >=1.0 + XmlBigCount activationThresholdBytes; +} MALLOC_TRACKER; + typedef struct entity_stats { unsigned int countEverOpened; unsigned int currentDepth; @@ -555,27 +564,24 @@ static XML_Bool setContext(XML_Parser parser, const XML_Char *context); static void FASTCALL normalizePublicId(XML_Char *s); -static DTD *dtdCreate(const XML_Memory_Handling_Suite *ms); +static DTD *dtdCreate(XML_Parser parser); /* do not call if m_parentParser != NULL */ -static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); -static void dtdDestroy(DTD *p, XML_Bool isDocEntity, - const XML_Memory_Handling_Suite *ms); +static void dtdReset(DTD *p, XML_Parser parser); +static void dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser); static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, - const XML_Memory_Handling_Suite *ms); + XML_Parser parser); static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable); static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); -static void FASTCALL hashTableInit(HASH_TABLE *table, - const XML_Memory_Handling_Suite *ms); +static void FASTCALL hashTableInit(HASH_TABLE *table, XML_Parser parser); static void FASTCALL hashTableClear(HASH_TABLE *table); static void FASTCALL hashTableDestroy(HASH_TABLE *table); static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table); static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter); -static void FASTCALL poolInit(STRING_POOL *pool, - const XML_Memory_Handling_Suite *ms); +static void FASTCALL poolInit(STRING_POOL *pool, XML_Parser parser); static void FASTCALL poolClear(STRING_POOL *pool); static void FASTCALL poolDestroy(STRING_POOL *pool); static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, @@ -595,15 +601,15 @@ static XML_Content *build_model(XML_Parser parser); static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); -static XML_Char *copyString(const XML_Char *s, - const XML_Memory_Handling_Suite *memsuite); +static XML_Char *copyString(const XML_Char *s, XML_Parser parser); static unsigned long generate_hash_secret_salt(XML_Parser parser); static XML_Bool startParsing(XML_Parser parser); static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep, DTD *dtd); + const XML_Char *nameSep, DTD *dtd, + XML_Parser parentParser); static void parserInit(XML_Parser parser, const XML_Char *encodingName); @@ -627,10 +633,10 @@ static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity, int sourceLine); static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity, int sourceLine); +#endif /* XML_GE == 1 */ static XML_Parser getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff); -#endif /* XML_GE == 1 */ static unsigned long getDebugLevel(const char *variableName, unsigned long defaultDebugLevel); @@ -773,14 +779,238 @@ struct XML_ParserStruct { unsigned long m_hash_secret_salt; #if XML_GE == 1 ACCOUNTING m_accounting; + MALLOC_TRACKER m_alloc_tracker; ENTITY_STATS m_entity_stats; #endif XML_Bool m_reenter; }; -#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) -#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) -#define FREE(parser, p) (parser->m_mem.free_fcn((p))) +#if XML_GE == 1 +# define MALLOC(parser, s) (expat_malloc((parser), (s), __LINE__)) +# define REALLOC(parser, p, s) (expat_realloc((parser), (p), (s), __LINE__)) +# define FREE(parser, p) (expat_free((parser), (p), __LINE__)) +#else +# define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) +# define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) +# define FREE(parser, p) (parser->m_mem.free_fcn((p))) +#endif + +#if XML_GE == 1 +static void +expat_heap_stat(XML_Parser rootParser, char operator, XmlBigCount absDiff, + XmlBigCount newTotal, XmlBigCount peakTotal, int sourceLine) { + // NOTE: This can be +infinity or -nan + const float amplification + = (float)newTotal / (float)rootParser->m_accounting.countBytesDirect; + fprintf( + stderr, + "expat: Allocations(%p): Direct " EXPAT_FMT_ULL("10") ", allocated %c" EXPAT_FMT_ULL( + "10") " to " EXPAT_FMT_ULL("10") " (" EXPAT_FMT_ULL("10") " peak), amplification %8.2f (xmlparse.c:%d)\n", + (void *)rootParser, rootParser->m_accounting.countBytesDirect, operator, + absDiff, newTotal, peakTotal, (double)amplification, sourceLine); +} + +static bool +expat_heap_increase_tolerable(XML_Parser rootParser, XmlBigCount increase, + int sourceLine) { + assert(rootParser != NULL); + assert(increase > 0); + + XmlBigCount newTotal = 0; + bool tolerable = true; + + // Detect integer overflow + if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < increase) { + tolerable = false; + } else { + newTotal = rootParser->m_alloc_tracker.bytesAllocated + increase; + + if (newTotal >= rootParser->m_alloc_tracker.activationThresholdBytes) { + assert(newTotal > 0); + // NOTE: This can be +infinity when dividing by zero but not -nan + const float amplification + = (float)newTotal / (float)rootParser->m_accounting.countBytesDirect; + if (amplification + > rootParser->m_alloc_tracker.maximumAmplificationFactor) { + tolerable = false; + } + } + } + + if (! tolerable && (rootParser->m_alloc_tracker.debugLevel >= 1)) { + expat_heap_stat(rootParser, '+', increase, newTotal, newTotal, sourceLine); + } + + return tolerable; +} + +# if defined(XML_TESTING) +void * +# else +static void * +# endif +expat_malloc(XML_Parser parser, size_t size, int sourceLine) { + // Detect integer overflow + if (SIZE_MAX - size < sizeof(size_t) + EXPAT_MALLOC_PADDING) { + return NULL; + } + + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(rootParser->m_parentParser == NULL); + + const size_t bytesToAllocate = sizeof(size_t) + EXPAT_MALLOC_PADDING + size; + + if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated + < bytesToAllocate) { + return NULL; // i.e. signal integer overflow as out-of-memory + } + + if (! expat_heap_increase_tolerable(rootParser, bytesToAllocate, + sourceLine)) { + return NULL; // i.e. signal violation as out-of-memory + } + + // Actually allocate + void *const mallocedPtr = parser->m_mem.malloc_fcn(bytesToAllocate); + + if (mallocedPtr == NULL) { + return NULL; + } + + // Update in-block recorded size + *(size_t *)mallocedPtr = size; + + // Update accounting + rootParser->m_alloc_tracker.bytesAllocated += bytesToAllocate; + + // Report as needed + if (rootParser->m_alloc_tracker.debugLevel >= 2) { + if (rootParser->m_alloc_tracker.bytesAllocated + > rootParser->m_alloc_tracker.peakBytesAllocated) { + rootParser->m_alloc_tracker.peakBytesAllocated + = rootParser->m_alloc_tracker.bytesAllocated; + } + expat_heap_stat(rootParser, '+', bytesToAllocate, + rootParser->m_alloc_tracker.bytesAllocated, + rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); + } + + return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING; +} + +# if defined(XML_TESTING) +void +# else +static void +# endif +expat_free(XML_Parser parser, void *ptr, int sourceLine) { + assert(parser != NULL); + + if (ptr == NULL) { + return; + } + + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(rootParser->m_parentParser == NULL); + + // Extract size (to the eyes of malloc_fcn/realloc_fcn) and + // the original pointer returned by malloc/realloc + void *const mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t); + const size_t bytesAllocated + = sizeof(size_t) + EXPAT_MALLOC_PADDING + *(size_t *)mallocedPtr; + + // Update accounting + assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated); + rootParser->m_alloc_tracker.bytesAllocated -= bytesAllocated; + + // Report as needed + if (rootParser->m_alloc_tracker.debugLevel >= 2) { + expat_heap_stat(rootParser, '-', bytesAllocated, + rootParser->m_alloc_tracker.bytesAllocated, + rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); + } + + // NOTE: This may be freeing rootParser, so freeing has to come last + parser->m_mem.free_fcn(mallocedPtr); +} + +# if defined(XML_TESTING) +void * +# else +static void * +# endif +expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { + assert(parser != NULL); + + if (ptr == NULL) { + return expat_malloc(parser, size, sourceLine); + } + + if (size == 0) { + expat_free(parser, ptr, sourceLine); + return NULL; + } + + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(rootParser->m_parentParser == NULL); + + // Extract original size (to the eyes of the caller) and the original + // pointer returned by malloc/realloc + void *mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t); + const size_t prevSize = *(size_t *)mallocedPtr; + + // Classify upcoming change + const bool isIncrease = (size > prevSize); + const size_t absDiff + = (size > prevSize) ? (size - prevSize) : (prevSize - size); + + // Ask for permission from accounting + if (isIncrease) { + if (! expat_heap_increase_tolerable(rootParser, absDiff, sourceLine)) { + return NULL; // i.e. signal violation as out-of-memory + } + } + + // NOTE: Integer overflow detection has already been done for us + // by expat_heap_increase_tolerable(..) above + assert(SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING >= size); + + // Actually allocate + mallocedPtr = parser->m_mem.realloc_fcn( + mallocedPtr, sizeof(size_t) + EXPAT_MALLOC_PADDING + size); + + if (mallocedPtr == NULL) { + return NULL; + } + + // Update accounting + if (isIncrease) { + assert((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated + >= absDiff); + rootParser->m_alloc_tracker.bytesAllocated += absDiff; + } else { // i.e. decrease + assert(rootParser->m_alloc_tracker.bytesAllocated >= absDiff); + rootParser->m_alloc_tracker.bytesAllocated -= absDiff; + } + + // Report as needed + if (rootParser->m_alloc_tracker.debugLevel >= 2) { + if (rootParser->m_alloc_tracker.bytesAllocated + > rootParser->m_alloc_tracker.peakBytesAllocated) { + rootParser->m_alloc_tracker.peakBytesAllocated + = rootParser->m_alloc_tracker.bytesAllocated; + } + expat_heap_stat(rootParser, isIncrease ? '+' : '-', absDiff, + rootParser->m_alloc_tracker.bytesAllocated, + rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); + } + + // Update in-block recorded size + *(size_t *)mallocedPtr = size; + + return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING; +} +#endif // XML_GE == 1 XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) { @@ -821,11 +1051,14 @@ writeRandomBytes_getrandom_nonblock(void *target, size_t count) { void *const currentTarget = (void *)((char *)target + bytesWrittenTotal); const size_t bytesToWrite = count - bytesWrittenTotal; + assert(bytesToWrite <= INT_MAX); + const int bytesWrittenMore = # if defined(HAVE_GETRANDOM) - getrandom(currentTarget, bytesToWrite, getrandomFlags); + (int)getrandom(currentTarget, bytesToWrite, getrandomFlags); # else - syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags); + (int)syscall(SYS_getrandom, currentTarget, bytesToWrite, + getrandomFlags); # endif if (bytesWrittenMore > 0) { @@ -1012,9 +1245,10 @@ generate_hash_secret_salt(XML_Parser parser) { static unsigned long get_hash_secret_salt(XML_Parser parser) { - if (parser->m_parentParser != NULL) - return get_hash_secret_salt(parser->m_parentParser); - return parser->m_hash_secret_salt; + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(! rootParser->m_parentParser); + + return rootParser->m_hash_secret_salt; } static enum XML_Error @@ -1100,19 +1334,43 @@ XML_Parser XMLCALL XML_ParserCreate_MM(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep) { - return parserCreate(encodingName, memsuite, nameSep, NULL); + return parserCreate(encodingName, memsuite, nameSep, NULL, NULL); } static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep, - DTD *dtd) { - XML_Parser parser; + DTD *dtd, XML_Parser parentParser) { + XML_Parser parser = NULL; + +#if XML_GE == 1 + const size_t increase + = sizeof(size_t) + EXPAT_MALLOC_PADDING + sizeof(struct XML_ParserStruct); + + if (parentParser != NULL) { + const XML_Parser rootParser = getRootParserOf(parentParser, NULL); + if (! expat_heap_increase_tolerable(rootParser, increase, __LINE__)) { + return NULL; + } + } +#else + UNUSED_P(parentParser); +#endif if (memsuite) { XML_Memory_Handling_Suite *mtemp; +#if XML_GE == 1 + void *const sizeAndParser + = memsuite->malloc_fcn(sizeof(size_t) + EXPAT_MALLOC_PADDING + + sizeof(struct XML_ParserStruct)); + if (sizeAndParser != NULL) { + *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t) + + EXPAT_MALLOC_PADDING); +#else parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); if (parser != NULL) { +#endif mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); mtemp->malloc_fcn = memsuite->malloc_fcn; mtemp->realloc_fcn = memsuite->realloc_fcn; @@ -1120,39 +1378,86 @@ parserCreate(const XML_Char *encodingName, } } else { XML_Memory_Handling_Suite *mtemp; - parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); +#if XML_GE == 1 + void *const sizeAndParser = malloc(sizeof(size_t) + EXPAT_MALLOC_PADDING + + sizeof(struct XML_ParserStruct)); + if (sizeAndParser != NULL) { + *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t) + + EXPAT_MALLOC_PADDING); +#else + parser = malloc(sizeof(struct XML_ParserStruct)); if (parser != NULL) { +#endif mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); mtemp->malloc_fcn = malloc; mtemp->realloc_fcn = realloc; mtemp->free_fcn = free; } - } + } // cppcheck-suppress[memleak symbolName=sizeAndParser] // Cppcheck >=2.18.0 if (! parser) return parser; +#if XML_GE == 1 + // Initialize .m_alloc_tracker + memset(&parser->m_alloc_tracker, 0, sizeof(MALLOC_TRACKER)); + if (parentParser == NULL) { + parser->m_alloc_tracker.debugLevel + = getDebugLevel("EXPAT_MALLOC_DEBUG", 0u); + parser->m_alloc_tracker.maximumAmplificationFactor + = EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT; + parser->m_alloc_tracker.activationThresholdBytes + = EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT; + + // NOTE: This initialization needs to come this early because these fields + // are read by allocation tracking code + parser->m_parentParser = NULL; + parser->m_accounting.countBytesDirect = 0; + } else { + parser->m_parentParser = parentParser; + } + + // Record XML_ParserStruct allocation we did a few lines up before + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(rootParser->m_parentParser == NULL); + assert(SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated >= increase); + rootParser->m_alloc_tracker.bytesAllocated += increase; + + // Report on allocation + if (rootParser->m_alloc_tracker.debugLevel >= 2) { + if (rootParser->m_alloc_tracker.bytesAllocated + > rootParser->m_alloc_tracker.peakBytesAllocated) { + rootParser->m_alloc_tracker.peakBytesAllocated + = rootParser->m_alloc_tracker.bytesAllocated; + } + + expat_heap_stat(rootParser, '+', increase, + rootParser->m_alloc_tracker.bytesAllocated, + rootParser->m_alloc_tracker.peakBytesAllocated, __LINE__); + } +#else + parser->m_parentParser = NULL; +#endif // XML_GE == 1 + parser->m_buffer = NULL; parser->m_bufferLim = NULL; parser->m_attsSize = INIT_ATTS_SIZE; - parser->m_atts - = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE)); + parser->m_atts = MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE)); if (parser->m_atts == NULL) { FREE(parser, parser); return NULL; } #ifdef XML_ATTR_INFO - parser->m_attInfo = (XML_AttrInfo *)MALLOC( - parser, parser->m_attsSize * sizeof(XML_AttrInfo)); + parser->m_attInfo = MALLOC(parser, parser->m_attsSize * sizeof(XML_AttrInfo)); if (parser->m_attInfo == NULL) { FREE(parser, parser->m_atts); FREE(parser, parser); return NULL; } #endif - parser->m_dataBuf - = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + parser->m_dataBuf = MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char)); if (parser->m_dataBuf == NULL) { FREE(parser, parser->m_atts); #ifdef XML_ATTR_INFO @@ -1166,7 +1471,7 @@ parserCreate(const XML_Char *encodingName, if (dtd) parser->m_dtd = dtd; else { - parser->m_dtd = dtdCreate(&parser->m_mem); + parser->m_dtd = dtdCreate(parser); if (parser->m_dtd == NULL) { FREE(parser, parser->m_dataBuf); FREE(parser, parser->m_atts); @@ -1200,8 +1505,8 @@ parserCreate(const XML_Char *encodingName, parser->m_protocolEncodingName = NULL; - poolInit(&parser->m_tempPool, &(parser->m_mem)); - poolInit(&parser->m_temp2Pool, &(parser->m_mem)); + poolInit(&parser->m_tempPool, parser); + poolInit(&parser->m_temp2Pool, parser); parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { @@ -1233,7 +1538,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { parser->m_processor = prologInitProcessor; XmlPrologStateInit(&parser->m_prologState); if (encodingName != NULL) { - parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); + parser->m_protocolEncodingName = copyString(encodingName, parser); } parser->m_curBase = NULL; XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0); @@ -1295,7 +1600,6 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { parser->m_unknownEncodingMem = NULL; parser->m_unknownEncodingRelease = NULL; parser->m_unknownEncodingData = NULL; - parser->m_parentParser = NULL; parser->m_parsingStatus.parsing = XML_INITIALIZED; // Reentry can only be triggered inside m_processor calls parser->m_reenter = XML_FALSE; @@ -1385,7 +1689,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { FREE(parser, (void *)parser->m_protocolEncodingName); parser->m_protocolEncodingName = NULL; parserInit(parser, encodingName); - dtdReset(parser->m_dtd, &parser->m_mem); + dtdReset(parser->m_dtd, parser); return XML_TRUE; } @@ -1421,7 +1725,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) { parser->m_protocolEncodingName = NULL; else { /* Copy the new encoding name into allocated memory */ - parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); + parser->m_protocolEncodingName = copyString(encodingName, parser); if (! parser->m_protocolEncodingName) return XML_STATUS_ERROR; } @@ -1530,9 +1834,10 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, */ if (parser->m_ns) { XML_Char tmp[2] = {parser->m_namespaceSeparator, 0}; - parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); + parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd, oldParser); } else { - parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); + parser + = parserCreate(encodingName, &parser->m_mem, NULL, newDtd, oldParser); } if (! parser) @@ -1576,7 +1881,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, parser->m_prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem) + if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, parser) || ! setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1688,14 +1993,16 @@ XML_ParserFree(XML_Parser parser) { #else if (parser->m_dtd) #endif /* XML_DTD */ - dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, - &parser->m_mem); - FREE(parser, (void *)parser->m_atts); + dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, parser); + FREE(parser, parser->m_atts); #ifdef XML_ATTR_INFO - FREE(parser, (void *)parser->m_attInfo); + FREE(parser, parser->m_attInfo); #endif FREE(parser, parser->m_groupConnector); - FREE(parser, parser->m_buffer); + // NOTE: We are avoiding FREE(..) here because parser->m_buffer + // is not being allocated with MALLOC(..) but with plain + // .malloc_fcn(..). + parser->m_mem.free_fcn(parser->m_buffer); FREE(parser, parser->m_dataBuf); FREE(parser, parser->m_nsAtts); FREE(parser, parser->m_unknownEncodingMem); @@ -2014,12 +2321,14 @@ int XMLCALL XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { if (parser == NULL) return 0; - if (parser->m_parentParser) - return XML_SetHashSalt(parser->m_parentParser, hash_salt); + + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(! rootParser->m_parentParser); + /* block after XML_Parse()/XML_ParseBuffer() has been called */ - if (parserBusy(parser)) + if (parserBusy(rootParser)) return 0; - parser->m_hash_secret_salt = hash_salt; + rootParser->m_hash_secret_salt = hash_salt; return 1; } @@ -2287,7 +2596,9 @@ XML_GetBuffer(XML_Parser parser, int len) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return NULL; } - newBuf = (char *)MALLOC(parser, bufferSize); + // NOTE: We are avoiding MALLOC(..) here to leave limiting + // the input size to the application using Expat. + newBuf = parser->m_mem.malloc_fcn(bufferSize); if (newBuf == 0) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return NULL; @@ -2298,7 +2609,10 @@ XML_GetBuffer(XML_Parser parser, int len) { memcpy(newBuf, &parser->m_bufferPtr[-keep], EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + keep); - FREE(parser, parser->m_buffer); + // NOTE: We are avoiding FREE(..) here because parser->m_buffer + // is not being allocated with MALLOC(..) but with plain + // .malloc_fcn(..). + parser->m_mem.free_fcn(parser->m_buffer); parser->m_buffer = newBuf; parser->m_bufferEnd = parser->m_buffer @@ -2314,7 +2628,10 @@ XML_GetBuffer(XML_Parser parser, int len) { if (parser->m_bufferPtr) { memcpy(newBuf, parser->m_bufferPtr, EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)); - FREE(parser, parser->m_buffer); + // NOTE: We are avoiding FREE(..) here because parser->m_buffer + // is not being allocated with MALLOC(..) but with plain + // .malloc_fcn(..). + parser->m_mem.free_fcn(parser->m_buffer); parser->m_bufferEnd = newBuf + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); @@ -2492,28 +2809,43 @@ XML_GetCurrentColumnNumber(XML_Parser parser) { void XMLCALL XML_FreeContentModel(XML_Parser parser, XML_Content *model) { - if (parser != NULL) - FREE(parser, model); + if (parser == NULL) + return; + + // NOTE: We are avoiding FREE(..) here because the content model + // has been created using plain .malloc_fcn(..) rather than MALLOC(..). + parser->m_mem.free_fcn(model); } void *XMLCALL XML_MemMalloc(XML_Parser parser, size_t size) { if (parser == NULL) return NULL; - return MALLOC(parser, size); + + // NOTE: We are avoiding MALLOC(..) here to not include + // user allocations with allocation tracking and limiting. + return parser->m_mem.malloc_fcn(size); } void *XMLCALL XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) { if (parser == NULL) return NULL; - return REALLOC(parser, ptr, size); + + // NOTE: We are avoiding REALLOC(..) here to not include + // user allocations with allocation tracking and limiting. + return parser->m_mem.realloc_fcn(ptr, size); } void XMLCALL XML_MemFree(XML_Parser parser, void *ptr) { - if (parser != NULL) - FREE(parser, ptr); + if (parser == NULL) + return; + + // NOTE: We are avoiding FREE(..) here because XML_MemMalloc and + // XML_MemRealloc are not using MALLOC(..) and REALLOC(..) + // but plain .malloc_fcn(..) and .realloc_fcn(..), internally. + parser->m_mem.free_fcn(ptr); } void XMLCALL @@ -2713,6 +3045,13 @@ XML_GetFeatureList(void) { EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT}, /* Added in Expat 2.6.0. */ {XML_FEATURE_GE, XML_L("XML_GE"), 0}, + /* Added in Expat 2.7.2. */ + {XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT, + XML_L("XML_AT_MAX_AMP"), + (long int)EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT}, + {XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT, + XML_L("XML_AT_ACT_THRES"), + (long int)EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT}, #endif {XML_FEATURE_END, NULL, 0}}; @@ -2741,6 +3080,29 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( parser->m_accounting.activationThresholdBytes = activationThresholdBytes; return XML_TRUE; } + +XML_Bool XMLCALL +XML_SetAllocTrackerMaximumAmplification(XML_Parser parser, + float maximumAmplificationFactor) { + if ((parser == NULL) || (parser->m_parentParser != NULL) + || isnan(maximumAmplificationFactor) + || (maximumAmplificationFactor < 1.0f)) { + return XML_FALSE; + } + parser->m_alloc_tracker.maximumAmplificationFactor + = maximumAmplificationFactor; + return XML_TRUE; +} + +XML_Bool XMLCALL +XML_SetAllocTrackerActivationThreshold( + XML_Parser parser, unsigned long long activationThresholdBytes) { + if ((parser == NULL) || (parser->m_parentParser != NULL)) { + return XML_FALSE; + } + parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes; + return XML_TRUE; +} #endif /* XML_GE == 1 */ XML_Bool XMLCALL @@ -2761,8 +3123,8 @@ static XML_Bool storeRawNames(XML_Parser parser) { TAG *tag = parser->m_tagStack; while (tag) { - int bufSize; - int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); + size_t bufSize; + size_t nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); size_t rawNameLen; char *rawNameBuf = tag->buf + nameLen; /* Stop if already stored. Since m_tagStack is a stack, we can stop @@ -2779,9 +3141,9 @@ storeRawNames(XML_Parser parser) { /* Detect and prevent integer overflow. */ if (rawNameLen > (size_t)INT_MAX - nameLen) return XML_FALSE; - bufSize = nameLen + (int)rawNameLen; - if (bufSize > tag->bufEnd - tag->buf) { - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); + bufSize = nameLen + rawNameLen; + if (bufSize > (size_t)(tag->bufEnd - tag->buf)) { + char *temp = REALLOC(parser, tag->buf, bufSize); if (temp == NULL) return XML_FALSE; /* if tag->name.str points to tag->buf (only when namespace @@ -3107,10 +3469,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, tag = parser->m_freeTagList; parser->m_freeTagList = parser->m_freeTagList->parent; } else { - tag = (TAG *)MALLOC(parser, sizeof(TAG)); + tag = MALLOC(parser, sizeof(TAG)); if (! tag) return XML_ERROR_NO_MEMORY; - tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE); + tag->buf = MALLOC(parser, INIT_TAG_BUF_SIZE); if (! tag->buf) { FREE(parser, tag); return XML_ERROR_NO_MEMORY; @@ -3143,7 +3505,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, } bufSize = (int)(tag->bufEnd - tag->buf) << 1; { - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); + char *temp = REALLOC(parser, tag->buf, bufSize); if (temp == NULL) return XML_ERROR_NO_MEMORY; tag->buf = temp; @@ -3522,8 +3884,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } #endif - temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, - parser->m_attsSize * sizeof(ATTRIBUTE)); + temp = REALLOC(parser, parser->m_atts, + parser->m_attsSize * sizeof(ATTRIBUTE)); if (temp == NULL) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; @@ -3541,8 +3903,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } # endif - temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, - parser->m_attsSize * sizeof(XML_AttrInfo)); + temp2 = REALLOC(parser, parser->m_attInfo, + parser->m_attsSize * sizeof(XML_AttrInfo)); if (temp2 == NULL) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; @@ -3677,7 +4039,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, and clear flags that say whether attributes were specified */ i = 0; if (nPrefixes) { - int j; /* hash table index */ + unsigned int j; /* hash table index */ unsigned long version = parser->m_nsAttsVersion; /* Detect and prevent invalid shift */ @@ -3718,8 +4080,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } #endif - temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, - nsAttsSize * sizeof(NS_ATT)); + temp = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT)); if (! temp) { /* Restore actual size of memory in m_nsAtts */ parser->m_nsAttsPower = oldNsAttsPower; @@ -3772,7 +4133,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, if (! b) return XML_ERROR_UNBOUND_PREFIX; - for (j = 0; j < b->uriLen; j++) { + for (j = 0; j < (unsigned int)b->uriLen; j++) { const XML_Char c = b->uri[j]; if (! poolAppendChar(&parser->m_tempPool, c)) return XML_ERROR_NO_MEMORY; @@ -3866,7 +4227,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, return XML_ERROR_NONE; prefixLen = 0; if (parser->m_ns_triplets && binding->prefix->name) { - for (; binding->prefix->name[prefixLen++];) + while (binding->prefix->name[prefixLen++]) ; /* prefixLen includes null terminator */ } tagNamePtr->localPart = localPart; @@ -3900,7 +4261,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, } #endif - uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); + uri = MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); if (! uri) return XML_ERROR_NO_MEMORY; binding->uriAlloc = n + EXPAND_SPARE; @@ -4146,8 +4507,8 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, } #endif - XML_Char *temp = (XML_Char *)REALLOC( - parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); + XML_Char *temp + = REALLOC(parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (temp == NULL) return XML_ERROR_NO_MEMORY; b->uri = temp; @@ -4155,7 +4516,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, } parser->m_freeBindingList = b->nextTagBinding; } else { - b = (BINDING *)MALLOC(parser, sizeof(BINDING)); + b = MALLOC(parser, sizeof(BINDING)); if (! b) return XML_ERROR_NO_MEMORY; @@ -4173,8 +4534,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, } #endif - b->uri - = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); + b->uri = MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (! b->uri) { FREE(parser, b); return XML_ERROR_NO_MEMORY; @@ -5545,7 +5905,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, return XML_ERROR_NO_MEMORY; } - char *const new_connector = (char *)REALLOC( + char *const new_connector = REALLOC( parser, parser->m_groupConnector, parser->m_groupSize *= 2); if (new_connector == NULL) { parser->m_groupSize /= 2; @@ -5565,15 +5925,14 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, } #endif - int *const new_scaff_index = (int *)REALLOC( + int *const new_scaff_index = REALLOC( parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); if (new_scaff_index == NULL) return XML_ERROR_NO_MEMORY; dtd->scaffIndex = new_scaff_index; } } else { - parser->m_groupConnector - = (char *)MALLOC(parser, parser->m_groupSize = 32); + parser->m_groupConnector = MALLOC(parser, parser->m_groupSize = 32); if (! parser->m_groupConnector) { parser->m_groupSize = 0; return XML_ERROR_NO_MEMORY; @@ -5730,8 +6089,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, case XML_ROLE_CONTENT_EMPTY: if (dtd->in_eldecl) { if (parser->m_elementDeclHandler) { - XML_Content *content - = (XML_Content *)MALLOC(parser, sizeof(XML_Content)); + // NOTE: We are avoiding MALLOC(..) here to so that + // applications that are not using XML_FreeContentModel but + // plain free(..) or .free_fcn() to free the content model's + // memory are safe. + XML_Content *content = parser->m_mem.malloc_fcn(sizeof(XML_Content)); if (! content) return XML_ERROR_NO_MEMORY; content->quant = XML_CQUANT_NONE; @@ -5787,7 +6149,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, name = el->name; dtd->scaffold[myindex].name = name; nameLen = 0; - for (; name[nameLen++];) + while (name[nameLen++]) ; /* Detect and prevent integer overflow */ @@ -6008,8 +6370,7 @@ processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl, openEntity = *freeEntityList; *freeEntityList = openEntity->next; } else { - openEntity - = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY)); + openEntity = MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY)); if (! openEntity) return XML_ERROR_NO_MEMORY; } @@ -6087,6 +6448,10 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, // process its possible inner entities (which are added to the // m_openInternalEntities during doProlog or doContent calls above) entity->hasMore = XML_FALSE; + if (! entity->is_param + && (openEntity->startTagLevel != parser->m_tagLevel)) { + return XML_ERROR_ASYNC_ENTITY; + } triggerReenter(parser); return result; } // End of entity processing, "if" block will return here @@ -6277,7 +6642,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, case XML_TOK_ENTITY_REF: { const XML_Char *name; ENTITY *entity; - char checkEntityDecl; + bool checkEntityDecl; XML_Char ch = (XML_Char)XmlPredefinedEntityName( enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar); if (ch) { @@ -6804,8 +7169,8 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, if (type->nDefaultAtts == type->allocDefaultAtts) { if (type->allocDefaultAtts == 0) { type->allocDefaultAtts = 8; - type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC( - parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + type->defaultAtts + = MALLOC(parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); if (! type->defaultAtts) { type->allocDefaultAtts = 0; return 0; @@ -6830,8 +7195,8 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, } #endif - temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, - (count * sizeof(DEFAULT_ATTRIBUTE))); + temp = REALLOC(parser, type->defaultAtts, + (count * sizeof(DEFAULT_ATTRIBUTE))); if (temp == NULL) return 0; type->allocDefaultAtts = count; @@ -7122,19 +7487,19 @@ normalizePublicId(XML_Char *publicId) { } static DTD * -dtdCreate(const XML_Memory_Handling_Suite *ms) { - DTD *p = ms->malloc_fcn(sizeof(DTD)); +dtdCreate(XML_Parser parser) { + DTD *p = MALLOC(parser, sizeof(DTD)); if (p == NULL) return p; - poolInit(&(p->pool), ms); - poolInit(&(p->entityValuePool), ms); - hashTableInit(&(p->generalEntities), ms); - hashTableInit(&(p->elementTypes), ms); - hashTableInit(&(p->attributeIds), ms); - hashTableInit(&(p->prefixes), ms); + poolInit(&(p->pool), parser); + poolInit(&(p->entityValuePool), parser); + hashTableInit(&(p->generalEntities), parser); + hashTableInit(&(p->elementTypes), parser); + hashTableInit(&(p->attributeIds), parser); + hashTableInit(&(p->prefixes), parser); #ifdef XML_DTD p->paramEntityRead = XML_FALSE; - hashTableInit(&(p->paramEntities), ms); + hashTableInit(&(p->paramEntities), parser); #endif /* XML_DTD */ p->defaultPrefix.name = NULL; p->defaultPrefix.binding = NULL; @@ -7154,7 +7519,7 @@ dtdCreate(const XML_Memory_Handling_Suite *ms) { } static void -dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { +dtdReset(DTD *p, XML_Parser parser) { HASH_TABLE_ITER iter; hashTableIterInit(&iter, &(p->elementTypes)); for (;;) { @@ -7162,7 +7527,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { if (! e) break; if (e->allocDefaultAtts != 0) - ms->free_fcn(e->defaultAtts); + FREE(parser, e->defaultAtts); } hashTableClear(&(p->generalEntities)); #ifdef XML_DTD @@ -7179,9 +7544,9 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { p->in_eldecl = XML_FALSE; - ms->free_fcn(p->scaffIndex); + FREE(parser, p->scaffIndex); p->scaffIndex = NULL; - ms->free_fcn(p->scaffold); + FREE(parser, p->scaffold); p->scaffold = NULL; p->scaffLevel = 0; @@ -7195,7 +7560,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { } static void -dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { +dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { HASH_TABLE_ITER iter; hashTableIterInit(&iter, &(p->elementTypes)); for (;;) { @@ -7203,7 +7568,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { if (! e) break; if (e->allocDefaultAtts != 0) - ms->free_fcn(e->defaultAtts); + FREE(parser, e->defaultAtts); } hashTableDestroy(&(p->generalEntities)); #ifdef XML_DTD @@ -7215,10 +7580,10 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { poolDestroy(&(p->pool)); poolDestroy(&(p->entityValuePool)); if (isDocEntity) { - ms->free_fcn(p->scaffIndex); - ms->free_fcn(p->scaffold); + FREE(parser, p->scaffIndex); + FREE(parser, p->scaffold); } - ms->free_fcn(p); + FREE(parser, p); } /* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. @@ -7226,7 +7591,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { */ static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, - const XML_Memory_Handling_Suite *ms) { + XML_Parser parser) { HASH_TABLE_ITER iter; /* Copy the prefix table. */ @@ -7307,7 +7672,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, } #endif newE->defaultAtts - = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + = MALLOC(parser, oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); if (! newE->defaultAtts) { return 0; } @@ -7469,7 +7834,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { /* table->size is a power of 2 */ table->size = (size_t)1 << INIT_POWER; tsize = table->size * sizeof(NAMED *); - table->v = table->mem->malloc_fcn(tsize); + table->v = MALLOC(table->parser, tsize); if (! table->v) { table->size = 0; return NULL; @@ -7509,7 +7874,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { } size_t tsize = newSize * sizeof(NAMED *); - NAMED **newV = table->mem->malloc_fcn(tsize); + NAMED **newV = MALLOC(table->parser, tsize); if (! newV) return NULL; memset(newV, 0, tsize); @@ -7525,7 +7890,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { } newV[j] = table->v[i]; } - table->mem->free_fcn(table->v); + FREE(table->parser, table->v); table->v = newV; table->power = newPower; table->size = newSize; @@ -7538,7 +7903,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { } } } - table->v[i] = table->mem->malloc_fcn(createSize); + table->v[i] = MALLOC(table->parser, createSize); if (! table->v[i]) return NULL; memset(table->v[i], 0, createSize); @@ -7551,7 +7916,7 @@ static void FASTCALL hashTableClear(HASH_TABLE *table) { size_t i; for (i = 0; i < table->size; i++) { - table->mem->free_fcn(table->v[i]); + FREE(table->parser, table->v[i]); table->v[i] = NULL; } table->used = 0; @@ -7561,17 +7926,17 @@ static void FASTCALL hashTableDestroy(HASH_TABLE *table) { size_t i; for (i = 0; i < table->size; i++) - table->mem->free_fcn(table->v[i]); - table->mem->free_fcn(table->v); + FREE(table->parser, table->v[i]); + FREE(table->parser, table->v); } static void FASTCALL -hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) { +hashTableInit(HASH_TABLE *p, XML_Parser parser) { p->power = 0; p->size = 0; p->used = 0; p->v = NULL; - p->mem = ms; + p->parser = parser; } static void FASTCALL @@ -7591,13 +7956,13 @@ hashTableIterNext(HASH_TABLE_ITER *iter) { } static void FASTCALL -poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) { +poolInit(STRING_POOL *pool, XML_Parser parser) { pool->blocks = NULL; pool->freeBlocks = NULL; pool->start = NULL; pool->ptr = NULL; pool->end = NULL; - pool->mem = ms; + pool->parser = parser; } static void FASTCALL @@ -7624,13 +7989,13 @@ poolDestroy(STRING_POOL *pool) { BLOCK *p = pool->blocks; while (p) { BLOCK *tem = p->next; - pool->mem->free_fcn(p); + FREE(pool->parser, p); p = tem; } p = pool->freeBlocks; while (p) { BLOCK *tem = p->next; - pool->mem->free_fcn(p); + FREE(pool->parser, p); p = tem; } } @@ -7785,8 +8150,7 @@ poolGrow(STRING_POOL *pool) { if (bytesToAllocate == 0) return XML_FALSE; - temp = (BLOCK *)pool->mem->realloc_fcn(pool->blocks, - (unsigned)bytesToAllocate); + temp = REALLOC(pool->parser, pool->blocks, bytesToAllocate); if (temp == NULL) return XML_FALSE; pool->blocks = temp; @@ -7826,7 +8190,7 @@ poolGrow(STRING_POOL *pool) { if (bytesToAllocate == 0) return XML_FALSE; - tem = pool->mem->malloc_fcn(bytesToAllocate); + tem = MALLOC(pool->parser, bytesToAllocate); if (! tem) return XML_FALSE; tem->size = blockSize; @@ -7857,12 +8221,17 @@ nextScaffoldPart(XML_Parser parser) { return -1; } #endif - dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int)); + dtd->scaffIndex = MALLOC(parser, parser->m_groupSize * sizeof(int)); if (! dtd->scaffIndex) return -1; dtd->scaffIndex[0] = 0; } + // Will casting to int be safe further down? + if (dtd->scaffCount > INT_MAX) { + return -1; + } + if (dtd->scaffCount >= dtd->scaffSize) { CONTENT_SCAFFOLD *temp; if (dtd->scaffold) { @@ -7880,21 +8249,20 @@ nextScaffoldPart(XML_Parser parser) { } #endif - temp = (CONTENT_SCAFFOLD *)REALLOC( - parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); + temp = REALLOC(parser, dtd->scaffold, + dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); if (temp == NULL) return -1; dtd->scaffSize *= 2; } else { - temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS - * sizeof(CONTENT_SCAFFOLD)); + temp = MALLOC(parser, INIT_SCAFFOLD_ELEMENTS * sizeof(CONTENT_SCAFFOLD)); if (temp == NULL) return -1; dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; } dtd->scaffold = temp; } - next = dtd->scaffCount++; + next = (int)dtd->scaffCount++; me = &dtd->scaffold[next]; if (dtd->scaffLevel) { CONTENT_SCAFFOLD *parent @@ -7941,7 +8309,10 @@ build_model(XML_Parser parser) { const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) + (dtd->contentStringLen * sizeof(XML_Char))); - ret = (XML_Content *)MALLOC(parser, allocsize); + // NOTE: We are avoiding MALLOC(..) here to so that + // applications that are not using XML_FreeContentModel but plain + // free(..) or .free_fcn() to free the content model's memory are safe. + ret = parser->m_mem.malloc_fcn(allocsize); if (! ret) return NULL; @@ -8062,7 +8433,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, } static XML_Char * -copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { +copyString(const XML_Char *s, XML_Parser parser) { size_t charsRequired = 0; XML_Char *result; @@ -8074,7 +8445,7 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { charsRequired++; /* Now allocate space for the copy */ - result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char)); + result = MALLOC(parser, charsRequired * sizeof(XML_Char)); if (result == NULL) return NULL; /* Copy the original into place */ @@ -8093,10 +8464,10 @@ accountingGetCurrentAmplification(XML_Parser rootParser) { + rootParser->m_accounting.countBytesIndirect; const float amplificationFactor = rootParser->m_accounting.countBytesDirect - ? (countBytesOutput + ? ((float)countBytesOutput / (float)(rootParser->m_accounting.countBytesDirect)) - : ((lenOfShortestInclude - + rootParser->m_accounting.countBytesIndirect) + : ((float)(lenOfShortestInclude + + rootParser->m_accounting.countBytesIndirect) / (float)lenOfShortestInclude); assert(! rootParser->m_parentParser); return amplificationFactor; @@ -8280,6 +8651,8 @@ entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) { rootParser->m_entity_stats.currentDepth--; } +#endif /* XML_GE == 1 */ + static XML_Parser getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) { XML_Parser rootParser = parser; @@ -8295,6 +8668,8 @@ getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) { return rootParser; } +#if XML_GE == 1 + const char * unsignedCharToPrintable(unsigned char c) { switch (c) { diff --git a/Modules/expat/xmlrole.h b/Modules/expat/xmlrole.h index a7904274c91..9d0d4ff11b7 100644 --- a/Modules/expat/xmlrole.h +++ b/Modules/expat/xmlrole.h @@ -10,7 +10,7 @@ Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net> Copyright (c) 2002 Karl Waclawek <karl@waclawek.net> Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> - Copyright (c) 2017-2024 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2017-2025 Sebastian Pipping <sebastian@pipping.org> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -34,19 +34,13 @@ */ #ifndef XmlRole_INCLUDED -#define XmlRole_INCLUDED 1 +# define XmlRole_INCLUDED 1 -#ifdef __VMS -/* 0 1 2 3 0 1 2 3 - 1234567890123456789012345678901 1234567890123456789012345678901 */ -# define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt -#endif +# include "xmltok.h" -#include "xmltok.h" - -#ifdef __cplusplus +# ifdef __cplusplus extern "C" { -#endif +# endif enum { XML_ROLE_ERROR = -1, @@ -107,11 +101,11 @@ enum { XML_ROLE_CONTENT_ELEMENT_PLUS, XML_ROLE_PI, XML_ROLE_COMMENT, -#ifdef XML_DTD +# ifdef XML_DTD XML_ROLE_TEXT_DECL, XML_ROLE_IGNORE_SECT, XML_ROLE_INNER_PARAM_ENTITY_REF, -#endif /* XML_DTD */ +# endif /* XML_DTD */ XML_ROLE_PARAM_ENTITY_REF }; @@ -120,23 +114,23 @@ typedef struct prolog_state { const char *end, const ENCODING *enc); unsigned level; int role_none; -#ifdef XML_DTD +# ifdef XML_DTD unsigned includeLevel; int documentEntity; int inEntityValue; -#endif /* XML_DTD */ +# endif /* XML_DTD */ } PROLOG_STATE; void XmlPrologStateInit(PROLOG_STATE *state); -#ifdef XML_DTD +# ifdef XML_DTD void XmlPrologStateInitExternalEntity(PROLOG_STATE *state); -#endif /* XML_DTD */ +# endif /* XML_DTD */ -#define XmlTokenRole(state, tok, ptr, end, enc) \ - (((state)->handler)(state, tok, ptr, end, enc)) +# define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) -#ifdef __cplusplus +# ifdef __cplusplus } -#endif +# endif #endif /* not XmlRole_INCLUDED */ diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c index 29a66d72cee..95d5e84b67f 100644 --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -1398,7 +1398,7 @@ unknown_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, } ENCODING * -XmlInitUnknownEncoding(void *mem, int *table, CONVERTER convert, +XmlInitUnknownEncoding(void *mem, const int *table, CONVERTER convert, void *userData) { int i; struct unknown_encoding *e = (struct unknown_encoding *)mem; @@ -1661,7 +1661,7 @@ initScan(const ENCODING *const *encodingTable, const INIT_ENCODING *enc, # undef ns ENCODING * -XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert, +XmlInitUnknownEncodingNS(void *mem, const int *table, CONVERTER convert, void *userData) { ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); if (enc) diff --git a/Modules/expat/xmltok.h b/Modules/expat/xmltok.h index c51fce1ec15..79a9fb76871 100644 --- a/Modules/expat/xmltok.h +++ b/Modules/expat/xmltok.h @@ -35,113 +35,113 @@ */ #ifndef XmlTok_INCLUDED -#define XmlTok_INCLUDED 1 +# define XmlTok_INCLUDED 1 -#ifdef __cplusplus +# ifdef __cplusplus extern "C" { -#endif +# endif /* The following token may be returned by XmlContentTok */ -#define XML_TOK_TRAILING_RSQB \ - -5 /* ] or ]] at the end of the scan; might be \ - start of illegal ]]> sequence */ +# define XML_TOK_TRAILING_RSQB \ + -5 /* ] or ]] at the end of the scan; might be \ + start of illegal ]]> sequence */ /* The following tokens may be returned by both XmlPrologTok and XmlContentTok. */ -#define XML_TOK_NONE -4 /* The string to be scanned is empty */ -#define XML_TOK_TRAILING_CR \ - -3 /* A CR at the end of the scan; \ - might be part of CRLF sequence */ -#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ -#define XML_TOK_PARTIAL -1 /* only part of a token */ -#define XML_TOK_INVALID 0 +# define XML_TOK_NONE -4 /* The string to be scanned is empty */ +# define XML_TOK_TRAILING_CR \ + -3 /* A CR at the end of the scan; \ + might be part of CRLF sequence */ +# define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +# define XML_TOK_PARTIAL -1 /* only part of a token */ +# define XML_TOK_INVALID 0 /* The following tokens are returned by XmlContentTok; some are also returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok. */ -#define XML_TOK_START_TAG_WITH_ATTS 1 -#define XML_TOK_START_TAG_NO_ATTS 2 -#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */ -#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 -#define XML_TOK_END_TAG 5 -#define XML_TOK_DATA_CHARS 6 -#define XML_TOK_DATA_NEWLINE 7 -#define XML_TOK_CDATA_SECT_OPEN 8 -#define XML_TOK_ENTITY_REF 9 -#define XML_TOK_CHAR_REF 10 /* numeric character reference */ +# define XML_TOK_START_TAG_WITH_ATTS 1 +# define XML_TOK_START_TAG_NO_ATTS 2 +# define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */ +# define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +# define XML_TOK_END_TAG 5 +# define XML_TOK_DATA_CHARS 6 +# define XML_TOK_DATA_NEWLINE 7 +# define XML_TOK_CDATA_SECT_OPEN 8 +# define XML_TOK_ENTITY_REF 9 +# define XML_TOK_CHAR_REF 10 /* numeric character reference */ /* The following tokens may be returned by both XmlPrologTok and XmlContentTok. */ -#define XML_TOK_PI 11 /* processing instruction */ -#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ -#define XML_TOK_COMMENT 13 -#define XML_TOK_BOM 14 /* Byte order mark */ +# define XML_TOK_PI 11 /* processing instruction */ +# define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +# define XML_TOK_COMMENT 13 +# define XML_TOK_BOM 14 /* Byte order mark */ /* The following tokens are returned only by XmlPrologTok */ -#define XML_TOK_PROLOG_S 15 -#define XML_TOK_DECL_OPEN 16 /* <!foo */ -#define XML_TOK_DECL_CLOSE 17 /* > */ -#define XML_TOK_NAME 18 -#define XML_TOK_NMTOKEN 19 -#define XML_TOK_POUND_NAME 20 /* #name */ -#define XML_TOK_OR 21 /* | */ -#define XML_TOK_PERCENT 22 -#define XML_TOK_OPEN_PAREN 23 -#define XML_TOK_CLOSE_PAREN 24 -#define XML_TOK_OPEN_BRACKET 25 -#define XML_TOK_CLOSE_BRACKET 26 -#define XML_TOK_LITERAL 27 -#define XML_TOK_PARAM_ENTITY_REF 28 -#define XML_TOK_INSTANCE_START 29 +# define XML_TOK_PROLOG_S 15 +# define XML_TOK_DECL_OPEN 16 /* <!foo */ +# define XML_TOK_DECL_CLOSE 17 /* > */ +# define XML_TOK_NAME 18 +# define XML_TOK_NMTOKEN 19 +# define XML_TOK_POUND_NAME 20 /* #name */ +# define XML_TOK_OR 21 /* | */ +# define XML_TOK_PERCENT 22 +# define XML_TOK_OPEN_PAREN 23 +# define XML_TOK_CLOSE_PAREN 24 +# define XML_TOK_OPEN_BRACKET 25 +# define XML_TOK_CLOSE_BRACKET 26 +# define XML_TOK_LITERAL 27 +# define XML_TOK_PARAM_ENTITY_REF 28 +# define XML_TOK_INSTANCE_START 29 /* The following occur only in element type declarations */ -#define XML_TOK_NAME_QUESTION 30 /* name? */ -#define XML_TOK_NAME_ASTERISK 31 /* name* */ -#define XML_TOK_NAME_PLUS 32 /* name+ */ -#define XML_TOK_COND_SECT_OPEN 33 /* <![ */ -#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */ -#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ -#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ -#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ -#define XML_TOK_COMMA 38 +# define XML_TOK_NAME_QUESTION 30 /* name? */ +# define XML_TOK_NAME_ASTERISK 31 /* name* */ +# define XML_TOK_NAME_PLUS 32 /* name+ */ +# define XML_TOK_COND_SECT_OPEN 33 /* <![ */ +# define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */ +# define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +# define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +# define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +# define XML_TOK_COMMA 38 /* The following token is returned only by XmlAttributeValueTok */ -#define XML_TOK_ATTRIBUTE_VALUE_S 39 +# define XML_TOK_ATTRIBUTE_VALUE_S 39 /* The following token is returned only by XmlCdataSectionTok */ -#define XML_TOK_CDATA_SECT_CLOSE 40 +# define XML_TOK_CDATA_SECT_CLOSE 40 /* With namespace processing this is returned by XmlPrologTok for a name with a colon. */ -#define XML_TOK_PREFIXED_NAME 41 +# define XML_TOK_PREFIXED_NAME 41 -#ifdef XML_DTD -# define XML_TOK_IGNORE_SECT 42 -#endif /* XML_DTD */ +# ifdef XML_DTD +# define XML_TOK_IGNORE_SECT 42 +# endif /* XML_DTD */ -#ifdef XML_DTD -# define XML_N_STATES 4 -#else /* not XML_DTD */ -# define XML_N_STATES 3 -#endif /* not XML_DTD */ +# ifdef XML_DTD +# define XML_N_STATES 4 +# else /* not XML_DTD */ +# define XML_N_STATES 3 +# endif /* not XML_DTD */ -#define XML_PROLOG_STATE 0 -#define XML_CONTENT_STATE 1 -#define XML_CDATA_SECTION_STATE 2 -#ifdef XML_DTD -# define XML_IGNORE_SECTION_STATE 3 -#endif /* XML_DTD */ +# define XML_PROLOG_STATE 0 +# define XML_CONTENT_STATE 1 +# define XML_CDATA_SECTION_STATE 2 +# ifdef XML_DTD +# define XML_IGNORE_SECTION_STATE 3 +# endif /* XML_DTD */ -#define XML_N_LITERAL_TYPES 2 -#define XML_ATTRIBUTE_VALUE_LITERAL 0 -#define XML_ENTITY_VALUE_LITERAL 1 +# define XML_N_LITERAL_TYPES 2 +# define XML_ATTRIBUTE_VALUE_LITERAL 0 +# define XML_ENTITY_VALUE_LITERAL 1 /* The size of the buffer passed to XmlUtf8Encode must be at least this. */ -#define XML_UTF8_ENCODE_MAX 4 +# define XML_UTF8_ENCODE_MAX 4 /* The size of the buffer passed to XmlUtf16Encode must be at least this. */ -#define XML_UTF16_ENCODE_MAX 2 +# define XML_UTF16_ENCODE_MAX 2 typedef struct position { /* first line and first column are 0 not 1 */ @@ -220,63 +220,63 @@ struct encoding { the prolog outside literals, comments and processing instructions. */ -#define XmlTok(enc, state, ptr, end, nextTokPtr) \ - (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) +# define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) -#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) +# define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) -#define XmlContentTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) +# define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) -#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) +# define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) -#ifdef XML_DTD +# ifdef XML_DTD -# define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) +# define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) -#endif /* XML_DTD */ +# endif /* XML_DTD */ /* This is used for performing a 2nd-level tokenization on the content of a literal that has already been returned by XmlTok. */ -#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ - (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) +# define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) -#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ - XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) +# define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) -#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ - XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) +# define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) -#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ - (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) +# define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) -#define XmlNameLength(enc, ptr) (((enc)->nameLength)(enc, ptr)) +# define XmlNameLength(enc, ptr) (((enc)->nameLength)(enc, ptr)) -#define XmlSkipS(enc, ptr) (((enc)->skipS)(enc, ptr)) +# define XmlSkipS(enc, ptr) (((enc)->skipS)(enc, ptr)) -#define XmlGetAttributes(enc, ptr, attsMax, atts) \ - (((enc)->getAtts)(enc, ptr, attsMax, atts)) +# define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) -#define XmlCharRefNumber(enc, ptr) (((enc)->charRefNumber)(enc, ptr)) +# define XmlCharRefNumber(enc, ptr) (((enc)->charRefNumber)(enc, ptr)) -#define XmlPredefinedEntityName(enc, ptr, end) \ - (((enc)->predefinedEntityName)(enc, ptr, end)) +# define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) -#define XmlUpdatePosition(enc, ptr, end, pos) \ - (((enc)->updatePosition)(enc, ptr, end, pos)) +# define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) -#define XmlIsPublicId(enc, ptr, end, badPtr) \ - (((enc)->isPublicId)(enc, ptr, end, badPtr)) +# define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) -#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ - (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) +# define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) -#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ - (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) +# define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) typedef struct { ENCODING initEnc; @@ -299,7 +299,7 @@ int XmlSizeOfUnknownEncoding(void); typedef int(XMLCALL *CONVERTER)(void *userData, const char *p); -ENCODING *XmlInitUnknownEncoding(void *mem, int *table, CONVERTER convert, +ENCODING *XmlInitUnknownEncoding(void *mem, const int *table, CONVERTER convert, void *userData); int XmlParseXmlDeclNS(int isGeneralTextEntity, const ENCODING *enc, @@ -312,10 +312,10 @@ int XmlInitEncodingNS(INIT_ENCODING *p, const ENCODING **encPtr, const char *name); const ENCODING *XmlGetUtf8InternalEncodingNS(void); const ENCODING *XmlGetUtf16InternalEncodingNS(void); -ENCODING *XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert, - void *userData); -#ifdef __cplusplus +ENCODING *XmlInitUnknownEncodingNS(void *mem, const int *table, + CONVERTER convert, void *userData); +# ifdef __cplusplus } -#endif +# endif #endif /* not XmlTok_INCLUDED */ diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index e49bf81b61f..e373bf36881 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -1,9 +1,8 @@ /* fcntl module */ -// Need limited C API version 3.14 for PyLong_AsNativeBytes() in AC code -#include "pyconfig.h" // Py_GIL_DISABLED -#ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030e0000 +// Argument Clinic uses the internal C API +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 #endif #include "Python.h" @@ -41,22 +40,27 @@ fcntl.fcntl arg: object(c_default='NULL') = 0 / -Perform the operation `cmd` on file descriptor fd. +Perform the operation cmd on file descriptor fd. -The values used for `cmd` are operating system dependent, and are available -as constants in the fcntl module, using the same names as used in -the relevant C header files. The argument arg is optional, and -defaults to 0; it may be an int or a string. If arg is given as a string, -the return value of fcntl is a string of that length, containing the -resulting value put in the arg buffer by the operating system. The length -of the arg string is not allowed to exceed 1024 bytes. If the arg given -is an integer or if none is specified, the result value is an integer -corresponding to the return value of the fcntl call in the C code. +The values used for cmd are operating system dependent, and are +available as constants in the fcntl module, using the same names as used +in the relevant C header files. The argument arg is optional, and +defaults to 0; it may be an integer, a bytes-like object or a string. +If arg is given as a string, it will be encoded to binary using the +UTF-8 encoding. + +If the arg given is an integer or if none is specified, the result value +is an integer corresponding to the return value of the fcntl() call in +the C code. + +If arg is given as a bytes-like object, the return value of fcntl() is a +bytes object of that length, containing the resulting value put in the +arg buffer by the operating system. [clinic start generated code]*/ static PyObject * fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg) -/*[clinic end generated code: output=888fc93b51c295bd input=7955340198e5f334]*/ +/*[clinic end generated code: output=888fc93b51c295bd input=77340720f11665da]*/ { int ret; int async_err = 0; @@ -113,12 +117,12 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg) return PyBytes_FromStringAndSize(buf, len); } else { - PyObject *result = PyBytes_FromStringAndSize(NULL, len); - if (result == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(len); + if (writer == NULL) { PyBuffer_Release(&view); return NULL; } - char *ptr = PyBytes_AsString(result); + char *ptr = PyBytesWriter_GetData(writer); memcpy(ptr, view.buf, len); PyBuffer_Release(&view); @@ -131,15 +135,15 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg) if (!async_err) { PyErr_SetFromErrno(PyExc_OSError); } - Py_DECREF(result); + PyBytesWriter_Discard(writer); return NULL; } if (ptr[len] != '\0') { PyErr_SetString(PyExc_SystemError, "buffer overflow"); - Py_DECREF(result); + PyBytesWriter_Discard(writer); return NULL; } - return result; + return PyBytesWriter_Finish(writer); } #undef FCNTL_BUFSZ } @@ -152,7 +156,6 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg) /*[clinic input] -@permit_long_docstring_body fcntl.ioctl fd: fildes @@ -161,40 +164,39 @@ fcntl.ioctl mutate_flag as mutate_arg: bool = True / -Perform the operation `request` on file descriptor `fd`. +Perform the operation request on file descriptor fd. -The values used for `request` are operating system dependent, and are available -as constants in the fcntl or termios library modules, using the same names as -used in the relevant C header files. +The values used for request are operating system dependent, and are +available as constants in the fcntl or termios library modules, using +the same names as used in the relevant C header files. -The argument `arg` is optional, and defaults to 0; it may be an int or a -buffer containing character data (most likely a string or an array). +The argument arg is optional, and defaults to 0; it may be an integer, a +bytes-like object or a string. If arg is given as a string, it will be +encoded to binary using the UTF-8 encoding. -If the argument is a mutable buffer (such as an array) and if the -mutate_flag argument (which is only allowed in this case) is true then the -buffer is (in effect) passed to the operating system and changes made by -the OS will be reflected in the contents of the buffer after the call has -returned. The return value is the integer returned by the ioctl system -call. +If the arg given is an integer or if none is specified, the result value +is an integer corresponding to the return value of the ioctl() call in +the C code. -If the argument is a mutable buffer and the mutable_flag argument is false, -the behavior is as if a string had been passed. +If the argument is a mutable buffer (such as a bytearray) and the +mutate_flag argument is true (default) then the buffer is (in effect) +passed to the operating system and changes made by the OS will be +reflected in the contents of the buffer after the call has returned. +The return value is the integer returned by the ioctl() system call. -If the argument is an immutable buffer (most likely a string) then a copy -of the buffer is passed to the operating system and the return value is a -string of the same length containing whatever the operating system put in -the buffer. The length of the arg buffer in this case is not allowed to -exceed 1024 bytes. +If the argument is a mutable buffer and the mutable_flag argument is +false, the behavior is as if an immutable buffer had been passed. -If the arg given is an integer or if none is specified, the result value is -an integer corresponding to the return value of the ioctl call in the C -code. +If the argument is an immutable buffer then a copy of the buffer is +passed to the operating system and the return value is a bytes object of +the same length containing whatever the operating system put in the +buffer. [clinic start generated code]*/ static PyObject * fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, int mutate_arg) -/*[clinic end generated code: output=f72baba2454d7a62 input=d7fe504d335449e2]*/ +/*[clinic end generated code: output=f72baba2454d7a62 input=954fe75c208cc492]*/ { /* We use the unsigned non-checked 'I' format for the 'code' parameter because the system expects it to be a 32bit bit field value @@ -297,12 +299,12 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, return PyBytes_FromStringAndSize(buf, len); } else { - PyObject *result = PyBytes_FromStringAndSize(NULL, len); - if (result == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(len); + if (writer == NULL) { PyBuffer_Release(&view); return NULL; } - char *ptr = PyBytes_AsString(result); + char *ptr = PyBytesWriter_GetData(writer); memcpy(ptr, view.buf, len); PyBuffer_Release(&view); @@ -315,15 +317,15 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, if (!async_err) { PyErr_SetFromErrno(PyExc_OSError); } - Py_DECREF(result); + PyBytesWriter_Discard(writer); return NULL; } if (ptr[len] != '\0') { PyErr_SetString(PyExc_SystemError, "buffer overflow"); - Py_DECREF(result); + PyBytesWriter_Discard(writer); return NULL; } - return result; + return PyBytesWriter_Finish(writer); } #undef IOCTL_BUFSZ } @@ -341,7 +343,7 @@ fcntl.flock operation as code: int / -Perform the lock operation `operation` on file descriptor `fd`. +Perform the lock operation on file descriptor fd. See the Unix manual page for flock(2) for details (On some systems, this function is emulated using fcntl()). @@ -349,7 +351,7 @@ function is emulated using fcntl()). static PyObject * fcntl_flock_impl(PyObject *module, int fd, int code) -/*[clinic end generated code: output=84059e2b37d2fc64 input=0bfc00f795953452]*/ +/*[clinic end generated code: output=84059e2b37d2fc64 input=ade68943e8599f0a]*/ { int ret; int async_err = 0; @@ -401,7 +403,6 @@ fcntl_flock_impl(PyObject *module, int fd, int code) /*[clinic input] -@permit_long_docstring_body fcntl.lockf fd: fildes @@ -413,22 +414,22 @@ fcntl.lockf A wrapper around the fcntl() locking calls. -`fd` is the file descriptor of the file to lock or unlock, and operation is one -of the following values: +fd is the file descriptor of the file to lock or unlock, and operation +is one of the following values: LOCK_UN - unlock LOCK_SH - acquire a shared lock LOCK_EX - acquire an exclusive lock When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with -LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the -lock cannot be acquired, an OSError will be raised and the exception will -have an errno attribute set to EACCES or EAGAIN (depending on the operating -system -- for portability, check for either value). +LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and +the lock cannot be acquired, an OSError will be raised and the exception +will have an errno attribute set to EACCES or EAGAIN (depending on the +operating system -- for portability, check for either value). -`len` is the number of bytes to lock, with the default meaning to lock to -EOF. `start` is the byte offset, relative to `whence`, to that the lock -starts. `whence` is as with fileobj.seek(), specifically: +len is the number of bytes to lock, with the default meaning to lock to +EOF. start is the byte offset, relative to whence, to that the lock +starts. whence is as with fileobj.seek(), specifically: 0 - relative to the start of the file (SEEK_SET) 1 - relative to the current buffer position (SEEK_CUR) @@ -438,7 +439,7 @@ starts. `whence` is as with fileobj.seek(), specifically: static PyObject * fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence) -/*[clinic end generated code: output=4985e7a172e7461a input=f666662ec2edd775]*/ +/*[clinic end generated code: output=4985e7a172e7461a input=369bef4d7a1c5ff4]*/ { int ret; int async_err = 0; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 02839ca3c99..4c286f5c12c 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -8,7 +8,6 @@ #include "pycore_gc.h" #include "pycore_object.h" // _PyObject_IS_GC() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_tuple.h" // _PyTuple_FromArray() typedef struct _gc_runtime_state GCState; @@ -359,10 +358,12 @@ gc_get_stats_impl(PyObject *module) for (i = 0; i < NUM_GENERATIONS; i++) { PyObject *dict; st = &stats[i]; - dict = Py_BuildValue("{snsnsn}", + dict = Py_BuildValue("{snsnsnsnsd}", "collections", st->collections, "collected", st->collected, - "uncollectable", st->uncollectable + "uncollectable", st->uncollectable, + "candidates", st->candidates, + "duration", st->duration ); if (dict == NULL) goto error; @@ -478,7 +479,7 @@ PyDoc_STRVAR(gc__doc__, "set_debug() -- Set debugging flags.\n" "get_debug() -- Get debugging flags.\n" "set_threshold() -- Set the collection thresholds.\n" -"get_threshold() -- Return the current the collection thresholds.\n" +"get_threshold() -- Return the current collection thresholds.\n" "get_objects() -- Return a list of all objects tracked by the collector.\n" "is_tracked() -- Returns true if a given object is tracked.\n" "is_finalized() -- Returns true if a given object has been already finalized.\n" diff --git a/Modules/hmacmodule.c b/Modules/hmacmodule.c index 680c93a04ca..f074f248077 100644 --- a/Modules/hmacmodule.c +++ b/Modules/hmacmodule.c @@ -756,7 +756,7 @@ _hmac_new_impl(PyObject *module, PyObject *keyobj, PyObject *msgobj, return NULL; } - HMACObject *self = PyObject_GC_New(HMACObject, state->hmac_type); + HMACObject *self = PyObject_New(HMACObject, state->hmac_type); if (self == NULL) { return NULL; } @@ -791,7 +791,6 @@ _hmac_new_impl(PyObject *module, PyObject *keyobj, PyObject *msgobj, #endif } assert(rc == 0); - PyObject_GC_Track(self); return (PyObject *)self; error_on_key: @@ -852,7 +851,7 @@ _hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls) /*[clinic end generated code: output=a955bfa55b65b215 input=17b2c0ad0b147e36]*/ { hmacmodule_state *state = get_hmacmodule_state_by_cls(cls); - HMACObject *copy = PyObject_GC_New(HMACObject, state->hmac_type); + HMACObject *copy = PyObject_New(HMACObject, state->hmac_type); if (copy == NULL) { return NULL; } @@ -870,7 +869,6 @@ _hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls) } HASHLIB_INIT_MUTEX(copy); - PyObject_GC_Track(copy); return (PyObject *)copy; } @@ -1026,19 +1024,11 @@ static void HMACObject_dealloc(PyObject *op) { PyTypeObject *type = Py_TYPE(op); - PyObject_GC_UnTrack(op); (void)HMACObject_clear(op); type->tp_free(op); Py_DECREF(type); } -static int -HMACObject_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; -} - static PyMethodDef HMACObject_methods[] = { _HMAC_HMAC_COPY_METHODDEF _HMAC_HMAC_UPDATE_METHODDEF @@ -1058,9 +1048,7 @@ static PyType_Slot HMACObject_Type_slots[] = { {Py_tp_repr, HMACObject_repr}, {Py_tp_methods, HMACObject_methods}, {Py_tp_getset, HMACObject_getsets}, - {Py_tp_clear, HMACObject_clear}, {Py_tp_dealloc, HMACObject_dealloc}, - {Py_tp_traverse, HMACObject_traverse}, {0, NULL} /* sentinel */ }; @@ -1070,8 +1058,7 @@ static PyType_Spec HMAC_Type_spec = { .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_HEAPTYPE - | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_HAVE_GC, + | Py_TPFLAGS_IMMUTABLETYPE, .slots = HMACObject_Type_slots, }; diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index bc23ad7e848..8685eff8be6 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -376,7 +376,7 @@ pairwise_next(PyObject *op) } result = po->result; - if (Py_REFCNT(result) == 1) { + if (_PyObject_IsUniquelyReferenced(result)) { Py_INCREF(result); PyObject *last_old = PyTuple_GET_ITEM(result, 0); PyObject *last_new = PyTuple_GET_ITEM(result, 1); @@ -802,7 +802,7 @@ teedataobject_traverse(PyObject *op, visitproc visit, void * arg) static void teedataobject_safe_decref(PyObject *obj) { - while (obj && Py_REFCNT(obj) == 1) { + while (obj && _PyObject_IsUniquelyReferenced(obj)) { teedataobject *tmp = teedataobject_CAST(obj); PyObject *nextlink = tmp->nextlink; tmp->nextlink = NULL; @@ -1069,22 +1069,18 @@ static PyType_Spec tee_spec = { /*[clinic input] itertools.tee iterable: object - n: Py_ssize_t = 2 + n: Py_ssize_t(allow_negative=False) = 2 / Returns a tuple of n independent iterators. [clinic start generated code]*/ static PyObject * itertools_tee_impl(PyObject *module, PyObject *iterable, Py_ssize_t n) -/*[clinic end generated code: output=1c64519cd859c2f0 input=c99a1472c425d66d]*/ +/*[clinic end generated code: output=1c64519cd859c2f0 input=0f72d78e655f45cb]*/ { Py_ssize_t i; PyObject *it, *to, *result; - if (n < 0) { - PyErr_SetString(PyExc_ValueError, "n must be >= 0"); - return NULL; - } result = PyTuple_New(n); if (result == NULL) return NULL; @@ -2133,9 +2129,9 @@ product_next_lock_held(PyObject *op) Py_ssize_t *indices = lz->indices; /* Copy the previous result tuple or re-use it if available */ - if (Py_REFCNT(result) > 1) { + if (!_PyObject_IsUniquelyReferenced(result)) { PyObject *old_result = result; - result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), npools); + result = PyTuple_FromArray(_PyTuple_ITEMS(old_result), npools); if (result == NULL) goto empty; lz->result = result; @@ -2255,7 +2251,7 @@ typedef struct { @classmethod itertools.combinations.__new__ iterable: object - r: Py_ssize_t + r: Py_ssize_t(allow_negative=False) Return successive r-length combinations of elements in the iterable. combinations(range(4), 3) --> (0,1,2), (0,1,3), (0,2,3), (1,2,3) @@ -2264,7 +2260,7 @@ combinations(range(4), 3) --> (0,1,2), (0,1,3), (0,2,3), (1,2,3) static PyObject * itertools_combinations_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t r) -/*[clinic end generated code: output=87a689b39c40039c input=06bede09e3da20f8]*/ +/*[clinic end generated code: output=87a689b39c40039c input=a32f07a15cfa4676]*/ { combinationsobject *co; Py_ssize_t n; @@ -2276,10 +2272,6 @@ itertools_combinations_impl(PyTypeObject *type, PyObject *iterable, if (pool == NULL) goto error; n = PyTuple_GET_SIZE(pool); - if (r < 0) { - PyErr_SetString(PyExc_ValueError, "r must be non-negative"); - goto error; - } indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { @@ -2372,9 +2364,9 @@ combinations_next_lock_held(PyObject *op) } } else { /* Copy the previous result tuple or re-use it if available */ - if (Py_REFCNT(result) > 1) { + if (!_PyObject_IsUniquelyReferenced(result)) { PyObject *old_result = result; - result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); + result = PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); if (result == NULL) goto empty; co->result = result; @@ -2510,7 +2502,7 @@ typedef struct { @classmethod itertools.combinations_with_replacement.__new__ iterable: object - r: Py_ssize_t + r: Py_ssize_t(allow_negative=False) Return successive r-length combinations of elements in the iterable allowing individual elements to have successive repeats. combinations_with_replacement('ABC', 2) --> ('A','A'), ('A','B'), ('A','C'), ('B','B'), ('B','C'), ('C','C') @@ -2520,7 +2512,7 @@ static PyObject * itertools_combinations_with_replacement_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t r) -/*[clinic end generated code: output=48b26856d4e659ca input=26ebe0e42149e9fb]*/ +/*[clinic end generated code: output=48b26856d4e659ca input=828696750169e84f]*/ { cwrobject *co; Py_ssize_t n; @@ -2532,10 +2524,6 @@ itertools_combinations_with_replacement_impl(PyTypeObject *type, if (pool == NULL) goto error; n = PyTuple_GET_SIZE(pool); - if (r < 0) { - PyErr_SetString(PyExc_ValueError, "r must be non-negative"); - goto error; - } indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { @@ -2630,9 +2618,9 @@ cwr_next(PyObject *op) } } else { /* Copy the previous result tuple or re-use it if available */ - if (Py_REFCNT(result) > 1) { + if (!_PyObject_IsUniquelyReferenced(result)) { PyObject *old_result = result; - result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); + result = PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); if (result == NULL) goto empty; co->result = result; @@ -2891,9 +2879,9 @@ permutations_next(PyObject *op) goto empty; /* Copy the previous result tuple or re-use it if available */ - if (Py_REFCNT(result) > 1) { + if (!_PyObject_IsUniquelyReferenced(result)) { PyObject *old_result = result; - result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); + result = PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); if (result == NULL) goto empty; po->result = result; @@ -3859,7 +3847,7 @@ zip_longest_next(PyObject *op) return NULL; if (lz->numactive == 0) return NULL; - if (Py_REFCNT(result) == 1) { + if (_PyObject_IsUniquelyReferenced(result)) { Py_INCREF(result); for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); diff --git a/Modules/makesetup b/Modules/makesetup index f6cf695b457..104c824b846 100755 --- a/Modules/makesetup +++ b/Modules/makesetup @@ -90,6 +90,7 @@ NL='\ # Main loop for i in ${*-Setup} do + echo '' # Add a linebreak so we don't choke on files missing EOL. case $i in -n) echo '*noobjects*';; *) echo '*doconfig*'; cat "$i";; diff --git a/Modules/mathintegermodule.c b/Modules/mathintegermodule.c new file mode 100644 index 00000000000..de5f619c9d0 --- /dev/null +++ b/Modules/mathintegermodule.c @@ -0,0 +1,1293 @@ +/* math.integer module -- integer-related mathematical functions */ + +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + +#include "Python.h" +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_bitutils.h" // _Py_bit_length() +#include "pycore_long.h" // _PyLong_GetZero() + +#include "clinic/mathintegermodule.c.h" + +/*[clinic input] +module math +module math.integer +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e3d09c1c90de7fa8]*/ + + +/*[clinic input] +math.integer.gcd + + *integers as args: array + +Greatest Common Divisor. +[clinic start generated code]*/ + +static PyObject * +math_integer_gcd_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=8e9c5bab06bea203 input=a90cde2ac5281551]*/ +{ + // Fast-path for the common case: gcd(int, int) + if (args_length == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1])) + { + return _PyLong_GCD(args[0], args[1]); + } + + if (args_length == 0) { + return PyLong_FromLong(0); + } + + PyObject *res = PyNumber_Index(args[0]); + if (res == NULL) { + return NULL; + } + if (args_length == 1) { + Py_SETREF(res, PyNumber_Absolute(res)); + return res; + } + + PyObject *one = _PyLong_GetOne(); // borrowed ref + for (Py_ssize_t i = 1; i < args_length; i++) { + PyObject *x = _PyNumber_Index(args[i]); + if (x == NULL) { + Py_DECREF(res); + return NULL; + } + if (res == one) { + /* Fast path: just check arguments. + It is okay to use identity comparison here. */ + Py_DECREF(x); + continue; + } + Py_SETREF(res, _PyLong_GCD(res, x)); + Py_DECREF(x); + if (res == NULL) { + return NULL; + } + } + return res; +} + + +static PyObject * +long_lcm(PyObject *a, PyObject *b) +{ + PyObject *g, *m, *f, *ab; + + if (_PyLong_IsZero((PyLongObject *)a) || _PyLong_IsZero((PyLongObject *)b)) { + return PyLong_FromLong(0); + } + g = _PyLong_GCD(a, b); + if (g == NULL) { + return NULL; + } + f = PyNumber_FloorDivide(a, g); + Py_DECREF(g); + if (f == NULL) { + return NULL; + } + m = PyNumber_Multiply(f, b); + Py_DECREF(f); + if (m == NULL) { + return NULL; + } + ab = PyNumber_Absolute(m); + Py_DECREF(m); + return ab; +} + + +/*[clinic input] +math.integer.lcm + + *integers as args: array + +Least Common Multiple. +[clinic start generated code]*/ + +static PyObject * +math_integer_lcm_impl(PyObject *module, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=3e88889b866ccc28 input=261bddc85a136bdf]*/ +{ + PyObject *res, *x; + Py_ssize_t i; + + if (args_length == 0) { + return PyLong_FromLong(1); + } + res = PyNumber_Index(args[0]); + if (res == NULL) { + return NULL; + } + if (args_length == 1) { + Py_SETREF(res, PyNumber_Absolute(res)); + return res; + } + + PyObject *zero = _PyLong_GetZero(); // borrowed ref + for (i = 1; i < args_length; i++) { + x = PyNumber_Index(args[i]); + if (x == NULL) { + Py_DECREF(res); + return NULL; + } + if (res == zero) { + /* Fast path: just check arguments. + It is okay to use identity comparison here. */ + Py_DECREF(x); + continue; + } + Py_SETREF(res, long_lcm(res, x)); + Py_DECREF(x); + if (res == NULL) { + return NULL; + } + } + return res; +} + + +/* Integer square root + +Given a nonnegative integer `n`, we want to compute the largest integer +`a` for which `a * a <= n`, or equivalently the integer part of the exact +square root of `n`. + +We use an adaptive-precision pure-integer version of Newton's iteration. Given +a positive integer `n`, the algorithm produces at each iteration an integer +approximation `a` to the square root of `n >> s` for some even integer `s`, +with `s` decreasing as the iterations progress. On the final iteration, `s` is +zero and we have an approximation to the square root of `n` itself. + +At every step, the approximation `a` is strictly within 1.0 of the true square +root, so we have + + (a - 1)**2 < (n >> s) < (a + 1)**2 + +After the final iteration, a check-and-correct step is needed to determine +whether `a` or `a - 1` gives the desired integer square root of `n`. + +The algorithm is remarkable in its simplicity. There's no need for a +per-iteration check-and-correct step, and termination is straightforward: the +number of iterations is known in advance (it's exactly `floor(log2(log2(n)))` +for `n > 1`). The only tricky part of the correctness proof is in establishing +that the bound `(a - 1)**2 < (n >> s) < (a + 1)**2` is maintained from one +iteration to the next. A sketch of the proof of this is given below. + +In addition to the proof sketch, a formal, computer-verified proof +of correctness (using Lean) of an equivalent recursive algorithm can be found +here: + + https://github.com/mdickinson/snippets/blob/master/proofs/isqrt/src/isqrt.lean + + +Here's Python code equivalent to the C implementation below: + + def isqrt(n): + """ + Return the integer part of the square root of the input. + """ + n = operator.index(n) + + if n < 0: + raise ValueError("isqrt() argument must be nonnegative") + if n == 0: + return 0 + + c = (n.bit_length() - 1) // 2 + a = 1 + d = 0 + for s in reversed(range(c.bit_length())): + # Loop invariant: (a-1)**2 < (n >> 2*(c - d)) < (a+1)**2 + e = d + d = c >> s + a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a + + return a - (a*a > n) + + +Sketch of proof of correctness +------------------------------ + +The delicate part of the correctness proof is showing that the loop invariant +is preserved from one iteration to the next. That is, just before the line + + a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a + +is executed in the above code, we know that + + (1) (a - 1)**2 < (n >> 2*(c - e)) < (a + 1)**2. + +(since `e` is always the value of `d` from the previous iteration). We must +prove that after that line is executed, we have + + (a - 1)**2 < (n >> 2*(c - d)) < (a + 1)**2 + +To facilitate the proof, we make some changes of notation. Write `m` for +`n >> 2*(c-d)`, and write `b` for the new value of `a`, so + + b = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a + +or equivalently: + + (2) b = (a << d - e - 1) + (m >> d - e + 1) // a + +Then we can rewrite (1) as: + + (3) (a - 1)**2 < (m >> 2*(d - e)) < (a + 1)**2 + +and we must show that (b - 1)**2 < m < (b + 1)**2. + +From this point on, we switch to mathematical notation, so `/` means exact +division rather than integer division and `^` is used for exponentiation. We +use the `√` symbol for the exact square root. In (3), we can remove the +implicit floor operation to give: + + (4) (a - 1)^2 < m / 4^(d - e) < (a + 1)^2 + +Taking square roots throughout (4), scaling by `2^(d-e)`, and rearranging gives + + (5) 0 <= | 2^(d-e)a - √m | < 2^(d-e) + +Squaring and dividing through by `2^(d-e+1) a` gives + + (6) 0 <= 2^(d-e-1) a + m / (2^(d-e+1) a) - √m < 2^(d-e-1) / a + +We'll show below that `2^(d-e-1) <= a`. Given that, we can replace the +right-hand side of (6) with `1`, and now replacing the central +term `m / (2^(d-e+1) a)` with its floor in (6) gives + + (7) -1 < 2^(d-e-1) a + m // 2^(d-e+1) a - √m < 1 + +Or equivalently, from (2): + + (7) -1 < b - √m < 1 + +and rearranging gives that `(b-1)^2 < m < (b+1)^2`, which is what we needed +to prove. + +We're not quite done: we still have to prove the inequality `2^(d - e - 1) <= +a` that was used to get line (7) above. From the definition of `c`, we have +`4^c <= n`, which implies + + (8) 4^d <= m + +also, since `e == d >> 1`, `d` is at most `2e + 1`, from which it follows +that `2d - 2e - 1 <= d` and hence that + + (9) 4^(2d - 2e - 1) <= m + +Dividing both sides by `4^(d - e)` gives + + (10) 4^(d - e - 1) <= m / 4^(d - e) + +But we know from (4) that `m / 4^(d-e) < (a + 1)^2`, hence + + (11) 4^(d - e - 1) < (a + 1)^2 + +Now taking square roots of both sides and observing that both `2^(d-e-1)` and +`a` are integers gives `2^(d - e - 1) <= a`, which is what we needed. This +completes the proof sketch. + +*/ + +/* + The _approximate_isqrt_tab table provides approximate square roots for + 16-bit integers. For any n in the range 2**14 <= n < 2**16, the value + + a = _approximate_isqrt_tab[(n >> 8) - 64] + + is an approximate square root of n, satisfying (a - 1)**2 < n < (a + 1)**2. + + The table was computed in Python using the expression: + + [min(round(sqrt(256*n + 128)), 255) for n in range(64, 256)] +*/ + +static const uint8_t _approximate_isqrt_tab[192] = { + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, + 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 160, + 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169, + 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, + 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 186, 186, + 187, 188, 188, 189, 190, 190, 191, 192, 192, 193, 194, 194, + 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 201, 202, + 203, 203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 210, + 210, 211, 211, 212, 213, 213, 214, 214, 215, 216, 216, 217, + 217, 218, 219, 219, 220, 220, 221, 221, 222, 223, 223, 224, + 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, + 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 237, 237, + 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, + 250, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255, 255, +}; + +/* Approximate square root of a large 64-bit integer. + + Given `n` satisfying `2**62 <= n < 2**64`, return `a` + satisfying `(a - 1)**2 < n < (a + 1)**2`. */ + +static inline uint32_t +_approximate_isqrt(uint64_t n) +{ + uint32_t u = _approximate_isqrt_tab[(n >> 56) - 64]; + u = (u << 7) + (uint32_t)(n >> 41) / u; + return (u << 15) + (uint32_t)((n >> 17) / u); +} + +/*[clinic input] +math.integer.isqrt + + n: object + / + +Return the integer part of the square root of the input. +[clinic start generated code]*/ + +static PyObject * +math_integer_isqrt(PyObject *module, PyObject *n) +/*[clinic end generated code: output=551031e41a0f5d9e input=921ddd9853133d8d]*/ +{ + int a_too_large, c_bit_length; + int64_t c, d; + uint64_t m; + uint32_t u; + PyObject *a = NULL, *b; + + n = _PyNumber_Index(n); + if (n == NULL) { + return NULL; + } + + if (_PyLong_IsNegative((PyLongObject *)n)) { + PyErr_SetString( + PyExc_ValueError, + "isqrt() argument must be nonnegative"); + goto error; + } + if (_PyLong_IsZero((PyLongObject *)n)) { + Py_DECREF(n); + return PyLong_FromLong(0); + } + + /* c = (n.bit_length() - 1) // 2 */ + c = _PyLong_NumBits(n); + assert(c > 0); + assert(!PyErr_Occurred()); + c = (c - 1) / 2; + + /* Fast path: if c <= 31 then n < 2**64 and we can compute directly with a + fast, almost branch-free algorithm. */ + if (c <= 31) { + int shift = 31 - (int)c; + m = (uint64_t)PyLong_AsUnsignedLongLong(n); + Py_DECREF(n); + if (m == (uint64_t)(-1) && PyErr_Occurred()) { + return NULL; + } + u = _approximate_isqrt(m << 2*shift) >> shift; + u -= (uint64_t)u * u > m; + return PyLong_FromUnsignedLong(u); + } + + /* Slow path: n >= 2**64. We perform the first five iterations in C integer + arithmetic, then switch to using Python long integers. */ + + /* From n >= 2**64 it follows that c.bit_length() >= 6. */ + c_bit_length = 6; + while ((c >> c_bit_length) > 0) { + ++c_bit_length; + } + + /* Initialise d and a. */ + d = c >> (c_bit_length - 5); + b = _PyLong_Rshift(n, 2*c - 62); + if (b == NULL) { + goto error; + } + m = (uint64_t)PyLong_AsUnsignedLongLong(b); + Py_DECREF(b); + if (m == (uint64_t)(-1) && PyErr_Occurred()) { + goto error; + } + u = _approximate_isqrt(m) >> (31U - d); + a = PyLong_FromUnsignedLong(u); + if (a == NULL) { + goto error; + } + + for (int s = c_bit_length - 6; s >= 0; --s) { + PyObject *q; + int64_t e = d; + + d = c >> s; + + /* q = (n >> 2*c - e - d + 1) // a */ + q = _PyLong_Rshift(n, 2*c - d - e + 1); + if (q == NULL) { + goto error; + } + Py_SETREF(q, PyNumber_FloorDivide(q, a)); + if (q == NULL) { + goto error; + } + + /* a = (a << d - 1 - e) + q */ + Py_SETREF(a, _PyLong_Lshift(a, d - 1 - e)); + if (a == NULL) { + Py_DECREF(q); + goto error; + } + Py_SETREF(a, PyNumber_Add(a, q)); + Py_DECREF(q); + if (a == NULL) { + goto error; + } + } + + /* The correct result is either a or a - 1. Figure out which, and + decrement a if necessary. */ + + /* a_too_large = n < a * a */ + b = PyNumber_Multiply(a, a); + if (b == NULL) { + goto error; + } + a_too_large = PyObject_RichCompareBool(n, b, Py_LT); + Py_DECREF(b); + if (a_too_large == -1) { + goto error; + } + + if (a_too_large) { + Py_SETREF(a, PyNumber_Subtract(a, _PyLong_GetOne())); + } + Py_DECREF(n); + return a; + + error: + Py_XDECREF(a); + Py_DECREF(n); + return NULL; +} + + +static unsigned long +count_set_bits(unsigned long n) +{ + unsigned long count = 0; + while (n != 0) { + ++count; + n &= n - 1; /* clear least significant bit */ + } + return count; +} + + +/* Divide-and-conquer factorial algorithm + * + * Based on the formula and pseudo-code provided at: + * http://www.luschny.de/math/factorial/binarysplitfact.html + * + * Faster algorithms exist, but they're more complicated and depend on + * a fast prime factorization algorithm. + * + * Notes on the algorithm + * ---------------------- + * + * factorial(n) is written in the form 2**k * m, with m odd. k and m are + * computed separately, and then combined using a left shift. + * + * The function factorial_odd_part computes the odd part m (i.e., the greatest + * odd divisor) of factorial(n), using the formula: + * + * factorial_odd_part(n) = + * + * product_{i >= 0} product_{0 < j <= n / 2**i, j odd} j + * + * Example: factorial_odd_part(20) = + * + * (1) * + * (1) * + * (1 * 3 * 5) * + * (1 * 3 * 5 * 7 * 9) * + * (1 * 3 * 5 * 7 * 9 * 11 * 13 * 15 * 17 * 19) + * + * Here i goes from large to small: the first term corresponds to i=4 (any + * larger i gives an empty product), and the last term corresponds to i=0. + * Each term can be computed from the last by multiplying by the extra odd + * numbers required: e.g., to get from the penultimate term to the last one, + * we multiply by (11 * 13 * 15 * 17 * 19). + * + * To see a hint of why this formula works, here are the same numbers as above + * but with the even parts (i.e., the appropriate powers of 2) included. For + * each subterm in the product for i, we multiply that subterm by 2**i: + * + * factorial(20) = + * + * (16) * + * (8) * + * (4 * 12 * 20) * + * (2 * 6 * 10 * 14 * 18) * + * (1 * 3 * 5 * 7 * 9 * 11 * 13 * 15 * 17 * 19) + * + * The factorial_partial_product function computes the product of all odd j in + * range(start, stop) for given start and stop. It's used to compute the + * partial products like (11 * 13 * 15 * 17 * 19) in the example above. It + * operates recursively, repeatedly splitting the range into two roughly equal + * pieces until the subranges are small enough to be computed using only C + * integer arithmetic. + * + * The two-valuation k (i.e., the exponent of the largest power of 2 dividing + * the factorial) is computed independently in the main math_integer_factorial + * function. By standard results, its value is: + * + * two_valuation = n//2 + n//4 + n//8 + .... + * + * It can be shown (e.g., by complete induction on n) that two_valuation is + * equal to n - count_set_bits(n), where count_set_bits(n) gives the number of + * '1'-bits in the binary expansion of n. + */ + +/* factorial_partial_product: Compute product(range(start, stop, 2)) using + * divide and conquer. Assumes start and stop are odd and stop > start. + * max_bits must be >= bit_length(stop - 2). */ + +static PyObject * +factorial_partial_product(unsigned long start, unsigned long stop, + unsigned long max_bits) +{ + unsigned long midpoint, num_operands; + PyObject *left = NULL, *right = NULL, *result = NULL; + + /* If the return value will fit an unsigned long, then we can + * multiply in a tight, fast loop where each multiply is O(1). + * Compute an upper bound on the number of bits required to store + * the answer. + * + * Storing some integer z requires floor(lg(z))+1 bits, which is + * conveniently the value returned by bit_length(z). The + * product x*y will require at most + * bit_length(x) + bit_length(y) bits to store, based + * on the idea that lg product = lg x + lg y. + * + * We know that stop - 2 is the largest number to be multiplied. From + * there, we have: bit_length(answer) <= num_operands * + * bit_length(stop - 2) + */ + + num_operands = (stop - start) / 2; + /* The "num_operands <= 8 * SIZEOF_LONG" check guards against the + * unlikely case of an overflow in num_operands * max_bits. */ + if (num_operands <= 8 * SIZEOF_LONG && + num_operands * max_bits <= 8 * SIZEOF_LONG) { + unsigned long j, total; + for (total = start, j = start + 2; j < stop; j += 2) + total *= j; + return PyLong_FromUnsignedLong(total); + } + + /* find midpoint of range(start, stop), rounded up to next odd number. */ + midpoint = (start + num_operands) | 1; + left = factorial_partial_product(start, midpoint, + _Py_bit_length(midpoint - 2)); + if (left == NULL) + goto error; + right = factorial_partial_product(midpoint, stop, max_bits); + if (right == NULL) + goto error; + result = PyNumber_Multiply(left, right); + + error: + Py_XDECREF(left); + Py_XDECREF(right); + return result; +} + +/* factorial_odd_part: compute the odd part of factorial(n). */ + +static PyObject * +factorial_odd_part(unsigned long n) +{ + long i; + unsigned long v, lower, upper; + PyObject *partial, *tmp, *inner, *outer; + + inner = PyLong_FromLong(1); + if (inner == NULL) + return NULL; + outer = Py_NewRef(inner); + + upper = 3; + for (i = _Py_bit_length(n) - 2; i >= 0; i--) { + v = n >> i; + if (v <= 2) + continue; + lower = upper; + /* (v + 1) | 1 = least odd integer strictly larger than n / 2**i */ + upper = (v + 1) | 1; + /* Here inner is the product of all odd integers j in the range (0, + n/2**(i+1)]. The factorial_partial_product call below gives the + product of all odd integers j in the range (n/2**(i+1), n/2**i]. */ + partial = factorial_partial_product(lower, upper, _Py_bit_length(upper-2)); + /* inner *= partial */ + if (partial == NULL) + goto error; + tmp = PyNumber_Multiply(inner, partial); + Py_DECREF(partial); + if (tmp == NULL) + goto error; + Py_SETREF(inner, tmp); + /* Now inner is the product of all odd integers j in the range (0, + n/2**i], giving the inner product in the formula above. */ + + /* outer *= inner; */ + tmp = PyNumber_Multiply(outer, inner); + if (tmp == NULL) + goto error; + Py_SETREF(outer, tmp); + } + Py_DECREF(inner); + return outer; + + error: + Py_DECREF(outer); + Py_DECREF(inner); + return NULL; +} + + +/* Lookup table for small factorial values */ + +static const unsigned long SmallFactorials[] = { + 1, 1, 2, 6, 24, 120, 720, 5040, 40320, + 362880, 3628800, 39916800, 479001600, +#if SIZEOF_LONG >= 8 + 6227020800, 87178291200, 1307674368000, + 20922789888000, 355687428096000, 6402373705728000, + 121645100408832000, 2432902008176640000 +#endif +}; + +/*[clinic input] +math.integer.factorial + + n as arg: object + / + +Find n!. +[clinic start generated code]*/ + +static PyObject * +math_integer_factorial(PyObject *module, PyObject *arg) +/*[clinic end generated code: output=131c23fd48650414 input=742f4dfa490a1b07]*/ +{ + long x, two_valuation; + int overflow; + PyObject *result, *odd_part; + + x = PyLong_AsLongAndOverflow(arg, &overflow); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + else if (overflow == 1) { + PyErr_Format(PyExc_OverflowError, + "factorial() argument should not exceed %ld", + LONG_MAX); + return NULL; + } + else if (overflow == -1 || x < 0) { + PyErr_SetString(PyExc_ValueError, + "factorial() not defined for negative values"); + return NULL; + } + + /* use lookup table if x is small */ + if (x < (long)Py_ARRAY_LENGTH(SmallFactorials)) + return PyLong_FromUnsignedLong(SmallFactorials[x]); + + /* else express in the form odd_part * 2**two_valuation, and compute as + odd_part << two_valuation. */ + odd_part = factorial_odd_part(x); + if (odd_part == NULL) + return NULL; + two_valuation = x - count_set_bits(x); + result = _PyLong_Lshift(odd_part, two_valuation); + Py_DECREF(odd_part); + return result; +} + + +/* least significant 64 bits of the odd part of factorial(n), for n in range(128). + +Python code to generate the values: + + import math.integer + + for n in range(128): + fac = math.integer.factorial(n) + fac_odd_part = fac // (fac & -fac) + reduced_fac_odd_part = fac_odd_part % (2**64) + print(f"{reduced_fac_odd_part:#018x}u") +*/ +static const uint64_t reduced_factorial_odd_part[] = { + 0x0000000000000001u, 0x0000000000000001u, 0x0000000000000001u, 0x0000000000000003u, + 0x0000000000000003u, 0x000000000000000fu, 0x000000000000002du, 0x000000000000013bu, + 0x000000000000013bu, 0x0000000000000b13u, 0x000000000000375fu, 0x0000000000026115u, + 0x000000000007233fu, 0x00000000005cca33u, 0x0000000002898765u, 0x00000000260eeeebu, + 0x00000000260eeeebu, 0x0000000286fddd9bu, 0x00000016beecca73u, 0x000001b02b930689u, + 0x00000870d9df20adu, 0x0000b141df4dae31u, 0x00079dd498567c1bu, 0x00af2e19afc5266du, + 0x020d8a4d0f4f7347u, 0x335281867ec241efu, 0x9b3093d46fdd5923u, 0x5e1f9767cc5866b1u, + 0x92dd23d6966aced7u, 0xa30d0f4f0a196e5bu, 0x8dc3e5a1977d7755u, 0x2ab8ce915831734bu, + 0x2ab8ce915831734bu, 0x81d2a0bc5e5fdcabu, 0x9efcac82445da75bu, 0xbc8b95cf58cde171u, + 0xa0e8444a1f3cecf9u, 0x4191deb683ce3ffdu, 0xddd3878bc84ebfc7u, 0xcb39a64b83ff3751u, + 0xf8203f7993fc1495u, 0xbd2a2a78b35f4bddu, 0x84757be6b6d13921u, 0x3fbbcfc0b524988bu, + 0xbd11ed47c8928df9u, 0x3c26b59e41c2f4c5u, 0x677a5137e883fdb3u, 0xff74e943b03b93ddu, + 0xfe5ebbcb10b2bb97u, 0xb021f1de3235e7e7u, 0x33509eb2e743a58fu, 0x390f9da41279fb7du, + 0xe5cb0154f031c559u, 0x93074695ba4ddb6du, 0x81c471caa636247fu, 0xe1347289b5a1d749u, + 0x286f21c3f76ce2ffu, 0x00be84a2173e8ac7u, 0x1595065ca215b88bu, 0xf95877595b018809u, + 0x9c2efe3c5516f887u, 0x373294604679382bu, 0xaf1ff7a888adcd35u, 0x18ddf279a2c5800bu, + 0x18ddf279a2c5800bu, 0x505a90e2542582cbu, 0x5bacad2cd8d5dc2bu, 0xfe3152bcbff89f41u, + 0xe1467e88bf829351u, 0xb8001adb9e31b4d5u, 0x2803ac06a0cbb91fu, 0x1904b5d698805799u, + 0xe12a648b5c831461u, 0x3516abbd6160cfa9u, 0xac46d25f12fe036du, 0x78bfa1da906b00efu, + 0xf6390338b7f111bdu, 0x0f25f80f538255d9u, 0x4ec8ca55b8db140fu, 0x4ff670740b9b30a1u, + 0x8fd032443a07f325u, 0x80dfe7965c83eeb5u, 0xa3dc1714d1213afdu, 0x205b7bbfcdc62007u, + 0xa78126bbe140a093u, 0x9de1dc61ca7550cfu, 0x84f0046d01b492c5u, 0x2d91810b945de0f3u, + 0xf5408b7f6008aa71u, 0x43707f4863034149u, 0xdac65fb9679279d5u, 0xc48406e7d1114eb7u, + 0xa7dc9ed3c88e1271u, 0xfb25b2efdb9cb30du, 0x1bebda0951c4df63u, 0x5c85e975580ee5bdu, + 0x1591bc60082cb137u, 0x2c38606318ef25d7u, 0x76ca72f7c5c63e27u, 0xf04a75d17baa0915u, + 0x77458175139ae30du, 0x0e6c1330bc1b9421u, 0xdf87d2b5797e8293u, 0xefa5c703e1e68925u, + 0x2b6b1b3278b4f6e1u, 0xceee27b382394249u, 0xd74e3829f5dab91du, 0xfdb17989c26b5f1fu, + 0xc1b7d18781530845u, 0x7b4436b2105a8561u, 0x7ba7c0418372a7d7u, 0x9dbc5c67feb6c639u, + 0x502686d7f6ff6b8fu, 0x6101855406be7a1fu, 0x9956afb5806930e7u, 0xe1f0ee88af40f7c5u, + 0x984b057bda5c1151u, 0x9a49819acc13ea05u, 0x8ef0dead0896ef27u, 0x71f7826efe292b21u, + 0xad80a480e46986efu, 0x01cdc0ebf5e0c6f7u, 0x6e06f839968f68dbu, 0xdd5943ab56e76139u, + 0xcdcf31bf8604c5e7u, 0x7e2b4a847054a1cbu, 0x0ca75697a4d3d0f5u, 0x4703f53ac514a98bu, +}; + +/* inverses of reduced_factorial_odd_part values modulo 2**64. + +Python code to generate the values: + + import math.integer + + for n in range(128): + fac = math.integer.factorial(n) + fac_odd_part = fac // (fac & -fac) + inverted_fac_odd_part = pow(fac_odd_part, -1, 2**64) + print(f"{inverted_fac_odd_part:#018x}u") +*/ +static const uint64_t inverted_factorial_odd_part[] = { + 0x0000000000000001u, 0x0000000000000001u, 0x0000000000000001u, 0xaaaaaaaaaaaaaaabu, + 0xaaaaaaaaaaaaaaabu, 0xeeeeeeeeeeeeeeefu, 0x4fa4fa4fa4fa4fa5u, 0x2ff2ff2ff2ff2ff3u, + 0x2ff2ff2ff2ff2ff3u, 0x938cc70553e3771bu, 0xb71c27cddd93e49fu, 0xb38e3229fcdee63du, + 0xe684bb63544a4cbfu, 0xc2f684917ca340fbu, 0xf747c9cba417526du, 0xbb26eb51d7bd49c3u, + 0xbb26eb51d7bd49c3u, 0xb0a7efb985294093u, 0xbe4b8c69f259eabbu, 0x6854d17ed6dc4fb9u, + 0xe1aa904c915f4325u, 0x3b8206df131cead1u, 0x79c6009fea76fe13u, 0xd8c5d381633cd365u, + 0x4841f12b21144677u, 0x4a91ff68200b0d0fu, 0x8f9513a58c4f9e8bu, 0x2b3e690621a42251u, + 0x4f520f00e03c04e7u, 0x2edf84ee600211d3u, 0xadcaa2764aaacdfdu, 0x161f4f9033f4fe63u, + 0x161f4f9033f4fe63u, 0xbada2932ea4d3e03u, 0xcec189f3efaa30d3u, 0xf7475bb68330bf91u, + 0x37eb7bf7d5b01549u, 0x46b35660a4e91555u, 0xa567c12d81f151f7u, 0x4c724007bb2071b1u, + 0x0f4a0cce58a016bdu, 0xfa21068e66106475u, 0x244ab72b5a318ae1u, 0x366ce67e080d0f23u, + 0xd666fdae5dd2a449u, 0xd740ddd0acc06a0du, 0xb050bbbb28e6f97bu, 0x70b003fe890a5c75u, + 0xd03aabff83037427u, 0x13ec4ca72c783bd7u, 0x90282c06afdbd96fu, 0x4414ddb9db4a95d5u, + 0xa2c68735ae6832e9u, 0xbf72d71455676665u, 0xa8469fab6b759b7fu, 0xc1e55b56e606caf9u, + 0x40455630fc4a1cffu, 0x0120a7b0046d16f7u, 0xa7c3553b08faef23u, 0x9f0bfd1b08d48639u, + 0xa433ffce9a304d37u, 0xa22ad1d53915c683u, 0xcb6cbc723ba5dd1du, 0x547fb1b8ab9d0ba3u, + 0x547fb1b8ab9d0ba3u, 0x8f15a826498852e3u, 0x32e1a03f38880283u, 0x3de4cce63283f0c1u, + 0x5dfe6667e4da95b1u, 0xfda6eeeef479e47du, 0xf14de991cc7882dfu, 0xe68db79247630ca9u, + 0xa7d6db8207ee8fa1u, 0x255e1f0fcf034499u, 0xc9a8990e43dd7e65u, 0x3279b6f289702e0fu, + 0xe7b5905d9b71b195u, 0x03025ba41ff0da69u, 0xb7df3d6d3be55aefu, 0xf89b212ebff2b361u, + 0xfe856d095996f0adu, 0xd6e533e9fdf20f9du, 0xf8c0e84a63da3255u, 0xa677876cd91b4db7u, + 0x07ed4f97780d7d9bu, 0x90a8705f258db62fu, 0xa41bbb2be31b1c0du, 0x6ec28690b038383bu, + 0xdb860c3bb2edd691u, 0x0838286838a980f9u, 0x558417a74b36f77du, 0x71779afc3646ef07u, + 0x743cda377ccb6e91u, 0x7fdf9f3fe89153c5u, 0xdc97d25df49b9a4bu, 0x76321a778eb37d95u, + 0x7cbb5e27da3bd487u, 0x9cff4ade1a009de7u, 0x70eb166d05c15197u, 0xdcf0460b71d5fe3du, + 0x5ac1ee5260b6a3c5u, 0xc922dedfdd78efe1u, 0xe5d381dc3b8eeb9bu, 0xd57e5347bafc6aadu, + 0x86939040983acd21u, 0x395b9d69740a4ff9u, 0x1467299c8e43d135u, 0x5fe440fcad975cdfu, + 0xcaa9a39794a6ca8du, 0xf61dbd640868dea1u, 0xac09d98d74843be7u, 0x2b103b9e1a6b4809u, + 0x2ab92d16960f536fu, 0x6653323d5e3681dfu, 0xefd48c1c0624e2d7u, 0xa496fefe04816f0du, + 0x1754a7b07bbdd7b1u, 0x23353c829a3852cdu, 0xbf831261abd59097u, 0x57a8e656df0618e1u, + 0x16e9206c3100680fu, 0xadad4c6ee921dac7u, 0x635f2b3860265353u, 0xdd6d0059f44b3d09u, + 0xac4dd6b894447dd7u, 0x42ea183eeaa87be3u, 0x15612d1550ee5b5du, 0x226fa19d656cb623u, +}; + +/* exponent of the largest power of 2 dividing factorial(n), for n in range(68) + +Python code to generate the values: + +import math.integer + +for n in range(128): + fac = math.integer.factorial(n) + fac_trailing_zeros = (fac & -fac).bit_length() - 1 + print(fac_trailing_zeros) +*/ + +static const uint8_t factorial_trailing_zeros[] = { + 0, 0, 1, 1, 3, 3, 4, 4, 7, 7, 8, 8, 10, 10, 11, 11, // 0-15 + 15, 15, 16, 16, 18, 18, 19, 19, 22, 22, 23, 23, 25, 25, 26, 26, // 16-31 + 31, 31, 32, 32, 34, 34, 35, 35, 38, 38, 39, 39, 41, 41, 42, 42, // 32-47 + 46, 46, 47, 47, 49, 49, 50, 50, 53, 53, 54, 54, 56, 56, 57, 57, // 48-63 + 63, 63, 64, 64, 66, 66, 67, 67, 70, 70, 71, 71, 73, 73, 74, 74, // 64-79 + 78, 78, 79, 79, 81, 81, 82, 82, 85, 85, 86, 86, 88, 88, 89, 89, // 80-95 + 94, 94, 95, 95, 97, 97, 98, 98, 101, 101, 102, 102, 104, 104, 105, 105, // 96-111 + 109, 109, 110, 110, 112, 112, 113, 113, 116, 116, 117, 117, 119, 119, 120, 120, // 112-127 +}; + +/* Number of permutations and combinations. + * P(n, k) = n! / (n-k)! + * C(n, k) = P(n, k) / k! + */ + +/* Calculate C(n, k) for n in the 63-bit range. */ +static PyObject * +perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) +{ + assert(k != 0); + + /* For small enough n and k the result fits in the 64-bit range and can + * be calculated without allocating intermediate PyLong objects. */ + if (iscomb) { + /* Maps k to the maximal n so that 2*k-1 <= n <= 127 and C(n, k) + * fits into a uint64_t. Exclude k = 1, because the second fast + * path is faster for this case.*/ + static const unsigned char fast_comb_limits1[] = { + 0, 0, 127, 127, 127, 127, 127, 127, // 0-7 + 127, 127, 127, 127, 127, 127, 127, 127, // 8-15 + 116, 105, 97, 91, 86, 82, 78, 76, // 16-23 + 74, 72, 71, 70, 69, 68, 68, 67, // 24-31 + 67, 67, 67, // 32-34 + }; + if (k < Py_ARRAY_LENGTH(fast_comb_limits1) && n <= fast_comb_limits1[k]) { + /* + comb(n, k) fits into a uint64_t. We compute it as + + comb_odd_part << shift + + where 2**shift is the largest power of two dividing comb(n, k) + and comb_odd_part is comb(n, k) >> shift. comb_odd_part can be + calculated efficiently via arithmetic modulo 2**64, using three + lookups and two uint64_t multiplications. + */ + uint64_t comb_odd_part = reduced_factorial_odd_part[n] + * inverted_factorial_odd_part[k] + * inverted_factorial_odd_part[n - k]; + int shift = factorial_trailing_zeros[n] + - factorial_trailing_zeros[k] + - factorial_trailing_zeros[n - k]; + return PyLong_FromUnsignedLongLong(comb_odd_part << shift); + } + + /* Maps k to the maximal n so that 2*k-1 <= n <= 127 and C(n, k)*k + * fits into a long long (which is at least 64 bit). Only contains + * items larger than in fast_comb_limits1. */ + static const unsigned long long fast_comb_limits2[] = { + 0, ULLONG_MAX, 4294967296ULL, 3329022, 102570, 13467, 3612, 1449, // 0-7 + 746, 453, 308, 227, 178, 147, // 8-13 + }; + if (k < Py_ARRAY_LENGTH(fast_comb_limits2) && n <= fast_comb_limits2[k]) { + /* C(n, k) = C(n, k-1) * (n-k+1) / k */ + unsigned long long result = n; + for (unsigned long long i = 1; i < k;) { + result *= --n; + result /= ++i; + } + return PyLong_FromUnsignedLongLong(result); + } + } + else { + /* Maps k to the maximal n so that k <= n and P(n, k) + * fits into a long long (which is at least 64 bit). */ + static const unsigned long long fast_perm_limits[] = { + 0, ULLONG_MAX, 4294967296ULL, 2642246, 65537, 7133, 1627, 568, // 0-7 + 259, 142, 88, 61, 45, 36, 30, 26, // 8-15 + 24, 22, 21, 20, 20, // 16-20 + }; + if (k < Py_ARRAY_LENGTH(fast_perm_limits) && n <= fast_perm_limits[k]) { + if (n <= 127) { + /* P(n, k) fits into a uint64_t. */ + uint64_t perm_odd_part = reduced_factorial_odd_part[n] + * inverted_factorial_odd_part[n - k]; + int shift = factorial_trailing_zeros[n] + - factorial_trailing_zeros[n - k]; + return PyLong_FromUnsignedLongLong(perm_odd_part << shift); + } + + /* P(n, k) = P(n, k-1) * (n-k+1) */ + unsigned long long result = n; + for (unsigned long long i = 1; i < k;) { + result *= --n; + ++i; + } + return PyLong_FromUnsignedLongLong(result); + } + } + + /* For larger n use recursive formulas: + * + * P(n, k) = P(n, j) * P(n-j, k-j) + * C(n, k) = C(n, j) * C(n-j, k-j) // C(k, j) + */ + unsigned long long j = k / 2; + PyObject *a, *b; + a = perm_comb_small(n, j, iscomb); + if (a == NULL) { + return NULL; + } + b = perm_comb_small(n - j, k - j, iscomb); + if (b == NULL) { + goto error; + } + Py_SETREF(a, PyNumber_Multiply(a, b)); + Py_DECREF(b); + if (iscomb && a != NULL) { + b = perm_comb_small(k, j, 1); + if (b == NULL) { + goto error; + } + Py_SETREF(a, PyNumber_FloorDivide(a, b)); + Py_DECREF(b); + } + return a; + +error: + Py_DECREF(a); + return NULL; +} + +/* Calculate P(n, k) or C(n, k) using recursive formulas. + * It is more efficient than sequential multiplication thanks to + * Karatsuba multiplication. + */ +static PyObject * +perm_comb(PyObject *n, unsigned long long k, int iscomb) +{ + if (k == 0) { + return PyLong_FromLong(1); + } + if (k == 1) { + return Py_NewRef(n); + } + + /* P(n, k) = P(n, j) * P(n-j, k-j) */ + /* C(n, k) = C(n, j) * C(n-j, k-j) // C(k, j) */ + unsigned long long j = k / 2; + PyObject *a, *b; + a = perm_comb(n, j, iscomb); + if (a == NULL) { + return NULL; + } + PyObject *t = PyLong_FromUnsignedLongLong(j); + if (t == NULL) { + goto error; + } + n = PyNumber_Subtract(n, t); + Py_DECREF(t); + if (n == NULL) { + goto error; + } + b = perm_comb(n, k - j, iscomb); + Py_DECREF(n); + if (b == NULL) { + goto error; + } + Py_SETREF(a, PyNumber_Multiply(a, b)); + Py_DECREF(b); + if (iscomb && a != NULL) { + b = perm_comb_small(k, j, 1); + if (b == NULL) { + goto error; + } + Py_SETREF(a, PyNumber_FloorDivide(a, b)); + Py_DECREF(b); + } + return a; + +error: + Py_DECREF(a); + return NULL; +} + +/*[clinic input] +@permit_long_summary +math.integer.perm + + n: object + k: object = None + / + +Number of ways to choose k items from n items without repetition and with order. + +Evaluates to n! / (n - k)! when k <= n and evaluates +to zero when k > n. + +If k is not specified or is None, then k defaults to n +and the function returns n!. + +Raises ValueError if either of the arguments are negative. +[clinic start generated code]*/ + +static PyObject * +math_integer_perm_impl(PyObject *module, PyObject *n, PyObject *k) +/*[clinic end generated code: output=9f9b96cd73a94de4 input=fd627e5a09dd5116]*/ +{ + PyObject *result = NULL; + int overflow, cmp; + long long ki, ni; + + if (k == Py_None) { + return math_integer_factorial(module, n); + } + n = PyNumber_Index(n); + if (n == NULL) { + return NULL; + } + k = PyNumber_Index(k); + if (k == NULL) { + Py_DECREF(n); + return NULL; + } + assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); + + if (_PyLong_IsNegative((PyLongObject *)n)) { + PyErr_SetString(PyExc_ValueError, + "n must be a non-negative integer"); + goto error; + } + if (_PyLong_IsNegative((PyLongObject *)k)) { + PyErr_SetString(PyExc_ValueError, + "k must be a non-negative integer"); + goto error; + } + + cmp = PyObject_RichCompareBool(n, k, Py_LT); + if (cmp != 0) { + if (cmp > 0) { + result = PyLong_FromLong(0); + goto done; + } + goto error; + } + + ki = PyLong_AsLongLongAndOverflow(k, &overflow); + assert(overflow >= 0 && !PyErr_Occurred()); + if (overflow > 0) { + PyErr_Format(PyExc_OverflowError, + "k must not exceed %lld", + LLONG_MAX); + goto error; + } + assert(ki >= 0); + + ni = PyLong_AsLongLongAndOverflow(n, &overflow); + assert(overflow >= 0 && !PyErr_Occurred()); + if (!overflow && ki > 1) { + assert(ni >= 0); + result = perm_comb_small((unsigned long long)ni, + (unsigned long long)ki, 0); + } + else { + result = perm_comb(n, (unsigned long long)ki, 0); + } + +done: + Py_DECREF(n); + Py_DECREF(k); + return result; + +error: + Py_DECREF(n); + Py_DECREF(k); + return NULL; +} + +/*[clinic input] +@permit_long_summary +math.integer.comb + + n: object + k: object + / + +Number of ways to choose k items from n items without repetition and without order. + +Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates +to zero when k > n. + +Also called the binomial coefficient because it is equivalent +to the coefficient of k-th term in polynomial expansion of the +expression (1 + x)**n. + +Raises ValueError if either of the arguments are negative. +[clinic start generated code]*/ + +static PyObject * +math_integer_comb_impl(PyObject *module, PyObject *n, PyObject *k) +/*[clinic end generated code: output=c2c9cdfe0d5dd43f input=8cc12726b682c4a5]*/ +{ + PyObject *result = NULL, *temp; + int overflow, cmp; + long long ki, ni; + + n = PyNumber_Index(n); + if (n == NULL) { + return NULL; + } + k = PyNumber_Index(k); + if (k == NULL) { + Py_DECREF(n); + return NULL; + } + assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); + + if (_PyLong_IsNegative((PyLongObject *)n)) { + PyErr_SetString(PyExc_ValueError, + "n must be a non-negative integer"); + goto error; + } + if (_PyLong_IsNegative((PyLongObject *)k)) { + PyErr_SetString(PyExc_ValueError, + "k must be a non-negative integer"); + goto error; + } + + ni = PyLong_AsLongLongAndOverflow(n, &overflow); + assert(overflow >= 0 && !PyErr_Occurred()); + if (!overflow) { + assert(ni >= 0); + ki = PyLong_AsLongLongAndOverflow(k, &overflow); + assert(overflow >= 0 && !PyErr_Occurred()); + if (overflow || ki > ni) { + result = PyLong_FromLong(0); + goto done; + } + assert(ki >= 0); + + ki = Py_MIN(ki, ni - ki); + if (ki > 1) { + result = perm_comb_small((unsigned long long)ni, + (unsigned long long)ki, 1); + goto done; + } + /* For k == 1 just return the original n in perm_comb(). */ + } + else { + /* k = min(k, n - k) */ + temp = PyNumber_Subtract(n, k); + if (temp == NULL) { + goto error; + } + assert(PyLong_Check(temp)); + if (_PyLong_IsNegative((PyLongObject *)temp)) { + Py_DECREF(temp); + result = PyLong_FromLong(0); + goto done; + } + cmp = PyObject_RichCompareBool(temp, k, Py_LT); + if (cmp > 0) { + Py_SETREF(k, temp); + } + else { + Py_DECREF(temp); + if (cmp < 0) { + goto error; + } + } + + ki = PyLong_AsLongLongAndOverflow(k, &overflow); + assert(overflow >= 0 && !PyErr_Occurred()); + if (overflow) { + PyErr_Format(PyExc_OverflowError, + "min(n - k, k) must not exceed %lld", + LLONG_MAX); + goto error; + } + assert(ki >= 0); + } + + result = perm_comb(n, (unsigned long long)ki, 1); + +done: + Py_DECREF(n); + Py_DECREF(k); + return result; + +error: + Py_DECREF(n); + Py_DECREF(k); + return NULL; +} + + +static PyMethodDef math_integer_methods[] = { + MATH_INTEGER_COMB_METHODDEF + MATH_INTEGER_FACTORIAL_METHODDEF + MATH_INTEGER_GCD_METHODDEF + MATH_INTEGER_ISQRT_METHODDEF + MATH_INTEGER_LCM_METHODDEF + MATH_INTEGER_PERM_METHODDEF + {NULL, NULL} /* sentinel */ +}; + +static int +math_integer_exec(PyObject *module) +{ + /* Fix the __name__ attribute of the module and the __module__ attribute + * of its functions. + */ + PyObject *name = PyUnicode_FromString("math.integer"); + if (name == NULL) { + return -1; + } + if (PyObject_SetAttrString(module, "__name__", name) < 0) { + Py_DECREF(name); + return -1; + } + for (const PyMethodDef *m = math_integer_methods; m->ml_name; m++) { + PyObject *obj = PyObject_GetAttrString(module, m->ml_name); + if (obj == NULL) { + Py_DECREF(name); + return -1; + } + if (PyObject_SetAttrString(obj, "__module__", name) < 0) { + Py_DECREF(name); + Py_DECREF(obj); + return -1; + } + Py_DECREF(obj); + } + Py_DECREF(name); + return 0; +} + +static PyModuleDef_Slot math_integer_slots[] = { + {Py_mod_exec, math_integer_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL} +}; + +PyDoc_STRVAR(module_doc, +"This module provides access to integer related mathematical functions."); + +static struct PyModuleDef math_integer_module = { + PyModuleDef_HEAD_INIT, + .m_name = "math.integer", + .m_doc = module_doc, + .m_size = 0, + .m_methods = math_integer_methods, + .m_slots = math_integer_slots, +}; + +PyMODINIT_FUNC +PyInit__math_integer(void) +{ + return PyModuleDef_Init(&math_integer_module); +} diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index c631beb9ce5..11c46c987e1 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -60,6 +60,7 @@ raised for division by zero and mod by zero. #include "pycore_abstract.h" // _PyNumber_Index() #include "pycore_bitutils.h" // _Py_bit_length() #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_import.h" // _PyImport_SetModuleString() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_object.h" // _PyObject_LookupSpecial() @@ -394,7 +395,7 @@ m_tgamma(double x) if (x == 0.0) { errno = EDOM; /* tgamma(+-0.0) = +-inf, divide-by-zero */ - return copysign(Py_INFINITY, x); + return copysign(INFINITY, x); } /* integer arguments */ @@ -425,7 +426,7 @@ m_tgamma(double x) } else { errno = ERANGE; - return Py_INFINITY; + return INFINITY; } } @@ -489,14 +490,14 @@ m_lgamma(double x) if (isnan(x)) return x; /* lgamma(nan) = nan */ else - return Py_INFINITY; /* lgamma(+-inf) = +inf */ + return INFINITY; /* lgamma(+-inf) = +inf */ } /* integer arguments */ if (x == floor(x) && x <= 2.0) { if (x <= 0.0) { errno = EDOM; /* lgamma(n) = inf, divide-by-zero for */ - return Py_INFINITY; /* integers n <= 0 */ + return INFINITY; /* integers n <= 0 */ } else { return 0.0; /* lgamma(1) = lgamma(2) = 0.0 */ @@ -632,7 +633,7 @@ m_log(double x) return log(x); errno = EDOM; if (x == 0.0) - return -Py_INFINITY; /* log(0) = -inf */ + return -INFINITY; /* log(0) = -inf */ else return Py_NAN; /* log(-ve) = nan */ } @@ -675,7 +676,7 @@ m_log2(double x) } else if (x == 0.0) { errno = EDOM; - return -Py_INFINITY; /* log2(0) = -inf, divide-by-zero */ + return -INFINITY; /* log2(0) = -inf, divide-by-zero */ } else { errno = EDOM; @@ -691,7 +692,7 @@ m_log10(double x) return log10(x); errno = EDOM; if (x == 0.0) - return -Py_INFINITY; /* log10(0) = -inf */ + return -INFINITY; /* log10(0) = -inf */ else return Py_NAN; /* log10(-ve) = nan */ } @@ -706,140 +707,6 @@ m_log10(double x) } -/*[clinic input] -math.gcd - - *integers as args: array - -Greatest Common Divisor. -[clinic start generated code]*/ - -static PyObject * -math_gcd_impl(PyObject *module, PyObject * const *args, - Py_ssize_t args_length) -/*[clinic end generated code: output=a26c95907374ffb4 input=ded7f0ea3850c05c]*/ -{ - // Fast-path for the common case: gcd(int, int) - if (args_length == 2 && PyLong_CheckExact(args[0]) && PyLong_CheckExact(args[1])) - { - return _PyLong_GCD(args[0], args[1]); - } - - if (args_length == 0) { - return PyLong_FromLong(0); - } - - PyObject *res = PyNumber_Index(args[0]); - if (res == NULL) { - return NULL; - } - if (args_length == 1) { - Py_SETREF(res, PyNumber_Absolute(res)); - return res; - } - - PyObject *one = _PyLong_GetOne(); // borrowed ref - for (Py_ssize_t i = 1; i < args_length; i++) { - PyObject *x = _PyNumber_Index(args[i]); - if (x == NULL) { - Py_DECREF(res); - return NULL; - } - if (res == one) { - /* Fast path: just check arguments. - It is okay to use identity comparison here. */ - Py_DECREF(x); - continue; - } - Py_SETREF(res, _PyLong_GCD(res, x)); - Py_DECREF(x); - if (res == NULL) { - return NULL; - } - } - return res; -} - - -static PyObject * -long_lcm(PyObject *a, PyObject *b) -{ - PyObject *g, *m, *f, *ab; - - if (_PyLong_IsZero((PyLongObject *)a) || _PyLong_IsZero((PyLongObject *)b)) { - return PyLong_FromLong(0); - } - g = _PyLong_GCD(a, b); - if (g == NULL) { - return NULL; - } - f = PyNumber_FloorDivide(a, g); - Py_DECREF(g); - if (f == NULL) { - return NULL; - } - m = PyNumber_Multiply(f, b); - Py_DECREF(f); - if (m == NULL) { - return NULL; - } - ab = PyNumber_Absolute(m); - Py_DECREF(m); - return ab; -} - - -/*[clinic input] -math.lcm - - *integers as args: array - -Least Common Multiple. -[clinic start generated code]*/ - -static PyObject * -math_lcm_impl(PyObject *module, PyObject * const *args, - Py_ssize_t args_length) -/*[clinic end generated code: output=c8a59a5c2e55c816 input=3e4f4b7cdf948a98]*/ -{ - PyObject *res, *x; - Py_ssize_t i; - - if (args_length == 0) { - return PyLong_FromLong(1); - } - res = PyNumber_Index(args[0]); - if (res == NULL) { - return NULL; - } - if (args_length == 1) { - Py_SETREF(res, PyNumber_Absolute(res)); - return res; - } - - PyObject *zero = _PyLong_GetZero(); // borrowed ref - for (i = 1; i < args_length; i++) { - x = PyNumber_Index(args[i]); - if (x == NULL) { - Py_DECREF(res); - return NULL; - } - if (res == zero) { - /* Fast path: just check arguments. - It is okay to use identity comparison here. */ - Py_DECREF(x); - continue; - } - Py_SETREF(res, long_lcm(res, x)); - Py_DECREF(x); - if (res == NULL) { - return NULL; - } - } - return res; -} - - /* Call is_error when errno != 0, and where x is the result libm * returned. is_error will usually set up an exception and return * true (1), but may return false (0) without setting up an exception. @@ -1531,576 +1398,6 @@ math_fsum(PyObject *module, PyObject *seq) #undef NUM_PARTIALS -static unsigned long -count_set_bits(unsigned long n) -{ - unsigned long count = 0; - while (n != 0) { - ++count; - n &= n - 1; /* clear least significant bit */ - } - return count; -} - -/* Integer square root - -Given a nonnegative integer `n`, we want to compute the largest integer -`a` for which `a * a <= n`, or equivalently the integer part of the exact -square root of `n`. - -We use an adaptive-precision pure-integer version of Newton's iteration. Given -a positive integer `n`, the algorithm produces at each iteration an integer -approximation `a` to the square root of `n >> s` for some even integer `s`, -with `s` decreasing as the iterations progress. On the final iteration, `s` is -zero and we have an approximation to the square root of `n` itself. - -At every step, the approximation `a` is strictly within 1.0 of the true square -root, so we have - - (a - 1)**2 < (n >> s) < (a + 1)**2 - -After the final iteration, a check-and-correct step is needed to determine -whether `a` or `a - 1` gives the desired integer square root of `n`. - -The algorithm is remarkable in its simplicity. There's no need for a -per-iteration check-and-correct step, and termination is straightforward: the -number of iterations is known in advance (it's exactly `floor(log2(log2(n)))` -for `n > 1`). The only tricky part of the correctness proof is in establishing -that the bound `(a - 1)**2 < (n >> s) < (a + 1)**2` is maintained from one -iteration to the next. A sketch of the proof of this is given below. - -In addition to the proof sketch, a formal, computer-verified proof -of correctness (using Lean) of an equivalent recursive algorithm can be found -here: - - https://github.com/mdickinson/snippets/blob/master/proofs/isqrt/src/isqrt.lean - - -Here's Python code equivalent to the C implementation below: - - def isqrt(n): - """ - Return the integer part of the square root of the input. - """ - n = operator.index(n) - - if n < 0: - raise ValueError("isqrt() argument must be nonnegative") - if n == 0: - return 0 - - c = (n.bit_length() - 1) // 2 - a = 1 - d = 0 - for s in reversed(range(c.bit_length())): - # Loop invariant: (a-1)**2 < (n >> 2*(c - d)) < (a+1)**2 - e = d - d = c >> s - a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a - - return a - (a*a > n) - - -Sketch of proof of correctness ------------------------------- - -The delicate part of the correctness proof is showing that the loop invariant -is preserved from one iteration to the next. That is, just before the line - - a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a - -is executed in the above code, we know that - - (1) (a - 1)**2 < (n >> 2*(c - e)) < (a + 1)**2. - -(since `e` is always the value of `d` from the previous iteration). We must -prove that after that line is executed, we have - - (a - 1)**2 < (n >> 2*(c - d)) < (a + 1)**2 - -To facilitate the proof, we make some changes of notation. Write `m` for -`n >> 2*(c-d)`, and write `b` for the new value of `a`, so - - b = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a - -or equivalently: - - (2) b = (a << d - e - 1) + (m >> d - e + 1) // a - -Then we can rewrite (1) as: - - (3) (a - 1)**2 < (m >> 2*(d - e)) < (a + 1)**2 - -and we must show that (b - 1)**2 < m < (b + 1)**2. - -From this point on, we switch to mathematical notation, so `/` means exact -division rather than integer division and `^` is used for exponentiation. We -use the `√` symbol for the exact square root. In (3), we can remove the -implicit floor operation to give: - - (4) (a - 1)^2 < m / 4^(d - e) < (a + 1)^2 - -Taking square roots throughout (4), scaling by `2^(d-e)`, and rearranging gives - - (5) 0 <= | 2^(d-e)a - √m | < 2^(d-e) - -Squaring and dividing through by `2^(d-e+1) a` gives - - (6) 0 <= 2^(d-e-1) a + m / (2^(d-e+1) a) - √m < 2^(d-e-1) / a - -We'll show below that `2^(d-e-1) <= a`. Given that, we can replace the -right-hand side of (6) with `1`, and now replacing the central -term `m / (2^(d-e+1) a)` with its floor in (6) gives - - (7) -1 < 2^(d-e-1) a + m // 2^(d-e+1) a - √m < 1 - -Or equivalently, from (2): - - (7) -1 < b - √m < 1 - -and rearranging gives that `(b-1)^2 < m < (b+1)^2`, which is what we needed -to prove. - -We're not quite done: we still have to prove the inequality `2^(d - e - 1) <= -a` that was used to get line (7) above. From the definition of `c`, we have -`4^c <= n`, which implies - - (8) 4^d <= m - -also, since `e == d >> 1`, `d` is at most `2e + 1`, from which it follows -that `2d - 2e - 1 <= d` and hence that - - (9) 4^(2d - 2e - 1) <= m - -Dividing both sides by `4^(d - e)` gives - - (10) 4^(d - e - 1) <= m / 4^(d - e) - -But we know from (4) that `m / 4^(d-e) < (a + 1)^2`, hence - - (11) 4^(d - e - 1) < (a + 1)^2 - -Now taking square roots of both sides and observing that both `2^(d-e-1)` and -`a` are integers gives `2^(d - e - 1) <= a`, which is what we needed. This -completes the proof sketch. - -*/ - -/* - The _approximate_isqrt_tab table provides approximate square roots for - 16-bit integers. For any n in the range 2**14 <= n < 2**16, the value - - a = _approximate_isqrt_tab[(n >> 8) - 64] - - is an approximate square root of n, satisfying (a - 1)**2 < n < (a + 1)**2. - - The table was computed in Python using the expression: - - [min(round(sqrt(256*n + 128)), 255) for n in range(64, 256)] -*/ - -static const uint8_t _approximate_isqrt_tab[192] = { - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, - 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 160, - 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169, - 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, - 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 186, 186, - 187, 188, 188, 189, 190, 190, 191, 192, 192, 193, 194, 194, - 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 201, 202, - 203, 203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 210, - 210, 211, 211, 212, 213, 213, 214, 214, 215, 216, 216, 217, - 217, 218, 219, 219, 220, 220, 221, 221, 222, 223, 223, 224, - 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, - 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 237, 237, - 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, - 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, - 250, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255, 255, -}; - -/* Approximate square root of a large 64-bit integer. - - Given `n` satisfying `2**62 <= n < 2**64`, return `a` - satisfying `(a - 1)**2 < n < (a + 1)**2`. */ - -static inline uint32_t -_approximate_isqrt(uint64_t n) -{ - uint32_t u = _approximate_isqrt_tab[(n >> 56) - 64]; - u = (u << 7) + (uint32_t)(n >> 41) / u; - return (u << 15) + (uint32_t)((n >> 17) / u); -} - -/*[clinic input] -math.isqrt - - n: object - / - -Return the integer part of the square root of the input. -[clinic start generated code]*/ - -static PyObject * -math_isqrt(PyObject *module, PyObject *n) -/*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/ -{ - int a_too_large, c_bit_length; - int64_t c, d; - uint64_t m; - uint32_t u; - PyObject *a = NULL, *b; - - n = _PyNumber_Index(n); - if (n == NULL) { - return NULL; - } - - if (_PyLong_IsNegative((PyLongObject *)n)) { - PyErr_SetString( - PyExc_ValueError, - "isqrt() argument must be nonnegative"); - goto error; - } - if (_PyLong_IsZero((PyLongObject *)n)) { - Py_DECREF(n); - return PyLong_FromLong(0); - } - - /* c = (n.bit_length() - 1) // 2 */ - c = _PyLong_NumBits(n); - assert(c > 0); - assert(!PyErr_Occurred()); - c = (c - 1) / 2; - - /* Fast path: if c <= 31 then n < 2**64 and we can compute directly with a - fast, almost branch-free algorithm. */ - if (c <= 31) { - int shift = 31 - (int)c; - m = (uint64_t)PyLong_AsUnsignedLongLong(n); - Py_DECREF(n); - if (m == (uint64_t)(-1) && PyErr_Occurred()) { - return NULL; - } - u = _approximate_isqrt(m << 2*shift) >> shift; - u -= (uint64_t)u * u > m; - return PyLong_FromUnsignedLong(u); - } - - /* Slow path: n >= 2**64. We perform the first five iterations in C integer - arithmetic, then switch to using Python long integers. */ - - /* From n >= 2**64 it follows that c.bit_length() >= 6. */ - c_bit_length = 6; - while ((c >> c_bit_length) > 0) { - ++c_bit_length; - } - - /* Initialise d and a. */ - d = c >> (c_bit_length - 5); - b = _PyLong_Rshift(n, 2*c - 62); - if (b == NULL) { - goto error; - } - m = (uint64_t)PyLong_AsUnsignedLongLong(b); - Py_DECREF(b); - if (m == (uint64_t)(-1) && PyErr_Occurred()) { - goto error; - } - u = _approximate_isqrt(m) >> (31U - d); - a = PyLong_FromUnsignedLong(u); - if (a == NULL) { - goto error; - } - - for (int s = c_bit_length - 6; s >= 0; --s) { - PyObject *q; - int64_t e = d; - - d = c >> s; - - /* q = (n >> 2*c - e - d + 1) // a */ - q = _PyLong_Rshift(n, 2*c - d - e + 1); - if (q == NULL) { - goto error; - } - Py_SETREF(q, PyNumber_FloorDivide(q, a)); - if (q == NULL) { - goto error; - } - - /* a = (a << d - 1 - e) + q */ - Py_SETREF(a, _PyLong_Lshift(a, d - 1 - e)); - if (a == NULL) { - Py_DECREF(q); - goto error; - } - Py_SETREF(a, PyNumber_Add(a, q)); - Py_DECREF(q); - if (a == NULL) { - goto error; - } - } - - /* The correct result is either a or a - 1. Figure out which, and - decrement a if necessary. */ - - /* a_too_large = n < a * a */ - b = PyNumber_Multiply(a, a); - if (b == NULL) { - goto error; - } - a_too_large = PyObject_RichCompareBool(n, b, Py_LT); - Py_DECREF(b); - if (a_too_large == -1) { - goto error; - } - - if (a_too_large) { - Py_SETREF(a, PyNumber_Subtract(a, _PyLong_GetOne())); - } - Py_DECREF(n); - return a; - - error: - Py_XDECREF(a); - Py_DECREF(n); - return NULL; -} - -/* Divide-and-conquer factorial algorithm - * - * Based on the formula and pseudo-code provided at: - * http://www.luschny.de/math/factorial/binarysplitfact.html - * - * Faster algorithms exist, but they're more complicated and depend on - * a fast prime factorization algorithm. - * - * Notes on the algorithm - * ---------------------- - * - * factorial(n) is written in the form 2**k * m, with m odd. k and m are - * computed separately, and then combined using a left shift. - * - * The function factorial_odd_part computes the odd part m (i.e., the greatest - * odd divisor) of factorial(n), using the formula: - * - * factorial_odd_part(n) = - * - * product_{i >= 0} product_{0 < j <= n / 2**i, j odd} j - * - * Example: factorial_odd_part(20) = - * - * (1) * - * (1) * - * (1 * 3 * 5) * - * (1 * 3 * 5 * 7 * 9) * - * (1 * 3 * 5 * 7 * 9 * 11 * 13 * 15 * 17 * 19) - * - * Here i goes from large to small: the first term corresponds to i=4 (any - * larger i gives an empty product), and the last term corresponds to i=0. - * Each term can be computed from the last by multiplying by the extra odd - * numbers required: e.g., to get from the penultimate term to the last one, - * we multiply by (11 * 13 * 15 * 17 * 19). - * - * To see a hint of why this formula works, here are the same numbers as above - * but with the even parts (i.e., the appropriate powers of 2) included. For - * each subterm in the product for i, we multiply that subterm by 2**i: - * - * factorial(20) = - * - * (16) * - * (8) * - * (4 * 12 * 20) * - * (2 * 6 * 10 * 14 * 18) * - * (1 * 3 * 5 * 7 * 9 * 11 * 13 * 15 * 17 * 19) - * - * The factorial_partial_product function computes the product of all odd j in - * range(start, stop) for given start and stop. It's used to compute the - * partial products like (11 * 13 * 15 * 17 * 19) in the example above. It - * operates recursively, repeatedly splitting the range into two roughly equal - * pieces until the subranges are small enough to be computed using only C - * integer arithmetic. - * - * The two-valuation k (i.e., the exponent of the largest power of 2 dividing - * the factorial) is computed independently in the main math_factorial - * function. By standard results, its value is: - * - * two_valuation = n//2 + n//4 + n//8 + .... - * - * It can be shown (e.g., by complete induction on n) that two_valuation is - * equal to n - count_set_bits(n), where count_set_bits(n) gives the number of - * '1'-bits in the binary expansion of n. - */ - -/* factorial_partial_product: Compute product(range(start, stop, 2)) using - * divide and conquer. Assumes start and stop are odd and stop > start. - * max_bits must be >= bit_length(stop - 2). */ - -static PyObject * -factorial_partial_product(unsigned long start, unsigned long stop, - unsigned long max_bits) -{ - unsigned long midpoint, num_operands; - PyObject *left = NULL, *right = NULL, *result = NULL; - - /* If the return value will fit an unsigned long, then we can - * multiply in a tight, fast loop where each multiply is O(1). - * Compute an upper bound on the number of bits required to store - * the answer. - * - * Storing some integer z requires floor(lg(z))+1 bits, which is - * conveniently the value returned by bit_length(z). The - * product x*y will require at most - * bit_length(x) + bit_length(y) bits to store, based - * on the idea that lg product = lg x + lg y. - * - * We know that stop - 2 is the largest number to be multiplied. From - * there, we have: bit_length(answer) <= num_operands * - * bit_length(stop - 2) - */ - - num_operands = (stop - start) / 2; - /* The "num_operands <= 8 * SIZEOF_LONG" check guards against the - * unlikely case of an overflow in num_operands * max_bits. */ - if (num_operands <= 8 * SIZEOF_LONG && - num_operands * max_bits <= 8 * SIZEOF_LONG) { - unsigned long j, total; - for (total = start, j = start + 2; j < stop; j += 2) - total *= j; - return PyLong_FromUnsignedLong(total); - } - - /* find midpoint of range(start, stop), rounded up to next odd number. */ - midpoint = (start + num_operands) | 1; - left = factorial_partial_product(start, midpoint, - _Py_bit_length(midpoint - 2)); - if (left == NULL) - goto error; - right = factorial_partial_product(midpoint, stop, max_bits); - if (right == NULL) - goto error; - result = PyNumber_Multiply(left, right); - - error: - Py_XDECREF(left); - Py_XDECREF(right); - return result; -} - -/* factorial_odd_part: compute the odd part of factorial(n). */ - -static PyObject * -factorial_odd_part(unsigned long n) -{ - long i; - unsigned long v, lower, upper; - PyObject *partial, *tmp, *inner, *outer; - - inner = PyLong_FromLong(1); - if (inner == NULL) - return NULL; - outer = Py_NewRef(inner); - - upper = 3; - for (i = _Py_bit_length(n) - 2; i >= 0; i--) { - v = n >> i; - if (v <= 2) - continue; - lower = upper; - /* (v + 1) | 1 = least odd integer strictly larger than n / 2**i */ - upper = (v + 1) | 1; - /* Here inner is the product of all odd integers j in the range (0, - n/2**(i+1)]. The factorial_partial_product call below gives the - product of all odd integers j in the range (n/2**(i+1), n/2**i]. */ - partial = factorial_partial_product(lower, upper, _Py_bit_length(upper-2)); - /* inner *= partial */ - if (partial == NULL) - goto error; - tmp = PyNumber_Multiply(inner, partial); - Py_DECREF(partial); - if (tmp == NULL) - goto error; - Py_SETREF(inner, tmp); - /* Now inner is the product of all odd integers j in the range (0, - n/2**i], giving the inner product in the formula above. */ - - /* outer *= inner; */ - tmp = PyNumber_Multiply(outer, inner); - if (tmp == NULL) - goto error; - Py_SETREF(outer, tmp); - } - Py_DECREF(inner); - return outer; - - error: - Py_DECREF(outer); - Py_DECREF(inner); - return NULL; -} - - -/* Lookup table for small factorial values */ - -static const unsigned long SmallFactorials[] = { - 1, 1, 2, 6, 24, 120, 720, 5040, 40320, - 362880, 3628800, 39916800, 479001600, -#if SIZEOF_LONG >= 8 - 6227020800, 87178291200, 1307674368000, - 20922789888000, 355687428096000, 6402373705728000, - 121645100408832000, 2432902008176640000 -#endif -}; - -/*[clinic input] -math.factorial - - n as arg: object - / - -Find n!. -[clinic start generated code]*/ - -static PyObject * -math_factorial(PyObject *module, PyObject *arg) -/*[clinic end generated code: output=6686f26fae00e9ca input=366cc321df3d4773]*/ -{ - long x, two_valuation; - int overflow; - PyObject *result, *odd_part; - - x = PyLong_AsLongAndOverflow(arg, &overflow); - if (x == -1 && PyErr_Occurred()) { - return NULL; - } - else if (overflow == 1) { - PyErr_Format(PyExc_OverflowError, - "factorial() argument should not exceed %ld", - LONG_MAX); - return NULL; - } - else if (overflow == -1 || x < 0) { - PyErr_SetString(PyExc_ValueError, - "factorial() not defined for negative values"); - return NULL; - } - - /* use lookup table if x is small */ - if (x < (long)Py_ARRAY_LENGTH(SmallFactorials)) - return PyLong_FromUnsignedLong(SmallFactorials[x]); - - /* else express in the form odd_part * 2**two_valuation, and compute as - odd_part << two_valuation. */ - odd_part = factorial_odd_part(x); - if (odd_part == NULL) - return NULL; - two_valuation = x - count_set_bits(x); - result = _PyLong_Lshift(odd_part, two_valuation); - Py_DECREF(odd_part); - return result; -} - - /*[clinic input] math.trunc @@ -2203,7 +1500,7 @@ math_ldexp_impl(PyObject *module, double x, PyObject *i) errno = 0; } else if (exp > INT_MAX) { /* overflow */ - r = copysign(Py_INFINITY, x); + r = copysign(INFINITY, x); errno = ERANGE; } else if (exp < INT_MIN) { /* underflow to +-0 */ @@ -2281,44 +1578,63 @@ math_modf_impl(PyObject *module, double x) However, intermediate overflow is possible for an int if the number of bits in that int is larger than PY_SSIZE_T_MAX. */ +static PyObject* +loghelper_int(PyObject* arg, double (*func)(double)) +{ + /* If it is int, do it ourselves. */ + double x, result; + int64_t e; + + /* Negative or zero inputs give a ValueError. */ + if (!_PyLong_IsPositive((PyLongObject *)arg)) { + PyErr_SetString(PyExc_ValueError, + "expected a positive input"); + return NULL; + } + + x = PyLong_AsDouble(arg); + if (x == -1.0 && PyErr_Occurred()) { + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + /* Here the conversion to double overflowed, but it's possible + to compute the log anyway. Clear the exception and continue. */ + PyErr_Clear(); + x = _PyLong_Frexp((PyLongObject *)arg, &e); + assert(!PyErr_Occurred()); + /* Value is ~= x * 2**e, so the log ~= log(x) + log(2) * e. */ + result = fma(func(2.0), (double)e, func(x)); + } + else + /* Successfully converted x to a double. */ + result = func(x); + return PyFloat_FromDouble(result); +} + static PyObject* loghelper(PyObject* arg, double (*func)(double)) { /* If it is int, do it ourselves. */ if (PyLong_Check(arg)) { - double x, result; - int64_t e; - - /* Negative or zero inputs give a ValueError. */ - if (!_PyLong_IsPositive((PyLongObject *)arg)) { - /* The input can be an arbitrary large integer, so we - don't include it's value in the error message. */ - PyErr_SetString(PyExc_ValueError, - "expected a positive input"); + return loghelper_int(arg, func); + } + /* Else let libm handle it by itself. */ + PyObject *res = math_1(arg, func, 0, "expected a positive input, got %s"); + if (res == NULL && + PyErr_ExceptionMatches(PyExc_OverflowError) && + PyIndex_Check(arg)) + { + /* Here the conversion to double overflowed, but it's possible + to compute the log anyway. Clear the exception, convert to + integer and continue. */ + PyErr_Clear(); + arg = _PyNumber_Index(arg); + if (arg == NULL) { return NULL; } - - x = PyLong_AsDouble(arg); - if (x == -1.0 && PyErr_Occurred()) { - if (!PyErr_ExceptionMatches(PyExc_OverflowError)) - return NULL; - /* Here the conversion to double overflowed, but it's possible - to compute the log anyway. Clear the exception and continue. */ - PyErr_Clear(); - x = _PyLong_Frexp((PyLongObject *)arg, &e); - assert(e >= 0); - assert(!PyErr_Occurred()); - /* Value is ~= x * 2**e, so the log ~= log(x) + log(2) * e. */ - result = func(x) + func(2.0) * e; - } - else - /* Successfully converted x to a double. */ - result = func(x); - return PyFloat_FromDouble(result); + res = loghelper_int(arg, func); + Py_DECREF(arg); } - - /* Else let libm handle it by itself. */ - return math_1(arg, func, 0, "expected a positive input, got %s"); + return res; } @@ -3514,511 +2830,6 @@ math_prod_impl(PyObject *module, PyObject *iterable, PyObject *start) } -/* least significant 64 bits of the odd part of factorial(n), for n in range(128). - -Python code to generate the values: - - import math - - for n in range(128): - fac = math.factorial(n) - fac_odd_part = fac // (fac & -fac) - reduced_fac_odd_part = fac_odd_part % (2**64) - print(f"{reduced_fac_odd_part:#018x}u") -*/ -static const uint64_t reduced_factorial_odd_part[] = { - 0x0000000000000001u, 0x0000000000000001u, 0x0000000000000001u, 0x0000000000000003u, - 0x0000000000000003u, 0x000000000000000fu, 0x000000000000002du, 0x000000000000013bu, - 0x000000000000013bu, 0x0000000000000b13u, 0x000000000000375fu, 0x0000000000026115u, - 0x000000000007233fu, 0x00000000005cca33u, 0x0000000002898765u, 0x00000000260eeeebu, - 0x00000000260eeeebu, 0x0000000286fddd9bu, 0x00000016beecca73u, 0x000001b02b930689u, - 0x00000870d9df20adu, 0x0000b141df4dae31u, 0x00079dd498567c1bu, 0x00af2e19afc5266du, - 0x020d8a4d0f4f7347u, 0x335281867ec241efu, 0x9b3093d46fdd5923u, 0x5e1f9767cc5866b1u, - 0x92dd23d6966aced7u, 0xa30d0f4f0a196e5bu, 0x8dc3e5a1977d7755u, 0x2ab8ce915831734bu, - 0x2ab8ce915831734bu, 0x81d2a0bc5e5fdcabu, 0x9efcac82445da75bu, 0xbc8b95cf58cde171u, - 0xa0e8444a1f3cecf9u, 0x4191deb683ce3ffdu, 0xddd3878bc84ebfc7u, 0xcb39a64b83ff3751u, - 0xf8203f7993fc1495u, 0xbd2a2a78b35f4bddu, 0x84757be6b6d13921u, 0x3fbbcfc0b524988bu, - 0xbd11ed47c8928df9u, 0x3c26b59e41c2f4c5u, 0x677a5137e883fdb3u, 0xff74e943b03b93ddu, - 0xfe5ebbcb10b2bb97u, 0xb021f1de3235e7e7u, 0x33509eb2e743a58fu, 0x390f9da41279fb7du, - 0xe5cb0154f031c559u, 0x93074695ba4ddb6du, 0x81c471caa636247fu, 0xe1347289b5a1d749u, - 0x286f21c3f76ce2ffu, 0x00be84a2173e8ac7u, 0x1595065ca215b88bu, 0xf95877595b018809u, - 0x9c2efe3c5516f887u, 0x373294604679382bu, 0xaf1ff7a888adcd35u, 0x18ddf279a2c5800bu, - 0x18ddf279a2c5800bu, 0x505a90e2542582cbu, 0x5bacad2cd8d5dc2bu, 0xfe3152bcbff89f41u, - 0xe1467e88bf829351u, 0xb8001adb9e31b4d5u, 0x2803ac06a0cbb91fu, 0x1904b5d698805799u, - 0xe12a648b5c831461u, 0x3516abbd6160cfa9u, 0xac46d25f12fe036du, 0x78bfa1da906b00efu, - 0xf6390338b7f111bdu, 0x0f25f80f538255d9u, 0x4ec8ca55b8db140fu, 0x4ff670740b9b30a1u, - 0x8fd032443a07f325u, 0x80dfe7965c83eeb5u, 0xa3dc1714d1213afdu, 0x205b7bbfcdc62007u, - 0xa78126bbe140a093u, 0x9de1dc61ca7550cfu, 0x84f0046d01b492c5u, 0x2d91810b945de0f3u, - 0xf5408b7f6008aa71u, 0x43707f4863034149u, 0xdac65fb9679279d5u, 0xc48406e7d1114eb7u, - 0xa7dc9ed3c88e1271u, 0xfb25b2efdb9cb30du, 0x1bebda0951c4df63u, 0x5c85e975580ee5bdu, - 0x1591bc60082cb137u, 0x2c38606318ef25d7u, 0x76ca72f7c5c63e27u, 0xf04a75d17baa0915u, - 0x77458175139ae30du, 0x0e6c1330bc1b9421u, 0xdf87d2b5797e8293u, 0xefa5c703e1e68925u, - 0x2b6b1b3278b4f6e1u, 0xceee27b382394249u, 0xd74e3829f5dab91du, 0xfdb17989c26b5f1fu, - 0xc1b7d18781530845u, 0x7b4436b2105a8561u, 0x7ba7c0418372a7d7u, 0x9dbc5c67feb6c639u, - 0x502686d7f6ff6b8fu, 0x6101855406be7a1fu, 0x9956afb5806930e7u, 0xe1f0ee88af40f7c5u, - 0x984b057bda5c1151u, 0x9a49819acc13ea05u, 0x8ef0dead0896ef27u, 0x71f7826efe292b21u, - 0xad80a480e46986efu, 0x01cdc0ebf5e0c6f7u, 0x6e06f839968f68dbu, 0xdd5943ab56e76139u, - 0xcdcf31bf8604c5e7u, 0x7e2b4a847054a1cbu, 0x0ca75697a4d3d0f5u, 0x4703f53ac514a98bu, -}; - -/* inverses of reduced_factorial_odd_part values modulo 2**64. - -Python code to generate the values: - - import math - - for n in range(128): - fac = math.factorial(n) - fac_odd_part = fac // (fac & -fac) - inverted_fac_odd_part = pow(fac_odd_part, -1, 2**64) - print(f"{inverted_fac_odd_part:#018x}u") -*/ -static const uint64_t inverted_factorial_odd_part[] = { - 0x0000000000000001u, 0x0000000000000001u, 0x0000000000000001u, 0xaaaaaaaaaaaaaaabu, - 0xaaaaaaaaaaaaaaabu, 0xeeeeeeeeeeeeeeefu, 0x4fa4fa4fa4fa4fa5u, 0x2ff2ff2ff2ff2ff3u, - 0x2ff2ff2ff2ff2ff3u, 0x938cc70553e3771bu, 0xb71c27cddd93e49fu, 0xb38e3229fcdee63du, - 0xe684bb63544a4cbfu, 0xc2f684917ca340fbu, 0xf747c9cba417526du, 0xbb26eb51d7bd49c3u, - 0xbb26eb51d7bd49c3u, 0xb0a7efb985294093u, 0xbe4b8c69f259eabbu, 0x6854d17ed6dc4fb9u, - 0xe1aa904c915f4325u, 0x3b8206df131cead1u, 0x79c6009fea76fe13u, 0xd8c5d381633cd365u, - 0x4841f12b21144677u, 0x4a91ff68200b0d0fu, 0x8f9513a58c4f9e8bu, 0x2b3e690621a42251u, - 0x4f520f00e03c04e7u, 0x2edf84ee600211d3u, 0xadcaa2764aaacdfdu, 0x161f4f9033f4fe63u, - 0x161f4f9033f4fe63u, 0xbada2932ea4d3e03u, 0xcec189f3efaa30d3u, 0xf7475bb68330bf91u, - 0x37eb7bf7d5b01549u, 0x46b35660a4e91555u, 0xa567c12d81f151f7u, 0x4c724007bb2071b1u, - 0x0f4a0cce58a016bdu, 0xfa21068e66106475u, 0x244ab72b5a318ae1u, 0x366ce67e080d0f23u, - 0xd666fdae5dd2a449u, 0xd740ddd0acc06a0du, 0xb050bbbb28e6f97bu, 0x70b003fe890a5c75u, - 0xd03aabff83037427u, 0x13ec4ca72c783bd7u, 0x90282c06afdbd96fu, 0x4414ddb9db4a95d5u, - 0xa2c68735ae6832e9u, 0xbf72d71455676665u, 0xa8469fab6b759b7fu, 0xc1e55b56e606caf9u, - 0x40455630fc4a1cffu, 0x0120a7b0046d16f7u, 0xa7c3553b08faef23u, 0x9f0bfd1b08d48639u, - 0xa433ffce9a304d37u, 0xa22ad1d53915c683u, 0xcb6cbc723ba5dd1du, 0x547fb1b8ab9d0ba3u, - 0x547fb1b8ab9d0ba3u, 0x8f15a826498852e3u, 0x32e1a03f38880283u, 0x3de4cce63283f0c1u, - 0x5dfe6667e4da95b1u, 0xfda6eeeef479e47du, 0xf14de991cc7882dfu, 0xe68db79247630ca9u, - 0xa7d6db8207ee8fa1u, 0x255e1f0fcf034499u, 0xc9a8990e43dd7e65u, 0x3279b6f289702e0fu, - 0xe7b5905d9b71b195u, 0x03025ba41ff0da69u, 0xb7df3d6d3be55aefu, 0xf89b212ebff2b361u, - 0xfe856d095996f0adu, 0xd6e533e9fdf20f9du, 0xf8c0e84a63da3255u, 0xa677876cd91b4db7u, - 0x07ed4f97780d7d9bu, 0x90a8705f258db62fu, 0xa41bbb2be31b1c0du, 0x6ec28690b038383bu, - 0xdb860c3bb2edd691u, 0x0838286838a980f9u, 0x558417a74b36f77du, 0x71779afc3646ef07u, - 0x743cda377ccb6e91u, 0x7fdf9f3fe89153c5u, 0xdc97d25df49b9a4bu, 0x76321a778eb37d95u, - 0x7cbb5e27da3bd487u, 0x9cff4ade1a009de7u, 0x70eb166d05c15197u, 0xdcf0460b71d5fe3du, - 0x5ac1ee5260b6a3c5u, 0xc922dedfdd78efe1u, 0xe5d381dc3b8eeb9bu, 0xd57e5347bafc6aadu, - 0x86939040983acd21u, 0x395b9d69740a4ff9u, 0x1467299c8e43d135u, 0x5fe440fcad975cdfu, - 0xcaa9a39794a6ca8du, 0xf61dbd640868dea1u, 0xac09d98d74843be7u, 0x2b103b9e1a6b4809u, - 0x2ab92d16960f536fu, 0x6653323d5e3681dfu, 0xefd48c1c0624e2d7u, 0xa496fefe04816f0du, - 0x1754a7b07bbdd7b1u, 0x23353c829a3852cdu, 0xbf831261abd59097u, 0x57a8e656df0618e1u, - 0x16e9206c3100680fu, 0xadad4c6ee921dac7u, 0x635f2b3860265353u, 0xdd6d0059f44b3d09u, - 0xac4dd6b894447dd7u, 0x42ea183eeaa87be3u, 0x15612d1550ee5b5du, 0x226fa19d656cb623u, -}; - -/* exponent of the largest power of 2 dividing factorial(n), for n in range(68) - -Python code to generate the values: - -import math - -for n in range(128): - fac = math.factorial(n) - fac_trailing_zeros = (fac & -fac).bit_length() - 1 - print(fac_trailing_zeros) -*/ - -static const uint8_t factorial_trailing_zeros[] = { - 0, 0, 1, 1, 3, 3, 4, 4, 7, 7, 8, 8, 10, 10, 11, 11, // 0-15 - 15, 15, 16, 16, 18, 18, 19, 19, 22, 22, 23, 23, 25, 25, 26, 26, // 16-31 - 31, 31, 32, 32, 34, 34, 35, 35, 38, 38, 39, 39, 41, 41, 42, 42, // 32-47 - 46, 46, 47, 47, 49, 49, 50, 50, 53, 53, 54, 54, 56, 56, 57, 57, // 48-63 - 63, 63, 64, 64, 66, 66, 67, 67, 70, 70, 71, 71, 73, 73, 74, 74, // 64-79 - 78, 78, 79, 79, 81, 81, 82, 82, 85, 85, 86, 86, 88, 88, 89, 89, // 80-95 - 94, 94, 95, 95, 97, 97, 98, 98, 101, 101, 102, 102, 104, 104, 105, 105, // 96-111 - 109, 109, 110, 110, 112, 112, 113, 113, 116, 116, 117, 117, 119, 119, 120, 120, // 112-127 -}; - -/* Number of permutations and combinations. - * P(n, k) = n! / (n-k)! - * C(n, k) = P(n, k) / k! - */ - -/* Calculate C(n, k) for n in the 63-bit range. */ -static PyObject * -perm_comb_small(unsigned long long n, unsigned long long k, int iscomb) -{ - assert(k != 0); - - /* For small enough n and k the result fits in the 64-bit range and can - * be calculated without allocating intermediate PyLong objects. */ - if (iscomb) { - /* Maps k to the maximal n so that 2*k-1 <= n <= 127 and C(n, k) - * fits into a uint64_t. Exclude k = 1, because the second fast - * path is faster for this case.*/ - static const unsigned char fast_comb_limits1[] = { - 0, 0, 127, 127, 127, 127, 127, 127, // 0-7 - 127, 127, 127, 127, 127, 127, 127, 127, // 8-15 - 116, 105, 97, 91, 86, 82, 78, 76, // 16-23 - 74, 72, 71, 70, 69, 68, 68, 67, // 24-31 - 67, 67, 67, // 32-34 - }; - if (k < Py_ARRAY_LENGTH(fast_comb_limits1) && n <= fast_comb_limits1[k]) { - /* - comb(n, k) fits into a uint64_t. We compute it as - - comb_odd_part << shift - - where 2**shift is the largest power of two dividing comb(n, k) - and comb_odd_part is comb(n, k) >> shift. comb_odd_part can be - calculated efficiently via arithmetic modulo 2**64, using three - lookups and two uint64_t multiplications. - */ - uint64_t comb_odd_part = reduced_factorial_odd_part[n] - * inverted_factorial_odd_part[k] - * inverted_factorial_odd_part[n - k]; - int shift = factorial_trailing_zeros[n] - - factorial_trailing_zeros[k] - - factorial_trailing_zeros[n - k]; - return PyLong_FromUnsignedLongLong(comb_odd_part << shift); - } - - /* Maps k to the maximal n so that 2*k-1 <= n <= 127 and C(n, k)*k - * fits into a long long (which is at least 64 bit). Only contains - * items larger than in fast_comb_limits1. */ - static const unsigned long long fast_comb_limits2[] = { - 0, ULLONG_MAX, 4294967296ULL, 3329022, 102570, 13467, 3612, 1449, // 0-7 - 746, 453, 308, 227, 178, 147, // 8-13 - }; - if (k < Py_ARRAY_LENGTH(fast_comb_limits2) && n <= fast_comb_limits2[k]) { - /* C(n, k) = C(n, k-1) * (n-k+1) / k */ - unsigned long long result = n; - for (unsigned long long i = 1; i < k;) { - result *= --n; - result /= ++i; - } - return PyLong_FromUnsignedLongLong(result); - } - } - else { - /* Maps k to the maximal n so that k <= n and P(n, k) - * fits into a long long (which is at least 64 bit). */ - static const unsigned long long fast_perm_limits[] = { - 0, ULLONG_MAX, 4294967296ULL, 2642246, 65537, 7133, 1627, 568, // 0-7 - 259, 142, 88, 61, 45, 36, 30, 26, // 8-15 - 24, 22, 21, 20, 20, // 16-20 - }; - if (k < Py_ARRAY_LENGTH(fast_perm_limits) && n <= fast_perm_limits[k]) { - if (n <= 127) { - /* P(n, k) fits into a uint64_t. */ - uint64_t perm_odd_part = reduced_factorial_odd_part[n] - * inverted_factorial_odd_part[n - k]; - int shift = factorial_trailing_zeros[n] - - factorial_trailing_zeros[n - k]; - return PyLong_FromUnsignedLongLong(perm_odd_part << shift); - } - - /* P(n, k) = P(n, k-1) * (n-k+1) */ - unsigned long long result = n; - for (unsigned long long i = 1; i < k;) { - result *= --n; - ++i; - } - return PyLong_FromUnsignedLongLong(result); - } - } - - /* For larger n use recursive formulas: - * - * P(n, k) = P(n, j) * P(n-j, k-j) - * C(n, k) = C(n, j) * C(n-j, k-j) // C(k, j) - */ - unsigned long long j = k / 2; - PyObject *a, *b; - a = perm_comb_small(n, j, iscomb); - if (a == NULL) { - return NULL; - } - b = perm_comb_small(n - j, k - j, iscomb); - if (b == NULL) { - goto error; - } - Py_SETREF(a, PyNumber_Multiply(a, b)); - Py_DECREF(b); - if (iscomb && a != NULL) { - b = perm_comb_small(k, j, 1); - if (b == NULL) { - goto error; - } - Py_SETREF(a, PyNumber_FloorDivide(a, b)); - Py_DECREF(b); - } - return a; - -error: - Py_DECREF(a); - return NULL; -} - -/* Calculate P(n, k) or C(n, k) using recursive formulas. - * It is more efficient than sequential multiplication thanks to - * Karatsuba multiplication. - */ -static PyObject * -perm_comb(PyObject *n, unsigned long long k, int iscomb) -{ - if (k == 0) { - return PyLong_FromLong(1); - } - if (k == 1) { - return Py_NewRef(n); - } - - /* P(n, k) = P(n, j) * P(n-j, k-j) */ - /* C(n, k) = C(n, j) * C(n-j, k-j) // C(k, j) */ - unsigned long long j = k / 2; - PyObject *a, *b; - a = perm_comb(n, j, iscomb); - if (a == NULL) { - return NULL; - } - PyObject *t = PyLong_FromUnsignedLongLong(j); - if (t == NULL) { - goto error; - } - n = PyNumber_Subtract(n, t); - Py_DECREF(t); - if (n == NULL) { - goto error; - } - b = perm_comb(n, k - j, iscomb); - Py_DECREF(n); - if (b == NULL) { - goto error; - } - Py_SETREF(a, PyNumber_Multiply(a, b)); - Py_DECREF(b); - if (iscomb && a != NULL) { - b = perm_comb_small(k, j, 1); - if (b == NULL) { - goto error; - } - Py_SETREF(a, PyNumber_FloorDivide(a, b)); - Py_DECREF(b); - } - return a; - -error: - Py_DECREF(a); - return NULL; -} - -/*[clinic input] -@permit_long_summary -math.perm - - n: object - k: object = None - / - -Number of ways to choose k items from n items without repetition and with order. - -Evaluates to n! / (n - k)! when k <= n and evaluates -to zero when k > n. - -If k is not specified or is None, then k defaults to n -and the function returns n!. - -Raises TypeError if either of the arguments are not integers. -Raises ValueError if either of the arguments are negative. -[clinic start generated code]*/ - -static PyObject * -math_perm_impl(PyObject *module, PyObject *n, PyObject *k) -/*[clinic end generated code: output=e021a25469653e23 input=9d54b8e13c0a3683]*/ -{ - PyObject *result = NULL; - int overflow, cmp; - long long ki, ni; - - if (k == Py_None) { - return math_factorial(module, n); - } - n = PyNumber_Index(n); - if (n == NULL) { - return NULL; - } - k = PyNumber_Index(k); - if (k == NULL) { - Py_DECREF(n); - return NULL; - } - assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - - if (_PyLong_IsNegative((PyLongObject *)n)) { - PyErr_SetString(PyExc_ValueError, - "n must be a non-negative integer"); - goto error; - } - if (_PyLong_IsNegative((PyLongObject *)k)) { - PyErr_SetString(PyExc_ValueError, - "k must be a non-negative integer"); - goto error; - } - - cmp = PyObject_RichCompareBool(n, k, Py_LT); - if (cmp != 0) { - if (cmp > 0) { - result = PyLong_FromLong(0); - goto done; - } - goto error; - } - - ki = PyLong_AsLongLongAndOverflow(k, &overflow); - assert(overflow >= 0 && !PyErr_Occurred()); - if (overflow > 0) { - PyErr_Format(PyExc_OverflowError, - "k must not exceed %lld", - LLONG_MAX); - goto error; - } - assert(ki >= 0); - - ni = PyLong_AsLongLongAndOverflow(n, &overflow); - assert(overflow >= 0 && !PyErr_Occurred()); - if (!overflow && ki > 1) { - assert(ni >= 0); - result = perm_comb_small((unsigned long long)ni, - (unsigned long long)ki, 0); - } - else { - result = perm_comb(n, (unsigned long long)ki, 0); - } - -done: - Py_DECREF(n); - Py_DECREF(k); - return result; - -error: - Py_DECREF(n); - Py_DECREF(k); - return NULL; -} - -/*[clinic input] -@permit_long_summary -math.comb - - n: object - k: object - / - -Number of ways to choose k items from n items without repetition and without order. - -Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates -to zero when k > n. - -Also called the binomial coefficient because it is equivalent -to the coefficient of k-th term in polynomial expansion of the -expression (1 + x)**n. - -Raises TypeError if either of the arguments are not integers. -Raises ValueError if either of the arguments are negative. - -[clinic start generated code]*/ - -static PyObject * -math_comb_impl(PyObject *module, PyObject *n, PyObject *k) -/*[clinic end generated code: output=bd2cec8d854f3493 input=7ad3c763d442d64c]*/ -{ - PyObject *result = NULL, *temp; - int overflow, cmp; - long long ki, ni; - - n = PyNumber_Index(n); - if (n == NULL) { - return NULL; - } - k = PyNumber_Index(k); - if (k == NULL) { - Py_DECREF(n); - return NULL; - } - assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - - if (_PyLong_IsNegative((PyLongObject *)n)) { - PyErr_SetString(PyExc_ValueError, - "n must be a non-negative integer"); - goto error; - } - if (_PyLong_IsNegative((PyLongObject *)k)) { - PyErr_SetString(PyExc_ValueError, - "k must be a non-negative integer"); - goto error; - } - - ni = PyLong_AsLongLongAndOverflow(n, &overflow); - assert(overflow >= 0 && !PyErr_Occurred()); - if (!overflow) { - assert(ni >= 0); - ki = PyLong_AsLongLongAndOverflow(k, &overflow); - assert(overflow >= 0 && !PyErr_Occurred()); - if (overflow || ki > ni) { - result = PyLong_FromLong(0); - goto done; - } - assert(ki >= 0); - - ki = Py_MIN(ki, ni - ki); - if (ki > 1) { - result = perm_comb_small((unsigned long long)ni, - (unsigned long long)ki, 1); - goto done; - } - /* For k == 1 just return the original n in perm_comb(). */ - } - else { - /* k = min(k, n - k) */ - temp = PyNumber_Subtract(n, k); - if (temp == NULL) { - goto error; - } - assert(PyLong_Check(temp)); - if (_PyLong_IsNegative((PyLongObject *)temp)) { - Py_DECREF(temp); - result = PyLong_FromLong(0); - goto done; - } - cmp = PyObject_RichCompareBool(temp, k, Py_LT); - if (cmp > 0) { - Py_SETREF(k, temp); - } - else { - Py_DECREF(temp); - if (cmp < 0) { - goto error; - } - } - - ki = PyLong_AsLongLongAndOverflow(k, &overflow); - assert(overflow >= 0 && !PyErr_Occurred()); - if (overflow) { - PyErr_Format(PyExc_OverflowError, - "min(n - k, k) must not exceed %lld", - LLONG_MAX); - goto error; - } - assert(ki >= 0); - } - - result = perm_comb(n, (unsigned long long)ki, 1); - -done: - Py_DECREF(n); - Py_DECREF(k); - return result; - -error: - Py_DECREF(n); - Py_DECREF(k); - return NULL; -} - - /*[clinic input] @permit_long_docstring_body math.nextafter @@ -4172,7 +2983,7 @@ math_ulp_impl(PyObject *module, double x) if (isinf(x)) { return x; } - double inf = Py_INFINITY; + double inf = INFINITY; double x2 = nextafter(x, inf); if (isinf(x2)) { /* special case: x is the largest positive representable float */ @@ -4196,12 +3007,38 @@ math_exec(PyObject *module) if (PyModule_Add(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_Add(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { + if (PyModule_Add(module, "inf", PyFloat_FromDouble(INFINITY)) < 0) { return -1; } if (PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } + + PyObject *intmath = PyImport_ImportModule("_math_integer"); + if (!intmath) { + return -1; + } +#define IMPORT_FROM_INTMATH(NAME) do { \ + if (PyModule_Add(module, #NAME, \ + PyObject_GetAttrString(intmath, #NAME)) < 0) { \ + Py_DECREF(intmath); \ + return -1; \ + } \ + } while(0) + + IMPORT_FROM_INTMATH(comb); + IMPORT_FROM_INTMATH(factorial); + IMPORT_FROM_INTMATH(gcd); + IMPORT_FROM_INTMATH(isqrt); + IMPORT_FROM_INTMATH(lcm); + IMPORT_FROM_INTMATH(perm); + if (_PyImport_SetModuleString("math.integer", intmath) < 0) { + Py_DECREF(intmath); + return -1; + } + if (PyModule_Add(module, "integer", intmath) < 0) { + return -1; + } return 0; } @@ -4226,7 +3063,6 @@ static PyMethodDef math_methods[] = { {"exp2", math_exp2, METH_O, math_exp2_doc}, {"expm1", math_expm1, METH_O, math_expm1_doc}, {"fabs", math_fabs, METH_O, math_fabs_doc}, - MATH_FACTORIAL_METHODDEF MATH_FLOOR_METHODDEF MATH_FMA_METHODDEF MATH_FMAX_METHODDEF @@ -4235,7 +3071,6 @@ static PyMethodDef math_methods[] = { MATH_FREXP_METHODDEF MATH_FSUM_METHODDEF {"gamma", math_gamma, METH_O, math_gamma_doc}, - MATH_GCD_METHODDEF MATH_HYPOT_METHODDEF MATH_ISCLOSE_METHODDEF MATH_ISFINITE_METHODDEF @@ -4243,8 +3078,6 @@ static PyMethodDef math_methods[] = { MATH_ISSUBNORMAL_METHODDEF MATH_ISINF_METHODDEF MATH_ISNAN_METHODDEF - MATH_ISQRT_METHODDEF - MATH_LCM_METHODDEF MATH_LDEXP_METHODDEF {"lgamma", math_lgamma, METH_O, math_lgamma_doc}, {"log", _PyCFunction_CAST(math_log), METH_FASTCALL, math_log_doc}, @@ -4264,8 +3097,6 @@ static PyMethodDef math_methods[] = { MATH_SUMPROD_METHODDEF MATH_TRUNC_METHODDEF MATH_PROD_METHODDEF - MATH_PERM_METHODDEF - MATH_COMB_METHODDEF MATH_NEXTAFTER_METHODDEF MATH_ULP_METHODDEF {NULL, NULL} /* sentinel */ diff --git a/Modules/md5module.c b/Modules/md5module.c index 8b6dd4a8195..56e9faf4c62 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -22,7 +22,8 @@ #endif #include "Python.h" -#include "pycore_strhex.h" // _Py_strhex() +#include "pycore_object.h" // _PyObject_VisitType() +#include "pycore_strhex.h" // _Py_strhex() #include "hashlib.h" @@ -82,13 +83,6 @@ newMD5object(MD5State * st) } /* Internal methods for a hash object */ -static int -MD5_traverse(PyObject *ptr, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(ptr)); - return 0; -} - static void MD5_dealloc(PyObject *op) { @@ -246,7 +240,7 @@ static PyType_Slot md5_type_slots[] = { {Py_tp_dealloc, MD5_dealloc}, {Py_tp_methods, MD5_methods}, {Py_tp_getset, MD5_getseters}, - {Py_tp_traverse, MD5_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 0cb4b62d734..37003020de2 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -26,6 +26,7 @@ #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() #include "pycore_bytesobject.h" // _PyBytes_Find() #include "pycore_fileutils.h" // _Py_stat_struct +#include "pycore_mmap.h" // _PyAnnotateMemoryMap() #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() #include <stddef.h> // offsetof() @@ -91,6 +92,12 @@ my_getpagesize(void) # define MAP_ANONYMOUS MAP_ANON #endif +/*[clinic input] +module mmap +class mmap.mmap "mmap_object *" "" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=82a9f8a529905b9b]*/ + typedef enum { ACCESS_DEFAULT, @@ -119,20 +126,34 @@ typedef struct { #ifdef UNIX int fd; - _Bool trackfd; + int flags; #endif PyObject *weakreflist; access_mode access; + _Bool trackfd; } mmap_object; #define mmap_object_CAST(op) ((mmap_object *)(op)) -static int -mmap_object_traverse(PyObject *op, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(op)); - return 0; +#include "clinic/mmapmodule.c.h" + + +/* Return a Py_ssize_t from the object arg. This conversion logic is similar + to what AC uses for `Py_ssize_t` arguments. + + Returns -1 on error. Use PyErr_Occurred() to disambiguate. +*/ +static Py_ssize_t +_As_Py_ssize_t(PyObject *arg) { + assert(arg != NULL); + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + return ival; } static void @@ -171,10 +192,16 @@ mmap_object_dealloc(PyObject *op) Py_DECREF(tp); } +/*[clinic input] +@critical_section +mmap.mmap.close + +[clinic start generated code]*/ + static PyObject * -mmap_close_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_close_impl(mmap_object *self) +/*[clinic end generated code: output=a1ae0c727546f78d input=25020035f047eae1]*/ { - mmap_object *self = mmap_object_CAST(op); if (self->exports > 0) { PyErr_SetString(PyExc_BufferError, "cannot close "\ "exported pointers exist"); @@ -454,7 +481,8 @@ _safe_PyBytes_ReverseFind(Py_ssize_t *out, mmap_object *self, } PyObject * -_safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) { +_safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) +{ if (num_bytes == 1) { char dest; if (safe_byte_copy(&dest, start) < 0) { @@ -465,21 +493,28 @@ _safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) { } } else { - PyObject *result = PyBytes_FromStringAndSize(NULL, num_bytes); - if (result == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(num_bytes); + if (writer == NULL) { return NULL; } - if (safe_memcpy(PyBytes_AS_STRING(result), start, num_bytes) < 0) { - Py_CLEAR(result); + if (safe_memcpy(PyBytesWriter_GetData(writer), start, num_bytes) < 0) { + PyBytesWriter_Discard(writer); + return NULL; } - return result; + return PyBytesWriter_Finish(writer); } } +/*[clinic input] +@critical_section +mmap.mmap.read_byte + +[clinic start generated code]*/ + static PyObject * -mmap_read_byte_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_read_byte_impl(mmap_object *self) +/*[clinic end generated code: output=d931da1319f3869b input=5b8c6a904bdddda9]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); if (self->pos >= self->size) { PyErr_SetString(PyExc_ValueError, "read byte out of range"); @@ -493,12 +528,18 @@ mmap_read_byte_method(PyObject *op, PyObject *Py_UNUSED(ignored)) return PyLong_FromLong((unsigned char) dest); } +/*[clinic input] +@critical_section +mmap.mmap.readline + +[clinic start generated code]*/ + static PyObject * -mmap_read_line_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_readline_impl(mmap_object *self) +/*[clinic end generated code: output=b9d2bf9999283311 input=2c4efd1d06e1cdd1]*/ { Py_ssize_t remaining; char *start, *eol; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -523,15 +564,21 @@ mmap_read_line_method(PyObject *op, PyObject *Py_UNUSED(ignored)) return result; } -static PyObject * -mmap_read_method(PyObject *op, PyObject *args) -{ - Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; - mmap_object *self = mmap_object_CAST(op); +/*[clinic input] +@critical_section +mmap.mmap.read + + n as num_bytes: object(converter='_Py_convert_optional_to_ssize_t', type='Py_ssize_t', c_default='PY_SSIZE_T_MAX') = None + / + +[clinic start generated code]*/ + +static PyObject * +mmap_mmap_read_impl(mmap_object *self, Py_ssize_t num_bytes) +/*[clinic end generated code: output=3b4d4f3704ed0969 input=8f97f361d435e357]*/ +{ + Py_ssize_t remaining; - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) - return NULL; CHECK_VALID(NULL); /* silently 'adjust' out-of-range requests */ @@ -548,81 +595,105 @@ mmap_read_method(PyObject *op, PyObject *args) } static PyObject * -mmap_gfind(mmap_object *self, - PyObject *args, - int reverse) +mmap_gfind_lock_held(mmap_object *self, Py_buffer *view, PyObject *start_obj, + PyObject *end_obj, int reverse) { Py_ssize_t start = self->pos; Py_ssize_t end = self->size; - Py_buffer view; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find", - &view, &start, &end)) { - return NULL; - } - else { - if (start < 0) - start += self->size; - if (start < 0) - start = 0; - else if (start > self->size) - start = self->size; - - if (end < 0) - end += self->size; - if (end < 0) - end = 0; - else if (end > self->size) - end = self->size; - - Py_ssize_t index; - PyObject *result; - CHECK_VALID_OR_RELEASE(NULL, view); - if (end < start) { - result = PyLong_FromSsize_t(-1); + if (start_obj != Py_None) { + start = _As_Py_ssize_t(start_obj); + if (start == -1 && PyErr_Occurred()) { + return NULL; } - else if (reverse) { - assert(0 <= start && start <= end && end <= self->size); - if (_safe_PyBytes_ReverseFind(&index, self, - self->data + start, end - start, - view.buf, view.len, start) < 0) - { - result = NULL; - } - else { - result = PyLong_FromSsize_t(index); + + if (end_obj != Py_None) { + end = _As_Py_ssize_t(end_obj); + if (end == -1 && PyErr_Occurred()) { + return NULL; } } + } + + if (start < 0) + start += self->size; + if (start < 0) + start = 0; + else if (start > self->size) + start = self->size; + + if (end < 0) + end += self->size; + if (end < 0) + end = 0; + else if (end > self->size) + end = self->size; + + Py_ssize_t index; + PyObject *result; + CHECK_VALID(NULL); + if (end < start) { + result = PyLong_FromSsize_t(-1); + } + else if (reverse) { + assert(0 <= start && start <= end && end <= self->size); + if (_safe_PyBytes_ReverseFind(&index, self, + self->data + start, end - start, + view->buf, view->len, start) < 0) + { + result = NULL; + } else { - assert(0 <= start && start <= end && end <= self->size); - if (_safe_PyBytes_Find(&index, self, - self->data + start, end - start, - view.buf, view.len, start) < 0) - { - result = NULL; - } - else { - result = PyLong_FromSsize_t(index); - } + result = PyLong_FromSsize_t(index); } - PyBuffer_Release(&view); - return result; } + else { + assert(0 <= start && start <= end && end <= self->size); + if (_safe_PyBytes_Find(&index, self, + self->data + start, end - start, + view->buf, view->len, start) < 0) + { + result = NULL; + } + else { + result = PyLong_FromSsize_t(index); + } + } + return result; } -static PyObject * -mmap_find_method(PyObject *op, PyObject *args) -{ - mmap_object *self = mmap_object_CAST(op); - return mmap_gfind(self, args, 0); -} +/*[clinic input] +@critical_section +mmap.mmap.find + + view: Py_buffer + start: object = None + end: object = None + / + +[clinic start generated code]*/ static PyObject * -mmap_rfind_method(PyObject *op, PyObject *args) +mmap_mmap_find_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end) +/*[clinic end generated code: output=ef8878a322f00192 input=0135504494b52c2b]*/ { - mmap_object *self = mmap_object_CAST(op); - return mmap_gfind(self, args, 1); + return mmap_gfind_lock_held(self, view, start, end, 0); +} + +/*[clinic input] +@critical_section +mmap.mmap.rfind = mmap.mmap.find + +[clinic start generated code]*/ + +static PyObject * +mmap_mmap_rfind_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end) +/*[clinic end generated code: output=73b918940d67c2b8 input=8aecdd1f70c06c62]*/ +{ + return mmap_gfind_lock_held(self, view, start, end, 1); } static int @@ -634,6 +705,7 @@ is_writable(mmap_object *self) return 0; } +#if defined(MS_WINDOWS) || defined(HAVE_MREMAP) static int is_resizeable(mmap_object *self) { @@ -642,13 +714,11 @@ is_resizeable(mmap_object *self) "mmap can't resize with extant buffers exported."); return 0; } -#ifdef UNIX if (!self->trackfd) { PyErr_SetString(PyExc_ValueError, "mmap can't resize with trackfd=False."); return 0; } -#endif if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT)) return 1; PyErr_Format(PyExc_TypeError, @@ -656,52 +726,58 @@ is_resizeable(mmap_object *self) return 0; } +#endif /* MS_WINDOWS || HAVE_MREMAP */ +/*[clinic input] +@critical_section +mmap.mmap.write + + bytes as data: Py_buffer + / + +[clinic start generated code]*/ + static PyObject * -mmap_write_method(PyObject *op, PyObject *args) +mmap_mmap_write_impl(mmap_object *self, Py_buffer *data) +/*[clinic end generated code: output=9e97063efb6fb27b input=3f16fa79aa89d6f7]*/ { - Py_buffer data; - mmap_object *self = mmap_object_CAST(op); - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "y*:write", &data)) - return NULL; - if (!is_writable(self)) { - PyBuffer_Release(&data); return NULL; } - if (self->pos > self->size || self->size - self->pos < data.len) { - PyBuffer_Release(&data); + if (self->pos > self->size || self->size - self->pos < data->len) { PyErr_SetString(PyExc_ValueError, "data out of range"); return NULL; } - CHECK_VALID_OR_RELEASE(NULL, data); + CHECK_VALID(NULL); PyObject *result; - if (safe_memcpy(self->data + self->pos, data.buf, data.len) < 0) { + if (safe_memcpy(self->data + self->pos, data->buf, data->len) < 0) { result = NULL; } else { - self->pos += data.len; - result = PyLong_FromSsize_t(data.len); + self->pos += data->len; + result = PyLong_FromSsize_t(data->len); } - PyBuffer_Release(&data); return result; } +/*[clinic input] +@critical_section +mmap.mmap.write_byte + + byte as value: unsigned_char + / + +[clinic start generated code]*/ + static PyObject * -mmap_write_byte_method(PyObject *op, PyObject *args) +mmap_mmap_write_byte_impl(mmap_object *self, unsigned char value) +/*[clinic end generated code: output=aa11adada9b17510 input=32740bfa174f0991]*/ { - char value; - mmap_object *self = mmap_object_CAST(op); - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "b:write_byte", &value)) - return(NULL); - if (!is_writable(self)) return NULL; @@ -711,17 +787,23 @@ mmap_write_byte_method(PyObject *op, PyObject *args) return NULL; } - if (safe_byte_copy(self->data + self->pos, &value) < 0) { + if (safe_byte_copy(self->data + self->pos, (const char*)&value) < 0) { return NULL; } self->pos++; Py_RETURN_NONE; } +/*[clinic input] +@critical_section +mmap.mmap.size + +[clinic start generated code]*/ + static PyObject * -mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_size_impl(mmap_object *self) +/*[clinic end generated code: output=c177e65e83a648ff input=f69c072efd2e1595]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); #ifdef MS_WINDOWS @@ -740,13 +822,11 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) return PyLong_FromLong((long)low); size = (((long long)high)<<32) + low; return PyLong_FromLongLong(size); - } else { - return PyLong_FromSsize_t(self->size); } #endif /* MS_WINDOWS */ #ifdef UNIX - { + if (self->fd != -1) { struct _Py_stat_struct status; if (_Py_fstat(self->fd, &status) == -1) return NULL; @@ -757,6 +837,14 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) #endif } #endif /* UNIX */ + else if (self->trackfd) { + return PyLong_FromSsize_t(self->size); + } + else { + PyErr_SetString(PyExc_ValueError, + "can't get size with trackfd=False"); + return NULL; + } } /* This assumes that you want the entire file mapped, @@ -768,14 +856,22 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) / new size? */ +#if defined(MS_WINDOWS) || defined(HAVE_MREMAP) +/*[clinic input] +@critical_section +mmap.mmap.resize + + newsize as new_size: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -mmap_resize_method(PyObject *op, PyObject *args) +mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size) +/*[clinic end generated code: output=6f262537ce9c2dcc input=b6b5dee52a41b79f]*/ { - Py_ssize_t new_size; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n:resize", &new_size) || - !is_resizeable(self)) { + if (!is_resizeable(self)) { return NULL; } if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { @@ -882,13 +978,15 @@ mmap_resize_method(PyObject *op, PyObject *args) #endif /* MS_WINDOWS */ #ifdef UNIX -#ifndef HAVE_MREMAP - PyErr_SetString(PyExc_SystemError, - "mmap: resizing not available--no mremap()"); - return NULL; -#else void *newmap; +#ifdef __linux__ + if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) { + PyErr_Format(PyExc_ValueError, + "mmap: can't expand a shared anonymous mapping on Linux"); + return NULL; + } +#endif if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -911,28 +1009,43 @@ mmap_resize_method(PyObject *op, PyObject *args) self->data = newmap; self->size = new_size; Py_RETURN_NONE; -#endif /* HAVE_MREMAP */ #endif /* UNIX */ } } +#endif /* MS_WINDOWS || HAVE_MREMAP */ + +/*[clinic input] +@critical_section +mmap.mmap.tell + +[clinic start generated code]*/ static PyObject * -mmap_tell_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_tell_impl(mmap_object *self) +/*[clinic end generated code: output=6034958630e1b1d1 input=fd163acacf45c3a5]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); return PyLong_FromSize_t(self->pos); } +/*[clinic input] +@critical_section +mmap.mmap.flush + + offset: Py_ssize_t = 0 + size: Py_ssize_t = -1 + / + +[clinic start generated code]*/ + static PyObject * -mmap_flush_method(PyObject *op, PyObject *args) +mmap_mmap_flush_impl(mmap_object *self, Py_ssize_t offset, Py_ssize_t size) +/*[clinic end generated code: output=956ced67466149cf input=c50b893bc69520ec]*/ { - Py_ssize_t offset = 0; - mmap_object *self = mmap_object_CAST(op); - Py_ssize_t size = self->size; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) - return NULL; + if (size == -1) { + size = self->size - offset; + } if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; @@ -960,60 +1073,80 @@ mmap_flush_method(PyObject *op, PyObject *args) #endif } +/*[clinic input] +@critical_section +mmap.mmap.seek + + pos as dist: Py_ssize_t + whence as how: int = 0 + / + +[clinic start generated code]*/ + static PyObject * -mmap_seek_method(PyObject *op, PyObject *args) +mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how) +/*[clinic end generated code: output=00310494e8b8c592 input=e2fda5d081c3db22]*/ { - Py_ssize_t dist; - mmap_object *self = mmap_object_CAST(op); - int how=0; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) - return NULL; - else { - Py_ssize_t where; - switch (how) { - case 0: /* relative to start */ - where = dist; - break; - case 1: /* relative to current position */ - if (PY_SSIZE_T_MAX - self->pos < dist) - goto onoutofrange; - where = self->pos + dist; - break; - case 2: /* relative to end */ - if (PY_SSIZE_T_MAX - self->size < dist) - goto onoutofrange; - where = self->size + dist; - break; - default: - PyErr_SetString(PyExc_ValueError, "unknown seek type"); - return NULL; - } - if (where > self->size || where < 0) + Py_ssize_t where; + switch (how) { + case 0: /* relative to start */ + where = dist; + break; + case 1: /* relative to current position */ + if (PY_SSIZE_T_MAX - self->pos < dist) goto onoutofrange; - self->pos = where; - return PyLong_FromSsize_t(self->pos); + where = self->pos + dist; + break; + case 2: /* relative to end */ + if (PY_SSIZE_T_MAX - self->size < dist) + goto onoutofrange; + where = self->size + dist; + break; + default: + PyErr_SetString(PyExc_ValueError, "unknown seek type"); + return NULL; } + if (where > self->size || where < 0) + goto onoutofrange; + self->pos = where; + return PyLong_FromSsize_t(self->pos); onoutofrange: PyErr_SetString(PyExc_ValueError, "seek out of range"); return NULL; } +/*[clinic input] +mmap.mmap.seekable + +[clinic start generated code]*/ + static PyObject * -mmap_seekable_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_seekable_impl(mmap_object *self) +/*[clinic end generated code: output=6311dc3ea300fa38 input=5132505f6e259001]*/ { Py_RETURN_TRUE; } +/*[clinic input] +@critical_section +mmap.mmap.move + + dest: Py_ssize_t + src: Py_ssize_t + count as cnt: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -mmap_move_method(PyObject *op, PyObject *args) +mmap_mmap_move_impl(mmap_object *self, Py_ssize_t dest, Py_ssize_t src, + Py_ssize_t cnt) +/*[clinic end generated code: output=391f549a44181793 input=cf8cfe10d9f6b448]*/ { - Py_ssize_t dest, src, cnt; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || - !is_writable(self)) { + if (!is_writable(self)) { return NULL; } else { /* bounds check the values */ @@ -1039,30 +1172,53 @@ static PyObject * mmap_closed_get(PyObject *op, void *Py_UNUSED(closure)) { mmap_object *self = mmap_object_CAST(op); + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); #ifdef MS_WINDOWS - return PyBool_FromLong(self->map_handle == NULL ? 1 : 0); + result = PyBool_FromLong(self->map_handle == NULL ? 1 : 0); #elif defined(UNIX) - return PyBool_FromLong(self->data == NULL ? 1 : 0); + result = PyBool_FromLong(self->data == NULL ? 1 : 0); #endif + Py_END_CRITICAL_SECTION(); + return result; } +/*[clinic input] +@critical_section +mmap.mmap.__enter__ + +[clinic start generated code]*/ + static PyObject * -mmap__enter__method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap___enter___impl(mmap_object *self) +/*[clinic end generated code: output=92cfc59f4c4e2d26 input=a446541fbfe0b890]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); return Py_NewRef(self); } +/*[clinic input] +@critical_section +mmap.mmap.__exit__ + + exc_type: object + exc_value: object + traceback: object + / + +[clinic start generated code]*/ + static PyObject * -mmap__exit__method(PyObject *op, PyObject *Py_UNUSED(args)) +mmap_mmap___exit___impl(mmap_object *self, PyObject *exc_type, + PyObject *exc_value, PyObject *traceback) +/*[clinic end generated code: output=bec7e3e319c1f07e input=5f28e91cf752bc64]*/ { - return mmap_close_method(op, NULL); + return mmap_mmap_close_impl(self); } static PyObject * -mmap__repr__method(PyObject *op) +mmap__repr__method_lock_held(PyObject *op) { mmap_object *mobj = mmap_object_CAST(op); @@ -1106,11 +1262,27 @@ mmap__repr__method(PyObject *op) } } -#ifdef MS_WINDOWS static PyObject * -mmap__sizeof__method(PyObject *op, PyObject *Py_UNUSED(dummy)) +mmap__repr__method(PyObject *op) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap__repr__method_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + +#ifdef MS_WINDOWS +/*[clinic input] +@critical_section +mmap.mmap.__sizeof__ + +[clinic start generated code]*/ + +static PyObject * +mmap_mmap___sizeof___impl(mmap_object *self) +/*[clinic end generated code: output=1aed30daff807d09 input=8a648868a089553c]*/ { - mmap_object *self = mmap_object_CAST(op); size_t res = _PyObject_SIZE(Py_TYPE(self)); if (self->tagname) { res += (wcslen(self->tagname) + 1) * sizeof(self->tagname[0]); @@ -1120,18 +1292,26 @@ mmap__sizeof__method(PyObject *op, PyObject *Py_UNUSED(dummy)) #endif #if defined(MS_WINDOWS) && defined(Py_DEBUG) +/*[clinic input] +@critical_section +mmap.mmap._protect + + flNewProtect: unsigned_int(bitwise=True) + start: Py_ssize_t + length: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -mmap_protect_method(PyObject *op, PyObject *args) { - DWORD flNewProtect, flOldProtect; - Py_ssize_t start, length; - mmap_object *self = mmap_object_CAST(op); +mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, + Py_ssize_t start, Py_ssize_t length) +/*[clinic end generated code: output=a87271a34d1ad6cf input=9170498c5e1482da]*/ +{ + DWORD flOldProtect; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "Inn:protect", &flNewProtect, &start, &length)) { - return NULL; - } - if (!VirtualProtect((void *) (self->data + start), length, flNewProtect, &flOldProtect)) { @@ -1144,18 +1324,32 @@ mmap_protect_method(PyObject *op, PyObject *args) { #endif #ifdef HAVE_MADVISE +/*[clinic input] +@critical_section +mmap.mmap.madvise + + option: int + start: Py_ssize_t = 0 + length as length_obj: object = None + / + +[clinic start generated code]*/ + static PyObject * -mmap_madvise_method(PyObject *op, PyObject *args) +mmap_mmap_madvise_impl(mmap_object *self, int option, Py_ssize_t start, + PyObject *length_obj) +/*[clinic end generated code: output=816be656f08c0e3c input=2d37f7a4c87f1053]*/ { - int option; - Py_ssize_t start = 0, length; - mmap_object *self = mmap_object_CAST(op); + Py_ssize_t length; CHECK_VALID(NULL); - length = self->size; - - if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) { - return NULL; + if (length_obj == Py_None) { + length = self->size; + } else { + length = _As_Py_ssize_t(length_obj); + if (length == -1 && PyErr_Occurred()) { + return NULL; + } } if (start < 0 || start >= self->size) { @@ -1191,32 +1385,26 @@ static struct PyMemberDef mmap_object_members[] = { }; static struct PyMethodDef mmap_object_methods[] = { - {"close", mmap_close_method, METH_NOARGS}, - {"find", mmap_find_method, METH_VARARGS}, - {"rfind", mmap_rfind_method, METH_VARARGS}, - {"flush", mmap_flush_method, METH_VARARGS}, -#ifdef HAVE_MADVISE - {"madvise", mmap_madvise_method, METH_VARARGS}, -#endif - {"move", mmap_move_method, METH_VARARGS}, - {"read", mmap_read_method, METH_VARARGS}, - {"read_byte", mmap_read_byte_method, METH_NOARGS}, - {"readline", mmap_read_line_method, METH_NOARGS}, - {"resize", mmap_resize_method, METH_VARARGS}, - {"seek", mmap_seek_method, METH_VARARGS}, - {"seekable", mmap_seekable_method, METH_NOARGS}, - {"size", mmap_size_method, METH_NOARGS}, - {"tell", mmap_tell_method, METH_NOARGS}, - {"write", mmap_write_method, METH_VARARGS}, - {"write_byte", mmap_write_byte_method, METH_VARARGS}, - {"__enter__", mmap__enter__method, METH_NOARGS}, - {"__exit__", mmap__exit__method, METH_VARARGS}, -#ifdef MS_WINDOWS - {"__sizeof__", mmap__sizeof__method, METH_NOARGS}, -#ifdef Py_DEBUG - {"_protect", mmap_protect_method, METH_VARARGS}, -#endif // Py_DEBUG -#endif // MS_WINDOWS + MMAP_MMAP_CLOSE_METHODDEF + MMAP_MMAP_FIND_METHODDEF + MMAP_MMAP_RFIND_METHODDEF + MMAP_MMAP_FLUSH_METHODDEF + MMAP_MMAP_MADVISE_METHODDEF + MMAP_MMAP_MOVE_METHODDEF + MMAP_MMAP_READ_METHODDEF + MMAP_MMAP_READ_BYTE_METHODDEF + MMAP_MMAP_READLINE_METHODDEF + MMAP_MMAP_RESIZE_METHODDEF + MMAP_MMAP_SEEK_METHODDEF + MMAP_MMAP_SEEKABLE_METHODDEF + MMAP_MMAP_SIZE_METHODDEF + MMAP_MMAP_TELL_METHODDEF + MMAP_MMAP_WRITE_METHODDEF + MMAP_MMAP_WRITE_BYTE_METHODDEF + MMAP_MMAP___ENTER___METHODDEF + MMAP_MMAP___EXIT___METHODDEF + MMAP_MMAP___SIZEOF___METHODDEF + MMAP_MMAP__PROTECT_METHODDEF {NULL, NULL} /* sentinel */ }; @@ -1229,7 +1417,7 @@ static PyGetSetDef mmap_object_getset[] = { /* Functions for treating an mmap'ed file as a buffer */ static int -mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) +mmap_buffer_getbuf_lock_held(PyObject *op, Py_buffer *view, int flags) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(-1); @@ -1240,23 +1428,45 @@ mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) return 0; } +static int +mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) +{ + int result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_buffer_getbuf_lock_held(op, view, flags); + Py_END_CRITICAL_SECTION(); + return result; +} + static void mmap_buffer_releasebuf(PyObject *op, Py_buffer *Py_UNUSED(view)) { mmap_object *self = mmap_object_CAST(op); + Py_BEGIN_CRITICAL_SECTION(self); self->exports--; + Py_END_CRITICAL_SECTION(); } static Py_ssize_t -mmap_length(PyObject *op) +mmap_length_lock_held(PyObject *op) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(-1); return self->size; } +static Py_ssize_t +mmap_length(PyObject *op) +{ + Py_ssize_t result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_length_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + static PyObject * -mmap_item(PyObject *op, Py_ssize_t i) +mmap_item_lock_held(PyObject *op, Py_ssize_t i) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -1273,7 +1483,16 @@ mmap_item(PyObject *op, Py_ssize_t i) } static PyObject * -mmap_subscript(PyObject *op, PyObject *item) +mmap_item(PyObject *op, Py_ssize_t i) { + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_item_lock_held(op, i); + Py_END_CRITICAL_SECTION(); + return result; +} + +static PyObject * +mmap_subscript_lock_held(PyObject *op, PyObject *item) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -1335,8 +1554,18 @@ mmap_subscript(PyObject *op, PyObject *item) } } +static PyObject * +mmap_subscript(PyObject *op, PyObject *item) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_subscript_lock_held(op, item); + Py_END_CRITICAL_SECTION(); + return result; +} + static int -mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) +mmap_ass_item_lock_held(PyObject *op, Py_ssize_t i, PyObject *v) { const char *buf; mmap_object *self = mmap_object_CAST(op); @@ -1367,7 +1596,17 @@ mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) } static int -mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) +mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) +{ + int result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_ass_item_lock_held(op, i, v); + Py_END_CRITICAL_SECTION(); + return result; +} + +static int +mmap_ass_subscript_lock_held(PyObject *op, PyObject *item, PyObject *value) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(-1); @@ -1463,11 +1702,21 @@ mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) } } +static int +mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) +{ + int result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_ass_subscript_lock_held(op, item, value); + Py_END_CRITICAL_SECTION(); + return result; +} + static PyObject * new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict); PyDoc_STRVAR(mmap_doc, -"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\ +"Windows: mmap(fileno, length[, tagname[, access[, offset[, trackfd]]]])\n\ \n\ Maps length bytes from the file specified by the file handle fileno,\n\ and returns a mmap object. If length is larger than the current size\n\ @@ -1499,7 +1748,7 @@ static PyType_Slot mmap_object_slots[] = { {Py_tp_members, mmap_object_members}, {Py_tp_getset, mmap_object_getset}, {Py_tp_getattro, PyObject_GenericGetAttr}, - {Py_tp_traverse, mmap_object_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, /* as sequence */ {Py_sq_length, mmap_length}, @@ -1685,6 +1934,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) else { m_obj->fd = -1; } + m_obj->flags = flags; Py_BEGIN_ALLOW_THREADS m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset); @@ -1702,6 +1952,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) PyErr_SetFromErrno(PyExc_OSError); return NULL; } + _PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap"); m_obj->access = (access_mode)access; return (PyObject *)m_obj; } @@ -1727,16 +1978,17 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) PyObject *tagname = Py_None; DWORD dwErr = 0; int fileno; - HANDLE fh = 0; + HANDLE fh = INVALID_HANDLE_VALUE; int access = (access_mode)ACCESS_DEFAULT; + int trackfd = 1; DWORD flProtect, dwDesiredAccess; static char *keywords[] = { "fileno", "length", "tagname", - "access", "offset", NULL }; + "access", "offset", "trackfd", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|OiL", keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|OiL$p", keywords, &fileno, &map_size, - &tagname, &access, &offset)) { + &tagname, &access, &offset, &trackfd)) { return NULL; } @@ -1803,22 +2055,27 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) m_obj->map_handle = NULL; m_obj->tagname = NULL; m_obj->offset = offset; + m_obj->trackfd = trackfd; - if (fh) { - /* It is necessary to duplicate the handle, so the - Python code can close it on us */ - if (!DuplicateHandle( - GetCurrentProcess(), /* source process handle */ - fh, /* handle to be duplicated */ - GetCurrentProcess(), /* target proc handle */ - (LPHANDLE)&m_obj->file_handle, /* result */ - 0, /* access - ignored due to options value */ - FALSE, /* inherited by child processes? */ - DUPLICATE_SAME_ACCESS)) { /* options */ - dwErr = GetLastError(); - Py_DECREF(m_obj); - PyErr_SetFromWindowsErr(dwErr); - return NULL; + if (fh != INVALID_HANDLE_VALUE) { + if (trackfd) { + /* It is necessary to duplicate the handle, so the + Python code can close it on us */ + if (!DuplicateHandle( + GetCurrentProcess(), /* source process handle */ + fh, /* handle to be duplicated */ + GetCurrentProcess(), /* target proc handle */ + &fh, /* result */ + 0, /* access - ignored due to options value */ + FALSE, /* inherited by child processes? */ + DUPLICATE_SAME_ACCESS)) /* options */ + { + dwErr = GetLastError(); + Py_DECREF(m_obj); + PyErr_SetFromWindowsErr(dwErr); + return NULL; + } + m_obj->file_handle = fh; } if (!map_size) { DWORD low,high; @@ -1826,7 +2083,8 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) /* low might just happen to have the value INVALID_FILE_SIZE; so we need to check the last error also. */ if (low == INVALID_FILE_SIZE && - (dwErr = GetLastError()) != NO_ERROR) { + (dwErr = GetLastError()) != NO_ERROR) + { Py_DECREF(m_obj); return PyErr_SetFromWindowsErr(dwErr); } @@ -1888,7 +2146,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) off_lo = (DWORD)(offset & 0xFFFFFFFF); /* For files, it would be sufficient to pass 0 as size. For anonymous maps, we have to pass the size explicitly. */ - m_obj->map_handle = CreateFileMappingW(m_obj->file_handle, + m_obj->map_handle = CreateFileMappingW(fh, NULL, flProtect, size_hi, diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 27cb8adc55f..221cfc5a934 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -40,6 +40,7 @@ // --- System includes ------------------------------------------------------ +#include <stddef.h> // offsetof() #include <stdio.h> // ctermid() #include <stdlib.h> // system() @@ -408,6 +409,31 @@ extern char *ctermid_r(char *); # define STRUCT_STAT struct stat #endif +#ifdef HAVE_STATX +/* until we can assume glibc 2.28 at runtime, we must weakly link */ +# pragma weak statx +static const unsigned int _Py_STATX_KNOWN = (STATX_BASIC_STATS | STATX_BTIME +#ifdef STATX_MNT_ID + | STATX_MNT_ID +#endif +#ifdef STATX_DIOALIGN + | STATX_DIOALIGN +#endif +#ifdef STATX_MNT_ID_UNIQUE + | STATX_MNT_ID_UNIQUE +#endif +#ifdef STATX_SUBVOL + | STATX_SUBVOL +#endif +#ifdef STATX_WRITE_ATOMIC + | STATX_WRITE_ATOMIC +#endif +#ifdef STATX_DIO_READ_ALIGN + | STATX_DIO_READ_ALIGN +#endif + ); +#endif /* HAVE_STATX */ + #if !defined(EX_OK) && defined(EXIT_SUCCESS) # define EX_OK EXIT_SUCCESS @@ -686,7 +712,15 @@ reset_remotedebug_data(PyThreadState *tstate) { tstate->remote_debugger_support.debugger_pending_call = 0; memset(tstate->remote_debugger_support.debugger_script_path, 0, - Py_MAX_SCRIPT_PATH_SIZE); + _Py_MAX_SCRIPT_PATH_SIZE); +} + +static void +reset_asyncio_state(_PyThreadStateImpl *tstate) +{ + llist_init(&tstate->asyncio_tasks_head); + tstate->asyncio_running_loop = NULL; + tstate->asyncio_running_task = NULL; } @@ -725,6 +759,8 @@ PyOS_AfterFork_Child(void) reset_remotedebug_data(tstate); + reset_asyncio_state((_PyThreadStateImpl *)tstate); + // Remove the dead thread states. We "start the world" once we are the only // thread state left to undo the stop the world call in `PyOS_BeforeFork`. // That needs to happen before `_PyThreadState_DeleteList`, because that @@ -1159,6 +1195,9 @@ typedef struct { #endif newfunc statresult_new_orig; PyObject *StatResultType; +#ifdef HAVE_STATX + PyObject *StatxResultType; +#endif PyObject *StatVFSResultType; PyObject *TerminalSizeType; PyObject *TimesResultType; @@ -2432,7 +2471,7 @@ static PyStructSequence_Field stat_result_fields[] = { #endif static PyStructSequence_Desc stat_result_desc = { - "stat_result", /* name */ + "os.stat_result", /* name; see issue gh-63408 */ stat_result__doc__, /* doc */ stat_result_fields, 10 @@ -2462,7 +2501,7 @@ static PyStructSequence_Field statvfs_result_fields[] = { }; static PyStructSequence_Desc statvfs_result_desc = { - "statvfs_result", /* name */ + "os.statvfs_result", /* name; see issue gh-63408 */ statvfs_result__doc__, /* doc */ statvfs_result_fields, 10 @@ -2487,7 +2526,7 @@ static PyStructSequence_Field waitid_result_fields[] = { }; static PyStructSequence_Desc waitid_result_desc = { - "waitid_result", /* name */ + MODNAME ".waitid_result", /* name */ waitid_result__doc__, /* doc */ waitid_result_fields, 5 @@ -2539,6 +2578,9 @@ _posix_clear(PyObject *module) Py_CLEAR(state->SchedParamType); #endif Py_CLEAR(state->StatResultType); +#ifdef HAVE_STATX + Py_CLEAR(state->StatxResultType); +#endif Py_CLEAR(state->StatVFSResultType); Py_CLEAR(state->TerminalSizeType); Py_CLEAR(state->TimesResultType); @@ -2564,6 +2606,9 @@ _posix_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->SchedParamType); #endif Py_VISIT(state->StatResultType); +#ifdef HAVE_STATX + Py_VISIT(state->StatxResultType); +#endif Py_VISIT(state->StatVFSResultType); Py_VISIT(state->TerminalSizeType); Py_VISIT(state->TimesResultType); @@ -2584,60 +2629,79 @@ _posix_free(void *module) _posix_clear((PyObject *)module); } + +#define SEC_TO_NS (1000000000LL) +static PyObject * +stat_nanosecond_timestamp(_posixstate *state, time_t sec, unsigned long nsec) +{ +#if SIZEOF_TIME_T == 4 + return PyLong_FromLongLong(sec * SEC_TO_NS + nsec); +#else + /* 1677-09-21 00:12:44 to 2262-04-11 23:47:15 UTC inclusive */ + if ((LLONG_MIN/SEC_TO_NS) <= sec && sec <= (LLONG_MAX/SEC_TO_NS - 1)) { + return PyLong_FromLongLong(sec * SEC_TO_NS + nsec); + } + else + { + PyObject *ns_total = NULL; + PyObject *s_in_ns = NULL; + PyObject *s = _PyLong_FromTime_t(sec); + PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); + if (s == NULL || ns_fractional == NULL) { + goto exit; + } + + s_in_ns = PyNumber_Multiply(s, state->billion); + if (s_in_ns == NULL) { + goto exit; + } + + ns_total = PyNumber_Add(s_in_ns, ns_fractional); + + exit: + Py_XDECREF(s); + Py_XDECREF(ns_fractional); + Py_XDECREF(s_in_ns); + return ns_total; + } +#endif +} + static int -fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec) +fill_time(_posixstate *state, PyObject *v, int s_index, int f_index, + int ns_index, time_t sec, unsigned long nsec) { assert(!PyErr_Occurred()); - - int res = -1; - PyObject *s_in_ns = NULL; - PyObject *ns_total = NULL; - PyObject *float_s = NULL; - - PyObject *s = _PyLong_FromTime_t(sec); - PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); - if (!(s && ns_fractional)) { - goto exit; - } - - s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion); - if (!s_in_ns) { - goto exit; - } - - ns_total = PyNumber_Add(s_in_ns, ns_fractional); - if (!ns_total) - goto exit; - - float_s = PyFloat_FromDouble(sec + 1e-9*nsec); - if (!float_s) { - goto exit; - } + assert(nsec < SEC_TO_NS); if (s_index >= 0) { + PyObject *s = _PyLong_FromTime_t(sec); + if (s == NULL) { + return -1; + } PyStructSequence_SET_ITEM(v, s_index, s); - s = NULL; } + if (f_index >= 0) { + PyObject *float_s = PyFloat_FromDouble((double)sec + 1e-9 * nsec); + if (float_s == NULL) { + return -1; + } PyStructSequence_SET_ITEM(v, f_index, float_s); - float_s = NULL; } + if (ns_index >= 0) { + PyObject *ns_total = stat_nanosecond_timestamp(state, sec, nsec); + if (ns_total == NULL) { + return -1; + } PyStructSequence_SET_ITEM(v, ns_index, ns_total); - ns_total = NULL; } assert(!PyErr_Occurred()); - res = 0; - -exit: - Py_XDECREF(s); - Py_XDECREF(ns_fractional); - Py_XDECREF(s_in_ns); - Py_XDECREF(ns_total); - Py_XDECREF(float_s); - return res; + return 0; } +#undef SEC_TO_NS #ifdef MS_WINDOWS static PyObject* @@ -2673,7 +2737,8 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) { assert(!PyErr_Occurred()); - PyObject *StatResultType = get_posix_state(module)->StatResultType; + _posixstate *state = get_posix_state(module); + PyObject *StatResultType = state->StatResultType; PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType); if (v == NULL) { return NULL; @@ -2727,13 +2792,13 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) #else ansec = mnsec = cnsec = 0; #endif - if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) { + if (fill_time(state, v, 7, 10, 13, st->st_atime, ansec) < 0) { goto error; } - if (fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec) < 0) { + if (fill_time(state, v, 8, 11, 14, st->st_mtime, mnsec) < 0) { goto error; } - if (fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec) < 0) { + if (fill_time(state, v, 9, 12, 15, st->st_ctime, cnsec) < 0) { goto error; } @@ -2744,7 +2809,7 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks)); #endif #ifdef HAVE_STRUCT_STAT_ST_RDEV - SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev)); + SET_ITEM(ST_RDEV_IDX, _PyLong_FromDev(st->st_rdev)); #endif #ifdef HAVE_STRUCT_STAT_ST_GEN SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen)); @@ -2761,7 +2826,7 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9)); } #elif defined(MS_WINDOWS) - if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, + if (fill_time(state, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, st->st_birthtime, st->st_birthtime_nsec) < 0) { goto error; } @@ -3122,17 +3187,6 @@ class dev_t_return_converter(unsigned_long_return_converter): conversion_fn = '_PyLong_FromDev' unsigned_cast = '(dev_t)' -class FSConverter_converter(CConverter): - type = 'PyObject *' - converter = 'PyUnicode_FSConverter' - def converter_init(self): - if self.default is not unspecified: - fail("FSConverter_converter does not support default values") - self.c_default = 'NULL' - - def cleanup(self): - return "Py_XDECREF(" + self.name + ");\n" - class pid_t_converter(CConverter): type = 'pid_t' format_unit = '" _Py_PARSE_PID "' @@ -3196,7 +3250,7 @@ class confname_converter(CConverter): """, argname=argname, converter=self.converter, table=self.table) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=8189d5ae78244626]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d2759f2332cd39b3]*/ /*[clinic input] @@ -3262,6 +3316,385 @@ os_lstat_impl(PyObject *module, path_t *path, int dir_fd) } +#ifdef HAVE_STATX +typedef struct { + PyObject_HEAD + dev_t rdev, dev; + struct statx stx; +} Py_statx_result; + +#define Py_statx_result_CAST(op) _Py_CAST(Py_statx_result*, (op)) + +#define M(attr, type, offset, doc) \ + {attr, type, offset, Py_READONLY, PyDoc_STR(doc)} +#define MM(attr, type, member, doc) \ + M(#attr, type, offsetof(Py_statx_result, stx.stx_##member), doc) +#define MX(attr, type, member, doc) \ + M(#attr, type, offsetof(Py_statx_result, member), doc) + +static PyMemberDef pystatx_result_members[] = { + MM(stx_mask, Py_T_UINT, mask, "member validity mask"), + MM(stx_blksize, Py_T_UINT, blksize, "blocksize for filesystem I/O"), + MM(stx_attributes, Py_T_ULONGLONG, attributes, "Linux inode attribute bits"), + MM(stx_attributes_mask, Py_T_ULONGLONG, attributes_mask, + "Mask of supported bits in stx_attributes"), + MM(stx_rdev_major, Py_T_UINT, rdev_major, "represented device major number"), + MM(stx_rdev_minor, Py_T_UINT, rdev_minor, "represented device minor number"), + MX(stx_rdev, Py_T_ULONGLONG, rdev, "device type (if inode device)"), + MM(stx_dev_major, Py_T_UINT, dev_major, "containing device major number"), + MM(stx_dev_minor, Py_T_UINT, dev_minor, "containing device minor number"), + MX(stx_dev, Py_T_ULONGLONG, dev, "device"), + {NULL}, +}; + +#undef MX +#undef MM +#undef M + + +#define STATX_GET_UINT(ATTR, MASK) \ + static PyObject* \ + pystatx_result_get_##ATTR(PyObject *op, void *Py_UNUSED(context)) \ + { \ + Py_statx_result *self = Py_statx_result_CAST(op); \ + if (!(self->stx.stx_mask & MASK)) { \ + Py_RETURN_NONE; \ + } \ + unsigned long value = self->stx.ATTR; \ + return PyLong_FromUnsignedLong(value); \ + } + +STATX_GET_UINT(stx_uid, STATX_UID) +STATX_GET_UINT(stx_gid, STATX_GID) +STATX_GET_UINT(stx_nlink, STATX_NLINK) +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN +STATX_GET_UINT(stx_dio_mem_align, STATX_DIOALIGN) +STATX_GET_UINT(stx_dio_offset_align, STATX_DIOALIGN) +#endif +#ifdef HAVE_STRUCT_STATX_STX_DIO_READ_OFFSET_ALIGN +STATX_GET_UINT(stx_dio_read_offset_align, STATX_DIO_READ_ALIGN) +#endif +#ifdef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MIN +STATX_GET_UINT(stx_atomic_write_unit_min, STATX_WRITE_ATOMIC) +STATX_GET_UINT(stx_atomic_write_unit_max, STATX_WRITE_ATOMIC) +STATX_GET_UINT(stx_atomic_write_segments_max, STATX_WRITE_ATOMIC) +#endif +#ifdef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT +STATX_GET_UINT(stx_atomic_write_unit_max_opt, STATX_WRITE_ATOMIC) +#endif + + +static PyObject* +pystatx_result_get_stx_mode(PyObject *op, void *Py_UNUSED(context)) +{ + Py_statx_result *self = Py_statx_result_CAST(op); + if (!(self->stx.stx_mask & (STATX_TYPE | STATX_MODE))) { + Py_RETURN_NONE; + } + return PyLong_FromUnsignedLong(self->stx.stx_mode); +} + + +#define STATX_GET_ULONGLONG(ATTR, MASK) \ + static PyObject* \ + pystatx_result_get_##ATTR(PyObject *op, void *Py_UNUSED(context)) \ + { \ + Py_statx_result *self = Py_statx_result_CAST(op); \ + if (!(self->stx.stx_mask & MASK)) { \ + Py_RETURN_NONE; \ + } \ + unsigned long long value = self->stx.ATTR; \ + return PyLong_FromUnsignedLongLong(value); \ + } + +STATX_GET_ULONGLONG(stx_blocks, STATX_BLOCKS) +STATX_GET_ULONGLONG(stx_ino, STATX_INO) +STATX_GET_ULONGLONG(stx_size, STATX_SIZE) +#if defined(STATX_MNT_ID) && defined(HAVE_STRUCT_STATX_STX_MNT_ID) +STATX_GET_ULONGLONG(stx_mnt_id, STATX_MNT_ID) +#endif +#if defined(STATX_SUBVOL) && defined(HAVE_STRUCT_STATX_STX_SUBVOL) +STATX_GET_ULONGLONG(stx_subvol, STATX_SUBVOL) +#endif + + +#define STATX_GET_DOUBLE(ATTR, MASK) \ + static PyObject* \ + pystatx_result_get_##ATTR(PyObject *op, void *Py_UNUSED(context)) \ + { \ + Py_statx_result *self = Py_statx_result_CAST(op); \ + if (!(self->stx.stx_mask & MASK)) { \ + Py_RETURN_NONE; \ + } \ + struct statx_timestamp *ts = &self->stx.ATTR; \ + double sec = ((double)ts->tv_sec + ts->tv_nsec * 1e-9); \ + return PyFloat_FromDouble(sec); \ + } + +STATX_GET_DOUBLE(stx_atime, STATX_ATIME) +STATX_GET_DOUBLE(stx_btime, STATX_BTIME) +STATX_GET_DOUBLE(stx_ctime, STATX_CTIME) +STATX_GET_DOUBLE(stx_mtime, STATX_MTIME) + +#define STATX_GET_NSEC(ATTR, MEMBER, MASK) \ + static PyObject* \ + pystatx_result_get_##ATTR(PyObject *op, void *context) \ + { \ + Py_statx_result *self = Py_statx_result_CAST(op); \ + if (!(self->stx.stx_mask & MASK)) { \ + Py_RETURN_NONE; \ + } \ + struct statx_timestamp *ts = &self->stx.MEMBER; \ + _posixstate *state = PyType_GetModuleState(Py_TYPE(op)); \ + assert(state != NULL); \ + return stat_nanosecond_timestamp(state, ts->tv_sec, ts->tv_nsec); \ + } + +STATX_GET_NSEC(stx_atime_ns, stx_atime, STATX_ATIME) +STATX_GET_NSEC(stx_btime_ns, stx_btime, STATX_BTIME) +STATX_GET_NSEC(stx_ctime_ns, stx_ctime, STATX_CTIME) +STATX_GET_NSEC(stx_mtime_ns, stx_mtime, STATX_MTIME) + +#define G(attr, doc) \ + {#attr, pystatx_result_get_##attr, NULL, PyDoc_STR(doc), NULL} + +static PyGetSetDef pystatx_result_getset[] = { + G(stx_mode, "protection bits"), + G(stx_nlink, "number of hard links"), + G(stx_uid, "user ID of owner"), + G(stx_gid, "group ID of owner"), + G(stx_ino, "inode"), + G(stx_size, "total size, in bytes"), + G(stx_blocks, "number of blocks allocated"), + G(stx_atime, "time of last access"), + G(stx_atime_ns, "time of last access in nanoseconds"), + G(stx_btime, "time of creation"), + G(stx_btime_ns, "time of creation in nanoseconds"), + G(stx_ctime, "time of last change"), + G(stx_ctime_ns, "time of last change in nanoseconds"), + G(stx_mtime, "time of last modification"), + G(stx_mtime_ns, "time of last modification in nanoseconds"), +#if defined(STATX_MNT_ID) && defined(HAVE_STRUCT_STATX_STX_MNT_ID) + G(stx_mnt_id, "mount ID"), +#endif +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + G(stx_dio_mem_align, "direct I/O memory buffer alignment"), + G(stx_dio_offset_align, "direct I/O file offset alignment"), +#endif +#if defined(STATX_SUBVOL) && defined(HAVE_STRUCT_STATX_STX_SUBVOL) + G(stx_subvol, "subvolume ID"), +#endif +#ifdef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MIN + G(stx_atomic_write_unit_min, + "minimum size for direct I/O with torn-write protection"), + G(stx_atomic_write_unit_max, + "maximum size for direct I/O with torn-write protection"), + G(stx_atomic_write_segments_max, + "maximum iovecs for direct I/O with torn-write protection"), +#endif +#ifdef HAVE_STRUCT_STATX_STX_DIO_READ_OFFSET_ALIGN + G(stx_dio_read_offset_align, "direct I/O file offset alignment for reads"), +#endif +#ifdef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT + G(stx_atomic_write_unit_max_opt, + "maximum optimized size for direct I/O with torn-write protection"), +#endif + {NULL}, +}; + +#undef G + +static PyObject * +pystatx_result_repr(PyObject *op) +{ + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (writer == NULL) { + return NULL; + } +#define WRITE_ASCII(s) \ + do { \ + if (PyUnicodeWriter_WriteASCII(writer, s, strlen(s)) < 0) { \ + goto error; \ + } \ + } while (0) + + WRITE_ASCII("os.statx_result("); + + for (size_t i = 0; i < Py_ARRAY_LENGTH(pystatx_result_members) - 1; ++i) { + if (i > 0) { + WRITE_ASCII(", "); + } + + PyMemberDef *d = &pystatx_result_members[i]; + WRITE_ASCII(d->name); + WRITE_ASCII("="); + + PyObject *o = PyMember_GetOne((const char *)op, d); + if (o == NULL) { + goto error; + } + if (PyUnicodeWriter_WriteRepr(writer, o) < 0) { + Py_DECREF(o); + goto error; + } + Py_DECREF(o); + } + + for (size_t i = 0; i < Py_ARRAY_LENGTH(pystatx_result_getset) - 1; ++i) { + PyGetSetDef *d = &pystatx_result_getset[i]; + PyObject *o = d->get(op, d->closure); + if (o == NULL) { + goto error; + } + if (o == Py_None) { + continue; + } + + WRITE_ASCII(", "); + WRITE_ASCII(d->name); + WRITE_ASCII("="); + if (PyUnicodeWriter_WriteRepr(writer, o) < 0) { + Py_DECREF(o); + goto error; + } + Py_DECREF(o); + } + + WRITE_ASCII(")"); + return PyUnicodeWriter_Finish(writer); +#undef WRITE_ASCII + +error: + PyUnicodeWriter_Discard(writer); + return NULL; +} + +static int +pystatx_result_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +pystatx_result_dealloc(PyObject *op) +{ + Py_statx_result *self = (Py_statx_result *) op; + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot pystatx_result_slots[] = { + {Py_tp_repr, pystatx_result_repr}, + {Py_tp_traverse, pystatx_result_traverse}, + {Py_tp_dealloc, pystatx_result_dealloc}, + {Py_tp_members, pystatx_result_members}, + {Py_tp_getset, pystatx_result_getset}, + {0, NULL}, +}; + +static PyType_Spec pystatx_result_spec = { + .name = "os.statx_result", + .basicsize = sizeof(Py_statx_result), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .slots = pystatx_result_slots, +}; + +/*[clinic input] + +os.statx + + path : path_t(allow_fd=True) + Path to be examined; can be string, bytes, a path-like object or + open-file-descriptor int. + + mask: unsigned_int(bitwise=True) + A bitmask of STATX_* constants defining the requested information. + + * + + flags: int = 0 + A bitmask of AT_NO_AUTOMOUNT and/or AT_STATX_* flags. + + dir_fd : dir_fd = None + If not None, it should be a file descriptor open to a directory, + and path should be a relative string; path will then be relative to + that directory. + + follow_symlinks: bool = True + If False, and the last element of the path is a symbolic link, + statx will examine the symbolic link itself instead of the file + the link points to. + +Perform a statx system call on the given path. + +It's an error to use dir_fd or follow_symlinks when specifying path as + an open file descriptor. + +[clinic start generated code]*/ + +static PyObject * +os_statx_impl(PyObject *module, path_t *path, unsigned int mask, int flags, + int dir_fd, int follow_symlinks) +/*[clinic end generated code: output=e3765979ac6fe15b input=f0116380c5dc4f2f]*/ +{ + if (path_and_dir_fd_invalid("statx", path, dir_fd) || + dir_fd_and_fd_invalid("statx", dir_fd, path->fd) || + fd_and_follow_symlinks_invalid("statx", path->fd, follow_symlinks)) { + return NULL; + } + + /* reject flags covered by kwargs, but allow unknown flags that may be + future AT_STATX_* extensions */ + if (flags & (AT_SYMLINK_NOFOLLOW | AT_SYMLINK_FOLLOW)) { + PyErr_Format(PyExc_ValueError, + "use follow_symlinks kwarg instead of AT_SYMLINK_* flag"); + return NULL; + } + if (flags & AT_EMPTY_PATH) { + PyErr_Format(PyExc_ValueError, + "use dir_fd kwarg instead of AT_EMPTY_PATH flag"); + return NULL; + } + + /* Future bits may refer to members beyond the current size of struct + statx, so we need to mask them off to prevent memory corruption. */ + mask &= _Py_STATX_KNOWN; + + _posixstate *state = get_posix_state(module); + PyTypeObject *tp = (PyTypeObject *)state->StatxResultType; + Py_statx_result *v = (Py_statx_result *)tp->tp_alloc(tp, 0); + if (v == NULL) { + return NULL; + } + + int result; + Py_BEGIN_ALLOW_THREADS + if (path->fd != -1) { + result = statx(path->fd, "", flags | AT_EMPTY_PATH, mask, &v->stx); + } + else { + result = statx(dir_fd, path->narrow, flags, mask, &v->stx); + } + Py_END_ALLOW_THREADS + + if (result != 0) { + Py_DECREF(v); + return path_error(path); + } + + v->rdev = makedev(v->stx.stx_rdev_major, v->stx.stx_rdev_minor); + v->dev = makedev(v->stx.stx_dev_major, v->stx.stx_dev_minor); + + assert(!PyErr_Occurred()); + return (PyObject *)v; +} +#endif /* HAVE_STATX */ + + /*[clinic input] os.access -> bool @@ -6120,14 +6553,14 @@ os_system_impl(PyObject *module, const wchar_t *command) /*[clinic input] os.system -> long - command: FSConverter + command: unicode_fs_encoded Execute the command in a subshell. [clinic start generated code]*/ static long os_system_impl(PyObject *module, PyObject *command) -/*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/ +/*[clinic end generated code: output=290fc437dd4f33a0 input=47c6f24b6dc92881]*/ { long result; const char *bytes = PyBytes_AsString(command); @@ -6663,7 +7096,7 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns, if (!PyTuple_CheckExact(times) || (PyTuple_Size(times) != 2)) { PyErr_SetString(PyExc_TypeError, "utime: 'times' must be either" - " a tuple of two ints or None"); + " a tuple of two numbers or None"); return NULL; } utime.now = 0; @@ -7470,7 +7903,7 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a if (argc < 1) { PyErr_Format(PyExc_ValueError, "%s: argv must not be empty", func_name); - return NULL; + goto exit; } if (!PyMapping_Check(env) && env != Py_None) { @@ -7998,53 +8431,19 @@ os_register_at_fork_impl(PyObject *module, PyObject *before, // running in the process. Best effort, silent if unable to count threads. // Constraint: Quick. Never overcounts. Never leaves an error set. // -// This should only be called from the parent process after +// This MUST only be called from the parent process after // PyOS_AfterFork_Parent(). static int -warn_about_fork_with_threads(const char* name) +warn_about_fork_with_threads( + const char* name, // Name of the API to use in the warning message. + const Py_ssize_t num_os_threads // Only trusted when >= 1. +) { // It's not safe to issue the warning while the world is stopped, because // other threads might be holding locks that we need, which would deadlock. assert(!_PyRuntime.stoptheworld.world_stopped); - // TODO: Consider making an `os` module API to return the current number - // of threads in the process. That'd presumably use this platform code but - // raise an error rather than using the inaccurate fallback. - Py_ssize_t num_python_threads = 0; -#if defined(__APPLE__) && defined(HAVE_GETPID) - mach_port_t macos_self = mach_task_self(); - mach_port_t macos_task; - if (task_for_pid(macos_self, getpid(), &macos_task) == KERN_SUCCESS) { - thread_array_t macos_threads; - mach_msg_type_number_t macos_n_threads; - if (task_threads(macos_task, &macos_threads, - &macos_n_threads) == KERN_SUCCESS) { - num_python_threads = macos_n_threads; - } - } -#elif defined(__linux__) - // Linux /proc/self/stat 20th field is the number of threads. - FILE* proc_stat = fopen("/proc/self/stat", "r"); - if (proc_stat) { - size_t n; - // Size chosen arbitrarily. ~60% more bytes than a 20th column index - // observed on the author's workstation. - char stat_line[160]; - n = fread(&stat_line, 1, 159, proc_stat); - stat_line[n] = '\0'; - fclose(proc_stat); - - char *saveptr = NULL; - char *field = strtok_r(stat_line, " ", &saveptr); - unsigned int idx; - for (idx = 19; idx && field; --idx) { - field = strtok_r(NULL, " ", &saveptr); - } - if (idx == 0 && field) { // found the 20th field - num_python_threads = atoi(field); // 0 on error - } - } -#endif + Py_ssize_t num_python_threads = num_os_threads; if (num_python_threads <= 0) { // Fall back to just the number our threading module knows about. // An incomplete view of the world, but better than nothing. @@ -8097,6 +8496,51 @@ warn_about_fork_with_threads(const char* name) } return 0; } + +// If this returns <= 0, we were unable to successfully use any OS APIs. +// Returns a positive number of threads otherwise. +static Py_ssize_t get_number_of_os_threads(void) +{ + // TODO: Consider making an `os` module API to return the current number + // of threads in the process. That'd presumably use this platform code but + // raise an error rather than using the inaccurate fallback. + Py_ssize_t num_python_threads = 0; +#if defined(__APPLE__) && defined(HAVE_GETPID) + mach_port_t macos_self = mach_task_self(); + mach_port_t macos_task; + if (task_for_pid(macos_self, getpid(), &macos_task) == KERN_SUCCESS) { + thread_array_t macos_threads; + mach_msg_type_number_t macos_n_threads; + if (task_threads(macos_task, &macos_threads, + &macos_n_threads) == KERN_SUCCESS) { + num_python_threads = macos_n_threads; + } + } +#elif defined(__linux__) + // Linux /proc/self/stat 20th field is the number of threads. + FILE* proc_stat = fopen("/proc/self/stat", "r"); + if (proc_stat) { + size_t n; + // Size chosen arbitrarily. ~60% more bytes than a 20th column index + // observed on the author's workstation. + char stat_line[160]; + n = fread(&stat_line, 1, 159, proc_stat); + stat_line[n] = '\0'; + fclose(proc_stat); + + char *saveptr = NULL; + char *field = strtok_r(stat_line, " ", &saveptr); + unsigned int idx; + for (idx = 19; idx && field; --idx) { + field = strtok_r(NULL, " ", &saveptr); + } + if (idx == 0 && field) { // found the 20th field + num_python_threads = atoi(field); // 0 on error + } + } +#endif + return num_python_threads; +} #endif // HAVE_FORK1 || HAVE_FORKPTY || HAVE_FORK #ifdef HAVE_FORK1 @@ -8131,10 +8575,12 @@ os_fork1_impl(PyObject *module) /* child: this clobbers and resets the import lock. */ PyOS_AfterFork_Child(); } else { + // Called before AfterFork_Parent in case those hooks start threads. + Py_ssize_t num_os_threads = get_number_of_os_threads(); /* parent: release the import lock. */ PyOS_AfterFork_Parent(); // After PyOS_AfterFork_Parent() starts the world to avoid deadlock. - if (warn_about_fork_with_threads("fork1") < 0) { + if (warn_about_fork_with_threads("fork1", num_os_threads) < 0) { return NULL; } } @@ -8182,10 +8628,12 @@ os_fork_impl(PyObject *module) /* child: this clobbers and resets the import lock. */ PyOS_AfterFork_Child(); } else { + // Called before AfterFork_Parent in case those hooks start threads. + Py_ssize_t num_os_threads = get_number_of_os_threads(); /* parent: release the import lock. */ PyOS_AfterFork_Parent(); // After PyOS_AfterFork_Parent() starts the world to avoid deadlock. - if (warn_about_fork_with_threads("fork") < 0) + if (warn_about_fork_with_threads("fork", num_os_threads) < 0) return NULL; } if (pid == -1) { @@ -8296,7 +8744,7 @@ os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority) static PyObject * os_sched_param_reduce(PyObject *self, PyObject *Py_UNUSED(dummy)) { - return Py_BuildValue("(O(N))", Py_TYPE(self), PyStructSequence_GetItem(self, 0)); + return Py_BuildValue("(O(O))", Py_TYPE(self), PyStructSequence_GetItem(self, 0)); } static PyMethodDef os_sched_param_reduce_method = { @@ -8311,7 +8759,7 @@ static PyStructSequence_Field sched_param_fields[] = { }; static PyStructSequence_Desc sched_param_desc = { - "sched_param", /* name */ + MODNAME ".sched_param", /* name */ os_sched_param__doc__, /* doc */ sched_param_fields, 1 @@ -9014,11 +9462,12 @@ Returns a tuple of (pid, master_fd). Like fork(), return pid of 0 to the child process, and pid of child to the parent process. To both, return fd of newly opened pseudo-terminal. +The master_fd is non-inheritable. [clinic start generated code]*/ static PyObject * os_forkpty_impl(PyObject *module) -/*[clinic end generated code: output=60d0a5c7512e4087 input=f1f7f4bae3966010]*/ +/*[clinic end generated code: output=60d0a5c7512e4087 input=24765e0f33275b3b]*/ { int master_fd = -1; pid_t pid; @@ -9042,15 +9491,24 @@ os_forkpty_impl(PyObject *module) /* child: this clobbers and resets the import lock. */ PyOS_AfterFork_Child(); } else { + // Called before AfterFork_Parent in case those hooks start threads. + Py_ssize_t num_os_threads = get_number_of_os_threads(); /* parent: release the import lock. */ PyOS_AfterFork_Parent(); + /* set O_CLOEXEC on master_fd */ + if (_Py_set_inheritable(master_fd, 0, NULL) < 0) { + PyErr_FormatUnraisable("Exception ignored when setting master_fd " + "non-inheritable in forkpty()"); + } + // After PyOS_AfterFork_Parent() starts the world to avoid deadlock. - if (warn_about_fork_with_threads("forkpty") < 0) + if (warn_about_fork_with_threads("forkpty", num_os_threads) < 0) return NULL; } if (pid == -1) { return posix_error(); } + return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd); } #endif /* HAVE_FORKPTY */ @@ -9313,7 +9771,7 @@ error: /*[clinic input] os.initgroups - username as oname: FSConverter + username as oname: unicode_fs_encoded gid: int / @@ -9326,12 +9784,12 @@ group id. static PyObject * os_initgroups_impl(PyObject *module, PyObject *oname, int gid) -/*[clinic end generated code: output=7f074d30a425fd3a input=df3d54331b0af204]*/ +/*[clinic end generated code: output=7f074d30a425fd3a input=984e60c7fed88cb4]*/ #else /*[clinic input] os.initgroups - username as oname: FSConverter + username as oname: unicode_fs_encoded gid: gid_t / @@ -9344,7 +9802,7 @@ group id. static PyObject * os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid) -/*[clinic end generated code: output=59341244521a9e3f input=0cb91bdc59a4c564]*/ +/*[clinic end generated code: output=59341244521a9e3f input=17d8fbe2dea42ca4]*/ #endif { const char *username = PyBytes_AS_STRING(oname); @@ -9590,7 +10048,7 @@ os_getlogin_impl(PyObject *module) int err = getlogin_r(name, sizeof(name)); if (err) { int old_errno = errno; - errno = -err; + errno = err; posix_error(); errno = old_errno; } @@ -10697,7 +11155,7 @@ and elapsed.\n\ See os.times for more information."); static PyStructSequence_Desc times_result_desc = { - "times_result", /* name */ + MODNAME ".times_result", /* name */ times_result__doc__, /* doc */ times_result_fields, 5 @@ -11492,9 +11950,6 @@ static PyObject * os_read_impl(PyObject *module, int fd, Py_ssize_t length) /*[clinic end generated code: output=dafbe9a5cddb987b input=1df2eaa27c0bf1d3]*/ { - Py_ssize_t n; - PyObject *buffer; - if (length < 0) { errno = EINVAL; return posix_error(); @@ -11502,20 +11957,18 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length) length = Py_MIN(length, _PY_READ_MAX); - buffer = PyBytes_FromStringAndSize((char *)NULL, length); - if (buffer == NULL) - return NULL; - - n = _Py_read(fd, PyBytes_AS_STRING(buffer), length); - if (n == -1) { - Py_DECREF(buffer); + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; } - if (n != length) - _PyBytes_Resize(&buffer, n); + Py_ssize_t n = _Py_read(fd, PyBytesWriter_GetData(writer), length); + if (n == -1) { + PyBytesWriter_Discard(writer); + return NULL; + } - return buffer; + return PyBytesWriter_FinishWithSize(writer, n); } /*[clinic input] @@ -11693,20 +12146,20 @@ os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset) { Py_ssize_t n; int async_err = 0; - PyObject *buffer; if (length < 0) { errno = EINVAL; return posix_error(); } - buffer = PyBytes_FromStringAndSize((char *)NULL, length); - if (buffer == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; + } do { Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH - n = pread(fd, PyBytes_AS_STRING(buffer), length, offset); + n = pread(fd, PyBytesWriter_GetData(writer), length, offset); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); @@ -11715,12 +12168,10 @@ os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset) if (!async_err) { posix_error(); } - Py_DECREF(buffer); + PyBytesWriter_Discard(writer); return NULL; } - if (n != length) - _PyBytes_Resize(&buffer, n); - return buffer; + return PyBytesWriter_FinishWithSize(writer, n); } #endif /* HAVE_PREAD */ @@ -11748,6 +12199,7 @@ The flags argument contains a bitwise OR of zero or more of the following flags: - RWF_HIPRI - RWF_NOWAIT +- RWF_DONTCACHE Using non-zero flags requires Linux 4.6 or newer. [clinic start generated code]*/ @@ -11755,7 +12207,7 @@ Using non-zero flags requires Linux 4.6 or newer. static Py_ssize_t os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, int flags) -/*[clinic end generated code: output=26fc9c6e58e7ada5 input=c1f876866fcd9d41]*/ +/*[clinic end generated code: output=26fc9c6e58e7ada5 input=34fb3b9ca06f7ba7]*/ { Py_ssize_t cnt, n; int async_err = 0; @@ -11874,7 +12326,7 @@ os.sendfile out_fd: int in_fd: int offset: Py_off_t - count: Py_ssize_t + count: Py_ssize_t(allow_negative=False) headers: object(c_default="NULL") = () trailers: object(c_default="NULL") = () flags: int = 0 @@ -11886,7 +12338,7 @@ static PyObject * os_sendfile_impl(PyObject *module, int out_fd, int in_fd, Py_off_t offset, Py_ssize_t count, PyObject *headers, PyObject *trailers, int flags) -/*[clinic end generated code: output=329ea009bdd55afc input=338adb8ff84ae8cd]*/ +/*[clinic end generated code: output=329ea009bdd55afc input=dcb026b94effa922]*/ #else /*[clinic input] os.sendfile @@ -11894,7 +12346,7 @@ os.sendfile out_fd: int in_fd: int offset as offobj: object - count: Py_ssize_t + count: Py_ssize_t(allow_negative=False) Copy count bytes from file descriptor in_fd to file descriptor out_fd. [clinic start generated code]*/ @@ -11902,12 +12354,22 @@ Copy count bytes from file descriptor in_fd to file descriptor out_fd. static PyObject * os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, Py_ssize_t count) -/*[clinic end generated code: output=ae81216e40f167d8 input=76d64058c74477ba]*/ +/*[clinic end generated code: output=ae81216e40f167d8 input=424df0949059ea5b]*/ #endif { Py_ssize_t ret; int async_err = 0; +#ifdef __APPLE__ + if(sbytes < 0) { + PyErr_SetString(PyExc_ValueError, + "count cannot be negative"); + return NULL; + } +#else + assert(count >= 0); +#endif + #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) #ifndef __APPLE__ off_t sbytes; @@ -12395,6 +12857,7 @@ The flags argument contains a bitwise OR of zero or more of the following flags: - RWF_DSYNC - RWF_SYNC - RWF_APPEND +- RWF_DONTCACHE Using non-zero flags requires Linux 4.7 or newer. [clinic start generated code]*/ @@ -12402,7 +12865,7 @@ Using non-zero flags requires Linux 4.7 or newer. static Py_ssize_t os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, int flags) -/*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=99d8a21493ff76ca]*/ +/*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=664a67626d485665]*/ { Py_ssize_t cnt; Py_ssize_t result; @@ -12483,7 +12946,7 @@ os.copy_file_range Source file descriptor. dst: int Destination file descriptor. - count: Py_ssize_t + count: Py_ssize_t(allow_negative=False) Number of bytes to copy. offset_src: object = None Starting offset in src. @@ -12499,7 +12962,7 @@ respectively for offset_dst. static PyObject * os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count, PyObject *offset_src, PyObject *offset_dst) -/*[clinic end generated code: output=1a91713a1d99fc7a input=42fdce72681b25a9]*/ +/*[clinic end generated code: output=1a91713a1d99fc7a input=08dacb760869b87c]*/ { off_t offset_src_val, offset_dst_val; off_t *p_offset_src = NULL; @@ -12511,11 +12974,6 @@ os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count, int flags = 0; - if (count < 0) { - PyErr_SetString(PyExc_ValueError, "negative value for 'count' not allowed"); - return NULL; - } - if (offset_src != Py_None) { if (!Py_off_t_converter(offset_src, &offset_src_val)) { return NULL; @@ -12552,7 +13010,7 @@ os.splice Source file descriptor. dst: int Destination file descriptor. - count: Py_ssize_t + count: Py_ssize_t(allow_negative=False) Number of bytes to copy. offset_src: object = None Starting offset in src. @@ -12572,7 +13030,7 @@ static PyObject * os_splice_impl(PyObject *module, int src, int dst, Py_ssize_t count, PyObject *offset_src, PyObject *offset_dst, unsigned int flags) -/*[clinic end generated code: output=d0386f25a8519dc5 input=047527c66c6d2e0a]*/ +/*[clinic end generated code: output=d0386f25a8519dc5 input=034852a7b2e7af35]*/ { off_t offset_src_val, offset_dst_val; off_t *p_offset_src = NULL; @@ -12580,10 +13038,6 @@ os_splice_impl(PyObject *module, int src, int dst, Py_ssize_t count, Py_ssize_t ret; int async_err = 0; - if (count < 0) { - PyErr_SetString(PyExc_ValueError, "negative value for 'count' not allowed"); - return NULL; - } if (offset_src != Py_None) { if (!Py_off_t_converter(offset_src, &offset_src_val)) { @@ -13104,8 +13558,8 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) /*[clinic input] os.putenv - name: FSConverter - value: FSConverter + name: unicode_fs_encoded + value: unicode_fs_encoded / Change or add an environment variable. @@ -13113,7 +13567,7 @@ Change or add an environment variable. static PyObject * os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) -/*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/ +/*[clinic end generated code: output=d29a567d6b2327d2 input=84fcd30f873c8c45]*/ { const char *name_string = PyBytes_AS_STRING(name); const char *value_string = PyBytes_AS_STRING(value); @@ -13156,7 +13610,7 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #else /*[clinic input] os.unsetenv - name: FSConverter + name: unicode_fs_encoded / Delete an environment variable. @@ -13164,7 +13618,7 @@ Delete an environment variable. static PyObject * os_unsetenv_impl(PyObject *module, PyObject *name) -/*[clinic end generated code: output=54c4137ab1834f02 input=2bb5288a599c7107]*/ +/*[clinic end generated code: output=54c4137ab1834f02 input=78ff12e505ade80a]*/ { if (PySys_Audit("os.unsetenv", "(O)", name) < 0) { return NULL; @@ -13183,6 +13637,25 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #endif /* !MS_WINDOWS */ +#ifdef HAVE_CLEARENV +/*[clinic input] +os._clearenv +[clinic start generated code]*/ + +static PyObject * +os__clearenv_impl(PyObject *module) +/*[clinic end generated code: output=2d6705d62c014b51 input=47d2fa7f323c43ca]*/ +{ + errno = 0; + int err = clearenv(); + if (err) { + return posix_error(); + } + Py_RETURN_NONE; +} +#endif + + /*[clinic input] os.strerror @@ -14929,9 +15402,6 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, int follow_symlinks) /*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/ { - Py_ssize_t i; - PyObject *buffer = NULL; - if (fd_and_follow_symlinks_invalid("getxattr", path->fd, follow_symlinks)) return NULL; @@ -14939,8 +15409,7 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, return NULL; } - for (i = 0; ; i++) { - void *ptr; + for (Py_ssize_t i = 0; ; i++) { ssize_t result; static const Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0}; Py_ssize_t buffer_size = buffer_sizes[i]; @@ -14948,10 +15417,11 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, path_error(path); return NULL; } - buffer = PyBytes_FromStringAndSize(NULL, buffer_size); - if (!buffer) + PyBytesWriter *writer = PyBytesWriter_Create(buffer_size); + if (writer == NULL) { return NULL; - ptr = PyBytes_AS_STRING(buffer); + } + void *ptr = PyBytesWriter_GetData(writer); Py_BEGIN_ALLOW_THREADS; if (path->fd >= 0) @@ -14963,23 +15433,16 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, Py_END_ALLOW_THREADS; if (result < 0) { + PyBytesWriter_Discard(writer); if (errno == ERANGE) { - Py_DECREF(buffer); continue; } path_error(path); - Py_DECREF(buffer); return NULL; } - if (result != buffer_size) { - /* Can only shrink. */ - _PyBytes_Resize(&buffer, result); - } - break; + return PyBytesWriter_FinishWithSize(writer, result); } - - return buffer; } @@ -15196,7 +15659,7 @@ exit: @permit_long_summary os.urandom - size: Py_ssize_t + size: Py_ssize_t(allow_negative=False) / Return a bytes object containing random bytes suitable for cryptographic use. @@ -15204,38 +15667,38 @@ Return a bytes object containing random bytes suitable for cryptographic use. static PyObject * os_urandom_impl(PyObject *module, Py_ssize_t size) -/*[clinic end generated code: output=42c5cca9d18068e9 input=ade19e6b362e7388]*/ +/*[clinic end generated code: output=42c5cca9d18068e9 input=58a0def87dbc2c22]*/ { - PyObject *bytes; - int result; - - if (size < 0) + if (size < 0) { return PyErr_Format(PyExc_ValueError, "negative argument not allowed"); - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) - return NULL; + } - result = _PyOS_URandom(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); - if (result == -1) { - Py_DECREF(bytes); + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; } - return bytes; + + int result = _PyOS_URandom(PyBytesWriter_GetData(writer), size); + if (result == -1) { + PyBytesWriter_Discard(writer); + return NULL; + } + return PyBytesWriter_Finish(writer); } #ifdef HAVE_MEMFD_CREATE /*[clinic input] os.memfd_create - name: FSConverter + name: unicode_fs_encoded flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC [clinic start generated code]*/ static PyObject * os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags) -/*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/ +/*[clinic end generated code: output=6681ede983bdb9a6 input=cd0eb092cfac474b]*/ { int fd; const char *bytes = PyBytes_AS_STRING(name); @@ -16037,11 +16500,14 @@ static PyType_Slot DirEntryType_slots[] = { }; static PyType_Spec DirEntryType_spec = { - MODNAME ".DirEntry", - sizeof(DirEntry), - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, - DirEntryType_slots + .name = MODNAME ".DirEntry", + .basicsize = sizeof(DirEntry), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = DirEntryType_slots }; @@ -16479,14 +16945,17 @@ static PyType_Slot ScandirIteratorType_slots[] = { }; static PyType_Spec ScandirIteratorType_spec = { - MODNAME ".ScandirIterator", - sizeof(ScandirIterator), - 0, + .name = MODNAME ".ScandirIterator", + .basicsize = sizeof(ScandirIterator), // bpo-40549: Py_TPFLAGS_BASETYPE should not be used, since // PyType_GetModule(Py_TYPE(self)) doesn't work on a subclass instance. - (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE - | Py_TPFLAGS_DISALLOW_INSTANTIATION), - ScandirIteratorType_slots + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_HAVE_FINALIZE + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = ScandirIteratorType_slots }; /*[clinic input] @@ -16685,25 +17154,20 @@ static PyObject * os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) /*[clinic end generated code: output=b3a618196a61409c input=59bafac39c594947]*/ { - PyObject *bytes; - Py_ssize_t n; - if (size < 0) { errno = EINVAL; return posix_error(); } - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) { - PyErr_NoMemory(); + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; } + void *data = PyBytesWriter_GetData(writer); + Py_ssize_t n; while (1) { - n = syscall(SYS_getrandom, - PyBytes_AS_STRING(bytes), - PyBytes_GET_SIZE(bytes), - flags); + n = syscall(SYS_getrandom, data, size, flags); if (n < 0 && errno == EINTR) { if (PyErr_CheckSignals() < 0) { goto error; @@ -16720,14 +17184,10 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) goto error; } - if (n != size) { - _PyBytes_Resize(&bytes, n); - } - - return bytes; + return PyBytesWriter_FinishWithSize(writer, n); error: - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); return NULL; } #endif /* HAVE_GETRANDOM_SYSCALL */ @@ -16946,12 +17406,12 @@ os__supports_virtual_terminal_impl(PyObject *module) /*[clinic input] os._inputhook -Calls PyOS_CallInputHook droppong the GIL first +Calls PyOS_InputHook dropping the GIL first [clinic start generated code]*/ static PyObject * os__inputhook_impl(PyObject *module) -/*[clinic end generated code: output=525aca4ef3c6149f input=fc531701930d064f]*/ +/*[clinic end generated code: output=525aca4ef3c6149f input=b5018fa1ec3aa440]*/ { int result = 0; if (PyOS_InputHook) { @@ -16965,12 +17425,12 @@ os__inputhook_impl(PyObject *module) /*[clinic input] os._is_inputhook_installed -Checks if PyOS_CallInputHook is set +Checks if PyOS_InputHook is set [clinic start generated code]*/ static PyObject * os__is_inputhook_installed_impl(PyObject *module) -/*[clinic end generated code: output=3b3eab4f672c689a input=ff177c9938dd76d8]*/ +/*[clinic end generated code: output=3b3eab4f672c689a input=757820f79f48820c]*/ { return PyBool_FromLong(PyOS_InputHook != NULL); } @@ -17027,6 +17487,7 @@ os__emscripten_log_impl(PyObject *module, const char *arg) static PyMethodDef posix_methods[] = { OS_STAT_METHODDEF + OS_STATX_METHODDEF OS_ACCESS_METHODDEF OS_TTYNAME_METHODDEF OS_CHDIR_METHODDEF @@ -17162,6 +17623,7 @@ static PyMethodDef posix_methods[] = { OS_POSIX_FADVISE_METHODDEF OS_PUTENV_METHODDEF OS_UNSETENV_METHODDEF + OS__CLEARENV_METHODDEF OS_STRERROR_METHODDEF OS_FCHDIR_METHODDEF OS_FSYNC_METHODDEF @@ -17650,6 +18112,9 @@ all_ins(PyObject *m) #ifdef RWF_NOWAIT if (PyModule_AddIntConstant(m, "RWF_NOWAIT", RWF_NOWAIT)) return -1; #endif +#ifdef RWF_DONTCACHE + if (PyModule_AddIntConstant(m, "RWF_DONTCACHE", RWF_DONTCACHE)) return -1; +#endif #ifdef RWF_APPEND if (PyModule_AddIntConstant(m, "RWF_APPEND", RWF_APPEND)) return -1; #endif @@ -17865,6 +18330,53 @@ all_ins(PyObject *m) #endif #endif /* HAVE_EVENTFD && EFD_CLOEXEC */ +#ifdef NODEV + if (PyModule_Add(m, "NODEV", _PyLong_FromDev(NODEV))) return -1; +#endif + +#ifdef AT_NO_AUTOMOUNT + if (PyModule_AddIntMacro(m, AT_NO_AUTOMOUNT)) return -1; +#endif + +#ifdef HAVE_STATX + if (PyModule_AddIntMacro(m, STATX_TYPE)) return -1; + if (PyModule_AddIntMacro(m, STATX_MODE)) return -1; + if (PyModule_AddIntMacro(m, STATX_NLINK)) return -1; + if (PyModule_AddIntMacro(m, STATX_UID)) return -1; + if (PyModule_AddIntMacro(m, STATX_GID)) return -1; + if (PyModule_AddIntMacro(m, STATX_ATIME)) return -1; + if (PyModule_AddIntMacro(m, STATX_MTIME)) return -1; + if (PyModule_AddIntMacro(m, STATX_CTIME)) return -1; + if (PyModule_AddIntMacro(m, STATX_INO)) return -1; + if (PyModule_AddIntMacro(m, STATX_SIZE)) return -1; + if (PyModule_AddIntMacro(m, STATX_BLOCKS)) return -1; + if (PyModule_AddIntMacro(m, STATX_BASIC_STATS)) return -1; + if (PyModule_AddIntMacro(m, STATX_BTIME)) return -1; +#ifdef STATX_MNT_ID + if (PyModule_AddIntMacro(m, STATX_MNT_ID)) return -1; +#endif +#ifdef STATX_DIOALIGN + if (PyModule_AddIntMacro(m, STATX_DIOALIGN)) return -1; +#endif +#ifdef STATX_MNT_ID_UNIQUE + if (PyModule_AddIntMacro(m, STATX_MNT_ID_UNIQUE)) return -1; +#endif +#ifdef STATX_SUBVOL + if (PyModule_AddIntMacro(m, STATX_SUBVOL)) return -1; +#endif +#ifdef STATX_WRITE_ATOMIC + if (PyModule_AddIntMacro(m, STATX_WRITE_ATOMIC)) return -1; +#endif +#ifdef STATX_DIO_READ_ALIGN + if (PyModule_AddIntMacro(m, STATX_DIO_READ_ALIGN)) return -1; +#endif + /* STATX_ALL intentionally omitted because it is deprecated */ + if (PyModule_AddIntMacro(m, AT_STATX_SYNC_AS_STAT)) return -1; + if (PyModule_AddIntMacro(m, AT_STATX_FORCE_SYNC)) return -1; + if (PyModule_AddIntMacro(m, AT_STATX_DONT_SYNC)) return -1; + /* STATX_ATTR_* constants are in the stat module */ +#endif /* HAVE_STATX */ + #if defined(__APPLE__) if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1; if (PyModule_AddIntConstant(m, "_COPYFILE_STAT", COPYFILE_STAT)) return -1; @@ -18136,6 +18648,24 @@ posixmodule_exec(PyObject *m) } #endif +#ifdef HAVE_STATX + if (statx == NULL) { + PyObject* dct = PyModule_GetDict(m); + if (dct == NULL) { + return -1; + } + if (PyDict_PopString(dct, "statx", NULL) < 0) { + return -1; + } + } + else { + state->StatxResultType = PyType_FromModuleAndSpec(m, &pystatx_result_spec, NULL); + if (PyModule_AddObjectRef(m, "statx_result", state->StatxResultType) < 0) { + return -1; + } + } +#endif + /* Initialize environ dictionary */ if (PyModule_Add(m, "environ", convertenviron()) != 0) { return -1; @@ -18152,14 +18682,12 @@ posixmodule_exec(PyObject *m) } #if defined(HAVE_WAITID) - waitid_result_desc.name = MODNAME ".waitid_result"; state->WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc); if (PyModule_AddObjectRef(m, "waitid_result", state->WaitidResultType) < 0) { return -1; } #endif - stat_result_desc.name = "os.stat_result"; /* see issue #19209 */ stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; @@ -18170,14 +18698,12 @@ posixmodule_exec(PyObject *m) state->statresult_new_orig = ((PyTypeObject *)state->StatResultType)->tp_new; ((PyTypeObject *)state->StatResultType)->tp_new = statresult_new; - statvfs_result_desc.name = "os.statvfs_result"; /* see issue #19209 */ state->StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc); if (PyModule_AddObjectRef(m, "statvfs_result", state->StatVFSResultType) < 0) { return -1; } #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) - sched_param_desc.name = MODNAME ".sched_param"; state->SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc); if (PyModule_AddObjectRef(m, "sched_param", state->SchedParamType) < 0) { return -1; @@ -18209,7 +18735,6 @@ posixmodule_exec(PyObject *m) return -1; } - times_result_desc.name = MODNAME ".times_result"; state->TimesResultType = (PyObject *)PyStructSequence_NewType(&times_result_desc); if (PyModule_AddObjectRef(m, "times_result", state->TimesResultType) < 0) { return -1; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 878368bf323..e9255038eee 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -9,6 +9,8 @@ #include <stdbool.h> #include <stddef.h> // offsetof() + +#include "expat_config.h" #include "expat.h" #include "pyexpat.h" @@ -74,6 +76,15 @@ typedef struct { PyObject_HEAD XML_Parser itself; + /* + * Strong reference to a parent `xmlparseobject` if this parser + * is a child parser. Set to NULL if this parser is a root parser. + * This is needed to keep the parent parser alive as long as it has + * at least one child parser. + * + * See https://github.com/python/cpython/issues/139400 for details. + */ + PyObject *parent; int ordered_attributes; /* Return attributes as a list. */ int specified_attributes; /* Report only specified attributes. */ int in_callback; /* Is a callback active? */ @@ -122,50 +133,91 @@ CALL_XML_HANDLER_SETTER(const struct HandlerInfo *handler_info, setter(xml_parser, xml_handler); } +static int +set_xml_error_attr_code(PyObject *err, enum XML_Error code) +{ + PyObject *v = PyLong_FromLong((long)code); + int ok = v != NULL && PyObject_SetAttr(err, &_Py_ID(code), v) != -1; + Py_XDECREF(v); + return ok; +} + /* Set an integer attribute on the error object; return true on success, * false on an exception. */ static int -set_error_attr(PyObject *err, const char *name, int value) +set_xml_error_attr_location(PyObject *err, const char *name, XML_Size value) { - PyObject *v = PyLong_FromLong(value); - - if (v == NULL || PyObject_SetAttrString(err, name, v) == -1) { - Py_XDECREF(v); - return 0; - } - Py_DECREF(v); - return 1; + PyObject *v = PyLong_FromSize_t((size_t)value); + int ok = v != NULL && PyObject_SetAttrString(err, name, v) != -1; + Py_XDECREF(v); + return ok; } + +static PyObject * +set_xml_error(pyexpat_state *state, + enum XML_Error code, XML_Size lineno, XML_Size column, + const char *errmsg) +{ + PyObject *arg; + if (errmsg == NULL) { + arg = PyUnicode_FromFormat( + "%s: line %zu, column %zu", + XML_ErrorString(code), + (size_t)lineno, (size_t)column + ); + } + else { + arg = PyUnicode_FromStringAndSize(errmsg, strlen(errmsg)); + } + if (arg == NULL) { + return NULL; + } + PyObject *res = PyObject_CallOneArg(state->error, arg); + Py_DECREF(arg); + if ( + res != NULL + && set_xml_error_attr_code(res, code) + && set_xml_error_attr_location(res, "lineno", lineno) + && set_xml_error_attr_location(res, "offset", column) + ) { + PyErr_SetObject(state->error, res); + } + Py_XDECREF(res); + return NULL; +} + +#define SET_XML_ERROR(STATE, SELF, CODE, ERRMSG) \ + do { \ + XML_Parser parser = SELF->itself; \ + assert(parser != NULL); \ + XML_Size lineno = XML_GetCurrentLineNumber(parser); \ + XML_Size column = XML_GetCurrentColumnNumber(parser); \ + (void)set_xml_error(state, CODE, lineno, column, ERRMSG); \ + } while (0) + /* Build and set an Expat exception, including positioning * information. Always returns NULL. */ static PyObject * set_error(pyexpat_state *state, xmlparseobject *self, enum XML_Error code) { - PyObject *err; - PyObject *buffer; - XML_Parser parser = self->itself; - int lineno = XML_GetErrorLineNumber(parser); - int column = XML_GetErrorColumnNumber(parser); - - buffer = PyUnicode_FromFormat("%s: line %i, column %i", - XML_ErrorString(code), lineno, column); - if (buffer == NULL) - return NULL; - err = PyObject_CallOneArg(state->error, buffer); - Py_DECREF(buffer); - if ( err != NULL - && set_error_attr(err, "code", code) - && set_error_attr(err, "offset", column) - && set_error_attr(err, "lineno", lineno)) { - PyErr_SetObject(state->error, err); - } - Py_XDECREF(err); + SET_XML_ERROR(state, self, code, NULL); return NULL; } +#if XML_COMBINED_VERSION >= 20400 +static PyObject * +set_invalid_arg(pyexpat_state *state, xmlparseobject *self, const char *errmsg) +{ + SET_XML_ERROR(state, self, XML_ERROR_INVALID_ARGUMENT, errmsg); + return NULL; +} +#endif + +#undef SET_XML_ERROR + static int have_handler(xmlparseobject *self, int type) { @@ -590,7 +642,7 @@ my_ElementDeclHandler(void *userData, PyObject *modelobj, *nameobj; if (PyErr_Occurred()) - return; + goto finally; if (flush_character_buffer(self) < 0) goto finally; @@ -1024,6 +1076,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, return NULL; } + // The new subparser will make use of the parent XML_Parser inside of Expat. + // So we need to take subparsers into account with the reference counting + // of their parent parser. + Py_INCREF(self); + new_parser->buffer_size = self->buffer_size; new_parser->buffer_used = 0; new_parser->buffer = NULL; @@ -1033,6 +1090,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, new_parser->ns_prefixes = self->ns_prefixes; new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context, encoding); + new_parser->parent = (PyObject *)self; new_parser->handlers = 0; new_parser->intern = Py_XNewRef(self->intern); @@ -1040,11 +1098,13 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, new_parser->buffer = PyMem_Malloc(new_parser->buffer_size); if (new_parser->buffer == NULL) { Py_DECREF(new_parser); + Py_DECREF(self); return PyErr_NoMemory(); } } if (!new_parser->itself) { Py_DECREF(new_parser); + Py_DECREF(self); return PyErr_NoMemory(); } @@ -1058,6 +1118,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, new_parser->handlers = PyMem_New(PyObject *, i); if (!new_parser->handlers) { Py_DECREF(new_parser); + Py_DECREF(self); return PyErr_NoMemory(); } clear_handlers(new_parser, 1); @@ -1133,6 +1194,192 @@ pyexpat_xmlparser_UseForeignDTD_impl(xmlparseobject *self, PyTypeObject *cls, } #endif +#if XML_COMBINED_VERSION >= 20400 +static PyObject * +set_activation_threshold(xmlparseobject *self, + PyTypeObject *cls, + unsigned long long threshold, + XML_Bool (*setter)(XML_Parser, unsigned long long)) +{ + assert(self->itself != NULL); + if (setter(self->itself, threshold) == XML_TRUE) { + Py_RETURN_NONE; + } + // The setter fails if self->itself is NULL (which is not possible here) + // or is a non-root parser, which currently only happens for parsers + // created by ExternalEntityParserCreate(). + pyexpat_state *state = PyType_GetModuleState(cls); + return set_invalid_arg(state, self, "parser must be a root parser"); +} + +static PyObject * +set_maximum_amplification(xmlparseobject *self, + PyTypeObject *cls, + float max_factor, + XML_Bool (*setter)(XML_Parser, float)) +{ + assert(self->itself != NULL); + if (setter(self->itself, max_factor) == XML_TRUE) { + Py_RETURN_NONE; + } + // The setter fails if self->itself is NULL (which is not possible here), + // is a non-root parser, which currently only happens for parsers created + // by ExternalEntityParserCreate(), or if 'max_factor' is NaN or < 1.0. + pyexpat_state *state = PyType_GetModuleState(cls); + // Note: Expat has no API to determine whether a parser is a root parser, + // and since the Expat functions for defining the various maximum allowed + // amplifcation factors fail when a bad parser or an out-of-range factor + // is given without specifying which check failed, we check whether the + // factor is out-of-range to improve the error message. See also gh-90949. + const char *message = (isnan(max_factor) || max_factor < 1.0f) + ? "'max_factor' must be at least 1.0" + : "parser must be a root parser"; + return set_invalid_arg(state, self, message); +} +#endif + +#if XML_COMBINED_VERSION >= 20400 +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +pyexpat.xmlparser.SetBillionLaughsAttackProtectionActivationThreshold + + cls: defining_class + threshold: unsigned_long_long + / + +Sets the number of output bytes needed to activate protection against billion laughs attacks. + +The number of output bytes includes amplification from entity expansion +and reading DTD files. + +Parser objects usually have a protection activation threshold of 8 MiB, +but the actual default value depends on the underlying Expat library. + +Activation thresholds below 4 MiB are known to break support for DITA 1.3 +payload and are hence not recommended. +[clinic start generated code]*/ + +static PyObject * +pyexpat_xmlparser_SetBillionLaughsAttackProtectionActivationThreshold_impl(xmlparseobject *self, + PyTypeObject *cls, + unsigned long long threshold) +/*[clinic end generated code: output=0c082342f1c78114 input=fa2f91f26b62a42a]*/ +{ + return set_activation_threshold( + self, cls, threshold, + XML_SetBillionLaughsAttackProtectionActivationThreshold + ); +} +#endif + +#if XML_COMBINED_VERSION >= 20400 +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +pyexpat.xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification + + cls: defining_class + max_factor: float + / + +Sets the maximum tolerated amplification factor for protection against billion laughs attacks. + +The amplification factor is calculated as "(direct + indirect) / direct" +while parsing, where "direct" is the number of bytes read from the primary +document in parsing and "indirect" is the number of bytes added by expanding +entities and reading external DTD files, combined. + +The 'max_factor' value must be a non-NaN floating point value greater than +or equal to 1.0. Amplification factors greater than 30,000 can be observed +in the middle of parsing even with benign files in practice. In particular, +the activation threshold should be carefully chosen to avoid false positives. + +Parser objects usually have a maximum amplification factor of 100, +but the actual default value depends on the underlying Expat library. +[clinic start generated code]*/ + +static PyObject * +pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification_impl(xmlparseobject *self, + PyTypeObject *cls, + float max_factor) +/*[clinic end generated code: output=c590439eadf463fa input=cc1e97c1fd2bd950]*/ +{ + return set_maximum_amplification( + self, cls, max_factor, + XML_SetBillionLaughsAttackProtectionMaximumAmplification + ); +} +#endif + +#if XML_COMBINED_VERSION >= 20702 +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +pyexpat.xmlparser.SetAllocTrackerActivationThreshold + + cls: defining_class + threshold: unsigned_long_long + / + +Sets the number of allocated bytes of dynamic memory needed to activate protection against disproportionate use of RAM. + +Parser objects usually have an allocation activation threshold of 64 MiB, +but the actual default value depends on the underlying Expat library. +[clinic start generated code]*/ + +static PyObject * +pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl(xmlparseobject *self, + PyTypeObject *cls, + unsigned long long threshold) +/*[clinic end generated code: output=bed7e93207ba08c5 input=b7a7a3e3d054286a]*/ +{ + return set_activation_threshold( + self, cls, threshold, + XML_SetAllocTrackerActivationThreshold + ); +} +#endif + +#if XML_COMBINED_VERSION >= 20702 +/*[clinic input] +@permit_long_summary +@permit_long_docstring_body +pyexpat.xmlparser.SetAllocTrackerMaximumAmplification + + cls: defining_class + max_factor: float + / + +Sets the maximum amplification factor between direct input and bytes of dynamic memory allocated. + +The amplification factor is calculated as "allocated / direct" while parsing, +where "direct" is the number of bytes read from the primary document in parsing +and "allocated" is the number of bytes of dynamic memory allocated in the parser +hierarchy. + +The 'max_factor' value must be a non-NaN floating point value greater than +or equal to 1.0. Amplification factors greater than 100.0 can be observed +near the start of parsing even with benign files in practice. In particular, +the activation threshold should be carefully chosen to avoid false positives. + +Parser objects usually have a maximum amplification factor of 100, +but the actual default value depends on the underlying Expat library. +[clinic start generated code]*/ + +static PyObject * +pyexpat_xmlparser_SetAllocTrackerMaximumAmplification_impl(xmlparseobject *self, + PyTypeObject *cls, + float max_factor) +/*[clinic end generated code: output=6e44bd48c9b112a0 input=c6af7ccb76ae5c6b]*/ +{ + return set_maximum_amplification( + self, cls, max_factor, + XML_SetAllocTrackerMaximumAmplification + ); +} +#endif + static struct PyMethodDef xmlparse_methods[] = { PYEXPAT_XMLPARSER_PARSE_METHODDEF PYEXPAT_XMLPARSER_PARSEFILE_METHODDEF @@ -1141,9 +1388,11 @@ static struct PyMethodDef xmlparse_methods[] = { PYEXPAT_XMLPARSER_GETINPUTCONTEXT_METHODDEF PYEXPAT_XMLPARSER_EXTERNALENTITYPARSERCREATE_METHODDEF PYEXPAT_XMLPARSER_SETPARAMENTITYPARSING_METHODDEF -#if XML_COMBINED_VERSION >= 19505 PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF -#endif + PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONACTIVATIONTHRESHOLD_METHODDEF + PYEXPAT_XMLPARSER_SETBILLIONLAUGHSATTACKPROTECTIONMAXIMUMAMPLIFICATION_METHODDEF + PYEXPAT_XMLPARSER_SETALLOCTRACKERACTIVATIONTHRESHOLD_METHODDEF + PYEXPAT_XMLPARSER_SETALLOCTRACKERMAXIMUMAMPLIFICATION_METHODDEF PYEXPAT_XMLPARSER_SETREPARSEDEFERRALENABLED_METHODDEF PYEXPAT_XMLPARSER_GETREPARSEDEFERRALENABLED_METHODDEF {NULL, NULL} /* sentinel */ @@ -1250,6 +1499,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding, /* namespace_separator is either NULL or contains one char + \0 */ self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler, namespace_separator); + self->parent = NULL; if (self->itself == NULL) { PyErr_SetString(PyExc_RuntimeError, "XML_ParserCreate failed"); @@ -1286,6 +1536,7 @@ xmlparse_traverse(PyObject *op, visitproc visit, void *arg) for (size_t i = 0; handler_info[i].name != NULL; i++) { Py_VISIT(self->handlers[i]); } + Py_VISIT(self->parent); Py_VISIT(Py_TYPE(op)); return 0; } @@ -1296,6 +1547,10 @@ xmlparse_clear(PyObject *op) xmlparseobject *self = xmlparseobject_CAST(op); clear_handlers(self, 0); Py_CLEAR(self->intern); + // NOTE: We cannot call Py_CLEAR(self->parent) prior to calling + // XML_ParserFree(self->itself), or a subparser could lose its parent + // XML_Parser while still making use of it internally. + // https://github.com/python/cpython/issues/139400 return 0; } @@ -1309,6 +1564,7 @@ xmlparse_dealloc(PyObject *op) XML_ParserFree(self->itself); } self->itself = NULL; + Py_CLEAR(self->parent); if (self->handlers != NULL) { PyMem_Free(self->handlers); @@ -2149,6 +2405,20 @@ pyexpat_exec(PyObject *mod) #else capi->SetReparseDeferralEnabled = NULL; #endif +#if XML_COMBINED_VERSION >= 20702 + capi->SetAllocTrackerActivationThreshold = XML_SetAllocTrackerActivationThreshold; + capi->SetAllocTrackerMaximumAmplification = XML_SetAllocTrackerMaximumAmplification; +#else + capi->SetAllocTrackerActivationThreshold = NULL; + capi->SetAllocTrackerMaximumAmplification = NULL; +#endif +#if XML_COMBINED_VERSION >= 20400 + capi->SetBillionLaughsAttackProtectionActivationThreshold = XML_SetBillionLaughsAttackProtectionActivationThreshold; + capi->SetBillionLaughsAttackProtectionMaximumAmplification = XML_SetBillionLaughsAttackProtectionMaximumAmplification; +#else + capi->SetAllocTrackerActivationThreshold = NULL; + capi->SetAllocTrackerMaximumAmplification = NULL; +#endif /* export using capsule */ PyObject *capi_object = PyCapsule_New(capi, PyExpat_CAPSULE_NAME, diff --git a/Modules/readline.c b/Modules/readline.c index 630a6879990..cc84eb6229e 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -255,6 +255,7 @@ readline_read_init_file_impl(PyObject *module, PyObject *filename_obj) if (!PyUnicode_FSConverter(filename_obj, &filename_bytes)) return NULL; if (PySys_Audit("open", "OCi", filename_obj, 'r', 0) < 0) { + Py_DECREF(filename_bytes); return NULL; } errno = rl_read_init_file(PyBytes_AS_STRING(filename_bytes)); @@ -298,6 +299,7 @@ readline_read_history_file_impl(PyObject *module, PyObject *filename_obj) if (!PyUnicode_FSConverter(filename_obj, &filename_bytes)) return NULL; if (PySys_Audit("open", "OCi", filename_obj, 'r', 0) < 0) { + Py_DECREF(filename_bytes); return NULL; } errno = read_history(PyBytes_AS_STRING(filename_bytes)); @@ -343,6 +345,7 @@ readline_write_history_file_impl(PyObject *module, PyObject *filename_obj) return NULL; filename = PyBytes_AS_STRING(filename_bytes); if (PySys_Audit("open", "OCi", filename_obj, 'w', 0) < 0) { + Py_DECREF(filename_bytes); return NULL; } } else { @@ -400,6 +403,7 @@ readline_append_history_file_impl(PyObject *module, int nelements, return NULL; filename = PyBytes_AS_STRING(filename_bytes); if (PySys_Audit("open", "OCi", filename_obj, 'a', 0) < 0) { + Py_DECREF(filename_bytes); return NULL; } } else { @@ -568,6 +572,26 @@ readline_set_pre_input_hook_impl(PyObject *module, PyObject *function) return set_hook("pre_input_hook", &state->pre_input_hook, function); } + +/* Get pre-input hook */ + +/*[clinic input] +readline.get_pre_input_hook + +Get the current pre-input hook function. +[clinic start generated code]*/ + +static PyObject * +readline_get_pre_input_hook_impl(PyObject *module) +/*[clinic end generated code: output=ad56b77a8e8981ca input=fb1e1b1fbd94e4e5]*/ +{ + readlinestate *state = get_readline_state(module); + if (state->pre_input_hook == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(state->pre_input_hook); +} + #endif @@ -1070,6 +1094,7 @@ static struct PyMethodDef readline_methods[] = READLINE_SET_STARTUP_HOOK_METHODDEF #ifdef HAVE_RL_PRE_INPUT_HOOK READLINE_SET_PRE_INPUT_HOOK_METHODDEF + READLINE_GET_PRE_INPUT_HOOK_METHODDEF #endif #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER READLINE_CLEAR_HISTORY_METHODDEF diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 99d96ebed2f..19fe509ec5e 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -262,7 +262,7 @@ A file descriptor is either a socket or file object, or a small integer gotten from a fileno() method call on one of those. The optional 4th argument specifies a timeout in seconds; it may be -a floating-point number to specify fractions of seconds. If it is absent +a non-integer to specify fractions of seconds. If it is absent or None, the call will never time out. The return value is a tuple of three lists corresponding to the first three @@ -277,7 +277,7 @@ descriptors can be used. static PyObject * select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, PyObject *xlist, PyObject *timeout_obj) -/*[clinic end generated code: output=2b3cfa824f7ae4cf input=df20779a9c2f5c1e]*/ +/*[clinic end generated code: output=2b3cfa824f7ae4cf input=b0403de75cd11cc1]*/ { #ifdef SELECT_USES_HEAP pylist *rfd2obj, *wfd2obj, *efd2obj; @@ -305,8 +305,9 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_SetString(PyExc_TypeError, - "timeout must be a float or None"); + PyErr_Format(PyExc_TypeError, + "timeout must be a real number or None, not %T", + timeout_obj); } return NULL; } @@ -433,7 +434,7 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, typedef struct { PyObject_HEAD - PyObject *dict; + PyObject *dict; // cannot create cycles as it only contains exact ints int ufd_uptodate; int ufd_len; struct pollfd *ufds; @@ -632,8 +633,9 @@ select_poll_poll_impl(pollObject *self, PyObject *timeout_obj) if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_SetString(PyExc_TypeError, - "timeout must be an integer or None"); + PyErr_Format(PyExc_TypeError, + "timeout must be a real number or None, not %T", + timeout_obj); } return NULL; } @@ -974,8 +976,9 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj) if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_SetString(PyExc_TypeError, - "timeout must be an integer or None"); + PyErr_Format(PyExc_TypeError, + "timeout must be a real number or None, not %T", + timeout_obj); } return NULL; } @@ -1565,7 +1568,7 @@ select_epoll_unregister_impl(pyEpoll_Object *self, int fd) select.epoll.poll timeout as timeout_obj: object = None - the maximum time to wait in seconds (as float); + the maximum time to wait in seconds (with fractions); a timeout of None or -1 makes poll wait indefinitely maxevents: int = -1 the maximum number of events returned; -1 means no limit @@ -1579,7 +1582,7 @@ as a list of (fd, events) 2-tuples. static PyObject * select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj, int maxevents) -/*[clinic end generated code: output=e02d121a20246c6c input=33d34a5ea430fd5b]*/ +/*[clinic end generated code: output=e02d121a20246c6c input=deafa7f04a60ebe0]*/ { int nfds, i; PyObject *elist = NULL, *etuple = NULL; @@ -1595,8 +1598,9 @@ select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj, if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_SetString(PyExc_TypeError, - "timeout must be an integer or None"); + PyErr_Format(PyExc_TypeError, + "timeout must be a real number or None, not %T", + timeout_obj); } return NULL; } @@ -2291,7 +2295,7 @@ select.kqueue.control The maximum number of events that the kernel will return. timeout as otimeout: object = None The maximum time to wait in seconds, or else None to wait forever. - This accepts floats for smaller timeouts, too. + This accepts non-integers for smaller timeouts, too. / Calls the kernel kevent function. @@ -2300,7 +2304,7 @@ Calls the kernel kevent function. static PyObject * select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist, int maxevents, PyObject *otimeout) -/*[clinic end generated code: output=81324ff5130db7ae input=59c4e30811209c47]*/ +/*[clinic end generated code: output=81324ff5130db7ae input=be969d2bc6f84205]*/ { int gotevents = 0; int nchanges = 0; @@ -2331,9 +2335,8 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist, if (_PyTime_FromSecondsObject(&timeout, otimeout, _PyTime_ROUND_TIMEOUT) < 0) { PyErr_Format(PyExc_TypeError, - "timeout argument must be a number " - "or None, got %.200s", - _PyType_Name(Py_TYPE(otimeout))); + "timeout must be a real number or None, not %T", + otimeout); return NULL; } @@ -2483,7 +2486,11 @@ static PyType_Slot poll_Type_slots[] = { static PyType_Spec poll_Type_spec = { .name = "select.poll", .basicsize = sizeof(pollObject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), .slots = poll_Type_slots, }; @@ -2529,11 +2536,10 @@ static PyType_Slot pyEpoll_Type_slots[] = { }; static PyType_Spec pyEpoll_Type_spec = { - "select.epoll", - sizeof(pyEpoll_Object), - 0, - Py_TPFLAGS_DEFAULT, - pyEpoll_Type_slots + .name = "select.epoll", + .basicsize = sizeof(pyEpoll_Object), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, + .slots = pyEpoll_Type_slots }; #endif /* HAVE_EPOLL */ diff --git a/Modules/sha1module.c b/Modules/sha1module.c index faa9dcccc57..89e66240d1d 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -21,6 +21,7 @@ #include "Python.h" #include "hashlib.h" +#include "pycore_object.h" // _PyObject_VisitType() #include "pycore_strhex.h" // _Py_strhex() #include "pycore_typeobject.h" // _PyType_GetModuleState() @@ -81,13 +82,6 @@ newSHA1object(SHA1State *st) /* Internal methods for a hash object */ -static int -SHA1_traverse(PyObject *ptr, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(ptr)); - return 0; -} - static void SHA1_dealloc(PyObject *op) { @@ -247,7 +241,7 @@ static PyType_Slot sha1_type_slots[] = { {Py_tp_dealloc, SHA1_dealloc}, {Py_tp_methods, SHA1_methods}, {Py_tp_getset, SHA1_getseters}, - {Py_tp_traverse, SHA1_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 36300ba899f..9453b0be512 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -22,8 +22,9 @@ #include "Python.h" #include "pycore_moduleobject.h" // _PyModule_GetState() -#include "pycore_typeobject.h" // _PyType_GetModuleState() +#include "pycore_object.h" // _PyObject_VisitType() #include "pycore_strhex.h" // _Py_strhex() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "hashlib.h" @@ -164,14 +165,6 @@ newSHA512object(sha2_state *state) } /* Internal methods for our hash objects. */ - -static int -SHA2_traverse(PyObject *ptr, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(ptr)); - return 0; -} - static void SHA256_dealloc(PyObject *op) { @@ -519,7 +512,7 @@ static PyType_Slot sha256_types_slots[] = { {Py_tp_dealloc, SHA256_dealloc}, {Py_tp_methods, SHA256_methods}, {Py_tp_getset, SHA256_getseters}, - {Py_tp_traverse, SHA2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; @@ -527,7 +520,7 @@ static PyType_Slot sha512_type_slots[] = { {Py_tp_dealloc, SHA512_dealloc}, {Py_tp_methods, SHA512_methods}, {Py_tp_getset, SHA512_getseters}, - {Py_tp_traverse, SHA2_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0,0} }; diff --git a/Modules/sha3module.c b/Modules/sha3module.c index 5764556bb68..38c9bc0405b 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -21,6 +21,7 @@ #endif #include "Python.h" +#include "pycore_object.h" // _PyObject_VisitType() #include "pycore_strhex.h" // _Py_strhex() #include "pycore_typeobject.h" // _PyType_GetModuleState() #include "hashlib.h" @@ -226,13 +227,6 @@ SHA3_dealloc(PyObject *self) Py_DECREF(tp); } -static int -SHA3_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - /* External methods for a hash object */ @@ -424,7 +418,7 @@ static PyGetSetDef SHA3_getseters[] = { static PyType_Slot type_slots_obj[] = { \ {Py_tp_clear, SHA3_clear}, \ {Py_tp_dealloc, SHA3_dealloc}, \ - {Py_tp_traverse, SHA3_traverse}, \ + {Py_tp_traverse, _PyObject_VisitType}, \ {Py_tp_doc, (char*)type_doc}, \ {Py_tp_methods, type_methods}, \ {Py_tp_getset, type_getseters}, \ @@ -478,10 +472,7 @@ SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots); static int sha3_shake_check_digest_length(Py_ssize_t length) { - if (length < 0) { - PyErr_SetString(PyExc_ValueError, "negative digest length"); - return -1; - } + assert(length >= 0); if ((size_t)length >= (1 << 29)) { /* * Raise OverflowError to match the semantics of OpenSSL SHAKE @@ -498,14 +489,14 @@ sha3_shake_check_digest_length(Py_ssize_t length) /*[clinic input] _sha3.shake_128.digest - length: Py_ssize_t + length: Py_ssize_t(allow_negative=False) Return the digest value as a bytes object. [clinic start generated code]*/ static PyObject * _sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length) -/*[clinic end generated code: output=6c53fb71a6cff0a0 input=be03ade4b31dd54c]*/ +/*[clinic end generated code: output=6c53fb71a6cff0a0 input=1160c9f86ae0f867]*/ { if (sha3_shake_check_digest_length(length) < 0) { return NULL; @@ -519,28 +510,33 @@ _sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length) if (length == 0) { return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - CHECK_HACL_UINT32_T_LENGTH(length); - PyObject *digest = PyBytes_FromStringAndSize(NULL, length); - uint8_t *buffer = (uint8_t *)PyBytes_AS_STRING(digest); + + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { + return NULL; + } + uint8_t *buffer = (uint8_t *)PyBytesWriter_GetData(writer); + HASHLIB_ACQUIRE_LOCK(self); (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length); HASHLIB_RELEASE_LOCK(self); - return digest; + + return PyBytesWriter_Finish(writer); } /*[clinic input] _sha3.shake_128.hexdigest - length: Py_ssize_t + length: Py_ssize_t(allow_negative=False) Return the digest value as a string of hexadecimal digits. [clinic start generated code]*/ static PyObject * _sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length) -/*[clinic end generated code: output=a27412d404f64512 input=0d84d05d7a8ccd37]*/ +/*[clinic end generated code: output=a27412d404f64512 input=ff06c9362949d2c8]*/ { if (sha3_shake_check_digest_length(length) < 0) { return NULL; @@ -550,8 +546,8 @@ _sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length) if (length == 0) { return Py_GetConstant(Py_CONSTANT_EMPTY_STR); } - CHECK_HACL_UINT32_T_LENGTH(length); + uint8_t *buffer = PyMem_Malloc(length); if (buffer == NULL) { return PyErr_NoMemory(); @@ -560,6 +556,7 @@ _sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length) HASHLIB_ACQUIRE_LOCK(self); (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length); HASHLIB_RELEASE_LOCK(self); + PyObject *digest = _Py_strhex((const char *)buffer, length); PyMem_Free(buffer); return digest; diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 59b08e28d7b..4d0e224ff75 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1183,7 +1183,13 @@ signal_sigwaitinfo_impl(PyObject *module, sigset_t sigset) err = sigwaitinfo(&sigset, &si); Py_END_ALLOW_THREADS } while (err == -1 - && errno == EINTR && !(async_err = PyErr_CheckSignals())); + && (errno == EINTR +#if defined(__NetBSD__) + /* NetBSD's implementation violates POSIX by setting + * errno to ECANCELED instead of EINTR. */ + || errno == ECANCELED +#endif + ) && !(async_err = PyErr_CheckSignals())); if (err == -1) return (!async_err) ? PyErr_SetFromErrno(PyExc_OSError) : NULL; @@ -1204,13 +1210,13 @@ signal.sigtimedwait Like sigwaitinfo(), but with a timeout. -The timeout is specified in seconds, with floating-point numbers allowed. +The timeout is specified in seconds, rounded up to nanoseconds. [clinic start generated code]*/ static PyObject * signal_sigtimedwait_impl(PyObject *module, sigset_t sigset, PyObject *timeout_obj) -/*[clinic end generated code: output=59c8971e8ae18a64 input=955773219c1596cd]*/ +/*[clinic end generated code: output=59c8971e8ae18a64 input=f89af57d645e48e0]*/ { PyTime_t timeout; if (_PyTime_FromSecondsObject(&timeout, @@ -1943,7 +1949,7 @@ signal_install_handlers(void) /* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. * * All of the code in this function must only use async-signal-safe functions, - * listed at `man 7 signal` or + * listed at `man 7 signal-safety` or * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. * * If this function is updated, update also _posix_spawn() of subprocess.py. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index c5b16dc4fe4..1ef359cb265 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -109,6 +109,7 @@ Local naming conventions: #include "pycore_capsule.h" // _PyCapsule_SetTraverse() #include "pycore_fileutils.h" // _Py_set_inheritable() #include "pycore_moduleobject.h" // _PyModule_GetState +#include "pycore_object.h" // _PyObject_VisitType() #include "pycore_time.h" // _PyTime_AsMilliseconds() #include "pycore_pystate.h" // _Py_AssertHoldsTstate() @@ -3467,7 +3468,6 @@ sock_getsockopt(PyObject *self, PyObject *args) int level; int optname; int res; - PyObject *buf; socklen_t buflen = 0; int flag = 0; socklen_t flagsize; @@ -3512,17 +3512,17 @@ sock_getsockopt(PyObject *self, PyObject *args) "getsockopt buflen out of range"); return NULL; } - buf = PyBytes_FromStringAndSize((char *)NULL, buflen); - if (buf == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(buflen); + if (writer == NULL) { return NULL; + } res = getsockopt(get_sock_fd(s), level, optname, - (void *)PyBytes_AS_STRING(buf), &buflen); + PyBytesWriter_GetData(writer), &buflen); if (res < 0) { - Py_DECREF(buf); + PyBytesWriter_Discard(writer); return s->errorhandler(); } - _PyBytes_Resize(&buf, buflen); - return buf; + return PyBytesWriter_FinishWithSize(writer, buflen); } PyDoc_STRVAR(getsockopt_doc, @@ -3979,7 +3979,6 @@ sock_recv(PyObject *self, PyObject *args) Py_ssize_t recvlen, outlen; int flags = 0; - PyObject *buf; if (!PyArg_ParseTuple(args, "n|i:recv", &recvlen, &flags)) return NULL; @@ -3991,25 +3990,21 @@ sock_recv(PyObject *self, PyObject *args) } /* Allocate a new string. */ - buf = PyBytes_FromStringAndSize((char *) 0, recvlen); - if (buf == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(recvlen); + if (writer == NULL) { return NULL; + } /* Call the guts */ - outlen = sock_recv_guts(s, PyBytes_AS_STRING(buf), recvlen, flags); + outlen = sock_recv_guts(s, PyBytesWriter_GetData(writer), recvlen, flags); if (outlen < 0) { /* An error occurred, release the string and return an error. */ - Py_DECREF(buf); + PyBytesWriter_Discard(writer); return NULL; } - if (outlen != recvlen) { - /* We did not read as many bytes as we anticipated, resize the - string if possible and be successful. */ - _PyBytes_Resize(&buf, outlen); - } - return buf; + return PyBytesWriter_FinishWithSize(writer, outlen); } PyDoc_STRVAR(recv_doc, @@ -4165,7 +4160,6 @@ sock_recvfrom(PyObject *self, PyObject *args) { PySocketSockObject *s = _PySocketSockObject_CAST(self); - PyObject *buf = NULL; PyObject *addr = NULL; PyObject *ret = NULL; int flags = 0; @@ -4180,28 +4174,27 @@ sock_recvfrom(PyObject *self, PyObject *args) return NULL; } - buf = PyBytes_FromStringAndSize((char *) 0, recvlen); - if (buf == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(recvlen); + if (writer == NULL) { return NULL; + } - outlen = sock_recvfrom_guts(s, PyBytes_AS_STRING(buf), + outlen = sock_recvfrom_guts(s, PyBytesWriter_GetData(writer), recvlen, flags, &addr); if (outlen < 0) { + PyBytesWriter_Discard(writer); goto finally; } - if (outlen != recvlen) { - /* We did not read as many bytes as we anticipated, resize the - string if possible and be successful. */ - if (_PyBytes_Resize(&buf, outlen) < 0) - /* Oopsy, not so successful after all. */ - goto finally; + PyObject *buf = PyBytesWriter_FinishWithSize(writer, outlen); + if (buf == NULL) { + goto finally; } ret = PyTuple_Pack(2, buf, addr); + Py_DECREF(buf); finally: - Py_XDECREF(buf); Py_XDECREF(addr); return ret; } @@ -4434,11 +4427,10 @@ err_closefds: static PyObject * makeval_recvmsg(ssize_t received, void *data) { - PyObject **buf = data; - - if (received < PyBytes_GET_SIZE(*buf)) - _PyBytes_Resize(buf, received); - return Py_XNewRef(*buf); + PyBytesWriter **writer = data; + PyObject *buf = PyBytesWriter_FinishWithSize(*writer, received); + *writer = NULL; + return buf; } /* s.recvmsg(bufsize[, ancbufsize[, flags]]) method */ @@ -4446,13 +4438,8 @@ makeval_recvmsg(ssize_t received, void *data) static PyObject * sock_recvmsg(PyObject *self, PyObject *args) { - PySocketSockObject *s = _PySocketSockObject_CAST(self); - Py_ssize_t bufsize, ancbufsize = 0; int flags = 0; - struct iovec iov; - PyObject *buf = NULL, *retval = NULL; - if (!PyArg_ParseTuple(args, "n|ni:recvmsg", &bufsize, &ancbufsize, &flags)) return NULL; @@ -4460,17 +4447,23 @@ sock_recvmsg(PyObject *self, PyObject *args) PyErr_SetString(PyExc_ValueError, "negative buffer size in recvmsg()"); return NULL; } - if ((buf = PyBytes_FromStringAndSize(NULL, bufsize)) == NULL) + + PyBytesWriter *writer = PyBytesWriter_Create(bufsize); + if (writer == NULL) { return NULL; - iov.iov_base = PyBytes_AS_STRING(buf); + } + struct iovec iov; + iov.iov_base = PyBytesWriter_GetData(writer); iov.iov_len = bufsize; /* Note that we're passing a pointer to *our pointer* to the bytes - object here (&buf); makeval_recvmsg() may incref the object, or - deallocate it and set our pointer to NULL. */ + writer (&writer); makeval_recvmsg() finish it and set our pointer to + NULL. */ + PyObject *retval; + PySocketSockObject *s = _PySocketSockObject_CAST(self); retval = sock_recvmsg_guts(s, &iov, 1, flags, ancbufsize, - &makeval_recvmsg, &buf); - Py_XDECREF(buf); + &makeval_recvmsg, &writer); + PyBytesWriter_Discard(writer); return retval; } @@ -5538,13 +5531,6 @@ sock_finalize(PyObject *self) PyErr_SetRaisedException(exc); } -static int -sock_traverse(PyObject *s, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(s)); - return 0; -} - static void sock_dealloc(PyObject *s) { @@ -5843,7 +5829,7 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, static PyType_Slot sock_slots[] = { {Py_tp_dealloc, sock_dealloc}, - {Py_tp_traverse, sock_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_repr, sock_repr}, {Py_tp_doc, (void *)sock_doc}, {Py_tp_methods, sock_methods}, @@ -7197,7 +7183,7 @@ socket_setdefaulttimeout(PyObject *self, PyObject *arg) PyDoc_STRVAR(setdefaulttimeout_doc, "setdefaulttimeout(timeout)\n\ \n\ -Set the default timeout in seconds (float) for new socket objects.\n\ +Set the default timeout in seconds (real number) for new socket objects.\n\ A value of None indicates that new socket objects have no timeout.\n\ When the socket module is first imported, the default is None."); @@ -7292,7 +7278,7 @@ Returns a list of network interface information (index, name) tuples."); /*[clinic input] _socket.if_nametoindex - oname: object(converter="PyUnicode_FSConverter") + oname: unicode_fs_encoded / Returns the interface index corresponding to the interface name if_name. @@ -7300,7 +7286,7 @@ Returns the interface index corresponding to the interface name if_name. static PyObject * _socket_if_nametoindex_impl(PyObject *module, PyObject *oname) -/*[clinic end generated code: output=289a411614f30244 input=01e0f1205307fb77]*/ +/*[clinic end generated code: output=289a411614f30244 input=6125dc20683560cf]*/ { #ifdef MS_WINDOWS NET_IFINDEX index; @@ -7308,11 +7294,10 @@ _socket_if_nametoindex_impl(PyObject *module, PyObject *oname) unsigned long index; #endif + errno = ENODEV; // in case 'if_nametoindex' does not set errno index = if_nametoindex(PyBytes_AS_STRING(oname)); - Py_DECREF(oname); if (index == 0) { - /* if_nametoindex() doesn't set errno */ - PyErr_SetString(PyExc_OSError, "no interface with this name"); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -7332,6 +7317,7 @@ static PyObject * _socket_if_indextoname_impl(PyObject *module, NET_IFINDEX index) /*[clinic end generated code: output=e48bc324993052e0 input=c93f753d0cf6d7d1]*/ { + errno = ENXIO; // in case 'if_indextoname' does not set errno char name[IF_NAMESIZE + 1]; if (if_indextoname(index, name) == NULL) { PyErr_SetFromErrno(PyExc_OSError); @@ -8536,6 +8522,43 @@ socket_exec(PyObject *m) ADD_INT_MACRO(m, J1939_FILTER_MAX); #endif +#ifdef HAVE_LINUX_CAN_ISOTP_H + ADD_INT_MACRO(m, SOL_CAN_ISOTP); + + ADD_INT_MACRO(m, CAN_ISOTP_OPTS); + ADD_INT_MACRO(m, CAN_ISOTP_RECV_FC); + + ADD_INT_MACRO(m, CAN_ISOTP_TX_STMIN); + ADD_INT_MACRO(m, CAN_ISOTP_RX_STMIN); + ADD_INT_MACRO(m, CAN_ISOTP_LL_OPTS); + + ADD_INT_MACRO(m, CAN_ISOTP_LISTEN_MODE); + ADD_INT_MACRO(m, CAN_ISOTP_EXTEND_ADDR); + ADD_INT_MACRO(m, CAN_ISOTP_TX_PADDING); + ADD_INT_MACRO(m, CAN_ISOTP_RX_PADDING); + ADD_INT_MACRO(m, CAN_ISOTP_CHK_PAD_LEN); + ADD_INT_MACRO(m, CAN_ISOTP_CHK_PAD_DATA); + ADD_INT_MACRO(m, CAN_ISOTP_HALF_DUPLEX); + ADD_INT_MACRO(m, CAN_ISOTP_FORCE_TXSTMIN); + ADD_INT_MACRO(m, CAN_ISOTP_FORCE_RXSTMIN); + ADD_INT_MACRO(m, CAN_ISOTP_RX_EXT_ADDR); + ADD_INT_MACRO(m, CAN_ISOTP_WAIT_TX_DONE); +#ifdef CAN_ISOTP_SF_BROADCAST + ADD_INT_MACRO(m, CAN_ISOTP_SF_BROADCAST); +#endif + + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_FLAGS); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_EXT_ADDRESS); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_PAD_CONTENT); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_FRAME_TXTIME); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_RECV_BS); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_RECV_STMIN); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_RECV_WFTMAX); + + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_LL_MTU); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_LL_TX_DL); + ADD_INT_MACRO(m, CAN_ISOTP_DEFAULT_LL_TX_FLAGS); +#endif #ifdef SOL_RDS ADD_INT_MACRO(m, SOL_RDS); #endif @@ -8878,6 +8901,9 @@ socket_exec(PyObject *m) #ifdef IPV6_HOPLIMIT ADD_INT_MACRO(m, IPV6_HOPLIMIT); #endif +#ifdef IPV6_HDRINCL + ADD_INT_MACRO(m, IPV6_HDRINCL); +#endif #ifdef IPV6_HOPOPTS ADD_INT_MACRO(m, IPV6_HOPOPTS); #endif diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index 7fd929af5f2..ac770889ae8 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -165,6 +165,10 @@ typedef int socklen_t; #include <linux/can/bcm.h> #endif +#ifdef HAVE_LINUX_CAN_ISOTP_H +#include <linux/can/isotp.h> +#endif + #ifdef HAVE_LINUX_CAN_J1939_H #include <linux/can/j1939.h> #endif diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c index d0d5223e5ac..a24927a9db6 100644 --- a/Modules/symtablemodule.c +++ b/Modules/symtablemodule.c @@ -13,17 +13,20 @@ module _symtable _symtable.symtable source: object - filename: object(converter='PyUnicode_FSDecoder') + filename: unicode_fs_decoded startstr: str / + * + module as modname: object = None Return symbol and scope dictionaries used internally by compiler. [clinic start generated code]*/ static PyObject * _symtable_symtable_impl(PyObject *module, PyObject *source, - PyObject *filename, const char *startstr) -/*[clinic end generated code: output=59eb0d5fc7285ac4 input=9dd8a50c0c36a4d7]*/ + PyObject *filename, const char *startstr, + PyObject *modname) +/*[clinic end generated code: output=235ec5a87a9ce178 input=fbf9adaa33c7070d]*/ { struct symtable *st; PyObject *t; @@ -47,12 +50,20 @@ _symtable_symtable_impl(PyObject *module, PyObject *source, else { PyErr_SetString(PyExc_ValueError, "symtable() arg 3 must be 'exec' or 'eval' or 'single'"); - Py_DECREF(filename); Py_XDECREF(source_copy); return NULL; } - st = _Py_SymtableStringObjectFlags(str, filename, start, &cf); - Py_DECREF(filename); + if (modname == Py_None) { + modname = NULL; + } + else if (!PyUnicode_Check(modname)) { + PyErr_Format(PyExc_TypeError, + "symtable() argument 'module' must be str or None, not %T", + modname); + Py_XDECREF(source_copy); + return NULL; + } + st = _Py_SymtableStringObjectFlags(str, filename, start, &cf, modname); Py_XDECREF(source_copy); if (st == NULL) { return NULL; diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 3271d87ddc2..3946d18479e 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -128,7 +128,7 @@ time_time_ns(PyObject *self, PyObject *unused) if (PyTime_Time(&t) < 0) { return NULL; } - return _PyTime_AsLong(t); + return PyLong_FromInt64(t); } PyDoc_STRVAR(time_ns_doc, @@ -261,7 +261,7 @@ time_clock_gettime_ns_impl(PyObject *module, clockid_t clk_id) if (_PyTime_FromTimespec(&t, &ts) < 0) { return NULL; } - return _PyTime_AsLong(t); + return PyLong_FromInt64(t); } #endif /* HAVE_CLOCK_GETTIME */ @@ -310,7 +310,7 @@ time_clock_settime_ns(PyObject *self, PyObject *args) return NULL; } - if (_PyTime_FromLong(&t, obj) < 0) { + if (PyLong_AsInt64(obj, &t) < 0) { return NULL; } if (_PyTime_AsTimespec(t, &ts) == -1) { @@ -1216,7 +1216,7 @@ time_monotonic_ns(PyObject *self, PyObject *unused) if (PyTime_Monotonic(&t) < 0) { return NULL; } - return _PyTime_AsLong(t); + return PyLong_FromInt64(t); } PyDoc_STRVAR(monotonic_ns_doc, @@ -1248,7 +1248,7 @@ time_perf_counter_ns(PyObject *self, PyObject *unused) if (PyTime_PerfCounter(&t) < 0) { return NULL; } - return _PyTime_AsLong(t); + return PyLong_FromInt64(t); } PyDoc_STRVAR(perf_counter_ns_doc, @@ -1437,7 +1437,7 @@ time_process_time_ns(PyObject *module, PyObject *unused) if (py_process_time(state, &t, NULL) < 0) { return NULL; } - return _PyTime_AsLong(t); + return PyLong_FromInt64(t); } PyDoc_STRVAR(process_time_ns_doc, @@ -1610,7 +1610,7 @@ time_thread_time_ns(PyObject *self, PyObject *unused) if (_PyTime_GetThreadTimeWithInfo(&t, NULL) < 0) { return NULL; } - return _PyTime_AsLong(t); + return PyLong_FromInt64(t); } PyDoc_STRVAR(thread_time_ns_doc, diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 2a30030a2a1..a6094676d41 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -17,7 +17,9 @@ #endif #include "Python.h" +#include "pycore_object.h" // _PyObject_VisitType() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI +#include "pycore_unicodectype.h" // _PyUnicode_IsXidStart() #include <stdbool.h> #include <stddef.h> // offsetof() @@ -1020,13 +1022,14 @@ is_unified_ideograph(Py_UCS4 code) (0x3400 <= code && code <= 0x4DBF) || /* CJK Ideograph Extension A */ (0x4E00 <= code && code <= 0x9FFF) || /* CJK Ideograph */ (0x20000 <= code && code <= 0x2A6DF) || /* CJK Ideograph Extension B */ - (0x2A700 <= code && code <= 0x2B739) || /* CJK Ideograph Extension C */ + (0x2A700 <= code && code <= 0x2B73F) || /* CJK Ideograph Extension C */ (0x2B740 <= code && code <= 0x2B81D) || /* CJK Ideograph Extension D */ - (0x2B820 <= code && code <= 0x2CEA1) || /* CJK Ideograph Extension E */ + (0x2B820 <= code && code <= 0x2CEAD) || /* CJK Ideograph Extension E */ (0x2CEB0 <= code && code <= 0x2EBE0) || /* CJK Ideograph Extension F */ (0x2EBF0 <= code && code <= 0x2EE5D) || /* CJK Ideograph Extension I */ (0x30000 <= code && code <= 0x3134A) || /* CJK Ideograph Extension G */ - (0x31350 <= code && code <= 0x323AF); /* CJK Ideograph Extension H */ + (0x31350 <= code && code <= 0x323AF) || /* CJK Ideograph Extension H */ + (0x323B0 <= code && code <= 0x33479); /* CJK Ideograph Extension J */ } /* macros used to determine if the given code point is in the PUA range that @@ -1523,6 +1526,58 @@ unicodedata_UCD_name_impl(PyObject *self, int chr, PyObject *default_value) return PyUnicode_FromString(name); } +/*[clinic input] +unicodedata.UCD.isxidstart + + self: self + chr: int(accept={str}) + / + +Return True if the character has the XID_Start property, else False. + +[clinic start generated code]*/ + +static PyObject * +unicodedata_UCD_isxidstart_impl(PyObject *self, int chr) +/*[clinic end generated code: output=944005823c72c3ef input=9353f88d709c21fb]*/ +{ + if (UCD_Check(self)) { + const change_record *old = get_old_record(self, chr); + if (old->category_changed == 0) { + /* unassigned */ + Py_RETURN_FALSE; + } + } + + return PyBool_FromLong(_PyUnicode_IsXidStart(chr)); +} + +/*[clinic input] +unicodedata.UCD.isxidcontinue + + self: self + chr: int(accept={str}) + / + +Return True if the character has the XID_Continue property, else False. + +[clinic start generated code]*/ + +static PyObject * +unicodedata_UCD_isxidcontinue_impl(PyObject *self, int chr) +/*[clinic end generated code: output=9438dcbff5ca3e41 input=bbb8dd3ac0d2d709]*/ +{ + if (UCD_Check(self)) { + const change_record *old = get_old_record(self, chr); + if (old->category_changed == 0) { + /* unassigned */ + Py_RETURN_FALSE; + } + } + + return PyBool_FromLong(_PyUnicode_IsXidContinue(chr)); +} + /*[clinic input] unicodedata.UCD.lookup @@ -1588,19 +1643,14 @@ static PyMethodDef unicodedata_functions[] = { UNICODEDATA_UCD_EAST_ASIAN_WIDTH_METHODDEF UNICODEDATA_UCD_DECOMPOSITION_METHODDEF UNICODEDATA_UCD_NAME_METHODDEF + UNICODEDATA_UCD_ISXIDSTART_METHODDEF + UNICODEDATA_UCD_ISXIDCONTINUE_METHODDEF UNICODEDATA_UCD_LOOKUP_METHODDEF UNICODEDATA_UCD_IS_NORMALIZED_METHODDEF UNICODEDATA_UCD_NORMALIZE_METHODDEF {NULL, NULL} /* sentinel */ }; -static int -ucd_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static void ucd_dealloc(PyObject *self) { @@ -1612,7 +1662,7 @@ ucd_dealloc(PyObject *self) static PyType_Slot ucd_type_slots[] = { {Py_tp_dealloc, ucd_dealloc}, - {Py_tp_traverse, ucd_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_methods, unicodedata_functions}, {Py_tp_members, DB_members}, diff --git a/Modules/unicodedata_db.h b/Modules/unicodedata_db.h index 610ee6b749c..eb0da8a6ff9 100644 --- a/Modules/unicodedata_db.h +++ b/Modules/unicodedata_db.h @@ -1,6 +1,6 @@ /* this file was generated by Tools/unicode/makeunicodedata.py 3.3 */ -#define UNIDATA_VERSION "16.0.0" +#define UNIDATA_VERSION "17.0.0" /* a list of unique database records */ const _PyUnicode_DatabaseRecord _PyUnicode_Database_Records[] = { {0, 0, 0, 0, 0, 0}, @@ -181,8 +181,8 @@ const _PyUnicode_DatabaseRecord _PyUnicode_Database_Records[] = { {8, 0, 1, 0, 0, 0}, {5, 9, 1, 0, 0, 0}, {14, 0, 15, 0, 0, 0}, - {4, 1, 14, 0, 0, 0}, {4, 234, 14, 0, 0, 0}, + {4, 1, 14, 0, 0, 0}, {4, 214, 14, 0, 0, 0}, {4, 202, 14, 0, 0, 0}, {4, 232, 14, 0, 0, 0}, @@ -783,7 +783,7 @@ static const unsigned short index1[] = { 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, - 101, 208, 101, 101, 101, 101, 101, 101, 101, 101, 101, 209, 210, 137, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 208, 209, 210, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, @@ -796,9 +796,9 @@ static const unsigned short index1[] = { 216, 216, 216, 218, 219, 220, 78, 221, 222, 223, 224, 225, 226, 137, 227, 228, 229, 230, 231, 232, 233, 234, 78, 78, 78, 78, 235, 236, 137, 137, 137, 137, 137, 137, 137, 137, 237, 137, 238, 239, 240, 137, 137, 241, - 137, 137, 137, 242, 137, 243, 137, 137, 137, 244, 245, 246, 247, 137, - 137, 137, 137, 137, 248, 249, 250, 137, 251, 252, 137, 137, 253, 254, - 255, 256, 257, 137, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 137, 137, 137, 242, 137, 243, 137, 244, 137, 245, 246, 247, 248, 137, + 137, 137, 137, 137, 249, 250, 251, 137, 252, 253, 137, 137, 254, 255, + 256, 257, 258, 137, 259, 260, 261, 262, 263, 264, 265, 266, 216, 267, 268, 269, 270, 271, 272, 273, 216, 274, 137, 137, 137, 137, 137, 137, 137, 137, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, @@ -826,54 +826,54 @@ static const unsigned short index1[] = { 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 275, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 276, 101, 277, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 276, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 101, 101, 101, 101, 101, 278, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 277, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 279, 101, 101, - 101, 101, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 121, 121, 121, 121, 282, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 283, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 278, 101, 101, + 101, 101, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 121, 121, 121, 121, 281, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 282, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 101, 101, 284, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 283, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 285, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 283, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 284, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 282, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, @@ -1239,7 +1239,7 @@ static const unsigned short index1[] = { 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, - 286, 137, 287, 288, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 285, 137, 286, 287, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, @@ -1312,7 +1312,7 @@ static const unsigned short index1[] = { 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, - 120, 289, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 288, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, @@ -1348,7 +1348,7 @@ static const unsigned short index1[] = { 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, 120, 289, + 120, 120, 120, 120, 120, 120, 120, 120, 120, 288, }; static const unsigned short index2[] = { @@ -1387,7 +1387,7 @@ static const unsigned short index2[] = { 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 41, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 48, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 48, 48, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 53, 53, 53, 53, 53, 53, 53, 54, 54, 55, 54, 52, 56, 52, 56, 56, 56, 52, 56, 52, 52, 57, 53, 54, 54, 54, @@ -1479,90 +1479,90 @@ static const unsigned short index2[] = { 107, 107, 107, 107, 107, 107, 86, 86, 86, 0, 0, 104, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 140, 118, 118, 118, 118, 118, 118, 0, - 108, 108, 0, 0, 0, 0, 0, 81, 81, 86, 86, 86, 81, 81, 81, 81, 118, 118, + 118, 118, 118, 118, 118, 118, 118, 140, 118, 118, 118, 118, 118, 118, + 118, 108, 108, 0, 0, 0, 0, 0, 81, 81, 86, 86, 86, 81, 81, 81, 81, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 120, 81, 81, 81, - 81, 81, 86, 86, 86, 86, 86, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 108, 86, 81, 81, 86, 81, 81, 86, 81, 81, 81, 86, 86, 86, 121, - 122, 123, 81, 81, 81, 86, 81, 81, 86, 86, 81, 81, 81, 81, 81, 135, 135, - 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 120, 81, 81, + 81, 81, 81, 86, 86, 86, 86, 86, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 108, 86, 81, 81, 86, 81, 81, 86, 81, 81, 81, 86, 86, 86, + 121, 122, 123, 81, 81, 81, 86, 81, 81, 86, 86, 81, 81, 81, 81, 81, 135, + 135, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 142, 48, 48, 48, 48, 48, 48, 48, 142, 48, 48, 142, 48, 48, - 48, 48, 48, 135, 141, 143, 48, 141, 141, 141, 135, 135, 135, 135, 135, - 135, 135, 135, 141, 141, 141, 141, 144, 141, 141, 48, 81, 86, 81, 81, - 135, 135, 135, 145, 145, 145, 145, 145, 145, 145, 145, 48, 48, 135, 135, - 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 53, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 141, 141, 0, 48, - 48, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 0, 0, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, - 48, 48, 48, 48, 48, 48, 0, 48, 0, 0, 0, 48, 48, 48, 48, 0, 0, 147, 48, - 148, 141, 141, 135, 135, 135, 135, 0, 0, 141, 141, 0, 0, 149, 149, 144, - 48, 0, 0, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 145, 145, 0, 145, 48, 48, - 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, - 85, 85, 150, 150, 150, 150, 150, 150, 80, 85, 48, 83, 81, 0, 0, 135, 135, - 141, 0, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 48, 48, 0, 0, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 142, 48, 48, 48, 48, 48, 48, 48, 142, 48, 48, 142, + 48, 48, 48, 48, 48, 135, 141, 143, 48, 141, 141, 141, 135, 135, 135, 135, + 135, 135, 135, 135, 141, 141, 141, 141, 144, 141, 141, 48, 81, 86, 81, + 81, 135, 135, 135, 145, 145, 145, 145, 145, 145, 145, 145, 48, 48, 135, + 135, 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 53, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 141, + 141, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 145, 0, 48, 145, 0, 48, 48, 0, 0, - 147, 0, 141, 141, 141, 135, 135, 0, 0, 0, 0, 135, 135, 0, 0, 135, 135, - 144, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 145, 145, 145, 48, 0, 145, 0, 0, - 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 135, - 135, 48, 48, 48, 135, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 141, 0, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, - 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 0, 0, 147, - 48, 141, 141, 141, 135, 135, 135, 135, 135, 0, 135, 135, 141, 0, 141, - 141, 144, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, - 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 85, - 0, 0, 0, 0, 0, 0, 0, 48, 135, 135, 135, 135, 135, 135, 0, 135, 141, 141, - 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 0, 0, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 0, 0, - 147, 48, 148, 135, 141, 135, 135, 135, 135, 0, 0, 141, 149, 0, 0, 149, - 149, 144, 0, 0, 0, 0, 0, 0, 0, 135, 151, 148, 0, 0, 0, 0, 145, 145, 0, - 48, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 80, 48, 150, 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 135, 48, 0, 48, 48, 48, 48, 48, 48, 0, 0, 0, 48, 48, 48, 0, 48, 48, 142, - 48, 0, 0, 0, 48, 48, 0, 48, 0, 48, 48, 0, 0, 0, 48, 48, 0, 0, 0, 48, 48, - 48, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, - 148, 141, 135, 141, 141, 0, 0, 0, 141, 141, 141, 0, 149, 149, 149, 144, - 0, 0, 48, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 150, 150, 150, 26, - 26, 26, 26, 26, 26, 85, 26, 0, 0, 0, 0, 0, 135, 141, 141, 141, 135, 48, - 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 147, - 48, 135, 135, 135, 141, 141, 141, 141, 0, 135, 135, 152, 0, 135, 135, - 135, 144, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 48, 48, 48, 0, 0, 48, 0, 0, + 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 0, 0, 0, 48, 48, 48, 48, 0, 0, + 147, 48, 148, 141, 141, 135, 135, 135, 135, 0, 0, 141, 141, 0, 0, 149, + 149, 144, 48, 0, 0, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 145, 145, 0, 145, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 0, 0, 0, 0, 0, 0, 0, 83, 155, 155, 155, 155, 155, 155, 155, 80, 48, 135, - 141, 141, 83, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, 48, 48, + 48, 48, 85, 85, 150, 150, 150, 150, 150, 150, 80, 85, 48, 83, 81, 0, 0, + 135, 135, 141, 0, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 48, 48, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, - 48, 0, 0, 147, 48, 141, 156, 149, 141, 148, 141, 141, 0, 156, 149, 149, - 0, 149, 149, 135, 144, 0, 0, 0, 0, 0, 0, 0, 148, 148, 0, 0, 0, 0, 0, 0, - 48, 48, 0, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 0, 48, 48, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, - 135, 141, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, 48, + 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 145, 0, 48, 145, 0, 48, + 48, 0, 0, 147, 0, 141, 141, 141, 135, 135, 0, 0, 0, 0, 135, 135, 0, 0, + 135, 135, 144, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 145, 145, 145, 48, 0, + 145, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 135, 135, 48, 48, 48, 135, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, + 135, 141, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, + 48, 0, 0, 147, 48, 141, 141, 141, 135, 135, 135, 135, 135, 0, 135, 135, + 141, 0, 141, 141, 144, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 83, 85, 0, 0, 0, 0, 0, 0, 0, 48, 135, 135, 135, 135, 135, 135, + 0, 135, 141, 141, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, + 48, 48, 0, 0, 147, 48, 148, 135, 141, 135, 135, 135, 135, 0, 0, 141, 149, + 0, 0, 149, 149, 144, 0, 0, 0, 0, 0, 0, 0, 135, 151, 148, 0, 0, 0, 0, 145, + 145, 0, 48, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 80, 48, 150, 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 135, 48, 0, 48, 48, 48, 48, 48, 48, 0, 0, 0, 48, 48, 48, 0, 48, + 48, 142, 48, 0, 0, 0, 48, 48, 0, 48, 0, 48, 48, 0, 0, 0, 48, 48, 0, 0, 0, + 48, 48, 48, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, + 0, 0, 0, 148, 141, 135, 141, 141, 0, 0, 0, 141, 141, 141, 0, 149, 149, + 149, 144, 0, 0, 48, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 150, 150, + 150, 26, 26, 26, 26, 26, 26, 85, 26, 0, 0, 0, 0, 0, 135, 141, 141, 141, + 135, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, + 0, 147, 48, 135, 135, 135, 141, 141, 141, 141, 0, 135, 135, 152, 0, 135, + 135, 135, 144, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 48, 48, 48, 0, 48, 48, + 0, 0, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 0, 0, 0, 0, 0, 0, 0, 83, 155, 155, 155, 155, 155, 155, 155, 80, + 48, 135, 141, 141, 83, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, + 48, 48, 48, 0, 0, 147, 48, 141, 156, 149, 141, 148, 141, 141, 0, 156, + 149, 149, 0, 149, 149, 135, 144, 0, 0, 0, 0, 0, 0, 0, 148, 148, 0, 0, 0, + 0, 0, 48, 48, 48, 0, 48, 48, 135, 135, 0, 0, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 0, 48, 48, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 135, 135, 141, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, + 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 144, 144, 48, 148, 141, 141, 135, 135, 135, 135, + 0, 141, 141, 141, 0, 149, 149, 149, 144, 48, 80, 0, 0, 0, 0, 48, 48, 48, + 148, 150, 150, 150, 150, 150, 150, 150, 48, 48, 48, 135, 135, 0, 0, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 80, 48, 48, 48, 48, 48, 48, 0, 135, 141, 141, 0, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, + 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, + 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 157, 0, 0, 0, 0, 148, 141, + 141, 135, 135, 135, 0, 135, 0, 141, 141, 149, 141, 149, 149, 149, 148, 0, + 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, + 141, 141, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 144, 144, 48, 148, 141, 141, 135, 135, 135, 135, 0, 141, - 141, 141, 0, 149, 149, 149, 144, 48, 80, 0, 0, 0, 0, 48, 48, 48, 148, - 150, 150, 150, 150, 150, 150, 150, 48, 48, 48, 135, 135, 0, 0, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 80, 48, 48, 48, 48, 48, 48, 0, 135, 141, 141, 0, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 0, - 0, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 157, 0, 0, 0, 0, 148, 141, 141, - 135, 135, 135, 0, 135, 0, 141, 141, 149, 141, 149, 149, 149, 148, 0, 0, - 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 141, - 141, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 135, 48, 158, 135, 135, 135, 135, 159, 159, 144, 0, - 0, 0, 0, 85, 48, 48, 48, 48, 48, 48, 53, 135, 160, 160, 160, 160, 135, + 48, 48, 48, 48, 48, 48, 135, 48, 158, 135, 135, 135, 135, 159, 159, 144, + 0, 0, 0, 0, 85, 48, 48, 48, 48, 48, 48, 53, 135, 160, 160, 160, 160, 135, 135, 135, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 48, 0, 48, 48, 48, 48, @@ -1729,511 +1729,511 @@ static const unsigned short index2[] = { 146, 146, 146, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 83, 83, 83, 83, 83, 83, 83, 53, 83, 83, 83, 83, 83, 83, 0, 0, 81, 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 81, 81, 86, - 82, 86, 86, 81, 81, 86, 86, 81, 81, 81, 81, 81, 86, 81, 81, 81, 81, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, - 135, 135, 135, 141, 48, 142, 48, 142, 48, 142, 48, 142, 48, 142, 48, 48, - 48, 142, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 147, - 148, 135, 135, 135, 135, 135, 149, 135, 149, 141, 141, 149, 149, 135, - 149, 176, 48, 48, 48, 48, 48, 48, 48, 48, 0, 83, 83, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 83, 83, 83, 83, 83, 83, 83, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 81, 86, 81, 81, 81, 81, 81, 81, 81, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 83, 83, 83, 135, 135, 141, 48, 48, 48, 48, 48, + 82, 86, 86, 81, 81, 86, 86, 81, 81, 81, 81, 81, 86, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 86, 0, 0, 81, 81, 81, + 81, 81, 81, 86, 81, 81, 81, 81, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 135, 135, 141, 48, 142, 48, 142, 48, + 142, 48, 142, 48, 142, 48, 48, 48, 142, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 141, 135, 135, 135, 135, 141, 141, 135, 135, - 176, 144, 135, 135, 48, 48, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 147, 141, 135, 135, 141, 141, 141, - 135, 141, 135, 135, 135, 176, 176, 0, 0, 0, 0, 0, 0, 0, 0, 83, 83, 83, - 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 141, 141, 141, 141, 141, 141, 141, 141, 135, 135, 135, 135, 135, 135, - 135, 135, 141, 141, 135, 147, 0, 0, 0, 83, 83, 83, 83, 83, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 48, 48, 48, 146, 146, 146, + 48, 48, 48, 48, 48, 48, 48, 147, 148, 135, 135, 135, 135, 135, 149, 135, + 149, 141, 141, 149, 149, 135, 149, 176, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 83, 83, + 83, 83, 83, 83, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 86, 81, 81, + 81, 81, 81, 81, 81, 80, 80, 80, 80, 80, 80, 80, 80, 80, 83, 83, 83, 135, + 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 135, 135, + 135, 135, 141, 141, 135, 135, 176, 144, 135, 135, 48, 48, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 53, 53, 53, 53, 53, 53, 83, 83, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 44, 47, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 44, 44, - 44, 83, 83, 83, 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 81, - 83, 178, 86, 86, 86, 86, 86, 81, 81, 86, 86, 86, 86, 81, 141, 178, 178, - 178, 178, 178, 178, 178, 48, 48, 48, 48, 86, 48, 48, 48, 48, 48, 48, 81, - 48, 48, 141, 81, 81, 48, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 51, 51, 51, 53, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 53, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 53, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 51, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 81, 81, 86, 81, 81, 81, 81, 81, 81, 81, 86, 81, 81, 179, - 180, 86, 181, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 182, 88, 88, 86, 183, 81, 184, 86, 81, 86, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 43, 43, 43, 43, 35, 185, 47, 47, 44, 47, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, - 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 44, 47, 44, 47, 44, - 47, 43, 43, 43, 43, 43, 43, 43, 43, 38, 38, 38, 38, 38, 38, 38, 38, 43, - 43, 43, 43, 43, 43, 0, 0, 38, 38, 38, 38, 38, 38, 0, 0, 43, 43, 43, 43, - 43, 43, 43, 43, 38, 38, 38, 38, 38, 38, 38, 38, 43, 43, 43, 43, 43, 43, - 43, 43, 38, 38, 38, 38, 38, 38, 38, 38, 43, 43, 43, 43, 43, 43, 0, 0, 38, - 38, 38, 38, 38, 38, 0, 0, 43, 43, 43, 43, 43, 43, 43, 43, 0, 38, 0, 38, - 0, 38, 0, 38, 43, 43, 43, 43, 43, 43, 43, 43, 38, 38, 38, 38, 38, 38, 38, - 38, 43, 186, 43, 186, 43, 186, 43, 186, 43, 186, 43, 186, 43, 186, 0, 0, - 43, 43, 43, 43, 43, 43, 43, 43, 187, 187, 187, 187, 187, 187, 187, 187, - 43, 43, 43, 43, 43, 43, 43, 43, 187, 187, 187, 187, 187, 187, 187, 187, - 43, 43, 43, 43, 43, 43, 43, 43, 187, 187, 187, 187, 187, 187, 187, 187, - 43, 43, 43, 43, 43, 0, 43, 43, 38, 38, 38, 188, 187, 58, 186, 58, 58, 76, - 43, 43, 43, 0, 43, 43, 38, 188, 38, 188, 187, 76, 76, 76, 43, 43, 43, - 186, 0, 0, 43, 43, 38, 38, 38, 188, 0, 76, 76, 76, 43, 43, 43, 186, 43, - 43, 43, 43, 38, 38, 38, 188, 38, 76, 189, 189, 0, 0, 43, 43, 43, 0, 43, - 43, 38, 188, 38, 188, 187, 189, 58, 0, 190, 190, 191, 191, 191, 191, 191, - 191, 191, 191, 191, 177, 177, 177, 192, 193, 194, 195, 84, 194, 194, 194, - 22, 196, 197, 198, 199, 200, 197, 198, 199, 200, 22, 22, 22, 138, 201, - 201, 201, 22, 202, 203, 204, 205, 206, 207, 208, 21, 209, 110, 209, 210, - 211, 22, 196, 196, 138, 28, 36, 22, 196, 138, 201, 212, 212, 138, 138, - 138, 213, 165, 166, 196, 196, 196, 138, 138, 138, 138, 138, 138, 138, - 138, 78, 138, 212, 138, 138, 196, 138, 138, 138, 138, 138, 138, 138, 191, - 177, 177, 177, 177, 177, 0, 214, 215, 216, 217, 177, 177, 177, 177, 177, - 177, 218, 51, 0, 0, 34, 218, 218, 218, 218, 218, 219, 219, 220, 221, 222, - 223, 218, 34, 34, 34, 34, 218, 218, 218, 218, 218, 219, 219, 220, 221, - 222, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 0, 0, 0, 85, - 85, 85, 85, 85, 85, 85, 85, 224, 225, 85, 85, 23, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 178, 178, 81, 81, 81, 81, 178, 178, - 178, 81, 81, 82, 82, 82, 82, 81, 82, 82, 82, 178, 178, 81, 86, 81, 178, - 178, 86, 86, 86, 86, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 226, 226, 49, 227, 26, 227, 226, 49, 26, 227, 35, 49, 49, 49, 35, 35, 49, - 49, 49, 46, 26, 49, 227, 26, 78, 49, 49, 49, 49, 49, 26, 26, 226, 227, - 227, 26, 49, 26, 228, 26, 49, 26, 188, 228, 49, 49, 229, 35, 49, 49, 44, - 49, 35, 158, 158, 158, 158, 35, 26, 226, 35, 35, 49, 49, 230, 78, 78, 78, - 78, 49, 35, 35, 35, 35, 26, 78, 26, 26, 47, 80, 231, 231, 231, 37, 37, - 231, 231, 231, 231, 231, 231, 37, 37, 37, 37, 231, 232, 232, 232, 232, - 232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 232, 232, - 232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, - 175, 175, 175, 44, 47, 175, 175, 175, 175, 37, 26, 26, 0, 0, 0, 0, 40, - 40, 40, 40, 40, 30, 30, 30, 30, 30, 234, 234, 26, 26, 26, 26, 78, 26, 26, - 78, 26, 26, 78, 26, 26, 26, 26, 26, 26, 26, 234, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 235, 234, 234, 26, 26, 40, 26, 40, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 40, 236, 237, 237, 238, 78, 78, 40, 237, 238, 236, 237, - 238, 236, 78, 40, 78, 237, 239, 240, 78, 237, 236, 78, 78, 78, 237, 236, - 236, 237, 40, 237, 237, 236, 236, 40, 238, 40, 238, 40, 40, 40, 40, 237, - 241, 230, 237, 230, 230, 236, 236, 236, 40, 40, 40, 40, 78, 236, 78, 236, - 237, 237, 236, 236, 236, 238, 236, 236, 238, 236, 236, 238, 237, 238, - 236, 236, 237, 78, 78, 78, 78, 78, 237, 236, 236, 236, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 236, 242, 40, 238, 78, 237, 237, 237, 237, 236, 236, - 237, 237, 78, 238, 242, 242, 238, 238, 236, 236, 238, 238, 236, 236, 238, - 238, 236, 236, 236, 236, 236, 236, 238, 238, 237, 237, 238, 238, 237, - 237, 238, 238, 236, 236, 236, 78, 78, 236, 236, 236, 236, 78, 78, 40, 78, - 78, 236, 40, 78, 78, 78, 78, 78, 78, 78, 78, 236, 236, 78, 40, 236, 236, - 236, 236, 236, 236, 238, 238, 238, 238, 236, 236, 236, 236, 236, 236, - 236, 236, 236, 78, 78, 78, 78, 78, 236, 237, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 236, 236, 236, 236, 236, 78, 78, 236, 236, 78, 78, 78, 78, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 238, 238, 238, 238, 236, - 236, 236, 236, 236, 236, 238, 238, 238, 238, 78, 78, 236, 236, 236, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 26, 26, 26, - 26, 26, 26, 26, 26, 165, 166, 165, 166, 26, 26, 26, 26, 26, 26, 30, 26, - 26, 26, 26, 26, 26, 26, 243, 243, 26, 26, 26, 26, 236, 236, 26, 26, 26, - 26, 26, 26, 26, 244, 245, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 26, 78, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 80, 26, 26, 26, 26, 26, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 78, 78, 78, 78, 78, 78, 26, 26, 26, 26, 26, 26, 26, 243, 243, - 243, 243, 26, 26, 26, 243, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 231, 247, - 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, - 247, 247, 247, 247, 247, 247, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, 26, 26, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 26, 26, 30, 30, 30, 30, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 30, 30, 30, 30, 26, 26, 26, - 26, 26, 26, 26, 26, 30, 30, 26, 26, 30, 40, 26, 26, 26, 26, 30, 30, 26, - 26, 30, 40, 26, 26, 26, 26, 30, 30, 30, 26, 26, 30, 26, 26, 30, 30, 30, - 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, - 30, 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, 26, - 26, 26, 26, 78, 78, 78, 78, 78, 248, 248, 78, 26, 26, 26, 26, 26, 30, 30, - 26, 26, 30, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 243, 243, 26, 26, 26, - 26, 26, 26, 30, 26, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, - 26, 26, 26, 26, 26, 30, 26, 30, 26, 26, 26, 26, 26, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 26, 30, 30, 30, 30, 26, 30, 30, - 26, 40, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, 26, - 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 243, 26, - 26, 26, 26, 26, 26, 26, 26, 243, 243, 80, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 30, 26, 26, 26, 26, 243, 243, - 30, 30, 30, 30, 30, 30, 30, 30, 243, 30, 30, 30, 30, 30, 243, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 30, 26, 26, 26, 26, 30, 30, - 243, 30, 30, 30, 30, 30, 30, 30, 243, 243, 30, 243, 30, 30, 30, 30, 243, - 30, 30, 243, 30, 30, 26, 26, 26, 26, 26, 243, 26, 26, 26, 26, 243, 243, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 26, 243, 26, 26, 26, 26, - 243, 243, 243, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 165, 166, 165, 166, 165, 166, 165, 166, 165, 166, 165, - 166, 165, 166, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 155, - 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, - 155, 155, 155, 155, 155, 26, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 236, 78, 78, - 236, 236, 165, 166, 78, 236, 236, 78, 236, 236, 236, 78, 78, 78, 78, 78, - 236, 236, 236, 236, 78, 78, 78, 78, 78, 236, 236, 236, 78, 78, 78, 236, - 236, 236, 236, 9, 10, 9, 10, 9, 10, 9, 10, 165, 166, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 165, 166, 9, 10, 165, 166, 165, 166, 165, 166, 165, 166, 165, 166, 165, - 166, 165, 166, 165, 166, 165, 166, 78, 78, 236, 236, 236, 236, 236, 236, - 78, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 78, 78, 78, 78, 78, 78, 78, 78, 236, 78, 78, 78, 78, 78, 78, 78, 236, - 236, 236, 236, 236, 236, 78, 78, 78, 236, 78, 78, 78, 78, 236, 236, 236, - 236, 236, 78, 236, 236, 78, 78, 165, 166, 165, 166, 236, 78, 78, 78, 78, - 236, 78, 236, 236, 236, 78, 78, 236, 236, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 236, 236, 236, 236, 236, 236, 78, 78, 165, 166, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 236, 236, 230, 236, 236, 236, 236, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 78, 236, 236, 236, - 236, 78, 78, 236, 78, 236, 78, 78, 236, 78, 236, 236, 236, 236, 78, 78, - 78, 78, 78, 236, 236, 78, 78, 78, 78, 78, 78, 236, 236, 236, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 236, 236, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 236, - 236, 78, 78, 78, 78, 236, 236, 236, 236, 78, 236, 236, 78, 78, 236, 230, - 220, 220, 78, 78, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 236, 236, 236, 236, 78, 78, 236, 236, 236, 236, 236, 236, 236, 236, 78, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 78, 78, 78, - 78, 78, 249, 78, 236, 78, 78, 78, 236, 236, 236, 236, 236, 78, 78, 78, - 78, 78, 236, 236, 236, 78, 78, 78, 78, 236, 78, 78, 78, 236, 236, 236, - 236, 236, 78, 236, 78, 78, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 26, 26, 78, 78, 78, 78, 78, 78, 26, 26, 26, 243, 26, 26, - 26, 26, 243, 30, 30, 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 250, 26, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 44, 47, - 44, 44, 44, 47, 47, 44, 47, 44, 47, 44, 47, 44, 44, 44, 44, 47, 44, 47, - 47, 44, 47, 47, 47, 47, 47, 47, 51, 51, 44, 44, 44, 47, 44, 47, 44, 47, - 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, - 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, - 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, - 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, - 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, - 44, 47, 44, 47, 47, 26, 26, 26, 26, 26, 26, 44, 47, 44, 47, 81, 81, 81, - 44, 47, 0, 0, 0, 0, 0, 138, 138, 138, 138, 155, 138, 138, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 0, 47, 0, - 0, 0, 0, 0, 47, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 51, 83, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, - 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, - 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, - 0, 48, 48, 48, 48, 48, 48, 48, 0, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 138, 138, 28, 36, 28, 36, 138, 138, 138, 28, 36, 138, 28, - 36, 138, 138, 138, 138, 138, 138, 138, 138, 138, 84, 138, 138, 84, 138, - 28, 36, 138, 138, 28, 36, 165, 166, 165, 166, 165, 166, 165, 166, 138, - 138, 138, 138, 138, 52, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, - 84, 84, 138, 138, 138, 138, 84, 138, 199, 138, 138, 138, 138, 138, 138, - 138, 138, 138, 138, 138, 138, 138, 26, 26, 138, 138, 138, 165, 166, 165, - 166, 165, 166, 165, 166, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 243, 243, 243, 243, 251, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 251, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, - 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 252, 253, - 253, 253, 243, 254, 172, 255, 256, 257, 256, 257, 256, 257, 256, 257, - 256, 257, 243, 243, 256, 257, 256, 257, 256, 257, 256, 257, 258, 259, - 260, 260, 243, 255, 255, 255, 255, 255, 255, 255, 255, 255, 261, 262, - 263, 264, 265, 265, 258, 254, 254, 254, 254, 254, 251, 243, 266, 266, - 266, 254, 172, 253, 243, 26, 0, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, - 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 172, - 267, 172, 267, 172, 267, 172, 172, 172, 172, 172, 172, 267, 267, 172, - 267, 267, 172, 267, 267, 172, 267, 267, 172, 267, 267, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 267, 172, 172, 0, 0, 268, 268, 269, 269, 254, - 270, 271, 258, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, - 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 172, 267, 172, 267, - 172, 267, 172, 172, 172, 172, 172, 172, 267, 267, 172, 267, 267, 172, - 267, 267, 172, 267, 267, 172, 267, 267, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 267, 172, 172, 267, 267, 267, 267, 253, 254, 254, 270, 271, 0, - 0, 0, 0, 0, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 0, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 0, 272, - 272, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 251, 251, 0, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, - 275, 275, 275, 275, 251, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 251, 251, 251, 272, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 251, 251, 251, 251, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 251, 251, 251, 251, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 251, 251, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 251, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 254, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 0, 0, 0, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 53, 53, 53, 53, 53, 53, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 53, 138, 138, 138, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 48, 81, 82, 82, 82, 138, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 138, 52, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 51, 51, 81, 81, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 81, 81, 83, - 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 54, 54, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 47, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 51, 47, 47, - 47, 47, 47, 47, 47, 47, 44, 47, 44, 47, 44, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 52, 277, 277, 44, 47, 44, 47, 48, 44, 47, 44, 47, 47, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 44, 44, 44, 44, 47, 44, 44, 44, 44, 44, 47, 44, 47, 44, 47, 44, - 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 44, 44, 44, 47, 44, 47, 44, 44, - 47, 0, 0, 44, 47, 0, 47, 0, 47, 44, 47, 44, 47, 44, 47, 44, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 51, 51, 44, 47, - 48, 51, 51, 47, 48, 48, 48, 48, 48, 48, 48, 135, 48, 48, 48, 144, 48, 48, - 48, 48, 135, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 141, 141, 135, 135, 141, 26, 26, 26, 26, - 144, 0, 0, 0, 150, 150, 150, 150, 150, 150, 80, 80, 85, 229, 0, 0, 0, 0, - 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 138, - 138, 138, 138, 0, 0, 0, 0, 0, 0, 0, 0, 141, 141, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 147, + 141, 135, 135, 141, 141, 141, 135, 141, 135, 135, 135, 176, 176, 0, 0, 0, + 0, 0, 0, 0, 0, 83, 83, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 141, 141, 141, 141, 141, 141, 141, - 141, 141, 141, 141, 141, 141, 141, 141, 144, 135, 0, 0, 0, 0, 0, 0, 0, 0, - 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, - 0, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 48, 48, 48, 48, 48, 48, 83, 83, 83, 48, 83, 48, 48, 135, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, 48, 48, 48, 48, 48, 48, + 135, 135, 135, 135, 135, 135, 135, 135, 141, 141, 135, 147, 0, 0, 0, 83, + 83, 83, 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, + 0, 48, 48, 48, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 135, 135, 135, 135, 135, 86, 86, 86, 83, 83, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 53, 53, 53, 53, 53, 83, 83, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 44, 47, 0, 0, 0, 0, 0, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 0, 0, 44, 44, 44, 83, 83, 83, 83, 83, 83, 83, 83, 0, 0, + 0, 0, 0, 0, 0, 0, 81, 81, 81, 83, 179, 86, 86, 86, 86, 86, 81, 81, 86, + 86, 86, 86, 81, 141, 179, 179, 179, 179, 179, 179, 179, 48, 48, 48, 48, + 86, 48, 48, 48, 48, 48, 48, 81, 48, 48, 141, 81, 81, 48, 0, 0, 0, 0, 0, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 53, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 53, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 53, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 81, 81, 86, 81, 81, 81, + 81, 81, 81, 81, 86, 81, 81, 178, 180, 86, 181, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 182, 88, 88, 86, 183, + 81, 184, 86, 81, 86, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 43, 43, 43, 43, 35, 185, 47, + 47, 44, 47, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, 43, 38, + 43, 38, 43, 44, 47, 44, 47, 44, 47, 43, 43, 43, 43, 43, 43, 43, 43, 38, + 38, 38, 38, 38, 38, 38, 38, 43, 43, 43, 43, 43, 43, 0, 0, 38, 38, 38, 38, + 38, 38, 0, 0, 43, 43, 43, 43, 43, 43, 43, 43, 38, 38, 38, 38, 38, 38, 38, + 38, 43, 43, 43, 43, 43, 43, 43, 43, 38, 38, 38, 38, 38, 38, 38, 38, 43, + 43, 43, 43, 43, 43, 0, 0, 38, 38, 38, 38, 38, 38, 0, 0, 43, 43, 43, 43, + 43, 43, 43, 43, 0, 38, 0, 38, 0, 38, 0, 38, 43, 43, 43, 43, 43, 43, 43, + 43, 38, 38, 38, 38, 38, 38, 38, 38, 43, 186, 43, 186, 43, 186, 43, 186, + 43, 186, 43, 186, 43, 186, 0, 0, 43, 43, 43, 43, 43, 43, 43, 43, 187, + 187, 187, 187, 187, 187, 187, 187, 43, 43, 43, 43, 43, 43, 43, 43, 187, + 187, 187, 187, 187, 187, 187, 187, 43, 43, 43, 43, 43, 43, 43, 43, 187, + 187, 187, 187, 187, 187, 187, 187, 43, 43, 43, 43, 43, 0, 43, 43, 38, 38, + 38, 188, 187, 58, 186, 58, 58, 76, 43, 43, 43, 0, 43, 43, 38, 188, 38, + 188, 187, 76, 76, 76, 43, 43, 43, 186, 0, 0, 43, 43, 38, 38, 38, 188, 0, + 76, 76, 76, 43, 43, 43, 186, 43, 43, 43, 43, 38, 38, 38, 188, 38, 76, + 189, 189, 0, 0, 43, 43, 43, 0, 43, 43, 38, 188, 38, 188, 187, 189, 58, 0, + 190, 190, 191, 191, 191, 191, 191, 191, 191, 191, 191, 177, 177, 177, + 192, 193, 194, 195, 84, 194, 194, 194, 22, 196, 197, 198, 199, 200, 197, + 198, 199, 200, 22, 22, 22, 138, 201, 201, 201, 22, 202, 203, 204, 205, + 206, 207, 208, 21, 209, 110, 209, 210, 211, 22, 196, 196, 138, 28, 36, + 22, 196, 138, 201, 212, 212, 138, 138, 138, 213, 165, 166, 196, 196, 196, + 138, 138, 138, 138, 138, 138, 138, 138, 78, 138, 212, 138, 138, 196, 138, + 138, 138, 138, 138, 138, 138, 191, 177, 177, 177, 177, 177, 0, 214, 215, + 216, 217, 177, 177, 177, 177, 177, 177, 218, 51, 0, 0, 34, 218, 218, 218, + 218, 218, 219, 219, 220, 221, 222, 223, 218, 34, 34, 34, 34, 218, 218, + 218, 218, 218, 219, 219, 220, 221, 222, 0, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 0, 0, 0, 85, 85, 85, 85, 85, 85, 85, 85, 224, + 225, 85, 85, 23, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, + 81, 179, 179, 81, 81, 81, 81, 179, 179, 179, 81, 81, 82, 82, 82, 82, 81, + 82, 82, 82, 179, 179, 81, 86, 81, 179, 179, 86, 86, 86, 86, 81, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 49, 227, 26, 227, 226, 49, + 26, 227, 35, 49, 49, 49, 35, 35, 49, 49, 49, 46, 26, 49, 227, 26, 78, 49, + 49, 49, 49, 49, 26, 26, 226, 227, 227, 26, 49, 26, 228, 26, 49, 26, 188, + 228, 49, 49, 229, 35, 49, 49, 44, 49, 35, 158, 158, 158, 158, 35, 26, + 226, 35, 35, 49, 49, 230, 78, 78, 78, 78, 49, 35, 35, 35, 35, 26, 78, 26, + 26, 47, 80, 231, 231, 231, 37, 37, 231, 231, 231, 231, 231, 231, 37, 37, + 37, 37, 231, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 233, 233, 233, 233, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 233, 233, 233, 233, 233, 233, 175, 175, 175, 44, 47, 175, 175, 175, 175, + 37, 26, 26, 0, 0, 0, 0, 40, 40, 40, 40, 40, 30, 30, 30, 30, 30, 234, 234, + 26, 26, 26, 26, 78, 26, 26, 78, 26, 26, 78, 26, 26, 26, 26, 26, 26, 26, + 234, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 235, 234, 234, 26, + 26, 40, 26, 40, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 40, 236, 237, 237, 238, 78, + 78, 40, 237, 238, 236, 237, 238, 236, 78, 40, 78, 237, 239, 240, 78, 237, + 236, 78, 78, 78, 237, 236, 236, 237, 40, 237, 237, 236, 236, 40, 238, 40, + 238, 40, 40, 40, 40, 237, 241, 230, 237, 230, 230, 236, 236, 236, 40, 40, + 40, 40, 78, 236, 78, 236, 237, 237, 236, 236, 236, 238, 236, 236, 238, + 236, 236, 238, 237, 238, 236, 236, 237, 78, 78, 78, 78, 78, 237, 236, + 236, 236, 78, 78, 78, 78, 78, 78, 78, 78, 78, 236, 242, 40, 238, 78, 237, + 237, 237, 237, 236, 236, 237, 237, 78, 238, 242, 242, 238, 238, 236, 236, + 238, 238, 236, 236, 238, 238, 236, 236, 236, 236, 236, 236, 238, 238, + 237, 237, 238, 238, 237, 237, 238, 238, 236, 236, 236, 78, 78, 236, 236, + 236, 236, 78, 78, 40, 78, 78, 236, 40, 78, 78, 78, 78, 78, 78, 78, 78, + 236, 236, 78, 40, 236, 236, 236, 236, 236, 236, 238, 238, 238, 238, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 78, 78, 78, 78, 78, 236, 237, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 236, 236, 236, 236, 236, 78, 78, 236, + 236, 78, 78, 78, 78, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 238, 238, 238, 238, 236, 236, 236, 236, 236, 236, 238, 238, 238, 238, 78, + 78, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 26, 26, 26, 26, 26, 26, 26, 26, 165, 166, 165, 166, 26, 26, 26, + 26, 26, 26, 30, 26, 26, 26, 26, 26, 26, 26, 243, 243, 26, 26, 26, 26, + 236, 236, 26, 26, 26, 26, 26, 26, 26, 244, 245, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 26, 78, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 80, 26, 26, 26, 26, 26, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 78, 78, 78, 78, 78, 78, 26, 26, 26, + 26, 26, 26, 26, 243, 243, 243, 243, 26, 26, 26, 243, 26, 26, 243, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 231, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, + 26, 26, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, 30, 30, 30, 30, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 30, 30, + 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 30, 40, 26, 26, + 26, 26, 30, 30, 26, 26, 30, 40, 26, 26, 26, 26, 30, 30, 30, 26, 26, 30, + 26, 26, 30, 30, 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 30, 30, 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, + 26, 26, 26, 26, 26, 26, 26, 26, 78, 78, 78, 78, 78, 248, 248, 78, 26, 26, + 26, 26, 26, 30, 30, 26, 26, 30, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, + 243, 243, 26, 26, 26, 26, 26, 26, 30, 26, 30, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, + 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 30, 26, 26, 26, 26, 26, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 26, 30, 30, + 30, 30, 26, 30, 30, 26, 40, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, + 243, 243, 243, 243, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 30, 30, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 80, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 30, + 26, 26, 26, 26, 243, 243, 30, 30, 30, 30, 30, 30, 30, 30, 243, 30, 30, + 30, 30, 30, 243, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, + 30, 26, 26, 26, 26, 30, 30, 243, 30, 30, 30, 30, 30, 30, 30, 243, 243, + 30, 243, 30, 30, 30, 30, 243, 30, 30, 243, 30, 30, 26, 26, 26, 26, 26, + 243, 26, 26, 26, 26, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 243, 26, 243, 26, 26, 26, 26, 243, 243, 243, 26, 243, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 165, 166, 165, 166, 165, 166, + 165, 166, 165, 166, 165, 166, 165, 166, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 26, 243, 243, 243, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 243, 236, 78, 78, 236, 236, 165, 166, 78, 236, 236, 78, 236, 236, + 236, 78, 78, 78, 78, 78, 236, 236, 236, 236, 78, 78, 78, 78, 78, 236, + 236, 236, 78, 78, 78, 236, 236, 236, 236, 9, 10, 9, 10, 9, 10, 9, 10, + 165, 166, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 165, 166, 9, 10, 165, 166, 165, 166, 165, + 166, 165, 166, 165, 166, 165, 166, 165, 166, 165, 166, 165, 166, 78, 78, + 236, 236, 236, 236, 236, 236, 78, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 78, 78, 78, 78, 78, 78, 78, 78, 236, 78, + 78, 78, 78, 78, 78, 78, 236, 236, 236, 236, 236, 236, 78, 78, 78, 236, + 78, 78, 78, 78, 236, 236, 236, 236, 236, 78, 236, 236, 78, 78, 165, 166, + 165, 166, 236, 78, 78, 78, 78, 236, 78, 236, 236, 236, 78, 78, 236, 236, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 236, 236, 236, 236, 236, 236, 78, + 78, 165, 166, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 236, 236, + 230, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 78, 236, 236, 236, 236, 78, 78, 236, 78, 236, 78, 78, 236, + 78, 236, 236, 236, 236, 78, 78, 78, 78, 78, 236, 236, 78, 78, 78, 78, 78, + 78, 236, 236, 236, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 236, 236, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 236, 236, 78, 78, 78, 78, 236, 236, 236, 236, 78, + 236, 236, 78, 78, 236, 230, 220, 220, 78, 78, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 78, 78, 236, 236, 236, + 236, 236, 236, 236, 236, 78, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 78, 78, 78, 78, 78, 249, 78, 236, 78, 78, 78, 236, 236, + 236, 236, 236, 78, 78, 78, 78, 78, 236, 236, 236, 78, 78, 78, 78, 236, + 78, 78, 78, 236, 236, 236, 236, 236, 78, 236, 78, 78, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 26, 26, 78, 78, 78, 78, 78, 78, + 26, 26, 26, 243, 26, 26, 26, 26, 243, 30, 30, 30, 30, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 250, 26, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 44, 47, 44, 44, 44, 47, 47, 44, 47, 44, 47, 44, 47, 44, + 44, 44, 44, 47, 44, 47, 47, 44, 47, 47, 47, 47, 47, 47, 51, 51, 44, 44, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 47, 26, 26, 26, 26, 26, 26, 44, + 47, 44, 47, 81, 81, 81, 44, 47, 0, 0, 0, 0, 0, 138, 138, 138, 138, 155, + 138, 138, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 0, 47, 0, 0, 0, 0, 0, 47, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 141, 176, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 83, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, + 0, 51, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, + 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, + 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, + 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 138, 138, 28, 36, 28, 36, 138, + 138, 138, 28, 36, 138, 28, 36, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 84, 138, 138, 84, 138, 28, 36, 138, 138, 28, 36, 165, 166, 165, 166, + 165, 166, 165, 166, 138, 138, 138, 138, 138, 52, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 84, 84, 138, 138, 138, 138, 84, 138, 199, 138, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 26, 26, 138, + 138, 138, 165, 166, 165, 166, 165, 166, 165, 166, 84, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, + 243, 243, 243, 243, 251, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, + 251, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 252, 253, 253, 253, 243, 254, 172, 255, 256, + 257, 256, 257, 256, 257, 256, 257, 256, 257, 243, 243, 256, 257, 256, + 257, 256, 257, 256, 257, 258, 259, 260, 260, 243, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 261, 262, 263, 264, 265, 265, 258, 254, 254, + 254, 254, 254, 251, 243, 266, 266, 266, 254, 172, 253, 243, 26, 0, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 267, 172, 267, 172, + 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, + 267, 172, 267, 172, 267, 172, 172, 267, 172, 267, 172, 267, 172, 172, + 172, 172, 172, 172, 267, 267, 172, 267, 267, 172, 267, 267, 172, 267, + 267, 172, 267, 267, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 267, 172, + 172, 0, 0, 268, 268, 269, 269, 254, 270, 271, 258, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 267, 172, 267, 172, 267, 172, 267, + 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, 172, 267, + 172, 267, 172, 172, 267, 172, 267, 172, 267, 172, 172, 172, 172, 172, + 172, 267, 267, 172, 267, 267, 172, 267, 267, 172, 267, 267, 172, 267, + 267, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 267, 172, 172, 267, 267, + 267, 267, 253, 254, 254, 270, 271, 0, 0, 0, 0, 0, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 0, 0, 0, 135, 135, 135, 141, 48, 48, 48, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 0, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 0, 272, 272, 273, 273, 273, 273, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 243, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 251, 251, 0, 273, 273, 273, 273, 273, 273, 273, 273, + 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 251, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 251, 251, 251, 272, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 251, 251, 251, 251, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 251, + 251, 251, 251, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 251, 251, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 251, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 254, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 53, 53, 53, 53, 53, + 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 138, 138, + 138, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 48, 81, 82, 82, 82, 138, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 138, 52, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 51, 51, 81, 81, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 147, 141, 141, 135, 135, 135, 135, 141, - 141, 135, 135, 141, 141, 176, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 0, 53, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, - 0, 83, 83, 48, 48, 48, 48, 48, 135, 53, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, 48, 48, 48, - 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 135, 135, 135, 135, 135, 135, 141, 141, 135, 135, - 141, 141, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 135, 48, 48, - 48, 48, 48, 48, 48, 48, 135, 141, 0, 0, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 0, 0, 83, 83, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 53, 48, 48, 48, 48, 48, 48, 80, 80, 80, - 48, 141, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 81, 81, 83, 83, 83, 83, 83, 83, 0, 0, + 0, 0, 0, 0, 0, 0, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 54, 54, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 47, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 51, 47, 47, 47, 47, 47, 47, 47, 47, 44, + 47, 44, 47, 44, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 52, 277, 277, 44, + 47, 44, 47, 48, 44, 47, 44, 47, 47, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 44, 44, 44, 44, 47, + 44, 44, 44, 44, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 44, 44, 44, 47, 44, 47, 44, 44, 47, 44, 47, 44, 47, 44, 47, + 44, 47, 44, 47, 44, 47, 44, 47, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 51, 51, 51, 51, 44, 47, 48, 51, 51, 47, 48, 48, + 48, 48, 48, 48, 48, 135, 48, 48, 48, 144, 48, 48, 48, 48, 135, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 141, 141, 135, 135, 141, 26, 26, 26, 26, 144, 0, 0, 0, 150, + 150, 150, 150, 150, 150, 80, 80, 85, 229, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 81, 48, 81, 81, 86, 48, 48, 81, 81, 48, 48, 48, 48, 48, 81, 81, 48, - 81, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 48, 48, 53, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 141, 135, 135, 141, 141, 83, 83, 48, 53, 53, 141, 144, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 48, 48, 48, 48, 0, 0, - 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, - 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 47, 47, 47, 47, 47, 47, 47, 47, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 138, 138, 138, 138, + 0, 0, 0, 0, 0, 0, 0, 0, 141, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 144, 135, 0, 0, 0, 0, 0, 0, 0, 0, 83, 83, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 48, 48, + 48, 48, 48, 48, 83, 83, 83, 48, 83, 48, 48, 135, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 135, + 135, 135, 135, 86, 86, 86, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 141, 176, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 83, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 0, 0, 0, 135, 135, 135, 141, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 147, 141, 141, 135, 135, 135, 135, 141, 141, 135, 135, + 141, 141, 176, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 0, 53, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 83, 83, 48, + 48, 48, 48, 48, 135, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 48, 48, 48, 48, 48, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 135, 135, 135, 135, 135, 135, 141, 141, 135, 135, 141, 141, + 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 135, 48, 48, 48, 48, 48, + 48, 48, 48, 135, 141, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 0, 0, 83, 83, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 53, 48, 48, 48, 48, 48, 48, 80, 80, 80, 48, 141, 135, + 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 81, 48, 81, + 81, 86, 48, 48, 81, 81, 48, 48, 48, 48, 48, 81, 81, 48, 81, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, + 53, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 135, 135, + 141, 141, 83, 83, 48, 53, 53, 141, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, + 48, 48, 48, 48, 48, 0, 0, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 48, 48, + 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, + 48, 48, 48, 48, 48, 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 277, - 51, 51, 51, 51, 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 54, 54, 0, 0, 0, - 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 277, 51, 51, 51, 51, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 54, 54, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 141, 141, 135, 141, 141, 135, 141, 141, - 83, 141, 144, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, - 0, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, + 48, 48, 48, 48, 141, 141, 135, 141, 141, 135, 141, 141, 83, 141, 144, 0, + 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, @@ -2244,12 +2244,13 @@ static const unsigned short index2[] = { 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, - 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 48, 48, 48, + 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 278, 278, 278, 278, + 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, @@ -2258,8 +2259,7 @@ static const unsigned short index2[] = { 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, @@ -2268,6 +2268,7 @@ static const unsigned short index2[] = { 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, @@ -2277,39 +2278,39 @@ static const unsigned short index2[] = { 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 172, 172, 280, 172, 280, 172, 172, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 280, 172, 280, 172, 280, 172, 172, 280, 280, 172, - 172, 172, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 172, + 172, 280, 172, 280, 172, 172, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 172, 280, 172, 280, 172, 172, 280, 280, 172, 172, 172, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 281, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 35, 35, 35, 35, 35, 0, 0, 0, 0, 0, 282, 283, 282, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 219, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 0, 282, 282, 282, 282, 282, - 0, 282, 0, 282, 282, 0, 282, 282, 0, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 284, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 281, 281, 281, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 35, 35, 35, 35, 35, 0, 0, 0, 0, 0, 282, 283, 282, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 219, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 0, 282, 282, 282, 282, 282, 0, 282, 0, 282, + 282, 0, 282, 282, 0, 282, 282, 282, 282, 282, 282, 282, 282, 282, 284, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 131, 131, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, @@ -2331,21 +2332,21 @@ static const unsigned short index2[] = { 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 131, 131, 131, 131, 131, 0, 0, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 26, 26, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 131, 131, 131, 131, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 131, 131, 131, 131, 131, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 286, 26, 26, - 26, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 287, - 287, 287, 287, 287, 287, 287, 288, 289, 287, 0, 0, 0, 0, 0, 0, 81, 81, - 81, 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 86, 81, 81, 287, 290, 290, - 291, 291, 288, 289, 288, 289, 288, 289, 288, 289, 288, 289, 288, 289, - 288, 289, 288, 289, 253, 253, 288, 289, 287, 287, 287, 287, 291, 291, - 291, 292, 287, 292, 0, 287, 292, 287, 287, 290, 293, 294, 293, 294, 293, - 294, 295, 287, 287, 296, 297, 298, 298, 299, 0, 287, 300, 295, 287, 0, 0, - 0, 0, 131, 131, 131, 118, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, + 0, 0, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 286, + 26, 26, 26, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 287, 287, 287, 287, 287, 287, 287, 288, 289, 287, 0, 0, 0, 0, 0, 0, + 81, 81, 81, 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 86, 81, 81, 287, 290, + 290, 291, 291, 288, 289, 288, 289, 288, 289, 288, 289, 288, 289, 288, + 289, 288, 289, 288, 289, 253, 253, 288, 289, 287, 287, 287, 287, 291, + 291, 291, 292, 287, 292, 0, 287, 292, 287, 287, 290, 293, 294, 293, 294, + 293, 294, 295, 287, 287, 296, 297, 298, 298, 299, 0, 287, 300, 295, 287, + 0, 0, 0, 0, 131, 131, 131, 118, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, @@ -2355,140 +2356,141 @@ static const unsigned short index2[] = { 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 0, 0, 177, 0, 301, 301, 302, 303, 302, 301, 301, 304, 305, 301, 306, - 307, 308, 307, 307, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, - 307, 301, 310, 311, 310, 301, 301, 312, 312, 312, 312, 312, 312, 312, + 131, 131, 131, 0, 0, 177, 0, 301, 301, 302, 303, 302, 301, 301, 304, 305, + 301, 306, 307, 308, 307, 307, 309, 309, 309, 309, 309, 309, 309, 309, + 309, 309, 307, 301, 310, 311, 310, 301, 301, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, - 312, 312, 312, 312, 312, 304, 301, 305, 313, 314, 313, 315, 315, 315, + 312, 312, 312, 312, 312, 312, 312, 304, 301, 305, 313, 314, 313, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, - 315, 315, 315, 315, 315, 315, 315, 315, 315, 304, 311, 305, 311, 304, - 305, 316, 317, 318, 316, 316, 319, 319, 319, 319, 319, 319, 319, 319, - 319, 319, 320, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 304, 311, 305, + 311, 304, 305, 316, 317, 318, 316, 316, 319, 319, 319, 319, 319, 319, + 319, 319, 319, 319, 320, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, - 319, 319, 319, 319, 319, 319, 320, 320, 319, 319, 319, 319, 319, 319, + 319, 319, 319, 319, 319, 319, 319, 319, 320, 320, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, - 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 0, 0, 0, 319, 319, - 319, 319, 319, 319, 0, 0, 319, 319, 319, 319, 319, 319, 0, 0, 319, 319, - 319, 319, 319, 319, 0, 0, 319, 319, 319, 0, 0, 0, 303, 303, 311, 313, - 321, 303, 303, 0, 322, 323, 323, 323, 323, 322, 322, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 324, 324, 324, 26, 30, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 0, 0, 0, + 319, 319, 319, 319, 319, 319, 0, 0, 319, 319, 319, 319, 319, 319, 0, 0, + 319, 319, 319, 319, 319, 319, 0, 0, 319, 319, 319, 0, 0, 0, 303, 303, + 311, 313, 321, 303, 303, 0, 322, 323, 323, 323, 323, 322, 322, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 324, 324, 324, 26, 30, 0, 0, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, + 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, + 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, - 0, 83, 138, 83, 0, 0, 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 48, 0, 0, 0, 0, 0, 83, 138, 83, 0, 0, 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, - 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 155, - 155, 155, 155, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 155, 155, 26, 80, 80, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, 325, + 325, 325, 155, 155, 155, 155, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 155, 155, 26, 80, 80, 0, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 86, 0, 0, 0, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 86, 326, 326, 326, 326, 326, 326, 326, 326, 326, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, - 326, 326, 326, 326, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 326, 326, 326, 326, 326, 326, 326, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 175, 48, 48, 48, 48, 48, 48, 48, 48, 175, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 175, 48, 48, 48, 48, 48, 48, 48, 48, 175, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 81, 81, - 81, 81, 81, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 0, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 0, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 83, 175, 175, - 175, 175, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, + 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 83, + 175, 175, 175, 175, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 44, 44, 44, 44, 44, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 47, 47, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, + 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 0, 0, 0, - 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 47, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44, 44, 44, 44, 44, 0, 44, - 44, 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 0, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 0, 47, 47, 47, 47, 47, 47, 47, 0, - 47, 47, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 142, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 142, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, - 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 53, 51, 51, 51, 51, 51, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 0, 0, 0, 83, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44, 44, 44, + 44, 44, 0, 44, 44, 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 0, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 0, 47, 47, 47, + 47, 47, 47, 47, 0, 47, 47, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 142, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 142, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 53, 51, 51, 51, 51, 51, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 0, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 0, 0, 107, 0, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 0, 107, - 107, 0, 0, 0, 107, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 0, - 104, 327, 327, 327, 327, 327, 327, 327, 327, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 328, 328, 327, 327, 327, 327, 327, 327, 327, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 327, 327, 327, 327, 327, 327, 327, 327, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 0, 0, 107, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 0, 107, 107, 0, 0, 0, 0, 0, 327, 327, 327, 327, - 327, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 327, 327, 327, 327, 327, - 327, 0, 0, 0, 138, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 0, 107, 107, 0, 0, 0, 107, 0, 0, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 0, 104, 327, 327, 327, 327, 327, 327, 327, 327, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 328, 328, 327, 327, 327, 327, 327, + 327, 327, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 327, 327, 327, 327, 327, + 327, 327, 327, 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 0, 107, 107, 0, 0, 0, 0, 0, 327, + 327, 327, 327, 327, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 327, 327, + 327, 327, 327, 327, 0, 0, 0, 138, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 0, 0, 0, 0, 0, 104, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, @@ -2502,7 +2504,7 @@ static const unsigned short index2[] = { 135, 135, 0, 135, 135, 0, 0, 0, 0, 0, 135, 86, 135, 81, 107, 107, 107, 107, 0, 107, 107, 107, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 0, 0, 81, 178, 86, 0, 0, 0, 0, 144, 327, + 107, 107, 107, 107, 107, 107, 0, 0, 81, 179, 86, 0, 0, 0, 0, 144, 327, 327, 327, 327, 327, 327, 327, 327, 327, 0, 0, 0, 0, 0, 0, 0, 104, 104, 104, 104, 104, 104, 104, 104, 104, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, @@ -2570,97 +2572,97 @@ static const unsigned short index2[] = { 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 0, 81, 81, 102, 0, 0, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 135, 86, 86, 86, 107, 107, 107, 107, 107, 107, 107, + 120, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 138, 26, 26, 26, 26, 26, 26, 26, + 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 135, 86, 86, 86, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 327, 327, 327, 327, 327, 327, - 327, 327, 327, 327, 107, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, 118, 118, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 327, 327, + 327, 327, 327, 327, 327, 327, 327, 327, 107, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 86, 86, 81, 81, 81, 86, 81, 86, 86, 86, 86, 333, 333, 333, - 333, 113, 113, 113, 113, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 81, 86, 81, 86, 104, 104, 104, - 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 118, 118, 118, 118, 118, 118, 118, 86, 86, 81, 81, 81, 86, 81, 86, 86, + 86, 86, 333, 333, 333, 333, 113, 113, 113, 113, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 81, 86, + 81, 86, 104, 104, 104, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 327, 327, 327, 327, 327, 327, 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 327, 327, 327, 327, 327, 327, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 135, 141, 48, 48, 48, 48, 48, 48, + 107, 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 144, 83, 83, 83, 83, 83, 83, 83, - 0, 0, 0, 0, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, - 155, 155, 155, 155, 155, 155, 155, 155, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 144, 48, 48, 135, 135, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 144, 135, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 142, 48, 142, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 142, 48, 48, 48, 48, 141, 141, 141, - 135, 135, 135, 135, 141, 141, 144, 143, 83, 83, 192, 83, 83, 83, 83, 135, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, - 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, - 0, 0, 0, 81, 81, 81, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 144, 83, 83, + 83, 83, 83, 83, 83, 0, 0, 0, 0, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 144, 48, 48, 135, 135, 48, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 144, 135, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 142, 48, 142, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 142, 48, 48, 48, + 48, 141, 141, 141, 135, 135, 135, 135, 141, 141, 144, 143, 83, 83, 192, + 83, 83, 83, 83, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 151, 135, 135, 135, 135, 141, 135, 152, 152, 135, - 135, 135, 144, 144, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 83, 83, 83, 83, 48, 141, 141, 48, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, + 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 0, 0, 0, 0, 0, 0, 81, 81, 81, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 147, 83, 83, 48, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 141, 141, 141, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 141, 176, 48, 48, 48, 48, 83, 83, 83, 83, 135, 147, 135, 135, 83, - 141, 135, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 48, 83, 48, - 83, 83, 83, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 151, 135, 135, 135, 135, 141, + 135, 152, 152, 135, 135, 135, 144, 144, 0, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 83, 83, 83, 83, 48, 141, 141, 48, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 141, 141, 135, 135, 135, 141, - 141, 135, 176, 147, 135, 83, 83, 83, 83, 83, 83, 135, 48, 48, 135, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 0, - 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 83, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 147, 83, 83, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 141, 141, 141, 135, 135, - 135, 135, 135, 135, 147, 144, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 135, 135, 141, 141, 0, 48, 48, - 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 0, 0, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, - 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 0, 147, 147, 48, - 148, 141, 135, 141, 141, 141, 141, 0, 0, 141, 141, 0, 0, 149, 149, 176, - 0, 0, 48, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 141, - 141, 0, 0, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 81, 81, 81, 81, 81, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 142, 48, 142, 48, 48, 48, 48, 0, - 48, 0, 0, 142, 0, 48, 142, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 0, 48, 148, 141, 141, 151, 135, 135, 135, - 135, 135, 0, 148, 0, 0, 334, 0, 334, 334, 148, 141, 0, 141, 141, 144, - 176, 144, 48, 135, 48, 83, 83, 0, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 135, - 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 141, 141, 141, 135, 135, 135, 135, 135, 135, 135, 135, 141, - 141, 144, 135, 135, 141, 147, 48, 48, 48, 48, 83, 83, 83, 83, 83, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 83, 0, 83, 81, 48, 48, - 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 141, 141, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 141, 176, 48, 48, 48, 48, 83, 83, 83, 83, 135, + 147, 135, 135, 83, 141, 135, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 48, 83, 48, 83, 83, 83, 0, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 148, - 141, 141, 135, 135, 135, 135, 135, 135, 141, 151, 149, 149, 148, 149, - 135, 135, 141, 144, 147, 48, 48, 83, 48, 0, 0, 0, 0, 0, 0, 0, 0, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 141, 141, 135, + 135, 135, 141, 141, 135, 176, 147, 135, 83, 83, 83, 83, 83, 83, 135, 48, + 48, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, + 48, 48, 0, 48, 0, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 83, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 148, 141, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 141, + 141, 141, 135, 135, 135, 135, 135, 135, 147, 144, 0, 0, 0, 0, 0, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 135, 135, + 141, 141, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 48, 48, 0, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, + 0, 147, 147, 48, 148, 141, 135, 141, 141, 141, 141, 0, 0, 141, 141, 0, 0, + 149, 149, 176, 0, 0, 48, 0, 0, 0, 0, 0, 0, 148, 0, 0, 0, 0, 0, 48, 48, + 48, 48, 48, 141, 141, 0, 0, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 81, 81, + 81, 81, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 142, 48, 142, + 48, 48, 48, 48, 0, 48, 0, 0, 142, 0, 48, 142, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 148, 141, 141, 151, + 135, 135, 135, 135, 135, 0, 148, 0, 0, 334, 0, 334, 334, 148, 141, 0, + 141, 141, 144, 176, 144, 48, 135, 48, 83, 83, 0, 83, 83, 0, 0, 0, 0, 0, + 0, 0, 0, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 141, 141, 141, 135, 135, 135, 135, 135, 135, + 135, 135, 141, 141, 144, 135, 135, 141, 147, 48, 48, 48, 48, 83, 83, 83, + 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 83, 83, 0, 83, + 81, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 148, 141, 141, 135, 135, 135, 135, 135, 135, 141, 151, 149, 149, + 148, 149, 135, 135, 141, 144, 147, 48, 48, 83, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 148, 141, 141, 135, 135, 135, 135, 0, 0, 141, 141, 149, 149, 135, 135, 141, 144, 147, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 48, 48, 48, 48, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2730,224 +2732,227 @@ static const unsigned short index2[] = { 83, 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 83, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 141, 135, - 135, 135, 135, 135, 135, 135, 0, 135, 135, 135, 135, 135, 135, 141, 335, - 48, 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 0, 0, 0, 83, 83, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 0, 141, 135, 135, 135, 135, 135, 135, 135, 141, 135, - 135, 141, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 135, 135, 135, 135, 135, 135, 0, 0, 0, 135, 0, 135, 135, 0, 135, 135, - 135, 147, 135, 144, 144, 48, 135, 0, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, - 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 141, 141, 141, 141, 141, 0, 135, 135, 0, 141, 141, 135, 141, 144, 48, 0, - 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 135, 141, 141, 83, 83, 0, 0, - 0, 0, 0, 0, 0, 135, 135, 48, 141, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 141, 141, 135, 135, 135, 135, 135, 0, 0, 0, 141, 141, 135, 176, - 144, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 150, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 26, 26, 26, 26, 26, 26, 26, 26, 85, 85, 85, 85, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 0, - 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 192, 192, 192, 192, 192, 135, 48, 48, 48, 48, 48, 48, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 151, 151, 151, 336, 336, 336, 336, 336, 336, 336, 336, 151, 141, 141, - 141, 135, 135, 144, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 83, - 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 0, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 0, 0, 178, 178, 178, 178, 178, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 81, 81, 81, 81, 81, 81, - 81, 83, 83, 83, 83, 83, 80, 80, 80, 80, 53, 53, 53, 53, 83, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, - 150, 150, 150, 150, 150, 150, 150, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 53, 53, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 173, 337, 142, 142, 53, 53, 83, 83, 83, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 83, 83, 83, 83, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, + 141, 135, 135, 135, 141, 135, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 83, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 141, 135, 135, 135, 135, 135, 135, 135, 0, 135, 135, 135, 135, + 135, 135, 141, 335, 48, 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 0, 0, 0, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 0, 141, 135, 135, 135, 135, 135, + 135, 135, 141, 135, 135, 141, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, + 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 135, 135, 135, 135, 135, 135, 0, 0, 0, 135, 0, 135, + 135, 0, 135, 135, 135, 147, 135, 144, 144, 48, 135, 0, 0, 0, 0, 0, 0, 0, + 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 0, 0, 0, 0, 135, 48, 141, 141, 141, 141, 141, 141, - 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, - 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, - 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, - 141, 141, 141, 141, 141, 141, 141, 0, 0, 0, 0, 0, 0, 0, 135, 135, 135, - 135, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 254, 253, 254, 338, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 339, 339, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, - 254, 254, 254, 0, 254, 254, 254, 254, 254, 254, 254, 0, 254, 254, 0, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 172, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 0, 0, 0, 0, 48, + 48, 48, 48, 48, 48, 141, 141, 141, 141, 141, 0, 135, 135, 0, 141, 141, + 135, 141, 144, 48, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 48, 48, 0, 0, + 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 135, 135, 141, 141, + 83, 83, 0, 0, 0, 0, 0, 0, 0, 135, 135, 48, 141, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 141, 141, 135, 135, 135, 135, 135, 0, 0, 0, 141, + 141, 135, 176, 144, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 135, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 26, 26, 26, 26, 26, 26, 26, 26, 85, + 85, 85, 85, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, + 175, 175, 175, 175, 175, 0, 83, 83, 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, - 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 0, 0, 80, 135, 178, 83, 177, 177, 177, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, + 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 135, 48, 48, + 48, 48, 48, 48, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 151, 151, 151, 336, 336, 336, 336, 336, 336, + 336, 336, 151, 141, 141, 141, 135, 135, 144, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 0, 0, 0, 0, 83, 83, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 0, 0, 179, 179, 179, 179, 179, 83, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 81, + 81, 81, 81, 81, 81, 81, 83, 83, 83, 83, 83, 80, 80, 80, 80, 53, 53, 53, + 53, 83, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 0, 150, 150, 150, 150, 150, 150, 150, 0, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 53, 53, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 173, 337, 142, 142, + 53, 53, 83, 83, 83, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, + 150, 83, 83, 83, 83, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 135, 48, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, + 141, 141, 141, 141, 141, 141, 141, 141, 0, 0, 0, 0, 0, 0, 0, 135, 135, + 135, 135, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 254, 253, 254, 338, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 339, 339, 254, 254, 255, 255, 255, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 254, 254, 254, 0, 254, + 254, 254, 254, 254, 254, 254, 0, 254, 254, 0, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 172, 172, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 172, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 0, 0, 0, 0, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 0, 0, 80, 135, 179, 83, 177, 177, 177, 177, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, @@ -2959,91 +2964,97 @@ static const unsigned short index2[] = { 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 340, 340, 340, 340, 340, 340, + 26, 26, 26, 26, 26, 26, 26, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 341, 341, 341, 341, 341, 341, 341, 341, - 341, 341, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 340, 340, 340, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 26, 26, + 26, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 135, 135, 135, 135, 135, 135, + 26, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 0, 0, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 0, + 0, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 80, 80, 80, 80, 80, 80, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 0, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 342, 342, - 342, 342, 342, 342, 342, 343, 343, 178, 178, 178, 80, 80, 80, 344, 343, - 343, 343, 343, 343, 177, 177, 177, 177, 177, 177, 177, 177, 86, 86, 86, - 86, 86, 86, 86, 86, 80, 80, 81, 81, 81, 81, 81, 86, 86, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 342, 342, 342, 342, 342, 342, 80, 80, 80, 80, + 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 342, 342, 342, 342, 342, 342, 342, 343, 343, 179, 179, 179, 80, 80, 80, + 344, 343, 343, 343, 343, 343, 177, 177, 177, 177, 177, 177, 177, 177, 86, + 86, 86, 86, 86, 86, 86, 86, 80, 80, 81, 81, 81, 81, 81, 86, 86, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 342, 342, 342, 342, 342, 342, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 81, 81, 81, 26, 0, 0, 0, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 81, 81, 81, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 150, + 150, 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, + 150, 150, 150, 150, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, - 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 150, - 150, 0, 0, 0, 0, 0, 0, 0, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 345, 345, 345, 345, 345, 345, 345, + 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, + 345, 150, 150, 0, 0, 0, 0, 0, 0, 0, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, - 35, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, + 35, 35, 35, 35, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 49, 0, 49, 49, 0, 0, 49, 0, 0, 49, 49, 0, 0, 49, 49, 49, 49, 0, 49, 49, - 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 0, 35, 0, 35, 35, 35, 35, 35, 35, - 35, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, + 35, 35, 35, 49, 0, 49, 49, 0, 0, 49, 0, 0, 49, 49, 0, 0, 49, 49, 49, 49, + 0, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 0, 35, 0, 35, 35, 35, + 35, 35, 35, 35, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 0, 49, + 49, 49, 49, 0, 0, 49, 49, 49, 49, 49, 49, 49, 49, 0, 49, 49, 49, 49, 49, + 49, 49, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 0, 49, 49, 49, 49, 0, - 0, 49, 49, 49, 49, 49, 49, 49, 49, 0, 49, 49, 49, 49, 49, 49, 49, 0, 35, + 49, 49, 49, 49, 49, 0, 49, 0, 0, 0, 49, 49, 49, 49, 49, 49, 49, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 49, 49, 0, 49, 49, 49, 49, 0, 49, 49, 49, 49, - 49, 0, 49, 0, 0, 0, 49, 49, 49, 49, 49, 49, 49, 0, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, @@ -3056,16 +3067,7 @@ static const unsigned short index2[] = { 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 220, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 230, 35, 35, 35, 35, 35, 35, 49, 49, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 220, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 230, 35, 35, 35, 35, @@ -3078,192 +3080,272 @@ static const unsigned short index2[] = { 35, 35, 35, 230, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 220, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 230, 35, 35, 35, 35, 35, 35, 49, 35, 0, 0, + 35, 35, 35, 35, 35, 35, 35, 230, 35, 35, 35, 35, 35, 35, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 220, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 230, 35, 35, 35, 35, 35, 35, + 49, 35, 0, 0, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, - 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, - 341, 341, 341, 341, 341, 341, 341, 341, 135, 135, 135, 135, 135, 135, + 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 80, 80, 80, 80, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 80, 80, 80, 80, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 80, 80, 80, 80, 80, 80, 80, 80, 135, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 135, 80, 80, 83, 83, 83, 83, 83, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 135, 135, 135, 0, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 135, 135, 135, 135, 135, 135, 80, 80, 80, 80, 80, 80, 80, 80, 135, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 135, 80, 80, 83, 83, + 83, 83, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 135, 135, + 135, 135, 0, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 0, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 48, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 0, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 81, 81, 81, 81, 81, 81, 81, 0, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 81, 81, 81, 81, 81, 81, 81, - 0, 81, 81, 0, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 51, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 81, 81, 81, 81, 81, 0, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 81, 81, 81, 81, + 81, 81, 81, 0, 81, 81, 0, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 51, 51, 51, 51, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 81, 81, 81, 81, - 81, 81, 81, 53, 53, 53, 53, 53, 53, 53, 0, 0, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 0, 0, 0, 0, 48, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 81, + 81, 81, 81, 81, 81, 81, 53, 53, 53, 53, 53, 53, 53, 0, 0, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 0, 0, 0, 0, 48, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 81, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 81, 81, 81, 81, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 81, 81, 81, 81, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 53, 182, 182, 86, 81, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 81, 86, 48, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, + 48, 48, 48, 81, 48, 48, 81, 48, 48, 48, 48, 48, 48, 48, 81, 81, 48, 48, + 48, 48, 48, 81, 0, 0, 0, 0, 0, 0, 0, 0, 48, 53, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 53, 182, 182, 86, 81, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 0, 48, 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 0, 0, 327, 327, 327, 327, 327, 327, 327, + 327, 327, 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 81, 86, 48, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 0, 48, - 48, 48, 48, 0, 48, 48, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 0, 0, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, + 0, 0, 0, 0, 0, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, - 329, 329, 329, 329, 329, 329, 329, 330, 330, 330, 330, 330, 330, 330, + 329, 329, 329, 329, 329, 329, 329, 329, 329, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 81, 81, - 81, 81, 81, 81, 147, 137, 0, 0, 0, 0, 136, 136, 136, 136, 136, 136, 136, - 136, 136, 136, 0, 0, 0, 0, 104, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, + 330, 81, 81, 81, 81, 81, 81, 147, 137, 0, 0, 0, 0, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 0, 0, 0, 0, 104, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, 333, 333, 333, 333, 333, 333, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, - 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 133, 333, 333, 333, - 111, 333, 333, 333, 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 133, + 333, 333, 333, 111, 333, 333, 333, 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, 333, 333, 333, 333, 333, 333, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, - 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 133, 333, 333, 333, - 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 0, 0, 0, 0, + 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 133, + 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, + 333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 131, 131, 131, 0, 131, - 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 0, 131, 131, - 0, 131, 0, 0, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 0, 131, 131, 131, 131, 0, 131, 0, 131, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, - 131, 0, 131, 0, 131, 0, 131, 131, 131, 0, 131, 131, 0, 131, 0, 0, 131, 0, - 131, 0, 131, 0, 131, 0, 131, 0, 131, 131, 0, 131, 0, 0, 131, 131, 131, - 131, 0, 131, 131, 131, 131, 131, 131, 131, 0, 131, 131, 131, 131, 0, 131, - 131, 131, 131, 0, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 131, 131, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 131, 131, 131, 0, 0, 0, 0, 0, 131, 131, 131, 0, 131, 131, 131, 131, - 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, - 131, 131, 131, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 0, + 131, 131, 0, 131, 0, 0, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 0, 131, 131, 131, 131, 0, 131, 0, 131, 0, 0, 0, 0, 0, 0, 131, + 0, 0, 0, 0, 131, 0, 131, 0, 131, 0, 131, 131, 131, 0, 131, 131, 0, 131, + 0, 0, 131, 0, 131, 0, 131, 0, 131, 0, 131, 0, 131, 131, 0, 131, 0, 0, + 131, 131, 131, 131, 0, 131, 131, 131, 131, 131, 131, 131, 0, 131, 131, + 131, 131, 0, 131, 131, 131, 131, 0, 131, 0, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 0, 0, 0, 0, 0, 131, 131, 131, 0, 131, + 131, 131, 131, 131, 0, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 78, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 243, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 155, 155, 26, 26, 26, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 340, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 155, 155, 26, 26, 26, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, + 246, 246, 340, 26, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, - 346, 346, 226, 226, 226, 26, 26, 26, 346, 346, 346, 346, 346, 346, 346, + 346, 346, 346, 346, 346, 226, 226, 226, 26, 26, 26, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, - 346, 346, 346, 346, 346, 346, 346, 346, 346, 272, 346, 246, 272, 272, - 272, 272, 272, 272, 272, 272, 272, 272, 346, 346, 346, 346, 346, 346, - 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 26, 0, 0, 0, + 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 272, 346, + 246, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 346, 346, 346, + 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, + 346, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 274, 274, 274, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 274, 274, 274, 274, 274, 274, 274, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 274, 274, + 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 274, 0, 0, 0, 0, 274, 274, 274, 274, - 274, 274, 274, 274, 274, 0, 0, 0, 0, 0, 0, 0, 274, 274, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 0, 0, 0, 0, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 0, 0, 0, 0, 0, 0, 0, 274, 274, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, + 26, 26, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 26, 26, 26, 243, 26, 26, 26, 243, 243, 243, 347, 347, + 347, 347, 347, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 243, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, - 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 26, 26, 26, 243, 26, 26, 26, 243, 243, 243, 347, 347, 347, - 347, 347, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 243, 26, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 243, 26, 26, + 26, 243, 243, 243, 26, 26, 243, 243, 243, 243, 0, 0, 0, 243, 243, 243, + 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 0, 0, 0, 26, + 26, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, + 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, + 0, 0, 0, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, + 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, @@ -3276,128 +3358,41 @@ static const unsigned short index2[] = { 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 26, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 243, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 243, 26, 26, 26, 243, 243, - 243, 26, 26, 243, 243, 243, 0, 0, 0, 0, 243, 243, 243, 243, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 243, 243, 0, 0, 0, 26, 26, 26, 26, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 26, 26, 26, 26, 26, 26, + 243, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, + 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, + 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, - 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, - 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 26, 26, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 26, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 26, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 0, 0, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 341, 341, - 341, 341, 341, 341, 341, 341, 341, 341, 0, 0, 0, 0, 0, 0, 172, 172, 172, + 26, 26, 26, 26, 26, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 26, + 0, 0, 0, 0, 0, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, + 172, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 172, + 281, 281, 281, 281, 281, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 281, 281, 281, 281, 281, 281, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 281, 281, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 281, 281, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, @@ -3406,7 +3401,21 @@ static const unsigned short index2[] = { 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 281, 281, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, @@ -3415,21 +3424,7 @@ static const unsigned short index2[] = { 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 172, 172, 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, @@ -3440,9 +3435,10 @@ static const unsigned short index2[] = { 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, + 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, @@ -3458,34 +3454,33 @@ static const unsigned short index2[] = { 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 0, 0, + 281, 281, 281, 0, 0, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 177, 177, 177, 177, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 281, 281, 281, 281, 281, 281, 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, - 177, 177, 177, 177, 177, 177, 177, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, @@ -3498,8 +3493,8 @@ static const unsigned short index2[] = { 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 279, 279, 279, 279, 279, 279, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, @@ -3508,7 +3503,7 @@ static const unsigned short index2[] = { 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, - 279, 279, 279, 279, 279, 279, 279, 0, 0, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 0, 0, }; /* decomposition data */ @@ -3992,85 +3987,85 @@ static const unsigned int decomp_data[] = { 50, 52, 26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770, 50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49, 26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, - 67, 259, 70, 259, 81, 259, 294, 259, 339, 259, 42791, 259, 43831, 259, - 619, 259, 43858, 259, 653, 256, 35912, 256, 26356, 256, 36554, 256, - 36040, 256, 28369, 256, 20018, 256, 21477, 256, 40860, 256, 22865, 256, - 37329, 256, 21895, 256, 22856, 256, 25078, 256, 30313, 256, 32645, 256, - 34367, 256, 34746, 256, 35064, 256, 37007, 256, 27138, 256, 27931, 256, - 28889, 256, 29662, 256, 33853, 256, 37226, 256, 39409, 256, 20098, 256, - 21365, 256, 27396, 256, 29211, 256, 34349, 256, 40478, 256, 23888, 256, - 28651, 256, 34253, 256, 35172, 256, 25289, 256, 33240, 256, 34847, 256, - 24266, 256, 26391, 256, 28010, 256, 29436, 256, 37070, 256, 20358, 256, - 20919, 256, 21214, 256, 25796, 256, 27347, 256, 29200, 256, 30439, 256, - 32769, 256, 34310, 256, 34396, 256, 36335, 256, 38706, 256, 39791, 256, - 40442, 256, 30860, 256, 31103, 256, 32160, 256, 33737, 256, 37636, 256, - 40575, 256, 35542, 256, 22751, 256, 24324, 256, 31840, 256, 32894, 256, - 29282, 256, 30922, 256, 36034, 256, 38647, 256, 22744, 256, 23650, 256, - 27155, 256, 28122, 256, 28431, 256, 32047, 256, 32311, 256, 38475, 256, - 21202, 256, 32907, 256, 20956, 256, 20940, 256, 31260, 256, 32190, 256, - 33777, 256, 38517, 256, 35712, 256, 25295, 256, 35582, 256, 20025, 256, - 23527, 256, 24594, 256, 29575, 256, 30064, 256, 21271, 256, 30971, 256, - 20415, 256, 24489, 256, 19981, 256, 27852, 256, 25976, 256, 32034, 256, - 21443, 256, 22622, 256, 30465, 256, 33865, 256, 35498, 256, 27578, 256, - 36784, 256, 27784, 256, 25342, 256, 33509, 256, 25504, 256, 30053, 256, - 20142, 256, 20841, 256, 20937, 256, 26753, 256, 31975, 256, 33391, 256, - 35538, 256, 37327, 256, 21237, 256, 21570, 256, 22899, 256, 24300, 256, - 26053, 256, 28670, 256, 31018, 256, 38317, 256, 39530, 256, 40599, 256, - 40654, 256, 21147, 256, 26310, 256, 27511, 256, 36706, 256, 24180, 256, - 24976, 256, 25088, 256, 25754, 256, 28451, 256, 29001, 256, 29833, 256, - 31178, 256, 32244, 256, 32879, 256, 36646, 256, 34030, 256, 36899, 256, - 37706, 256, 21015, 256, 21155, 256, 21693, 256, 28872, 256, 35010, 256, - 24265, 256, 24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, - 20196, 256, 22265, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256, - 32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256, - 20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256, - 20698, 256, 23534, 256, 23615, 256, 26009, 256, 29134, 256, 30274, 256, - 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256, 21129, 256, - 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256, 30041, 256, - 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256, 38520, 256, - 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256, 24900, 256, - 26647, 256, 38534, 256, 21033, 256, 21519, 256, 23653, 256, 26131, 256, - 26446, 256, 26792, 256, 27877, 256, 29702, 256, 30178, 256, 32633, 256, - 35023, 256, 35041, 256, 37324, 256, 38626, 256, 21311, 256, 28346, 256, - 21533, 256, 29136, 256, 29848, 256, 34298, 256, 38563, 256, 40023, 256, - 40607, 256, 26519, 256, 28107, 256, 33256, 256, 31435, 256, 31520, 256, - 31890, 256, 29376, 256, 28825, 256, 35672, 256, 20160, 256, 33590, 256, - 21050, 256, 20999, 256, 24230, 256, 25299, 256, 31958, 256, 23429, 256, - 27934, 256, 26292, 256, 36667, 256, 34892, 256, 38477, 256, 35211, 256, - 24275, 256, 20800, 256, 21952, 256, 22618, 256, 26228, 256, 20958, 256, - 29482, 256, 30410, 256, 31036, 256, 31070, 256, 31077, 256, 31119, 256, - 38742, 256, 31934, 256, 32701, 256, 34322, 256, 35576, 256, 36920, 256, - 37117, 256, 39151, 256, 39164, 256, 39208, 256, 40372, 256, 37086, 256, - 38583, 256, 20398, 256, 20711, 256, 20813, 256, 21193, 256, 21220, 256, - 21329, 256, 21917, 256, 22022, 256, 22120, 256, 22592, 256, 22696, 256, - 23652, 256, 23662, 256, 24724, 256, 24936, 256, 24974, 256, 25074, 256, - 25935, 256, 26082, 256, 26257, 256, 26757, 256, 28023, 256, 28186, 256, - 28450, 256, 29038, 256, 29227, 256, 29730, 256, 30865, 256, 31038, 256, - 31049, 256, 31048, 256, 31056, 256, 31062, 256, 31069, 256, 31117, 256, - 31118, 256, 31296, 256, 31361, 256, 31680, 256, 32265, 256, 32321, 256, - 32626, 256, 32773, 256, 33261, 256, 33401, 256, 33879, 256, 35088, 256, - 35222, 256, 35585, 256, 35641, 256, 36051, 256, 36104, 256, 36790, 256, - 38627, 256, 38911, 256, 38971, 256, 24693, 256, 148206, 256, 33304, 256, - 20006, 256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, - 21191, 256, 21242, 256, 21845, 256, 21913, 256, 21986, 256, 22707, 256, - 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274, 256, 24281, 256, - 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840, 256, 24928, 256, - 25140, 256, 25540, 256, 25628, 256, 25682, 256, 25942, 256, 26395, 256, - 26454, 256, 27513, 256, 28379, 256, 28363, 256, 28702, 256, 30631, 256, - 29237, 256, 29359, 256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, - 30239, 256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, - 31409, 256, 31867, 256, 32091, 256, 32574, 256, 33618, 256, 33775, 256, - 34681, 256, 35137, 256, 35206, 256, 35519, 256, 35531, 256, 35565, 256, - 35722, 256, 36664, 256, 36978, 256, 37273, 256, 37494, 256, 38524, 256, - 38875, 256, 38923, 256, 39698, 256, 141386, 256, 141380, 256, 144341, - 256, 15261, 256, 16408, 256, 16441, 256, 152137, 256, 154832, 256, - 163539, 256, 40771, 256, 40846, 514, 102, 102, 514, 102, 105, 514, 102, - 108, 770, 102, 102, 105, 770, 102, 102, 108, 514, 383, 116, 514, 115, - 116, 514, 1396, 1398, 514, 1396, 1381, 514, 1396, 1387, 514, 1406, 1398, - 514, 1396, 1389, 512, 1497, 1460, 512, 1522, 1463, 262, 1506, 262, 1488, - 262, 1491, 262, 1492, 262, 1499, 262, 1500, 262, 1501, 262, 1512, 262, - 1514, 262, 43, 512, 1513, 1473, 512, 1513, 1474, 512, 64329, 1473, 512, - 64329, 1474, 512, 1488, 1463, 512, 1488, 1464, 512, 1488, 1468, 512, + 83, 259, 67, 259, 70, 259, 81, 259, 294, 259, 339, 259, 42791, 259, + 43831, 259, 619, 259, 43858, 259, 653, 256, 35912, 256, 26356, 256, + 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256, 40860, 256, + 22865, 256, 37329, 256, 21895, 256, 22856, 256, 25078, 256, 30313, 256, + 32645, 256, 34367, 256, 34746, 256, 35064, 256, 37007, 256, 27138, 256, + 27931, 256, 28889, 256, 29662, 256, 33853, 256, 37226, 256, 39409, 256, + 20098, 256, 21365, 256, 27396, 256, 29211, 256, 34349, 256, 40478, 256, + 23888, 256, 28651, 256, 34253, 256, 35172, 256, 25289, 256, 33240, 256, + 34847, 256, 24266, 256, 26391, 256, 28010, 256, 29436, 256, 37070, 256, + 20358, 256, 20919, 256, 21214, 256, 25796, 256, 27347, 256, 29200, 256, + 30439, 256, 32769, 256, 34310, 256, 34396, 256, 36335, 256, 38706, 256, + 39791, 256, 40442, 256, 30860, 256, 31103, 256, 32160, 256, 33737, 256, + 37636, 256, 40575, 256, 35542, 256, 22751, 256, 24324, 256, 31840, 256, + 32894, 256, 29282, 256, 30922, 256, 36034, 256, 38647, 256, 22744, 256, + 23650, 256, 27155, 256, 28122, 256, 28431, 256, 32047, 256, 32311, 256, + 38475, 256, 21202, 256, 32907, 256, 20956, 256, 20940, 256, 31260, 256, + 32190, 256, 33777, 256, 38517, 256, 35712, 256, 25295, 256, 35582, 256, + 20025, 256, 23527, 256, 24594, 256, 29575, 256, 30064, 256, 21271, 256, + 30971, 256, 20415, 256, 24489, 256, 19981, 256, 27852, 256, 25976, 256, + 32034, 256, 21443, 256, 22622, 256, 30465, 256, 33865, 256, 35498, 256, + 27578, 256, 36784, 256, 27784, 256, 25342, 256, 33509, 256, 25504, 256, + 30053, 256, 20142, 256, 20841, 256, 20937, 256, 26753, 256, 31975, 256, + 33391, 256, 35538, 256, 37327, 256, 21237, 256, 21570, 256, 22899, 256, + 24300, 256, 26053, 256, 28670, 256, 31018, 256, 38317, 256, 39530, 256, + 40599, 256, 40654, 256, 21147, 256, 26310, 256, 27511, 256, 36706, 256, + 24180, 256, 24976, 256, 25088, 256, 25754, 256, 28451, 256, 29001, 256, + 29833, 256, 31178, 256, 32244, 256, 32879, 256, 36646, 256, 34030, 256, + 36899, 256, 37706, 256, 21015, 256, 21155, 256, 21693, 256, 28872, 256, + 35010, 256, 24265, 256, 24565, 256, 25467, 256, 27566, 256, 31806, 256, + 29557, 256, 20196, 256, 22265, 256, 23994, 256, 24604, 256, 29618, 256, + 29801, 256, 32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, + 38936, 256, 20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, + 20102, 256, 20698, 256, 23534, 256, 23615, 256, 26009, 256, 29134, 256, + 30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256, + 21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256, + 30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256, + 38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256, + 24900, 256, 26647, 256, 38534, 256, 21033, 256, 21519, 256, 23653, 256, + 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256, 30178, 256, + 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256, 21311, 256, + 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256, 38563, 256, + 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256, 31435, 256, + 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256, 20160, 256, + 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256, 31958, 256, + 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256, 38477, 256, + 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256, 26228, 256, + 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256, 31077, 256, + 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256, 35576, 256, + 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256, 40372, 256, + 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256, 21193, 256, + 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256, 22592, 256, + 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256, 24974, 256, + 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256, 28023, 256, + 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256, 30865, 256, + 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256, 31069, 256, + 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256, 32265, 256, + 32321, 256, 32626, 256, 32773, 256, 33261, 256, 33401, 256, 33879, 256, + 35088, 256, 35222, 256, 35585, 256, 35641, 256, 36051, 256, 36104, 256, + 36790, 256, 38627, 256, 38911, 256, 38971, 256, 24693, 256, 148206, 256, + 33304, 256, 20006, 256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, + 20864, 256, 21191, 256, 21242, 256, 21845, 256, 21913, 256, 21986, 256, + 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274, 256, + 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840, 256, + 24928, 256, 25140, 256, 25540, 256, 25628, 256, 25682, 256, 25942, 256, + 26395, 256, 26454, 256, 27513, 256, 28379, 256, 28363, 256, 28702, 256, + 30631, 256, 29237, 256, 29359, 256, 29809, 256, 29958, 256, 30011, 256, + 30237, 256, 30239, 256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, + 30924, 256, 31409, 256, 31867, 256, 32091, 256, 32574, 256, 33618, 256, + 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35519, 256, 35531, 256, + 35565, 256, 35722, 256, 36664, 256, 36978, 256, 37273, 256, 37494, 256, + 38524, 256, 38875, 256, 38923, 256, 39698, 256, 141386, 256, 141380, 256, + 144341, 256, 15261, 256, 16408, 256, 16441, 256, 152137, 256, 154832, + 256, 163539, 256, 40771, 256, 40846, 514, 102, 102, 514, 102, 105, 514, + 102, 108, 770, 102, 102, 105, 770, 102, 102, 108, 514, 383, 116, 514, + 115, 116, 514, 1396, 1398, 514, 1396, 1381, 514, 1396, 1387, 514, 1406, + 1398, 514, 1396, 1389, 512, 1497, 1460, 512, 1522, 1463, 262, 1506, 262, + 1488, 262, 1491, 262, 1492, 262, 1499, 262, 1500, 262, 1501, 262, 1512, + 262, 1514, 262, 43, 512, 1513, 1473, 512, 1513, 1474, 512, 64329, 1473, + 512, 64329, 1474, 512, 1488, 1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468, 512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512, 1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500, 1468, 512, 1502, 1468, 512, 1504, 1468, 512, @@ -5234,210 +5229,210 @@ static const unsigned short decomp_index2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6603, 6605, - 6607, 0, 0, 0, 6609, 6611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6603, 6605, 6607, + 6609, 0, 0, 0, 6611, 6613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6613, 6615, 6617, 6619, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 6621, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 6623, 6625, 6627, 6629, 6631, 6633, 6635, 6637, 6637, 6639, - 6641, 6643, 6645, 6647, 6649, 6651, 6653, 6655, 6657, 6659, 6661, 6663, - 6665, 6667, 6669, 6671, 6673, 6675, 6677, 6679, 6681, 6683, 6685, 6687, - 6689, 6691, 6693, 6695, 6697, 6699, 6701, 6703, 6705, 6707, 6709, 6711, - 6713, 6715, 6717, 6719, 6721, 6723, 6725, 6727, 6729, 6731, 6733, 6735, - 6737, 6739, 6741, 6743, 6745, 6747, 6749, 6751, 6753, 6755, 6757, 6759, - 6761, 6763, 6765, 6767, 6769, 6771, 6773, 6775, 6777, 6779, 6781, 6783, - 6785, 6787, 6789, 6791, 6793, 6795, 6797, 6799, 6801, 6803, 6661, 6805, - 6807, 6809, 6811, 6813, 6815, 6817, 6819, 6821, 6823, 6825, 6827, 6829, - 6831, 6833, 6835, 6837, 6839, 6841, 6843, 6845, 6847, 6849, 6851, 6853, - 6855, 6857, 6859, 6861, 6863, 6865, 6867, 6869, 6871, 6873, 6875, 6877, - 6879, 6881, 6883, 6885, 6887, 6889, 6891, 6893, 6895, 6897, 6899, 6901, - 6903, 6905, 6907, 6909, 6911, 6913, 6915, 6917, 6919, 6921, 6923, 6925, - 6927, 6929, 6931, 6933, 6935, 6937, 6939, 6841, 6941, 6943, 6945, 6947, - 6949, 6951, 6953, 6955, 6809, 6957, 6959, 6961, 6963, 6965, 6967, 6969, - 6971, 6973, 6975, 6977, 6979, 6981, 6983, 6985, 6987, 6989, 6991, 6993, - 6995, 6661, 6997, 6999, 7001, 7003, 7005, 7007, 7009, 7011, 7013, 7015, - 7017, 7019, 7021, 7023, 7025, 7027, 7029, 7031, 7033, 7035, 7037, 7039, - 7041, 7043, 7045, 7047, 7049, 6813, 7051, 7053, 7055, 7057, 7059, 7061, - 7063, 7065, 7067, 7069, 7071, 7073, 7075, 7077, 7079, 7081, 7083, 7085, - 7087, 7089, 7091, 7093, 7095, 7097, 7099, 7101, 7103, 7105, 7107, 7109, - 7111, 7113, 7115, 7117, 7119, 7121, 7123, 7125, 7127, 7129, 7131, 7133, - 7135, 7137, 7139, 7141, 7143, 7145, 7147, 7149, 0, 0, 7151, 0, 7153, 0, - 0, 7155, 7157, 7159, 7161, 7163, 7165, 7167, 7169, 7171, 7173, 0, 7175, - 0, 7177, 0, 0, 7179, 7181, 0, 0, 0, 7183, 7185, 7187, 7189, 7191, 7193, - 7195, 7197, 7199, 7201, 7203, 7205, 7207, 7209, 7211, 7213, 7215, 7217, - 7219, 7221, 7223, 7225, 7227, 7229, 7231, 7233, 7235, 7237, 7239, 7241, - 7243, 7245, 7247, 7249, 7251, 7253, 7255, 7257, 7259, 7261, 7263, 7265, - 7267, 7269, 7271, 6919, 7273, 7275, 7277, 7279, 7281, 7283, 7283, 7285, - 7287, 7289, 7291, 7293, 7295, 7297, 7299, 7179, 7301, 7303, 7305, 7307, - 7309, 7311, 0, 0, 7313, 7315, 7317, 7319, 7321, 7323, 7325, 7327, 7207, - 7329, 7331, 7333, 7151, 7335, 7337, 7339, 7341, 7343, 7345, 7347, 7349, - 7351, 7353, 7355, 7357, 7225, 7359, 7227, 7361, 7363, 7365, 7367, 7369, - 7153, 6703, 7371, 7373, 7375, 6843, 7017, 7377, 7379, 7241, 7381, 7243, - 7383, 7385, 7387, 7157, 7389, 7391, 7393, 7395, 7397, 7159, 7399, 7401, - 7403, 7405, 7407, 7409, 7271, 7411, 7413, 6919, 7415, 7279, 7417, 7419, - 7421, 7423, 7425, 7289, 7427, 7177, 7429, 7291, 6805, 7431, 7293, 7433, - 7297, 7435, 7437, 7439, 7441, 7443, 7301, 7169, 7445, 7303, 7447, 7305, - 7449, 6637, 7451, 7453, 7455, 7457, 7459, 7461, 7463, 7465, 7467, 7469, - 7471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7473, 7476, 7479, 7482, - 7486, 7490, 7493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7496, 7499, 7502, - 7505, 7508, 0, 0, 0, 0, 0, 7511, 0, 7514, 7517, 7519, 7521, 7523, 7525, - 7527, 7529, 7531, 7533, 7535, 7537, 7540, 7543, 7546, 7549, 7552, 7555, - 7558, 7561, 7564, 7567, 7570, 7573, 0, 7576, 7579, 7582, 7585, 7588, 0, - 7591, 0, 7594, 7597, 0, 7600, 7603, 0, 7606, 7609, 7612, 7615, 7618, - 7621, 7624, 7627, 7630, 7633, 7636, 7638, 7640, 7642, 7644, 7646, 7648, - 7650, 7652, 7654, 7656, 7658, 7660, 7662, 7664, 7666, 7668, 7670, 7672, - 7674, 7676, 7678, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, - 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, - 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, - 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, - 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, - 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, - 7818, 7820, 7822, 7824, 7826, 7828, 7830, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6615, 6617, 6619, 6621, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6625, 6627, 6629, 6631, 6633, 6635, 6637, 6639, 6639, 6641, + 6643, 6645, 6647, 6649, 6651, 6653, 6655, 6657, 6659, 6661, 6663, 6665, + 6667, 6669, 6671, 6673, 6675, 6677, 6679, 6681, 6683, 6685, 6687, 6689, + 6691, 6693, 6695, 6697, 6699, 6701, 6703, 6705, 6707, 6709, 6711, 6713, + 6715, 6717, 6719, 6721, 6723, 6725, 6727, 6729, 6731, 6733, 6735, 6737, + 6739, 6741, 6743, 6745, 6747, 6749, 6751, 6753, 6755, 6757, 6759, 6761, + 6763, 6765, 6767, 6769, 6771, 6773, 6775, 6777, 6779, 6781, 6783, 6785, + 6787, 6789, 6791, 6793, 6795, 6797, 6799, 6801, 6803, 6805, 6663, 6807, + 6809, 6811, 6813, 6815, 6817, 6819, 6821, 6823, 6825, 6827, 6829, 6831, + 6833, 6835, 6837, 6839, 6841, 6843, 6845, 6847, 6849, 6851, 6853, 6855, + 6857, 6859, 6861, 6863, 6865, 6867, 6869, 6871, 6873, 6875, 6877, 6879, + 6881, 6883, 6885, 6887, 6889, 6891, 6893, 6895, 6897, 6899, 6901, 6903, + 6905, 6907, 6909, 6911, 6913, 6915, 6917, 6919, 6921, 6923, 6925, 6927, + 6929, 6931, 6933, 6935, 6937, 6939, 6941, 6843, 6943, 6945, 6947, 6949, + 6951, 6953, 6955, 6957, 6811, 6959, 6961, 6963, 6965, 6967, 6969, 6971, + 6973, 6975, 6977, 6979, 6981, 6983, 6985, 6987, 6989, 6991, 6993, 6995, + 6997, 6663, 6999, 7001, 7003, 7005, 7007, 7009, 7011, 7013, 7015, 7017, + 7019, 7021, 7023, 7025, 7027, 7029, 7031, 7033, 7035, 7037, 7039, 7041, + 7043, 7045, 7047, 7049, 7051, 6815, 7053, 7055, 7057, 7059, 7061, 7063, + 7065, 7067, 7069, 7071, 7073, 7075, 7077, 7079, 7081, 7083, 7085, 7087, + 7089, 7091, 7093, 7095, 7097, 7099, 7101, 7103, 7105, 7107, 7109, 7111, + 7113, 7115, 7117, 7119, 7121, 7123, 7125, 7127, 7129, 7131, 7133, 7135, + 7137, 7139, 7141, 7143, 7145, 7147, 7149, 7151, 0, 0, 7153, 0, 7155, 0, + 0, 7157, 7159, 7161, 7163, 7165, 7167, 7169, 7171, 7173, 7175, 0, 7177, + 0, 7179, 0, 0, 7181, 7183, 0, 0, 0, 7185, 7187, 7189, 7191, 7193, 7195, + 7197, 7199, 7201, 7203, 7205, 7207, 7209, 7211, 7213, 7215, 7217, 7219, + 7221, 7223, 7225, 7227, 7229, 7231, 7233, 7235, 7237, 7239, 7241, 7243, + 7245, 7247, 7249, 7251, 7253, 7255, 7257, 7259, 7261, 7263, 7265, 7267, + 7269, 7271, 7273, 6921, 7275, 7277, 7279, 7281, 7283, 7285, 7285, 7287, + 7289, 7291, 7293, 7295, 7297, 7299, 7301, 7181, 7303, 7305, 7307, 7309, + 7311, 7313, 0, 0, 7315, 7317, 7319, 7321, 7323, 7325, 7327, 7329, 7209, + 7331, 7333, 7335, 7153, 7337, 7339, 7341, 7343, 7345, 7347, 7349, 7351, + 7353, 7355, 7357, 7359, 7227, 7361, 7229, 7363, 7365, 7367, 7369, 7371, + 7155, 6705, 7373, 7375, 7377, 6845, 7019, 7379, 7381, 7243, 7383, 7245, + 7385, 7387, 7389, 7159, 7391, 7393, 7395, 7397, 7399, 7161, 7401, 7403, + 7405, 7407, 7409, 7411, 7273, 7413, 7415, 6921, 7417, 7281, 7419, 7421, + 7423, 7425, 7427, 7291, 7429, 7179, 7431, 7293, 6807, 7433, 7295, 7435, + 7299, 7437, 7439, 7441, 7443, 7445, 7303, 7171, 7447, 7305, 7449, 7307, + 7451, 6639, 7453, 7455, 7457, 7459, 7461, 7463, 7465, 7467, 7469, 7471, + 7473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7475, 7478, 7481, 7484, + 7488, 7492, 7495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7498, 7501, 7504, + 7507, 7510, 0, 0, 0, 0, 0, 7513, 0, 7516, 7519, 7521, 7523, 7525, 7527, + 7529, 7531, 7533, 7535, 7537, 7539, 7542, 7545, 7548, 7551, 7554, 7557, + 7560, 7563, 7566, 7569, 7572, 7575, 0, 7578, 7581, 7584, 7587, 7590, 0, + 7593, 0, 7596, 7599, 0, 7602, 7605, 0, 7608, 7611, 7614, 7617, 7620, + 7623, 7626, 7629, 7632, 7635, 7638, 7640, 7642, 7644, 7646, 7648, 7650, + 7652, 7654, 7656, 7658, 7660, 7662, 7664, 7666, 7668, 7670, 7672, 7674, + 7676, 7678, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, + 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, + 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, + 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, + 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, + 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, + 7820, 7822, 7824, 7826, 7828, 7830, 7832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, - 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, - 7881, 7884, 7887, 7890, 7893, 7896, 7899, 7902, 7905, 7908, 7911, 7914, - 7917, 7920, 7923, 7926, 7929, 7932, 7934, 7936, 7938, 7940, 7943, 7946, - 7923, 7949, 7952, 7955, 7958, 7961, 7964, 7967, 7970, 7973, 7976, 7979, - 7982, 7985, 7988, 7991, 7994, 7997, 8000, 8003, 8006, 8009, 8012, 8015, - 8018, 8021, 8024, 8027, 8030, 8033, 8036, 8039, 8042, 8045, 8048, 8051, - 8054, 8057, 8060, 8063, 8066, 8069, 8072, 8075, 8078, 8081, 8084, 8087, - 8090, 8093, 8096, 8099, 8102, 8105, 8108, 8111, 8114, 8117, 8120, 8123, - 8126, 8129, 8132, 8135, 8138, 8141, 8144, 8147, 8150, 8153, 8156, 8159, - 8162, 8165, 8168, 8171, 8174, 8177, 8180, 8183, 8186, 8189, 8192, 8195, - 8198, 8201, 8204, 8207, 8210, 8213, 8216, 8219, 8223, 8227, 8231, 8235, - 8239, 8243, 8246, 8249, 8252, 7926, 8255, 8258, 8261, 8264, 8267, 8270, - 8273, 8276, 8279, 8282, 8285, 8288, 8291, 8294, 8297, 8300, 8303, 8306, - 8309, 8312, 8315, 8318, 8321, 8324, 8327, 8330, 8333, 8336, 8339, 8342, - 8345, 8348, 8351, 8354, 8357, 8360, 8363, 8366, 8369, 8372, 8375, 8378, - 8381, 8384, 8387, 8390, 8393, 8396, 8399, 8402, 8405, 8408, 8411, 8414, - 8417, 8420, 8423, 8426, 8429, 8432, 8435, 8438, 8441, 8444, 8447, 8450, - 8453, 8456, 8459, 8462, 8465, 8468, 8471, 8474, 8477, 8480, 8483, 8486, - 8489, 8492, 8495, 8498, 8501, 8504, 8507, 8510, 8513, 8516, 8519, 8522, - 8525, 8528, 8531, 8534, 8537, 8540, 8543, 8546, 8549, 8552, 8555, 8558, - 8561, 8564, 8567, 8570, 8573, 8576, 8579, 8582, 8585, 8588, 8591, 8594, - 8597, 8600, 8603, 8606, 8609, 8612, 8615, 8618, 8621, 8624, 8627, 8630, - 8633, 8636, 8639, 8642, 8645, 8648, 8651, 8654, 8657, 8660, 8663, 8666, - 8670, 8674, 8678, 8681, 8684, 8687, 8690, 8693, 8696, 8699, 8702, 8705, - 8708, 8711, 8714, 8717, 8720, 8723, 8726, 8729, 8732, 8735, 8738, 8741, - 8744, 8747, 8750, 8753, 8756, 8759, 8762, 8765, 8768, 8771, 8774, 8777, - 8780, 8783, 8786, 8789, 8792, 8795, 8798, 8801, 8804, 8807, 8810, 8813, - 8816, 8819, 8822, 8825, 8828, 8831, 8834, 8837, 8840, 8843, 8846, 8849, - 8852, 8855, 8858, 8861, 8864, 8867, 8870, 8873, 8876, 8879, 8882, 8885, - 8888, 8891, 8894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8897, 8901, 8905, 8909, 8913, 8917, 8921, 8925, 8929, 8933, 8937, 8941, - 8945, 8949, 8953, 8957, 8961, 8965, 8969, 8973, 8977, 8981, 8985, 8989, - 8993, 8997, 9001, 9005, 9009, 9013, 9017, 9021, 9025, 9029, 9033, 9037, - 9041, 9045, 9049, 9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, - 9089, 9093, 9097, 9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, - 9137, 9141, 9145, 9149, 0, 0, 9153, 9157, 9161, 9165, 9169, 9173, 9177, - 9181, 9185, 9189, 9193, 9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, - 9229, 9233, 9237, 9241, 9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, - 9277, 9281, 9285, 9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, - 9325, 9329, 9333, 9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 0, 0, + 7834, 7836, 7838, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, + 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, + 7883, 7886, 7889, 7892, 7895, 7898, 7901, 7904, 7907, 7910, 7913, 7916, + 7919, 7922, 7925, 7928, 7931, 7934, 7936, 7938, 7940, 7942, 7945, 7948, + 7925, 7951, 7954, 7957, 7960, 7963, 7966, 7969, 7972, 7975, 7978, 7981, + 7984, 7987, 7990, 7993, 7996, 7999, 8002, 8005, 8008, 8011, 8014, 8017, + 8020, 8023, 8026, 8029, 8032, 8035, 8038, 8041, 8044, 8047, 8050, 8053, + 8056, 8059, 8062, 8065, 8068, 8071, 8074, 8077, 8080, 8083, 8086, 8089, + 8092, 8095, 8098, 8101, 8104, 8107, 8110, 8113, 8116, 8119, 8122, 8125, + 8128, 8131, 8134, 8137, 8140, 8143, 8146, 8149, 8152, 8155, 8158, 8161, + 8164, 8167, 8170, 8173, 8176, 8179, 8182, 8185, 8188, 8191, 8194, 8197, + 8200, 8203, 8206, 8209, 8212, 8215, 8218, 8221, 8225, 8229, 8233, 8237, + 8241, 8245, 8248, 8251, 8254, 7928, 8257, 8260, 8263, 8266, 8269, 8272, + 8275, 8278, 8281, 8284, 8287, 8290, 8293, 8296, 8299, 8302, 8305, 8308, + 8311, 8314, 8317, 8320, 8323, 8326, 8329, 8332, 8335, 8338, 8341, 8344, + 8347, 8350, 8353, 8356, 8359, 8362, 8365, 8368, 8371, 8374, 8377, 8380, + 8383, 8386, 8389, 8392, 8395, 8398, 8401, 8404, 8407, 8410, 8413, 8416, + 8419, 8422, 8425, 8428, 8431, 8434, 8437, 8440, 8443, 8446, 8449, 8452, + 8455, 8458, 8461, 8464, 8467, 8470, 8473, 8476, 8479, 8482, 8485, 8488, + 8491, 8494, 8497, 8500, 8503, 8506, 8509, 8512, 8515, 8518, 8521, 8524, + 8527, 8530, 8533, 8536, 8539, 8542, 8545, 8548, 8551, 8554, 8557, 8560, + 8563, 8566, 8569, 8572, 8575, 8578, 8581, 8584, 8587, 8590, 8593, 8596, + 8599, 8602, 8605, 8608, 8611, 8614, 8617, 8620, 8623, 8626, 8629, 8632, + 8635, 8638, 8641, 8644, 8647, 8650, 8653, 8656, 8659, 8662, 8665, 8668, + 8672, 8676, 8680, 8683, 8686, 8689, 8692, 8695, 8698, 8701, 8704, 8707, + 8710, 8713, 8716, 8719, 8722, 8725, 8728, 8731, 8734, 8737, 8740, 8743, + 8746, 8749, 8752, 8755, 8758, 8761, 8764, 8767, 8770, 8773, 8776, 8779, + 8782, 8785, 8788, 8791, 8794, 8797, 8800, 8803, 8806, 8809, 8812, 8815, + 8818, 8821, 8824, 8827, 8830, 8833, 8836, 8839, 8842, 8845, 8848, 8851, + 8854, 8857, 8860, 8863, 8866, 8869, 8872, 8875, 8878, 8881, 8884, 8887, + 8890, 8893, 8896, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8899, 8903, 8907, 8911, 8915, 8919, 8923, 8927, 8931, 8935, 8939, 8943, + 8947, 8951, 8955, 8959, 8963, 8967, 8971, 8975, 8979, 8983, 8987, 8991, + 8995, 8999, 9003, 9007, 9011, 9015, 9019, 9023, 9027, 9031, 9035, 9039, + 9043, 9047, 9051, 9055, 9059, 9063, 9067, 9071, 9075, 9079, 9083, 9087, + 9091, 9095, 9099, 9103, 9107, 9111, 9115, 9119, 9123, 9127, 9131, 9135, + 9139, 9143, 9147, 9151, 0, 0, 9155, 9159, 9163, 9167, 9171, 9175, 9179, + 9183, 9187, 9191, 9195, 9199, 9203, 9207, 9211, 9215, 9219, 9223, 9227, + 9231, 9235, 9239, 9243, 9247, 9251, 9255, 9259, 9263, 9267, 9271, 9275, + 9279, 9283, 9287, 9291, 9295, 9299, 9303, 9307, 9311, 9315, 9319, 9323, + 9327, 9331, 9335, 9339, 9343, 9347, 9351, 9355, 9359, 9363, 9367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9369, 9373, 9377, 9382, 9387, - 9392, 9397, 9402, 9407, 9412, 9416, 9435, 9444, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9449, 9451, 9453, 9455, 9457, 9459, - 9461, 9463, 9465, 9467, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9469, 9471, 9473, 9475, 9475, 9477, 9479, 9481, 9483, - 9485, 9487, 9489, 9491, 9493, 9495, 9497, 9499, 9501, 9503, 9505, 9507, - 0, 0, 9509, 9511, 9513, 9513, 9513, 9513, 9515, 9515, 9515, 9517, 9519, - 9521, 0, 9523, 9525, 9527, 9529, 9531, 9533, 9535, 9537, 9539, 9541, - 9543, 9545, 9547, 9549, 9551, 9553, 9555, 9557, 9559, 0, 9561, 9563, - 9565, 9567, 0, 0, 0, 0, 9569, 9572, 9575, 0, 9578, 0, 9581, 9584, 9587, - 9590, 9593, 9596, 9599, 9602, 9605, 9608, 9611, 9613, 9615, 9617, 9619, - 9621, 9623, 9625, 9627, 9629, 9631, 9633, 9635, 9637, 9639, 9641, 9643, - 9645, 9647, 9649, 9651, 9653, 9655, 9657, 9659, 9661, 9663, 9665, 9667, - 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685, 9687, 9689, 9691, - 9693, 9695, 9697, 9699, 9701, 9703, 9705, 9707, 9709, 9711, 9713, 9715, - 9717, 9719, 9721, 9723, 9725, 9727, 9729, 9731, 9733, 9735, 9737, 9739, - 9741, 9743, 9745, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763, - 9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787, - 9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811, - 9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835, - 9837, 9839, 9841, 9843, 9845, 9848, 9851, 9854, 9857, 9860, 9863, 9866, - 0, 0, 0, 0, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883, 9885, 9887, - 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907, 9909, 9911, - 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931, 9933, 9935, - 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955, 9957, 9959, - 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979, 9981, 9983, - 9985, 9987, 9989, 9991, 9993, 9995, 9997, 9999, 10001, 10003, 10005, - 10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025, - 10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045, - 10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065, - 10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085, - 10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105, - 10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125, - 10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145, - 10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165, - 10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185, - 10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205, - 10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225, - 10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245, - 10247, 0, 0, 0, 10249, 10251, 10253, 10255, 10257, 10259, 0, 0, 10261, - 10263, 10265, 10267, 10269, 10271, 0, 0, 10273, 10275, 10277, 10279, - 10281, 10283, 0, 0, 10285, 10287, 10289, 0, 0, 0, 10291, 10293, 10295, - 10297, 10299, 10301, 10303, 0, 10305, 10307, 10309, 10311, 10313, 10315, - 10317, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9371, 9375, 9379, 9384, 9389, + 9394, 9399, 9404, 9409, 9414, 9418, 9437, 9446, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9451, 9453, 9455, 9457, 9459, 9461, + 9463, 9465, 9467, 9469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9471, 9473, 9475, 9477, 9477, 9479, 9481, 9483, 9485, + 9487, 9489, 9491, 9493, 9495, 9497, 9499, 9501, 9503, 9505, 9507, 9509, + 0, 0, 9511, 9513, 9515, 9515, 9515, 9515, 9517, 9517, 9517, 9519, 9521, + 9523, 0, 9525, 9527, 9529, 9531, 9533, 9535, 9537, 9539, 9541, 9543, + 9545, 9547, 9549, 9551, 9553, 9555, 9557, 9559, 9561, 0, 9563, 9565, + 9567, 9569, 0, 0, 0, 0, 9571, 9574, 9577, 0, 9580, 0, 9583, 9586, 9589, + 9592, 9595, 9598, 9601, 9604, 9607, 9610, 9613, 9615, 9617, 9619, 9621, + 9623, 9625, 9627, 9629, 9631, 9633, 9635, 9637, 9639, 9641, 9643, 9645, + 9647, 9649, 9651, 9653, 9655, 9657, 9659, 9661, 9663, 9665, 9667, 9669, + 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685, 9687, 9689, 9691, 9693, + 9695, 9697, 9699, 9701, 9703, 9705, 9707, 9709, 9711, 9713, 9715, 9717, + 9719, 9721, 9723, 9725, 9727, 9729, 9731, 9733, 9735, 9737, 9739, 9741, + 9743, 9745, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763, 9765, + 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787, 9789, + 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811, 9813, + 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835, 9837, + 9839, 9841, 9843, 9845, 9847, 9850, 9853, 9856, 9859, 9862, 9865, 9868, + 0, 0, 0, 0, 9871, 9873, 9875, 9877, 9879, 9881, 9883, 9885, 9887, 9889, + 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907, 9909, 9911, 9913, + 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931, 9933, 9935, 9937, + 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955, 9957, 9959, 9961, + 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979, 9981, 9983, 9985, + 9987, 9989, 9991, 9993, 9995, 9997, 9999, 10001, 10003, 10005, 10007, + 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025, 10027, + 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045, 10047, + 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065, 10067, + 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085, 10087, + 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105, 10107, + 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125, 10127, + 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145, 10147, + 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165, 10167, + 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185, 10187, + 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205, 10207, + 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225, 10227, + 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245, 10247, + 10249, 0, 0, 0, 10251, 10253, 10255, 10257, 10259, 10261, 0, 0, 10263, + 10265, 10267, 10269, 10271, 10273, 0, 0, 10275, 10277, 10279, 10281, + 10283, 10285, 0, 0, 10287, 10289, 10291, 0, 0, 0, 10293, 10295, 10297, + 10299, 10301, 10303, 10305, 0, 10307, 10309, 10311, 10313, 10315, 10317, + 10319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10319, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10321, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 10322, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 10325, 10327, 10329, 10331, 10333, 0, 10335, 10337, - 10339, 10341, 10343, 10345, 10347, 10349, 10351, 10353, 10355, 10357, - 10359, 10361, 10363, 10365, 10367, 10369, 10371, 10373, 10375, 10377, - 10379, 10381, 10383, 10385, 10387, 10389, 10391, 10393, 10395, 10397, - 10399, 10401, 10403, 10405, 10407, 10409, 10411, 10413, 10415, 10417, 0, - 10419, 10421, 10423, 10425, 10427, 10429, 10431, 10433, 10435, 0, 0, 0, + 10324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 10327, 10329, 10331, 10333, 10335, 0, 10337, 10339, + 10341, 10343, 10345, 10347, 10349, 10351, 10353, 10355, 10357, 10359, + 10361, 10363, 10365, 10367, 10369, 10371, 10373, 10375, 10377, 10379, + 10381, 10383, 10385, 10387, 10389, 10391, 10393, 10395, 10397, 10399, + 10401, 10403, 10405, 10407, 10409, 10411, 10413, 10415, 10417, 10419, 0, + 10421, 10423, 10425, 10427, 10429, 10431, 10433, 10435, 10437, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10437, 0, - 10440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10443, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10439, 0, + 10442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10445, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 10446, 10449, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10448, 10451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10452, 10455, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10454, 10457, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 10458, 0, 10461, 0, 0, 0, 0, 0, 0, 0, 0, 10464, 0, 0, - 10467, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10460, 0, 10463, 0, 0, 0, 0, 0, 0, 0, 0, 10466, 0, 0, + 10469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 10470, 0, 10473, 10476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10472, 0, 10475, 10478, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 10479, 10482, 0, 10485, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10481, 10484, 0, 10487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10488, 10491, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 10494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10497, 10500, 10503, 10506, 10509, - 10512, 10515, 10518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10499, 10502, 10505, 10508, 10511, + 10514, 10517, 10520, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -5445,234 +5440,234 @@ static const unsigned short decomp_index2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 10521, 10524, 10527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 10523, 10526, 10529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 10530, 3253, 3192, 3289, 3257, 3259, 10532, 3212, 3218, 10534, 10536, - 3220, 3261, 3224, 10538, 3229, 3231, 3233, 10540, 10542, 10544, 10546, - 10548, 10550, 10552, 3245, 10554, 10556, 10558, 10560, 10562, 10564, - 10566, 10568, 10570, 10572, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10532, 3253, 3192, 3289, 3257, 3259, 10534, 3212, 3218, 10536, 10538, + 3220, 3261, 3224, 10540, 3229, 3231, 3233, 10542, 10544, 10546, 10548, + 10550, 10552, 10554, 3245, 10556, 10558, 10560, 10562, 10564, 10566, + 10568, 10570, 10572, 10574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10574, 10577, 10580, 10583, 10586, - 10589, 10592, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10576, 10579, 10582, 10585, 10588, + 10591, 10594, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10595, 10598, - 10601, 10604, 10607, 10610, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10597, 10600, + 10603, 10606, 10609, 10612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 10530, 3253, 3192, 3289, 3257, 3259, 10532, 3212, 3218, 10534, 10536, - 3220, 3261, 3224, 10538, 3229, 3231, 3233, 10540, 10542, 10544, 10546, - 10548, 10550, 10552, 3245, 10613, 10615, 10617, 3291, 3255, 10619, 3210, - 3214, 3273, 3293, 10621, 3222, 10623, 10625, 3263, 10627, 10629, 10631, - 10633, 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10530, 3253, - 3192, 3289, 3257, 3259, 10532, 3212, 3218, 10534, 10536, 3220, 3261, - 3224, 10538, 3229, 3231, 3233, 10540, 10542, 10544, 10546, 10548, 10550, - 10552, 3245, 10613, 10615, 10617, 3291, 3255, 10619, 3210, 0, 3273, 3293, - 10621, 3222, 10623, 10625, 3263, 10627, 10629, 10631, 10633, 10635, - 10637, 10639, 10641, 10643, 10645, 10647, 10530, 3253, 3192, 3289, 3257, - 3259, 10532, 3212, 3218, 10534, 10536, 3220, 3261, 3224, 10538, 3229, - 3231, 3233, 10540, 10542, 10544, 10546, 10548, 10550, 10552, 3245, 10613, - 10615, 10617, 3291, 3255, 10619, 3210, 3214, 3273, 3293, 10621, 3222, - 10623, 10625, 3263, 10627, 10629, 10631, 10633, 10635, 10637, 10639, - 10641, 10643, 10645, 10647, 10530, 0, 3192, 3289, 0, 0, 10532, 0, 0, - 10534, 10536, 0, 0, 3224, 10538, 3229, 3231, 0, 10540, 10542, 10544, - 10546, 10548, 10550, 10552, 3245, 10613, 10615, 10617, 3291, 0, 10619, 0, - 3214, 3273, 3293, 10621, 3222, 10623, 10625, 0, 10627, 10629, 10631, - 10633, 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10530, 3253, - 3192, 3289, 3257, 3259, 10532, 3212, 3218, 10534, 10536, 3220, 3261, - 3224, 10538, 3229, 3231, 3233, 10540, 10542, 10544, 10546, 10548, 10550, - 10552, 3245, 10613, 10615, 10617, 3291, 3255, 10619, 3210, 3214, 3273, - 3293, 10621, 3222, 10623, 10625, 3263, 10627, 10629, 10631, 10633, 10635, - 10637, 10639, 10641, 10643, 10645, 10647, 10530, 3253, 0, 3289, 3257, - 3259, 10532, 0, 0, 10534, 10536, 3220, 3261, 3224, 10538, 3229, 3231, 0, - 10540, 10542, 10544, 10546, 10548, 10550, 10552, 0, 10613, 10615, 10617, - 3291, 3255, 10619, 3210, 3214, 3273, 3293, 10621, 3222, 10623, 10625, - 3263, 10627, 10629, 10631, 10633, 10635, 10637, 10639, 10641, 10643, - 10645, 10647, 10530, 3253, 0, 3289, 3257, 3259, 10532, 0, 3218, 10534, - 10536, 3220, 3261, 0, 10538, 0, 0, 0, 10540, 10542, 10544, 10546, 10548, - 10550, 10552, 0, 10613, 10615, 10617, 3291, 3255, 10619, 3210, 3214, - 3273, 3293, 10621, 3222, 10623, 10625, 3263, 10627, 10629, 10631, 10633, - 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10530, 3253, 3192, 3289, - 3257, 3259, 10532, 3212, 3218, 10534, 10536, 3220, 3261, 3224, 10538, - 3229, 3231, 3233, 10540, 10542, 10544, 10546, 10548, 10550, 10552, 3245, - 10613, 10615, 10617, 3291, 3255, 10619, 3210, 3214, 3273, 3293, 10621, - 3222, 10623, 10625, 3263, 10627, 10629, 10631, 10633, 10635, 10637, - 10639, 10641, 10643, 10645, 10647, 10530, 3253, 3192, 3289, 3257, 3259, - 10532, 3212, 3218, 10534, 10536, 3220, 3261, 3224, 10538, 3229, 3231, - 3233, 10540, 10542, 10544, 10546, 10548, 10550, 10552, 3245, 10613, - 10615, 10617, 3291, 3255, 10619, 3210, 3214, 3273, 3293, 10621, 3222, - 10623, 10625, 3263, 10627, 10629, 10631, 10633, 10635, 10637, 10639, - 10641, 10643, 10645, 10647, 10530, 3253, 3192, 3289, 3257, 3259, 10532, - 3212, 3218, 10534, 10536, 3220, 3261, 3224, 10538, 3229, 3231, 3233, - 10540, 10542, 10544, 10546, 10548, 10550, 10552, 3245, 10613, 10615, - 10617, 3291, 3255, 10619, 3210, 3214, 3273, 3293, 10621, 3222, 10623, - 10625, 3263, 10627, 10629, 10631, 10633, 10635, 10637, 10639, 10641, - 10643, 10645, 10647, 10530, 3253, 3192, 3289, 3257, 3259, 10532, 3212, - 3218, 10534, 10536, 3220, 3261, 3224, 10538, 3229, 3231, 3233, 10540, - 10542, 10544, 10546, 10548, 10550, 10552, 3245, 10613, 10615, 10617, - 3291, 3255, 10619, 3210, 3214, 3273, 3293, 10621, 3222, 10623, 10625, - 3263, 10627, 10629, 10631, 10633, 10635, 10637, 10639, 10641, 10643, - 10645, 10647, 10530, 3253, 3192, 3289, 3257, 3259, 10532, 3212, 3218, - 10534, 10536, 3220, 3261, 3224, 10538, 3229, 3231, 3233, 10540, 10542, - 10544, 10546, 10548, 10550, 10552, 3245, 10613, 10615, 10617, 3291, 3255, - 10619, 3210, 3214, 3273, 3293, 10621, 3222, 10623, 10625, 3263, 10627, - 10629, 10631, 10633, 10635, 10637, 10639, 10641, 10643, 10645, 10647, - 10530, 3253, 3192, 3289, 3257, 3259, 10532, 3212, 3218, 10534, 10536, - 3220, 3261, 3224, 10538, 3229, 3231, 3233, 10540, 10542, 10544, 10546, - 10548, 10550, 10552, 3245, 10613, 10615, 10617, 3291, 3255, 10619, 3210, - 3214, 3273, 3293, 10621, 3222, 10623, 10625, 3263, 10627, 10629, 10631, - 10633, 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10649, 10651, 0, - 0, 10653, 10655, 3283, 10657, 10659, 10661, 10663, 10665, 10667, 10669, - 10671, 10673, 10675, 10677, 10679, 3285, 10681, 10683, 10685, 10687, - 10689, 10691, 10693, 10695, 10697, 10699, 10701, 10703, 3281, 10705, - 10707, 10709, 10711, 10713, 10715, 10717, 10719, 10721, 10723, 10725, - 10727, 3279, 10729, 10731, 10733, 10735, 10737, 10739, 10741, 10743, - 10745, 10747, 10749, 10751, 10753, 10755, 10757, 10759, 10653, 10655, - 3283, 10657, 10659, 10661, 10663, 10665, 10667, 10669, 10671, 10673, - 10675, 10677, 10679, 3285, 10681, 10683, 10685, 10687, 10689, 10691, - 10693, 10695, 10697, 10699, 10701, 10703, 3281, 10705, 10707, 10709, - 10711, 10713, 10715, 10717, 10719, 10721, 10723, 10725, 10727, 3279, - 10729, 10731, 10733, 10735, 10737, 10739, 10741, 10743, 10745, 10747, - 10749, 10751, 10753, 10755, 10757, 10759, 10653, 10655, 3283, 10657, - 10659, 10661, 10663, 10665, 10667, 10669, 10671, 10673, 10675, 10677, - 10679, 3285, 10681, 10683, 10685, 10687, 10689, 10691, 10693, 10695, - 10697, 10699, 10701, 10703, 3281, 10705, 10707, 10709, 10711, 10713, - 10715, 10717, 10719, 10721, 10723, 10725, 10727, 3279, 10729, 10731, - 10733, 10735, 10737, 10739, 10741, 10743, 10745, 10747, 10749, 10751, - 10753, 10755, 10757, 10759, 10653, 10655, 3283, 10657, 10659, 10661, - 10663, 10665, 10667, 10669, 10671, 10673, 10675, 10677, 10679, 3285, - 10681, 10683, 10685, 10687, 10689, 10691, 10693, 10695, 10697, 10699, - 10701, 10703, 3281, 10705, 10707, 10709, 10711, 10713, 10715, 10717, - 10719, 10721, 10723, 10725, 10727, 3279, 10729, 10731, 10733, 10735, - 10737, 10739, 10741, 10743, 10745, 10747, 10749, 10751, 10753, 10755, - 10757, 10759, 10653, 10655, 3283, 10657, 10659, 10661, 10663, 10665, - 10667, 10669, 10671, 10673, 10675, 10677, 10679, 3285, 10681, 10683, - 10685, 10687, 10689, 10691, 10693, 10695, 10697, 10699, 10701, 10703, - 3281, 10705, 10707, 10709, 10711, 10713, 10715, 10717, 10719, 10721, - 10723, 10725, 10727, 3279, 10729, 10731, 10733, 10735, 10737, 10739, - 10741, 10743, 10745, 10747, 10749, 10751, 10753, 10755, 10757, 10759, - 10761, 10763, 0, 0, 10554, 10556, 10558, 10560, 10562, 10564, 10566, - 10568, 10570, 10572, 10554, 10556, 10558, 10560, 10562, 10564, 10566, - 10568, 10570, 10572, 10554, 10556, 10558, 10560, 10562, 10564, 10566, - 10568, 10570, 10572, 10554, 10556, 10558, 10560, 10562, 10564, 10566, - 10568, 10570, 10572, 10554, 10556, 10558, 10560, 10562, 10564, 10566, - 10568, 10570, 10572, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 10765, 10767, 10769, 10771, 10773, 10775, 10777, - 10779, 10781, 10783, 10785, 10787, 10789, 10791, 10793, 10795, 10797, - 10799, 10801, 10803, 10805, 10807, 10809, 10811, 10813, 10815, 10817, - 10819, 10821, 10823, 10825, 10827, 10829, 10831, 10833, 10835, 10837, - 10839, 10841, 10843, 10845, 10847, 10849, 10851, 10853, 10855, 10857, - 10859, 10861, 10863, 10865, 10867, 10869, 10871, 10873, 10875, 10877, - 10879, 10881, 10883, 10885, 10887, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 10889, 10891, 10893, 10895, 0, 10897, 10899, 10901, 10903, - 10905, 10907, 10909, 10911, 10913, 10915, 10917, 10919, 10921, 10923, - 10925, 10927, 10929, 10931, 10933, 10935, 10937, 10939, 10941, 10943, - 10945, 10947, 10949, 0, 10891, 10893, 0, 10951, 0, 0, 10901, 0, 10905, - 10907, 10909, 10911, 10913, 10915, 10917, 10919, 10921, 10923, 0, 10927, - 10929, 10931, 10933, 0, 10937, 0, 10941, 0, 0, 0, 0, 0, 0, 10893, 0, 0, - 0, 0, 10901, 0, 10905, 0, 10909, 0, 10913, 10915, 10917, 0, 10921, 10923, - 0, 10927, 0, 0, 10933, 0, 10937, 0, 10941, 0, 10945, 0, 10949, 0, 10891, - 10893, 0, 10951, 0, 0, 10901, 10903, 10905, 10907, 0, 10911, 10913, - 10915, 10917, 10919, 10921, 10923, 0, 10927, 10929, 10931, 10933, 0, - 10937, 10939, 10941, 10943, 0, 10947, 0, 10889, 10891, 10893, 10895, - 10951, 10897, 10899, 10901, 10903, 10905, 0, 10909, 10911, 10913, 10915, - 10917, 10919, 10921, 10923, 10925, 10927, 10929, 10931, 10933, 10935, - 10937, 10939, 10941, 0, 0, 0, 0, 0, 10891, 10893, 10895, 0, 10897, 10899, - 10901, 10903, 10905, 0, 10909, 10911, 10913, 10915, 10917, 10919, 10921, - 10923, 10925, 10927, 10929, 10931, 10933, 10935, 10937, 10939, 10941, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10953, 10956, - 10959, 10962, 10965, 10968, 10971, 10974, 10977, 10980, 10983, 0, 0, 0, - 0, 0, 10986, 10990, 10994, 10998, 11002, 11006, 11010, 11014, 11018, - 11022, 11026, 11030, 11034, 11038, 11042, 11046, 11050, 11054, 11058, - 11062, 11066, 11070, 11074, 11078, 11082, 11086, 11090, 3926, 3956, - 11094, 11097, 0, 11100, 11102, 11104, 11106, 11108, 11110, 11112, 11114, - 11116, 11118, 11120, 11122, 11124, 11126, 11128, 11130, 11132, 11134, - 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150, 11152, 6348, - 11155, 11158, 11161, 11165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11168, 11171, 11174, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 11177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11180, - 11183, 11186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11188, 11190, 11192, - 11194, 11196, 11198, 11200, 11202, 11204, 11206, 11208, 11210, 11212, - 11214, 11216, 11218, 11220, 11222, 11224, 11226, 11228, 11230, 11232, - 11234, 11236, 11238, 11240, 11242, 11244, 11246, 11248, 11250, 11252, - 11254, 11256, 11258, 11260, 11262, 11264, 11266, 11268, 11270, 11272, - 11274, 0, 0, 0, 0, 11276, 11280, 11284, 11288, 11292, 11296, 11300, - 11304, 11308, 0, 0, 0, 0, 0, 0, 0, 11312, 11314, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 10554, 10556, 10558, 10560, 10562, 10564, 10566, 10568, - 10570, 10572, 0, 0, 0, 0, 0, 0, 11316, 11318, 11320, 11322, 11324, 7195, - 11326, 11328, 11330, 11332, 7197, 11334, 11336, 11338, 7199, 11340, - 11342, 11344, 11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, - 11362, 7315, 11364, 11366, 11368, 11370, 11372, 11374, 11376, 11378, - 11380, 7325, 7201, 7203, 7327, 11382, 11384, 6817, 11386, 7205, 11388, - 11390, 11392, 11394, 11394, 11394, 11396, 11398, 11400, 11402, 11404, - 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, - 11426, 11428, 11430, 11430, 7331, 11432, 11434, 11436, 11438, 7209, - 11440, 11442, 11444, 7123, 11446, 11448, 11450, 11452, 11454, 11456, - 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, - 11478, 11480, 11482, 11484, 11486, 11488, 11490, 11492, 11494, 11496, - 11496, 11498, 11500, 11502, 6809, 11504, 11506, 11508, 11510, 11512, - 11514, 11516, 11518, 7219, 11520, 11522, 11524, 11526, 11528, 11530, - 11532, 11534, 11536, 11538, 11540, 11542, 11544, 11546, 11548, 11550, - 11552, 11554, 11556, 11558, 11560, 6701, 11562, 11564, 11566, 11566, - 11568, 11570, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584, - 11586, 11588, 11590, 11592, 11594, 11596, 7221, 11598, 11600, 11602, - 11604, 7355, 11604, 11606, 7225, 11608, 11610, 11612, 11614, 7227, 6647, - 11616, 11618, 11620, 11622, 11624, 11626, 11628, 11630, 11632, 11634, - 11636, 11638, 11640, 11642, 11644, 11646, 11648, 11650, 11652, 11654, - 11656, 11658, 7229, 11660, 11662, 11664, 11666, 11668, 11670, 7233, - 11672, 11674, 11676, 11678, 11680, 11682, 11684, 11686, 6703, 7371, - 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 7235, 11704, - 11706, 11708, 11710, 7457, 11712, 11714, 11716, 11718, 11720, 11722, - 11724, 11726, 11728, 11730, 11732, 11734, 11736, 6843, 11738, 11740, - 11742, 11744, 11746, 11748, 11750, 11752, 11754, 11756, 11758, 7237, - 7017, 11760, 11762, 11764, 11766, 11768, 11770, 11772, 11774, 7379, - 11776, 11778, 11780, 11782, 11784, 11786, 11788, 11790, 7381, 11792, - 11794, 11796, 11798, 11800, 11802, 11804, 11806, 11808, 11810, 11812, - 11814, 7385, 11816, 11818, 11820, 11822, 11824, 11826, 11828, 11830, - 11832, 11834, 11836, 11836, 11838, 11840, 7389, 11842, 11844, 11846, - 11848, 11850, 11852, 11854, 6815, 11856, 11858, 11860, 11862, 11864, - 11866, 11868, 7401, 11870, 11872, 11874, 11876, 11878, 11880, 11880, - 7403, 7461, 11882, 11884, 11886, 11888, 11890, 6739, 7407, 11892, 11894, - 7259, 11896, 11898, 7167, 11900, 11902, 7267, 11904, 11906, 11908, 11910, - 11910, 11912, 11914, 11916, 11918, 11920, 11922, 11924, 11926, 11928, - 11930, 11932, 11934, 11936, 11938, 11940, 11942, 11944, 11946, 11948, - 11950, 11952, 11954, 11956, 11958, 11960, 11962, 11964, 7279, 11966, - 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982, 11984, 11986, - 11988, 11990, 11992, 11994, 11996, 11568, 11998, 12000, 12002, 12004, - 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 6851, 12022, - 12024, 12026, 12028, 12030, 12032, 7285, 12034, 12036, 12038, 12040, - 12042, 12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, - 12062, 12064, 12066, 12068, 12070, 12072, 6729, 12074, 12076, 12078, - 12080, 12082, 12084, 7421, 12086, 12088, 12090, 12092, 12094, 12096, - 12098, 12100, 12102, 12104, 12106, 12108, 12110, 12112, 12114, 12116, - 12118, 12120, 12122, 12124, 7431, 7433, 12126, 12128, 12130, 12132, - 12134, 12136, 12138, 12140, 12142, 12144, 12146, 12148, 12150, 7435, - 12152, 12154, 12156, 12158, 12160, 12162, 12164, 12166, 12168, 12170, - 12172, 12174, 12176, 12178, 12180, 12182, 12184, 12186, 12188, 12190, - 12192, 12194, 12196, 12198, 12200, 12202, 12204, 12206, 12208, 12210, - 7447, 7447, 12212, 12214, 12216, 12218, 12220, 12222, 12224, 12226, - 12228, 12230, 7449, 12232, 12234, 12236, 12238, 12240, 12242, 12244, - 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262, 12264, - 12266, 12268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10532, 3253, 3192, 3289, 3257, 3259, 10534, 3212, 3218, 10536, 10538, + 3220, 3261, 3224, 10540, 3229, 3231, 3233, 10542, 10544, 10546, 10548, + 10550, 10552, 10554, 3245, 10615, 10617, 10619, 3291, 3255, 10621, 3210, + 3214, 3273, 3293, 10623, 3222, 10625, 10627, 3263, 10629, 10631, 10633, + 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10649, 10532, 3253, + 3192, 3289, 3257, 3259, 10534, 3212, 3218, 10536, 10538, 3220, 3261, + 3224, 10540, 3229, 3231, 3233, 10542, 10544, 10546, 10548, 10550, 10552, + 10554, 3245, 10615, 10617, 10619, 3291, 3255, 10621, 3210, 0, 3273, 3293, + 10623, 3222, 10625, 10627, 3263, 10629, 10631, 10633, 10635, 10637, + 10639, 10641, 10643, 10645, 10647, 10649, 10532, 3253, 3192, 3289, 3257, + 3259, 10534, 3212, 3218, 10536, 10538, 3220, 3261, 3224, 10540, 3229, + 3231, 3233, 10542, 10544, 10546, 10548, 10550, 10552, 10554, 3245, 10615, + 10617, 10619, 3291, 3255, 10621, 3210, 3214, 3273, 3293, 10623, 3222, + 10625, 10627, 3263, 10629, 10631, 10633, 10635, 10637, 10639, 10641, + 10643, 10645, 10647, 10649, 10532, 0, 3192, 3289, 0, 0, 10534, 0, 0, + 10536, 10538, 0, 0, 3224, 10540, 3229, 3231, 0, 10542, 10544, 10546, + 10548, 10550, 10552, 10554, 3245, 10615, 10617, 10619, 3291, 0, 10621, 0, + 3214, 3273, 3293, 10623, 3222, 10625, 10627, 0, 10629, 10631, 10633, + 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10649, 10532, 3253, + 3192, 3289, 3257, 3259, 10534, 3212, 3218, 10536, 10538, 3220, 3261, + 3224, 10540, 3229, 3231, 3233, 10542, 10544, 10546, 10548, 10550, 10552, + 10554, 3245, 10615, 10617, 10619, 3291, 3255, 10621, 3210, 3214, 3273, + 3293, 10623, 3222, 10625, 10627, 3263, 10629, 10631, 10633, 10635, 10637, + 10639, 10641, 10643, 10645, 10647, 10649, 10532, 3253, 0, 3289, 3257, + 3259, 10534, 0, 0, 10536, 10538, 3220, 3261, 3224, 10540, 3229, 3231, 0, + 10542, 10544, 10546, 10548, 10550, 10552, 10554, 0, 10615, 10617, 10619, + 3291, 3255, 10621, 3210, 3214, 3273, 3293, 10623, 3222, 10625, 10627, + 3263, 10629, 10631, 10633, 10635, 10637, 10639, 10641, 10643, 10645, + 10647, 10649, 10532, 3253, 0, 3289, 3257, 3259, 10534, 0, 3218, 10536, + 10538, 3220, 3261, 0, 10540, 0, 0, 0, 10542, 10544, 10546, 10548, 10550, + 10552, 10554, 0, 10615, 10617, 10619, 3291, 3255, 10621, 3210, 3214, + 3273, 3293, 10623, 3222, 10625, 10627, 3263, 10629, 10631, 10633, 10635, + 10637, 10639, 10641, 10643, 10645, 10647, 10649, 10532, 3253, 3192, 3289, + 3257, 3259, 10534, 3212, 3218, 10536, 10538, 3220, 3261, 3224, 10540, + 3229, 3231, 3233, 10542, 10544, 10546, 10548, 10550, 10552, 10554, 3245, + 10615, 10617, 10619, 3291, 3255, 10621, 3210, 3214, 3273, 3293, 10623, + 3222, 10625, 10627, 3263, 10629, 10631, 10633, 10635, 10637, 10639, + 10641, 10643, 10645, 10647, 10649, 10532, 3253, 3192, 3289, 3257, 3259, + 10534, 3212, 3218, 10536, 10538, 3220, 3261, 3224, 10540, 3229, 3231, + 3233, 10542, 10544, 10546, 10548, 10550, 10552, 10554, 3245, 10615, + 10617, 10619, 3291, 3255, 10621, 3210, 3214, 3273, 3293, 10623, 3222, + 10625, 10627, 3263, 10629, 10631, 10633, 10635, 10637, 10639, 10641, + 10643, 10645, 10647, 10649, 10532, 3253, 3192, 3289, 3257, 3259, 10534, + 3212, 3218, 10536, 10538, 3220, 3261, 3224, 10540, 3229, 3231, 3233, + 10542, 10544, 10546, 10548, 10550, 10552, 10554, 3245, 10615, 10617, + 10619, 3291, 3255, 10621, 3210, 3214, 3273, 3293, 10623, 3222, 10625, + 10627, 3263, 10629, 10631, 10633, 10635, 10637, 10639, 10641, 10643, + 10645, 10647, 10649, 10532, 3253, 3192, 3289, 3257, 3259, 10534, 3212, + 3218, 10536, 10538, 3220, 3261, 3224, 10540, 3229, 3231, 3233, 10542, + 10544, 10546, 10548, 10550, 10552, 10554, 3245, 10615, 10617, 10619, + 3291, 3255, 10621, 3210, 3214, 3273, 3293, 10623, 3222, 10625, 10627, + 3263, 10629, 10631, 10633, 10635, 10637, 10639, 10641, 10643, 10645, + 10647, 10649, 10532, 3253, 3192, 3289, 3257, 3259, 10534, 3212, 3218, + 10536, 10538, 3220, 3261, 3224, 10540, 3229, 3231, 3233, 10542, 10544, + 10546, 10548, 10550, 10552, 10554, 3245, 10615, 10617, 10619, 3291, 3255, + 10621, 3210, 3214, 3273, 3293, 10623, 3222, 10625, 10627, 3263, 10629, + 10631, 10633, 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10649, + 10532, 3253, 3192, 3289, 3257, 3259, 10534, 3212, 3218, 10536, 10538, + 3220, 3261, 3224, 10540, 3229, 3231, 3233, 10542, 10544, 10546, 10548, + 10550, 10552, 10554, 3245, 10615, 10617, 10619, 3291, 3255, 10621, 3210, + 3214, 3273, 3293, 10623, 3222, 10625, 10627, 3263, 10629, 10631, 10633, + 10635, 10637, 10639, 10641, 10643, 10645, 10647, 10649, 10651, 10653, 0, + 0, 10655, 10657, 3283, 10659, 10661, 10663, 10665, 10667, 10669, 10671, + 10673, 10675, 10677, 10679, 10681, 3285, 10683, 10685, 10687, 10689, + 10691, 10693, 10695, 10697, 10699, 10701, 10703, 10705, 3281, 10707, + 10709, 10711, 10713, 10715, 10717, 10719, 10721, 10723, 10725, 10727, + 10729, 3279, 10731, 10733, 10735, 10737, 10739, 10741, 10743, 10745, + 10747, 10749, 10751, 10753, 10755, 10757, 10759, 10761, 10655, 10657, + 3283, 10659, 10661, 10663, 10665, 10667, 10669, 10671, 10673, 10675, + 10677, 10679, 10681, 3285, 10683, 10685, 10687, 10689, 10691, 10693, + 10695, 10697, 10699, 10701, 10703, 10705, 3281, 10707, 10709, 10711, + 10713, 10715, 10717, 10719, 10721, 10723, 10725, 10727, 10729, 3279, + 10731, 10733, 10735, 10737, 10739, 10741, 10743, 10745, 10747, 10749, + 10751, 10753, 10755, 10757, 10759, 10761, 10655, 10657, 3283, 10659, + 10661, 10663, 10665, 10667, 10669, 10671, 10673, 10675, 10677, 10679, + 10681, 3285, 10683, 10685, 10687, 10689, 10691, 10693, 10695, 10697, + 10699, 10701, 10703, 10705, 3281, 10707, 10709, 10711, 10713, 10715, + 10717, 10719, 10721, 10723, 10725, 10727, 10729, 3279, 10731, 10733, + 10735, 10737, 10739, 10741, 10743, 10745, 10747, 10749, 10751, 10753, + 10755, 10757, 10759, 10761, 10655, 10657, 3283, 10659, 10661, 10663, + 10665, 10667, 10669, 10671, 10673, 10675, 10677, 10679, 10681, 3285, + 10683, 10685, 10687, 10689, 10691, 10693, 10695, 10697, 10699, 10701, + 10703, 10705, 3281, 10707, 10709, 10711, 10713, 10715, 10717, 10719, + 10721, 10723, 10725, 10727, 10729, 3279, 10731, 10733, 10735, 10737, + 10739, 10741, 10743, 10745, 10747, 10749, 10751, 10753, 10755, 10757, + 10759, 10761, 10655, 10657, 3283, 10659, 10661, 10663, 10665, 10667, + 10669, 10671, 10673, 10675, 10677, 10679, 10681, 3285, 10683, 10685, + 10687, 10689, 10691, 10693, 10695, 10697, 10699, 10701, 10703, 10705, + 3281, 10707, 10709, 10711, 10713, 10715, 10717, 10719, 10721, 10723, + 10725, 10727, 10729, 3279, 10731, 10733, 10735, 10737, 10739, 10741, + 10743, 10745, 10747, 10749, 10751, 10753, 10755, 10757, 10759, 10761, + 10763, 10765, 0, 0, 10556, 10558, 10560, 10562, 10564, 10566, 10568, + 10570, 10572, 10574, 10556, 10558, 10560, 10562, 10564, 10566, 10568, + 10570, 10572, 10574, 10556, 10558, 10560, 10562, 10564, 10566, 10568, + 10570, 10572, 10574, 10556, 10558, 10560, 10562, 10564, 10566, 10568, + 10570, 10572, 10574, 10556, 10558, 10560, 10562, 10564, 10566, 10568, + 10570, 10572, 10574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10767, 10769, 10771, 10773, 10775, 10777, 10779, + 10781, 10783, 10785, 10787, 10789, 10791, 10793, 10795, 10797, 10799, + 10801, 10803, 10805, 10807, 10809, 10811, 10813, 10815, 10817, 10819, + 10821, 10823, 10825, 10827, 10829, 10831, 10833, 10835, 10837, 10839, + 10841, 10843, 10845, 10847, 10849, 10851, 10853, 10855, 10857, 10859, + 10861, 10863, 10865, 10867, 10869, 10871, 10873, 10875, 10877, 10879, + 10881, 10883, 10885, 10887, 10889, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10891, 10893, 10895, 10897, 0, 10899, 10901, 10903, 10905, + 10907, 10909, 10911, 10913, 10915, 10917, 10919, 10921, 10923, 10925, + 10927, 10929, 10931, 10933, 10935, 10937, 10939, 10941, 10943, 10945, + 10947, 10949, 10951, 0, 10893, 10895, 0, 10953, 0, 0, 10903, 0, 10907, + 10909, 10911, 10913, 10915, 10917, 10919, 10921, 10923, 10925, 0, 10929, + 10931, 10933, 10935, 0, 10939, 0, 10943, 0, 0, 0, 0, 0, 0, 10895, 0, 0, + 0, 0, 10903, 0, 10907, 0, 10911, 0, 10915, 10917, 10919, 0, 10923, 10925, + 0, 10929, 0, 0, 10935, 0, 10939, 0, 10943, 0, 10947, 0, 10951, 0, 10893, + 10895, 0, 10953, 0, 0, 10903, 10905, 10907, 10909, 0, 10913, 10915, + 10917, 10919, 10921, 10923, 10925, 0, 10929, 10931, 10933, 10935, 0, + 10939, 10941, 10943, 10945, 0, 10949, 0, 10891, 10893, 10895, 10897, + 10953, 10899, 10901, 10903, 10905, 10907, 0, 10911, 10913, 10915, 10917, + 10919, 10921, 10923, 10925, 10927, 10929, 10931, 10933, 10935, 10937, + 10939, 10941, 10943, 0, 0, 0, 0, 0, 10893, 10895, 10897, 0, 10899, 10901, + 10903, 10905, 10907, 0, 10911, 10913, 10915, 10917, 10919, 10921, 10923, + 10925, 10927, 10929, 10931, 10933, 10935, 10937, 10939, 10941, 10943, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10955, 10958, + 10961, 10964, 10967, 10970, 10973, 10976, 10979, 10982, 10985, 0, 0, 0, + 0, 0, 10988, 10992, 10996, 11000, 11004, 11008, 11012, 11016, 11020, + 11024, 11028, 11032, 11036, 11040, 11044, 11048, 11052, 11056, 11060, + 11064, 11068, 11072, 11076, 11080, 11084, 11088, 11092, 3926, 3956, + 11096, 11099, 0, 11102, 11104, 11106, 11108, 11110, 11112, 11114, 11116, + 11118, 11120, 11122, 11124, 11126, 11128, 11130, 11132, 11134, 11136, + 11138, 11140, 11142, 11144, 11146, 11148, 11150, 11152, 11154, 6348, + 11157, 11160, 11163, 11167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11170, 11173, 11176, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 11179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11182, + 11185, 11188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11190, 11192, 11194, + 11196, 11198, 11200, 11202, 11204, 11206, 11208, 11210, 11212, 11214, + 11216, 11218, 11220, 11222, 11224, 11226, 11228, 11230, 11232, 11234, + 11236, 11238, 11240, 11242, 11244, 11246, 11248, 11250, 11252, 11254, + 11256, 11258, 11260, 11262, 11264, 11266, 11268, 11270, 11272, 11274, + 11276, 0, 0, 0, 0, 11278, 11282, 11286, 11290, 11294, 11298, 11302, + 11306, 11310, 0, 0, 0, 0, 0, 0, 0, 11314, 11316, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 10556, 10558, 10560, 10562, 10564, 10566, 10568, 10570, + 10572, 10574, 0, 0, 0, 0, 0, 0, 11318, 11320, 11322, 11324, 11326, 7197, + 11328, 11330, 11332, 11334, 7199, 11336, 11338, 11340, 7201, 11342, + 11344, 11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, + 11364, 7317, 11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, + 11382, 7327, 7203, 7205, 7329, 11384, 11386, 6819, 11388, 7207, 11390, + 11392, 11394, 11396, 11396, 11396, 11398, 11400, 11402, 11404, 11406, + 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, + 11428, 11430, 11432, 11432, 7333, 11434, 11436, 11438, 11440, 7211, + 11442, 11444, 11446, 7125, 11448, 11450, 11452, 11454, 11456, 11458, + 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, + 11480, 11482, 11484, 11486, 11488, 11490, 11492, 11494, 11496, 11498, + 11498, 11500, 11502, 11504, 6811, 11506, 11508, 11510, 11512, 11514, + 11516, 11518, 11520, 7221, 11522, 11524, 11526, 11528, 11530, 11532, + 11534, 11536, 11538, 11540, 11542, 11544, 11546, 11548, 11550, 11552, + 11554, 11556, 11558, 11560, 11562, 6703, 11564, 11566, 11568, 11568, + 11570, 11572, 11572, 11574, 11576, 11578, 11580, 11582, 11584, 11586, + 11588, 11590, 11592, 11594, 11596, 11598, 7223, 11600, 11602, 11604, + 11606, 7357, 11606, 11608, 7227, 11610, 11612, 11614, 11616, 7229, 6649, + 11618, 11620, 11622, 11624, 11626, 11628, 11630, 11632, 11634, 11636, + 11638, 11640, 11642, 11644, 11646, 11648, 11650, 11652, 11654, 11656, + 11658, 11660, 7231, 11662, 11664, 11666, 11668, 11670, 11672, 7235, + 11674, 11676, 11678, 11680, 11682, 11684, 11686, 11688, 6705, 7373, + 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704, 7237, 11706, + 11708, 11710, 11712, 7459, 11714, 11716, 11718, 11720, 11722, 11724, + 11726, 11728, 11730, 11732, 11734, 11736, 11738, 6845, 11740, 11742, + 11744, 11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 7239, + 7019, 11762, 11764, 11766, 11768, 11770, 11772, 11774, 11776, 7381, + 11778, 11780, 11782, 11784, 11786, 11788, 11790, 11792, 7383, 11794, + 11796, 11798, 11800, 11802, 11804, 11806, 11808, 11810, 11812, 11814, + 11816, 7387, 11818, 11820, 11822, 11824, 11826, 11828, 11830, 11832, + 11834, 11836, 11838, 11838, 11840, 11842, 7391, 11844, 11846, 11848, + 11850, 11852, 11854, 11856, 6817, 11858, 11860, 11862, 11864, 11866, + 11868, 11870, 7403, 11872, 11874, 11876, 11878, 11880, 11882, 11882, + 7405, 7463, 11884, 11886, 11888, 11890, 11892, 6741, 7409, 11894, 11896, + 7261, 11898, 11900, 7169, 11902, 11904, 7269, 11906, 11908, 11910, 11912, + 11912, 11914, 11916, 11918, 11920, 11922, 11924, 11926, 11928, 11930, + 11932, 11934, 11936, 11938, 11940, 11942, 11944, 11946, 11948, 11950, + 11952, 11954, 11956, 11958, 11960, 11962, 11964, 11966, 7281, 11968, + 11970, 11972, 11974, 11976, 11978, 11980, 11982, 11984, 11986, 11988, + 11990, 11992, 11994, 11996, 11998, 11570, 12000, 12002, 12004, 12006, + 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022, 6853, 12024, + 12026, 12028, 12030, 12032, 12034, 7287, 12036, 12038, 12040, 12042, + 12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062, + 12064, 12066, 12068, 12070, 12072, 12074, 6731, 12076, 12078, 12080, + 12082, 12084, 12086, 7423, 12088, 12090, 12092, 12094, 12096, 12098, + 12100, 12102, 12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, + 12120, 12122, 12124, 12126, 7433, 7435, 12128, 12130, 12132, 12134, + 12136, 12138, 12140, 12142, 12144, 12146, 12148, 12150, 12152, 7437, + 12154, 12156, 12158, 12160, 12162, 12164, 12166, 12168, 12170, 12172, + 12174, 12176, 12178, 12180, 12182, 12184, 12186, 12188, 12190, 12192, + 12194, 12196, 12198, 12200, 12202, 12204, 12206, 12208, 12210, 12212, + 7449, 7449, 12214, 12216, 12218, 12220, 12222, 12224, 12226, 12228, + 12230, 12232, 7451, 12234, 12236, 12238, 12240, 12242, 12244, 12246, + 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262, 12264, 12266, + 12268, 12270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6196,7 +6191,6 @@ static const change_record change_records_3_2_0[] = { { 9, 255, 255, 255, 255, 0 }, { 255, 255, 255, 1, 255, 0 }, { 255, 20, 255, 255, 255, 0 }, - { 255, 255, 255, 255, 255, 1000000000000.0 }, { 255, 255, 255, 255, 255, 1e+20 }, { 255, 19, 255, 255, 255, -1 }, { 1, 255, 255, 255, 255, 0 }, @@ -6206,42 +6200,43 @@ static const unsigned char changes_3_2_0_index[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 21, 22, 23, 24, 25, 26, 27, 28, 29, 1, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 1, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 1, 1, 1, 50, 1, 1, 51, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52, 53, 54, 55, 56, 1, - 57, 1, 1, 1, 58, 1, 1, 1, 1, 1, 1, 59, 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 61, 1, 55, 1, 1, 1, 1, 1, 1, 62, 1, 1, 63, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 65, 1, 66, 1, 67, 1, - 1, 1, 1, 1, 1, 1, 1, 68, 69, 1, 1, 1, 70, 28, 71, 72, 73, 74, 75, 76, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52, 53, 54, 55, 1, 1, + 56, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 58, 1, 1, 1, 59, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 55, 1, 1, 1, 1, 1, 1, 61, 1, 1, 62, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 63, 1, 1, 1, 1, 1, 64, 1, 65, 1, 66, 1, + 1, 1, 1, 1, 1, 1, 1, 67, 68, 1, 1, 1, 69, 28, 70, 71, 72, 73, 74, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 78, 79, 80, 1, 81, 82, 83, 84, 85, 86, 87, 88, 89, 28, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 28, 28, 28, 115, 116, 117, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 118, 28, 28, 28, 28, 119, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 120, 28, 28, 121, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 122, 1, 1, 1, 1, 1, - 1, 28, 28, 123, 124, 1, 125, 126, 127, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 128, 28, 28, - 28, 28, 129, 130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 131, 28, 132, 133, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 134, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 135, - 28, 136, 137, 1, 138, 139, 140, 141, 1, 142, 143, 28, 28, 144, 1, 1, 1, - 1, 145, 146, 147, 148, 1, 149, 150, 1, 151, 152, 153, 1, 1, 154, 155, - 156, 1, 157, 158, 159, 28, 28, 28, 160, 161, 162, 28, 163, 164, 1, 1, 1, - 1, 165, 67, 1, 1, 1, 1, 1, 1, 1, 166, 167, 168, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 169, 1, 1, 1, 1, 1, 170, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 171, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 77, 78, 79, 1, 80, 81, 82, 83, 84, 85, 86, 87, 88, 28, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 28, 28, 28, 114, 115, 116, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 117, 28, 28, 28, 28, 118, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 119, 28, 28, 120, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 121, 1, 1, 1, 1, 1, + 1, 28, 28, 122, 123, 1, 124, 125, 126, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 127, 128, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 129, 28, 130, 131, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 132, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 133, + 28, 134, 135, 1, 136, 137, 138, 139, 1, 140, 141, 28, 28, 142, 1, 1, 1, + 1, 143, 144, 145, 146, 1, 147, 148, 149, 150, 151, 152, 1, 1, 153, 154, + 155, 1, 156, 157, 158, 28, 28, 28, 159, 160, 161, 28, 162, 163, 1, 1, 1, + 1, 164, 66, 1, 1, 1, 1, 1, 1, 1, 165, 166, 167, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 168, 1, 1, 1, 1, 1, 169, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 170, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 172, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 171, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 173, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 174, 175, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 176, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 177, - 28, 28, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 169, 1, 1, 1, 1, 1, 1, 1, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 178, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 179, 1, 1, 1, + 1, 1, 1, 172, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 173, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 174, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 175, + 28, 28, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 168, 1, 1, 1, 1, 1, 1, 1, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 176, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 177, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -6357,7 +6352,7 @@ static const unsigned char changes_3_2_0_index[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 180, 1, 1, 1, 1, 1, + 178, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -6388,8 +6383,7 @@ static const unsigned char changes_3_2_0_index[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; static const unsigned char changes_3_2_0_data[] = { @@ -6420,7 +6414,7 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6484,7 +6478,7 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -6525,12 +6519,12 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, - 0, 0, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 20, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6670,8 +6664,8 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -6723,7 +6717,7 @@ static const unsigned char changes_3_2_0_data[] = { 41, 42, 43, 44, 1, 1, 0, 0, 0, 4, 38, 8, 6, 7, 39, 40, 41, 42, 43, 44, 1, 1, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, @@ -6832,7 +6826,7 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -6999,23 +6993,13 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -7023,8 +7007,7 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -7034,12 +7017,12 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -7048,10 +7031,10 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -7067,20 +7050,6 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -7089,1109 +7058,12 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 9, 9, 0, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, - 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 49, 50, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 21, 21, 21, 21, 21, 21, 0, 0, 0, 1, 1, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, - 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, - 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 9, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 0, 0, 9, 0, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, - 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 0, 0, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 0, 9, 9, 9, 9, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, - 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 0, 0, 9, 9, 9, - 0, 0, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 0, 0, 9, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 0, 0, 9, - 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 0, 9, 9, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 0, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 9, 9, 0, 9, 0, 0, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, - 9, 9, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 9, 0, 9, 0, 9, 0, 9, - 9, 9, 0, 9, 9, 0, 9, 0, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 9, 0, 9, 0, - 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 0, - 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, - 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -8201,14 +7073,10 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -8219,21 +7087,13 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -8254,11 +7114,35 @@ static const unsigned char changes_3_2_0_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -8266,9 +7150,7 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -8278,12 +7160,502 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 9, + 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, + 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 0, 0, 0, 1, 1, 21, 21, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, + 9, 9, 9, 9, 0, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 0, 0, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 0, 0, 0, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, + 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, + 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 0, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, + 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 9, 9, 0, 0, 9, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 0, 0, + 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 9, 0, 0, 9, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, + 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 0, 0, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -8297,28 +7669,426 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 9, + 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, + 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, + 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, + 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 0, 9, 9, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 0, 9, 0, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 0, 9, 0, 9, 0, 9, 0, 9, 9, 9, 0, 9, 9, 0, 9, 0, 0, 9, 0, 9, 0, 9, 0, 9, + 0, 9, 0, 9, 9, 0, 9, 0, 0, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, + 9, 9, 0, 9, 9, 9, 9, 0, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 0, 9, + 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, @@ -8328,9 +8098,212 @@ static const unsigned char changes_3_2_0_data[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 0, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, }; static const change_record* get_change_3_2_0(Py_UCS4 n) diff --git a/Modules/unicodename_db.h b/Modules/unicodename_db.h index 0697e259b39..d67e968e7a0 100644 --- a/Modules/unicodename_db.h +++ b/Modules/unicodename_db.h @@ -4,6595 +4,6669 @@ /* name->code dictionary */ static const unsigned char packed_name_dawg[] = { - 238, 255, 4, 254, 2, 65, 218, 130, 3, 66, 130, 154, 3, 67, 174, 245, 4, - 68, 206, 135, 1, 69, 186, 157, 1, 70, 190, 54, 71, 210, 164, 1, 72, 182, - 225, 1, 73, 222, 65, 74, 138, 23, 75, 238, 138, 1, 76, 130, 158, 3, 77, - 250, 200, 3, 78, 242, 107, 79, 138, 131, 1, 80, 128, 159, 1, 2, 81, 85, - 226, 7, 82, 194, 180, 1, 83, 214, 193, 4, 84, 134, 225, 2, 85, 242, 104, - 86, 138, 84, 87, 170, 114, 88, 254, 4, 89, 187, 48, 90, 214, 40, 222, 2, + 136, 135, 5, 254, 2, 65, 246, 145, 3, 66, 206, 160, 3, 67, 146, 251, 4, + 68, 250, 135, 1, 69, 230, 157, 1, 70, 174, 55, 71, 214, 169, 1, 72, 138, + 226, 1, 73, 138, 66, 74, 142, 23, 75, 250, 138, 1, 76, 150, 164, 3, 77, + 198, 201, 3, 78, 246, 107, 79, 174, 131, 1, 80, 212, 159, 1, 2, 81, 85, + 226, 7, 82, 158, 180, 1, 83, 210, 197, 4, 84, 146, 236, 2, 85, 246, 104, + 86, 242, 84, 87, 246, 114, 88, 130, 5, 89, 211, 50, 90, 176, 41, 218, 2, 67, 238, 1, 68, 182, 10, 69, 172, 5, 4, 72, 79, 77, 32, 244, 6, 7, 73, - 82, 80, 76, 65, 78, 69, 82, 76, 146, 36, 77, 198, 1, 78, 154, 26, 80, - 138, 20, 82, 226, 136, 2, 83, 210, 2, 84, 70, 85, 214, 1, 86, 144, 254, - 11, 4, 70, 71, 72, 65, 186, 231, 9, 66, 180, 227, 2, 9, 75, 84, 73, 69, - 83, 69, 76, 83, 75, 196, 198, 2, 2, 81, 85, 199, 196, 10, 88, 18, 132, 1, - 2, 67, 79, 46, 75, 20, 5, 85, 84, 69, 32, 65, 164, 153, 17, 6, 84, 73, - 86, 65, 84, 69, 145, 135, 23, 5, 32, 67, 85, 82, 82, 4, 170, 142, 26, 85, - 173, 133, 14, 2, 82, 68, 5, 151, 168, 34, 78, 4, 154, 199, 35, 67, 143, - 248, 3, 78, 188, 1, 232, 1, 4, 76, 65, 77, 32, 242, 7, 77, 212, 179, 13, - 7, 72, 69, 83, 73, 86, 69, 32, 144, 165, 4, 19, 68, 82, 69, 83, 83, 69, - 68, 32, 84, 79, 32, 84, 72, 69, 32, 83, 85, 66, 74, 146, 233, 13, 85, - 237, 185, 1, 6, 73, 32, 83, 72, 65, 75, 176, 1, 218, 1, 67, 44, 4, 83, + 82, 80, 76, 65, 78, 69, 82, 76, 190, 36, 77, 242, 1, 78, 162, 26, 80, + 162, 20, 82, 186, 150, 2, 83, 162, 3, 84, 70, 85, 214, 1, 86, 252, 197, + 1, 8, 75, 84, 73, 69, 83, 69, 76, 83, 168, 203, 10, 4, 70, 71, 72, 65, + 150, 239, 9, 66, 196, 170, 5, 2, 81, 85, 171, 215, 10, 88, 18, 132, 1, 2, + 67, 79, 46, 75, 20, 5, 85, 84, 69, 32, 65, 160, 188, 17, 6, 84, 73, 86, + 65, 84, 69, 213, 161, 23, 5, 32, 67, 85, 82, 82, 4, 186, 184, 26, 85, + 221, 152, 14, 2, 82, 68, 5, 203, 215, 34, 78, 4, 142, 252, 35, 67, 199, + 254, 3, 78, 188, 1, 232, 1, 4, 76, 65, 77, 32, 242, 7, 77, 252, 207, 13, + 7, 72, 69, 83, 73, 86, 69, 32, 136, 172, 4, 19, 68, 82, 69, 83, 83, 69, + 68, 32, 84, 79, 32, 84, 72, 69, 32, 83, 85, 66, 74, 174, 245, 13, 85, + 233, 185, 1, 6, 73, 32, 83, 72, 65, 75, 176, 1, 218, 1, 67, 44, 4, 83, 77, 65, 76, 168, 4, 7, 71, 69, 77, 73, 78, 65, 84, 116, 8, 73, 78, 73, - 84, 73, 65, 76, 32, 38, 78, 198, 213, 2, 72, 200, 197, 23, 4, 65, 76, 73, - 70, 0, 5, 86, 79, 87, 69, 76, 211, 205, 12, 68, 70, 40, 5, 65, 80, 73, + 84, 73, 65, 76, 32, 38, 78, 146, 228, 2, 72, 140, 225, 23, 4, 65, 76, 73, + 70, 0, 5, 86, 79, 87, 69, 76, 155, 222, 12, 68, 70, 40, 5, 65, 80, 73, 84, 65, 215, 4, 79, 68, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, 32, 68, - 142, 2, 68, 38, 71, 34, 74, 2, 77, 22, 75, 46, 78, 42, 83, 166, 133, 30, - 81, 238, 223, 4, 76, 194, 39, 67, 194, 197, 4, 90, 212, 7, 2, 65, 76, + 142, 2, 68, 38, 71, 34, 74, 2, 77, 22, 75, 46, 78, 42, 83, 130, 176, 30, + 81, 142, 228, 4, 76, 142, 45, 67, 158, 204, 4, 90, 240, 9, 2, 65, 76, 170, 2, 66, 2, 89, 154, 1, 87, 198, 89, 84, 150, 14, 80, 158, 20, 70, 2, - 72, 2, 82, 2, 86, 186, 2, 69, 2, 73, 2, 79, 3, 85, 4, 170, 218, 5, 65, - 155, 128, 35, 72, 4, 130, 198, 40, 66, 215, 22, 65, 2, 231, 217, 39, 73, - 6, 254, 218, 39, 65, 178, 98, 80, 191, 28, 72, 6, 150, 140, 40, 85, 170, - 77, 72, 3, 89, 4, 212, 185, 2, 6, 73, 78, 78, 89, 73, 73, 195, 159, 38, - 72, 4, 40, 4, 69, 32, 67, 79, 219, 241, 39, 73, 2, 233, 209, 39, 13, 78, - 83, 79, 78, 65, 78, 84, 32, 77, 79, 68, 73, 70, 4, 214, 204, 33, 69, 183, - 188, 4, 81, 4, 174, 236, 25, 65, 251, 217, 10, 85, 4, 238, 178, 27, 69, - 189, 146, 12, 12, 73, 83, 83, 73, 79, 78, 32, 84, 73, 67, 75, 69, 116, - 80, 5, 71, 69, 65, 78, 32, 241, 135, 34, 9, 82, 73, 65, 76, 32, 84, 82, + 72, 2, 82, 2, 86, 186, 2, 69, 2, 73, 2, 79, 3, 85, 4, 150, 240, 5, 65, + 239, 167, 35, 72, 4, 194, 131, 41, 66, 215, 22, 65, 2, 167, 151, 40, 73, + 6, 190, 152, 40, 65, 178, 98, 80, 191, 28, 72, 6, 214, 201, 40, 85, 170, + 77, 72, 3, 89, 4, 164, 200, 2, 6, 73, 78, 78, 89, 73, 73, 179, 206, 38, + 72, 4, 40, 4, 69, 32, 67, 79, 155, 175, 40, 73, 2, 145, 141, 40, 13, 78, + 83, 79, 78, 65, 78, 84, 32, 77, 79, 68, 73, 70, 4, 134, 252, 33, 69, 247, + 198, 4, 81, 4, 186, 150, 26, 65, 143, 228, 10, 85, 4, 230, 220, 27, 69, + 245, 177, 12, 12, 73, 83, 83, 73, 79, 78, 32, 84, 73, 67, 75, 69, 116, + 80, 5, 71, 69, 65, 78, 32, 161, 183, 34, 9, 82, 73, 65, 76, 32, 84, 82, 65, 77, 114, 136, 1, 3, 68, 82, 89, 0, 6, 76, 73, 81, 85, 73, 68, 60, 8, - 77, 69, 65, 83, 85, 82, 69, 32, 26, 87, 230, 147, 27, 78, 183, 255, 11, + 77, 69, 65, 83, 85, 82, 69, 32, 26, 87, 146, 190, 27, 78, 183, 144, 12, 67, 2, 153, 2, 11, 32, 77, 69, 65, 83, 85, 82, 69, 32, 70, 73, 4, 246, 1, 83, 31, 84, 14, 100, 6, 69, 73, 71, 72, 84, 32, 241, 1, 14, 79, 82, 68, 32, 83, 69, 80, 65, 82, 65, 84, 79, 82, 32, 10, 54, 70, 66, 83, 30, 84, 65, 5, 66, 65, 83, 69, 32, 4, 38, 73, 89, 5, 79, 85, 82, 84, 72, 2, 85, 3, 82, 83, 84, 2, 49, 4, 69, 67, 79, 78, 2, 21, 3, 72, 73, 82, 2, 11, 68, - 2, 25, 4, 32, 83, 85, 66, 2, 217, 183, 40, 2, 85, 78, 4, 190, 186, 39, - 76, 131, 73, 68, 130, 1, 140, 2, 22, 67, 79, 78, 83, 79, 78, 65, 78, 84, + 2, 25, 4, 32, 83, 85, 66, 2, 153, 245, 40, 2, 85, 78, 4, 250, 245, 39, + 76, 135, 75, 68, 130, 1, 140, 2, 22, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 77, 69, 68, 73, 65, 76, 32, 88, 7, 76, 69, 84, 84, 69, 82, 32, 242, 1, 83, 168, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, - 71, 78, 32, 140, 212, 32, 8, 78, 85, 77, 66, 69, 82, 32, 84, 171, 136, 6, - 68, 6, 26, 76, 243, 206, 40, 82, 4, 204, 134, 40, 7, 73, 71, 65, 84, 73, - 78, 71, 219, 74, 65, 68, 154, 1, 65, 214, 245, 36, 68, 114, 84, 218, 207, - 1, 76, 250, 192, 1, 78, 126, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, + 71, 78, 32, 196, 131, 33, 8, 78, 85, 77, 66, 69, 82, 32, 84, 203, 147, 6, + 68, 6, 26, 76, 179, 140, 41, 82, 4, 140, 196, 40, 7, 73, 71, 65, 84, 73, + 78, 71, 219, 74, 65, 68, 154, 1, 65, 194, 175, 37, 68, 114, 84, 198, 208, + 1, 76, 226, 195, 1, 78, 126, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 82, 3, 83, 9, 45, 9, 76, 84, 69, 82, 78, 65, 84, 69, - 32, 6, 230, 204, 40, 66, 2, 71, 3, 84, 10, 60, 4, 73, 71, 78, 32, 153, - 149, 23, 5, 89, 77, 66, 79, 76, 8, 50, 83, 170, 215, 25, 75, 229, 139, - 10, 2, 82, 85, 4, 180, 207, 37, 4, 77, 65, 76, 76, 247, 173, 2, 69, 22, - 66, 65, 234, 249, 36, 85, 206, 201, 1, 73, 222, 137, 2, 69, 3, 79, 11, - 142, 205, 40, 65, 2, 73, 2, 77, 3, 87, 7, 11, 32, 4, 192, 182, 35, 3, 68, - 69, 80, 145, 197, 4, 5, 65, 82, 82, 73, 86, 150, 2, 216, 1, 20, 67, 72, - 69, 77, 73, 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, - 166, 28, 69, 60, 4, 73, 69, 78, 32, 208, 3, 2, 76, 32, 82, 77, 108, 6, - 84, 69, 82, 78, 65, 84, 141, 142, 36, 3, 65, 82, 77, 232, 1, 158, 2, 65, - 246, 2, 66, 210, 1, 67, 138, 3, 68, 98, 71, 38, 72, 132, 1, 4, 73, 82, - 79, 78, 82, 76, 74, 77, 144, 1, 2, 78, 73, 34, 80, 176, 2, 3, 81, 85, 73, - 74, 82, 146, 2, 83, 210, 5, 84, 166, 1, 86, 200, 1, 2, 87, 65, 170, 238, - 34, 85, 154, 215, 1, 69, 158, 181, 1, 79, 139, 31, 70, 30, 194, 1, 76, - 72, 3, 81, 85, 65, 204, 8, 7, 78, 84, 73, 77, 79, 78, 89, 236, 142, 3, 3, - 77, 65, 76, 128, 174, 21, 3, 82, 83, 69, 248, 229, 13, 5, 85, 82, 73, 80, - 73, 210, 134, 1, 83, 171, 91, 73, 8, 224, 24, 2, 69, 77, 212, 171, 26, 4, - 75, 65, 76, 73, 191, 241, 13, 85, 10, 38, 32, 129, 223, 24, 3, 70, 79, - 82, 8, 216, 7, 4, 86, 73, 84, 65, 145, 150, 23, 4, 82, 69, 71, 73, 16, - 148, 1, 7, 65, 84, 72, 32, 79, 70, 32, 204, 6, 6, 73, 83, 77, 85, 84, 72, - 144, 1, 4, 79, 82, 65, 88, 164, 1, 4, 76, 65, 67, 75, 139, 139, 39, 82, - 4, 138, 234, 16, 77, 165, 203, 22, 5, 86, 65, 80, 79, 85, 28, 82, 65, 92, - 6, 79, 80, 80, 69, 82, 32, 34, 82, 185, 160, 39, 4, 73, 78, 78, 65, 6, - 152, 250, 5, 2, 68, 85, 204, 159, 33, 9, 80, 85, 84, 32, 77, 79, 82, 84, - 85, 239, 28, 76, 4, 230, 13, 65, 255, 147, 39, 79, 16, 72, 8, 79, 67, 85, - 83, 32, 79, 70, 32, 53, 6, 85, 67, 73, 66, 76, 69, 6, 228, 16, 5, 67, 79, - 80, 80, 69, 171, 139, 39, 73, 11, 11, 45, 8, 238, 192, 40, 50, 2, 51, 2, - 52, 3, 53, 8, 44, 2, 73, 83, 129, 198, 37, 3, 65, 89, 45, 6, 144, 2, 4, - 83, 79, 76, 86, 255, 197, 37, 84, 4, 218, 161, 30, 79, 179, 141, 10, 85, - 8, 32, 4, 65, 76, 70, 32, 47, 79, 4, 200, 183, 35, 2, 79, 85, 203, 204, - 3, 68, 4, 212, 250, 2, 4, 82, 83, 69, 32, 191, 139, 37, 85, 6, 56, 3, 32, - 79, 82, 73, 7, 45, 67, 79, 80, 80, 69, 82, 4, 235, 187, 26, 69, 4, 48, 3, - 69, 65, 68, 229, 204, 13, 3, 79, 68, 69, 2, 223, 216, 35, 32, 10, 120, - 16, 69, 82, 67, 85, 82, 89, 32, 83, 85, 66, 76, 73, 77, 65, 84, 69, 196, - 183, 16, 4, 65, 82, 67, 65, 203, 130, 22, 79, 7, 179, 187, 40, 45, 4, - 218, 155, 39, 84, 131, 118, 71, 14, 108, 11, 72, 73, 76, 79, 83, 79, 80, - 72, 69, 82, 83, 34, 79, 98, 85, 173, 134, 30, 6, 82, 69, 67, 73, 80, 73, - 2, 209, 9, 4, 32, 83, 85, 76, 6, 52, 4, 87, 68, 69, 82, 205, 136, 36, 3, - 84, 32, 65, 5, 173, 138, 39, 5, 69, 68, 32, 66, 82, 4, 200, 136, 34, 4, - 84, 82, 69, 70, 241, 159, 6, 3, 82, 73, 70, 4, 220, 176, 35, 5, 78, 84, - 69, 83, 83, 237, 240, 3, 4, 67, 75, 32, 76, 24, 58, 69, 173, 182, 26, 8, - 79, 67, 75, 32, 83, 65, 76, 84, 20, 68, 5, 71, 85, 76, 85, 83, 164, 7, 3, - 65, 76, 71, 195, 129, 26, 84, 15, 32, 4, 32, 79, 70, 32, 71, 45, 6, 188, - 181, 26, 8, 65, 78, 84, 73, 77, 79, 78, 89, 247, 220, 12, 73, 6, 142, - 183, 40, 50, 2, 51, 3, 52, 34, 164, 1, 2, 65, 76, 194, 1, 84, 142, 1, 85, - 192, 191, 17, 2, 80, 73, 164, 178, 12, 2, 73, 76, 170, 176, 9, 79, 141, - 20, 11, 67, 69, 80, 84, 69, 82, 32, 79, 70, 32, 74, 8, 58, 84, 141, 141, - 39, 8, 45, 65, 77, 77, 79, 78, 73, 65, 7, 25, 4, 32, 79, 70, 32, 4, 52, - 8, 67, 79, 80, 80, 69, 82, 32, 65, 231, 5, 65, 2, 229, 128, 30, 7, 78, - 84, 73, 77, 79, 78, 73, 6, 236, 3, 8, 65, 82, 82, 69, 68, 32, 84, 82, - 129, 174, 26, 19, 82, 65, 84, 85, 77, 32, 83, 85, 80, 69, 82, 32, 83, 84, - 82, 65, 84, 85, 77, 12, 44, 6, 66, 76, 73, 77, 65, 84, 155, 1, 76, 10, - 44, 5, 69, 32, 79, 70, 32, 175, 226, 39, 73, 8, 68, 8, 83, 65, 76, 84, - 32, 79, 70, 32, 130, 3, 65, 247, 172, 27, 67, 4, 254, 2, 65, 247, 172, - 27, 67, 2, 219, 184, 39, 70, 12, 68, 3, 65, 82, 84, 32, 2, 73, 78, 34, - 82, 157, 195, 38, 2, 85, 84, 4, 11, 65, 4, 179, 174, 26, 82, 4, 182, 154, - 35, 67, 167, 49, 32, 2, 233, 236, 39, 2, 73, 68, 14, 50, 73, 145, 140, - 38, 6, 69, 82, 68, 73, 71, 82, 12, 64, 5, 78, 69, 71, 65, 82, 237, 172, - 26, 5, 84, 82, 73, 79, 76, 9, 44, 5, 32, 79, 70, 32, 65, 223, 173, 40, - 45, 2, 181, 144, 24, 3, 78, 84, 73, 4, 194, 240, 39, 84, 239, 61, 88, 6, - 38, 77, 194, 154, 39, 70, 255, 118, 82, 2, 223, 133, 39, 66, 22, 104, 7, - 77, 79, 78, 83, 84, 69, 82, 138, 1, 83, 241, 204, 35, 10, 67, 82, 65, 66, - 32, 83, 84, 69, 80, 80, 11, 11, 32, 8, 88, 6, 67, 76, 79, 83, 69, 68, 0, - 4, 79, 80, 69, 78, 237, 170, 36, 4, 83, 84, 69, 80, 2, 205, 208, 37, 3, - 32, 74, 65, 8, 60, 6, 80, 73, 68, 69, 82, 32, 57, 5, 81, 85, 73, 68, 32, - 4, 140, 153, 29, 5, 67, 82, 79, 85, 67, 215, 245, 1, 83, 4, 56, 6, 67, - 76, 79, 83, 69, 68, 1, 4, 79, 80, 69, 78, 2, 217, 207, 27, 5, 32, 84, 69, - 78, 84, 4, 190, 214, 33, 69, 209, 174, 4, 11, 65, 82, 79, 85, 78, 68, 45, - 80, 82, 79, 70, 9, 49, 10, 79, 83, 84, 32, 69, 81, 85, 65, 76, 32, 6, 32, - 2, 84, 79, 251, 151, 32, 79, 5, 227, 232, 6, 32, 4, 232, 219, 10, 3, 73, - 86, 69, 253, 163, 28, 5, 69, 32, 79, 78, 69, 10, 162, 1, 80, 200, 165, - 29, 6, 69, 82, 73, 67, 65, 78, 188, 249, 5, 3, 66, 85, 76, 197, 248, 3, - 16, 65, 76, 71, 65, 77, 65, 84, 73, 79, 78, 32, 79, 82, 32, 67, 79, 4, - 210, 215, 36, 69, 139, 94, 72, 194, 9, 92, 3, 65, 84, 79, 174, 20, 71, - 174, 1, 84, 146, 248, 24, 67, 222, 139, 12, 68, 139, 139, 3, 75, 144, 9, - 104, 17, 76, 73, 65, 78, 32, 72, 73, 69, 82, 79, 71, 76, 89, 80, 72, 32, - 65, 141, 148, 13, 3, 77, 73, 67, 142, 9, 70, 48, 138, 4, 49, 198, 2, 50, - 162, 3, 51, 174, 5, 52, 163, 3, 53, 222, 1, 106, 50, 102, 52, 110, 54, - 102, 57, 182, 7, 51, 210, 219, 11, 49, 206, 134, 23, 48, 242, 1, 53, 2, - 55, 3, 56, 22, 170, 183, 34, 54, 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 2, 55, 2, 56, 3, 57, 28, 158, 164, 12, 54, 170, 146, 22, 49, - 2, 53, 134, 236, 5, 48, 2, 50, 2, 51, 2, 52, 2, 55, 2, 56, 3, 57, 26, - 246, 138, 12, 54, 234, 150, 28, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, - 55, 2, 56, 3, 57, 24, 246, 180, 34, 55, 2, 56, 134, 236, 5, 48, 2, 49, 2, - 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 57, 232, 1, 98, 48, 114, 49, 162, 143, - 12, 50, 2, 51, 230, 217, 22, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 42, - 198, 136, 12, 52, 2, 55, 190, 24, 53, 170, 146, 22, 48, 2, 49, 2, 50, - 134, 236, 5, 51, 2, 54, 2, 56, 3, 57, 26, 146, 160, 12, 48, 170, 146, 22, - 53, 134, 236, 5, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, - 222, 1, 102, 48, 110, 49, 102, 57, 210, 1, 56, 206, 253, 11, 50, 2, 54, - 194, 230, 22, 51, 2, 52, 2, 53, 3, 55, 28, 186, 158, 12, 50, 170, 146, - 22, 55, 2, 57, 134, 236, 5, 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, 54, 3, 56, - 24, 246, 175, 34, 53, 2, 54, 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, 52, - 2, 55, 2, 56, 3, 57, 24, 146, 175, 34, 52, 2, 57, 134, 236, 5, 48, 2, 49, - 2, 50, 2, 51, 2, 53, 2, 54, 2, 55, 3, 56, 228, 1, 102, 48, 2, 50, 2, 53, - 102, 51, 110, 54, 102, 56, 162, 1, 57, 130, 230, 11, 55, 186, 250, 22, - 49, 3, 52, 22, 194, 173, 34, 57, 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 2, 54, 2, 55, 3, 56, 30, 250, 129, 12, 54, 150, 196, 8, 50, - 214, 210, 19, 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 24, - 242, 171, 34, 52, 2, 56, 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, 53, 2, - 54, 2, 55, 3, 57, 26, 98, 51, 174, 170, 34, 49, 2, 54, 134, 236, 5, 48, - 2, 50, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 4, 216, 246, 20, 6, 32, 82, 65, - 32, 79, 82, 215, 159, 19, 65, 20, 160, 235, 39, 3, 51, 32, 69, 210, 42, - 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 202, 1, 102, - 49, 210, 1, 53, 202, 205, 20, 57, 202, 143, 14, 48, 2, 50, 2, 51, 2, 52, - 2, 54, 2, 55, 3, 56, 22, 90, 48, 194, 147, 40, 49, 2, 50, 2, 51, 2, 52, - 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 4, 60, 6, 32, 66, 69, 71, 73, 78, 1, - 5, 65, 32, 69, 78, 68, 2, 213, 167, 16, 8, 32, 76, 79, 71, 79, 71, 82, - 65, 24, 198, 166, 34, 48, 2, 55, 134, 236, 5, 49, 2, 50, 2, 51, 2, 52, 2, - 53, 2, 54, 2, 56, 3, 57, 60, 150, 249, 32, 51, 166, 225, 1, 48, 242, 1, - 49, 3, 50, 14, 96, 2, 76, 69, 198, 162, 2, 85, 136, 162, 32, 2, 83, 84, - 242, 232, 3, 69, 241, 165, 1, 2, 82, 89, 7, 33, 6, 32, 87, 73, 84, 72, - 32, 4, 182, 236, 31, 83, 231, 184, 4, 85, 31, 76, 4, 69, 78, 78, 65, 41, - 11, 73, 67, 76, 79, 67, 75, 87, 73, 83, 69, 32, 5, 241, 230, 36, 5, 32, - 87, 73, 84, 72, 24, 90, 84, 222, 248, 6, 67, 58, 68, 122, 71, 138, 4, 79, - 153, 134, 28, 5, 73, 78, 84, 69, 71, 12, 84, 15, 82, 73, 65, 78, 71, 76, - 69, 45, 72, 69, 65, 68, 69, 68, 32, 155, 253, 6, 79, 10, 112, 3, 76, 69, - 70, 0, 4, 82, 73, 71, 72, 12, 6, 66, 79, 84, 84, 79, 77, 0, 3, 84, 79, - 80, 191, 252, 6, 79, 2, 11, 84, 2, 193, 178, 37, 7, 32, 85, 45, 83, 72, - 65, 80, 158, 1, 128, 1, 20, 76, 32, 70, 85, 78, 67, 84, 73, 79, 78, 65, - 76, 32, 83, 89, 77, 66, 79, 76, 32, 206, 15, 79, 38, 80, 179, 251, 39, - 67, 140, 1, 222, 2, 67, 186, 1, 68, 190, 2, 73, 44, 4, 65, 76, 80, 72, 0, - 4, 79, 77, 69, 71, 32, 4, 74, 79, 84, 32, 36, 4, 76, 69, 70, 84, 68, 2, - 81, 85, 218, 3, 82, 54, 83, 92, 4, 69, 80, 83, 73, 32, 6, 66, 65, 67, 75, - 83, 76, 76, 2, 85, 80, 156, 136, 16, 12, 71, 82, 69, 65, 84, 69, 82, 45, - 84, 72, 65, 78, 0, 5, 84, 73, 76, 68, 69, 203, 145, 20, 90, 14, 64, 6, - 73, 82, 67, 76, 69, 32, 169, 230, 38, 4, 79, 77, 77, 65, 12, 80, 2, 83, - 84, 190, 206, 19, 68, 234, 131, 6, 66, 246, 201, 10, 85, 215, 154, 3, 74, - 4, 250, 226, 38, 73, 207, 107, 65, 22, 76, 2, 69, 76, 120, 3, 79, 87, 78, - 129, 244, 31, 6, 73, 65, 77, 79, 78, 68, 10, 30, 32, 53, 3, 84, 65, 32, - 6, 170, 205, 19, 68, 142, 213, 16, 84, 223, 190, 1, 83, 4, 210, 154, 36, - 85, 143, 198, 1, 83, 10, 22, 32, 167, 9, 87, 8, 52, 5, 84, 65, 67, 75, - 32, 182, 1, 83, 227, 6, 67, 4, 222, 153, 36, 85, 215, 154, 3, 74, 6, 40, - 2, 79, 84, 225, 129, 32, 2, 45, 66, 4, 11, 65, 5, 223, 242, 31, 32, 4, - 146, 203, 19, 68, 223, 205, 16, 85, 4, 28, 2, 32, 83, 187, 7, 87, 2, 169, - 222, 37, 4, 72, 79, 69, 32, 46, 44, 2, 65, 68, 133, 3, 4, 79, 84, 69, 32, - 43, 11, 32, 40, 178, 1, 67, 38, 68, 92, 2, 85, 80, 36, 2, 76, 69, 142, - 186, 6, 81, 176, 216, 13, 3, 78, 79, 84, 22, 69, 178, 184, 5, 66, 194, - 158, 7, 83, 170, 132, 5, 71, 162, 114, 82, 195, 79, 74, 4, 178, 175, 38, - 73, 251, 129, 1, 79, 12, 54, 73, 36, 3, 79, 87, 78, 213, 199, 36, 2, 69, - 76, 4, 130, 221, 31, 86, 251, 230, 6, 65, 4, 222, 245, 3, 32, 255, 234, - 34, 87, 4, 162, 238, 37, 83, 255, 113, 70, 4, 238, 153, 12, 81, 231, 250, - 23, 85, 4, 184, 3, 5, 73, 71, 72, 84, 87, 143, 221, 39, 72, 10, 88, 5, - 69, 77, 73, 67, 79, 34, 76, 34, 84, 253, 151, 12, 7, 81, 85, 73, 83, 72, - 32, 81, 2, 237, 236, 31, 3, 76, 79, 78, 2, 185, 220, 38, 3, 65, 83, 72, - 4, 196, 136, 16, 2, 65, 82, 163, 166, 7, 73, 12, 22, 32, 171, 1, 87, 10, - 78, 67, 36, 5, 84, 65, 67, 75, 32, 253, 171, 39, 6, 83, 72, 79, 69, 32, - 74, 2, 229, 173, 23, 4, 65, 82, 69, 84, 6, 202, 195, 19, 68, 198, 138, - 17, 79, 239, 221, 2, 74, 2, 209, 222, 36, 6, 65, 82, 68, 83, 32, 86, 4, - 178, 227, 33, 83, 171, 200, 5, 76, 12, 92, 2, 82, 79, 177, 159, 26, 15, - 76, 73, 67, 65, 84, 73, 79, 78, 32, 80, 82, 79, 71, 82, 65, 10, 112, 9, - 88, 73, 77, 65, 84, 69, 76, 89, 32, 165, 221, 39, 13, 65, 67, 72, 69, 83, - 32, 84, 72, 69, 32, 76, 73, 77, 8, 76, 6, 69, 81, 85, 65, 76, 32, 245, - 242, 24, 7, 66, 85, 84, 32, 78, 79, 84, 6, 32, 2, 84, 79, 135, 232, 31, - 79, 5, 185, 160, 26, 13, 32, 79, 82, 32, 84, 72, 69, 32, 73, 77, 65, 71, - 69, 240, 22, 148, 1, 4, 65, 66, 73, 67, 156, 246, 1, 7, 77, 69, 78, 73, - 65, 78, 32, 224, 12, 3, 82, 79, 87, 228, 3, 2, 84, 73, 174, 220, 36, 73, - 251, 147, 1, 67, 158, 21, 54, 32, 217, 244, 1, 7, 45, 73, 78, 68, 73, 67, - 32, 130, 21, 178, 3, 67, 238, 1, 68, 246, 2, 69, 186, 1, 70, 212, 1, 2, - 72, 65, 104, 5, 75, 65, 83, 82, 65, 86, 76, 248, 167, 1, 2, 77, 65, 204, - 18, 7, 78, 85, 77, 66, 69, 82, 32, 36, 5, 79, 80, 69, 78, 32, 82, 80, - 238, 1, 82, 156, 2, 8, 66, 65, 83, 69, 76, 73, 78, 69, 52, 6, 73, 78, 86, - 69, 82, 84, 98, 83, 150, 33, 84, 202, 4, 86, 232, 184, 17, 9, 87, 65, 86, - 89, 32, 72, 65, 77, 90, 190, 249, 17, 81, 145, 197, 1, 6, 90, 87, 65, 82, - 65, 75, 16, 44, 2, 79, 77, 81, 5, 85, 82, 76, 89, 32, 4, 216, 158, 19, - 11, 66, 73, 78, 73, 78, 71, 32, 65, 76, 69, 70, 207, 209, 20, 77, 12, 72, - 4, 68, 65, 77, 77, 0, 4, 70, 65, 84, 72, 1, 4, 75, 65, 83, 82, 4, 11, 65, - 5, 183, 167, 38, 84, 24, 158, 1, 65, 108, 5, 79, 85, 66, 76, 69, 188, - 206, 23, 5, 69, 67, 73, 77, 65, 209, 192, 9, 16, 73, 83, 80, 85, 84, 69, - 68, 32, 69, 78, 68, 32, 79, 70, 32, 65, 14, 36, 3, 77, 77, 65, 147, 178, - 33, 84, 13, 22, 32, 199, 5, 84, 6, 154, 226, 1, 73, 54, 77, 135, 233, 36, - 87, 6, 190, 4, 68, 165, 193, 1, 18, 32, 82, 73, 71, 72, 84, 32, 65, 82, - 82, 79, 87, 72, 69, 65, 68, 32, 65, 8, 88, 12, 77, 80, 84, 89, 32, 67, - 69, 78, 84, 82, 69, 32, 57, 6, 78, 68, 32, 79, 70, 32, 4, 144, 156, 37, - 4, 72, 73, 71, 72, 1, 3, 76, 79, 87, 4, 146, 223, 29, 84, 255, 173, 3, - 65, 22, 84, 4, 65, 84, 72, 65, 238, 209, 1, 79, 156, 223, 4, 3, 73, 86, - 69, 195, 233, 30, 85, 17, 22, 32, 139, 2, 84, 10, 52, 5, 87, 73, 84, 72, - 32, 170, 222, 1, 73, 55, 77, 6, 250, 154, 38, 84, 138, 80, 68, 203, 47, - 82, 6, 72, 13, 76, 70, 32, 77, 65, 68, 68, 65, 32, 79, 86, 69, 82, 235, - 16, 77, 2, 165, 205, 17, 2, 32, 77, 13, 18, 32, 43, 84, 6, 254, 71, 87, - 130, 149, 1, 73, 55, 77, 4, 173, 82, 2, 65, 78, 230, 15, 84, 5, 65, 82, - 71, 69, 32, 146, 1, 69, 149, 90, 8, 73, 71, 65, 84, 85, 82, 69, 32, 8, - 64, 10, 82, 79, 85, 78, 68, 32, 68, 79, 84, 32, 179, 245, 10, 67, 6, 148, - 245, 10, 6, 73, 78, 83, 73, 68, 69, 162, 213, 26, 66, 167, 161, 1, 65, - 130, 8, 80, 5, 84, 84, 69, 82, 32, 185, 150, 7, 9, 70, 84, 32, 65, 82, - 82, 79, 87, 72, 254, 7, 210, 2, 65, 240, 10, 2, 66, 69, 150, 4, 68, 186, - 5, 70, 246, 4, 71, 226, 2, 72, 156, 9, 2, 74, 69, 154, 1, 75, 130, 5, 76, - 222, 2, 77, 154, 1, 78, 140, 3, 3, 80, 69, 72, 176, 1, 3, 81, 65, 70, - 214, 1, 82, 230, 3, 83, 162, 9, 84, 174, 8, 85, 148, 2, 2, 86, 69, 28, 3, - 87, 65, 87, 202, 1, 89, 246, 3, 79, 236, 2, 2, 90, 65, 31, 69, 112, 92, - 7, 70, 82, 73, 67, 65, 78, 32, 92, 2, 73, 78, 144, 2, 3, 76, 69, 70, 131, - 225, 39, 69, 8, 52, 3, 81, 65, 70, 218, 251, 32, 70, 139, 193, 3, 78, 5, - 241, 63, 5, 32, 87, 73, 84, 72, 21, 11, 32, 18, 72, 6, 87, 73, 84, 72, - 32, 84, 150, 160, 1, 70, 238, 43, 73, 199, 9, 77, 10, 60, 10, 72, 82, 69, - 69, 32, 68, 79, 84, 83, 32, 147, 54, 87, 6, 160, 250, 14, 17, 80, 79, 73, - 78, 84, 73, 78, 71, 32, 68, 79, 87, 78, 87, 65, 82, 68, 198, 201, 22, 66, - 167, 161, 1, 65, 83, 11, 32, 80, 70, 87, 212, 44, 6, 77, 65, 75, 83, 85, - 82, 182, 113, 70, 255, 52, 73, 70, 48, 4, 73, 84, 72, 32, 161, 44, 3, 65, - 83, 76, 64, 192, 2, 9, 65, 84, 84, 65, 67, 72, 69, 68, 32, 220, 1, 19, - 82, 73, 71, 72, 84, 32, 77, 73, 68, 68, 76, 69, 32, 83, 84, 82, 79, 75, - 69, 188, 1, 6, 72, 65, 77, 90, 65, 32, 44, 8, 87, 65, 86, 89, 32, 72, 65, - 77, 134, 70, 69, 204, 1, 4, 77, 65, 68, 68, 136, 165, 36, 9, 76, 69, 70, - 84, 32, 77, 73, 68, 68, 207, 236, 1, 68, 28, 204, 1, 17, 66, 79, 84, 84, - 79, 77, 32, 82, 73, 71, 72, 84, 32, 75, 65, 83, 82, 0, 14, 84, 79, 80, - 32, 82, 73, 71, 72, 84, 32, 70, 65, 84, 72, 94, 82, 56, 3, 76, 69, 70, - 190, 201, 1, 75, 207, 149, 32, 70, 6, 11, 65, 7, 29, 5, 32, 65, 78, 68, - 32, 4, 240, 170, 19, 3, 76, 69, 70, 251, 175, 19, 68, 8, 52, 3, 73, 71, - 72, 253, 214, 1, 4, 79, 85, 78, 68, 4, 17, 2, 84, 32, 4, 166, 176, 1, 82, - 223, 37, 72, 12, 154, 72, 65, 37, 5, 66, 69, 76, 79, 87, 4, 179, 168, 37, - 90, 50, 22, 72, 227, 63, 69, 41, 22, 32, 203, 63, 69, 28, 68, 5, 87, 73, - 84, 72, 32, 194, 150, 1, 70, 238, 43, 73, 199, 9, 77, 20, 116, 6, 83, 77, - 65, 76, 76, 32, 34, 84, 254, 18, 73, 248, 32, 10, 68, 79, 84, 32, 66, 69, - 76, 79, 87, 32, 191, 20, 72, 6, 242, 38, 77, 231, 184, 23, 86, 8, 88, 10, - 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 193, 48, 7, 87, 79, 32, 68, 79, - 84, 83, 6, 144, 1, 22, 80, 79, 73, 78, 84, 73, 78, 71, 32, 85, 80, 87, - 65, 82, 68, 83, 32, 66, 69, 76, 79, 87, 161, 54, 8, 72, 79, 82, 73, 90, - 79, 78, 84, 5, 171, 237, 14, 32, 78, 90, 65, 136, 4, 2, 68, 65, 40, 7, - 79, 84, 76, 69, 83, 83, 32, 234, 27, 89, 247, 25, 85, 44, 34, 76, 254, 3, - 72, 235, 45, 68, 27, 11, 32, 24, 56, 5, 87, 73, 84, 72, 32, 222, 145, 1, - 70, 255, 52, 73, 20, 108, 9, 73, 78, 86, 69, 82, 84, 69, 68, 32, 34, 84, - 168, 1, 3, 68, 79, 84, 250, 246, 11, 70, 207, 137, 27, 82, 4, 238, 14, - 83, 163, 196, 39, 86, 8, 132, 1, 10, 72, 82, 69, 69, 32, 68, 79, 84, 83, - 32, 33, 18, 87, 79, 32, 68, 79, 84, 83, 32, 86, 69, 82, 84, 73, 67, 65, - 76, 76, 89, 4, 182, 54, 65, 163, 253, 36, 66, 4, 33, 6, 32, 66, 69, 76, - 79, 87, 5, 157, 154, 15, 11, 32, 65, 78, 68, 32, 83, 77, 65, 76, 76, 32, - 12, 22, 72, 243, 62, 76, 6, 235, 53, 65, 6, 222, 232, 32, 66, 2, 70, 175, - 230, 5, 81, 44, 60, 8, 65, 82, 83, 73, 32, 89, 69, 72, 169, 2, 2, 69, 72, - 23, 11, 32, 20, 68, 5, 87, 73, 84, 72, 32, 218, 140, 1, 70, 238, 43, 73, - 199, 9, 77, 12, 144, 1, 28, 69, 88, 84, 69, 78, 68, 69, 68, 32, 65, 82, - 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, 32, 68, 73, 71, 73, 84, 32, 30, - 84, 207, 39, 73, 6, 250, 8, 70, 255, 49, 84, 4, 150, 145, 7, 72, 179, - 212, 7, 87, 23, 11, 32, 20, 68, 5, 87, 73, 84, 72, 32, 178, 138, 1, 70, - 238, 43, 73, 199, 9, 77, 12, 32, 4, 68, 79, 84, 32, 51, 84, 6, 174, 40, - 66, 229, 190, 15, 4, 77, 79, 86, 69, 6, 64, 10, 72, 82, 69, 69, 32, 68, - 79, 84, 83, 32, 199, 157, 37, 87, 4, 198, 17, 80, 231, 155, 37, 66, 44, - 72, 2, 65, 70, 160, 1, 4, 72, 65, 73, 78, 222, 20, 85, 167, 179, 38, 82, - 19, 11, 32, 16, 68, 5, 87, 73, 84, 72, 32, 218, 135, 1, 70, 238, 43, 73, - 199, 9, 77, 8, 206, 23, 84, 170, 225, 38, 82, 241, 32, 8, 73, 78, 86, 69, - 82, 84, 69, 68, 15, 11, 32, 12, 68, 5, 87, 73, 84, 72, 32, 186, 134, 1, - 70, 238, 43, 73, 199, 9, 77, 4, 174, 37, 84, 131, 228, 26, 68, 82, 78, - 65, 236, 5, 2, 69, 72, 161, 2, 9, 73, 71, 72, 32, 72, 65, 77, 90, 65, 34, - 34, 72, 249, 47, 3, 77, 90, 65, 31, 11, 32, 28, 68, 5, 87, 73, 84, 72, - 32, 210, 132, 1, 70, 238, 43, 73, 199, 9, 77, 20, 132, 2, 29, 69, 88, 84, - 69, 78, 68, 69, 68, 32, 65, 82, 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, - 32, 68, 73, 71, 73, 84, 32, 70, 30, 73, 92, 24, 83, 77, 65, 76, 76, 32, - 65, 82, 65, 66, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 84, 65, 72, 32, - 62, 84, 159, 52, 72, 2, 173, 186, 1, 2, 79, 85, 2, 45, 9, 78, 86, 69, 82, - 84, 69, 68, 32, 83, 2, 217, 150, 37, 6, 77, 65, 76, 76, 32, 86, 6, 26, - 65, 203, 165, 37, 66, 4, 222, 30, 78, 155, 168, 38, 66, 8, 88, 10, 72, - 82, 69, 69, 32, 68, 79, 84, 83, 32, 33, 8, 87, 79, 32, 68, 79, 84, 83, - 32, 4, 230, 8, 80, 139, 189, 38, 65, 4, 180, 197, 38, 8, 86, 69, 82, 84, - 73, 67, 65, 76, 27, 65, 41, 11, 32, 38, 144, 1, 4, 71, 79, 65, 76, 88, 5, - 87, 73, 84, 72, 32, 128, 47, 10, 68, 79, 65, 67, 72, 65, 83, 72, 77, 69, - 230, 78, 70, 238, 43, 73, 199, 9, 77, 13, 11, 32, 10, 180, 49, 6, 87, 73, - 84, 72, 32, 72, 250, 76, 70, 238, 43, 73, 199, 9, 77, 8, 134, 26, 73, - 237, 19, 3, 89, 69, 72, 9, 11, 32, 6, 138, 206, 23, 65, 238, 137, 9, 89, - 179, 233, 5, 87, 22, 28, 2, 69, 77, 167, 45, 72, 17, 11, 32, 14, 68, 6, - 87, 73, 84, 72, 32, 84, 138, 124, 70, 238, 43, 73, 199, 9, 77, 6, 166, - 214, 14, 87, 179, 201, 18, 72, 70, 98, 65, 204, 1, 4, 69, 72, 69, 72, - 176, 2, 7, 73, 82, 71, 72, 73, 90, 32, 197, 31, 2, 72, 65, 24, 46, 70, - 177, 162, 1, 5, 83, 72, 77, 73, 82, 23, 11, 32, 20, 64, 5, 87, 73, 84, - 72, 32, 130, 122, 70, 238, 43, 73, 199, 9, 77, 12, 42, 84, 134, 161, 35, - 68, 243, 201, 3, 82, 6, 222, 27, 87, 251, 241, 36, 72, 25, 11, 32, 22, - 64, 5, 87, 73, 84, 72, 32, 230, 120, 70, 238, 43, 73, 199, 9, 77, 14, 38, - 84, 234, 41, 83, 175, 144, 38, 68, 10, 60, 10, 72, 82, 69, 69, 32, 68, - 79, 84, 83, 32, 139, 26, 87, 6, 42, 80, 230, 155, 37, 66, 167, 161, 1, - 65, 2, 161, 140, 37, 14, 79, 73, 78, 84, 73, 78, 71, 32, 85, 80, 87, 65, - 82, 68, 12, 190, 39, 79, 13, 2, 89, 85, 26, 40, 2, 65, 77, 233, 170, 1, - 2, 79, 87, 25, 11, 32, 22, 64, 5, 87, 73, 84, 72, 32, 234, 117, 70, 238, - 43, 73, 199, 9, 77, 14, 88, 2, 68, 79, 36, 6, 83, 77, 65, 76, 76, 32, - 184, 152, 33, 2, 84, 72, 159, 253, 4, 66, 4, 146, 229, 17, 85, 155, 213, - 20, 84, 4, 196, 27, 16, 65, 82, 65, 66, 73, 67, 32, 76, 69, 84, 84, 69, - 82, 32, 84, 65, 199, 155, 39, 86, 18, 36, 3, 69, 69, 77, 231, 244, 38, - 65, 17, 11, 32, 14, 64, 5, 87, 73, 84, 72, 32, 146, 115, 70, 238, 43, 73, - 199, 9, 77, 6, 134, 18, 84, 187, 136, 35, 68, 60, 38, 71, 26, 89, 17, 3, - 79, 79, 78, 21, 22, 79, 235, 109, 32, 10, 239, 26, 69, 31, 11, 32, 28, - 92, 5, 71, 72, 85, 78, 78, 16, 5, 87, 73, 84, 72, 32, 166, 113, 70, 238, - 43, 73, 199, 9, 77, 6, 251, 33, 65, 14, 116, 6, 83, 77, 65, 76, 76, 32, - 38, 84, 176, 24, 8, 73, 78, 86, 69, 82, 84, 69, 68, 210, 218, 26, 68, - 171, 238, 11, 82, 4, 206, 210, 32, 84, 131, 224, 6, 86, 4, 246, 245, 6, - 72, 191, 142, 30, 87, 25, 22, 32, 143, 24, 69, 12, 88, 11, 87, 73, 84, - 72, 32, 83, 77, 65, 76, 76, 32, 242, 110, 70, 238, 43, 73, 199, 9, 77, 4, - 26, 77, 251, 176, 39, 86, 2, 241, 179, 38, 3, 69, 69, 77, 19, 11, 32, 16, - 64, 5, 87, 73, 84, 72, 32, 230, 109, 70, 238, 43, 73, 199, 9, 77, 8, 36, - 4, 68, 79, 84, 32, 183, 12, 84, 6, 44, 5, 66, 69, 76, 79, 87, 199, 178, - 38, 65, 5, 169, 199, 14, 6, 32, 65, 78, 68, 32, 78, 52, 108, 2, 69, 72, - 184, 28, 3, 82, 69, 72, 252, 2, 4, 78, 79, 79, 78, 205, 118, 7, 79, 72, - 73, 78, 71, 89, 65, 35, 11, 32, 32, 52, 5, 87, 73, 84, 72, 32, 174, 107, - 70, 255, 52, 73, 28, 134, 1, 83, 96, 2, 84, 87, 234, 5, 73, 230, 22, 72, - 206, 180, 11, 70, 144, 133, 7, 5, 68, 79, 84, 32, 66, 234, 39, 76, 215, - 220, 19, 82, 10, 44, 5, 77, 65, 76, 76, 32, 171, 252, 38, 84, 8, 198, 6, - 65, 186, 226, 6, 78, 135, 203, 16, 86, 4, 37, 7, 79, 32, 68, 79, 84, 83, - 32, 4, 166, 8, 86, 175, 166, 38, 65, 60, 184, 1, 2, 65, 68, 120, 3, 69, - 69, 78, 136, 6, 4, 72, 69, 69, 78, 204, 148, 1, 4, 85, 80, 69, 82, 180, - 172, 4, 7, 84, 82, 65, 73, 71, 72, 84, 181, 224, 32, 6, 87, 65, 83, 72, - 32, 75, 17, 11, 32, 14, 68, 6, 87, 73, 84, 72, 32, 84, 238, 102, 70, 238, - 43, 73, 199, 9, 77, 6, 186, 138, 33, 72, 223, 240, 3, 87, 27, 11, 32, 24, - 64, 5, 87, 73, 84, 72, 32, 250, 101, 70, 238, 43, 73, 199, 9, 77, 16, - 232, 1, 3, 68, 79, 84, 50, 73, 48, 7, 83, 77, 65, 76, 76, 32, 65, 110, - 84, 150, 202, 11, 70, 221, 152, 5, 31, 69, 88, 84, 69, 78, 68, 69, 68, - 32, 65, 82, 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, 32, 68, 73, 71, 73, - 84, 32, 70, 79, 85, 2, 149, 209, 18, 7, 32, 66, 69, 76, 79, 87, 32, 2, - 173, 186, 17, 7, 78, 86, 69, 82, 84, 69, 68, 2, 85, 19, 82, 65, 66, 73, - 67, 32, 76, 69, 84, 84, 69, 82, 32, 84, 65, 72, 32, 65, 78, 2, 179, 247, - 22, 68, 6, 96, 11, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 66, 105, 9, - 87, 79, 32, 68, 79, 84, 83, 32, 86, 4, 25, 4, 69, 76, 79, 87, 5, 11, 32, - 2, 21, 3, 65, 78, 68, 2, 17, 2, 32, 84, 2, 247, 230, 6, 72, 2, 237, 198, - 11, 8, 69, 82, 84, 73, 67, 65, 76, 76, 13, 11, 32, 10, 46, 87, 134, 96, - 70, 238, 43, 73, 199, 9, 77, 2, 249, 226, 26, 5, 73, 84, 72, 32, 68, 120, - 92, 2, 65, 72, 132, 2, 4, 67, 72, 69, 72, 124, 2, 69, 72, 150, 3, 72, 61, - 3, 84, 69, 72, 21, 11, 32, 18, 64, 5, 87, 73, 84, 72, 32, 174, 94, 70, - 238, 43, 73, 199, 9, 77, 10, 26, 84, 139, 225, 26, 68, 8, 26, 87, 199, - 129, 33, 72, 4, 37, 7, 79, 32, 68, 79, 84, 83, 32, 4, 48, 6, 86, 69, 82, - 84, 73, 67, 211, 162, 38, 65, 2, 165, 195, 11, 3, 65, 76, 76, 25, 22, 32, - 163, 5, 69, 12, 64, 5, 87, 73, 84, 72, 32, 158, 92, 70, 238, 43, 73, 199, - 9, 77, 4, 198, 13, 83, 175, 144, 38, 68, 37, 22, 32, 167, 4, 69, 24, 62, - 77, 116, 5, 87, 73, 84, 72, 32, 178, 90, 70, 239, 43, 73, 10, 48, 6, 65, - 82, 66, 85, 84, 65, 175, 144, 1, 69, 9, 11, 32, 6, 226, 90, 70, 254, 52, - 73, 233, 131, 37, 2, 71, 79, 8, 104, 6, 83, 77, 65, 76, 76, 32, 56, 12, - 84, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 65, 175, 202, 38, 82, 4, 32, - 2, 84, 69, 199, 155, 39, 86, 2, 191, 158, 38, 72, 2, 161, 233, 27, 4, 66, - 79, 86, 69, 18, 42, 65, 126, 69, 209, 129, 1, 2, 73, 78, 6, 131, 9, 76, - 23, 18, 32, 91, 69, 10, 60, 4, 87, 73, 84, 72, 218, 87, 70, 238, 43, 73, - 199, 9, 77, 2, 129, 9, 2, 32, 83, 10, 131, 11, 72, 15, 158, 1, 32, 169, - 80, 33, 73, 71, 72, 85, 82, 32, 75, 65, 90, 65, 75, 72, 32, 75, 73, 82, - 71, 72, 73, 90, 32, 65, 76, 69, 70, 32, 77, 65, 75, 83, 85, 82, 65, 8, - 96, 16, 87, 73, 84, 72, 32, 72, 65, 77, 90, 65, 32, 65, 66, 79, 86, 69, - 174, 85, 70, 255, 52, 73, 5, 143, 75, 32, 17, 222, 8, 72, 167, 76, 32, - 25, 11, 32, 22, 52, 5, 87, 73, 84, 72, 32, 190, 84, 70, 255, 52, 73, 18, - 80, 4, 68, 79, 84, 32, 162, 2, 69, 182, 1, 72, 170, 170, 14, 84, 143, - 151, 24, 82, 4, 164, 152, 31, 3, 87, 73, 84, 251, 128, 7, 65, 54, 28, 2, - 69, 72, 227, 3, 85, 49, 11, 32, 46, 100, 6, 66, 65, 82, 82, 69, 69, 252, - 2, 5, 87, 73, 84, 72, 32, 170, 79, 70, 238, 43, 73, 199, 9, 77, 17, 11, - 32, 14, 52, 5, 87, 73, 84, 72, 32, 226, 81, 70, 255, 52, 73, 10, 22, 69, - 183, 1, 72, 4, 121, 28, 88, 84, 69, 78, 68, 69, 68, 32, 65, 82, 65, 66, - 73, 67, 45, 73, 78, 68, 73, 67, 32, 68, 73, 71, 73, 84, 32, 84, 4, 184, - 239, 35, 3, 72, 82, 69, 177, 166, 2, 2, 87, 79, 6, 21, 3, 65, 77, 90, 6, - 11, 65, 6, 17, 2, 32, 65, 6, 21, 3, 66, 79, 86, 6, 11, 69, 7, 159, 79, - 32, 22, 64, 10, 72, 65, 77, 90, 65, 32, 65, 66, 79, 86, 18, 83, 39, 84, - 10, 167, 2, 69, 2, 165, 165, 17, 4, 77, 65, 76, 76, 10, 108, 18, 87, 79, - 32, 68, 79, 84, 83, 32, 66, 69, 76, 79, 87, 32, 65, 78, 68, 32, 146, 220, - 36, 65, 183, 5, 72, 6, 70, 72, 132, 204, 6, 7, 83, 77, 65, 76, 76, 32, - 78, 207, 194, 31, 68, 2, 169, 236, 33, 3, 65, 77, 90, 18, 26, 72, 17, 2, - 73, 78, 11, 243, 71, 32, 9, 11, 32, 6, 158, 76, 70, 254, 52, 73, 157, 11, - 13, 87, 73, 84, 72, 32, 73, 78, 86, 69, 82, 84, 69, 68, 220, 7, 230, 5, - 65, 158, 5, 66, 176, 2, 9, 68, 65, 68, 32, 87, 73, 84, 72, 32, 80, 9, 70, - 69, 72, 32, 87, 73, 84, 72, 32, 72, 11, 71, 72, 65, 73, 78, 32, 87, 73, - 84, 72, 32, 154, 1, 72, 134, 3, 74, 190, 2, 75, 252, 1, 9, 76, 65, 77, - 32, 87, 73, 84, 72, 32, 226, 4, 77, 152, 4, 10, 78, 79, 79, 78, 32, 87, - 73, 84, 72, 32, 182, 2, 81, 190, 2, 82, 178, 2, 83, 146, 16, 84, 196, 9, - 7, 87, 65, 83, 65, 76, 76, 65, 40, 9, 89, 69, 72, 32, 87, 73, 84, 72, 32, - 216, 3, 53, 85, 73, 71, 72, 85, 82, 32, 75, 73, 82, 71, 72, 73, 90, 32, - 89, 69, 72, 32, 87, 73, 84, 72, 32, 72, 65, 77, 90, 65, 32, 65, 66, 79, - 86, 69, 32, 87, 73, 84, 72, 32, 65, 76, 69, 70, 32, 77, 65, 75, 83, 85, - 82, 65, 205, 6, 14, 90, 65, 72, 32, 87, 73, 84, 72, 32, 77, 69, 69, 77, - 32, 54, 128, 1, 8, 73, 78, 32, 87, 73, 84, 72, 32, 70, 76, 232, 57, 4, - 75, 66, 65, 82, 129, 197, 36, 8, 90, 90, 65, 32, 87, 65, 32, 74, 28, 152, - 19, 4, 77, 69, 69, 77, 150, 16, 74, 238, 23, 65, 255, 8, 89, 22, 56, 3, - 65, 89, 72, 216, 1, 3, 69, 70, 32, 207, 13, 76, 12, 30, 73, 122, 65, 151, - 56, 69, 8, 52, 9, 32, 65, 83, 45, 83, 65, 76, 65, 65, 47, 77, 4, 80, 4, - 84, 85, 32, 87, 207, 132, 39, 77, 4, 18, 65, 23, 32, 2, 17, 2, 65, 32, 2, - 137, 142, 33, 6, 65, 83, 45, 83, 65, 76, 8, 212, 65, 29, 77, 65, 75, 83, - 85, 82, 65, 32, 87, 73, 84, 72, 32, 83, 85, 80, 69, 82, 83, 67, 82, 73, - 80, 84, 32, 65, 76, 69, 70, 1, 13, 87, 73, 84, 72, 32, 70, 65, 84, 72, - 65, 84, 65, 78, 44, 160, 1, 8, 69, 72, 32, 87, 73, 84, 72, 32, 177, 222, - 25, 25, 73, 83, 77, 73, 76, 76, 65, 72, 32, 65, 82, 45, 82, 65, 72, 77, - 65, 78, 32, 65, 82, 45, 82, 65, 72, 42, 98, 72, 24, 3, 75, 72, 65, 230, - 52, 65, 250, 3, 74, 78, 77, 86, 78, 78, 90, 242, 2, 82, 43, 89, 10, 22, - 65, 171, 56, 69, 6, 131, 59, 72, 36, 222, 6, 72, 158, 7, 75, 218, 38, 65, - 250, 3, 74, 2, 77, 134, 5, 82, 3, 89, 30, 170, 13, 75, 218, 38, 65, 250, + 32, 6, 166, 138, 41, 66, 2, 71, 3, 84, 10, 60, 4, 73, 71, 78, 32, 241, + 190, 23, 5, 89, 77, 66, 79, 76, 8, 50, 83, 182, 129, 26, 75, 197, 150, + 10, 2, 82, 85, 4, 160, 137, 38, 4, 77, 65, 76, 76, 203, 177, 2, 69, 22, + 66, 65, 214, 179, 37, 85, 186, 202, 1, 73, 198, 140, 2, 69, 3, 79, 11, + 206, 138, 41, 65, 2, 73, 2, 77, 3, 87, 7, 11, 32, 4, 180, 235, 35, 3, 68, + 69, 80, 221, 205, 4, 5, 65, 82, 82, 73, 86, 152, 2, 212, 1, 4, 65, 82, + 77, 32, 48, 20, 67, 72, 69, 77, 73, 67, 65, 76, 32, 83, 89, 77, 66, 79, + 76, 32, 70, 79, 82, 32, 166, 28, 69, 60, 4, 73, 69, 78, 32, 208, 3, 2, + 76, 32, 82, 77, 109, 6, 84, 69, 82, 78, 65, 84, 4, 136, 140, 14, 3, 66, + 69, 76, 227, 137, 24, 67, 232, 1, 158, 2, 65, 246, 2, 66, 210, 1, 67, + 138, 3, 68, 98, 71, 38, 72, 132, 1, 4, 73, 82, 79, 78, 82, 76, 74, 77, + 144, 1, 2, 78, 73, 34, 80, 176, 2, 3, 81, 85, 73, 74, 82, 146, 2, 83, + 210, 5, 84, 166, 1, 86, 200, 1, 2, 87, 65, 198, 162, 35, 85, 154, 220, 1, + 69, 194, 212, 1, 70, 219, 56, 79, 30, 194, 1, 76, 72, 3, 81, 85, 65, 204, + 8, 7, 78, 84, 73, 77, 79, 78, 89, 224, 157, 3, 3, 77, 65, 76, 240, 200, + 21, 3, 82, 83, 69, 204, 245, 13, 5, 85, 82, 73, 80, 73, 162, 136, 1, 83, + 183, 93, 73, 8, 224, 24, 2, 69, 77, 188, 213, 26, 4, 75, 65, 76, 73, 235, + 132, 14, 85, 10, 38, 32, 233, 136, 25, 3, 70, 79, 82, 8, 216, 7, 4, 86, + 73, 84, 65, 189, 191, 23, 4, 82, 69, 71, 73, 16, 148, 1, 7, 65, 84, 72, + 32, 79, 70, 32, 204, 6, 6, 73, 83, 77, 85, 84, 72, 144, 1, 4, 79, 82, 65, + 88, 164, 1, 4, 76, 65, 67, 75, 139, 198, 39, 82, 4, 218, 140, 17, 77, + 205, 227, 22, 5, 86, 65, 80, 79, 85, 28, 82, 65, 92, 6, 79, 80, 80, 69, + 82, 32, 34, 82, 201, 219, 39, 4, 73, 78, 78, 65, 6, 216, 143, 6, 2, 68, + 85, 140, 197, 33, 9, 80, 85, 84, 32, 77, 79, 82, 84, 85, 231, 28, 76, 4, + 230, 13, 65, 143, 207, 39, 79, 16, 72, 8, 79, 67, 85, 83, 32, 79, 70, 32, + 53, 6, 85, 67, 73, 66, 76, 69, 6, 228, 16, 5, 67, 79, 80, 80, 69, 171, + 198, 39, 73, 11, 11, 45, 8, 130, 254, 40, 50, 2, 51, 2, 52, 3, 53, 8, 44, + 2, 73, 83, 197, 255, 37, 3, 65, 89, 45, 6, 144, 2, 4, 83, 79, 76, 86, + 195, 255, 37, 84, 4, 170, 205, 30, 79, 247, 158, 10, 85, 8, 32, 4, 65, + 76, 70, 32, 47, 79, 4, 144, 236, 35, 2, 79, 85, 131, 211, 3, 68, 4, 200, + 137, 3, 4, 82, 83, 69, 32, 223, 185, 37, 85, 6, 56, 3, 32, 79, 82, 73, 7, + 45, 67, 79, 80, 80, 69, 82, 4, 211, 229, 26, 69, 4, 48, 3, 69, 65, 68, + 209, 233, 13, 3, 79, 68, 69, 2, 187, 141, 36, 32, 10, 120, 16, 69, 82, + 67, 85, 82, 89, 32, 83, 85, 66, 76, 73, 77, 65, 84, 69, 252, 217, 16, 4, + 65, 82, 67, 65, 191, 154, 22, 79, 7, 199, 248, 40, 45, 4, 234, 214, 39, + 84, 135, 120, 71, 14, 108, 11, 72, 73, 76, 79, 83, 79, 80, 72, 69, 82, + 83, 34, 79, 98, 85, 153, 177, 30, 6, 82, 69, 67, 73, 80, 73, 2, 209, 9, + 4, 32, 83, 85, 76, 6, 52, 4, 87, 68, 69, 82, 133, 189, 36, 3, 84, 32, 65, + 5, 173, 197, 39, 5, 69, 68, 32, 66, 82, 4, 252, 182, 34, 4, 84, 82, 69, + 70, 209, 174, 6, 3, 82, 73, 70, 4, 164, 229, 35, 5, 78, 84, 69, 83, 83, + 181, 247, 3, 4, 67, 75, 32, 76, 24, 58, 69, 149, 224, 26, 8, 79, 67, 75, + 32, 83, 65, 76, 84, 20, 68, 5, 71, 85, 76, 85, 83, 164, 7, 3, 65, 76, 71, + 163, 171, 26, 84, 15, 32, 4, 32, 79, 70, 32, 71, 45, 6, 164, 223, 26, 8, + 65, 78, 84, 73, 77, 79, 78, 89, 143, 238, 12, 73, 6, 162, 244, 40, 50, 2, + 51, 3, 52, 34, 164, 1, 2, 65, 76, 194, 1, 84, 142, 1, 85, 180, 226, 17, + 2, 80, 73, 156, 186, 12, 2, 73, 76, 182, 192, 9, 79, 169, 22, 11, 67, 69, + 80, 84, 69, 82, 32, 79, 70, 32, 74, 8, 58, 84, 141, 200, 39, 8, 45, 65, + 77, 77, 79, 78, 73, 65, 7, 25, 4, 32, 79, 70, 32, 4, 52, 8, 67, 79, 80, + 80, 69, 82, 32, 65, 231, 5, 65, 2, 209, 171, 30, 7, 78, 84, 73, 77, 79, + 78, 73, 6, 236, 3, 8, 65, 82, 82, 69, 68, 32, 84, 82, 233, 215, 26, 19, + 82, 65, 84, 85, 77, 32, 83, 85, 80, 69, 82, 32, 83, 84, 82, 65, 84, 85, + 77, 12, 44, 6, 66, 76, 73, 77, 65, 84, 155, 1, 76, 10, 44, 5, 69, 32, 79, + 70, 32, 195, 159, 40, 73, 8, 68, 8, 83, 65, 76, 84, 32, 79, 70, 32, 130, + 3, 65, 231, 214, 27, 67, 4, 254, 2, 65, 231, 214, 27, 67, 2, 239, 245, + 39, 70, 12, 68, 3, 65, 82, 84, 32, 2, 73, 78, 34, 82, 201, 253, 38, 2, + 85, 84, 4, 11, 65, 4, 155, 216, 26, 82, 4, 254, 206, 35, 67, 187, 49, 32, + 2, 253, 169, 40, 2, 73, 68, 14, 50, 73, 209, 197, 38, 6, 69, 82, 68, 73, + 71, 82, 12, 64, 5, 78, 69, 71, 65, 82, 213, 214, 26, 5, 84, 82, 73, 79, + 76, 9, 44, 5, 32, 79, 70, 32, 65, 243, 234, 40, 45, 2, 141, 186, 24, 3, + 78, 84, 73, 4, 214, 173, 40, 84, 239, 61, 88, 6, 38, 77, 186, 213, 39, + 70, 155, 121, 82, 2, 223, 192, 39, 66, 22, 104, 7, 77, 79, 78, 83, 84, + 69, 82, 138, 1, 83, 205, 129, 36, 10, 67, 82, 65, 66, 32, 83, 84, 69, 80, + 80, 11, 11, 32, 8, 88, 6, 67, 76, 79, 83, 69, 68, 0, 4, 79, 80, 69, 78, + 173, 227, 36, 4, 83, 84, 69, 80, 2, 145, 138, 38, 3, 32, 74, 65, 8, 60, + 6, 80, 73, 68, 69, 82, 32, 57, 5, 81, 85, 73, 68, 32, 4, 196, 195, 29, 5, + 67, 82, 79, 85, 67, 175, 250, 1, 83, 4, 56, 6, 67, 76, 79, 83, 69, 68, 1, + 4, 79, 80, 69, 78, 2, 197, 249, 27, 5, 32, 84, 69, 78, 84, 4, 210, 133, + 34, 69, 253, 184, 4, 11, 65, 82, 79, 85, 78, 68, 45, 80, 82, 79, 70, 9, + 49, 10, 79, 83, 84, 32, 69, 81, 85, 65, 76, 32, 6, 32, 2, 84, 79, 247, + 198, 32, 79, 5, 219, 255, 6, 32, 4, 136, 247, 10, 3, 73, 86, 69, 221, + 195, 28, 5, 69, 32, 79, 78, 69, 12, 162, 1, 80, 128, 208, 29, 6, 69, 82, + 73, 67, 65, 78, 204, 131, 6, 3, 66, 85, 76, 245, 254, 3, 16, 65, 76, 71, + 65, 77, 65, 84, 73, 79, 78, 32, 79, 82, 32, 67, 79, 6, 26, 72, 251, 144, + 37, 69, 4, 204, 254, 24, 3, 73, 84, 82, 203, 160, 15, 79, 194, 9, 92, 3, + 65, 84, 79, 182, 20, 71, 174, 1, 84, 190, 161, 25, 67, 190, 155, 12, 68, + 223, 142, 3, 75, 144, 9, 112, 17, 76, 73, 65, 78, 32, 72, 73, 69, 82, 79, + 71, 76, 89, 80, 72, 32, 65, 145, 218, 39, 5, 77, 73, 67, 65, 76, 142, 9, + 70, 48, 138, 4, 49, 198, 2, 50, 162, 3, 51, 174, 5, 52, 163, 3, 53, 222, + 1, 106, 50, 102, 52, 110, 54, 102, 57, 182, 7, 51, 254, 246, 11, 49, 142, + 159, 23, 48, 130, 2, 53, 2, 55, 3, 56, 22, 158, 206, 36, 54, 242, 145, 4, + 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 28, 202, 191, + 12, 54, 242, 141, 24, 49, 2, 53, 242, 145, 4, 48, 2, 50, 2, 51, 2, 52, 2, + 55, 2, 56, 3, 57, 26, 162, 166, 12, 54, 158, 184, 28, 48, 2, 49, 2, 50, + 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 24, 234, 203, 36, 55, 2, 56, + 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 57, 232, 1, + 98, 48, 114, 49, 206, 170, 12, 50, 2, 51, 182, 242, 22, 52, 2, 53, 2, 54, + 2, 55, 2, 56, 3, 57, 42, 242, 163, 12, 52, 2, 55, 190, 24, 53, 242, 141, + 24, 48, 2, 49, 2, 50, 242, 145, 4, 51, 2, 54, 2, 56, 3, 57, 26, 190, 187, + 12, 48, 242, 141, 24, 53, 242, 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, + 55, 2, 56, 3, 57, 222, 1, 102, 48, 110, 49, 102, 57, 210, 1, 56, 250, + 152, 12, 50, 2, 54, 146, 255, 22, 51, 2, 52, 2, 53, 3, 55, 28, 230, 185, + 12, 50, 242, 141, 24, 55, 2, 57, 242, 145, 4, 48, 2, 49, 2, 51, 2, 52, 2, + 53, 2, 54, 3, 56, 24, 234, 198, 36, 53, 2, 54, 242, 145, 4, 48, 2, 49, 2, + 50, 2, 51, 2, 52, 2, 55, 2, 56, 3, 57, 24, 134, 198, 36, 52, 2, 57, 242, + 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 53, 2, 54, 2, 55, 3, 56, 228, 1, 102, + 48, 2, 50, 2, 53, 102, 51, 110, 54, 102, 56, 162, 1, 57, 174, 129, 12, + 55, 138, 147, 23, 49, 3, 52, 22, 182, 196, 36, 57, 242, 145, 4, 48, 2, + 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 30, 166, 157, 12, + 54, 226, 204, 8, 50, 190, 235, 19, 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, 55, + 2, 56, 3, 57, 24, 230, 194, 36, 52, 2, 56, 242, 145, 4, 48, 2, 49, 2, 50, + 2, 51, 2, 53, 2, 54, 2, 55, 3, 57, 26, 98, 51, 162, 193, 36, 49, 2, 54, + 242, 145, 4, 48, 2, 50, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 4, 196, 154, + 21, 6, 32, 82, 65, 32, 79, 82, 203, 184, 19, 65, 20, 128, 168, 40, 3, 51, + 32, 69, 210, 42, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, + 57, 202, 1, 102, 49, 210, 1, 53, 178, 241, 20, 57, 222, 159, 14, 48, 2, + 50, 2, 51, 2, 52, 2, 54, 2, 55, 3, 56, 22, 90, 48, 162, 208, 40, 49, 2, + 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 4, 60, 6, 32, 66, + 69, 71, 73, 78, 1, 5, 65, 32, 69, 78, 68, 2, 241, 201, 16, 8, 32, 76, 79, + 71, 79, 71, 82, 65, 24, 186, 189, 36, 48, 2, 55, 242, 145, 4, 49, 2, 50, + 2, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 60, 226, 167, 33, 51, 198, 230, + 1, 48, 130, 2, 49, 3, 50, 14, 96, 2, 76, 69, 182, 176, 2, 85, 128, 200, + 32, 2, 83, 84, 130, 239, 3, 69, 217, 168, 1, 2, 82, 89, 7, 33, 6, 32, 87, + 73, 84, 72, 32, 4, 254, 154, 32, 83, 135, 195, 4, 85, 31, 76, 4, 69, 78, + 78, 65, 41, 11, 73, 67, 76, 79, 67, 75, 87, 73, 83, 69, 32, 5, 253, 159, + 37, 5, 32, 87, 73, 84, 72, 24, 90, 84, 162, 143, 7, 67, 58, 68, 122, 71, + 138, 4, 79, 233, 163, 28, 5, 73, 78, 84, 69, 71, 12, 84, 15, 82, 73, 65, + 78, 71, 76, 69, 45, 72, 69, 65, 68, 69, 68, 32, 223, 147, 7, 79, 10, 112, + 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 12, 6, 66, 79, 84, 84, 79, 77, 0, 3, + 84, 79, 80, 131, 147, 7, 79, 2, 11, 84, 2, 209, 235, 37, 7, 32, 85, 45, + 83, 72, 65, 80, 160, 1, 128, 1, 20, 76, 32, 70, 85, 78, 67, 84, 73, 79, + 78, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 206, 15, 79, 38, 80, 147, + 184, 40, 67, 140, 1, 222, 2, 67, 186, 1, 68, 190, 2, 73, 44, 4, 65, 76, + 80, 72, 0, 4, 79, 77, 69, 71, 32, 4, 74, 79, 84, 32, 36, 4, 76, 69, 70, + 84, 68, 2, 81, 85, 218, 3, 82, 54, 83, 92, 4, 69, 80, 83, 73, 32, 6, 66, + 65, 67, 75, 83, 76, 76, 2, 85, 80, 172, 170, 16, 12, 71, 82, 69, 65, 84, + 69, 82, 45, 84, 72, 65, 78, 0, 5, 84, 73, 76, 68, 69, 163, 168, 20, 90, + 14, 64, 6, 73, 82, 67, 76, 69, 32, 133, 161, 39, 4, 79, 77, 77, 65, 12, + 80, 2, 83, 84, 166, 242, 19, 68, 226, 137, 6, 66, 254, 216, 10, 85, 207, + 158, 3, 74, 4, 198, 157, 39, 73, 227, 109, 65, 22, 76, 2, 69, 76, 120, 3, + 79, 87, 78, 201, 162, 32, 6, 73, 65, 77, 79, 78, 68, 10, 30, 32, 53, 3, + 84, 65, 32, 6, 146, 241, 19, 68, 142, 234, 16, 84, 131, 191, 1, 83, 4, + 186, 211, 36, 85, 179, 198, 1, 83, 10, 22, 32, 167, 9, 87, 8, 52, 5, 84, + 65, 67, 75, 32, 182, 1, 83, 227, 6, 67, 4, 198, 210, 36, 85, 207, 158, 3, + 74, 6, 40, 2, 79, 84, 185, 176, 32, 2, 45, 66, 4, 11, 65, 5, 167, 161, + 32, 32, 4, 250, 238, 19, 68, 223, 226, 16, 85, 4, 28, 2, 32, 83, 187, 7, + 87, 2, 181, 151, 38, 4, 72, 79, 69, 32, 46, 44, 2, 65, 68, 133, 3, 4, 79, + 84, 69, 32, 43, 11, 32, 40, 178, 1, 67, 38, 68, 92, 2, 85, 80, 36, 2, 76, + 69, 210, 208, 6, 81, 228, 229, 13, 3, 78, 79, 84, 22, 69, 154, 190, 5, + 66, 174, 163, 7, 83, 226, 142, 5, 71, 250, 115, 82, 199, 81, 74, 4, 246, + 233, 38, 73, 151, 132, 1, 79, 12, 54, 73, 36, 3, 79, 87, 78, 225, 128, + 37, 2, 69, 76, 4, 202, 139, 32, 86, 255, 242, 6, 65, 4, 230, 138, 4, 32, + 211, 144, 35, 87, 4, 166, 167, 38, 83, 215, 115, 70, 4, 154, 181, 12, 81, + 163, 152, 24, 85, 4, 184, 3, 5, 73, 71, 72, 84, 87, 239, 153, 40, 72, 10, + 88, 5, 69, 77, 73, 67, 79, 34, 76, 34, 84, 169, 179, 12, 7, 81, 85, 73, + 83, 72, 32, 81, 2, 181, 155, 32, 3, 76, 79, 78, 2, 149, 151, 39, 3, 65, + 83, 72, 4, 212, 170, 16, 2, 65, 82, 175, 173, 7, 73, 12, 22, 32, 171, 1, + 87, 10, 78, 67, 36, 5, 84, 65, 67, 75, 32, 221, 232, 39, 6, 83, 72, 79, + 69, 32, 74, 2, 129, 215, 23, 4, 65, 82, 69, 84, 6, 178, 231, 19, 68, 234, + 159, 17, 79, 195, 225, 2, 74, 2, 221, 151, 37, 6, 65, 82, 68, 83, 32, 86, + 4, 182, 145, 34, 83, 135, 215, 5, 76, 14, 26, 76, 93, 2, 82, 79, 4, 164, + 201, 26, 14, 73, 67, 65, 84, 73, 79, 78, 32, 80, 82, 79, 71, 82, 65, 139, + 217, 12, 69, 10, 112, 9, 88, 73, 77, 65, 84, 69, 76, 89, 32, 237, 153, + 40, 13, 65, 67, 72, 69, 83, 32, 84, 72, 69, 32, 76, 73, 77, 8, 76, 6, 69, + 81, 85, 65, 76, 32, 137, 156, 25, 7, 66, 85, 84, 32, 78, 79, 84, 6, 32, + 2, 84, 79, 183, 150, 32, 79, 5, 237, 201, 26, 13, 32, 79, 82, 32, 84, 72, + 69, 32, 73, 77, 65, 71, 69, 192, 23, 148, 1, 4, 65, 66, 73, 67, 240, 131, + 2, 7, 77, 69, 78, 73, 65, 78, 32, 224, 12, 3, 82, 79, 87, 228, 3, 2, 84, + 73, 150, 137, 37, 73, 135, 150, 1, 67, 238, 21, 54, 32, 173, 130, 2, 7, + 45, 73, 78, 68, 73, 67, 32, 210, 21, 150, 3, 66, 134, 1, 67, 238, 1, 68, + 138, 3, 69, 186, 1, 70, 212, 1, 2, 72, 65, 104, 5, 75, 65, 83, 82, 65, + 86, 76, 212, 180, 1, 2, 77, 65, 204, 18, 7, 78, 85, 77, 66, 69, 82, 32, + 36, 5, 79, 80, 69, 78, 32, 82, 80, 238, 1, 82, 208, 2, 6, 73, 78, 86, 69, + 82, 84, 98, 83, 146, 33, 84, 202, 4, 86, 228, 206, 17, 9, 87, 65, 86, 89, + 32, 72, 65, 77, 90, 230, 142, 18, 81, 197, 198, 1, 6, 90, 87, 65, 82, 65, + 75, 4, 216, 214, 1, 7, 65, 83, 69, 76, 73, 78, 69, 233, 205, 37, 17, 73, + 66, 76, 73, 67, 65, 76, 32, 69, 78, 68, 32, 79, 70, 32, 86, 69, 16, 44, + 2, 79, 77, 81, 5, 85, 82, 76, 89, 32, 4, 192, 193, 19, 11, 66, 73, 78, + 73, 78, 71, 32, 65, 76, 69, 70, 199, 234, 20, 77, 12, 72, 4, 68, 65, 77, + 77, 0, 4, 70, 65, 84, 72, 1, 4, 75, 65, 83, 82, 4, 11, 65, 5, 251, 224, + 38, 84, 26, 158, 1, 65, 108, 5, 79, 85, 66, 76, 69, 216, 246, 23, 5, 69, + 67, 73, 77, 65, 149, 198, 9, 16, 73, 83, 80, 85, 84, 69, 68, 32, 69, 78, + 68, 32, 79, 70, 32, 65, 14, 36, 3, 77, 77, 65, 231, 223, 33, 84, 13, 22, + 32, 219, 5, 84, 6, 242, 238, 1, 73, 54, 77, 251, 149, 37, 87, 8, 22, 32, + 191, 4, 68, 6, 184, 210, 1, 17, 82, 73, 71, 72, 84, 32, 65, 82, 82, 79, + 87, 72, 69, 65, 68, 32, 65, 191, 30, 86, 8, 88, 12, 77, 80, 84, 89, 32, + 67, 69, 78, 84, 82, 69, 32, 57, 6, 78, 68, 32, 79, 70, 32, 4, 140, 212, + 37, 4, 72, 73, 71, 72, 1, 3, 76, 79, 87, 4, 210, 139, 30, 84, 139, 175, + 3, 65, 22, 84, 4, 65, 84, 72, 65, 166, 222, 1, 79, 148, 232, 4, 3, 73, + 86, 69, 143, 140, 31, 85, 17, 22, 32, 139, 2, 84, 10, 52, 5, 87, 73, 84, + 72, 32, 238, 234, 1, 73, 55, 77, 6, 170, 212, 38, 84, 166, 82, 68, 203, + 47, 82, 6, 72, 13, 76, 70, 32, 77, 65, 68, 68, 65, 32, 79, 86, 69, 82, + 235, 16, 77, 2, 221, 238, 17, 2, 32, 77, 13, 18, 32, 43, 84, 6, 166, 72, + 87, 158, 161, 1, 73, 55, 77, 4, 253, 82, 2, 65, 78, 174, 16, 84, 5, 65, + 82, 71, 69, 32, 146, 1, 69, 133, 91, 8, 73, 71, 65, 84, 85, 82, 69, 32, + 8, 64, 10, 82, 79, 85, 78, 68, 32, 68, 79, 84, 32, 179, 143, 11, 67, 6, + 148, 143, 11, 6, 73, 78, 83, 73, 68, 69, 146, 243, 26, 66, 131, 165, 1, + 65, 136, 8, 80, 5, 84, 84, 69, 82, 32, 137, 174, 7, 9, 70, 84, 32, 65, + 82, 82, 79, 87, 72, 132, 8, 210, 2, 65, 240, 10, 2, 66, 69, 150, 4, 68, + 186, 5, 70, 246, 4, 71, 226, 2, 72, 156, 9, 2, 74, 69, 158, 1, 75, 138, + 5, 76, 226, 2, 77, 154, 1, 78, 160, 3, 3, 80, 69, 72, 176, 1, 3, 81, 65, + 70, 214, 1, 82, 234, 3, 83, 162, 9, 84, 214, 8, 85, 148, 2, 2, 86, 69, + 28, 3, 87, 65, 87, 202, 1, 89, 246, 3, 79, 140, 3, 2, 90, 65, 31, 69, + 112, 92, 7, 70, 82, 73, 67, 65, 78, 32, 92, 2, 73, 78, 144, 2, 3, 76, 69, + 70, 207, 156, 40, 69, 8, 52, 3, 81, 65, 70, 166, 169, 33, 70, 183, 203, + 3, 78, 5, 153, 64, 5, 32, 87, 73, 84, 72, 21, 11, 32, 18, 72, 6, 87, 73, + 84, 72, 32, 84, 242, 172, 1, 70, 202, 43, 73, 211, 9, 77, 10, 60, 10, 72, + 82, 69, 69, 32, 68, 79, 84, 83, 32, 187, 54, 87, 6, 220, 154, 15, 17, 80, + 79, 73, 78, 84, 73, 78, 71, 32, 68, 79, 87, 78, 87, 65, 82, 68, 250, 224, + 22, 66, 131, 165, 1, 65, 83, 11, 32, 80, 70, 87, 228, 44, 6, 77, 65, 75, + 83, 85, 82, 130, 126, 70, 231, 52, 73, 70, 48, 4, 73, 84, 72, 32, 177, + 44, 3, 65, 83, 76, 64, 192, 2, 9, 65, 84, 84, 65, 67, 72, 69, 68, 32, + 220, 1, 19, 82, 73, 71, 72, 84, 32, 77, 73, 68, 68, 76, 69, 32, 83, 84, + 82, 79, 75, 69, 188, 1, 6, 72, 65, 77, 90, 65, 32, 44, 8, 87, 65, 86, 89, + 32, 72, 65, 77, 214, 70, 69, 204, 1, 4, 77, 65, 68, 68, 180, 220, 36, 9, + 76, 69, 70, 84, 32, 77, 73, 68, 68, 159, 240, 1, 68, 28, 204, 1, 17, 66, + 79, 84, 84, 79, 77, 32, 82, 73, 71, 72, 84, 32, 75, 65, 83, 82, 0, 14, + 84, 79, 80, 32, 82, 73, 71, 72, 84, 32, 70, 65, 84, 72, 94, 82, 56, 3, + 76, 69, 70, 130, 214, 1, 75, 143, 182, 32, 70, 6, 11, 65, 7, 29, 5, 32, + 65, 78, 68, 32, 4, 196, 205, 19, 3, 76, 69, 70, 243, 200, 19, 68, 8, 52, + 3, 73, 71, 72, 213, 227, 1, 4, 79, 85, 78, 68, 4, 17, 2, 84, 32, 4, 130, + 189, 1, 82, 219, 37, 72, 12, 234, 72, 65, 37, 5, 66, 69, 76, 79, 87, 4, + 171, 224, 37, 90, 50, 22, 72, 179, 64, 69, 41, 22, 32, 155, 64, 69, 28, + 68, 5, 87, 73, 84, 72, 32, 158, 163, 1, 70, 202, 43, 73, 211, 9, 77, 20, + 116, 6, 83, 77, 65, 76, 76, 32, 34, 84, 254, 18, 73, 160, 33, 10, 68, 79, + 84, 32, 66, 69, 76, 79, 87, 32, 135, 21, 72, 6, 150, 39, 77, 231, 224, + 23, 86, 8, 88, 10, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 233, 48, 7, + 87, 79, 32, 68, 79, 84, 83, 6, 144, 1, 22, 80, 79, 73, 78, 84, 73, 78, + 71, 32, 85, 80, 87, 65, 82, 68, 83, 32, 66, 69, 76, 79, 87, 201, 54, 8, + 72, 79, 82, 73, 90, 79, 78, 84, 5, 231, 141, 15, 32, 78, 90, 65, 136, 4, + 2, 68, 65, 40, 7, 79, 84, 76, 69, 83, 83, 32, 250, 27, 89, 147, 26, 85, + 44, 34, 76, 254, 3, 72, 147, 46, 68, 27, 11, 32, 24, 56, 5, 87, 73, 84, + 72, 32, 186, 158, 1, 70, 231, 52, 73, 20, 108, 9, 73, 78, 86, 69, 82, 84, + 69, 68, 32, 34, 84, 168, 1, 3, 68, 79, 84, 146, 145, 12, 70, 131, 171, + 27, 82, 4, 238, 14, 83, 239, 255, 39, 86, 8, 132, 1, 10, 72, 82, 69, 69, + 32, 68, 79, 84, 83, 32, 33, 18, 87, 79, 32, 68, 79, 84, 83, 32, 86, 69, + 82, 84, 73, 67, 65, 76, 76, 89, 4, 226, 54, 65, 231, 180, 37, 66, 4, 33, + 6, 32, 66, 69, 76, 79, 87, 5, 141, 187, 15, 11, 32, 65, 78, 68, 32, 83, + 77, 65, 76, 76, 32, 12, 22, 72, 195, 63, 76, 6, 151, 54, 65, 6, 170, 150, + 33, 66, 2, 70, 175, 244, 5, 81, 44, 60, 8, 65, 82, 83, 73, 32, 89, 69, + 72, 169, 2, 2, 69, 72, 23, 11, 32, 20, 68, 5, 87, 73, 84, 72, 32, 182, + 153, 1, 70, 202, 43, 73, 211, 9, 77, 12, 144, 1, 28, 69, 88, 84, 69, 78, + 68, 69, 68, 32, 65, 82, 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, 32, 68, + 73, 71, 73, 84, 32, 30, 84, 247, 39, 73, 6, 250, 8, 70, 207, 50, 84, 4, + 190, 169, 7, 72, 199, 220, 7, 87, 23, 11, 32, 20, 68, 5, 87, 73, 84, 72, + 32, 142, 151, 1, 70, 202, 43, 73, 211, 9, 77, 12, 32, 4, 68, 79, 84, 32, + 51, 84, 6, 214, 40, 66, 197, 223, 15, 4, 77, 79, 86, 69, 6, 64, 10, 72, + 82, 69, 69, 32, 68, 79, 84, 83, 32, 191, 213, 37, 87, 4, 210, 17, 80, + 203, 211, 37, 66, 44, 72, 2, 65, 70, 160, 1, 4, 72, 65, 73, 78, 238, 20, + 85, 227, 238, 38, 82, 19, 11, 32, 16, 68, 5, 87, 73, 84, 72, 32, 182, + 148, 1, 70, 202, 43, 73, 211, 9, 77, 8, 242, 23, 84, 210, 156, 39, 82, + 241, 32, 8, 73, 78, 86, 69, 82, 84, 69, 68, 15, 11, 32, 12, 68, 5, 87, + 73, 84, 72, 32, 150, 147, 1, 70, 202, 43, 73, 211, 9, 77, 4, 214, 37, 84, + 135, 140, 27, 68, 82, 78, 65, 236, 5, 2, 69, 72, 161, 2, 9, 73, 71, 72, + 32, 72, 65, 77, 90, 65, 34, 34, 72, 201, 48, 3, 77, 90, 65, 31, 11, 32, + 28, 68, 5, 87, 73, 84, 72, 32, 174, 145, 1, 70, 202, 43, 73, 211, 9, 77, + 20, 132, 2, 29, 69, 88, 84, 69, 78, 68, 69, 68, 32, 65, 82, 65, 66, 73, + 67, 45, 73, 78, 68, 73, 67, 32, 68, 73, 71, 73, 84, 32, 70, 30, 73, 92, + 24, 83, 77, 65, 76, 76, 32, 65, 82, 65, 66, 73, 67, 32, 76, 69, 84, 84, + 69, 82, 32, 84, 65, 72, 32, 62, 84, 143, 53, 72, 2, 129, 199, 1, 2, 79, + 85, 2, 45, 9, 78, 86, 69, 82, 84, 69, 68, 32, 83, 2, 209, 206, 37, 6, 77, + 65, 76, 76, 32, 86, 6, 26, 65, 187, 221, 37, 66, 4, 134, 31, 78, 191, + 227, 38, 66, 8, 88, 10, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 33, 8, + 87, 79, 32, 68, 79, 84, 83, 32, 4, 242, 8, 80, 203, 248, 38, 65, 4, 128, + 129, 39, 8, 86, 69, 82, 84, 73, 67, 65, 76, 27, 65, 41, 11, 32, 38, 144, + 1, 4, 71, 79, 65, 76, 88, 5, 87, 73, 84, 72, 32, 240, 47, 10, 68, 79, 65, + 67, 72, 65, 83, 72, 77, 69, 210, 90, 70, 202, 43, 73, 211, 9, 77, 13, 11, + 32, 10, 164, 50, 6, 87, 73, 84, 72, 32, 72, 230, 88, 70, 202, 43, 73, + 211, 9, 77, 8, 174, 26, 73, 149, 20, 3, 89, 69, 72, 9, 11, 32, 6, 174, + 246, 23, 65, 150, 143, 9, 89, 179, 247, 5, 87, 22, 28, 2, 69, 77, 247, + 45, 72, 17, 11, 32, 14, 72, 6, 87, 73, 84, 72, 32, 84, 226, 136, 1, 70, + 202, 43, 73, 211, 9, 77, 6, 222, 246, 14, 87, 227, 213, 18, 72, 70, 98, + 65, 208, 1, 4, 69, 72, 69, 72, 180, 2, 7, 73, 82, 71, 72, 73, 90, 32, + 137, 32, 2, 72, 65, 24, 46, 70, 229, 174, 1, 5, 83, 72, 77, 73, 82, 23, + 11, 32, 20, 68, 5, 87, 73, 84, 72, 32, 214, 134, 1, 70, 202, 43, 73, 211, + 9, 77, 12, 42, 84, 166, 211, 35, 68, 151, 211, 3, 82, 6, 254, 27, 87, + 203, 169, 37, 72, 25, 11, 32, 22, 68, 5, 87, 73, 84, 72, 32, 182, 133, 1, + 70, 202, 43, 73, 211, 9, 77, 14, 38, 84, 206, 42, 83, 139, 203, 38, 68, + 10, 60, 10, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 167, 26, 87, 6, 42, + 80, 202, 211, 37, 66, 131, 165, 1, 65, 2, 141, 196, 37, 14, 79, 73, 78, + 84, 73, 78, 71, 32, 85, 80, 87, 65, 82, 68, 12, 130, 40, 79, 13, 2, 89, + 85, 26, 40, 2, 65, 77, 161, 183, 1, 2, 79, 87, 25, 11, 32, 22, 68, 5, 87, + 73, 84, 72, 32, 182, 130, 1, 70, 202, 43, 73, 211, 9, 77, 14, 88, 2, 68, + 79, 36, 6, 83, 77, 65, 76, 76, 32, 148, 197, 33, 2, 84, 72, 251, 137, 5, + 66, 4, 146, 135, 18, 85, 215, 238, 20, 84, 4, 224, 27, 16, 65, 82, 65, + 66, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 84, 65, 231, 214, 39, 86, 18, + 36, 3, 69, 69, 77, 163, 176, 39, 65, 17, 11, 32, 14, 64, 5, 87, 73, 84, + 72, 32, 222, 127, 70, 202, 43, 73, 211, 9, 77, 6, 158, 18, 84, 187, 186, + 35, 68, 62, 38, 71, 26, 89, 17, 3, 79, 79, 78, 21, 22, 79, 183, 122, 32, + 10, 175, 27, 69, 33, 11, 32, 30, 92, 5, 71, 72, 85, 78, 78, 16, 5, 87, + 73, 84, 72, 32, 242, 125, 70, 202, 43, 73, 211, 9, 77, 6, 187, 34, 65, + 16, 136, 1, 6, 83, 77, 65, 76, 76, 32, 38, 84, 220, 24, 8, 73, 78, 86, + 69, 82, 84, 69, 68, 132, 151, 24, 4, 82, 73, 78, 71, 171, 235, 2, 68, 4, + 246, 255, 32, 84, 131, 238, 6, 86, 4, 250, 141, 7, 72, 143, 174, 30, 87, + 25, 22, 32, 187, 24, 69, 12, 88, 11, 87, 73, 84, 72, 32, 83, 77, 65, 76, + 76, 32, 170, 123, 70, 202, 43, 73, 211, 9, 77, 4, 26, 77, 163, 236, 39, + 86, 2, 153, 239, 38, 3, 69, 69, 77, 19, 11, 32, 16, 64, 5, 87, 73, 84, + 72, 32, 158, 122, 70, 202, 43, 73, 211, 9, 77, 8, 36, 4, 68, 79, 84, 32, + 187, 12, 84, 6, 44, 5, 66, 69, 76, 79, 87, 239, 237, 38, 65, 5, 193, 231, + 14, 6, 32, 65, 78, 68, 32, 78, 52, 112, 2, 69, 72, 224, 28, 3, 82, 69, + 72, 156, 3, 4, 78, 79, 79, 78, 149, 130, 1, 7, 79, 72, 73, 78, 71, 89, + 65, 35, 11, 32, 32, 52, 5, 87, 73, 84, 72, 32, 226, 119, 70, 231, 52, 73, + 28, 134, 1, 83, 96, 2, 84, 87, 234, 5, 73, 174, 23, 72, 246, 205, 11, 70, + 204, 141, 7, 5, 68, 79, 84, 32, 66, 234, 39, 76, 207, 245, 19, 82, 10, + 44, 5, 77, 65, 76, 76, 32, 207, 183, 39, 84, 8, 198, 6, 65, 166, 250, 6, + 78, 151, 219, 16, 86, 4, 37, 7, 79, 32, 68, 79, 84, 83, 32, 4, 166, 8, + 86, 211, 225, 38, 65, 60, 184, 1, 2, 65, 68, 120, 3, 69, 69, 78, 136, 6, + 4, 72, 69, 69, 78, 232, 160, 1, 4, 85, 80, 69, 82, 160, 181, 4, 7, 84, + 82, 65, 73, 71, 72, 84, 209, 134, 33, 6, 87, 65, 83, 72, 32, 75, 17, 11, + 32, 14, 68, 6, 87, 73, 84, 72, 32, 84, 162, 115, 70, 202, 43, 73, 211, 9, + 77, 6, 254, 182, 33, 72, 235, 251, 3, 87, 27, 11, 32, 24, 64, 5, 87, 73, + 84, 72, 32, 174, 114, 70, 202, 43, 73, 211, 9, 77, 16, 232, 1, 3, 68, 79, + 84, 50, 73, 48, 7, 83, 77, 65, 76, 76, 32, 65, 110, 84, 134, 228, 11, 70, + 241, 159, 5, 31, 69, 88, 84, 69, 78, 68, 69, 68, 32, 65, 82, 65, 66, 73, + 67, 45, 73, 78, 68, 73, 67, 32, 68, 73, 71, 73, 84, 32, 70, 79, 85, 2, + 193, 243, 18, 7, 32, 66, 69, 76, 79, 87, 32, 2, 213, 219, 17, 7, 78, 86, + 69, 82, 84, 69, 68, 2, 85, 19, 82, 65, 66, 73, 67, 32, 76, 69, 84, 84, + 69, 82, 32, 84, 65, 72, 32, 65, 78, 2, 147, 159, 23, 68, 6, 96, 11, 72, + 82, 69, 69, 32, 68, 79, 84, 83, 32, 66, 105, 9, 87, 79, 32, 68, 79, 84, + 83, 32, 86, 4, 25, 4, 69, 76, 79, 87, 5, 11, 32, 2, 21, 3, 65, 78, 68, 2, + 17, 2, 32, 84, 2, 247, 254, 6, 72, 2, 221, 224, 11, 8, 69, 82, 84, 73, + 67, 65, 76, 76, 13, 11, 32, 10, 46, 87, 186, 108, 70, 202, 43, 73, 211, + 9, 77, 2, 253, 138, 27, 5, 73, 84, 72, 32, 68, 122, 92, 2, 65, 72, 136, + 2, 4, 67, 72, 69, 72, 124, 2, 69, 72, 150, 3, 72, 97, 3, 84, 69, 72, 21, + 11, 32, 18, 64, 5, 87, 73, 84, 72, 32, 226, 106, 70, 202, 43, 73, 211, 9, + 77, 10, 26, 84, 143, 137, 27, 68, 8, 26, 87, 139, 174, 33, 72, 4, 37, 7, + 79, 32, 68, 79, 84, 83, 32, 4, 48, 6, 86, 69, 82, 84, 73, 67, 247, 221, + 38, 65, 2, 197, 169, 37, 4, 65, 76, 76, 89, 25, 22, 32, 199, 5, 69, 12, + 64, 5, 87, 73, 84, 72, 32, 206, 104, 70, 202, 43, 73, 211, 9, 77, 4, 138, + 14, 83, 139, 203, 38, 68, 37, 22, 32, 203, 4, 69, 24, 62, 77, 116, 5, 87, + 73, 84, 72, 32, 226, 102, 70, 203, 43, 73, 10, 48, 6, 65, 82, 66, 85, 84, + 65, 199, 156, 1, 69, 9, 11, 32, 6, 146, 103, 70, 230, 52, 73, 213, 176, + 37, 2, 71, 79, 8, 104, 6, 83, 77, 65, 76, 76, 32, 56, 12, 84, 72, 82, 69, + 69, 32, 68, 79, 84, 83, 32, 65, 207, 133, 39, 82, 4, 32, 2, 84, 69, 231, + 214, 39, 86, 2, 223, 217, 38, 72, 2, 153, 146, 28, 4, 66, 79, 86, 69, 20, + 42, 65, 16, 3, 73, 78, 32, 147, 1, 69, 6, 167, 9, 76, 4, 146, 224, 32, + 89, 183, 203, 3, 78, 23, 18, 32, 91, 69, 10, 60, 4, 87, 73, 84, 72, 230, + 99, 70, 202, 43, 73, 211, 9, 77, 2, 161, 9, 2, 32, 83, 10, 163, 11, 72, + 15, 158, 1, 32, 181, 92, 33, 73, 71, 72, 85, 82, 32, 75, 65, 90, 65, 75, + 72, 32, 75, 73, 82, 71, 72, 73, 90, 32, 65, 76, 69, 70, 32, 77, 65, 75, + 83, 85, 82, 65, 8, 96, 16, 87, 73, 84, 72, 32, 72, 65, 77, 90, 65, 32, + 65, 66, 79, 86, 69, 186, 97, 70, 231, 52, 73, 5, 155, 87, 32, 17, 254, 8, + 72, 147, 88, 32, 25, 11, 32, 22, 52, 5, 87, 73, 84, 72, 32, 202, 96, 70, + 231, 52, 73, 18, 80, 4, 68, 79, 84, 32, 162, 2, 69, 182, 1, 72, 150, 202, + 14, 84, 159, 178, 24, 82, 4, 152, 197, 31, 3, 87, 73, 84, 131, 143, 7, + 65, 56, 28, 2, 69, 72, 227, 3, 85, 51, 11, 32, 48, 100, 6, 66, 65, 82, + 82, 69, 69, 252, 2, 5, 87, 73, 84, 72, 32, 182, 91, 70, 202, 43, 73, 211, + 9, 77, 17, 11, 32, 14, 52, 5, 87, 73, 84, 72, 32, 238, 93, 70, 231, 52, + 73, 10, 22, 69, 183, 1, 72, 4, 121, 28, 88, 84, 69, 78, 68, 69, 68, 32, + 65, 82, 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, 32, 68, 73, 71, 73, 84, + 32, 84, 4, 224, 166, 36, 3, 72, 82, 69, 133, 170, 2, 2, 87, 79, 6, 21, 3, + 65, 77, 90, 6, 11, 65, 6, 17, 2, 32, 65, 6, 21, 3, 66, 79, 86, 6, 11, 69, + 7, 171, 91, 32, 24, 96, 10, 72, 65, 77, 90, 65, 32, 65, 66, 79, 86, 18, + 83, 38, 84, 241, 153, 37, 4, 70, 79, 85, 82, 10, 167, 2, 69, 2, 133, 198, + 17, 4, 77, 65, 76, 76, 10, 108, 18, 87, 79, 32, 68, 79, 84, 83, 32, 66, + 69, 76, 79, 87, 32, 65, 78, 68, 32, 206, 152, 37, 72, 167, 82, 65, 6, 70, + 72, 168, 227, 6, 7, 83, 77, 65, 76, 76, 32, 78, 135, 230, 31, 68, 2, 185, + 158, 34, 3, 65, 77, 90, 18, 26, 72, 17, 2, 73, 78, 11, 223, 83, 32, 9, + 11, 32, 6, 138, 88, 70, 230, 52, 73, 177, 11, 13, 87, 73, 84, 72, 32, 73, + 78, 86, 69, 82, 84, 69, 68, 158, 8, 166, 5, 65, 178, 7, 66, 176, 2, 2, + 68, 65, 184, 1, 9, 70, 69, 72, 32, 87, 73, 84, 72, 32, 72, 11, 71, 72, + 65, 73, 78, 32, 87, 73, 84, 72, 32, 154, 1, 72, 150, 4, 74, 234, 2, 75, + 216, 2, 9, 76, 65, 77, 32, 87, 73, 84, 72, 32, 226, 4, 77, 154, 4, 78, + 202, 3, 81, 146, 4, 82, 186, 5, 83, 186, 17, 84, 196, 9, 7, 87, 65, 83, + 65, 76, 76, 65, 40, 9, 89, 69, 72, 32, 87, 73, 84, 72, 32, 216, 3, 53, + 85, 73, 71, 72, 85, 82, 32, 75, 73, 82, 71, 72, 73, 90, 32, 89, 69, 72, + 32, 87, 73, 84, 72, 32, 72, 65, 77, 90, 65, 32, 65, 66, 79, 86, 69, 32, + 87, 73, 84, 72, 32, 65, 76, 69, 70, 32, 77, 65, 75, 83, 85, 82, 65, 205, + 6, 14, 90, 65, 72, 32, 87, 73, 84, 72, 32, 77, 69, 69, 77, 32, 66, 192, + 1, 8, 73, 78, 32, 87, 73, 84, 72, 32, 68, 13, 74, 74, 65, 76, 32, 65, 76, + 76, 65, 65, 72, 85, 32, 146, 1, 76, 196, 68, 4, 75, 66, 65, 82, 137, 241, + 36, 8, 90, 90, 65, 32, 87, 65, 32, 74, 28, 236, 23, 4, 77, 69, 69, 77, + 130, 22, 74, 154, 25, 65, 255, 8, 89, 4, 54, 70, 1, 9, 84, 65, 65, 65, + 76, 65, 65, 32, 70, 2, 209, 223, 28, 17, 65, 82, 65, 74, 65, 72, 85, 32, + 65, 83, 72, 45, 83, 72, 65, 82, 69, 30, 56, 3, 65, 89, 72, 156, 2, 3, 69, + 70, 32, 207, 16, 76, 20, 30, 73, 102, 65, 135, 67, 69, 14, 24, 2, 32, 65, + 55, 77, 6, 110, 83, 153, 208, 32, 6, 82, 45, 82, 65, 72, 77, 8, 18, 65, + 23, 32, 4, 17, 2, 65, 32, 4, 17, 2, 65, 83, 4, 33, 6, 45, 83, 65, 76, 65, + 65, 4, 236, 184, 33, 10, 84, 85, 32, 87, 65, 83, 45, 83, 65, 76, 135, + 133, 6, 77, 8, 236, 75, 29, 77, 65, 75, 83, 85, 82, 65, 32, 87, 73, 84, + 72, 32, 83, 85, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, 76, 69, 70, + 1, 13, 87, 73, 84, 72, 32, 70, 65, 84, 72, 65, 84, 65, 78, 44, 160, 1, 8, + 69, 72, 32, 87, 73, 84, 72, 32, 241, 131, 26, 25, 73, 83, 77, 73, 76, 76, + 65, 72, 32, 65, 82, 45, 82, 65, 72, 77, 65, 78, 32, 65, 82, 45, 82, 65, + 72, 42, 98, 72, 24, 3, 75, 72, 65, 254, 62, 65, 250, 3, 74, 78, 77, 86, + 78, 78, 90, 242, 2, 82, 43, 89, 10, 22, 65, 195, 66, 69, 6, 155, 69, 72, + 38, 100, 7, 68, 32, 87, 73, 84, 72, 32, 185, 28, 13, 65, 77, 65, 84, 32, + 66, 65, 82, 65, 75, 65, 65, 84, 36, 154, 8, 72, 250, 7, 75, 242, 45, 65, + 250, 3, 74, 2, 77, 134, 5, 82, 3, 89, 30, 194, 15, 75, 242, 45, 65, 250, 3, 74, 146, 2, 77, 110, 72, 139, 2, 89, 22, 64, 5, 77, 69, 69, 77, 32, - 250, 50, 65, 250, 3, 74, 135, 5, 89, 10, 40, 5, 87, 73, 84, 72, 32, 243, - 103, 73, 6, 174, 21, 77, 170, 25, 65, 203, 12, 89, 40, 80, 8, 65, 72, 32, - 87, 73, 84, 72, 32, 69, 8, 69, 72, 32, 87, 73, 84, 72, 32, 22, 236, 3, 4, - 77, 69, 69, 77, 226, 45, 65, 138, 6, 74, 247, 2, 89, 18, 164, 1, 5, 77, - 69, 69, 77, 32, 196, 11, 6, 65, 76, 69, 70, 32, 77, 150, 2, 89, 134, 38, - 74, 53, 16, 83, 85, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, 76, 69, - 70, 8, 40, 5, 87, 73, 84, 72, 32, 223, 100, 73, 4, 254, 43, 74, 3, 77, - 30, 104, 9, 69, 69, 77, 32, 87, 73, 84, 72, 32, 205, 129, 4, 11, 65, 76, - 76, 65, 74, 65, 76, 65, 76, 79, 85, 28, 62, 72, 60, 5, 77, 69, 69, 77, - 32, 186, 45, 65, 255, 8, 89, 8, 17, 2, 65, 72, 8, 11, 32, 8, 178, 29, 87, - 199, 69, 73, 12, 40, 5, 87, 73, 84, 72, 32, 179, 98, 73, 8, 166, 37, 72, - 242, 3, 65, 203, 12, 89, 64, 84, 8, 65, 70, 32, 87, 73, 84, 72, 32, 93, - 9, 72, 65, 72, 32, 87, 73, 84, 72, 32, 46, 168, 46, 2, 65, 76, 218, 1, - 74, 96, 2, 76, 65, 146, 2, 75, 14, 72, 30, 77, 239, 1, 89, 18, 54, 72, - 250, 42, 65, 250, 3, 74, 2, 77, 135, 5, 89, 2, 247, 8, 65, 74, 116, 5, - 65, 76, 69, 70, 32, 210, 1, 72, 124, 5, 74, 69, 69, 77, 32, 78, 75, 28, - 5, 77, 69, 69, 77, 32, 187, 47, 89, 20, 64, 5, 87, 73, 84, 72, 32, 138, - 44, 77, 222, 6, 70, 255, 52, 73, 12, 68, 6, 72, 65, 77, 90, 65, 32, 41, - 7, 77, 65, 68, 68, 65, 32, 65, 8, 38, 65, 249, 45, 4, 66, 69, 76, 79, 4, - 229, 45, 3, 66, 79, 86, 14, 28, 2, 65, 72, 163, 44, 69, 12, 11, 32, 12, - 40, 5, 87, 73, 84, 72, 32, 239, 92, 73, 8, 210, 35, 65, 130, 12, 77, 75, - 89, 14, 40, 5, 87, 73, 84, 72, 32, 159, 92, 73, 10, 130, 47, 74, 2, 77, - 75, 89, 8, 129, 15, 3, 72, 65, 72, 14, 150, 14, 87, 222, 33, 70, 238, 43, - 73, 199, 9, 77, 48, 84, 9, 69, 69, 77, 32, 87, 73, 84, 72, 32, 193, 36, - 7, 79, 72, 65, 77, 77, 65, 68, 46, 116, 5, 65, 76, 69, 70, 32, 66, 72, 0, - 2, 75, 72, 104, 5, 74, 69, 69, 77, 32, 92, 5, 77, 69, 69, 77, 32, 43, 89, - 4, 22, 77, 219, 45, 70, 2, 173, 35, 6, 65, 75, 83, 85, 82, 65, 10, 21, 3, - 65, 72, 32, 10, 40, 5, 87, 73, 84, 72, 32, 219, 88, 73, 6, 250, 31, 74, - 2, 77, 143, 12, 89, 12, 40, 5, 87, 73, 84, 72, 32, 139, 88, 73, 8, 170, - 31, 77, 194, 7, 75, 14, 72, 195, 4, 89, 8, 246, 40, 87, 246, 2, 70, 239, - 43, 73, 2, 11, 69, 2, 143, 33, 72, 60, 134, 1, 72, 28, 5, 74, 69, 69, 77, - 32, 92, 5, 77, 69, 69, 77, 32, 242, 31, 65, 154, 5, 78, 78, 90, 134, 1, - 75, 238, 1, 82, 43, 89, 14, 146, 27, 65, 155, 9, 69, 16, 40, 5, 87, 73, - 84, 72, 32, 199, 85, 73, 12, 186, 24, 72, 242, 3, 65, 130, 12, 77, 75, - 89, 12, 206, 15, 87, 218, 25, 70, 238, 43, 73, 199, 9, 77, 28, 70, 65, - 209, 138, 32, 11, 85, 68, 68, 73, 83, 65, 32, 83, 73, 82, 82, 26, 64, 7, - 70, 32, 87, 73, 84, 72, 32, 193, 8, 4, 76, 65, 32, 85, 24, 64, 5, 77, 69, - 69, 77, 32, 238, 29, 65, 246, 6, 72, 139, 2, 89, 12, 40, 5, 87, 73, 84, - 72, 32, 231, 82, 73, 8, 34, 77, 186, 21, 72, 187, 16, 89, 2, 129, 38, 3, - 69, 69, 77, 18, 30, 65, 129, 26, 2, 69, 72, 16, 128, 1, 14, 68, 73, 32, - 65, 76, 76, 65, 65, 72, 85, 32, 65, 78, 72, 76, 6, 72, 73, 77, 65, 72, - 85, 161, 26, 4, 83, 79, 85, 76, 11, 26, 85, 231, 228, 38, 65, 6, 26, 77, - 255, 170, 37, 78, 5, 199, 228, 38, 65, 4, 26, 32, 1, 2, 77, 32, 2, 205, - 134, 32, 4, 65, 76, 76, 65, 190, 1, 138, 1, 65, 192, 6, 9, 69, 69, 78, - 32, 87, 73, 84, 72, 32, 250, 3, 72, 233, 5, 13, 85, 66, 72, 65, 65, 78, - 65, 72, 85, 32, 87, 65, 32, 46, 48, 7, 68, 32, 87, 73, 84, 72, 32, 251, - 1, 76, 32, 76, 4, 72, 65, 72, 32, 82, 77, 238, 23, 65, 138, 4, 75, 246, - 4, 82, 3, 89, 10, 22, 87, 203, 77, 73, 6, 25, 4, 73, 84, 72, 32, 6, 162, - 16, 72, 187, 16, 89, 8, 21, 3, 69, 69, 77, 8, 11, 32, 8, 208, 31, 6, 87, - 73, 84, 72, 32, 77, 155, 45, 73, 14, 26, 65, 77, 2, 76, 65, 4, 134, 22, - 77, 129, 218, 36, 11, 65, 77, 85, 72, 85, 32, 65, 76, 65, 89, 78, 10, 34, - 32, 133, 1, 3, 76, 76, 65, 4, 22, 85, 167, 84, 73, 2, 217, 8, 23, 83, 69, - 68, 32, 65, 83, 32, 75, 79, 82, 65, 78, 73, 67, 32, 83, 84, 79, 80, 32, - 83, 73, 71, 6, 98, 72, 237, 222, 38, 18, 65, 72, 85, 32, 65, 76, 65, 89, - 72, 73, 32, 87, 65, 45, 65, 65, 76, 73, 4, 228, 63, 12, 79, 85, 32, 65, - 76, 65, 89, 72, 69, 32, 87, 65, 1, 22, 85, 32, 65, 76, 65, 89, 72, 73, - 32, 87, 65, 65, 65, 76, 73, 72, 69, 69, 32, 87, 65, 45, 60, 130, 1, 72, - 100, 5, 74, 69, 69, 77, 32, 84, 5, 75, 72, 65, 72, 32, 92, 5, 77, 69, 69, - 77, 32, 234, 15, 65, 254, 8, 82, 3, 89, 12, 32, 3, 65, 72, 32, 159, 21, - 69, 8, 156, 14, 6, 87, 73, 84, 72, 32, 74, 222, 56, 73, 199, 9, 77, 10, - 52, 5, 87, 73, 84, 72, 32, 134, 70, 73, 199, 9, 77, 4, 234, 12, 65, 139, - 8, 72, 10, 34, 87, 198, 69, 73, 199, 9, 77, 4, 25, 4, 73, 84, 72, 32, 4, - 142, 12, 65, 203, 12, 89, 16, 52, 5, 87, 73, 84, 72, 32, 214, 68, 73, - 199, 9, 77, 10, 202, 7, 72, 174, 4, 74, 199, 11, 77, 82, 96, 10, 65, 68, - 68, 65, 32, 87, 73, 84, 72, 32, 161, 1, 9, 69, 69, 78, 32, 87, 73, 84, - 72, 32, 18, 96, 4, 68, 65, 77, 77, 0, 4, 75, 65, 83, 82, 138, 11, 83, - 245, 41, 6, 70, 65, 84, 72, 65, 32, 6, 11, 65, 6, 28, 2, 84, 65, 211, 52, - 32, 2, 163, 12, 78, 64, 130, 1, 72, 36, 5, 74, 69, 69, 77, 32, 52, 5, 77, - 69, 69, 77, 32, 170, 11, 65, 228, 4, 4, 75, 72, 65, 72, 154, 4, 82, 3, - 89, 18, 194, 15, 69, 229, 3, 2, 65, 72, 10, 158, 18, 87, 246, 2, 70, 238, - 43, 73, 199, 9, 77, 16, 64, 5, 87, 73, 84, 72, 32, 158, 20, 70, 238, 43, - 73, 199, 9, 77, 8, 252, 2, 2, 75, 72, 243, 15, 77, 122, 66, 65, 176, 2, - 8, 69, 72, 32, 87, 73, 84, 72, 32, 179, 4, 72, 28, 88, 11, 66, 65, 65, - 82, 65, 75, 65, 32, 87, 65, 45, 29, 7, 72, 32, 87, 73, 84, 72, 32, 2, - 245, 133, 28, 2, 84, 65, 26, 64, 5, 77, 69, 69, 77, 32, 194, 8, 65, 246, - 6, 72, 139, 2, 89, 14, 52, 5, 87, 73, 84, 72, 32, 174, 61, 73, 199, 9, - 77, 8, 34, 72, 174, 4, 77, 143, 12, 89, 4, 133, 16, 2, 65, 72, 66, 138, - 1, 72, 108, 3, 75, 72, 65, 12, 4, 74, 69, 69, 77, 92, 5, 77, 69, 69, 77, - 32, 238, 4, 65, 154, 5, 78, 78, 90, 242, 2, 82, 43, 89, 14, 32, 3, 65, - 72, 32, 227, 9, 69, 10, 40, 5, 87, 73, 84, 72, 32, 151, 59, 73, 6, 182, - 2, 77, 199, 11, 74, 10, 11, 72, 10, 11, 32, 10, 40, 5, 87, 73, 84, 72, - 32, 183, 58, 73, 6, 154, 1, 65, 62, 77, 143, 12, 89, 18, 64, 5, 87, 73, - 84, 72, 32, 226, 13, 70, 238, 43, 73, 199, 9, 77, 10, 50, 65, 62, 74, - 194, 7, 75, 14, 72, 195, 4, 89, 2, 217, 12, 11, 76, 69, 70, 32, 77, 65, - 75, 83, 85, 82, 65, 2, 225, 7, 3, 69, 69, 77, 28, 56, 2, 65, 76, 117, 8, - 69, 72, 32, 87, 73, 84, 72, 32, 2, 37, 7, 32, 87, 73, 84, 72, 32, 83, 2, - 197, 1, 15, 85, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, 76, 69, 70, - 26, 108, 3, 74, 69, 69, 126, 65, 198, 4, 77, 86, 78, 78, 90, 242, 2, 82, - 42, 89, 237, 53, 5, 72, 69, 72, 32, 77, 2, 11, 77, 2, 11, 32, 2, 151, 63, - 73, 114, 82, 65, 38, 72, 246, 4, 78, 78, 90, 38, 74, 98, 75, 42, 77, 198, - 1, 82, 43, 89, 4, 217, 2, 5, 76, 69, 70, 32, 77, 76, 22, 65, 139, 3, 69, - 72, 80, 15, 77, 90, 65, 32, 65, 66, 79, 86, 69, 32, 87, 73, 84, 72, 32, - 147, 5, 72, 66, 118, 65, 126, 69, 42, 72, 78, 74, 18, 75, 62, 77, 86, 78, - 22, 79, 16, 2, 87, 65, 18, 89, 26, 90, 242, 2, 82, 67, 85, 12, 22, 76, - 247, 6, 69, 8, 21, 3, 69, 70, 32, 8, 34, 77, 222, 6, 70, 255, 52, 73, 4, - 181, 6, 6, 65, 75, 83, 85, 82, 65, 6, 11, 32, 6, 166, 6, 70, 239, 43, 73, - 8, 22, 69, 191, 3, 65, 4, 11, 72, 4, 11, 32, 4, 230, 4, 73, 167, 54, 77, - 4, 131, 49, 69, 2, 11, 72, 2, 11, 65, 2, 11, 72, 2, 149, 4, 2, 32, 73, 8, - 17, 2, 69, 69, 8, 11, 77, 8, 11, 32, 8, 198, 4, 70, 238, 43, 73, 199, 9, - 77, 2, 93, 2, 79, 79, 4, 231, 3, 69, 4, 215, 3, 87, 8, 186, 3, 69, 15, - 85, 2, 17, 2, 65, 73, 2, 239, 2, 78, 6, 21, 3, 69, 69, 77, 6, 11, 32, 6, - 22, 87, 227, 46, 73, 2, 141, 2, 5, 73, 84, 72, 32, 89, 4, 11, 72, 4, 11, - 65, 4, 143, 46, 72, 14, 21, 3, 69, 69, 77, 14, 11, 32, 14, 64, 5, 87, 73, - 84, 72, 32, 194, 1, 70, 238, 43, 73, 199, 9, 77, 6, 18, 77, 75, 89, 4, - 21, 3, 69, 69, 77, 4, 11, 32, 4, 18, 73, 119, 70, 2, 247, 44, 78, 2, 17, - 2, 69, 72, 2, 77, 2, 32, 70, 4, 11, 69, 4, 11, 72, 4, 11, 32, 4, 22, 70, - 255, 52, 73, 2, 209, 53, 2, 73, 78, 6, 210, 43, 73, 199, 9, 77, 166, 2, - 92, 3, 68, 68, 65, 52, 3, 82, 75, 32, 109, 11, 84, 72, 69, 77, 65, 84, - 73, 67, 65, 76, 32, 4, 152, 133, 37, 5, 32, 87, 65, 65, 74, 239, 62, 72, - 4, 58, 78, 1, 10, 83, 73, 68, 69, 87, 65, 89, 83, 32, 78, 2, 173, 137, - 35, 7, 79, 79, 78, 32, 71, 72, 85, 158, 2, 174, 2, 68, 140, 3, 8, 73, 78, - 73, 84, 73, 65, 76, 32, 222, 1, 76, 132, 2, 9, 79, 80, 69, 82, 65, 84, - 79, 82, 32, 166, 1, 83, 142, 3, 84, 190, 162, 24, 65, 102, 75, 110, 90, - 134, 107, 74, 2, 77, 178, 187, 6, 66, 2, 70, 2, 82, 2, 89, 222, 7, 72, - 190, 59, 71, 242, 253, 2, 78, 166, 165, 2, 81, 135, 3, 87, 62, 26, 79, - 235, 186, 37, 65, 58, 88, 6, 84, 76, 69, 83, 83, 32, 61, 12, 85, 66, 76, - 69, 45, 83, 84, 82, 85, 67, 75, 32, 8, 226, 212, 31, 66, 2, 70, 138, 193, - 3, 78, 167, 165, 2, 81, 50, 178, 12, 83, 210, 20, 75, 170, 140, 24, 84, - 74, 90, 134, 107, 74, 2, 77, 178, 187, 6, 66, 2, 70, 2, 82, 2, 89, 222, - 7, 72, 190, 59, 71, 242, 253, 2, 78, 218, 235, 1, 76, 190, 56, 68, 146, - 1, 81, 222, 1, 65, 171, 1, 87, 40, 182, 1, 84, 166, 9, 83, 186, 160, 24, - 72, 30, 75, 242, 107, 74, 2, 77, 178, 187, 6, 66, 2, 70, 2, 89, 154, 67, - 71, 242, 253, 2, 78, 218, 235, 1, 76, 206, 57, 81, 222, 1, 65, 171, 57, - 68, 4, 150, 209, 31, 72, 207, 230, 6, 69, 56, 48, 6, 79, 79, 80, 69, 68, - 32, 199, 167, 38, 65, 54, 202, 8, 83, 210, 20, 75, 162, 139, 24, 65, 74, - 72, 66, 84, 74, 90, 134, 107, 74, 2, 77, 178, 187, 6, 66, 2, 70, 2, 82, - 2, 89, 154, 67, 71, 242, 253, 2, 78, 218, 235, 1, 76, 190, 56, 68, 146, - 1, 81, 135, 3, 87, 4, 168, 128, 29, 23, 77, 69, 69, 77, 32, 87, 73, 84, - 72, 32, 72, 65, 72, 32, 87, 73, 84, 72, 32, 84, 65, 84, 87, 221, 162, 8, - 9, 72, 65, 72, 32, 87, 73, 84, 72, 32, 52, 84, 9, 84, 82, 69, 84, 67, 72, - 69, 68, 32, 222, 224, 36, 72, 14, 69, 203, 141, 1, 65, 46, 178, 1, 68, - 86, 84, 250, 2, 83, 186, 160, 24, 72, 30, 75, 242, 107, 74, 2, 77, 178, - 187, 6, 66, 2, 70, 2, 89, 222, 7, 90, 190, 59, 71, 242, 253, 2, 78, 166, - 165, 2, 81, 223, 1, 65, 6, 52, 7, 79, 84, 76, 69, 83, 83, 32, 199, 236, - 37, 65, 4, 134, 203, 31, 66, 3, 70, 6, 234, 202, 31, 72, 206, 230, 6, 65, - 3, 69, 38, 42, 65, 190, 163, 24, 72, 167, 141, 14, 69, 32, 44, 5, 73, 76, - 69, 68, 32, 195, 177, 38, 72, 30, 146, 1, 68, 94, 83, 210, 20, 75, 246, - 247, 24, 74, 178, 187, 6, 89, 222, 7, 72, 190, 59, 71, 242, 253, 2, 78, - 218, 235, 1, 76, 206, 57, 81, 223, 1, 65, 6, 52, 7, 79, 84, 76, 69, 83, - 83, 32, 215, 233, 37, 65, 4, 158, 137, 35, 78, 167, 165, 2, 81, 6, 218, - 219, 36, 72, 14, 69, 203, 141, 1, 65, 4, 242, 197, 18, 77, 203, 226, 18, - 83, 6, 228, 235, 24, 3, 75, 65, 83, 12, 4, 68, 65, 77, 77, 1, 4, 70, 65, - 84, 72, 12, 118, 69, 38, 79, 172, 197, 12, 11, 76, 65, 67, 69, 32, 79, - 70, 32, 83, 65, 74, 165, 254, 5, 6, 73, 65, 83, 84, 82, 69, 4, 182, 157, - 32, 82, 235, 218, 5, 80, 4, 252, 181, 12, 8, 69, 84, 73, 67, 32, 86, 69, - 82, 209, 141, 6, 3, 85, 78, 68, 14, 238, 1, 65, 96, 5, 69, 86, 69, 82, - 83, 36, 15, 73, 71, 72, 84, 32, 65, 82, 82, 79, 87, 72, 69, 65, 68, 32, - 225, 158, 23, 28, 79, 85, 78, 68, 69, 68, 32, 72, 73, 71, 72, 32, 83, 84, - 79, 80, 32, 87, 73, 84, 72, 32, 70, 73, 76, 76, 69, 68, 4, 40, 4, 73, 83, - 69, 68, 171, 170, 38, 89, 2, 17, 2, 32, 82, 2, 149, 222, 36, 3, 79, 85, - 78, 2, 181, 214, 21, 4, 69, 68, 32, 68, 6, 26, 65, 167, 139, 36, 66, 4, - 157, 133, 37, 3, 66, 79, 86, 202, 1, 238, 1, 69, 244, 2, 5, 72, 65, 68, - 68, 65, 36, 4, 73, 71, 78, 32, 240, 4, 5, 77, 65, 76, 76, 32, 246, 15, - 85, 240, 2, 6, 89, 77, 66, 79, 76, 32, 209, 208, 36, 18, 84, 65, 82, 84, - 32, 79, 70, 32, 82, 85, 66, 32, 69, 76, 32, 72, 73, 90, 20, 52, 7, 81, - 85, 69, 78, 67, 69, 32, 187, 219, 34, 77, 18, 184, 1, 26, 89, 69, 72, 32, - 87, 73, 84, 72, 32, 72, 65, 77, 90, 65, 32, 65, 66, 79, 86, 69, 32, 87, - 73, 84, 72, 32, 209, 189, 31, 13, 78, 79, 79, 78, 32, 87, 73, 84, 72, 32, - 75, 69, 72, 16, 70, 65, 186, 166, 37, 87, 198, 89, 89, 150, 14, 79, 214, - 22, 69, 3, 85, 6, 36, 3, 76, 69, 70, 191, 164, 38, 69, 5, 159, 13, 32, 7, - 11, 32, 4, 246, 22, 73, 55, 77, 22, 132, 1, 2, 82, 65, 158, 1, 83, 188, - 1, 7, 65, 76, 65, 89, 72, 69, 32, 160, 15, 2, 77, 73, 209, 138, 34, 6, - 84, 65, 75, 72, 65, 76, 4, 132, 1, 13, 72, 77, 65, 84, 85, 76, 76, 65, - 72, 32, 65, 76, 65, 133, 180, 33, 13, 68, 73, 32, 65, 76, 76, 65, 72, 79, - 85, 32, 65, 78, 2, 235, 244, 37, 89, 12, 46, 65, 193, 1, 6, 73, 78, 68, - 72, 73, 32, 8, 136, 1, 18, 76, 76, 65, 76, 76, 65, 72, 79, 85, 32, 65, - 76, 65, 89, 72, 69, 32, 87, 170, 192, 31, 78, 194, 229, 4, 70, 217, 102, - 2, 77, 86, 2, 17, 2, 65, 83, 2, 189, 221, 15, 3, 83, 65, 76, 4, 152, 200, - 20, 12, 80, 79, 83, 84, 80, 79, 83, 73, 84, 73, 79, 78, 185, 136, 14, 2, - 65, 77, 106, 132, 1, 2, 70, 65, 32, 5, 72, 73, 71, 72, 32, 240, 11, 4, - 76, 79, 87, 32, 110, 75, 218, 189, 21, 68, 226, 235, 9, 89, 179, 233, 5, - 87, 4, 190, 3, 82, 147, 160, 36, 84, 74, 236, 2, 17, 68, 79, 84, 76, 69, - 83, 83, 32, 72, 69, 65, 68, 32, 79, 70, 32, 75, 22, 70, 102, 76, 142, 3, - 77, 116, 4, 78, 79, 79, 78, 18, 83, 78, 84, 38, 87, 196, 2, 3, 89, 69, - 72, 224, 175, 14, 18, 85, 80, 82, 73, 71, 72, 84, 32, 82, 69, 67, 84, 65, - 78, 71, 85, 76, 65, 236, 213, 8, 7, 82, 79, 85, 78, 68, 69, 68, 234, 126, - 90, 134, 107, 74, 222, 161, 12, 81, 223, 1, 65, 2, 255, 186, 31, 72, 4, - 24, 2, 65, 82, 31, 79, 2, 11, 83, 2, 175, 2, 73, 2, 253, 180, 26, 6, 79, - 84, 78, 79, 84, 69, 10, 60, 8, 73, 71, 65, 84, 85, 82, 69, 32, 213, 11, - 2, 65, 77, 8, 88, 10, 65, 76, 69, 70, 32, 87, 73, 84, 72, 32, 116, 3, 81, - 65, 70, 1, 3, 83, 65, 68, 4, 84, 8, 76, 65, 77, 32, 87, 73, 84, 72, 209, - 168, 36, 7, 89, 69, 72, 32, 66, 65, 82, 2, 181, 176, 31, 2, 32, 89, 2, - 89, 20, 32, 87, 73, 84, 72, 32, 76, 65, 77, 32, 87, 73, 84, 72, 32, 65, - 76, 69, 70, 32, 2, 165, 145, 22, 3, 77, 65, 75, 6, 26, 69, 191, 249, 15, - 65, 4, 17, 2, 69, 77, 4, 17, 2, 32, 73, 4, 22, 78, 135, 9, 83, 2, 193, 9, - 2, 73, 84, 5, 207, 4, 32, 6, 180, 155, 36, 7, 73, 71, 78, 32, 83, 65, 70, - 218, 38, 69, 203, 141, 1, 65, 4, 178, 196, 23, 72, 235, 207, 14, 65, 20, - 40, 4, 79, 82, 68, 32, 191, 150, 37, 65, 18, 74, 65, 172, 1, 2, 83, 65, - 172, 173, 25, 3, 87, 65, 81, 207, 227, 11, 81, 10, 192, 252, 6, 3, 76, - 45, 74, 244, 185, 18, 3, 82, 45, 82, 144, 226, 6, 7, 84, 72, 45, 84, 72, - 65, 76, 164, 250, 4, 5, 78, 45, 78, 73, 83, 161, 92, 5, 83, 45, 83, 65, - 74, 4, 150, 238, 37, 75, 207, 36, 72, 5, 193, 182, 10, 12, 32, 66, 65, - 82, 82, 69, 69, 32, 87, 73, 84, 72, 20, 68, 5, 78, 79, 79, 78, 32, 70, - 87, 234, 237, 24, 77, 155, 207, 11, 83, 2, 33, 6, 87, 73, 84, 72, 32, 75, - 2, 11, 65, 2, 199, 204, 37, 83, 14, 40, 4, 79, 82, 68, 32, 171, 146, 37, - 65, 12, 106, 73, 174, 242, 15, 77, 148, 175, 9, 3, 84, 65, 83, 200, 218, - 8, 2, 83, 65, 249, 218, 3, 3, 81, 65, 83, 4, 156, 148, 13, 2, 77, 65, - 253, 132, 19, 3, 83, 72, 77, 12, 138, 1, 66, 64, 3, 75, 85, 78, 205, 239, - 24, 22, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, 76, 69, 70, 32, 77, - 79, 75, 72, 65, 83, 83, 2, 33, 6, 83, 67, 82, 73, 80, 84, 2, 169, 156, - 22, 2, 32, 65, 9, 11, 32, 6, 34, 73, 54, 77, 231, 238, 35, 66, 2, 11, 83, - 2, 213, 204, 31, 5, 79, 76, 65, 84, 69, 2, 11, 69, 2, 11, 68, 2, 11, 73, - 2, 237, 141, 37, 2, 65, 76, 34, 152, 1, 2, 68, 79, 114, 84, 248, 172, 5, - 8, 83, 77, 65, 76, 76, 32, 84, 65, 244, 190, 26, 4, 70, 79, 85, 82, 204, - 123, 4, 87, 65, 83, 76, 239, 209, 4, 82, 6, 88, 16, 85, 66, 76, 69, 32, - 86, 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, 135, 236, 35, 84, 2, 247, - 220, 35, 82, 16, 88, 10, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, 121, 8, - 87, 79, 32, 68, 79, 84, 83, 32, 8, 168, 235, 31, 17, 80, 79, 73, 78, 84, - 73, 78, 71, 32, 68, 79, 87, 78, 87, 65, 82, 68, 146, 128, 4, 66, 167, - 161, 1, 65, 8, 152, 234, 35, 10, 86, 69, 82, 84, 73, 67, 65, 76, 76, 89, - 42, 66, 167, 161, 1, 65, 30, 202, 1, 65, 152, 2, 4, 79, 78, 69, 32, 168, - 244, 10, 12, 82, 73, 80, 76, 69, 32, 68, 79, 84, 32, 80, 85, 144, 197, 6, - 8, 85, 82, 78, 69, 68, 32, 68, 65, 217, 143, 14, 8, 72, 79, 85, 83, 65, - 78, 68, 83, 12, 68, 5, 84, 87, 69, 69, 76, 153, 235, 35, 6, 73, 76, 32, - 70, 82, 65, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 112, 11, 79, 86, 69, - 82, 83, 84, 82, 85, 67, 75, 32, 208, 193, 5, 7, 70, 65, 84, 72, 65, 84, - 65, 155, 231, 4, 84, 4, 26, 72, 143, 134, 37, 87, 2, 169, 228, 29, 2, 65, - 77, 12, 68, 3, 79, 78, 69, 214, 133, 30, 84, 201, 223, 5, 4, 76, 79, 79, - 80, 4, 221, 232, 33, 2, 32, 68, 8, 64, 10, 79, 87, 69, 76, 32, 83, 73, - 71, 78, 32, 183, 137, 24, 69, 6, 72, 10, 73, 78, 86, 69, 82, 84, 69, 68, - 32, 83, 2, 83, 255, 194, 25, 68, 2, 25, 4, 77, 65, 76, 76, 2, 133, 133, - 37, 2, 32, 86, 28, 104, 4, 80, 69, 82, 32, 232, 240, 5, 3, 67, 85, 66, - 156, 137, 5, 5, 70, 79, 85, 82, 84, 227, 149, 25, 68, 4, 158, 142, 25, - 77, 31, 84, 188, 1, 222, 1, 65, 34, 67, 138, 3, 69, 60, 7, 83, 77, 65, - 76, 76, 32, 76, 152, 128, 21, 17, 77, 79, 68, 73, 70, 73, 69, 82, 32, 76, - 69, 84, 84, 69, 82, 32, 76, 162, 248, 8, 72, 252, 182, 2, 3, 68, 82, 65, - 138, 250, 2, 70, 83, 81, 4, 198, 204, 31, 66, 139, 26, 80, 78, 80, 14, - 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 155, 172, 35, 79, - 76, 250, 1, 84, 36, 2, 89, 73, 150, 3, 67, 38, 82, 34, 69, 42, 71, 34, - 74, 38, 75, 22, 80, 38, 83, 106, 65, 22, 86, 158, 1, 76, 130, 141, 31, - 70, 2, 88, 218, 235, 1, 73, 158, 168, 3, 66, 2, 77, 198, 57, 78, 226, 26, - 90, 210, 96, 72, 190, 28, 68, 171, 1, 79, 4, 254, 167, 36, 73, 151, 212, - 1, 79, 5, 143, 172, 37, 87, 4, 138, 230, 31, 88, 169, 198, 4, 6, 77, 80, - 72, 65, 83, 73, 92, 76, 6, 69, 84, 84, 69, 82, 32, 157, 5, 8, 73, 71, 65, - 84, 85, 82, 69, 32, 80, 242, 1, 67, 38, 82, 34, 69, 42, 71, 34, 74, 38, - 75, 22, 80, 38, 83, 34, 84, 74, 65, 22, 86, 32, 2, 89, 73, 126, 76, 130, - 141, 31, 70, 2, 88, 218, 235, 1, 73, 158, 168, 3, 66, 2, 77, 198, 57, 78, - 226, 26, 90, 210, 96, 72, 190, 28, 68, 171, 1, 79, 8, 34, 72, 186, 248, - 37, 65, 3, 79, 4, 166, 247, 37, 69, 147, 1, 65, 6, 134, 247, 37, 67, 146, - 1, 72, 3, 84, 4, 194, 177, 37, 72, 215, 53, 73, 4, 242, 143, 31, 72, 223, - 231, 6, 65, 4, 211, 212, 33, 69, 4, 194, 244, 3, 73, 199, 129, 34, 69, 4, - 186, 244, 37, 72, 171, 1, 69, 6, 68, 7, 85, 82, 78, 69, 68, 32, 65, 250, - 161, 36, 73, 151, 212, 1, 79, 2, 167, 186, 36, 89, 4, 214, 247, 36, 69, - 163, 126, 79, 7, 146, 168, 21, 32, 231, 253, 15, 87, 12, 84, 5, 69, 67, - 72, 32, 89, 20, 4, 77, 69, 78, 32, 241, 237, 29, 4, 86, 69, 87, 32, 2, - 199, 160, 36, 73, 8, 234, 140, 31, 88, 218, 235, 1, 73, 226, 225, 3, 78, - 255, 119, 69, 14, 108, 10, 32, 80, 79, 73, 78, 84, 73, 78, 71, 32, 169, - 181, 36, 11, 72, 69, 65, 68, 45, 83, 72, 65, 80, 69, 68, 12, 156, 2, 24, - 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 84, 72, 69, 78, 32, 67, 85, - 82, 86, 73, 78, 71, 32, 48, 16, 85, 80, 87, 65, 82, 68, 83, 32, 84, 72, - 69, 78, 32, 78, 79, 82, 161, 146, 35, 22, 68, 79, 87, 78, 87, 65, 82, 68, - 83, 32, 84, 72, 69, 78, 32, 67, 85, 82, 86, 73, 78, 71, 6, 44, 3, 83, 79, - 85, 198, 209, 26, 68, 35, 85, 2, 149, 147, 29, 4, 84, 72, 32, 87, 4, 168, - 240, 30, 10, 67, 85, 76, 65, 84, 69, 68, 32, 76, 79, 237, 184, 5, 6, 83, - 84, 32, 80, 65, 76, 20, 58, 67, 38, 84, 142, 153, 23, 89, 173, 191, 9, 2, - 83, 69, 4, 206, 168, 8, 69, 231, 180, 11, 73, 12, 48, 4, 69, 82, 73, 83, - 36, 2, 79, 78, 31, 82, 6, 146, 220, 2, 75, 155, 146, 35, 77, 2, 217, 246, - 13, 2, 73, 83, 4, 250, 231, 30, 65, 221, 255, 4, 22, 79, 78, 79, 77, 73, - 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 85, 82, 4, - 132, 171, 19, 6, 72, 76, 69, 84, 73, 67, 193, 174, 17, 2, 79, 77, 10, 68, - 2, 84, 79, 200, 222, 21, 2, 83, 84, 181, 169, 2, 3, 66, 69, 82, 6, 54, - 77, 129, 237, 36, 7, 32, 82, 73, 67, 75, 83, 72, 4, 174, 135, 24, 79, - 189, 197, 5, 12, 65, 84, 69, 68, 32, 84, 69, 76, 76, 69, 82, 32, 112, 56, - 6, 69, 83, 84, 65, 78, 32, 165, 223, 4, 2, 79, 67, 110, 52, 7, 76, 69, - 84, 84, 69, 82, 32, 159, 183, 31, 65, 108, 234, 1, 65, 58, 71, 42, 72, - 34, 78, 50, 88, 42, 83, 42, 89, 34, 84, 178, 146, 34, 85, 202, 141, 1, - 79, 134, 60, 73, 190, 137, 1, 66, 2, 68, 2, 90, 130, 64, 69, 206, 41, 67, - 2, 70, 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, 2, 82, 3, 86, 17, 230, 155, 35, - 65, 242, 139, 2, 69, 162, 64, 78, 3, 79, 6, 234, 208, 37, 71, 2, 72, 215, - 22, 69, 4, 194, 208, 37, 77, 215, 22, 69, 12, 46, 71, 246, 207, 37, 78, - 2, 89, 215, 22, 69, 6, 242, 207, 37, 86, 2, 89, 215, 22, 69, 8, 38, 72, - 238, 184, 37, 83, 143, 45, 69, 4, 162, 207, 37, 89, 215, 22, 69, 6, 130, - 207, 37, 72, 2, 84, 215, 22, 69, 192, 41, 178, 1, 65, 242, 170, 1, 69, - 252, 15, 9, 72, 65, 73, 75, 83, 85, 75, 73, 32, 202, 6, 73, 130, 3, 76, - 182, 45, 79, 138, 70, 82, 242, 18, 85, 138, 8, 89, 130, 144, 35, 80, 147, - 1, 83, 190, 14, 132, 1, 2, 66, 89, 94, 67, 206, 2, 68, 146, 1, 71, 106, - 76, 192, 29, 4, 77, 85, 77, 32, 238, 114, 78, 178, 1, 82, 98, 83, 223, 6, - 84, 11, 11, 32, 8, 190, 234, 12, 67, 230, 241, 5, 66, 216, 249, 13, 3, - 65, 78, 71, 215, 249, 3, 83, 16, 62, 75, 160, 251, 8, 5, 84, 82, 73, 65, - 78, 211, 150, 28, 79, 12, 42, 32, 46, 83, 153, 222, 10, 2, 45, 84, 4, - 234, 252, 9, 87, 217, 218, 20, 2, 79, 70, 6, 132, 1, 26, 76, 65, 78, 84, - 69, 68, 32, 83, 79, 85, 84, 72, 32, 65, 82, 82, 79, 87, 32, 87, 73, 84, - 72, 32, 72, 79, 235, 162, 37, 80, 4, 130, 189, 29, 82, 221, 182, 5, 2, - 79, 75, 4, 144, 241, 34, 27, 77, 73, 78, 84, 79, 78, 32, 82, 65, 67, 81, - 85, 69, 84, 32, 65, 78, 68, 32, 83, 72, 85, 84, 84, 76, 69, 67, 199, 176, - 2, 71, 6, 192, 226, 30, 6, 85, 69, 84, 84, 69, 32, 190, 242, 5, 69, 229, - 6, 8, 71, 65, 71, 69, 32, 67, 76, 65, 156, 2, 44, 6, 73, 78, 69, 83, 69, - 32, 183, 25, 76, 254, 1, 132, 3, 6, 67, 65, 82, 73, 75, 32, 84, 15, 73, - 78, 86, 69, 82, 84, 69, 68, 32, 67, 65, 82, 73, 75, 32, 68, 7, 76, 69, - 84, 84, 69, 82, 32, 224, 8, 15, 77, 85, 83, 73, 67, 65, 76, 32, 83, 89, - 77, 66, 79, 76, 32, 196, 6, 2, 80, 65, 184, 1, 5, 83, 73, 71, 78, 32, - 176, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 224, 164, 14, 5, - 65, 68, 69, 71, 32, 254, 141, 19, 87, 239, 162, 2, 68, 6, 32, 2, 80, 65, - 219, 129, 3, 83, 4, 86, 82, 145, 249, 30, 5, 77, 85, 78, 71, 75, 4, 36, - 3, 80, 65, 82, 131, 129, 3, 83, 2, 165, 133, 36, 2, 69, 82, 110, 166, 2, - 65, 112, 2, 66, 65, 32, 2, 67, 65, 32, 2, 68, 65, 110, 69, 32, 2, 71, 65, - 30, 73, 2, 79, 2, 85, 36, 2, 74, 65, 30, 75, 68, 2, 76, 65, 18, 78, 72, - 2, 80, 65, 36, 2, 82, 65, 16, 2, 83, 65, 54, 84, 128, 1, 2, 86, 69, 0, 3, - 90, 65, 76, 250, 205, 37, 72, 2, 77, 2, 87, 3, 89, 10, 226, 2, 75, 184, - 3, 5, 83, 89, 85, 82, 65, 172, 162, 15, 8, 82, 67, 72, 65, 73, 67, 32, - 74, 167, 249, 3, 73, 5, 165, 244, 18, 3, 32, 75, 69, 5, 129, 248, 30, 3, - 32, 76, 65, 9, 17, 2, 32, 77, 6, 44, 5, 85, 82, 68, 65, 32, 231, 192, 33, - 65, 4, 130, 176, 14, 77, 25, 3, 65, 76, 80, 4, 254, 3, 70, 231, 139, 37, - 75, 5, 137, 227, 34, 2, 32, 71, 4, 11, 75, 4, 161, 15, 2, 65, 82, 5, 193, - 196, 35, 2, 32, 74, 8, 34, 65, 225, 2, 3, 72, 79, 84, 7, 222, 2, 70, 211, - 171, 14, 32, 7, 131, 13, 32, 8, 34, 65, 134, 208, 37, 71, 3, 89, 5, 173, - 252, 26, 4, 32, 82, 65, 77, 5, 213, 200, 36, 4, 32, 75, 65, 80, 7, 167, - 12, 32, 7, 21, 3, 32, 83, 65, 4, 146, 207, 37, 71, 3, 80, 10, 30, 65, 97, - 3, 90, 73, 82, 9, 11, 32, 6, 160, 172, 14, 6, 77, 85, 82, 68, 65, 32, - 208, 7, 3, 76, 65, 84, 255, 171, 18, 84, 2, 193, 168, 14, 2, 32, 83, 56, - 168, 1, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 246, 1, 68, 172, 1, - 10, 76, 69, 70, 84, 45, 72, 65, 78, 68, 32, 117, 11, 82, 73, 71, 72, 84, - 45, 72, 65, 78, 68, 32, 18, 132, 1, 4, 75, 69, 77, 80, 78, 74, 240, 131, - 20, 2, 66, 69, 180, 182, 7, 3, 69, 78, 68, 148, 171, 3, 3, 84, 69, 71, - 159, 164, 4, 71, 8, 32, 2, 76, 73, 1, 2, 85, 76, 5, 37, 7, 32, 87, 73, - 84, 72, 32, 74, 2, 189, 162, 14, 3, 69, 71, 79, 20, 50, 65, 90, 69, 242, - 250, 36, 73, 2, 79, 3, 85, 10, 40, 2, 78, 71, 158, 251, 36, 69, 3, 73, 7, - 11, 32, 4, 218, 4, 83, 155, 244, 10, 71, 4, 238, 250, 36, 85, 167, 80, - 78, 10, 76, 6, 79, 80, 69, 78, 32, 80, 113, 9, 67, 76, 79, 83, 69, 68, - 32, 80, 76, 6, 254, 249, 36, 65, 2, 73, 3, 85, 8, 72, 8, 67, 76, 79, 83, - 69, 68, 32, 84, 29, 6, 79, 80, 69, 78, 32, 68, 4, 238, 198, 37, 65, 3, - 85, 4, 150, 201, 37, 65, 3, 85, 12, 30, 77, 69, 3, 78, 84, 73, 6, 44, 3, - 65, 68, 65, 241, 133, 35, 2, 69, 78, 5, 69, 2, 32, 76, 7, 11, 32, 4, 38, - 76, 245, 146, 35, 3, 66, 65, 87, 2, 225, 239, 36, 3, 65, 78, 84, 12, 106, - 83, 20, 4, 85, 76, 85, 32, 170, 224, 30, 67, 240, 6, 3, 66, 73, 83, 217, - 249, 1, 4, 82, 69, 82, 69, 2, 179, 232, 24, 85, 4, 254, 194, 20, 67, 237, - 241, 16, 3, 82, 73, 67, 30, 120, 3, 76, 65, 32, 32, 3, 82, 65, 32, 12, 4, - 83, 85, 75, 85, 34, 84, 104, 5, 80, 69, 80, 69, 84, 53, 3, 85, 76, 85, 4, - 165, 1, 4, 76, 69, 78, 71, 4, 115, 82, 5, 237, 203, 36, 3, 32, 73, 76, - 10, 36, 5, 65, 76, 73, 78, 71, 99, 69, 9, 11, 32, 6, 18, 82, 55, 84, 4, - 17, 2, 69, 80, 4, 11, 65, 5, 17, 2, 32, 84, 2, 11, 69, 2, 219, 222, 30, - 68, 5, 181, 230, 30, 3, 32, 83, 65, 30, 86, 79, 228, 147, 23, 5, 32, 79, - 70, 32, 89, 177, 155, 13, 6, 69, 84, 32, 83, 72, 79, 26, 32, 2, 79, 78, - 21, 2, 84, 32, 5, 195, 174, 35, 45, 22, 44, 2, 66, 79, 246, 1, 83, 179, - 192, 37, 88, 18, 38, 88, 205, 1, 4, 76, 68, 32, 83, 17, 33, 6, 32, 87, - 73, 84, 72, 32, 14, 82, 66, 86, 83, 168, 211, 12, 4, 76, 73, 71, 72, 246, - 180, 10, 67, 151, 184, 14, 88, 6, 52, 4, 79, 76, 68, 32, 149, 240, 36, 3, - 65, 76, 76, 4, 26, 83, 159, 136, 23, 67, 2, 165, 211, 12, 4, 67, 82, 73, - 80, 164, 10, 120, 2, 67, 79, 180, 1, 7, 76, 69, 84, 84, 69, 82, 32, 128, - 92, 3, 78, 74, 65, 138, 207, 28, 83, 238, 192, 5, 70, 83, 81, 8, 26, 77, - 135, 239, 36, 76, 6, 72, 12, 66, 73, 78, 73, 78, 71, 32, 77, 65, 82, 75, - 32, 239, 187, 37, 77, 4, 196, 215, 21, 6, 84, 85, 75, 87, 69, 78, 201, - 173, 3, 4, 75, 79, 81, 78, 148, 10, 170, 1, 70, 58, 75, 170, 1, 76, 66, - 77, 102, 78, 234, 1, 80, 214, 103, 82, 102, 83, 134, 1, 84, 54, 89, 178, - 219, 2, 87, 202, 219, 33, 69, 214, 22, 65, 2, 73, 2, 79, 3, 85, 8, 234, - 79, 65, 234, 213, 36, 69, 254, 5, 79, 219, 16, 85, 22, 78, 69, 46, 79, - 190, 203, 35, 89, 130, 237, 1, 80, 186, 2, 65, 2, 73, 3, 85, 6, 250, 174, - 36, 85, 166, 140, 1, 78, 3, 84, 7, 234, 200, 35, 86, 165, 225, 1, 2, 71, - 72, 10, 202, 102, 69, 202, 131, 26, 79, 182, 208, 10, 65, 2, 73, 3, 85, - 19, 62, 69, 174, 101, 66, 158, 212, 36, 65, 2, 73, 2, 79, 3, 85, 4, 142, - 202, 35, 69, 187, 239, 1, 78, 30, 102, 71, 50, 74, 50, 84, 158, 101, 85, - 130, 216, 34, 83, 246, 7, 68, 246, 222, 1, 89, 218, 19, 65, 3, 73, 6, - 186, 209, 32, 75, 202, 228, 4, 71, 187, 2, 65, 6, 242, 205, 26, 85, 198, - 211, 10, 69, 171, 4, 65, 4, 242, 146, 37, 85, 151, 14, 69, 128, 9, 76, 5, - 72, 65, 83, 69, 45, 218, 100, 69, 138, 2, 85, 138, 208, 36, 65, 3, 73, - 244, 8, 116, 2, 65, 32, 168, 18, 2, 66, 32, 136, 13, 2, 67, 32, 160, 20, - 2, 68, 32, 172, 18, 2, 69, 32, 137, 25, 2, 70, 32, 176, 1, 158, 1, 71, - 106, 75, 130, 1, 76, 102, 77, 198, 3, 78, 210, 4, 80, 146, 2, 83, 190, 2, - 84, 154, 1, 85, 184, 198, 30, 2, 70, 73, 150, 238, 4, 86, 215, 222, 1, - 82, 6, 60, 5, 72, 69, 85, 65, 69, 181, 46, 5, 66, 73, 69, 69, 32, 4, 176, - 27, 2, 71, 72, 191, 174, 26, 82, 12, 38, 65, 34, 69, 150, 67, 80, 3, 85, - 4, 254, 176, 37, 70, 187, 2, 81, 4, 240, 214, 33, 5, 85, 75, 69, 85, 84, - 167, 220, 3, 84, 10, 78, 85, 230, 65, 79, 236, 159, 26, 2, 65, 80, 241, - 214, 9, 4, 69, 84, 32, 75, 5, 159, 159, 27, 65, 36, 142, 1, 65, 176, 1, - 2, 66, 65, 38, 79, 76, 6, 86, 69, 85, 65, 69, 78, 244, 70, 8, 69, 85, 78, - 74, 79, 77, 78, 68, 201, 175, 34, 2, 71, 66, 20, 62, 69, 172, 49, 2, 78, - 83, 149, 239, 31, 4, 80, 32, 80, 73, 16, 58, 77, 234, 170, 12, 75, 226, - 168, 7, 78, 211, 200, 17, 83, 11, 186, 24, 66, 14, 71, 194, 44, 86, 239, - 220, 27, 75, 4, 146, 211, 19, 78, 171, 220, 17, 81, 6, 36, 2, 79, 77, - 237, 1, 2, 78, 32, 4, 178, 252, 12, 80, 239, 184, 23, 69, 2, 207, 243, - 35, 71, 48, 122, 65, 32, 2, 68, 65, 54, 71, 98, 75, 32, 2, 83, 72, 38, - 84, 102, 89, 74, 90, 158, 239, 35, 74, 158, 107, 69, 251, 70, 73, 4, 250, - 8, 65, 195, 164, 37, 81, 4, 22, 65, 159, 22, 32, 2, 153, 44, 3, 78, 71, - 71, 8, 52, 3, 75, 85, 69, 222, 188, 32, 65, 239, 155, 3, 71, 4, 250, 7, - 32, 165, 155, 12, 2, 78, 90, 4, 246, 25, 65, 135, 203, 19, 73, 4, 174, - 188, 35, 73, 187, 239, 1, 65, 8, 40, 2, 65, 80, 157, 157, 28, 2, 79, 81, - 7, 11, 32, 4, 188, 184, 35, 2, 77, 70, 1, 2, 78, 84, 6, 26, 73, 155, 142, - 37, 69, 5, 193, 13, 7, 84, 32, 77, 79, 78, 71, 75, 4, 214, 5, 65, 229, - 159, 12, 4, 85, 78, 32, 77, 22, 58, 65, 80, 3, 79, 78, 32, 178, 140, 37, - 69, 163, 28, 85, 10, 42, 65, 154, 18, 32, 250, 17, 77, 15, 83, 4, 230, - 190, 26, 82, 155, 234, 10, 77, 8, 56, 4, 77, 70, 79, 78, 1, 6, 80, 65, - 32, 78, 74, 73, 4, 37, 7, 32, 80, 73, 80, 65, 69, 77, 4, 206, 16, 71, - 243, 148, 37, 66, 22, 70, 72, 194, 1, 79, 192, 66, 2, 69, 85, 170, 190, - 36, 85, 167, 34, 73, 10, 74, 73, 70, 85, 241, 252, 35, 10, 79, 81, 32, - 78, 83, 72, 85, 84, 32, 89, 4, 170, 188, 26, 82, 177, 211, 6, 8, 78, 68, - 65, 32, 80, 65, 32, 78, 4, 188, 11, 4, 69, 78, 83, 72, 195, 154, 37, 77, - 6, 208, 234, 35, 2, 78, 74, 254, 186, 1, 81, 3, 84, 10, 44, 2, 69, 85, - 44, 3, 73, 84, 65, 31, 85, 4, 130, 209, 35, 65, 1, 4, 84, 69, 85, 87, 2, - 11, 32, 2, 223, 30, 77, 4, 186, 26, 32, 251, 246, 26, 65, 4, 228, 3, 5, - 32, 89, 85, 81, 32, 217, 230, 27, 3, 78, 75, 78, 112, 164, 1, 7, 71, 72, - 69, 85, 71, 72, 69, 34, 75, 126, 76, 122, 77, 154, 3, 78, 234, 2, 80, 90, - 83, 178, 1, 84, 106, 89, 190, 22, 87, 204, 46, 2, 70, 69, 131, 201, 11, - 86, 4, 198, 56, 85, 215, 233, 36, 78, 12, 40, 2, 69, 85, 50, 73, 203, - 144, 37, 65, 6, 230, 54, 89, 174, 184, 12, 80, 147, 160, 24, 65, 4, 242, - 142, 37, 69, 175, 18, 81, 8, 46, 65, 240, 69, 2, 79, 77, 183, 190, 36, - 69, 4, 50, 65, 129, 61, 7, 77, 32, 78, 83, 72, 85, 84, 2, 131, 182, 26, - 78, 26, 70, 65, 74, 66, 140, 1, 2, 69, 85, 58, 70, 145, 23, 3, 79, 78, - 84, 7, 21, 3, 32, 78, 74, 4, 178, 212, 18, 85, 229, 142, 17, 3, 69, 85, - 65, 10, 90, 65, 154, 46, 85, 184, 146, 30, 2, 69, 85, 133, 139, 6, 7, 73, - 84, 32, 77, 66, 65, 65, 4, 150, 12, 65, 205, 192, 19, 4, 32, 77, 65, 69, - 4, 252, 141, 32, 5, 84, 32, 78, 71, 71, 239, 143, 5, 81, 4, 48, 4, 79, - 78, 32, 84, 193, 204, 26, 2, 73, 89, 2, 163, 65, 69, 24, 110, 71, 166, 1, - 83, 50, 89, 152, 23, 8, 84, 73, 69, 69, 32, 83, 72, 69, 201, 144, 35, 5, - 68, 85, 32, 78, 74, 12, 70, 71, 164, 162, 36, 8, 75, 73, 78, 68, 73, 32, - 77, 86, 191, 104, 79, 8, 60, 3, 85, 79, 81, 204, 211, 19, 2, 69, 85, 179, - 140, 16, 65, 5, 193, 180, 28, 2, 32, 76, 4, 26, 72, 227, 202, 36, 69, 2, - 167, 229, 36, 85, 4, 248, 45, 2, 65, 69, 211, 17, 73, 8, 200, 195, 10, 2, - 69, 69, 218, 169, 12, 65, 164, 182, 8, 3, 85, 78, 71, 151, 218, 5, 73, - 12, 88, 2, 65, 75, 16, 2, 72, 69, 252, 185, 19, 2, 69, 84, 146, 239, 15, - 73, 231, 216, 1, 85, 2, 211, 25, 69, 4, 128, 200, 26, 4, 84, 32, 78, 74, - 241, 128, 5, 4, 85, 65, 69, 81, 6, 32, 2, 85, 32, 227, 220, 35, 65, 4, - 36, 4, 77, 65, 69, 77, 139, 7, 78, 2, 11, 71, 2, 135, 7, 66, 4, 44, 4, - 65, 70, 85, 32, 229, 4, 2, 69, 85, 2, 221, 165, 32, 6, 76, 69, 69, 82, - 65, 69, 196, 1, 170, 1, 71, 82, 75, 206, 2, 76, 50, 77, 250, 3, 78, 238, - 6, 80, 78, 83, 118, 84, 176, 1, 3, 86, 69, 85, 46, 87, 62, 89, 202, 157, - 30, 66, 182, 218, 2, 70, 163, 230, 3, 82, 6, 40, 2, 72, 65, 185, 184, 19, - 2, 66, 65, 4, 198, 170, 26, 82, 155, 234, 10, 80, 22, 66, 69, 182, 1, 85, - 132, 194, 26, 3, 80, 65, 82, 139, 206, 10, 65, 14, 40, 2, 78, 32, 54, 85, - 155, 147, 37, 84, 4, 180, 136, 33, 4, 70, 65, 84, 73, 235, 140, 3, 76, 8, - 42, 83, 174, 194, 26, 75, 195, 208, 10, 77, 4, 232, 14, 3, 72, 69, 85, - 239, 53, 69, 4, 48, 6, 79, 80, 32, 78, 75, 65, 147, 146, 37, 84, 2, 11, - 65, 2, 235, 167, 26, 82, 8, 202, 47, 65, 242, 145, 26, 73, 183, 208, 10, - 85, 38, 82, 65, 130, 1, 66, 214, 165, 26, 85, 216, 25, 4, 71, 66, 65, 83, - 139, 225, 8, 73, 8, 18, 32, 79, 69, 4, 42, 78, 145, 231, 17, 4, 75, 69, - 85, 65, 2, 11, 83, 2, 231, 160, 35, 73, 4, 226, 226, 36, 77, 211, 25, 83, - 24, 34, 65, 114, 69, 82, 73, 35, 85, 6, 32, 2, 65, 32, 255, 178, 19, 78, - 4, 200, 206, 31, 8, 67, 65, 66, 66, 65, 71, 69, 45, 133, 238, 4, 2, 80, - 73, 8, 50, 85, 142, 164, 26, 82, 173, 218, 5, 2, 69, 75, 4, 162, 142, 37, - 77, 3, 88, 7, 226, 7, 82, 167, 134, 37, 84, 4, 186, 251, 36, 65, 175, 18, - 69, 72, 130, 1, 65, 54, 68, 110, 71, 222, 1, 74, 102, 83, 130, 1, 84, - 102, 90, 237, 7, 12, 89, 73, 82, 32, 77, 75, 80, 65, 82, 65, 81, 32, 4, - 128, 188, 26, 4, 78, 83, 65, 78, 195, 208, 10, 81, 12, 60, 2, 69, 85, - 174, 41, 65, 134, 155, 19, 79, 159, 162, 17, 73, 4, 136, 156, 35, 2, 65, - 69, 199, 239, 1, 84, 20, 50, 71, 98, 75, 222, 185, 26, 65, 223, 191, 10, - 79, 12, 26, 85, 247, 186, 36, 69, 11, 180, 39, 3, 65, 69, 78, 190, 147, - 36, 79, 202, 26, 69, 155, 53, 77, 4, 36, 3, 85, 69, 32, 183, 185, 26, 65, - 2, 241, 179, 19, 3, 77, 65, 69, 10, 34, 65, 34, 69, 183, 214, 12, 85, 4, - 202, 248, 36, 69, 219, 16, 77, 4, 202, 153, 35, 69, 151, 99, 85, 12, 78, - 85, 214, 183, 26, 72, 204, 233, 5, 2, 69, 85, 158, 214, 4, 79, 219, 16, - 65, 4, 224, 244, 36, 4, 79, 84, 32, 78, 179, 19, 78, 8, 54, 69, 244, 234, - 36, 4, 85, 32, 77, 66, 131, 26, 65, 4, 168, 175, 19, 2, 85, 78, 131, 216, - 17, 78, 4, 238, 221, 35, 69, 147, 169, 1, 65, 6, 26, 73, 227, 182, 36, - 69, 4, 26, 82, 167, 134, 37, 78, 2, 175, 178, 35, 73, 10, 30, 69, 50, 72, - 255, 6, 85, 4, 26, 84, 179, 249, 35, 85, 2, 231, 181, 36, 70, 4, 238, - 210, 12, 85, 159, 226, 13, 73, 10, 40, 2, 65, 65, 34, 69, 41, 2, 73, 84, - 2, 11, 83, 2, 203, 154, 26, 72, 4, 228, 25, 2, 85, 84, 235, 234, 36, 84, - 4, 38, 85, 249, 248, 32, 3, 65, 32, 89, 2, 143, 241, 26, 65, 4, 236, 245, - 27, 2, 65, 69, 255, 141, 9, 88, 4, 40, 4, 65, 78, 71, 75, 139, 131, 37, - 85, 2, 143, 19, 85, 10, 42, 85, 158, 208, 12, 69, 135, 176, 24, 65, 6, - 210, 18, 87, 212, 3, 4, 32, 77, 85, 79, 179, 236, 36, 77, 234, 1, 134, 1, - 70, 68, 2, 71, 72, 34, 75, 254, 1, 76, 142, 1, 77, 130, 3, 78, 130, 5, - 80, 122, 82, 90, 83, 190, 1, 84, 158, 1, 87, 39, 89, 4, 36, 3, 69, 85, - 70, 179, 254, 36, 65, 2, 11, 69, 2, 151, 2, 85, 4, 202, 1, 69, 203, 252, - 36, 65, 22, 46, 69, 146, 1, 85, 42, 87, 143, 143, 35, 89, 10, 26, 85, - 227, 255, 36, 84, 8, 72, 3, 65, 69, 84, 20, 5, 79, 84, 32, 77, 66, 130, - 255, 36, 77, 3, 80, 2, 235, 249, 11, 77, 2, 231, 148, 26, 85, 9, 146, - 238, 36, 79, 218, 16, 78, 3, 81, 2, 171, 201, 36, 65, 14, 58, 69, 194, - 173, 26, 79, 254, 224, 8, 73, 227, 222, 1, 85, 8, 42, 85, 146, 142, 35, - 69, 187, 239, 1, 84, 4, 214, 234, 26, 65, 243, 146, 10, 77, 41, 94, 65, - 58, 66, 66, 69, 38, 70, 80, 2, 71, 66, 214, 254, 31, 79, 242, 130, 4, 86, - 151, 121, 85, 4, 164, 211, 17, 2, 76, 69, 133, 244, 18, 3, 69, 78, 74, 6, - 32, 2, 65, 65, 247, 220, 36, 85, 5, 189, 231, 28, 2, 32, 83, 6, 234, 176, - 18, 85, 171, 219, 16, 69, 10, 44, 2, 69, 85, 246, 255, 34, 79, 207, 11, - 73, 4, 162, 228, 36, 65, 215, 22, 84, 6, 158, 139, 35, 73, 168, 70, 2, - 79, 70, 227, 40, 69, 72, 78, 68, 46, 71, 226, 1, 74, 98, 83, 110, 84, 34, - 89, 222, 245, 36, 73, 3, 85, 8, 194, 39, 69, 178, 130, 36, 79, 139, 63, - 65, 24, 18, 71, 99, 75, 12, 54, 65, 202, 42, 69, 162, 231, 31, 87, 147, - 214, 4, 85, 6, 152, 38, 2, 65, 77, 195, 210, 36, 80, 12, 68, 2, 69, 85, - 182, 136, 35, 73, 2, 89, 218, 159, 1, 85, 215, 79, 65, 4, 154, 197, 12, - 65, 251, 158, 24, 82, 12, 60, 2, 69, 85, 230, 15, 73, 214, 180, 12, 85, - 199, 178, 24, 65, 4, 218, 228, 36, 65, 175, 18, 84, 10, 46, 72, 32, 3, - 73, 69, 69, 195, 229, 36, 85, 4, 138, 218, 36, 85, 219, 5, 69, 4, 150, - 246, 36, 80, 3, 84, 6, 130, 14, 69, 147, 195, 36, 85, 8, 174, 217, 36, - 69, 218, 5, 85, 254, 5, 65, 219, 16, 73, 12, 42, 69, 46, 85, 194, 244, - 36, 65, 3, 73, 4, 220, 138, 26, 2, 85, 84, 155, 234, 10, 69, 4, 158, 216, - 36, 85, 175, 28, 81, 8, 48, 3, 69, 78, 32, 162, 224, 36, 73, 175, 1, 65, - 4, 238, 213, 26, 79, 215, 251, 9, 77, 26, 58, 72, 90, 85, 186, 16, 65, - 174, 6, 69, 179, 191, 36, 79, 12, 54, 69, 174, 162, 26, 79, 222, 188, 10, - 73, 219, 19, 85, 6, 214, 7, 85, 139, 235, 36, 69, 6, 234, 219, 36, 65, - 214, 22, 69, 3, 85, 18, 62, 69, 74, 85, 222, 160, 26, 79, 226, 185, 10, - 65, 215, 22, 73, 8, 26, 85, 135, 130, 35, 69, 6, 210, 157, 35, 65, 234, - 211, 1, 78, 3, 84, 5, 227, 212, 36, 79, 4, 134, 138, 32, 85, 235, 230, 4, - 65, 10, 40, 2, 65, 69, 18, 85, 191, 160, 36, 69, 2, 251, 3, 77, 6, 22, - 87, 227, 13, 79, 2, 207, 159, 26, 79, 186, 2, 178, 1, 70, 154, 1, 71, - 202, 1, 75, 170, 1, 76, 158, 1, 77, 134, 2, 78, 190, 7, 80, 166, 2, 82, - 78, 83, 166, 1, 84, 246, 1, 86, 66, 87, 34, 89, 238, 216, 36, 65, 2, 73, - 3, 79, 18, 54, 85, 234, 129, 23, 65, 198, 213, 13, 69, 255, 5, 79, 10, - 26, 32, 135, 142, 31, 69, 6, 132, 229, 23, 4, 82, 69, 77, 69, 146, 129, - 11, 67, 207, 135, 2, 73, 16, 24, 2, 66, 69, 39, 72, 4, 222, 224, 35, 85, - 167, 140, 1, 84, 12, 34, 65, 34, 69, 199, 219, 36, 79, 2, 11, 65, 2, 151, - 130, 26, 77, 8, 26, 85, 131, 236, 36, 84, 6, 170, 213, 36, 65, 214, 22, - 78, 3, 88, 18, 50, 69, 62, 80, 18, 85, 218, 234, 36, 73, 3, 79, 6, 26, - 85, 139, 235, 36, 84, 4, 178, 212, 36, 65, 215, 22, 88, 2, 211, 28, 69, - 6, 170, 206, 36, 69, 162, 28, 79, 15, 84, 18, 50, 65, 40, 2, 69, 85, 22, - 79, 195, 233, 36, 85, 6, 162, 217, 36, 65, 218, 16, 80, 3, 81, 2, 167, - 215, 36, 65, 8, 222, 158, 18, 79, 226, 202, 18, 77, 3, 81, 32, 110, 65, - 44, 2, 66, 69, 34, 70, 20, 2, 71, 66, 34, 73, 142, 253, 25, 85, 186, 154, - 10, 69, 2, 79, 139, 60, 86, 11, 250, 242, 17, 69, 170, 245, 18, 80, 3, - 81, 4, 158, 215, 36, 85, 219, 16, 69, 2, 155, 181, 12, 69, 4, 226, 151, - 36, 69, 227, 79, 65, 5, 207, 208, 36, 69, 80, 114, 68, 170, 1, 71, 138, - 3, 74, 112, 2, 83, 72, 58, 84, 32, 3, 89, 73, 32, 54, 90, 210, 159, 36, - 65, 191, 47, 75, 12, 34, 65, 98, 73, 187, 149, 36, 85, 6, 32, 2, 65, 32, - 215, 229, 36, 80, 4, 240, 164, 18, 3, 77, 89, 32, 137, 177, 13, 3, 83, - 79, 70, 4, 226, 148, 26, 65, 183, 208, 10, 81, 36, 78, 71, 50, 85, 122, - 75, 118, 79, 172, 221, 11, 3, 69, 85, 82, 223, 132, 25, 65, 12, 18, 69, - 51, 85, 6, 26, 85, 191, 244, 34, 69, 4, 255, 144, 24, 65, 6, 64, 6, 65, - 69, 83, 72, 65, 69, 134, 249, 25, 82, 155, 234, 10, 80, 2, 11, 32, 2, - 183, 189, 23, 78, 12, 34, 65, 20, 2, 69, 85, 35, 85, 5, 243, 206, 36, 65, - 4, 150, 208, 36, 65, 175, 18, 88, 4, 162, 226, 36, 77, 3, 80, 4, 134, - 226, 36, 80, 3, 81, 8, 18, 65, 31, 69, 2, 201, 230, 31, 2, 69, 77, 6, 26, - 69, 255, 212, 35, 85, 5, 245, 190, 36, 4, 32, 69, 80, 79, 6, 26, 85, 171, - 241, 34, 73, 4, 210, 224, 36, 79, 15, 69, 4, 234, 207, 36, 85, 207, 16, - 65, 4, 140, 159, 26, 4, 67, 76, 69, 65, 151, 244, 1, 66, 4, 186, 143, 26, - 65, 3, 85, 34, 42, 65, 90, 69, 58, 73, 50, 79, 23, 85, 8, 32, 2, 32, 80, - 223, 233, 17, 65, 4, 196, 148, 28, 2, 69, 79, 241, 192, 7, 2, 76, 85, 6, - 26, 85, 223, 205, 36, 69, 4, 178, 222, 36, 84, 3, 88, 7, 11, 69, 4, 214, - 141, 26, 69, 183, 208, 10, 84, 5, 135, 142, 36, 79, 11, 82, 65, 130, 221, - 36, 69, 3, 77, 8, 46, 65, 238, 14, 69, 149, 246, 18, 2, 73, 77, 4, 254, - 220, 36, 69, 3, 81, 18, 62, 69, 30, 72, 150, 245, 31, 85, 158, 214, 4, - 79, 163, 14, 65, 4, 162, 220, 36, 69, 3, 84, 8, 42, 69, 198, 239, 22, 79, - 231, 155, 3, 73, 2, 137, 169, 12, 2, 85, 65, 28, 34, 65, 94, 69, 50, 79, - 39, 85, 10, 56, 2, 69, 78, 202, 238, 22, 65, 154, 236, 13, 77, 3, 81, 2, - 205, 209, 11, 3, 32, 78, 84, 6, 26, 85, 167, 218, 36, 78, 5, 211, 167, - 12, 65, 6, 138, 223, 34, 79, 135, 251, 1, 81, 6, 170, 7, 77, 239, 187, - 36, 65, 6, 26, 69, 219, 200, 36, 79, 4, 150, 239, 25, 85, 155, 234, 10, - 69, 6, 246, 10, 69, 207, 187, 32, 85, 26, 68, 2, 69, 85, 46, 73, 32, 3, - 79, 81, 32, 54, 85, 155, 215, 36, 65, 8, 174, 133, 24, 65, 246, 210, 12, - 77, 3, 88, 4, 162, 193, 36, 69, 215, 22, 84, 4, 180, 195, 12, 4, 83, 87, - 73, 77, 227, 197, 9, 67, 8, 238, 134, 26, 69, 206, 252, 8, 65, 234, 211, - 1, 78, 3, 81, 108, 162, 1, 75, 82, 76, 46, 77, 98, 78, 190, 1, 80, 66, - 82, 50, 83, 110, 84, 38, 89, 146, 222, 2, 87, 204, 191, 9, 2, 86, 85, - 254, 155, 24, 69, 242, 5, 70, 231, 16, 85, 14, 226, 138, 18, 69, 170, - 219, 16, 89, 130, 237, 1, 80, 186, 2, 65, 2, 79, 3, 85, 6, 190, 132, 26, - 79, 182, 208, 10, 65, 3, 73, 13, 42, 66, 34, 69, 254, 211, 36, 65, 3, 79, - 4, 186, 132, 36, 69, 171, 77, 65, 2, 195, 228, 34, 69, 22, 94, 71, 38, - 74, 38, 85, 130, 216, 34, 83, 246, 7, 68, 150, 3, 84, 226, 219, 1, 89, - 219, 19, 73, 4, 134, 236, 31, 75, 203, 228, 4, 71, 4, 202, 232, 25, 85, - 239, 215, 10, 65, 5, 235, 187, 36, 65, 6, 26, 69, 251, 231, 25, 85, 4, - 234, 197, 35, 85, 167, 140, 1, 69, 12, 186, 2, 69, 150, 134, 9, 73, 159, - 201, 27, 85, 14, 66, 72, 230, 2, 69, 162, 248, 18, 65, 142, 177, 17, 85, - 235, 36, 73, 6, 158, 189, 36, 73, 218, 19, 79, 3, 85, 6, 182, 141, 21, - 65, 239, 166, 15, 69, 4, 246, 255, 25, 79, 183, 208, 10, 65, 4, 178, 185, - 36, 65, 215, 22, 69, 14, 54, 69, 150, 134, 9, 73, 202, 178, 27, 65, 215, - 22, 85, 6, 138, 195, 35, 85, 166, 140, 1, 69, 3, 78, 16, 62, 72, 50, 69, - 162, 248, 18, 65, 142, 177, 17, 85, 235, 36, 73, 8, 46, 69, 190, 186, 36, - 73, 218, 19, 79, 3, 85, 2, 239, 193, 35, 85, 10, 158, 131, 18, 69, 202, - 135, 3, 65, 155, 195, 15, 73, 6, 150, 253, 25, 79, 2, 85, 183, 208, 10, - 65, 14, 42, 75, 242, 144, 35, 65, 147, 157, 1, 74, 11, 49, 10, 78, 79, - 84, 69, 32, 87, 73, 84, 72, 32, 8, 184, 207, 9, 2, 80, 79, 198, 1, 89, - 156, 177, 12, 2, 69, 85, 163, 177, 6, 68, 6, 38, 32, 173, 244, 16, 3, 66, - 69, 82, 4, 134, 202, 29, 67, 213, 240, 5, 5, 79, 70, 32, 83, 79, 78, 72, - 3, 75, 69, 84, 60, 7, 83, 65, 32, 86, 65, 72, 32, 179, 194, 34, 69, 5, - 233, 156, 16, 10, 66, 65, 76, 76, 32, 65, 78, 68, 32, 72, 72, 104, 10, + 170, 60, 65, 250, 3, 74, 135, 5, 89, 10, 40, 5, 87, 73, 84, 72, 32, 255, + 112, 73, 6, 158, 25, 77, 234, 30, 65, 203, 12, 89, 48, 54, 65, 241, 1, 8, + 69, 72, 32, 87, 73, 84, 72, 32, 30, 68, 6, 70, 73, 90, 65, 72, 85, 101, + 7, 72, 32, 87, 73, 84, 72, 32, 8, 22, 77, 247, 28, 32, 4, 30, 32, 1, 3, + 65, 65, 32, 2, 201, 47, 7, 65, 76, 76, 65, 65, 72, 85, 22, 152, 4, 4, 77, + 69, 69, 77, 214, 53, 65, 138, 6, 74, 247, 2, 89, 18, 164, 1, 5, 77, 69, + 69, 77, 32, 204, 12, 6, 65, 76, 69, 70, 32, 77, 150, 2, 89, 158, 45, 74, + 53, 16, 83, 85, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, 76, 69, 70, + 8, 40, 5, 87, 73, 84, 72, 32, 219, 108, 73, 4, 158, 52, 74, 3, 77, 32, + 68, 4, 65, 76, 76, 65, 81, 9, 69, 69, 77, 32, 87, 73, 84, 72, 32, 4, 168, + 145, 4, 7, 74, 65, 76, 65, 76, 79, 85, 189, 190, 24, 4, 32, 87, 65, 45, + 28, 62, 72, 60, 5, 77, 69, 69, 77, 32, 174, 53, 65, 255, 8, 89, 8, 17, 2, + 65, 72, 8, 11, 32, 8, 150, 37, 87, 179, 69, 73, 12, 40, 5, 87, 73, 84, + 72, 32, 131, 106, 73, 8, 154, 45, 72, 242, 3, 65, 203, 12, 89, 66, 58, + 65, 213, 1, 9, 72, 65, 72, 32, 87, 73, 84, 72, 32, 48, 116, 7, 70, 32, + 87, 73, 84, 72, 32, 221, 99, 17, 82, 82, 65, 77, 65, 32, 65, 76, 76, 65, + 65, 72, 85, 32, 87, 65, 74, 46, 192, 53, 2, 65, 76, 218, 1, 74, 96, 2, + 76, 65, 146, 2, 75, 14, 72, 30, 77, 239, 1, 89, 18, 54, 72, 146, 50, 65, + 250, 3, 74, 2, 77, 135, 5, 89, 2, 247, 8, 65, 74, 116, 5, 65, 76, 69, 70, + 32, 210, 1, 72, 124, 5, 74, 69, 69, 77, 32, 78, 75, 28, 5, 77, 69, 69, + 77, 32, 211, 54, 89, 20, 64, 5, 87, 73, 84, 72, 32, 162, 51, 77, 222, 6, + 70, 231, 52, 73, 12, 68, 6, 72, 65, 77, 90, 65, 32, 41, 7, 77, 65, 68, + 68, 65, 32, 65, 8, 38, 65, 145, 53, 4, 66, 69, 76, 79, 4, 253, 52, 3, 66, + 79, 86, 14, 28, 2, 65, 72, 187, 51, 69, 12, 11, 32, 12, 40, 5, 87, 73, + 84, 72, 32, 227, 99, 73, 8, 234, 42, 65, 130, 12, 77, 75, 89, 14, 40, 5, + 87, 73, 84, 72, 32, 147, 99, 73, 10, 154, 54, 74, 2, 77, 75, 89, 8, 237, + 20, 3, 72, 65, 72, 14, 130, 20, 87, 138, 35, 70, 202, 43, 73, 211, 9, 77, + 48, 84, 9, 69, 69, 77, 32, 87, 73, 84, 72, 32, 217, 43, 7, 79, 72, 65, + 77, 77, 65, 68, 46, 116, 5, 65, 76, 69, 70, 32, 66, 72, 0, 2, 75, 72, + 104, 5, 74, 69, 69, 77, 32, 92, 5, 77, 69, 69, 77, 32, 43, 89, 4, 22, 77, + 243, 52, 70, 2, 197, 42, 6, 65, 75, 83, 85, 82, 65, 10, 21, 3, 65, 72, + 32, 10, 40, 5, 87, 73, 84, 72, 32, 207, 95, 73, 6, 146, 39, 74, 2, 77, + 143, 12, 89, 12, 40, 5, 87, 73, 84, 72, 32, 255, 94, 73, 8, 194, 38, 77, + 194, 7, 75, 14, 72, 195, 4, 89, 8, 142, 48, 87, 246, 2, 70, 203, 43, 73, + 2, 11, 69, 2, 167, 40, 72, 62, 144, 1, 9, 79, 79, 78, 32, 87, 73, 84, 72, + 32, 205, 159, 13, 20, 65, 87, 87, 65, 82, 65, 32, 65, 76, 76, 65, 65, 72, + 85, 32, 77, 65, 82, 81, 65, 60, 134, 1, 72, 28, 5, 74, 69, 69, 77, 32, + 92, 5, 77, 69, 69, 77, 32, 246, 37, 65, 154, 5, 78, 78, 90, 134, 1, 75, + 238, 1, 82, 43, 89, 14, 150, 33, 65, 155, 9, 69, 16, 40, 5, 87, 73, 84, + 72, 32, 167, 91, 73, 12, 190, 30, 72, 242, 3, 65, 130, 12, 77, 75, 89, + 12, 194, 21, 87, 234, 25, 70, 202, 43, 73, 211, 9, 77, 36, 46, 65, 209, + 2, 6, 85, 68, 68, 73, 83, 65, 28, 156, 1, 7, 70, 32, 87, 73, 84, 72, 32, + 212, 12, 4, 76, 65, 32, 85, 233, 163, 32, 18, 68, 68, 65, 83, 65, 32, 65, + 76, 76, 65, 65, 72, 85, 32, 83, 73, 82, 82, 24, 64, 5, 77, 69, 69, 77, + 32, 174, 35, 65, 246, 6, 72, 139, 2, 89, 12, 40, 5, 87, 73, 84, 72, 32, + 131, 88, 73, 8, 34, 77, 250, 26, 72, 187, 16, 89, 2, 193, 43, 3, 69, 69, + 77, 8, 68, 5, 32, 83, 73, 82, 82, 45, 8, 84, 32, 65, 83, 82, 65, 65, 82, + 6, 220, 5, 3, 85, 72, 85, 215, 149, 39, 65, 2, 241, 240, 37, 2, 85, 72, + 44, 30, 65, 177, 30, 2, 69, 72, 42, 92, 11, 68, 73, 32, 65, 76, 76, 65, + 65, 72, 85, 32, 170, 1, 72, 153, 30, 4, 83, 79, 85, 76, 18, 72, 3, 65, + 78, 72, 61, 11, 84, 65, 65, 65, 76, 65, 65, 32, 65, 78, 72, 11, 26, 85, + 223, 151, 39, 65, 6, 186, 3, 77, 195, 216, 37, 78, 9, 142, 3, 85, 175, + 148, 39, 65, 22, 92, 5, 73, 77, 65, 72, 85, 149, 1, 13, 77, 65, 84, 85, + 32, 65, 76, 76, 65, 65, 72, 73, 32, 12, 44, 7, 32, 65, 76, 76, 65, 65, + 72, 19, 77, 5, 215, 20, 32, 8, 30, 32, 1, 3, 65, 65, 32, 4, 33, 6, 65, + 76, 76, 65, 65, 72, 5, 211, 18, 85, 10, 92, 5, 65, 76, 65, 89, 72, 241, + 149, 39, 12, 84, 65, 65, 65, 76, 65, 65, 32, 65, 76, 65, 89, 9, 26, 73, + 175, 148, 39, 65, 4, 11, 77, 5, 159, 148, 39, 65, 194, 1, 134, 1, 65, + 220, 7, 9, 69, 69, 78, 32, 87, 73, 84, 72, 32, 250, 3, 72, 201, 4, 12, + 85, 66, 72, 65, 65, 78, 65, 72, 85, 32, 87, 65, 50, 48, 7, 68, 32, 87, + 73, 84, 72, 32, 251, 1, 76, 32, 76, 4, 72, 65, 72, 32, 82, 77, 154, 25, + 65, 138, 4, 75, 246, 4, 82, 3, 89, 10, 22, 87, 211, 78, 73, 6, 25, 4, 73, + 84, 72, 32, 6, 206, 17, 72, 187, 16, 89, 8, 21, 3, 69, 69, 77, 8, 11, 32, + 8, 252, 32, 6, 87, 73, 84, 72, 32, 77, 247, 44, 73, 18, 26, 65, 77, 2, + 76, 65, 4, 178, 23, 77, 137, 134, 37, 11, 65, 77, 85, 72, 85, 32, 65, 76, + 65, 89, 78, 14, 34, 32, 133, 1, 3, 76, 76, 65, 4, 22, 85, 187, 85, 73, 2, + 245, 9, 23, 83, 69, 68, 32, 65, 83, 32, 75, 79, 82, 65, 78, 73, 67, 32, + 83, 84, 79, 80, 32, 83, 73, 71, 10, 36, 4, 65, 72, 85, 32, 147, 1, 72, 4, + 212, 2, 14, 84, 65, 65, 65, 76, 65, 65, 32, 65, 76, 65, 89, 72, 73, 237, + 140, 39, 14, 65, 76, 65, 89, 72, 73, 32, 87, 65, 45, 65, 65, 76, 73, 6, + 112, 11, 85, 32, 65, 76, 65, 89, 72, 73, 32, 87, 65, 205, 63, 12, 79, 85, + 32, 65, 76, 65, 89, 72, 69, 32, 87, 65, 4, 44, 7, 45, 65, 76, 65, 65, 32, + 65, 3, 65, 2, 33, 6, 65, 76, 73, 72, 69, 69, 2, 245, 62, 4, 32, 87, 65, + 45, 60, 130, 1, 72, 100, 5, 74, 69, 69, 77, 32, 84, 5, 75, 72, 65, 72, + 32, 92, 5, 77, 69, 69, 77, 32, 250, 15, 65, 254, 8, 82, 3, 89, 12, 32, 3, + 65, 72, 32, 175, 21, 69, 8, 172, 14, 6, 87, 73, 84, 72, 32, 74, 186, 56, + 73, 211, 9, 77, 10, 52, 5, 87, 73, 84, 72, 32, 242, 69, 73, 211, 9, 77, + 4, 250, 12, 65, 139, 8, 72, 10, 34, 87, 178, 69, 73, 211, 9, 77, 4, 25, + 4, 73, 84, 72, 32, 4, 158, 12, 65, 203, 12, 89, 16, 52, 5, 87, 73, 84, + 72, 32, 194, 68, 73, 211, 9, 77, 10, 218, 7, 72, 174, 4, 74, 199, 11, 77, + 82, 96, 10, 65, 68, 68, 65, 32, 87, 73, 84, 72, 32, 161, 1, 9, 69, 69, + 78, 32, 87, 73, 84, 72, 32, 18, 96, 4, 68, 65, 77, 77, 0, 4, 75, 65, 83, + 82, 154, 11, 83, 245, 41, 6, 70, 65, 84, 72, 65, 32, 6, 11, 65, 6, 28, 2, + 84, 65, 227, 52, 32, 2, 179, 12, 78, 64, 130, 1, 72, 36, 5, 74, 69, 69, + 77, 32, 52, 5, 77, 69, 69, 77, 32, 186, 11, 65, 228, 4, 4, 75, 72, 65, + 72, 154, 4, 82, 3, 89, 18, 210, 15, 69, 229, 3, 2, 65, 72, 10, 174, 18, + 87, 246, 2, 70, 202, 43, 73, 211, 9, 77, 16, 64, 5, 87, 73, 84, 72, 32, + 174, 20, 70, 202, 43, 73, 211, 9, 77, 8, 140, 3, 2, 75, 72, 243, 15, 77, + 2, 175, 1, 32, 122, 66, 65, 176, 2, 8, 69, 72, 32, 87, 73, 84, 72, 32, + 179, 4, 72, 28, 88, 11, 66, 65, 65, 82, 65, 75, 65, 32, 87, 65, 45, 29, + 7, 72, 32, 87, 73, 84, 72, 32, 2, 129, 162, 28, 2, 84, 65, 26, 64, 5, 77, + 69, 69, 77, 32, 194, 8, 65, 246, 6, 72, 139, 2, 89, 14, 52, 5, 87, 73, + 84, 72, 32, 138, 61, 73, 211, 9, 77, 8, 34, 72, 174, 4, 77, 143, 12, 89, + 4, 133, 16, 2, 65, 72, 66, 138, 1, 72, 108, 3, 75, 72, 65, 12, 4, 74, 69, + 69, 77, 92, 5, 77, 69, 69, 77, 32, 238, 4, 65, 154, 5, 78, 78, 90, 242, + 2, 82, 43, 89, 14, 32, 3, 65, 72, 32, 227, 9, 69, 10, 40, 5, 87, 73, 84, + 72, 32, 243, 58, 73, 6, 182, 2, 77, 199, 11, 74, 10, 11, 72, 10, 11, 32, + 10, 40, 5, 87, 73, 84, 72, 32, 147, 58, 73, 6, 154, 1, 65, 62, 77, 143, + 12, 89, 18, 64, 5, 87, 73, 84, 72, 32, 226, 13, 70, 202, 43, 73, 211, 9, + 77, 10, 50, 65, 62, 74, 194, 7, 75, 14, 72, 195, 4, 89, 2, 217, 12, 11, + 76, 69, 70, 32, 77, 65, 75, 83, 85, 82, 65, 2, 225, 7, 3, 69, 69, 77, 28, + 56, 2, 65, 76, 117, 8, 69, 72, 32, 87, 73, 84, 72, 32, 2, 37, 7, 32, 87, + 73, 84, 72, 32, 83, 2, 197, 1, 15, 85, 80, 69, 82, 83, 67, 82, 73, 80, + 84, 32, 65, 76, 69, 70, 26, 108, 3, 74, 69, 69, 126, 65, 198, 4, 77, 86, + 78, 78, 90, 242, 2, 82, 42, 89, 213, 53, 5, 72, 69, 72, 32, 77, 2, 11, + 77, 2, 11, 32, 2, 255, 62, 73, 114, 82, 65, 38, 72, 246, 4, 78, 78, 90, + 38, 74, 98, 75, 42, 77, 198, 1, 82, 43, 89, 4, 217, 2, 5, 76, 69, 70, 32, + 77, 76, 22, 65, 139, 3, 69, 72, 80, 15, 77, 90, 65, 32, 65, 66, 79, 86, + 69, 32, 87, 73, 84, 72, 32, 147, 5, 72, 66, 118, 65, 126, 69, 42, 72, 78, + 74, 18, 75, 62, 77, 86, 78, 22, 79, 16, 2, 87, 65, 18, 89, 26, 90, 242, + 2, 82, 67, 85, 12, 22, 76, 247, 6, 69, 8, 21, 3, 69, 70, 32, 8, 34, 77, + 222, 6, 70, 231, 52, 73, 4, 181, 6, 6, 65, 75, 83, 85, 82, 65, 6, 11, 32, + 6, 166, 6, 70, 203, 43, 73, 8, 22, 69, 191, 3, 65, 4, 11, 72, 4, 11, 32, + 4, 230, 4, 73, 143, 54, 77, 4, 223, 48, 69, 2, 11, 72, 2, 11, 65, 2, 11, + 72, 2, 149, 4, 2, 32, 73, 8, 17, 2, 69, 69, 8, 11, 77, 8, 11, 32, 8, 198, + 4, 70, 202, 43, 73, 211, 9, 77, 2, 93, 2, 79, 79, 4, 231, 3, 69, 4, 215, + 3, 87, 8, 186, 3, 69, 15, 85, 2, 17, 2, 65, 73, 2, 239, 2, 78, 6, 21, 3, + 69, 69, 77, 6, 11, 32, 6, 22, 87, 191, 46, 73, 2, 141, 2, 5, 73, 84, 72, + 32, 89, 4, 11, 72, 4, 11, 65, 4, 235, 45, 72, 14, 21, 3, 69, 69, 77, 14, + 11, 32, 14, 64, 5, 87, 73, 84, 72, 32, 194, 1, 70, 202, 43, 73, 211, 9, + 77, 6, 18, 77, 75, 89, 4, 21, 3, 69, 69, 77, 4, 11, 32, 4, 18, 73, 119, + 70, 2, 211, 44, 78, 2, 17, 2, 69, 72, 2, 77, 2, 32, 70, 4, 11, 69, 4, 11, + 72, 4, 11, 32, 4, 22, 70, 231, 52, 73, 2, 185, 53, 2, 73, 78, 6, 174, 43, + 73, 211, 9, 77, 166, 2, 92, 3, 68, 68, 65, 52, 3, 82, 75, 32, 109, 11, + 84, 72, 69, 77, 65, 84, 73, 67, 65, 76, 32, 4, 244, 177, 37, 5, 32, 87, + 65, 65, 74, 131, 65, 72, 4, 58, 78, 1, 10, 83, 73, 68, 69, 87, 65, 89, + 83, 32, 78, 2, 201, 180, 35, 7, 79, 79, 78, 32, 71, 72, 85, 158, 2, 174, + 2, 68, 140, 3, 8, 73, 78, 73, 84, 73, 65, 76, 32, 222, 1, 76, 132, 2, 9, + 79, 80, 69, 82, 65, 84, 79, 82, 32, 166, 1, 83, 142, 3, 84, 130, 190, 24, + 65, 102, 75, 110, 90, 234, 106, 74, 2, 77, 250, 192, 6, 66, 2, 70, 2, 82, + 2, 89, 222, 7, 72, 222, 58, 71, 254, 136, 3, 78, 250, 168, 2, 81, 135, 3, + 87, 62, 26, 79, 219, 233, 37, 65, 58, 88, 6, 84, 76, 69, 83, 83, 32, 61, + 12, 85, 66, 76, 69, 45, 83, 84, 82, 85, 67, 75, 32, 8, 210, 245, 31, 66, + 2, 70, 182, 203, 3, 78, 251, 168, 2, 81, 50, 178, 12, 83, 174, 20, 75, + 146, 168, 24, 84, 74, 90, 234, 106, 74, 2, 77, 250, 192, 6, 66, 2, 70, 2, + 82, 2, 89, 222, 7, 72, 222, 58, 71, 254, 136, 3, 78, 154, 237, 1, 76, + 210, 58, 68, 146, 1, 81, 222, 1, 65, 171, 1, 87, 40, 182, 1, 84, 166, 9, + 83, 254, 187, 24, 72, 30, 75, 214, 107, 74, 2, 77, 250, 192, 6, 66, 2, + 70, 2, 89, 186, 66, 71, 254, 136, 3, 78, 154, 237, 1, 76, 226, 59, 81, + 222, 1, 65, 171, 57, 68, 4, 134, 242, 31, 72, 207, 244, 6, 69, 56, 48, 6, + 79, 79, 80, 69, 68, 32, 183, 214, 38, 65, 54, 202, 8, 83, 174, 20, 75, + 138, 167, 24, 65, 74, 72, 66, 84, 74, 90, 234, 106, 74, 2, 77, 250, 192, + 6, 66, 2, 70, 2, 82, 2, 89, 186, 66, 71, 254, 136, 3, 78, 154, 237, 1, + 76, 210, 58, 68, 146, 1, 81, 135, 3, 87, 4, 148, 161, 29, 23, 77, 69, 69, + 77, 32, 87, 73, 84, 72, 32, 72, 65, 72, 32, 87, 73, 84, 72, 32, 84, 65, + 84, 87, 197, 174, 8, 9, 72, 65, 72, 32, 87, 73, 84, 72, 32, 52, 84, 9, + 84, 82, 69, 84, 67, 72, 69, 68, 32, 178, 141, 37, 72, 14, 69, 231, 143, + 1, 65, 46, 178, 1, 68, 86, 84, 250, 2, 83, 254, 187, 24, 72, 30, 75, 214, + 107, 74, 2, 77, 250, 192, 6, 66, 2, 70, 2, 89, 222, 7, 90, 222, 58, 71, + 254, 136, 3, 78, 250, 168, 2, 81, 223, 1, 65, 6, 52, 7, 79, 84, 76, 69, + 83, 83, 32, 183, 155, 38, 65, 4, 246, 235, 31, 66, 3, 70, 6, 218, 235, + 31, 72, 206, 244, 6, 65, 3, 69, 38, 42, 65, 130, 191, 24, 72, 211, 160, + 14, 69, 32, 44, 5, 73, 76, 69, 68, 32, 179, 224, 38, 72, 30, 146, 1, 68, + 94, 83, 174, 20, 75, 194, 147, 25, 74, 250, 192, 6, 89, 222, 7, 72, 222, + 58, 71, 254, 136, 3, 78, 154, 237, 1, 76, 226, 59, 81, 223, 1, 65, 6, 52, + 7, 79, 84, 76, 69, 83, 83, 32, 199, 152, 38, 65, 4, 186, 180, 35, 78, + 251, 168, 2, 81, 6, 174, 136, 37, 72, 14, 69, 231, 143, 1, 65, 4, 250, + 219, 18, 77, 179, 251, 18, 83, 6, 192, 135, 25, 3, 75, 65, 83, 12, 4, 68, + 65, 77, 77, 1, 4, 70, 65, 84, 72, 12, 118, 69, 38, 79, 144, 217, 12, 11, + 76, 65, 67, 69, 32, 79, 70, 32, 83, 65, 74, 201, 128, 6, 6, 73, 65, 83, + 84, 82, 69, 4, 202, 189, 32, 82, 199, 233, 5, 80, 4, 224, 201, 12, 8, 69, + 84, 73, 67, 32, 86, 69, 82, 245, 143, 6, 3, 85, 78, 68, 14, 238, 1, 65, + 96, 5, 69, 86, 69, 82, 83, 36, 15, 73, 71, 72, 84, 32, 65, 82, 82, 79, + 87, 72, 69, 65, 68, 32, 157, 186, 23, 28, 79, 85, 78, 68, 69, 68, 32, 72, + 73, 71, 72, 32, 83, 84, 79, 80, 32, 87, 73, 84, 72, 32, 70, 73, 76, 76, + 69, 68, 4, 40, 4, 73, 83, 69, 68, 155, 217, 38, 89, 2, 17, 2, 32, 82, 2, + 233, 138, 37, 3, 79, 85, 78, 2, 225, 241, 21, 4, 69, 68, 32, 68, 6, 26, + 65, 187, 182, 36, 66, 4, 249, 177, 37, 3, 66, 79, 86, 206, 1, 238, 1, 69, + 244, 2, 5, 72, 65, 68, 68, 65, 36, 4, 73, 71, 78, 32, 240, 4, 5, 77, 65, + 76, 76, 32, 222, 15, 85, 240, 2, 6, 89, 77, 66, 79, 76, 32, 197, 253, 36, + 18, 84, 65, 82, 84, 32, 79, 70, 32, 82, 85, 66, 32, 69, 76, 32, 72, 73, + 90, 20, 52, 7, 81, 85, 69, 78, 67, 69, 32, 215, 134, 35, 77, 18, 184, 1, + 26, 89, 69, 72, 32, 87, 73, 84, 72, 32, 72, 65, 77, 90, 65, 32, 65, 66, + 79, 86, 69, 32, 87, 73, 84, 72, 32, 193, 222, 31, 13, 78, 79, 79, 78, 32, + 87, 73, 84, 72, 32, 75, 69, 72, 16, 70, 65, 170, 213, 37, 87, 198, 89, + 89, 150, 14, 79, 214, 22, 69, 3, 85, 6, 36, 3, 76, 69, 70, 175, 211, 38, + 69, 5, 251, 12, 32, 7, 11, 32, 4, 222, 22, 73, 55, 77, 22, 132, 1, 2, 82, + 65, 158, 1, 83, 188, 1, 7, 65, 76, 65, 89, 72, 69, 32, 136, 15, 2, 77, + 73, 133, 181, 34, 6, 84, 65, 75, 72, 65, 76, 4, 132, 1, 13, 72, 77, 65, + 84, 85, 76, 76, 65, 72, 32, 65, 76, 65, 161, 218, 33, 13, 68, 73, 32, 65, + 76, 76, 65, 72, 79, 85, 32, 65, 78, 2, 219, 163, 38, 89, 12, 46, 65, 193, + 1, 6, 73, 78, 68, 72, 73, 32, 8, 136, 1, 18, 76, 76, 65, 76, 76, 65, 72, + 79, 85, 32, 65, 76, 65, 89, 72, 69, 32, 87, 154, 225, 31, 78, 218, 240, + 4, 70, 249, 115, 2, 77, 86, 2, 17, 2, 65, 83, 2, 141, 242, 15, 3, 83, 65, + 76, 4, 160, 227, 20, 12, 80, 79, 83, 84, 80, 79, 83, 73, 84, 73, 79, 78, + 205, 152, 14, 2, 65, 77, 110, 120, 2, 70, 65, 32, 5, 72, 73, 71, 72, 32, + 134, 11, 89, 88, 4, 76, 79, 87, 32, 118, 75, 158, 217, 21, 68, 215, 232, + 15, 87, 4, 166, 3, 82, 191, 204, 36, 84, 74, 212, 2, 17, 68, 79, 84, 76, + 69, 83, 83, 32, 72, 69, 65, 68, 32, 79, 70, 32, 75, 22, 70, 102, 76, 142, + 3, 77, 118, 83, 78, 84, 38, 87, 198, 2, 89, 142, 1, 78, 180, 195, 14, 18, + 85, 80, 82, 73, 71, 72, 84, 32, 82, 69, 67, 84, 65, 78, 71, 85, 76, 65, + 252, 220, 8, 7, 82, 79, 85, 78, 68, 69, 68, 242, 126, 90, 234, 106, 74, + 166, 181, 12, 81, 223, 1, 65, 2, 147, 220, 31, 72, 4, 24, 2, 65, 82, 31, + 79, 2, 11, 83, 2, 175, 2, 73, 2, 233, 209, 26, 6, 79, 84, 78, 79, 84, 69, + 10, 60, 8, 73, 71, 65, 84, 85, 82, 69, 32, 225, 11, 2, 65, 77, 8, 88, 10, + 65, 76, 69, 70, 32, 87, 73, 84, 72, 32, 116, 3, 81, 65, 70, 1, 3, 83, 65, + 68, 4, 84, 8, 76, 65, 77, 32, 87, 73, 84, 72, 253, 212, 36, 7, 89, 69, + 72, 32, 66, 65, 82, 2, 201, 209, 31, 2, 32, 89, 2, 89, 20, 32, 87, 73, + 84, 72, 32, 76, 65, 77, 32, 87, 73, 84, 72, 32, 65, 76, 69, 70, 32, 2, + 133, 173, 22, 3, 77, 65, 75, 6, 26, 69, 191, 142, 16, 65, 4, 17, 2, 69, + 77, 4, 17, 2, 32, 73, 4, 22, 78, 147, 9, 83, 2, 205, 9, 2, 73, 84, 6, + 240, 199, 36, 7, 73, 71, 78, 32, 83, 65, 70, 166, 39, 69, 231, 143, 1, + 65, 4, 166, 224, 23, 72, 155, 227, 14, 65, 20, 40, 4, 79, 82, 68, 32, + 227, 197, 37, 65, 18, 74, 65, 172, 1, 2, 83, 65, 168, 201, 25, 3, 87, 65, + 81, 247, 246, 11, 81, 10, 244, 137, 7, 3, 76, 45, 74, 188, 200, 18, 3, + 82, 45, 82, 240, 230, 6, 7, 84, 72, 45, 84, 72, 65, 76, 236, 136, 5, 5, + 78, 45, 78, 73, 83, 161, 92, 5, 83, 45, 83, 65, 74, 4, 186, 157, 38, 75, + 207, 36, 72, 4, 17, 2, 69, 72, 5, 157, 196, 10, 12, 32, 66, 65, 82, 82, + 69, 69, 32, 87, 73, 84, 72, 22, 50, 78, 98, 87, 170, 137, 25, 77, 199, + 224, 11, 83, 4, 21, 3, 79, 79, 78, 5, 37, 7, 32, 87, 73, 84, 72, 32, 75, + 2, 11, 65, 2, 207, 251, 37, 83, 14, 40, 4, 79, 82, 68, 32, 179, 193, 37, + 65, 12, 106, 73, 162, 135, 16, 77, 128, 182, 9, 3, 84, 65, 83, 208, 228, + 8, 2, 83, 65, 153, 228, 3, 3, 81, 65, 83, 4, 168, 168, 13, 2, 77, 65, + 181, 145, 19, 3, 83, 72, 77, 12, 138, 1, 66, 64, 3, 75, 85, 78, 141, 139, + 25, 22, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, 76, 69, 70, 32, 77, + 79, 75, 72, 65, 83, 83, 2, 33, 6, 83, 67, 82, 73, 80, 84, 2, 137, 184, + 22, 2, 32, 65, 9, 11, 32, 6, 34, 73, 54, 77, 147, 154, 36, 66, 2, 11, 83, + 2, 209, 237, 31, 5, 79, 76, 65, 84, 69, 2, 11, 69, 2, 11, 68, 2, 11, 73, + 2, 245, 188, 37, 2, 65, 76, 34, 156, 1, 2, 68, 79, 126, 84, 188, 183, 5, + 8, 83, 77, 65, 76, 76, 32, 84, 65, 200, 212, 26, 4, 70, 79, 85, 82, 224, + 129, 1, 4, 87, 65, 83, 76, 187, 218, 4, 82, 6, 48, 6, 85, 66, 76, 69, 32, + 86, 215, 151, 36, 84, 2, 49, 10, 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, + 2, 155, 136, 36, 82, 16, 88, 10, 72, 82, 69, 69, 32, 68, 79, 84, 83, 32, + 121, 8, 87, 79, 32, 68, 79, 84, 83, 32, 8, 192, 139, 32, 17, 80, 79, 73, + 78, 84, 73, 78, 71, 32, 68, 79, 87, 78, 87, 65, 82, 68, 150, 139, 4, 66, + 131, 165, 1, 65, 8, 128, 186, 10, 9, 86, 69, 82, 84, 73, 67, 65, 76, 76, + 222, 219, 25, 66, 131, 165, 1, 65, 30, 202, 1, 65, 152, 2, 4, 79, 78, 69, + 32, 164, 130, 11, 12, 82, 73, 80, 76, 69, 32, 68, 79, 84, 32, 80, 85, + 144, 205, 6, 8, 85, 82, 78, 69, 68, 32, 68, 65, 197, 154, 14, 8, 72, 79, + 85, 83, 65, 78, 68, 83, 12, 68, 5, 84, 87, 69, 69, 76, 177, 150, 36, 6, + 73, 76, 32, 70, 82, 65, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 112, 11, + 79, 86, 69, 82, 83, 84, 82, 85, 67, 75, 32, 140, 205, 5, 7, 70, 65, 84, + 72, 65, 84, 65, 159, 233, 4, 84, 4, 26, 72, 131, 181, 37, 87, 2, 133, + 133, 30, 2, 65, 77, 12, 68, 3, 79, 78, 69, 194, 166, 30, 84, 245, 233, 5, + 4, 76, 79, 79, 80, 4, 173, 142, 34, 2, 32, 68, 8, 64, 10, 79, 87, 69, 76, + 32, 83, 73, 71, 78, 32, 255, 164, 24, 69, 6, 72, 10, 73, 78, 86, 69, 82, + 84, 69, 68, 32, 83, 2, 83, 211, 222, 25, 68, 2, 25, 4, 77, 65, 76, 76, 2, + 249, 179, 37, 2, 32, 86, 28, 104, 4, 80, 69, 82, 32, 236, 253, 5, 3, 67, + 85, 66, 204, 138, 5, 5, 70, 79, 85, 82, 84, 187, 179, 25, 68, 4, 234, + 169, 25, 77, 31, 84, 188, 1, 222, 1, 65, 34, 67, 138, 3, 69, 60, 7, 83, + 77, 65, 76, 76, 32, 76, 200, 155, 21, 17, 77, 79, 68, 73, 70, 73, 69, 82, + 32, 76, 69, 84, 84, 69, 82, 32, 76, 222, 253, 8, 72, 140, 188, 2, 3, 68, + 82, 65, 178, 255, 2, 70, 83, 81, 4, 218, 236, 31, 66, 143, 26, 80, 78, + 80, 14, 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 191, 215, + 35, 79, 76, 250, 1, 84, 36, 2, 89, 73, 150, 3, 67, 38, 82, 34, 69, 42, + 71, 34, 74, 38, 75, 22, 80, 38, 83, 106, 65, 22, 86, 158, 1, 76, 246, + 173, 31, 70, 2, 88, 134, 241, 1, 73, 214, 174, 3, 66, 2, 77, 222, 57, 78, + 230, 28, 90, 210, 96, 72, 190, 28, 68, 171, 1, 79, 4, 214, 212, 36, 73, + 179, 214, 1, 79, 5, 131, 219, 37, 87, 4, 162, 134, 32, 88, 233, 210, 4, + 6, 77, 80, 72, 65, 83, 73, 92, 76, 6, 69, 84, 84, 69, 82, 32, 157, 5, 8, + 73, 71, 65, 84, 85, 82, 69, 32, 80, 242, 1, 67, 38, 82, 34, 69, 42, 71, + 34, 74, 38, 75, 22, 80, 38, 83, 34, 84, 74, 65, 22, 86, 32, 2, 89, 73, + 126, 76, 246, 173, 31, 70, 2, 88, 134, 241, 1, 73, 214, 174, 3, 66, 2, + 77, 222, 57, 78, 230, 28, 90, 210, 96, 72, 190, 28, 68, 171, 1, 79, 8, + 34, 72, 174, 167, 38, 65, 3, 79, 4, 154, 166, 38, 69, 147, 1, 65, 6, 250, + 165, 38, 67, 146, 1, 72, 3, 84, 4, 182, 224, 37, 72, 215, 53, 73, 4, 230, + 176, 31, 72, 223, 245, 6, 65, 4, 223, 250, 33, 69, 4, 214, 251, 3, 73, + 167, 169, 34, 69, 4, 174, 163, 38, 72, 171, 1, 69, 6, 68, 7, 85, 82, 78, + 69, 68, 32, 65, 210, 206, 36, 73, 179, 214, 1, 79, 2, 135, 231, 36, 89, + 4, 202, 166, 37, 69, 163, 126, 79, 7, 194, 195, 21, 32, 171, 145, 16, 87, + 12, 84, 5, 69, 67, 72, 32, 89, 20, 4, 77, 69, 78, 32, 221, 142, 30, 4, + 86, 69, 87, 32, 2, 159, 205, 36, 73, 8, 222, 173, 31, 88, 134, 241, 1, + 73, 178, 232, 3, 78, 131, 122, 69, 14, 108, 10, 32, 80, 79, 73, 78, 84, + 73, 78, 71, 32, 137, 226, 36, 11, 72, 69, 65, 68, 45, 83, 72, 65, 80, 69, + 68, 12, 156, 2, 24, 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 84, 72, + 69, 78, 32, 67, 85, 82, 86, 73, 78, 71, 32, 48, 16, 85, 80, 87, 65, 82, + 68, 83, 32, 84, 72, 69, 78, 32, 78, 79, 82, 197, 189, 35, 22, 68, 79, 87, + 78, 87, 65, 82, 68, 83, 32, 84, 72, 69, 78, 32, 67, 85, 82, 86, 73, 78, + 71, 6, 44, 3, 83, 79, 85, 222, 237, 26, 68, 35, 85, 2, 153, 173, 34, 4, + 84, 72, 32, 87, 4, 176, 217, 31, 11, 67, 85, 76, 65, 84, 69, 68, 32, 76, + 79, 82, 189, 252, 4, 6, 83, 84, 32, 80, 65, 76, 24, 58, 67, 38, 84, 206, + 180, 23, 89, 145, 202, 9, 2, 83, 69, 4, 242, 181, 8, 69, 167, 194, 11, + 73, 16, 48, 4, 69, 82, 73, 83, 36, 2, 79, 78, 31, 82, 6, 174, 227, 2, 75, + 239, 185, 35, 77, 2, 237, 138, 14, 2, 73, 83, 8, 104, 20, 79, 78, 79, 77, + 73, 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 211, 138, + 14, 65, 4, 164, 227, 25, 13, 65, 83, 84, 69, 82, 79, 73, 68, 32, 80, 82, + 79, 83, 205, 175, 10, 2, 85, 82, 4, 164, 197, 19, 6, 72, 76, 69, 84, 73, + 67, 165, 192, 17, 2, 79, 77, 10, 68, 2, 84, 79, 160, 249, 21, 2, 83, 84, + 209, 169, 2, 3, 66, 69, 82, 6, 54, 77, 161, 155, 37, 7, 32, 82, 73, 67, + 75, 83, 72, 4, 162, 162, 24, 79, 209, 202, 5, 12, 65, 84, 69, 68, 32, 84, + 69, 76, 76, 69, 82, 32, 112, 56, 6, 69, 83, 84, 65, 78, 32, 169, 231, 4, + 2, 79, 67, 110, 52, 7, 76, 69, 84, 84, 69, 82, 32, 223, 214, 31, 65, 108, + 234, 1, 65, 58, 71, 42, 72, 34, 78, 50, 88, 42, 83, 42, 89, 34, 84, 254, + 188, 34, 85, 206, 141, 1, 79, 238, 60, 73, 166, 140, 1, 66, 2, 68, 2, 90, + 130, 64, 69, 206, 41, 67, 2, 70, 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, 2, + 82, 3, 86, 17, 182, 198, 35, 65, 194, 143, 2, 69, 162, 64, 78, 3, 79, 6, + 138, 255, 37, 71, 2, 72, 215, 22, 69, 4, 226, 254, 37, 77, 215, 22, 69, + 12, 46, 71, 150, 254, 37, 78, 2, 89, 215, 22, 69, 6, 146, 254, 37, 86, 2, + 89, 215, 22, 69, 8, 38, 72, 142, 231, 37, 83, 143, 45, 69, 4, 194, 253, + 37, 89, 215, 22, 69, 6, 162, 253, 37, 72, 2, 84, 215, 22, 69, 178, 42, + 178, 1, 65, 194, 171, 1, 69, 244, 21, 9, 72, 65, 73, 75, 83, 85, 75, 73, + 32, 202, 6, 73, 130, 3, 76, 182, 45, 79, 138, 70, 82, 246, 18, 85, 138, + 8, 89, 214, 183, 35, 80, 147, 1, 83, 198, 14, 132, 1, 2, 66, 89, 94, 67, + 206, 2, 68, 146, 1, 71, 106, 76, 192, 29, 4, 77, 85, 77, 32, 190, 115, + 78, 178, 1, 82, 98, 83, 223, 6, 84, 11, 11, 32, 8, 226, 253, 12, 67, 222, + 248, 5, 66, 144, 133, 14, 3, 65, 78, 71, 135, 128, 4, 83, 16, 62, 75, + 244, 135, 9, 5, 84, 82, 73, 65, 78, 159, 184, 28, 79, 12, 42, 32, 46, 83, + 145, 236, 10, 2, 45, 84, 4, 214, 137, 10, 87, 253, 237, 20, 2, 79, 70, 6, + 132, 1, 26, 76, 65, 78, 84, 69, 68, 32, 83, 79, 85, 84, 72, 32, 65, 82, + 82, 79, 87, 32, 87, 73, 84, 72, 32, 72, 79, 139, 209, 37, 80, 4, 138, + 221, 29, 82, 165, 193, 5, 2, 79, 75, 4, 224, 155, 35, 27, 77, 73, 78, 84, + 79, 78, 32, 82, 65, 67, 81, 85, 69, 84, 32, 65, 78, 68, 32, 83, 72, 85, + 84, 84, 76, 69, 67, 151, 180, 2, 71, 6, 224, 130, 31, 6, 85, 69, 84, 84, + 69, 32, 162, 254, 5, 69, 129, 9, 8, 71, 65, 71, 69, 32, 67, 76, 65, 156, + 2, 44, 6, 73, 78, 69, 83, 69, 32, 183, 25, 76, 254, 1, 132, 3, 6, 67, 65, + 82, 73, 75, 32, 84, 15, 73, 78, 86, 69, 82, 84, 69, 68, 32, 67, 65, 82, + 73, 75, 32, 68, 7, 76, 69, 84, 84, 69, 82, 32, 224, 8, 15, 77, 85, 83, + 73, 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 196, 6, 2, 80, 65, 184, + 1, 5, 83, 73, 71, 78, 32, 176, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, + 78, 32, 220, 184, 14, 5, 65, 68, 69, 71, 32, 130, 159, 19, 87, 167, 169, + 2, 68, 6, 32, 2, 80, 65, 167, 136, 3, 83, 4, 86, 82, 177, 153, 31, 5, 77, + 85, 78, 71, 75, 4, 36, 3, 80, 65, 82, 207, 135, 3, 83, 2, 169, 177, 36, + 2, 69, 82, 110, 166, 2, 65, 112, 2, 66, 65, 32, 2, 67, 65, 32, 2, 68, 65, + 110, 69, 32, 2, 71, 65, 30, 73, 2, 79, 2, 85, 36, 2, 74, 65, 30, 75, 68, + 2, 76, 65, 18, 78, 72, 2, 80, 65, 36, 2, 82, 65, 16, 2, 83, 65, 54, 84, + 128, 1, 2, 86, 69, 0, 3, 90, 65, 76, 154, 252, 37, 72, 2, 77, 2, 87, 3, + 89, 10, 226, 2, 75, 184, 3, 5, 83, 89, 85, 82, 65, 184, 182, 15, 8, 82, + 67, 72, 65, 73, 67, 32, 74, 187, 255, 3, 73, 5, 197, 142, 19, 3, 32, 75, + 69, 5, 161, 152, 31, 3, 32, 76, 65, 9, 17, 2, 32, 77, 6, 44, 5, 85, 82, + 68, 65, 32, 231, 229, 33, 65, 4, 254, 195, 14, 77, 25, 3, 65, 76, 80, 4, + 254, 3, 70, 135, 186, 37, 75, 5, 217, 141, 35, 2, 32, 71, 4, 11, 75, 4, + 161, 15, 2, 65, 82, 5, 249, 239, 35, 2, 32, 74, 8, 34, 65, 225, 2, 3, 72, + 79, 84, 7, 222, 2, 70, 207, 191, 14, 32, 7, 131, 13, 32, 8, 34, 65, 166, + 254, 37, 71, 3, 89, 5, 233, 151, 27, 4, 32, 82, 65, 77, 5, 217, 244, 36, + 4, 32, 75, 65, 80, 7, 167, 12, 32, 7, 21, 3, 32, 83, 65, 4, 178, 253, 37, + 71, 3, 80, 10, 30, 65, 97, 3, 90, 73, 82, 9, 11, 32, 6, 156, 192, 14, 6, + 77, 85, 82, 68, 65, 32, 212, 7, 3, 76, 65, 84, 203, 189, 18, 84, 2, 189, + 188, 14, 2, 32, 83, 56, 168, 1, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, + 32, 246, 1, 68, 172, 1, 10, 76, 69, 70, 84, 45, 72, 65, 78, 68, 32, 117, + 11, 82, 73, 71, 72, 84, 45, 72, 65, 78, 68, 32, 18, 132, 1, 4, 75, 69, + 77, 80, 78, 74, 168, 158, 20, 2, 66, 69, 168, 187, 7, 3, 69, 78, 68, 136, + 172, 3, 3, 84, 69, 71, 207, 174, 4, 71, 8, 32, 2, 76, 73, 1, 2, 85, 76, + 5, 37, 7, 32, 87, 73, 84, 72, 32, 74, 2, 185, 182, 14, 3, 69, 71, 79, 20, + 50, 65, 90, 69, 146, 169, 37, 73, 2, 79, 3, 85, 10, 40, 2, 78, 71, 190, + 169, 37, 69, 3, 73, 7, 11, 32, 4, 218, 4, 83, 171, 135, 11, 71, 4, 142, + 169, 37, 85, 167, 80, 78, 10, 76, 6, 79, 80, 69, 78, 32, 80, 113, 9, 67, + 76, 79, 83, 69, 68, 32, 80, 76, 6, 158, 168, 37, 65, 2, 73, 3, 85, 8, 72, + 8, 67, 76, 79, 83, 69, 68, 32, 84, 29, 6, 79, 80, 69, 78, 32, 68, 4, 142, + 245, 37, 65, 3, 85, 4, 182, 247, 37, 65, 3, 85, 12, 30, 77, 69, 3, 78, + 84, 73, 6, 44, 3, 65, 68, 65, 193, 176, 35, 2, 69, 78, 5, 69, 2, 32, 76, + 7, 11, 32, 4, 38, 76, 209, 189, 35, 3, 66, 65, 87, 2, 129, 158, 37, 3, + 65, 78, 84, 12, 106, 83, 20, 4, 85, 76, 85, 32, 202, 128, 31, 67, 240, 6, + 3, 66, 73, 83, 133, 255, 1, 4, 82, 69, 82, 69, 2, 171, 131, 25, 85, 4, + 210, 221, 20, 67, 185, 133, 17, 3, 82, 73, 67, 30, 120, 3, 76, 65, 32, + 32, 3, 82, 65, 32, 12, 4, 83, 85, 75, 85, 34, 84, 104, 5, 80, 69, 80, 69, + 84, 53, 3, 85, 76, 85, 4, 165, 1, 4, 76, 69, 78, 71, 4, 115, 82, 5, 141, + 250, 36, 3, 32, 73, 76, 10, 36, 5, 65, 76, 73, 78, 71, 99, 69, 9, 11, 32, + 6, 18, 82, 55, 84, 4, 17, 2, 69, 80, 4, 11, 65, 5, 17, 2, 32, 84, 2, 11, + 69, 2, 251, 254, 30, 68, 5, 213, 134, 31, 3, 32, 83, 65, 30, 86, 79, 208, + 174, 23, 5, 32, 79, 70, 32, 89, 217, 172, 13, 6, 69, 84, 32, 83, 72, 79, + 26, 32, 2, 79, 78, 21, 2, 84, 32, 5, 135, 217, 35, 45, 22, 44, 2, 66, 79, + 246, 1, 83, 211, 238, 37, 88, 18, 38, 88, 205, 1, 4, 76, 68, 32, 83, 17, + 33, 6, 32, 87, 73, 84, 72, 32, 14, 82, 66, 86, 83, 184, 230, 12, 4, 76, + 73, 71, 72, 134, 189, 10, 67, 151, 203, 14, 88, 6, 52, 4, 79, 76, 68, 32, + 181, 158, 37, 3, 65, 76, 76, 4, 26, 83, 191, 163, 23, 67, 2, 181, 230, + 12, 4, 67, 82, 73, 80, 172, 10, 120, 2, 67, 79, 180, 1, 7, 76, 69, 84, + 84, 69, 82, 32, 208, 92, 3, 78, 74, 65, 194, 238, 28, 83, 182, 203, 5, + 70, 83, 81, 8, 26, 77, 167, 157, 37, 76, 6, 72, 12, 66, 73, 78, 73, 78, + 71, 32, 77, 65, 82, 75, 32, 143, 234, 37, 77, 4, 184, 242, 21, 6, 84, 85, + 75, 87, 69, 78, 217, 173, 3, 4, 75, 79, 81, 78, 156, 10, 170, 1, 70, 58, + 75, 170, 1, 76, 66, 77, 102, 78, 234, 1, 80, 166, 104, 82, 102, 83, 134, + 1, 84, 54, 89, 162, 225, 2, 87, 170, 131, 34, 69, 214, 22, 65, 2, 73, 2, + 79, 3, 85, 8, 170, 80, 65, 202, 131, 37, 69, 254, 5, 79, 219, 16, 85, 22, + 78, 69, 46, 79, 246, 246, 35, 89, 234, 239, 1, 80, 186, 2, 65, 2, 73, 3, + 85, 6, 254, 218, 36, 85, 194, 142, 1, 78, 3, 84, 7, 162, 244, 35, 86, + 141, 228, 1, 2, 71, 72, 10, 154, 103, 69, 182, 158, 26, 79, 154, 227, 10, + 65, 2, 73, 3, 85, 19, 62, 69, 254, 101, 66, 238, 129, 37, 65, 2, 73, 2, + 79, 3, 85, 4, 198, 245, 35, 69, 163, 242, 1, 78, 30, 102, 71, 50, 74, 50, + 84, 238, 101, 85, 234, 130, 35, 83, 246, 7, 68, 222, 225, 1, 89, 218, 19, + 65, 3, 73, 6, 134, 247, 32, 75, 158, 237, 4, 71, 187, 2, 65, 6, 182, 233, + 26, 85, 162, 230, 10, 69, 171, 4, 65, 4, 146, 193, 37, 85, 151, 14, 69, + 136, 9, 76, 5, 72, 65, 83, 69, 45, 170, 101, 69, 138, 2, 85, 218, 253, + 36, 65, 3, 73, 252, 8, 116, 2, 65, 32, 168, 18, 2, 66, 32, 180, 13, 2, + 67, 32, 180, 20, 2, 68, 32, 172, 18, 2, 69, 32, 153, 25, 2, 70, 32, 176, + 1, 158, 1, 71, 106, 75, 130, 1, 76, 102, 77, 198, 3, 78, 210, 4, 80, 146, + 2, 83, 190, 2, 84, 154, 1, 85, 216, 230, 30, 2, 70, 73, 174, 249, 4, 86, + 191, 225, 1, 82, 6, 60, 5, 72, 69, 85, 65, 69, 153, 47, 5, 66, 73, 69, + 69, 32, 4, 220, 27, 2, 71, 72, 215, 201, 26, 82, 12, 38, 65, 34, 69, 214, + 67, 80, 3, 85, 4, 158, 223, 37, 70, 187, 2, 81, 4, 188, 129, 34, 5, 85, + 75, 69, 85, 84, 251, 223, 3, 84, 10, 78, 85, 166, 66, 79, 232, 186, 26, + 2, 65, 80, 213, 233, 9, 4, 69, 84, 32, 75, 5, 203, 190, 27, 65, 36, 142, + 1, 65, 176, 1, 2, 66, 65, 38, 79, 76, 6, 86, 69, 85, 65, 69, 78, 180, 71, + 8, 69, 85, 78, 74, 79, 77, 78, 68, 229, 217, 34, 2, 71, 66, 20, 62, 69, + 236, 49, 2, 78, 83, 169, 148, 32, 4, 80, 32, 80, 73, 16, 58, 77, 142, + 190, 12, 75, 138, 176, 7, 78, 167, 220, 17, 83, 11, 230, 24, 66, 14, 71, + 214, 44, 86, 203, 252, 27, 75, 4, 222, 237, 19, 78, 255, 239, 17, 81, 6, + 36, 2, 79, 77, 237, 1, 2, 78, 32, 4, 242, 143, 13, 80, 207, 211, 23, 69, + 2, 219, 159, 36, 71, 48, 122, 65, 32, 2, 68, 65, 54, 71, 98, 75, 32, 2, + 83, 72, 38, 84, 102, 89, 74, 90, 170, 155, 36, 74, 178, 109, 69, 251, 70, + 73, 4, 250, 8, 65, 227, 210, 37, 81, 4, 22, 65, 203, 22, 32, 2, 217, 44, + 3, 78, 71, 71, 8, 52, 3, 75, 85, 69, 170, 226, 32, 65, 167, 162, 3, 71, + 4, 250, 7, 32, 201, 174, 12, 2, 78, 90, 4, 166, 26, 65, 143, 229, 19, 73, + 4, 230, 231, 35, 73, 163, 242, 1, 65, 8, 40, 2, 65, 80, 185, 189, 28, 2, + 79, 81, 7, 11, 32, 4, 244, 227, 35, 2, 77, 70, 1, 2, 78, 84, 6, 26, 73, + 187, 188, 37, 69, 5, 193, 13, 7, 84, 32, 77, 79, 78, 71, 75, 4, 214, 5, + 65, 137, 179, 12, 4, 85, 78, 32, 77, 22, 58, 65, 80, 3, 79, 78, 32, 210, + 186, 37, 69, 163, 28, 85, 10, 42, 65, 198, 18, 32, 142, 18, 77, 15, 83, + 4, 170, 218, 26, 82, 247, 252, 10, 77, 8, 56, 4, 77, 70, 79, 78, 1, 6, + 80, 65, 32, 78, 74, 73, 4, 37, 7, 32, 80, 73, 80, 65, 69, 77, 4, 250, 16, + 71, 231, 194, 37, 66, 22, 70, 72, 194, 1, 79, 144, 67, 2, 69, 85, 250, + 235, 36, 85, 167, 34, 73, 10, 74, 73, 70, 85, 253, 168, 36, 10, 79, 81, + 32, 78, 83, 72, 85, 84, 32, 89, 4, 238, 215, 26, 82, 237, 220, 6, 8, 78, + 68, 65, 32, 80, 65, 32, 78, 4, 204, 11, 4, 69, 78, 83, 72, 211, 200, 37, + 77, 6, 220, 150, 36, 2, 78, 74, 146, 189, 1, 81, 3, 84, 10, 44, 2, 69, + 85, 44, 3, 73, 84, 65, 31, 85, 4, 134, 253, 35, 65, 1, 4, 84, 69, 85, 87, + 2, 11, 32, 2, 195, 31, 77, 4, 234, 26, 32, 247, 149, 27, 65, 4, 228, 3, + 5, 32, 89, 85, 81, 32, 245, 134, 28, 3, 78, 75, 78, 116, 164, 1, 7, 71, + 72, 69, 85, 71, 72, 69, 34, 75, 126, 76, 122, 77, 154, 3, 78, 250, 2, 80, + 118, 83, 178, 1, 84, 106, 89, 210, 22, 87, 220, 46, 2, 70, 69, 215, 219, + 11, 86, 4, 134, 57, 85, 183, 151, 37, 78, 12, 40, 2, 69, 85, 50, 73, 235, + 190, 37, 65, 6, 166, 55, 89, 174, 203, 12, 80, 243, 186, 24, 65, 4, 146, + 189, 37, 69, 175, 18, 81, 8, 46, 65, 192, 70, 2, 79, 77, 135, 236, 36, + 69, 4, 50, 65, 209, 61, 7, 77, 32, 78, 83, 72, 85, 84, 2, 199, 209, 26, + 78, 26, 70, 65, 74, 66, 140, 1, 2, 69, 85, 58, 70, 193, 23, 3, 79, 78, + 84, 7, 21, 3, 32, 78, 74, 4, 210, 238, 18, 85, 209, 160, 17, 3, 69, 85, + 65, 10, 90, 65, 218, 46, 85, 152, 178, 30, 2, 69, 85, 133, 153, 6, 7, 73, + 84, 32, 77, 66, 65, 65, 4, 198, 12, 65, 213, 218, 19, 4, 32, 77, 65, 69, + 4, 208, 179, 32, 5, 84, 32, 78, 71, 71, 187, 152, 5, 81, 4, 48, 4, 79, + 78, 32, 84, 253, 231, 26, 2, 73, 89, 2, 243, 65, 69, 26, 110, 71, 182, 1, + 83, 50, 89, 200, 23, 8, 84, 73, 69, 69, 32, 83, 72, 69, 193, 187, 35, 5, + 68, 85, 32, 78, 74, 14, 70, 71, 196, 208, 36, 8, 75, 73, 78, 68, 73, 32, + 77, 86, 191, 104, 79, 10, 76, 3, 85, 79, 81, 244, 237, 19, 2, 69, 85, + 134, 158, 16, 65, 187, 172, 1, 79, 5, 205, 212, 28, 2, 32, 76, 4, 26, 72, + 243, 248, 36, 69, 2, 183, 147, 37, 85, 4, 168, 46, 2, 65, 69, 227, 17, + 73, 10, 76, 3, 85, 78, 71, 252, 213, 10, 2, 69, 69, 178, 177, 12, 65, + 243, 163, 14, 73, 4, 194, 194, 31, 71, 247, 199, 4, 65, 12, 88, 2, 65, + 75, 16, 2, 72, 69, 156, 212, 19, 2, 69, 84, 254, 255, 15, 73, 207, 219, + 1, 85, 2, 231, 25, 69, 4, 144, 227, 26, 4, 84, 32, 78, 74, 221, 138, 5, + 4, 85, 65, 69, 81, 6, 32, 2, 85, 32, 195, 136, 36, 65, 4, 36, 4, 77, 65, + 69, 77, 143, 7, 78, 2, 11, 71, 2, 139, 7, 66, 4, 44, 4, 65, 70, 85, 32, + 233, 4, 2, 69, 85, 2, 253, 202, 32, 6, 76, 69, 69, 82, 65, 69, 198, 1, + 174, 1, 71, 82, 75, 206, 2, 76, 50, 77, 250, 3, 78, 238, 6, 80, 78, 83, + 134, 1, 84, 176, 1, 3, 86, 69, 85, 46, 87, 62, 89, 170, 189, 30, 66, 226, + 227, 2, 70, 247, 234, 3, 82, 6, 40, 2, 72, 65, 213, 210, 19, 2, 66, 65, + 4, 218, 197, 26, 82, 247, 252, 10, 80, 22, 66, 69, 182, 1, 85, 144, 221, + 26, 3, 80, 65, 82, 239, 224, 10, 65, 14, 40, 2, 78, 32, 54, 85, 139, 193, + 37, 84, 4, 208, 177, 33, 4, 70, 65, 84, 73, 191, 145, 3, 76, 8, 42, 83, + 186, 221, 26, 75, 167, 227, 10, 77, 4, 248, 14, 3, 72, 69, 85, 255, 53, + 69, 4, 48, 6, 79, 80, 32, 78, 75, 65, 131, 192, 37, 84, 2, 11, 65, 2, + 255, 194, 26, 82, 8, 234, 47, 65, 222, 172, 26, 73, 155, 227, 10, 85, 38, + 82, 65, 130, 1, 66, 234, 192, 26, 85, 208, 25, 4, 71, 66, 65, 83, 135, + 241, 8, 73, 8, 18, 32, 79, 69, 4, 42, 78, 141, 252, 17, 4, 75, 69, 85, + 65, 2, 11, 83, 2, 239, 203, 35, 73, 4, 210, 144, 37, 77, 211, 25, 83, 24, + 34, 65, 114, 69, 82, 73, 35, 85, 6, 32, 2, 65, 32, 155, 205, 19, 78, 4, + 192, 243, 31, 8, 67, 65, 66, 66, 65, 71, 69, 45, 253, 246, 4, 2, 80, 73, + 8, 50, 85, 162, 191, 26, 82, 189, 228, 5, 2, 69, 75, 4, 146, 188, 37, 77, + 3, 88, 7, 226, 7, 82, 151, 180, 37, 84, 4, 170, 169, 37, 65, 175, 18, 69, + 72, 130, 1, 65, 54, 68, 110, 71, 222, 1, 74, 102, 83, 130, 1, 84, 102, + 90, 253, 7, 12, 89, 73, 82, 32, 77, 75, 80, 65, 82, 65, 81, 32, 4, 140, + 215, 26, 4, 78, 83, 65, 78, 167, 227, 10, 81, 12, 60, 2, 69, 85, 206, 41, + 65, 238, 180, 19, 79, 135, 182, 17, 73, 4, 144, 199, 35, 2, 65, 69, 175, + 242, 1, 84, 20, 50, 71, 98, 75, 234, 212, 26, 65, 195, 210, 10, 79, 12, + 26, 85, 231, 232, 36, 69, 11, 212, 39, 3, 65, 69, 78, 142, 193, 36, 79, + 202, 26, 69, 155, 53, 77, 4, 36, 3, 85, 69, 32, 195, 212, 26, 65, 2, 249, + 205, 19, 3, 77, 65, 69, 10, 34, 65, 34, 69, 199, 233, 12, 85, 4, 186, + 166, 37, 69, 219, 16, 77, 4, 210, 196, 35, 69, 227, 99, 85, 12, 78, 85, + 226, 210, 26, 72, 220, 243, 5, 2, 69, 85, 242, 222, 4, 79, 219, 16, 65, + 4, 208, 162, 37, 4, 79, 84, 32, 78, 179, 19, 78, 8, 54, 69, 228, 152, 37, + 4, 85, 32, 77, 66, 131, 26, 65, 4, 176, 201, 19, 2, 85, 78, 235, 235, 17, + 78, 4, 202, 137, 36, 69, 167, 171, 1, 65, 6, 26, 73, 211, 228, 36, 69, 4, + 26, 82, 151, 180, 37, 78, 2, 131, 222, 35, 73, 12, 30, 69, 30, 72, 163, + 7, 85, 4, 78, 84, 211, 164, 36, 85, 6, 48, 2, 69, 84, 226, 229, 12, 85, + 155, 234, 13, 73, 2, 163, 227, 36, 70, 10, 40, 2, 65, 65, 34, 69, 41, 2, + 73, 84, 2, 11, 83, 2, 207, 181, 26, 72, 4, 228, 25, 2, 85, 84, 203, 152, + 37, 84, 4, 38, 85, 133, 162, 33, 3, 65, 32, 89, 2, 251, 143, 27, 65, 4, + 200, 149, 28, 2, 65, 69, 131, 156, 9, 88, 4, 40, 4, 65, 78, 71, 75, 235, + 176, 37, 85, 2, 143, 19, 85, 10, 42, 85, 158, 227, 12, 69, 231, 202, 24, + 65, 6, 210, 18, 87, 212, 3, 4, 32, 77, 85, 79, 147, 154, 37, 77, 234, 1, + 134, 1, 70, 68, 2, 71, 72, 34, 75, 254, 1, 76, 142, 1, 77, 130, 3, 78, + 130, 5, 80, 122, 82, 90, 83, 190, 1, 84, 158, 1, 87, 39, 89, 4, 36, 3, + 69, 85, 70, 147, 172, 37, 65, 2, 11, 69, 2, 151, 2, 85, 4, 202, 1, 69, + 171, 170, 37, 65, 22, 46, 69, 146, 1, 85, 42, 87, 135, 186, 35, 89, 10, + 26, 85, 195, 173, 37, 84, 8, 72, 3, 65, 69, 84, 20, 5, 79, 84, 32, 77, + 66, 226, 172, 37, 77, 3, 80, 2, 207, 140, 12, 77, 2, 235, 175, 26, 85, 9, + 242, 155, 37, 79, 218, 16, 78, 3, 81, 2, 139, 247, 36, 65, 14, 58, 69, + 190, 200, 26, 79, 250, 240, 8, 73, 203, 225, 1, 85, 8, 42, 85, 138, 185, + 35, 69, 163, 242, 1, 84, 4, 194, 137, 27, 65, 231, 161, 10, 77, 41, 94, + 65, 58, 66, 66, 69, 38, 70, 80, 2, 71, 66, 226, 163, 32, 79, 198, 139, 4, + 86, 151, 121, 85, 4, 144, 232, 17, 2, 76, 69, 249, 140, 19, 3, 69, 78, + 74, 6, 32, 2, 65, 65, 215, 138, 37, 85, 5, 133, 135, 29, 2, 32, 83, 6, + 202, 202, 18, 85, 195, 236, 16, 69, 10, 44, 2, 69, 85, 238, 170, 35, 79, + 207, 11, 73, 4, 130, 146, 37, 65, 215, 22, 84, 6, 150, 182, 35, 73, 252, + 70, 2, 79, 70, 247, 42, 69, 72, 78, 68, 46, 71, 226, 1, 74, 98, 83, 110, + 84, 34, 89, 190, 163, 37, 73, 3, 85, 8, 210, 39, 69, 130, 176, 36, 79, + 139, 63, 65, 24, 18, 71, 99, 75, 12, 54, 65, 218, 42, 69, 158, 140, 32, + 87, 231, 222, 4, 85, 6, 168, 38, 2, 65, 77, 147, 128, 37, 80, 12, 68, 2, + 69, 85, 174, 179, 35, 73, 2, 89, 194, 162, 1, 85, 215, 79, 65, 4, 154, + 216, 12, 65, 219, 185, 24, 82, 12, 60, 2, 69, 85, 230, 15, 73, 214, 199, + 12, 85, 167, 205, 24, 65, 4, 186, 146, 37, 65, 175, 18, 84, 10, 46, 72, + 32, 3, 73, 69, 69, 163, 147, 37, 85, 4, 234, 135, 37, 85, 219, 5, 69, 4, + 246, 163, 37, 80, 3, 84, 6, 130, 14, 69, 243, 240, 36, 85, 8, 142, 135, + 37, 69, 218, 5, 85, 254, 5, 65, 219, 16, 73, 12, 42, 69, 46, 85, 162, + 162, 37, 65, 3, 73, 4, 224, 165, 26, 2, 85, 84, 247, 252, 10, 69, 4, 254, + 133, 37, 85, 175, 28, 81, 8, 48, 3, 69, 78, 32, 130, 142, 37, 73, 175, 1, + 65, 4, 138, 242, 26, 79, 155, 141, 10, 77, 26, 58, 72, 90, 85, 202, 16, + 65, 174, 6, 69, 131, 237, 36, 79, 12, 54, 69, 170, 189, 26, 79, 194, 207, + 10, 73, 219, 19, 85, 6, 214, 7, 85, 235, 152, 37, 69, 6, 202, 137, 37, + 65, 214, 22, 69, 3, 85, 18, 62, 69, 74, 85, 218, 187, 26, 79, 198, 204, + 10, 65, 215, 22, 73, 8, 26, 85, 255, 172, 35, 69, 6, 150, 201, 35, 65, + 134, 214, 1, 78, 3, 84, 5, 195, 130, 37, 79, 4, 146, 175, 32, 85, 191, + 239, 4, 65, 10, 40, 2, 65, 69, 18, 85, 159, 206, 36, 69, 2, 251, 3, 77, + 6, 22, 87, 243, 13, 79, 2, 203, 186, 26, 79, 188, 2, 178, 1, 70, 154, 1, + 71, 202, 1, 75, 170, 1, 76, 158, 1, 77, 134, 2, 78, 206, 7, 80, 166, 2, + 82, 78, 83, 166, 1, 84, 246, 1, 86, 66, 87, 34, 89, 190, 134, 37, 65, 2, + 73, 3, 79, 18, 54, 85, 158, 156, 23, 65, 242, 232, 13, 69, 255, 5, 79, + 10, 26, 32, 239, 178, 31, 69, 6, 156, 255, 23, 4, 82, 69, 77, 69, 242, + 145, 11, 67, 183, 138, 2, 73, 16, 24, 2, 66, 69, 39, 72, 4, 162, 140, 36, + 85, 195, 142, 1, 84, 12, 34, 65, 34, 69, 167, 137, 37, 79, 2, 11, 65, 2, + 155, 157, 26, 77, 8, 26, 85, 227, 153, 37, 84, 6, 138, 131, 37, 65, 214, + 22, 78, 3, 88, 18, 50, 69, 62, 80, 18, 85, 186, 152, 37, 73, 3, 79, 6, + 26, 85, 235, 152, 37, 84, 4, 146, 130, 37, 65, 215, 22, 88, 2, 227, 28, + 69, 6, 138, 252, 36, 69, 162, 28, 79, 15, 84, 18, 50, 65, 40, 2, 69, 85, + 22, 79, 163, 151, 37, 85, 6, 130, 135, 37, 65, 218, 16, 80, 3, 81, 2, + 135, 133, 37, 65, 8, 190, 184, 18, 79, 226, 222, 18, 77, 3, 81, 32, 110, + 65, 44, 2, 66, 69, 34, 70, 20, 2, 71, 66, 34, 73, 146, 152, 26, 85, 150, + 173, 10, 69, 2, 79, 139, 60, 86, 11, 218, 140, 18, 69, 170, 137, 19, 80, + 3, 81, 4, 254, 132, 37, 85, 219, 16, 69, 2, 155, 200, 12, 69, 4, 194, + 197, 36, 69, 227, 79, 65, 5, 175, 254, 36, 69, 82, 114, 68, 170, 1, 71, + 154, 3, 74, 112, 2, 83, 72, 58, 84, 32, 3, 89, 73, 32, 54, 90, 162, 205, + 36, 65, 191, 47, 75, 12, 34, 65, 98, 73, 155, 195, 36, 85, 6, 32, 2, 65, + 32, 183, 147, 37, 80, 4, 208, 190, 18, 3, 77, 89, 32, 189, 188, 13, 3, + 83, 79, 70, 4, 222, 175, 26, 65, 155, 227, 10, 81, 38, 78, 71, 66, 85, + 122, 75, 118, 79, 128, 240, 11, 3, 69, 85, 82, 219, 159, 25, 65, 14, 34, + 69, 50, 85, 167, 145, 37, 79, 6, 26, 85, 167, 159, 35, 69, 4, 167, 171, + 24, 65, 6, 64, 6, 65, 69, 83, 72, 65, 69, 250, 147, 26, 82, 247, 252, 10, + 80, 2, 11, 32, 2, 191, 215, 23, 78, 12, 34, 65, 20, 2, 69, 85, 35, 85, 5, + 195, 252, 36, 65, 4, 230, 253, 36, 65, 175, 18, 88, 4, 242, 143, 37, 77, + 3, 80, 4, 214, 143, 37, 80, 3, 81, 8, 18, 65, 31, 69, 2, 197, 139, 32, 2, + 69, 77, 6, 26, 69, 179, 128, 36, 85, 5, 197, 236, 36, 4, 32, 69, 80, 79, + 6, 26, 85, 147, 156, 35, 73, 4, 162, 142, 37, 79, 15, 69, 4, 186, 253, + 36, 85, 207, 16, 65, 4, 180, 186, 26, 4, 67, 76, 69, 65, 167, 248, 1, 66, + 4, 166, 170, 26, 65, 3, 85, 34, 42, 65, 90, 69, 58, 73, 50, 79, 23, 85, + 8, 32, 2, 32, 80, 175, 131, 18, 65, 4, 252, 179, 28, 2, 69, 79, 237, 204, + 7, 2, 76, 85, 6, 26, 85, 175, 251, 36, 69, 4, 130, 140, 37, 84, 3, 88, 7, + 11, 69, 4, 194, 168, 26, 69, 155, 227, 10, 84, 5, 215, 187, 36, 79, 11, + 82, 65, 210, 138, 37, 69, 3, 77, 8, 46, 65, 238, 14, 69, 253, 143, 19, 2, + 73, 77, 4, 206, 138, 37, 69, 3, 81, 18, 62, 69, 30, 72, 146, 154, 32, 85, + 242, 222, 4, 79, 163, 14, 65, 4, 242, 137, 37, 69, 3, 84, 8, 42, 69, 234, + 137, 23, 79, 175, 156, 3, 73, 2, 249, 187, 12, 2, 85, 65, 28, 34, 65, 94, + 69, 50, 79, 39, 85, 10, 56, 2, 69, 78, 238, 136, 23, 65, 198, 255, 13, + 77, 3, 81, 2, 161, 228, 11, 3, 32, 78, 84, 6, 26, 85, 247, 135, 37, 78, + 5, 195, 186, 12, 65, 6, 242, 137, 35, 79, 239, 253, 1, 81, 6, 170, 7, 77, + 191, 233, 36, 65, 6, 26, 69, 171, 246, 36, 79, 4, 138, 138, 26, 85, 247, + 252, 10, 69, 6, 246, 10, 69, 255, 223, 32, 85, 26, 68, 2, 69, 85, 46, 73, + 32, 3, 79, 81, 32, 54, 85, 235, 132, 37, 65, 8, 214, 159, 24, 65, 158, + 230, 12, 77, 3, 88, 4, 242, 238, 36, 69, 215, 22, 84, 4, 168, 214, 12, 4, + 83, 87, 73, 77, 143, 205, 9, 67, 8, 218, 161, 26, 69, 150, 141, 9, 65, + 134, 214, 1, 78, 3, 81, 108, 162, 1, 75, 82, 76, 46, 77, 98, 78, 190, 1, + 80, 66, 82, 50, 83, 110, 84, 38, 89, 130, 228, 2, 87, 204, 204, 9, 2, 86, + 85, 222, 182, 24, 69, 242, 5, 70, 231, 16, 85, 14, 178, 164, 18, 69, 194, + 236, 16, 89, 234, 239, 1, 80, 186, 2, 65, 2, 79, 3, 85, 6, 170, 159, 26, + 79, 154, 227, 10, 65, 3, 73, 13, 42, 66, 34, 69, 206, 129, 37, 65, 3, 79, + 4, 138, 178, 36, 69, 171, 77, 65, 2, 171, 143, 35, 69, 22, 94, 71, 38, + 74, 38, 85, 234, 130, 35, 83, 246, 7, 68, 150, 3, 84, 202, 222, 1, 89, + 219, 19, 73, 4, 130, 145, 32, 75, 159, 237, 4, 71, 4, 190, 131, 26, 85, + 203, 234, 10, 65, 5, 187, 233, 36, 65, 6, 26, 69, 239, 130, 26, 85, 4, + 158, 241, 35, 85, 195, 142, 1, 69, 12, 186, 2, 69, 178, 146, 9, 73, 211, + 234, 27, 85, 14, 66, 72, 230, 2, 69, 138, 146, 19, 65, 246, 196, 17, 85, + 235, 36, 73, 6, 238, 234, 36, 73, 218, 19, 79, 3, 85, 6, 214, 167, 21, + 65, 159, 186, 15, 69, 4, 226, 154, 26, 79, 155, 227, 10, 65, 4, 130, 231, + 36, 65, 215, 22, 69, 14, 54, 69, 178, 146, 9, 73, 254, 211, 27, 65, 215, + 22, 85, 6, 190, 238, 35, 85, 194, 142, 1, 69, 3, 78, 16, 62, 72, 50, 69, + 138, 146, 19, 65, 246, 196, 17, 85, 235, 36, 73, 8, 46, 69, 142, 232, 36, + 73, 218, 19, 79, 3, 85, 2, 163, 237, 35, 85, 10, 238, 156, 18, 69, 154, + 136, 3, 65, 203, 214, 15, 73, 6, 130, 152, 26, 79, 2, 85, 155, 227, 10, + 65, 14, 42, 75, 174, 188, 35, 65, 167, 159, 1, 74, 11, 49, 10, 78, 79, + 84, 69, 32, 87, 73, 84, 72, 32, 8, 224, 220, 9, 2, 80, 79, 198, 1, 89, + 148, 190, 12, 2, 69, 85, 187, 182, 6, 68, 6, 38, 32, 149, 137, 17, 3, 66, + 69, 82, 4, 198, 233, 29, 67, 201, 252, 5, 5, 79, 70, 32, 83, 79, 78, 72, + 3, 75, 69, 84, 60, 7, 83, 65, 32, 86, 65, 72, 32, 155, 237, 34, 69, 5, + 193, 177, 16, 10, 66, 65, 76, 76, 32, 65, 78, 68, 32, 72, 72, 104, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 164, 1, 7, 76, 69, 84, 84, 69, - 82, 32, 151, 246, 33, 70, 10, 52, 4, 72, 73, 71, 72, 44, 3, 76, 79, 87, - 39, 77, 4, 236, 219, 21, 2, 45, 76, 159, 252, 10, 32, 4, 32, 2, 45, 77, - 191, 215, 32, 32, 2, 173, 215, 32, 2, 73, 68, 60, 238, 1, 68, 38, 69, 38, - 71, 34, 75, 38, 85, 20, 2, 87, 65, 22, 89, 212, 228, 29, 2, 72, 87, 230, - 191, 1, 77, 190, 218, 2, 79, 250, 160, 2, 86, 246, 5, 74, 2, 84, 2, 90, + 82, 32, 151, 160, 34, 70, 10, 52, 4, 72, 73, 71, 72, 44, 3, 76, 79, 87, + 39, 77, 4, 136, 246, 21, 2, 45, 76, 255, 138, 11, 32, 4, 32, 2, 45, 77, + 187, 128, 33, 32, 2, 169, 128, 33, 2, 73, 68, 60, 238, 1, 68, 38, 69, 38, + 71, 34, 75, 38, 85, 20, 2, 87, 65, 22, 89, 164, 132, 30, 2, 72, 87, 154, + 197, 1, 77, 186, 223, 2, 79, 202, 164, 2, 86, 246, 5, 74, 2, 84, 2, 90, 162, 8, 67, 2, 83, 158, 20, 66, 2, 70, 2, 80, 186, 2, 65, 3, 73, 4, 138, - 131, 34, 72, 255, 194, 2, 79, 7, 222, 201, 31, 78, 135, 252, 4, 69, 4, - 214, 160, 36, 66, 219, 35, 65, 4, 158, 229, 29, 80, 131, 224, 6, 65, 5, - 147, 160, 36, 87, 5, 227, 159, 36, 68, 4, 254, 196, 35, 69, 131, 105, 73, - 121, 48, 3, 65, 75, 32, 230, 10, 72, 143, 174, 22, 84, 112, 196, 1, 15, + 173, 34, 72, 207, 198, 2, 79, 7, 218, 238, 31, 78, 219, 132, 5, 69, 4, + 166, 206, 36, 66, 219, 35, 65, 4, 238, 132, 30, 80, 131, 238, 6, 65, 5, + 227, 205, 36, 87, 5, 179, 205, 36, 68, 4, 206, 242, 35, 69, 131, 105, 73, + 121, 48, 3, 65, 75, 32, 230, 10, 72, 179, 200, 22, 84, 112, 196, 1, 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 28, 7, 76, 69, 84, 84, 69, 82, 32, 248, 4, 3, 80, 65, 78, 50, 83, 141, 2, 11, 86, - 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 4, 226, 193, 36, 78, 87, 72, 76, - 194, 1, 77, 114, 78, 68, 2, 80, 65, 38, 83, 196, 222, 18, 4, 75, 65, 82, - 79, 134, 222, 17, 66, 2, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 76, 2, 82, 2, - 87, 2, 89, 186, 2, 65, 2, 73, 3, 85, 10, 26, 65, 135, 190, 36, 66, 9, 45, - 9, 78, 68, 65, 73, 76, 73, 78, 71, 32, 6, 210, 189, 36, 72, 2, 78, 3, 83, - 10, 152, 2, 2, 79, 82, 150, 187, 36, 68, 2, 71, 2, 89, 187, 2, 65, 5, - 189, 244, 20, 4, 75, 80, 65, 75, 24, 80, 10, 73, 77, 65, 76, 85, 78, 71, - 85, 78, 32, 96, 2, 79, 85, 207, 189, 36, 65, 20, 242, 187, 36, 71, 2, 72, - 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 87, 2, 89, 187, 2, 65, 2, 237, 222, - 18, 5, 84, 72, 69, 82, 78, 4, 166, 2, 71, 253, 222, 18, 4, 79, 78, 71, - 79, 10, 96, 12, 89, 77, 66, 79, 76, 32, 66, 73, 78, 68, 85, 32, 249, 179, - 10, 6, 73, 71, 78, 32, 84, 79, 8, 78, 80, 136, 159, 11, 3, 74, 85, 68, - 149, 153, 25, 6, 78, 65, 32, 77, 69, 84, 4, 64, 3, 65, 78, 71, 241, 156, - 23, 7, 73, 78, 65, 82, 66, 79, 82, 2, 151, 228, 25, 79, 18, 122, 85, 252, - 146, 26, 6, 80, 65, 75, 80, 65, 75, 232, 250, 2, 5, 75, 65, 82, 79, 32, - 234, 235, 6, 69, 162, 64, 73, 3, 79, 5, 241, 187, 30, 15, 32, 70, 79, 82, - 32, 83, 73, 77, 65, 76, 85, 78, 71, 85, 78, 5, 195, 219, 23, 84, 254, 1, - 134, 1, 65, 230, 2, 69, 50, 76, 130, 1, 78, 190, 10, 84, 224, 228, 32, 2, - 67, 65, 248, 183, 2, 5, 86, 69, 82, 65, 71, 215, 140, 1, 68, 20, 136, 1, - 4, 77, 69, 68, 32, 170, 1, 82, 136, 169, 3, 10, 67, 72, 32, 87, 73, 84, - 72, 32, 85, 77, 178, 158, 7, 84, 166, 176, 25, 86, 19, 78, 8, 86, 65, 0, - 2, 68, 69, 52, 4, 69, 73, 71, 72, 1, 7, 83, 73, 88, 84, 69, 69, 78, 2, - 197, 164, 20, 8, 83, 67, 69, 78, 68, 73, 78, 71, 2, 189, 164, 20, 2, 84, - 72, 4, 220, 181, 32, 3, 68, 69, 68, 215, 194, 3, 32, 4, 172, 197, 8, 3, - 82, 32, 77, 195, 203, 26, 84, 13, 11, 76, 11, 38, 32, 149, 156, 25, 3, - 72, 79, 80, 6, 238, 185, 12, 80, 152, 160, 16, 6, 87, 73, 84, 72, 32, 67, - 159, 199, 6, 83, 208, 1, 84, 5, 71, 65, 76, 73, 32, 158, 9, 84, 37, 9, - 90, 69, 78, 69, 32, 82, 73, 78, 71, 200, 1, 210, 1, 65, 40, 9, 67, 85, - 82, 82, 69, 78, 67, 89, 32, 148, 2, 7, 76, 69, 84, 84, 69, 82, 32, 204, - 3, 6, 82, 85, 80, 69, 69, 32, 34, 83, 250, 213, 22, 73, 134, 4, 86, 242, - 223, 11, 68, 249, 107, 3, 71, 65, 78, 6, 154, 154, 32, 66, 50, 78, 187, - 57, 85, 12, 120, 10, 78, 85, 77, 69, 82, 65, 84, 79, 82, 32, 209, 170, - 23, 14, 68, 69, 78, 79, 77, 73, 78, 65, 84, 79, 82, 32, 83, 73, 10, 52, - 3, 79, 78, 69, 218, 156, 31, 70, 163, 163, 3, 84, 5, 157, 177, 29, 19, - 32, 76, 69, 83, 83, 32, 84, 72, 65, 78, 32, 84, 72, 69, 32, 68, 69, 78, - 79, 108, 226, 1, 75, 90, 82, 146, 184, 21, 86, 138, 138, 8, 89, 134, 144, - 3, 65, 38, 68, 114, 84, 230, 5, 85, 206, 201, 1, 73, 162, 193, 1, 78, 46, - 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 80, 138, 69, 72, 2, 76, 2, 77, 186, - 2, 69, 3, 79, 8, 26, 72, 251, 172, 36, 65, 6, 26, 65, 219, 254, 13, 73, - 5, 253, 205, 18, 3, 78, 68, 65, 10, 34, 65, 226, 169, 36, 72, 3, 82, 7, - 33, 6, 32, 87, 73, 84, 72, 32, 4, 180, 148, 25, 5, 76, 79, 87, 69, 82, 1, - 6, 77, 73, 68, 68, 76, 69, 4, 194, 164, 35, 83, 191, 69, 77, 20, 116, 19, - 69, 81, 85, 69, 78, 67, 69, 32, 70, 79, 82, 32, 76, 69, 84, 84, 69, 82, - 32, 182, 255, 25, 65, 219, 149, 6, 73, 6, 158, 216, 22, 82, 155, 207, 13, - 89, 4, 226, 146, 26, 32, 199, 138, 9, 79, 5, 133, 179, 33, 3, 32, 87, 73, - 4, 182, 213, 34, 87, 219, 64, 32, 194, 1, 184, 2, 7, 76, 69, 84, 84, 69, - 82, 32, 244, 1, 7, 78, 85, 77, 66, 69, 82, 32, 72, 5, 83, 73, 71, 78, 32, - 48, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 142, 245, 25, 68, - 170, 243, 3, 87, 152, 186, 2, 10, 71, 65, 80, 32, 70, 73, 76, 76, 69, 82, - 205, 182, 3, 12, 72, 85, 78, 68, 82, 69, 68, 83, 32, 85, 78, 73, 92, 210, - 1, 86, 218, 202, 32, 65, 38, 68, 114, 84, 230, 5, 85, 206, 201, 1, 73, - 162, 193, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, - 69, 72, 2, 76, 2, 77, 2, 82, 2, 89, 186, 2, 69, 3, 79, 8, 234, 1, 79, - 143, 163, 36, 65, 36, 142, 126, 69, 38, 70, 66, 78, 26, 83, 138, 173, 21, - 84, 155, 223, 12, 79, 10, 206, 143, 32, 67, 210, 61, 65, 231, 147, 3, 86, - 24, 80, 2, 86, 79, 194, 207, 32, 65, 38, 85, 206, 201, 1, 73, 222, 137, - 2, 69, 3, 79, 6, 33, 6, 67, 65, 76, 73, 67, 32, 6, 158, 208, 32, 82, 203, - 210, 3, 76, 26, 148, 1, 4, 67, 89, 67, 76, 36, 2, 71, 32, 28, 2, 76, 76, - 46, 82, 66, 84, 204, 166, 19, 4, 79, 72, 65, 90, 176, 253, 11, 2, 75, 73, - 155, 172, 4, 83, 4, 174, 183, 32, 73, 255, 233, 3, 69, 4, 178, 139, 34, - 82, 67, 83, 4, 216, 215, 9, 2, 69, 68, 199, 235, 23, 73, 4, 140, 184, 32, - 7, 84, 72, 68, 65, 89, 32, 67, 179, 232, 3, 68, 4, 188, 211, 13, 2, 67, - 79, 137, 203, 22, 4, 73, 78, 71, 32, 192, 7, 42, 65, 174, 33, 79, 165, - 11, 2, 85, 69, 242, 2, 32, 2, 67, 75, 247, 236, 17, 78, 240, 2, 22, 32, - 223, 31, 45, 224, 2, 210, 1, 67, 254, 4, 68, 174, 2, 70, 102, 72, 82, 76, - 186, 4, 77, 250, 2, 78, 38, 80, 46, 82, 150, 4, 83, 154, 4, 84, 82, 85, - 248, 2, 3, 86, 69, 82, 214, 128, 12, 79, 156, 205, 20, 3, 66, 79, 87, - 251, 247, 1, 81, 98, 196, 1, 5, 73, 82, 67, 76, 69, 200, 1, 6, 85, 82, - 86, 69, 68, 32, 224, 251, 25, 12, 82, 79, 83, 83, 32, 79, 78, 32, 83, 72, - 73, 69, 180, 158, 3, 5, 69, 78, 84, 82, 69, 230, 161, 5, 72, 211, 13, 76, - 11, 11, 32, 8, 72, 5, 87, 73, 84, 72, 32, 217, 235, 16, 7, 70, 79, 82, - 32, 82, 69, 67, 6, 140, 69, 8, 87, 72, 73, 84, 69, 32, 68, 79, 198, 242, - 18, 68, 161, 146, 2, 8, 84, 87, 79, 32, 87, 72, 73, 84, 16, 84, 4, 68, - 79, 87, 78, 0, 2, 85, 80, 56, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 4, - 229, 252, 31, 9, 87, 65, 82, 68, 83, 32, 65, 78, 68, 4, 53, 11, 84, 87, - 65, 82, 68, 83, 32, 65, 78, 68, 32, 4, 158, 143, 21, 85, 231, 154, 12, - 68, 30, 64, 6, 73, 65, 77, 79, 78, 68, 152, 1, 3, 79, 87, 78, 43, 82, 13, - 11, 32, 10, 154, 19, 67, 244, 250, 12, 10, 77, 73, 78, 85, 83, 32, 87, - 72, 73, 84, 152, 166, 6, 6, 87, 73, 84, 72, 32, 68, 206, 161, 15, 79, - 135, 13, 83, 12, 214, 19, 32, 62, 45, 247, 167, 31, 87, 6, 212, 182, 34, - 2, 79, 80, 231, 20, 65, 8, 18, 76, 39, 79, 4, 206, 234, 27, 79, 155, 170, - 8, 65, 4, 252, 217, 2, 2, 85, 82, 151, 155, 31, 76, 12, 38, 69, 218, 206, - 34, 65, 251, 2, 79, 6, 160, 208, 34, 2, 65, 82, 247, 11, 88, 40, 64, 5, - 65, 82, 71, 69, 32, 140, 2, 3, 69, 70, 84, 203, 1, 79, 12, 48, 6, 67, 73, - 82, 67, 76, 69, 203, 242, 34, 83, 11, 37, 7, 32, 77, 73, 78, 85, 83, 32, - 8, 54, 76, 36, 4, 82, 73, 71, 72, 13, 3, 85, 80, 80, 4, 32, 2, 69, 70, - 13, 2, 79, 87, 2, 31, 84, 2, 17, 2, 69, 82, 2, 173, 147, 33, 8, 32, 81, - 85, 65, 82, 84, 69, 82, 22, 96, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, - 32, 64, 6, 87, 65, 82, 68, 83, 32, 235, 207, 34, 32, 12, 146, 7, 68, 190, - 8, 73, 190, 195, 34, 80, 206, 24, 83, 51, 84, 4, 242, 164, 33, 69, 255, - 139, 1, 66, 6, 158, 15, 87, 175, 203, 34, 90, 30, 76, 6, 69, 68, 73, 85, - 77, 32, 245, 222, 21, 7, 79, 79, 78, 32, 76, 73, 76, 28, 66, 68, 42, 76, - 36, 4, 82, 73, 71, 72, 12, 2, 85, 80, 111, 83, 6, 84, 3, 79, 87, 78, 163, - 209, 34, 73, 6, 32, 2, 69, 70, 195, 216, 34, 79, 4, 11, 84, 4, 81, 18, - 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 84, 82, 73, 65, 78, 71, 76, 69, - 5, 145, 9, 2, 32, 67, 8, 198, 13, 77, 247, 222, 34, 81, 4, 238, 145, 17, - 69, 155, 191, 17, 73, 8, 238, 135, 25, 85, 158, 201, 9, 65, 87, 69, 34, - 52, 4, 73, 71, 72, 84, 254, 252, 33, 79, 155, 85, 69, 30, 94, 32, 84, 10, - 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 245, 1, 6, 87, 65, 82, 68, 83, - 32, 6, 60, 9, 84, 82, 73, 65, 78, 71, 76, 69, 32, 171, 227, 34, 80, 2, - 231, 204, 6, 67, 16, 90, 68, 88, 8, 84, 82, 73, 65, 78, 71, 76, 69, 230, - 7, 73, 194, 200, 34, 80, 203, 19, 83, 4, 65, 14, 79, 85, 66, 76, 69, 32, - 84, 82, 73, 65, 78, 71, 76, 69, 5, 207, 189, 12, 32, 5, 205, 229, 20, 11, - 32, 87, 73, 84, 72, 32, 68, 79, 85, 66, 76, 8, 230, 158, 19, 65, 162, - 254, 13, 69, 255, 139, 1, 66, 40, 158, 2, 77, 148, 1, 5, 81, 85, 65, 82, - 69, 180, 253, 25, 3, 85, 78, 32, 172, 223, 1, 5, 75, 85, 76, 76, 32, 160, - 178, 3, 3, 78, 79, 87, 168, 223, 1, 5, 65, 70, 69, 84, 89, 192, 131, 1, - 13, 76, 73, 71, 72, 84, 76, 89, 32, 83, 77, 65, 76, 76, 254, 91, 67, 50, - 72, 222, 1, 80, 175, 19, 84, 12, 40, 4, 65, 76, 76, 32, 203, 208, 34, 73, - 10, 214, 200, 34, 68, 150, 7, 76, 70, 83, 213, 15, 13, 85, 80, 45, 80, - 79, 73, 78, 84, 73, 78, 71, 32, 67, 9, 11, 32, 6, 54, 67, 208, 178, 33, - 3, 70, 79, 82, 163, 158, 1, 66, 2, 181, 248, 30, 3, 69, 78, 84, 14, 192, - 4, 3, 73, 78, 89, 242, 174, 23, 82, 154, 165, 11, 79, 54, 69, 135, 2, 87, - 18, 38, 80, 229, 213, 32, 3, 78, 73, 86, 16, 46, 32, 62, 45, 170, 1, 80, - 207, 166, 31, 87, 2, 233, 219, 34, 10, 80, 79, 73, 78, 84, 73, 78, 71, - 32, 66, 8, 45, 9, 80, 79, 73, 78, 84, 73, 78, 71, 32, 8, 66, 73, 156, - 216, 34, 5, 68, 79, 85, 66, 76, 238, 3, 83, 51, 84, 2, 213, 218, 33, 8, - 83, 79, 83, 67, 69, 76, 69, 83, 4, 21, 3, 69, 82, 32, 4, 210, 182, 24, - 76, 207, 163, 9, 82, 10, 56, 6, 84, 73, 67, 65, 76, 32, 41, 4, 89, 32, - 83, 77, 4, 152, 198, 34, 2, 82, 69, 239, 22, 69, 6, 21, 3, 65, 76, 76, 6, - 11, 32, 6, 186, 194, 34, 68, 150, 7, 76, 247, 20, 83, 16, 84, 15, 76, 69, - 84, 84, 69, 82, 32, 67, 65, 80, 73, 84, 65, 76, 32, 227, 146, 11, 70, 10, - 154, 254, 35, 67, 2, 72, 2, 73, 2, 82, 3, 90, 200, 4, 52, 3, 67, 75, 32, - 166, 151, 2, 83, 183, 201, 10, 87, 196, 4, 80, 7, 79, 67, 84, 65, 78, 84, - 45, 149, 7, 8, 83, 69, 88, 84, 65, 78, 84, 45, 204, 3, 58, 49, 130, 3, - 50, 114, 53, 50, 54, 18, 51, 215, 1, 52, 234, 1, 74, 50, 246, 1, 51, 174, - 91, 52, 46, 53, 38, 54, 30, 55, 187, 157, 35, 56, 116, 62, 51, 226, 92, - 52, 46, 53, 38, 54, 30, 55, 187, 157, 35, 56, 55, 54, 52, 214, 92, 53, - 38, 54, 30, 55, 187, 157, 35, 56, 22, 50, 53, 166, 2, 54, 190, 90, 55, - 187, 157, 35, 56, 11, 42, 54, 210, 220, 28, 55, 159, 157, 7, 56, 4, 234, - 249, 35, 55, 3, 56, 56, 170, 1, 53, 50, 54, 210, 89, 52, 110, 55, 187, - 157, 35, 56, 118, 62, 52, 254, 89, 51, 98, 53, 38, 54, 30, 55, 187, 157, - 35, 56, 24, 46, 53, 50, 54, 190, 90, 55, 187, 157, 35, 56, 13, 206, 1, - 54, 186, 217, 28, 55, 159, 157, 7, 56, 7, 187, 90, 55, 61, 54, 52, 118, - 53, 230, 88, 54, 30, 55, 187, 157, 35, 56, 31, 46, 53, 170, 89, 54, 30, - 55, 187, 157, 35, 56, 15, 38, 54, 158, 89, 55, 187, 157, 35, 56, 7, 210, - 246, 35, 55, 3, 56, 14, 226, 88, 54, 30, 55, 187, 157, 35, 56, 31, 46, - 54, 234, 87, 53, 66, 55, 187, 157, 35, 56, 6, 166, 88, 55, 187, 157, 35, - 56, 120, 70, 49, 238, 1, 50, 190, 188, 25, 51, 38, 52, 30, 53, 147, 182, - 10, 54, 61, 58, 50, 126, 51, 150, 189, 25, 52, 30, 53, 147, 182, 10, 54, - 31, 50, 51, 222, 189, 25, 52, 30, 53, 147, 182, 10, 54, 15, 42, 52, 206, - 189, 25, 53, 147, 182, 10, 54, 7, 218, 243, 35, 53, 3, 54, 15, 146, 189, - 25, 52, 166, 153, 3, 53, 139, 157, 7, 54, 31, 50, 52, 138, 188, 25, 51, - 66, 53, 147, 182, 10, 54, 7, 199, 188, 25, 53, 6, 190, 153, 22, 32, 237, - 195, 8, 4, 66, 69, 82, 82, 232, 4, 200, 1, 3, 76, 68, 32, 78, 79, 104, 7, - 80, 79, 77, 79, 70, 79, 32, 188, 6, 2, 84, 84, 216, 6, 5, 85, 81, 85, 69, - 84, 54, 87, 198, 1, 88, 206, 215, 5, 77, 178, 168, 3, 89, 170, 167, 26, - 65, 139, 34, 78, 14, 254, 190, 8, 83, 142, 204, 7, 69, 190, 207, 17, 70, - 234, 2, 87, 215, 10, 71, 10, 26, 75, 215, 144, 23, 77, 9, 40, 4, 77, 65, - 82, 75, 175, 239, 35, 83, 5, 133, 171, 23, 3, 32, 84, 65, 150, 1, 96, 13, - 70, 73, 78, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 53, 7, 76, 69, 84, - 84, 69, 82, 32, 10, 162, 238, 35, 71, 2, 72, 2, 75, 2, 80, 3, 84, 140, 1, - 234, 1, 65, 54, 85, 22, 69, 82, 71, 46, 73, 70, 78, 38, 79, 98, 90, 170, - 154, 7, 75, 178, 174, 24, 67, 2, 76, 2, 83, 246, 76, 66, 206, 201, 1, 74, - 222, 137, 2, 68, 2, 70, 2, 72, 2, 77, 2, 80, 2, 81, 2, 82, 2, 84, 2, 86, - 3, 88, 21, 50, 73, 2, 85, 74, 78, 134, 235, 35, 72, 3, 77, 5, 235, 155, - 35, 78, 17, 50, 78, 134, 235, 35, 69, 2, 72, 2, 73, 3, 82, 7, 130, 235, - 35, 71, 3, 78, 11, 230, 234, 35, 72, 2, 78, 2, 85, 3, 87, 15, 180, 239, - 33, 2, 78, 78, 134, 251, 1, 72, 2, 77, 2, 82, 3, 85, 9, 222, 238, 33, 71, - 155, 251, 1, 78, 17, 66, 78, 142, 232, 34, 32, 134, 129, 1, 69, 2, 77, 2, - 79, 3, 85, 4, 142, 233, 35, 71, 3, 78, 9, 242, 232, 35, 72, 2, 73, 3, 89, - 66, 104, 3, 79, 77, 32, 133, 179, 21, 17, 76, 69, 32, 87, 73, 84, 72, 32, - 80, 79, 80, 80, 73, 78, 71, 32, 67, 64, 152, 2, 5, 72, 65, 76, 70, 32, - 232, 1, 5, 76, 69, 70, 84, 32, 88, 6, 82, 73, 71, 72, 84, 32, 88, 14, 83, - 81, 85, 65, 82, 69, 32, 66, 82, 65, 67, 75, 69, 84, 206, 213, 15, 65, - 226, 134, 16, 67, 210, 3, 80, 140, 3, 13, 74, 85, 83, 84, 73, 70, 73, 69, - 68, 32, 85, 80, 80, 135, 5, 84, 32, 148, 1, 16, 70, 79, 82, 87, 65, 82, - 68, 45, 70, 65, 67, 73, 78, 71, 32, 82, 130, 225, 31, 76, 22, 82, 252, 2, - 2, 83, 84, 174, 5, 66, 231, 243, 1, 73, 10, 252, 153, 29, 11, 85, 78, 78, - 69, 82, 32, 70, 82, 65, 77, 69, 223, 200, 2, 79, 8, 192, 230, 31, 13, 74, - 85, 83, 84, 73, 70, 73, 69, 68, 32, 85, 80, 80, 126, 67, 51, 72, 8, 230, - 230, 31, 67, 50, 72, 33, 13, 74, 85, 83, 84, 73, 70, 73, 69, 68, 32, 85, - 80, 80, 5, 225, 214, 23, 9, 32, 79, 86, 69, 82, 32, 84, 79, 80, 5, 149, - 211, 34, 8, 32, 79, 70, 32, 70, 76, 79, 87, 14, 58, 76, 116, 3, 84, 73, - 69, 141, 134, 33, 3, 32, 65, 78, 6, 26, 32, 247, 143, 35, 73, 4, 148, - 183, 9, 7, 79, 70, 32, 72, 89, 71, 73, 245, 130, 23, 6, 87, 73, 84, 72, - 32, 83, 7, 207, 195, 32, 32, 218, 2, 88, 10, 32, 68, 82, 65, 87, 73, 78, - 71, 83, 32, 193, 226, 34, 6, 73, 78, 71, 32, 71, 76, 216, 2, 176, 1, 2, - 68, 79, 228, 6, 6, 72, 69, 65, 86, 89, 32, 254, 2, 76, 204, 25, 6, 82, - 73, 71, 72, 84, 32, 144, 4, 3, 85, 80, 32, 245, 3, 9, 86, 69, 82, 84, 73, - 67, 65, 76, 32, 66, 52, 5, 85, 66, 76, 69, 32, 165, 3, 3, 87, 78, 32, 30, - 58, 68, 216, 2, 2, 85, 80, 234, 5, 86, 211, 163, 29, 72, 14, 64, 8, 73, - 65, 71, 79, 78, 65, 76, 32, 149, 2, 3, 79, 87, 78, 8, 104, 6, 85, 80, 80, - 69, 82, 32, 205, 14, 15, 76, 79, 87, 69, 82, 32, 76, 69, 70, 84, 32, 84, - 79, 32, 77, 6, 76, 8, 76, 69, 70, 84, 32, 84, 79, 32, 237, 24, 6, 82, 73, - 71, 72, 84, 32, 4, 204, 23, 14, 77, 73, 68, 68, 76, 69, 32, 67, 69, 78, - 84, 82, 69, 32, 159, 173, 23, 76, 6, 199, 26, 32, 36, 128, 1, 10, 72, 69, - 65, 86, 89, 32, 65, 78, 68, 32, 132, 1, 10, 76, 73, 71, 72, 84, 32, 65, - 78, 68, 32, 210, 38, 68, 131, 4, 83, 12, 76, 3, 76, 69, 70, 0, 4, 82, 73, - 71, 72, 228, 35, 2, 85, 80, 151, 5, 72, 4, 17, 2, 84, 32, 4, 230, 32, 85, - 239, 140, 35, 76, 12, 76, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 156, 36, - 2, 85, 80, 235, 4, 72, 4, 17, 2, 84, 32, 4, 198, 32, 85, 135, 9, 72, 46, - 136, 1, 4, 76, 69, 70, 84, 68, 2, 85, 80, 130, 1, 86, 172, 20, 2, 68, 79, - 170, 2, 81, 100, 2, 84, 82, 154, 140, 29, 72, 151, 134, 6, 82, 5, 45, 9, - 32, 65, 78, 68, 32, 76, 73, 71, 72, 2, 195, 132, 34, 84, 11, 29, 5, 32, - 65, 78, 68, 32, 8, 42, 76, 134, 164, 29, 72, 151, 134, 6, 82, 4, 224, - 174, 24, 4, 73, 71, 72, 84, 167, 251, 10, 69, 8, 209, 20, 7, 69, 82, 84, - 73, 67, 65, 76, 156, 1, 56, 4, 69, 70, 84, 32, 169, 2, 5, 73, 71, 72, 84, - 32, 16, 160, 27, 19, 68, 79, 87, 78, 32, 72, 69, 65, 86, 89, 32, 65, 78, - 68, 32, 82, 73, 71, 72, 24, 14, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, - 82, 73, 71, 72, 100, 14, 76, 73, 71, 72, 84, 32, 65, 78, 68, 32, 82, 73, - 71, 72, 97, 17, 85, 80, 32, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 82, - 73, 71, 72, 140, 1, 248, 1, 4, 65, 82, 67, 32, 30, 68, 248, 15, 10, 72, - 79, 82, 73, 90, 79, 78, 84, 65, 76, 112, 4, 76, 69, 70, 84, 62, 81, 34, - 84, 172, 1, 2, 85, 80, 120, 8, 86, 69, 82, 84, 73, 67, 65, 76, 192, 197, - 13, 7, 66, 79, 84, 84, 79, 77, 32, 143, 203, 21, 82, 8, 230, 202, 17, 68, - 67, 85, 80, 52, 8, 73, 65, 71, 79, 78, 65, 76, 32, 199, 14, 79, 68, 168, - 1, 14, 76, 79, 87, 69, 82, 32, 76, 69, 70, 84, 32, 84, 79, 32, 96, 7, 77, - 73, 68, 68, 76, 69, 32, 136, 3, 6, 85, 80, 80, 69, 82, 32, 162, 136, 34, - 67, 183, 4, 68, 4, 38, 77, 33, 5, 85, 80, 80, 69, 82, 2, 29, 5, 73, 68, - 68, 76, 69, 2, 129, 12, 2, 32, 67, 16, 88, 8, 76, 69, 70, 84, 32, 84, 79, - 32, 213, 1, 9, 82, 73, 71, 72, 84, 32, 84, 79, 32, 10, 156, 1, 6, 76, 79, - 87, 69, 82, 32, 33, 28, 85, 80, 80, 69, 82, 32, 67, 69, 78, 84, 82, 69, - 32, 84, 79, 32, 77, 73, 68, 68, 76, 69, 32, 82, 73, 71, 72, 84, 6, 246, - 3, 67, 255, 155, 35, 82, 5, 135, 191, 20, 32, 6, 232, 4, 15, 85, 80, 80, - 69, 82, 32, 67, 69, 78, 84, 82, 69, 32, 84, 79, 235, 3, 76, 44, 144, 1, - 10, 67, 69, 78, 84, 82, 69, 32, 84, 79, 32, 248, 3, 8, 76, 69, 70, 84, - 32, 84, 79, 32, 193, 2, 9, 82, 73, 71, 72, 84, 32, 84, 79, 32, 20, 52, 7, - 77, 73, 68, 68, 76, 69, 32, 171, 176, 23, 76, 16, 56, 4, 76, 69, 70, 84, - 165, 1, 5, 82, 73, 71, 72, 84, 9, 11, 32, 6, 84, 10, 84, 79, 32, 76, 79, - 87, 69, 82, 32, 67, 233, 186, 20, 5, 65, 78, 68, 32, 77, 4, 29, 5, 69, - 78, 84, 82, 69, 5, 133, 196, 32, 3, 32, 84, 79, 9, 11, 32, 6, 88, 3, 65, - 78, 68, 65, 15, 84, 79, 32, 76, 79, 87, 69, 82, 32, 67, 69, 78, 84, 82, - 69, 2, 241, 185, 20, 11, 32, 77, 73, 68, 68, 76, 69, 32, 76, 69, 70, 5, - 189, 211, 10, 9, 32, 84, 79, 32, 77, 73, 68, 68, 76, 14, 68, 6, 76, 79, - 87, 69, 82, 32, 97, 7, 77, 73, 68, 68, 76, 69, 32, 6, 48, 6, 67, 69, 78, - 84, 82, 69, 227, 152, 35, 82, 5, 11, 32, 2, 233, 4, 4, 84, 79, 32, 85, 8, - 76, 10, 67, 69, 78, 84, 82, 69, 32, 84, 79, 32, 33, 5, 82, 73, 71, 72, - 84, 4, 250, 3, 85, 139, 201, 13, 76, 5, 11, 32, 2, 193, 204, 13, 2, 84, - 79, 10, 46, 76, 69, 7, 77, 73, 68, 68, 76, 69, 32, 4, 29, 5, 79, 87, 69, - 82, 32, 4, 198, 191, 32, 67, 235, 214, 2, 76, 6, 34, 67, 37, 4, 76, 69, - 70, 84, 2, 45, 6, 69, 78, 84, 82, 69, 32, 5, 11, 32, 2, 133, 170, 23, 2, - 84, 79, 12, 36, 2, 87, 78, 253, 2, 2, 85, 66, 9, 11, 32, 6, 25, 4, 65, - 78, 68, 32, 6, 210, 142, 29, 72, 250, 133, 6, 76, 31, 82, 9, 11, 32, 6, - 40, 4, 65, 78, 68, 32, 227, 141, 35, 87, 4, 26, 85, 179, 168, 23, 76, 2, - 193, 168, 23, 2, 80, 80, 5, 149, 237, 33, 10, 32, 65, 78, 68, 32, 72, 69, - 65, 86, 89, 4, 109, 5, 85, 65, 68, 82, 85, 6, 66, 82, 225, 199, 13, 10, - 79, 80, 32, 65, 78, 68, 32, 85, 80, 80, 4, 11, 73, 4, 11, 80, 4, 41, 8, - 76, 69, 32, 68, 65, 83, 72, 32, 4, 190, 178, 16, 86, 151, 217, 12, 72, - 11, 29, 5, 32, 65, 78, 68, 32, 8, 34, 72, 230, 144, 35, 76, 31, 82, 4, - 200, 149, 24, 4, 69, 65, 86, 89, 175, 245, 4, 79, 17, 29, 5, 32, 65, 78, - 68, 32, 14, 162, 143, 28, 66, 42, 84, 206, 122, 72, 250, 133, 6, 76, 31, - 82, 16, 148, 2, 18, 68, 79, 87, 78, 32, 72, 69, 65, 86, 89, 32, 65, 78, - 68, 32, 76, 69, 70, 24, 13, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 76, - 69, 70, 100, 13, 76, 73, 71, 72, 84, 32, 65, 78, 68, 32, 76, 69, 70, 97, - 16, 85, 80, 32, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 76, 69, 70, 2, - 101, 3, 84, 32, 85, 6, 17, 2, 84, 32, 6, 58, 85, 178, 3, 68, 245, 4, 6, - 86, 69, 82, 84, 73, 67, 2, 183, 158, 33, 80, 6, 17, 2, 84, 32, 6, 58, 85, - 134, 4, 68, 205, 4, 6, 86, 69, 82, 84, 73, 67, 2, 239, 8, 80, 2, 185, 2, - 3, 84, 32, 68, 36, 128, 1, 10, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, - 188, 1, 10, 76, 73, 71, 72, 84, 32, 65, 78, 68, 32, 186, 2, 68, 131, 4, - 83, 12, 80, 4, 68, 79, 87, 78, 24, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, - 255, 4, 72, 2, 145, 5, 2, 32, 72, 4, 17, 2, 84, 32, 4, 26, 68, 191, 137, - 35, 76, 2, 133, 155, 33, 3, 79, 87, 78, 12, 80, 4, 68, 79, 87, 78, 24, 3, - 76, 69, 70, 0, 4, 82, 73, 71, 72, 211, 4, 72, 2, 229, 4, 2, 32, 72, 4, - 17, 2, 84, 32, 4, 22, 68, 131, 5, 72, 2, 233, 4, 3, 79, 87, 78, 24, 130, - 1, 68, 188, 1, 10, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 144, 1, 10, - 76, 73, 71, 72, 84, 32, 65, 78, 68, 32, 183, 1, 83, 6, 49, 10, 79, 85, - 66, 76, 69, 32, 65, 78, 68, 32, 6, 92, 3, 76, 69, 70, 0, 4, 82, 73, 71, - 72, 13, 10, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 2, 11, 84, 2, 233, - 231, 26, 2, 32, 83, 6, 54, 72, 68, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, - 2, 37, 7, 79, 82, 73, 90, 79, 78, 84, 2, 145, 150, 33, 2, 65, 76, 2, 247, - 149, 33, 84, 6, 54, 72, 60, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 37, - 7, 79, 82, 73, 90, 79, 78, 84, 2, 29, 2, 65, 76, 2, 11, 84, 2, 17, 2, 32, - 72, 2, 137, 156, 35, 3, 69, 65, 86, 6, 49, 10, 73, 78, 71, 76, 69, 32, - 65, 78, 68, 32, 6, 96, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 221, 171, 26, - 9, 72, 79, 82, 73, 90, 79, 78, 84, 65, 2, 231, 171, 26, 84, 134, 6, 46, - 65, 178, 14, 69, 150, 1, 73, 175, 1, 79, 232, 5, 36, 4, 72, 77, 73, 32, - 247, 9, 73, 230, 1, 192, 1, 7, 76, 69, 84, 84, 69, 82, 32, 196, 2, 7, 78, - 85, 77, 66, 69, 82, 32, 144, 2, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, - 79, 78, 32, 84, 5, 83, 73, 71, 78, 32, 122, 86, 239, 244, 24, 68, 108, - 210, 1, 79, 238, 205, 31, 65, 38, 68, 114, 84, 46, 86, 186, 5, 85, 206, - 201, 1, 73, 42, 76, 250, 192, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, - 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 82, 2, 89, 187, 2, 69, 15, 45, 9, - 76, 68, 32, 84, 65, 77, 73, 76, 32, 12, 158, 255, 28, 76, 206, 149, 2, - 83, 134, 92, 78, 175, 242, 2, 82, 42, 82, 69, 38, 70, 66, 78, 26, 83, - 138, 173, 21, 84, 238, 228, 5, 79, 203, 213, 7, 74, 4, 145, 135, 31, 4, - 73, 71, 72, 84, 8, 26, 79, 227, 147, 21, 73, 4, 142, 185, 33, 82, 159, - 180, 1, 85, 4, 65, 3, 73, 78, 69, 8, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, - 5, 215, 147, 35, 84, 10, 46, 76, 202, 208, 12, 68, 177, 16, 2, 67, 82, 4, - 198, 190, 19, 79, 235, 204, 14, 73, 12, 246, 143, 31, 67, 152, 62, 9, 79, - 76, 68, 32, 84, 65, 77, 73, 76, 230, 157, 1, 74, 158, 2, 86, 122, 85, - 187, 240, 1, 65, 34, 64, 10, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 167, - 234, 32, 73, 32, 138, 1, 79, 208, 174, 29, 11, 66, 72, 65, 84, 84, 73, - 80, 82, 79, 76, 85, 214, 159, 2, 65, 38, 85, 22, 86, 186, 201, 1, 73, - 223, 137, 2, 69, 7, 253, 142, 31, 10, 76, 68, 32, 84, 65, 77, 73, 76, 32, - 83, 130, 4, 72, 12, 76, 76, 69, 32, 80, 65, 84, 84, 69, 82, 78, 32, 231, - 160, 35, 78, 128, 4, 44, 5, 68, 79, 84, 83, 45, 171, 244, 6, 66, 254, 3, - 74, 49, 74, 50, 66, 51, 54, 52, 46, 53, 38, 54, 30, 55, 187, 157, 35, 56, - 129, 2, 66, 50, 66, 51, 54, 52, 46, 53, 38, 54, 30, 55, 187, 157, 35, 56, - 129, 1, 58, 51, 54, 52, 46, 53, 38, 54, 30, 55, 187, 157, 35, 56, 65, 50, - 52, 46, 53, 38, 54, 30, 55, 187, 157, 35, 56, 33, 42, 53, 38, 54, 30, 55, - 187, 157, 35, 56, 17, 34, 54, 30, 55, 187, 157, 35, 56, 9, 26, 55, 187, - 157, 35, 56, 5, 183, 157, 35, 56, 8, 26, 65, 183, 134, 35, 86, 6, 156, - 185, 20, 11, 75, 32, 80, 69, 82, 77, 73, 84, 84, 69, 68, 196, 171, 8, 6, - 83, 84, 45, 70, 69, 69, 167, 184, 6, 68, 10, 42, 68, 92, 2, 69, 70, 243, - 151, 35, 67, 4, 204, 161, 32, 6, 71, 69, 32, 65, 84, 32, 193, 70, 9, 69, - 32, 87, 73, 84, 72, 32, 86, 69, 4, 190, 245, 31, 67, 203, 165, 3, 83, 12, - 84, 4, 75, 69, 78, 32, 176, 192, 8, 2, 67, 67, 160, 210, 25, 2, 87, 78, - 231, 118, 79, 6, 248, 173, 27, 17, 67, 73, 82, 67, 76, 69, 32, 87, 73, - 84, 72, 32, 78, 79, 82, 84, 72, 218, 202, 6, 66, 147, 26, 72, 134, 1, - 208, 1, 4, 66, 66, 76, 69, 46, 71, 156, 4, 4, 72, 73, 68, 32, 36, 2, 76, - 76, 122, 83, 56, 4, 84, 84, 69, 82, 176, 249, 10, 10, 73, 76, 68, 73, 78, - 71, 32, 67, 79, 78, 184, 213, 16, 2, 82, 82, 247, 239, 6, 67, 4, 204, - 145, 28, 2, 32, 84, 243, 133, 7, 83, 63, 33, 6, 73, 78, 69, 83, 69, 32, - 60, 144, 1, 7, 76, 69, 84, 84, 69, 82, 32, 172, 2, 11, 86, 79, 87, 69, - 76, 32, 83, 73, 71, 78, 32, 190, 176, 16, 69, 225, 241, 13, 4, 80, 65, - 76, 76, 46, 154, 1, 77, 34, 78, 234, 145, 35, 66, 2, 67, 2, 68, 2, 71, 2, - 72, 2, 74, 2, 75, 2, 76, 2, 80, 2, 82, 2, 83, 2, 84, 2, 86, 2, 89, 187, - 2, 65, 4, 134, 146, 35, 80, 187, 2, 65, 12, 46, 71, 34, 89, 154, 145, 35, - 82, 187, 2, 65, 4, 182, 145, 35, 75, 187, 2, 65, 4, 150, 145, 35, 67, - 187, 2, 65, 10, 218, 252, 34, 65, 214, 22, 69, 2, 73, 2, 79, 3, 85, 40, - 142, 152, 10, 76, 135, 241, 18, 86, 10, 56, 2, 69, 84, 20, 4, 72, 79, 82, - 78, 231, 162, 9, 83, 5, 179, 210, 31, 32, 5, 241, 184, 27, 5, 32, 87, 73, - 84, 72, 9, 26, 84, 143, 192, 32, 32, 4, 234, 184, 27, 83, 15, 32, 5, 243, - 237, 34, 70, 240, 3, 140, 1, 23, 90, 65, 78, 84, 73, 78, 69, 32, 77, 85, - 83, 73, 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 245, 179, 20, 5, 84, - 69, 32, 79, 82, 238, 3, 154, 2, 65, 128, 7, 2, 67, 72, 170, 1, 68, 158, - 5, 69, 206, 2, 70, 166, 8, 71, 202, 3, 73, 162, 2, 75, 142, 5, 76, 190, - 2, 77, 250, 4, 79, 114, 80, 174, 4, 82, 42, 83, 194, 5, 84, 196, 5, 2, - 86, 65, 250, 1, 89, 178, 160, 32, 78, 245, 142, 2, 9, 88, 73, 82, 79, 78, - 32, 75, 76, 65, 62, 60, 5, 71, 79, 71, 73, 32, 222, 1, 78, 118, 80, 199, - 2, 82, 16, 70, 65, 0, 2, 71, 79, 64, 2, 77, 69, 37, 5, 80, 79, 76, 73, - 32, 4, 17, 2, 82, 71, 4, 160, 227, 15, 2, 79, 84, 159, 169, 19, 73, 4, - 214, 151, 9, 84, 231, 224, 25, 83, 4, 26, 65, 1, 2, 71, 79, 2, 131, 203, - 17, 82, 6, 72, 6, 84, 73, 75, 69, 78, 79, 205, 233, 34, 6, 65, 84, 82, - 73, 67, 72, 4, 168, 32, 2, 75, 89, 147, 232, 34, 77, 22, 52, 5, 69, 83, - 79, 32, 69, 38, 79, 155, 246, 34, 76, 4, 204, 1, 2, 88, 79, 147, 55, 75, - 16, 80, 6, 83, 84, 82, 79, 70, 79, 188, 40, 3, 68, 69, 82, 181, 128, 1, - 2, 84, 72, 10, 24, 2, 73, 32, 79, 83, 4, 56, 9, 83, 89, 78, 68, 69, 83, - 77, 79, 83, 195, 24, 84, 2, 143, 44, 32, 7, 11, 32, 4, 214, 60, 68, 255, - 145, 22, 78, 18, 48, 2, 71, 79, 33, 6, 75, 84, 73, 75, 79, 32, 4, 170, - 21, 83, 171, 242, 34, 78, 14, 182, 190, 27, 86, 138, 170, 7, 90, 162, 8, - 75, 254, 2, 68, 2, 78, 162, 17, 71, 3, 80, 14, 80, 4, 82, 79, 65, 32, - 168, 37, 4, 79, 82, 69, 86, 221, 2, 4, 65, 77, 73, 76, 6, 228, 214, 19, - 2, 83, 80, 220, 191, 3, 3, 90, 89, 71, 185, 188, 10, 3, 75, 76, 73, 42, - 50, 73, 172, 219, 8, 2, 65, 83, 227, 138, 26, 89, 38, 122, 65, 200, 1, 5, - 69, 83, 73, 83, 32, 70, 71, 208, 1, 3, 80, 76, 73, 173, 183, 27, 8, 70, - 84, 79, 71, 71, 79, 83, 32, 10, 48, 6, 83, 84, 79, 76, 73, 32, 179, 203, - 33, 82, 8, 80, 6, 65, 80, 76, 73, 32, 77, 174, 55, 68, 141, 220, 22, 5, - 84, 72, 69, 83, 69, 4, 40, 2, 69, 71, 133, 165, 28, 2, 73, 75, 2, 195, - 135, 30, 65, 12, 38, 84, 246, 50, 65, 42, 68, 63, 77, 6, 194, 10, 69, - 239, 41, 82, 10, 72, 5, 79, 82, 71, 79, 78, 217, 128, 35, 7, 82, 65, 77, - 77, 65, 32, 71, 9, 69, 15, 32, 80, 65, 82, 69, 83, 84, 73, 71, 77, 69, - 78, 79, 78, 32, 6, 222, 38, 68, 137, 10, 8, 65, 82, 73, 83, 84, 69, 82, - 65, 5, 175, 47, 32, 16, 166, 1, 78, 116, 6, 84, 69, 82, 79, 78, 32, 188, - 44, 4, 88, 79, 32, 69, 156, 238, 32, 4, 80, 69, 71, 69, 152, 48, 6, 75, - 83, 84, 82, 69, 80, 237, 13, 3, 76, 65, 70, 4, 224, 22, 3, 68, 79, 70, - 145, 159, 27, 18, 65, 82, 88, 73, 83, 32, 75, 65, 73, 32, 70, 84, 72, 79, - 82, 65, 32, 86, 4, 208, 11, 5, 65, 82, 71, 79, 83, 151, 20, 80, 44, 180, - 1, 9, 65, 78, 69, 82, 79, 83, 73, 83, 32, 52, 6, 84, 72, 79, 82, 65, 32, - 165, 6, 22, 72, 84, 79, 82, 65, 32, 83, 75, 76, 73, 82, 79, 78, 32, 67, - 72, 82, 79, 77, 65, 32, 86, 6, 246, 4, 68, 14, 77, 25, 5, 84, 69, 84, 82, - 65, 36, 220, 2, 8, 65, 82, 67, 72, 65, 73, 79, 78, 80, 10, 68, 73, 65, - 84, 79, 78, 73, 75, 73, 32, 96, 11, 73, 32, 89, 70, 69, 83, 73, 83, 32, - 84, 69, 32, 15, 77, 65, 76, 65, 75, 79, 78, 32, 67, 72, 82, 79, 77, 65, - 32, 74, 78, 40, 8, 83, 75, 76, 73, 82, 79, 78, 32, 141, 209, 18, 18, 69, - 78, 65, 82, 77, 79, 78, 73, 79, 83, 32, 65, 78, 84, 73, 70, 79, 78, 5, - 57, 12, 32, 68, 69, 89, 84, 69, 82, 79, 85, 32, 73, 67, 2, 199, 175, 27, - 72, 14, 62, 78, 254, 216, 34, 90, 162, 8, 75, 254, 2, 68, 163, 17, 80, 6, - 242, 39, 73, 251, 147, 33, 65, 2, 237, 42, 4, 84, 65, 82, 84, 4, 18, 68, - 15, 77, 2, 35, 73, 2, 21, 3, 79, 78, 79, 2, 151, 19, 70, 4, 166, 19, 65, - 213, 219, 32, 2, 69, 78, 6, 84, 7, 67, 72, 82, 79, 77, 65, 32, 193, 149, - 17, 8, 68, 73, 65, 84, 79, 78, 79, 78, 4, 42, 86, 169, 153, 17, 4, 83, - 89, 78, 65, 2, 251, 209, 32, 65, 22, 80, 6, 69, 78, 73, 75, 73, 32, 44, - 2, 79, 82, 185, 26, 5, 82, 79, 78, 84, 72, 4, 192, 242, 30, 2, 68, 73, 1, - 2, 89, 70, 16, 68, 2, 71, 79, 225, 1, 10, 84, 72, 77, 73, 75, 79, 78, 32, - 78, 32, 12, 28, 2, 78, 32, 155, 1, 83, 10, 96, 14, 80, 65, 82, 69, 83, - 84, 73, 71, 77, 69, 78, 79, 78, 32, 242, 33, 65, 113, 3, 78, 69, 79, 4, - 214, 24, 68, 249, 202, 32, 5, 65, 82, 73, 83, 84, 2, 153, 191, 33, 5, 89, - 78, 84, 72, 69, 4, 142, 28, 65, 1, 2, 68, 73, 16, 56, 2, 77, 73, 114, 83, - 225, 240, 33, 4, 67, 72, 65, 68, 8, 34, 70, 169, 28, 3, 68, 73, 65, 6, - 40, 4, 84, 72, 79, 82, 195, 230, 33, 79, 4, 242, 160, 34, 79, 227, 79, - 65, 6, 44, 6, 65, 75, 73, 65, 32, 84, 231, 13, 79, 2, 153, 201, 21, 12, - 69, 76, 79, 85, 83, 32, 73, 67, 72, 73, 77, 65, 54, 108, 2, 65, 84, 96, - 6, 69, 78, 84, 73, 77, 65, 140, 1, 5, 76, 65, 83, 77, 65, 18, 79, 98, 82, - 175, 1, 89, 6, 40, 3, 65, 86, 65, 201, 3, 2, 72, 73, 4, 140, 29, 5, 32, - 84, 82, 79, 77, 135, 176, 34, 83, 18, 24, 2, 84, 65, 15, 32, 11, 11, 32, - 8, 36, 4, 78, 69, 79, 32, 183, 28, 65, 6, 252, 140, 28, 2, 77, 69, 254, - 212, 2, 75, 151, 226, 3, 65, 7, 243, 28, 32, 8, 64, 6, 78, 84, 69, 86, - 77, 65, 202, 212, 8, 82, 151, 246, 25, 85, 5, 181, 166, 14, 2, 32, 65, - 14, 44, 4, 65, 84, 73, 77, 105, 3, 69, 77, 65, 12, 18, 65, 35, 79, 8, - 182, 23, 32, 195, 209, 34, 84, 4, 134, 12, 75, 181, 184, 31, 5, 89, 80, - 79, 82, 82, 2, 227, 140, 27, 83, 2, 159, 201, 34, 76, 14, 22, 69, 147, - 22, 89, 12, 44, 5, 73, 77, 77, 65, 32, 191, 251, 29, 77, 10, 72, 2, 69, - 78, 0, 5, 73, 77, 73, 83, 69, 54, 84, 69, 3, 68, 89, 79, 2, 161, 160, 27, - 8, 79, 83, 32, 67, 72, 82, 79, 78, 4, 44, 5, 69, 83, 83, 65, 82, 1, 2, - 82, 73, 2, 17, 2, 79, 78, 2, 25, 4, 32, 67, 72, 82, 2, 247, 221, 33, 79, - 28, 84, 8, 65, 82, 84, 89, 82, 73, 65, 32, 229, 231, 30, 7, 73, 75, 82, - 79, 78, 32, 73, 26, 72, 5, 65, 76, 76, 73, 32, 38, 68, 38, 80, 134, 1, - 86, 30, 84, 87, 76, 4, 34, 68, 177, 2, 3, 80, 82, 79, 2, 237, 2, 5, 69, - 89, 84, 69, 82, 8, 60, 7, 76, 65, 71, 73, 79, 83, 32, 45, 4, 82, 79, 84, - 79, 4, 200, 1, 5, 84, 69, 84, 65, 82, 111, 73, 4, 22, 86, 227, 1, 83, 2, - 209, 1, 3, 65, 82, 89, 8, 56, 8, 69, 84, 65, 82, 84, 79, 83, 32, 61, 2, - 82, 73, 4, 22, 76, 135, 1, 73, 2, 21, 3, 69, 71, 69, 2, 63, 84, 4, 18, - 70, 35, 84, 2, 209, 197, 21, 3, 79, 78, 73, 2, 11, 79, 2, 11, 83, 2, 17, - 2, 32, 73, 2, 155, 239, 22, 67, 18, 92, 4, 76, 73, 71, 79, 180, 1, 5, 89, - 82, 65, 78, 73, 210, 14, 88, 165, 130, 34, 2, 77, 65, 4, 211, 1, 78, 42, - 60, 2, 65, 82, 100, 2, 73, 65, 90, 69, 169, 1, 2, 83, 73, 12, 40, 2, 65, - 75, 181, 170, 17, 2, 73, 67, 10, 52, 3, 65, 76, 69, 45, 6, 76, 73, 84, - 73, 75, 73, 4, 11, 83, 4, 17, 2, 77, 65, 4, 23, 32, 7, 11, 32, 4, 198, - 15, 65, 155, 151, 22, 78, 12, 72, 3, 84, 65, 83, 136, 3, 6, 76, 65, 83, - 84, 79, 78, 191, 216, 8, 82, 6, 26, 84, 247, 220, 34, 77, 4, 32, 2, 79, - 75, 139, 223, 34, 73, 2, 209, 189, 34, 2, 79, 85, 14, 36, 5, 70, 73, 83, - 84, 79, 67, 76, 10, 46, 80, 214, 1, 78, 170, 8, 76, 187, 1, 83, 2, 135, - 11, 65, 4, 162, 142, 34, 79, 227, 79, 73, 4, 178, 5, 69, 137, 183, 34, 2, - 65, 80, 42, 120, 5, 69, 73, 83, 77, 65, 32, 8, 73, 77, 65, 78, 83, 73, - 83, 32, 182, 1, 84, 154, 1, 89, 245, 240, 1, 3, 65, 88, 73, 5, 11, 32, 2, - 223, 162, 22, 78, 16, 36, 2, 65, 82, 1, 3, 84, 72, 69, 8, 25, 4, 83, 69, - 79, 83, 9, 11, 32, 6, 18, 84, 39, 68, 4, 34, 82, 13, 4, 69, 84, 82, 65, - 2, 11, 73, 2, 141, 146, 27, 3, 83, 73, 77, 8, 68, 5, 65, 86, 82, 79, 83, - 52, 4, 82, 65, 71, 71, 179, 199, 16, 73, 5, 29, 5, 32, 65, 80, 79, 68, 2, - 255, 219, 8, 69, 2, 141, 241, 1, 2, 73, 83, 12, 34, 78, 149, 1, 3, 82, - 77, 65, 8, 36, 5, 65, 71, 77, 65, 32, 91, 69, 6, 154, 8, 65, 154, 151, - 22, 78, 217, 240, 4, 10, 77, 69, 84, 65, 32, 83, 84, 65, 86, 82, 2, 159, - 183, 34, 86, 5, 11, 84, 2, 243, 245, 16, 73, 40, 42, 69, 70, 72, 218, 1, - 82, 227, 2, 73, 6, 136, 12, 3, 84, 82, 65, 242, 161, 8, 76, 201, 154, 24, - 2, 83, 83, 12, 26, 69, 167, 178, 34, 73, 10, 64, 2, 77, 65, 145, 194, 33, - 8, 83, 32, 75, 65, 73, 32, 65, 80, 9, 56, 2, 32, 65, 33, 8, 84, 73, 83, - 77, 79, 83, 32, 69, 2, 189, 213, 33, 3, 80, 76, 79, 4, 218, 182, 34, 83, - 3, 88, 20, 38, 73, 73, 5, 79, 77, 73, 75, 79, 6, 48, 2, 71, 79, 206, 217, - 29, 80, 143, 251, 4, 65, 2, 183, 156, 33, 82, 14, 42, 76, 32, 2, 78, 32, - 62, 80, 95, 83, 2, 11, 89, 2, 227, 178, 34, 71, 6, 26, 65, 139, 154, 22, - 78, 4, 250, 2, 82, 147, 174, 34, 76, 4, 46, 65, 129, 160, 33, 5, 83, 73, - 70, 73, 83, 2, 237, 177, 34, 6, 82, 65, 75, 65, 76, 69, 2, 11, 89, 2, - 145, 192, 16, 2, 78, 65, 10, 26, 82, 219, 176, 34, 84, 8, 21, 3, 69, 73, - 65, 8, 26, 32, 113, 2, 73, 32, 6, 38, 69, 242, 5, 68, 255, 145, 22, 78, - 2, 11, 75, 2, 29, 5, 70, 79, 78, 73, 84, 2, 165, 129, 34, 2, 73, 75, 2, - 11, 65, 2, 11, 82, 2, 153, 128, 34, 3, 67, 72, 65, 22, 28, 2, 70, 69, - 231, 3, 80, 14, 34, 78, 49, 4, 83, 73, 83, 32, 4, 11, 32, 4, 202, 196, - 30, 75, 151, 226, 3, 65, 10, 42, 65, 42, 68, 62, 77, 89, 2, 84, 82, 2, - 133, 2, 6, 80, 76, 73, 32, 68, 89, 2, 233, 1, 11, 73, 71, 82, 65, 77, 77, - 79, 83, 32, 69, 88, 2, 173, 1, 18, 79, 78, 79, 71, 82, 65, 77, 77, 79, - 83, 32, 84, 69, 83, 83, 69, 82, 65, 4, 11, 73, 4, 60, 11, 71, 82, 65, 77, - 77, 79, 83, 32, 79, 75, 84, 59, 84, 2, 11, 79, 2, 181, 174, 2, 6, 32, 68, - 79, 68, 69, 75, 2, 153, 252, 33, 4, 73, 77, 79, 82, 8, 26, 79, 139, 209, - 29, 83, 6, 56, 6, 75, 82, 73, 83, 73, 83, 181, 221, 29, 2, 82, 82, 5, 17, - 2, 32, 68, 2, 11, 73, 2, 183, 208, 29, 80, 172, 82, 182, 1, 65, 134, 72, - 69, 230, 1, 72, 154, 31, 73, 208, 41, 3, 74, 75, 32, 138, 26, 76, 186, - 18, 79, 194, 113, 82, 234, 7, 85, 150, 128, 2, 89, 242, 164, 19, 71, 226, - 216, 10, 83, 203, 18, 67, 198, 13, 110, 68, 66, 76, 50, 77, 90, 78, 174, - 51, 80, 62, 82, 198, 7, 84, 138, 1, 85, 242, 164, 18, 67, 187, 203, 6, - 83, 4, 34, 85, 137, 139, 27, 2, 65, 32, 2, 221, 194, 32, 2, 67, 69, 4, - 152, 207, 9, 3, 76, 32, 77, 247, 200, 19, 69, 6, 36, 3, 69, 82, 65, 231, - 246, 33, 80, 5, 165, 177, 27, 7, 32, 87, 73, 84, 72, 32, 70, 193, 11, - 148, 1, 16, 65, 68, 73, 65, 78, 32, 83, 89, 76, 76, 65, 66, 73, 67, 83, - 32, 148, 49, 2, 67, 69, 94, 68, 216, 227, 23, 3, 78, 69, 68, 131, 154, - 10, 79, 172, 11, 226, 1, 65, 190, 1, 66, 162, 2, 67, 242, 8, 69, 50, 70, - 198, 4, 72, 38, 73, 30, 75, 134, 1, 76, 82, 77, 174, 1, 78, 202, 4, 81, - 178, 1, 79, 194, 1, 80, 70, 82, 142, 1, 83, 194, 4, 84, 246, 3, 87, 254, - 5, 89, 247, 204, 17, 71, 21, 90, 65, 30, 73, 40, 10, 84, 72, 65, 80, 65, - 83, 67, 65, 78, 32, 150, 195, 34, 78, 3, 89, 7, 214, 195, 34, 73, 3, 89, - 5, 169, 221, 23, 5, 86, 73, 76, 73, 75, 4, 146, 195, 34, 77, 3, 83, 42, - 156, 1, 9, 76, 65, 67, 75, 70, 79, 79, 84, 32, 172, 151, 19, 9, 73, 66, - 76, 69, 45, 67, 82, 69, 69, 221, 202, 7, 10, 69, 65, 86, 69, 82, 32, 68, - 69, 78, 69, 36, 82, 87, 230, 228, 11, 75, 2, 78, 162, 220, 22, 65, 2, 69, - 2, 73, 2, 79, 3, 83, 11, 130, 193, 34, 65, 2, 69, 2, 73, 3, 79, 141, 3, - 82, 65, 186, 42, 87, 142, 169, 8, 72, 222, 166, 23, 79, 134, 60, 73, 223, - 137, 2, 69, 241, 2, 48, 6, 82, 82, 73, 69, 82, 32, 239, 181, 32, 65, 234, - 2, 170, 1, 68, 122, 71, 94, 72, 46, 73, 46, 74, 82, 75, 30, 78, 66, 83, - 66, 80, 2, 90, 58, 84, 38, 76, 132, 1, 2, 67, 72, 2, 77, 2, 82, 2, 87, 2, - 89, 207, 161, 34, 69, 32, 46, 69, 202, 5, 76, 2, 90, 163, 184, 34, 73, 6, - 26, 78, 207, 189, 34, 69, 4, 146, 134, 17, 69, 237, 210, 6, 2, 84, 65, - 30, 254, 4, 72, 182, 166, 21, 87, 234, 165, 7, 65, 230, 171, 5, 69, 162, - 64, 73, 2, 79, 3, 85, 19, 162, 4, 87, 206, 161, 34, 69, 215, 22, 73, 5, - 225, 135, 14, 6, 78, 73, 84, 73, 65, 76, 26, 202, 3, 74, 130, 248, 33, - 69, 234, 61, 87, 186, 2, 65, 2, 73, 2, 79, 3, 85, 26, 154, 1, 75, 227, 1, - 72, 14, 222, 250, 33, 69, 162, 64, 65, 2, 71, 2, 73, 2, 79, 3, 85, 26, - 62, 72, 226, 249, 33, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 15, 222, 249, - 33, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 72, 34, 76, 70, 84, 66, 72, 3, - 83, 24, 130, 1, 72, 130, 248, 33, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, - 24, 62, 83, 130, 248, 33, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 12, 254, - 247, 33, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 7, 236, 29, 4, 65, 83, 84, - 69, 251, 153, 34, 78, 51, 74, 65, 22, 73, 130, 229, 31, 85, 250, 11, 79, - 150, 83, 87, 207, 242, 1, 69, 7, 143, 173, 32, 65, 33, 40, 4, 78, 65, 76, - 32, 175, 182, 34, 73, 28, 160, 1, 2, 68, 79, 134, 1, 82, 78, 83, 166, - 133, 14, 71, 186, 2, 65, 128, 177, 3, 6, 66, 79, 84, 84, 79, 77, 0, 3, - 84, 79, 80, 166, 244, 12, 80, 247, 244, 2, 77, 6, 44, 5, 85, 66, 76, 69, - 32, 131, 160, 24, 87, 4, 252, 198, 6, 12, 83, 72, 79, 82, 84, 32, 86, 69, - 82, 84, 73, 67, 255, 193, 7, 65, 6, 38, 73, 213, 231, 32, 3, 65, 73, 83, - 4, 230, 184, 17, 71, 163, 250, 16, 78, 4, 152, 146, 25, 4, 77, 65, 76, - 76, 213, 252, 6, 4, 72, 79, 82, 84, 4, 150, 176, 26, 89, 223, 130, 8, 75, - 7, 206, 178, 34, 73, 3, 78, 39, 66, 87, 234, 27, 65, 170, 208, 31, 79, - 134, 60, 73, 223, 137, 2, 69, 19, 138, 143, 12, 65, 134, 221, 19, 79, - 134, 60, 73, 223, 137, 2, 69, 49, 142, 7, 72, 154, 20, 65, 66, 87, 234, - 207, 31, 79, 134, 60, 73, 223, 137, 2, 69, 43, 70, 69, 38, 79, 238, 25, - 65, 66, 87, 238, 139, 32, 73, 223, 137, 2, 72, 7, 197, 208, 26, 4, 68, - 73, 65, 76, 7, 11, 79, 5, 249, 234, 32, 8, 83, 69, 45, 67, 82, 69, 69, - 32, 149, 1, 164, 1, 8, 45, 67, 82, 69, 69, 32, 84, 72, 38, 65, 250, 2, - 71, 76, 2, 78, 71, 48, 4, 85, 78, 65, 86, 142, 20, 79, 30, 87, 238, 139, - 32, 73, 222, 137, 2, 69, 3, 72, 6, 170, 164, 32, 73, 223, 137, 2, 69, 63, - 104, 6, 83, 75, 65, 80, 73, 32, 188, 1, 7, 84, 84, 73, 76, 73, 75, 32, - 226, 161, 32, 65, 223, 137, 2, 89, 30, 70, 83, 86, 87, 210, 17, 67, 2, - 75, 2, 77, 2, 78, 2, 84, 3, 89, 14, 168, 192, 28, 2, 75, 87, 254, 122, - 67, 2, 80, 2, 84, 190, 254, 2, 87, 175, 116, 45, 4, 230, 140, 34, 79, - 191, 28, 65, 24, 30, 72, 1, 3, 83, 72, 82, 12, 150, 191, 28, 65, 166, - 166, 3, 79, 135, 60, 73, 19, 38, 65, 230, 228, 31, 79, 135, 60, 73, 9, - 230, 160, 32, 65, 223, 137, 2, 73, 15, 154, 190, 28, 65, 166, 166, 3, 79, - 135, 60, 73, 18, 224, 9, 3, 73, 75, 32, 185, 186, 23, 2, 85, 84, 33, 68, - 7, 74, 73, 66, 87, 65, 89, 32, 246, 168, 34, 78, 2, 79, 3, 89, 24, 74, - 78, 142, 136, 30, 83, 158, 160, 4, 67, 2, 75, 2, 77, 2, 80, 3, 84, 11, - 11, 87, 8, 186, 226, 31, 79, 135, 60, 73, 39, 206, 4, 87, 166, 13, 65, - 38, 79, 138, 140, 32, 73, 223, 137, 2, 69, 39, 104, 7, 45, 67, 82, 69, - 69, 32, 82, 146, 14, 87, 182, 2, 65, 170, 208, 31, 79, 134, 60, 73, 223, - 137, 2, 69, 4, 246, 143, 34, 87, 215, 22, 69, 125, 94, 65, 218, 1, 72, - 138, 1, 79, 238, 2, 87, 226, 195, 11, 80, 198, 210, 20, 73, 223, 137, 2, - 69, 43, 26, 89, 215, 155, 32, 65, 37, 25, 4, 73, 83, 73, 32, 34, 70, 72, - 54, 74, 218, 4, 83, 234, 139, 34, 89, 202, 18, 84, 147, 1, 77, 10, 234, - 222, 31, 79, 226, 197, 2, 65, 2, 69, 3, 73, 6, 238, 208, 30, 85, 171, - 211, 3, 73, 37, 70, 87, 202, 13, 79, 130, 243, 11, 65, 138, 153, 20, 73, - 223, 137, 2, 69, 16, 198, 13, 79, 226, 169, 28, 65, 170, 226, 3, 73, 223, - 137, 2, 69, 15, 80, 12, 85, 84, 72, 45, 83, 76, 65, 86, 69, 89, 32, 75, - 154, 162, 34, 79, 3, 89, 8, 134, 161, 34, 65, 2, 69, 2, 73, 3, 79, 117, - 110, 72, 190, 1, 76, 78, 84, 238, 8, 65, 66, 87, 170, 185, 11, 89, 194, - 150, 20, 79, 134, 60, 73, 223, 137, 2, 69, 39, 108, 7, 45, 67, 82, 69, - 69, 32, 84, 226, 4, 87, 170, 175, 28, 65, 166, 166, 3, 79, 134, 60, 73, - 223, 137, 2, 69, 16, 11, 72, 17, 250, 179, 28, 65, 166, 166, 3, 79, 134, - 60, 73, 223, 137, 2, 69, 12, 11, 72, 12, 210, 217, 31, 79, 142, 175, 2, - 87, 214, 22, 65, 2, 69, 3, 73, 24, 50, 72, 194, 158, 34, 65, 2, 69, 2, - 73, 3, 79, 17, 186, 178, 28, 65, 166, 166, 3, 79, 142, 175, 2, 87, 214, - 22, 69, 3, 73, 224, 1, 54, 69, 218, 3, 79, 130, 247, 11, 65, 139, 153, - 20, 73, 185, 1, 17, 2, 83, 84, 182, 1, 44, 6, 45, 67, 82, 69, 69, 32, - 251, 2, 69, 180, 1, 110, 76, 66, 77, 2, 80, 2, 89, 16, 2, 78, 87, 38, 82, - 62, 83, 26, 67, 2, 75, 18, 84, 26, 70, 199, 4, 87, 27, 178, 6, 87, 198, - 169, 28, 65, 166, 166, 3, 79, 227, 197, 2, 69, 17, 243, 5, 87, 6, 166, - 175, 28, 65, 135, 236, 5, 69, 13, 186, 168, 32, 87, 206, 242, 1, 65, 2, - 69, 2, 73, 3, 79, 28, 22, 72, 239, 4, 87, 14, 235, 4, 87, 16, 22, 72, - 199, 4, 87, 2, 191, 167, 32, 87, 2, 171, 183, 23, 82, 31, 11, 79, 29, 41, - 8, 68, 83, 45, 67, 82, 69, 69, 32, 26, 56, 2, 84, 72, 225, 150, 32, 6, - 70, 73, 78, 65, 76, 32, 25, 50, 87, 190, 152, 34, 65, 2, 69, 2, 73, 3, - 79, 14, 182, 172, 28, 65, 166, 166, 3, 79, 134, 60, 73, 139, 243, 1, 69, - 61, 92, 6, 45, 67, 82, 69, 69, 32, 150, 1, 65, 38, 79, 30, 87, 238, 139, - 32, 73, 223, 137, 2, 69, 24, 110, 80, 134, 207, 31, 67, 2, 75, 2, 76, 2, - 77, 2, 78, 2, 83, 2, 84, 2, 89, 182, 168, 2, 79, 247, 30, 87, 4, 222, - 163, 32, 87, 219, 211, 1, 79, 9, 170, 140, 32, 65, 223, 137, 2, 89, 7, - 226, 149, 34, 79, 3, 89, 14, 194, 169, 28, 65, 166, 166, 3, 79, 134, 60, - 73, 223, 137, 2, 69, 10, 26, 76, 239, 148, 34, 82, 9, 26, 32, 155, 181, - 9, 76, 4, 182, 150, 22, 67, 151, 149, 10, 84, 4, 214, 253, 33, 76, 215, - 22, 89, 4, 216, 171, 15, 3, 73, 84, 85, 253, 132, 8, 3, 82, 73, 67, 124, - 140, 1, 2, 68, 32, 102, 69, 72, 11, 73, 65, 78, 32, 76, 69, 84, 84, 69, - 82, 32, 210, 3, 79, 62, 80, 90, 82, 141, 212, 27, 4, 32, 83, 76, 73, 6, - 52, 5, 73, 78, 68, 69, 88, 169, 133, 33, 2, 70, 73, 5, 165, 131, 33, 6, - 32, 68, 73, 86, 73, 68, 6, 26, 84, 227, 190, 21, 32, 5, 181, 156, 10, 6, - 32, 73, 78, 83, 69, 82, 98, 196, 1, 2, 67, 45, 38, 76, 22, 77, 50, 78, - 38, 83, 46, 84, 22, 85, 186, 213, 3, 65, 2, 68, 2, 69, 2, 71, 2, 75, 2, - 80, 130, 230, 26, 82, 238, 200, 1, 73, 222, 137, 2, 66, 2, 79, 2, 81, 3, - 88, 4, 174, 242, 26, 49, 219, 167, 3, 51, 7, 223, 214, 3, 68, 11, 11, 66, - 9, 134, 143, 34, 50, 2, 51, 3, 52, 9, 226, 142, 34, 68, 2, 71, 3, 78, 13, - 246, 213, 3, 72, 2, 84, 203, 184, 30, 83, 7, 203, 213, 3, 84, 13, 11, 85, - 11, 11, 85, 9, 230, 141, 34, 50, 2, 51, 3, 85, 4, 160, 132, 33, 6, 85, - 83, 69, 76, 32, 72, 163, 137, 1, 78, 4, 224, 189, 27, 6, 32, 83, 84, 82, - 69, 65, 249, 208, 5, 7, 69, 78, 84, 82, 89, 32, 83, 4, 142, 200, 27, 73, - 247, 167, 6, 79, 9, 29, 5, 32, 70, 65, 67, 69, 7, 33, 6, 32, 87, 73, 84, - 72, 32, 4, 208, 235, 6, 2, 84, 69, 129, 251, 24, 6, 87, 82, 89, 32, 83, - 77, 108, 88, 16, 67, 65, 83, 73, 65, 78, 32, 65, 76, 66, 65, 78, 73, 65, - 78, 32, 235, 137, 30, 84, 106, 60, 7, 76, 69, 84, 84, 69, 82, 32, 161, - 250, 27, 2, 67, 73, 104, 174, 2, 65, 34, 67, 146, 1, 68, 78, 69, 34, 71, - 46, 73, 46, 74, 34, 75, 34, 76, 34, 80, 34, 83, 74, 84, 62, 89, 46, 90, - 128, 241, 16, 2, 81, 65, 214, 192, 6, 77, 148, 173, 6, 3, 86, 69, 89, - 178, 232, 2, 70, 128, 19, 3, 78, 79, 87, 150, 20, 82, 242, 21, 88, 154, - 46, 79, 202, 26, 66, 237, 24, 3, 72, 69, 89, 4, 218, 206, 33, 79, 179, - 28, 76, 16, 34, 65, 34, 72, 49, 2, 89, 65, 4, 146, 183, 33, 89, 227, 79, - 82, 8, 242, 166, 28, 65, 154, 206, 5, 79, 203, 17, 73, 4, 162, 134, 34, - 87, 3, 89, 8, 42, 90, 222, 187, 32, 89, 215, 173, 1, 65, 4, 214, 249, 32, - 89, 191, 122, 65, 4, 218, 181, 33, 89, 227, 79, 66, 4, 136, 217, 32, 2, - 72, 69, 187, 155, 1, 73, 6, 138, 201, 32, 82, 134, 108, 87, 135, 77, 78, - 4, 146, 248, 32, 72, 199, 14, 65, 4, 130, 134, 33, 73, 199, 69, 65, 4, - 162, 180, 33, 65, 171, 51, 89, 4, 142, 1, 73, 247, 178, 33, 69, 8, 34, - 72, 137, 128, 34, 2, 69, 89, 6, 182, 151, 20, 65, 163, 218, 13, 79, 6, - 38, 73, 210, 246, 32, 89, 171, 78, 65, 2, 247, 201, 33, 87, 4, 156, 188, - 33, 2, 65, 89, 1, 2, 79, 87, 6, 130, 147, 16, 72, 219, 185, 4, 65, 16, - 72, 2, 68, 73, 32, 2, 78, 84, 212, 156, 32, 3, 76, 84, 73, 187, 80, 82, - 4, 174, 250, 32, 32, 223, 100, 76, 8, 32, 2, 82, 69, 239, 249, 32, 32, 6, - 44, 5, 76, 73, 78, 69, 32, 147, 226, 4, 32, 4, 178, 214, 21, 76, 155, - 194, 10, 79, 252, 5, 102, 65, 170, 17, 69, 134, 8, 73, 150, 1, 79, 244, - 191, 13, 6, 82, 73, 83, 84, 77, 65, 139, 130, 10, 85, 198, 2, 66, 73, 32, - 4, 75, 77, 65, 32, 148, 6, 2, 77, 32, 131, 8, 82, 4, 250, 192, 33, 78, - 223, 61, 82, 142, 1, 156, 1, 7, 76, 69, 84, 84, 69, 82, 32, 142, 3, 83, - 98, 86, 214, 202, 23, 68, 194, 221, 7, 81, 200, 94, 5, 77, 65, 65, 89, - 89, 136, 177, 1, 2, 65, 85, 3, 79, 76, 202, 1, 68, 54, 78, 54, 84, 54, - 89, 166, 250, 28, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 76, 2, 80, 190, 141, - 3, 72, 2, 77, 2, 82, 2, 83, 2, 86, 2, 87, 150, 240, 1, 65, 186, 2, 69, 2, - 73, 3, 85, 8, 190, 251, 28, 68, 190, 141, 3, 72, 151, 240, 1, 65, 8, 198, - 136, 32, 71, 2, 78, 2, 89, 151, 240, 1, 65, 8, 214, 250, 28, 84, 190, - 141, 3, 72, 151, 240, 1, 65, 4, 222, 135, 32, 89, 151, 240, 1, 65, 8, 40, - 4, 73, 71, 78, 32, 155, 249, 21, 69, 6, 154, 229, 29, 67, 154, 222, 1, - 86, 179, 241, 1, 65, 26, 64, 10, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, - 143, 192, 31, 73, 24, 194, 158, 30, 65, 250, 6, 85, 206, 201, 1, 69, 2, - 73, 3, 79, 166, 1, 236, 1, 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, - 83, 73, 71, 78, 32, 112, 7, 76, 69, 84, 84, 69, 82, 32, 152, 4, 12, 80, - 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 60, 11, 86, 79, 87, 69, 76, - 32, 83, 73, 71, 78, 32, 207, 255, 31, 68, 14, 72, 6, 70, 73, 78, 65, 76, - 32, 174, 243, 33, 76, 2, 82, 2, 87, 3, 89, 6, 142, 245, 33, 78, 86, 72, - 3, 77, 104, 132, 2, 6, 70, 73, 78, 65, 76, 32, 110, 78, 50, 77, 78, 80, - 226, 215, 11, 66, 138, 135, 6, 68, 206, 134, 12, 83, 194, 130, 2, 65, - 156, 194, 1, 2, 67, 72, 2, 71, 2, 74, 2, 75, 2, 84, 138, 69, 72, 2, 76, - 2, 82, 2, 86, 2, 89, 186, 2, 69, 2, 73, 2, 79, 3, 85, 22, 158, 248, 31, - 78, 190, 189, 1, 83, 206, 60, 67, 146, 1, 71, 2, 75, 2, 76, 2, 80, 2, 82, - 2, 84, 3, 89, 14, 46, 71, 34, 72, 170, 219, 33, 85, 215, 22, 65, 4, 198, - 219, 33, 85, 215, 22, 65, 6, 166, 219, 33, 85, 158, 20, 74, 187, 2, 65, - 6, 150, 239, 33, 72, 2, 80, 187, 2, 65, 8, 246, 156, 11, 83, 186, 247, - 18, 68, 45, 4, 84, 82, 73, 80, 20, 158, 157, 30, 65, 242, 201, 1, 73, - 190, 201, 1, 79, 2, 85, 203, 44, 69, 14, 72, 7, 65, 67, 84, 69, 82, 32, - 84, 49, 7, 84, 32, 87, 73, 84, 72, 32, 8, 240, 242, 9, 3, 65, 66, 85, - 147, 230, 23, 73, 6, 128, 1, 13, 85, 80, 87, 65, 82, 68, 83, 32, 84, 82, - 69, 78, 68, 217, 160, 25, 12, 68, 79, 87, 78, 87, 65, 82, 68, 83, 32, 84, - 82, 5, 225, 242, 6, 6, 32, 65, 78, 68, 32, 89, 234, 2, 80, 2, 67, 75, 82, - 69, 90, 82, 156, 247, 4, 2, 83, 84, 229, 151, 15, 2, 81, 85, 6, 56, 8, - 69, 82, 32, 66, 79, 65, 82, 68, 175, 171, 33, 32, 5, 211, 244, 30, 32, 4, - 140, 177, 27, 4, 83, 69, 32, 87, 229, 144, 5, 9, 82, 73, 78, 71, 32, 77, - 69, 71, 65, 220, 2, 40, 5, 79, 75, 69, 69, 32, 143, 5, 82, 216, 2, 46, + 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 4, 178, 239, 36, 78, 87, 72, 76, + 194, 1, 77, 114, 78, 68, 2, 80, 65, 38, 83, 192, 248, 18, 4, 75, 65, 82, + 79, 218, 241, 17, 66, 2, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 76, 2, 82, 2, + 87, 2, 89, 186, 2, 65, 2, 73, 3, 85, 10, 26, 65, 215, 235, 36, 66, 9, 45, + 9, 78, 68, 65, 73, 76, 73, 78, 71, 32, 6, 162, 235, 36, 72, 2, 78, 3, 83, + 10, 152, 2, 2, 79, 82, 230, 232, 36, 68, 2, 71, 2, 89, 187, 2, 65, 5, + 221, 142, 21, 4, 75, 80, 65, 75, 24, 80, 10, 73, 77, 65, 76, 85, 78, 71, + 85, 78, 32, 96, 2, 79, 85, 159, 235, 36, 65, 20, 194, 233, 36, 71, 2, 72, + 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 87, 2, 89, 187, 2, 65, 2, 233, 248, + 18, 5, 84, 72, 69, 82, 78, 4, 166, 2, 71, 249, 248, 18, 4, 79, 78, 71, + 79, 10, 96, 12, 89, 77, 66, 79, 76, 32, 66, 73, 78, 68, 85, 32, 189, 198, + 10, 6, 73, 71, 78, 32, 84, 79, 8, 78, 80, 220, 177, 11, 3, 74, 85, 68, + 145, 180, 25, 6, 78, 65, 32, 77, 69, 84, 4, 64, 3, 65, 78, 71, 249, 182, + 23, 7, 73, 78, 65, 82, 66, 79, 82, 2, 131, 255, 25, 79, 18, 122, 85, 136, + 175, 26, 6, 80, 65, 75, 80, 65, 75, 152, 254, 2, 5, 75, 65, 82, 79, 32, + 254, 249, 6, 69, 162, 64, 73, 3, 79, 5, 249, 218, 30, 15, 32, 70, 79, 82, + 32, 83, 73, 77, 65, 76, 85, 78, 71, 85, 78, 5, 235, 245, 23, 84, 228, 2, + 182, 1, 65, 230, 2, 69, 50, 76, 146, 1, 78, 188, 10, 9, 82, 73, 65, 32, + 69, 82, 70, 69, 32, 186, 5, 84, 228, 136, 33, 2, 67, 65, 176, 185, 2, 5, + 86, 69, 82, 65, 71, 243, 142, 1, 68, 20, 136, 1, 4, 77, 69, 68, 32, 170, + 1, 82, 140, 176, 3, 10, 67, 72, 32, 87, 73, 84, 72, 32, 85, 77, 194, 169, + 7, 84, 178, 203, 25, 86, 19, 78, 8, 86, 65, 0, 2, 68, 69, 52, 4, 69, 73, + 71, 72, 1, 7, 83, 73, 88, 84, 69, 69, 78, 2, 169, 190, 20, 8, 83, 67, 69, + 78, 68, 73, 78, 71, 2, 161, 190, 20, 2, 84, 72, 4, 168, 222, 32, 3, 68, + 69, 68, 171, 199, 3, 32, 4, 152, 209, 8, 3, 82, 32, 77, 227, 234, 26, 84, + 15, 11, 76, 13, 54, 32, 200, 182, 25, 3, 72, 79, 80, 231, 236, 9, 79, 6, + 162, 204, 12, 80, 236, 172, 16, 6, 87, 73, 84, 72, 32, 67, 139, 211, 6, + 83, 208, 1, 84, 5, 71, 65, 76, 73, 32, 158, 9, 84, 37, 9, 90, 69, 78, 69, + 32, 82, 73, 78, 71, 200, 1, 210, 1, 65, 40, 9, 67, 85, 82, 82, 69, 78, + 67, 89, 32, 148, 2, 7, 76, 69, 84, 84, 69, 82, 32, 204, 3, 6, 82, 85, 80, + 69, 69, 32, 34, 83, 246, 239, 22, 73, 134, 4, 86, 158, 240, 11, 68, 225, + 110, 3, 71, 65, 78, 6, 138, 190, 32, 66, 50, 78, 135, 63, 85, 12, 120, + 10, 78, 85, 77, 69, 82, 65, 84, 79, 82, 32, 153, 196, 23, 14, 68, 69, 78, + 79, 77, 73, 78, 65, 84, 79, 82, 32, 83, 73, 10, 52, 3, 79, 78, 69, 158, + 193, 31, 70, 135, 169, 3, 84, 5, 173, 208, 29, 19, 32, 76, 69, 83, 83, + 32, 84, 72, 65, 78, 32, 84, 72, 69, 32, 68, 69, 78, 79, 108, 226, 1, 75, + 90, 82, 238, 209, 21, 86, 190, 143, 8, 89, 178, 154, 3, 65, 38, 68, 114, + 84, 230, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, 46, 83, 82, 66, 2, 67, + 2, 71, 2, 74, 2, 80, 138, 69, 72, 2, 76, 2, 77, 186, 2, 69, 3, 79, 8, 26, + 72, 139, 218, 36, 65, 6, 26, 65, 215, 145, 14, 73, 5, 185, 231, 18, 3, + 78, 68, 65, 10, 34, 65, 242, 214, 36, 72, 3, 82, 7, 33, 6, 32, 87, 73, + 84, 72, 32, 4, 232, 174, 25, 5, 76, 79, 87, 69, 82, 1, 6, 77, 73, 68, 68, + 76, 69, 4, 210, 209, 35, 83, 191, 69, 77, 20, 116, 19, 69, 81, 85, 69, + 78, 67, 69, 32, 70, 79, 82, 32, 76, 69, 84, 84, 69, 82, 32, 158, 154, 26, + 65, 227, 158, 6, 73, 6, 154, 242, 22, 82, 175, 226, 13, 89, 4, 134, 174, + 26, 32, 151, 154, 9, 79, 5, 197, 220, 33, 3, 32, 87, 73, 100, 56, 6, 67, + 65, 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 50, 45, 9, 76, 32, 76, 69, 84, + 84, 69, 82, 32, 50, 182, 2, 65, 50, 68, 42, 69, 82, 71, 38, 78, 38, 83, + 154, 143, 17, 77, 136, 235, 1, 6, 72, 73, 82, 68, 69, 65, 0, 2, 75, 79, + 172, 199, 13, 6, 84, 65, 84, 65, 83, 79, 196, 209, 2, 5, 66, 65, 83, 73, + 71, 244, 50, 3, 87, 65, 83, 164, 108, 3, 70, 73, 84, 0, 3, 76, 65, 75, + 170, 11, 79, 2, 80, 2, 85, 219, 19, 73, 4, 26, 82, 255, 210, 36, 89, 2, + 215, 157, 23, 75, 4, 160, 223, 31, 3, 65, 82, 66, 3, 74, 6, 40, 4, 82, + 73, 71, 79, 151, 210, 36, 72, 5, 245, 184, 20, 4, 32, 84, 65, 77, 4, 158, + 243, 29, 79, 155, 220, 6, 78, 4, 242, 204, 31, 73, 187, 246, 3, 71, 4, + 194, 175, 26, 72, 155, 182, 3, 69, 4, 242, 250, 34, 87, 219, 64, 32, 194, + 1, 184, 2, 7, 76, 69, 84, 84, 69, 82, 32, 244, 1, 7, 78, 85, 77, 66, 69, + 82, 32, 72, 5, 83, 73, 71, 78, 32, 48, 11, 86, 79, 87, 69, 76, 32, 83, + 73, 71, 78, 32, 190, 138, 26, 68, 198, 247, 3, 87, 208, 195, 2, 10, 71, + 65, 80, 32, 70, 73, 76, 76, 69, 82, 161, 187, 3, 12, 72, 85, 78, 68, 82, + 69, 68, 83, 32, 85, 78, 73, 92, 210, 1, 86, 222, 238, 32, 65, 38, 68, + 114, 84, 230, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, 46, 83, 82, 66, 2, + 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 89, + 186, 2, 69, 3, 79, 8, 234, 1, 79, 231, 202, 36, 65, 36, 142, 126, 69, 38, + 70, 66, 78, 26, 83, 182, 193, 21, 84, 195, 240, 12, 79, 10, 134, 174, 32, + 67, 158, 67, 65, 187, 151, 3, 86, 24, 80, 2, 86, 79, 198, 243, 32, 65, + 38, 85, 186, 202, 1, 73, 198, 140, 2, 69, 3, 79, 6, 33, 6, 67, 65, 76, + 73, 67, 32, 6, 162, 244, 32, 82, 159, 214, 3, 76, 26, 148, 1, 4, 67, 89, + 67, 76, 36, 2, 71, 32, 28, 2, 76, 76, 46, 82, 66, 84, 224, 186, 19, 4, + 79, 72, 65, 90, 160, 136, 12, 2, 75, 73, 239, 180, 4, 83, 4, 142, 219, + 32, 73, 247, 237, 3, 69, 4, 174, 175, 34, 82, 67, 83, 4, 164, 228, 9, 2, + 69, 68, 131, 131, 24, 73, 4, 236, 219, 32, 7, 84, 72, 68, 65, 89, 32, 67, + 171, 236, 3, 68, 4, 244, 224, 13, 2, 67, 79, 169, 229, 22, 4, 73, 78, 71, + 32, 196, 7, 42, 65, 174, 33, 79, 165, 11, 2, 85, 69, 246, 2, 32, 2, 67, + 75, 207, 128, 18, 78, 244, 2, 22, 32, 223, 31, 45, 228, 2, 210, 1, 67, + 254, 4, 68, 174, 2, 70, 102, 72, 82, 76, 186, 4, 77, 250, 2, 78, 38, 80, + 46, 82, 150, 4, 83, 154, 4, 84, 82, 85, 248, 2, 3, 86, 69, 82, 210, 141, + 12, 79, 164, 228, 20, 3, 66, 79, 87, 187, 249, 1, 81, 102, 196, 1, 5, 73, + 82, 67, 76, 69, 200, 1, 6, 85, 82, 86, 69, 68, 32, 244, 145, 26, 12, 82, + 79, 83, 83, 32, 79, 78, 32, 83, 72, 73, 69, 248, 161, 3, 5, 69, 78, 84, + 82, 69, 254, 172, 5, 72, 159, 14, 76, 11, 11, 32, 8, 72, 5, 87, 73, 84, + 72, 32, 189, 250, 16, 7, 70, 79, 82, 32, 82, 69, 67, 6, 140, 69, 8, 87, + 72, 73, 84, 69, 32, 68, 79, 218, 134, 19, 68, 181, 146, 2, 8, 84, 87, 79, + 32, 87, 72, 73, 84, 16, 84, 4, 68, 79, 87, 78, 0, 2, 85, 80, 56, 3, 76, + 69, 70, 1, 4, 82, 73, 71, 72, 4, 153, 155, 32, 9, 87, 65, 82, 68, 83, 32, + 65, 78, 68, 4, 53, 11, 84, 87, 65, 82, 68, 83, 32, 65, 78, 68, 32, 4, + 194, 163, 21, 85, 203, 170, 12, 68, 30, 64, 6, 73, 65, 77, 79, 78, 68, + 152, 1, 3, 79, 87, 78, 43, 82, 13, 11, 32, 10, 154, 19, 67, 172, 136, 13, + 10, 77, 73, 78, 85, 83, 32, 87, 72, 73, 84, 244, 172, 6, 6, 87, 73, 84, + 72, 32, 68, 254, 178, 15, 79, 135, 13, 83, 12, 214, 19, 32, 62, 45, 151, + 199, 31, 87, 6, 196, 219, 34, 2, 79, 80, 179, 21, 65, 8, 18, 76, 39, 79, + 4, 142, 132, 28, 79, 179, 184, 8, 65, 4, 184, 219, 2, 2, 85, 82, 223, + 189, 31, 76, 12, 38, 69, 158, 244, 34, 65, 251, 2, 79, 6, 228, 245, 34, + 2, 65, 82, 247, 11, 88, 40, 64, 5, 65, 82, 71, 69, 32, 140, 2, 3, 69, 70, + 84, 203, 1, 79, 12, 48, 6, 67, 73, 82, 67, 76, 69, 159, 152, 35, 83, 11, + 37, 7, 32, 77, 73, 78, 85, 83, 32, 8, 54, 76, 36, 4, 82, 73, 71, 72, 13, + 3, 85, 80, 80, 4, 32, 2, 69, 70, 13, 2, 79, 87, 2, 31, 84, 2, 17, 2, 69, + 82, 2, 177, 183, 33, 8, 32, 81, 85, 65, 82, 84, 69, 82, 22, 96, 10, 45, + 80, 79, 73, 78, 84, 73, 78, 71, 32, 64, 6, 87, 65, 82, 68, 83, 32, 175, + 245, 34, 32, 12, 146, 7, 68, 190, 8, 73, 130, 233, 34, 80, 206, 24, 83, + 51, 84, 4, 250, 200, 33, 69, 231, 140, 1, 66, 6, 158, 15, 87, 243, 240, + 34, 90, 30, 76, 6, 69, 68, 73, 85, 77, 32, 153, 243, 21, 7, 79, 79, 78, + 32, 76, 73, 76, 28, 66, 68, 42, 76, 36, 4, 82, 73, 71, 72, 12, 2, 85, 80, + 111, 83, 6, 84, 3, 79, 87, 78, 231, 246, 34, 73, 6, 32, 2, 69, 70, 135, + 254, 34, 79, 4, 11, 84, 4, 81, 18, 45, 80, 79, 73, 78, 84, 73, 78, 71, + 32, 84, 82, 73, 65, 78, 71, 76, 69, 5, 145, 9, 2, 32, 67, 8, 198, 13, 77, + 203, 132, 35, 81, 4, 194, 165, 17, 69, 139, 209, 17, 73, 8, 234, 156, 25, + 85, 230, 217, 9, 65, 87, 69, 34, 52, 4, 73, 71, 72, 84, 238, 161, 34, 79, + 239, 85, 69, 30, 94, 32, 84, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, + 245, 1, 6, 87, 65, 82, 68, 83, 32, 6, 60, 9, 84, 82, 73, 65, 78, 71, 76, + 69, 32, 239, 136, 35, 80, 2, 243, 210, 6, 67, 16, 90, 68, 88, 8, 84, 82, + 73, 65, 78, 71, 76, 69, 230, 7, 73, 134, 238, 34, 80, 203, 19, 83, 4, 65, + 14, 79, 85, 66, 76, 69, 32, 84, 82, 73, 65, 78, 71, 76, 69, 5, 227, 202, + 12, 32, 5, 241, 249, 20, 11, 32, 87, 73, 84, 72, 32, 68, 79, 85, 66, 76, + 8, 250, 178, 19, 65, 150, 142, 14, 69, 231, 140, 1, 66, 40, 158, 2, 77, + 148, 1, 5, 81, 85, 65, 82, 69, 128, 150, 26, 3, 85, 78, 32, 160, 224, 1, + 5, 75, 85, 76, 76, 32, 228, 183, 3, 3, 78, 79, 87, 168, 228, 1, 5, 65, + 70, 69, 84, 89, 184, 131, 1, 13, 76, 73, 71, 72, 84, 76, 89, 32, 83, 77, + 65, 76, 76, 198, 93, 67, 50, 72, 222, 1, 80, 191, 19, 84, 12, 40, 4, 65, + 76, 76, 32, 143, 246, 34, 73, 10, 154, 238, 34, 68, 150, 7, 76, 70, 83, + 213, 15, 13, 85, 80, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 67, 9, 11, + 32, 6, 54, 67, 216, 214, 33, 3, 70, 79, 82, 223, 159, 1, 66, 2, 193, 151, + 31, 3, 69, 78, 84, 14, 192, 4, 3, 73, 78, 89, 162, 195, 23, 82, 174, 182, + 11, 79, 54, 69, 135, 2, 87, 18, 38, 80, 233, 249, 32, 3, 78, 73, 86, 16, + 46, 32, 62, 45, 170, 1, 80, 239, 197, 31, 87, 2, 173, 129, 35, 10, 80, + 79, 73, 78, 84, 73, 78, 71, 32, 66, 8, 45, 9, 80, 79, 73, 78, 84, 73, 78, + 71, 32, 8, 66, 73, 224, 253, 34, 5, 68, 79, 85, 66, 76, 238, 3, 83, 51, + 84, 2, 217, 254, 33, 8, 83, 79, 83, 67, 69, 76, 69, 83, 4, 21, 3, 69, 82, + 32, 4, 130, 204, 24, 76, 163, 178, 9, 82, 10, 56, 6, 84, 73, 67, 65, 76, + 32, 41, 4, 89, 32, 83, 77, 4, 220, 235, 34, 2, 82, 69, 235, 22, 69, 6, + 21, 3, 65, 76, 76, 6, 11, 32, 6, 254, 231, 34, 68, 150, 7, 76, 135, 21, + 83, 16, 84, 15, 76, 69, 84, 84, 69, 82, 32, 67, 65, 80, 73, 84, 65, 76, + 32, 171, 159, 11, 70, 10, 242, 165, 36, 67, 2, 72, 2, 73, 2, 82, 3, 90, + 200, 4, 52, 3, 67, 75, 32, 186, 151, 2, 83, 219, 214, 10, 87, 196, 4, 80, + 7, 79, 67, 84, 65, 78, 84, 45, 149, 7, 8, 83, 69, 88, 84, 65, 78, 84, 45, + 204, 3, 58, 49, 130, 3, 50, 114, 53, 50, 54, 18, 51, 215, 1, 52, 234, 1, + 74, 50, 246, 1, 51, 174, 91, 52, 46, 53, 38, 54, 30, 55, 147, 197, 35, + 56, 116, 62, 51, 226, 92, 52, 46, 53, 38, 54, 30, 55, 147, 197, 35, 56, + 55, 54, 52, 214, 92, 53, 38, 54, 30, 55, 147, 197, 35, 56, 22, 50, 53, + 166, 2, 54, 190, 90, 55, 147, 197, 35, 56, 11, 42, 54, 150, 246, 28, 55, + 179, 171, 7, 56, 4, 194, 161, 36, 55, 3, 56, 56, 170, 1, 53, 50, 54, 210, + 89, 52, 110, 55, 147, 197, 35, 56, 118, 62, 52, 254, 89, 51, 98, 53, 38, + 54, 30, 55, 147, 197, 35, 56, 24, 46, 53, 50, 54, 190, 90, 55, 147, 197, + 35, 56, 13, 206, 1, 54, 254, 242, 28, 55, 179, 171, 7, 56, 7, 187, 90, + 55, 61, 54, 52, 118, 53, 230, 88, 54, 30, 55, 147, 197, 35, 56, 31, 46, + 53, 170, 89, 54, 30, 55, 147, 197, 35, 56, 15, 38, 54, 158, 89, 55, 147, + 197, 35, 56, 7, 170, 158, 36, 55, 3, 56, 14, 226, 88, 54, 30, 55, 147, + 197, 35, 56, 31, 46, 54, 234, 87, 53, 66, 55, 147, 197, 35, 56, 6, 166, + 88, 55, 147, 197, 35, 56, 120, 70, 49, 238, 1, 50, 238, 209, 25, 51, 38, + 52, 30, 53, 187, 200, 10, 54, 61, 58, 50, 126, 51, 198, 210, 25, 52, 30, + 53, 187, 200, 10, 54, 31, 50, 51, 142, 211, 25, 52, 30, 53, 187, 200, 10, + 54, 15, 42, 52, 254, 210, 25, 53, 187, 200, 10, 54, 7, 178, 155, 36, 53, + 3, 54, 15, 194, 210, 25, 52, 186, 157, 3, 53, 159, 171, 7, 54, 31, 50, + 52, 186, 209, 25, 51, 66, 53, 187, 200, 10, 54, 7, 247, 209, 25, 53, 6, + 226, 173, 22, 32, 213, 206, 8, 4, 66, 69, 82, 82, 232, 4, 200, 1, 3, 76, + 68, 32, 78, 79, 104, 7, 80, 79, 77, 79, 70, 79, 32, 188, 6, 2, 84, 84, + 216, 6, 5, 85, 81, 85, 69, 84, 54, 87, 198, 1, 88, 182, 221, 5, 77, 146, + 175, 3, 89, 186, 194, 26, 65, 139, 34, 78, 14, 190, 197, 8, 83, 190, 212, + 7, 69, 202, 228, 17, 70, 234, 2, 87, 203, 11, 71, 10, 26, 75, 135, 165, + 23, 77, 9, 40, 4, 77, 65, 82, 75, 135, 151, 36, 83, 5, 189, 191, 23, 3, + 32, 84, 65, 150, 1, 96, 13, 70, 73, 78, 65, 76, 32, 76, 69, 84, 84, 69, + 82, 32, 53, 7, 76, 69, 84, 84, 69, 82, 32, 10, 250, 149, 36, 71, 2, 72, + 2, 75, 2, 80, 3, 84, 140, 1, 234, 1, 65, 54, 85, 22, 69, 82, 71, 46, 73, + 70, 78, 38, 79, 98, 90, 190, 160, 7, 75, 178, 223, 24, 67, 2, 76, 2, 83, + 230, 57, 66, 186, 202, 1, 74, 198, 140, 2, 68, 2, 70, 2, 72, 2, 77, 2, + 80, 2, 81, 2, 82, 2, 84, 2, 86, 3, 88, 21, 50, 73, 2, 85, 74, 78, 222, + 146, 36, 72, 3, 77, 5, 195, 195, 35, 78, 17, 50, 78, 222, 146, 36, 69, 2, + 72, 2, 73, 3, 82, 7, 218, 146, 36, 71, 3, 78, 11, 190, 146, 36, 72, 2, + 78, 2, 85, 3, 87, 15, 164, 148, 34, 2, 78, 78, 238, 253, 1, 72, 2, 77, 2, + 82, 3, 85, 9, 206, 147, 34, 71, 131, 254, 1, 78, 17, 66, 78, 230, 143, + 35, 32, 134, 129, 1, 69, 2, 77, 2, 79, 3, 85, 4, 230, 144, 36, 71, 3, 78, + 9, 202, 144, 36, 72, 2, 73, 3, 89, 66, 104, 3, 79, 77, 32, 221, 199, 21, + 17, 76, 69, 32, 87, 73, 84, 72, 32, 80, 79, 80, 80, 73, 78, 71, 32, 67, + 64, 152, 2, 5, 72, 65, 76, 70, 32, 232, 1, 5, 76, 69, 70, 84, 32, 88, 6, + 82, 73, 71, 72, 84, 32, 88, 14, 83, 81, 85, 65, 82, 69, 32, 66, 82, 65, + 67, 75, 69, 84, 210, 228, 15, 65, 226, 154, 16, 67, 210, 3, 80, 140, 3, + 13, 74, 85, 83, 84, 73, 70, 73, 69, 68, 32, 85, 80, 80, 135, 5, 84, 32, + 148, 1, 16, 70, 79, 82, 87, 65, 82, 68, 45, 70, 65, 67, 73, 78, 71, 32, + 82, 134, 132, 32, 76, 22, 82, 252, 2, 2, 83, 84, 174, 5, 66, 211, 245, 1, + 73, 10, 196, 179, 29, 11, 85, 78, 78, 69, 82, 32, 70, 82, 65, 77, 69, + 155, 210, 2, 79, 8, 196, 137, 32, 13, 74, 85, 83, 84, 73, 70, 73, 69, 68, + 32, 85, 80, 80, 126, 67, 51, 72, 8, 234, 137, 32, 67, 50, 72, 33, 13, 74, + 85, 83, 84, 73, 70, 73, 69, 68, 32, 85, 80, 80, 5, 129, 236, 23, 9, 32, + 79, 86, 69, 82, 32, 84, 79, 80, 5, 209, 248, 34, 8, 32, 79, 70, 32, 70, + 76, 79, 87, 14, 58, 76, 116, 3, 84, 73, 69, 149, 170, 33, 3, 32, 65, 78, + 6, 26, 32, 207, 183, 35, 73, 4, 224, 195, 9, 7, 79, 70, 32, 72, 89, 71, + 73, 173, 154, 23, 6, 87, 73, 84, 72, 32, 83, 7, 211, 231, 32, 32, 218, 2, + 88, 10, 32, 68, 82, 65, 87, 73, 78, 71, 83, 32, 153, 138, 35, 6, 73, 78, + 71, 32, 71, 76, 216, 2, 176, 1, 2, 68, 79, 228, 6, 6, 72, 69, 65, 86, 89, + 32, 254, 2, 76, 204, 25, 6, 82, 73, 71, 72, 84, 32, 144, 4, 3, 85, 80, + 32, 245, 3, 9, 86, 69, 82, 84, 73, 67, 65, 76, 32, 66, 52, 5, 85, 66, 76, + 69, 32, 165, 3, 3, 87, 78, 32, 30, 58, 68, 216, 2, 2, 85, 80, 234, 5, 86, + 203, 188, 29, 72, 14, 64, 8, 73, 65, 71, 79, 78, 65, 76, 32, 149, 2, 3, + 79, 87, 78, 8, 104, 6, 85, 80, 80, 69, 82, 32, 205, 14, 15, 76, 79, 87, + 69, 82, 32, 76, 69, 70, 84, 32, 84, 79, 32, 77, 6, 76, 8, 76, 69, 70, 84, + 32, 84, 79, 32, 237, 24, 6, 82, 73, 71, 72, 84, 32, 4, 204, 23, 14, 77, + 73, 68, 68, 76, 69, 32, 67, 69, 78, 84, 82, 69, 32, 191, 194, 23, 76, 6, + 199, 26, 32, 36, 128, 1, 10, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 132, + 1, 10, 76, 73, 71, 72, 84, 32, 65, 78, 68, 32, 210, 38, 68, 131, 4, 83, + 12, 76, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 228, 35, 2, 85, 80, 151, 5, + 72, 4, 17, 2, 84, 32, 4, 230, 32, 85, 199, 180, 35, 76, 12, 76, 3, 76, + 69, 70, 0, 4, 82, 73, 71, 72, 156, 36, 2, 85, 80, 235, 4, 72, 4, 17, 2, + 84, 32, 4, 198, 32, 85, 135, 9, 72, 46, 136, 1, 4, 76, 69, 70, 84, 68, 2, + 85, 80, 130, 1, 86, 172, 20, 2, 68, 79, 170, 2, 81, 100, 2, 84, 82, 146, + 165, 29, 72, 247, 148, 6, 82, 5, 45, 9, 32, 65, 78, 68, 32, 76, 73, 71, + 72, 2, 255, 169, 34, 84, 11, 29, 5, 32, 65, 78, 68, 32, 8, 42, 76, 254, + 188, 29, 72, 247, 148, 6, 82, 4, 220, 195, 24, 4, 73, 71, 72, 84, 131, + 142, 11, 69, 8, 209, 20, 7, 69, 82, 84, 73, 67, 65, 76, 156, 1, 56, 4, + 69, 70, 84, 32, 169, 2, 5, 73, 71, 72, 84, 32, 16, 160, 27, 19, 68, 79, + 87, 78, 32, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 82, 73, 71, 72, 24, + 14, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 82, 73, 71, 72, 100, 14, 76, + 73, 71, 72, 84, 32, 65, 78, 68, 32, 82, 73, 71, 72, 97, 17, 85, 80, 32, + 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 82, 73, 71, 72, 140, 1, 248, 1, + 4, 65, 82, 67, 32, 30, 68, 248, 15, 10, 72, 79, 82, 73, 90, 79, 78, 84, + 65, 76, 112, 4, 76, 69, 70, 84, 62, 81, 34, 84, 172, 1, 2, 85, 80, 120, + 8, 86, 69, 82, 84, 73, 67, 65, 76, 156, 211, 13, 7, 66, 79, 84, 84, 79, + 77, 32, 139, 229, 21, 82, 8, 166, 222, 17, 68, 67, 85, 80, 52, 8, 73, 65, + 71, 79, 78, 65, 76, 32, 199, 14, 79, 68, 168, 1, 14, 76, 79, 87, 69, 82, + 32, 76, 69, 70, 84, 32, 84, 79, 32, 96, 7, 77, 73, 68, 68, 76, 69, 32, + 136, 3, 6, 85, 80, 80, 69, 82, 32, 230, 173, 34, 67, 183, 4, 68, 4, 38, + 77, 33, 5, 85, 80, 80, 69, 82, 2, 29, 5, 73, 68, 68, 76, 69, 2, 129, 12, + 2, 32, 67, 16, 88, 8, 76, 69, 70, 84, 32, 84, 79, 32, 213, 1, 9, 82, 73, + 71, 72, 84, 32, 84, 79, 32, 10, 156, 1, 6, 76, 79, 87, 69, 82, 32, 33, + 28, 85, 80, 80, 69, 82, 32, 67, 69, 78, 84, 82, 69, 32, 84, 79, 32, 77, + 73, 68, 68, 76, 69, 32, 82, 73, 71, 72, 84, 6, 246, 3, 67, 215, 195, 35, + 82, 5, 171, 211, 20, 32, 6, 232, 4, 15, 85, 80, 80, 69, 82, 32, 67, 69, + 78, 84, 82, 69, 32, 84, 79, 235, 3, 76, 44, 144, 1, 10, 67, 69, 78, 84, + 82, 69, 32, 84, 79, 32, 248, 3, 8, 76, 69, 70, 84, 32, 84, 79, 32, 193, + 2, 9, 82, 73, 71, 72, 84, 32, 84, 79, 32, 20, 52, 7, 77, 73, 68, 68, 76, + 69, 32, 203, 197, 23, 76, 16, 56, 4, 76, 69, 70, 84, 165, 1, 5, 82, 73, + 71, 72, 84, 9, 11, 32, 6, 84, 10, 84, 79, 32, 76, 79, 87, 69, 82, 32, 67, + 141, 207, 20, 5, 65, 78, 68, 32, 77, 4, 29, 5, 69, 78, 84, 82, 69, 5, + 137, 232, 32, 3, 32, 84, 79, 9, 11, 32, 6, 88, 3, 65, 78, 68, 65, 15, 84, + 79, 32, 76, 79, 87, 69, 82, 32, 67, 69, 78, 84, 82, 69, 2, 149, 206, 20, + 11, 32, 77, 73, 68, 68, 76, 69, 32, 76, 69, 70, 5, 133, 224, 10, 9, 32, + 84, 79, 32, 77, 73, 68, 68, 76, 14, 68, 6, 76, 79, 87, 69, 82, 32, 97, 7, + 77, 73, 68, 68, 76, 69, 32, 6, 48, 6, 67, 69, 78, 84, 82, 69, 187, 192, + 35, 82, 5, 11, 32, 2, 233, 4, 4, 84, 79, 32, 85, 8, 76, 10, 67, 69, 78, + 84, 82, 69, 32, 84, 79, 32, 33, 5, 82, 73, 71, 72, 84, 4, 250, 3, 85, + 231, 214, 13, 76, 5, 11, 32, 2, 157, 218, 13, 2, 84, 79, 10, 46, 76, 69, + 7, 77, 73, 68, 68, 76, 69, 32, 4, 29, 5, 79, 87, 69, 82, 32, 4, 202, 227, + 32, 67, 191, 218, 2, 76, 6, 34, 67, 37, 4, 76, 69, 70, 84, 2, 45, 6, 69, + 78, 84, 82, 69, 32, 5, 11, 32, 2, 165, 191, 23, 2, 84, 79, 12, 36, 2, 87, + 78, 253, 2, 2, 85, 66, 9, 11, 32, 6, 25, 4, 65, 78, 68, 32, 6, 202, 167, + 29, 72, 218, 148, 6, 76, 31, 82, 9, 11, 32, 6, 40, 4, 65, 78, 68, 32, + 187, 181, 35, 87, 4, 26, 85, 211, 189, 23, 76, 2, 225, 189, 23, 2, 80, + 80, 5, 209, 146, 34, 10, 32, 65, 78, 68, 32, 72, 69, 65, 86, 89, 4, 109, + 5, 85, 65, 68, 82, 85, 6, 66, 82, 189, 213, 13, 10, 79, 80, 32, 65, 78, + 68, 32, 85, 80, 80, 4, 11, 73, 4, 11, 80, 4, 41, 8, 76, 69, 32, 68, 65, + 83, 72, 32, 4, 166, 193, 16, 86, 167, 227, 12, 72, 11, 29, 5, 32, 65, 78, + 68, 32, 8, 34, 72, 190, 184, 35, 76, 31, 82, 4, 196, 170, 24, 4, 69, 65, + 86, 89, 171, 249, 4, 79, 17, 29, 5, 32, 65, 78, 68, 32, 14, 230, 168, 28, + 66, 42, 84, 130, 122, 72, 218, 148, 6, 76, 31, 82, 16, 148, 2, 18, 68, + 79, 87, 78, 32, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 76, 69, 70, 24, + 13, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 76, 69, 70, 100, 13, 76, 73, + 71, 72, 84, 32, 65, 78, 68, 32, 76, 69, 70, 97, 16, 85, 80, 32, 72, 69, + 65, 86, 89, 32, 65, 78, 68, 32, 76, 69, 70, 2, 101, 3, 84, 32, 85, 6, 17, + 2, 84, 32, 6, 58, 85, 178, 3, 68, 245, 4, 6, 86, 69, 82, 84, 73, 67, 2, + 179, 194, 33, 80, 6, 17, 2, 84, 32, 6, 58, 85, 134, 4, 68, 205, 4, 6, 86, + 69, 82, 84, 73, 67, 2, 239, 8, 80, 2, 185, 2, 3, 84, 32, 68, 36, 128, 1, + 10, 72, 69, 65, 86, 89, 32, 65, 78, 68, 32, 188, 1, 10, 76, 73, 71, 72, + 84, 32, 65, 78, 68, 32, 186, 2, 68, 131, 4, 83, 12, 80, 4, 68, 79, 87, + 78, 24, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 255, 4, 72, 2, 145, 5, 2, + 32, 72, 4, 17, 2, 84, 32, 4, 26, 68, 151, 177, 35, 76, 2, 129, 191, 33, + 3, 79, 87, 78, 12, 80, 4, 68, 79, 87, 78, 24, 3, 76, 69, 70, 0, 4, 82, + 73, 71, 72, 211, 4, 72, 2, 229, 4, 2, 32, 72, 4, 17, 2, 84, 32, 4, 22, + 68, 131, 5, 72, 2, 233, 4, 3, 79, 87, 78, 24, 130, 1, 68, 188, 1, 10, 72, + 69, 65, 86, 89, 32, 65, 78, 68, 32, 144, 1, 10, 76, 73, 71, 72, 84, 32, + 65, 78, 68, 32, 183, 1, 83, 6, 49, 10, 79, 85, 66, 76, 69, 32, 65, 78, + 68, 32, 6, 92, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 13, 10, 72, 79, 82, + 73, 90, 79, 78, 84, 65, 76, 2, 11, 84, 2, 169, 129, 27, 2, 32, 83, 6, 54, + 72, 68, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 37, 7, 79, 82, 73, 90, + 79, 78, 84, 2, 141, 186, 33, 2, 65, 76, 2, 243, 185, 33, 84, 6, 54, 72, + 60, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 37, 7, 79, 82, 73, 90, 79, + 78, 84, 2, 29, 2, 65, 76, 2, 11, 84, 2, 17, 2, 32, 72, 2, 225, 195, 35, + 3, 69, 65, 86, 6, 49, 10, 73, 78, 71, 76, 69, 32, 65, 78, 68, 32, 6, 96, + 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 177, 197, 26, 9, 72, 79, 82, 73, 90, + 79, 78, 84, 65, 2, 187, 197, 26, 84, 134, 6, 46, 65, 178, 14, 69, 150, 1, + 73, 179, 1, 79, 232, 5, 36, 4, 72, 77, 73, 32, 247, 9, 73, 230, 1, 192, + 1, 7, 76, 69, 84, 84, 69, 82, 32, 196, 2, 7, 78, 85, 77, 66, 69, 82, 32, + 144, 2, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 84, 5, 83, + 73, 71, 78, 32, 122, 86, 159, 138, 25, 68, 108, 210, 1, 79, 242, 241, 31, + 65, 38, 68, 114, 84, 46, 86, 186, 5, 85, 186, 202, 1, 73, 42, 76, 226, + 195, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, + 72, 2, 77, 2, 82, 2, 89, 187, 2, 69, 15, 45, 9, 76, 68, 32, 84, 65, 77, + 73, 76, 32, 12, 150, 152, 29, 76, 142, 155, 2, 83, 210, 97, 78, 131, 246, + 2, 82, 42, 82, 69, 38, 70, 66, 78, 26, 83, 182, 193, 21, 84, 130, 234, 5, + 79, 227, 227, 7, 74, 4, 129, 189, 31, 4, 73, 71, 72, 84, 8, 26, 79, 143, + 168, 21, 73, 4, 254, 221, 33, 82, 135, 183, 1, 85, 4, 65, 3, 73, 78, 69, + 8, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, 5, 175, 187, 35, 84, 10, 46, 76, + 130, 222, 12, 68, 177, 16, 2, 67, 82, 4, 242, 210, 19, 79, 147, 222, 14, + 73, 12, 174, 174, 31, 67, 228, 67, 9, 79, 76, 68, 32, 84, 65, 77, 73, 76, + 246, 157, 1, 74, 158, 2, 86, 122, 85, 255, 243, 1, 65, 34, 64, 10, 79, + 87, 69, 76, 32, 83, 73, 71, 78, 32, 187, 142, 33, 73, 32, 138, 1, 79, + 228, 199, 29, 11, 66, 72, 65, 84, 84, 73, 80, 82, 79, 76, 85, 198, 170, + 2, 65, 38, 85, 22, 86, 166, 202, 1, 73, 199, 140, 2, 69, 7, 181, 173, 31, + 10, 76, 68, 32, 84, 65, 77, 73, 76, 32, 83, 130, 4, 72, 12, 76, 76, 69, + 32, 80, 65, 84, 84, 69, 82, 78, 32, 191, 200, 35, 78, 128, 4, 44, 5, 68, + 79, 84, 83, 45, 207, 250, 6, 66, 254, 3, 74, 49, 74, 50, 66, 51, 54, 52, + 46, 53, 38, 54, 30, 55, 147, 197, 35, 56, 129, 2, 66, 50, 66, 51, 54, 52, + 46, 53, 38, 54, 30, 55, 147, 197, 35, 56, 129, 1, 58, 51, 54, 52, 46, 53, + 38, 54, 30, 55, 147, 197, 35, 56, 65, 50, 52, 46, 53, 38, 54, 30, 55, + 147, 197, 35, 56, 33, 42, 53, 38, 54, 30, 55, 147, 197, 35, 56, 17, 34, + 54, 30, 55, 147, 197, 35, 56, 9, 26, 55, 147, 197, 35, 56, 5, 143, 197, + 35, 56, 8, 26, 65, 143, 174, 35, 86, 6, 196, 205, 20, 11, 75, 32, 80, 69, + 82, 77, 73, 84, 84, 69, 68, 228, 176, 8, 6, 83, 84, 45, 70, 69, 69, 183, + 198, 6, 68, 10, 42, 68, 96, 2, 69, 70, 199, 191, 35, 67, 4, 212, 197, 32, + 6, 71, 69, 32, 65, 84, 32, 149, 158, 1, 9, 69, 32, 87, 73, 84, 72, 32, + 86, 69, 4, 190, 153, 32, 67, 159, 169, 3, 83, 12, 84, 4, 75, 69, 78, 32, + 244, 204, 8, 2, 67, 67, 176, 237, 25, 2, 87, 78, 231, 118, 79, 6, 196, + 199, 27, 17, 67, 73, 82, 67, 76, 69, 32, 87, 73, 84, 72, 32, 78, 79, 82, + 84, 72, 222, 214, 6, 66, 151, 28, 72, 134, 1, 208, 1, 4, 66, 66, 76, 69, + 46, 71, 156, 4, 4, 72, 73, 68, 32, 36, 2, 76, 76, 122, 83, 56, 4, 84, 84, + 69, 82, 164, 134, 11, 10, 73, 76, 68, 73, 78, 71, 32, 67, 79, 78, 144, + 226, 16, 2, 82, 82, 255, 253, 6, 67, 4, 144, 171, 28, 2, 32, 84, 131, + 148, 7, 83, 63, 33, 6, 73, 78, 69, 83, 69, 32, 60, 144, 1, 7, 76, 69, 84, + 84, 69, 82, 32, 172, 2, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, + 146, 196, 16, 69, 141, 253, 13, 4, 80, 65, 76, 76, 46, 154, 1, 77, 34, + 78, 190, 185, 35, 66, 2, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, 2, + 80, 2, 82, 2, 83, 2, 84, 2, 86, 2, 89, 187, 2, 65, 4, 218, 185, 35, 80, + 187, 2, 65, 12, 46, 71, 34, 89, 238, 184, 35, 82, 187, 2, 65, 4, 138, + 185, 35, 75, 187, 2, 65, 4, 234, 184, 35, 67, 187, 2, 65, 10, 174, 164, + 35, 65, 214, 22, 69, 2, 73, 2, 79, 3, 85, 40, 230, 164, 10, 76, 167, 253, + 18, 86, 10, 56, 2, 69, 84, 20, 4, 72, 79, 82, 78, 175, 175, 9, 83, 5, + 179, 246, 31, 32, 5, 189, 210, 27, 5, 32, 87, 73, 84, 72, 9, 26, 84, 147, + 228, 32, 32, 4, 182, 210, 27, 83, 15, 32, 5, 199, 149, 35, 70, 240, 3, + 140, 1, 23, 90, 65, 78, 84, 73, 78, 69, 32, 77, 85, 83, 73, 67, 65, 76, + 32, 83, 89, 77, 66, 79, 76, 32, 153, 200, 20, 5, 84, 69, 32, 79, 82, 238, + 3, 154, 2, 65, 128, 7, 2, 67, 72, 170, 1, 68, 158, 5, 69, 206, 2, 70, + 166, 8, 71, 202, 3, 73, 162, 2, 75, 142, 5, 76, 190, 2, 77, 250, 4, 79, + 114, 80, 174, 4, 82, 42, 83, 194, 5, 84, 196, 5, 2, 86, 65, 250, 1, 89, + 178, 196, 32, 78, 201, 146, 2, 9, 88, 73, 82, 79, 78, 32, 75, 76, 65, 62, + 60, 5, 71, 79, 71, 73, 32, 222, 1, 78, 118, 80, 199, 2, 82, 16, 70, 65, + 0, 2, 71, 79, 64, 2, 77, 69, 37, 5, 80, 79, 76, 73, 32, 4, 17, 2, 82, 71, + 4, 128, 242, 15, 2, 79, 84, 147, 194, 19, 73, 4, 158, 164, 9, 84, 243, + 251, 25, 83, 4, 26, 65, 1, 2, 71, 79, 2, 239, 222, 17, 82, 6, 72, 6, 84, + 73, 75, 69, 78, 79, 161, 145, 35, 6, 65, 84, 82, 73, 67, 72, 4, 168, 32, + 2, 75, 89, 231, 143, 35, 77, 22, 52, 5, 69, 83, 79, 32, 69, 38, 79, 239, + 157, 35, 76, 4, 204, 1, 2, 88, 79, 147, 55, 75, 16, 80, 6, 83, 84, 82, + 79, 70, 79, 188, 40, 3, 68, 69, 82, 237, 129, 1, 2, 84, 72, 10, 24, 2, + 73, 32, 79, 83, 4, 56, 9, 83, 89, 78, 68, 69, 83, 77, 79, 83, 195, 24, + 84, 2, 143, 44, 32, 7, 11, 32, 4, 214, 60, 68, 183, 166, 22, 78, 18, 48, + 2, 71, 79, 33, 6, 75, 84, 73, 75, 79, 32, 4, 170, 21, 83, 255, 153, 35, + 78, 14, 130, 216, 27, 86, 146, 184, 7, 90, 162, 8, 75, 254, 2, 68, 2, 78, + 162, 17, 71, 3, 80, 14, 80, 4, 82, 79, 65, 32, 168, 37, 4, 79, 82, 69, + 86, 221, 2, 4, 65, 77, 73, 76, 6, 132, 235, 19, 2, 83, 80, 232, 192, 3, + 3, 90, 89, 71, 205, 204, 10, 3, 75, 76, 73, 42, 50, 73, 244, 231, 8, 2, + 65, 83, 239, 165, 26, 89, 38, 122, 65, 200, 1, 5, 69, 83, 73, 83, 32, 70, + 71, 208, 1, 3, 80, 76, 73, 249, 208, 27, 8, 70, 84, 79, 71, 71, 79, 83, + 32, 10, 48, 6, 83, 84, 79, 76, 73, 32, 243, 240, 33, 82, 8, 80, 6, 65, + 80, 76, 73, 32, 77, 174, 55, 68, 185, 241, 22, 5, 84, 72, 69, 83, 69, 4, + 40, 2, 69, 71, 217, 190, 28, 2, 73, 75, 2, 195, 166, 30, 65, 12, 38, 84, + 246, 50, 65, 42, 68, 63, 77, 6, 194, 10, 69, 239, 41, 82, 10, 72, 5, 79, + 82, 71, 79, 78, 173, 168, 35, 7, 82, 65, 77, 77, 65, 32, 71, 9, 69, 15, + 32, 80, 65, 82, 69, 83, 84, 73, 71, 77, 69, 78, 79, 78, 32, 6, 222, 38, + 68, 137, 10, 8, 65, 82, 73, 83, 84, 69, 82, 65, 5, 175, 47, 32, 16, 166, + 1, 78, 116, 6, 84, 69, 82, 79, 78, 32, 188, 44, 4, 88, 79, 32, 69, 136, + 147, 33, 4, 80, 69, 71, 69, 236, 48, 6, 75, 83, 84, 82, 69, 80, 237, 13, + 3, 76, 65, 70, 4, 224, 22, 3, 68, 79, 70, 221, 184, 27, 18, 65, 82, 88, + 73, 83, 32, 75, 65, 73, 32, 70, 84, 72, 79, 82, 65, 32, 86, 4, 208, 11, + 5, 65, 82, 71, 79, 83, 151, 20, 80, 44, 180, 1, 9, 65, 78, 69, 82, 79, + 83, 73, 83, 32, 52, 6, 84, 72, 79, 82, 65, 32, 165, 6, 22, 72, 84, 79, + 82, 65, 32, 83, 75, 76, 73, 82, 79, 78, 32, 67, 72, 82, 79, 77, 65, 32, + 86, 6, 246, 4, 68, 14, 77, 25, 5, 84, 69, 84, 82, 65, 36, 220, 2, 8, 65, + 82, 67, 72, 65, 73, 79, 78, 80, 10, 68, 73, 65, 84, 79, 78, 73, 75, 73, + 32, 96, 11, 73, 32, 89, 70, 69, 83, 73, 83, 32, 84, 69, 32, 15, 77, 65, + 76, 65, 75, 79, 78, 32, 67, 72, 82, 79, 77, 65, 32, 74, 78, 40, 8, 83, + 75, 76, 73, 82, 79, 78, 32, 157, 229, 18, 18, 69, 78, 65, 82, 77, 79, 78, + 73, 79, 83, 32, 65, 78, 84, 73, 70, 79, 78, 5, 57, 12, 32, 68, 69, 89, + 84, 69, 82, 79, 85, 32, 73, 67, 2, 147, 201, 27, 72, 14, 62, 78, 210, + 128, 35, 90, 162, 8, 75, 254, 2, 68, 163, 17, 80, 6, 242, 39, 73, 187, + 185, 33, 65, 2, 237, 42, 4, 84, 65, 82, 84, 4, 18, 68, 15, 77, 2, 35, 73, + 2, 21, 3, 79, 78, 79, 2, 151, 19, 70, 4, 166, 19, 65, 193, 128, 33, 2, + 69, 78, 6, 84, 7, 67, 72, 82, 79, 77, 65, 32, 193, 169, 17, 8, 68, 73, + 65, 84, 79, 78, 79, 78, 4, 42, 86, 169, 173, 17, 4, 83, 89, 78, 65, 2, + 251, 245, 32, 65, 22, 80, 6, 69, 78, 73, 75, 73, 32, 44, 2, 79, 82, 185, + 26, 5, 82, 79, 78, 84, 72, 4, 192, 149, 31, 2, 68, 73, 1, 2, 89, 70, 16, + 68, 2, 71, 79, 225, 1, 10, 84, 72, 77, 73, 75, 79, 78, 32, 78, 32, 12, + 28, 2, 78, 32, 155, 1, 83, 10, 96, 14, 80, 65, 82, 69, 83, 84, 73, 71, + 77, 69, 78, 79, 78, 32, 242, 33, 65, 113, 3, 78, 69, 79, 4, 214, 24, 68, + 229, 239, 32, 5, 65, 82, 73, 83, 84, 2, 217, 228, 33, 5, 89, 78, 84, 72, + 69, 4, 142, 28, 65, 1, 2, 68, 73, 16, 56, 2, 77, 73, 114, 83, 181, 152, + 34, 4, 67, 72, 65, 68, 8, 34, 70, 169, 28, 3, 68, 73, 65, 6, 40, 4, 84, + 72, 79, 82, 251, 139, 34, 79, 4, 198, 200, 34, 79, 227, 79, 65, 6, 44, 6, + 65, 75, 73, 65, 32, 84, 231, 13, 79, 2, 165, 221, 21, 12, 69, 76, 79, 85, + 83, 32, 73, 67, 72, 73, 77, 65, 54, 108, 2, 65, 84, 96, 6, 69, 78, 84, + 73, 77, 65, 140, 1, 5, 76, 65, 83, 77, 65, 18, 79, 98, 82, 175, 1, 89, 6, + 40, 3, 65, 86, 65, 201, 3, 2, 72, 73, 4, 140, 29, 5, 32, 84, 82, 79, 77, + 219, 215, 34, 83, 18, 24, 2, 84, 65, 15, 32, 11, 11, 32, 8, 36, 4, 78, + 69, 79, 32, 183, 28, 65, 6, 208, 166, 28, 2, 77, 69, 170, 222, 2, 75, + 235, 230, 3, 65, 7, 243, 28, 32, 8, 64, 6, 78, 84, 69, 86, 77, 65, 146, + 225, 8, 82, 163, 145, 26, 85, 5, 145, 181, 14, 2, 32, 65, 14, 44, 4, 65, + 84, 73, 77, 105, 3, 69, 77, 65, 12, 18, 65, 35, 79, 8, 182, 23, 32, 151, + 249, 34, 84, 4, 134, 12, 75, 181, 220, 31, 5, 89, 80, 79, 82, 82, 2, 175, + 166, 27, 83, 2, 243, 240, 34, 76, 14, 22, 69, 147, 22, 89, 12, 44, 5, 73, + 77, 77, 65, 32, 191, 154, 30, 77, 10, 72, 2, 69, 78, 0, 5, 73, 77, 73, + 83, 69, 54, 84, 69, 3, 68, 89, 79, 2, 237, 185, 27, 8, 79, 83, 32, 67, + 72, 82, 79, 78, 4, 44, 5, 69, 83, 83, 65, 82, 1, 2, 82, 73, 2, 17, 2, 79, + 78, 2, 25, 4, 32, 67, 72, 82, 2, 175, 131, 34, 79, 28, 84, 8, 65, 82, 84, + 89, 82, 73, 65, 32, 229, 138, 31, 7, 73, 75, 82, 79, 78, 32, 73, 26, 72, + 5, 65, 76, 76, 73, 32, 38, 68, 38, 80, 134, 1, 86, 30, 84, 87, 76, 4, 34, + 68, 177, 2, 3, 80, 82, 79, 2, 237, 2, 5, 69, 89, 84, 69, 82, 8, 60, 7, + 76, 65, 71, 73, 79, 83, 32, 45, 4, 82, 79, 84, 79, 4, 200, 1, 5, 84, 69, + 84, 65, 82, 111, 73, 4, 22, 86, 227, 1, 83, 2, 209, 1, 3, 65, 82, 89, 8, + 56, 8, 69, 84, 65, 82, 84, 79, 83, 32, 61, 2, 82, 73, 4, 22, 76, 135, 1, + 73, 2, 21, 3, 69, 71, 69, 2, 63, 84, 4, 18, 70, 35, 84, 2, 221, 217, 21, + 3, 79, 78, 73, 2, 11, 79, 2, 11, 83, 2, 17, 2, 32, 73, 2, 199, 132, 23, + 67, 18, 92, 4, 76, 73, 71, 79, 180, 1, 5, 89, 82, 65, 78, 73, 210, 14, + 88, 249, 169, 34, 2, 77, 65, 4, 211, 1, 78, 42, 60, 2, 65, 82, 100, 2, + 73, 65, 90, 69, 169, 1, 2, 83, 73, 12, 40, 2, 65, 75, 161, 190, 17, 2, + 73, 67, 10, 52, 3, 65, 76, 69, 45, 6, 76, 73, 84, 73, 75, 73, 4, 11, 83, + 4, 17, 2, 77, 65, 4, 23, 32, 7, 11, 32, 4, 198, 15, 65, 211, 171, 22, 78, + 12, 72, 3, 84, 65, 83, 136, 3, 6, 76, 65, 83, 84, 79, 78, 135, 229, 8, + 82, 6, 26, 84, 203, 132, 35, 77, 4, 32, 2, 79, 75, 223, 134, 35, 73, 2, + 165, 229, 34, 2, 79, 85, 14, 36, 5, 70, 73, 83, 84, 79, 67, 76, 10, 46, + 80, 214, 1, 78, 170, 8, 76, 187, 1, 83, 2, 135, 11, 65, 4, 246, 181, 34, + 79, 227, 79, 73, 4, 178, 5, 69, 221, 222, 34, 2, 65, 80, 42, 120, 5, 69, + 73, 83, 77, 65, 32, 8, 73, 77, 65, 78, 83, 73, 83, 32, 182, 1, 84, 154, + 1, 89, 229, 243, 1, 3, 65, 88, 73, 5, 11, 32, 2, 151, 183, 22, 78, 16, + 36, 2, 65, 82, 1, 3, 84, 72, 69, 8, 25, 4, 83, 69, 79, 83, 9, 11, 32, 6, + 18, 84, 39, 68, 4, 34, 82, 13, 4, 69, 84, 82, 65, 2, 11, 73, 2, 217, 171, + 27, 3, 83, 73, 77, 8, 68, 5, 65, 86, 82, 79, 83, 52, 4, 82, 65, 71, 71, + 251, 218, 16, 73, 5, 29, 5, 32, 65, 80, 79, 68, 2, 199, 232, 8, 69, 2, + 253, 243, 1, 2, 73, 83, 12, 34, 78, 149, 1, 3, 82, 77, 65, 8, 36, 5, 65, + 71, 77, 65, 32, 91, 69, 6, 154, 8, 65, 210, 171, 22, 78, 237, 245, 4, 10, + 77, 69, 84, 65, 32, 83, 84, 65, 86, 82, 2, 243, 222, 34, 86, 5, 11, 84, + 2, 243, 137, 17, 73, 40, 42, 69, 70, 72, 218, 1, 82, 227, 2, 73, 6, 136, + 12, 3, 84, 82, 65, 186, 174, 8, 76, 237, 178, 24, 2, 83, 83, 12, 26, 69, + 251, 217, 34, 73, 10, 64, 2, 77, 65, 217, 231, 33, 8, 83, 32, 75, 65, 73, + 32, 65, 80, 9, 56, 2, 32, 65, 33, 8, 84, 73, 83, 77, 79, 83, 32, 69, 2, + 145, 253, 33, 3, 80, 76, 79, 4, 174, 222, 34, 83, 3, 88, 20, 38, 73, 73, + 5, 79, 77, 73, 75, 79, 6, 48, 2, 71, 79, 206, 248, 29, 80, 227, 131, 5, + 65, 2, 247, 193, 33, 82, 14, 42, 76, 32, 2, 78, 32, 62, 80, 95, 83, 2, + 11, 89, 2, 183, 218, 34, 71, 6, 26, 65, 195, 174, 22, 78, 4, 250, 2, 82, + 231, 213, 34, 76, 4, 46, 65, 193, 197, 33, 5, 83, 73, 70, 73, 83, 2, 193, + 217, 34, 6, 82, 65, 75, 65, 76, 69, 2, 11, 89, 2, 217, 211, 16, 2, 78, + 65, 10, 26, 82, 175, 216, 34, 84, 8, 21, 3, 69, 73, 65, 8, 26, 32, 113, + 2, 73, 32, 6, 38, 69, 242, 5, 68, 183, 166, 22, 78, 2, 11, 75, 2, 29, 5, + 70, 79, 78, 73, 84, 2, 249, 168, 34, 2, 73, 75, 2, 11, 65, 2, 11, 82, 2, + 237, 167, 34, 3, 67, 72, 65, 22, 28, 2, 70, 69, 231, 3, 80, 14, 34, 78, + 49, 4, 83, 73, 83, 32, 4, 11, 32, 4, 202, 231, 30, 75, 235, 230, 3, 65, + 10, 42, 65, 42, 68, 62, 77, 89, 2, 84, 82, 2, 133, 2, 6, 80, 76, 73, 32, + 68, 89, 2, 233, 1, 11, 73, 71, 82, 65, 77, 77, 79, 83, 32, 69, 88, 2, + 173, 1, 18, 79, 78, 79, 71, 82, 65, 77, 77, 79, 83, 32, 84, 69, 83, 83, + 69, 82, 65, 4, 11, 73, 4, 60, 11, 71, 82, 65, 77, 77, 79, 83, 32, 79, 75, + 84, 59, 84, 2, 11, 79, 2, 153, 180, 2, 6, 32, 68, 79, 68, 69, 75, 2, 237, + 163, 34, 4, 73, 77, 79, 82, 8, 26, 79, 139, 240, 29, 83, 6, 56, 6, 75, + 82, 73, 83, 73, 83, 181, 252, 29, 2, 82, 82, 5, 17, 2, 32, 68, 2, 11, 73, + 2, 183, 239, 29, 80, 232, 82, 182, 1, 65, 250, 71, 69, 230, 1, 72, 222, + 32, 73, 208, 41, 3, 74, 75, 32, 138, 26, 76, 186, 18, 79, 238, 117, 82, + 234, 7, 85, 150, 128, 2, 89, 134, 180, 19, 71, 190, 235, 10, 83, 203, 18, + 67, 198, 13, 110, 68, 58, 76, 50, 77, 90, 78, 174, 51, 80, 62, 82, 198, + 7, 84, 138, 1, 85, 162, 185, 18, 67, 227, 208, 6, 83, 4, 34, 85, 205, + 164, 27, 2, 65, 32, 2, 147, 229, 7, 67, 4, 248, 219, 9, 3, 76, 32, 77, + 231, 218, 19, 69, 6, 36, 3, 69, 82, 65, 195, 158, 34, 80, 5, 237, 202, + 27, 7, 32, 87, 73, 84, 72, 32, 70, 193, 11, 148, 1, 16, 65, 68, 73, 65, + 78, 32, 83, 89, 76, 76, 65, 66, 73, 67, 83, 32, 148, 49, 2, 67, 69, 94, + 68, 140, 249, 23, 3, 78, 69, 68, 171, 172, 10, 79, 172, 11, 226, 1, 65, + 190, 1, 66, 162, 2, 67, 242, 8, 69, 50, 70, 198, 4, 72, 38, 73, 30, 75, + 134, 1, 76, 82, 77, 174, 1, 78, 202, 4, 81, 178, 1, 79, 194, 1, 80, 70, + 82, 142, 1, 83, 194, 4, 84, 246, 3, 87, 254, 5, 89, 143, 225, 17, 71, 21, + 90, 65, 30, 73, 40, 10, 84, 72, 65, 80, 65, 83, 67, 65, 78, 32, 242, 234, + 34, 78, 3, 89, 7, 178, 235, 34, 73, 3, 89, 5, 169, 242, 23, 5, 86, 73, + 76, 73, 75, 4, 238, 234, 34, 77, 3, 83, 42, 156, 1, 9, 76, 65, 67, 75, + 70, 79, 79, 84, 32, 212, 171, 19, 9, 73, 66, 76, 69, 45, 67, 82, 69, 69, + 137, 208, 7, 10, 69, 65, 86, 69, 82, 32, 68, 69, 78, 69, 36, 82, 87, 162, + 242, 11, 75, 2, 78, 194, 246, 22, 65, 2, 69, 2, 73, 2, 79, 3, 83, 11, + 222, 232, 34, 65, 2, 69, 2, 73, 3, 79, 141, 3, 82, 65, 186, 42, 87, 222, + 181, 8, 72, 154, 190, 23, 79, 238, 60, 73, 199, 140, 2, 69, 241, 2, 48, + 6, 82, 82, 73, 69, 82, 32, 227, 218, 32, 65, 234, 2, 170, 1, 68, 122, 71, + 94, 72, 46, 73, 46, 74, 82, 75, 30, 78, 66, 83, 66, 80, 2, 90, 58, 84, + 38, 76, 132, 1, 2, 67, 72, 2, 77, 2, 82, 2, 87, 2, 89, 171, 201, 34, 69, + 32, 46, 69, 202, 5, 76, 2, 90, 255, 223, 34, 73, 6, 26, 78, 171, 229, 34, + 69, 4, 134, 154, 17, 69, 249, 211, 6, 2, 84, 65, 30, 254, 4, 72, 202, + 186, 21, 87, 198, 147, 9, 65, 210, 209, 3, 69, 162, 64, 73, 2, 79, 3, 85, + 19, 162, 4, 87, 170, 201, 34, 69, 215, 22, 73, 5, 197, 150, 14, 6, 78, + 73, 84, 73, 65, 76, 26, 202, 3, 74, 222, 159, 34, 69, 234, 61, 87, 186, + 2, 65, 2, 73, 2, 79, 3, 85, 26, 154, 1, 75, 227, 1, 72, 14, 186, 162, 34, + 69, 162, 64, 65, 2, 71, 2, 73, 2, 79, 3, 85, 26, 62, 72, 190, 161, 34, + 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 15, 186, 161, 34, 69, 162, 64, 65, + 2, 73, 2, 79, 3, 85, 72, 34, 76, 70, 84, 66, 72, 3, 83, 24, 130, 1, 72, + 222, 159, 34, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 24, 62, 83, 222, 159, + 34, 69, 162, 64, 65, 2, 73, 2, 79, 3, 85, 12, 218, 159, 34, 69, 162, 64, + 65, 2, 73, 2, 79, 3, 85, 7, 236, 29, 4, 65, 83, 84, 69, 215, 193, 34, 78, + 51, 74, 65, 22, 73, 142, 137, 32, 85, 250, 11, 79, 254, 83, 87, 183, 245, + 1, 69, 7, 131, 210, 32, 65, 33, 40, 4, 78, 65, 76, 32, 139, 222, 34, 73, + 28, 160, 1, 2, 68, 79, 134, 1, 82, 78, 83, 138, 148, 14, 71, 186, 2, 65, + 180, 182, 3, 6, 66, 79, 84, 84, 79, 77, 0, 3, 84, 79, 80, 150, 131, 13, + 80, 175, 247, 2, 77, 6, 44, 5, 85, 66, 76, 69, 32, 235, 184, 24, 87, 4, + 164, 205, 6, 12, 83, 72, 79, 82, 84, 32, 86, 69, 82, 84, 73, 67, 187, + 202, 7, 65, 6, 38, 73, 149, 141, 33, 3, 65, 73, 83, 4, 254, 204, 17, 71, + 231, 141, 17, 78, 4, 240, 171, 25, 4, 77, 65, 76, 76, 133, 135, 7, 4, 72, + 79, 82, 84, 4, 234, 201, 26, 89, 231, 144, 8, 75, 7, 170, 218, 34, 73, 3, + 78, 39, 66, 87, 234, 27, 65, 182, 244, 31, 79, 238, 60, 73, 199, 140, 2, + 69, 19, 210, 156, 12, 65, 202, 243, 19, 79, 238, 60, 73, 199, 140, 2, 69, + 49, 142, 7, 72, 154, 20, 65, 66, 87, 246, 243, 31, 79, 238, 60, 73, 199, + 140, 2, 69, 43, 70, 69, 38, 79, 238, 25, 65, 66, 87, 226, 176, 32, 73, + 199, 140, 2, 72, 7, 153, 234, 26, 4, 68, 73, 65, 76, 7, 11, 79, 5, 193, + 144, 33, 8, 83, 69, 45, 67, 82, 69, 69, 32, 149, 1, 164, 1, 8, 45, 67, + 82, 69, 69, 32, 84, 72, 38, 65, 250, 2, 71, 76, 2, 78, 71, 48, 4, 85, 78, + 65, 86, 142, 20, 79, 30, 87, 226, 176, 32, 73, 198, 140, 2, 69, 3, 72, 6, + 158, 201, 32, 73, 199, 140, 2, 69, 63, 104, 6, 83, 75, 65, 80, 73, 32, + 188, 1, 7, 84, 84, 73, 76, 73, 75, 32, 214, 198, 32, 65, 199, 140, 2, 89, + 30, 70, 83, 86, 87, 210, 17, 67, 2, 75, 2, 77, 2, 78, 2, 84, 3, 89, 14, + 174, 218, 29, 67, 2, 80, 2, 84, 236, 103, 2, 75, 87, 190, 156, 2, 87, + 151, 119, 45, 4, 194, 180, 34, 79, 191, 28, 65, 24, 30, 72, 1, 3, 83, 72, + 82, 12, 134, 193, 30, 65, 194, 200, 1, 79, 239, 60, 73, 19, 38, 65, 242, + 136, 32, 79, 239, 60, 73, 9, 218, 197, 32, 65, 199, 140, 2, 73, 15, 138, + 192, 30, 65, 194, 200, 1, 79, 239, 60, 73, 18, 224, 9, 3, 73, 75, 32, + 185, 207, 23, 2, 85, 84, 33, 68, 7, 74, 73, 66, 87, 65, 89, 32, 210, 208, + 34, 78, 2, 79, 3, 89, 24, 74, 78, 166, 191, 30, 83, 226, 144, 4, 67, 2, + 75, 2, 77, 2, 80, 3, 84, 11, 11, 87, 8, 198, 134, 32, 79, 239, 60, 73, + 39, 206, 4, 87, 166, 13, 65, 38, 79, 254, 176, 32, 73, 199, 140, 2, 69, + 39, 104, 7, 45, 67, 82, 69, 69, 32, 82, 146, 14, 87, 182, 2, 65, 182, + 244, 31, 79, 238, 60, 73, 199, 140, 2, 69, 4, 210, 183, 34, 87, 215, 22, + 69, 125, 94, 65, 218, 1, 72, 138, 1, 79, 238, 2, 87, 158, 209, 11, 80, + 254, 233, 20, 73, 199, 140, 2, 69, 43, 26, 89, 203, 192, 32, 65, 37, 25, + 4, 73, 83, 73, 32, 34, 70, 72, 54, 74, 218, 4, 83, 198, 179, 34, 89, 202, + 18, 84, 147, 1, 77, 10, 246, 130, 32, 79, 178, 201, 2, 65, 2, 69, 3, 73, + 6, 246, 244, 30, 85, 255, 214, 3, 73, 37, 70, 87, 202, 13, 79, 202, 128, + 12, 65, 182, 176, 20, 73, 199, 140, 2, 69, 16, 198, 13, 79, 210, 171, 30, + 65, 174, 133, 2, 73, 199, 140, 2, 69, 15, 80, 12, 85, 84, 72, 45, 83, 76, + 65, 86, 69, 89, 32, 75, 246, 201, 34, 79, 3, 89, 8, 226, 200, 34, 65, 2, + 69, 2, 73, 3, 79, 117, 110, 72, 190, 1, 76, 78, 84, 238, 8, 65, 66, 87, + 230, 198, 11, 89, 146, 173, 20, 79, 238, 60, 73, 199, 140, 2, 69, 39, + 108, 7, 45, 67, 82, 69, 69, 32, 84, 226, 4, 87, 154, 177, 30, 65, 194, + 200, 1, 79, 238, 60, 73, 199, 140, 2, 69, 16, 11, 72, 17, 234, 181, 30, + 65, 194, 200, 1, 79, 238, 60, 73, 199, 140, 2, 69, 12, 11, 72, 12, 222, + 253, 31, 79, 222, 178, 2, 87, 214, 22, 65, 2, 69, 3, 73, 24, 50, 72, 158, + 198, 34, 65, 2, 69, 2, 73, 3, 79, 17, 170, 180, 30, 65, 194, 200, 1, 79, + 222, 178, 2, 87, 214, 22, 69, 3, 73, 224, 1, 54, 69, 218, 3, 79, 202, + 132, 12, 65, 183, 176, 20, 73, 185, 1, 17, 2, 83, 84, 182, 1, 44, 6, 45, + 67, 82, 69, 69, 32, 251, 2, 69, 180, 1, 110, 76, 66, 77, 2, 80, 2, 89, + 16, 2, 78, 87, 38, 82, 62, 83, 26, 67, 2, 75, 18, 84, 26, 70, 199, 4, 87, + 27, 178, 6, 87, 182, 171, 30, 65, 194, 200, 1, 79, 179, 201, 2, 69, 17, + 243, 5, 87, 6, 150, 177, 30, 65, 243, 145, 4, 69, 13, 174, 205, 32, 87, + 182, 245, 1, 65, 2, 69, 2, 73, 3, 79, 28, 22, 72, 239, 4, 87, 14, 235, 4, + 87, 16, 22, 72, 199, 4, 87, 2, 179, 204, 32, 87, 2, 171, 204, 23, 82, 31, + 11, 79, 29, 41, 8, 68, 83, 45, 67, 82, 69, 69, 32, 26, 56, 2, 84, 72, + 213, 187, 32, 6, 70, 73, 78, 65, 76, 32, 25, 50, 87, 154, 192, 34, 65, 2, + 69, 2, 73, 3, 79, 14, 166, 174, 30, 65, 194, 200, 1, 79, 238, 60, 73, + 243, 245, 1, 69, 61, 92, 6, 45, 67, 82, 69, 69, 32, 150, 1, 65, 38, 79, + 30, 87, 226, 176, 32, 73, 199, 140, 2, 69, 24, 110, 80, 146, 243, 31, 67, + 2, 75, 2, 76, 2, 77, 2, 78, 2, 83, 2, 84, 2, 89, 134, 172, 2, 79, 247, + 30, 87, 4, 210, 200, 32, 87, 195, 214, 1, 79, 9, 158, 177, 32, 65, 199, + 140, 2, 89, 7, 190, 189, 34, 79, 3, 89, 14, 178, 171, 30, 65, 194, 200, + 1, 79, 238, 60, 73, 199, 140, 2, 69, 10, 26, 76, 203, 188, 34, 82, 9, 26, + 32, 231, 193, 9, 76, 4, 218, 171, 22, 67, 231, 164, 10, 84, 4, 178, 165, + 34, 76, 215, 22, 89, 4, 180, 191, 15, 3, 73, 84, 85, 161, 134, 8, 3, 82, + 73, 67, 124, 140, 1, 2, 68, 32, 102, 69, 72, 11, 73, 65, 78, 32, 76, 69, + 84, 84, 69, 82, 32, 210, 3, 79, 62, 80, 90, 82, 217, 237, 27, 4, 32, 83, + 76, 73, 6, 52, 5, 73, 78, 68, 69, 88, 233, 170, 33, 2, 70, 73, 5, 229, + 168, 33, 6, 32, 68, 73, 86, 73, 68, 6, 26, 84, 151, 211, 21, 32, 5, 193, + 169, 10, 6, 32, 73, 78, 83, 69, 82, 98, 196, 1, 2, 67, 45, 38, 76, 22, + 77, 50, 78, 38, 83, 46, 84, 22, 85, 166, 219, 3, 65, 2, 68, 2, 69, 2, 71, + 2, 75, 2, 80, 158, 132, 27, 82, 218, 201, 1, 73, 198, 140, 2, 66, 2, 79, + 2, 81, 3, 88, 4, 246, 139, 27, 49, 155, 177, 3, 51, 7, 203, 220, 3, 68, + 11, 11, 66, 9, 226, 182, 34, 50, 2, 51, 3, 52, 9, 190, 182, 34, 68, 2, + 71, 3, 78, 13, 226, 219, 3, 72, 2, 84, 187, 218, 30, 83, 7, 183, 219, 3, + 84, 13, 11, 85, 11, 11, 85, 9, 194, 181, 34, 50, 2, 51, 3, 85, 4, 224, + 169, 33, 6, 85, 83, 69, 76, 32, 72, 191, 139, 1, 78, 4, 172, 215, 27, 6, + 32, 83, 84, 82, 69, 65, 137, 223, 5, 7, 69, 78, 84, 82, 89, 32, 83, 4, + 218, 225, 27, 73, 135, 182, 6, 79, 9, 29, 5, 32, 70, 65, 67, 69, 7, 33, + 6, 32, 87, 73, 84, 72, 32, 4, 148, 242, 6, 2, 84, 69, 197, 152, 25, 6, + 87, 82, 89, 32, 83, 77, 108, 88, 16, 67, 65, 83, 73, 65, 78, 32, 65, 76, + 66, 65, 78, 73, 65, 78, 32, 243, 172, 30, 84, 106, 60, 7, 76, 69, 84, 84, + 69, 82, 32, 161, 147, 28, 2, 67, 73, 104, 170, 2, 65, 34, 67, 146, 1, 68, + 78, 69, 34, 71, 46, 73, 46, 74, 34, 75, 34, 76, 34, 80, 34, 83, 74, 84, + 62, 89, 46, 90, 148, 133, 17, 2, 81, 65, 190, 193, 6, 77, 252, 132, 9, 3, + 86, 69, 89, 154, 33, 70, 128, 19, 3, 78, 79, 87, 226, 32, 82, 186, 11, + 88, 154, 46, 79, 202, 26, 66, 237, 24, 3, 72, 69, 89, 4, 186, 246, 33, + 79, 179, 28, 76, 16, 34, 65, 34, 72, 49, 2, 89, 65, 4, 242, 222, 33, 89, + 227, 79, 82, 8, 218, 197, 28, 65, 146, 215, 5, 79, 203, 17, 73, 4, 130, + 174, 34, 87, 3, 89, 8, 42, 90, 162, 225, 32, 89, 243, 175, 1, 65, 4, 154, + 159, 33, 89, 219, 124, 65, 4, 186, 221, 33, 89, 227, 79, 66, 4, 212, 254, + 32, 2, 72, 69, 207, 157, 1, 73, 6, 214, 238, 32, 82, 154, 110, 87, 135, + 77, 78, 4, 214, 157, 33, 72, 227, 16, 65, 4, 226, 173, 33, 73, 199, 69, + 65, 4, 130, 220, 33, 65, 171, 51, 89, 4, 142, 1, 73, 215, 218, 33, 69, 8, + 34, 72, 233, 167, 34, 2, 69, 89, 6, 234, 171, 20, 65, 207, 237, 13, 79, + 6, 38, 73, 150, 156, 33, 89, 199, 80, 65, 2, 215, 241, 33, 87, 4, 252, + 227, 33, 2, 65, 89, 1, 2, 79, 87, 6, 242, 166, 16, 72, 131, 186, 4, 65, + 16, 72, 2, 68, 73, 32, 2, 78, 84, 204, 193, 32, 3, 76, 84, 73, 151, 81, + 82, 4, 142, 162, 33, 32, 223, 100, 76, 8, 32, 2, 82, 69, 207, 161, 33, + 32, 6, 44, 5, 76, 73, 78, 69, 32, 167, 232, 4, 32, 4, 246, 234, 21, 76, + 207, 210, 10, 79, 130, 6, 102, 65, 170, 17, 69, 162, 8, 73, 190, 2, 79, + 188, 205, 13, 6, 82, 73, 83, 84, 77, 65, 155, 137, 10, 85, 198, 2, 66, + 73, 32, 4, 75, 77, 65, 32, 148, 6, 2, 77, 32, 131, 8, 82, 4, 218, 232, + 33, 78, 223, 61, 82, 142, 1, 156, 1, 7, 76, 69, 84, 84, 69, 82, 32, 142, + 3, 83, 98, 86, 142, 224, 23, 68, 154, 236, 7, 81, 176, 95, 5, 77, 65, 65, + 89, 89, 240, 179, 1, 2, 65, 85, 3, 79, 76, 202, 1, 68, 54, 78, 54, 84, + 54, 89, 178, 153, 29, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 76, 2, 80, 170, + 147, 3, 72, 2, 77, 2, 82, 2, 83, 2, 86, 2, 87, 254, 242, 1, 65, 186, 2, + 69, 2, 73, 3, 85, 8, 202, 154, 29, 68, 170, 147, 3, 72, 255, 242, 1, 65, + 8, 190, 173, 32, 71, 2, 78, 2, 89, 255, 242, 1, 65, 8, 226, 153, 29, 84, + 170, 147, 3, 72, 255, 242, 1, 65, 4, 214, 172, 32, 89, 255, 242, 1, 65, + 8, 40, 4, 73, 71, 78, 32, 195, 142, 22, 69, 6, 218, 131, 30, 67, 246, + 227, 1, 86, 247, 244, 1, 65, 26, 64, 10, 79, 87, 69, 76, 32, 83, 73, 71, + 78, 32, 171, 228, 31, 73, 24, 206, 194, 30, 65, 250, 6, 85, 186, 202, 1, + 69, 2, 73, 3, 79, 166, 1, 236, 1, 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, + 32, 83, 73, 71, 78, 32, 112, 7, 76, 69, 84, 84, 69, 82, 32, 152, 4, 12, + 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 60, 11, 86, 79, 87, 69, + 76, 32, 83, 73, 71, 78, 32, 199, 164, 32, 68, 14, 72, 6, 70, 73, 78, 65, + 76, 32, 142, 155, 34, 76, 2, 82, 2, 87, 3, 89, 6, 238, 156, 34, 78, 86, + 72, 3, 77, 104, 132, 2, 6, 70, 73, 78, 65, 76, 32, 110, 78, 50, 77, 78, + 80, 174, 229, 11, 66, 226, 141, 6, 68, 158, 145, 12, 83, 198, 136, 2, 65, + 132, 197, 1, 2, 67, 72, 2, 71, 2, 74, 2, 75, 2, 84, 138, 69, 72, 2, 76, + 2, 82, 2, 86, 2, 89, 186, 2, 69, 2, 73, 2, 79, 3, 85, 22, 150, 157, 32, + 78, 166, 192, 1, 83, 206, 60, 67, 146, 1, 71, 2, 75, 2, 76, 2, 80, 2, 82, + 2, 84, 3, 89, 14, 46, 71, 34, 72, 138, 131, 34, 85, 215, 22, 65, 4, 166, + 131, 34, 85, 215, 22, 65, 6, 134, 131, 34, 85, 158, 20, 74, 187, 2, 65, + 6, 246, 150, 34, 72, 2, 80, 187, 2, 65, 8, 182, 170, 11, 83, 134, 142, + 19, 68, 45, 4, 84, 82, 73, 80, 20, 170, 193, 30, 65, 222, 202, 1, 73, + 166, 204, 1, 79, 2, 85, 203, 44, 69, 14, 72, 7, 65, 67, 84, 69, 82, 32, + 84, 49, 7, 84, 32, 87, 73, 84, 72, 32, 8, 244, 255, 9, 3, 65, 66, 85, + 239, 128, 24, 73, 6, 128, 1, 13, 85, 80, 87, 65, 82, 68, 83, 32, 84, 82, + 69, 78, 68, 161, 186, 25, 12, 68, 79, 87, 78, 87, 65, 82, 68, 83, 32, 84, + 82, 5, 153, 250, 6, 6, 32, 65, 78, 68, 32, 89, 236, 2, 80, 2, 67, 75, 82, + 69, 90, 82, 176, 253, 4, 2, 83, 84, 133, 166, 15, 2, 81, 85, 6, 56, 8, + 69, 82, 32, 66, 79, 65, 82, 68, 143, 211, 33, 32, 5, 227, 152, 31, 32, 4, + 224, 202, 27, 4, 83, 69, 32, 87, 221, 156, 5, 9, 82, 73, 78, 71, 32, 77, + 69, 71, 65, 222, 2, 40, 5, 79, 75, 69, 69, 32, 143, 5, 82, 216, 2, 46, 76, 1, 7, 83, 77, 65, 76, 76, 32, 76, 172, 1, 33, 6, 69, 84, 84, 69, 82, 32, 172, 1, 170, 1, 68, 74, 72, 74, 78, 70, 83, 62, 84, 54, 71, 2, 76, 2, - 77, 0, 2, 81, 85, 2, 87, 2, 89, 194, 228, 33, 75, 186, 2, 65, 2, 69, 2, - 73, 2, 79, 2, 85, 3, 86, 14, 130, 231, 33, 76, 186, 2, 65, 2, 69, 2, 73, - 2, 79, 2, 85, 3, 86, 14, 186, 230, 33, 78, 186, 2, 65, 2, 69, 2, 73, 2, - 79, 2, 85, 3, 86, 14, 142, 200, 29, 65, 158, 160, 4, 69, 2, 73, 2, 79, 2, - 85, 3, 86, 15, 230, 231, 33, 65, 2, 69, 2, 73, 2, 79, 2, 85, 3, 86, 30, - 50, 76, 2, 83, 250, 230, 33, 65, 2, 69, 3, 73, 12, 246, 230, 33, 65, 2, - 69, 2, 73, 2, 79, 2, 85, 3, 86, 4, 48, 6, 89, 32, 66, 76, 79, 83, 147, - 210, 32, 73, 2, 163, 213, 33, 83, 12, 96, 2, 76, 68, 254, 235, 7, 32, - 204, 246, 2, 2, 80, 77, 224, 174, 21, 2, 67, 75, 255, 131, 1, 82, 5, 237, - 216, 28, 7, 82, 69, 78, 32, 67, 82, 79, 60, 92, 8, 82, 65, 83, 77, 73, - 65, 78, 32, 174, 254, 4, 80, 189, 255, 11, 5, 67, 79, 76, 65, 84, 56, 52, - 7, 76, 69, 84, 84, 69, 82, 32, 247, 194, 21, 78, 42, 224, 1, 6, 67, 85, - 82, 76, 69, 68, 30, 83, 206, 191, 21, 68, 34, 76, 158, 206, 1, 82, 178, - 215, 2, 65, 50, 71, 90, 90, 98, 89, 158, 208, 1, 72, 234, 5, 75, 198, 75, - 66, 178, 216, 4, 78, 134, 2, 84, 2, 87, 218, 103, 80, 171, 4, 77, 2, 181, - 227, 32, 2, 32, 87, 6, 180, 191, 21, 6, 77, 65, 76, 76, 32, 65, 252, 239, - 5, 2, 65, 77, 195, 178, 5, 72, 232, 4, 66, 78, 20, 2, 82, 67, 201, 40, 7, - 84, 89, 83, 67, 65, 80, 69, 2, 155, 191, 33, 69, 226, 4, 28, 2, 76, 69, - 207, 39, 85, 220, 4, 30, 32, 185, 6, 2, 68, 32, 24, 244, 1, 5, 87, 73, - 84, 72, 32, 185, 186, 18, 49, 68, 73, 86, 73, 68, 69, 68, 32, 66, 89, 32, - 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 66, 65, 82, 32, 65, 78, 68, - 32, 84, 79, 80, 32, 72, 65, 76, 70, 32, 68, 73, 86, 73, 68, 69, 68, 32, - 66, 89, 22, 146, 2, 76, 46, 83, 108, 22, 84, 87, 79, 32, 72, 79, 82, 73, - 90, 79, 78, 84, 65, 76, 32, 83, 84, 82, 79, 75, 69, 83, 44, 6, 85, 80, - 80, 69, 82, 32, 44, 17, 65, 76, 76, 32, 66, 85, 84, 32, 85, 80, 80, 69, - 82, 32, 76, 69, 70, 182, 181, 26, 86, 178, 136, 4, 82, 231, 249, 1, 72, - 4, 198, 191, 30, 69, 49, 4, 79, 87, 69, 82, 4, 104, 11, 77, 65, 76, 76, - 32, 67, 73, 82, 67, 76, 69, 221, 5, 10, 85, 80, 69, 82, 73, 77, 80, 79, - 83, 69, 2, 153, 217, 30, 6, 32, 84, 79, 32, 84, 72, 4, 40, 4, 82, 73, 71, - 72, 159, 190, 30, 72, 2, 177, 190, 30, 10, 84, 32, 81, 85, 65, 68, 82, - 65, 78, 84, 196, 4, 230, 2, 65, 186, 1, 66, 58, 67, 230, 1, 68, 246, 1, - 72, 230, 2, 73, 194, 10, 75, 190, 2, 76, 38, 77, 136, 1, 7, 78, 85, 77, - 66, 69, 82, 32, 192, 4, 17, 79, 80, 69, 78, 32, 67, 69, 78, 84, 82, 69, - 32, 69, 73, 71, 72, 84, 54, 80, 114, 82, 50, 84, 78, 87, 232, 248, 9, 4, - 90, 69, 82, 79, 234, 183, 16, 69, 246, 177, 4, 86, 158, 68, 71, 190, 113, - 83, 223, 160, 1, 88, 6, 100, 12, 78, 84, 73, 67, 76, 79, 67, 75, 87, 73, - 83, 69, 213, 149, 30, 7, 83, 84, 69, 82, 73, 83, 75, 4, 200, 238, 8, 11, - 45, 82, 79, 84, 65, 84, 69, 68, 32, 68, 73, 179, 204, 23, 32, 4, 32, 2, - 79, 76, 167, 245, 31, 85, 2, 131, 143, 14, 68, 16, 60, 4, 82, 79, 83, 83, - 210, 2, 32, 174, 209, 33, 67, 3, 68, 10, 26, 32, 155, 193, 1, 73, 8, 64, - 6, 70, 79, 82, 77, 69, 69, 229, 227, 31, 4, 80, 79, 77, 77, 7, 33, 6, 32, - 87, 73, 84, 72, 32, 4, 214, 175, 31, 70, 207, 82, 84, 30, 34, 73, 70, 79, - 211, 233, 31, 65, 24, 216, 187, 4, 8, 86, 73, 83, 73, 79, 78, 32, 83, - 211, 165, 27, 71, 4, 64, 10, 76, 76, 65, 82, 32, 83, 73, 71, 78, 32, 191, - 145, 30, 84, 2, 145, 156, 19, 13, 87, 73, 84, 72, 32, 79, 86, 69, 82, 76, - 65, 73, 68, 64, 192, 1, 6, 65, 78, 71, 85, 76, 32, 204, 191, 12, 20, 79, - 82, 73, 90, 79, 78, 84, 65, 76, 32, 66, 65, 82, 32, 87, 73, 84, 72, 32, - 78, 136, 210, 9, 4, 85, 77, 65, 78, 145, 1, 4, 69, 65, 86, 89, 58, 110, - 67, 184, 188, 20, 5, 73, 69, 85, 78, 71, 42, 72, 30, 75, 66, 77, 34, 78, - 34, 80, 62, 82, 30, 83, 27, 84, 8, 150, 188, 20, 72, 157, 3, 4, 73, 69, - 85, 67, 116, 220, 1, 9, 68, 69, 79, 71, 82, 65, 80, 72, 32, 196, 8, 27, - 84, 65, 76, 73, 67, 32, 76, 65, 84, 73, 78, 32, 67, 65, 80, 73, 84, 65, - 76, 32, 76, 69, 84, 84, 69, 82, 32, 157, 138, 27, 9, 78, 70, 79, 82, 77, - 65, 84, 73, 79, 110, 174, 1, 65, 110, 67, 90, 69, 86, 70, 62, 72, 38, 75, - 70, 76, 50, 77, 86, 78, 62, 81, 30, 82, 74, 83, 162, 173, 6, 80, 242, - 143, 14, 84, 50, 87, 170, 214, 1, 73, 255, 151, 10, 79, 8, 158, 189, 20, - 76, 184, 133, 1, 3, 67, 67, 69, 204, 239, 6, 3, 84, 84, 69, 249, 17, 5, - 68, 86, 65, 78, 84, 8, 26, 79, 163, 200, 30, 69, 6, 240, 200, 10, 2, 82, - 82, 230, 243, 9, 78, 203, 251, 12, 80, 8, 234, 188, 20, 78, 222, 163, 9, - 65, 188, 165, 3, 5, 88, 67, 69, 76, 76, 231, 24, 73, 10, 246, 188, 20, - 73, 208, 184, 5, 2, 69, 77, 191, 218, 6, 79, 4, 210, 163, 29, 73, 247, - 167, 3, 65, 4, 212, 155, 7, 8, 73, 78, 68, 69, 82, 71, 65, 82, 231, 189, - 22, 79, 6, 134, 188, 20, 65, 142, 141, 12, 79, 195, 83, 69, 8, 38, 69, - 182, 162, 32, 65, 191, 84, 79, 4, 160, 173, 32, 3, 68, 73, 67, 251, 15, - 84, 6, 26, 73, 171, 174, 32, 65, 4, 218, 155, 33, 71, 231, 19, 78, 2, - 153, 179, 28, 2, 85, 69, 8, 26, 69, 251, 154, 33, 73, 6, 142, 187, 20, - 83, 221, 253, 7, 2, 76, 73, 22, 90, 69, 38, 85, 144, 148, 14, 2, 67, 72, - 214, 166, 6, 79, 22, 80, 34, 84, 215, 252, 11, 73, 4, 246, 152, 10, 67, - 215, 215, 21, 86, 6, 226, 187, 20, 80, 166, 255, 1, 73, 139, 137, 11, 78, - 4, 218, 195, 33, 67, 3, 82, 98, 116, 8, 65, 84, 65, 75, 65, 78, 65, 32, - 133, 1, 16, 79, 82, 69, 65, 78, 32, 67, 72, 65, 82, 65, 67, 84, 69, 82, - 32, 94, 170, 229, 10, 72, 2, 75, 2, 77, 2, 78, 2, 82, 2, 83, 2, 84, 126, - 87, 46, 89, 246, 219, 22, 65, 2, 69, 2, 73, 2, 79, 3, 85, 4, 228, 138, - 16, 3, 74, 85, 69, 221, 151, 17, 4, 67, 72, 65, 77, 106, 158, 173, 27, - 65, 255, 129, 4, 69, 4, 100, 19, 85, 76, 84, 73, 80, 76, 73, 67, 65, 84, - 73, 79, 78, 32, 83, 73, 71, 78, 32, 243, 185, 31, 73, 2, 157, 84, 4, 87, - 73, 84, 72, 98, 50, 69, 46, 70, 98, 83, 94, 84, 191, 183, 20, 78, 6, 180, - 1, 3, 73, 71, 72, 199, 169, 25, 76, 30, 28, 3, 73, 70, 84, 35, 79, 6, - 214, 1, 89, 155, 233, 31, 69, 24, 142, 2, 82, 167, 183, 20, 85, 8, 40, 4, - 69, 86, 69, 78, 1, 2, 73, 88, 4, 11, 84, 4, 104, 2, 89, 32, 143, 233, 31, - 69, 52, 56, 2, 69, 78, 32, 4, 72, 73, 82, 84, 29, 2, 87, 69, 5, 11, 32, - 2, 247, 198, 25, 79, 24, 74, 89, 175, 232, 31, 69, 24, 26, 78, 215, 191, - 32, 76, 22, 17, 2, 84, 89, 23, 11, 32, 20, 72, 2, 79, 78, 154, 203, 31, - 70, 30, 83, 42, 84, 170, 86, 78, 235, 110, 69, 4, 210, 197, 25, 32, 235, - 245, 7, 69, 2, 129, 165, 31, 8, 32, 80, 79, 73, 78, 84, 69, 68, 8, 132, - 199, 17, 3, 79, 83, 84, 154, 246, 6, 65, 192, 204, 2, 8, 69, 82, 80, 69, - 78, 68, 73, 67, 139, 171, 4, 76, 4, 128, 250, 29, 3, 73, 78, 71, 171, - 170, 1, 69, 6, 52, 7, 82, 73, 65, 78, 71, 76, 69, 131, 175, 26, 73, 5, - 147, 147, 22, 32, 6, 44, 5, 72, 73, 84, 69, 32, 203, 184, 33, 90, 4, 142, - 217, 31, 66, 139, 25, 83, 6, 218, 160, 27, 77, 196, 178, 4, 6, 76, 65, - 84, 73, 79, 78, 225, 161, 1, 3, 83, 32, 84, 5, 225, 242, 31, 6, 32, 65, - 84, 32, 68, 85, 158, 18, 192, 1, 24, 67, 79, 77, 80, 65, 84, 73, 66, 73, - 76, 73, 84, 89, 32, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 144, 3, 8, - 82, 65, 68, 73, 67, 65, 76, 32, 245, 17, 7, 83, 84, 82, 79, 75, 69, 32, - 236, 15, 24, 2, 50, 70, 75, 70, 188, 8, 34, 65, 162, 246, 10, 56, 3, 57, - 60, 202, 1, 49, 135, 236, 18, 48, 176, 7, 26, 65, 227, 245, 10, 57, 176, - 3, 134, 1, 54, 134, 236, 18, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, - 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 139, 146, 9, 68, 28, 198, 179, 33, - 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, - 2, 66, 2, 67, 3, 68, 230, 1, 210, 1, 66, 126, 67, 226, 4, 68, 62, 69, 50, - 70, 34, 71, 50, 72, 86, 74, 154, 1, 76, 62, 77, 130, 1, 80, 46, 82, 78, - 83, 182, 3, 84, 82, 87, 168, 218, 10, 2, 78, 69, 144, 17, 4, 75, 78, 73, - 70, 251, 151, 12, 79, 14, 74, 79, 180, 250, 10, 4, 82, 85, 83, 72, 246, - 233, 4, 65, 251, 192, 13, 76, 6, 186, 161, 10, 76, 154, 248, 22, 78, 215, - 22, 88, 56, 104, 12, 45, 83, 73, 77, 80, 76, 73, 70, 73, 69, 68, 32, 162, - 3, 73, 50, 76, 158, 173, 32, 79, 191, 78, 72, 44, 114, 69, 38, 70, 50, - 71, 38, 76, 34, 83, 94, 84, 154, 199, 14, 87, 42, 68, 234, 226, 16, 66, - 222, 120, 72, 135, 2, 67, 4, 174, 218, 31, 86, 191, 183, 1, 65, 6, 210, - 197, 31, 73, 218, 214, 1, 76, 235, 16, 82, 4, 186, 143, 23, 79, 147, 215, - 8, 65, 4, 238, 171, 32, 69, 187, 48, 79, 10, 150, 219, 6, 73, 134, 186, - 17, 65, 198, 194, 1, 72, 248, 178, 7, 3, 80, 69, 69, 215, 11, 69, 6, 214, - 10, 85, 152, 176, 10, 2, 65, 78, 203, 158, 4, 79, 4, 140, 210, 20, 3, 86, - 73, 76, 151, 200, 12, 84, 4, 170, 214, 17, 73, 131, 193, 14, 79, 6, 216, - 148, 24, 2, 73, 86, 186, 241, 2, 69, 179, 164, 6, 79, 10, 196, 6, 2, 65, - 84, 194, 141, 33, 87, 3, 89, 4, 242, 137, 32, 73, 131, 80, 79, 8, 244, 5, - 4, 82, 65, 83, 83, 143, 186, 29, 72, 10, 48, 2, 69, 65, 146, 159, 28, 79, - 163, 252, 3, 65, 6, 186, 8, 82, 239, 160, 33, 68, 10, 72, 12, 45, 83, 73, - 77, 80, 76, 73, 70, 73, 69, 68, 32, 179, 152, 31, 65, 8, 42, 84, 174, - 195, 14, 68, 247, 244, 16, 69, 4, 194, 6, 85, 227, 206, 14, 79, 12, 248, - 241, 10, 3, 79, 78, 71, 197, 245, 15, 3, 65, 77, 69, 14, 18, 69, 35, 79, - 4, 242, 138, 33, 65, 159, 27, 83, 10, 136, 241, 10, 3, 85, 78, 68, 166, - 162, 13, 84, 162, 205, 7, 82, 211, 118, 79, 6, 188, 240, 10, 2, 65, 87, - 175, 182, 18, 69, 8, 34, 65, 169, 213, 28, 2, 69, 80, 6, 130, 214, 32, - 73, 226, 79, 77, 3, 80, 38, 122, 69, 90, 73, 186, 1, 78, 196, 1, 4, 80, - 73, 82, 73, 248, 234, 10, 4, 77, 65, 76, 76, 214, 149, 12, 72, 195, 208, - 9, 85, 8, 40, 4, 67, 79, 78, 68, 227, 154, 32, 65, 6, 11, 32, 6, 166, - 180, 31, 84, 183, 86, 79, 12, 60, 9, 77, 80, 76, 73, 70, 73, 69, 68, 32, - 147, 160, 33, 76, 10, 34, 72, 50, 87, 135, 182, 10, 89, 4, 140, 160, 10, - 3, 65, 76, 70, 223, 248, 17, 79, 4, 234, 208, 6, 65, 175, 129, 22, 72, 6, - 192, 1, 2, 79, 85, 151, 241, 32, 65, 8, 58, 85, 146, 217, 24, 65, 218, - 204, 1, 72, 147, 174, 3, 73, 2, 239, 134, 24, 82, 12, 26, 65, 49, 2, 69, - 83, 8, 164, 235, 10, 2, 76, 75, 1, 3, 84, 69, 82, 4, 247, 234, 10, 84, - 76, 110, 72, 182, 1, 80, 38, 83, 142, 163, 31, 84, 176, 250, 1, 2, 66, - 88, 2, 87, 2, 88, 86, 68, 2, 78, 3, 81, 31, 42, 80, 22, 88, 30, 90, 143, - 159, 33, 71, 5, 231, 158, 33, 87, 4, 210, 158, 33, 87, 87, 71, 19, 50, - 90, 194, 163, 31, 87, 154, 251, 1, 71, 3, 84, 9, 190, 163, 31, 90, 155, - 251, 1, 80, 9, 178, 158, 33, 68, 2, 71, 3, 90, 23, 50, 87, 30, 90, 194, - 157, 33, 71, 2, 80, 3, 84, 7, 218, 157, 33, 71, 3, 90, 9, 234, 156, 33, - 87, 86, 80, 3, 90, 124, 62, 65, 194, 1, 73, 114, 79, 181, 241, 20, 4, 69, - 65, 82, 32, 8, 132, 1, 2, 80, 80, 208, 231, 18, 6, 83, 83, 73, 67, 65, - 76, 169, 137, 13, 14, 77, 83, 72, 69, 76, 76, 32, 77, 79, 66, 73, 76, 69, - 32, 4, 196, 189, 19, 5, 73, 78, 71, 32, 72, 239, 227, 1, 69, 6, 48, 6, - 78, 75, 73, 78, 71, 32, 223, 131, 32, 80, 4, 190, 145, 25, 71, 181, 183, - 3, 6, 66, 69, 69, 82, 32, 77, 108, 72, 2, 67, 75, 140, 10, 2, 83, 69, - 236, 3, 2, 85, 68, 131, 153, 30, 87, 70, 64, 6, 32, 70, 65, 67, 69, 32, - 237, 2, 5, 87, 73, 83, 69, 32, 48, 58, 69, 46, 70, 36, 2, 78, 73, 2, 79, - 18, 83, 51, 84, 8, 120, 2, 76, 69, 125, 4, 73, 71, 72, 84, 8, 178, 1, 73, - 25, 3, 79, 85, 82, 4, 155, 1, 78, 8, 26, 69, 125, 2, 73, 88, 4, 57, 2, - 86, 69, 16, 38, 69, 14, 87, 41, 3, 72, 82, 69, 4, 63, 78, 8, 24, 2, 69, - 76, 27, 79, 4, 11, 86, 4, 11, 69, 4, 180, 252, 28, 2, 32, 79, 137, 173, - 2, 3, 45, 84, 72, 22, 90, 67, 58, 68, 122, 71, 48, 5, 82, 73, 71, 72, 84, - 226, 2, 84, 122, 79, 143, 137, 31, 73, 4, 196, 1, 3, 76, 79, 83, 141, 99, - 4, 79, 78, 84, 79, 2, 141, 3, 26, 79, 87, 78, 87, 65, 82, 68, 83, 32, 65, + 77, 0, 2, 81, 85, 2, 87, 2, 89, 162, 140, 34, 75, 186, 2, 65, 2, 69, 2, + 73, 2, 79, 2, 85, 3, 86, 14, 226, 142, 34, 76, 186, 2, 65, 2, 69, 2, 73, + 2, 79, 2, 85, 3, 86, 14, 154, 142, 34, 78, 186, 2, 65, 2, 69, 2, 73, 2, + 79, 2, 85, 3, 86, 14, 170, 255, 29, 65, 226, 144, 4, 69, 2, 73, 2, 79, 2, + 85, 3, 86, 15, 198, 143, 34, 65, 2, 69, 2, 73, 2, 79, 2, 85, 3, 86, 30, + 50, 76, 2, 83, 218, 142, 34, 65, 2, 69, 3, 73, 12, 214, 142, 34, 65, 2, + 69, 2, 73, 2, 79, 2, 85, 3, 86, 6, 32, 2, 89, 32, 247, 247, 32, 73, 4, + 40, 4, 66, 76, 79, 83, 163, 248, 32, 83, 2, 231, 252, 33, 83, 16, 152, 1, + 2, 76, 68, 48, 11, 78, 69, 83, 69, 32, 83, 77, 65, 76, 76, 32, 206, 247, + 7, 32, 184, 247, 2, 2, 80, 77, 228, 198, 21, 2, 67, 75, 155, 134, 1, 82, + 5, 173, 247, 28, 7, 82, 69, 78, 32, 67, 82, 79, 4, 248, 224, 19, 10, 83, + 73, 77, 80, 76, 73, 70, 73, 69, 68, 1, 11, 84, 82, 65, 68, 73, 84, 73, + 79, 78, 65, 76, 60, 92, 8, 82, 65, 83, 77, 73, 65, 78, 32, 254, 130, 5, + 80, 197, 141, 12, 5, 67, 79, 76, 65, 84, 56, 52, 7, 76, 69, 84, 84, 69, + 82, 32, 199, 214, 21, 78, 42, 224, 1, 6, 67, 85, 82, 76, 69, 68, 30, 83, + 158, 211, 21, 68, 34, 76, 134, 206, 1, 82, 142, 220, 2, 65, 50, 71, 90, + 90, 98, 89, 198, 207, 1, 72, 234, 5, 75, 174, 81, 66, 170, 225, 4, 78, + 134, 2, 84, 2, 87, 218, 103, 80, 171, 4, 77, 2, 209, 137, 33, 2, 32, 87, + 6, 132, 211, 21, 6, 77, 65, 76, 76, 32, 65, 232, 243, 5, 2, 65, 77, 163, + 193, 5, 72, 232, 4, 66, 78, 20, 2, 82, 67, 201, 40, 7, 84, 89, 83, 67, + 65, 80, 69, 2, 183, 229, 33, 69, 226, 4, 28, 2, 76, 69, 207, 39, 85, 220, + 4, 30, 32, 185, 6, 2, 68, 32, 24, 244, 1, 5, 87, 73, 84, 72, 32, 161, + 205, 18, 49, 68, 73, 86, 73, 68, 69, 68, 32, 66, 89, 32, 72, 79, 82, 73, + 90, 79, 78, 84, 65, 76, 32, 66, 65, 82, 32, 65, 78, 68, 32, 84, 79, 80, + 32, 72, 65, 76, 70, 32, 68, 73, 86, 73, 68, 69, 68, 32, 66, 89, 22, 146, + 2, 76, 46, 83, 108, 22, 84, 87, 79, 32, 72, 79, 82, 73, 90, 79, 78, 84, + 65, 76, 32, 83, 84, 82, 79, 75, 69, 83, 44, 6, 85, 80, 80, 69, 82, 32, + 44, 17, 65, 76, 76, 32, 66, 85, 84, 32, 85, 80, 80, 69, 82, 32, 76, 69, + 70, 190, 205, 26, 86, 242, 146, 4, 82, 183, 251, 1, 72, 4, 142, 226, 30, + 69, 49, 4, 79, 87, 69, 82, 4, 104, 11, 77, 65, 76, 76, 32, 67, 73, 82, + 67, 76, 69, 221, 5, 10, 85, 80, 69, 82, 73, 77, 80, 79, 83, 69, 2, 225, + 251, 30, 6, 32, 84, 79, 32, 84, 72, 4, 40, 4, 82, 73, 71, 72, 231, 224, + 30, 72, 2, 249, 224, 30, 10, 84, 32, 81, 85, 65, 68, 82, 65, 78, 84, 196, + 4, 230, 2, 65, 186, 1, 66, 58, 67, 230, 1, 68, 246, 1, 72, 230, 2, 73, + 194, 10, 75, 190, 2, 76, 38, 77, 136, 1, 7, 78, 85, 77, 66, 69, 82, 32, + 192, 4, 17, 79, 80, 69, 78, 32, 67, 69, 78, 84, 82, 69, 32, 69, 73, 71, + 72, 84, 54, 80, 114, 82, 50, 84, 78, 87, 192, 132, 10, 4, 90, 69, 82, 79, + 158, 196, 16, 69, 182, 188, 4, 86, 146, 68, 71, 150, 115, 83, 227, 162, + 1, 88, 6, 100, 12, 78, 84, 73, 67, 76, 79, 67, 75, 87, 73, 83, 69, 157, + 184, 30, 7, 83, 84, 69, 82, 73, 83, 75, 4, 212, 249, 8, 11, 45, 82, 79, + 84, 65, 84, 69, 68, 32, 68, 73, 191, 229, 23, 32, 4, 32, 2, 79, 76, 219, + 152, 32, 85, 2, 223, 221, 14, 68, 16, 60, 4, 82, 79, 83, 83, 210, 2, 32, + 202, 247, 33, 67, 3, 68, 10, 26, 32, 199, 197, 1, 73, 8, 64, 6, 70, 79, + 82, 77, 69, 69, 153, 135, 32, 4, 80, 79, 77, 77, 7, 33, 6, 32, 87, 73, + 84, 72, 32, 4, 158, 210, 31, 70, 135, 84, 84, 30, 34, 73, 70, 79, 135, + 141, 32, 65, 24, 168, 192, 4, 8, 86, 73, 83, 73, 79, 78, 32, 83, 183, + 196, 27, 71, 4, 64, 10, 76, 76, 65, 82, 32, 83, 73, 71, 78, 32, 135, 180, + 30, 84, 2, 173, 175, 19, 13, 87, 73, 84, 72, 32, 79, 86, 69, 82, 76, 65, + 73, 68, 64, 192, 1, 6, 65, 78, 71, 85, 76, 32, 252, 203, 12, 20, 79, 82, + 73, 90, 79, 78, 84, 65, 76, 32, 66, 65, 82, 32, 87, 73, 84, 72, 32, 78, + 204, 217, 9, 4, 85, 77, 65, 78, 145, 1, 4, 69, 65, 86, 89, 58, 110, 67, + 140, 207, 20, 5, 73, 69, 85, 78, 71, 42, 72, 30, 75, 66, 77, 34, 78, 34, + 80, 62, 82, 30, 83, 27, 84, 8, 234, 206, 20, 72, 157, 3, 4, 73, 69, 85, + 67, 116, 220, 1, 9, 68, 69, 79, 71, 82, 65, 80, 72, 32, 196, 8, 27, 84, + 65, 76, 73, 67, 32, 76, 65, 84, 73, 78, 32, 67, 65, 80, 73, 84, 65, 76, + 32, 76, 69, 84, 84, 69, 82, 32, 169, 162, 27, 9, 78, 70, 79, 82, 77, 65, + 84, 73, 79, 110, 174, 1, 65, 110, 67, 90, 69, 86, 70, 62, 72, 38, 75, 70, + 76, 50, 77, 86, 78, 62, 81, 30, 82, 74, 83, 198, 178, 6, 80, 162, 157, + 14, 84, 50, 87, 202, 215, 1, 73, 163, 168, 10, 79, 8, 242, 207, 20, 76, + 200, 134, 1, 3, 67, 67, 69, 184, 249, 6, 3, 84, 84, 69, 249, 17, 5, 68, + 86, 65, 78, 84, 8, 26, 79, 235, 234, 30, 69, 6, 236, 212, 10, 2, 82, 82, + 190, 250, 9, 78, 147, 143, 13, 80, 8, 190, 207, 20, 78, 174, 179, 9, 65, + 180, 169, 3, 5, 88, 67, 69, 76, 76, 231, 24, 73, 10, 202, 207, 20, 73, + 144, 190, 5, 2, 69, 77, 199, 232, 6, 79, 4, 146, 193, 29, 73, 211, 176, + 3, 65, 4, 228, 166, 7, 8, 73, 78, 68, 69, 82, 71, 65, 82, 167, 212, 22, + 79, 6, 218, 206, 20, 65, 214, 160, 12, 79, 195, 83, 69, 8, 38, 69, 190, + 198, 32, 65, 211, 86, 79, 4, 184, 209, 32, 3, 68, 73, 67, 227, 15, 84, 6, + 26, 73, 195, 210, 32, 65, 4, 246, 193, 33, 71, 231, 19, 78, 2, 233, 208, + 28, 2, 85, 69, 8, 26, 69, 151, 193, 33, 73, 6, 226, 205, 20, 83, 217, + 136, 8, 2, 76, 73, 22, 90, 69, 38, 85, 184, 161, 14, 2, 67, 72, 130, 172, + 6, 79, 22, 80, 34, 84, 131, 142, 12, 73, 4, 238, 164, 10, 67, 223, 239, + 21, 86, 6, 182, 206, 20, 80, 146, 128, 2, 73, 231, 155, 11, 78, 4, 246, + 233, 33, 67, 3, 82, 98, 116, 8, 65, 84, 65, 75, 65, 78, 65, 32, 133, 1, + 16, 79, 82, 69, 65, 78, 32, 67, 72, 65, 82, 65, 67, 84, 69, 82, 32, 94, + 166, 241, 10, 72, 2, 75, 2, 77, 2, 78, 2, 82, 2, 83, 2, 84, 126, 87, 46, + 89, 150, 246, 22, 65, 2, 69, 2, 73, 2, 79, 3, 85, 4, 152, 157, 16, 3, 74, + 85, 69, 197, 171, 17, 4, 67, 72, 65, 77, 106, 222, 196, 27, 65, 255, 140, + 4, 69, 4, 100, 19, 85, 76, 84, 73, 80, 76, 73, 67, 65, 84, 73, 79, 78, + 32, 83, 73, 71, 78, 32, 167, 221, 31, 73, 2, 209, 85, 4, 87, 73, 84, 72, + 98, 50, 69, 46, 70, 98, 83, 94, 84, 147, 202, 20, 78, 6, 180, 1, 3, 73, + 71, 72, 203, 193, 25, 76, 30, 28, 3, 73, 70, 84, 35, 79, 6, 214, 1, 89, + 155, 141, 32, 69, 24, 142, 2, 82, 251, 201, 20, 85, 8, 40, 4, 69, 86, 69, + 78, 1, 2, 73, 88, 4, 11, 84, 4, 104, 2, 89, 32, 143, 141, 32, 69, 52, 56, + 2, 69, 78, 32, 4, 72, 73, 82, 84, 29, 2, 87, 69, 5, 11, 32, 2, 139, 223, + 25, 79, 24, 74, 89, 175, 140, 32, 69, 24, 26, 78, 243, 229, 32, 76, 22, + 17, 2, 84, 89, 23, 11, 32, 20, 72, 2, 79, 78, 206, 238, 31, 70, 30, 83, + 42, 84, 142, 87, 78, 239, 112, 69, 4, 230, 221, 25, 32, 243, 131, 8, 69, + 2, 193, 199, 31, 8, 32, 80, 79, 73, 78, 84, 69, 68, 8, 248, 217, 17, 3, + 79, 83, 84, 190, 251, 6, 65, 228, 203, 2, 8, 69, 82, 80, 69, 78, 68, 73, + 67, 131, 183, 4, 76, 4, 200, 156, 30, 3, 73, 78, 71, 163, 170, 1, 69, 6, + 52, 7, 82, 73, 65, 78, 71, 76, 69, 143, 199, 26, 73, 5, 211, 166, 22, 32, + 6, 44, 5, 72, 73, 84, 69, 32, 231, 222, 33, 90, 4, 194, 252, 31, 66, 215, + 25, 83, 6, 154, 184, 27, 77, 184, 190, 4, 6, 76, 65, 84, 73, 79, 78, 201, + 164, 1, 3, 83, 32, 84, 5, 233, 150, 32, 6, 32, 65, 84, 32, 68, 85, 158, + 18, 192, 1, 24, 67, 79, 77, 80, 65, 84, 73, 66, 73, 76, 73, 84, 89, 32, + 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 144, 3, 8, 82, 65, 68, 73, 67, + 65, 76, 32, 245, 17, 7, 83, 84, 82, 79, 75, 69, 32, 236, 15, 24, 2, 50, + 70, 75, 70, 188, 8, 34, 65, 170, 130, 11, 56, 3, 57, 60, 202, 1, 49, 243, + 254, 18, 48, 176, 7, 26, 65, 235, 129, 11, 57, 176, 3, 134, 1, 54, 242, + 254, 18, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 2, 57, 2, + 65, 2, 66, 2, 67, 215, 156, 9, 68, 28, 226, 217, 33, 48, 2, 49, 2, 50, 2, + 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 3, 68, + 230, 1, 210, 1, 66, 126, 67, 226, 4, 68, 62, 69, 50, 70, 34, 71, 50, 72, + 86, 74, 154, 1, 76, 62, 77, 130, 1, 80, 46, 82, 78, 83, 182, 3, 84, 82, + 87, 164, 230, 10, 2, 78, 69, 156, 17, 4, 75, 78, 73, 70, 203, 160, 12, + 79, 14, 74, 79, 188, 134, 11, 4, 82, 85, 83, 72, 162, 240, 4, 65, 143, + 208, 13, 76, 6, 182, 173, 10, 76, 186, 146, 23, 78, 215, 22, 88, 56, 104, + 12, 45, 83, 73, 77, 80, 76, 73, 70, 73, 69, 68, 32, 162, 3, 73, 50, 76, + 186, 211, 32, 79, 191, 78, 72, 44, 114, 69, 38, 70, 50, 71, 38, 76, 34, + 83, 94, 84, 182, 217, 14, 87, 42, 68, 130, 244, 16, 66, 170, 121, 72, + 163, 4, 67, 4, 174, 254, 31, 86, 219, 185, 1, 65, 6, 134, 233, 31, 73, + 194, 217, 1, 76, 235, 16, 82, 4, 146, 164, 23, 79, 187, 230, 8, 65, 4, + 138, 210, 32, 69, 187, 48, 79, 10, 162, 230, 6, 73, 146, 199, 17, 65, + 194, 194, 1, 72, 128, 193, 7, 3, 80, 69, 69, 215, 11, 69, 6, 214, 10, 85, + 148, 188, 10, 2, 65, 78, 235, 164, 4, 79, 4, 128, 229, 20, 3, 86, 73, 76, + 191, 219, 12, 84, 4, 150, 233, 17, 73, 167, 210, 14, 79, 6, 240, 172, 24, + 2, 73, 86, 222, 240, 2, 69, 147, 179, 6, 79, 10, 196, 6, 2, 65, 84, 222, + 179, 33, 87, 3, 89, 4, 138, 174, 32, 73, 135, 82, 79, 8, 244, 5, 4, 82, + 65, 83, 83, 179, 220, 29, 72, 10, 48, 2, 69, 65, 226, 188, 28, 79, 211, + 130, 4, 65, 6, 186, 8, 82, 139, 199, 33, 68, 10, 72, 12, 45, 83, 73, 77, + 80, 76, 73, 70, 73, 69, 68, 32, 231, 187, 31, 65, 8, 42, 84, 202, 213, + 14, 68, 143, 134, 17, 69, 4, 194, 6, 85, 255, 224, 14, 79, 12, 128, 254, + 10, 3, 79, 78, 71, 205, 129, 16, 3, 65, 77, 69, 14, 18, 69, 35, 79, 4, + 142, 177, 33, 65, 159, 27, 83, 10, 144, 253, 10, 3, 85, 78, 68, 182, 174, + 13, 84, 138, 217, 7, 82, 239, 120, 79, 6, 196, 252, 10, 2, 65, 87, 239, + 203, 18, 69, 8, 34, 65, 197, 194, 32, 2, 69, 80, 6, 158, 252, 32, 73, + 226, 79, 77, 3, 80, 38, 122, 69, 90, 73, 186, 1, 78, 196, 1, 4, 80, 73, + 82, 73, 128, 247, 10, 4, 77, 65, 76, 76, 166, 158, 12, 72, 135, 226, 9, + 85, 8, 40, 4, 67, 79, 78, 68, 227, 190, 32, 65, 6, 11, 32, 6, 218, 215, + 31, 84, 155, 87, 79, 12, 60, 9, 77, 80, 76, 73, 70, 73, 69, 68, 32, 175, + 198, 33, 76, 10, 34, 72, 50, 87, 131, 194, 10, 89, 4, 136, 172, 10, 3, + 65, 76, 70, 179, 138, 18, 79, 4, 246, 219, 6, 65, 191, 227, 25, 72, 6, + 192, 1, 2, 79, 85, 179, 151, 33, 65, 8, 58, 85, 150, 241, 24, 65, 242, + 204, 1, 72, 191, 184, 3, 73, 2, 135, 159, 24, 82, 12, 26, 65, 49, 2, 69, + 83, 8, 172, 247, 10, 2, 76, 75, 1, 3, 84, 69, 82, 4, 255, 246, 10, 84, + 76, 110, 72, 182, 1, 80, 38, 83, 194, 198, 31, 84, 152, 253, 1, 2, 66, + 88, 2, 87, 2, 88, 86, 68, 2, 78, 3, 81, 31, 42, 80, 22, 88, 30, 90, 171, + 197, 33, 71, 5, 131, 197, 33, 87, 4, 238, 196, 33, 87, 87, 71, 19, 50, + 90, 246, 198, 31, 87, 130, 254, 1, 71, 3, 84, 9, 242, 198, 31, 90, 131, + 254, 1, 80, 9, 206, 196, 33, 68, 2, 71, 3, 90, 23, 50, 87, 30, 90, 222, + 195, 33, 71, 2, 80, 3, 84, 7, 246, 195, 33, 71, 3, 90, 9, 134, 195, 33, + 87, 86, 80, 3, 90, 124, 62, 65, 194, 1, 73, 114, 79, 181, 132, 21, 4, 69, + 65, 82, 32, 8, 132, 1, 2, 80, 80, 128, 217, 3, 6, 83, 83, 73, 67, 65, 76, + 129, 188, 28, 14, 77, 83, 72, 69, 76, 76, 32, 77, 79, 66, 73, 76, 69, 32, + 4, 180, 208, 19, 5, 73, 78, 71, 32, 72, 227, 228, 1, 69, 6, 48, 6, 78, + 75, 73, 78, 71, 32, 247, 167, 32, 80, 4, 194, 169, 25, 71, 149, 189, 3, + 6, 66, 69, 69, 82, 32, 77, 108, 72, 2, 67, 75, 140, 10, 2, 83, 69, 236, + 3, 2, 85, 68, 207, 187, 30, 87, 70, 64, 6, 32, 70, 65, 67, 69, 32, 237, + 2, 5, 87, 73, 83, 69, 32, 48, 58, 69, 46, 70, 36, 2, 78, 73, 2, 79, 18, + 83, 51, 84, 8, 120, 2, 76, 69, 125, 4, 73, 71, 72, 84, 8, 178, 1, 73, 25, + 3, 79, 85, 82, 4, 155, 1, 78, 8, 26, 69, 125, 2, 73, 88, 4, 57, 2, 86, + 69, 16, 38, 69, 14, 87, 41, 3, 72, 82, 69, 4, 63, 78, 8, 24, 2, 69, 76, + 27, 79, 4, 11, 86, 4, 11, 69, 4, 176, 153, 29, 2, 32, 79, 193, 179, 2, 3, + 45, 84, 72, 22, 90, 67, 58, 68, 122, 71, 48, 5, 82, 73, 71, 72, 84, 226, + 2, 84, 122, 79, 195, 172, 31, 73, 4, 196, 1, 3, 76, 79, 83, 181, 103, 4, + 79, 78, 84, 79, 2, 141, 3, 26, 79, 87, 78, 87, 65, 82, 68, 83, 32, 65, 78, 68, 32, 85, 80, 87, 65, 82, 68, 83, 32, 79, 80, 69, 78, 32, 2, 21, 3, 65, 80, 80, 2, 133, 4, 2, 69, 68, 6, 228, 1, 14, 32, 65, 78, 68, 32, 76, 69, 70, 84, 32, 83, 69, 77, 73, 45, 38, 87, 65, 82, 68, 83, 32, 65, 78, 68, 32, 76, 69, 70, 84, 87, 65, 82, 68, 83, 32, 79, 80, 69, 78, 32, 67, - 73, 82, 67, 76, 69, 32, 65, 82, 82, 79, 87, 83, 2, 185, 182, 30, 6, 67, - 73, 82, 67, 76, 69, 5, 161, 83, 15, 32, 87, 73, 84, 72, 32, 67, 73, 82, + 73, 82, 67, 76, 69, 32, 65, 82, 82, 79, 87, 83, 2, 133, 217, 30, 6, 67, + 73, 82, 67, 76, 69, 5, 253, 85, 15, 32, 87, 73, 84, 72, 32, 67, 73, 82, 67, 76, 69, 68, 32, 79, 4, 82, 79, 37, 16, 82, 73, 65, 78, 71, 76, 69, 45, 72, 69, 65, 68, 69, 68, 32, 79, 2, 69, 6, 80, 32, 83, 69, 77, 73, 2, - 21, 3, 80, 69, 78, 2, 11, 32, 2, 217, 180, 30, 4, 67, 73, 82, 67, 26, 32, - 2, 68, 32, 191, 153, 32, 32, 24, 216, 1, 2, 83, 85, 66, 85, 178, 175, 19, - 77, 180, 3, 9, 76, 79, 67, 75, 32, 87, 73, 84, 72, 222, 134, 12, 66, 249, - 149, 1, 23, 73, 78, 84, 69, 82, 83, 69, 67, 84, 73, 79, 78, 32, 87, 73, - 84, 72, 32, 83, 69, 82, 73, 70, 8, 30, 66, 1, 3, 80, 69, 82, 4, 181, 252, - 24, 3, 83, 69, 84, 6, 82, 77, 33, 16, 78, 73, 79, 78, 32, 87, 73, 84, 72, - 32, 83, 69, 82, 73, 70, 83, 2, 145, 223, 24, 3, 66, 82, 69, 5, 237, 252, - 31, 9, 32, 65, 78, 68, 32, 83, 77, 65, 83, 11, 33, 6, 32, 87, 73, 84, 72, - 32, 8, 72, 4, 84, 79, 82, 78, 214, 167, 5, 76, 206, 220, 19, 83, 135, - 218, 6, 82, 2, 203, 217, 25, 65, 226, 9, 158, 1, 67, 82, 76, 98, 77, 162, - 82, 78, 220, 5, 2, 79, 75, 58, 80, 150, 19, 82, 138, 1, 85, 170, 253, 27, - 87, 196, 158, 3, 2, 70, 70, 246, 47, 73, 183, 51, 65, 6, 26, 75, 203, - 148, 4, 79, 4, 142, 233, 8, 82, 189, 136, 23, 4, 84, 65, 73, 76, 8, 44, - 2, 79, 78, 165, 134, 25, 3, 76, 73, 83, 7, 11, 32, 4, 138, 128, 26, 69, - 195, 129, 6, 83, 158, 6, 72, 7, 66, 73, 78, 73, 78, 71, 32, 166, 80, 77, - 94, 80, 151, 154, 32, 69, 142, 6, 214, 2, 65, 174, 2, 66, 134, 1, 67, - 246, 12, 68, 174, 9, 69, 146, 2, 70, 54, 71, 140, 9, 2, 72, 79, 82, 73, - 216, 1, 2, 75, 65, 162, 1, 76, 230, 13, 77, 250, 1, 78, 78, 79, 138, 2, - 80, 174, 1, 82, 244, 4, 5, 90, 73, 71, 90, 65, 166, 2, 83, 242, 3, 84, - 238, 2, 85, 148, 1, 9, 86, 69, 82, 84, 73, 67, 65, 76, 32, 36, 2, 87, 73, - 183, 1, 88, 24, 148, 1, 4, 67, 85, 84, 69, 86, 78, 252, 131, 25, 6, 83, - 84, 69, 82, 73, 83, 197, 224, 5, 14, 76, 77, 79, 83, 84, 32, 69, 81, 85, - 65, 76, 32, 84, 79, 10, 22, 45, 167, 33, 32, 4, 200, 204, 12, 6, 71, 82, - 65, 86, 69, 45, 199, 205, 3, 77, 6, 244, 2, 4, 84, 73, 67, 76, 189, 179, - 3, 4, 78, 85, 73, 84, 12, 42, 82, 201, 212, 30, 4, 73, 78, 68, 85, 10, - 48, 3, 69, 86, 69, 149, 227, 30, 3, 73, 68, 71, 7, 166, 164, 12, 45, 251, - 175, 18, 32, 142, 1, 142, 1, 65, 34, 76, 98, 79, 116, 8, 89, 82, 73, 76, - 76, 73, 67, 32, 184, 28, 11, 73, 82, 67, 85, 77, 70, 76, 69, 88, 32, 65, - 195, 150, 12, 69, 6, 162, 18, 82, 215, 217, 28, 78, 4, 41, 8, 79, 67, 75, - 87, 73, 83, 69, 32, 4, 204, 171, 12, 4, 82, 73, 78, 71, 231, 218, 16, 65, - 10, 76, 4, 77, 77, 65, 32, 189, 16, 10, 78, 74, 79, 73, 78, 73, 78, 71, - 32, 77, 6, 210, 147, 13, 65, 239, 204, 17, 66, 116, 252, 1, 8, 72, 85, + 21, 3, 80, 69, 78, 2, 11, 32, 2, 165, 215, 30, 4, 67, 73, 82, 67, 26, 32, + 2, 68, 32, 219, 191, 32, 32, 24, 216, 1, 2, 83, 85, 66, 85, 162, 194, 19, + 77, 180, 3, 9, 76, 79, 67, 75, 32, 87, 73, 84, 72, 238, 151, 12, 66, 149, + 152, 1, 23, 73, 78, 84, 69, 82, 83, 69, 67, 84, 73, 79, 78, 32, 87, 73, + 84, 72, 32, 83, 69, 82, 73, 70, 8, 30, 66, 1, 3, 80, 69, 82, 4, 185, 148, + 25, 3, 83, 69, 84, 6, 82, 77, 33, 16, 78, 73, 79, 78, 32, 87, 73, 84, 72, + 32, 83, 69, 82, 73, 70, 83, 2, 149, 247, 24, 3, 66, 82, 69, 5, 237, 160, + 32, 9, 32, 65, 78, 68, 32, 83, 77, 65, 83, 11, 33, 6, 32, 87, 73, 84, 72, + 32, 8, 72, 4, 84, 79, 82, 78, 190, 172, 5, 76, 250, 239, 19, 83, 251, + 229, 6, 82, 2, 211, 241, 25, 65, 152, 10, 158, 1, 67, 82, 76, 98, 77, + 202, 86, 78, 220, 5, 2, 79, 75, 58, 80, 154, 19, 82, 138, 1, 85, 246, + 149, 28, 87, 232, 167, 3, 2, 70, 70, 246, 47, 73, 183, 51, 65, 6, 26, 75, + 155, 153, 4, 79, 4, 202, 244, 8, 82, 153, 161, 23, 4, 84, 65, 73, 76, 8, + 44, 2, 79, 78, 185, 158, 25, 3, 76, 73, 83, 7, 11, 32, 4, 150, 152, 26, + 69, 211, 143, 6, 83, 212, 6, 72, 7, 66, 73, 78, 73, 78, 71, 32, 206, 84, + 77, 94, 80, 139, 188, 32, 69, 196, 6, 210, 2, 65, 186, 2, 66, 118, 67, + 246, 12, 68, 226, 10, 69, 142, 2, 70, 70, 71, 156, 9, 2, 72, 79, 82, 73, + 248, 1, 2, 75, 65, 162, 1, 76, 158, 14, 77, 178, 2, 78, 78, 79, 138, 2, + 80, 182, 1, 82, 248, 4, 5, 90, 73, 71, 90, 65, 138, 2, 83, 162, 4, 84, + 238, 2, 85, 168, 1, 8, 86, 69, 82, 84, 73, 67, 65, 76, 204, 1, 2, 87, 73, + 171, 1, 88, 26, 148, 1, 4, 67, 85, 84, 69, 98, 78, 136, 156, 25, 6, 83, + 84, 69, 82, 73, 83, 241, 234, 5, 14, 76, 77, 79, 83, 84, 32, 69, 81, 85, + 65, 76, 32, 84, 79, 12, 22, 45, 231, 34, 32, 6, 186, 57, 86, 184, 160, + 12, 6, 71, 82, 65, 86, 69, 45, 251, 210, 3, 77, 6, 228, 2, 4, 84, 73, 67, + 76, 237, 183, 3, 4, 78, 85, 73, 84, 12, 42, 82, 137, 247, 30, 4, 73, 78, + 68, 85, 10, 32, 3, 69, 86, 69, 243, 37, 73, 7, 210, 177, 12, 45, 159, + 197, 18, 32, 142, 1, 142, 1, 65, 34, 76, 98, 79, 116, 8, 89, 82, 73, 76, + 76, 73, 67, 32, 252, 29, 11, 73, 82, 67, 85, 77, 70, 76, 69, 88, 32, 65, + 171, 162, 12, 69, 6, 222, 19, 82, 159, 245, 28, 78, 4, 41, 8, 79, 67, 75, + 87, 73, 83, 69, 32, 4, 248, 184, 12, 4, 82, 73, 78, 71, 139, 239, 16, 65, + 10, 76, 4, 77, 77, 65, 32, 249, 17, 10, 78, 74, 79, 73, 78, 73, 78, 71, + 32, 77, 6, 142, 161, 13, 65, 251, 225, 17, 66, 116, 252, 1, 8, 72, 85, 78, 68, 82, 69, 68, 32, 32, 7, 76, 69, 84, 84, 69, 82, 32, 166, 5, 80, - 116, 5, 68, 65, 83, 73, 65, 38, 84, 106, 77, 178, 243, 2, 75, 176, 138, - 13, 15, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 66, 89, 229, - 193, 16, 2, 86, 90, 4, 194, 7, 77, 195, 158, 3, 84, 84, 238, 1, 66, 38, - 68, 50, 69, 82, 73, 106, 79, 22, 83, 66, 85, 30, 89, 186, 137, 3, 76, - 140, 5, 5, 77, 79, 78, 79, 71, 150, 18, 72, 238, 226, 12, 84, 190, 243, - 15, 90, 150, 83, 67, 2, 71, 182, 8, 70, 134, 14, 80, 2, 86, 158, 20, 75, - 187, 2, 65, 4, 250, 161, 6, 73, 163, 216, 26, 69, 4, 248, 233, 25, 3, 74, - 69, 82, 255, 143, 7, 69, 14, 58, 83, 142, 249, 32, 70, 2, 76, 2, 77, 2, - 78, 3, 82, 5, 147, 178, 31, 45, 11, 56, 8, 79, 84, 73, 70, 73, 69, 68, - 32, 191, 248, 32, 69, 6, 142, 160, 6, 66, 174, 216, 26, 65, 3, 69, 5, - 159, 193, 25, 77, 6, 26, 72, 171, 133, 16, 79, 4, 158, 253, 30, 67, 195, - 250, 1, 65, 5, 173, 153, 3, 2, 75, 82, 8, 254, 189, 28, 69, 246, 156, 4, - 65, 174, 28, 73, 3, 85, 8, 66, 65, 48, 4, 83, 73, 76, 73, 189, 195, 29, - 4, 79, 75, 82, 89, 4, 142, 246, 2, 89, 133, 228, 12, 3, 76, 65, 84, 2, - 145, 13, 5, 32, 80, 78, 69, 85, 10, 80, 2, 69, 78, 0, 7, 72, 79, 85, 83, - 65, 78, 68, 177, 8, 4, 73, 84, 76, 79, 2, 17, 2, 32, 77, 2, 129, 235, 21, - 5, 73, 76, 76, 73, 79, 110, 62, 69, 244, 1, 8, 73, 65, 69, 82, 69, 83, - 73, 83, 39, 79, 38, 68, 9, 86, 65, 78, 65, 71, 65, 82, 73, 32, 145, 138, - 32, 2, 76, 69, 36, 92, 7, 76, 69, 84, 84, 69, 82, 32, 216, 131, 26, 6, - 83, 73, 71, 78, 32, 65, 227, 253, 4, 68, 14, 254, 222, 32, 86, 162, 17, - 75, 2, 78, 2, 80, 2, 82, 186, 2, 65, 3, 85, 7, 146, 229, 27, 45, 195, - 223, 2, 32, 66, 58, 84, 128, 1, 4, 85, 66, 76, 69, 241, 4, 2, 87, 78, 14, - 38, 32, 173, 139, 16, 3, 84, 69, 68, 10, 64, 5, 65, 66, 79, 86, 69, 197, - 179, 6, 5, 66, 69, 76, 79, 87, 7, 191, 197, 32, 32, 48, 22, 32, 191, 4, - 68, 46, 230, 1, 66, 0, 10, 73, 78, 86, 69, 82, 84, 69, 68, 32, 66, 26, + 116, 5, 68, 65, 83, 73, 65, 38, 84, 106, 77, 230, 247, 2, 75, 220, 152, + 13, 15, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 66, 89, 169, + 213, 16, 2, 86, 90, 4, 194, 7, 77, 247, 162, 3, 84, 84, 238, 1, 66, 38, + 68, 50, 69, 82, 73, 106, 79, 22, 83, 66, 85, 30, 89, 238, 141, 3, 76, + 140, 5, 5, 77, 79, 78, 79, 71, 150, 18, 72, 154, 241, 12, 84, 130, 135, + 16, 90, 150, 83, 67, 2, 71, 182, 8, 70, 134, 14, 80, 2, 86, 158, 20, 75, + 187, 2, 65, 4, 142, 173, 6, 73, 179, 243, 26, 69, 4, 136, 130, 26, 3, 74, + 69, 82, 147, 158, 7, 69, 14, 58, 83, 178, 159, 33, 70, 2, 76, 2, 77, 2, + 78, 3, 82, 5, 155, 214, 31, 45, 11, 56, 8, 79, 84, 73, 70, 73, 69, 68, + 32, 227, 158, 33, 69, 6, 162, 171, 6, 66, 190, 243, 26, 65, 3, 69, 5, + 175, 217, 25, 77, 6, 26, 72, 139, 152, 16, 79, 4, 218, 160, 31, 67, 171, + 253, 1, 65, 5, 225, 157, 3, 2, 75, 82, 8, 198, 219, 28, 69, 210, 165, 4, + 65, 174, 28, 73, 3, 85, 8, 66, 65, 48, 4, 83, 73, 76, 73, 141, 230, 29, + 4, 79, 75, 82, 89, 4, 194, 250, 2, 89, 169, 242, 12, 3, 76, 65, 84, 2, + 209, 14, 5, 32, 80, 78, 69, 85, 10, 80, 2, 69, 78, 0, 7, 72, 79, 85, 83, + 65, 78, 68, 237, 9, 4, 73, 84, 76, 79, 2, 17, 2, 32, 77, 2, 201, 254, 21, + 5, 73, 76, 76, 73, 79, 124, 66, 69, 244, 1, 8, 73, 65, 69, 82, 69, 83, + 73, 83, 131, 1, 79, 38, 68, 9, 86, 65, 78, 65, 71, 65, 82, 73, 32, 177, + 176, 32, 2, 76, 69, 36, 92, 7, 76, 69, 84, 84, 69, 82, 32, 248, 155, 26, + 6, 83, 73, 71, 78, 32, 65, 251, 136, 5, 68, 14, 158, 133, 33, 86, 162, + 17, 75, 2, 78, 2, 80, 2, 82, 186, 2, 65, 3, 85, 9, 26, 32, 207, 130, 28, + 45, 4, 162, 246, 30, 66, 189, 142, 1, 16, 87, 73, 84, 72, 32, 82, 65, 73, + 83, 69, 68, 32, 76, 69, 70, 84, 78, 58, 84, 164, 1, 4, 85, 66, 76, 69, + 169, 5, 2, 87, 78, 16, 74, 32, 232, 186, 10, 5, 45, 65, 78, 68, 45, 161, + 226, 5, 3, 84, 69, 68, 10, 64, 5, 65, 66, 79, 86, 69, 217, 189, 6, 5, 66, + 69, 76, 79, 87, 7, 223, 234, 32, 32, 56, 22, 32, 247, 4, 68, 54, 222, 1, + 65, 34, 66, 0, 10, 73, 78, 86, 69, 82, 84, 69, 68, 32, 66, 26, 67, 34, 77, 54, 79, 34, 80, 68, 2, 82, 73, 48, 5, 84, 73, 76, 68, 69, 80, 9, 86, - 69, 82, 84, 73, 67, 65, 76, 32, 198, 134, 16, 65, 42, 71, 150, 187, 4, - 76, 203, 172, 11, 67, 4, 229, 16, 2, 82, 69, 4, 21, 3, 65, 67, 82, 4, - 229, 245, 16, 2, 79, 78, 4, 230, 35, 80, 163, 226, 30, 86, 6, 238, 36, - 76, 253, 224, 7, 9, 65, 82, 69, 78, 84, 72, 69, 83, 69, 4, 156, 51, 4, - 71, 72, 84, 87, 207, 248, 9, 78, 7, 11, 32, 4, 44, 3, 76, 69, 70, 1, 4, - 82, 73, 71, 72, 2, 199, 203, 30, 84, 6, 198, 151, 12, 83, 151, 177, 14, - 76, 2, 165, 129, 16, 2, 32, 67, 4, 128, 41, 2, 32, 84, 243, 162, 31, 87, - 16, 76, 9, 78, 67, 76, 79, 83, 73, 78, 71, 32, 205, 152, 26, 4, 81, 85, - 65, 76, 14, 132, 1, 6, 67, 73, 82, 67, 76, 69, 22, 83, 164, 160, 6, 3, - 75, 69, 89, 228, 203, 19, 7, 85, 80, 87, 65, 82, 68, 32, 191, 192, 5, 68, - 5, 175, 180, 18, 32, 4, 214, 216, 25, 67, 131, 240, 5, 81, 4, 32, 2, 69, - 82, 159, 142, 5, 79, 2, 139, 74, 77, 126, 88, 17, 76, 65, 71, 79, 76, 73, - 84, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 143, 3, 82, 76, 238, 1, 68, - 30, 73, 46, 83, 50, 84, 130, 137, 6, 65, 22, 66, 94, 67, 134, 1, 70, 38, - 71, 238, 2, 77, 32, 2, 76, 74, 34, 78, 88, 2, 80, 79, 30, 82, 194, 2, 86, - 22, 89, 90, 90, 226, 132, 19, 72, 174, 128, 2, 85, 170, 168, 5, 79, 235, - 5, 75, 4, 186, 139, 6, 74, 31, 79, 11, 198, 140, 6, 78, 54, 79, 227, 171, - 26, 90, 8, 166, 141, 6, 77, 130, 4, 76, 211, 200, 22, 72, 4, 218, 145, 6, - 86, 219, 191, 26, 83, 50, 38, 65, 173, 3, 4, 69, 69, 75, 32, 36, 84, 5, - 78, 84, 72, 65, 32, 196, 1, 2, 86, 69, 133, 188, 28, 5, 80, 72, 69, 77, - 69, 24, 68, 6, 68, 73, 71, 73, 84, 32, 65, 7, 76, 69, 84, 84, 69, 82, 32, - 14, 250, 229, 16, 83, 130, 141, 14, 70, 70, 84, 62, 90, 251, 85, 79, 10, - 134, 207, 32, 86, 162, 17, 75, 2, 78, 2, 80, 187, 2, 65, 10, 18, 32, 67, - 45, 6, 26, 65, 231, 166, 16, 84, 4, 209, 144, 4, 4, 67, 67, 69, 78, 4, - 212, 132, 12, 6, 65, 67, 85, 84, 69, 45, 215, 243, 3, 77, 14, 148, 1, 8, - 77, 85, 83, 73, 67, 65, 76, 32, 242, 151, 4, 75, 242, 195, 2, 80, 174, 4, - 89, 225, 238, 3, 11, 68, 73, 65, 76, 89, 84, 73, 75, 65, 32, 84, 6, 26, - 84, 247, 186, 15, 80, 4, 206, 187, 15, 69, 35, 82, 6, 166, 246, 12, 79, - 152, 236, 18, 8, 77, 79, 84, 72, 69, 84, 73, 67, 167, 45, 82, 14, 26, 78, - 151, 177, 30, 83, 12, 52, 7, 86, 69, 82, 84, 69, 68, 32, 251, 181, 28, - 70, 10, 64, 2, 66, 82, 45, 10, 68, 79, 85, 66, 76, 69, 32, 65, 82, 67, 6, - 22, 69, 235, 37, 73, 4, 219, 221, 11, 86, 4, 247, 190, 30, 72, 8, 128, 1, - 16, 84, 65, 75, 65, 78, 65, 45, 72, 73, 82, 65, 71, 65, 78, 65, 32, 229, - 233, 17, 9, 86, 89, 75, 65, 32, 65, 66, 79, 86, 4, 222, 129, 10, 83, 35, - 86, 158, 1, 80, 5, 65, 84, 73, 78, 32, 156, 8, 3, 69, 70, 84, 184, 3, 2, - 73, 71, 83, 79, 106, 156, 1, 21, 76, 69, 84, 84, 69, 82, 32, 83, 77, 65, - 76, 76, 32, 67, 65, 80, 73, 84, 65, 76, 32, 53, 13, 83, 77, 65, 76, 76, - 32, 76, 69, 84, 84, 69, 82, 32, 10, 130, 218, 32, 71, 2, 76, 2, 77, 2, - 78, 3, 82, 96, 226, 1, 65, 70, 67, 34, 69, 30, 70, 78, 73, 86, 76, 106, - 79, 2, 85, 134, 1, 82, 50, 84, 226, 171, 12, 83, 182, 146, 2, 66, 138, - 157, 2, 87, 150, 248, 15, 68, 2, 71, 2, 72, 2, 75, 2, 77, 2, 78, 2, 80, - 2, 86, 2, 88, 3, 90, 13, 242, 243, 2, 32, 198, 139, 26, 76, 182, 216, 3, - 69, 2, 79, 3, 86, 5, 241, 139, 12, 3, 32, 67, 69, 7, 246, 213, 32, 83, 3, - 84, 5, 249, 179, 27, 14, 76, 65, 84, 84, 69, 78, 69, 68, 32, 79, 80, 69, - 78, 32, 11, 37, 7, 78, 83, 85, 76, 65, 82, 32, 8, 246, 213, 32, 68, 2, - 71, 2, 82, 3, 84, 7, 164, 134, 16, 14, 32, 87, 73, 84, 72, 32, 68, 79, - 85, 66, 76, 69, 32, 77, 149, 218, 12, 3, 79, 78, 71, 7, 33, 6, 32, 87, - 73, 84, 72, 32, 4, 214, 155, 12, 68, 225, 222, 12, 15, 76, 73, 71, 72, - 84, 32, 67, 69, 78, 84, 82, 65, 76, 73, 90, 7, 11, 32, 4, 150, 250, 11, - 82, 175, 187, 18, 66, 5, 129, 26, 6, 85, 82, 78, 69, 68, 32, 32, 46, 32, - 213, 2, 6, 87, 65, 82, 68, 83, 32, 28, 154, 1, 65, 112, 12, 80, 65, 82, - 69, 78, 84, 72, 69, 83, 73, 83, 32, 226, 12, 72, 182, 1, 84, 129, 164, - 30, 11, 82, 73, 71, 72, 84, 32, 65, 82, 82, 79, 87, 12, 48, 4, 82, 82, - 79, 87, 185, 178, 30, 2, 78, 71, 8, 26, 72, 195, 178, 30, 32, 4, 177, - 178, 30, 3, 69, 65, 68, 4, 164, 223, 7, 4, 65, 66, 79, 86, 225, 190, 24, - 5, 66, 69, 76, 79, 87, 4, 230, 13, 72, 153, 238, 11, 5, 65, 82, 82, 79, - 87, 10, 52, 6, 65, 84, 85, 82, 69, 32, 169, 17, 2, 72, 84, 8, 238, 1, 76, - 23, 82, 10, 36, 3, 78, 71, 32, 139, 181, 31, 87, 8, 172, 7, 7, 68, 79, - 85, 66, 76, 69, 32, 246, 7, 83, 71, 86, 20, 52, 5, 65, 67, 82, 79, 78, - 221, 251, 25, 2, 73, 78, 19, 18, 32, 127, 45, 10, 34, 76, 22, 82, 135, - 175, 30, 66, 4, 41, 2, 69, 70, 4, 21, 3, 73, 71, 72, 4, 229, 212, 16, 6, - 84, 32, 72, 65, 76, 70, 6, 186, 158, 12, 71, 186, 2, 65, 135, 169, 3, 66, - 4, 152, 9, 9, 85, 77, 66, 69, 82, 32, 83, 73, 71, 181, 213, 11, 2, 79, - 84, 18, 136, 1, 17, 76, 68, 32, 80, 69, 82, 77, 73, 67, 32, 76, 69, 84, - 84, 69, 82, 32, 82, 80, 140, 156, 12, 4, 71, 79, 78, 69, 151, 198, 18, - 86, 10, 242, 43, 90, 202, 148, 18, 78, 222, 155, 9, 68, 182, 171, 2, 83, - 159, 243, 1, 65, 2, 169, 203, 24, 6, 69, 78, 32, 77, 65, 82, 12, 18, 65, - 107, 76, 8, 236, 7, 9, 82, 69, 78, 84, 72, 69, 83, 69, 83, 225, 194, 24, - 9, 76, 65, 84, 65, 76, 73, 90, 69, 68, 4, 149, 170, 30, 7, 85, 83, 32, - 83, 73, 71, 78, 38, 18, 69, 127, 73, 6, 72, 5, 86, 69, 82, 83, 69, 217, - 200, 24, 7, 84, 82, 79, 70, 76, 69, 88, 4, 22, 32, 227, 12, 68, 2, 141, - 8, 2, 83, 79, 32, 40, 3, 71, 72, 84, 157, 5, 2, 78, 71, 26, 50, 32, 149, - 4, 7, 87, 65, 82, 68, 83, 32, 72, 24, 104, 5, 65, 82, 82, 79, 87, 218, 1, - 72, 124, 12, 80, 65, 82, 69, 78, 84, 72, 69, 83, 73, 83, 32, 59, 84, 12, - 44, 5, 72, 69, 65, 68, 32, 235, 166, 30, 32, 8, 26, 65, 235, 166, 30, 66, - 6, 36, 3, 78, 68, 32, 243, 199, 31, 66, 4, 40, 4, 68, 79, 87, 78, 1, 2, - 85, 80, 2, 133, 223, 8, 9, 32, 65, 82, 82, 79, 87, 72, 69, 65, 6, 11, 65, - 6, 48, 6, 76, 70, 32, 82, 73, 78, 21, 2, 82, 80, 4, 243, 164, 30, 71, 2, - 17, 2, 79, 79, 2, 255, 197, 31, 78, 4, 250, 218, 9, 65, 241, 150, 21, 5, - 66, 69, 76, 79, 87, 2, 233, 195, 24, 2, 65, 67, 2, 141, 144, 21, 16, 65, - 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, 32, 66, 65, 82, 66, 6, 11, 32, 6, - 202, 237, 11, 79, 226, 181, 18, 66, 167, 161, 1, 65, 18, 188, 1, 5, 72, - 79, 82, 84, 32, 160, 1, 7, 81, 85, 65, 82, 69, 32, 66, 56, 5, 84, 82, 79, - 78, 71, 168, 193, 3, 2, 85, 83, 168, 254, 20, 2, 78, 65, 221, 208, 5, 6, - 69, 65, 71, 85, 76, 76, 6, 18, 83, 71, 86, 4, 26, 79, 243, 234, 11, 84, - 2, 145, 235, 11, 5, 76, 73, 68, 85, 83, 2, 49, 10, 69, 82, 84, 73, 67, - 65, 76, 32, 76, 73, 2, 171, 234, 11, 78, 4, 196, 214, 7, 5, 82, 65, 67, - 75, 69, 223, 201, 22, 69, 2, 181, 191, 24, 17, 32, 67, 69, 78, 84, 82, - 65, 76, 73, 90, 65, 84, 73, 79, 78, 32, 83, 20, 98, 72, 32, 4, 73, 76, - 68, 69, 136, 1, 6, 82, 73, 80, 76, 69, 32, 69, 5, 85, 82, 78, 69, 68, 2, - 185, 212, 7, 3, 82, 69, 69, 11, 11, 32, 8, 76, 3, 76, 69, 70, 0, 4, 82, - 73, 71, 72, 202, 231, 11, 79, 227, 181, 18, 66, 2, 241, 141, 30, 6, 84, - 32, 72, 65, 76, 70, 6, 210, 213, 15, 65, 176, 212, 15, 5, 85, 78, 68, 69, - 82, 211, 64, 68, 2, 161, 176, 15, 2, 32, 67, 10, 34, 80, 134, 189, 31, - 82, 3, 83, 6, 42, 87, 225, 186, 24, 4, 32, 84, 65, 67, 2, 45, 9, 65, 82, - 68, 83, 32, 65, 82, 82, 79, 2, 231, 139, 30, 87, 6, 246, 149, 26, 76, - 199, 191, 2, 84, 6, 52, 3, 68, 69, 32, 153, 229, 11, 4, 71, 71, 76, 89, - 4, 92, 12, 73, 78, 86, 69, 82, 84, 69, 68, 32, 66, 82, 73, 169, 148, 29, - 5, 66, 82, 73, 68, 71, 2, 197, 185, 24, 2, 68, 71, 6, 198, 236, 11, 45, - 207, 172, 18, 32, 6, 52, 7, 69, 82, 67, 73, 65, 76, 32, 231, 182, 32, 65, - 4, 134, 136, 29, 77, 179, 146, 3, 65, 8, 138, 159, 8, 82, 140, 149, 16, - 3, 79, 83, 73, 190, 239, 2, 76, 159, 252, 3, 65, 38, 214, 1, 70, 84, 10, - 83, 84, 82, 85, 67, 84, 73, 79, 78, 32, 46, 84, 252, 235, 2, 8, 86, 69, - 78, 73, 69, 78, 67, 69, 180, 180, 18, 6, 73, 67, 65, 76, 32, 84, 246, - 173, 9, 74, 241, 99, 7, 71, 82, 85, 69, 78, 84, 32, 6, 228, 147, 27, 4, - 69, 84, 84, 73, 158, 237, 1, 85, 189, 162, 2, 4, 79, 85, 78, 68, 4, 164, - 206, 20, 2, 87, 79, 183, 222, 10, 83, 20, 80, 5, 65, 73, 78, 83, 32, 198, - 1, 79, 28, 4, 82, 79, 76, 32, 143, 146, 3, 73, 12, 48, 3, 65, 83, 32, 93, - 5, 87, 73, 84, 72, 32, 6, 222, 152, 24, 77, 181, 8, 15, 78, 79, 82, 77, - 65, 76, 32, 83, 85, 66, 71, 82, 79, 85, 80, 6, 186, 195, 4, 76, 174, 214, - 19, 86, 171, 233, 4, 79, 2, 217, 169, 30, 2, 85, 82, 4, 188, 236, 19, 3, - 75, 78, 79, 165, 129, 4, 8, 83, 69, 81, 85, 69, 78, 67, 69, 6, 26, 73, - 143, 158, 2, 69, 4, 162, 175, 32, 78, 87, 69, 206, 2, 36, 4, 84, 73, 67, - 32, 171, 18, 89, 202, 2, 186, 1, 67, 204, 1, 6, 69, 80, 65, 67, 84, 32, - 86, 70, 36, 11, 79, 76, 68, 32, 78, 85, 66, 73, 65, 78, 32, 110, 83, 181, - 244, 28, 13, 77, 79, 82, 80, 72, 79, 76, 79, 71, 73, 67, 65, 76, 126, 76, - 9, 79, 77, 66, 73, 78, 73, 78, 71, 32, 161, 3, 5, 65, 80, 73, 84, 65, 6, - 68, 9, 83, 80, 73, 82, 73, 84, 85, 83, 32, 213, 175, 31, 2, 78, 73, 4, - 152, 149, 6, 2, 76, 69, 173, 131, 17, 2, 65, 83, 56, 134, 173, 21, 78, - 230, 193, 2, 68, 145, 238, 6, 8, 84, 72, 79, 85, 83, 65, 78, 68, 4, 146, - 173, 18, 82, 231, 172, 11, 85, 8, 58, 68, 0, 3, 73, 78, 68, 142, 15, 86, - 131, 202, 29, 70, 2, 217, 217, 29, 7, 73, 82, 69, 67, 84, 32, 81, 134, 1, - 56, 3, 77, 65, 76, 193, 11, 6, 89, 77, 66, 79, 76, 32, 120, 45, 9, 76, - 32, 76, 69, 84, 84, 69, 82, 32, 120, 138, 2, 65, 48, 6, 66, 79, 72, 65, - 73, 82, 32, 2, 67, 82, 170, 1, 68, 160, 1, 2, 71, 65, 34, 72, 38, 75, 46, - 70, 34, 76, 66, 79, 134, 3, 83, 90, 84, 46, 90, 230, 211, 5, 86, 214, 54, - 80, 190, 210, 3, 73, 238, 162, 22, 82, 198, 3, 69, 218, 7, 77, 2, 78, - 163, 17, 85, 4, 44, 5, 75, 72, 77, 73, 77, 223, 193, 19, 76, 2, 177, 1, - 4, 73, 67, 32, 75, 10, 92, 12, 89, 80, 84, 79, 71, 82, 65, 77, 77, 73, - 67, 32, 53, 7, 79, 83, 83, 69, 68, 32, 83, 8, 50, 83, 226, 4, 71, 210, - 133, 32, 69, 219, 7, 78, 2, 207, 220, 24, 72, 12, 80, 9, 73, 65, 76, 69, - 67, 84, 45, 80, 32, 244, 255, 31, 2, 65, 76, 175, 17, 69, 8, 182, 156, 8, - 72, 250, 150, 8, 65, 244, 183, 12, 2, 75, 65, 255, 165, 3, 78, 4, 190, 3, - 78, 223, 255, 31, 77, 4, 190, 198, 25, 79, 215, 150, 5, 65, 8, 42, 72, - 234, 233, 28, 65, 255, 165, 3, 83, 4, 226, 143, 32, 69, 219, 19, 73, 4, - 176, 191, 19, 7, 45, 83, 72, 65, 80, 69, 68, 155, 241, 7, 65, 35, 36, 3, - 76, 68, 32, 207, 253, 31, 79, 30, 76, 7, 67, 79, 80, 84, 73, 67, 32, 189, - 1, 7, 78, 85, 66, 73, 65, 78, 32, 22, 98, 71, 42, 72, 184, 1, 2, 83, 72, - 154, 222, 14, 68, 142, 248, 9, 79, 222, 224, 5, 69, 207, 104, 65, 2, 17, - 2, 65, 78, 2, 183, 251, 15, 71, 8, 138, 195, 25, 79, 238, 125, 65, 139, - 204, 5, 69, 8, 50, 78, 228, 177, 16, 2, 83, 72, 155, 158, 5, 87, 4, 154, - 140, 32, 71, 3, 89, 10, 54, 72, 138, 151, 6, 65, 178, 227, 25, 79, 219, - 3, 73, 4, 142, 254, 31, 73, 187, 13, 69, 4, 240, 241, 31, 3, 72, 69, 84, - 167, 8, 65, 2, 135, 250, 31, 65, 14, 62, 75, 30, 77, 2, 80, 22, 83, 241, - 234, 27, 3, 84, 65, 85, 4, 26, 72, 143, 138, 32, 65, 2, 131, 235, 27, 73, - 4, 188, 175, 16, 6, 72, 73, 77, 65, 32, 83, 193, 254, 3, 3, 84, 65, 85, - 4, 188, 200, 24, 3, 76, 69, 70, 245, 145, 2, 4, 82, 73, 71, 72, 6, 96, 6, - 78, 73, 83, 72, 32, 86, 204, 200, 25, 8, 82, 69, 83, 80, 79, 78, 68, 83, - 231, 201, 5, 65, 2, 213, 229, 28, 4, 69, 82, 83, 69, 44, 104, 2, 78, 84, - 156, 132, 3, 6, 67, 72, 32, 65, 78, 68, 253, 142, 28, 8, 80, 76, 69, 32, - 87, 73, 84, 72, 40, 56, 2, 69, 82, 37, 8, 73, 78, 71, 32, 82, 79, 68, 32, - 4, 190, 181, 27, 66, 195, 131, 1, 83, 36, 48, 4, 84, 69, 78, 83, 1, 4, - 85, 78, 73, 84, 18, 133, 220, 23, 2, 32, 68, 51, 82, 69, 76, 5, 73, 67, - 75, 69, 84, 34, 79, 198, 5, 85, 50, 89, 143, 214, 30, 65, 4, 196, 168, 8, - 3, 68, 73, 84, 181, 201, 20, 7, 83, 67, 69, 78, 84, 32, 77, 5, 169, 247, - 26, 3, 32, 66, 65, 28, 84, 2, 83, 83, 152, 242, 29, 3, 67, 79, 68, 152, - 155, 1, 3, 73, 83, 83, 255, 57, 87, 22, 46, 32, 184, 2, 3, 69, 68, 32, - 223, 1, 73, 14, 44, 3, 79, 70, 32, 82, 80, 179, 212, 31, 77, 4, 224, 172, - 28, 6, 74, 69, 82, 85, 83, 65, 145, 208, 2, 5, 76, 79, 82, 82, 65, 8, 76, - 10, 65, 84, 84, 89, 32, 87, 73, 84, 72, 32, 41, 5, 79, 77, 77, 69, 69, 4, - 218, 165, 10, 82, 25, 3, 76, 69, 70, 5, 189, 161, 3, 11, 32, 87, 73, 84, - 72, 32, 72, 65, 76, 70, 45, 6, 204, 132, 25, 37, 78, 69, 71, 65, 84, 73, - 86, 69, 32, 83, 81, 85, 65, 82, 69, 68, 32, 76, 65, 84, 73, 78, 32, 67, - 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, 192, 221, 2, 2, 70, - 76, 189, 210, 2, 3, 83, 87, 79, 2, 145, 235, 23, 5, 78, 71, 32, 76, 65, - 4, 248, 199, 17, 3, 90, 69, 73, 255, 167, 14, 84, 6, 130, 220, 19, 73, - 189, 149, 7, 4, 83, 84, 65, 76, 206, 19, 154, 1, 66, 20, 8, 78, 69, 73, - 70, 79, 82, 77, 32, 154, 250, 1, 80, 114, 82, 180, 3, 2, 83, 84, 242, - 219, 15, 67, 161, 229, 9, 6, 84, 32, 79, 70, 32, 77, 2, 211, 175, 5, 69, - 170, 19, 176, 1, 13, 78, 85, 77, 69, 82, 73, 67, 32, 83, 73, 71, 78, 32, - 184, 20, 17, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 83, 73, 71, - 78, 32, 233, 1, 5, 83, 73, 71, 78, 32, 222, 1, 78, 69, 166, 2, 70, 152, - 3, 2, 78, 73, 154, 2, 79, 130, 3, 83, 151, 4, 84, 24, 68, 5, 73, 71, 72, - 84, 32, 153, 1, 7, 76, 65, 77, 73, 84, 69, 32, 16, 142, 14, 83, 230, 113, - 85, 238, 50, 71, 136, 56, 17, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, - 77, 32, 85, 83, 83, 85, 214, 193, 26, 68, 219, 248, 1, 65, 8, 232, 140, - 21, 5, 79, 78, 69, 32, 84, 246, 144, 9, 70, 175, 14, 84, 58, 48, 4, 73, - 86, 69, 32, 125, 4, 79, 85, 82, 32, 26, 70, 83, 206, 1, 66, 250, 12, 65, - 82, 71, 138, 110, 85, 203, 172, 27, 68, 6, 182, 15, 72, 173, 144, 19, 5, - 73, 88, 84, 72, 83, 32, 150, 1, 66, 44, 18, 86, 65, 82, 73, 65, 78, 84, - 32, 70, 79, 82, 77, 32, 76, 73, 77, 77, 85, 206, 12, 65, 82, 71, 26, 83, - 242, 109, 85, 203, 172, 27, 68, 6, 204, 123, 3, 65, 78, 50, 163, 212, 26, - 85, 9, 214, 202, 12, 32, 143, 190, 19, 52, 24, 44, 4, 71, 73, 68, 65, 33, - 3, 78, 69, 32, 4, 238, 159, 30, 69, 207, 104, 77, 20, 156, 1, 19, 86, 65, - 82, 73, 65, 78, 84, 32, 70, 79, 82, 77, 32, 73, 76, 73, 77, 77, 85, 174, - 7, 83, 230, 113, 85, 238, 50, 71, 222, 249, 26, 68, 219, 248, 1, 65, 9, - 150, 132, 32, 32, 186, 2, 51, 3, 52, 28, 92, 16, 76, 68, 32, 65, 83, 83, - 89, 82, 73, 65, 78, 32, 79, 78, 69, 32, 37, 3, 78, 69, 32, 4, 154, 194, - 18, 83, 175, 192, 11, 81, 24, 166, 1, 69, 52, 8, 81, 85, 65, 82, 84, 69, - 82, 32, 206, 7, 66, 54, 71, 84, 5, 84, 72, 73, 82, 68, 200, 194, 24, 2, - 83, 72, 217, 191, 6, 6, 72, 65, 76, 70, 32, 71, 4, 158, 8, 83, 205, 164, - 1, 5, 73, 71, 72, 84, 72, 4, 166, 155, 30, 65, 207, 111, 71, 38, 144, 1, - 5, 69, 86, 69, 78, 32, 188, 1, 20, 72, 65, 82, 50, 32, 84, 73, 77, 69, - 83, 32, 71, 65, 76, 32, 80, 76, 85, 83, 32, 37, 3, 73, 88, 32, 18, 148, - 1, 17, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, 77, 32, 73, 77, 73, - 78, 218, 1, 83, 230, 113, 85, 238, 50, 71, 222, 249, 26, 68, 219, 248, 1, - 65, 6, 238, 194, 12, 32, 143, 190, 19, 51, 4, 222, 159, 28, 68, 167, 225, - 2, 77, 16, 142, 1, 83, 142, 3, 65, 218, 110, 85, 238, 50, 71, 144, 229, - 26, 16, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, 77, 32, 65, 83, 72, - 207, 20, 68, 2, 227, 61, 72, 50, 52, 5, 72, 82, 69, 69, 32, 241, 1, 3, - 87, 79, 32, 28, 142, 1, 66, 40, 4, 83, 72, 65, 82, 24, 16, 86, 65, 82, - 73, 65, 78, 84, 32, 70, 79, 82, 77, 32, 69, 83, 72, 118, 65, 82, 71, 211, - 154, 28, 68, 6, 136, 112, 3, 85, 82, 85, 199, 10, 65, 8, 226, 111, 50, 3, - 85, 4, 130, 224, 24, 49, 203, 3, 50, 22, 82, 65, 30, 66, 32, 2, 69, 83, - 22, 71, 26, 83, 61, 6, 84, 72, 73, 82, 68, 83, 4, 225, 184, 1, 2, 83, 72, - 4, 254, 120, 65, 223, 201, 26, 85, 2, 247, 226, 24, 72, 4, 53, 3, 69, 83, - 72, 4, 11, 72, 4, 17, 2, 65, 82, 4, 142, 251, 31, 50, 3, 85, 4, 11, 32, - 4, 196, 186, 27, 12, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, 77, 171, - 95, 68, 10, 160, 1, 9, 68, 73, 65, 71, 79, 78, 65, 76, 32, 204, 203, 25, - 6, 86, 69, 82, 84, 73, 67, 133, 247, 2, 14, 79, 76, 68, 32, 65, 83, 83, - 89, 82, 73, 65, 78, 32, 87, 6, 192, 173, 28, 2, 84, 82, 160, 251, 2, 4, - 81, 85, 65, 68, 15, 67, 194, 17, 202, 1, 65, 186, 15, 66, 170, 5, 68, - 190, 15, 69, 202, 10, 71, 182, 30, 72, 238, 3, 73, 238, 4, 75, 154, 20, - 76, 134, 37, 77, 134, 6, 78, 226, 17, 80, 210, 3, 82, 42, 83, 238, 19, - 84, 186, 8, 85, 207, 20, 90, 141, 1, 160, 1, 7, 32, 84, 73, 77, 69, 83, - 32, 142, 1, 66, 250, 3, 68, 38, 75, 90, 76, 212, 1, 3, 77, 65, 82, 78, - 78, 134, 2, 82, 42, 83, 154, 235, 30, 80, 215, 127, 50, 16, 144, 173, 1, - 5, 76, 65, 71, 65, 82, 226, 23, 71, 246, 239, 12, 73, 154, 182, 13, 77, - 182, 161, 2, 83, 218, 162, 1, 66, 246, 67, 72, 187, 2, 65, 45, 22, 32, - 219, 2, 50, 28, 48, 6, 84, 73, 77, 69, 83, 32, 139, 203, 1, 71, 26, 180, - 1, 2, 71, 65, 38, 73, 36, 2, 83, 72, 128, 113, 8, 85, 32, 80, 76, 85, 83, - 32, 85, 188, 56, 4, 68, 85, 78, 51, 166, 2, 65, 204, 2, 3, 78, 85, 78, - 242, 27, 76, 143, 165, 30, 72, 4, 194, 210, 1, 78, 231, 159, 30, 76, 4, - 210, 169, 1, 71, 223, 200, 29, 77, 4, 178, 216, 24, 85, 143, 177, 5, 69, - 15, 37, 7, 32, 84, 73, 77, 69, 83, 32, 12, 206, 133, 1, 77, 130, 59, 71, - 194, 9, 83, 234, 10, 84, 140, 179, 28, 2, 66, 65, 147, 233, 1, 65, 5, - 249, 51, 5, 32, 84, 73, 77, 69, 7, 37, 7, 32, 84, 73, 77, 69, 83, 32, 4, - 252, 27, 5, 83, 72, 73, 84, 65, 215, 80, 69, 23, 68, 7, 32, 84, 73, 77, - 69, 83, 32, 218, 202, 25, 69, 187, 212, 5, 65, 16, 102, 75, 156, 173, 1, - 2, 68, 73, 246, 223, 26, 71, 218, 248, 1, 85, 238, 94, 65, 170, 92, 83, - 215, 42, 72, 4, 130, 158, 1, 65, 135, 208, 30, 73, 7, 37, 7, 32, 84, 73, - 77, 69, 83, 32, 4, 210, 253, 3, 75, 223, 194, 27, 83, 13, 26, 32, 243, - 191, 31, 83, 8, 128, 1, 10, 80, 76, 85, 83, 32, 78, 65, 71, 65, 32, 128, - 185, 8, 7, 84, 72, 82, 69, 69, 32, 84, 177, 252, 5, 4, 79, 86, 69, 82, 4, - 144, 140, 1, 16, 79, 80, 80, 79, 83, 73, 78, 71, 32, 65, 78, 32, 80, 76, - 85, 83, 251, 175, 23, 83, 6, 200, 49, 2, 65, 68, 239, 151, 18, 75, 18, - 26, 72, 131, 164, 12, 65, 17, 42, 32, 202, 200, 18, 71, 223, 161, 13, 50, - 10, 68, 9, 79, 86, 69, 82, 32, 65, 83, 72, 32, 174, 97, 90, 135, 112, 75, - 6, 176, 1, 8, 79, 86, 69, 82, 32, 65, 83, 72, 157, 143, 1, 29, 84, 85, - 71, 50, 32, 79, 86, 69, 82, 32, 84, 85, 71, 50, 32, 84, 85, 71, 50, 32, - 79, 86, 69, 82, 32, 84, 85, 71, 50, 5, 149, 145, 1, 27, 32, 67, 82, 79, - 83, 83, 73, 78, 71, 32, 65, 83, 72, 32, 79, 86, 69, 82, 32, 65, 83, 72, - 32, 79, 86, 69, 82, 52, 30, 65, 158, 2, 73, 95, 85, 27, 66, 68, 44, 4, - 72, 65, 82, 50, 90, 76, 66, 82, 251, 238, 27, 71, 5, 145, 208, 1, 6, 32, - 84, 73, 77, 69, 83, 9, 37, 7, 32, 84, 73, 77, 69, 83, 32, 6, 238, 164, 1, - 65, 170, 173, 30, 78, 163, 17, 90, 7, 252, 219, 30, 7, 32, 79, 86, 69, - 82, 32, 66, 239, 136, 1, 65, 5, 211, 203, 24, 65, 9, 37, 7, 32, 84, 73, - 77, 69, 83, 32, 6, 134, 156, 1, 73, 134, 167, 29, 71, 187, 161, 1, 65, - 19, 50, 32, 168, 1, 3, 76, 85, 71, 239, 169, 1, 82, 8, 88, 8, 79, 86, 69, - 82, 32, 66, 85, 32, 129, 183, 27, 8, 67, 82, 79, 83, 83, 73, 78, 71, 6, - 164, 198, 12, 7, 84, 73, 77, 69, 83, 32, 78, 246, 224, 17, 65, 135, 108, - 85, 5, 189, 242, 3, 8, 32, 79, 86, 69, 82, 32, 66, 85, 180, 1, 34, 65, - 222, 5, 73, 195, 2, 85, 67, 50, 71, 150, 5, 82, 146, 49, 32, 131, 171, - 31, 77, 55, 26, 32, 139, 225, 31, 51, 50, 76, 13, 75, 73, 83, 73, 77, 53, - 32, 84, 73, 77, 69, 83, 32, 227, 198, 1, 84, 48, 146, 1, 65, 30, 66, 38, - 71, 112, 2, 73, 82, 42, 76, 94, 85, 182, 131, 1, 80, 162, 61, 84, 218, - 230, 27, 75, 242, 158, 2, 78, 254, 2, 83, 163, 17, 72, 4, 110, 32, 255, - 188, 30, 77, 4, 246, 245, 29, 65, 147, 233, 1, 73, 10, 34, 65, 58, 73, - 235, 151, 31, 85, 5, 11, 32, 2, 133, 246, 29, 6, 80, 76, 85, 83, 32, 77, - 5, 219, 196, 24, 82, 5, 229, 255, 13, 5, 32, 80, 76, 85, 83, 8, 26, 85, - 179, 221, 31, 65, 7, 160, 151, 1, 7, 32, 80, 76, 85, 83, 32, 77, 143, - 198, 30, 77, 6, 52, 7, 50, 32, 80, 76, 85, 83, 32, 171, 219, 31, 83, 4, - 128, 27, 2, 71, 73, 139, 217, 29, 77, 7, 191, 193, 12, 65, 25, 54, 77, - 150, 1, 78, 76, 2, 83, 72, 231, 217, 31, 66, 13, 44, 7, 32, 84, 73, 77, - 69, 83, 32, 59, 50, 6, 220, 69, 2, 85, 32, 230, 212, 13, 73, 199, 147, - 17, 83, 5, 221, 152, 13, 6, 32, 84, 73, 77, 69, 83, 5, 181, 239, 18, 14, - 32, 75, 65, 83, 75, 65, 76, 32, 85, 32, 71, 85, 78, 85, 5, 245, 157, 1, - 5, 32, 80, 76, 85, 83, 91, 70, 32, 66, 66, 94, 71, 234, 4, 78, 198, 185, - 24, 82, 175, 153, 7, 72, 6, 154, 176, 1, 71, 170, 3, 83, 153, 197, 12, 4, - 79, 86, 69, 82, 9, 52, 7, 32, 84, 73, 77, 69, 83, 32, 255, 215, 31, 50, - 4, 250, 145, 1, 69, 247, 152, 30, 83, 61, 52, 7, 32, 84, 73, 77, 69, 83, - 32, 131, 145, 31, 85, 56, 122, 65, 58, 68, 30, 71, 74, 75, 90, 76, 110, - 77, 50, 83, 130, 80, 69, 218, 58, 73, 190, 198, 16, 72, 170, 238, 13, 78, - 3, 80, 6, 32, 2, 83, 72, 235, 168, 31, 78, 5, 215, 206, 14, 32, 4, 138, - 134, 31, 73, 3, 85, 8, 26, 73, 183, 213, 31, 65, 7, 140, 141, 1, 2, 82, - 50, 151, 199, 30, 83, 8, 26, 85, 211, 185, 1, 65, 6, 40, 4, 83, 72, 85, - 50, 195, 212, 31, 82, 5, 175, 26, 32, 8, 26, 65, 45, 2, 85, 72, 6, 202, - 26, 77, 205, 158, 24, 3, 75, 45, 48, 2, 225, 57, 5, 32, 80, 76, 85, 83, - 6, 162, 235, 29, 65, 198, 170, 1, 69, 223, 61, 73, 4, 238, 138, 1, 73, - 211, 177, 30, 72, 11, 26, 51, 215, 210, 31, 52, 7, 143, 9, 32, 117, 130, - 1, 32, 90, 50, 210, 1, 78, 202, 1, 82, 60, 3, 83, 72, 50, 52, 3, 90, 69, - 78, 170, 225, 18, 71, 230, 235, 11, 68, 215, 127, 76, 4, 168, 25, 11, 79, - 86, 69, 82, 32, 69, 32, 78, 85, 78, 32, 253, 94, 4, 84, 73, 77, 69, 19, - 37, 7, 32, 84, 73, 77, 69, 83, 32, 16, 134, 1, 83, 144, 168, 1, 10, 65, - 32, 80, 76, 85, 83, 32, 72, 65, 32, 242, 133, 29, 71, 206, 16, 80, 154, - 24, 75, 254, 100, 77, 219, 19, 85, 4, 130, 198, 30, 65, 227, 114, 72, 15, - 11, 32, 12, 96, 4, 67, 82, 79, 83, 0, 4, 79, 80, 80, 79, 36, 6, 84, 73, - 77, 69, 83, 32, 155, 158, 24, 83, 2, 237, 146, 14, 4, 83, 73, 78, 71, 6, - 204, 138, 1, 4, 71, 65, 78, 50, 227, 172, 30, 77, 6, 36, 3, 73, 78, 50, - 203, 253, 30, 69, 5, 131, 193, 30, 32, 5, 229, 16, 9, 32, 67, 82, 79, 83, - 83, 73, 78, 71, 63, 11, 32, 60, 96, 14, 83, 72, 69, 83, 72, 73, 71, 32, - 84, 73, 77, 69, 83, 32, 97, 6, 84, 73, 77, 69, 83, 32, 16, 178, 131, 1, - 73, 194, 224, 2, 77, 222, 255, 25, 65, 244, 107, 2, 76, 65, 198, 87, 83, - 147, 17, 72, 44, 134, 1, 65, 68, 5, 68, 85, 78, 51, 32, 26, 75, 58, 76, - 62, 83, 34, 85, 222, 127, 73, 204, 31, 2, 72, 65, 150, 253, 28, 71, 179, - 101, 66, 9, 244, 86, 9, 32, 80, 76, 85, 83, 32, 76, 65, 76, 147, 243, 30, - 78, 4, 217, 32, 2, 71, 85, 6, 168, 153, 24, 5, 65, 83, 75, 65, 76, 251, - 185, 3, 85, 8, 34, 65, 210, 200, 31, 73, 3, 85, 5, 201, 85, 2, 76, 32, 4, - 226, 177, 31, 72, 215, 22, 85, 4, 150, 200, 31, 50, 3, 68, 160, 2, 42, - 65, 166, 19, 69, 122, 73, 135, 5, 85, 191, 1, 114, 50, 144, 16, 2, 66, - 65, 94, 68, 22, 76, 38, 78, 206, 140, 1, 32, 154, 6, 82, 146, 145, 28, - 83, 191, 145, 2, 77, 153, 1, 11, 32, 150, 1, 68, 6, 84, 73, 77, 69, 83, - 32, 153, 128, 1, 5, 79, 86, 69, 82, 32, 148, 1, 202, 1, 65, 162, 2, 66, - 154, 1, 68, 178, 1, 69, 58, 71, 178, 1, 72, 230, 1, 73, 70, 75, 194, 1, - 76, 62, 77, 50, 78, 130, 1, 83, 142, 1, 85, 222, 154, 1, 84, 240, 130, - 23, 3, 90, 73, 90, 247, 150, 7, 80, 18, 132, 1, 6, 32, 80, 76, 85, 83, - 32, 50, 78, 52, 2, 83, 72, 225, 160, 18, 14, 66, 50, 32, 84, 69, 78, 85, - 32, 80, 76, 85, 83, 32, 84, 6, 202, 58, 68, 134, 200, 13, 73, 155, 190, - 17, 72, 5, 185, 61, 9, 32, 80, 76, 85, 83, 32, 75, 65, 75, 7, 11, 50, 5, - 133, 90, 6, 32, 80, 76, 85, 83, 32, 10, 26, 65, 77, 2, 85, 82, 6, 42, 72, - 44, 2, 82, 32, 151, 193, 31, 68, 2, 11, 65, 2, 135, 168, 24, 82, 5, 11, - 32, 2, 185, 246, 30, 4, 80, 76, 85, 83, 14, 34, 73, 54, 85, 155, 192, 31, - 65, 7, 17, 2, 77, 32, 4, 146, 22, 84, 207, 129, 1, 71, 6, 56, 8, 71, 32, - 84, 73, 77, 69, 83, 32, 223, 191, 31, 66, 4, 158, 119, 73, 151, 45, 75, - 10, 38, 78, 254, 2, 76, 183, 232, 29, 82, 5, 243, 28, 32, 18, 18, 65, 99, - 73, 11, 26, 82, 247, 158, 1, 78, 7, 33, 6, 32, 80, 76, 85, 83, 32, 4, - 222, 167, 31, 78, 255, 2, 68, 9, 174, 122, 52, 225, 228, 12, 7, 82, 50, - 32, 80, 76, 85, 83, 12, 62, 65, 154, 124, 85, 205, 226, 12, 6, 73, 32, - 80, 76, 85, 83, 8, 40, 6, 32, 80, 76, 85, 83, 32, 83, 76, 4, 48, 6, 76, - 85, 32, 80, 76, 85, 187, 188, 31, 65, 2, 11, 83, 2, 215, 97, 32, 5, 249, - 221, 13, 5, 32, 80, 76, 85, 83, 4, 176, 100, 10, 83, 72, 32, 80, 76, 85, - 83, 32, 72, 85, 147, 15, 71, 12, 34, 65, 36, 2, 73, 68, 27, 85, 4, 250, - 204, 24, 83, 147, 238, 6, 75, 5, 225, 77, 2, 32, 80, 4, 60, 5, 83, 72, - 85, 50, 32, 197, 127, 5, 51, 32, 80, 76, 85, 2, 205, 158, 1, 3, 80, 76, - 85, 8, 26, 65, 199, 184, 31, 85, 7, 11, 77, 5, 227, 159, 1, 32, 6, 250, - 77, 69, 154, 131, 29, 85, 163, 232, 1, 73, 10, 26, 69, 73, 2, 85, 78, 7, - 33, 6, 32, 80, 76, 85, 83, 32, 4, 150, 159, 24, 69, 215, 133, 7, 71, 5, - 11, 32, 2, 187, 101, 79, 14, 42, 72, 150, 216, 23, 65, 239, 206, 7, 85, - 8, 18, 69, 51, 73, 5, 237, 190, 30, 7, 32, 80, 76, 85, 83, 32, 84, 4, - 146, 183, 31, 68, 3, 77, 7, 11, 68, 5, 209, 214, 13, 5, 32, 80, 76, 85, - 83, 7, 11, 32, 4, 142, 218, 29, 82, 129, 175, 1, 11, 67, 82, 79, 83, 83, - 73, 78, 71, 32, 71, 65, 5, 191, 131, 1, 32, 7, 134, 131, 1, 32, 247, 161, - 30, 65, 11, 11, 50, 9, 11, 32, 6, 80, 8, 67, 82, 79, 83, 83, 73, 78, 71, - 0, 4, 79, 86, 69, 82, 211, 182, 26, 84, 2, 197, 49, 3, 32, 71, 65, 8, 44, - 5, 83, 72, 84, 73, 78, 207, 154, 24, 50, 7, 37, 7, 32, 84, 73, 77, 69, - 83, 32, 4, 250, 186, 30, 75, 215, 120, 85, 49, 70, 32, 94, 52, 114, 82, - 190, 1, 83, 146, 173, 30, 68, 211, 130, 1, 71, 6, 188, 253, 8, 6, 84, 73, - 77, 69, 83, 32, 205, 244, 4, 8, 67, 82, 79, 83, 83, 73, 78, 71, 7, 11, - 32, 4, 64, 8, 67, 82, 79, 83, 83, 73, 78, 71, 1, 4, 79, 86, 69, 82, 2, - 233, 150, 24, 3, 32, 71, 73, 16, 26, 51, 147, 136, 1, 50, 13, 37, 7, 32, - 84, 73, 77, 69, 83, 32, 10, 70, 65, 0, 2, 76, 85, 206, 127, 71, 246, 239, - 12, 73, 155, 190, 17, 80, 2, 189, 239, 13, 7, 32, 80, 76, 85, 83, 32, 73, - 14, 26, 72, 147, 166, 30, 65, 13, 11, 32, 10, 22, 84, 247, 20, 67, 8, 44, - 5, 73, 77, 69, 83, 32, 255, 137, 31, 69, 6, 192, 20, 6, 71, 73, 83, 72, - 32, 67, 146, 126, 84, 243, 213, 29, 66, 43, 110, 50, 174, 1, 68, 218, 1, - 77, 54, 82, 144, 236, 13, 9, 32, 67, 82, 79, 83, 83, 73, 78, 71, 247, - 189, 17, 76, 15, 11, 32, 12, 48, 6, 84, 73, 77, 69, 83, 32, 167, 132, 1, - 71, 10, 252, 24, 3, 75, 65, 75, 194, 75, 73, 152, 20, 10, 83, 65, 76, 32, - 80, 76, 85, 83, 32, 84, 247, 179, 29, 78, 11, 11, 32, 8, 128, 1, 10, 80, - 76, 85, 83, 32, 71, 73, 83, 72, 32, 16, 6, 84, 73, 77, 69, 83, 32, 177, - 66, 8, 79, 86, 69, 82, 32, 71, 85, 68, 2, 135, 121, 84, 4, 172, 145, 1, - 5, 65, 32, 80, 76, 85, 239, 160, 29, 75, 5, 17, 2, 32, 84, 2, 241, 42, 4, - 73, 77, 69, 83, 9, 26, 85, 235, 169, 31, 55, 4, 214, 168, 31, 83, 147, 1, - 78, 50, 30, 65, 82, 73, 215, 1, 85, 11, 26, 32, 143, 169, 31, 76, 6, 32, - 2, 84, 69, 147, 128, 1, 71, 4, 235, 127, 78, 23, 37, 7, 32, 84, 73, 77, - 69, 83, 32, 20, 104, 3, 65, 83, 72, 206, 198, 27, 68, 202, 224, 2, 78, - 94, 75, 170, 57, 66, 2, 71, 162, 25, 83, 143, 45, 85, 7, 224, 55, 8, 32, - 79, 86, 69, 82, 32, 72, 73, 227, 239, 30, 50, 19, 48, 2, 66, 50, 166, - 141, 24, 76, 159, 152, 7, 83, 13, 37, 7, 32, 84, 73, 77, 69, 83, 32, 10, - 254, 138, 1, 75, 178, 186, 26, 76, 186, 215, 2, 72, 226, 57, 65, 195, 9, - 85, 49, 104, 3, 68, 73, 77, 94, 71, 214, 1, 76, 62, 77, 206, 159, 31, 32, - 170, 1, 83, 146, 1, 66, 2, 78, 3, 82, 7, 53, 11, 32, 79, 86, 69, 82, 32, - 73, 68, 73, 77, 32, 4, 202, 244, 23, 83, 155, 183, 6, 66, 13, 11, 73, 11, - 11, 32, 8, 162, 123, 71, 220, 230, 11, 31, 79, 86, 69, 82, 32, 73, 71, - 73, 32, 83, 72, 73, 82, 32, 79, 86, 69, 82, 32, 83, 72, 73, 82, 32, 85, - 68, 32, 79, 86, 69, 82, 142, 134, 17, 68, 155, 168, 1, 82, 7, 26, 32, - 167, 162, 31, 50, 2, 169, 72, 4, 84, 73, 77, 69, 13, 26, 32, 139, 210, - 30, 73, 8, 76, 4, 67, 82, 79, 83, 0, 4, 79, 80, 80, 79, 162, 111, 84, - 143, 130, 23, 83, 2, 197, 158, 30, 5, 83, 73, 78, 71, 32, 224, 1, 78, 65, - 146, 15, 73, 242, 1, 85, 158, 73, 69, 229, 168, 23, 4, 87, 85, 51, 49, - 177, 1, 164, 1, 7, 32, 84, 73, 77, 69, 83, 32, 210, 9, 50, 66, 68, 102, - 75, 50, 76, 98, 77, 28, 4, 83, 75, 65, 76, 248, 192, 15, 6, 80, 32, 69, - 76, 65, 77, 219, 209, 15, 66, 134, 1, 170, 1, 65, 94, 66, 82, 69, 30, 71, - 182, 2, 73, 34, 75, 34, 76, 38, 77, 170, 1, 83, 118, 84, 34, 85, 214, 8, - 72, 246, 51, 78, 222, 215, 16, 80, 154, 221, 13, 82, 147, 17, 90, 13, 46, - 68, 250, 239, 30, 78, 165, 44, 2, 83, 72, 5, 229, 50, 7, 32, 80, 76, 85, - 83, 32, 75, 10, 34, 65, 194, 156, 31, 73, 3, 85, 6, 186, 179, 29, 76, - 134, 233, 1, 68, 3, 82, 4, 138, 25, 82, 151, 61, 83, 26, 30, 65, 98, 73, - 147, 1, 85, 11, 38, 82, 206, 123, 78, 231, 159, 30, 76, 5, 249, 21, 10, - 32, 80, 76, 85, 83, 32, 83, 72, 65, 51, 11, 32, 2, 83, 72, 171, 129, 24, + 69, 82, 84, 73, 67, 65, 76, 32, 146, 152, 16, 71, 191, 187, 4, 76, 6, + 226, 17, 82, 131, 137, 16, 67, 4, 145, 17, 2, 82, 69, 4, 230, 235, 31, + 65, 135, 42, 73, 4, 21, 3, 65, 67, 82, 4, 165, 135, 17, 2, 79, 78, 4, + 138, 37, 80, 255, 130, 31, 86, 6, 146, 38, 76, 177, 233, 7, 9, 65, 82, + 69, 78, 84, 72, 69, 83, 69, 6, 240, 52, 4, 71, 72, 84, 87, 207, 129, 10, + 78, 7, 11, 32, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 219, 236, + 30, 84, 6, 182, 163, 12, 83, 175, 187, 14, 76, 2, 201, 146, 16, 2, 32, + 67, 6, 138, 51, 32, 207, 187, 31, 87, 18, 72, 9, 78, 67, 76, 79, 83, 73, + 78, 71, 32, 177, 35, 4, 81, 85, 65, 76, 14, 132, 1, 6, 67, 73, 82, 67, + 76, 69, 22, 83, 140, 170, 6, 3, 75, 69, 89, 240, 216, 19, 7, 85, 80, 87, + 65, 82, 68, 32, 171, 204, 5, 68, 5, 163, 198, 18, 32, 4, 182, 239, 25, + 67, 147, 252, 5, 81, 6, 48, 2, 69, 82, 206, 145, 5, 79, 251, 134, 12, 76, + 2, 255, 76, 77, 128, 1, 88, 17, 76, 65, 71, 79, 76, 73, 84, 73, 67, 32, + 76, 69, 84, 84, 69, 82, 32, 143, 3, 82, 76, 238, 1, 68, 30, 73, 46, 83, + 50, 84, 210, 146, 6, 65, 22, 66, 94, 67, 134, 1, 70, 38, 71, 238, 2, 77, + 32, 2, 76, 74, 34, 78, 88, 2, 80, 79, 30, 82, 194, 2, 86, 22, 89, 90, 90, + 234, 145, 19, 72, 190, 133, 2, 85, 162, 177, 5, 79, 235, 5, 75, 4, 138, + 149, 6, 74, 31, 79, 11, 150, 150, 6, 78, 54, 79, 243, 198, 26, 90, 8, + 246, 150, 6, 77, 130, 4, 76, 247, 218, 22, 72, 4, 170, 155, 6, 86, 235, + 218, 26, 83, 52, 38, 65, 185, 3, 4, 69, 69, 75, 32, 38, 84, 5, 78, 84, + 72, 65, 32, 196, 1, 2, 86, 69, 137, 216, 28, 5, 80, 72, 69, 77, 69, 24, + 68, 6, 68, 73, 71, 73, 84, 32, 65, 7, 76, 69, 84, 84, 69, 82, 32, 14, + 170, 247, 16, 83, 202, 157, 14, 70, 70, 84, 62, 90, 223, 86, 79, 10, 230, + 243, 32, 86, 162, 17, 75, 2, 78, 2, 80, 187, 2, 65, 12, 18, 32, 67, 45, + 6, 26, 65, 131, 184, 16, 84, 4, 237, 147, 4, 4, 67, 67, 69, 78, 6, 150, + 22, 86, 168, 250, 11, 6, 65, 67, 85, 84, 69, 45, 139, 249, 3, 77, 14, + 148, 1, 8, 77, 85, 83, 73, 67, 65, 76, 32, 130, 155, 4, 75, 170, 202, 2, + 80, 174, 4, 89, 217, 239, 3, 11, 68, 73, 65, 76, 89, 84, 73, 75, 65, 32, + 84, 6, 26, 84, 255, 203, 15, 80, 4, 214, 204, 15, 69, 35, 82, 6, 146, + 130, 13, 79, 128, 133, 19, 8, 77, 79, 84, 72, 69, 84, 73, 67, 167, 45, + 82, 16, 26, 78, 151, 210, 30, 83, 14, 52, 7, 86, 69, 82, 84, 69, 68, 32, + 243, 209, 28, 70, 12, 60, 2, 66, 82, 69, 9, 68, 79, 85, 66, 76, 69, 32, + 65, 82, 8, 18, 69, 23, 73, 4, 203, 232, 11, 86, 4, 233, 223, 30, 2, 68, + 71, 4, 11, 67, 4, 207, 223, 30, 72, 8, 128, 1, 16, 84, 65, 75, 65, 78, + 65, 45, 72, 73, 82, 65, 71, 65, 78, 65, 32, 229, 250, 17, 9, 86, 89, 75, + 65, 32, 65, 66, 79, 86, 4, 242, 139, 10, 83, 35, 86, 162, 1, 80, 5, 65, + 84, 73, 78, 32, 164, 8, 3, 69, 70, 84, 232, 3, 2, 73, 71, 83, 79, 106, + 156, 1, 21, 76, 69, 84, 84, 69, 82, 32, 83, 77, 65, 76, 76, 32, 67, 65, + 80, 73, 84, 65, 76, 32, 53, 13, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, + 69, 82, 32, 10, 182, 254, 32, 71, 2, 76, 2, 77, 2, 78, 3, 82, 96, 226, 1, + 65, 70, 67, 34, 69, 30, 70, 78, 73, 86, 76, 106, 79, 2, 85, 134, 1, 82, + 50, 84, 158, 183, 12, 83, 162, 151, 2, 66, 238, 157, 2, 87, 190, 139, 16, + 68, 2, 71, 2, 72, 2, 75, 2, 77, 2, 78, 2, 80, 2, 86, 2, 88, 3, 90, 13, + 182, 246, 2, 32, 226, 169, 26, 76, 138, 220, 3, 69, 2, 79, 3, 86, 5, 173, + 151, 12, 3, 32, 67, 69, 7, 170, 250, 32, 83, 3, 84, 5, 225, 207, 27, 14, + 76, 65, 84, 84, 69, 78, 69, 68, 32, 79, 80, 69, 78, 32, 11, 37, 7, 78, + 83, 85, 76, 65, 82, 32, 8, 170, 250, 32, 68, 2, 71, 2, 82, 3, 84, 7, 148, + 151, 16, 14, 32, 87, 73, 84, 72, 32, 68, 79, 85, 66, 76, 69, 32, 77, 133, + 233, 12, 3, 79, 78, 71, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 146, 167, + 12, 68, 209, 233, 12, 15, 76, 73, 71, 72, 84, 32, 67, 69, 78, 84, 82, 65, + 76, 73, 90, 7, 11, 32, 4, 210, 133, 12, 82, 203, 208, 18, 66, 5, 201, + 198, 30, 7, 85, 82, 78, 69, 68, 32, 87, 36, 46, 32, 133, 3, 6, 87, 65, + 82, 68, 83, 32, 32, 122, 65, 192, 1, 12, 80, 65, 82, 69, 78, 84, 72, 69, + 83, 73, 83, 32, 166, 13, 72, 154, 10, 84, 57, 5, 82, 73, 71, 72, 84, 14, + 52, 5, 78, 71, 76, 69, 32, 77, 4, 82, 82, 79, 87, 6, 140, 253, 3, 6, 67, + 69, 78, 84, 82, 69, 214, 214, 26, 66, 131, 165, 1, 65, 8, 26, 72, 227, + 210, 30, 32, 4, 209, 210, 30, 3, 69, 65, 68, 4, 144, 232, 7, 4, 65, 66, + 79, 86, 241, 217, 24, 5, 66, 69, 76, 79, 87, 4, 142, 14, 72, 245, 248, + 11, 5, 65, 82, 82, 79, 87, 10, 52, 6, 65, 84, 85, 82, 69, 32, 129, 18, 2, + 72, 84, 8, 234, 1, 76, 23, 82, 10, 36, 3, 78, 71, 32, 131, 215, 31, 87, + 8, 236, 7, 7, 68, 79, 85, 66, 76, 69, 32, 242, 7, 83, 71, 86, 26, 48, 5, + 65, 67, 82, 79, 78, 205, 5, 2, 73, 78, 23, 18, 32, 127, 45, 10, 34, 76, + 22, 82, 171, 207, 30, 66, 4, 41, 2, 69, 70, 4, 21, 3, 73, 71, 72, 4, 189, + 229, 16, 6, 84, 32, 72, 65, 76, 70, 10, 54, 86, 250, 20, 65, 150, 148, + 12, 71, 235, 176, 3, 66, 2, 205, 212, 31, 8, 69, 82, 84, 73, 67, 65, 76, + 45, 4, 164, 9, 9, 85, 77, 66, 69, 82, 32, 83, 73, 71, 129, 223, 11, 2, + 79, 84, 18, 136, 1, 17, 76, 68, 32, 80, 69, 82, 77, 73, 67, 32, 76, 69, + 84, 84, 69, 82, 32, 82, 80, 216, 166, 12, 4, 71, 79, 78, 69, 167, 220, + 18, 86, 10, 198, 45, 90, 142, 163, 18, 78, 182, 166, 9, 68, 186, 176, 2, + 83, 239, 246, 1, 65, 2, 229, 224, 24, 6, 69, 78, 32, 77, 65, 82, 12, 18, + 65, 107, 76, 8, 220, 7, 9, 82, 69, 78, 84, 72, 69, 83, 69, 83, 173, 216, + 24, 9, 76, 65, 84, 65, 76, 73, 90, 69, 68, 4, 11, 85, 4, 241, 201, 30, 6, + 83, 32, 83, 73, 71, 78, 40, 18, 69, 127, 73, 6, 72, 5, 86, 69, 82, 83, + 69, 141, 222, 24, 7, 84, 82, 79, 70, 76, 69, 88, 4, 22, 32, 251, 12, 68, + 2, 137, 8, 2, 83, 79, 34, 40, 3, 71, 72, 84, 133, 5, 2, 78, 71, 28, 50, + 32, 253, 3, 7, 87, 65, 82, 68, 83, 32, 72, 26, 108, 5, 65, 82, 82, 79, + 87, 218, 1, 72, 124, 12, 80, 65, 82, 69, 78, 84, 72, 69, 83, 73, 83, 32, + 159, 9, 84, 12, 44, 5, 72, 69, 65, 68, 32, 199, 198, 30, 32, 8, 26, 65, + 199, 198, 30, 66, 6, 36, 3, 78, 68, 32, 171, 235, 31, 66, 4, 40, 4, 68, + 79, 87, 78, 1, 2, 85, 80, 2, 249, 231, 8, 9, 32, 65, 82, 82, 79, 87, 72, + 69, 65, 6, 11, 65, 6, 48, 6, 76, 70, 32, 82, 73, 78, 21, 2, 82, 80, 4, + 207, 196, 30, 71, 2, 17, 2, 79, 79, 2, 183, 233, 31, 78, 4, 146, 228, 9, + 65, 245, 174, 21, 5, 66, 69, 76, 79, 87, 2, 185, 161, 21, 16, 65, 82, 80, + 79, 79, 78, 32, 87, 73, 84, 72, 32, 66, 65, 82, 66, 6, 11, 32, 6, 166, + 248, 11, 79, 254, 202, 18, 66, 131, 165, 1, 65, 24, 166, 1, 72, 204, 1, + 6, 81, 85, 65, 82, 69, 32, 84, 5, 84, 82, 79, 78, 71, 128, 195, 3, 2, 85, + 83, 236, 145, 21, 2, 78, 65, 149, 234, 5, 6, 69, 65, 71, 85, 76, 76, 8, + 40, 4, 79, 82, 84, 32, 187, 194, 16, 65, 6, 18, 83, 71, 86, 4, 26, 79, + 187, 245, 11, 84, 2, 217, 245, 11, 5, 76, 73, 68, 85, 83, 2, 49, 10, 69, + 82, 84, 73, 67, 65, 76, 32, 76, 73, 2, 243, 244, 11, 78, 6, 26, 66, 227, + 228, 31, 65, 4, 216, 222, 7, 5, 82, 65, 67, 75, 69, 147, 225, 22, 69, 2, + 209, 212, 24, 17, 32, 67, 69, 78, 84, 82, 65, 76, 73, 90, 65, 84, 73, 79, + 78, 32, 83, 20, 98, 72, 32, 4, 73, 76, 68, 69, 136, 1, 6, 82, 73, 80, 76, + 69, 32, 69, 5, 85, 82, 78, 69, 68, 2, 205, 220, 7, 3, 82, 69, 69, 11, 11, + 32, 8, 76, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 246, 241, 11, 79, 255, + 202, 18, 66, 2, 193, 173, 30, 6, 84, 32, 72, 65, 76, 70, 6, 178, 229, 15, + 65, 216, 229, 15, 5, 85, 78, 68, 69, 82, 239, 66, 68, 2, 249, 191, 15, 2, + 32, 67, 12, 34, 80, 170, 224, 31, 82, 3, 83, 8, 18, 32, 43, 87, 4, 11, + 84, 4, 133, 208, 24, 2, 65, 67, 4, 25, 4, 65, 82, 68, 83, 4, 189, 186, + 30, 6, 32, 65, 82, 82, 79, 87, 16, 42, 32, 37, 6, 45, 76, 73, 78, 69, 45, + 6, 250, 169, 26, 76, 175, 202, 2, 84, 10, 54, 65, 48, 5, 71, 82, 65, 86, + 69, 139, 222, 15, 77, 4, 25, 4, 67, 85, 84, 69, 5, 147, 229, 11, 45, 5, + 143, 139, 12, 45, 6, 52, 3, 68, 69, 32, 137, 238, 11, 4, 71, 71, 76, 89, + 4, 132, 206, 24, 14, 73, 78, 86, 69, 82, 84, 69, 68, 32, 66, 82, 73, 68, + 71, 149, 229, 4, 5, 66, 82, 73, 68, 71, 6, 194, 245, 11, 45, 235, 193, + 18, 32, 6, 52, 7, 69, 82, 67, 73, 65, 76, 32, 219, 216, 32, 65, 4, 166, + 166, 29, 77, 135, 150, 3, 65, 8, 158, 166, 8, 82, 228, 161, 16, 3, 79, + 83, 73, 250, 244, 2, 76, 231, 130, 4, 65, 38, 214, 1, 70, 84, 10, 83, 84, + 82, 85, 67, 84, 73, 79, 78, 32, 46, 84, 252, 235, 2, 8, 86, 69, 78, 73, + 69, 78, 67, 69, 204, 195, 18, 6, 73, 67, 65, 76, 32, 84, 234, 189, 9, 74, + 217, 102, 7, 71, 82, 85, 69, 78, 84, 32, 6, 140, 173, 27, 4, 69, 84, 84, + 73, 150, 242, 1, 85, 245, 163, 2, 4, 79, 85, 78, 68, 4, 240, 221, 20, 2, + 87, 79, 223, 240, 10, 83, 20, 80, 5, 65, 73, 78, 83, 32, 198, 1, 79, 28, + 4, 82, 79, 76, 32, 183, 146, 3, 73, 12, 48, 3, 65, 83, 32, 93, 5, 87, 73, + 84, 72, 32, 6, 186, 172, 24, 77, 181, 8, 15, 78, 79, 82, 77, 65, 76, 32, + 83, 85, 66, 71, 82, 79, 85, 80, 6, 250, 195, 4, 76, 202, 233, 19, 86, + 239, 243, 4, 79, 2, 229, 200, 30, 2, 85, 82, 4, 144, 251, 19, 3, 75, 78, + 79, 173, 134, 4, 8, 83, 69, 81, 85, 69, 78, 67, 69, 6, 26, 73, 147, 158, + 2, 69, 4, 150, 209, 32, 78, 87, 69, 206, 2, 36, 4, 84, 73, 67, 32, 175, + 18, 89, 202, 2, 186, 1, 67, 204, 1, 6, 69, 80, 65, 67, 84, 32, 86, 70, + 36, 11, 79, 76, 68, 32, 78, 85, 66, 73, 65, 78, 32, 110, 83, 213, 146, + 29, 13, 77, 79, 82, 80, 72, 79, 76, 79, 71, 73, 67, 65, 76, 126, 76, 9, + 79, 77, 66, 73, 78, 73, 78, 71, 32, 161, 3, 5, 65, 80, 73, 84, 65, 6, 68, + 9, 83, 80, 73, 82, 73, 84, 85, 83, 32, 201, 209, 31, 2, 78, 73, 4, 128, + 156, 6, 2, 76, 69, 181, 144, 17, 2, 65, 83, 56, 158, 188, 21, 78, 170, + 198, 2, 68, 141, 250, 6, 8, 84, 72, 79, 85, 83, 65, 78, 68, 4, 218, 187, + 18, 82, 195, 188, 11, 85, 8, 58, 68, 0, 3, 73, 78, 68, 146, 15, 86, 163, + 232, 29, 70, 2, 253, 247, 29, 7, 73, 82, 69, 67, 84, 32, 81, 134, 1, 56, + 3, 77, 65, 76, 197, 11, 6, 89, 77, 66, 79, 76, 32, 120, 45, 9, 76, 32, + 76, 69, 84, 84, 69, 82, 32, 120, 138, 2, 65, 48, 6, 66, 79, 72, 65, 73, + 82, 32, 2, 67, 82, 170, 1, 68, 160, 1, 2, 71, 65, 34, 72, 38, 75, 46, 70, + 34, 76, 66, 79, 138, 3, 83, 90, 84, 46, 90, 202, 218, 5, 86, 214, 54, 80, + 170, 211, 3, 73, 142, 189, 22, 82, 198, 3, 69, 218, 7, 77, 2, 78, 163, + 17, 85, 4, 44, 5, 75, 72, 77, 73, 77, 171, 208, 19, 76, 2, 177, 1, 4, 73, + 67, 32, 75, 10, 92, 12, 89, 80, 84, 79, 71, 82, 65, 77, 77, 73, 67, 32, + 53, 7, 79, 83, 83, 69, 68, 32, 83, 8, 50, 83, 226, 4, 71, 198, 167, 32, + 69, 219, 7, 78, 2, 187, 240, 24, 72, 12, 80, 9, 73, 65, 76, 69, 67, 84, + 45, 80, 32, 232, 161, 32, 2, 65, 76, 175, 17, 69, 8, 206, 163, 8, 72, + 174, 158, 8, 65, 200, 199, 12, 2, 75, 65, 211, 169, 3, 78, 4, 190, 3, 78, + 211, 161, 32, 77, 4, 178, 218, 25, 79, 187, 162, 5, 65, 8, 42, 72, 138, + 136, 29, 65, 211, 169, 3, 83, 4, 214, 177, 32, 69, 219, 19, 73, 4, 252, + 205, 19, 7, 45, 83, 72, 65, 80, 69, 68, 239, 251, 7, 65, 35, 36, 3, 76, + 68, 32, 195, 159, 32, 79, 30, 76, 7, 67, 79, 80, 84, 73, 67, 32, 193, 1, + 7, 78, 85, 66, 73, 65, 78, 32, 22, 98, 71, 42, 72, 188, 1, 2, 83, 72, + 162, 236, 14, 68, 238, 253, 9, 79, 254, 235, 5, 69, 183, 107, 65, 2, 17, + 2, 65, 78, 2, 231, 137, 16, 71, 8, 254, 214, 25, 79, 246, 130, 1, 65, + 131, 213, 5, 69, 8, 50, 78, 172, 192, 16, 2, 83, 72, 223, 158, 5, 87, 4, + 138, 174, 32, 71, 3, 89, 10, 54, 72, 238, 157, 6, 65, 190, 254, 25, 79, + 219, 3, 73, 4, 254, 159, 32, 73, 187, 13, 69, 4, 224, 147, 32, 3, 72, 69, + 84, 167, 8, 65, 2, 247, 155, 32, 65, 14, 62, 75, 30, 77, 2, 80, 22, 83, + 133, 132, 28, 3, 84, 65, 85, 4, 26, 72, 255, 171, 32, 65, 2, 151, 132, + 28, 73, 4, 132, 190, 16, 6, 72, 73, 77, 65, 32, 83, 193, 255, 3, 3, 84, + 65, 85, 4, 164, 220, 24, 3, 76, 69, 70, 133, 151, 2, 4, 82, 73, 71, 72, + 6, 96, 6, 78, 73, 83, 72, 32, 86, 188, 220, 25, 8, 82, 69, 83, 80, 79, + 78, 68, 83, 203, 213, 5, 65, 2, 241, 131, 29, 4, 69, 82, 83, 69, 44, 104, + 2, 78, 84, 192, 132, 3, 6, 67, 72, 32, 65, 78, 68, 201, 176, 28, 8, 80, + 76, 69, 32, 87, 73, 84, 72, 40, 56, 2, 69, 82, 37, 8, 73, 78, 71, 32, 82, + 79, 68, 32, 4, 246, 206, 27, 66, 167, 136, 1, 83, 36, 48, 4, 84, 69, 78, + 83, 1, 4, 85, 78, 73, 84, 18, 221, 239, 23, 2, 32, 68, 51, 82, 69, 76, 5, + 73, 67, 75, 69, 84, 34, 79, 198, 5, 85, 50, 89, 235, 245, 30, 65, 4, 240, + 175, 8, 3, 68, 73, 84, 165, 224, 20, 7, 83, 67, 69, 78, 84, 32, 77, 5, + 205, 144, 27, 3, 32, 66, 65, 28, 84, 2, 83, 83, 180, 144, 30, 3, 67, 79, + 68, 208, 156, 1, 3, 73, 83, 83, 155, 60, 87, 22, 46, 32, 184, 2, 3, 69, + 68, 32, 223, 1, 73, 14, 44, 3, 79, 70, 32, 82, 80, 163, 246, 31, 77, 4, + 216, 202, 28, 6, 74, 69, 82, 85, 83, 65, 133, 210, 2, 5, 76, 79, 82, 82, + 65, 8, 76, 10, 65, 84, 84, 89, 32, 87, 73, 84, 72, 32, 41, 5, 79, 77, 77, + 69, 69, 4, 206, 173, 10, 82, 25, 3, 76, 69, 70, 5, 225, 161, 3, 11, 32, + 87, 73, 84, 72, 32, 72, 65, 76, 70, 45, 6, 168, 152, 25, 37, 78, 69, 71, + 65, 84, 73, 86, 69, 32, 83, 81, 85, 65, 82, 69, 68, 32, 76, 65, 84, 73, + 78, 32, 67, 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, 248, 226, + 2, 2, 70, 76, 177, 216, 2, 3, 83, 87, 79, 2, 233, 254, 23, 5, 78, 71, 32, + 76, 65, 4, 184, 214, 17, 3, 90, 69, 73, 175, 187, 14, 84, 6, 214, 234, + 19, 73, 141, 160, 7, 4, 83, 84, 65, 76, 206, 19, 154, 1, 66, 20, 8, 78, + 69, 73, 70, 79, 82, 77, 32, 154, 250, 1, 80, 114, 82, 180, 3, 2, 83, 84, + 226, 234, 15, 67, 161, 191, 13, 6, 84, 32, 79, 70, 32, 77, 2, 179, 182, + 5, 69, 170, 19, 176, 1, 13, 78, 85, 77, 69, 82, 73, 67, 32, 83, 73, 71, + 78, 32, 184, 20, 17, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 83, + 73, 71, 78, 32, 233, 1, 5, 83, 73, 71, 78, 32, 222, 1, 78, 69, 166, 2, + 70, 152, 3, 2, 78, 73, 154, 2, 79, 130, 3, 83, 151, 4, 84, 24, 68, 5, 73, + 71, 72, 84, 32, 153, 1, 7, 76, 65, 77, 73, 84, 69, 32, 16, 142, 14, 83, + 230, 113, 85, 238, 50, 71, 136, 56, 17, 86, 65, 82, 73, 65, 78, 84, 32, + 70, 79, 82, 77, 32, 85, 83, 83, 85, 242, 223, 26, 68, 199, 249, 1, 65, 8, + 252, 155, 21, 5, 79, 78, 69, 32, 84, 234, 160, 9, 70, 175, 14, 84, 58, + 48, 4, 73, 86, 69, 32, 125, 4, 79, 85, 82, 32, 26, 70, 83, 206, 1, 66, + 250, 12, 65, 82, 71, 138, 110, 85, 231, 202, 27, 68, 6, 182, 15, 72, 245, + 158, 19, 5, 73, 88, 84, 72, 83, 32, 150, 1, 66, 44, 18, 86, 65, 82, 73, + 65, 78, 84, 32, 70, 79, 82, 77, 32, 76, 73, 77, 77, 85, 206, 12, 65, 82, + 71, 26, 83, 242, 109, 85, 231, 202, 27, 68, 6, 204, 123, 3, 65, 78, 50, + 183, 237, 26, 85, 9, 206, 211, 12, 32, 135, 215, 19, 52, 24, 44, 4, 71, + 73, 68, 65, 33, 3, 78, 69, 32, 4, 246, 190, 30, 69, 183, 107, 77, 20, + 156, 1, 19, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, 77, 32, 73, 76, + 73, 77, 77, 85, 174, 7, 83, 230, 113, 85, 238, 50, 71, 250, 151, 27, 68, + 199, 249, 1, 65, 9, 134, 166, 32, 32, 186, 2, 51, 3, 52, 28, 92, 16, 76, + 68, 32, 65, 83, 83, 89, 82, 73, 65, 78, 32, 79, 78, 69, 32, 37, 3, 78, + 69, 32, 4, 246, 208, 18, 83, 219, 208, 11, 81, 24, 166, 1, 69, 52, 8, 81, + 85, 65, 82, 84, 69, 82, 32, 206, 7, 66, 54, 71, 84, 5, 84, 72, 73, 82, + 68, 164, 214, 24, 2, 83, 72, 237, 205, 6, 6, 72, 65, 76, 70, 32, 71, 4, + 158, 8, 83, 205, 164, 1, 5, 73, 71, 72, 84, 72, 4, 174, 186, 30, 65, 183, + 114, 71, 38, 144, 1, 5, 69, 86, 69, 78, 32, 188, 1, 20, 72, 65, 82, 50, + 32, 84, 73, 77, 69, 83, 32, 71, 65, 76, 32, 80, 76, 85, 83, 32, 37, 3, + 73, 88, 32, 18, 148, 1, 17, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, + 77, 32, 73, 77, 73, 78, 218, 1, 83, 230, 113, 85, 238, 50, 71, 250, 151, + 27, 68, 199, 249, 1, 65, 6, 230, 203, 12, 32, 135, 215, 19, 51, 4, 250, + 189, 28, 68, 251, 228, 2, 77, 16, 142, 1, 83, 142, 3, 65, 218, 110, 85, + 238, 50, 71, 172, 130, 27, 16, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, + 82, 77, 32, 65, 83, 72, 207, 21, 68, 2, 227, 61, 72, 50, 52, 5, 72, 82, + 69, 69, 32, 241, 1, 3, 87, 79, 32, 28, 142, 1, 66, 40, 4, 83, 72, 65, 82, + 24, 16, 86, 65, 82, 73, 65, 78, 84, 32, 70, 79, 82, 77, 32, 69, 83, 72, + 118, 65, 82, 71, 239, 184, 28, 68, 6, 136, 112, 3, 85, 82, 85, 199, 10, + 65, 8, 226, 111, 50, 3, 85, 4, 222, 243, 24, 49, 203, 3, 50, 22, 82, 65, + 30, 66, 32, 2, 69, 83, 22, 71, 26, 83, 61, 6, 84, 72, 73, 82, 68, 83, 4, + 225, 184, 1, 2, 83, 72, 4, 254, 120, 65, 243, 226, 26, 85, 2, 211, 246, + 24, 72, 4, 53, 3, 69, 83, 72, 4, 11, 72, 4, 17, 2, 65, 82, 4, 254, 156, + 32, 50, 3, 85, 4, 11, 32, 4, 216, 211, 27, 12, 86, 65, 82, 73, 65, 78, + 84, 32, 70, 79, 82, 77, 179, 100, 68, 10, 160, 1, 9, 68, 73, 65, 71, 79, + 78, 65, 76, 32, 220, 222, 25, 6, 86, 69, 82, 84, 73, 67, 145, 130, 3, 14, + 79, 76, 68, 32, 65, 83, 83, 89, 82, 73, 65, 78, 32, 87, 6, 220, 203, 28, + 2, 84, 82, 244, 254, 2, 4, 81, 85, 65, 68, 15, 67, 194, 17, 202, 1, 65, + 186, 15, 66, 170, 5, 68, 190, 15, 69, 202, 10, 71, 182, 30, 72, 238, 3, + 73, 238, 4, 75, 154, 20, 76, 134, 37, 77, 134, 6, 78, 226, 17, 80, 210, + 3, 82, 42, 83, 238, 19, 84, 186, 8, 85, 207, 20, 90, 141, 1, 160, 1, 7, + 32, 84, 73, 77, 69, 83, 32, 142, 1, 66, 250, 3, 68, 38, 75, 90, 76, 212, + 1, 3, 77, 65, 82, 78, 78, 134, 2, 82, 42, 83, 138, 141, 31, 80, 215, 127, + 50, 16, 144, 173, 1, 5, 76, 65, 71, 65, 82, 226, 23, 71, 254, 253, 12, + 73, 174, 197, 13, 77, 162, 163, 2, 83, 194, 165, 1, 66, 246, 67, 72, 187, + 2, 65, 45, 22, 32, 219, 2, 50, 28, 48, 6, 84, 73, 77, 69, 83, 32, 139, + 203, 1, 71, 26, 180, 1, 2, 71, 65, 38, 73, 36, 2, 83, 72, 128, 113, 8, + 85, 32, 80, 76, 85, 83, 32, 85, 188, 56, 4, 68, 85, 78, 51, 166, 2, 65, + 204, 2, 3, 78, 85, 78, 242, 27, 76, 255, 198, 30, 72, 4, 194, 210, 1, 78, + 215, 193, 30, 76, 4, 210, 169, 1, 71, 207, 234, 29, 77, 4, 142, 236, 24, + 85, 187, 188, 5, 69, 15, 37, 7, 32, 84, 73, 77, 69, 83, 32, 12, 206, 133, + 1, 77, 130, 59, 71, 194, 9, 83, 234, 10, 84, 148, 210, 28, 2, 66, 65, + 251, 235, 1, 65, 5, 249, 51, 5, 32, 84, 73, 77, 69, 7, 37, 7, 32, 84, 73, + 77, 69, 83, 32, 4, 252, 27, 5, 83, 72, 73, 84, 65, 215, 80, 69, 23, 68, + 7, 32, 84, 73, 77, 69, 83, 32, 234, 221, 25, 69, 155, 227, 5, 65, 16, + 102, 75, 156, 173, 1, 2, 68, 73, 146, 254, 26, 71, 198, 249, 1, 85, 186, + 95, 65, 198, 94, 83, 215, 42, 72, 4, 130, 158, 1, 65, 247, 241, 30, 73, + 7, 37, 7, 32, 84, 73, 77, 69, 83, 32, 4, 142, 254, 3, 75, 147, 228, 27, + 83, 13, 26, 32, 227, 225, 31, 83, 8, 128, 1, 10, 80, 76, 85, 83, 32, 78, + 65, 71, 65, 32, 172, 192, 8, 7, 84, 72, 82, 69, 69, 32, 84, 141, 131, 6, + 4, 79, 86, 69, 82, 4, 144, 140, 1, 16, 79, 80, 80, 79, 83, 73, 78, 71, + 32, 65, 78, 32, 80, 76, 85, 83, 215, 195, 23, 83, 6, 200, 49, 2, 65, 68, + 151, 166, 18, 75, 18, 26, 72, 139, 173, 12, 65, 17, 42, 32, 242, 214, 18, + 71, 167, 181, 13, 50, 10, 68, 9, 79, 86, 69, 82, 32, 65, 83, 72, 32, 174, + 97, 90, 135, 112, 75, 6, 176, 1, 8, 79, 86, 69, 82, 32, 65, 83, 72, 157, + 143, 1, 29, 84, 85, 71, 50, 32, 79, 86, 69, 82, 32, 84, 85, 71, 50, 32, + 84, 85, 71, 50, 32, 79, 86, 69, 82, 32, 84, 85, 71, 50, 5, 149, 145, 1, + 27, 32, 67, 82, 79, 83, 83, 73, 78, 71, 32, 65, 83, 72, 32, 79, 86, 69, + 82, 32, 65, 83, 72, 32, 79, 86, 69, 82, 52, 30, 65, 158, 2, 73, 95, 85, + 27, 66, 68, 44, 4, 72, 65, 82, 50, 90, 76, 66, 82, 151, 140, 28, 71, 5, + 145, 208, 1, 6, 32, 84, 73, 77, 69, 83, 9, 37, 7, 32, 84, 73, 77, 69, 83, + 32, 6, 238, 164, 1, 65, 154, 207, 30, 78, 163, 17, 90, 7, 208, 251, 30, + 7, 32, 79, 86, 69, 82, 32, 66, 139, 139, 1, 65, 5, 175, 223, 24, 65, 9, + 37, 7, 32, 84, 73, 77, 69, 83, 32, 6, 134, 156, 1, 73, 242, 198, 29, 71, + 191, 163, 1, 65, 19, 50, 32, 168, 1, 3, 76, 85, 71, 239, 169, 1, 82, 8, + 88, 8, 79, 86, 69, 82, 32, 66, 85, 32, 149, 208, 27, 8, 67, 82, 79, 83, + 83, 73, 78, 71, 6, 160, 207, 12, 7, 84, 73, 77, 69, 83, 32, 78, 214, 247, + 17, 65, 155, 110, 85, 5, 249, 242, 3, 8, 32, 79, 86, 69, 82, 32, 66, 85, + 180, 1, 34, 65, 222, 5, 73, 195, 2, 85, 67, 50, 71, 150, 5, 82, 146, 49, + 32, 243, 204, 31, 77, 55, 26, 32, 251, 130, 32, 51, 50, 76, 13, 75, 73, + 83, 73, 77, 53, 32, 84, 73, 77, 69, 83, 32, 227, 198, 1, 84, 48, 146, 1, + 65, 30, 66, 38, 71, 112, 2, 73, 82, 42, 76, 94, 85, 182, 131, 1, 80, 162, + 61, 84, 134, 133, 28, 75, 182, 162, 2, 78, 254, 2, 83, 163, 17, 72, 4, + 110, 32, 235, 220, 30, 77, 4, 254, 148, 30, 65, 251, 235, 1, 73, 10, 34, + 65, 58, 73, 219, 185, 31, 85, 5, 11, 32, 2, 141, 149, 30, 6, 80, 76, 85, + 83, 32, 77, 5, 183, 216, 24, 82, 5, 129, 142, 14, 5, 32, 80, 76, 85, 83, + 8, 26, 85, 163, 255, 31, 65, 7, 160, 151, 1, 7, 32, 80, 76, 85, 83, 32, + 77, 255, 231, 30, 77, 6, 52, 7, 50, 32, 80, 76, 85, 83, 32, 155, 253, 31, + 83, 4, 128, 27, 2, 71, 73, 147, 248, 29, 77, 7, 187, 202, 12, 65, 25, 54, + 77, 150, 1, 78, 76, 2, 83, 72, 215, 251, 31, 66, 13, 44, 7, 32, 84, 73, + 77, 69, 83, 32, 59, 50, 6, 220, 69, 2, 85, 32, 238, 226, 13, 73, 175, + 167, 17, 83, 5, 205, 166, 13, 6, 32, 84, 73, 77, 69, 83, 5, 253, 253, 18, + 14, 32, 75, 65, 83, 75, 65, 76, 32, 85, 32, 71, 85, 78, 85, 5, 245, 157, + 1, 5, 32, 80, 76, 85, 83, 91, 70, 32, 66, 66, 94, 71, 234, 4, 78, 162, + 205, 24, 82, 195, 167, 7, 72, 6, 154, 176, 1, 71, 170, 3, 83, 181, 211, + 12, 4, 79, 86, 69, 82, 9, 52, 7, 32, 84, 73, 77, 69, 83, 32, 239, 249, + 31, 50, 4, 250, 145, 1, 69, 231, 186, 30, 83, 61, 52, 7, 32, 84, 73, 77, + 69, 83, 32, 243, 178, 31, 85, 56, 122, 65, 58, 68, 30, 71, 74, 75, 90, + 76, 110, 77, 50, 83, 130, 80, 69, 218, 58, 73, 130, 213, 16, 72, 214, + 129, 14, 78, 3, 80, 6, 32, 2, 83, 72, 219, 202, 31, 78, 5, 251, 220, 14, + 32, 4, 250, 167, 31, 73, 3, 85, 8, 26, 73, 167, 247, 31, 65, 7, 140, 141, + 1, 2, 82, 50, 135, 233, 30, 83, 8, 26, 85, 211, 185, 1, 65, 6, 40, 4, 83, + 72, 85, 50, 179, 246, 31, 82, 5, 175, 26, 32, 8, 26, 65, 45, 2, 85, 72, + 6, 202, 26, 77, 169, 178, 24, 3, 75, 45, 48, 2, 225, 57, 5, 32, 80, 76, + 85, 83, 6, 170, 138, 30, 65, 174, 173, 1, 69, 223, 61, 73, 4, 238, 138, + 1, 73, 195, 211, 30, 72, 11, 26, 51, 199, 244, 31, 52, 7, 143, 9, 32, + 117, 130, 1, 32, 90, 50, 210, 1, 78, 202, 1, 82, 60, 3, 83, 72, 50, 52, + 3, 90, 69, 78, 242, 239, 18, 71, 142, 255, 11, 68, 215, 127, 76, 4, 168, + 25, 11, 79, 86, 69, 82, 32, 69, 32, 78, 85, 78, 32, 253, 94, 4, 84, 73, + 77, 69, 19, 37, 7, 32, 84, 73, 77, 69, 83, 32, 16, 134, 1, 83, 144, 168, + 1, 10, 65, 32, 80, 76, 85, 83, 32, 72, 65, 32, 222, 165, 29, 71, 182, 16, + 80, 182, 26, 75, 254, 100, 77, 219, 19, 85, 4, 214, 229, 30, 65, 255, + 116, 72, 15, 11, 32, 12, 96, 4, 67, 82, 79, 83, 0, 4, 79, 80, 80, 79, 36, + 6, 84, 73, 77, 69, 83, 32, 247, 177, 24, 83, 2, 245, 160, 14, 4, 83, 73, + 78, 71, 6, 204, 138, 1, 4, 71, 65, 78, 50, 211, 206, 30, 77, 6, 36, 3, + 73, 78, 50, 187, 159, 31, 69, 5, 215, 224, 30, 32, 5, 229, 16, 9, 32, 67, + 82, 79, 83, 83, 73, 78, 71, 63, 11, 32, 60, 96, 14, 83, 72, 69, 83, 72, + 73, 71, 32, 84, 73, 77, 69, 83, 32, 97, 6, 84, 73, 77, 69, 83, 32, 16, + 178, 131, 1, 73, 254, 224, 2, 77, 170, 158, 26, 65, 220, 110, 2, 76, 65, + 198, 87, 83, 147, 17, 72, 44, 134, 1, 65, 68, 5, 68, 85, 78, 51, 32, 26, + 75, 58, 76, 62, 83, 34, 85, 222, 127, 73, 204, 31, 2, 72, 65, 242, 156, + 29, 71, 199, 103, 66, 9, 244, 86, 9, 32, 80, 76, 85, 83, 32, 76, 65, 76, + 131, 149, 31, 78, 4, 217, 32, 2, 71, 85, 6, 132, 173, 24, 5, 65, 83, 75, + 65, 76, 187, 195, 3, 85, 8, 34, 65, 194, 234, 31, 73, 3, 85, 5, 201, 85, + 2, 76, 32, 4, 210, 211, 31, 72, 215, 22, 85, 4, 134, 234, 31, 50, 3, 68, + 160, 2, 42, 65, 166, 19, 69, 122, 73, 135, 5, 85, 191, 1, 114, 50, 144, + 16, 2, 66, 65, 94, 68, 22, 76, 38, 78, 206, 140, 1, 32, 154, 6, 82, 166, + 175, 28, 83, 155, 149, 2, 77, 153, 1, 11, 32, 150, 1, 68, 6, 84, 73, 77, + 69, 83, 32, 153, 128, 1, 5, 79, 86, 69, 82, 32, 148, 1, 202, 1, 65, 162, + 2, 66, 154, 1, 68, 178, 1, 69, 58, 71, 178, 1, 72, 230, 1, 73, 70, 75, + 194, 1, 76, 62, 77, 50, 78, 130, 1, 83, 142, 1, 85, 222, 154, 1, 84, 204, + 150, 23, 3, 90, 73, 90, 139, 165, 7, 80, 18, 132, 1, 6, 32, 80, 76, 85, + 83, 32, 50, 78, 52, 2, 83, 72, 137, 175, 18, 14, 66, 50, 32, 84, 69, 78, + 85, 32, 80, 76, 85, 83, 32, 84, 6, 202, 58, 68, 142, 214, 13, 73, 131, + 210, 17, 72, 5, 185, 61, 9, 32, 80, 76, 85, 83, 32, 75, 65, 75, 7, 11, + 50, 5, 133, 90, 6, 32, 80, 76, 85, 83, 32, 10, 26, 65, 77, 2, 85, 82, 6, + 42, 72, 44, 2, 82, 32, 135, 227, 31, 68, 2, 11, 65, 2, 227, 187, 24, 82, + 5, 11, 32, 2, 169, 152, 31, 4, 80, 76, 85, 83, 14, 34, 73, 54, 85, 139, + 226, 31, 65, 7, 17, 2, 77, 32, 4, 146, 22, 84, 207, 129, 1, 71, 6, 56, 8, + 71, 32, 84, 73, 77, 69, 83, 32, 207, 225, 31, 66, 4, 158, 119, 73, 151, + 45, 75, 10, 38, 78, 254, 2, 76, 139, 136, 30, 82, 5, 243, 28, 32, 18, 18, + 65, 99, 73, 11, 26, 82, 247, 158, 1, 78, 7, 33, 6, 32, 80, 76, 85, 83, + 32, 4, 206, 201, 31, 78, 255, 2, 68, 9, 174, 122, 52, 253, 242, 12, 7, + 82, 50, 32, 80, 76, 85, 83, 12, 62, 65, 154, 124, 85, 233, 240, 12, 6, + 73, 32, 80, 76, 85, 83, 8, 40, 6, 32, 80, 76, 85, 83, 32, 83, 76, 4, 48, + 6, 76, 85, 32, 80, 76, 85, 171, 222, 31, 65, 2, 11, 83, 2, 215, 97, 32, + 5, 149, 236, 13, 5, 32, 80, 76, 85, 83, 4, 176, 100, 10, 83, 72, 32, 80, + 76, 85, 83, 32, 72, 85, 147, 15, 71, 12, 34, 65, 36, 2, 73, 68, 27, 85, + 4, 234, 224, 24, 83, 147, 252, 6, 75, 5, 225, 77, 2, 32, 80, 4, 60, 5, + 83, 72, 85, 50, 32, 197, 127, 5, 51, 32, 80, 76, 85, 2, 205, 158, 1, 3, + 80, 76, 85, 8, 26, 65, 183, 218, 31, 85, 7, 11, 77, 5, 227, 159, 1, 32, + 6, 250, 77, 69, 162, 162, 29, 85, 139, 235, 1, 73, 10, 26, 69, 73, 2, 85, + 78, 7, 33, 6, 32, 80, 76, 85, 83, 32, 4, 242, 178, 24, 69, 235, 147, 7, + 71, 5, 11, 32, 2, 187, 101, 79, 14, 42, 72, 254, 235, 23, 65, 247, 220, + 7, 85, 8, 18, 69, 51, 73, 5, 221, 224, 30, 7, 32, 80, 76, 85, 83, 32, 84, + 4, 130, 217, 31, 68, 3, 77, 7, 11, 68, 5, 237, 228, 13, 5, 32, 80, 76, + 85, 83, 7, 11, 32, 4, 206, 249, 29, 82, 177, 177, 1, 11, 67, 82, 79, 83, + 83, 73, 78, 71, 32, 71, 65, 5, 191, 131, 1, 32, 7, 134, 131, 1, 32, 231, + 195, 30, 65, 11, 11, 50, 9, 11, 32, 6, 80, 8, 67, 82, 79, 83, 83, 73, 78, + 71, 0, 4, 79, 86, 69, 82, 239, 207, 26, 84, 2, 197, 49, 3, 32, 71, 65, 8, + 44, 5, 83, 72, 84, 73, 78, 171, 174, 24, 50, 7, 37, 7, 32, 84, 73, 77, + 69, 83, 32, 4, 234, 220, 30, 75, 215, 120, 85, 49, 70, 32, 94, 52, 114, + 82, 190, 1, 83, 130, 207, 30, 68, 211, 130, 1, 71, 6, 152, 133, 9, 6, 84, + 73, 77, 69, 83, 32, 249, 250, 4, 8, 67, 82, 79, 83, 83, 73, 78, 71, 7, + 11, 32, 4, 64, 8, 67, 82, 79, 83, 83, 73, 78, 71, 1, 4, 79, 86, 69, 82, + 2, 197, 170, 24, 3, 32, 71, 73, 16, 26, 51, 147, 136, 1, 50, 13, 37, 7, + 32, 84, 73, 77, 69, 83, 32, 10, 70, 65, 0, 2, 76, 85, 206, 127, 71, 254, + 253, 12, 73, 131, 210, 17, 80, 2, 197, 253, 13, 7, 32, 80, 76, 85, 83, + 32, 73, 14, 26, 72, 231, 197, 30, 65, 13, 11, 32, 10, 22, 84, 247, 20, + 67, 8, 44, 5, 73, 77, 69, 83, 32, 239, 171, 31, 69, 6, 192, 20, 6, 71, + 73, 83, 72, 32, 67, 146, 126, 84, 227, 247, 29, 66, 43, 110, 50, 174, 1, + 68, 218, 1, 77, 54, 82, 152, 250, 13, 9, 32, 67, 82, 79, 83, 83, 73, 78, + 71, 223, 209, 17, 76, 15, 11, 32, 12, 48, 6, 84, 73, 77, 69, 83, 32, 167, + 132, 1, 71, 10, 252, 24, 3, 75, 65, 75, 194, 75, 73, 152, 20, 10, 83, 65, + 76, 32, 80, 76, 85, 83, 32, 84, 231, 213, 29, 78, 11, 11, 32, 8, 128, 1, + 10, 80, 76, 85, 83, 32, 71, 73, 83, 72, 32, 16, 6, 84, 73, 77, 69, 83, + 32, 177, 66, 8, 79, 86, 69, 82, 32, 71, 85, 68, 2, 135, 121, 84, 4, 172, + 145, 1, 5, 65, 32, 80, 76, 85, 223, 194, 29, 75, 5, 17, 2, 32, 84, 2, + 241, 42, 4, 73, 77, 69, 83, 9, 26, 85, 219, 203, 31, 55, 4, 198, 202, 31, + 83, 147, 1, 78, 50, 30, 65, 82, 73, 215, 1, 85, 11, 26, 32, 255, 202, 31, + 76, 6, 32, 2, 84, 69, 147, 128, 1, 71, 4, 235, 127, 78, 23, 37, 7, 32, + 84, 73, 77, 69, 83, 32, 20, 104, 3, 65, 83, 72, 234, 228, 27, 68, 158, + 228, 2, 78, 94, 75, 170, 57, 66, 2, 71, 162, 25, 83, 143, 45, 85, 7, 224, + 55, 8, 32, 79, 86, 69, 82, 32, 72, 73, 211, 145, 31, 50, 19, 48, 2, 66, + 50, 130, 161, 24, 76, 179, 166, 7, 83, 13, 37, 7, 32, 84, 73, 77, 69, 83, + 32, 10, 254, 138, 1, 75, 206, 216, 26, 76, 242, 216, 2, 72, 254, 59, 65, + 195, 9, 85, 49, 104, 3, 68, 73, 77, 94, 71, 214, 1, 76, 62, 77, 190, 193, + 31, 32, 170, 1, 83, 146, 1, 66, 2, 78, 3, 82, 7, 53, 11, 32, 79, 86, 69, + 82, 32, 73, 68, 73, 77, 32, 4, 166, 136, 24, 83, 175, 197, 6, 66, 13, 11, + 73, 11, 11, 32, 8, 162, 123, 71, 204, 244, 11, 31, 79, 86, 69, 82, 32, + 73, 71, 73, 32, 83, 72, 73, 82, 32, 79, 86, 69, 82, 32, 83, 72, 73, 82, + 32, 85, 68, 32, 79, 86, 69, 82, 250, 151, 17, 68, 175, 170, 1, 82, 7, 26, + 32, 151, 196, 31, 50, 2, 169, 72, 4, 84, 73, 77, 69, 13, 26, 32, 251, + 243, 30, 73, 8, 76, 4, 67, 82, 79, 83, 0, 4, 79, 80, 80, 79, 162, 111, + 84, 235, 149, 23, 83, 2, 181, 192, 30, 5, 83, 73, 78, 71, 32, 224, 1, 78, + 65, 146, 15, 73, 242, 1, 85, 158, 73, 69, 193, 188, 23, 4, 87, 85, 51, + 49, 177, 1, 164, 1, 7, 32, 84, 73, 77, 69, 83, 32, 210, 9, 50, 66, 68, + 102, 75, 50, 76, 98, 77, 28, 4, 83, 75, 65, 76, 184, 207, 15, 6, 80, 32, + 69, 76, 65, 77, 139, 229, 15, 66, 134, 1, 170, 1, 65, 94, 66, 82, 69, 30, + 71, 182, 2, 73, 34, 75, 34, 76, 38, 77, 170, 1, 83, 118, 84, 34, 85, 214, + 8, 72, 246, 51, 78, 162, 230, 16, 80, 198, 240, 13, 82, 147, 17, 90, 13, + 46, 68, 234, 145, 31, 78, 165, 44, 2, 83, 72, 5, 229, 50, 7, 32, 80, 76, + 85, 83, 32, 75, 10, 34, 65, 178, 190, 31, 73, 3, 85, 6, 194, 210, 29, 76, + 238, 235, 1, 68, 3, 82, 4, 138, 25, 82, 151, 61, 83, 26, 30, 65, 98, 73, + 147, 1, 85, 11, 38, 82, 206, 123, 78, 215, 193, 30, 76, 5, 249, 21, 10, + 32, 80, 76, 85, 83, 32, 83, 72, 65, 51, 11, 32, 2, 83, 72, 135, 149, 24, 82, 7, 11, 32, 4, 26, 67, 255, 130, 1, 80, 2, 37, 7, 82, 79, 83, 83, 73, - 78, 71, 2, 137, 185, 27, 2, 32, 71, 7, 182, 164, 27, 82, 179, 245, 3, 68, - 4, 234, 133, 31, 71, 219, 19, 77, 8, 250, 8, 73, 195, 164, 17, 65, 6, - 218, 163, 12, 85, 171, 245, 18, 73, 12, 18, 69, 83, 73, 9, 33, 6, 32, 80, - 76, 85, 83, 32, 6, 190, 243, 30, 68, 150, 14, 84, 255, 2, 71, 5, 45, 9, - 32, 80, 76, 85, 83, 32, 78, 85, 78, 2, 159, 244, 26, 85, 18, 62, 72, 178, - 196, 27, 65, 244, 217, 2, 2, 85, 72, 131, 120, 73, 10, 202, 154, 30, 85, - 142, 54, 73, 162, 70, 65, 3, 69, 4, 230, 221, 30, 65, 223, 56, 85, 17, - 110, 32, 238, 92, 82, 180, 142, 26, 9, 77, 85, 77, 32, 84, 73, 77, 69, - 83, 134, 169, 4, 83, 146, 1, 50, 3, 68, 2, 235, 137, 21, 85, 5, 197, 248, - 11, 11, 32, 67, 82, 79, 83, 83, 73, 78, 71, 32, 75, 10, 42, 53, 182, 148, - 31, 50, 2, 51, 3, 52, 5, 129, 249, 23, 9, 32, 79, 86, 69, 82, 32, 75, 65, - 68, 5, 189, 75, 8, 32, 84, 73, 77, 69, 83, 32, 73, 9, 26, 32, 219, 130, - 31, 65, 4, 166, 105, 84, 249, 187, 23, 9, 67, 82, 79, 83, 83, 73, 78, 71, - 32, 4, 234, 146, 31, 50, 3, 52, 7, 11, 32, 4, 70, 76, 1, 13, 79, 86, 69, + 78, 71, 2, 165, 215, 27, 2, 32, 71, 7, 210, 193, 27, 82, 135, 250, 3, 68, + 4, 218, 167, 31, 71, 219, 19, 77, 8, 250, 8, 73, 135, 179, 17, 65, 6, + 202, 177, 12, 85, 171, 137, 19, 73, 12, 18, 69, 83, 73, 9, 33, 6, 32, 80, + 76, 85, 83, 32, 6, 174, 149, 31, 68, 150, 14, 84, 255, 2, 71, 5, 45, 9, + 32, 80, 76, 85, 83, 32, 78, 85, 78, 2, 147, 219, 29, 85, 18, 62, 72, 206, + 226, 27, 65, 200, 221, 2, 2, 85, 72, 131, 120, 73, 10, 186, 188, 30, 85, + 142, 54, 73, 162, 70, 65, 3, 69, 4, 214, 255, 30, 65, 223, 56, 85, 17, + 110, 32, 238, 92, 82, 200, 167, 26, 9, 77, 85, 77, 32, 84, 73, 77, 69, + 83, 226, 177, 4, 83, 146, 1, 50, 3, 68, 2, 207, 156, 21, 85, 5, 193, 129, + 12, 11, 32, 67, 82, 79, 83, 83, 73, 78, 71, 32, 75, 10, 42, 53, 166, 182, + 31, 50, 2, 51, 3, 52, 5, 221, 140, 24, 9, 32, 79, 86, 69, 82, 32, 75, 65, + 68, 5, 189, 75, 8, 32, 84, 73, 77, 69, 83, 32, 73, 9, 26, 32, 203, 164, + 31, 65, 4, 166, 105, 84, 233, 207, 23, 9, 67, 82, 79, 83, 83, 73, 78, 71, + 32, 4, 218, 180, 31, 50, 3, 52, 7, 11, 32, 4, 70, 76, 1, 13, 79, 86, 69, 82, 32, 75, 65, 83, 75, 65, 76, 32, 76, 2, 173, 116, 24, 65, 71, 65, 66, 32, 84, 73, 77, 69, 83, 32, 85, 32, 79, 86, 69, 82, 32, 76, 65, 71, 65, - 66, 32, 21, 68, 7, 32, 84, 73, 77, 69, 83, 32, 50, 83, 150, 144, 31, 68, - 3, 78, 6, 26, 85, 255, 201, 30, 66, 5, 167, 144, 31, 68, 8, 52, 3, 73, - 77, 53, 170, 134, 30, 65, 183, 137, 1, 72, 5, 169, 244, 23, 11, 32, 79, + 66, 32, 21, 68, 7, 32, 84, 73, 77, 69, 83, 32, 50, 83, 134, 178, 31, 68, + 3, 78, 6, 26, 85, 239, 235, 30, 66, 5, 151, 178, 31, 68, 8, 52, 3, 73, + 77, 53, 254, 165, 30, 65, 211, 139, 1, 72, 5, 133, 136, 24, 11, 32, 79, 86, 69, 82, 32, 75, 73, 83, 73, 77, 25, 200, 1, 29, 32, 79, 86, 69, 82, 32, 72, 73, 32, 84, 73, 77, 69, 83, 32, 65, 83, 72, 50, 32, 75, 85, 32, - 79, 86, 69, 82, 32, 72, 18, 52, 54, 82, 186, 98, 83, 230, 1, 76, 242, - 168, 30, 51, 2, 55, 3, 78, 2, 155, 71, 73, 5, 221, 142, 30, 8, 32, 86, + 79, 86, 69, 82, 32, 72, 18, 52, 54, 82, 186, 98, 83, 230, 1, 76, 226, + 202, 30, 51, 2, 55, 3, 78, 2, 155, 71, 73, 5, 205, 176, 30, 8, 32, 86, 65, 82, 73, 65, 78, 84, 5, 213, 115, 9, 32, 79, 80, 80, 79, 83, 73, 78, 71, 240, 2, 30, 65, 174, 26, 73, 59, 85, 141, 2, 68, 2, 71, 65, 252, 12, 2, 75, 45, 222, 11, 76, 46, 77, 135, 55, 72, 118, 22, 66, 131, 11, 82, - 109, 11, 32, 106, 48, 6, 84, 73, 77, 69, 83, 32, 167, 219, 23, 83, 104, + 109, 11, 32, 106, 48, 6, 84, 73, 77, 69, 83, 32, 131, 239, 23, 83, 104, 190, 1, 65, 186, 1, 66, 34, 71, 70, 72, 66, 73, 94, 75, 118, 76, 46, 77, - 46, 83, 138, 2, 84, 126, 85, 188, 165, 4, 8, 90, 85, 32, 79, 86, 69, 82, - 32, 214, 186, 25, 68, 218, 81, 69, 143, 57, 78, 15, 80, 6, 32, 80, 76, - 85, 83, 32, 76, 4, 83, 72, 32, 90, 178, 136, 31, 76, 3, 78, 6, 38, 68, - 158, 231, 29, 71, 251, 23, 76, 2, 201, 62, 5, 65, 32, 80, 76, 85, 2, 149, - 112, 2, 73, 68, 4, 246, 193, 30, 65, 163, 70, 73, 10, 48, 2, 85, 68, 254, - 180, 27, 65, 203, 210, 3, 73, 5, 191, 105, 32, 6, 164, 238, 17, 7, 73, - 32, 84, 73, 77, 69, 83, 227, 156, 12, 65, 8, 22, 77, 175, 62, 71, 7, 33, - 6, 32, 80, 76, 85, 83, 32, 4, 206, 225, 30, 76, 179, 34, 72, 10, 26, 85, - 251, 138, 29, 73, 6, 26, 76, 227, 133, 31, 51, 5, 41, 8, 32, 80, 76, 85, - 83, 32, 72, 73, 2, 219, 65, 32, 8, 198, 100, 65, 190, 184, 28, 73, 247, - 107, 85, 6, 26, 69, 191, 156, 29, 85, 5, 175, 25, 32, 12, 26, 72, 219, - 243, 30, 85, 10, 100, 14, 73, 84, 65, 32, 80, 76, 85, 83, 32, 71, 73, 83, + 46, 83, 138, 2, 84, 126, 85, 156, 172, 4, 8, 90, 85, 32, 79, 86, 69, 82, + 32, 226, 211, 25, 68, 222, 83, 69, 143, 57, 78, 15, 80, 6, 32, 80, 76, + 85, 83, 32, 76, 4, 83, 72, 32, 90, 162, 170, 31, 76, 3, 78, 6, 38, 68, + 138, 135, 30, 71, 227, 23, 76, 2, 201, 62, 5, 65, 32, 80, 76, 85, 2, 149, + 112, 2, 73, 68, 4, 230, 227, 30, 65, 163, 70, 73, 10, 48, 2, 85, 68, 154, + 211, 27, 65, 159, 214, 3, 73, 5, 191, 105, 32, 6, 204, 252, 17, 7, 73, + 32, 84, 73, 77, 69, 83, 171, 176, 12, 65, 8, 22, 77, 175, 62, 71, 7, 33, + 6, 32, 80, 76, 85, 83, 32, 4, 190, 131, 31, 76, 179, 34, 72, 10, 26, 85, + 131, 170, 29, 73, 6, 26, 76, 211, 167, 31, 51, 5, 41, 8, 32, 80, 76, 85, + 83, 32, 72, 73, 2, 219, 65, 32, 8, 198, 100, 65, 198, 215, 28, 73, 223, + 110, 85, 6, 26, 69, 199, 187, 29, 85, 5, 175, 25, 32, 12, 26, 72, 203, + 149, 31, 85, 10, 100, 14, 73, 84, 65, 32, 80, 76, 85, 83, 32, 71, 73, 83, 72, 32, 96, 2, 85, 50, 217, 3, 2, 69, 32, 4, 48, 6, 80, 76, 85, 83, 32, - 69, 163, 133, 26, 84, 2, 11, 82, 2, 11, 73, 2, 207, 233, 23, 78, 5, 189, + 69, 191, 158, 26, 84, 2, 11, 82, 2, 11, 73, 2, 171, 253, 23, 78, 5, 189, 73, 5, 32, 80, 76, 85, 83, 6, 86, 65, 189, 30, 16, 69, 32, 80, 76, 85, - 83, 32, 65, 32, 80, 76, 85, 83, 32, 83, 85, 4, 154, 231, 23, 75, 211, - 154, 7, 71, 13, 72, 6, 32, 80, 76, 85, 83, 32, 190, 41, 50, 178, 214, 30, - 83, 147, 1, 68, 4, 26, 85, 227, 128, 31, 65, 2, 255, 40, 32, 11, 11, 32, + 83, 32, 65, 32, 80, 76, 85, 83, 32, 83, 85, 4, 246, 250, 23, 75, 231, + 168, 7, 71, 13, 72, 6, 32, 80, 76, 85, 83, 32, 190, 41, 50, 162, 248, 30, + 83, 147, 1, 68, 4, 26, 85, 211, 162, 31, 65, 2, 255, 40, 32, 11, 11, 32, 8, 68, 4, 71, 85, 78, 85, 97, 9, 84, 73, 77, 69, 83, 32, 83, 72, 69, 5, 73, 16, 32, 79, 86, 69, 82, 32, 76, 65, 71, 65, 82, 32, 71, 85, 78, 85, - 2, 151, 210, 30, 32, 5, 11, 32, 2, 157, 196, 14, 4, 80, 76, 85, 83, 136, + 2, 135, 244, 30, 32, 5, 11, 32, 2, 201, 210, 14, 4, 80, 76, 85, 83, 136, 1, 82, 48, 146, 2, 49, 30, 50, 114, 51, 82, 52, 222, 2, 54, 154, 4, 55, 243, 24, 53, 22, 158, 1, 50, 30, 56, 180, 52, 15, 55, 57, 32, 79, 86, 69, - 82, 32, 76, 65, 75, 45, 48, 55, 57, 246, 245, 10, 53, 134, 185, 12, 54, - 2, 57, 94, 51, 203, 162, 3, 48, 4, 242, 252, 30, 49, 3, 53, 4, 136, 227, - 23, 12, 49, 32, 79, 86, 69, 82, 32, 76, 65, 75, 45, 48, 207, 153, 7, 48, - 4, 214, 226, 23, 52, 95, 51, 16, 46, 50, 38, 54, 222, 219, 23, 49, 159, - 2, 51, 6, 182, 251, 30, 48, 2, 53, 3, 56, 4, 146, 251, 30, 53, 3, 54, 12, - 42, 52, 254, 223, 11, 56, 131, 130, 12, 57, 6, 202, 250, 30, 51, 2, 55, - 3, 56, 30, 62, 52, 214, 1, 53, 30, 57, 170, 223, 23, 55, 203, 162, 3, 56, - 14, 26, 57, 207, 249, 30, 49, 13, 37, 7, 32, 84, 73, 77, 69, 83, 32, 10, - 116, 9, 80, 65, 80, 32, 80, 76, 85, 83, 32, 240, 151, 13, 7, 85, 50, 32, - 80, 76, 85, 83, 238, 31, 73, 235, 155, 17, 71, 4, 210, 13, 80, 51, 76, 4, - 146, 248, 30, 48, 3, 55, 8, 246, 247, 30, 48, 2, 50, 2, 51, 3, 53, 46, - 60, 2, 49, 55, 240, 1, 2, 52, 56, 130, 216, 23, 48, 23, 51, 23, 37, 7, + 82, 32, 76, 65, 75, 45, 48, 55, 57, 254, 254, 10, 53, 218, 195, 12, 54, + 2, 57, 94, 51, 139, 172, 3, 48, 4, 226, 158, 31, 49, 3, 53, 4, 228, 246, + 23, 12, 49, 32, 79, 86, 69, 82, 32, 76, 65, 75, 45, 48, 227, 167, 7, 48, + 4, 178, 246, 23, 52, 95, 51, 16, 46, 50, 38, 54, 186, 239, 23, 49, 159, + 2, 51, 6, 166, 157, 31, 48, 2, 53, 3, 56, 4, 130, 157, 31, 53, 3, 54, 12, + 42, 52, 250, 232, 11, 56, 227, 140, 12, 57, 6, 186, 156, 31, 51, 2, 55, + 3, 56, 30, 62, 52, 214, 1, 53, 30, 57, 134, 243, 23, 55, 139, 172, 3, 56, + 14, 26, 57, 191, 155, 31, 49, 13, 37, 7, 32, 84, 73, 77, 69, 83, 32, 10, + 116, 9, 80, 65, 80, 32, 80, 76, 85, 83, 32, 140, 166, 13, 7, 85, 50, 32, + 80, 76, 85, 83, 218, 31, 73, 211, 175, 17, 71, 4, 210, 13, 80, 51, 76, 4, + 130, 154, 31, 48, 3, 55, 8, 230, 153, 31, 48, 2, 50, 2, 51, 3, 53, 46, + 60, 2, 49, 55, 240, 1, 2, 52, 56, 222, 235, 23, 48, 23, 51, 23, 37, 7, 32, 84, 73, 77, 69, 83, 32, 20, 122, 84, 34, 85, 162, 11, 75, 132, 34, 9, - 68, 85, 78, 51, 32, 71, 85, 78, 85, 134, 224, 28, 65, 246, 161, 1, 66, - 247, 67, 76, 4, 138, 189, 30, 65, 223, 56, 69, 6, 178, 199, 14, 82, 150, - 174, 16, 50, 3, 68, 21, 37, 7, 32, 84, 73, 77, 69, 83, 32, 18, 154, 1, - 85, 220, 8, 4, 80, 65, 80, 32, 146, 45, 73, 196, 219, 12, 10, 83, 72, 69, - 83, 72, 32, 80, 76, 85, 83, 210, 132, 5, 68, 130, 202, 12, 78, 163, 17, - 71, 4, 194, 197, 14, 82, 151, 174, 16, 68, 4, 226, 216, 23, 50, 143, 165, + 68, 85, 78, 51, 32, 71, 85, 78, 85, 142, 255, 28, 65, 222, 164, 1, 66, + 247, 67, 76, 4, 250, 222, 30, 65, 223, 56, 69, 6, 222, 213, 14, 82, 218, + 193, 16, 50, 3, 68, 21, 37, 7, 32, 84, 73, 77, 69, 83, 32, 18, 154, 1, + 85, 220, 8, 4, 80, 65, 80, 32, 146, 45, 73, 224, 233, 12, 10, 83, 72, 69, + 83, 72, 32, 80, 76, 85, 83, 254, 132, 5, 68, 170, 221, 12, 78, 163, 17, + 71, 4, 238, 211, 14, 82, 219, 193, 16, 68, 4, 190, 236, 23, 50, 207, 174, 3, 52, 5, 11, 32, 2, 145, 6, 4, 84, 73, 77, 69, 7, 49, 10, 32, 84, 73, - 77, 69, 83, 32, 75, 85, 82, 5, 225, 206, 11, 5, 32, 80, 76, 85, 83, 9, - 204, 206, 11, 2, 77, 77, 170, 162, 19, 83, 147, 1, 76, 93, 90, 50, 212, - 7, 3, 71, 65, 76, 142, 1, 77, 130, 62, 32, 150, 170, 30, 51, 2, 72, 3, + 77, 69, 83, 32, 75, 85, 82, 5, 221, 215, 11, 5, 32, 80, 76, 85, 83, 9, + 200, 215, 11, 2, 77, 77, 158, 187, 19, 83, 147, 1, 76, 93, 90, 50, 212, + 7, 3, 71, 65, 76, 142, 1, 77, 130, 62, 32, 134, 204, 30, 51, 2, 72, 3, 76, 69, 11, 32, 66, 88, 4, 67, 82, 79, 83, 0, 4, 79, 80, 80, 79, 44, 4, - 71, 85, 78, 85, 38, 83, 35, 84, 2, 209, 204, 11, 6, 83, 73, 78, 71, 32, - 76, 2, 193, 24, 5, 32, 84, 73, 77, 69, 6, 250, 68, 72, 227, 250, 22, 81, - 54, 44, 5, 73, 77, 69, 83, 32, 251, 201, 30, 69, 52, 188, 1, 4, 69, 83, + 71, 85, 78, 85, 38, 83, 35, 84, 2, 205, 213, 11, 6, 83, 73, 78, 71, 32, + 76, 2, 193, 24, 5, 32, 84, 73, 77, 69, 6, 250, 68, 72, 191, 142, 23, 81, + 54, 44, 5, 73, 77, 69, 83, 32, 235, 235, 30, 69, 52, 188, 1, 4, 69, 83, 72, 50, 94, 72, 42, 75, 68, 2, 76, 65, 34, 77, 60, 3, 80, 65, 80, 118, - 83, 90, 84, 250, 56, 71, 158, 251, 7, 78, 178, 212, 18, 68, 198, 215, 2, - 65, 138, 67, 66, 215, 53, 73, 7, 11, 32, 4, 26, 80, 147, 239, 25, 84, 2, - 17, 2, 76, 85, 2, 173, 227, 29, 3, 83, 32, 76, 4, 184, 66, 2, 73, 32, - 227, 160, 29, 65, 8, 32, 2, 65, 68, 135, 236, 30, 73, 6, 226, 19, 51, - 163, 216, 30, 50, 4, 174, 20, 32, 219, 181, 17, 71, 2, 11, 69, 2, 11, 32, - 2, 241, 175, 13, 4, 80, 76, 85, 83, 5, 11, 32, 2, 33, 6, 80, 76, 85, 83, - 32, 80, 2, 45, 9, 65, 80, 32, 80, 76, 85, 83, 32, 76, 2, 159, 244, 26, - 85, 6, 26, 73, 147, 197, 30, 72, 4, 194, 18, 32, 181, 171, 26, 7, 75, 50, + 83, 90, 84, 250, 56, 71, 250, 130, 8, 78, 242, 234, 18, 68, 254, 216, 2, + 65, 166, 69, 66, 215, 53, 73, 7, 11, 32, 4, 26, 80, 175, 136, 26, 84, 2, + 17, 2, 76, 85, 2, 129, 131, 30, 3, 83, 32, 76, 4, 184, 66, 2, 73, 32, + 183, 192, 29, 65, 8, 32, 2, 65, 68, 247, 141, 31, 73, 6, 226, 19, 51, + 147, 250, 30, 50, 4, 174, 20, 32, 131, 196, 17, 71, 2, 11, 69, 2, 11, 32, + 2, 249, 189, 13, 4, 80, 76, 85, 83, 5, 11, 32, 2, 33, 6, 80, 76, 85, 83, + 32, 80, 2, 45, 9, 65, 80, 32, 80, 76, 85, 83, 32, 76, 2, 187, 145, 27, + 85, 6, 26, 73, 131, 231, 30, 72, 4, 194, 18, 32, 201, 196, 26, 7, 75, 50, 32, 80, 76, 85, 83, 4, 162, 53, 85, 139, 24, 65, 9, 11, 32, 6, 22, 79, 207, 67, 83, 4, 56, 7, 80, 80, 79, 83, 73, 78, 71, 1, 3, 86, 69, 82, 2, - 21, 3, 32, 76, 85, 2, 231, 222, 29, 71, 7, 45, 9, 32, 79, 86, 69, 82, 32, + 21, 3, 32, 76, 85, 2, 187, 254, 29, 71, 7, 45, 9, 32, 79, 86, 69, 82, 32, 76, 85, 77, 5, 187, 59, 32, 70, 34, 65, 70, 69, 22, 73, 71, 85, 17, 170, - 45, 32, 188, 1, 2, 83, 72, 202, 184, 30, 50, 2, 72, 3, 82, 7, 207, 198, - 26, 83, 7, 164, 241, 26, 8, 32, 80, 76, 85, 83, 32, 90, 65, 179, 245, 3, - 78, 43, 104, 2, 83, 72, 186, 60, 71, 144, 133, 11, 5, 32, 79, 86, 69, 82, - 40, 2, 82, 71, 225, 197, 6, 2, 78, 83, 31, 22, 32, 183, 2, 51, 16, 136, + 45, 32, 188, 1, 2, 83, 72, 186, 218, 30, 50, 2, 72, 3, 82, 7, 251, 247, + 26, 83, 7, 192, 142, 27, 8, 32, 80, 76, 85, 83, 32, 90, 65, 135, 250, 3, + 78, 43, 104, 2, 83, 72, 186, 60, 71, 140, 142, 11, 5, 32, 79, 86, 69, 82, + 40, 2, 82, 71, 173, 203, 6, 2, 78, 83, 31, 22, 32, 183, 2, 51, 16, 136, 1, 9, 79, 86, 69, 82, 32, 77, 85, 83, 72, 124, 6, 84, 73, 77, 69, 83, 32, - 209, 216, 26, 10, 67, 82, 79, 83, 83, 73, 78, 71, 32, 77, 9, 37, 7, 32, - 84, 73, 77, 69, 83, 32, 6, 42, 65, 238, 173, 28, 75, 143, 179, 2, 71, 2, - 241, 188, 11, 5, 32, 80, 76, 85, 83, 6, 178, 234, 29, 75, 158, 118, 90, + 237, 245, 26, 10, 67, 82, 79, 83, 83, 73, 78, 71, 32, 77, 9, 37, 7, 32, + 84, 73, 77, 69, 83, 32, 6, 42, 65, 154, 204, 28, 75, 211, 182, 2, 71, 2, + 237, 197, 11, 5, 32, 80, 76, 85, 83, 6, 162, 140, 30, 75, 158, 118, 90, 187, 2, 65, 13, 11, 32, 10, 44, 6, 84, 73, 77, 69, 83, 32, 203, 57, 71, - 8, 38, 65, 162, 206, 30, 68, 163, 17, 90, 5, 205, 129, 13, 5, 32, 80, 76, + 8, 38, 65, 146, 240, 30, 68, 163, 17, 90, 5, 233, 143, 13, 5, 32, 80, 76, 85, 83, 158, 1, 42, 65, 134, 2, 69, 94, 73, 199, 7, 85, 23, 52, 2, 71, - 65, 166, 1, 77, 198, 223, 30, 50, 3, 52, 11, 26, 32, 207, 224, 30, 82, 6, + 65, 166, 1, 77, 182, 129, 31, 50, 3, 52, 11, 26, 32, 191, 130, 31, 82, 6, 100, 8, 79, 80, 80, 79, 83, 73, 78, 71, 146, 59, 73, 197, 14, 9, 84, 73, - 77, 69, 83, 32, 83, 72, 85, 2, 157, 157, 30, 3, 32, 78, 65, 7, 204, 21, - 2, 32, 78, 247, 201, 30, 50, 9, 11, 32, 6, 44, 6, 84, 73, 77, 69, 83, 32, - 179, 57, 83, 4, 190, 152, 30, 85, 163, 70, 65, 73, 90, 77, 78, 78, 168, - 182, 20, 6, 32, 84, 73, 77, 69, 83, 238, 189, 8, 83, 135, 233, 1, 50, 7, + 77, 69, 83, 32, 83, 72, 85, 2, 141, 191, 30, 3, 32, 78, 65, 7, 204, 21, + 2, 32, 78, 231, 235, 30, 50, 9, 11, 32, 6, 44, 6, 84, 73, 77, 69, 83, 32, + 179, 57, 83, 4, 174, 186, 30, 85, 163, 70, 65, 73, 90, 77, 78, 78, 212, + 198, 20, 6, 32, 84, 73, 77, 69, 83, 202, 204, 8, 83, 239, 235, 1, 50, 7, 45, 9, 32, 84, 73, 77, 69, 83, 32, 71, 65, 4, 158, 3, 82, 179, 58, 78, - 59, 36, 3, 68, 65, 50, 243, 220, 30, 57, 55, 37, 7, 32, 84, 73, 77, 69, + 59, 36, 3, 68, 65, 50, 227, 254, 30, 57, 55, 37, 7, 32, 84, 73, 77, 69, 83, 32, 52, 162, 1, 65, 34, 71, 50, 75, 16, 5, 76, 65, 75, 45, 48, 22, 77, 86, 78, 34, 80, 76, 3, 83, 72, 69, 94, 85, 240, 15, 3, 68, 73, 77, - 230, 190, 29, 66, 235, 117, 72, 6, 246, 2, 83, 175, 216, 30, 78, 8, 26, - 73, 183, 216, 29, 85, 5, 215, 217, 30, 83, 2, 211, 20, 69, 2, 243, 193, - 23, 53, 4, 26, 69, 247, 241, 28, 65, 2, 25, 4, 32, 80, 76, 85, 2, 177, - 41, 3, 83, 32, 71, 4, 250, 137, 30, 85, 227, 79, 69, 2, 33, 6, 65, 80, - 32, 80, 76, 85, 2, 11, 83, 2, 157, 200, 29, 2, 32, 80, 9, 37, 7, 32, 80, - 76, 85, 83, 32, 65, 6, 26, 83, 175, 142, 29, 32, 4, 11, 72, 5, 107, 32, - 11, 50, 32, 34, 50, 174, 169, 14, 82, 135, 173, 16, 83, 2, 173, 142, 14, - 3, 80, 76, 85, 2, 11, 32, 2, 21, 3, 80, 76, 85, 2, 11, 83, 2, 227, 238, - 28, 32, 57, 24, 2, 49, 49, 99, 78, 9, 11, 32, 6, 200, 25, 9, 79, 86, 69, - 82, 32, 78, 85, 49, 49, 150, 191, 25, 84, 207, 161, 3, 82, 47, 30, 32, + 186, 222, 29, 66, 135, 120, 72, 6, 246, 2, 83, 159, 250, 30, 78, 8, 26, + 73, 167, 250, 29, 85, 5, 199, 251, 30, 83, 2, 211, 20, 69, 2, 207, 213, + 23, 53, 4, 26, 69, 255, 144, 29, 65, 2, 25, 4, 32, 80, 76, 85, 2, 177, + 41, 3, 83, 32, 71, 4, 234, 171, 30, 85, 227, 79, 69, 2, 33, 6, 65, 80, + 32, 80, 76, 85, 2, 11, 83, 2, 241, 231, 29, 2, 32, 80, 9, 37, 7, 32, 80, + 76, 85, 83, 32, 65, 6, 26, 83, 131, 174, 29, 32, 4, 11, 72, 5, 107, 32, + 11, 50, 32, 34, 50, 218, 183, 14, 82, 203, 192, 16, 83, 2, 217, 156, 14, + 3, 80, 76, 85, 2, 11, 32, 2, 21, 3, 80, 76, 85, 2, 11, 83, 2, 235, 141, + 29, 32, 57, 24, 2, 49, 49, 99, 78, 9, 11, 32, 6, 200, 25, 9, 79, 86, 69, + 82, 32, 78, 85, 49, 49, 178, 216, 25, 84, 243, 167, 3, 82, 47, 30, 32, 169, 3, 2, 85, 90, 18, 144, 1, 12, 67, 82, 79, 83, 83, 73, 78, 71, 32, 78, 85, 78, 72, 12, 76, 65, 71, 65, 82, 32, 84, 73, 77, 69, 83, 32, 174, - 1, 79, 231, 212, 25, 84, 5, 209, 40, 14, 32, 76, 65, 71, 65, 82, 32, 79, - 86, 69, 82, 32, 76, 65, 10, 56, 3, 83, 65, 76, 158, 235, 28, 77, 14, 85, - 235, 70, 71, 5, 133, 202, 29, 23, 32, 79, 86, 69, 82, 32, 78, 85, 78, 32, - 76, 65, 71, 65, 82, 32, 84, 73, 77, 69, 83, 32, 83, 2, 201, 185, 17, 3, + 1, 79, 131, 238, 25, 84, 5, 209, 40, 14, 32, 76, 65, 71, 65, 82, 32, 79, + 86, 69, 82, 32, 76, 65, 10, 56, 3, 83, 65, 76, 166, 138, 29, 77, 14, 85, + 207, 71, 71, 5, 217, 233, 29, 23, 32, 79, 86, 69, 82, 32, 78, 85, 78, 32, + 76, 65, 71, 65, 82, 32, 84, 73, 77, 69, 83, 32, 83, 2, 241, 199, 17, 3, 86, 69, 82, 27, 11, 32, 24, 120, 10, 65, 66, 50, 32, 84, 73, 77, 69, 83, 32, 205, 37, 15, 75, 73, 83, 73, 77, 53, 32, 84, 73, 77, 69, 83, 32, 66, - 73, 20, 168, 1, 2, 75, 65, 202, 7, 73, 212, 39, 2, 65, 83, 130, 177, 2, - 68, 232, 206, 8, 3, 83, 73, 76, 214, 135, 12, 85, 210, 237, 5, 71, 138, - 149, 1, 78, 254, 2, 66, 163, 17, 76, 2, 251, 217, 26, 68, 46, 42, 65, 36, - 4, 69, 83, 72, 50, 23, 73, 9, 194, 207, 30, 68, 2, 78, 3, 80, 5, 191, - 187, 28, 32, 35, 22, 32, 151, 1, 82, 20, 80, 6, 84, 73, 77, 69, 83, 32, - 201, 131, 18, 8, 67, 82, 79, 83, 83, 73, 78, 71, 18, 214, 21, 85, 150, - 48, 65, 2, 73, 254, 199, 29, 66, 187, 64, 69, 12, 32, 2, 73, 71, 191, - 205, 30, 50, 11, 11, 32, 8, 96, 6, 84, 73, 77, 69, 83, 32, 197, 153, 26, - 12, 79, 80, 80, 79, 83, 73, 78, 71, 32, 80, 73, 82, 6, 138, 195, 29, 75, - 162, 67, 85, 235, 67, 90, 8, 234, 67, 65, 182, 136, 30, 73, 3, 85, 202, + 73, 20, 168, 1, 2, 75, 65, 202, 7, 73, 212, 39, 2, 65, 83, 190, 177, 2, + 68, 168, 215, 8, 3, 83, 73, 76, 182, 146, 12, 85, 210, 249, 5, 71, 158, + 151, 1, 78, 254, 2, 66, 163, 17, 76, 2, 151, 247, 26, 68, 46, 42, 65, 36, + 4, 69, 83, 72, 50, 23, 73, 9, 178, 241, 30, 68, 2, 78, 3, 80, 5, 211, + 217, 28, 32, 35, 22, 32, 151, 1, 82, 20, 80, 6, 84, 73, 77, 69, 83, 32, + 141, 146, 18, 8, 67, 82, 79, 83, 83, 73, 78, 71, 18, 214, 21, 85, 150, + 48, 65, 2, 73, 238, 233, 29, 66, 187, 64, 69, 12, 32, 2, 73, 71, 175, + 239, 30, 50, 11, 11, 32, 8, 96, 6, 84, 73, 77, 69, 83, 32, 217, 178, 26, + 12, 79, 80, 80, 79, 83, 73, 78, 71, 32, 80, 73, 82, 6, 222, 226, 29, 75, + 190, 69, 85, 235, 67, 90, 8, 234, 67, 65, 166, 170, 30, 73, 3, 85, 202, 1, 46, 65, 250, 5, 72, 150, 11, 73, 163, 1, 85, 63, 46, 71, 190, 4, 76, - 122, 78, 227, 197, 30, 82, 53, 11, 32, 50, 92, 4, 71, 85, 78, 85, 54, 78, + 122, 78, 211, 231, 30, 82, 53, 11, 32, 50, 92, 4, 71, 85, 78, 85, 54, 78, 32, 6, 84, 73, 77, 69, 83, 32, 241, 21, 4, 79, 86, 69, 82, 5, 29, 5, 32, - 84, 73, 77, 69, 2, 159, 230, 17, 83, 2, 149, 164, 25, 3, 85, 84, 73, 42, + 84, 73, 77, 69, 2, 231, 244, 17, 83, 2, 185, 189, 25, 3, 85, 84, 73, 42, 150, 1, 73, 42, 75, 34, 83, 64, 2, 84, 65, 38, 85, 220, 62, 2, 68, 85, - 166, 223, 28, 76, 226, 40, 78, 210, 48, 69, 138, 60, 77, 162, 17, 72, - 187, 2, 65, 2, 11, 71, 2, 11, 73, 2, 191, 31, 32, 4, 182, 143, 30, 85, - 199, 53, 65, 6, 26, 72, 167, 190, 29, 65, 4, 162, 192, 13, 69, 151, 193, - 16, 73, 4, 226, 172, 23, 75, 211, 154, 7, 66, 10, 254, 197, 30, 83, 146, + 130, 255, 28, 76, 246, 42, 78, 210, 48, 69, 138, 60, 77, 162, 17, 72, + 187, 2, 65, 2, 11, 71, 2, 11, 73, 2, 191, 31, 32, 4, 166, 177, 30, 85, + 199, 53, 65, 6, 26, 72, 251, 221, 29, 65, 4, 198, 206, 13, 69, 227, 212, + 16, 73, 4, 190, 192, 23, 75, 231, 168, 7, 66, 10, 238, 231, 30, 83, 146, 1, 50, 2, 66, 2, 77, 3, 82, 5, 33, 6, 32, 76, 65, 71, 65, 66, 2, 37, 7, - 32, 84, 73, 77, 69, 83, 32, 2, 11, 65, 2, 11, 83, 2, 199, 172, 23, 72, 2, - 135, 169, 11, 71, 106, 46, 65, 250, 1, 69, 242, 2, 73, 239, 3, 85, 29, - 50, 51, 182, 1, 54, 174, 166, 23, 66, 223, 3, 82, 19, 37, 7, 32, 84, 73, - 77, 69, 83, 32, 16, 90, 85, 146, 25, 83, 222, 201, 26, 71, 166, 232, 2, - 84, 170, 50, 66, 218, 47, 78, 215, 22, 65, 5, 11, 32, 2, 181, 131, 26, 4, - 80, 76, 85, 83, 5, 175, 45, 32, 27, 62, 32, 140, 2, 2, 83, 72, 150, 203, - 26, 71, 199, 245, 3, 78, 14, 84, 8, 79, 86, 69, 82, 32, 83, 72, 69, 88, - 5, 80, 76, 85, 83, 32, 207, 156, 30, 72, 7, 11, 32, 4, 190, 15, 71, 141, + 32, 84, 73, 77, 69, 83, 32, 2, 11, 65, 2, 11, 83, 2, 163, 192, 23, 72, 2, + 131, 178, 11, 71, 106, 46, 65, 250, 1, 69, 242, 2, 73, 239, 3, 85, 29, + 50, 51, 182, 1, 54, 138, 186, 23, 66, 223, 3, 82, 19, 37, 7, 32, 84, 73, + 77, 69, 83, 32, 16, 90, 85, 146, 25, 83, 250, 231, 26, 71, 250, 235, 2, + 84, 170, 50, 66, 218, 47, 78, 215, 22, 65, 5, 11, 32, 2, 201, 156, 26, 4, + 80, 76, 85, 83, 5, 175, 45, 32, 27, 62, 32, 140, 2, 2, 83, 72, 178, 232, + 26, 71, 155, 250, 3, 78, 14, 84, 8, 79, 86, 69, 82, 32, 83, 72, 69, 88, + 5, 80, 76, 85, 83, 32, 191, 190, 30, 72, 7, 11, 32, 4, 190, 15, 71, 141, 6, 12, 84, 65, 66, 32, 79, 86, 69, 82, 32, 84, 65, 66, 6, 48, 2, 72, 85, - 20, 2, 78, 65, 183, 159, 29, 83, 2, 211, 167, 23, 66, 2, 191, 167, 23, - 77, 7, 218, 133, 29, 76, 255, 186, 1, 50, 40, 62, 68, 74, 77, 218, 1, 82, - 206, 138, 26, 78, 211, 176, 4, 84, 7, 37, 7, 32, 84, 73, 77, 69, 83, 32, - 4, 242, 174, 30, 73, 219, 16, 65, 25, 37, 7, 32, 84, 73, 77, 69, 83, 32, - 22, 114, 66, 38, 73, 130, 19, 75, 134, 187, 2, 77, 178, 211, 2, 76, 130, - 251, 23, 71, 250, 23, 83, 238, 9, 68, 215, 127, 65, 4, 154, 206, 2, 85, - 195, 230, 26, 65, 4, 249, 20, 2, 71, 73, 7, 11, 32, 4, 60, 9, 79, 86, 69, - 82, 32, 83, 72, 73, 82, 151, 191, 25, 84, 2, 177, 196, 29, 11, 32, 66, + 20, 2, 78, 65, 163, 191, 29, 83, 2, 175, 187, 23, 66, 2, 155, 187, 23, + 77, 7, 182, 165, 29, 76, 147, 189, 1, 50, 40, 62, 68, 74, 77, 218, 1, 82, + 226, 163, 26, 78, 175, 185, 4, 84, 7, 37, 7, 32, 84, 73, 77, 69, 83, 32, + 4, 226, 208, 30, 73, 219, 16, 65, 25, 37, 7, 32, 84, 73, 77, 69, 83, 32, + 22, 114, 66, 38, 73, 130, 19, 75, 194, 187, 2, 77, 234, 217, 2, 76, 250, + 147, 24, 71, 226, 23, 83, 138, 12, 68, 215, 127, 65, 4, 214, 206, 2, 85, + 219, 133, 27, 65, 4, 249, 20, 2, 71, 73, 7, 11, 32, 4, 60, 9, 79, 86, 69, + 82, 32, 83, 72, 73, 82, 179, 216, 25, 84, 2, 161, 230, 29, 11, 32, 66, 85, 82, 32, 79, 86, 69, 82, 32, 66, 13, 88, 14, 32, 79, 86, 69, 82, 32, - 73, 78, 86, 69, 82, 84, 69, 68, 34, 50, 251, 194, 29, 66, 2, 11, 32, 2, - 235, 205, 25, 83, 7, 33, 6, 32, 80, 76, 85, 83, 32, 4, 88, 7, 69, 50, 32, - 84, 73, 77, 69, 177, 152, 11, 9, 68, 85, 71, 32, 84, 73, 77, 69, 83, 2, - 131, 132, 13, 83, 17, 50, 32, 30, 71, 234, 152, 11, 76, 215, 135, 12, 75, + 73, 78, 86, 69, 82, 84, 69, 68, 34, 50, 235, 228, 29, 66, 2, 11, 32, 2, + 135, 231, 25, 83, 7, 33, 6, 32, 80, 76, 85, 83, 32, 4, 88, 7, 69, 50, 32, + 84, 73, 77, 69, 173, 161, 11, 9, 68, 85, 71, 32, 84, 73, 77, 69, 83, 2, + 139, 146, 13, 83, 17, 50, 32, 30, 71, 230, 161, 11, 76, 183, 146, 12, 75, 4, 138, 8, 84, 163, 9, 71, 7, 11, 52, 5, 49, 10, 32, 79, 86, 69, 82, 32, - 83, 73, 71, 52, 2, 199, 14, 32, 19, 78, 68, 22, 77, 22, 82, 156, 217, 12, - 5, 32, 79, 86, 69, 82, 179, 230, 16, 72, 5, 199, 184, 30, 50, 5, 147, - 208, 28, 65, 5, 159, 184, 30, 57, 72, 46, 65, 150, 4, 73, 250, 1, 85, - 227, 8, 69, 37, 66, 32, 94, 66, 166, 1, 71, 148, 1, 2, 75, 52, 135, 180, - 30, 82, 8, 60, 6, 84, 73, 77, 69, 83, 32, 130, 14, 71, 135, 149, 28, 65, - 4, 254, 162, 30, 72, 3, 77, 7, 11, 32, 4, 180, 203, 17, 29, 79, 86, 69, + 83, 73, 71, 52, 2, 199, 14, 32, 19, 78, 68, 22, 77, 22, 82, 184, 231, 12, + 5, 32, 79, 86, 69, 82, 135, 250, 16, 72, 5, 183, 218, 30, 50, 5, 155, + 239, 28, 65, 5, 143, 218, 30, 57, 72, 46, 65, 150, 4, 73, 250, 1, 85, + 227, 8, 69, 37, 66, 32, 94, 66, 166, 1, 71, 148, 1, 2, 75, 52, 247, 213, + 30, 82, 8, 60, 6, 84, 73, 77, 69, 83, 32, 130, 14, 71, 155, 179, 28, 65, + 4, 238, 196, 30, 72, 3, 77, 7, 11, 32, 4, 252, 217, 17, 29, 79, 86, 69, 82, 32, 84, 65, 66, 32, 78, 73, 32, 79, 86, 69, 82, 32, 78, 73, 32, 68, - 73, 83, 72, 32, 79, 86, 69, 82, 143, 187, 5, 83, 15, 37, 7, 32, 84, 73, - 77, 69, 83, 32, 12, 74, 84, 252, 254, 7, 2, 83, 72, 206, 137, 21, 71, - 190, 101, 85, 203, 50, 66, 2, 11, 85, 2, 235, 154, 23, 71, 5, 29, 5, 32, - 80, 76, 85, 83, 2, 221, 202, 28, 2, 32, 83, 17, 46, 82, 150, 29, 32, 134, - 150, 30, 50, 3, 76, 9, 11, 32, 6, 48, 8, 79, 86, 69, 82, 32, 84, 73, 82, + 73, 83, 72, 32, 79, 86, 69, 82, 163, 192, 5, 83, 15, 37, 7, 32, 84, 73, + 77, 69, 83, 32, 12, 74, 84, 216, 134, 8, 2, 83, 72, 206, 161, 21, 71, + 210, 103, 85, 203, 50, 66, 2, 11, 85, 2, 199, 174, 23, 71, 5, 29, 5, 32, + 80, 76, 85, 83, 2, 229, 233, 28, 2, 32, 83, 17, 46, 82, 150, 29, 32, 246, + 183, 30, 50, 3, 76, 9, 11, 32, 6, 48, 8, 79, 86, 69, 82, 32, 84, 73, 82, 99, 84, 5, 11, 32, 2, 11, 71, 2, 21, 3, 65, 68, 32, 2, 241, 5, 8, 79, 86, 69, 82, 32, 71, 65, 68, 2, 217, 21, 6, 73, 77, 69, 83, 32, 84, 17, 50, - 77, 114, 82, 130, 151, 23, 71, 175, 153, 7, 75, 7, 37, 7, 32, 84, 73, 77, - 69, 83, 32, 4, 46, 71, 205, 197, 17, 5, 84, 72, 82, 69, 69, 2, 221, 16, - 2, 65, 78, 5, 141, 139, 11, 17, 32, 79, 86, 69, 82, 32, 84, 85, 82, 32, + 77, 114, 82, 222, 170, 23, 71, 195, 167, 7, 75, 7, 37, 7, 32, 84, 73, 77, + 69, 83, 32, 4, 46, 71, 149, 212, 17, 5, 84, 72, 82, 69, 69, 2, 221, 16, + 2, 65, 78, 5, 137, 148, 11, 17, 32, 79, 86, 69, 82, 32, 84, 85, 82, 32, 90, 65, 32, 79, 86, 69, 82, 179, 1, 138, 1, 32, 246, 2, 68, 226, 2, 78, - 46, 77, 158, 2, 82, 128, 9, 2, 83, 72, 174, 1, 90, 224, 185, 12, 2, 84, - 85, 158, 226, 17, 50, 3, 66, 12, 64, 7, 79, 86, 69, 82, 32, 85, 32, 158, - 2, 85, 139, 128, 29, 71, 6, 200, 1, 10, 80, 65, 32, 79, 86, 69, 82, 32, - 80, 65, 216, 159, 9, 19, 85, 32, 82, 69, 86, 69, 82, 83, 69, 68, 32, 79, - 86, 69, 82, 32, 85, 32, 82, 137, 148, 20, 10, 83, 85, 82, 32, 79, 86, 69, + 46, 77, 158, 2, 82, 128, 9, 2, 83, 72, 174, 1, 90, 252, 199, 12, 2, 84, + 85, 242, 245, 17, 50, 3, 66, 12, 64, 7, 79, 86, 69, 82, 32, 85, 32, 158, + 2, 85, 231, 159, 29, 71, 6, 200, 1, 10, 80, 65, 32, 79, 86, 69, 82, 32, + 80, 65, 220, 167, 9, 19, 85, 32, 82, 69, 86, 69, 82, 83, 69, 68, 32, 79, + 86, 69, 82, 32, 85, 32, 82, 245, 173, 20, 10, 83, 85, 82, 32, 79, 86, 69, 82, 32, 83, 2, 11, 32, 2, 45, 9, 71, 65, 82, 32, 79, 86, 69, 82, 32, 2, - 191, 138, 29, 71, 5, 251, 134, 30, 32, 21, 26, 32, 227, 170, 30, 85, 16, + 171, 170, 29, 71, 5, 235, 168, 30, 32, 21, 26, 32, 211, 204, 30, 85, 16, 70, 75, 44, 2, 83, 72, 100, 6, 84, 73, 77, 69, 83, 32, 135, 1, 71, 2, 11, - 85, 2, 11, 83, 2, 155, 135, 11, 72, 4, 29, 5, 69, 83, 72, 73, 71, 5, 11, - 32, 2, 11, 84, 2, 217, 227, 29, 6, 73, 77, 69, 83, 32, 66, 8, 92, 14, 85, - 32, 80, 76, 85, 83, 32, 85, 32, 80, 76, 85, 83, 32, 210, 226, 29, 66, - 215, 50, 77, 4, 11, 85, 5, 11, 32, 2, 11, 71, 2, 227, 131, 30, 85, 21, - 72, 7, 32, 84, 73, 77, 69, 83, 32, 136, 1, 2, 85, 77, 159, 167, 29, 66, - 10, 50, 76, 16, 2, 77, 69, 50, 83, 135, 167, 30, 85, 2, 231, 6, 65, 5, - 11, 32, 2, 201, 241, 25, 4, 80, 76, 85, 83, 2, 131, 134, 11, 72, 7, 37, - 7, 32, 84, 73, 77, 69, 83, 32, 4, 158, 11, 75, 243, 152, 30, 80, 93, 54, - 32, 102, 50, 194, 2, 73, 22, 85, 187, 162, 30, 52, 4, 62, 83, 221, 172, - 29, 9, 67, 82, 79, 83, 83, 73, 78, 71, 32, 2, 165, 242, 25, 4, 72, 69, - 83, 72, 23, 11, 32, 20, 42, 73, 37, 6, 84, 73, 77, 69, 83, 32, 2, 165, - 130, 24, 4, 78, 86, 69, 82, 18, 46, 65, 82, 85, 130, 163, 29, 78, 251, - 125, 72, 6, 48, 6, 32, 80, 76, 85, 83, 32, 207, 163, 30, 76, 4, 146, 161, - 30, 72, 3, 78, 8, 26, 50, 151, 163, 30, 68, 7, 33, 6, 32, 80, 76, 85, 83, - 32, 4, 206, 186, 28, 65, 203, 212, 1, 66, 5, 203, 162, 30, 51, 59, 56, 7, + 85, 2, 11, 83, 2, 151, 144, 11, 72, 4, 29, 5, 69, 83, 72, 73, 71, 5, 11, + 32, 2, 11, 84, 2, 201, 133, 30, 6, 73, 77, 69, 83, 32, 66, 8, 92, 14, 85, + 32, 80, 76, 85, 83, 32, 85, 32, 80, 76, 85, 83, 32, 194, 132, 30, 66, + 215, 50, 77, 4, 11, 85, 5, 11, 32, 2, 11, 71, 2, 211, 165, 30, 85, 21, + 72, 7, 32, 84, 73, 77, 69, 83, 32, 136, 1, 2, 85, 77, 143, 201, 29, 66, + 10, 50, 76, 16, 2, 77, 69, 50, 83, 247, 200, 30, 85, 2, 231, 6, 65, 5, + 11, 32, 2, 221, 138, 26, 4, 80, 76, 85, 83, 2, 255, 142, 11, 72, 7, 37, + 7, 32, 84, 73, 77, 69, 83, 32, 4, 158, 11, 75, 227, 186, 30, 80, 93, 54, + 32, 102, 50, 194, 2, 73, 22, 85, 171, 196, 30, 52, 4, 62, 83, 205, 206, + 29, 9, 67, 82, 79, 83, 83, 73, 78, 71, 32, 2, 185, 139, 26, 4, 72, 69, + 83, 72, 23, 11, 32, 20, 42, 73, 37, 6, 84, 73, 77, 69, 83, 32, 2, 181, + 149, 24, 4, 78, 86, 69, 82, 18, 46, 65, 82, 85, 242, 196, 29, 78, 251, + 125, 72, 6, 48, 6, 32, 80, 76, 85, 83, 32, 191, 197, 30, 76, 4, 130, 195, + 30, 72, 3, 78, 8, 26, 50, 135, 197, 30, 68, 7, 33, 6, 32, 80, 76, 85, 83, + 32, 4, 214, 217, 28, 65, 179, 215, 1, 66, 5, 187, 196, 30, 51, 59, 56, 7, 32, 84, 73, 77, 69, 83, 32, 165, 4, 2, 68, 65, 52, 134, 1, 65, 46, 68, - 38, 71, 82, 73, 46, 76, 78, 83, 46, 85, 250, 252, 28, 66, 230, 33, 77, + 38, 71, 82, 73, 46, 76, 78, 83, 46, 85, 230, 156, 29, 66, 234, 35, 77, 238, 90, 84, 146, 17, 75, 162, 17, 72, 3, 80, 5, 11, 83, 2, 11, 72, 2, - 255, 254, 16, 71, 4, 190, 254, 10, 65, 171, 210, 18, 85, 10, 26, 65, 139, - 160, 30, 85, 9, 34, 78, 230, 159, 30, 76, 3, 82, 2, 211, 9, 50, 6, 250, - 139, 30, 71, 202, 18, 83, 147, 1, 77, 6, 46, 85, 221, 129, 23, 5, 65, 75, - 45, 54, 54, 4, 246, 158, 30, 51, 3, 77, 4, 136, 132, 23, 2, 73, 71, 255, - 131, 7, 72, 6, 42, 32, 242, 239, 13, 82, 151, 174, 16, 68, 2, 165, 242, - 28, 6, 80, 76, 85, 83, 32, 71, 5, 11, 32, 2, 153, 212, 13, 4, 84, 73, 77, - 69, 17, 84, 7, 32, 84, 73, 77, 69, 83, 32, 172, 144, 29, 2, 85, 77, 166, - 140, 1, 50, 3, 88, 8, 50, 84, 212, 201, 26, 2, 75, 85, 203, 210, 3, 65, - 2, 11, 65, 2, 191, 129, 23, 75, 6, 26, 51, 227, 155, 30, 85, 5, 29, 5, - 32, 84, 73, 77, 69, 2, 21, 3, 83, 32, 75, 2, 11, 65, 2, 139, 173, 23, 83, - 42, 50, 65, 190, 1, 73, 146, 1, 85, 223, 254, 22, 69, 13, 50, 32, 254, - 141, 29, 77, 166, 140, 1, 55, 3, 71, 4, 56, 8, 83, 81, 85, 65, 82, 69, - 68, 32, 243, 155, 25, 84, 2, 11, 84, 2, 21, 3, 73, 77, 69, 2, 11, 83, 2, - 221, 160, 29, 2, 32, 75, 15, 86, 66, 220, 229, 22, 6, 32, 79, 86, 69, 82, - 32, 186, 25, 90, 174, 153, 7, 51, 3, 71, 5, 17, 2, 32, 75, 2, 17, 2, 65, + 167, 141, 17, 71, 4, 186, 135, 11, 65, 159, 235, 18, 85, 10, 26, 65, 251, + 193, 30, 85, 9, 34, 78, 214, 193, 30, 76, 3, 82, 2, 211, 9, 50, 6, 234, + 173, 30, 71, 202, 18, 83, 147, 1, 77, 6, 46, 85, 185, 149, 23, 5, 65, 75, + 45, 54, 54, 4, 230, 192, 30, 51, 3, 77, 4, 228, 151, 23, 2, 73, 71, 147, + 146, 7, 72, 6, 42, 32, 158, 254, 13, 82, 219, 193, 16, 68, 2, 129, 146, + 29, 6, 80, 76, 85, 83, 32, 71, 5, 11, 32, 2, 197, 226, 13, 4, 84, 73, 77, + 69, 17, 84, 7, 32, 84, 73, 77, 69, 83, 32, 128, 176, 29, 2, 85, 77, 194, + 142, 1, 50, 3, 88, 8, 50, 84, 240, 231, 26, 2, 75, 85, 159, 214, 3, 65, + 2, 11, 65, 2, 155, 149, 23, 75, 6, 26, 51, 211, 189, 30, 85, 5, 29, 5, + 32, 84, 73, 77, 69, 2, 21, 3, 83, 32, 75, 2, 11, 65, 2, 251, 192, 23, 83, + 42, 50, 65, 190, 1, 73, 146, 1, 85, 187, 146, 23, 69, 13, 50, 32, 210, + 173, 29, 77, 194, 142, 1, 55, 3, 71, 4, 56, 8, 83, 81, 85, 65, 82, 69, + 68, 32, 143, 181, 25, 84, 2, 11, 84, 2, 21, 3, 73, 77, 69, 2, 11, 83, 2, + 205, 194, 29, 2, 32, 75, 15, 86, 66, 184, 249, 22, 6, 32, 79, 86, 69, 82, + 32, 186, 25, 90, 194, 167, 7, 51, 3, 71, 5, 17, 2, 32, 75, 2, 17, 2, 65, 66, 2, 135, 2, 65, 15, 84, 10, 32, 79, 86, 69, 82, 32, 90, 85, 32, 80, - 42, 53, 182, 158, 29, 66, 215, 120, 77, 2, 245, 245, 28, 5, 76, 85, 83, + 42, 53, 166, 192, 29, 66, 215, 120, 77, 2, 225, 149, 29, 5, 76, 85, 83, 32, 83, 7, 37, 7, 32, 84, 73, 77, 69, 83, 32, 4, 44, 5, 84, 72, 82, 69, - 69, 179, 150, 30, 65, 2, 29, 5, 32, 68, 73, 83, 72, 2, 11, 32, 2, 143, - 152, 25, 84, 8, 42, 32, 154, 228, 22, 73, 255, 200, 3, 67, 4, 198, 159, - 22, 79, 209, 247, 6, 8, 87, 73, 84, 72, 32, 83, 84, 82, 18, 134, 1, 76, - 162, 1, 82, 249, 206, 29, 23, 86, 69, 68, 32, 83, 84, 69, 77, 32, 80, 65, - 82, 65, 71, 82, 65, 80, 72, 32, 83, 73, 71, 78, 10, 48, 2, 89, 32, 241, - 162, 3, 4, 73, 78, 71, 32, 8, 68, 2, 76, 79, 193, 243, 27, 9, 66, 82, 65, - 67, 75, 69, 84, 32, 69, 6, 214, 209, 26, 71, 155, 193, 3, 79, 6, 52, 5, - 69, 78, 67, 89, 32, 53, 4, 89, 32, 65, 78, 4, 212, 247, 24, 4, 69, 88, - 67, 72, 227, 147, 4, 83, 2, 217, 235, 19, 3, 68, 32, 82, 4, 218, 131, 3, - 79, 135, 247, 25, 65, 240, 8, 128, 1, 2, 80, 82, 140, 9, 7, 82, 73, 76, - 76, 73, 67, 32, 132, 223, 25, 7, 76, 73, 78, 68, 82, 73, 67, 205, 253, 2, + 69, 163, 184, 30, 65, 2, 29, 5, 32, 68, 73, 83, 72, 2, 11, 32, 2, 171, + 177, 25, 84, 8, 42, 32, 246, 247, 22, 73, 155, 211, 3, 67, 4, 174, 179, + 22, 79, 217, 133, 7, 8, 87, 73, 84, 72, 32, 83, 84, 82, 18, 134, 1, 76, + 162, 1, 82, 233, 240, 29, 23, 86, 69, 68, 32, 83, 84, 69, 77, 32, 80, 65, + 82, 65, 71, 82, 65, 80, 72, 32, 83, 73, 71, 78, 10, 48, 2, 89, 32, 185, + 164, 3, 4, 73, 78, 71, 32, 8, 68, 2, 76, 79, 221, 145, 28, 9, 66, 82, 65, + 67, 75, 69, 84, 32, 69, 6, 242, 239, 26, 71, 239, 196, 3, 79, 6, 52, 5, + 69, 78, 67, 89, 32, 53, 4, 89, 32, 65, 78, 4, 248, 144, 25, 4, 69, 88, + 67, 72, 175, 156, 4, 83, 2, 133, 252, 19, 3, 68, 32, 82, 4, 234, 132, 3, + 79, 227, 149, 26, 65, 240, 8, 128, 1, 2, 80, 82, 140, 9, 7, 82, 73, 76, + 76, 73, 67, 32, 152, 248, 25, 7, 76, 73, 78, 68, 82, 73, 67, 149, 132, 3, 2, 67, 76, 180, 2, 140, 1, 13, 73, 79, 84, 32, 83, 89, 76, 76, 65, 66, 76, 69, 32, 169, 1, 16, 79, 45, 77, 73, 78, 79, 65, 78, 32, 83, 73, 71, - 78, 32, 67, 77, 110, 238, 177, 7, 75, 2, 76, 2, 77, 2, 78, 2, 80, 2, 82, - 2, 83, 2, 84, 126, 87, 138, 42, 74, 2, 90, 130, 239, 6, 88, 154, 195, 15, - 65, 2, 69, 2, 73, 2, 79, 3, 85, 198, 1, 46, 48, 146, 5, 49, 153, 135, 26, + 78, 32, 67, 77, 110, 190, 185, 7, 75, 2, 76, 2, 77, 2, 78, 2, 80, 2, 82, + 2, 83, 2, 84, 126, 87, 150, 42, 74, 2, 90, 230, 245, 6, 88, 202, 214, 15, + 65, 2, 69, 2, 73, 2, 79, 3, 85, 198, 1, 46, 48, 146, 5, 49, 181, 164, 26, 2, 51, 48, 170, 1, 102, 48, 78, 49, 74, 50, 78, 51, 78, 52, 62, 53, 86, - 55, 190, 186, 10, 57, 190, 3, 54, 215, 149, 14, 56, 16, 194, 140, 30, 49, - 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 16, 194, 3, 50, 182, - 136, 30, 48, 2, 49, 2, 51, 2, 53, 2, 55, 3, 57, 16, 174, 139, 30, 49, 2, - 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 16, 226, 138, 30, 48, 2, - 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 12, 150, 138, 30, 48, 2, - 49, 2, 52, 2, 54, 2, 55, 3, 57, 18, 218, 137, 30, 48, 2, 49, 2, 50, 2, - 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 20, 82, 53, 182, 136, 30, 48, 2, - 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 56, 3, 57, 5, 179, 136, 30, 66, 24, - 18, 48, 87, 49, 18, 138, 136, 30, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, - 2, 55, 2, 56, 3, 57, 6, 182, 135, 30, 48, 2, 50, 3, 52, 184, 6, 140, 1, + 55, 198, 195, 10, 57, 190, 3, 54, 219, 165, 14, 56, 16, 178, 174, 30, 49, + 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 16, 194, 3, 50, 166, + 170, 30, 48, 2, 49, 2, 51, 2, 53, 2, 55, 3, 57, 16, 158, 173, 30, 49, 2, + 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 16, 210, 172, 30, 48, 2, + 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 12, 134, 172, 30, 48, 2, + 49, 2, 52, 2, 54, 2, 55, 3, 57, 18, 202, 171, 30, 48, 2, 49, 2, 50, 2, + 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 20, 82, 53, 166, 170, 30, 48, 2, + 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 56, 3, 57, 5, 163, 170, 30, 66, 24, + 18, 48, 87, 49, 18, 250, 169, 30, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, + 2, 55, 2, 56, 3, 57, 6, 166, 169, 30, 48, 2, 50, 3, 52, 184, 6, 140, 1, 9, 67, 65, 80, 73, 84, 65, 76, 32, 76, 202, 4, 75, 32, 7, 76, 69, 84, 84, 69, 82, 32, 132, 1, 3, 80, 65, 89, 30, 83, 211, 41, 84, 242, 2, 44, 6, 69, 84, 84, 69, 82, 32, 175, 43, 73, 236, 2, 150, 2, 76, 46, 78, 34, 80, 34, 82, 58, 84, 62, 85, 190, 5, 65, 214, 1, 66, 242, 1, 67, 150, 1, 68, 254, 1, 69, 206, 2, 71, 130, 1, 72, 134, 1, 73, 230, 3, 75, 226, 3, 77, - 218, 1, 79, 226, 2, 83, 218, 7, 89, 166, 1, 90, 162, 183, 29, 70, 134, - 14, 74, 2, 86, 2, 87, 159, 20, 81, 6, 222, 25, 73, 254, 210, 29, 74, 159, - 20, 72, 4, 134, 27, 69, 171, 209, 29, 74, 8, 134, 34, 69, 135, 205, 29, - 83, 12, 220, 9, 3, 79, 85, 78, 226, 18, 69, 207, 227, 29, 72, 20, 174, - 33, 69, 106, 83, 234, 178, 29, 67, 186, 22, 74, 3, 87, 13, 198, 34, 32, - 115, 75, 2, 205, 248, 29, 3, 65, 86, 89, 6, 248, 10, 5, 77, 85, 76, 84, - 73, 200, 129, 13, 2, 80, 65, 241, 231, 11, 14, 83, 77, 65, 76, 76, 32, - 67, 65, 80, 73, 84, 65, 76, 32, 2, 177, 214, 29, 2, 69, 82, 186, 3, 136, + 218, 1, 79, 226, 2, 83, 218, 7, 89, 166, 1, 90, 146, 217, 29, 70, 134, + 14, 74, 2, 86, 2, 87, 159, 20, 81, 6, 222, 25, 73, 238, 244, 29, 74, 159, + 20, 72, 4, 134, 27, 69, 155, 243, 29, 74, 8, 134, 34, 69, 247, 238, 29, + 83, 12, 220, 9, 3, 79, 85, 78, 226, 18, 69, 191, 133, 30, 72, 20, 174, + 33, 69, 106, 83, 218, 212, 29, 67, 186, 22, 74, 3, 87, 13, 198, 34, 32, + 115, 75, 2, 189, 154, 30, 3, 65, 86, 89, 6, 248, 10, 5, 77, 85, 76, 84, + 73, 244, 143, 13, 2, 80, 65, 233, 242, 11, 14, 83, 77, 65, 76, 76, 32, + 67, 65, 80, 73, 84, 65, 76, 32, 2, 161, 248, 29, 2, 69, 82, 186, 3, 136, 1, 6, 77, 65, 76, 76, 32, 76, 201, 37, 22, 85, 66, 83, 67, 82, 73, 80, 84, 32, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 134, 3, 44, 6, 69, 84, 84, 69, 82, 32, 151, 36, 73, 128, 3, 154, 2, 65, 214, 1, 66, 242, 1, 67, 150, 1, 68, 254, 1, 69, 206, 2, 71, 130, 1, 72, 134, 1, 73, 230, 3, 75, 222, 2, 76, 134, 1, 77, 114, 78, 106, 79, 110, 80, 50, 82, - 198, 1, 83, 218, 2, 84, 218, 2, 85, 246, 1, 87, 54, 89, 166, 1, 90, 162, - 183, 29, 70, 134, 14, 74, 2, 86, 159, 20, 81, 17, 108, 6, 32, 87, 73, 84, - 72, 32, 36, 9, 66, 75, 72, 65, 83, 73, 65, 78, 32, 249, 152, 12, 4, 76, - 69, 85, 84, 4, 186, 194, 9, 68, 147, 182, 3, 66, 8, 172, 133, 13, 3, 67, - 72, 69, 158, 213, 6, 68, 255, 157, 10, 72, 18, 110, 65, 78, 73, 32, 3, - 82, 79, 65, 232, 160, 3, 6, 76, 69, 78, 68, 69, 68, 246, 224, 9, 89, 139, - 247, 16, 69, 6, 200, 21, 6, 82, 82, 69, 68, 32, 79, 253, 129, 12, 5, 83, - 72, 75, 73, 82, 4, 230, 2, 78, 163, 158, 3, 71, 2, 171, 179, 10, 68, 14, - 76, 2, 72, 69, 246, 9, 76, 220, 146, 13, 4, 82, 79, 83, 83, 167, 174, 16, - 67, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 150, 29, 68, 255, 169, 29, 86, - 26, 96, 2, 74, 69, 20, 6, 79, 85, 66, 76, 69, 32, 66, 90, 250, 200, 29, - 67, 186, 22, 87, 215, 22, 69, 5, 219, 230, 22, 82, 4, 36, 3, 77, 79, 78, - 159, 246, 29, 79, 2, 153, 13, 2, 79, 67, 12, 46, 69, 182, 245, 28, 90, - 206, 105, 72, 3, 87, 5, 223, 214, 29, 76, 41, 86, 76, 98, 78, 110, 82, - 166, 15, 32, 170, 238, 12, 83, 178, 193, 14, 77, 163, 180, 2, 70, 11, 33, - 6, 32, 87, 73, 84, 72, 32, 8, 166, 20, 77, 130, 235, 12, 68, 190, 193, - 14, 84, 143, 96, 72, 13, 33, 6, 32, 87, 73, 84, 72, 32, 10, 198, 19, 77, - 130, 235, 12, 68, 202, 52, 76, 246, 140, 14, 84, 143, 96, 72, 5, 133, - 195, 28, 5, 32, 87, 73, 84, 72, 14, 32, 2, 72, 69, 255, 219, 29, 74, 13, - 33, 6, 32, 87, 73, 84, 72, 32, 10, 142, 18, 77, 146, 15, 85, 242, 219, - 12, 68, 155, 31, 83, 12, 26, 65, 135, 219, 29, 87, 11, 48, 6, 32, 87, 73, - 84, 72, 32, 207, 136, 28, 82, 6, 134, 252, 12, 68, 202, 161, 15, 72, 219, - 163, 1, 83, 35, 84, 6, 32, 87, 73, 84, 72, 32, 50, 69, 74, 79, 201, 1, 6, - 90, 72, 73, 84, 83, 65, 6, 174, 183, 9, 68, 214, 10, 71, 243, 196, 3, 77, - 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 174, 193, 9, 71, 191, 171, 3, 66, - 17, 11, 84, 14, 48, 6, 73, 70, 73, 69, 68, 32, 227, 238, 29, 65, 12, 80, - 2, 67, 76, 38, 76, 190, 149, 3, 66, 198, 196, 25, 89, 234, 147, 1, 65, 3, - 69, 2, 33, 6, 79, 83, 69, 68, 32, 76, 2, 151, 4, 73, 5, 197, 136, 13, 14, + 198, 1, 83, 218, 2, 84, 218, 2, 85, 246, 1, 87, 54, 89, 166, 1, 90, 146, + 217, 29, 70, 134, 14, 74, 2, 86, 159, 20, 81, 17, 108, 6, 32, 87, 73, 84, + 72, 32, 36, 9, 66, 75, 72, 65, 83, 73, 65, 78, 32, 149, 167, 12, 4, 76, + 69, 85, 84, 4, 178, 203, 9, 68, 191, 187, 3, 66, 8, 216, 147, 13, 3, 67, + 72, 69, 158, 215, 6, 68, 195, 175, 10, 72, 18, 110, 65, 78, 73, 32, 3, + 82, 79, 65, 200, 167, 3, 6, 76, 69, 78, 68, 69, 68, 194, 232, 9, 89, 207, + 138, 17, 69, 6, 200, 21, 6, 82, 82, 69, 68, 32, 79, 153, 144, 12, 5, 83, + 72, 75, 73, 82, 4, 230, 2, 78, 131, 165, 3, 71, 2, 163, 188, 10, 68, 14, + 76, 2, 72, 69, 246, 9, 76, 136, 161, 13, 4, 82, 79, 83, 83, 235, 193, 16, + 67, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 150, 29, 68, 239, 203, 29, 86, + 26, 96, 2, 74, 69, 20, 6, 79, 85, 66, 76, 69, 32, 66, 90, 234, 234, 29, + 67, 186, 22, 87, 215, 22, 69, 5, 183, 250, 22, 82, 4, 36, 3, 77, 79, 78, + 143, 152, 30, 79, 2, 153, 13, 2, 79, 67, 12, 46, 69, 166, 151, 29, 90, + 206, 105, 72, 3, 87, 5, 207, 248, 29, 76, 41, 86, 76, 98, 78, 110, 82, + 166, 15, 32, 214, 252, 12, 83, 178, 209, 14, 77, 231, 183, 2, 70, 11, 33, + 6, 32, 87, 73, 84, 72, 32, 8, 166, 20, 77, 174, 249, 12, 68, 190, 209, + 14, 84, 183, 97, 72, 13, 33, 6, 32, 87, 73, 84, 72, 32, 10, 198, 19, 77, + 174, 249, 12, 68, 202, 52, 76, 246, 156, 14, 84, 183, 97, 72, 5, 225, + 226, 28, 5, 32, 87, 73, 84, 72, 14, 32, 2, 72, 69, 239, 253, 29, 74, 13, + 33, 6, 32, 87, 73, 84, 72, 32, 10, 142, 18, 77, 146, 15, 85, 158, 234, + 12, 68, 155, 31, 83, 12, 26, 65, 247, 252, 29, 87, 11, 48, 6, 32, 87, 73, + 84, 72, 32, 215, 167, 28, 82, 6, 178, 138, 13, 68, 242, 178, 15, 72, 247, + 165, 1, 83, 35, 84, 6, 32, 87, 73, 84, 72, 32, 50, 69, 74, 79, 201, 1, 6, + 90, 72, 73, 84, 83, 65, 6, 166, 192, 9, 68, 214, 10, 71, 167, 202, 3, 77, + 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 166, 202, 9, 71, 235, 176, 3, 66, + 17, 11, 84, 14, 48, 6, 73, 70, 73, 69, 68, 32, 211, 144, 30, 65, 12, 80, + 2, 67, 76, 38, 76, 158, 156, 3, 66, 142, 234, 25, 89, 178, 137, 1, 65, 3, + 69, 2, 33, 6, 79, 83, 69, 68, 32, 76, 2, 151, 4, 73, 5, 241, 150, 13, 14, 32, 87, 73, 84, 72, 32, 68, 79, 85, 66, 76, 69, 32, 71, 34, 102, 65, 98, - 79, 184, 190, 29, 11, 72, 65, 75, 65, 83, 83, 73, 65, 78, 32, 67, 186, - 22, 74, 255, 2, 83, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 226, 246, 12, - 68, 202, 161, 15, 72, 142, 163, 1, 86, 79, 83, 18, 36, 3, 77, 73, 32, - 203, 177, 26, 80, 16, 58, 68, 246, 160, 12, 76, 2, 78, 2, 83, 2, 84, 3, - 90, 6, 242, 160, 12, 90, 154, 179, 17, 74, 215, 22, 69, 8, 94, 73, 228, - 200, 10, 10, 79, 78, 71, 45, 76, 69, 71, 71, 69, 68, 154, 138, 19, 74, - 159, 20, 72, 2, 209, 145, 3, 4, 84, 84, 76, 69, 4, 21, 3, 79, 78, 79, 4, - 18, 67, 39, 71, 2, 145, 132, 19, 4, 85, 76, 65, 82, 2, 245, 10, 4, 82, - 65, 80, 72, 6, 62, 69, 144, 131, 19, 5, 65, 82, 82, 79, 87, 155, 206, 10, - 74, 2, 165, 245, 12, 5, 85, 84, 82, 65, 76, 11, 52, 4, 77, 69, 71, 65, - 166, 3, 32, 251, 227, 29, 84, 5, 173, 190, 29, 8, 32, 87, 73, 84, 72, 32, - 84, 73, 10, 138, 6, 69, 138, 236, 12, 65, 255, 224, 16, 83, 14, 50, 69, - 100, 4, 79, 85, 78, 68, 235, 226, 29, 72, 8, 37, 7, 86, 69, 82, 83, 69, - 68, 32, 8, 166, 197, 19, 68, 170, 151, 9, 84, 166, 100, 89, 151, 14, 90, - 4, 242, 159, 10, 32, 137, 244, 1, 2, 69, 68, 34, 108, 4, 67, 72, 87, 65, - 34, 72, 132, 1, 4, 79, 70, 84, 32, 214, 238, 12, 84, 213, 1, 5, 69, 77, - 73, 83, 79, 5, 11, 32, 2, 187, 238, 5, 87, 16, 92, 4, 79, 82, 84, 32, - 180, 237, 12, 2, 72, 65, 146, 251, 14, 67, 238, 227, 1, 87, 215, 22, 65, - 6, 226, 174, 27, 73, 163, 180, 2, 85, 8, 38, 69, 210, 219, 28, 83, 151, - 112, 68, 4, 182, 226, 29, 76, 3, 77, 28, 140, 1, 4, 65, 76, 76, 32, 50, - 69, 106, 83, 224, 135, 12, 11, 72, 82, 69, 69, 45, 76, 69, 71, 71, 69, - 68, 138, 171, 17, 67, 186, 22, 74, 3, 87, 6, 214, 231, 12, 72, 206, 229, - 15, 89, 151, 125, 84, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 26, 77, 131, - 235, 12, 68, 2, 189, 244, 21, 5, 73, 68, 68, 76, 69, 8, 158, 201, 29, 72, + 79, 180, 219, 17, 10, 72, 65, 75, 65, 83, 83, 73, 65, 78, 32, 174, 155, + 12, 74, 255, 2, 83, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 142, 133, 13, + 68, 242, 178, 15, 72, 170, 165, 1, 86, 79, 83, 18, 36, 3, 77, 73, 32, + 231, 207, 26, 80, 16, 58, 68, 254, 174, 12, 76, 2, 78, 2, 83, 2, 84, 3, + 90, 6, 250, 174, 12, 90, 130, 199, 17, 74, 215, 22, 69, 8, 94, 73, 224, + 209, 10, 10, 79, 78, 71, 45, 76, 69, 71, 71, 69, 68, 142, 163, 19, 74, + 159, 20, 72, 2, 177, 152, 3, 4, 84, 84, 76, 69, 4, 21, 3, 79, 78, 79, 4, + 18, 67, 39, 71, 2, 165, 147, 19, 4, 85, 76, 65, 82, 2, 245, 10, 4, 82, + 65, 80, 72, 6, 62, 69, 164, 146, 19, 5, 65, 82, 82, 79, 87, 247, 224, 10, + 74, 2, 209, 131, 13, 5, 85, 84, 82, 65, 76, 11, 52, 4, 77, 69, 71, 65, + 166, 3, 32, 235, 133, 30, 84, 5, 157, 224, 29, 8, 32, 87, 73, 84, 72, 32, + 84, 73, 10, 138, 6, 69, 182, 250, 12, 65, 195, 244, 16, 83, 14, 50, 69, + 100, 4, 79, 85, 78, 68, 219, 132, 30, 72, 8, 37, 7, 86, 69, 82, 83, 69, + 68, 32, 8, 210, 213, 19, 68, 214, 166, 9, 84, 190, 102, 89, 151, 14, 90, + 4, 234, 168, 10, 32, 153, 249, 1, 2, 69, 68, 34, 108, 4, 67, 72, 87, 65, + 34, 72, 132, 1, 4, 79, 70, 84, 32, 130, 253, 12, 84, 213, 1, 5, 69, 77, + 73, 83, 79, 5, 11, 32, 2, 219, 245, 5, 87, 16, 92, 4, 79, 82, 84, 32, + 224, 251, 12, 2, 72, 65, 238, 139, 15, 67, 214, 230, 1, 87, 215, 22, 65, + 6, 142, 205, 27, 73, 231, 183, 2, 85, 8, 38, 69, 194, 253, 28, 83, 151, + 112, 68, 4, 166, 132, 30, 76, 3, 77, 28, 140, 1, 4, 65, 76, 76, 32, 50, + 69, 106, 83, 232, 149, 12, 11, 72, 82, 69, 69, 45, 76, 69, 71, 71, 69, + 68, 242, 190, 17, 67, 186, 22, 74, 3, 87, 6, 130, 246, 12, 72, 202, 131, + 16, 89, 223, 114, 84, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 26, 77, 175, + 249, 12, 68, 2, 165, 136, 22, 5, 73, 68, 68, 76, 69, 8, 142, 235, 29, 72, 2, 83, 2, 87, 215, 22, 69, 15, 58, 32, 114, 75, 53, 8, 78, 66, 76, 69, - 78, 68, 69, 68, 6, 29, 5, 87, 73, 84, 72, 32, 6, 26, 68, 171, 245, 12, - 77, 4, 212, 167, 9, 5, 79, 85, 66, 76, 69, 187, 8, 73, 5, 11, 82, 2, 213, - 4, 6, 65, 73, 78, 73, 65, 78, 2, 207, 232, 24, 32, 4, 212, 201, 28, 4, - 73, 68, 69, 32, 251, 147, 1, 69, 18, 62, 65, 28, 3, 69, 82, 85, 194, 220, - 29, 73, 2, 78, 3, 85, 7, 218, 220, 29, 69, 3, 84, 7, 33, 6, 32, 87, 73, - 84, 72, 32, 4, 178, 163, 9, 68, 255, 197, 3, 66, 18, 18, 69, 71, 72, 9, - 156, 1, 7, 32, 87, 73, 84, 72, 32, 68, 233, 215, 29, 2, 77, 76, 10, 26, - 69, 179, 196, 29, 87, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 26, 68, 239, - 215, 12, 66, 4, 134, 172, 9, 73, 175, 185, 3, 69, 6, 37, 7, 71, 65, 84, - 85, 82, 69, 32, 6, 66, 65, 188, 198, 15, 2, 84, 69, 237, 229, 13, 4, 69, - 78, 32, 71, 2, 131, 190, 29, 32, 52, 198, 1, 66, 38, 68, 38, 69, 36, 3, - 71, 72, 69, 38, 72, 130, 137, 22, 89, 138, 211, 5, 83, 182, 113, 84, 238, - 8, 90, 130, 64, 73, 150, 19, 67, 186, 22, 80, 2, 86, 158, 20, 75, 186, 2, - 65, 2, 79, 3, 85, 4, 206, 224, 12, 89, 139, 247, 16, 69, 6, 146, 215, 28, - 90, 163, 128, 1, 69, 6, 142, 215, 29, 70, 2, 76, 3, 83, 5, 201, 5, 5, 32, - 87, 73, 84, 72, 4, 11, 65, 5, 227, 237, 27, 82, 2, 153, 248, 15, 4, 72, - 79, 85, 83, 212, 15, 178, 1, 65, 138, 4, 67, 54, 69, 146, 35, 73, 138, - 23, 79, 154, 45, 82, 174, 3, 85, 144, 232, 12, 13, 78, 65, 32, 68, 79, - 85, 66, 76, 69, 32, 72, 69, 76, 134, 183, 15, 86, 207, 47, 76, 30, 116, - 4, 71, 71, 69, 82, 146, 1, 78, 32, 4, 82, 75, 32, 83, 36, 2, 83, 72, 184, - 253, 21, 2, 76, 69, 139, 145, 1, 84, 9, 11, 32, 6, 44, 5, 87, 73, 84, 72, - 32, 219, 210, 6, 75, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 237, - 187, 28, 4, 84, 32, 71, 85, 4, 214, 148, 29, 67, 251, 30, 71, 4, 230, - 200, 21, 85, 211, 146, 5, 72, 10, 30, 32, 105, 3, 69, 68, 32, 4, 60, 9, - 87, 73, 84, 72, 32, 76, 69, 70, 84, 147, 190, 28, 83, 2, 17, 2, 32, 85, - 2, 143, 141, 23, 80, 6, 238, 233, 4, 84, 142, 189, 12, 76, 155, 194, 10, - 79, 10, 194, 208, 29, 49, 2, 50, 2, 51, 2, 52, 3, 83, 180, 4, 226, 1, 67, - 248, 1, 5, 71, 82, 69, 69, 32, 98, 76, 82, 78, 228, 3, 8, 80, 65, 82, 84, - 77, 69, 78, 84, 34, 83, 174, 6, 86, 192, 140, 15, 11, 82, 69, 76, 73, 67, - 84, 32, 72, 79, 85, 83, 168, 180, 10, 2, 65, 70, 143, 199, 3, 69, 8, 50, - 73, 177, 250, 5, 6, 82, 69, 65, 83, 69, 32, 6, 56, 4, 77, 65, 76, 32, - 205, 168, 9, 4, 68, 85, 79, 85, 4, 88, 9, 83, 69, 80, 65, 82, 65, 84, 79, - 82, 149, 248, 21, 7, 69, 88, 80, 79, 78, 69, 78, 2, 21, 3, 32, 75, 69, 2, - 155, 185, 28, 89, 6, 140, 194, 22, 4, 67, 69, 76, 83, 186, 131, 6, 83, - 177, 106, 8, 70, 65, 72, 82, 69, 78, 72, 69, 9, 248, 250, 16, 5, 73, 86, - 69, 82, 89, 248, 252, 5, 2, 84, 65, 231, 140, 5, 69, 34, 104, 20, 84, 73, + 78, 68, 69, 68, 6, 29, 5, 87, 73, 84, 72, 32, 6, 26, 68, 215, 131, 13, + 77, 4, 204, 176, 9, 5, 79, 85, 66, 76, 69, 187, 8, 73, 5, 11, 82, 2, 213, + 4, 6, 65, 73, 78, 73, 65, 78, 2, 235, 129, 25, 32, 4, 184, 233, 28, 4, + 73, 68, 69, 32, 135, 150, 1, 69, 18, 62, 65, 28, 3, 69, 82, 85, 178, 254, + 29, 73, 2, 78, 3, 85, 7, 202, 254, 29, 69, 3, 84, 7, 33, 6, 32, 87, 73, + 84, 72, 32, 4, 170, 172, 9, 68, 179, 203, 3, 66, 18, 18, 69, 71, 72, 9, + 156, 1, 7, 32, 87, 73, 84, 72, 32, 68, 217, 249, 29, 2, 77, 76, 10, 26, + 69, 163, 230, 29, 87, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 26, 68, 147, + 230, 12, 66, 4, 254, 180, 9, 73, 227, 190, 3, 69, 6, 37, 7, 71, 65, 84, + 85, 82, 69, 32, 6, 66, 65, 128, 213, 15, 2, 84, 69, 153, 249, 13, 4, 69, + 78, 32, 71, 2, 243, 223, 29, 32, 52, 198, 1, 66, 38, 68, 38, 69, 36, 3, + 71, 72, 69, 38, 72, 234, 156, 22, 89, 170, 222, 5, 83, 134, 114, 84, 134, + 11, 90, 130, 64, 73, 150, 19, 67, 186, 22, 80, 2, 86, 158, 20, 75, 186, + 2, 65, 2, 79, 3, 85, 4, 250, 238, 12, 89, 207, 138, 17, 69, 6, 130, 249, + 28, 90, 163, 128, 1, 69, 6, 254, 248, 29, 70, 2, 76, 3, 83, 5, 201, 5, 5, + 32, 87, 73, 84, 72, 4, 11, 65, 5, 235, 140, 28, 82, 2, 221, 134, 16, 4, + 72, 79, 85, 83, 214, 15, 178, 1, 65, 138, 4, 67, 54, 69, 154, 35, 73, + 166, 23, 79, 154, 45, 82, 174, 3, 85, 172, 246, 12, 13, 78, 65, 32, 68, + 79, 85, 66, 76, 69, 32, 72, 69, 76, 182, 202, 15, 86, 207, 47, 76, 30, + 116, 4, 71, 71, 69, 82, 146, 1, 78, 32, 4, 82, 75, 32, 83, 36, 2, 83, 72, + 160, 145, 22, 2, 76, 69, 131, 145, 1, 84, 9, 11, 32, 6, 44, 5, 87, 73, + 84, 72, 32, 171, 218, 6, 75, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, + 2, 217, 219, 28, 4, 84, 32, 71, 85, 4, 198, 182, 29, 67, 251, 30, 71, 4, + 190, 220, 21, 85, 155, 157, 5, 72, 10, 30, 32, 105, 3, 69, 68, 32, 4, 60, + 9, 87, 73, 84, 72, 32, 76, 69, 70, 84, 231, 221, 28, 83, 2, 17, 2, 32, + 85, 2, 239, 160, 23, 80, 6, 206, 240, 4, 84, 130, 197, 12, 76, 207, 210, + 10, 79, 10, 178, 242, 29, 49, 2, 50, 2, 51, 2, 52, 3, 83, 180, 4, 222, 1, + 67, 248, 1, 5, 71, 82, 69, 69, 32, 98, 76, 82, 78, 228, 3, 8, 80, 65, 82, + 84, 77, 69, 78, 84, 32, 12, 82, 69, 76, 73, 67, 84, 32, 72, 79, 85, 83, + 69, 42, 83, 174, 6, 86, 224, 221, 25, 2, 65, 70, 227, 203, 3, 69, 8, 50, + 73, 225, 129, 6, 6, 82, 69, 65, 83, 69, 32, 6, 56, 4, 77, 65, 76, 32, + 237, 177, 9, 4, 68, 85, 79, 85, 4, 88, 9, 83, 69, 80, 65, 82, 65, 84, 79, + 82, 129, 140, 22, 7, 69, 88, 80, 79, 78, 69, 78, 2, 21, 3, 32, 75, 69, 2, + 243, 216, 28, 89, 6, 240, 213, 22, 4, 67, 69, 76, 83, 202, 145, 6, 83, + 177, 106, 8, 70, 65, 72, 82, 69, 78, 72, 69, 9, 196, 137, 17, 5, 73, 86, + 69, 82, 89, 160, 130, 6, 2, 84, 65, 203, 152, 5, 69, 34, 104, 20, 84, 73, 83, 84, 82, 89, 32, 83, 89, 77, 66, 79, 76, 32, 76, 73, 71, 72, 84, 32, - 135, 237, 21, 83, 30, 88, 4, 68, 79, 87, 78, 0, 2, 85, 80, 153, 1, 9, 86, + 243, 128, 22, 83, 30, 88, 4, 68, 79, 87, 78, 0, 2, 85, 80, 153, 1, 9, 86, 69, 82, 84, 73, 67, 65, 76, 32, 8, 69, 15, 32, 65, 78, 68, 32, 72, 79, - 82, 73, 90, 79, 78, 84, 65, 76, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 150, - 221, 27, 87, 186, 25, 67, 159, 45, 84, 14, 52, 4, 65, 78, 68, 32, 45, 5, - 87, 73, 84, 72, 32, 10, 142, 156, 22, 66, 42, 84, 255, 191, 5, 87, 4, - 190, 245, 27, 67, 159, 45, 84, 2, 193, 226, 24, 3, 32, 83, 84, 170, 1, - 64, 2, 67, 69, 48, 2, 69, 82, 129, 5, 5, 75, 84, 79, 80, 32, 2, 153, 182, - 27, 7, 78, 68, 73, 78, 71, 32, 78, 164, 1, 32, 3, 69, 84, 32, 183, 4, 84, - 160, 1, 56, 6, 67, 65, 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 80, 45, 9, - 76, 32, 76, 69, 84, 84, 69, 82, 32, 80, 218, 1, 69, 96, 4, 76, 79, 78, - 71, 0, 5, 83, 72, 79, 82, 84, 74, 79, 30, 84, 2, 90, 158, 231, 11, 67, - 250, 234, 15, 66, 2, 68, 2, 74, 2, 80, 2, 86, 2, 89, 182, 99, 71, 2, 75, - 158, 103, 87, 162, 19, 65, 203, 17, 72, 20, 242, 162, 25, 83, 134, 165, - 2, 78, 138, 250, 1, 84, 146, 1, 70, 2, 76, 2, 77, 2, 82, 3, 87, 12, 11, - 32, 12, 134, 162, 25, 65, 190, 218, 1, 79, 226, 197, 2, 69, 3, 73, 4, - 230, 193, 29, 73, 3, 87, 4, 146, 210, 27, 72, 231, 216, 1, 69, 5, 161, - 179, 28, 4, 32, 73, 83, 76, 4, 158, 198, 26, 67, 193, 224, 1, 4, 87, 73, - 78, 68, 202, 2, 100, 8, 65, 78, 65, 71, 65, 82, 73, 32, 161, 18, 12, 73, - 67, 69, 32, 67, 79, 78, 84, 82, 79, 76, 32, 192, 2, 222, 1, 65, 38, 67, - 22, 71, 36, 4, 72, 69, 65, 68, 96, 7, 76, 69, 84, 84, 69, 82, 32, 198, 5, - 83, 148, 7, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 154, 129, 19, - 68, 212, 129, 6, 4, 74, 65, 73, 78, 171, 156, 4, 79, 4, 210, 216, 12, 67, - 151, 206, 12, 66, 2, 159, 146, 6, 65, 4, 194, 216, 12, 82, 135, 238, 1, - 65, 6, 44, 5, 32, 77, 65, 82, 75, 251, 140, 29, 83, 5, 181, 143, 19, 7, - 32, 87, 73, 84, 72, 32, 72, 158, 1, 158, 2, 65, 54, 67, 62, 68, 50, 71, - 62, 72, 52, 2, 77, 65, 46, 83, 130, 10, 79, 246, 147, 7, 66, 206, 252, 4, - 75, 150, 202, 3, 82, 238, 232, 6, 89, 154, 119, 85, 174, 30, 78, 254, - 198, 1, 74, 150, 52, 76, 70, 84, 46, 86, 134, 207, 1, 73, 158, 194, 1, - 80, 2, 90, 138, 69, 70, 2, 81, 187, 2, 69, 13, 158, 186, 29, 65, 2, 73, - 2, 85, 2, 87, 3, 89, 10, 26, 65, 155, 183, 29, 72, 9, 185, 2, 4, 78, 68, - 82, 65, 12, 178, 223, 25, 68, 198, 215, 3, 72, 187, 2, 65, 10, 130, 238, - 12, 76, 190, 131, 16, 72, 138, 69, 71, 187, 2, 65, 4, 232, 210, 16, 4, - 69, 65, 86, 89, 219, 229, 12, 65, 5, 233, 154, 7, 6, 82, 87, 65, 82, 73, - 32, 12, 38, 72, 134, 181, 29, 83, 187, 2, 65, 8, 36, 3, 79, 82, 84, 151, - 183, 29, 65, 6, 199, 136, 12, 32, 68, 168, 1, 19, 69, 81, 85, 69, 78, 67, - 69, 32, 70, 79, 82, 32, 76, 69, 84, 84, 69, 82, 32, 104, 4, 73, 71, 78, - 32, 133, 254, 26, 10, 84, 82, 69, 83, 83, 32, 83, 73, 71, 78, 16, 174, - 217, 3, 71, 2, 75, 228, 225, 23, 3, 68, 68, 68, 2, 82, 230, 247, 1, 89, - 38, 70, 2, 81, 3, 90, 48, 178, 3, 66, 0, 10, 69, 88, 84, 69, 78, 68, 69, - 68, 32, 66, 36, 11, 67, 65, 78, 68, 82, 65, 66, 73, 78, 68, 85, 64, 8, - 87, 69, 83, 84, 69, 82, 78, 32, 32, 10, 82, 69, 86, 69, 82, 83, 69, 68, - 32, 78, 226, 200, 6, 83, 190, 190, 12, 73, 142, 149, 6, 77, 46, 78, 242, - 60, 65, 72, 18, 68, 79, 85, 66, 76, 69, 32, 67, 65, 78, 68, 82, 65, 66, - 73, 78, 68, 85, 62, 80, 216, 196, 2, 12, 72, 73, 71, 72, 32, 83, 80, 65, - 67, 73, 78, 71, 139, 78, 86, 4, 241, 222, 12, 4, 72, 65, 76, 69, 11, 11, - 32, 8, 134, 194, 22, 65, 238, 152, 3, 86, 183, 230, 1, 84, 4, 30, 78, 21, - 3, 70, 73, 86, 2, 17, 2, 73, 78, 2, 129, 221, 21, 8, 69, 45, 76, 73, 75, - 69, 32, 66, 50, 150, 1, 65, 52, 7, 67, 65, 78, 68, 82, 65, 32, 62, 79, - 186, 134, 19, 80, 162, 180, 4, 85, 158, 224, 1, 83, 222, 63, 86, 186, - 201, 1, 73, 223, 137, 2, 69, 10, 210, 174, 29, 65, 2, 73, 2, 85, 2, 87, - 3, 89, 6, 172, 135, 19, 4, 76, 79, 78, 71, 242, 166, 10, 69, 3, 79, 7, - 142, 151, 29, 79, 215, 22, 69, 10, 194, 154, 24, 70, 136, 6, 2, 83, 84, - 154, 157, 3, 84, 183, 86, 79, 230, 2, 182, 2, 65, 150, 2, 69, 74, 71, + 82, 73, 90, 79, 78, 84, 65, 76, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 162, + 252, 27, 87, 134, 26, 67, 167, 45, 84, 14, 52, 4, 65, 78, 68, 32, 45, 5, + 87, 73, 84, 72, 32, 10, 238, 175, 22, 66, 42, 84, 171, 203, 5, 87, 4, + 150, 149, 28, 67, 167, 45, 84, 2, 253, 251, 24, 3, 32, 83, 84, 2, 185, + 162, 23, 5, 32, 66, 85, 73, 76, 170, 1, 64, 2, 67, 69, 48, 2, 69, 82, + 129, 5, 5, 75, 84, 79, 80, 32, 2, 253, 212, 27, 7, 78, 68, 73, 78, 71, + 32, 78, 164, 1, 32, 3, 69, 84, 32, 183, 4, 84, 160, 1, 56, 6, 67, 65, 80, + 73, 84, 65, 1, 4, 83, 77, 65, 76, 80, 45, 9, 76, 32, 76, 69, 84, 84, 69, + 82, 32, 80, 218, 1, 69, 96, 4, 76, 79, 78, 71, 0, 5, 83, 72, 79, 82, 84, + 74, 79, 30, 84, 2, 90, 158, 245, 11, 67, 222, 251, 15, 66, 2, 68, 2, 74, + 2, 80, 2, 86, 2, 89, 130, 100, 71, 2, 75, 186, 105, 87, 162, 19, 65, 203, + 17, 72, 20, 250, 211, 25, 83, 226, 146, 2, 78, 242, 252, 1, 84, 146, 1, + 70, 2, 76, 2, 77, 2, 82, 3, 87, 12, 11, 32, 12, 142, 211, 25, 65, 178, + 199, 1, 79, 178, 201, 2, 69, 3, 73, 4, 178, 227, 29, 73, 3, 87, 4, 246, + 240, 27, 72, 207, 219, 1, 69, 5, 209, 210, 28, 4, 32, 73, 83, 76, 4, 154, + 228, 26, 67, 141, 226, 1, 4, 87, 73, 78, 68, 202, 2, 100, 8, 65, 78, 65, + 71, 65, 82, 73, 32, 133, 18, 12, 73, 67, 69, 32, 67, 79, 78, 84, 82, 79, + 76, 32, 192, 2, 222, 1, 65, 38, 67, 22, 71, 36, 4, 72, 69, 65, 68, 96, 7, + 76, 69, 84, 84, 69, 82, 32, 202, 5, 83, 148, 7, 11, 86, 79, 87, 69, 76, + 32, 83, 73, 71, 78, 32, 186, 144, 19, 68, 160, 139, 6, 4, 74, 65, 73, 78, + 135, 165, 4, 79, 4, 218, 230, 12, 67, 187, 216, 12, 66, 2, 199, 153, 6, + 65, 4, 202, 230, 12, 82, 151, 238, 1, 65, 6, 44, 5, 32, 77, 65, 82, 75, + 199, 174, 29, 83, 5, 217, 158, 19, 7, 32, 87, 73, 84, 72, 32, 72, 158, 1, + 162, 2, 65, 54, 67, 62, 68, 50, 71, 62, 72, 52, 2, 77, 65, 46, 83, 170, + 165, 7, 66, 150, 131, 5, 75, 206, 202, 3, 82, 150, 173, 3, 79, 238, 192, + 3, 89, 214, 118, 85, 250, 35, 78, 138, 199, 1, 74, 174, 57, 76, 70, 84, + 46, 86, 242, 207, 1, 73, 134, 197, 1, 80, 2, 90, 138, 69, 70, 2, 81, 187, + 2, 69, 13, 230, 219, 29, 65, 2, 73, 2, 85, 2, 87, 3, 89, 10, 26, 65, 227, + 216, 29, 72, 9, 185, 2, 4, 78, 68, 82, 65, 12, 166, 253, 25, 68, 154, + 219, 3, 72, 187, 2, 65, 10, 134, 252, 12, 76, 130, 151, 16, 72, 138, 69, + 71, 187, 2, 65, 4, 136, 225, 16, 4, 69, 65, 86, 89, 131, 249, 12, 65, 5, + 157, 162, 7, 6, 82, 87, 65, 82, 73, 32, 12, 38, 72, 206, 214, 29, 83, + 187, 2, 65, 8, 36, 3, 79, 82, 84, 223, 216, 29, 65, 6, 167, 150, 12, 32, + 68, 168, 1, 19, 69, 81, 85, 69, 78, 67, 69, 32, 70, 79, 82, 32, 76, 69, + 84, 84, 69, 82, 32, 104, 4, 73, 71, 78, 32, 137, 156, 27, 10, 84, 82, 69, + 83, 83, 32, 83, 73, 71, 78, 16, 210, 223, 3, 71, 2, 75, 160, 250, 23, 3, + 68, 68, 68, 2, 82, 206, 250, 1, 89, 38, 70, 2, 81, 3, 90, 48, 178, 3, 66, + 0, 10, 69, 88, 84, 69, 78, 68, 69, 68, 32, 66, 36, 11, 67, 65, 78, 68, + 82, 65, 66, 73, 78, 68, 85, 64, 8, 87, 69, 83, 84, 69, 82, 78, 32, 32, + 10, 82, 69, 86, 69, 82, 83, 69, 68, 32, 78, 138, 208, 6, 83, 182, 198, + 12, 73, 150, 158, 6, 77, 46, 78, 190, 66, 65, 72, 18, 68, 79, 85, 66, 76, + 69, 32, 67, 65, 78, 68, 82, 65, 66, 73, 78, 68, 85, 62, 80, 144, 198, 2, + 12, 72, 73, 71, 72, 32, 83, 80, 65, 67, 73, 78, 71, 167, 80, 86, 4, 245, + 236, 12, 4, 72, 65, 76, 69, 11, 11, 32, 8, 206, 213, 22, 65, 154, 163, 3, + 86, 163, 231, 1, 84, 4, 30, 78, 21, 3, 70, 73, 86, 2, 17, 2, 73, 78, 2, + 193, 240, 21, 8, 69, 45, 76, 73, 75, 69, 32, 66, 50, 150, 1, 65, 52, 7, + 67, 65, 78, 68, 82, 65, 32, 218, 150, 19, 79, 34, 80, 162, 183, 4, 85, + 194, 229, 1, 83, 170, 69, 86, 166, 202, 1, 73, 199, 140, 2, 69, 10, 154, + 208, 29, 65, 2, 73, 2, 85, 2, 87, 3, 89, 6, 176, 151, 19, 4, 76, 79, 78, + 71, 182, 184, 10, 69, 3, 79, 10, 222, 179, 24, 70, 136, 6, 2, 83, 84, + 254, 162, 3, 84, 155, 87, 79, 232, 2, 182, 2, 65, 150, 2, 69, 74, 71, 224, 4, 6, 78, 71, 66, 65, 84, 32, 248, 1, 5, 82, 69, 67, 84, 32, 98, 83, - 178, 2, 86, 200, 7, 2, 89, 65, 32, 4, 90, 90, 89, 32, 224, 172, 5, 2, 84, - 84, 184, 156, 15, 10, 70, 70, 69, 82, 69, 78, 67, 69, 32, 66, 173, 205, - 7, 12, 77, 69, 78, 83, 73, 79, 78, 32, 79, 82, 73, 71, 20, 42, 77, 242, - 251, 8, 69, 183, 134, 13, 71, 16, 40, 4, 79, 78, 68, 32, 207, 152, 3, 69, - 14, 128, 1, 5, 87, 73, 84, 72, 32, 186, 164, 18, 84, 164, 224, 2, 12, 83, - 72, 65, 80, 69, 32, 87, 73, 84, 72, 32, 65, 183, 228, 4, 79, 8, 190, 128, - 22, 66, 182, 2, 84, 238, 137, 4, 76, 27, 82, 14, 176, 131, 5, 5, 32, 70, - 65, 67, 69, 133, 161, 17, 4, 83, 69, 76, 32, 78, 64, 3, 73, 84, 32, 149, + 206, 2, 86, 200, 7, 2, 89, 65, 32, 4, 90, 90, 89, 32, 232, 179, 5, 2, 84, + 84, 228, 168, 15, 10, 70, 70, 69, 82, 69, 78, 67, 69, 32, 66, 197, 219, + 7, 12, 77, 69, 78, 83, 73, 79, 78, 32, 79, 82, 73, 71, 20, 42, 77, 226, + 132, 9, 69, 155, 145, 13, 71, 16, 40, 4, 79, 78, 68, 32, 171, 159, 3, 69, + 14, 128, 1, 5, 87, 73, 84, 72, 32, 198, 179, 18, 84, 232, 228, 2, 12, 83, + 72, 65, 80, 69, 32, 87, 73, 84, 72, 32, 65, 251, 238, 4, 79, 8, 146, 148, + 22, 66, 182, 2, 84, 174, 148, 4, 76, 27, 82, 14, 184, 138, 5, 5, 32, 70, + 65, 67, 69, 213, 173, 17, 4, 83, 69, 76, 32, 78, 64, 3, 73, 84, 32, 149, 2, 8, 82, 65, 77, 32, 70, 79, 82, 32, 60, 98, 70, 44, 2, 78, 73, 2, 79, 14, 83, 46, 84, 44, 3, 90, 69, 82, 13, 5, 69, 73, 71, 72, 84, 12, 128, 1, 2, 73, 86, 25, 3, 79, 85, 82, 6, 87, 78, 12, 96, 4, 69, 86, 69, 78, 1, 2, - 73, 88, 12, 28, 3, 72, 82, 69, 15, 87, 6, 23, 69, 6, 11, 79, 7, 143, 247, - 16, 32, 18, 88, 5, 69, 65, 82, 84, 72, 64, 5, 71, 82, 69, 65, 84, 0, 4, - 76, 69, 83, 83, 39, 72, 7, 25, 4, 76, 89, 32, 72, 4, 194, 174, 24, 85, - 147, 141, 1, 69, 4, 169, 132, 13, 4, 69, 82, 32, 89, 4, 188, 148, 5, 7, + 73, 88, 12, 28, 3, 72, 82, 69, 15, 87, 6, 23, 69, 6, 11, 79, 7, 219, 133, + 17, 32, 18, 88, 5, 69, 65, 82, 84, 72, 64, 5, 71, 82, 69, 65, 84, 0, 4, + 76, 69, 83, 83, 39, 72, 7, 25, 4, 76, 89, 32, 72, 4, 214, 199, 24, 85, + 239, 145, 1, 69, 4, 193, 146, 13, 4, 69, 82, 32, 89, 4, 200, 155, 5, 7, 69, 65, 86, 69, 78, 76, 89, 1, 4, 85, 77, 65, 78, 64, 120, 17, 78, 69, 71, 65, 84, 73, 86, 69, 32, 67, 73, 82, 67, 76, 69, 68, 32, 41, 9, 67, - 73, 82, 67, 76, 69, 68, 32, 83, 42, 38, 83, 154, 32, 78, 151, 196, 20, - 68, 22, 49, 10, 65, 78, 83, 45, 83, 69, 82, 73, 70, 32, 22, 226, 31, 78, - 175, 144, 27, 68, 4, 148, 233, 22, 15, 67, 85, 82, 82, 69, 78, 84, 32, - 83, 89, 77, 66, 79, 76, 32, 195, 155, 6, 72, 10, 70, 65, 144, 1, 5, 67, - 79, 78, 84, 73, 197, 235, 25, 3, 71, 85, 73, 6, 76, 9, 80, 80, 79, 73, - 78, 84, 69, 68, 32, 133, 132, 27, 4, 66, 76, 69, 68, 4, 252, 159, 17, 7, - 66, 85, 84, 32, 82, 69, 76, 147, 194, 11, 70, 2, 53, 11, 78, 85, 79, 85, - 83, 32, 85, 78, 68, 69, 82, 2, 137, 130, 17, 3, 76, 73, 78, 156, 1, 80, - 9, 69, 83, 32, 65, 75, 85, 82, 85, 32, 238, 5, 73, 157, 251, 16, 2, 79, - 82, 144, 1, 142, 2, 68, 36, 7, 76, 69, 84, 84, 69, 82, 32, 236, 1, 5, 83, - 73, 71, 78, 32, 58, 86, 140, 162, 9, 6, 77, 69, 68, 73, 65, 76, 182, 255, - 4, 71, 222, 232, 4, 69, 128, 203, 4, 12, 80, 82, 69, 70, 73, 88, 69, 68, - 32, 78, 65, 83, 217, 248, 4, 7, 73, 78, 73, 84, 73, 65, 76, 22, 174, 190, - 25, 79, 211, 235, 1, 73, 84, 142, 195, 10, 84, 190, 237, 11, 89, 162, - 126, 65, 138, 146, 2, 68, 214, 6, 85, 206, 201, 1, 73, 42, 76, 250, 192, - 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 75, 2, 80, 138, 69, 72, 2, 74, 2, - 77, 2, 82, 2, 86, 2, 90, 186, 2, 69, 3, 79, 8, 174, 217, 24, 72, 150, 43, - 67, 98, 78, 235, 206, 3, 65, 18, 64, 10, 79, 87, 69, 76, 32, 83, 73, 71, - 78, 32, 179, 223, 26, 73, 16, 134, 150, 15, 65, 218, 174, 10, 85, 206, - 201, 1, 73, 222, 137, 2, 69, 3, 79, 10, 68, 5, 83, 73, 79, 78, 32, 212, - 241, 1, 2, 78, 71, 171, 145, 26, 68, 6, 26, 83, 227, 227, 5, 84, 4, 170, - 174, 27, 76, 211, 97, 73, 2, 165, 132, 19, 3, 32, 76, 65, 4, 134, 131, - 28, 83, 139, 86, 70, 212, 5, 188, 2, 6, 67, 85, 77, 69, 78, 84, 124, 7, - 69, 83, 32, 78, 79, 84, 32, 194, 3, 71, 202, 3, 76, 36, 10, 77, 73, 78, - 79, 32, 84, 73, 76, 69, 32, 226, 1, 78, 38, 84, 246, 2, 85, 204, 17, 2, - 87, 78, 164, 189, 16, 8, 32, 78, 79, 84, 32, 76, 73, 84, 156, 250, 11, 8, - 86, 69, 32, 79, 70, 32, 80, 69, 174, 4, 79, 235, 25, 68, 9, 33, 6, 32, - 87, 73, 84, 72, 32, 6, 40, 4, 84, 69, 88, 84, 139, 142, 2, 80, 5, 133, - 142, 2, 6, 32, 65, 78, 68, 32, 80, 22, 164, 1, 11, 67, 79, 78, 84, 65, - 73, 78, 32, 65, 83, 32, 92, 6, 68, 73, 86, 73, 68, 69, 112, 2, 80, 82, - 48, 7, 83, 85, 67, 67, 69, 69, 68, 253, 213, 22, 2, 70, 79, 6, 248, 1, - 15, 78, 79, 82, 77, 65, 76, 32, 83, 85, 66, 71, 82, 79, 85, 80, 231, 245, - 20, 77, 5, 217, 249, 21, 23, 32, 87, 73, 84, 72, 32, 82, 69, 86, 69, 82, - 83, 69, 68, 32, 78, 69, 71, 65, 84, 73, 79, 78, 6, 44, 5, 69, 67, 69, 68, - 69, 195, 146, 28, 79, 5, 233, 158, 9, 2, 32, 79, 125, 36, 3, 82, 65, 32, - 191, 209, 28, 32, 120, 120, 7, 76, 69, 84, 84, 69, 82, 32, 208, 1, 11, - 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 170, 161, 23, 65, 187, 2, 83, - 88, 178, 179, 25, 65, 38, 68, 82, 82, 34, 84, 230, 5, 85, 206, 201, 1, - 73, 162, 193, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, - 138, 69, 72, 2, 76, 2, 77, 2, 86, 2, 89, 186, 2, 69, 3, 79, 22, 194, 140, - 19, 86, 246, 171, 6, 65, 38, 85, 206, 201, 1, 73, 222, 137, 2, 69, 3, 79, - 4, 202, 141, 21, 80, 183, 188, 2, 76, 200, 1, 72, 8, 72, 79, 82, 73, 90, - 79, 78, 84, 1, 6, 86, 69, 82, 84, 73, 67, 100, 17, 2, 65, 76, 100, 32, 2, - 45, 48, 155, 251, 23, 32, 98, 58, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, - 3, 54, 14, 205, 166, 20, 2, 45, 48, 4, 174, 239, 26, 75, 255, 146, 1, 71, - 26, 34, 32, 57, 4, 84, 69, 68, 32, 8, 170, 130, 25, 80, 34, 77, 194, 70, - 79, 239, 194, 2, 65, 18, 214, 1, 67, 34, 83, 220, 145, 16, 3, 76, 73, 78, - 148, 133, 1, 4, 79, 66, 69, 76, 244, 9, 9, 84, 82, 65, 78, 83, 80, 79, - 83, 73, 238, 220, 6, 70, 141, 41, 14, 82, 73, 71, 72, 84, 45, 80, 79, 73, - 78, 84, 73, 78, 71, 4, 226, 180, 27, 73, 231, 16, 82, 4, 134, 243, 26, - 79, 223, 114, 81, 162, 1, 40, 3, 66, 76, 69, 137, 17, 2, 71, 72, 160, 1, - 42, 32, 190, 10, 45, 241, 5, 2, 68, 32, 106, 226, 2, 67, 174, 1, 68, 38, - 72, 32, 4, 73, 78, 84, 69, 38, 76, 144, 1, 7, 78, 69, 83, 84, 69, 68, 32, - 74, 80, 66, 83, 130, 2, 85, 36, 9, 86, 69, 82, 84, 73, 67, 65, 76, 32, - 144, 161, 6, 6, 79, 66, 76, 73, 81, 85, 196, 189, 2, 9, 82, 73, 71, 72, - 84, 32, 65, 82, 67, 246, 183, 3, 65, 242, 215, 9, 69, 182, 188, 4, 81, - 177, 105, 6, 87, 65, 86, 89, 32, 79, 24, 100, 7, 73, 82, 67, 76, 69, 68, - 32, 180, 207, 7, 4, 85, 82, 76, 89, 241, 196, 1, 4, 79, 76, 79, 78, 20, - 26, 78, 151, 196, 20, 68, 2, 157, 213, 2, 5, 85, 77, 66, 69, 82, 4, 190, - 236, 18, 79, 135, 199, 6, 65, 4, 198, 190, 20, 73, 223, 63, 89, 4, 154, - 130, 26, 82, 251, 244, 1, 71, 12, 54, 79, 129, 156, 17, 7, 69, 70, 84, - 32, 65, 82, 67, 10, 26, 87, 199, 190, 25, 71, 6, 26, 45, 139, 230, 27, - 32, 4, 174, 189, 20, 82, 211, 1, 57, 6, 224, 137, 17, 9, 76, 69, 83, 83, - 45, 84, 72, 65, 78, 179, 227, 9, 71, 8, 26, 82, 207, 248, 26, 76, 6, 242, - 157, 1, 69, 207, 235, 15, 73, 18, 80, 6, 81, 85, 65, 82, 69, 32, 30, 84, - 50, 85, 149, 215, 13, 4, 79, 76, 73, 68, 4, 230, 205, 25, 73, 55, 85, 4, - 204, 191, 12, 3, 65, 67, 75, 135, 201, 4, 82, 8, 58, 83, 146, 156, 1, 67, - 222, 136, 21, 80, 151, 236, 4, 66, 2, 169, 147, 28, 4, 80, 69, 78, 83, 4, - 214, 231, 18, 80, 139, 196, 9, 78, 10, 36, 3, 66, 65, 82, 163, 226, 27, - 76, 9, 11, 32, 6, 52, 7, 68, 79, 85, 66, 76, 69, 32, 151, 213, 26, 76, 4, - 146, 213, 26, 76, 51, 82, 48, 112, 5, 76, 73, 78, 69, 32, 220, 1, 7, 83, - 84, 82, 85, 67, 75, 32, 141, 226, 8, 7, 69, 78, 68, 69, 68, 32, 77, 12, - 48, 8, 83, 76, 65, 78, 84, 69, 68, 32, 75, 69, 8, 70, 69, 56, 7, 71, 82, - 69, 65, 84, 69, 82, 1, 4, 76, 69, 83, 83, 4, 185, 179, 20, 9, 81, 85, 65, - 76, 32, 84, 79, 32, 79, 2, 221, 165, 14, 5, 45, 84, 72, 65, 78, 34, 160, - 1, 8, 67, 65, 80, 73, 84, 65, 76, 32, 92, 7, 73, 84, 65, 76, 73, 67, 32, - 124, 6, 83, 77, 65, 76, 76, 32, 245, 208, 13, 8, 78, 45, 65, 82, 89, 32, - 83, 85, 18, 198, 163, 12, 71, 226, 201, 14, 80, 222, 137, 2, 67, 2, 72, - 2, 78, 2, 81, 2, 82, 3, 90, 10, 76, 6, 83, 77, 65, 76, 76, 32, 201, 230, - 21, 7, 67, 65, 80, 73, 84, 65, 76, 8, 214, 245, 28, 68, 2, 69, 2, 73, 3, - 74, 4, 238, 161, 12, 71, 231, 191, 16, 80, 6, 218, 161, 10, 70, 26, 77, - 135, 192, 17, 83, 2, 139, 251, 27, 78, 166, 1, 50, 32, 158, 1, 45, 189, - 1, 4, 87, 65, 82, 68, 10, 60, 4, 84, 65, 67, 75, 226, 206, 25, 70, 30, - 82, 191, 79, 65, 5, 29, 5, 32, 87, 73, 84, 72, 2, 11, 32, 2, 11, 67, 2, - 129, 245, 20, 4, 73, 82, 67, 76, 28, 60, 9, 80, 79, 73, 78, 84, 73, 78, - 71, 32, 211, 207, 25, 70, 24, 62, 83, 246, 209, 25, 65, 86, 69, 62, 70, - 46, 82, 207, 1, 84, 4, 142, 180, 17, 84, 205, 160, 8, 6, 77, 65, 76, 76, - 32, 82, 128, 1, 56, 8, 32, 70, 65, 67, 73, 78, 71, 32, 89, 2, 83, 32, 8, - 54, 72, 1, 9, 78, 79, 84, 67, 72, 69, 68, 32, 72, 4, 181, 204, 27, 3, 79, - 79, 75, 120, 178, 1, 65, 200, 2, 6, 66, 76, 65, 67, 75, 32, 38, 84, 172, - 237, 8, 2, 87, 72, 150, 154, 8, 90, 218, 250, 8, 68, 50, 70, 82, 72, 150, - 4, 67, 46, 81, 42, 82, 22, 83, 247, 7, 80, 34, 40, 4, 82, 82, 79, 87, - 179, 253, 25, 78, 33, 11, 32, 30, 144, 1, 5, 87, 73, 84, 72, 32, 160, - 228, 13, 14, 76, 69, 70, 84, 87, 65, 82, 68, 83, 32, 79, 70, 32, 85, 166, - 153, 12, 65, 178, 10, 70, 179, 5, 84, 22, 184, 183, 5, 6, 67, 79, 82, 78, - 69, 82, 182, 200, 20, 68, 58, 76, 42, 77, 38, 78, 58, 83, 66, 69, 250, - 12, 84, 139, 58, 72, 6, 178, 130, 21, 65, 175, 255, 4, 67, 36, 36, 2, 82, - 73, 161, 2, 2, 87, 79, 32, 44, 5, 65, 78, 71, 76, 69, 143, 144, 26, 80, - 30, 56, 8, 45, 72, 69, 65, 68, 69, 68, 32, 203, 149, 26, 32, 28, 68, 5, - 65, 82, 82, 79, 87, 230, 133, 17, 90, 166, 136, 9, 68, 39, 80, 23, 11, - 32, 20, 184, 137, 26, 15, 76, 69, 70, 84, 87, 65, 82, 68, 83, 32, 79, 70, - 32, 85, 80, 98, 84, 23, 87, 4, 134, 143, 26, 32, 105, 15, 45, 72, 69, 65, - 68, 69, 68, 32, 65, 82, 82, 79, 87, 32, 87, 22, 138, 1, 65, 106, 79, 152, - 1, 12, 85, 77, 32, 87, 73, 84, 72, 32, 68, 82, 85, 77, 160, 242, 16, 6, - 73, 86, 69, 32, 83, 76, 231, 220, 10, 69, 8, 238, 202, 2, 67, 200, 147, - 6, 10, 70, 84, 73, 78, 71, 32, 80, 79, 73, 78, 133, 235, 15, 3, 71, 79, - 78, 8, 56, 6, 77, 69, 68, 65, 82, 89, 34, 80, 159, 177, 27, 79, 2, 217, - 234, 20, 3, 32, 67, 65, 4, 204, 181, 18, 6, 32, 79, 70, 32, 66, 76, 171, - 251, 9, 76, 2, 189, 217, 12, 3, 83, 84, 73, 162, 2, 76, 7, 80, 76, 79, - 89, 65, 78, 32, 244, 132, 20, 2, 77, 80, 215, 220, 8, 67, 158, 2, 212, 2, - 6, 65, 70, 70, 73, 88, 32, 160, 7, 7, 76, 69, 84, 84, 69, 82, 32, 148, - 194, 1, 16, 84, 72, 73, 67, 75, 32, 76, 69, 84, 84, 69, 82, 32, 83, 69, - 76, 180, 174, 3, 4, 68, 79, 85, 66, 220, 230, 16, 19, 80, 85, 78, 67, 84, - 85, 65, 84, 73, 79, 78, 32, 67, 72, 73, 78, 79, 79, 75, 149, 194, 5, 11, - 83, 73, 71, 78, 32, 79, 32, 87, 73, 84, 72, 64, 140, 1, 9, 65, 84, 84, - 65, 67, 72, 69, 68, 32, 184, 1, 5, 72, 73, 71, 72, 32, 106, 76, 40, 4, - 82, 73, 71, 72, 173, 2, 4, 77, 73, 68, 32, 14, 112, 2, 84, 65, 232, 4, - 13, 76, 69, 70, 84, 45, 84, 79, 45, 82, 73, 71, 72, 84, 26, 83, 166, 239, - 20, 69, 3, 73, 6, 44, 5, 78, 71, 69, 78, 84, 159, 214, 27, 73, 5, 255, - 243, 20, 32, 20, 174, 2, 76, 50, 84, 38, 86, 166, 174, 8, 71, 186, 2, 65, - 170, 192, 18, 87, 186, 25, 67, 199, 129, 1, 68, 24, 36, 2, 69, 70, 29, 3, - 79, 87, 32, 2, 213, 2, 3, 84, 32, 72, 22, 94, 65, 38, 76, 50, 84, 38, 86, - 166, 174, 8, 71, 226, 194, 18, 87, 186, 25, 67, 199, 129, 1, 68, 4, 186, - 229, 21, 67, 199, 221, 5, 82, 4, 132, 128, 8, 3, 79, 78, 71, 219, 195, - 19, 73, 2, 229, 165, 8, 4, 73, 71, 72, 84, 4, 37, 7, 69, 82, 84, 73, 67, - 65, 76, 5, 131, 1, 32, 4, 42, 72, 41, 6, 86, 69, 82, 84, 73, 67, 2, 37, - 7, 79, 82, 73, 90, 79, 78, 84, 2, 17, 2, 65, 76, 2, 11, 32, 2, 11, 83, 2, - 161, 209, 27, 2, 69, 67, 214, 1, 222, 1, 65, 22, 68, 34, 69, 30, 70, 22, - 71, 22, 74, 162, 1, 75, 66, 76, 50, 77, 62, 78, 134, 1, 79, 50, 80, 86, - 82, 74, 83, 210, 2, 84, 66, 85, 42, 86, 38, 87, 70, 88, 162, 210, 27, 72, - 142, 60, 73, 206, 41, 89, 215, 22, 66, 5, 151, 180, 28, 79, 7, 142, 155, - 28, 32, 223, 61, 72, 7, 202, 216, 28, 69, 3, 85, 5, 207, 136, 28, 32, 5, - 255, 226, 24, 32, 19, 11, 32, 16, 76, 8, 87, 73, 84, 72, 32, 68, 79, 84, - 230, 5, 77, 2, 78, 195, 173, 27, 83, 5, 165, 218, 27, 12, 83, 32, 73, 78, - 83, 73, 68, 69, 32, 65, 78, 68, 9, 26, 32, 207, 214, 28, 75, 4, 186, 225, - 24, 82, 147, 245, 3, 77, 9, 248, 204, 22, 3, 79, 78, 71, 175, 137, 6, 72, - 11, 11, 32, 8, 162, 4, 78, 218, 173, 27, 87, 243, 163, 1, 83, 19, 38, 32, - 49, 5, 65, 83, 65, 76, 32, 8, 202, 3, 77, 218, 173, 27, 87, 243, 163, 1, - 83, 8, 226, 212, 28, 65, 2, 73, 2, 79, 3, 85, 11, 166, 211, 28, 79, 146, - 1, 65, 2, 85, 3, 87, 9, 52, 7, 69, 82, 78, 73, 78, 32, 65, 243, 131, 28, - 32, 4, 206, 211, 28, 77, 3, 78, 11, 248, 201, 22, 6, 79, 77, 65, 78, 73, - 65, 222, 203, 5, 32, 223, 61, 72, 49, 58, 32, 164, 1, 5, 76, 79, 65, 78, - 32, 191, 178, 6, 72, 26, 102, 74, 22, 75, 2, 80, 2, 84, 20, 7, 87, 73, - 84, 72, 32, 68, 79, 162, 209, 28, 77, 2, 78, 3, 83, 5, 235, 147, 28, 32, - 5, 215, 152, 28, 32, 4, 139, 217, 12, 84, 18, 74, 69, 230, 195, 5, 79, - 254, 188, 22, 65, 210, 78, 68, 146, 1, 74, 3, 85, 6, 190, 208, 28, 69, 2, - 72, 3, 78, 9, 26, 32, 131, 208, 28, 72, 4, 238, 218, 24, 82, 147, 245, 3, - 83, 9, 250, 255, 27, 32, 226, 79, 72, 3, 73, 5, 245, 148, 7, 4, 79, 67, - 65, 76, 17, 66, 79, 242, 149, 28, 32, 134, 37, 69, 218, 19, 65, 2, 72, 3, - 73, 5, 203, 206, 28, 87, 188, 91, 234, 2, 65, 188, 3, 10, 68, 73, 84, 79, - 82, 73, 65, 76, 32, 67, 22, 71, 224, 79, 4, 73, 71, 72, 84, 146, 2, 76, - 194, 9, 77, 214, 5, 78, 246, 3, 79, 36, 2, 81, 85, 182, 8, 82, 222, 1, - 83, 118, 84, 242, 31, 85, 198, 1, 88, 128, 5, 2, 89, 69, 200, 80, 4, 45, - 77, 65, 73, 148, 140, 19, 3, 74, 69, 67, 228, 147, 2, 8, 86, 69, 82, 71, - 82, 69, 69, 78, 175, 190, 5, 80, 22, 38, 82, 202, 230, 26, 83, 179, 64, - 71, 19, 30, 32, 137, 1, 2, 84, 72, 6, 88, 3, 79, 70, 32, 233, 229, 4, 13, - 87, 73, 84, 72, 32, 72, 69, 65, 82, 73, 78, 71, 32, 4, 140, 190, 11, 2, - 77, 65, 135, 230, 6, 82, 11, 17, 2, 32, 71, 8, 44, 5, 76, 79, 66, 69, 32, - 203, 148, 25, 82, 6, 70, 65, 181, 235, 21, 11, 69, 85, 82, 79, 80, 69, - 45, 65, 70, 82, 73, 4, 176, 137, 10, 4, 77, 69, 82, 73, 133, 154, 2, 11, - 83, 73, 65, 45, 65, 85, 83, 84, 82, 65, 76, 2, 183, 176, 2, 79, 228, 79, - 92, 17, 89, 80, 84, 73, 65, 78, 32, 72, 73, 69, 82, 79, 71, 76, 89, 80, - 72, 151, 199, 28, 71, 226, 79, 30, 32, 197, 74, 2, 45, 49, 172, 17, 146, - 3, 65, 178, 4, 66, 52, 2, 67, 48, 224, 1, 2, 68, 48, 170, 4, 69, 178, 3, - 70, 164, 4, 2, 71, 48, 210, 3, 72, 214, 1, 73, 238, 2, 76, 122, 77, 222, - 8, 78, 210, 5, 79, 140, 5, 2, 80, 48, 120, 2, 82, 48, 232, 1, 2, 83, 48, - 190, 3, 84, 220, 2, 2, 85, 48, 250, 2, 86, 134, 5, 87, 236, 2, 3, 88, 48, - 48, 88, 3, 89, 48, 48, 84, 2, 90, 48, 252, 214, 3, 3, 75, 48, 48, 189, - 146, 15, 3, 81, 48, 48, 228, 1, 30, 48, 133, 3, 2, 65, 48, 160, 1, 86, - 48, 98, 49, 102, 52, 166, 55, 51, 162, 241, 20, 55, 150, 227, 1, 50, 2, - 53, 3, 54, 24, 170, 68, 54, 170, 146, 22, 53, 134, 236, 5, 49, 2, 50, 2, - 51, 2, 52, 2, 55, 2, 56, 3, 57, 24, 242, 213, 22, 52, 2, 55, 134, 236, 5, - 48, 2, 49, 2, 50, 2, 51, 2, 53, 2, 54, 2, 56, 3, 57, 28, 142, 213, 22, - 48, 2, 50, 2, 51, 2, 53, 134, 236, 5, 49, 2, 52, 2, 54, 2, 55, 2, 56, 3, - 57, 68, 46, 48, 246, 54, 51, 210, 211, 22, 49, 3, 50, 22, 210, 65, 55, - 174, 254, 27, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 26, - 148, 9, 4, 69, 71, 73, 78, 185, 25, 2, 48, 48, 56, 34, 48, 90, 49, 175, - 244, 8, 50, 24, 230, 39, 50, 234, 150, 28, 49, 2, 51, 2, 52, 2, 53, 2, - 54, 2, 55, 2, 56, 3, 57, 22, 242, 209, 22, 48, 134, 236, 5, 49, 2, 50, 2, - 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 184, 1, 70, 48, 94, 51, - 102, 52, 102, 53, 106, 54, 194, 29, 50, 195, 230, 22, 49, 20, 194, 208, - 22, 56, 134, 236, 5, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, - 24, 230, 207, 22, 49, 2, 52, 134, 236, 5, 48, 2, 50, 2, 51, 2, 53, 2, 54, - 2, 55, 2, 56, 3, 57, 24, 130, 207, 22, 54, 2, 56, 134, 236, 5, 48, 2, 49, - 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 3, 57, 42, 214, 60, 48, 202, 145, 22, - 50, 2, 52, 134, 236, 5, 49, 2, 51, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 32, - 194, 60, 55, 250, 252, 27, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, - 94, 30, 48, 189, 2, 2, 78, 68, 88, 38, 48, 94, 50, 102, 51, 215, 7, 49, - 22, 158, 204, 22, 56, 2, 57, 134, 236, 5, 49, 2, 50, 2, 51, 2, 52, 2, 53, - 2, 54, 3, 55, 24, 194, 203, 22, 48, 2, 56, 134, 236, 5, 49, 2, 50, 2, 51, - 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 18, 222, 202, 22, 52, 134, 236, 5, 48, - 2, 49, 2, 50, 2, 51, 2, 54, 2, 55, 3, 56, 6, 11, 32, 6, 136, 180, 5, 6, - 87, 65, 76, 76, 69, 68, 210, 19, 69, 203, 211, 20, 83, 132, 1, 42, 48, - 133, 9, 5, 85, 76, 76, 32, 66, 130, 1, 54, 48, 94, 49, 102, 51, 102, 52, - 102, 53, 215, 1, 50, 20, 202, 200, 22, 49, 134, 236, 5, 50, 2, 51, 2, 52, - 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 22, 238, 199, 22, 51, 134, 236, 5, 48, - 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 26, 138, 199, 22, - 49, 2, 55, 2, 56, 134, 236, 5, 48, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, - 57, 26, 166, 198, 22, 53, 2, 54, 2, 55, 134, 236, 5, 48, 2, 49, 2, 50, 2, - 51, 2, 52, 2, 56, 3, 57, 14, 222, 26, 49, 234, 150, 28, 48, 2, 50, 3, 51, - 128, 1, 62, 48, 98, 49, 102, 51, 102, 52, 210, 27, 50, 147, 201, 8, 53, - 24, 166, 50, 55, 170, 146, 22, 54, 134, 236, 5, 49, 2, 50, 2, 51, 2, 52, - 2, 53, 2, 56, 3, 57, 22, 238, 195, 22, 49, 134, 236, 5, 48, 2, 50, 2, 51, - 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 24, 138, 195, 22, 54, 2, 55, - 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 56, 3, 57, 24, - 166, 194, 22, 51, 2, 53, 134, 236, 5, 48, 2, 49, 2, 50, 2, 52, 2, 54, 2, - 55, 2, 56, 3, 57, 24, 80, 2, 48, 48, 84, 4, 65, 76, 70, 32, 161, 40, 7, - 79, 82, 73, 90, 79, 78, 84, 18, 238, 192, 22, 54, 134, 236, 5, 49, 2, 50, - 2, 51, 2, 52, 2, 53, 2, 55, 3, 56, 4, 22, 66, 255, 42, 76, 2, 223, 238, - 16, 76, 52, 58, 48, 181, 1, 9, 78, 83, 69, 82, 84, 32, 65, 84, 32, 38, - 18, 48, 95, 49, 22, 158, 191, 22, 53, 2, 57, 134, 236, 5, 49, 2, 50, 2, - 51, 2, 52, 2, 54, 2, 55, 3, 56, 16, 194, 190, 22, 48, 2, 49, 134, 236, 5, - 50, 2, 51, 2, 52, 3, 53, 14, 68, 6, 66, 79, 84, 84, 79, 77, 0, 3, 84, 79, - 80, 215, 212, 19, 77, 7, 11, 32, 4, 182, 155, 27, 69, 221, 6, 2, 83, 84, - 22, 32, 2, 48, 48, 203, 221, 15, 79, 20, 222, 188, 22, 50, 2, 54, 134, - 236, 5, 49, 2, 51, 2, 52, 2, 53, 2, 55, 3, 56, 164, 1, 118, 48, 128, 4, - 15, 79, 68, 73, 70, 73, 69, 82, 32, 68, 65, 77, 65, 71, 69, 68, 205, 228, - 24, 5, 73, 82, 82, 79, 82, 132, 1, 42, 48, 98, 49, 106, 50, 102, 51, 107, - 52, 24, 182, 40, 49, 170, 146, 22, 51, 134, 236, 5, 50, 2, 52, 2, 53, 2, - 54, 2, 55, 2, 56, 3, 57, 44, 138, 41, 50, 246, 144, 22, 48, 2, 53, 2, 54, - 2, 55, 134, 236, 5, 49, 2, 51, 2, 52, 2, 56, 3, 57, 26, 150, 185, 22, 50, - 2, 52, 2, 56, 134, 236, 5, 48, 2, 49, 2, 51, 2, 53, 2, 54, 2, 55, 3, 57, - 26, 138, 38, 51, 170, 146, 22, 49, 134, 236, 5, 48, 2, 50, 2, 52, 2, 53, - 2, 54, 2, 55, 2, 56, 3, 57, 12, 202, 183, 22, 48, 134, 236, 5, 49, 2, 50, - 2, 51, 3, 52, 31, 25, 4, 32, 65, 84, 32, 28, 96, 6, 66, 79, 84, 84, 79, - 77, 120, 5, 83, 84, 65, 82, 84, 68, 3, 84, 79, 80, 227, 146, 27, 69, 11, - 11, 32, 8, 56, 5, 83, 84, 65, 82, 84, 186, 1, 65, 159, 146, 27, 69, 5, - 129, 2, 8, 32, 65, 78, 68, 32, 84, 79, 80, 7, 29, 5, 32, 65, 78, 68, 32, - 4, 206, 181, 24, 66, 155, 242, 2, 84, 11, 11, 32, 8, 54, 65, 20, 5, 83, - 84, 65, 82, 84, 139, 146, 27, 69, 2, 73, 2, 78, 68, 5, 53, 11, 32, 65, - 78, 68, 32, 66, 79, 84, 84, 79, 77, 2, 251, 209, 19, 32, 194, 1, 50, 48, - 128, 2, 2, 76, 48, 229, 1, 2, 85, 48, 98, 58, 49, 98, 51, 194, 14, 50, - 150, 6, 52, 227, 209, 22, 48, 24, 146, 32, 56, 174, 254, 27, 48, 2, 49, - 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 28, 218, 177, 22, 51, 2, - 52, 2, 53, 2, 55, 134, 236, 5, 48, 2, 49, 2, 50, 2, 54, 2, 56, 3, 57, 44, - 34, 48, 94, 49, 175, 131, 21, 50, 20, 210, 176, 22, 53, 134, 236, 5, 49, - 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 22, 246, 175, 22, 55, - 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, - 52, 34, 49, 102, 50, 231, 226, 22, 48, 26, 238, 174, 22, 48, 2, 49, 2, - 56, 134, 236, 5, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 8, 138, - 174, 22, 50, 134, 236, 5, 48, 3, 49, 152, 1, 50, 48, 145, 247, 18, 6, 86, - 69, 82, 76, 65, 89, 150, 1, 66, 48, 154, 1, 49, 138, 1, 50, 102, 51, 106, - 53, 191, 223, 22, 52, 34, 90, 54, 134, 172, 22, 49, 2, 53, 134, 236, 5, - 50, 2, 51, 2, 52, 2, 55, 2, 56, 3, 57, 15, 134, 152, 28, 65, 2, 66, 2, - 67, 2, 68, 2, 69, 3, 70, 28, 98, 48, 230, 170, 22, 57, 134, 236, 5, 49, - 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 9, 230, 150, 28, 65, 2, - 66, 3, 67, 28, 190, 170, 22, 48, 2, 52, 2, 53, 2, 57, 134, 236, 5, 49, 2, - 50, 2, 51, 2, 54, 2, 55, 3, 56, 32, 134, 23, 54, 214, 146, 22, 48, 2, 51, - 134, 236, 5, 49, 2, 50, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 8, 202, 22, - 48, 175, 254, 27, 49, 26, 26, 48, 143, 194, 8, 49, 22, 182, 168, 22, 49, - 2, 51, 134, 236, 5, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 68, 34, - 48, 98, 49, 163, 221, 22, 50, 24, 142, 21, 51, 170, 146, 22, 50, 134, - 236, 5, 49, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 24, 214, 166, 22, - 48, 2, 54, 134, 236, 5, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, - 57, 108, 50, 48, 94, 49, 106, 50, 98, 51, 171, 172, 19, 52, 22, 190, 165, - 22, 50, 2, 54, 134, 236, 5, 49, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, - 26, 186, 18, 52, 170, 146, 22, 55, 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, - 2, 53, 2, 54, 2, 56, 3, 57, 24, 210, 17, 54, 174, 254, 27, 48, 2, 49, 2, - 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 22, 154, 163, 22, 53, 134, - 236, 5, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 90, - 34, 48, 249, 12, 3, 65, 76, 76, 88, 42, 48, 94, 49, 102, 51, 243, 214, - 22, 50, 26, 230, 161, 22, 51, 2, 55, 2, 56, 2, 57, 134, 236, 5, 49, 2, - 50, 2, 52, 2, 53, 3, 54, 24, 138, 161, 22, 49, 2, 54, 134, 236, 5, 48, 2, - 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 18, 166, 160, 22, 50, 2, - 51, 134, 236, 5, 48, 2, 49, 2, 52, 2, 53, 3, 54, 94, 50, 48, 90, 50, 102, - 51, 102, 52, 211, 211, 22, 49, 22, 254, 12, 54, 174, 254, 27, 49, 2, 50, - 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 24, 206, 158, 22, 51, 2, 57, - 134, 236, 5, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 22, - 234, 157, 22, 50, 134, 236, 5, 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, 54, 2, - 55, 2, 56, 3, 57, 6, 138, 137, 28, 48, 2, 49, 3, 50, 158, 1, 42, 48, 185, - 4, 5, 69, 82, 84, 73, 67, 156, 1, 62, 48, 98, 49, 98, 50, 210, 1, 51, - 225, 152, 22, 2, 52, 48, 42, 198, 9, 55, 98, 49, 202, 145, 22, 50, 134, - 236, 5, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 32, 186, 8, 49, 46, 50, - 174, 254, 27, 48, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 50, - 98, 48, 206, 153, 22, 51, 2, 56, 2, 57, 134, 236, 5, 49, 2, 50, 2, 52, 2, - 53, 2, 54, 3, 55, 27, 206, 133, 28, 65, 2, 66, 2, 67, 2, 68, 2, 69, 2, - 70, 2, 71, 2, 72, 2, 73, 2, 74, 2, 75, 3, 76, 28, 222, 152, 22, 48, 2, - 49, 2, 51, 2, 55, 134, 236, 5, 50, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 2, - 221, 221, 23, 2, 65, 76, 66, 34, 48, 161, 2, 3, 73, 68, 69, 64, 26, 48, - 94, 49, 103, 50, 22, 158, 151, 22, 51, 2, 57, 134, 236, 5, 49, 2, 50, 2, - 52, 2, 53, 2, 54, 2, 55, 3, 56, 28, 194, 150, 22, 48, 2, 52, 2, 55, 2, - 56, 134, 236, 5, 49, 2, 50, 2, 51, 2, 53, 2, 54, 3, 57, 14, 222, 149, 22, - 52, 134, 236, 5, 48, 2, 49, 2, 50, 2, 51, 3, 53, 2, 17, 2, 32, 76, 2, - 239, 181, 15, 79, 24, 202, 2, 52, 170, 146, 22, 54, 2, 56, 134, 236, 5, - 49, 2, 50, 2, 51, 2, 53, 3, 55, 18, 154, 148, 22, 49, 134, 236, 5, 50, 2, - 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 82, 22, 48, 167, 1, 49, 34, 90, - 50, 46, 51, 170, 146, 22, 52, 2, 53, 134, 236, 5, 49, 2, 54, 2, 55, 2, - 56, 3, 57, 11, 214, 254, 27, 65, 2, 66, 2, 67, 3, 68, 7, 170, 254, 27, - 65, 3, 66, 48, 66, 53, 86, 54, 250, 252, 27, 48, 2, 49, 2, 50, 2, 51, 3, - 52, 21, 202, 253, 27, 65, 2, 66, 2, 67, 2, 68, 2, 69, 2, 70, 2, 71, 2, - 72, 3, 73, 19, 246, 252, 27, 65, 2, 66, 2, 67, 2, 68, 2, 69, 2, 70, 2, - 71, 3, 72, 182, 62, 22, 51, 211, 1, 52, 192, 46, 106, 52, 174, 188, 5, + 73, 82, 67, 76, 69, 68, 32, 83, 42, 38, 83, 182, 32, 78, 203, 215, 20, + 68, 22, 49, 10, 65, 78, 83, 45, 83, 69, 82, 73, 70, 32, 22, 254, 31, 78, + 147, 175, 27, 68, 4, 132, 174, 27, 15, 67, 85, 82, 82, 69, 78, 84, 32, + 83, 89, 77, 66, 79, 76, 32, 187, 248, 1, 72, 12, 98, 65, 144, 1, 5, 67, + 79, 78, 84, 73, 192, 240, 15, 3, 84, 79, 82, 253, 152, 10, 3, 71, 85, 73, + 6, 76, 9, 80, 80, 79, 73, 78, 84, 69, 68, 32, 245, 161, 27, 4, 66, 76, + 69, 68, 4, 144, 175, 17, 7, 66, 85, 84, 32, 82, 69, 76, 203, 212, 11, 70, + 2, 53, 11, 78, 85, 79, 85, 83, 32, 85, 78, 68, 69, 82, 2, 157, 145, 17, + 3, 76, 73, 78, 156, 1, 80, 9, 69, 83, 32, 65, 75, 85, 82, 85, 32, 238, 5, + 73, 177, 138, 17, 2, 79, 82, 144, 1, 142, 2, 68, 36, 7, 76, 69, 84, 84, + 69, 82, 32, 236, 1, 5, 83, 73, 71, 78, 32, 58, 86, 240, 170, 9, 6, 77, + 69, 68, 73, 65, 76, 234, 132, 5, 71, 134, 237, 4, 69, 148, 209, 4, 12, + 80, 82, 69, 70, 73, 88, 69, 68, 32, 78, 65, 83, 209, 129, 5, 7, 73, 78, + 73, 84, 73, 65, 76, 22, 166, 220, 25, 79, 191, 236, 1, 73, 84, 218, 208, + 10, 84, 190, 243, 11, 89, 182, 230, 2, 65, 162, 52, 68, 214, 6, 85, 186, + 202, 1, 73, 42, 76, 226, 195, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 75, + 2, 80, 138, 69, 72, 2, 74, 2, 77, 2, 82, 2, 86, 2, 90, 186, 2, 69, 3, 79, + 8, 158, 242, 24, 72, 210, 42, 67, 98, 78, 139, 216, 3, 65, 18, 64, 10, + 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 187, 253, 26, 73, 16, 166, 164, + 15, 65, 178, 190, 10, 85, 186, 202, 1, 73, 198, 140, 2, 69, 3, 79, 10, + 68, 5, 83, 73, 79, 78, 32, 136, 242, 1, 2, 78, 71, 183, 176, 26, 68, 6, + 26, 83, 235, 234, 5, 84, 4, 142, 205, 27, 76, 187, 100, 73, 2, 253, 150, + 19, 3, 32, 76, 65, 4, 182, 162, 28, 83, 167, 88, 70, 212, 5, 188, 2, 6, + 67, 85, 77, 69, 78, 84, 124, 7, 69, 83, 32, 78, 79, 84, 32, 194, 3, 71, + 202, 3, 76, 36, 10, 77, 73, 78, 79, 32, 84, 73, 76, 69, 32, 226, 1, 78, + 38, 84, 246, 2, 85, 204, 17, 2, 87, 78, 212, 203, 16, 8, 32, 78, 79, 84, + 32, 76, 73, 84, 184, 141, 12, 8, 86, 69, 32, 79, 70, 32, 80, 69, 174, 4, + 79, 235, 25, 68, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 40, 4, 84, 69, 88, + 84, 175, 143, 2, 80, 5, 169, 143, 2, 6, 32, 65, 78, 68, 32, 80, 22, 164, + 1, 11, 67, 79, 78, 84, 65, 73, 78, 32, 65, 83, 32, 92, 6, 68, 73, 86, 73, + 68, 69, 112, 2, 80, 82, 48, 7, 83, 85, 67, 67, 69, 69, 68, 185, 233, 22, + 2, 70, 79, 6, 248, 1, 15, 78, 79, 82, 77, 65, 76, 32, 83, 85, 66, 71, 82, + 79, 85, 80, 155, 137, 21, 77, 5, 145, 141, 22, 23, 32, 87, 73, 84, 72, + 32, 82, 69, 86, 69, 82, 83, 69, 68, 32, 78, 69, 71, 65, 84, 73, 79, 78, + 6, 44, 5, 69, 67, 69, 68, 69, 143, 180, 28, 79, 5, 205, 167, 9, 2, 32, + 79, 125, 36, 3, 82, 65, 32, 139, 243, 28, 32, 120, 120, 7, 76, 69, 84, + 84, 69, 82, 32, 208, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, + 254, 185, 23, 65, 187, 2, 83, 88, 170, 209, 25, 65, 38, 68, 82, 82, 34, + 84, 230, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, 46, 83, 82, 66, 2, 67, + 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 86, 2, 89, 186, + 2, 69, 3, 79, 22, 130, 159, 19, 86, 174, 183, 6, 65, 38, 85, 186, 202, 1, + 73, 198, 140, 2, 69, 3, 79, 4, 142, 161, 21, 80, 199, 193, 2, 76, 200, 1, + 72, 8, 72, 79, 82, 73, 90, 79, 78, 84, 1, 6, 86, 69, 82, 84, 73, 67, 100, + 17, 2, 65, 76, 100, 32, 2, 45, 48, 155, 148, 24, 32, 98, 58, 48, 2, 49, + 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 14, 149, 186, 20, 2, 45, 48, 4, 158, + 141, 27, 75, 219, 150, 1, 71, 26, 34, 32, 57, 4, 84, 69, 68, 32, 8, 162, + 159, 25, 80, 34, 77, 194, 71, 79, 195, 198, 2, 65, 18, 214, 1, 67, 34, + 83, 128, 160, 16, 3, 76, 73, 78, 148, 134, 1, 4, 79, 66, 69, 76, 244, 9, + 9, 84, 82, 65, 78, 83, 80, 79, 83, 73, 202, 230, 6, 70, 161, 41, 14, 82, + 73, 71, 72, 84, 45, 80, 79, 73, 78, 84, 73, 78, 71, 4, 146, 212, 27, 73, + 239, 16, 82, 4, 246, 144, 27, 79, 183, 116, 81, 162, 1, 40, 3, 66, 76, + 69, 137, 17, 2, 71, 72, 160, 1, 42, 32, 190, 10, 45, 241, 5, 2, 68, 32, + 106, 226, 2, 67, 174, 1, 68, 38, 72, 32, 4, 73, 78, 84, 69, 38, 76, 144, + 1, 7, 78, 69, 83, 84, 69, 68, 32, 74, 80, 66, 83, 130, 2, 85, 36, 9, 86, + 69, 82, 84, 73, 67, 65, 76, 32, 188, 168, 6, 6, 79, 66, 76, 73, 81, 85, + 144, 191, 2, 9, 82, 73, 71, 72, 84, 32, 65, 82, 67, 134, 189, 3, 65, 166, + 221, 9, 69, 246, 198, 4, 81, 153, 106, 6, 87, 65, 86, 89, 32, 79, 24, + 100, 7, 73, 82, 67, 76, 69, 68, 32, 140, 215, 7, 4, 85, 82, 76, 89, 253, + 197, 1, 4, 79, 76, 79, 78, 20, 26, 78, 203, 215, 20, 68, 2, 221, 219, 2, + 5, 85, 77, 66, 69, 82, 4, 150, 255, 18, 79, 167, 210, 6, 65, 4, 250, 209, + 20, 73, 239, 63, 89, 4, 146, 160, 26, 82, 179, 246, 1, 71, 12, 54, 79, + 165, 171, 17, 7, 69, 70, 84, 32, 65, 82, 67, 10, 26, 87, 191, 220, 25, + 71, 6, 26, 45, 211, 133, 28, 32, 4, 226, 208, 20, 82, 211, 1, 57, 6, 132, + 153, 17, 9, 76, 69, 83, 83, 45, 84, 72, 65, 78, 255, 241, 9, 71, 8, 26, + 82, 179, 151, 27, 76, 6, 138, 158, 1, 69, 219, 250, 15, 73, 18, 80, 6, + 81, 85, 65, 82, 69, 32, 30, 84, 50, 85, 173, 229, 13, 4, 79, 76, 73, 68, + 4, 222, 235, 25, 73, 55, 85, 4, 212, 205, 12, 3, 65, 67, 75, 163, 202, 4, + 82, 8, 58, 83, 170, 156, 1, 67, 146, 156, 21, 80, 175, 247, 4, 66, 2, + 245, 180, 28, 4, 80, 69, 78, 83, 4, 174, 250, 18, 80, 255, 210, 9, 78, + 10, 36, 3, 66, 65, 82, 235, 129, 28, 76, 9, 11, 32, 6, 52, 7, 68, 79, 85, + 66, 76, 69, 32, 143, 243, 26, 76, 4, 138, 243, 26, 76, 51, 82, 48, 112, + 5, 76, 73, 78, 69, 32, 220, 1, 7, 83, 84, 82, 85, 67, 75, 32, 133, 235, + 8, 7, 69, 78, 68, 69, 68, 32, 77, 12, 48, 8, 83, 76, 65, 78, 84, 69, 68, + 32, 75, 69, 8, 70, 69, 56, 7, 71, 82, 69, 65, 84, 69, 82, 1, 4, 76, 69, + 83, 83, 4, 237, 198, 20, 9, 81, 85, 65, 76, 32, 84, 79, 32, 79, 2, 249, + 179, 14, 5, 45, 84, 72, 65, 78, 34, 160, 1, 8, 67, 65, 80, 73, 84, 65, + 76, 32, 92, 7, 73, 84, 65, 76, 73, 67, 32, 124, 6, 83, 77, 65, 76, 76, + 32, 141, 223, 13, 8, 78, 45, 65, 82, 89, 32, 83, 85, 18, 206, 177, 12, + 71, 190, 218, 14, 80, 198, 140, 2, 67, 2, 72, 2, 78, 2, 81, 2, 82, 3, 90, + 10, 76, 6, 83, 77, 65, 76, 76, 32, 129, 250, 21, 7, 67, 65, 80, 73, 84, + 65, 76, 8, 162, 151, 29, 68, 2, 69, 2, 73, 3, 74, 4, 246, 175, 12, 71, + 171, 211, 16, 80, 6, 166, 175, 10, 70, 26, 77, 235, 209, 17, 83, 2, 215, + 156, 28, 78, 166, 1, 50, 32, 158, 1, 45, 189, 1, 4, 87, 65, 82, 68, 10, + 60, 4, 84, 65, 67, 75, 218, 236, 25, 70, 30, 82, 195, 79, 65, 5, 29, 5, + 32, 87, 73, 84, 72, 2, 11, 32, 2, 11, 67, 2, 197, 136, 21, 4, 73, 82, 67, + 76, 28, 60, 9, 80, 79, 73, 78, 84, 73, 78, 71, 32, 203, 237, 25, 70, 24, + 62, 83, 238, 239, 25, 65, 86, 69, 62, 70, 46, 82, 207, 1, 84, 4, 178, + 195, 17, 84, 161, 175, 8, 6, 77, 65, 76, 76, 32, 82, 128, 1, 56, 8, 32, + 70, 65, 67, 73, 78, 71, 32, 89, 2, 83, 32, 8, 54, 72, 1, 9, 78, 79, 84, + 67, 72, 69, 68, 32, 72, 4, 237, 235, 27, 3, 79, 79, 75, 120, 178, 1, 65, + 200, 2, 6, 66, 76, 65, 67, 75, 32, 38, 84, 144, 246, 8, 2, 87, 72, 214, + 160, 8, 90, 178, 137, 9, 68, 50, 70, 82, 72, 150, 4, 67, 46, 81, 42, 82, + 22, 83, 247, 7, 80, 34, 40, 4, 82, 82, 79, 87, 175, 155, 26, 78, 33, 11, + 32, 30, 144, 1, 5, 87, 73, 84, 72, 32, 184, 242, 13, 14, 76, 69, 70, 84, + 87, 65, 82, 68, 83, 32, 79, 70, 32, 85, 138, 169, 12, 65, 178, 10, 70, + 179, 5, 84, 22, 192, 190, 5, 6, 67, 79, 82, 78, 69, 82, 170, 223, 20, 68, + 58, 76, 42, 77, 38, 78, 58, 83, 66, 69, 250, 12, 84, 135, 58, 72, 6, 246, + 149, 21, 65, 231, 137, 5, 67, 36, 36, 2, 82, 73, 161, 2, 2, 87, 79, 32, + 44, 5, 65, 78, 71, 76, 69, 139, 174, 26, 80, 30, 56, 8, 45, 72, 69, 65, + 68, 69, 68, 32, 199, 179, 26, 32, 28, 68, 5, 65, 82, 82, 79, 87, 138, + 149, 17, 90, 254, 150, 9, 68, 39, 80, 23, 11, 32, 20, 180, 167, 26, 15, + 76, 69, 70, 84, 87, 65, 82, 68, 83, 32, 79, 70, 32, 85, 80, 98, 84, 23, + 87, 4, 130, 173, 26, 32, 105, 15, 45, 72, 69, 65, 68, 69, 68, 32, 65, 82, + 82, 79, 87, 32, 87, 22, 138, 1, 65, 106, 79, 152, 1, 12, 85, 77, 32, 87, + 73, 84, 72, 32, 68, 82, 85, 77, 196, 129, 17, 6, 73, 86, 69, 32, 83, 76, + 139, 237, 10, 69, 8, 174, 209, 2, 67, 128, 150, 6, 10, 70, 84, 73, 78, + 71, 32, 80, 79, 73, 78, 181, 250, 15, 3, 71, 79, 78, 8, 56, 6, 77, 69, + 68, 65, 82, 89, 34, 80, 215, 208, 27, 79, 2, 157, 254, 20, 3, 32, 67, 65, + 4, 240, 196, 18, 6, 32, 79, 70, 32, 66, 76, 211, 141, 10, 76, 2, 213, + 231, 12, 3, 83, 84, 73, 162, 2, 76, 7, 80, 76, 79, 89, 65, 78, 32, 188, + 152, 20, 2, 77, 80, 219, 234, 8, 67, 158, 2, 212, 2, 6, 65, 70, 70, 73, + 88, 32, 160, 7, 7, 76, 69, 84, 84, 69, 82, 32, 232, 194, 1, 16, 84, 72, + 73, 67, 75, 32, 76, 69, 84, 84, 69, 82, 32, 83, 69, 76, 232, 180, 3, 4, + 68, 79, 85, 66, 144, 243, 16, 19, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, + 78, 32, 67, 72, 73, 78, 79, 79, 75, 145, 206, 5, 11, 83, 73, 71, 78, 32, + 79, 32, 87, 73, 84, 72, 64, 140, 1, 9, 65, 84, 84, 65, 67, 72, 69, 68, + 32, 184, 1, 5, 72, 73, 71, 72, 32, 106, 76, 40, 4, 82, 73, 71, 72, 173, + 2, 4, 77, 73, 68, 32, 14, 112, 2, 84, 65, 232, 4, 13, 76, 69, 70, 84, 45, + 84, 79, 45, 82, 73, 71, 72, 84, 26, 83, 234, 130, 21, 69, 3, 73, 6, 44, + 5, 78, 71, 69, 78, 84, 207, 245, 27, 73, 5, 195, 135, 21, 32, 20, 174, 2, + 76, 50, 84, 38, 86, 250, 182, 8, 71, 186, 2, 65, 186, 214, 18, 87, 134, + 26, 67, 227, 131, 1, 68, 24, 36, 2, 69, 70, 29, 3, 79, 87, 32, 2, 213, 2, + 3, 84, 32, 72, 22, 94, 65, 38, 76, 50, 84, 38, 86, 250, 182, 8, 71, 242, + 216, 18, 87, 134, 26, 67, 227, 131, 1, 68, 4, 134, 249, 21, 67, 195, 233, + 5, 82, 4, 216, 136, 8, 3, 79, 78, 71, 207, 218, 19, 73, 2, 185, 174, 8, + 4, 73, 71, 72, 84, 4, 37, 7, 69, 82, 84, 73, 67, 65, 76, 5, 131, 1, 32, + 4, 42, 72, 41, 6, 86, 69, 82, 84, 73, 67, 2, 37, 7, 79, 82, 73, 90, 79, + 78, 84, 2, 17, 2, 65, 76, 2, 11, 32, 2, 11, 83, 2, 209, 240, 27, 2, 69, + 67, 214, 1, 222, 1, 65, 22, 68, 34, 69, 30, 70, 22, 71, 22, 74, 170, 1, + 75, 66, 76, 50, 77, 62, 78, 134, 1, 79, 50, 80, 86, 82, 74, 83, 210, 2, + 84, 66, 85, 42, 86, 38, 87, 70, 88, 230, 243, 27, 72, 142, 60, 73, 206, + 41, 89, 215, 22, 66, 5, 227, 213, 28, 79, 7, 218, 188, 28, 32, 223, 61, + 72, 7, 150, 250, 28, 69, 3, 85, 5, 155, 170, 28, 32, 5, 247, 255, 24, 32, + 19, 11, 32, 16, 76, 8, 87, 73, 84, 72, 32, 68, 79, 84, 238, 5, 77, 2, 78, + 243, 204, 27, 83, 5, 53, 11, 83, 32, 73, 78, 83, 73, 68, 69, 32, 65, 78, + 2, 187, 251, 27, 68, 9, 26, 32, 147, 248, 28, 75, 4, 170, 254, 24, 82, + 231, 249, 3, 77, 9, 224, 223, 22, 3, 79, 78, 71, 139, 152, 6, 72, 11, 11, + 32, 8, 162, 4, 78, 138, 205, 27, 87, 135, 166, 1, 83, 19, 38, 32, 49, 5, + 65, 83, 65, 76, 32, 8, 202, 3, 77, 138, 205, 27, 87, 135, 166, 1, 83, 8, + 166, 246, 28, 65, 2, 73, 2, 79, 3, 85, 11, 234, 244, 28, 79, 146, 1, 65, + 2, 85, 3, 87, 9, 52, 7, 69, 82, 78, 73, 78, 32, 65, 183, 165, 28, 32, 4, + 146, 245, 28, 77, 3, 78, 11, 224, 220, 22, 6, 79, 77, 65, 78, 73, 65, + 186, 218, 5, 32, 223, 61, 72, 49, 58, 32, 164, 1, 5, 76, 79, 65, 78, 32, + 239, 185, 6, 72, 26, 102, 74, 22, 75, 2, 80, 2, 84, 20, 7, 87, 73, 84, + 72, 32, 68, 79, 230, 242, 28, 77, 2, 78, 3, 83, 5, 175, 181, 28, 32, 5, + 155, 186, 28, 32, 4, 167, 231, 12, 84, 18, 74, 69, 138, 203, 5, 79, 158, + 215, 22, 65, 210, 78, 68, 146, 1, 74, 3, 85, 6, 130, 242, 28, 69, 2, 72, + 3, 78, 9, 26, 32, 199, 241, 28, 72, 4, 222, 247, 24, 82, 231, 249, 3, 83, + 9, 190, 161, 28, 32, 226, 79, 72, 3, 73, 5, 137, 157, 7, 4, 79, 67, 65, + 76, 17, 66, 79, 182, 183, 28, 32, 134, 37, 69, 218, 19, 65, 2, 72, 3, 73, + 5, 143, 240, 28, 87, 194, 91, 234, 2, 65, 188, 3, 10, 68, 73, 84, 79, 82, + 73, 65, 76, 32, 67, 22, 71, 240, 79, 4, 73, 71, 72, 84, 146, 2, 76, 194, + 9, 77, 214, 5, 78, 246, 3, 79, 36, 2, 81, 85, 182, 8, 82, 222, 1, 83, + 118, 84, 242, 31, 85, 226, 1, 88, 128, 5, 2, 89, 69, 208, 86, 4, 45, 77, + 65, 73, 156, 153, 19, 3, 74, 69, 67, 244, 152, 2, 8, 86, 69, 82, 71, 82, + 69, 69, 78, 167, 199, 5, 80, 22, 38, 82, 166, 133, 27, 83, 135, 65, 71, + 19, 30, 32, 137, 1, 2, 84, 72, 6, 88, 3, 79, 70, 32, 233, 236, 4, 13, 87, + 73, 84, 72, 32, 72, 69, 65, 82, 73, 78, 71, 32, 4, 132, 204, 11, 2, 77, + 65, 143, 232, 6, 82, 11, 17, 2, 32, 71, 8, 44, 5, 76, 79, 66, 69, 32, + 187, 178, 25, 82, 6, 70, 65, 249, 254, 21, 11, 69, 85, 82, 79, 80, 69, + 45, 65, 70, 82, 73, 4, 244, 150, 10, 4, 77, 69, 82, 73, 193, 154, 2, 11, + 83, 73, 65, 45, 65, 85, 83, 84, 82, 65, 76, 2, 239, 182, 2, 79, 230, 79, + 108, 17, 89, 80, 84, 73, 65, 78, 32, 72, 73, 69, 82, 79, 71, 76, 89, 80, + 72, 130, 217, 2, 69, 203, 143, 26, 71, 226, 79, 30, 32, 197, 74, 2, 45, + 49, 172, 17, 146, 3, 65, 178, 4, 66, 52, 2, 67, 48, 224, 1, 2, 68, 48, + 170, 4, 69, 178, 3, 70, 164, 4, 2, 71, 48, 210, 3, 72, 214, 1, 73, 238, + 2, 76, 122, 77, 222, 8, 78, 210, 5, 79, 140, 5, 2, 80, 48, 120, 2, 82, + 48, 232, 1, 2, 83, 48, 190, 3, 84, 220, 2, 2, 85, 48, 250, 2, 86, 134, 5, + 87, 236, 2, 3, 88, 48, 48, 88, 3, 89, 48, 48, 84, 2, 90, 48, 208, 221, 3, + 3, 75, 48, 48, 153, 159, 15, 3, 81, 48, 48, 228, 1, 30, 48, 133, 3, 2, + 65, 48, 160, 1, 86, 48, 98, 49, 102, 52, 166, 55, 51, 194, 132, 21, 55, + 198, 232, 1, 50, 2, 53, 3, 54, 24, 170, 68, 54, 242, 141, 24, 53, 242, + 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 55, 2, 56, 3, 57, 24, 186, 209, 24, + 52, 2, 55, 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 53, 2, 54, 2, 56, 3, + 57, 28, 214, 208, 24, 48, 2, 50, 2, 51, 2, 53, 242, 145, 4, 49, 2, 52, 2, + 54, 2, 55, 2, 56, 3, 57, 68, 46, 48, 246, 54, 51, 162, 236, 22, 49, 3, + 50, 22, 210, 65, 55, 226, 159, 28, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, + 2, 56, 3, 57, 26, 148, 9, 4, 69, 71, 73, 78, 185, 25, 2, 48, 48, 56, 34, + 48, 90, 49, 251, 252, 8, 50, 24, 230, 39, 50, 158, 184, 28, 49, 2, 51, 2, + 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 22, 186, 205, 24, 48, 242, 145, 4, + 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 184, 1, 70, + 48, 94, 51, 102, 52, 102, 53, 106, 54, 194, 29, 50, 147, 255, 22, 49, 20, + 138, 204, 24, 56, 242, 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, + 55, 3, 57, 24, 174, 203, 24, 49, 2, 52, 242, 145, 4, 48, 2, 50, 2, 51, 2, + 53, 2, 54, 2, 55, 2, 56, 3, 57, 24, 202, 202, 24, 54, 2, 56, 242, 145, 4, + 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 3, 57, 42, 214, 60, 48, + 146, 141, 24, 50, 2, 52, 242, 145, 4, 49, 2, 51, 2, 53, 2, 54, 2, 55, 2, + 56, 3, 57, 32, 194, 60, 55, 174, 158, 28, 48, 2, 49, 2, 50, 2, 51, 2, 52, + 2, 53, 3, 54, 94, 30, 48, 189, 2, 2, 78, 68, 88, 38, 48, 94, 50, 102, 51, + 215, 7, 49, 22, 230, 199, 24, 56, 2, 57, 242, 145, 4, 49, 2, 50, 2, 51, + 2, 52, 2, 53, 2, 54, 3, 55, 24, 138, 199, 24, 48, 2, 56, 242, 145, 4, 49, + 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 18, 166, 198, 24, 52, + 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 54, 2, 55, 3, 56, 6, 11, 32, 6, + 156, 187, 5, 6, 87, 65, 76, 76, 69, 68, 210, 19, 69, 143, 234, 20, 83, + 132, 1, 42, 48, 133, 9, 5, 85, 76, 76, 32, 66, 130, 1, 54, 48, 94, 49, + 102, 51, 102, 52, 102, 53, 215, 1, 50, 20, 146, 196, 24, 49, 242, 145, 4, + 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 22, 182, 195, 24, + 51, 242, 145, 4, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, + 57, 26, 210, 194, 24, 49, 2, 55, 2, 56, 242, 145, 4, 48, 2, 50, 2, 51, 2, + 52, 2, 53, 2, 54, 3, 57, 26, 238, 193, 24, 53, 2, 54, 2, 55, 242, 145, 4, + 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 56, 3, 57, 14, 222, 26, 49, 158, 184, + 28, 48, 2, 50, 3, 51, 128, 1, 62, 48, 98, 49, 102, 51, 102, 52, 210, 27, + 50, 223, 209, 8, 53, 24, 166, 50, 55, 242, 141, 24, 54, 242, 145, 4, 49, + 2, 50, 2, 51, 2, 52, 2, 53, 2, 56, 3, 57, 22, 182, 191, 24, 49, 242, 145, + 4, 48, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 24, 210, + 190, 24, 54, 2, 55, 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, + 2, 56, 3, 57, 24, 238, 189, 24, 51, 2, 53, 242, 145, 4, 48, 2, 49, 2, 50, + 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 24, 80, 2, 48, 48, 84, 4, 65, 76, 70, + 32, 161, 40, 7, 79, 82, 73, 90, 79, 78, 84, 18, 182, 188, 24, 54, 242, + 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 3, 56, 4, 22, 66, 255, 42, + 76, 2, 235, 253, 16, 76, 52, 58, 48, 181, 1, 9, 78, 83, 69, 82, 84, 32, + 65, 84, 32, 38, 18, 48, 95, 49, 22, 230, 186, 24, 53, 2, 57, 242, 145, 4, + 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 3, 56, 16, 138, 186, 24, 48, 2, + 49, 242, 145, 4, 50, 2, 51, 2, 52, 3, 53, 14, 68, 6, 66, 79, 84, 84, 79, + 77, 0, 3, 84, 79, 80, 243, 231, 19, 77, 7, 11, 32, 4, 206, 186, 27, 69, + 249, 8, 2, 83, 84, 22, 32, 2, 48, 48, 211, 235, 15, 79, 20, 166, 184, 24, + 50, 2, 54, 242, 145, 4, 49, 2, 51, 2, 52, 2, 53, 2, 55, 3, 56, 164, 1, + 118, 48, 128, 4, 15, 79, 68, 73, 70, 73, 69, 82, 32, 68, 65, 77, 65, 71, + 69, 68, 173, 130, 25, 5, 73, 82, 82, 79, 82, 132, 1, 42, 48, 98, 49, 106, + 50, 102, 51, 107, 52, 24, 182, 40, 49, 242, 141, 24, 51, 242, 145, 4, 50, + 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 44, 138, 41, 50, 190, 140, 24, + 48, 2, 53, 2, 54, 2, 55, 242, 145, 4, 49, 2, 51, 2, 52, 2, 56, 3, 57, 26, + 222, 180, 24, 50, 2, 52, 2, 56, 242, 145, 4, 48, 2, 49, 2, 51, 2, 53, 2, + 54, 2, 55, 3, 57, 26, 138, 38, 51, 242, 141, 24, 49, 242, 145, 4, 48, 2, + 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 12, 146, 179, 24, 48, 242, + 145, 4, 49, 2, 50, 2, 51, 3, 52, 31, 25, 4, 32, 65, 84, 32, 28, 96, 6, + 66, 79, 84, 84, 79, 77, 120, 5, 83, 84, 65, 82, 84, 68, 3, 84, 79, 80, + 251, 177, 27, 69, 11, 11, 32, 8, 56, 5, 83, 84, 65, 82, 84, 186, 1, 65, + 183, 177, 27, 69, 5, 129, 2, 8, 32, 65, 78, 68, 32, 84, 79, 80, 7, 29, 5, + 32, 65, 78, 68, 32, 4, 138, 211, 24, 66, 147, 246, 2, 84, 11, 11, 32, 8, + 54, 65, 20, 5, 83, 84, 65, 82, 84, 163, 177, 27, 69, 2, 73, 2, 78, 68, 5, + 53, 11, 32, 65, 78, 68, 32, 66, 79, 84, 84, 79, 77, 2, 151, 229, 19, 32, + 194, 1, 50, 48, 128, 2, 2, 76, 48, 229, 1, 2, 85, 48, 98, 58, 49, 98, 51, + 194, 14, 50, 150, 6, 52, 163, 234, 22, 48, 24, 146, 32, 56, 226, 159, 28, + 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 28, 162, 173, + 24, 51, 2, 52, 2, 53, 2, 55, 242, 145, 4, 48, 2, 49, 2, 50, 2, 54, 2, 56, + 3, 57, 44, 34, 48, 94, 49, 207, 150, 21, 50, 20, 154, 172, 24, 53, 242, + 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 22, 190, + 171, 24, 55, 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, + 2, 56, 3, 57, 52, 34, 49, 102, 50, 167, 251, 22, 48, 26, 182, 170, 24, + 48, 2, 49, 2, 56, 242, 145, 4, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, + 57, 8, 210, 169, 24, 50, 242, 145, 4, 48, 3, 49, 152, 1, 50, 48, 193, + 138, 19, 6, 86, 69, 82, 76, 65, 89, 150, 1, 66, 48, 154, 1, 49, 138, 1, + 50, 102, 51, 106, 53, 143, 248, 22, 52, 34, 90, 54, 206, 167, 24, 49, 2, + 53, 242, 145, 4, 50, 2, 51, 2, 52, 2, 55, 2, 56, 3, 57, 15, 186, 185, 28, + 65, 2, 66, 2, 67, 2, 68, 2, 69, 3, 70, 28, 98, 48, 174, 166, 24, 57, 242, + 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 9, 154, 184, + 28, 65, 2, 66, 3, 67, 28, 134, 166, 24, 48, 2, 52, 2, 53, 2, 57, 242, + 145, 4, 49, 2, 50, 2, 51, 2, 54, 2, 55, 3, 56, 32, 134, 23, 54, 158, 142, + 24, 48, 2, 51, 242, 145, 4, 49, 2, 50, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, + 8, 202, 22, 48, 227, 159, 28, 49, 26, 26, 48, 219, 202, 8, 49, 22, 254, + 163, 24, 49, 2, 51, 242, 145, 4, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, + 3, 57, 68, 34, 48, 98, 49, 243, 245, 22, 50, 24, 142, 21, 51, 242, 141, + 24, 50, 242, 145, 4, 49, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 24, + 158, 162, 24, 48, 2, 54, 242, 145, 4, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, + 55, 2, 56, 3, 57, 108, 50, 48, 94, 49, 106, 50, 98, 51, 219, 191, 19, 52, + 22, 134, 161, 24, 50, 2, 54, 242, 145, 4, 49, 2, 51, 2, 52, 2, 53, 2, 55, + 2, 56, 3, 57, 26, 186, 18, 52, 242, 141, 24, 55, 242, 145, 4, 48, 2, 49, + 2, 50, 2, 51, 2, 53, 2, 54, 2, 56, 3, 57, 24, 210, 17, 54, 226, 159, 28, + 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 22, 226, 158, + 24, 53, 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, + 3, 57, 90, 34, 48, 249, 12, 3, 65, 76, 76, 88, 42, 48, 94, 49, 102, 51, + 195, 239, 22, 50, 26, 174, 157, 24, 51, 2, 55, 2, 56, 2, 57, 242, 145, 4, + 49, 2, 50, 2, 52, 2, 53, 3, 54, 24, 210, 156, 24, 49, 2, 54, 242, 145, 4, + 48, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 18, 238, 155, 24, + 50, 2, 51, 242, 145, 4, 48, 2, 49, 2, 52, 2, 53, 3, 54, 94, 50, 48, 90, + 50, 102, 51, 102, 52, 163, 236, 22, 49, 22, 254, 12, 54, 226, 159, 28, + 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, 2, 56, 3, 57, 24, 150, 154, 24, + 51, 2, 57, 242, 145, 4, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 3, + 56, 22, 178, 153, 24, 50, 242, 145, 4, 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, + 54, 2, 55, 2, 56, 3, 57, 6, 190, 170, 28, 48, 2, 49, 3, 50, 158, 1, 42, + 48, 185, 4, 5, 69, 82, 84, 73, 67, 156, 1, 62, 48, 98, 49, 98, 50, 210, + 1, 51, 169, 148, 24, 2, 52, 48, 42, 198, 9, 55, 98, 49, 146, 141, 24, 50, + 242, 145, 4, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 32, 186, 8, 49, 46, + 50, 226, 159, 28, 48, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, + 50, 98, 48, 150, 149, 24, 51, 2, 56, 2, 57, 242, 145, 4, 49, 2, 50, 2, + 52, 2, 53, 2, 54, 3, 55, 27, 130, 167, 28, 65, 2, 66, 2, 67, 2, 68, 2, + 69, 2, 70, 2, 71, 2, 72, 2, 73, 2, 74, 2, 75, 3, 76, 28, 166, 148, 24, + 48, 2, 49, 2, 51, 2, 55, 242, 145, 4, 50, 2, 52, 2, 53, 2, 54, 2, 56, 3, + 57, 2, 181, 246, 23, 2, 65, 76, 66, 34, 48, 161, 2, 3, 73, 68, 69, 64, + 26, 48, 94, 49, 103, 50, 22, 230, 146, 24, 51, 2, 57, 242, 145, 4, 49, 2, + 50, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 28, 138, 146, 24, 48, 2, 52, 2, + 55, 2, 56, 242, 145, 4, 49, 2, 50, 2, 51, 2, 53, 2, 54, 3, 57, 14, 166, + 145, 24, 52, 242, 145, 4, 48, 2, 49, 2, 50, 2, 51, 3, 53, 2, 17, 2, 32, + 76, 2, 247, 195, 15, 79, 24, 202, 2, 52, 242, 141, 24, 54, 2, 56, 242, + 145, 4, 49, 2, 50, 2, 51, 2, 53, 3, 55, 18, 226, 143, 24, 49, 242, 145, + 4, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 82, 22, 48, 167, 1, 49, + 34, 90, 50, 46, 51, 242, 141, 24, 52, 2, 53, 242, 145, 4, 49, 2, 54, 2, + 55, 2, 56, 3, 57, 11, 138, 160, 28, 65, 2, 66, 2, 67, 3, 68, 7, 222, 159, + 28, 65, 3, 66, 48, 66, 53, 86, 54, 174, 158, 28, 48, 2, 49, 2, 50, 2, 51, + 3, 52, 21, 254, 158, 28, 65, 2, 66, 2, 67, 2, 68, 2, 69, 2, 70, 2, 71, 2, + 72, 3, 73, 19, 170, 158, 28, 65, 2, 66, 2, 67, 2, 68, 2, 69, 2, 70, 2, + 71, 3, 72, 182, 62, 22, 51, 211, 1, 52, 192, 46, 106, 52, 206, 195, 5, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, 68, 2, 69, 3, 70, - 192, 2, 214, 179, 13, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, - 68, 2, 69, 3, 70, 246, 15, 42, 51, 158, 187, 5, 48, 2, 49, 3, 50, 246, 3, - 142, 1, 70, 186, 177, 13, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, - 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, 68, 3, 69, 22, 250, 248, 27, + 192, 2, 218, 193, 13, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, + 68, 2, 69, 3, 70, 246, 15, 42, 51, 190, 194, 5, 48, 2, 49, 3, 50, 246, 3, + 142, 1, 70, 190, 191, 13, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, + 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, 68, 3, 69, 22, 174, 154, 28, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 3, 65, - 18, 26, 32, 239, 226, 15, 72, 16, 70, 80, 124, 5, 82, 65, 89, 83, 32, - 190, 146, 3, 84, 231, 207, 22, 83, 8, 186, 146, 3, 79, 241, 185, 16, 22, + 18, 26, 32, 235, 241, 15, 72, 16, 70, 80, 124, 5, 82, 65, 89, 83, 32, + 226, 152, 3, 84, 155, 231, 22, 83, 8, 222, 152, 3, 79, 233, 198, 16, 22, 69, 84, 65, 76, 76, 69, 68, 32, 79, 85, 84, 76, 73, 78, 69, 68, 32, 66, - 76, 65, 67, 75, 4, 228, 234, 18, 2, 73, 78, 1, 3, 79, 85, 84, 160, 1, + 76, 65, 67, 75, 4, 148, 254, 18, 2, 73, 78, 1, 3, 79, 85, 84, 160, 1, 132, 1, 13, 66, 65, 83, 65, 78, 32, 76, 69, 84, 84, 69, 82, 32, 166, 3, - 69, 176, 4, 7, 89, 77, 65, 73, 67, 32, 76, 171, 237, 27, 70, 80, 230, 1, - 71, 78, 76, 34, 78, 50, 82, 158, 232, 25, 69, 190, 137, 1, 67, 2, 68, 2, + 69, 176, 4, 7, 89, 77, 65, 73, 67, 32, 76, 223, 142, 28, 70, 80, 230, 1, + 71, 78, 76, 34, 78, 50, 82, 234, 134, 26, 69, 166, 140, 1, 67, 2, 68, 2, 75, 2, 83, 2, 84, 2, 90, 206, 105, 66, 2, 70, 2, 72, 2, 74, 2, 77, 2, 80, 2, 81, 2, 86, 2, 88, 214, 22, 65, 2, 73, 2, 79, 2, 85, 3, 89, 8, 38, 72, - 154, 220, 27, 74, 215, 22, 69, 4, 242, 160, 25, 65, 251, 209, 2, 69, 4, - 242, 219, 27, 76, 215, 22, 69, 8, 210, 219, 27, 68, 2, 74, 214, 22, 65, - 3, 69, 4, 162, 219, 27, 82, 215, 22, 69, 32, 96, 5, 67, 84, 82, 73, 67, - 160, 1, 7, 77, 69, 78, 84, 32, 79, 70, 238, 229, 26, 80, 235, 80, 86, 10, - 26, 32, 179, 130, 24, 65, 8, 98, 80, 144, 205, 17, 2, 84, 79, 128, 231, - 8, 9, 76, 73, 71, 72, 84, 32, 66, 85, 76, 171, 33, 65, 2, 11, 76, 2, 147, - 239, 27, 85, 19, 11, 32, 16, 72, 5, 87, 73, 84, 72, 32, 217, 207, 16, 7, + 206, 253, 27, 74, 215, 22, 69, 4, 214, 190, 25, 65, 203, 213, 2, 69, 4, + 166, 253, 27, 76, 215, 22, 69, 8, 134, 253, 27, 68, 2, 74, 214, 22, 65, + 3, 69, 4, 214, 252, 27, 82, 215, 22, 69, 32, 96, 5, 67, 84, 82, 73, 67, + 160, 1, 7, 77, 69, 78, 84, 32, 79, 70, 134, 133, 27, 80, 135, 83, 86, 10, + 26, 32, 155, 159, 24, 65, 8, 98, 80, 128, 221, 17, 2, 84, 79, 176, 246, + 8, 9, 76, 73, 71, 72, 84, 32, 66, 85, 76, 187, 33, 65, 2, 11, 76, 2, 199, + 144, 28, 85, 19, 11, 32, 16, 72, 5, 87, 73, 84, 72, 32, 177, 222, 16, 7, 79, 80, 69, 78, 73, 78, 71, 12, 130, 1, 76, 32, 12, 84, 87, 79, 32, 72, - 79, 82, 73, 90, 79, 78, 84, 142, 214, 19, 86, 194, 172, 4, 85, 234, 60, - 79, 219, 173, 2, 68, 2, 173, 201, 25, 3, 79, 78, 71, 2, 217, 213, 14, 7, - 65, 76, 32, 83, 84, 82, 79, 46, 254, 168, 4, 69, 129, 202, 15, 15, 73, + 79, 82, 73, 90, 79, 78, 84, 170, 233, 19, 86, 226, 182, 4, 85, 142, 61, + 79, 175, 177, 2, 68, 2, 141, 231, 25, 3, 79, 78, 71, 2, 197, 227, 14, 7, + 65, 76, 32, 83, 84, 82, 79, 46, 238, 175, 4, 69, 189, 214, 15, 15, 73, 71, 65, 84, 85, 82, 69, 32, 90, 65, 89, 73, 78, 45, 89, 53, 48, 4, 79, 74, 73, 32, 218, 2, 80, 163, 3, 32, 18, 164, 1, 10, 67, 79, 77, 80, 79, 78, 69, 78, 84, 32, 109, 26, 77, 79, 68, 73, 70, 73, 69, 82, 32, 70, 73, - 84, 90, 80, 65, 84, 82, 73, 67, 75, 32, 84, 89, 80, 69, 45, 8, 128, 255, - 14, 2, 82, 69, 12, 5, 67, 85, 82, 76, 89, 0, 5, 87, 72, 73, 84, 69, 213, - 205, 2, 2, 66, 65, 10, 208, 208, 20, 2, 49, 45, 174, 153, 7, 51, 2, 52, - 2, 53, 3, 54, 26, 44, 3, 84, 89, 32, 177, 244, 3, 2, 72, 65, 24, 82, 78, - 60, 3, 80, 65, 71, 20, 3, 83, 69, 84, 181, 164, 27, 4, 68, 79, 67, 85, 8, - 36, 3, 79, 84, 69, 151, 254, 23, 69, 7, 199, 152, 13, 32, 4, 139, 225, - 25, 69, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 130, 130, 14, 82, 24, 3, - 76, 69, 70, 212, 166, 1, 2, 83, 77, 179, 144, 9, 79, 38, 86, 32, 64, 2, - 68, 32, 214, 1, 81, 20, 6, 86, 69, 76, 79, 80, 69, 227, 220, 15, 84, 6, - 42, 81, 198, 253, 25, 68, 131, 170, 1, 83, 2, 195, 159, 27, 85, 20, 32, - 3, 79, 70, 32, 131, 1, 87, 18, 88, 3, 80, 82, 79, 242, 221, 20, 71, 56, - 2, 83, 69, 162, 71, 77, 30, 84, 195, 165, 5, 76, 4, 178, 222, 20, 84, - 135, 133, 6, 79, 2, 173, 239, 19, 7, 73, 84, 72, 32, 76, 69, 70, 5, 231, - 165, 21, 85, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 42, 76, 209, 233, 23, - 4, 68, 79, 87, 78, 2, 209, 203, 22, 4, 73, 71, 72, 84, 6, 254, 226, 27, - 76, 2, 77, 3, 84, 44, 28, 2, 65, 76, 231, 6, 73, 38, 30, 32, 133, 2, 2, - 83, 32, 12, 56, 3, 84, 79, 32, 177, 141, 13, 5, 65, 78, 68, 32, 80, 10, - 68, 3, 79, 82, 32, 221, 143, 27, 8, 66, 89, 32, 68, 69, 70, 73, 78, 8, - 64, 3, 80, 82, 69, 28, 3, 83, 85, 67, 162, 206, 25, 71, 39, 76, 2, 193, - 156, 15, 2, 67, 69, 2, 233, 128, 26, 3, 67, 69, 69, 26, 72, 4, 83, 73, - 71, 78, 224, 203, 25, 4, 87, 73, 84, 72, 235, 195, 1, 67, 23, 11, 32, 20, + 84, 90, 80, 65, 84, 82, 73, 67, 75, 32, 84, 89, 80, 69, 45, 8, 140, 141, + 15, 2, 82, 69, 12, 5, 67, 85, 82, 76, 89, 0, 5, 87, 72, 73, 84, 69, 185, + 207, 2, 2, 66, 65, 10, 240, 227, 20, 2, 49, 45, 194, 167, 7, 51, 2, 52, + 2, 53, 3, 54, 26, 44, 3, 84, 89, 32, 149, 251, 3, 2, 72, 65, 24, 82, 78, + 60, 3, 80, 65, 71, 20, 3, 83, 69, 84, 233, 197, 27, 4, 68, 79, 67, 85, 8, + 36, 3, 79, 84, 69, 211, 155, 24, 69, 7, 203, 166, 13, 32, 4, 215, 255, + 25, 69, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 138, 144, 14, 82, 24, 3, + 76, 69, 70, 224, 166, 1, 2, 83, 77, 255, 159, 9, 79, 38, 86, 32, 64, 2, + 68, 32, 214, 1, 81, 20, 6, 86, 69, 76, 79, 80, 69, 223, 235, 15, 84, 6, + 42, 81, 146, 156, 26, 68, 235, 172, 1, 83, 2, 247, 192, 27, 85, 20, 32, + 3, 79, 70, 32, 131, 1, 87, 18, 88, 3, 80, 82, 79, 150, 241, 20, 71, 56, + 2, 83, 69, 166, 71, 77, 30, 84, 203, 177, 5, 76, 4, 214, 241, 20, 84, + 151, 147, 6, 79, 2, 217, 130, 20, 7, 73, 84, 72, 32, 76, 69, 70, 5, 143, + 185, 21, 85, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 42, 76, 177, 134, 24, + 4, 68, 79, 87, 78, 2, 185, 228, 22, 4, 73, 71, 72, 84, 6, 178, 132, 28, + 76, 2, 77, 3, 84, 46, 28, 2, 65, 76, 231, 6, 73, 40, 30, 32, 133, 2, 2, + 83, 32, 12, 56, 3, 84, 79, 32, 181, 155, 13, 5, 65, 78, 68, 32, 80, 10, + 68, 3, 79, 82, 32, 145, 177, 27, 8, 66, 89, 32, 68, 69, 70, 73, 78, 8, + 64, 3, 80, 82, 69, 28, 3, 83, 85, 67, 250, 235, 25, 71, 39, 76, 2, 213, + 170, 15, 2, 67, 69, 2, 181, 159, 26, 3, 67, 69, 69, 28, 72, 4, 83, 73, + 71, 78, 184, 233, 25, 4, 87, 73, 84, 72, 199, 199, 1, 67, 25, 11, 32, 22, 42, 65, 201, 1, 5, 87, 73, 84, 72, 32, 12, 112, 5, 66, 79, 86, 69, 32, 65, 19, 78, 68, 32, 83, 76, 65, 78, 84, 69, 68, 32, 80, 65, 82, 65, 76, - 76, 69, 76, 8, 154, 132, 21, 80, 210, 5, 84, 182, 184, 2, 76, 139, 252, - 2, 82, 5, 243, 239, 6, 32, 8, 160, 1, 4, 66, 85, 77, 80, 20, 7, 73, 78, + 76, 69, 76, 8, 206, 151, 21, 80, 210, 5, 84, 146, 189, 2, 76, 171, 131, + 3, 82, 5, 187, 247, 6, 32, 10, 160, 1, 4, 66, 85, 77, 80, 20, 7, 73, 78, 70, 73, 78, 73, 84, 20, 18, 84, 87, 79, 32, 68, 79, 84, 83, 32, 65, 66, - 79, 86, 69, 32, 65, 78, 68, 215, 156, 15, 68, 2, 163, 223, 26, 89, 2, - 207, 174, 25, 89, 2, 17, 2, 32, 84, 2, 243, 173, 25, 87, 6, 80, 7, 86, - 65, 76, 69, 78, 84, 32, 237, 135, 21, 7, 65, 78, 71, 85, 76, 65, 82, 4, - 48, 6, 87, 73, 84, 72, 32, 70, 223, 187, 27, 84, 2, 11, 79, 2, 201, 242, + 79, 86, 69, 32, 65, 78, 68, 235, 170, 15, 68, 2, 215, 128, 27, 89, 4, + 179, 219, 25, 89, 2, 17, 2, 32, 84, 2, 211, 203, 25, 87, 6, 80, 7, 86, + 65, 76, 69, 78, 84, 32, 161, 155, 21, 7, 65, 78, 71, 85, 76, 65, 82, 4, + 48, 6, 87, 73, 84, 72, 32, 70, 147, 221, 27, 84, 2, 11, 79, 2, 237, 248, 2, 2, 85, 82, 20, 152, 1, 11, 82, 79, 82, 45, 66, 65, 82, 82, 69, 68, 32, - 152, 163, 5, 7, 73, 83, 32, 70, 79, 82, 77, 193, 195, 7, 9, 65, 83, 69, - 32, 84, 79, 32, 84, 72, 12, 160, 220, 5, 4, 87, 72, 73, 84, 13, 5, 66, - 76, 65, 67, 75, 10, 58, 67, 20, 6, 84, 73, 77, 65, 84, 69, 255, 215, 27, - 65, 5, 211, 144, 26, 65, 4, 210, 196, 26, 68, 171, 147, 1, 83, 154, 8, - 60, 7, 72, 73, 79, 80, 73, 67, 32, 150, 215, 27, 66, 3, 88, 150, 8, 204, + 184, 170, 5, 7, 73, 83, 32, 70, 79, 82, 77, 161, 202, 7, 9, 65, 83, 69, + 32, 84, 79, 32, 84, 72, 12, 216, 227, 5, 4, 87, 72, 73, 84, 13, 5, 66, + 76, 65, 67, 75, 10, 58, 67, 20, 6, 84, 73, 77, 65, 84, 69, 179, 249, 27, + 65, 5, 235, 175, 26, 65, 4, 234, 227, 26, 68, 199, 149, 1, 83, 154, 8, + 60, 7, 72, 73, 79, 80, 73, 67, 32, 202, 248, 27, 66, 3, 88, 150, 8, 204, 1, 2, 67, 79, 232, 1, 7, 78, 85, 77, 66, 69, 82, 32, 114, 80, 54, 83, - 156, 24, 11, 84, 79, 78, 65, 76, 32, 77, 65, 82, 75, 32, 226, 252, 18, - 68, 214, 235, 5, 70, 82, 81, 221, 146, 2, 4, 87, 79, 82, 68, 10, 26, 77, - 187, 133, 27, 76, 8, 52, 7, 66, 73, 78, 73, 78, 71, 32, 183, 210, 27, 77, + 156, 24, 11, 84, 79, 78, 65, 76, 32, 77, 65, 82, 75, 32, 254, 143, 19, + 68, 158, 246, 5, 70, 82, 81, 173, 150, 2, 4, 87, 79, 82, 68, 10, 26, 77, + 239, 166, 27, 76, 8, 52, 7, 66, 73, 78, 73, 78, 71, 32, 235, 243, 27, 77, 6, 60, 11, 71, 69, 77, 73, 78, 65, 84, 73, 79, 78, 32, 51, 86, 4, 44, 5, - 65, 78, 68, 32, 86, 211, 146, 27, 77, 2, 201, 246, 23, 4, 79, 87, 69, 76, - 22, 66, 84, 226, 255, 21, 72, 222, 228, 3, 69, 30, 70, 42, 78, 39, 83, 8, - 194, 199, 16, 69, 170, 158, 9, 72, 27, 87, 4, 166, 113, 65, 153, 145, 26, + 65, 78, 68, 32, 86, 135, 180, 27, 77, 2, 169, 148, 24, 4, 79, 87, 69, 76, + 22, 66, 84, 158, 152, 22, 72, 238, 234, 3, 69, 30, 70, 42, 78, 39, 83, 8, + 154, 214, 16, 69, 158, 174, 9, 72, 27, 87, 4, 202, 119, 65, 169, 172, 26, 5, 82, 69, 70, 65, 67, 198, 7, 50, 69, 37, 8, 89, 76, 76, 65, 66, 76, 69, - 32, 4, 202, 134, 24, 77, 139, 226, 2, 67, 194, 7, 210, 1, 66, 90, 67, + 32, 4, 170, 164, 24, 77, 223, 229, 2, 67, 194, 7, 210, 1, 66, 90, 67, 246, 1, 68, 186, 1, 70, 90, 71, 214, 2, 72, 162, 1, 75, 102, 77, 90, 78, 90, 80, 138, 2, 81, 174, 1, 82, 86, 83, 210, 1, 84, 122, 74, 2, 76, 138, 1, 87, 2, 89, 66, 88, 134, 1, 90, 95, 86, 38, 194, 12, 87, 230, 8, 66, - 214, 206, 21, 65, 2, 79, 230, 171, 5, 69, 162, 64, 73, 3, 85, 78, 94, 67, - 254, 15, 72, 202, 210, 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 186, - 2, 73, 3, 85, 42, 70, 72, 254, 225, 21, 65, 230, 171, 5, 69, 162, 64, 73, - 2, 79, 3, 85, 28, 166, 19, 72, 214, 206, 21, 65, 230, 171, 5, 69, 162, - 64, 73, 2, 79, 3, 85, 60, 94, 68, 214, 14, 90, 254, 209, 21, 65, 2, 79, - 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 3, 85, 30, 210, 14, 72, 254, - 209, 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 3, 85, 24, - 190, 8, 87, 186, 215, 21, 65, 230, 171, 5, 69, 234, 61, 89, 186, 2, 73, + 158, 202, 23, 65, 2, 79, 210, 209, 3, 69, 162, 64, 73, 3, 85, 78, 94, 67, + 254, 15, 72, 146, 206, 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 186, + 2, 73, 3, 85, 42, 70, 72, 198, 221, 23, 65, 210, 209, 3, 69, 162, 64, 73, + 2, 79, 3, 85, 28, 166, 19, 72, 158, 202, 23, 65, 210, 209, 3, 69, 162, + 64, 73, 2, 79, 3, 85, 60, 94, 68, 214, 14, 90, 198, 205, 23, 65, 2, 79, + 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 3, 85, 30, 210, 14, 72, 198, + 205, 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 3, 85, 24, + 190, 8, 87, 130, 211, 23, 65, 210, 209, 3, 69, 234, 61, 89, 186, 2, 73, 2, 79, 3, 85, 118, 142, 1, 85, 226, 7, 71, 232, 3, 7, 76, 79, 84, 84, 65, - 76, 32, 158, 2, 87, 218, 1, 89, 214, 206, 21, 65, 2, 79, 230, 171, 5, 69, + 76, 32, 158, 2, 87, 218, 1, 89, 158, 202, 23, 65, 2, 79, 210, 209, 3, 69, 163, 64, 73, 39, 29, 5, 82, 65, 71, 69, 32, 36, 74, 66, 2, 70, 2, 77, 2, - 80, 46, 71, 2, 75, 2, 81, 191, 130, 12, 72, 4, 11, 87, 4, 198, 178, 27, - 69, 215, 22, 73, 6, 11, 87, 6, 206, 136, 27, 69, 163, 64, 73, 52, 70, 72, - 134, 220, 21, 65, 2, 79, 230, 171, 5, 69, 162, 64, 73, 3, 85, 36, 202, 4, - 87, 230, 8, 89, 214, 206, 21, 65, 230, 171, 5, 69, 162, 64, 73, 2, 79, 3, - 85, 64, 250, 4, 88, 134, 6, 87, 218, 1, 89, 214, 206, 21, 65, 2, 79, 230, - 171, 5, 69, 162, 64, 73, 3, 85, 26, 142, 3, 87, 186, 215, 21, 65, 2, 79, - 230, 171, 5, 69, 234, 61, 89, 186, 2, 73, 3, 85, 36, 166, 7, 89, 202, - 210, 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 3, 85, 56, - 82, 72, 142, 1, 87, 186, 215, 21, 65, 2, 79, 230, 171, 5, 69, 162, 64, - 73, 3, 85, 32, 74, 65, 250, 215, 21, 79, 230, 171, 5, 69, 234, 61, 87, - 186, 2, 73, 3, 85, 19, 160, 9, 8, 82, 89, 78, 71, 69, 65, 76, 32, 219, - 186, 27, 65, 8, 154, 131, 27, 69, 162, 64, 65, 3, 73, 64, 94, 72, 134, 6, - 87, 218, 1, 89, 214, 206, 21, 65, 2, 79, 230, 171, 5, 69, 162, 64, 73, 3, - 85, 24, 130, 6, 87, 174, 208, 21, 65, 230, 171, 5, 69, 162, 64, 73, 2, - 79, 3, 85, 20, 226, 213, 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 2, - 89, 186, 2, 73, 3, 85, 74, 102, 69, 226, 1, 72, 170, 3, 90, 78, 83, 214, - 206, 21, 65, 2, 79, 206, 233, 5, 87, 186, 2, 73, 3, 85, 13, 56, 8, 66, - 65, 84, 66, 69, 73, 84, 32, 243, 191, 27, 69, 8, 230, 206, 22, 66, 2, 70, - 2, 77, 3, 80, 80, 118, 72, 76, 2, 84, 72, 62, 90, 162, 2, 83, 162, 207, - 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 3, 85, 18, 198, - 210, 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 3, 85, 12, - 222, 253, 26, 69, 234, 61, 65, 186, 2, 73, 2, 79, 3, 85, 16, 190, 209, - 21, 65, 2, 79, 230, 171, 5, 69, 162, 64, 73, 3, 85, 40, 82, 87, 218, 1, - 89, 214, 206, 21, 65, 2, 79, 230, 171, 5, 69, 162, 64, 73, 3, 85, 10, - 170, 208, 21, 65, 230, 171, 5, 69, 163, 64, 73, 48, 90, 72, 78, 90, 214, - 206, 21, 65, 2, 79, 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 3, 85, 16, - 158, 207, 21, 65, 230, 171, 5, 69, 234, 61, 87, 186, 2, 73, 2, 79, 3, 85, - 14, 210, 206, 21, 65, 230, 171, 5, 69, 162, 64, 73, 2, 79, 3, 85, 20, + 80, 46, 71, 2, 75, 2, 81, 195, 144, 12, 72, 4, 11, 87, 4, 250, 211, 27, + 69, 215, 22, 73, 6, 11, 87, 6, 130, 170, 27, 69, 163, 64, 73, 52, 70, 72, + 206, 215, 23, 65, 2, 79, 210, 209, 3, 69, 162, 64, 73, 3, 85, 36, 202, 4, + 87, 230, 8, 89, 158, 202, 23, 65, 210, 209, 3, 69, 162, 64, 73, 2, 79, 3, + 85, 64, 250, 4, 88, 134, 6, 87, 218, 1, 89, 158, 202, 23, 65, 2, 79, 210, + 209, 3, 69, 162, 64, 73, 3, 85, 26, 142, 3, 87, 130, 211, 23, 65, 2, 79, + 210, 209, 3, 69, 234, 61, 89, 186, 2, 73, 3, 85, 36, 166, 7, 89, 146, + 206, 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 3, 85, 56, + 82, 72, 142, 1, 87, 130, 211, 23, 65, 2, 79, 210, 209, 3, 69, 162, 64, + 73, 3, 85, 32, 74, 65, 194, 211, 23, 79, 210, 209, 3, 69, 234, 61, 87, + 186, 2, 73, 3, 85, 19, 160, 9, 8, 82, 89, 78, 71, 69, 65, 76, 32, 143, + 220, 27, 65, 8, 206, 164, 27, 69, 162, 64, 65, 3, 73, 64, 94, 72, 134, 6, + 87, 218, 1, 89, 158, 202, 23, 65, 2, 79, 210, 209, 3, 69, 162, 64, 73, 3, + 85, 24, 130, 6, 87, 246, 203, 23, 65, 210, 209, 3, 69, 162, 64, 73, 2, + 79, 3, 85, 20, 170, 209, 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 2, + 89, 186, 2, 73, 3, 85, 74, 102, 69, 226, 1, 72, 170, 3, 90, 78, 83, 158, + 202, 23, 65, 2, 79, 186, 143, 4, 87, 186, 2, 73, 3, 85, 13, 56, 8, 66, + 65, 84, 66, 69, 73, 84, 32, 167, 225, 27, 69, 8, 198, 231, 22, 66, 2, 70, + 2, 77, 3, 80, 80, 118, 72, 76, 2, 84, 72, 62, 90, 162, 2, 83, 234, 202, + 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 3, 85, 18, 142, + 206, 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 3, 85, 12, + 146, 159, 27, 69, 234, 61, 65, 186, 2, 73, 2, 79, 3, 85, 16, 134, 205, + 23, 65, 2, 79, 210, 209, 3, 69, 162, 64, 73, 3, 85, 40, 82, 87, 218, 1, + 89, 158, 202, 23, 65, 2, 79, 210, 209, 3, 69, 162, 64, 73, 3, 85, 10, + 242, 203, 23, 65, 210, 209, 3, 69, 163, 64, 73, 48, 90, 72, 78, 90, 158, + 202, 23, 65, 2, 79, 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 3, 85, 16, + 230, 202, 23, 65, 210, 209, 3, 69, 234, 61, 87, 186, 2, 73, 2, 79, 3, 85, + 14, 154, 202, 23, 65, 210, 209, 3, 69, 162, 64, 73, 2, 79, 3, 85, 20, 130, 1, 68, 74, 72, 30, 75, 42, 82, 0, 7, 83, 72, 79, 82, 84, 32, 82, - 204, 140, 4, 3, 67, 72, 73, 165, 246, 22, 3, 89, 73, 90, 6, 48, 4, 69, - 82, 69, 84, 249, 164, 26, 2, 73, 70, 5, 17, 2, 45, 72, 2, 177, 131, 27, - 2, 73, 68, 4, 196, 164, 26, 2, 69, 78, 219, 12, 85, 2, 245, 154, 4, 3, - 73, 75, 82, 10, 68, 2, 82, 79, 197, 173, 26, 9, 76, 69, 82, 32, 67, 79, - 78, 83, 84, 8, 92, 5, 80, 69, 65, 78, 32, 204, 131, 24, 8, 45, 67, 85, - 82, 82, 69, 78, 67, 131, 172, 2, 32, 4, 214, 135, 4, 67, 19, 80, 50, 30, - 67, 102, 80, 187, 1, 84, 6, 60, 9, 76, 65, 77, 65, 84, 73, 79, 78, 32, - 247, 158, 26, 69, 4, 174, 228, 24, 81, 235, 143, 2, 77, 10, 96, 7, 76, - 79, 83, 73, 79, 78, 32, 157, 247, 26, 11, 82, 69, 83, 83, 73, 79, 78, 76, - 69, 83, 83, 8, 232, 209, 11, 4, 70, 82, 65, 77, 229, 146, 15, 8, 65, 84, - 32, 72, 79, 82, 73, 90, 34, 98, 82, 153, 179, 21, 18, 69, 78, 68, 69, 68, - 32, 65, 82, 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, 14, 140, 1, 12, 69, - 77, 69, 76, 89, 32, 72, 69, 65, 86, 89, 32, 141, 222, 25, 16, 65, 84, 69, - 82, 82, 69, 83, 84, 82, 73, 65, 76, 32, 65, 76, 73, 12, 50, 83, 202, 155, - 25, 70, 234, 2, 87, 215, 10, 71, 4, 218, 156, 25, 65, 43, 73, 7, 250, - 167, 19, 71, 171, 137, 8, 83, 142, 4, 142, 1, 65, 130, 19, 69, 190, 1, - 73, 230, 7, 76, 242, 5, 79, 238, 6, 82, 234, 4, 85, 228, 183, 20, 2, 86, - 83, 202, 192, 4, 83, 223, 137, 2, 70, 92, 122, 67, 178, 15, 76, 176, 2, - 2, 88, 32, 238, 141, 3, 77, 172, 247, 5, 2, 82, 83, 188, 250, 1, 2, 84, - 72, 187, 230, 9, 73, 70, 72, 2, 69, 32, 248, 172, 16, 4, 83, 73, 77, 73, - 169, 202, 4, 2, 84, 79, 66, 226, 1, 83, 160, 1, 4, 87, 73, 84, 72, 224, - 250, 12, 2, 80, 65, 228, 136, 2, 2, 77, 65, 140, 145, 11, 13, 84, 72, 82, - 79, 87, 73, 78, 71, 32, 65, 32, 75, 73, 201, 1, 14, 72, 79, 76, 68, 73, - 78, 71, 32, 66, 65, 67, 75, 32, 84, 4, 232, 251, 16, 18, 65, 86, 79, 85, - 82, 73, 78, 71, 32, 68, 69, 76, 73, 67, 73, 79, 85, 83, 241, 128, 5, 13, - 67, 82, 69, 65, 77, 73, 78, 71, 32, 73, 78, 32, 70, 54, 38, 32, 201, 137, - 24, 3, 79, 85, 84, 52, 196, 4, 2, 67, 79, 44, 5, 72, 69, 65, 68, 45, 38, - 77, 98, 79, 92, 7, 78, 79, 32, 71, 79, 79, 68, 238, 1, 80, 164, 1, 16, - 83, 84, 85, 67, 75, 45, 79, 85, 84, 32, 84, 79, 78, 71, 85, 69, 110, 84, - 192, 177, 1, 9, 66, 65, 71, 83, 32, 85, 78, 68, 69, 224, 158, 17, 22, 70, - 73, 78, 71, 69, 82, 32, 67, 79, 86, 69, 82, 73, 78, 71, 32, 67, 76, 79, - 83, 69, 68, 244, 67, 3, 82, 79, 76, 252, 231, 1, 13, 76, 79, 79, 75, 32, - 79, 70, 32, 84, 82, 73, 85, 77, 232, 130, 3, 8, 68, 73, 65, 71, 79, 78, - 65, 76, 1, 20, 85, 78, 69, 86, 69, 78, 32, 69, 89, 69, 83, 32, 65, 78, - 68, 32, 87, 65, 86, 89, 4, 252, 4, 3, 87, 66, 79, 227, 148, 19, 76, 2, - 173, 159, 22, 4, 66, 65, 78, 68, 4, 60, 6, 69, 68, 73, 67, 65, 76, 189, - 211, 25, 3, 79, 78, 79, 2, 177, 224, 25, 3, 32, 77, 65, 12, 90, 75, 36, - 4, 80, 69, 78, 32, 205, 161, 20, 10, 78, 69, 32, 69, 89, 69, 66, 82, 79, - 87, 2, 165, 142, 22, 4, 32, 71, 69, 83, 8, 116, 5, 77, 79, 85, 84, 72, - 217, 129, 24, 18, 69, 89, 69, 83, 32, 65, 78, 68, 32, 72, 65, 78, 68, 32, - 79, 86, 69, 82, 7, 11, 32, 4, 136, 252, 9, 3, 86, 79, 77, 141, 154, 9, 5, - 65, 78, 68, 32, 67, 6, 132, 1, 18, 65, 82, 84, 89, 32, 72, 79, 82, 78, - 32, 65, 78, 68, 32, 80, 65, 82, 84, 100, 2, 69, 69, 197, 148, 19, 4, 76, - 69, 65, 68, 2, 161, 184, 22, 2, 89, 32, 7, 29, 5, 32, 65, 78, 68, 32, 4, - 36, 3, 87, 73, 78, 231, 148, 19, 84, 2, 157, 177, 1, 4, 75, 73, 78, 71, - 4, 50, 69, 225, 187, 22, 6, 72, 69, 82, 77, 79, 77, 2, 157, 142, 27, 8, - 65, 82, 83, 32, 79, 70, 32, 74, 10, 34, 76, 185, 146, 22, 2, 65, 70, 8, - 84, 13, 73, 78, 71, 32, 68, 73, 65, 71, 79, 78, 65, 76, 32, 189, 212, 23, - 2, 69, 78, 6, 128, 1, 9, 67, 82, 79, 83, 83, 73, 78, 71, 32, 185, 167, - 19, 16, 73, 78, 32, 87, 72, 73, 84, 69, 32, 67, 73, 82, 67, 76, 69, 32, - 4, 232, 133, 16, 3, 82, 73, 83, 143, 169, 3, 78, 4, 222, 244, 14, 73, - 255, 137, 4, 77, 14, 50, 65, 50, 77, 44, 2, 82, 82, 147, 217, 18, 78, 4, - 212, 161, 8, 3, 82, 70, 85, 147, 231, 9, 84, 4, 204, 233, 8, 2, 73, 78, - 143, 177, 7, 65, 4, 184, 238, 7, 2, 73, 83, 163, 173, 19, 89, 56, 156, 1, - 5, 71, 85, 82, 69, 32, 38, 76, 178, 1, 78, 98, 82, 182, 2, 83, 236, 13, - 4, 86, 69, 32, 68, 213, 249, 4, 10, 69, 76, 68, 32, 72, 79, 67, 75, 69, - 89, 4, 226, 177, 25, 68, 131, 170, 1, 83, 10, 32, 2, 69, 32, 65, 2, 77, - 32, 6, 166, 187, 13, 70, 136, 154, 2, 3, 67, 65, 66, 191, 150, 8, 83, 4, - 52, 4, 80, 82, 79, 74, 197, 142, 20, 3, 70, 82, 65, 2, 171, 203, 15, 69, - 4, 72, 4, 71, 69, 82, 80, 205, 144, 25, 8, 73, 84, 69, 32, 80, 65, 82, - 84, 2, 167, 255, 15, 82, 22, 34, 69, 189, 1, 3, 83, 84, 32, 13, 56, 2, - 32, 69, 68, 4, 87, 79, 82, 75, 171, 170, 15, 67, 4, 146, 179, 13, 78, - 153, 208, 4, 8, 88, 84, 73, 78, 71, 85, 73, 83, 4, 216, 172, 23, 6, 32, - 83, 80, 65, 82, 75, 223, 233, 3, 83, 10, 190, 170, 5, 81, 216, 176, 10, - 8, 83, 84, 82, 79, 78, 71, 32, 73, 239, 215, 6, 80, 10, 38, 72, 129, 200, - 23, 3, 84, 69, 68, 9, 168, 248, 3, 13, 73, 78, 71, 32, 80, 79, 76, 69, - 32, 65, 78, 68, 32, 246, 202, 5, 69, 237, 202, 16, 19, 32, 67, 65, 75, - 69, 32, 87, 73, 84, 72, 32, 83, 87, 73, 82, 76, 32, 68, 69, 42, 50, 65, - 170, 1, 69, 98, 79, 194, 1, 85, 39, 89, 12, 114, 84, 148, 157, 4, 5, 80, - 80, 73, 78, 71, 136, 158, 3, 6, 71, 32, 73, 78, 32, 72, 161, 202, 17, 3, - 77, 73, 78, 6, 198, 208, 8, 32, 250, 197, 11, 66, 139, 229, 5, 78, 4, - 160, 221, 23, 8, 88, 69, 68, 32, 66, 73, 67, 69, 153, 145, 1, 7, 85, 82, - 45, 68, 69, 45, 76, 10, 46, 82, 28, 3, 87, 69, 82, 167, 203, 25, 80, 2, - 161, 137, 26, 2, 65, 76, 7, 17, 2, 32, 80, 4, 58, 85, 169, 178, 24, 8, - 76, 65, 89, 73, 78, 71, 32, 67, 2, 189, 166, 26, 4, 78, 67, 84, 85, 4, - 162, 152, 3, 83, 219, 224, 23, 84, 13, 25, 4, 73, 78, 71, 32, 10, 64, 6, - 83, 65, 85, 67, 69, 82, 166, 130, 10, 68, 223, 130, 10, 69, 7, 29, 5, 32, - 87, 73, 84, 72, 4, 34, 32, 1, 4, 79, 85, 84, 32, 2, 21, 3, 66, 69, 65, 2, - 147, 208, 26, 77, 54, 102, 71, 20, 2, 76, 68, 68, 2, 79, 84, 22, 82, 238, - 1, 85, 148, 255, 22, 2, 78, 68, 235, 205, 3, 88, 5, 171, 251, 26, 71, 4, - 164, 192, 9, 8, 73, 78, 71, 32, 72, 65, 78, 68, 223, 147, 17, 69, 5, 139, - 148, 14, 80, 16, 102, 75, 158, 206, 20, 77, 186, 181, 4, 32, 214, 115, - 67, 201, 120, 9, 84, 85, 78, 69, 32, 67, 79, 79, 75, 8, 80, 10, 32, 65, - 78, 68, 32, 75, 78, 73, 70, 69, 162, 150, 15, 69, 183, 163, 11, 73, 5, - 249, 207, 15, 7, 32, 87, 73, 84, 72, 32, 80, 22, 26, 82, 255, 161, 23, - 78, 20, 38, 32, 218, 2, 84, 183, 221, 18, 45, 16, 110, 67, 174, 1, 68, - 134, 165, 2, 66, 248, 147, 10, 7, 76, 69, 65, 70, 32, 67, 76, 182, 111, - 84, 155, 200, 11, 80, 4, 128, 170, 13, 3, 76, 85, 66, 209, 86, 32, 79, - 82, 78, 69, 82, 32, 65, 82, 82, 79, 87, 83, 32, 67, 73, 82, 67, 76, 73, - 78, 71, 32, 65, 78, 84, 73, 67, 76, 79, 67, 75, 87, 4, 21, 3, 79, 84, 32, - 4, 138, 197, 23, 80, 239, 128, 3, 77, 2, 183, 38, 72, 28, 78, 65, 226, 1, - 69, 98, 79, 209, 241, 16, 8, 73, 69, 68, 32, 83, 72, 82, 73, 10, 72, 6, - 67, 84, 73, 79, 78, 32, 69, 8, 77, 69, 32, 87, 73, 84, 72, 32, 4, 146, - 239, 19, 83, 177, 6, 9, 78, 85, 77, 69, 82, 65, 84, 79, 82, 6, 50, 80, - 194, 165, 2, 65, 217, 161, 21, 2, 84, 73, 2, 221, 238, 21, 2, 73, 67, 6, - 48, 6, 78, 67, 72, 32, 70, 82, 235, 251, 18, 69, 4, 146, 240, 25, 73, - 249, 12, 3, 65, 78, 67, 10, 52, 3, 78, 84, 45, 116, 2, 87, 78, 151, 197, - 26, 71, 4, 70, 84, 173, 138, 2, 11, 70, 65, 67, 73, 78, 71, 32, 66, 65, - 66, 89, 2, 197, 178, 12, 6, 73, 76, 84, 69, 68, 32, 5, 149, 135, 8, 6, - 73, 78, 71, 32, 70, 65, 226, 1, 80, 2, 76, 76, 134, 6, 78, 156, 233, 16, - 5, 69, 76, 32, 80, 85, 191, 251, 9, 83, 216, 1, 42, 32, 73, 6, 87, 73, - 68, 84, 72, 32, 10, 246, 255, 11, 77, 252, 169, 3, 2, 79, 85, 210, 232, - 8, 66, 151, 29, 83, 206, 1, 242, 1, 67, 42, 76, 78, 78, 30, 80, 66, 82, - 142, 1, 83, 38, 89, 158, 146, 10, 77, 198, 208, 10, 65, 158, 2, 68, 58, - 69, 98, 71, 118, 72, 202, 4, 81, 190, 143, 2, 87, 218, 28, 84, 250, 145, - 1, 70, 148, 176, 1, 6, 66, 82, 79, 75, 69, 78, 211, 7, 86, 10, 214, 230, - 20, 73, 62, 79, 159, 75, 69, 116, 42, 69, 138, 234, 20, 65, 243, 171, 4, - 79, 10, 162, 1, 70, 251, 235, 20, 83, 4, 246, 186, 21, 79, 35, 85, 6, 42, - 79, 250, 236, 20, 69, 203, 225, 2, 76, 2, 159, 148, 25, 85, 10, 36, 3, - 73, 71, 72, 131, 231, 24, 69, 8, 17, 2, 84, 32, 8, 228, 162, 20, 5, 87, - 72, 73, 84, 69, 202, 211, 2, 67, 210, 3, 80, 239, 7, 83, 4, 166, 176, 23, - 69, 147, 184, 1, 79, 2, 159, 130, 25, 69, 6, 136, 192, 11, 8, 67, 84, 73, - 79, 78, 32, 65, 80, 176, 247, 8, 5, 69, 82, 65, 76, 32, 143, 183, 1, 78, - 226, 20, 114, 65, 250, 6, 69, 198, 17, 73, 162, 1, 76, 134, 15, 79, 194, - 6, 82, 178, 92, 85, 246, 131, 22, 72, 139, 234, 3, 83, 142, 1, 42, 82, - 237, 221, 26, 4, 77, 69, 32, 68, 140, 1, 36, 3, 65, 89, 32, 235, 208, 25, - 76, 138, 1, 166, 1, 67, 210, 1, 83, 192, 2, 6, 86, 79, 87, 69, 76, 32, - 132, 166, 8, 6, 82, 69, 68, 85, 80, 76, 202, 202, 10, 72, 230, 168, 1, - 80, 170, 171, 3, 77, 191, 189, 1, 68, 52, 42, 79, 205, 1, 5, 65, 80, 73, - 84, 65, 8, 88, 10, 77, 66, 73, 78, 73, 78, 71, 32, 68, 79, 37, 8, 78, 83, - 79, 78, 65, 78, 84, 32, 4, 246, 135, 12, 85, 195, 241, 13, 84, 4, 190, - 136, 12, 78, 203, 145, 11, 71, 46, 36, 3, 77, 65, 76, 215, 250, 21, 85, - 44, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, 32, 44, 200, 1, 4, 79, 76, 68, - 32, 174, 137, 20, 78, 238, 231, 6, 66, 2, 67, 2, 68, 2, 70, 2, 71, 2, 72, - 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, 88, 2, - 89, 187, 2, 65, 4, 150, 241, 26, 75, 3, 78, 12, 44, 5, 83, 73, 71, 78, - 32, 139, 177, 26, 76, 10, 226, 178, 26, 69, 162, 64, 65, 2, 73, 3, 79, - 242, 2, 112, 2, 65, 82, 110, 77, 50, 79, 204, 189, 23, 9, 82, 77, 65, 78, - 32, 80, 69, 78, 78, 218, 173, 2, 84, 239, 105, 78, 7, 29, 5, 32, 87, 73, - 84, 72, 4, 224, 147, 14, 5, 79, 85, 84, 32, 72, 149, 160, 9, 5, 32, 72, - 65, 78, 68, 4, 26, 32, 211, 244, 21, 73, 2, 251, 255, 22, 83, 226, 2, 64, - 6, 77, 69, 84, 82, 73, 67, 73, 6, 82, 71, 73, 65, 78, 32, 6, 236, 250, - 19, 4, 65, 76, 76, 89, 213, 222, 1, 5, 32, 80, 82, 79, 80, 220, 2, 228, - 1, 6, 67, 65, 80, 73, 84, 65, 0, 4, 83, 77, 65, 76, 172, 3, 7, 76, 69, - 84, 84, 69, 82, 32, 180, 2, 24, 77, 84, 65, 86, 82, 85, 76, 73, 32, 67, - 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 165, 6, 2, 80, - 65, 80, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, 32, 80, 142, 2, 65, 34, - 72, 166, 5, 67, 118, 71, 130, 1, 74, 34, 75, 82, 80, 34, 83, 94, 90, 220, - 180, 5, 2, 84, 65, 250, 142, 8, 76, 246, 179, 2, 82, 154, 160, 9, 66, 2, - 77, 2, 88, 202, 40, 78, 2, 81, 230, 33, 86, 234, 47, 68, 14, 69, 2, 73, - 2, 79, 2, 85, 2, 89, 143, 57, 87, 4, 162, 155, 26, 69, 227, 79, 78, 10, - 46, 65, 226, 211, 26, 73, 2, 79, 215, 22, 69, 4, 178, 234, 26, 69, 3, 82, - 94, 254, 1, 85, 178, 2, 65, 42, 67, 74, 69, 46, 71, 34, 72, 98, 74, 34, - 75, 34, 76, 50, 80, 34, 83, 34, 84, 62, 90, 202, 247, 15, 82, 154, 160, - 9, 66, 2, 77, 2, 88, 202, 40, 78, 2, 81, 230, 33, 86, 234, 47, 68, 14, - 73, 2, 79, 2, 89, 142, 57, 87, 255, 2, 70, 4, 204, 248, 21, 4, 45, 66, - 82, 74, 203, 239, 4, 78, 92, 250, 1, 65, 42, 67, 74, 69, 46, 71, 34, 72, - 98, 74, 34, 75, 34, 76, 50, 80, 34, 83, 34, 84, 62, 90, 202, 247, 15, 82, - 154, 160, 9, 66, 2, 77, 2, 88, 202, 40, 78, 2, 81, 230, 33, 86, 234, 47, - 68, 14, 73, 2, 79, 2, 85, 2, 89, 142, 57, 87, 255, 2, 70, 6, 134, 150, - 26, 69, 2, 73, 227, 79, 78, 8, 38, 72, 230, 219, 25, 73, 215, 57, 65, 4, - 182, 149, 26, 73, 135, 23, 65, 4, 224, 136, 9, 2, 76, 73, 151, 220, 17, - 78, 4, 202, 154, 25, 72, 163, 122, 65, 12, 46, 65, 170, 205, 26, 73, 2, - 79, 215, 22, 69, 6, 26, 82, 227, 227, 26, 69, 5, 223, 220, 25, 68, 4, - 202, 153, 25, 72, 207, 64, 73, 4, 242, 193, 25, 72, 219, 81, 65, 4, 11, - 65, 4, 146, 210, 15, 66, 239, 144, 11, 83, 4, 162, 193, 25, 72, 223, 104, - 65, 4, 230, 226, 25, 72, 247, 47, 65, 6, 196, 183, 3, 6, 85, 82, 78, 69, - 68, 32, 211, 253, 1, 65, 4, 166, 192, 25, 72, 219, 81, 69, 2, 177, 166, - 20, 7, 82, 65, 71, 82, 65, 80, 72, 10, 48, 2, 77, 69, 20, 4, 78, 71, 69, - 82, 31, 82, 2, 179, 205, 25, 76, 2, 141, 184, 18, 2, 32, 82, 6, 38, 76, - 173, 235, 13, 3, 65, 70, 70, 5, 219, 204, 25, 83, 202, 1, 66, 65, 214, - 13, 79, 169, 144, 26, 7, 69, 73, 67, 72, 32, 83, 84, 194, 1, 84, 8, 71, - 79, 76, 73, 84, 73, 67, 32, 229, 12, 8, 83, 83, 32, 79, 70, 32, 77, 73, - 192, 1, 56, 6, 67, 65, 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 96, 45, 9, - 76, 32, 76, 69, 84, 84, 69, 82, 32, 96, 206, 1, 65, 22, 66, 42, 67, 94, - 68, 94, 70, 38, 71, 46, 73, 138, 2, 76, 58, 77, 66, 78, 34, 79, 30, 80, - 58, 82, 30, 83, 186, 1, 84, 110, 86, 22, 89, 90, 90, 226, 132, 19, 72, - 174, 128, 2, 85, 147, 174, 5, 75, 2, 163, 183, 26, 90, 4, 214, 3, 73, - 217, 198, 26, 2, 85, 75, 4, 48, 8, 65, 85, 68, 65, 84, 69, 32, 67, 15, - 72, 2, 11, 72, 2, 217, 250, 19, 2, 82, 73, 6, 42, 74, 30, 79, 221, 183, - 26, 2, 90, 69, 2, 145, 250, 19, 2, 69, 82, 2, 147, 235, 24, 66, 4, 186, - 138, 21, 82, 147, 171, 5, 73, 2, 21, 3, 76, 65, 71, 2, 207, 222, 21, 79, - 13, 38, 78, 54, 79, 141, 1, 2, 90, 72, 2, 145, 172, 26, 8, 73, 84, 73, - 65, 76, 32, 73, 90, 4, 33, 6, 84, 65, 84, 69, 68, 32, 4, 26, 66, 25, 2, - 83, 77, 2, 11, 73, 2, 35, 71, 2, 21, 3, 65, 76, 76, 2, 253, 209, 24, 2, - 32, 89, 4, 142, 213, 26, 73, 211, 2, 69, 4, 52, 9, 65, 84, 73, 78, 65, - 84, 69, 32, 77, 35, 74, 2, 173, 133, 11, 3, 89, 83, 76, 2, 249, 140, 9, - 3, 85, 68, 73, 2, 11, 65, 2, 187, 135, 21, 83, 4, 190, 177, 26, 78, 3, - 84, 4, 26, 79, 243, 213, 26, 69, 2, 133, 191, 22, 2, 75, 79, 2, 177, 235, - 21, 2, 73, 84, 14, 106, 72, 58, 76, 172, 240, 13, 6, 80, 73, 68, 69, 82, - 89, 201, 175, 10, 8, 77, 65, 76, 76, 32, 89, 85, 83, 6, 32, 2, 84, 65, - 171, 212, 26, 65, 5, 159, 172, 25, 80, 2, 239, 246, 19, 79, 6, 78, 86, - 144, 147, 22, 9, 82, 79, 75, 85, 84, 65, 83, 84, 73, 203, 172, 4, 83, 2, - 129, 162, 19, 2, 82, 73, 2, 135, 195, 24, 69, 12, 50, 69, 214, 244, 18, - 65, 250, 221, 7, 79, 3, 85, 6, 250, 130, 21, 83, 155, 143, 5, 82, 4, 156, - 145, 9, 3, 69, 77, 76, 145, 250, 15, 4, 72, 73, 86, 69, 2, 207, 206, 26, - 76, 6, 228, 238, 11, 13, 66, 69, 32, 87, 73, 84, 72, 32, 77, 69, 82, 73, - 68, 250, 198, 4, 87, 255, 135, 9, 86, 68, 162, 1, 65, 44, 12, 84, 72, 73, - 67, 32, 76, 69, 84, 84, 69, 82, 32, 230, 161, 18, 82, 206, 102, 71, 172, - 131, 5, 3, 78, 71, 71, 182, 186, 1, 79, 161, 75, 2, 76, 70, 4, 144, 183, - 15, 2, 76, 32, 183, 152, 11, 84, 54, 206, 2, 65, 50, 72, 46, 73, 46, 78, - 46, 80, 2, 81, 40, 2, 82, 65, 22, 84, 200, 137, 9, 2, 87, 73, 230, 141, - 12, 85, 188, 69, 3, 70, 65, 73, 204, 7, 4, 66, 65, 73, 82, 128, 22, 2, - 79, 84, 150, 30, 68, 158, 123, 77, 164, 131, 1, 3, 83, 65, 85, 162, 16, - 69, 184, 29, 3, 76, 65, 71, 146, 200, 1, 74, 196, 16, 2, 71, 73, 141, 12, - 2, 75, 85, 4, 204, 198, 24, 3, 73, 72, 86, 187, 131, 2, 72, 4, 214, 224, - 13, 87, 145, 226, 11, 2, 65, 71, 4, 230, 138, 9, 85, 217, 229, 14, 2, 71, - 71, 6, 154, 206, 15, 73, 253, 252, 8, 2, 65, 85, 2, 213, 134, 26, 5, 65, - 73, 82, 84, 72, 2, 235, 165, 26, 73, 4, 192, 169, 23, 2, 72, 73, 233, 69, - 2, 69, 73, 234, 9, 46, 65, 198, 5, 69, 206, 82, 73, 151, 3, 79, 152, 1, - 96, 7, 68, 85, 65, 84, 73, 79, 78, 32, 5, 78, 84, 72, 65, 32, 242, 179, - 20, 86, 139, 129, 5, 80, 2, 11, 32, 2, 151, 184, 25, 67, 146, 1, 120, 7, - 76, 69, 84, 84, 69, 82, 32, 212, 2, 5, 83, 73, 71, 78, 32, 226, 231, 22, - 65, 248, 8, 2, 86, 79, 239, 195, 3, 79, 100, 214, 1, 86, 250, 235, 22, - 65, 38, 68, 114, 84, 230, 5, 85, 206, 201, 1, 73, 42, 76, 250, 192, 1, - 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 206, 40, 79, 162, - 8, 69, 158, 20, 72, 2, 77, 2, 82, 3, 89, 14, 60, 5, 69, 68, 73, 67, 32, - 210, 242, 22, 79, 139, 211, 3, 65, 4, 244, 143, 24, 6, 68, 79, 85, 66, - 76, 69, 235, 240, 1, 65, 16, 66, 67, 250, 176, 22, 78, 242, 60, 65, 182, - 1, 80, 179, 146, 3, 86, 4, 226, 238, 7, 79, 195, 193, 14, 65, 192, 8, 76, - 10, 65, 84, 69, 82, 45, 84, 72, 65, 78, 32, 206, 7, 69, 219, 180, 25, 89, - 56, 134, 1, 65, 150, 3, 66, 62, 79, 216, 2, 11, 69, 81, 85, 65, 76, 32, - 84, 79, 32, 79, 82, 222, 205, 6, 67, 138, 4, 87, 231, 227, 18, 83, 16, - 44, 5, 66, 79, 86, 69, 32, 187, 210, 6, 78, 12, 150, 1, 83, 180, 1, 19, - 68, 79, 85, 66, 76, 69, 45, 76, 73, 78, 69, 32, 69, 81, 85, 65, 76, 32, - 65, 224, 204, 6, 4, 76, 69, 83, 83, 135, 211, 18, 82, 6, 148, 1, 7, 73, - 77, 73, 76, 65, 82, 32, 225, 207, 6, 23, 76, 65, 78, 84, 69, 68, 32, 69, - 81, 85, 65, 76, 32, 65, 66, 79, 86, 69, 32, 76, 69, 83, 83, 4, 26, 65, - 183, 207, 6, 79, 2, 65, 3, 66, 79, 86, 6, 40, 4, 69, 83, 73, 68, 159, - 208, 6, 85, 2, 231, 2, 69, 20, 40, 2, 82, 32, 245, 1, 3, 86, 69, 82, 16, - 120, 16, 83, 76, 65, 78, 84, 69, 68, 32, 69, 81, 85, 65, 76, 32, 84, 79, - 230, 209, 6, 65, 138, 247, 12, 69, 131, 227, 4, 76, 9, 49, 10, 32, 87, - 73, 84, 72, 32, 68, 79, 84, 32, 6, 44, 5, 65, 66, 79, 86, 69, 163, 153, - 18, 73, 5, 195, 138, 26, 32, 4, 52, 7, 76, 65, 80, 80, 73, 78, 71, 227, - 232, 19, 32, 2, 185, 170, 24, 2, 32, 76, 134, 8, 36, 2, 75, 32, 185, 73, - 2, 78, 32, 254, 7, 130, 3, 65, 216, 15, 8, 67, 65, 80, 73, 84, 65, 76, - 32, 182, 11, 68, 134, 1, 70, 68, 2, 73, 78, 222, 3, 75, 138, 1, 76, 174, - 3, 78, 66, 77, 84, 3, 88, 69, 83, 22, 79, 202, 1, 80, 90, 82, 182, 1, 83, - 130, 22, 84, 200, 2, 13, 85, 80, 83, 73, 76, 79, 78, 32, 87, 73, 84, 72, - 32, 150, 1, 86, 142, 2, 89, 178, 225, 7, 66, 248, 175, 3, 4, 71, 82, 65, - 77, 204, 23, 2, 90, 69, 147, 249, 11, 81, 112, 92, 10, 67, 82, 79, 80, - 72, 79, 78, 73, 67, 32, 172, 14, 6, 78, 79, 32, 84, 69, 76, 23, 82, 106, - 188, 2, 6, 65, 84, 84, 73, 67, 32, 222, 5, 67, 92, 3, 78, 65, 88, 32, 12, - 68, 69, 76, 80, 72, 73, 67, 32, 70, 73, 86, 69, 0, 14, 83, 84, 82, 65, - 84, 73, 65, 78, 32, 70, 73, 70, 84, 89, 40, 11, 69, 80, 73, 68, 65, 85, - 82, 69, 65, 78, 32, 112, 3, 72, 69, 82, 164, 1, 9, 77, 69, 83, 83, 69, - 78, 73, 65, 78, 35, 84, 48, 72, 2, 70, 73, 180, 2, 4, 79, 78, 69, 32, - 205, 1, 4, 84, 69, 78, 32, 26, 36, 3, 70, 84, 89, 105, 2, 86, 69, 11, 11, - 32, 8, 22, 84, 171, 4, 83, 6, 48, 7, 72, 79, 85, 83, 65, 78, 68, 215, 3, - 65, 5, 231, 3, 32, 17, 11, 32, 14, 56, 7, 72, 85, 78, 68, 82, 69, 68, 18, - 84, 143, 3, 83, 7, 131, 2, 32, 6, 48, 7, 72, 79, 85, 83, 65, 78, 68, 187, - 2, 65, 5, 213, 1, 2, 32, 84, 14, 98, 72, 48, 7, 84, 72, 79, 85, 83, 65, - 78, 174, 174, 24, 81, 241, 225, 1, 5, 68, 82, 65, 67, 72, 6, 44, 5, 85, - 78, 68, 82, 69, 143, 174, 24, 65, 4, 17, 2, 68, 32, 4, 22, 84, 131, 1, - 83, 2, 95, 65, 8, 30, 84, 86, 83, 175, 1, 77, 4, 50, 65, 21, 8, 72, 79, - 85, 83, 65, 78, 68, 32, 2, 187, 174, 16, 76, 2, 11, 83, 2, 145, 175, 24, - 2, 84, 65, 4, 88, 5, 65, 82, 89, 83, 84, 145, 1, 12, 89, 82, 69, 78, 65, - 73, 67, 32, 84, 87, 79, 32, 2, 101, 5, 73, 65, 78, 32, 70, 2, 17, 2, 32, - 77, 2, 199, 144, 13, 78, 6, 30, 70, 29, 3, 84, 87, 79, 2, 177, 178, 15, - 2, 73, 86, 5, 11, 32, 2, 233, 144, 10, 5, 68, 82, 65, 67, 72, 8, 112, 8, - 77, 73, 79, 78, 73, 65, 78, 32, 189, 135, 25, 14, 65, 69, 85, 77, 32, 79, - 78, 69, 32, 80, 76, 69, 84, 72, 6, 238, 185, 12, 70, 134, 159, 12, 84, - 191, 58, 79, 2, 11, 32, 2, 183, 216, 24, 84, 32, 92, 8, 72, 69, 83, 80, - 73, 65, 78, 32, 129, 1, 10, 82, 79, 69, 90, 69, 78, 73, 65, 78, 32, 20, - 40, 2, 70, 73, 38, 84, 135, 151, 18, 79, 6, 162, 215, 20, 86, 231, 230, - 3, 70, 8, 202, 174, 15, 72, 178, 172, 10, 69, 239, 48, 87, 12, 36, 2, 70, - 73, 209, 24, 2, 84, 69, 8, 142, 176, 18, 86, 205, 250, 6, 3, 70, 84, 89, - 2, 159, 132, 10, 69, 4, 240, 215, 22, 2, 79, 85, 161, 181, 1, 3, 84, 65, - 66, 154, 2, 66, 76, 174, 45, 82, 66, 68, 220, 226, 7, 2, 75, 65, 135, 6, - 84, 144, 2, 44, 6, 69, 84, 84, 69, 82, 32, 239, 45, 85, 142, 2, 198, 2, - 65, 190, 1, 69, 28, 4, 73, 79, 84, 65, 128, 1, 2, 79, 77, 156, 3, 3, 82, - 72, 79, 46, 83, 48, 7, 85, 80, 83, 73, 76, 79, 78, 146, 33, 80, 170, 2, - 84, 202, 183, 5, 68, 144, 176, 2, 2, 75, 65, 166, 192, 1, 71, 190, 132, - 11, 67, 194, 149, 2, 66, 2, 72, 2, 90, 166, 1, 76, 230, 231, 2, 89, 210, - 43, 77, 2, 78, 147, 17, 88, 48, 68, 4, 76, 80, 72, 65, 213, 28, 8, 82, - 67, 72, 65, 73, 67, 32, 83, 47, 33, 6, 32, 87, 73, 84, 72, 32, 44, 242, - 2, 68, 30, 80, 226, 29, 86, 226, 5, 79, 246, 236, 3, 84, 239, 167, 5, 77, - 62, 186, 1, 84, 131, 27, 80, 31, 33, 6, 32, 87, 73, 84, 72, 32, 28, 186, - 5, 68, 136, 25, 2, 80, 83, 158, 1, 86, 226, 5, 79, 246, 236, 3, 84, 239, - 167, 5, 77, 62, 28, 2, 69, 71, 235, 34, 73, 42, 11, 65, 43, 33, 6, 32, - 87, 73, 84, 72, 32, 40, 54, 68, 30, 80, 194, 35, 79, 22, 86, 227, 236, 3, - 84, 16, 65, 4, 65, 83, 73, 65, 18, 36, 4, 83, 73, 76, 73, 211, 16, 82, - 17, 29, 5, 32, 65, 78, 68, 32, 14, 44, 2, 79, 88, 0, 3, 86, 65, 82, 23, - 80, 4, 81, 2, 73, 65, 6, 60, 10, 69, 82, 73, 83, 80, 79, 77, 69, 78, 73, - 175, 15, 82, 5, 169, 15, 7, 32, 65, 78, 68, 32, 80, 82, 5, 161, 35, 7, - 32, 87, 73, 84, 72, 32, 68, 6, 222, 140, 8, 73, 226, 194, 17, 65, 239, - 48, 72, 23, 33, 6, 32, 87, 73, 84, 72, 32, 20, 66, 68, 166, 26, 86, 226, - 5, 79, 246, 236, 3, 84, 239, 167, 5, 77, 10, 130, 24, 65, 181, 176, 22, - 5, 73, 65, 76, 89, 84, 18, 76, 9, 73, 65, 76, 89, 84, 73, 75, 65, 32, 32, - 3, 82, 65, 67, 227, 22, 65, 8, 174, 24, 65, 199, 243, 3, 84, 2, 243, 186, - 11, 72, 4, 40, 3, 73, 86, 69, 1, 3, 79, 85, 82, 2, 205, 37, 2, 32, 79, - 76, 144, 1, 27, 83, 84, 82, 85, 77, 69, 78, 84, 65, 76, 32, 78, 79, 84, - 65, 84, 73, 79, 78, 32, 83, 89, 77, 66, 79, 76, 45, 161, 154, 22, 2, 68, - 73, 74, 70, 49, 70, 50, 62, 51, 62, 52, 170, 37, 53, 206, 243, 25, 55, 3, - 56, 17, 174, 154, 26, 49, 2, 50, 2, 51, 2, 52, 2, 55, 2, 56, 3, 57, 15, - 234, 153, 26, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 12, 174, 153, 26, - 48, 2, 50, 2, 54, 2, 55, 2, 56, 3, 57, 17, 242, 152, 26, 48, 2, 50, 2, - 51, 2, 53, 2, 55, 2, 56, 3, 57, 8, 54, 65, 38, 79, 169, 32, 6, 89, 65, - 84, 72, 79, 83, 4, 134, 255, 7, 80, 203, 133, 17, 73, 2, 11, 82, 2, 11, - 79, 2, 135, 244, 23, 78, 32, 128, 1, 6, 69, 84, 84, 69, 82, 32, 168, 2, - 6, 79, 87, 69, 82, 32, 78, 32, 6, 85, 78, 65, 84, 69, 32, 145, 194, 22, - 2, 73, 84, 24, 94, 83, 140, 13, 9, 65, 82, 67, 72, 65, 73, 67, 32, 75, 2, - 75, 182, 11, 68, 207, 172, 25, 89, 16, 88, 13, 77, 65, 76, 76, 32, 67, - 65, 80, 73, 84, 65, 76, 32, 210, 12, 65, 247, 243, 7, 84, 12, 74, 80, - 226, 192, 9, 71, 194, 156, 9, 79, 218, 206, 2, 82, 139, 176, 1, 76, 4, - 194, 128, 26, 83, 219, 19, 73, 2, 221, 134, 10, 3, 85, 77, 69, 4, 222, - 25, 83, 215, 224, 7, 69, 4, 80, 4, 69, 84, 82, 69, 241, 192, 23, 10, 85, - 83, 73, 67, 65, 76, 32, 76, 69, 73, 2, 163, 212, 2, 84, 12, 88, 3, 78, - 69, 32, 198, 236, 9, 88, 148, 155, 5, 3, 85, 78, 75, 253, 198, 5, 2, 66, - 79, 6, 64, 8, 72, 65, 76, 70, 32, 83, 73, 71, 21, 4, 81, 85, 65, 82, 4, - 139, 146, 25, 78, 2, 255, 206, 20, 84, 16, 62, 82, 206, 11, 83, 114, 69, - 154, 236, 7, 72, 211, 132, 17, 73, 2, 217, 29, 2, 79, 83, 6, 100, 3, 72, - 79, 32, 165, 246, 7, 16, 69, 86, 69, 82, 83, 69, 68, 32, 76, 85, 78, 65, - 84, 69, 32, 69, 4, 180, 243, 13, 10, 87, 73, 84, 72, 32, 83, 84, 82, 79, - 75, 135, 137, 11, 83, 226, 2, 220, 1, 5, 77, 65, 76, 76, 32, 192, 19, 22, - 85, 66, 83, 67, 82, 73, 80, 84, 32, 83, 77, 65, 76, 76, 32, 76, 69, 84, - 84, 69, 82, 32, 72, 10, 89, 77, 66, 79, 76, 32, 84, 65, 85, 32, 189, 144, - 24, 6, 73, 78, 85, 83, 79, 73, 212, 2, 56, 7, 76, 69, 84, 84, 69, 82, 32, - 202, 17, 82, 67, 68, 206, 2, 178, 2, 65, 162, 2, 68, 38, 69, 52, 4, 73, - 79, 84, 65, 0, 7, 85, 80, 83, 73, 76, 79, 78, 254, 3, 75, 28, 2, 79, 77, - 182, 5, 80, 112, 3, 82, 72, 79, 94, 83, 94, 84, 244, 230, 7, 2, 70, 73, - 138, 193, 1, 71, 190, 132, 11, 67, 194, 149, 2, 66, 2, 72, 2, 90, 166, 1, - 76, 182, 147, 3, 77, 2, 78, 147, 17, 88, 58, 64, 4, 76, 80, 72, 65, 149, - 1, 7, 82, 67, 72, 65, 73, 67, 32, 55, 33, 6, 32, 87, 73, 84, 72, 32, 52, - 82, 86, 226, 6, 68, 30, 80, 114, 79, 142, 1, 89, 226, 238, 3, 84, 239, - 167, 5, 77, 6, 154, 5, 82, 155, 3, 65, 4, 18, 75, 23, 83, 2, 215, 244, 7, - 79, 2, 11, 65, 2, 203, 189, 13, 77, 4, 138, 223, 7, 73, 235, 239, 14, 69, - 70, 22, 80, 215, 4, 84, 20, 249, 7, 3, 83, 73, 76, 41, 33, 6, 32, 87, 73, - 84, 72, 32, 38, 78, 68, 166, 1, 80, 178, 1, 86, 226, 5, 79, 246, 236, 3, - 84, 239, 167, 5, 77, 18, 50, 65, 29, 8, 73, 65, 76, 89, 84, 73, 75, 65, - 8, 153, 1, 3, 83, 73, 65, 11, 29, 5, 32, 65, 78, 68, 32, 8, 170, 1, 80, - 154, 6, 79, 22, 86, 227, 236, 3, 84, 10, 18, 83, 115, 69, 8, 21, 3, 73, - 76, 73, 9, 17, 2, 32, 65, 6, 21, 3, 78, 68, 32, 6, 30, 80, 154, 6, 79, - 23, 86, 2, 11, 69, 2, 11, 82, 2, 181, 17, 4, 73, 83, 80, 79, 4, 22, 82, - 147, 15, 65, 2, 133, 226, 25, 2, 65, 67, 4, 206, 239, 7, 65, 3, 79, 70, - 28, 2, 69, 71, 151, 3, 73, 50, 11, 65, 51, 33, 6, 32, 87, 73, 84, 72, 32, - 48, 58, 68, 30, 80, 114, 79, 62, 86, 82, 89, 227, 238, 3, 84, 16, 61, 4, - 65, 83, 73, 65, 20, 32, 4, 83, 73, 76, 73, 91, 69, 17, 29, 5, 32, 65, 78, - 68, 32, 14, 42, 79, 12, 2, 80, 69, 50, 86, 83, 89, 4, 83, 88, 4, 89, 9, - 82, 73, 83, 80, 79, 77, 69, 78, 73, 4, 11, 65, 4, 11, 82, 4, 17, 2, 73, - 65, 5, 33, 6, 32, 65, 78, 68, 32, 89, 2, 243, 12, 80, 20, 17, 2, 67, 82, - 20, 17, 2, 79, 78, 21, 33, 6, 32, 87, 73, 84, 72, 32, 18, 88, 5, 68, 65, - 83, 73, 65, 0, 5, 80, 83, 73, 76, 73, 54, 79, 22, 86, 227, 236, 3, 84, 7, - 29, 5, 32, 65, 78, 68, 32, 4, 18, 79, 23, 86, 2, 207, 216, 9, 88, 2, 179, - 9, 65, 8, 88, 11, 65, 77, 80, 72, 89, 76, 73, 65, 78, 32, 68, 174, 233, - 25, 72, 2, 83, 219, 19, 73, 2, 139, 212, 7, 73, 7, 33, 6, 32, 87, 73, 84, - 72, 32, 4, 34, 68, 145, 129, 21, 2, 80, 83, 2, 243, 197, 8, 65, 10, 54, - 65, 186, 231, 7, 84, 230, 1, 73, 207, 243, 17, 72, 4, 142, 177, 13, 77, - 207, 202, 12, 78, 4, 246, 193, 22, 72, 219, 148, 3, 65, 4, 41, 8, 69, 86, - 69, 82, 83, 69, 68, 32, 4, 18, 68, 43, 76, 2, 37, 7, 79, 84, 84, 69, 68, - 32, 76, 2, 11, 85, 2, 33, 6, 78, 65, 84, 69, 32, 83, 2, 169, 232, 7, 3, - 73, 71, 77, 10, 158, 166, 9, 71, 190, 132, 11, 67, 2, 80, 222, 102, 82, - 231, 174, 1, 66, 2, 239, 144, 21, 82, 16, 106, 72, 104, 7, 82, 89, 66, - 76, 73, 79, 78, 44, 3, 87, 79, 32, 254, 229, 3, 79, 233, 196, 16, 2, 65, - 76, 6, 40, 4, 82, 69, 69, 32, 143, 230, 7, 69, 4, 146, 1, 79, 157, 200, - 22, 7, 81, 85, 65, 82, 84, 69, 82, 2, 21, 3, 32, 66, 65, 2, 231, 218, 23, - 83, 4, 42, 79, 221, 152, 12, 4, 84, 72, 73, 82, 2, 237, 224, 19, 2, 66, - 79, 6, 80, 5, 65, 67, 85, 84, 69, 0, 9, 68, 73, 65, 69, 82, 69, 83, 73, - 83, 39, 72, 2, 33, 6, 32, 65, 78, 68, 32, 72, 2, 197, 195, 7, 2, 79, 79, - 60, 102, 65, 21, 21, 79, 67, 65, 76, 32, 78, 79, 84, 65, 84, 73, 79, 78, - 32, 83, 89, 77, 66, 79, 76, 45, 2, 135, 207, 9, 82, 58, 90, 50, 2, 53, - 154, 179, 23, 49, 182, 192, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 13, - 202, 243, 25, 48, 2, 49, 2, 50, 2, 51, 3, 52, 4, 26, 80, 207, 177, 20, - 69, 2, 11, 79, 2, 33, 6, 71, 69, 71, 82, 65, 77, 2, 197, 246, 20, 2, 77, - 69, 8, 170, 237, 13, 65, 178, 177, 10, 66, 174, 76, 72, 253, 64, 3, 83, - 65, 76, 12, 60, 6, 78, 78, 73, 78, 71, 32, 137, 233, 24, 3, 77, 65, 67, - 10, 100, 4, 70, 65, 67, 69, 149, 228, 17, 15, 67, 65, 84, 32, 70, 65, 67, - 69, 32, 87, 73, 84, 72, 32, 83, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 108, - 23, 79, 78, 69, 32, 76, 65, 82, 71, 69, 32, 65, 78, 68, 32, 79, 78, 69, - 32, 83, 77, 65, 76, 76, 35, 83, 2, 11, 32, 2, 191, 157, 8, 69, 4, 32, 2, - 84, 65, 203, 226, 17, 77, 2, 187, 243, 22, 82, 6, 28, 3, 85, 80, 32, 39, - 87, 4, 214, 192, 22, 83, 179, 236, 2, 77, 2, 227, 144, 18, 73, 220, 4, - 136, 1, 2, 65, 82, 70, 73, 52, 7, 74, 65, 82, 65, 84, 73, 32, 208, 6, 12, - 78, 74, 65, 76, 65, 32, 71, 79, 78, 68, 73, 32, 143, 3, 82, 4, 34, 65, - 245, 246, 20, 2, 68, 83, 2, 11, 78, 2, 187, 229, 24, 73, 4, 238, 202, 24, - 84, 217, 160, 1, 4, 68, 69, 32, 68, 182, 1, 168, 1, 7, 76, 69, 84, 84, - 69, 82, 32, 220, 1, 5, 83, 73, 71, 78, 32, 160, 2, 6, 86, 79, 87, 69, 76, - 32, 238, 251, 19, 65, 154, 24, 82, 166, 225, 3, 68, 203, 224, 1, 79, 98, - 162, 144, 22, 65, 38, 68, 114, 84, 46, 86, 186, 5, 85, 206, 201, 1, 73, - 42, 76, 246, 14, 90, 134, 178, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, - 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 82, 2, 89, 186, 2, 69, 3, 79, - 24, 98, 67, 28, 3, 77, 65, 68, 22, 84, 138, 202, 3, 83, 238, 137, 18, 78, - 242, 60, 65, 231, 147, 3, 86, 4, 118, 73, 219, 210, 21, 65, 2, 231, 135, - 19, 68, 4, 68, 5, 87, 79, 45, 67, 73, 29, 8, 72, 82, 69, 69, 45, 68, 79, - 84, 2, 25, 4, 82, 67, 76, 69, 2, 253, 195, 20, 5, 32, 78, 85, 75, 84, 34, - 36, 5, 83, 73, 71, 78, 32, 87, 67, 30, 82, 67, 130, 146, 22, 65, 38, 85, - 22, 86, 186, 201, 1, 73, 222, 137, 2, 69, 3, 79, 4, 245, 210, 21, 5, 65, - 78, 68, 82, 65, 126, 108, 7, 76, 69, 84, 84, 69, 82, 32, 216, 1, 5, 83, - 73, 71, 78, 32, 38, 86, 154, 241, 23, 68, 203, 224, 1, 79, 80, 130, 243, - 21, 78, 146, 23, 65, 38, 68, 114, 84, 230, 5, 85, 206, 201, 1, 73, 42, - 76, 246, 193, 1, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 206, 40, 79, 162, - 8, 69, 158, 20, 72, 2, 77, 2, 82, 2, 83, 2, 86, 3, 89, 4, 178, 172, 23, - 86, 179, 241, 1, 65, 20, 190, 7, 79, 163, 162, 23, 73, 160, 2, 84, 6, 77, - 85, 75, 72, 73, 32, 189, 7, 10, 85, 78, 71, 32, 75, 72, 69, 77, 65, 32, - 172, 1, 194, 1, 65, 44, 7, 76, 69, 84, 84, 69, 82, 32, 238, 1, 83, 228, - 2, 2, 86, 79, 172, 144, 13, 3, 84, 73, 80, 130, 237, 5, 73, 216, 170, 2, - 5, 69, 75, 32, 79, 78, 214, 193, 2, 68, 227, 172, 1, 85, 4, 218, 200, 21, - 66, 213, 225, 1, 2, 68, 68, 96, 162, 194, 8, 71, 2, 75, 134, 195, 13, 65, - 38, 68, 82, 82, 34, 84, 230, 5, 85, 206, 201, 1, 73, 42, 76, 250, 192, 1, - 78, 126, 66, 2, 67, 2, 74, 2, 80, 2, 83, 206, 40, 79, 162, 8, 69, 158, - 20, 70, 2, 72, 2, 77, 2, 86, 2, 89, 3, 90, 26, 108, 19, 69, 81, 85, 69, - 78, 67, 69, 32, 70, 79, 82, 32, 76, 69, 84, 84, 69, 82, 32, 93, 4, 73, - 71, 78, 32, 12, 70, 71, 2, 75, 230, 225, 23, 83, 170, 216, 1, 76, 226, - 31, 70, 3, 90, 2, 227, 225, 23, 72, 14, 128, 1, 6, 65, 68, 65, 75, 32, - 66, 2, 66, 176, 140, 15, 2, 85, 68, 254, 186, 6, 78, 180, 171, 2, 3, 89, - 65, 75, 163, 165, 1, 86, 2, 255, 147, 8, 73, 18, 45, 9, 87, 69, 76, 32, - 83, 73, 71, 78, 32, 18, 250, 134, 22, 65, 38, 85, 206, 201, 1, 73, 234, - 234, 1, 79, 163, 8, 69, 116, 216, 1, 22, 67, 79, 78, 83, 79, 78, 65, 78, - 84, 32, 83, 73, 71, 78, 32, 77, 69, 68, 73, 65, 76, 32, 44, 7, 76, 69, - 84, 84, 69, 82, 32, 168, 1, 5, 83, 73, 71, 78, 32, 56, 6, 86, 79, 87, 69, - 76, 32, 251, 228, 23, 68, 8, 234, 213, 25, 72, 2, 82, 2, 86, 3, 89, 60, - 198, 230, 21, 78, 182, 23, 68, 114, 84, 206, 145, 3, 66, 2, 67, 2, 71, 2, - 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 83, 2, 86, 2, 89, - 187, 2, 65, 4, 214, 145, 25, 65, 233, 35, 6, 84, 72, 79, 76, 72, 79, 24, - 130, 148, 20, 83, 155, 128, 5, 76, 162, 23, 110, 65, 174, 95, 69, 246, - 103, 73, 146, 9, 79, 158, 12, 84, 30, 85, 130, 1, 89, 249, 236, 12, 4, - 82, 89, 86, 78, 138, 11, 236, 1, 2, 73, 82, 60, 8, 76, 70, 87, 73, 68, - 84, 72, 32, 242, 10, 77, 210, 1, 78, 236, 76, 21, 80, 80, 89, 32, 80, 69, - 82, 83, 79, 78, 32, 82, 65, 73, 83, 73, 78, 71, 32, 79, 78, 22, 82, 38, - 84, 252, 242, 17, 2, 85, 77, 251, 241, 5, 68, 6, 26, 32, 163, 217, 24, - 67, 4, 242, 162, 24, 80, 211, 113, 83, 244, 1, 140, 2, 7, 72, 65, 78, 71, - 85, 76, 32, 216, 4, 8, 75, 65, 84, 65, 75, 65, 78, 65, 204, 3, 3, 76, 69, - 70, 0, 4, 82, 73, 71, 72, 140, 190, 6, 11, 70, 79, 82, 77, 83, 32, 76, - 73, 71, 72, 84, 142, 129, 4, 85, 174, 218, 2, 73, 250, 184, 4, 66, 242, - 227, 4, 87, 211, 35, 68, 104, 52, 7, 76, 69, 84, 84, 69, 82, 32, 167, - 217, 10, 70, 102, 206, 1, 75, 28, 5, 78, 73, 69, 85, 78, 42, 80, 24, 5, - 82, 73, 69, 85, 76, 86, 83, 98, 89, 202, 61, 67, 54, 69, 30, 73, 242, 4, - 77, 138, 1, 84, 206, 3, 87, 198, 1, 72, 230, 194, 24, 65, 2, 79, 163, 64, - 85, 6, 222, 65, 72, 155, 3, 73, 7, 11, 45, 4, 134, 72, 67, 131, 3, 72, 6, - 146, 69, 72, 35, 73, 17, 11, 45, 14, 206, 49, 84, 226, 14, 80, 130, 4, - 77, 194, 3, 75, 218, 2, 72, 99, 83, 12, 40, 4, 83, 65, 78, 71, 151, 221, - 13, 73, 10, 210, 70, 67, 42, 75, 74, 80, 34, 84, 211, 2, 83, 14, 194, - 134, 23, 69, 194, 133, 2, 65, 162, 64, 73, 2, 79, 3, 85, 118, 70, 32, - 193, 240, 2, 11, 45, 72, 73, 82, 65, 71, 65, 78, 65, 32, 80, 116, 76, 7, - 76, 69, 84, 84, 69, 82, 32, 150, 240, 2, 83, 34, 86, 215, 200, 21, 77, - 110, 146, 1, 83, 138, 234, 2, 78, 150, 2, 72, 2, 75, 2, 77, 2, 82, 2, 84, - 170, 1, 89, 222, 41, 87, 154, 178, 22, 65, 2, 69, 2, 73, 2, 79, 3, 85, - 28, 76, 5, 77, 65, 76, 76, 32, 234, 200, 25, 65, 2, 69, 2, 73, 2, 79, 3, - 85, 18, 242, 236, 2, 89, 142, 183, 22, 84, 234, 36, 65, 2, 69, 2, 73, 2, - 79, 3, 85, 4, 11, 84, 4, 212, 157, 13, 2, 32, 67, 239, 138, 11, 87, 14, - 56, 3, 77, 69, 82, 106, 83, 233, 248, 21, 3, 66, 85, 82, 9, 29, 5, 32, - 65, 78, 68, 32, 6, 168, 170, 12, 3, 87, 82, 69, 144, 228, 3, 2, 83, 73, - 207, 136, 8, 80, 4, 152, 137, 25, 3, 84, 69, 82, 163, 61, 65, 194, 8, - 118, 68, 202, 2, 71, 128, 66, 13, 73, 70, 73, 32, 82, 79, 72, 73, 78, 71, - 89, 65, 32, 165, 5, 5, 85, 78, 79, 79, 32, 10, 100, 12, 32, 87, 73, 84, - 72, 32, 73, 78, 68, 69, 88, 32, 188, 1, 2, 66, 65, 193, 218, 21, 2, 83, - 72, 4, 156, 1, 18, 65, 78, 68, 32, 77, 73, 68, 68, 76, 69, 32, 70, 73, - 78, 71, 69, 82, 83, 1, 16, 70, 73, 78, 71, 69, 82, 32, 65, 78, 68, 32, - 84, 72, 85, 77, 66, 2, 233, 134, 16, 2, 32, 67, 4, 186, 185, 24, 76, 183, - 137, 1, 71, 170, 7, 84, 3, 85, 76, 32, 217, 64, 13, 90, 72, 79, 85, 32, - 78, 85, 77, 69, 82, 65, 76, 32, 146, 7, 164, 1, 9, 67, 72, 79, 83, 69, - 79, 78, 71, 32, 244, 15, 4, 68, 79, 85, 66, 0, 4, 83, 73, 78, 71, 46, 74, - 180, 31, 7, 76, 69, 84, 84, 69, 82, 32, 147, 154, 10, 70, 250, 1, 246, 1, - 67, 172, 2, 5, 73, 69, 85, 78, 71, 146, 1, 75, 132, 1, 5, 77, 73, 69, 85, - 77, 56, 5, 78, 73, 69, 85, 78, 74, 80, 172, 2, 5, 82, 73, 69, 85, 76, - 210, 1, 83, 166, 3, 84, 124, 2, 89, 69, 200, 40, 5, 72, 73, 69, 85, 72, - 199, 145, 10, 70, 30, 76, 2, 72, 73, 84, 7, 69, 79, 78, 71, 67, 72, 73, - 121, 4, 73, 69, 85, 67, 16, 40, 4, 69, 85, 67, 72, 41, 2, 84, 85, 7, 11, - 45, 4, 202, 31, 75, 243, 26, 72, 10, 21, 3, 69, 85, 77, 10, 22, 83, 155, - 46, 67, 6, 40, 4, 83, 65, 78, 71, 135, 205, 13, 73, 4, 194, 54, 67, 227, - 3, 83, 5, 215, 30, 45, 27, 11, 45, 24, 90, 80, 234, 30, 82, 242, 13, 67, - 194, 5, 77, 138, 1, 84, 186, 2, 75, 218, 2, 72, 99, 83, 6, 214, 50, 72, - 214, 3, 73, 207, 2, 65, 16, 80, 7, 65, 80, 89, 69, 79, 85, 78, 228, 20, - 5, 73, 89, 69, 79, 75, 131, 25, 72, 10, 234, 29, 82, 178, 15, 80, 30, 83, - 231, 3, 77, 11, 11, 45, 8, 158, 52, 75, 74, 80, 34, 84, 211, 2, 83, 15, - 11, 45, 12, 190, 51, 67, 42, 75, 74, 80, 34, 84, 242, 1, 72, 99, 83, 42, - 68, 6, 72, 73, 69, 85, 80, 72, 40, 4, 73, 69, 85, 80, 223, 53, 65, 7, 11, - 45, 4, 158, 51, 80, 147, 2, 72, 35, 11, 45, 32, 82, 83, 234, 20, 80, 214, - 7, 75, 162, 12, 67, 202, 6, 84, 226, 2, 78, 179, 2, 72, 14, 32, 3, 73, - 79, 83, 251, 3, 83, 13, 11, 45, 10, 242, 46, 84, 146, 2, 67, 42, 75, 75, - 80, 29, 11, 45, 26, 78, 75, 42, 83, 190, 44, 77, 154, 3, 67, 82, 78, 34, - 80, 34, 84, 243, 1, 72, 6, 170, 22, 65, 130, 19, 72, 135, 7, 73, 8, 40, - 4, 83, 65, 78, 71, 235, 197, 13, 73, 6, 206, 47, 75, 74, 80, 35, 84, 58, - 48, 3, 73, 79, 83, 217, 1, 4, 83, 65, 78, 71, 33, 11, 45, 30, 130, 1, 80, - 44, 2, 83, 83, 210, 22, 82, 210, 1, 75, 162, 12, 67, 194, 5, 77, 138, 1, - 84, 226, 2, 78, 178, 2, 72, 191, 157, 18, 73, 6, 184, 23, 4, 73, 69, 85, - 80, 179, 19, 72, 2, 233, 48, 3, 65, 78, 71, 26, 236, 17, 5, 67, 73, 69, - 85, 67, 172, 3, 4, 83, 73, 79, 83, 154, 1, 82, 186, 20, 84, 54, 89, 134, - 2, 75, 42, 78, 34, 80, 146, 2, 72, 191, 157, 18, 73, 16, 40, 5, 73, 75, - 69, 85, 84, 195, 41, 72, 15, 11, 45, 12, 226, 20, 82, 178, 19, 77, 154, - 3, 67, 42, 75, 74, 80, 243, 2, 83, 4, 150, 19, 83, 139, 22, 79, 2, 169, - 245, 8, 6, 76, 69, 32, 68, 79, 84, 216, 3, 92, 9, 79, 78, 71, 83, 69, 79, - 78, 71, 32, 165, 21, 9, 85, 78, 71, 83, 69, 79, 78, 71, 32, 154, 2, 226, - 1, 67, 80, 5, 72, 73, 69, 85, 72, 60, 5, 73, 69, 85, 78, 71, 46, 75, 220, - 1, 5, 77, 73, 69, 85, 77, 188, 1, 5, 78, 73, 69, 85, 78, 94, 80, 240, 2, - 5, 82, 73, 69, 85, 76, 190, 4, 83, 194, 3, 84, 213, 1, 2, 89, 69, 8, 36, - 4, 73, 69, 85, 67, 239, 30, 72, 7, 11, 45, 4, 162, 32, 83, 239, 7, 80, - 11, 11, 45, 8, 174, 16, 82, 178, 19, 77, 234, 3, 78, 35, 80, 9, 11, 45, - 6, 194, 17, 75, 57, 2, 83, 83, 28, 76, 7, 65, 80, 89, 69, 79, 85, 78, 40, - 5, 73, 89, 69, 79, 75, 215, 30, 72, 8, 130, 15, 82, 178, 15, 80, 131, 4, - 77, 19, 11, 45, 16, 166, 13, 75, 170, 1, 82, 42, 83, 224, 13, 2, 67, 72, - 146, 9, 78, 34, 80, 147, 2, 72, 27, 11, 45, 24, 74, 80, 30, 83, 134, 13, - 82, 242, 13, 67, 130, 9, 75, 42, 78, 179, 2, 72, 6, 174, 33, 73, 131, 6, - 65, 6, 40, 4, 83, 65, 78, 71, 227, 185, 13, 73, 4, 238, 35, 78, 147, 3, - 83, 21, 11, 45, 18, 174, 12, 82, 242, 13, 67, 202, 6, 84, 186, 2, 75, - 218, 2, 72, 62, 80, 39, 83, 36, 88, 6, 65, 78, 83, 73, 79, 83, 48, 6, 72, - 73, 69, 85, 80, 72, 53, 4, 73, 69, 85, 80, 7, 11, 45, 4, 236, 7, 2, 75, - 65, 195, 26, 80, 9, 11, 45, 6, 150, 11, 84, 234, 22, 80, 243, 2, 83, 23, - 11, 45, 20, 112, 5, 82, 73, 69, 85, 76, 24, 4, 83, 73, 79, 83, 134, 3, - 80, 246, 19, 67, 194, 5, 77, 170, 4, 84, 243, 1, 72, 5, 153, 3, 2, 45, - 80, 5, 221, 32, 2, 45, 84, 57, 11, 45, 54, 102, 75, 92, 5, 77, 73, 69, - 85, 77, 50, 80, 126, 83, 74, 84, 44, 2, 89, 69, 154, 28, 78, 179, 2, 72, - 10, 52, 5, 73, 89, 69, 79, 75, 190, 4, 65, 131, 19, 72, 7, 11, 45, 4, - 254, 32, 72, 99, 83, 9, 11, 45, 6, 130, 30, 75, 218, 2, 72, 99, 83, 14, - 48, 4, 73, 69, 85, 80, 174, 26, 72, 163, 6, 65, 11, 11, 45, 8, 42, 80, - 222, 29, 84, 242, 1, 72, 99, 83, 2, 243, 25, 72, 6, 40, 4, 83, 65, 78, - 71, 211, 178, 13, 73, 4, 182, 28, 75, 187, 3, 83, 6, 100, 5, 73, 75, 69, - 85, 84, 151, 25, 72, 6, 56, 9, 79, 82, 73, 78, 72, 73, 69, 85, 72, 191, - 3, 83, 5, 255, 29, 45, 52, 48, 3, 73, 79, 83, 161, 1, 4, 83, 65, 78, 71, - 25, 11, 45, 22, 82, 75, 162, 3, 82, 242, 13, 67, 198, 2, 80, 254, 2, 77, - 138, 1, 84, 147, 5, 72, 4, 22, 65, 135, 26, 73, 2, 237, 18, 6, 80, 89, - 69, 79, 85, 78, 28, 160, 1, 5, 82, 73, 69, 85, 76, 36, 6, 84, 73, 75, 69, - 85, 84, 16, 3, 89, 69, 83, 138, 19, 83, 178, 1, 77, 154, 3, 67, 42, 75, - 42, 78, 34, 80, 207, 159, 18, 73, 5, 17, 2, 45, 75, 2, 159, 17, 72, 5, - 255, 16, 45, 2, 139, 184, 18, 73, 20, 40, 5, 73, 75, 69, 85, 84, 155, 21, - 72, 19, 11, 45, 16, 58, 82, 42, 83, 42, 84, 162, 13, 67, 130, 9, 75, 75, - 80, 2, 17, 2, 73, 69, 2, 131, 147, 24, 85, 4, 21, 3, 73, 79, 83, 5, 223, - 1, 45, 2, 255, 19, 72, 18, 44, 6, 83, 73, 69, 85, 78, 71, 243, 19, 79, - 17, 11, 45, 14, 50, 75, 30, 83, 198, 17, 77, 154, 6, 72, 63, 80, 4, 166, - 14, 72, 135, 7, 73, 4, 26, 83, 131, 171, 13, 73, 2, 21, 3, 65, 78, 71, 2, - 207, 20, 75, 190, 1, 122, 65, 118, 69, 134, 1, 73, 92, 7, 83, 83, 65, 78, - 71, 65, 82, 106, 79, 138, 1, 85, 102, 89, 174, 15, 87, 235, 141, 10, 70, - 23, 48, 4, 82, 65, 69, 65, 98, 45, 139, 152, 25, 69, 13, 11, 45, 10, 250, - 210, 22, 69, 226, 197, 2, 65, 2, 73, 3, 85, 25, 18, 79, 55, 85, 9, 11, - 45, 6, 158, 243, 24, 69, 234, 36, 79, 3, 85, 15, 11, 45, 12, 170, 9, 69, - 170, 142, 25, 65, 2, 79, 3, 85, 31, 11, 45, 28, 66, 65, 34, 89, 166, 1, - 79, 170, 240, 24, 69, 234, 36, 73, 3, 85, 5, 11, 82, 2, 215, 144, 18, 65, - 14, 50, 65, 162, 208, 22, 69, 226, 197, 2, 79, 3, 85, 7, 138, 247, 24, - 45, 247, 30, 69, 23, 26, 45, 199, 149, 25, 69, 18, 50, 79, 22, 89, 158, - 207, 22, 69, 227, 197, 2, 85, 5, 183, 129, 25, 45, 8, 154, 207, 22, 69, - 195, 133, 2, 65, 17, 11, 45, 14, 158, 19, 89, 186, 164, 5, 73, 152, 254, - 12, 3, 69, 79, 45, 190, 158, 6, 65, 163, 64, 85, 62, 42, 65, 70, 69, 66, - 73, 22, 79, 107, 85, 11, 26, 45, 175, 147, 25, 69, 6, 182, 244, 24, 89, - 246, 30, 79, 3, 85, 11, 11, 79, 9, 11, 45, 6, 178, 144, 25, 89, 186, 2, - 79, 3, 85, 5, 219, 237, 24, 45, 19, 11, 45, 16, 58, 89, 202, 209, 24, 65, - 174, 33, 69, 246, 30, 73, 3, 79, 6, 198, 209, 24, 65, 175, 33, 69, 21, - 11, 45, 18, 142, 16, 89, 206, 187, 22, 69, 194, 133, 2, 65, 162, 64, 73, - 2, 79, 3, 85, 186, 1, 226, 1, 65, 46, 67, 54, 69, 30, 73, 22, 75, 188, 1, - 5, 77, 73, 69, 85, 77, 64, 5, 78, 73, 69, 85, 78, 70, 80, 168, 1, 5, 82, - 73, 69, 85, 76, 254, 1, 84, 90, 83, 246, 2, 87, 50, 89, 150, 1, 72, 230, - 194, 24, 79, 163, 64, 85, 9, 156, 13, 3, 82, 65, 69, 235, 129, 25, 69, 4, - 22, 72, 207, 8, 73, 2, 141, 236, 24, 2, 73, 69, 7, 166, 142, 25, 79, 3, - 85, 5, 207, 168, 18, 69, 14, 56, 7, 65, 80, 89, 69, 79, 85, 78, 106, 72, - 155, 3, 73, 8, 30, 80, 30, 83, 231, 3, 77, 4, 190, 4, 72, 215, 3, 73, 2, - 25, 4, 83, 65, 78, 71, 2, 207, 7, 80, 2, 213, 60, 2, 73, 69, 9, 11, 45, - 6, 22, 80, 247, 9, 83, 4, 142, 7, 73, 207, 2, 65, 13, 11, 45, 10, 234, 5, - 67, 146, 1, 84, 242, 1, 72, 62, 80, 39, 83, 20, 48, 4, 73, 69, 85, 80, - 170, 2, 72, 163, 6, 65, 17, 11, 45, 14, 42, 83, 186, 2, 84, 146, 2, 67, - 43, 75, 6, 21, 3, 73, 79, 83, 7, 11, 45, 4, 202, 4, 75, 107, 84, 27, 11, - 45, 24, 68, 2, 75, 73, 34, 77, 34, 80, 106, 84, 54, 89, 222, 4, 72, 99, - 83, 4, 149, 1, 4, 89, 69, 79, 75, 2, 11, 73, 2, 255, 223, 23, 69, 8, 30, - 72, 34, 73, 131, 6, 65, 2, 193, 228, 18, 3, 73, 69, 85, 4, 21, 3, 69, 85, - 80, 5, 243, 5, 45, 4, 22, 72, 151, 3, 73, 2, 225, 230, 21, 2, 73, 69, 2, - 17, 2, 69, 79, 2, 167, 4, 82, 28, 44, 3, 73, 79, 83, 57, 4, 83, 65, 78, - 71, 13, 11, 45, 10, 122, 67, 42, 75, 42, 78, 34, 80, 35, 84, 16, 78, 67, - 42, 75, 42, 78, 34, 80, 34, 84, 242, 1, 72, 98, 83, 223, 156, 18, 73, 2, - 11, 73, 2, 249, 221, 23, 2, 69, 85, 2, 11, 73, 2, 237, 219, 24, 2, 89, - 69, 2, 11, 73, 2, 247, 132, 24, 69, 2, 11, 73, 2, 147, 143, 24, 69, 2, - 11, 73, 2, 11, 75, 2, 139, 139, 24, 69, 10, 230, 190, 22, 69, 194, 133, - 2, 65, 163, 64, 73, 34, 58, 69, 206, 1, 79, 62, 85, 182, 193, 24, 65, - 163, 64, 73, 13, 42, 79, 73, 6, 83, 73, 69, 85, 78, 71, 5, 11, 82, 2, 17, - 2, 73, 78, 2, 11, 72, 2, 161, 235, 9, 2, 73, 69, 7, 11, 45, 4, 18, 80, - 39, 83, 2, 11, 65, 2, 11, 78, 2, 11, 83, 2, 223, 146, 13, 73, 9, 11, 45, - 6, 26, 89, 235, 129, 25, 73, 4, 199, 193, 24, 65, 9, 11, 45, 6, 26, 89, - 175, 129, 25, 73, 4, 203, 187, 22, 69, 24, 210, 136, 11, 84, 162, 136, - 12, 70, 30, 83, 210, 86, 78, 14, 79, 223, 110, 69, 100, 156, 1, 7, 76, - 69, 84, 84, 69, 82, 32, 196, 2, 5, 77, 65, 82, 75, 32, 72, 5, 83, 73, 71, - 78, 32, 132, 159, 2, 6, 86, 79, 87, 69, 76, 32, 255, 235, 20, 68, 58, - 202, 1, 68, 34, 75, 254, 241, 20, 84, 154, 50, 82, 130, 223, 1, 78, 238, - 178, 1, 83, 138, 69, 66, 2, 67, 2, 70, 2, 71, 2, 72, 2, 74, 2, 76, 2, 77, - 2, 80, 2, 86, 2, 87, 2, 89, 2, 90, 187, 2, 65, 4, 166, 251, 24, 68, 187, - 2, 65, 8, 56, 5, 73, 78, 78, 65, 32, 206, 250, 24, 72, 187, 2, 65, 4, - 202, 250, 24, 87, 3, 89, 4, 248, 197, 21, 6, 78, 65, 32, 75, 72, 79, 153, - 183, 2, 3, 83, 65, 75, 8, 52, 2, 84, 65, 217, 238, 22, 5, 72, 65, 82, 66, - 65, 6, 42, 72, 158, 145, 20, 83, 235, 231, 4, 78, 2, 163, 217, 24, 65, - 42, 62, 76, 144, 239, 18, 6, 83, 73, 71, 78, 32, 80, 247, 1, 86, 36, 33, - 6, 69, 84, 84, 69, 82, 32, 36, 146, 137, 21, 78, 250, 238, 3, 66, 2, 68, - 2, 71, 2, 72, 2, 75, 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, - 89, 186, 2, 65, 2, 73, 3, 85, 2, 139, 235, 23, 69, 4, 130, 180, 23, 68, - 143, 197, 1, 80, 54, 52, 5, 67, 72, 73, 78, 71, 41, 4, 82, 65, 78, 32, 2, - 17, 2, 32, 67, 2, 163, 200, 23, 72, 52, 52, 7, 76, 69, 84, 84, 69, 82, - 32, 175, 179, 6, 78, 42, 218, 1, 65, 234, 173, 11, 90, 162, 47, 84, 150, - 119, 76, 50, 81, 60, 6, 68, 65, 76, 69, 84, 72, 146, 165, 4, 71, 122, 83, - 66, 89, 158, 208, 1, 72, 234, 5, 75, 198, 75, 66, 178, 216, 4, 78, 134, - 2, 87, 218, 103, 80, 171, 4, 77, 4, 130, 250, 16, 76, 151, 172, 7, 89, - 172, 9, 230, 1, 65, 240, 32, 5, 66, 82, 69, 87, 32, 210, 32, 76, 200, 1, - 16, 78, 84, 65, 73, 71, 65, 78, 65, 32, 76, 69, 84, 84, 69, 82, 32, 174, - 12, 82, 120, 11, 88, 65, 71, 82, 65, 77, 32, 70, 79, 82, 32, 221, 162, - 24, 4, 68, 71, 69, 72, 214, 1, 42, 68, 98, 82, 201, 1, 3, 86, 89, 32, 6, - 44, 5, 83, 84, 79, 78, 69, 187, 200, 23, 80, 5, 217, 225, 2, 7, 32, 71, - 82, 65, 86, 69, 89, 12, 32, 2, 84, 32, 139, 151, 17, 45, 10, 60, 5, 87, - 73, 84, 72, 32, 246, 163, 12, 68, 155, 143, 9, 72, 6, 76, 9, 84, 73, 80, - 32, 79, 78, 32, 84, 72, 174, 242, 12, 82, 191, 228, 10, 65, 2, 223, 190, - 24, 69, 196, 1, 134, 2, 65, 202, 1, 66, 230, 2, 67, 154, 3, 68, 162, 1, - 69, 186, 3, 70, 94, 72, 62, 76, 222, 1, 77, 110, 79, 162, 1, 82, 142, 2, - 83, 228, 1, 3, 78, 79, 82, 198, 1, 84, 128, 2, 2, 85, 80, 174, 1, 87, - 138, 140, 14, 73, 254, 238, 3, 80, 210, 131, 4, 86, 251, 77, 71, 12, 108, - 17, 82, 82, 79, 87, 32, 83, 72, 65, 70, 84, 32, 87, 73, 68, 84, 72, 32, - 182, 158, 18, 77, 155, 188, 4, 83, 8, 36, 3, 79, 78, 69, 223, 141, 23, - 84, 7, 11, 32, 4, 174, 238, 13, 84, 135, 252, 8, 72, 14, 48, 4, 65, 76, - 76, 79, 21, 4, 76, 65, 67, 75, 2, 187, 167, 5, 84, 12, 30, 32, 153, 1, 2, - 45, 70, 6, 52, 7, 67, 85, 82, 86, 69, 68, 32, 247, 228, 23, 72, 4, 40, 4, - 68, 79, 87, 78, 1, 2, 85, 80, 2, 213, 203, 23, 8, 87, 65, 82, 68, 83, 32, - 65, 78, 6, 45, 9, 69, 65, 84, 72, 69, 82, 69, 68, 32, 6, 234, 211, 13, - 83, 218, 168, 3, 78, 211, 206, 6, 82, 14, 116, 2, 72, 69, 52, 5, 73, 82, - 67, 76, 69, 149, 220, 17, 14, 79, 78, 67, 65, 86, 69, 45, 80, 79, 73, 78, - 84, 69, 68, 4, 216, 203, 20, 4, 86, 82, 79, 78, 239, 218, 2, 67, 9, 64, - 6, 32, 87, 73, 84, 72, 32, 133, 212, 22, 4, 68, 32, 83, 65, 4, 52, 7, 83, - 84, 82, 79, 75, 69, 32, 199, 254, 4, 67, 2, 29, 5, 65, 78, 68, 32, 84, 2, - 11, 87, 2, 11, 79, 2, 21, 3, 32, 68, 79, 2, 11, 84, 2, 207, 234, 23, 83, - 14, 52, 7, 65, 83, 72, 69, 68, 32, 84, 18, 73, 31, 79, 2, 175, 16, 82, 2, - 137, 144, 19, 2, 86, 73, 10, 192, 16, 3, 87, 78, 87, 198, 139, 14, 85, - 187, 180, 4, 76, 16, 120, 5, 73, 71, 72, 84, 32, 156, 2, 16, 88, 67, 76, - 65, 77, 65, 84, 73, 79, 78, 32, 77, 65, 82, 75, 32, 147, 205, 18, 81, 10, - 40, 2, 80, 79, 126, 84, 231, 207, 22, 83, 6, 33, 6, 73, 78, 84, 69, 68, - 32, 6, 202, 186, 16, 80, 196, 147, 6, 11, 82, 69, 67, 84, 73, 76, 73, 78, - 69, 65, 82, 23, 66, 2, 141, 208, 22, 24, 69, 65, 82, 68, 82, 79, 80, 45, - 83, 80, 79, 75, 69, 68, 32, 80, 82, 79, 80, 69, 76, 76, 69, 82, 4, 246, - 207, 23, 83, 199, 79, 79, 6, 44, 5, 79, 85, 82, 32, 66, 139, 254, 4, 73, - 2, 209, 131, 11, 6, 65, 76, 76, 79, 79, 78, 4, 242, 186, 17, 79, 169, - 221, 5, 6, 69, 65, 82, 84, 32, 69, 20, 74, 65, 44, 3, 69, 70, 84, 28, 2, - 79, 87, 149, 249, 4, 3, 73, 71, 65, 4, 172, 207, 21, 2, 82, 71, 147, 208, - 1, 84, 8, 254, 3, 45, 195, 6, 87, 6, 26, 32, 223, 143, 10, 69, 4, 154, - 150, 14, 68, 25, 4, 83, 73, 78, 71, 4, 56, 8, 85, 76, 84, 73, 80, 76, 73, - 67, 235, 176, 21, 73, 2, 25, 4, 65, 84, 73, 79, 2, 207, 153, 5, 78, 6, - 132, 140, 6, 9, 80, 69, 78, 32, 67, 69, 78, 84, 82, 144, 175, 10, 13, 86, - 65, 76, 32, 87, 73, 84, 72, 32, 79, 86, 65, 76, 153, 141, 6, 5, 85, 84, - 76, 73, 78, 12, 76, 4, 73, 71, 72, 84, 245, 188, 23, 9, 79, 85, 78, 68, - 45, 84, 73, 80, 80, 10, 62, 45, 109, 11, 87, 65, 82, 68, 83, 32, 65, 82, - 82, 79, 87, 4, 69, 15, 80, 79, 73, 78, 84, 73, 78, 71, 32, 65, 78, 71, - 76, 69, 32, 4, 222, 229, 6, 66, 147, 173, 7, 81, 7, 139, 6, 32, 26, 106, - 65, 78, 73, 44, 2, 79, 85, 160, 154, 14, 7, 67, 82, 73, 80, 84, 32, 76, - 157, 135, 1, 3, 80, 65, 82, 4, 236, 145, 14, 10, 78, 83, 45, 83, 69, 82, - 73, 70, 32, 73, 171, 180, 8, 76, 8, 216, 143, 14, 2, 78, 71, 179, 179, 8, - 88, 10, 21, 3, 84, 72, 32, 10, 60, 5, 69, 65, 83, 84, 32, 29, 6, 87, 69, - 83, 84, 32, 80, 6, 26, 80, 203, 190, 23, 65, 4, 41, 8, 79, 73, 78, 84, - 73, 78, 71, 32, 4, 242, 237, 16, 86, 139, 191, 6, 66, 12, 88, 9, 69, 65, - 82, 68, 82, 79, 80, 45, 83, 130, 1, 82, 241, 225, 6, 4, 87, 69, 76, 86, - 6, 64, 6, 80, 79, 75, 69, 68, 32, 241, 182, 23, 4, 72, 65, 78, 75, 4, - 164, 195, 22, 8, 80, 73, 78, 87, 72, 69, 69, 76, 27, 65, 2, 193, 3, 5, - 73, 65, 78, 71, 76, 6, 26, 87, 203, 133, 10, 80, 4, 53, 11, 65, 82, 68, - 83, 32, 65, 82, 82, 79, 87, 32, 4, 29, 5, 87, 73, 84, 72, 32, 4, 192, - 251, 19, 5, 76, 65, 82, 71, 69, 203, 238, 1, 69, 12, 76, 5, 72, 73, 84, - 69, 32, 164, 1, 2, 73, 68, 237, 236, 22, 3, 69, 68, 71, 8, 64, 6, 83, 81, - 85, 65, 82, 69, 166, 214, 17, 68, 215, 171, 5, 67, 5, 173, 161, 23, 19, - 32, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, 65, 67, 75, 32, - 86, 2, 157, 232, 20, 2, 69, 45, 140, 2, 112, 7, 65, 67, 67, 69, 78, 84, - 32, 138, 8, 76, 164, 14, 5, 77, 65, 82, 75, 32, 114, 80, 217, 157, 21, 2, - 89, 79, 60, 128, 2, 9, 65, 84, 78, 65, 72, 32, 72, 65, 70, 22, 68, 36, 3, - 71, 69, 82, 74, 77, 124, 2, 80, 65, 28, 4, 69, 84, 78, 65, 20, 2, 81, 65, - 58, 83, 58, 84, 156, 1, 2, 89, 69, 78, 90, 196, 165, 8, 3, 82, 69, 86, - 142, 129, 15, 79, 225, 146, 1, 3, 73, 76, 85, 2, 243, 157, 18, 85, 4, - 230, 128, 19, 69, 179, 140, 5, 65, 6, 32, 3, 69, 83, 72, 179, 28, 83, 5, - 129, 221, 6, 4, 32, 77, 85, 81, 8, 84, 5, 69, 82, 75, 72, 65, 164, 238, - 17, 2, 85, 78, 249, 45, 5, 65, 72, 65, 80, 65, 5, 209, 219, 19, 4, 32, - 75, 69, 70, 4, 26, 83, 251, 143, 24, 90, 2, 151, 169, 24, 72, 4, 128, - 137, 24, 6, 82, 78, 69, 89, 32, 80, 191, 35, 68, 4, 182, 24, 69, 193, - 213, 22, 6, 72, 65, 76, 83, 72, 69, 8, 38, 69, 249, 209, 22, 3, 73, 80, - 69, 6, 48, 6, 76, 73, 83, 72, 65, 32, 207, 224, 11, 86, 4, 240, 155, 22, - 3, 81, 69, 84, 249, 141, 2, 4, 71, 69, 68, 79, 4, 128, 205, 8, 10, 82, - 65, 72, 32, 66, 69, 78, 32, 89, 79, 255, 221, 2, 84, 8, 34, 65, 237, 145, - 24, 2, 73, 78, 6, 40, 4, 81, 69, 70, 32, 183, 255, 5, 82, 4, 154, 135, - 11, 81, 157, 176, 12, 3, 71, 65, 68, 150, 1, 76, 6, 69, 84, 84, 69, 82, - 32, 201, 11, 8, 73, 71, 65, 84, 85, 82, 69, 32, 140, 1, 134, 3, 65, 204, - 1, 3, 66, 69, 84, 0, 3, 75, 65, 70, 0, 2, 80, 69, 68, 6, 70, 73, 78, 65, - 76, 32, 92, 2, 81, 79, 16, 2, 72, 69, 52, 2, 78, 85, 0, 4, 90, 65, 89, - 73, 18, 83, 48, 3, 82, 69, 83, 170, 1, 84, 52, 4, 68, 65, 76, 69, 12, 5, - 71, 73, 77, 69, 76, 0, 5, 76, 65, 77, 69, 68, 0, 3, 77, 69, 77, 48, 3, - 86, 65, 86, 80, 5, 87, 73, 68, 69, 32, 153, 1, 3, 89, 79, 68, 14, 26, 76, - 171, 198, 23, 89, 12, 64, 2, 69, 70, 73, 10, 84, 69, 82, 78, 65, 84, 73, - 86, 69, 32, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 130, 13, 77, 130, 1, 80, - 35, 81, 4, 242, 201, 16, 65, 251, 160, 1, 80, 7, 33, 6, 32, 87, 73, 84, - 72, 32, 4, 142, 15, 82, 199, 225, 13, 68, 14, 88, 2, 75, 65, 236, 2, 2, - 80, 69, 220, 153, 1, 2, 84, 83, 182, 166, 22, 78, 135, 110, 77, 4, 235, - 2, 70, 7, 244, 10, 5, 32, 87, 73, 84, 72, 167, 184, 24, 84, 4, 167, 2, - 78, 16, 44, 4, 65, 77, 69, 75, 17, 3, 72, 73, 78, 4, 231, 1, 72, 13, 33, - 6, 32, 87, 73, 84, 72, 32, 10, 40, 6, 68, 65, 71, 69, 83, 72, 39, 83, 7, - 33, 6, 32, 65, 78, 68, 32, 83, 4, 254, 254, 5, 72, 203, 192, 2, 73, 12, - 50, 69, 12, 2, 65, 86, 1, 4, 83, 65, 68, 73, 4, 11, 84, 5, 233, 236, 13, - 7, 32, 87, 73, 84, 72, 32, 68, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 148, - 253, 1, 2, 72, 79, 131, 239, 11, 68, 16, 174, 2, 76, 202, 203, 8, 65, - 210, 196, 2, 84, 186, 217, 2, 82, 160, 244, 8, 2, 68, 65, 242, 93, 75, - 222, 106, 72, 169, 4, 7, 70, 73, 78, 65, 76, 32, 77, 7, 33, 6, 32, 87, - 73, 84, 72, 32, 4, 176, 7, 2, 72, 73, 255, 226, 13, 68, 10, 72, 6, 65, - 76, 69, 70, 32, 76, 29, 8, 89, 73, 68, 68, 73, 83, 72, 32, 2, 193, 177, - 19, 2, 65, 77, 8, 120, 7, 68, 79, 85, 66, 76, 69, 32, 232, 4, 9, 89, 79, - 68, 32, 89, 79, 68, 32, 80, 185, 128, 21, 5, 86, 65, 86, 32, 89, 4, 254, - 142, 11, 86, 163, 246, 9, 89, 6, 80, 3, 76, 79, 87, 0, 3, 85, 80, 80, - 237, 232, 22, 6, 77, 65, 83, 79, 82, 65, 2, 233, 169, 23, 2, 69, 82, 50, - 84, 5, 79, 73, 78, 84, 32, 229, 5, 11, 85, 78, 67, 84, 85, 65, 84, 73, - 79, 78, 32, 38, 228, 1, 9, 68, 65, 71, 69, 83, 72, 32, 79, 82, 46, 72, - 106, 80, 166, 1, 81, 86, 82, 22, 83, 176, 209, 9, 2, 84, 83, 132, 142, - 11, 17, 74, 85, 68, 69, 79, 45, 83, 80, 65, 78, 73, 83, 72, 32, 86, 65, - 82, 233, 143, 3, 3, 77, 69, 84, 2, 17, 2, 32, 77, 2, 201, 1, 2, 65, 80, - 12, 60, 5, 65, 84, 65, 70, 32, 106, 73, 33, 4, 79, 76, 65, 77, 6, 38, 80, - 34, 81, 145, 2, 2, 83, 69, 2, 11, 65, 2, 131, 215, 17, 84, 2, 193, 162, - 23, 3, 65, 77, 65, 2, 11, 82, 2, 143, 230, 13, 73, 5, 181, 137, 11, 12, - 32, 72, 65, 83, 69, 82, 32, 70, 79, 82, 32, 86, 6, 52, 5, 65, 77, 65, 84, - 83, 189, 191, 11, 2, 85, 66, 5, 165, 242, 10, 2, 32, 81, 2, 167, 225, 6, - 65, 8, 34, 69, 22, 72, 243, 178, 8, 73, 2, 239, 161, 23, 71, 4, 238, 178, - 8, 73, 199, 209, 7, 69, 12, 152, 1, 3, 71, 69, 82, 60, 3, 80, 65, 83, 20, - 7, 83, 79, 70, 32, 80, 65, 83, 212, 249, 21, 7, 78, 85, 78, 32, 72, 65, - 70, 185, 183, 1, 3, 77, 65, 81, 4, 26, 83, 211, 202, 22, 69, 2, 157, 176, - 23, 3, 72, 65, 89, 2, 155, 226, 13, 69, 2, 135, 226, 13, 85, 8, 114, 77, - 160, 149, 12, 15, 76, 83, 67, 72, 82, 69, 73, 66, 69, 82, 32, 80, 65, 85, - 83, 185, 223, 5, 3, 73, 67, 79, 4, 176, 222, 5, 12, 69, 84, 32, 87, 73, - 84, 72, 32, 87, 72, 73, 84, 231, 191, 17, 32, 188, 4, 164, 1, 2, 65, 45, - 50, 72, 70, 75, 230, 1, 77, 114, 78, 146, 2, 82, 66, 83, 154, 1, 84, 226, - 1, 87, 62, 89, 110, 69, 134, 241, 8, 85, 190, 170, 5, 79, 143, 191, 3, - 73, 8, 190, 144, 24, 87, 246, 30, 49, 2, 50, 3, 51, 72, 166, 6, 79, 146, - 191, 8, 65, 146, 224, 5, 85, 158, 115, 69, 3, 73, 74, 72, 2, 65, 45, 104, - 2, 79, 45, 178, 4, 73, 226, 3, 69, 223, 142, 15, 85, 24, 210, 234, 11, - 49, 206, 172, 12, 75, 214, 22, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, - 56, 3, 57, 8, 178, 153, 24, 75, 218, 19, 49, 2, 50, 3, 51, 54, 68, 2, 69, - 45, 154, 7, 79, 222, 142, 15, 65, 2, 73, 243, 203, 2, 85, 6, 218, 169, - 24, 77, 186, 2, 49, 3, 50, 68, 116, 2, 69, 45, 72, 2, 73, 45, 246, 2, 65, - 194, 243, 8, 79, 190, 170, 5, 85, 169, 136, 6, 6, 45, 77, 85, 45, 77, 79, - 14, 254, 139, 24, 75, 246, 30, 49, 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 16, - 214, 147, 24, 84, 214, 22, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 55, - 54, 222, 4, 79, 2, 85, 222, 142, 15, 73, 242, 203, 2, 65, 3, 69, 68, 62, - 65, 2, 85, 226, 3, 73, 134, 241, 8, 69, 219, 157, 6, 79, 16, 11, 45, 16, - 206, 168, 24, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 64, - 74, 69, 20, 2, 79, 45, 72, 2, 85, 45, 190, 144, 15, 73, 243, 203, 2, 65, - 18, 139, 240, 18, 45, 14, 234, 164, 24, 82, 186, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 3, 54, 10, 230, 135, 24, 84, 246, 30, 49, 2, 50, 2, 51, 3, 52, - 42, 170, 242, 8, 65, 2, 73, 218, 157, 6, 79, 243, 203, 2, 69, 32, 40, 2, - 65, 45, 66, 79, 207, 218, 17, 85, 12, 198, 134, 24, 89, 246, 30, 49, 2, - 50, 2, 51, 2, 52, 3, 53, 12, 11, 45, 12, 238, 164, 24, 49, 2, 50, 2, 51, - 2, 52, 2, 53, 3, 54, 4, 140, 167, 8, 21, 77, 73, 84, 73, 65, 78, 32, 67, - 79, 78, 74, 85, 71, 65, 84, 69, 32, 77, 65, 84, 82, 167, 253, 15, 66, - 128, 1, 210, 2, 65, 110, 66, 144, 1, 2, 67, 79, 94, 68, 198, 2, 70, 66, - 71, 40, 4, 72, 79, 76, 68, 164, 1, 2, 73, 78, 116, 2, 77, 79, 58, 79, - 122, 80, 100, 2, 82, 69, 62, 83, 238, 1, 84, 210, 5, 87, 212, 155, 15, 4, - 76, 73, 77, 73, 220, 180, 5, 11, 89, 79, 85, 84, 72, 70, 85, 76, 32, 70, - 79, 181, 173, 3, 9, 69, 78, 84, 72, 85, 83, 73, 65, 83, 6, 76, 3, 80, 80, - 82, 124, 4, 70, 84, 69, 82, 189, 151, 19, 4, 66, 85, 78, 68, 2, 233, 253, - 23, 2, 79, 65, 6, 92, 5, 69, 70, 79, 82, 69, 128, 215, 3, 6, 73, 84, 73, - 78, 71, 32, 1, 4, 82, 69, 65, 75, 2, 197, 206, 23, 7, 32, 67, 79, 77, 80, - 76, 69, 6, 26, 78, 183, 142, 19, 77, 4, 228, 187, 20, 4, 84, 69, 77, 80, - 245, 211, 2, 3, 70, 76, 73, 14, 110, 69, 78, 73, 206, 146, 19, 85, 129, - 241, 2, 15, 65, 82, 75, 69, 78, 73, 78, 71, 32, 79, 70, 32, 84, 72, 69, - 6, 222, 142, 19, 67, 192, 6, 2, 76, 73, 201, 196, 4, 5, 86, 69, 76, 79, - 80, 4, 252, 132, 19, 21, 70, 70, 73, 67, 85, 76, 84, 89, 32, 65, 84, 32, - 84, 72, 69, 32, 66, 69, 71, 73, 78, 177, 248, 2, 4, 83, 80, 69, 82, 4, - 220, 137, 19, 2, 79, 76, 217, 188, 4, 5, 69, 76, 76, 79, 87, 12, 36, 5, - 65, 84, 72, 69, 82, 35, 82, 2, 225, 134, 15, 3, 73, 78, 71, 10, 40, 4, - 69, 65, 84, 32, 155, 221, 23, 65, 8, 22, 80, 211, 5, 84, 6, 22, 79, 147, - 5, 82, 4, 172, 2, 2, 83, 83, 203, 217, 23, 87, 8, 50, 78, 206, 138, 19, - 67, 217, 5, 3, 70, 76, 85, 4, 160, 144, 19, 2, 79, 67, 205, 231, 1, 5, - 69, 82, 32, 84, 82, 4, 204, 171, 22, 3, 68, 69, 83, 189, 61, 3, 85, 84, - 72, 6, 26, 66, 37, 2, 80, 80, 2, 149, 199, 23, 4, 83, 84, 82, 85, 4, 26, - 82, 239, 197, 23, 79, 2, 145, 248, 21, 2, 69, 83, 6, 196, 139, 15, 9, 85, - 83, 72, 73, 78, 71, 32, 85, 80, 204, 137, 2, 3, 82, 79, 71, 255, 196, 6, - 69, 6, 26, 84, 207, 250, 18, 86, 4, 254, 139, 19, 85, 223, 57, 82, 8, - 132, 1, 5, 77, 65, 76, 76, 32, 236, 156, 21, 6, 84, 65, 78, 68, 83, 84, - 233, 240, 1, 11, 80, 76, 73, 84, 84, 73, 78, 71, 32, 65, 80, 4, 24, 2, - 80, 82, 43, 84, 2, 225, 140, 19, 5, 69, 80, 79, 78, 68, 2, 11, 65, 2, - 155, 195, 23, 77, 30, 36, 3, 72, 69, 32, 175, 219, 17, 82, 28, 186, 2, - 65, 130, 1, 67, 132, 1, 3, 70, 65, 77, 20, 9, 82, 69, 67, 69, 80, 84, 73, - 86, 69, 30, 87, 172, 22, 12, 77, 65, 82, 82, 89, 73, 78, 71, 32, 77, 65, - 73, 168, 147, 5, 6, 71, 69, 78, 84, 76, 69, 248, 221, 10, 13, 75, 69, 69, - 80, 73, 78, 71, 32, 83, 84, 73, 76, 76, 201, 233, 3, 7, 74, 79, 89, 79, - 85, 83, 32, 6, 58, 82, 133, 181, 11, 8, 66, 89, 83, 77, 65, 76, 32, 87, - 4, 248, 168, 20, 8, 79, 85, 83, 73, 78, 71, 32, 84, 171, 214, 3, 77, 6, - 128, 131, 1, 2, 65, 85, 212, 164, 19, 9, 82, 69, 65, 84, 73, 86, 69, 32, - 72, 133, 212, 1, 9, 76, 73, 78, 71, 73, 78, 71, 32, 70, 2, 243, 235, 23, - 73, 2, 157, 166, 20, 2, 32, 69, 4, 178, 135, 22, 69, 213, 201, 1, 5, 65, - 78, 68, 69, 82, 4, 202, 231, 6, 65, 141, 166, 6, 14, 79, 82, 75, 32, 79, - 78, 32, 84, 72, 69, 32, 68, 69, 67, 222, 1, 236, 1, 2, 71, 72, 180, 2, 7, - 82, 65, 71, 65, 78, 65, 32, 212, 4, 7, 83, 84, 79, 82, 73, 67, 32, 168, - 186, 15, 7, 78, 68, 85, 32, 84, 69, 77, 240, 33, 4, 75, 73, 78, 71, 162, - 250, 1, 66, 177, 168, 4, 8, 80, 80, 79, 80, 79, 84, 65, 77, 12, 18, 32, - 119, 45, 6, 204, 135, 5, 2, 66, 82, 220, 231, 16, 6, 86, 79, 76, 84, 65, - 71, 229, 48, 9, 79, 67, 84, 69, 84, 32, 80, 82, 69, 6, 92, 11, 83, 80, - 69, 69, 68, 32, 84, 82, 65, 73, 78, 157, 200, 5, 6, 72, 69, 69, 76, 69, - 68, 5, 129, 186, 11, 14, 32, 87, 73, 84, 72, 32, 66, 85, 76, 76, 69, 84, - 32, 78, 200, 1, 112, 9, 68, 73, 71, 82, 65, 80, 72, 32, 89, 20, 7, 76, - 69, 84, 84, 69, 82, 32, 222, 172, 1, 86, 139, 185, 20, 73, 2, 243, 170, - 17, 79, 194, 1, 194, 1, 65, 74, 83, 206, 163, 1, 66, 162, 3, 78, 150, 2, - 68, 2, 71, 2, 72, 2, 75, 2, 77, 2, 80, 2, 82, 2, 84, 2, 90, 126, 87, 46, - 89, 142, 183, 22, 86, 234, 36, 69, 2, 73, 2, 79, 3, 85, 7, 37, 7, 82, 67, - 72, 65, 73, 67, 32, 4, 210, 225, 23, 87, 151, 14, 89, 42, 76, 5, 77, 65, - 76, 76, 32, 206, 133, 24, 65, 2, 69, 2, 73, 2, 79, 3, 85, 32, 170, 169, - 1, 87, 46, 89, 170, 173, 5, 75, 230, 137, 17, 84, 234, 36, 65, 2, 69, 2, - 73, 2, 79, 3, 85, 2, 139, 179, 8, 83, 108, 166, 1, 76, 52, 3, 78, 69, 89, - 46, 82, 146, 7, 84, 138, 1, 85, 154, 188, 16, 83, 246, 213, 2, 67, 156, - 192, 3, 6, 77, 79, 84, 72, 69, 84, 242, 164, 1, 79, 155, 3, 80, 6, 176, - 140, 16, 4, 76, 79, 87, 32, 247, 246, 7, 69, 4, 186, 147, 22, 66, 129, - 159, 1, 2, 32, 80, 66, 60, 8, 73, 90, 79, 78, 84, 65, 76, 32, 153, 6, 2, - 83, 69, 60, 218, 1, 66, 110, 76, 152, 1, 17, 79, 78, 69, 32, 69, 73, 71, - 72, 84, 72, 32, 66, 76, 79, 67, 75, 45, 88, 10, 83, 67, 65, 78, 32, 76, - 73, 78, 69, 45, 46, 84, 162, 217, 21, 67, 42, 69, 238, 6, 77, 150, 1, 82, - 247, 2, 90, 6, 44, 5, 76, 65, 67, 75, 32, 163, 199, 23, 65, 4, 38, 79, - 169, 199, 22, 3, 72, 69, 88, 2, 155, 199, 22, 67, 10, 40, 4, 73, 78, 69, - 32, 135, 223, 21, 65, 8, 44, 5, 87, 73, 84, 72, 32, 171, 223, 21, 69, 6, - 26, 84, 219, 224, 21, 70, 4, 250, 224, 21, 72, 171, 90, 73, 14, 136, 225, - 16, 3, 49, 51, 53, 158, 157, 7, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 55, 8, - 206, 253, 23, 49, 2, 51, 2, 55, 3, 57, 10, 32, 2, 65, 66, 223, 227, 21, - 82, 8, 26, 85, 223, 226, 21, 32, 6, 33, 6, 76, 65, 84, 73, 79, 78, 7, 11, - 32, 4, 188, 197, 9, 8, 87, 73, 84, 72, 32, 74, 85, 83, 223, 129, 14, 83, - 7, 11, 32, 4, 180, 191, 7, 2, 82, 65, 167, 255, 15, 70, 10, 26, 32, 235, - 241, 22, 69, 8, 86, 80, 240, 243, 18, 5, 66, 69, 86, 69, 82, 160, 80, 3, - 83, 80, 82, 215, 181, 4, 68, 2, 167, 230, 14, 69, 12, 48, 6, 82, 71, 76, - 65, 83, 83, 77, 2, 83, 69, 5, 249, 170, 20, 14, 32, 87, 73, 84, 72, 32, - 70, 76, 79, 87, 73, 78, 71, 32, 9, 11, 32, 6, 88, 8, 87, 73, 84, 72, 32, - 71, 65, 82, 217, 241, 21, 8, 66, 85, 73, 76, 68, 73, 78, 71, 2, 223, 164, - 22, 68, 7, 178, 248, 23, 74, 3, 83, 8, 106, 83, 248, 227, 22, 11, 78, 68, - 82, 69, 68, 32, 80, 79, 73, 78, 84, 148, 11, 2, 71, 71, 163, 136, 1, 84, - 2, 211, 230, 22, 72, 18, 90, 80, 224, 1, 5, 83, 84, 69, 82, 69, 236, 238, - 16, 2, 71, 73, 229, 130, 5, 2, 65, 67, 12, 60, 3, 72, 69, 78, 245, 158, - 4, 6, 79, 68, 73, 65, 83, 84, 11, 34, 32, 82, 65, 231, 238, 19, 45, 4, - 26, 87, 135, 150, 22, 66, 2, 21, 3, 73, 84, 72, 2, 185, 188, 3, 2, 32, - 68, 2, 177, 220, 12, 6, 84, 73, 79, 78, 32, 80, 2, 165, 225, 22, 2, 83, - 73, 206, 5, 160, 1, 3, 67, 69, 32, 152, 1, 2, 68, 69, 222, 24, 77, 222, - 2, 78, 200, 37, 7, 90, 65, 75, 65, 89, 65, 32, 129, 228, 19, 9, 32, 76, - 79, 86, 69, 32, 89, 79, 85, 8, 114, 67, 232, 161, 11, 18, 72, 79, 67, 75, - 69, 89, 32, 83, 84, 73, 67, 75, 32, 65, 78, 68, 32, 80, 159, 190, 1, 83, - 4, 230, 239, 15, 82, 163, 226, 2, 85, 246, 1, 68, 3, 78, 84, 73, 201, 1, - 9, 79, 71, 82, 65, 80, 72, 73, 67, 32, 8, 64, 4, 67, 65, 76, 32, 105, 8, - 70, 73, 67, 65, 84, 73, 79, 78, 6, 32, 2, 84, 79, 215, 239, 22, 87, 5, - 237, 242, 14, 12, 32, 65, 78, 68, 32, 83, 76, 65, 78, 84, 69, 68, 2, 141, - 217, 22, 2, 32, 67, 238, 1, 208, 2, 11, 65, 78, 78, 79, 84, 65, 84, 73, - 79, 78, 32, 242, 3, 67, 72, 2, 68, 69, 248, 5, 5, 78, 85, 77, 66, 69, 22, - 84, 128, 237, 5, 8, 72, 65, 76, 70, 32, 70, 73, 76, 148, 186, 1, 5, 69, - 78, 84, 69, 82, 0, 3, 82, 73, 83, 24, 5, 76, 69, 86, 69, 76, 140, 138, 9, - 5, 86, 65, 82, 73, 65, 182, 223, 4, 70, 158, 47, 73, 159, 228, 1, 83, 32, - 232, 1, 5, 66, 79, 84, 84, 79, 22, 70, 82, 77, 62, 84, 140, 1, 4, 76, 73, - 78, 75, 160, 143, 1, 4, 83, 69, 67, 79, 218, 158, 6, 79, 144, 134, 6, 6, - 82, 69, 86, 69, 82, 83, 240, 203, 9, 5, 72, 69, 65, 86, 69, 169, 39, 3, - 69, 65, 82, 2, 227, 169, 23, 77, 6, 48, 3, 79, 85, 82, 153, 160, 23, 3, - 73, 82, 83, 4, 142, 169, 23, 84, 27, 32, 4, 36, 3, 73, 68, 68, 155, 129, - 23, 65, 2, 167, 181, 13, 76, 8, 34, 72, 46, 87, 203, 130, 8, 79, 4, 194, - 142, 9, 82, 133, 143, 14, 2, 73, 82, 2, 243, 167, 23, 79, 4, 36, 3, 76, - 79, 83, 135, 151, 21, 79, 2, 181, 167, 23, 3, 73, 78, 71, 36, 104, 20, - 83, 67, 82, 73, 80, 84, 73, 79, 78, 32, 67, 72, 65, 82, 65, 67, 84, 69, - 82, 32, 159, 172, 7, 80, 34, 144, 2, 9, 65, 66, 79, 86, 69, 32, 84, 79, - 32, 84, 8, 76, 69, 70, 84, 32, 84, 79, 32, 76, 5, 79, 86, 69, 82, 76, 20, - 2, 83, 85, 182, 241, 14, 82, 252, 189, 5, 8, 70, 85, 76, 76, 32, 83, 85, - 82, 145, 228, 2, 15, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 82, 69, - 70, 76, 4, 60, 9, 77, 73, 68, 68, 76, 69, 32, 65, 78, 143, 199, 21, 66, - 2, 215, 183, 21, 68, 4, 128, 148, 22, 10, 77, 73, 68, 68, 76, 69, 32, 65, - 78, 68, 183, 166, 1, 82, 2, 247, 220, 16, 65, 18, 72, 12, 82, 82, 79, 85, - 78, 68, 32, 70, 82, 79, 77, 32, 147, 178, 17, 66, 16, 82, 76, 220, 203, - 11, 3, 85, 80, 80, 158, 249, 9, 66, 166, 161, 1, 65, 159, 82, 82, 6, 206, - 203, 11, 79, 219, 236, 11, 69, 2, 235, 213, 8, 82, 148, 1, 92, 10, 65, - 76, 76, 89, 32, 77, 65, 82, 75, 32, 41, 9, 69, 76, 69, 71, 82, 65, 80, - 72, 32, 10, 198, 241, 21, 70, 70, 84, 183, 86, 79, 138, 1, 140, 1, 11, - 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 141, 231, 12, 17, 76, 73, 78, - 69, 32, 70, 69, 69, 68, 32, 83, 69, 80, 65, 82, 65, 84, 136, 1, 182, 1, - 65, 58, 68, 200, 2, 5, 72, 79, 85, 82, 32, 214, 1, 74, 28, 4, 70, 69, 66, - 82, 64, 2, 77, 65, 148, 192, 15, 3, 78, 79, 86, 0, 4, 83, 69, 80, 84, 25, - 4, 79, 67, 84, 79, 4, 244, 244, 19, 3, 85, 71, 85, 169, 182, 1, 2, 80, - 82, 64, 44, 3, 65, 89, 32, 221, 196, 15, 2, 69, 67, 62, 66, 84, 162, 209, - 5, 69, 66, 70, 70, 78, 26, 83, 227, 241, 16, 79, 34, 34, 72, 90, 87, 239, - 140, 23, 69, 8, 36, 3, 73, 82, 84, 199, 237, 21, 82, 6, 26, 89, 251, 136, - 22, 69, 5, 155, 178, 22, 45, 24, 26, 69, 179, 220, 23, 79, 22, 36, 3, 78, - 84, 89, 183, 223, 22, 76, 21, 247, 158, 15, 45, 50, 78, 84, 254, 206, 5, - 69, 66, 70, 70, 78, 26, 83, 234, 155, 16, 90, 251, 85, 79, 20, 42, 87, - 218, 208, 5, 72, 195, 186, 17, 69, 14, 26, 69, 223, 218, 23, 79, 12, 36, - 3, 78, 84, 89, 227, 221, 22, 76, 11, 143, 154, 17, 45, 6, 24, 2, 65, 78, - 35, 85, 2, 11, 85, 2, 243, 162, 17, 65, 4, 142, 195, 23, 78, 143, 5, 76, - 4, 154, 183, 23, 82, 171, 34, 89, 68, 40, 6, 65, 71, 69, 32, 79, 70, 83, - 80, 5, 221, 131, 9, 15, 32, 79, 82, 32, 65, 80, 80, 82, 79, 88, 73, 77, - 65, 84, 69, 65, 65, 14, 69, 82, 73, 65, 76, 32, 65, 82, 65, 77, 65, 73, - 67, 32, 62, 72, 7, 78, 85, 77, 66, 69, 82, 32, 230, 18, 76, 221, 195, 19, - 2, 83, 69, 16, 26, 84, 167, 195, 15, 79, 10, 162, 183, 11, 87, 138, 148, - 1, 69, 143, 156, 9, 72, 136, 3, 202, 1, 67, 234, 1, 68, 214, 6, 70, 132, - 2, 5, 72, 73, 66, 73, 84, 156, 1, 15, 80, 85, 84, 32, 83, 89, 77, 66, 79, - 76, 32, 70, 79, 82, 32, 206, 1, 83, 236, 5, 2, 84, 69, 206, 8, 86, 251, - 250, 9, 66, 10, 32, 2, 79, 77, 69, 2, 82, 69, 4, 240, 202, 16, 3, 73, 78, - 71, 157, 225, 2, 5, 80, 76, 69, 84, 69, 6, 36, 3, 65, 83, 69, 195, 144, - 23, 77, 4, 34, 32, 185, 181, 10, 2, 83, 32, 2, 173, 183, 11, 8, 70, 79, - 78, 84, 32, 83, 73, 90, 145, 1, 24, 2, 69, 88, 103, 73, 5, 237, 185, 22, - 20, 32, 80, 79, 73, 78, 84, 73, 78, 71, 32, 65, 84, 32, 84, 72, 69, 32, - 86, 73, 69, 138, 1, 72, 8, 67, 32, 83, 73, 89, 65, 81, 32, 249, 254, 17, - 4, 65, 78, 32, 82, 136, 1, 196, 1, 11, 65, 76, 84, 69, 82, 78, 65, 84, - 69, 32, 76, 2, 76, 28, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 100, 7, 78, - 85, 77, 66, 69, 82, 32, 190, 243, 8, 82, 149, 125, 6, 80, 76, 65, 67, 69, - 72, 2, 157, 142, 23, 2, 65, 75, 6, 68, 4, 79, 78, 69, 32, 137, 206, 21, - 7, 84, 72, 82, 69, 69, 32, 81, 4, 222, 203, 21, 72, 47, 81, 122, 212, 1, - 10, 65, 76, 84, 69, 82, 78, 65, 84, 69, 32, 72, 5, 75, 65, 82, 79, 82, 0, - 4, 76, 65, 75, 72, 198, 138, 10, 69, 66, 70, 94, 78, 26, 83, 78, 84, 240, - 130, 5, 8, 80, 82, 69, 70, 73, 88, 69, 68, 199, 41, 79, 6, 26, 84, 211, - 179, 22, 79, 4, 244, 160, 6, 2, 69, 78, 147, 141, 17, 87, 5, 239, 252, - 22, 65, 16, 72, 5, 73, 78, 73, 84, 89, 85, 9, 79, 82, 77, 65, 84, 73, 79, - 78, 32, 5, 45, 9, 32, 78, 69, 71, 65, 84, 69, 68, 32, 2, 157, 168, 8, 4, - 87, 73, 84, 72, 12, 42, 83, 137, 203, 19, 4, 68, 69, 83, 75, 10, 192, - 149, 7, 5, 69, 80, 65, 82, 65, 139, 252, 9, 79, 4, 11, 32, 4, 152, 249, - 22, 15, 65, 82, 65, 66, 73, 67, 32, 70, 79, 82, 77, 32, 83, 72, 65, 1, + 220, 147, 4, 3, 67, 72, 73, 201, 144, 23, 3, 89, 73, 90, 6, 48, 4, 69, + 82, 69, 84, 229, 208, 26, 2, 73, 70, 5, 17, 2, 45, 72, 2, 229, 164, 27, + 2, 73, 68, 4, 176, 208, 26, 2, 69, 78, 163, 2, 85, 2, 137, 162, 4, 3, 73, + 75, 82, 12, 96, 2, 82, 79, 192, 159, 11, 3, 78, 79, 77, 129, 173, 15, 9, + 76, 69, 82, 32, 67, 79, 78, 83, 84, 8, 92, 5, 80, 69, 65, 78, 32, 144, + 161, 24, 8, 45, 67, 85, 82, 82, 69, 78, 67, 215, 175, 2, 32, 4, 202, 142, + 4, 67, 19, 80, 50, 30, 67, 102, 80, 187, 1, 84, 6, 60, 9, 76, 65, 77, 65, + 84, 73, 79, 78, 32, 139, 190, 26, 69, 4, 246, 129, 25, 81, 187, 147, 2, + 77, 10, 96, 7, 76, 79, 83, 73, 79, 78, 32, 181, 152, 27, 11, 82, 69, 83, + 83, 73, 79, 78, 76, 69, 83, 83, 8, 212, 223, 11, 4, 70, 82, 65, 77, 145, + 166, 15, 8, 65, 84, 32, 72, 79, 82, 73, 90, 34, 98, 82, 233, 197, 21, 18, + 69, 78, 68, 69, 68, 32, 65, 82, 65, 66, 73, 67, 45, 73, 78, 68, 73, 67, + 14, 140, 1, 12, 69, 77, 69, 76, 89, 32, 72, 69, 65, 86, 89, 32, 137, 253, + 25, 16, 65, 84, 69, 82, 82, 69, 83, 84, 82, 73, 65, 76, 32, 65, 76, 73, + 12, 50, 83, 134, 185, 25, 70, 234, 2, 87, 203, 11, 71, 4, 150, 186, 25, + 65, 43, 73, 7, 250, 186, 19, 71, 195, 151, 8, 83, 152, 4, 142, 1, 65, + 130, 19, 69, 190, 1, 73, 134, 8, 76, 138, 6, 79, 142, 7, 82, 130, 5, 85, + 252, 201, 20, 2, 86, 83, 242, 203, 4, 83, 199, 140, 2, 70, 92, 122, 67, + 178, 15, 76, 176, 2, 2, 88, 32, 170, 148, 3, 77, 252, 253, 5, 2, 82, 83, + 140, 251, 1, 2, 84, 72, 151, 235, 9, 73, 70, 72, 2, 69, 32, 180, 187, 16, + 4, 83, 73, 77, 73, 165, 206, 4, 2, 84, 79, 66, 226, 1, 83, 160, 1, 4, 87, + 73, 84, 72, 196, 136, 13, 2, 80, 65, 252, 136, 2, 2, 77, 65, 164, 162, + 11, 13, 84, 72, 82, 79, 87, 73, 78, 71, 32, 65, 32, 75, 73, 201, 1, 14, + 72, 79, 76, 68, 73, 78, 71, 32, 66, 65, 67, 75, 32, 84, 4, 216, 138, 17, + 18, 65, 86, 79, 85, 82, 73, 78, 71, 32, 68, 69, 76, 73, 67, 73, 79, 85, + 83, 141, 138, 5, 13, 67, 82, 69, 65, 77, 73, 78, 71, 32, 73, 78, 32, 70, + 54, 38, 32, 141, 167, 24, 3, 79, 85, 84, 52, 196, 4, 2, 67, 79, 44, 5, + 72, 69, 65, 68, 45, 38, 77, 98, 79, 92, 7, 78, 79, 32, 71, 79, 79, 68, + 238, 1, 80, 164, 1, 16, 83, 84, 85, 67, 75, 45, 79, 85, 84, 32, 84, 79, + 78, 71, 85, 69, 110, 84, 204, 183, 1, 9, 66, 65, 71, 83, 32, 85, 78, 68, + 69, 212, 171, 17, 22, 70, 73, 78, 71, 69, 82, 32, 67, 79, 86, 69, 82, 73, + 78, 71, 32, 67, 76, 79, 83, 69, 68, 244, 67, 3, 82, 79, 76, 180, 231, 1, + 13, 76, 79, 79, 75, 32, 79, 70, 32, 84, 82, 73, 85, 77, 244, 141, 3, 8, + 68, 73, 65, 71, 79, 78, 65, 76, 1, 20, 85, 78, 69, 86, 69, 78, 32, 69, + 89, 69, 83, 32, 65, 78, 68, 32, 87, 65, 86, 89, 4, 252, 4, 3, 87, 66, 79, + 227, 167, 19, 76, 2, 249, 183, 22, 4, 66, 65, 78, 68, 4, 60, 6, 69, 68, + 73, 67, 65, 76, 185, 242, 25, 3, 79, 78, 79, 2, 181, 255, 25, 3, 32, 77, + 65, 12, 90, 75, 36, 4, 80, 69, 78, 32, 213, 180, 20, 10, 78, 69, 32, 69, + 89, 69, 66, 82, 79, 87, 2, 241, 166, 22, 4, 32, 71, 69, 83, 8, 116, 5, + 77, 79, 85, 84, 72, 157, 159, 24, 18, 69, 89, 69, 83, 32, 65, 78, 68, 32, + 72, 65, 78, 68, 32, 79, 86, 69, 82, 7, 11, 32, 4, 184, 137, 10, 3, 86, + 79, 77, 221, 159, 9, 5, 65, 78, 68, 32, 67, 6, 132, 1, 18, 65, 82, 84, + 89, 32, 72, 79, 82, 78, 32, 65, 78, 68, 32, 80, 65, 82, 84, 100, 2, 69, + 69, 197, 167, 19, 4, 76, 69, 65, 68, 2, 229, 208, 22, 2, 89, 32, 7, 29, + 5, 32, 65, 78, 68, 32, 4, 36, 3, 87, 73, 78, 231, 167, 19, 84, 2, 169, + 183, 1, 4, 75, 73, 78, 71, 4, 50, 69, 193, 212, 22, 6, 72, 69, 82, 77, + 79, 77, 2, 181, 175, 27, 8, 65, 82, 83, 32, 79, 70, 32, 74, 10, 34, 76, + 133, 171, 22, 2, 65, 70, 8, 84, 13, 73, 78, 71, 32, 68, 73, 65, 71, 79, + 78, 65, 76, 32, 129, 242, 23, 2, 69, 78, 6, 128, 1, 9, 67, 82, 79, 83, + 83, 73, 78, 71, 32, 201, 186, 19, 16, 73, 78, 32, 87, 72, 73, 84, 69, 32, + 67, 73, 82, 67, 76, 69, 32, 4, 164, 148, 16, 3, 82, 73, 83, 227, 173, 3, + 78, 4, 218, 130, 15, 73, 131, 143, 4, 77, 14, 50, 65, 50, 77, 44, 2, 82, + 82, 147, 236, 18, 78, 4, 232, 174, 8, 3, 82, 70, 85, 147, 237, 9, 84, 4, + 228, 246, 8, 2, 73, 78, 179, 178, 7, 65, 4, 220, 246, 7, 2, 73, 83, 151, + 198, 19, 89, 58, 138, 1, 71, 90, 76, 178, 1, 78, 98, 82, 182, 2, 83, 164, + 14, 4, 86, 69, 32, 68, 217, 255, 4, 10, 69, 76, 68, 32, 72, 79, 67, 75, + 69, 89, 6, 48, 4, 85, 82, 69, 32, 245, 140, 26, 2, 72, 84, 4, 242, 207, + 25, 68, 235, 172, 1, 83, 10, 32, 2, 69, 32, 65, 2, 77, 32, 6, 242, 200, + 13, 70, 140, 155, 2, 3, 67, 65, 66, 147, 165, 8, 83, 4, 52, 4, 80, 82, + 79, 74, 173, 161, 20, 3, 70, 82, 65, 2, 251, 217, 15, 69, 4, 72, 4, 71, + 69, 82, 80, 221, 174, 25, 8, 73, 84, 69, 32, 80, 65, 82, 84, 2, 195, 141, + 16, 82, 22, 34, 69, 189, 1, 3, 83, 84, 32, 13, 56, 2, 32, 69, 68, 4, 87, + 79, 82, 75, 251, 184, 15, 67, 4, 222, 192, 13, 78, 193, 213, 4, 8, 88, + 84, 73, 78, 71, 85, 73, 83, 4, 216, 201, 23, 6, 32, 83, 80, 65, 82, 75, + 215, 237, 3, 83, 10, 186, 177, 5, 81, 172, 184, 10, 8, 83, 84, 82, 79, + 78, 71, 32, 73, 223, 225, 6, 80, 10, 38, 72, 165, 229, 23, 3, 84, 69, 68, + 9, 128, 255, 3, 13, 73, 78, 71, 32, 80, 79, 76, 69, 32, 65, 78, 68, 32, + 174, 209, 5, 69, 213, 222, 16, 19, 32, 67, 65, 75, 69, 32, 87, 73, 84, + 72, 32, 83, 87, 73, 82, 76, 32, 68, 69, 46, 50, 65, 170, 1, 69, 98, 79, + 194, 1, 85, 39, 89, 12, 114, 84, 236, 163, 4, 5, 80, 80, 73, 78, 71, 192, + 159, 3, 6, 71, 32, 73, 78, 32, 72, 161, 224, 17, 3, 77, 73, 78, 6, 190, + 221, 8, 32, 250, 203, 11, 66, 135, 241, 5, 78, 4, 196, 250, 23, 8, 88, + 69, 68, 32, 66, 73, 67, 69, 153, 145, 1, 7, 85, 82, 45, 68, 69, 45, 76, + 12, 52, 2, 82, 65, 20, 3, 87, 69, 82, 139, 234, 25, 80, 5, 147, 170, 26, + 76, 7, 17, 2, 32, 80, 4, 58, 85, 209, 207, 24, 8, 76, 65, 89, 73, 78, 71, + 32, 67, 2, 181, 199, 26, 4, 78, 67, 84, 85, 4, 190, 158, 3, 83, 183, 251, + 23, 84, 15, 25, 4, 73, 78, 71, 32, 12, 64, 6, 83, 65, 85, 67, 69, 82, + 210, 143, 10, 68, 155, 136, 10, 69, 9, 11, 32, 6, 40, 4, 87, 73, 84, 72, + 227, 153, 26, 83, 4, 34, 32, 1, 4, 79, 85, 84, 32, 2, 21, 3, 66, 69, 65, + 2, 243, 240, 26, 77, 56, 102, 71, 20, 2, 76, 68, 68, 2, 79, 84, 22, 82, + 142, 2, 85, 128, 155, 23, 2, 78, 68, 191, 210, 3, 88, 5, 139, 156, 27, + 71, 4, 156, 205, 9, 8, 73, 78, 71, 32, 72, 65, 78, 68, 199, 167, 17, 69, + 5, 195, 161, 14, 80, 18, 78, 75, 132, 1, 3, 84, 85, 78, 134, 224, 20, 77, + 222, 192, 4, 32, 179, 116, 67, 8, 80, 10, 32, 65, 78, 68, 32, 75, 78, 73, + 70, 69, 242, 164, 15, 69, 223, 181, 11, 73, 5, 201, 222, 15, 7, 32, 87, + 73, 84, 72, 32, 80, 4, 224, 143, 27, 6, 69, 32, 67, 79, 79, 75, 179, 27, + 65, 22, 26, 82, 199, 190, 23, 78, 20, 38, 32, 218, 2, 84, 223, 239, 18, + 45, 16, 110, 67, 174, 1, 68, 182, 170, 2, 66, 216, 155, 10, 7, 76, 69, + 65, 70, 32, 67, 76, 186, 111, 84, 235, 215, 11, 80, 4, 148, 183, 13, 3, + 76, 85, 66, 181, 86, 32, 79, 82, 78, 69, 82, 32, 65, 82, 82, 79, 87, 83, + 32, 67, 73, 82, 67, 76, 73, 78, 71, 32, 65, 78, 84, 73, 67, 76, 79, 67, + 75, 87, 4, 21, 3, 79, 84, 32, 4, 246, 225, 23, 80, 195, 132, 3, 77, 2, + 231, 43, 72, 30, 78, 65, 250, 1, 69, 98, 79, 133, 131, 17, 8, 73, 69, 68, + 32, 83, 72, 82, 73, 12, 96, 6, 67, 84, 73, 79, 78, 32, 68, 8, 77, 69, 32, + 87, 73, 84, 72, 32, 193, 242, 10, 2, 71, 73, 4, 166, 129, 20, 83, 177, 6, + 9, 78, 85, 77, 69, 82, 65, 84, 79, 82, 6, 50, 80, 218, 170, 2, 65, 149, + 185, 21, 2, 84, 73, 2, 185, 134, 22, 2, 73, 67, 6, 48, 6, 78, 67, 72, 32, + 70, 82, 139, 142, 19, 69, 4, 174, 142, 26, 73, 133, 15, 3, 65, 78, 67, + 10, 52, 3, 78, 84, 45, 116, 2, 87, 78, 191, 229, 26, 71, 4, 70, 84, 217, + 143, 2, 11, 70, 65, 67, 73, 78, 71, 32, 66, 65, 66, 89, 2, 189, 191, 12, + 6, 73, 76, 84, 69, 68, 32, 5, 185, 147, 8, 6, 73, 78, 71, 32, 70, 65, + 226, 1, 80, 2, 76, 76, 134, 6, 78, 208, 250, 16, 5, 69, 76, 32, 80, 85, + 179, 138, 10, 83, 216, 1, 42, 32, 73, 6, 87, 73, 68, 84, 72, 32, 10, 234, + 140, 12, 77, 136, 171, 3, 2, 79, 85, 170, 247, 8, 66, 151, 29, 83, 206, + 1, 242, 1, 67, 42, 76, 78, 78, 30, 80, 66, 82, 142, 1, 83, 38, 89, 130, + 159, 10, 77, 174, 213, 10, 65, 158, 2, 68, 58, 69, 98, 71, 118, 72, 202, + 4, 81, 198, 153, 2, 87, 182, 29, 84, 162, 146, 1, 70, 224, 177, 1, 6, 66, + 82, 79, 75, 69, 78, 211, 7, 86, 10, 162, 248, 20, 73, 62, 79, 131, 81, + 69, 116, 42, 69, 214, 251, 20, 65, 231, 183, 4, 79, 10, 162, 1, 70, 199, + 253, 20, 83, 4, 166, 210, 21, 79, 35, 85, 6, 42, 79, 198, 254, 20, 69, + 211, 236, 2, 76, 2, 223, 177, 25, 85, 10, 36, 3, 73, 71, 72, 207, 131, + 25, 69, 8, 17, 2, 84, 32, 8, 140, 181, 20, 5, 87, 72, 73, 84, 69, 246, + 220, 2, 67, 210, 3, 80, 239, 7, 83, 4, 250, 204, 23, 69, 139, 184, 1, 79, + 2, 223, 159, 25, 69, 6, 128, 205, 11, 8, 67, 84, 73, 79, 78, 32, 65, 80, + 208, 252, 8, 5, 69, 82, 65, 76, 32, 211, 188, 1, 78, 130, 21, 114, 65, + 250, 6, 69, 222, 22, 73, 162, 1, 76, 134, 15, 79, 198, 6, 82, 178, 92, + 85, 138, 155, 22, 72, 131, 238, 3, 83, 142, 1, 42, 82, 149, 254, 26, 4, + 77, 69, 32, 68, 140, 1, 36, 3, 65, 89, 32, 255, 238, 25, 76, 138, 1, 166, + 1, 67, 210, 1, 83, 192, 2, 6, 86, 79, 87, 69, 76, 32, 172, 178, 8, 6, 82, + 69, 68, 85, 80, 76, 194, 208, 10, 72, 238, 168, 1, 80, 214, 181, 3, 77, + 171, 190, 1, 68, 52, 42, 79, 205, 1, 5, 65, 80, 73, 84, 65, 8, 88, 10, + 77, 66, 73, 78, 73, 78, 71, 32, 68, 79, 37, 8, 78, 83, 79, 78, 65, 78, + 84, 32, 4, 234, 148, 12, 85, 247, 132, 14, 84, 4, 178, 149, 12, 78, 171, + 161, 11, 71, 46, 36, 3, 77, 65, 76, 171, 146, 22, 85, 44, 45, 9, 76, 32, + 76, 69, 84, 84, 69, 82, 32, 44, 200, 1, 4, 79, 76, 68, 32, 214, 155, 20, + 78, 238, 245, 6, 66, 2, 67, 2, 68, 2, 70, 2, 71, 2, 72, 2, 74, 2, 75, 2, + 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, 88, 2, 89, 187, 2, 65, + 4, 190, 145, 27, 75, 3, 78, 12, 44, 5, 83, 73, 71, 78, 32, 179, 209, 26, + 76, 10, 138, 211, 26, 69, 162, 64, 65, 2, 73, 3, 79, 146, 3, 112, 2, 65, + 82, 110, 77, 50, 79, 160, 218, 23, 9, 82, 77, 65, 78, 32, 80, 69, 78, 78, + 174, 177, 2, 84, 239, 105, 78, 7, 29, 5, 32, 87, 73, 84, 72, 4, 224, 160, + 14, 5, 79, 85, 84, 32, 72, 233, 175, 9, 5, 32, 72, 65, 78, 68, 4, 26, 32, + 167, 140, 22, 73, 2, 207, 155, 23, 83, 130, 3, 46, 77, 245, 5, 6, 82, 71, + 73, 65, 78, 32, 38, 92, 13, 65, 78, 84, 73, 67, 32, 70, 73, 71, 85, 82, + 69, 32, 205, 4, 5, 69, 84, 82, 73, 67, 32, 158, 1, 65, 82, 67, 172, 1, 9, + 70, 79, 82, 84, 85, 78, 65, 32, 77, 44, 3, 76, 65, 69, 0, 4, 84, 82, 73, + 83, 34, 80, 80, 3, 82, 85, 66, 167, 210, 10, 86, 6, 216, 1, 6, 67, 81, + 85, 73, 83, 73, 12, 4, 77, 73, 83, 83, 235, 166, 23, 76, 8, 42, 65, 97, + 6, 79, 78, 74, 85, 78, 67, 6, 56, 3, 80, 85, 84, 0, 3, 85, 68, 65, 155, + 188, 18, 82, 2, 165, 90, 5, 32, 68, 82, 65, 67, 2, 11, 84, 2, 215, 237, + 26, 73, 4, 206, 167, 2, 73, 129, 172, 24, 2, 65, 74, 2, 145, 211, 10, 3, + 84, 73, 84, 6, 44, 2, 85, 69, 177, 128, 23, 3, 79, 80, 85, 4, 162, 233, + 26, 76, 155, 34, 82, 2, 183, 130, 25, 69, 6, 252, 135, 20, 4, 65, 76, 76, + 89, 137, 228, 1, 5, 32, 80, 82, 79, 80, 220, 2, 228, 1, 6, 67, 65, 80, + 73, 84, 65, 0, 4, 83, 77, 65, 76, 172, 3, 7, 76, 69, 84, 84, 69, 82, 32, + 180, 2, 24, 77, 84, 65, 86, 82, 85, 76, 73, 32, 67, 65, 80, 73, 84, 65, + 76, 32, 76, 69, 84, 84, 69, 82, 32, 165, 6, 2, 80, 65, 80, 45, 9, 76, 32, + 76, 69, 84, 84, 69, 82, 32, 80, 142, 2, 65, 34, 72, 166, 5, 67, 118, 71, + 130, 1, 74, 34, 75, 82, 80, 34, 83, 94, 90, 252, 181, 5, 2, 84, 65, 162, + 149, 8, 76, 226, 180, 2, 82, 218, 176, 9, 66, 2, 77, 2, 88, 226, 40, 78, + 2, 81, 234, 35, 86, 234, 47, 68, 14, 69, 2, 73, 2, 79, 2, 85, 2, 89, 143, + 57, 87, 4, 178, 182, 26, 69, 227, 79, 78, 10, 46, 65, 242, 238, 26, 73, + 2, 79, 215, 22, 69, 4, 194, 133, 27, 69, 3, 82, 94, 254, 1, 85, 178, 2, + 65, 42, 67, 74, 69, 46, 71, 34, 72, 98, 74, 34, 75, 34, 76, 50, 80, 34, + 83, 34, 84, 62, 90, 254, 255, 15, 82, 218, 176, 9, 66, 2, 77, 2, 88, 226, + 40, 78, 2, 81, 234, 35, 86, 234, 47, 68, 14, 73, 2, 79, 2, 89, 142, 57, + 87, 255, 2, 70, 4, 136, 139, 22, 4, 45, 66, 82, 74, 159, 248, 4, 78, 92, + 250, 1, 65, 42, 67, 74, 69, 46, 71, 34, 72, 98, 74, 34, 75, 34, 76, 50, + 80, 34, 83, 34, 84, 62, 90, 254, 255, 15, 82, 218, 176, 9, 66, 2, 77, 2, + 88, 226, 40, 78, 2, 81, 234, 35, 86, 234, 47, 68, 14, 73, 2, 79, 2, 85, + 2, 89, 142, 57, 87, 255, 2, 70, 6, 150, 177, 26, 69, 2, 73, 227, 79, 78, + 8, 38, 72, 218, 244, 25, 73, 243, 59, 65, 4, 198, 176, 26, 73, 135, 23, + 65, 4, 156, 144, 9, 2, 76, 73, 235, 239, 17, 78, 4, 190, 179, 25, 72, + 191, 124, 65, 12, 46, 65, 186, 232, 26, 73, 2, 79, 215, 22, 69, 6, 26, + 82, 243, 254, 26, 69, 5, 239, 247, 25, 68, 4, 190, 178, 25, 72, 207, 64, + 73, 4, 254, 218, 25, 72, 223, 83, 65, 4, 11, 65, 4, 198, 218, 15, 66, + 203, 163, 11, 83, 4, 174, 218, 25, 72, 227, 106, 65, 4, 246, 253, 25, 72, + 247, 47, 65, 6, 176, 184, 3, 6, 85, 82, 78, 69, 68, 32, 135, 254, 1, 65, + 4, 178, 217, 25, 72, 223, 83, 69, 2, 181, 179, 20, 7, 82, 65, 71, 82, 65, + 80, 72, 10, 48, 2, 77, 69, 20, 4, 78, 71, 69, 82, 31, 82, 2, 167, 230, + 25, 76, 2, 133, 197, 18, 2, 32, 82, 6, 38, 76, 149, 243, 13, 3, 65, 70, + 70, 5, 207, 229, 25, 83, 202, 1, 66, 65, 214, 13, 79, 185, 171, 26, 7, + 69, 73, 67, 72, 32, 83, 84, 194, 1, 84, 8, 71, 79, 76, 73, 84, 73, 67, + 32, 229, 12, 8, 83, 83, 32, 79, 70, 32, 77, 73, 192, 1, 56, 6, 67, 65, + 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 96, 45, 9, 76, 32, 76, 69, 84, 84, + 69, 82, 32, 96, 206, 1, 65, 22, 66, 42, 67, 94, 68, 94, 70, 38, 71, 46, + 73, 138, 2, 76, 58, 77, 66, 78, 34, 79, 30, 80, 58, 82, 30, 83, 186, 1, + 84, 110, 86, 22, 89, 90, 90, 234, 145, 19, 72, 190, 133, 2, 85, 139, 183, + 5, 75, 2, 179, 210, 26, 90, 4, 214, 3, 73, 233, 225, 26, 2, 85, 75, 4, + 48, 8, 65, 85, 68, 65, 84, 69, 32, 67, 15, 72, 2, 11, 72, 2, 233, 135, + 20, 2, 82, 73, 6, 42, 74, 30, 79, 237, 210, 26, 2, 90, 69, 2, 161, 135, + 20, 2, 69, 82, 2, 187, 131, 25, 66, 4, 210, 156, 21, 82, 139, 180, 5, 73, + 2, 21, 3, 76, 65, 71, 2, 139, 241, 21, 79, 13, 38, 78, 54, 79, 141, 1, 2, + 90, 72, 2, 161, 199, 26, 8, 73, 84, 73, 65, 76, 32, 73, 90, 4, 33, 6, 84, + 65, 84, 69, 68, 32, 4, 26, 66, 25, 2, 83, 77, 2, 11, 73, 2, 35, 71, 2, + 21, 3, 65, 76, 76, 2, 165, 234, 24, 2, 32, 89, 4, 158, 240, 26, 73, 211, + 2, 69, 4, 52, 9, 65, 84, 73, 78, 65, 84, 69, 32, 77, 35, 74, 2, 141, 141, + 11, 3, 89, 83, 76, 2, 161, 148, 9, 3, 85, 68, 73, 2, 11, 65, 2, 211, 153, + 21, 83, 4, 206, 204, 26, 78, 3, 84, 4, 26, 79, 131, 241, 26, 69, 2, 245, + 208, 22, 2, 75, 79, 2, 237, 253, 21, 2, 73, 84, 14, 106, 72, 58, 76, 148, + 248, 13, 6, 80, 73, 68, 69, 82, 89, 173, 191, 10, 8, 77, 65, 76, 76, 32, + 89, 85, 83, 6, 32, 2, 84, 65, 187, 239, 26, 65, 5, 155, 197, 25, 80, 2, + 255, 131, 20, 79, 6, 78, 86, 196, 165, 22, 9, 82, 79, 75, 85, 84, 65, 83, + 84, 73, 167, 181, 4, 83, 2, 253, 174, 19, 2, 82, 73, 2, 175, 219, 24, 69, + 12, 50, 69, 222, 129, 19, 65, 130, 236, 7, 79, 3, 85, 6, 146, 149, 21, + 83, 147, 152, 5, 82, 4, 196, 152, 9, 3, 69, 77, 76, 221, 139, 16, 4, 72, + 73, 86, 69, 2, 223, 233, 26, 76, 6, 196, 246, 11, 13, 66, 69, 32, 87, 73, + 84, 72, 32, 77, 69, 82, 73, 68, 230, 200, 4, 87, 183, 151, 9, 86, 68, + 162, 1, 65, 44, 12, 84, 72, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 222, + 174, 18, 82, 222, 102, 71, 228, 141, 5, 3, 78, 71, 71, 238, 187, 1, 79, + 185, 77, 2, 76, 70, 4, 196, 191, 15, 2, 76, 32, 147, 171, 11, 84, 54, + 210, 2, 65, 50, 72, 46, 73, 46, 78, 46, 80, 2, 81, 40, 2, 82, 65, 22, 84, + 236, 144, 9, 2, 87, 73, 194, 152, 12, 85, 244, 69, 3, 70, 65, 73, 204, 7, + 4, 66, 65, 73, 82, 248, 21, 2, 79, 84, 150, 30, 68, 166, 128, 1, 77, 198, + 147, 1, 69, 164, 30, 3, 76, 65, 71, 148, 41, 3, 83, 65, 85, 230, 161, 1, + 74, 196, 16, 2, 71, 73, 141, 12, 2, 75, 85, 4, 240, 222, 24, 3, 73, 72, + 86, 163, 134, 2, 72, 4, 186, 232, 13, 87, 157, 243, 11, 2, 65, 71, 4, + 138, 146, 9, 85, 241, 245, 14, 2, 71, 71, 6, 202, 214, 15, 73, 241, 140, + 9, 2, 65, 85, 2, 225, 161, 26, 5, 65, 73, 82, 84, 72, 2, 247, 192, 26, + 73, 4, 248, 192, 23, 2, 72, 73, 237, 69, 2, 69, 73, 234, 9, 46, 65, 198, + 5, 69, 206, 82, 73, 151, 3, 79, 152, 1, 96, 7, 68, 85, 65, 84, 73, 79, + 78, 32, 5, 78, 84, 72, 65, 32, 162, 192, 20, 86, 219, 141, 5, 80, 2, 11, + 32, 2, 135, 209, 25, 67, 146, 1, 120, 7, 76, 69, 84, 84, 69, 82, 32, 212, + 2, 5, 83, 73, 71, 78, 32, 154, 255, 22, 65, 248, 8, 2, 86, 79, 195, 199, + 3, 79, 100, 214, 1, 86, 178, 131, 23, 65, 38, 68, 114, 84, 230, 5, 85, + 186, 202, 1, 73, 42, 76, 226, 195, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, + 2, 74, 2, 75, 2, 80, 206, 40, 79, 162, 8, 69, 158, 20, 72, 2, 77, 2, 82, + 3, 89, 14, 60, 5, 69, 68, 73, 67, 32, 138, 138, 23, 79, 223, 214, 3, 65, + 4, 188, 167, 24, 6, 68, 79, 85, 66, 76, 69, 175, 244, 1, 65, 16, 66, 67, + 230, 194, 22, 78, 190, 66, 65, 182, 1, 80, 135, 150, 3, 86, 4, 238, 245, + 7, 79, 163, 204, 14, 65, 192, 8, 76, 10, 65, 84, 69, 82, 45, 84, 72, 65, + 78, 32, 206, 7, 69, 231, 207, 25, 89, 56, 134, 1, 65, 150, 3, 66, 62, 79, + 216, 2, 11, 69, 81, 85, 65, 76, 32, 84, 79, 32, 79, 82, 130, 208, 6, 67, + 138, 4, 87, 207, 252, 18, 83, 16, 44, 5, 66, 79, 86, 69, 32, 223, 212, 6, + 78, 12, 150, 1, 83, 180, 1, 19, 68, 79, 85, 66, 76, 69, 45, 76, 73, 78, + 69, 32, 69, 81, 85, 65, 76, 32, 65, 132, 207, 6, 4, 76, 69, 83, 83, 235, + 233, 18, 82, 6, 148, 1, 7, 73, 77, 73, 76, 65, 82, 32, 133, 210, 6, 23, + 76, 65, 78, 84, 69, 68, 32, 69, 81, 85, 65, 76, 32, 65, 66, 79, 86, 69, + 32, 76, 69, 83, 83, 4, 26, 65, 219, 209, 6, 79, 2, 65, 3, 66, 79, 86, 6, + 40, 4, 69, 83, 73, 68, 195, 210, 6, 85, 2, 231, 2, 69, 20, 40, 2, 82, 32, + 245, 1, 3, 86, 69, 82, 16, 120, 16, 83, 76, 65, 78, 84, 69, 68, 32, 69, + 81, 85, 65, 76, 32, 84, 79, 138, 212, 6, 65, 242, 129, 13, 69, 167, 237, + 4, 76, 9, 49, 10, 32, 87, 73, 84, 72, 32, 68, 79, 84, 32, 6, 44, 5, 65, + 66, 79, 86, 69, 151, 166, 18, 73, 5, 207, 165, 26, 32, 4, 52, 7, 76, 65, + 80, 80, 73, 78, 71, 239, 245, 19, 32, 2, 233, 193, 24, 2, 32, 76, 134, 8, + 36, 2, 75, 32, 185, 73, 2, 78, 32, 254, 7, 130, 3, 65, 216, 15, 8, 67, + 65, 80, 73, 84, 65, 76, 32, 182, 11, 68, 134, 1, 70, 68, 2, 73, 78, 222, + 3, 75, 138, 1, 76, 174, 3, 78, 66, 77, 84, 3, 88, 69, 83, 22, 79, 202, 1, + 80, 90, 82, 182, 1, 83, 130, 22, 84, 200, 2, 13, 85, 80, 83, 73, 76, 79, + 78, 32, 87, 73, 84, 72, 32, 150, 1, 86, 142, 2, 89, 178, 232, 7, 66, 212, + 176, 3, 4, 71, 82, 65, 77, 204, 23, 2, 90, 69, 243, 136, 12, 81, 112, 92, + 10, 67, 82, 79, 80, 72, 79, 78, 73, 67, 32, 172, 14, 6, 78, 79, 32, 84, + 69, 76, 23, 82, 106, 188, 2, 6, 65, 84, 84, 73, 67, 32, 222, 5, 67, 92, + 3, 78, 65, 88, 32, 12, 68, 69, 76, 80, 72, 73, 67, 32, 70, 73, 86, 69, 0, + 14, 83, 84, 82, 65, 84, 73, 65, 78, 32, 70, 73, 70, 84, 89, 40, 11, 69, + 80, 73, 68, 65, 85, 82, 69, 65, 78, 32, 112, 3, 72, 69, 82, 164, 1, 9, + 77, 69, 83, 83, 69, 78, 73, 65, 78, 35, 84, 48, 72, 2, 70, 73, 180, 2, 4, + 79, 78, 69, 32, 205, 1, 4, 84, 69, 78, 32, 26, 36, 3, 70, 84, 89, 105, 2, + 86, 69, 11, 11, 32, 8, 22, 84, 171, 4, 83, 6, 48, 7, 72, 79, 85, 83, 65, + 78, 68, 215, 3, 65, 5, 231, 3, 32, 17, 11, 32, 14, 56, 7, 72, 85, 78, 68, + 82, 69, 68, 18, 84, 143, 3, 83, 7, 131, 2, 32, 6, 48, 7, 72, 79, 85, 83, + 65, 78, 68, 187, 2, 65, 5, 213, 1, 2, 32, 84, 14, 98, 72, 48, 7, 84, 72, + 79, 85, 83, 65, 78, 210, 198, 24, 81, 217, 228, 1, 5, 68, 82, 65, 67, 72, + 6, 44, 5, 85, 78, 68, 82, 69, 179, 198, 24, 65, 4, 17, 2, 68, 32, 4, 22, + 84, 131, 1, 83, 2, 95, 65, 8, 30, 84, 86, 83, 175, 1, 77, 4, 50, 65, 21, + 8, 72, 79, 85, 83, 65, 78, 68, 32, 2, 187, 186, 16, 76, 2, 11, 83, 2, + 181, 199, 24, 2, 84, 65, 4, 88, 5, 65, 82, 89, 83, 84, 145, 1, 12, 89, + 82, 69, 78, 65, 73, 67, 32, 84, 87, 79, 32, 2, 101, 5, 73, 65, 78, 32, + 70, 2, 17, 2, 32, 77, 2, 139, 152, 13, 78, 6, 30, 70, 29, 3, 84, 87, 79, + 2, 225, 186, 15, 2, 73, 86, 5, 11, 32, 2, 185, 152, 10, 5, 68, 82, 65, + 67, 72, 8, 112, 8, 77, 73, 79, 78, 73, 65, 78, 32, 181, 160, 25, 14, 65, + 69, 85, 77, 32, 79, 78, 69, 32, 80, 76, 69, 84, 72, 6, 206, 193, 12, 70, + 150, 176, 12, 84, 215, 58, 79, 2, 11, 32, 2, 167, 241, 24, 84, 32, 92, 8, + 72, 69, 83, 80, 73, 65, 78, 32, 129, 1, 10, 82, 79, 69, 90, 69, 78, 73, + 65, 78, 32, 20, 40, 2, 70, 73, 38, 84, 251, 163, 18, 79, 6, 182, 233, 20, + 86, 247, 236, 3, 70, 8, 250, 182, 15, 72, 142, 191, 10, 69, 239, 48, 87, + 12, 36, 2, 70, 73, 209, 24, 2, 84, 69, 8, 146, 189, 18, 86, 213, 136, 7, + 3, 70, 84, 89, 2, 231, 139, 10, 69, 4, 168, 239, 22, 2, 79, 85, 153, 181, + 1, 3, 84, 65, 66, 154, 2, 66, 76, 174, 45, 82, 66, 68, 220, 233, 7, 2, + 75, 65, 135, 6, 84, 144, 2, 44, 6, 69, 84, 84, 69, 82, 32, 239, 45, 85, + 142, 2, 198, 2, 65, 190, 1, 69, 28, 4, 73, 79, 84, 65, 128, 1, 2, 79, 77, + 156, 3, 3, 82, 72, 79, 46, 83, 48, 7, 85, 80, 83, 73, 76, 79, 78, 146, + 33, 80, 170, 2, 84, 222, 185, 5, 68, 252, 180, 2, 2, 75, 65, 238, 192, 1, + 71, 138, 143, 11, 67, 230, 154, 2, 66, 2, 72, 2, 90, 166, 1, 76, 186, + 235, 2, 89, 210, 43, 77, 2, 78, 147, 17, 88, 48, 68, 4, 76, 80, 72, 65, + 213, 28, 8, 82, 67, 72, 65, 73, 67, 32, 83, 47, 33, 6, 32, 87, 73, 84, + 72, 32, 44, 242, 2, 68, 30, 80, 226, 29, 86, 226, 5, 79, 238, 237, 3, 84, + 191, 174, 5, 77, 62, 186, 1, 84, 131, 27, 80, 31, 33, 6, 32, 87, 73, 84, + 72, 32, 28, 186, 5, 68, 136, 25, 2, 80, 83, 158, 1, 86, 226, 5, 79, 238, + 237, 3, 84, 191, 174, 5, 77, 62, 28, 2, 69, 71, 235, 34, 73, 42, 11, 65, + 43, 33, 6, 32, 87, 73, 84, 72, 32, 40, 54, 68, 30, 80, 194, 35, 79, 22, + 86, 219, 237, 3, 84, 16, 65, 4, 65, 83, 73, 65, 18, 36, 4, 83, 73, 76, + 73, 211, 16, 82, 17, 29, 5, 32, 65, 78, 68, 32, 14, 44, 2, 79, 88, 0, 3, + 86, 65, 82, 23, 80, 4, 81, 2, 73, 65, 6, 60, 10, 69, 82, 73, 83, 80, 79, + 77, 69, 78, 73, 175, 15, 82, 5, 169, 15, 7, 32, 65, 78, 68, 32, 80, 82, + 5, 161, 35, 7, 32, 87, 73, 84, 72, 32, 68, 6, 222, 147, 8, 73, 238, 214, + 17, 65, 239, 48, 72, 23, 33, 6, 32, 87, 73, 84, 72, 32, 20, 66, 68, 166, + 26, 86, 226, 5, 79, 238, 237, 3, 84, 191, 174, 5, 77, 10, 130, 24, 65, + 237, 199, 22, 5, 73, 65, 76, 89, 84, 18, 76, 9, 73, 65, 76, 89, 84, 73, + 75, 65, 32, 32, 3, 82, 65, 67, 227, 22, 65, 8, 174, 24, 65, 191, 244, 3, + 84, 2, 207, 194, 11, 72, 4, 40, 3, 73, 86, 69, 1, 3, 79, 85, 82, 2, 205, + 37, 2, 32, 79, 76, 144, 1, 27, 83, 84, 82, 85, 77, 69, 78, 84, 65, 76, + 32, 78, 79, 84, 65, 84, 73, 79, 78, 32, 83, 89, 77, 66, 79, 76, 45, 217, + 176, 22, 2, 68, 73, 74, 70, 49, 70, 50, 62, 51, 62, 52, 170, 37, 53, 218, + 142, 26, 55, 3, 56, 17, 186, 181, 26, 49, 2, 50, 2, 51, 2, 52, 2, 55, 2, + 56, 3, 57, 15, 246, 180, 26, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 12, + 186, 180, 26, 48, 2, 50, 2, 54, 2, 55, 2, 56, 3, 57, 17, 254, 179, 26, + 48, 2, 50, 2, 51, 2, 53, 2, 55, 2, 56, 3, 57, 8, 54, 65, 38, 79, 169, 32, + 6, 89, 65, 84, 72, 79, 83, 4, 134, 134, 8, 80, 187, 151, 17, 73, 2, 11, + 82, 2, 11, 79, 2, 191, 139, 24, 78, 32, 128, 1, 6, 69, 84, 84, 69, 82, + 32, 168, 2, 6, 79, 87, 69, 82, 32, 78, 32, 6, 85, 78, 65, 84, 69, 32, + 201, 217, 22, 2, 73, 84, 24, 94, 83, 140, 13, 9, 65, 82, 67, 72, 65, 73, + 67, 32, 75, 2, 75, 182, 11, 68, 219, 199, 25, 89, 16, 88, 13, 77, 65, 76, + 76, 32, 67, 65, 80, 73, 84, 65, 76, 32, 210, 12, 65, 247, 250, 7, 84, 12, + 74, 80, 170, 200, 9, 71, 242, 161, 9, 79, 154, 212, 2, 82, 139, 181, 1, + 76, 4, 206, 155, 26, 83, 219, 19, 73, 2, 161, 142, 10, 3, 85, 77, 69, 4, + 222, 25, 83, 215, 231, 7, 69, 4, 80, 4, 69, 84, 82, 69, 173, 216, 23, 10, + 85, 83, 73, 67, 65, 76, 32, 76, 69, 73, 2, 235, 212, 2, 84, 12, 88, 3, + 78, 69, 32, 142, 244, 9, 88, 252, 155, 5, 3, 85, 78, 75, 225, 208, 5, 2, + 66, 79, 6, 64, 8, 72, 65, 76, 70, 32, 83, 73, 71, 21, 4, 81, 85, 65, 82, + 4, 151, 173, 25, 78, 2, 147, 225, 20, 84, 16, 62, 82, 206, 11, 83, 114, + 69, 154, 243, 7, 72, 195, 150, 17, 73, 2, 217, 29, 2, 79, 83, 6, 100, 3, + 72, 79, 32, 165, 253, 7, 16, 69, 86, 69, 82, 83, 69, 68, 32, 76, 85, 78, + 65, 84, 69, 32, 69, 4, 136, 252, 13, 10, 87, 73, 84, 72, 32, 83, 84, 82, + 79, 75, 163, 153, 11, 83, 226, 2, 220, 1, 5, 77, 65, 76, 76, 32, 192, 19, + 22, 85, 66, 83, 67, 82, 73, 80, 84, 32, 83, 77, 65, 76, 76, 32, 76, 69, + 84, 84, 69, 82, 32, 72, 10, 89, 77, 66, 79, 76, 32, 84, 65, 85, 32, 225, + 168, 24, 6, 73, 78, 85, 83, 79, 73, 212, 2, 56, 7, 76, 69, 84, 84, 69, + 82, 32, 202, 17, 82, 67, 68, 206, 2, 178, 2, 65, 162, 2, 68, 38, 69, 52, + 4, 73, 79, 84, 65, 0, 7, 85, 80, 83, 73, 76, 79, 78, 254, 3, 75, 28, 2, + 79, 77, 182, 5, 80, 112, 3, 82, 72, 79, 94, 83, 94, 84, 244, 237, 7, 2, + 70, 73, 210, 193, 1, 71, 138, 143, 11, 67, 230, 154, 2, 66, 2, 72, 2, 90, + 166, 1, 76, 138, 151, 3, 77, 2, 78, 147, 17, 88, 58, 64, 4, 76, 80, 72, + 65, 149, 1, 7, 82, 67, 72, 65, 73, 67, 32, 55, 33, 6, 32, 87, 73, 84, 72, + 32, 52, 82, 86, 226, 6, 68, 30, 80, 114, 79, 142, 1, 89, 218, 239, 3, 84, + 191, 174, 5, 77, 6, 154, 5, 82, 155, 3, 65, 4, 18, 75, 23, 83, 2, 215, + 251, 7, 79, 2, 11, 65, 2, 171, 197, 13, 77, 4, 150, 230, 7, 73, 151, 128, + 15, 69, 70, 22, 80, 215, 4, 84, 20, 249, 7, 3, 83, 73, 76, 41, 33, 6, 32, + 87, 73, 84, 72, 32, 38, 78, 68, 166, 1, 80, 178, 1, 86, 226, 5, 79, 238, + 237, 3, 84, 191, 174, 5, 77, 18, 50, 65, 29, 8, 73, 65, 76, 89, 84, 73, + 75, 65, 8, 153, 1, 3, 83, 73, 65, 11, 29, 5, 32, 65, 78, 68, 32, 8, 170, + 1, 80, 154, 6, 79, 22, 86, 219, 237, 3, 84, 10, 18, 83, 115, 69, 8, 21, + 3, 73, 76, 73, 9, 17, 2, 32, 65, 6, 21, 3, 78, 68, 32, 6, 30, 80, 154, 6, + 79, 23, 86, 2, 11, 69, 2, 11, 82, 2, 181, 17, 4, 73, 83, 80, 79, 4, 22, + 82, 147, 15, 65, 2, 145, 253, 25, 2, 65, 67, 4, 206, 246, 7, 65, 3, 79, + 70, 28, 2, 69, 71, 151, 3, 73, 50, 11, 65, 51, 33, 6, 32, 87, 73, 84, 72, + 32, 48, 58, 68, 30, 80, 114, 79, 62, 86, 82, 89, 219, 239, 3, 84, 16, 61, + 4, 65, 83, 73, 65, 20, 32, 4, 83, 73, 76, 73, 91, 69, 17, 29, 5, 32, 65, + 78, 68, 32, 14, 42, 79, 12, 2, 80, 69, 50, 86, 83, 89, 4, 83, 88, 4, 89, + 9, 82, 73, 83, 80, 79, 77, 69, 78, 73, 4, 11, 65, 4, 11, 82, 4, 17, 2, + 73, 65, 5, 33, 6, 32, 65, 78, 68, 32, 89, 2, 243, 12, 80, 20, 17, 2, 67, + 82, 20, 17, 2, 79, 78, 21, 33, 6, 32, 87, 73, 84, 72, 32, 18, 88, 5, 68, + 65, 83, 73, 65, 0, 5, 80, 83, 73, 76, 73, 54, 79, 22, 86, 219, 237, 3, + 84, 7, 29, 5, 32, 65, 78, 68, 32, 4, 18, 79, 23, 86, 2, 151, 224, 9, 88, + 2, 179, 9, 65, 8, 88, 11, 65, 77, 80, 72, 89, 76, 73, 65, 78, 32, 68, + 186, 132, 26, 72, 2, 83, 219, 19, 73, 2, 151, 219, 7, 73, 7, 33, 6, 32, + 87, 73, 84, 72, 32, 4, 34, 68, 201, 147, 21, 2, 80, 83, 2, 151, 205, 8, + 65, 10, 54, 65, 186, 238, 7, 84, 230, 1, 73, 219, 135, 18, 72, 4, 238, + 184, 13, 77, 251, 221, 12, 78, 4, 174, 217, 22, 72, 175, 152, 3, 65, 4, + 41, 8, 69, 86, 69, 82, 83, 69, 68, 32, 4, 18, 68, 43, 76, 2, 37, 7, 79, + 84, 84, 69, 68, 32, 76, 2, 11, 85, 2, 33, 6, 78, 65, 84, 69, 32, 83, 2, + 169, 239, 7, 3, 73, 71, 77, 10, 230, 173, 9, 71, 138, 143, 11, 67, 2, 80, + 130, 103, 82, 231, 179, 1, 66, 2, 167, 163, 21, 82, 16, 106, 72, 104, 7, + 82, 89, 66, 76, 73, 79, 78, 44, 3, 87, 79, 32, 246, 230, 3, 79, 133, 214, + 16, 2, 65, 76, 6, 40, 4, 82, 69, 69, 32, 143, 237, 7, 69, 4, 146, 1, 79, + 213, 223, 22, 7, 81, 85, 65, 82, 84, 69, 82, 2, 21, 3, 32, 66, 65, 2, + 151, 242, 23, 83, 4, 42, 79, 189, 160, 12, 4, 84, 72, 73, 82, 2, 157, + 237, 19, 2, 66, 79, 6, 80, 5, 65, 67, 85, 84, 69, 0, 9, 68, 73, 65, 69, + 82, 69, 83, 73, 83, 39, 72, 2, 33, 6, 32, 65, 78, 68, 32, 72, 2, 209, + 202, 7, 2, 79, 79, 60, 102, 65, 21, 21, 79, 67, 65, 76, 32, 78, 79, 84, + 65, 84, 73, 79, 78, 32, 83, 89, 77, 66, 79, 76, 45, 2, 207, 214, 9, 82, + 58, 90, 50, 2, 53, 214, 202, 23, 49, 134, 196, 2, 51, 2, 52, 2, 54, 2, + 55, 2, 56, 3, 57, 13, 214, 142, 26, 48, 2, 49, 2, 50, 2, 51, 3, 52, 4, + 26, 80, 227, 195, 20, 69, 2, 11, 79, 2, 33, 6, 71, 69, 71, 82, 65, 77, 2, + 253, 136, 21, 2, 77, 69, 8, 254, 245, 13, 65, 206, 193, 10, 66, 202, 78, + 72, 253, 64, 3, 83, 65, 76, 12, 60, 6, 78, 78, 73, 78, 71, 32, 149, 132, + 25, 3, 77, 65, 67, 10, 100, 4, 70, 65, 67, 69, 137, 241, 17, 15, 67, 65, + 84, 32, 70, 65, 67, 69, 32, 87, 73, 84, 72, 32, 83, 9, 33, 6, 32, 87, 73, + 84, 72, 32, 6, 108, 23, 79, 78, 69, 32, 76, 65, 82, 71, 69, 32, 65, 78, + 68, 32, 79, 78, 69, 32, 83, 77, 65, 76, 76, 35, 83, 2, 11, 32, 2, 227, + 164, 8, 69, 4, 32, 2, 84, 65, 191, 239, 17, 77, 2, 247, 138, 23, 82, 6, + 28, 3, 85, 80, 32, 39, 87, 4, 142, 216, 22, 83, 135, 240, 2, 77, 2, 231, + 157, 18, 73, 220, 4, 136, 1, 2, 65, 82, 70, 73, 52, 7, 74, 65, 82, 65, + 84, 73, 32, 184, 6, 12, 78, 74, 65, 76, 65, 32, 71, 79, 78, 68, 73, 32, + 143, 3, 82, 4, 34, 65, 173, 137, 21, 2, 68, 83, 2, 11, 78, 2, 199, 128, + 25, 73, 4, 246, 227, 24, 84, 221, 162, 1, 4, 68, 69, 32, 68, 182, 1, 168, + 1, 7, 76, 69, 84, 84, 69, 82, 32, 220, 1, 5, 83, 73, 71, 78, 32, 160, 2, + 6, 86, 79, 87, 69, 76, 32, 130, 142, 20, 65, 154, 24, 82, 182, 231, 3, + 68, 179, 227, 1, 79, 98, 218, 167, 22, 65, 38, 68, 114, 84, 46, 86, 186, + 5, 85, 186, 202, 1, 73, 42, 76, 246, 14, 90, 238, 180, 1, 78, 46, 83, 82, + 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 82, 2, 89, + 186, 2, 69, 3, 79, 24, 98, 67, 28, 3, 77, 65, 68, 22, 84, 130, 203, 3, + 83, 226, 154, 18, 78, 190, 66, 65, 187, 151, 3, 86, 4, 118, 73, 199, 228, + 21, 65, 2, 243, 148, 19, 68, 4, 68, 5, 87, 79, 45, 67, 73, 29, 8, 72, 82, + 69, 69, 45, 68, 79, 84, 2, 25, 4, 82, 67, 76, 69, 2, 189, 214, 20, 5, 32, + 78, 85, 75, 84, 34, 44, 5, 83, 73, 71, 78, 32, 239, 199, 15, 67, 30, 234, + 199, 15, 67, 154, 226, 6, 65, 38, 85, 22, 86, 166, 202, 1, 73, 198, 140, + 2, 69, 3, 79, 126, 108, 7, 76, 69, 84, 84, 69, 82, 32, 216, 1, 5, 83, 73, + 71, 78, 32, 38, 86, 214, 137, 24, 68, 179, 227, 1, 79, 80, 210, 137, 22, + 78, 146, 24, 65, 38, 68, 114, 84, 230, 5, 85, 186, 202, 1, 73, 42, 76, + 222, 196, 1, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 206, 40, 79, 162, 8, + 69, 158, 20, 72, 2, 77, 2, 82, 2, 83, 2, 86, 3, 89, 4, 146, 196, 23, 86, + 247, 244, 1, 65, 20, 190, 7, 79, 131, 186, 23, 73, 160, 2, 84, 6, 77, 85, + 75, 72, 73, 32, 189, 7, 10, 85, 78, 71, 32, 75, 72, 69, 77, 65, 32, 172, + 1, 194, 1, 65, 44, 7, 76, 69, 84, 84, 69, 82, 32, 238, 1, 83, 228, 2, 2, + 86, 79, 164, 152, 13, 3, 84, 73, 80, 174, 242, 5, 73, 252, 175, 2, 5, 69, + 75, 32, 79, 78, 202, 199, 2, 68, 203, 175, 1, 85, 4, 222, 218, 21, 66, + 177, 231, 1, 2, 68, 68, 96, 250, 201, 8, 71, 2, 75, 254, 210, 13, 65, 38, + 68, 82, 82, 34, 84, 230, 5, 85, 186, 202, 1, 73, 42, 76, 226, 195, 1, 78, + 126, 66, 2, 67, 2, 74, 2, 80, 2, 83, 206, 40, 79, 162, 8, 69, 158, 20, + 70, 2, 72, 2, 77, 2, 86, 2, 89, 3, 90, 26, 108, 19, 69, 81, 85, 69, 78, + 67, 69, 32, 70, 79, 82, 32, 76, 69, 84, 84, 69, 82, 32, 93, 4, 73, 71, + 78, 32, 12, 70, 71, 2, 75, 162, 250, 23, 83, 146, 219, 1, 76, 226, 31, + 70, 3, 90, 2, 159, 250, 23, 72, 14, 128, 1, 6, 65, 68, 65, 75, 32, 66, 2, + 66, 244, 148, 15, 2, 85, 68, 190, 196, 6, 78, 236, 177, 2, 3, 89, 65, 75, + 139, 168, 1, 86, 2, 187, 155, 8, 73, 18, 45, 9, 87, 69, 76, 32, 83, 73, + 71, 78, 32, 18, 202, 158, 22, 65, 38, 85, 186, 202, 1, 73, 210, 237, 1, + 79, 163, 8, 69, 116, 216, 1, 22, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, + 83, 73, 71, 78, 32, 77, 69, 68, 73, 65, 76, 32, 44, 7, 76, 69, 84, 84, + 69, 82, 32, 168, 1, 5, 83, 73, 71, 78, 32, 56, 6, 86, 79, 87, 69, 76, 32, + 183, 253, 23, 68, 8, 142, 241, 25, 72, 2, 82, 2, 86, 3, 89, 60, 150, 253, + 21, 78, 182, 24, 68, 114, 84, 162, 149, 3, 66, 2, 67, 2, 71, 2, 74, 2, + 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 83, 2, 86, 2, 89, 187, 2, + 65, 4, 250, 172, 25, 65, 233, 35, 6, 84, 72, 79, 76, 72, 79, 24, 174, + 166, 20, 83, 147, 137, 5, 76, 168, 23, 110, 65, 214, 95, 69, 150, 104, + 73, 146, 9, 79, 158, 12, 84, 30, 85, 130, 1, 89, 249, 244, 12, 4, 82, 89, + 86, 78, 140, 11, 236, 1, 2, 73, 82, 100, 8, 76, 70, 87, 73, 68, 84, 72, + 32, 242, 10, 77, 210, 1, 78, 236, 76, 21, 80, 80, 89, 32, 80, 69, 82, 83, + 79, 78, 32, 82, 65, 73, 83, 73, 78, 71, 32, 79, 78, 22, 82, 38, 84, 232, + 255, 17, 2, 85, 77, 255, 253, 5, 68, 8, 66, 32, 164, 207, 20, 6, 89, 32, + 67, 82, 69, 65, 251, 164, 4, 67, 4, 218, 187, 24, 80, 231, 115, 83, 244, + 1, 140, 2, 7, 72, 65, 78, 71, 85, 76, 32, 216, 4, 8, 75, 65, 84, 65, 75, + 65, 78, 65, 204, 3, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 152, 192, 6, 11, + 70, 79, 82, 77, 83, 32, 76, 73, 71, 72, 84, 202, 134, 4, 85, 198, 218, 2, + 73, 142, 190, 4, 66, 166, 238, 4, 87, 215, 35, 68, 104, 52, 7, 76, 69, + 84, 84, 69, 82, 32, 239, 224, 10, 70, 102, 206, 1, 75, 28, 5, 78, 73, 69, + 85, 78, 42, 80, 24, 5, 82, 73, 69, 85, 76, 86, 83, 98, 89, 202, 61, 67, + 54, 69, 30, 73, 242, 4, 77, 138, 1, 84, 206, 3, 87, 198, 1, 72, 226, 221, + 24, 65, 2, 79, 163, 64, 85, 6, 222, 65, 72, 155, 3, 73, 7, 11, 45, 4, + 134, 72, 67, 131, 3, 72, 6, 146, 69, 72, 35, 73, 17, 11, 45, 14, 206, 49, + 84, 226, 14, 80, 130, 4, 77, 194, 3, 75, 218, 2, 72, 99, 83, 12, 40, 4, + 83, 65, 78, 71, 235, 229, 13, 73, 10, 210, 70, 67, 42, 75, 74, 80, 34, + 84, 211, 2, 83, 14, 238, 157, 23, 69, 146, 137, 2, 65, 162, 64, 73, 2, + 79, 3, 85, 118, 70, 32, 157, 241, 2, 11, 45, 72, 73, 82, 65, 71, 65, 78, + 65, 32, 80, 116, 76, 7, 76, 69, 84, 84, 69, 82, 32, 242, 240, 2, 83, 34, + 86, 219, 224, 21, 77, 110, 146, 1, 83, 230, 234, 2, 78, 150, 2, 72, 2, + 75, 2, 77, 2, 82, 2, 84, 170, 1, 89, 234, 41, 87, 174, 204, 22, 65, 2, + 69, 2, 73, 2, 79, 3, 85, 28, 76, 5, 77, 65, 76, 76, 32, 230, 227, 25, 65, + 2, 69, 2, 73, 2, 79, 3, 85, 18, 206, 237, 2, 89, 174, 209, 22, 84, 234, + 36, 65, 2, 69, 2, 73, 2, 79, 3, 85, 4, 11, 84, 4, 180, 165, 13, 2, 32, + 67, 135, 156, 11, 87, 14, 56, 3, 77, 69, 82, 106, 83, 145, 144, 22, 3, + 66, 85, 82, 9, 29, 5, 32, 65, 78, 68, 32, 6, 220, 177, 12, 3, 87, 82, 69, + 212, 233, 3, 2, 83, 73, 191, 148, 8, 80, 4, 148, 164, 25, 3, 84, 69, 82, + 163, 61, 65, 194, 8, 118, 68, 202, 2, 71, 128, 66, 13, 73, 70, 73, 32, + 82, 79, 72, 73, 78, 71, 89, 65, 32, 165, 5, 5, 85, 78, 79, 79, 32, 10, + 100, 12, 32, 87, 73, 84, 72, 32, 73, 78, 68, 69, 88, 32, 188, 1, 2, 66, + 65, 197, 241, 21, 2, 83, 72, 4, 156, 1, 18, 65, 78, 68, 32, 77, 73, 68, + 68, 76, 69, 32, 70, 73, 78, 71, 69, 82, 83, 1, 16, 70, 73, 78, 71, 69, + 82, 32, 65, 78, 68, 32, 84, 72, 85, 77, 66, 2, 225, 147, 16, 2, 32, 67, + 4, 154, 210, 24, 76, 211, 139, 1, 71, 170, 7, 84, 3, 85, 76, 32, 217, 64, + 13, 90, 72, 79, 85, 32, 78, 85, 77, 69, 82, 65, 76, 32, 146, 7, 164, 1, + 9, 67, 72, 79, 83, 69, 79, 78, 71, 32, 244, 15, 4, 68, 79, 85, 66, 0, 4, + 83, 73, 78, 71, 46, 74, 180, 31, 7, 76, 69, 84, 84, 69, 82, 32, 219, 161, + 10, 70, 250, 1, 246, 1, 67, 172, 2, 5, 73, 69, 85, 78, 71, 146, 1, 75, + 132, 1, 5, 77, 73, 69, 85, 77, 56, 5, 78, 73, 69, 85, 78, 74, 80, 172, 2, + 5, 82, 73, 69, 85, 76, 210, 1, 83, 166, 3, 84, 124, 2, 89, 69, 200, 40, + 5, 72, 73, 69, 85, 72, 143, 153, 10, 70, 30, 76, 2, 72, 73, 84, 7, 69, + 79, 78, 71, 67, 72, 73, 121, 4, 73, 69, 85, 67, 16, 40, 4, 69, 85, 67, + 72, 41, 2, 84, 85, 7, 11, 45, 4, 202, 31, 75, 243, 26, 72, 10, 21, 3, 69, + 85, 77, 10, 22, 83, 155, 46, 67, 6, 40, 4, 83, 65, 78, 71, 219, 213, 13, + 73, 4, 194, 54, 67, 227, 3, 83, 5, 215, 30, 45, 27, 11, 45, 24, 90, 80, + 234, 30, 82, 242, 13, 67, 194, 5, 77, 138, 1, 84, 186, 2, 75, 218, 2, 72, + 99, 83, 6, 214, 50, 72, 214, 3, 73, 207, 2, 65, 16, 80, 7, 65, 80, 89, + 69, 79, 85, 78, 228, 20, 5, 73, 89, 69, 79, 75, 131, 25, 72, 10, 234, 29, + 82, 178, 15, 80, 30, 83, 231, 3, 77, 11, 11, 45, 8, 158, 52, 75, 74, 80, + 34, 84, 211, 2, 83, 15, 11, 45, 12, 190, 51, 67, 42, 75, 74, 80, 34, 84, + 242, 1, 72, 99, 83, 42, 68, 6, 72, 73, 69, 85, 80, 72, 40, 4, 73, 69, 85, + 80, 223, 53, 65, 7, 11, 45, 4, 158, 51, 80, 147, 2, 72, 35, 11, 45, 32, + 82, 83, 234, 20, 80, 214, 7, 75, 162, 12, 67, 202, 6, 84, 226, 2, 78, + 179, 2, 72, 14, 32, 3, 73, 79, 83, 251, 3, 83, 13, 11, 45, 10, 242, 46, + 84, 146, 2, 67, 42, 75, 75, 80, 29, 11, 45, 26, 78, 75, 42, 83, 190, 44, + 77, 154, 3, 67, 82, 78, 34, 80, 34, 84, 243, 1, 72, 6, 170, 22, 65, 130, + 19, 72, 135, 7, 73, 8, 40, 4, 83, 65, 78, 71, 191, 206, 13, 73, 6, 206, + 47, 75, 74, 80, 35, 84, 58, 48, 3, 73, 79, 83, 217, 1, 4, 83, 65, 78, 71, + 33, 11, 45, 30, 130, 1, 80, 44, 2, 83, 83, 210, 22, 82, 210, 1, 75, 162, + 12, 67, 194, 5, 77, 138, 1, 84, 226, 2, 78, 178, 2, 72, 187, 170, 18, 73, + 6, 184, 23, 4, 73, 69, 85, 80, 179, 19, 72, 2, 233, 48, 3, 65, 78, 71, + 26, 236, 17, 5, 67, 73, 69, 85, 67, 172, 3, 4, 83, 73, 79, 83, 154, 1, + 82, 186, 20, 84, 54, 89, 134, 2, 75, 42, 78, 34, 80, 146, 2, 72, 187, + 170, 18, 73, 16, 40, 5, 73, 75, 69, 85, 84, 195, 41, 72, 15, 11, 45, 12, + 226, 20, 82, 178, 19, 77, 154, 3, 67, 42, 75, 74, 80, 243, 2, 83, 4, 150, + 19, 83, 139, 22, 79, 2, 225, 252, 8, 6, 76, 69, 32, 68, 79, 84, 216, 3, + 92, 9, 79, 78, 71, 83, 69, 79, 78, 71, 32, 165, 21, 9, 85, 78, 71, 83, + 69, 79, 78, 71, 32, 154, 2, 226, 1, 67, 80, 5, 72, 73, 69, 85, 72, 60, 5, + 73, 69, 85, 78, 71, 46, 75, 220, 1, 5, 77, 73, 69, 85, 77, 188, 1, 5, 78, + 73, 69, 85, 78, 94, 80, 240, 2, 5, 82, 73, 69, 85, 76, 190, 4, 83, 194, + 3, 84, 213, 1, 2, 89, 69, 8, 36, 4, 73, 69, 85, 67, 239, 30, 72, 7, 11, + 45, 4, 162, 32, 83, 239, 7, 80, 11, 11, 45, 8, 174, 16, 82, 178, 19, 77, + 234, 3, 78, 35, 80, 9, 11, 45, 6, 194, 17, 75, 57, 2, 83, 83, 28, 76, 7, + 65, 80, 89, 69, 79, 85, 78, 40, 5, 73, 89, 69, 79, 75, 215, 30, 72, 8, + 130, 15, 82, 178, 15, 80, 131, 4, 77, 19, 11, 45, 16, 166, 13, 75, 170, + 1, 82, 42, 83, 224, 13, 2, 67, 72, 146, 9, 78, 34, 80, 147, 2, 72, 27, + 11, 45, 24, 74, 80, 30, 83, 134, 13, 82, 242, 13, 67, 130, 9, 75, 42, 78, + 179, 2, 72, 6, 174, 33, 73, 131, 6, 65, 6, 40, 4, 83, 65, 78, 71, 183, + 194, 13, 73, 4, 238, 35, 78, 147, 3, 83, 21, 11, 45, 18, 174, 12, 82, + 242, 13, 67, 202, 6, 84, 186, 2, 75, 218, 2, 72, 62, 80, 39, 83, 36, 88, + 6, 65, 78, 83, 73, 79, 83, 48, 6, 72, 73, 69, 85, 80, 72, 53, 4, 73, 69, + 85, 80, 7, 11, 45, 4, 236, 7, 2, 75, 65, 195, 26, 80, 9, 11, 45, 6, 150, + 11, 84, 234, 22, 80, 243, 2, 83, 23, 11, 45, 20, 112, 5, 82, 73, 69, 85, + 76, 24, 4, 83, 73, 79, 83, 134, 3, 80, 246, 19, 67, 194, 5, 77, 170, 4, + 84, 243, 1, 72, 5, 153, 3, 2, 45, 80, 5, 221, 32, 2, 45, 84, 57, 11, 45, + 54, 102, 75, 92, 5, 77, 73, 69, 85, 77, 50, 80, 126, 83, 74, 84, 44, 2, + 89, 69, 154, 28, 78, 179, 2, 72, 10, 52, 5, 73, 89, 69, 79, 75, 190, 4, + 65, 131, 19, 72, 7, 11, 45, 4, 254, 32, 72, 99, 83, 9, 11, 45, 6, 130, + 30, 75, 218, 2, 72, 99, 83, 14, 48, 4, 73, 69, 85, 80, 174, 26, 72, 163, + 6, 65, 11, 11, 45, 8, 42, 80, 222, 29, 84, 242, 1, 72, 99, 83, 2, 243, + 25, 72, 6, 40, 4, 83, 65, 78, 71, 167, 187, 13, 73, 4, 182, 28, 75, 187, + 3, 83, 6, 100, 5, 73, 75, 69, 85, 84, 151, 25, 72, 6, 56, 9, 79, 82, 73, + 78, 72, 73, 69, 85, 72, 191, 3, 83, 5, 255, 29, 45, 52, 48, 3, 73, 79, + 83, 161, 1, 4, 83, 65, 78, 71, 25, 11, 45, 22, 82, 75, 162, 3, 82, 242, + 13, 67, 198, 2, 80, 254, 2, 77, 138, 1, 84, 147, 5, 72, 4, 22, 65, 135, + 26, 73, 2, 237, 18, 6, 80, 89, 69, 79, 85, 78, 28, 160, 1, 5, 82, 73, 69, + 85, 76, 36, 6, 84, 73, 75, 69, 85, 84, 16, 3, 89, 69, 83, 138, 19, 83, + 178, 1, 77, 154, 3, 67, 42, 75, 42, 78, 34, 80, 203, 172, 18, 73, 5, 17, + 2, 45, 75, 2, 159, 17, 72, 5, 255, 16, 45, 2, 135, 197, 18, 73, 20, 40, + 5, 73, 75, 69, 85, 84, 155, 21, 72, 19, 11, 45, 16, 58, 82, 42, 83, 42, + 84, 162, 13, 67, 130, 9, 75, 75, 80, 2, 17, 2, 73, 69, 2, 227, 171, 24, + 85, 4, 21, 3, 73, 79, 83, 5, 223, 1, 45, 2, 255, 19, 72, 18, 44, 6, 83, + 73, 69, 85, 78, 71, 243, 19, 79, 17, 11, 45, 14, 50, 75, 30, 83, 198, 17, + 77, 154, 6, 72, 63, 80, 4, 166, 14, 72, 135, 7, 73, 4, 26, 83, 215, 179, + 13, 73, 2, 21, 3, 65, 78, 71, 2, 207, 20, 75, 190, 1, 122, 65, 118, 69, + 134, 1, 73, 92, 7, 83, 83, 65, 78, 71, 65, 82, 106, 79, 138, 1, 85, 102, + 89, 174, 15, 87, 179, 149, 10, 70, 23, 48, 4, 82, 65, 69, 65, 98, 45, + 135, 179, 25, 69, 13, 11, 45, 10, 166, 234, 22, 69, 178, 201, 2, 65, 2, + 73, 3, 85, 25, 18, 79, 55, 85, 9, 11, 45, 6, 154, 142, 25, 69, 234, 36, + 79, 3, 85, 15, 11, 45, 12, 170, 9, 69, 166, 169, 25, 65, 2, 79, 3, 85, + 31, 11, 45, 28, 66, 65, 34, 89, 166, 1, 79, 166, 139, 25, 69, 234, 36, + 73, 3, 85, 5, 11, 82, 2, 195, 157, 18, 65, 14, 50, 65, 206, 231, 22, 69, + 178, 201, 2, 79, 3, 85, 7, 134, 146, 25, 45, 247, 30, 69, 23, 26, 45, + 195, 176, 25, 69, 18, 50, 79, 22, 89, 202, 230, 22, 69, 179, 201, 2, 85, + 5, 179, 156, 25, 45, 8, 198, 230, 22, 69, 147, 137, 2, 65, 17, 11, 45, + 14, 158, 19, 89, 206, 166, 5, 73, 128, 137, 13, 3, 69, 79, 45, 190, 172, + 6, 65, 163, 64, 85, 62, 42, 65, 70, 69, 66, 73, 22, 79, 107, 85, 11, 26, + 45, 171, 174, 25, 69, 6, 178, 143, 25, 89, 246, 30, 79, 3, 85, 11, 11, + 79, 9, 11, 45, 6, 174, 171, 25, 89, 186, 2, 79, 3, 85, 5, 215, 136, 25, + 45, 19, 11, 45, 16, 58, 89, 198, 236, 24, 65, 174, 33, 69, 246, 30, 73, + 3, 79, 6, 194, 236, 24, 65, 175, 33, 69, 21, 11, 45, 18, 142, 16, 89, + 250, 210, 22, 69, 146, 137, 2, 65, 162, 64, 73, 2, 79, 3, 85, 186, 1, + 226, 1, 65, 46, 67, 54, 69, 30, 73, 22, 75, 188, 1, 5, 77, 73, 69, 85, + 77, 64, 5, 78, 73, 69, 85, 78, 70, 80, 168, 1, 5, 82, 73, 69, 85, 76, + 254, 1, 84, 90, 83, 246, 2, 87, 50, 89, 150, 1, 72, 226, 221, 24, 79, + 163, 64, 85, 9, 156, 13, 3, 82, 65, 69, 231, 156, 25, 69, 4, 22, 72, 207, + 8, 73, 2, 137, 135, 25, 2, 73, 69, 7, 162, 169, 25, 79, 3, 85, 5, 203, + 181, 18, 69, 14, 56, 7, 65, 80, 89, 69, 79, 85, 78, 106, 72, 155, 3, 73, + 8, 30, 80, 30, 83, 231, 3, 77, 4, 190, 4, 72, 215, 3, 73, 2, 25, 4, 83, + 65, 78, 71, 2, 207, 7, 80, 2, 241, 60, 2, 73, 69, 9, 11, 45, 6, 22, 80, + 247, 9, 83, 4, 142, 7, 73, 207, 2, 65, 13, 11, 45, 10, 234, 5, 67, 146, + 1, 84, 242, 1, 72, 62, 80, 39, 83, 20, 48, 4, 73, 69, 85, 80, 170, 2, 72, + 163, 6, 65, 17, 11, 45, 14, 42, 83, 186, 2, 84, 146, 2, 67, 43, 75, 6, + 21, 3, 73, 79, 83, 7, 11, 45, 4, 202, 4, 75, 107, 84, 27, 11, 45, 24, 68, + 2, 75, 73, 34, 77, 34, 80, 106, 84, 54, 89, 222, 4, 72, 99, 83, 4, 149, + 1, 4, 89, 69, 79, 75, 2, 11, 73, 2, 231, 248, 23, 69, 8, 30, 72, 34, 73, + 131, 6, 65, 2, 221, 240, 18, 3, 73, 69, 85, 4, 21, 3, 69, 85, 80, 5, 243, + 5, 45, 4, 22, 72, 151, 3, 73, 2, 137, 254, 21, 2, 73, 69, 2, 17, 2, 69, + 79, 2, 167, 4, 82, 28, 44, 3, 73, 79, 83, 57, 4, 83, 65, 78, 71, 13, 11, + 45, 10, 122, 67, 42, 75, 42, 78, 34, 80, 35, 84, 16, 78, 67, 42, 75, 42, + 78, 34, 80, 34, 84, 242, 1, 72, 98, 83, 219, 169, 18, 73, 2, 11, 73, 2, + 225, 246, 23, 2, 69, 85, 2, 11, 73, 2, 233, 246, 24, 2, 89, 69, 2, 11, + 73, 2, 243, 159, 24, 69, 2, 11, 73, 2, 143, 170, 24, 69, 2, 11, 73, 2, + 11, 75, 2, 135, 166, 24, 69, 10, 146, 214, 22, 69, 146, 137, 2, 65, 163, + 64, 73, 34, 58, 69, 206, 1, 79, 62, 85, 178, 220, 24, 65, 163, 64, 73, + 13, 42, 79, 73, 6, 83, 73, 69, 85, 78, 71, 5, 11, 82, 2, 17, 2, 73, 78, + 2, 11, 72, 2, 233, 242, 9, 2, 73, 69, 7, 11, 45, 4, 18, 80, 39, 83, 2, + 11, 65, 2, 11, 78, 2, 11, 83, 2, 179, 155, 13, 73, 9, 11, 45, 6, 26, 89, + 231, 156, 25, 73, 4, 195, 220, 24, 65, 9, 11, 45, 6, 26, 89, 171, 156, + 25, 73, 4, 247, 210, 22, 69, 24, 162, 144, 11, 84, 230, 152, 12, 70, 30, + 83, 182, 87, 78, 14, 79, 227, 112, 69, 100, 156, 1, 7, 76, 69, 84, 84, + 69, 82, 32, 196, 2, 5, 77, 65, 82, 75, 32, 72, 5, 83, 73, 71, 78, 32, + 224, 159, 2, 6, 86, 79, 87, 69, 76, 32, 183, 131, 21, 68, 58, 202, 1, 68, + 34, 75, 142, 132, 21, 84, 178, 55, 82, 238, 223, 1, 78, 214, 181, 1, 83, + 138, 69, 66, 2, 67, 2, 70, 2, 71, 2, 72, 2, 74, 2, 76, 2, 77, 2, 80, 2, + 86, 2, 87, 2, 89, 2, 90, 187, 2, 65, 4, 162, 150, 25, 68, 187, 2, 65, 8, + 56, 5, 73, 78, 78, 65, 32, 202, 149, 25, 72, 187, 2, 65, 4, 198, 149, 25, + 87, 3, 89, 4, 160, 221, 21, 6, 78, 65, 32, 75, 72, 79, 237, 186, 2, 3, + 83, 65, 75, 8, 52, 2, 84, 65, 237, 134, 23, 5, 72, 65, 82, 66, 65, 6, 42, + 72, 198, 163, 20, 83, 191, 240, 4, 78, 2, 159, 244, 24, 65, 42, 62, 76, + 176, 251, 18, 6, 83, 73, 71, 78, 32, 80, 247, 1, 86, 36, 33, 6, 69, 84, + 84, 69, 82, 32, 36, 186, 159, 21, 78, 206, 243, 3, 66, 2, 68, 2, 71, 2, + 72, 2, 75, 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, 89, 186, + 2, 65, 2, 73, 3, 85, 2, 235, 131, 24, 69, 4, 234, 204, 23, 68, 163, 199, + 1, 80, 54, 52, 5, 67, 72, 73, 78, 71, 41, 4, 82, 65, 78, 32, 2, 17, 2, + 32, 67, 2, 139, 225, 23, 72, 52, 52, 7, 76, 69, 84, 84, 69, 82, 32, 171, + 186, 6, 78, 42, 218, 1, 65, 210, 181, 11, 90, 238, 46, 84, 146, 120, 76, + 50, 81, 60, 6, 68, 65, 76, 69, 84, 72, 214, 169, 4, 71, 122, 83, 66, 89, + 198, 207, 1, 72, 234, 5, 75, 174, 81, 66, 170, 225, 4, 78, 134, 2, 87, + 218, 103, 80, 171, 4, 77, 4, 246, 134, 17, 76, 159, 186, 7, 89, 174, 9, + 210, 1, 65, 242, 32, 66, 130, 33, 76, 200, 1, 16, 78, 84, 65, 73, 71, 65, + 78, 65, 32, 76, 69, 84, 84, 69, 82, 32, 174, 12, 82, 120, 11, 88, 65, 71, + 82, 65, 77, 32, 70, 79, 82, 32, 189, 189, 24, 4, 68, 71, 69, 72, 214, 1, + 42, 68, 98, 82, 201, 1, 3, 86, 89, 32, 6, 44, 5, 83, 84, 79, 78, 69, 183, + 225, 23, 80, 5, 213, 226, 2, 7, 32, 71, 82, 65, 86, 69, 89, 12, 32, 2, + 84, 32, 147, 164, 17, 45, 10, 60, 5, 87, 73, 84, 72, 32, 222, 171, 12, + 68, 239, 158, 9, 72, 6, 76, 9, 84, 73, 80, 32, 79, 78, 32, 84, 72, 134, + 251, 12, 82, 243, 244, 10, 65, 2, 239, 217, 24, 69, 196, 1, 134, 2, 65, + 202, 1, 66, 230, 2, 67, 154, 3, 68, 162, 1, 69, 186, 3, 70, 94, 72, 62, + 76, 222, 1, 77, 110, 79, 162, 1, 82, 142, 2, 83, 228, 1, 3, 78, 79, 82, + 198, 1, 84, 128, 2, 2, 85, 80, 174, 1, 87, 186, 148, 14, 73, 222, 243, 3, + 80, 130, 142, 4, 86, 227, 78, 71, 12, 108, 17, 82, 82, 79, 87, 32, 83, + 72, 65, 70, 84, 32, 87, 73, 68, 84, 72, 32, 182, 171, 18, 77, 207, 198, + 4, 83, 8, 36, 3, 79, 78, 69, 135, 166, 23, 84, 7, 11, 32, 4, 226, 246, + 13, 84, 251, 139, 9, 72, 14, 48, 4, 65, 76, 76, 79, 21, 4, 76, 65, 67, + 75, 2, 139, 235, 5, 84, 12, 30, 32, 153, 1, 2, 45, 70, 6, 52, 7, 67, 85, + 82, 86, 69, 68, 32, 135, 128, 24, 72, 4, 40, 4, 68, 79, 87, 78, 1, 2, 85, + 80, 2, 225, 228, 23, 8, 87, 65, 82, 68, 83, 32, 65, 78, 6, 45, 9, 69, 65, + 84, 72, 69, 82, 69, 68, 32, 6, 158, 220, 13, 83, 174, 173, 3, 78, 215, + 218, 6, 82, 14, 116, 2, 72, 69, 52, 5, 73, 82, 67, 76, 69, 149, 233, 17, + 14, 79, 78, 67, 65, 86, 69, 45, 80, 79, 73, 78, 84, 69, 68, 4, 196, 221, + 20, 4, 86, 82, 79, 78, 255, 225, 2, 67, 9, 64, 6, 32, 87, 73, 84, 72, 32, + 185, 235, 22, 4, 68, 32, 83, 65, 4, 52, 7, 83, 84, 82, 79, 75, 69, 32, + 239, 128, 5, 67, 2, 29, 5, 65, 78, 68, 32, 84, 2, 11, 87, 2, 11, 79, 2, + 21, 3, 32, 68, 79, 2, 11, 84, 2, 223, 133, 24, 83, 14, 52, 7, 65, 83, 72, + 69, 68, 32, 84, 18, 73, 31, 79, 2, 175, 16, 82, 2, 161, 162, 19, 2, 86, + 73, 10, 192, 16, 3, 87, 78, 87, 246, 147, 14, 85, 191, 184, 4, 76, 16, + 120, 5, 73, 71, 72, 84, 32, 156, 2, 16, 88, 67, 76, 65, 77, 65, 84, 73, + 79, 78, 32, 77, 65, 82, 75, 32, 199, 217, 18, 81, 10, 40, 2, 80, 79, 126, + 84, 155, 231, 22, 83, 6, 33, 6, 73, 78, 84, 69, 68, 32, 6, 194, 199, 16, + 80, 128, 158, 6, 11, 82, 69, 67, 84, 73, 76, 73, 78, 69, 65, 82, 23, 66, + 2, 193, 231, 22, 24, 69, 65, 82, 68, 82, 79, 80, 45, 83, 80, 79, 75, 69, + 68, 32, 80, 82, 79, 80, 69, 76, 76, 69, 82, 4, 234, 232, 23, 83, 227, 81, + 79, 6, 44, 5, 79, 85, 82, 32, 66, 179, 128, 5, 73, 2, 181, 139, 11, 6, + 65, 76, 76, 79, 79, 78, 4, 238, 199, 17, 79, 161, 233, 5, 6, 69, 65, 82, + 84, 32, 69, 20, 74, 65, 44, 3, 69, 70, 84, 28, 2, 79, 87, 189, 251, 4, 3, + 73, 71, 65, 4, 232, 230, 21, 2, 82, 71, 211, 209, 1, 84, 8, 254, 3, 45, + 195, 6, 87, 6, 26, 32, 191, 151, 10, 69, 4, 202, 158, 14, 68, 25, 4, 83, + 73, 78, 71, 4, 56, 8, 85, 76, 84, 73, 80, 76, 73, 67, 167, 200, 21, 73, + 2, 25, 4, 65, 84, 73, 79, 2, 159, 221, 5, 78, 6, 148, 147, 6, 9, 80, 69, + 78, 32, 67, 69, 78, 84, 82, 248, 180, 10, 13, 86, 65, 76, 32, 87, 73, 84, + 72, 32, 79, 86, 65, 76, 213, 151, 6, 5, 85, 84, 76, 73, 78, 12, 76, 4, + 73, 71, 72, 84, 129, 214, 23, 9, 79, 85, 78, 68, 45, 84, 73, 80, 80, 10, + 62, 45, 109, 11, 87, 65, 82, 68, 83, 32, 65, 82, 82, 79, 87, 4, 69, 15, + 80, 79, 73, 78, 84, 73, 78, 71, 32, 65, 78, 71, 76, 69, 32, 4, 214, 236, + 6, 66, 203, 174, 7, 81, 7, 139, 6, 32, 26, 106, 65, 78, 73, 44, 2, 79, + 85, 136, 163, 14, 7, 67, 82, 73, 80, 84, 32, 76, 193, 139, 1, 3, 80, 65, + 82, 4, 156, 154, 14, 10, 78, 83, 45, 83, 69, 82, 73, 70, 32, 73, 175, + 195, 8, 76, 8, 136, 152, 14, 2, 78, 71, 183, 194, 8, 88, 10, 21, 3, 84, + 72, 32, 10, 60, 5, 69, 65, 83, 84, 32, 29, 6, 87, 69, 83, 84, 32, 80, 6, + 26, 80, 215, 215, 23, 65, 4, 41, 8, 79, 73, 78, 84, 73, 78, 71, 32, 4, + 250, 250, 16, 86, 255, 202, 6, 66, 12, 88, 9, 69, 65, 82, 68, 82, 79, 80, + 45, 83, 130, 1, 82, 145, 233, 6, 4, 87, 69, 76, 86, 6, 64, 6, 80, 79, 75, + 69, 68, 32, 253, 207, 23, 4, 72, 65, 78, 75, 4, 216, 218, 22, 8, 80, 73, + 78, 87, 72, 69, 69, 76, 27, 65, 2, 193, 3, 5, 73, 65, 78, 71, 76, 6, 26, + 87, 171, 141, 10, 80, 4, 53, 11, 65, 82, 68, 83, 32, 65, 82, 82, 79, 87, + 32, 4, 29, 5, 87, 73, 84, 72, 32, 4, 152, 142, 20, 5, 76, 65, 82, 71, 69, + 179, 243, 1, 69, 12, 76, 5, 72, 73, 84, 69, 32, 164, 1, 2, 73, 68, 149, + 133, 23, 3, 69, 68, 71, 8, 64, 6, 83, 81, 85, 65, 82, 69, 182, 227, 17, + 68, 187, 183, 5, 67, 5, 169, 186, 23, 19, 32, 67, 79, 78, 84, 65, 73, 78, + 73, 78, 71, 32, 66, 76, 65, 67, 75, 32, 86, 2, 181, 255, 20, 2, 69, 45, + 142, 2, 40, 4, 82, 69, 87, 32, 219, 237, 24, 69, 140, 2, 112, 7, 65, 67, + 67, 69, 78, 84, 32, 142, 8, 76, 164, 14, 5, 77, 65, 82, 75, 32, 114, 80, + 225, 180, 21, 2, 89, 79, 60, 128, 2, 9, 65, 84, 78, 65, 72, 32, 72, 65, + 70, 22, 68, 36, 3, 71, 69, 82, 74, 77, 124, 2, 80, 65, 28, 4, 69, 84, 78, + 65, 20, 2, 81, 65, 58, 83, 58, 84, 156, 1, 2, 89, 69, 78, 90, 224, 172, + 8, 3, 82, 69, 86, 190, 146, 15, 79, 245, 148, 1, 3, 73, 76, 85, 2, 243, + 169, 18, 85, 4, 206, 146, 19, 69, 171, 149, 5, 65, 6, 32, 3, 69, 83, 72, + 179, 28, 83, 5, 241, 227, 6, 4, 32, 77, 85, 81, 8, 84, 5, 69, 82, 75, 72, + 65, 132, 251, 17, 2, 85, 78, 153, 45, 5, 65, 72, 65, 80, 65, 5, 221, 237, + 19, 4, 32, 75, 69, 70, 4, 26, 83, 219, 170, 24, 90, 2, 247, 195, 24, 72, + 4, 224, 163, 24, 6, 82, 78, 69, 89, 32, 80, 191, 35, 68, 4, 182, 24, 69, + 185, 237, 22, 6, 72, 65, 76, 83, 72, 69, 8, 38, 69, 241, 233, 22, 3, 73, + 80, 69, 6, 48, 6, 76, 73, 83, 72, 65, 32, 135, 232, 11, 86, 4, 252, 178, + 22, 3, 81, 69, 84, 205, 145, 2, 4, 71, 69, 68, 79, 4, 176, 212, 8, 10, + 82, 65, 72, 32, 66, 69, 78, 32, 89, 79, 231, 221, 2, 84, 8, 18, 65, 95, + 73, 6, 40, 4, 81, 69, 70, 32, 167, 134, 6, 82, 4, 246, 142, 11, 81, 149, + 193, 12, 3, 71, 65, 68, 2, 255, 171, 24, 78, 150, 1, 76, 6, 69, 84, 84, + 69, 82, 32, 201, 11, 8, 73, 71, 65, 84, 85, 82, 69, 32, 140, 1, 134, 3, + 65, 204, 1, 3, 66, 69, 84, 0, 3, 75, 65, 70, 0, 2, 80, 69, 68, 6, 70, 73, + 78, 65, 76, 32, 92, 2, 81, 79, 16, 2, 72, 69, 52, 2, 78, 85, 0, 4, 90, + 65, 89, 73, 18, 83, 48, 3, 82, 69, 83, 170, 1, 84, 52, 4, 68, 65, 76, 69, + 12, 5, 71, 73, 77, 69, 76, 0, 5, 76, 65, 77, 69, 68, 0, 3, 77, 69, 77, + 48, 3, 86, 65, 86, 80, 5, 87, 73, 68, 69, 32, 153, 1, 3, 89, 79, 68, 14, + 26, 76, 135, 225, 23, 89, 12, 64, 2, 69, 70, 73, 10, 84, 69, 82, 78, 65, + 84, 73, 86, 69, 32, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 130, 13, 77, + 130, 1, 80, 35, 81, 4, 198, 214, 16, 65, 131, 161, 1, 80, 7, 33, 6, 32, + 87, 73, 84, 72, 32, 4, 138, 15, 82, 195, 233, 13, 68, 14, 88, 2, 75, 65, + 236, 2, 2, 80, 69, 148, 154, 1, 2, 84, 83, 218, 192, 22, 78, 135, 110, + 77, 4, 235, 2, 70, 7, 244, 10, 5, 32, 87, 73, 84, 72, 131, 211, 24, 84, + 4, 167, 2, 78, 16, 44, 4, 65, 77, 69, 75, 17, 3, 72, 73, 78, 4, 231, 1, + 72, 13, 33, 6, 32, 87, 73, 84, 72, 32, 10, 40, 6, 68, 65, 71, 69, 83, 72, + 39, 83, 7, 33, 6, 32, 65, 78, 68, 32, 83, 4, 218, 133, 6, 72, 155, 193, + 2, 73, 12, 50, 69, 12, 2, 65, 86, 1, 4, 83, 65, 68, 73, 4, 11, 84, 5, + 225, 244, 13, 7, 32, 87, 73, 84, 72, 32, 68, 7, 33, 6, 32, 87, 73, 84, + 72, 32, 4, 208, 253, 1, 2, 72, 79, 191, 246, 11, 68, 16, 174, 2, 76, 254, + 210, 8, 65, 178, 196, 2, 84, 158, 218, 2, 82, 156, 132, 9, 2, 68, 65, + 218, 96, 75, 222, 106, 72, 169, 4, 7, 70, 73, 78, 65, 76, 32, 77, 7, 33, + 6, 32, 87, 73, 84, 72, 32, 4, 172, 7, 2, 72, 73, 251, 234, 13, 68, 10, + 72, 6, 65, 76, 69, 70, 32, 76, 29, 8, 89, 73, 68, 68, 73, 83, 72, 32, 2, + 209, 195, 19, 2, 65, 77, 8, 120, 7, 68, 79, 85, 66, 76, 69, 32, 232, 4, + 9, 89, 79, 68, 32, 89, 79, 68, 32, 80, 193, 151, 21, 5, 86, 65, 86, 32, + 89, 4, 146, 150, 11, 86, 151, 134, 10, 89, 6, 80, 3, 76, 79, 87, 0, 3, + 85, 80, 80, 173, 129, 23, 6, 77, 65, 83, 79, 82, 65, 2, 169, 194, 23, 2, + 69, 82, 50, 84, 5, 79, 73, 78, 84, 32, 225, 5, 11, 85, 78, 67, 84, 85, + 65, 84, 73, 79, 78, 32, 38, 228, 1, 9, 68, 65, 71, 69, 83, 72, 32, 79, + 82, 46, 72, 106, 80, 162, 1, 81, 86, 82, 22, 83, 224, 216, 9, 2, 84, 83, + 224, 157, 11, 17, 74, 85, 68, 69, 79, 45, 83, 80, 65, 78, 73, 83, 72, 32, + 86, 65, 82, 189, 147, 3, 3, 77, 69, 84, 2, 17, 2, 32, 77, 2, 197, 1, 2, + 65, 80, 12, 60, 5, 65, 84, 65, 70, 32, 102, 73, 33, 4, 79, 76, 65, 77, 6, + 38, 80, 34, 81, 141, 2, 2, 83, 69, 2, 11, 65, 2, 223, 227, 17, 84, 2, + 129, 201, 23, 2, 65, 77, 2, 11, 82, 2, 139, 238, 13, 73, 5, 205, 144, 11, + 12, 32, 72, 65, 83, 69, 82, 32, 70, 79, 82, 32, 86, 6, 52, 5, 65, 77, 65, + 84, 83, 245, 198, 11, 2, 85, 66, 5, 241, 249, 10, 2, 32, 81, 2, 159, 232, + 6, 65, 8, 34, 69, 22, 72, 163, 186, 8, 73, 2, 179, 186, 23, 71, 4, 158, + 186, 8, 73, 223, 214, 7, 69, 12, 152, 1, 3, 71, 69, 82, 60, 3, 80, 65, + 83, 20, 7, 83, 79, 70, 32, 80, 65, 83, 240, 144, 22, 7, 78, 85, 78, 32, + 72, 65, 70, 253, 186, 1, 3, 77, 65, 81, 4, 26, 83, 203, 226, 22, 69, 2, + 253, 202, 23, 3, 72, 65, 89, 2, 151, 234, 13, 69, 2, 131, 234, 13, 85, 8, + 114, 77, 200, 157, 12, 15, 76, 83, 67, 72, 82, 69, 73, 66, 69, 82, 32, + 80, 65, 85, 83, 229, 227, 5, 3, 73, 67, 79, 4, 144, 229, 5, 12, 69, 84, + 32, 87, 73, 84, 72, 32, 87, 72, 73, 84, 203, 209, 17, 32, 188, 4, 164, 1, + 2, 65, 45, 50, 72, 70, 75, 230, 1, 77, 114, 78, 146, 2, 82, 66, 83, 154, + 1, 84, 226, 1, 87, 62, 89, 110, 69, 182, 248, 8, 85, 226, 174, 5, 79, + 139, 192, 3, 73, 8, 158, 171, 24, 87, 246, 30, 49, 2, 50, 3, 51, 72, 166, + 6, 79, 198, 198, 8, 65, 178, 228, 5, 85, 166, 116, 69, 3, 73, 74, 72, 2, + 65, 45, 104, 2, 79, 45, 178, 4, 73, 226, 3, 69, 187, 155, 15, 85, 24, + 146, 242, 11, 49, 238, 191, 12, 75, 214, 22, 50, 2, 51, 2, 52, 2, 53, 2, + 54, 2, 55, 2, 56, 3, 57, 8, 146, 180, 24, 75, 218, 19, 49, 2, 50, 3, 51, + 54, 68, 2, 69, 45, 154, 7, 79, 186, 155, 15, 65, 2, 73, 231, 203, 2, 85, + 6, 186, 196, 24, 77, 186, 2, 49, 3, 50, 68, 116, 2, 69, 45, 72, 2, 73, + 45, 246, 2, 65, 242, 250, 8, 79, 226, 174, 5, 85, 225, 146, 6, 6, 45, 77, + 85, 45, 77, 79, 14, 222, 166, 24, 75, 246, 30, 49, 2, 50, 2, 51, 2, 52, + 2, 53, 3, 54, 16, 182, 174, 24, 84, 214, 22, 49, 2, 50, 2, 51, 2, 52, 2, + 53, 2, 54, 3, 55, 54, 222, 4, 79, 2, 85, 186, 155, 15, 73, 230, 203, 2, + 65, 3, 69, 68, 62, 65, 2, 85, 226, 3, 73, 182, 248, 8, 69, 135, 163, 6, + 79, 16, 11, 45, 16, 174, 195, 24, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, + 2, 55, 3, 56, 64, 74, 69, 20, 2, 79, 45, 72, 2, 85, 45, 154, 157, 15, 73, + 231, 203, 2, 65, 18, 247, 129, 19, 45, 14, 202, 191, 24, 82, 186, 2, 49, + 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 10, 198, 162, 24, 84, 246, 30, 49, 2, + 50, 2, 51, 3, 52, 42, 218, 249, 8, 65, 2, 73, 134, 163, 6, 79, 231, 203, + 2, 69, 32, 40, 2, 65, 45, 66, 79, 159, 231, 17, 85, 12, 166, 161, 24, 89, + 246, 30, 49, 2, 50, 2, 51, 2, 52, 3, 53, 12, 11, 45, 12, 206, 191, 24, + 49, 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 4, 188, 174, 8, 21, 77, 73, 84, + 73, 65, 78, 32, 67, 79, 78, 74, 85, 71, 65, 84, 69, 32, 77, 65, 84, 82, + 215, 144, 16, 66, 128, 1, 210, 2, 65, 110, 66, 144, 1, 2, 67, 79, 94, 68, + 198, 2, 70, 66, 71, 40, 4, 72, 79, 76, 68, 164, 1, 2, 73, 78, 116, 2, 77, + 79, 58, 79, 122, 80, 100, 2, 82, 69, 66, 83, 238, 1, 84, 210, 5, 87, 172, + 168, 15, 4, 76, 73, 77, 73, 140, 191, 5, 11, 89, 79, 85, 84, 72, 70, 85, + 76, 32, 70, 79, 137, 177, 3, 9, 69, 78, 84, 72, 85, 83, 73, 65, 83, 6, + 76, 3, 80, 80, 82, 124, 4, 70, 84, 69, 82, 209, 169, 19, 4, 66, 85, 78, + 68, 2, 201, 152, 24, 2, 79, 65, 6, 92, 5, 69, 70, 79, 82, 69, 232, 216, + 3, 6, 73, 84, 73, 78, 71, 32, 1, 4, 82, 69, 65, 75, 2, 165, 233, 23, 7, + 32, 67, 79, 77, 80, 76, 69, 6, 26, 78, 203, 160, 19, 77, 4, 204, 210, 20, + 4, 84, 69, 77, 80, 209, 213, 2, 3, 70, 76, 73, 14, 110, 69, 78, 73, 226, + 164, 19, 85, 241, 245, 2, 15, 65, 82, 75, 69, 78, 73, 78, 71, 32, 79, 70, + 32, 84, 72, 69, 6, 242, 160, 19, 67, 192, 6, 2, 76, 73, 149, 205, 4, 5, + 86, 69, 76, 79, 80, 4, 144, 151, 19, 21, 70, 70, 73, 67, 85, 76, 84, 89, + 32, 65, 84, 32, 84, 72, 69, 32, 66, 69, 71, 73, 78, 169, 253, 2, 4, 83, + 80, 69, 82, 4, 240, 155, 19, 2, 79, 76, 165, 197, 4, 5, 69, 76, 76, 79, + 87, 12, 36, 5, 65, 84, 72, 69, 82, 35, 82, 2, 189, 147, 15, 3, 73, 78, + 71, 10, 40, 4, 69, 65, 84, 32, 251, 247, 23, 65, 8, 22, 80, 215, 5, 84, + 6, 22, 79, 151, 5, 82, 4, 172, 2, 2, 83, 83, 171, 244, 23, 87, 8, 50, 78, + 226, 156, 19, 67, 217, 5, 3, 70, 76, 85, 4, 180, 162, 19, 2, 79, 67, 197, + 236, 1, 5, 69, 82, 32, 84, 82, 4, 196, 195, 22, 3, 68, 69, 83, 145, 62, + 3, 85, 84, 72, 6, 26, 66, 37, 2, 80, 80, 2, 245, 225, 23, 4, 83, 84, 82, + 85, 4, 26, 82, 207, 224, 23, 79, 2, 157, 143, 22, 2, 69, 83, 6, 160, 152, + 15, 9, 85, 83, 72, 73, 78, 71, 32, 85, 80, 192, 137, 2, 3, 82, 79, 71, + 143, 211, 6, 69, 6, 26, 84, 227, 140, 19, 86, 4, 146, 158, 19, 85, 171, + 137, 4, 82, 8, 132, 1, 5, 77, 65, 76, 76, 32, 248, 179, 21, 6, 84, 65, + 78, 68, 83, 84, 185, 244, 1, 11, 80, 76, 73, 84, 84, 73, 78, 71, 32, 65, + 80, 4, 24, 2, 80, 82, 43, 84, 2, 241, 158, 19, 5, 69, 80, 79, 78, 68, 2, + 11, 65, 2, 247, 221, 23, 77, 30, 36, 3, 72, 69, 32, 251, 231, 17, 82, 28, + 186, 2, 65, 130, 1, 67, 132, 1, 3, 70, 65, 77, 20, 9, 82, 69, 67, 69, 80, + 84, 73, 86, 69, 30, 87, 172, 22, 12, 77, 65, 82, 82, 89, 73, 78, 71, 32, + 77, 65, 73, 132, 154, 5, 6, 71, 69, 78, 84, 76, 69, 240, 227, 10, 13, 75, + 69, 69, 80, 73, 78, 71, 32, 83, 84, 73, 76, 76, 173, 238, 3, 7, 74, 79, + 89, 79, 85, 83, 32, 6, 58, 82, 185, 188, 11, 8, 66, 89, 83, 77, 65, 76, + 32, 87, 4, 220, 191, 20, 8, 79, 85, 83, 73, 78, 71, 32, 84, 163, 218, 3, + 77, 6, 188, 131, 1, 2, 65, 85, 252, 186, 19, 9, 82, 69, 65, 84, 73, 86, + 69, 32, 72, 161, 212, 1, 9, 76, 73, 78, 71, 73, 78, 71, 32, 70, 2, 207, + 134, 24, 73, 2, 129, 189, 20, 2, 32, 69, 4, 166, 159, 22, 69, 189, 204, + 1, 5, 65, 78, 68, 69, 82, 4, 190, 238, 6, 65, 153, 167, 6, 14, 79, 82, + 75, 32, 79, 78, 32, 84, 72, 69, 32, 68, 69, 67, 222, 1, 236, 1, 2, 71, + 72, 180, 2, 7, 82, 65, 71, 65, 78, 65, 32, 212, 4, 7, 83, 84, 79, 82, 73, + 67, 32, 236, 198, 15, 7, 78, 68, 85, 32, 84, 69, 77, 240, 33, 4, 75, 73, + 78, 71, 218, 249, 1, 66, 169, 180, 4, 8, 80, 80, 79, 80, 79, 84, 65, 77, + 12, 18, 32, 119, 45, 6, 164, 142, 5, 2, 66, 82, 132, 248, 16, 6, 86, 79, + 76, 84, 65, 71, 217, 49, 9, 79, 67, 84, 69, 84, 32, 80, 82, 69, 6, 92, + 11, 83, 80, 69, 69, 68, 32, 84, 82, 65, 73, 78, 249, 206, 5, 6, 72, 69, + 69, 76, 69, 68, 5, 181, 193, 11, 14, 32, 87, 73, 84, 72, 32, 66, 85, 76, + 76, 69, 84, 32, 78, 200, 1, 112, 9, 68, 73, 71, 82, 65, 80, 72, 32, 89, + 20, 7, 76, 69, 84, 84, 69, 82, 32, 154, 173, 1, 86, 215, 207, 20, 73, 2, + 207, 183, 17, 79, 194, 1, 194, 1, 65, 74, 83, 138, 164, 1, 66, 162, 3, + 78, 150, 2, 68, 2, 71, 2, 72, 2, 75, 2, 77, 2, 80, 2, 82, 2, 84, 2, 90, + 126, 87, 46, 89, 174, 209, 22, 86, 234, 36, 69, 2, 73, 2, 79, 3, 85, 7, + 37, 7, 82, 67, 72, 65, 73, 67, 32, 4, 174, 252, 23, 87, 151, 14, 89, 42, + 76, 5, 77, 65, 76, 76, 32, 170, 160, 24, 65, 2, 69, 2, 73, 2, 79, 3, 85, + 32, 230, 169, 1, 87, 46, 89, 226, 179, 5, 75, 206, 157, 17, 84, 234, 36, + 65, 2, 69, 2, 73, 2, 79, 3, 85, 2, 183, 186, 8, 83, 108, 166, 1, 76, 52, + 3, 78, 69, 89, 46, 82, 146, 7, 84, 138, 1, 85, 230, 200, 16, 83, 178, + 219, 2, 67, 220, 198, 3, 6, 77, 79, 84, 72, 69, 84, 134, 167, 1, 79, 155, + 3, 80, 6, 132, 153, 16, 4, 76, 79, 87, 32, 255, 132, 8, 69, 4, 174, 171, + 22, 66, 233, 161, 1, 2, 32, 80, 66, 60, 8, 73, 90, 79, 78, 84, 65, 76, + 32, 153, 6, 2, 83, 69, 60, 218, 1, 66, 110, 76, 152, 1, 17, 79, 78, 69, + 32, 69, 73, 71, 72, 84, 72, 32, 66, 76, 79, 67, 75, 45, 88, 10, 83, 67, + 65, 78, 32, 76, 73, 78, 69, 45, 46, 84, 170, 240, 21, 67, 42, 69, 230, 6, + 77, 150, 1, 82, 247, 2, 90, 6, 44, 5, 76, 65, 67, 75, 32, 255, 225, 23, + 65, 4, 38, 79, 241, 223, 22, 3, 72, 69, 88, 2, 227, 223, 22, 67, 10, 40, + 4, 73, 78, 69, 32, 143, 246, 21, 65, 8, 44, 5, 87, 73, 84, 72, 32, 179, + 246, 21, 69, 6, 26, 84, 219, 247, 21, 70, 4, 250, 247, 21, 72, 243, 91, + 73, 14, 208, 237, 16, 3, 49, 51, 53, 178, 171, 7, 50, 2, 51, 2, 52, 2, + 53, 2, 54, 3, 55, 8, 170, 152, 24, 49, 2, 51, 2, 55, 3, 57, 10, 32, 2, + 65, 66, 223, 250, 21, 82, 8, 26, 85, 223, 249, 21, 32, 6, 33, 6, 76, 65, + 84, 73, 79, 78, 7, 11, 32, 4, 152, 205, 9, 8, 87, 73, 84, 72, 32, 74, 85, + 83, 223, 148, 14, 83, 7, 11, 32, 4, 204, 198, 7, 2, 82, 65, 235, 146, 16, + 70, 10, 26, 32, 171, 138, 23, 69, 8, 86, 80, 128, 134, 19, 5, 66, 69, 86, + 69, 82, 144, 80, 3, 83, 80, 82, 179, 190, 4, 68, 2, 255, 242, 14, 69, 12, + 48, 6, 82, 71, 76, 65, 83, 83, 77, 2, 83, 69, 5, 129, 194, 20, 14, 32, + 87, 73, 84, 72, 32, 70, 76, 79, 87, 73, 78, 71, 32, 9, 11, 32, 6, 88, 8, + 87, 73, 84, 72, 32, 71, 65, 82, 205, 137, 22, 8, 66, 85, 73, 76, 68, 73, + 78, 71, 2, 159, 189, 22, 68, 7, 142, 147, 24, 74, 3, 83, 8, 106, 83, 184, + 252, 22, 11, 78, 68, 82, 69, 68, 32, 80, 79, 73, 78, 84, 176, 13, 2, 71, + 71, 163, 136, 1, 84, 2, 147, 255, 22, 72, 20, 80, 2, 71, 73, 22, 80, 224, + 1, 5, 83, 84, 69, 82, 69, 185, 137, 22, 2, 65, 67, 4, 151, 252, 21, 69, + 12, 60, 3, 72, 69, 78, 221, 160, 4, 6, 79, 68, 73, 65, 83, 84, 11, 34, + 32, 82, 65, 227, 132, 20, 45, 4, 26, 87, 239, 173, 22, 66, 2, 21, 3, 73, + 84, 72, 2, 145, 190, 3, 2, 32, 68, 2, 165, 228, 12, 6, 84, 73, 79, 78, + 32, 80, 2, 217, 249, 22, 2, 83, 73, 210, 5, 172, 1, 3, 67, 69, 32, 152, + 1, 2, 68, 69, 222, 24, 77, 222, 2, 78, 230, 35, 82, 132, 2, 7, 90, 65, + 75, 65, 89, 65, 32, 209, 250, 19, 9, 32, 76, 79, 86, 69, 32, 89, 79, 85, + 8, 114, 67, 132, 169, 11, 18, 72, 79, 67, 75, 69, 89, 32, 83, 84, 73, 67, + 75, 32, 65, 78, 68, 32, 80, 235, 190, 1, 83, 4, 162, 252, 15, 82, 223, + 231, 2, 85, 246, 1, 68, 3, 78, 84, 73, 201, 1, 9, 79, 71, 82, 65, 80, 72, + 73, 67, 32, 8, 64, 4, 67, 65, 76, 32, 105, 8, 70, 73, 67, 65, 84, 73, 79, + 78, 6, 32, 2, 84, 79, 155, 138, 23, 87, 5, 173, 255, 14, 12, 32, 65, 78, + 68, 32, 83, 76, 65, 78, 84, 69, 68, 2, 205, 241, 22, 2, 32, 67, 238, 1, + 208, 2, 11, 65, 78, 78, 79, 84, 65, 84, 73, 79, 78, 32, 242, 3, 67, 72, + 2, 68, 69, 248, 5, 5, 78, 85, 77, 66, 69, 22, 84, 172, 243, 5, 8, 72, 65, + 76, 70, 32, 70, 73, 76, 232, 186, 1, 5, 69, 78, 84, 69, 82, 0, 3, 82, 73, + 83, 24, 5, 76, 69, 86, 69, 76, 188, 143, 9, 5, 86, 65, 82, 73, 65, 250, + 233, 4, 70, 154, 47, 73, 243, 231, 1, 83, 32, 232, 1, 5, 66, 79, 84, 84, + 79, 22, 70, 82, 77, 62, 84, 140, 1, 4, 76, 73, 78, 75, 196, 143, 1, 4, + 83, 69, 67, 79, 182, 165, 6, 79, 172, 135, 6, 6, 82, 69, 86, 69, 82, 83, + 152, 222, 9, 5, 72, 69, 65, 86, 69, 169, 39, 3, 69, 65, 82, 2, 167, 196, + 23, 77, 6, 48, 3, 79, 85, 82, 221, 186, 23, 3, 73, 82, 83, 4, 210, 195, + 23, 84, 27, 32, 4, 36, 3, 73, 68, 68, 223, 155, 23, 65, 2, 195, 189, 13, + 76, 8, 34, 72, 46, 87, 227, 137, 8, 79, 4, 214, 149, 9, 82, 181, 162, 14, + 2, 73, 82, 2, 183, 194, 23, 79, 4, 36, 3, 76, 79, 83, 251, 173, 21, 79, + 2, 249, 193, 23, 3, 73, 78, 71, 36, 104, 20, 83, 67, 82, 73, 80, 84, 73, + 79, 78, 32, 67, 72, 65, 82, 65, 67, 84, 69, 82, 32, 159, 179, 7, 80, 34, + 144, 2, 9, 65, 66, 79, 86, 69, 32, 84, 79, 32, 84, 8, 76, 69, 70, 84, 32, + 84, 79, 32, 76, 5, 79, 86, 69, 82, 76, 20, 2, 83, 85, 246, 253, 14, 82, + 172, 200, 5, 8, 70, 85, 76, 76, 32, 83, 85, 82, 229, 231, 2, 15, 72, 79, + 82, 73, 90, 79, 78, 84, 65, 76, 32, 82, 69, 70, 76, 4, 60, 9, 77, 73, 68, + 68, 76, 69, 32, 65, 78, 247, 221, 21, 66, 2, 199, 206, 21, 68, 4, 168, + 172, 22, 10, 77, 73, 68, 68, 76, 69, 32, 65, 78, 68, 211, 168, 1, 82, 2, + 171, 233, 16, 65, 18, 72, 12, 82, 82, 79, 85, 78, 68, 32, 70, 82, 79, 77, + 32, 247, 189, 17, 66, 16, 82, 76, 232, 211, 11, 3, 85, 80, 80, 250, 135, + 10, 66, 130, 165, 1, 65, 159, 82, 82, 6, 218, 211, 11, 79, 147, 255, 11, + 69, 2, 251, 220, 8, 82, 148, 1, 92, 10, 65, 76, 76, 89, 32, 77, 65, 82, + 75, 32, 41, 9, 69, 76, 69, 71, 82, 65, 80, 72, 32, 10, 162, 137, 22, 70, + 70, 84, 155, 87, 79, 138, 1, 140, 1, 11, 83, 89, 77, 66, 79, 76, 32, 70, + 79, 82, 32, 245, 238, 12, 17, 76, 73, 78, 69, 32, 70, 69, 69, 68, 32, 83, + 69, 80, 65, 82, 65, 84, 136, 1, 182, 1, 65, 58, 68, 200, 2, 5, 72, 79, + 85, 82, 32, 214, 1, 74, 28, 4, 70, 69, 66, 82, 64, 2, 77, 65, 192, 204, + 15, 3, 78, 79, 86, 0, 4, 83, 69, 80, 84, 25, 4, 79, 67, 84, 79, 4, 192, + 139, 20, 3, 85, 71, 85, 165, 142, 2, 2, 80, 82, 64, 44, 3, 65, 89, 32, + 137, 209, 15, 2, 69, 67, 62, 66, 84, 218, 215, 5, 69, 66, 70, 70, 78, 26, + 83, 235, 131, 17, 79, 34, 34, 72, 90, 87, 179, 167, 23, 69, 8, 36, 3, 73, + 82, 84, 163, 133, 22, 82, 6, 26, 89, 163, 161, 22, 69, 5, 203, 202, 22, + 45, 24, 26, 69, 247, 246, 23, 79, 22, 36, 3, 78, 84, 89, 251, 249, 22, + 76, 21, 163, 171, 15, 45, 50, 78, 84, 182, 213, 5, 69, 66, 70, 70, 78, + 26, 83, 142, 173, 16, 90, 223, 86, 79, 20, 42, 87, 146, 215, 5, 72, 207, + 206, 17, 69, 14, 26, 69, 163, 245, 23, 79, 12, 36, 3, 78, 84, 89, 167, + 248, 22, 76, 11, 199, 166, 17, 45, 6, 24, 2, 65, 78, 35, 85, 2, 11, 85, + 2, 215, 174, 17, 65, 4, 210, 221, 23, 78, 143, 5, 76, 4, 222, 209, 23, + 82, 171, 34, 89, 68, 40, 6, 65, 71, 69, 32, 79, 70, 83, 80, 5, 241, 138, + 9, 15, 32, 79, 82, 32, 65, 80, 80, 82, 79, 88, 73, 77, 65, 84, 69, 65, + 65, 14, 69, 82, 73, 65, 76, 32, 65, 82, 65, 77, 65, 73, 67, 32, 62, 72, + 7, 78, 85, 77, 66, 69, 82, 32, 230, 18, 76, 205, 217, 19, 2, 83, 69, 16, + 26, 84, 211, 207, 15, 79, 10, 154, 191, 11, 87, 250, 147, 1, 69, 131, + 172, 9, 72, 136, 3, 202, 1, 67, 234, 1, 68, 214, 6, 70, 132, 2, 5, 72, + 73, 66, 73, 84, 156, 1, 15, 80, 85, 84, 32, 83, 89, 77, 66, 79, 76, 32, + 70, 79, 82, 32, 206, 1, 83, 236, 5, 2, 84, 69, 206, 8, 86, 171, 130, 10, + 66, 10, 32, 2, 79, 77, 69, 2, 82, 69, 4, 164, 215, 16, 3, 73, 78, 71, + 209, 230, 2, 5, 80, 76, 69, 84, 69, 6, 36, 3, 65, 83, 69, 135, 171, 23, + 77, 4, 34, 32, 181, 188, 10, 2, 83, 32, 2, 185, 191, 11, 8, 70, 79, 78, + 84, 32, 83, 73, 90, 145, 1, 24, 2, 69, 88, 103, 73, 5, 173, 210, 22, 20, + 32, 80, 79, 73, 78, 84, 73, 78, 71, 32, 65, 84, 32, 84, 72, 69, 32, 86, + 73, 69, 138, 1, 72, 8, 67, 32, 83, 73, 89, 65, 81, 32, 197, 144, 18, 4, + 65, 78, 32, 82, 136, 1, 196, 1, 11, 65, 76, 84, 69, 82, 78, 65, 84, 69, + 32, 76, 2, 76, 28, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 100, 7, 78, 85, + 77, 66, 69, 82, 32, 210, 250, 8, 82, 153, 125, 6, 80, 76, 65, 67, 69, 72, + 2, 225, 168, 23, 2, 65, 75, 6, 68, 4, 79, 78, 69, 32, 229, 229, 21, 7, + 84, 72, 82, 69, 69, 32, 81, 4, 186, 227, 21, 72, 47, 81, 122, 212, 1, 10, + 65, 76, 84, 69, 82, 78, 65, 84, 69, 32, 72, 5, 75, 65, 82, 79, 82, 0, 4, + 76, 65, 75, 72, 246, 145, 10, 69, 66, 70, 94, 78, 26, 83, 78, 84, 236, + 135, 5, 8, 80, 82, 69, 70, 73, 88, 69, 68, 199, 41, 79, 6, 26, 84, 147, + 204, 22, 79, 4, 208, 167, 6, 2, 69, 78, 251, 160, 17, 87, 5, 179, 151, + 23, 65, 16, 72, 5, 73, 78, 73, 84, 89, 85, 9, 79, 82, 77, 65, 84, 73, 79, + 78, 32, 5, 45, 9, 32, 78, 69, 71, 65, 84, 69, 68, 32, 2, 173, 175, 8, 4, + 87, 73, 84, 72, 12, 42, 83, 249, 224, 19, 4, 68, 69, 83, 75, 10, 192, + 156, 7, 5, 69, 80, 65, 82, 65, 191, 129, 10, 79, 4, 11, 32, 4, 220, 147, + 23, 15, 65, 82, 65, 66, 73, 67, 32, 70, 79, 82, 77, 32, 83, 72, 65, 1, 14, 83, 89, 77, 77, 69, 84, 82, 73, 67, 32, 83, 87, 65, 80, 10, 80, 6, - 76, 65, 84, 73, 78, 32, 198, 240, 14, 83, 165, 201, 7, 4, 78, 85, 77, 66, + 76, 65, 84, 73, 78, 32, 242, 252, 14, 83, 161, 213, 7, 4, 78, 85, 77, 66, 6, 64, 6, 67, 65, 80, 73, 84, 65, 0, 4, 83, 77, 65, 76, 27, 76, 2, 21, 3, - 76, 32, 76, 2, 253, 198, 21, 2, 69, 84, 116, 84, 13, 67, 82, 73, 80, 84, - 73, 79, 78, 65, 76, 32, 80, 65, 209, 196, 15, 2, 69, 82, 114, 72, 6, 72, + 76, 32, 76, 2, 217, 222, 21, 2, 69, 84, 116, 84, 13, 67, 82, 73, 80, 84, + 73, 79, 78, 65, 76, 32, 80, 65, 141, 209, 15, 2, 69, 82, 114, 72, 6, 72, 76, 65, 86, 73, 32, 225, 1, 7, 82, 84, 72, 73, 65, 78, 32, 54, 48, 7, 76, - 69, 84, 84, 69, 82, 32, 191, 3, 78, 38, 134, 173, 10, 84, 226, 118, 65, - 22, 68, 34, 76, 22, 77, 50, 87, 186, 165, 4, 71, 90, 90, 34, 83, 66, 89, - 158, 208, 1, 72, 234, 5, 75, 198, 75, 66, 178, 216, 4, 78, 223, 105, 80, + 69, 84, 84, 69, 82, 32, 191, 3, 78, 38, 130, 180, 10, 84, 222, 119, 65, + 22, 68, 34, 76, 22, 77, 50, 87, 254, 169, 4, 71, 90, 90, 34, 83, 66, 89, + 198, 207, 1, 72, 234, 5, 75, 174, 81, 66, 170, 225, 4, 78, 223, 105, 80, 60, 22, 76, 251, 1, 78, 44, 11, 69, 44, 29, 5, 84, 84, 69, 82, 32, 44, - 150, 171, 10, 84, 246, 118, 68, 34, 76, 50, 81, 238, 205, 1, 82, 178, - 215, 2, 65, 50, 71, 90, 90, 34, 83, 66, 89, 158, 208, 1, 72, 234, 5, 75, - 198, 75, 66, 178, 216, 4, 78, 134, 2, 87, 218, 103, 80, 171, 4, 77, 16, - 33, 6, 85, 77, 66, 69, 82, 32, 16, 146, 162, 11, 84, 174, 140, 4, 79, - 219, 128, 3, 70, 50, 36, 4, 71, 82, 65, 76, 179, 3, 82, 23, 11, 32, 20, - 58, 65, 140, 1, 5, 87, 73, 84, 72, 32, 175, 160, 21, 69, 4, 96, 6, 86, - 69, 82, 65, 71, 69, 145, 168, 16, 12, 82, 79, 85, 78, 68, 32, 65, 32, 80, - 79, 73, 78, 2, 181, 169, 16, 5, 32, 87, 73, 84, 72, 14, 160, 1, 3, 84, - 73, 77, 20, 2, 85, 78, 248, 235, 6, 16, 76, 69, 70, 84, 87, 65, 82, 68, - 83, 32, 65, 82, 82, 79, 87, 32, 210, 162, 13, 73, 198, 1, 79, 247, 64, - 68, 2, 139, 144, 20, 69, 4, 150, 144, 20, 68, 175, 222, 2, 73, 28, 94, - 76, 232, 1, 7, 83, 69, 67, 84, 73, 79, 78, 146, 7, 82, 228, 249, 11, 2, + 146, 178, 10, 84, 242, 119, 68, 34, 76, 50, 81, 214, 205, 1, 82, 142, + 220, 2, 65, 50, 71, 90, 90, 34, 83, 66, 89, 198, 207, 1, 72, 234, 5, 75, + 174, 81, 66, 170, 225, 4, 78, 134, 2, 87, 218, 103, 80, 171, 4, 77, 16, + 33, 6, 85, 77, 66, 69, 82, 32, 16, 138, 170, 11, 84, 226, 144, 4, 79, + 167, 134, 3, 70, 50, 36, 4, 71, 82, 65, 76, 179, 3, 82, 23, 11, 32, 20, + 58, 65, 140, 1, 5, 87, 73, 84, 72, 32, 159, 183, 21, 69, 4, 96, 6, 86, + 69, 82, 65, 71, 69, 193, 180, 16, 12, 82, 79, 85, 78, 68, 32, 65, 32, 80, + 79, 73, 78, 2, 229, 181, 16, 5, 32, 87, 73, 84, 72, 14, 160, 1, 3, 84, + 73, 77, 20, 2, 85, 78, 248, 242, 6, 16, 76, 69, 70, 84, 87, 65, 82, 68, + 83, 32, 65, 82, 82, 79, 87, 32, 194, 178, 13, 73, 198, 1, 79, 251, 64, + 68, 2, 251, 166, 20, 69, 4, 134, 167, 20, 68, 131, 226, 2, 73, 28, 94, + 76, 232, 1, 7, 83, 69, 67, 84, 73, 79, 78, 146, 7, 82, 128, 130, 12, 2, 67, 65, 43, 73, 8, 164, 1, 17, 73, 78, 69, 65, 82, 32, 65, 78, 78, 79, - 84, 65, 84, 73, 79, 78, 32, 229, 232, 4, 17, 79, 67, 75, 69, 68, 32, 70, - 69, 77, 65, 76, 69, 32, 65, 78, 68, 32, 6, 140, 164, 8, 3, 65, 78, 67, - 170, 153, 8, 84, 243, 208, 3, 83, 15, 11, 32, 12, 168, 1, 6, 65, 66, 79, - 86, 69, 32, 64, 5, 87, 73, 84, 72, 32, 209, 137, 20, 22, 66, 69, 83, 73, + 84, 65, 84, 73, 79, 78, 32, 169, 239, 4, 17, 79, 67, 75, 69, 68, 32, 70, + 69, 77, 65, 76, 69, 32, 65, 78, 68, 32, 6, 156, 171, 8, 3, 65, 78, 67, + 222, 158, 8, 84, 159, 219, 3, 83, 15, 11, 32, 12, 168, 1, 6, 65, 66, 79, + 86, 69, 32, 64, 5, 87, 73, 84, 72, 32, 193, 160, 20, 22, 66, 69, 83, 73, 68, 69, 32, 65, 78, 68, 32, 74, 79, 73, 78, 69, 68, 32, 87, 73, 84, 72, - 4, 192, 138, 20, 9, 66, 65, 82, 32, 65, 66, 79, 86, 69, 23, 85, 6, 202, - 171, 4, 76, 222, 223, 15, 79, 239, 221, 2, 68, 40, 56, 2, 69, 82, 189, 5, + 4, 176, 161, 20, 9, 66, 65, 82, 32, 65, 66, 79, 86, 69, 23, 85, 6, 154, + 173, 4, 76, 254, 244, 15, 79, 195, 225, 2, 68, 40, 56, 2, 69, 82, 189, 5, 7, 73, 83, 73, 66, 76, 69, 32, 34, 48, 3, 83, 69, 32, 225, 2, 4, 84, 69, 68, 32, 16, 174, 1, 66, 80, 5, 67, 72, 69, 67, 75, 68, 24, 68, 79, 87, 78, 87, 65, 82, 68, 83, 32, 65, 82, 82, 79, 87, 32, 87, 73, 84, 72, 32, - 84, 73, 80, 250, 163, 20, 87, 215, 26, 77, 6, 44, 5, 76, 65, 67, 75, 32, - 159, 215, 21, 85, 4, 226, 249, 21, 68, 211, 27, 83, 4, 136, 190, 20, 8, - 69, 82, 32, 66, 79, 65, 82, 68, 231, 182, 2, 32, 2, 233, 215, 20, 2, 32, - 76, 18, 144, 1, 6, 73, 78, 84, 69, 82, 82, 22, 76, 142, 242, 11, 80, 206, - 180, 4, 69, 220, 193, 1, 2, 79, 72, 168, 153, 2, 4, 85, 78, 68, 69, 179, - 97, 81, 2, 139, 211, 4, 79, 6, 60, 9, 79, 87, 32, 75, 65, 86, 89, 75, 65, - 163, 228, 6, 65, 5, 237, 144, 18, 11, 32, 87, 73, 84, 72, 32, 75, 65, 86, - 89, 75, 6, 38, 84, 194, 172, 19, 80, 223, 88, 83, 2, 235, 168, 16, 73, - 218, 1, 94, 65, 134, 21, 69, 62, 79, 42, 85, 165, 187, 11, 10, 73, 71, - 83, 65, 87, 32, 80, 85, 90, 90, 202, 1, 120, 5, 67, 75, 45, 79, 45, 32, - 7, 80, 65, 78, 69, 83, 69, 32, 184, 2, 7, 86, 65, 78, 69, 83, 69, 32, - 171, 174, 23, 82, 2, 209, 166, 18, 3, 76, 65, 78, 16, 246, 1, 67, 18, 80, - 136, 157, 1, 10, 73, 78, 68, 85, 83, 84, 82, 73, 65, 76, 216, 223, 3, 3, - 66, 65, 78, 186, 173, 3, 68, 252, 128, 11, 15, 83, 89, 77, 66, 79, 76, - 32, 70, 79, 82, 32, 66, 69, 71, 73, 200, 246, 1, 3, 71, 79, 66, 197, 108, - 2, 79, 71, 2, 203, 32, 65, 2, 197, 136, 13, 7, 79, 83, 84, 32, 79, 70, - 70, 182, 1, 172, 2, 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, - 71, 78, 32, 76, 2, 76, 69, 40, 4, 82, 73, 71, 72, 224, 6, 2, 80, 65, 176, - 3, 14, 84, 85, 82, 78, 69, 68, 32, 80, 65, 68, 65, 32, 80, 73, 88, 5, 83, - 73, 71, 78, 32, 140, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, - 239, 173, 21, 68, 6, 52, 2, 75, 69, 152, 189, 16, 2, 80, 69, 175, 5, 67, - 2, 163, 246, 22, 82, 96, 38, 70, 65, 5, 84, 84, 69, 82, 32, 2, 41, 8, 84, - 32, 82, 69, 82, 69, 78, 71, 2, 211, 224, 21, 71, 94, 230, 1, 68, 26, 73, - 48, 2, 75, 65, 66, 78, 130, 1, 66, 2, 67, 2, 71, 16, 2, 80, 65, 56, 2, - 82, 65, 32, 2, 83, 65, 42, 84, 74, 74, 158, 155, 21, 65, 166, 135, 2, 72, - 2, 76, 2, 77, 2, 87, 2, 89, 186, 2, 69, 2, 79, 3, 85, 8, 222, 3, 68, 15, - 65, 7, 232, 198, 5, 3, 32, 75, 65, 215, 225, 17, 73, 7, 11, 32, 4, 22, - 83, 215, 2, 77, 2, 165, 242, 20, 2, 65, 83, 14, 36, 2, 71, 65, 90, 89, - 167, 1, 65, 7, 33, 6, 32, 76, 69, 76, 69, 84, 5, 29, 5, 32, 82, 65, 83, - 87, 2, 227, 223, 5, 65, 4, 163, 1, 65, 7, 11, 32, 4, 154, 1, 77, 245, - 161, 23, 3, 67, 69, 82, 5, 201, 192, 16, 3, 32, 65, 71, 7, 17, 2, 32, 77, - 4, 70, 85, 71, 65, 8, 18, 65, 55, 84, 5, 17, 2, 32, 77, 2, 11, 85, 2, - 135, 128, 23, 82, 4, 11, 65, 5, 11, 32, 2, 11, 77, 2, 11, 65, 2, 11, 72, - 2, 141, 174, 17, 2, 65, 80, 28, 40, 3, 68, 65, 32, 165, 3, 2, 78, 71, 24, - 174, 1, 65, 90, 76, 86, 80, 140, 144, 7, 10, 84, 73, 82, 84, 65, 32, 84, - 85, 77, 69, 130, 253, 11, 87, 164, 192, 2, 7, 73, 83, 69, 78, 45, 73, 83, - 141, 209, 1, 3, 77, 65, 68, 6, 44, 3, 68, 69, 71, 169, 145, 22, 2, 78, - 68, 5, 11, 32, 2, 157, 220, 22, 2, 65, 68, 6, 38, 85, 129, 159, 23, 3, - 73, 78, 71, 4, 160, 183, 18, 2, 78, 71, 207, 241, 3, 72, 4, 38, 73, 253, - 175, 18, 3, 65, 78, 71, 2, 145, 185, 16, 3, 83, 69, 76, 4, 220, 141, 13, - 5, 82, 65, 78, 71, 75, 135, 195, 9, 75, 10, 104, 5, 67, 69, 67, 65, 75, - 144, 197, 5, 5, 80, 65, 78, 89, 65, 176, 2, 3, 87, 73, 71, 227, 240, 10, - 76, 5, 209, 158, 18, 3, 32, 84, 69, 18, 116, 4, 83, 85, 75, 85, 42, 84, - 64, 4, 87, 85, 76, 85, 238, 182, 16, 80, 213, 218, 1, 7, 68, 73, 82, 71, - 65, 32, 77, 5, 193, 164, 22, 5, 32, 77, 69, 78, 68, 6, 26, 65, 171, 184, - 16, 79, 4, 146, 184, 16, 82, 187, 148, 6, 76, 5, 25, 4, 32, 77, 69, 76, - 2, 247, 153, 23, 73, 4, 36, 3, 76, 76, 89, 255, 216, 19, 65, 2, 219, 187, - 19, 70, 4, 180, 236, 21, 2, 89, 83, 171, 96, 73, 6, 168, 188, 14, 2, 71, - 71, 182, 253, 4, 80, 199, 195, 3, 78, 186, 25, 74, 65, 178, 78, 69, 218, - 1, 72, 150, 50, 73, 198, 6, 78, 50, 79, 111, 82, 200, 10, 200, 1, 5, 73, - 84, 72, 73, 32, 234, 4, 78, 188, 45, 6, 84, 65, 75, 65, 78, 65, 208, 13, - 3, 87, 73, 32, 220, 8, 7, 89, 65, 72, 32, 76, 73, 32, 204, 195, 4, 6, 75, - 84, 79, 86, 73, 75, 251, 223, 17, 65, 136, 1, 204, 1, 7, 76, 69, 84, 84, - 69, 82, 32, 178, 2, 83, 138, 116, 68, 208, 237, 3, 2, 86, 79, 160, 137, - 3, 11, 78, 85, 77, 66, 69, 82, 32, 83, 73, 71, 78, 230, 191, 9, 65, 229, - 211, 1, 6, 69, 78, 85, 77, 69, 82, 90, 214, 1, 68, 242, 187, 19, 65, 150, - 1, 84, 230, 5, 85, 206, 201, 1, 73, 162, 193, 1, 78, 46, 83, 82, 66, 2, - 67, 2, 71, 2, 74, 2, 75, 2, 80, 2, 82, 138, 69, 72, 2, 76, 2, 77, 2, 86, - 2, 89, 186, 2, 69, 3, 79, 10, 38, 68, 178, 147, 23, 72, 187, 2, 65, 6, - 166, 155, 21, 68, 138, 248, 1, 72, 187, 2, 65, 12, 40, 4, 73, 71, 78, 32, - 203, 148, 11, 69, 10, 202, 128, 19, 67, 98, 78, 234, 206, 3, 65, 239, 1, - 86, 230, 4, 42, 71, 241, 39, 5, 78, 65, 68, 65, 32, 174, 3, 76, 11, 88, - 73, 32, 82, 65, 68, 73, 67, 65, 76, 32, 169, 204, 20, 2, 65, 82, 172, 3, - 130, 2, 65, 94, 66, 230, 2, 67, 150, 2, 68, 158, 3, 69, 198, 1, 70, 138, - 2, 71, 146, 1, 72, 210, 2, 73, 76, 2, 74, 65, 34, 75, 30, 76, 230, 1, 77, - 254, 1, 78, 62, 79, 102, 80, 110, 82, 166, 1, 83, 230, 6, 84, 226, 2, 86, - 50, 87, 210, 2, 89, 199, 227, 21, 85, 10, 56, 2, 82, 82, 186, 228, 21, - 71, 182, 102, 78, 207, 47, 88, 4, 234, 146, 22, 79, 207, 1, 73, 34, 58, - 65, 38, 73, 46, 76, 54, 79, 102, 82, 203, 196, 21, 69, 4, 186, 196, 5, - 77, 163, 254, 13, 68, 6, 146, 216, 21, 84, 218, 113, 82, 163, 70, 71, 6, - 134, 217, 19, 79, 234, 134, 2, 65, 159, 153, 1, 85, 10, 62, 76, 194, 242, - 22, 65, 218, 5, 78, 142, 5, 68, 203, 17, 87, 2, 209, 218, 3, 4, 84, 32, - 79, 70, 6, 42, 73, 198, 241, 9, 65, 187, 180, 11, 85, 2, 191, 243, 13, - 83, 28, 58, 65, 70, 76, 74, 79, 214, 174, 10, 72, 247, 240, 10, 73, 6, - 38, 85, 250, 240, 22, 82, 219, 5, 86, 2, 129, 232, 21, 2, 76, 68, 8, 42, - 65, 206, 183, 7, 73, 131, 193, 14, 79, 4, 218, 140, 23, 78, 3, 87, 10, - 250, 233, 21, 82, 128, 2, 2, 77, 80, 218, 98, 86, 134, 5, 76, 235, 56, - 87, 34, 38, 69, 38, 73, 98, 79, 195, 1, 82, 4, 186, 137, 21, 65, 183, - 201, 1, 69, 8, 38, 83, 198, 244, 13, 86, 175, 2, 80, 4, 132, 170, 19, 5, - 84, 73, 78, 71, 85, 251, 224, 3, 72, 16, 94, 84, 76, 3, 85, 66, 76, 222, - 246, 12, 87, 136, 194, 9, 2, 32, 78, 222, 23, 79, 223, 56, 71, 7, 25, 4, - 84, 69, 68, 32, 4, 184, 180, 7, 3, 67, 76, 73, 235, 145, 15, 84, 2, 207, - 195, 3, 69, 6, 230, 208, 21, 65, 202, 167, 1, 85, 219, 16, 89, 20, 106, - 65, 38, 78, 32, 3, 86, 69, 78, 152, 252, 8, 6, 77, 66, 82, 79, 73, 68, - 206, 224, 13, 73, 243, 19, 89, 6, 234, 221, 16, 82, 131, 170, 6, 84, 4, - 178, 25, 67, 171, 176, 22, 84, 5, 175, 182, 22, 73, 28, 74, 65, 50, 73, - 62, 76, 38, 82, 170, 20, 69, 218, 160, 22, 79, 223, 23, 85, 6, 246, 242, - 13, 84, 254, 252, 8, 67, 131, 22, 78, 8, 142, 232, 12, 69, 210, 243, 9, - 71, 230, 19, 82, 199, 21, 83, 4, 226, 190, 21, 85, 251, 198, 1, 89, 4, - 168, 215, 21, 2, 65, 71, 187, 173, 1, 79, 14, 58, 79, 52, 2, 82, 65, 150, - 154, 19, 72, 147, 163, 2, 65, 7, 174, 190, 22, 76, 241, 34, 5, 32, 83, - 76, 79, 87, 4, 186, 180, 22, 73, 135, 18, 83, 22, 58, 65, 142, 1, 69, 60, - 5, 73, 68, 73, 78, 71, 19, 79, 8, 38, 76, 250, 188, 22, 78, 199, 13, 73, - 4, 34, 70, 137, 236, 21, 2, 66, 69, 2, 41, 8, 32, 84, 82, 69, 69, 32, 84, - 82, 2, 187, 161, 19, 85, 6, 26, 65, 143, 130, 23, 77, 4, 234, 229, 22, - 82, 175, 28, 68, 2, 195, 19, 32, 6, 26, 82, 183, 254, 22, 79, 4, 246, - 234, 22, 83, 215, 22, 78, 6, 26, 78, 191, 234, 22, 67, 4, 26, 83, 231, - 255, 22, 67, 2, 131, 242, 21, 69, 4, 138, 234, 22, 68, 215, 22, 82, 2, - 205, 172, 5, 2, 78, 73, 22, 46, 65, 34, 69, 78, 73, 41, 3, 79, 78, 71, 4, - 158, 233, 22, 77, 191, 19, 67, 8, 38, 65, 210, 193, 22, 71, 199, 58, 69, - 4, 218, 235, 13, 84, 211, 147, 9, 70, 6, 178, 232, 22, 70, 2, 78, 215, - 22, 68, 5, 161, 196, 11, 3, 32, 83, 84, 22, 42, 69, 34, 73, 46, 79, 235, - 173, 22, 65, 4, 166, 174, 22, 76, 195, 51, 65, 4, 188, 235, 11, 2, 78, - 73, 151, 179, 9, 76, 12, 34, 82, 34, 85, 167, 173, 22, 79, 4, 234, 219, - 21, 84, 183, 80, 78, 6, 26, 78, 219, 251, 22, 84, 4, 146, 208, 21, 84, - 215, 172, 1, 68, 6, 26, 79, 255, 223, 22, 69, 4, 210, 229, 22, 83, 215, - 22, 84, 10, 40, 2, 78, 69, 22, 80, 171, 181, 22, 76, 5, 235, 150, 6, 83, - 4, 198, 171, 10, 80, 195, 189, 2, 69, 10, 54, 82, 202, 224, 21, 76, 166, - 1, 79, 175, 152, 1, 73, 4, 156, 199, 12, 2, 73, 86, 225, 254, 6, 2, 79, - 70, 18, 62, 65, 42, 73, 242, 166, 10, 79, 130, 131, 12, 85, 195, 9, 69, - 6, 150, 170, 22, 73, 226, 79, 80, 3, 84, 6, 240, 230, 12, 3, 71, 72, 84, - 242, 212, 9, 86, 155, 39, 67, 74, 170, 1, 65, 86, 67, 54, 69, 62, 72, - 178, 1, 73, 46, 76, 62, 80, 106, 84, 186, 227, 17, 87, 166, 155, 1, 78, - 234, 63, 79, 150, 173, 1, 77, 254, 102, 81, 254, 32, 75, 247, 47, 85, 6, - 228, 193, 3, 9, 67, 82, 73, 70, 73, 67, 73, 65, 76, 214, 153, 19, 76, - 175, 28, 89, 4, 248, 238, 10, 2, 82, 73, 161, 215, 5, 2, 72, 79, 8, 158, - 186, 21, 67, 142, 51, 65, 146, 8, 76, 167, 129, 1, 69, 10, 18, 69, 39, - 79, 4, 218, 236, 21, 76, 171, 137, 1, 69, 6, 40, 4, 82, 84, 32, 84, 151, - 217, 22, 79, 4, 44, 5, 65, 73, 76, 69, 68, 175, 249, 15, 72, 2, 145, 243, - 20, 2, 32, 66, 4, 228, 229, 17, 2, 67, 75, 247, 139, 5, 76, 6, 26, 65, - 179, 183, 22, 73, 4, 214, 221, 22, 86, 199, 21, 83, 10, 50, 69, 34, 73, - 242, 254, 18, 82, 223, 164, 3, 79, 4, 250, 186, 22, 65, 183, 22, 69, 2, - 255, 214, 22, 82, 12, 34, 69, 34, 79, 235, 228, 21, 65, 4, 166, 226, 22, - 65, 219, 16, 80, 6, 26, 80, 243, 219, 22, 78, 5, 191, 161, 22, 80, 30, - 82, 65, 98, 73, 34, 79, 38, 82, 52, 2, 85, 82, 32, 2, 87, 79, 135, 160, - 22, 69, 6, 38, 78, 142, 205, 21, 66, 247, 26, 76, 2, 33, 6, 78, 69, 68, - 32, 76, 69, 2, 179, 221, 13, 65, 4, 142, 179, 22, 71, 155, 39, 76, 4, - 198, 229, 18, 78, 135, 137, 2, 79, 6, 250, 228, 16, 73, 206, 219, 4, 65, - 159, 153, 1, 69, 4, 130, 166, 21, 66, 219, 37, 84, 5, 239, 176, 19, 32, - 4, 162, 212, 12, 65, 217, 148, 5, 3, 73, 76, 76, 26, 58, 65, 110, 69, 42, - 72, 32, 2, 73, 78, 30, 79, 39, 82, 6, 32, 2, 76, 75, 215, 176, 22, 84, 5, - 11, 32, 2, 11, 69, 2, 17, 2, 78, 67, 2, 153, 226, 17, 2, 76, 79, 4, 136, - 158, 22, 2, 65, 80, 195, 51, 83, 4, 214, 166, 21, 73, 147, 51, 69, 4, - 174, 237, 22, 68, 3, 69, 4, 146, 163, 21, 77, 235, 198, 1, 82, 4, 246, - 155, 22, 79, 239, 80, 65, 2, 201, 206, 20, 2, 69, 76, 184, 1, 92, 2, 76, - 69, 148, 2, 5, 83, 73, 71, 78, 32, 150, 190, 17, 65, 250, 8, 86, 147, - 177, 3, 68, 110, 44, 5, 84, 84, 69, 82, 32, 187, 169, 22, 78, 108, 234, - 196, 17, 78, 150, 204, 1, 65, 38, 68, 46, 76, 38, 82, 34, 84, 46, 86, - 186, 5, 85, 202, 141, 1, 79, 134, 60, 73, 206, 193, 1, 83, 82, 66, 2, 67, - 2, 71, 2, 74, 2, 75, 2, 80, 162, 7, 69, 234, 61, 70, 2, 72, 2, 77, 3, 89, - 22, 94, 67, 138, 1, 83, 246, 211, 18, 78, 242, 60, 65, 174, 158, 1, 74, - 150, 3, 85, 167, 242, 1, 86, 4, 100, 19, 79, 77, 66, 73, 78, 73, 78, 71, - 32, 65, 78, 85, 83, 86, 65, 82, 65, 32, 65, 195, 211, 18, 65, 2, 225, - 230, 19, 3, 66, 79, 86, 4, 224, 190, 12, 6, 80, 65, 67, 73, 78, 71, 163, - 134, 5, 73, 162, 2, 62, 32, 173, 11, 10, 45, 72, 73, 82, 65, 71, 65, 78, - 65, 32, 154, 2, 140, 1, 7, 76, 69, 84, 84, 69, 82, 32, 242, 9, 86, 148, - 237, 18, 10, 68, 73, 71, 82, 65, 80, 72, 32, 75, 79, 246, 203, 1, 73, - 135, 145, 1, 77, 146, 2, 186, 1, 65, 178, 1, 66, 106, 77, 186, 2, 78, 54, - 83, 226, 1, 68, 2, 71, 2, 72, 2, 75, 2, 80, 2, 82, 2, 84, 2, 86, 2, 90, - 126, 87, 46, 89, 246, 219, 22, 69, 2, 73, 2, 79, 3, 85, 19, 60, 4, 73, - 78, 85, 32, 45, 7, 82, 67, 72, 65, 73, 67, 32, 8, 130, 7, 84, 234, 197, - 22, 67, 215, 22, 80, 8, 38, 89, 134, 190, 22, 87, 235, 36, 69, 4, 234, - 226, 22, 69, 3, 73, 20, 50, 73, 158, 226, 22, 65, 2, 69, 2, 79, 3, 85, - 13, 253, 4, 9, 68, 65, 75, 85, 79, 78, 32, 78, 71, 36, 50, 73, 182, 225, - 22, 65, 2, 69, 2, 79, 3, 85, 29, 29, 5, 78, 78, 65, 78, 32, 26, 96, 15, - 78, 65, 83, 65, 76, 73, 90, 69, 68, 32, 84, 79, 78, 69, 45, 69, 5, 84, - 79, 78, 69, 45, 14, 174, 224, 22, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 55, - 3, 56, 12, 234, 223, 22, 50, 2, 51, 2, 52, 2, 53, 2, 55, 3, 56, 13, 174, - 223, 22, 65, 2, 69, 2, 73, 2, 79, 3, 85, 76, 76, 5, 77, 65, 76, 76, 32, - 174, 222, 22, 65, 2, 69, 2, 73, 2, 79, 3, 85, 66, 142, 1, 72, 2, 82, 54, - 75, 46, 84, 30, 87, 46, 89, 206, 136, 19, 78, 242, 146, 3, 83, 210, 27, - 77, 234, 36, 65, 2, 69, 2, 73, 2, 79, 3, 85, 10, 154, 221, 22, 65, 2, 69, - 2, 73, 2, 79, 3, 85, 8, 230, 220, 22, 65, 2, 69, 2, 79, 3, 85, 4, 186, - 220, 22, 79, 3, 85, 8, 158, 220, 22, 65, 2, 69, 2, 73, 3, 79, 6, 242, - 219, 22, 65, 2, 79, 3, 85, 2, 241, 184, 20, 5, 79, 73, 67, 69, 68, 8, 52, - 5, 68, 79, 85, 66, 76, 22, 80, 38, 83, 35, 86, 2, 139, 250, 7, 69, 2, 89, - 6, 82, 79, 76, 79, 78, 71, 2, 29, 5, 69, 77, 73, 45, 86, 2, 21, 3, 79, - 73, 67, 2, 33, 6, 69, 68, 32, 83, 79, 85, 2, 191, 141, 22, 78, 174, 1, - 216, 1, 7, 76, 69, 84, 84, 69, 82, 32, 128, 2, 12, 80, 85, 78, 67, 84, - 85, 65, 84, 73, 79, 78, 32, 148, 3, 5, 83, 73, 71, 78, 32, 88, 11, 86, - 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 170, 163, 12, 68, 195, 209, 6, - 67, 94, 226, 1, 65, 166, 160, 4, 74, 230, 219, 14, 68, 114, 84, 230, 5, - 85, 22, 86, 186, 201, 1, 73, 162, 193, 1, 78, 46, 83, 82, 66, 2, 67, 2, - 71, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 87, 2, 89, 186, 2, - 69, 3, 79, 7, 130, 214, 22, 65, 3, 73, 22, 122, 67, 90, 68, 58, 70, 54, - 83, 20, 12, 65, 76, 84, 69, 82, 78, 65, 84, 69, 32, 83, 69, 233, 193, 21, - 4, 84, 82, 73, 80, 4, 56, 8, 76, 79, 83, 73, 78, 71, 32, 83, 195, 130, - 21, 73, 2, 225, 202, 21, 2, 80, 73, 4, 11, 79, 4, 216, 194, 21, 2, 85, - 66, 175, 145, 1, 84, 4, 196, 129, 21, 5, 73, 76, 76, 69, 68, 139, 57, 76, - 6, 18, 69, 23, 80, 2, 195, 237, 10, 67, 4, 236, 144, 4, 2, 65, 67, 199, - 184, 17, 73, 12, 242, 219, 7, 75, 162, 226, 10, 67, 98, 78, 162, 59, 82, - 154, 162, 1, 86, 179, 241, 1, 65, 20, 66, 65, 214, 158, 4, 86, 190, 223, - 14, 69, 2, 85, 207, 201, 1, 73, 6, 148, 222, 16, 8, 76, 84, 69, 82, 78, - 65, 84, 69, 162, 243, 5, 65, 3, 73, 96, 148, 1, 7, 76, 69, 84, 84, 69, - 82, 32, 200, 1, 5, 83, 73, 71, 78, 32, 44, 5, 84, 79, 78, 69, 32, 92, 6, - 86, 79, 87, 69, 76, 32, 231, 219, 20, 68, 56, 138, 189, 18, 79, 134, 7, - 72, 154, 145, 2, 78, 238, 178, 1, 75, 2, 80, 2, 83, 2, 84, 138, 69, 66, - 2, 67, 2, 68, 2, 71, 2, 76, 2, 77, 2, 82, 2, 86, 2, 87, 2, 89, 2, 90, - 186, 2, 65, 3, 73, 4, 182, 236, 4, 67, 249, 222, 17, 2, 83, 72, 6, 36, 5, - 67, 65, 76, 89, 65, 23, 80, 5, 17, 2, 32, 80, 2, 173, 223, 17, 3, 76, 79, - 80, 10, 226, 140, 22, 69, 2, 85, 163, 64, 79, 36, 24, 2, 76, 86, 23, 89, - 2, 159, 211, 20, 73, 35, 68, 5, 66, 79, 65, 82, 68, 36, 4, 67, 65, 80, - 32, 187, 244, 2, 72, 5, 245, 134, 19, 4, 32, 65, 78, 68, 26, 254, 136, - 17, 78, 238, 174, 3, 65, 182, 34, 68, 187, 29, 84, 188, 13, 202, 1, 65, - 212, 9, 18, 73, 84, 65, 78, 32, 83, 77, 65, 76, 76, 32, 83, 67, 82, 73, - 80, 84, 32, 204, 3, 4, 77, 69, 82, 32, 204, 25, 5, 79, 74, 75, 73, 32, - 141, 6, 8, 85, 68, 65, 87, 65, 68, 73, 32, 138, 1, 56, 8, 82, 79, 83, 72, - 84, 72, 73, 32, 243, 163, 22, 78, 136, 1, 220, 1, 4, 68, 73, 71, 73, 20, - 7, 76, 69, 84, 84, 69, 82, 32, 144, 2, 7, 78, 85, 77, 66, 69, 82, 32, 36, - 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 136, 2, 5, 83, 73, - 71, 78, 32, 198, 1, 86, 183, 194, 8, 70, 8, 223, 134, 16, 84, 74, 182, 1, - 75, 42, 84, 234, 133, 7, 78, 186, 229, 11, 68, 238, 145, 3, 83, 82, 66, - 2, 67, 2, 71, 2, 80, 2, 86, 138, 69, 72, 2, 74, 2, 76, 2, 77, 2, 82, 2, - 89, 2, 90, 187, 2, 65, 6, 138, 195, 22, 72, 2, 75, 187, 2, 65, 12, 142, - 236, 18, 84, 214, 214, 3, 72, 187, 2, 65, 8, 162, 203, 14, 84, 227, 165, - 2, 79, 18, 70, 67, 74, 68, 66, 76, 36, 5, 77, 65, 78, 71, 65, 159, 240, - 20, 83, 4, 26, 82, 247, 241, 20, 73, 2, 145, 162, 21, 6, 69, 83, 67, 69, - 78, 84, 6, 26, 79, 251, 230, 18, 65, 4, 194, 230, 18, 85, 219, 220, 3, - 84, 4, 226, 220, 6, 79, 227, 190, 7, 73, 2, 215, 135, 21, 76, 12, 72, 2, - 66, 65, 22, 67, 20, 2, 68, 79, 166, 139, 20, 86, 179, 241, 1, 65, 2, 239, - 196, 21, 82, 2, 203, 147, 6, 65, 4, 56, 8, 85, 66, 76, 69, 32, 82, 73, - 78, 207, 147, 20, 84, 2, 203, 147, 20, 71, 14, 44, 5, 79, 87, 69, 76, 32, - 247, 135, 20, 73, 12, 44, 5, 83, 73, 71, 78, 32, 163, 254, 21, 76, 10, - 182, 141, 4, 86, 230, 178, 18, 69, 2, 73, 2, 79, 3, 85, 176, 7, 72, 12, - 67, 72, 65, 82, 65, 67, 84, 69, 82, 45, 49, 56, 179, 200, 7, 70, 174, 7, - 22, 66, 147, 1, 67, 128, 4, 170, 247, 7, 48, 2, 49, 2, 50, 2, 51, 2, 52, - 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, 68, 2, 69, 3, - 70, 174, 3, 142, 1, 68, 142, 245, 7, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, - 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 163, 198, 13, 70, - 12, 206, 188, 22, 48, 2, 49, 2, 50, 2, 51, 2, 52, 3, 53, 246, 2, 202, 1, - 67, 240, 2, 18, 73, 78, 68, 69, 80, 69, 78, 68, 69, 78, 84, 32, 86, 79, - 87, 69, 76, 32, 220, 2, 7, 76, 69, 84, 84, 69, 82, 32, 254, 2, 83, 208, - 12, 6, 86, 79, 87, 69, 76, 32, 143, 180, 20, 68, 70, 176, 1, 20, 79, 78, - 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 67, 79, 69, 78, 71, 32, - 173, 172, 17, 17, 85, 82, 82, 69, 78, 67, 89, 32, 83, 89, 77, 66, 79, 76, - 32, 82, 73, 68, 138, 1, 78, 154, 4, 67, 2, 75, 90, 80, 74, 84, 54, 68, 2, - 76, 138, 234, 21, 83, 158, 41, 77, 2, 82, 2, 86, 2, 89, 190, 28, 66, 3, - 72, 8, 142, 153, 22, 71, 2, 89, 246, 30, 65, 3, 79, 42, 82, 81, 196, 1, - 11, 83, 73, 71, 78, 32, 67, 79, 69, 78, 71, 32, 50, 76, 3, 82, 26, 82, - 65, 44, 6, 79, 79, 32, 84, 89, 80, 34, 85, 134, 172, 20, 73, 223, 137, 2, - 69, 8, 170, 182, 22, 65, 2, 73, 2, 81, 3, 85, 4, 11, 69, 4, 207, 142, 10, - 32, 9, 198, 185, 7, 85, 155, 252, 14, 75, 8, 18, 81, 31, 82, 4, 166, 181, - 22, 69, 3, 85, 4, 215, 149, 18, 89, 70, 138, 1, 67, 2, 75, 42, 78, 50, - 80, 30, 83, 46, 84, 54, 68, 2, 76, 166, 147, 22, 77, 2, 82, 2, 86, 2, 89, - 190, 28, 66, 2, 72, 3, 81, 8, 210, 1, 72, 154, 178, 22, 65, 3, 79, 8, - 206, 148, 22, 71, 2, 78, 2, 89, 247, 30, 79, 6, 122, 72, 155, 178, 22, - 79, 6, 130, 148, 22, 83, 190, 28, 72, 187, 2, 65, 12, 50, 72, 0, 2, 84, - 72, 154, 178, 22, 65, 3, 79, 4, 150, 178, 22, 65, 3, 79, 130, 1, 60, 4, - 73, 71, 78, 32, 221, 6, 6, 89, 77, 66, 79, 76, 32, 46, 202, 2, 65, 104, - 10, 83, 65, 77, 89, 79, 75, 32, 83, 65, 78, 22, 66, 118, 67, 86, 75, 74, - 82, 54, 84, 144, 223, 4, 3, 76, 69, 75, 168, 11, 6, 80, 72, 78, 65, 69, - 75, 248, 226, 10, 10, 89, 85, 85, 75, 65, 76, 69, 65, 80, 73, 200, 238, - 1, 3, 78, 73, 75, 180, 165, 3, 9, 77, 85, 85, 83, 73, 75, 65, 84, 79, - 133, 15, 4, 86, 73, 82, 73, 6, 100, 9, 86, 65, 75, 82, 65, 72, 65, 83, - 65, 176, 128, 18, 4, 84, 84, 72, 65, 209, 136, 4, 2, 72, 83, 2, 167, 171, - 22, 78, 8, 38, 65, 137, 164, 21, 3, 69, 89, 89, 6, 174, 6, 84, 216, 1, 2, - 78, 84, 193, 219, 20, 6, 82, 73, 89, 79, 79, 83, 4, 152, 149, 7, 12, 65, - 77, 78, 85, 67, 32, 80, 73, 73, 32, 75, 85, 211, 212, 12, 79, 6, 140, - 214, 11, 2, 65, 75, 154, 140, 9, 72, 177, 80, 4, 79, 79, 77, 85, 4, 210, - 213, 11, 79, 249, 224, 5, 4, 69, 65, 72, 77, 4, 192, 151, 21, 8, 79, 65, - 78, 68, 65, 75, 72, 73, 253, 2, 4, 82, 73, 73, 83, 84, 128, 1, 3, 68, 65, - 80, 92, 10, 76, 69, 75, 32, 65, 84, 84, 65, 75, 32, 182, 1, 80, 72, 5, - 84, 85, 84, 69, 89, 78, 66, 47, 77, 24, 22, 45, 223, 3, 32, 20, 30, 80, - 238, 2, 66, 47, 77, 8, 138, 3, 73, 37, 3, 82, 65, 77, 20, 50, 80, 98, 66, - 130, 143, 11, 77, 255, 200, 10, 83, 12, 36, 3, 82, 65, 77, 203, 148, 22, - 73, 11, 11, 45, 8, 42, 66, 130, 143, 11, 77, 239, 213, 8, 80, 4, 250, - 215, 21, 85, 151, 60, 69, 26, 44, 2, 65, 84, 44, 3, 82, 65, 77, 91, 73, - 2, 21, 3, 72, 65, 77, 2, 223, 178, 16, 65, 20, 18, 45, 119, 32, 16, 34, - 66, 32, 2, 80, 73, 15, 77, 8, 30, 69, 37, 3, 85, 79, 78, 4, 35, 73, 4, - 21, 3, 85, 79, 89, 4, 11, 32, 4, 34, 82, 169, 240, 21, 2, 75, 79, 2, 195, - 253, 20, 79, 42, 76, 10, 73, 78, 72, 69, 82, 69, 78, 84, 32, 65, 29, 5, - 83, 73, 71, 78, 32, 4, 218, 164, 22, 65, 3, 81, 38, 102, 65, 54, 73, 30, - 79, 38, 89, 184, 253, 2, 5, 67, 79, 69, 78, 71, 250, 165, 7, 85, 183, - 255, 11, 69, 10, 174, 174, 3, 65, 170, 245, 18, 69, 2, 73, 3, 85, 7, 162, - 163, 22, 69, 3, 73, 6, 134, 163, 22, 69, 2, 77, 3, 79, 7, 226, 162, 22, - 65, 3, 89, 130, 1, 146, 1, 68, 88, 7, 76, 69, 84, 84, 69, 82, 32, 170, 2, - 83, 160, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 230, 225, 15, - 87, 211, 80, 65, 6, 48, 6, 79, 85, 66, 76, 69, 32, 219, 196, 18, 65, 4, - 170, 160, 10, 83, 163, 164, 8, 68, 90, 234, 1, 83, 254, 4, 66, 42, 71, - 186, 134, 6, 68, 214, 134, 12, 74, 158, 50, 65, 150, 1, 84, 218, 207, 1, - 76, 250, 192, 1, 78, 126, 67, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 81, 2, - 82, 2, 86, 2, 89, 186, 2, 69, 2, 73, 2, 79, 3, 85, 4, 26, 72, 211, 158, - 22, 65, 2, 189, 222, 21, 3, 79, 82, 84, 12, 40, 4, 73, 71, 78, 32, 195, - 157, 10, 69, 10, 54, 83, 238, 137, 18, 78, 206, 61, 86, 159, 145, 3, 65, - 4, 26, 72, 187, 162, 17, 85, 2, 11, 65, 2, 159, 248, 21, 68, 18, 170, - 234, 3, 86, 154, 223, 14, 65, 242, 201, 1, 73, 222, 137, 2, 69, 2, 79, 3, - 85, 138, 1, 100, 7, 76, 69, 84, 84, 69, 82, 32, 176, 2, 5, 83, 73, 71, - 78, 32, 202, 177, 16, 86, 187, 246, 3, 68, 94, 222, 1, 66, 42, 71, 186, - 134, 6, 68, 174, 133, 12, 74, 198, 51, 65, 118, 82, 34, 84, 230, 5, 85, - 206, 201, 1, 73, 162, 193, 1, 78, 126, 67, 2, 75, 2, 80, 2, 83, 138, 69, - 72, 2, 76, 2, 77, 2, 86, 2, 89, 186, 2, 69, 3, 79, 6, 182, 151, 22, 66, - 2, 72, 187, 2, 65, 6, 142, 151, 22, 71, 2, 72, 187, 2, 65, 6, 190, 133, - 18, 78, 206, 61, 86, 159, 145, 3, 65, 136, 1, 140, 1, 8, 82, 65, 84, 32, - 82, 65, 73, 32, 216, 3, 2, 83, 83, 208, 223, 20, 4, 87, 73, 70, 82, 182, - 45, 80, 240, 93, 2, 77, 79, 191, 18, 84, 116, 140, 1, 7, 76, 69, 84, 84, - 69, 82, 32, 172, 1, 5, 83, 73, 71, 78, 32, 92, 11, 86, 79, 87, 69, 76, - 32, 83, 73, 71, 78, 32, 243, 229, 11, 68, 64, 206, 188, 18, 68, 114, 84, - 226, 222, 1, 78, 238, 178, 1, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 2, - 83, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 86, 2, 89, 187, 2, 65, 12, 208, - 202, 9, 3, 84, 79, 78, 0, 2, 89, 85, 242, 251, 1, 83, 230, 137, 10, 65, - 239, 1, 86, 16, 246, 192, 18, 65, 174, 147, 3, 85, 162, 64, 69, 2, 73, 3, - 79, 13, 40, 4, 73, 78, 71, 32, 163, 210, 21, 32, 8, 96, 4, 70, 65, 67, - 69, 181, 135, 14, 14, 67, 65, 84, 32, 70, 65, 67, 69, 32, 87, 73, 84, 72, - 32, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 162, 134, 14, 83, 215, 144, 5, - 67, 4, 168, 146, 18, 3, 69, 69, 76, 215, 227, 3, 79, 4, 40, 4, 82, 69, - 65, 78, 187, 239, 21, 65, 2, 33, 6, 32, 83, 84, 65, 78, 68, 2, 129, 228, - 18, 2, 65, 82, 2, 11, 79, 2, 191, 161, 10, 78, 174, 43, 154, 1, 65, 150, - 232, 1, 69, 182, 62, 73, 238, 83, 79, 222, 28, 85, 94, 89, 226, 224, 7, - 82, 244, 179, 9, 5, 32, 66, 32, 66, 65, 166, 160, 1, 76, 239, 66, 70, - 252, 22, 182, 1, 66, 44, 6, 67, 82, 79, 83, 83, 69, 46, 68, 56, 2, 79, - 32, 222, 11, 82, 236, 21, 4, 83, 84, 32, 81, 76, 4, 84, 73, 78, 32, 237, - 129, 20, 8, 78, 71, 85, 65, 71, 69, 32, 84, 4, 176, 182, 14, 2, 32, 67, - 175, 206, 6, 69, 2, 153, 237, 16, 6, 32, 83, 84, 73, 67, 75, 4, 220, 242, - 12, 5, 89, 32, 66, 69, 69, 243, 220, 8, 68, 174, 1, 200, 2, 3, 72, 79, - 32, 28, 7, 76, 69, 84, 84, 69, 82, 32, 214, 5, 83, 148, 1, 9, 84, 79, 78, - 69, 32, 77, 65, 73, 32, 84, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, - 32, 188, 164, 4, 2, 75, 79, 224, 247, 12, 2, 89, 65, 230, 194, 2, 69, - 190, 50, 68, 236, 135, 1, 7, 67, 65, 78, 67, 69, 76, 76, 221, 68, 6, 78, - 73, 71, 71, 65, 72, 4, 190, 235, 21, 77, 3, 78, 94, 176, 1, 3, 70, 79, - 32, 78, 75, 96, 2, 76, 79, 50, 80, 154, 1, 83, 86, 84, 30, 72, 234, 149, - 16, 78, 166, 208, 5, 66, 2, 67, 2, 68, 2, 77, 2, 82, 2, 87, 2, 89, 247, - 30, 79, 8, 42, 70, 254, 162, 15, 83, 195, 170, 5, 84, 4, 214, 184, 21, - 79, 155, 62, 65, 10, 26, 72, 255, 135, 22, 79, 8, 32, 3, 77, 85, 32, 231, - 2, 79, 4, 146, 175, 21, 78, 211, 57, 71, 7, 17, 2, 32, 76, 4, 170, 182, - 21, 73, 67, 79, 30, 52, 4, 65, 76, 73, 32, 210, 1, 72, 131, 133, 22, 79, - 24, 154, 194, 6, 68, 34, 84, 206, 6, 78, 138, 195, 13, 66, 2, 67, 2, 71, - 2, 74, 171, 216, 1, 76, 8, 52, 9, 65, 78, 83, 75, 82, 73, 84, 32, 83, 71, - 79, 4, 254, 130, 22, 72, 3, 83, 6, 26, 72, 131, 133, 22, 79, 4, 11, 79, - 4, 11, 32, 4, 170, 159, 15, 83, 195, 170, 5, 84, 6, 112, 14, 69, 77, 73, - 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 169, 173, 18, 8, 73, 71, 78, - 32, 80, 65, 76, 73, 4, 138, 171, 21, 78, 211, 57, 76, 8, 50, 84, 220, - 145, 17, 2, 67, 65, 139, 238, 4, 69, 4, 134, 228, 21, 72, 247, 30, 73, - 32, 106, 65, 44, 5, 77, 65, 73, 32, 75, 146, 226, 17, 89, 142, 76, 85, - 206, 201, 1, 69, 2, 73, 223, 137, 2, 79, 11, 238, 129, 22, 65, 2, 73, 2, - 77, 3, 89, 4, 226, 177, 21, 65, 3, 79, 166, 1, 32, 2, 71, 69, 131, 250, - 20, 73, 164, 1, 26, 32, 199, 239, 13, 82, 160, 1, 254, 1, 66, 44, 4, 71, - 82, 69, 69, 22, 79, 250, 1, 84, 182, 231, 11, 68, 36, 2, 85, 80, 176, - 192, 3, 12, 76, 69, 70, 84, 32, 84, 82, 73, 65, 78, 71, 76, 164, 193, 4, - 5, 80, 85, 82, 80, 76, 12, 3, 82, 69, 68, 0, 6, 89, 69, 76, 76, 79, 87, - 243, 64, 67, 10, 40, 3, 82, 79, 87, 201, 1, 2, 76, 85, 4, 195, 235, 19, - 78, 10, 48, 3, 78, 69, 32, 129, 1, 4, 82, 65, 78, 71, 4, 160, 155, 8, 5, - 68, 79, 84, 32, 79, 181, 233, 2, 18, 82, 73, 78, 71, 32, 79, 86, 69, 82, - 32, 84, 87, 79, 32, 82, 73, 78, 71, 6, 11, 69, 6, 11, 32, 6, 210, 170, - 20, 67, 154, 21, 68, 139, 28, 83, 116, 156, 1, 3, 87, 79, 32, 108, 10, - 89, 80, 69, 32, 80, 73, 69, 67, 69, 32, 157, 186, 18, 17, 82, 73, 80, 76, - 69, 32, 86, 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, 4, 150, 225, 17, 68, - 193, 87, 19, 82, 73, 78, 71, 83, 32, 79, 86, 69, 82, 32, 79, 78, 69, 32, - 82, 73, 78, 71, 110, 182, 1, 67, 136, 2, 9, 68, 73, 65, 71, 79, 78, 65, - 76, 32, 218, 1, 76, 186, 2, 82, 158, 1, 83, 204, 3, 6, 85, 80, 80, 69, - 82, 32, 145, 2, 9, 86, 69, 82, 84, 69, 88, 32, 79, 70, 14, 80, 9, 69, 78, - 84, 82, 69, 32, 79, 70, 32, 73, 7, 82, 79, 83, 83, 66, 65, 82, 8, 252, 8, - 6, 90, 32, 87, 73, 84, 72, 142, 239, 21, 75, 2, 88, 3, 89, 7, 33, 6, 32, - 87, 73, 84, 72, 32, 4, 40, 3, 76, 79, 87, 1, 3, 85, 80, 80, 2, 181, 197, - 10, 2, 69, 82, 12, 48, 6, 85, 80, 80, 69, 82, 32, 227, 222, 9, 76, 8, 56, - 4, 76, 69, 70, 84, 157, 223, 9, 4, 82, 73, 71, 72, 5, 11, 32, 2, 21, 3, - 65, 78, 68, 2, 17, 2, 32, 76, 2, 17, 2, 79, 87, 2, 213, 194, 21, 2, 69, - 82, 26, 48, 5, 79, 87, 69, 82, 32, 129, 3, 2, 69, 70, 24, 84, 5, 76, 69, - 70, 84, 32, 56, 6, 82, 73, 71, 72, 84, 32, 158, 6, 72, 179, 1, 84, 8, 22, - 65, 207, 7, 67, 4, 194, 1, 78, 159, 202, 20, 82, 10, 22, 65, 151, 7, 67, - 6, 192, 1, 13, 78, 68, 32, 85, 80, 80, 69, 82, 32, 82, 73, 71, 72, 193, - 189, 19, 2, 82, 67, 4, 44, 4, 65, 73, 83, 69, 77, 3, 73, 71, 72, 2, 53, - 11, 68, 32, 85, 80, 80, 69, 82, 32, 76, 69, 70, 2, 187, 245, 18, 84, 2, - 141, 243, 20, 3, 84, 32, 65, 34, 48, 5, 72, 79, 82, 84, 32, 77, 3, 84, - 69, 77, 4, 40, 3, 76, 79, 87, 1, 3, 85, 80, 80, 2, 217, 4, 4, 69, 82, 32, - 84, 31, 44, 6, 32, 87, 73, 84, 72, 32, 171, 1, 45, 8, 44, 5, 76, 69, 70, - 84, 32, 30, 82, 59, 67, 4, 82, 67, 167, 214, 10, 74, 2, 21, 3, 73, 71, - 72, 2, 11, 84, 2, 17, 2, 32, 67, 2, 177, 205, 20, 4, 82, 79, 83, 83, 20, - 48, 2, 49, 50, 22, 50, 26, 52, 247, 181, 11, 51, 5, 207, 211, 14, 51, 9, - 11, 51, 7, 11, 52, 5, 243, 237, 21, 53, 18, 62, 72, 96, 3, 76, 69, 70, 0, - 4, 82, 73, 71, 72, 83, 84, 4, 65, 14, 65, 76, 70, 32, 86, 69, 82, 84, 69, - 88, 32, 79, 70, 32, 4, 218, 236, 21, 77, 3, 87, 6, 17, 2, 84, 32, 6, 26, - 67, 131, 240, 18, 65, 4, 186, 92, 82, 211, 147, 17, 79, 2, 201, 243, 8, - 3, 69, 82, 77, 2, 211, 219, 14, 32, 6, 53, 11, 85, 65, 82, 84, 69, 82, - 32, 77, 79, 79, 78, 7, 151, 234, 6, 32, 150, 20, 150, 1, 67, 148, 46, 18, - 69, 80, 73, 71, 82, 65, 80, 72, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, - 252, 1, 7, 76, 69, 84, 84, 69, 82, 32, 183, 13, 83, 200, 7, 56, 8, 65, - 80, 73, 84, 65, 76, 32, 76, 139, 168, 20, 82, 198, 7, 76, 6, 69, 84, 84, - 69, 82, 32, 221, 44, 8, 73, 71, 65, 84, 85, 82, 69, 32, 194, 7, 154, 2, - 65, 158, 3, 66, 154, 1, 67, 254, 1, 68, 250, 1, 69, 174, 2, 70, 82, 71, - 194, 1, 72, 146, 1, 73, 154, 2, 74, 118, 75, 126, 76, 234, 2, 77, 114, - 78, 134, 2, 79, 198, 2, 80, 102, 81, 62, 82, 190, 2, 83, 130, 3, 84, 142, - 3, 85, 234, 1, 86, 146, 1, 87, 118, 88, 50, 89, 167, 1, 90, 93, 172, 1, - 6, 32, 87, 73, 84, 72, 32, 166, 1, 69, 230, 65, 78, 216, 146, 14, 6, 70, - 82, 73, 67, 65, 78, 222, 182, 3, 76, 130, 182, 2, 86, 182, 162, 1, 65, 2, - 79, 2, 85, 3, 89, 66, 230, 64, 66, 34, 68, 108, 3, 82, 73, 78, 242, 33, - 77, 250, 21, 67, 162, 49, 72, 158, 1, 79, 198, 10, 71, 186, 2, 65, 202, - 168, 3, 73, 186, 159, 13, 84, 227, 179, 3, 83, 7, 33, 6, 32, 87, 73, 84, - 72, 32, 4, 202, 183, 1, 65, 187, 194, 3, 77, 21, 60, 6, 32, 87, 73, 84, - 72, 32, 174, 68, 82, 207, 249, 20, 69, 14, 138, 67, 84, 142, 60, 70, 218, - 56, 76, 226, 143, 16, 68, 162, 199, 2, 72, 219, 163, 1, 83, 33, 108, 6, - 32, 87, 73, 84, 72, 32, 188, 70, 7, 76, 79, 83, 69, 68, 32, 73, 54, 85, - 174, 202, 20, 79, 139, 60, 72, 20, 94, 67, 194, 180, 1, 65, 230, 227, 3, - 80, 166, 244, 14, 72, 158, 50, 66, 238, 32, 68, 211, 80, 83, 8, 182, 68, - 69, 202, 112, 73, 255, 133, 19, 65, 31, 44, 6, 32, 87, 73, 84, 72, 32, - 179, 1, 90, 24, 78, 83, 194, 15, 67, 250, 47, 84, 230, 116, 76, 226, 143, - 16, 68, 163, 199, 2, 72, 8, 92, 13, 77, 65, 76, 76, 32, 76, 69, 84, 84, - 69, 82, 32, 90, 178, 137, 1, 72, 243, 164, 20, 84, 5, 225, 72, 2, 32, 87, - 91, 104, 6, 32, 87, 73, 84, 72, 32, 152, 1, 2, 90, 72, 182, 76, 71, 166, - 239, 16, 84, 142, 159, 4, 83, 63, 78, 70, 174, 74, 67, 158, 2, 68, 194, - 16, 84, 158, 23, 77, 250, 1, 86, 250, 44, 72, 158, 1, 79, 198, 10, 71, - 186, 2, 65, 202, 168, 3, 73, 62, 66, 223, 210, 16, 83, 7, 11, 32, 4, 186, - 70, 87, 211, 8, 82, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 210, 135, 20, - 72, 138, 83, 68, 211, 80, 83, 35, 76, 6, 32, 87, 73, 84, 72, 32, 238, 81, - 76, 202, 182, 18, 65, 195, 207, 2, 72, 20, 202, 84, 67, 134, 90, 65, 134, - 169, 3, 66, 182, 25, 77, 198, 140, 4, 79, 142, 137, 11, 72, 138, 83, 68, - 211, 80, 83, 29, 76, 6, 32, 87, 73, 84, 72, 32, 182, 126, 65, 246, 238, - 7, 87, 207, 154, 12, 69, 20, 234, 82, 66, 34, 67, 46, 68, 226, 177, 19, - 72, 219, 163, 1, 83, 59, 80, 6, 32, 87, 73, 84, 72, 32, 180, 88, 2, 78, - 83, 218, 218, 20, 79, 207, 36, 83, 40, 138, 1, 68, 210, 83, 67, 242, 1, - 77, 142, 1, 84, 142, 70, 72, 158, 1, 79, 198, 10, 71, 186, 2, 65, 202, - 168, 3, 73, 62, 66, 223, 210, 16, 83, 10, 22, 79, 239, 83, 73, 6, 150, - 121, 85, 231, 190, 18, 84, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 42, 67, - 234, 241, 17, 84, 227, 179, 3, 83, 4, 166, 170, 1, 73, 207, 217, 3, 82, - 25, 33, 6, 32, 87, 73, 84, 72, 32, 22, 230, 89, 67, 34, 68, 50, 83, 234, - 78, 65, 138, 1, 76, 246, 205, 7, 79, 143, 137, 11, 72, 41, 60, 6, 32, 87, - 73, 84, 72, 32, 238, 94, 65, 251, 244, 20, 74, 32, 138, 1, 66, 36, 2, 68, - 79, 52, 7, 77, 73, 68, 68, 76, 69, 32, 38, 83, 174, 2, 67, 230, 91, 72, - 242, 71, 65, 138, 1, 76, 251, 198, 16, 84, 4, 242, 186, 12, 69, 139, 223, - 8, 65, 6, 22, 85, 151, 92, 84, 2, 129, 236, 4, 2, 66, 76, 4, 162, 238, - 17, 84, 167, 147, 3, 68, 4, 214, 2, 77, 151, 159, 21, 84, 19, 44, 6, 32, - 87, 73, 84, 72, 32, 255, 94, 73, 10, 174, 165, 1, 65, 234, 144, 16, 68, - 154, 55, 84, 139, 144, 2, 72, 33, 48, 6, 32, 87, 73, 84, 72, 32, 155, - 208, 21, 74, 28, 102, 67, 44, 2, 83, 77, 226, 96, 76, 146, 64, 71, 186, - 2, 65, 102, 68, 154, 206, 7, 79, 135, 249, 8, 84, 6, 250, 131, 1, 69, 22, - 73, 131, 166, 19, 65, 2, 189, 226, 10, 10, 65, 76, 76, 32, 76, 69, 84, - 84, 69, 82, 101, 108, 6, 32, 87, 73, 84, 72, 32, 226, 103, 76, 226, 152, - 4, 80, 170, 150, 9, 77, 242, 182, 7, 73, 2, 79, 3, 85, 84, 144, 1, 2, 76, - 79, 34, 77, 146, 97, 67, 70, 68, 154, 2, 79, 38, 83, 66, 84, 106, 86, - 234, 43, 72, 242, 12, 71, 186, 2, 65, 202, 168, 3, 73, 63, 66, 4, 206, - 99, 78, 235, 232, 20, 79, 8, 202, 99, 65, 195, 153, 4, 73, 17, 33, 6, 32, - 87, 73, 84, 72, 32, 14, 178, 104, 70, 34, 83, 178, 55, 65, 138, 216, 18, - 72, 139, 83, 68, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 134, 105, 68, 39, - 83, 43, 94, 32, 156, 1, 8, 69, 86, 69, 82, 83, 69, 68, 32, 160, 111, 3, - 85, 77, 32, 243, 141, 4, 65, 28, 40, 5, 87, 73, 84, 72, 32, 159, 112, 82, - 26, 194, 78, 67, 230, 28, 68, 170, 2, 84, 174, 48, 65, 138, 1, 76, 194, - 167, 3, 73, 182, 166, 4, 79, 231, 172, 12, 83, 8, 162, 110, 72, 230, 150, - 4, 79, 202, 183, 13, 67, 155, 140, 3, 69, 49, 136, 1, 6, 32, 87, 73, 84, - 72, 32, 136, 1, 5, 77, 65, 76, 76, 32, 184, 115, 2, 65, 76, 234, 1, 72, - 152, 2, 2, 73, 71, 243, 132, 4, 67, 32, 86, 67, 210, 111, 65, 118, 68, - 138, 1, 83, 174, 1, 86, 238, 246, 7, 79, 143, 137, 11, 72, 10, 170, 112, - 65, 230, 10, 69, 82, 79, 203, 31, 73, 4, 152, 146, 19, 11, 81, 32, 87, - 73, 84, 72, 32, 72, 79, 79, 75, 233, 243, 1, 7, 67, 65, 80, 73, 84, 65, - 76, 59, 136, 1, 6, 32, 87, 73, 84, 72, 32, 168, 1, 6, 85, 82, 78, 69, 68, - 32, 132, 123, 2, 72, 79, 176, 1, 2, 79, 78, 74, 82, 251, 197, 20, 90, 22, - 82, 67, 50, 68, 198, 152, 1, 76, 182, 232, 3, 82, 206, 238, 14, 72, 219, - 163, 1, 83, 8, 146, 120, 69, 22, 73, 62, 79, 199, 165, 19, 65, 6, 134, - 142, 1, 73, 171, 154, 16, 79, 18, 178, 40, 73, 146, 133, 3, 65, 178, 149, - 18, 72, 2, 75, 2, 76, 2, 77, 2, 84, 3, 86, 79, 26, 32, 203, 129, 5, 80, - 74, 44, 5, 87, 73, 84, 72, 32, 155, 160, 20, 66, 72, 238, 131, 1, 67, 74, - 68, 150, 2, 72, 170, 1, 77, 134, 1, 79, 142, 1, 84, 186, 9, 71, 186, 2, - 65, 202, 168, 3, 73, 62, 66, 242, 209, 14, 82, 239, 128, 2, 83, 23, 88, - 6, 32, 87, 73, 84, 72, 32, 250, 138, 1, 73, 66, 79, 170, 166, 19, 69, - 251, 141, 1, 89, 8, 170, 138, 1, 68, 210, 209, 16, 84, 139, 144, 2, 72, - 19, 48, 6, 32, 87, 73, 84, 72, 32, 251, 145, 7, 89, 14, 134, 144, 1, 67, - 18, 68, 70, 71, 186, 2, 65, 139, 216, 18, 72, 7, 145, 140, 1, 7, 32, 87, - 73, 84, 72, 32, 68, 29, 48, 6, 32, 87, 73, 84, 72, 32, 135, 153, 17, 79, - 24, 226, 142, 1, 67, 18, 68, 70, 71, 22, 72, 42, 76, 254, 1, 65, 186, - 194, 3, 77, 202, 133, 13, 84, 227, 179, 3, 83, 25, 33, 6, 32, 87, 73, 84, - 72, 32, 22, 186, 57, 67, 162, 87, 65, 102, 68, 38, 76, 34, 83, 190, 226, - 3, 80, 167, 244, 14, 72, 4, 170, 207, 10, 73, 231, 213, 10, 79, 12, 128, - 1, 5, 65, 82, 67, 72, 65, 30, 73, 64, 9, 82, 69, 86, 69, 82, 83, 69, 68, - 32, 245, 204, 10, 7, 83, 73, 68, 69, 87, 65, 89, 2, 177, 235, 13, 2, 73, - 67, 4, 164, 107, 5, 78, 86, 69, 82, 84, 221, 205, 14, 3, 32, 76, 79, 4, - 222, 185, 21, 70, 3, 80, 138, 1, 198, 3, 65, 36, 2, 66, 73, 152, 1, 21, - 73, 78, 86, 69, 82, 84, 69, 68, 32, 71, 76, 79, 84, 84, 65, 76, 32, 83, - 84, 79, 80, 72, 2, 82, 69, 222, 1, 83, 128, 8, 3, 84, 87, 79, 178, 20, - 87, 216, 163, 4, 2, 68, 69, 148, 5, 2, 76, 65, 206, 11, 71, 128, 176, 1, - 21, 80, 72, 65, 82, 89, 78, 71, 69, 65, 76, 32, 86, 79, 73, 67, 69, 68, - 32, 70, 82, 73, 164, 131, 14, 20, 86, 79, 73, 67, 69, 68, 32, 76, 65, 82, - 89, 78, 71, 69, 65, 76, 32, 83, 80, 73, 179, 117, 89, 4, 174, 181, 4, 76, - 235, 176, 16, 73, 6, 76, 7, 76, 65, 66, 73, 65, 76, 32, 29, 8, 68, 69, - 78, 84, 65, 76, 32, 80, 4, 26, 80, 175, 200, 4, 67, 2, 161, 129, 16, 6, - 69, 82, 67, 85, 83, 83, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 170, 237, 4, - 67, 243, 150, 16, 83, 8, 104, 7, 86, 69, 82, 83, 69, 68, 32, 185, 237, 4, - 13, 84, 82, 79, 70, 76, 69, 88, 32, 67, 76, 73, 67, 75, 4, 80, 3, 69, 83, - 72, 157, 8, 12, 71, 76, 79, 84, 84, 65, 76, 32, 83, 84, 79, 80, 2, 217, - 132, 1, 2, 32, 76, 96, 172, 1, 13, 77, 65, 76, 76, 32, 67, 65, 80, 73, - 84, 65, 76, 32, 248, 111, 10, 84, 82, 69, 84, 67, 72, 69, 68, 32, 67, - 221, 175, 19, 10, 73, 78, 79, 76, 79, 71, 73, 67, 65, 76, 90, 230, 1, 69, - 30, 73, 22, 76, 74, 79, 42, 82, 122, 84, 210, 176, 4, 66, 214, 41, 71, - 166, 146, 16, 65, 162, 64, 67, 2, 68, 2, 70, 2, 72, 2, 74, 2, 75, 2, 77, - 2, 78, 2, 80, 2, 81, 2, 83, 2, 85, 2, 86, 2, 87, 2, 89, 3, 90, 7, 238, - 173, 21, 84, 3, 90, 5, 227, 213, 4, 78, 7, 33, 6, 32, 87, 73, 84, 72, 32, - 4, 162, 219, 8, 66, 143, 163, 12, 83, 9, 242, 94, 80, 150, 207, 20, 69, - 3, 85, 11, 88, 8, 69, 86, 69, 82, 83, 69, 68, 32, 244, 127, 5, 32, 87, - 73, 84, 72, 187, 156, 20, 85, 4, 130, 173, 21, 78, 3, 82, 13, 33, 6, 85, - 82, 78, 69, 68, 32, 10, 194, 172, 21, 69, 2, 71, 2, 75, 2, 77, 3, 82, - 184, 11, 136, 1, 5, 77, 65, 76, 76, 32, 153, 130, 1, 22, 85, 66, 83, 67, - 82, 73, 80, 84, 32, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, - 148, 11, 76, 15, 67, 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, - 32, 43, 76, 4, 18, 73, 3, 85, 2, 211, 220, 4, 32, 144, 11, 76, 6, 69, 84, - 84, 69, 82, 32, 173, 127, 8, 73, 71, 65, 84, 85, 82, 69, 32, 254, 10, - 182, 2, 65, 190, 5, 66, 198, 3, 67, 186, 4, 68, 182, 4, 69, 174, 9, 70, - 214, 1, 71, 162, 2, 72, 230, 2, 73, 166, 7, 74, 182, 1, 75, 178, 2, 76, - 206, 6, 77, 178, 2, 78, 218, 3, 79, 242, 8, 80, 230, 1, 81, 174, 1, 82, - 142, 8, 83, 250, 10, 84, 246, 13, 85, 218, 9, 86, 130, 3, 87, 110, 88, - 226, 2, 89, 171, 3, 90, 101, 118, 32, 198, 3, 69, 82, 78, 152, 220, 4, 4, - 76, 80, 72, 65, 158, 163, 15, 86, 182, 162, 1, 65, 2, 79, 2, 85, 3, 89, - 72, 88, 5, 87, 73, 84, 72, 32, 225, 222, 5, 11, 82, 69, 86, 69, 82, 83, - 69, 68, 45, 83, 67, 70, 150, 1, 66, 34, 68, 54, 82, 170, 34, 77, 250, 21, - 67, 162, 49, 72, 158, 1, 79, 198, 10, 71, 186, 2, 65, 202, 168, 3, 73, - 186, 159, 13, 84, 227, 179, 3, 83, 12, 173, 105, 4, 82, 69, 86, 69, 12, - 22, 79, 151, 57, 73, 8, 214, 57, 84, 223, 12, 85, 10, 26, 73, 135, 225, - 4, 69, 8, 26, 78, 139, 168, 4, 71, 6, 17, 2, 71, 32, 6, 236, 58, 4, 65, - 66, 79, 86, 235, 201, 18, 66, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 254, - 115, 71, 186, 2, 65, 187, 194, 3, 77, 2, 165, 191, 10, 7, 71, 76, 73, 67, - 65, 78, 65, 41, 140, 1, 6, 32, 87, 73, 84, 72, 32, 130, 1, 65, 108, 11, - 76, 65, 67, 75, 76, 69, 84, 84, 69, 82, 32, 38, 82, 134, 195, 4, 79, 203, - 182, 16, 69, 18, 110, 84, 142, 60, 70, 218, 56, 76, 178, 219, 3, 77, 174, - 7, 80, 134, 173, 12, 68, 162, 199, 2, 72, 219, 163, 1, 83, 2, 255, 7, 79, - 8, 64, 5, 82, 82, 69, 68, 32, 173, 80, 6, 83, 69, 76, 73, 78, 69, 6, 182, - 32, 65, 174, 254, 20, 69, 3, 79, 6, 202, 189, 4, 79, 243, 224, 16, 69, 2, - 165, 179, 10, 4, 79, 75, 69, 78, 47, 108, 6, 32, 87, 73, 84, 72, 32, 196, - 1, 2, 72, 73, 92, 6, 76, 79, 83, 69, 68, 32, 90, 85, 175, 202, 20, 79, - 24, 102, 67, 194, 112, 65, 230, 227, 3, 80, 218, 5, 82, 206, 238, 14, 72, - 158, 50, 66, 238, 32, 68, 211, 80, 83, 10, 54, 69, 202, 112, 73, 230, - 245, 6, 85, 155, 144, 12, 65, 4, 245, 51, 5, 68, 73, 76, 76, 65, 7, 49, - 10, 32, 87, 73, 84, 72, 32, 76, 79, 87, 32, 4, 174, 106, 82, 45, 4, 76, - 69, 70, 84, 8, 34, 73, 18, 79, 247, 193, 4, 82, 2, 175, 87, 78, 4, 218, - 214, 4, 80, 231, 140, 9, 77, 4, 37, 7, 65, 84, 82, 73, 76, 76, 79, 5, - 253, 130, 13, 5, 32, 87, 73, 84, 72, 73, 96, 6, 32, 87, 73, 84, 72, 32, - 182, 1, 69, 34, 79, 178, 1, 90, 138, 207, 4, 66, 247, 181, 16, 85, 32, - 98, 83, 34, 84, 238, 32, 67, 238, 44, 77, 170, 31, 76, 214, 211, 3, 72, - 138, 15, 80, 135, 173, 12, 68, 4, 146, 67, 72, 243, 164, 20, 84, 4, 26, - 79, 231, 227, 18, 65, 2, 243, 245, 19, 80, 8, 130, 78, 90, 215, 164, 20, - 76, 16, 60, 6, 84, 76, 69, 83, 83, 32, 49, 5, 85, 66, 76, 69, 32, 8, 26, - 74, 171, 150, 21, 73, 7, 255, 191, 4, 32, 8, 42, 87, 230, 195, 4, 82, - 199, 238, 5, 84, 2, 239, 232, 6, 89, 11, 11, 32, 8, 26, 87, 239, 191, 4, - 68, 2, 181, 89, 5, 73, 84, 72, 32, 67, 119, 112, 6, 32, 87, 73, 84, 72, - 32, 214, 4, 71, 72, 2, 78, 71, 68, 2, 83, 72, 164, 1, 2, 90, 72, 247, - 236, 16, 84, 76, 182, 1, 67, 158, 2, 68, 110, 78, 214, 15, 84, 158, 23, - 77, 250, 1, 86, 194, 3, 70, 186, 41, 72, 158, 1, 79, 198, 10, 71, 186, 2, - 65, 202, 168, 3, 73, 62, 66, 186, 64, 82, 167, 146, 16, 83, 24, 92, 6, - 69, 68, 73, 76, 76, 65, 32, 9, 73, 82, 67, 85, 77, 70, 76, 69, 88, 191, - 236, 19, 65, 5, 137, 143, 4, 3, 32, 65, 78, 19, 11, 32, 16, 40, 4, 65, - 78, 68, 32, 151, 243, 18, 66, 14, 174, 85, 67, 130, 2, 72, 226, 11, 71, - 186, 2, 65, 186, 194, 3, 77, 250, 169, 4, 68, 211, 219, 8, 84, 12, 22, - 79, 239, 97, 73, 10, 28, 2, 84, 32, 239, 50, 85, 8, 204, 87, 5, 65, 66, - 79, 86, 69, 171, 154, 18, 66, 2, 167, 142, 14, 79, 4, 221, 255, 6, 13, - 89, 80, 84, 79, 76, 79, 71, 73, 67, 65, 76, 32, 65, 7, 33, 6, 32, 87, 73, - 84, 72, 32, 4, 246, 188, 4, 67, 231, 9, 80, 13, 33, 6, 32, 87, 73, 84, - 72, 32, 10, 88, 10, 68, 79, 85, 66, 76, 69, 32, 66, 65, 82, 190, 197, 4, - 80, 142, 1, 67, 207, 4, 82, 5, 177, 198, 4, 4, 32, 65, 78, 68, 15, 11, - 32, 12, 38, 82, 37, 5, 87, 73, 84, 72, 32, 2, 193, 138, 14, 4, 69, 86, - 69, 82, 10, 54, 67, 138, 196, 4, 80, 218, 5, 82, 195, 142, 14, 84, 4, - 198, 214, 7, 85, 155, 144, 12, 65, 17, 84, 6, 32, 87, 73, 84, 72, 32, 73, - 11, 69, 78, 71, 32, 68, 73, 71, 82, 65, 80, 72, 10, 222, 187, 4, 77, 174, - 7, 80, 166, 244, 14, 72, 138, 83, 68, 211, 80, 83, 5, 181, 146, 18, 8, - 32, 87, 73, 84, 72, 32, 84, 82, 37, 72, 6, 32, 87, 73, 84, 72, 32, 126, - 76, 202, 182, 18, 65, 195, 207, 2, 72, 22, 218, 3, 67, 134, 90, 65, 134, - 169, 3, 66, 182, 25, 77, 174, 33, 80, 154, 235, 3, 79, 142, 137, 11, 72, - 138, 83, 68, 211, 80, 83, 8, 33, 6, 79, 84, 84, 65, 76, 32, 8, 242, 182, - 18, 83, 170, 209, 2, 65, 2, 73, 3, 85, 39, 140, 1, 6, 32, 87, 73, 84, 72, - 32, 162, 44, 65, 232, 25, 12, 79, 79, 75, 69, 68, 32, 83, 67, 72, 87, 65, - 32, 250, 237, 3, 69, 219, 210, 16, 86, 24, 86, 66, 34, 67, 46, 68, 226, - 90, 76, 222, 226, 3, 80, 166, 244, 14, 72, 219, 163, 1, 83, 2, 233, 135, - 13, 3, 82, 69, 86, 6, 170, 58, 69, 154, 32, 73, 255, 133, 19, 65, 8, 246, - 86, 73, 174, 185, 3, 69, 171, 218, 12, 79, 75, 80, 6, 32, 87, 73, 84, 72, - 32, 222, 4, 78, 188, 1, 2, 79, 84, 155, 254, 20, 83, 48, 178, 1, 67, 34, - 68, 210, 1, 77, 64, 6, 79, 71, 79, 78, 69, 75, 78, 84, 142, 70, 72, 226, - 11, 71, 186, 2, 65, 202, 168, 3, 73, 62, 66, 136, 64, 6, 83, 84, 82, 79, - 75, 69, 51, 82, 4, 222, 87, 73, 255, 133, 19, 65, 14, 18, 73, 47, 79, 4, - 217, 26, 7, 65, 69, 82, 69, 83, 73, 83, 10, 28, 2, 84, 32, 227, 36, 85, - 8, 64, 10, 65, 66, 79, 86, 69, 32, 65, 78, 68, 32, 171, 227, 18, 66, 6, - 162, 83, 71, 186, 2, 65, 131, 200, 16, 84, 4, 29, 5, 65, 67, 82, 79, 78, - 5, 229, 35, 4, 32, 65, 78, 68, 7, 157, 72, 15, 32, 65, 78, 68, 32, 68, - 79, 84, 32, 65, 66, 79, 86, 69, 32, 4, 21, 3, 73, 76, 68, 4, 211, 135, 5, - 69, 16, 46, 83, 93, 7, 86, 69, 82, 84, 69, 68, 32, 12, 29, 5, 85, 76, 65, - 82, 32, 12, 130, 255, 20, 68, 2, 70, 2, 71, 2, 82, 2, 83, 3, 84, 4, 26, - 65, 219, 231, 20, 79, 2, 247, 165, 17, 76, 6, 166, 157, 4, 65, 129, 186, - 6, 5, 73, 70, 73, 69, 68, 13, 33, 6, 32, 87, 73, 84, 72, 32, 10, 94, 67, - 236, 173, 4, 13, 68, 79, 84, 32, 65, 66, 79, 86, 69, 32, 65, 78, 68, 247, - 158, 16, 83, 6, 190, 81, 73, 206, 217, 3, 82, 179, 172, 15, 65, 29, 48, - 6, 32, 87, 73, 84, 72, 32, 195, 249, 20, 82, 24, 98, 67, 34, 68, 50, 83, - 234, 78, 65, 138, 1, 76, 222, 226, 3, 80, 154, 235, 3, 79, 143, 137, 11, - 72, 4, 222, 47, 69, 151, 166, 19, 65, 6, 226, 69, 73, 130, 192, 3, 69, - 243, 181, 4, 79, 4, 29, 5, 84, 82, 79, 75, 69, 5, 173, 24, 6, 32, 65, 78, - 68, 32, 68, 79, 136, 1, 6, 32, 87, 73, 84, 72, 32, 250, 3, 65, 38, 69, - 48, 5, 79, 78, 71, 32, 83, 218, 173, 4, 83, 2, 90, 246, 181, 16, 85, 219, - 16, 74, 50, 178, 1, 66, 86, 67, 56, 2, 68, 79, 100, 3, 77, 73, 68, 130, - 2, 72, 242, 71, 65, 138, 1, 76, 226, 218, 3, 73, 162, 1, 82, 222, 2, 70, - 130, 4, 80, 158, 228, 12, 84, 227, 179, 3, 83, 6, 36, 3, 69, 76, 84, 187, - 190, 20, 65, 5, 153, 175, 4, 6, 32, 65, 78, 68, 32, 80, 8, 178, 43, 69, - 22, 73, 234, 149, 7, 85, 155, 144, 12, 65, 8, 38, 84, 25, 5, 85, 66, 76, - 69, 32, 4, 153, 24, 2, 32, 66, 4, 202, 166, 4, 77, 239, 173, 15, 66, 8, - 36, 4, 68, 76, 69, 32, 219, 43, 45, 6, 198, 145, 17, 84, 218, 146, 3, 82, - 79, 68, 4, 133, 148, 4, 4, 77, 66, 68, 65, 6, 246, 174, 4, 90, 205, 250, - 12, 3, 78, 73, 83, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 18, 68, 35, 72, - 4, 218, 62, 73, 211, 180, 19, 79, 2, 157, 166, 4, 2, 73, 71, 27, 56, 6, - 32, 87, 73, 84, 72, 32, 102, 73, 187, 225, 20, 85, 16, 150, 71, 65, 130, - 218, 3, 67, 186, 2, 77, 174, 7, 80, 134, 173, 12, 68, 154, 55, 84, 139, - 144, 2, 72, 6, 25, 4, 68, 68, 76, 69, 6, 76, 7, 45, 87, 69, 76, 83, 72, - 32, 149, 252, 16, 6, 32, 83, 67, 79, 84, 83, 4, 238, 231, 19, 76, 183, - 137, 1, 86, 49, 58, 32, 216, 2, 2, 71, 32, 150, 221, 20, 85, 219, 16, 74, - 40, 88, 5, 87, 73, 84, 72, 32, 153, 136, 6, 11, 80, 82, 69, 67, 69, 68, - 69, 68, 32, 66, 89, 38, 122, 67, 74, 76, 170, 36, 77, 234, 27, 71, 186, - 2, 65, 102, 68, 130, 227, 3, 80, 218, 5, 82, 194, 229, 3, 79, 135, 249, - 8, 84, 10, 182, 35, 69, 22, 73, 210, 249, 3, 82, 154, 156, 3, 85, 155, - 144, 12, 65, 6, 144, 65, 3, 79, 78, 71, 202, 2, 73, 131, 234, 3, 69, 2, - 25, 4, 87, 73, 84, 72, 2, 153, 202, 17, 5, 32, 84, 73, 76, 68, 115, 116, - 6, 32, 87, 73, 84, 72, 32, 186, 6, 76, 52, 4, 80, 69, 78, 32, 214, 174, - 13, 77, 242, 182, 7, 73, 2, 79, 3, 85, 86, 154, 1, 67, 70, 68, 152, 1, 2, - 76, 79, 86, 77, 46, 79, 38, 83, 66, 84, 106, 86, 234, 43, 72, 242, 12, - 71, 186, 2, 65, 202, 168, 3, 73, 62, 66, 187, 64, 82, 14, 184, 48, 9, 73, - 82, 67, 85, 77, 70, 76, 69, 88, 187, 149, 19, 65, 14, 18, 73, 47, 79, 4, - 233, 12, 7, 65, 69, 82, 69, 83, 73, 83, 10, 22, 84, 183, 46, 85, 6, 11, - 32, 6, 152, 12, 5, 65, 66, 79, 86, 69, 195, 191, 18, 66, 6, 66, 78, 132, - 197, 12, 6, 87, 32, 82, 73, 78, 71, 231, 163, 8, 79, 2, 171, 20, 71, 6, - 11, 65, 6, 189, 2, 4, 67, 82, 79, 78, 4, 229, 10, 5, 71, 79, 78, 69, 75, - 4, 25, 4, 84, 82, 79, 75, 4, 11, 69, 5, 225, 48, 2, 32, 65, 8, 25, 4, 73, - 76, 68, 69, 9, 29, 5, 32, 65, 78, 68, 32, 6, 174, 46, 68, 142, 13, 65, - 187, 194, 3, 77, 6, 81, 18, 69, 82, 84, 73, 67, 65, 76, 32, 76, 73, 78, - 69, 32, 66, 69, 76, 79, 87, 7, 233, 42, 4, 32, 65, 78, 68, 2, 137, 129, - 10, 8, 68, 32, 80, 79, 76, 73, 83, 72, 16, 26, 79, 219, 159, 4, 69, 13, - 48, 6, 32, 87, 73, 84, 72, 32, 247, 228, 20, 69, 8, 222, 54, 71, 186, 2, - 65, 190, 233, 3, 82, 167, 146, 16, 83, 23, 48, 6, 32, 87, 73, 84, 72, 32, - 175, 208, 20, 72, 18, 86, 70, 34, 83, 178, 55, 65, 186, 220, 3, 77, 174, - 7, 80, 166, 244, 14, 72, 139, 83, 68, 2, 137, 185, 14, 3, 76, 79, 85, 6, - 218, 27, 84, 241, 164, 12, 6, 81, 85, 73, 82, 82, 69, 13, 48, 6, 32, 87, - 73, 84, 72, 32, 215, 155, 4, 80, 8, 42, 68, 16, 4, 72, 79, 79, 75, 23, - 83, 2, 227, 44, 73, 5, 247, 173, 18, 32, 2, 197, 26, 6, 84, 82, 79, 75, - 69, 32, 77, 90, 32, 228, 4, 8, 69, 86, 69, 82, 83, 69, 68, 32, 148, 2, 2, - 85, 77, 255, 141, 4, 65, 46, 36, 4, 87, 73, 84, 72, 235, 6, 82, 44, 26, - 32, 215, 174, 15, 79, 42, 166, 1, 67, 50, 68, 200, 1, 8, 70, 73, 83, 72, - 72, 79, 79, 75, 66, 76, 34, 84, 142, 18, 77, 162, 30, 65, 202, 168, 3, - 73, 158, 59, 80, 154, 235, 3, 79, 231, 172, 12, 83, 6, 170, 19, 69, 230, - 249, 3, 82, 179, 172, 15, 65, 8, 11, 79, 8, 24, 2, 84, 32, 111, 85, 6, - 26, 66, 131, 225, 19, 65, 4, 25, 4, 69, 76, 79, 87, 5, 29, 5, 32, 65, 78, - 68, 32, 2, 139, 244, 3, 77, 2, 21, 3, 66, 76, 69, 2, 11, 32, 2, 227, 46, - 71, 7, 29, 5, 32, 65, 78, 68, 32, 4, 162, 141, 4, 77, 175, 7, 80, 4, 222, - 49, 73, 207, 230, 3, 79, 4, 178, 168, 18, 65, 163, 26, 73, 22, 162, 1, - 72, 40, 6, 79, 80, 69, 78, 32, 69, 164, 142, 4, 8, 82, 32, 87, 73, 84, - 72, 32, 70, 168, 2, 3, 83, 67, 82, 226, 206, 14, 69, 234, 86, 67, 139, - 164, 1, 75, 2, 11, 65, 2, 225, 244, 9, 2, 76, 70, 7, 33, 6, 32, 87, 73, - 84, 72, 32, 4, 214, 151, 4, 82, 207, 238, 14, 72, 5, 11, 32, 2, 11, 82, - 2, 149, 253, 16, 3, 79, 84, 85, 85, 180, 1, 6, 32, 87, 73, 84, 72, 32, - 218, 4, 65, 66, 67, 218, 1, 72, 34, 73, 156, 2, 13, 81, 85, 65, 84, 32, - 82, 69, 86, 69, 82, 83, 69, 68, 193, 229, 9, 6, 84, 73, 82, 82, 85, 80, - 40, 110, 65, 34, 67, 86, 68, 138, 1, 83, 174, 1, 86, 210, 9, 77, 134, - 130, 4, 80, 154, 235, 3, 79, 143, 137, 11, 72, 4, 205, 1, 4, 67, 85, 84, - 69, 12, 58, 65, 230, 10, 69, 82, 79, 202, 31, 73, 231, 245, 6, 85, 4, - 113, 3, 82, 79, 78, 8, 32, 3, 79, 84, 32, 207, 32, 73, 6, 26, 66, 215, - 216, 19, 65, 4, 25, 4, 69, 76, 79, 87, 5, 11, 32, 2, 181, 212, 19, 3, 65, - 78, 68, 4, 22, 72, 203, 42, 87, 2, 21, 3, 79, 82, 84, 2, 17, 2, 32, 83, - 2, 11, 84, 2, 21, 3, 82, 79, 75, 2, 11, 69, 2, 17, 2, 32, 79, 2, 233, - 199, 19, 4, 86, 69, 82, 76, 2, 37, 7, 69, 82, 84, 73, 67, 65, 76, 2, 205, - 40, 2, 32, 76, 4, 46, 76, 245, 190, 19, 5, 75, 72, 65, 32, 89, 2, 247, - 12, 84, 18, 48, 3, 72, 87, 65, 97, 5, 82, 73, 80, 84, 32, 11, 33, 6, 32, - 87, 73, 84, 72, 32, 8, 222, 35, 71, 186, 2, 65, 190, 233, 3, 82, 207, - 238, 14, 72, 8, 26, 82, 155, 255, 3, 71, 5, 253, 175, 11, 5, 32, 87, 73, - 84, 72, 2, 225, 219, 16, 3, 65, 82, 80, 14, 48, 7, 68, 69, 87, 65, 89, - 83, 32, 199, 1, 71, 12, 110, 79, 56, 4, 84, 85, 82, 78, 176, 195, 10, 11, - 68, 73, 65, 69, 82, 69, 83, 73, 90, 69, 68, 203, 139, 10, 85, 7, 26, 80, - 211, 129, 4, 32, 2, 165, 234, 9, 2, 69, 78, 2, 237, 255, 12, 2, 69, 68, - 2, 201, 217, 16, 4, 77, 79, 73, 68, 2, 247, 250, 9, 32, 147, 1, 188, 1, - 6, 32, 87, 73, 84, 72, 32, 192, 3, 2, 69, 83, 70, 72, 130, 2, 79, 102, - 82, 54, 85, 250, 253, 3, 67, 202, 1, 83, 132, 247, 10, 9, 65, 73, 76, 76, - 69, 83, 83, 32, 80, 131, 207, 5, 90, 34, 110, 67, 182, 1, 68, 66, 77, - 170, 31, 76, 222, 226, 3, 80, 168, 5, 4, 72, 79, 79, 75, 50, 82, 167, - 146, 16, 83, 10, 58, 69, 22, 73, 62, 79, 174, 149, 7, 85, 155, 144, 12, - 65, 2, 251, 157, 12, 68, 2, 37, 7, 82, 67, 85, 77, 70, 76, 69, 2, 179, - 157, 18, 88, 2, 17, 2, 77, 77, 2, 139, 157, 18, 65, 8, 32, 2, 73, 65, - 179, 175, 16, 79, 4, 154, 21, 71, 215, 6, 69, 4, 17, 2, 73, 68, 4, 26, - 45, 203, 250, 3, 68, 2, 225, 136, 4, 6, 72, 69, 73, 71, 72, 84, 6, 45, 9, - 72, 32, 68, 73, 71, 82, 65, 80, 72, 7, 191, 128, 4, 32, 8, 64, 12, 32, - 87, 73, 84, 72, 32, 83, 84, 82, 73, 75, 69, 43, 79, 2, 205, 163, 16, 5, - 84, 72, 82, 79, 85, 6, 17, 2, 82, 78, 7, 41, 8, 32, 87, 73, 84, 72, 32, - 83, 84, 4, 25, 4, 82, 79, 75, 69, 5, 11, 32, 2, 209, 209, 3, 6, 84, 72, - 82, 79, 85, 71, 8, 26, 78, 151, 128, 4, 80, 6, 17, 2, 69, 32, 6, 134, - 201, 4, 83, 230, 197, 9, 84, 255, 131, 1, 70, 2, 17, 2, 69, 83, 2, 11, - 73, 2, 135, 163, 20, 76, 76, 44, 5, 82, 78, 69, 68, 32, 151, 197, 20, 77, - 74, 162, 1, 68, 22, 72, 66, 73, 54, 79, 142, 1, 82, 110, 84, 22, 86, 146, - 252, 3, 65, 38, 77, 198, 2, 89, 142, 174, 16, 85, 218, 19, 69, 2, 71, 2, - 75, 2, 76, 3, 87, 2, 223, 138, 17, 69, 7, 217, 236, 3, 11, 32, 87, 73, - 84, 72, 32, 70, 73, 83, 72, 72, 5, 11, 78, 2, 169, 212, 9, 5, 83, 85, 76, - 65, 82, 12, 66, 69, 180, 225, 3, 7, 32, 79, 80, 69, 78, 45, 79, 159, 29, - 80, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 202, 157, 18, 72, 187, 244, 1, - 83, 15, 33, 6, 32, 87, 73, 84, 72, 32, 12, 146, 242, 3, 77, 174, 7, 80, - 130, 5, 76, 154, 143, 14, 84, 143, 96, 72, 5, 211, 249, 3, 32, 7, 11, 32, - 4, 161, 5, 4, 87, 73, 84, 72, 97, 90, 32, 228, 222, 3, 6, 80, 83, 73, 76, - 79, 78, 242, 224, 16, 69, 2, 73, 2, 77, 3, 79, 82, 48, 3, 66, 65, 82, 49, - 5, 87, 73, 84, 72, 32, 5, 245, 17, 8, 32, 87, 73, 84, 72, 32, 83, 72, 78, - 142, 1, 67, 74, 68, 150, 2, 72, 170, 1, 77, 134, 1, 79, 106, 82, 38, 84, - 186, 9, 71, 82, 83, 234, 1, 65, 202, 168, 3, 73, 62, 66, 135, 66, 76, 6, - 200, 197, 4, 9, 73, 82, 67, 85, 77, 70, 76, 69, 88, 247, 210, 14, 65, 18, - 52, 8, 73, 65, 69, 82, 69, 83, 73, 83, 131, 1, 79, 13, 11, 32, 10, 40, 4, - 65, 78, 68, 32, 155, 158, 18, 66, 8, 50, 67, 226, 13, 71, 186, 2, 65, - 187, 194, 3, 77, 2, 211, 150, 19, 65, 6, 26, 85, 131, 142, 18, 84, 4, 21, - 3, 66, 76, 69, 4, 11, 32, 4, 138, 13, 71, 187, 2, 65, 14, 11, 79, 14, 28, - 2, 82, 78, 191, 81, 79, 13, 29, 5, 32, 65, 78, 68, 32, 10, 66, 72, 226, - 11, 71, 186, 2, 65, 178, 236, 7, 68, 211, 219, 8, 84, 2, 213, 80, 2, 79, - 79, 10, 29, 5, 65, 67, 82, 79, 78, 11, 29, 5, 32, 65, 78, 68, 32, 8, 50, - 68, 214, 10, 71, 186, 2, 65, 131, 200, 16, 84, 2, 171, 10, 73, 6, 29, 5, - 71, 79, 78, 69, 75, 7, 11, 32, 4, 25, 4, 65, 78, 68, 32, 4, 178, 12, 65, - 131, 200, 16, 84, 4, 218, 245, 3, 69, 187, 145, 14, 73, 6, 25, 4, 73, 76, - 68, 69, 7, 11, 32, 4, 26, 65, 251, 152, 18, 66, 2, 17, 2, 78, 68, 2, 11, - 32, 2, 139, 11, 65, 29, 84, 6, 32, 87, 73, 84, 72, 32, 162, 1, 73, 66, - 79, 170, 166, 19, 69, 251, 141, 1, 89, 14, 82, 68, 182, 237, 3, 80, 142, - 1, 67, 146, 7, 82, 130, 220, 12, 84, 139, 144, 2, 72, 4, 26, 73, 243, - 245, 7, 79, 2, 17, 2, 65, 71, 2, 209, 132, 20, 2, 79, 78, 2, 41, 8, 83, - 73, 71, 79, 84, 72, 73, 67, 2, 135, 145, 16, 32, 6, 33, 6, 76, 65, 80, - 85, 75, 32, 6, 166, 157, 20, 65, 2, 79, 3, 85, 19, 33, 6, 32, 87, 73, 84, - 72, 32, 16, 202, 4, 67, 18, 68, 70, 71, 186, 2, 65, 246, 250, 17, 82, - 151, 93, 72, 17, 33, 6, 32, 87, 73, 84, 72, 32, 14, 42, 68, 32, 2, 76, - 79, 135, 234, 3, 80, 4, 222, 3, 73, 255, 173, 19, 79, 8, 60, 11, 78, 71, - 32, 76, 69, 70, 84, 32, 76, 69, 71, 79, 87, 7, 11, 32, 4, 60, 7, 65, 78, - 68, 32, 76, 79, 87, 65, 4, 87, 73, 84, 72, 2, 17, 2, 32, 82, 2, 21, 3, - 73, 71, 72, 2, 167, 143, 11, 84, 2, 193, 174, 19, 4, 32, 83, 69, 82, 33, - 48, 6, 32, 87, 73, 84, 72, 32, 147, 139, 16, 79, 28, 110, 67, 18, 68, 70, - 71, 22, 72, 42, 76, 22, 83, 234, 1, 65, 186, 194, 3, 77, 202, 133, 13, - 84, 247, 178, 1, 82, 2, 203, 3, 73, 6, 26, 73, 215, 147, 16, 79, 2, 17, - 2, 65, 69, 2, 151, 172, 16, 82, 2, 223, 194, 18, 82, 4, 17, 2, 79, 79, 4, - 171, 131, 5, 75, 2, 195, 180, 19, 79, 4, 26, 72, 187, 253, 19, 84, 2, 21, - 3, 79, 82, 84, 2, 233, 246, 7, 6, 32, 82, 73, 71, 72, 84, 31, 33, 6, 32, - 87, 73, 84, 72, 32, 28, 98, 65, 22, 67, 82, 68, 38, 76, 34, 83, 146, 219, - 3, 77, 174, 7, 80, 218, 5, 82, 207, 238, 14, 72, 2, 231, 179, 13, 67, 6, - 42, 73, 230, 245, 6, 85, 155, 144, 12, 65, 2, 241, 192, 11, 4, 82, 67, - 85, 77, 6, 230, 181, 3, 69, 171, 218, 12, 79, 2, 11, 73, 2, 179, 172, 12, - 78, 4, 26, 87, 171, 250, 19, 84, 2, 179, 133, 17, 65, 18, 90, 70, 242, - 188, 9, 73, 172, 9, 6, 76, 79, 78, 71, 32, 83, 226, 198, 10, 83, 219, 5, - 79, 10, 34, 70, 134, 169, 20, 73, 3, 76, 7, 130, 169, 20, 73, 3, 76, 36, - 150, 1, 83, 210, 167, 20, 65, 2, 69, 2, 72, 2, 73, 2, 74, 2, 75, 2, 76, - 2, 77, 2, 78, 2, 79, 2, 80, 2, 82, 2, 84, 2, 85, 2, 86, 3, 88, 5, 143, - 225, 4, 67, 224, 5, 204, 1, 2, 65, 70, 144, 1, 2, 70, 84, 210, 38, 79, - 20, 5, 80, 67, 72, 65, 32, 164, 8, 8, 83, 83, 45, 84, 72, 65, 78, 32, - 254, 167, 16, 68, 228, 23, 6, 86, 69, 76, 32, 83, 76, 134, 230, 2, 77, - 239, 79, 71, 6, 120, 3, 76, 69, 83, 204, 191, 1, 14, 32, 70, 76, 85, 84, - 84, 69, 82, 73, 78, 71, 32, 73, 78, 209, 212, 11, 3, 89, 32, 71, 2, 135, - 228, 14, 83, 134, 4, 58, 32, 250, 20, 45, 217, 2, 6, 87, 65, 82, 68, 83, - 32, 246, 1, 166, 2, 65, 234, 4, 66, 202, 1, 67, 96, 2, 68, 79, 112, 2, - 72, 65, 166, 3, 76, 46, 77, 38, 79, 102, 82, 146, 3, 83, 82, 84, 222, 1, - 87, 242, 176, 8, 70, 236, 5, 14, 74, 85, 83, 84, 73, 70, 73, 69, 68, 32, - 82, 73, 71, 72, 86, 78, 202, 1, 80, 153, 13, 10, 86, 69, 82, 84, 73, 67, - 65, 76, 32, 66, 28, 22, 78, 143, 4, 82, 22, 28, 2, 68, 32, 191, 3, 71, - 16, 96, 6, 76, 79, 87, 69, 82, 32, 32, 6, 82, 73, 71, 72, 84, 32, 89, 6, - 85, 80, 80, 69, 82, 32, 4, 202, 1, 65, 235, 175, 17, 79, 6, 50, 84, 209, - 250, 17, 6, 68, 79, 85, 66, 76, 69, 4, 250, 136, 17, 82, 147, 231, 1, 65, - 6, 82, 65, 53, 16, 79, 78, 69, 32, 69, 73, 71, 72, 84, 72, 32, 66, 76, - 79, 67, 75, 2, 237, 134, 17, 8, 78, 68, 32, 82, 73, 71, 72, 84, 5, 165, - 253, 18, 17, 32, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, 65, - 67, 75, 6, 154, 182, 8, 69, 185, 1, 4, 76, 69, 32, 66, 6, 26, 67, 247, - 185, 8, 82, 2, 209, 185, 8, 5, 32, 76, 69, 83, 83, 12, 40, 4, 65, 82, 66, - 32, 143, 186, 8, 76, 8, 40, 4, 68, 79, 87, 78, 1, 2, 85, 80, 4, 57, 12, - 32, 82, 73, 71, 72, 84, 32, 66, 65, 82, 66, 32, 4, 240, 244, 16, 4, 68, - 79, 87, 78, 1, 2, 85, 80, 14, 210, 185, 8, 85, 166, 26, 79, 206, 231, 2, - 69, 233, 168, 2, 8, 76, 79, 83, 69, 68, 32, 69, 78, 10, 44, 5, 85, 66, - 76, 69, 32, 255, 185, 8, 84, 8, 178, 187, 8, 87, 190, 30, 65, 138, 128, - 3, 81, 131, 190, 4, 80, 38, 36, 3, 76, 70, 32, 247, 191, 8, 78, 36, 132, - 2, 6, 67, 73, 82, 67, 76, 69, 246, 186, 8, 66, 90, 70, 82, 72, 50, 82, - 58, 84, 70, 87, 246, 13, 76, 22, 85, 220, 185, 8, 30, 73, 78, 86, 69, 82, - 83, 69, 32, 77, 69, 68, 73, 85, 77, 32, 83, 72, 65, 68, 69, 32, 65, 78, - 68, 32, 82, 73, 71, 72, 84, 251, 26, 77, 11, 33, 6, 32, 87, 73, 84, 72, - 32, 8, 42, 84, 206, 243, 17, 70, 235, 210, 1, 68, 4, 242, 197, 5, 72, - 179, 128, 13, 87, 4, 152, 158, 1, 2, 85, 71, 199, 159, 7, 79, 2, 161, - 133, 19, 4, 85, 76, 84, 73, 8, 36, 3, 78, 69, 32, 199, 190, 8, 85, 6, - 190, 162, 17, 81, 146, 4, 69, 45, 5, 84, 72, 73, 82, 68, 30, 44, 5, 73, - 71, 72, 84, 32, 155, 191, 8, 65, 28, 152, 1, 5, 65, 82, 82, 79, 87, 132, - 1, 12, 68, 79, 85, 66, 76, 69, 32, 65, 82, 82, 79, 87, 30, 87, 222, 236, - 8, 79, 154, 128, 8, 66, 54, 83, 207, 68, 84, 11, 11, 32, 8, 72, 5, 87, - 73, 84, 72, 32, 165, 192, 18, 7, 84, 72, 82, 79, 85, 71, 72, 6, 182, 174, - 16, 68, 242, 179, 3, 86, 79, 83, 7, 201, 228, 8, 2, 32, 87, 4, 210, 247, - 8, 65, 215, 176, 8, 72, 34, 174, 189, 8, 45, 70, 69, 78, 73, 168, 1, 3, - 80, 69, 69, 26, 81, 227, 2, 85, 26, 106, 82, 134, 194, 8, 72, 174, 212, - 7, 79, 208, 133, 1, 8, 87, 79, 32, 84, 72, 73, 82, 68, 219, 196, 1, 65, - 6, 40, 4, 73, 65, 78, 71, 255, 196, 8, 65, 4, 236, 236, 4, 8, 76, 69, 32, - 66, 69, 83, 73, 68, 207, 175, 12, 85, 16, 162, 199, 8, 72, 202, 1, 73, - 169, 184, 10, 2, 82, 73, 62, 128, 1, 9, 80, 79, 73, 78, 84, 73, 78, 71, - 32, 138, 1, 83, 206, 199, 8, 70, 226, 2, 72, 153, 7, 7, 84, 79, 45, 82, - 73, 71, 72, 30, 86, 65, 214, 204, 8, 67, 94, 68, 58, 77, 58, 82, 182, 1, - 83, 74, 84, 255, 157, 8, 69, 6, 146, 205, 8, 78, 202, 160, 8, 84, 159, 2, - 73, 4, 44, 5, 73, 68, 69, 32, 65, 131, 208, 8, 72, 2, 253, 142, 1, 2, 82, - 67, 210, 1, 172, 1, 5, 65, 82, 82, 79, 87, 174, 5, 66, 70, 72, 134, 4, - 84, 178, 2, 87, 226, 207, 8, 68, 210, 1, 70, 222, 7, 76, 26, 79, 34, 80, - 50, 82, 70, 83, 230, 191, 8, 67, 47, 81, 73, 26, 32, 143, 215, 17, 45, - 68, 102, 65, 138, 1, 84, 132, 2, 5, 87, 73, 84, 72, 32, 198, 209, 8, 70, - 181, 149, 10, 4, 79, 86, 69, 82, 12, 44, 5, 66, 79, 86, 69, 32, 179, 211, - 8, 78, 10, 64, 4, 83, 72, 79, 82, 170, 210, 8, 82, 142, 226, 4, 65, 55, - 84, 2, 143, 233, 18, 84, 12, 56, 7, 72, 82, 79, 85, 71, 72, 32, 53, 3, - 79, 32, 66, 6, 142, 178, 13, 83, 202, 196, 4, 76, 247, 145, 2, 88, 6, 32, - 2, 65, 82, 187, 212, 8, 76, 5, 169, 158, 12, 23, 32, 79, 86, 69, 82, 32, - 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 65, 82, 82, 79, 87, 32, 36, - 118, 76, 154, 212, 8, 68, 182, 1, 80, 30, 83, 38, 84, 178, 195, 8, 77, - 38, 78, 122, 69, 226, 151, 1, 72, 143, 163, 1, 86, 4, 158, 153, 17, 65, - 219, 243, 1, 79, 8, 190, 214, 8, 65, 224, 10, 5, 79, 84, 84, 79, 77, 207, - 185, 8, 76, 30, 26, 65, 255, 159, 17, 69, 26, 48, 6, 82, 80, 79, 79, 78, - 32, 183, 190, 19, 78, 24, 100, 10, 87, 73, 84, 72, 32, 66, 65, 82, 66, - 32, 209, 216, 8, 9, 79, 86, 69, 82, 32, 82, 73, 71, 72, 22, 40, 4, 68, - 79, 87, 78, 117, 2, 85, 80, 10, 26, 32, 219, 165, 17, 87, 8, 222, 217, 8, - 66, 188, 2, 7, 65, 66, 79, 86, 69, 32, 82, 222, 193, 8, 70, 179, 5, 84, - 12, 26, 32, 231, 164, 17, 87, 10, 60, 6, 65, 66, 79, 86, 69, 32, 198, - 156, 17, 70, 179, 5, 84, 6, 42, 76, 201, 217, 8, 4, 82, 73, 71, 72, 4, - 238, 215, 8, 69, 199, 218, 4, 79, 54, 44, 2, 82, 73, 190, 221, 8, 79, - 159, 5, 87, 34, 44, 5, 65, 78, 71, 76, 69, 243, 225, 8, 80, 30, 56, 8, - 45, 72, 69, 65, 68, 69, 68, 32, 227, 170, 17, 32, 28, 52, 5, 65, 82, 82, - 79, 87, 178, 163, 17, 68, 39, 80, 25, 11, 32, 22, 180, 222, 8, 9, 79, 86, - 69, 82, 32, 82, 73, 71, 72, 22, 87, 251, 192, 8, 84, 6, 26, 72, 131, 228, - 8, 65, 4, 45, 9, 73, 84, 69, 32, 65, 82, 82, 79, 87, 5, 149, 168, 17, 2, - 32, 87, 5, 143, 231, 18, 80, 148, 1, 252, 1, 15, 67, 79, 78, 83, 79, 78, - 65, 78, 84, 32, 83, 73, 71, 78, 32, 124, 7, 76, 69, 84, 84, 69, 82, 32, - 236, 1, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 198, 1, 83, - 172, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 251, 132, 18, 68, - 18, 66, 75, 22, 78, 154, 251, 19, 76, 2, 77, 2, 80, 2, 82, 3, 84, 5, 179, - 170, 19, 65, 5, 233, 201, 12, 4, 89, 73, 78, 45, 78, 194, 1, 75, 2, 80, - 190, 148, 7, 68, 194, 219, 10, 66, 2, 70, 2, 71, 2, 72, 2, 77, 138, 15, - 78, 194, 178, 1, 84, 46, 67, 2, 83, 138, 69, 74, 2, 76, 2, 82, 2, 86, 2, - 87, 2, 89, 187, 2, 65, 6, 246, 246, 19, 72, 2, 76, 187, 2, 65, 10, 82, - 84, 40, 14, 78, 89, 69, 84, 32, 84, 72, 89, 79, 79, 77, 32, 84, 65, 43, - 67, 6, 38, 65, 21, 5, 83, 72, 79, 79, 75, 2, 179, 248, 6, 45, 5, 17, 2, - 32, 67, 2, 217, 134, 15, 3, 69, 82, 45, 8, 92, 4, 73, 71, 78, 32, 37, 15, - 85, 66, 74, 79, 73, 78, 69, 68, 32, 76, 69, 84, 84, 69, 82, 4, 130, 227, - 15, 78, 227, 201, 2, 82, 4, 11, 32, 4, 250, 243, 19, 82, 3, 89, 14, 238, - 162, 16, 85, 202, 141, 1, 79, 170, 195, 2, 65, 186, 2, 69, 3, 73, 52, - 138, 1, 65, 128, 4, 11, 69, 81, 85, 65, 76, 32, 84, 79, 32, 79, 82, 200, - 1, 2, 66, 85, 42, 67, 186, 1, 79, 210, 2, 87, 231, 227, 18, 83, 16, 40, - 5, 66, 79, 86, 69, 32, 171, 4, 78, 12, 152, 1, 7, 71, 82, 69, 65, 84, 69, - 82, 110, 83, 176, 1, 19, 68, 79, 85, 66, 76, 69, 45, 76, 73, 78, 69, 32, - 69, 81, 85, 65, 76, 32, 65, 227, 212, 15, 76, 2, 181, 5, 23, 45, 84, 72, - 65, 78, 32, 65, 66, 79, 86, 69, 32, 68, 79, 85, 66, 76, 69, 45, 76, 73, - 78, 69, 6, 152, 1, 7, 73, 77, 73, 76, 65, 82, 32, 93, 26, 76, 65, 78, 84, - 69, 68, 32, 69, 81, 85, 65, 76, 32, 65, 66, 79, 86, 69, 32, 71, 82, 69, - 65, 84, 69, 82, 4, 18, 65, 59, 79, 2, 25, 4, 66, 79, 86, 69, 2, 169, 222, - 17, 2, 32, 71, 2, 227, 2, 82, 2, 145, 2, 6, 45, 84, 72, 65, 78, 32, 4, - 17, 2, 68, 32, 4, 220, 3, 5, 78, 79, 84, 32, 65, 245, 151, 13, 11, 83, - 73, 78, 71, 76, 69, 45, 76, 73, 78, 69, 4, 241, 249, 12, 5, 84, 32, 78, - 79, 84, 4, 65, 14, 76, 79, 83, 69, 68, 32, 66, 89, 32, 67, 85, 82, 86, - 69, 5, 11, 32, 2, 61, 13, 65, 66, 79, 86, 69, 32, 83, 76, 65, 78, 84, 69, - 68, 2, 17, 2, 32, 69, 2, 251, 228, 14, 81, 18, 40, 2, 82, 32, 141, 220, - 11, 2, 86, 69, 16, 114, 65, 48, 16, 83, 76, 65, 78, 84, 69, 68, 32, 69, - 81, 85, 65, 76, 32, 84, 79, 218, 246, 12, 69, 223, 226, 4, 71, 2, 173, - 184, 9, 7, 80, 80, 82, 79, 88, 73, 77, 9, 49, 10, 32, 87, 73, 84, 72, 32, - 68, 79, 84, 32, 6, 26, 65, 163, 199, 11, 73, 4, 25, 4, 66, 79, 86, 69, 5, - 231, 153, 18, 32, 6, 25, 4, 73, 84, 72, 32, 6, 66, 67, 40, 8, 81, 85, 69, - 83, 84, 73, 79, 78, 143, 153, 19, 68, 2, 249, 197, 11, 5, 73, 82, 67, 76, - 69, 2, 17, 2, 32, 77, 2, 17, 2, 65, 82, 2, 151, 236, 18, 75, 136, 11, - 190, 1, 71, 186, 5, 77, 166, 7, 78, 168, 65, 2, 80, 83, 20, 3, 83, 85, - 32, 238, 199, 15, 82, 136, 35, 11, 86, 82, 69, 32, 84, 79, 85, 82, 78, - 79, 73, 210, 59, 79, 242, 219, 1, 90, 187, 82, 66, 44, 26, 65, 57, 2, 72, - 84, 2, 245, 167, 9, 9, 84, 85, 82, 69, 32, 79, 80, 69, 78, 42, 38, 32, - 137, 4, 4, 78, 73, 78, 71, 36, 146, 1, 69, 38, 70, 126, 82, 40, 3, 76, - 69, 70, 86, 83, 42, 84, 188, 198, 7, 3, 66, 76, 85, 138, 156, 9, 87, 250, - 41, 86, 250, 77, 71, 135, 69, 67, 2, 129, 209, 17, 4, 73, 71, 72, 84, 8, - 94, 73, 205, 157, 18, 17, 79, 85, 82, 32, 80, 79, 73, 78, 84, 69, 68, 32, - 66, 76, 65, 67, 75, 4, 149, 205, 17, 2, 86, 69, 4, 36, 3, 73, 71, 72, - 155, 176, 17, 65, 2, 165, 237, 1, 16, 84, 32, 84, 79, 82, 84, 79, 73, 83, - 69, 32, 83, 72, 69, 76, 76, 6, 170, 236, 16, 72, 138, 98, 65, 43, 73, 4, - 200, 153, 16, 2, 87, 69, 21, 3, 72, 82, 69, 7, 29, 5, 32, 77, 79, 79, 68, - 5, 155, 149, 8, 32, 138, 1, 80, 3, 66, 85, 32, 137, 157, 8, 11, 73, 84, - 69, 68, 32, 76, 73, 65, 66, 73, 76, 136, 1, 128, 1, 7, 76, 69, 84, 84, - 69, 82, 32, 222, 1, 83, 200, 2, 5, 86, 79, 87, 69, 76, 194, 206, 12, 69, - 182, 188, 4, 81, 247, 95, 68, 60, 170, 1, 71, 242, 139, 6, 84, 170, 221, - 8, 89, 186, 132, 1, 78, 162, 169, 3, 83, 82, 66, 2, 67, 2, 68, 2, 74, 2, - 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 3, 87, 6, 254, 148, 18, 89, - 202, 199, 1, 72, 187, 2, 65, 32, 108, 4, 73, 71, 78, 32, 128, 1, 12, 77, - 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 181, 250, 6, 2, 85, 66, 8, - 72, 3, 75, 69, 77, 0, 3, 77, 85, 75, 32, 2, 83, 65, 207, 149, 17, 76, 2, - 129, 154, 17, 3, 80, 72, 82, 2, 155, 201, 19, 45, 18, 174, 235, 15, 78, - 186, 172, 3, 65, 194, 66, 75, 2, 76, 2, 77, 2, 80, 2, 82, 3, 84, 20, 84, - 6, 32, 83, 73, 71, 78, 32, 177, 85, 10, 45, 67, 65, 82, 82, 73, 69, 82, - 32, 76, 18, 170, 211, 5, 65, 166, 194, 11, 79, 194, 133, 2, 69, 162, 64, - 73, 3, 85, 226, 8, 22, 69, 199, 64, 75, 222, 8, 34, 32, 177, 3, 3, 65, - 82, 32, 14, 120, 12, 73, 78, 84, 69, 71, 82, 65, 84, 73, 79, 78, 32, 186, - 156, 13, 70, 150, 143, 3, 83, 245, 147, 1, 4, 84, 65, 66, 85, 6, 108, 5, - 87, 73, 84, 72, 32, 157, 1, 17, 78, 79, 84, 32, 73, 78, 67, 76, 85, 68, - 73, 78, 71, 32, 84, 72, 69, 4, 76, 7, 82, 69, 67, 84, 65, 78, 71, 1, 8, - 83, 69, 77, 73, 67, 73, 82, 67, 2, 73, 16, 85, 76, 65, 82, 32, 80, 65, - 84, 72, 32, 65, 82, 79, 85, 78, 68, 2, 17, 2, 32, 80, 2, 223, 178, 18, - 79, 208, 8, 60, 8, 65, 32, 83, 73, 71, 78, 32, 65, 221, 24, 2, 66, 32, - 170, 5, 122, 49, 86, 51, 202, 2, 52, 214, 1, 53, 158, 4, 54, 142, 3, 55, - 148, 4, 2, 56, 48, 78, 66, 213, 136, 18, 3, 48, 50, 56, 6, 128, 188, 12, - 5, 48, 48, 45, 49, 48, 200, 221, 5, 2, 50, 48, 233, 19, 2, 51, 49, 150, - 1, 78, 48, 90, 49, 130, 1, 55, 246, 156, 14, 50, 2, 51, 2, 52, 2, 53, 3, - 54, 22, 178, 1, 57, 214, 210, 19, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, - 2, 55, 3, 56, 24, 90, 51, 214, 210, 19, 48, 2, 49, 2, 50, 2, 52, 2, 53, - 2, 54, 2, 55, 2, 56, 3, 57, 6, 210, 210, 19, 65, 2, 66, 3, 67, 4, 174, - 210, 19, 48, 3, 49, 38, 18, 48, 91, 49, 20, 162, 1, 48, 2, 49, 2, 50, 2, - 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 18, 74, 48, 2, 49, 2, 50, - 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 2, 205, 178, 6, 2, 45, 86, 160, - 1, 102, 48, 78, 49, 62, 51, 86, 52, 70, 53, 86, 54, 206, 11, 50, 150, - 166, 2, 57, 198, 229, 11, 55, 3, 56, 16, 210, 207, 19, 49, 2, 50, 2, 51, - 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 12, 134, 207, 19, 48, 2, 49, 2, 50, 2, - 51, 2, 53, 3, 54, 18, 202, 206, 19, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, - 54, 2, 55, 2, 56, 3, 57, 14, 246, 205, 19, 48, 2, 49, 2, 50, 2, 53, 2, - 55, 2, 56, 3, 57, 18, 178, 205, 19, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, - 53, 2, 54, 2, 55, 3, 57, 12, 222, 204, 19, 51, 2, 52, 2, 53, 2, 54, 2, - 56, 3, 57, 104, 70, 48, 78, 50, 86, 51, 38, 52, 78, 54, 162, 146, 14, 53, - 243, 1, 49, 16, 218, 203, 19, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, - 56, 3, 57, 18, 142, 203, 19, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, - 55, 2, 56, 3, 57, 6, 186, 202, 19, 52, 2, 55, 3, 56, 16, 150, 202, 19, - 48, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 10, 202, 201, 19, - 48, 2, 49, 2, 50, 2, 51, 3, 52, 44, 86, 48, 134, 2, 49, 196, 252, 1, 2, - 51, 50, 177, 184, 17, 6, 50, 54, 32, 69, 89, 89, 26, 110, 57, 142, 219, - 8, 55, 182, 6, 50, 62, 54, 230, 62, 52, 226, 151, 3, 51, 110, 56, 134, - 206, 2, 49, 147, 117, 53, 10, 26, 45, 131, 190, 18, 32, 8, 96, 2, 50, 32, - 200, 169, 12, 3, 54, 32, 76, 184, 2, 3, 52, 32, 76, 201, 164, 3, 3, 51, - 32, 76, 2, 163, 173, 12, 76, 14, 110, 49, 22, 51, 32, 3, 52, 32, 65, 0, - 2, 53, 32, 238, 154, 4, 50, 238, 199, 4, 48, 241, 235, 6, 2, 55, 32, 2, - 167, 185, 18, 32, 2, 11, 32, 2, 175, 142, 12, 79, 2, 179, 137, 18, 66, - 16, 130, 197, 19, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 55, - 162, 1, 22, 48, 155, 5, 49, 140, 1, 82, 49, 54, 50, 118, 51, 62, 52, 78, - 53, 86, 54, 62, 55, 70, 56, 151, 136, 14, 48, 10, 194, 195, 19, 48, 2, - 49, 2, 51, 2, 54, 3, 55, 28, 86, 49, 2, 50, 146, 77, 51, 170, 245, 18, - 48, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 7, 182, 194, 19, 70, 3, 77, 12, - 154, 194, 19, 48, 2, 49, 2, 52, 2, 55, 2, 56, 3, 57, 16, 222, 193, 19, - 48, 2, 49, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 18, 146, 193, 19, - 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 12, 190, 192, - 19, 48, 2, 49, 2, 53, 2, 54, 2, 55, 3, 57, 14, 130, 192, 19, 48, 2, 51, - 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 12, 190, 191, 19, 48, 2, 49, 2, 50, 2, - 53, 2, 54, 3, 55, 22, 82, 50, 36, 2, 51, 49, 30, 56, 214, 160, 12, 49, - 206, 2, 54, 146, 1, 55, 3, 57, 6, 174, 190, 19, 48, 2, 50, 3, 51, 4, 138, - 190, 19, 65, 3, 66, 4, 238, 189, 19, 48, 3, 56, 166, 3, 116, 9, 73, 68, - 69, 79, 71, 82, 65, 77, 32, 216, 17, 10, 77, 79, 78, 79, 71, 82, 65, 77, - 32, 66, 249, 1, 2, 83, 89, 234, 1, 54, 66, 249, 15, 8, 86, 69, 83, 83, - 69, 76, 32, 66, 176, 1, 22, 49, 255, 10, 50, 126, 86, 48, 210, 3, 50, - 162, 1, 51, 86, 52, 122, 53, 114, 54, 146, 1, 55, 118, 56, 71, 57, 28, - 114, 53, 98, 54, 58, 55, 78, 56, 62, 57, 192, 133, 7, 3, 50, 32, 87, 138, - 88, 48, 225, 156, 11, 4, 52, 32, 68, 69, 6, 168, 132, 7, 2, 32, 69, 196, - 149, 11, 3, 70, 32, 77, 129, 80, 7, 77, 32, 83, 84, 65, 76, 76, 4, 152, - 240, 1, 3, 70, 32, 69, 177, 142, 16, 2, 77, 32, 4, 36, 3, 70, 32, 83, 1, - 2, 77, 32, 2, 145, 225, 11, 4, 72, 69, 45, 71, 4, 188, 152, 9, 3, 77, 32, - 66, 237, 133, 9, 3, 70, 32, 83, 4, 208, 176, 17, 4, 77, 32, 66, 85, 157, - 109, 3, 70, 32, 67, 10, 196, 145, 9, 4, 51, 32, 83, 80, 240, 10, 5, 49, - 32, 66, 65, 82, 220, 231, 4, 4, 50, 32, 79, 76, 20, 6, 53, 32, 67, 89, - 80, 69, 245, 98, 4, 48, 32, 87, 72, 6, 54, 49, 172, 130, 17, 3, 48, 32, - 79, 215, 179, 2, 50, 2, 197, 156, 18, 2, 32, 87, 10, 224, 5, 3, 53, 32, - 87, 204, 143, 9, 6, 48, 32, 66, 82, 79, 78, 172, 2, 4, 49, 32, 71, 79, - 138, 158, 10, 50, 3, 54, 16, 82, 57, 214, 232, 2, 49, 198, 203, 16, 48, - 2, 50, 2, 51, 2, 52, 2, 55, 3, 56, 2, 169, 97, 3, 32, 67, 76, 20, 248, - 160, 14, 5, 51, 32, 65, 82, 77, 204, 207, 4, 5, 50, 32, 71, 65, 82, 182, - 67, 48, 2, 49, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 18, 134, 242, - 13, 54, 200, 190, 3, 4, 51, 32, 77, 79, 158, 130, 2, 48, 2, 49, 2, 50, 2, - 52, 2, 55, 2, 56, 3, 57, 14, 246, 177, 19, 48, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 3, 57, 4, 164, 164, 2, 3, 49, 32, 72, 143, 141, 17, 48, 50, - 42, 50, 110, 51, 130, 1, 52, 227, 1, 53, 4, 84, 8, 48, 32, 70, 79, 79, - 84, 83, 84, 169, 210, 6, 7, 53, 32, 66, 65, 84, 72, 84, 2, 143, 157, 18, - 79, 12, 104, 4, 51, 32, 83, 87, 156, 255, 13, 4, 48, 32, 83, 80, 146, - 149, 4, 49, 214, 154, 1, 50, 2, 52, 3, 54, 2, 147, 152, 18, 79, 16, 168, - 1, 9, 48, 32, 87, 72, 69, 69, 76, 69, 68, 2, 49, 34, 51, 168, 158, 17, - 12, 50, 32, 67, 72, 65, 82, 73, 79, 84, 32, 70, 82, 250, 142, 2, 53, 2, - 54, 2, 56, 3, 57, 2, 185, 163, 18, 3, 32, 67, 72, 2, 247, 190, 6, 32, 18, - 236, 165, 18, 3, 52, 32, 68, 158, 135, 1, 49, 2, 50, 2, 51, 2, 53, 2, 54, - 2, 55, 2, 56, 3, 57, 58, 50, 50, 192, 144, 12, 2, 49, 53, 1, 2, 51, 48, - 54, 50, 50, 238, 146, 12, 53, 150, 227, 1, 48, 3, 49, 12, 186, 171, 19, + 84, 73, 80, 234, 186, 20, 87, 219, 26, 77, 6, 44, 5, 76, 65, 67, 75, 32, + 251, 238, 21, 85, 4, 146, 146, 22, 68, 227, 27, 83, 4, 252, 212, 20, 8, + 69, 82, 32, 66, 79, 65, 82, 68, 183, 186, 2, 32, 2, 221, 238, 20, 2, 32, + 76, 18, 144, 1, 6, 73, 78, 84, 69, 82, 82, 22, 76, 170, 250, 11, 80, 230, + 184, 4, 69, 244, 198, 1, 2, 79, 72, 204, 158, 2, 4, 85, 78, 68, 69, 183, + 97, 81, 2, 207, 217, 4, 79, 6, 60, 9, 79, 87, 32, 75, 65, 86, 89, 75, 65, + 163, 235, 6, 65, 5, 229, 162, 18, 11, 32, 87, 73, 84, 72, 32, 75, 65, 86, + 89, 75, 6, 38, 84, 178, 194, 19, 80, 223, 89, 83, 2, 159, 181, 16, 73, 4, + 246, 177, 22, 69, 215, 93, 73, 218, 1, 94, 65, 138, 21, 69, 62, 79, 42, + 85, 157, 195, 11, 10, 73, 71, 83, 65, 87, 32, 80, 85, 90, 90, 202, 1, + 120, 5, 67, 75, 45, 79, 45, 32, 7, 80, 65, 78, 69, 83, 69, 32, 184, 2, 7, + 86, 65, 78, 69, 83, 69, 32, 207, 200, 23, 82, 2, 169, 184, 18, 3, 76, 65, + 78, 16, 246, 1, 67, 18, 80, 152, 157, 1, 10, 73, 78, 68, 85, 83, 84, 82, + 73, 65, 76, 236, 229, 3, 3, 66, 65, 78, 134, 174, 3, 68, 220, 143, 11, + 15, 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 66, 69, 71, 73, 180, 248, + 1, 3, 71, 79, 66, 169, 109, 2, 79, 71, 2, 207, 32, 65, 2, 165, 145, 13, + 7, 79, 83, 84, 32, 79, 70, 70, 182, 1, 172, 2, 15, 67, 79, 78, 83, 79, + 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 76, 2, 76, 69, 40, 4, 82, 73, 71, + 72, 224, 6, 2, 80, 65, 176, 3, 14, 84, 85, 82, 78, 69, 68, 32, 80, 65, + 68, 65, 32, 80, 73, 88, 5, 83, 73, 71, 78, 32, 144, 1, 11, 86, 79, 87, + 69, 76, 32, 83, 73, 71, 78, 32, 167, 197, 21, 68, 6, 52, 2, 75, 69, 188, + 201, 16, 2, 80, 69, 175, 5, 67, 2, 199, 144, 23, 82, 96, 38, 70, 65, 5, + 84, 84, 69, 82, 32, 2, 41, 8, 84, 32, 82, 69, 82, 69, 78, 71, 2, 219, + 248, 21, 71, 94, 230, 1, 68, 26, 73, 48, 2, 75, 65, 66, 78, 130, 1, 66, + 2, 67, 2, 71, 16, 2, 80, 65, 56, 2, 82, 65, 32, 2, 83, 65, 42, 84, 74, + 74, 218, 178, 21, 65, 142, 138, 2, 72, 2, 76, 2, 77, 2, 87, 2, 89, 186, + 2, 69, 2, 79, 3, 85, 8, 222, 3, 68, 15, 65, 7, 184, 205, 5, 3, 32, 75, + 65, 171, 245, 17, 73, 7, 11, 32, 4, 22, 83, 215, 2, 77, 2, 133, 137, 21, + 2, 65, 83, 14, 36, 2, 71, 65, 90, 89, 167, 1, 65, 7, 33, 6, 32, 76, 69, + 76, 69, 84, 5, 29, 5, 32, 82, 65, 83, 87, 2, 159, 230, 5, 65, 4, 163, 1, + 65, 7, 11, 32, 4, 154, 1, 77, 153, 188, 23, 3, 67, 69, 82, 5, 237, 204, + 16, 3, 32, 65, 71, 7, 17, 2, 32, 77, 4, 70, 85, 71, 65, 8, 18, 65, 55, + 84, 5, 17, 2, 32, 77, 2, 11, 85, 2, 171, 154, 23, 82, 4, 11, 65, 5, 11, + 32, 2, 11, 77, 2, 11, 65, 2, 11, 72, 2, 237, 185, 17, 2, 65, 80, 28, 40, + 3, 68, 65, 32, 165, 3, 2, 78, 71, 24, 174, 1, 65, 90, 76, 86, 80, 244, + 150, 7, 10, 84, 73, 82, 84, 65, 32, 84, 85, 77, 69, 158, 135, 12, 87, + 168, 199, 2, 7, 73, 83, 69, 78, 45, 73, 83, 169, 211, 1, 3, 77, 65, 68, + 6, 44, 3, 68, 69, 71, 177, 169, 22, 2, 78, 68, 5, 11, 32, 2, 193, 246, + 22, 2, 65, 68, 6, 38, 85, 165, 185, 23, 3, 73, 78, 71, 4, 240, 200, 18, + 2, 78, 71, 163, 250, 3, 72, 4, 38, 73, 205, 193, 18, 3, 65, 78, 71, 2, + 181, 197, 16, 3, 83, 69, 76, 4, 140, 153, 13, 5, 82, 65, 78, 71, 75, 251, + 209, 9, 75, 10, 108, 5, 67, 69, 67, 65, 75, 248, 205, 5, 3, 87, 73, 71, + 202, 246, 10, 76, 249, 228, 2, 5, 80, 65, 78, 89, 65, 5, 157, 176, 18, 3, + 32, 84, 69, 18, 116, 4, 83, 85, 75, 85, 42, 84, 64, 4, 87, 85, 76, 85, + 142, 195, 16, 80, 137, 224, 1, 7, 68, 73, 82, 71, 65, 32, 77, 5, 225, + 190, 22, 5, 32, 77, 69, 78, 68, 6, 26, 65, 203, 196, 16, 79, 4, 178, 196, + 16, 82, 187, 162, 6, 76, 5, 25, 4, 32, 77, 69, 76, 2, 151, 180, 23, 73, + 4, 36, 3, 76, 76, 89, 203, 239, 19, 65, 2, 167, 210, 19, 70, 4, 192, 132, + 22, 2, 89, 83, 191, 98, 73, 6, 196, 200, 14, 2, 71, 71, 194, 135, 5, 80, + 191, 199, 3, 78, 188, 25, 74, 65, 178, 78, 69, 218, 1, 72, 162, 50, 73, + 198, 6, 78, 50, 79, 111, 82, 202, 10, 200, 1, 5, 73, 84, 72, 73, 32, 234, + 4, 78, 188, 45, 6, 84, 65, 75, 65, 78, 65, 208, 13, 3, 87, 73, 32, 220, + 8, 7, 89, 65, 72, 32, 76, 73, 32, 224, 201, 4, 6, 75, 84, 79, 86, 73, 75, + 135, 244, 17, 65, 136, 1, 204, 1, 7, 76, 69, 84, 84, 69, 82, 32, 178, 2, + 83, 150, 116, 68, 228, 243, 3, 2, 86, 79, 236, 137, 3, 11, 78, 85, 77, + 66, 69, 82, 32, 83, 73, 71, 78, 162, 202, 9, 65, 189, 211, 1, 6, 69, 78, + 85, 77, 69, 82, 90, 214, 1, 68, 190, 210, 19, 65, 150, 1, 84, 230, 5, 85, + 186, 202, 1, 73, 138, 196, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, + 75, 2, 80, 2, 82, 138, 69, 72, 2, 76, 2, 77, 2, 86, 2, 89, 186, 2, 69, 3, + 79, 10, 38, 68, 210, 173, 23, 72, 187, 2, 65, 6, 222, 178, 21, 68, 242, + 250, 1, 72, 187, 2, 65, 12, 40, 4, 73, 71, 78, 32, 179, 156, 11, 69, 10, + 202, 145, 19, 67, 98, 78, 138, 216, 3, 65, 239, 1, 86, 232, 4, 42, 71, + 241, 39, 5, 78, 65, 68, 65, 32, 174, 3, 76, 11, 88, 73, 32, 82, 65, 68, + 73, 67, 65, 76, 32, 249, 226, 20, 2, 65, 82, 172, 3, 130, 2, 65, 94, 66, + 230, 2, 67, 150, 2, 68, 158, 3, 69, 198, 1, 70, 138, 2, 71, 146, 1, 72, + 210, 2, 73, 76, 2, 74, 65, 34, 75, 30, 76, 230, 1, 77, 254, 1, 78, 62, + 79, 102, 80, 110, 82, 166, 1, 83, 230, 6, 84, 226, 2, 86, 50, 87, 210, 2, + 89, 207, 251, 21, 85, 10, 56, 2, 82, 82, 198, 252, 21, 71, 202, 104, 78, + 207, 47, 88, 4, 138, 173, 22, 79, 207, 1, 73, 34, 58, 65, 38, 73, 46, 76, + 54, 79, 102, 82, 207, 220, 21, 69, 4, 242, 202, 5, 77, 183, 142, 14, 68, + 6, 158, 240, 21, 84, 238, 115, 82, 163, 70, 71, 6, 210, 239, 19, 79, 170, + 136, 2, 65, 179, 155, 1, 85, 10, 62, 76, 226, 140, 23, 65, 218, 5, 78, + 142, 5, 68, 203, 17, 87, 2, 253, 219, 3, 4, 84, 32, 79, 70, 6, 42, 73, + 158, 248, 9, 65, 155, 197, 11, 85, 2, 219, 255, 13, 83, 28, 58, 65, 70, + 76, 74, 79, 206, 181, 10, 72, 183, 129, 11, 73, 6, 38, 85, 154, 139, 23, + 82, 219, 5, 86, 2, 141, 128, 22, 2, 76, 68, 8, 42, 65, 190, 190, 7, 73, + 167, 210, 14, 79, 4, 250, 166, 23, 78, 3, 87, 10, 130, 130, 22, 82, 148, + 2, 2, 77, 80, 222, 100, 86, 134, 5, 76, 235, 56, 87, 34, 38, 69, 38, 73, + 98, 79, 195, 1, 82, 4, 242, 160, 21, 65, 159, 204, 1, 69, 8, 38, 83, 226, + 128, 14, 86, 175, 2, 80, 4, 208, 192, 19, 5, 84, 73, 78, 71, 85, 207, + 228, 3, 72, 16, 94, 84, 76, 3, 85, 66, 76, 138, 130, 13, 87, 252, 208, 9, + 2, 32, 78, 222, 23, 79, 223, 56, 71, 7, 25, 4, 84, 69, 68, 32, 4, 168, + 187, 7, 3, 67, 76, 73, 155, 165, 15, 84, 2, 175, 134, 4, 69, 6, 242, 232, + 21, 65, 222, 169, 1, 85, 219, 16, 89, 20, 106, 65, 38, 78, 32, 3, 86, 69, + 78, 140, 131, 9, 6, 77, 66, 82, 79, 73, 68, 250, 243, 13, 73, 243, 19, + 89, 6, 170, 233, 16, 82, 227, 184, 6, 84, 4, 178, 25, 67, 203, 202, 22, + 84, 5, 207, 208, 22, 73, 28, 74, 65, 50, 73, 62, 76, 38, 82, 170, 20, 69, + 250, 186, 22, 79, 223, 23, 85, 6, 146, 255, 13, 84, 130, 139, 9, 67, 131, + 22, 78, 8, 234, 240, 12, 69, 150, 133, 10, 71, 230, 19, 82, 199, 21, 83, + 4, 230, 214, 21, 85, 151, 201, 1, 89, 4, 180, 239, 21, 2, 65, 71, 207, + 175, 1, 79, 14, 58, 79, 52, 2, 82, 65, 190, 176, 19, 72, 239, 164, 2, 65, + 7, 206, 216, 22, 76, 241, 34, 5, 32, 83, 76, 79, 87, 4, 218, 206, 22, 73, + 135, 18, 83, 22, 58, 65, 142, 1, 69, 60, 5, 73, 68, 73, 78, 71, 19, 79, + 8, 38, 76, 154, 215, 22, 78, 199, 13, 73, 4, 34, 70, 165, 132, 22, 2, 66, + 69, 2, 41, 8, 32, 84, 82, 69, 69, 32, 84, 82, 2, 135, 184, 19, 85, 6, 26, + 65, 175, 156, 23, 77, 4, 138, 128, 23, 82, 175, 28, 68, 2, 195, 19, 32, + 6, 26, 82, 215, 152, 23, 79, 4, 150, 133, 23, 83, 215, 22, 78, 6, 26, 78, + 223, 132, 23, 67, 4, 26, 83, 135, 154, 23, 67, 2, 135, 138, 22, 69, 4, + 170, 132, 23, 68, 215, 22, 82, 2, 133, 179, 5, 2, 78, 73, 22, 46, 65, 34, + 69, 78, 73, 41, 3, 79, 78, 71, 4, 190, 131, 23, 77, 191, 19, 67, 8, 38, + 65, 242, 219, 22, 71, 199, 58, 69, 4, 246, 247, 13, 84, 215, 161, 9, 70, + 6, 210, 130, 23, 70, 2, 78, 215, 22, 68, 5, 153, 204, 11, 3, 32, 83, 84, + 22, 42, 69, 34, 73, 46, 79, 139, 200, 22, 65, 4, 198, 200, 22, 76, 195, + 51, 65, 4, 128, 243, 11, 2, 78, 73, 139, 195, 9, 76, 12, 34, 82, 34, 85, + 199, 199, 22, 79, 4, 134, 244, 21, 84, 187, 82, 78, 6, 26, 78, 251, 149, + 23, 84, 4, 158, 232, 21, 84, 235, 174, 1, 68, 6, 26, 79, 159, 250, 22, + 69, 4, 242, 255, 22, 83, 215, 22, 84, 10, 40, 2, 78, 69, 22, 80, 203, + 207, 22, 76, 5, 199, 157, 6, 83, 4, 190, 178, 10, 80, 247, 193, 2, 69, + 10, 54, 82, 230, 248, 21, 76, 166, 1, 79, 179, 154, 1, 73, 4, 148, 207, + 12, 2, 73, 86, 181, 141, 7, 2, 79, 70, 18, 62, 65, 42, 73, 234, 173, 10, + 79, 170, 150, 12, 85, 195, 9, 69, 6, 182, 196, 22, 73, 226, 79, 80, 3, + 84, 6, 156, 242, 12, 3, 71, 72, 84, 230, 227, 9, 86, 155, 39, 67, 74, + 170, 1, 65, 86, 67, 54, 69, 62, 72, 178, 1, 73, 46, 76, 62, 80, 106, 84, + 142, 245, 17, 87, 158, 159, 1, 78, 234, 64, 79, 130, 174, 1, 77, 226, + 103, 81, 130, 35, 75, 247, 47, 85, 6, 144, 195, 3, 9, 67, 82, 73, 70, 73, + 67, 73, 65, 76, 202, 178, 19, 76, 175, 28, 89, 4, 224, 246, 10, 2, 82, + 73, 249, 218, 5, 2, 72, 79, 8, 170, 210, 21, 67, 134, 51, 65, 174, 10, + 76, 167, 129, 1, 69, 10, 18, 69, 39, 79, 4, 222, 132, 22, 76, 199, 139, + 1, 69, 6, 40, 4, 82, 84, 32, 84, 183, 243, 22, 79, 4, 44, 5, 65, 73, 76, + 69, 68, 207, 133, 16, 72, 2, 201, 138, 21, 2, 32, 66, 4, 184, 247, 17, 2, + 67, 75, 195, 148, 5, 76, 6, 26, 65, 211, 209, 22, 73, 4, 246, 247, 22, + 86, 199, 21, 83, 10, 50, 69, 34, 73, 190, 148, 19, 82, 179, 169, 3, 79, + 4, 154, 213, 22, 65, 183, 22, 69, 2, 159, 241, 22, 82, 12, 34, 69, 34, + 79, 239, 252, 21, 65, 4, 198, 252, 22, 65, 219, 16, 80, 6, 26, 80, 147, + 246, 22, 78, 5, 223, 187, 22, 80, 30, 82, 65, 98, 73, 34, 79, 38, 82, 52, + 2, 85, 82, 32, 2, 87, 79, 167, 186, 22, 69, 6, 38, 78, 154, 229, 21, 66, + 239, 26, 76, 2, 33, 6, 78, 69, 68, 32, 76, 69, 2, 207, 233, 13, 65, 4, + 174, 205, 22, 71, 155, 39, 76, 4, 146, 251, 18, 78, 243, 138, 2, 79, 6, + 190, 240, 16, 73, 150, 232, 4, 65, 179, 155, 1, 69, 4, 134, 190, 21, 66, + 227, 37, 84, 5, 187, 199, 19, 32, 4, 254, 220, 12, 65, 209, 157, 5, 3, + 73, 76, 76, 26, 58, 65, 110, 69, 42, 72, 32, 2, 73, 78, 30, 79, 39, 82, + 6, 32, 2, 76, 75, 247, 202, 22, 84, 5, 11, 32, 2, 11, 69, 2, 17, 2, 78, + 67, 2, 237, 243, 17, 2, 76, 79, 4, 168, 184, 22, 2, 65, 80, 195, 51, 83, + 4, 218, 190, 21, 73, 231, 63, 69, 4, 206, 135, 23, 68, 3, 69, 4, 150, + 187, 21, 77, 135, 201, 1, 82, 4, 150, 182, 22, 79, 239, 80, 65, 2, 141, + 229, 20, 2, 69, 76, 186, 1, 92, 2, 76, 69, 148, 2, 5, 83, 73, 71, 78, 32, + 170, 207, 17, 65, 186, 9, 86, 247, 182, 3, 68, 110, 44, 5, 84, 84, 69, + 82, 32, 219, 195, 22, 78, 108, 190, 214, 17, 78, 142, 209, 1, 65, 38, 68, + 46, 76, 38, 82, 34, 84, 46, 86, 186, 5, 85, 206, 141, 1, 79, 238, 60, 73, + 182, 196, 1, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 162, 7, 69, + 234, 61, 70, 2, 72, 2, 77, 3, 89, 22, 94, 67, 138, 1, 83, 246, 228, 18, + 78, 190, 66, 65, 190, 158, 1, 74, 150, 3, 85, 235, 245, 1, 86, 4, 100, + 19, 79, 77, 66, 73, 78, 73, 78, 71, 32, 65, 78, 85, 83, 86, 65, 82, 65, + 32, 65, 195, 228, 18, 65, 2, 173, 253, 19, 3, 66, 79, 86, 4, 216, 198, + 12, 6, 80, 65, 67, 73, 78, 71, 255, 143, 5, 73, 162, 2, 62, 32, 173, 11, + 10, 45, 72, 73, 82, 65, 71, 65, 78, 65, 32, 154, 2, 140, 1, 7, 76, 69, + 84, 84, 69, 82, 32, 242, 9, 86, 232, 130, 19, 10, 68, 73, 71, 82, 65, 80, + 72, 32, 75, 79, 238, 204, 1, 73, 191, 146, 1, 77, 146, 2, 186, 1, 65, + 178, 1, 66, 106, 77, 186, 2, 78, 54, 83, 226, 1, 68, 2, 71, 2, 72, 2, 75, + 2, 80, 2, 82, 2, 84, 2, 86, 2, 90, 126, 87, 46, 89, 150, 246, 22, 69, 2, + 73, 2, 79, 3, 85, 19, 60, 4, 73, 78, 85, 32, 45, 7, 82, 67, 72, 65, 73, + 67, 32, 8, 130, 7, 84, 138, 224, 22, 67, 215, 22, 80, 8, 38, 89, 166, + 216, 22, 87, 235, 36, 69, 4, 138, 253, 22, 69, 3, 73, 20, 50, 73, 190, + 252, 22, 65, 2, 69, 2, 79, 3, 85, 13, 253, 4, 9, 68, 65, 75, 85, 79, 78, + 32, 78, 71, 36, 50, 73, 214, 251, 22, 65, 2, 69, 2, 79, 3, 85, 29, 29, 5, + 78, 78, 65, 78, 32, 26, 96, 15, 78, 65, 83, 65, 76, 73, 90, 69, 68, 32, + 84, 79, 78, 69, 45, 69, 5, 84, 79, 78, 69, 45, 14, 206, 250, 22, 49, 2, + 50, 2, 51, 2, 52, 2, 53, 2, 55, 3, 56, 12, 138, 250, 22, 50, 2, 51, 2, + 52, 2, 53, 2, 55, 3, 56, 13, 206, 249, 22, 65, 2, 69, 2, 73, 2, 79, 3, + 85, 76, 76, 5, 77, 65, 76, 76, 32, 206, 248, 22, 65, 2, 69, 2, 73, 2, 79, + 3, 85, 66, 142, 1, 72, 2, 82, 54, 75, 46, 84, 30, 87, 46, 89, 154, 159, + 19, 78, 198, 150, 3, 83, 210, 27, 77, 234, 36, 65, 2, 69, 2, 73, 2, 79, + 3, 85, 10, 186, 247, 22, 65, 2, 69, 2, 73, 2, 79, 3, 85, 8, 134, 247, 22, + 65, 2, 69, 2, 79, 3, 85, 4, 218, 246, 22, 79, 3, 85, 8, 190, 246, 22, 65, + 2, 69, 2, 73, 3, 79, 6, 146, 246, 22, 65, 2, 79, 3, 85, 2, 189, 207, 20, + 5, 79, 73, 67, 69, 68, 8, 52, 5, 68, 79, 85, 66, 76, 22, 80, 38, 83, 35, + 86, 2, 251, 128, 8, 69, 2, 89, 6, 82, 79, 76, 79, 78, 71, 2, 29, 5, 69, + 77, 73, 45, 86, 2, 21, 3, 79, 73, 67, 2, 33, 6, 69, 68, 32, 83, 79, 85, + 2, 223, 167, 22, 78, 174, 1, 216, 1, 7, 76, 69, 84, 84, 69, 82, 32, 128, + 2, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 148, 3, 5, 83, 73, + 71, 78, 32, 88, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 162, 171, + 12, 68, 151, 224, 6, 67, 94, 226, 1, 65, 198, 166, 4, 74, 146, 236, 14, + 68, 114, 84, 230, 5, 85, 22, 86, 166, 202, 1, 73, 138, 196, 1, 78, 46, + 83, 82, 66, 2, 67, 2, 71, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, + 2, 87, 2, 89, 186, 2, 69, 3, 79, 7, 162, 240, 22, 65, 3, 73, 22, 122, 67, + 90, 68, 58, 70, 54, 83, 20, 12, 65, 76, 84, 69, 82, 78, 65, 84, 69, 32, + 83, 69, 237, 217, 21, 4, 84, 82, 73, 80, 4, 56, 8, 76, 79, 83, 73, 78, + 71, 32, 83, 199, 154, 21, 73, 2, 229, 226, 21, 2, 80, 73, 4, 11, 79, 4, + 220, 218, 21, 2, 85, 66, 203, 147, 1, 84, 4, 200, 153, 21, 5, 73, 76, 76, + 69, 68, 163, 57, 76, 6, 18, 69, 23, 80, 2, 187, 245, 10, 67, 4, 140, 151, + 4, 2, 65, 67, 171, 202, 17, 73, 12, 222, 226, 7, 75, 182, 236, 10, 67, + 98, 78, 238, 64, 82, 170, 162, 1, 86, 247, 244, 1, 65, 20, 66, 65, 246, + 164, 4, 86, 234, 239, 14, 69, 2, 85, 187, 202, 1, 73, 6, 240, 233, 16, 8, + 76, 84, 69, 82, 78, 65, 84, 69, 230, 129, 6, 65, 3, 73, 96, 148, 1, 7, + 76, 69, 84, 84, 69, 82, 32, 200, 1, 5, 83, 73, 71, 78, 32, 44, 5, 84, 79, + 78, 69, 32, 92, 6, 86, 79, 87, 69, 76, 32, 159, 243, 20, 68, 56, 138, + 206, 18, 79, 186, 7, 72, 158, 151, 2, 78, 214, 181, 1, 75, 2, 80, 2, 83, + 2, 84, 138, 69, 66, 2, 67, 2, 68, 2, 71, 2, 76, 2, 77, 2, 82, 2, 86, 2, + 87, 2, 89, 2, 90, 186, 2, 65, 3, 73, 4, 130, 243, 4, 67, 205, 242, 17, 2, + 83, 72, 6, 36, 5, 67, 65, 76, 89, 65, 23, 80, 5, 17, 2, 32, 80, 2, 249, + 240, 17, 3, 76, 79, 80, 10, 130, 167, 22, 69, 2, 85, 163, 64, 79, 36, 24, + 2, 76, 86, 23, 89, 2, 215, 234, 20, 73, 35, 68, 5, 66, 79, 65, 82, 68, + 36, 4, 67, 65, 80, 32, 243, 245, 2, 72, 5, 193, 157, 19, 4, 32, 65, 78, + 68, 26, 166, 154, 17, 78, 138, 180, 3, 65, 170, 35, 68, 135, 30, 84, 188, + 13, 202, 1, 65, 224, 9, 18, 73, 84, 65, 78, 32, 83, 77, 65, 76, 76, 32, + 83, 67, 82, 73, 80, 84, 32, 204, 3, 4, 77, 69, 82, 32, 204, 25, 5, 79, + 74, 75, 73, 32, 141, 6, 8, 85, 68, 65, 87, 65, 68, 73, 32, 138, 1, 56, 8, + 82, 79, 83, 72, 84, 72, 73, 32, 147, 190, 22, 78, 136, 1, 220, 1, 4, 68, + 73, 71, 73, 20, 7, 76, 69, 84, 84, 69, 82, 32, 144, 2, 7, 78, 85, 77, 66, + 69, 82, 32, 36, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 136, + 2, 5, 83, 73, 71, 78, 32, 210, 1, 86, 159, 201, 8, 70, 8, 243, 146, 16, + 84, 74, 182, 1, 75, 42, 84, 218, 140, 7, 78, 150, 245, 11, 68, 194, 149, + 3, 83, 82, 66, 2, 67, 2, 71, 2, 80, 2, 86, 138, 69, 72, 2, 74, 2, 76, 2, + 77, 2, 82, 2, 89, 2, 90, 187, 2, 65, 6, 170, 221, 22, 72, 2, 75, 187, 2, + 65, 12, 218, 130, 19, 84, 170, 218, 3, 72, 187, 2, 65, 8, 186, 215, 14, + 84, 243, 170, 2, 79, 18, 70, 67, 74, 68, 66, 76, 36, 5, 77, 65, 78, 71, + 65, 163, 136, 21, 83, 4, 26, 82, 251, 137, 21, 73, 2, 173, 186, 21, 6, + 69, 83, 67, 69, 78, 84, 6, 26, 79, 199, 253, 18, 65, 4, 142, 253, 18, 85, + 175, 224, 3, 84, 4, 214, 227, 6, 79, 247, 195, 7, 73, 2, 227, 159, 21, + 76, 12, 72, 2, 66, 65, 22, 67, 20, 2, 68, 79, 130, 162, 20, 86, 247, 244, + 1, 65, 2, 143, 223, 21, 82, 2, 167, 154, 6, 65, 4, 44, 5, 85, 66, 76, 69, + 32, 167, 170, 20, 84, 2, 21, 3, 82, 73, 78, 2, 139, 170, 20, 71, 14, 44, + 5, 79, 87, 69, 76, 32, 199, 158, 20, 73, 12, 44, 5, 83, 73, 71, 78, 32, + 183, 152, 22, 76, 10, 202, 147, 4, 86, 230, 198, 18, 69, 2, 73, 2, 79, 3, + 85, 176, 7, 72, 12, 67, 72, 65, 82, 65, 67, 84, 69, 82, 45, 49, 56, 147, + 207, 7, 70, 174, 7, 22, 66, 147, 1, 67, 128, 4, 142, 254, 7, 48, 2, 49, + 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, + 67, 2, 68, 2, 69, 3, 70, 174, 3, 142, 1, 68, 242, 251, 7, 48, 2, 49, 2, + 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, + 211, 217, 13, 70, 12, 226, 214, 22, 48, 2, 49, 2, 50, 2, 51, 2, 52, 3, + 53, 246, 2, 202, 1, 67, 240, 2, 18, 73, 78, 68, 69, 80, 69, 78, 68, 69, + 78, 84, 32, 86, 79, 87, 69, 76, 32, 220, 2, 7, 76, 69, 84, 84, 69, 82, + 32, 254, 2, 83, 208, 12, 6, 86, 79, 87, 69, 76, 32, 187, 203, 20, 68, 70, + 176, 1, 20, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 67, + 79, 69, 78, 71, 32, 245, 189, 17, 17, 85, 82, 82, 69, 78, 67, 89, 32, 83, + 89, 77, 66, 79, 76, 32, 82, 73, 68, 138, 1, 78, 154, 4, 67, 2, 75, 90, + 80, 74, 84, 54, 68, 2, 76, 158, 132, 22, 83, 158, 41, 77, 2, 82, 2, 86, + 2, 89, 190, 28, 66, 3, 72, 8, 162, 179, 22, 71, 2, 89, 246, 30, 65, 3, + 79, 42, 82, 81, 196, 1, 11, 83, 73, 71, 78, 32, 67, 79, 69, 78, 71, 32, + 50, 76, 3, 82, 26, 82, 65, 44, 6, 79, 79, 32, 84, 89, 80, 34, 85, 178, + 195, 20, 73, 199, 140, 2, 69, 8, 190, 208, 22, 65, 2, 73, 2, 81, 3, 85, + 4, 11, 69, 4, 199, 149, 10, 32, 9, 166, 192, 7, 85, 207, 143, 15, 75, 8, + 18, 81, 31, 82, 4, 186, 207, 22, 69, 3, 85, 4, 131, 190, 18, 89, 70, 138, + 1, 67, 2, 75, 42, 78, 50, 80, 30, 83, 46, 84, 54, 68, 2, 76, 186, 173, + 22, 77, 2, 82, 2, 86, 2, 89, 190, 28, 66, 2, 72, 3, 81, 8, 210, 1, 72, + 174, 204, 22, 65, 3, 79, 8, 226, 174, 22, 71, 2, 78, 2, 89, 247, 30, 79, + 6, 122, 72, 175, 204, 22, 79, 6, 150, 174, 22, 83, 190, 28, 72, 187, 2, + 65, 12, 50, 72, 0, 2, 84, 72, 174, 204, 22, 65, 3, 79, 4, 170, 204, 22, + 65, 3, 79, 130, 1, 60, 4, 73, 71, 78, 32, 221, 6, 6, 89, 77, 66, 79, 76, + 32, 46, 202, 2, 65, 104, 10, 83, 65, 77, 89, 79, 75, 32, 83, 65, 78, 22, + 66, 118, 67, 86, 75, 74, 82, 54, 84, 188, 229, 4, 3, 76, 69, 75, 168, 11, + 6, 80, 72, 78, 65, 69, 75, 224, 232, 10, 10, 89, 85, 85, 75, 65, 76, 69, + 65, 80, 73, 244, 243, 1, 3, 78, 73, 75, 236, 171, 3, 9, 77, 85, 85, 83, + 73, 75, 65, 84, 79, 141, 15, 4, 86, 73, 82, 73, 6, 100, 9, 86, 65, 75, + 82, 65, 72, 65, 83, 65, 232, 145, 18, 4, 84, 84, 72, 65, 173, 145, 4, 2, + 72, 83, 2, 187, 197, 22, 78, 8, 38, 65, 129, 188, 21, 3, 69, 89, 89, 6, + 174, 6, 84, 216, 1, 2, 78, 84, 185, 243, 20, 6, 82, 73, 89, 79, 79, 83, + 4, 248, 155, 7, 12, 65, 77, 78, 85, 67, 32, 80, 73, 73, 32, 75, 85, 183, + 228, 12, 79, 6, 188, 221, 11, 2, 65, 75, 226, 156, 9, 72, 205, 82, 4, 79, + 79, 77, 85, 4, 130, 221, 11, 79, 137, 235, 5, 4, 69, 65, 72, 77, 4, 180, + 178, 21, 4, 82, 73, 73, 83, 217, 9, 8, 79, 65, 78, 68, 65, 75, 72, 73, + 84, 128, 1, 3, 68, 65, 80, 92, 10, 76, 69, 75, 32, 65, 84, 84, 65, 75, + 32, 182, 1, 80, 72, 5, 84, 85, 84, 69, 89, 78, 66, 47, 77, 24, 22, 45, + 223, 3, 32, 20, 30, 80, 238, 2, 66, 47, 77, 8, 138, 3, 73, 37, 3, 82, 65, + 77, 20, 50, 80, 98, 66, 186, 150, 11, 77, 219, 219, 10, 83, 12, 36, 3, + 82, 65, 77, 223, 174, 22, 73, 11, 11, 45, 8, 42, 66, 186, 150, 11, 77, + 251, 228, 8, 80, 4, 142, 242, 21, 85, 151, 60, 69, 26, 44, 2, 65, 84, 44, + 3, 82, 65, 77, 91, 73, 2, 21, 3, 72, 65, 77, 2, 175, 190, 16, 65, 20, 18, + 45, 119, 32, 16, 34, 66, 32, 2, 80, 73, 15, 77, 8, 30, 69, 37, 3, 85, 79, + 78, 4, 35, 73, 4, 21, 3, 85, 79, 89, 4, 11, 32, 4, 34, 82, 189, 138, 22, + 2, 75, 79, 2, 195, 149, 21, 79, 42, 76, 10, 73, 78, 72, 69, 82, 69, 78, + 84, 32, 65, 29, 5, 83, 73, 71, 78, 32, 4, 238, 190, 22, 65, 3, 81, 38, + 102, 65, 54, 73, 30, 79, 38, 89, 216, 254, 2, 5, 67, 79, 69, 78, 71, 182, + 172, 7, 85, 239, 145, 12, 69, 10, 194, 180, 3, 65, 170, 137, 19, 69, 2, + 73, 3, 85, 7, 182, 189, 22, 69, 3, 73, 6, 154, 189, 22, 69, 2, 77, 3, 79, + 7, 246, 188, 22, 65, 3, 89, 130, 1, 146, 1, 68, 88, 7, 76, 69, 84, 84, + 69, 82, 32, 170, 2, 83, 160, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, + 78, 32, 238, 237, 15, 87, 231, 85, 65, 6, 48, 6, 79, 85, 66, 76, 69, 32, + 155, 219, 18, 65, 4, 134, 168, 10, 83, 135, 179, 8, 68, 90, 234, 1, 83, + 254, 4, 66, 42, 71, 146, 141, 6, 68, 166, 145, 12, 74, 182, 55, 65, 150, + 1, 84, 198, 208, 1, 76, 226, 195, 1, 78, 126, 67, 2, 75, 2, 80, 138, 69, + 72, 2, 77, 2, 81, 2, 82, 2, 86, 2, 89, 186, 2, 69, 2, 73, 2, 79, 3, 85, + 4, 26, 72, 231, 184, 22, 65, 2, 209, 248, 21, 3, 79, 82, 84, 12, 40, 4, + 73, 71, 78, 32, 159, 165, 10, 69, 10, 54, 83, 226, 154, 18, 78, 154, 67, + 86, 243, 148, 3, 65, 4, 26, 72, 251, 179, 17, 85, 2, 11, 65, 2, 179, 146, + 22, 68, 18, 190, 240, 3, 86, 198, 239, 14, 65, 222, 202, 1, 73, 198, 140, + 2, 69, 2, 79, 3, 85, 138, 1, 100, 7, 76, 69, 84, 84, 69, 82, 32, 176, 2, + 5, 83, 73, 71, 78, 32, 230, 194, 16, 86, 203, 252, 3, 68, 94, 222, 1, 66, + 42, 71, 146, 141, 6, 68, 254, 143, 12, 74, 222, 56, 65, 118, 82, 34, 84, + 230, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, 126, 67, 2, 75, 2, 80, 2, + 83, 138, 69, 72, 2, 76, 2, 77, 2, 86, 2, 89, 186, 2, 69, 3, 79, 6, 202, + 177, 22, 66, 2, 72, 187, 2, 65, 6, 162, 177, 22, 71, 2, 72, 187, 2, 65, + 6, 178, 150, 18, 78, 154, 67, 86, 243, 148, 3, 65, 136, 1, 140, 1, 8, 82, + 65, 84, 32, 82, 65, 73, 32, 216, 3, 2, 83, 83, 208, 247, 20, 4, 87, 73, + 70, 82, 202, 47, 80, 240, 93, 2, 77, 79, 191, 18, 84, 116, 140, 1, 7, 76, + 69, 84, 84, 69, 82, 32, 172, 1, 5, 83, 73, 71, 78, 32, 92, 11, 86, 79, + 87, 69, 76, 32, 83, 73, 71, 78, 32, 223, 237, 11, 68, 64, 142, 211, 18, + 68, 114, 84, 206, 223, 1, 78, 214, 181, 1, 66, 2, 67, 2, 71, 2, 74, 2, + 75, 2, 80, 2, 83, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 86, 2, 89, 187, 2, + 65, 12, 184, 209, 9, 3, 84, 79, 78, 0, 2, 89, 85, 190, 252, 1, 83, 198, + 156, 10, 65, 239, 1, 86, 16, 182, 215, 18, 65, 130, 151, 3, 85, 162, 64, + 69, 2, 73, 3, 79, 13, 40, 4, 73, 78, 71, 32, 183, 236, 21, 32, 8, 96, 4, + 70, 65, 67, 69, 177, 147, 14, 14, 67, 65, 84, 32, 70, 65, 67, 69, 32, 87, + 73, 84, 72, 32, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 158, 146, 14, 83, + 159, 155, 5, 67, 4, 232, 167, 18, 3, 69, 69, 76, 171, 232, 3, 79, 4, 40, + 4, 82, 69, 65, 78, 207, 137, 22, 65, 2, 33, 6, 32, 83, 84, 65, 78, 68, 2, + 193, 250, 18, 2, 65, 82, 2, 11, 79, 2, 171, 169, 10, 78, 200, 43, 154, 1, + 65, 178, 233, 1, 69, 198, 62, 73, 226, 83, 79, 206, 33, 85, 94, 89, 138, + 226, 7, 82, 232, 195, 9, 5, 32, 66, 32, 66, 65, 142, 163, 1, 76, 239, 66, + 70, 134, 23, 142, 1, 66, 44, 6, 67, 82, 79, 83, 83, 69, 46, 68, 58, 78, + 64, 2, 79, 32, 222, 11, 82, 236, 21, 4, 83, 84, 32, 81, 77, 4, 84, 73, + 78, 32, 4, 228, 194, 14, 2, 32, 67, 155, 218, 6, 69, 2, 137, 255, 16, 6, + 32, 83, 84, 73, 67, 75, 4, 148, 255, 12, 5, 89, 32, 66, 69, 69, 247, 234, + 8, 68, 4, 178, 202, 9, 68, 161, 241, 10, 7, 71, 85, 65, 71, 69, 32, 84, + 174, 1, 200, 2, 3, 72, 79, 32, 28, 7, 76, 69, 84, 84, 69, 82, 32, 214, 5, + 83, 148, 1, 9, 84, 79, 78, 69, 32, 77, 65, 73, 32, 84, 11, 86, 79, 87, + 69, 76, 32, 83, 73, 71, 78, 32, 228, 170, 4, 2, 75, 79, 224, 130, 13, 2, + 89, 65, 230, 199, 2, 69, 170, 51, 68, 212, 138, 1, 7, 67, 65, 78, 67, 69, + 76, 76, 221, 68, 6, 78, 73, 71, 71, 65, 72, 4, 186, 133, 22, 77, 3, 78, + 94, 176, 1, 3, 70, 79, 32, 78, 75, 96, 2, 76, 79, 50, 80, 154, 1, 83, 86, + 84, 30, 72, 162, 161, 16, 78, 234, 222, 5, 66, 2, 67, 2, 68, 2, 77, 2, + 82, 2, 87, 2, 89, 247, 30, 79, 8, 42, 70, 250, 174, 15, 83, 175, 182, 5, + 84, 4, 210, 210, 21, 79, 155, 62, 65, 10, 26, 72, 251, 161, 22, 79, 8, + 32, 3, 77, 85, 32, 231, 2, 79, 4, 142, 201, 21, 78, 211, 57, 71, 7, 17, + 2, 32, 76, 4, 166, 208, 21, 73, 67, 79, 30, 52, 4, 65, 76, 73, 32, 210, + 1, 72, 255, 158, 22, 79, 24, 230, 200, 6, 68, 34, 84, 206, 6, 78, 210, + 211, 13, 66, 2, 67, 2, 71, 2, 74, 147, 219, 1, 76, 8, 52, 9, 65, 78, 83, + 75, 82, 73, 84, 32, 83, 71, 79, 4, 250, 156, 22, 72, 3, 83, 6, 26, 72, + 255, 158, 22, 79, 4, 11, 79, 4, 11, 32, 4, 166, 171, 15, 83, 175, 182, 5, + 84, 6, 112, 14, 69, 77, 73, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, + 209, 195, 18, 8, 73, 71, 78, 32, 80, 65, 76, 73, 4, 134, 197, 21, 78, + 211, 57, 76, 8, 50, 84, 132, 163, 17, 2, 67, 65, 223, 246, 4, 69, 4, 130, + 254, 21, 72, 247, 30, 73, 32, 106, 65, 44, 5, 77, 65, 73, 32, 75, 166, + 138, 18, 89, 162, 58, 85, 186, 202, 1, 69, 2, 73, 199, 140, 2, 79, 11, + 234, 155, 22, 65, 2, 73, 2, 77, 3, 89, 4, 222, 203, 21, 65, 3, 79, 166, + 1, 32, 2, 71, 69, 255, 147, 21, 73, 164, 1, 26, 32, 171, 251, 13, 82, + 160, 1, 254, 1, 66, 44, 4, 71, 82, 69, 69, 22, 79, 250, 1, 84, 190, 242, + 11, 68, 36, 2, 85, 80, 164, 193, 3, 12, 76, 69, 70, 84, 32, 84, 82, 73, + 65, 78, 71, 76, 200, 203, 4, 5, 80, 85, 82, 80, 76, 12, 3, 82, 69, 68, 0, + 6, 89, 69, 76, 76, 79, 87, 179, 66, 67, 10, 40, 3, 82, 79, 87, 201, 1, 2, + 76, 85, 4, 227, 129, 20, 78, 10, 48, 3, 78, 69, 32, 129, 1, 4, 82, 65, + 78, 71, 4, 240, 161, 8, 5, 68, 79, 84, 32, 79, 133, 234, 2, 18, 82, 73, + 78, 71, 32, 79, 86, 69, 82, 32, 84, 87, 79, 32, 82, 73, 78, 71, 6, 11, + 69, 6, 11, 32, 6, 178, 194, 20, 67, 162, 21, 68, 155, 28, 83, 116, 156, + 1, 3, 87, 79, 32, 108, 10, 89, 80, 69, 32, 80, 73, 69, 67, 69, 32, 197, + 208, 18, 17, 82, 73, 80, 76, 69, 32, 86, 69, 82, 84, 73, 67, 65, 76, 32, + 66, 65, 4, 242, 241, 17, 68, 141, 93, 19, 82, 73, 78, 71, 83, 32, 79, 86, + 69, 82, 32, 79, 78, 69, 32, 82, 73, 78, 71, 110, 182, 1, 67, 136, 2, 9, + 68, 73, 65, 71, 79, 78, 65, 76, 32, 218, 1, 76, 186, 2, 82, 158, 1, 83, + 204, 3, 6, 85, 80, 80, 69, 82, 32, 145, 2, 9, 86, 69, 82, 84, 69, 88, 32, + 79, 70, 14, 80, 9, 69, 78, 84, 82, 69, 32, 79, 70, 32, 73, 7, 82, 79, 83, + 83, 66, 65, 82, 8, 252, 8, 6, 90, 32, 87, 73, 84, 72, 138, 137, 22, 75, + 2, 88, 3, 89, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 40, 3, 76, 79, 87, 1, + 3, 85, 80, 80, 2, 137, 205, 10, 2, 69, 82, 12, 48, 6, 85, 80, 80, 69, 82, + 32, 167, 230, 9, 76, 8, 56, 4, 76, 69, 70, 84, 225, 230, 9, 4, 82, 73, + 71, 72, 5, 11, 32, 2, 21, 3, 65, 78, 68, 2, 17, 2, 32, 76, 2, 17, 2, 79, + 87, 2, 209, 220, 21, 2, 69, 82, 26, 48, 5, 79, 87, 69, 82, 32, 129, 3, 2, + 69, 70, 24, 84, 5, 76, 69, 70, 84, 32, 56, 6, 82, 73, 71, 72, 84, 32, + 158, 6, 72, 179, 1, 84, 8, 22, 65, 207, 7, 67, 4, 194, 1, 78, 135, 226, + 20, 82, 10, 22, 65, 151, 7, 67, 6, 192, 1, 13, 78, 68, 32, 85, 80, 80, + 69, 82, 32, 82, 73, 71, 72, 249, 211, 19, 2, 82, 67, 4, 44, 4, 65, 73, + 83, 69, 77, 3, 73, 71, 72, 2, 53, 11, 68, 32, 85, 80, 80, 69, 82, 32, 76, + 69, 70, 2, 231, 139, 19, 84, 2, 137, 141, 21, 3, 84, 32, 65, 34, 48, 5, + 72, 79, 82, 84, 32, 77, 3, 84, 69, 77, 4, 40, 3, 76, 79, 87, 1, 3, 85, + 80, 80, 2, 217, 4, 4, 69, 82, 32, 84, 31, 44, 6, 32, 87, 73, 84, 72, 32, + 171, 1, 45, 8, 44, 5, 76, 69, 70, 84, 32, 30, 82, 59, 67, 4, 82, 67, 199, + 221, 10, 74, 2, 21, 3, 73, 71, 72, 2, 11, 84, 2, 17, 2, 32, 67, 2, 169, + 229, 20, 4, 82, 79, 83, 83, 20, 48, 2, 49, 50, 22, 50, 26, 52, 203, 189, + 11, 51, 5, 183, 223, 14, 51, 9, 11, 51, 7, 11, 52, 5, 239, 135, 22, 53, + 18, 62, 72, 96, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 83, 84, 4, 65, 14, + 65, 76, 70, 32, 86, 69, 82, 84, 69, 88, 32, 79, 70, 32, 4, 214, 134, 22, + 77, 3, 87, 6, 17, 2, 84, 32, 6, 26, 67, 175, 134, 19, 65, 4, 202, 92, 82, + 235, 168, 17, 79, 2, 157, 250, 8, 3, 69, 82, 77, 2, 187, 231, 14, 32, 6, + 53, 11, 85, 65, 82, 84, 69, 82, 32, 77, 79, 79, 78, 7, 223, 240, 6, 32, + 158, 20, 150, 1, 67, 224, 46, 18, 69, 80, 73, 71, 82, 65, 80, 72, 73, 67, + 32, 76, 69, 84, 84, 69, 82, 32, 252, 1, 7, 76, 69, 84, 84, 69, 82, 32, + 247, 12, 83, 206, 7, 56, 8, 65, 80, 73, 84, 65, 76, 32, 76, 243, 191, 20, + 82, 204, 7, 76, 6, 69, 84, 84, 69, 82, 32, 169, 45, 8, 73, 71, 65, 84, + 85, 82, 69, 32, 200, 7, 154, 2, 65, 158, 3, 66, 154, 1, 67, 254, 1, 68, + 186, 2, 69, 174, 2, 70, 82, 71, 194, 1, 72, 146, 1, 73, 154, 2, 74, 118, + 75, 126, 76, 234, 2, 77, 114, 78, 134, 2, 79, 198, 2, 80, 114, 81, 62, + 82, 190, 2, 83, 130, 3, 84, 142, 3, 85, 234, 1, 86, 146, 1, 87, 118, 88, + 50, 89, 167, 1, 90, 93, 172, 1, 6, 32, 87, 73, 84, 72, 32, 166, 1, 69, + 246, 65, 78, 176, 158, 14, 6, 70, 82, 73, 67, 65, 78, 158, 193, 3, 76, + 210, 183, 2, 86, 186, 164, 1, 65, 2, 79, 2, 85, 3, 89, 66, 246, 64, 66, + 34, 68, 108, 3, 82, 73, 78, 242, 33, 77, 250, 21, 67, 150, 50, 72, 158, + 1, 79, 198, 10, 71, 186, 2, 65, 246, 173, 3, 73, 142, 175, 13, 84, 219, + 183, 3, 83, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 206, 184, 1, 65, 239, + 199, 3, 77, 21, 60, 6, 32, 87, 73, 84, 72, 32, 190, 68, 82, 187, 147, 21, + 69, 14, 154, 67, 84, 138, 60, 70, 210, 57, 76, 182, 159, 16, 68, 170, + 206, 2, 72, 247, 165, 1, 83, 33, 108, 6, 32, 87, 73, 84, 72, 32, 204, 70, + 7, 76, 79, 83, 69, 68, 32, 73, 54, 85, 154, 228, 20, 79, 139, 60, 72, 20, + 94, 67, 198, 181, 1, 65, 154, 233, 3, 80, 206, 133, 15, 72, 182, 50, 66, + 242, 34, 68, 211, 80, 83, 8, 198, 68, 69, 190, 113, 73, 227, 156, 19, 65, + 35, 76, 6, 32, 87, 73, 84, 72, 32, 178, 1, 90, 25, 6, 79, 85, 66, 76, 69, + 32, 24, 78, 83, 226, 15, 67, 202, 47, 84, 218, 117, 76, 182, 159, 16, 68, + 171, 206, 2, 72, 8, 92, 13, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, + 32, 90, 150, 138, 1, 72, 235, 189, 20, 84, 5, 209, 72, 2, 32, 87, 4, 254, + 71, 87, 187, 185, 10, 84, 91, 104, 6, 32, 87, 73, 84, 72, 32, 152, 1, 2, + 90, 72, 134, 76, 71, 206, 152, 17, 84, 210, 143, 4, 83, 63, 78, 70, 254, + 73, 67, 158, 2, 68, 194, 16, 84, 158, 23, 77, 250, 1, 86, 238, 45, 72, + 158, 1, 79, 198, 10, 71, 186, 2, 65, 246, 173, 3, 73, 62, 66, 171, 230, + 16, 83, 7, 11, 32, 4, 138, 70, 87, 211, 8, 82, 9, 33, 6, 32, 87, 73, 84, + 72, 32, 6, 242, 158, 20, 72, 166, 85, 68, 211, 80, 83, 35, 76, 6, 32, 87, + 73, 84, 72, 32, 190, 81, 76, 230, 204, 18, 65, 147, 211, 2, 72, 20, 154, + 84, 67, 250, 90, 65, 178, 174, 3, 66, 190, 25, 77, 226, 140, 4, 79, 154, + 154, 11, 72, 166, 85, 68, 211, 80, 83, 29, 76, 6, 32, 87, 73, 84, 72, 32, + 250, 126, 65, 198, 244, 7, 87, 247, 173, 12, 69, 20, 186, 82, 66, 34, 67, + 46, 68, 178, 201, 19, 72, 247, 165, 1, 83, 59, 80, 6, 32, 87, 73, 84, 72, + 32, 132, 88, 2, 78, 83, 198, 244, 20, 79, 207, 36, 83, 40, 138, 1, 68, + 162, 83, 67, 242, 1, 77, 142, 1, 84, 130, 71, 72, 158, 1, 79, 198, 10, + 71, 186, 2, 65, 246, 173, 3, 73, 62, 66, 171, 230, 16, 83, 10, 22, 79, + 191, 83, 73, 6, 218, 121, 85, 131, 212, 18, 84, 11, 33, 6, 32, 87, 73, + 84, 72, 32, 8, 42, 67, 174, 135, 18, 84, 219, 183, 3, 83, 4, 234, 170, 1, + 73, 131, 223, 3, 82, 25, 33, 6, 32, 87, 73, 84, 72, 32, 22, 182, 89, 67, + 34, 68, 50, 83, 222, 79, 65, 138, 1, 76, 198, 211, 7, 79, 155, 154, 11, + 72, 41, 60, 6, 32, 87, 73, 84, 72, 32, 190, 94, 65, 231, 142, 21, 74, 32, + 138, 1, 66, 36, 2, 68, 79, 52, 7, 77, 73, 68, 68, 76, 69, 32, 38, 83, + 174, 2, 67, 182, 91, 72, 230, 72, 65, 138, 1, 76, 251, 219, 16, 84, 4, + 170, 198, 12, 69, 143, 237, 8, 65, 6, 22, 85, 231, 91, 84, 2, 249, 241, + 4, 2, 66, 76, 4, 230, 131, 18, 84, 159, 151, 3, 68, 4, 214, 2, 77, 211, + 184, 21, 84, 19, 44, 6, 32, 87, 73, 84, 72, 32, 207, 94, 73, 10, 242, + 165, 1, 65, 190, 160, 16, 68, 198, 60, 84, 231, 145, 2, 72, 33, 48, 6, + 32, 87, 73, 84, 72, 32, 215, 233, 21, 74, 28, 102, 67, 44, 2, 83, 77, + 178, 96, 76, 134, 65, 71, 186, 2, 65, 102, 68, 234, 211, 7, 79, 183, 136, + 9, 84, 6, 190, 132, 1, 69, 22, 73, 231, 188, 19, 65, 2, 157, 233, 10, 10, + 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 101, 108, 6, 32, 87, 73, 84, 72, + 32, 178, 103, 76, 138, 159, 4, 80, 218, 155, 9, 77, 134, 197, 7, 73, 2, + 79, 3, 85, 84, 144, 1, 2, 76, 79, 34, 77, 226, 96, 67, 70, 68, 154, 2, + 79, 38, 83, 66, 84, 106, 86, 222, 44, 72, 242, 12, 71, 186, 2, 65, 246, + 173, 3, 73, 63, 66, 4, 158, 99, 78, 215, 130, 21, 79, 8, 154, 99, 65, + 235, 159, 4, 73, 19, 44, 6, 32, 87, 73, 84, 72, 32, 155, 23, 72, 14, 242, + 103, 70, 34, 83, 170, 56, 65, 230, 238, 18, 72, 167, 85, 68, 7, 33, 6, + 32, 87, 73, 84, 72, 32, 4, 190, 105, 68, 39, 83, 43, 94, 32, 156, 1, 8, + 69, 86, 69, 82, 83, 69, 68, 32, 216, 111, 3, 85, 77, 32, 167, 147, 4, 65, + 28, 40, 5, 87, 73, 84, 72, 32, 215, 112, 82, 26, 134, 78, 67, 218, 29, + 68, 170, 2, 84, 174, 48, 65, 138, 1, 76, 238, 172, 3, 73, 218, 166, 4, + 79, 143, 192, 12, 83, 8, 218, 110, 72, 154, 156, 4, 79, 186, 199, 13, 67, + 239, 143, 3, 69, 49, 136, 1, 6, 32, 87, 73, 84, 72, 32, 136, 1, 5, 77, + 65, 76, 76, 32, 240, 115, 2, 65, 76, 234, 1, 72, 152, 2, 2, 73, 71, 167, + 138, 4, 67, 32, 86, 67, 138, 112, 65, 118, 68, 138, 1, 83, 174, 1, 86, + 190, 252, 7, 79, 155, 154, 11, 72, 10, 226, 112, 65, 230, 10, 69, 82, 79, + 203, 31, 73, 4, 132, 168, 19, 11, 81, 32, 87, 73, 84, 72, 32, 72, 79, 79, + 75, 173, 247, 1, 7, 67, 65, 80, 73, 84, 65, 76, 59, 136, 1, 6, 32, 87, + 73, 84, 72, 32, 168, 1, 6, 85, 82, 78, 69, 68, 32, 188, 123, 2, 72, 79, + 176, 1, 2, 79, 78, 74, 82, 243, 222, 20, 90, 22, 82, 67, 50, 68, 254, + 152, 1, 76, 234, 237, 3, 82, 246, 255, 14, 72, 247, 165, 1, 83, 8, 202, + 120, 69, 22, 73, 62, 79, 171, 188, 19, 65, 6, 190, 142, 1, 73, 255, 169, + 16, 79, 18, 246, 39, 73, 242, 138, 3, 65, 190, 169, 18, 72, 2, 75, 2, 76, + 2, 77, 2, 84, 3, 86, 79, 26, 32, 183, 135, 5, 80, 74, 44, 5, 87, 73, 84, + 72, 32, 199, 183, 20, 66, 72, 166, 132, 1, 67, 74, 68, 150, 2, 72, 170, + 1, 77, 134, 1, 79, 142, 1, 84, 186, 9, 71, 186, 2, 65, 246, 173, 3, 73, + 62, 66, 234, 225, 14, 82, 195, 132, 2, 83, 23, 88, 6, 32, 87, 73, 84, 72, + 32, 178, 139, 1, 73, 66, 79, 134, 189, 19, 69, 151, 144, 1, 89, 8, 226, + 138, 1, 68, 210, 230, 16, 84, 231, 145, 2, 72, 19, 48, 6, 32, 87, 73, 84, + 72, 32, 243, 151, 7, 89, 14, 190, 144, 1, 67, 18, 68, 70, 71, 186, 2, 65, + 231, 238, 18, 72, 7, 201, 140, 1, 7, 32, 87, 73, 84, 72, 32, 68, 29, 48, + 6, 32, 87, 73, 84, 72, 32, 219, 169, 17, 79, 24, 154, 143, 1, 67, 18, 68, + 70, 71, 22, 72, 42, 76, 254, 1, 65, 238, 199, 3, 77, 150, 149, 13, 84, + 219, 183, 3, 83, 25, 33, 6, 32, 87, 73, 84, 72, 32, 22, 254, 56, 67, 150, + 88, 65, 102, 68, 38, 76, 34, 83, 242, 231, 3, 80, 207, 133, 15, 72, 4, + 254, 213, 10, 73, 195, 232, 10, 79, 12, 128, 1, 5, 65, 82, 67, 72, 65, + 30, 73, 64, 9, 82, 69, 86, 69, 82, 83, 69, 68, 32, 201, 211, 10, 7, 83, + 73, 68, 69, 87, 65, 89, 2, 217, 246, 13, 2, 73, 67, 4, 220, 107, 5, 78, + 86, 69, 82, 84, 149, 216, 14, 3, 32, 76, 79, 4, 142, 211, 21, 70, 3, 80, + 138, 1, 242, 2, 65, 36, 2, 66, 73, 152, 1, 21, 73, 78, 86, 69, 82, 84, + 69, 68, 32, 71, 76, 79, 84, 84, 65, 76, 32, 83, 84, 79, 80, 72, 2, 80, + 72, 16, 2, 82, 69, 222, 1, 83, 132, 8, 3, 84, 87, 79, 182, 20, 87, 128, + 170, 4, 2, 68, 69, 148, 5, 2, 76, 65, 206, 11, 71, 212, 196, 15, 20, 86, + 79, 73, 67, 69, 68, 32, 76, 65, 82, 89, 78, 71, 69, 65, 76, 32, 83, 80, + 73, 199, 119, 89, 4, 230, 187, 4, 76, 183, 196, 16, 73, 6, 76, 7, 76, 65, + 66, 73, 65, 76, 32, 29, 8, 68, 69, 78, 84, 65, 76, 32, 80, 4, 26, 80, + 239, 206, 4, 67, 2, 153, 146, 16, 6, 69, 82, 67, 85, 83, 83, 7, 33, 6, + 32, 87, 73, 84, 72, 32, 4, 234, 243, 4, 67, 183, 170, 16, 83, 2, 207, 81, + 65, 8, 104, 7, 86, 69, 82, 83, 69, 68, 32, 233, 243, 4, 13, 84, 82, 79, + 70, 76, 69, 88, 32, 67, 76, 73, 67, 75, 4, 80, 3, 69, 83, 72, 161, 8, 12, + 71, 76, 79, 84, 84, 65, 76, 32, 83, 84, 79, 80, 2, 213, 133, 1, 2, 32, + 76, 96, 172, 1, 13, 77, 65, 76, 76, 32, 67, 65, 80, 73, 84, 65, 76, 32, + 244, 112, 10, 84, 82, 69, 84, 67, 72, 69, 68, 32, 67, 185, 198, 19, 10, + 73, 78, 79, 76, 79, 71, 73, 67, 65, 76, 90, 230, 1, 69, 30, 73, 22, 76, + 74, 79, 42, 82, 126, 84, 254, 182, 4, 66, 214, 41, 71, 234, 165, 16, 65, + 162, 64, 67, 2, 68, 2, 70, 2, 72, 2, 74, 2, 75, 2, 77, 2, 78, 2, 80, 2, + 81, 2, 83, 2, 85, 2, 86, 2, 87, 2, 89, 3, 90, 7, 226, 199, 21, 84, 3, 90, + 5, 147, 220, 4, 78, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 238, 225, 8, 66, + 183, 182, 12, 83, 9, 238, 95, 80, 142, 232, 20, 69, 3, 85, 11, 92, 8, 69, + 86, 69, 82, 83, 69, 68, 32, 236, 128, 1, 5, 32, 87, 73, 84, 72, 179, 181, + 20, 85, 4, 242, 198, 21, 78, 3, 82, 13, 33, 6, 85, 82, 78, 69, 68, 32, + 10, 178, 198, 21, 69, 2, 71, 2, 75, 2, 77, 3, 82, 186, 11, 136, 1, 5, 77, + 65, 76, 76, 32, 145, 131, 1, 22, 85, 66, 83, 67, 82, 73, 80, 84, 32, 83, + 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 150, 11, 76, 15, 67, 65, + 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 43, 76, 4, 18, 73, 3, + 85, 2, 255, 226, 4, 32, 146, 11, 80, 6, 69, 84, 84, 69, 82, 32, 161, 128, + 1, 8, 73, 71, 65, 84, 85, 82, 69, 32, 128, 11, 182, 2, 65, 190, 5, 66, + 198, 3, 67, 186, 4, 68, 182, 4, 69, 174, 9, 70, 214, 1, 71, 162, 2, 72, + 230, 2, 73, 166, 7, 74, 182, 1, 75, 178, 2, 76, 206, 6, 77, 178, 2, 78, + 218, 3, 79, 242, 8, 80, 218, 2, 81, 174, 1, 82, 142, 8, 83, 250, 10, 84, + 246, 13, 85, 218, 9, 86, 130, 3, 87, 110, 88, 226, 2, 89, 171, 3, 90, + 101, 118, 32, 198, 3, 69, 82, 78, 192, 226, 4, 4, 76, 80, 72, 65, 222, + 180, 15, 86, 186, 164, 1, 65, 2, 79, 2, 85, 3, 89, 72, 88, 5, 87, 73, 84, + 72, 32, 157, 229, 5, 11, 82, 69, 86, 69, 82, 83, 69, 68, 45, 83, 67, 70, + 150, 1, 66, 34, 68, 54, 82, 170, 34, 77, 250, 21, 67, 150, 50, 72, 158, + 1, 79, 198, 10, 71, 186, 2, 65, 246, 173, 3, 73, 142, 175, 13, 84, 219, + 183, 3, 83, 12, 161, 106, 4, 82, 69, 86, 69, 12, 22, 79, 151, 57, 73, 8, + 214, 57, 84, 211, 13, 85, 10, 26, 73, 175, 231, 4, 69, 8, 26, 78, 179, + 174, 4, 71, 6, 17, 2, 71, 32, 6, 236, 58, 4, 65, 66, 79, 86, 251, 223, + 18, 66, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 242, 116, 71, 186, 2, 65, + 239, 199, 3, 77, 2, 181, 198, 10, 7, 71, 76, 73, 67, 65, 78, 65, 41, 140, + 1, 6, 32, 87, 73, 84, 72, 32, 130, 1, 65, 108, 11, 76, 65, 67, 75, 76, + 69, 84, 84, 69, 82, 32, 38, 82, 174, 201, 4, 79, 143, 202, 16, 69, 18, + 110, 84, 138, 60, 70, 210, 57, 76, 230, 224, 3, 77, 174, 7, 80, 166, 183, + 12, 68, 170, 206, 2, 72, 247, 165, 1, 83, 2, 255, 7, 79, 8, 64, 5, 82, + 82, 69, 68, 32, 161, 81, 6, 83, 69, 76, 73, 78, 69, 6, 182, 32, 65, 154, + 152, 21, 69, 3, 79, 6, 242, 195, 4, 79, 183, 244, 16, 69, 2, 181, 186, + 10, 4, 79, 75, 69, 78, 47, 108, 6, 32, 87, 73, 84, 72, 32, 196, 1, 2, 72, + 73, 92, 6, 76, 79, 83, 69, 68, 32, 90, 85, 155, 228, 20, 79, 24, 102, 67, + 182, 113, 65, 154, 233, 3, 80, 218, 5, 82, 246, 255, 14, 72, 182, 50, 66, + 242, 34, 68, 211, 80, 83, 10, 54, 69, 190, 113, 73, 150, 251, 6, 85, 207, + 161, 12, 65, 4, 245, 51, 5, 68, 73, 76, 76, 65, 7, 49, 10, 32, 87, 73, + 84, 72, 32, 76, 79, 87, 32, 4, 162, 107, 82, 45, 4, 76, 69, 70, 84, 8, + 34, 73, 18, 79, 159, 200, 4, 82, 2, 163, 88, 78, 4, 130, 221, 4, 80, 151, + 146, 9, 77, 4, 37, 7, 65, 84, 82, 73, 76, 76, 79, 5, 209, 142, 13, 5, 32, + 87, 73, 84, 72, 73, 96, 6, 32, 87, 73, 84, 72, 32, 182, 1, 69, 34, 79, + 178, 1, 90, 178, 213, 4, 66, 187, 201, 16, 85, 32, 98, 83, 34, 84, 238, + 32, 67, 226, 45, 77, 170, 31, 76, 138, 217, 3, 72, 138, 15, 80, 167, 183, + 12, 68, 4, 134, 68, 72, 235, 189, 20, 84, 4, 26, 79, 215, 209, 19, 65, 2, + 219, 141, 20, 80, 8, 246, 78, 90, 207, 189, 20, 76, 16, 60, 6, 84, 76, + 69, 83, 83, 32, 49, 5, 85, 66, 76, 69, 32, 8, 26, 74, 151, 176, 21, 73, + 7, 167, 198, 4, 32, 8, 42, 87, 142, 202, 4, 82, 175, 239, 5, 84, 2, 163, + 239, 6, 89, 11, 11, 32, 8, 26, 87, 151, 198, 4, 68, 2, 169, 90, 5, 73, + 84, 72, 32, 67, 119, 112, 6, 32, 87, 73, 84, 72, 32, 214, 4, 71, 72, 2, + 78, 71, 68, 2, 83, 72, 164, 1, 2, 90, 72, 159, 150, 17, 84, 76, 182, 1, + 67, 158, 2, 68, 110, 78, 214, 15, 84, 158, 23, 77, 250, 1, 86, 190, 3, + 70, 178, 42, 72, 158, 1, 79, 198, 10, 71, 186, 2, 65, 246, 173, 3, 73, + 62, 66, 194, 64, 82, 235, 165, 16, 83, 24, 92, 6, 69, 68, 73, 76, 76, 65, + 32, 9, 73, 82, 67, 85, 77, 70, 76, 69, 88, 151, 132, 20, 65, 5, 169, 149, + 4, 3, 32, 65, 78, 19, 11, 32, 16, 40, 4, 65, 78, 68, 32, 167, 137, 19, + 66, 14, 162, 86, 67, 130, 2, 72, 226, 11, 71, 186, 2, 65, 238, 199, 3, + 77, 158, 170, 4, 68, 251, 234, 8, 84, 12, 22, 79, 227, 98, 73, 10, 28, 2, + 84, 32, 227, 51, 85, 8, 192, 88, 5, 65, 66, 79, 86, 69, 199, 175, 18, 66, + 2, 131, 154, 14, 79, 4, 157, 134, 7, 13, 89, 80, 84, 79, 76, 79, 71, 73, + 67, 65, 76, 32, 65, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 158, 195, 4, 67, + 231, 9, 80, 13, 33, 6, 32, 87, 73, 84, 72, 32, 10, 88, 10, 68, 79, 85, + 66, 76, 69, 32, 66, 65, 82, 230, 203, 4, 80, 142, 1, 67, 207, 4, 82, 5, + 217, 204, 4, 4, 32, 65, 78, 68, 15, 11, 32, 12, 38, 82, 37, 5, 87, 73, + 84, 72, 32, 2, 157, 150, 14, 4, 69, 86, 69, 82, 10, 54, 67, 178, 202, 4, + 80, 218, 5, 82, 195, 158, 14, 84, 4, 234, 220, 7, 85, 207, 161, 12, 65, + 17, 84, 6, 32, 87, 73, 84, 72, 32, 73, 11, 69, 78, 71, 32, 68, 73, 71, + 82, 65, 80, 72, 10, 134, 194, 4, 77, 174, 7, 80, 206, 133, 15, 72, 166, + 85, 68, 211, 80, 83, 5, 209, 168, 18, 8, 32, 87, 73, 84, 72, 32, 84, 82, + 37, 72, 6, 32, 87, 73, 84, 72, 32, 126, 76, 230, 204, 18, 65, 147, 211, + 2, 72, 22, 218, 3, 67, 250, 90, 65, 178, 174, 3, 66, 190, 25, 77, 174, + 33, 80, 182, 235, 3, 79, 154, 154, 11, 72, 166, 85, 68, 211, 80, 83, 8, + 33, 6, 79, 84, 84, 65, 76, 32, 8, 142, 205, 18, 83, 250, 212, 2, 65, 2, + 73, 3, 85, 39, 140, 1, 6, 32, 87, 73, 84, 72, 32, 150, 45, 65, 232, 25, + 12, 79, 79, 75, 69, 68, 32, 83, 67, 72, 87, 65, 32, 174, 243, 3, 69, 159, + 230, 16, 86, 24, 86, 66, 34, 67, 46, 68, 214, 91, 76, 146, 232, 3, 80, + 206, 133, 15, 72, 247, 165, 1, 83, 2, 205, 147, 13, 3, 82, 69, 86, 6, + 158, 59, 69, 154, 32, 73, 227, 156, 19, 65, 8, 234, 87, 73, 226, 190, 3, + 69, 203, 228, 12, 79, 75, 80, 6, 32, 87, 73, 84, 72, 32, 222, 4, 78, 188, + 1, 2, 79, 84, 135, 152, 21, 83, 48, 178, 1, 67, 34, 68, 210, 1, 77, 64, + 6, 79, 71, 79, 78, 69, 75, 78, 84, 130, 71, 72, 226, 11, 71, 186, 2, 65, + 246, 173, 3, 73, 62, 66, 144, 64, 6, 83, 84, 82, 79, 75, 69, 51, 82, 4, + 210, 88, 73, 227, 156, 19, 65, 14, 18, 73, 47, 79, 4, 217, 26, 7, 65, 69, + 82, 69, 83, 73, 83, 10, 28, 2, 84, 32, 215, 37, 85, 8, 64, 10, 65, 66, + 79, 86, 69, 32, 65, 78, 68, 32, 187, 249, 18, 66, 6, 150, 84, 71, 186, 2, + 65, 131, 221, 16, 84, 4, 29, 5, 65, 67, 82, 79, 78, 5, 217, 36, 4, 32, + 65, 78, 68, 7, 145, 73, 15, 32, 65, 78, 68, 32, 68, 79, 84, 32, 65, 66, + 79, 86, 69, 32, 4, 21, 3, 73, 76, 68, 4, 151, 142, 5, 69, 16, 46, 83, 93, + 7, 86, 69, 82, 84, 69, 68, 32, 12, 29, 5, 85, 76, 65, 82, 32, 12, 238, + 152, 21, 68, 2, 70, 2, 71, 2, 82, 2, 83, 3, 84, 4, 26, 65, 199, 129, 21, + 79, 2, 143, 188, 17, 76, 6, 206, 163, 4, 65, 129, 188, 6, 5, 73, 70, 73, + 69, 68, 13, 33, 6, 32, 87, 73, 84, 72, 32, 10, 94, 67, 148, 180, 4, 13, + 68, 79, 84, 32, 65, 66, 79, 86, 69, 32, 65, 78, 68, 187, 178, 16, 83, 6, + 178, 82, 73, 130, 223, 3, 82, 227, 189, 15, 65, 29, 48, 6, 32, 87, 73, + 84, 72, 32, 175, 147, 21, 82, 24, 98, 67, 34, 68, 50, 83, 222, 79, 65, + 138, 1, 76, 146, 232, 3, 80, 182, 235, 3, 79, 155, 154, 11, 72, 4, 210, + 48, 69, 251, 188, 19, 65, 6, 214, 70, 73, 182, 197, 3, 69, 151, 182, 4, + 79, 4, 29, 5, 84, 82, 79, 75, 69, 5, 161, 25, 6, 32, 65, 78, 68, 32, 68, + 79, 136, 1, 6, 32, 87, 73, 84, 72, 32, 250, 3, 65, 38, 69, 48, 5, 79, 78, + 71, 32, 83, 130, 180, 4, 83, 2, 90, 186, 201, 16, 85, 219, 16, 74, 50, + 178, 1, 66, 86, 67, 56, 2, 68, 79, 100, 3, 77, 73, 68, 130, 2, 72, 230, + 72, 65, 138, 1, 76, 150, 224, 3, 73, 162, 1, 82, 222, 2, 70, 130, 4, 80, + 234, 243, 12, 84, 219, 183, 3, 83, 6, 36, 3, 69, 76, 84, 167, 216, 20, + 65, 5, 193, 181, 4, 6, 32, 65, 78, 68, 32, 80, 8, 166, 44, 69, 22, 73, + 154, 155, 7, 85, 207, 161, 12, 65, 8, 38, 84, 25, 5, 85, 66, 76, 69, 32, + 4, 141, 25, 2, 32, 66, 4, 242, 172, 4, 77, 175, 191, 15, 66, 8, 36, 4, + 68, 76, 69, 32, 207, 44, 45, 6, 186, 167, 17, 84, 210, 150, 3, 82, 79, + 68, 4, 173, 154, 4, 4, 77, 66, 68, 65, 6, 158, 181, 4, 90, 189, 138, 13, + 3, 78, 73, 83, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 18, 68, 35, 72, 4, + 206, 63, 73, 203, 205, 19, 79, 2, 197, 172, 4, 2, 73, 71, 27, 56, 6, 32, + 87, 73, 84, 72, 32, 102, 73, 167, 251, 20, 85, 16, 138, 72, 65, 182, 223, + 3, 67, 186, 2, 77, 174, 7, 80, 166, 183, 12, 68, 198, 60, 84, 231, 145, + 2, 72, 6, 25, 4, 68, 68, 76, 69, 6, 76, 7, 45, 87, 69, 76, 83, 72, 32, + 173, 145, 17, 6, 32, 83, 67, 79, 84, 83, 4, 190, 255, 19, 76, 211, 139, + 1, 86, 49, 58, 32, 216, 2, 2, 71, 32, 130, 247, 20, 85, 219, 16, 74, 40, + 88, 5, 87, 73, 84, 72, 32, 209, 142, 6, 11, 80, 82, 69, 67, 69, 68, 69, + 68, 32, 66, 89, 38, 122, 67, 74, 76, 158, 37, 77, 234, 27, 71, 186, 2, + 65, 102, 68, 182, 232, 3, 80, 218, 5, 82, 222, 229, 3, 79, 183, 136, 9, + 84, 10, 170, 36, 69, 22, 73, 134, 255, 3, 82, 150, 156, 3, 85, 207, 161, + 12, 65, 6, 132, 66, 3, 79, 78, 71, 202, 2, 73, 183, 239, 3, 69, 2, 25, 4, + 87, 73, 84, 72, 2, 177, 224, 17, 5, 32, 84, 73, 76, 68, 115, 116, 6, 32, + 87, 73, 84, 72, 32, 186, 6, 76, 52, 4, 80, 69, 78, 32, 174, 186, 13, 77, + 134, 197, 7, 73, 2, 79, 3, 85, 86, 154, 1, 67, 70, 68, 152, 1, 2, 76, 79, + 86, 77, 46, 79, 38, 83, 66, 84, 106, 86, 222, 44, 72, 242, 12, 71, 186, + 2, 65, 246, 173, 3, 73, 62, 66, 195, 64, 82, 14, 172, 49, 9, 73, 82, 67, + 85, 77, 70, 76, 69, 88, 159, 172, 19, 65, 14, 18, 73, 47, 79, 4, 221, 13, + 7, 65, 69, 82, 69, 83, 73, 83, 10, 22, 84, 171, 47, 85, 6, 11, 32, 6, + 140, 13, 5, 65, 66, 79, 86, 69, 223, 212, 18, 66, 6, 66, 78, 216, 208, + 12, 6, 87, 32, 82, 73, 78, 71, 255, 177, 8, 79, 2, 159, 21, 71, 6, 11, + 65, 6, 189, 2, 4, 67, 82, 79, 78, 4, 217, 11, 5, 71, 79, 78, 69, 75, 4, + 25, 4, 84, 82, 79, 75, 4, 11, 69, 5, 213, 49, 2, 32, 65, 8, 25, 4, 73, + 76, 68, 69, 9, 29, 5, 32, 65, 78, 68, 32, 6, 162, 47, 68, 142, 13, 65, + 239, 199, 3, 77, 6, 81, 18, 69, 82, 84, 73, 67, 65, 76, 32, 76, 73, 78, + 69, 32, 66, 69, 76, 79, 87, 7, 221, 43, 4, 32, 65, 78, 68, 2, 153, 136, + 10, 8, 68, 32, 80, 79, 76, 73, 83, 72, 16, 26, 79, 131, 166, 4, 69, 13, + 48, 6, 32, 87, 73, 84, 72, 32, 227, 254, 20, 69, 8, 210, 55, 71, 186, 2, + 65, 242, 238, 3, 82, 235, 165, 16, 83, 25, 44, 6, 32, 87, 73, 84, 72, 32, + 179, 1, 72, 18, 86, 70, 34, 83, 170, 56, 65, 238, 225, 3, 77, 174, 7, 80, + 206, 133, 15, 72, 167, 85, 68, 2, 153, 196, 14, 3, 76, 79, 85, 6, 210, + 28, 84, 209, 175, 12, 6, 81, 85, 73, 82, 82, 69, 4, 26, 65, 171, 252, 20, + 73, 2, 193, 183, 5, 18, 82, 89, 78, 71, 69, 65, 76, 32, 86, 79, 73, 67, + 69, 68, 32, 70, 82, 73, 13, 48, 6, 32, 87, 73, 84, 72, 32, 139, 161, 4, + 80, 8, 42, 68, 16, 4, 72, 79, 79, 75, 23, 83, 2, 227, 44, 73, 5, 171, + 195, 18, 32, 2, 197, 26, 6, 84, 82, 79, 75, 69, 32, 77, 90, 32, 228, 4, + 8, 69, 86, 69, 82, 83, 69, 68, 32, 148, 2, 2, 85, 77, 179, 147, 4, 65, + 46, 36, 4, 87, 73, 84, 72, 235, 6, 82, 44, 26, 32, 195, 190, 15, 79, 42, + 166, 1, 67, 50, 68, 200, 1, 8, 70, 73, 83, 72, 72, 79, 79, 75, 66, 76, + 34, 84, 142, 18, 77, 162, 30, 65, 246, 173, 3, 73, 166, 59, 80, 182, 235, + 3, 79, 143, 192, 12, 83, 6, 170, 19, 69, 154, 255, 3, 82, 227, 189, 15, + 65, 8, 11, 79, 8, 24, 2, 84, 32, 111, 85, 6, 26, 66, 251, 249, 19, 65, 4, + 25, 4, 69, 76, 79, 87, 5, 29, 5, 32, 65, 78, 68, 32, 2, 191, 249, 3, 77, + 2, 21, 3, 66, 76, 69, 2, 11, 32, 2, 227, 46, 71, 7, 29, 5, 32, 65, 78, + 68, 32, 4, 214, 146, 4, 77, 175, 7, 80, 4, 222, 49, 73, 131, 236, 3, 79, + 4, 238, 215, 18, 73, 195, 61, 65, 22, 162, 1, 72, 40, 6, 79, 80, 69, 78, + 32, 69, 216, 147, 4, 8, 82, 32, 87, 73, 84, 72, 32, 70, 168, 2, 3, 83, + 67, 82, 190, 223, 14, 69, 190, 87, 67, 159, 166, 1, 75, 2, 11, 65, 2, + 253, 250, 9, 2, 76, 70, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 138, 157, 4, + 82, 247, 255, 14, 72, 5, 11, 32, 2, 11, 82, 2, 185, 146, 17, 3, 79, 84, + 85, 85, 180, 1, 6, 32, 87, 73, 84, 72, 32, 218, 4, 65, 66, 67, 218, 1, + 72, 34, 73, 156, 2, 13, 81, 85, 65, 84, 32, 82, 69, 86, 69, 82, 83, 69, + 68, 221, 235, 9, 6, 84, 73, 82, 82, 85, 80, 40, 110, 65, 34, 67, 86, 68, + 138, 1, 83, 174, 1, 86, 210, 9, 77, 186, 135, 4, 80, 182, 235, 3, 79, + 155, 154, 11, 72, 4, 205, 1, 4, 67, 85, 84, 69, 12, 58, 65, 230, 10, 69, + 82, 79, 202, 31, 73, 151, 251, 6, 85, 4, 113, 3, 82, 79, 78, 8, 32, 3, + 79, 84, 32, 207, 32, 73, 6, 26, 66, 207, 241, 19, 65, 4, 25, 4, 69, 76, + 79, 87, 5, 11, 32, 2, 173, 237, 19, 3, 65, 78, 68, 4, 22, 72, 203, 42, + 87, 2, 21, 3, 79, 82, 84, 2, 17, 2, 32, 83, 2, 11, 84, 2, 21, 3, 82, 79, + 75, 2, 11, 69, 2, 17, 2, 32, 79, 2, 197, 222, 19, 4, 86, 69, 82, 76, 2, + 37, 7, 69, 82, 84, 73, 67, 65, 76, 2, 205, 40, 2, 32, 76, 4, 46, 76, 165, + 226, 19, 5, 75, 72, 65, 32, 89, 2, 247, 12, 84, 18, 48, 3, 72, 87, 65, + 97, 5, 82, 73, 80, 84, 32, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 222, 35, + 71, 186, 2, 65, 242, 238, 3, 82, 247, 255, 14, 72, 8, 26, 82, 207, 132, + 4, 71, 5, 241, 186, 11, 5, 32, 87, 73, 84, 72, 2, 133, 240, 16, 3, 65, + 82, 80, 14, 48, 7, 68, 69, 87, 65, 89, 83, 32, 199, 1, 71, 12, 110, 79, + 56, 4, 84, 85, 82, 78, 156, 205, 10, 11, 68, 73, 65, 69, 82, 69, 83, 73, + 90, 69, 68, 215, 154, 10, 85, 7, 26, 80, 135, 135, 4, 32, 2, 193, 240, 9, + 2, 69, 78, 2, 221, 138, 13, 2, 69, 68, 2, 237, 237, 16, 4, 77, 79, 73, + 68, 2, 139, 129, 10, 32, 147, 1, 188, 1, 6, 32, 87, 73, 84, 72, 32, 192, + 3, 2, 69, 83, 70, 72, 130, 2, 79, 102, 82, 54, 85, 174, 131, 4, 67, 202, + 1, 83, 208, 129, 11, 9, 65, 73, 76, 76, 69, 83, 83, 32, 80, 251, 215, 5, + 90, 34, 110, 67, 182, 1, 68, 66, 77, 170, 31, 76, 146, 232, 3, 80, 168, + 5, 4, 72, 79, 79, 75, 50, 82, 235, 165, 16, 83, 10, 58, 69, 22, 73, 62, + 79, 222, 154, 7, 85, 207, 161, 12, 65, 2, 219, 168, 12, 68, 2, 37, 7, 82, + 67, 85, 77, 70, 76, 69, 2, 215, 178, 18, 88, 2, 17, 2, 77, 77, 2, 175, + 178, 18, 65, 8, 32, 2, 73, 65, 135, 191, 16, 79, 4, 154, 21, 71, 215, 6, + 69, 4, 17, 2, 73, 68, 4, 26, 45, 255, 255, 3, 68, 2, 149, 142, 4, 6, 72, + 69, 73, 71, 72, 84, 6, 45, 9, 72, 32, 68, 73, 71, 82, 65, 80, 72, 7, 243, + 133, 4, 32, 8, 64, 12, 32, 87, 73, 84, 72, 32, 83, 84, 82, 73, 75, 69, + 43, 79, 2, 233, 179, 16, 5, 84, 72, 82, 79, 85, 6, 17, 2, 82, 78, 7, 41, + 8, 32, 87, 73, 84, 72, 32, 83, 84, 4, 25, 4, 82, 79, 75, 69, 5, 11, 32, + 2, 133, 215, 3, 6, 84, 72, 82, 79, 85, 71, 8, 26, 78, 203, 133, 4, 80, 6, + 17, 2, 69, 32, 6, 206, 206, 4, 83, 134, 212, 10, 70, 155, 168, 3, 84, 2, + 17, 2, 69, 83, 2, 11, 73, 2, 255, 187, 20, 76, 76, 44, 5, 82, 78, 69, 68, + 32, 143, 222, 20, 77, 74, 162, 1, 68, 22, 72, 66, 73, 54, 79, 142, 1, 82, + 110, 84, 22, 86, 198, 129, 4, 65, 38, 77, 198, 2, 89, 210, 193, 16, 85, + 218, 19, 69, 2, 71, 2, 75, 2, 76, 3, 87, 2, 131, 160, 17, 69, 7, 141, + 242, 3, 11, 32, 87, 73, 84, 72, 32, 70, 73, 83, 72, 72, 5, 11, 78, 2, + 197, 218, 9, 5, 83, 85, 76, 65, 82, 12, 66, 69, 232, 230, 3, 7, 32, 79, + 80, 69, 78, 45, 79, 159, 29, 80, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, + 238, 178, 18, 72, 143, 248, 1, 83, 15, 33, 6, 32, 87, 73, 84, 72, 32, 12, + 198, 247, 3, 77, 174, 7, 80, 130, 5, 76, 154, 159, 14, 84, 183, 97, 72, + 5, 135, 255, 3, 32, 7, 11, 32, 4, 161, 5, 4, 87, 73, 84, 72, 97, 90, 32, + 152, 228, 3, 6, 80, 83, 73, 76, 79, 78, 182, 244, 16, 69, 2, 73, 2, 77, + 3, 79, 82, 48, 3, 66, 65, 82, 49, 5, 87, 73, 84, 72, 32, 5, 245, 17, 8, + 32, 87, 73, 84, 72, 32, 83, 72, 78, 142, 1, 67, 74, 68, 150, 2, 72, 170, + 1, 77, 134, 1, 79, 106, 82, 38, 84, 186, 9, 71, 82, 83, 234, 1, 65, 246, + 173, 3, 73, 62, 66, 143, 66, 76, 6, 152, 203, 4, 9, 73, 82, 67, 85, 77, + 70, 76, 69, 88, 139, 228, 14, 65, 18, 52, 8, 73, 65, 69, 82, 69, 83, 73, + 83, 131, 1, 79, 13, 11, 32, 10, 40, 4, 65, 78, 68, 32, 183, 179, 18, 66, + 8, 50, 67, 226, 13, 71, 186, 2, 65, 239, 199, 3, 77, 2, 183, 173, 19, 65, + 6, 26, 85, 167, 163, 18, 84, 4, 21, 3, 66, 76, 69, 4, 11, 32, 4, 138, 13, + 71, 187, 2, 65, 14, 11, 79, 14, 28, 2, 82, 78, 207, 81, 79, 13, 29, 5, + 32, 65, 78, 68, 32, 10, 66, 72, 226, 11, 71, 186, 2, 65, 138, 242, 7, 68, + 251, 234, 8, 84, 2, 229, 80, 2, 79, 79, 10, 29, 5, 65, 67, 82, 79, 78, + 11, 29, 5, 32, 65, 78, 68, 32, 8, 50, 68, 214, 10, 71, 186, 2, 65, 131, + 221, 16, 84, 2, 171, 10, 73, 6, 29, 5, 71, 79, 78, 69, 75, 7, 11, 32, 4, + 25, 4, 65, 78, 68, 32, 4, 178, 12, 65, 131, 221, 16, 84, 4, 142, 251, 3, + 69, 171, 161, 14, 73, 6, 25, 4, 73, 76, 68, 69, 7, 11, 32, 4, 26, 65, + 151, 174, 18, 66, 2, 17, 2, 78, 68, 2, 11, 32, 2, 139, 11, 65, 29, 84, 6, + 32, 87, 73, 84, 72, 32, 162, 1, 73, 66, 79, 134, 189, 19, 69, 151, 144, + 1, 89, 14, 82, 68, 234, 242, 3, 80, 142, 1, 67, 146, 7, 82, 206, 235, 12, + 84, 231, 145, 2, 72, 4, 26, 73, 203, 251, 7, 79, 2, 17, 2, 65, 71, 2, + 201, 157, 20, 2, 79, 78, 2, 41, 8, 83, 73, 71, 79, 84, 72, 73, 67, 2, + 131, 239, 18, 32, 6, 33, 6, 76, 65, 80, 85, 75, 32, 6, 158, 182, 20, 65, + 2, 79, 3, 85, 19, 33, 6, 32, 87, 73, 84, 72, 32, 16, 202, 4, 67, 18, 68, + 70, 71, 186, 2, 65, 154, 144, 18, 82, 207, 94, 72, 17, 33, 6, 32, 87, 73, + 84, 72, 32, 14, 42, 68, 32, 2, 76, 79, 187, 239, 3, 80, 4, 222, 3, 73, + 247, 198, 19, 79, 8, 60, 11, 78, 71, 32, 76, 69, 70, 84, 32, 76, 69, 71, + 79, 87, 7, 11, 32, 4, 60, 7, 65, 78, 68, 32, 76, 79, 87, 65, 4, 87, 73, + 84, 72, 2, 17, 2, 32, 82, 2, 21, 3, 73, 71, 72, 2, 155, 154, 11, 84, 2, + 185, 199, 19, 4, 32, 83, 69, 82, 33, 48, 6, 32, 87, 73, 84, 72, 32, 175, + 155, 16, 79, 28, 110, 67, 18, 68, 70, 71, 22, 72, 42, 76, 22, 83, 234, 1, + 65, 238, 199, 3, 77, 150, 149, 13, 84, 155, 179, 1, 82, 2, 203, 3, 73, 6, + 26, 73, 171, 163, 16, 79, 2, 17, 2, 65, 69, 2, 187, 192, 16, 82, 2, 239, + 216, 18, 82, 4, 17, 2, 79, 79, 4, 239, 136, 5, 75, 2, 187, 205, 19, 79, + 4, 26, 72, 179, 150, 20, 84, 2, 21, 3, 79, 82, 84, 2, 197, 252, 7, 6, 32, + 82, 73, 71, 72, 84, 31, 33, 6, 32, 87, 73, 84, 72, 32, 28, 98, 65, 22, + 67, 82, 68, 38, 76, 34, 83, 198, 224, 3, 77, 174, 7, 80, 218, 5, 82, 247, + 255, 14, 72, 2, 223, 190, 13, 67, 6, 42, 73, 150, 251, 6, 85, 207, 161, + 12, 65, 2, 229, 203, 11, 4, 82, 67, 85, 77, 6, 154, 187, 3, 69, 203, 228, + 12, 79, 2, 11, 73, 2, 163, 183, 12, 78, 4, 26, 87, 163, 147, 20, 84, 2, + 215, 154, 17, 65, 18, 90, 70, 142, 195, 9, 73, 172, 9, 6, 76, 79, 78, 71, + 32, 83, 190, 217, 10, 83, 219, 5, 79, 10, 34, 70, 254, 193, 20, 73, 3, + 76, 7, 250, 193, 20, 73, 3, 76, 36, 150, 1, 83, 202, 192, 20, 65, 2, 69, + 2, 72, 2, 73, 2, 74, 2, 75, 2, 76, 2, 77, 2, 78, 2, 79, 2, 80, 2, 82, 2, + 84, 2, 85, 2, 86, 3, 88, 5, 215, 230, 4, 67, 226, 5, 240, 1, 2, 65, 70, + 144, 1, 2, 70, 84, 190, 38, 79, 20, 5, 80, 67, 72, 65, 32, 164, 8, 8, 83, + 83, 45, 84, 72, 65, 78, 32, 184, 250, 12, 5, 85, 75, 79, 84, 72, 218, + 194, 3, 68, 228, 23, 6, 86, 69, 76, 32, 83, 76, 218, 233, 2, 77, 239, 79, + 71, 6, 120, 3, 76, 69, 83, 160, 196, 1, 14, 32, 70, 76, 85, 84, 84, 69, + 82, 73, 78, 71, 32, 73, 78, 189, 218, 11, 3, 89, 32, 71, 2, 227, 243, 14, + 83, 134, 4, 58, 32, 250, 20, 45, 217, 2, 6, 87, 65, 82, 68, 83, 32, 246, + 1, 166, 2, 65, 234, 4, 66, 202, 1, 67, 96, 2, 68, 79, 112, 2, 72, 65, + 166, 3, 76, 46, 77, 38, 79, 102, 82, 146, 3, 83, 82, 84, 222, 1, 87, 158, + 183, 8, 70, 236, 5, 14, 74, 85, 83, 84, 73, 70, 73, 69, 68, 32, 82, 73, + 71, 72, 86, 78, 202, 1, 80, 153, 13, 10, 86, 69, 82, 84, 73, 67, 65, 76, + 32, 66, 28, 22, 78, 143, 4, 82, 22, 28, 2, 68, 32, 191, 3, 71, 16, 96, 6, + 76, 79, 87, 69, 82, 32, 32, 6, 82, 73, 71, 72, 84, 32, 89, 6, 85, 80, 80, + 69, 82, 32, 4, 202, 1, 65, 239, 196, 17, 79, 6, 50, 84, 209, 143, 18, 6, + 68, 79, 85, 66, 76, 69, 4, 250, 157, 17, 82, 211, 232, 1, 65, 6, 82, 65, + 53, 16, 79, 78, 69, 32, 69, 73, 71, 72, 84, 72, 32, 66, 76, 79, 67, 75, + 2, 237, 155, 17, 8, 78, 68, 32, 82, 73, 71, 72, 84, 5, 245, 147, 19, 17, + 32, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, 65, 67, 75, 6, + 198, 188, 8, 69, 185, 1, 4, 76, 69, 32, 66, 6, 26, 67, 163, 192, 8, 82, + 2, 253, 191, 8, 5, 32, 76, 69, 83, 83, 12, 40, 4, 65, 82, 66, 32, 187, + 192, 8, 76, 8, 40, 4, 68, 79, 87, 78, 1, 2, 85, 80, 4, 57, 12, 32, 82, + 73, 71, 72, 84, 32, 66, 65, 82, 66, 32, 4, 240, 137, 17, 4, 68, 79, 87, + 78, 1, 2, 85, 80, 14, 254, 191, 8, 85, 166, 26, 79, 242, 235, 2, 69, 141, + 168, 2, 8, 76, 79, 83, 69, 68, 32, 69, 78, 10, 44, 5, 85, 66, 76, 69, 32, + 171, 192, 8, 84, 8, 222, 193, 8, 87, 190, 30, 65, 154, 132, 3, 81, 199, + 199, 4, 80, 38, 36, 3, 76, 70, 32, 163, 198, 8, 78, 36, 132, 2, 6, 67, + 73, 82, 67, 76, 69, 162, 193, 8, 66, 90, 70, 82, 72, 50, 82, 58, 84, 70, + 87, 246, 13, 76, 22, 85, 176, 200, 8, 30, 73, 78, 86, 69, 82, 83, 69, 32, + 77, 69, 68, 73, 85, 77, 32, 83, 72, 65, 68, 69, 32, 65, 78, 68, 32, 82, + 73, 71, 72, 84, 255, 26, 77, 11, 33, 6, 32, 87, 73, 84, 72, 32, 8, 42, + 84, 206, 136, 18, 70, 191, 214, 1, 68, 4, 150, 203, 5, 72, 199, 145, 13, + 87, 4, 232, 162, 1, 2, 85, 71, 163, 161, 7, 79, 2, 217, 155, 19, 4, 85, + 76, 84, 73, 8, 36, 3, 78, 69, 32, 243, 196, 8, 85, 6, 194, 183, 17, 81, + 146, 4, 69, 45, 5, 84, 72, 73, 82, 68, 30, 44, 5, 73, 71, 72, 84, 32, + 199, 197, 8, 65, 28, 152, 1, 5, 65, 82, 82, 79, 87, 132, 1, 12, 68, 79, + 85, 66, 76, 69, 32, 65, 82, 82, 79, 87, 30, 87, 214, 242, 8, 79, 162, + 143, 8, 66, 54, 83, 211, 68, 84, 11, 11, 32, 8, 72, 5, 87, 73, 84, 72, + 32, 221, 214, 18, 7, 84, 72, 82, 79, 85, 71, 72, 6, 146, 195, 16, 68, + 234, 183, 3, 86, 79, 83, 7, 245, 234, 8, 2, 32, 87, 4, 202, 253, 8, 65, + 227, 191, 8, 72, 34, 218, 195, 8, 45, 70, 69, 78, 73, 168, 1, 3, 80, 69, + 69, 26, 81, 227, 2, 85, 26, 106, 82, 178, 200, 8, 72, 130, 226, 7, 79, + 212, 134, 1, 8, 87, 79, 32, 84, 72, 73, 82, 68, 151, 198, 1, 65, 6, 40, + 4, 73, 65, 78, 71, 171, 203, 8, 65, 4, 140, 242, 4, 8, 76, 69, 32, 66, + 69, 83, 73, 68, 179, 191, 12, 85, 16, 206, 205, 8, 72, 202, 1, 73, 181, + 200, 10, 2, 82, 73, 62, 128, 1, 9, 80, 79, 73, 78, 84, 73, 78, 71, 32, + 138, 1, 83, 250, 205, 8, 70, 226, 2, 72, 153, 7, 7, 84, 79, 45, 82, 73, + 71, 72, 30, 86, 65, 130, 211, 8, 67, 94, 68, 58, 77, 58, 82, 182, 1, 83, + 74, 84, 211, 172, 8, 69, 6, 190, 211, 8, 78, 158, 175, 8, 84, 159, 2, 73, + 4, 44, 5, 73, 68, 69, 32, 65, 175, 214, 8, 72, 2, 205, 147, 1, 2, 82, 67, + 210, 1, 172, 1, 5, 65, 82, 82, 79, 87, 174, 5, 66, 70, 72, 242, 3, 84, + 178, 2, 87, 162, 214, 8, 68, 210, 1, 70, 170, 7, 76, 26, 79, 34, 80, 50, + 82, 70, 83, 242, 206, 8, 67, 47, 81, 73, 26, 32, 159, 236, 17, 45, 68, + 102, 65, 138, 1, 84, 132, 2, 5, 87, 73, 84, 72, 32, 242, 215, 8, 70, 217, + 165, 10, 4, 79, 86, 69, 82, 12, 44, 5, 66, 79, 86, 69, 32, 223, 217, 8, + 78, 10, 64, 4, 83, 72, 79, 82, 214, 216, 8, 82, 182, 230, 4, 65, 55, 84, + 2, 223, 255, 18, 84, 12, 56, 7, 72, 82, 79, 85, 71, 72, 32, 53, 3, 79, + 32, 66, 6, 226, 188, 13, 83, 238, 206, 4, 76, 211, 149, 2, 88, 6, 32, 2, + 65, 82, 231, 218, 8, 76, 5, 245, 168, 12, 23, 32, 79, 86, 69, 82, 32, 82, + 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 65, 82, 82, 79, 87, 32, 36, 118, + 76, 198, 218, 8, 68, 182, 1, 80, 30, 83, 38, 84, 138, 210, 8, 77, 38, 78, + 122, 69, 150, 153, 1, 72, 171, 165, 1, 86, 4, 162, 174, 17, 65, 171, 247, + 1, 79, 8, 234, 220, 8, 65, 172, 10, 5, 79, 84, 84, 79, 77, 219, 200, 8, + 76, 30, 26, 65, 131, 181, 17, 69, 26, 48, 6, 82, 80, 79, 79, 78, 32, 139, + 215, 19, 78, 24, 80, 10, 87, 73, 84, 72, 32, 66, 65, 82, 66, 32, 249, + 245, 9, 4, 79, 86, 69, 82, 22, 40, 4, 68, 79, 87, 78, 117, 2, 85, 80, 10, + 26, 32, 243, 186, 17, 87, 8, 234, 223, 8, 66, 188, 2, 7, 65, 66, 79, 86, + 69, 32, 82, 234, 208, 8, 70, 179, 5, 84, 12, 26, 32, 255, 185, 17, 87, + 10, 60, 6, 65, 66, 79, 86, 69, 32, 222, 177, 17, 70, 179, 5, 84, 6, 42, + 76, 213, 223, 8, 4, 82, 73, 71, 72, 4, 250, 221, 8, 69, 147, 223, 4, 79, + 54, 44, 2, 82, 73, 202, 227, 8, 79, 159, 5, 87, 34, 44, 5, 65, 78, 71, + 76, 69, 255, 231, 8, 80, 30, 56, 8, 45, 72, 69, 65, 68, 69, 68, 32, 251, + 191, 17, 32, 28, 52, 5, 65, 82, 82, 79, 87, 202, 184, 17, 68, 39, 80, 25, + 11, 32, 22, 192, 228, 8, 9, 79, 86, 69, 82, 32, 82, 73, 71, 72, 22, 87, + 135, 208, 8, 84, 6, 26, 72, 143, 234, 8, 65, 4, 45, 9, 73, 84, 69, 32, + 65, 82, 82, 79, 87, 5, 173, 189, 17, 2, 32, 87, 5, 243, 253, 18, 80, 148, + 1, 252, 1, 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, + 32, 124, 7, 76, 69, 84, 84, 69, 82, 32, 236, 1, 12, 80, 85, 78, 67, 84, + 85, 65, 84, 73, 79, 78, 32, 198, 1, 83, 172, 1, 11, 86, 79, 87, 69, 76, + 32, 83, 73, 71, 78, 32, 251, 154, 18, 68, 18, 66, 75, 22, 78, 130, 148, + 20, 76, 2, 77, 2, 80, 2, 82, 3, 84, 5, 155, 195, 19, 65, 5, 189, 212, 12, + 4, 89, 73, 78, 45, 78, 194, 1, 75, 2, 80, 254, 153, 7, 68, 130, 236, 10, + 66, 2, 70, 2, 71, 2, 72, 2, 77, 138, 15, 78, 170, 181, 1, 84, 46, 67, 2, + 83, 138, 69, 74, 2, 76, 2, 82, 2, 86, 2, 87, 2, 89, 187, 2, 65, 6, 222, + 143, 20, 72, 2, 76, 187, 2, 65, 10, 82, 84, 40, 14, 78, 89, 69, 84, 32, + 84, 72, 89, 79, 79, 77, 32, 84, 65, 43, 67, 6, 38, 65, 21, 5, 83, 72, 79, + 79, 75, 2, 247, 253, 6, 45, 5, 17, 2, 32, 67, 2, 237, 150, 15, 3, 69, 82, + 45, 8, 92, 4, 73, 71, 78, 32, 37, 15, 85, 66, 74, 79, 73, 78, 69, 68, 32, + 76, 69, 84, 84, 69, 82, 4, 202, 242, 15, 78, 231, 208, 2, 82, 4, 11, 32, + 4, 226, 140, 20, 82, 3, 89, 14, 130, 184, 16, 85, 206, 141, 1, 79, 250, + 198, 2, 65, 186, 2, 69, 3, 73, 52, 138, 1, 65, 128, 4, 11, 69, 81, 85, + 65, 76, 32, 84, 79, 32, 79, 82, 200, 1, 2, 66, 85, 42, 67, 186, 1, 79, + 210, 2, 87, 207, 252, 18, 83, 16, 40, 5, 66, 79, 86, 69, 32, 171, 4, 78, + 12, 152, 1, 7, 71, 82, 69, 65, 84, 69, 82, 110, 83, 176, 1, 19, 68, 79, + 85, 66, 76, 69, 45, 76, 73, 78, 69, 32, 69, 81, 85, 65, 76, 32, 65, 167, + 228, 15, 76, 2, 181, 5, 23, 45, 84, 72, 65, 78, 32, 65, 66, 79, 86, 69, + 32, 68, 79, 85, 66, 76, 69, 45, 76, 73, 78, 69, 6, 152, 1, 7, 73, 77, 73, + 76, 65, 82, 32, 93, 26, 76, 65, 78, 84, 69, 68, 32, 69, 81, 85, 65, 76, + 32, 65, 66, 79, 86, 69, 32, 71, 82, 69, 65, 84, 69, 82, 4, 18, 65, 59, + 79, 2, 25, 4, 66, 79, 86, 69, 2, 181, 243, 17, 2, 32, 71, 2, 227, 2, 82, + 2, 145, 2, 6, 45, 84, 72, 65, 78, 32, 4, 17, 2, 68, 32, 4, 220, 3, 5, 78, + 79, 84, 32, 65, 221, 162, 13, 11, 83, 73, 78, 71, 76, 69, 45, 76, 73, 78, + 69, 4, 217, 132, 13, 5, 84, 32, 78, 79, 84, 4, 65, 14, 76, 79, 83, 69, + 68, 32, 66, 89, 32, 67, 85, 82, 86, 69, 5, 11, 32, 2, 61, 13, 65, 66, 79, + 86, 69, 32, 83, 76, 65, 78, 84, 69, 68, 2, 17, 2, 32, 69, 2, 151, 245, + 14, 81, 18, 40, 2, 82, 32, 221, 230, 11, 2, 86, 69, 16, 114, 65, 48, 16, + 83, 76, 65, 78, 84, 69, 68, 32, 69, 81, 85, 65, 76, 32, 84, 79, 194, 129, + 13, 69, 131, 237, 4, 71, 2, 237, 190, 9, 7, 80, 80, 82, 79, 88, 73, 77, + 9, 49, 10, 32, 87, 73, 84, 72, 32, 68, 79, 84, 32, 6, 26, 65, 243, 209, + 11, 73, 4, 25, 4, 66, 79, 86, 69, 5, 179, 176, 18, 32, 6, 25, 4, 73, 84, + 72, 32, 6, 66, 67, 40, 8, 81, 85, 69, 83, 84, 73, 79, 78, 247, 177, 19, + 68, 2, 201, 208, 11, 5, 73, 82, 67, 76, 69, 2, 17, 2, 32, 77, 2, 17, 2, + 65, 82, 2, 255, 132, 19, 75, 136, 11, 190, 1, 71, 186, 5, 77, 166, 7, 78, + 156, 65, 2, 80, 83, 20, 3, 83, 85, 32, 142, 221, 15, 82, 136, 35, 11, 86, + 82, 69, 32, 84, 79, 85, 82, 78, 79, 73, 214, 59, 79, 190, 221, 1, 90, + 191, 84, 66, 44, 26, 65, 57, 2, 72, 84, 2, 181, 174, 9, 9, 84, 85, 82, + 69, 32, 79, 80, 69, 78, 42, 38, 32, 137, 4, 4, 78, 73, 78, 71, 36, 146, + 1, 69, 38, 70, 126, 82, 40, 3, 76, 69, 70, 86, 83, 42, 84, 236, 204, 7, + 3, 66, 76, 85, 238, 170, 9, 87, 254, 41, 86, 226, 78, 71, 219, 69, 67, 2, + 141, 230, 17, 4, 73, 71, 72, 84, 8, 94, 73, 153, 180, 18, 17, 79, 85, 82, + 32, 80, 79, 73, 78, 84, 69, 68, 32, 66, 76, 65, 67, 75, 4, 161, 226, 17, + 2, 86, 69, 4, 36, 3, 73, 71, 72, 135, 157, 18, 65, 2, 245, 241, 1, 16, + 84, 32, 84, 79, 82, 84, 79, 73, 83, 69, 32, 83, 72, 69, 76, 76, 6, 194, + 129, 17, 72, 254, 97, 65, 43, 73, 4, 220, 174, 16, 2, 87, 69, 21, 3, 72, + 82, 69, 7, 29, 5, 32, 77, 79, 79, 68, 5, 219, 155, 8, 32, 138, 1, 80, 3, + 66, 85, 32, 201, 163, 8, 11, 73, 84, 69, 68, 32, 76, 73, 65, 66, 73, 76, + 136, 1, 128, 1, 7, 76, 69, 84, 84, 69, 82, 32, 222, 1, 83, 200, 2, 5, 86, + 79, 87, 69, 76, 154, 217, 12, 69, 246, 198, 4, 81, 223, 96, 68, 60, 170, + 1, 71, 198, 145, 6, 84, 234, 231, 8, 89, 186, 136, 1, 78, 246, 173, 3, + 83, 82, 66, 2, 67, 2, 68, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, + 2, 82, 3, 87, 6, 202, 171, 18, 89, 230, 201, 1, 72, 187, 2, 65, 32, 108, + 4, 73, 71, 78, 32, 128, 1, 12, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, + 82, 32, 245, 255, 6, 2, 85, 66, 8, 72, 3, 75, 69, 77, 0, 3, 77, 85, 75, + 32, 2, 83, 65, 231, 170, 17, 76, 2, 153, 175, 17, 3, 80, 72, 82, 2, 131, + 226, 19, 45, 18, 194, 255, 15, 78, 142, 177, 3, 65, 194, 66, 75, 2, 76, + 2, 77, 2, 80, 2, 82, 3, 84, 20, 84, 6, 32, 83, 73, 71, 78, 32, 149, 90, + 10, 45, 67, 65, 82, 82, 73, 69, 82, 32, 76, 18, 230, 216, 5, 65, 130, + 210, 11, 79, 146, 137, 2, 69, 162, 64, 73, 3, 85, 226, 8, 22, 69, 187, + 64, 75, 222, 8, 34, 32, 177, 3, 3, 65, 82, 32, 14, 120, 12, 73, 78, 84, + 69, 71, 82, 65, 84, 73, 79, 78, 32, 150, 167, 13, 70, 206, 153, 3, 83, + 237, 147, 1, 4, 84, 65, 66, 85, 6, 108, 5, 87, 73, 84, 72, 32, 157, 1, + 17, 78, 79, 84, 32, 73, 78, 67, 76, 85, 68, 73, 78, 71, 32, 84, 72, 69, + 4, 76, 7, 82, 69, 67, 84, 65, 78, 71, 1, 8, 83, 69, 77, 73, 67, 73, 82, + 67, 2, 73, 16, 85, 76, 65, 82, 32, 80, 65, 84, 72, 32, 65, 82, 79, 85, + 78, 68, 2, 17, 2, 32, 80, 2, 179, 201, 18, 79, 208, 8, 60, 8, 65, 32, 83, + 73, 71, 78, 32, 65, 205, 24, 2, 66, 32, 170, 5, 122, 49, 86, 51, 202, 2, + 52, 214, 1, 53, 158, 4, 54, 142, 3, 55, 132, 4, 2, 56, 48, 78, 66, 185, + 159, 18, 3, 48, 50, 56, 6, 212, 198, 12, 5, 48, 48, 45, 49, 48, 200, 233, + 5, 2, 50, 48, 233, 19, 2, 51, 49, 150, 1, 78, 48, 90, 49, 130, 1, 55, + 250, 172, 14, 50, 2, 51, 2, 52, 2, 53, 3, 54, 22, 178, 1, 57, 190, 235, + 19, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 24, 90, 51, 190, + 235, 19, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 6, + 186, 235, 19, 65, 2, 66, 3, 67, 4, 150, 235, 19, 48, 3, 49, 38, 18, 48, + 91, 49, 20, 162, 1, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, + 2, 56, 3, 57, 18, 74, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, + 55, 3, 56, 2, 237, 183, 6, 2, 45, 86, 160, 1, 102, 48, 78, 49, 62, 51, + 86, 52, 70, 53, 86, 54, 190, 11, 50, 194, 171, 2, 57, 174, 240, 11, 55, + 3, 56, 16, 186, 232, 19, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, + 57, 12, 238, 231, 19, 48, 2, 49, 2, 50, 2, 51, 2, 53, 3, 54, 18, 178, + 231, 19, 48, 2, 49, 2, 50, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 14, + 222, 230, 19, 48, 2, 49, 2, 50, 2, 53, 2, 55, 2, 56, 3, 57, 18, 154, 230, + 19, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 57, 12, 198, + 229, 19, 51, 2, 52, 2, 53, 2, 54, 2, 56, 3, 57, 104, 70, 48, 78, 50, 86, + 51, 38, 52, 78, 54, 150, 162, 14, 53, 131, 2, 49, 16, 194, 228, 19, 48, + 2, 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 56, 3, 57, 18, 246, 227, 19, 48, 2, + 49, 2, 50, 2, 51, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 6, 162, 227, 19, 52, + 2, 55, 3, 56, 16, 254, 226, 19, 48, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, + 56, 3, 57, 10, 178, 226, 19, 48, 2, 49, 2, 50, 2, 51, 3, 52, 44, 86, 48, + 134, 2, 49, 196, 129, 2, 2, 51, 50, 153, 204, 17, 6, 50, 54, 32, 69, 89, + 89, 26, 110, 57, 154, 225, 8, 55, 182, 6, 50, 62, 54, 254, 63, 52, 146, + 155, 3, 51, 114, 56, 186, 211, 2, 49, 155, 122, 53, 10, 26, 45, 207, 212, + 18, 32, 8, 96, 2, 50, 32, 156, 180, 12, 3, 54, 32, 76, 184, 2, 3, 52, 32, + 76, 137, 174, 3, 3, 51, 32, 76, 2, 247, 183, 12, 76, 14, 114, 51, 32, 3, + 52, 32, 65, 0, 2, 53, 32, 134, 65, 49, 174, 223, 3, 50, 198, 200, 4, 48, + 249, 249, 6, 2, 55, 32, 2, 11, 32, 2, 147, 153, 12, 79, 2, 151, 160, 18, + 66, 16, 250, 221, 19, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, + 55, 162, 1, 22, 48, 155, 5, 49, 140, 1, 82, 49, 54, 50, 118, 51, 62, 52, + 78, 53, 86, 54, 62, 55, 70, 56, 155, 152, 14, 48, 10, 186, 220, 19, 48, + 2, 49, 2, 51, 2, 54, 3, 55, 28, 86, 49, 2, 50, 138, 82, 51, 170, 137, 19, + 48, 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 7, 174, 219, 19, 70, 3, 77, 12, + 146, 219, 19, 48, 2, 49, 2, 52, 2, 55, 2, 56, 3, 57, 16, 214, 218, 19, + 48, 2, 49, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 18, 138, 218, 19, + 48, 2, 49, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 12, 182, 217, + 19, 48, 2, 49, 2, 53, 2, 54, 2, 55, 3, 57, 14, 250, 216, 19, 48, 2, 51, + 2, 52, 2, 54, 2, 55, 2, 56, 3, 57, 12, 182, 216, 19, 48, 2, 49, 2, 50, 2, + 53, 2, 54, 3, 55, 22, 82, 50, 36, 2, 51, 49, 30, 56, 186, 171, 12, 49, + 206, 2, 54, 146, 1, 55, 3, 57, 6, 166, 215, 19, 48, 2, 50, 3, 51, 4, 130, + 215, 19, 65, 3, 66, 4, 230, 214, 19, 48, 3, 56, 166, 3, 116, 9, 73, 68, + 69, 79, 71, 82, 65, 77, 32, 220, 17, 10, 77, 79, 78, 79, 71, 82, 65, 77, + 32, 66, 249, 1, 2, 83, 89, 234, 1, 54, 66, 253, 15, 8, 86, 69, 83, 83, + 69, 76, 32, 66, 176, 1, 22, 49, 131, 11, 50, 126, 86, 48, 210, 3, 50, + 166, 1, 51, 86, 52, 122, 53, 114, 54, 146, 1, 55, 118, 56, 71, 57, 28, + 114, 53, 98, 54, 58, 55, 78, 56, 62, 57, 156, 139, 7, 3, 50, 32, 87, 254, + 88, 48, 137, 175, 11, 4, 52, 32, 68, 69, 6, 132, 138, 7, 2, 32, 69, 220, + 166, 11, 3, 70, 32, 77, 133, 82, 7, 77, 32, 83, 84, 65, 76, 76, 4, 168, + 245, 1, 3, 70, 32, 69, 133, 160, 16, 2, 77, 32, 4, 36, 3, 70, 32, 83, 1, + 2, 77, 32, 2, 129, 236, 11, 4, 72, 69, 45, 71, 4, 240, 159, 9, 3, 77, 32, + 66, 173, 149, 9, 3, 70, 32, 83, 4, 224, 198, 17, 4, 77, 32, 66, 85, 129, + 110, 3, 70, 32, 67, 10, 248, 152, 9, 4, 51, 32, 83, 80, 240, 10, 5, 49, + 32, 66, 65, 82, 148, 240, 4, 4, 50, 32, 79, 76, 20, 6, 53, 32, 67, 89, + 80, 69, 129, 179, 4, 4, 48, 32, 87, 72, 6, 54, 49, 164, 239, 17, 3, 48, + 32, 79, 211, 223, 1, 50, 2, 181, 179, 18, 2, 32, 87, 10, 224, 5, 3, 53, + 32, 87, 252, 150, 9, 6, 48, 32, 66, 82, 79, 78, 172, 2, 4, 49, 32, 71, + 79, 206, 175, 10, 50, 3, 54, 16, 82, 57, 134, 238, 2, 49, 138, 223, 16, + 48, 2, 50, 2, 51, 2, 52, 2, 55, 3, 56, 2, 157, 102, 3, 32, 67, 76, 20, + 160, 177, 14, 5, 51, 32, 65, 82, 77, 152, 216, 4, 5, 50, 32, 71, 65, 82, + 182, 67, 48, 2, 49, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 18, 130, + 130, 14, 54, 216, 196, 3, 4, 51, 32, 77, 79, 134, 133, 2, 48, 2, 49, 2, + 50, 2, 52, 2, 55, 2, 56, 3, 57, 14, 234, 202, 19, 48, 2, 49, 2, 50, 2, + 51, 2, 52, 2, 53, 3, 57, 4, 204, 169, 2, 3, 49, 32, 72, 219, 160, 17, 48, + 50, 42, 50, 110, 51, 130, 1, 52, 227, 1, 53, 4, 84, 8, 48, 32, 70, 79, + 79, 84, 83, 84, 245, 215, 6, 7, 53, 32, 66, 65, 84, 72, 84, 2, 231, 179, + 18, 79, 12, 104, 4, 51, 32, 83, 87, 132, 143, 14, 4, 48, 32, 83, 80, 154, + 156, 4, 49, 218, 156, 1, 50, 2, 52, 3, 54, 2, 131, 175, 18, 79, 16, 168, + 1, 9, 48, 32, 87, 72, 69, 69, 76, 69, 68, 2, 49, 34, 51, 180, 180, 17, + 12, 50, 32, 67, 72, 65, 82, 73, 79, 84, 32, 70, 82, 226, 145, 2, 53, 2, + 54, 2, 56, 3, 57, 2, 145, 186, 18, 3, 32, 67, 72, 2, 195, 196, 6, 32, 18, + 224, 190, 18, 3, 52, 32, 68, 158, 135, 1, 49, 2, 50, 2, 51, 2, 53, 2, 54, + 2, 55, 2, 56, 3, 57, 58, 50, 50, 160, 155, 12, 2, 49, 53, 1, 2, 51, 48, + 54, 50, 50, 206, 157, 12, 53, 198, 232, 1, 48, 3, 49, 12, 174, 196, 19, 49, 2, 50, 2, 54, 2, 55, 2, 56, 3, 57, 12, 46, 49, 153, 12, 6, 50, 52, 55, 32, 68, 73, 10, 50, 50, 70, 51, 181, 11, 5, 53, 54, 32, 84, 85, 4, - 208, 174, 3, 3, 55, 32, 75, 189, 220, 15, 5, 56, 32, 75, 65, 78, 4, 56, - 3, 53, 32, 77, 201, 239, 15, 5, 51, 32, 65, 82, 69, 2, 207, 203, 12, 69, + 148, 180, 3, 3, 55, 32, 75, 237, 239, 15, 5, 56, 32, 75, 65, 78, 4, 56, + 3, 53, 32, 77, 233, 132, 16, 5, 51, 32, 65, 82, 69, 2, 195, 214, 12, 69, 176, 1, 84, 9, 76, 76, 65, 66, 76, 69, 32, 66, 48, 229, 12, 7, 77, 66, 79, 76, 32, 66, 48, 148, 1, 114, 48, 142, 1, 49, 162, 1, 50, 230, 1, 51, 174, 1, 52, 162, 1, 53, 154, 1, 54, 186, 1, 55, 198, 1, 56, 87, 57, 18, - 118, 54, 150, 198, 1, 55, 150, 8, 52, 190, 14, 57, 194, 246, 10, 53, 250, - 146, 2, 56, 198, 10, 49, 254, 2, 50, 207, 8, 51, 2, 183, 234, 17, 32, 16, - 122, 54, 18, 55, 190, 207, 1, 49, 134, 2, 50, 166, 26, 52, 248, 186, 1, - 2, 53, 32, 250, 242, 5, 48, 221, 243, 8, 2, 51, 32, 2, 183, 90, 32, 2, - 143, 133, 11, 32, 18, 166, 1, 51, 22, 54, 20, 3, 57, 32, 80, 224, 6, 2, - 53, 32, 220, 174, 3, 2, 48, 32, 196, 205, 14, 2, 55, 32, 140, 7, 2, 52, - 32, 158, 89, 56, 185, 44, 3, 49, 32, 81, 2, 215, 164, 14, 32, 2, 171, - 234, 14, 32, 2, 139, 138, 12, 85, 16, 134, 1, 48, 20, 2, 51, 32, 154, - 195, 1, 55, 254, 34, 54, 158, 241, 4, 57, 234, 163, 2, 56, 250, 168, 4, - 49, 133, 223, 5, 3, 50, 32, 81, 2, 151, 166, 14, 32, 2, 135, 1, 82, 16, - 116, 2, 51, 32, 22, 53, 142, 191, 1, 48, 222, 1, 49, 134, 6, 50, 218, 10, - 52, 178, 5, 54, 241, 216, 12, 3, 56, 32, 78, 2, 247, 170, 15, 65, 2, 223, - 144, 17, 32, 18, 130, 1, 51, 190, 191, 1, 49, 150, 1, 56, 42, 57, 102, - 55, 214, 5, 48, 194, 141, 2, 52, 212, 161, 15, 2, 50, 32, 157, 4, 2, 53, - 32, 2, 135, 194, 12, 32, 16, 132, 1, 2, 50, 32, 20, 2, 56, 32, 204, 1, 3, - 54, 32, 84, 178, 186, 1, 55, 226, 3, 57, 146, 2, 53, 206, 247, 6, 49, - 151, 154, 10, 48, 2, 191, 215, 17, 80, 2, 245, 132, 12, 2, 82, 79, 18, - 172, 1, 3, 54, 32, 82, 210, 186, 1, 55, 158, 8, 48, 170, 16, 53, 12, 3, - 49, 32, 68, 132, 169, 7, 2, 52, 32, 250, 249, 3, 50, 232, 143, 6, 3, 56, - 32, 81, 241, 2, 2, 51, 32, 2, 171, 131, 12, 65, 8, 206, 186, 1, 49, 188, - 24, 3, 55, 32, 84, 192, 249, 6, 2, 53, 32, 183, 146, 6, 48, 4, 154, 228, - 12, 49, 21, 3, 48, 32, 68, 28, 90, 52, 30, 54, 30, 56, 174, 253, 11, 53, - 158, 2, 49, 30, 51, 166, 1, 50, 235, 163, 3, 55, 4, 234, 154, 19, 55, 3, - 57, 4, 206, 154, 19, 51, 3, 52, 8, 178, 154, 19, 50, 2, 51, 2, 54, 3, 57, - 4, 136, 202, 10, 9, 69, 68, 32, 80, 65, 80, 69, 82, 67, 227, 188, 7, 32, - 5, 195, 233, 17, 84, 98, 96, 7, 76, 69, 84, 84, 69, 82, 32, 169, 234, 6, - 11, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 94, 238, 1, 84, 230, 240, - 2, 68, 178, 159, 10, 85, 150, 149, 2, 78, 138, 30, 69, 234, 139, 3, 67, + 118, 54, 182, 203, 1, 55, 130, 8, 52, 190, 14, 57, 170, 252, 10, 53, 158, + 152, 2, 56, 198, 10, 49, 254, 2, 50, 207, 8, 51, 2, 151, 129, 18, 32, 16, + 122, 54, 18, 55, 202, 212, 1, 49, 134, 2, 50, 166, 26, 52, 176, 187, 1, + 2, 53, 32, 158, 247, 5, 48, 229, 128, 9, 2, 51, 32, 2, 171, 95, 32, 2, + 235, 143, 11, 32, 18, 166, 1, 51, 22, 54, 20, 3, 57, 32, 80, 224, 6, 2, + 53, 32, 168, 180, 3, 2, 48, 32, 232, 222, 14, 2, 55, 32, 140, 7, 2, 52, + 32, 162, 91, 56, 185, 44, 3, 49, 32, 81, 2, 247, 180, 14, 32, 2, 195, + 250, 14, 32, 2, 235, 148, 12, 85, 16, 134, 1, 48, 20, 2, 51, 32, 186, + 200, 1, 55, 234, 34, 54, 218, 241, 4, 57, 210, 165, 2, 56, 246, 171, 4, + 49, 205, 237, 5, 3, 50, 32, 81, 2, 183, 182, 14, 32, 2, 135, 1, 82, 16, + 116, 2, 51, 32, 22, 53, 174, 196, 1, 48, 222, 1, 49, 242, 5, 50, 218, 10, + 52, 178, 5, 54, 133, 228, 12, 3, 56, 32, 78, 2, 151, 191, 15, 65, 2, 235, + 166, 17, 32, 18, 130, 1, 51, 222, 196, 1, 49, 150, 1, 56, 42, 57, 102, + 55, 194, 5, 48, 250, 141, 2, 52, 132, 181, 15, 2, 50, 32, 157, 4, 2, 53, + 32, 2, 251, 204, 12, 32, 16, 132, 1, 2, 50, 32, 20, 2, 56, 32, 204, 1, 3, + 54, 32, 84, 210, 191, 1, 55, 226, 3, 57, 146, 2, 53, 198, 248, 6, 49, + 243, 172, 10, 48, 2, 151, 238, 17, 80, 2, 213, 143, 12, 2, 82, 79, 18, + 172, 1, 3, 54, 32, 82, 242, 191, 1, 55, 138, 8, 48, 170, 16, 53, 12, 3, + 49, 32, 68, 168, 171, 7, 2, 52, 32, 222, 252, 3, 50, 200, 158, 6, 3, 56, + 32, 81, 241, 2, 2, 51, 32, 2, 139, 142, 12, 65, 8, 238, 191, 1, 49, 168, + 24, 3, 55, 32, 84, 196, 250, 6, 2, 53, 32, 191, 156, 6, 48, 4, 150, 160, + 17, 49, 21, 3, 48, 32, 68, 28, 90, 52, 30, 54, 30, 56, 142, 136, 12, 53, + 158, 2, 49, 30, 51, 166, 1, 50, 171, 173, 3, 55, 4, 222, 179, 19, 55, 3, + 57, 4, 194, 179, 19, 51, 3, 52, 8, 166, 179, 19, 50, 2, 51, 2, 54, 3, 57, + 4, 228, 212, 10, 9, 69, 68, 32, 80, 65, 80, 69, 82, 67, 223, 200, 7, 32, + 5, 163, 128, 18, 84, 98, 96, 7, 76, 69, 84, 84, 69, 82, 32, 129, 240, 6, + 11, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 94, 238, 1, 84, 150, 246, + 2, 68, 182, 164, 10, 85, 130, 159, 2, 78, 138, 31, 69, 190, 143, 3, 67, 2, 71, 2, 72, 2, 75, 2, 80, 2, 83, 2, 89, 2, 90, 162, 7, 65, 2, 79, 234, 61, 66, 2, 70, 2, 74, 2, 76, 2, 77, 2, 87, 2, 88, 187, 2, 73, 20, 64, 4, - 79, 78, 69, 32, 214, 206, 18, 83, 138, 69, 72, 187, 2, 65, 12, 48, 4, 77, - 89, 65, 32, 129, 192, 1, 2, 78, 65, 10, 130, 183, 12, 74, 234, 191, 6, - 66, 158, 11, 84, 254, 16, 67, 39, 78, 196, 2, 232, 1, 2, 67, 75, 132, 1, - 3, 71, 73, 67, 176, 6, 3, 78, 71, 32, 222, 4, 84, 116, 3, 86, 69, 32, 70, - 87, 172, 12, 5, 90, 69, 78, 71, 69, 134, 231, 7, 66, 148, 138, 10, 8, 85, + 79, 78, 69, 32, 202, 231, 18, 83, 138, 69, 72, 187, 2, 65, 12, 48, 4, 77, + 89, 65, 32, 141, 197, 1, 2, 78, 65, 10, 246, 193, 12, 74, 234, 205, 6, + 66, 158, 11, 84, 254, 16, 67, 39, 78, 210, 2, 232, 1, 2, 67, 75, 132, 1, + 3, 71, 73, 67, 176, 6, 3, 78, 71, 32, 206, 9, 84, 116, 3, 86, 69, 32, 70, + 87, 172, 12, 5, 90, 69, 78, 71, 69, 174, 232, 7, 66, 240, 156, 10, 8, 85, 68, 76, 89, 32, 67, 82, 89, 141, 15, 4, 76, 76, 73, 80, 9, 96, 10, 73, - 78, 71, 45, 83, 72, 73, 70, 84, 32, 153, 20, 9, 32, 87, 73, 84, 72, 32, - 73, 78, 75, 4, 162, 163, 17, 90, 251, 85, 79, 40, 56, 6, 32, 71, 65, 84, + 78, 71, 45, 83, 72, 73, 70, 84, 32, 137, 25, 9, 32, 87, 73, 84, 72, 32, + 73, 78, 75, 4, 174, 185, 17, 90, 223, 86, 79, 40, 56, 6, 32, 71, 65, 84, 69, 32, 137, 2, 3, 65, 76, 32, 12, 104, 6, 66, 85, 70, 70, 69, 82, 84, 9, - 73, 78, 86, 69, 82, 84, 69, 68, 32, 182, 130, 18, 65, 159, 85, 79, 5, + 73, 78, 86, 69, 82, 84, 69, 68, 32, 142, 153, 18, 65, 187, 87, 79, 5, 133, 1, 17, 32, 87, 73, 84, 72, 32, 73, 78, 86, 69, 82, 84, 69, 68, 32, - 73, 78, 4, 48, 3, 79, 85, 84, 129, 154, 6, 3, 73, 78, 80, 2, 167, 150, + 73, 78, 4, 48, 3, 79, 85, 84, 205, 159, 6, 3, 73, 78, 80, 2, 155, 175, 18, 80, 28, 36, 3, 65, 78, 68, 85, 2, 79, 82, 15, 33, 6, 32, 87, 73, 84, - 72, 32, 12, 226, 1, 68, 94, 72, 58, 77, 151, 161, 15, 85, 15, 11, 32, 12, + 72, 32, 12, 226, 1, 68, 94, 72, 58, 77, 147, 182, 15, 85, 15, 11, 32, 12, 88, 13, 79, 86, 69, 82, 76, 65, 80, 80, 73, 78, 71, 32, 76, 49, 5, 87, - 73, 84, 72, 32, 2, 249, 255, 17, 7, 79, 71, 73, 67, 65, 76, 32, 10, 26, - 68, 94, 72, 59, 77, 6, 11, 79, 6, 44, 5, 85, 66, 76, 69, 32, 247, 143, - 18, 84, 4, 234, 161, 15, 85, 235, 60, 79, 2, 177, 207, 15, 9, 79, 82, 73, - 90, 79, 78, 84, 65, 76, 2, 225, 218, 7, 5, 73, 68, 68, 76, 69, 34, 66, - 68, 228, 1, 4, 76, 69, 70, 84, 109, 5, 82, 73, 71, 72, 84, 6, 164, 1, 30, - 65, 83, 72, 32, 70, 82, 79, 77, 32, 76, 69, 70, 84, 32, 77, 69, 77, 66, - 69, 82, 32, 79, 70, 32, 68, 79, 85, 66, 76, 69, 166, 144, 16, 73, 219, - 208, 1, 82, 2, 17, 2, 32, 86, 2, 181, 128, 18, 5, 69, 82, 84, 73, 67, 16, - 18, 32, 119, 87, 6, 48, 6, 82, 73, 71, 72, 84, 32, 139, 238, 15, 84, 4, - 246, 227, 15, 68, 215, 138, 2, 65, 12, 26, 87, 139, 244, 8, 32, 10, 29, - 5, 65, 82, 68, 83, 32, 10, 82, 65, 0, 8, 68, 79, 85, 66, 76, 69, 32, 65, - 221, 227, 7, 4, 83, 81, 85, 73, 4, 25, 4, 82, 82, 79, 87, 5, 137, 162, - 16, 2, 32, 70, 6, 92, 5, 73, 79, 78, 32, 66, 144, 237, 17, 9, 32, 79, 70, - 32, 70, 79, 82, 84, 85, 211, 91, 85, 2, 211, 235, 9, 79, 4, 38, 76, 157, - 249, 13, 3, 72, 79, 84, 2, 133, 206, 17, 2, 69, 84, 222, 1, 34, 32, 229, - 1, 3, 69, 82, 32, 14, 138, 1, 66, 196, 195, 10, 11, 68, 79, 85, 66, 76, - 69, 32, 80, 82, 73, 77, 154, 173, 6, 65, 204, 111, 6, 75, 65, 86, 89, 75, - 65, 211, 10, 76, 4, 38, 82, 249, 248, 4, 3, 65, 84, 84, 2, 209, 240, 17, - 7, 73, 71, 72, 84, 78, 69, 83, 208, 1, 158, 1, 72, 140, 2, 5, 76, 69, 70, - 84, 32, 236, 2, 6, 82, 73, 71, 72, 84, 32, 234, 230, 15, 66, 74, 67, 74, - 70, 234, 10, 77, 150, 2, 79, 166, 18, 83, 67, 84, 20, 84, 4, 65, 76, 70, - 32, 241, 184, 7, 11, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 82, 18, 212, - 164, 7, 9, 65, 78, 68, 32, 85, 80, 80, 69, 82, 32, 7, 73, 78, 86, 69, 82, - 83, 69, 194, 201, 8, 72, 230, 1, 86, 170, 26, 77, 130, 3, 76, 22, 82, - 202, 5, 66, 195, 156, 1, 67, 72, 186, 1, 66, 60, 8, 70, 79, 85, 78, 84, - 65, 73, 78, 22, 80, 56, 12, 83, 69, 77, 73, 67, 73, 82, 67, 85, 76, 65, - 82, 154, 1, 81, 246, 2, 84, 248, 191, 11, 3, 67, 82, 65, 139, 177, 4, 79, - 24, 56, 8, 65, 76, 76, 80, 79, 73, 78, 84, 255, 246, 15, 76, 2, 179, 240, - 9, 32, 4, 212, 243, 14, 5, 65, 73, 78, 84, 66, 163, 140, 1, 69, 2, 221, - 193, 7, 5, 32, 65, 78, 84, 73, 74, 110, 81, 166, 2, 83, 82, 84, 238, 176, - 7, 82, 202, 184, 8, 66, 238, 3, 67, 226, 3, 79, 222, 7, 68, 207, 2, 80, - 30, 17, 2, 85, 65, 30, 48, 6, 68, 82, 65, 78, 84, 32, 187, 130, 16, 82, - 28, 74, 70, 60, 2, 78, 69, 50, 83, 226, 253, 15, 67, 226, 1, 77, 143, 1, - 84, 4, 26, 65, 255, 180, 17, 82, 2, 185, 183, 7, 3, 67, 69, 32, 2, 25, 4, - 85, 84, 82, 65, 2, 191, 189, 18, 76, 4, 254, 218, 10, 77, 143, 165, 5, - 84, 6, 148, 190, 7, 11, 69, 77, 73, 67, 73, 82, 67, 85, 76, 65, 82, 231, - 194, 8, 72, 6, 226, 129, 16, 82, 155, 1, 87, 5, 141, 213, 17, 25, 32, 68, - 73, 86, 73, 68, 69, 68, 32, 66, 89, 32, 72, 79, 82, 73, 90, 79, 78, 84, - 65, 76, 32, 82, 85, 6, 18, 71, 23, 78, 2, 215, 241, 13, 71, 4, 188, 213, - 17, 5, 65, 82, 32, 69, 67, 255, 100, 71, 114, 104, 12, 67, 73, 65, 78, - 32, 76, 69, 84, 84, 69, 82, 32, 228, 1, 5, 68, 73, 65, 78, 32, 131, 237, - 17, 73, 58, 206, 1, 77, 194, 137, 5, 75, 206, 203, 9, 66, 50, 84, 234, - 164, 2, 65, 2, 69, 2, 78, 134, 251, 1, 68, 2, 71, 2, 72, 2, 73, 2, 74, 2, - 76, 2, 80, 2, 81, 2, 82, 2, 83, 2, 85, 2, 87, 2, 88, 3, 90, 5, 167, 245, - 18, 77, 54, 88, 7, 76, 69, 84, 84, 69, 82, 32, 189, 213, 14, 9, 84, 82, - 73, 65, 78, 71, 85, 76, 65, 52, 214, 148, 13, 84, 174, 192, 1, 76, 198, - 152, 2, 83, 238, 11, 65, 2, 69, 2, 78, 134, 251, 1, 66, 2, 67, 2, 68, 2, - 70, 2, 71, 2, 73, 2, 75, 2, 77, 2, 79, 2, 81, 2, 82, 2, 85, 2, 86, 3, 89, - 248, 53, 162, 1, 65, 206, 103, 69, 246, 102, 73, 154, 25, 79, 148, 112, - 3, 82, 79, 32, 234, 3, 85, 192, 70, 7, 89, 65, 78, 77, 65, 82, 32, 218, - 145, 15, 86, 198, 61, 77, 27, 87, 204, 23, 186, 1, 71, 62, 72, 254, 10, - 75, 234, 3, 76, 252, 13, 2, 77, 77, 22, 78, 154, 17, 80, 118, 82, 174, 7, - 83, 190, 7, 84, 196, 36, 3, 89, 65, 78, 140, 129, 1, 3, 88, 73, 77, 247, - 230, 15, 67, 6, 128, 226, 17, 4, 73, 67, 32, 87, 238, 88, 78, 155, 53, - 69, 166, 1, 84, 6, 65, 74, 65, 78, 73, 32, 129, 3, 10, 74, 79, 78, 71, - 32, 84, 73, 76, 69, 32, 78, 38, 76, 162, 2, 83, 207, 129, 13, 65, 72, 88, - 6, 69, 84, 84, 69, 82, 32, 161, 144, 12, 10, 73, 71, 65, 84, 85, 82, 69, - 32, 83, 72, 70, 182, 174, 3, 78, 186, 229, 11, 68, 82, 82, 34, 84, 206, - 145, 3, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, - 2, 83, 2, 86, 186, 2, 65, 2, 69, 2, 73, 2, 79, 3, 85, 4, 226, 235, 6, 69, - 229, 236, 7, 5, 73, 71, 78, 32, 78, 88, 236, 1, 2, 66, 65, 38, 69, 46, - 70, 46, 78, 42, 79, 46, 80, 22, 83, 118, 84, 194, 1, 87, 112, 5, 71, 82, - 69, 69, 78, 0, 3, 82, 69, 68, 208, 135, 6, 3, 65, 85, 84, 214, 21, 74, - 197, 158, 11, 11, 67, 72, 82, 89, 83, 65, 78, 84, 72, 69, 77, 4, 138, - 158, 1, 77, 223, 200, 17, 67, 8, 228, 2, 4, 73, 71, 72, 84, 195, 1, 65, - 12, 172, 2, 2, 73, 86, 13, 3, 79, 85, 82, 8, 192, 1, 2, 79, 82, 65, 2, - 73, 78, 8, 218, 1, 78, 189, 223, 11, 3, 82, 67, 72, 2, 159, 191, 17, 76, - 18, 88, 2, 79, 85, 76, 4, 69, 86, 69, 78, 0, 2, 73, 88, 198, 151, 12, 85, - 187, 194, 1, 80, 2, 157, 2, 2, 84, 72, 12, 36, 3, 72, 82, 69, 13, 2, 87, - 79, 6, 11, 69, 6, 25, 4, 32, 79, 70, 32, 6, 46, 67, 229, 246, 6, 5, 66, - 65, 77, 66, 79, 4, 224, 139, 6, 2, 73, 82, 217, 217, 10, 5, 72, 65, 82, - 65, 67, 6, 50, 69, 60, 4, 72, 73, 84, 69, 247, 172, 17, 73, 2, 17, 2, 83, - 84, 2, 17, 2, 32, 87, 2, 147, 215, 17, 73, 2, 17, 2, 32, 68, 2, 183, 172, - 17, 82, 52, 52, 5, 65, 83, 65, 82, 32, 233, 251, 14, 2, 69, 77, 50, 162, - 1, 69, 40, 7, 76, 69, 84, 84, 69, 82, 32, 152, 1, 5, 80, 65, 83, 83, 73, - 32, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 173, 216, 18, 3, 65, - 78, 71, 2, 161, 228, 15, 5, 78, 68, 32, 79, 70, 36, 158, 232, 16, 78, - 246, 247, 1, 66, 2, 67, 2, 68, 2, 71, 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, - 2, 82, 2, 83, 2, 84, 2, 86, 2, 89, 187, 2, 65, 2, 11, 77, 2, 211, 136, - 18, 66, 8, 146, 225, 18, 69, 2, 73, 2, 79, 3, 85, 246, 1, 80, 7, 65, 89, - 65, 76, 65, 77, 32, 176, 11, 2, 69, 32, 225, 1, 3, 84, 69, 83, 236, 1, - 198, 1, 68, 44, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 240, 1, 7, 76, 69, - 84, 84, 69, 82, 32, 164, 5, 7, 78, 85, 77, 66, 69, 82, 32, 36, 5, 83, 73, - 71, 78, 32, 178, 180, 13, 86, 247, 196, 1, 65, 22, 204, 169, 8, 2, 65, - 84, 227, 195, 8, 73, 26, 56, 4, 79, 78, 69, 32, 121, 6, 84, 72, 82, 69, - 69, 32, 18, 82, 84, 146, 135, 5, 83, 230, 249, 7, 70, 62, 79, 130, 216, - 3, 69, 46, 72, 47, 81, 4, 254, 131, 13, 87, 239, 214, 3, 69, 8, 170, 135, - 5, 83, 170, 253, 7, 69, 110, 84, 163, 214, 3, 81, 132, 1, 226, 1, 65, 82, - 67, 158, 1, 68, 78, 84, 82, 86, 218, 130, 13, 78, 146, 251, 1, 76, 38, - 82, 134, 6, 85, 202, 141, 1, 79, 134, 60, 73, 206, 193, 1, 83, 82, 66, 2, - 71, 2, 74, 2, 75, 2, 80, 162, 7, 69, 234, 61, 72, 2, 77, 3, 89, 11, 192, - 151, 16, 7, 82, 67, 72, 65, 73, 67, 32, 254, 194, 2, 65, 2, 73, 3, 85, - 22, 26, 72, 215, 217, 18, 65, 20, 44, 5, 73, 76, 76, 85, 32, 167, 217, - 18, 65, 18, 130, 249, 12, 76, 158, 229, 3, 78, 170, 194, 1, 82, 222, 56, - 75, 2, 77, 3, 89, 10, 220, 220, 10, 4, 79, 84, 32, 82, 182, 180, 7, 68, - 138, 69, 72, 187, 2, 65, 10, 38, 84, 170, 213, 18, 72, 187, 2, 65, 6, - 166, 213, 18, 72, 2, 84, 187, 2, 65, 12, 166, 227, 3, 69, 138, 161, 11, - 79, 139, 211, 3, 65, 6, 154, 131, 13, 79, 131, 128, 4, 84, 18, 50, 67, - 114, 86, 206, 254, 14, 65, 167, 146, 3, 80, 6, 54, 79, 120, 5, 73, 82, - 67, 85, 76, 203, 192, 14, 65, 2, 221, 178, 13, 9, 77, 66, 73, 78, 73, 78, - 71, 32, 65, 6, 60, 9, 69, 82, 84, 73, 67, 65, 76, 32, 66, 255, 145, 18, - 73, 2, 209, 254, 14, 2, 65, 82, 8, 80, 12, 87, 73, 84, 72, 32, 83, 84, - 82, 79, 75, 69, 32, 70, 65, 227, 204, 17, 83, 4, 64, 10, 65, 78, 68, 32, - 77, 65, 76, 69, 32, 65, 227, 204, 17, 83, 2, 25, 4, 78, 68, 32, 70, 2, - 11, 69, 2, 11, 77, 2, 231, 209, 7, 65, 2, 211, 145, 17, 69, 2, 219, 208, - 16, 79, 185, 1, 210, 1, 32, 220, 2, 5, 68, 65, 73, 67, 32, 224, 3, 8, 73, - 67, 72, 65, 69, 65, 78, 32, 222, 8, 83, 216, 165, 2, 3, 85, 65, 76, 190, - 217, 10, 65, 152, 168, 1, 8, 84, 69, 76, 80, 73, 69, 67, 69, 203, 251, 3, - 71, 12, 132, 1, 3, 73, 78, 32, 128, 1, 5, 87, 73, 84, 72, 32, 204, 146, - 2, 3, 68, 65, 78, 253, 252, 12, 8, 65, 78, 68, 32, 87, 79, 77, 65, 4, - 144, 135, 10, 19, 66, 85, 83, 73, 78, 69, 83, 83, 32, 83, 85, 73, 84, 32, - 76, 69, 86, 73, 84, 185, 151, 1, 4, 84, 85, 88, 69, 4, 224, 231, 13, 8, - 71, 85, 65, 32, 80, 73, 32, 77, 149, 157, 3, 4, 84, 85, 82, 66, 58, 112, - 4, 65, 70, 70, 82, 28, 7, 76, 69, 84, 84, 69, 82, 32, 244, 173, 14, 3, - 86, 79, 67, 146, 67, 71, 251, 25, 80, 2, 249, 227, 17, 2, 73, 67, 50, 82, - 65, 176, 1, 2, 68, 85, 2, 85, 28, 3, 72, 65, 76, 22, 73, 183, 132, 18, - 75, 38, 154, 1, 75, 198, 235, 12, 84, 146, 192, 1, 83, 242, 207, 3, 73, - 226, 79, 66, 2, 68, 2, 71, 2, 72, 2, 76, 2, 77, 2, 78, 2, 80, 2, 81, 2, - 82, 3, 90, 5, 235, 200, 18, 83, 2, 153, 131, 8, 2, 83, 72, 2, 187, 200, - 18, 81, 4, 222, 202, 18, 78, 3, 84, 102, 216, 1, 7, 76, 69, 84, 84, 69, - 82, 32, 194, 4, 78, 80, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, - 32, 220, 1, 4, 83, 73, 71, 78, 129, 195, 10, 16, 65, 66, 66, 82, 69, 86, - 73, 65, 84, 73, 79, 78, 32, 77, 65, 82, 72, 218, 1, 65, 46, 66, 38, 68, - 30, 71, 30, 74, 2, 90, 30, 75, 30, 81, 38, 83, 50, 84, 54, 88, 234, 162, - 6, 76, 158, 206, 1, 82, 154, 217, 2, 89, 158, 208, 1, 72, 222, 169, 5, - 78, 134, 2, 87, 218, 103, 70, 2, 80, 171, 4, 77, 6, 150, 203, 10, 76, - 122, 65, 171, 251, 6, 89, 4, 254, 237, 12, 72, 211, 214, 3, 69, 4, 202, - 164, 6, 65, 23, 72, 4, 190, 202, 10, 72, 15, 73, 4, 250, 202, 10, 72, 15, - 65, 4, 194, 161, 12, 72, 15, 65, 4, 158, 164, 6, 72, 151, 253, 5, 79, 8, - 194, 199, 10, 83, 154, 3, 65, 251, 250, 6, 72, 6, 154, 163, 6, 72, 206, - 159, 10, 69, 243, 131, 1, 65, 4, 170, 160, 12, 65, 3, 79, 10, 33, 6, 85, - 77, 66, 69, 82, 32, 10, 130, 202, 10, 79, 58, 84, 135, 198, 2, 70, 14, - 80, 2, 68, 79, 116, 3, 76, 73, 78, 134, 167, 5, 70, 186, 202, 11, 84, - 167, 10, 83, 6, 54, 84, 13, 9, 85, 66, 76, 69, 32, 68, 79, 84, 32, 5, 11, - 32, 2, 25, 4, 87, 73, 84, 72, 2, 199, 192, 2, 73, 2, 155, 203, 3, 69, 2, - 159, 150, 17, 32, 2, 11, 32, 2, 249, 170, 18, 2, 83, 72, 4, 92, 17, 32, - 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 76, 73, 71, 72, 84, 147, 214, - 10, 76, 2, 135, 252, 14, 72, 142, 1, 142, 1, 65, 20, 5, 67, 72, 69, 78, - 32, 144, 163, 6, 4, 82, 73, 65, 71, 193, 157, 11, 13, 84, 73, 65, 76, 32, - 65, 82, 84, 83, 32, 85, 78, 73, 2, 171, 161, 5, 67, 136, 1, 152, 1, 7, - 76, 69, 84, 84, 69, 82, 32, 194, 1, 83, 236, 2, 11, 86, 79, 87, 69, 76, - 32, 83, 73, 71, 78, 32, 170, 237, 17, 72, 225, 5, 4, 77, 65, 82, 75, 60, - 254, 3, 84, 146, 148, 2, 68, 202, 171, 14, 78, 238, 178, 1, 67, 2, 75, 2, - 80, 2, 83, 2, 90, 138, 69, 45, 2, 66, 2, 71, 2, 72, 2, 74, 2, 76, 2, 77, - 2, 82, 2, 87, 2, 89, 187, 2, 65, 62, 96, 4, 73, 71, 78, 32, 37, 16, 85, - 66, 74, 79, 73, 78, 69, 68, 32, 76, 69, 84, 84, 69, 82, 32, 4, 158, 167, - 14, 67, 203, 207, 3, 65, 58, 182, 1, 84, 146, 148, 2, 68, 202, 171, 14, - 78, 238, 178, 1, 67, 2, 75, 2, 80, 2, 83, 2, 90, 138, 69, 66, 2, 71, 2, - 72, 2, 74, 2, 76, 2, 77, 2, 82, 2, 87, 2, 89, 187, 2, 65, 8, 194, 242, - 17, 83, 138, 69, 72, 187, 2, 65, 10, 158, 183, 18, 65, 186, 2, 69, 2, 73, - 2, 79, 3, 85, 156, 1, 120, 11, 65, 82, 65, 77, 32, 71, 79, 78, 68, 73, - 32, 232, 5, 3, 67, 85, 76, 64, 5, 75, 32, 87, 79, 82, 183, 240, 17, 85, - 150, 1, 100, 7, 76, 69, 84, 84, 69, 82, 32, 178, 2, 82, 56, 5, 83, 73, - 71, 78, 32, 82, 86, 223, 194, 16, 68, 94, 210, 1, 74, 42, 84, 154, 219, - 14, 65, 38, 68, 214, 6, 85, 206, 201, 1, 73, 42, 76, 214, 192, 1, 75, 38, - 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 80, 138, 69, 72, 2, 77, 2, 82, 2, - 86, 2, 89, 186, 2, 69, 3, 79, 6, 130, 179, 18, 78, 38, 72, 187, 2, 65, - 10, 246, 237, 17, 84, 138, 69, 72, 2, 82, 187, 2, 65, 4, 32, 2, 65, 45, - 175, 220, 14, 69, 2, 147, 240, 17, 75, 10, 178, 176, 1, 67, 198, 196, 12, - 72, 246, 43, 78, 186, 221, 1, 86, 179, 241, 1, 65, 22, 26, 79, 139, 251, - 15, 73, 20, 45, 9, 87, 69, 76, 32, 83, 73, 71, 78, 32, 20, 74, 86, 154, - 223, 14, 65, 38, 85, 206, 201, 1, 73, 222, 137, 2, 69, 3, 79, 2, 233, - 201, 7, 6, 79, 67, 65, 76, 73, 67, 2, 145, 249, 17, 11, 73, 78, 69, 32, - 79, 82, 68, 73, 78, 65, 76, 2, 207, 158, 17, 75, 226, 15, 76, 10, 72, 69, - 77, 65, 84, 73, 67, 65, 76, 32, 237, 207, 14, 3, 69, 32, 68, 224, 15, - 252, 1, 5, 66, 79, 76, 68, 32, 168, 6, 14, 68, 79, 85, 66, 76, 69, 45, - 83, 84, 82, 85, 67, 75, 32, 238, 1, 70, 164, 2, 7, 73, 84, 65, 76, 73, - 67, 32, 180, 3, 10, 77, 79, 78, 79, 83, 80, 65, 67, 69, 32, 40, 2, 82, - 73, 36, 3, 76, 69, 70, 167, 1, 83, 160, 5, 176, 1, 8, 67, 65, 80, 73, 84, - 65, 76, 32, 130, 2, 83, 210, 14, 73, 222, 3, 69, 38, 75, 38, 78, 30, 80, - 98, 82, 242, 5, 84, 56, 7, 70, 82, 65, 75, 84, 85, 82, 159, 160, 16, 68, - 104, 190, 4, 68, 174, 15, 84, 186, 4, 65, 22, 66, 2, 90, 42, 69, 98, 71, - 22, 73, 22, 75, 34, 76, 22, 79, 50, 80, 42, 82, 22, 83, 70, 85, 142, 197, - 1, 67, 214, 249, 12, 77, 2, 78, 206, 201, 1, 88, 222, 137, 2, 70, 2, 72, - 2, 74, 2, 81, 2, 86, 2, 87, 3, 89, 208, 1, 60, 5, 77, 65, 76, 76, 32, - 213, 25, 5, 67, 82, 73, 80, 84, 104, 250, 1, 68, 230, 19, 65, 22, 66, 2, - 90, 42, 69, 38, 70, 62, 71, 22, 73, 22, 75, 34, 76, 22, 79, 50, 80, 42, - 82, 22, 83, 34, 84, 38, 85, 142, 197, 1, 67, 214, 249, 12, 77, 2, 78, - 206, 201, 1, 88, 222, 137, 2, 72, 2, 74, 2, 81, 2, 86, 2, 87, 3, 89, 7, - 26, 73, 235, 239, 14, 69, 2, 187, 213, 1, 71, 110, 68, 8, 67, 65, 80, 73, - 84, 65, 76, 32, 162, 23, 83, 223, 159, 16, 68, 38, 154, 168, 18, 65, 2, - 66, 2, 68, 2, 69, 2, 70, 2, 71, 2, 73, 2, 74, 2, 75, 2, 76, 2, 77, 2, 79, - 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, 3, 89, 96, 52, 7, 82, 65, 75, - 84, 85, 82, 32, 219, 142, 7, 65, 94, 52, 8, 67, 65, 80, 73, 84, 65, 76, - 32, 143, 21, 83, 42, 134, 166, 18, 65, 2, 66, 2, 68, 2, 69, 2, 70, 2, 71, - 2, 74, 2, 75, 2, 76, 2, 77, 2, 78, 2, 79, 2, 80, 2, 81, 2, 83, 2, 84, 2, - 85, 2, 86, 2, 87, 2, 88, 3, 89, 222, 1, 100, 6, 83, 77, 65, 76, 76, 32, - 222, 7, 67, 230, 2, 69, 38, 75, 38, 78, 30, 80, 98, 82, 243, 5, 84, 104, - 242, 1, 68, 198, 12, 65, 22, 66, 2, 90, 42, 69, 38, 70, 62, 71, 22, 73, - 22, 75, 34, 76, 22, 79, 50, 80, 42, 82, 22, 83, 34, 84, 38, 85, 142, 197, - 1, 67, 214, 249, 12, 77, 2, 78, 206, 201, 1, 88, 222, 137, 2, 74, 2, 81, - 2, 86, 2, 87, 3, 89, 9, 52, 7, 79, 84, 76, 69, 83, 83, 32, 175, 232, 14, - 69, 4, 186, 161, 18, 73, 3, 74, 124, 130, 16, 67, 34, 83, 223, 159, 16, - 68, 12, 32, 2, 71, 72, 131, 137, 7, 83, 10, 17, 2, 84, 32, 10, 112, 6, - 87, 72, 73, 84, 69, 32, 170, 244, 5, 68, 234, 106, 65, 241, 230, 4, 9, - 70, 76, 65, 84, 84, 69, 78, 69, 68, 4, 130, 165, 14, 83, 39, 84, 130, 6, - 84, 10, 65, 78, 83, 45, 83, 69, 82, 73, 70, 32, 133, 14, 6, 67, 82, 73, - 80, 84, 32, 176, 5, 96, 5, 66, 79, 76, 68, 32, 176, 12, 6, 73, 84, 65, - 76, 73, 67, 34, 67, 34, 83, 223, 159, 16, 68, 204, 3, 98, 73, 122, 67, - 230, 2, 69, 38, 75, 38, 78, 30, 80, 98, 82, 30, 83, 214, 5, 84, 215, 160, - 16, 68, 220, 1, 33, 6, 84, 65, 76, 73, 67, 32, 220, 1, 74, 67, 230, 2, - 69, 38, 75, 38, 78, 30, 80, 98, 82, 30, 83, 215, 5, 84, 102, 37, 7, 65, - 80, 73, 84, 65, 76, 32, 102, 250, 1, 84, 186, 4, 65, 22, 66, 2, 90, 22, - 68, 22, 69, 98, 71, 22, 73, 22, 75, 34, 76, 22, 79, 50, 80, 42, 82, 22, - 83, 70, 85, 142, 197, 1, 67, 214, 249, 12, 77, 2, 78, 206, 201, 1, 88, - 222, 137, 2, 70, 2, 72, 2, 74, 2, 81, 2, 86, 2, 87, 3, 89, 9, 40, 4, 72, - 69, 84, 65, 215, 244, 17, 65, 5, 159, 134, 17, 32, 2, 213, 161, 16, 4, - 80, 83, 73, 76, 2, 17, 2, 65, 80, 2, 159, 7, 80, 2, 197, 246, 17, 2, 65, - 66, 6, 74, 72, 172, 149, 5, 8, 65, 82, 84, 73, 65, 76, 32, 68, 167, 239, - 11, 73, 2, 207, 132, 17, 73, 2, 185, 132, 17, 2, 72, 79, 102, 29, 5, 77, - 65, 76, 76, 32, 102, 246, 1, 65, 22, 66, 2, 90, 22, 68, 22, 69, 38, 70, - 62, 71, 22, 73, 22, 75, 34, 76, 22, 79, 50, 80, 42, 82, 22, 83, 34, 84, - 38, 85, 142, 197, 1, 67, 214, 249, 12, 77, 2, 78, 206, 201, 1, 88, 222, - 137, 2, 72, 2, 74, 2, 81, 2, 86, 2, 87, 3, 89, 5, 251, 188, 14, 76, 5, - 207, 240, 17, 69, 5, 247, 219, 14, 69, 7, 186, 212, 1, 80, 131, 190, 16, - 84, 5, 11, 73, 2, 29, 5, 78, 65, 76, 32, 83, 2, 227, 1, 73, 5, 155, 194, - 15, 65, 5, 179, 239, 17, 79, 5, 11, 65, 2, 139, 218, 14, 80, 5, 187, 219, - 14, 65, 7, 11, 77, 4, 246, 170, 1, 73, 243, 165, 16, 69, 9, 174, 255, 17, - 72, 2, 83, 219, 19, 73, 5, 235, 243, 17, 72, 5, 11, 73, 2, 175, 241, 17, - 71, 7, 234, 216, 14, 72, 219, 148, 3, 65, 5, 207, 209, 1, 80, 2, 11, 72, - 2, 11, 69, 2, 11, 84, 2, 167, 254, 16, 65, 104, 11, 32, 104, 18, 67, 35, - 83, 52, 53, 5, 65, 80, 73, 84, 65, 52, 21, 3, 77, 65, 76, 52, 147, 254, - 11, 76, 82, 76, 8, 67, 65, 80, 73, 84, 65, 76, 32, 157, 1, 6, 83, 77, 65, - 76, 76, 32, 36, 254, 143, 18, 65, 2, 67, 2, 68, 2, 71, 2, 74, 2, 75, 2, - 78, 2, 79, 2, 80, 2, 81, 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, 2, 89, - 3, 90, 46, 226, 142, 18, 65, 2, 66, 2, 67, 2, 68, 2, 70, 2, 72, 2, 73, 2, - 74, 2, 75, 2, 76, 2, 77, 2, 78, 2, 80, 2, 81, 2, 82, 2, 83, 2, 84, 2, 85, - 2, 86, 2, 87, 2, 88, 2, 89, 3, 90, 40, 45, 9, 32, 78, 85, 77, 69, 82, 65, - 76, 32, 40, 70, 69, 66, 70, 70, 78, 26, 83, 66, 84, 170, 155, 16, 90, - 251, 85, 79, 6, 40, 4, 73, 71, 72, 84, 215, 247, 9, 76, 5, 147, 184, 16, - 69, 8, 30, 73, 105, 3, 79, 85, 82, 4, 206, 134, 5, 70, 167, 238, 12, 86, - 4, 65, 3, 73, 78, 69, 8, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, 5, 235, - 182, 16, 84, 10, 42, 72, 162, 247, 9, 87, 163, 195, 7, 69, 4, 154, 133, - 5, 73, 207, 149, 11, 82, 252, 8, 234, 1, 65, 192, 4, 9, 67, 72, 65, 78, - 73, 67, 65, 76, 32, 34, 68, 164, 15, 11, 69, 84, 69, 73, 32, 77, 65, 89, - 69, 75, 32, 178, 11, 76, 34, 78, 154, 50, 82, 176, 15, 8, 83, 83, 65, 71, - 69, 32, 87, 65, 20, 2, 84, 82, 235, 135, 17, 77, 26, 72, 6, 83, 85, 82, - 69, 68, 32, 253, 220, 16, 6, 84, 32, 79, 78, 32, 66, 24, 96, 5, 65, 78, - 71, 76, 69, 148, 142, 10, 9, 82, 73, 71, 72, 84, 32, 65, 78, 71, 131, - 231, 7, 66, 21, 11, 32, 18, 212, 1, 39, 87, 73, 84, 72, 32, 79, 80, 69, - 78, 32, 65, 82, 77, 32, 69, 78, 68, 73, 78, 71, 32, 73, 78, 32, 65, 82, - 82, 79, 87, 32, 80, 79, 73, 78, 84, 73, 78, 71, 32, 181, 210, 17, 7, 79, - 80, 69, 78, 73, 78, 71, 16, 62, 68, 24, 3, 76, 69, 70, 0, 4, 82, 73, 71, - 72, 43, 85, 4, 73, 3, 79, 87, 78, 4, 137, 144, 8, 5, 84, 32, 65, 78, 68, - 4, 11, 80, 4, 225, 227, 11, 3, 32, 65, 78, 4, 142, 133, 17, 65, 215, 56, - 76, 250, 1, 56, 9, 69, 70, 65, 73, 68, 82, 73, 78, 32, 159, 7, 73, 190, - 1, 174, 1, 67, 52, 6, 68, 73, 71, 73, 84, 32, 152, 1, 7, 78, 85, 77, 66, - 69, 82, 32, 114, 83, 164, 146, 7, 12, 69, 88, 67, 76, 65, 77, 65, 84, 73, - 79, 78, 32, 247, 154, 8, 70, 70, 128, 3, 5, 65, 80, 73, 84, 65, 191, 172, - 15, 79, 26, 82, 84, 48, 2, 79, 78, 222, 143, 16, 70, 30, 83, 102, 90, - 238, 85, 78, 235, 110, 69, 8, 44, 3, 72, 82, 69, 217, 128, 17, 2, 87, 79, - 4, 215, 128, 17, 69, 20, 50, 84, 230, 248, 4, 69, 46, 70, 42, 78, 31, 83, - 6, 166, 250, 4, 72, 172, 242, 4, 2, 87, 69, 135, 195, 7, 69, 70, 68, 3, - 77, 65, 76, 157, 206, 9, 8, 89, 77, 66, 79, 76, 32, 65, 73, 68, 45, 9, - 76, 32, 76, 69, 84, 84, 69, 82, 32, 68, 242, 1, 65, 38, 78, 130, 227, 3, - 72, 2, 75, 198, 197, 10, 89, 138, 147, 3, 79, 162, 64, 66, 2, 67, 2, 68, - 2, 69, 2, 70, 2, 71, 2, 73, 2, 74, 2, 76, 2, 77, 2, 80, 2, 81, 2, 82, 2, - 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, 3, 90, 7, 146, 243, 3, 84, 255, - 136, 14, 73, 7, 234, 251, 17, 71, 3, 89, 60, 48, 5, 69, 86, 65, 76, 32, - 45, 3, 85, 77, 32, 6, 210, 237, 10, 69, 198, 187, 4, 67, 115, 81, 54, - 210, 1, 66, 50, 70, 164, 1, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 248, 1, - 11, 77, 65, 84, 72, 69, 77, 65, 84, 73, 67, 65, 22, 83, 84, 4, 84, 72, - 82, 69, 182, 158, 15, 86, 130, 63, 69, 166, 4, 87, 215, 10, 71, 4, 180, - 156, 6, 3, 79, 76, 68, 255, 225, 7, 76, 10, 84, 9, 76, 65, 84, 84, 69, - 78, 69, 68, 32, 184, 3, 3, 79, 85, 82, 243, 222, 15, 73, 4, 44, 3, 76, - 69, 70, 1, 4, 82, 73, 71, 72, 2, 213, 1, 3, 84, 32, 80, 6, 11, 84, 6, 78, - 32, 41, 15, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 65, 78, 71, 76, 69, - 4, 36, 5, 67, 85, 82, 76, 89, 59, 80, 2, 17, 2, 32, 66, 2, 137, 183, 7, - 4, 82, 65, 67, 75, 2, 169, 178, 17, 10, 65, 82, 69, 78, 84, 72, 69, 83, - 73, 83, 2, 139, 183, 17, 76, 10, 212, 152, 6, 4, 77, 65, 76, 76, 250, - 229, 8, 72, 212, 95, 2, 73, 88, 183, 2, 65, 4, 11, 69, 4, 45, 9, 32, 80, - 79, 73, 78, 84, 69, 68, 32, 4, 162, 202, 9, 80, 219, 147, 6, 66, 158, 1, - 146, 1, 65, 104, 6, 67, 72, 69, 73, 75, 72, 34, 76, 144, 6, 8, 83, 89, - 76, 76, 65, 66, 76, 69, 0, 4, 87, 79, 82, 68, 50, 86, 139, 250, 15, 68, - 6, 80, 8, 72, 65, 78, 71, 32, 75, 72, 85, 164, 6, 3, 80, 85, 78, 147, - 213, 13, 78, 2, 159, 183, 16, 68, 4, 166, 162, 17, 65, 139, 60, 69, 94, + 73, 84, 72, 32, 2, 209, 150, 18, 7, 79, 71, 73, 67, 65, 76, 32, 10, 26, + 68, 94, 72, 59, 77, 6, 11, 79, 6, 44, 5, 85, 66, 76, 69, 32, 235, 168, + 18, 84, 4, 230, 182, 15, 85, 143, 61, 79, 2, 209, 228, 15, 9, 79, 82, 73, + 90, 79, 78, 84, 65, 76, 2, 173, 225, 7, 5, 73, 68, 68, 76, 69, 48, 70, + 68, 228, 1, 4, 76, 69, 70, 84, 241, 2, 5, 82, 73, 71, 72, 84, 6, 164, 1, + 30, 65, 83, 72, 32, 70, 82, 79, 77, 32, 76, 69, 70, 84, 32, 77, 69, 77, + 66, 69, 82, 32, 79, 70, 32, 68, 79, 85, 66, 76, 69, 198, 165, 16, 73, + 151, 210, 1, 82, 2, 17, 2, 32, 86, 2, 137, 151, 18, 5, 69, 82, 84, 73, + 67, 20, 46, 32, 193, 1, 6, 87, 65, 82, 68, 83, 32, 8, 48, 6, 82, 73, 71, + 72, 84, 32, 139, 131, 16, 84, 6, 44, 5, 65, 82, 82, 79, 87, 203, 248, 15, + 68, 5, 193, 248, 13, 18, 32, 87, 73, 84, 72, 32, 68, 69, 80, 69, 78, 68, + 69, 78, 84, 32, 76, 79, 12, 214, 3, 68, 42, 65, 146, 1, 83, 229, 244, 8, + 19, 72, 65, 82, 80, 79, 79, 78, 32, 65, 66, 79, 86, 69, 32, 83, 72, 79, + 82, 84, 22, 48, 6, 87, 65, 82, 68, 83, 32, 235, 251, 8, 32, 20, 88, 5, + 65, 82, 82, 79, 87, 202, 1, 68, 96, 8, 72, 65, 82, 80, 79, 79, 78, 32, + 91, 83, 11, 11, 32, 8, 164, 1, 7, 84, 72, 82, 79, 85, 71, 72, 132, 143, + 3, 10, 87, 73, 84, 72, 32, 68, 79, 85, 66, 76, 196, 232, 5, 9, 79, 86, + 69, 82, 32, 76, 79, 78, 71, 203, 188, 7, 70, 2, 203, 142, 18, 32, 4, 37, + 7, 79, 85, 66, 76, 69, 32, 65, 4, 25, 4, 82, 82, 79, 87, 5, 181, 179, 16, + 2, 32, 70, 4, 236, 246, 8, 4, 79, 86, 69, 82, 33, 11, 65, 66, 79, 86, 69, + 32, 83, 72, 79, 82, 84, 2, 233, 228, 7, 3, 81, 85, 73, 6, 92, 5, 73, 79, + 78, 32, 66, 144, 255, 17, 9, 32, 79, 70, 32, 70, 79, 82, 84, 85, 215, 93, + 85, 2, 211, 241, 9, 79, 4, 38, 76, 213, 132, 14, 3, 72, 79, 84, 2, 245, + 223, 17, 2, 69, 84, 222, 1, 34, 32, 229, 1, 3, 69, 82, 32, 14, 138, 1, + 66, 176, 201, 10, 11, 68, 79, 85, 66, 76, 69, 32, 80, 82, 73, 77, 214, + 183, 6, 65, 148, 113, 6, 75, 65, 86, 89, 75, 65, 227, 10, 76, 4, 38, 82, + 209, 249, 4, 3, 65, 84, 84, 2, 185, 130, 18, 7, 73, 71, 72, 84, 78, 69, + 83, 208, 1, 158, 1, 72, 140, 2, 5, 76, 69, 70, 84, 32, 236, 2, 6, 82, 73, + 71, 72, 84, 32, 154, 247, 15, 66, 74, 67, 74, 70, 234, 10, 77, 150, 2, + 79, 170, 18, 83, 67, 84, 20, 84, 4, 65, 76, 70, 32, 205, 186, 7, 11, 79, + 82, 73, 90, 79, 78, 84, 65, 76, 32, 82, 18, 176, 166, 7, 9, 65, 78, 68, + 32, 85, 80, 80, 69, 82, 32, 7, 73, 78, 86, 69, 82, 83, 69, 150, 216, 8, + 72, 230, 1, 86, 174, 26, 77, 130, 3, 76, 22, 82, 202, 5, 66, 247, 157, 1, + 67, 72, 186, 1, 66, 60, 8, 70, 79, 85, 78, 84, 65, 73, 78, 22, 80, 56, + 12, 83, 69, 77, 73, 67, 73, 82, 67, 85, 76, 65, 82, 154, 1, 81, 246, 2, + 84, 232, 197, 11, 3, 67, 82, 65, 203, 187, 4, 79, 24, 56, 8, 65, 76, 76, + 80, 79, 73, 78, 84, 175, 135, 16, 76, 2, 179, 246, 9, 32, 4, 132, 131, + 15, 5, 65, 73, 78, 84, 66, 163, 141, 1, 69, 2, 185, 195, 7, 5, 32, 65, + 78, 84, 73, 74, 110, 81, 166, 2, 83, 82, 84, 202, 178, 7, 82, 158, 199, + 8, 66, 238, 3, 67, 226, 3, 79, 222, 7, 68, 207, 2, 80, 30, 17, 2, 85, 65, + 30, 48, 6, 68, 82, 65, 78, 84, 32, 239, 146, 16, 82, 28, 74, 70, 60, 2, + 78, 69, 50, 83, 150, 142, 16, 67, 226, 1, 77, 143, 1, 84, 4, 26, 65, 231, + 198, 17, 82, 2, 149, 185, 7, 3, 67, 69, 32, 2, 25, 4, 85, 84, 82, 65, 2, + 195, 209, 18, 76, 4, 234, 224, 10, 77, 215, 175, 5, 84, 6, 240, 191, 7, + 11, 69, 77, 73, 67, 73, 82, 67, 85, 76, 65, 82, 191, 209, 8, 72, 6, 150, + 146, 16, 82, 155, 1, 87, 5, 253, 230, 17, 25, 32, 68, 73, 86, 73, 68, 69, + 68, 32, 66, 89, 32, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 82, 85, + 6, 18, 71, 23, 78, 2, 143, 253, 13, 71, 4, 168, 231, 17, 5, 65, 82, 32, + 69, 67, 151, 103, 71, 114, 104, 12, 67, 73, 65, 78, 32, 76, 69, 84, 84, + 69, 82, 32, 232, 1, 5, 68, 73, 65, 78, 32, 131, 129, 18, 73, 58, 210, 1, + 77, 150, 138, 5, 75, 154, 214, 9, 84, 158, 24, 66, 246, 146, 2, 65, 2, + 69, 2, 78, 238, 253, 1, 68, 2, 71, 2, 72, 2, 73, 2, 74, 2, 76, 2, 80, 2, + 81, 2, 82, 2, 83, 2, 85, 2, 87, 2, 88, 3, 90, 5, 167, 137, 19, 77, 54, + 88, 7, 76, 69, 84, 84, 69, 82, 32, 153, 224, 14, 9, 84, 82, 73, 65, 78, + 71, 85, 76, 65, 52, 222, 159, 13, 84, 190, 215, 1, 76, 198, 135, 2, 83, + 238, 11, 65, 2, 69, 2, 78, 238, 253, 1, 66, 2, 67, 2, 68, 2, 70, 2, 71, + 2, 73, 2, 75, 2, 77, 2, 79, 2, 81, 2, 82, 2, 85, 2, 86, 3, 89, 128, 54, + 162, 1, 65, 194, 103, 69, 182, 103, 73, 154, 25, 79, 164, 112, 3, 82, 79, + 32, 234, 3, 85, 204, 70, 7, 89, 65, 78, 77, 65, 82, 32, 138, 165, 15, 86, + 198, 61, 77, 27, 87, 204, 23, 186, 1, 71, 62, 72, 254, 10, 75, 234, 3, + 76, 252, 13, 2, 77, 77, 22, 78, 154, 17, 80, 118, 82, 174, 7, 83, 190, 7, + 84, 184, 36, 3, 89, 65, 78, 204, 129, 1, 3, 88, 73, 77, 175, 248, 15, 67, + 6, 228, 243, 17, 4, 73, 67, 32, 87, 138, 91, 78, 155, 53, 69, 166, 1, 84, + 6, 65, 74, 65, 78, 73, 32, 129, 3, 10, 74, 79, 78, 71, 32, 84, 73, 76, + 69, 32, 78, 38, 76, 162, 2, 83, 215, 140, 13, 65, 72, 88, 6, 69, 84, 84, + 69, 82, 32, 161, 150, 12, 10, 73, 71, 65, 84, 85, 82, 69, 32, 83, 72, 70, + 134, 175, 3, 78, 150, 245, 11, 68, 82, 82, 34, 84, 162, 149, 3, 66, 2, + 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 83, 2, 86, + 186, 2, 65, 2, 69, 2, 73, 2, 79, 3, 85, 4, 170, 237, 6, 69, 253, 245, 7, + 5, 73, 71, 78, 32, 78, 88, 236, 1, 2, 66, 65, 38, 69, 46, 70, 46, 78, 42, + 79, 46, 80, 22, 83, 118, 84, 194, 1, 87, 112, 5, 71, 82, 69, 69, 78, 0, + 3, 82, 69, 68, 168, 136, 6, 3, 65, 85, 84, 222, 21, 74, 209, 175, 11, 11, + 67, 72, 82, 89, 83, 65, 78, 84, 72, 69, 77, 4, 162, 158, 1, 77, 199, 220, + 17, 67, 8, 228, 2, 4, 73, 71, 72, 84, 195, 1, 65, 12, 172, 2, 2, 73, 86, + 13, 3, 79, 85, 82, 8, 192, 1, 2, 79, 82, 65, 2, 73, 78, 8, 218, 1, 78, + 173, 229, 11, 3, 82, 67, 72, 2, 139, 209, 17, 76, 18, 88, 2, 79, 85, 76, + 4, 69, 86, 69, 78, 0, 2, 73, 88, 182, 157, 12, 85, 255, 199, 1, 80, 2, + 157, 2, 2, 84, 72, 12, 36, 3, 72, 82, 69, 13, 2, 87, 79, 6, 11, 69, 6, + 25, 4, 32, 79, 70, 32, 6, 46, 67, 189, 248, 6, 5, 66, 65, 77, 66, 79, 4, + 184, 140, 6, 2, 73, 82, 153, 234, 10, 5, 72, 65, 82, 65, 67, 6, 50, 69, + 60, 4, 72, 73, 84, 69, 227, 190, 17, 73, 2, 17, 2, 83, 84, 2, 17, 2, 32, + 87, 2, 247, 232, 17, 73, 2, 17, 2, 32, 68, 2, 163, 190, 17, 82, 52, 52, + 5, 65, 83, 65, 82, 32, 241, 139, 15, 2, 69, 77, 50, 162, 1, 69, 40, 7, + 76, 69, 84, 84, 69, 82, 32, 152, 1, 5, 80, 65, 83, 83, 73, 32, 11, 86, + 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 173, 236, 18, 3, 65, 78, 71, 2, + 205, 244, 15, 5, 78, 68, 32, 79, 70, 36, 182, 249, 16, 78, 222, 250, 1, + 66, 2, 67, 2, 68, 2, 71, 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, + 2, 84, 2, 86, 2, 89, 187, 2, 65, 2, 11, 77, 2, 211, 156, 18, 66, 8, 146, + 245, 18, 69, 2, 73, 2, 79, 3, 85, 246, 1, 80, 7, 65, 89, 65, 76, 65, 77, + 32, 176, 11, 2, 69, 32, 225, 1, 3, 84, 69, 83, 236, 1, 198, 1, 68, 44, 9, + 70, 82, 65, 67, 84, 73, 79, 78, 32, 240, 1, 7, 76, 69, 84, 84, 69, 82, + 32, 164, 5, 7, 78, 85, 77, 66, 69, 82, 32, 36, 5, 83, 73, 71, 78, 32, + 230, 191, 13, 86, 239, 201, 1, 65, 22, 164, 171, 8, 2, 65, 84, 163, 211, + 8, 73, 26, 56, 4, 79, 78, 69, 32, 121, 6, 84, 72, 82, 69, 69, 32, 18, 82, + 84, 254, 135, 5, 83, 130, 132, 8, 70, 62, 79, 146, 222, 3, 69, 46, 72, + 47, 81, 4, 134, 143, 13, 87, 255, 220, 3, 69, 8, 150, 136, 5, 83, 198, + 135, 8, 69, 110, 84, 179, 220, 3, 81, 132, 1, 226, 1, 65, 82, 67, 158, 1, + 68, 78, 84, 82, 86, 226, 141, 13, 78, 182, 128, 2, 76, 38, 82, 134, 6, + 85, 206, 141, 1, 79, 238, 60, 73, 182, 196, 1, 83, 82, 66, 2, 71, 2, 74, + 2, 75, 2, 80, 162, 7, 69, 234, 61, 72, 2, 77, 3, 89, 11, 240, 167, 16, 7, + 82, 67, 72, 65, 73, 67, 32, 206, 198, 2, 65, 2, 73, 3, 85, 22, 26, 72, + 215, 237, 18, 65, 20, 44, 5, 73, 76, 76, 85, 32, 167, 237, 18, 65, 18, + 138, 132, 13, 76, 174, 235, 3, 78, 146, 197, 1, 82, 222, 56, 75, 2, 77, + 3, 89, 10, 212, 226, 10, 4, 79, 84, 32, 82, 190, 194, 7, 68, 138, 69, 72, + 187, 2, 65, 10, 38, 84, 170, 233, 18, 72, 187, 2, 65, 6, 166, 233, 18, + 72, 2, 84, 187, 2, 65, 12, 242, 227, 3, 69, 234, 176, 11, 79, 223, 214, + 3, 65, 6, 162, 142, 13, 79, 223, 134, 4, 84, 18, 50, 67, 114, 86, 250, + 142, 15, 65, 251, 149, 3, 80, 6, 54, 79, 120, 5, 73, 82, 67, 85, 76, 171, + 203, 14, 65, 2, 145, 190, 13, 9, 77, 66, 73, 78, 73, 78, 71, 32, 65, 6, + 60, 9, 69, 82, 84, 73, 67, 65, 76, 32, 66, 255, 165, 18, 73, 2, 253, 142, + 15, 2, 65, 82, 8, 80, 12, 87, 73, 84, 72, 32, 83, 84, 82, 79, 75, 69, 32, + 70, 65, 227, 224, 17, 83, 4, 64, 10, 65, 78, 68, 32, 77, 65, 76, 69, 32, + 65, 227, 224, 17, 83, 2, 25, 4, 78, 68, 32, 70, 2, 11, 69, 2, 11, 77, 2, + 139, 211, 7, 65, 2, 191, 163, 17, 69, 2, 243, 225, 16, 79, 185, 1, 210, + 1, 32, 220, 2, 5, 68, 65, 73, 67, 32, 224, 3, 8, 73, 67, 72, 65, 69, 65, + 78, 32, 222, 8, 83, 156, 166, 2, 3, 85, 65, 76, 130, 228, 10, 65, 240, + 167, 1, 8, 84, 69, 76, 80, 73, 69, 67, 69, 235, 132, 4, 71, 12, 132, 1, + 3, 73, 78, 32, 128, 1, 5, 87, 73, 84, 72, 32, 136, 147, 2, 3, 68, 65, 78, + 237, 140, 13, 8, 65, 78, 68, 32, 87, 79, 77, 65, 4, 248, 140, 10, 19, 66, + 85, 83, 73, 78, 69, 83, 83, 32, 83, 85, 73, 84, 32, 76, 69, 86, 73, 84, + 189, 151, 1, 4, 84, 85, 88, 69, 4, 140, 243, 13, 8, 71, 85, 65, 32, 80, + 73, 32, 77, 205, 163, 3, 4, 84, 85, 82, 66, 58, 112, 4, 65, 70, 70, 82, + 28, 7, 76, 69, 84, 84, 69, 82, 32, 208, 184, 14, 3, 86, 79, 67, 226, 72, + 71, 251, 25, 80, 2, 249, 247, 17, 2, 73, 67, 50, 82, 65, 176, 1, 2, 68, + 85, 2, 85, 28, 3, 72, 65, 76, 22, 73, 183, 152, 18, 75, 38, 154, 1, 75, + 206, 246, 12, 84, 250, 191, 1, 83, 130, 217, 3, 73, 226, 79, 66, 2, 68, + 2, 71, 2, 72, 2, 76, 2, 77, 2, 78, 2, 80, 2, 81, 2, 82, 3, 90, 5, 235, + 220, 18, 83, 2, 185, 132, 8, 2, 83, 72, 2, 187, 220, 18, 81, 4, 222, 222, + 18, 78, 3, 84, 102, 216, 1, 7, 76, 69, 84, 84, 69, 82, 32, 194, 4, 78, + 80, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 220, 1, 4, 83, + 73, 71, 78, 249, 200, 10, 16, 65, 66, 66, 82, 69, 86, 73, 65, 84, 73, 79, + 78, 32, 77, 65, 82, 72, 218, 1, 65, 46, 66, 38, 68, 30, 71, 30, 74, 2, + 90, 30, 75, 30, 81, 38, 83, 50, 84, 54, 88, 158, 164, 6, 76, 134, 206, 1, + 82, 246, 221, 2, 89, 198, 207, 1, 72, 190, 184, 5, 78, 134, 2, 87, 218, + 103, 70, 2, 80, 171, 4, 77, 6, 142, 209, 10, 76, 122, 65, 179, 137, 7, + 89, 4, 134, 249, 12, 72, 227, 220, 3, 69, 4, 254, 165, 6, 65, 23, 72, 4, + 182, 208, 10, 72, 15, 73, 4, 242, 208, 10, 72, 15, 65, 4, 226, 166, 12, + 72, 15, 65, 4, 210, 165, 6, 72, 131, 129, 6, 79, 8, 186, 205, 10, 83, + 154, 3, 65, 131, 137, 7, 72, 6, 206, 164, 6, 72, 178, 175, 10, 69, 219, + 134, 1, 65, 4, 202, 165, 12, 65, 3, 79, 10, 33, 6, 85, 77, 66, 69, 82, + 32, 10, 250, 207, 10, 79, 58, 84, 131, 203, 2, 70, 14, 80, 2, 68, 79, + 116, 3, 76, 73, 78, 190, 167, 5, 70, 230, 219, 11, 84, 167, 10, 83, 6, + 54, 84, 13, 9, 85, 66, 76, 69, 32, 68, 79, 84, 32, 5, 11, 32, 2, 25, 4, + 87, 73, 84, 72, 2, 151, 193, 2, 73, 2, 231, 203, 3, 69, 2, 139, 168, 17, + 32, 2, 11, 32, 2, 249, 190, 18, 2, 83, 72, 4, 92, 17, 32, 83, 89, 77, 66, + 79, 76, 32, 70, 79, 82, 32, 76, 73, 71, 72, 84, 139, 220, 10, 76, 2, 179, + 140, 15, 72, 142, 1, 142, 1, 65, 20, 5, 67, 72, 69, 78, 32, 216, 164, 6, + 4, 82, 73, 65, 71, 249, 175, 11, 13, 84, 73, 65, 76, 32, 65, 82, 84, 83, + 32, 85, 78, 73, 2, 227, 161, 5, 67, 136, 1, 152, 1, 7, 76, 69, 84, 84, + 69, 82, 32, 194, 1, 83, 236, 2, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, + 78, 32, 170, 129, 18, 72, 225, 5, 4, 77, 65, 82, 75, 60, 254, 3, 84, 206, + 148, 2, 68, 166, 188, 14, 78, 214, 181, 1, 67, 2, 75, 2, 80, 2, 83, 2, + 90, 138, 69, 45, 2, 66, 2, 71, 2, 72, 2, 74, 2, 76, 2, 77, 2, 82, 2, 87, + 2, 89, 187, 2, 65, 62, 96, 4, 73, 71, 78, 32, 37, 16, 85, 66, 74, 79, 73, + 78, 69, 68, 32, 76, 69, 84, 84, 69, 82, 32, 4, 254, 177, 14, 67, 235, + 216, 3, 65, 58, 182, 1, 84, 206, 148, 2, 68, 166, 188, 14, 78, 214, 181, + 1, 67, 2, 75, 2, 80, 2, 83, 2, 90, 138, 69, 66, 2, 71, 2, 72, 2, 74, 2, + 76, 2, 77, 2, 82, 2, 87, 2, 89, 187, 2, 65, 8, 194, 134, 18, 83, 138, 69, + 72, 187, 2, 65, 10, 158, 203, 18, 65, 186, 2, 69, 2, 73, 2, 79, 3, 85, + 156, 1, 120, 11, 65, 82, 65, 77, 32, 71, 79, 78, 68, 73, 32, 232, 5, 3, + 67, 85, 76, 64, 5, 75, 32, 87, 79, 82, 183, 132, 18, 85, 150, 1, 100, 7, + 76, 69, 84, 84, 69, 82, 32, 178, 2, 82, 56, 5, 83, 73, 71, 78, 32, 82, + 86, 247, 211, 16, 68, 94, 210, 1, 74, 42, 84, 198, 235, 14, 65, 38, 68, + 214, 6, 85, 186, 202, 1, 73, 42, 76, 190, 195, 1, 75, 38, 78, 46, 83, 82, + 66, 2, 67, 2, 71, 2, 80, 138, 69, 72, 2, 77, 2, 82, 2, 86, 2, 89, 186, 2, + 69, 3, 79, 6, 130, 199, 18, 78, 38, 72, 187, 2, 65, 10, 246, 129, 18, 84, + 138, 69, 72, 2, 82, 187, 2, 65, 4, 32, 2, 65, 45, 219, 236, 14, 69, 2, + 147, 132, 18, 75, 10, 230, 176, 1, 67, 182, 207, 12, 72, 178, 43, 78, + 150, 227, 1, 86, 247, 244, 1, 65, 22, 26, 79, 199, 139, 16, 73, 20, 45, + 9, 87, 69, 76, 32, 83, 73, 71, 78, 32, 20, 74, 86, 198, 239, 14, 65, 38, + 85, 186, 202, 1, 73, 198, 140, 2, 69, 3, 79, 2, 141, 203, 7, 6, 79, 67, + 65, 76, 73, 67, 2, 145, 141, 18, 11, 73, 78, 69, 32, 79, 82, 68, 73, 78, + 65, 76, 2, 179, 176, 17, 75, 226, 15, 76, 10, 72, 69, 77, 65, 84, 73, 67, + 65, 76, 32, 153, 224, 14, 3, 69, 32, 68, 224, 15, 252, 1, 5, 66, 79, 76, + 68, 32, 168, 6, 14, 68, 79, 85, 66, 76, 69, 45, 83, 84, 82, 85, 67, 75, + 32, 238, 1, 70, 164, 2, 7, 73, 84, 65, 76, 73, 67, 32, 180, 3, 10, 77, + 79, 78, 79, 83, 80, 65, 67, 69, 32, 40, 2, 82, 73, 36, 3, 76, 69, 70, + 167, 1, 83, 160, 5, 176, 1, 8, 67, 65, 80, 73, 84, 65, 76, 32, 130, 2, + 83, 210, 14, 73, 210, 3, 69, 38, 75, 38, 78, 30, 80, 98, 82, 242, 5, 84, + 56, 7, 70, 82, 65, 75, 84, 85, 82, 195, 177, 16, 68, 104, 190, 4, 68, + 174, 15, 84, 174, 4, 65, 22, 66, 2, 90, 42, 69, 98, 71, 22, 73, 22, 75, + 34, 76, 22, 79, 50, 80, 42, 82, 22, 83, 70, 85, 214, 197, 1, 67, 198, + 137, 13, 77, 2, 78, 186, 202, 1, 88, 198, 140, 2, 70, 2, 72, 2, 74, 2, + 81, 2, 86, 2, 87, 3, 89, 208, 1, 60, 5, 77, 65, 76, 76, 32, 201, 25, 5, + 67, 82, 73, 80, 84, 104, 250, 1, 68, 218, 19, 65, 22, 66, 2, 90, 42, 69, + 38, 70, 62, 71, 22, 73, 22, 75, 34, 76, 22, 79, 50, 80, 42, 82, 22, 83, + 34, 84, 38, 85, 214, 197, 1, 67, 198, 137, 13, 77, 2, 78, 186, 202, 1, + 88, 198, 140, 2, 72, 2, 74, 2, 81, 2, 86, 2, 87, 3, 89, 7, 26, 73, 151, + 128, 15, 69, 2, 247, 213, 1, 71, 110, 68, 8, 67, 65, 80, 73, 84, 65, 76, + 32, 150, 23, 83, 131, 177, 16, 68, 38, 154, 188, 18, 65, 2, 66, 2, 68, 2, + 69, 2, 70, 2, 71, 2, 73, 2, 74, 2, 75, 2, 76, 2, 77, 2, 79, 2, 83, 2, 84, + 2, 85, 2, 86, 2, 87, 2, 88, 3, 89, 96, 52, 7, 82, 65, 75, 84, 85, 82, 32, + 255, 143, 7, 65, 94, 52, 8, 67, 65, 80, 73, 84, 65, 76, 32, 131, 21, 83, + 42, 134, 186, 18, 65, 2, 66, 2, 68, 2, 69, 2, 70, 2, 71, 2, 74, 2, 75, 2, + 76, 2, 77, 2, 78, 2, 79, 2, 80, 2, 81, 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, + 2, 88, 3, 89, 222, 1, 100, 6, 83, 77, 65, 76, 76, 32, 222, 7, 67, 218, 2, + 69, 38, 75, 38, 78, 30, 80, 98, 82, 243, 5, 84, 104, 242, 1, 68, 186, 12, + 65, 22, 66, 2, 90, 42, 69, 38, 70, 62, 71, 22, 73, 22, 75, 34, 76, 22, + 79, 50, 80, 42, 82, 22, 83, 34, 84, 38, 85, 214, 197, 1, 67, 198, 137, + 13, 77, 2, 78, 186, 202, 1, 88, 198, 140, 2, 74, 2, 81, 2, 86, 2, 87, 3, + 89, 9, 52, 7, 79, 84, 76, 69, 83, 83, 32, 219, 248, 14, 69, 4, 186, 181, + 18, 73, 3, 74, 124, 246, 15, 67, 34, 83, 131, 177, 16, 68, 12, 32, 2, 71, + 72, 167, 138, 7, 83, 10, 17, 2, 84, 32, 10, 112, 6, 87, 72, 73, 84, 69, + 32, 142, 245, 5, 68, 222, 107, 65, 153, 235, 4, 9, 70, 76, 65, 84, 84, + 69, 78, 69, 68, 4, 174, 180, 14, 83, 39, 84, 130, 6, 84, 10, 65, 78, 83, + 45, 83, 69, 82, 73, 70, 32, 249, 13, 6, 67, 82, 73, 80, 84, 32, 176, 5, + 96, 5, 66, 79, 76, 68, 32, 164, 12, 6, 73, 84, 65, 76, 73, 67, 34, 67, + 34, 83, 131, 177, 16, 68, 204, 3, 98, 73, 122, 67, 218, 2, 69, 38, 75, + 38, 78, 30, 80, 98, 82, 30, 83, 214, 5, 84, 251, 177, 16, 68, 220, 1, 33, + 6, 84, 65, 76, 73, 67, 32, 220, 1, 74, 67, 218, 2, 69, 38, 75, 38, 78, + 30, 80, 98, 82, 30, 83, 215, 5, 84, 102, 37, 7, 65, 80, 73, 84, 65, 76, + 32, 102, 250, 1, 84, 174, 4, 65, 22, 66, 2, 90, 22, 68, 22, 69, 98, 71, + 22, 73, 22, 75, 34, 76, 22, 79, 50, 80, 42, 82, 22, 83, 70, 85, 214, 197, + 1, 67, 198, 137, 13, 77, 2, 78, 186, 202, 1, 88, 198, 140, 2, 70, 2, 72, + 2, 74, 2, 81, 2, 86, 2, 87, 3, 89, 9, 232, 159, 11, 4, 72, 69, 84, 65, + 151, 233, 6, 65, 2, 249, 178, 16, 4, 80, 83, 73, 76, 2, 17, 2, 65, 80, 2, + 159, 7, 80, 2, 209, 138, 18, 2, 65, 66, 6, 74, 72, 148, 150, 5, 8, 65, + 82, 84, 73, 65, 76, 32, 68, 175, 128, 12, 73, 2, 191, 150, 17, 73, 2, + 169, 150, 17, 2, 72, 79, 102, 29, 5, 77, 65, 76, 76, 32, 102, 246, 1, 65, + 22, 66, 2, 90, 22, 68, 22, 69, 38, 70, 62, 71, 22, 73, 22, 75, 34, 76, + 22, 79, 50, 80, 42, 82, 22, 83, 34, 84, 38, 85, 214, 197, 1, 67, 198, + 137, 13, 77, 2, 78, 186, 202, 1, 88, 198, 140, 2, 72, 2, 74, 2, 81, 2, + 86, 2, 87, 3, 89, 5, 179, 205, 14, 76, 5, 219, 132, 18, 69, 5, 175, 236, + 14, 69, 7, 130, 213, 1, 80, 199, 209, 16, 84, 5, 11, 73, 2, 29, 5, 78, + 65, 76, 32, 83, 2, 227, 1, 73, 5, 215, 210, 15, 65, 5, 191, 131, 18, 79, + 5, 11, 65, 2, 195, 234, 14, 80, 5, 243, 235, 14, 65, 7, 11, 77, 4, 190, + 171, 1, 73, 183, 185, 16, 69, 9, 186, 147, 18, 72, 2, 83, 219, 19, 73, 5, + 247, 135, 18, 72, 5, 11, 73, 2, 187, 133, 18, 71, 7, 162, 233, 14, 72, + 175, 152, 3, 65, 5, 151, 210, 1, 80, 2, 11, 72, 2, 11, 69, 2, 11, 84, 2, + 151, 144, 17, 65, 104, 11, 32, 104, 18, 67, 35, 83, 52, 53, 5, 65, 80, + 73, 84, 65, 52, 21, 3, 77, 65, 76, 52, 195, 131, 12, 76, 82, 76, 8, 67, + 65, 80, 73, 84, 65, 76, 32, 157, 1, 6, 83, 77, 65, 76, 76, 32, 36, 138, + 164, 18, 65, 2, 67, 2, 68, 2, 71, 2, 74, 2, 75, 2, 78, 2, 79, 2, 80, 2, + 81, 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, 2, 89, 3, 90, 46, 238, 162, + 18, 65, 2, 66, 2, 67, 2, 68, 2, 70, 2, 72, 2, 73, 2, 74, 2, 75, 2, 76, 2, + 77, 2, 78, 2, 80, 2, 81, 2, 82, 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, + 2, 89, 3, 90, 40, 45, 9, 32, 78, 85, 77, 69, 82, 65, 76, 32, 40, 70, 69, + 66, 70, 70, 78, 26, 83, 66, 84, 206, 172, 16, 90, 223, 86, 79, 6, 40, 4, + 73, 71, 72, 84, 203, 253, 9, 76, 5, 131, 202, 16, 69, 8, 30, 73, 105, 3, + 79, 85, 82, 4, 146, 135, 5, 70, 239, 129, 13, 86, 4, 65, 3, 73, 78, 69, + 8, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, 5, 219, 200, 16, 84, 10, 42, 72, + 150, 253, 9, 87, 187, 209, 7, 69, 4, 222, 133, 5, 73, 175, 166, 11, 82, + 130, 9, 226, 1, 65, 188, 4, 9, 67, 72, 65, 78, 73, 67, 65, 76, 32, 34, + 68, 204, 15, 11, 69, 84, 69, 73, 32, 77, 65, 89, 69, 75, 32, 178, 11, 76, + 62, 78, 134, 50, 82, 176, 15, 8, 83, 83, 65, 71, 69, 32, 87, 65, 22, 84, + 211, 155, 17, 77, 26, 68, 6, 83, 85, 82, 69, 68, 32, 137, 182, 14, 5, 84, + 32, 79, 78, 32, 24, 96, 5, 65, 78, 71, 76, 69, 164, 148, 10, 9, 82, 73, + 71, 72, 84, 32, 65, 78, 71, 139, 245, 7, 66, 21, 11, 32, 18, 212, 1, 39, + 87, 73, 84, 72, 32, 79, 80, 69, 78, 32, 65, 82, 77, 32, 69, 78, 68, 73, + 78, 71, 32, 73, 78, 32, 65, 82, 82, 79, 87, 32, 80, 79, 73, 78, 84, 73, + 78, 71, 32, 205, 230, 17, 7, 79, 80, 69, 78, 73, 78, 71, 16, 62, 68, 24, + 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 43, 85, 4, 73, 3, 79, 87, 78, 4, + 157, 150, 8, 5, 84, 32, 65, 78, 68, 4, 11, 80, 4, 153, 233, 11, 3, 32, + 65, 78, 4, 166, 153, 17, 65, 215, 56, 76, 252, 1, 56, 9, 69, 70, 65, 73, + 68, 82, 73, 78, 32, 159, 7, 73, 190, 1, 174, 1, 67, 52, 6, 68, 73, 71, + 73, 84, 32, 152, 1, 7, 78, 85, 77, 66, 69, 82, 32, 114, 83, 224, 147, 7, + 12, 69, 88, 67, 76, 65, 77, 65, 84, 73, 79, 78, 32, 131, 170, 8, 70, 70, + 128, 3, 5, 65, 80, 73, 84, 65, 135, 189, 15, 79, 26, 82, 84, 48, 2, 79, + 78, 142, 161, 16, 70, 30, 83, 102, 90, 210, 86, 78, 239, 112, 69, 8, 44, + 3, 72, 82, 69, 241, 148, 17, 2, 87, 79, 4, 239, 148, 17, 69, 20, 50, 84, + 182, 249, 4, 69, 46, 70, 42, 78, 31, 83, 6, 246, 250, 4, 72, 220, 247, 4, + 2, 87, 69, 159, 209, 7, 69, 70, 68, 3, 77, 65, 76, 157, 212, 9, 8, 89, + 77, 66, 79, 76, 32, 65, 73, 68, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, + 32, 68, 242, 1, 65, 38, 78, 218, 227, 3, 72, 2, 75, 178, 213, 10, 89, + 222, 150, 3, 79, 162, 64, 66, 2, 67, 2, 68, 2, 69, 2, 70, 2, 71, 2, 73, + 2, 74, 2, 76, 2, 77, 2, 80, 2, 81, 2, 82, 2, 83, 2, 84, 2, 85, 2, 86, 2, + 87, 2, 88, 3, 90, 7, 254, 243, 3, 84, 171, 156, 14, 73, 7, 130, 144, 18, + 71, 3, 89, 62, 48, 5, 69, 86, 65, 76, 32, 45, 3, 85, 77, 32, 6, 218, 243, + 10, 69, 134, 198, 4, 67, 115, 81, 56, 210, 1, 66, 50, 70, 164, 1, 3, 76, + 69, 70, 0, 4, 82, 73, 71, 72, 248, 1, 11, 77, 65, 84, 72, 69, 77, 65, 84, + 73, 67, 65, 22, 83, 124, 4, 84, 72, 82, 69, 214, 174, 15, 86, 246, 62, + 69, 166, 4, 87, 203, 11, 71, 4, 164, 158, 6, 3, 79, 76, 68, 211, 239, 7, + 76, 10, 84, 9, 76, 65, 84, 84, 69, 78, 69, 68, 32, 224, 3, 3, 79, 85, 82, + 135, 239, 15, 73, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 213, 1, + 3, 84, 32, 80, 6, 11, 84, 6, 78, 32, 41, 15, 45, 80, 79, 73, 78, 84, 73, + 78, 71, 32, 65, 78, 71, 76, 69, 4, 36, 5, 67, 85, 82, 76, 89, 59, 80, 2, + 17, 2, 32, 66, 2, 249, 184, 7, 4, 82, 65, 67, 75, 2, 193, 198, 17, 10, + 65, 82, 69, 78, 84, 72, 69, 83, 73, 83, 2, 163, 203, 17, 76, 12, 150, + 143, 15, 72, 200, 95, 2, 73, 88, 182, 2, 65, 245, 115, 15, 77, 65, 76, + 76, 32, 87, 72, 73, 84, 69, 32, 67, 73, 82, 67, 4, 11, 69, 4, 45, 9, 32, + 80, 79, 73, 78, 84, 69, 68, 32, 4, 250, 207, 9, 80, 151, 158, 6, 66, 158, + 1, 146, 1, 65, 104, 6, 67, 72, 69, 73, 75, 72, 34, 76, 144, 6, 8, 83, 89, + 76, 76, 65, 66, 76, 69, 0, 4, 87, 79, 82, 68, 50, 86, 147, 139, 16, 68, + 6, 80, 8, 72, 65, 78, 71, 32, 75, 72, 85, 164, 6, 3, 80, 85, 78, 227, + 223, 13, 78, 2, 251, 200, 16, 68, 4, 150, 182, 17, 65, 139, 60, 69, 94, 52, 6, 69, 84, 84, 69, 82, 32, 185, 5, 2, 85, 77, 92, 250, 1, 66, 36, 2, 67, 72, 38, 68, 50, 71, 38, 74, 34, 75, 42, 78, 62, 80, 30, 83, 42, 84, - 54, 73, 0, 3, 76, 65, 73, 0, 3, 77, 73, 84, 138, 247, 12, 72, 166, 10, - 82, 2, 87, 232, 181, 2, 2, 65, 84, 182, 220, 1, 89, 246, 8, 85, 226, 79, - 69, 3, 79, 4, 182, 180, 16, 72, 255, 186, 1, 65, 4, 218, 229, 16, 73, - 183, 137, 1, 65, 8, 238, 165, 10, 72, 202, 191, 6, 73, 247, 65, 68, 4, - 190, 165, 10, 72, 231, 197, 7, 79, 4, 154, 179, 16, 72, 203, 49, 73, 6, - 216, 1, 2, 79, 75, 163, 163, 10, 72, 12, 178, 1, 65, 0, 3, 71, 79, 85, - 230, 233, 17, 78, 3, 89, 6, 118, 65, 163, 177, 16, 72, 6, 158, 220, 17, - 65, 162, 14, 72, 3, 83, 10, 48, 2, 73, 76, 162, 163, 10, 72, 191, 129, 7, - 84, 5, 181, 177, 1, 4, 32, 76, 79, 78, 2, 209, 232, 17, 3, 32, 73, 89, 2, - 173, 130, 17, 7, 32, 82, 69, 80, 69, 84, 73, 30, 64, 10, 79, 87, 69, 76, - 32, 83, 73, 71, 78, 32, 143, 178, 15, 73, 28, 130, 1, 65, 44, 4, 67, 72, - 69, 73, 2, 79, 0, 3, 83, 79, 85, 0, 2, 89, 69, 22, 73, 38, 85, 194, 131, - 11, 78, 151, 175, 4, 86, 8, 242, 216, 16, 78, 182, 80, 65, 187, 64, 85, - 2, 199, 216, 16, 78, 4, 178, 216, 16, 78, 239, 144, 1, 73, 4, 142, 216, - 16, 78, 239, 144, 1, 85, 4, 182, 224, 16, 84, 195, 56, 79, 178, 3, 160, - 1, 11, 68, 69, 32, 75, 73, 75, 65, 75, 85, 73, 32, 140, 211, 16, 20, 79, - 82, 65, 72, 32, 87, 73, 84, 72, 32, 78, 73, 78, 69, 32, 66, 82, 65, 78, - 67, 95, 83, 174, 3, 148, 1, 17, 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, - 78, 85, 77, 66, 69, 82, 32, 164, 1, 10, 83, 89, 76, 76, 65, 66, 76, 69, - 32, 77, 155, 167, 9, 68, 14, 62, 84, 56, 7, 72, 85, 78, 68, 82, 69, 68, - 135, 186, 4, 77, 8, 26, 69, 207, 186, 4, 72, 6, 26, 78, 167, 161, 14, 69, - 4, 160, 186, 4, 2, 32, 84, 219, 170, 13, 83, 142, 3, 22, 48, 163, 21, 49, - 198, 1, 118, 48, 250, 1, 49, 210, 1, 50, 138, 2, 51, 254, 1, 52, 150, 2, - 53, 158, 2, 54, 242, 1, 55, 134, 2, 56, 187, 2, 57, 18, 142, 1, 49, 34, - 50, 22, 51, 22, 52, 254, 150, 2, 53, 154, 240, 3, 56, 156, 218, 10, 3, - 57, 32, 77, 92, 3, 55, 32, 77, 237, 90, 3, 54, 32, 87, 2, 11, 32, 2, 195, - 206, 17, 75, 2, 159, 217, 17, 32, 2, 215, 148, 12, 32, 2, 11, 32, 2, 251, - 205, 17, 87, 20, 130, 1, 49, 22, 54, 18, 56, 22, 57, 248, 28, 2, 48, 32, - 198, 183, 7, 53, 170, 203, 5, 52, 198, 10, 55, 222, 9, 50, 243, 235, 3, - 51, 2, 147, 179, 17, 32, 2, 167, 25, 32, 2, 163, 204, 13, 32, 2, 227, - 245, 12, 32, 20, 106, 49, 22, 50, 22, 51, 22, 52, 22, 53, 22, 54, 22, 55, - 22, 57, 130, 224, 11, 48, 145, 231, 1, 2, 56, 32, 2, 211, 169, 10, 32, 2, - 247, 128, 10, 32, 2, 143, 186, 17, 32, 2, 247, 142, 12, 32, 2, 167, 227, - 12, 32, 2, 135, 188, 17, 32, 2, 179, 221, 12, 32, 2, 239, 28, 32, 20, - 174, 1, 48, 16, 2, 49, 32, 20, 2, 52, 32, 20, 2, 56, 32, 246, 194, 4, 57, - 182, 51, 50, 22, 53, 136, 230, 7, 2, 54, 32, 232, 255, 3, 3, 55, 32, 78, - 237, 90, 3, 51, 32, 89, 2, 179, 37, 32, 2, 207, 200, 17, 89, 2, 187, 200, - 17, 70, 2, 255, 145, 16, 78, 20, 184, 1, 2, 48, 32, 20, 2, 51, 32, 30, - 53, 22, 56, 160, 8, 3, 52, 32, 75, 128, 22, 3, 54, 32, 72, 222, 2, 55, - 138, 213, 4, 49, 208, 179, 4, 3, 57, 32, 87, 241, 232, 5, 3, 50, 32, 72, - 2, 247, 234, 15, 72, 2, 213, 151, 17, 2, 78, 71, 2, 191, 162, 11, 32, 2, - 235, 186, 17, 32, 20, 178, 1, 48, 18, 53, 20, 2, 54, 32, 20, 2, 56, 32, - 22, 57, 136, 213, 9, 2, 50, 32, 236, 4, 2, 51, 32, 170, 215, 1, 49, 148, - 223, 3, 3, 52, 32, 76, 137, 143, 1, 3, 55, 32, 78, 2, 159, 4, 32, 2, 155, - 145, 16, 32, 2, 215, 170, 17, 71, 2, 247, 144, 13, 78, 2, 237, 131, 16, - 2, 32, 77, 20, 196, 1, 2, 50, 32, 22, 54, 238, 25, 51, 168, 2, 3, 55, 32, - 78, 140, 216, 1, 2, 52, 32, 234, 150, 3, 56, 248, 144, 5, 3, 48, 32, 78, - 172, 89, 3, 49, 32, 87, 158, 13, 57, 225, 227, 4, 3, 53, 32, 75, 2, 203, - 168, 17, 77, 2, 247, 151, 10, 32, 20, 196, 1, 3, 52, 32, 75, 20, 2, 53, - 32, 22, 57, 232, 7, 3, 49, 32, 71, 234, 1, 51, 236, 6, 3, 48, 32, 71, - 146, 5, 50, 236, 224, 10, 2, 55, 32, 252, 149, 4, 3, 54, 32, 75, 241, 87, - 3, 56, 32, 70, 2, 155, 175, 17, 80, 2, 155, 189, 17, 70, 2, 187, 243, 10, - 32, 20, 228, 1, 2, 48, 32, 20, 2, 49, 32, 20, 2, 52, 32, 22, 53, 172, 14, - 6, 54, 32, 76, 79, 78, 71, 224, 11, 2, 57, 32, 168, 173, 3, 3, 51, 32, - 72, 168, 154, 9, 4, 50, 32, 78, 71, 152, 239, 3, 3, 55, 32, 72, 189, 97, - 3, 56, 32, 70, 2, 139, 187, 17, 89, 2, 147, 226, 15, 80, 2, 255, 225, 15, - 76, 2, 207, 212, 16, 32, 20, 230, 1, 53, 216, 14, 4, 48, 32, 78, 71, 244, - 7, 3, 51, 32, 71, 192, 152, 12, 2, 55, 32, 138, 118, 57, 192, 112, 3, 50, - 32, 75, 156, 202, 1, 3, 49, 32, 84, 208, 27, 4, 56, 32, 78, 89, 252, 131, - 1, 3, 52, 32, 77, 225, 34, 2, 54, 32, 2, 207, 159, 17, 32, 200, 1, 118, - 48, 186, 2, 49, 210, 2, 50, 166, 2, 51, 222, 1, 52, 186, 2, 53, 214, 2, - 54, 166, 2, 55, 190, 2, 56, 223, 2, 57, 20, 222, 1, 49, 30, 52, 28, 7, - 53, 32, 76, 79, 78, 71, 32, 12, 2, 51, 32, 184, 11, 6, 54, 32, 76, 79, - 78, 71, 138, 241, 4, 50, 198, 168, 2, 48, 212, 134, 5, 3, 55, 32, 71, - 228, 176, 3, 3, 57, 32, 89, 253, 39, 3, 56, 32, 75, 2, 181, 130, 16, 2, - 32, 70, 2, 241, 132, 15, 2, 32, 84, 2, 11, 77, 2, 203, 132, 15, 66, 20, - 208, 1, 6, 48, 32, 76, 79, 78, 71, 22, 51, 34, 54, 22, 56, 32, 2, 57, 32, - 248, 17, 4, 53, 32, 78, 71, 204, 208, 2, 2, 55, 32, 184, 151, 2, 3, 50, - 32, 75, 128, 136, 10, 3, 52, 32, 87, 229, 132, 2, 2, 49, 32, 2, 227, 165, - 16, 32, 2, 11, 32, 2, 151, 179, 17, 74, 2, 203, 192, 16, 32, 2, 11, 32, - 2, 227, 178, 17, 87, 2, 151, 185, 15, 78, 20, 226, 1, 50, 32, 2, 51, 32, - 128, 4, 3, 52, 32, 71, 254, 9, 48, 148, 240, 9, 4, 56, 32, 72, 79, 156, - 220, 2, 5, 55, 32, 78, 71, 71, 224, 88, 2, 53, 32, 220, 55, 2, 57, 32, - 236, 236, 1, 3, 54, 32, 87, 245, 150, 1, 2, 49, 32, 2, 11, 32, 2, 171, - 155, 13, 77, 2, 11, 78, 2, 167, 179, 17, 68, 20, 200, 3, 2, 56, 32, 252, - 4, 3, 52, 32, 78, 216, 243, 4, 3, 50, 32, 75, 210, 210, 2, 49, 2, 53, - 236, 174, 2, 2, 55, 32, 232, 129, 5, 3, 51, 32, 70, 0, 3, 54, 32, 83, - 236, 53, 2, 48, 32, 233, 148, 1, 3, 57, 32, 87, 20, 236, 1, 8, 50, 32, + 54, 73, 0, 3, 76, 65, 73, 0, 3, 77, 73, 84, 166, 130, 13, 72, 166, 10, + 82, 2, 87, 248, 186, 2, 2, 65, 84, 250, 223, 1, 89, 246, 8, 85, 226, 79, + 69, 3, 79, 4, 146, 198, 16, 72, 147, 189, 1, 65, 4, 174, 247, 16, 73, + 211, 139, 1, 65, 8, 214, 171, 10, 72, 182, 203, 6, 73, 147, 68, 68, 4, + 166, 171, 10, 72, 239, 211, 7, 79, 4, 246, 196, 16, 72, 195, 49, 73, 6, + 216, 1, 2, 79, 75, 139, 169, 10, 72, 12, 178, 1, 65, 0, 3, 71, 79, 85, + 214, 253, 17, 78, 3, 89, 6, 118, 65, 255, 194, 16, 72, 6, 142, 240, 17, + 65, 162, 14, 72, 3, 83, 10, 48, 2, 73, 76, 138, 169, 10, 72, 199, 143, 7, + 84, 5, 225, 177, 1, 4, 32, 76, 79, 78, 2, 193, 252, 17, 3, 32, 73, 89, 2, + 157, 150, 17, 7, 32, 82, 69, 80, 69, 84, 73, 30, 64, 10, 79, 87, 69, 76, + 32, 83, 73, 71, 78, 32, 187, 194, 15, 73, 28, 130, 1, 65, 44, 4, 67, 72, + 69, 73, 2, 79, 0, 3, 83, 79, 85, 0, 2, 89, 69, 22, 73, 38, 85, 178, 137, + 11, 78, 211, 185, 4, 86, 8, 198, 234, 16, 78, 210, 82, 65, 187, 64, 85, + 2, 155, 234, 16, 78, 4, 134, 234, 16, 78, 139, 147, 1, 73, 4, 226, 233, + 16, 78, 139, 147, 1, 85, 6, 148, 225, 16, 4, 80, 79, 77, 69, 146, 19, 84, + 195, 56, 79, 178, 3, 160, 1, 11, 68, 69, 32, 75, 73, 75, 65, 75, 85, 73, + 32, 212, 228, 16, 20, 79, 82, 65, 72, 32, 87, 73, 84, 72, 32, 78, 73, 78, + 69, 32, 66, 82, 65, 78, 67, 79, 83, 174, 3, 148, 1, 17, 67, 79, 77, 66, + 73, 78, 73, 78, 71, 32, 78, 85, 77, 66, 69, 82, 32, 164, 1, 10, 83, 89, + 76, 76, 65, 66, 76, 69, 32, 77, 215, 172, 9, 68, 14, 62, 84, 56, 7, 72, + 85, 78, 68, 82, 69, 68, 147, 186, 4, 77, 8, 26, 69, 219, 186, 4, 72, 6, + 26, 78, 167, 177, 14, 69, 4, 172, 186, 4, 2, 32, 84, 163, 190, 13, 83, + 142, 3, 22, 48, 143, 21, 49, 198, 1, 118, 48, 250, 1, 49, 210, 1, 50, + 138, 2, 51, 254, 1, 52, 130, 2, 53, 158, 2, 54, 242, 1, 55, 134, 2, 56, + 187, 2, 57, 18, 142, 1, 49, 34, 50, 22, 51, 22, 52, 162, 151, 2, 53, 162, + 241, 3, 56, 196, 236, 10, 3, 57, 32, 77, 92, 3, 55, 32, 77, 237, 90, 3, + 54, 32, 87, 2, 11, 32, 2, 151, 226, 17, 75, 2, 243, 236, 17, 32, 2, 179, + 159, 12, 32, 2, 11, 32, 2, 207, 225, 17, 87, 20, 130, 1, 49, 22, 54, 18, + 56, 22, 57, 228, 28, 2, 48, 32, 162, 188, 7, 53, 218, 209, 5, 52, 198, + 10, 55, 222, 9, 50, 207, 244, 3, 51, 2, 231, 198, 17, 32, 2, 147, 25, 32, + 2, 215, 214, 13, 32, 2, 227, 128, 13, 32, 20, 106, 49, 22, 50, 22, 51, + 22, 52, 22, 53, 22, 54, 22, 55, 22, 57, 142, 229, 11, 48, 185, 236, 1, 2, + 56, 32, 2, 147, 175, 10, 32, 2, 195, 134, 10, 32, 2, 227, 205, 17, 32, 2, + 211, 153, 12, 32, 2, 167, 238, 12, 32, 2, 219, 207, 17, 32, 2, 179, 232, + 12, 32, 2, 219, 28, 32, 20, 174, 1, 48, 16, 2, 49, 32, 20, 2, 52, 32, 20, + 2, 56, 32, 130, 195, 4, 57, 214, 51, 50, 22, 53, 220, 240, 7, 2, 54, 32, + 188, 136, 4, 3, 55, 32, 78, 237, 90, 3, 51, 32, 89, 2, 159, 37, 32, 2, + 163, 220, 17, 89, 2, 143, 220, 17, 70, 2, 183, 163, 16, 78, 20, 192, 1, + 2, 48, 32, 22, 53, 22, 56, 160, 8, 3, 52, 32, 75, 128, 22, 3, 54, 32, 72, + 222, 2, 55, 202, 213, 4, 49, 224, 184, 4, 3, 57, 32, 87, 156, 174, 4, 2, + 51, 32, 157, 197, 1, 3, 50, 32, 72, 2, 219, 251, 15, 72, 2, 175, 217, 15, + 32, 2, 211, 206, 17, 32, 20, 178, 1, 48, 18, 53, 20, 2, 54, 32, 20, 2, + 56, 32, 22, 57, 232, 218, 9, 2, 50, 32, 236, 4, 2, 51, 32, 210, 214, 1, + 49, 164, 234, 3, 3, 52, 32, 76, 197, 144, 1, 3, 55, 32, 78, 2, 159, 4, + 32, 2, 231, 162, 16, 32, 2, 191, 190, 17, 71, 2, 131, 156, 13, 78, 2, + 185, 149, 16, 2, 32, 77, 20, 196, 1, 2, 50, 32, 22, 54, 238, 25, 51, 168, + 2, 3, 55, 32, 78, 200, 216, 1, 2, 52, 32, 234, 150, 3, 56, 144, 150, 5, + 3, 48, 32, 78, 192, 89, 3, 49, 32, 87, 158, 13, 57, 249, 238, 4, 3, 53, + 32, 75, 2, 179, 188, 17, 77, 2, 207, 157, 10, 32, 20, 196, 1, 3, 52, 32, + 75, 20, 2, 53, 32, 22, 57, 232, 7, 3, 49, 32, 71, 234, 1, 51, 236, 6, 3, + 48, 32, 71, 146, 5, 50, 212, 230, 10, 2, 55, 32, 172, 160, 4, 3, 54, 32, + 75, 217, 88, 3, 56, 32, 70, 2, 131, 195, 17, 80, 2, 131, 209, 17, 70, 2, + 163, 249, 10, 32, 20, 228, 1, 2, 48, 32, 20, 2, 49, 32, 20, 2, 52, 32, + 22, 53, 172, 14, 6, 54, 32, 76, 79, 78, 71, 224, 11, 2, 57, 32, 228, 173, + 3, 3, 51, 32, 72, 128, 165, 9, 4, 50, 32, 78, 71, 236, 247, 3, 3, 55, 32, + 72, 189, 97, 3, 56, 32, 70, 2, 243, 206, 17, 89, 2, 147, 243, 15, 80, 2, + 255, 242, 15, 76, 2, 183, 232, 16, 32, 20, 230, 1, 53, 216, 14, 4, 48, + 32, 78, 71, 244, 7, 3, 51, 32, 71, 220, 163, 12, 2, 55, 32, 250, 117, 57, + 200, 117, 3, 50, 32, 75, 136, 203, 1, 3, 49, 32, 84, 156, 28, 4, 56, 32, + 78, 89, 152, 134, 1, 3, 52, 32, 77, 225, 34, 2, 54, 32, 2, 183, 179, 17, + 32, 200, 1, 118, 48, 186, 2, 49, 210, 2, 50, 166, 2, 51, 222, 1, 52, 186, + 2, 53, 214, 2, 54, 166, 2, 55, 190, 2, 56, 223, 2, 57, 20, 222, 1, 49, + 30, 52, 28, 7, 53, 32, 76, 79, 78, 71, 32, 12, 2, 51, 32, 184, 11, 6, 54, + 32, 76, 79, 78, 71, 202, 241, 4, 50, 170, 170, 2, 48, 204, 143, 5, 3, 55, + 32, 71, 200, 182, 3, 3, 57, 32, 89, 201, 40, 3, 56, 32, 75, 2, 129, 148, + 16, 2, 32, 70, 2, 137, 149, 15, 2, 32, 84, 2, 11, 77, 2, 227, 148, 15, + 66, 20, 208, 1, 6, 48, 32, 76, 79, 78, 71, 22, 51, 34, 54, 22, 56, 32, 2, + 57, 32, 248, 17, 4, 53, 32, 78, 71, 128, 209, 2, 2, 55, 32, 196, 151, 2, + 3, 50, 32, 75, 216, 151, 10, 3, 52, 32, 87, 181, 136, 2, 2, 49, 32, 2, + 183, 183, 16, 32, 2, 11, 32, 2, 255, 198, 17, 74, 2, 155, 210, 16, 32, 2, + 11, 32, 2, 203, 198, 17, 87, 2, 151, 202, 15, 78, 20, 226, 1, 50, 32, 2, + 51, 32, 128, 4, 3, 52, 32, 71, 254, 9, 48, 244, 245, 9, 4, 56, 32, 72, + 79, 208, 225, 2, 5, 55, 32, 78, 71, 71, 148, 88, 2, 53, 32, 168, 61, 2, + 57, 32, 216, 237, 1, 3, 54, 32, 87, 221, 153, 1, 2, 49, 32, 2, 11, 32, 2, + 183, 166, 13, 77, 2, 11, 78, 2, 143, 199, 17, 68, 20, 200, 3, 2, 56, 32, + 252, 4, 3, 52, 32, 78, 148, 244, 4, 3, 50, 32, 75, 250, 215, 2, 49, 2, + 53, 232, 174, 2, 2, 55, 32, 160, 140, 5, 3, 51, 32, 70, 0, 3, 54, 32, 83, + 224, 53, 2, 48, 32, 197, 152, 1, 3, 57, 32, 87, 20, 236, 1, 8, 50, 32, 76, 79, 78, 71, 32, 77, 20, 3, 53, 32, 77, 22, 54, 224, 2, 3, 57, 32, 78, - 174, 219, 6, 55, 220, 155, 3, 3, 51, 32, 87, 236, 224, 2, 2, 48, 32, 176, - 60, 3, 56, 32, 71, 204, 228, 1, 3, 49, 32, 89, 1, 3, 52, 32, 86, 2, 171, - 164, 17, 66, 2, 179, 175, 17, 66, 2, 213, 141, 16, 3, 32, 78, 71, 20, + 186, 220, 6, 55, 176, 160, 3, 3, 51, 32, 87, 160, 230, 2, 2, 48, 32, 168, + 60, 3, 56, 32, 71, 216, 233, 1, 3, 49, 32, 89, 1, 3, 52, 32, 86, 2, 147, + 184, 17, 66, 2, 155, 195, 17, 66, 2, 169, 159, 16, 3, 32, 78, 71, 20, 192, 1, 2, 50, 32, 34, 52, 26, 53, 34, 54, 36, 2, 55, 32, 188, 7, 2, 48, - 32, 244, 250, 9, 3, 56, 32, 75, 128, 193, 2, 2, 49, 32, 156, 138, 3, 5, - 57, 32, 78, 71, 71, 253, 207, 1, 2, 51, 32, 2, 11, 78, 2, 207, 190, 17, - 74, 2, 165, 5, 2, 32, 77, 2, 11, 32, 2, 247, 172, 17, 71, 2, 145, 249, - 14, 4, 32, 78, 71, 71, 2, 223, 208, 15, 74, 20, 220, 1, 2, 48, 32, 20, 6, - 49, 32, 76, 79, 78, 71, 30, 56, 156, 2, 2, 55, 32, 220, 192, 9, 3, 52, - 32, 78, 236, 49, 4, 54, 32, 71, 85, 232, 129, 5, 2, 53, 32, 240, 87, 3, - 50, 32, 83, 0, 2, 51, 32, 165, 101, 2, 57, 32, 2, 251, 246, 14, 74, 2, - 241, 157, 12, 2, 32, 77, 2, 171, 206, 12, 32, 24, 198, 1, 50, 2, 52, 36, - 6, 53, 32, 76, 79, 78, 71, 28, 3, 55, 32, 78, 34, 56, 184, 236, 11, 2, - 54, 32, 160, 98, 3, 57, 32, 75, 168, 253, 2, 3, 51, 32, 86, 136, 111, 4, - 48, 32, 78, 89, 219, 53, 49, 4, 181, 246, 14, 4, 32, 77, 66, 79, 2, 253, - 156, 17, 2, 32, 74, 2, 11, 71, 2, 203, 241, 15, 85, 2, 207, 231, 15, 32, + 32, 204, 128, 10, 3, 56, 32, 75, 188, 198, 2, 2, 49, 32, 136, 144, 3, 5, + 57, 32, 78, 71, 71, 229, 210, 1, 2, 51, 32, 2, 11, 78, 2, 183, 210, 17, + 74, 2, 165, 5, 2, 32, 77, 2, 11, 32, 2, 223, 192, 17, 71, 2, 169, 137, + 15, 4, 32, 78, 71, 71, 2, 223, 225, 15, 74, 20, 220, 1, 2, 48, 32, 20, 6, + 49, 32, 76, 79, 78, 71, 30, 56, 156, 2, 2, 55, 32, 188, 198, 9, 3, 52, + 32, 78, 236, 49, 4, 54, 32, 71, 85, 160, 140, 5, 2, 53, 32, 216, 88, 3, + 50, 32, 83, 0, 2, 51, 32, 241, 101, 2, 57, 32, 2, 147, 135, 15, 74, 2, + 141, 169, 12, 2, 32, 77, 2, 191, 217, 12, 32, 24, 198, 1, 50, 2, 52, 36, + 6, 53, 32, 76, 79, 78, 71, 28, 3, 55, 32, 78, 34, 56, 168, 247, 11, 2, + 54, 32, 196, 98, 3, 57, 32, 75, 148, 131, 3, 3, 51, 32, 86, 240, 113, 4, + 48, 32, 78, 89, 219, 53, 49, 4, 205, 134, 15, 4, 32, 77, 66, 79, 2, 229, + 176, 17, 2, 32, 74, 2, 11, 71, 2, 151, 131, 16, 85, 2, 155, 249, 15, 32, 20, 212, 1, 2, 48, 32, 22, 49, 22, 50, 20, 6, 51, 32, 76, 79, 78, 71, 34, - 56, 216, 136, 9, 2, 53, 32, 252, 128, 1, 3, 52, 32, 78, 168, 193, 2, 2, - 54, 32, 236, 251, 2, 4, 55, 32, 77, 66, 161, 30, 4, 57, 32, 77, 85, 2, - 163, 242, 14, 68, 2, 139, 136, 10, 32, 2, 239, 216, 10, 32, 2, 165, 172, - 15, 3, 32, 78, 71, 2, 17, 2, 32, 77, 2, 163, 201, 15, 66, 16, 142, 1, 48, + 56, 168, 142, 9, 2, 53, 32, 128, 129, 1, 3, 52, 32, 78, 232, 198, 2, 2, + 54, 32, 216, 129, 3, 4, 55, 32, 77, 66, 237, 30, 4, 57, 32, 77, 85, 2, + 187, 130, 15, 68, 2, 223, 141, 10, 32, 2, 215, 222, 10, 32, 2, 165, 189, + 15, 3, 32, 78, 71, 2, 17, 2, 32, 77, 2, 163, 218, 15, 66, 16, 142, 1, 48, 32, 3, 49, 32, 78, 20, 3, 50, 32, 78, 20, 2, 51, 32, 20, 3, 52, 32, 87, - 22, 53, 20, 2, 54, 32, 213, 201, 12, 3, 55, 32, 70, 2, 11, 32, 2, 243, - 199, 15, 71, 2, 223, 199, 15, 68, 2, 155, 146, 17, 74, 2, 131, 231, 16, - 72, 2, 131, 163, 17, 85, 2, 199, 236, 15, 32, 2, 255, 144, 1, 83, 248, 1, - 72, 6, 79, 73, 84, 73, 67, 32, 204, 254, 10, 2, 67, 85, 179, 183, 2, 80, + 22, 53, 20, 2, 54, 32, 233, 212, 12, 3, 55, 32, 70, 2, 11, 32, 2, 243, + 216, 15, 71, 2, 223, 216, 15, 68, 2, 131, 166, 17, 74, 2, 235, 250, 16, + 72, 2, 235, 182, 17, 85, 2, 147, 254, 15, 32, 2, 163, 145, 1, 83, 248, 1, + 72, 6, 79, 73, 84, 73, 67, 32, 212, 131, 11, 2, 67, 85, 191, 193, 2, 80, 244, 1, 104, 8, 67, 85, 82, 83, 73, 86, 69, 32, 221, 10, 13, 72, 73, 69, 82, 79, 71, 76, 89, 80, 72, 73, 67, 32, 180, 1, 96, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 250, 2, 76, 133, 3, 7, 78, 85, 77, 66, 69, 82, 32, 24, 78, 69, 50, 70, 44, 4, 79, 78, 69, 32, 46, 83, 50, 84, 61, 3, 78, 73, 78, 4, 160, 1, 2, 76, 69, 93, 4, 73, 71, 72, 84, 4, 192, 1, 2, 73, 86, - 13, 3, 79, 85, 82, 4, 140, 175, 15, 4, 84, 87, 69, 76, 19, 72, 4, 26, 69, + 13, 3, 79, 85, 82, 4, 140, 192, 15, 4, 84, 87, 69, 76, 19, 72, 4, 26, 69, 93, 2, 73, 88, 2, 65, 2, 86, 69, 6, 46, 69, 12, 3, 72, 82, 69, 13, 2, 87, - 79, 2, 23, 78, 2, 11, 69, 2, 237, 176, 15, 5, 32, 84, 87, 69, 76, 52, 76, + 79, 2, 23, 78, 2, 11, 69, 2, 237, 193, 15, 5, 32, 84, 87, 69, 76, 52, 76, 6, 69, 84, 84, 69, 82, 32, 137, 2, 8, 79, 71, 79, 71, 82, 65, 77, 32, 48, - 182, 1, 65, 46, 84, 182, 235, 1, 78, 2, 83, 218, 200, 13, 72, 130, 179, + 182, 1, 65, 46, 84, 238, 235, 1, 78, 2, 83, 162, 217, 13, 72, 234, 181, 1, 75, 138, 69, 66, 2, 68, 2, 76, 2, 77, 2, 80, 2, 81, 2, 82, 2, 87, 2, - 89, 186, 2, 69, 2, 73, 3, 79, 5, 253, 176, 11, 6, 82, 67, 72, 65, 73, 67, - 6, 202, 174, 17, 65, 2, 69, 3, 79, 4, 138, 209, 4, 73, 241, 192, 12, 2, + 89, 186, 2, 69, 2, 73, 3, 79, 5, 157, 182, 11, 6, 82, 67, 72, 65, 73, 67, + 6, 178, 194, 17, 65, 2, 69, 3, 79, 4, 202, 209, 4, 73, 153, 212, 12, 2, 82, 77, 104, 92, 5, 69, 73, 71, 72, 84, 30, 70, 92, 4, 78, 73, 78, 69, 54, 83, 78, 84, 73, 2, 79, 78, 11, 150, 1, 89, 223, 1, 32, 24, 18, 73, - 35, 79, 12, 142, 2, 86, 207, 235, 3, 70, 12, 148, 2, 2, 85, 82, 167, 235, - 3, 82, 11, 28, 2, 84, 89, 223, 1, 32, 2, 203, 160, 6, 32, 24, 40, 4, 69, - 86, 69, 78, 1, 2, 73, 88, 13, 154, 1, 32, 167, 235, 3, 84, 28, 34, 72, - 50, 87, 131, 159, 6, 69, 12, 32, 2, 82, 69, 155, 235, 3, 73, 8, 39, 69, - 12, 26, 79, 155, 235, 3, 69, 9, 11, 32, 6, 166, 157, 6, 72, 235, 185, 5, - 84, 64, 96, 7, 76, 69, 84, 84, 69, 82, 32, 141, 167, 3, 11, 83, 89, 77, + 35, 79, 12, 142, 2, 86, 163, 236, 3, 70, 12, 148, 2, 2, 85, 82, 251, 235, + 3, 82, 11, 28, 2, 84, 89, 223, 1, 32, 2, 215, 161, 6, 32, 24, 40, 4, 69, + 86, 69, 78, 1, 2, 73, 88, 13, 154, 1, 32, 251, 235, 3, 84, 28, 34, 72, + 50, 87, 143, 160, 6, 69, 12, 32, 2, 82, 69, 239, 235, 3, 73, 8, 39, 69, + 12, 26, 79, 239, 235, 3, 69, 9, 11, 32, 6, 178, 158, 6, 72, 207, 195, 5, + 84, 64, 96, 7, 76, 69, 84, 84, 69, 82, 32, 201, 167, 3, 11, 83, 89, 77, 66, 79, 76, 32, 86, 73, 68, 74, 60, 174, 1, 66, 2, 82, 22, 78, 30, 83, - 38, 84, 222, 172, 15, 72, 130, 179, 1, 75, 138, 69, 68, 2, 76, 2, 77, 2, - 80, 2, 81, 2, 87, 2, 89, 186, 2, 65, 2, 69, 2, 73, 3, 79, 4, 219, 165, 3, - 65, 8, 198, 165, 3, 65, 3, 69, 6, 170, 165, 3, 65, 151, 130, 14, 69, 10, - 134, 165, 3, 65, 2, 69, 151, 130, 14, 79, 2, 215, 160, 12, 73, 20, 44, 5, - 73, 67, 65, 76, 32, 175, 166, 17, 79, 18, 116, 10, 76, 79, 78, 71, 32, - 79, 86, 69, 82, 32, 74, 80, 26, 84, 168, 1, 7, 83, 72, 79, 82, 84, 32, - 79, 215, 32, 66, 4, 156, 246, 2, 2, 83, 72, 201, 237, 10, 7, 84, 87, 79, - 32, 83, 72, 79, 2, 109, 3, 69, 78, 84, 8, 66, 69, 34, 82, 41, 10, 87, 79, - 32, 83, 72, 79, 82, 84, 83, 32, 2, 17, 2, 84, 82, 2, 23, 65, 2, 11, 73, - 2, 245, 139, 16, 2, 83, 69, 4, 26, 79, 163, 254, 7, 74, 2, 129, 190, 10, - 4, 86, 69, 82, 32, 230, 2, 104, 3, 65, 79, 32, 136, 18, 2, 67, 82, 142, - 1, 68, 142, 1, 76, 130, 1, 78, 245, 2, 4, 82, 82, 79, 82, 170, 2, 156, 1, - 7, 76, 69, 84, 84, 69, 82, 32, 180, 10, 5, 83, 73, 71, 78, 32, 212, 1, 5, - 84, 79, 78, 69, 32, 69, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, - 178, 1, 214, 1, 65, 110, 66, 34, 68, 106, 71, 34, 76, 50, 78, 106, 82, - 170, 1, 83, 54, 84, 218, 1, 86, 32, 3, 89, 73, 32, 118, 90, 246, 165, 13, - 81, 254, 231, 1, 80, 246, 193, 1, 72, 2, 77, 138, 69, 70, 2, 75, 2, 87, - 3, 88, 10, 52, 7, 82, 67, 72, 65, 73, 67, 32, 227, 158, 17, 72, 8, 210, - 254, 8, 90, 222, 174, 4, 78, 251, 238, 3, 77, 4, 210, 138, 17, 82, 219, - 19, 65, 16, 50, 90, 154, 4, 76, 138, 151, 17, 68, 187, 2, 65, 8, 254, - 137, 17, 89, 162, 17, 72, 2, 90, 187, 2, 65, 6, 226, 213, 16, 72, 195, - 71, 65, 8, 222, 178, 10, 72, 238, 231, 6, 89, 187, 2, 65, 18, 54, 65, - 222, 212, 16, 71, 2, 78, 2, 89, 139, 69, 72, 5, 11, 83, 2, 149, 218, 13, - 4, 65, 76, 73, 90, 16, 60, 9, 69, 70, 79, 82, 77, 69, 68, 32, 84, 219, - 132, 17, 84, 14, 40, 4, 79, 78, 69, 45, 195, 160, 15, 83, 12, 254, 154, - 17, 49, 2, 50, 2, 52, 2, 53, 2, 54, 3, 56, 8, 234, 134, 17, 89, 162, 17, - 72, 2, 83, 187, 2, 65, 32, 78, 76, 20, 4, 79, 78, 69, 45, 70, 83, 178, - 150, 17, 84, 186, 2, 65, 3, 69, 4, 155, 175, 10, 72, 14, 170, 153, 17, - 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 8, 174, 150, 17, 72, 2, 83, - 186, 2, 65, 3, 69, 4, 254, 149, 17, 70, 187, 2, 65, 16, 70, 84, 144, 157, - 15, 2, 68, 90, 190, 62, 78, 206, 185, 1, 75, 3, 80, 8, 142, 208, 16, 83, - 138, 69, 84, 187, 2, 65, 16, 50, 90, 178, 207, 16, 83, 138, 69, 72, 187, - 2, 65, 8, 202, 172, 10, 83, 238, 231, 6, 89, 187, 2, 65, 8, 144, 1, 9, - 82, 69, 70, 79, 82, 77, 69, 68, 32, 34, 65, 189, 243, 15, 18, 67, 79, 78, - 83, 79, 78, 65, 78, 84, 32, 77, 79, 68, 73, 70, 73, 69, 82, 4, 30, 65, - 213, 88, 2, 86, 79, 2, 133, 139, 12, 3, 83, 80, 73, 8, 218, 246, 14, 66, - 140, 77, 3, 84, 79, 80, 154, 84, 65, 159, 82, 82, 104, 146, 1, 65, 78, - 69, 62, 73, 78, 79, 74, 85, 74, 89, 160, 145, 7, 9, 82, 79, 85, 78, 68, - 69, 68, 32, 69, 178, 185, 7, 87, 202, 74, 78, 251, 124, 86, 19, 250, 151, - 15, 78, 250, 186, 1, 69, 146, 63, 72, 146, 1, 65, 2, 73, 3, 85, 15, 254, - 191, 13, 82, 178, 215, 1, 78, 154, 251, 1, 65, 3, 73, 23, 230, 150, 15, - 65, 54, 79, 158, 250, 1, 78, 86, 69, 2, 71, 2, 73, 3, 85, 13, 42, 69, - 150, 145, 17, 71, 2, 79, 3, 85, 4, 146, 145, 17, 82, 3, 89, 19, 210, 149, - 15, 65, 206, 231, 1, 69, 134, 19, 78, 2, 79, 86, 73, 3, 85, 7, 214, 252, - 16, 85, 219, 19, 73, 12, 18, 32, 63, 79, 4, 196, 252, 15, 4, 79, 78, 32, - 85, 13, 4, 68, 65, 83, 72, 8, 206, 226, 11, 83, 162, 130, 4, 80, 222, 35, - 32, 163, 112, 66, 12, 64, 4, 68, 76, 69, 32, 189, 223, 4, 6, 76, 73, 78, - 69, 32, 72, 10, 184, 192, 5, 3, 84, 72, 73, 238, 217, 8, 76, 22, 82, 207, - 163, 2, 68, 8, 76, 6, 73, 84, 65, 82, 89, 32, 232, 188, 10, 3, 75, 89, - 32, 195, 201, 5, 76, 4, 26, 72, 199, 170, 12, 77, 2, 227, 177, 4, 69, 24, - 42, 73, 76, 2, 85, 83, 131, 140, 17, 89, 6, 34, 68, 22, 77, 155, 134, 15, - 66, 2, 219, 156, 6, 73, 2, 223, 235, 6, 73, 16, 46, 32, 205, 177, 10, 5, - 45, 79, 82, 45, 80, 14, 40, 4, 83, 73, 71, 78, 203, 167, 13, 84, 13, 11, - 32, 10, 44, 5, 87, 73, 84, 72, 32, 135, 173, 6, 73, 8, 66, 67, 250, 202, - 4, 68, 234, 163, 8, 82, 21, 4, 70, 65, 76, 76, 2, 177, 231, 11, 3, 79, - 77, 77, 5, 171, 130, 15, 32, 184, 9, 184, 1, 10, 66, 73, 76, 69, 32, 80, - 72, 79, 78, 69, 166, 1, 68, 190, 76, 78, 170, 27, 79, 172, 1, 3, 83, 81, - 85, 38, 84, 250, 1, 85, 242, 176, 11, 89, 209, 219, 2, 5, 86, 73, 69, 32, - 67, 7, 11, 32, 4, 108, 21, 87, 73, 84, 72, 32, 82, 73, 71, 72, 84, 87, - 65, 82, 68, 83, 32, 65, 82, 82, 79, 87, 167, 178, 1, 79, 2, 11, 32, 2, - 225, 212, 16, 2, 65, 84, 154, 6, 58, 69, 74, 73, 149, 75, 7, 85, 76, 79, - 32, 84, 87, 79, 4, 208, 182, 16, 10, 82, 78, 32, 80, 69, 78, 84, 65, 84, - 72, 159, 18, 76, 148, 6, 42, 32, 221, 1, 5, 70, 73, 69, 82, 32, 158, 1, - 88, 5, 83, 73, 71, 78, 32, 230, 179, 3, 86, 190, 162, 3, 68, 186, 1, 76, - 195, 194, 4, 65, 10, 42, 65, 166, 212, 8, 72, 155, 237, 7, 86, 4, 44, 5, - 82, 68, 72, 65, 67, 175, 191, 16, 78, 2, 213, 191, 16, 3, 65, 78, 68, - 246, 4, 92, 12, 66, 82, 69, 86, 69, 32, 87, 73, 84, 72, 32, 73, 89, 7, - 76, 69, 84, 84, 69, 82, 32, 2, 33, 6, 78, 86, 69, 82, 84, 69, 2, 21, 3, - 68, 32, 66, 2, 129, 134, 16, 2, 82, 69, 244, 4, 198, 1, 65, 82, 66, 66, - 67, 190, 13, 68, 202, 1, 69, 182, 2, 71, 82, 72, 46, 76, 230, 4, 77, 216, - 3, 7, 79, 80, 69, 78, 32, 83, 72, 22, 80, 38, 82, 182, 4, 83, 206, 33, - 84, 114, 85, 118, 86, 63, 89, 6, 38, 76, 158, 27, 67, 251, 204, 10, 80, - 2, 245, 19, 6, 86, 69, 79, 76, 65, 82, 6, 184, 19, 5, 73, 76, 65, 66, 73, - 193, 45, 4, 69, 71, 73, 78, 160, 1, 240, 1, 7, 65, 80, 73, 84, 65, 76, - 32, 192, 2, 7, 69, 78, 84, 82, 69, 68, 32, 100, 13, 72, 73, 78, 69, 83, - 69, 32, 84, 79, 78, 69, 32, 89, 108, 8, 89, 82, 73, 76, 76, 73, 67, 32, - 242, 225, 10, 73, 244, 2, 4, 82, 79, 83, 83, 255, 196, 5, 79, 56, 206, 1, - 66, 42, 82, 130, 27, 72, 202, 141, 13, 79, 138, 147, 3, 65, 162, 64, 67, - 2, 68, 2, 69, 2, 70, 2, 71, 2, 73, 2, 74, 2, 75, 2, 76, 2, 77, 2, 78, 2, - 80, 2, 81, 2, 84, 2, 85, 2, 86, 3, 87, 5, 133, 150, 6, 5, 65, 82, 82, 69, - 68, 7, 41, 8, 69, 86, 69, 82, 83, 69, 68, 32, 4, 194, 251, 16, 69, 3, 78, - 4, 30, 76, 21, 3, 82, 73, 71, 2, 29, 2, 69, 70, 2, 11, 72, 2, 11, 84, 2, - 181, 26, 2, 32, 72, 16, 36, 3, 65, 78, 71, 1, 2, 73, 78, 8, 11, 32, 8, - 182, 134, 12, 83, 214, 162, 4, 80, 158, 44, 81, 3, 82, 78, 34, 72, 30, - 83, 187, 169, 16, 69, 2, 217, 144, 15, 2, 65, 82, 74, 40, 5, 77, 65, 76, - 76, 32, 183, 6, 79, 72, 186, 1, 66, 138, 1, 68, 38, 69, 150, 1, 80, 58, - 83, 94, 84, 34, 89, 158, 243, 15, 90, 130, 64, 73, 150, 19, 67, 2, 71, - 186, 22, 74, 2, 86, 158, 20, 72, 2, 75, 186, 2, 65, 2, 79, 3, 85, 6, 38, - 89, 198, 27, 65, 199, 219, 16, 69, 2, 221, 202, 1, 19, 69, 76, 79, 82, - 85, 83, 83, 73, 65, 78, 45, 85, 75, 82, 65, 73, 78, 73, 65, 4, 242, 213, - 6, 90, 183, 160, 10, 69, 15, 50, 83, 210, 245, 16, 70, 2, 76, 2, 77, 3, - 82, 5, 25, 4, 32, 87, 73, 84, 2, 21, 3, 72, 32, 68, 2, 11, 69, 2, 177, - 141, 13, 3, 83, 67, 69, 4, 26, 65, 215, 244, 16, 69, 2, 137, 200, 16, 2, - 76, 79, 8, 42, 84, 206, 173, 1, 67, 139, 196, 15, 72, 4, 153, 19, 8, 82, - 65, 73, 71, 72, 84, 32, 85, 4, 134, 221, 16, 83, 215, 22, 69, 6, 36, 3, - 69, 82, 85, 151, 243, 16, 85, 5, 37, 7, 32, 87, 73, 84, 72, 32, 66, 2, - 21, 3, 65, 67, 75, 2, 229, 180, 16, 2, 32, 89, 2, 227, 175, 11, 70, 16, - 18, 69, 27, 79, 2, 169, 5, 2, 78, 84, 14, 64, 2, 84, 32, 52, 5, 85, 66, - 76, 69, 32, 129, 52, 2, 87, 78, 6, 242, 218, 9, 83, 142, 192, 4, 86, 171, - 180, 1, 72, 4, 194, 137, 2, 65, 219, 247, 2, 80, 24, 40, 5, 88, 84, 82, - 65, 45, 131, 49, 78, 20, 52, 5, 72, 73, 71, 72, 32, 81, 4, 76, 79, 87, - 32, 10, 156, 1, 9, 69, 88, 84, 82, 65, 45, 76, 79, 87, 154, 7, 68, 70, - 76, 79, 84, 10, 76, 10, 69, 88, 84, 82, 65, 45, 72, 73, 71, 72, 154, 7, - 68, 70, 76, 79, 84, 2, 145, 8, 8, 32, 67, 79, 78, 84, 79, 85, 82, 8, 162, - 9, 82, 226, 3, 76, 237, 191, 15, 9, 69, 79, 82, 71, 73, 65, 78, 32, 78, - 10, 248, 5, 4, 73, 71, 72, 32, 255, 40, 65, 44, 46, 65, 84, 2, 79, 87, - 201, 11, 2, 69, 70, 2, 21, 3, 84, 69, 82, 2, 17, 2, 65, 76, 2, 17, 2, 32, - 67, 2, 191, 188, 15, 76, 36, 86, 32, 249, 139, 12, 15, 69, 82, 32, 82, - 73, 71, 72, 84, 32, 67, 79, 82, 78, 69, 82, 34, 158, 1, 67, 20, 2, 68, - 79, 40, 4, 76, 69, 70, 84, 82, 77, 12, 2, 82, 73, 50, 84, 178, 3, 65, 42, - 71, 170, 2, 73, 184, 141, 14, 2, 85, 80, 179, 187, 1, 86, 2, 199, 210, - 10, 73, 6, 238, 2, 84, 253, 145, 14, 2, 87, 78, 6, 28, 2, 32, 65, 247, 2, - 45, 4, 25, 4, 82, 82, 79, 87, 5, 199, 148, 14, 72, 2, 111, 65, 4, 228, - 147, 14, 3, 71, 72, 84, 223, 212, 2, 78, 4, 194, 2, 79, 243, 204, 14, 73, - 18, 18, 65, 23, 73, 2, 147, 195, 15, 67, 16, 26, 68, 195, 185, 13, 78, - 14, 38, 32, 217, 1, 4, 68, 76, 69, 32, 8, 26, 68, 70, 76, 79, 84, 4, 17, - 2, 79, 84, 4, 25, 4, 84, 69, 68, 32, 4, 18, 76, 79, 84, 2, 25, 4, 69, 70, - 84, 45, 2, 25, 4, 83, 84, 69, 77, 2, 17, 2, 32, 84, 2, 11, 79, 2, 11, 78, - 2, 199, 196, 15, 69, 6, 40, 6, 68, 79, 85, 66, 76, 69, 75, 71, 4, 11, 32, - 4, 18, 65, 43, 71, 2, 11, 67, 2, 169, 208, 10, 2, 85, 84, 2, 11, 82, 2, - 247, 207, 10, 65, 2, 207, 225, 14, 69, 4, 150, 182, 13, 76, 207, 150, 2, - 82, 26, 104, 6, 65, 73, 83, 69, 68, 32, 150, 1, 69, 216, 1, 3, 73, 71, - 72, 133, 245, 8, 5, 72, 79, 84, 73, 67, 10, 70, 68, 30, 73, 162, 213, 9, - 69, 244, 242, 5, 2, 85, 80, 211, 74, 67, 2, 157, 146, 15, 2, 79, 87, 2, - 137, 213, 9, 7, 78, 86, 69, 82, 84, 69, 68, 8, 104, 7, 86, 69, 82, 83, - 69, 68, 32, 137, 28, 14, 84, 82, 79, 70, 76, 69, 88, 32, 67, 76, 73, 67, - 75, 32, 6, 26, 71, 175, 143, 14, 67, 4, 11, 76, 4, 49, 10, 79, 84, 84, - 65, 76, 32, 83, 84, 79, 80, 5, 171, 19, 32, 6, 17, 2, 84, 32, 6, 38, 72, - 166, 197, 13, 84, 235, 69, 65, 2, 133, 191, 7, 3, 65, 76, 70, 156, 2, - 138, 1, 72, 48, 5, 77, 65, 76, 76, 32, 148, 31, 8, 84, 82, 69, 83, 83, - 32, 65, 78, 53, 11, 85, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 4, 136, - 153, 8, 3, 79, 82, 84, 203, 194, 6, 69, 144, 2, 154, 2, 65, 50, 66, 130, - 1, 67, 238, 2, 68, 238, 2, 90, 66, 69, 46, 70, 30, 71, 110, 72, 102, 77, - 34, 73, 34, 74, 98, 76, 176, 3, 7, 78, 32, 87, 73, 84, 72, 32, 30, 79, - 94, 80, 22, 82, 146, 2, 83, 190, 1, 84, 246, 7, 85, 142, 1, 86, 158, 192, - 16, 75, 2, 81, 2, 87, 2, 88, 3, 89, 9, 238, 131, 13, 76, 214, 136, 3, 73, - 227, 79, 69, 11, 46, 65, 50, 79, 222, 8, 32, 239, 173, 16, 69, 2, 17, 2, - 82, 82, 2, 193, 246, 5, 2, 69, 68, 2, 229, 20, 4, 84, 84, 79, 77, 41, - 100, 7, 65, 80, 73, 84, 65, 76, 32, 180, 1, 6, 76, 79, 83, 69, 68, 32, - 190, 17, 32, 199, 179, 16, 72, 30, 114, 73, 214, 6, 71, 226, 16, 76, 146, - 171, 16, 79, 158, 20, 65, 186, 2, 66, 2, 72, 2, 78, 2, 82, 2, 85, 3, 89, - 7, 22, 78, 191, 11, 32, 2, 249, 239, 5, 5, 86, 69, 82, 84, 69, 4, 26, 82, - 195, 161, 9, 79, 2, 217, 20, 9, 69, 86, 69, 82, 83, 69, 68, 32, 79, 23, - 104, 6, 32, 87, 73, 84, 72, 32, 86, 69, 32, 9, 79, 84, 76, 69, 83, 83, - 32, 74, 32, 105, 3, 90, 32, 68, 6, 26, 72, 163, 163, 14, 84, 4, 21, 3, - 79, 79, 75, 5, 225, 234, 13, 3, 32, 65, 78, 4, 238, 15, 90, 143, 162, 16, - 76, 4, 33, 6, 87, 73, 84, 72, 32, 83, 4, 29, 5, 84, 82, 79, 75, 69, 5, - 133, 234, 8, 4, 32, 65, 78, 68, 6, 33, 6, 73, 71, 82, 65, 80, 72, 7, 33, - 6, 32, 87, 73, 84, 72, 32, 4, 138, 14, 67, 207, 4, 82, 11, 202, 211, 16, - 83, 2, 84, 2, 90, 63, 78, 5, 225, 13, 3, 69, 78, 71, 11, 56, 5, 82, 69, - 69, 75, 32, 162, 1, 32, 195, 128, 14, 65, 4, 26, 71, 191, 132, 11, 80, 2, - 195, 129, 14, 65, 11, 40, 6, 32, 87, 73, 84, 72, 32, 39, 69, 4, 166, 255, - 14, 72, 219, 163, 1, 83, 4, 17, 2, 78, 71, 5, 11, 32, 2, 195, 230, 8, 87, - 4, 222, 4, 32, 251, 168, 16, 79, 5, 37, 7, 32, 87, 73, 84, 72, 32, 67, 2, - 11, 82, 2, 225, 157, 14, 6, 79, 83, 83, 69, 68, 45, 25, 116, 6, 32, 87, - 73, 84, 72, 32, 226, 9, 83, 2, 90, 112, 2, 69, 90, 253, 174, 16, 8, 73, - 71, 65, 84, 85, 82, 69, 32, 12, 54, 73, 82, 77, 82, 82, 222, 6, 80, 243, - 244, 3, 66, 2, 49, 10, 78, 86, 69, 82, 84, 69, 68, 32, 76, 65, 2, 173, - 218, 12, 2, 90, 89, 2, 11, 73, 2, 17, 2, 68, 68, 2, 17, 2, 76, 69, 2, - 145, 235, 12, 2, 32, 84, 4, 61, 13, 69, 84, 82, 79, 70, 76, 69, 88, 32, - 72, 79, 79, 75, 5, 205, 12, 4, 32, 65, 78, 68, 4, 210, 11, 82, 207, 1, - 76, 9, 18, 32, 47, 80, 2, 21, 3, 87, 73, 84, 2, 151, 157, 16, 72, 4, 193, - 186, 12, 2, 69, 78, 5, 163, 185, 16, 72, 15, 80, 6, 32, 87, 73, 84, 72, - 32, 62, 65, 41, 8, 69, 86, 69, 82, 83, 69, 68, 32, 4, 26, 70, 155, 152, - 14, 84, 2, 165, 224, 8, 3, 73, 83, 72, 2, 17, 2, 77, 83, 2, 131, 232, 5, - 32, 6, 38, 71, 170, 7, 79, 227, 195, 16, 69, 2, 11, 76, 2, 173, 249, 13, - 4, 79, 84, 84, 65, 13, 72, 6, 32, 87, 73, 84, 72, 32, 34, 67, 61, 6, 73, - 68, 69, 87, 65, 89, 4, 158, 3, 67, 155, 243, 14, 72, 4, 26, 82, 203, 216, - 11, 72, 2, 233, 218, 5, 3, 73, 80, 84, 2, 231, 189, 6, 83, 51, 106, 32, - 102, 67, 116, 2, 69, 83, 44, 2, 79, 80, 42, 83, 96, 6, 85, 82, 78, 69, - 68, 32, 231, 139, 13, 72, 4, 29, 5, 87, 73, 84, 72, 32, 4, 22, 80, 219, - 5, 82, 2, 153, 220, 8, 6, 65, 76, 65, 84, 65, 76, 2, 45, 9, 32, 68, 73, - 71, 82, 65, 80, 72, 32, 2, 25, 4, 87, 73, 84, 72, 2, 17, 2, 32, 67, 2, - 179, 145, 3, 85, 2, 11, 72, 2, 217, 150, 10, 3, 32, 68, 73, 2, 189, 225, - 5, 5, 32, 72, 65, 76, 70, 4, 37, 7, 32, 68, 73, 71, 82, 65, 80, 4, 11, - 72, 5, 11, 32, 2, 141, 3, 4, 87, 73, 84, 72, 32, 86, 65, 38, 77, 74, 79, - 42, 82, 214, 1, 89, 230, 193, 16, 72, 2, 73, 2, 86, 3, 87, 7, 150, 236, - 12, 76, 183, 216, 3, 69, 5, 41, 8, 32, 87, 73, 84, 72, 32, 76, 79, 2, - 213, 141, 4, 2, 78, 71, 2, 11, 80, 2, 225, 156, 6, 2, 69, 78, 9, 33, 6, - 32, 87, 73, 84, 72, 32, 6, 26, 76, 167, 239, 14, 72, 4, 37, 7, 79, 78, - 71, 32, 76, 69, 71, 5, 25, 4, 32, 65, 78, 68, 2, 17, 2, 32, 82, 2, 11, - 69, 2, 181, 214, 8, 7, 84, 82, 79, 70, 76, 69, 88, 5, 29, 5, 32, 87, 73, - 84, 72, 2, 185, 238, 3, 2, 32, 66, 9, 18, 32, 95, 80, 4, 40, 4, 87, 73, - 84, 72, 179, 159, 15, 66, 2, 17, 2, 32, 76, 2, 11, 69, 2, 131, 1, 70, 2, - 189, 240, 15, 2, 83, 73, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 26, 82, - 139, 236, 14, 72, 2, 21, 3, 73, 71, 72, 2, 231, 211, 8, 84, 4, 11, 68, 4, - 11, 32, 4, 130, 210, 1, 72, 35, 76, 4, 24, 2, 72, 65, 31, 84, 2, 25, 4, - 76, 70, 32, 84, 2, 43, 82, 4, 30, 82, 53, 3, 85, 82, 78, 2, 249, 237, 15, - 8, 73, 65, 78, 71, 85, 76, 65, 82, 2, 253, 166, 8, 2, 69, 68, 8, 70, 80, - 212, 154, 10, 7, 78, 65, 83, 80, 73, 82, 65, 175, 162, 6, 83, 4, 11, 32, - 4, 242, 161, 13, 84, 235, 69, 65, 4, 26, 79, 199, 162, 15, 69, 2, 11, 73, - 2, 167, 235, 15, 67, 4, 36, 3, 65, 78, 71, 1, 2, 73, 78, 2, 25, 4, 32, - 68, 69, 80, 2, 21, 3, 65, 82, 84, 2, 21, 3, 73, 78, 71, 2, 17, 2, 32, 84, - 2, 11, 79, 2, 143, 134, 6, 78, 2, 11, 32, 2, 211, 145, 15, 83, 234, 2, - 92, 2, 69, 89, 88, 7, 71, 79, 76, 73, 65, 78, 32, 206, 24, 79, 177, 130, - 12, 3, 75, 69, 89, 6, 26, 32, 135, 252, 15, 45, 4, 152, 131, 12, 6, 87, - 73, 84, 72, 32, 87, 179, 205, 2, 66, 214, 2, 194, 2, 68, 46, 70, 148, 1, - 14, 73, 78, 86, 69, 82, 84, 69, 68, 32, 66, 73, 82, 71, 65, 16, 7, 76, - 69, 84, 84, 69, 82, 32, 138, 16, 83, 132, 1, 7, 82, 79, 84, 65, 84, 69, - 68, 22, 66, 98, 84, 160, 2, 4, 86, 79, 87, 69, 154, 241, 3, 67, 164, 1, - 6, 77, 65, 78, 67, 72, 85, 216, 190, 7, 4, 78, 73, 82, 85, 239, 203, 2, - 69, 22, 232, 20, 3, 79, 85, 66, 207, 176, 14, 73, 12, 112, 19, 82, 69, - 69, 32, 86, 65, 82, 73, 65, 84, 73, 79, 78, 32, 83, 69, 76, 69, 67, 214, - 227, 13, 85, 199, 46, 79, 8, 249, 244, 9, 3, 84, 79, 82, 5, 227, 19, 32, - 136, 2, 130, 2, 65, 244, 4, 2, 67, 72, 88, 2, 77, 65, 174, 2, 83, 246, 1, - 84, 234, 3, 90, 214, 178, 14, 72, 142, 171, 1, 75, 2, 76, 162, 7, 69, 2, - 79, 2, 85, 234, 61, 66, 2, 68, 2, 70, 2, 71, 2, 74, 2, 78, 2, 80, 2, 81, - 2, 82, 2, 87, 2, 89, 187, 2, 73, 59, 56, 8, 76, 73, 32, 71, 65, 76, 73, - 32, 231, 177, 16, 78, 54, 174, 1, 65, 52, 6, 86, 73, 83, 65, 82, 71, 22, - 68, 76, 5, 72, 65, 76, 70, 32, 34, 73, 50, 85, 34, 78, 30, 84, 66, 66, - 234, 230, 15, 80, 2, 90, 254, 68, 83, 14, 67, 3, 75, 7, 48, 6, 78, 85, - 83, 86, 65, 82, 215, 176, 16, 72, 2, 195, 160, 9, 65, 8, 26, 65, 239, - 173, 16, 68, 7, 246, 247, 8, 77, 233, 245, 6, 3, 71, 65, 76, 4, 186, 173, - 16, 89, 187, 2, 85, 5, 45, 9, 78, 86, 69, 82, 84, 69, 68, 32, 85, 2, 181, - 236, 15, 3, 66, 65, 68, 4, 202, 172, 16, 71, 3, 78, 8, 60, 6, 72, 82, 69, - 69, 32, 66, 234, 230, 15, 84, 195, 71, 65, 2, 17, 2, 65, 76, 2, 143, 137, - 16, 85, 6, 26, 65, 231, 173, 16, 73, 5, 29, 5, 32, 87, 73, 84, 72, 2, - 237, 220, 14, 2, 32, 84, 41, 29, 5, 78, 67, 72, 85, 32, 38, 104, 9, 65, - 76, 73, 32, 71, 65, 76, 73, 32, 222, 177, 14, 90, 138, 248, 1, 70, 2, 75, - 2, 82, 187, 2, 73, 28, 122, 68, 254, 192, 9, 67, 226, 222, 2, 84, 134, - 145, 2, 66, 2, 71, 2, 74, 2, 76, 130, 179, 1, 90, 254, 4, 78, 131, 64, - 83, 4, 222, 176, 14, 68, 139, 248, 1, 72, 48, 52, 4, 73, 66, 69, 32, 142, - 168, 16, 72, 187, 2, 65, 44, 242, 221, 5, 71, 2, 72, 158, 173, 6, 73, - 154, 19, 84, 222, 145, 2, 67, 2, 83, 246, 7, 82, 214, 161, 1, 65, 186, 9, - 90, 162, 7, 85, 234, 61, 68, 2, 70, 2, 74, 2, 75, 2, 80, 187, 2, 69, 60, - 52, 4, 79, 68, 79, 32, 154, 166, 16, 83, 187, 2, 65, 56, 250, 1, 65, 98, - 68, 34, 74, 34, 78, 236, 164, 1, 8, 76, 79, 78, 71, 32, 86, 79, 87, 250, - 179, 4, 71, 182, 192, 6, 84, 222, 145, 2, 67, 246, 7, 72, 174, 178, 1, - 79, 2, 85, 234, 61, 66, 2, 75, 2, 77, 2, 80, 2, 81, 2, 87, 2, 89, 186, 2, - 69, 3, 73, 6, 56, 8, 76, 73, 32, 71, 65, 76, 73, 32, 199, 165, 16, 78, 4, - 214, 171, 14, 90, 139, 248, 1, 84, 4, 186, 163, 16, 90, 187, 2, 65, 4, - 154, 163, 16, 73, 187, 2, 65, 2, 251, 162, 16, 73, 6, 198, 145, 16, 72, - 162, 17, 82, 187, 2, 65, 8, 128, 1, 4, 87, 73, 82, 76, 189, 190, 4, 21, - 73, 66, 69, 32, 83, 89, 76, 76, 65, 66, 76, 69, 32, 66, 79, 85, 78, 68, - 65, 82, 89, 6, 17, 2, 32, 66, 6, 25, 4, 73, 82, 71, 65, 7, 33, 6, 32, 87, - 73, 84, 72, 32, 4, 150, 2, 68, 187, 221, 15, 79, 6, 152, 1, 3, 82, 73, - 80, 56, 18, 85, 82, 78, 69, 68, 32, 83, 87, 73, 82, 76, 32, 66, 73, 82, - 71, 65, 32, 197, 192, 1, 8, 79, 68, 79, 32, 83, 79, 70, 84, 2, 225, 221, - 15, 9, 76, 69, 32, 66, 73, 82, 71, 65, 32, 2, 33, 6, 87, 73, 84, 72, 32, - 68, 2, 161, 221, 15, 5, 79, 85, 66, 76, 69, 2, 207, 229, 9, 76, 10, 96, - 9, 71, 82, 65, 77, 32, 70, 79, 82, 32, 208, 131, 4, 5, 83, 84, 65, 66, - 76, 183, 232, 9, 82, 6, 26, 89, 219, 182, 12, 69, 4, 206, 206, 15, 65, - 155, 1, 73, 10, 48, 2, 78, 32, 230, 209, 4, 68, 191, 182, 11, 83, 6, 88, - 12, 86, 73, 69, 87, 73, 78, 71, 32, 67, 69, 82, 69, 234, 181, 12, 67, 85, - 2, 76, 65, 2, 189, 254, 15, 2, 77, 79, 4, 190, 175, 12, 73, 191, 238, 3, - 69, 10, 26, 72, 69, 2, 79, 82, 2, 45, 9, 69, 82, 32, 67, 72, 82, 73, 83, - 84, 2, 255, 254, 2, 77, 8, 50, 32, 52, 4, 73, 90, 69, 68, 143, 144, 15, - 87, 4, 226, 196, 8, 66, 233, 159, 6, 4, 83, 67, 79, 79, 2, 189, 176, 3, - 7, 32, 87, 72, 69, 69, 76, 67, 18, 52, 2, 78, 84, 152, 1, 2, 83, 69, 131, - 153, 16, 84, 10, 48, 3, 65, 73, 78, 141, 132, 12, 3, 32, 70, 85, 9, 11, - 32, 6, 142, 202, 9, 82, 24, 5, 67, 65, 66, 76, 69, 217, 235, 1, 6, 66, - 73, 67, 89, 67, 76, 7, 11, 32, 4, 148, 137, 15, 2, 84, 82, 231, 83, 70, - 86, 52, 7, 76, 69, 84, 84, 69, 82, 32, 211, 234, 5, 68, 62, 198, 1, 75, - 62, 77, 34, 78, 34, 79, 30, 80, 34, 84, 234, 105, 68, 180, 128, 8, 2, 72, - 65, 2, 82, 134, 192, 1, 69, 134, 29, 83, 154, 89, 76, 246, 7, 67, 130, - 207, 4, 89, 190, 28, 66, 2, 87, 187, 2, 65, 6, 192, 173, 5, 2, 69, 65, - 170, 255, 5, 72, 243, 234, 4, 79, 4, 242, 132, 16, 65, 215, 1, 73, 4, - 158, 199, 15, 73, 139, 60, 71, 7, 222, 150, 16, 76, 3, 79, 4, 234, 130, - 16, 72, 219, 19, 65, 6, 178, 144, 9, 72, 218, 130, 7, 69, 155, 3, 65, - 206, 4, 44, 2, 76, 84, 234, 6, 83, 151, 252, 13, 67, 102, 36, 4, 65, 78, - 73, 32, 219, 2, 73, 76, 52, 7, 76, 69, 84, 84, 69, 82, 32, 147, 148, 4, - 83, 74, 206, 1, 68, 222, 83, 78, 166, 236, 1, 82, 214, 198, 9, 74, 178, - 51, 84, 206, 145, 3, 66, 2, 67, 2, 71, 2, 75, 2, 80, 138, 69, 72, 2, 76, + 38, 84, 222, 189, 15, 72, 234, 181, 1, 75, 138, 69, 68, 2, 76, 2, 77, 2, + 80, 2, 81, 2, 87, 2, 89, 186, 2, 65, 2, 69, 2, 73, 3, 79, 4, 151, 166, 3, + 65, 8, 130, 166, 3, 65, 3, 69, 6, 230, 165, 3, 65, 195, 149, 14, 69, 10, + 194, 165, 3, 65, 2, 69, 195, 149, 14, 79, 2, 243, 171, 12, 73, 22, 26, + 82, 207, 252, 16, 73, 20, 44, 5, 73, 67, 65, 76, 32, 251, 185, 17, 79, + 18, 116, 10, 76, 79, 78, 71, 32, 79, 86, 69, 82, 32, 74, 80, 26, 84, 168, + 1, 7, 83, 72, 79, 82, 84, 32, 79, 215, 32, 66, 4, 180, 246, 2, 2, 83, 72, + 169, 253, 10, 7, 84, 87, 79, 32, 83, 72, 79, 2, 109, 3, 69, 78, 84, 8, + 66, 69, 34, 82, 41, 10, 87, 79, 32, 83, 72, 79, 82, 84, 83, 32, 2, 17, 2, + 84, 82, 2, 23, 65, 2, 11, 73, 2, 189, 157, 16, 2, 83, 69, 4, 26, 79, 235, + 131, 8, 74, 2, 205, 195, 10, 4, 86, 69, 82, 32, 230, 2, 104, 3, 65, 79, + 32, 136, 18, 2, 67, 82, 142, 1, 68, 142, 1, 76, 130, 1, 78, 245, 2, 4, + 82, 82, 79, 82, 170, 2, 156, 1, 7, 76, 69, 84, 84, 69, 82, 32, 180, 10, + 5, 83, 73, 71, 78, 32, 212, 1, 5, 84, 79, 78, 69, 32, 69, 11, 86, 79, 87, + 69, 76, 32, 83, 73, 71, 78, 32, 178, 1, 214, 1, 65, 110, 66, 34, 68, 106, + 71, 34, 76, 50, 78, 106, 82, 170, 1, 83, 54, 84, 218, 1, 86, 32, 3, 89, + 73, 32, 118, 90, 238, 180, 13, 81, 234, 233, 1, 80, 222, 196, 1, 72, 2, + 77, 138, 69, 70, 2, 75, 2, 87, 3, 88, 10, 52, 7, 82, 67, 72, 65, 73, 67, + 32, 175, 178, 17, 72, 8, 134, 132, 9, 90, 162, 184, 4, 78, 207, 243, 3, + 77, 4, 158, 158, 17, 82, 219, 19, 65, 16, 50, 90, 154, 4, 76, 214, 170, + 17, 68, 187, 2, 65, 8, 202, 157, 17, 89, 162, 17, 72, 2, 90, 187, 2, 65, + 6, 174, 233, 16, 72, 195, 71, 65, 8, 170, 184, 10, 72, 238, 245, 6, 89, + 187, 2, 65, 18, 54, 65, 170, 232, 16, 71, 2, 78, 2, 89, 139, 69, 72, 5, + 11, 83, 2, 141, 234, 13, 4, 65, 76, 73, 90, 16, 60, 9, 69, 70, 79, 82, + 77, 69, 68, 32, 84, 167, 152, 17, 84, 14, 40, 4, 79, 78, 69, 45, 167, + 177, 15, 83, 12, 202, 174, 17, 49, 2, 50, 2, 52, 2, 53, 2, 54, 3, 56, 8, + 182, 154, 17, 89, 162, 17, 72, 2, 83, 187, 2, 65, 32, 78, 76, 20, 4, 79, + 78, 69, 45, 70, 83, 254, 169, 17, 84, 186, 2, 65, 3, 69, 4, 231, 180, 10, + 72, 14, 246, 172, 17, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 8, + 250, 169, 17, 72, 2, 83, 186, 2, 65, 3, 69, 4, 202, 169, 17, 70, 187, 2, + 65, 16, 70, 84, 244, 173, 15, 2, 68, 90, 146, 63, 78, 226, 187, 1, 75, 3, + 80, 8, 218, 227, 16, 83, 138, 69, 84, 187, 2, 65, 16, 50, 90, 254, 226, + 16, 83, 138, 69, 72, 187, 2, 65, 8, 150, 178, 10, 83, 238, 245, 6, 89, + 187, 2, 65, 8, 144, 1, 9, 82, 69, 70, 79, 82, 77, 69, 68, 32, 34, 65, + 133, 133, 16, 18, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 77, 79, 68, 73, + 70, 73, 69, 82, 4, 30, 65, 221, 88, 2, 86, 79, 2, 133, 150, 12, 3, 83, + 80, 73, 8, 202, 134, 15, 66, 204, 78, 3, 84, 79, 80, 182, 86, 65, 159, + 82, 82, 104, 146, 1, 65, 78, 69, 62, 73, 78, 79, 74, 85, 74, 89, 224, + 149, 7, 9, 82, 79, 85, 78, 68, 69, 68, 32, 69, 238, 196, 7, 87, 178, 75, + 78, 227, 127, 86, 19, 222, 168, 15, 78, 226, 189, 1, 69, 146, 63, 72, + 146, 1, 65, 2, 73, 3, 85, 15, 246, 207, 13, 82, 158, 216, 1, 78, 130, + 254, 1, 65, 3, 73, 23, 202, 167, 15, 65, 54, 79, 134, 253, 1, 78, 86, 69, + 2, 71, 2, 73, 3, 85, 13, 42, 69, 226, 164, 17, 71, 2, 79, 3, 85, 4, 222, + 164, 17, 82, 3, 89, 19, 182, 166, 15, 65, 182, 234, 1, 69, 134, 19, 78, + 2, 79, 86, 73, 3, 85, 7, 162, 144, 17, 85, 219, 19, 73, 12, 18, 32, 63, + 79, 4, 244, 141, 16, 4, 79, 78, 32, 85, 13, 4, 68, 65, 83, 72, 8, 142, + 237, 11, 83, 154, 137, 4, 80, 242, 37, 32, 163, 112, 66, 12, 64, 4, 68, + 76, 69, 32, 237, 223, 4, 6, 76, 73, 78, 69, 32, 72, 10, 220, 193, 5, 3, + 84, 72, 73, 198, 232, 8, 76, 22, 82, 159, 167, 2, 68, 8, 76, 6, 73, 84, + 65, 82, 89, 32, 164, 194, 10, 3, 75, 89, 32, 211, 215, 5, 76, 4, 26, 72, + 219, 181, 12, 77, 2, 135, 178, 4, 69, 24, 42, 73, 76, 2, 85, 83, 207, + 159, 17, 89, 6, 34, 68, 22, 77, 255, 150, 15, 66, 2, 203, 157, 6, 73, 2, + 231, 237, 6, 73, 16, 46, 32, 153, 183, 10, 5, 45, 79, 82, 45, 80, 14, 40, + 4, 83, 73, 71, 78, 159, 183, 13, 84, 13, 11, 32, 10, 44, 5, 87, 73, 84, + 72, 32, 247, 173, 6, 73, 8, 66, 67, 166, 203, 4, 68, 230, 173, 8, 82, 21, + 4, 70, 65, 76, 76, 2, 177, 242, 11, 3, 79, 77, 77, 5, 143, 147, 15, 32, + 186, 9, 184, 1, 10, 66, 73, 76, 69, 32, 80, 72, 79, 78, 69, 166, 1, 68, + 198, 76, 78, 178, 27, 79, 172, 1, 3, 83, 81, 85, 38, 84, 250, 1, 85, 218, + 187, 11, 89, 189, 225, 2, 5, 86, 73, 69, 32, 67, 7, 11, 32, 4, 108, 21, + 87, 73, 84, 72, 32, 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 65, 82, + 82, 79, 87, 195, 178, 1, 79, 2, 11, 32, 2, 173, 232, 16, 2, 65, 84, 156, + 6, 58, 69, 74, 73, 157, 75, 7, 85, 76, 79, 32, 84, 87, 79, 4, 156, 202, + 16, 10, 82, 78, 32, 80, 69, 78, 84, 65, 84, 72, 159, 18, 76, 150, 6, 42, + 32, 221, 1, 5, 70, 73, 69, 82, 32, 158, 1, 88, 5, 83, 73, 71, 78, 32, + 158, 180, 3, 86, 170, 163, 3, 68, 186, 1, 76, 243, 203, 4, 65, 10, 42, + 65, 218, 217, 8, 72, 179, 251, 7, 86, 4, 44, 5, 82, 68, 72, 65, 67, 251, + 210, 16, 78, 2, 161, 211, 16, 3, 65, 78, 68, 248, 4, 92, 12, 66, 82, 69, + 86, 69, 32, 87, 73, 84, 72, 32, 73, 89, 7, 76, 69, 84, 84, 69, 82, 32, 2, + 33, 6, 78, 86, 69, 82, 84, 69, 2, 21, 3, 68, 32, 66, 2, 205, 153, 16, 2, + 82, 69, 246, 4, 198, 1, 65, 82, 66, 66, 67, 198, 13, 68, 202, 1, 69, 182, + 2, 71, 82, 72, 46, 76, 230, 4, 77, 216, 3, 7, 79, 80, 69, 78, 32, 83, 72, + 22, 80, 38, 82, 182, 4, 83, 206, 33, 84, 114, 85, 118, 86, 63, 89, 6, 38, + 76, 166, 27, 67, 227, 209, 10, 80, 2, 253, 19, 6, 86, 69, 79, 76, 65, 82, + 6, 192, 19, 5, 73, 76, 65, 66, 73, 193, 45, 4, 69, 71, 73, 78, 162, 1, + 240, 1, 7, 65, 80, 73, 84, 65, 76, 32, 200, 2, 7, 69, 78, 84, 82, 69, 68, + 32, 100, 13, 72, 73, 78, 69, 83, 69, 32, 84, 79, 78, 69, 32, 89, 108, 8, + 89, 82, 73, 76, 76, 73, 67, 32, 218, 230, 10, 73, 244, 2, 4, 82, 79, 83, + 83, 219, 211, 5, 79, 58, 214, 1, 66, 42, 82, 130, 27, 72, 186, 157, 13, + 79, 222, 150, 3, 65, 162, 64, 67, 2, 68, 2, 69, 2, 70, 2, 71, 2, 73, 2, + 74, 2, 75, 2, 76, 2, 77, 2, 78, 2, 80, 2, 81, 2, 83, 2, 84, 2, 85, 2, 86, + 3, 87, 5, 237, 150, 6, 5, 65, 82, 82, 69, 68, 7, 41, 8, 69, 86, 69, 82, + 83, 69, 68, 32, 4, 134, 143, 17, 69, 3, 78, 4, 30, 76, 21, 3, 82, 73, 71, + 2, 29, 2, 69, 70, 2, 11, 72, 2, 11, 84, 2, 181, 26, 2, 32, 72, 16, 36, 3, + 65, 78, 71, 1, 2, 73, 78, 8, 11, 32, 8, 166, 145, 12, 83, 170, 171, 4, + 80, 158, 44, 81, 3, 82, 78, 34, 72, 30, 83, 255, 188, 16, 69, 2, 181, + 161, 15, 2, 65, 82, 74, 40, 5, 77, 65, 76, 76, 32, 183, 6, 79, 72, 186, + 1, 66, 138, 1, 68, 38, 69, 150, 1, 80, 58, 83, 94, 84, 34, 89, 226, 134, + 16, 90, 130, 64, 73, 150, 19, 67, 2, 71, 186, 22, 74, 2, 86, 158, 20, 72, + 2, 75, 186, 2, 65, 2, 79, 3, 85, 6, 38, 89, 198, 27, 65, 139, 239, 16, + 69, 2, 237, 202, 1, 19, 69, 76, 79, 82, 85, 83, 83, 73, 65, 78, 45, 85, + 75, 82, 65, 73, 78, 73, 65, 4, 242, 215, 6, 90, 251, 177, 10, 69, 15, 50, + 83, 150, 137, 17, 70, 2, 76, 2, 77, 3, 82, 5, 25, 4, 32, 87, 73, 84, 2, + 21, 3, 72, 32, 68, 2, 11, 69, 2, 253, 156, 13, 3, 83, 67, 69, 4, 26, 65, + 155, 136, 17, 69, 2, 205, 219, 16, 2, 76, 79, 8, 42, 84, 226, 173, 1, 67, + 187, 215, 15, 72, 4, 153, 19, 8, 82, 65, 73, 71, 72, 84, 32, 85, 4, 202, + 240, 16, 83, 215, 22, 69, 6, 36, 3, 69, 82, 85, 219, 134, 17, 85, 5, 37, + 7, 32, 87, 73, 84, 72, 32, 66, 2, 21, 3, 65, 67, 75, 2, 169, 200, 16, 2, + 32, 89, 2, 175, 186, 11, 70, 16, 18, 69, 27, 79, 2, 169, 5, 2, 78, 84, + 14, 64, 2, 84, 32, 52, 5, 85, 66, 76, 69, 32, 129, 52, 2, 87, 78, 6, 162, + 224, 9, 83, 210, 202, 4, 86, 247, 181, 1, 72, 4, 210, 137, 2, 65, 231, + 248, 2, 80, 24, 40, 5, 88, 84, 82, 65, 45, 131, 49, 78, 20, 52, 5, 72, + 73, 71, 72, 32, 81, 4, 76, 79, 87, 32, 10, 156, 1, 9, 69, 88, 84, 82, 65, + 45, 76, 79, 87, 154, 7, 68, 70, 76, 79, 84, 10, 76, 10, 69, 88, 84, 82, + 65, 45, 72, 73, 71, 72, 154, 7, 68, 70, 76, 79, 84, 2, 145, 8, 8, 32, 67, + 79, 78, 84, 79, 85, 82, 8, 162, 9, 82, 226, 3, 76, 173, 209, 15, 9, 69, + 79, 82, 71, 73, 65, 78, 32, 78, 10, 248, 5, 4, 73, 71, 72, 32, 255, 40, + 65, 44, 46, 65, 84, 2, 79, 87, 201, 11, 2, 69, 70, 2, 21, 3, 84, 69, 82, + 2, 17, 2, 65, 76, 2, 17, 2, 32, 67, 2, 239, 205, 15, 76, 36, 86, 32, 133, + 151, 12, 15, 69, 82, 32, 82, 73, 71, 72, 84, 32, 67, 79, 82, 78, 69, 82, + 34, 158, 1, 67, 20, 2, 68, 79, 40, 4, 76, 69, 70, 84, 82, 77, 12, 2, 82, + 73, 50, 84, 178, 3, 65, 42, 71, 170, 2, 73, 172, 157, 14, 2, 85, 80, 255, + 188, 1, 86, 2, 175, 215, 10, 73, 6, 238, 2, 84, 241, 161, 14, 2, 87, 78, + 6, 28, 2, 32, 65, 247, 2, 45, 4, 25, 4, 82, 82, 79, 87, 5, 187, 164, 14, + 72, 2, 111, 65, 4, 216, 163, 14, 3, 71, 72, 84, 175, 216, 2, 78, 4, 194, + 2, 79, 219, 220, 14, 73, 18, 18, 65, 23, 73, 2, 195, 212, 15, 67, 16, 26, + 68, 179, 201, 13, 78, 14, 38, 32, 217, 1, 4, 68, 76, 69, 32, 8, 26, 68, + 70, 76, 79, 84, 4, 17, 2, 79, 84, 4, 25, 4, 84, 69, 68, 32, 4, 18, 76, + 79, 84, 2, 25, 4, 69, 70, 84, 45, 2, 25, 4, 83, 84, 69, 77, 2, 17, 2, 32, + 84, 2, 11, 79, 2, 11, 78, 2, 135, 214, 15, 69, 6, 40, 6, 68, 79, 85, 66, + 76, 69, 75, 71, 4, 11, 32, 4, 18, 65, 43, 71, 2, 11, 67, 2, 145, 213, 10, + 2, 85, 84, 2, 11, 82, 2, 223, 212, 10, 65, 2, 171, 242, 14, 69, 4, 134, + 198, 13, 76, 159, 152, 2, 82, 26, 104, 6, 65, 73, 83, 69, 68, 32, 150, 1, + 69, 216, 1, 3, 73, 71, 72, 193, 250, 8, 5, 72, 79, 84, 73, 67, 10, 70, + 68, 30, 73, 214, 218, 9, 69, 128, 255, 5, 2, 85, 80, 215, 76, 67, 2, 197, + 163, 15, 2, 79, 87, 2, 189, 218, 9, 7, 78, 86, 69, 82, 84, 69, 68, 8, + 104, 7, 86, 69, 82, 83, 69, 68, 32, 137, 28, 14, 84, 82, 79, 70, 76, 69, + 88, 32, 67, 76, 73, 67, 75, 32, 6, 26, 71, 163, 159, 14, 67, 4, 11, 76, + 4, 49, 10, 79, 84, 84, 65, 76, 32, 83, 84, 79, 80, 5, 171, 19, 32, 6, 17, + 2, 84, 32, 6, 38, 72, 150, 213, 13, 84, 239, 69, 65, 2, 197, 196, 7, 3, + 65, 76, 70, 156, 2, 138, 1, 72, 48, 5, 77, 65, 76, 76, 32, 148, 31, 8, + 84, 82, 69, 83, 83, 32, 65, 78, 53, 11, 85, 80, 69, 82, 83, 67, 82, 73, + 80, 84, 32, 4, 180, 158, 8, 3, 79, 82, 84, 251, 205, 6, 69, 144, 2, 154, + 2, 65, 50, 66, 130, 1, 67, 238, 2, 68, 238, 2, 90, 66, 69, 46, 70, 30, + 71, 110, 72, 102, 77, 34, 73, 34, 74, 98, 76, 176, 3, 7, 78, 32, 87, 73, + 84, 72, 32, 30, 79, 94, 80, 22, 82, 146, 2, 83, 190, 1, 84, 246, 7, 85, + 142, 1, 86, 226, 211, 16, 75, 2, 81, 2, 87, 2, 88, 3, 89, 9, 222, 147, + 13, 76, 170, 140, 3, 73, 227, 79, 69, 11, 46, 65, 50, 79, 222, 8, 32, + 179, 193, 16, 69, 2, 17, 2, 82, 82, 2, 169, 247, 5, 2, 69, 68, 2, 229, + 20, 4, 84, 84, 79, 77, 41, 100, 7, 65, 80, 73, 84, 65, 76, 32, 180, 1, 6, + 76, 79, 83, 69, 68, 32, 190, 17, 32, 139, 199, 16, 72, 30, 114, 73, 214, + 6, 71, 226, 16, 76, 214, 190, 16, 79, 158, 20, 65, 186, 2, 66, 2, 72, 2, + 78, 2, 82, 2, 85, 3, 89, 7, 22, 78, 191, 11, 32, 2, 225, 240, 5, 5, 86, + 69, 82, 84, 69, 4, 26, 82, 243, 166, 9, 79, 2, 217, 20, 9, 69, 86, 69, + 82, 83, 69, 68, 32, 79, 23, 104, 6, 32, 87, 73, 84, 72, 32, 86, 69, 32, + 9, 79, 84, 76, 69, 83, 83, 32, 74, 32, 105, 3, 90, 32, 68, 6, 26, 72, + 163, 179, 14, 84, 4, 21, 3, 79, 79, 75, 5, 213, 250, 13, 3, 32, 65, 78, + 4, 238, 15, 90, 211, 181, 16, 76, 4, 33, 6, 87, 73, 84, 72, 32, 83, 4, + 29, 5, 84, 82, 79, 75, 69, 5, 193, 239, 8, 4, 32, 65, 78, 68, 6, 33, 6, + 73, 71, 82, 65, 80, 72, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 138, 14, 67, + 207, 4, 82, 11, 142, 231, 16, 83, 2, 84, 2, 90, 63, 78, 5, 225, 13, 3, + 69, 78, 71, 11, 56, 5, 82, 69, 69, 75, 32, 162, 1, 32, 183, 144, 14, 65, + 4, 26, 71, 139, 143, 11, 80, 2, 183, 145, 14, 65, 11, 40, 6, 32, 87, 73, + 84, 72, 32, 39, 69, 4, 206, 144, 15, 72, 247, 165, 1, 83, 4, 17, 2, 78, + 71, 5, 11, 32, 2, 255, 235, 8, 87, 4, 222, 4, 32, 191, 188, 16, 79, 5, + 37, 7, 32, 87, 73, 84, 72, 32, 67, 2, 11, 82, 2, 225, 173, 14, 6, 79, 83, + 83, 69, 68, 45, 25, 116, 6, 32, 87, 73, 84, 72, 32, 226, 9, 83, 2, 90, + 112, 2, 69, 90, 193, 194, 16, 8, 73, 71, 65, 84, 85, 82, 69, 32, 12, 54, + 73, 82, 77, 82, 82, 222, 6, 80, 143, 245, 3, 66, 2, 49, 10, 78, 86, 69, + 82, 84, 69, 68, 32, 76, 65, 2, 157, 233, 12, 2, 90, 89, 2, 11, 73, 2, 17, + 2, 68, 68, 2, 17, 2, 76, 69, 2, 221, 250, 12, 2, 32, 84, 4, 61, 13, 69, + 84, 82, 79, 70, 76, 69, 88, 32, 72, 79, 79, 75, 5, 205, 12, 4, 32, 65, + 78, 68, 4, 210, 11, 82, 207, 1, 76, 9, 18, 32, 47, 80, 2, 21, 3, 87, 73, + 84, 2, 219, 176, 16, 72, 4, 229, 196, 12, 2, 69, 78, 5, 231, 204, 16, 72, + 15, 80, 6, 32, 87, 73, 84, 72, 32, 62, 65, 41, 8, 69, 86, 69, 82, 83, 69, + 68, 32, 4, 26, 70, 155, 168, 14, 84, 2, 225, 229, 8, 3, 73, 83, 72, 2, + 17, 2, 77, 83, 2, 235, 232, 5, 32, 6, 38, 71, 170, 7, 79, 167, 215, 16, + 69, 2, 11, 76, 2, 161, 137, 14, 4, 79, 84, 84, 65, 13, 72, 6, 32, 87, 73, + 84, 72, 32, 34, 67, 61, 6, 73, 68, 69, 87, 65, 89, 4, 158, 3, 67, 195, + 132, 15, 72, 4, 26, 82, 187, 227, 11, 72, 2, 209, 219, 5, 3, 73, 80, 84, + 2, 159, 194, 6, 83, 51, 106, 32, 102, 67, 116, 2, 69, 83, 44, 2, 79, 80, + 42, 83, 96, 6, 85, 82, 78, 69, 68, 32, 215, 155, 13, 72, 4, 29, 5, 87, + 73, 84, 72, 32, 4, 22, 80, 219, 5, 82, 2, 213, 225, 8, 6, 65, 76, 65, 84, + 65, 76, 2, 45, 9, 32, 68, 73, 71, 82, 65, 80, 72, 32, 2, 25, 4, 87, 73, + 84, 72, 2, 17, 2, 32, 67, 2, 175, 145, 3, 85, 2, 11, 72, 2, 189, 155, 10, + 3, 32, 68, 73, 2, 165, 226, 5, 5, 32, 72, 65, 76, 70, 4, 37, 7, 32, 68, + 73, 71, 82, 65, 80, 4, 11, 72, 5, 11, 32, 2, 141, 3, 4, 87, 73, 84, 72, + 32, 86, 65, 38, 77, 74, 79, 42, 82, 214, 1, 89, 170, 213, 16, 72, 2, 73, + 2, 86, 3, 87, 7, 134, 252, 12, 76, 139, 220, 3, 69, 5, 41, 8, 32, 87, 73, + 84, 72, 32, 76, 79, 2, 253, 141, 4, 2, 78, 71, 2, 11, 80, 2, 225, 158, 6, + 2, 69, 78, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 26, 76, 207, 128, 15, 72, + 4, 37, 7, 79, 78, 71, 32, 76, 69, 71, 5, 25, 4, 32, 65, 78, 68, 2, 17, 2, + 32, 82, 2, 11, 69, 2, 241, 219, 8, 7, 84, 82, 79, 70, 76, 69, 88, 5, 29, + 5, 32, 87, 73, 84, 72, 2, 213, 238, 3, 2, 32, 66, 9, 18, 32, 95, 80, 4, + 40, 4, 87, 73, 84, 72, 243, 176, 15, 66, 2, 17, 2, 32, 76, 2, 11, 69, 2, + 131, 1, 70, 2, 129, 132, 16, 2, 83, 73, 7, 33, 6, 32, 87, 73, 84, 72, 32, + 4, 26, 82, 179, 253, 14, 72, 2, 21, 3, 73, 71, 72, 2, 163, 217, 8, 84, 4, + 11, 68, 4, 11, 32, 4, 146, 210, 1, 72, 35, 76, 4, 24, 2, 72, 65, 31, 84, + 2, 25, 4, 76, 70, 32, 84, 2, 43, 82, 4, 30, 82, 53, 3, 85, 82, 78, 2, + 189, 129, 16, 8, 73, 65, 78, 71, 85, 76, 65, 82, 2, 169, 172, 8, 2, 69, + 68, 8, 70, 80, 184, 159, 10, 7, 78, 65, 83, 80, 73, 82, 65, 143, 177, 6, + 83, 4, 11, 32, 4, 226, 177, 13, 84, 239, 69, 65, 4, 26, 79, 135, 180, 15, + 69, 2, 11, 73, 2, 235, 254, 15, 67, 4, 36, 3, 65, 78, 71, 1, 2, 73, 78, + 2, 25, 4, 32, 68, 69, 80, 2, 21, 3, 65, 82, 84, 2, 21, 3, 73, 78, 71, 2, + 17, 2, 32, 84, 2, 11, 79, 2, 171, 135, 6, 78, 2, 11, 32, 2, 131, 163, 15, + 83, 234, 2, 92, 2, 69, 89, 88, 7, 71, 79, 76, 73, 65, 78, 32, 206, 24, + 79, 209, 140, 12, 3, 75, 69, 89, 6, 26, 32, 203, 143, 16, 45, 4, 128, + 142, 12, 6, 87, 73, 84, 72, 32, 87, 167, 211, 2, 66, 214, 2, 194, 2, 68, + 46, 70, 148, 1, 14, 73, 78, 86, 69, 82, 84, 69, 68, 32, 66, 73, 82, 71, + 65, 16, 7, 76, 69, 84, 84, 69, 82, 32, 138, 16, 83, 132, 1, 7, 82, 79, + 84, 65, 84, 69, 68, 22, 66, 98, 84, 160, 2, 4, 86, 79, 87, 69, 194, 241, + 3, 67, 164, 1, 6, 77, 65, 78, 67, 72, 85, 160, 201, 7, 4, 78, 73, 82, 85, + 239, 208, 2, 69, 22, 232, 20, 3, 79, 85, 66, 171, 193, 14, 73, 12, 112, + 19, 82, 69, 69, 32, 86, 65, 82, 73, 65, 84, 73, 79, 78, 32, 83, 69, 76, + 69, 67, 202, 243, 13, 85, 195, 46, 79, 8, 177, 250, 9, 3, 84, 79, 82, 5, + 227, 19, 32, 136, 2, 130, 2, 65, 244, 4, 2, 67, 72, 88, 2, 77, 65, 174, + 2, 83, 246, 1, 84, 234, 3, 90, 178, 195, 14, 72, 246, 173, 1, 75, 2, 76, + 162, 7, 69, 2, 79, 2, 85, 234, 61, 66, 2, 68, 2, 70, 2, 71, 2, 74, 2, 78, + 2, 80, 2, 81, 2, 82, 2, 87, 2, 89, 187, 2, 73, 59, 56, 8, 76, 73, 32, 71, + 65, 76, 73, 32, 171, 197, 16, 78, 54, 174, 1, 65, 52, 6, 86, 73, 83, 65, + 82, 71, 22, 68, 76, 5, 72, 65, 76, 70, 32, 34, 73, 50, 85, 34, 78, 30, + 84, 66, 66, 174, 250, 15, 80, 2, 90, 254, 68, 83, 14, 67, 3, 75, 7, 48, + 6, 78, 85, 83, 86, 65, 82, 155, 196, 16, 72, 2, 243, 165, 9, 65, 8, 26, + 65, 179, 193, 16, 68, 7, 166, 253, 8, 77, 253, 131, 7, 3, 71, 65, 76, 4, + 254, 192, 16, 89, 187, 2, 85, 5, 45, 9, 78, 86, 69, 82, 84, 69, 68, 32, + 85, 2, 249, 255, 15, 3, 66, 65, 68, 4, 142, 192, 16, 71, 3, 78, 8, 60, 6, + 72, 82, 69, 69, 32, 66, 174, 250, 15, 84, 195, 71, 65, 2, 17, 2, 65, 76, + 2, 211, 156, 16, 85, 6, 26, 65, 171, 193, 16, 73, 5, 29, 5, 32, 87, 73, + 84, 72, 2, 149, 238, 14, 2, 32, 84, 41, 29, 5, 78, 67, 72, 85, 32, 38, + 104, 9, 65, 76, 73, 32, 71, 65, 76, 73, 32, 186, 194, 14, 90, 242, 250, + 1, 70, 2, 75, 2, 82, 187, 2, 73, 28, 122, 68, 194, 198, 9, 67, 246, 227, + 2, 84, 138, 151, 2, 66, 2, 71, 2, 74, 2, 76, 234, 181, 1, 90, 254, 4, 78, + 131, 64, 83, 4, 186, 193, 14, 68, 243, 250, 1, 72, 48, 52, 4, 73, 66, 69, + 32, 210, 187, 16, 72, 187, 2, 65, 44, 214, 222, 5, 71, 2, 72, 170, 202, + 6, 84, 238, 3, 73, 246, 147, 2, 67, 2, 83, 246, 7, 82, 190, 164, 1, 65, + 186, 9, 90, 162, 7, 85, 234, 61, 68, 2, 70, 2, 74, 2, 75, 2, 80, 187, 2, + 69, 60, 52, 4, 79, 68, 79, 32, 222, 185, 16, 83, 187, 2, 65, 56, 250, 1, + 65, 98, 68, 34, 74, 34, 78, 252, 164, 1, 8, 76, 79, 78, 71, 32, 86, 79, + 87, 206, 180, 4, 71, 170, 202, 6, 84, 226, 151, 2, 67, 246, 7, 72, 150, + 181, 1, 79, 2, 85, 234, 61, 66, 2, 75, 2, 77, 2, 80, 2, 81, 2, 87, 2, 89, + 186, 2, 69, 3, 73, 6, 56, 8, 76, 73, 32, 71, 65, 76, 73, 32, 139, 185, + 16, 78, 4, 178, 188, 14, 90, 243, 250, 1, 84, 4, 254, 182, 16, 90, 187, + 2, 65, 4, 222, 182, 16, 73, 187, 2, 65, 2, 191, 182, 16, 73, 6, 138, 165, + 16, 72, 162, 17, 82, 187, 2, 65, 8, 128, 1, 4, 87, 73, 82, 76, 217, 191, + 4, 21, 73, 66, 69, 32, 83, 89, 76, 76, 65, 66, 76, 69, 32, 66, 79, 85, + 78, 68, 65, 82, 89, 6, 17, 2, 32, 66, 6, 25, 4, 73, 82, 71, 65, 7, 33, 6, + 32, 87, 73, 84, 72, 32, 4, 150, 2, 68, 255, 240, 15, 79, 6, 152, 1, 3, + 82, 73, 80, 56, 18, 85, 82, 78, 69, 68, 32, 83, 87, 73, 82, 76, 32, 66, + 73, 82, 71, 65, 32, 217, 192, 1, 8, 79, 68, 79, 32, 83, 79, 70, 84, 2, + 165, 241, 15, 9, 76, 69, 32, 66, 73, 82, 71, 65, 32, 2, 33, 6, 87, 73, + 84, 72, 32, 68, 2, 229, 240, 15, 5, 79, 85, 66, 76, 69, 2, 135, 235, 9, + 76, 10, 84, 9, 71, 82, 65, 77, 32, 70, 79, 82, 32, 60, 4, 83, 84, 65, 66, + 215, 251, 13, 82, 6, 26, 89, 179, 198, 12, 69, 4, 158, 226, 15, 65, 155, + 1, 73, 2, 171, 132, 4, 76, 10, 48, 2, 78, 32, 250, 210, 4, 68, 231, 200, + 11, 83, 6, 88, 12, 86, 73, 69, 87, 73, 78, 71, 32, 67, 69, 82, 69, 174, + 197, 12, 67, 85, 2, 76, 65, 2, 249, 145, 16, 2, 77, 79, 4, 174, 190, 12, + 73, 139, 243, 3, 69, 10, 26, 72, 69, 2, 79, 82, 2, 45, 9, 69, 82, 32, 67, + 72, 82, 73, 83, 84, 2, 243, 254, 2, 77, 8, 50, 32, 52, 4, 73, 90, 69, 68, + 175, 161, 15, 87, 4, 150, 202, 8, 66, 221, 171, 6, 4, 83, 67, 79, 79, 2, + 209, 176, 3, 7, 32, 87, 72, 69, 69, 76, 67, 18, 52, 2, 78, 84, 152, 1, 2, + 83, 69, 191, 172, 16, 84, 10, 48, 3, 65, 73, 78, 169, 142, 12, 3, 32, 70, + 85, 9, 11, 32, 6, 186, 207, 9, 82, 24, 5, 67, 65, 66, 76, 69, 177, 241, + 1, 6, 66, 73, 67, 89, 67, 76, 7, 11, 32, 4, 180, 154, 15, 2, 84, 82, 131, + 86, 70, 86, 52, 7, 76, 69, 84, 84, 69, 82, 32, 231, 235, 5, 68, 62, 198, + 1, 75, 62, 77, 34, 78, 34, 79, 30, 80, 34, 84, 242, 105, 68, 212, 133, 8, + 2, 72, 65, 2, 82, 166, 226, 1, 83, 190, 89, 76, 246, 7, 67, 218, 100, 69, + 254, 242, 3, 89, 190, 28, 66, 2, 87, 187, 2, 65, 6, 160, 174, 5, 2, 69, + 65, 178, 137, 6, 72, 199, 243, 4, 79, 4, 174, 152, 16, 65, 215, 1, 73, 4, + 218, 218, 15, 73, 139, 60, 71, 7, 154, 170, 16, 76, 3, 79, 4, 166, 150, + 16, 72, 219, 19, 65, 6, 222, 149, 9, 72, 234, 144, 7, 69, 155, 3, 65, + 206, 4, 44, 2, 76, 84, 234, 6, 83, 247, 139, 14, 67, 102, 36, 4, 65, 78, + 73, 32, 219, 2, 73, 76, 52, 7, 76, 69, 84, 84, 69, 82, 32, 151, 149, 4, + 83, 74, 206, 1, 68, 234, 83, 78, 194, 236, 1, 82, 254, 208, 9, 74, 202, + 56, 84, 162, 149, 3, 66, 2, 67, 2, 71, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 83, 2, 86, 2, 89, 186, 2, 65, 2, 69, 2, 73, 3, 85, 10, 38, 68, - 178, 144, 16, 72, 187, 2, 65, 6, 174, 144, 16, 68, 2, 72, 187, 2, 65, 26, - 56, 2, 80, 76, 236, 2, 3, 83, 69, 84, 175, 254, 14, 77, 18, 50, 69, 89, + 238, 163, 16, 72, 187, 2, 65, 6, 234, 163, 16, 68, 2, 72, 187, 2, 65, 26, + 56, 2, 80, 76, 236, 2, 3, 83, 69, 84, 207, 143, 15, 77, 18, 50, 69, 89, 8, 73, 67, 65, 84, 73, 79, 78, 32, 2, 41, 8, 32, 77, 85, 83, 73, 67, 65, - 76, 2, 21, 3, 32, 78, 79, 2, 147, 253, 14, 84, 16, 40, 4, 83, 73, 71, 78, - 207, 144, 16, 88, 15, 11, 32, 12, 48, 3, 73, 78, 32, 81, 5, 87, 73, 84, - 72, 32, 8, 226, 206, 3, 76, 22, 82, 192, 175, 9, 5, 68, 79, 85, 66, 76, - 247, 236, 1, 84, 4, 174, 164, 12, 85, 195, 234, 2, 68, 7, 11, 32, 4, 232, - 83, 5, 77, 85, 76, 84, 73, 239, 139, 12, 85, 228, 3, 44, 5, 72, 82, 79, - 79, 77, 21, 2, 73, 67, 5, 175, 226, 14, 32, 224, 3, 30, 32, 101, 3, 65, - 76, 32, 6, 76, 4, 78, 65, 84, 85, 200, 43, 2, 70, 76, 161, 137, 11, 4, - 83, 72, 65, 82, 2, 235, 201, 10, 82, 218, 3, 64, 8, 75, 69, 89, 66, 79, - 65, 82, 68, 66, 83, 135, 247, 3, 78, 5, 41, 8, 32, 87, 73, 84, 72, 32, - 74, 65, 2, 143, 239, 13, 67, 212, 3, 48, 6, 89, 77, 66, 79, 76, 32, 243, - 166, 11, 67, 210, 3, 230, 2, 66, 238, 1, 67, 226, 9, 68, 242, 2, 69, 162, - 1, 70, 166, 2, 71, 112, 9, 65, 82, 80, 69, 71, 71, 73, 65, 84, 168, 1, 2, - 72, 65, 126, 75, 198, 3, 76, 138, 1, 77, 190, 2, 78, 162, 1, 79, 218, 2, - 80, 200, 2, 2, 81, 85, 146, 2, 82, 198, 2, 83, 230, 5, 84, 182, 10, 86, - 42, 88, 42, 87, 200, 140, 9, 9, 73, 78, 86, 69, 82, 84, 69, 68, 32, 255, - 195, 6, 90, 20, 36, 5, 69, 71, 73, 78, 32, 59, 82, 8, 130, 15, 80, 30, - 83, 218, 246, 7, 66, 143, 231, 7, 84, 12, 24, 2, 65, 67, 35, 69, 4, 198, - 210, 15, 75, 155, 53, 69, 8, 26, 86, 203, 197, 15, 65, 6, 32, 2, 73, 83, - 131, 135, 16, 69, 5, 171, 26, 32, 84, 120, 2, 65, 69, 30, 76, 94, 79, - 194, 7, 82, 234, 11, 32, 232, 32, 7, 73, 82, 67, 76, 69, 32, 88, 189, - 222, 5, 2, 85, 84, 2, 177, 193, 15, 2, 83, 85, 8, 42, 73, 245, 23, 5, 85, - 83, 84, 69, 82, 4, 26, 77, 223, 225, 13, 86, 2, 247, 214, 9, 65, 64, 26, - 77, 171, 130, 16, 68, 62, 64, 7, 66, 73, 78, 73, 78, 71, 32, 237, 145, 6, - 3, 77, 79, 78, 60, 202, 1, 65, 80, 7, 77, 65, 82, 67, 65, 84, 79, 56, 2, - 68, 79, 56, 2, 85, 80, 28, 2, 70, 76, 40, 5, 72, 65, 82, 77, 79, 22, 83, - 142, 2, 84, 226, 176, 7, 66, 224, 193, 3, 2, 76, 79, 195, 138, 5, 82, 6, - 76, 5, 67, 67, 69, 78, 84, 37, 10, 85, 71, 77, 69, 78, 84, 65, 84, 73, - 79, 5, 205, 2, 5, 45, 83, 84, 65, 67, 2, 199, 240, 14, 78, 6, 52, 2, 87, - 78, 168, 3, 2, 85, 66, 191, 225, 15, 73, 2, 233, 230, 14, 2, 32, 66, 12, - 248, 76, 2, 65, 71, 239, 179, 15, 73, 2, 195, 216, 14, 78, 12, 132, 1, 9, - 78, 65, 80, 32, 80, 73, 90, 90, 73, 22, 84, 224, 205, 4, 11, 80, 82, 69, - 67, 72, 71, 69, 83, 65, 78, 71, 219, 129, 6, 77, 2, 139, 244, 11, 67, 6, - 44, 5, 65, 67, 67, 65, 84, 151, 238, 15, 69, 4, 40, 4, 73, 83, 83, 73, - 195, 254, 15, 79, 2, 203, 223, 15, 77, 10, 34, 82, 193, 143, 12, 2, 69, - 78, 8, 28, 2, 73, 80, 191, 6, 69, 2, 209, 242, 11, 6, 76, 69, 32, 84, 79, - 78, 4, 22, 79, 191, 2, 69, 2, 255, 240, 14, 73, 24, 98, 65, 142, 1, 69, - 84, 6, 79, 85, 66, 76, 69, 32, 225, 158, 10, 7, 82, 85, 77, 32, 67, 76, - 69, 10, 96, 2, 32, 67, 20, 2, 77, 80, 204, 29, 4, 83, 72, 69, 68, 217, - 180, 15, 5, 76, 32, 83, 69, 71, 2, 223, 189, 8, 65, 5, 231, 243, 13, 32, - 4, 52, 3, 67, 82, 69, 145, 228, 8, 4, 71, 82, 69, 69, 2, 165, 25, 3, 83, - 67, 69, 6, 246, 21, 83, 130, 7, 66, 243, 134, 5, 70, 14, 32, 3, 78, 68, - 32, 155, 16, 73, 10, 74, 80, 30, 83, 208, 13, 3, 79, 70, 32, 138, 233, 7, - 66, 143, 231, 7, 84, 2, 229, 211, 12, 2, 72, 82, 2, 191, 128, 15, 76, 34, - 104, 6, 69, 82, 77, 65, 84, 65, 22, 73, 122, 79, 102, 32, 152, 36, 3, 85, - 83, 65, 205, 229, 3, 2, 76, 65, 5, 219, 202, 13, 32, 10, 22, 78, 143, 34, - 86, 8, 56, 9, 71, 69, 82, 69, 68, 32, 84, 82, 69, 243, 20, 65, 6, 237, - 237, 5, 4, 77, 79, 76, 79, 6, 216, 25, 3, 85, 82, 45, 183, 150, 14, 82, - 18, 54, 32, 56, 7, 76, 73, 83, 83, 65, 78, 68, 23, 82, 6, 25, 4, 67, 76, - 69, 70, 7, 161, 13, 3, 32, 79, 84, 4, 215, 129, 6, 79, 8, 84, 9, 65, 67, - 69, 32, 78, 79, 84, 69, 32, 37, 8, 69, 71, 79, 82, 73, 65, 78, 32, 4, - 164, 222, 8, 2, 78, 79, 27, 83, 4, 250, 2, 67, 3, 70, 8, 44, 3, 76, 70, - 32, 209, 8, 3, 85, 80, 84, 6, 52, 3, 80, 69, 68, 226, 222, 3, 78, 207, - 183, 3, 82, 2, 139, 198, 5, 65, 24, 48, 6, 73, 69, 86, 65, 78, 32, 247, - 205, 14, 79, 22, 178, 1, 67, 46, 69, 68, 7, 81, 85, 65, 82, 84, 69, 82, - 62, 70, 164, 219, 3, 4, 72, 65, 76, 70, 0, 5, 87, 72, 79, 76, 69, 157, - 224, 1, 9, 82, 69, 67, 73, 84, 65, 84, 73, 86, 2, 11, 32, 2, 11, 67, 2, - 163, 163, 5, 76, 6, 64, 5, 73, 71, 72, 84, 72, 201, 186, 14, 5, 78, 68, - 32, 79, 70, 4, 217, 252, 5, 10, 32, 78, 79, 84, 69, 32, 83, 84, 69, 77, - 4, 222, 14, 76, 197, 204, 3, 4, 73, 78, 65, 76, 8, 44, 4, 79, 78, 71, 65, - 221, 13, 2, 69, 70, 7, 11, 32, 4, 28, 3, 73, 77, 80, 3, 80, 2, 197, 2, 7, - 69, 82, 70, 69, 67, 84, 65, 18, 104, 2, 65, 88, 20, 2, 69, 90, 20, 5, 73, - 78, 73, 77, 65, 48, 3, 79, 79, 78, 25, 4, 85, 76, 84, 73, 2, 255, 204, - 15, 73, 2, 135, 207, 15, 90, 7, 11, 32, 4, 170, 144, 7, 82, 167, 194, 5, - 66, 4, 193, 17, 2, 32, 78, 4, 60, 11, 80, 76, 69, 32, 77, 69, 65, 83, 85, - 82, 69, 15, 32, 2, 11, 32, 2, 163, 143, 7, 82, 10, 120, 4, 69, 66, 69, - 78, 216, 26, 3, 85, 76, 76, 192, 220, 5, 3, 65, 84, 85, 141, 217, 6, 7, - 79, 84, 69, 72, 69, 65, 68, 2, 213, 211, 14, 4, 83, 84, 73, 77, 32, 88, - 2, 78, 69, 120, 14, 82, 78, 65, 77, 69, 78, 84, 32, 83, 84, 82, 79, 75, - 69, 107, 84, 6, 92, 18, 32, 72, 85, 78, 68, 82, 69, 68, 32, 84, 87, 69, - 78, 84, 89, 45, 69, 73, 163, 20, 45, 4, 185, 13, 2, 71, 72, 22, 11, 45, - 22, 158, 166, 3, 49, 162, 195, 12, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, - 2, 56, 3, 57, 4, 173, 4, 3, 84, 65, 86, 18, 96, 9, 65, 82, 69, 78, 84, - 72, 69, 83, 73, 0, 2, 76, 85, 18, 69, 142, 1, 79, 223, 222, 13, 73, 2, - 247, 22, 83, 6, 68, 4, 68, 65, 76, 32, 49, 9, 83, 32, 83, 85, 66, 80, 85, - 78, 67, 4, 26, 85, 199, 165, 15, 77, 2, 171, 165, 15, 80, 2, 167, 195, - 13, 84, 6, 48, 2, 68, 65, 245, 5, 5, 82, 82, 69, 67, 84, 2, 151, 224, 13, - 84, 12, 76, 6, 65, 82, 84, 69, 82, 32, 125, 9, 73, 78, 68, 73, 67, 69, - 83, 73, 77, 8, 60, 5, 84, 79, 78, 69, 32, 246, 207, 3, 78, 207, 183, 3, - 82, 4, 26, 83, 243, 141, 5, 70, 2, 197, 228, 15, 3, 72, 65, 82, 4, 17, 2, - 65, 32, 4, 142, 171, 12, 65, 205, 182, 3, 3, 66, 65, 83, 14, 22, 69, 175, - 1, 73, 10, 72, 4, 80, 69, 65, 84, 81, 10, 86, 69, 82, 83, 69, 32, 70, 73, - 78, 65, 8, 56, 8, 69, 68, 32, 70, 73, 71, 85, 82, 163, 146, 14, 32, 6, - 147, 217, 5, 69, 2, 211, 4, 76, 4, 48, 2, 71, 72, 57, 6, 78, 70, 79, 82, - 90, 65, 2, 33, 6, 84, 32, 82, 69, 80, 69, 2, 255, 158, 10, 65, 2, 147, - 176, 8, 78, 48, 136, 1, 6, 67, 65, 78, 68, 73, 67, 62, 69, 166, 1, 72, - 54, 73, 252, 1, 6, 81, 85, 65, 82, 69, 32, 212, 153, 8, 2, 85, 66, 243, - 100, 79, 4, 17, 2, 85, 83, 5, 141, 218, 13, 5, 32, 70, 76, 69, 88, 14, - 32, 2, 77, 73, 179, 182, 15, 71, 12, 64, 6, 66, 82, 69, 86, 73, 83, 1, 6, - 77, 73, 78, 73, 77, 65, 6, 11, 32, 6, 138, 13, 87, 182, 244, 6, 82, 167, - 194, 5, 66, 6, 84, 3, 79, 82, 84, 213, 233, 5, 3, 65, 82, 80, 14, 32, 4, - 78, 71, 76, 69, 43, 88, 2, 17, 2, 32, 66, 2, 135, 246, 13, 65, 12, 18, - 45, 79, 84, 4, 242, 7, 76, 173, 190, 14, 11, 83, 84, 82, 73, 78, 71, 32, - 70, 82, 69, 84, 8, 52, 3, 69, 69, 78, 1, 6, 89, 45, 70, 79, 85, 82, 4, - 193, 12, 2, 84, 72, 6, 26, 78, 247, 219, 15, 66, 4, 229, 9, 7, 79, 84, - 69, 72, 69, 65, 68, 60, 132, 1, 6, 69, 77, 80, 85, 83, 32, 154, 4, 72, - 88, 2, 87, 79, 84, 7, 79, 82, 67, 85, 76, 85, 83, 46, 82, 141, 3, 3, 85, - 82, 78, 16, 232, 1, 27, 73, 77, 80, 69, 82, 70, 69, 67, 84, 85, 77, 32, - 67, 85, 77, 32, 80, 82, 79, 76, 65, 84, 73, 79, 78, 69, 32, 129, 1, 25, - 80, 69, 82, 70, 69, 67, 84, 85, 77, 32, 67, 85, 77, 32, 80, 82, 79, 76, - 65, 84, 73, 79, 78, 69, 32, 10, 60, 10, 73, 77, 80, 69, 82, 70, 69, 67, - 84, 65, 131, 1, 80, 9, 213, 206, 5, 11, 32, 68, 73, 77, 73, 78, 85, 84, - 73, 79, 78, 6, 60, 3, 73, 77, 80, 41, 8, 80, 69, 82, 70, 69, 67, 84, 65, - 2, 197, 178, 15, 5, 69, 82, 70, 69, 67, 5, 169, 189, 8, 12, 32, 68, 73, - 77, 73, 78, 85, 84, 73, 79, 78, 45, 6, 72, 2, 82, 69, 249, 5, 11, 73, 82, - 84, 89, 45, 83, 69, 67, 79, 78, 68, 2, 11, 69, 2, 11, 45, 2, 11, 76, 2, - 37, 7, 73, 78, 69, 32, 83, 84, 65, 2, 235, 211, 14, 70, 5, 225, 206, 11, - 6, 32, 82, 69, 83, 85, 80, 27, 33, 6, 73, 65, 78, 71, 76, 69, 24, 128, 1, - 10, 32, 78, 79, 84, 69, 72, 69, 65, 68, 32, 61, 17, 45, 82, 79, 85, 78, - 68, 32, 78, 79, 84, 69, 72, 69, 65, 68, 32, 68, 20, 58, 68, 24, 3, 85, - 80, 32, 38, 82, 25, 3, 76, 69, 70, 4, 93, 3, 79, 87, 78, 8, 34, 82, 78, - 87, 219, 182, 12, 66, 4, 21, 3, 73, 71, 72, 4, 11, 84, 4, 11, 32, 4, 26, - 87, 219, 182, 12, 66, 2, 11, 72, 2, 223, 138, 14, 73, 7, 11, 32, 4, 246, - 186, 8, 83, 183, 150, 7, 85, 4, 36, 3, 79, 73, 68, 159, 142, 15, 73, 2, - 237, 251, 12, 5, 32, 78, 79, 84, 69, 6, 92, 4, 72, 79, 76, 69, 221, 199, - 8, 13, 73, 84, 72, 32, 70, 73, 78, 71, 69, 82, 78, 65, 73, 4, 11, 32, 4, - 218, 186, 3, 78, 207, 183, 3, 82, 232, 3, 224, 2, 15, 67, 79, 78, 83, 79, - 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 254, 1, 76, 212, 14, 16, 77, 79, - 68, 73, 70, 73, 69, 82, 32, 76, 69, 84, 84, 69, 82, 32, 122, 83, 80, 16, - 69, 65, 83, 84, 69, 82, 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 222, 9, - 84, 204, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 160, 175, 9, - 3, 80, 65, 79, 207, 142, 4, 68, 16, 66, 77, 165, 1, 11, 83, 72, 65, 78, - 32, 77, 69, 68, 73, 65, 76, 14, 80, 6, 69, 68, 73, 65, 76, 32, 45, 10, - 79, 78, 32, 77, 69, 68, 73, 65, 76, 32, 8, 250, 200, 15, 72, 2, 82, 2, - 87, 3, 89, 6, 206, 200, 15, 76, 2, 77, 3, 78, 2, 219, 217, 10, 32, 238, - 1, 104, 6, 69, 84, 84, 69, 82, 32, 185, 13, 15, 79, 71, 79, 71, 82, 65, - 77, 32, 75, 72, 65, 77, 84, 73, 32, 232, 1, 238, 1, 65, 50, 69, 146, 1, - 71, 50, 75, 254, 1, 77, 134, 1, 78, 58, 82, 86, 83, 130, 3, 84, 198, 1, - 87, 178, 227, 11, 68, 214, 6, 85, 22, 86, 186, 201, 1, 73, 42, 76, 246, - 193, 1, 66, 2, 67, 2, 74, 2, 80, 138, 69, 72, 2, 89, 187, 2, 79, 7, 144, - 253, 14, 4, 73, 84, 79, 78, 219, 74, 85, 9, 77, 17, 65, 83, 84, 69, 82, - 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 78, 32, 6, 42, 71, 186, 213, 10, - 89, 135, 181, 3, 78, 2, 183, 213, 10, 72, 6, 154, 200, 9, 82, 218, 251, - 5, 72, 187, 2, 65, 44, 32, 2, 72, 65, 219, 197, 15, 65, 43, 25, 4, 77, - 84, 73, 32, 40, 134, 1, 68, 34, 84, 242, 217, 8, 78, 230, 162, 6, 67, 2, - 72, 2, 74, 170, 37, 76, 226, 31, 70, 2, 71, 2, 82, 2, 83, 2, 88, 3, 90, - 6, 242, 252, 14, 68, 139, 69, 72, 4, 211, 252, 14, 84, 12, 36, 3, 79, 78, - 32, 219, 195, 15, 65, 10, 60, 2, 66, 66, 218, 200, 13, 74, 254, 183, 1, - 78, 199, 66, 69, 4, 150, 195, 15, 65, 3, 69, 10, 214, 216, 8, 78, 238, - 231, 6, 71, 2, 89, 187, 2, 65, 4, 252, 220, 2, 12, 85, 77, 65, 73, 32, - 80, 65, 76, 65, 85, 78, 71, 199, 229, 12, 65, 50, 90, 72, 192, 221, 2, 9, - 71, 65, 87, 32, 75, 65, 82, 69, 78, 158, 225, 12, 83, 187, 2, 65, 44, 66, - 65, 197, 1, 11, 87, 69, 32, 80, 65, 76, 65, 85, 78, 71, 32, 41, 17, 2, - 78, 32, 38, 134, 1, 78, 246, 196, 13, 74, 2, 80, 2, 84, 130, 179, 1, 66, - 2, 67, 2, 71, 2, 75, 138, 69, 68, 2, 70, 2, 72, 2, 90, 187, 2, 65, 6, - 250, 188, 15, 78, 2, 89, 187, 2, 65, 4, 202, 196, 13, 67, 3, 83, 36, 38, - 65, 138, 247, 14, 84, 139, 69, 72, 31, 41, 8, 73, 32, 76, 65, 73, 78, 71, - 32, 28, 82, 78, 206, 227, 11, 68, 190, 146, 3, 66, 2, 71, 2, 74, 170, 37, - 76, 227, 31, 70, 4, 142, 187, 15, 78, 3, 89, 6, 92, 17, 69, 83, 84, 69, - 82, 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 78, 32, 207, 188, 15, 65, 4, - 194, 203, 10, 80, 203, 246, 2, 84, 6, 162, 176, 14, 79, 166, 60, 81, 139, - 63, 72, 4, 56, 6, 75, 72, 65, 77, 84, 73, 1, 4, 83, 72, 65, 78, 2, 29, 5, - 32, 82, 69, 68, 85, 2, 193, 132, 1, 2, 80, 76, 90, 76, 2, 72, 65, 20, 4, - 73, 71, 78, 32, 233, 6, 6, 89, 77, 66, 79, 76, 32, 20, 199, 186, 9, 78, - 52, 202, 3, 65, 32, 12, 75, 72, 65, 77, 84, 73, 32, 84, 79, 78, 69, 45, - 30, 83, 132, 2, 15, 84, 65, 73, 32, 76, 65, 73, 78, 71, 32, 84, 79, 78, - 69, 45, 28, 22, 87, 69, 83, 84, 69, 82, 78, 32, 80, 87, 79, 32, 75, 65, - 82, 69, 78, 32, 84, 79, 78, 69, 206, 244, 2, 68, 252, 163, 5, 19, 82, 85, - 77, 65, 73, 32, 80, 65, 76, 65, 85, 78, 71, 32, 84, 79, 78, 69, 45, 204, - 170, 3, 9, 80, 65, 79, 32, 75, 65, 82, 69, 78, 148, 114, 6, 76, 73, 84, - 84, 76, 69, 199, 187, 2, 86, 4, 234, 162, 14, 83, 255, 78, 78, 4, 178, - 182, 15, 49, 3, 51, 18, 40, 4, 72, 65, 78, 32, 147, 229, 14, 69, 16, 84, - 8, 67, 79, 85, 78, 67, 73, 76, 32, 84, 5, 84, 79, 78, 69, 45, 151, 182, - 14, 83, 6, 172, 196, 11, 8, 69, 77, 80, 72, 65, 84, 73, 67, 229, 239, 3, - 4, 84, 79, 78, 69, 8, 190, 180, 15, 50, 2, 51, 2, 53, 3, 54, 4, 146, 180, - 15, 50, 3, 53, 10, 11, 45, 10, 234, 179, 15, 49, 2, 50, 2, 51, 2, 52, 3, - 53, 18, 130, 1, 65, 132, 1, 2, 76, 79, 28, 5, 83, 72, 65, 78, 32, 192, - 173, 8, 4, 71, 69, 78, 73, 169, 97, 6, 67, 79, 77, 80, 76, 69, 8, 84, 5, - 73, 84, 79, 78, 32, 141, 174, 6, 10, 70, 79, 82, 69, 77, 69, 78, 84, 73, - 79, 6, 98, 69, 186, 249, 8, 84, 151, 158, 5, 79, 2, 217, 173, 8, 2, 67, - 65, 4, 26, 69, 207, 151, 14, 79, 2, 201, 12, 4, 88, 67, 76, 65, 24, 140, - 1, 20, 79, 78, 69, 32, 77, 65, 82, 75, 32, 83, 71, 65, 87, 32, 75, 65, - 82, 69, 78, 32, 221, 175, 9, 8, 65, 73, 32, 76, 65, 73, 78, 71, 4, 38, - 72, 129, 206, 8, 3, 75, 69, 32, 2, 139, 208, 8, 65, 56, 150, 2, 65, 76, - 9, 71, 69, 66, 65, 32, 75, 65, 82, 69, 20, 6, 75, 65, 89, 65, 72, 32, 40, - 4, 77, 79, 78, 32, 34, 83, 142, 1, 69, 40, 18, 87, 69, 83, 84, 69, 82, - 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 78, 32, 228, 182, 9, 2, 84, 65, - 142, 160, 2, 85, 22, 86, 187, 201, 1, 73, 8, 26, 73, 219, 172, 15, 65, 7, - 25, 4, 84, 79, 78, 32, 4, 223, 162, 13, 65, 2, 151, 236, 14, 78, 6, 190, - 149, 15, 69, 2, 79, 215, 22, 85, 4, 146, 152, 15, 73, 219, 19, 79, 10, - 80, 4, 72, 65, 78, 32, 157, 204, 8, 10, 71, 65, 87, 32, 75, 65, 82, 69, - 78, 32, 8, 54, 69, 20, 5, 70, 73, 78, 65, 76, 247, 167, 15, 65, 5, 199, - 173, 14, 32, 2, 227, 152, 15, 32, 4, 174, 133, 15, 69, 151, 14, 85, 230, - 17, 152, 2, 5, 45, 65, 82, 89, 32, 214, 4, 65, 222, 16, 66, 30, 69, 146, - 32, 73, 136, 1, 3, 75, 79, 32, 170, 10, 79, 162, 24, 85, 224, 8, 22, 89, - 73, 65, 75, 69, 78, 71, 32, 80, 85, 65, 67, 72, 85, 69, 32, 72, 77, 79, - 78, 71, 32, 216, 135, 2, 2, 80, 78, 220, 189, 12, 2, 78, 66, 27, 76, 32, - 130, 1, 67, 114, 84, 46, 83, 160, 1, 5, 85, 78, 73, 79, 78, 108, 4, 87, - 72, 73, 84, 246, 225, 11, 76, 210, 17, 73, 223, 160, 2, 80, 8, 52, 7, 73, - 82, 67, 76, 69, 68, 32, 135, 151, 14, 79, 6, 40, 2, 80, 76, 14, 84, 219, - 141, 8, 68, 2, 35, 85, 2, 21, 3, 73, 77, 69, 2, 219, 229, 11, 83, 6, 40, - 6, 81, 85, 65, 82, 69, 32, 87, 85, 4, 60, 9, 73, 78, 84, 69, 82, 83, 69, - 67, 84, 1, 2, 85, 78, 2, 215, 191, 11, 73, 2, 11, 77, 2, 179, 226, 11, - 77, 7, 69, 15, 32, 79, 80, 69, 82, 65, 84, 79, 82, 32, 87, 73, 84, 72, - 32, 4, 150, 157, 11, 80, 131, 182, 3, 68, 2, 11, 69, 2, 233, 204, 12, 2, - 32, 86, 188, 2, 170, 2, 66, 252, 4, 10, 71, 32, 77, 85, 78, 68, 65, 82, - 73, 32, 142, 4, 73, 52, 2, 78, 68, 208, 4, 7, 84, 73, 79, 78, 65, 76, 32, - 228, 213, 1, 2, 85, 83, 140, 137, 8, 5, 77, 69, 32, 66, 65, 184, 212, 3, - 7, 90, 65, 82, 32, 65, 77, 85, 188, 160, 1, 8, 82, 82, 79, 87, 32, 78, - 79, 45, 231, 62, 75, 82, 52, 7, 65, 84, 65, 69, 65, 78, 32, 231, 157, 15, - 76, 80, 160, 1, 7, 76, 69, 84, 84, 69, 82, 32, 236, 2, 7, 78, 85, 77, 66, - 69, 82, 32, 133, 243, 9, 16, 67, 82, 85, 67, 73, 70, 79, 82, 77, 32, 78, - 85, 77, 66, 69, 82, 62, 236, 1, 6, 70, 73, 78, 65, 76, 32, 154, 132, 2, - 84, 246, 118, 68, 34, 76, 50, 81, 238, 205, 1, 82, 178, 215, 2, 65, 50, - 71, 90, 90, 34, 83, 66, 89, 158, 208, 1, 72, 234, 5, 75, 198, 75, 66, - 178, 216, 4, 78, 134, 2, 87, 218, 103, 80, 171, 4, 77, 18, 246, 250, 2, - 65, 54, 76, 250, 163, 4, 83, 190, 3, 89, 134, 214, 1, 75, 198, 75, 66, - 178, 216, 4, 78, 222, 105, 72, 171, 4, 77, 16, 134, 252, 2, 84, 134, 166, - 4, 79, 223, 137, 6, 70, 84, 84, 7, 76, 69, 84, 84, 69, 82, 32, 164, 2, 5, - 83, 73, 71, 78, 32, 191, 167, 13, 68, 54, 42, 65, 50, 69, 66, 73, 50, 79, - 47, 85, 11, 138, 137, 15, 78, 202, 17, 66, 2, 72, 3, 74, 15, 158, 159, - 13, 78, 210, 113, 76, 138, 109, 84, 174, 28, 71, 3, 77, 11, 194, 211, 14, - 68, 162, 70, 72, 2, 83, 3, 84, 11, 222, 152, 15, 78, 86, 76, 2, 80, 3, - 89, 11, 134, 153, 15, 67, 2, 68, 2, 75, 3, 82, 10, 100, 2, 77, 85, 20, 3, - 83, 85, 84, 182, 118, 73, 212, 234, 10, 2, 79, 74, 241, 253, 2, 3, 84, - 79, 89, 2, 139, 223, 14, 72, 2, 207, 150, 15, 85, 4, 208, 182, 11, 5, 76, - 32, 80, 79, 76, 187, 15, 82, 133, 1, 41, 8, 73, 78, 65, 71, 65, 82, 73, - 32, 130, 1, 140, 1, 7, 76, 69, 84, 84, 69, 82, 32, 248, 1, 5, 83, 73, 71, - 78, 32, 52, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 239, 229, 4, - 72, 94, 210, 1, 86, 226, 185, 11, 65, 38, 68, 82, 82, 34, 84, 230, 5, 85, - 206, 201, 1, 73, 42, 76, 250, 192, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, - 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 89, 186, 2, 69, 3, 79, 6, - 202, 148, 5, 79, 183, 255, 9, 65, 10, 254, 240, 9, 83, 238, 203, 1, 65, - 231, 147, 3, 86, 24, 250, 235, 4, 80, 238, 39, 86, 246, 171, 6, 65, 38, - 85, 206, 201, 1, 73, 222, 137, 2, 69, 3, 79, 4, 158, 48, 68, 255, 160, - 14, 80, 4, 154, 146, 15, 83, 15, 72, 254, 4, 216, 1, 3, 71, 65, 84, 192, - 7, 6, 73, 84, 72, 69, 82, 32, 194, 3, 83, 136, 1, 2, 85, 84, 242, 1, 87, - 148, 16, 3, 88, 84, 32, 144, 186, 8, 4, 80, 84, 85, 78, 216, 133, 3, 2, - 67, 75, 238, 161, 2, 82, 207, 144, 1, 76, 162, 1, 152, 1, 4, 73, 86, 69, - 32, 161, 233, 12, 27, 69, 68, 32, 68, 79, 85, 66, 76, 69, 32, 86, 69, 82, - 84, 73, 67, 65, 76, 32, 66, 65, 82, 32, 68, 79, 85, 66, 160, 1, 152, 1, - 8, 67, 73, 82, 67, 76, 69, 68, 32, 224, 1, 9, 68, 73, 65, 71, 79, 78, 65, - 76, 32, 184, 1, 8, 83, 81, 85, 65, 82, 69, 68, 32, 231, 206, 8, 65, 78, - 112, 5, 68, 73, 71, 73, 84, 28, 7, 78, 85, 77, 66, 69, 82, 32, 180, 3, 2, - 76, 65, 202, 228, 13, 84, 135, 4, 83, 2, 209, 157, 13, 2, 32, 90, 20, 50, - 84, 214, 133, 2, 69, 46, 70, 42, 78, 31, 83, 6, 150, 135, 2, 72, 47, 87, - 6, 38, 77, 206, 202, 13, 67, 183, 4, 68, 2, 49, 10, 73, 68, 68, 76, 69, - 32, 82, 73, 71, 72, 2, 17, 2, 84, 32, 2, 41, 8, 84, 79, 32, 76, 79, 87, - 69, 82, 2, 153, 137, 12, 2, 32, 67, 74, 142, 1, 76, 70, 85, 230, 154, 12, - 68, 138, 29, 81, 216, 129, 1, 2, 67, 82, 218, 19, 65, 234, 19, 73, 2, 87, - 134, 8, 82, 194, 157, 1, 80, 3, 83, 54, 26, 65, 183, 237, 10, 69, 52, - 129, 246, 8, 5, 84, 73, 78, 32, 67, 2, 171, 233, 13, 80, 18, 158, 1, 65, - 216, 1, 17, 71, 82, 69, 65, 84, 69, 82, 45, 84, 72, 65, 78, 32, 78, 79, - 82, 32, 37, 14, 76, 69, 83, 83, 45, 84, 72, 65, 78, 32, 78, 79, 82, 32, - 6, 92, 3, 32, 83, 85, 85, 16, 80, 80, 82, 79, 88, 73, 77, 65, 84, 69, 76, - 89, 32, 78, 79, 82, 4, 30, 66, 1, 3, 80, 69, 82, 2, 217, 245, 6, 8, 83, - 69, 84, 32, 79, 70, 32, 78, 2, 233, 48, 5, 32, 65, 67, 84, 85, 6, 254, - 144, 8, 69, 131, 227, 4, 76, 6, 218, 144, 8, 69, 223, 226, 4, 71, 6, 26, - 84, 151, 255, 12, 83, 4, 76, 5, 73, 78, 71, 32, 68, 185, 210, 10, 8, 32, - 87, 73, 84, 72, 32, 69, 71, 2, 181, 252, 7, 2, 79, 76, 64, 40, 4, 82, 65, - 76, 32, 159, 203, 14, 69, 62, 48, 6, 67, 72, 69, 83, 83, 32, 191, 198, - 14, 70, 60, 74, 75, 234, 165, 13, 66, 38, 69, 130, 5, 80, 22, 81, 38, 82, - 131, 2, 84, 20, 44, 5, 78, 73, 71, 72, 84, 251, 166, 13, 73, 15, 167, - 167, 13, 32, 246, 2, 70, 32, 184, 8, 2, 65, 32, 252, 6, 3, 76, 73, 78, - 195, 223, 3, 83, 174, 1, 90, 77, 64, 4, 83, 72, 69, 81, 20, 8, 84, 65, - 73, 32, 76, 85, 69, 32, 255, 230, 13, 76, 4, 25, 4, 79, 79, 78, 32, 4, - 138, 143, 8, 87, 211, 222, 5, 83, 2, 163, 189, 9, 69, 166, 1, 160, 1, 7, - 76, 69, 84, 84, 69, 82, 32, 244, 2, 8, 83, 73, 71, 78, 32, 76, 65, 69, - 22, 84, 76, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 155, 138, 13, + 76, 2, 21, 3, 32, 78, 79, 2, 195, 142, 15, 84, 16, 40, 4, 83, 73, 71, 78, + 139, 164, 16, 88, 15, 11, 32, 12, 48, 3, 73, 78, 32, 81, 5, 87, 73, 84, + 72, 32, 8, 254, 206, 3, 76, 22, 82, 140, 191, 9, 5, 68, 79, 85, 66, 76, + 183, 238, 1, 84, 4, 242, 179, 12, 85, 187, 238, 2, 68, 7, 11, 32, 4, 244, + 83, 5, 77, 85, 76, 84, 73, 203, 155, 12, 85, 228, 3, 44, 5, 72, 82, 79, + 79, 77, 21, 2, 73, 67, 5, 215, 243, 14, 32, 224, 3, 30, 32, 109, 3, 65, + 76, 32, 6, 64, 4, 78, 65, 84, 85, 20, 3, 83, 72, 65, 209, 43, 2, 70, 76, + 2, 187, 212, 10, 82, 2, 227, 191, 11, 82, 218, 3, 64, 8, 75, 69, 89, 66, + 79, 65, 82, 68, 66, 83, 131, 248, 3, 78, 5, 41, 8, 32, 87, 73, 84, 72, + 32, 74, 65, 2, 231, 254, 13, 67, 212, 3, 48, 6, 89, 77, 66, 79, 76, 32, + 239, 177, 11, 67, 210, 3, 230, 2, 66, 238, 1, 67, 230, 9, 68, 250, 2, 69, + 162, 1, 70, 166, 2, 71, 112, 9, 65, 82, 80, 69, 71, 71, 73, 65, 84, 168, + 1, 2, 72, 65, 126, 75, 198, 3, 76, 138, 1, 77, 186, 2, 78, 162, 1, 79, + 218, 2, 80, 200, 2, 2, 81, 85, 146, 2, 82, 198, 2, 83, 226, 5, 84, 182, + 10, 86, 42, 88, 42, 87, 232, 145, 9, 9, 73, 78, 86, 69, 82, 84, 69, 68, + 32, 143, 210, 6, 90, 20, 36, 5, 69, 71, 73, 78, 32, 59, 82, 8, 142, 15, + 80, 30, 83, 250, 251, 7, 66, 151, 245, 7, 84, 12, 24, 2, 65, 67, 35, 69, + 4, 250, 229, 15, 75, 155, 53, 69, 8, 26, 86, 255, 216, 15, 65, 6, 32, 2, + 73, 83, 183, 154, 16, 69, 5, 179, 26, 32, 84, 120, 2, 65, 69, 34, 76, 94, + 79, 194, 7, 82, 242, 11, 32, 224, 32, 7, 73, 82, 67, 76, 69, 32, 88, 233, + 227, 5, 2, 85, 84, 2, 11, 83, 2, 219, 212, 15, 85, 8, 42, 73, 249, 23, 5, + 85, 83, 84, 69, 82, 4, 26, 77, 187, 241, 13, 86, 2, 199, 219, 9, 65, 64, + 26, 77, 219, 149, 16, 68, 62, 64, 7, 66, 73, 78, 73, 78, 71, 32, 153, + 151, 6, 3, 77, 79, 78, 60, 202, 1, 65, 80, 7, 77, 65, 82, 67, 65, 84, 79, + 56, 2, 68, 79, 56, 2, 85, 80, 28, 2, 70, 76, 40, 5, 72, 65, 82, 77, 79, + 22, 83, 142, 2, 84, 250, 181, 7, 66, 172, 199, 3, 2, 76, 79, 143, 147, 5, + 82, 6, 76, 5, 67, 67, 69, 78, 84, 37, 10, 85, 71, 77, 69, 78, 84, 65, 84, + 73, 79, 5, 205, 2, 5, 45, 83, 84, 65, 67, 2, 219, 129, 15, 78, 6, 52, 2, + 87, 78, 168, 3, 2, 85, 66, 239, 244, 15, 73, 2, 149, 248, 14, 2, 32, 66, + 12, 248, 76, 2, 65, 71, 159, 199, 15, 73, 2, 223, 233, 14, 78, 12, 132, + 1, 9, 78, 65, 80, 32, 80, 73, 90, 90, 73, 22, 84, 232, 206, 4, 11, 80, + 82, 69, 67, 72, 71, 69, 83, 65, 78, 71, 247, 138, 6, 77, 2, 231, 130, 12, + 67, 6, 44, 5, 65, 67, 67, 65, 84, 199, 129, 16, 69, 4, 40, 4, 73, 83, 83, + 73, 243, 145, 16, 79, 2, 251, 242, 15, 77, 10, 34, 82, 165, 158, 12, 2, + 69, 78, 8, 28, 2, 73, 80, 199, 6, 69, 2, 173, 129, 12, 6, 76, 69, 32, 84, + 79, 78, 4, 22, 79, 179, 2, 69, 2, 147, 130, 15, 73, 24, 98, 65, 142, 1, + 69, 92, 6, 79, 85, 66, 76, 69, 32, 145, 169, 10, 7, 82, 85, 77, 32, 67, + 76, 69, 10, 96, 2, 32, 67, 20, 2, 77, 80, 204, 29, 4, 83, 72, 69, 68, + 137, 200, 15, 5, 76, 32, 83, 69, 71, 2, 255, 194, 8, 65, 5, 175, 132, 14, + 32, 4, 40, 3, 67, 82, 69, 29, 3, 71, 82, 69, 2, 181, 25, 3, 83, 67, 69, + 2, 155, 233, 8, 69, 6, 242, 21, 83, 254, 6, 66, 191, 135, 5, 70, 14, 32, + 3, 78, 68, 32, 151, 16, 73, 10, 74, 80, 30, 83, 204, 13, 3, 79, 70, 32, + 174, 238, 7, 66, 151, 245, 7, 84, 2, 185, 227, 12, 2, 72, 82, 2, 231, + 147, 15, 76, 34, 104, 6, 69, 82, 77, 65, 84, 65, 22, 73, 122, 79, 102, + 32, 144, 36, 3, 85, 83, 65, 213, 230, 3, 2, 76, 65, 5, 175, 218, 13, 32, + 10, 22, 78, 135, 34, 86, 8, 56, 9, 71, 69, 82, 69, 68, 32, 84, 82, 69, + 239, 20, 65, 6, 137, 242, 5, 4, 77, 79, 76, 79, 6, 208, 25, 3, 85, 82, + 45, 203, 167, 14, 82, 18, 54, 32, 56, 7, 76, 73, 83, 83, 65, 78, 68, 23, + 82, 6, 25, 4, 67, 76, 69, 70, 7, 157, 13, 3, 32, 79, 84, 4, 251, 134, 6, + 79, 8, 84, 9, 65, 67, 69, 32, 78, 79, 84, 69, 32, 37, 8, 69, 71, 79, 82, + 73, 65, 78, 32, 4, 184, 227, 8, 2, 78, 79, 27, 83, 4, 250, 2, 67, 3, 70, + 8, 44, 3, 76, 70, 32, 205, 8, 3, 85, 80, 84, 6, 52, 3, 80, 69, 68, 210, + 223, 3, 78, 151, 181, 8, 82, 2, 139, 199, 5, 65, 24, 48, 6, 73, 69, 86, + 65, 78, 32, 139, 223, 14, 79, 22, 178, 1, 67, 46, 69, 68, 7, 81, 85, 65, + 82, 84, 69, 82, 62, 70, 148, 220, 3, 4, 72, 65, 76, 70, 0, 5, 87, 72, 79, + 76, 69, 173, 224, 1, 9, 82, 69, 67, 73, 84, 65, 84, 73, 86, 2, 11, 32, 2, + 11, 67, 2, 235, 163, 5, 76, 6, 64, 5, 73, 71, 72, 84, 72, 221, 203, 14, + 5, 78, 68, 32, 79, 70, 4, 253, 129, 6, 10, 32, 78, 79, 84, 69, 32, 83, + 84, 69, 77, 4, 218, 14, 76, 185, 205, 3, 4, 73, 78, 65, 76, 8, 44, 4, 79, + 78, 71, 65, 217, 13, 2, 69, 70, 7, 11, 32, 4, 28, 3, 73, 77, 80, 3, 80, + 2, 193, 2, 7, 69, 82, 70, 69, 67, 84, 65, 18, 104, 2, 65, 88, 20, 2, 69, + 90, 20, 5, 73, 78, 73, 77, 65, 44, 3, 79, 79, 78, 25, 4, 85, 76, 84, 73, + 2, 167, 224, 15, 73, 2, 175, 226, 15, 90, 7, 11, 32, 4, 226, 142, 12, 82, + 195, 83, 66, 4, 189, 17, 2, 32, 78, 4, 60, 11, 80, 76, 69, 32, 77, 69, + 65, 83, 85, 82, 69, 15, 32, 2, 11, 32, 2, 223, 141, 12, 82, 10, 120, 4, + 69, 66, 69, 78, 212, 26, 3, 85, 76, 76, 236, 225, 5, 3, 65, 84, 85, 189, + 227, 6, 7, 79, 84, 69, 72, 69, 65, 68, 2, 253, 228, 14, 4, 83, 84, 73, + 77, 32, 88, 2, 78, 69, 120, 14, 82, 78, 65, 77, 69, 78, 84, 32, 83, 84, + 82, 79, 75, 69, 107, 84, 6, 92, 18, 32, 72, 85, 78, 68, 82, 69, 68, 32, + 84, 87, 69, 78, 84, 89, 45, 69, 73, 159, 20, 45, 4, 181, 13, 2, 71, 72, + 22, 11, 45, 22, 170, 166, 3, 49, 194, 214, 12, 50, 2, 51, 2, 52, 2, 53, + 2, 54, 2, 55, 2, 56, 3, 57, 4, 173, 4, 3, 84, 65, 86, 18, 96, 9, 65, 82, + 69, 78, 84, 72, 69, 83, 73, 0, 2, 76, 85, 18, 69, 142, 1, 79, 163, 239, + 13, 73, 2, 243, 22, 83, 6, 68, 4, 68, 65, 76, 32, 49, 9, 83, 32, 83, 85, + 66, 80, 85, 78, 67, 4, 26, 85, 243, 184, 15, 77, 2, 215, 184, 15, 80, 2, + 255, 210, 13, 84, 6, 48, 2, 68, 65, 245, 5, 5, 82, 82, 69, 67, 84, 2, + 219, 240, 13, 84, 12, 76, 6, 65, 82, 84, 69, 82, 32, 125, 9, 73, 78, 68, + 73, 67, 69, 83, 73, 77, 8, 60, 5, 84, 79, 78, 69, 32, 234, 208, 3, 78, + 151, 181, 8, 82, 4, 26, 83, 187, 142, 5, 70, 2, 241, 247, 15, 3, 72, 65, + 82, 4, 17, 2, 65, 32, 4, 230, 186, 12, 65, 161, 186, 3, 3, 66, 65, 83, + 14, 22, 69, 175, 1, 73, 10, 72, 4, 80, 69, 65, 84, 81, 10, 86, 69, 82, + 83, 69, 32, 70, 73, 78, 65, 8, 56, 8, 69, 68, 32, 70, 73, 71, 85, 82, + 179, 163, 14, 32, 6, 179, 221, 5, 69, 2, 207, 4, 76, 4, 48, 2, 71, 72, + 57, 6, 78, 70, 79, 82, 90, 65, 2, 33, 6, 84, 32, 82, 69, 80, 69, 2, 179, + 169, 10, 65, 2, 171, 181, 8, 78, 48, 136, 1, 6, 67, 65, 78, 68, 73, 67, + 62, 69, 162, 1, 72, 54, 73, 252, 1, 6, 81, 85, 65, 82, 69, 32, 252, 158, + 8, 2, 85, 66, 251, 100, 79, 4, 17, 2, 85, 83, 5, 209, 234, 13, 5, 32, 70, + 76, 69, 88, 14, 32, 2, 77, 73, 223, 201, 15, 71, 12, 64, 6, 66, 82, 69, + 86, 73, 83, 1, 6, 77, 73, 78, 73, 77, 65, 6, 11, 32, 6, 134, 13, 87, 246, + 242, 11, 82, 195, 83, 66, 6, 84, 3, 79, 82, 84, 129, 239, 5, 3, 65, 82, + 80, 14, 32, 4, 78, 71, 76, 69, 43, 88, 2, 17, 2, 32, 66, 2, 207, 134, 14, + 65, 12, 18, 45, 79, 84, 4, 242, 7, 76, 217, 207, 14, 11, 83, 84, 82, 73, + 78, 71, 32, 70, 82, 69, 84, 8, 52, 3, 69, 69, 78, 1, 6, 89, 45, 70, 79, + 85, 82, 4, 193, 12, 2, 84, 72, 6, 26, 78, 167, 239, 15, 66, 4, 229, 9, 7, + 79, 84, 69, 72, 69, 65, 68, 60, 132, 1, 6, 69, 77, 80, 85, 83, 32, 154, + 4, 72, 88, 2, 87, 79, 84, 7, 79, 82, 67, 85, 76, 85, 83, 46, 82, 141, 3, + 3, 85, 82, 78, 16, 232, 1, 27, 73, 77, 80, 69, 82, 70, 69, 67, 84, 85, + 77, 32, 67, 85, 77, 32, 80, 82, 79, 76, 65, 84, 73, 79, 78, 69, 32, 129, + 1, 25, 80, 69, 82, 70, 69, 67, 84, 85, 77, 32, 67, 85, 77, 32, 80, 82, + 79, 76, 65, 84, 73, 79, 78, 69, 32, 10, 60, 10, 73, 77, 80, 69, 82, 70, + 69, 67, 84, 65, 131, 1, 80, 9, 249, 210, 5, 11, 32, 68, 73, 77, 73, 78, + 85, 84, 73, 79, 78, 6, 60, 3, 73, 77, 80, 41, 8, 80, 69, 82, 70, 69, 67, + 84, 65, 2, 245, 197, 15, 5, 69, 82, 70, 69, 67, 5, 197, 194, 8, 12, 32, + 68, 73, 77, 73, 78, 85, 84, 73, 79, 78, 45, 6, 72, 2, 82, 69, 249, 5, 11, + 73, 82, 84, 89, 45, 83, 69, 67, 79, 78, 68, 2, 11, 69, 2, 11, 45, 2, 11, + 76, 2, 37, 7, 73, 78, 69, 32, 83, 84, 65, 2, 155, 231, 14, 70, 5, 189, + 221, 11, 6, 32, 82, 69, 83, 85, 80, 27, 33, 6, 73, 65, 78, 71, 76, 69, + 24, 128, 1, 10, 32, 78, 79, 84, 69, 72, 69, 65, 68, 32, 61, 17, 45, 82, + 79, 85, 78, 68, 32, 78, 79, 84, 69, 72, 69, 65, 68, 32, 68, 20, 58, 68, + 24, 3, 85, 80, 32, 38, 82, 25, 3, 76, 69, 70, 4, 93, 3, 79, 87, 78, 8, + 34, 82, 78, 87, 183, 198, 12, 66, 4, 21, 3, 73, 71, 72, 4, 11, 84, 4, 11, + 32, 4, 26, 87, 183, 198, 12, 66, 2, 11, 72, 2, 243, 155, 14, 73, 7, 11, + 32, 4, 146, 192, 8, 83, 203, 164, 7, 85, 4, 36, 3, 79, 73, 68, 207, 161, + 15, 73, 2, 205, 139, 13, 5, 32, 78, 79, 84, 69, 6, 92, 4, 72, 79, 76, 69, + 253, 204, 8, 13, 73, 84, 72, 32, 70, 73, 78, 71, 69, 82, 78, 65, 73, 4, + 11, 32, 4, 210, 187, 3, 78, 151, 181, 8, 82, 232, 3, 224, 2, 15, 67, 79, + 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 254, 1, 76, 212, 14, + 16, 77, 79, 68, 73, 70, 73, 69, 82, 32, 76, 69, 84, 84, 69, 82, 32, 122, + 83, 80, 16, 69, 65, 83, 84, 69, 82, 78, 32, 80, 87, 79, 32, 75, 65, 82, + 69, 218, 9, 84, 204, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, + 140, 180, 9, 3, 80, 65, 79, 175, 154, 4, 68, 16, 66, 77, 165, 1, 11, 83, + 72, 65, 78, 32, 77, 69, 68, 73, 65, 76, 14, 80, 6, 69, 68, 73, 65, 76, + 32, 45, 10, 79, 78, 32, 77, 69, 68, 73, 65, 76, 32, 8, 170, 220, 15, 72, + 2, 82, 2, 87, 3, 89, 6, 254, 219, 15, 76, 2, 77, 3, 78, 2, 183, 228, 10, + 32, 238, 1, 104, 6, 69, 84, 84, 69, 82, 32, 185, 13, 15, 79, 71, 79, 71, + 82, 65, 77, 32, 75, 72, 65, 77, 84, 73, 32, 232, 1, 238, 1, 65, 50, 69, + 146, 1, 71, 50, 75, 254, 1, 77, 134, 1, 78, 58, 82, 86, 83, 130, 3, 84, + 198, 1, 87, 142, 243, 11, 68, 214, 6, 85, 22, 86, 166, 202, 1, 73, 42, + 76, 222, 196, 1, 66, 2, 67, 2, 74, 2, 80, 138, 69, 72, 2, 89, 187, 2, 79, + 7, 192, 144, 15, 4, 73, 84, 79, 78, 219, 74, 85, 9, 77, 17, 65, 83, 84, + 69, 82, 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 78, 32, 6, 42, 71, 150, + 224, 10, 89, 199, 187, 3, 78, 2, 147, 224, 10, 72, 6, 130, 205, 9, 82, + 162, 138, 6, 72, 187, 2, 65, 44, 32, 2, 72, 65, 139, 217, 15, 65, 43, 25, + 4, 77, 84, 73, 32, 40, 134, 1, 68, 34, 84, 162, 223, 8, 78, 230, 176, 6, + 67, 2, 72, 2, 74, 170, 37, 76, 226, 31, 70, 2, 71, 2, 82, 2, 83, 2, 88, + 3, 90, 6, 162, 144, 15, 68, 139, 69, 72, 4, 131, 144, 15, 84, 12, 36, 3, + 79, 78, 32, 139, 215, 15, 65, 10, 60, 2, 66, 66, 162, 217, 13, 74, 230, + 186, 1, 78, 199, 66, 69, 4, 198, 214, 15, 65, 3, 69, 10, 134, 222, 8, 78, + 238, 245, 6, 71, 2, 89, 187, 2, 65, 4, 132, 221, 2, 12, 85, 77, 65, 73, + 32, 80, 65, 76, 65, 85, 78, 71, 239, 248, 12, 65, 50, 90, 72, 200, 221, + 2, 9, 71, 65, 87, 32, 75, 65, 82, 69, 78, 198, 244, 12, 83, 187, 2, 65, + 44, 66, 65, 197, 1, 11, 87, 69, 32, 80, 65, 76, 65, 85, 78, 71, 32, 41, + 17, 2, 78, 32, 38, 134, 1, 78, 190, 213, 13, 74, 2, 80, 2, 84, 234, 181, + 1, 66, 2, 67, 2, 71, 2, 75, 138, 69, 68, 2, 70, 2, 72, 2, 90, 187, 2, 65, + 6, 170, 208, 15, 78, 2, 89, 187, 2, 65, 4, 146, 213, 13, 67, 3, 83, 36, + 38, 65, 186, 138, 15, 84, 139, 69, 72, 31, 41, 8, 73, 32, 76, 65, 73, 78, + 71, 32, 28, 82, 78, 170, 243, 11, 68, 146, 150, 3, 66, 2, 71, 2, 74, 170, + 37, 76, 227, 31, 70, 4, 190, 206, 15, 78, 3, 89, 6, 92, 17, 69, 83, 84, + 69, 82, 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 78, 32, 255, 207, 15, 65, + 4, 158, 214, 10, 80, 183, 252, 2, 84, 6, 182, 193, 14, 79, 194, 62, 81, + 139, 63, 72, 4, 56, 6, 75, 72, 65, 77, 84, 73, 1, 4, 83, 72, 65, 78, 2, + 29, 5, 32, 82, 69, 68, 85, 2, 241, 132, 1, 2, 80, 76, 90, 76, 2, 72, 65, + 20, 4, 73, 71, 78, 32, 233, 6, 6, 89, 77, 66, 79, 76, 32, 20, 175, 191, + 9, 78, 52, 202, 3, 65, 32, 12, 75, 72, 65, 77, 84, 73, 32, 84, 79, 78, + 69, 45, 30, 83, 132, 2, 15, 84, 65, 73, 32, 76, 65, 73, 78, 71, 32, 84, + 79, 78, 69, 45, 28, 22, 87, 69, 83, 84, 69, 82, 78, 32, 80, 87, 79, 32, + 75, 65, 82, 69, 78, 32, 84, 79, 78, 69, 222, 244, 2, 68, 136, 169, 5, 19, + 82, 85, 77, 65, 73, 32, 80, 65, 76, 65, 85, 78, 71, 32, 84, 79, 78, 69, + 45, 140, 180, 3, 9, 80, 65, 79, 32, 75, 65, 82, 69, 78, 148, 115, 6, 76, + 73, 84, 84, 76, 69, 155, 191, 2, 86, 4, 210, 192, 14, 83, 199, 68, 78, 4, + 226, 201, 15, 49, 3, 51, 18, 40, 4, 72, 65, 78, 32, 195, 248, 14, 69, 16, + 84, 8, 67, 79, 85, 78, 67, 73, 76, 32, 84, 5, 84, 79, 78, 69, 45, 199, + 201, 14, 83, 6, 136, 211, 11, 8, 69, 77, 80, 72, 65, 84, 73, 67, 185, + 244, 3, 4, 84, 79, 78, 69, 8, 238, 199, 15, 50, 2, 51, 2, 53, 3, 54, 4, + 194, 199, 15, 50, 3, 53, 10, 11, 45, 10, 154, 199, 15, 49, 2, 50, 2, 51, + 2, 52, 3, 53, 18, 130, 1, 65, 128, 1, 2, 76, 79, 28, 5, 83, 72, 65, 78, + 32, 228, 178, 8, 4, 71, 69, 78, 73, 217, 96, 6, 67, 79, 77, 80, 76, 69, + 8, 84, 5, 73, 84, 79, 78, 32, 185, 179, 6, 10, 70, 79, 82, 69, 77, 69, + 78, 84, 73, 79, 6, 94, 69, 246, 175, 13, 84, 139, 121, 79, 2, 253, 178, + 8, 2, 67, 65, 4, 26, 69, 255, 168, 14, 79, 2, 201, 12, 4, 88, 67, 76, 65, + 24, 140, 1, 20, 79, 78, 69, 32, 77, 65, 82, 75, 32, 83, 71, 65, 87, 32, + 75, 65, 82, 69, 78, 32, 201, 180, 9, 8, 65, 73, 32, 76, 65, 73, 78, 71, + 4, 38, 72, 181, 211, 8, 3, 75, 69, 32, 2, 191, 213, 8, 65, 56, 150, 2, + 65, 76, 9, 71, 69, 66, 65, 32, 75, 65, 82, 69, 20, 6, 75, 65, 89, 65, 72, + 32, 40, 4, 77, 79, 78, 32, 34, 83, 142, 1, 69, 40, 18, 87, 69, 83, 84, + 69, 82, 78, 32, 80, 87, 79, 32, 75, 65, 82, 69, 78, 32, 212, 187, 9, 2, + 84, 65, 254, 170, 2, 85, 22, 86, 167, 202, 1, 73, 8, 26, 73, 143, 192, + 15, 65, 7, 25, 4, 84, 79, 78, 32, 4, 171, 179, 13, 65, 2, 203, 255, 14, + 78, 6, 242, 168, 15, 69, 2, 79, 215, 22, 85, 4, 198, 171, 15, 73, 219, + 19, 79, 10, 80, 4, 72, 65, 78, 32, 209, 209, 8, 10, 71, 65, 87, 32, 75, + 65, 82, 69, 78, 32, 8, 54, 69, 20, 5, 70, 73, 78, 65, 76, 171, 187, 15, + 65, 5, 251, 192, 14, 32, 2, 151, 172, 15, 32, 4, 226, 152, 15, 69, 151, + 14, 85, 232, 17, 152, 2, 5, 45, 65, 82, 89, 32, 214, 4, 65, 222, 16, 66, + 30, 69, 146, 32, 73, 136, 1, 3, 75, 79, 32, 170, 10, 79, 166, 24, 85, + 224, 8, 22, 89, 73, 65, 75, 69, 78, 71, 32, 80, 85, 65, 67, 72, 85, 69, + 32, 72, 77, 79, 78, 71, 32, 232, 135, 2, 2, 80, 78, 252, 208, 12, 2, 78, + 66, 27, 76, 32, 130, 1, 67, 114, 84, 46, 83, 160, 1, 5, 85, 78, 73, 79, + 78, 108, 4, 87, 72, 73, 84, 214, 241, 11, 76, 210, 17, 73, 151, 162, 2, + 80, 8, 52, 7, 73, 82, 67, 76, 69, 68, 32, 159, 168, 14, 79, 6, 40, 2, 80, + 76, 14, 84, 251, 146, 8, 68, 2, 35, 85, 2, 21, 3, 73, 77, 69, 2, 187, + 245, 11, 83, 6, 40, 6, 81, 85, 65, 82, 69, 32, 87, 85, 4, 60, 9, 73, 78, + 84, 69, 82, 83, 69, 67, 84, 1, 2, 85, 78, 2, 147, 207, 11, 73, 2, 11, 77, + 2, 147, 242, 11, 77, 7, 69, 15, 32, 79, 80, 69, 82, 65, 84, 79, 82, 32, + 87, 73, 84, 72, 32, 4, 246, 171, 11, 80, 215, 186, 3, 68, 2, 11, 69, 2, + 205, 220, 12, 2, 32, 86, 188, 2, 170, 2, 66, 252, 4, 10, 71, 32, 77, 85, + 78, 68, 65, 82, 73, 32, 142, 4, 73, 52, 2, 78, 68, 208, 4, 7, 84, 73, 79, + 78, 65, 76, 32, 132, 214, 1, 2, 85, 83, 148, 147, 8, 5, 77, 69, 32, 66, + 65, 220, 218, 3, 7, 90, 65, 82, 32, 65, 77, 85, 164, 163, 1, 8, 82, 82, + 79, 87, 32, 78, 79, 45, 231, 62, 75, 82, 52, 7, 65, 84, 65, 69, 65, 78, + 32, 155, 177, 15, 76, 80, 160, 1, 7, 76, 69, 84, 84, 69, 82, 32, 236, 2, + 7, 78, 85, 77, 66, 69, 82, 32, 237, 253, 9, 16, 67, 82, 85, 67, 73, 70, + 79, 82, 77, 32, 78, 85, 77, 66, 69, 82, 62, 236, 1, 6, 70, 73, 78, 65, + 76, 32, 134, 132, 2, 84, 242, 119, 68, 34, 76, 50, 81, 214, 205, 1, 82, + 142, 220, 2, 65, 50, 71, 90, 90, 34, 83, 66, 89, 198, 207, 1, 72, 234, 5, + 75, 174, 81, 66, 170, 225, 4, 78, 134, 2, 87, 218, 103, 80, 171, 4, 77, + 18, 222, 251, 2, 65, 54, 76, 190, 168, 4, 83, 190, 3, 89, 174, 213, 1, + 75, 174, 81, 66, 170, 225, 4, 78, 222, 105, 72, 171, 4, 77, 16, 238, 252, + 2, 84, 202, 170, 4, 79, 255, 148, 6, 70, 84, 84, 7, 76, 69, 84, 84, 69, + 82, 32, 164, 2, 5, 83, 73, 71, 78, 32, 139, 184, 13, 68, 54, 42, 65, 50, + 69, 66, 73, 50, 79, 47, 85, 11, 190, 156, 15, 78, 202, 17, 66, 2, 72, 3, + 74, 15, 234, 175, 13, 78, 158, 114, 76, 166, 111, 84, 174, 28, 71, 3, 77, + 11, 246, 230, 14, 68, 162, 70, 72, 2, 83, 3, 84, 11, 146, 172, 15, 78, + 86, 76, 2, 80, 3, 89, 11, 186, 172, 15, 67, 2, 68, 2, 75, 3, 82, 10, 100, + 2, 77, 85, 20, 3, 83, 85, 84, 178, 118, 73, 184, 250, 10, 2, 79, 74, 197, + 129, 3, 3, 84, 79, 89, 2, 191, 242, 14, 72, 2, 131, 170, 15, 85, 4, 176, + 198, 11, 5, 76, 32, 80, 79, 76, 187, 15, 82, 133, 1, 41, 8, 73, 78, 65, + 71, 65, 82, 73, 32, 130, 1, 140, 1, 7, 76, 69, 84, 84, 69, 82, 32, 248, + 1, 5, 83, 73, 71, 78, 32, 52, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, + 32, 251, 230, 4, 72, 94, 210, 1, 86, 194, 201, 11, 65, 38, 68, 82, 82, + 34, 84, 230, 5, 85, 186, 202, 1, 73, 42, 76, 226, 195, 1, 78, 46, 83, 82, + 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 89, 186, 2, + 69, 3, 79, 6, 242, 152, 5, 79, 195, 142, 10, 65, 10, 230, 251, 9, 83, + 230, 208, 1, 65, 187, 151, 3, 86, 24, 234, 237, 4, 80, 166, 42, 86, 174, + 183, 6, 65, 38, 85, 186, 202, 1, 73, 198, 140, 2, 69, 3, 79, 4, 162, 48, + 68, 175, 180, 14, 80, 4, 206, 165, 15, 83, 15, 72, 254, 4, 216, 1, 3, 71, + 65, 84, 192, 7, 6, 73, 84, 72, 69, 82, 32, 194, 3, 83, 136, 1, 2, 85, 84, + 242, 1, 87, 148, 16, 3, 88, 84, 32, 180, 191, 8, 4, 80, 84, 85, 78, 148, + 144, 3, 2, 67, 75, 166, 163, 2, 82, 235, 146, 1, 76, 162, 1, 152, 1, 4, + 73, 86, 69, 32, 129, 249, 12, 27, 69, 68, 32, 68, 79, 85, 66, 76, 69, 32, + 86, 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, 82, 32, 68, 79, 85, 66, 160, + 1, 152, 1, 8, 67, 73, 82, 67, 76, 69, 68, 32, 224, 1, 9, 68, 73, 65, 71, + 79, 78, 65, 76, 32, 184, 1, 8, 83, 81, 85, 65, 82, 69, 68, 32, 143, 212, + 8, 65, 78, 112, 5, 68, 73, 71, 73, 84, 28, 7, 78, 85, 77, 66, 69, 82, 32, + 180, 3, 2, 76, 65, 234, 245, 13, 84, 151, 4, 83, 2, 157, 174, 13, 2, 32, + 90, 20, 50, 84, 194, 133, 2, 69, 46, 70, 42, 78, 31, 83, 6, 130, 135, 2, + 72, 47, 87, 6, 38, 77, 238, 219, 13, 67, 183, 4, 68, 2, 49, 10, 73, 68, + 68, 76, 69, 32, 82, 73, 71, 72, 2, 17, 2, 84, 32, 2, 41, 8, 84, 79, 32, + 76, 79, 87, 69, 82, 2, 249, 152, 12, 2, 32, 67, 74, 142, 1, 76, 70, 85, + 202, 170, 12, 68, 138, 29, 81, 140, 131, 1, 2, 67, 82, 226, 19, 65, 234, + 19, 73, 2, 87, 150, 8, 82, 198, 159, 1, 80, 3, 83, 54, 26, 65, 199, 247, + 10, 69, 52, 217, 250, 8, 5, 84, 73, 78, 32, 67, 2, 219, 250, 13, 80, 18, + 158, 1, 65, 216, 1, 17, 71, 82, 69, 65, 84, 69, 82, 45, 84, 72, 65, 78, + 32, 78, 79, 82, 32, 37, 14, 76, 69, 83, 83, 45, 84, 72, 65, 78, 32, 78, + 79, 82, 32, 6, 92, 3, 32, 83, 85, 85, 16, 80, 80, 82, 79, 88, 73, 77, 65, + 84, 69, 76, 89, 32, 78, 79, 82, 4, 30, 66, 1, 3, 80, 69, 82, 2, 245, 250, + 6, 8, 83, 69, 84, 32, 79, 70, 32, 78, 2, 237, 48, 5, 32, 65, 67, 84, 85, + 6, 178, 150, 8, 69, 167, 237, 4, 76, 6, 142, 150, 8, 69, 131, 237, 4, 71, + 6, 26, 84, 227, 143, 13, 83, 4, 76, 5, 73, 78, 71, 32, 68, 145, 221, 10, + 8, 32, 87, 73, 84, 72, 32, 69, 71, 2, 217, 129, 8, 2, 79, 76, 64, 40, 4, + 82, 65, 76, 32, 211, 222, 14, 69, 62, 48, 6, 67, 72, 69, 83, 83, 32, 243, + 217, 14, 70, 60, 74, 75, 238, 182, 13, 66, 38, 69, 150, 5, 80, 22, 81, + 38, 82, 131, 2, 84, 20, 44, 5, 78, 73, 71, 72, 84, 147, 184, 13, 73, 15, + 191, 184, 13, 32, 246, 2, 70, 32, 184, 8, 2, 65, 32, 252, 6, 3, 76, 73, + 78, 155, 224, 3, 83, 174, 1, 90, 77, 64, 4, 83, 72, 69, 81, 20, 8, 84, + 65, 73, 32, 76, 85, 69, 32, 175, 248, 13, 76, 4, 25, 4, 79, 79, 78, 32, + 4, 190, 148, 8, 87, 183, 234, 5, 83, 2, 223, 199, 9, 69, 166, 1, 160, 1, + 7, 76, 69, 84, 84, 69, 82, 32, 244, 2, 8, 83, 73, 71, 78, 32, 76, 65, 69, + 22, 84, 76, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 231, 154, 13, 68, 102, 76, 6, 70, 73, 78, 65, 76, 32, 68, 4, 72, 73, 71, 72, 1, 3, 76, - 79, 87, 14, 162, 131, 13, 78, 154, 251, 1, 66, 2, 68, 2, 75, 2, 77, 3, - 86, 44, 11, 32, 44, 146, 1, 75, 2, 88, 34, 83, 138, 139, 11, 78, 162, - 169, 3, 84, 82, 80, 138, 69, 66, 2, 68, 2, 70, 2, 72, 2, 76, 2, 77, 2, - 81, 2, 86, 3, 89, 4, 158, 250, 14, 86, 187, 2, 65, 4, 254, 249, 14, 85, - 187, 2, 65, 5, 151, 252, 14, 86, 6, 252, 154, 7, 3, 79, 78, 69, 233, 80, + 79, 87, 14, 238, 147, 13, 78, 130, 254, 1, 66, 2, 68, 2, 75, 2, 77, 3, + 86, 44, 11, 32, 44, 146, 1, 75, 2, 88, 34, 83, 234, 153, 11, 78, 246, + 173, 3, 84, 82, 80, 138, 69, 66, 2, 68, 2, 70, 2, 72, 2, 76, 2, 77, 2, + 81, 2, 86, 3, 89, 4, 210, 141, 15, 86, 187, 2, 65, 4, 178, 141, 15, 85, + 187, 2, 65, 5, 203, 143, 15, 86, 6, 168, 160, 7, 3, 79, 78, 69, 221, 80, 8, 72, 65, 77, 32, 68, 73, 71, 73, 34, 110, 65, 46, 73, 30, 79, 38, 85, - 216, 175, 12, 11, 86, 79, 87, 69, 76, 32, 83, 72, 79, 82, 84, 135, 202, - 2, 69, 8, 146, 219, 10, 65, 182, 159, 4, 69, 3, 89, 4, 154, 250, 14, 73, - 3, 89, 9, 202, 218, 10, 65, 183, 159, 4, 89, 11, 166, 218, 10, 69, 182, - 159, 4, 85, 3, 89, 194, 1, 182, 1, 68, 106, 71, 72, 7, 76, 69, 84, 84, - 69, 82, 32, 214, 2, 83, 194, 23, 80, 162, 139, 1, 86, 182, 230, 7, 65, - 144, 234, 1, 5, 73, 78, 83, 69, 82, 202, 174, 1, 67, 175, 193, 2, 79, 26, - 64, 6, 79, 85, 66, 76, 69, 32, 142, 155, 11, 65, 147, 235, 1, 73, 4, 254, - 154, 11, 68, 175, 138, 1, 67, 2, 11, 65, 2, 11, 80, 2, 17, 2, 32, 70, 2, - 129, 141, 11, 2, 73, 76, 108, 218, 1, 78, 62, 86, 142, 154, 11, 65, 38, - 68, 114, 84, 230, 5, 85, 206, 201, 1, 73, 206, 193, 1, 83, 82, 66, 2, 67, + 188, 191, 12, 11, 86, 79, 87, 69, 76, 32, 83, 72, 79, 82, 84, 215, 205, + 2, 69, 8, 222, 252, 10, 65, 158, 145, 4, 69, 3, 89, 4, 206, 141, 15, 73, + 3, 89, 9, 150, 252, 10, 65, 159, 145, 4, 89, 11, 242, 251, 10, 69, 158, + 145, 4, 85, 3, 89, 194, 1, 182, 1, 68, 106, 71, 72, 7, 76, 69, 84, 84, + 69, 82, 32, 214, 2, 83, 198, 23, 80, 190, 139, 1, 86, 210, 240, 7, 65, + 180, 238, 1, 5, 73, 78, 83, 69, 82, 206, 175, 1, 67, 255, 196, 2, 79, 26, + 64, 6, 79, 85, 66, 76, 69, 32, 238, 170, 11, 65, 255, 235, 1, 73, 4, 222, + 170, 11, 68, 179, 138, 1, 67, 2, 11, 65, 2, 11, 80, 2, 17, 2, 32, 70, 2, + 189, 156, 11, 2, 73, 76, 108, 218, 1, 78, 62, 86, 238, 169, 11, 65, 38, + 68, 114, 84, 230, 5, 85, 186, 202, 1, 73, 182, 196, 1, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, 2, 82, 138, 69, 72, 2, 87, 2, - 89, 186, 2, 69, 3, 79, 14, 166, 173, 14, 71, 2, 89, 138, 69, 72, 2, 78, - 187, 2, 65, 10, 26, 69, 139, 161, 11, 79, 2, 173, 190, 12, 3, 68, 73, 67, - 22, 26, 73, 247, 200, 4, 65, 20, 44, 3, 71, 78, 32, 165, 164, 9, 2, 68, - 68, 18, 226, 222, 10, 67, 98, 78, 242, 60, 65, 174, 158, 1, 74, 228, 2, - 5, 70, 73, 78, 65, 76, 50, 85, 167, 242, 1, 86, 4, 167, 199, 14, 69, 4, - 202, 235, 9, 80, 159, 237, 3, 76, 6, 70, 78, 185, 220, 13, 11, 71, 72, - 84, 32, 87, 73, 84, 72, 32, 83, 84, 4, 200, 241, 7, 7, 69, 32, 80, 79, - 73, 78, 84, 179, 253, 6, 74, 124, 152, 1, 3, 67, 79, 77, 130, 3, 68, 78, - 76, 156, 4, 4, 72, 73, 71, 72, 72, 7, 83, 89, 77, 66, 79, 76, 32, 226, - 217, 7, 69, 205, 188, 1, 3, 84, 65, 77, 20, 52, 7, 66, 73, 78, 73, 78, - 71, 32, 235, 236, 14, 77, 18, 88, 3, 68, 79, 85, 32, 5, 76, 79, 78, 71, - 32, 78, 78, 33, 6, 83, 72, 79, 82, 84, 32, 2, 225, 237, 13, 3, 66, 76, - 69, 8, 142, 1, 72, 34, 76, 230, 251, 10, 82, 21, 7, 68, 69, 83, 67, 69, - 78, 68, 2, 11, 65, 2, 171, 206, 10, 83, 6, 34, 72, 34, 76, 231, 251, 10, - 82, 2, 173, 252, 10, 3, 73, 71, 72, 2, 141, 252, 10, 2, 79, 87, 24, 152, - 1, 4, 65, 78, 84, 65, 144, 207, 12, 4, 79, 82, 79, 77, 155, 43, 73, 70, + 89, 186, 2, 69, 3, 79, 14, 218, 192, 14, 71, 2, 89, 138, 69, 72, 2, 78, + 187, 2, 65, 10, 26, 69, 235, 176, 11, 79, 2, 157, 206, 12, 3, 68, 73, 67, + 22, 26, 73, 131, 202, 4, 65, 20, 44, 3, 71, 78, 32, 225, 174, 9, 2, 68, + 68, 18, 246, 232, 10, 67, 98, 78, 190, 66, 65, 190, 158, 1, 74, 228, 2, + 5, 70, 73, 78, 65, 76, 50, 85, 235, 245, 1, 86, 4, 219, 218, 14, 69, 4, + 178, 246, 9, 80, 231, 243, 3, 76, 6, 70, 78, 233, 237, 13, 11, 71, 72, + 84, 32, 87, 73, 84, 72, 32, 83, 84, 4, 252, 246, 7, 7, 69, 32, 80, 79, + 73, 78, 84, 179, 139, 7, 74, 124, 152, 1, 3, 67, 79, 77, 130, 3, 68, 78, + 76, 156, 4, 4, 72, 73, 71, 72, 72, 7, 83, 89, 77, 66, 79, 76, 32, 134, + 223, 7, 69, 229, 193, 1, 3, 84, 65, 77, 20, 52, 7, 66, 73, 78, 73, 78, + 71, 32, 159, 128, 15, 77, 18, 88, 3, 68, 79, 85, 32, 5, 76, 79, 78, 71, + 32, 78, 78, 33, 6, 83, 72, 79, 82, 84, 32, 2, 149, 129, 14, 3, 66, 76, + 69, 8, 142, 1, 72, 34, 76, 198, 138, 11, 82, 21, 7, 68, 69, 83, 67, 69, + 78, 68, 2, 11, 65, 2, 187, 216, 10, 83, 6, 34, 72, 34, 76, 199, 138, 11, + 82, 2, 141, 139, 11, 3, 73, 71, 72, 2, 237, 138, 11, 2, 79, 87, 24, 152, + 1, 4, 65, 78, 84, 65, 232, 222, 12, 4, 79, 82, 79, 77, 143, 44, 73, 70, 76, 4, 65, 74, 65, 78, 32, 6, 69, 84, 84, 69, 82, 32, 173, 3, 2, 79, 87, - 2, 185, 161, 13, 3, 89, 65, 76, 66, 228, 1, 2, 68, 65, 42, 74, 90, 78, - 138, 143, 11, 82, 206, 147, 1, 79, 162, 75, 67, 162, 186, 1, 69, 250, 18, + 2, 209, 178, 13, 3, 89, 65, 76, 66, 228, 1, 2, 68, 65, 42, 74, 90, 78, + 234, 158, 11, 82, 210, 147, 1, 79, 138, 76, 67, 138, 189, 1, 69, 250, 18, 71, 242, 42, 66, 2, 70, 2, 72, 2, 75, 2, 76, 2, 77, 2, 80, 2, 83, 2, 84, - 2, 87, 2, 89, 186, 2, 65, 2, 73, 3, 85, 5, 197, 178, 11, 5, 71, 66, 65, - 83, 73, 8, 40, 4, 79, 78, 65, 32, 227, 232, 14, 65, 6, 158, 238, 12, 67, - 138, 248, 1, 74, 3, 82, 11, 26, 65, 1, 2, 89, 65, 5, 245, 135, 8, 5, 32, - 87, 79, 76, 79, 2, 29, 5, 32, 84, 79, 78, 69, 2, 17, 2, 32, 65, 2, 135, - 207, 8, 80, 4, 68, 7, 71, 66, 65, 75, 85, 82, 85, 1, 6, 79, 79, 32, 68, - 69, 78, 2, 247, 146, 13, 78, 184, 1, 90, 32, 156, 3, 2, 77, 73, 118, 78, - 150, 1, 82, 238, 7, 84, 250, 153, 14, 45, 147, 40, 83, 18, 202, 1, 66, - 96, 5, 69, 78, 84, 82, 89, 22, 80, 204, 186, 2, 15, 79, 78, 69, 32, 85, - 78, 68, 69, 82, 32, 69, 73, 71, 72, 84, 160, 129, 4, 9, 77, 79, 66, 73, + 2, 87, 2, 89, 186, 2, 65, 2, 73, 3, 85, 5, 165, 194, 11, 5, 71, 66, 65, + 83, 73, 8, 40, 4, 79, 78, 65, 32, 151, 252, 14, 65, 6, 234, 254, 12, 67, + 242, 250, 1, 74, 3, 82, 11, 26, 65, 1, 2, 89, 65, 5, 169, 141, 8, 5, 32, + 87, 79, 76, 79, 2, 29, 5, 32, 84, 79, 78, 69, 2, 17, 2, 32, 65, 2, 223, + 211, 8, 80, 4, 68, 7, 71, 66, 65, 75, 85, 82, 85, 1, 6, 79, 79, 32, 68, + 69, 78, 2, 143, 164, 13, 78, 186, 1, 94, 32, 156, 3, 2, 77, 73, 118, 78, + 150, 1, 82, 238, 7, 84, 206, 213, 6, 83, 223, 215, 7, 45, 18, 202, 1, 66, + 96, 5, 69, 78, 84, 82, 89, 22, 80, 224, 186, 2, 15, 79, 78, 69, 32, 85, + 78, 68, 69, 82, 32, 69, 73, 71, 72, 84, 164, 134, 4, 9, 77, 79, 66, 73, 76, 69, 32, 80, 72, 189, 30, 3, 83, 77, 79, 4, 52, 4, 82, 69, 65, 75, - 165, 137, 2, 3, 73, 67, 89, 2, 17, 2, 32, 72, 2, 155, 195, 13, 69, 5, - 203, 220, 13, 32, 4, 60, 6, 69, 68, 69, 83, 84, 82, 221, 201, 9, 3, 73, - 82, 65, 2, 145, 159, 11, 2, 73, 65, 4, 36, 5, 78, 65, 76, 32, 68, 59, 83, - 2, 173, 206, 13, 9, 73, 71, 73, 84, 32, 83, 72, 65, 80, 2, 175, 144, 11, - 77, 6, 38, 45, 249, 217, 9, 3, 70, 79, 82, 4, 76, 8, 66, 82, 69, 65, 75, - 73, 78, 71, 161, 169, 2, 5, 80, 79, 84, 65, 66, 2, 249, 221, 6, 2, 32, - 72, 97, 56, 2, 84, 72, 146, 11, 77, 209, 229, 10, 3, 68, 73, 67, 88, 42, - 32, 201, 205, 6, 4, 69, 65, 83, 84, 86, 96, 5, 69, 65, 83, 84, 32, 148, + 173, 137, 2, 3, 73, 67, 89, 2, 17, 2, 32, 72, 2, 199, 212, 13, 69, 5, + 251, 239, 13, 32, 4, 60, 6, 69, 68, 69, 83, 84, 82, 193, 212, 9, 3, 73, + 82, 65, 2, 237, 174, 11, 2, 73, 65, 4, 36, 5, 78, 65, 76, 32, 68, 59, 83, + 2, 209, 223, 13, 9, 73, 71, 73, 84, 32, 83, 72, 65, 80, 2, 139, 160, 11, + 77, 6, 38, 45, 221, 228, 9, 3, 70, 79, 82, 4, 76, 8, 66, 82, 69, 65, 75, + 73, 78, 71, 181, 169, 2, 5, 80, 79, 84, 65, 66, 2, 161, 227, 6, 2, 32, + 72, 97, 56, 2, 84, 72, 146, 11, 77, 181, 244, 10, 3, 68, 73, 67, 88, 42, + 32, 225, 210, 6, 4, 69, 65, 83, 84, 86, 96, 5, 69, 65, 83, 84, 32, 148, 2, 6, 73, 78, 68, 73, 67, 32, 221, 1, 5, 87, 69, 83, 84, 32, 32, 82, 65, - 238, 242, 6, 80, 130, 1, 84, 138, 197, 4, 66, 38, 68, 18, 83, 247, 58, - 87, 14, 40, 4, 82, 82, 79, 87, 215, 238, 6, 78, 13, 11, 32, 10, 96, 9, - 67, 82, 79, 83, 83, 73, 78, 71, 32, 248, 2, 2, 65, 78, 162, 238, 6, 87, - 203, 134, 5, 70, 4, 234, 197, 3, 83, 231, 170, 3, 78, 20, 54, 80, 60, 3, - 81, 85, 65, 66, 82, 171, 132, 1, 70, 2, 37, 7, 76, 65, 67, 69, 72, 79, - 76, 2, 243, 179, 4, 68, 4, 220, 179, 4, 2, 82, 84, 209, 230, 9, 5, 78, - 84, 73, 84, 89, 2, 17, 2, 85, 80, 2, 171, 166, 4, 69, 34, 82, 65, 254, - 238, 6, 80, 130, 1, 84, 138, 197, 4, 66, 38, 68, 18, 83, 247, 58, 87, 16, - 34, 78, 33, 4, 82, 82, 79, 87, 2, 241, 194, 3, 3, 68, 32, 83, 15, 11, 32, - 12, 84, 3, 84, 79, 32, 142, 234, 6, 67, 40, 3, 65, 78, 68, 234, 2, 87, - 203, 134, 5, 70, 4, 150, 235, 6, 67, 169, 204, 6, 4, 76, 79, 78, 71, 56, + 150, 248, 6, 80, 130, 1, 84, 190, 207, 4, 66, 38, 68, 18, 83, 251, 58, + 87, 14, 40, 4, 82, 82, 79, 87, 255, 243, 6, 78, 13, 11, 32, 10, 96, 9, + 67, 82, 79, 83, 83, 73, 78, 71, 32, 248, 2, 2, 65, 78, 202, 243, 6, 87, + 131, 145, 5, 70, 4, 190, 198, 3, 83, 187, 175, 3, 78, 20, 54, 80, 60, 3, + 81, 85, 65, 66, 82, 199, 132, 1, 70, 2, 37, 7, 76, 65, 67, 69, 72, 79, + 76, 2, 251, 180, 4, 68, 4, 228, 180, 4, 2, 82, 84, 249, 248, 9, 5, 78, + 84, 73, 84, 89, 2, 17, 2, 85, 80, 2, 179, 167, 4, 69, 34, 82, 65, 166, + 244, 6, 80, 130, 1, 84, 190, 207, 4, 66, 38, 68, 18, 83, 251, 58, 87, 16, + 34, 78, 33, 4, 82, 82, 79, 87, 2, 197, 195, 3, 3, 68, 32, 83, 15, 11, 32, + 12, 84, 3, 84, 79, 32, 182, 239, 6, 67, 40, 3, 65, 78, 68, 234, 2, 87, + 131, 145, 5, 70, 4, 190, 240, 6, 67, 173, 216, 6, 4, 76, 79, 78, 71, 56, 54, 32, 236, 5, 5, 67, 72, 69, 68, 32, 207, 2, 69, 38, 162, 1, 65, 132, - 2, 4, 78, 79, 82, 77, 78, 80, 46, 83, 170, 1, 84, 234, 221, 7, 69, 196, - 33, 7, 73, 68, 69, 78, 84, 73, 67, 154, 193, 4, 71, 38, 76, 191, 78, 67, + 2, 4, 78, 79, 82, 77, 78, 80, 46, 83, 170, 1, 84, 154, 227, 7, 69, 196, + 33, 7, 73, 68, 69, 78, 84, 73, 67, 190, 203, 4, 71, 38, 76, 135, 80, 67, 10, 88, 3, 32, 83, 85, 52, 7, 78, 32, 69, 76, 69, 77, 69, 28, 2, 83, 89, - 251, 128, 8, 76, 4, 30, 66, 1, 3, 80, 69, 82, 2, 29, 2, 83, 69, 2, 11, - 78, 2, 183, 125, 84, 2, 37, 7, 77, 80, 84, 79, 84, 73, 67, 2, 17, 2, 65, - 76, 2, 185, 129, 8, 2, 76, 89, 4, 253, 195, 6, 14, 65, 76, 32, 83, 85, - 66, 71, 82, 79, 85, 80, 32, 79, 70, 2, 137, 129, 8, 6, 65, 82, 65, 76, - 76, 69, 6, 48, 6, 81, 85, 65, 82, 69, 32, 247, 204, 13, 73, 4, 68, 5, 73, + 171, 134, 8, 76, 4, 30, 66, 1, 3, 80, 69, 82, 2, 29, 2, 83, 69, 2, 11, + 78, 2, 211, 125, 84, 2, 37, 7, 77, 80, 84, 79, 84, 73, 67, 2, 17, 2, 65, + 76, 2, 233, 134, 8, 2, 76, 89, 4, 149, 201, 6, 14, 65, 76, 32, 83, 85, + 66, 71, 82, 79, 85, 80, 32, 79, 70, 2, 185, 134, 8, 6, 65, 82, 65, 76, + 76, 69, 6, 48, 6, 81, 85, 65, 82, 69, 32, 167, 224, 13, 73, 4, 68, 5, 73, 77, 65, 71, 69, 1, 8, 79, 82, 73, 71, 73, 78, 65, 76, 2, 21, 3, 32, 79, - 70, 2, 255, 193, 6, 32, 4, 210, 199, 10, 82, 215, 241, 1, 73, 8, 58, 76, + 70, 2, 151, 199, 6, 32, 4, 174, 214, 10, 82, 207, 242, 1, 73, 8, 58, 76, 40, 4, 82, 73, 71, 72, 133, 1, 3, 85, 80, 80, 4, 36, 2, 69, 70, 133, 1, 2, 79, 87, 2, 89, 20, 84, 32, 83, 69, 77, 73, 67, 73, 82, 67, 76, 69, 32, - 87, 73, 84, 72, 32, 84, 72, 2, 17, 2, 82, 69, 2, 167, 128, 13, 69, 2, 11, - 69, 2, 41, 8, 82, 32, 82, 73, 71, 72, 84, 45, 2, 197, 147, 3, 6, 83, 72, + 87, 73, 84, 72, 32, 84, 72, 2, 17, 2, 82, 69, 2, 187, 145, 13, 69, 2, 11, + 69, 2, 41, 8, 82, 32, 82, 73, 71, 72, 84, 45, 2, 205, 148, 3, 6, 83, 72, 65, 68, 79, 87, 11, 34, 32, 53, 4, 66, 79, 79, 75, 4, 17, 2, 80, 65, 4, - 222, 184, 14, 71, 215, 22, 68, 5, 81, 18, 32, 87, 73, 84, 72, 32, 68, 69, - 67, 79, 82, 65, 84, 73, 86, 69, 32, 67, 2, 171, 141, 4, 79, 186, 6, 102, - 77, 176, 3, 4, 83, 72, 85, 32, 172, 178, 5, 8, 84, 32, 65, 78, 68, 32, - 66, 79, 187, 155, 8, 76, 26, 36, 4, 66, 69, 82, 32, 247, 2, 69, 24, 58, + 142, 204, 14, 71, 215, 22, 68, 5, 81, 18, 32, 87, 73, 84, 72, 32, 68, 69, + 67, 79, 82, 65, 84, 73, 86, 69, 32, 67, 2, 179, 142, 4, 79, 186, 6, 102, + 77, 176, 3, 4, 83, 72, 85, 32, 216, 183, 5, 8, 84, 32, 65, 78, 68, 32, + 66, 79, 191, 169, 8, 76, 26, 36, 4, 66, 69, 82, 32, 247, 2, 69, 24, 58, 69, 50, 70, 42, 83, 66, 84, 57, 4, 78, 73, 78, 69, 4, 204, 1, 3, 73, 71, 72, 21, 3, 76, 69, 86, 4, 144, 1, 2, 79, 85, 13, 2, 73, 70, 6, 34, 73, - 85, 4, 69, 86, 69, 78, 4, 82, 88, 175, 251, 13, 71, 8, 40, 2, 72, 73, 46, - 69, 21, 2, 87, 69, 2, 11, 82, 2, 17, 2, 84, 69, 2, 11, 69, 2, 171, 199, - 7, 78, 4, 148, 199, 7, 3, 76, 86, 69, 1, 3, 78, 84, 89, 2, 215, 242, 6, - 82, 154, 6, 72, 12, 67, 72, 65, 82, 65, 67, 84, 69, 82, 45, 49, 66, 251, - 166, 12, 73, 152, 6, 18, 49, 87, 50, 160, 2, 222, 1, 55, 2, 56, 2, 57, 2, + 85, 4, 69, 86, 69, 78, 4, 82, 88, 223, 142, 14, 71, 8, 40, 2, 72, 73, 46, + 69, 21, 2, 87, 69, 2, 11, 82, 2, 17, 2, 84, 69, 2, 11, 69, 2, 203, 204, + 7, 78, 4, 180, 204, 7, 3, 76, 86, 69, 1, 3, 78, 84, 89, 2, 255, 247, 6, + 82, 154, 6, 72, 12, 67, 72, 65, 82, 65, 67, 84, 69, 82, 45, 49, 66, 215, + 182, 12, 73, 152, 6, 18, 49, 87, 50, 160, 2, 222, 1, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, 68, 2, 69, 3, 70, 248, 3, 138, 1, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, - 68, 2, 69, 143, 1, 70, 32, 194, 199, 14, 48, 2, 49, 2, 50, 2, 51, 2, 52, + 68, 2, 69, 143, 1, 70, 32, 242, 218, 14, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 2, 66, 2, 67, 2, 68, 2, 69, 3, - 70, 24, 182, 198, 14, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, + 70, 24, 230, 217, 14, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 65, 3, 66, 142, 1, 118, 76, 226, 3, 83, 164, 2, 5, - 84, 79, 78, 69, 45, 148, 225, 7, 8, 67, 73, 82, 67, 76, 69, 68, 32, 155, - 236, 4, 68, 92, 88, 6, 69, 84, 84, 69, 82, 32, 197, 163, 1, 10, 79, 71, - 79, 71, 82, 65, 77, 32, 78, 89, 90, 130, 2, 78, 90, 84, 246, 214, 7, 88, - 162, 126, 65, 232, 203, 1, 2, 72, 65, 242, 70, 82, 206, 147, 1, 79, 174, - 60, 68, 2, 77, 2, 80, 150, 201, 1, 69, 234, 61, 67, 2, 70, 2, 71, 2, 75, + 84, 79, 78, 69, 45, 196, 230, 7, 8, 67, 73, 82, 67, 76, 69, 68, 32, 179, + 247, 4, 68, 92, 88, 6, 69, 84, 84, 69, 82, 32, 173, 163, 1, 10, 79, 71, + 79, 71, 82, 65, 77, 32, 78, 89, 90, 130, 2, 78, 90, 84, 166, 220, 7, 88, + 182, 230, 2, 65, 144, 1, 2, 72, 65, 226, 51, 82, 210, 147, 1, 79, 150, + 61, 68, 2, 77, 2, 80, 254, 203, 1, 69, 234, 61, 67, 2, 70, 2, 71, 2, 75, 2, 76, 2, 81, 2, 83, 2, 86, 2, 89, 2, 90, 186, 2, 73, 2, 85, 3, 87, 22, - 86, 84, 230, 183, 12, 80, 254, 134, 2, 67, 2, 75, 2, 81, 2, 82, 2, 89, - 187, 2, 65, 6, 222, 190, 14, 83, 2, 88, 187, 2, 65, 14, 64, 4, 73, 71, + 86, 84, 174, 200, 12, 80, 230, 137, 2, 67, 2, 75, 2, 81, 2, 82, 2, 89, + 187, 2, 65, 6, 142, 210, 14, 83, 2, 88, 187, 2, 65, 14, 64, 4, 73, 71, 78, 32, 189, 1, 7, 89, 76, 76, 65, 66, 76, 69, 12, 56, 4, 70, 79, 82, 32, - 209, 193, 13, 4, 88, 87, 32, 88, 10, 156, 9, 2, 76, 79, 194, 164, 3, 84, - 232, 93, 8, 73, 78, 86, 69, 82, 84, 69, 66, 160, 141, 4, 3, 65, 78, 73, - 183, 167, 2, 80, 2, 209, 244, 11, 4, 32, 76, 69, 78, 14, 202, 190, 14, - 66, 2, 68, 2, 71, 2, 74, 2, 77, 2, 83, 3, 86, 250, 14, 178, 2, 66, 226, - 1, 67, 224, 5, 4, 70, 70, 73, 67, 54, 71, 248, 6, 4, 73, 76, 32, 68, 22, - 76, 186, 69, 78, 150, 5, 80, 234, 7, 82, 218, 10, 83, 188, 8, 2, 84, 84, - 154, 8, 85, 248, 1, 3, 86, 69, 82, 198, 170, 2, 89, 202, 198, 5, 72, 238, - 254, 1, 75, 154, 249, 1, 68, 194, 64, 77, 246, 9, 87, 183, 137, 1, 88, - 10, 132, 1, 6, 76, 73, 81, 85, 69, 32, 180, 158, 2, 9, 83, 69, 82, 86, - 69, 82, 32, 69, 89, 189, 29, 8, 74, 69, 67, 84, 32, 82, 69, 80, 6, 176, - 198, 4, 13, 65, 78, 71, 76, 69, 32, 79, 80, 69, 78, 73, 78, 71, 175, 241, - 1, 72, 28, 56, 2, 82, 32, 234, 4, 84, 229, 193, 5, 3, 67, 85, 76, 22, - 156, 1, 11, 65, 77, 79, 85, 78, 84, 32, 79, 70, 32, 67, 22, 66, 198, 1, - 67, 118, 68, 106, 70, 0, 10, 73, 78, 86, 69, 82, 84, 69, 68, 32, 70, 143, - 225, 12, 72, 2, 207, 179, 5, 72, 6, 136, 1, 15, 82, 65, 78, 67, 72, 32, - 66, 65, 78, 75, 32, 73, 68, 69, 78, 160, 254, 4, 5, 69, 76, 84, 32, 66, - 157, 134, 6, 3, 79, 87, 32, 2, 21, 3, 84, 73, 70, 2, 11, 73, 2, 215, 244, - 10, 67, 4, 92, 17, 85, 83, 84, 79, 77, 69, 82, 32, 65, 67, 67, 79, 85, - 78, 84, 32, 78, 155, 202, 1, 72, 2, 183, 156, 6, 85, 4, 44, 5, 79, 85, - 66, 76, 69, 251, 204, 12, 65, 2, 11, 32, 2, 11, 66, 2, 177, 158, 7, 3, - 65, 67, 75, 2, 191, 243, 13, 79, 4, 152, 241, 8, 4, 65, 71, 79, 78, 181, - 189, 3, 2, 79, 80, 2, 11, 69, 2, 221, 251, 7, 5, 32, 66, 85, 73, 76, 60, - 48, 4, 72, 65, 77, 32, 133, 176, 14, 2, 79, 78, 58, 122, 70, 0, 10, 82, + 129, 213, 13, 4, 88, 87, 32, 88, 10, 204, 9, 2, 76, 79, 230, 164, 3, 84, + 156, 94, 8, 73, 78, 86, 69, 82, 84, 69, 66, 232, 144, 4, 3, 65, 78, 73, + 195, 177, 2, 80, 2, 177, 132, 12, 4, 32, 76, 69, 78, 14, 250, 209, 14, + 66, 2, 68, 2, 71, 2, 74, 2, 77, 2, 83, 3, 86, 254, 14, 226, 2, 66, 226, + 1, 67, 226, 5, 71, 244, 6, 4, 73, 76, 32, 68, 22, 76, 198, 69, 78, 150, + 5, 80, 234, 7, 82, 242, 10, 83, 188, 8, 2, 84, 84, 154, 8, 85, 248, 1, 3, + 86, 69, 82, 254, 170, 2, 89, 148, 151, 4, 14, 70, 70, 73, 67, 69, 32, 66, + 85, 73, 76, 68, 73, 78, 71, 154, 185, 1, 72, 146, 132, 2, 75, 210, 250, + 1, 68, 194, 64, 77, 246, 9, 87, 211, 139, 1, 88, 10, 132, 1, 6, 76, 73, + 81, 85, 69, 32, 252, 158, 2, 9, 83, 69, 82, 86, 69, 82, 32, 69, 89, 189, + 29, 8, 74, 69, 67, 84, 32, 82, 69, 80, 6, 172, 203, 4, 13, 65, 78, 71, + 76, 69, 32, 79, 80, 69, 78, 73, 78, 71, 171, 241, 1, 72, 28, 56, 2, 82, + 32, 234, 4, 84, 225, 198, 5, 3, 67, 85, 76, 22, 156, 1, 11, 65, 77, 79, + 85, 78, 84, 32, 79, 70, 32, 67, 22, 66, 198, 1, 67, 118, 68, 106, 70, 0, + 10, 73, 78, 86, 69, 82, 84, 69, 68, 32, 70, 243, 241, 12, 72, 2, 203, + 184, 5, 72, 6, 136, 1, 15, 82, 65, 78, 67, 72, 32, 66, 65, 78, 75, 32, + 73, 68, 69, 78, 156, 131, 5, 5, 69, 76, 84, 32, 66, 205, 144, 6, 3, 79, + 87, 32, 2, 21, 3, 84, 73, 70, 2, 11, 73, 2, 131, 132, 11, 67, 4, 92, 17, + 85, 83, 84, 79, 77, 69, 82, 32, 65, 67, 67, 79, 85, 78, 84, 32, 78, 243, + 201, 1, 72, 2, 159, 161, 6, 85, 4, 44, 5, 79, 85, 66, 76, 69, 147, 221, + 12, 65, 2, 11, 32, 2, 11, 66, 2, 157, 163, 7, 3, 65, 67, 75, 2, 191, 134, + 14, 79, 4, 160, 251, 8, 4, 65, 71, 79, 78, 197, 195, 3, 2, 79, 80, 60, + 48, 4, 72, 65, 77, 32, 185, 195, 14, 2, 79, 78, 58, 122, 70, 0, 10, 82, 69, 86, 69, 82, 83, 69, 68, 32, 70, 36, 7, 76, 69, 84, 84, 69, 82, 32, - 137, 253, 3, 3, 83, 80, 65, 2, 149, 138, 4, 4, 69, 65, 84, 72, 52, 196, + 149, 254, 3, 3, 83, 80, 65, 2, 161, 139, 4, 4, 69, 65, 84, 72, 52, 196, 1, 2, 65, 73, 22, 66, 2, 80, 34, 67, 36, 2, 69, 65, 64, 2, 70, 69, 22, - 71, 22, 73, 58, 76, 2, 82, 22, 78, 46, 79, 34, 83, 50, 85, 206, 184, 1, - 77, 170, 9, 68, 153, 210, 11, 3, 84, 73, 78, 2, 231, 159, 14, 76, 2, 11, - 69, 2, 143, 174, 12, 73, 4, 142, 147, 8, 69, 191, 149, 4, 79, 6, 138, 1, - 66, 2, 68, 169, 141, 4, 6, 77, 72, 65, 78, 67, 72, 2, 143, 165, 9, 65, 2, - 131, 168, 13, 79, 4, 32, 2, 79, 68, 139, 175, 13, 70, 2, 239, 132, 8, 72, - 2, 147, 139, 12, 85, 4, 236, 154, 13, 3, 71, 69, 65, 219, 67, 73, 4, 166, - 222, 13, 78, 227, 79, 82, 4, 146, 250, 11, 65, 233, 177, 1, 3, 84, 82, - 65, 6, 60, 5, 73, 76, 76, 69, 65, 234, 170, 12, 65, 147, 130, 2, 82, 2, - 151, 221, 13, 78, 2, 211, 131, 13, 82, 182, 8, 38, 32, 142, 11, 68, 199, - 164, 13, 73, 184, 1, 64, 6, 67, 72, 73, 75, 73, 32, 205, 6, 5, 79, 78, - 65, 76, 32, 96, 132, 1, 7, 76, 69, 84, 84, 69, 82, 32, 148, 3, 2, 77, 85, - 62, 71, 74, 80, 204, 215, 3, 2, 82, 69, 210, 221, 8, 68, 235, 170, 1, 65, - 60, 50, 65, 98, 69, 54, 73, 50, 76, 62, 79, 51, 85, 16, 50, 65, 154, 169, - 14, 78, 86, 71, 2, 76, 3, 84, 8, 234, 169, 14, 74, 2, 75, 2, 77, 3, 87, - 8, 158, 227, 13, 68, 198, 13, 82, 222, 56, 78, 3, 80, 8, 194, 151, 14, - 78, 202, 17, 72, 2, 82, 3, 83, 12, 214, 188, 8, 65, 134, 236, 5, 69, 2, - 73, 2, 79, 3, 85, 8, 242, 139, 14, 84, 174, 28, 66, 2, 72, 3, 86, 8, 142, - 216, 13, 78, 226, 79, 67, 2, 68, 3, 89, 4, 56, 2, 45, 71, 129, 190, 12, - 6, 32, 84, 84, 85, 68, 68, 2, 253, 189, 12, 13, 65, 65, 72, 76, 65, 65, - 32, 84, 84, 85, 68, 68, 65, 6, 84, 11, 85, 78, 67, 84, 85, 65, 84, 73, - 79, 78, 32, 129, 219, 6, 4, 72, 65, 65, 82, 4, 48, 8, 68, 79, 85, 66, 76, - 69, 32, 77, 3, 77, 2, 129, 223, 13, 3, 85, 67, 65, 88, 100, 7, 76, 69, - 84, 84, 69, 82, 32, 192, 2, 5, 83, 73, 71, 78, 32, 142, 183, 8, 65, 191, - 249, 3, 68, 60, 42, 65, 54, 69, 58, 73, 54, 79, 59, 85, 13, 250, 163, 14, - 66, 2, 68, 2, 72, 2, 76, 3, 87, 13, 230, 211, 13, 78, 226, 79, 67, 2, 71, - 2, 72, 3, 83, 13, 174, 195, 8, 84, 226, 223, 5, 68, 2, 78, 3, 80, 13, - 254, 233, 13, 82, 138, 56, 78, 86, 77, 2, 79, 3, 89, 13, 130, 220, 13, - 68, 218, 52, 78, 202, 17, 74, 2, 75, 3, 82, 6, 58, 73, 236, 228, 12, 4, - 72, 79, 68, 68, 219, 151, 1, 77, 2, 243, 181, 1, 75, 252, 6, 34, 32, 153, - 57, 3, 69, 82, 32, 246, 6, 240, 2, 8, 67, 72, 73, 78, 69, 83, 69, 32, 44, - 10, 72, 85, 78, 71, 65, 82, 73, 65, 78, 32, 244, 6, 7, 73, 84, 65, 76, - 73, 67, 32, 212, 4, 14, 78, 79, 82, 84, 72, 32, 65, 82, 65, 66, 73, 65, - 78, 32, 196, 4, 3, 80, 69, 82, 216, 13, 2, 83, 79, 144, 13, 14, 84, 85, - 82, 75, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 132, 7, 7, 85, 89, 71, - 72, 85, 82, 32, 219, 209, 11, 75, 4, 174, 251, 11, 73, 177, 95, 3, 72, - 79, 79, 216, 1, 96, 6, 67, 65, 80, 73, 84, 65, 0, 4, 83, 77, 65, 76, 221, - 5, 7, 78, 85, 77, 66, 69, 82, 32, 102, 45, 9, 76, 32, 76, 69, 84, 84, 69, - 82, 32, 102, 226, 1, 65, 54, 69, 164, 2, 10, 78, 73, 75, 79, 76, 83, 66, - 85, 82, 71, 0, 9, 82, 85, 68, 73, 77, 69, 78, 84, 65, 42, 79, 34, 85, - 192, 240, 3, 5, 67, 76, 79, 83, 69, 150, 157, 8, 73, 241, 203, 1, 6, 83, - 72, 79, 82, 84, 32, 11, 234, 222, 12, 77, 198, 117, 78, 162, 70, 65, 3, - 75, 63, 174, 1, 77, 22, 78, 78, 83, 134, 248, 9, 67, 86, 71, 2, 76, 2, - 84, 198, 152, 2, 90, 242, 134, 2, 66, 2, 68, 2, 69, 2, 70, 2, 72, 2, 74, - 2, 75, 2, 80, 2, 82, 3, 86, 5, 235, 152, 14, 80, 11, 34, 84, 182, 152, - 14, 67, 3, 89, 5, 189, 148, 2, 5, 45, 83, 72, 65, 80, 5, 139, 152, 14, - 90, 4, 11, 32, 4, 150, 129, 14, 79, 3, 85, 7, 250, 128, 14, 69, 215, 22, - 79, 9, 150, 148, 14, 78, 154, 3, 83, 3, 85, 12, 210, 4, 70, 222, 254, 5, - 79, 243, 191, 6, 84, 78, 80, 7, 76, 69, 84, 84, 69, 82, 32, 169, 3, 8, + 71, 22, 73, 58, 76, 2, 82, 22, 78, 46, 79, 34, 83, 46, 85, 222, 184, 1, + 77, 170, 9, 68, 189, 227, 11, 3, 84, 73, 78, 2, 155, 179, 14, 76, 2, 11, + 69, 2, 219, 190, 12, 73, 4, 226, 151, 8, 69, 183, 161, 4, 79, 6, 138, 1, + 66, 2, 68, 153, 143, 4, 6, 77, 72, 65, 78, 67, 72, 2, 247, 175, 9, 65, 2, + 183, 187, 13, 79, 4, 32, 2, 79, 68, 191, 194, 13, 70, 2, 195, 137, 8, 72, + 2, 243, 154, 12, 85, 4, 132, 172, 13, 3, 71, 69, 65, 247, 69, 73, 4, 218, + 241, 13, 78, 227, 79, 82, 4, 202, 225, 12, 65, 229, 93, 3, 84, 82, 65, 6, + 60, 5, 73, 76, 76, 69, 65, 186, 187, 12, 65, 251, 132, 2, 82, 2, 207, + 240, 13, 78, 2, 247, 148, 13, 82, 182, 8, 38, 32, 142, 11, 68, 255, 183, + 13, 73, 184, 1, 64, 6, 67, 72, 73, 75, 73, 32, 205, 6, 5, 79, 78, 65, 76, + 32, 96, 132, 1, 7, 76, 69, 84, 84, 69, 82, 32, 148, 3, 2, 77, 85, 62, 71, + 74, 80, 164, 216, 3, 2, 82, 69, 202, 237, 8, 68, 211, 173, 1, 65, 60, 50, + 65, 98, 69, 54, 73, 50, 76, 62, 79, 51, 85, 16, 50, 65, 210, 188, 14, 78, + 86, 71, 2, 76, 3, 84, 8, 162, 189, 14, 74, 2, 75, 2, 77, 3, 87, 8, 214, + 246, 13, 68, 198, 13, 82, 222, 56, 78, 3, 80, 8, 250, 170, 14, 78, 202, + 17, 72, 2, 82, 3, 83, 12, 162, 170, 10, 65, 242, 145, 4, 69, 2, 73, 2, + 79, 3, 85, 8, 170, 159, 14, 84, 174, 28, 66, 2, 72, 3, 86, 8, 198, 235, + 13, 78, 226, 79, 67, 2, 68, 3, 89, 4, 56, 2, 45, 71, 209, 206, 12, 6, 32, + 84, 84, 85, 68, 68, 2, 205, 206, 12, 13, 65, 65, 72, 76, 65, 65, 32, 84, + 84, 85, 68, 68, 65, 6, 84, 11, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, + 32, 177, 224, 6, 4, 72, 65, 65, 82, 4, 48, 8, 68, 79, 85, 66, 76, 69, 32, + 77, 3, 77, 2, 185, 242, 13, 3, 85, 67, 65, 88, 100, 7, 76, 69, 84, 84, + 69, 82, 32, 192, 2, 5, 83, 73, 71, 78, 32, 206, 193, 8, 65, 207, 255, 3, + 68, 60, 42, 65, 54, 69, 58, 73, 54, 79, 59, 85, 13, 178, 183, 14, 66, 2, + 68, 2, 72, 2, 76, 3, 87, 13, 158, 231, 13, 78, 226, 79, 67, 2, 71, 2, 72, + 3, 83, 13, 238, 205, 8, 84, 218, 232, 5, 68, 2, 78, 3, 80, 13, 182, 253, + 13, 82, 138, 56, 78, 86, 77, 2, 79, 3, 89, 13, 186, 239, 13, 68, 218, 52, + 78, 202, 17, 74, 2, 75, 3, 82, 6, 58, 73, 144, 246, 12, 4, 72, 79, 68, + 68, 239, 153, 1, 77, 2, 131, 182, 1, 75, 252, 6, 34, 32, 165, 57, 3, 69, + 82, 32, 246, 6, 240, 2, 8, 67, 72, 73, 78, 69, 83, 69, 32, 44, 10, 72, + 85, 78, 71, 65, 82, 73, 65, 78, 32, 128, 7, 7, 73, 84, 65, 76, 73, 67, + 32, 212, 4, 14, 78, 79, 82, 84, 72, 32, 65, 82, 65, 66, 73, 65, 78, 32, + 196, 4, 3, 80, 69, 82, 216, 13, 2, 83, 79, 144, 13, 14, 84, 85, 82, 75, + 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 132, 7, 7, 85, 89, 71, 72, 85, + 82, 32, 171, 225, 11, 75, 4, 146, 139, 12, 73, 241, 96, 3, 72, 79, 79, + 216, 1, 96, 6, 67, 65, 80, 73, 84, 65, 0, 4, 83, 77, 65, 76, 233, 5, 7, + 78, 85, 77, 66, 69, 82, 32, 102, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, + 32, 102, 214, 1, 65, 54, 69, 168, 2, 10, 78, 73, 75, 79, 76, 83, 66, 85, + 82, 71, 0, 9, 82, 85, 68, 73, 77, 69, 78, 84, 65, 42, 79, 32, 5, 83, 72, + 79, 82, 84, 22, 85, 168, 242, 3, 5, 67, 76, 79, 83, 69, 243, 171, 8, 73, + 11, 154, 240, 12, 77, 218, 119, 78, 162, 70, 65, 3, 75, 63, 178, 1, 77, + 22, 78, 78, 83, 182, 130, 10, 67, 254, 23, 71, 2, 76, 2, 84, 198, 135, 2, + 90, 218, 137, 2, 66, 2, 68, 2, 69, 2, 70, 2, 72, 2, 74, 2, 75, 2, 80, 2, + 82, 3, 86, 5, 171, 172, 14, 80, 11, 34, 84, 246, 171, 14, 67, 3, 89, 5, + 197, 149, 2, 5, 45, 83, 72, 65, 80, 5, 203, 171, 14, 90, 4, 11, 32, 4, + 214, 148, 14, 79, 3, 85, 7, 186, 148, 14, 69, 215, 22, 79, 2, 131, 237, + 13, 32, 9, 194, 167, 14, 78, 154, 3, 83, 3, 85, 12, 210, 4, 70, 242, 131, + 6, 79, 239, 203, 6, 84, 78, 80, 7, 76, 69, 84, 84, 69, 82, 32, 169, 3, 8, 78, 85, 77, 69, 82, 65, 76, 32, 70, 190, 1, 69, 90, 75, 50, 83, 36, 3, - 78, 79, 82, 242, 191, 10, 85, 206, 201, 1, 73, 190, 137, 1, 80, 2, 84, + 78, 79, 82, 202, 207, 10, 85, 186, 202, 1, 73, 166, 140, 1, 80, 2, 84, 150, 83, 67, 186, 22, 66, 2, 68, 2, 72, 2, 86, 2, 89, 2, 90, 214, 22, 65, - 3, 79, 23, 186, 244, 9, 83, 154, 153, 2, 82, 150, 201, 1, 75, 222, 61, - 70, 2, 76, 2, 77, 3, 78, 8, 150, 253, 13, 72, 214, 22, 65, 2, 69, 3, 85, - 4, 32, 2, 79, 85, 199, 252, 13, 72, 2, 29, 5, 84, 72, 69, 82, 78, 2, 233, - 137, 13, 2, 32, 84, 8, 38, 70, 206, 190, 12, 84, 191, 58, 79, 4, 11, 73, - 4, 174, 165, 12, 70, 167, 214, 1, 86, 64, 76, 7, 76, 69, 84, 84, 69, 82, + 3, 79, 23, 214, 254, 9, 83, 194, 159, 2, 82, 254, 203, 1, 75, 222, 61, + 70, 2, 76, 2, 77, 3, 78, 8, 194, 144, 14, 72, 214, 22, 65, 2, 69, 3, 85, + 4, 32, 2, 79, 85, 243, 143, 14, 72, 2, 29, 5, 84, 72, 69, 82, 78, 2, 253, + 154, 13, 2, 32, 84, 8, 38, 70, 222, 207, 12, 84, 215, 58, 79, 4, 11, 73, + 4, 242, 181, 12, 70, 143, 217, 1, 86, 64, 76, 7, 76, 69, 84, 84, 69, 82, 32, 209, 3, 7, 78, 85, 77, 66, 69, 82, 32, 58, 210, 1, 65, 38, 71, 38, - 72, 30, 75, 38, 84, 74, 90, 134, 107, 77, 208, 153, 3, 2, 69, 83, 226, - 161, 3, 66, 2, 70, 2, 82, 2, 89, 138, 193, 3, 78, 218, 235, 1, 76, 190, - 56, 68, 146, 1, 81, 134, 3, 87, 131, 56, 83, 4, 186, 193, 3, 76, 199, - 254, 9, 73, 4, 230, 226, 12, 72, 171, 154, 1, 69, 4, 134, 142, 14, 65, 3, - 69, 4, 250, 174, 7, 72, 223, 222, 5, 65, 8, 34, 72, 166, 141, 14, 65, 3, - 69, 4, 254, 132, 13, 65, 167, 136, 1, 69, 4, 11, 65, 4, 162, 190, 13, 73, - 227, 79, 72, 6, 154, 148, 6, 84, 159, 224, 6, 79, 180, 1, 64, 11, 77, 73, - 67, 32, 76, 69, 84, 84, 69, 82, 32, 183, 5, 83, 76, 228, 1, 2, 67, 72, - 22, 68, 66, 69, 22, 73, 30, 77, 2, 78, 30, 80, 22, 83, 70, 84, 50, 86, - 38, 89, 94, 90, 218, 190, 6, 76, 2, 82, 162, 222, 2, 71, 146, 165, 2, 79, - 142, 205, 1, 66, 246, 40, 65, 254, 31, 75, 174, 45, 72, 187, 2, 85, 2, - 139, 212, 7, 69, 6, 26, 90, 139, 247, 13, 79, 4, 174, 156, 9, 72, 231, - 201, 4, 73, 5, 187, 138, 14, 70, 7, 166, 138, 14, 65, 3, 69, 2, 169, 243, - 13, 2, 69, 78, 2, 223, 192, 6, 69, 6, 26, 72, 235, 245, 13, 73, 4, 140, - 155, 9, 3, 67, 72, 79, 3, 79, 4, 26, 83, 167, 245, 13, 65, 2, 147, 228, - 13, 73, 4, 182, 154, 9, 79, 215, 181, 4, 69, 14, 60, 2, 69, 82, 166, 168, - 8, 65, 154, 206, 5, 82, 203, 17, 85, 7, 130, 136, 14, 73, 3, 85, 4, 182, - 153, 9, 72, 231, 201, 4, 65, 104, 88, 4, 73, 65, 78, 32, 241, 5, 13, 79, + 72, 30, 75, 38, 84, 74, 90, 234, 106, 77, 140, 158, 3, 2, 69, 83, 238, + 162, 3, 66, 2, 70, 2, 82, 2, 89, 182, 203, 3, 78, 154, 237, 1, 76, 210, + 58, 68, 146, 1, 81, 134, 3, 87, 131, 56, 83, 4, 134, 194, 3, 76, 167, + 145, 10, 73, 4, 254, 243, 12, 72, 191, 156, 1, 69, 4, 178, 161, 14, 65, + 3, 69, 4, 166, 180, 7, 72, 223, 236, 5, 65, 8, 34, 72, 210, 160, 14, 65, + 3, 69, 4, 142, 150, 13, 65, 195, 138, 1, 69, 4, 11, 65, 4, 206, 209, 13, + 73, 227, 79, 72, 6, 190, 153, 6, 84, 163, 236, 6, 79, 180, 1, 64, 11, 77, + 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 183, 5, 83, 76, 228, 1, 2, 67, + 72, 22, 68, 66, 69, 22, 73, 30, 77, 2, 78, 30, 80, 22, 83, 70, 84, 50, + 86, 38, 89, 94, 90, 254, 195, 6, 76, 2, 82, 214, 227, 2, 71, 150, 170, 2, + 79, 222, 208, 1, 66, 246, 40, 65, 254, 31, 75, 174, 45, 72, 187, 2, 85, + 2, 215, 216, 7, 69, 6, 26, 90, 183, 138, 14, 79, 4, 134, 167, 9, 72, 187, + 210, 4, 73, 5, 231, 157, 14, 70, 7, 210, 157, 14, 65, 3, 69, 2, 213, 134, + 14, 2, 69, 78, 2, 131, 198, 6, 69, 6, 26, 72, 151, 137, 14, 73, 4, 228, + 165, 9, 3, 67, 72, 79, 3, 79, 4, 26, 83, 211, 136, 14, 65, 2, 191, 247, + 13, 73, 4, 142, 165, 9, 79, 171, 190, 4, 69, 14, 60, 2, 69, 82, 218, 178, + 8, 65, 146, 215, 5, 82, 203, 17, 85, 7, 174, 155, 14, 73, 3, 85, 4, 142, + 164, 9, 72, 187, 210, 4, 65, 104, 88, 4, 73, 65, 78, 32, 241, 5, 13, 79, 78, 65, 76, 32, 67, 79, 77, 80, 85, 84, 69, 82, 100, 80, 7, 78, 85, 77, - 66, 69, 82, 32, 80, 5, 83, 73, 71, 78, 32, 163, 207, 10, 87, 10, 42, 84, - 182, 178, 8, 72, 139, 186, 4, 79, 6, 142, 230, 1, 87, 251, 207, 11, 69, - 88, 210, 1, 65, 86, 66, 62, 68, 98, 74, 2, 86, 30, 84, 42, 88, 210, 111, - 71, 2, 75, 2, 78, 2, 82, 162, 190, 9, 77, 190, 139, 3, 83, 218, 69, 67, + 66, 69, 82, 32, 80, 5, 83, 73, 71, 78, 32, 251, 222, 10, 87, 10, 42, 84, + 234, 188, 8, 72, 255, 192, 4, 79, 6, 238, 230, 1, 87, 199, 226, 11, 69, + 88, 210, 1, 65, 86, 66, 62, 68, 98, 74, 2, 86, 30, 84, 42, 88, 182, 111, + 71, 2, 75, 2, 78, 2, 82, 150, 206, 9, 77, 146, 143, 3, 83, 218, 69, 67, 2, 70, 2, 72, 2, 76, 2, 80, 2, 89, 2, 90, 186, 2, 73, 3, 85, 9, 45, 9, - 85, 82, 65, 77, 65, 90, 68, 65, 65, 7, 146, 234, 6, 45, 247, 150, 7, 72, - 6, 38, 65, 253, 161, 10, 3, 85, 85, 77, 5, 187, 128, 14, 71, 10, 34, 65, - 190, 130, 14, 73, 3, 85, 7, 37, 7, 72, 89, 65, 65, 85, 83, 72, 5, 231, - 232, 6, 45, 4, 254, 129, 14, 65, 3, 73, 6, 170, 255, 13, 72, 186, 2, 65, - 3, 85, 4, 176, 204, 11, 8, 83, 72, 65, 65, 89, 65, 84, 72, 139, 181, 2, - 65, 5, 141, 142, 5, 31, 32, 87, 73, 84, 72, 32, 77, 79, 78, 73, 84, 79, + 85, 82, 65, 77, 65, 90, 68, 65, 65, 7, 170, 239, 6, 45, 139, 165, 7, 72, + 6, 38, 65, 213, 177, 10, 3, 85, 85, 77, 5, 231, 147, 14, 71, 10, 34, 65, + 234, 149, 14, 73, 3, 85, 7, 37, 7, 72, 89, 65, 65, 85, 83, 72, 5, 255, + 237, 6, 45, 4, 170, 149, 14, 65, 3, 73, 6, 214, 146, 14, 72, 186, 2, 65, + 3, 85, 4, 152, 220, 11, 8, 83, 72, 65, 65, 89, 65, 84, 72, 207, 184, 2, + 65, 5, 181, 147, 5, 31, 32, 87, 73, 84, 72, 32, 77, 79, 78, 73, 84, 79, 82, 32, 73, 78, 32, 80, 79, 82, 84, 82, 65, 73, 84, 32, 79, 82, 73, 69, 78, 144, 1, 92, 6, 71, 68, 73, 65, 78, 32, 141, 7, 12, 85, 84, 72, 32, 65, 82, 65, 66, 73, 65, 78, 32, 80, 58, 70, 74, 76, 145, 5, 7, 78, 85, - 77, 66, 69, 82, 32, 2, 11, 82, 2, 241, 221, 11, 10, 65, 67, 84, 73, 79, + 77, 66, 69, 82, 32, 2, 11, 82, 2, 201, 237, 11, 10, 65, 67, 84, 73, 79, 78, 32, 79, 78, 69, 60, 76, 6, 69, 84, 84, 69, 82, 32, 149, 4, 8, 73, 71, 65, 84, 85, 82, 69, 32, 58, 234, 1, 65, 96, 6, 70, 73, 78, 65, 76, 32, - 200, 1, 5, 82, 69, 83, 72, 45, 194, 215, 1, 76, 254, 165, 4, 71, 90, 90, - 34, 83, 66, 89, 158, 208, 1, 72, 234, 5, 75, 198, 75, 66, 178, 216, 4, - 78, 134, 2, 84, 2, 87, 218, 103, 80, 171, 4, 77, 6, 26, 76, 215, 251, 12, - 89, 4, 156, 128, 6, 8, 84, 69, 82, 78, 65, 84, 69, 32, 243, 214, 1, 69, - 18, 116, 3, 78, 85, 78, 0, 5, 83, 65, 68, 72, 69, 0, 3, 84, 65, 87, 222, - 215, 1, 65, 178, 201, 6, 66, 143, 194, 5, 72, 5, 41, 8, 32, 87, 73, 84, - 72, 32, 86, 69, 2, 241, 214, 5, 4, 82, 84, 73, 67, 2, 157, 215, 1, 6, 65, - 89, 73, 78, 45, 68, 18, 42, 84, 198, 254, 5, 79, 223, 137, 6, 70, 10, 42, - 72, 194, 216, 1, 87, 251, 207, 11, 69, 4, 222, 136, 12, 82, 159, 2, 73, + 200, 1, 5, 82, 69, 83, 72, 45, 162, 216, 1, 76, 194, 170, 4, 71, 90, 90, + 34, 83, 66, 89, 198, 207, 1, 72, 234, 5, 75, 174, 81, 66, 170, 225, 4, + 78, 134, 2, 84, 2, 87, 218, 103, 80, 171, 4, 77, 6, 26, 76, 131, 143, 13, + 89, 4, 192, 133, 6, 8, 84, 69, 82, 78, 65, 84, 69, 32, 155, 214, 1, 69, + 18, 116, 3, 78, 85, 78, 0, 5, 83, 65, 68, 72, 69, 0, 3, 84, 65, 87, 190, + 216, 1, 65, 134, 211, 6, 66, 135, 203, 5, 72, 5, 41, 8, 32, 87, 73, 84, + 72, 32, 86, 69, 2, 133, 220, 5, 4, 82, 84, 73, 67, 2, 253, 215, 1, 6, 65, + 89, 73, 78, 45, 68, 18, 42, 84, 234, 131, 6, 79, 255, 148, 6, 70, 10, 42, + 72, 162, 217, 1, 87, 199, 226, 11, 69, 4, 162, 153, 12, 82, 159, 2, 73, 64, 60, 7, 76, 69, 84, 84, 69, 82, 32, 245, 3, 3, 78, 85, 77, 58, 202, 1, - 65, 38, 68, 74, 71, 34, 75, 34, 83, 78, 84, 230, 43, 90, 182, 166, 1, 76, - 50, 81, 238, 205, 1, 82, 154, 217, 2, 89, 158, 208, 1, 72, 174, 81, 66, - 178, 216, 4, 78, 134, 2, 87, 218, 103, 70, 171, 4, 77, 4, 198, 167, 3, - 76, 199, 254, 9, 89, 6, 32, 2, 72, 65, 183, 211, 1, 65, 4, 194, 156, 8, - 76, 215, 171, 5, 68, 4, 238, 44, 72, 191, 204, 5, 73, 4, 198, 208, 7, 65, - 187, 75, 72, 8, 26, 65, 211, 244, 12, 72, 6, 142, 194, 7, 77, 138, 133, - 6, 68, 143, 45, 84, 8, 130, 91, 72, 226, 150, 11, 69, 243, 131, 1, 65, 6, - 56, 4, 66, 69, 82, 32, 229, 185, 13, 4, 69, 82, 73, 67, 4, 26, 70, 195, - 217, 12, 79, 2, 199, 132, 12, 73, 146, 1, 80, 7, 79, 82, 75, 72, 79, 78, + 65, 38, 68, 74, 71, 34, 75, 34, 83, 78, 84, 254, 43, 90, 254, 166, 1, 76, + 50, 81, 214, 205, 1, 82, 246, 221, 2, 89, 198, 207, 1, 72, 150, 87, 66, + 170, 225, 4, 78, 134, 2, 87, 218, 103, 70, 171, 4, 77, 4, 146, 168, 3, + 76, 167, 145, 10, 89, 6, 32, 2, 72, 65, 151, 212, 1, 65, 4, 246, 166, 8, + 76, 207, 180, 5, 68, 4, 134, 45, 72, 203, 209, 5, 73, 4, 146, 213, 7, 65, + 163, 81, 72, 8, 26, 65, 255, 135, 13, 72, 6, 218, 198, 7, 77, 234, 147, + 6, 68, 143, 45, 84, 8, 230, 90, 72, 194, 167, 11, 69, 219, 134, 1, 65, 6, + 56, 4, 66, 69, 82, 32, 145, 205, 13, 4, 69, 82, 73, 67, 4, 26, 70, 235, + 234, 12, 79, 2, 139, 149, 12, 73, 146, 1, 80, 7, 79, 82, 75, 72, 79, 78, 32, 197, 3, 8, 89, 69, 78, 73, 83, 69, 73, 32, 84, 54, 65, 202, 1, 69, - 122, 73, 30, 79, 195, 134, 12, 66, 45, 106, 69, 194, 208, 9, 83, 158, - 160, 4, 66, 2, 68, 2, 71, 2, 76, 2, 78, 2, 81, 2, 82, 2, 84, 3, 89, 20, - 218, 240, 13, 66, 2, 68, 2, 71, 2, 75, 2, 76, 2, 78, 2, 82, 2, 83, 2, 84, - 3, 89, 20, 74, 78, 138, 211, 13, 76, 158, 27, 83, 146, 1, 67, 2, 77, 2, - 80, 3, 90, 8, 178, 239, 13, 67, 2, 71, 2, 84, 3, 89, 7, 134, 239, 13, 67, - 3, 81, 13, 130, 3, 69, 234, 235, 13, 80, 2, 81, 3, 84, 62, 38, 65, 170, - 1, 69, 86, 73, 23, 79, 39, 98, 69, 162, 236, 13, 83, 62, 78, 86, 66, 2, - 68, 2, 71, 2, 76, 2, 81, 2, 82, 2, 84, 3, 89, 17, 150, 242, 11, 78, 154, - 251, 1, 66, 2, 71, 2, 75, 2, 84, 3, 89, 15, 46, 78, 174, 235, 13, 83, - 146, 1, 67, 3, 90, 6, 186, 236, 13, 67, 2, 84, 3, 89, 5, 151, 236, 13, - 81, 6, 26, 69, 235, 235, 13, 81, 5, 231, 235, 13, 75, 52, 148, 1, 10, 67, + 122, 73, 30, 79, 135, 151, 12, 66, 45, 106, 69, 170, 243, 9, 83, 226, + 144, 4, 66, 2, 68, 2, 71, 2, 76, 2, 78, 2, 81, 2, 82, 2, 84, 3, 89, 20, + 134, 132, 14, 66, 2, 68, 2, 71, 2, 75, 2, 76, 2, 78, 2, 82, 2, 83, 2, 84, + 3, 89, 20, 74, 78, 182, 230, 13, 76, 158, 27, 83, 146, 1, 67, 2, 77, 2, + 80, 3, 90, 8, 222, 130, 14, 67, 2, 71, 2, 84, 3, 89, 7, 178, 130, 14, 67, + 3, 81, 13, 130, 3, 69, 150, 255, 13, 80, 2, 81, 3, 84, 62, 38, 65, 170, + 1, 69, 86, 73, 23, 79, 39, 98, 69, 206, 255, 13, 83, 62, 78, 86, 66, 2, + 68, 2, 71, 2, 76, 2, 81, 2, 82, 2, 84, 3, 89, 17, 218, 130, 12, 78, 130, + 254, 1, 66, 2, 71, 2, 75, 2, 84, 3, 89, 15, 46, 78, 218, 254, 13, 83, + 146, 1, 67, 3, 90, 6, 230, 255, 13, 67, 2, 84, 3, 89, 5, 195, 255, 13, + 81, 6, 26, 69, 151, 255, 13, 81, 5, 147, 255, 13, 75, 52, 148, 1, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 36, 7, 76, 69, 84, 84, 69, 82, 32, - 233, 1, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 8, 186, 236, - 5, 84, 143, 227, 3, 68, 36, 134, 200, 1, 65, 210, 206, 1, 82, 130, 216, - 2, 76, 58, 90, 34, 83, 66, 89, 128, 211, 1, 6, 70, 73, 78, 65, 76, 32, 0, - 6, 71, 73, 77, 69, 76, 45, 134, 3, 75, 198, 75, 66, 178, 216, 4, 78, 134, - 2, 84, 2, 87, 218, 103, 80, 171, 4, 77, 8, 56, 4, 84, 87, 79, 32, 214, - 196, 11, 70, 235, 129, 1, 66, 4, 246, 210, 12, 66, 71, 68, 6, 130, 181, - 1, 87, 240, 154, 3, 3, 65, 68, 85, 231, 205, 7, 77, 22, 212, 1, 34, 32, + 233, 1, 12, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 8, 222, 241, + 5, 84, 243, 231, 3, 68, 36, 230, 200, 1, 65, 186, 206, 1, 82, 222, 220, + 2, 76, 58, 90, 34, 83, 66, 89, 168, 210, 1, 6, 70, 73, 78, 65, 76, 32, 0, + 6, 71, 73, 77, 69, 76, 45, 134, 3, 75, 174, 81, 66, 170, 225, 4, 78, 134, + 2, 84, 2, 87, 218, 103, 80, 171, 4, 77, 8, 56, 4, 84, 87, 79, 32, 174, + 212, 11, 70, 187, 131, 1, 66, 4, 158, 228, 12, 66, 75, 68, 6, 146, 181, + 1, 87, 136, 160, 3, 3, 65, 68, 85, 207, 217, 7, 77, 22, 212, 1, 34, 32, 87, 73, 84, 72, 32, 69, 88, 67, 76, 65, 77, 65, 84, 73, 79, 78, 32, 77, 65, 82, 75, 32, 87, 73, 84, 72, 32, 76, 69, 70, 84, 32, 82, 44, 7, 67, - 79, 77, 73, 78, 71, 32, 194, 1, 69, 235, 147, 13, 73, 2, 21, 3, 73, 71, - 72, 2, 243, 235, 9, 84, 10, 148, 1, 6, 65, 85, 84, 79, 77, 79, 20, 7, 70, - 73, 82, 69, 32, 69, 78, 192, 224, 2, 2, 84, 65, 148, 232, 8, 6, 80, 79, - 76, 73, 67, 69, 155, 21, 66, 2, 135, 191, 11, 66, 2, 175, 202, 12, 71, 8, - 70, 32, 205, 174, 12, 11, 45, 80, 73, 69, 67, 69, 32, 83, 87, 73, 77, 6, - 40, 4, 68, 79, 84, 32, 215, 157, 10, 66, 4, 26, 79, 175, 159, 10, 76, 2, - 177, 233, 2, 11, 86, 69, 82, 32, 84, 87, 79, 32, 68, 79, 84, 46, 82, 69, - 188, 6, 2, 84, 73, 248, 212, 11, 5, 72, 73, 85, 67, 72, 171, 180, 1, 80, + 79, 77, 73, 78, 71, 32, 194, 1, 69, 151, 167, 13, 73, 2, 21, 3, 73, 71, + 72, 2, 203, 250, 9, 84, 10, 148, 1, 6, 65, 85, 84, 79, 77, 79, 20, 7, 70, + 73, 82, 69, 32, 69, 78, 144, 225, 2, 2, 84, 65, 148, 247, 8, 6, 80, 79, + 76, 73, 67, 69, 143, 22, 66, 2, 223, 206, 11, 66, 2, 215, 219, 12, 71, 8, + 70, 32, 229, 191, 12, 11, 45, 80, 73, 69, 67, 69, 32, 83, 87, 73, 77, 6, + 40, 4, 68, 79, 84, 32, 175, 173, 10, 66, 4, 26, 79, 135, 175, 10, 76, 2, + 129, 234, 2, 11, 86, 69, 82, 32, 84, 87, 79, 32, 68, 79, 84, 46, 82, 69, + 188, 6, 2, 84, 73, 188, 229, 11, 5, 72, 73, 85, 67, 72, 147, 183, 1, 80, 36, 70, 78, 201, 5, 12, 82, 65, 84, 73, 78, 71, 32, 83, 89, 83, 84, 69, 34, 22, 32, 139, 4, 45, 28, 108, 2, 66, 79, 32, 7, 67, 69, 78, 84, 82, - 69, 32, 114, 70, 70, 72, 42, 77, 226, 133, 7, 83, 215, 233, 3, 76, 4, - 198, 220, 13, 79, 155, 3, 88, 8, 50, 84, 222, 200, 11, 66, 222, 2, 65, - 191, 82, 67, 2, 37, 7, 69, 65, 82, 68, 82, 79, 80, 2, 191, 202, 11, 45, - 4, 44, 5, 73, 76, 69, 32, 70, 239, 130, 2, 79, 2, 235, 130, 2, 79, 2, 17, - 2, 65, 78, 2, 191, 175, 10, 68, 4, 57, 12, 65, 73, 76, 66, 79, 88, 32, + 69, 32, 114, 70, 70, 72, 42, 77, 142, 139, 7, 83, 135, 244, 3, 76, 4, + 242, 239, 13, 79, 155, 3, 88, 8, 50, 84, 174, 216, 11, 66, 222, 2, 65, + 135, 84, 67, 2, 37, 7, 69, 65, 82, 68, 82, 79, 80, 2, 143, 218, 11, 45, + 4, 44, 5, 73, 76, 69, 32, 70, 243, 131, 2, 79, 2, 239, 131, 2, 79, 2, 17, + 2, 65, 78, 2, 151, 191, 10, 68, 4, 57, 12, 65, 73, 76, 66, 79, 88, 32, 87, 73, 84, 72, 32, 4, 44, 3, 76, 79, 87, 21, 4, 82, 65, 73, 83, 2, 17, - 2, 69, 82, 2, 189, 243, 11, 2, 69, 68, 6, 108, 15, 67, 73, 82, 67, 85, - 73, 84, 45, 79, 85, 84, 80, 85, 84, 32, 181, 187, 12, 6, 79, 85, 84, 76, - 73, 78, 4, 18, 72, 3, 76, 2, 173, 191, 1, 4, 45, 84, 89, 80, 2, 153, 205, - 12, 6, 77, 32, 67, 79, 77, 77, 6, 64, 2, 79, 78, 237, 177, 1, 8, 67, 65, - 76, 32, 68, 73, 83, 67, 2, 167, 192, 11, 32, 206, 1, 112, 3, 65, 78, 71, - 66, 73, 212, 8, 5, 78, 65, 84, 69, 32, 32, 3, 84, 72, 79, 202, 171, 5, - 32, 175, 158, 6, 67, 6, 28, 2, 69, 32, 135, 22, 85, 4, 174, 133, 12, 66, - 175, 76, 72, 188, 1, 48, 5, 71, 73, 78, 65, 76, 21, 3, 89, 65, 32, 2, - 203, 133, 1, 32, 186, 1, 106, 65, 30, 70, 250, 1, 73, 32, 7, 76, 69, 84, - 84, 69, 82, 32, 142, 2, 83, 218, 1, 86, 243, 223, 11, 68, 4, 246, 249, 9, - 73, 3, 85, 12, 41, 8, 82, 65, 67, 84, 73, 79, 78, 32, 12, 56, 4, 79, 78, - 69, 32, 81, 6, 84, 72, 82, 69, 69, 32, 8, 42, 83, 162, 210, 11, 69, 46, - 72, 47, 81, 2, 173, 211, 11, 4, 73, 88, 84, 69, 4, 26, 83, 183, 212, 11, - 81, 2, 245, 253, 7, 4, 73, 88, 84, 69, 2, 217, 179, 12, 3, 83, 83, 72, - 104, 226, 1, 82, 238, 232, 6, 89, 134, 144, 3, 65, 38, 68, 114, 84, 46, - 86, 186, 5, 85, 206, 201, 1, 73, 42, 76, 250, 192, 1, 78, 46, 83, 82, 66, - 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 87, 186, 2, 69, - 3, 79, 6, 214, 208, 13, 72, 2, 82, 187, 2, 65, 18, 112, 20, 69, 81, 85, - 69, 78, 67, 69, 32, 70, 79, 82, 32, 76, 69, 84, 84, 69, 82, 32, 82, 29, - 4, 73, 71, 78, 32, 4, 186, 207, 13, 72, 3, 82, 14, 150, 189, 9, 67, 98, - 78, 242, 60, 65, 142, 239, 1, 79, 219, 164, 1, 86, 26, 49, 10, 79, 87, - 69, 76, 32, 83, 73, 71, 78, 32, 26, 142, 253, 9, 65, 38, 85, 22, 86, 186, - 201, 1, 73, 222, 137, 2, 69, 3, 79, 4, 174, 215, 6, 76, 243, 30, 82, 4, - 224, 240, 3, 2, 68, 79, 155, 183, 2, 71, 226, 1, 76, 4, 65, 71, 69, 32, - 140, 4, 6, 77, 65, 78, 89, 65, 32, 231, 202, 13, 67, 144, 1, 56, 6, 67, - 65, 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 72, 45, 9, 76, 32, 76, 69, 84, - 84, 69, 82, 32, 72, 194, 1, 65, 38, 69, 90, 75, 42, 79, 22, 84, 226, 224, - 6, 72, 230, 239, 4, 67, 2, 68, 2, 71, 130, 179, 1, 83, 2, 90, 130, 3, 66, - 138, 66, 76, 2, 77, 2, 78, 2, 80, 2, 87, 186, 2, 73, 3, 85, 9, 182, 209, - 11, 73, 135, 251, 1, 72, 15, 26, 72, 159, 252, 12, 73, 10, 222, 191, 9, - 84, 222, 145, 2, 67, 138, 248, 1, 75, 3, 80, 6, 134, 201, 13, 72, 2, 89, - 187, 2, 65, 5, 183, 251, 12, 73, 6, 194, 131, 13, 83, 195, 71, 65, 80, - 52, 7, 76, 69, 84, 84, 69, 82, 32, 143, 217, 11, 68, 60, 246, 1, 65, 38, - 67, 22, 68, 38, 75, 34, 83, 30, 77, 242, 240, 2, 81, 206, 144, 8, 79, - 224, 123, 2, 76, 65, 208, 73, 2, 78, 85, 134, 2, 87, 142, 62, 69, 234, - 61, 66, 2, 70, 2, 71, 2, 72, 2, 74, 2, 82, 2, 84, 2, 88, 2, 89, 186, 2, - 73, 3, 85, 7, 142, 250, 2, 76, 167, 206, 10, 65, 2, 163, 202, 12, 65, 4, - 150, 187, 8, 69, 175, 138, 5, 72, 4, 166, 198, 12, 65, 251, 126, 72, 4, - 26, 72, 159, 199, 13, 65, 2, 199, 199, 12, 73, 124, 68, 11, 79, 77, 65, - 78, 32, 83, 73, 89, 65, 81, 32, 231, 141, 13, 69, 122, 172, 1, 17, 65, - 76, 84, 69, 82, 78, 65, 84, 69, 32, 78, 85, 77, 66, 69, 82, 32, 200, 1, - 13, 70, 82, 65, 67, 84, 73, 79, 78, 32, 79, 78, 69, 32, 48, 3, 77, 65, - 82, 47, 78, 26, 54, 70, 50, 83, 46, 84, 198, 170, 12, 78, 235, 110, 69, - 6, 236, 202, 5, 3, 79, 85, 82, 151, 253, 6, 73, 6, 188, 202, 5, 2, 73, - 88, 251, 137, 6, 69, 10, 170, 184, 2, 69, 12, 2, 87, 79, 131, 156, 9, 72, - 4, 26, 83, 131, 192, 11, 72, 2, 239, 192, 11, 73, 2, 11, 82, 2, 11, 65, - 2, 255, 248, 11, 84, 90, 33, 6, 85, 77, 66, 69, 82, 32, 90, 58, 69, 66, - 70, 94, 78, 26, 83, 78, 84, 183, 172, 5, 79, 10, 25, 4, 73, 71, 72, 84, - 11, 170, 182, 2, 89, 255, 183, 5, 32, 20, 18, 73, 35, 79, 10, 166, 2, 70, - 199, 171, 5, 86, 10, 134, 2, 82, 209, 171, 5, 2, 85, 82, 10, 65, 3, 73, - 78, 69, 20, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, 11, 166, 1, 84, 191, - 235, 7, 32, 24, 34, 72, 50, 87, 235, 179, 2, 69, 10, 34, 73, 249, 171, 5, - 2, 82, 69, 4, 51, 82, 10, 26, 69, 223, 171, 5, 79, 4, 11, 78, 4, 11, 84, - 4, 191, 179, 2, 89, 84, 34, 84, 161, 162, 11, 2, 78, 67, 82, 42, 66, 37, - 6, 76, 73, 78, 69, 68, 32, 2, 141, 178, 12, 4, 79, 88, 32, 84, 80, 92, 7, - 76, 65, 84, 73, 78, 32, 67, 222, 189, 6, 87, 146, 233, 4, 66, 246, 13, - 71, 159, 23, 68, 54, 130, 170, 7, 65, 143, 210, 4, 82, 12, 18, 72, 35, - 76, 2, 137, 172, 12, 3, 69, 65, 84, 10, 32, 2, 65, 80, 247, 162, 12, 73, - 9, 29, 5, 80, 73, 78, 71, 32, 6, 40, 6, 87, 72, 73, 84, 69, 32, 51, 66, - 4, 44, 5, 65, 78, 68, 32, 66, 223, 250, 9, 83, 2, 197, 250, 9, 4, 76, 65, - 67, 75, 146, 13, 210, 1, 65, 174, 65, 68, 30, 69, 134, 13, 72, 138, 25, - 73, 206, 4, 76, 148, 15, 2, 78, 80, 54, 79, 234, 8, 82, 208, 15, 15, 83, - 65, 76, 84, 69, 82, 32, 80, 65, 72, 76, 65, 86, 73, 32, 214, 5, 85, 183, - 159, 12, 77, 154, 6, 134, 2, 68, 38, 71, 212, 1, 11, 72, 65, 87, 72, 32, - 72, 77, 79, 78, 71, 32, 134, 23, 76, 130, 6, 78, 58, 82, 160, 22, 2, 83, - 83, 132, 2, 10, 85, 32, 67, 73, 78, 32, 72, 65, 85, 32, 180, 7, 3, 87, - 32, 80, 188, 241, 7, 2, 67, 75, 157, 133, 5, 4, 80, 69, 82, 67, 5, 237, - 184, 1, 4, 68, 73, 78, 71, 14, 26, 69, 219, 145, 13, 79, 13, 34, 32, 186, - 182, 13, 82, 3, 83, 6, 72, 6, 87, 73, 84, 72, 32, 67, 241, 153, 4, 6, 70, - 65, 67, 73, 78, 71, 4, 50, 85, 193, 226, 7, 6, 73, 82, 67, 76, 69, 68, 2, - 131, 172, 12, 82, 254, 1, 190, 1, 67, 160, 6, 9, 77, 65, 82, 75, 32, 67, - 73, 77, 32, 160, 1, 7, 78, 85, 77, 66, 69, 82, 32, 244, 1, 5, 83, 73, 71, - 78, 32, 144, 10, 7, 86, 79, 87, 69, 76, 32, 75, 255, 174, 11, 68, 78, 92, - 9, 76, 65, 78, 32, 83, 73, 71, 78, 32, 137, 3, 9, 79, 78, 83, 79, 78, 65, - 78, 84, 32, 38, 132, 1, 2, 72, 65, 38, 75, 46, 76, 34, 84, 82, 86, 30, - 89, 148, 9, 2, 88, 89, 172, 5, 2, 80, 72, 174, 1, 70, 165, 2, 2, 77, 85, - 4, 190, 197, 2, 87, 187, 236, 10, 77, 6, 246, 15, 72, 234, 130, 13, 79, - 159, 14, 87, 4, 210, 12, 65, 251, 230, 12, 73, 8, 22, 83, 247, 9, 72, 6, - 180, 196, 2, 3, 72, 69, 69, 214, 176, 9, 65, 3, 87, 4, 254, 195, 2, 65, - 3, 87, 4, 226, 195, 2, 65, 211, 166, 10, 69, 40, 122, 67, 38, 72, 46, 78, - 60, 2, 80, 76, 2, 81, 250, 221, 2, 76, 2, 77, 2, 82, 2, 86, 2, 88, 2, 89, - 147, 171, 10, 65, 4, 130, 223, 2, 72, 147, 171, 10, 65, 6, 222, 222, 2, - 76, 2, 78, 147, 171, 10, 65, 12, 58, 67, 22, 84, 230, 221, 2, 75, 2, 76, - 147, 171, 10, 65, 2, 247, 221, 2, 72, 4, 226, 221, 2, 72, 3, 83, 14, 42, - 75, 50, 83, 38, 84, 223, 155, 13, 72, 4, 26, 72, 159, 239, 12, 69, 2, - 251, 156, 6, 65, 4, 230, 241, 11, 85, 255, 186, 1, 79, 4, 218, 240, 11, - 85, 215, 18, 65, 14, 52, 7, 72, 85, 78, 68, 82, 69, 68, 38, 84, 79, 77, - 4, 108, 2, 32, 77, 251, 170, 13, 83, 8, 24, 2, 69, 78, 51, 82, 6, 26, 32, - 143, 171, 13, 83, 4, 18, 66, 35, 84, 2, 205, 208, 4, 3, 73, 76, 76, 2, - 11, 72, 2, 225, 235, 9, 3, 79, 85, 83, 72, 188, 1, 4, 67, 73, 77, 32, - 246, 2, 72, 32, 3, 73, 66, 32, 22, 77, 86, 78, 50, 84, 124, 4, 86, 79, - 83, 32, 198, 1, 88, 208, 1, 6, 90, 87, 74, 32, 84, 72, 238, 176, 1, 76, - 203, 223, 4, 65, 16, 174, 1, 67, 84, 5, 78, 82, 69, 83, 32, 22, 84, 240, - 234, 11, 7, 80, 85, 66, 32, 68, 65, 87, 133, 187, 1, 16, 72, 65, 73, 83, - 32, 76, 85, 83, 32, 78, 84, 79, 71, 32, 78, 84, 4, 48, 7, 85, 65, 77, 32, - 84, 83, 72, 255, 3, 72, 2, 11, 79, 2, 195, 186, 2, 79, 2, 163, 183, 1, - 84, 6, 52, 3, 88, 87, 86, 173, 135, 10, 4, 83, 79, 86, 32, 5, 157, 150, - 6, 4, 32, 67, 72, 87, 4, 158, 72, 78, 131, 202, 12, 76, 2, 219, 234, 11, - 89, 6, 40, 4, 69, 69, 74, 32, 191, 231, 12, 85, 4, 128, 3, 2, 84, 83, 57, - 2, 83, 85, 4, 26, 84, 207, 241, 8, 81, 2, 155, 184, 2, 85, 6, 196, 1, 7, - 88, 72, 69, 69, 74, 32, 67, 236, 167, 8, 12, 72, 73, 82, 68, 45, 83, 84, - 65, 71, 69, 32, 72, 167, 214, 4, 65, 14, 54, 70, 22, 83, 30, 84, 134, 69, - 76, 239, 240, 7, 78, 2, 223, 144, 13, 69, 2, 249, 146, 6, 2, 69, 69, 6, - 42, 72, 29, 6, 83, 72, 65, 66, 32, 67, 4, 82, 73, 135, 145, 13, 79, 2, - 239, 203, 5, 69, 14, 34, 73, 22, 89, 207, 155, 11, 65, 2, 247, 229, 11, - 65, 10, 40, 4, 69, 69, 77, 32, 171, 130, 13, 79, 8, 84, 3, 78, 84, 88, - 200, 144, 6, 2, 84, 79, 218, 167, 2, 82, 181, 172, 3, 2, 70, 65, 2, 199, - 144, 6, 73, 2, 247, 179, 2, 65, 56, 50, 65, 66, 69, 38, 73, 2, 85, 38, - 79, 39, 87, 20, 170, 1, 65, 2, 73, 2, 85, 2, 87, 190, 158, 13, 66, 3, 86, - 8, 106, 69, 190, 158, 13, 66, 3, 86, 8, 70, 65, 190, 158, 13, 66, 3, 86, - 8, 34, 79, 190, 158, 13, 66, 3, 86, 4, 186, 158, 13, 66, 3, 86, 76, 18, - 76, 23, 77, 2, 175, 224, 12, 65, 74, 74, 32, 104, 6, 89, 82, 69, 78, 69, - 32, 201, 136, 4, 4, 83, 32, 85, 80, 8, 80, 3, 66, 82, 65, 150, 173, 11, - 84, 172, 97, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, 175, 250, 12, 78, 64, - 80, 2, 76, 69, 40, 4, 82, 73, 71, 72, 253, 2, 7, 78, 85, 77, 66, 69, 82, - 32, 48, 38, 70, 89, 5, 84, 84, 69, 82, 32, 2, 57, 12, 84, 45, 80, 79, 73, - 78, 84, 73, 78, 71, 32, 70, 2, 177, 226, 5, 2, 76, 69, 46, 224, 1, 5, 70, - 73, 78, 65, 76, 30, 84, 246, 118, 68, 34, 76, 50, 81, 238, 205, 1, 82, - 178, 215, 2, 65, 50, 71, 90, 90, 34, 83, 66, 89, 158, 208, 1, 72, 234, 5, - 75, 198, 75, 66, 178, 216, 4, 78, 134, 2, 87, 218, 103, 80, 171, 4, 77, - 2, 217, 152, 12, 2, 32, 78, 4, 222, 150, 11, 69, 243, 131, 1, 65, 14, - 198, 120, 84, 226, 175, 10, 70, 251, 86, 79, 4, 32, 2, 67, 65, 203, 216, - 12, 68, 2, 131, 132, 12, 75, 184, 2, 94, 65, 220, 1, 11, 69, 78, 84, 72, - 69, 83, 73, 90, 69, 68, 32, 242, 16, 84, 131, 180, 12, 82, 14, 80, 5, 71, - 82, 65, 80, 72, 52, 5, 76, 76, 69, 76, 32, 137, 158, 6, 2, 67, 72, 6, - 198, 232, 9, 32, 194, 222, 1, 85, 207, 145, 1, 79, 6, 44, 5, 87, 73, 84, - 72, 32, 219, 246, 12, 84, 4, 150, 193, 6, 84, 131, 176, 4, 72, 150, 2, - 252, 1, 7, 72, 65, 78, 71, 85, 76, 32, 188, 4, 10, 73, 68, 69, 79, 71, - 82, 65, 80, 72, 32, 188, 7, 18, 75, 79, 82, 69, 65, 78, 32, 67, 72, 65, - 82, 65, 67, 84, 69, 82, 32, 79, 44, 7, 78, 85, 77, 66, 69, 82, 32, 202, - 201, 4, 68, 213, 169, 2, 2, 76, 65, 58, 102, 67, 110, 72, 30, 75, 66, 77, - 34, 78, 34, 80, 62, 82, 30, 83, 26, 84, 73, 5, 73, 69, 85, 78, 71, 10, - 34, 72, 33, 4, 73, 69, 85, 67, 4, 141, 3, 4, 73, 69, 85, 67, 7, 11, 32, - 4, 234, 145, 13, 65, 3, 85, 4, 197, 2, 3, 73, 69, 85, 8, 168, 2, 5, 72, - 73, 69, 85, 75, 13, 5, 73, 89, 69, 79, 75, 4, 245, 1, 4, 73, 69, 85, 77, - 4, 213, 1, 4, 73, 69, 85, 78, 8, 168, 1, 5, 72, 73, 69, 85, 80, 13, 4, - 73, 69, 85, 80, 4, 121, 4, 73, 69, 85, 76, 4, 93, 3, 73, 79, 83, 8, 56, - 5, 72, 73, 69, 85, 84, 13, 5, 73, 75, 69, 85, 84, 4, 11, 72, 5, 195, 140, - 13, 32, 72, 148, 1, 2, 65, 76, 30, 67, 74, 69, 82, 70, 112, 2, 76, 65, - 22, 77, 38, 78, 32, 2, 82, 69, 78, 83, 138, 2, 84, 50, 87, 158, 156, 11, - 72, 139, 82, 79, 2, 241, 133, 8, 2, 76, 73, 4, 32, 2, 79, 78, 211, 133, - 11, 65, 2, 185, 240, 7, 4, 71, 82, 65, 84, 6, 42, 78, 222, 163, 9, 65, - 163, 190, 3, 73, 2, 169, 4, 5, 84, 69, 82, 80, 82, 10, 58, 73, 160, 130, - 12, 5, 69, 83, 84, 73, 86, 239, 16, 79, 6, 208, 2, 3, 78, 65, 78, 186, - 242, 12, 82, 3, 86, 2, 195, 210, 12, 66, 4, 234, 182, 10, 69, 195, 132, - 2, 79, 4, 198, 241, 11, 73, 195, 1, 65, 8, 38, 83, 174, 250, 11, 80, 219, - 109, 65, 4, 134, 209, 6, 79, 167, 185, 6, 84, 18, 58, 69, 34, 79, 22, 80, - 34, 84, 50, 85, 167, 252, 11, 73, 4, 226, 181, 11, 86, 199, 82, 76, 2, - 243, 240, 7, 67, 2, 11, 69, 2, 179, 176, 4, 67, 4, 26, 85, 239, 216, 11, - 79, 2, 147, 247, 12, 68, 4, 26, 80, 175, 136, 13, 78, 2, 21, 3, 69, 82, - 86, 2, 135, 255, 11, 73, 6, 186, 152, 11, 72, 230, 159, 1, 69, 239, 48, - 87, 4, 246, 208, 9, 79, 227, 254, 1, 65, 4, 182, 153, 8, 32, 137, 158, 4, - 2, 74, 69, 22, 42, 69, 46, 70, 42, 78, 30, 83, 51, 84, 4, 216, 1, 3, 73, - 71, 72, 211, 240, 4, 76, 4, 160, 1, 2, 79, 85, 13, 2, 73, 70, 2, 133, 1, - 3, 73, 78, 69, 4, 34, 73, 73, 4, 69, 86, 69, 78, 2, 71, 88, 8, 34, 72, - 46, 87, 135, 181, 12, 69, 2, 11, 73, 2, 11, 82, 2, 131, 177, 11, 84, 4, - 11, 69, 4, 222, 151, 11, 78, 167, 112, 76, 18, 128, 1, 3, 73, 65, 76, - 216, 1, 3, 89, 32, 80, 168, 169, 8, 6, 78, 69, 82, 83, 72, 73, 169, 211, - 3, 6, 32, 65, 76, 84, 69, 82, 12, 62, 32, 193, 123, 10, 76, 89, 45, 82, - 69, 67, 89, 67, 76, 69, 10, 38, 68, 41, 5, 76, 73, 78, 69, 32, 2, 217, - 169, 4, 5, 73, 70, 70, 69, 82, 8, 222, 200, 3, 68, 226, 45, 70, 20, 4, - 66, 65, 67, 75, 199, 139, 9, 85, 2, 191, 237, 3, 79, 10, 98, 69, 52, 9, - 73, 86, 69, 45, 80, 85, 76, 76, 45, 89, 9, 80, 79, 82, 84, 32, 67, 79, - 78, 84, 4, 224, 226, 9, 4, 78, 71, 69, 82, 219, 138, 2, 68, 4, 40, 4, 68, - 79, 87, 78, 1, 2, 85, 80, 2, 185, 171, 5, 6, 45, 79, 85, 84, 80, 85, 2, - 231, 236, 11, 82, 114, 192, 1, 12, 71, 76, 79, 84, 84, 65, 76, 32, 83, - 84, 79, 80, 62, 76, 160, 3, 3, 82, 73, 83, 36, 14, 77, 73, 68, 45, 76, + 2, 69, 82, 2, 129, 132, 12, 2, 69, 68, 6, 108, 15, 67, 73, 82, 67, 85, + 73, 84, 45, 79, 85, 84, 80, 85, 84, 32, 221, 204, 12, 6, 79, 85, 84, 76, + 73, 78, 4, 18, 72, 3, 76, 2, 161, 192, 1, 4, 45, 84, 89, 80, 2, 169, 222, + 12, 6, 77, 32, 67, 79, 77, 77, 6, 64, 2, 79, 78, 253, 177, 1, 8, 67, 65, + 76, 32, 68, 73, 83, 67, 2, 247, 207, 11, 32, 208, 1, 104, 3, 65, 78, 71, + 66, 67, 34, 73, 212, 8, 5, 78, 65, 84, 69, 32, 32, 3, 84, 72, 79, 199, + 176, 5, 32, 6, 28, 2, 69, 32, 167, 22, 85, 4, 198, 150, 12, 66, 203, 78, + 72, 4, 186, 174, 13, 85, 223, 61, 65, 188, 1, 48, 5, 71, 73, 78, 65, 76, + 21, 3, 89, 65, 32, 2, 183, 133, 1, 32, 186, 1, 106, 65, 30, 70, 250, 1, + 73, 32, 7, 76, 69, 84, 84, 69, 82, 32, 142, 2, 83, 218, 1, 86, 159, 240, + 11, 68, 4, 182, 137, 10, 73, 3, 85, 12, 41, 8, 82, 65, 67, 84, 73, 79, + 78, 32, 12, 56, 4, 79, 78, 69, 32, 81, 6, 84, 72, 82, 69, 69, 32, 8, 42, + 83, 206, 226, 11, 69, 46, 72, 47, 81, 2, 217, 227, 11, 4, 73, 88, 84, 69, + 4, 26, 83, 227, 228, 11, 81, 2, 145, 136, 8, 4, 73, 88, 84, 69, 2, 233, + 196, 12, 3, 83, 83, 72, 104, 226, 1, 82, 130, 238, 6, 89, 178, 154, 3, + 65, 38, 68, 114, 84, 46, 86, 186, 5, 85, 186, 202, 1, 73, 42, 76, 226, + 195, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, + 72, 2, 77, 2, 87, 186, 2, 69, 3, 79, 6, 234, 227, 13, 72, 2, 82, 187, 2, + 65, 18, 112, 20, 69, 81, 85, 69, 78, 67, 69, 32, 70, 79, 82, 32, 76, 69, + 84, 84, 69, 82, 32, 82, 29, 4, 73, 71, 78, 32, 4, 206, 226, 13, 72, 3, + 82, 14, 138, 199, 9, 67, 98, 78, 190, 66, 65, 250, 239, 1, 79, 195, 167, + 1, 86, 26, 49, 10, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 26, 206, 140, + 10, 65, 38, 85, 22, 86, 166, 202, 1, 73, 198, 140, 2, 69, 3, 79, 4, 194, + 220, 6, 76, 243, 30, 82, 4, 240, 245, 3, 2, 68, 79, 139, 183, 2, 71, 226, + 1, 76, 4, 65, 71, 69, 32, 140, 4, 6, 77, 65, 78, 89, 65, 32, 251, 221, + 13, 67, 144, 1, 56, 6, 67, 65, 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 72, + 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, 32, 72, 194, 1, 65, 38, 69, 90, + 75, 42, 79, 22, 84, 246, 229, 6, 72, 254, 250, 4, 67, 2, 68, 2, 71, 234, + 181, 1, 83, 2, 90, 130, 3, 66, 138, 66, 76, 2, 77, 2, 78, 2, 80, 2, 87, + 186, 2, 73, 3, 85, 9, 226, 225, 11, 73, 239, 253, 1, 72, 15, 26, 72, 179, + 143, 13, 73, 10, 134, 202, 9, 84, 226, 151, 2, 67, 242, 250, 1, 75, 3, + 80, 6, 154, 220, 13, 72, 2, 89, 187, 2, 65, 5, 203, 142, 13, 73, 6, 214, + 150, 13, 83, 195, 71, 65, 80, 52, 7, 76, 69, 84, 84, 69, 82, 32, 187, + 233, 11, 68, 60, 246, 1, 65, 38, 67, 22, 68, 38, 75, 34, 83, 30, 77, 162, + 241, 2, 81, 226, 159, 8, 79, 148, 125, 2, 76, 65, 236, 75, 2, 78, 85, + 134, 2, 87, 142, 62, 69, 234, 61, 66, 2, 70, 2, 71, 2, 72, 2, 74, 2, 82, + 2, 84, 2, 88, 2, 89, 186, 2, 73, 3, 85, 7, 194, 250, 2, 76, 135, 225, 10, + 65, 2, 183, 221, 12, 65, 4, 222, 197, 8, 69, 251, 146, 5, 72, 4, 186, + 217, 12, 65, 251, 126, 72, 4, 26, 72, 179, 218, 13, 65, 2, 219, 218, 12, + 73, 124, 68, 11, 79, 77, 65, 78, 32, 83, 73, 89, 65, 81, 32, 251, 160, + 13, 69, 122, 172, 1, 17, 65, 76, 84, 69, 82, 78, 65, 84, 69, 32, 78, 85, + 77, 66, 69, 82, 32, 200, 1, 13, 70, 82, 65, 67, 84, 73, 79, 78, 32, 79, + 78, 69, 32, 48, 3, 77, 65, 82, 47, 78, 26, 54, 70, 50, 83, 46, 84, 214, + 187, 12, 78, 239, 112, 69, 6, 248, 207, 5, 3, 79, 85, 82, 159, 139, 7, + 73, 6, 200, 207, 5, 2, 73, 88, 155, 149, 6, 69, 10, 226, 184, 2, 69, 12, + 2, 87, 79, 247, 171, 9, 72, 4, 26, 83, 175, 208, 11, 72, 2, 155, 209, 11, + 73, 2, 11, 82, 2, 11, 65, 2, 247, 137, 12, 84, 90, 33, 6, 85, 77, 66, 69, + 82, 32, 90, 58, 69, 66, 70, 94, 78, 26, 83, 78, 84, 179, 177, 5, 79, 10, + 25, 4, 73, 71, 72, 84, 11, 226, 182, 2, 89, 227, 193, 5, 32, 20, 18, 73, + 35, 79, 10, 166, 2, 70, 195, 176, 5, 86, 10, 134, 2, 82, 205, 176, 5, 2, + 85, 82, 10, 65, 3, 73, 78, 69, 20, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, + 11, 166, 1, 84, 219, 245, 7, 32, 24, 34, 72, 50, 87, 163, 180, 2, 69, 10, + 34, 73, 245, 176, 5, 2, 82, 69, 4, 51, 82, 10, 26, 69, 219, 176, 5, 79, + 4, 11, 78, 4, 11, 84, 4, 247, 179, 2, 89, 84, 34, 84, 217, 177, 11, 2, + 78, 67, 82, 42, 66, 37, 6, 76, 73, 78, 69, 68, 32, 2, 133, 195, 12, 4, + 79, 88, 32, 84, 80, 92, 7, 76, 65, 84, 73, 78, 32, 67, 242, 194, 6, 87, + 182, 243, 4, 66, 234, 14, 71, 159, 23, 68, 54, 186, 174, 7, 65, 215, 222, + 4, 82, 12, 18, 72, 43, 76, 2, 17, 2, 69, 65, 2, 239, 188, 12, 84, 10, 32, + 2, 65, 80, 255, 179, 12, 73, 9, 29, 5, 80, 73, 78, 71, 32, 6, 40, 6, 87, + 72, 73, 84, 69, 32, 51, 66, 4, 44, 5, 65, 78, 68, 32, 66, 151, 138, 10, + 83, 2, 253, 137, 10, 4, 76, 65, 67, 75, 152, 13, 150, 1, 65, 206, 65, 68, + 30, 69, 134, 13, 72, 138, 25, 73, 202, 4, 76, 160, 15, 2, 78, 80, 54, 79, + 238, 8, 82, 210, 15, 83, 186, 6, 85, 239, 177, 12, 77, 158, 6, 134, 2, + 68, 38, 71, 212, 1, 11, 72, 65, 87, 72, 32, 72, 77, 79, 78, 71, 32, 134, + 23, 76, 130, 6, 78, 58, 82, 196, 22, 2, 83, 83, 132, 2, 10, 85, 32, 67, + 73, 78, 32, 72, 65, 85, 32, 176, 7, 3, 87, 32, 80, 152, 252, 7, 2, 67, + 75, 233, 141, 5, 4, 80, 69, 82, 67, 5, 253, 185, 1, 4, 68, 73, 78, 71, + 14, 26, 69, 163, 165, 13, 79, 13, 34, 32, 130, 202, 13, 82, 3, 83, 6, 72, + 6, 87, 73, 84, 72, 32, 67, 181, 159, 4, 6, 70, 65, 67, 73, 78, 71, 4, 50, + 85, 145, 237, 7, 6, 73, 82, 67, 76, 69, 68, 2, 175, 189, 12, 82, 254, 1, + 190, 1, 67, 160, 6, 9, 77, 65, 82, 75, 32, 67, 73, 77, 32, 160, 1, 7, 78, + 85, 77, 66, 69, 82, 32, 244, 1, 5, 83, 73, 71, 78, 32, 144, 10, 7, 86, + 79, 87, 69, 76, 32, 75, 223, 191, 11, 68, 78, 92, 9, 76, 65, 78, 32, 83, + 73, 71, 78, 32, 137, 3, 9, 79, 78, 83, 79, 78, 65, 78, 84, 32, 38, 132, + 1, 2, 72, 65, 38, 75, 46, 76, 34, 84, 82, 86, 30, 89, 148, 9, 2, 88, 89, + 172, 5, 2, 80, 72, 174, 1, 70, 165, 2, 2, 77, 85, 4, 170, 198, 2, 87, + 151, 255, 10, 77, 6, 246, 15, 72, 178, 150, 13, 79, 159, 14, 87, 4, 210, + 12, 65, 195, 250, 12, 73, 8, 22, 83, 247, 9, 72, 6, 160, 197, 2, 3, 72, + 69, 69, 158, 193, 9, 65, 3, 87, 4, 234, 196, 2, 65, 3, 87, 4, 206, 196, + 2, 65, 175, 185, 10, 69, 40, 122, 67, 38, 72, 46, 78, 60, 2, 80, 76, 2, + 81, 222, 222, 2, 76, 2, 77, 2, 82, 2, 86, 2, 88, 2, 89, 247, 189, 10, 65, + 4, 230, 223, 2, 72, 247, 189, 10, 65, 6, 194, 223, 2, 76, 2, 78, 247, + 189, 10, 65, 12, 58, 67, 22, 84, 202, 222, 2, 75, 2, 76, 247, 189, 10, + 65, 2, 219, 222, 2, 72, 4, 198, 222, 2, 72, 3, 83, 14, 42, 75, 50, 83, + 38, 84, 167, 175, 13, 72, 4, 26, 72, 231, 130, 13, 69, 2, 175, 162, 6, + 65, 4, 154, 131, 12, 85, 147, 189, 1, 79, 4, 142, 130, 12, 85, 215, 18, + 65, 14, 52, 7, 72, 85, 78, 68, 82, 69, 68, 38, 84, 79, 77, 4, 108, 2, 32, + 77, 195, 190, 13, 83, 8, 24, 2, 69, 78, 51, 82, 6, 26, 32, 215, 190, 13, + 83, 4, 18, 66, 35, 84, 2, 253, 213, 4, 3, 73, 76, 76, 2, 11, 72, 2, 213, + 251, 9, 3, 79, 85, 83, 72, 188, 1, 4, 67, 73, 77, 32, 246, 2, 72, 32, 3, + 73, 66, 32, 22, 77, 86, 78, 50, 84, 124, 4, 86, 79, 83, 32, 198, 1, 88, + 208, 1, 6, 90, 87, 74, 32, 84, 72, 142, 178, 1, 76, 223, 227, 4, 65, 16, + 174, 1, 67, 84, 5, 78, 82, 69, 83, 32, 22, 84, 164, 252, 11, 7, 80, 85, + 66, 32, 68, 65, 87, 153, 189, 1, 16, 72, 65, 73, 83, 32, 76, 85, 83, 32, + 78, 84, 79, 71, 32, 78, 84, 4, 48, 7, 85, 65, 77, 32, 84, 83, 72, 255, 3, + 72, 2, 11, 79, 2, 175, 187, 2, 79, 2, 195, 184, 1, 84, 6, 52, 3, 88, 87, + 86, 161, 151, 10, 4, 83, 79, 86, 32, 5, 209, 155, 6, 4, 32, 67, 72, 87, + 4, 190, 72, 78, 171, 221, 12, 76, 2, 143, 252, 11, 89, 6, 40, 4, 69, 69, + 74, 32, 135, 251, 12, 85, 4, 128, 3, 2, 84, 83, 57, 2, 83, 85, 4, 26, 84, + 187, 252, 8, 81, 2, 135, 185, 2, 85, 6, 196, 1, 7, 88, 72, 69, 69, 74, + 32, 67, 224, 178, 8, 12, 72, 73, 82, 68, 45, 83, 84, 65, 71, 69, 32, 72, + 251, 222, 4, 65, 14, 54, 70, 22, 83, 30, 84, 166, 69, 76, 195, 251, 7, + 78, 2, 167, 164, 13, 69, 2, 173, 152, 6, 2, 69, 69, 6, 42, 72, 29, 6, 83, + 72, 65, 66, 32, 67, 4, 82, 73, 207, 164, 13, 79, 2, 175, 209, 5, 69, 14, + 34, 73, 22, 89, 175, 172, 11, 65, 2, 171, 247, 11, 65, 10, 40, 4, 69, 69, + 77, 32, 243, 149, 13, 79, 8, 84, 3, 78, 84, 88, 252, 149, 6, 2, 84, 79, + 154, 173, 2, 82, 245, 178, 3, 2, 70, 65, 2, 251, 149, 6, 73, 2, 227, 180, + 2, 65, 56, 50, 65, 66, 69, 38, 73, 2, 85, 38, 79, 39, 87, 20, 170, 1, 65, + 2, 73, 2, 85, 2, 87, 134, 178, 13, 66, 3, 86, 8, 106, 69, 134, 178, 13, + 66, 3, 86, 8, 70, 65, 134, 178, 13, 66, 3, 86, 8, 34, 79, 134, 178, 13, + 66, 3, 86, 4, 130, 178, 13, 66, 3, 86, 76, 18, 76, 23, 77, 2, 247, 243, + 12, 65, 74, 74, 32, 104, 6, 89, 82, 69, 78, 69, 32, 141, 142, 4, 4, 83, + 32, 85, 80, 8, 80, 3, 66, 82, 65, 246, 189, 11, 84, 248, 97, 4, 68, 79, + 87, 78, 1, 2, 85, 80, 2, 247, 141, 13, 78, 64, 80, 2, 76, 69, 40, 4, 82, + 73, 71, 72, 253, 2, 7, 78, 85, 77, 66, 69, 82, 32, 48, 38, 70, 89, 5, 84, + 84, 69, 82, 32, 2, 57, 12, 84, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, + 70, 2, 229, 231, 5, 2, 76, 69, 46, 224, 1, 5, 70, 73, 78, 65, 76, 30, 84, + 242, 119, 68, 34, 76, 50, 81, 214, 205, 1, 82, 142, 220, 2, 65, 50, 71, + 90, 90, 34, 83, 66, 89, 198, 207, 1, 72, 234, 5, 75, 174, 81, 66, 170, + 225, 4, 78, 134, 2, 87, 218, 103, 80, 171, 4, 77, 2, 161, 172, 12, 2, 32, + 78, 4, 190, 167, 11, 69, 219, 134, 1, 65, 14, 194, 121, 84, 198, 191, 10, + 70, 223, 87, 79, 4, 32, 2, 67, 65, 147, 236, 12, 68, 2, 191, 149, 12, 75, + 188, 2, 94, 65, 220, 1, 11, 69, 78, 84, 72, 69, 83, 73, 90, 69, 68, 32, + 242, 16, 84, 203, 199, 12, 82, 14, 80, 5, 71, 82, 65, 80, 72, 52, 5, 76, + 76, 69, 76, 32, 209, 163, 6, 2, 67, 72, 6, 186, 248, 9, 32, 250, 223, 1, + 85, 235, 147, 1, 79, 6, 44, 5, 87, 73, 84, 72, 32, 163, 138, 13, 84, 4, + 222, 198, 6, 84, 175, 186, 4, 72, 150, 2, 252, 1, 7, 72, 65, 78, 71, 85, + 76, 32, 188, 4, 10, 73, 68, 69, 79, 71, 82, 65, 80, 72, 32, 188, 7, 18, + 75, 79, 82, 69, 65, 78, 32, 67, 72, 65, 82, 65, 67, 84, 69, 82, 32, 79, + 44, 7, 78, 85, 77, 66, 69, 82, 32, 250, 206, 4, 68, 145, 169, 2, 2, 76, + 65, 58, 102, 67, 110, 72, 30, 75, 66, 77, 34, 78, 34, 80, 62, 82, 30, 83, + 26, 84, 73, 5, 73, 69, 85, 78, 71, 10, 34, 72, 33, 4, 73, 69, 85, 67, 4, + 141, 3, 4, 73, 69, 85, 67, 7, 11, 32, 4, 178, 165, 13, 65, 3, 85, 4, 197, + 2, 3, 73, 69, 85, 8, 168, 2, 5, 72, 73, 69, 85, 75, 13, 5, 73, 89, 69, + 79, 75, 4, 245, 1, 4, 73, 69, 85, 77, 4, 213, 1, 4, 73, 69, 85, 78, 8, + 168, 1, 5, 72, 73, 69, 85, 80, 13, 4, 73, 69, 85, 80, 4, 121, 4, 73, 69, + 85, 76, 4, 93, 3, 73, 79, 83, 8, 56, 5, 72, 73, 69, 85, 84, 13, 5, 73, + 75, 69, 85, 84, 4, 11, 72, 5, 139, 160, 13, 32, 72, 148, 1, 2, 65, 76, + 30, 67, 74, 69, 82, 70, 112, 2, 76, 65, 22, 77, 38, 78, 32, 2, 82, 69, + 78, 83, 138, 2, 84, 50, 87, 254, 172, 11, 72, 239, 82, 79, 2, 237, 144, + 8, 2, 76, 73, 4, 32, 2, 79, 78, 179, 150, 11, 65, 2, 181, 251, 7, 4, 71, + 82, 65, 84, 6, 42, 78, 174, 179, 9, 65, 155, 194, 3, 73, 2, 169, 4, 5, + 84, 69, 82, 80, 82, 10, 58, 73, 204, 147, 12, 5, 69, 83, 84, 73, 86, 139, + 19, 79, 6, 208, 2, 3, 78, 65, 78, 130, 134, 13, 82, 3, 86, 2, 139, 230, + 12, 66, 4, 226, 198, 10, 69, 147, 136, 2, 79, 4, 138, 131, 12, 73, 195, + 1, 65, 8, 38, 83, 218, 139, 12, 80, 247, 111, 65, 4, 190, 214, 6, 79, + 183, 199, 6, 84, 18, 58, 69, 34, 79, 22, 80, 34, 84, 50, 85, 211, 141, + 12, 73, 4, 142, 199, 11, 86, 227, 84, 76, 2, 239, 251, 7, 67, 2, 11, 69, + 2, 227, 181, 4, 67, 4, 26, 85, 163, 234, 11, 79, 2, 219, 138, 13, 68, 4, + 26, 80, 247, 155, 13, 78, 2, 21, 3, 69, 82, 86, 2, 183, 144, 12, 73, 6, + 154, 169, 11, 72, 206, 162, 1, 69, 239, 48, 87, 4, 234, 224, 9, 79, 163, + 128, 2, 65, 4, 170, 164, 8, 32, 221, 166, 4, 2, 74, 69, 22, 42, 69, 46, + 70, 42, 78, 30, 83, 51, 84, 4, 216, 1, 3, 73, 71, 72, 131, 246, 4, 76, 4, + 160, 1, 2, 79, 85, 13, 2, 73, 70, 2, 133, 1, 3, 73, 78, 69, 4, 34, 73, + 73, 4, 69, 86, 69, 78, 2, 71, 88, 8, 34, 72, 46, 87, 207, 200, 12, 69, 2, + 11, 73, 2, 11, 82, 2, 175, 194, 11, 84, 4, 11, 69, 4, 190, 168, 11, 78, + 143, 115, 76, 22, 164, 1, 3, 73, 65, 76, 216, 1, 3, 89, 32, 80, 224, 206, + 6, 5, 72, 69, 78, 79, 80, 180, 229, 1, 6, 78, 69, 82, 83, 72, 73, 225, + 219, 3, 6, 32, 65, 76, 84, 69, 82, 12, 62, 32, 173, 124, 10, 76, 89, 45, + 82, 69, 67, 89, 67, 76, 69, 10, 38, 68, 41, 5, 76, 73, 78, 69, 32, 2, + 229, 174, 4, 5, 73, 70, 70, 69, 82, 8, 254, 205, 3, 68, 226, 45, 70, 20, + 4, 66, 65, 67, 75, 203, 153, 9, 85, 2, 223, 242, 3, 79, 10, 98, 69, 52, + 9, 73, 86, 69, 45, 80, 85, 76, 76, 45, 89, 9, 80, 79, 82, 84, 32, 67, 79, + 78, 84, 4, 176, 242, 9, 4, 78, 71, 69, 82, 147, 140, 2, 68, 4, 40, 4, 68, + 79, 87, 78, 1, 2, 85, 80, 2, 213, 176, 5, 6, 45, 79, 85, 84, 80, 85, 2, + 239, 253, 11, 82, 114, 192, 1, 12, 71, 76, 79, 84, 84, 65, 76, 32, 83, + 84, 79, 80, 62, 76, 156, 3, 3, 82, 73, 83, 36, 14, 77, 73, 68, 45, 76, 69, 86, 69, 76, 32, 84, 79, 78, 69, 57, 7, 83, 65, 78, 68, 72, 73, 32, 7, - 11, 32, 4, 206, 5, 70, 201, 238, 11, 4, 86, 65, 82, 73, 82, 72, 6, 69, - 84, 84, 69, 82, 32, 213, 2, 7, 79, 87, 45, 70, 65, 76, 76, 74, 206, 1, - 70, 166, 143, 7, 73, 2, 85, 214, 250, 1, 78, 242, 169, 3, 67, 2, 75, 2, - 80, 2, 84, 138, 69, 66, 2, 68, 2, 71, 2, 72, 2, 76, 2, 77, 2, 82, 2, 83, - 2, 86, 2, 90, 186, 2, 65, 2, 69, 3, 79, 20, 44, 5, 73, 78, 65, 76, 32, - 251, 250, 12, 65, 18, 222, 255, 10, 78, 154, 251, 1, 75, 2, 76, 2, 77, 2, - 80, 2, 84, 2, 87, 3, 89, 8, 157, 1, 5, 73, 78, 71, 32, 84, 7, 11, 32, 4, - 192, 1, 5, 76, 79, 78, 71, 32, 15, 70, 12, 66, 84, 73, 12, 71, 76, 79, - 84, 84, 65, 76, 32, 83, 84, 79, 80, 8, 21, 3, 79, 78, 69, 9, 11, 32, 6, - 32, 4, 76, 79, 78, 71, 27, 70, 5, 11, 32, 2, 11, 70, 2, 223, 195, 3, 73, - 2, 155, 176, 4, 82, 4, 250, 247, 12, 70, 3, 73, 80, 130, 1, 65, 122, 78, - 162, 1, 82, 162, 9, 83, 44, 3, 84, 82, 73, 130, 17, 68, 245, 136, 12, 9, - 79, 80, 76, 69, 32, 72, 85, 71, 71, 12, 50, 67, 50, 78, 190, 234, 6, 32, - 191, 139, 6, 82, 6, 182, 198, 11, 79, 202, 28, 69, 171, 147, 1, 72, 2, - 203, 225, 11, 85, 10, 118, 71, 20, 3, 83, 73, 86, 222, 178, 1, 84, 132, - 184, 4, 10, 32, 79, 86, 69, 82, 32, 83, 84, 65, 77, 167, 214, 4, 67, 2, - 151, 245, 11, 85, 2, 183, 183, 12, 69, 48, 186, 1, 32, 116, 10, 80, 69, - 78, 68, 73, 67, 85, 76, 65, 82, 42, 83, 210, 165, 7, 67, 252, 9, 10, 77, - 65, 78, 69, 78, 84, 32, 80, 65, 80, 201, 128, 2, 8, 70, 79, 82, 77, 73, - 78, 71, 32, 6, 34, 77, 30, 84, 227, 235, 11, 83, 2, 181, 241, 1, 2, 73, - 76, 2, 213, 137, 11, 8, 69, 78, 32, 84, 72, 79, 85, 83, 5, 129, 253, 8, - 5, 32, 87, 73, 84, 72, 32, 60, 2, 79, 78, 178, 75, 80, 221, 157, 11, 4, - 69, 86, 69, 82, 28, 38, 32, 149, 246, 9, 3, 65, 76, 32, 26, 216, 2, 10, - 68, 79, 73, 78, 71, 32, 67, 65, 82, 84, 32, 3, 73, 78, 32, 92, 5, 87, 73, - 84, 72, 32, 220, 213, 7, 4, 70, 82, 79, 87, 204, 13, 27, 82, 65, 73, 83, - 73, 78, 71, 32, 66, 79, 84, 72, 32, 72, 65, 78, 68, 83, 32, 73, 78, 32, - 67, 69, 76, 69, 66, 128, 185, 4, 5, 67, 76, 73, 77, 66, 213, 45, 11, 66, - 79, 87, 73, 78, 71, 32, 68, 69, 69, 80, 2, 11, 87, 2, 251, 183, 3, 72, 4, - 164, 156, 12, 6, 76, 79, 84, 85, 83, 32, 253, 64, 9, 83, 84, 69, 65, 77, - 89, 32, 82, 79, 12, 154, 1, 66, 240, 145, 2, 3, 80, 79, 85, 220, 160, 1, - 2, 67, 82, 196, 250, 5, 6, 70, 79, 76, 68, 69, 68, 221, 189, 2, 8, 72, - 69, 65, 68, 83, 67, 65, 82, 4, 36, 3, 76, 79, 78, 171, 228, 10, 65, 2, - 11, 68, 2, 11, 32, 2, 11, 72, 2, 11, 65, 2, 219, 178, 12, 73, 4, 224, - 153, 9, 2, 69, 84, 195, 202, 2, 79, 2, 253, 137, 9, 2, 32, 68, 140, 2, + 11, 32, 4, 202, 5, 70, 213, 255, 11, 4, 86, 65, 82, 73, 82, 72, 6, 69, + 84, 84, 69, 82, 32, 209, 2, 7, 79, 87, 45, 70, 65, 76, 76, 74, 202, 1, + 70, 226, 252, 8, 73, 2, 85, 238, 27, 78, 198, 174, 3, 67, 2, 75, 2, 80, + 2, 84, 138, 69, 66, 2, 68, 2, 71, 2, 72, 2, 76, 2, 77, 2, 82, 2, 83, 2, + 86, 2, 90, 186, 2, 65, 2, 69, 3, 79, 20, 44, 5, 73, 78, 65, 76, 32, 163, + 142, 13, 65, 18, 158, 144, 11, 78, 130, 254, 1, 75, 2, 76, 2, 77, 2, 80, + 2, 84, 2, 87, 3, 89, 8, 157, 1, 5, 73, 78, 71, 32, 84, 7, 11, 32, 4, 192, + 1, 5, 76, 79, 78, 71, 32, 15, 70, 12, 66, 84, 73, 12, 71, 76, 79, 84, 84, + 65, 76, 32, 83, 84, 79, 80, 8, 21, 3, 79, 78, 69, 9, 11, 32, 6, 32, 4, + 76, 79, 78, 71, 27, 70, 5, 11, 32, 2, 11, 70, 2, 131, 201, 3, 73, 2, 171, + 181, 4, 82, 4, 162, 139, 13, 70, 3, 73, 80, 130, 1, 65, 122, 78, 162, 1, + 82, 162, 9, 83, 44, 3, 84, 82, 73, 130, 17, 68, 157, 156, 12, 9, 79, 80, + 76, 69, 32, 72, 85, 71, 71, 12, 50, 67, 50, 78, 138, 239, 6, 32, 155, + 154, 6, 82, 6, 202, 215, 11, 79, 194, 28, 69, 199, 149, 1, 72, 2, 227, + 128, 12, 85, 10, 118, 71, 20, 3, 83, 73, 86, 222, 179, 1, 84, 156, 188, + 4, 10, 32, 79, 86, 69, 82, 32, 83, 84, 65, 77, 187, 184, 5, 67, 2, 191, + 136, 12, 85, 2, 223, 202, 12, 69, 48, 186, 1, 32, 116, 10, 80, 69, 78, + 68, 73, 67, 85, 76, 65, 82, 42, 83, 130, 176, 7, 67, 252, 9, 10, 77, 65, + 78, 69, 78, 84, 32, 80, 65, 80, 237, 133, 2, 8, 70, 79, 82, 77, 73, 78, + 71, 32, 6, 34, 77, 30, 84, 139, 255, 11, 83, 2, 129, 242, 1, 2, 73, 76, + 2, 149, 154, 11, 8, 69, 78, 32, 84, 72, 79, 85, 83, 5, 213, 139, 9, 5, + 32, 87, 73, 84, 72, 32, 60, 2, 79, 78, 154, 75, 80, 157, 177, 11, 4, 69, + 86, 69, 82, 28, 38, 32, 237, 133, 10, 3, 65, 76, 32, 26, 216, 2, 10, 68, + 79, 73, 78, 71, 32, 67, 65, 82, 84, 32, 3, 73, 78, 32, 92, 5, 87, 73, 84, + 72, 32, 184, 224, 7, 4, 70, 82, 79, 87, 204, 13, 27, 82, 65, 73, 83, 73, + 78, 71, 32, 66, 79, 84, 72, 32, 72, 65, 78, 68, 83, 32, 73, 78, 32, 67, + 69, 76, 69, 66, 204, 193, 4, 5, 67, 76, 73, 77, 66, 213, 45, 11, 66, 79, + 87, 73, 78, 71, 32, 68, 69, 69, 80, 2, 11, 87, 2, 159, 189, 3, 72, 4, + 204, 175, 12, 6, 76, 79, 84, 85, 83, 32, 253, 64, 9, 83, 84, 69, 65, 77, + 89, 32, 82, 79, 12, 154, 1, 66, 180, 146, 2, 3, 80, 79, 85, 188, 165, 1, + 2, 67, 82, 244, 132, 6, 6, 70, 79, 76, 68, 69, 68, 177, 193, 2, 8, 72, + 69, 65, 68, 83, 67, 65, 82, 4, 36, 3, 76, 79, 78, 235, 244, 10, 65, 2, + 11, 68, 2, 11, 32, 2, 11, 72, 2, 11, 65, 2, 131, 198, 12, 73, 4, 180, + 169, 9, 2, 69, 84, 151, 206, 2, 79, 2, 209, 153, 9, 2, 32, 68, 140, 2, 66, 65, 184, 19, 9, 73, 76, 73, 80, 80, 73, 78, 69, 32, 47, 79, 204, 1, 108, 6, 71, 83, 45, 80, 65, 32, 189, 7, 16, 73, 83, 84, 79, 83, 32, 68, 73, 83, 67, 32, 83, 73, 71, 78, 32, 112, 100, 7, 76, 69, 84, 84, 69, 82, 32, 248, 4, 5, 77, 65, 82, 75, 32, 30, 83, 33, 4, 68, 79, 85, 66, 96, - 138, 2, 65, 138, 1, 67, 50, 68, 42, 83, 64, 5, 86, 79, 73, 67, 69, 222, - 242, 8, 71, 246, 168, 3, 78, 82, 84, 46, 75, 2, 80, 2, 90, 162, 7, 69, + 138, 2, 65, 138, 1, 67, 50, 68, 42, 83, 64, 5, 86, 79, 73, 67, 69, 178, + 129, 9, 71, 202, 173, 3, 78, 82, 84, 46, 75, 2, 80, 2, 90, 162, 7, 69, 234, 61, 66, 2, 70, 2, 72, 2, 74, 2, 76, 2, 77, 2, 81, 2, 82, 2, 87, 2, 88, 2, 89, 186, 2, 73, 2, 79, 3, 85, 7, 80, 8, 76, 84, 69, 82, 78, 65, - 84, 69, 21, 8, 83, 80, 73, 82, 65, 84, 69, 68, 2, 251, 226, 12, 32, 2, - 11, 32, 2, 255, 226, 12, 70, 6, 26, 65, 211, 226, 12, 72, 5, 223, 208, 8, - 78, 6, 186, 226, 12, 68, 2, 90, 187, 2, 65, 6, 168, 164, 8, 4, 77, 65, - 76, 76, 234, 189, 4, 72, 187, 2, 65, 4, 34, 68, 21, 4, 76, 69, 83, 83, 2, - 167, 233, 10, 32, 2, 215, 171, 9, 32, 4, 206, 156, 12, 68, 59, 83, 10, - 28, 3, 73, 78, 71, 31, 85, 2, 189, 150, 12, 2, 76, 69, 8, 58, 66, 173, - 151, 12, 8, 80, 69, 82, 70, 73, 88, 69, 68, 6, 133, 179, 8, 13, 74, 79, + 84, 69, 21, 8, 83, 80, 73, 82, 65, 84, 69, 68, 2, 163, 246, 12, 32, 2, + 11, 32, 2, 167, 246, 12, 70, 6, 26, 65, 251, 245, 12, 72, 5, 231, 218, 8, + 78, 6, 226, 245, 12, 68, 2, 90, 187, 2, 65, 6, 244, 174, 8, 4, 77, 65, + 76, 76, 198, 198, 4, 72, 187, 2, 65, 4, 34, 68, 21, 4, 76, 69, 83, 83, 2, + 231, 249, 10, 32, 2, 171, 187, 9, 32, 4, 246, 175, 12, 68, 59, 83, 10, + 28, 3, 73, 78, 71, 31, 85, 2, 229, 169, 12, 2, 76, 69, 8, 58, 66, 213, + 170, 12, 8, 80, 69, 82, 70, 73, 88, 69, 68, 6, 209, 189, 8, 13, 74, 79, 73, 78, 69, 68, 32, 76, 69, 84, 84, 69, 82, 92, 238, 1, 66, 146, 1, 67, 172, 2, 2, 68, 79, 38, 71, 66, 72, 64, 2, 76, 73, 32, 2, 77, 65, 70, 80, - 162, 1, 82, 38, 83, 150, 1, 84, 70, 87, 160, 223, 5, 2, 70, 76, 252, 232, - 1, 2, 79, 88, 196, 234, 3, 2, 69, 65, 250, 9, 65, 135, 1, 86, 10, 52, 2, - 69, 69, 22, 79, 133, 41, 4, 85, 76, 76, 83, 5, 247, 171, 7, 72, 4, 32, 2, - 79, 77, 135, 223, 12, 87, 2, 11, 69, 2, 163, 134, 12, 82, 16, 34, 65, 86, - 72, 22, 76, 23, 79, 6, 234, 218, 5, 80, 148, 230, 3, 8, 82, 80, 69, 78, - 84, 82, 89, 32, 195, 157, 3, 84, 2, 227, 191, 2, 73, 2, 243, 161, 11, 85, - 6, 26, 76, 33, 2, 77, 66, 2, 11, 85, 2, 187, 141, 12, 77, 5, 37, 7, 73, - 78, 73, 78, 71, 32, 79, 2, 209, 239, 9, 5, 66, 76, 73, 81, 85, 4, 154, - 179, 11, 76, 203, 146, 1, 86, 4, 42, 82, 201, 252, 10, 4, 65, 85, 78, 84, - 2, 239, 163, 11, 65, 6, 42, 69, 146, 209, 7, 79, 143, 250, 2, 73, 2, 131, - 166, 12, 76, 4, 202, 201, 12, 76, 203, 17, 68, 4, 34, 78, 161, 236, 9, 2, - 84, 84, 2, 11, 65, 2, 255, 156, 9, 67, 8, 52, 2, 69, 68, 50, 76, 153, - 166, 7, 3, 65, 80, 89, 2, 25, 4, 69, 83, 84, 82, 2, 219, 143, 11, 73, 4, - 176, 182, 4, 2, 85, 77, 177, 226, 2, 3, 65, 78, 69, 4, 166, 202, 10, 79, - 147, 254, 1, 65, 12, 108, 2, 72, 73, 222, 217, 11, 65, 158, 45, 76, 128, - 19, 3, 84, 82, 65, 177, 39, 7, 77, 65, 76, 76, 32, 65, 88, 4, 242, 185, - 2, 69, 139, 158, 10, 80, 6, 192, 180, 4, 5, 65, 84, 84, 79, 79, 202, 222, - 7, 73, 207, 36, 85, 4, 190, 225, 7, 79, 209, 231, 3, 5, 65, 86, 89, 32, - 66, 4, 174, 244, 1, 83, 25, 4, 68, 79, 85, 66, 60, 56, 8, 69, 78, 73, 67, - 73, 65, 78, 32, 251, 207, 10, 76, 58, 92, 7, 76, 69, 84, 84, 69, 82, 32, - 160, 3, 7, 78, 85, 77, 66, 69, 82, 32, 203, 150, 6, 87, 44, 234, 1, 65, - 34, 68, 22, 72, 22, 81, 22, 83, 58, 84, 158, 130, 2, 87, 138, 229, 5, 90, - 154, 180, 1, 89, 184, 206, 1, 2, 82, 79, 236, 94, 3, 71, 65, 77, 134, 8, + 162, 1, 82, 38, 83, 150, 1, 84, 70, 87, 200, 228, 5, 2, 70, 76, 176, 238, + 1, 2, 79, 88, 252, 240, 3, 2, 69, 65, 138, 10, 65, 135, 1, 86, 10, 52, 2, + 69, 69, 22, 79, 145, 41, 4, 85, 76, 76, 83, 5, 147, 182, 7, 72, 4, 32, 2, + 79, 77, 175, 242, 12, 87, 2, 11, 69, 2, 203, 153, 12, 82, 16, 34, 65, 86, + 72, 22, 76, 23, 79, 6, 130, 224, 5, 80, 208, 240, 3, 8, 82, 80, 69, 78, + 84, 82, 89, 32, 151, 161, 3, 84, 2, 199, 193, 2, 73, 2, 135, 179, 11, 85, + 6, 26, 76, 33, 2, 77, 66, 2, 11, 85, 2, 227, 160, 12, 77, 5, 37, 7, 73, + 78, 73, 78, 71, 32, 79, 2, 169, 255, 9, 5, 66, 76, 73, 81, 85, 4, 174, + 196, 11, 76, 223, 148, 1, 86, 4, 42, 82, 137, 141, 11, 4, 65, 85, 78, 84, + 2, 131, 181, 11, 65, 6, 42, 69, 238, 219, 7, 79, 243, 255, 2, 73, 2, 171, + 185, 12, 76, 4, 242, 220, 12, 76, 203, 17, 68, 4, 34, 78, 249, 251, 9, 2, + 84, 84, 2, 11, 65, 2, 211, 172, 9, 67, 8, 52, 2, 69, 68, 50, 76, 181, + 176, 7, 3, 65, 80, 89, 2, 25, 4, 69, 83, 84, 82, 2, 231, 160, 11, 73, 4, + 192, 187, 4, 2, 85, 77, 209, 231, 2, 3, 65, 78, 69, 4, 230, 218, 10, 79, + 251, 128, 2, 65, 12, 108, 2, 72, 73, 134, 237, 11, 65, 158, 45, 76, 128, + 19, 3, 84, 82, 65, 177, 39, 7, 77, 65, 76, 76, 32, 65, 88, 4, 214, 187, + 2, 69, 207, 175, 10, 80, 6, 208, 185, 4, 5, 65, 84, 84, 79, 79, 226, 236, + 7, 73, 207, 36, 85, 4, 146, 236, 7, 79, 137, 238, 3, 5, 65, 86, 89, 32, + 66, 4, 250, 244, 1, 83, 25, 4, 68, 79, 85, 66, 60, 56, 8, 69, 78, 73, 67, + 73, 65, 78, 32, 187, 224, 10, 76, 58, 92, 7, 76, 69, 84, 84, 69, 82, 32, + 160, 3, 7, 78, 85, 77, 66, 69, 82, 32, 231, 155, 6, 87, 44, 234, 1, 65, + 34, 68, 22, 72, 22, 81, 22, 83, 58, 84, 226, 130, 2, 87, 154, 239, 5, 90, + 154, 185, 1, 89, 164, 207, 1, 2, 82, 79, 184, 95, 3, 71, 65, 77, 162, 10, 75, 130, 1, 78, 144, 58, 3, 76, 65, 77, 138, 17, 66, 198, 30, 80, 171, 4, - 77, 4, 130, 210, 11, 76, 199, 49, 73, 2, 163, 187, 3, 69, 4, 147, 243, 6, - 69, 2, 187, 209, 11, 79, 6, 190, 194, 10, 65, 186, 144, 1, 72, 189, 124, - 2, 69, 77, 4, 170, 173, 12, 65, 191, 8, 69, 12, 238, 49, 84, 135, 166, 4, - 79, 40, 104, 2, 67, 75, 66, 71, 62, 76, 90, 78, 178, 1, 83, 32, 7, 84, - 67, 72, 70, 79, 82, 75, 199, 205, 12, 69, 5, 17, 2, 85, 80, 2, 21, 3, 32, - 84, 82, 2, 203, 160, 11, 85, 7, 11, 32, 4, 26, 78, 251, 146, 12, 70, 2, - 243, 198, 11, 79, 6, 52, 4, 69, 32, 79, 70, 246, 91, 67, 195, 243, 11, - 76, 2, 11, 32, 2, 255, 135, 10, 80, 14, 68, 2, 67, 72, 46, 69, 178, 164, - 4, 87, 182, 162, 7, 75, 243, 98, 65, 4, 160, 155, 3, 2, 69, 68, 255, 164, - 8, 73, 4, 28, 2, 32, 68, 255, 72, 65, 2, 221, 129, 5, 2, 69, 67, 4, 234, - 185, 11, 67, 139, 1, 84, 5, 153, 252, 9, 10, 32, 87, 73, 84, 72, 32, 84, - 69, 69, 32, 218, 1, 38, 65, 218, 9, 85, 135, 195, 12, 68, 176, 1, 78, 67, + 77, 4, 170, 229, 11, 76, 199, 49, 73, 2, 199, 192, 3, 69, 4, 195, 253, 6, + 69, 2, 227, 228, 11, 79, 6, 254, 210, 10, 65, 162, 147, 1, 72, 189, 124, + 2, 69, 77, 4, 210, 192, 12, 65, 191, 8, 69, 12, 202, 50, 84, 203, 170, 4, + 79, 40, 104, 2, 67, 75, 66, 71, 62, 76, 90, 78, 178, 1, 83, 28, 7, 84, + 67, 72, 70, 79, 82, 75, 243, 224, 12, 69, 5, 17, 2, 85, 80, 2, 21, 3, 32, + 84, 82, 2, 223, 177, 11, 85, 7, 11, 32, 4, 26, 78, 163, 166, 12, 70, 2, + 131, 216, 11, 79, 6, 52, 4, 69, 32, 79, 70, 246, 92, 67, 235, 133, 12, + 76, 2, 11, 32, 2, 215, 151, 10, 80, 14, 68, 2, 67, 72, 46, 69, 194, 169, + 4, 87, 206, 176, 7, 75, 243, 98, 65, 4, 196, 160, 3, 2, 69, 68, 231, 176, + 8, 73, 4, 28, 2, 32, 68, 239, 73, 65, 2, 253, 134, 5, 2, 69, 67, 4, 134, + 203, 11, 67, 123, 84, 5, 245, 139, 10, 10, 32, 87, 73, 84, 72, 32, 84, + 69, 69, 32, 218, 1, 38, 65, 230, 9, 85, 167, 214, 12, 68, 176, 1, 78, 67, 128, 1, 12, 78, 67, 75, 32, 67, 79, 78, 83, 84, 65, 78, 84, 83, 89, 6, - 44, 5, 69, 32, 79, 70, 32, 239, 180, 11, 65, 4, 56, 6, 73, 78, 84, 69, - 82, 69, 129, 246, 11, 2, 87, 79, 2, 199, 136, 7, 83, 5, 45, 9, 32, 79, - 86, 69, 82, 32, 84, 87, 79, 2, 11, 32, 2, 243, 182, 12, 80, 166, 1, 96, - 9, 73, 78, 71, 32, 67, 65, 82, 68, 32, 141, 166, 4, 9, 71, 82, 79, 85, - 78, 68, 32, 83, 76, 164, 1, 182, 1, 66, 44, 3, 82, 69, 68, 0, 5, 87, 72, - 73, 84, 69, 42, 70, 74, 75, 38, 69, 34, 83, 36, 3, 81, 85, 69, 14, 84, - 92, 2, 65, 67, 0, 3, 78, 73, 78, 13, 4, 74, 65, 67, 75, 4, 40, 4, 76, 65, - 67, 75, 251, 151, 11, 65, 2, 17, 2, 32, 74, 2, 159, 237, 1, 79, 18, 30, - 79, 249, 1, 2, 73, 86, 10, 128, 2, 2, 85, 82, 235, 187, 11, 79, 16, 34, - 78, 185, 1, 3, 73, 78, 71, 8, 181, 1, 4, 73, 71, 72, 84, 16, 32, 2, 69, - 86, 117, 2, 73, 88, 8, 91, 69, 66, 78, 69, 12, 3, 72, 82, 69, 12, 2, 87, - 79, 161, 1, 5, 82, 85, 77, 80, 45, 8, 23, 78, 8, 11, 69, 8, 25, 4, 32, - 79, 70, 32, 8, 88, 3, 67, 76, 85, 20, 3, 83, 80, 65, 174, 130, 9, 72, - 137, 3, 5, 68, 73, 65, 77, 79, 2, 199, 134, 12, 66, 2, 151, 176, 11, 68, - 42, 90, 50, 238, 130, 10, 49, 182, 192, 2, 51, 2, 52, 2, 53, 2, 54, 2, - 55, 2, 56, 3, 57, 7, 158, 195, 12, 48, 3, 49, 41, 46, 83, 160, 4, 2, 84, - 79, 227, 240, 8, 78, 26, 52, 5, 32, 83, 73, 71, 78, 193, 147, 9, 2, 45, - 77, 25, 11, 32, 22, 64, 3, 73, 78, 32, 124, 5, 87, 73, 84, 72, 32, 207, - 250, 3, 65, 6, 34, 76, 22, 82, 183, 156, 11, 84, 2, 41, 2, 69, 70, 2, 21, - 3, 73, 71, 72, 2, 229, 238, 10, 6, 84, 32, 72, 65, 76, 70, 14, 162, 1, - 68, 34, 83, 200, 160, 10, 4, 84, 73, 76, 68, 208, 121, 5, 66, 76, 65, 67, - 75, 181, 36, 16, 67, 73, 82, 67, 85, 77, 70, 76, 69, 88, 32, 65, 67, 67, - 69, 78, 2, 11, 79, 2, 219, 145, 10, 84, 4, 54, 77, 161, 176, 5, 7, 85, - 66, 83, 67, 82, 73, 80, 2, 249, 154, 9, 3, 65, 76, 76, 11, 33, 6, 32, 70, - 79, 82, 77, 32, 8, 234, 205, 10, 70, 71, 84, 2, 253, 132, 12, 8, 32, 84, - 82, 65, 78, 83, 73, 83, 58, 232, 1, 5, 76, 73, 67, 69, 32, 122, 80, 136, + 44, 5, 69, 32, 79, 70, 32, 151, 198, 11, 65, 4, 56, 6, 73, 78, 84, 69, + 82, 69, 173, 137, 12, 2, 87, 79, 2, 251, 146, 7, 83, 5, 45, 9, 32, 79, + 86, 69, 82, 32, 84, 87, 79, 2, 11, 32, 2, 159, 202, 12, 80, 166, 1, 80, + 7, 71, 82, 79, 85, 78, 68, 32, 29, 9, 73, 78, 71, 32, 67, 65, 82, 68, 32, + 2, 173, 171, 4, 2, 83, 76, 164, 1, 182, 1, 66, 44, 3, 82, 69, 68, 0, 5, + 87, 72, 73, 84, 69, 42, 70, 74, 75, 38, 69, 34, 83, 36, 3, 81, 85, 69, + 14, 84, 92, 2, 65, 67, 0, 3, 78, 73, 78, 13, 4, 74, 65, 67, 75, 4, 40, 4, + 76, 65, 67, 75, 135, 169, 11, 65, 2, 17, 2, 32, 74, 2, 219, 237, 1, 79, + 18, 30, 79, 249, 1, 2, 73, 86, 10, 128, 2, 2, 85, 82, 239, 204, 11, 79, + 16, 34, 78, 185, 1, 3, 73, 78, 71, 8, 181, 1, 4, 73, 71, 72, 84, 16, 32, + 2, 69, 86, 117, 2, 73, 88, 8, 91, 69, 66, 78, 69, 12, 3, 72, 82, 69, 12, + 2, 87, 79, 161, 1, 5, 82, 85, 77, 80, 45, 8, 23, 78, 8, 11, 69, 8, 25, 4, + 32, 79, 70, 32, 8, 88, 3, 67, 76, 85, 20, 3, 83, 80, 65, 250, 145, 9, 72, + 137, 3, 5, 68, 73, 65, 77, 79, 2, 231, 153, 12, 66, 2, 171, 193, 11, 68, + 42, 90, 50, 190, 146, 10, 49, 134, 196, 2, 51, 2, 52, 2, 53, 2, 54, 2, + 55, 2, 56, 3, 57, 7, 190, 214, 12, 48, 3, 49, 41, 46, 83, 160, 4, 2, 84, + 79, 175, 128, 9, 78, 26, 52, 5, 32, 83, 73, 71, 78, 141, 163, 9, 2, 45, + 77, 25, 11, 32, 22, 64, 3, 73, 78, 32, 124, 5, 87, 73, 84, 72, 32, 215, + 255, 3, 65, 6, 34, 76, 22, 82, 195, 173, 11, 84, 2, 41, 2, 69, 70, 2, 21, + 3, 73, 71, 72, 2, 233, 255, 10, 6, 84, 32, 72, 65, 76, 70, 14, 162, 1, + 68, 34, 83, 140, 176, 10, 4, 84, 73, 76, 68, 152, 123, 5, 66, 76, 65, 67, + 75, 201, 38, 16, 67, 73, 82, 67, 85, 77, 70, 76, 69, 88, 32, 65, 67, 67, + 69, 78, 2, 11, 79, 2, 167, 161, 10, 84, 4, 54, 77, 173, 181, 5, 7, 85, + 66, 83, 67, 82, 73, 80, 2, 197, 170, 9, 3, 65, 76, 76, 11, 33, 6, 32, 70, + 79, 82, 77, 32, 8, 162, 222, 10, 70, 71, 84, 2, 157, 152, 12, 8, 32, 84, + 82, 65, 78, 83, 73, 83, 58, 232, 1, 5, 76, 73, 67, 69, 32, 122, 80, 140, 1, 11, 82, 84, 65, 66, 76, 69, 32, 83, 84, 69, 82, 22, 83, 158, 1, 84, - 146, 1, 85, 196, 1, 4, 87, 69, 82, 32, 194, 132, 7, 79, 145, 248, 4, 11, - 67, 75, 69, 84, 32, 67, 65, 76, 67, 85, 76, 6, 52, 3, 67, 65, 82, 209, - 248, 3, 4, 79, 70, 70, 73, 5, 149, 162, 10, 11, 83, 32, 82, 69, 86, 79, + 146, 1, 85, 196, 1, 4, 87, 69, 82, 32, 210, 142, 7, 79, 157, 129, 5, 11, + 67, 75, 69, 84, 32, 67, 65, 76, 67, 85, 76, 6, 52, 3, 67, 65, 82, 217, + 253, 3, 4, 79, 70, 70, 73, 5, 217, 177, 10, 11, 83, 32, 82, 69, 86, 79, 76, 86, 73, 78, 71, 6, 76, 13, 32, 68, 73, 82, 69, 67, 84, 73, 79, 78, - 65, 76, 32, 219, 214, 1, 67, 4, 166, 127, 73, 205, 180, 6, 6, 70, 79, 82, - 77, 65, 84, 2, 223, 154, 12, 69, 12, 40, 2, 69, 73, 22, 84, 235, 135, 5, - 73, 2, 167, 233, 11, 68, 8, 36, 3, 65, 76, 32, 171, 172, 11, 66, 6, 162, - 213, 1, 72, 157, 197, 6, 4, 77, 65, 82, 75, 8, 66, 65, 250, 134, 2, 32, - 141, 167, 9, 6, 84, 69, 68, 32, 80, 76, 4, 26, 66, 211, 152, 12, 84, 2, - 29, 5, 76, 69, 32, 87, 65, 2, 143, 48, 84, 12, 108, 4, 76, 84, 82, 89, - 28, 7, 82, 73, 78, 71, 32, 76, 73, 28, 2, 84, 73, 150, 205, 10, 78, 203, - 231, 1, 67, 2, 185, 240, 11, 2, 32, 76, 2, 193, 174, 5, 2, 81, 85, 4, - 225, 206, 10, 2, 78, 71, 8, 24, 2, 79, 78, 47, 83, 4, 136, 162, 11, 4, - 45, 79, 70, 70, 15, 32, 4, 212, 136, 9, 3, 76, 69, 69, 175, 153, 2, 89, - 140, 1, 74, 69, 162, 10, 73, 234, 2, 79, 157, 206, 9, 6, 65, 89, 69, 82, - 32, 66, 102, 132, 1, 6, 71, 78, 65, 78, 84, 32, 66, 83, 224, 186, 5, 4, - 67, 69, 68, 69, 204, 202, 1, 5, 86, 73, 79, 85, 83, 177, 32, 2, 84, 90, - 6, 42, 87, 130, 179, 8, 80, 215, 181, 2, 77, 2, 255, 188, 7, 79, 70, 176, + 65, 76, 32, 159, 215, 1, 67, 4, 158, 128, 1, 73, 169, 190, 6, 6, 70, 79, + 82, 77, 65, 84, 2, 251, 173, 12, 69, 12, 40, 2, 69, 73, 22, 84, 243, 140, + 5, 73, 2, 195, 252, 11, 68, 8, 36, 3, 65, 76, 32, 171, 189, 11, 66, 6, + 226, 213, 1, 72, 213, 206, 6, 4, 77, 65, 82, 75, 8, 66, 65, 238, 135, 2, + 32, 153, 183, 9, 6, 84, 69, 68, 32, 80, 76, 4, 26, 66, 239, 171, 12, 84, + 2, 29, 5, 76, 69, 32, 87, 65, 2, 243, 48, 84, 12, 108, 4, 76, 84, 82, 89, + 28, 7, 82, 73, 78, 71, 32, 76, 73, 28, 2, 84, 73, 202, 221, 10, 78, 179, + 234, 1, 67, 2, 213, 131, 12, 2, 32, 76, 2, 205, 179, 5, 2, 81, 85, 4, + 149, 223, 10, 2, 78, 71, 8, 24, 2, 79, 78, 47, 83, 4, 136, 179, 11, 4, + 45, 79, 70, 70, 15, 32, 4, 156, 152, 9, 3, 76, 69, 69, 231, 154, 2, 89, + 140, 1, 74, 69, 162, 10, 73, 230, 2, 79, 237, 221, 9, 6, 65, 89, 69, 82, + 32, 66, 102, 132, 1, 6, 71, 78, 65, 78, 84, 32, 66, 83, 252, 191, 5, 4, + 67, 69, 68, 69, 192, 207, 1, 5, 86, 73, 79, 85, 83, 241, 32, 2, 84, 90, + 6, 42, 87, 202, 193, 8, 80, 143, 184, 2, 77, 2, 199, 199, 7, 79, 70, 176, 1, 27, 69, 78, 84, 65, 84, 73, 79, 78, 32, 70, 79, 82, 77, 32, 70, 79, - 82, 32, 86, 69, 82, 84, 73, 67, 65, 76, 32, 221, 200, 8, 10, 67, 82, 73, + 82, 32, 86, 69, 82, 84, 73, 67, 65, 76, 32, 129, 216, 8, 10, 67, 82, 73, 80, 84, 73, 79, 78, 32, 84, 68, 198, 1, 67, 22, 69, 46, 72, 50, 73, 94, 76, 188, 1, 6, 82, 73, 71, 72, 84, 32, 192, 2, 6, 87, 65, 86, 89, 32, 76, - 174, 151, 4, 83, 184, 207, 4, 9, 84, 87, 79, 32, 68, 79, 84, 32, 76, 135, - 114, 81, 4, 167, 185, 2, 79, 6, 222, 153, 6, 88, 174, 216, 2, 77, 3, 78, - 2, 229, 138, 9, 7, 79, 82, 73, 90, 79, 78, 84, 4, 49, 10, 68, 69, 79, 71, - 82, 65, 80, 72, 73, 67, 4, 11, 32, 4, 142, 220, 9, 67, 35, 70, 22, 40, 4, - 69, 70, 84, 32, 219, 197, 10, 79, 20, 112, 6, 87, 72, 73, 84, 69, 32, - 142, 1, 66, 42, 68, 198, 99, 67, 166, 7, 65, 138, 190, 7, 80, 238, 7, 83, - 39, 84, 4, 162, 2, 67, 139, 99, 76, 22, 110, 66, 42, 68, 36, 6, 87, 72, - 73, 84, 69, 32, 162, 99, 67, 166, 7, 65, 138, 190, 7, 80, 238, 7, 83, 39, - 84, 2, 157, 100, 6, 76, 65, 67, 75, 32, 76, 2, 209, 106, 5, 79, 85, 66, - 76, 69, 6, 74, 67, 17, 14, 76, 69, 78, 84, 73, 67, 85, 76, 65, 82, 32, - 66, 82, 65, 2, 239, 98, 79, 4, 218, 215, 11, 67, 177, 29, 2, 75, 67, 2, - 135, 194, 10, 79, 22, 46, 78, 156, 1, 2, 86, 65, 203, 145, 12, 77, 10, - 34, 84, 225, 200, 6, 2, 67, 69, 6, 26, 32, 53, 2, 69, 82, 2, 21, 3, 83, - 67, 82, 2, 153, 177, 10, 2, 69, 69, 5, 17, 2, 32, 73, 2, 195, 216, 11, - 67, 10, 60, 5, 67, 89, 32, 77, 69, 29, 6, 84, 69, 32, 85, 83, 69, 2, 133, - 161, 7, 2, 83, 83, 8, 26, 32, 159, 166, 8, 45, 4, 226, 239, 5, 84, 151, - 158, 5, 79, 14, 130, 1, 74, 30, 80, 236, 33, 5, 72, 73, 66, 73, 84, 200, - 230, 8, 6, 66, 73, 78, 71, 32, 67, 169, 225, 1, 5, 83, 69, 82, 80, 73, 2, - 165, 162, 5, 2, 69, 67, 6, 64, 6, 79, 82, 84, 73, 79, 78, 205, 139, 11, - 4, 69, 82, 84, 89, 5, 247, 209, 5, 65, 58, 172, 1, 15, 70, 79, 85, 82, - 32, 68, 79, 84, 83, 32, 87, 73, 84, 72, 32, 32, 7, 76, 69, 84, 84, 69, - 82, 32, 230, 2, 78, 134, 32, 83, 1, 8, 84, 85, 82, 78, 69, 68, 32, 83, 4, - 190, 226, 10, 67, 227, 112, 68, 36, 166, 1, 65, 22, 68, 34, 76, 22, 77, - 50, 87, 186, 165, 4, 71, 90, 90, 34, 83, 66, 89, 158, 208, 1, 72, 234, 5, - 75, 198, 75, 66, 178, 216, 4, 78, 134, 2, 84, 219, 103, 80, 2, 155, 166, - 4, 76, 2, 11, 65, 2, 143, 201, 6, 76, 2, 183, 166, 4, 65, 2, 25, 4, 69, - 77, 45, 81, 2, 147, 253, 5, 79, 2, 37, 7, 65, 87, 45, 65, 89, 73, 78, 2, - 173, 205, 1, 2, 45, 82, 14, 33, 6, 85, 77, 66, 69, 82, 32, 14, 42, 84, - 134, 166, 4, 79, 131, 231, 2, 70, 8, 42, 87, 150, 176, 10, 72, 231, 159, - 1, 69, 4, 210, 178, 10, 69, 135, 237, 1, 79, 18, 252, 1, 4, 78, 67, 84, - 85, 94, 82, 56, 19, 84, 32, 76, 73, 84, 84, 69, 82, 32, 73, 78, 32, 73, - 84, 83, 32, 80, 76, 65, 214, 151, 1, 83, 140, 42, 20, 66, 76, 73, 67, 32, - 65, 68, 68, 82, 69, 83, 83, 32, 76, 79, 85, 68, 83, 80, 69, 194, 218, 10, - 49, 3, 50, 4, 136, 206, 10, 9, 83, 32, 69, 76, 69, 86, 65, 84, 85, 229, - 144, 1, 5, 65, 84, 73, 79, 78, 4, 32, 2, 80, 76, 227, 133, 12, 83, 2, - 247, 148, 11, 69, 2, 11, 67, 2, 235, 136, 11, 69, 40, 98, 65, 180, 6, 6, - 69, 83, 84, 73, 79, 78, 162, 133, 6, 79, 165, 131, 5, 5, 73, 78, 67, 85, - 78, 30, 104, 2, 68, 82, 240, 4, 9, 84, 69, 82, 78, 73, 79, 78, 32, 73, - 48, 4, 82, 84, 69, 82, 219, 243, 10, 79, 24, 56, 4, 65, 78, 84, 32, 157, - 4, 5, 85, 80, 76, 69, 32, 20, 44, 6, 85, 80, 80, 69, 82, 32, 131, 2, 76, - 16, 56, 4, 76, 69, 70, 84, 249, 1, 5, 82, 73, 71, 72, 84, 11, 29, 5, 32, - 65, 78, 68, 32, 8, 108, 6, 76, 79, 87, 69, 82, 32, 53, 17, 85, 80, 80, - 69, 82, 32, 82, 73, 71, 72, 84, 32, 65, 78, 68, 32, 76, 4, 192, 1, 5, 76, - 69, 70, 84, 32, 231, 235, 11, 82, 4, 11, 79, 4, 11, 87, 4, 157, 236, 11, - 2, 69, 82, 7, 65, 14, 32, 65, 78, 68, 32, 76, 79, 87, 69, 82, 32, 76, 69, - 70, 4, 11, 84, 5, 11, 32, 2, 21, 3, 65, 78, 68, 2, 17, 2, 32, 76, 2, 17, - 2, 79, 87, 2, 237, 196, 10, 2, 69, 82, 4, 22, 73, 223, 37, 80, 2, 205, - 213, 8, 7, 78, 84, 69, 71, 82, 65, 76, 2, 17, 2, 32, 78, 2, 131, 206, 10, - 79, 6, 34, 32, 233, 192, 5, 2, 69, 68, 4, 250, 134, 5, 69, 159, 204, 6, - 77, 220, 9, 114, 65, 142, 8, 69, 204, 27, 6, 72, 73, 78, 79, 67, 69, 34, - 73, 174, 88, 76, 46, 79, 198, 19, 85, 151, 131, 11, 83, 62, 110, 67, 104, - 2, 68, 73, 130, 1, 73, 162, 5, 84, 152, 237, 7, 4, 66, 66, 73, 84, 178, - 229, 3, 90, 235, 56, 77, 6, 40, 4, 73, 78, 71, 32, 187, 235, 8, 67, 4, - 164, 192, 10, 7, 77, 79, 84, 79, 82, 67, 89, 175, 48, 67, 8, 66, 79, 205, - 165, 8, 10, 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 7, 232, 174, 6, 4, - 65, 67, 84, 73, 129, 175, 4, 2, 32, 66, 36, 60, 5, 76, 87, 65, 89, 32, - 46, 78, 21, 4, 83, 69, 68, 32, 4, 140, 245, 8, 2, 84, 82, 203, 249, 1, - 67, 5, 191, 245, 10, 66, 28, 152, 1, 3, 68, 79, 84, 34, 73, 48, 4, 72, - 65, 78, 68, 182, 1, 77, 38, 83, 166, 167, 7, 70, 230, 146, 2, 67, 237, - 195, 1, 7, 66, 65, 67, 75, 32, 79, 70, 5, 29, 5, 84, 69, 68, 32, 73, 2, - 193, 40, 8, 78, 84, 69, 82, 80, 79, 76, 65, 7, 33, 6, 32, 87, 73, 84, 72, - 32, 4, 198, 27, 70, 209, 190, 2, 28, 80, 65, 82, 84, 32, 66, 69, 84, 87, - 69, 69, 78, 32, 77, 73, 68, 68, 76, 69, 32, 65, 78, 68, 32, 82, 73, 78, - 71, 6, 174, 133, 11, 67, 2, 68, 3, 82, 4, 60, 9, 77, 65, 76, 76, 32, 76, - 69, 70, 84, 255, 234, 10, 81, 2, 129, 145, 8, 2, 32, 83, 5, 187, 236, 11, - 73, 250, 1, 226, 1, 67, 132, 4, 2, 68, 32, 64, 2, 71, 73, 144, 1, 5, 74, - 65, 78, 71, 32, 202, 4, 76, 32, 8, 77, 73, 78, 68, 69, 82, 32, 82, 34, - 80, 106, 83, 136, 1, 5, 84, 85, 82, 78, 32, 42, 86, 193, 199, 1, 5, 70, - 69, 82, 69, 78, 26, 114, 69, 60, 3, 89, 67, 76, 230, 204, 5, 79, 149, - 145, 4, 13, 82, 69, 65, 84, 73, 79, 78, 65, 76, 32, 86, 69, 72, 4, 38, - 73, 181, 182, 10, 3, 80, 84, 65, 2, 235, 235, 11, 80, 18, 78, 69, 53, 15, - 73, 78, 71, 32, 83, 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 2, 29, 5, 68, - 32, 80, 65, 80, 2, 131, 164, 10, 69, 16, 100, 5, 84, 89, 80, 69, 45, 133, - 254, 4, 14, 71, 69, 78, 69, 82, 73, 67, 32, 77, 65, 84, 69, 82, 73, 14, - 58, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 55, 2, 173, 206, 5, 6, 32, - 80, 76, 65, 83, 84, 4, 42, 65, 165, 251, 4, 4, 71, 73, 70, 84, 2, 199, - 186, 3, 80, 54, 120, 4, 83, 84, 69, 82, 249, 240, 5, 20, 79, 78, 65, 76, - 32, 73, 78, 68, 73, 67, 65, 84, 79, 82, 32, 83, 89, 77, 66, 79, 2, 155, - 155, 10, 69, 74, 128, 1, 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, - 73, 71, 78, 32, 44, 7, 76, 69, 84, 84, 69, 82, 32, 226, 1, 83, 35, 86, 8, - 194, 135, 10, 78, 154, 251, 1, 72, 3, 82, 46, 162, 1, 78, 238, 243, 7, - 77, 234, 138, 4, 66, 2, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, 2, - 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, 89, 187, 2, 65, 12, 206, 244, 7, 89, - 142, 27, 71, 250, 238, 3, 68, 187, 2, 65, 2, 11, 69, 2, 155, 151, 11, 67, - 18, 64, 10, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 151, 199, 9, 73, 16, - 54, 69, 254, 190, 11, 65, 186, 64, 73, 2, 79, 3, 85, 7, 178, 255, 11, 65, - 3, 85, 2, 189, 238, 10, 3, 73, 69, 86, 2, 137, 175, 11, 3, 73, 66, 66, 2, - 41, 8, 76, 65, 67, 69, 77, 69, 78, 84, 2, 17, 2, 32, 67, 2, 157, 198, 10, - 5, 72, 65, 82, 65, 67, 8, 32, 2, 84, 82, 251, 244, 6, 80, 6, 180, 252, 7, - 16, 73, 67, 84, 69, 68, 32, 76, 69, 70, 84, 32, 69, 78, 84, 82, 89, 179, - 240, 3, 79, 6, 214, 233, 10, 83, 166, 104, 76, 31, 82, 70, 64, 4, 69, 82, - 83, 69, 165, 242, 3, 6, 79, 76, 86, 73, 78, 71, 68, 30, 32, 169, 3, 2, - 68, 32, 20, 184, 1, 6, 67, 72, 69, 67, 75, 69, 28, 2, 76, 73, 108, 7, 83, - 79, 76, 73, 68, 85, 83, 212, 220, 7, 16, 84, 73, 76, 68, 69, 32, 79, 80, - 69, 82, 65, 84, 79, 82, 32, 65, 179, 246, 2, 73, 2, 145, 227, 10, 2, 82, - 32, 4, 248, 207, 3, 18, 71, 72, 84, 32, 70, 79, 85, 82, 32, 80, 79, 73, - 78, 84, 69, 68, 32, 80, 251, 236, 1, 78, 9, 11, 32, 6, 184, 162, 5, 9, - 80, 82, 69, 67, 69, 68, 73, 78, 71, 250, 150, 3, 79, 251, 154, 1, 87, 48, - 232, 2, 5, 65, 78, 71, 76, 69, 20, 7, 68, 79, 85, 66, 76, 69, 32, 118, - 78, 20, 5, 70, 79, 82, 75, 69, 70, 80, 82, 82, 214, 1, 83, 106, 84, 144, - 229, 6, 30, 72, 65, 78, 68, 32, 87, 73, 84, 72, 32, 77, 73, 68, 68, 76, - 69, 32, 70, 73, 78, 71, 69, 82, 32, 69, 88, 84, 69, 78, 68, 202, 185, 2, - 67, 114, 81, 156, 65, 3, 86, 73, 67, 177, 36, 6, 69, 77, 80, 84, 89, 32, - 5, 231, 227, 3, 32, 6, 40, 3, 80, 82, 73, 41, 3, 83, 84, 82, 4, 17, 2, - 77, 69, 5, 179, 180, 3, 32, 2, 29, 5, 79, 75, 69, 32, 78, 2, 235, 177, 6, + 178, 156, 4, 83, 252, 217, 4, 9, 84, 87, 79, 32, 68, 79, 84, 32, 76, 139, + 114, 81, 4, 191, 190, 2, 79, 6, 158, 158, 6, 88, 182, 227, 2, 77, 3, 78, + 2, 173, 154, 9, 7, 79, 82, 73, 90, 79, 78, 84, 4, 49, 10, 68, 69, 79, 71, + 82, 65, 80, 72, 73, 67, 4, 11, 32, 4, 218, 235, 9, 67, 35, 70, 22, 40, 4, + 69, 70, 84, 32, 143, 214, 10, 79, 20, 112, 6, 87, 72, 73, 84, 69, 32, + 142, 1, 66, 42, 68, 186, 100, 67, 166, 7, 65, 222, 203, 7, 80, 238, 7, + 83, 39, 84, 4, 162, 2, 67, 255, 99, 76, 22, 110, 66, 42, 68, 36, 6, 87, + 72, 73, 84, 69, 32, 150, 100, 67, 166, 7, 65, 222, 203, 7, 80, 238, 7, + 83, 39, 84, 2, 145, 101, 6, 76, 65, 67, 75, 32, 76, 2, 197, 107, 5, 79, + 85, 66, 76, 69, 6, 74, 67, 17, 14, 76, 69, 78, 84, 73, 67, 85, 76, 65, + 82, 32, 66, 82, 65, 2, 227, 99, 79, 4, 246, 234, 11, 67, 177, 29, 2, 75, + 67, 2, 187, 210, 10, 79, 22, 46, 78, 156, 1, 2, 86, 65, 231, 164, 12, 77, + 10, 34, 84, 133, 211, 6, 2, 67, 69, 6, 26, 32, 53, 2, 69, 82, 2, 21, 3, + 83, 67, 82, 2, 205, 193, 10, 2, 69, 69, 5, 17, 2, 32, 73, 2, 223, 235, + 11, 67, 10, 60, 5, 67, 89, 32, 77, 69, 29, 6, 84, 69, 32, 85, 83, 69, 2, + 213, 171, 7, 2, 83, 83, 8, 26, 32, 231, 180, 8, 45, 4, 134, 166, 10, 84, + 139, 121, 79, 14, 98, 74, 30, 80, 90, 83, 156, 34, 5, 72, 73, 66, 73, 84, + 173, 245, 8, 6, 66, 73, 78, 71, 32, 67, 2, 213, 167, 5, 2, 69, 67, 6, 64, + 6, 79, 82, 84, 73, 79, 78, 137, 157, 11, 4, 69, 82, 84, 89, 5, 183, 215, + 5, 65, 2, 173, 250, 10, 4, 69, 82, 80, 73, 60, 76, 14, 65, 76, 84, 69, + 82, 32, 80, 65, 72, 76, 65, 86, 73, 32, 215, 5, 89, 58, 172, 1, 15, 70, + 79, 85, 82, 32, 68, 79, 84, 83, 32, 87, 73, 84, 72, 32, 32, 7, 76, 69, + 84, 84, 69, 82, 32, 230, 2, 78, 154, 32, 83, 1, 8, 84, 85, 82, 78, 69, + 68, 32, 83, 4, 246, 242, 10, 67, 247, 114, 68, 36, 166, 1, 65, 22, 68, + 34, 76, 22, 77, 50, 87, 254, 169, 4, 71, 90, 90, 34, 83, 66, 89, 198, + 207, 1, 72, 234, 5, 75, 174, 81, 66, 170, 225, 4, 78, 134, 2, 84, 219, + 103, 80, 2, 223, 170, 4, 76, 2, 11, 65, 2, 227, 210, 6, 76, 2, 251, 170, + 4, 65, 2, 25, 4, 69, 77, 45, 81, 2, 255, 128, 6, 79, 2, 37, 7, 65, 87, + 45, 65, 89, 73, 78, 2, 149, 205, 1, 2, 45, 82, 14, 33, 6, 85, 77, 66, 69, + 82, 32, 14, 42, 84, 202, 170, 4, 79, 191, 236, 2, 70, 8, 42, 87, 250, + 191, 10, 72, 207, 162, 1, 69, 4, 182, 194, 10, 69, 239, 239, 1, 79, 2, + 243, 132, 12, 67, 18, 252, 1, 4, 78, 67, 84, 85, 94, 82, 56, 19, 84, 32, + 76, 73, 84, 84, 69, 82, 32, 73, 78, 32, 73, 84, 83, 32, 80, 76, 65, 178, + 151, 1, 83, 132, 42, 20, 66, 76, 73, 67, 32, 65, 68, 68, 82, 69, 83, 83, + 32, 76, 79, 85, 68, 83, 80, 69, 166, 237, 10, 49, 3, 50, 4, 164, 222, 10, + 9, 83, 32, 69, 76, 69, 86, 65, 84, 85, 129, 147, 1, 5, 65, 84, 73, 79, + 78, 4, 32, 2, 80, 76, 155, 152, 12, 83, 2, 175, 167, 11, 69, 2, 11, 67, + 2, 135, 153, 11, 69, 40, 98, 65, 180, 6, 6, 69, 83, 84, 73, 79, 78, 254, + 136, 6, 79, 229, 143, 5, 5, 73, 78, 67, 85, 78, 30, 104, 2, 68, 82, 240, + 4, 9, 84, 69, 82, 78, 73, 79, 78, 32, 73, 48, 4, 82, 84, 69, 82, 143, + 132, 11, 79, 24, 56, 4, 65, 78, 84, 32, 157, 4, 5, 85, 80, 76, 69, 32, + 20, 44, 6, 85, 80, 80, 69, 82, 32, 131, 2, 76, 16, 56, 4, 76, 69, 70, 84, + 249, 1, 5, 82, 73, 71, 72, 84, 11, 29, 5, 32, 65, 78, 68, 32, 8, 108, 6, + 76, 79, 87, 69, 82, 32, 53, 17, 85, 80, 80, 69, 82, 32, 82, 73, 71, 72, + 84, 32, 65, 78, 68, 32, 76, 4, 192, 1, 5, 76, 69, 70, 84, 32, 159, 254, + 11, 82, 4, 11, 79, 4, 11, 87, 4, 213, 254, 11, 2, 69, 82, 7, 65, 14, 32, + 65, 78, 68, 32, 76, 79, 87, 69, 82, 32, 76, 69, 70, 4, 11, 84, 5, 11, 32, + 2, 21, 3, 65, 78, 68, 2, 17, 2, 32, 76, 2, 17, 2, 79, 87, 2, 137, 213, + 10, 2, 69, 82, 4, 22, 73, 239, 37, 80, 2, 177, 228, 8, 7, 78, 84, 69, 71, + 82, 65, 76, 2, 17, 2, 32, 78, 2, 159, 222, 10, 79, 6, 34, 32, 161, 197, + 5, 2, 69, 68, 4, 162, 139, 5, 69, 175, 218, 6, 77, 220, 9, 114, 65, 142, + 8, 69, 220, 27, 6, 72, 73, 78, 79, 67, 69, 34, 73, 250, 87, 76, 46, 79, + 198, 19, 85, 243, 149, 11, 83, 62, 110, 67, 104, 2, 68, 73, 130, 1, 73, + 162, 5, 84, 172, 246, 7, 4, 66, 66, 73, 84, 214, 238, 3, 90, 235, 56, 77, + 6, 40, 4, 73, 78, 71, 32, 159, 250, 8, 67, 4, 192, 208, 10, 7, 77, 79, + 84, 79, 82, 67, 89, 199, 48, 67, 8, 66, 79, 141, 180, 8, 10, 67, 65, 76, + 32, 83, 89, 77, 66, 79, 76, 7, 168, 184, 6, 4, 65, 67, 84, 73, 229, 181, + 4, 2, 32, 66, 36, 60, 5, 76, 87, 65, 89, 32, 46, 78, 21, 4, 83, 69, 68, + 32, 4, 240, 131, 9, 2, 84, 82, 155, 251, 1, 67, 5, 243, 133, 11, 66, 28, + 152, 1, 3, 68, 79, 84, 34, 73, 48, 4, 72, 65, 78, 68, 182, 1, 77, 38, 83, + 166, 177, 7, 70, 206, 151, 2, 67, 161, 197, 1, 7, 66, 65, 67, 75, 32, 79, + 70, 5, 29, 5, 84, 69, 68, 32, 73, 2, 209, 40, 8, 78, 84, 69, 82, 80, 79, + 76, 65, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 214, 27, 70, 245, 194, 2, + 28, 80, 65, 82, 84, 32, 66, 69, 84, 87, 69, 69, 78, 32, 77, 73, 68, 68, + 76, 69, 32, 65, 78, 68, 32, 82, 73, 78, 71, 6, 230, 151, 11, 67, 2, 68, + 3, 82, 4, 60, 9, 77, 65, 76, 76, 32, 76, 69, 70, 84, 179, 251, 10, 81, 2, + 229, 158, 8, 2, 32, 83, 5, 243, 254, 11, 73, 250, 1, 226, 1, 67, 132, 4, + 2, 68, 32, 64, 2, 71, 73, 144, 1, 5, 74, 65, 78, 71, 32, 202, 4, 76, 32, + 8, 77, 73, 78, 68, 69, 82, 32, 82, 34, 80, 106, 83, 136, 1, 5, 84, 85, + 82, 78, 32, 42, 86, 209, 199, 1, 5, 70, 69, 82, 69, 78, 26, 114, 69, 60, + 3, 89, 67, 76, 146, 209, 5, 79, 205, 155, 4, 13, 82, 69, 65, 84, 73, 79, + 78, 65, 76, 32, 86, 69, 72, 4, 38, 73, 209, 198, 10, 3, 80, 84, 65, 2, + 163, 254, 11, 80, 18, 78, 69, 53, 15, 73, 78, 71, 32, 83, 89, 77, 66, 79, + 76, 32, 70, 79, 82, 32, 2, 29, 5, 68, 32, 80, 65, 80, 2, 211, 179, 10, + 69, 16, 100, 5, 84, 89, 80, 69, 45, 173, 130, 5, 14, 71, 69, 78, 69, 82, + 73, 67, 32, 77, 65, 84, 69, 82, 73, 14, 58, 49, 2, 50, 2, 51, 2, 52, 2, + 53, 2, 54, 3, 55, 2, 133, 210, 5, 6, 32, 80, 76, 65, 83, 84, 4, 42, 65, + 205, 255, 4, 4, 71, 73, 70, 84, 2, 231, 190, 3, 80, 54, 120, 4, 83, 84, + 69, 82, 213, 244, 5, 20, 79, 78, 65, 76, 32, 73, 78, 68, 73, 67, 65, 84, + 79, 82, 32, 83, 89, 77, 66, 79, 2, 235, 170, 10, 69, 74, 128, 1, 15, 67, + 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 44, 7, 76, 69, + 84, 84, 69, 82, 32, 226, 1, 83, 35, 86, 8, 146, 151, 10, 78, 130, 254, 1, + 72, 3, 82, 46, 162, 1, 78, 186, 253, 7, 77, 214, 147, 4, 66, 2, 67, 2, + 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, + 2, 89, 187, 2, 65, 12, 154, 254, 7, 89, 166, 31, 71, 206, 243, 3, 68, + 187, 2, 65, 2, 11, 69, 2, 211, 169, 11, 67, 18, 64, 10, 79, 87, 69, 76, + 32, 83, 73, 71, 78, 32, 139, 214, 9, 73, 16, 54, 69, 182, 209, 11, 65, + 186, 64, 73, 2, 79, 3, 85, 7, 234, 145, 12, 65, 3, 85, 2, 217, 254, 10, + 3, 73, 69, 86, 2, 193, 193, 11, 3, 73, 66, 66, 2, 41, 8, 76, 65, 67, 69, + 77, 69, 78, 84, 2, 17, 2, 32, 67, 2, 193, 214, 10, 5, 72, 65, 82, 65, 67, + 8, 32, 2, 84, 82, 231, 254, 6, 80, 6, 152, 138, 8, 16, 73, 67, 84, 69, + 68, 32, 76, 69, 70, 84, 32, 69, 78, 84, 82, 89, 135, 245, 3, 79, 6, 242, + 249, 10, 83, 194, 106, 76, 31, 82, 70, 64, 4, 69, 82, 83, 69, 197, 246, + 3, 6, 79, 76, 86, 73, 78, 71, 68, 30, 32, 169, 3, 2, 68, 32, 20, 184, 1, + 6, 67, 72, 69, 67, 75, 69, 28, 2, 76, 73, 108, 7, 83, 79, 76, 73, 68, 85, + 83, 232, 229, 7, 16, 84, 73, 76, 68, 69, 32, 79, 80, 69, 82, 65, 84, 79, + 82, 32, 65, 195, 253, 2, 73, 2, 197, 243, 10, 2, 82, 32, 4, 152, 212, 3, + 18, 71, 72, 84, 32, 70, 79, 85, 82, 32, 80, 79, 73, 78, 84, 69, 68, 32, + 80, 135, 237, 1, 78, 9, 11, 32, 6, 240, 166, 5, 9, 80, 82, 69, 67, 69, + 68, 73, 78, 71, 166, 161, 3, 79, 251, 154, 1, 87, 48, 248, 2, 5, 65, 78, + 71, 76, 69, 20, 7, 68, 79, 85, 66, 76, 69, 32, 118, 78, 20, 5, 70, 79, + 82, 75, 69, 70, 80, 82, 82, 214, 1, 83, 106, 84, 236, 238, 6, 30, 72, 65, + 78, 68, 32, 87, 73, 84, 72, 32, 77, 73, 68, 68, 76, 69, 32, 70, 73, 78, + 71, 69, 82, 32, 69, 88, 84, 69, 78, 68, 198, 190, 2, 67, 114, 81, 180, + 102, 6, 69, 77, 80, 84, 89, 32, 253, 93, 7, 86, 73, 67, 84, 79, 82, 89, + 5, 247, 231, 3, 32, 6, 40, 3, 80, 82, 73, 41, 3, 83, 84, 82, 4, 17, 2, + 77, 69, 5, 195, 184, 3, 32, 2, 29, 5, 79, 75, 69, 32, 78, 2, 155, 187, 6, 79, 2, 49, 10, 68, 32, 80, 65, 82, 65, 71, 82, 65, 80, 2, 179, 4, 72, 4, - 36, 3, 73, 76, 67, 203, 219, 10, 82, 2, 11, 82, 2, 177, 236, 10, 2, 79, + 36, 3, 73, 76, 67, 239, 235, 10, 82, 2, 11, 82, 2, 217, 254, 10, 2, 79, 87, 6, 156, 1, 17, 65, 73, 83, 69, 68, 32, 72, 65, 78, 68, 32, 87, 73, - 84, 72, 32, 70, 200, 107, 8, 79, 84, 65, 84, 69, 68, 32, 70, 217, 166, 6, - 4, 73, 71, 72, 84, 2, 133, 113, 9, 73, 78, 71, 69, 82, 83, 32, 83, 80, 4, - 208, 134, 1, 17, 65, 78, 83, 45, 83, 69, 82, 73, 70, 32, 67, 65, 80, 73, - 84, 65, 76, 183, 159, 7, 69, 10, 88, 4, 73, 76, 68, 69, 28, 7, 82, 73, - 80, 76, 69, 32, 80, 241, 150, 7, 3, 72, 85, 77, 5, 213, 231, 4, 2, 32, - 69, 2, 235, 215, 10, 82, 2, 11, 82, 2, 231, 177, 11, 79, 147, 4, 228, 1, - 4, 66, 66, 79, 78, 152, 1, 3, 67, 69, 32, 60, 3, 71, 72, 84, 240, 81, 2, + 84, 72, 32, 70, 148, 107, 8, 79, 84, 65, 84, 69, 68, 32, 70, 253, 176, 6, + 4, 73, 71, 72, 84, 2, 209, 112, 9, 73, 78, 71, 69, 82, 83, 32, 83, 80, 4, + 156, 134, 1, 17, 65, 78, 83, 45, 83, 69, 82, 73, 70, 32, 67, 65, 80, 73, + 84, 65, 76, 191, 174, 7, 69, 10, 88, 4, 73, 76, 68, 69, 28, 7, 82, 73, + 80, 76, 69, 32, 80, 225, 160, 7, 3, 72, 85, 77, 5, 237, 235, 4, 2, 32, + 69, 2, 143, 232, 10, 82, 2, 11, 82, 2, 143, 196, 11, 79, 147, 4, 228, 1, + 4, 66, 66, 79, 78, 152, 1, 3, 67, 69, 32, 60, 3, 71, 72, 84, 188, 81, 2, 78, 71, 252, 1, 23, 83, 73, 78, 71, 32, 68, 73, 65, 71, 79, 78, 65, 76, - 32, 67, 82, 79, 83, 83, 73, 78, 71, 32, 226, 212, 5, 65, 255, 158, 4, 70, + 32, 67, 82, 79, 83, 83, 73, 78, 71, 32, 198, 222, 5, 65, 227, 165, 4, 70, 19, 37, 7, 32, 65, 82, 82, 79, 87, 32, 16, 88, 3, 76, 69, 70, 0, 4, 82, - 73, 71, 72, 158, 193, 4, 85, 141, 128, 7, 3, 68, 79, 87, 4, 171, 248, 1, - 84, 4, 26, 67, 199, 228, 9, 66, 2, 217, 145, 1, 3, 82, 65, 67, 224, 3, + 73, 71, 72, 178, 197, 4, 85, 161, 142, 7, 3, 68, 79, 87, 4, 207, 252, 1, + 84, 4, 26, 67, 135, 244, 9, 66, 2, 157, 145, 1, 3, 82, 65, 67, 224, 3, 110, 32, 190, 36, 45, 152, 12, 11, 72, 65, 78, 68, 32, 73, 78, 84, 69, 82, 73, 29, 6, 87, 65, 82, 68, 83, 32, 202, 1, 166, 2, 65, 132, 6, 2, 66, 76, 62, 67, 184, 1, 2, 68, 79, 242, 1, 70, 60, 2, 72, 65, 176, 5, 13, 74, @@ -6601,2251 +6675,2279 @@ static const unsigned char packed_name_dawg[] = { 69, 82, 84, 73, 67, 65, 76, 32, 147, 1, 87, 28, 22, 78, 163, 4, 82, 22, 24, 2, 68, 32, 39, 71, 4, 170, 50, 76, 21, 3, 85, 80, 80, 18, 26, 69, 17, 2, 76, 69, 2, 203, 26, 82, 17, 11, 32, 14, 154, 1, 66, 44, 8, 68, 79, 84, - 84, 69, 68, 32, 83, 2, 83, 112, 5, 87, 73, 84, 72, 32, 153, 196, 10, 12, - 86, 65, 82, 73, 65, 78, 84, 32, 87, 73, 84, 72, 4, 153, 194, 10, 6, 82, + 84, 69, 68, 32, 83, 2, 83, 112, 5, 87, 73, 84, 72, 32, 189, 212, 10, 12, + 86, 65, 82, 73, 65, 78, 84, 32, 87, 73, 84, 72, 4, 173, 210, 10, 6, 82, 65, 67, 75, 69, 84, 2, 37, 7, 85, 66, 83, 84, 73, 84, 85, 2, 25, 4, 84, - 73, 79, 78, 2, 21, 3, 32, 77, 65, 2, 231, 138, 1, 82, 4, 68, 11, 68, 79, - 87, 78, 87, 65, 82, 68, 83, 32, 90, 179, 232, 8, 65, 2, 233, 201, 10, 5, + 73, 79, 78, 2, 21, 3, 32, 77, 65, 2, 171, 138, 1, 82, 4, 68, 11, 68, 79, + 87, 78, 87, 65, 82, 68, 83, 32, 90, 139, 247, 8, 65, 2, 141, 218, 10, 5, 73, 71, 90, 65, 71, 6, 18, 67, 79, 82, 2, 41, 8, 32, 71, 82, 69, 65, 84, 69, 82, 2, 249, 24, 4, 45, 84, 72, 65, 4, 41, 8, 79, 87, 32, 87, 73, 84, - 72, 32, 4, 188, 220, 7, 7, 67, 73, 82, 67, 76, 69, 68, 151, 180, 2, 83, - 4, 25, 4, 65, 67, 75, 32, 4, 130, 27, 76, 139, 205, 7, 84, 12, 38, 85, - 166, 26, 79, 207, 231, 2, 69, 8, 53, 11, 82, 76, 89, 32, 66, 82, 65, 67, + 72, 32, 4, 144, 234, 7, 7, 67, 73, 82, 67, 76, 69, 68, 207, 182, 2, 83, + 4, 25, 4, 65, 67, 75, 32, 4, 130, 27, 76, 223, 218, 7, 84, 12, 38, 85, + 166, 26, 79, 243, 235, 2, 69, 8, 53, 11, 82, 76, 89, 32, 66, 82, 65, 67, 75, 69, 84, 9, 11, 32, 6, 44, 4, 77, 73, 68, 68, 250, 10, 76, 27, 85, 2, - 201, 170, 10, 2, 76, 69, 12, 38, 84, 41, 5, 85, 66, 76, 69, 32, 2, 137, - 17, 6, 84, 69, 68, 32, 83, 85, 10, 50, 65, 94, 87, 198, 158, 3, 81, 131, - 190, 4, 80, 4, 162, 31, 78, 157, 157, 3, 15, 82, 82, 79, 87, 32, 87, 73, - 84, 72, 32, 82, 79, 85, 78, 68, 2, 139, 24, 73, 6, 26, 73, 247, 254, 2, - 76, 4, 154, 201, 8, 86, 175, 97, 83, 28, 32, 3, 76, 70, 32, 187, 4, 78, + 221, 186, 10, 2, 76, 69, 12, 38, 84, 41, 5, 85, 66, 76, 69, 32, 2, 137, + 17, 6, 84, 69, 68, 32, 83, 85, 10, 50, 65, 94, 87, 214, 162, 3, 81, 199, + 199, 4, 80, 4, 162, 31, 78, 173, 161, 3, 15, 82, 82, 79, 87, 32, 87, 73, + 84, 72, 32, 82, 79, 85, 78, 68, 2, 139, 24, 73, 6, 26, 73, 155, 131, 3, + 76, 4, 238, 215, 8, 86, 191, 97, 83, 28, 32, 3, 76, 70, 32, 187, 4, 78, 26, 128, 1, 8, 65, 78, 68, 32, 76, 69, 70, 84, 62, 66, 90, 70, 82, 72, - 50, 82, 58, 84, 70, 87, 246, 13, 76, 22, 85, 215, 212, 8, 77, 2, 29, 5, - 32, 72, 65, 76, 70, 2, 245, 202, 8, 2, 32, 87, 6, 11, 76, 6, 40, 4, 65, - 67, 75, 32, 163, 172, 10, 79, 4, 146, 138, 10, 67, 207, 11, 83, 4, 58, - 79, 221, 152, 3, 8, 76, 89, 73, 78, 71, 32, 83, 65, 2, 175, 187, 9, 76, - 2, 253, 201, 8, 7, 79, 82, 73, 90, 79, 78, 84, 2, 33, 6, 85, 78, 78, 73, - 78, 71, 2, 247, 228, 6, 32, 2, 209, 169, 5, 12, 82, 73, 80, 76, 69, 32, - 68, 65, 83, 72, 32, 72, 2, 189, 151, 10, 4, 72, 73, 84, 69, 2, 173, 152, + 50, 82, 58, 84, 70, 87, 246, 13, 76, 22, 85, 175, 227, 8, 77, 2, 29, 5, + 32, 72, 65, 76, 70, 2, 201, 217, 8, 2, 32, 87, 6, 11, 76, 6, 40, 4, 65, + 67, 75, 32, 183, 188, 10, 79, 4, 158, 154, 10, 67, 207, 11, 83, 4, 58, + 79, 237, 156, 3, 8, 76, 89, 73, 78, 71, 32, 83, 65, 2, 131, 202, 9, 76, + 2, 209, 216, 8, 7, 79, 82, 73, 90, 79, 78, 84, 2, 33, 6, 85, 78, 78, 73, + 78, 71, 2, 203, 238, 6, 32, 2, 153, 173, 5, 12, 82, 73, 80, 76, 69, 32, + 68, 65, 83, 72, 32, 72, 2, 209, 167, 10, 4, 72, 73, 84, 69, 2, 173, 152, 1, 16, 68, 32, 84, 69, 76, 69, 80, 72, 79, 78, 69, 32, 82, 69, 67, 69, 4, - 231, 217, 7, 84, 2, 233, 133, 11, 11, 87, 32, 80, 65, 82, 65, 80, 72, 82, + 187, 231, 7, 84, 2, 145, 152, 11, 11, 87, 32, 80, 65, 82, 65, 80, 72, 82, 65, 83, 2, 177, 4, 16, 79, 82, 77, 65, 76, 32, 70, 65, 67, 84, 79, 82, - 32, 83, 69, 77, 8, 74, 85, 210, 206, 8, 78, 169, 188, 1, 8, 80, 69, 78, - 32, 83, 81, 85, 65, 2, 181, 215, 10, 6, 84, 69, 82, 32, 74, 79, 8, 49, + 32, 83, 69, 77, 8, 74, 85, 166, 221, 8, 78, 225, 189, 1, 8, 80, 69, 78, + 32, 83, 81, 85, 65, 2, 221, 233, 10, 6, 84, 69, 82, 32, 74, 79, 8, 49, 10, 65, 82, 69, 78, 84, 72, 69, 83, 73, 83, 9, 11, 32, 6, 34, 76, 26, 85, - 171, 182, 9, 69, 2, 157, 37, 2, 79, 87, 2, 133, 37, 2, 80, 80, 2, 217, + 255, 196, 9, 69, 2, 157, 37, 2, 79, 87, 2, 133, 37, 2, 80, 80, 2, 217, 10, 10, 73, 83, 69, 68, 32, 79, 77, 73, 83, 83, 40, 62, 45, 70, 69, 78, - 73, 68, 2, 80, 69, 126, 81, 227, 2, 85, 2, 253, 241, 7, 12, 83, 72, 65, - 80, 69, 68, 32, 66, 65, 71, 32, 68, 4, 26, 77, 231, 221, 8, 86, 2, 205, - 196, 10, 7, 73, 68, 73, 82, 69, 67, 84, 4, 194, 146, 3, 78, 145, 238, 7, + 73, 68, 2, 80, 69, 126, 81, 227, 2, 85, 2, 173, 128, 8, 12, 83, 72, 65, + 80, 69, 68, 32, 66, 65, 71, 32, 68, 4, 26, 77, 191, 236, 8, 86, 2, 217, + 212, 10, 7, 73, 68, 73, 82, 69, 67, 84, 4, 210, 150, 3, 78, 169, 252, 7, 8, 68, 69, 87, 65, 89, 83, 32, 85, 8, 32, 4, 65, 75, 69, 82, 67, 69, 7, - 33, 6, 32, 87, 73, 84, 72, 32, 4, 214, 248, 3, 79, 55, 84, 2, 137, 5, 2, + 33, 6, 32, 87, 73, 84, 72, 32, 4, 246, 252, 3, 79, 55, 84, 2, 137, 5, 2, 67, 72, 20, 57, 12, 85, 65, 82, 69, 32, 66, 82, 65, 67, 75, 69, 84, 21, 11, 32, 18, 84, 3, 76, 79, 87, 0, 3, 85, 80, 80, 28, 5, 87, 73, 84, 72, - 32, 143, 177, 9, 69, 2, 213, 226, 3, 2, 69, 82, 12, 96, 8, 84, 73, 67, - 75, 32, 73, 78, 32, 230, 6, 81, 246, 221, 7, 85, 222, 125, 68, 183, 189, - 2, 83, 4, 212, 225, 3, 6, 66, 79, 84, 84, 79, 77, 1, 3, 84, 79, 80, 2, - 165, 4, 6, 66, 83, 84, 73, 84, 85, 26, 54, 72, 130, 3, 82, 174, 209, 7, - 79, 171, 202, 2, 65, 14, 62, 73, 116, 5, 79, 85, 71, 72, 84, 45, 4, 82, - 69, 69, 32, 4, 21, 3, 82, 68, 32, 4, 68, 4, 73, 78, 68, 85, 185, 207, 1, - 7, 87, 72, 73, 84, 69, 32, 82, 2, 175, 148, 11, 67, 2, 11, 32, 2, 197, - 132, 3, 3, 66, 85, 66, 8, 60, 9, 81, 85, 65, 82, 84, 69, 82, 83, 32, 191, - 215, 8, 69, 6, 34, 76, 22, 85, 179, 221, 8, 66, 2, 37, 2, 79, 87, 2, 17, - 2, 80, 80, 2, 139, 216, 8, 69, 8, 34, 65, 89, 4, 73, 65, 78, 71, 2, 33, - 6, 78, 83, 80, 79, 83, 73, 2, 11, 84, 2, 17, 2, 73, 79, 2, 235, 247, 10, - 78, 6, 32, 2, 76, 69, 199, 214, 8, 85, 5, 41, 8, 32, 65, 66, 79, 86, 69, - 32, 76, 2, 225, 163, 9, 2, 69, 70, 6, 18, 66, 95, 82, 4, 68, 9, 65, 82, - 32, 87, 73, 84, 72, 32, 81, 177, 175, 10, 2, 79, 88, 2, 251, 208, 8, 85, - 2, 241, 173, 9, 3, 85, 76, 69, 14, 22, 72, 203, 1, 73, 12, 25, 4, 73, 84, - 69, 32, 12, 54, 67, 54, 76, 250, 196, 7, 80, 238, 7, 83, 39, 84, 4, 26, - 79, 207, 193, 7, 85, 2, 65, 3, 82, 78, 69, 2, 41, 8, 69, 78, 84, 73, 67, - 85, 76, 65, 2, 143, 244, 10, 82, 2, 133, 190, 6, 6, 71, 71, 76, 89, 32, + 32, 227, 191, 9, 69, 2, 245, 230, 3, 2, 69, 82, 12, 96, 8, 84, 73, 67, + 75, 32, 73, 78, 32, 230, 6, 81, 166, 236, 7, 85, 134, 126, 68, 135, 193, + 2, 83, 4, 244, 229, 3, 6, 66, 79, 84, 84, 79, 77, 1, 3, 84, 79, 80, 2, + 165, 4, 6, 66, 83, 84, 73, 84, 85, 26, 54, 72, 130, 3, 82, 130, 223, 7, + 79, 235, 204, 2, 65, 14, 62, 73, 116, 5, 79, 85, 71, 72, 84, 45, 4, 82, + 69, 69, 32, 4, 21, 3, 82, 68, 32, 4, 68, 4, 73, 78, 68, 85, 221, 211, 1, + 7, 87, 72, 73, 84, 69, 32, 82, 2, 215, 166, 11, 67, 2, 11, 32, 2, 213, + 136, 3, 3, 66, 85, 66, 8, 60, 9, 81, 85, 65, 82, 84, 69, 82, 83, 32, 151, + 230, 8, 69, 6, 34, 76, 22, 85, 139, 236, 8, 66, 2, 37, 2, 79, 87, 2, 17, + 2, 80, 80, 2, 227, 230, 8, 69, 8, 34, 65, 89, 4, 73, 65, 78, 71, 2, 33, + 6, 78, 83, 80, 79, 83, 73, 2, 11, 84, 2, 17, 2, 73, 79, 2, 147, 138, 11, + 78, 6, 32, 2, 76, 69, 159, 229, 8, 85, 5, 41, 8, 32, 65, 66, 79, 86, 69, + 32, 76, 2, 181, 178, 9, 2, 69, 70, 6, 18, 66, 95, 82, 4, 68, 9, 65, 82, + 32, 87, 73, 84, 72, 32, 81, 213, 191, 10, 2, 79, 88, 2, 211, 223, 8, 85, + 2, 189, 188, 9, 3, 85, 76, 69, 14, 22, 72, 203, 1, 73, 12, 25, 4, 73, 84, + 69, 32, 12, 54, 67, 54, 76, 206, 210, 7, 80, 238, 7, 83, 39, 84, 4, 26, + 79, 163, 207, 7, 85, 2, 65, 3, 82, 78, 69, 2, 41, 8, 69, 78, 84, 73, 67, + 85, 76, 65, 2, 183, 134, 11, 82, 2, 225, 199, 6, 6, 71, 71, 76, 89, 32, 70, 62, 118, 70, 226, 2, 72, 128, 1, 9, 80, 79, 73, 78, 84, 73, 78, 71, 32, 214, 4, 83, 197, 1, 6, 84, 79, 45, 76, 69, 70, 18, 33, 6, 65, 67, 73, 78, 71, 32, 18, 116, 14, 65, 82, 77, 69, 78, 73, 65, 78, 32, 69, 84, 69, - 82, 78, 20, 4, 66, 65, 83, 83, 16, 3, 70, 73, 83, 87, 83, 2, 171, 145, 8, - 73, 2, 227, 43, 73, 6, 26, 72, 239, 195, 11, 84, 5, 11, 32, 2, 149, 162, - 8, 6, 87, 73, 84, 72, 32, 79, 8, 236, 203, 3, 10, 86, 65, 83, 84, 73, 32, - 83, 73, 71, 78, 143, 213, 4, 78, 2, 81, 18, 65, 78, 68, 69, 68, 32, 73, - 78, 84, 69, 82, 76, 65, 67, 69, 68, 32, 80, 2, 21, 3, 69, 78, 84, 2, 231, - 134, 10, 65, 30, 90, 65, 30, 67, 94, 68, 58, 77, 58, 82, 182, 1, 83, 74, - 84, 254, 157, 8, 69, 179, 124, 71, 4, 90, 78, 203, 160, 8, 84, 2, 29, 5, - 85, 82, 86, 69, 68, 2, 17, 2, 32, 65, 2, 11, 78, 2, 177, 237, 10, 2, 71, - 76, 4, 248, 254, 2, 5, 79, 85, 66, 76, 69, 131, 177, 6, 73, 2, 129, 168, - 10, 9, 65, 71, 78, 73, 70, 89, 73, 78, 71, 10, 38, 79, 206, 163, 9, 65, - 247, 28, 73, 6, 92, 5, 67, 75, 69, 84, 32, 137, 163, 9, 12, 76, 76, 69, - 82, 32, 67, 79, 65, 83, 84, 69, 82, 4, 228, 43, 3, 66, 79, 79, 179, 189, - 10, 83, 2, 11, 84, 2, 21, 3, 73, 67, 75, 2, 221, 177, 6, 4, 32, 70, 73, - 71, 2, 155, 220, 7, 65, 4, 46, 72, 85, 7, 73, 68, 69, 32, 65, 82, 67, 2, - 17, 2, 65, 68, 2, 17, 2, 69, 68, 2, 173, 156, 10, 6, 32, 87, 72, 73, 84, - 69, 2, 11, 32, 2, 241, 224, 8, 8, 67, 76, 79, 67, 75, 87, 73, 83, 8, 17, - 2, 84, 32, 8, 86, 73, 40, 4, 79, 86, 69, 82, 152, 130, 5, 5, 69, 77, 66, - 69, 68, 251, 246, 5, 77, 2, 17, 2, 83, 79, 2, 131, 135, 1, 76, 2, 247, - 150, 3, 82, 2, 129, 171, 10, 2, 79, 82, 214, 1, 160, 1, 5, 65, 82, 82, - 79, 87, 130, 9, 66, 86, 68, 210, 1, 70, 122, 72, 230, 6, 76, 26, 79, 34, - 80, 50, 82, 70, 83, 94, 84, 206, 8, 87, 190, 182, 8, 67, 47, 81, 75, 26, - 32, 223, 132, 9, 45, 70, 94, 65, 170, 2, 70, 110, 84, 184, 1, 5, 87, 73, - 84, 72, 32, 181, 157, 1, 4, 79, 86, 69, 82, 12, 40, 5, 66, 79, 86, 69, - 32, 143, 1, 78, 10, 70, 82, 140, 161, 1, 5, 83, 72, 79, 82, 84, 130, 193, - 3, 65, 55, 84, 4, 37, 7, 69, 86, 69, 82, 83, 69, 32, 4, 226, 225, 4, 65, + 82, 78, 20, 4, 66, 65, 83, 83, 16, 3, 70, 73, 83, 87, 83, 2, 255, 159, 8, + 73, 2, 175, 43, 73, 6, 26, 72, 151, 214, 11, 84, 5, 11, 32, 2, 233, 176, + 8, 6, 87, 73, 84, 72, 32, 79, 8, 140, 208, 3, 10, 86, 65, 83, 84, 73, 32, + 83, 73, 71, 78, 195, 223, 4, 78, 2, 81, 18, 65, 78, 68, 69, 68, 32, 73, + 78, 84, 69, 82, 76, 65, 67, 69, 68, 32, 80, 2, 21, 3, 69, 78, 84, 2, 251, + 150, 10, 65, 30, 90, 65, 30, 67, 94, 68, 58, 77, 58, 82, 182, 1, 83, 74, + 84, 210, 172, 8, 69, 179, 124, 71, 4, 90, 78, 159, 175, 8, 84, 2, 29, 5, + 85, 82, 86, 69, 68, 2, 17, 2, 32, 65, 2, 11, 78, 2, 217, 255, 10, 2, 71, + 76, 4, 136, 131, 3, 5, 79, 85, 66, 76, 69, 179, 188, 6, 73, 2, 165, 184, + 10, 9, 65, 71, 78, 73, 70, 89, 73, 78, 71, 10, 38, 79, 154, 178, 9, 65, + 235, 29, 73, 6, 92, 5, 67, 75, 69, 84, 32, 213, 177, 9, 12, 76, 76, 69, + 82, 32, 67, 79, 65, 83, 84, 69, 82, 4, 176, 43, 3, 66, 79, 79, 143, 208, + 10, 83, 2, 11, 84, 2, 21, 3, 73, 67, 75, 2, 185, 187, 6, 4, 32, 70, 73, + 71, 2, 239, 234, 7, 65, 4, 46, 72, 85, 7, 73, 68, 69, 32, 65, 82, 67, 2, + 17, 2, 65, 68, 2, 17, 2, 69, 68, 2, 209, 172, 10, 6, 32, 87, 72, 73, 84, + 69, 2, 11, 32, 2, 201, 239, 8, 8, 67, 76, 79, 67, 75, 87, 73, 83, 8, 17, + 2, 84, 32, 8, 86, 73, 40, 4, 79, 86, 69, 82, 176, 134, 5, 5, 69, 77, 66, + 69, 68, 139, 133, 6, 77, 2, 17, 2, 83, 79, 2, 131, 135, 1, 76, 2, 135, + 155, 3, 82, 2, 141, 187, 10, 2, 79, 82, 214, 1, 160, 1, 5, 65, 82, 82, + 79, 87, 130, 9, 66, 86, 68, 210, 1, 70, 122, 72, 178, 6, 76, 26, 79, 34, + 80, 50, 82, 70, 83, 94, 84, 206, 8, 87, 202, 197, 8, 67, 47, 81, 75, 26, + 32, 195, 147, 9, 45, 70, 94, 65, 170, 2, 70, 110, 84, 184, 1, 5, 87, 73, + 84, 72, 32, 129, 160, 1, 4, 79, 86, 69, 82, 12, 40, 5, 66, 79, 86, 69, + 32, 143, 1, 78, 10, 70, 82, 216, 163, 1, 5, 83, 72, 79, 82, 84, 222, 194, + 3, 65, 55, 84, 4, 37, 7, 69, 86, 69, 82, 83, 69, 32, 4, 138, 230, 4, 65, 55, 84, 2, 61, 13, 68, 32, 85, 80, 80, 69, 82, 32, 65, 78, 68, 32, 76, 2, - 17, 2, 79, 87, 2, 169, 198, 8, 2, 69, 82, 6, 25, 4, 82, 79, 77, 32, 6, - 36, 3, 66, 65, 82, 227, 198, 8, 68, 5, 189, 1, 6, 32, 84, 79, 32, 66, 76, - 10, 56, 7, 72, 82, 79, 85, 71, 72, 32, 65, 3, 79, 32, 66, 6, 184, 220, 4, - 3, 83, 85, 80, 198, 197, 4, 71, 155, 146, 2, 88, 4, 26, 76, 227, 250, 10, - 65, 2, 141, 231, 9, 3, 65, 67, 75, 40, 140, 1, 6, 67, 79, 82, 78, 69, 82, - 26, 68, 98, 76, 86, 80, 30, 83, 38, 84, 178, 195, 8, 77, 38, 78, 122, 69, - 226, 151, 1, 72, 143, 163, 1, 86, 2, 133, 19, 2, 32, 68, 4, 11, 79, 4, - 40, 4, 84, 84, 69, 68, 155, 205, 7, 85, 2, 17, 2, 32, 83, 2, 251, 158, - 11, 84, 6, 26, 79, 143, 196, 8, 65, 4, 26, 87, 211, 176, 11, 79, 2, 253, - 196, 3, 2, 69, 82, 2, 237, 130, 9, 2, 76, 85, 6, 186, 196, 8, 77, 251, - 187, 2, 84, 10, 206, 16, 73, 171, 3, 65, 8, 58, 65, 128, 12, 5, 79, 84, - 84, 79, 77, 175, 184, 8, 76, 2, 145, 2, 2, 67, 75, 14, 48, 6, 79, 85, 66, - 76, 69, 32, 207, 210, 8, 65, 12, 40, 5, 65, 82, 82, 79, 87, 135, 19, 68, - 11, 26, 32, 171, 250, 8, 45, 6, 26, 87, 207, 200, 8, 70, 4, 25, 4, 73, - 84, 72, 32, 4, 146, 253, 10, 86, 79, 83, 4, 40, 4, 82, 79, 78, 84, 235, - 195, 8, 73, 2, 233, 194, 8, 14, 45, 84, 73, 76, 84, 69, 68, 32, 83, 72, - 65, 68, 79, 87, 30, 26, 65, 163, 199, 8, 69, 26, 48, 6, 82, 80, 79, 79, - 78, 32, 219, 229, 10, 78, 24, 88, 8, 79, 86, 69, 82, 32, 76, 69, 70, 45, - 10, 87, 73, 84, 72, 32, 66, 65, 82, 66, 32, 2, 157, 132, 8, 6, 84, 87, - 65, 82, 68, 83, 22, 44, 4, 68, 79, 87, 78, 173, 1, 2, 85, 80, 10, 26, 32, - 219, 204, 8, 87, 8, 76, 8, 65, 66, 79, 86, 69, 32, 76, 69, 18, 66, 154, - 196, 8, 70, 179, 5, 84, 2, 227, 2, 70, 2, 177, 218, 4, 7, 69, 76, 79, 87, - 32, 76, 79, 12, 26, 32, 175, 203, 8, 87, 10, 60, 6, 65, 66, 79, 86, 69, - 32, 142, 195, 8, 70, 179, 5, 84, 6, 22, 76, 155, 1, 82, 4, 32, 2, 69, 70, - 239, 216, 4, 79, 2, 253, 139, 2, 24, 84, 87, 65, 82, 68, 83, 32, 72, 65, - 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, 32, 66, 65, 82, 66, 2, 21, 3, 73, - 71, 72, 2, 105, 24, 84, 87, 65, 82, 68, 83, 32, 72, 65, 82, 80, 79, 79, - 78, 32, 87, 73, 84, 72, 32, 66, 65, 82, 66, 2, 11, 32, 2, 179, 236, 1, - 68, 2, 141, 1, 2, 69, 70, 2, 189, 197, 8, 3, 80, 69, 78, 4, 190, 201, 8, - 65, 181, 205, 1, 3, 85, 83, 72, 4, 36, 3, 73, 71, 72, 131, 210, 10, 79, - 2, 11, 84, 2, 171, 1, 45, 6, 32, 2, 81, 85, 203, 192, 8, 65, 4, 26, 73, - 227, 192, 8, 65, 2, 217, 200, 8, 2, 71, 71, 54, 38, 79, 60, 2, 82, 73, - 227, 4, 87, 2, 11, 80, 2, 11, 32, 2, 241, 184, 8, 4, 83, 72, 65, 68, 34, - 40, 5, 65, 78, 71, 76, 69, 255, 3, 80, 30, 56, 8, 45, 72, 69, 65, 68, 69, - 68, 32, 239, 204, 8, 32, 28, 52, 5, 65, 82, 82, 79, 87, 190, 197, 8, 68, - 39, 80, 25, 11, 32, 22, 64, 8, 79, 86, 69, 82, 32, 76, 69, 70, 22, 87, - 251, 192, 8, 84, 2, 171, 192, 8, 84, 18, 25, 4, 73, 84, 72, 32, 18, 128, - 1, 7, 68, 79, 85, 66, 76, 69, 32, 36, 7, 76, 79, 78, 71, 32, 84, 73, 218, - 192, 8, 66, 158, 1, 77, 34, 78, 34, 86, 35, 72, 4, 158, 251, 8, 72, 239, - 243, 1, 86, 4, 11, 80, 4, 11, 32, 4, 18, 68, 35, 85, 2, 169, 193, 8, 3, - 79, 87, 78, 2, 139, 193, 8, 80, 4, 21, 3, 76, 69, 32, 4, 138, 3, 68, 243, - 128, 10, 65, 18, 11, 79, 18, 56, 8, 45, 72, 69, 65, 68, 69, 68, 32, 163, - 195, 8, 32, 16, 76, 6, 65, 82, 82, 79, 87, 32, 213, 1, 8, 84, 82, 73, 80, - 76, 69, 32, 68, 14, 44, 5, 87, 73, 84, 72, 32, 167, 183, 8, 70, 12, 42, - 84, 238, 183, 7, 68, 243, 179, 3, 86, 8, 26, 65, 231, 194, 8, 82, 6, 17, - 2, 73, 76, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 150, 183, 7, 68, 243, - 179, 3, 86, 2, 137, 132, 1, 2, 65, 83, 8, 58, 65, 21, 10, 72, 73, 84, 69, - 32, 65, 82, 82, 79, 87, 2, 195, 191, 8, 86, 7, 11, 32, 4, 148, 189, 2, 4, - 70, 82, 79, 77, 147, 135, 6, 87, 19, 66, 32, 136, 1, 6, 69, 68, 32, 80, - 76, 65, 21, 3, 73, 78, 71, 12, 82, 66, 22, 80, 248, 196, 4, 2, 73, 78, - 26, 69, 238, 147, 3, 79, 239, 194, 2, 65, 2, 147, 135, 11, 85, 2, 11, 79, - 2, 171, 213, 10, 73, 2, 155, 227, 10, 78, 2, 253, 194, 3, 2, 32, 66, 4, - 24, 2, 70, 65, 75, 83, 2, 17, 2, 76, 76, 2, 21, 3, 73, 78, 71, 2, 217, - 226, 1, 2, 32, 68, 2, 233, 168, 3, 2, 79, 85, 8, 130, 151, 11, 69, 2, 73, - 2, 77, 3, 79, 126, 136, 2, 2, 67, 75, 20, 2, 76, 76, 188, 2, 4, 77, 65, - 78, 32, 194, 8, 79, 80, 2, 83, 69, 20, 6, 84, 65, 84, 69, 68, 32, 152, 3, - 3, 85, 78, 68, 214, 173, 3, 87, 200, 204, 3, 15, 65, 83, 84, 69, 68, 32, - 83, 87, 69, 69, 84, 32, 80, 79, 84, 205, 164, 2, 2, 66, 79, 5, 159, 248, - 10, 69, 10, 130, 1, 69, 64, 4, 32, 79, 70, 32, 101, 21, 73, 78, 71, 32, - 79, 78, 32, 84, 72, 69, 32, 70, 76, 79, 79, 82, 32, 76, 65, 85, 71, 6, - 60, 9, 68, 45, 85, 80, 32, 78, 69, 87, 83, 33, 2, 82, 32, 2, 11, 80, 2, - 215, 254, 1, 65, 4, 28, 3, 67, 79, 65, 23, 83, 2, 187, 218, 9, 83, 2, - 211, 94, 75, 2, 139, 193, 10, 72, 72, 140, 1, 6, 67, 69, 78, 84, 85, 82, - 22, 68, 100, 3, 81, 85, 73, 28, 8, 78, 85, 77, 69, 82, 65, 76, 32, 182, - 4, 83, 114, 85, 255, 219, 7, 65, 2, 187, 205, 5, 73, 6, 98, 69, 232, 5, - 5, 85, 80, 79, 78, 68, 61, 12, 73, 77, 73, 68, 73, 65, 32, 83, 69, 88, - 84, 85, 2, 229, 5, 3, 78, 65, 82, 48, 142, 1, 70, 136, 1, 3, 79, 78, 69, - 134, 1, 83, 66, 84, 232, 14, 10, 82, 69, 86, 69, 82, 83, 69, 68, 32, 79, - 210, 232, 2, 69, 143, 251, 6, 78, 14, 26, 73, 219, 149, 10, 79, 12, 36, - 3, 70, 84, 89, 187, 250, 2, 86, 7, 11, 32, 4, 222, 186, 5, 84, 185, 212, - 4, 5, 69, 65, 82, 76, 89, 11, 11, 32, 8, 50, 72, 41, 8, 84, 72, 79, 85, - 83, 65, 78, 68, 4, 185, 1, 6, 85, 78, 68, 82, 69, 68, 5, 197, 253, 3, 2, - 32, 67, 6, 32, 2, 73, 88, 171, 156, 9, 69, 5, 149, 141, 10, 2, 32, 76, - 10, 42, 69, 210, 248, 2, 87, 191, 163, 6, 72, 4, 11, 78, 5, 11, 32, 2, - 159, 184, 5, 84, 10, 46, 69, 181, 185, 7, 5, 73, 76, 73, 81, 85, 8, 60, - 2, 77, 85, 40, 5, 83, 84, 69, 82, 84, 21, 2, 88, 84, 2, 17, 2, 78, 67, 2, - 223, 184, 7, 73, 2, 199, 219, 7, 73, 4, 18, 65, 23, 85, 2, 171, 219, 7, - 78, 2, 143, 184, 7, 76, 4, 48, 6, 84, 32, 86, 69, 71, 69, 147, 209, 9, - 83, 2, 201, 192, 2, 2, 84, 65, 5, 243, 193, 9, 84, 10, 166, 2, 70, 32, - 11, 72, 69, 65, 86, 89, 32, 66, 76, 65, 67, 75, 52, 24, 76, 73, 71, 72, - 84, 32, 70, 79, 85, 82, 32, 80, 79, 73, 78, 84, 69, 68, 32, 66, 76, 65, - 67, 75, 0, 18, 87, 72, 73, 84, 69, 32, 70, 79, 85, 82, 32, 80, 79, 73, - 78, 84, 69, 68, 169, 53, 8, 67, 65, 80, 73, 84, 65, 76, 32, 2, 29, 5, 76, - 79, 82, 65, 76, 2, 213, 166, 9, 8, 32, 72, 69, 65, 82, 84, 32, 66, 2, - 149, 191, 9, 2, 32, 67, 16, 74, 32, 89, 14, 69, 68, 32, 83, 89, 77, 66, - 79, 76, 32, 70, 79, 82, 32, 4, 24, 2, 80, 85, 43, 84, 2, 11, 83, 2, 245, - 132, 10, 2, 72, 80, 2, 203, 217, 3, 65, 12, 68, 2, 83, 72, 230, 152, 6, - 67, 138, 198, 4, 70, 2, 76, 147, 17, 88, 4, 40, 4, 85, 65, 78, 71, 195, - 222, 10, 79, 2, 207, 239, 10, 88, 136, 2, 226, 1, 66, 20, 3, 71, 66, 89, - 40, 5, 76, 69, 45, 68, 69, 40, 3, 77, 73, 32, 154, 5, 78, 156, 26, 26, - 83, 83, 73, 65, 78, 32, 65, 83, 84, 82, 79, 76, 79, 71, 73, 67, 65, 76, - 32, 83, 89, 77, 66, 79, 76, 32, 231, 142, 5, 80, 2, 255, 228, 8, 76, 2, - 189, 249, 8, 5, 32, 70, 79, 79, 84, 2, 11, 76, 2, 149, 245, 5, 2, 65, 89, - 62, 68, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 102, 78, 231, 193, 2, 68, - 8, 40, 4, 79, 78, 69, 32, 199, 159, 9, 84, 6, 34, 84, 134, 252, 8, 72, - 47, 81, 2, 179, 253, 8, 72, 36, 33, 6, 85, 77, 66, 69, 82, 32, 36, 76, 5, - 69, 73, 71, 72, 84, 38, 70, 92, 2, 78, 73, 22, 79, 18, 83, 83, 84, 4, - 202, 132, 3, 32, 223, 249, 7, 89, 8, 18, 73, 35, 79, 4, 130, 2, 86, 247, - 142, 9, 70, 4, 136, 2, 2, 85, 82, 207, 142, 9, 82, 4, 77, 2, 78, 69, 2, - 167, 1, 78, 8, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, 4, 250, 130, 3, 32, - 151, 232, 7, 84, 10, 34, 72, 50, 87, 131, 172, 10, 69, 4, 32, 2, 82, 69, - 211, 142, 9, 73, 2, 39, 69, 4, 26, 79, 195, 142, 9, 69, 2, 231, 129, 3, - 32, 182, 1, 32, 3, 73, 67, 32, 147, 25, 78, 178, 1, 220, 1, 6, 66, 69, - 76, 71, 84, 72, 20, 4, 67, 82, 79, 83, 20, 7, 76, 69, 84, 84, 69, 82, 32, - 210, 22, 83, 24, 6, 77, 85, 76, 84, 73, 80, 208, 181, 7, 5, 65, 82, 76, - 65, 85, 181, 201, 1, 7, 84, 86, 73, 77, 65, 68, 85, 2, 147, 150, 9, 79, - 2, 227, 182, 7, 83, 166, 1, 202, 4, 65, 110, 67, 98, 68, 126, 69, 82, 70, - 222, 1, 71, 104, 2, 72, 65, 50, 73, 220, 1, 5, 74, 69, 82, 65, 78, 34, - 75, 58, 76, 234, 1, 79, 128, 1, 13, 82, 65, 73, 68, 79, 32, 82, 65, 68, - 32, 82, 69, 73, 34, 83, 176, 2, 16, 66, 69, 82, 75, 65, 78, 65, 78, 32, - 66, 69, 79, 82, 67, 32, 66, 144, 1, 12, 78, 65, 85, 68, 73, 90, 32, 78, - 89, 68, 32, 78, 110, 84, 194, 1, 87, 176, 87, 7, 85, 82, 85, 90, 32, 85, - 82, 192, 188, 2, 10, 77, 65, 78, 78, 65, 90, 32, 77, 65, 78, 180, 63, 13, - 80, 69, 82, 84, 72, 79, 32, 80, 69, 79, 82, 84, 72, 142, 189, 3, 89, 202, - 210, 3, 81, 2, 86, 2, 88, 3, 90, 8, 222, 4, 69, 174, 175, 6, 67, 0, 4, - 78, 83, 85, 90, 253, 179, 3, 9, 76, 71, 73, 90, 32, 69, 79, 76, 72, 11, - 46, 69, 30, 65, 145, 138, 7, 3, 87, 69, 79, 4, 26, 65, 247, 242, 10, 78, - 2, 247, 202, 9, 76, 11, 84, 6, 79, 84, 84, 69, 68, 45, 249, 226, 3, 9, - 65, 71, 65, 90, 32, 68, 65, 69, 71, 6, 134, 242, 10, 76, 2, 78, 3, 80, - 11, 240, 74, 7, 72, 87, 65, 90, 32, 69, 72, 150, 238, 9, 65, 206, 55, 84, - 63, 78, 12, 120, 13, 82, 65, 78, 75, 83, 32, 67, 65, 83, 75, 69, 84, 32, - 137, 165, 7, 11, 69, 72, 85, 32, 70, 69, 79, 72, 32, 70, 69, 10, 46, 65, - 142, 178, 10, 73, 2, 79, 207, 60, 69, 4, 26, 69, 207, 239, 10, 67, 2, - 207, 199, 9, 83, 9, 26, 69, 195, 182, 10, 65, 4, 52, 7, 66, 79, 32, 71, - 89, 70, 85, 231, 238, 10, 82, 2, 143, 238, 10, 32, 4, 236, 8, 2, 69, 71, - 13, 4, 71, 76, 65, 90, 12, 156, 1, 2, 78, 71, 20, 9, 83, 65, 90, 32, 73, - 83, 32, 73, 83, 20, 5, 87, 65, 90, 32, 69, 252, 179, 10, 10, 67, 69, 76, - 65, 78, 68, 73, 67, 45, 89, 3, 79, 5, 199, 201, 6, 87, 2, 219, 172, 10, - 83, 2, 199, 235, 10, 79, 2, 11, 32, 2, 183, 236, 10, 74, 7, 21, 3, 65, - 85, 78, 4, 242, 232, 10, 32, 155, 3, 65, 12, 120, 15, 65, 85, 75, 65, 90, - 32, 76, 65, 71, 85, 32, 76, 79, 71, 82, 21, 11, 79, 78, 71, 45, 66, 82, - 65, 78, 67, 72, 45, 2, 187, 225, 9, 32, 10, 64, 3, 65, 82, 32, 158, 4, - 72, 62, 77, 66, 79, 167, 172, 10, 89, 2, 195, 211, 10, 65, 15, 150, 5, - 83, 0, 12, 84, 72, 65, 76, 65, 78, 32, 69, 84, 72, 69, 76, 224, 228, 10, - 4, 80, 69, 78, 45, 14, 69, 2, 78, 3, 79, 2, 11, 68, 2, 155, 176, 10, 32, - 26, 150, 1, 72, 244, 2, 18, 73, 71, 69, 76, 32, 76, 79, 78, 71, 45, 66, - 82, 65, 78, 67, 72, 45, 83, 200, 239, 6, 5, 79, 87, 73, 76, 79, 147, 171, - 2, 84, 21, 45, 9, 79, 82, 84, 45, 84, 87, 73, 71, 45, 18, 102, 66, 58, - 72, 62, 77, 30, 78, 38, 79, 42, 83, 186, 1, 84, 128, 163, 6, 2, 65, 82, - 199, 135, 4, 89, 2, 33, 6, 74, 65, 82, 75, 65, 78, 2, 171, 170, 9, 32, 2, - 25, 4, 65, 71, 65, 76, 2, 11, 76, 2, 195, 228, 10, 32, 2, 169, 150, 3, 2, - 65, 68, 2, 193, 149, 10, 4, 65, 85, 68, 32, 2, 17, 2, 83, 83, 2, 247, - 197, 10, 32, 2, 11, 79, 2, 187, 239, 6, 76, 4, 116, 15, 72, 85, 82, 73, - 83, 65, 90, 32, 84, 72, 85, 82, 83, 32, 84, 33, 10, 73, 87, 65, 90, 32, - 84, 73, 82, 32, 84, 2, 11, 72, 2, 155, 217, 5, 79, 2, 17, 2, 89, 82, 2, - 223, 198, 10, 32, 5, 41, 8, 85, 78, 74, 79, 32, 87, 89, 78, 2, 11, 78, 2, - 159, 228, 9, 32, 2, 21, 3, 73, 78, 71, 2, 229, 159, 7, 2, 76, 69, 4, 200, - 249, 8, 16, 73, 78, 71, 32, 83, 72, 73, 82, 84, 32, 87, 73, 84, 72, 32, - 83, 211, 175, 1, 69, 12, 120, 3, 66, 73, 78, 2, 78, 28, 2, 81, 85, 0, 3, - 86, 73, 71, 166, 145, 7, 83, 229, 169, 1, 6, 84, 82, 69, 68, 69, 67, 2, - 161, 187, 8, 2, 79, 86, 2, 249, 186, 8, 2, 73, 78, 250, 39, 244, 1, 2, - 32, 73, 22, 65, 238, 25, 67, 138, 5, 69, 166, 11, 72, 190, 33, 73, 198, - 232, 1, 75, 154, 2, 76, 142, 9, 77, 166, 21, 78, 174, 2, 79, 158, 39, 80, - 172, 12, 2, 81, 85, 146, 70, 83, 38, 84, 250, 16, 85, 166, 43, 87, 186, - 1, 89, 251, 166, 5, 71, 2, 239, 184, 9, 78, 196, 2, 140, 2, 5, 70, 69, - 84, 89, 32, 36, 4, 71, 73, 84, 84, 30, 76, 112, 8, 77, 65, 82, 73, 84, - 65, 78, 32, 142, 14, 78, 190, 3, 84, 100, 2, 85, 82, 244, 239, 2, 2, 73, - 76, 234, 91, 88, 144, 134, 6, 15, 75, 69, 32, 66, 79, 84, 84, 76, 69, 32, - 65, 78, 68, 32, 67, 159, 98, 82, 4, 138, 254, 1, 86, 223, 221, 7, 80, 2, - 245, 208, 3, 2, 65, 82, 6, 18, 84, 75, 85, 4, 36, 3, 32, 83, 72, 139, - 186, 9, 73, 2, 11, 65, 2, 199, 156, 10, 75, 2, 255, 209, 9, 84, 122, 184, - 1, 7, 76, 69, 84, 84, 69, 82, 32, 198, 3, 77, 248, 2, 12, 80, 85, 78, 67, - 84, 85, 65, 84, 73, 79, 78, 32, 132, 4, 11, 86, 79, 87, 69, 76, 32, 83, - 73, 71, 78, 32, 203, 155, 4, 65, 44, 202, 1, 66, 32, 2, 68, 65, 22, 73, - 38, 75, 22, 76, 34, 83, 46, 84, 182, 2, 65, 196, 221, 5, 2, 71, 65, 222, - 148, 1, 82, 146, 141, 2, 90, 154, 81, 77, 172, 1, 2, 81, 85, 118, 78, - 226, 6, 89, 251, 101, 70, 4, 214, 186, 10, 73, 247, 25, 65, 2, 251, 194, - 9, 76, 6, 206, 214, 10, 78, 2, 84, 3, 89, 2, 251, 212, 9, 65, 2, 11, 65, - 2, 163, 194, 9, 66, 4, 152, 7, 3, 73, 78, 71, 223, 132, 9, 72, 6, 154, - 212, 9, 65, 134, 101, 73, 229, 10, 5, 83, 65, 65, 68, 73, 18, 96, 4, 65, - 82, 75, 32, 165, 1, 15, 79, 68, 73, 70, 73, 69, 82, 32, 76, 69, 84, 84, - 69, 82, 32, 12, 82, 68, 40, 2, 73, 78, 90, 69, 242, 2, 78, 197, 176, 8, - 5, 79, 67, 67, 76, 85, 2, 17, 2, 65, 71, 2, 159, 235, 8, 69, 5, 17, 2, - 45, 65, 2, 231, 209, 9, 76, 6, 46, 69, 180, 6, 2, 83, 72, 163, 204, 10, - 73, 2, 129, 217, 9, 11, 80, 69, 78, 84, 72, 69, 84, 73, 67, 32, 89, 28, - 130, 1, 65, 154, 1, 66, 22, 78, 30, 83, 130, 1, 90, 174, 162, 3, 84, 136, - 135, 7, 9, 77, 69, 76, 79, 68, 73, 67, 32, 81, 3, 81, 10, 76, 3, 70, 83, - 65, 34, 78, 28, 2, 84, 77, 145, 171, 10, 4, 82, 75, 65, 65, 2, 11, 65, 2, - 179, 208, 10, 81, 4, 26, 78, 187, 196, 5, 71, 2, 11, 65, 2, 143, 171, 10, - 65, 2, 201, 138, 3, 2, 69, 81, 4, 64, 4, 72, 73, 89, 89, 41, 8, 79, 70, - 32, 77, 65, 83, 72, 70, 2, 17, 2, 65, 65, 2, 163, 220, 8, 76, 2, 243, - 186, 9, 65, 4, 34, 65, 217, 219, 8, 2, 73, 81, 2, 255, 204, 9, 69, 30, - 92, 5, 76, 79, 78, 71, 32, 54, 79, 66, 83, 186, 224, 4, 65, 134, 236, 5, - 69, 2, 73, 3, 85, 10, 170, 225, 4, 65, 134, 236, 5, 69, 2, 73, 3, 85, 7, - 41, 8, 86, 69, 82, 76, 79, 78, 71, 32, 4, 203, 224, 4, 65, 4, 26, 72, - 171, 209, 5, 85, 2, 253, 139, 6, 3, 79, 82, 84, 10, 68, 8, 83, 45, 83, - 69, 82, 73, 70, 32, 145, 169, 10, 3, 68, 87, 73, 8, 44, 6, 72, 69, 65, - 86, 89, 32, 139, 2, 73, 6, 48, 3, 68, 79, 85, 81, 5, 76, 79, 87, 32, 68, - 4, 11, 66, 4, 21, 3, 76, 69, 32, 4, 84, 6, 84, 85, 82, 78, 69, 68, 23, - 67, 2, 21, 3, 79, 85, 66, 2, 17, 2, 76, 69, 2, 17, 2, 32, 67, 2, 33, 6, - 79, 77, 77, 65, 32, 81, 2, 205, 255, 8, 3, 85, 79, 84, 2, 157, 133, 10, - 10, 78, 84, 69, 82, 82, 79, 66, 65, 78, 71, 6, 48, 6, 69, 76, 76, 73, 84, - 69, 251, 189, 5, 85, 5, 25, 4, 32, 65, 78, 84, 2, 135, 145, 7, 69, 166, - 1, 52, 7, 65, 83, 72, 84, 82, 65, 32, 235, 187, 4, 79, 164, 1, 180, 1, 7, + 17, 2, 79, 87, 2, 129, 213, 8, 2, 69, 82, 6, 25, 4, 82, 79, 77, 32, 6, + 36, 3, 66, 65, 82, 187, 213, 8, 68, 5, 189, 1, 6, 32, 84, 79, 32, 66, 76, + 10, 56, 7, 72, 82, 79, 85, 71, 72, 32, 65, 3, 79, 32, 66, 6, 224, 224, 4, + 3, 83, 85, 80, 234, 207, 4, 71, 247, 149, 2, 88, 4, 26, 76, 139, 141, 11, + 65, 2, 153, 247, 9, 3, 65, 67, 75, 40, 140, 1, 6, 67, 79, 82, 78, 69, 82, + 26, 68, 98, 76, 86, 80, 30, 83, 38, 84, 138, 210, 8, 77, 38, 78, 122, 69, + 150, 153, 1, 72, 171, 165, 1, 86, 2, 209, 18, 2, 32, 68, 4, 11, 79, 4, + 40, 4, 84, 84, 69, 68, 203, 219, 7, 85, 2, 17, 2, 32, 83, 2, 163, 177, + 11, 84, 6, 26, 79, 231, 210, 8, 65, 4, 26, 87, 251, 194, 11, 79, 2, 157, + 201, 3, 2, 69, 82, 2, 193, 145, 9, 2, 76, 85, 6, 146, 211, 8, 77, 203, + 191, 2, 84, 10, 154, 16, 73, 171, 3, 65, 8, 58, 65, 204, 11, 5, 79, 84, + 84, 79, 77, 187, 199, 8, 76, 2, 145, 2, 2, 67, 75, 14, 48, 6, 79, 85, 66, + 76, 69, 32, 167, 225, 8, 65, 12, 40, 5, 65, 82, 82, 79, 87, 211, 18, 68, + 11, 26, 32, 143, 137, 9, 45, 6, 26, 87, 167, 215, 8, 70, 4, 25, 4, 73, + 84, 72, 32, 4, 186, 143, 11, 86, 79, 83, 4, 40, 4, 82, 79, 78, 84, 195, + 210, 8, 73, 2, 193, 209, 8, 14, 45, 84, 73, 76, 84, 69, 68, 32, 83, 72, + 65, 68, 79, 87, 30, 26, 65, 251, 213, 8, 69, 26, 48, 6, 82, 80, 79, 79, + 78, 32, 131, 248, 10, 78, 24, 80, 10, 87, 73, 84, 72, 32, 66, 65, 82, 66, + 32, 197, 152, 1, 4, 79, 86, 69, 82, 22, 44, 4, 68, 79, 87, 78, 173, 1, 2, + 85, 80, 10, 26, 32, 231, 219, 8, 87, 8, 76, 8, 65, 66, 79, 86, 69, 32, + 76, 69, 18, 66, 166, 211, 8, 70, 179, 5, 84, 2, 227, 2, 70, 2, 253, 222, + 4, 7, 69, 76, 79, 87, 32, 76, 79, 12, 26, 32, 187, 218, 8, 87, 10, 60, 6, + 65, 66, 79, 86, 69, 32, 154, 210, 8, 70, 179, 5, 84, 6, 22, 76, 155, 1, + 82, 4, 32, 2, 69, 70, 187, 221, 4, 79, 2, 213, 144, 2, 24, 84, 87, 65, + 82, 68, 83, 32, 72, 65, 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, 32, 66, + 65, 82, 66, 2, 21, 3, 73, 71, 72, 2, 105, 24, 84, 87, 65, 82, 68, 83, 32, + 72, 65, 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, 32, 66, 65, 82, 66, 2, + 11, 32, 2, 139, 241, 1, 68, 2, 141, 1, 2, 69, 70, 2, 201, 212, 8, 3, 80, + 69, 78, 4, 202, 216, 8, 65, 233, 206, 1, 3, 85, 83, 72, 4, 36, 3, 73, 71, + 72, 223, 228, 10, 79, 2, 11, 84, 2, 171, 1, 45, 6, 32, 2, 81, 85, 215, + 207, 8, 65, 4, 26, 73, 239, 207, 8, 65, 2, 229, 215, 8, 2, 71, 71, 54, + 38, 79, 60, 2, 82, 73, 227, 4, 87, 2, 11, 80, 2, 11, 32, 2, 253, 199, 8, + 4, 83, 72, 65, 68, 34, 40, 5, 65, 78, 71, 76, 69, 255, 3, 80, 30, 56, 8, + 45, 72, 69, 65, 68, 69, 68, 32, 251, 219, 8, 32, 28, 52, 5, 65, 82, 82, + 79, 87, 202, 212, 8, 68, 39, 80, 25, 11, 32, 22, 64, 8, 79, 86, 69, 82, + 32, 76, 69, 70, 22, 87, 135, 208, 8, 84, 2, 183, 207, 8, 84, 18, 25, 4, + 73, 84, 72, 32, 18, 128, 1, 7, 68, 79, 85, 66, 76, 69, 32, 36, 7, 76, 79, + 78, 71, 32, 84, 73, 230, 207, 8, 66, 158, 1, 77, 34, 78, 34, 86, 35, 72, + 4, 166, 138, 9, 72, 195, 247, 1, 86, 4, 11, 80, 4, 11, 32, 4, 18, 68, 35, + 85, 2, 181, 208, 8, 3, 79, 87, 78, 2, 151, 208, 8, 80, 4, 21, 3, 76, 69, + 32, 4, 138, 3, 68, 203, 145, 10, 65, 18, 11, 79, 18, 56, 8, 45, 72, 69, + 65, 68, 69, 68, 32, 175, 210, 8, 32, 16, 76, 6, 65, 82, 82, 79, 87, 32, + 213, 1, 8, 84, 82, 73, 80, 76, 69, 32, 68, 14, 44, 5, 87, 73, 84, 72, 32, + 179, 198, 8, 70, 12, 42, 84, 210, 198, 7, 68, 235, 183, 3, 86, 8, 26, 65, + 243, 209, 8, 82, 6, 17, 2, 73, 76, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, + 250, 197, 7, 68, 235, 183, 3, 86, 2, 249, 132, 1, 2, 65, 83, 8, 58, 65, + 21, 10, 72, 73, 84, 69, 32, 65, 82, 82, 79, 87, 2, 207, 206, 8, 86, 7, + 11, 32, 4, 216, 193, 2, 4, 70, 82, 79, 77, 219, 145, 6, 87, 19, 66, 32, + 136, 1, 6, 69, 68, 32, 80, 76, 65, 21, 3, 73, 78, 71, 12, 82, 66, 22, 80, + 212, 201, 4, 2, 73, 78, 26, 69, 154, 158, 3, 79, 195, 198, 2, 65, 2, 239, + 153, 11, 85, 2, 11, 79, 2, 135, 232, 10, 73, 2, 247, 245, 10, 78, 2, 209, + 199, 3, 2, 32, 66, 4, 24, 2, 70, 65, 75, 83, 2, 17, 2, 76, 76, 2, 21, 3, + 73, 78, 71, 2, 177, 231, 1, 2, 32, 68, 2, 189, 173, 3, 2, 79, 85, 8, 222, + 169, 11, 69, 2, 73, 2, 77, 3, 79, 126, 136, 2, 2, 67, 75, 20, 2, 76, 76, + 188, 2, 4, 77, 65, 78, 32, 194, 8, 79, 80, 2, 83, 69, 20, 6, 84, 65, 84, + 69, 68, 32, 152, 3, 3, 85, 78, 68, 170, 178, 3, 87, 252, 213, 3, 15, 65, + 83, 84, 69, 68, 32, 83, 87, 69, 69, 84, 32, 80, 79, 84, 185, 166, 2, 2, + 66, 79, 5, 251, 138, 11, 69, 10, 130, 1, 69, 64, 4, 32, 79, 70, 32, 101, + 21, 73, 78, 71, 32, 79, 78, 32, 84, 72, 69, 32, 70, 76, 79, 79, 82, 32, + 76, 65, 85, 71, 6, 60, 9, 68, 45, 85, 80, 32, 78, 69, 87, 83, 33, 2, 82, + 32, 2, 11, 80, 2, 175, 131, 2, 65, 4, 28, 3, 67, 79, 65, 23, 83, 2, 131, + 235, 9, 83, 2, 135, 95, 75, 2, 231, 211, 10, 72, 72, 140, 1, 6, 67, 69, + 78, 84, 85, 82, 22, 68, 100, 3, 81, 85, 73, 28, 8, 78, 85, 77, 69, 82, + 65, 76, 32, 182, 4, 83, 114, 85, 135, 235, 7, 65, 2, 159, 215, 5, 73, 6, + 98, 69, 232, 5, 5, 85, 80, 79, 78, 68, 61, 12, 73, 77, 73, 68, 73, 65, + 32, 83, 69, 88, 84, 85, 2, 229, 5, 3, 78, 65, 82, 48, 142, 1, 70, 136, 1, + 3, 79, 78, 69, 134, 1, 83, 66, 84, 232, 14, 10, 82, 69, 86, 69, 82, 83, + 69, 68, 32, 79, 150, 237, 2, 69, 163, 135, 7, 78, 14, 26, 73, 183, 168, + 10, 79, 12, 36, 3, 70, 84, 89, 255, 254, 2, 86, 7, 11, 32, 4, 194, 196, + 5, 84, 177, 221, 4, 5, 69, 65, 82, 76, 89, 11, 11, 32, 8, 50, 72, 41, 8, + 84, 72, 79, 85, 83, 65, 78, 68, 4, 185, 1, 6, 85, 78, 68, 82, 69, 68, 5, + 141, 130, 4, 2, 32, 67, 6, 32, 2, 73, 88, 159, 172, 9, 69, 5, 241, 159, + 10, 2, 32, 76, 10, 42, 69, 150, 253, 2, 87, 239, 174, 6, 72, 4, 11, 78, + 5, 11, 32, 2, 131, 194, 5, 84, 10, 46, 69, 189, 200, 7, 5, 73, 76, 73, + 81, 85, 8, 60, 2, 77, 85, 40, 5, 83, 84, 69, 82, 84, 21, 2, 88, 84, 2, + 17, 2, 78, 67, 2, 231, 199, 7, 73, 2, 207, 234, 7, 73, 4, 18, 65, 23, 85, + 2, 179, 234, 7, 78, 2, 151, 199, 7, 76, 4, 48, 6, 84, 32, 86, 69, 71, 69, + 219, 225, 9, 83, 2, 141, 197, 2, 2, 84, 65, 5, 179, 210, 9, 84, 10, 166, + 2, 70, 32, 11, 72, 69, 65, 86, 89, 32, 66, 76, 65, 67, 75, 52, 24, 76, + 73, 71, 72, 84, 32, 70, 79, 85, 82, 32, 80, 79, 73, 78, 84, 69, 68, 32, + 66, 76, 65, 67, 75, 0, 18, 87, 72, 73, 84, 69, 32, 70, 79, 85, 82, 32, + 80, 79, 73, 78, 84, 69, 68, 161, 53, 8, 67, 65, 80, 73, 84, 65, 76, 32, + 2, 29, 5, 76, 79, 82, 65, 76, 2, 201, 182, 9, 8, 32, 72, 69, 65, 82, 84, + 32, 66, 2, 213, 207, 9, 2, 32, 67, 16, 74, 32, 89, 14, 69, 68, 32, 83, + 89, 77, 66, 79, 76, 32, 70, 79, 82, 32, 4, 24, 2, 80, 85, 43, 84, 2, 11, + 83, 2, 209, 151, 10, 2, 72, 80, 2, 147, 222, 3, 65, 12, 68, 2, 83, 72, + 238, 162, 6, 67, 222, 206, 4, 70, 2, 76, 147, 17, 88, 4, 40, 4, 85, 65, + 78, 71, 159, 241, 10, 79, 2, 171, 130, 11, 88, 136, 2, 226, 1, 66, 20, 3, + 71, 66, 89, 40, 5, 76, 69, 45, 68, 69, 40, 3, 77, 73, 32, 154, 5, 78, + 156, 26, 26, 83, 83, 73, 65, 78, 32, 65, 83, 84, 82, 79, 76, 79, 71, 73, + 67, 65, 76, 32, 83, 89, 77, 66, 79, 76, 32, 203, 152, 5, 80, 2, 255, 243, + 8, 76, 2, 177, 137, 9, 5, 32, 70, 79, 79, 84, 2, 11, 76, 2, 165, 255, 5, + 2, 65, 89, 62, 68, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 102, 78, 171, + 198, 2, 68, 8, 40, 4, 79, 78, 69, 32, 187, 175, 9, 84, 6, 34, 84, 250, + 139, 9, 72, 47, 81, 2, 167, 141, 9, 72, 36, 33, 6, 85, 77, 66, 69, 82, + 32, 36, 76, 5, 69, 73, 71, 72, 84, 38, 70, 92, 2, 78, 73, 22, 79, 18, 83, + 83, 84, 4, 158, 137, 3, 32, 231, 135, 8, 89, 8, 18, 73, 35, 79, 4, 130, + 2, 86, 235, 158, 9, 70, 4, 136, 2, 2, 85, 82, 195, 158, 9, 82, 4, 77, 2, + 78, 69, 2, 167, 1, 78, 8, 40, 4, 69, 86, 69, 78, 1, 2, 73, 88, 4, 206, + 135, 3, 32, 159, 246, 7, 84, 10, 34, 72, 50, 87, 223, 190, 10, 69, 4, 32, + 2, 82, 69, 199, 158, 9, 73, 2, 39, 69, 4, 26, 79, 183, 158, 9, 69, 2, + 187, 134, 3, 32, 182, 1, 32, 3, 73, 67, 32, 147, 25, 78, 178, 1, 220, 1, + 6, 66, 69, 76, 71, 84, 72, 20, 4, 67, 82, 79, 83, 20, 7, 76, 69, 84, 84, + 69, 82, 32, 210, 22, 83, 24, 6, 77, 85, 76, 84, 73, 80, 216, 196, 7, 5, + 65, 82, 76, 65, 85, 161, 202, 1, 7, 84, 86, 73, 77, 65, 68, 85, 2, 135, + 166, 9, 79, 2, 235, 197, 7, 83, 166, 1, 202, 4, 65, 110, 67, 98, 68, 126, + 69, 82, 70, 222, 1, 71, 104, 2, 72, 65, 50, 73, 220, 1, 5, 74, 69, 82, + 65, 78, 34, 75, 58, 76, 234, 1, 79, 128, 1, 13, 82, 65, 73, 68, 79, 32, + 82, 65, 68, 32, 82, 69, 73, 34, 83, 176, 2, 16, 66, 69, 82, 75, 65, 78, + 65, 78, 32, 66, 69, 79, 82, 67, 32, 66, 144, 1, 12, 78, 65, 85, 68, 73, + 90, 32, 78, 89, 68, 32, 78, 110, 84, 194, 1, 87, 128, 91, 7, 85, 82, 85, + 90, 32, 85, 82, 196, 189, 2, 10, 77, 65, 78, 78, 65, 90, 32, 77, 65, 78, + 168, 63, 13, 80, 69, 82, 84, 72, 79, 32, 80, 69, 79, 82, 84, 72, 206, + 199, 3, 89, 158, 214, 3, 81, 2, 86, 2, 88, 3, 90, 8, 222, 4, 69, 174, + 185, 6, 67, 0, 4, 78, 83, 85, 90, 189, 186, 3, 9, 76, 71, 73, 90, 32, 69, + 79, 76, 72, 11, 46, 69, 30, 65, 245, 152, 7, 3, 87, 69, 79, 4, 26, 65, + 211, 133, 11, 78, 2, 191, 219, 9, 76, 11, 84, 6, 79, 84, 84, 69, 68, 45, + 193, 231, 3, 9, 65, 71, 65, 90, 32, 68, 65, 69, 71, 6, 226, 132, 11, 76, + 2, 78, 3, 80, 11, 136, 76, 7, 72, 87, 65, 90, 32, 69, 72, 218, 255, 9, + 65, 206, 55, 84, 63, 78, 12, 120, 13, 82, 65, 78, 75, 83, 32, 67, 65, 83, + 75, 69, 84, 32, 145, 180, 7, 11, 69, 72, 85, 32, 70, 69, 79, 72, 32, 70, + 69, 10, 46, 65, 234, 196, 10, 73, 2, 79, 207, 60, 69, 4, 26, 69, 171, + 130, 11, 67, 2, 151, 216, 9, 83, 9, 26, 69, 159, 201, 10, 65, 4, 52, 7, + 66, 79, 32, 71, 89, 70, 85, 195, 129, 11, 82, 2, 235, 128, 11, 32, 4, + 236, 8, 2, 69, 71, 13, 4, 71, 76, 65, 90, 12, 156, 1, 2, 78, 71, 20, 9, + 83, 65, 90, 32, 73, 83, 32, 73, 83, 20, 5, 87, 65, 90, 32, 69, 216, 198, + 10, 10, 67, 69, 76, 65, 78, 68, 73, 67, 45, 89, 3, 79, 5, 199, 211, 6, + 87, 2, 183, 191, 10, 83, 2, 163, 254, 10, 79, 2, 11, 32, 2, 147, 255, 10, + 74, 7, 21, 3, 65, 85, 78, 4, 206, 251, 10, 32, 155, 3, 65, 12, 120, 15, + 65, 85, 75, 65, 90, 32, 76, 65, 71, 85, 32, 76, 79, 71, 82, 21, 11, 79, + 78, 71, 45, 66, 82, 65, 78, 67, 72, 45, 2, 251, 241, 9, 32, 10, 64, 3, + 65, 82, 32, 158, 4, 72, 62, 77, 66, 79, 131, 191, 10, 89, 2, 159, 230, + 10, 65, 15, 150, 5, 83, 0, 12, 84, 72, 65, 76, 65, 78, 32, 69, 84, 72, + 69, 76, 188, 247, 10, 4, 80, 69, 78, 45, 14, 69, 2, 78, 3, 79, 2, 11, 68, + 2, 247, 194, 10, 32, 26, 150, 1, 72, 244, 2, 18, 73, 71, 69, 76, 32, 76, + 79, 78, 71, 45, 66, 82, 65, 78, 67, 72, 45, 83, 208, 253, 6, 5, 79, 87, + 73, 76, 79, 203, 173, 2, 84, 21, 45, 9, 79, 82, 84, 45, 84, 87, 73, 71, + 45, 18, 102, 66, 58, 72, 62, 77, 30, 78, 38, 79, 42, 83, 186, 1, 84, 128, + 173, 6, 2, 65, 82, 163, 144, 4, 89, 2, 33, 6, 74, 65, 82, 75, 65, 78, 2, + 243, 186, 9, 32, 2, 25, 4, 65, 71, 65, 76, 2, 11, 76, 2, 159, 247, 10, + 32, 2, 253, 154, 3, 2, 65, 68, 2, 157, 168, 10, 4, 65, 85, 68, 32, 2, 17, + 2, 83, 83, 2, 211, 216, 10, 32, 2, 11, 79, 2, 195, 253, 6, 76, 4, 116, + 15, 72, 85, 82, 73, 83, 65, 90, 32, 84, 72, 85, 82, 83, 32, 84, 33, 10, + 73, 87, 65, 90, 32, 84, 73, 82, 32, 84, 2, 11, 72, 2, 171, 227, 5, 79, 2, + 17, 2, 89, 82, 2, 187, 217, 10, 32, 5, 41, 8, 85, 78, 74, 79, 32, 87, 89, + 78, 2, 11, 78, 2, 251, 246, 9, 32, 2, 21, 3, 73, 78, 71, 2, 237, 174, 7, + 2, 76, 69, 4, 188, 137, 9, 16, 73, 78, 71, 32, 83, 72, 73, 82, 84, 32, + 87, 73, 84, 72, 32, 83, 187, 178, 1, 69, 12, 120, 3, 66, 73, 78, 2, 78, + 28, 2, 81, 85, 0, 3, 86, 73, 71, 174, 160, 7, 83, 229, 169, 1, 6, 84, 82, + 69, 68, 69, 67, 2, 169, 202, 8, 2, 79, 86, 2, 129, 202, 8, 2, 73, 78, + 200, 40, 244, 1, 2, 32, 73, 22, 65, 162, 26, 67, 138, 5, 69, 166, 11, 72, + 242, 36, 73, 162, 233, 1, 75, 154, 2, 76, 142, 9, 77, 166, 21, 78, 190, + 2, 79, 158, 39, 80, 172, 12, 2, 81, 85, 138, 70, 83, 38, 84, 138, 17, 85, + 150, 43, 87, 186, 1, 89, 247, 178, 5, 71, 2, 183, 201, 9, 78, 198, 2, + 132, 2, 5, 70, 69, 84, 89, 32, 36, 4, 71, 73, 84, 84, 30, 76, 112, 8, 77, + 65, 82, 73, 84, 65, 78, 32, 146, 14, 78, 190, 3, 84, 102, 85, 204, 244, + 2, 2, 73, 76, 242, 91, 88, 144, 148, 6, 15, 75, 69, 32, 66, 79, 84, 84, + 76, 69, 32, 65, 78, 68, 32, 67, 159, 98, 82, 4, 254, 251, 6, 86, 207, + 242, 2, 80, 2, 201, 213, 3, 2, 65, 82, 6, 18, 84, 75, 85, 4, 36, 3, 32, + 83, 72, 235, 202, 9, 73, 2, 11, 65, 2, 171, 175, 10, 75, 2, 227, 228, 9, + 84, 122, 184, 1, 7, 76, 69, 84, 84, 69, 82, 32, 198, 3, 77, 248, 2, 12, + 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 136, 4, 11, 86, 79, 87, + 69, 76, 32, 83, 73, 71, 78, 32, 203, 159, 4, 65, 44, 202, 1, 66, 32, 2, + 68, 65, 22, 73, 38, 75, 22, 76, 34, 83, 46, 84, 182, 2, 65, 212, 231, 5, + 2, 71, 65, 222, 153, 1, 82, 202, 142, 2, 90, 182, 83, 77, 172, 1, 2, 81, + 85, 118, 78, 226, 6, 89, 251, 101, 70, 4, 186, 205, 10, 73, 247, 25, 65, + 2, 151, 224, 9, 76, 6, 178, 233, 10, 78, 2, 84, 3, 89, 2, 223, 231, 9, + 65, 2, 11, 65, 2, 191, 223, 9, 66, 4, 156, 7, 3, 73, 78, 71, 163, 149, 9, + 72, 6, 254, 230, 9, 65, 134, 101, 73, 229, 10, 5, 83, 65, 65, 68, 73, 18, + 96, 4, 65, 82, 75, 32, 165, 1, 15, 79, 68, 73, 70, 73, 69, 82, 32, 76, + 69, 84, 84, 69, 82, 32, 12, 82, 68, 40, 2, 73, 78, 90, 69, 242, 2, 78, + 213, 191, 8, 5, 79, 67, 67, 76, 85, 2, 17, 2, 65, 71, 2, 155, 251, 8, 69, + 5, 17, 2, 45, 65, 2, 203, 228, 9, 76, 6, 46, 69, 184, 6, 2, 83, 72, 131, + 223, 10, 73, 2, 229, 235, 9, 11, 80, 69, 78, 84, 72, 69, 84, 73, 67, 32, + 89, 28, 130, 1, 65, 154, 1, 66, 22, 78, 30, 83, 134, 1, 90, 250, 166, 3, + 84, 156, 149, 7, 9, 77, 69, 76, 79, 68, 73, 67, 32, 81, 3, 81, 10, 76, 3, + 70, 83, 65, 34, 78, 28, 2, 84, 77, 245, 189, 10, 4, 82, 75, 65, 65, 2, + 11, 65, 2, 151, 227, 10, 81, 4, 26, 78, 211, 206, 5, 71, 2, 11, 65, 2, + 243, 189, 10, 65, 2, 165, 143, 3, 2, 69, 81, 4, 64, 4, 72, 73, 89, 89, + 45, 8, 79, 70, 32, 77, 65, 83, 72, 70, 2, 11, 65, 2, 11, 65, 2, 155, 236, + 8, 76, 2, 139, 216, 9, 65, 4, 34, 65, 209, 235, 8, 2, 73, 81, 2, 223, + 223, 9, 69, 30, 92, 5, 76, 79, 78, 71, 32, 54, 79, 66, 83, 174, 205, 6, + 65, 242, 145, 4, 69, 2, 73, 3, 85, 10, 158, 206, 6, 65, 242, 145, 4, 69, + 2, 73, 3, 85, 7, 41, 8, 86, 69, 82, 76, 79, 78, 71, 32, 4, 191, 205, 6, + 65, 4, 26, 72, 183, 219, 5, 85, 2, 129, 150, 6, 3, 79, 82, 84, 10, 68, 8, + 83, 45, 83, 69, 82, 73, 70, 32, 241, 187, 10, 3, 68, 87, 73, 8, 44, 6, + 72, 69, 65, 86, 89, 32, 139, 2, 73, 6, 48, 3, 68, 79, 85, 81, 5, 76, 79, + 87, 32, 68, 4, 11, 66, 4, 21, 3, 76, 69, 32, 4, 84, 6, 84, 85, 82, 78, + 69, 68, 23, 67, 2, 21, 3, 79, 85, 66, 2, 17, 2, 76, 69, 2, 17, 2, 32, 67, + 2, 33, 6, 79, 77, 77, 65, 32, 81, 2, 145, 144, 9, 3, 85, 79, 84, 2, 253, + 151, 10, 10, 78, 84, 69, 82, 82, 79, 66, 65, 78, 71, 6, 48, 6, 69, 76, + 76, 73, 84, 69, 143, 200, 5, 85, 5, 25, 4, 32, 65, 78, 84, 2, 147, 160, + 7, 69, 168, 1, 50, 82, 225, 141, 5, 6, 68, 73, 32, 82, 73, 89, 166, 1, + 52, 7, 65, 83, 72, 84, 82, 65, 32, 183, 191, 4, 79, 164, 1, 180, 1, 7, 76, 69, 84, 84, 69, 82, 32, 212, 1, 5, 83, 73, 71, 78, 32, 194, 21, 68, - 156, 246, 2, 16, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, - 32, 72, 139, 150, 2, 86, 100, 198, 235, 6, 65, 38, 68, 114, 84, 46, 86, - 186, 5, 85, 202, 141, 1, 79, 134, 60, 73, 42, 76, 250, 192, 1, 78, 46, + 176, 250, 2, 16, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, + 32, 72, 211, 155, 2, 86, 100, 154, 250, 6, 65, 38, 68, 114, 84, 46, 86, + 186, 5, 85, 206, 141, 1, 79, 238, 60, 73, 42, 76, 226, 195, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 162, 7, 69, 234, 61, 72, - 2, 77, 2, 82, 3, 89, 8, 210, 175, 6, 67, 202, 207, 3, 65, 239, 1, 86, 52, - 66, 65, 32, 4, 72, 79, 79, 76, 46, 79, 74, 82, 143, 194, 10, 73, 4, 166, - 175, 9, 76, 215, 18, 82, 5, 153, 182, 5, 6, 32, 83, 65, 84, 67, 72, 6, - 36, 3, 82, 80, 73, 183, 138, 9, 79, 4, 202, 242, 9, 79, 135, 18, 85, 36, - 66, 69, 72, 4, 73, 80, 84, 32, 198, 246, 1, 85, 255, 194, 6, 79, 4, 36, - 3, 87, 68, 82, 195, 241, 9, 69, 2, 11, 73, 2, 167, 131, 10, 86, 28, 80, + 2, 77, 2, 82, 3, 89, 8, 218, 184, 6, 67, 234, 216, 3, 65, 239, 1, 86, 52, + 66, 65, 32, 4, 72, 79, 79, 76, 46, 79, 74, 82, 183, 212, 10, 73, 4, 194, + 191, 9, 76, 227, 20, 82, 5, 245, 191, 5, 6, 32, 83, 65, 84, 67, 72, 6, + 36, 3, 82, 80, 73, 203, 154, 9, 79, 4, 242, 132, 10, 79, 135, 18, 85, 36, + 66, 69, 72, 4, 73, 80, 84, 32, 214, 250, 1, 85, 175, 206, 6, 79, 4, 36, + 3, 87, 68, 82, 235, 131, 10, 69, 2, 11, 73, 2, 207, 149, 10, 86, 28, 80, 8, 67, 65, 80, 73, 84, 65, 76, 32, 86, 76, 81, 6, 83, 77, 65, 76, 76, 32, - 18, 170, 192, 10, 66, 2, 69, 2, 70, 2, 72, 2, 73, 2, 76, 2, 77, 2, 80, 3, - 82, 2, 37, 7, 73, 71, 65, 84, 85, 82, 69, 2, 11, 32, 2, 193, 251, 9, 2, - 69, 84, 8, 134, 191, 10, 69, 2, 71, 2, 76, 3, 79, 220, 1, 130, 2, 65, 30, + 18, 210, 210, 10, 66, 2, 69, 2, 70, 2, 72, 2, 73, 2, 76, 2, 77, 2, 80, 3, + 82, 2, 37, 7, 73, 71, 65, 84, 85, 82, 69, 2, 11, 32, 2, 233, 141, 10, 2, + 69, 84, 8, 174, 209, 10, 69, 2, 71, 2, 76, 3, 79, 220, 1, 130, 2, 65, 30, 67, 74, 69, 36, 5, 71, 77, 69, 78, 84, 28, 2, 77, 73, 172, 1, 8, 80, 65, - 82, 65, 84, 69, 68, 32, 138, 4, 82, 158, 1, 83, 68, 2, 84, 32, 140, 131, - 5, 8, 87, 73, 78, 71, 32, 78, 69, 69, 146, 140, 3, 88, 254, 104, 68, 213, - 160, 1, 2, 76, 70, 4, 210, 188, 10, 76, 3, 84, 6, 34, 84, 133, 217, 5, 2, - 79, 78, 4, 222, 187, 6, 73, 219, 199, 3, 79, 4, 130, 220, 1, 68, 195, - 132, 1, 45, 23, 221, 187, 4, 2, 69, 68, 6, 176, 80, 28, 68, 73, 82, 69, + 82, 65, 84, 69, 68, 32, 138, 4, 82, 158, 1, 83, 68, 2, 84, 32, 168, 140, + 5, 8, 87, 73, 78, 71, 32, 78, 69, 69, 202, 145, 3, 88, 190, 106, 68, 233, + 162, 1, 2, 76, 70, 4, 250, 206, 10, 76, 3, 84, 6, 34, 84, 245, 226, 5, 2, + 79, 78, 4, 178, 201, 6, 73, 175, 204, 3, 79, 4, 166, 224, 1, 68, 191, + 132, 1, 45, 23, 189, 191, 4, 2, 69, 68, 6, 212, 84, 28, 68, 73, 82, 69, 67, 84, 32, 80, 82, 79, 68, 85, 67, 84, 32, 87, 73, 84, 72, 32, 66, 79, - 84, 84, 79, 77, 32, 67, 252, 197, 7, 3, 83, 69, 88, 255, 212, 1, 67, 158, - 1, 48, 6, 66, 76, 79, 67, 75, 32, 191, 166, 9, 83, 156, 1, 88, 9, 81, 85, + 84, 84, 79, 77, 32, 67, 172, 208, 7, 3, 83, 69, 88, 211, 216, 1, 67, 158, + 1, 48, 6, 66, 76, 79, 67, 75, 32, 203, 182, 9, 83, 156, 1, 88, 9, 81, 85, 65, 68, 82, 65, 78, 84, 45, 129, 1, 8, 83, 69, 88, 84, 65, 78, 84, 45, - 30, 42, 49, 38, 50, 30, 51, 131, 184, 10, 52, 17, 34, 50, 30, 51, 131, - 184, 10, 52, 9, 26, 51, 131, 184, 10, 52, 5, 255, 183, 10, 52, 126, 58, - 49, 54, 50, 46, 51, 38, 52, 30, 53, 147, 182, 10, 54, 65, 50, 50, 46, 51, - 38, 52, 30, 53, 147, 182, 10, 54, 33, 42, 51, 38, 52, 30, 53, 147, 182, - 10, 54, 17, 34, 52, 30, 53, 147, 182, 10, 54, 9, 26, 53, 147, 182, 10, - 54, 5, 143, 182, 10, 54, 4, 120, 2, 86, 73, 241, 170, 2, 22, 73, 79, 85, + 30, 42, 49, 38, 50, 30, 51, 171, 202, 10, 52, 17, 34, 50, 30, 51, 171, + 202, 10, 52, 9, 26, 51, 171, 202, 10, 52, 5, 167, 202, 10, 52, 126, 58, + 49, 54, 50, 46, 51, 38, 52, 30, 53, 187, 200, 10, 54, 65, 50, 50, 46, 51, + 38, 52, 30, 53, 187, 200, 10, 54, 33, 42, 51, 38, 52, 30, 53, 187, 200, + 10, 54, 17, 34, 52, 30, 53, 187, 200, 10, 54, 9, 26, 53, 187, 200, 10, + 54, 5, 183, 200, 10, 54, 4, 120, 2, 86, 73, 129, 175, 2, 22, 73, 79, 85, 83, 32, 70, 65, 67, 69, 32, 87, 73, 84, 72, 32, 83, 89, 77, 66, 79, 76, - 83, 2, 11, 67, 2, 175, 243, 9, 69, 4, 52, 7, 81, 85, 73, 81, 85, 65, 68, - 219, 253, 8, 65, 2, 91, 82, 4, 64, 10, 84, 82, 65, 78, 83, 77, 73, 84, - 32, 83, 195, 173, 6, 77, 2, 11, 84, 2, 211, 236, 8, 65, 242, 2, 102, 65, - 246, 19, 73, 102, 79, 134, 11, 69, 70, 82, 136, 131, 9, 5, 85, 70, 70, - 76, 69, 167, 143, 1, 89, 176, 2, 164, 1, 12, 68, 79, 87, 69, 68, 32, 87, + 83, 2, 11, 67, 2, 215, 133, 10, 69, 4, 52, 7, 81, 85, 73, 81, 85, 65, 68, + 239, 141, 9, 65, 2, 91, 82, 4, 64, 10, 84, 82, 65, 78, 83, 77, 73, 84, + 32, 83, 151, 187, 6, 77, 2, 11, 84, 2, 223, 252, 8, 65, 134, 3, 102, 65, + 218, 20, 73, 102, 79, 214, 13, 69, 70, 82, 224, 143, 9, 5, 85, 70, 70, + 76, 69, 195, 145, 1, 89, 192, 2, 164, 1, 12, 68, 79, 87, 69, 68, 32, 87, 72, 73, 84, 69, 32, 56, 9, 76, 76, 79, 87, 32, 80, 65, 78, 32, 62, 82, - 210, 9, 86, 172, 184, 7, 2, 77, 82, 147, 230, 1, 75, 6, 162, 223, 8, 67, - 206, 11, 83, 237, 4, 3, 76, 65, 84, 2, 17, 2, 79, 70, 2, 17, 2, 32, 70, - 2, 231, 249, 6, 79, 194, 1, 40, 4, 65, 68, 65, 32, 255, 175, 10, 75, 192, + 182, 10, 86, 160, 198, 7, 2, 77, 82, 227, 233, 1, 75, 6, 174, 239, 8, 67, + 206, 11, 83, 245, 4, 3, 76, 65, 84, 2, 17, 2, 79, 70, 2, 17, 2, 32, 70, + 2, 187, 136, 7, 79, 210, 1, 40, 4, 65, 68, 65, 32, 167, 194, 10, 75, 208, 1, 162, 1, 68, 46, 69, 110, 72, 34, 76, 246, 1, 83, 212, 2, 6, 86, 79, - 87, 69, 76, 32, 250, 189, 4, 65, 228, 211, 1, 7, 67, 79, 78, 84, 73, 78, - 85, 163, 134, 4, 79, 24, 238, 209, 6, 79, 66, 65, 147, 235, 1, 73, 4, 84, - 15, 88, 84, 82, 65, 32, 83, 72, 79, 82, 84, 32, 86, 79, 87, 69, 215, 242, - 8, 75, 2, 139, 236, 9, 76, 2, 177, 253, 9, 3, 69, 65, 68, 96, 33, 6, 69, - 84, 84, 69, 82, 32, 96, 214, 210, 6, 65, 38, 68, 114, 84, 46, 86, 186, 5, - 85, 206, 201, 1, 73, 42, 76, 250, 192, 1, 78, 46, 83, 82, 66, 2, 67, 2, + 87, 69, 76, 32, 170, 199, 4, 65, 188, 211, 1, 7, 67, 79, 78, 84, 73, 78, + 85, 195, 143, 4, 79, 24, 194, 224, 6, 79, 66, 65, 255, 235, 1, 73, 4, 84, + 15, 88, 84, 82, 65, 32, 83, 72, 79, 82, 84, 32, 86, 79, 87, 69, 235, 130, + 9, 75, 2, 179, 254, 9, 76, 2, 217, 143, 10, 3, 69, 65, 68, 96, 33, 6, 69, + 84, 84, 69, 82, 32, 96, 170, 225, 6, 65, 38, 68, 114, 84, 46, 86, 186, 5, + 85, 186, 202, 1, 73, 42, 76, 226, 195, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 77, 2, 82, 2, 89, 186, 2, 69, 3, - 79, 30, 70, 65, 38, 69, 56, 4, 73, 71, 78, 32, 233, 164, 9, 3, 85, 84, - 82, 2, 153, 233, 9, 4, 78, 68, 72, 73, 6, 180, 201, 2, 5, 67, 84, 73, 79, - 78, 191, 179, 4, 80, 20, 106, 73, 190, 134, 5, 83, 158, 142, 1, 67, 98, - 78, 242, 60, 65, 174, 158, 1, 74, 150, 3, 85, 167, 242, 1, 86, 2, 37, 7, - 78, 86, 69, 82, 84, 69, 68, 2, 173, 148, 6, 2, 32, 67, 30, 60, 6, 77, 79, - 68, 73, 70, 73, 21, 5, 83, 73, 71, 78, 32, 2, 151, 137, 6, 69, 28, 82, - 80, 226, 211, 6, 65, 38, 85, 22, 86, 186, 201, 1, 73, 222, 137, 2, 69, 3, - 79, 2, 57, 12, 82, 73, 83, 72, 84, 72, 65, 77, 65, 84, 82, 65, 2, 155, - 144, 10, 32, 98, 72, 3, 69, 68, 32, 21, 11, 73, 65, 78, 32, 76, 69, 84, - 84, 69, 82, 32, 2, 147, 233, 9, 73, 96, 158, 2, 65, 120, 3, 67, 72, 85, - 22, 69, 70, 72, 46, 73, 46, 76, 22, 77, 38, 79, 94, 80, 18, 82, 22, 83, - 38, 84, 64, 2, 87, 79, 36, 2, 89, 69, 156, 235, 4, 2, 74, 85, 234, 222, - 2, 68, 202, 13, 90, 242, 87, 70, 182, 6, 71, 150, 45, 66, 246, 11, 75, - 218, 21, 86, 246, 25, 78, 167, 128, 1, 85, 16, 82, 82, 174, 234, 9, 73, - 234, 25, 68, 162, 8, 71, 2, 87, 198, 21, 83, 147, 1, 72, 4, 130, 151, 9, - 82, 135, 140, 1, 69, 2, 187, 128, 10, 82, 8, 38, 65, 206, 233, 9, 82, - 139, 56, 71, 4, 166, 162, 10, 82, 3, 84, 4, 200, 167, 8, 2, 65, 45, 203, - 169, 1, 85, 6, 254, 209, 9, 65, 142, 57, 67, 215, 22, 70, 2, 243, 153, 8, - 79, 4, 154, 149, 5, 69, 155, 244, 3, 73, 12, 70, 79, 130, 151, 9, 73, - 138, 109, 85, 150, 25, 65, 154, 3, 78, 3, 82, 2, 223, 137, 10, 90, 2, - 175, 13, 69, 2, 215, 254, 8, 79, 4, 194, 255, 8, 85, 187, 160, 1, 79, 6, - 26, 72, 147, 131, 10, 79, 4, 242, 250, 5, 73, 131, 147, 4, 69, 4, 226, - 149, 9, 79, 183, 137, 1, 69, 4, 242, 158, 10, 65, 3, 87, 10, 78, 69, 134, - 229, 3, 70, 252, 120, 6, 78, 84, 79, 32, 83, 72, 139, 192, 5, 80, 2, 231, - 215, 9, 76, 46, 252, 1, 2, 79, 84, 32, 6, 80, 80, 73, 78, 71, 32, 72, 2, - 82, 84, 176, 8, 7, 85, 76, 68, 69, 82, 69, 68, 220, 239, 1, 24, 67, 75, - 69, 68, 32, 70, 65, 67, 69, 32, 87, 73, 84, 72, 32, 69, 88, 80, 76, 79, - 68, 73, 78, 71, 158, 150, 3, 86, 251, 206, 4, 87, 2, 221, 133, 8, 3, 73, - 78, 71, 4, 36, 3, 84, 82, 79, 155, 233, 5, 66, 2, 11, 76, 2, 163, 129, 8, - 76, 32, 102, 32, 248, 5, 12, 72, 65, 78, 68, 32, 70, 79, 82, 77, 65, 84, - 32, 254, 171, 6, 67, 179, 232, 3, 83, 20, 154, 2, 66, 92, 11, 83, 76, 65, - 78, 84, 69, 68, 32, 78, 79, 82, 196, 1, 22, 82, 73, 71, 72, 84, 87, 65, - 82, 68, 83, 32, 65, 82, 82, 79, 87, 32, 65, 66, 79, 86, 69, 28, 7, 85, - 80, 32, 84, 65, 67, 75, 128, 1, 4, 76, 69, 70, 84, 149, 159, 2, 9, 68, - 79, 87, 78, 32, 84, 65, 67, 75, 4, 88, 14, 65, 67, 75, 83, 76, 65, 78, - 84, 69, 68, 32, 83, 79, 85, 33, 4, 69, 78, 84, 32, 2, 11, 84, 2, 203, - 252, 8, 72, 2, 245, 36, 37, 65, 82, 82, 79, 87, 32, 80, 79, 73, 78, 84, - 73, 78, 71, 32, 68, 79, 87, 78, 87, 65, 82, 68, 83, 32, 84, 72, 69, 78, - 32, 78, 79, 82, 84, 72, 32, 69, 2, 229, 249, 5, 2, 32, 76, 7, 11, 32, 4, - 76, 13, 65, 66, 79, 86, 69, 32, 83, 72, 79, 82, 84, 32, 68, 159, 131, 2, - 87, 2, 11, 79, 2, 11, 87, 2, 11, 78, 2, 11, 32, 2, 191, 249, 6, 84, 8, + 79, 30, 70, 65, 38, 69, 56, 4, 73, 71, 78, 32, 145, 183, 9, 3, 85, 84, + 82, 2, 193, 251, 9, 4, 78, 68, 72, 73, 6, 212, 205, 2, 5, 67, 84, 73, 79, + 78, 243, 189, 4, 80, 20, 106, 73, 154, 144, 5, 83, 202, 141, 1, 67, 98, + 78, 190, 66, 65, 190, 158, 1, 74, 150, 3, 85, 235, 245, 1, 86, 2, 37, 7, + 78, 86, 69, 82, 84, 69, 68, 2, 181, 157, 6, 2, 32, 67, 46, 60, 6, 77, 79, + 68, 73, 70, 73, 21, 5, 83, 73, 71, 78, 32, 2, 155, 146, 6, 69, 44, 110, + 67, 42, 79, 34, 80, 162, 183, 4, 85, 194, 229, 1, 83, 242, 68, 65, 58, + 86, 166, 202, 1, 73, 199, 140, 2, 69, 4, 193, 157, 6, 5, 65, 78, 68, 82, + 65, 7, 186, 162, 10, 79, 215, 22, 69, 2, 57, 12, 82, 73, 83, 72, 84, 72, + 65, 77, 65, 84, 82, 65, 2, 223, 161, 10, 32, 98, 72, 3, 69, 68, 32, 21, + 11, 73, 65, 78, 32, 76, 69, 84, 84, 69, 82, 32, 2, 215, 250, 9, 73, 96, + 158, 2, 65, 120, 3, 67, 72, 85, 22, 69, 70, 72, 46, 73, 46, 76, 22, 77, + 38, 79, 94, 80, 18, 82, 22, 83, 38, 84, 64, 2, 87, 79, 36, 2, 89, 69, + 212, 243, 4, 2, 74, 85, 166, 228, 2, 68, 202, 13, 90, 218, 88, 70, 182, + 6, 71, 234, 45, 66, 246, 11, 75, 234, 21, 86, 250, 27, 78, 167, 128, 1, + 85, 16, 82, 82, 242, 251, 9, 73, 234, 25, 68, 162, 8, 71, 2, 87, 198, 21, + 83, 147, 1, 72, 4, 170, 166, 9, 82, 163, 142, 1, 69, 2, 255, 145, 10, 82, + 8, 38, 65, 146, 251, 9, 82, 139, 56, 71, 4, 234, 179, 10, 82, 3, 84, 4, + 164, 182, 8, 2, 65, 45, 179, 172, 1, 85, 6, 194, 227, 9, 65, 142, 57, 67, + 215, 22, 70, 2, 207, 168, 8, 79, 4, 146, 158, 5, 69, 227, 250, 3, 73, 12, + 70, 79, 170, 166, 9, 73, 166, 111, 85, 150, 25, 65, 154, 3, 78, 3, 82, 2, + 163, 155, 10, 90, 2, 255, 15, 69, 2, 151, 142, 9, 79, 4, 130, 143, 9, 85, + 191, 162, 1, 79, 6, 26, 72, 215, 148, 10, 79, 4, 218, 131, 6, 73, 223, + 155, 4, 69, 4, 138, 165, 9, 79, 211, 139, 1, 69, 4, 182, 176, 10, 65, 3, + 87, 10, 78, 69, 186, 232, 3, 70, 148, 126, 6, 78, 84, 79, 32, 83, 72, + 131, 201, 5, 80, 2, 171, 233, 9, 76, 50, 252, 1, 2, 79, 84, 32, 6, 80, + 80, 73, 78, 71, 32, 72, 2, 82, 84, 128, 11, 7, 85, 76, 68, 69, 82, 69, + 68, 184, 240, 1, 24, 67, 75, 69, 68, 32, 70, 65, 67, 69, 32, 87, 73, 84, + 72, 32, 69, 88, 80, 76, 79, 68, 73, 78, 71, 234, 155, 3, 86, 199, 215, 4, + 87, 2, 197, 147, 8, 3, 73, 78, 71, 4, 36, 3, 84, 82, 79, 131, 242, 5, 66, + 2, 11, 76, 2, 139, 143, 8, 76, 36, 102, 32, 200, 8, 12, 72, 65, 78, 68, + 32, 70, 79, 82, 77, 65, 84, 32, 250, 182, 6, 67, 171, 236, 3, 83, 24, + 242, 1, 66, 92, 11, 83, 76, 65, 78, 84, 69, 68, 32, 78, 79, 82, 196, 1, + 4, 76, 69, 70, 84, 156, 1, 11, 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, + 32, 248, 1, 7, 85, 80, 32, 84, 65, 67, 75, 129, 161, 2, 9, 68, 79, 87, + 78, 32, 84, 65, 67, 75, 4, 88, 14, 65, 67, 75, 83, 76, 65, 78, 84, 69, + 68, 32, 83, 79, 85, 33, 4, 69, 78, 84, 32, 2, 11, 84, 2, 179, 140, 9, 72, + 2, 221, 40, 37, 65, 82, 82, 79, 87, 32, 80, 79, 73, 78, 84, 73, 78, 71, + 32, 68, 79, 87, 78, 87, 65, 82, 68, 83, 32, 84, 72, 69, 78, 32, 78, 79, + 82, 84, 72, 32, 69, 4, 116, 24, 87, 65, 82, 68, 83, 32, 72, 65, 82, 80, + 79, 79, 78, 32, 65, 66, 79, 86, 69, 32, 76, 79, 78, 71, 171, 3, 32, 2, + 237, 1, 5, 32, 82, 73, 71, 72, 4, 112, 11, 65, 82, 82, 79, 87, 32, 65, + 66, 79, 86, 69, 29, 13, 72, 65, 82, 80, 79, 79, 78, 32, 65, 66, 79, 86, + 69, 2, 157, 128, 6, 2, 32, 76, 2, 29, 5, 32, 76, 79, 78, 71, 2, 25, 4, + 32, 76, 69, 70, 2, 153, 250, 6, 6, 84, 87, 65, 82, 68, 83, 7, 11, 32, 4, + 76, 13, 65, 66, 79, 86, 69, 32, 83, 72, 79, 82, 84, 32, 68, 251, 131, 2, + 87, 2, 11, 79, 2, 11, 87, 2, 11, 78, 2, 11, 32, 2, 223, 132, 7, 84, 8, 120, 10, 67, 79, 78, 84, 73, 78, 85, 73, 78, 71, 0, 6, 76, 69, 84, 84, - 69, 82, 40, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, 205, 178, 3, 5, 32, 79, - 86, 69, 82, 2, 21, 3, 32, 83, 84, 2, 227, 146, 10, 69, 2, 25, 4, 32, 79, - 80, 69, 2, 247, 133, 9, 78, 4, 26, 73, 191, 145, 10, 85, 2, 131, 146, 10, - 77, 159, 14, 174, 1, 68, 168, 19, 2, 71, 78, 204, 181, 1, 6, 77, 73, 76, - 65, 82, 32, 158, 2, 78, 202, 24, 88, 241, 226, 6, 15, 76, 72, 79, 85, 69, - 84, 84, 69, 32, 79, 70, 32, 74, 65, 80, 200, 1, 64, 5, 68, 72, 65, 77, - 32, 133, 17, 6, 69, 87, 65, 89, 83, 32, 184, 1, 202, 1, 69, 68, 7, 76, - 69, 84, 84, 69, 82, 32, 176, 4, 15, 82, 69, 80, 69, 84, 73, 84, 73, 79, - 78, 32, 77, 65, 82, 75, 50, 83, 164, 8, 11, 86, 79, 87, 69, 76, 32, 83, - 73, 71, 78, 32, 243, 163, 6, 68, 2, 37, 7, 78, 68, 32, 79, 70, 32, 84, 2, - 189, 195, 9, 2, 69, 88, 102, 214, 1, 65, 98, 84, 186, 177, 6, 68, 158, 1, - 86, 186, 5, 85, 206, 201, 1, 73, 162, 193, 1, 78, 46, 83, 82, 66, 2, 67, - 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 89, 186, - 2, 69, 3, 79, 11, 72, 8, 76, 84, 69, 82, 78, 65, 84, 69, 202, 139, 10, - 65, 2, 73, 3, 85, 2, 223, 230, 9, 32, 14, 134, 1, 72, 204, 225, 5, 19, - 87, 79, 45, 67, 73, 82, 67, 76, 69, 32, 65, 76, 84, 69, 82, 78, 65, 84, - 69, 162, 225, 3, 84, 195, 71, 65, 4, 152, 202, 9, 20, 82, 69, 69, 45, 67, - 73, 82, 67, 76, 69, 32, 65, 76, 84, 69, 82, 78, 65, 84, 69, 147, 64, 65, - 6, 11, 45, 6, 174, 137, 10, 49, 2, 50, 3, 51, 44, 38, 69, 181, 7, 4, 73, - 71, 78, 32, 32, 96, 11, 67, 84, 73, 79, 78, 32, 77, 65, 82, 75, 32, 177, - 6, 8, 80, 65, 82, 65, 84, 79, 82, 32, 28, 80, 11, 68, 79, 85, 66, 76, 69, - 32, 82, 73, 78, 71, 57, 5, 87, 73, 84, 72, 32, 5, 11, 32, 2, 129, 219, 8, - 6, 87, 73, 84, 72, 32, 82, 24, 212, 1, 12, 67, 73, 82, 67, 76, 69, 83, - 32, 65, 78, 68, 32, 116, 5, 81, 85, 65, 68, 82, 0, 4, 83, 69, 80, 84, 12, - 16, 82, 65, 89, 83, 32, 65, 78, 68, 32, 68, 79, 84, 84, 69, 68, 32, 46, - 68, 45, 3, 84, 82, 73, 6, 60, 4, 70, 79, 85, 82, 0, 3, 84, 87, 79, 195, - 216, 8, 82, 2, 169, 196, 6, 8, 32, 69, 78, 67, 76, 79, 83, 85, 2, 83, 85, - 6, 42, 68, 28, 3, 84, 82, 73, 215, 1, 67, 2, 197, 1, 3, 79, 85, 66, 2, - 171, 1, 80, 6, 52, 9, 68, 69, 78, 84, 32, 65, 78, 68, 32, 103, 80, 4, - 116, 6, 68, 79, 84, 84, 69, 68, 49, 14, 85, 45, 83, 72, 65, 80, 69, 68, - 32, 79, 82, 78, 65, 77, 2, 17, 2, 76, 69, 2, 17, 2, 32, 67, 2, 25, 4, 82, - 69, 83, 67, 2, 251, 185, 1, 69, 4, 150, 224, 8, 66, 131, 81, 68, 12, 210, - 222, 4, 83, 158, 142, 1, 67, 98, 78, 234, 206, 3, 65, 239, 1, 86, 26, 74, - 65, 94, 86, 154, 172, 6, 85, 206, 201, 1, 73, 222, 137, 2, 69, 3, 79, 10, - 240, 172, 6, 10, 76, 84, 69, 82, 78, 65, 84, 69, 32, 85, 170, 211, 3, 65, - 2, 73, 3, 85, 4, 11, 79, 4, 33, 6, 67, 65, 76, 73, 67, 32, 4, 199, 172, - 6, 82, 16, 56, 5, 66, 76, 65, 67, 75, 1, 5, 87, 72, 73, 84, 69, 8, 11, - 32, 8, 70, 82, 24, 3, 76, 69, 70, 12, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, - 21, 3, 73, 71, 72, 2, 11, 84, 2, 225, 92, 6, 32, 80, 79, 73, 78, 84, 194, - 10, 96, 8, 87, 82, 73, 84, 73, 78, 71, 32, 133, 239, 1, 10, 32, 79, 70, - 32, 84, 72, 69, 32, 72, 79, 192, 10, 136, 3, 4, 65, 73, 82, 32, 192, 1, - 2, 66, 82, 102, 67, 138, 1, 68, 218, 4, 69, 242, 6, 70, 244, 3, 4, 87, - 65, 76, 76, 138, 1, 72, 234, 77, 76, 212, 6, 2, 77, 79, 222, 42, 78, 218, - 1, 82, 202, 7, 83, 162, 5, 84, 180, 10, 5, 71, 82, 65, 83, 80, 184, 5, - 30, 85, 80, 80, 69, 82, 32, 66, 79, 68, 89, 32, 84, 73, 76, 84, 73, 78, - 71, 32, 70, 82, 79, 77, 32, 72, 73, 80, 32, 74, 79, 195, 197, 4, 80, 8, - 48, 4, 66, 76, 79, 87, 29, 4, 83, 85, 67, 75, 4, 58, 32, 155, 221, 4, 73, - 4, 30, 32, 61, 3, 73, 78, 71, 2, 129, 158, 1, 10, 83, 77, 65, 76, 76, 32, - 82, 79, 84, 65, 2, 167, 248, 8, 32, 10, 52, 5, 69, 65, 84, 72, 32, 249, - 169, 1, 2, 85, 83, 4, 144, 164, 2, 2, 69, 88, 1, 2, 73, 78, 10, 40, 6, - 72, 69, 69, 75, 83, 32, 63, 79, 6, 154, 107, 83, 146, 38, 78, 225, 217, - 3, 4, 80, 85, 70, 70, 4, 174, 166, 9, 76, 223, 46, 77, 28, 108, 15, 82, - 69, 65, 77, 89, 32, 69, 89, 69, 66, 82, 79, 87, 83, 32, 165, 1, 7, 89, - 78, 65, 77, 73, 67, 32, 8, 64, 4, 68, 79, 87, 78, 0, 2, 85, 80, 29, 4, - 78, 69, 85, 84, 2, 153, 143, 1, 2, 32, 78, 4, 21, 3, 82, 65, 76, 4, 11, - 32, 4, 194, 58, 68, 187, 185, 9, 85, 20, 180, 1, 11, 69, 86, 69, 82, 89, - 32, 79, 84, 72, 69, 82, 30, 70, 22, 83, 128, 122, 9, 65, 82, 82, 79, 87, - 72, 69, 65, 68, 254, 38, 82, 188, 200, 3, 2, 84, 69, 21, 4, 71, 82, 65, - 68, 2, 181, 218, 8, 2, 32, 84, 2, 151, 136, 6, 65, 6, 68, 11, 73, 77, 85, - 76, 84, 65, 78, 69, 79, 85, 83, 151, 215, 8, 76, 5, 223, 151, 1, 32, 54, - 64, 2, 89, 69, 244, 221, 4, 4, 88, 67, 73, 84, 155, 132, 4, 65, 50, 166, - 1, 32, 56, 15, 66, 82, 79, 87, 83, 32, 83, 84, 82, 65, 73, 71, 72, 84, - 32, 44, 5, 71, 65, 90, 69, 45, 140, 2, 7, 76, 65, 83, 72, 69, 83, 32, 65, - 2, 83, 32, 6, 240, 150, 1, 5, 66, 76, 73, 78, 75, 175, 247, 4, 87, 6, - 186, 53, 68, 154, 84, 78, 163, 229, 8, 85, 18, 100, 11, 70, 76, 79, 79, - 82, 80, 76, 65, 78, 69, 32, 25, 10, 87, 65, 76, 76, 80, 76, 65, 78, 69, - 32, 8, 82, 83, 207, 45, 67, 10, 18, 67, 43, 83, 4, 254, 45, 85, 213, 95, - 3, 73, 82, 67, 6, 37, 7, 84, 82, 65, 73, 71, 72, 84, 7, 11, 32, 4, 222, - 163, 1, 65, 55, 68, 6, 130, 51, 68, 252, 167, 4, 4, 70, 76, 85, 84, 191, - 145, 5, 85, 14, 112, 5, 72, 65, 76, 70, 32, 26, 67, 28, 4, 87, 73, 68, - 69, 230, 92, 79, 177, 130, 4, 6, 83, 81, 85, 69, 69, 90, 4, 22, 67, 131, - 93, 79, 2, 225, 232, 2, 2, 76, 79, 4, 162, 67, 32, 217, 61, 4, 78, 73, - 78, 71, 38, 204, 1, 28, 65, 67, 69, 32, 68, 73, 82, 69, 67, 84, 73, 79, - 78, 32, 80, 79, 83, 73, 84, 73, 79, 78, 32, 78, 79, 83, 69, 32, 138, 1, - 73, 82, 76, 176, 1, 8, 79, 82, 69, 72, 69, 65, 68, 32, 135, 148, 7, 85, - 6, 88, 10, 85, 80, 32, 79, 82, 32, 68, 79, 87, 78, 13, 8, 70, 79, 82, 87, - 65, 82, 68, 32, 5, 11, 32, 2, 225, 225, 4, 3, 84, 73, 76, 12, 240, 225, - 3, 11, 76, 76, 32, 77, 79, 68, 73, 70, 73, 69, 82, 151, 184, 2, 78, 12, - 44, 4, 73, 67, 75, 32, 29, 3, 79, 79, 82, 10, 146, 141, 1, 76, 35, 83, 2, - 221, 233, 8, 20, 80, 76, 65, 78, 69, 32, 83, 72, 79, 85, 76, 68, 69, 82, - 32, 72, 73, 80, 32, 77, 6, 166, 89, 87, 222, 38, 67, 47, 78, 156, 4, 34, - 65, 133, 75, 3, 69, 65, 68, 140, 4, 36, 3, 78, 68, 45, 139, 172, 9, 73, - 138, 4, 92, 5, 65, 78, 71, 76, 69, 138, 5, 67, 150, 10, 70, 186, 42, 72, - 241, 12, 4, 79, 86, 65, 76, 37, 11, 32, 34, 188, 1, 5, 73, 78, 68, 69, - 88, 176, 1, 7, 76, 73, 84, 84, 76, 69, 32, 136, 1, 5, 82, 73, 78, 71, 32, - 173, 66, 18, 77, 73, 68, 68, 76, 69, 32, 82, 73, 78, 71, 32, 76, 73, 84, - 84, 76, 69, 17, 11, 32, 14, 128, 1, 7, 77, 73, 68, 68, 76, 69, 32, 228, - 24, 11, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, 241, 42, 5, 84, 72, - 85, 77, 66, 4, 174, 70, 76, 243, 201, 8, 82, 8, 44, 5, 73, 78, 68, 69, - 88, 203, 224, 9, 85, 7, 145, 24, 18, 32, 84, 72, 85, 77, 66, 32, 73, 78, - 68, 69, 88, 32, 84, 72, 85, 77, 66, 4, 108, 22, 68, 79, 87, 78, 32, 77, - 73, 68, 68, 76, 69, 32, 84, 72, 85, 77, 66, 32, 73, 78, 68, 69, 155, 68, - 76, 2, 223, 157, 8, 88, 88, 64, 5, 73, 82, 67, 76, 69, 184, 3, 3, 76, 65, - 87, 183, 2, 85, 35, 11, 32, 32, 116, 5, 73, 78, 68, 69, 88, 200, 1, 7, - 76, 73, 84, 84, 76, 69, 32, 36, 7, 77, 73, 68, 68, 76, 69, 32, 163, 64, - 82, 21, 11, 32, 18, 72, 6, 77, 73, 68, 68, 76, 69, 198, 26, 72, 242, 38, - 82, 255, 215, 8, 66, 13, 11, 32, 10, 64, 5, 67, 82, 79, 83, 83, 198, 64, - 84, 82, 76, 243, 201, 8, 82, 4, 134, 65, 32, 227, 212, 8, 69, 4, 210, - 181, 8, 73, 139, 166, 1, 85, 6, 252, 47, 10, 82, 73, 78, 71, 32, 76, 73, - 84, 84, 76, 187, 171, 9, 85, 17, 11, 32, 14, 144, 2, 28, 77, 73, 68, 68, - 76, 69, 32, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, 32, 67, 79, 78, - 74, 79, 73, 78, 69, 68, 176, 49, 2, 70, 79, 198, 11, 78, 162, 1, 84, 217, - 118, 23, 73, 78, 68, 69, 88, 32, 84, 72, 85, 77, 66, 32, 67, 85, 82, 86, - 69, 32, 84, 72, 85, 77, 66, 5, 139, 181, 1, 32, 38, 46, 80, 149, 2, 6, - 82, 76, 73, 67, 85, 69, 31, 11, 32, 28, 188, 1, 5, 73, 78, 68, 69, 88, - 56, 19, 70, 73, 86, 69, 32, 70, 73, 78, 71, 69, 82, 83, 32, 83, 80, 82, - 69, 65, 68, 196, 50, 7, 77, 73, 68, 68, 76, 69, 32, 18, 79, 218, 7, 78, - 163, 1, 84, 9, 11, 32, 6, 40, 5, 84, 72, 85, 77, 66, 243, 58, 82, 5, 215, - 46, 32, 9, 11, 32, 6, 72, 5, 73, 78, 68, 69, 88, 0, 6, 77, 73, 68, 68, - 76, 69, 179, 71, 79, 2, 189, 133, 9, 13, 32, 82, 73, 78, 71, 32, 76, 73, - 84, 84, 76, 69, 32, 172, 2, 44, 3, 73, 83, 84, 177, 33, 3, 76, 65, 84, - 247, 1, 11, 32, 244, 1, 160, 2, 5, 73, 78, 68, 69, 88, 192, 16, 7, 76, - 73, 84, 84, 76, 69, 32, 196, 2, 7, 77, 73, 68, 68, 76, 69, 32, 200, 4, 5, - 82, 73, 78, 71, 32, 132, 2, 5, 84, 72, 85, 77, 66, 138, 2, 72, 205, 9, - 22, 70, 79, 85, 82, 32, 70, 73, 78, 71, 69, 82, 83, 32, 67, 79, 78, 74, - 79, 73, 78, 69, 68, 137, 1, 11, 32, 134, 1, 232, 1, 4, 66, 69, 78, 84, - 36, 6, 72, 73, 78, 71, 69, 68, 76, 6, 77, 73, 68, 68, 76, 69, 168, 7, 2, - 67, 85, 64, 6, 84, 72, 85, 77, 66, 32, 160, 5, 16, 85, 80, 32, 77, 73, - 68, 68, 76, 69, 32, 72, 73, 78, 71, 69, 68, 151, 4, 82, 5, 217, 45, 5, - 32, 79, 86, 69, 82, 9, 11, 32, 6, 252, 20, 8, 77, 73, 68, 68, 76, 69, 32, - 85, 167, 160, 8, 76, 71, 11, 32, 68, 236, 1, 4, 66, 69, 78, 84, 42, 67, - 244, 1, 10, 85, 80, 32, 83, 80, 82, 69, 65, 68, 32, 100, 6, 72, 73, 78, - 71, 69, 68, 46, 82, 80, 5, 84, 72, 85, 77, 66, 188, 28, 14, 83, 84, 82, - 65, 73, 71, 72, 84, 32, 84, 72, 85, 77, 66, 227, 17, 76, 5, 213, 92, 6, - 32, 84, 72, 85, 77, 66, 28, 68, 8, 79, 78, 74, 79, 73, 78, 69, 68, 233, - 1, 4, 82, 79, 83, 83, 23, 11, 32, 20, 144, 1, 6, 67, 85, 80, 80, 69, 68, - 28, 6, 84, 72, 85, 77, 66, 32, 68, 5, 72, 73, 78, 71, 69, 166, 22, 73, - 165, 7, 6, 77, 73, 68, 68, 76, 69, 5, 11, 32, 2, 203, 27, 84, 8, 160, 1, - 4, 83, 73, 68, 69, 219, 61, 70, 6, 22, 69, 159, 47, 32, 4, 223, 15, 68, - 5, 241, 30, 7, 32, 83, 80, 82, 69, 65, 68, 8, 32, 3, 73, 78, 71, 247, 19, - 65, 7, 11, 32, 4, 138, 36, 67, 255, 225, 8, 66, 19, 11, 32, 16, 64, 6, - 65, 78, 71, 76, 69, 68, 22, 67, 106, 72, 159, 132, 9, 66, 5, 247, 211, 5, - 32, 6, 74, 85, 230, 7, 73, 241, 25, 10, 79, 78, 74, 79, 73, 78, 69, 68, - 32, 72, 2, 145, 188, 4, 2, 80, 80, 4, 194, 33, 73, 217, 26, 2, 79, 79, - 40, 164, 1, 7, 65, 78, 71, 76, 69, 68, 32, 46, 67, 220, 1, 14, 70, 79, - 82, 87, 65, 82, 68, 32, 73, 78, 68, 69, 88, 32, 32, 4, 72, 79, 79, 75, - 53, 4, 83, 73, 68, 69, 4, 128, 1, 2, 73, 78, 1, 3, 79, 85, 84, 12, 36, 5, - 73, 82, 67, 76, 69, 15, 85, 5, 47, 68, 8, 32, 4, 80, 80, 69, 68, 39, 82, - 2, 225, 40, 5, 32, 77, 73, 68, 68, 6, 56, 9, 86, 69, 32, 84, 72, 85, 77, - 66, 32, 143, 37, 76, 4, 182, 160, 1, 73, 131, 188, 4, 85, 4, 202, 84, 83, - 255, 171, 8, 66, 7, 157, 8, 9, 69, 68, 32, 77, 73, 68, 68, 76, 69, 15, - 11, 32, 12, 92, 6, 73, 78, 68, 69, 88, 32, 156, 13, 5, 84, 72, 85, 77, - 66, 193, 8, 4, 66, 79, 84, 72, 4, 26, 72, 239, 254, 8, 66, 2, 231, 140, - 8, 73, 7, 37, 7, 32, 84, 72, 85, 77, 66, 32, 4, 178, 28, 67, 227, 129, 1, - 83, 22, 88, 4, 68, 79, 87, 78, 186, 1, 84, 158, 6, 82, 130, 21, 73, 226, - 224, 8, 66, 159, 67, 85, 9, 11, 32, 6, 80, 9, 79, 84, 72, 69, 82, 83, 32, - 67, 73, 25, 7, 82, 73, 80, 80, 76, 69, 32, 2, 225, 51, 2, 82, 67, 4, 22, - 67, 171, 80, 83, 2, 11, 85, 2, 241, 179, 4, 2, 82, 86, 4, 196, 35, 6, 79, - 85, 67, 72, 69, 83, 39, 72, 30, 134, 1, 82, 28, 6, 84, 72, 85, 77, 66, - 32, 138, 3, 85, 134, 1, 68, 210, 30, 76, 205, 244, 7, 9, 66, 69, 78, 84, - 32, 79, 86, 69, 82, 4, 238, 4, 65, 231, 29, 73, 16, 80, 7, 65, 78, 71, - 76, 69, 68, 32, 126, 67, 124, 4, 72, 79, 79, 75, 147, 32, 76, 6, 60, 10, - 79, 85, 84, 32, 73, 78, 68, 69, 88, 32, 215, 1, 73, 4, 26, 67, 151, 188, - 9, 85, 2, 133, 186, 2, 3, 82, 79, 83, 6, 76, 12, 73, 82, 67, 76, 69, 68, - 32, 73, 78, 68, 69, 88, 45, 3, 85, 80, 80, 4, 11, 32, 4, 150, 21, 72, - 131, 166, 9, 85, 2, 25, 4, 69, 68, 32, 73, 2, 233, 30, 4, 78, 68, 69, 88, - 4, 11, 80, 5, 175, 15, 32, 18, 102, 68, 20, 6, 77, 73, 68, 68, 76, 69, - 42, 82, 198, 29, 84, 82, 76, 226, 244, 7, 73, 139, 166, 1, 85, 2, 175, - 229, 7, 79, 7, 11, 32, 4, 206, 3, 82, 179, 16, 67, 2, 11, 65, 2, 37, 7, - 73, 83, 69, 68, 32, 75, 78, 2, 11, 85, 2, 11, 67, 2, 147, 148, 8, 75, 35, - 11, 32, 32, 148, 1, 8, 66, 69, 84, 87, 69, 69, 78, 32, 102, 72, 20, 5, - 79, 86, 69, 82, 32, 120, 4, 83, 73, 68, 69, 100, 6, 85, 78, 68, 69, 82, - 32, 207, 40, 70, 8, 80, 12, 73, 78, 68, 69, 88, 32, 77, 73, 68, 68, 76, - 69, 246, 20, 77, 155, 6, 82, 5, 135, 70, 32, 2, 187, 169, 4, 69, 4, 52, - 6, 70, 79, 85, 82, 32, 82, 161, 2, 2, 84, 87, 2, 11, 65, 2, 233, 80, 9, - 73, 83, 69, 68, 32, 75, 78, 85, 67, 6, 11, 32, 6, 38, 68, 190, 15, 67, - 255, 225, 8, 66, 2, 25, 4, 73, 65, 71, 79, 2, 131, 171, 8, 78, 10, 54, - 73, 34, 84, 48, 4, 70, 79, 85, 82, 131, 23, 76, 2, 161, 7, 4, 78, 68, 69, - 88, 4, 34, 87, 13, 4, 72, 82, 69, 69, 2, 11, 79, 2, 197, 164, 8, 5, 32, - 70, 73, 78, 71, 55, 11, 32, 52, 194, 1, 70, 172, 3, 4, 72, 69, 69, 76, - 192, 1, 6, 83, 80, 76, 73, 84, 32, 236, 1, 6, 84, 72, 85, 77, 66, 32, - 165, 244, 4, 16, 66, 69, 84, 87, 69, 69, 78, 32, 80, 65, 76, 77, 32, 70, - 65, 67, 24, 140, 1, 18, 73, 86, 69, 32, 70, 73, 78, 71, 69, 82, 83, 32, - 83, 80, 82, 69, 65, 68, 165, 1, 11, 79, 85, 82, 32, 70, 73, 78, 71, 69, - 82, 83, 15, 11, 32, 12, 68, 6, 72, 73, 78, 71, 69, 68, 42, 84, 186, 2, - 70, 199, 233, 8, 66, 7, 11, 32, 4, 190, 4, 84, 155, 15, 78, 2, 189, 35, - 6, 72, 85, 77, 66, 32, 70, 11, 11, 32, 8, 72, 9, 67, 79, 78, 74, 79, 73, - 78, 69, 68, 154, 8, 72, 231, 226, 8, 66, 5, 221, 145, 9, 3, 32, 83, 80, - 11, 11, 32, 8, 96, 19, 70, 73, 86, 69, 32, 70, 73, 78, 71, 69, 82, 83, - 32, 83, 80, 82, 69, 65, 68, 151, 2, 84, 7, 11, 32, 4, 26, 70, 199, 233, - 8, 66, 2, 21, 3, 79, 85, 82, 2, 167, 1, 32, 10, 72, 6, 67, 69, 78, 84, - 82, 69, 96, 5, 73, 78, 68, 69, 88, 167, 16, 76, 7, 49, 10, 32, 84, 72, - 85, 77, 66, 32, 83, 73, 68, 4, 11, 69, 5, 11, 32, 2, 131, 232, 8, 66, 2, - 11, 32, 2, 11, 84, 2, 173, 135, 1, 5, 72, 85, 77, 66, 32, 6, 242, 30, 70, - 162, 104, 83, 159, 224, 7, 66, 82, 48, 4, 73, 78, 71, 69, 181, 9, 3, 79, - 79, 75, 63, 11, 32, 60, 206, 1, 70, 172, 1, 5, 73, 78, 68, 69, 88, 196, - 2, 6, 76, 73, 84, 84, 76, 69, 80, 6, 77, 73, 68, 68, 76, 69, 30, 79, 64, - 4, 82, 73, 78, 71, 124, 6, 84, 72, 85, 77, 66, 32, 158, 6, 78, 139, 142, - 4, 83, 4, 92, 19, 73, 86, 69, 32, 70, 73, 78, 71, 69, 82, 83, 32, 83, 80, - 82, 69, 65, 68, 32, 19, 79, 2, 191, 25, 79, 2, 249, 1, 11, 85, 82, 32, - 70, 73, 78, 71, 69, 82, 83, 32, 23, 11, 32, 20, 86, 72, 40, 7, 77, 73, - 68, 68, 76, 69, 32, 104, 5, 84, 72, 85, 77, 66, 219, 9, 82, 2, 11, 73, 2, - 177, 154, 4, 2, 78, 71, 6, 36, 4, 82, 73, 78, 71, 203, 10, 76, 5, 11, 32, - 2, 11, 67, 2, 21, 3, 79, 78, 74, 2, 175, 33, 79, 11, 11, 32, 8, 34, 83, - 210, 22, 79, 203, 39, 76, 4, 190, 148, 7, 73, 195, 8, 77, 9, 11, 32, 6, - 22, 73, 199, 8, 84, 4, 25, 4, 78, 68, 69, 88, 5, 155, 8, 32, 5, 11, 32, - 2, 171, 8, 82, 8, 21, 3, 80, 69, 78, 9, 11, 32, 6, 178, 7, 78, 163, 1, - 84, 5, 97, 22, 32, 68, 79, 87, 78, 32, 73, 78, 68, 69, 88, 32, 84, 72, - 85, 77, 66, 32, 72, 79, 79, 75, 2, 177, 77, 2, 32, 77, 6, 68, 9, 66, 69, - 84, 87, 69, 69, 78, 32, 77, 53, 4, 83, 73, 68, 69, 2, 29, 5, 73, 68, 68, - 76, 69, 2, 163, 148, 4, 32, 5, 33, 6, 32, 84, 79, 85, 67, 72, 2, 185, - 250, 7, 3, 73, 78, 71, 21, 11, 32, 18, 172, 1, 4, 67, 85, 82, 76, 28, 18, - 73, 78, 68, 69, 88, 32, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, 32, - 48, 7, 77, 73, 68, 68, 76, 69, 32, 225, 2, 4, 82, 73, 78, 71, 2, 253, - 147, 5, 2, 73, 67, 6, 142, 183, 5, 85, 142, 238, 2, 79, 243, 41, 73, 8, - 104, 21, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, 32, 67, 79, 78, 74, - 79, 73, 78, 69, 68, 143, 2, 84, 7, 223, 228, 2, 32, 17, 11, 32, 14, 112, - 14, 70, 73, 86, 69, 32, 70, 73, 78, 71, 69, 82, 83, 32, 83, 22, 76, 66, - 78, 70, 82, 94, 84, 183, 244, 7, 73, 2, 215, 160, 2, 80, 2, 21, 3, 73, - 84, 84, 2, 17, 2, 76, 69, 2, 135, 166, 8, 32, 2, 11, 79, 2, 11, 32, 2, - 11, 84, 2, 11, 72, 2, 247, 251, 5, 85, 2, 11, 73, 2, 21, 3, 78, 71, 32, - 2, 11, 76, 2, 11, 73, 2, 11, 84, 2, 179, 246, 7, 84, 4, 29, 5, 72, 85, - 77, 66, 32, 4, 194, 14, 70, 163, 104, 83, 17, 11, 32, 14, 56, 8, 77, 79, - 86, 69, 77, 69, 78, 84, 247, 150, 8, 82, 12, 26, 45, 163, 199, 7, 32, 10, - 100, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, 25, 10, 87, 65, 76, - 76, 80, 76, 65, 78, 69, 32, 4, 62, 67, 223, 40, 83, 6, 38, 67, 28, 2, 84, - 73, 195, 40, 83, 2, 169, 155, 8, 2, 85, 82, 2, 183, 251, 8, 76, 38, 50, - 73, 225, 3, 7, 79, 67, 65, 84, 73, 79, 78, 22, 32, 3, 77, 66, 32, 171, 1, - 80, 16, 56, 4, 67, 79, 77, 66, 29, 6, 76, 69, 78, 71, 84, 72, 2, 193, - 212, 5, 2, 73, 78, 14, 11, 45, 14, 146, 150, 9, 49, 2, 50, 2, 51, 2, 52, - 2, 53, 2, 54, 3, 55, 6, 58, 32, 153, 1, 9, 83, 32, 80, 82, 69, 83, 83, - 69, 68, 4, 116, 12, 76, 79, 87, 69, 82, 32, 79, 86, 69, 82, 32, 85, 133, - 251, 7, 11, 85, 80, 80, 69, 82, 32, 79, 86, 69, 82, 32, 2, 11, 80, 2, - 163, 214, 8, 80, 2, 29, 5, 32, 84, 79, 71, 69, 2, 11, 84, 2, 227, 213, 8, - 72, 16, 22, 32, 203, 1, 45, 12, 148, 1, 2, 72, 69, 236, 177, 2, 3, 84, - 79, 82, 144, 222, 4, 3, 68, 69, 80, 0, 3, 87, 73, 68, 229, 109, 10, 76, - 73, 77, 66, 83, 32, 68, 73, 71, 73, 4, 196, 13, 4, 65, 68, 32, 78, 131, - 218, 8, 73, 4, 52, 5, 70, 76, 79, 79, 82, 1, 4, 87, 65, 76, 76, 2, 221, - 210, 8, 5, 80, 76, 65, 78, 69, 156, 3, 64, 4, 85, 84, 72, 32, 161, 5, 7, - 86, 69, 77, 69, 78, 84, 45, 54, 186, 1, 67, 88, 5, 70, 82, 79, 87, 78, 0, - 5, 83, 77, 73, 76, 69, 56, 4, 75, 73, 83, 83, 36, 5, 79, 80, 69, 78, 32, - 192, 1, 5, 84, 69, 78, 83, 69, 165, 29, 5, 87, 82, 73, 78, 75, 8, 48, 6, - 76, 79, 83, 69, 68, 32, 163, 223, 7, 79, 6, 222, 2, 70, 142, 38, 67, 47, - 78, 7, 11, 32, 4, 22, 79, 203, 1, 87, 2, 147, 186, 7, 80, 7, 11, 32, 4, - 166, 1, 87, 83, 70, 18, 100, 4, 79, 86, 65, 76, 0, 9, 82, 69, 67, 84, 65, - 78, 71, 76, 69, 42, 87, 82, 70, 235, 185, 7, 67, 7, 11, 32, 4, 26, 87, - 151, 184, 7, 89, 2, 25, 4, 82, 73, 78, 75, 2, 203, 128, 4, 76, 7, 11, 32, - 4, 18, 70, 43, 83, 2, 17, 2, 79, 82, 2, 215, 244, 7, 87, 2, 17, 2, 85, - 67, 2, 219, 255, 3, 75, 230, 2, 192, 1, 9, 68, 73, 65, 71, 79, 78, 65, - 76, 32, 148, 1, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, 184, 14, - 6, 72, 73, 78, 71, 69, 32, 189, 2, 10, 87, 65, 76, 76, 80, 76, 65, 78, - 69, 32, 32, 56, 8, 66, 69, 84, 87, 69, 69, 78, 32, 22, 65, 31, 84, 16, - 18, 65, 31, 84, 8, 229, 28, 3, 87, 65, 89, 8, 201, 28, 6, 79, 87, 65, 82, - 68, 83, 150, 1, 208, 2, 24, 65, 82, 77, 32, 67, 73, 82, 67, 76, 69, 32, - 72, 73, 84, 84, 73, 78, 71, 32, 87, 65, 76, 76, 32, 38, 66, 34, 67, 224, - 1, 8, 70, 73, 78, 71, 69, 82, 32, 67, 52, 5, 72, 85, 77, 80, 32, 184, 3, - 5, 76, 79, 79, 80, 32, 198, 1, 83, 108, 7, 84, 82, 73, 80, 76, 69, 32, - 110, 87, 206, 12, 68, 198, 2, 80, 154, 6, 90, 227, 232, 7, 74, 12, 178, - 7, 76, 154, 9, 77, 39, 83, 8, 150, 17, 79, 175, 230, 7, 69, 28, 86, 72, - 20, 5, 85, 82, 86, 69, 32, 196, 29, 5, 79, 82, 78, 69, 82, 227, 165, 7, - 82, 2, 211, 212, 7, 69, 18, 80, 4, 67, 79, 77, 66, 158, 8, 72, 230, 15, - 76, 202, 172, 2, 77, 183, 177, 1, 83, 2, 11, 73, 2, 131, 248, 3, 78, 6, - 128, 9, 6, 73, 82, 67, 76, 69, 83, 239, 20, 79, 18, 56, 8, 72, 73, 84, - 84, 73, 78, 71, 32, 239, 244, 3, 83, 16, 72, 8, 67, 69, 73, 76, 73, 78, - 71, 32, 101, 6, 70, 76, 79, 79, 82, 32, 8, 56, 5, 76, 65, 82, 71, 69, 1, - 5, 83, 77, 65, 76, 76, 4, 11, 32, 4, 226, 54, 84, 135, 2, 68, 8, 88, 4, - 83, 77, 65, 76, 12, 5, 76, 65, 82, 71, 69, 17, 7, 84, 82, 73, 80, 76, 69, - 32, 2, 11, 76, 2, 255, 18, 32, 4, 56, 5, 76, 65, 82, 71, 69, 1, 5, 83, - 77, 65, 76, 76, 2, 145, 53, 2, 32, 84, 18, 56, 8, 72, 73, 84, 84, 73, 78, - 71, 32, 183, 241, 3, 83, 16, 64, 7, 67, 69, 73, 76, 73, 78, 71, 1, 5, 70, - 76, 79, 79, 82, 8, 11, 32, 8, 22, 76, 191, 9, 83, 4, 249, 22, 4, 65, 82, - 71, 69, 12, 44, 6, 72, 65, 75, 73, 78, 71, 243, 16, 73, 2, 21, 3, 32, 80, - 65, 2, 221, 240, 3, 4, 82, 65, 76, 76, 8, 76, 12, 65, 76, 84, 69, 82, 78, - 65, 84, 73, 78, 71, 32, 138, 18, 87, 63, 83, 4, 134, 18, 87, 147, 21, 77, - 18, 80, 4, 65, 86, 69, 32, 169, 1, 11, 82, 73, 83, 84, 32, 67, 73, 82, - 67, 76, 69, 14, 30, 72, 102, 83, 171, 20, 76, 8, 37, 7, 73, 84, 84, 73, - 78, 71, 32, 8, 252, 2, 4, 67, 69, 73, 76, 25, 5, 70, 76, 79, 79, 82, 4, - 170, 146, 5, 78, 231, 224, 1, 77, 4, 209, 5, 10, 32, 72, 73, 84, 84, 73, - 78, 71, 32, 87, 14, 112, 3, 85, 80, 32, 184, 1, 6, 68, 79, 87, 78, 32, - 83, 149, 225, 5, 10, 83, 73, 68, 69, 32, 84, 79, 32, 83, 73, 10, 40, 5, - 68, 79, 87, 78, 32, 143, 1, 83, 8, 68, 8, 65, 76, 84, 69, 82, 78, 65, 84, - 230, 17, 76, 215, 216, 3, 83, 4, 21, 3, 73, 78, 71, 4, 11, 32, 4, 190, - 17, 76, 215, 216, 3, 83, 2, 207, 30, 69, 162, 1, 148, 2, 11, 65, 82, 77, - 32, 67, 73, 82, 67, 76, 69, 32, 98, 66, 54, 67, 174, 4, 68, 100, 8, 70, - 73, 78, 71, 69, 82, 32, 67, 64, 5, 72, 85, 77, 80, 32, 60, 5, 76, 79, 79, - 80, 32, 102, 80, 34, 83, 216, 1, 7, 84, 82, 73, 80, 76, 69, 32, 218, 1, - 87, 202, 2, 90, 227, 232, 7, 74, 8, 18, 77, 39, 83, 4, 225, 13, 5, 69, - 68, 73, 85, 77, 4, 11, 77, 4, 177, 13, 3, 65, 76, 76, 12, 34, 79, 185, - 13, 3, 69, 78, 68, 6, 183, 13, 88, 46, 100, 6, 79, 82, 78, 69, 82, 32, - 88, 4, 85, 82, 86, 69, 232, 11, 4, 72, 69, 67, 75, 227, 165, 7, 82, 8, - 54, 82, 194, 12, 76, 162, 167, 2, 77, 183, 177, 1, 83, 2, 11, 79, 2, 239, - 176, 5, 84, 30, 50, 32, 137, 2, 7, 68, 32, 67, 82, 79, 83, 83, 26, 66, - 72, 68, 2, 84, 72, 133, 5, 7, 81, 85, 65, 82, 84, 69, 82, 12, 196, 5, 10, - 65, 76, 70, 45, 67, 73, 82, 67, 76, 69, 147, 14, 73, 6, 96, 2, 69, 78, - 29, 18, 82, 69, 69, 45, 81, 85, 65, 82, 84, 69, 82, 32, 67, 73, 82, 67, - 76, 69, 2, 11, 32, 2, 131, 1, 83, 4, 11, 32, 4, 246, 176, 2, 77, 183, - 177, 1, 83, 8, 33, 6, 79, 85, 66, 76, 69, 32, 8, 30, 83, 150, 4, 65, 75, - 87, 2, 209, 196, 8, 3, 84, 82, 65, 6, 32, 3, 73, 82, 67, 151, 9, 79, 4, - 173, 7, 3, 76, 69, 83, 10, 142, 8, 76, 166, 8, 72, 254, 158, 2, 77, 183, - 177, 1, 83, 12, 68, 5, 83, 77, 65, 76, 76, 142, 7, 76, 166, 8, 72, 255, - 158, 2, 77, 5, 11, 32, 2, 227, 36, 68, 6, 181, 6, 4, 69, 65, 75, 83, 12, - 22, 73, 231, 36, 72, 10, 29, 5, 78, 71, 76, 69, 32, 10, 52, 8, 83, 84, - 82, 65, 73, 71, 72, 84, 207, 1, 87, 8, 11, 32, 8, 42, 76, 202, 172, 2, - 77, 183, 177, 1, 83, 4, 25, 4, 65, 82, 71, 69, 5, 147, 207, 8, 83, 8, 26, - 65, 74, 87, 63, 83, 4, 49, 10, 76, 84, 69, 82, 78, 65, 84, 73, 78, 71, 5, - 17, 2, 32, 87, 2, 29, 5, 82, 73, 83, 84, 32, 2, 165, 196, 7, 2, 70, 76, - 2, 37, 7, 84, 82, 65, 73, 71, 72, 84, 2, 159, 20, 32, 26, 104, 4, 65, 86, - 69, 32, 185, 1, 17, 82, 73, 83, 84, 32, 67, 73, 82, 67, 76, 69, 32, 70, - 82, 79, 78, 84, 22, 108, 6, 67, 85, 82, 86, 69, 32, 140, 1, 13, 68, 73, - 65, 71, 79, 78, 65, 76, 32, 80, 65, 84, 72, 223, 8, 72, 12, 48, 4, 68, - 79, 85, 66, 1, 4, 84, 82, 73, 80, 6, 85, 2, 76, 69, 4, 11, 32, 4, 210, - 30, 68, 43, 83, 6, 29, 5, 73, 71, 90, 65, 71, 6, 11, 32, 6, 42, 76, 162, - 167, 2, 77, 183, 177, 1, 83, 2, 175, 166, 7, 65, 10, 40, 4, 79, 83, 69, - 32, 135, 182, 7, 69, 8, 26, 67, 46, 78, 35, 87, 2, 11, 79, 2, 217, 214, - 7, 3, 78, 84, 65, 2, 221, 219, 7, 3, 69, 85, 84, 4, 44, 3, 82, 73, 78, - 241, 157, 1, 2, 73, 71, 2, 151, 167, 5, 75, 72, 56, 7, 79, 84, 65, 84, - 73, 79, 78, 225, 22, 2, 85, 66, 66, 60, 10, 32, 77, 79, 68, 73, 70, 73, - 69, 82, 45, 155, 1, 45, 30, 82, 49, 250, 226, 8, 50, 2, 51, 2, 52, 2, 53, - 2, 54, 2, 55, 2, 56, 3, 57, 14, 246, 226, 8, 48, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 3, 54, 36, 104, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, - 32, 133, 2, 10, 87, 65, 76, 76, 80, 76, 65, 78, 69, 32, 18, 100, 4, 68, - 79, 85, 66, 0, 4, 83, 73, 78, 71, 21, 11, 65, 76, 84, 69, 82, 78, 65, 84, - 73, 78, 71, 6, 17, 2, 76, 69, 7, 45, 9, 32, 72, 73, 84, 84, 73, 78, 71, - 32, 4, 32, 2, 67, 69, 33, 2, 70, 76, 2, 11, 73, 2, 231, 142, 8, 76, 2, - 239, 166, 8, 79, 18, 88, 8, 65, 76, 84, 69, 82, 78, 65, 84, 44, 4, 68, - 79, 85, 66, 1, 4, 83, 73, 78, 71, 6, 72, 4, 73, 78, 71, 32, 159, 222, 8, - 69, 6, 17, 2, 76, 69, 7, 11, 32, 4, 11, 72, 4, 11, 73, 4, 33, 6, 84, 84, - 73, 78, 71, 32, 4, 44, 2, 67, 72, 21, 5, 70, 82, 79, 78, 84, 2, 179, 243, - 4, 69, 2, 205, 213, 6, 2, 32, 87, 30, 172, 1, 8, 72, 79, 85, 76, 68, 69, - 82, 32, 196, 1, 7, 81, 85, 69, 69, 90, 69, 32, 240, 1, 7, 85, 82, 70, 65, - 67, 69, 32, 240, 10, 5, 84, 82, 73, 75, 69, 243, 129, 5, 69, 6, 100, 4, - 72, 73, 80, 32, 129, 246, 3, 15, 84, 73, 76, 84, 73, 78, 71, 32, 70, 82, - 79, 77, 32, 87, 65, 4, 48, 4, 80, 79, 83, 73, 253, 192, 7, 2, 83, 80, 2, - 11, 84, 2, 205, 150, 5, 2, 73, 79, 12, 48, 6, 70, 76, 73, 67, 75, 32, 18, - 76, 35, 83, 2, 211, 16, 65, 4, 129, 1, 4, 65, 82, 71, 69, 6, 34, 69, 65, - 4, 77, 65, 76, 76, 2, 17, 2, 81, 85, 2, 21, 3, 69, 78, 84, 2, 151, 207, - 7, 73, 4, 11, 32, 4, 214, 11, 77, 187, 4, 83, 4, 22, 83, 135, 11, 66, 2, - 249, 207, 1, 4, 89, 77, 66, 79, 82, 58, 69, 218, 2, 79, 137, 8, 6, 82, - 65, 86, 69, 76, 45, 20, 76, 3, 69, 84, 72, 185, 1, 11, 78, 83, 69, 32, - 67, 72, 69, 69, 75, 83, 32, 15, 11, 32, 12, 56, 3, 79, 78, 32, 86, 77, - 177, 5, 4, 66, 73, 84, 69, 8, 56, 4, 76, 73, 80, 83, 1, 6, 84, 79, 78, - 71, 85, 69, 5, 11, 32, 2, 11, 77, 2, 201, 194, 3, 2, 79, 86, 6, 50, 77, - 160, 176, 4, 2, 72, 73, 167, 138, 3, 76, 2, 213, 163, 3, 2, 73, 68, 28, - 76, 5, 78, 71, 85, 69, 32, 196, 4, 4, 82, 83, 79, 45, 129, 2, 2, 85, 67, - 16, 192, 2, 7, 67, 69, 78, 84, 82, 69, 32, 52, 14, 73, 78, 83, 73, 68, - 69, 32, 77, 79, 85, 84, 72, 32, 82, 36, 4, 84, 73, 80, 32, 88, 7, 76, 73, - 67, 75, 73, 78, 71, 208, 174, 7, 14, 83, 84, 73, 67, 75, 73, 78, 71, 32, - 79, 85, 84, 32, 70, 149, 158, 1, 17, 77, 79, 86, 69, 83, 32, 65, 71, 65, - 73, 78, 83, 84, 32, 67, 72, 69, 4, 214, 1, 73, 181, 180, 3, 5, 83, 84, - 73, 67, 75, 2, 181, 197, 3, 4, 69, 76, 65, 88, 4, 84, 7, 66, 69, 84, 87, - 69, 69, 78, 41, 10, 84, 79, 85, 67, 72, 73, 78, 71, 32, 73, 2, 11, 32, 2, - 173, 155, 5, 2, 76, 73, 2, 173, 174, 5, 5, 78, 83, 73, 68, 69, 6, 120, - 10, 87, 65, 76, 76, 80, 76, 65, 78, 69, 32, 253, 199, 3, 14, 70, 76, 79, - 79, 82, 80, 76, 65, 78, 69, 32, 84, 87, 73, 4, 108, 8, 67, 85, 82, 86, - 69, 68, 32, 66, 161, 204, 1, 13, 83, 84, 82, 65, 73, 71, 72, 84, 32, 83, - 84, 82, 69, 2, 211, 191, 7, 69, 6, 11, 72, 6, 11, 32, 6, 30, 66, 34, 77, - 187, 4, 83, 2, 137, 249, 6, 3, 69, 84, 87, 2, 149, 2, 3, 85, 76, 84, 34, - 100, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, 29, 10, 87, 65, 76, - 76, 80, 76, 65, 78, 69, 32, 14, 178, 1, 82, 151, 2, 83, 20, 72, 11, 65, - 82, 77, 32, 83, 80, 73, 82, 65, 76, 32, 78, 82, 151, 2, 83, 6, 30, 84, - 134, 2, 68, 43, 83, 2, 11, 82, 2, 11, 73, 2, 147, 166, 7, 80, 12, 41, 8, - 79, 84, 65, 84, 73, 79, 78, 45, 12, 52, 5, 70, 76, 79, 79, 82, 1, 4, 87, - 65, 76, 76, 6, 33, 6, 80, 76, 65, 78, 69, 32, 6, 26, 65, 54, 68, 43, 83, - 2, 29, 5, 76, 84, 69, 82, 78, 2, 203, 194, 3, 65, 2, 17, 2, 79, 85, 2, - 147, 164, 7, 66, 2, 231, 163, 7, 73, 2, 11, 72, 2, 203, 192, 3, 65, 2, - 11, 73, 2, 187, 179, 7, 78, 10, 100, 6, 65, 66, 79, 86, 69, 32, 162, 1, - 79, 213, 148, 2, 10, 77, 73, 78, 85, 83, 32, 83, 73, 77, 73, 4, 60, 7, - 71, 82, 69, 65, 84, 69, 82, 1, 4, 76, 69, 83, 83, 2, 37, 7, 45, 84, 72, - 65, 78, 32, 65, 2, 25, 4, 66, 79, 86, 69, 2, 161, 241, 1, 2, 32, 69, 4, - 147, 179, 6, 82, 250, 1, 68, 3, 71, 76, 69, 212, 4, 5, 72, 65, 76, 65, - 32, 143, 161, 5, 69, 20, 50, 32, 185, 195, 8, 6, 45, 83, 72, 73, 70, 84, - 16, 138, 1, 67, 0, 9, 71, 82, 65, 80, 72, 73, 67, 32, 67, 116, 2, 72, 73, - 74, 76, 36, 4, 82, 73, 71, 72, 141, 244, 4, 4, 83, 72, 73, 70, 2, 41, 8, - 72, 65, 82, 65, 67, 84, 69, 82, 2, 37, 7, 32, 73, 78, 84, 82, 79, 68, 2, - 11, 85, 2, 223, 132, 8, 67, 2, 25, 4, 71, 72, 45, 82, 2, 185, 1, 7, 69, - 86, 69, 82, 83, 69, 68, 4, 32, 2, 69, 70, 109, 2, 79, 87, 2, 49, 10, 84, - 45, 80, 79, 73, 78, 84, 73, 78, 71, 2, 21, 3, 32, 65, 78, 2, 17, 2, 71, - 76, 2, 31, 69, 2, 17, 2, 45, 57, 2, 11, 32, 2, 11, 81, 2, 233, 176, 2, 2, - 85, 79, 228, 1, 168, 2, 8, 65, 82, 67, 72, 65, 73, 67, 32, 224, 1, 15, - 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 114, 76, 188, - 8, 5, 83, 73, 71, 78, 32, 144, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, - 78, 32, 177, 227, 2, 17, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, - 75, 85, 78, 68, 68, 40, 46, 68, 109, 7, 78, 85, 77, 66, 69, 82, 32, 18, - 25, 4, 73, 71, 73, 84, 18, 11, 32, 18, 234, 204, 6, 70, 30, 83, 42, 84, - 170, 86, 78, 14, 79, 223, 110, 69, 22, 226, 232, 2, 79, 146, 229, 3, 69, - 30, 70, 42, 78, 38, 83, 39, 84, 6, 18, 82, 63, 89, 4, 56, 6, 65, 75, 65, - 65, 82, 65, 209, 184, 8, 2, 69, 80, 2, 205, 184, 8, 3, 65, 78, 83, 138, - 1, 60, 6, 69, 84, 84, 69, 82, 32, 233, 186, 2, 3, 73, 84, 72, 118, 246, - 1, 65, 106, 69, 34, 73, 62, 85, 34, 77, 220, 1, 4, 68, 65, 78, 84, 58, - 79, 28, 8, 83, 65, 78, 89, 65, 75, 65, 32, 50, 70, 2, 72, 2, 82, 2, 86, - 2, 89, 32, 8, 84, 65, 65, 76, 85, 74, 65, 32, 29, 9, 75, 65, 78, 84, 65, - 74, 65, 32, 78, 34, 102, 69, 204, 1, 2, 76, 80, 144, 2, 5, 77, 66, 65, - 32, 66, 14, 65, 2, 73, 2, 85, 151, 253, 4, 89, 4, 230, 3, 69, 151, 253, - 4, 89, 12, 46, 76, 2, 82, 154, 3, 73, 151, 253, 4, 89, 4, 11, 85, 4, 138, - 3, 85, 151, 253, 4, 89, 28, 42, 65, 177, 1, 5, 85, 85, 82, 68, 72, 22, - 32, 2, 72, 65, 179, 255, 4, 89, 20, 41, 8, 65, 80, 82, 65, 65, 78, 65, - 32, 20, 70, 84, 138, 1, 68, 22, 66, 2, 67, 2, 71, 2, 74, 2, 75, 3, 80, 4, - 154, 1, 84, 15, 65, 6, 25, 4, 65, 74, 65, 32, 6, 102, 76, 2, 78, 3, 83, - 4, 86, 79, 151, 253, 4, 89, 8, 26, 68, 22, 71, 3, 74, 4, 18, 68, 15, 65, - 2, 11, 65, 2, 147, 253, 4, 89, 6, 26, 78, 21, 2, 83, 65, 2, 89, 2, 65, - 65, 4, 68, 11, 78, 89, 79, 79, 71, 65, 32, 78, 65, 65, 75, 139, 252, 4, - 89, 2, 149, 176, 8, 4, 83, 73, 75, 89, 8, 66, 65, 218, 157, 4, 67, 217, - 145, 4, 6, 86, 73, 83, 65, 82, 71, 4, 192, 116, 5, 76, 45, 76, 65, 75, - 237, 186, 7, 6, 78, 85, 83, 86, 65, 82, 34, 56, 5, 68, 73, 71, 65, 32, - 62, 71, 82, 75, 155, 2, 65, 12, 58, 71, 48, 4, 75, 79, 77, 66, 118, 65, - 26, 73, 19, 80, 4, 11, 65, 4, 236, 2, 3, 69, 84, 84, 67, 89, 2, 11, 85, - 2, 223, 173, 8, 86, 16, 52, 5, 69, 84, 84, 73, 32, 85, 4, 79, 77, 66, 85, - 6, 26, 65, 26, 73, 19, 80, 2, 213, 1, 2, 69, 68, 2, 203, 1, 83, 2, 175, - 1, 65, 10, 40, 2, 86, 65, 137, 128, 8, 2, 32, 68, 9, 29, 5, 32, 72, 65, - 65, 32, 6, 62, 65, 0, 6, 68, 73, 71, 65, 32, 65, 85, 3, 71, 65, 89, 2, - 17, 2, 69, 76, 2, 11, 65, 2, 17, 2, 45, 80, 2, 11, 73, 2, 147, 139, 8, - 76, 2, 189, 253, 5, 5, 65, 78, 85, 75, 73, 12, 84, 2, 32, 80, 206, 2, 45, - 205, 149, 6, 10, 84, 69, 69, 78, 32, 80, 79, 73, 78, 84, 8, 140, 1, 23, - 69, 84, 65, 76, 76, 69, 68, 32, 66, 76, 65, 67, 75, 32, 65, 78, 68, 32, - 87, 72, 73, 84, 69, 49, 7, 79, 73, 78, 84, 69, 68, 32, 2, 25, 4, 32, 70, - 76, 79, 2, 223, 227, 6, 82, 6, 78, 80, 218, 147, 6, 66, 217, 132, 1, 9, - 83, 84, 65, 82, 32, 87, 73, 84, 72, 2, 21, 3, 73, 78, 87, 2, 217, 147, 6, - 4, 72, 69, 69, 76, 2, 139, 208, 3, 80, 12, 46, 73, 102, 85, 153, 145, 7, - 3, 65, 84, 69, 4, 56, 8, 32, 65, 78, 68, 32, 83, 75, 73, 243, 239, 7, 69, - 2, 17, 2, 32, 66, 2, 255, 215, 7, 79, 6, 32, 2, 76, 76, 235, 164, 8, 78, - 5, 11, 32, 2, 49, 10, 65, 78, 68, 32, 67, 82, 79, 83, 83, 66, 2, 11, 79, - 2, 187, 147, 7, 78, 42, 46, 65, 198, 4, 69, 210, 1, 73, 167, 1, 79, 14, - 64, 5, 78, 84, 69, 68, 32, 193, 146, 6, 5, 86, 79, 78, 73, 67, 12, 148, - 1, 12, 69, 81, 85, 65, 76, 32, 84, 79, 32, 79, 82, 32, 229, 1, 19, 78, - 79, 82, 84, 72, 32, 65, 82, 82, 79, 87, 32, 87, 73, 84, 72, 32, 72, 79, - 8, 60, 7, 71, 82, 69, 65, 84, 69, 82, 1, 4, 76, 69, 83, 83, 4, 29, 5, 45, - 84, 72, 65, 78, 5, 11, 32, 2, 25, 4, 87, 73, 84, 72, 2, 25, 4, 32, 68, - 79, 84, 2, 17, 2, 32, 73, 2, 11, 78, 2, 11, 83, 2, 183, 147, 6, 73, 4, - 24, 2, 79, 75, 43, 82, 2, 17, 2, 69, 68, 2, 131, 206, 5, 32, 2, 29, 5, - 73, 90, 79, 78, 84, 2, 11, 65, 2, 199, 238, 5, 76, 12, 80, 2, 69, 80, - 144, 144, 8, 9, 85, 84, 72, 32, 79, 82, 32, 83, 80, 203, 17, 68, 8, 40, - 4, 73, 78, 71, 32, 143, 228, 7, 89, 6, 176, 223, 4, 8, 65, 67, 67, 79, - 77, 77, 79, 68, 234, 174, 2, 83, 139, 86, 70, 6, 76, 9, 67, 69, 32, 79, - 70, 32, 80, 73, 90, 21, 6, 71, 72, 84, 76, 89, 32, 2, 211, 157, 8, 90, 4, - 40, 2, 83, 77, 173, 217, 6, 2, 70, 82, 2, 215, 234, 6, 73, 10, 18, 80, - 75, 84, 6, 152, 222, 4, 9, 73, 78, 71, 32, 76, 65, 82, 71, 69, 139, 193, - 3, 69, 4, 26, 32, 195, 158, 8, 72, 2, 11, 77, 2, 249, 132, 7, 3, 65, 67, - 72, 150, 1, 34, 65, 158, 13, 73, 207, 7, 79, 116, 32, 2, 76, 76, 155, - 142, 7, 83, 114, 30, 32, 141, 12, 2, 69, 82, 110, 194, 2, 65, 48, 3, 66, - 76, 85, 0, 5, 79, 82, 65, 78, 71, 20, 2, 67, 79, 158, 1, 68, 22, 69, 140, - 2, 11, 73, 68, 69, 79, 71, 82, 65, 80, 72, 73, 67, 28, 2, 76, 69, 34, 82, - 218, 3, 83, 22, 84, 36, 2, 85, 80, 56, 4, 86, 69, 69, 32, 136, 253, 1, 3, - 71, 82, 69, 34, 72, 146, 4, 80, 234, 77, 78, 222, 240, 2, 70, 83, 81, 6, - 194, 203, 4, 77, 214, 49, 73, 135, 138, 1, 83, 2, 135, 206, 6, 69, 12, - 68, 7, 78, 84, 65, 73, 78, 83, 32, 202, 130, 2, 77, 167, 199, 5, 76, 6, - 36, 4, 65, 83, 32, 77, 175, 1, 87, 2, 11, 69, 2, 11, 77, 2, 171, 219, 7, - 66, 2, 219, 130, 2, 79, 12, 84, 9, 76, 69, 77, 69, 78, 84, 32, 79, 70, - 162, 130, 2, 81, 42, 88, 175, 216, 2, 77, 7, 17, 2, 32, 87, 4, 25, 4, 73, - 84, 72, 32, 4, 26, 86, 171, 233, 4, 79, 2, 129, 243, 5, 21, 69, 82, 84, - 73, 67, 65, 76, 32, 66, 65, 82, 32, 65, 84, 32, 69, 78, 68, 32, 79, 70, - 2, 221, 196, 5, 2, 32, 67, 8, 130, 1, 70, 247, 132, 2, 83, 40, 96, 3, 73, - 71, 72, 64, 13, 79, 77, 65, 78, 32, 78, 85, 77, 69, 82, 65, 76, 32, 191, - 255, 5, 69, 6, 17, 2, 84, 32, 6, 170, 143, 4, 67, 210, 3, 80, 147, 8, 84, - 32, 62, 69, 50, 70, 62, 79, 46, 84, 166, 163, 6, 83, 211, 86, 78, 4, 26, - 76, 231, 233, 7, 73, 2, 183, 164, 6, 69, 8, 26, 73, 167, 155, 7, 79, 6, - 130, 26, 86, 255, 140, 6, 70, 6, 11, 78, 6, 11, 69, 7, 247, 191, 2, 32, - 8, 42, 87, 190, 163, 6, 72, 231, 159, 1, 69, 4, 26, 69, 231, 146, 8, 79, - 2, 143, 150, 7, 76, 2, 147, 199, 4, 69, 4, 182, 248, 3, 87, 211, 128, 2, - 73, 2, 185, 243, 4, 9, 45, 80, 79, 73, 78, 84, 73, 78, 71, 2, 11, 87, 2, - 21, 3, 73, 84, 72, 2, 11, 32, 2, 163, 166, 4, 85, 4, 29, 5, 32, 84, 72, - 65, 78, 5, 11, 32, 2, 11, 79, 2, 135, 189, 1, 82, 32, 34, 76, 141, 136, - 7, 2, 82, 75, 30, 40, 4, 73, 78, 71, 32, 131, 144, 8, 69, 28, 112, 14, - 67, 65, 84, 32, 70, 65, 67, 69, 32, 87, 73, 84, 72, 32, 41, 10, 70, 65, - 67, 69, 32, 87, 73, 84, 72, 32, 4, 160, 1, 2, 72, 69, 163, 236, 4, 79, - 24, 86, 72, 108, 10, 79, 80, 69, 78, 32, 77, 79, 85, 84, 72, 246, 1, 83, - 203, 219, 2, 84, 6, 34, 69, 54, 79, 231, 234, 7, 65, 2, 165, 146, 5, 8, - 65, 82, 84, 45, 83, 72, 65, 80, 2, 219, 201, 4, 82, 9, 29, 5, 32, 65, 78, - 68, 32, 6, 26, 67, 58, 83, 71, 84, 2, 17, 2, 79, 76, 2, 145, 188, 3, 4, - 68, 32, 83, 87, 2, 11, 77, 2, 11, 73, 2, 11, 76, 2, 217, 144, 5, 3, 73, - 78, 71, 2, 37, 7, 73, 71, 72, 84, 76, 89, 45, 2, 231, 143, 5, 67, 8, 64, - 11, 77, 73, 76, 73, 78, 71, 32, 69, 89, 69, 83, 175, 1, 85, 7, 29, 5, 32, - 65, 78, 68, 32, 4, 52, 4, 72, 65, 78, 68, 57, 5, 84, 72, 82, 69, 69, 2, - 221, 232, 4, 9, 32, 67, 79, 86, 69, 82, 73, 78, 71, 2, 241, 199, 4, 2, - 32, 72, 2, 17, 2, 78, 71, 2, 173, 245, 6, 4, 76, 65, 83, 83, 2, 171, 220, - 4, 75, 16, 42, 65, 32, 2, 69, 69, 21, 2, 79, 87, 4, 142, 255, 6, 73, 227, - 114, 75, 2, 131, 128, 7, 90, 10, 100, 7, 32, 67, 65, 80, 80, 69, 68, 28, - 3, 77, 65, 78, 136, 218, 2, 3, 66, 79, 65, 167, 143, 1, 70, 2, 137, 159, - 4, 2, 32, 77, 5, 49, 10, 32, 87, 73, 84, 72, 79, 85, 84, 32, 83, 2, 179, - 236, 6, 78, 155, 3, 162, 2, 67, 48, 2, 70, 84, 228, 1, 6, 71, 68, 73, 65, - 78, 32, 244, 10, 3, 76, 73, 68, 140, 2, 12, 79, 78, 32, 87, 73, 84, 72, - 32, 82, 73, 71, 72, 20, 11, 82, 65, 32, 83, 79, 77, 80, 69, 78, 71, 32, - 234, 2, 85, 216, 8, 6, 89, 79, 77, 66, 79, 32, 182, 226, 6, 77, 130, 135, - 1, 72, 3, 83, 4, 232, 227, 2, 3, 67, 69, 82, 215, 226, 4, 75, 10, 70, 32, - 124, 9, 87, 65, 82, 69, 45, 70, 85, 78, 67, 223, 250, 5, 66, 6, 58, 72, - 44, 6, 73, 67, 69, 32, 67, 82, 239, 188, 6, 83, 2, 11, 89, 2, 11, 80, 2, - 231, 174, 6, 72, 2, 191, 199, 6, 69, 2, 11, 84, 2, 203, 138, 6, 73, 84, - 248, 1, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 168, 2, 13, 73, 78, - 68, 69, 80, 69, 78, 68, 69, 78, 84, 32, 83, 20, 7, 76, 69, 84, 84, 69, - 82, 32, 188, 3, 7, 78, 85, 77, 66, 69, 82, 32, 113, 12, 80, 85, 78, 67, - 84, 85, 65, 84, 73, 79, 78, 32, 22, 140, 1, 3, 72, 79, 79, 20, 4, 76, 79, - 78, 71, 50, 83, 58, 84, 142, 227, 3, 68, 176, 237, 1, 4, 82, 69, 83, 72, - 129, 15, 4, 67, 85, 82, 86, 4, 195, 224, 5, 75, 2, 25, 4, 32, 72, 79, 79, - 2, 135, 209, 5, 75, 2, 21, 3, 84, 82, 79, 2, 11, 75, 2, 207, 208, 5, 69, - 4, 193, 223, 1, 2, 87, 79, 2, 143, 254, 6, 72, 42, 190, 1, 65, 50, 71, - 34, 76, 56, 5, 82, 69, 83, 72, 45, 2, 90, 34, 83, 66, 89, 158, 208, 1, - 72, 234, 5, 75, 198, 75, 66, 2, 70, 178, 216, 4, 78, 134, 2, 84, 2, 87, - 218, 103, 80, 171, 4, 77, 4, 26, 76, 163, 252, 6, 89, 2, 219, 215, 1, 69, - 2, 11, 73, 2, 239, 238, 2, 77, 4, 26, 65, 135, 147, 6, 69, 2, 193, 209, - 1, 2, 77, 69, 2, 11, 65, 2, 167, 251, 6, 89, 6, 26, 65, 251, 250, 6, 72, - 4, 182, 200, 1, 77, 139, 133, 6, 68, 2, 199, 208, 1, 79, 8, 18, 79, 59, - 84, 4, 11, 78, 4, 11, 69, 5, 11, 32, 2, 167, 166, 2, 72, 4, 182, 140, 6, - 87, 179, 157, 1, 69, 10, 66, 67, 0, 6, 72, 65, 76, 70, 32, 67, 53, 4, 84, - 87, 79, 32, 2, 21, 3, 73, 82, 67, 2, 173, 236, 4, 2, 76, 69, 6, 100, 13, - 86, 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, 82, 83, 13, 8, 67, 73, 82, - 67, 76, 69, 83, 32, 5, 11, 32, 2, 249, 166, 6, 4, 87, 73, 84, 72, 8, 30, - 32, 189, 1, 2, 85, 83, 4, 93, 21, 81, 85, 73, 76, 84, 32, 83, 81, 85, 65, - 82, 69, 32, 79, 82, 78, 65, 77, 69, 78, 84, 5, 11, 32, 2, 11, 73, 2, 17, - 2, 78, 32, 2, 11, 66, 2, 233, 212, 6, 4, 76, 65, 67, 75, 5, 145, 199, 4, - 7, 32, 87, 73, 84, 72, 32, 79, 2, 179, 251, 3, 84, 70, 52, 7, 76, 69, 84, - 84, 69, 82, 32, 159, 131, 6, 68, 50, 198, 1, 69, 32, 2, 77, 65, 30, 78, - 186, 146, 1, 66, 2, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, 2, 80, - 2, 82, 2, 83, 2, 84, 2, 86, 2, 89, 242, 222, 6, 65, 2, 73, 2, 79, 3, 85, - 4, 226, 241, 7, 69, 147, 1, 72, 4, 210, 242, 7, 69, 3, 72, 6, 182, 146, - 1, 71, 2, 89, 243, 222, 6, 65, 58, 104, 3, 84, 72, 32, 169, 160, 6, 17, + 69, 82, 40, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, 193, 179, 3, 5, 32, 79, + 86, 69, 82, 2, 21, 3, 32, 83, 84, 2, 215, 161, 10, 69, 2, 25, 4, 32, 79, + 80, 69, 2, 207, 146, 9, 78, 4, 26, 73, 179, 160, 10, 85, 2, 247, 160, 10, + 77, 211, 14, 174, 1, 68, 152, 20, 2, 71, 78, 184, 181, 1, 6, 77, 73, 76, + 65, 82, 32, 158, 2, 78, 202, 24, 88, 237, 238, 6, 15, 76, 72, 79, 85, 69, + 84, 84, 69, 32, 79, 70, 32, 74, 65, 80, 252, 1, 40, 5, 68, 72, 65, 77, + 32, 135, 17, 69, 184, 1, 202, 1, 69, 68, 7, 76, 69, 84, 84, 69, 82, 32, + 176, 4, 15, 82, 69, 80, 69, 84, 73, 84, 73, 79, 78, 32, 77, 65, 82, 75, + 50, 83, 164, 8, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 171, 175, + 6, 68, 2, 37, 7, 78, 68, 32, 79, 70, 32, 84, 2, 201, 210, 9, 2, 69, 88, + 102, 214, 1, 65, 98, 84, 242, 188, 6, 68, 158, 1, 86, 186, 5, 85, 186, + 202, 1, 73, 138, 196, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, + 2, 80, 138, 69, 72, 2, 76, 2, 77, 2, 82, 2, 89, 186, 2, 69, 3, 79, 11, + 72, 8, 76, 84, 69, 82, 78, 65, 84, 69, 214, 154, 10, 65, 2, 73, 3, 85, 2, + 235, 245, 9, 32, 14, 134, 1, 72, 252, 231, 5, 19, 87, 79, 45, 67, 73, 82, + 67, 76, 69, 32, 65, 76, 84, 69, 82, 78, 65, 84, 69, 254, 233, 3, 84, 195, + 71, 65, 4, 164, 217, 9, 20, 82, 69, 69, 45, 67, 73, 82, 67, 76, 69, 32, + 65, 76, 84, 69, 82, 78, 65, 84, 69, 147, 64, 65, 6, 11, 45, 6, 186, 152, + 10, 49, 2, 50, 3, 51, 44, 38, 69, 181, 7, 4, 73, 71, 78, 32, 32, 96, 11, + 67, 84, 73, 79, 78, 32, 77, 65, 82, 75, 32, 177, 6, 8, 80, 65, 82, 65, + 84, 79, 82, 32, 28, 80, 11, 68, 79, 85, 66, 76, 69, 32, 82, 73, 78, 71, + 57, 5, 87, 73, 84, 72, 32, 5, 11, 32, 2, 249, 231, 8, 6, 87, 73, 84, 72, + 32, 82, 24, 212, 1, 12, 67, 73, 82, 67, 76, 69, 83, 32, 65, 78, 68, 32, + 116, 5, 81, 85, 65, 68, 82, 0, 4, 83, 69, 80, 84, 12, 16, 82, 65, 89, 83, + 32, 65, 78, 68, 32, 68, 79, 84, 84, 69, 68, 32, 46, 68, 45, 3, 84, 82, + 73, 6, 60, 4, 70, 79, 85, 82, 0, 3, 84, 87, 79, 187, 229, 8, 82, 2, 225, + 207, 6, 8, 32, 69, 78, 67, 76, 79, 83, 85, 2, 83, 85, 6, 42, 68, 28, 3, + 84, 82, 73, 215, 1, 67, 2, 197, 1, 3, 79, 85, 66, 2, 171, 1, 80, 6, 52, + 9, 68, 69, 78, 84, 32, 65, 78, 68, 32, 103, 80, 4, 116, 6, 68, 79, 84, + 84, 69, 68, 49, 14, 85, 45, 83, 72, 65, 80, 69, 68, 32, 79, 82, 78, 65, + 77, 2, 17, 2, 76, 69, 2, 17, 2, 32, 67, 2, 25, 4, 82, 69, 83, 67, 2, 239, + 186, 1, 69, 4, 158, 237, 8, 66, 135, 83, 68, 12, 146, 229, 4, 83, 202, + 141, 1, 67, 98, 78, 138, 216, 3, 65, 239, 1, 86, 26, 74, 65, 94, 86, 210, + 183, 6, 85, 186, 202, 1, 73, 198, 140, 2, 69, 3, 79, 10, 168, 184, 6, 10, + 76, 84, 69, 82, 78, 65, 84, 69, 32, 85, 254, 214, 3, 65, 2, 73, 3, 85, 4, + 11, 79, 4, 33, 6, 67, 65, 76, 73, 67, 32, 4, 255, 183, 6, 82, 68, 84, 12, + 84, 73, 67, 32, 76, 69, 84, 84, 69, 82, 32, 78, 49, 5, 87, 65, 89, 83, + 32, 52, 178, 156, 1, 50, 222, 176, 3, 48, 131, 2, 49, 16, 56, 5, 66, 76, + 65, 67, 75, 1, 5, 87, 72, 73, 84, 69, 8, 11, 32, 8, 70, 82, 24, 3, 76, + 69, 70, 12, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, 21, 3, 73, 71, 72, 2, 11, + 84, 2, 225, 92, 6, 32, 80, 79, 73, 78, 84, 194, 10, 96, 8, 87, 82, 73, + 84, 73, 78, 71, 32, 241, 238, 1, 10, 32, 79, 70, 32, 84, 72, 69, 32, 72, + 79, 192, 10, 136, 3, 4, 65, 73, 82, 32, 192, 1, 2, 66, 82, 102, 67, 138, + 1, 68, 218, 4, 69, 242, 6, 70, 244, 3, 4, 87, 65, 76, 76, 138, 1, 72, + 234, 77, 76, 212, 6, 2, 77, 79, 222, 42, 78, 218, 1, 82, 182, 7, 83, 162, + 5, 84, 180, 10, 5, 71, 82, 65, 83, 80, 184, 5, 30, 85, 80, 80, 69, 82, + 32, 66, 79, 68, 89, 32, 84, 73, 76, 84, 73, 78, 71, 32, 70, 82, 79, 77, + 32, 72, 73, 80, 32, 74, 79, 135, 207, 4, 80, 8, 48, 4, 66, 76, 79, 87, + 29, 4, 83, 85, 67, 75, 4, 58, 32, 211, 226, 4, 73, 4, 30, 32, 61, 3, 73, + 78, 71, 2, 237, 157, 1, 10, 83, 77, 65, 76, 76, 32, 82, 79, 84, 65, 2, + 171, 134, 9, 32, 10, 52, 5, 69, 65, 84, 72, 32, 229, 169, 1, 2, 85, 83, + 4, 140, 164, 2, 2, 69, 88, 1, 2, 73, 78, 10, 40, 6, 72, 69, 69, 75, 83, + 32, 63, 79, 6, 154, 107, 83, 146, 38, 78, 153, 223, 3, 4, 80, 85, 70, 70, + 4, 178, 180, 9, 76, 223, 46, 77, 28, 108, 15, 82, 69, 65, 77, 89, 32, 69, + 89, 69, 66, 82, 79, 87, 83, 32, 165, 1, 7, 89, 78, 65, 77, 73, 67, 32, 8, + 64, 4, 68, 79, 87, 78, 0, 2, 85, 80, 29, 4, 78, 69, 85, 84, 2, 153, 143, + 1, 2, 32, 78, 4, 21, 3, 82, 65, 76, 4, 11, 32, 4, 194, 58, 68, 191, 199, + 9, 85, 20, 180, 1, 11, 69, 86, 69, 82, 89, 32, 79, 84, 72, 69, 82, 30, + 70, 22, 83, 128, 122, 9, 65, 82, 82, 79, 87, 72, 69, 65, 68, 234, 38, 82, + 136, 206, 3, 2, 84, 69, 21, 4, 71, 82, 65, 68, 2, 181, 230, 8, 2, 32, 84, + 2, 163, 146, 6, 65, 6, 68, 11, 73, 77, 85, 76, 84, 65, 78, 69, 79, 85, + 83, 151, 227, 8, 76, 5, 203, 151, 1, 32, 54, 64, 2, 89, 69, 172, 227, 4, + 4, 88, 67, 73, 84, 203, 138, 4, 65, 50, 166, 1, 32, 56, 15, 66, 82, 79, + 87, 83, 32, 83, 84, 82, 65, 73, 71, 72, 84, 32, 44, 5, 71, 65, 90, 69, + 45, 140, 2, 7, 76, 65, 83, 72, 69, 83, 32, 65, 2, 83, 32, 6, 220, 150, 1, + 5, 66, 76, 73, 78, 75, 243, 129, 5, 87, 6, 186, 53, 68, 154, 84, 78, 167, + 243, 8, 85, 18, 100, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, 25, + 10, 87, 65, 76, 76, 80, 76, 65, 78, 69, 32, 8, 82, 83, 207, 45, 67, 10, + 18, 67, 43, 83, 4, 254, 45, 85, 213, 95, 3, 73, 82, 67, 6, 37, 7, 84, 82, + 65, 73, 71, 72, 84, 7, 11, 32, 4, 202, 163, 1, 65, 55, 68, 6, 130, 51, + 68, 180, 173, 4, 4, 70, 76, 85, 84, 139, 154, 5, 85, 14, 112, 5, 72, 65, + 76, 70, 32, 26, 67, 28, 4, 87, 73, 68, 69, 230, 92, 79, 233, 135, 4, 6, + 83, 81, 85, 69, 69, 90, 4, 22, 67, 131, 93, 79, 2, 213, 232, 2, 2, 76, + 79, 4, 162, 67, 32, 217, 61, 4, 78, 73, 78, 71, 38, 204, 1, 28, 65, 67, + 69, 32, 68, 73, 82, 69, 67, 84, 73, 79, 78, 32, 80, 79, 83, 73, 84, 73, + 79, 78, 32, 78, 79, 83, 69, 32, 138, 1, 73, 82, 76, 176, 1, 8, 79, 82, + 69, 72, 69, 65, 68, 32, 187, 158, 7, 85, 6, 88, 10, 85, 80, 32, 79, 82, + 32, 68, 79, 87, 78, 13, 8, 70, 79, 82, 87, 65, 82, 68, 32, 5, 11, 32, 2, + 153, 231, 4, 3, 84, 73, 76, 12, 180, 225, 3, 11, 76, 76, 32, 77, 79, 68, + 73, 70, 73, 69, 82, 131, 195, 2, 78, 12, 44, 4, 73, 67, 75, 32, 29, 3, + 79, 79, 82, 10, 254, 140, 1, 76, 35, 83, 2, 225, 247, 8, 20, 80, 76, 65, + 78, 69, 32, 83, 72, 79, 85, 76, 68, 69, 82, 32, 72, 73, 80, 32, 77, 6, + 166, 89, 87, 222, 38, 67, 47, 78, 156, 4, 34, 65, 133, 75, 3, 69, 65, 68, + 140, 4, 36, 3, 78, 68, 45, 143, 186, 9, 73, 138, 4, 92, 5, 65, 78, 71, + 76, 69, 138, 5, 67, 150, 10, 70, 186, 42, 72, 241, 12, 4, 79, 86, 65, 76, + 37, 11, 32, 34, 188, 1, 5, 73, 78, 68, 69, 88, 176, 1, 7, 76, 73, 84, 84, + 76, 69, 32, 136, 1, 5, 82, 73, 78, 71, 32, 173, 66, 18, 77, 73, 68, 68, + 76, 69, 32, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, 17, 11, 32, 14, + 128, 1, 7, 77, 73, 68, 68, 76, 69, 32, 228, 24, 11, 82, 73, 78, 71, 32, + 76, 73, 84, 84, 76, 69, 241, 42, 5, 84, 72, 85, 77, 66, 4, 174, 70, 76, + 247, 215, 8, 82, 8, 44, 5, 73, 78, 68, 69, 88, 207, 238, 9, 85, 7, 145, + 24, 18, 32, 84, 72, 85, 77, 66, 32, 73, 78, 68, 69, 88, 32, 84, 72, 85, + 77, 66, 4, 108, 22, 68, 79, 87, 78, 32, 77, 73, 68, 68, 76, 69, 32, 84, + 72, 85, 77, 66, 32, 73, 78, 68, 69, 155, 68, 76, 2, 207, 169, 8, 88, 88, + 64, 5, 73, 82, 67, 76, 69, 184, 3, 3, 76, 65, 87, 183, 2, 85, 35, 11, 32, + 32, 116, 5, 73, 78, 68, 69, 88, 200, 1, 7, 76, 73, 84, 84, 76, 69, 32, + 36, 7, 77, 73, 68, 68, 76, 69, 32, 163, 64, 82, 21, 11, 32, 18, 72, 6, + 77, 73, 68, 68, 76, 69, 198, 26, 72, 242, 38, 82, 131, 230, 8, 66, 13, + 11, 32, 10, 64, 5, 67, 82, 79, 83, 83, 198, 64, 84, 82, 76, 247, 215, 8, + 82, 4, 134, 65, 32, 231, 226, 8, 69, 4, 194, 193, 8, 73, 159, 168, 1, 85, + 6, 252, 47, 10, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 191, 185, 9, 85, + 17, 11, 32, 14, 144, 2, 28, 77, 73, 68, 68, 76, 69, 32, 82, 73, 78, 71, + 32, 76, 73, 84, 84, 76, 69, 32, 67, 79, 78, 74, 79, 73, 78, 69, 68, 176, + 49, 2, 70, 79, 198, 11, 78, 162, 1, 84, 197, 118, 23, 73, 78, 68, 69, 88, + 32, 84, 72, 85, 77, 66, 32, 67, 85, 82, 86, 69, 32, 84, 72, 85, 77, 66, + 5, 247, 180, 1, 32, 38, 46, 80, 149, 2, 6, 82, 76, 73, 67, 85, 69, 31, + 11, 32, 28, 188, 1, 5, 73, 78, 68, 69, 88, 56, 19, 70, 73, 86, 69, 32, + 70, 73, 78, 71, 69, 82, 83, 32, 83, 80, 82, 69, 65, 68, 196, 50, 7, 77, + 73, 68, 68, 76, 69, 32, 18, 79, 218, 7, 78, 163, 1, 84, 9, 11, 32, 6, 40, + 5, 84, 72, 85, 77, 66, 243, 58, 82, 5, 215, 46, 32, 9, 11, 32, 6, 72, 5, + 73, 78, 68, 69, 88, 0, 6, 77, 73, 68, 68, 76, 69, 179, 71, 79, 2, 193, + 147, 9, 13, 32, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, 32, 172, 2, + 44, 3, 73, 83, 84, 177, 33, 3, 76, 65, 84, 247, 1, 11, 32, 244, 1, 160, + 2, 5, 73, 78, 68, 69, 88, 192, 16, 7, 76, 73, 84, 84, 76, 69, 32, 196, 2, + 7, 77, 73, 68, 68, 76, 69, 32, 200, 4, 5, 82, 73, 78, 71, 32, 132, 2, 5, + 84, 72, 85, 77, 66, 138, 2, 72, 205, 9, 22, 70, 79, 85, 82, 32, 70, 73, + 78, 71, 69, 82, 83, 32, 67, 79, 78, 74, 79, 73, 78, 69, 68, 137, 1, 11, + 32, 134, 1, 232, 1, 4, 66, 69, 78, 84, 36, 6, 72, 73, 78, 71, 69, 68, 76, + 6, 77, 73, 68, 68, 76, 69, 168, 7, 2, 67, 85, 64, 6, 84, 72, 85, 77, 66, + 32, 160, 5, 16, 85, 80, 32, 77, 73, 68, 68, 76, 69, 32, 72, 73, 78, 71, + 69, 68, 151, 4, 82, 5, 217, 45, 5, 32, 79, 86, 69, 82, 9, 11, 32, 6, 252, + 20, 8, 77, 73, 68, 68, 76, 69, 32, 85, 167, 172, 8, 76, 71, 11, 32, 68, + 236, 1, 4, 66, 69, 78, 84, 42, 67, 244, 1, 10, 85, 80, 32, 83, 80, 82, + 69, 65, 68, 32, 100, 6, 72, 73, 78, 71, 69, 68, 46, 82, 80, 5, 84, 72, + 85, 77, 66, 188, 28, 14, 83, 84, 82, 65, 73, 71, 72, 84, 32, 84, 72, 85, + 77, 66, 227, 17, 76, 5, 213, 92, 6, 32, 84, 72, 85, 77, 66, 28, 68, 8, + 79, 78, 74, 79, 73, 78, 69, 68, 233, 1, 4, 82, 79, 83, 83, 23, 11, 32, + 20, 144, 1, 6, 67, 85, 80, 80, 69, 68, 28, 6, 84, 72, 85, 77, 66, 32, 68, + 5, 72, 73, 78, 71, 69, 166, 22, 73, 165, 7, 6, 77, 73, 68, 68, 76, 69, 5, + 11, 32, 2, 203, 27, 84, 8, 160, 1, 4, 83, 73, 68, 69, 219, 61, 70, 6, 22, + 69, 159, 47, 32, 4, 223, 15, 68, 5, 241, 30, 7, 32, 83, 80, 82, 69, 65, + 68, 8, 32, 3, 73, 78, 71, 247, 19, 65, 7, 11, 32, 4, 138, 36, 67, 131, + 240, 8, 66, 19, 11, 32, 16, 64, 6, 65, 78, 71, 76, 69, 68, 22, 67, 106, + 72, 163, 146, 9, 66, 5, 167, 221, 5, 32, 6, 74, 85, 230, 7, 73, 241, 25, + 10, 79, 78, 74, 79, 73, 78, 69, 68, 32, 72, 2, 201, 193, 4, 2, 80, 80, 4, + 194, 33, 73, 217, 26, 2, 79, 79, 40, 164, 1, 7, 65, 78, 71, 76, 69, 68, + 32, 46, 67, 220, 1, 14, 70, 79, 82, 87, 65, 82, 68, 32, 73, 78, 68, 69, + 88, 32, 32, 4, 72, 79, 79, 75, 53, 4, 83, 73, 68, 69, 4, 128, 1, 2, 73, + 78, 1, 3, 79, 85, 84, 12, 36, 5, 73, 82, 67, 76, 69, 15, 85, 5, 47, 68, + 8, 32, 4, 80, 80, 69, 68, 39, 82, 2, 225, 40, 5, 32, 77, 73, 68, 68, 6, + 56, 9, 86, 69, 32, 84, 72, 85, 77, 66, 32, 143, 37, 76, 4, 162, 160, 1, + 73, 163, 198, 4, 85, 4, 202, 84, 83, 131, 186, 8, 66, 7, 157, 8, 9, 69, + 68, 32, 77, 73, 68, 68, 76, 69, 15, 11, 32, 12, 92, 6, 73, 78, 68, 69, + 88, 32, 156, 13, 5, 84, 72, 85, 77, 66, 193, 8, 4, 66, 79, 84, 72, 4, 26, + 72, 243, 140, 9, 66, 2, 215, 152, 8, 73, 7, 37, 7, 32, 84, 72, 85, 77, + 66, 32, 4, 178, 28, 67, 207, 129, 1, 83, 22, 88, 4, 68, 79, 87, 78, 186, + 1, 84, 158, 6, 82, 130, 21, 73, 230, 238, 8, 66, 159, 67, 85, 9, 11, 32, + 6, 80, 9, 79, 84, 72, 69, 82, 83, 32, 67, 73, 25, 7, 82, 73, 80, 80, 76, + 69, 32, 2, 225, 51, 2, 82, 67, 4, 22, 67, 171, 80, 83, 2, 11, 85, 2, 169, + 185, 4, 2, 82, 86, 4, 196, 35, 6, 79, 85, 67, 72, 69, 83, 39, 72, 30, + 134, 1, 82, 28, 6, 84, 72, 85, 77, 66, 32, 138, 3, 85, 134, 1, 68, 210, + 30, 76, 189, 128, 8, 9, 66, 69, 78, 84, 32, 79, 86, 69, 82, 4, 238, 4, + 65, 231, 29, 73, 16, 80, 7, 65, 78, 71, 76, 69, 68, 32, 126, 67, 124, 4, + 72, 79, 79, 75, 147, 32, 76, 6, 60, 10, 79, 85, 84, 32, 73, 78, 68, 69, + 88, 32, 215, 1, 73, 4, 26, 67, 155, 202, 9, 85, 2, 249, 185, 2, 3, 82, + 79, 83, 6, 76, 12, 73, 82, 67, 76, 69, 68, 32, 73, 78, 68, 69, 88, 45, 3, + 85, 80, 80, 4, 11, 32, 4, 150, 21, 72, 135, 180, 9, 85, 2, 25, 4, 69, 68, + 32, 73, 2, 233, 30, 4, 78, 68, 69, 88, 4, 11, 80, 5, 175, 15, 32, 18, + 102, 68, 20, 6, 77, 73, 68, 68, 76, 69, 42, 82, 198, 29, 84, 82, 76, 210, + 128, 8, 73, 159, 168, 1, 85, 2, 151, 241, 7, 79, 7, 11, 32, 4, 206, 3, + 82, 179, 16, 67, 2, 11, 65, 2, 37, 7, 73, 83, 69, 68, 32, 75, 78, 2, 11, + 85, 2, 11, 67, 2, 131, 160, 8, 75, 35, 11, 32, 32, 148, 1, 8, 66, 69, 84, + 87, 69, 69, 78, 32, 102, 72, 20, 5, 79, 86, 69, 82, 32, 120, 4, 83, 73, + 68, 69, 100, 6, 85, 78, 68, 69, 82, 32, 207, 40, 70, 8, 80, 12, 73, 78, + 68, 69, 88, 32, 77, 73, 68, 68, 76, 69, 246, 20, 77, 155, 6, 82, 5, 135, + 70, 32, 2, 243, 174, 4, 69, 4, 52, 6, 70, 79, 85, 82, 32, 82, 161, 2, 2, + 84, 87, 2, 11, 65, 2, 233, 80, 9, 73, 83, 69, 68, 32, 75, 78, 85, 67, 6, + 11, 32, 6, 38, 68, 190, 15, 67, 131, 240, 8, 66, 2, 25, 4, 73, 65, 71, + 79, 2, 235, 182, 8, 78, 10, 54, 73, 34, 84, 48, 4, 70, 79, 85, 82, 131, + 23, 76, 2, 161, 7, 4, 78, 68, 69, 88, 4, 34, 87, 13, 4, 72, 82, 69, 69, + 2, 11, 79, 2, 173, 176, 8, 5, 32, 70, 73, 78, 71, 55, 11, 32, 52, 194, 1, + 70, 172, 3, 4, 72, 69, 69, 76, 192, 1, 6, 83, 80, 76, 73, 84, 32, 236, 1, + 6, 84, 72, 85, 77, 66, 32, 205, 249, 4, 16, 66, 69, 84, 87, 69, 69, 78, + 32, 80, 65, 76, 77, 32, 70, 65, 67, 24, 140, 1, 18, 73, 86, 69, 32, 70, + 73, 78, 71, 69, 82, 83, 32, 83, 80, 82, 69, 65, 68, 165, 1, 11, 79, 85, + 82, 32, 70, 73, 78, 71, 69, 82, 83, 15, 11, 32, 12, 68, 6, 72, 73, 78, + 71, 69, 68, 42, 84, 186, 2, 70, 203, 247, 8, 66, 7, 11, 32, 4, 190, 4, + 84, 155, 15, 78, 2, 189, 35, 6, 72, 85, 77, 66, 32, 70, 11, 11, 32, 8, + 72, 9, 67, 79, 78, 74, 79, 73, 78, 69, 68, 154, 8, 72, 235, 240, 8, 66, + 5, 225, 159, 9, 3, 32, 83, 80, 11, 11, 32, 8, 96, 19, 70, 73, 86, 69, 32, + 70, 73, 78, 71, 69, 82, 83, 32, 83, 80, 82, 69, 65, 68, 151, 2, 84, 7, + 11, 32, 4, 26, 70, 203, 247, 8, 66, 2, 21, 3, 79, 85, 82, 2, 167, 1, 32, + 10, 72, 6, 67, 69, 78, 84, 82, 69, 96, 5, 73, 78, 68, 69, 88, 167, 16, + 76, 7, 49, 10, 32, 84, 72, 85, 77, 66, 32, 83, 73, 68, 4, 11, 69, 5, 11, + 32, 2, 135, 246, 8, 66, 2, 11, 32, 2, 11, 84, 2, 153, 135, 1, 5, 72, 85, + 77, 66, 32, 6, 242, 30, 70, 142, 104, 83, 183, 238, 7, 66, 82, 48, 4, 73, + 78, 71, 69, 181, 9, 3, 79, 79, 75, 63, 11, 32, 60, 206, 1, 70, 172, 1, 5, + 73, 78, 68, 69, 88, 196, 2, 6, 76, 73, 84, 84, 76, 69, 80, 6, 77, 73, 68, + 68, 76, 69, 30, 79, 64, 4, 82, 73, 78, 71, 124, 6, 84, 72, 85, 77, 66, + 32, 158, 6, 78, 195, 147, 4, 83, 4, 92, 19, 73, 86, 69, 32, 70, 73, 78, + 71, 69, 82, 83, 32, 83, 80, 82, 69, 65, 68, 32, 19, 79, 2, 191, 25, 79, + 2, 249, 1, 11, 85, 82, 32, 70, 73, 78, 71, 69, 82, 83, 32, 23, 11, 32, + 20, 86, 72, 40, 7, 77, 73, 68, 68, 76, 69, 32, 104, 5, 84, 72, 85, 77, + 66, 219, 9, 82, 2, 11, 73, 2, 233, 159, 4, 2, 78, 71, 6, 36, 4, 82, 73, + 78, 71, 203, 10, 76, 5, 11, 32, 2, 11, 67, 2, 21, 3, 79, 78, 74, 2, 175, + 33, 79, 11, 11, 32, 8, 34, 83, 210, 22, 79, 203, 39, 76, 4, 218, 159, 7, + 73, 195, 8, 77, 9, 11, 32, 6, 22, 73, 199, 8, 84, 4, 25, 4, 78, 68, 69, + 88, 5, 155, 8, 32, 5, 11, 32, 2, 171, 8, 82, 8, 21, 3, 80, 69, 78, 9, 11, + 32, 6, 178, 7, 78, 163, 1, 84, 5, 97, 22, 32, 68, 79, 87, 78, 32, 73, 78, + 68, 69, 88, 32, 84, 72, 85, 77, 66, 32, 72, 79, 79, 75, 2, 157, 77, 2, + 32, 77, 6, 68, 9, 66, 69, 84, 87, 69, 69, 78, 32, 77, 53, 4, 83, 73, 68, + 69, 2, 29, 5, 73, 68, 68, 76, 69, 2, 219, 153, 4, 32, 5, 33, 6, 32, 84, + 79, 85, 67, 72, 2, 169, 134, 8, 3, 73, 78, 71, 21, 11, 32, 18, 172, 1, 4, + 67, 85, 82, 76, 28, 18, 73, 78, 68, 69, 88, 32, 82, 73, 78, 71, 32, 76, + 73, 84, 84, 76, 69, 32, 48, 7, 77, 73, 68, 68, 76, 69, 32, 225, 2, 4, 82, + 73, 78, 71, 2, 173, 157, 5, 2, 73, 67, 6, 154, 193, 5, 85, 134, 242, 2, + 79, 243, 41, 73, 8, 104, 21, 82, 73, 78, 71, 32, 76, 73, 84, 84, 76, 69, + 32, 67, 79, 78, 74, 79, 73, 78, 69, 68, 143, 2, 84, 7, 211, 228, 2, 32, + 17, 11, 32, 14, 112, 14, 70, 73, 86, 69, 32, 70, 73, 78, 71, 69, 82, 83, + 32, 83, 22, 76, 66, 78, 70, 82, 94, 84, 167, 128, 8, 73, 2, 219, 160, 2, + 80, 2, 21, 3, 73, 84, 84, 2, 17, 2, 76, 69, 2, 139, 180, 8, 32, 2, 11, + 79, 2, 11, 32, 2, 11, 84, 2, 11, 72, 2, 167, 134, 6, 85, 2, 11, 73, 2, + 21, 3, 78, 71, 32, 2, 11, 76, 2, 11, 73, 2, 11, 84, 2, 163, 130, 8, 84, + 4, 29, 5, 72, 85, 77, 66, 32, 4, 194, 14, 70, 143, 104, 83, 17, 11, 32, + 14, 56, 8, 77, 79, 86, 69, 77, 69, 78, 84, 251, 164, 8, 82, 12, 26, 45, + 139, 211, 7, 32, 10, 100, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, + 25, 10, 87, 65, 76, 76, 80, 76, 65, 78, 69, 32, 4, 62, 67, 223, 40, 83, + 6, 38, 67, 28, 2, 84, 73, 195, 40, 83, 2, 173, 169, 8, 2, 85, 82, 2, 187, + 137, 9, 76, 38, 50, 73, 225, 3, 7, 79, 67, 65, 84, 73, 79, 78, 22, 32, 3, + 77, 66, 32, 171, 1, 80, 16, 56, 4, 67, 79, 77, 66, 29, 6, 76, 69, 78, 71, + 84, 72, 2, 241, 222, 5, 2, 73, 78, 14, 11, 45, 14, 150, 164, 9, 49, 2, + 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 55, 6, 58, 32, 153, 1, 9, 83, 32, 80, + 82, 69, 83, 83, 69, 68, 4, 116, 12, 76, 79, 87, 69, 82, 32, 79, 86, 69, + 82, 32, 85, 133, 135, 8, 11, 85, 80, 80, 69, 82, 32, 79, 86, 69, 82, 32, + 2, 11, 80, 2, 167, 228, 8, 80, 2, 29, 5, 32, 84, 79, 71, 69, 2, 11, 84, + 2, 231, 227, 8, 72, 16, 22, 32, 203, 1, 45, 12, 148, 1, 2, 72, 69, 240, + 177, 2, 3, 84, 79, 82, 168, 233, 4, 3, 68, 69, 80, 0, 3, 87, 73, 68, 189, + 124, 10, 76, 73, 77, 66, 83, 32, 68, 73, 71, 73, 4, 196, 13, 4, 65, 68, + 32, 78, 135, 232, 8, 73, 4, 52, 5, 70, 76, 79, 79, 82, 1, 4, 87, 65, 76, + 76, 2, 225, 224, 8, 5, 80, 76, 65, 78, 69, 156, 3, 64, 4, 85, 84, 72, 32, + 161, 5, 7, 86, 69, 77, 69, 78, 84, 45, 54, 186, 1, 67, 88, 5, 70, 82, 79, + 87, 78, 0, 5, 83, 77, 73, 76, 69, 56, 4, 75, 73, 83, 83, 36, 5, 79, 80, + 69, 78, 32, 192, 1, 5, 84, 69, 78, 83, 69, 165, 29, 5, 87, 82, 73, 78, + 75, 8, 48, 6, 76, 79, 83, 69, 68, 32, 147, 235, 7, 79, 6, 222, 2, 70, + 142, 38, 67, 47, 78, 7, 11, 32, 4, 22, 79, 203, 1, 87, 2, 251, 197, 7, + 80, 7, 11, 32, 4, 166, 1, 87, 83, 70, 18, 100, 4, 79, 86, 65, 76, 0, 9, + 82, 69, 67, 84, 65, 78, 71, 76, 69, 42, 87, 82, 70, 211, 197, 7, 67, 7, + 11, 32, 4, 26, 87, 255, 195, 7, 89, 2, 25, 4, 82, 73, 78, 75, 2, 131, + 134, 4, 76, 7, 11, 32, 4, 18, 70, 43, 83, 2, 17, 2, 79, 82, 2, 215, 128, + 8, 87, 2, 17, 2, 85, 67, 2, 147, 133, 4, 75, 230, 2, 192, 1, 9, 68, 73, + 65, 71, 79, 78, 65, 76, 32, 148, 1, 11, 70, 76, 79, 79, 82, 80, 76, 65, + 78, 69, 32, 184, 14, 6, 72, 73, 78, 71, 69, 32, 189, 2, 10, 87, 65, 76, + 76, 80, 76, 65, 78, 69, 32, 32, 56, 8, 66, 69, 84, 87, 69, 69, 78, 32, + 22, 65, 31, 84, 16, 18, 65, 31, 84, 8, 229, 28, 3, 87, 65, 89, 8, 201, + 28, 6, 79, 87, 65, 82, 68, 83, 150, 1, 208, 2, 24, 65, 82, 77, 32, 67, + 73, 82, 67, 76, 69, 32, 72, 73, 84, 84, 73, 78, 71, 32, 87, 65, 76, 76, + 32, 38, 66, 34, 67, 224, 1, 8, 70, 73, 78, 71, 69, 82, 32, 67, 52, 5, 72, + 85, 77, 80, 32, 184, 3, 5, 76, 79, 79, 80, 32, 198, 1, 83, 108, 7, 84, + 82, 73, 80, 76, 69, 32, 110, 87, 206, 12, 68, 198, 2, 80, 154, 6, 90, + 231, 246, 7, 74, 12, 178, 7, 76, 154, 9, 77, 39, 83, 8, 150, 17, 79, 151, + 242, 7, 69, 28, 86, 72, 20, 5, 85, 82, 86, 69, 32, 196, 29, 5, 79, 82, + 78, 69, 82, 211, 177, 7, 82, 2, 195, 224, 7, 69, 18, 80, 4, 67, 79, 77, + 66, 158, 8, 72, 230, 15, 76, 194, 172, 2, 77, 247, 182, 1, 83, 2, 11, 73, + 2, 187, 253, 3, 78, 6, 128, 9, 6, 73, 82, 67, 76, 69, 83, 239, 20, 79, + 18, 56, 8, 72, 73, 84, 84, 73, 78, 71, 32, 167, 250, 3, 83, 16, 72, 8, + 67, 69, 73, 76, 73, 78, 71, 32, 101, 6, 70, 76, 79, 79, 82, 32, 8, 56, 5, + 76, 65, 82, 71, 69, 1, 5, 83, 77, 65, 76, 76, 4, 11, 32, 4, 206, 54, 84, + 135, 2, 68, 8, 88, 4, 83, 77, 65, 76, 12, 5, 76, 65, 82, 71, 69, 17, 7, + 84, 82, 73, 80, 76, 69, 32, 2, 11, 76, 2, 255, 18, 32, 4, 56, 5, 76, 65, + 82, 71, 69, 1, 5, 83, 77, 65, 76, 76, 2, 253, 52, 2, 32, 84, 18, 56, 8, + 72, 73, 84, 84, 73, 78, 71, 32, 239, 246, 3, 83, 16, 64, 7, 67, 69, 73, + 76, 73, 78, 71, 1, 5, 70, 76, 79, 79, 82, 8, 11, 32, 8, 22, 76, 191, 9, + 83, 4, 249, 22, 4, 65, 82, 71, 69, 12, 44, 6, 72, 65, 75, 73, 78, 71, + 243, 16, 73, 2, 21, 3, 32, 80, 65, 2, 149, 246, 3, 4, 82, 65, 76, 76, 8, + 76, 12, 65, 76, 84, 69, 82, 78, 65, 84, 73, 78, 71, 32, 138, 18, 87, 63, + 83, 4, 134, 18, 87, 255, 20, 77, 18, 80, 4, 65, 86, 69, 32, 169, 1, 11, + 82, 73, 83, 84, 32, 67, 73, 82, 67, 76, 69, 14, 30, 72, 102, 83, 171, 20, + 76, 8, 37, 7, 73, 84, 84, 73, 78, 71, 32, 8, 252, 2, 4, 67, 69, 73, 76, + 25, 5, 70, 76, 79, 79, 82, 4, 182, 156, 5, 78, 247, 225, 1, 77, 4, 209, + 5, 10, 32, 72, 73, 84, 84, 73, 78, 71, 32, 87, 14, 112, 3, 85, 80, 32, + 184, 1, 6, 68, 79, 87, 78, 32, 83, 197, 235, 5, 10, 83, 73, 68, 69, 32, + 84, 79, 32, 83, 73, 10, 40, 5, 68, 79, 87, 78, 32, 143, 1, 83, 8, 68, 8, + 65, 76, 84, 69, 82, 78, 65, 84, 230, 17, 76, 143, 222, 3, 83, 4, 21, 3, + 73, 78, 71, 4, 11, 32, 4, 190, 17, 76, 143, 222, 3, 83, 2, 187, 30, 69, + 162, 1, 148, 2, 11, 65, 82, 77, 32, 67, 73, 82, 67, 76, 69, 32, 98, 66, + 54, 67, 174, 4, 68, 100, 8, 70, 73, 78, 71, 69, 82, 32, 67, 64, 5, 72, + 85, 77, 80, 32, 60, 5, 76, 79, 79, 80, 32, 102, 80, 34, 83, 216, 1, 7, + 84, 82, 73, 80, 76, 69, 32, 218, 1, 87, 202, 2, 90, 231, 246, 7, 74, 8, + 18, 77, 39, 83, 4, 225, 13, 5, 69, 68, 73, 85, 77, 4, 11, 77, 4, 177, 13, + 3, 65, 76, 76, 12, 34, 79, 185, 13, 3, 69, 78, 68, 6, 183, 13, 88, 46, + 100, 6, 79, 82, 78, 69, 82, 32, 88, 4, 85, 82, 86, 69, 232, 11, 4, 72, + 69, 67, 75, 211, 177, 7, 82, 8, 54, 82, 194, 12, 76, 154, 167, 2, 77, + 247, 182, 1, 83, 2, 11, 79, 2, 159, 187, 5, 84, 30, 50, 32, 137, 2, 7, + 68, 32, 67, 82, 79, 83, 83, 26, 66, 72, 68, 2, 84, 72, 133, 5, 7, 81, 85, + 65, 82, 84, 69, 82, 12, 196, 5, 10, 65, 76, 70, 45, 67, 73, 82, 67, 76, + 69, 147, 14, 73, 6, 96, 2, 69, 78, 29, 18, 82, 69, 69, 45, 81, 85, 65, + 82, 84, 69, 82, 32, 67, 73, 82, 67, 76, 69, 2, 11, 32, 2, 131, 1, 83, 4, + 11, 32, 4, 238, 176, 2, 77, 247, 182, 1, 83, 8, 33, 6, 79, 85, 66, 76, + 69, 32, 8, 30, 83, 150, 4, 65, 75, 87, 2, 213, 210, 8, 3, 84, 82, 65, 6, + 32, 3, 73, 82, 67, 151, 9, 79, 4, 173, 7, 3, 76, 69, 83, 10, 142, 8, 76, + 166, 8, 72, 246, 158, 2, 77, 247, 182, 1, 83, 12, 68, 5, 83, 77, 65, 76, + 76, 142, 7, 76, 166, 8, 72, 247, 158, 2, 77, 5, 11, 32, 2, 207, 36, 68, + 6, 181, 6, 4, 69, 65, 75, 83, 12, 22, 73, 211, 36, 72, 10, 29, 5, 78, 71, + 76, 69, 32, 10, 52, 8, 83, 84, 82, 65, 73, 71, 72, 84, 207, 1, 87, 8, 11, + 32, 8, 42, 76, 194, 172, 2, 77, 247, 182, 1, 83, 4, 25, 4, 65, 82, 71, + 69, 5, 151, 221, 8, 83, 8, 26, 65, 74, 87, 63, 83, 4, 49, 10, 76, 84, 69, + 82, 78, 65, 84, 73, 78, 71, 5, 17, 2, 32, 87, 2, 29, 5, 82, 73, 83, 84, + 32, 2, 149, 208, 7, 2, 70, 76, 2, 37, 7, 84, 82, 65, 73, 71, 72, 84, 2, + 139, 20, 32, 26, 104, 4, 65, 86, 69, 32, 185, 1, 17, 82, 73, 83, 84, 32, + 67, 73, 82, 67, 76, 69, 32, 70, 82, 79, 78, 84, 22, 108, 6, 67, 85, 82, + 86, 69, 32, 140, 1, 13, 68, 73, 65, 71, 79, 78, 65, 76, 32, 80, 65, 84, + 72, 223, 8, 72, 12, 48, 4, 68, 79, 85, 66, 1, 4, 84, 82, 73, 80, 6, 85, + 2, 76, 69, 4, 11, 32, 4, 190, 30, 68, 43, 83, 6, 29, 5, 73, 71, 90, 65, + 71, 6, 11, 32, 6, 42, 76, 154, 167, 2, 77, 247, 182, 1, 83, 2, 159, 178, + 7, 65, 10, 40, 4, 79, 83, 69, 32, 247, 193, 7, 69, 8, 26, 67, 46, 78, 35, + 87, 2, 11, 79, 2, 193, 226, 7, 3, 78, 84, 65, 2, 197, 231, 7, 3, 69, 85, + 84, 4, 44, 3, 82, 73, 78, 237, 157, 1, 2, 73, 71, 2, 199, 177, 5, 75, 72, + 56, 7, 79, 84, 65, 84, 73, 79, 78, 205, 22, 2, 85, 66, 66, 60, 10, 32, + 77, 79, 68, 73, 70, 73, 69, 82, 45, 155, 1, 45, 30, 82, 49, 254, 240, 8, + 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 14, 250, 240, 8, 48, + 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 36, 104, 11, 70, 76, 79, 79, + 82, 80, 76, 65, 78, 69, 32, 133, 2, 10, 87, 65, 76, 76, 80, 76, 65, 78, + 69, 32, 18, 100, 4, 68, 79, 85, 66, 0, 4, 83, 73, 78, 71, 21, 11, 65, 76, + 84, 69, 82, 78, 65, 84, 73, 78, 71, 6, 17, 2, 76, 69, 7, 45, 9, 32, 72, + 73, 84, 84, 73, 78, 71, 32, 4, 32, 2, 67, 69, 33, 2, 70, 76, 2, 11, 73, + 2, 235, 156, 8, 76, 2, 243, 180, 8, 79, 18, 88, 8, 65, 76, 84, 69, 82, + 78, 65, 84, 44, 4, 68, 79, 85, 66, 1, 4, 83, 73, 78, 71, 6, 72, 4, 73, + 78, 71, 32, 163, 236, 8, 69, 6, 17, 2, 76, 69, 7, 11, 32, 4, 11, 72, 4, + 11, 73, 4, 33, 6, 84, 84, 73, 78, 71, 32, 4, 44, 5, 70, 82, 79, 78, 84, + 139, 249, 4, 67, 2, 253, 224, 6, 2, 32, 87, 30, 172, 1, 8, 72, 79, 85, + 76, 68, 69, 82, 32, 196, 1, 7, 81, 85, 69, 69, 90, 69, 32, 240, 1, 7, 85, + 82, 70, 65, 67, 69, 32, 240, 10, 5, 84, 82, 73, 75, 69, 183, 140, 5, 69, + 6, 100, 4, 72, 73, 80, 32, 225, 251, 3, 15, 84, 73, 76, 84, 73, 78, 71, + 32, 70, 82, 79, 77, 32, 87, 65, 4, 48, 4, 80, 79, 83, 73, 145, 205, 7, 2, + 83, 80, 2, 11, 84, 2, 145, 161, 5, 2, 73, 79, 12, 48, 6, 70, 76, 73, 67, + 75, 32, 18, 76, 35, 83, 2, 211, 16, 65, 4, 129, 1, 4, 65, 82, 71, 69, 6, + 34, 69, 65, 4, 77, 65, 76, 76, 2, 17, 2, 81, 85, 2, 21, 3, 69, 78, 84, 2, + 147, 219, 7, 73, 4, 11, 32, 4, 214, 11, 77, 187, 4, 83, 4, 22, 83, 135, + 11, 66, 2, 129, 208, 1, 4, 89, 77, 66, 79, 82, 58, 69, 218, 2, 79, 137, + 8, 6, 82, 65, 86, 69, 76, 45, 20, 76, 3, 69, 84, 72, 185, 1, 11, 78, 83, + 69, 32, 67, 72, 69, 69, 75, 83, 32, 15, 11, 32, 12, 56, 3, 79, 78, 32, + 86, 77, 177, 5, 4, 66, 73, 84, 69, 8, 56, 4, 76, 73, 80, 83, 1, 6, 84, + 79, 78, 71, 85, 69, 5, 11, 32, 2, 11, 77, 2, 149, 200, 3, 2, 79, 86, 6, + 50, 77, 220, 181, 4, 2, 72, 73, 255, 144, 3, 76, 2, 225, 168, 3, 2, 73, + 68, 28, 76, 5, 78, 71, 85, 69, 32, 196, 4, 4, 82, 83, 79, 45, 129, 2, 2, + 85, 67, 16, 192, 2, 7, 67, 69, 78, 84, 82, 69, 32, 52, 14, 73, 78, 83, + 73, 68, 69, 32, 77, 79, 85, 84, 72, 32, 82, 36, 4, 84, 73, 80, 32, 88, 7, + 76, 73, 67, 75, 73, 78, 71, 228, 186, 7, 14, 83, 84, 73, 67, 75, 73, 78, + 71, 32, 79, 85, 84, 32, 70, 153, 160, 1, 17, 77, 79, 86, 69, 83, 32, 65, + 71, 65, 73, 78, 83, 84, 32, 67, 72, 69, 4, 214, 1, 73, 129, 186, 3, 5, + 83, 84, 73, 67, 75, 2, 129, 203, 3, 4, 69, 76, 65, 88, 4, 84, 7, 66, 69, + 84, 87, 69, 69, 78, 41, 10, 84, 79, 85, 67, 72, 73, 78, 71, 32, 73, 2, + 11, 32, 2, 241, 165, 5, 2, 76, 73, 2, 241, 184, 5, 5, 78, 83, 73, 68, 69, + 6, 120, 10, 87, 65, 76, 76, 80, 76, 65, 78, 69, 32, 201, 205, 3, 14, 70, + 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, 84, 87, 73, 4, 108, 8, 67, 85, + 82, 86, 69, 68, 32, 66, 169, 204, 1, 13, 83, 84, 82, 65, 73, 71, 72, 84, + 32, 83, 84, 82, 69, 2, 207, 203, 7, 69, 6, 11, 72, 6, 11, 32, 6, 30, 66, + 34, 77, 187, 4, 83, 2, 133, 133, 7, 3, 69, 84, 87, 2, 149, 2, 3, 85, 76, + 84, 34, 100, 11, 70, 76, 79, 79, 82, 80, 76, 65, 78, 69, 32, 29, 10, 87, + 65, 76, 76, 80, 76, 65, 78, 69, 32, 14, 178, 1, 82, 151, 2, 83, 20, 72, + 11, 65, 82, 77, 32, 83, 80, 73, 82, 65, 76, 32, 78, 82, 151, 2, 83, 6, + 30, 84, 134, 2, 68, 43, 83, 2, 11, 82, 2, 11, 73, 2, 151, 178, 7, 80, 12, + 41, 8, 79, 84, 65, 84, 73, 79, 78, 45, 12, 52, 5, 70, 76, 79, 79, 82, 1, + 4, 87, 65, 76, 76, 6, 33, 6, 80, 76, 65, 78, 69, 32, 6, 26, 65, 54, 68, + 43, 83, 2, 29, 5, 76, 84, 69, 82, 78, 2, 151, 200, 3, 65, 2, 17, 2, 79, + 85, 2, 151, 176, 7, 66, 2, 235, 175, 7, 73, 2, 11, 72, 2, 151, 198, 3, + 65, 2, 11, 73, 2, 195, 205, 7, 78, 10, 100, 6, 65, 66, 79, 86, 69, 32, + 162, 1, 79, 141, 148, 2, 10, 77, 73, 78, 85, 83, 32, 83, 73, 77, 73, 4, + 60, 7, 71, 82, 69, 65, 84, 69, 82, 1, 4, 76, 69, 83, 83, 2, 37, 7, 45, + 84, 72, 65, 78, 32, 65, 2, 25, 4, 66, 79, 86, 69, 2, 185, 241, 1, 2, 32, + 69, 4, 207, 189, 6, 82, 250, 1, 68, 3, 71, 76, 69, 212, 4, 5, 72, 65, 76, + 65, 32, 211, 171, 5, 69, 20, 50, 32, 209, 209, 8, 6, 45, 83, 72, 73, 70, + 84, 16, 138, 1, 67, 0, 9, 71, 82, 65, 80, 72, 73, 67, 32, 67, 116, 2, 72, + 73, 74, 76, 36, 4, 82, 73, 71, 72, 209, 254, 4, 4, 83, 72, 73, 70, 2, 41, + 8, 72, 65, 82, 65, 67, 84, 69, 82, 2, 37, 7, 32, 73, 78, 84, 82, 79, 68, + 2, 11, 85, 2, 247, 146, 8, 67, 2, 25, 4, 71, 72, 45, 82, 2, 185, 1, 7, + 69, 86, 69, 82, 83, 69, 68, 4, 32, 2, 69, 70, 109, 2, 79, 87, 2, 49, 10, + 84, 45, 80, 79, 73, 78, 84, 73, 78, 71, 2, 21, 3, 32, 65, 78, 2, 17, 2, + 71, 76, 2, 31, 69, 2, 17, 2, 45, 57, 2, 11, 32, 2, 11, 81, 2, 165, 176, + 2, 2, 85, 79, 228, 1, 168, 2, 8, 65, 82, 67, 72, 65, 73, 67, 32, 224, 1, + 15, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 114, 76, + 188, 8, 5, 83, 73, 71, 78, 32, 144, 1, 11, 86, 79, 87, 69, 76, 32, 83, + 73, 71, 78, 32, 209, 232, 2, 17, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, + 78, 32, 75, 85, 78, 68, 68, 40, 46, 68, 109, 7, 78, 85, 77, 66, 69, 82, + 32, 18, 25, 4, 73, 71, 73, 84, 18, 11, 32, 18, 154, 216, 6, 70, 30, 83, + 42, 84, 142, 87, 78, 14, 79, 227, 112, 69, 22, 130, 238, 2, 79, 162, 235, + 3, 69, 30, 70, 42, 78, 38, 83, 39, 84, 6, 18, 82, 63, 89, 4, 56, 6, 65, + 75, 65, 65, 82, 65, 233, 198, 8, 2, 69, 80, 2, 229, 198, 8, 3, 65, 78, + 83, 138, 1, 60, 6, 69, 84, 84, 69, 82, 32, 185, 186, 2, 3, 73, 84, 72, + 118, 246, 1, 65, 106, 69, 34, 73, 62, 85, 34, 77, 220, 1, 4, 68, 65, 78, + 84, 58, 79, 28, 8, 83, 65, 78, 89, 65, 75, 65, 32, 50, 70, 2, 72, 2, 82, + 2, 86, 2, 89, 32, 8, 84, 65, 65, 76, 85, 74, 65, 32, 29, 9, 75, 65, 78, + 84, 65, 74, 65, 32, 78, 34, 102, 69, 204, 1, 2, 76, 80, 144, 2, 5, 77, + 66, 65, 32, 66, 14, 65, 2, 73, 2, 85, 219, 135, 5, 89, 4, 230, 3, 69, + 219, 135, 5, 89, 12, 46, 76, 2, 82, 154, 3, 73, 219, 135, 5, 89, 4, 11, + 85, 4, 138, 3, 85, 219, 135, 5, 89, 28, 42, 65, 177, 1, 5, 85, 85, 82, + 68, 72, 22, 32, 2, 72, 65, 247, 137, 5, 89, 20, 41, 8, 65, 80, 82, 65, + 65, 78, 65, 32, 20, 70, 84, 138, 1, 68, 22, 66, 2, 67, 2, 71, 2, 74, 2, + 75, 3, 80, 4, 154, 1, 84, 15, 65, 6, 25, 4, 65, 74, 65, 32, 6, 102, 76, + 2, 78, 3, 83, 4, 86, 79, 219, 135, 5, 89, 8, 26, 68, 22, 71, 3, 74, 4, + 18, 68, 15, 65, 2, 11, 65, 2, 215, 135, 5, 89, 6, 26, 78, 21, 2, 83, 65, + 2, 89, 2, 65, 65, 4, 68, 11, 78, 89, 79, 79, 71, 65, 32, 78, 65, 65, 75, + 207, 134, 5, 89, 2, 173, 190, 8, 4, 83, 73, 75, 89, 8, 66, 65, 210, 162, + 4, 67, 249, 154, 4, 6, 86, 73, 83, 65, 82, 71, 4, 200, 116, 5, 76, 45, + 76, 65, 75, 253, 200, 7, 6, 78, 85, 83, 86, 65, 82, 34, 56, 5, 68, 73, + 71, 65, 32, 62, 71, 82, 75, 155, 2, 65, 12, 58, 71, 48, 4, 75, 79, 77, + 66, 118, 65, 26, 73, 19, 80, 4, 11, 65, 4, 236, 2, 3, 69, 84, 84, 67, 89, + 2, 11, 85, 2, 247, 187, 8, 86, 16, 52, 5, 69, 84, 84, 73, 32, 85, 4, 79, + 77, 66, 85, 6, 26, 65, 26, 73, 19, 80, 2, 213, 1, 2, 69, 68, 2, 203, 1, + 83, 2, 175, 1, 65, 10, 40, 2, 86, 65, 161, 142, 8, 2, 32, 68, 9, 29, 5, + 32, 72, 65, 65, 32, 6, 62, 65, 0, 6, 68, 73, 71, 65, 32, 65, 85, 3, 71, + 65, 89, 2, 17, 2, 69, 76, 2, 11, 65, 2, 17, 2, 45, 80, 2, 11, 73, 2, 171, + 153, 8, 76, 2, 129, 136, 6, 5, 65, 78, 85, 75, 73, 12, 84, 2, 32, 80, + 206, 2, 45, 137, 160, 6, 10, 84, 69, 69, 78, 32, 80, 79, 73, 78, 84, 8, + 140, 1, 23, 69, 84, 65, 76, 76, 69, 68, 32, 66, 76, 65, 67, 75, 32, 65, + 78, 68, 32, 87, 72, 73, 84, 69, 49, 7, 79, 73, 78, 84, 69, 68, 32, 2, 25, + 4, 32, 70, 76, 79, 2, 219, 239, 6, 82, 6, 78, 80, 150, 158, 6, 66, 153, + 134, 1, 9, 83, 84, 65, 82, 32, 87, 73, 84, 72, 2, 21, 3, 73, 78, 87, 2, + 149, 158, 6, 4, 72, 69, 69, 76, 2, 235, 213, 3, 80, 12, 46, 73, 102, 85, + 173, 157, 7, 3, 65, 84, 69, 4, 56, 8, 32, 65, 78, 68, 32, 83, 75, 73, + 139, 254, 7, 69, 2, 17, 2, 32, 66, 2, 151, 230, 7, 79, 6, 32, 2, 76, 76, + 131, 179, 8, 78, 5, 11, 32, 2, 49, 10, 65, 78, 68, 32, 67, 82, 79, 83, + 83, 66, 2, 11, 79, 2, 199, 159, 7, 78, 42, 46, 65, 198, 4, 69, 210, 1, + 73, 167, 1, 79, 14, 64, 5, 78, 84, 69, 68, 32, 253, 156, 6, 5, 86, 79, + 78, 73, 67, 12, 148, 1, 12, 69, 81, 85, 65, 76, 32, 84, 79, 32, 79, 82, + 32, 229, 1, 19, 78, 79, 82, 84, 72, 32, 65, 82, 82, 79, 87, 32, 87, 73, + 84, 72, 32, 72, 79, 8, 60, 7, 71, 82, 69, 65, 84, 69, 82, 1, 4, 76, 69, + 83, 83, 4, 29, 5, 45, 84, 72, 65, 78, 5, 11, 32, 2, 25, 4, 87, 73, 84, + 72, 2, 25, 4, 32, 68, 79, 84, 2, 17, 2, 32, 73, 2, 11, 78, 2, 11, 83, 2, + 231, 158, 6, 73, 4, 24, 2, 79, 75, 43, 82, 2, 17, 2, 69, 68, 2, 203, 216, + 5, 32, 2, 29, 5, 73, 90, 79, 78, 84, 2, 11, 65, 2, 155, 249, 5, 76, 12, + 80, 2, 69, 80, 168, 158, 8, 9, 85, 84, 72, 32, 79, 82, 32, 83, 80, 203, + 17, 68, 8, 40, 4, 73, 78, 71, 32, 167, 242, 7, 89, 6, 244, 233, 4, 8, 65, + 67, 67, 79, 77, 77, 79, 68, 162, 176, 2, 83, 167, 88, 70, 6, 76, 9, 67, + 69, 32, 79, 70, 32, 80, 73, 90, 21, 6, 71, 72, 84, 76, 89, 32, 2, 235, + 171, 8, 90, 4, 40, 2, 83, 77, 169, 229, 6, 2, 70, 82, 2, 219, 246, 6, 73, + 10, 18, 80, 75, 84, 6, 220, 232, 4, 9, 73, 78, 71, 32, 76, 65, 82, 71, + 69, 223, 196, 3, 69, 4, 26, 32, 219, 172, 8, 72, 2, 11, 77, 2, 141, 145, + 7, 3, 65, 67, 72, 150, 1, 34, 65, 158, 13, 73, 207, 7, 79, 116, 32, 2, + 76, 76, 151, 154, 7, 83, 114, 30, 32, 141, 12, 2, 69, 82, 110, 194, 2, + 65, 48, 3, 66, 76, 85, 0, 5, 79, 82, 65, 78, 71, 20, 2, 67, 79, 158, 1, + 68, 22, 69, 140, 2, 11, 73, 68, 69, 79, 71, 82, 65, 80, 72, 73, 67, 28, + 2, 76, 69, 34, 82, 218, 3, 83, 22, 84, 36, 2, 85, 80, 56, 4, 86, 69, 69, + 32, 196, 252, 1, 3, 71, 82, 69, 34, 72, 146, 4, 80, 206, 83, 78, 134, + 246, 2, 70, 83, 81, 6, 134, 214, 4, 77, 214, 49, 73, 255, 137, 1, 83, 2, + 131, 218, 6, 69, 12, 68, 7, 78, 84, 65, 73, 78, 83, 32, 134, 130, 2, 77, + 131, 214, 5, 76, 6, 36, 4, 65, 83, 32, 77, 175, 1, 87, 2, 11, 69, 2, 11, + 77, 2, 195, 233, 7, 66, 2, 151, 130, 2, 79, 12, 84, 9, 76, 69, 77, 69, + 78, 84, 32, 79, 70, 222, 129, 2, 81, 42, 88, 183, 227, 2, 77, 7, 17, 2, + 32, 87, 4, 25, 4, 73, 84, 72, 32, 4, 26, 86, 239, 243, 4, 79, 2, 197, + 253, 5, 21, 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, 82, 32, 65, 84, 32, + 69, 78, 68, 32, 79, 70, 2, 165, 207, 5, 2, 32, 67, 8, 130, 1, 70, 179, + 132, 2, 83, 40, 96, 3, 73, 71, 72, 64, 13, 79, 77, 65, 78, 32, 78, 85, + 77, 69, 82, 65, 76, 32, 251, 137, 6, 69, 6, 17, 2, 84, 32, 6, 238, 152, + 4, 67, 210, 3, 80, 147, 8, 84, 32, 62, 69, 50, 70, 62, 79, 46, 84, 214, + 174, 6, 83, 183, 87, 78, 4, 26, 76, 255, 247, 7, 73, 2, 231, 175, 6, 69, + 8, 26, 73, 191, 169, 7, 79, 6, 146, 26, 86, 159, 152, 6, 70, 6, 11, 78, + 6, 11, 69, 7, 151, 197, 2, 32, 8, 42, 87, 238, 174, 6, 72, 207, 162, 1, + 69, 4, 26, 69, 255, 160, 8, 79, 2, 167, 164, 7, 76, 2, 215, 209, 4, 69, + 4, 174, 253, 3, 87, 151, 134, 2, 73, 2, 253, 253, 4, 9, 45, 80, 79, 73, + 78, 84, 73, 78, 71, 2, 11, 87, 2, 21, 3, 73, 84, 72, 2, 11, 32, 2, 195, + 176, 4, 85, 4, 29, 5, 32, 84, 72, 65, 78, 5, 11, 32, 2, 11, 79, 2, 159, + 189, 1, 82, 32, 34, 76, 165, 150, 7, 2, 82, 75, 30, 40, 4, 73, 78, 71, + 32, 155, 158, 8, 69, 28, 112, 14, 67, 65, 84, 32, 70, 65, 67, 69, 32, 87, + 73, 84, 72, 32, 41, 10, 70, 65, 67, 69, 32, 87, 73, 84, 72, 32, 4, 160, + 1, 2, 72, 69, 231, 246, 4, 79, 24, 86, 72, 108, 10, 79, 80, 69, 78, 32, + 77, 79, 85, 84, 72, 246, 1, 83, 215, 224, 2, 84, 6, 34, 69, 54, 79, 255, + 248, 7, 65, 2, 237, 156, 5, 8, 65, 82, 84, 45, 83, 72, 65, 80, 2, 159, + 212, 4, 82, 9, 29, 5, 32, 65, 78, 68, 32, 6, 26, 67, 58, 83, 71, 84, 2, + 17, 2, 79, 76, 2, 169, 145, 7, 4, 68, 32, 83, 87, 2, 11, 77, 2, 11, 73, + 2, 11, 76, 2, 161, 155, 5, 3, 73, 78, 71, 2, 37, 7, 73, 71, 72, 84, 76, + 89, 45, 2, 175, 154, 5, 67, 8, 64, 11, 77, 73, 76, 73, 78, 71, 32, 69, + 89, 69, 83, 175, 1, 85, 7, 29, 5, 32, 65, 78, 68, 32, 4, 52, 4, 72, 65, + 78, 68, 57, 5, 84, 72, 82, 69, 69, 2, 161, 243, 4, 9, 32, 67, 79, 86, 69, + 82, 73, 78, 71, 2, 181, 210, 4, 2, 32, 72, 2, 17, 2, 78, 71, 2, 185, 129, + 7, 4, 76, 65, 83, 83, 2, 239, 230, 4, 75, 18, 42, 65, 48, 2, 69, 69, 21, + 2, 79, 87, 6, 26, 75, 243, 138, 7, 73, 4, 195, 136, 1, 69, 2, 139, 142, + 7, 90, 10, 100, 7, 32, 67, 65, 80, 80, 69, 68, 28, 3, 77, 65, 78, 132, + 223, 2, 3, 66, 79, 65, 143, 143, 1, 70, 2, 153, 169, 4, 2, 32, 77, 5, 49, + 10, 32, 87, 73, 84, 72, 79, 85, 84, 32, 83, 2, 183, 248, 6, 78, 155, 3, + 162, 2, 67, 48, 2, 70, 84, 228, 1, 6, 71, 68, 73, 65, 78, 32, 244, 10, 3, + 76, 73, 68, 140, 2, 12, 79, 78, 32, 87, 73, 84, 72, 32, 82, 73, 71, 72, + 20, 11, 82, 65, 32, 83, 79, 77, 80, 69, 78, 71, 32, 234, 2, 85, 216, 8, + 6, 89, 79, 77, 66, 79, 32, 190, 240, 6, 77, 130, 135, 1, 72, 3, 83, 4, + 164, 233, 2, 3, 67, 69, 82, 163, 235, 4, 75, 10, 70, 32, 124, 9, 87, 65, + 82, 69, 45, 70, 85, 78, 67, 255, 133, 6, 66, 6, 58, 72, 44, 6, 73, 67, + 69, 32, 67, 82, 227, 200, 6, 83, 2, 11, 89, 2, 11, 80, 2, 211, 186, 6, + 72, 2, 179, 211, 6, 69, 2, 11, 84, 2, 235, 149, 6, 73, 84, 248, 1, 10, + 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 168, 2, 13, 73, 78, 68, 69, 80, + 69, 78, 68, 69, 78, 84, 32, 83, 20, 7, 76, 69, 84, 84, 69, 82, 32, 188, + 3, 7, 78, 85, 77, 66, 69, 82, 32, 113, 12, 80, 85, 78, 67, 84, 85, 65, + 84, 73, 79, 78, 32, 22, 140, 1, 3, 72, 79, 79, 20, 4, 76, 79, 78, 71, 50, + 83, 58, 84, 242, 231, 3, 68, 128, 243, 1, 4, 82, 69, 83, 72, 249, 14, 4, + 67, 85, 82, 86, 4, 239, 234, 5, 75, 2, 25, 4, 32, 72, 79, 79, 2, 187, + 219, 5, 75, 2, 21, 3, 84, 82, 79, 2, 11, 75, 2, 131, 219, 5, 69, 4, 233, + 222, 1, 2, 87, 79, 2, 151, 140, 7, 72, 42, 190, 1, 65, 50, 71, 34, 76, + 56, 5, 82, 69, 83, 72, 45, 2, 90, 34, 83, 66, 89, 198, 207, 1, 72, 234, + 5, 75, 174, 81, 66, 2, 70, 170, 225, 4, 78, 134, 2, 84, 2, 87, 218, 103, + 80, 171, 4, 77, 4, 26, 76, 171, 138, 7, 89, 2, 131, 215, 1, 69, 2, 11, + 73, 2, 171, 244, 2, 77, 4, 26, 65, 167, 158, 6, 69, 2, 233, 208, 1, 2, + 77, 69, 2, 11, 65, 2, 175, 137, 7, 89, 6, 26, 65, 131, 137, 7, 72, 4, + 222, 199, 1, 77, 235, 147, 6, 68, 2, 239, 207, 1, 79, 8, 18, 79, 59, 84, + 4, 11, 78, 4, 11, 69, 5, 11, 32, 2, 183, 171, 2, 72, 4, 214, 151, 6, 87, + 155, 160, 1, 69, 10, 66, 67, 0, 6, 72, 65, 76, 70, 32, 67, 53, 4, 84, 87, + 79, 32, 2, 21, 3, 73, 82, 67, 2, 225, 246, 4, 2, 76, 69, 6, 100, 13, 86, + 69, 82, 84, 73, 67, 65, 76, 32, 66, 65, 82, 83, 13, 8, 67, 73, 82, 67, + 76, 69, 83, 32, 5, 11, 32, 2, 229, 178, 6, 4, 87, 73, 84, 72, 8, 30, 32, + 189, 1, 2, 85, 83, 4, 93, 21, 81, 85, 73, 76, 84, 32, 83, 81, 85, 65, 82, + 69, 32, 79, 82, 78, 65, 77, 69, 78, 84, 5, 11, 32, 2, 11, 73, 2, 17, 2, + 78, 32, 2, 11, 66, 2, 237, 224, 6, 4, 76, 65, 67, 75, 5, 197, 209, 4, 7, + 32, 87, 73, 84, 72, 32, 79, 2, 231, 132, 4, 84, 70, 52, 7, 76, 69, 84, + 84, 69, 82, 32, 191, 142, 6, 68, 50, 198, 1, 69, 32, 2, 77, 65, 30, 78, + 194, 146, 1, 66, 2, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, 2, 80, + 2, 82, 2, 83, 2, 84, 2, 86, 2, 89, 242, 236, 6, 65, 2, 73, 2, 79, 3, 85, + 4, 234, 255, 7, 69, 147, 1, 72, 4, 218, 128, 8, 69, 3, 72, 6, 190, 146, + 1, 71, 2, 89, 243, 236, 6, 65, 58, 104, 3, 84, 72, 32, 149, 172, 6, 17, 78, 68, 32, 82, 69, 67, 79, 82, 68, 73, 78, 71, 32, 67, 79, 80, 89, 56, 60, 5, 69, 65, 83, 84, 32, 253, 2, 5, 87, 69, 83, 84, 32, 30, 96, 5, 65, - 82, 82, 79, 87, 194, 4, 80, 130, 1, 84, 138, 197, 4, 66, 38, 68, 18, 83, - 247, 58, 87, 13, 11, 32, 10, 68, 2, 65, 78, 38, 67, 120, 2, 84, 79, 154, - 2, 87, 203, 134, 5, 70, 2, 253, 2, 5, 68, 32, 83, 79, 85, 2, 37, 7, 82, - 79, 83, 83, 73, 78, 71, 2, 17, 2, 32, 78, 2, 17, 2, 79, 82, 2, 173, 133, - 5, 5, 84, 72, 32, 69, 65, 2, 17, 2, 32, 67, 2, 243, 241, 3, 79, 26, 96, - 5, 65, 82, 82, 79, 87, 198, 1, 80, 130, 1, 84, 138, 197, 4, 66, 38, 68, - 18, 83, 247, 58, 87, 9, 11, 32, 6, 52, 5, 65, 78, 68, 32, 78, 74, 87, - 203, 134, 5, 70, 2, 17, 2, 79, 82, 2, 21, 3, 84, 72, 32, 2, 137, 131, 5, - 2, 87, 69, 2, 21, 3, 73, 84, 72, 2, 11, 32, 2, 251, 151, 6, 72, 6, 41, 8, - 79, 73, 78, 84, 73, 78, 71, 32, 6, 42, 86, 242, 160, 4, 76, 155, 158, 2, - 66, 2, 17, 2, 73, 78, 2, 199, 160, 4, 69, 4, 73, 16, 82, 73, 65, 78, 71, + 82, 82, 79, 87, 194, 4, 80, 130, 1, 84, 190, 207, 4, 66, 38, 68, 18, 83, + 251, 58, 87, 13, 11, 32, 10, 68, 2, 65, 78, 38, 67, 120, 2, 84, 79, 154, + 2, 87, 131, 145, 5, 70, 2, 253, 2, 5, 68, 32, 83, 79, 85, 2, 37, 7, 82, + 79, 83, 83, 73, 78, 71, 2, 17, 2, 32, 78, 2, 17, 2, 79, 82, 2, 229, 143, + 5, 5, 84, 72, 32, 69, 65, 2, 17, 2, 32, 67, 2, 167, 251, 3, 79, 26, 96, + 5, 65, 82, 82, 79, 87, 198, 1, 80, 130, 1, 84, 190, 207, 4, 66, 38, 68, + 18, 83, 251, 58, 87, 9, 11, 32, 6, 52, 5, 65, 78, 68, 32, 78, 74, 87, + 131, 145, 5, 70, 2, 17, 2, 79, 82, 2, 21, 3, 84, 72, 32, 2, 193, 141, 5, + 2, 87, 69, 2, 21, 3, 73, 84, 72, 2, 11, 32, 2, 231, 163, 6, 72, 6, 41, 8, + 79, 73, 78, 84, 73, 78, 71, 32, 6, 42, 86, 166, 171, 4, 76, 219, 159, 2, + 66, 2, 17, 2, 73, 78, 2, 251, 170, 4, 69, 4, 73, 16, 82, 73, 65, 78, 71, 76, 69, 45, 72, 69, 65, 68, 69, 68, 32, 65, 4, 25, 4, 82, 82, 79, 87, 5, - 11, 32, 2, 203, 137, 5, 84, 166, 1, 220, 3, 23, 67, 76, 85, 83, 84, 69, + 11, 32, 2, 131, 148, 5, 84, 166, 1, 220, 3, 23, 67, 76, 85, 83, 84, 69, 82, 45, 73, 78, 73, 84, 73, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 40, 21, 70, 73, 78, 65, 76, 32, 67, 79, 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 112, 27, 72, 69, 65, 68, 32, 77, 65, 82, 75, 32, 87, 73, 84, 72, 32, 77, 79, 79, 78, 32, 65, 78, 68, 32, 83, 85, 78, 104, 7, 76, 69, 84, 84, 69, 82, 32, 180, 1, 5, 77, 65, 82, 75, 32, 54, 83, 100, 8, - 84, 69, 82, 77, 73, 78, 65, 76, 40, 6, 86, 79, 87, 69, 76, 32, 207, 132, - 4, 71, 8, 142, 158, 7, 83, 138, 69, 76, 3, 82, 24, 138, 197, 3, 83, 134, - 165, 2, 78, 226, 248, 1, 45, 186, 2, 66, 2, 68, 2, 71, 2, 75, 2, 76, 2, + 84, 69, 82, 77, 73, 78, 65, 76, 40, 6, 86, 79, 87, 69, 76, 32, 131, 143, + 4, 71, 8, 150, 172, 7, 83, 138, 69, 76, 3, 82, 24, 206, 226, 3, 83, 226, + 146, 2, 78, 202, 251, 1, 45, 186, 2, 66, 2, 68, 2, 71, 2, 75, 2, 76, 2, 77, 3, 82, 7, 29, 5, 32, 65, 78, 68, 32, 4, 50, 70, 1, 8, 84, 82, 73, 80, - 76, 69, 32, 70, 2, 235, 212, 5, 76, 82, 230, 188, 2, 68, 138, 222, 4, 75, + 76, 69, 32, 70, 2, 139, 224, 5, 76, 82, 162, 194, 2, 68, 214, 230, 4, 75, 38, 78, 46, 83, 38, 84, 46, 66, 2, 67, 2, 71, 2, 74, 2, 80, 2, 90, 138, - 69, 45, 2, 72, 2, 76, 2, 77, 2, 82, 2, 86, 2, 89, 187, 2, 65, 8, 222, - 140, 4, 80, 206, 142, 3, 68, 58, 83, 63, 84, 10, 40, 4, 73, 71, 78, 32, - 139, 159, 7, 85, 8, 246, 168, 5, 74, 158, 2, 86, 122, 85, 187, 240, 1, - 65, 4, 237, 223, 3, 5, 32, 77, 65, 82, 75, 22, 44, 5, 83, 73, 71, 78, 32, - 179, 158, 7, 76, 20, 88, 7, 86, 79, 67, 65, 76, 73, 67, 154, 159, 7, 65, - 26, 79, 2, 85, 162, 64, 69, 3, 73, 4, 11, 32, 4, 194, 223, 7, 76, 3, 82, + 69, 45, 2, 72, 2, 76, 2, 77, 2, 82, 2, 86, 2, 89, 187, 2, 65, 8, 146, + 151, 4, 80, 162, 146, 3, 68, 58, 83, 63, 84, 10, 40, 4, 73, 71, 78, 32, + 147, 173, 7, 85, 8, 186, 179, 5, 74, 158, 2, 86, 122, 85, 255, 243, 1, + 65, 4, 161, 233, 3, 5, 32, 77, 65, 82, 75, 22, 44, 5, 83, 73, 71, 78, 32, + 187, 172, 7, 76, 20, 88, 7, 86, 79, 67, 65, 76, 73, 67, 162, 173, 7, 65, + 26, 79, 2, 85, 162, 64, 69, 3, 73, 4, 11, 32, 4, 202, 237, 7, 76, 3, 82, 71, 122, 65, 206, 1, 69, 168, 5, 13, 72, 69, 82, 73, 67, 65, 76, 32, 65, 78, 71, 76, 69, 82, 73, 220, 1, 2, 76, 65, 91, 79, 17, 48, 4, 71, 72, 69, - 84, 22, 82, 147, 199, 7, 67, 2, 159, 202, 7, 84, 10, 24, 2, 75, 76, 59, - 83, 6, 26, 73, 191, 214, 5, 69, 2, 237, 213, 6, 2, 78, 71, 4, 17, 2, 69, - 32, 4, 214, 53, 72, 135, 3, 86, 22, 104, 2, 65, 75, 230, 3, 69, 68, 4, - 83, 77, 73, 76, 141, 214, 3, 9, 67, 75, 76, 69, 32, 70, 73, 76, 76, 12, - 70, 45, 64, 2, 69, 82, 153, 2, 8, 73, 78, 71, 32, 72, 69, 65, 68, 2, 161, - 193, 5, 11, 78, 79, 45, 69, 86, 73, 76, 32, 77, 79, 78, 9, 33, 6, 32, 87, + 84, 22, 82, 155, 213, 7, 67, 2, 167, 216, 7, 84, 10, 24, 2, 75, 76, 59, + 83, 6, 26, 73, 223, 225, 5, 69, 2, 245, 227, 6, 2, 78, 71, 4, 17, 2, 69, + 32, 4, 202, 53, 72, 135, 3, 86, 22, 104, 2, 65, 75, 230, 3, 69, 68, 4, + 83, 77, 73, 76, 193, 223, 3, 9, 67, 75, 76, 69, 32, 70, 73, 76, 76, 12, + 70, 45, 64, 2, 69, 82, 153, 2, 8, 73, 78, 71, 32, 72, 69, 65, 68, 2, 205, + 203, 5, 11, 78, 79, 45, 69, 86, 73, 76, 32, 77, 79, 78, 9, 33, 6, 32, 87, 73, 84, 72, 32, 6, 26, 67, 78, 79, 55, 84, 2, 33, 6, 65, 78, 67, 69, 76, - 76, 2, 241, 169, 7, 5, 65, 84, 73, 79, 78, 2, 209, 186, 4, 8, 78, 69, 32, - 83, 79, 85, 78, 68, 2, 25, 4, 72, 82, 69, 69, 2, 149, 197, 6, 10, 32, 83, - 79, 85, 78, 68, 32, 87, 65, 86, 2, 11, 32, 2, 185, 145, 6, 9, 73, 78, 32, - 83, 73, 76, 72, 79, 85, 4, 34, 68, 245, 245, 2, 2, 67, 72, 2, 11, 66, 2, - 247, 195, 6, 79, 2, 203, 208, 6, 79, 7, 45, 9, 32, 79, 80, 69, 78, 73, - 78, 71, 32, 4, 154, 172, 7, 76, 227, 42, 85, 10, 44, 3, 68, 69, 82, 41, - 4, 82, 65, 76, 32, 5, 17, 2, 32, 87, 2, 191, 154, 6, 69, 6, 80, 8, 67, - 65, 76, 69, 78, 68, 65, 82, 0, 4, 78, 79, 84, 69, 29, 2, 83, 72, 2, 141, - 143, 7, 2, 32, 80, 2, 223, 205, 5, 69, 4, 64, 10, 83, 72, 73, 78, 71, 32, - 83, 87, 69, 65, 211, 156, 6, 84, 2, 159, 193, 6, 84, 10, 90, 79, 60, 7, - 85, 84, 73, 78, 71, 32, 87, 192, 240, 2, 3, 82, 84, 83, 191, 173, 3, 78, - 4, 240, 87, 7, 76, 32, 79, 70, 32, 84, 72, 231, 251, 6, 78, 2, 11, 72, 2, - 231, 174, 6, 65, 222, 5, 26, 65, 191, 140, 7, 73, 220, 5, 28, 2, 82, 69, - 163, 69, 84, 218, 5, 30, 32, 245, 46, 2, 68, 32, 234, 3, 250, 1, 65, 104, + 76, 2, 249, 183, 7, 5, 65, 84, 73, 79, 78, 2, 133, 197, 4, 8, 78, 69, 32, + 83, 79, 85, 78, 68, 2, 25, 4, 72, 82, 69, 69, 2, 145, 209, 6, 10, 32, 83, + 79, 85, 78, 68, 32, 87, 65, 86, 2, 11, 32, 2, 165, 157, 6, 9, 73, 78, 32, + 83, 73, 76, 72, 79, 85, 4, 34, 68, 197, 251, 2, 2, 67, 72, 2, 11, 66, 2, + 183, 220, 6, 79, 2, 211, 222, 6, 79, 7, 45, 9, 32, 79, 80, 69, 78, 73, + 78, 71, 32, 4, 162, 186, 7, 76, 227, 42, 85, 10, 44, 3, 68, 69, 82, 41, + 4, 82, 65, 76, 32, 5, 17, 2, 32, 87, 2, 179, 166, 6, 69, 6, 80, 8, 67, + 65, 76, 69, 78, 68, 65, 82, 0, 4, 78, 79, 84, 69, 29, 2, 83, 72, 2, 149, + 157, 7, 2, 32, 80, 2, 255, 216, 5, 69, 4, 64, 10, 83, 72, 73, 78, 71, 32, + 83, 87, 69, 65, 199, 168, 6, 84, 2, 139, 205, 6, 84, 10, 90, 79, 60, 7, + 85, 84, 73, 78, 71, 32, 87, 144, 246, 2, 3, 82, 84, 83, 227, 179, 3, 78, + 4, 248, 87, 7, 76, 32, 79, 70, 32, 84, 72, 231, 137, 7, 78, 2, 11, 72, 2, + 219, 186, 6, 65, 222, 5, 26, 65, 199, 154, 7, 73, 220, 5, 28, 2, 82, 69, + 155, 69, 84, 218, 5, 30, 32, 233, 46, 2, 68, 32, 234, 3, 250, 1, 65, 104, 2, 86, 32, 94, 66, 158, 1, 67, 170, 1, 68, 102, 69, 194, 2, 70, 146, 2, - 71, 222, 1, 72, 214, 2, 73, 94, 75, 190, 4, 76, 102, 77, 210, 5, 78, 94, + 71, 222, 1, 72, 214, 2, 73, 94, 75, 182, 4, 76, 102, 77, 206, 5, 78, 94, 79, 178, 1, 80, 222, 3, 82, 154, 3, 83, 206, 2, 84, 74, 87, 230, 6, 89, - 251, 211, 6, 85, 16, 102, 32, 58, 80, 132, 73, 2, 78, 80, 144, 153, 2, 3, - 82, 85, 72, 194, 51, 65, 162, 185, 4, 77, 3, 85, 2, 21, 3, 79, 86, 69, 2, - 11, 82, 2, 175, 190, 7, 32, 4, 234, 184, 2, 69, 231, 138, 1, 65, 14, 98, - 65, 36, 4, 85, 83, 83, 89, 170, 148, 3, 73, 216, 74, 2, 79, 82, 138, 53, - 69, 195, 185, 3, 81, 4, 32, 2, 65, 82, 203, 205, 7, 82, 2, 167, 148, 3, - 69, 22, 98, 65, 30, 79, 158, 20, 77, 196, 183, 7, 7, 32, 79, 86, 69, 82, - 32, 75, 74, 85, 14, 67, 3, 68, 4, 206, 204, 7, 76, 3, 80, 5, 17, 2, 82, - 80, 2, 155, 194, 2, 79, 20, 82, 65, 162, 19, 77, 250, 205, 2, 69, 130, - 49, 79, 162, 185, 4, 66, 2, 74, 3, 76, 5, 135, 22, 65, 18, 66, 69, 22, - 82, 164, 25, 5, 83, 85, 75, 85, 85, 175, 177, 7, 86, 2, 151, 216, 5, 75, - 12, 52, 7, 65, 32, 78, 65, 77, 69, 32, 155, 202, 7, 71, 10, 132, 1, 4, - 72, 69, 73, 83, 20, 5, 84, 65, 73, 83, 89, 152, 22, 3, 77, 69, 73, 220, - 193, 2, 3, 82, 69, 73, 1, 4, 83, 89, 79, 85, 2, 183, 181, 7, 69, 2, 147, - 164, 7, 79, 12, 26, 79, 207, 200, 7, 77, 10, 60, 9, 85, 82, 32, 67, 79, - 82, 78, 69, 82, 227, 171, 7, 79, 8, 26, 32, 243, 199, 7, 83, 6, 128, 1, - 11, 66, 76, 65, 67, 75, 32, 84, 82, 73, 65, 78, 216, 62, 6, 68, 73, 65, - 71, 79, 78, 229, 199, 3, 5, 83, 65, 76, 84, 73, 2, 167, 137, 4, 71, 24, - 102, 65, 46, 73, 172, 12, 5, 85, 82, 65, 77, 85, 238, 149, 3, 72, 246, - 160, 4, 80, 186, 2, 66, 3, 89, 6, 130, 246, 6, 82, 222, 46, 78, 147, 33, - 76, 6, 42, 82, 158, 130, 5, 78, 199, 192, 2, 71, 2, 201, 210, 5, 2, 85, - 68, 30, 130, 1, 65, 22, 69, 54, 79, 62, 85, 242, 214, 1, 80, 156, 227, 5, - 10, 73, 82, 65, 71, 65, 78, 65, 32, 72, 79, 234, 8, 71, 3, 90, 5, 167, - 244, 1, 73, 4, 168, 11, 3, 75, 85, 84, 233, 232, 1, 2, 82, 85, 6, 26, 79, - 151, 195, 7, 78, 4, 170, 158, 7, 82, 235, 36, 78, 6, 54, 73, 144, 17, 4, - 65, 82, 65, 68, 175, 231, 5, 82, 2, 255, 211, 3, 73, 14, 54, 78, 212, 12, - 4, 77, 65, 71, 69, 159, 181, 7, 85, 7, 154, 210, 2, 73, 255, 219, 4, 84, - 58, 230, 1, 65, 48, 2, 89, 85, 20, 3, 73, 82, 79, 78, 77, 90, 79, 60, 2, - 85, 82, 144, 8, 2, 69, 69, 134, 146, 3, 72, 238, 153, 3, 67, 232, 120, 3, - 32, 79, 72, 162, 14, 80, 186, 2, 66, 2, 71, 2, 75, 2, 76, 2, 84, 2, 86, - 3, 87, 9, 22, 82, 131, 98, 73, 4, 22, 79, 163, 21, 65, 2, 183, 252, 4, - 82, 9, 252, 16, 3, 77, 69, 69, 140, 4, 2, 87, 65, 129, 171, 2, 3, 71, 85, - 82, 9, 11, 32, 6, 22, 67, 199, 14, 83, 4, 22, 65, 179, 6, 85, 2, 233, - 233, 4, 2, 80, 73, 4, 18, 79, 23, 82, 2, 243, 158, 7, 80, 2, 207, 129, 6, - 85, 4, 164, 206, 5, 4, 85, 90, 69, 73, 215, 68, 79, 12, 62, 79, 244, 13, - 2, 69, 70, 222, 174, 7, 77, 2, 78, 3, 88, 4, 150, 135, 6, 90, 187, 181, - 1, 71, 82, 162, 1, 32, 70, 65, 122, 66, 22, 69, 54, 73, 110, 77, 68, 2, - 85, 32, 78, 86, 2, 87, 222, 147, 3, 72, 250, 153, 3, 79, 254, 134, 1, 80, - 186, 2, 71, 2, 76, 3, 83, 10, 34, 79, 242, 2, 67, 139, 8, 83, 6, 198, 10, - 86, 199, 159, 7, 72, 13, 54, 73, 44, 2, 78, 83, 206, 84, 82, 215, 234, 4, - 72, 4, 240, 202, 5, 2, 75, 85, 179, 202, 1, 82, 2, 243, 233, 6, 89, 5, - 223, 171, 2, 32, 6, 28, 2, 71, 65, 251, 10, 69, 5, 171, 233, 6, 84, 8, - 42, 75, 20, 2, 82, 73, 199, 184, 7, 76, 2, 183, 147, 6, 85, 5, 11, 66, 2, - 11, 65, 2, 139, 255, 2, 65, 7, 11, 32, 4, 22, 67, 139, 8, 83, 2, 11, 85, - 2, 155, 172, 2, 66, 16, 210, 183, 7, 65, 2, 70, 2, 71, 2, 76, 2, 77, 2, - 83, 2, 86, 3, 87, 5, 11, 32, 2, 11, 77, 2, 171, 244, 6, 69, 16, 70, 65, - 130, 12, 79, 150, 170, 7, 70, 2, 77, 2, 83, 2, 86, 3, 87, 5, 159, 151, 7, - 78, 12, 78, 78, 20, 7, 82, 73, 71, 73, 78, 65, 76, 150, 182, 2, 79, 139, - 255, 4, 86, 2, 199, 144, 7, 83, 6, 21, 3, 32, 79, 70, 7, 25, 4, 32, 79, - 82, 32, 4, 242, 96, 78, 51, 69, 46, 118, 65, 82, 69, 94, 73, 74, 79, 142, - 161, 7, 80, 218, 16, 67, 2, 70, 2, 72, 2, 77, 2, 82, 2, 83, 2, 86, 3, 87, - 9, 38, 65, 229, 254, 3, 3, 32, 65, 77, 4, 236, 1, 2, 83, 69, 219, 140, 7, - 84, 8, 34, 69, 22, 78, 223, 147, 7, 83, 2, 139, 159, 7, 90, 4, 206, 227, - 1, 73, 155, 170, 5, 83, 6, 34, 75, 233, 3, 3, 65, 83, 85, 4, 230, 248, 2, - 85, 163, 185, 4, 79, 6, 34, 73, 22, 78, 21, 2, 83, 73, 2, 131, 195, 3, - 78, 2, 183, 146, 7, 68, 2, 241, 247, 6, 4, 84, 73, 79, 78, 22, 60, 2, 65, - 68, 114, 69, 62, 73, 134, 1, 85, 207, 221, 6, 79, 7, 21, 3, 32, 79, 86, - 4, 25, 4, 69, 82, 32, 83, 5, 17, 2, 32, 83, 2, 11, 81, 2, 133, 164, 2, 2, - 85, 65, 4, 36, 3, 78, 84, 79, 183, 138, 7, 77, 2, 179, 219, 5, 71, 6, 40, - 2, 71, 72, 62, 84, 235, 171, 7, 82, 2, 233, 238, 3, 10, 84, 32, 79, 80, - 69, 78, 32, 66, 79, 88, 2, 253, 244, 2, 2, 84, 79, 4, 228, 1, 2, 85, 66, - 163, 233, 4, 80, 22, 138, 1, 65, 72, 3, 69, 78, 84, 28, 11, 80, 73, 82, - 65, 76, 32, 70, 82, 79, 77, 32, 152, 188, 2, 3, 73, 82, 73, 214, 239, 4, - 82, 3, 86, 4, 48, 2, 73, 75, 149, 173, 2, 4, 78, 84, 73, 73, 2, 251, 242, - 2, 85, 4, 134, 172, 7, 73, 3, 79, 8, 18, 66, 43, 84, 4, 201, 128, 7, 5, - 79, 84, 84, 79, 77, 4, 11, 79, 4, 151, 128, 7, 80, 6, 42, 65, 186, 135, - 3, 72, 207, 211, 3, 79, 2, 201, 245, 6, 2, 82, 71, 34, 50, 65, 20, 4, 73, - 84, 72, 32, 131, 170, 7, 66, 2, 215, 187, 3, 84, 30, 214, 1, 66, 40, 3, + 143, 226, 6, 85, 16, 102, 32, 58, 80, 252, 72, 2, 78, 80, 204, 158, 2, 3, + 82, 85, 72, 186, 51, 65, 254, 193, 4, 77, 3, 85, 2, 21, 3, 79, 86, 69, 2, + 11, 82, 2, 183, 204, 7, 32, 4, 166, 190, 2, 69, 223, 142, 1, 65, 14, 98, + 65, 36, 4, 85, 83, 83, 89, 214, 153, 3, 73, 232, 78, 2, 79, 82, 130, 54, + 69, 151, 189, 3, 81, 4, 32, 2, 65, 82, 211, 219, 7, 82, 2, 211, 153, 3, + 69, 22, 98, 65, 30, 79, 146, 20, 77, 216, 197, 7, 7, 32, 79, 86, 69, 82, + 32, 75, 74, 85, 14, 67, 3, 68, 4, 214, 218, 7, 76, 3, 80, 5, 17, 2, 82, + 80, 2, 215, 199, 2, 79, 20, 82, 65, 150, 19, 77, 186, 211, 2, 69, 250, + 48, 79, 254, 193, 4, 66, 2, 74, 3, 76, 5, 251, 21, 65, 18, 66, 69, 22, + 82, 152, 25, 5, 83, 85, 75, 85, 85, 195, 191, 7, 86, 2, 183, 227, 5, 75, + 12, 52, 7, 65, 32, 78, 65, 77, 69, 32, 163, 216, 7, 71, 10, 132, 1, 4, + 72, 69, 73, 83, 20, 5, 84, 65, 73, 83, 89, 140, 22, 3, 77, 69, 73, 156, + 199, 2, 3, 82, 69, 73, 1, 4, 83, 89, 79, 85, 2, 191, 195, 7, 69, 2, 155, + 178, 7, 79, 12, 26, 79, 215, 214, 7, 77, 10, 60, 9, 85, 82, 32, 67, 79, + 82, 78, 69, 82, 235, 185, 7, 79, 8, 26, 32, 251, 213, 7, 83, 6, 128, 1, + 11, 66, 76, 65, 67, 75, 32, 84, 82, 73, 65, 78, 208, 62, 6, 68, 73, 65, + 71, 79, 78, 161, 210, 3, 5, 83, 65, 76, 84, 73, 2, 219, 147, 4, 71, 24, + 102, 65, 46, 73, 160, 12, 5, 85, 82, 65, 77, 85, 134, 233, 5, 72, 242, + 219, 1, 80, 186, 2, 66, 3, 89, 6, 138, 132, 7, 82, 222, 46, 78, 147, 33, + 76, 6, 42, 82, 214, 140, 5, 78, 151, 196, 2, 71, 2, 233, 221, 5, 2, 85, + 68, 30, 130, 1, 65, 22, 69, 54, 79, 62, 85, 142, 191, 3, 80, 136, 137, 4, + 10, 73, 82, 65, 71, 65, 78, 65, 32, 72, 79, 234, 8, 71, 3, 90, 5, 183, + 249, 1, 73, 4, 156, 11, 3, 75, 85, 84, 133, 238, 1, 2, 82, 85, 6, 26, 79, + 159, 209, 7, 78, 4, 178, 172, 7, 82, 235, 36, 78, 6, 54, 73, 132, 17, 4, + 65, 82, 65, 68, 167, 243, 5, 82, 2, 187, 221, 3, 73, 14, 54, 78, 200, 12, + 4, 77, 65, 71, 69, 179, 195, 7, 85, 7, 206, 215, 2, 73, 211, 228, 4, 84, + 58, 234, 1, 65, 56, 3, 73, 82, 79, 78, 77, 90, 79, 60, 2, 85, 82, 140, 8, + 2, 69, 69, 208, 143, 2, 2, 89, 85, 206, 213, 3, 72, 206, 82, 67, 132, + 123, 3, 32, 79, 72, 162, 14, 80, 186, 2, 66, 2, 71, 2, 75, 2, 76, 2, 84, + 2, 86, 3, 87, 9, 22, 82, 135, 98, 73, 4, 166, 21, 65, 183, 132, 2, 79, 9, + 248, 16, 3, 77, 69, 69, 140, 4, 2, 87, 65, 193, 176, 2, 3, 71, 85, 82, 9, + 11, 32, 6, 22, 67, 195, 14, 83, 4, 22, 65, 175, 6, 85, 2, 169, 244, 4, 2, + 80, 73, 4, 18, 79, 23, 82, 2, 131, 173, 7, 80, 2, 203, 141, 6, 85, 4, + 204, 217, 5, 4, 85, 90, 69, 73, 171, 69, 79, 12, 62, 79, 240, 13, 2, 69, + 70, 242, 188, 7, 77, 2, 78, 3, 88, 4, 146, 147, 6, 90, 207, 183, 1, 71, + 82, 158, 1, 32, 70, 65, 122, 66, 22, 69, 54, 73, 110, 77, 68, 2, 85, 32, + 78, 86, 2, 87, 246, 230, 5, 72, 218, 82, 79, 154, 137, 1, 80, 186, 2, 71, + 2, 76, 3, 83, 10, 34, 79, 242, 2, 67, 139, 8, 83, 6, 198, 10, 86, 219, + 173, 7, 72, 13, 54, 73, 44, 2, 78, 83, 226, 84, 82, 239, 245, 4, 72, 4, + 156, 214, 5, 2, 75, 85, 155, 205, 1, 82, 2, 135, 248, 6, 89, 5, 167, 177, + 2, 32, 6, 28, 2, 71, 65, 251, 10, 69, 5, 191, 247, 6, 84, 8, 42, 75, 20, + 2, 82, 73, 219, 198, 7, 76, 2, 183, 159, 6, 85, 5, 11, 66, 2, 11, 65, 2, + 195, 132, 3, 65, 7, 11, 32, 4, 22, 67, 139, 8, 83, 2, 11, 85, 2, 227, + 177, 2, 66, 16, 230, 197, 7, 65, 2, 70, 2, 71, 2, 76, 2, 77, 2, 83, 2, + 86, 3, 87, 5, 11, 32, 2, 11, 77, 2, 191, 130, 7, 69, 16, 70, 65, 130, 12, + 79, 170, 184, 7, 70, 2, 77, 2, 83, 2, 86, 3, 87, 5, 179, 165, 7, 78, 12, + 78, 78, 20, 7, 82, 73, 71, 73, 78, 65, 76, 214, 187, 2, 79, 223, 135, 5, + 86, 2, 219, 158, 7, 83, 6, 21, 3, 32, 79, 70, 7, 25, 4, 32, 79, 82, 32, + 4, 134, 97, 78, 51, 69, 46, 118, 65, 82, 69, 94, 73, 74, 79, 162, 175, 7, + 80, 218, 16, 67, 2, 70, 2, 72, 2, 77, 2, 82, 2, 83, 2, 86, 3, 87, 9, 38, + 65, 165, 137, 4, 3, 32, 65, 77, 4, 236, 1, 2, 83, 69, 239, 154, 7, 84, 8, + 34, 69, 22, 78, 243, 161, 7, 83, 2, 159, 173, 7, 90, 4, 234, 232, 1, 73, + 147, 179, 5, 83, 6, 34, 75, 233, 3, 3, 65, 83, 85, 4, 158, 254, 2, 85, + 255, 193, 4, 79, 6, 34, 73, 22, 78, 21, 2, 83, 73, 2, 203, 204, 3, 78, 2, + 203, 160, 7, 68, 2, 133, 134, 7, 4, 84, 73, 79, 78, 22, 60, 2, 65, 68, + 114, 69, 62, 73, 134, 1, 85, 227, 235, 6, 79, 7, 21, 3, 32, 79, 86, 4, + 25, 4, 69, 82, 32, 83, 5, 17, 2, 32, 83, 2, 11, 81, 2, 205, 169, 2, 2, + 85, 65, 4, 36, 3, 78, 84, 79, 203, 152, 7, 77, 2, 171, 231, 5, 71, 6, 40, + 2, 71, 72, 62, 84, 255, 185, 7, 82, 2, 169, 249, 3, 10, 84, 32, 79, 80, + 69, 78, 32, 66, 79, 88, 2, 181, 250, 2, 2, 84, 79, 4, 228, 1, 2, 85, 66, + 231, 243, 4, 80, 22, 138, 1, 65, 72, 3, 69, 78, 84, 28, 11, 80, 73, 82, + 65, 76, 32, 70, 82, 79, 77, 32, 216, 193, 2, 3, 73, 82, 73, 170, 248, 4, + 82, 3, 86, 4, 48, 2, 73, 75, 213, 178, 2, 4, 78, 84, 73, 73, 2, 179, 248, + 2, 85, 4, 154, 186, 7, 73, 3, 79, 8, 18, 66, 43, 84, 4, 221, 142, 7, 5, + 79, 84, 84, 79, 77, 4, 11, 79, 4, 171, 142, 7, 80, 6, 42, 65, 210, 218, + 5, 72, 203, 142, 1, 79, 2, 221, 131, 7, 2, 82, 71, 34, 50, 65, 20, 4, 73, + 84, 72, 32, 151, 184, 7, 66, 2, 159, 197, 3, 84, 30, 214, 1, 66, 40, 3, 68, 73, 65, 0, 5, 79, 82, 84, 72, 79, 94, 72, 54, 76, 126, 84, 28, 6, 85, - 80, 80, 69, 82, 32, 186, 1, 86, 178, 136, 4, 82, 173, 130, 2, 13, 67, 79, - 78, 84, 79, 85, 82, 69, 68, 32, 79, 85, 84, 2, 217, 140, 4, 5, 79, 84, - 84, 79, 77, 2, 11, 71, 2, 213, 175, 4, 15, 79, 78, 65, 76, 32, 67, 82, + 80, 80, 69, 82, 32, 186, 1, 86, 242, 146, 4, 82, 253, 131, 2, 13, 67, 79, + 78, 84, 79, 85, 82, 69, 68, 32, 79, 85, 84, 2, 153, 151, 4, 5, 79, 84, + 84, 79, 77, 2, 11, 71, 2, 153, 186, 4, 15, 79, 78, 65, 76, 32, 67, 82, 79, 83, 83, 72, 65, 84, 67, 72, 2, 11, 79, 2, 149, 3, 6, 82, 73, 90, 79, - 78, 84, 6, 44, 5, 79, 87, 69, 82, 32, 199, 138, 4, 69, 4, 44, 3, 76, 69, - 70, 1, 4, 82, 73, 71, 72, 2, 189, 1, 3, 84, 32, 68, 2, 165, 138, 4, 2, + 78, 84, 6, 44, 5, 79, 87, 69, 82, 32, 135, 149, 4, 69, 4, 44, 3, 76, 69, + 70, 1, 4, 82, 73, 71, 72, 2, 189, 1, 3, 84, 32, 68, 2, 229, 148, 4, 2, 79, 80, 8, 60, 5, 76, 69, 70, 84, 32, 37, 6, 82, 73, 71, 72, 84, 32, 4, - 70, 68, 185, 153, 4, 2, 84, 79, 4, 34, 68, 245, 171, 4, 2, 84, 79, 2, - 129, 137, 4, 7, 73, 65, 71, 79, 78, 65, 76, 2, 29, 5, 69, 82, 84, 73, 67, - 2, 225, 171, 4, 2, 65, 76, 6, 32, 2, 65, 65, 195, 217, 5, 85, 4, 214, - 254, 6, 82, 247, 5, 68, 240, 1, 226, 1, 67, 174, 9, 68, 34, 70, 88, 3, + 70, 68, 249, 163, 4, 2, 84, 79, 4, 34, 68, 185, 182, 4, 2, 84, 79, 2, + 193, 147, 4, 7, 73, 65, 71, 79, 78, 65, 76, 2, 29, 5, 69, 82, 84, 73, 67, + 2, 165, 182, 4, 2, 65, 76, 6, 32, 2, 65, 65, 187, 229, 5, 85, 4, 234, + 140, 7, 82, 247, 5, 68, 240, 1, 226, 1, 67, 174, 9, 68, 34, 70, 88, 3, 82, 73, 83, 142, 1, 72, 66, 75, 106, 76, 166, 1, 77, 38, 78, 34, 79, 94, - 80, 34, 83, 190, 2, 84, 156, 1, 5, 69, 73, 71, 72, 84, 22, 85, 90, 86, - 230, 249, 4, 65, 218, 107, 87, 223, 97, 73, 90, 128, 1, 21, 74, 75, 32, + 80, 34, 83, 190, 2, 84, 160, 1, 5, 69, 73, 71, 72, 84, 22, 85, 90, 86, + 154, 132, 5, 65, 162, 109, 87, 243, 99, 73, 90, 128, 1, 21, 74, 75, 32, 85, 78, 73, 70, 73, 69, 68, 32, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, - 198, 141, 6, 79, 243, 146, 1, 76, 86, 68, 2, 52, 69, 82, 53, 206, 2, 54, - 150, 2, 55, 166, 1, 56, 95, 57, 10, 50, 48, 234, 4, 65, 214, 242, 5, 56, - 223, 97, 50, 4, 182, 159, 7, 48, 3, 57, 30, 150, 1, 50, 42, 51, 38, 52, - 48, 2, 53, 66, 0, 2, 68, 69, 22, 57, 164, 4, 2, 56, 70, 222, 162, 3, 66, - 248, 205, 2, 2, 70, 56, 221, 97, 2, 49, 56, 6, 214, 4, 55, 142, 211, 6, - 49, 3, 52, 4, 210, 167, 3, 70, 143, 206, 2, 67, 4, 26, 48, 219, 167, 3, - 51, 2, 155, 157, 7, 56, 2, 135, 157, 7, 54, 4, 174, 167, 3, 50, 143, 243, + 190, 153, 6, 79, 143, 149, 1, 76, 86, 68, 2, 52, 69, 82, 53, 206, 2, 54, + 150, 2, 55, 166, 1, 56, 95, 57, 10, 50, 48, 234, 4, 65, 214, 254, 5, 56, + 243, 99, 50, 4, 202, 173, 7, 48, 3, 57, 30, 150, 1, 50, 42, 51, 38, 52, + 48, 2, 53, 66, 0, 2, 68, 69, 22, 57, 164, 4, 2, 56, 70, 158, 172, 3, 66, + 184, 208, 2, 2, 70, 56, 241, 99, 2, 49, 56, 6, 214, 4, 55, 162, 225, 6, + 49, 3, 52, 4, 146, 177, 3, 70, 207, 208, 2, 67, 4, 26, 48, 155, 177, 3, + 51, 2, 175, 171, 7, 56, 2, 155, 171, 7, 54, 4, 238, 176, 3, 50, 227, 247, 3, 49, 24, 86, 50, 46, 51, 50, 53, 34, 54, 16, 2, 55, 48, 28, 2, 70, 49, - 129, 2, 2, 69, 56, 6, 70, 57, 170, 165, 3, 53, 167, 186, 2, 52, 4, 26, - 53, 131, 166, 3, 48, 2, 175, 155, 7, 53, 4, 202, 2, 66, 143, 163, 3, 57, - 2, 171, 2, 50, 4, 234, 154, 7, 56, 3, 57, 2, 207, 154, 7, 52, 12, 74, 53, - 38, 57, 12, 2, 49, 50, 20, 2, 68, 52, 245, 150, 7, 2, 65, 55, 4, 230, - 163, 3, 51, 231, 244, 2, 49, 2, 11, 56, 2, 191, 153, 7, 49, 2, 171, 153, - 7, 50, 6, 50, 57, 20, 2, 68, 55, 141, 163, 3, 2, 67, 65, 2, 219, 162, 3, - 69, 2, 207, 152, 7, 48, 4, 152, 210, 6, 2, 49, 52, 233, 67, 2, 48, 52, 2, - 11, 79, 2, 143, 216, 3, 84, 10, 84, 3, 65, 76, 76, 104, 4, 79, 85, 82, - 32, 240, 5, 3, 73, 86, 69, 135, 161, 5, 82, 2, 57, 12, 73, 78, 71, 32, - 68, 73, 65, 71, 79, 78, 65, 76, 2, 11, 32, 2, 11, 83, 2, 147, 174, 5, 76, - 4, 230, 211, 3, 68, 199, 194, 3, 75, 8, 212, 213, 3, 2, 73, 45, 214, 135, - 3, 68, 222, 56, 67, 3, 86, 8, 56, 8, 65, 84, 65, 75, 65, 78, 65, 32, 199, - 131, 7, 69, 6, 226, 225, 6, 75, 214, 28, 68, 159, 20, 83, 60, 36, 5, 65, + 129, 2, 2, 69, 56, 6, 70, 57, 234, 174, 3, 53, 231, 188, 2, 52, 4, 26, + 53, 195, 175, 3, 48, 2, 195, 169, 7, 53, 4, 202, 2, 66, 207, 172, 3, 57, + 2, 171, 2, 50, 4, 254, 168, 7, 56, 3, 57, 2, 227, 168, 7, 52, 12, 74, 53, + 38, 57, 12, 2, 49, 50, 20, 2, 68, 52, 137, 165, 7, 2, 65, 55, 4, 166, + 173, 3, 51, 187, 249, 2, 49, 2, 11, 56, 2, 211, 167, 7, 49, 2, 191, 167, + 7, 50, 6, 50, 57, 20, 2, 68, 55, 205, 172, 3, 2, 67, 65, 2, 155, 172, 3, + 69, 2, 227, 166, 7, 48, 4, 172, 224, 6, 2, 49, 52, 233, 67, 2, 48, 52, 2, + 11, 79, 2, 207, 226, 3, 84, 10, 84, 3, 65, 76, 76, 104, 4, 79, 85, 82, + 32, 240, 5, 3, 73, 86, 69, 179, 172, 5, 82, 2, 57, 12, 73, 78, 71, 32, + 68, 73, 65, 71, 79, 78, 65, 76, 2, 11, 32, 2, 11, 83, 2, 191, 185, 5, 76, + 4, 166, 222, 3, 68, 155, 198, 3, 75, 8, 148, 224, 3, 2, 73, 45, 170, 139, + 3, 68, 222, 56, 67, 3, 86, 8, 56, 8, 65, 84, 65, 75, 65, 78, 65, 32, 219, + 145, 7, 69, 6, 246, 239, 6, 75, 214, 28, 68, 159, 20, 83, 60, 36, 5, 65, 84, 73, 78, 32, 79, 79, 54, 164, 5, 12, 83, 77, 65, 76, 76, 32, 76, 69, - 84, 84, 69, 82, 239, 123, 67, 6, 198, 210, 3, 71, 201, 170, 2, 3, 83, 83, - 76, 4, 178, 141, 5, 73, 139, 134, 2, 86, 4, 246, 148, 6, 69, 163, 126, + 84, 84, 69, 82, 167, 123, 67, 6, 134, 221, 3, 71, 153, 172, 2, 3, 83, 83, + 76, 4, 222, 152, 5, 73, 243, 136, 2, 86, 4, 138, 163, 6, 69, 163, 126, 71, 4, 140, 3, 15, 78, 69, 32, 72, 85, 78, 68, 82, 69, 68, 32, 84, 87, - 69, 78, 235, 143, 7, 75, 4, 158, 2, 80, 131, 138, 5, 76, 20, 110, 69, - 146, 1, 72, 20, 2, 73, 88, 134, 251, 4, 65, 186, 66, 77, 222, 49, 81, - 246, 98, 79, 222, 61, 68, 3, 83, 4, 56, 7, 67, 79, 78, 68, 32, 83, 67, - 21, 3, 86, 69, 78, 2, 219, 188, 5, 82, 2, 29, 5, 32, 80, 79, 73, 78, 2, - 11, 84, 2, 203, 229, 5, 32, 2, 251, 143, 7, 86, 2, 17, 2, 84, 89, 2, 199, - 143, 7, 32, 8, 44, 4, 72, 82, 69, 69, 22, 87, 243, 4, 73, 2, 239, 200, 6, - 32, 4, 68, 13, 69, 78, 84, 89, 45, 84, 87, 79, 32, 80, 79, 73, 78, 19, - 79, 2, 223, 86, 84, 2, 139, 139, 7, 32, 4, 48, 6, 80, 32, 87, 73, 84, 72, - 191, 199, 6, 72, 2, 17, 2, 32, 69, 2, 247, 119, 88, 4, 150, 199, 6, 79, - 163, 70, 83, 2, 137, 237, 5, 6, 32, 66, 76, 65, 67, 75, 6, 234, 140, 7, - 50, 2, 51, 3, 65, 93, 134, 1, 65, 178, 6, 69, 236, 1, 10, 73, 67, 75, 32, - 70, 73, 71, 85, 82, 69, 182, 1, 79, 90, 82, 174, 4, 85, 238, 252, 6, 83, - 3, 88, 38, 92, 6, 70, 70, 32, 79, 70, 32, 106, 77, 82, 82, 206, 3, 84, - 210, 133, 3, 78, 243, 214, 2, 68, 4, 60, 8, 65, 69, 83, 67, 85, 76, 65, - 80, 21, 3, 72, 69, 82, 2, 163, 132, 5, 73, 2, 147, 246, 5, 77, 2, 21, 3, - 80, 69, 68, 2, 17, 2, 32, 69, 2, 229, 220, 1, 4, 78, 86, 69, 76, 24, 42, - 32, 205, 1, 5, 84, 32, 79, 70, 32, 12, 82, 69, 54, 79, 180, 235, 1, 8, - 65, 78, 68, 32, 67, 82, 69, 83, 139, 128, 2, 87, 2, 17, 2, 81, 85, 2, 11, - 65, 2, 171, 202, 6, 76, 4, 44, 5, 70, 32, 68, 65, 86, 251, 199, 3, 80, 2, - 163, 193, 6, 73, 12, 66, 71, 30, 83, 40, 4, 80, 82, 79, 84, 242, 77, 72, - 215, 101, 84, 2, 89, 4, 85, 65, 82, 68, 4, 26, 69, 191, 249, 1, 84, 2, - 11, 76, 2, 21, 3, 69, 67, 84, 2, 29, 5, 69, 68, 32, 65, 82, 2, 183, 131, - 7, 69, 4, 188, 152, 5, 10, 85, 69, 32, 79, 70, 32, 76, 73, 66, 69, 179, - 157, 1, 73, 8, 92, 2, 65, 77, 112, 9, 78, 79, 71, 82, 65, 80, 72, 73, 67, - 209, 214, 1, 4, 84, 72, 79, 83, 4, 54, 32, 197, 250, 5, 7, 73, 78, 71, - 32, 66, 79, 87, 2, 33, 6, 76, 79, 67, 79, 77, 79, 2, 143, 208, 1, 84, 2, - 217, 177, 4, 2, 32, 70, 11, 11, 32, 8, 60, 5, 87, 73, 84, 72, 32, 233, - 163, 2, 4, 76, 69, 65, 78, 4, 32, 4, 65, 82, 77, 83, 51, 68, 2, 25, 4, - 32, 82, 65, 73, 2, 203, 246, 1, 83, 2, 167, 235, 5, 82, 4, 44, 4, 67, 75, - 32, 67, 21, 3, 80, 87, 65, 2, 163, 250, 5, 72, 2, 131, 223, 6, 84, 20, - 66, 65, 108, 10, 69, 83, 83, 32, 79, 85, 84, 76, 73, 78, 79, 73, 6, 44, - 4, 73, 71, 72, 84, 45, 3, 87, 66, 69, 4, 184, 150, 3, 2, 32, 82, 143, - 211, 2, 78, 2, 243, 72, 82, 2, 17, 2, 69, 68, 2, 17, 2, 32, 87, 2, 169, - 233, 4, 4, 72, 73, 84, 69, 12, 76, 4, 78, 71, 32, 84, 52, 4, 80, 69, 68, - 32, 241, 8, 4, 67, 84, 76, 89, 2, 17, 2, 69, 82, 2, 181, 197, 6, 3, 77, - 73, 78, 8, 70, 68, 24, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, 13, 2, 85, - 80, 2, 33, 3, 79, 87, 78, 2, 11, 84, 2, 11, 45, 2, 169, 216, 5, 8, 80, - 79, 73, 78, 84, 73, 78, 71, 6, 100, 8, 68, 73, 79, 32, 77, 73, 67, 82, - 20, 9, 70, 70, 69, 68, 32, 70, 76, 65, 84, 187, 249, 6, 80, 2, 167, 209, - 5, 79, 2, 11, 66, 2, 243, 166, 4, 82, 162, 3, 150, 1, 66, 212, 2, 5, 67, - 67, 69, 69, 68, 192, 3, 8, 77, 77, 65, 84, 73, 79, 78, 32, 70, 78, 204, - 22, 3, 80, 69, 82, 204, 11, 2, 82, 70, 47, 83, 63, 11, 83, 60, 76, 6, 67, - 82, 73, 80, 84, 32, 136, 1, 3, 69, 84, 32, 93, 3, 84, 73, 84, 30, 118, - 76, 186, 29, 69, 166, 1, 80, 22, 82, 218, 211, 2, 77, 246, 149, 2, 70, - 30, 83, 42, 84, 62, 90, 238, 85, 78, 15, 79, 2, 207, 30, 69, 28, 56, 6, - 65, 66, 79, 86, 69, 32, 246, 33, 79, 159, 3, 87, 6, 142, 32, 83, 143, - 184, 5, 82, 2, 251, 176, 5, 85, 22, 11, 83, 23, 11, 32, 20, 128, 1, 6, - 65, 66, 79, 86, 69, 32, 156, 1, 7, 66, 85, 84, 32, 78, 79, 84, 32, 2, 79, - 82, 141, 146, 3, 5, 85, 78, 68, 69, 82, 12, 100, 4, 78, 79, 84, 32, 28, - 12, 83, 73, 78, 71, 76, 69, 45, 76, 73, 78, 69, 32, 218, 32, 65, 39, 69, - 4, 242, 32, 65, 167, 1, 69, 4, 250, 32, 69, 83, 78, 2, 93, 5, 32, 69, 81, - 85, 73, 4, 17, 2, 32, 69, 4, 17, 2, 81, 85, 4, 22, 73, 167, 33, 65, 2, - 173, 33, 6, 86, 65, 76, 69, 78, 84, 6, 242, 136, 3, 66, 136, 228, 1, 4, - 87, 73, 84, 72, 147, 142, 1, 84, 249, 1, 194, 1, 32, 72, 7, 68, 65, 78, - 69, 83, 69, 32, 204, 12, 4, 82, 73, 83, 69, 72, 5, 85, 87, 65, 82, 32, - 132, 174, 2, 14, 83, 69, 84, 32, 79, 86, 69, 82, 32, 66, 85, 73, 76, 68, - 159, 157, 3, 70, 4, 50, 87, 225, 197, 5, 6, 66, 69, 72, 73, 78, 68, 2, - 171, 180, 6, 73, 146, 1, 198, 2, 65, 20, 17, 67, 79, 78, 83, 79, 78, 65, - 78, 84, 32, 83, 73, 71, 78, 32, 80, 65, 172, 1, 7, 76, 69, 84, 84, 69, - 82, 32, 188, 3, 18, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 66, - 73, 78, 68, 85, 32, 228, 1, 5, 83, 73, 71, 78, 32, 204, 1, 13, 86, 79, - 87, 69, 76, 32, 83, 73, 71, 78, 32, 80, 65, 183, 245, 4, 68, 2, 171, 152, - 3, 86, 10, 68, 2, 77, 73, 40, 2, 78, 89, 33, 7, 83, 65, 78, 71, 65, 78, - 32, 2, 17, 2, 78, 71, 2, 207, 228, 5, 75, 4, 142, 5, 65, 211, 155, 1, 73, - 4, 162, 235, 6, 77, 3, 87, 76, 246, 1, 65, 58, 70, 78, 76, 2, 82, 34, 83, - 254, 150, 3, 69, 254, 216, 1, 78, 238, 178, 1, 66, 2, 75, 138, 69, 67, 2, - 68, 2, 71, 2, 72, 2, 74, 2, 77, 2, 80, 2, 81, 2, 84, 2, 86, 2, 87, 2, 88, - 2, 89, 2, 90, 186, 2, 73, 2, 79, 3, 85, 7, 180, 171, 6, 6, 82, 67, 72, - 65, 73, 67, 147, 64, 69, 6, 44, 5, 73, 78, 65, 76, 32, 227, 234, 6, 65, - 4, 222, 234, 6, 75, 3, 77, 4, 218, 197, 6, 69, 235, 36, 65, 4, 234, 231, - 6, 89, 187, 2, 65, 16, 90, 66, 2, 68, 2, 75, 12, 3, 76, 69, 85, 38, 67, - 34, 80, 253, 229, 6, 3, 83, 85, 82, 2, 11, 65, 2, 253, 103, 5, 32, 83, - 65, 84, 65, 2, 11, 65, 2, 171, 164, 6, 75, 4, 172, 3, 3, 65, 78, 71, 189, - 162, 6, 3, 85, 82, 78, 10, 32, 2, 80, 65, 235, 145, 3, 86, 8, 28, 3, 77, - 65, 65, 23, 78, 2, 203, 230, 6, 69, 6, 18, 71, 71, 89, 4, 38, 76, 225, - 160, 6, 3, 87, 73, 83, 2, 209, 197, 5, 2, 65, 89, 2, 201, 227, 6, 2, 69, - 67, 12, 18, 77, 23, 78, 2, 187, 134, 3, 69, 10, 96, 3, 69, 85, 76, 34, - 79, 22, 89, 188, 228, 1, 3, 71, 72, 85, 201, 189, 2, 4, 65, 69, 76, 65, - 2, 11, 69, 2, 195, 148, 6, 85, 2, 231, 161, 4, 76, 2, 247, 151, 1, 85, 5, - 165, 161, 3, 13, 32, 79, 86, 69, 82, 32, 77, 79, 85, 78, 84, 65, 73, 88, - 88, 7, 76, 69, 84, 84, 69, 82, 32, 184, 6, 6, 83, 73, 71, 78, 32, 80, - 135, 236, 4, 68, 66, 142, 2, 65, 66, 67, 66, 68, 44, 3, 72, 65, 77, 22, - 74, 34, 75, 42, 78, 38, 79, 2, 85, 34, 80, 38, 82, 20, 4, 83, 72, 89, 69, - 34, 84, 112, 3, 86, 65, 82, 230, 169, 4, 71, 148, 57, 4, 76, 79, 65, 67, - 136, 89, 2, 73, 77, 210, 13, 89, 150, 27, 66, 214, 89, 69, 203, 28, 77, - 6, 42, 80, 238, 215, 5, 65, 255, 134, 1, 86, 2, 251, 248, 1, 80, 4, 40, - 2, 72, 69, 253, 204, 6, 2, 65, 82, 2, 243, 207, 5, 76, 4, 22, 69, 155, - 95, 79, 2, 219, 204, 6, 86, 2, 171, 193, 6, 83, 2, 11, 89, 2, 239, 222, - 6, 65, 6, 194, 172, 6, 76, 146, 48, 73, 99, 72, 4, 138, 190, 5, 71, 171, - 160, 1, 65, 2, 11, 84, 2, 147, 144, 1, 84, 4, 198, 189, 5, 72, 175, 161, - 1, 73, 2, 243, 185, 6, 69, 4, 242, 199, 6, 76, 215, 22, 82, 8, 42, 69, - 22, 72, 209, 187, 6, 2, 65, 83, 2, 171, 142, 1, 78, 4, 26, 65, 167, 185, - 5, 69, 2, 243, 201, 6, 82, 2, 255, 218, 6, 67, 2, 175, 190, 6, 86, 72, - 54, 83, 182, 237, 4, 72, 209, 66, 4, 86, 73, 76, 76, 68, 56, 6, 67, 82, - 73, 80, 84, 32, 229, 2, 3, 69, 84, 32, 34, 114, 69, 34, 76, 134, 1, 80, - 22, 82, 218, 211, 2, 77, 246, 149, 2, 70, 30, 83, 42, 84, 62, 90, 238, - 85, 78, 15, 79, 4, 174, 69, 81, 183, 235, 5, 73, 6, 88, 18, 65, 84, 73, - 78, 32, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 31, 69, 4, - 170, 218, 6, 73, 3, 78, 2, 55, 70, 2, 191, 171, 3, 76, 2, 21, 3, 73, 71, - 72, 2, 11, 84, 2, 139, 215, 2, 32, 34, 148, 1, 6, 65, 66, 79, 86, 69, 32, - 96, 7, 66, 69, 83, 73, 68, 69, 32, 162, 1, 79, 158, 3, 87, 221, 189, 4, - 9, 80, 82, 69, 67, 69, 68, 73, 78, 71, 6, 26, 83, 135, 188, 2, 76, 4, 11, - 85, 4, 26, 80, 151, 236, 4, 66, 2, 145, 236, 4, 2, 69, 82, 4, 108, 23, - 65, 78, 68, 32, 74, 79, 73, 78, 69, 68, 32, 66, 89, 32, 68, 65, 83, 72, - 32, 87, 73, 84, 72, 23, 83, 2, 17, 2, 32, 83, 2, 241, 234, 4, 2, 85, 66, - 16, 11, 70, 17, 11, 32, 14, 120, 6, 65, 66, 79, 86, 69, 32, 132, 1, 4, - 87, 73, 84, 72, 249, 210, 5, 11, 79, 82, 32, 69, 81, 85, 65, 76, 32, 84, - 79, 8, 34, 65, 38, 69, 18, 84, 67, 78, 2, 11, 76, 2, 113, 3, 77, 79, 83, - 2, 203, 62, 81, 2, 21, 3, 73, 76, 68, 2, 171, 148, 3, 69, 2, 17, 2, 32, - 78, 2, 11, 79, 2, 11, 84, 2, 11, 32, 2, 11, 69, 2, 17, 2, 81, 85, 2, 11, - 65, 2, 11, 76, 2, 219, 228, 2, 32, 6, 25, 4, 73, 84, 72, 32, 6, 96, 2, - 80, 76, 24, 14, 77, 85, 76, 84, 73, 80, 76, 73, 67, 65, 84, 73, 79, 78, - 183, 129, 6, 68, 2, 11, 85, 2, 11, 83, 2, 165, 164, 4, 5, 32, 83, 73, 71, - 78, 4, 144, 202, 4, 2, 65, 67, 215, 206, 1, 69, 4, 60, 9, 80, 69, 78, 83, - 73, 79, 78, 32, 82, 131, 189, 6, 72, 2, 21, 3, 65, 73, 76, 2, 187, 196, - 5, 87, 8, 26, 65, 98, 73, 35, 85, 4, 44, 5, 83, 72, 32, 65, 77, 227, 207, - 6, 78, 2, 253, 139, 6, 7, 80, 69, 82, 83, 65, 78, 68, 2, 11, 77, 2, 183, - 145, 6, 77, 2, 233, 145, 3, 2, 78, 71, 236, 2, 92, 11, 76, 79, 84, 73, - 32, 78, 65, 71, 82, 73, 32, 226, 5, 77, 194, 17, 78, 97, 2, 82, 73, 90, - 180, 1, 7, 76, 69, 84, 84, 69, 82, 32, 168, 2, 11, 80, 79, 69, 84, 82, - 89, 32, 77, 65, 82, 75, 56, 5, 83, 73, 71, 78, 32, 145, 1, 11, 86, 79, - 87, 69, 76, 32, 83, 73, 71, 78, 32, 64, 174, 1, 68, 46, 82, 34, 84, 166, - 91, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 198, 208, 5, 72, 2, 76, 2, 77, - 2, 78, 2, 83, 246, 30, 65, 2, 69, 2, 73, 2, 79, 3, 85, 8, 238, 91, 68, - 198, 208, 5, 72, 247, 30, 79, 4, 134, 172, 6, 82, 247, 30, 79, 8, 162, - 91, 84, 198, 208, 5, 72, 247, 30, 79, 8, 11, 45, 8, 162, 202, 6, 49, 2, - 50, 2, 51, 3, 52, 8, 46, 65, 70, 72, 165, 132, 6, 3, 68, 86, 73, 4, 64, - 10, 76, 84, 69, 82, 78, 65, 84, 69, 32, 72, 155, 132, 6, 78, 2, 193, 137, - 2, 2, 65, 83, 10, 242, 169, 6, 79, 246, 30, 65, 2, 69, 2, 73, 3, 85, 88, - 60, 8, 66, 79, 76, 32, 70, 79, 82, 32, 225, 16, 2, 77, 69, 86, 238, 2, - 66, 48, 2, 67, 65, 118, 68, 234, 3, 69, 130, 2, 70, 56, 8, 72, 79, 82, - 73, 90, 79, 78, 84, 0, 6, 86, 69, 82, 84, 73, 67, 44, 3, 76, 73, 78, 52, - 9, 77, 65, 82, 75, 83, 32, 67, 72, 65, 22, 78, 90, 65, 68, 3, 82, 69, 67, - 32, 5, 71, 82, 79, 85, 80, 0, 4, 85, 78, 73, 84, 22, 83, 205, 3, 15, 84, - 89, 80, 69, 32, 65, 32, 69, 76, 69, 67, 84, 82, 79, 78, 4, 190, 189, 4, - 69, 137, 201, 1, 3, 65, 67, 75, 4, 44, 3, 82, 82, 73, 189, 183, 1, 2, 78, - 67, 2, 33, 6, 65, 71, 69, 32, 82, 69, 2, 11, 84, 2, 215, 185, 1, 85, 20, - 24, 2, 65, 84, 55, 69, 2, 173, 5, 9, 65, 32, 76, 73, 78, 75, 32, 69, 83, - 18, 84, 4, 76, 69, 84, 69, 133, 2, 12, 86, 73, 67, 69, 32, 67, 79, 78, - 84, 82, 79, 76, 11, 11, 32, 8, 160, 1, 11, 82, 69, 67, 84, 65, 78, 71, - 85, 76, 65, 82, 0, 6, 83, 81, 85, 65, 82, 69, 154, 9, 70, 129, 185, 5, - 11, 77, 69, 68, 73, 85, 77, 32, 83, 72, 65, 68, 2, 61, 13, 32, 67, 72, - 69, 67, 75, 69, 82, 32, 66, 79, 65, 82, 2, 227, 193, 5, 68, 8, 11, 32, 8, - 162, 173, 1, 70, 162, 163, 3, 84, 183, 86, 79, 12, 22, 78, 207, 1, 83, - 10, 48, 5, 68, 32, 79, 70, 32, 137, 1, 2, 81, 85, 8, 18, 77, 31, 84, 2, - 245, 149, 5, 2, 69, 68, 6, 64, 11, 82, 65, 78, 83, 77, 73, 83, 83, 73, - 79, 78, 223, 107, 69, 5, 235, 207, 3, 32, 2, 155, 7, 73, 2, 209, 246, 4, - 2, 67, 65, 4, 36, 2, 73, 76, 73, 3, 79, 82, 77, 2, 191, 2, 69, 2, 229, - 160, 1, 6, 65, 76, 32, 84, 65, 66, 2, 11, 69, 2, 17, 2, 32, 70, 2, 163, - 177, 1, 69, 2, 227, 132, 5, 80, 6, 26, 69, 239, 180, 4, 85, 4, 56, 8, 71, - 65, 84, 73, 86, 69, 32, 65, 175, 162, 5, 87, 2, 21, 3, 67, 75, 78, 2, 21, - 3, 79, 87, 76, 2, 231, 135, 1, 69, 2, 11, 79, 2, 17, 2, 82, 68, 2, 163, - 141, 3, 32, 18, 180, 1, 7, 65, 77, 65, 82, 73, 84, 65, 60, 3, 72, 73, 70, - 52, 8, 84, 65, 82, 84, 32, 79, 70, 32, 64, 8, 85, 66, 83, 84, 73, 84, 85, - 84, 200, 1, 3, 89, 78, 67, 195, 249, 5, 80, 2, 25, 4, 78, 32, 83, 79, 2, - 11, 85, 2, 155, 252, 5, 82, 4, 17, 2, 84, 32, 4, 158, 191, 5, 79, 243, - 41, 73, 4, 22, 72, 215, 101, 84, 2, 17, 2, 69, 65, 2, 159, 231, 5, 68, 4, - 11, 69, 5, 11, 32, 2, 11, 70, 2, 21, 3, 79, 82, 77, 2, 17, 2, 32, 84, 2, - 203, 152, 6, 87, 2, 205, 249, 5, 2, 73, 67, 2, 11, 84, 2, 187, 165, 6, - 82, 7, 38, 67, 181, 171, 2, 3, 65, 71, 79, 2, 181, 133, 1, 9, 72, 82, 79, - 78, 79, 85, 83, 32, 73, 180, 1, 36, 3, 65, 67, 32, 199, 128, 5, 78, 178, - 1, 150, 3, 65, 52, 4, 66, 65, 82, 82, 32, 2, 67, 79, 80, 13, 68, 79, 84, - 84, 69, 68, 32, 90, 76, 65, 77, 65, 32, 118, 69, 90, 72, 204, 2, 7, 76, - 69, 84, 84, 69, 82, 32, 236, 9, 9, 79, 66, 76, 73, 81, 85, 69, 32, 76, - 28, 4, 80, 84, 72, 65, 0, 4, 90, 81, 65, 80, 110, 82, 88, 2, 83, 85, 174, - 2, 84, 140, 247, 4, 3, 77, 85, 83, 232, 22, 7, 70, 69, 77, 73, 78, 73, - 78, 253, 136, 1, 5, 81, 85, 83, 72, 83, 2, 11, 66, 2, 133, 201, 5, 5, 66, - 82, 69, 86, 73, 2, 11, 69, 2, 247, 176, 6, 75, 6, 38, 78, 165, 17, 4, 76, - 79, 78, 32, 2, 17, 2, 84, 82, 2, 219, 224, 5, 65, 4, 28, 3, 65, 78, 71, - 35, 72, 2, 11, 85, 2, 191, 143, 5, 76, 2, 11, 79, 2, 169, 220, 3, 5, 82, - 73, 90, 79, 78, 6, 60, 10, 78, 68, 32, 79, 70, 32, 80, 65, 82, 65, 151, - 14, 83, 2, 201, 11, 2, 71, 82, 14, 104, 8, 65, 82, 75, 76, 69, 65, 78, - 32, 132, 1, 4, 66, 65, 83, 65, 65, 7, 79, 82, 73, 90, 79, 78, 84, 6, 60, - 5, 65, 83, 84, 69, 82, 40, 4, 77, 69, 84, 79, 3, 79, 2, 17, 2, 73, 83, 2, - 155, 168, 4, 67, 2, 201, 167, 2, 2, 66, 69, 6, 164, 11, 8, 45, 69, 83, - 65, 83, 65, 32, 68, 151, 132, 4, 32, 2, 137, 221, 5, 2, 65, 76, 92, 154, - 2, 68, 102, 72, 32, 3, 76, 65, 77, 34, 77, 204, 1, 2, 80, 69, 142, 1, 82, - 78, 83, 144, 1, 8, 70, 73, 78, 65, 76, 32, 83, 69, 106, 65, 14, 75, 2, - 81, 34, 84, 40, 5, 71, 65, 77, 65, 76, 40, 4, 89, 85, 68, 72, 214, 74, - 66, 142, 172, 4, 90, 166, 44, 78, 134, 2, 87, 175, 126, 69, 4, 76, 14, - 79, 84, 76, 69, 83, 83, 32, 68, 65, 76, 65, 84, 72, 32, 139, 3, 65, 2, - 167, 201, 2, 82, 4, 11, 69, 5, 239, 168, 6, 84, 2, 11, 65, 2, 207, 168, - 6, 68, 24, 60, 9, 65, 76, 65, 89, 65, 76, 65, 77, 32, 183, 152, 6, 73, - 22, 78, 76, 22, 78, 234, 173, 4, 66, 246, 213, 1, 84, 138, 34, 83, 14, - 74, 3, 82, 4, 135, 159, 4, 76, 8, 246, 83, 78, 250, 209, 5, 71, 3, 89, 9, - 33, 6, 82, 83, 73, 65, 78, 32, 6, 50, 66, 16, 3, 68, 72, 65, 17, 3, 71, - 72, 65, 2, 199, 78, 72, 2, 147, 2, 76, 2, 199, 157, 5, 77, 4, 52, 7, 69, - 86, 69, 82, 83, 69, 68, 159, 190, 4, 73, 2, 255, 222, 4, 32, 14, 142, 1, - 69, 40, 7, 79, 71, 68, 73, 65, 78, 32, 64, 12, 85, 80, 69, 82, 83, 67, - 82, 73, 80, 84, 32, 65, 222, 164, 5, 72, 201, 82, 2, 65, 68, 2, 17, 2, - 77, 75, 2, 243, 162, 4, 65, 6, 42, 90, 32, 2, 75, 72, 211, 141, 6, 70, 2, - 239, 247, 4, 72, 2, 11, 76, 2, 11, 65, 2, 135, 163, 6, 80, 6, 36, 3, 69, - 84, 72, 191, 165, 5, 65, 5, 173, 85, 6, 32, 71, 65, 82, 83, 72, 5, 167, - 246, 5, 32, 4, 217, 132, 4, 2, 73, 78, 6, 21, 3, 72, 65, 32, 6, 42, 68, - 178, 132, 4, 66, 167, 161, 1, 65, 2, 17, 2, 79, 84, 2, 223, 150, 1, 84, - 8, 58, 66, 162, 203, 2, 87, 249, 166, 1, 4, 85, 75, 75, 65, 4, 157, 240, - 3, 2, 65, 83, 14, 88, 8, 66, 76, 73, 78, 69, 65, 82, 32, 113, 10, 80, 82, - 65, 76, 73, 78, 69, 65, 82, 32, 8, 44, 5, 67, 79, 76, 79, 78, 211, 206, - 3, 70, 7, 11, 32, 4, 29, 5, 83, 75, 69, 87, 69, 4, 251, 244, 5, 68, 6, - 44, 5, 67, 79, 76, 79, 78, 227, 205, 3, 70, 5, 253, 236, 5, 7, 32, 83, - 75, 69, 87, 69, 68, 8, 62, 72, 25, 11, 87, 79, 32, 86, 69, 82, 84, 73, - 67, 65, 76, 4, 21, 3, 82, 69, 69, 4, 25, 4, 32, 68, 79, 84, 4, 231, 255, - 3, 83, 190, 43, 102, 45, 58, 65, 206, 105, 69, 154, 45, 72, 182, 46, 73, - 230, 69, 79, 170, 33, 82, 214, 16, 85, 147, 22, 87, 4, 32, 2, 83, 72, - 255, 246, 4, 82, 2, 235, 149, 5, 73, 244, 26, 182, 1, 66, 82, 71, 196, - 17, 2, 73, 32, 170, 29, 75, 144, 5, 9, 76, 76, 89, 32, 77, 65, 82, 75, - 32, 34, 77, 178, 37, 78, 132, 13, 3, 80, 69, 32, 94, 85, 190, 148, 5, 67, - 159, 11, 88, 5, 221, 122, 16, 76, 69, 32, 84, 69, 78, 78, 73, 83, 32, 80, - 65, 68, 68, 76, 69, 144, 2, 78, 32, 240, 11, 5, 65, 76, 79, 71, 32, 241, - 2, 6, 66, 65, 78, 87, 65, 32, 190, 1, 162, 1, 65, 102, 67, 186, 1, 68, - 58, 69, 98, 71, 118, 72, 46, 76, 230, 3, 80, 58, 81, 62, 82, 106, 83, - 142, 76, 78, 230, 222, 1, 84, 250, 145, 1, 70, 231, 183, 1, 86, 6, 42, - 80, 150, 201, 2, 77, 219, 187, 1, 83, 2, 17, 2, 79, 83, 2, 145, 235, 5, - 4, 84, 82, 79, 80, 8, 18, 73, 63, 79, 2, 25, 4, 82, 67, 85, 77, 2, 213, - 2, 4, 70, 76, 69, 88, 6, 26, 77, 167, 199, 5, 76, 4, 11, 77, 4, 152, 131, - 5, 7, 69, 82, 67, 73, 65, 76, 32, 235, 147, 1, 65, 22, 26, 79, 151, 165, - 4, 73, 2, 11, 76, 2, 235, 84, 76, 4, 18, 81, 43, 88, 2, 17, 2, 85, 65, 2, - 171, 231, 2, 76, 2, 153, 172, 5, 4, 67, 76, 65, 77, 4, 11, 82, 4, 18, 65, - 55, 69, 2, 11, 86, 2, 11, 69, 2, 177, 120, 3, 32, 65, 67, 2, 145, 4, 4, - 65, 84, 69, 82, 2, 145, 142, 2, 6, 89, 80, 72, 69, 78, 45, 114, 38, 65, - 254, 2, 69, 247, 168, 4, 79, 104, 25, 4, 84, 73, 78, 32, 104, 34, 67, 41, - 4, 83, 77, 65, 76, 52, 11, 65, 52, 25, 4, 80, 73, 84, 65, 52, 41, 8, 76, - 32, 76, 69, 84, 84, 69, 82, 52, 11, 32, 52, 194, 146, 6, 65, 2, 66, 2, - 67, 2, 68, 2, 69, 2, 70, 2, 71, 2, 72, 2, 73, 2, 74, 2, 75, 2, 76, 2, 77, - 2, 78, 2, 79, 2, 80, 2, 81, 2, 82, 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, - 88, 2, 89, 3, 90, 8, 22, 83, 199, 1, 70, 2, 11, 83, 2, 197, 63, 3, 45, - 84, 72, 4, 26, 69, 203, 225, 2, 76, 2, 11, 82, 2, 227, 67, 67, 4, 11, 85, - 4, 26, 79, 203, 190, 3, 69, 2, 147, 166, 5, 84, 8, 36, 3, 73, 71, 72, - 199, 249, 3, 69, 6, 17, 2, 84, 32, 6, 242, 136, 2, 67, 210, 3, 80, 239, - 7, 83, 6, 142, 195, 2, 69, 146, 184, 1, 79, 167, 214, 1, 80, 46, 80, 7, - 76, 69, 84, 84, 69, 82, 32, 208, 1, 5, 83, 73, 71, 78, 32, 147, 2, 86, - 38, 162, 1, 65, 242, 154, 2, 78, 250, 238, 3, 66, 2, 68, 2, 71, 2, 72, 2, - 75, 2, 76, 2, 77, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, 89, 186, 2, 73, - 3, 85, 5, 197, 193, 5, 6, 82, 67, 72, 65, 73, 67, 4, 26, 80, 199, 181, 2, - 86, 2, 25, 4, 65, 77, 85, 68, 2, 227, 212, 2, 80, 36, 48, 7, 76, 69, 84, - 84, 69, 82, 32, 147, 1, 86, 32, 194, 153, 2, 78, 250, 238, 3, 66, 2, 68, - 2, 71, 2, 75, 2, 76, 2, 77, 2, 80, 2, 83, 2, 84, 2, 87, 2, 89, 186, 2, - 65, 2, 73, 3, 85, 4, 41, 8, 79, 87, 69, 76, 32, 83, 73, 71, 4, 11, 78, 4, - 243, 200, 5, 32, 212, 3, 112, 10, 76, 69, 32, 76, 69, 84, 84, 69, 82, 32, - 248, 2, 5, 84, 72, 65, 77, 32, 189, 18, 5, 86, 73, 69, 84, 32, 70, 186, - 1, 65, 34, 69, 30, 84, 250, 148, 2, 78, 210, 171, 1, 79, 162, 254, 1, 75, - 2, 80, 162, 7, 85, 234, 61, 70, 2, 72, 2, 76, 2, 77, 2, 81, 2, 83, 2, 86, - 2, 88, 2, 89, 187, 2, 73, 7, 142, 240, 5, 85, 215, 22, 73, 7, 194, 134, - 6, 69, 3, 72, 18, 60, 3, 79, 78, 69, 170, 190, 5, 83, 138, 69, 72, 187, - 2, 65, 10, 11, 45, 10, 218, 133, 6, 50, 2, 51, 2, 52, 2, 53, 3, 54, 254, - 1, 196, 1, 2, 67, 79, 240, 3, 4, 72, 79, 82, 65, 0, 4, 84, 72, 65, 77, - 28, 7, 76, 69, 84, 84, 69, 82, 32, 220, 4, 5, 83, 73, 71, 78, 32, 213, 5, - 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 20, 164, 1, 13, 78, 83, - 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 161, 241, 4, 21, 77, 66, 73, - 78, 73, 78, 71, 32, 67, 82, 89, 80, 84, 79, 71, 82, 65, 77, 77, 73, 67, - 18, 148, 1, 6, 70, 73, 78, 65, 76, 32, 22, 76, 56, 16, 72, 73, 71, 72, - 32, 82, 65, 84, 72, 65, 32, 79, 82, 32, 76, 79, 22, 77, 134, 254, 5, 66, - 3, 83, 2, 215, 190, 5, 78, 4, 54, 79, 213, 149, 1, 7, 65, 32, 84, 65, 78, - 71, 32, 2, 187, 214, 1, 87, 6, 48, 6, 69, 68, 73, 65, 76, 32, 139, 128, - 6, 65, 4, 206, 253, 5, 76, 3, 82, 20, 201, 142, 4, 2, 32, 68, 106, 188, - 1, 2, 71, 82, 44, 5, 72, 73, 71, 72, 32, 94, 76, 222, 1, 82, 134, 168, 2, - 85, 206, 201, 1, 73, 178, 15, 78, 186, 219, 1, 79, 162, 8, 69, 158, 20, - 66, 2, 68, 2, 77, 2, 87, 187, 2, 65, 2, 21, 3, 69, 65, 84, 2, 179, 251, - 5, 32, 32, 242, 1, 75, 42, 82, 186, 179, 5, 83, 82, 67, 2, 80, 2, 84, - 138, 69, 70, 2, 72, 3, 89, 36, 60, 3, 79, 87, 32, 170, 188, 5, 65, 206, - 41, 85, 159, 20, 76, 28, 86, 75, 42, 82, 138, 180, 5, 67, 2, 80, 2, 84, - 138, 69, 70, 2, 72, 2, 83, 3, 89, 6, 182, 249, 5, 72, 2, 88, 187, 2, 65, - 2, 133, 129, 4, 2, 65, 84, 8, 26, 65, 191, 228, 5, 85, 7, 214, 248, 5, - 78, 3, 84, 50, 178, 1, 72, 34, 75, 176, 1, 4, 77, 65, 73, 32, 82, 82, - 136, 1, 2, 83, 65, 92, 5, 87, 73, 65, 78, 71, 188, 126, 3, 68, 79, 75, - 224, 117, 3, 84, 79, 78, 205, 168, 3, 2, 67, 65, 4, 198, 168, 5, 65, 179, - 63, 79, 14, 52, 4, 72, 85, 69, 78, 134, 3, 65, 195, 219, 4, 69, 8, 80, 6, - 32, 84, 79, 78, 69, 45, 149, 174, 4, 8, 45, 76, 85, 69, 32, 75, 65, 82, - 6, 146, 248, 5, 51, 2, 52, 3, 53, 8, 56, 4, 75, 65, 78, 71, 134, 135, 1, - 89, 183, 181, 3, 83, 5, 183, 140, 1, 32, 4, 92, 3, 65, 32, 72, 21, 16, - 69, 86, 69, 82, 83, 69, 68, 32, 82, 79, 84, 65, 84, 69, 68, 32, 2, 195, - 187, 4, 65, 2, 155, 198, 3, 82, 8, 48, 3, 84, 75, 65, 230, 171, 4, 87, - 203, 121, 75, 4, 17, 2, 65, 78, 5, 199, 131, 4, 75, 5, 245, 191, 3, 2, - 87, 65, 38, 90, 65, 36, 4, 77, 65, 73, 32, 22, 79, 46, 84, 86, 85, 178, - 233, 3, 73, 223, 137, 2, 69, 9, 194, 244, 5, 65, 2, 69, 3, 73, 2, 183, - 224, 4, 83, 11, 210, 213, 3, 65, 186, 158, 2, 79, 3, 89, 4, 42, 65, 197, - 136, 1, 4, 72, 65, 77, 32, 2, 17, 2, 76, 76, 2, 211, 128, 4, 32, 9, 234, - 178, 5, 85, 163, 64, 69, 144, 1, 184, 1, 7, 76, 69, 84, 84, 69, 82, 32, - 188, 2, 5, 77, 65, 73, 32, 75, 32, 7, 83, 89, 77, 66, 79, 76, 32, 116, 9, + 69, 78, 255, 157, 7, 75, 4, 158, 2, 80, 175, 149, 5, 76, 20, 110, 69, + 146, 1, 72, 20, 2, 73, 88, 190, 133, 5, 65, 250, 67, 77, 246, 49, 81, + 250, 100, 79, 222, 61, 68, 3, 83, 4, 56, 7, 67, 79, 78, 68, 32, 83, 67, + 21, 3, 86, 69, 78, 2, 211, 200, 5, 82, 2, 29, 5, 32, 80, 79, 73, 78, 2, + 11, 84, 2, 203, 241, 5, 32, 2, 143, 158, 7, 86, 2, 17, 2, 84, 89, 2, 219, + 157, 7, 32, 8, 44, 4, 72, 82, 69, 69, 22, 87, 247, 4, 73, 2, 131, 215, 6, + 32, 4, 68, 13, 69, 78, 84, 89, 45, 84, 87, 79, 32, 80, 79, 73, 78, 23, + 79, 2, 251, 135, 5, 84, 2, 155, 153, 7, 32, 4, 48, 6, 80, 32, 87, 73, 84, + 72, 207, 213, 6, 72, 2, 17, 2, 32, 69, 2, 171, 119, 88, 4, 166, 213, 6, + 79, 163, 70, 83, 2, 149, 249, 5, 6, 32, 66, 76, 65, 67, 75, 6, 250, 154, + 7, 50, 2, 51, 3, 65, 95, 134, 1, 65, 178, 6, 69, 236, 1, 10, 73, 67, 75, + 32, 70, 73, 71, 85, 82, 69, 182, 1, 79, 90, 82, 190, 4, 85, 238, 138, 7, + 83, 3, 88, 38, 92, 6, 70, 70, 32, 79, 70, 32, 106, 77, 82, 82, 206, 3, + 84, 142, 143, 3, 78, 179, 217, 2, 68, 4, 60, 8, 65, 69, 83, 67, 85, 76, + 65, 80, 21, 3, 72, 69, 82, 2, 203, 143, 5, 73, 2, 151, 130, 6, 77, 2, 21, + 3, 80, 69, 68, 2, 17, 2, 32, 69, 2, 233, 225, 1, 4, 78, 86, 69, 76, 24, + 42, 32, 205, 1, 5, 84, 32, 79, 70, 32, 12, 82, 69, 54, 79, 248, 240, 1, + 8, 65, 78, 68, 32, 67, 82, 69, 83, 131, 133, 2, 87, 2, 17, 2, 81, 85, 2, + 11, 65, 2, 187, 216, 6, 76, 4, 44, 5, 70, 32, 68, 65, 86, 183, 210, 3, + 80, 2, 179, 207, 6, 73, 12, 66, 71, 30, 83, 40, 4, 80, 82, 79, 84, 242, + 77, 72, 239, 106, 84, 2, 89, 4, 85, 65, 82, 68, 4, 26, 69, 131, 255, 1, + 84, 2, 11, 76, 2, 21, 3, 69, 67, 84, 2, 29, 5, 69, 68, 32, 65, 82, 2, + 199, 145, 7, 69, 4, 228, 163, 5, 10, 85, 69, 32, 79, 70, 32, 76, 73, 66, + 69, 155, 160, 1, 73, 8, 92, 2, 65, 77, 112, 9, 78, 79, 71, 82, 65, 80, + 72, 73, 67, 213, 219, 1, 4, 84, 72, 79, 83, 4, 54, 32, 185, 134, 6, 7, + 73, 78, 71, 32, 66, 79, 87, 2, 33, 6, 76, 79, 67, 79, 77, 79, 2, 147, + 213, 1, 84, 2, 153, 188, 4, 2, 32, 70, 11, 11, 32, 8, 60, 5, 87, 73, 84, + 72, 32, 193, 169, 2, 4, 76, 69, 65, 78, 4, 32, 4, 65, 82, 77, 83, 51, 68, + 2, 25, 4, 32, 82, 65, 73, 2, 143, 252, 1, 83, 2, 179, 247, 5, 82, 4, 44, + 4, 67, 75, 32, 67, 21, 3, 80, 87, 65, 2, 179, 136, 6, 72, 2, 147, 237, 6, + 84, 22, 66, 65, 124, 10, 69, 83, 83, 32, 79, 85, 84, 76, 73, 78, 79, 73, + 8, 56, 4, 73, 71, 72, 84, 45, 6, 87, 66, 69, 82, 82, 89, 4, 196, 160, 3, + 2, 32, 82, 131, 213, 2, 78, 5, 195, 248, 5, 32, 2, 17, 2, 69, 68, 2, 17, + 2, 32, 87, 2, 205, 243, 4, 4, 72, 73, 84, 69, 12, 76, 4, 78, 71, 32, 84, + 52, 4, 80, 69, 68, 32, 241, 8, 4, 67, 84, 76, 89, 2, 17, 2, 69, 82, 2, + 181, 211, 6, 3, 77, 73, 78, 8, 70, 68, 24, 3, 76, 69, 70, 0, 4, 82, 73, + 71, 72, 13, 2, 85, 80, 2, 33, 3, 79, 87, 78, 2, 11, 84, 2, 11, 45, 2, + 149, 228, 5, 8, 80, 79, 73, 78, 84, 73, 78, 71, 6, 100, 8, 68, 73, 79, + 32, 77, 73, 67, 82, 20, 9, 70, 70, 69, 68, 32, 70, 76, 65, 84, 187, 135, + 7, 80, 2, 147, 221, 5, 79, 2, 11, 66, 2, 163, 177, 4, 82, 162, 3, 150, 1, + 66, 212, 2, 5, 67, 67, 69, 69, 68, 192, 3, 8, 77, 77, 65, 84, 73, 79, 78, + 32, 70, 78, 204, 22, 3, 80, 69, 82, 188, 11, 2, 82, 70, 47, 83, 63, 11, + 83, 60, 76, 6, 67, 82, 73, 80, 84, 32, 136, 1, 3, 69, 84, 32, 93, 3, 84, + 73, 84, 30, 118, 76, 186, 29, 69, 166, 1, 80, 22, 82, 134, 221, 2, 77, + 226, 151, 2, 70, 30, 83, 42, 84, 62, 90, 210, 86, 78, 15, 79, 2, 207, 30, + 69, 28, 56, 6, 65, 66, 79, 86, 69, 32, 246, 33, 79, 159, 3, 87, 6, 142, + 32, 83, 139, 196, 5, 82, 2, 223, 188, 5, 85, 22, 11, 83, 23, 11, 32, 20, + 128, 1, 6, 65, 66, 79, 86, 69, 32, 156, 1, 7, 66, 85, 84, 32, 78, 79, 84, + 32, 2, 79, 82, 149, 156, 3, 5, 85, 78, 68, 69, 82, 12, 100, 4, 78, 79, + 84, 32, 28, 12, 83, 73, 78, 71, 76, 69, 45, 76, 73, 78, 69, 32, 218, 32, + 65, 39, 69, 4, 242, 32, 65, 167, 1, 69, 4, 250, 32, 69, 83, 78, 2, 93, 5, + 32, 69, 81, 85, 73, 4, 17, 2, 32, 69, 4, 17, 2, 81, 85, 4, 22, 73, 167, + 33, 65, 2, 173, 33, 6, 86, 65, 76, 69, 78, 84, 6, 250, 146, 3, 66, 152, + 229, 1, 4, 87, 73, 84, 72, 251, 144, 1, 84, 249, 1, 194, 1, 32, 72, 7, + 68, 65, 78, 69, 83, 69, 32, 204, 12, 4, 82, 73, 83, 69, 72, 5, 85, 87, + 65, 82, 32, 168, 179, 2, 14, 83, 69, 84, 32, 79, 86, 69, 82, 32, 66, 85, + 73, 76, 68, 247, 163, 3, 70, 4, 50, 87, 205, 209, 5, 6, 66, 69, 72, 73, + 78, 68, 2, 171, 194, 6, 73, 146, 1, 198, 2, 65, 20, 17, 67, 79, 78, 83, + 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 80, 65, 172, 1, 7, 76, 69, + 84, 84, 69, 82, 32, 188, 3, 18, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, + 78, 32, 66, 73, 78, 68, 85, 32, 228, 1, 5, 83, 73, 71, 78, 32, 204, 1, + 13, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 80, 65, 207, 128, 5, 68, + 2, 215, 162, 3, 86, 10, 68, 2, 77, 73, 40, 2, 78, 89, 33, 7, 83, 65, 78, + 71, 65, 78, 32, 2, 17, 2, 78, 71, 2, 179, 240, 5, 75, 4, 142, 5, 65, 219, + 160, 1, 73, 4, 162, 249, 6, 77, 3, 87, 76, 246, 1, 65, 58, 70, 78, 76, 2, + 82, 34, 83, 170, 161, 3, 69, 234, 217, 1, 78, 214, 181, 1, 66, 2, 75, + 138, 69, 67, 2, 68, 2, 71, 2, 72, 2, 74, 2, 77, 2, 80, 2, 81, 2, 84, 2, + 86, 2, 87, 2, 88, 2, 89, 2, 90, 186, 2, 73, 2, 79, 3, 85, 7, 180, 185, 6, + 6, 82, 67, 72, 65, 73, 67, 147, 64, 69, 6, 44, 5, 73, 78, 65, 76, 32, + 227, 248, 6, 65, 4, 222, 248, 6, 75, 3, 77, 4, 218, 211, 6, 69, 235, 36, + 65, 4, 234, 245, 6, 89, 187, 2, 65, 16, 90, 66, 2, 68, 2, 75, 12, 3, 76, + 69, 85, 38, 67, 34, 80, 253, 243, 6, 3, 83, 85, 82, 2, 11, 65, 2, 189, + 103, 5, 32, 83, 65, 84, 65, 2, 11, 65, 2, 171, 178, 6, 75, 4, 172, 3, 3, + 65, 78, 71, 189, 176, 6, 3, 85, 82, 78, 10, 32, 2, 80, 65, 151, 156, 3, + 86, 8, 28, 3, 77, 65, 65, 23, 78, 2, 203, 244, 6, 69, 6, 18, 71, 71, 89, + 4, 38, 76, 225, 174, 6, 3, 87, 73, 83, 2, 205, 209, 5, 2, 65, 89, 2, 201, + 241, 6, 2, 69, 67, 12, 18, 77, 23, 78, 2, 231, 144, 3, 69, 10, 96, 3, 69, + 85, 76, 34, 79, 22, 89, 232, 233, 1, 3, 71, 72, 85, 205, 194, 2, 4, 65, + 69, 76, 65, 2, 11, 69, 2, 195, 162, 6, 85, 2, 151, 172, 4, 76, 2, 255, + 156, 1, 85, 5, 209, 171, 3, 13, 32, 79, 86, 69, 82, 32, 77, 79, 85, 78, + 84, 65, 73, 88, 88, 7, 76, 69, 84, 84, 69, 82, 32, 184, 6, 6, 83, 73, 71, + 78, 32, 80, 159, 247, 4, 68, 66, 142, 2, 65, 66, 67, 66, 68, 44, 3, 72, + 65, 77, 22, 74, 34, 75, 42, 78, 38, 79, 2, 85, 34, 80, 38, 82, 20, 4, 83, + 72, 89, 69, 34, 84, 112, 3, 86, 65, 82, 144, 238, 4, 4, 76, 79, 65, 67, + 218, 29, 71, 148, 60, 2, 73, 77, 142, 26, 89, 222, 16, 66, 214, 89, 69, + 203, 28, 77, 6, 42, 80, 210, 227, 5, 65, 155, 137, 1, 86, 2, 167, 254, 1, + 80, 4, 40, 2, 72, 69, 253, 218, 6, 2, 65, 82, 2, 215, 219, 5, 76, 4, 22, + 69, 219, 94, 79, 2, 219, 218, 6, 86, 2, 171, 207, 6, 83, 2, 11, 89, 2, + 239, 236, 6, 65, 6, 194, 186, 6, 76, 146, 48, 73, 99, 72, 4, 134, 202, 5, + 71, 175, 162, 1, 65, 2, 11, 84, 2, 155, 149, 1, 84, 4, 194, 201, 5, 72, + 179, 163, 1, 73, 2, 243, 199, 6, 69, 4, 242, 213, 6, 76, 215, 22, 82, 8, + 42, 69, 22, 72, 209, 201, 6, 2, 65, 83, 2, 179, 147, 1, 78, 4, 26, 65, + 147, 197, 5, 69, 2, 243, 215, 6, 82, 2, 255, 232, 6, 67, 2, 175, 204, 6, + 86, 72, 54, 83, 206, 248, 4, 72, 165, 67, 4, 86, 73, 76, 76, 68, 56, 6, + 67, 82, 73, 80, 84, 32, 229, 2, 3, 69, 84, 32, 34, 114, 69, 34, 76, 134, + 1, 80, 22, 82, 134, 221, 2, 77, 226, 151, 2, 70, 30, 83, 42, 84, 62, 90, + 210, 86, 78, 15, 79, 4, 210, 68, 81, 147, 250, 5, 73, 6, 88, 18, 65, 84, + 73, 78, 32, 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 31, 69, + 4, 170, 232, 6, 73, 3, 78, 2, 55, 70, 2, 235, 181, 3, 76, 2, 21, 3, 73, + 71, 72, 2, 11, 84, 2, 183, 224, 2, 32, 34, 148, 1, 6, 65, 66, 79, 86, 69, + 32, 96, 7, 66, 69, 83, 73, 68, 69, 32, 162, 1, 79, 158, 3, 87, 129, 200, + 4, 9, 80, 82, 69, 67, 69, 68, 73, 78, 71, 6, 26, 83, 227, 192, 2, 76, 4, + 11, 85, 4, 26, 80, 175, 247, 4, 66, 2, 169, 247, 4, 2, 69, 82, 4, 108, + 23, 65, 78, 68, 32, 74, 79, 73, 78, 69, 68, 32, 66, 89, 32, 68, 65, 83, + 72, 32, 87, 73, 84, 72, 23, 83, 2, 17, 2, 32, 83, 2, 137, 246, 4, 2, 85, + 66, 16, 11, 70, 17, 11, 32, 14, 120, 6, 65, 66, 79, 86, 69, 32, 132, 1, + 4, 87, 73, 84, 72, 249, 224, 5, 11, 79, 82, 32, 69, 81, 85, 65, 76, 32, + 84, 79, 8, 34, 65, 38, 69, 18, 84, 67, 78, 2, 11, 76, 2, 113, 3, 77, 79, + 83, 2, 239, 61, 81, 2, 21, 3, 73, 76, 68, 2, 215, 158, 3, 69, 2, 17, 2, + 32, 78, 2, 11, 79, 2, 11, 84, 2, 11, 32, 2, 11, 69, 2, 17, 2, 81, 85, 2, + 11, 65, 2, 11, 76, 2, 143, 238, 2, 32, 6, 25, 4, 73, 84, 72, 32, 6, 104, + 14, 77, 85, 76, 84, 73, 80, 76, 73, 67, 65, 84, 73, 79, 78, 0, 4, 80, 76, + 85, 83, 199, 143, 6, 68, 2, 225, 174, 4, 5, 32, 83, 73, 71, 78, 4, 184, + 213, 4, 2, 65, 67, 191, 209, 1, 69, 4, 60, 9, 80, 69, 78, 83, 73, 79, 78, + 32, 82, 147, 203, 6, 72, 2, 21, 3, 65, 73, 76, 2, 175, 208, 5, 87, 8, 26, + 65, 98, 73, 35, 85, 4, 44, 5, 83, 72, 32, 65, 77, 243, 221, 6, 78, 2, + 141, 154, 6, 7, 80, 69, 82, 83, 65, 78, 68, 2, 11, 77, 2, 199, 159, 6, + 77, 2, 165, 156, 3, 2, 78, 71, 236, 2, 92, 11, 76, 79, 84, 73, 32, 78, + 65, 71, 82, 73, 32, 226, 5, 77, 242, 16, 78, 97, 2, 82, 73, 90, 180, 1, + 7, 76, 69, 84, 84, 69, 82, 32, 168, 2, 11, 80, 79, 69, 84, 82, 89, 32, + 77, 65, 82, 75, 56, 5, 83, 73, 71, 78, 32, 145, 1, 11, 86, 79, 87, 69, + 76, 32, 83, 73, 71, 78, 32, 64, 174, 1, 68, 46, 82, 34, 84, 242, 90, 66, + 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 223, 5, 72, 2, 76, 2, 77, 2, 78, + 2, 83, 246, 30, 65, 2, 69, 2, 73, 2, 79, 3, 85, 8, 186, 91, 68, 138, 223, + 5, 72, 247, 30, 79, 4, 150, 186, 6, 82, 247, 30, 79, 8, 238, 90, 84, 138, + 223, 5, 72, 247, 30, 79, 8, 11, 45, 8, 178, 216, 6, 49, 2, 50, 2, 51, 3, + 52, 8, 46, 65, 70, 72, 181, 146, 6, 3, 68, 86, 73, 4, 64, 10, 76, 84, 69, + 82, 78, 65, 84, 69, 32, 72, 171, 146, 6, 78, 2, 245, 142, 2, 2, 65, 83, + 10, 130, 184, 6, 79, 246, 30, 65, 2, 69, 2, 73, 3, 85, 88, 60, 8, 66, 79, + 76, 32, 70, 79, 82, 32, 145, 16, 2, 77, 69, 86, 238, 2, 66, 48, 2, 67, + 65, 118, 68, 238, 3, 69, 130, 2, 70, 56, 8, 72, 79, 82, 73, 90, 79, 78, + 84, 0, 6, 86, 69, 82, 84, 73, 67, 44, 3, 76, 73, 78, 52, 9, 77, 65, 82, + 75, 83, 32, 67, 72, 65, 22, 78, 90, 65, 68, 3, 82, 69, 67, 32, 5, 71, 82, + 79, 85, 80, 0, 4, 85, 78, 73, 84, 22, 83, 249, 2, 15, 84, 89, 80, 69, 32, + 65, 32, 69, 76, 69, 67, 84, 82, 79, 78, 4, 230, 200, 4, 69, 241, 203, 1, + 3, 65, 67, 75, 4, 44, 3, 82, 82, 73, 129, 189, 1, 2, 78, 67, 2, 33, 6, + 65, 71, 69, 32, 82, 69, 2, 11, 84, 2, 155, 191, 1, 85, 20, 24, 2, 65, 84, + 55, 69, 2, 177, 5, 9, 65, 32, 76, 73, 78, 75, 32, 69, 83, 18, 84, 4, 76, + 69, 84, 69, 137, 2, 12, 86, 73, 67, 69, 32, 67, 79, 78, 84, 82, 79, 76, + 11, 11, 32, 8, 164, 1, 11, 82, 69, 67, 84, 65, 78, 71, 85, 76, 65, 82, 0, + 6, 83, 81, 85, 65, 82, 69, 174, 186, 4, 70, 249, 149, 1, 11, 77, 69, 68, + 73, 85, 77, 32, 83, 72, 65, 68, 2, 61, 13, 32, 67, 72, 69, 67, 75, 69, + 82, 32, 66, 79, 65, 82, 2, 239, 207, 5, 68, 8, 11, 32, 8, 226, 178, 1, + 70, 134, 169, 3, 84, 155, 87, 79, 12, 22, 78, 207, 1, 83, 10, 48, 5, 68, + 32, 79, 70, 32, 137, 1, 2, 81, 85, 8, 18, 77, 31, 84, 2, 237, 161, 5, 2, + 69, 68, 6, 64, 11, 82, 65, 78, 83, 77, 73, 83, 83, 73, 79, 78, 243, 112, + 69, 5, 167, 218, 3, 32, 2, 199, 6, 73, 2, 193, 130, 5, 2, 67, 65, 4, 36, + 2, 73, 76, 73, 3, 79, 82, 77, 2, 191, 2, 69, 2, 165, 166, 1, 6, 65, 76, + 32, 84, 65, 66, 2, 11, 69, 2, 17, 2, 32, 70, 2, 227, 182, 1, 69, 2, 219, + 144, 5, 80, 6, 26, 69, 147, 192, 4, 85, 4, 56, 8, 71, 65, 84, 73, 86, 69, + 32, 65, 183, 174, 5, 87, 2, 21, 3, 67, 75, 78, 2, 21, 3, 79, 87, 76, 2, + 231, 140, 1, 69, 2, 11, 79, 2, 17, 2, 82, 68, 2, 219, 151, 3, 32, 18, + 176, 1, 7, 65, 77, 65, 82, 73, 84, 65, 60, 3, 72, 73, 70, 52, 8, 84, 65, + 82, 84, 32, 79, 70, 32, 64, 8, 85, 66, 83, 84, 73, 84, 85, 84, 120, 3, + 89, 78, 67, 163, 136, 6, 80, 2, 25, 4, 78, 32, 83, 79, 2, 11, 85, 2, 171, + 138, 6, 82, 4, 17, 2, 84, 32, 4, 174, 205, 5, 79, 243, 41, 73, 4, 22, 72, + 239, 106, 84, 2, 17, 2, 69, 65, 2, 175, 245, 5, 68, 4, 163, 177, 4, 69, + 2, 173, 136, 6, 2, 73, 67, 2, 11, 84, 2, 155, 180, 6, 82, 7, 38, 67, 193, + 181, 2, 3, 65, 71, 79, 2, 137, 139, 1, 9, 72, 82, 79, 78, 79, 85, 83, 32, + 73, 180, 1, 36, 3, 65, 67, 32, 147, 141, 5, 78, 178, 1, 150, 3, 65, 52, + 4, 66, 65, 82, 82, 32, 2, 67, 79, 80, 13, 68, 79, 84, 84, 69, 68, 32, 90, + 76, 65, 77, 65, 32, 118, 69, 90, 72, 204, 2, 7, 76, 69, 84, 84, 69, 82, + 32, 236, 9, 9, 79, 66, 76, 73, 81, 85, 69, 32, 76, 28, 4, 80, 84, 72, 65, + 0, 4, 90, 81, 65, 80, 110, 82, 88, 2, 83, 85, 174, 2, 84, 216, 131, 5, 3, + 77, 85, 83, 224, 22, 7, 70, 69, 77, 73, 78, 73, 78, 153, 139, 1, 5, 81, + 85, 83, 72, 83, 2, 11, 66, 2, 229, 215, 5, 5, 66, 82, 69, 86, 73, 2, 11, + 69, 2, 215, 191, 6, 75, 6, 38, 78, 165, 17, 4, 76, 79, 78, 32, 2, 17, 2, + 84, 82, 2, 187, 239, 5, 65, 4, 28, 3, 65, 78, 71, 35, 72, 2, 11, 85, 2, + 155, 156, 5, 76, 2, 11, 79, 2, 185, 231, 3, 5, 82, 73, 90, 79, 78, 6, 60, + 10, 78, 68, 32, 79, 70, 32, 80, 65, 82, 65, 151, 14, 83, 2, 201, 11, 2, + 71, 82, 14, 104, 8, 65, 82, 75, 76, 69, 65, 78, 32, 132, 1, 4, 66, 65, + 83, 65, 65, 7, 79, 82, 73, 90, 79, 78, 84, 6, 60, 5, 65, 83, 84, 69, 82, + 40, 4, 77, 69, 84, 79, 3, 79, 2, 17, 2, 73, 83, 2, 147, 180, 4, 67, 2, + 213, 177, 2, 2, 66, 69, 6, 164, 11, 8, 45, 69, 83, 65, 83, 65, 32, 68, + 155, 143, 4, 32, 2, 233, 235, 5, 2, 65, 76, 92, 154, 2, 68, 102, 72, 32, + 3, 76, 65, 77, 34, 77, 204, 1, 2, 80, 69, 142, 1, 82, 78, 83, 144, 1, 8, + 70, 73, 78, 65, 76, 32, 83, 69, 106, 65, 14, 75, 2, 81, 34, 84, 40, 5, + 71, 65, 77, 65, 76, 40, 4, 89, 85, 68, 72, 190, 80, 66, 242, 178, 4, 90, + 186, 46, 78, 134, 2, 87, 175, 126, 69, 4, 76, 14, 79, 84, 76, 69, 83, 83, + 32, 68, 65, 76, 65, 84, 72, 32, 139, 3, 65, 2, 179, 212, 2, 82, 4, 11, + 69, 5, 207, 183, 6, 84, 2, 11, 65, 2, 175, 183, 6, 68, 24, 60, 9, 65, 76, + 65, 89, 65, 76, 65, 77, 32, 151, 167, 6, 73, 22, 78, 76, 22, 78, 226, + 185, 4, 66, 222, 216, 1, 84, 138, 34, 83, 14, 74, 3, 82, 4, 255, 170, 4, + 76, 8, 222, 89, 78, 242, 218, 5, 71, 3, 89, 9, 33, 6, 82, 83, 73, 65, 78, + 32, 6, 50, 66, 16, 3, 68, 72, 65, 17, 3, 71, 72, 65, 2, 175, 84, 72, 2, + 147, 2, 76, 2, 139, 170, 5, 77, 4, 52, 7, 69, 86, 69, 82, 83, 69, 68, + 151, 202, 4, 73, 2, 195, 235, 4, 32, 14, 142, 1, 69, 40, 7, 79, 71, 68, + 73, 65, 78, 32, 64, 12, 85, 80, 69, 82, 83, 67, 82, 73, 80, 84, 32, 65, + 190, 179, 5, 72, 201, 82, 2, 65, 68, 2, 17, 2, 77, 75, 2, 235, 174, 4, + 65, 6, 42, 90, 32, 2, 75, 72, 179, 156, 6, 70, 2, 187, 132, 5, 72, 2, 11, + 76, 2, 11, 65, 2, 231, 177, 6, 80, 6, 36, 3, 69, 84, 72, 159, 180, 5, 65, + 5, 149, 91, 6, 32, 71, 65, 82, 83, 72, 5, 135, 133, 6, 32, 4, 221, 143, + 4, 2, 73, 78, 6, 21, 3, 72, 65, 32, 6, 42, 68, 182, 143, 4, 66, 131, 165, + 1, 65, 2, 17, 2, 79, 84, 2, 243, 156, 1, 84, 8, 58, 66, 174, 214, 2, 87, + 249, 166, 1, 4, 85, 75, 75, 65, 4, 169, 251, 3, 2, 65, 83, 14, 88, 8, 66, + 76, 73, 78, 69, 65, 82, 32, 113, 10, 80, 82, 65, 76, 73, 78, 69, 65, 82, + 32, 8, 44, 5, 67, 79, 76, 79, 78, 227, 217, 3, 70, 7, 11, 32, 4, 29, 5, + 83, 75, 69, 87, 69, 4, 219, 131, 6, 68, 6, 44, 5, 67, 79, 76, 79, 78, + 243, 216, 3, 70, 5, 221, 251, 5, 7, 32, 83, 75, 69, 87, 69, 68, 8, 62, + 72, 25, 11, 87, 79, 32, 86, 69, 82, 84, 73, 67, 65, 76, 4, 21, 3, 82, 69, + 69, 4, 25, 4, 32, 68, 79, 84, 4, 235, 138, 4, 83, 136, 47, 102, 45, 58, + 65, 162, 111, 69, 218, 45, 72, 202, 46, 73, 254, 68, 79, 246, 37, 82, + 214, 17, 85, 147, 22, 87, 4, 32, 2, 83, 72, 203, 131, 5, 82, 2, 203, 164, + 5, 73, 200, 29, 182, 1, 66, 86, 71, 196, 17, 2, 73, 32, 142, 35, 75, 144, + 5, 9, 76, 76, 89, 32, 77, 65, 82, 75, 32, 34, 77, 178, 37, 78, 240, 12, + 3, 80, 69, 32, 94, 85, 202, 157, 5, 67, 159, 11, 88, 5, 241, 128, 1, 16, + 76, 69, 32, 84, 69, 78, 78, 73, 83, 32, 80, 65, 68, 68, 76, 69, 144, 2, + 78, 32, 240, 11, 5, 65, 76, 79, 71, 32, 241, 2, 6, 66, 65, 78, 87, 65, + 32, 190, 1, 162, 1, 65, 102, 67, 186, 1, 68, 58, 69, 98, 71, 118, 72, 46, + 76, 230, 3, 80, 58, 81, 62, 82, 106, 83, 242, 81, 78, 230, 227, 1, 84, + 162, 146, 1, 70, 179, 185, 1, 86, 6, 42, 80, 158, 212, 2, 77, 211, 187, + 1, 83, 2, 17, 2, 79, 83, 2, 237, 249, 5, 4, 84, 82, 79, 80, 8, 18, 73, + 63, 79, 2, 25, 4, 82, 67, 85, 77, 2, 213, 2, 4, 70, 76, 69, 88, 6, 26, + 77, 131, 214, 5, 76, 4, 11, 77, 4, 172, 156, 5, 7, 69, 82, 67, 73, 65, + 76, 32, 179, 137, 1, 65, 22, 26, 79, 139, 177, 4, 73, 2, 11, 76, 2, 207, + 90, 76, 4, 18, 81, 43, 88, 2, 17, 2, 85, 65, 2, 179, 242, 2, 76, 2, 245, + 186, 5, 4, 67, 76, 65, 77, 4, 11, 82, 4, 18, 65, 55, 69, 2, 11, 86, 2, + 11, 69, 2, 193, 126, 3, 32, 65, 67, 2, 145, 4, 4, 65, 84, 69, 82, 2, 153, + 152, 2, 6, 89, 80, 72, 69, 78, 45, 114, 38, 65, 254, 2, 69, 235, 180, 4, + 79, 104, 25, 4, 84, 73, 78, 32, 104, 34, 67, 41, 4, 83, 77, 65, 76, 52, + 11, 65, 52, 25, 4, 80, 73, 84, 65, 52, 41, 8, 76, 32, 76, 69, 84, 84, 69, + 82, 52, 11, 32, 52, 158, 161, 6, 65, 2, 66, 2, 67, 2, 68, 2, 69, 2, 70, + 2, 71, 2, 72, 2, 73, 2, 74, 2, 75, 2, 76, 2, 77, 2, 78, 2, 79, 2, 80, 2, + 81, 2, 82, 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, 2, 89, 3, 90, 8, 22, + 83, 199, 1, 70, 2, 11, 83, 2, 169, 69, 3, 45, 84, 72, 4, 26, 69, 211, + 236, 2, 76, 2, 11, 82, 2, 199, 73, 67, 4, 11, 85, 4, 26, 79, 215, 201, 3, + 69, 2, 239, 180, 5, 84, 8, 36, 3, 73, 71, 72, 199, 132, 4, 69, 6, 17, 2, + 84, 32, 6, 250, 146, 2, 67, 210, 3, 80, 239, 7, 83, 6, 150, 206, 2, 69, + 138, 184, 1, 79, 131, 218, 1, 80, 46, 80, 7, 76, 69, 84, 84, 69, 82, 32, + 208, 1, 5, 83, 73, 71, 78, 32, 147, 2, 86, 38, 162, 1, 65, 250, 164, 2, + 78, 206, 243, 3, 66, 2, 68, 2, 71, 2, 72, 2, 75, 2, 76, 2, 77, 2, 80, 2, + 82, 2, 83, 2, 84, 2, 87, 2, 89, 186, 2, 73, 3, 85, 5, 161, 208, 5, 6, 82, + 67, 72, 65, 73, 67, 4, 26, 80, 207, 192, 2, 86, 2, 25, 4, 65, 77, 85, 68, + 2, 235, 223, 2, 80, 36, 48, 7, 76, 69, 84, 84, 69, 82, 32, 147, 1, 86, + 32, 202, 163, 2, 78, 206, 243, 3, 66, 2, 68, 2, 71, 2, 75, 2, 76, 2, 77, + 2, 80, 2, 83, 2, 84, 2, 87, 2, 89, 186, 2, 65, 2, 73, 3, 85, 4, 41, 8, + 79, 87, 69, 76, 32, 83, 73, 71, 4, 11, 78, 4, 207, 215, 5, 32, 194, 4, + 140, 1, 10, 76, 69, 32, 76, 69, 84, 84, 69, 82, 32, 248, 2, 5, 84, 72, + 65, 77, 32, 184, 18, 5, 86, 73, 69, 84, 32, 225, 6, 3, 89, 79, 32, 70, + 186, 1, 65, 34, 69, 30, 84, 230, 158, 2, 78, 214, 172, 1, 79, 242, 129, + 2, 75, 2, 80, 162, 7, 85, 234, 61, 70, 2, 72, 2, 76, 2, 77, 2, 81, 2, 83, + 2, 86, 2, 88, 2, 89, 187, 2, 73, 7, 206, 254, 5, 85, 215, 22, 73, 7, 130, + 149, 6, 69, 3, 72, 18, 60, 3, 79, 78, 69, 234, 204, 5, 83, 138, 69, 72, + 187, 2, 65, 10, 11, 45, 10, 154, 148, 6, 50, 2, 51, 2, 52, 2, 53, 3, 54, + 254, 1, 196, 1, 2, 67, 79, 232, 3, 4, 72, 79, 82, 65, 0, 4, 84, 72, 65, + 77, 28, 7, 76, 69, 84, 84, 69, 82, 32, 220, 4, 5, 83, 73, 71, 78, 32, + 217, 5, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 20, 164, 1, 13, + 78, 83, 79, 78, 65, 78, 84, 32, 83, 73, 71, 78, 32, 197, 253, 4, 21, 77, + 66, 73, 78, 73, 78, 71, 32, 67, 82, 89, 80, 84, 79, 71, 82, 65, 77, 77, + 73, 67, 18, 148, 1, 6, 70, 73, 78, 65, 76, 32, 22, 76, 48, 16, 72, 73, + 71, 72, 32, 82, 65, 84, 72, 65, 32, 79, 82, 32, 76, 79, 22, 77, 206, 140, + 6, 66, 3, 83, 2, 151, 205, 5, 78, 4, 46, 79, 157, 26, 6, 65, 32, 84, 65, + 78, 71, 2, 167, 220, 1, 87, 6, 48, 6, 69, 68, 73, 65, 76, 32, 211, 142, + 6, 65, 4, 150, 140, 6, 76, 3, 82, 20, 169, 154, 4, 2, 32, 68, 106, 188, + 1, 2, 71, 82, 44, 5, 72, 73, 71, 72, 32, 94, 76, 222, 1, 82, 250, 178, 2, + 85, 186, 202, 1, 73, 178, 15, 78, 162, 222, 1, 79, 162, 8, 69, 158, 20, + 66, 2, 68, 2, 77, 2, 87, 187, 2, 65, 2, 21, 3, 69, 65, 84, 2, 251, 137, + 6, 32, 32, 242, 1, 75, 42, 82, 130, 194, 5, 83, 82, 67, 2, 80, 2, 84, + 138, 69, 70, 2, 72, 3, 89, 36, 60, 3, 79, 87, 32, 242, 202, 5, 65, 206, + 41, 85, 159, 20, 76, 28, 86, 75, 42, 82, 210, 194, 5, 67, 2, 80, 2, 84, + 138, 69, 70, 2, 72, 2, 83, 3, 89, 6, 254, 135, 6, 72, 2, 88, 187, 2, 65, + 2, 229, 140, 4, 2, 65, 84, 8, 26, 65, 135, 243, 5, 85, 7, 158, 135, 6, + 78, 3, 84, 50, 182, 1, 72, 34, 75, 176, 1, 4, 77, 65, 73, 32, 82, 82, + 136, 1, 2, 83, 65, 92, 5, 87, 73, 65, 78, 71, 172, 132, 1, 3, 68, 79, 75, + 224, 121, 3, 84, 79, 78, 161, 173, 3, 2, 67, 65, 4, 138, 183, 5, 65, 179, + 63, 79, 14, 52, 4, 72, 85, 69, 78, 134, 3, 65, 131, 232, 4, 69, 8, 80, 6, + 32, 84, 79, 78, 69, 45, 189, 186, 4, 8, 45, 76, 85, 69, 32, 75, 65, 82, + 6, 214, 134, 6, 51, 2, 52, 3, 53, 8, 56, 4, 75, 65, 78, 71, 246, 140, 1, + 89, 247, 187, 3, 83, 5, 167, 146, 1, 32, 4, 92, 3, 65, 32, 72, 21, 16, + 69, 86, 69, 82, 83, 69, 68, 32, 82, 79, 84, 65, 84, 69, 68, 32, 2, 243, + 199, 4, 65, 2, 139, 209, 3, 82, 8, 48, 3, 84, 75, 65, 142, 184, 4, 87, + 231, 123, 75, 4, 17, 2, 65, 78, 5, 163, 143, 4, 75, 5, 245, 202, 3, 2, + 87, 65, 38, 90, 65, 36, 4, 77, 65, 73, 32, 22, 79, 46, 84, 86, 85, 142, + 245, 3, 73, 199, 140, 2, 69, 9, 134, 131, 6, 65, 2, 69, 3, 73, 2, 179, + 249, 4, 83, 11, 186, 224, 3, 65, 150, 162, 2, 79, 3, 89, 4, 42, 65, 181, + 142, 1, 4, 72, 65, 77, 32, 2, 17, 2, 76, 76, 2, 175, 140, 4, 32, 9, 174, + 193, 5, 85, 163, 64, 69, 144, 1, 184, 1, 7, 76, 69, 84, 84, 69, 82, 32, + 188, 2, 5, 77, 65, 73, 32, 75, 32, 7, 83, 89, 77, 66, 79, 76, 32, 124, 9, 84, 79, 78, 69, 32, 77, 65, 73, 32, 81, 6, 86, 79, 87, 69, 76, 32, 96, 44, 4, 72, 73, 71, 72, 1, 3, 76, 79, 87, 48, 11, 32, 48, 154, 1, 75, 30, - 67, 2, 80, 2, 84, 34, 78, 166, 208, 5, 66, 2, 68, 2, 70, 2, 71, 2, 72, 2, - 76, 2, 77, 2, 82, 2, 83, 2, 86, 2, 89, 247, 30, 79, 6, 26, 72, 187, 239, - 5, 79, 4, 194, 208, 5, 72, 247, 30, 79, 6, 162, 208, 5, 71, 2, 89, 247, - 30, 79, 4, 246, 157, 5, 65, 195, 52, 72, 10, 68, 2, 75, 79, 106, 78, 240, - 126, 4, 72, 79, 32, 72, 183, 179, 3, 83, 4, 212, 127, 3, 73, 32, 75, 179, - 238, 4, 78, 8, 58, 78, 254, 132, 1, 84, 230, 164, 2, 83, 171, 192, 2, 69, - 2, 143, 170, 3, 85, 26, 50, 65, 58, 85, 30, 73, 134, 236, 5, 69, 3, 79, - 10, 130, 214, 5, 85, 214, 22, 65, 2, 77, 2, 78, 3, 89, 9, 26, 69, 135, - 236, 5, 65, 5, 131, 236, 5, 65, 138, 1, 52, 3, 82, 73, 32, 237, 222, 4, - 4, 69, 79, 85, 84, 136, 1, 82, 65, 20, 7, 76, 69, 84, 84, 69, 82, 32, - 166, 2, 83, 78, 86, 187, 246, 3, 68, 2, 195, 211, 1, 66, 88, 210, 1, 65, - 250, 142, 2, 68, 82, 82, 34, 84, 230, 5, 85, 206, 201, 1, 73, 162, 193, - 1, 78, 126, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 2, 83, 138, 69, 72, 2, - 76, 2, 77, 2, 86, 2, 89, 186, 2, 69, 3, 79, 11, 172, 185, 3, 7, 82, 67, - 72, 65, 73, 67, 32, 198, 175, 2, 65, 2, 73, 3, 85, 8, 25, 4, 73, 71, 78, - 32, 8, 166, 212, 1, 78, 234, 206, 3, 65, 239, 1, 86, 18, 49, 10, 79, 87, - 69, 76, 32, 83, 73, 71, 78, 32, 18, 214, 147, 2, 65, 38, 85, 206, 201, 1, - 73, 222, 137, 2, 69, 3, 79, 4, 154, 51, 70, 155, 154, 4, 79, 188, 6, 36, - 3, 73, 76, 32, 239, 193, 4, 65, 186, 6, 154, 3, 65, 106, 67, 194, 2, 68, - 72, 3, 87, 69, 84, 48, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 232, 7, 9, - 73, 78, 32, 80, 79, 83, 83, 69, 83, 22, 76, 200, 2, 7, 78, 85, 77, 66, - 69, 82, 32, 152, 1, 18, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, - 69, 78, 68, 32, 79, 70, 54, 82, 42, 83, 166, 14, 84, 228, 1, 7, 86, 79, - 87, 69, 76, 32, 83, 100, 2, 89, 69, 176, 186, 4, 5, 77, 79, 78, 84, 72, - 171, 118, 79, 6, 80, 5, 83, 32, 65, 66, 79, 242, 132, 2, 85, 217, 244, 1, - 5, 78, 68, 32, 79, 68, 2, 243, 197, 3, 86, 52, 80, 9, 79, 78, 83, 79, 78, - 65, 78, 84, 32, 156, 21, 3, 85, 82, 82, 171, 9, 82, 48, 130, 1, 75, 22, - 76, 22, 78, 46, 84, 218, 191, 1, 83, 194, 77, 82, 202, 210, 3, 67, 2, 72, - 2, 74, 2, 77, 2, 80, 2, 86, 3, 89, 5, 215, 162, 5, 83, 7, 243, 227, 4, - 76, 11, 134, 229, 3, 78, 134, 251, 1, 71, 3, 89, 5, 223, 223, 5, 84, 26, - 68, 2, 82, 89, 164, 28, 2, 69, 66, 238, 143, 2, 65, 227, 193, 1, 73, 2, - 137, 200, 1, 7, 32, 67, 85, 76, 84, 73, 86, 42, 168, 1, 4, 79, 78, 69, - 32, 220, 4, 6, 84, 72, 82, 69, 69, 32, 177, 215, 5, 22, 68, 79, 87, 78, - 83, 67, 65, 76, 73, 78, 71, 32, 70, 65, 67, 84, 79, 82, 32, 75, 73, 73, - 30, 112, 5, 69, 73, 71, 72, 84, 34, 70, 40, 3, 72, 65, 76, 22, 79, 88, 4, - 83, 73, 88, 84, 74, 84, 187, 215, 3, 81, 4, 210, 3, 73, 227, 216, 5, 72, - 4, 156, 3, 2, 79, 82, 187, 213, 3, 73, 4, 215, 218, 1, 70, 2, 225, 2, 18, - 78, 69, 45, 72, 85, 78, 68, 82, 69, 68, 45, 65, 78, 68, 45, 83, 73, 88, - 6, 232, 217, 1, 5, 69, 69, 78, 84, 72, 177, 24, 5, 89, 45, 70, 79, 85, 8, - 38, 72, 138, 1, 87, 239, 214, 3, 69, 4, 132, 1, 18, 82, 69, 69, 45, 72, - 85, 78, 68, 82, 69, 68, 45, 65, 78, 68, 45, 84, 87, 201, 156, 4, 8, 73, - 82, 84, 89, 45, 83, 69, 67, 2, 17, 2, 69, 78, 2, 17, 2, 84, 73, 2, 207, - 214, 3, 69, 10, 58, 69, 28, 4, 83, 73, 88, 84, 82, 84, 163, 214, 3, 81, - 2, 129, 1, 3, 73, 71, 72, 4, 50, 69, 149, 215, 3, 6, 89, 45, 70, 79, 85, - 82, 2, 145, 215, 3, 2, 69, 78, 2, 21, 3, 87, 69, 78, 2, 221, 214, 3, 3, - 84, 73, 69, 2, 171, 214, 1, 83, 72, 48, 6, 69, 84, 84, 69, 82, 32, 195, - 237, 3, 65, 70, 194, 1, 78, 158, 201, 1, 84, 166, 49, 65, 82, 76, 38, 82, - 134, 6, 85, 202, 141, 1, 79, 134, 60, 73, 206, 193, 1, 83, 242, 7, 69, - 234, 61, 67, 2, 72, 2, 74, 2, 75, 2, 77, 2, 80, 2, 86, 3, 89, 10, 46, 78, - 250, 209, 5, 71, 2, 89, 187, 2, 65, 4, 246, 209, 5, 78, 187, 2, 65, 8, - 38, 79, 130, 128, 4, 84, 131, 77, 83, 4, 11, 78, 4, 17, 2, 69, 32, 4, 18, - 72, 31, 84, 2, 217, 71, 3, 85, 78, 68, 2, 149, 132, 2, 3, 72, 79, 85, 2, - 17, 2, 32, 84, 2, 11, 69, 2, 171, 182, 5, 88, 2, 17, 2, 85, 80, 2, 131, - 182, 3, 69, 194, 4, 152, 1, 5, 65, 76, 84, 32, 80, 20, 4, 73, 71, 78, 32, - 206, 4, 80, 28, 9, 84, 65, 82, 84, 73, 78, 71, 32, 70, 41, 8, 89, 76, 76, - 65, 66, 76, 69, 32, 2, 219, 215, 3, 65, 40, 90, 65, 48, 3, 67, 69, 86, - 34, 75, 80, 2, 77, 85, 102, 85, 14, 80, 118, 86, 167, 64, 78, 4, 216, 2, - 4, 65, 90, 72, 65, 199, 136, 5, 78, 2, 11, 73, 2, 231, 170, 5, 84, 6, 38, - 85, 173, 170, 5, 3, 65, 65, 67, 4, 18, 90, 87, 82, 2, 167, 187, 5, 72, 6, - 60, 4, 75, 75, 85, 82, 16, 2, 84, 72, 21, 3, 85, 86, 85, 2, 167, 82, 85, - 2, 251, 149, 3, 65, 2, 75, 90, 8, 26, 65, 131, 254, 4, 79, 6, 34, 84, - 182, 146, 4, 65, 15, 78, 2, 11, 72, 2, 17, 2, 65, 75, 2, 179, 168, 5, 75, - 10, 38, 65, 214, 81, 69, 143, 184, 4, 73, 4, 180, 102, 3, 82, 65, 65, - 221, 243, 2, 6, 75, 65, 73, 89, 65, 82, 2, 11, 69, 2, 187, 9, 78, 2, 17, - 2, 82, 79, 2, 235, 196, 4, 77, 148, 4, 130, 1, 75, 166, 1, 76, 166, 1, - 78, 186, 1, 82, 86, 83, 178, 1, 84, 214, 2, 67, 2, 72, 2, 74, 2, 77, 2, - 80, 2, 86, 3, 89, 46, 84, 2, 83, 83, 174, 246, 1, 65, 38, 85, 202, 141, - 1, 79, 134, 60, 73, 191, 201, 1, 69, 24, 214, 239, 1, 65, 250, 6, 85, - 202, 141, 1, 79, 134, 60, 73, 191, 201, 1, 69, 66, 78, 76, 146, 245, 1, - 65, 38, 85, 202, 141, 1, 79, 134, 60, 73, 191, 201, 1, 69, 44, 226, 6, - 76, 174, 238, 1, 65, 38, 85, 202, 141, 1, 79, 134, 60, 73, 191, 201, 1, - 69, 110, 98, 78, 174, 5, 71, 2, 89, 174, 238, 1, 65, 38, 85, 202, 141, 1, - 79, 134, 60, 73, 191, 201, 1, 69, 44, 170, 5, 78, 174, 238, 1, 65, 38, - 85, 202, 141, 1, 79, 134, 60, 73, 191, 201, 1, 69, 44, 214, 4, 82, 174, - 238, 1, 65, 38, 85, 202, 141, 1, 79, 134, 60, 73, 191, 201, 1, 69, 68, - 90, 72, 170, 3, 83, 174, 238, 1, 65, 38, 85, 202, 141, 1, 79, 134, 60, - 73, 191, 201, 1, 69, 24, 210, 241, 1, 65, 38, 85, 202, 141, 1, 79, 230, - 2, 82, 162, 57, 73, 191, 201, 1, 69, 44, 210, 2, 84, 174, 238, 1, 65, 38, - 85, 202, 141, 1, 79, 134, 60, 73, 191, 201, 1, 69, 6, 68, 2, 79, 84, 33, - 11, 82, 65, 68, 73, 84, 73, 79, 78, 65, 76, 32, 2, 11, 65, 2, 163, 188, - 4, 76, 4, 24, 2, 67, 82, 55, 78, 2, 17, 2, 69, 68, 2, 11, 73, 2, 211, - 187, 4, 84, 2, 11, 85, 2, 17, 2, 77, 66, 2, 123, 69, 22, 25, 4, 73, 71, - 78, 32, 22, 170, 238, 1, 65, 38, 85, 202, 141, 1, 79, 134, 60, 73, 191, - 201, 1, 69, 2, 11, 65, 2, 163, 186, 4, 82, 184, 13, 36, 5, 65, 66, 65, - 84, 65, 35, 71, 2, 11, 32, 2, 147, 209, 3, 84, 182, 13, 54, 69, 20, 3, - 83, 65, 32, 217, 6, 3, 85, 84, 32, 2, 207, 166, 4, 82, 178, 1, 52, 7, 76, - 69, 84, 84, 69, 82, 32, 155, 206, 3, 68, 158, 1, 210, 1, 65, 58, 70, 54, - 72, 38, 76, 58, 77, 54, 78, 50, 83, 126, 85, 114, 69, 2, 73, 2, 79, 2, - 86, 186, 241, 4, 84, 82, 67, 2, 68, 2, 71, 2, 75, 2, 80, 138, 69, 66, 2, - 82, 2, 87, 2, 88, 2, 89, 3, 90, 16, 150, 4, 87, 202, 185, 5, 67, 2, 81, - 2, 88, 3, 90, 4, 172, 236, 4, 5, 73, 78, 65, 76, 32, 251, 80, 65, 6, 174, - 177, 1, 84, 199, 139, 4, 65, 4, 204, 150, 4, 5, 79, 78, 71, 32, 85, 131, - 166, 1, 65, 10, 150, 188, 5, 65, 2, 67, 2, 81, 2, 88, 3, 90, 8, 170, 185, - 5, 71, 2, 72, 2, 89, 187, 2, 65, 8, 26, 72, 155, 187, 5, 65, 6, 40, 4, - 79, 82, 84, 32, 239, 186, 5, 65, 4, 188, 151, 1, 2, 85, 69, 137, 151, 3, - 2, 65, 87, 32, 58, 73, 54, 69, 202, 185, 5, 67, 2, 81, 2, 88, 3, 90, 16, - 50, 85, 202, 185, 5, 67, 2, 81, 2, 88, 3, 90, 8, 198, 185, 5, 67, 2, 81, - 2, 88, 3, 90, 130, 12, 64, 10, 67, 79, 77, 80, 79, 78, 69, 78, 84, 45, - 143, 150, 3, 73, 128, 12, 70, 48, 178, 1, 49, 2, 50, 2, 51, 2, 52, 2, 53, - 2, 54, 95, 55, 198, 1, 86, 48, 242, 1, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, - 54, 2, 55, 2, 56, 3, 57, 18, 170, 183, 5, 49, 2, 50, 2, 51, 2, 52, 2, 53, - 2, 54, 2, 55, 2, 56, 3, 57, 200, 1, 150, 1, 48, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 138, 1, 58, 48, 2, 49, 2, 50, 2, - 51, 2, 52, 2, 53, 95, 54, 20, 186, 181, 5, 48, 2, 49, 2, 50, 2, 51, 2, - 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 18, 222, 180, 5, 48, 2, 49, 2, 50, - 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 3, 56, 4, 48, 6, 67, 65, 82, 84, 82, - 73, 21, 2, 68, 82, 2, 183, 254, 3, 68, 2, 239, 182, 4, 73, 2, 179, 173, - 3, 82, 142, 3, 154, 1, 65, 152, 2, 5, 68, 68, 89, 32, 66, 22, 76, 166, - 14, 78, 144, 1, 5, 83, 84, 32, 84, 85, 21, 12, 84, 82, 65, 71, 82, 65, - 77, 32, 70, 79, 82, 32, 10, 68, 9, 67, 85, 80, 32, 87, 73, 84, 72, 79, - 58, 82, 199, 224, 4, 80, 2, 33, 6, 85, 84, 32, 72, 65, 78, 2, 231, 140, - 4, 68, 6, 72, 9, 45, 79, 70, 70, 32, 67, 65, 76, 69, 29, 5, 68, 82, 79, - 80, 45, 2, 245, 142, 4, 2, 78, 68, 4, 250, 155, 3, 83, 245, 115, 4, 66, - 65, 82, 66, 2, 171, 142, 4, 69, 216, 1, 38, 69, 213, 2, 4, 85, 71, 85, - 32, 16, 60, 6, 80, 72, 79, 78, 69, 32, 246, 1, 83, 151, 179, 2, 86, 12, - 132, 1, 3, 82, 69, 67, 228, 150, 1, 3, 76, 79, 67, 146, 144, 3, 83, 189, - 116, 13, 79, 78, 32, 84, 79, 80, 32, 79, 70, 32, 77, 79, 68, 6, 36, 5, - 69, 73, 86, 69, 82, 51, 79, 5, 29, 5, 32, 87, 73, 84, 72, 2, 179, 38, 32, - 2, 255, 140, 3, 82, 2, 11, 67, 2, 167, 229, 3, 79, 200, 1, 162, 1, 65, - 20, 15, 70, 82, 65, 67, 84, 73, 79, 78, 32, 68, 73, 71, 73, 84, 32, 164, - 2, 2, 76, 69, 252, 3, 5, 83, 73, 71, 78, 32, 198, 2, 86, 147, 177, 3, 68, - 2, 247, 205, 1, 73, 14, 74, 84, 40, 2, 79, 78, 81, 10, 90, 69, 82, 79, - 32, 70, 79, 82, 32, 79, 8, 36, 3, 72, 82, 69, 13, 2, 87, 79, 4, 11, 69, - 4, 29, 5, 32, 70, 79, 82, 32, 4, 34, 79, 21, 4, 69, 86, 69, 78, 2, 17, 2, - 68, 68, 2, 49, 10, 32, 80, 79, 87, 69, 82, 83, 32, 79, 70, 2, 133, 22, 2, - 32, 70, 114, 44, 5, 84, 84, 69, 82, 32, 219, 230, 4, 78, 112, 214, 1, 68, - 54, 78, 106, 82, 38, 84, 138, 203, 1, 65, 82, 76, 114, 86, 186, 5, 85, - 202, 141, 1, 79, 134, 60, 73, 206, 193, 1, 83, 82, 66, 2, 67, 2, 71, 2, - 74, 2, 75, 2, 80, 162, 7, 69, 234, 61, 72, 2, 77, 3, 89, 10, 166, 223, 4, - 68, 138, 69, 72, 2, 90, 187, 2, 65, 10, 42, 65, 210, 163, 5, 71, 2, 78, - 3, 89, 5, 41, 8, 75, 65, 65, 82, 65, 32, 80, 79, 2, 131, 37, 76, 6, 158, - 204, 1, 82, 175, 217, 3, 65, 10, 230, 221, 4, 84, 138, 69, 72, 2, 83, - 187, 2, 65, 20, 86, 67, 194, 1, 83, 212, 35, 3, 84, 85, 85, 170, 107, 78, - 242, 60, 65, 231, 147, 3, 86, 6, 60, 9, 79, 77, 66, 73, 78, 73, 78, 71, - 32, 171, 143, 1, 65, 4, 70, 65, 145, 166, 4, 11, 67, 65, 78, 68, 82, 65, - 66, 73, 78, 68, 85, 2, 33, 6, 78, 85, 83, 86, 65, 82, 2, 235, 165, 4, 65, - 2, 11, 73, 2, 209, 231, 3, 3, 68, 68, 72, 30, 49, 10, 79, 87, 69, 76, 32, - 83, 73, 71, 78, 32, 30, 174, 206, 1, 65, 38, 85, 22, 86, 182, 141, 1, 79, - 134, 60, 73, 191, 201, 1, 69, 6, 80, 10, 78, 73, 83, 32, 82, 65, 67, 81, - 85, 69, 174, 132, 3, 71, 175, 156, 2, 84, 2, 11, 84, 2, 25, 4, 32, 65, - 78, 68, 2, 215, 152, 3, 32, 2, 199, 137, 5, 66, 162, 1, 210, 2, 65, 134, - 1, 66, 174, 1, 67, 222, 2, 68, 202, 3, 69, 154, 2, 70, 182, 1, 71, 198, - 1, 72, 64, 8, 89, 79, 85, 84, 72, 70, 85, 76, 52, 2, 73, 78, 46, 75, 98, - 76, 146, 1, 77, 134, 1, 79, 62, 80, 142, 1, 82, 210, 1, 83, 224, 1, 14, - 86, 65, 83, 84, 78, 69, 83, 83, 32, 79, 82, 32, 87, 65, 12, 2, 87, 65, - 154, 94, 85, 203, 150, 4, 74, 8, 88, 4, 67, 67, 85, 77, 22, 83, 228, 20, - 2, 68, 86, 229, 197, 1, 5, 71, 71, 82, 65, 86, 2, 239, 185, 1, 85, 2, - 151, 217, 4, 67, 6, 92, 7, 79, 76, 68, 32, 82, 69, 83, 32, 5, 82, 65, 78, - 67, 72, 177, 146, 4, 3, 65, 82, 82, 2, 249, 202, 4, 3, 79, 76, 85, 2, 11, - 73, 2, 213, 166, 1, 3, 78, 71, 32, 22, 54, 72, 20, 3, 76, 79, 83, 66, 79, - 175, 152, 2, 69, 2, 155, 229, 3, 65, 6, 26, 69, 227, 249, 3, 85, 4, 230, - 248, 1, 68, 215, 138, 2, 78, 12, 28, 3, 77, 80, 76, 35, 78, 4, 246, 17, - 73, 143, 183, 4, 69, 8, 32, 4, 83, 84, 65, 78, 23, 84, 2, 199, 135, 5, - 67, 6, 46, 69, 20, 3, 82, 65, 82, 203, 137, 4, 65, 2, 251, 199, 4, 78, 2, - 183, 170, 3, 73, 20, 80, 4, 65, 82, 75, 69, 22, 69, 210, 1, 73, 74, 85, - 249, 248, 4, 3, 79, 85, 66, 2, 203, 198, 4, 78, 6, 132, 1, 19, 70, 69, - 67, 84, 73, 86, 69, 78, 69, 83, 83, 32, 79, 82, 32, 68, 73, 83, 84, 34, - 80, 137, 7, 6, 67, 73, 83, 73, 86, 69, 2, 11, 79, 2, 215, 197, 4, 82, 2, - 11, 65, 2, 11, 82, 2, 143, 10, 84, 8, 68, 6, 70, 70, 73, 67, 85, 76, 34, - 77, 161, 12, 4, 86, 69, 82, 71, 2, 11, 84, 2, 159, 129, 4, 73, 4, 140, 1, - 2, 73, 78, 243, 194, 4, 77, 14, 100, 5, 77, 66, 69, 76, 76, 34, 78, 124, - 4, 88, 72, 65, 85, 188, 106, 3, 84, 69, 82, 147, 159, 3, 65, 2, 189, 208, - 4, 3, 73, 83, 72, 6, 80, 4, 68, 69, 65, 86, 20, 4, 76, 65, 82, 71, 129, - 146, 3, 4, 67, 79, 85, 78, 2, 171, 154, 4, 79, 2, 183, 207, 4, 69, 2, - 135, 194, 4, 83, 12, 70, 79, 76, 3, 85, 76, 76, 196, 5, 3, 65, 73, 76, - 159, 225, 4, 76, 4, 18, 76, 35, 83, 2, 225, 192, 4, 3, 76, 79, 87, 2, - 205, 4, 2, 84, 69, 4, 166, 191, 3, 32, 175, 59, 78, 10, 96, 8, 65, 84, - 72, 69, 82, 73, 78, 71, 22, 79, 64, 3, 82, 69, 65, 65, 5, 85, 65, 82, 68, - 69, 5, 215, 144, 4, 32, 2, 41, 8, 73, 78, 71, 32, 84, 79, 32, 77, 2, 211, - 218, 4, 69, 2, 75, 84, 4, 48, 2, 65, 82, 33, 6, 79, 76, 68, 73, 78, 71, - 2, 11, 68, 2, 175, 248, 3, 78, 2, 11, 32, 2, 235, 243, 1, 66, 4, 26, 67, - 211, 208, 4, 78, 2, 143, 5, 82, 4, 60, 7, 69, 69, 80, 73, 78, 71, 32, - 221, 184, 4, 2, 73, 78, 2, 11, 83, 2, 147, 134, 3, 77, 6, 18, 65, 107, - 69, 4, 60, 3, 66, 79, 85, 21, 8, 87, 32, 79, 82, 32, 77, 79, 68, 2, 243, - 187, 4, 82, 2, 175, 131, 4, 69, 2, 139, 188, 4, 71, 6, 26, 65, 30, 69, - 47, 73, 2, 153, 187, 4, 2, 83, 83, 2, 11, 65, 2, 11, 83, 2, 179, 235, 3, - 85, 2, 11, 82, 2, 171, 197, 4, 69, 4, 164, 203, 3, 7, 78, 32, 84, 72, 69, - 32, 86, 179, 110, 80, 8, 54, 65, 64, 4, 69, 78, 69, 84, 245, 97, 2, 85, - 82, 4, 22, 84, 243, 2, 67, 2, 17, 2, 84, 69, 2, 183, 186, 4, 82, 2, 139, - 200, 1, 82, 12, 30, 69, 157, 1, 2, 73, 84, 10, 34, 76, 22, 83, 243, 230, - 4, 65, 2, 227, 227, 1, 69, 6, 18, 73, 51, 80, 4, 30, 68, 137, 1, 2, 83, - 84, 2, 147, 1, 69, 2, 11, 79, 2, 187, 255, 3, 78, 2, 243, 254, 3, 85, 10, - 34, 69, 64, 2, 73, 78, 23, 84, 2, 11, 86, 2, 17, 2, 69, 82, 2, 11, 65, 2, - 211, 202, 4, 78, 2, 183, 182, 4, 75, 6, 42, 79, 237, 132, 3, 4, 82, 69, - 78, 71, 4, 26, 80, 143, 240, 4, 86, 2, 11, 80, 2, 179, 209, 3, 65, 2, 39, - 83, 4, 26, 73, 243, 227, 4, 84, 2, 147, 181, 4, 84, 224, 2, 86, 65, 180, - 31, 2, 69, 82, 246, 1, 73, 206, 1, 79, 100, 3, 82, 69, 69, 187, 8, 85, - 146, 2, 44, 4, 65, 78, 65, 32, 145, 10, 2, 73, 32, 100, 122, 65, 38, 69, - 76, 7, 76, 69, 84, 84, 69, 82, 32, 154, 7, 79, 76, 3, 73, 66, 73, 0, 3, - 85, 66, 85, 45, 2, 83, 85, 4, 184, 8, 3, 65, 66, 65, 3, 66, 6, 58, 66, 0, - 3, 69, 66, 69, 245, 7, 4, 89, 66, 69, 89, 2, 243, 7, 69, 78, 202, 1, 65, - 42, 68, 82, 70, 2, 81, 14, 71, 50, 72, 38, 75, 62, 76, 32, 3, 77, 69, 69, - 20, 2, 67, 72, 2, 74, 2, 80, 18, 78, 42, 83, 94, 84, 102, 86, 2, 87, 42, - 90, 138, 138, 3, 66, 2, 82, 3, 89, 4, 252, 1, 2, 76, 73, 203, 218, 4, 73, - 6, 30, 65, 29, 3, 72, 65, 65, 4, 218, 2, 65, 255, 1, 86, 2, 239, 219, 4, - 76, 2, 123, 65, 6, 110, 65, 86, 78, 129, 218, 4, 3, 72, 65, 73, 4, 186, - 141, 3, 72, 151, 240, 1, 65, 4, 26, 65, 255, 140, 3, 72, 2, 11, 65, 2, - 211, 218, 4, 70, 4, 18, 65, 35, 72, 2, 11, 65, 2, 159, 218, 4, 77, 2, - 211, 1, 65, 4, 236, 217, 4, 2, 79, 79, 191, 34, 65, 8, 32, 2, 65, 65, 18, - 72, 23, 69, 2, 163, 16, 68, 4, 18, 69, 87, 65, 2, 255, 216, 4, 69, 10, - 62, 65, 16, 3, 72, 65, 65, 198, 138, 3, 84, 207, 242, 1, 79, 2, 131, 1, - 86, 5, 167, 216, 4, 76, 2, 17, 2, 65, 65, 2, 255, 215, 4, 86, 6, 26, 65, - 187, 252, 4, 79, 4, 26, 86, 159, 252, 4, 65, 2, 21, 3, 73, 89, 65, 2, - 171, 232, 4, 78, 6, 48, 3, 65, 66, 79, 14, 66, 1, 3, 79, 66, 79, 2, 23, - 65, 2, 11, 79, 2, 11, 70, 2, 11, 73, 2, 179, 231, 4, 76, 2, 199, 250, 3, - 75, 174, 1, 26, 67, 167, 137, 3, 68, 154, 1, 132, 1, 9, 72, 65, 82, 65, - 67, 84, 69, 82, 32, 129, 207, 4, 17, 85, 82, 82, 69, 78, 67, 89, 32, 83, - 89, 77, 66, 79, 76, 32, 66, 65, 152, 1, 176, 2, 6, 66, 79, 32, 66, 65, - 73, 16, 6, 67, 72, 79, 32, 67, 72, 56, 3, 68, 79, 32, 44, 2, 70, 79, 76, - 3, 72, 79, 32, 66, 75, 190, 1, 76, 138, 1, 77, 252, 1, 7, 65, 78, 71, 75, - 72, 65, 78, 46, 78, 158, 1, 80, 234, 1, 82, 70, 83, 238, 2, 84, 224, 2, - 3, 87, 79, 32, 34, 89, 141, 142, 4, 2, 79, 32, 2, 143, 12, 77, 8, 212, - 251, 2, 2, 65, 78, 162, 170, 1, 73, 167, 58, 79, 4, 176, 209, 4, 3, 67, - 72, 65, 227, 33, 68, 6, 32, 2, 32, 70, 21, 2, 78, 71, 4, 227, 250, 2, 65, - 2, 211, 171, 3, 77, 4, 40, 4, 78, 79, 75, 72, 235, 243, 4, 72, 2, 251, - 241, 4, 85, 14, 40, 2, 72, 79, 229, 9, 3, 79, 32, 75, 12, 26, 32, 235, - 250, 3, 77, 10, 36, 2, 75, 72, 57, 3, 82, 65, 75, 8, 158, 9, 87, 138, - 215, 3, 85, 138, 68, 79, 139, 60, 65, 2, 131, 155, 4, 72, 8, 76, 2, 79, - 32, 224, 11, 8, 65, 75, 75, 72, 65, 78, 71, 89, 151, 231, 4, 85, 4, 32, - 2, 67, 72, 207, 161, 4, 76, 2, 183, 208, 4, 85, 16, 28, 2, 65, 73, 219, - 52, 79, 14, 42, 32, 176, 1, 3, 84, 65, 73, 19, 89, 10, 76, 4, 67, 72, 65, - 84, 44, 5, 72, 65, 78, 45, 65, 22, 84, 203, 237, 4, 69, 2, 11, 84, 2, 11, - 65, 2, 207, 238, 4, 87, 2, 139, 221, 3, 75, 4, 234, 209, 4, 72, 159, 11, - 82, 2, 203, 2, 75, 2, 205, 198, 4, 2, 65, 77, 8, 60, 3, 71, 79, 32, 32, - 3, 73, 75, 72, 29, 3, 79, 32, 78, 2, 11, 78, 2, 223, 202, 4, 71, 2, 249, - 210, 4, 2, 65, 72, 4, 182, 159, 4, 69, 227, 79, 85, 12, 68, 6, 65, 73, - 89, 65, 78, 78, 22, 72, 133, 204, 4, 3, 79, 32, 80, 2, 215, 218, 4, 79, - 8, 36, 3, 73, 78, 84, 21, 2, 79, 32, 2, 139, 201, 4, 72, 6, 44, 2, 80, - 72, 161, 5, 4, 83, 65, 77, 80, 4, 182, 156, 4, 85, 155, 1, 65, 4, 32, 2, - 79, 32, 239, 236, 4, 85, 2, 11, 82, 2, 167, 234, 4, 85, 36, 44, 4, 65, - 82, 65, 32, 225, 1, 2, 79, 32, 28, 62, 65, 130, 1, 85, 130, 225, 2, 73, - 222, 137, 2, 69, 3, 79, 13, 64, 6, 73, 32, 77, 65, 73, 77, 154, 235, 4, - 65, 2, 69, 3, 77, 4, 26, 65, 255, 160, 3, 85, 2, 11, 76, 2, 151, 215, 4, - 65, 9, 186, 170, 4, 69, 163, 64, 85, 8, 24, 2, 82, 85, 23, 83, 2, 199, - 214, 4, 83, 6, 242, 199, 4, 65, 226, 31, 85, 187, 2, 79, 18, 30, 72, 133, - 2, 2, 79, 32, 14, 48, 6, 65, 78, 84, 72, 65, 75, 21, 2, 79, 32, 2, 163, - 213, 3, 72, 12, 80, 8, 78, 65, 78, 71, 77, 79, 78, 84, 20, 4, 80, 72, 85, - 84, 13, 2, 84, 72, 2, 175, 201, 4, 72, 2, 123, 72, 8, 34, 65, 234, 150, - 4, 79, 3, 85, 4, 222, 157, 3, 72, 131, 202, 1, 78, 4, 38, 84, 209, 177, - 2, 3, 80, 65, 84, 2, 159, 200, 4, 65, 2, 11, 87, 2, 139, 147, 3, 65, 6, - 30, 65, 45, 3, 79, 32, 89, 2, 21, 3, 77, 65, 75, 2, 167, 156, 3, 75, 4, - 154, 149, 4, 73, 227, 77, 65, 10, 30, 69, 145, 1, 2, 77, 79, 6, 18, 32, - 107, 70, 4, 84, 11, 68, 79, 69, 83, 32, 78, 79, 84, 32, 69, 88, 189, 208, - 3, 4, 69, 88, 73, 83, 2, 235, 122, 73, 2, 159, 196, 3, 79, 4, 46, 77, - 141, 188, 3, 5, 68, 89, 78, 65, 77, 2, 155, 172, 3, 69, 10, 18, 78, 95, - 82, 8, 26, 32, 179, 219, 3, 75, 6, 26, 83, 251, 218, 2, 71, 4, 206, 206, - 2, 65, 223, 215, 1, 80, 2, 21, 3, 68, 32, 80, 2, 25, 4, 76, 65, 67, 69, - 2, 17, 2, 32, 77, 2, 131, 207, 3, 69, 4, 56, 4, 85, 71, 72, 84, 161, 206, - 3, 4, 78, 71, 32, 83, 2, 161, 187, 1, 5, 32, 66, 65, 76, 76, 46, 22, 32, - 207, 3, 45, 30, 154, 1, 68, 90, 76, 118, 82, 198, 153, 1, 66, 86, 67, - 194, 6, 83, 134, 167, 1, 80, 137, 22, 15, 78, 69, 84, 87, 79, 82, 75, 69, - 68, 32, 67, 79, 77, 80, 85, 4, 64, 10, 73, 77, 69, 78, 83, 73, 79, 78, - 65, 76, 163, 157, 1, 79, 2, 139, 187, 3, 32, 6, 80, 12, 73, 78, 69, 83, - 32, 67, 79, 78, 86, 69, 82, 71, 149, 150, 1, 2, 69, 70, 4, 225, 179, 4, - 3, 73, 78, 71, 10, 40, 4, 65, 89, 83, 32, 183, 149, 1, 73, 8, 146, 192, - 2, 66, 166, 161, 1, 65, 130, 82, 76, 31, 82, 16, 44, 2, 68, 32, 254, 3, - 80, 147, 156, 1, 69, 12, 196, 2, 12, 84, 79, 80, 45, 76, 73, 71, 72, 84, - 69, 68, 32, 80, 17, 76, 69, 70, 84, 45, 76, 73, 71, 72, 84, 69, 68, 32, - 68, 79, 87, 78, 0, 16, 82, 73, 71, 72, 84, 45, 76, 73, 71, 72, 84, 69, - 68, 32, 85, 80, 245, 132, 2, 25, 66, 79, 84, 84, 79, 77, 45, 76, 73, 71, - 72, 84, 69, 68, 32, 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 6, 76, 4, 76, - 69, 70, 84, 69, 11, 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 2, 11, - 87, 2, 25, 4, 65, 82, 68, 83, 2, 197, 238, 1, 2, 32, 69, 4, 170, 238, 1, - 69, 159, 22, 65, 2, 249, 154, 4, 5, 69, 82, 45, 69, 77, 8, 34, 77, 85, 4, - 78, 68, 69, 82, 4, 21, 3, 66, 83, 32, 4, 38, 85, 149, 223, 2, 3, 68, 79, - 87, 2, 179, 209, 3, 80, 4, 180, 171, 3, 10, 32, 67, 76, 79, 85, 68, 32, - 65, 78, 68, 161, 46, 2, 83, 84, 230, 5, 204, 1, 6, 66, 69, 84, 65, 78, - 32, 184, 45, 6, 69, 32, 79, 86, 69, 82, 72, 7, 70, 73, 78, 65, 71, 72, - 32, 150, 9, 71, 152, 1, 3, 76, 68, 69, 252, 2, 2, 77, 69, 56, 2, 78, 89, - 78, 82, 139, 199, 3, 67, 160, 3, 228, 2, 18, 65, 83, 84, 82, 79, 76, 79, - 71, 73, 67, 65, 76, 32, 83, 73, 71, 78, 32, 172, 1, 18, 67, 65, 78, 84, - 73, 76, 76, 65, 84, 73, 79, 78, 32, 83, 73, 71, 78, 32, 208, 1, 6, 68, - 73, 71, 73, 84, 32, 100, 9, 75, 85, 32, 82, 85, 32, 75, 72, 65, 26, 76, - 176, 3, 5, 77, 65, 82, 75, 32, 222, 18, 83, 181, 15, 11, 86, 79, 87, 69, - 76, 32, 83, 73, 71, 78, 32, 6, 46, 83, 205, 40, 6, 45, 75, 72, 89, 85, - 68, 4, 104, 8, 68, 79, 78, 71, 32, 84, 83, 72, 205, 21, 13, 71, 82, 65, - 32, 71, 67, 65, 78, 32, 45, 67, 72, 65, 2, 235, 31, 85, 8, 144, 1, 5, 72, - 69, 65, 86, 89, 0, 5, 76, 73, 71, 72, 84, 40, 7, 83, 66, 85, 66, 32, 45, - 67, 193, 171, 4, 8, 67, 65, 78, 71, 32, 84, 69, 45, 2, 17, 2, 32, 66, 2, - 211, 188, 3, 69, 2, 231, 198, 3, 72, 40, 156, 223, 2, 4, 72, 65, 76, 70, - 82, 70, 30, 83, 42, 84, 62, 90, 238, 85, 78, 14, 79, 223, 110, 69, 5, - 221, 10, 2, 32, 66, 92, 96, 6, 69, 84, 84, 69, 82, 32, 153, 2, 13, 79, - 71, 79, 84, 89, 80, 69, 32, 83, 73, 71, 78, 32, 88, 230, 1, 75, 162, 115, - 82, 212, 142, 3, 10, 70, 73, 88, 69, 68, 45, 70, 79, 82, 77, 202, 1, 68, - 86, 78, 46, 83, 38, 84, 46, 66, 2, 67, 2, 71, 2, 80, 2, 90, 138, 69, 45, - 2, 72, 2, 74, 2, 76, 2, 77, 2, 87, 2, 89, 187, 2, 65, 8, 134, 202, 4, 83, - 14, 72, 2, 75, 187, 2, 65, 4, 224, 25, 3, 76, 72, 65, 13, 4, 67, 72, 65, - 68, 80, 254, 2, 66, 176, 1, 8, 77, 78, 89, 65, 77, 32, 89, 73, 114, 67, - 172, 2, 13, 89, 73, 71, 32, 77, 71, 79, 32, 84, 83, 72, 69, 71, 190, 1, - 71, 212, 2, 9, 65, 78, 71, 32, 75, 72, 65, 78, 71, 58, 72, 48, 2, 73, 78, - 246, 1, 78, 222, 1, 82, 118, 83, 46, 84, 36, 4, 76, 69, 65, 68, 212, 100, - 2, 80, 65, 181, 191, 1, 17, 68, 69, 76, 73, 77, 73, 84, 69, 82, 32, 84, - 83, 72, 69, 71, 32, 66, 10, 52, 9, 75, 65, 45, 32, 83, 72, 79, 71, 32, - 27, 83, 4, 142, 1, 71, 67, 89, 6, 34, 75, 201, 21, 3, 68, 85, 83, 4, 56, - 6, 65, 45, 32, 83, 72, 79, 89, 4, 85, 82, 32, 89, 2, 21, 3, 71, 32, 71, - 2, 41, 8, 73, 32, 77, 71, 79, 32, 82, 71, 2, 243, 252, 2, 89, 2, 221, 2, - 2, 73, 71, 12, 84, 5, 65, 82, 69, 84, 32, 240, 1, 2, 72, 69, 29, 7, 76, - 79, 83, 73, 78, 71, 32, 6, 112, 12, 45, 68, 90, 85, 68, 32, 82, 84, 65, - 71, 83, 32, 97, 12, 89, 73, 71, 32, 77, 71, 79, 32, 80, 72, 85, 82, 4, - 42, 66, 37, 6, 77, 69, 32, 76, 79, 78, 2, 33, 6, 90, 72, 73, 32, 77, 73, - 2, 203, 22, 71, 2, 225, 3, 3, 32, 83, 72, 2, 149, 183, 2, 2, 32, 77, 4, - 68, 13, 66, 82, 68, 65, 32, 82, 78, 89, 73, 78, 71, 32, 89, 3, 89, 2, - 213, 5, 11, 73, 71, 32, 77, 71, 79, 32, 83, 71, 65, 66, 12, 68, 4, 84, - 69, 82, 32, 141, 2, 8, 85, 71, 32, 82, 84, 65, 71, 83, 8, 56, 8, 89, 73, - 71, 32, 77, 71, 79, 32, 227, 251, 3, 84, 6, 68, 4, 45, 85, 77, 32, 117, - 9, 84, 82, 85, 78, 67, 65, 84, 69, 68, 4, 88, 7, 82, 78, 65, 77, 32, 66, - 67, 245, 2, 10, 71, 84, 69, 82, 32, 84, 83, 72, 69, 71, 2, 241, 2, 2, 65, - 68, 2, 231, 189, 4, 32, 4, 21, 3, 32, 71, 89, 4, 146, 240, 3, 79, 135, - 18, 65, 2, 17, 2, 65, 76, 2, 241, 154, 4, 2, 65, 78, 6, 92, 6, 73, 84, - 73, 65, 76, 32, 181, 248, 3, 11, 84, 69, 82, 83, 89, 76, 76, 65, 66, 73, - 67, 4, 68, 13, 66, 82, 68, 65, 32, 82, 78, 89, 73, 78, 71, 32, 89, 3, 89, - 2, 53, 11, 73, 71, 32, 77, 71, 79, 32, 77, 68, 85, 78, 2, 179, 156, 4, - 32, 10, 72, 10, 71, 65, 83, 32, 66, 90, 85, 78, 71, 32, 77, 4, 89, 73, - 83, 32, 4, 56, 3, 83, 71, 79, 145, 154, 4, 5, 78, 89, 73, 32, 90, 2, 251, - 9, 82, 6, 44, 5, 84, 83, 72, 69, 71, 179, 245, 3, 83, 5, 163, 245, 3, 32, - 4, 128, 245, 3, 8, 71, 89, 65, 32, 71, 82, 65, 77, 1, 14, 73, 78, 32, 67, - 72, 69, 78, 32, 83, 80, 85, 78, 71, 83, 4, 140, 244, 3, 4, 66, 82, 85, - 76, 39, 72, 6, 32, 4, 82, 65, 73, 76, 55, 83, 2, 225, 7, 9, 73, 78, 71, - 32, 77, 67, 72, 65, 78, 4, 56, 5, 65, 32, 45, 80, 72, 209, 242, 3, 3, 72, - 69, 71, 2, 183, 148, 4, 82, 156, 1, 84, 4, 73, 71, 78, 32, 228, 6, 9, 85, - 66, 74, 79, 73, 78, 69, 68, 32, 143, 4, 89, 42, 176, 1, 4, 71, 82, 85, - 32, 96, 2, 76, 67, 30, 77, 36, 11, 78, 89, 73, 32, 90, 76, 65, 32, 78, - 65, 65, 22, 82, 252, 2, 2, 89, 65, 130, 4, 73, 165, 4, 5, 83, 78, 65, 32, - 76, 4, 40, 3, 67, 65, 78, 1, 3, 77, 69, 68, 2, 25, 4, 32, 82, 71, 89, 2, - 169, 4, 2, 73, 78, 4, 238, 3, 73, 179, 4, 69, 4, 136, 4, 2, 65, 82, 231, - 3, 67, 2, 215, 144, 4, 32, 20, 116, 4, 68, 69, 76, 32, 240, 1, 10, 74, - 69, 83, 32, 83, 85, 32, 78, 71, 65, 181, 236, 3, 6, 78, 65, 77, 32, 66, - 67, 16, 52, 5, 68, 75, 65, 82, 32, 53, 4, 78, 65, 71, 32, 8, 94, 71, 181, - 202, 2, 6, 82, 68, 69, 76, 32, 78, 8, 42, 71, 69, 6, 82, 68, 69, 76, 32, - 68, 6, 46, 67, 212, 143, 2, 2, 78, 89, 167, 122, 83, 2, 179, 178, 4, 73, - 2, 187, 145, 3, 75, 2, 199, 195, 2, 32, 4, 18, 78, 71, 82, 2, 11, 71, 2, - 21, 3, 32, 82, 84, 2, 11, 65, 2, 171, 244, 3, 71, 2, 17, 2, 32, 84, 2, - 219, 157, 3, 83, 94, 68, 7, 76, 69, 84, 84, 69, 82, 32, 145, 2, 5, 83, - 73, 71, 78, 32, 88, 220, 1, 10, 70, 73, 88, 69, 68, 45, 70, 79, 82, 77, - 150, 230, 3, 68, 50, 75, 38, 78, 46, 83, 38, 84, 46, 66, 2, 67, 2, 71, 2, - 80, 2, 90, 138, 69, 45, 2, 72, 2, 74, 2, 76, 2, 77, 2, 82, 2, 87, 2, 89, - 187, 2, 65, 6, 11, 32, 6, 222, 172, 4, 82, 2, 87, 3, 89, 6, 38, 73, 50, - 77, 33, 3, 76, 67, 69, 2, 45, 9, 78, 86, 69, 82, 84, 69, 68, 32, 77, 2, - 11, 67, 2, 45, 2, 72, 85, 2, 25, 4, 32, 84, 83, 65, 2, 11, 32, 2, 211, - 227, 2, 67, 20, 60, 6, 76, 76, 65, 66, 76, 69, 21, 5, 77, 66, 79, 76, 32, - 2, 155, 156, 4, 32, 18, 104, 4, 68, 82, 73, 76, 32, 6, 78, 79, 82, 32, - 66, 85, 130, 1, 80, 93, 7, 82, 68, 79, 32, 82, 74, 69, 2, 11, 32, 2, 139, - 135, 4, 66, 9, 11, 32, 6, 72, 4, 66, 90, 72, 73, 0, 4, 71, 83, 85, 77, 1, - 4, 78, 89, 73, 83, 2, 177, 247, 1, 5, 32, 45, 75, 72, 89, 4, 52, 6, 65, - 68, 77, 65, 32, 71, 21, 3, 72, 85, 82, 2, 167, 224, 2, 68, 2, 191, 112, - 32, 5, 237, 238, 2, 6, 32, 82, 71, 89, 65, 32, 30, 116, 8, 82, 69, 86, - 69, 82, 83, 69, 68, 186, 85, 85, 22, 86, 182, 141, 1, 79, 134, 60, 73, - 190, 201, 1, 69, 235, 61, 65, 4, 129, 159, 2, 2, 32, 73, 2, 25, 4, 32, - 73, 78, 70, 2, 11, 73, 2, 11, 78, 2, 151, 187, 2, 73, 118, 216, 1, 9, 67, - 79, 78, 83, 79, 78, 65, 78, 84, 20, 7, 76, 69, 84, 84, 69, 82, 32, 236, - 6, 20, 77, 79, 68, 73, 70, 73, 69, 82, 32, 76, 69, 84, 84, 69, 82, 32, - 76, 65, 66, 73, 37, 8, 83, 69, 80, 65, 82, 65, 84, 79, 2, 131, 232, 3, - 32, 112, 106, 65, 108, 17, 66, 69, 82, 66, 69, 82, 32, 65, 67, 65, 68, - 69, 77, 89, 32, 89, 65, 30, 84, 223, 1, 89, 4, 84, 6, 89, 69, 82, 32, 89, - 65, 173, 163, 4, 9, 72, 65, 71, 71, 65, 82, 32, 89, 65, 2, 183, 163, 4, - 71, 4, 178, 164, 4, 72, 3, 74, 18, 92, 11, 65, 87, 69, 76, 76, 69, 77, - 69, 84, 32, 89, 33, 8, 85, 65, 82, 69, 71, 32, 89, 65, 2, 11, 65, 2, 171, - 163, 4, 90, 16, 62, 71, 190, 2, 75, 142, 159, 4, 90, 62, 78, 86, 72, 3, - 81, 4, 214, 162, 4, 72, 3, 78, 86, 54, 65, 210, 2, 69, 182, 159, 4, 73, - 2, 79, 3, 85, 77, 190, 1, 68, 30, 71, 2, 75, 14, 66, 2, 72, 22, 83, 30, - 84, 30, 90, 138, 77, 82, 186, 209, 3, 67, 146, 1, 65, 2, 70, 2, 74, 2, - 76, 2, 77, 2, 78, 2, 80, 2, 81, 2, 86, 2, 87, 3, 89, 9, 38, 68, 159, 160, - 4, 72, 7, 11, 72, 5, 155, 160, 4, 72, 7, 134, 160, 4, 72, 3, 83, 7, 234, - 159, 4, 72, 3, 84, 7, 206, 159, 4, 72, 3, 90, 5, 179, 159, 4, 89, 2, 233, - 181, 3, 4, 65, 76, 73, 90, 2, 183, 221, 3, 82, 6, 76, 2, 69, 82, 21, 13, - 72, 84, 32, 84, 82, 73, 70, 79, 76, 73, 65, 84, 69, 5, 131, 225, 3, 32, - 2, 33, 6, 32, 83, 78, 79, 87, 70, 2, 175, 53, 76, 19, 11, 32, 16, 72, 8, - 79, 80, 69, 82, 65, 84, 79, 82, 233, 1, 5, 87, 73, 84, 72, 32, 11, 11, - 32, 8, 38, 65, 101, 5, 87, 73, 84, 72, 32, 4, 25, 4, 66, 79, 86, 69, 4, - 11, 32, 4, 26, 76, 139, 252, 2, 82, 2, 11, 69, 2, 147, 252, 2, 70, 4, 26, - 82, 251, 154, 3, 68, 2, 17, 2, 73, 83, 2, 241, 202, 2, 3, 73, 78, 71, 6, - 26, 68, 143, 234, 1, 82, 4, 11, 79, 4, 175, 252, 1, 84, 6, 22, 82, 239, - 125, 83, 2, 11, 32, 2, 243, 171, 1, 67, 5, 21, 3, 32, 84, 87, 2, 21, 3, - 79, 32, 68, 2, 237, 86, 3, 79, 84, 83, 170, 1, 100, 5, 72, 85, 84, 65, - 32, 184, 6, 11, 79, 78, 73, 65, 78, 32, 83, 73, 71, 78, 32, 227, 129, 3, - 69, 164, 1, 178, 1, 65, 88, 7, 76, 69, 84, 84, 69, 82, 32, 204, 1, 2, 83, - 73, 200, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 162, 162, 2, - 68, 204, 152, 1, 2, 71, 86, 255, 71, 79, 4, 18, 66, 51, 78, 2, 29, 5, 66, - 82, 69, 86, 73, 2, 171, 22, 65, 2, 143, 131, 4, 74, 94, 178, 60, 65, 38, - 68, 114, 84, 46, 86, 186, 5, 85, 206, 201, 1, 73, 162, 193, 1, 78, 46, - 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, 77, - 2, 82, 2, 89, 186, 2, 69, 3, 79, 12, 21, 3, 71, 78, 32, 12, 46, 67, 98, - 78, 242, 60, 65, 231, 147, 3, 86, 2, 11, 65, 2, 11, 78, 2, 25, 4, 68, 82, - 65, 66, 2, 11, 73, 2, 11, 78, 2, 139, 239, 3, 68, 2, 11, 85, 2, 135, 239, - 3, 75, 30, 78, 83, 166, 63, 65, 38, 85, 22, 86, 186, 201, 1, 73, 222, - 137, 2, 69, 3, 79, 4, 25, 4, 72, 79, 82, 84, 4, 11, 32, 4, 198, 146, 4, - 69, 3, 79, 4, 144, 221, 3, 8, 67, 65, 80, 73, 84, 65, 76, 32, 239, 24, - 69, 146, 2, 140, 2, 12, 68, 72, 82, 73, 32, 76, 69, 84, 84, 69, 82, 32, - 182, 4, 77, 18, 78, 34, 79, 80, 2, 80, 32, 168, 17, 23, 82, 84, 79, 73, - 83, 69, 32, 83, 72, 69, 76, 76, 32, 66, 82, 65, 67, 75, 69, 84, 69, 68, - 32, 130, 4, 84, 222, 149, 2, 73, 149, 70, 5, 75, 89, 79, 32, 84, 104, - 242, 1, 71, 42, 74, 30, 77, 34, 78, 70, 72, 34, 80, 34, 83, 210, 50, 82, - 206, 147, 1, 79, 134, 60, 69, 42, 76, 198, 2, 65, 178, 191, 1, 67, 2, 68, - 2, 75, 2, 84, 2, 88, 2, 90, 138, 69, 66, 2, 70, 2, 81, 2, 86, 186, 2, 73, - 2, 85, 3, 89, 6, 170, 139, 4, 72, 2, 74, 187, 2, 65, 4, 186, 141, 4, 65, - 3, 89, 4, 230, 138, 4, 66, 187, 2, 65, 14, 66, 71, 190, 194, 2, 74, 194, - 130, 1, 88, 138, 69, 68, 187, 2, 65, 4, 130, 138, 4, 74, 187, 2, 65, 4, - 226, 137, 4, 83, 187, 2, 65, 10, 54, 72, 198, 193, 2, 75, 202, 199, 1, - 84, 187, 2, 65, 4, 138, 137, 4, 84, 187, 2, 65, 2, 231, 28, 65, 2, 11, - 71, 2, 179, 244, 3, 85, 6, 32, 2, 84, 72, 151, 254, 2, 76, 5, 11, 66, 2, - 11, 82, 2, 151, 162, 2, 85, 72, 252, 1, 4, 65, 82, 67, 32, 162, 2, 67, - 44, 2, 72, 65, 166, 3, 80, 140, 3, 13, 74, 85, 83, 84, 73, 70, 73, 69, - 68, 32, 76, 79, 87, 84, 5, 76, 69, 70, 84, 32, 228, 1, 6, 82, 73, 71, 72, - 84, 32, 170, 2, 83, 38, 84, 81, 7, 87, 73, 84, 72, 32, 85, 80, 6, 180, 1, - 19, 65, 78, 84, 73, 67, 76, 79, 67, 75, 87, 73, 83, 69, 32, 65, 82, 82, - 79, 87, 73, 21, 67, 76, 79, 67, 75, 87, 73, 83, 69, 32, 65, 82, 82, 79, - 87, 32, 87, 73, 84, 72, 32, 5, 29, 5, 32, 87, 73, 84, 72, 2, 17, 2, 32, - 80, 2, 187, 128, 2, 76, 2, 11, 77, 2, 143, 128, 2, 73, 2, 11, 85, 2, 133, - 179, 3, 3, 82, 76, 89, 34, 36, 3, 76, 70, 32, 179, 133, 4, 84, 32, 70, - 70, 186, 1, 76, 22, 82, 178, 2, 83, 250, 5, 66, 231, 243, 1, 73, 8, 136, - 1, 15, 79, 82, 87, 65, 82, 68, 45, 70, 65, 67, 73, 78, 71, 32, 82, 157, - 2, 13, 76, 65, 73, 76, 73, 78, 71, 32, 82, 79, 66, 79, 84, 4, 22, 85, - 243, 1, 79, 2, 203, 197, 3, 78, 8, 41, 2, 69, 70, 8, 21, 3, 73, 71, 72, - 8, 11, 84, 8, 54, 32, 69, 9, 45, 70, 65, 67, 73, 78, 71, 32, 82, 2, 11, - 80, 2, 33, 6, 65, 82, 69, 78, 84, 72, 2, 207, 222, 1, 69, 6, 38, 79, 21, - 5, 85, 78, 78, 69, 82, 2, 155, 177, 3, 66, 4, 29, 5, 32, 70, 82, 65, 77, - 4, 11, 69, 4, 11, 45, 4, 134, 129, 4, 49, 3, 50, 4, 18, 69, 59, 84, 2, - 11, 67, 2, 11, 84, 2, 11, 73, 2, 147, 135, 2, 79, 2, 17, 2, 65, 78, 2, - 11, 68, 2, 21, 3, 73, 78, 71, 2, 17, 2, 32, 80, 2, 11, 69, 2, 11, 82, 2, - 207, 175, 3, 83, 4, 17, 2, 69, 82, 4, 33, 6, 32, 72, 65, 76, 70, 32, 4, - 250, 3, 66, 139, 105, 87, 10, 180, 1, 13, 74, 85, 83, 84, 73, 70, 73, 69, - 68, 32, 76, 79, 87, 126, 67, 50, 72, 225, 214, 2, 21, 66, 76, 65, 67, 75, - 32, 76, 69, 70, 84, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 83, 2, 237, - 1, 7, 69, 82, 32, 82, 73, 71, 72, 8, 78, 67, 50, 72, 33, 13, 74, 85, 83, - 84, 73, 70, 73, 69, 68, 32, 76, 79, 87, 4, 26, 79, 243, 130, 3, 82, 2, - 139, 190, 3, 82, 2, 253, 168, 3, 3, 65, 76, 70, 2, 33, 6, 69, 82, 32, 76, - 69, 70, 2, 53, 11, 84, 32, 81, 85, 65, 82, 84, 69, 82, 32, 66, 2, 11, 76, - 2, 209, 168, 2, 3, 65, 67, 75, 2, 201, 167, 3, 4, 81, 85, 65, 82, 2, 11, - 79, 2, 165, 167, 3, 12, 82, 84, 79, 73, 83, 69, 32, 83, 72, 69, 76, 76, - 2, 29, 5, 87, 65, 82, 68, 83, 2, 17, 2, 32, 65, 2, 153, 252, 2, 4, 82, - 82, 79, 87, 20, 188, 1, 22, 67, 74, 75, 32, 85, 78, 73, 70, 73, 69, 68, - 32, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 161, 2, 19, 76, 65, 84, 73, - 78, 32, 67, 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 18, 40, 2, - 52, 69, 34, 53, 54, 54, 87, 55, 4, 202, 1, 48, 203, 205, 2, 56, 4, 30, - 50, 141, 1, 2, 66, 56, 2, 175, 176, 3, 68, 6, 48, 2, 50, 53, 22, 53, 249, - 205, 2, 2, 55, 50, 2, 135, 246, 3, 51, 2, 67, 53, 4, 32, 2, 48, 66, 21, - 2, 54, 68, 2, 195, 245, 3, 57, 2, 175, 245, 3, 55, 2, 11, 82, 2, 179, - 183, 3, 32, 64, 48, 6, 65, 76, 32, 82, 85, 78, 21, 2, 79, 32, 2, 247, - 250, 2, 79, 62, 72, 7, 76, 69, 84, 84, 69, 82, 32, 217, 2, 6, 83, 73, 71, - 78, 32, 82, 60, 206, 1, 66, 106, 78, 138, 30, 73, 202, 141, 1, 69, 162, - 75, 67, 162, 186, 1, 65, 234, 61, 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, - 2, 77, 2, 80, 2, 82, 2, 83, 2, 84, 2, 87, 2, 89, 186, 2, 79, 3, 85, 12, - 52, 7, 82, 69, 65, 84, 72, 89, 32, 227, 241, 3, 65, 10, 182, 30, 73, 202, - 141, 1, 69, 143, 175, 2, 65, 4, 246, 238, 3, 71, 187, 2, 65, 2, 17, 2, - 73, 83, 2, 21, 3, 73, 78, 71, 2, 11, 32, 2, 147, 198, 2, 84, 98, 46, 65, - 254, 1, 73, 246, 11, 79, 195, 1, 85, 16, 66, 67, 36, 2, 68, 69, 34, 77, - 20, 2, 78, 83, 155, 159, 3, 73, 4, 246, 231, 1, 75, 243, 206, 1, 84, 2, - 141, 16, 4, 32, 77, 65, 82, 5, 131, 212, 1, 32, 4, 44, 2, 80, 76, 33, 5, - 86, 69, 82, 83, 65, 2, 11, 85, 2, 199, 207, 3, 84, 2, 171, 62, 76, 66, - 156, 1, 3, 65, 78, 71, 176, 3, 8, 68, 69, 78, 84, 32, 69, 77, 66, 20, 9, - 71, 82, 65, 77, 32, 70, 79, 82, 32, 140, 2, 4, 80, 76, 69, 32, 167, 151, - 3, 67, 16, 48, 2, 76, 69, 245, 1, 5, 85, 76, 65, 82, 32, 10, 44, 6, 32, - 87, 73, 84, 72, 32, 163, 1, 45, 8, 80, 9, 83, 69, 82, 73, 70, 83, 32, 65, - 84, 54, 85, 138, 168, 2, 82, 187, 66, 68, 2, 17, 2, 32, 66, 2, 197, 218, - 3, 3, 79, 84, 84, 2, 241, 60, 2, 78, 68, 2, 205, 202, 2, 4, 72, 69, 65, - 68, 6, 68, 9, 70, 76, 65, 71, 32, 79, 78, 32, 80, 34, 82, 179, 138, 2, - 66, 2, 11, 79, 2, 207, 205, 3, 83, 2, 11, 85, 2, 239, 171, 3, 76, 2, 155, - 215, 3, 76, 16, 66, 69, 34, 72, 34, 76, 22, 77, 46, 84, 42, 87, 255, 210, - 1, 70, 2, 11, 65, 2, 211, 230, 1, 82, 2, 11, 69, 2, 211, 248, 1, 65, 2, - 215, 184, 3, 65, 2, 21, 3, 79, 85, 78, 2, 175, 187, 2, 84, 2, 17, 2, 72, - 85, 2, 215, 199, 1, 78, 4, 206, 175, 2, 65, 131, 42, 73, 30, 176, 2, 3, - 67, 79, 76, 24, 20, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 66, 65, - 82, 32, 87, 73, 84, 72, 32, 98, 80, 34, 84, 20, 13, 86, 69, 82, 84, 73, - 67, 65, 76, 32, 66, 65, 82, 32, 44, 9, 83, 79, 76, 73, 68, 85, 83, 32, - 66, 188, 21, 2, 68, 65, 168, 187, 1, 6, 78, 69, 83, 84, 69, 68, 171, 11, - 73, 2, 129, 37, 2, 79, 78, 4, 34, 68, 33, 4, 84, 82, 73, 80, 2, 17, 2, - 79, 85, 2, 11, 66, 2, 185, 179, 3, 2, 76, 69, 4, 254, 221, 1, 76, 135, - 110, 82, 2, 167, 202, 1, 73, 8, 42, 66, 74, 68, 134, 189, 1, 82, 115, 87, - 2, 29, 5, 73, 78, 65, 82, 89, 2, 21, 3, 32, 82, 69, 2, 235, 32, 76, 2, - 25, 4, 69, 76, 73, 77, 2, 191, 170, 2, 73, 10, 24, 2, 76, 76, 35, 80, 5, - 137, 220, 1, 3, 69, 89, 66, 6, 44, 5, 73, 67, 65, 76, 32, 243, 207, 3, - 72, 4, 18, 68, 47, 70, 2, 11, 82, 2, 11, 73, 2, 243, 221, 3, 78, 2, 215, - 248, 1, 73, 6, 18, 69, 79, 77, 5, 129, 188, 3, 14, 32, 76, 73, 71, 72, - 84, 32, 77, 79, 79, 78, 32, 65, 82, 2, 235, 170, 3, 80, 216, 1, 76, 3, - 71, 82, 73, 22, 76, 214, 12, 82, 221, 186, 2, 5, 77, 66, 76, 69, 82, 2, - 155, 216, 2, 75, 162, 1, 68, 11, 85, 45, 84, 73, 71, 65, 76, 65, 82, 73, - 32, 179, 222, 3, 73, 160, 1, 122, 65, 42, 67, 30, 68, 106, 71, 32, 7, 76, - 69, 84, 84, 69, 82, 32, 178, 3, 82, 32, 5, 83, 73, 71, 78, 32, 131, 3, - 86, 2, 11, 85, 2, 177, 155, 3, 2, 32, 76, 2, 245, 158, 3, 2, 79, 78, 4, - 18, 79, 67, 65, 2, 11, 85, 2, 11, 66, 2, 25, 4, 76, 69, 32, 68, 2, 11, - 65, 2, 159, 183, 3, 78, 2, 129, 215, 2, 3, 69, 77, 73, 100, 206, 1, 65, - 38, 68, 46, 76, 38, 82, 34, 84, 46, 86, 186, 5, 85, 206, 201, 1, 73, 162, - 193, 1, 78, 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 206, 40, - 79, 162, 8, 69, 158, 20, 72, 2, 77, 3, 89, 9, 158, 218, 3, 65, 2, 73, 3, - 85, 8, 186, 146, 3, 68, 138, 69, 72, 187, 2, 65, 6, 154, 208, 1, 76, 183, - 137, 2, 65, 4, 242, 214, 3, 82, 187, 2, 65, 8, 202, 145, 3, 84, 138, 69, - 72, 187, 2, 65, 10, 214, 5, 79, 139, 211, 3, 65, 2, 11, 69, 2, 243, 221, - 1, 80, 18, 174, 1, 65, 72, 6, 76, 79, 79, 80, 69, 68, 40, 2, 79, 77, 0, - 5, 83, 72, 82, 73, 73, 48, 13, 67, 65, 78, 68, 82, 65, 32, 65, 78, 85, - 78, 65, 83, 22, 80, 179, 146, 3, 86, 4, 26, 86, 235, 145, 3, 78, 2, 21, - 3, 65, 71, 82, 2, 251, 219, 1, 65, 2, 17, 2, 32, 86, 2, 187, 157, 1, 73, - 2, 17, 2, 32, 80, 2, 25, 4, 85, 83, 72, 80, 2, 231, 204, 3, 73, 2, 237, - 176, 3, 2, 76, 85, 30, 56, 10, 69, 68, 73, 67, 32, 84, 79, 78, 69, 32, - 35, 79, 4, 226, 164, 1, 65, 235, 4, 83, 26, 45, 9, 87, 69, 76, 32, 83, - 73, 71, 78, 32, 26, 70, 65, 38, 85, 22, 86, 186, 201, 1, 73, 234, 234, 1, - 79, 163, 8, 69, 6, 202, 211, 3, 65, 2, 73, 3, 85, 5, 167, 211, 3, 85, 8, - 11, 79, 8, 33, 6, 67, 65, 76, 73, 67, 32, 8, 26, 82, 159, 214, 2, 76, 5, - 199, 210, 3, 82, 50, 50, 75, 84, 4, 78, 69, 68, 32, 135, 173, 2, 84, 4, - 48, 6, 73, 83, 72, 32, 76, 73, 135, 192, 3, 69, 2, 11, 82, 2, 191, 202, - 2, 65, 44, 238, 1, 65, 80, 6, 66, 76, 65, 67, 75, 32, 40, 7, 87, 72, 73, - 84, 69, 32, 83, 22, 67, 50, 68, 96, 2, 78, 79, 32, 2, 79, 75, 30, 83, - 153, 168, 3, 21, 71, 82, 69, 69, 75, 32, 83, 77, 65, 76, 76, 32, 76, 69, - 84, 84, 69, 82, 32, 73, 79, 4, 26, 77, 239, 170, 2, 78, 2, 17, 2, 80, 69, - 2, 11, 82, 2, 251, 192, 2, 83, 4, 18, 80, 23, 83, 2, 147, 150, 2, 69, 2, - 131, 152, 2, 72, 4, 144, 3, 5, 65, 80, 73, 84, 65, 167, 121, 79, 6, 30, - 65, 33, 3, 73, 71, 73, 2, 11, 71, 2, 231, 143, 3, 71, 4, 221, 221, 1, 3, - 84, 32, 84, 6, 162, 2, 82, 255, 195, 2, 84, 2, 141, 228, 1, 2, 32, 72, - 14, 128, 1, 18, 65, 78, 83, 45, 83, 69, 82, 73, 70, 32, 67, 65, 80, 73, - 84, 65, 76, 32, 38, 69, 32, 3, 77, 65, 76, 33, 2, 79, 85, 6, 222, 203, 3, - 71, 2, 76, 3, 89, 2, 11, 77, 2, 159, 251, 2, 73, 2, 11, 76, 2, 235, 201, - 2, 32, 4, 21, 3, 84, 72, 32, 4, 32, 2, 69, 65, 1, 2, 87, 69, 2, 53, 11, - 83, 84, 32, 80, 79, 73, 78, 84, 73, 78, 71, 2, 17, 2, 32, 76, 2, 195, - 200, 2, 69, 38, 58, 69, 52, 8, 73, 83, 84, 69, 68, 32, 82, 73, 63, 79, 2, - 17, 2, 76, 86, 2, 153, 178, 1, 3, 69, 32, 80, 2, 17, 2, 71, 72, 2, 137, - 109, 6, 84, 87, 65, 82, 68, 83, 34, 30, 32, 229, 10, 2, 45, 69, 32, 134, - 3, 66, 86, 67, 116, 3, 68, 79, 84, 226, 1, 72, 44, 14, 73, 78, 84, 69, - 82, 83, 69, 67, 84, 73, 78, 71, 32, 76, 92, 6, 74, 79, 73, 78, 69, 68, - 64, 8, 76, 79, 71, 73, 67, 65, 76, 32, 98, 77, 0, 3, 87, 79, 77, 116, 13, - 82, 73, 78, 71, 83, 32, 65, 76, 73, 71, 78, 69, 68, 48, 24, 65, 83, 84, - 69, 82, 73, 83, 75, 83, 32, 65, 76, 73, 71, 78, 69, 68, 32, 86, 69, 82, - 84, 73, 67, 35, 83, 2, 29, 5, 85, 84, 84, 79, 78, 2, 17, 2, 32, 77, 2, - 11, 79, 2, 191, 187, 2, 85, 2, 93, 21, 79, 78, 83, 69, 67, 85, 84, 73, - 86, 69, 32, 69, 81, 85, 65, 76, 83, 32, 83, 73, 71, 2, 251, 133, 3, 78, - 6, 18, 32, 55, 83, 4, 22, 76, 131, 1, 80, 2, 145, 163, 1, 2, 69, 65, 2, - 53, 11, 32, 79, 86, 69, 82, 32, 79, 78, 69, 32, 68, 2, 11, 79, 2, 11, 84, - 2, 17, 2, 32, 80, 2, 29, 5, 85, 78, 67, 84, 85, 2, 167, 241, 2, 65, 2, - 11, 69, 2, 11, 65, 2, 159, 173, 2, 82, 4, 17, 2, 79, 71, 4, 25, 4, 73, - 67, 65, 76, 4, 11, 32, 4, 130, 179, 2, 65, 159, 85, 79, 2, 17, 2, 32, 83, - 2, 21, 3, 81, 85, 65, 2, 183, 172, 2, 82, 4, 30, 79, 13, 3, 65, 78, 68, - 2, 11, 82, 2, 11, 32, 2, 11, 79, 2, 11, 80, 2, 143, 18, 69, 2, 11, 69, 2, - 45, 9, 78, 32, 72, 79, 76, 68, 73, 78, 71, 2, 11, 32, 2, 11, 72, 2, 11, - 65, 2, 143, 223, 1, 78, 2, 45, 9, 32, 72, 79, 82, 73, 90, 79, 78, 84, 2, - 11, 65, 2, 219, 154, 3, 76, 2, 49, 10, 80, 69, 69, 67, 72, 32, 66, 85, - 66, 66, 2, 203, 169, 2, 76, 2, 11, 77, 2, 245, 212, 1, 2, 32, 68, 248, 3, - 140, 1, 8, 71, 65, 82, 73, 84, 73, 67, 32, 152, 6, 7, 77, 66, 82, 69, 76, - 76, 65, 166, 1, 78, 158, 8, 80, 138, 166, 1, 82, 151, 134, 2, 83, 62, 48, - 7, 76, 69, 84, 84, 69, 82, 32, 159, 5, 87, 60, 206, 1, 65, 28, 2, 81, 79, - 22, 66, 22, 68, 50, 71, 44, 2, 72, 79, 22, 75, 34, 76, 32, 2, 82, 65, 22, - 83, 74, 84, 74, 89, 22, 90, 150, 182, 2, 78, 202, 91, 80, 246, 5, 87, - 202, 12, 77, 174, 18, 73, 3, 85, 4, 26, 76, 247, 233, 2, 73, 2, 155, 183, - 3, 80, 2, 243, 148, 3, 69, 4, 26, 69, 211, 175, 2, 72, 2, 195, 148, 3, - 76, 4, 166, 140, 2, 72, 189, 138, 1, 2, 65, 77, 5, 151, 182, 3, 84, 4, - 150, 183, 2, 65, 239, 126, 72, 2, 11, 65, 2, 139, 147, 3, 77, 2, 187, - 189, 1, 83, 8, 38, 65, 238, 183, 2, 72, 239, 90, 83, 4, 234, 160, 3, 68, - 239, 13, 77, 6, 38, 72, 206, 154, 3, 69, 175, 28, 79, 2, 11, 65, 2, 231, - 250, 1, 78, 2, 183, 240, 2, 79, 4, 246, 145, 3, 69, 207, 36, 85, 2, 21, - 3, 79, 82, 68, 2, 25, 4, 32, 68, 73, 86, 2, 235, 149, 1, 73, 7, 11, 32, - 4, 84, 4, 79, 78, 32, 71, 45, 13, 87, 73, 84, 72, 32, 82, 65, 73, 78, 32, - 68, 82, 79, 2, 11, 82, 2, 11, 79, 2, 231, 166, 2, 85, 2, 239, 246, 2, 80, - 32, 160, 1, 3, 65, 77, 85, 20, 7, 67, 69, 82, 84, 65, 73, 78, 34, 68, 62, - 73, 245, 5, 18, 77, 65, 82, 82, 73, 69, 68, 32, 80, 65, 82, 84, 78, 69, - 82, 83, 72, 73, 2, 187, 162, 2, 83, 2, 11, 84, 2, 243, 171, 2, 89, 4, 26, - 69, 159, 159, 2, 79, 2, 11, 82, 2, 135, 151, 3, 84, 22, 60, 2, 79, 78, - 234, 3, 84, 106, 86, 173, 58, 3, 67, 79, 82, 15, 11, 32, 12, 160, 1, 6, - 65, 66, 79, 86, 69, 32, 108, 22, 66, 69, 83, 73, 68, 69, 32, 65, 78, 68, - 32, 74, 79, 73, 78, 69, 68, 32, 87, 73, 84, 72, 41, 5, 87, 73, 84, 72, - 32, 4, 52, 9, 66, 65, 82, 32, 65, 66, 79, 86, 69, 23, 73, 2, 17, 2, 32, - 73, 2, 161, 49, 4, 78, 84, 69, 82, 2, 17, 2, 32, 85, 2, 239, 222, 2, 78, - 6, 66, 77, 58, 79, 189, 245, 2, 8, 76, 79, 71, 73, 67, 65, 76, 32, 2, 11, - 73, 2, 11, 78, 2, 11, 85, 2, 183, 167, 2, 83, 2, 11, 86, 2, 209, 140, 2, - 2, 69, 82, 4, 18, 32, 67, 69, 2, 11, 83, 2, 17, 2, 69, 80, 2, 11, 65, 2, - 187, 244, 2, 82, 2, 255, 153, 2, 68, 2, 57, 12, 69, 82, 83, 65, 76, 32, - 82, 69, 67, 89, 67, 76, 2, 17, 2, 73, 78, 2, 155, 153, 2, 71, 2, 135, - 153, 2, 80, 144, 3, 130, 1, 32, 246, 7, 45, 180, 8, 4, 80, 69, 82, 32, - 132, 40, 8, 83, 73, 68, 69, 45, 68, 79, 87, 21, 6, 87, 65, 82, 68, 83, - 32, 38, 140, 1, 5, 65, 82, 82, 79, 87, 224, 1, 5, 66, 65, 82, 66, 32, - 228, 1, 5, 68, 79, 87, 78, 32, 210, 1, 70, 30, 82, 93, 4, 84, 65, 67, 75, - 8, 64, 4, 72, 69, 65, 68, 137, 51, 7, 32, 84, 72, 82, 79, 85, 71, 7, 11, - 32, 4, 112, 22, 66, 69, 84, 87, 69, 69, 78, 32, 84, 87, 79, 32, 72, 79, - 82, 73, 90, 79, 78, 84, 65, 76, 171, 155, 2, 73, 2, 193, 147, 2, 2, 32, - 66, 8, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 4, 57, 12, 84, 32, 68, - 79, 87, 78, 32, 66, 65, 82, 66, 32, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, - 71, 72, 2, 11, 84, 2, 25, 4, 32, 72, 65, 82, 2, 11, 80, 2, 231, 214, 2, - 79, 14, 76, 5, 65, 82, 82, 79, 87, 62, 66, 38, 68, 18, 83, 246, 58, 87, - 219, 9, 84, 5, 37, 7, 32, 87, 73, 84, 72, 32, 66, 2, 187, 156, 2, 65, 2, - 221, 138, 2, 4, 76, 65, 67, 75, 2, 191, 59, 79, 2, 179, 65, 65, 2, 11, - 73, 2, 223, 112, 83, 2, 53, 11, 73, 71, 72, 84, 32, 68, 73, 65, 71, 79, - 78, 2, 189, 128, 1, 4, 65, 76, 32, 69, 5, 29, 5, 32, 87, 73, 84, 72, 2, - 33, 6, 32, 67, 73, 82, 67, 76, 2, 175, 166, 2, 69, 32, 58, 70, 225, 1, 9, - 80, 79, 73, 78, 84, 73, 78, 71, 32, 4, 41, 8, 65, 67, 73, 78, 71, 32, 83, - 78, 4, 65, 14, 65, 75, 69, 32, 72, 69, 65, 68, 32, 87, 73, 84, 72, 32, 4, - 42, 79, 25, 6, 67, 76, 79, 83, 69, 68, 2, 21, 3, 80, 69, 78, 2, 21, 3, - 32, 77, 79, 2, 135, 159, 1, 85, 28, 130, 1, 65, 86, 69, 62, 70, 20, 8, - 77, 73, 76, 73, 84, 65, 82, 89, 26, 82, 88, 6, 83, 77, 65, 76, 76, 32, - 118, 84, 255, 121, 71, 4, 22, 84, 159, 2, 73, 2, 37, 7, 79, 77, 73, 67, - 32, 66, 79, 2, 219, 227, 1, 77, 2, 29, 5, 78, 69, 82, 71, 89, 2, 213, - 179, 1, 2, 32, 87, 2, 143, 158, 3, 82, 2, 129, 1, 2, 32, 65, 8, 64, 5, - 79, 67, 75, 69, 84, 118, 69, 222, 129, 1, 65, 247, 28, 73, 2, 239, 200, - 2, 32, 4, 18, 65, 67, 82, 2, 11, 73, 2, 11, 82, 2, 17, 2, 80, 76, 2, 255, - 131, 2, 65, 2, 11, 69, 2, 151, 248, 1, 68, 4, 37, 7, 82, 73, 65, 78, 71, - 76, 69, 4, 11, 32, 4, 11, 87, 4, 25, 4, 73, 84, 72, 32, 4, 18, 76, 27, - 82, 2, 11, 69, 2, 35, 70, 2, 21, 3, 73, 71, 72, 2, 11, 84, 2, 17, 2, 32, - 72, 2, 21, 3, 65, 76, 70, 2, 17, 2, 32, 66, 2, 11, 76, 2, 143, 235, 1, - 65, 200, 1, 192, 1, 4, 65, 78, 68, 32, 210, 2, 66, 74, 67, 74, 70, 36, 5, - 72, 65, 76, 70, 32, 200, 4, 5, 76, 69, 70, 84, 32, 254, 5, 77, 150, 2, - 79, 60, 6, 82, 73, 71, 72, 84, 32, 234, 17, 83, 67, 84, 8, 34, 76, 53, 4, - 82, 73, 71, 72, 6, 48, 2, 69, 70, 173, 1, 5, 79, 87, 69, 82, 32, 2, 53, - 11, 84, 32, 65, 78, 68, 32, 76, 79, 87, 69, 82, 2, 201, 35, 25, 32, 84, - 82, 73, 65, 78, 71, 85, 76, 65, 82, 32, 84, 72, 82, 69, 69, 32, 81, 85, - 65, 82, 84, 69, 82, 4, 28, 2, 84, 82, 231, 39, 79, 2, 225, 4, 7, 73, 65, - 78, 71, 85, 76, 65, 2, 17, 2, 76, 65, 2, 17, 2, 68, 69, 2, 185, 223, 1, - 3, 32, 83, 67, 10, 33, 6, 69, 78, 84, 82, 69, 32, 10, 174, 12, 76, 22, - 82, 251, 21, 79, 2, 17, 2, 73, 86, 2, 179, 31, 69, 20, 140, 1, 5, 66, 76, - 79, 67, 75, 110, 72, 32, 8, 73, 78, 86, 69, 82, 83, 69, 32, 198, 1, 86, - 170, 26, 77, 130, 3, 76, 22, 82, 139, 162, 1, 67, 5, 225, 28, 23, 32, 65, - 78, 68, 32, 76, 79, 87, 69, 82, 32, 72, 65, 76, 70, 32, 73, 78, 86, 69, - 82, 83, 69, 2, 225, 18, 4, 69, 65, 86, 89, 4, 100, 21, 77, 69, 68, 73, - 85, 77, 32, 83, 72, 65, 68, 69, 32, 65, 78, 68, 32, 76, 79, 87, 69, 51, - 87, 2, 11, 82, 2, 185, 35, 5, 32, 72, 65, 76, 70, 2, 21, 3, 72, 73, 84, - 2, 191, 191, 1, 69, 2, 29, 5, 69, 82, 84, 73, 67, 2, 197, 115, 14, 65, - 76, 32, 76, 73, 78, 69, 32, 87, 73, 84, 72, 32, 84, 62, 50, 66, 238, 3, - 67, 54, 79, 74, 84, 179, 13, 81, 22, 65, 14, 76, 79, 67, 75, 32, 68, 73, - 65, 71, 79, 78, 65, 76, 32, 22, 144, 1, 6, 76, 79, 87, 69, 82, 32, 233, - 8, 24, 85, 80, 80, 69, 82, 32, 77, 73, 68, 68, 76, 69, 32, 76, 69, 70, - 84, 32, 84, 79, 32, 85, 80, 80, 18, 176, 1, 10, 67, 69, 78, 84, 82, 69, - 32, 84, 79, 32, 36, 8, 76, 69, 70, 84, 32, 84, 79, 32, 229, 10, 18, 77, - 73, 68, 68, 76, 69, 32, 76, 69, 70, 84, 32, 84, 79, 32, 85, 80, 80, 6, - 70, 76, 253, 8, 3, 85, 80, 80, 6, 34, 76, 213, 9, 3, 85, 80, 80, 2, 149, - 10, 2, 79, 87, 2, 29, 5, 79, 82, 78, 69, 82, 2, 155, 232, 1, 32, 4, 182, - 12, 78, 53, 12, 82, 32, 76, 79, 87, 69, 82, 32, 82, 73, 71, 72, 8, 34, - 79, 166, 19, 82, 155, 1, 87, 2, 237, 18, 11, 32, 76, 79, 87, 69, 82, 32, - 82, 73, 71, 72, 12, 33, 6, 73, 68, 68, 76, 69, 32, 12, 52, 7, 67, 69, 78, - 84, 82, 69, 32, 74, 76, 23, 82, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, - 72, 2, 117, 3, 84, 32, 79, 4, 41, 2, 69, 70, 4, 21, 3, 73, 71, 72, 4, 17, - 2, 84, 32, 4, 30, 79, 253, 17, 2, 84, 87, 2, 139, 9, 78, 4, 11, 78, 4, - 17, 2, 69, 32, 4, 150, 21, 81, 147, 4, 69, 68, 84, 2, 66, 76, 186, 6, 68, - 114, 79, 222, 1, 80, 38, 81, 224, 4, 2, 83, 72, 51, 84, 22, 61, 13, 79, - 67, 75, 32, 68, 73, 65, 71, 79, 78, 65, 76, 32, 22, 140, 1, 24, 76, 79, - 87, 69, 82, 32, 77, 73, 68, 68, 76, 69, 32, 76, 69, 70, 84, 32, 84, 79, - 32, 76, 79, 87, 57, 6, 85, 80, 80, 69, 82, 32, 4, 21, 3, 69, 82, 32, 4, - 246, 3, 67, 135, 215, 2, 82, 18, 176, 1, 10, 67, 69, 78, 84, 82, 69, 32, - 84, 79, 32, 92, 8, 76, 69, 70, 84, 32, 84, 79, 32, 141, 1, 18, 77, 73, - 68, 68, 76, 69, 32, 76, 69, 70, 84, 32, 84, 79, 32, 76, 79, 87, 6, 32, 3, - 76, 79, 87, 139, 1, 85, 4, 21, 3, 69, 82, 32, 4, 142, 2, 77, 223, 214, 2, - 82, 6, 28, 3, 76, 79, 87, 51, 85, 4, 21, 3, 69, 82, 32, 4, 142, 1, 67, - 43, 77, 2, 17, 2, 80, 80, 2, 17, 2, 69, 82, 2, 117, 2, 32, 77, 6, 21, 3, - 69, 82, 32, 6, 34, 67, 42, 77, 223, 214, 2, 82, 2, 11, 69, 2, 141, 225, - 1, 2, 78, 84, 2, 25, 4, 73, 68, 68, 76, 2, 139, 176, 1, 69, 2, 57, 12, - 82, 79, 80, 45, 83, 72, 65, 68, 79, 87, 69, 68, 2, 17, 2, 32, 87, 2, 213, - 190, 1, 3, 72, 73, 84, 4, 62, 78, 53, 11, 82, 32, 76, 79, 87, 69, 82, 32, - 76, 69, 70, 2, 225, 16, 9, 69, 32, 83, 73, 88, 84, 69, 69, 78, 2, 69, 15, - 84, 32, 67, 85, 82, 76, 89, 32, 66, 82, 65, 67, 75, 69, 84, 2, 11, 32, 2, - 219, 173, 2, 83, 2, 11, 69, 2, 205, 74, 2, 78, 67, 26, 17, 2, 85, 65, 26, - 44, 6, 68, 82, 65, 78, 84, 32, 255, 3, 82, 24, 90, 67, 112, 10, 70, 65, - 67, 69, 32, 87, 73, 84, 72, 32, 114, 77, 76, 2, 83, 84, 67, 84, 14, 68, - 7, 73, 82, 67, 85, 76, 65, 82, 145, 167, 1, 4, 72, 69, 83, 83, 2, 17, 2, - 32, 65, 2, 147, 212, 1, 82, 4, 34, 67, 45, 4, 79, 80, 69, 78, 2, 21, 3, - 76, 79, 83, 2, 17, 2, 69, 68, 2, 177, 231, 1, 3, 32, 69, 89, 2, 25, 4, - 73, 67, 82, 79, 2, 11, 67, 2, 233, 194, 1, 4, 79, 77, 80, 85, 2, 41, 8, - 65, 78, 68, 73, 78, 71, 32, 75, 2, 195, 207, 2, 78, 2, 21, 3, 69, 76, 69, - 2, 11, 86, 2, 187, 90, 73, 2, 181, 167, 1, 3, 84, 69, 82, 4, 153, 102, 8, - 65, 68, 79, 87, 69, 68, 32, 87, 8, 30, 79, 106, 82, 155, 1, 87, 2, 49, - 10, 32, 76, 79, 87, 69, 82, 32, 76, 69, 70, 2, 11, 84, 2, 11, 32, 2, 11, - 70, 2, 195, 112, 73, 4, 25, 4, 73, 65, 78, 71, 4, 40, 4, 85, 76, 65, 82, - 219, 224, 2, 76, 2, 17, 2, 32, 77, 2, 41, 8, 69, 68, 73, 85, 77, 32, 83, - 72, 2, 223, 102, 65, 2, 21, 3, 69, 76, 70, 2, 11, 84, 2, 163, 164, 1, 72, - 2, 17, 2, 69, 86, 2, 17, 2, 69, 78, 2, 145, 1, 2, 32, 69, 10, 64, 5, 72, - 82, 69, 69, 32, 193, 1, 6, 82, 73, 65, 78, 71, 85, 8, 54, 69, 49, 9, 81, - 85, 65, 82, 84, 69, 82, 83, 32, 2, 29, 5, 73, 71, 72, 84, 72, 2, 243, 5, - 83, 6, 30, 76, 22, 82, 203, 5, 66, 2, 41, 2, 69, 70, 2, 21, 3, 73, 71, - 72, 2, 43, 84, 2, 17, 2, 76, 65, 2, 11, 82, 2, 17, 2, 32, 79, 2, 25, 4, - 78, 69, 32, 81, 2, 185, 4, 6, 85, 65, 82, 84, 69, 82, 2, 199, 181, 2, 78, - 128, 1, 154, 1, 65, 184, 6, 2, 66, 76, 150, 1, 68, 50, 70, 82, 72, 150, - 4, 67, 46, 81, 42, 82, 22, 83, 102, 84, 146, 7, 80, 173, 3, 6, 87, 72, - 73, 84, 69, 32, 32, 34, 78, 33, 4, 82, 82, 79, 87, 2, 11, 67, 2, 195, - 172, 2, 79, 31, 11, 32, 28, 134, 1, 65, 192, 1, 14, 76, 69, 70, 84, 87, - 65, 82, 68, 83, 32, 79, 70, 32, 68, 32, 5, 87, 73, 84, 72, 32, 210, 8, - 70, 179, 5, 84, 2, 41, 8, 78, 68, 32, 82, 73, 71, 72, 84, 2, 17, 2, 32, - 79, 2, 25, 4, 78, 69, 32, 69, 2, 21, 3, 73, 71, 72, 2, 17, 2, 84, 72, 2, - 11, 32, 2, 11, 66, 2, 11, 76, 2, 191, 190, 1, 79, 2, 197, 206, 1, 3, 79, - 87, 78, 20, 74, 68, 58, 76, 42, 77, 38, 78, 58, 83, 66, 69, 250, 12, 84, - 139, 58, 72, 2, 21, 3, 79, 85, 66, 2, 11, 76, 2, 247, 188, 2, 69, 2, 11, - 65, 2, 253, 22, 3, 82, 71, 69, 2, 225, 22, 5, 69, 68, 73, 85, 77, 2, 25, - 4, 79, 84, 67, 72, 2, 11, 69, 2, 139, 56, 68, 4, 11, 77, 4, 25, 4, 65, - 76, 76, 32, 4, 22, 69, 223, 21, 84, 2, 129, 22, 10, 81, 85, 73, 76, 65, - 84, 69, 82, 65, 76, 4, 25, 4, 65, 67, 75, 32, 4, 26, 67, 139, 208, 1, 65, - 2, 25, 4, 73, 82, 67, 76, 2, 25, 4, 69, 68, 32, 87, 2, 11, 72, 2, 237, - 14, 2, 73, 84, 4, 22, 79, 195, 13, 65, 2, 177, 14, 2, 85, 66, 2, 11, 73, - 2, 37, 7, 78, 71, 69, 82, 45, 80, 79, 2, 173, 206, 1, 2, 83, 84, 20, 88, - 17, 65, 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, 32, 66, 65, 82, 66, 32, - 131, 3, 69, 16, 56, 4, 76, 69, 70, 84, 245, 1, 5, 82, 73, 71, 72, 84, 10, - 22, 32, 239, 9, 87, 8, 60, 7, 66, 69, 83, 73, 68, 69, 32, 206, 1, 70, - 179, 5, 84, 4, 40, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, 197, 149, 1, 23, - 87, 65, 82, 68, 83, 32, 72, 65, 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, - 32, 66, 65, 82, 66, 6, 22, 32, 251, 7, 87, 4, 22, 70, 179, 5, 84, 2, 217, - 195, 1, 3, 82, 79, 77, 4, 25, 4, 65, 86, 89, 32, 4, 26, 67, 155, 202, 1, - 65, 2, 189, 10, 7, 79, 77, 80, 82, 69, 83, 83, 2, 137, 9, 6, 85, 65, 68, - 82, 85, 80, 2, 171, 145, 2, 79, 4, 30, 65, 53, 3, 81, 85, 65, 2, 245, - 200, 1, 8, 78, 83, 45, 83, 69, 82, 73, 70, 2, 131, 9, 82, 36, 36, 2, 82, - 73, 229, 7, 2, 87, 79, 30, 40, 5, 65, 78, 71, 76, 69, 155, 7, 80, 28, 52, - 8, 45, 72, 69, 65, 68, 69, 68, 32, 219, 12, 32, 26, 48, 5, 65, 82, 82, - 79, 87, 174, 5, 68, 39, 80, 23, 11, 32, 20, 92, 17, 76, 69, 70, 84, 87, - 65, 82, 68, 83, 32, 79, 70, 32, 68, 79, 87, 78, 98, 84, 23, 87, 2, 37, 7, - 87, 65, 82, 68, 83, 32, 84, 2, 37, 7, 82, 73, 65, 78, 71, 76, 69, 2, 219, - 5, 45, 2, 171, 190, 1, 79, 16, 25, 4, 73, 84, 72, 32, 16, 114, 66, 28, 6, - 76, 79, 78, 71, 32, 84, 130, 1, 77, 34, 78, 34, 86, 34, 72, 149, 56, 6, - 68, 79, 85, 66, 76, 69, 2, 149, 2, 3, 79, 76, 68, 4, 17, 2, 73, 80, 4, - 11, 32, 4, 34, 76, 21, 4, 82, 73, 71, 72, 2, 17, 2, 69, 70, 2, 11, 84, 2, - 11, 87, 2, 243, 125, 65, 2, 121, 5, 69, 68, 73, 85, 77, 2, 89, 5, 65, 82, - 82, 79, 87, 2, 29, 5, 69, 82, 89, 32, 72, 2, 25, 4, 69, 65, 86, 89, 2, - 221, 177, 2, 4, 32, 83, 72, 65, 2, 11, 65, 2, 249, 1, 2, 83, 72, 2, 11, - 65, 2, 25, 4, 73, 82, 69, 68, 2, 29, 5, 32, 65, 82, 82, 79, 2, 211, 157, - 2, 87, 2, 11, 76, 2, 187, 192, 1, 69, 6, 74, 32, 61, 14, 45, 72, 69, 65, - 68, 69, 68, 32, 65, 82, 82, 79, 87, 32, 2, 25, 4, 72, 69, 65, 68, 2, 11, - 69, 2, 179, 191, 1, 68, 4, 42, 87, 253, 134, 1, 4, 70, 82, 79, 77, 2, 33, - 6, 73, 84, 72, 32, 84, 82, 2, 61, 13, 73, 65, 78, 71, 76, 69, 32, 65, 82, - 82, 79, 87, 72, 2, 149, 121, 2, 69, 65, 18, 88, 5, 65, 82, 82, 79, 87, - 149, 3, 12, 68, 79, 85, 66, 76, 69, 32, 65, 82, 82, 79, 87, 15, 11, 32, - 12, 108, 11, 79, 78, 32, 80, 69, 68, 69, 83, 84, 65, 76, 106, 87, 217, - 179, 1, 8, 70, 82, 79, 77, 32, 66, 65, 82, 7, 33, 6, 32, 87, 73, 84, 72, - 32, 4, 26, 86, 171, 180, 1, 72, 2, 205, 180, 1, 5, 69, 82, 84, 73, 67, 2, - 29, 5, 73, 84, 72, 73, 78, 2, 17, 2, 32, 84, 2, 37, 7, 82, 73, 65, 78, - 71, 76, 69, 2, 11, 32, 2, 11, 65, 2, 25, 4, 82, 82, 79, 87, 2, 11, 72, 2, - 195, 142, 2, 69, 5, 45, 9, 32, 79, 78, 32, 80, 69, 68, 69, 83, 2, 235, - 202, 1, 84, 240, 15, 86, 65, 254, 16, 83, 174, 3, 69, 234, 45, 73, 186, - 8, 79, 134, 2, 84, 21, 2, 85, 76, 218, 8, 116, 2, 73, 32, 128, 16, 17, - 82, 73, 65, 84, 73, 79, 78, 32, 83, 69, 76, 69, 67, 84, 79, 82, 45, 245, - 45, 2, 77, 80, 216, 4, 54, 67, 34, 70, 82, 81, 40, 2, 83, 89, 207, 95, - 68, 2, 11, 79, 2, 231, 176, 2, 77, 2, 11, 85, 2, 11, 76, 2, 11, 76, 2, - 11, 32, 2, 11, 83, 2, 147, 216, 1, 84, 2, 17, 2, 85, 69, 2, 215, 231, 1, - 83, 190, 4, 68, 7, 76, 76, 65, 66, 76, 69, 32, 197, 11, 5, 77, 66, 79, - 76, 32, 164, 4, 214, 1, 68, 70, 66, 2, 83, 2, 84, 2, 90, 70, 71, 122, 72, - 82, 75, 134, 1, 76, 130, 1, 77, 86, 78, 134, 3, 67, 2, 70, 2, 74, 2, 80, - 2, 82, 2, 86, 2, 89, 78, 87, 50, 69, 34, 79, 250, 73, 65, 2, 73, 3, 85, - 42, 66, 72, 162, 8, 79, 194, 133, 2, 69, 162, 64, 65, 2, 73, 3, 85, 28, - 230, 7, 72, 58, 79, 194, 133, 2, 69, 162, 64, 65, 2, 73, 3, 85, 34, 62, - 66, 202, 6, 69, 86, 79, 226, 197, 2, 65, 2, 73, 3, 85, 18, 106, 79, 222, - 5, 69, 182, 198, 2, 65, 2, 73, 3, 85, 24, 50, 79, 222, 5, 69, 178, 75, - 65, 2, 73, 3, 85, 7, 142, 204, 2, 78, 3, 79, 34, 70, 80, 206, 5, 79, 222, - 74, 65, 230, 186, 1, 69, 162, 64, 73, 3, 85, 18, 246, 4, 69, 86, 79, 222, - 74, 65, 134, 251, 1, 73, 3, 85, 16, 54, 69, 218, 4, 79, 226, 197, 2, 65, - 2, 73, 3, 85, 7, 26, 78, 159, 202, 2, 69, 2, 21, 3, 71, 84, 72, 2, 139, - 140, 2, 69, 42, 214, 3, 66, 0, 2, 71, 66, 58, 79, 194, 133, 2, 69, 162, - 64, 65, 2, 73, 3, 85, 90, 90, 68, 174, 1, 71, 126, 74, 2, 89, 58, 79, - 194, 133, 2, 69, 162, 64, 65, 2, 73, 3, 85, 24, 54, 79, 234, 135, 2, 69, - 162, 64, 65, 2, 73, 3, 85, 15, 36, 3, 76, 69, 32, 227, 199, 2, 79, 10, - 54, 83, 182, 168, 2, 68, 190, 28, 70, 2, 75, 3, 77, 2, 179, 168, 2, 79, - 25, 42, 71, 138, 247, 1, 65, 2, 69, 3, 79, 16, 50, 69, 86, 79, 226, 197, - 2, 65, 2, 73, 3, 85, 7, 178, 198, 2, 69, 3, 78, 14, 54, 79, 194, 133, 2, - 69, 162, 64, 65, 2, 73, 3, 85, 5, 223, 197, 2, 79, 28, 46, 69, 34, 79, - 250, 73, 65, 2, 73, 3, 85, 9, 150, 74, 69, 135, 251, 1, 78, 9, 246, 73, - 79, 135, 251, 1, 78, 26, 66, 68, 62, 70, 30, 74, 22, 75, 50, 78, 22, 84, - 151, 234, 1, 66, 6, 26, 79, 135, 243, 1, 65, 4, 130, 243, 1, 79, 135, 50, - 45, 4, 74, 69, 219, 192, 2, 65, 2, 199, 242, 1, 79, 4, 26, 69, 155, 242, - 1, 85, 2, 151, 242, 1, 69, 2, 163, 175, 2, 73, 6, 238, 241, 1, 73, 2, 79, - 195, 78, 65, 128, 4, 74, 49, 94, 50, 98, 51, 2, 52, 2, 53, 2, 54, 2, 55, - 2, 56, 3, 57, 223, 1, 182, 1, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, - 54, 2, 55, 2, 56, 3, 57, 137, 1, 90, 48, 2, 49, 2, 50, 2, 51, 2, 52, 94, - 53, 218, 191, 2, 54, 2, 55, 2, 56, 3, 57, 23, 178, 192, 2, 48, 2, 49, 2, - 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 17, 214, 191, 2, 48, - 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 194, 1, 116, 4, 68, 73, 67, 32, - 206, 19, 82, 168, 155, 1, 13, 67, 84, 79, 82, 32, 79, 82, 32, 67, 82, 79, - 83, 83, 219, 106, 83, 86, 60, 5, 83, 73, 71, 78, 32, 153, 10, 5, 84, 79, - 78, 69, 32, 48, 218, 2, 65, 216, 1, 17, 68, 79, 85, 66, 76, 69, 32, 65, - 78, 85, 83, 86, 65, 82, 65, 32, 65, 98, 74, 52, 6, 78, 73, 72, 83, 72, - 86, 22, 82, 240, 1, 8, 72, 69, 88, 73, 70, 79, 82, 77, 22, 76, 52, 4, 84, - 73, 82, 89, 22, 85, 60, 8, 86, 73, 83, 65, 82, 71, 65, 32, 237, 6, 17, - 89, 65, 74, 85, 82, 86, 69, 68, 73, 67, 32, 77, 73, 68, 76, 73, 78, 14, - 76, 8, 78, 85, 83, 86, 65, 82, 65, 32, 212, 1, 3, 84, 73, 75, 151, 2, 82, - 10, 134, 1, 65, 24, 4, 66, 65, 72, 73, 24, 9, 85, 66, 72, 65, 89, 65, 84, - 79, 32, 201, 4, 10, 86, 65, 77, 65, 71, 79, 77, 85, 75, 72, 2, 21, 3, 78, - 84, 65, 2, 21, 3, 82, 71, 79, 2, 11, 77, 2, 163, 9, 85, 2, 235, 245, 1, - 82, 2, 33, 6, 73, 72, 86, 65, 77, 85, 2, 151, 3, 76, 2, 203, 181, 2, 65, - 8, 144, 1, 15, 69, 86, 69, 82, 83, 69, 68, 32, 86, 73, 83, 65, 82, 71, - 65, 36, 9, 79, 84, 65, 84, 69, 68, 32, 65, 82, 57, 5, 84, 72, 65, 78, 71, - 4, 11, 32, 4, 218, 6, 65, 23, 85, 2, 25, 4, 68, 72, 65, 86, 2, 201, 243, - 1, 2, 73, 83, 2, 17, 2, 32, 76, 2, 21, 3, 79, 78, 71, 2, 229, 240, 1, 2, - 32, 65, 2, 171, 178, 2, 65, 2, 37, 7, 80, 65, 68, 72, 77, 65, 78, 2, 171, - 178, 2, 73, 10, 40, 3, 65, 78, 85, 2, 85, 179, 9, 83, 4, 25, 4, 68, 65, - 84, 84, 4, 11, 65, 5, 25, 4, 32, 87, 73, 84, 2, 11, 72, 2, 11, 32, 2, 11, - 84, 2, 11, 65, 2, 159, 170, 1, 73, 38, 128, 2, 5, 67, 65, 78, 68, 82, 16, - 2, 68, 79, 96, 2, 75, 65, 136, 1, 4, 80, 82, 69, 78, 16, 2, 82, 73, 106, - 84, 164, 1, 11, 89, 65, 74, 85, 82, 86, 69, 68, 73, 67, 32, 180, 1, 12, - 65, 84, 72, 65, 82, 86, 65, 86, 69, 68, 73, 67, 169, 231, 1, 2, 83, 72, - 4, 131, 19, 65, 6, 40, 5, 85, 66, 76, 69, 32, 191, 3, 84, 4, 22, 82, 211, - 5, 83, 2, 11, 73, 2, 251, 1, 78, 4, 56, 3, 82, 83, 72, 17, 7, 84, 72, 65, - 75, 65, 32, 65, 2, 139, 116, 65, 2, 17, 2, 78, 85, 2, 17, 2, 68, 65, 2, - 139, 139, 2, 84, 2, 131, 53, 75, 4, 82, 78, 237, 2, 15, 71, 86, 69, 68, - 73, 67, 32, 75, 65, 83, 72, 77, 73, 82, 73, 2, 219, 177, 1, 71, 6, 42, - 72, 24, 4, 82, 73, 80, 76, 19, 87, 2, 49, 3, 82, 69, 69, 2, 219, 2, 69, - 2, 11, 79, 2, 25, 4, 32, 68, 79, 84, 2, 11, 83, 2, 11, 32, 2, 167, 15, - 66, 8, 176, 1, 10, 65, 71, 71, 82, 65, 86, 65, 84, 69, 68, 22, 73, 105, - 27, 75, 65, 84, 72, 65, 75, 65, 32, 73, 78, 68, 69, 80, 69, 78, 68, 69, - 78, 84, 32, 83, 86, 65, 82, 73, 84, 65, 2, 17, 2, 32, 73, 2, 49, 10, 78, - 68, 69, 80, 69, 78, 68, 69, 78, 84, 2, 17, 2, 32, 83, 2, 189, 134, 2, 3, - 86, 65, 82, 5, 241, 10, 7, 32, 83, 67, 72, 82, 79, 69, 104, 62, 83, 16, - 6, 84, 73, 67, 65, 76, 32, 181, 17, 2, 89, 32, 2, 167, 88, 73, 76, 200, - 2, 4, 66, 65, 82, 32, 174, 3, 67, 42, 69, 62, 70, 38, 71, 32, 11, 73, 68, - 69, 79, 71, 82, 65, 80, 72, 73, 67, 48, 12, 75, 65, 78, 65, 32, 82, 69, - 80, 69, 65, 84, 32, 254, 1, 76, 194, 3, 77, 88, 17, 79, 78, 69, 32, 69, - 73, 71, 72, 84, 72, 32, 66, 76, 79, 67, 75, 45, 62, 82, 158, 1, 84, 218, - 1, 90, 173, 72, 3, 83, 73, 88, 8, 108, 6, 66, 69, 83, 73, 68, 69, 64, 8, - 68, 79, 85, 66, 76, 69, 32, 76, 20, 4, 84, 82, 73, 80, 143, 1, 87, 2, 17, - 2, 32, 82, 2, 21, 3, 73, 71, 72, 2, 159, 129, 1, 84, 2, 69, 2, 69, 70, 2, - 25, 4, 76, 69, 32, 82, 2, 21, 3, 73, 71, 72, 2, 11, 84, 2, 29, 5, 32, 84, - 85, 82, 78, 2, 11, 83, 2, 11, 84, 2, 203, 128, 1, 73, 2, 21, 3, 73, 84, - 72, 2, 17, 2, 32, 72, 2, 137, 244, 1, 7, 79, 82, 73, 90, 79, 78, 84, 2, - 141, 235, 1, 5, 65, 80, 65, 67, 73, 2, 25, 4, 76, 76, 73, 80, 2, 11, 83, - 2, 215, 229, 1, 73, 2, 11, 79, 2, 213, 82, 2, 85, 82, 2, 221, 155, 1, 3, - 79, 45, 75, 2, 17, 2, 32, 73, 2, 133, 185, 1, 2, 84, 69, 10, 120, 4, 77, - 65, 82, 75, 45, 22, 87, 73, 84, 72, 32, 86, 79, 73, 67, 69, 68, 32, 83, - 79, 85, 78, 68, 32, 77, 65, 82, 75, 7, 11, 32, 4, 50, 85, 21, 3, 76, 79, - 87, 5, 17, 2, 32, 85, 2, 17, 2, 80, 80, 2, 17, 2, 69, 82, 2, 153, 29, 2, - 32, 72, 16, 30, 65, 33, 3, 73, 78, 69, 2, 11, 68, 2, 151, 226, 1, 68, 15, - 11, 32, 12, 38, 69, 49, 5, 87, 73, 84, 72, 32, 2, 25, 4, 88, 84, 69, 78, - 2, 219, 206, 1, 83, 10, 56, 4, 67, 73, 82, 67, 98, 70, 26, 84, 151, 140, - 1, 77, 4, 11, 76, 4, 11, 69, 4, 11, 32, 4, 26, 66, 167, 161, 1, 65, 2, - 11, 69, 2, 223, 131, 1, 76, 2, 57, 3, 79, 85, 82, 2, 11, 72, 2, 21, 3, - 82, 69, 69, 2, 45, 9, 32, 84, 73, 67, 75, 32, 77, 65, 82, 2, 167, 223, 1, - 75, 2, 65, 14, 65, 76, 69, 32, 87, 73, 84, 72, 32, 83, 84, 82, 79, 75, 2, - 171, 149, 1, 69, 12, 150, 156, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 3, 55, - 4, 42, 65, 57, 6, 69, 83, 73, 83, 84, 79, 2, 25, 4, 67, 73, 78, 71, 2, - 11, 32, 2, 207, 121, 67, 2, 21, 3, 82, 32, 83, 2, 11, 69, 2, 159, 215, 1, - 71, 10, 32, 2, 65, 66, 106, 73, 19, 82, 6, 18, 32, 35, 85, 2, 11, 75, 2, - 179, 136, 2, 69, 4, 33, 6, 76, 65, 84, 73, 79, 78, 5, 251, 45, 32, 2, - 167, 9, 76, 2, 29, 5, 65, 70, 70, 73, 67, 2, 177, 238, 1, 2, 32, 76, 2, - 233, 106, 4, 73, 71, 90, 65, 26, 80, 6, 72, 69, 65, 86, 89, 32, 176, 5, - 3, 77, 85, 67, 241, 9, 3, 66, 79, 76, 20, 62, 69, 190, 1, 70, 38, 82, 82, - 83, 246, 1, 87, 215, 10, 71, 4, 25, 4, 73, 71, 72, 84, 4, 11, 32, 4, 22, - 80, 223, 2, 83, 2, 25, 4, 79, 73, 78, 84, 2, 17, 2, 69, 68, 2, 17, 2, 32, - 66, 2, 25, 4, 76, 65, 67, 75, 2, 11, 32, 2, 215, 79, 83, 2, 11, 73, 2, - 185, 1, 2, 86, 69, 2, 11, 69, 2, 29, 5, 86, 69, 82, 83, 69, 2, 17, 2, 32, - 83, 2, 231, 1, 79, 6, 30, 65, 42, 73, 147, 1, 79, 2, 11, 76, 2, 11, 84, - 2, 147, 116, 73, 2, 11, 88, 2, 11, 32, 2, 11, 83, 2, 21, 3, 80, 79, 75, - 2, 17, 2, 69, 68, 2, 11, 32, 2, 11, 65, 2, 11, 83, 2, 205, 78, 3, 84, 69, - 82, 2, 173, 13, 3, 76, 73, 68, 4, 21, 3, 72, 73, 84, 4, 11, 69, 4, 11, - 32, 4, 226, 64, 67, 163, 49, 83, 4, 11, 72, 4, 11, 32, 4, 18, 71, 39, 76, - 2, 69, 6, 82, 69, 65, 84, 69, 82, 2, 11, 69, 2, 11, 83, 2, 11, 83, 2, 17, - 2, 45, 84, 2, 187, 71, 72, 160, 1, 140, 1, 9, 66, 82, 65, 84, 73, 79, 78, - 32, 77, 34, 67, 36, 3, 68, 69, 79, 126, 69, 222, 1, 79, 22, 82, 21, 7, - 84, 72, 75, 85, 81, 73, 32, 2, 11, 79, 2, 183, 249, 1, 68, 2, 221, 129, - 1, 4, 84, 79, 82, 89, 6, 30, 32, 77, 3, 67, 65, 83, 4, 18, 67, 43, 71, 2, - 17, 2, 65, 77, 2, 203, 202, 1, 69, 2, 139, 119, 65, 2, 219, 71, 83, 6, + 67, 2, 80, 2, 84, 34, 78, 234, 222, 5, 66, 2, 68, 2, 70, 2, 71, 2, 72, 2, + 76, 2, 77, 2, 82, 2, 83, 2, 86, 2, 89, 247, 30, 79, 6, 26, 72, 255, 253, + 5, 79, 4, 134, 223, 5, 72, 247, 30, 79, 6, 230, 222, 5, 71, 2, 89, 247, + 30, 79, 4, 186, 172, 5, 65, 195, 52, 72, 10, 72, 2, 75, 79, 110, 78, 216, + 132, 1, 4, 72, 79, 32, 72, 247, 185, 3, 83, 4, 192, 133, 1, 3, 73, 32, + 75, 135, 247, 4, 78, 8, 58, 78, 230, 138, 1, 84, 234, 169, 2, 83, 251, + 195, 2, 69, 2, 251, 180, 3, 85, 26, 62, 65, 206, 4, 85, 206, 228, 1, 73, + 242, 145, 4, 69, 3, 79, 10, 178, 228, 5, 85, 214, 22, 65, 2, 77, 2, 78, + 3, 89, 110, 72, 7, 76, 69, 84, 84, 69, 82, 32, 238, 3, 83, 157, 1, 3, 88, + 65, 77, 96, 206, 1, 65, 80, 2, 76, 79, 12, 4, 72, 73, 71, 72, 126, 78, + 34, 85, 198, 133, 1, 80, 2, 84, 138, 95, 73, 194, 200, 1, 79, 190, 170, + 2, 66, 2, 67, 2, 68, 2, 71, 2, 77, 2, 81, 2, 86, 2, 89, 247, 30, 69, 16, + 222, 225, 5, 85, 214, 22, 65, 2, 69, 2, 75, 2, 77, 2, 78, 2, 80, 3, 84, + 21, 11, 87, 18, 11, 32, 18, 70, 75, 194, 158, 5, 78, 210, 57, 70, 2, 72, + 2, 80, 2, 84, 3, 88, 6, 142, 216, 5, 72, 2, 86, 247, 30, 79, 4, 230, 215, + 5, 71, 247, 30, 79, 9, 202, 228, 1, 69, 243, 145, 4, 65, 12, 76, 4, 73, + 71, 78, 32, 245, 156, 5, 9, 89, 77, 66, 79, 76, 32, 77, 85, 69, 10, 38, + 65, 206, 222, 5, 85, 255, 5, 79, 6, 202, 244, 5, 78, 86, 85, 3, 89, 2, + 171, 129, 1, 32, 138, 1, 52, 3, 82, 73, 32, 201, 229, 4, 4, 69, 79, 85, + 84, 136, 1, 82, 65, 20, 7, 76, 69, 84, 84, 69, 82, 32, 166, 2, 83, 78, + 86, 203, 252, 3, 68, 2, 155, 211, 1, 66, 88, 210, 1, 65, 158, 148, 2, 68, + 82, 82, 34, 84, 230, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, 126, 66, 2, + 67, 2, 71, 2, 74, 2, 75, 2, 80, 2, 83, 138, 69, 72, 2, 76, 2, 77, 2, 86, + 2, 89, 186, 2, 69, 3, 79, 11, 208, 190, 3, 7, 82, 67, 72, 65, 73, 67, 32, + 154, 179, 2, 65, 2, 73, 3, 85, 8, 25, 4, 73, 71, 78, 32, 8, 254, 211, 1, + 78, 138, 216, 3, 65, 239, 1, 86, 18, 49, 10, 79, 87, 69, 76, 32, 83, 73, + 71, 78, 32, 18, 250, 152, 2, 65, 38, 85, 186, 202, 1, 73, 198, 140, 2, + 69, 3, 79, 4, 134, 51, 70, 163, 161, 4, 79, 188, 6, 36, 3, 73, 76, 32, + 211, 200, 4, 65, 186, 6, 154, 3, 65, 106, 67, 194, 2, 68, 72, 3, 87, 69, + 84, 48, 9, 70, 82, 65, 67, 84, 73, 79, 78, 32, 232, 7, 9, 73, 78, 32, 80, + 79, 83, 83, 69, 83, 22, 76, 200, 2, 7, 78, 85, 77, 66, 69, 82, 32, 152, + 1, 18, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 32, 69, 78, 68, 32, + 79, 70, 54, 82, 42, 83, 166, 14, 84, 228, 1, 7, 86, 79, 87, 69, 76, 32, + 83, 100, 2, 89, 69, 168, 195, 4, 5, 77, 79, 78, 84, 72, 171, 118, 79, 6, + 80, 5, 83, 32, 65, 66, 79, 150, 138, 2, 85, 197, 245, 1, 5, 78, 68, 32, + 79, 68, 2, 143, 203, 3, 86, 52, 80, 9, 79, 78, 83, 79, 78, 65, 78, 84, + 32, 156, 21, 3, 85, 82, 82, 171, 9, 82, 48, 130, 1, 75, 22, 76, 22, 78, + 46, 84, 194, 191, 1, 83, 254, 82, 82, 158, 214, 3, 67, 2, 72, 2, 74, 2, + 77, 2, 80, 2, 86, 3, 89, 5, 207, 171, 5, 83, 7, 235, 236, 4, 76, 11, 150, + 235, 3, 78, 238, 253, 1, 71, 3, 89, 5, 215, 232, 5, 84, 26, 68, 2, 82, + 89, 164, 28, 2, 69, 66, 146, 149, 2, 65, 207, 194, 1, 73, 2, 225, 199, 1, + 7, 32, 67, 85, 76, 84, 73, 86, 42, 168, 1, 4, 79, 78, 69, 32, 220, 4, 6, + 84, 72, 82, 69, 69, 32, 169, 224, 5, 22, 68, 79, 87, 78, 83, 67, 65, 76, + 73, 78, 71, 32, 70, 65, 67, 84, 79, 82, 32, 75, 73, 73, 30, 112, 5, 69, + 73, 71, 72, 84, 34, 70, 40, 3, 72, 65, 76, 22, 79, 88, 4, 83, 73, 88, 84, + 74, 84, 203, 221, 3, 81, 4, 210, 3, 73, 219, 225, 5, 72, 4, 156, 3, 2, + 79, 82, 203, 219, 3, 73, 4, 251, 222, 1, 70, 2, 225, 2, 18, 78, 69, 45, + 72, 85, 78, 68, 82, 69, 68, 45, 65, 78, 68, 45, 83, 73, 88, 6, 140, 222, + 1, 5, 69, 69, 78, 84, 72, 141, 25, 5, 89, 45, 70, 79, 85, 8, 38, 72, 138, + 1, 87, 255, 220, 3, 69, 4, 132, 1, 18, 82, 69, 69, 45, 72, 85, 78, 68, + 82, 69, 68, 45, 65, 78, 68, 45, 84, 87, 173, 163, 4, 8, 73, 82, 84, 89, + 45, 83, 69, 67, 2, 17, 2, 69, 78, 2, 17, 2, 84, 73, 2, 223, 220, 3, 69, + 10, 58, 69, 28, 4, 83, 73, 88, 84, 82, 84, 179, 220, 3, 81, 2, 129, 1, 3, + 73, 71, 72, 4, 50, 69, 165, 221, 3, 6, 89, 45, 70, 79, 85, 82, 2, 161, + 221, 3, 2, 69, 78, 2, 21, 3, 87, 69, 78, 2, 237, 220, 3, 3, 84, 73, 69, + 2, 207, 218, 1, 83, 72, 48, 6, 69, 84, 84, 69, 82, 32, 211, 243, 3, 65, + 70, 194, 1, 78, 170, 201, 1, 84, 190, 54, 65, 82, 76, 38, 82, 134, 6, 85, + 206, 141, 1, 79, 238, 60, 73, 182, 196, 1, 83, 242, 7, 69, 234, 61, 67, + 2, 72, 2, 74, 2, 75, 2, 77, 2, 80, 2, 86, 3, 89, 10, 46, 78, 242, 218, 5, + 71, 2, 89, 187, 2, 65, 4, 238, 218, 5, 78, 187, 2, 65, 8, 38, 79, 222, + 134, 4, 84, 159, 79, 83, 4, 11, 78, 4, 17, 2, 69, 32, 4, 18, 72, 31, 84, + 2, 133, 72, 3, 85, 78, 68, 2, 185, 137, 2, 3, 72, 79, 85, 2, 17, 2, 32, + 84, 2, 11, 69, 2, 163, 191, 5, 88, 2, 17, 2, 85, 80, 2, 159, 187, 3, 69, + 194, 4, 152, 1, 5, 65, 76, 84, 32, 80, 20, 4, 73, 71, 78, 32, 206, 4, 80, + 28, 9, 84, 65, 82, 84, 73, 78, 71, 32, 70, 41, 8, 89, 76, 76, 65, 66, 76, + 69, 32, 2, 235, 221, 3, 65, 40, 90, 65, 48, 3, 67, 69, 86, 34, 75, 80, 2, + 77, 85, 102, 85, 14, 80, 118, 86, 211, 64, 78, 4, 216, 2, 4, 65, 90, 72, + 65, 191, 145, 5, 78, 2, 11, 73, 2, 223, 179, 5, 84, 6, 38, 85, 165, 179, + 5, 3, 65, 65, 67, 4, 18, 90, 87, 82, 2, 159, 196, 5, 72, 6, 60, 4, 75, + 75, 85, 82, 16, 2, 84, 72, 21, 3, 85, 86, 85, 2, 203, 82, 85, 2, 175, + 155, 3, 65, 2, 75, 90, 8, 26, 65, 251, 134, 5, 79, 6, 34, 84, 154, 153, + 4, 65, 15, 78, 2, 11, 72, 2, 17, 2, 65, 75, 2, 171, 177, 5, 75, 10, 38, + 65, 250, 81, 69, 227, 192, 4, 73, 4, 216, 102, 3, 82, 65, 65, 201, 249, + 2, 6, 75, 65, 73, 89, 65, 82, 2, 11, 69, 2, 187, 9, 78, 2, 17, 2, 82, 79, + 2, 227, 205, 4, 77, 148, 4, 130, 1, 75, 166, 1, 76, 166, 1, 78, 186, 1, + 82, 86, 83, 178, 1, 84, 214, 2, 67, 2, 72, 2, 74, 2, 77, 2, 80, 2, 86, 3, + 89, 46, 84, 2, 83, 83, 210, 251, 1, 65, 38, 85, 206, 141, 1, 79, 238, 60, + 73, 167, 204, 1, 69, 24, 250, 244, 1, 65, 250, 6, 85, 206, 141, 1, 79, + 238, 60, 73, 167, 204, 1, 69, 66, 78, 76, 182, 250, 1, 65, 38, 85, 206, + 141, 1, 79, 238, 60, 73, 167, 204, 1, 69, 44, 226, 6, 76, 210, 243, 1, + 65, 38, 85, 206, 141, 1, 79, 238, 60, 73, 167, 204, 1, 69, 110, 98, 78, + 174, 5, 71, 2, 89, 210, 243, 1, 65, 38, 85, 206, 141, 1, 79, 238, 60, 73, + 167, 204, 1, 69, 44, 170, 5, 78, 210, 243, 1, 65, 38, 85, 206, 141, 1, + 79, 238, 60, 73, 167, 204, 1, 69, 44, 214, 4, 82, 210, 243, 1, 65, 38, + 85, 206, 141, 1, 79, 238, 60, 73, 167, 204, 1, 69, 68, 90, 72, 170, 3, + 83, 210, 243, 1, 65, 38, 85, 206, 141, 1, 79, 238, 60, 73, 167, 204, 1, + 69, 24, 246, 246, 1, 65, 38, 85, 206, 141, 1, 79, 230, 2, 82, 138, 58, + 73, 167, 204, 1, 69, 44, 210, 2, 84, 210, 243, 1, 65, 38, 85, 206, 141, + 1, 79, 238, 60, 73, 167, 204, 1, 69, 6, 68, 2, 79, 84, 33, 11, 82, 65, + 68, 73, 84, 73, 79, 78, 65, 76, 32, 2, 11, 65, 2, 155, 197, 4, 76, 4, 24, + 2, 67, 82, 55, 78, 2, 17, 2, 69, 68, 2, 11, 73, 2, 203, 196, 4, 84, 2, + 11, 85, 2, 17, 2, 77, 66, 2, 123, 69, 22, 25, 4, 73, 71, 78, 32, 22, 206, + 243, 1, 65, 38, 85, 206, 141, 1, 79, 238, 60, 73, 167, 204, 1, 69, 2, 11, + 65, 2, 155, 195, 4, 82, 158, 15, 36, 5, 65, 66, 65, 84, 65, 35, 71, 2, + 11, 32, 2, 163, 215, 3, 84, 156, 15, 54, 69, 20, 3, 83, 65, 32, 213, 6, + 3, 85, 84, 32, 2, 195, 173, 4, 82, 178, 1, 52, 7, 76, 69, 84, 84, 69, 82, + 32, 171, 212, 3, 68, 158, 1, 210, 1, 65, 58, 70, 54, 72, 38, 76, 58, 77, + 54, 78, 50, 83, 122, 85, 114, 69, 2, 73, 2, 79, 2, 86, 182, 250, 4, 84, + 82, 67, 2, 68, 2, 71, 2, 75, 2, 80, 138, 69, 66, 2, 82, 2, 87, 2, 88, 2, + 89, 3, 90, 16, 146, 4, 87, 198, 194, 5, 67, 2, 81, 2, 88, 3, 90, 4, 164, + 245, 4, 5, 73, 78, 65, 76, 32, 251, 80, 65, 6, 186, 177, 1, 84, 179, 148, + 4, 65, 4, 176, 157, 4, 5, 79, 78, 71, 32, 85, 151, 168, 1, 65, 10, 142, + 197, 5, 65, 2, 67, 2, 81, 2, 88, 3, 90, 8, 162, 194, 5, 71, 2, 72, 2, 89, + 187, 2, 65, 8, 26, 72, 147, 196, 5, 65, 6, 40, 4, 79, 82, 84, 32, 231, + 195, 5, 65, 4, 184, 229, 3, 2, 85, 69, 233, 79, 2, 65, 87, 32, 58, 73, + 54, 69, 198, 194, 5, 67, 2, 81, 2, 88, 3, 90, 16, 50, 85, 198, 194, 5, + 67, 2, 81, 2, 88, 3, 90, 8, 194, 194, 5, 67, 2, 81, 2, 88, 3, 90, 232, + 13, 64, 10, 67, 79, 77, 80, 79, 78, 69, 78, 84, 45, 183, 155, 3, 73, 230, + 13, 78, 48, 178, 1, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 95, 56, + 198, 1, 86, 48, 130, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, + 56, 3, 57, 18, 158, 192, 5, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, + 2, 56, 3, 57, 200, 1, 166, 1, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, + 54, 2, 55, 2, 56, 3, 57, 168, 1, 74, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, + 53, 2, 54, 2, 55, 95, 56, 20, 158, 190, 5, 48, 2, 49, 2, 50, 2, 51, 2, + 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 8, 194, 189, 5, 48, 2, 49, 2, 50, + 3, 51, 4, 48, 6, 67, 65, 82, 84, 82, 73, 21, 2, 68, 82, 2, 175, 133, 4, + 68, 2, 251, 191, 4, 73, 2, 215, 179, 3, 82, 144, 3, 154, 1, 65, 152, 2, + 5, 68, 68, 89, 32, 66, 22, 76, 230, 14, 78, 144, 1, 5, 83, 84, 32, 84, + 85, 21, 12, 84, 82, 65, 71, 82, 65, 77, 32, 70, 79, 82, 32, 10, 68, 9, + 67, 85, 80, 32, 87, 73, 84, 72, 79, 58, 82, 211, 233, 4, 80, 2, 33, 6, + 85, 84, 32, 72, 65, 78, 2, 223, 147, 4, 68, 6, 72, 9, 45, 79, 70, 70, 32, + 67, 65, 76, 69, 29, 5, 68, 82, 79, 80, 45, 2, 253, 149, 4, 2, 78, 68, 4, + 170, 161, 3, 83, 205, 117, 4, 66, 65, 82, 66, 2, 179, 149, 4, 69, 218, 1, + 38, 69, 213, 2, 4, 85, 71, 85, 32, 16, 60, 6, 80, 72, 79, 78, 69, 32, + 246, 1, 83, 211, 184, 2, 86, 12, 132, 1, 3, 82, 69, 67, 208, 150, 1, 3, + 76, 79, 67, 178, 153, 3, 83, 189, 116, 13, 79, 78, 32, 84, 79, 80, 32, + 79, 70, 32, 77, 79, 68, 6, 36, 5, 69, 73, 86, 69, 82, 51, 79, 5, 29, 5, + 32, 87, 73, 84, 72, 2, 243, 38, 32, 2, 183, 146, 3, 82, 2, 11, 67, 2, + 151, 236, 3, 79, 202, 1, 162, 1, 65, 84, 15, 70, 82, 65, 67, 84, 73, 79, + 78, 32, 68, 73, 71, 73, 84, 32, 164, 2, 2, 76, 69, 252, 3, 5, 83, 73, 71, + 78, 32, 198, 2, 86, 247, 182, 3, 68, 4, 60, 9, 82, 67, 72, 65, 73, 67, + 32, 83, 72, 243, 210, 1, 73, 2, 167, 237, 2, 82, 14, 74, 84, 40, 2, 79, + 78, 81, 10, 90, 69, 82, 79, 32, 70, 79, 82, 32, 79, 8, 36, 3, 72, 82, 69, + 13, 2, 87, 79, 4, 11, 69, 4, 29, 5, 32, 70, 79, 82, 32, 4, 34, 79, 21, 4, + 69, 86, 69, 78, 2, 17, 2, 68, 68, 2, 49, 10, 32, 80, 79, 87, 69, 82, 83, + 32, 79, 70, 2, 133, 22, 2, 32, 70, 114, 44, 5, 84, 84, 69, 82, 32, 167, + 239, 4, 78, 112, 214, 1, 68, 54, 78, 106, 82, 38, 84, 130, 208, 1, 65, + 82, 76, 114, 86, 186, 5, 85, 206, 141, 1, 79, 238, 60, 73, 182, 196, 1, + 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 162, 7, 69, 234, 61, 72, + 2, 77, 3, 89, 10, 242, 231, 4, 68, 138, 69, 72, 2, 90, 187, 2, 65, 10, + 42, 65, 158, 172, 5, 71, 2, 78, 3, 89, 5, 41, 8, 75, 65, 65, 82, 65, 32, + 80, 79, 2, 251, 36, 76, 6, 150, 209, 1, 82, 131, 221, 3, 65, 10, 178, + 230, 4, 84, 138, 69, 72, 2, 83, 187, 2, 65, 20, 86, 67, 194, 1, 83, 204, + 35, 3, 84, 85, 85, 222, 106, 78, 190, 66, 65, 187, 151, 3, 86, 6, 60, 9, + 79, 77, 66, 73, 78, 73, 78, 71, 32, 215, 142, 1, 65, 4, 70, 65, 221, 174, + 4, 11, 67, 65, 78, 68, 82, 65, 66, 73, 78, 68, 85, 2, 33, 6, 78, 85, 83, + 86, 65, 82, 2, 183, 174, 4, 65, 2, 11, 73, 2, 137, 238, 3, 3, 68, 68, 72, + 30, 49, 10, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 30, 166, 211, 1, 65, + 38, 85, 22, 86, 186, 141, 1, 79, 238, 60, 73, 167, 204, 1, 69, 6, 80, 10, + 78, 73, 83, 32, 82, 65, 67, 81, 85, 69, 158, 137, 3, 71, 139, 160, 2, 84, + 2, 11, 84, 2, 25, 4, 32, 65, 78, 68, 2, 187, 158, 3, 32, 2, 147, 146, 5, + 66, 162, 1, 210, 2, 65, 134, 1, 66, 174, 1, 67, 222, 2, 68, 202, 3, 69, + 154, 2, 70, 182, 1, 71, 198, 1, 72, 64, 8, 89, 79, 85, 84, 72, 70, 85, + 76, 52, 2, 73, 78, 46, 75, 98, 76, 146, 1, 77, 134, 1, 79, 62, 80, 142, + 1, 82, 210, 1, 83, 224, 1, 14, 86, 65, 83, 84, 78, 69, 83, 83, 32, 79, + 82, 32, 87, 65, 12, 2, 87, 65, 138, 94, 85, 167, 159, 4, 74, 8, 88, 4, + 67, 67, 85, 77, 22, 83, 228, 20, 2, 68, 86, 221, 202, 1, 5, 71, 71, 82, + 65, 86, 2, 195, 190, 1, 85, 2, 227, 225, 4, 67, 6, 92, 7, 79, 76, 68, 32, + 82, 69, 83, 32, 5, 82, 65, 78, 67, 72, 229, 152, 4, 3, 65, 82, 82, 2, + 197, 211, 4, 3, 79, 76, 85, 2, 11, 73, 2, 205, 170, 1, 3, 78, 71, 32, 22, + 54, 72, 20, 3, 76, 79, 83, 66, 79, 167, 157, 2, 69, 2, 211, 235, 3, 65, + 6, 26, 69, 171, 128, 4, 85, 4, 222, 253, 1, 68, 167, 140, 2, 78, 12, 28, + 3, 77, 80, 76, 35, 78, 4, 246, 17, 73, 219, 191, 4, 69, 8, 32, 4, 83, 84, + 65, 78, 23, 84, 2, 147, 144, 5, 67, 6, 46, 69, 20, 3, 82, 65, 82, 251, + 143, 4, 65, 2, 199, 208, 4, 78, 2, 155, 176, 3, 73, 20, 80, 4, 65, 82, + 75, 69, 22, 69, 210, 1, 73, 74, 85, 197, 129, 5, 3, 79, 85, 66, 2, 151, + 207, 4, 78, 6, 132, 1, 19, 70, 69, 67, 84, 73, 86, 69, 78, 69, 83, 83, + 32, 79, 82, 32, 68, 73, 83, 84, 34, 80, 137, 7, 6, 67, 73, 83, 73, 86, + 69, 2, 11, 79, 2, 163, 206, 4, 82, 2, 11, 65, 2, 11, 82, 2, 143, 10, 84, + 8, 68, 6, 70, 70, 73, 67, 85, 76, 34, 77, 161, 12, 4, 86, 69, 82, 71, 2, + 11, 84, 2, 223, 135, 4, 73, 4, 140, 1, 2, 73, 78, 191, 203, 4, 77, 14, + 100, 5, 77, 66, 69, 76, 76, 34, 78, 124, 4, 88, 72, 65, 85, 172, 106, 3, + 84, 69, 82, 215, 165, 3, 65, 2, 137, 217, 4, 3, 73, 83, 72, 6, 80, 4, 68, + 69, 65, 86, 20, 4, 76, 65, 82, 71, 229, 151, 3, 4, 67, 79, 85, 78, 2, + 247, 162, 4, 79, 2, 131, 216, 4, 69, 2, 211, 202, 4, 83, 12, 70, 79, 76, + 3, 85, 76, 76, 196, 5, 3, 65, 73, 76, 235, 233, 4, 76, 4, 18, 76, 35, 83, + 2, 173, 201, 4, 3, 76, 79, 87, 2, 205, 4, 2, 84, 69, 4, 214, 197, 3, 32, + 199, 59, 78, 10, 96, 8, 65, 84, 72, 69, 82, 73, 78, 71, 22, 79, 64, 3, + 82, 69, 65, 65, 5, 85, 65, 82, 68, 69, 5, 163, 153, 4, 32, 2, 41, 8, 73, + 78, 71, 32, 84, 79, 32, 77, 2, 159, 227, 4, 69, 2, 75, 84, 4, 48, 2, 65, + 82, 33, 6, 79, 76, 68, 73, 78, 71, 2, 11, 68, 2, 247, 254, 3, 78, 2, 11, + 32, 2, 227, 248, 1, 66, 4, 26, 67, 159, 217, 4, 78, 2, 143, 5, 82, 4, 60, + 7, 69, 69, 80, 73, 78, 71, 32, 169, 193, 4, 2, 73, 78, 2, 11, 83, 2, 247, + 139, 3, 77, 6, 18, 65, 107, 69, 4, 60, 3, 66, 79, 85, 21, 8, 87, 32, 79, + 82, 32, 77, 79, 68, 2, 191, 196, 4, 82, 2, 223, 137, 4, 69, 2, 215, 196, + 4, 71, 6, 26, 65, 30, 69, 47, 73, 2, 229, 195, 4, 2, 83, 83, 2, 11, 65, + 2, 11, 83, 2, 251, 241, 3, 85, 2, 11, 82, 2, 247, 205, 4, 69, 4, 220, + 209, 3, 7, 78, 32, 84, 72, 69, 32, 86, 199, 112, 80, 8, 54, 65, 64, 4, + 69, 78, 69, 84, 229, 97, 2, 85, 82, 4, 22, 84, 243, 2, 67, 2, 17, 2, 84, + 69, 2, 131, 195, 4, 82, 2, 131, 205, 1, 82, 12, 30, 69, 157, 1, 2, 73, + 84, 10, 34, 76, 22, 83, 191, 239, 4, 65, 2, 219, 232, 1, 69, 6, 18, 73, + 51, 80, 4, 30, 68, 137, 1, 2, 83, 84, 2, 147, 1, 69, 2, 11, 79, 2, 239, + 133, 4, 78, 2, 163, 133, 4, 85, 10, 34, 69, 64, 2, 73, 78, 23, 84, 2, 11, + 86, 2, 17, 2, 69, 82, 2, 11, 65, 2, 159, 211, 4, 78, 2, 131, 191, 4, 75, + 6, 42, 79, 209, 138, 3, 4, 82, 69, 78, 71, 4, 26, 80, 219, 248, 4, 86, 2, + 11, 80, 2, 235, 215, 3, 65, 2, 39, 83, 4, 26, 73, 191, 236, 4, 84, 2, + 223, 189, 4, 84, 226, 2, 78, 65, 182, 31, 69, 146, 2, 73, 206, 1, 79, + 100, 3, 82, 69, 69, 187, 8, 85, 146, 2, 44, 4, 65, 78, 65, 32, 145, 10, + 2, 73, 32, 100, 122, 65, 38, 69, 76, 7, 76, 69, 84, 84, 69, 82, 32, 154, + 7, 79, 76, 3, 73, 66, 73, 0, 3, 85, 66, 85, 45, 2, 83, 85, 4, 184, 8, 3, + 65, 66, 65, 3, 66, 6, 58, 66, 0, 3, 69, 66, 69, 245, 7, 4, 89, 66, 69, + 89, 2, 243, 7, 69, 78, 202, 1, 65, 42, 68, 82, 70, 2, 81, 14, 71, 50, 72, + 38, 75, 62, 76, 32, 3, 77, 69, 69, 20, 2, 67, 72, 2, 74, 2, 80, 18, 78, + 42, 83, 94, 84, 102, 86, 2, 87, 42, 90, 246, 143, 3, 66, 2, 82, 3, 89, 4, + 252, 1, 2, 76, 73, 159, 227, 4, 73, 6, 30, 65, 29, 3, 72, 65, 65, 4, 218, + 2, 65, 255, 1, 86, 2, 195, 228, 4, 76, 2, 123, 65, 6, 110, 65, 86, 78, + 213, 226, 4, 3, 72, 65, 73, 4, 166, 147, 3, 72, 255, 242, 1, 65, 4, 26, + 65, 235, 146, 3, 72, 2, 11, 65, 2, 167, 227, 4, 70, 4, 18, 65, 35, 72, 2, + 11, 65, 2, 243, 226, 4, 77, 2, 211, 1, 65, 4, 192, 226, 4, 2, 79, 79, + 191, 34, 65, 8, 32, 2, 65, 65, 18, 72, 23, 69, 2, 163, 16, 68, 4, 18, 69, + 87, 65, 2, 211, 225, 4, 69, 10, 62, 65, 16, 3, 72, 65, 65, 178, 144, 3, + 84, 183, 245, 1, 79, 2, 131, 1, 86, 5, 251, 224, 4, 76, 2, 17, 2, 65, 65, + 2, 211, 224, 4, 86, 6, 26, 65, 143, 133, 5, 79, 4, 26, 86, 243, 132, 5, + 65, 2, 21, 3, 73, 89, 65, 2, 255, 240, 4, 78, 6, 48, 3, 65, 66, 79, 14, + 66, 1, 3, 79, 66, 79, 2, 23, 65, 2, 11, 79, 2, 11, 70, 2, 11, 73, 2, 135, + 240, 4, 76, 2, 155, 131, 4, 75, 174, 1, 26, 67, 147, 143, 3, 68, 154, 1, + 132, 1, 9, 72, 65, 82, 65, 67, 84, 69, 82, 32, 213, 215, 4, 17, 85, 82, + 82, 69, 78, 67, 89, 32, 83, 89, 77, 66, 79, 76, 32, 66, 65, 152, 1, 176, + 2, 6, 66, 79, 32, 66, 65, 73, 16, 6, 67, 72, 79, 32, 67, 72, 56, 3, 68, + 79, 32, 44, 2, 70, 79, 76, 3, 72, 79, 32, 66, 75, 190, 1, 76, 138, 1, 77, + 252, 1, 7, 65, 78, 71, 75, 72, 65, 78, 46, 78, 158, 1, 80, 234, 1, 82, + 70, 83, 238, 2, 84, 224, 2, 3, 87, 79, 32, 34, 89, 225, 150, 4, 2, 79, + 32, 2, 143, 12, 77, 8, 192, 129, 3, 2, 65, 78, 138, 173, 1, 73, 167, 58, + 79, 4, 132, 218, 4, 3, 67, 72, 65, 227, 33, 68, 6, 32, 2, 32, 70, 21, 2, + 78, 71, 4, 207, 128, 3, 65, 2, 139, 178, 3, 77, 4, 40, 4, 78, 79, 75, 72, + 191, 252, 4, 72, 2, 207, 250, 4, 85, 14, 40, 2, 72, 79, 229, 9, 3, 79, + 32, 75, 12, 26, 32, 191, 131, 4, 77, 10, 36, 2, 75, 72, 57, 3, 82, 65, + 75, 8, 158, 9, 87, 150, 234, 3, 85, 210, 57, 79, 139, 60, 65, 2, 215, + 163, 4, 72, 8, 76, 2, 79, 32, 224, 11, 8, 65, 75, 75, 72, 65, 78, 71, 89, + 235, 239, 4, 85, 4, 32, 2, 67, 72, 163, 170, 4, 76, 2, 139, 217, 4, 85, + 16, 28, 2, 65, 73, 211, 52, 79, 14, 42, 32, 176, 1, 3, 84, 65, 73, 19, + 89, 10, 76, 4, 67, 72, 65, 84, 44, 5, 72, 65, 78, 45, 65, 22, 84, 159, + 246, 4, 69, 2, 11, 84, 2, 11, 65, 2, 163, 247, 4, 87, 2, 151, 240, 3, 75, + 4, 190, 218, 4, 72, 159, 11, 82, 2, 203, 2, 75, 2, 161, 207, 4, 2, 65, + 77, 8, 60, 3, 71, 79, 32, 32, 3, 73, 75, 72, 29, 3, 79, 32, 78, 2, 11, + 78, 2, 179, 211, 4, 71, 2, 205, 219, 4, 2, 65, 72, 4, 138, 168, 4, 69, + 227, 79, 85, 12, 68, 6, 65, 73, 89, 65, 78, 78, 22, 72, 217, 212, 4, 3, + 79, 32, 80, 2, 171, 227, 4, 79, 8, 36, 3, 73, 78, 84, 21, 2, 79, 32, 2, + 223, 209, 4, 72, 6, 44, 2, 80, 72, 161, 5, 4, 83, 65, 77, 80, 4, 138, + 165, 4, 85, 155, 1, 65, 4, 32, 2, 79, 32, 195, 245, 4, 85, 2, 11, 82, 2, + 251, 242, 4, 85, 36, 44, 4, 65, 82, 65, 32, 225, 1, 2, 79, 32, 28, 62, + 65, 130, 1, 85, 238, 230, 2, 73, 198, 140, 2, 69, 3, 79, 13, 64, 6, 73, + 32, 77, 65, 73, 77, 238, 243, 4, 65, 2, 69, 3, 77, 4, 26, 65, 183, 167, + 3, 85, 2, 11, 76, 2, 235, 223, 4, 65, 9, 142, 179, 4, 69, 163, 64, 85, 8, + 24, 2, 82, 85, 23, 83, 2, 155, 223, 4, 83, 6, 198, 208, 4, 65, 226, 31, + 85, 187, 2, 79, 18, 30, 72, 133, 2, 2, 79, 32, 14, 48, 6, 65, 78, 84, 72, + 65, 75, 21, 2, 79, 32, 2, 175, 232, 3, 72, 12, 80, 8, 78, 65, 78, 71, 77, + 79, 78, 84, 20, 4, 80, 72, 85, 84, 13, 2, 84, 72, 2, 131, 210, 4, 72, 2, + 123, 72, 8, 34, 65, 190, 159, 4, 79, 3, 85, 4, 150, 164, 3, 72, 159, 204, + 1, 78, 4, 38, 84, 225, 182, 2, 3, 80, 65, 84, 2, 243, 208, 4, 65, 2, 11, + 87, 2, 195, 153, 3, 65, 6, 30, 65, 45, 3, 79, 32, 89, 2, 21, 3, 77, 65, + 75, 2, 223, 162, 3, 75, 4, 238, 157, 4, 73, 227, 77, 65, 12, 26, 82, 167, + 199, 2, 84, 10, 30, 69, 145, 1, 2, 77, 79, 6, 18, 32, 107, 70, 4, 84, 11, + 68, 79, 69, 83, 32, 78, 79, 84, 32, 69, 88, 229, 228, 3, 4, 69, 88, 73, + 83, 2, 171, 127, 73, 2, 211, 202, 3, 79, 4, 46, 77, 177, 194, 3, 5, 68, + 89, 78, 65, 77, 2, 191, 178, 3, 69, 10, 18, 78, 95, 82, 8, 26, 32, 235, + 227, 3, 75, 6, 26, 83, 203, 224, 2, 71, 4, 170, 211, 2, 65, 187, 219, 1, + 80, 2, 21, 3, 68, 32, 80, 2, 25, 4, 76, 65, 67, 69, 2, 17, 2, 32, 77, 2, + 159, 213, 3, 69, 4, 56, 4, 85, 71, 72, 84, 189, 212, 3, 4, 78, 71, 32, + 83, 2, 133, 192, 1, 5, 32, 66, 65, 76, 76, 46, 22, 32, 207, 3, 45, 30, + 154, 1, 68, 90, 76, 118, 82, 170, 158, 1, 66, 86, 67, 194, 6, 83, 254, + 166, 1, 80, 253, 22, 15, 78, 69, 84, 87, 79, 82, 75, 69, 68, 32, 67, 79, + 77, 80, 85, 4, 64, 10, 73, 77, 69, 78, 83, 73, 79, 78, 65, 76, 135, 162, + 1, 79, 2, 175, 193, 3, 32, 6, 80, 12, 73, 78, 69, 83, 32, 67, 79, 78, 86, + 69, 82, 71, 249, 154, 1, 2, 69, 70, 4, 153, 188, 4, 3, 73, 78, 71, 10, + 40, 4, 65, 89, 83, 32, 155, 154, 1, 73, 8, 238, 196, 2, 66, 130, 165, 1, + 65, 130, 82, 76, 31, 82, 16, 44, 2, 68, 32, 254, 3, 80, 247, 160, 1, 69, + 12, 196, 2, 12, 84, 79, 80, 45, 76, 73, 71, 72, 84, 69, 68, 32, 80, 17, + 76, 69, 70, 84, 45, 76, 73, 71, 72, 84, 69, 68, 32, 68, 79, 87, 78, 0, + 16, 82, 73, 71, 72, 84, 45, 76, 73, 71, 72, 84, 69, 68, 32, 85, 80, 221, + 137, 2, 25, 66, 79, 84, 84, 79, 77, 45, 76, 73, 71, 72, 84, 69, 68, 32, + 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 6, 76, 4, 76, 69, 70, 84, 69, 11, + 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 32, 2, 11, 87, 2, 25, 4, 65, 82, + 68, 83, 2, 173, 243, 1, 2, 32, 69, 4, 146, 243, 1, 69, 159, 22, 65, 2, + 177, 163, 4, 5, 69, 82, 45, 69, 77, 8, 34, 77, 85, 4, 78, 68, 69, 82, 4, + 21, 3, 66, 83, 32, 4, 38, 85, 229, 228, 2, 3, 68, 79, 87, 2, 235, 217, 3, + 80, 4, 216, 177, 3, 10, 32, 67, 76, 79, 85, 68, 32, 65, 78, 68, 181, 48, + 2, 83, 84, 230, 5, 204, 1, 6, 66, 69, 84, 65, 78, 32, 148, 45, 6, 69, 32, + 79, 86, 69, 82, 72, 7, 70, 73, 78, 65, 71, 72, 32, 206, 8, 71, 152, 1, 3, + 76, 68, 69, 252, 2, 2, 77, 69, 60, 2, 78, 89, 78, 82, 171, 208, 3, 67, + 160, 3, 228, 2, 18, 65, 83, 84, 82, 79, 76, 79, 71, 73, 67, 65, 76, 32, + 83, 73, 71, 78, 32, 172, 1, 18, 67, 65, 78, 84, 73, 76, 76, 65, 84, 73, + 79, 78, 32, 83, 73, 71, 78, 32, 172, 1, 6, 68, 73, 71, 73, 84, 32, 100, + 9, 75, 85, 32, 82, 85, 32, 75, 72, 65, 26, 76, 176, 3, 5, 77, 65, 82, 75, + 32, 222, 18, 83, 181, 15, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, + 6, 46, 83, 169, 40, 6, 45, 75, 72, 89, 85, 68, 4, 104, 8, 68, 79, 78, 71, + 32, 84, 83, 72, 169, 21, 13, 71, 82, 65, 32, 71, 67, 65, 78, 32, 45, 67, + 72, 65, 2, 199, 31, 85, 8, 148, 1, 7, 83, 66, 85, 66, 32, 45, 67, 180, + 207, 3, 5, 72, 69, 65, 86, 89, 0, 5, 76, 73, 71, 72, 84, 233, 100, 8, 67, + 65, 78, 71, 32, 84, 69, 45, 2, 167, 205, 3, 72, 40, 144, 229, 2, 4, 72, + 65, 76, 70, 82, 70, 30, 83, 42, 84, 62, 90, 210, 86, 78, 14, 79, 227, + 112, 69, 5, 221, 10, 2, 32, 66, 92, 96, 6, 69, 84, 84, 69, 82, 32, 153, + 2, 13, 79, 71, 79, 84, 89, 80, 69, 32, 83, 73, 71, 78, 32, 88, 230, 1, + 75, 170, 120, 82, 168, 146, 3, 10, 70, 73, 88, 69, 68, 45, 70, 79, 82, + 77, 202, 1, 68, 86, 78, 46, 83, 38, 84, 46, 66, 2, 67, 2, 71, 2, 80, 2, + 90, 138, 69, 45, 2, 72, 2, 74, 2, 76, 2, 77, 2, 87, 2, 89, 187, 2, 65, 8, + 226, 210, 4, 83, 14, 72, 2, 75, 187, 2, 65, 4, 224, 25, 3, 76, 72, 65, + 13, 4, 67, 72, 65, 68, 80, 254, 2, 66, 176, 1, 8, 77, 78, 89, 65, 77, 32, + 89, 73, 114, 67, 172, 2, 13, 89, 73, 71, 32, 77, 71, 79, 32, 84, 83, 72, + 69, 71, 190, 1, 71, 212, 2, 9, 65, 78, 71, 32, 75, 72, 65, 78, 71, 58, + 72, 48, 2, 73, 78, 246, 1, 78, 222, 1, 82, 118, 83, 46, 84, 36, 4, 76, + 69, 65, 68, 220, 105, 2, 80, 65, 173, 191, 1, 17, 68, 69, 76, 73, 77, 73, + 84, 69, 82, 32, 84, 83, 72, 69, 71, 32, 66, 10, 52, 9, 75, 65, 45, 32, + 83, 72, 79, 71, 32, 27, 83, 4, 142, 1, 71, 67, 89, 6, 34, 75, 201, 21, 3, + 68, 85, 83, 4, 56, 6, 65, 45, 32, 83, 72, 79, 89, 4, 85, 82, 32, 89, 2, + 21, 3, 71, 32, 71, 2, 41, 8, 73, 32, 77, 71, 79, 32, 82, 71, 2, 179, 131, + 3, 89, 2, 221, 2, 2, 73, 71, 12, 84, 5, 65, 82, 69, 84, 32, 240, 1, 2, + 72, 69, 29, 7, 76, 79, 83, 73, 78, 71, 32, 6, 112, 12, 45, 68, 90, 85, + 68, 32, 82, 84, 65, 71, 83, 32, 97, 12, 89, 73, 71, 32, 77, 71, 79, 32, + 80, 72, 85, 82, 4, 42, 66, 37, 6, 77, 69, 32, 76, 79, 78, 2, 33, 6, 90, + 72, 73, 32, 77, 73, 2, 203, 22, 71, 2, 225, 3, 3, 32, 83, 72, 2, 137, + 189, 2, 2, 32, 77, 4, 68, 13, 66, 82, 68, 65, 32, 82, 78, 89, 73, 78, 71, + 32, 89, 3, 89, 2, 213, 5, 11, 73, 71, 32, 77, 71, 79, 32, 83, 71, 65, 66, + 12, 68, 4, 84, 69, 82, 32, 141, 2, 8, 85, 71, 32, 82, 84, 65, 71, 83, 8, + 56, 8, 89, 73, 71, 32, 77, 71, 79, 32, 191, 132, 4, 84, 6, 68, 4, 45, 85, + 77, 32, 117, 9, 84, 82, 85, 78, 67, 65, 84, 69, 68, 4, 88, 7, 82, 78, 65, + 77, 32, 66, 67, 245, 2, 10, 71, 84, 69, 82, 32, 84, 83, 72, 69, 71, 2, + 241, 2, 2, 65, 68, 2, 195, 198, 4, 32, 4, 21, 3, 32, 71, 89, 4, 238, 248, + 3, 79, 135, 18, 65, 2, 17, 2, 65, 76, 2, 205, 163, 4, 2, 65, 78, 6, 92, + 6, 73, 84, 73, 65, 76, 32, 145, 129, 4, 11, 84, 69, 82, 83, 89, 76, 76, + 65, 66, 73, 67, 4, 68, 13, 66, 82, 68, 65, 32, 82, 78, 89, 73, 78, 71, + 32, 89, 3, 89, 2, 53, 11, 73, 71, 32, 77, 71, 79, 32, 77, 68, 85, 78, 2, + 143, 165, 4, 32, 10, 72, 10, 71, 65, 83, 32, 66, 90, 85, 78, 71, 32, 77, + 4, 89, 73, 83, 32, 4, 56, 3, 83, 71, 79, 237, 162, 4, 5, 78, 89, 73, 32, + 90, 2, 251, 9, 82, 6, 44, 5, 84, 83, 72, 69, 71, 143, 254, 3, 83, 5, 255, + 253, 3, 32, 4, 220, 253, 3, 8, 71, 89, 65, 32, 71, 82, 65, 77, 1, 14, 73, + 78, 32, 67, 72, 69, 78, 32, 83, 80, 85, 78, 71, 83, 4, 232, 252, 3, 4, + 66, 82, 85, 76, 39, 72, 6, 32, 4, 82, 65, 73, 76, 55, 83, 2, 225, 7, 9, + 73, 78, 71, 32, 77, 67, 72, 65, 78, 4, 56, 5, 65, 32, 45, 80, 72, 173, + 251, 3, 3, 72, 69, 71, 2, 147, 157, 4, 82, 156, 1, 84, 4, 73, 71, 78, 32, + 228, 6, 9, 85, 66, 74, 79, 73, 78, 69, 68, 32, 143, 4, 89, 42, 176, 1, 4, + 71, 82, 85, 32, 96, 2, 76, 67, 30, 77, 36, 11, 78, 89, 73, 32, 90, 76, + 65, 32, 78, 65, 65, 22, 82, 252, 2, 2, 89, 65, 130, 4, 73, 165, 4, 5, 83, + 78, 65, 32, 76, 4, 40, 3, 67, 65, 78, 1, 3, 77, 69, 68, 2, 25, 4, 32, 82, + 71, 89, 2, 169, 4, 2, 73, 78, 4, 238, 3, 73, 179, 4, 69, 4, 136, 4, 2, + 65, 82, 231, 3, 67, 2, 179, 153, 4, 32, 20, 116, 4, 68, 69, 76, 32, 240, + 1, 10, 74, 69, 83, 32, 83, 85, 32, 78, 71, 65, 145, 245, 3, 6, 78, 65, + 77, 32, 66, 67, 16, 52, 5, 68, 75, 65, 82, 32, 53, 4, 78, 65, 71, 32, 8, + 94, 71, 169, 208, 2, 6, 82, 68, 69, 76, 32, 78, 8, 42, 71, 69, 6, 82, 68, + 69, 76, 32, 68, 6, 46, 67, 220, 148, 2, 2, 78, 89, 231, 123, 83, 2, 143, + 187, 4, 73, 2, 147, 152, 3, 75, 2, 187, 201, 2, 32, 4, 18, 78, 71, 82, 2, + 11, 71, 2, 21, 3, 32, 82, 84, 2, 11, 65, 2, 135, 253, 3, 71, 2, 17, 2, + 32, 84, 2, 171, 164, 3, 83, 94, 68, 7, 76, 69, 84, 84, 69, 82, 32, 145, + 2, 5, 83, 73, 71, 78, 32, 88, 220, 1, 10, 70, 73, 88, 69, 68, 45, 70, 79, + 82, 77, 242, 238, 3, 68, 50, 75, 38, 78, 46, 83, 38, 84, 46, 66, 2, 67, + 2, 71, 2, 80, 2, 90, 138, 69, 45, 2, 72, 2, 74, 2, 76, 2, 77, 2, 82, 2, + 87, 2, 89, 187, 2, 65, 6, 11, 32, 6, 186, 181, 4, 82, 2, 87, 3, 89, 6, + 38, 73, 50, 77, 33, 3, 76, 67, 69, 2, 45, 9, 78, 86, 69, 82, 84, 69, 68, + 32, 77, 2, 11, 67, 2, 45, 2, 72, 85, 2, 25, 4, 32, 84, 83, 65, 2, 11, 32, + 2, 147, 234, 2, 67, 20, 60, 6, 76, 76, 65, 66, 76, 69, 21, 5, 77, 66, 79, + 76, 32, 2, 247, 164, 4, 32, 18, 104, 4, 68, 82, 73, 76, 32, 6, 78, 79, + 82, 32, 66, 85, 130, 1, 80, 93, 7, 82, 68, 79, 32, 82, 74, 69, 2, 11, 32, + 2, 231, 143, 4, 66, 9, 11, 32, 6, 72, 4, 66, 90, 72, 73, 0, 4, 71, 83, + 85, 77, 1, 4, 78, 89, 73, 83, 2, 145, 212, 2, 5, 32, 45, 75, 72, 89, 4, + 52, 6, 65, 68, 77, 65, 32, 71, 21, 3, 72, 85, 82, 2, 231, 230, 2, 68, 2, + 199, 117, 32, 5, 181, 245, 2, 6, 32, 82, 71, 89, 65, 32, 30, 116, 8, 82, + 69, 86, 69, 82, 83, 69, 68, 194, 90, 85, 22, 86, 186, 141, 1, 79, 238, + 60, 73, 166, 204, 1, 69, 235, 61, 65, 4, 245, 164, 2, 2, 32, 73, 2, 25, + 4, 32, 73, 78, 70, 2, 11, 73, 2, 11, 78, 2, 139, 193, 2, 73, 118, 216, 1, + 9, 67, 79, 78, 83, 79, 78, 65, 78, 84, 20, 7, 76, 69, 84, 84, 69, 82, 32, + 164, 6, 20, 77, 79, 68, 73, 70, 73, 69, 82, 32, 76, 69, 84, 84, 69, 82, + 32, 76, 65, 66, 73, 37, 8, 83, 69, 80, 65, 82, 65, 84, 79, 2, 223, 240, + 3, 32, 112, 106, 65, 108, 17, 66, 69, 82, 66, 69, 82, 32, 65, 67, 65, 68, + 69, 77, 89, 32, 89, 65, 30, 84, 211, 1, 89, 4, 84, 6, 89, 69, 82, 32, 89, + 65, 137, 172, 4, 9, 72, 65, 71, 71, 65, 82, 32, 89, 65, 2, 147, 172, 4, + 71, 4, 142, 173, 4, 72, 3, 74, 18, 92, 11, 65, 87, 69, 76, 76, 69, 77, + 69, 84, 32, 89, 21, 8, 85, 65, 82, 69, 71, 32, 89, 65, 2, 235, 205, 2, + 65, 16, 62, 71, 226, 26, 75, 210, 143, 4, 90, 62, 78, 86, 72, 3, 81, 4, + 190, 171, 4, 72, 3, 78, 86, 54, 65, 210, 25, 69, 158, 145, 4, 73, 2, 79, + 3, 85, 77, 194, 1, 71, 2, 75, 18, 83, 30, 84, 30, 90, 134, 23, 68, 126, + 66, 2, 72, 198, 58, 82, 142, 213, 3, 67, 146, 1, 65, 2, 70, 2, 74, 2, 76, + 2, 77, 2, 78, 2, 80, 2, 81, 2, 86, 2, 87, 3, 89, 7, 199, 24, 72, 7, 150, + 169, 4, 72, 3, 83, 7, 250, 168, 4, 72, 3, 84, 7, 222, 168, 4, 72, 3, 90, + 2, 141, 191, 3, 4, 65, 76, 73, 90, 2, 219, 230, 3, 82, 6, 76, 2, 69, 82, + 21, 13, 72, 84, 32, 84, 82, 73, 70, 79, 76, 73, 65, 84, 69, 5, 167, 234, + 3, 32, 2, 33, 6, 32, 83, 78, 79, 87, 70, 2, 219, 58, 76, 19, 11, 32, 16, + 72, 8, 79, 80, 69, 82, 65, 84, 79, 82, 233, 1, 5, 87, 73, 84, 72, 32, 11, + 11, 32, 8, 38, 65, 101, 5, 87, 73, 84, 72, 32, 4, 25, 4, 66, 79, 86, 69, + 4, 11, 32, 4, 26, 76, 171, 131, 3, 82, 2, 11, 69, 2, 179, 131, 3, 70, 4, + 26, 82, 159, 164, 3, 68, 2, 17, 2, 73, 83, 2, 249, 209, 2, 3, 73, 78, 71, + 6, 26, 68, 223, 239, 1, 82, 4, 11, 79, 4, 247, 129, 2, 84, 6, 26, 82, + 187, 131, 1, 83, 2, 11, 32, 2, 195, 177, 1, 67, 5, 21, 3, 32, 84, 87, 2, + 21, 3, 79, 32, 68, 2, 185, 92, 3, 79, 84, 83, 170, 1, 100, 5, 72, 85, 84, + 65, 32, 184, 6, 11, 79, 78, 73, 65, 78, 32, 83, 73, 71, 78, 32, 231, 136, + 3, 69, 164, 1, 178, 1, 65, 88, 7, 76, 69, 84, 84, 69, 82, 32, 204, 1, 2, + 83, 73, 200, 1, 11, 86, 79, 87, 69, 76, 32, 83, 73, 71, 78, 32, 218, 168, + 2, 68, 180, 155, 1, 2, 71, 86, 255, 71, 79, 4, 18, 66, 51, 78, 2, 29, 5, + 66, 82, 69, 86, 73, 2, 247, 26, 65, 2, 175, 140, 4, 74, 94, 254, 65, 65, + 38, 68, 114, 84, 46, 86, 186, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, + 46, 83, 82, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, 80, 138, 69, 72, 2, 76, 2, + 77, 2, 82, 2, 89, 186, 2, 69, 3, 79, 12, 21, 3, 71, 78, 32, 12, 46, 67, + 98, 78, 190, 66, 65, 187, 151, 3, 86, 2, 11, 65, 2, 11, 78, 2, 25, 4, 68, + 82, 65, 66, 2, 11, 73, 2, 11, 78, 2, 171, 248, 3, 68, 2, 11, 85, 2, 167, + 248, 3, 75, 30, 78, 83, 242, 68, 65, 38, 85, 22, 86, 166, 202, 1, 73, + 198, 140, 2, 69, 3, 79, 4, 25, 4, 72, 79, 82, 84, 4, 11, 32, 4, 230, 155, + 4, 69, 3, 79, 4, 176, 230, 3, 8, 67, 65, 80, 73, 84, 65, 76, 32, 239, 24, + 69, 254, 2, 192, 2, 12, 68, 72, 82, 73, 32, 76, 69, 84, 84, 69, 82, 32, + 180, 4, 10, 76, 79, 78, 71, 32, 83, 73, 75, 73, 32, 154, 4, 77, 18, 78, + 34, 79, 80, 2, 80, 32, 168, 17, 23, 82, 84, 79, 73, 83, 69, 32, 83, 72, + 69, 76, 76, 32, 66, 82, 65, 67, 75, 69, 84, 69, 68, 32, 130, 4, 84, 202, + 151, 2, 73, 249, 70, 5, 75, 89, 79, 32, 84, 104, 242, 1, 71, 42, 74, 30, + 77, 34, 78, 70, 72, 34, 80, 34, 83, 234, 55, 82, 210, 147, 1, 79, 238, + 60, 69, 42, 76, 198, 2, 65, 154, 194, 1, 67, 2, 68, 2, 75, 2, 84, 2, 88, + 2, 90, 138, 69, 66, 2, 70, 2, 81, 2, 86, 186, 2, 73, 2, 85, 3, 89, 6, + 150, 148, 4, 72, 2, 74, 187, 2, 65, 4, 166, 150, 4, 65, 3, 89, 4, 210, + 147, 4, 66, 187, 2, 65, 14, 66, 71, 142, 201, 2, 74, 222, 132, 1, 88, + 138, 69, 68, 187, 2, 65, 4, 238, 146, 4, 74, 187, 2, 65, 4, 206, 146, 4, + 83, 187, 2, 65, 10, 54, 72, 150, 200, 2, 75, 230, 201, 1, 84, 187, 2, 65, + 4, 246, 145, 4, 84, 187, 2, 65, 108, 92, 7, 76, 69, 84, 84, 69, 82, 32, + 228, 2, 5, 83, 73, 71, 78, 32, 58, 85, 143, 156, 2, 68, 82, 190, 1, 65, + 22, 68, 30, 78, 58, 82, 14, 84, 30, 66, 2, 67, 2, 71, 2, 74, 2, 75, 2, + 80, 226, 144, 4, 69, 2, 72, 2, 73, 2, 76, 2, 77, 2, 79, 2, 83, 2, 85, 2, + 86, 2, 88, 3, 89, 5, 239, 145, 4, 65, 9, 122, 68, 227, 144, 4, 72, 11, + 34, 78, 158, 145, 4, 71, 3, 89, 5, 155, 145, 4, 89, 7, 39, 82, 9, 26, 84, + 227, 144, 4, 72, 5, 223, 144, 4, 72, 4, 176, 238, 3, 2, 83, 69, 177, 25, + 4, 72, 69, 67, 65, 2, 205, 205, 3, 2, 78, 71, 2, 239, 28, 65, 2, 11, 71, + 2, 135, 249, 3, 85, 6, 32, 2, 84, 72, 207, 128, 3, 76, 5, 11, 66, 2, 11, + 82, 2, 131, 164, 2, 85, 72, 252, 1, 4, 65, 82, 67, 32, 162, 2, 67, 44, 2, + 72, 65, 166, 3, 80, 140, 3, 13, 74, 85, 83, 84, 73, 70, 73, 69, 68, 32, + 76, 79, 87, 84, 5, 76, 69, 70, 84, 32, 228, 1, 6, 82, 73, 71, 72, 84, 32, + 170, 2, 83, 38, 84, 81, 7, 87, 73, 84, 72, 32, 85, 80, 6, 180, 1, 19, 65, + 78, 84, 73, 67, 76, 79, 67, 75, 87, 73, 83, 69, 32, 65, 82, 82, 79, 87, + 73, 21, 67, 76, 79, 67, 75, 87, 73, 83, 69, 32, 65, 82, 82, 79, 87, 32, + 87, 73, 84, 72, 32, 5, 29, 5, 32, 87, 73, 84, 72, 2, 17, 2, 32, 80, 2, + 167, 130, 2, 76, 2, 11, 77, 2, 251, 129, 2, 73, 2, 11, 85, 2, 217, 183, + 3, 3, 82, 76, 89, 34, 36, 3, 76, 70, 32, 135, 138, 4, 84, 32, 70, 70, + 186, 1, 76, 22, 82, 178, 2, 83, 250, 5, 66, 211, 245, 1, 73, 8, 136, 1, + 15, 79, 82, 87, 65, 82, 68, 45, 70, 65, 67, 73, 78, 71, 32, 82, 157, 2, + 13, 76, 65, 73, 76, 73, 78, 71, 32, 82, 79, 66, 79, 84, 4, 22, 85, 243, + 1, 79, 2, 159, 202, 3, 78, 8, 41, 2, 69, 70, 8, 21, 3, 73, 71, 72, 8, 11, + 84, 8, 54, 32, 69, 9, 45, 70, 65, 67, 73, 78, 71, 32, 82, 2, 11, 80, 2, + 33, 6, 65, 82, 69, 78, 84, 72, 2, 207, 223, 1, 69, 6, 38, 79, 21, 5, 85, + 78, 78, 69, 82, 2, 239, 181, 3, 66, 4, 29, 5, 32, 70, 82, 65, 77, 4, 11, + 69, 4, 11, 45, 4, 218, 133, 4, 49, 3, 50, 4, 18, 69, 59, 84, 2, 11, 67, + 2, 11, 84, 2, 11, 73, 2, 255, 136, 2, 79, 2, 17, 2, 65, 78, 2, 11, 68, 2, + 21, 3, 73, 78, 71, 2, 17, 2, 32, 80, 2, 11, 69, 2, 11, 82, 2, 163, 180, + 3, 83, 4, 17, 2, 69, 82, 4, 33, 6, 32, 72, 65, 76, 70, 32, 4, 250, 3, 66, + 139, 106, 87, 10, 180, 1, 13, 74, 85, 83, 84, 73, 70, 73, 69, 68, 32, 76, + 79, 87, 126, 67, 50, 72, 161, 217, 2, 21, 66, 76, 65, 67, 75, 32, 76, 69, + 70, 84, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 83, 2, 237, 1, 7, 69, 82, + 32, 82, 73, 71, 72, 8, 78, 67, 50, 72, 33, 13, 74, 85, 83, 84, 73, 70, + 73, 69, 68, 32, 76, 79, 87, 4, 26, 79, 199, 135, 3, 82, 2, 223, 194, 3, + 82, 2, 209, 173, 3, 3, 65, 76, 70, 2, 33, 6, 69, 82, 32, 76, 69, 70, 2, + 53, 11, 84, 32, 81, 85, 65, 82, 84, 69, 82, 32, 66, 2, 11, 76, 2, 137, + 171, 2, 3, 65, 67, 75, 2, 157, 172, 3, 4, 81, 85, 65, 82, 2, 11, 79, 2, + 249, 171, 3, 12, 82, 84, 79, 73, 83, 69, 32, 83, 72, 69, 76, 76, 2, 29, + 5, 87, 65, 82, 68, 83, 2, 17, 2, 32, 65, 2, 237, 128, 3, 4, 82, 82, 79, + 87, 20, 188, 1, 22, 67, 74, 75, 32, 85, 78, 73, 70, 73, 69, 68, 32, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 161, 2, 19, 76, 65, 84, 73, 78, 32, + 67, 65, 80, 73, 84, 65, 76, 32, 76, 69, 84, 84, 69, 18, 40, 2, 52, 69, + 34, 53, 54, 54, 87, 55, 4, 202, 1, 48, 139, 208, 2, 56, 4, 30, 50, 141, + 1, 2, 66, 56, 2, 131, 181, 3, 68, 6, 48, 2, 50, 53, 22, 53, 185, 208, 2, + 2, 55, 50, 2, 219, 250, 3, 51, 2, 67, 53, 4, 32, 2, 48, 66, 21, 2, 54, + 68, 2, 151, 250, 3, 57, 2, 131, 250, 3, 55, 2, 11, 82, 2, 135, 188, 3, + 32, 64, 48, 6, 65, 76, 32, 82, 85, 78, 21, 2, 79, 32, 2, 203, 255, 2, 79, + 62, 72, 7, 76, 69, 84, 84, 69, 82, 32, 217, 2, 6, 83, 73, 71, 78, 32, 82, + 60, 206, 1, 66, 106, 78, 138, 31, 73, 206, 141, 1, 69, 138, 76, 67, 138, + 189, 1, 65, 234, 61, 68, 2, 71, 2, 72, 2, 74, 2, 75, 2, 76, 2, 77, 2, 80, + 2, 82, 2, 83, 2, 84, 2, 87, 2, 89, 186, 2, 79, 3, 85, 12, 52, 7, 82, 69, + 65, 84, 72, 89, 32, 183, 246, 3, 65, 10, 182, 31, 73, 206, 141, 1, 69, + 223, 178, 2, 65, 4, 202, 243, 3, 71, 187, 2, 65, 2, 17, 2, 73, 83, 2, 21, + 3, 73, 78, 71, 2, 11, 32, 2, 211, 200, 2, 84, 104, 54, 65, 254, 1, 69, + 86, 73, 246, 11, 79, 231, 1, 85, 16, 66, 67, 36, 2, 68, 69, 34, 77, 20, + 2, 78, 83, 231, 163, 3, 73, 4, 218, 233, 1, 75, 219, 209, 1, 84, 2, 133, + 17, 4, 32, 77, 65, 82, 5, 243, 212, 1, 32, 4, 44, 2, 80, 76, 33, 5, 86, + 69, 82, 83, 65, 2, 11, 85, 2, 147, 212, 3, 84, 2, 163, 63, 76, 4, 52, 7, + 65, 83, 85, 82, 69, 32, 67, 235, 220, 2, 69, 2, 11, 72, 2, 171, 4, 69, + 66, 156, 1, 3, 65, 78, 71, 176, 3, 8, 68, 69, 78, 84, 32, 69, 77, 66, 20, + 9, 71, 82, 65, 77, 32, 70, 79, 82, 32, 140, 2, 4, 80, 76, 69, 32, 159, + 155, 3, 67, 16, 48, 2, 76, 69, 245, 1, 5, 85, 76, 65, 82, 32, 10, 44, 6, + 32, 87, 73, 84, 72, 32, 163, 1, 45, 8, 80, 9, 83, 69, 82, 73, 70, 83, 32, + 65, 84, 54, 85, 238, 169, 2, 82, 207, 68, 68, 2, 17, 2, 32, 66, 2, 189, + 222, 3, 3, 79, 84, 84, 2, 149, 61, 2, 78, 68, 2, 193, 204, 2, 4, 72, 69, + 65, 68, 6, 68, 9, 70, 76, 65, 71, 32, 79, 78, 32, 80, 34, 82, 195, 139, + 2, 66, 2, 11, 79, 2, 199, 209, 3, 83, 2, 11, 85, 2, 231, 175, 3, 76, 2, + 147, 219, 3, 76, 16, 66, 69, 34, 72, 34, 76, 22, 77, 46, 84, 42, 87, 155, + 211, 1, 70, 2, 11, 65, 2, 227, 231, 1, 82, 2, 11, 69, 2, 227, 249, 1, 65, + 2, 207, 188, 3, 65, 2, 21, 3, 79, 85, 78, 2, 147, 189, 2, 84, 2, 17, 2, + 72, 85, 2, 251, 199, 1, 78, 4, 178, 177, 2, 65, 251, 41, 73, 30, 176, 2, + 3, 67, 79, 76, 24, 20, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 66, + 65, 82, 32, 87, 73, 84, 72, 32, 98, 80, 34, 84, 20, 13, 86, 69, 82, 84, + 73, 67, 65, 76, 32, 66, 65, 82, 32, 44, 9, 83, 79, 76, 73, 68, 85, 83, + 32, 66, 224, 21, 2, 68, 65, 160, 187, 1, 6, 78, 69, 83, 84, 69, 68, 159, + 12, 73, 2, 165, 37, 2, 79, 78, 4, 34, 68, 33, 4, 84, 82, 73, 80, 2, 17, + 2, 79, 85, 2, 11, 66, 2, 177, 183, 3, 2, 76, 69, 4, 142, 223, 1, 76, 235, + 110, 82, 2, 195, 202, 1, 73, 8, 42, 66, 74, 68, 170, 189, 1, 82, 115, 87, + 2, 29, 5, 73, 78, 65, 82, 89, 2, 21, 3, 32, 82, 69, 2, 143, 33, 76, 2, + 25, 4, 69, 76, 73, 77, 2, 163, 172, 2, 73, 12, 32, 2, 76, 76, 42, 77, 23, + 80, 5, 17, 2, 69, 89, 2, 255, 220, 1, 66, 2, 247, 184, 2, 66, 6, 44, 5, + 73, 67, 65, 76, 32, 199, 211, 3, 72, 4, 18, 68, 47, 70, 2, 11, 82, 2, 11, + 73, 2, 199, 225, 3, 78, 2, 195, 249, 1, 73, 6, 18, 69, 79, 77, 5, 213, + 191, 3, 14, 32, 76, 73, 71, 72, 84, 32, 77, 79, 79, 78, 32, 65, 82, 2, + 191, 174, 3, 80, 216, 1, 76, 3, 71, 82, 73, 22, 76, 214, 12, 82, 173, + 188, 2, 5, 77, 66, 76, 69, 82, 2, 239, 219, 2, 75, 162, 1, 68, 11, 85, + 45, 84, 73, 71, 65, 76, 65, 82, 73, 32, 135, 226, 3, 73, 160, 1, 122, 65, + 42, 67, 30, 68, 106, 71, 32, 7, 76, 69, 84, 84, 69, 82, 32, 178, 3, 82, + 32, 5, 83, 73, 71, 78, 32, 131, 3, 86, 2, 11, 85, 2, 133, 159, 3, 2, 32, + 76, 2, 201, 162, 3, 2, 79, 78, 4, 18, 79, 67, 65, 2, 11, 85, 2, 11, 66, + 2, 25, 4, 76, 69, 32, 68, 2, 11, 65, 2, 243, 186, 3, 78, 2, 213, 218, 2, + 3, 69, 77, 73, 100, 206, 1, 65, 38, 68, 46, 76, 38, 82, 34, 84, 46, 86, + 186, 5, 85, 186, 202, 1, 73, 138, 196, 1, 78, 46, 83, 82, 66, 2, 67, 2, + 71, 2, 74, 2, 75, 2, 80, 206, 40, 79, 162, 8, 69, 158, 20, 72, 2, 77, 3, + 89, 9, 242, 221, 3, 65, 2, 73, 3, 85, 8, 142, 150, 3, 68, 138, 69, 72, + 187, 2, 65, 6, 134, 209, 1, 76, 159, 140, 2, 65, 4, 198, 218, 3, 82, 187, + 2, 65, 8, 158, 149, 3, 84, 138, 69, 72, 187, 2, 65, 10, 214, 5, 79, 223, + 214, 3, 65, 2, 11, 69, 2, 223, 222, 1, 80, 18, 174, 1, 65, 72, 6, 76, 79, + 79, 80, 69, 68, 40, 2, 79, 77, 0, 5, 83, 72, 82, 73, 73, 48, 13, 67, 65, + 78, 68, 82, 65, 32, 65, 78, 85, 78, 65, 83, 22, 80, 135, 150, 3, 86, 4, + 26, 86, 191, 149, 3, 78, 2, 21, 3, 65, 71, 82, 2, 231, 220, 1, 65, 2, 17, + 2, 32, 86, 2, 203, 157, 1, 73, 2, 17, 2, 32, 80, 2, 25, 4, 85, 83, 72, + 80, 2, 187, 208, 3, 73, 2, 193, 180, 3, 2, 76, 85, 30, 56, 10, 69, 68, + 73, 67, 32, 84, 79, 78, 69, 32, 35, 79, 4, 226, 164, 1, 65, 235, 4, 83, + 26, 45, 9, 87, 69, 76, 32, 83, 73, 71, 78, 32, 26, 70, 65, 38, 85, 22, + 86, 166, 202, 1, 73, 210, 237, 1, 79, 163, 8, 69, 6, 158, 215, 3, 65, 2, + 73, 3, 85, 5, 251, 214, 3, 85, 8, 11, 79, 8, 33, 6, 67, 65, 76, 73, 67, + 32, 8, 26, 82, 243, 217, 2, 76, 5, 155, 214, 3, 82, 50, 50, 75, 84, 4, + 78, 69, 68, 32, 199, 174, 2, 84, 4, 48, 6, 73, 83, 72, 32, 76, 73, 219, + 195, 3, 69, 2, 11, 82, 2, 147, 206, 2, 65, 44, 238, 1, 65, 80, 6, 66, 76, + 65, 67, 75, 32, 40, 7, 87, 72, 73, 84, 69, 32, 83, 22, 67, 50, 68, 96, 2, + 78, 79, 32, 2, 79, 75, 30, 83, 237, 171, 3, 21, 71, 82, 69, 69, 75, 32, + 83, 77, 65, 76, 76, 32, 76, 69, 84, 84, 69, 82, 32, 73, 79, 4, 26, 77, + 175, 172, 2, 78, 2, 17, 2, 80, 69, 2, 11, 82, 2, 179, 194, 2, 83, 4, 18, + 80, 23, 83, 2, 211, 151, 2, 69, 2, 195, 153, 2, 72, 4, 144, 3, 5, 65, 80, + 73, 84, 65, 171, 121, 79, 6, 30, 65, 33, 3, 73, 71, 73, 2, 11, 71, 2, + 187, 147, 3, 71, 4, 201, 222, 1, 3, 84, 32, 84, 6, 162, 2, 82, 211, 199, + 2, 84, 2, 249, 228, 1, 2, 32, 72, 14, 128, 1, 18, 65, 78, 83, 45, 83, 69, + 82, 73, 70, 32, 67, 65, 80, 73, 84, 65, 76, 32, 38, 69, 32, 3, 77, 65, + 76, 33, 2, 79, 85, 6, 178, 207, 3, 71, 2, 76, 3, 89, 2, 11, 77, 2, 243, + 254, 2, 73, 2, 11, 76, 2, 191, 205, 2, 32, 4, 21, 3, 84, 72, 32, 4, 32, + 2, 69, 65, 1, 2, 87, 69, 2, 53, 11, 83, 84, 32, 80, 79, 73, 78, 84, 73, + 78, 71, 2, 17, 2, 32, 76, 2, 151, 204, 2, 69, 38, 58, 69, 52, 8, 73, 83, + 84, 69, 68, 32, 82, 73, 63, 79, 2, 17, 2, 76, 86, 2, 145, 178, 1, 3, 69, + 32, 80, 2, 17, 2, 71, 72, 2, 141, 109, 6, 84, 87, 65, 82, 68, 83, 34, 30, + 32, 229, 10, 2, 45, 69, 32, 134, 3, 66, 86, 67, 116, 3, 68, 79, 84, 226, + 1, 72, 44, 14, 73, 78, 84, 69, 82, 83, 69, 67, 84, 73, 78, 71, 32, 76, + 92, 6, 74, 79, 73, 78, 69, 68, 64, 8, 76, 79, 71, 73, 67, 65, 76, 32, 98, + 77, 0, 3, 87, 79, 77, 116, 13, 82, 73, 78, 71, 83, 32, 65, 76, 73, 71, + 78, 69, 68, 48, 24, 65, 83, 84, 69, 82, 73, 83, 75, 83, 32, 65, 76, 73, + 71, 78, 69, 68, 32, 86, 69, 82, 84, 73, 67, 35, 83, 2, 29, 5, 85, 84, 84, + 79, 78, 2, 17, 2, 32, 77, 2, 11, 79, 2, 251, 188, 2, 85, 2, 93, 21, 79, + 78, 83, 69, 67, 85, 84, 73, 86, 69, 32, 69, 81, 85, 65, 76, 83, 32, 83, + 73, 71, 2, 207, 137, 3, 78, 6, 18, 32, 55, 83, 4, 22, 76, 131, 1, 80, 2, + 145, 163, 1, 2, 69, 65, 2, 53, 11, 32, 79, 86, 69, 82, 32, 79, 78, 69, + 32, 68, 2, 11, 79, 2, 11, 84, 2, 17, 2, 32, 80, 2, 29, 5, 85, 78, 67, 84, + 85, 2, 251, 244, 2, 65, 2, 11, 69, 2, 11, 65, 2, 227, 188, 2, 82, 4, 17, + 2, 79, 71, 4, 25, 4, 73, 67, 65, 76, 4, 11, 32, 4, 186, 180, 2, 65, 187, + 87, 79, 2, 17, 2, 32, 83, 2, 21, 3, 81, 85, 65, 2, 255, 173, 2, 82, 4, + 30, 79, 13, 3, 65, 78, 68, 2, 11, 82, 2, 11, 32, 2, 11, 79, 2, 11, 80, 2, + 143, 18, 69, 2, 11, 69, 2, 45, 9, 78, 32, 72, 79, 76, 68, 73, 78, 71, 2, + 11, 32, 2, 11, 72, 2, 11, 65, 2, 251, 223, 1, 78, 2, 45, 9, 32, 72, 79, + 82, 73, 90, 79, 78, 84, 2, 11, 65, 2, 175, 158, 3, 76, 2, 49, 10, 80, 69, + 69, 67, 72, 32, 66, 85, 66, 66, 2, 147, 171, 2, 76, 2, 11, 77, 2, 225, + 213, 1, 2, 32, 68, 248, 3, 140, 1, 8, 71, 65, 82, 73, 84, 73, 67, 32, + 152, 6, 7, 77, 66, 82, 69, 76, 76, 65, 166, 1, 78, 158, 8, 80, 246, 166, + 1, 82, 255, 136, 2, 83, 62, 48, 7, 76, 69, 84, 84, 69, 82, 32, 159, 5, + 87, 60, 206, 1, 65, 28, 2, 81, 79, 22, 66, 22, 68, 50, 71, 44, 2, 72, 79, + 22, 75, 34, 76, 32, 2, 82, 65, 22, 83, 74, 84, 74, 89, 22, 90, 234, 185, + 2, 78, 202, 91, 80, 246, 5, 87, 202, 12, 77, 174, 18, 73, 3, 85, 4, 26, + 76, 203, 237, 2, 73, 2, 239, 186, 3, 80, 2, 199, 152, 3, 69, 4, 26, 69, + 139, 177, 2, 72, 2, 151, 152, 3, 76, 4, 230, 141, 2, 72, 209, 140, 1, 2, + 65, 77, 5, 235, 185, 3, 84, 4, 234, 186, 2, 65, 239, 126, 72, 2, 11, 65, + 2, 223, 150, 3, 77, 2, 167, 190, 1, 83, 8, 38, 65, 194, 187, 2, 72, 239, + 90, 83, 4, 190, 164, 3, 68, 239, 13, 77, 6, 38, 72, 162, 158, 3, 69, 175, + 28, 79, 2, 11, 65, 2, 167, 252, 1, 78, 2, 139, 244, 2, 79, 4, 202, 149, + 3, 69, 207, 36, 85, 2, 21, 3, 79, 82, 68, 2, 25, 4, 32, 68, 73, 86, 2, + 235, 149, 1, 73, 7, 11, 32, 4, 84, 4, 79, 78, 32, 71, 45, 13, 87, 73, 84, + 72, 32, 82, 65, 73, 78, 32, 68, 82, 79, 2, 11, 82, 2, 11, 79, 2, 159, + 168, 2, 85, 2, 195, 250, 2, 80, 32, 160, 1, 3, 65, 77, 85, 20, 7, 67, 69, + 82, 84, 65, 73, 78, 34, 68, 62, 73, 245, 5, 18, 77, 65, 82, 82, 73, 69, + 68, 32, 80, 65, 82, 84, 78, 69, 82, 83, 72, 73, 2, 243, 163, 2, 83, 2, + 11, 84, 2, 199, 175, 2, 89, 4, 26, 69, 215, 160, 2, 79, 2, 11, 82, 2, + 219, 154, 3, 84, 22, 60, 2, 79, 78, 234, 3, 84, 106, 86, 177, 58, 3, 67, + 79, 82, 15, 11, 32, 12, 160, 1, 6, 65, 66, 79, 86, 69, 32, 108, 22, 66, + 69, 83, 73, 68, 69, 32, 65, 78, 68, 32, 74, 79, 73, 78, 69, 68, 32, 87, + 73, 84, 72, 41, 5, 87, 73, 84, 72, 32, 4, 52, 9, 66, 65, 82, 32, 65, 66, + 79, 86, 69, 23, 73, 2, 17, 2, 32, 73, 2, 161, 49, 4, 78, 84, 69, 82, 2, + 17, 2, 32, 85, 2, 195, 226, 2, 78, 6, 66, 77, 58, 79, 145, 249, 2, 8, 76, + 79, 71, 73, 67, 65, 76, 32, 2, 11, 73, 2, 11, 78, 2, 11, 85, 2, 139, 171, + 2, 83, 2, 11, 86, 2, 161, 142, 2, 2, 69, 82, 4, 18, 32, 67, 69, 2, 11, + 83, 2, 17, 2, 69, 80, 2, 11, 65, 2, 143, 248, 2, 82, 2, 183, 155, 2, 68, + 2, 57, 12, 69, 82, 83, 65, 76, 32, 82, 69, 67, 89, 67, 76, 2, 17, 2, 73, + 78, 2, 211, 154, 2, 71, 2, 191, 154, 2, 80, 144, 3, 130, 1, 32, 246, 7, + 45, 180, 8, 4, 80, 69, 82, 32, 136, 40, 8, 83, 73, 68, 69, 45, 68, 79, + 87, 21, 6, 87, 65, 82, 68, 83, 32, 38, 140, 1, 5, 65, 82, 82, 79, 87, + 224, 1, 5, 66, 65, 82, 66, 32, 228, 1, 5, 68, 79, 87, 78, 32, 210, 1, 70, + 30, 82, 93, 4, 84, 65, 67, 75, 8, 64, 4, 72, 69, 65, 68, 141, 51, 7, 32, + 84, 72, 82, 79, 85, 71, 7, 11, 32, 4, 112, 22, 66, 69, 84, 87, 69, 69, + 78, 32, 84, 87, 79, 32, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 227, 156, + 2, 73, 2, 145, 149, 2, 2, 32, 66, 8, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, + 72, 4, 57, 12, 84, 32, 68, 79, 87, 78, 32, 66, 65, 82, 66, 32, 4, 44, 3, + 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 11, 84, 2, 25, 4, 32, 72, 65, 82, 2, + 11, 80, 2, 187, 218, 2, 79, 14, 76, 5, 65, 82, 82, 79, 87, 62, 66, 38, + 68, 18, 83, 250, 58, 87, 219, 9, 84, 5, 37, 7, 32, 87, 73, 84, 72, 32, + 66, 2, 247, 157, 2, 65, 2, 173, 140, 2, 4, 76, 65, 67, 75, 2, 195, 59, + 79, 2, 183, 65, 65, 2, 11, 73, 2, 239, 112, 83, 2, 53, 11, 73, 71, 72, + 84, 32, 68, 73, 65, 71, 79, 78, 2, 189, 128, 1, 4, 65, 76, 32, 69, 5, 29, + 5, 32, 87, 73, 84, 72, 2, 33, 6, 32, 67, 73, 82, 67, 76, 2, 131, 170, 2, + 69, 32, 58, 70, 225, 1, 9, 80, 79, 73, 78, 84, 73, 78, 71, 32, 4, 41, 8, + 65, 67, 73, 78, 71, 32, 83, 78, 4, 65, 14, 65, 75, 69, 32, 72, 69, 65, + 68, 32, 87, 73, 84, 72, 32, 4, 42, 79, 25, 6, 67, 76, 79, 83, 69, 68, 2, + 21, 3, 80, 69, 78, 2, 21, 3, 32, 77, 79, 2, 243, 159, 1, 85, 28, 130, 1, + 65, 86, 69, 62, 70, 20, 8, 77, 73, 76, 73, 84, 65, 82, 89, 26, 82, 88, 6, + 83, 77, 65, 76, 76, 32, 118, 84, 255, 121, 71, 4, 22, 84, 159, 2, 73, 2, + 37, 7, 79, 77, 73, 67, 32, 66, 79, 2, 155, 229, 1, 77, 2, 29, 5, 78, 69, + 82, 71, 89, 2, 193, 180, 1, 2, 32, 87, 2, 227, 161, 3, 82, 2, 129, 1, 2, + 32, 65, 8, 64, 5, 79, 67, 75, 69, 84, 118, 69, 214, 129, 1, 65, 235, 29, + 73, 2, 195, 204, 2, 32, 4, 18, 65, 67, 82, 2, 11, 73, 2, 11, 82, 2, 17, + 2, 80, 76, 2, 207, 133, 2, 65, 2, 11, 69, 2, 215, 249, 1, 68, 4, 37, 7, + 82, 73, 65, 78, 71, 76, 69, 4, 11, 32, 4, 11, 87, 4, 25, 4, 73, 84, 72, + 32, 4, 18, 76, 27, 82, 2, 11, 69, 2, 35, 70, 2, 21, 3, 73, 71, 72, 2, 11, + 84, 2, 17, 2, 32, 72, 2, 21, 3, 65, 76, 70, 2, 17, 2, 32, 66, 2, 11, 76, + 2, 207, 236, 1, 65, 200, 1, 192, 1, 4, 65, 78, 68, 32, 210, 2, 66, 74, + 67, 74, 70, 36, 5, 72, 65, 76, 70, 32, 200, 4, 5, 76, 69, 70, 84, 32, + 254, 5, 77, 150, 2, 79, 60, 6, 82, 73, 71, 72, 84, 32, 238, 17, 83, 67, + 84, 8, 34, 76, 53, 4, 82, 73, 71, 72, 6, 48, 2, 69, 70, 173, 1, 5, 79, + 87, 69, 82, 32, 2, 53, 11, 84, 32, 65, 78, 68, 32, 76, 79, 87, 69, 82, 2, + 205, 35, 25, 32, 84, 82, 73, 65, 78, 71, 85, 76, 65, 82, 32, 84, 72, 82, + 69, 69, 32, 81, 85, 65, 82, 84, 69, 82, 4, 28, 2, 84, 82, 235, 39, 79, 2, + 225, 4, 7, 73, 65, 78, 71, 85, 76, 65, 2, 17, 2, 76, 65, 2, 17, 2, 68, + 69, 2, 249, 224, 1, 3, 32, 83, 67, 10, 33, 6, 69, 78, 84, 82, 69, 32, 10, + 174, 12, 76, 22, 82, 255, 21, 79, 2, 17, 2, 73, 86, 2, 183, 31, 69, 20, + 140, 1, 5, 66, 76, 79, 67, 75, 110, 72, 32, 8, 73, 78, 86, 69, 82, 83, + 69, 32, 198, 1, 86, 174, 26, 77, 130, 3, 76, 22, 82, 191, 163, 1, 67, 5, + 229, 28, 23, 32, 65, 78, 68, 32, 76, 79, 87, 69, 82, 32, 72, 65, 76, 70, + 32, 73, 78, 86, 69, 82, 83, 69, 2, 225, 18, 4, 69, 65, 86, 89, 4, 100, + 21, 77, 69, 68, 73, 85, 77, 32, 83, 72, 65, 68, 69, 32, 65, 78, 68, 32, + 76, 79, 87, 69, 51, 87, 2, 11, 82, 2, 189, 35, 5, 32, 72, 65, 76, 70, 2, + 21, 3, 72, 73, 84, 2, 247, 192, 1, 69, 2, 29, 5, 69, 82, 84, 73, 67, 2, + 189, 115, 14, 65, 76, 32, 76, 73, 78, 69, 32, 87, 73, 84, 72, 32, 84, 62, + 50, 66, 238, 3, 67, 54, 79, 74, 84, 183, 13, 81, 22, 65, 14, 76, 79, 67, + 75, 32, 68, 73, 65, 71, 79, 78, 65, 76, 32, 22, 144, 1, 6, 76, 79, 87, + 69, 82, 32, 233, 8, 24, 85, 80, 80, 69, 82, 32, 77, 73, 68, 68, 76, 69, + 32, 76, 69, 70, 84, 32, 84, 79, 32, 85, 80, 80, 18, 176, 1, 10, 67, 69, + 78, 84, 82, 69, 32, 84, 79, 32, 36, 8, 76, 69, 70, 84, 32, 84, 79, 32, + 229, 10, 18, 77, 73, 68, 68, 76, 69, 32, 76, 69, 70, 84, 32, 84, 79, 32, + 85, 80, 80, 6, 70, 76, 253, 8, 3, 85, 80, 80, 6, 34, 76, 213, 9, 3, 85, + 80, 80, 2, 149, 10, 2, 79, 87, 2, 29, 5, 79, 82, 78, 69, 82, 2, 219, 233, + 1, 32, 4, 182, 12, 78, 53, 12, 82, 32, 76, 79, 87, 69, 82, 32, 82, 73, + 71, 72, 8, 34, 79, 170, 19, 82, 155, 1, 87, 2, 241, 18, 11, 32, 76, 79, + 87, 69, 82, 32, 82, 73, 71, 72, 12, 33, 6, 73, 68, 68, 76, 69, 32, 12, + 52, 7, 67, 69, 78, 84, 82, 69, 32, 74, 76, 23, 82, 4, 44, 3, 76, 69, 70, + 1, 4, 82, 73, 71, 72, 2, 117, 3, 84, 32, 79, 4, 41, 2, 69, 70, 4, 21, 3, + 73, 71, 72, 4, 17, 2, 84, 32, 4, 30, 79, 129, 18, 2, 84, 87, 2, 139, 9, + 78, 4, 11, 78, 4, 17, 2, 69, 32, 4, 154, 21, 81, 147, 4, 69, 68, 84, 2, + 66, 76, 186, 6, 68, 114, 79, 222, 1, 80, 42, 81, 224, 4, 2, 83, 72, 51, + 84, 22, 61, 13, 79, 67, 75, 32, 68, 73, 65, 71, 79, 78, 65, 76, 32, 22, + 140, 1, 24, 76, 79, 87, 69, 82, 32, 77, 73, 68, 68, 76, 69, 32, 76, 69, + 70, 84, 32, 84, 79, 32, 76, 79, 87, 57, 6, 85, 80, 80, 69, 82, 32, 4, 21, + 3, 69, 82, 32, 4, 246, 3, 67, 219, 218, 2, 82, 18, 176, 1, 10, 67, 69, + 78, 84, 82, 69, 32, 84, 79, 32, 92, 8, 76, 69, 70, 84, 32, 84, 79, 32, + 141, 1, 18, 77, 73, 68, 68, 76, 69, 32, 76, 69, 70, 84, 32, 84, 79, 32, + 76, 79, 87, 6, 32, 3, 76, 79, 87, 139, 1, 85, 4, 21, 3, 69, 82, 32, 4, + 142, 2, 77, 179, 218, 2, 82, 6, 28, 3, 76, 79, 87, 51, 85, 4, 21, 3, 69, + 82, 32, 4, 142, 1, 67, 43, 77, 2, 17, 2, 80, 80, 2, 17, 2, 69, 82, 2, + 117, 2, 32, 77, 6, 21, 3, 69, 82, 32, 6, 34, 67, 42, 77, 179, 218, 2, 82, + 2, 11, 69, 2, 221, 226, 1, 2, 78, 84, 2, 25, 4, 73, 68, 68, 76, 2, 195, + 177, 1, 69, 2, 57, 12, 82, 79, 80, 45, 83, 72, 65, 68, 79, 87, 69, 68, 2, + 17, 2, 32, 87, 2, 149, 192, 1, 3, 72, 73, 84, 4, 62, 78, 53, 11, 82, 32, + 76, 79, 87, 69, 82, 32, 76, 69, 70, 2, 229, 16, 9, 69, 32, 83, 73, 88, + 84, 69, 69, 78, 2, 69, 15, 84, 32, 67, 85, 82, 76, 89, 32, 66, 82, 65, + 67, 75, 69, 84, 2, 11, 32, 2, 175, 177, 2, 83, 2, 11, 69, 2, 165, 162, 1, + 2, 78, 67, 26, 17, 2, 85, 65, 26, 44, 6, 68, 82, 65, 78, 84, 32, 255, 3, + 82, 24, 90, 67, 112, 10, 70, 65, 67, 69, 32, 87, 73, 84, 72, 32, 114, 77, + 76, 2, 83, 84, 67, 84, 14, 68, 7, 73, 82, 67, 85, 76, 65, 82, 197, 168, + 1, 4, 72, 69, 83, 83, 2, 17, 2, 32, 65, 2, 207, 213, 1, 82, 4, 34, 67, + 45, 4, 79, 80, 69, 78, 2, 21, 3, 76, 79, 83, 2, 17, 2, 69, 68, 2, 245, + 232, 1, 3, 32, 69, 89, 2, 25, 4, 73, 67, 82, 79, 2, 11, 67, 2, 165, 196, + 1, 4, 79, 77, 80, 85, 2, 41, 8, 65, 78, 68, 73, 78, 71, 32, 75, 2, 147, + 211, 2, 78, 2, 21, 3, 69, 76, 69, 2, 11, 86, 2, 183, 90, 73, 2, 233, 168, + 1, 3, 84, 69, 82, 4, 141, 102, 8, 65, 68, 79, 87, 69, 68, 32, 87, 8, 30, + 79, 106, 82, 155, 1, 87, 2, 49, 10, 32, 76, 79, 87, 69, 82, 32, 76, 69, + 70, 2, 11, 84, 2, 11, 32, 2, 11, 70, 2, 171, 113, 73, 4, 25, 4, 73, 65, + 78, 71, 4, 40, 4, 85, 76, 65, 82, 171, 228, 2, 76, 2, 17, 2, 32, 77, 2, + 41, 8, 69, 68, 73, 85, 77, 32, 83, 72, 2, 199, 103, 65, 2, 21, 3, 69, 76, + 70, 2, 11, 84, 2, 215, 165, 1, 72, 2, 17, 2, 69, 86, 2, 17, 2, 69, 78, 2, + 145, 1, 2, 32, 69, 10, 64, 5, 72, 82, 69, 69, 32, 193, 1, 6, 82, 73, 65, + 78, 71, 85, 8, 54, 69, 49, 9, 81, 85, 65, 82, 84, 69, 82, 83, 32, 2, 29, + 5, 73, 71, 72, 84, 72, 2, 243, 5, 83, 6, 30, 76, 22, 82, 203, 5, 66, 2, + 41, 2, 69, 70, 2, 21, 3, 73, 71, 72, 2, 43, 84, 2, 17, 2, 76, 65, 2, 11, + 82, 2, 17, 2, 32, 79, 2, 25, 4, 78, 69, 32, 81, 2, 185, 4, 6, 85, 65, 82, + 84, 69, 82, 2, 151, 185, 2, 78, 128, 1, 154, 1, 65, 184, 6, 2, 66, 76, + 150, 1, 68, 50, 70, 82, 72, 150, 4, 67, 46, 81, 42, 82, 22, 83, 102, 84, + 146, 7, 80, 173, 3, 6, 87, 72, 73, 84, 69, 32, 32, 34, 78, 33, 4, 82, 82, + 79, 87, 2, 11, 67, 2, 147, 176, 2, 79, 31, 11, 32, 28, 134, 1, 65, 192, + 1, 14, 76, 69, 70, 84, 87, 65, 82, 68, 83, 32, 79, 70, 32, 68, 32, 5, 87, + 73, 84, 72, 32, 210, 8, 70, 179, 5, 84, 2, 41, 8, 78, 68, 32, 82, 73, 71, + 72, 84, 2, 17, 2, 32, 79, 2, 25, 4, 78, 69, 32, 69, 2, 21, 3, 73, 71, 72, + 2, 17, 2, 84, 72, 2, 11, 32, 2, 11, 66, 2, 11, 76, 2, 251, 191, 1, 79, 2, + 145, 208, 1, 3, 79, 87, 78, 20, 74, 68, 58, 76, 42, 77, 38, 78, 58, 83, + 66, 69, 250, 12, 84, 135, 58, 72, 2, 21, 3, 79, 85, 66, 2, 11, 76, 2, + 199, 192, 2, 69, 2, 11, 65, 2, 253, 22, 3, 82, 71, 69, 2, 225, 22, 5, 69, + 68, 73, 85, 77, 2, 25, 4, 79, 84, 67, 72, 2, 11, 69, 2, 151, 56, 68, 4, + 11, 77, 4, 25, 4, 65, 76, 76, 32, 4, 22, 69, 223, 21, 84, 2, 129, 22, 10, + 81, 85, 73, 76, 65, 84, 69, 82, 65, 76, 4, 25, 4, 65, 67, 75, 32, 4, 26, + 67, 215, 209, 1, 65, 2, 25, 4, 73, 82, 67, 76, 2, 25, 4, 69, 68, 32, 87, + 2, 11, 72, 2, 237, 14, 2, 73, 84, 4, 22, 79, 195, 13, 65, 2, 177, 14, 2, + 85, 66, 2, 11, 73, 2, 37, 7, 78, 71, 69, 82, 45, 80, 79, 2, 249, 207, 1, + 2, 83, 84, 20, 88, 17, 65, 82, 80, 79, 79, 78, 32, 87, 73, 84, 72, 32, + 66, 65, 82, 66, 32, 131, 3, 69, 16, 56, 4, 76, 69, 70, 84, 245, 1, 5, 82, + 73, 71, 72, 84, 10, 22, 32, 239, 9, 87, 8, 60, 7, 66, 69, 83, 73, 68, 69, + 32, 206, 1, 70, 179, 5, 84, 4, 40, 4, 68, 79, 87, 78, 1, 2, 85, 80, 2, + 249, 150, 1, 23, 87, 65, 82, 68, 83, 32, 72, 65, 82, 80, 79, 79, 78, 32, + 87, 73, 84, 72, 32, 66, 65, 82, 66, 6, 22, 32, 251, 7, 87, 4, 22, 70, + 179, 5, 84, 2, 165, 197, 1, 3, 82, 79, 77, 4, 25, 4, 65, 86, 89, 32, 4, + 26, 67, 231, 203, 1, 65, 2, 189, 10, 7, 79, 77, 80, 82, 69, 83, 83, 2, + 137, 9, 6, 85, 65, 68, 82, 85, 80, 2, 251, 148, 2, 79, 4, 30, 65, 53, 3, + 81, 85, 65, 2, 193, 202, 1, 8, 78, 83, 45, 83, 69, 82, 73, 70, 2, 131, 9, + 82, 36, 36, 2, 82, 73, 229, 7, 2, 87, 79, 30, 40, 5, 65, 78, 71, 76, 69, + 155, 7, 80, 28, 52, 8, 45, 72, 69, 65, 68, 69, 68, 32, 219, 12, 32, 26, + 48, 5, 65, 82, 82, 79, 87, 174, 5, 68, 39, 80, 23, 11, 32, 20, 92, 17, + 76, 69, 70, 84, 87, 65, 82, 68, 83, 32, 79, 70, 32, 68, 79, 87, 78, 98, + 84, 23, 87, 2, 37, 7, 87, 65, 82, 68, 83, 32, 84, 2, 37, 7, 82, 73, 65, + 78, 71, 76, 69, 2, 219, 5, 45, 2, 247, 191, 1, 79, 16, 25, 4, 73, 84, 72, + 32, 16, 114, 66, 28, 6, 76, 79, 78, 71, 32, 84, 130, 1, 77, 34, 78, 34, + 86, 34, 72, 145, 56, 6, 68, 79, 85, 66, 76, 69, 2, 149, 2, 3, 79, 76, 68, + 4, 17, 2, 73, 80, 4, 11, 32, 4, 34, 76, 21, 4, 82, 73, 71, 72, 2, 17, 2, + 69, 70, 2, 11, 84, 2, 11, 87, 2, 219, 126, 65, 2, 121, 5, 69, 68, 73, 85, + 77, 2, 89, 5, 65, 82, 82, 79, 87, 2, 29, 5, 69, 82, 89, 32, 72, 2, 25, 4, + 69, 65, 86, 89, 2, 173, 181, 2, 4, 32, 83, 72, 65, 2, 11, 65, 2, 249, 1, + 2, 83, 72, 2, 11, 65, 2, 25, 4, 73, 82, 69, 68, 2, 29, 5, 32, 65, 82, 82, + 79, 2, 163, 161, 2, 87, 2, 11, 76, 2, 135, 194, 1, 69, 6, 74, 32, 61, 14, + 45, 72, 69, 65, 68, 69, 68, 32, 65, 82, 82, 79, 87, 32, 2, 25, 4, 72, 69, + 65, 68, 2, 11, 69, 2, 255, 192, 1, 68, 4, 42, 87, 177, 136, 1, 4, 70, 82, + 79, 77, 2, 33, 6, 73, 84, 72, 32, 84, 82, 2, 61, 13, 73, 65, 78, 71, 76, + 69, 32, 65, 82, 82, 79, 87, 72, 2, 253, 121, 2, 69, 65, 18, 88, 5, 65, + 82, 82, 79, 87, 149, 3, 12, 68, 79, 85, 66, 76, 69, 32, 65, 82, 82, 79, + 87, 15, 11, 32, 12, 108, 11, 79, 78, 32, 80, 69, 68, 69, 83, 84, 65, 76, + 106, 87, 165, 181, 1, 8, 70, 82, 79, 77, 32, 66, 65, 82, 7, 33, 6, 32, + 87, 73, 84, 72, 32, 4, 26, 86, 247, 181, 1, 72, 2, 153, 182, 1, 5, 69, + 82, 84, 73, 67, 2, 29, 5, 73, 84, 72, 73, 78, 2, 17, 2, 32, 84, 2, 37, 7, + 82, 73, 65, 78, 71, 76, 69, 2, 11, 32, 2, 11, 65, 2, 25, 4, 82, 82, 79, + 87, 2, 11, 72, 2, 147, 146, 2, 69, 5, 45, 9, 32, 79, 78, 32, 80, 69, 68, + 69, 83, 2, 159, 204, 1, 84, 244, 15, 86, 65, 254, 16, 83, 174, 3, 69, + 194, 46, 73, 202, 8, 79, 134, 2, 84, 21, 2, 85, 76, 218, 8, 116, 2, 73, + 32, 128, 16, 17, 82, 73, 65, 84, 73, 79, 78, 32, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 233, 45, 2, 77, 80, 216, 4, 54, 67, 34, 70, 82, 81, 40, 2, + 83, 89, 183, 96, 68, 2, 11, 79, 2, 183, 180, 2, 77, 2, 11, 85, 2, 11, 76, + 2, 11, 76, 2, 11, 32, 2, 11, 83, 2, 227, 219, 1, 84, 2, 17, 2, 85, 69, 2, + 167, 235, 1, 83, 190, 4, 68, 7, 76, 76, 65, 66, 76, 69, 32, 197, 11, 5, + 77, 66, 79, 76, 32, 164, 4, 214, 1, 68, 70, 66, 2, 83, 2, 84, 2, 90, 70, + 71, 122, 72, 82, 75, 134, 1, 76, 130, 1, 77, 86, 78, 134, 3, 67, 2, 70, + 2, 74, 2, 80, 2, 82, 2, 86, 2, 89, 78, 87, 50, 69, 34, 79, 226, 74, 65, + 2, 73, 3, 85, 42, 66, 72, 162, 8, 79, 146, 137, 2, 69, 162, 64, 65, 2, + 73, 3, 85, 28, 230, 7, 72, 58, 79, 146, 137, 2, 69, 162, 64, 65, 2, 73, + 3, 85, 34, 62, 66, 202, 6, 69, 86, 79, 178, 201, 2, 65, 2, 73, 3, 85, 18, + 106, 79, 222, 5, 69, 134, 202, 2, 65, 2, 73, 3, 85, 24, 50, 79, 222, 5, + 69, 154, 76, 65, 2, 73, 3, 85, 7, 222, 207, 2, 78, 3, 79, 34, 70, 80, + 206, 5, 79, 198, 75, 65, 206, 189, 1, 69, 162, 64, 73, 3, 85, 18, 246, 4, + 69, 86, 79, 198, 75, 65, 238, 253, 1, 73, 3, 85, 16, 54, 69, 218, 4, 79, + 178, 201, 2, 65, 2, 73, 3, 85, 7, 26, 78, 239, 205, 2, 69, 2, 21, 3, 71, + 84, 72, 2, 219, 143, 2, 69, 42, 214, 3, 66, 0, 2, 71, 66, 58, 79, 146, + 137, 2, 69, 162, 64, 65, 2, 73, 3, 85, 90, 90, 68, 174, 1, 71, 126, 74, + 2, 89, 58, 79, 146, 137, 2, 69, 162, 64, 65, 2, 73, 3, 85, 24, 54, 79, + 186, 139, 2, 69, 162, 64, 65, 2, 73, 3, 85, 15, 36, 3, 76, 69, 32, 179, + 203, 2, 79, 10, 54, 83, 134, 172, 2, 68, 190, 28, 70, 2, 75, 3, 77, 2, + 131, 172, 2, 79, 25, 42, 71, 218, 250, 1, 65, 2, 69, 3, 79, 16, 50, 69, + 86, 79, 178, 201, 2, 65, 2, 73, 3, 85, 7, 130, 202, 2, 69, 3, 78, 14, 54, + 79, 146, 137, 2, 69, 162, 64, 65, 2, 73, 3, 85, 5, 175, 201, 2, 79, 28, + 46, 69, 34, 79, 226, 74, 65, 2, 73, 3, 85, 9, 254, 74, 69, 239, 253, 1, + 78, 9, 222, 74, 79, 239, 253, 1, 78, 26, 66, 68, 62, 70, 30, 74, 22, 75, + 50, 78, 22, 84, 231, 237, 1, 66, 6, 26, 79, 215, 246, 1, 65, 4, 210, 246, + 1, 79, 135, 50, 45, 4, 74, 69, 171, 196, 2, 65, 2, 151, 246, 1, 79, 4, + 26, 69, 235, 245, 1, 85, 2, 231, 245, 1, 69, 2, 243, 178, 2, 73, 6, 190, + 245, 1, 73, 2, 79, 195, 78, 65, 128, 4, 74, 49, 94, 50, 98, 51, 2, 52, 2, + 53, 2, 54, 2, 55, 2, 56, 3, 57, 223, 1, 182, 1, 48, 2, 49, 2, 50, 2, 51, + 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 137, 1, 90, 48, 2, 49, 2, 50, + 2, 51, 2, 52, 94, 53, 170, 195, 2, 54, 2, 55, 2, 56, 3, 57, 23, 130, 196, + 2, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 2, 54, 2, 55, 2, 56, 3, 57, 17, + 166, 195, 2, 48, 2, 49, 2, 50, 2, 51, 2, 52, 2, 53, 3, 54, 196, 1, 128, + 1, 4, 68, 73, 67, 32, 190, 19, 82, 152, 25, 2, 83, 84, 201, 131, 1, 13, + 67, 84, 79, 82, 32, 79, 82, 32, 67, 82, 79, 83, 83, 86, 60, 5, 83, 73, + 71, 78, 32, 137, 10, 5, 84, 79, 78, 69, 32, 48, 218, 2, 65, 216, 1, 17, + 68, 79, 85, 66, 76, 69, 32, 65, 78, 85, 83, 86, 65, 82, 65, 32, 65, 98, + 74, 52, 6, 78, 73, 72, 83, 72, 86, 22, 82, 240, 1, 8, 72, 69, 88, 73, 70, + 79, 82, 77, 22, 76, 52, 4, 84, 73, 82, 89, 22, 85, 60, 8, 86, 73, 83, 65, + 82, 71, 65, 32, 221, 6, 17, 89, 65, 74, 85, 82, 86, 69, 68, 73, 67, 32, + 77, 73, 68, 76, 73, 78, 14, 76, 8, 78, 85, 83, 86, 65, 82, 65, 32, 212, + 1, 3, 84, 73, 75, 151, 2, 82, 10, 134, 1, 65, 24, 4, 66, 65, 72, 73, 24, + 9, 85, 66, 72, 65, 89, 65, 84, 79, 32, 201, 4, 10, 86, 65, 77, 65, 71, + 79, 77, 85, 75, 72, 2, 21, 3, 78, 84, 65, 2, 21, 3, 82, 71, 79, 2, 11, + 77, 2, 147, 9, 85, 2, 175, 249, 1, 82, 2, 33, 6, 73, 72, 86, 65, 77, 85, + 2, 151, 3, 76, 2, 143, 185, 2, 65, 8, 144, 1, 15, 69, 86, 69, 82, 83, 69, + 68, 32, 86, 73, 83, 65, 82, 71, 65, 36, 9, 79, 84, 65, 84, 69, 68, 32, + 65, 82, 57, 5, 84, 72, 65, 78, 71, 4, 11, 32, 4, 202, 6, 65, 23, 85, 2, + 25, 4, 68, 72, 65, 86, 2, 141, 247, 1, 2, 73, 83, 2, 17, 2, 32, 76, 2, + 21, 3, 79, 78, 71, 2, 169, 244, 1, 2, 32, 65, 2, 239, 181, 2, 65, 2, 37, + 7, 80, 65, 68, 72, 77, 65, 78, 2, 239, 181, 2, 73, 10, 40, 3, 65, 78, 85, + 2, 85, 163, 9, 83, 4, 25, 4, 68, 65, 84, 84, 4, 11, 65, 5, 25, 4, 32, 87, + 73, 84, 2, 11, 72, 2, 11, 32, 2, 11, 84, 2, 211, 87, 65, 38, 128, 2, 5, + 67, 65, 78, 68, 82, 16, 2, 68, 79, 96, 2, 75, 65, 136, 1, 4, 80, 82, 69, + 78, 16, 2, 82, 73, 106, 84, 164, 1, 11, 89, 65, 74, 85, 82, 86, 69, 68, + 73, 67, 32, 180, 1, 12, 65, 84, 72, 65, 82, 86, 65, 86, 69, 68, 73, 67, + 253, 234, 1, 2, 83, 72, 4, 251, 18, 65, 6, 40, 5, 85, 66, 76, 69, 32, + 191, 3, 84, 4, 22, 82, 211, 5, 83, 2, 11, 73, 2, 251, 1, 78, 4, 56, 3, + 82, 83, 72, 17, 7, 84, 72, 65, 75, 65, 32, 65, 2, 203, 117, 65, 2, 17, 2, + 78, 85, 2, 17, 2, 68, 65, 2, 223, 142, 2, 84, 2, 239, 53, 75, 4, 82, 78, + 237, 2, 15, 71, 86, 69, 68, 73, 67, 32, 75, 65, 83, 72, 77, 73, 82, 73, + 2, 175, 181, 1, 71, 6, 42, 72, 24, 4, 82, 73, 80, 76, 19, 87, 2, 49, 3, + 82, 69, 69, 2, 219, 2, 69, 2, 11, 79, 2, 25, 4, 32, 68, 79, 84, 2, 11, + 83, 2, 11, 32, 2, 159, 15, 66, 8, 176, 1, 10, 65, 71, 71, 82, 65, 86, 65, + 84, 69, 68, 22, 73, 105, 27, 75, 65, 84, 72, 65, 75, 65, 32, 73, 78, 68, + 69, 80, 69, 78, 68, 69, 78, 84, 32, 83, 86, 65, 82, 73, 84, 65, 2, 17, 2, + 32, 73, 2, 49, 10, 78, 68, 69, 80, 69, 78, 68, 69, 78, 84, 2, 17, 2, 32, + 83, 2, 145, 138, 2, 3, 86, 65, 82, 5, 241, 10, 7, 32, 83, 67, 72, 82, 79, + 69, 104, 62, 83, 16, 6, 84, 73, 67, 65, 76, 32, 173, 17, 2, 89, 32, 2, + 223, 89, 73, 76, 200, 2, 4, 66, 65, 82, 32, 174, 3, 67, 42, 69, 62, 70, + 38, 71, 32, 11, 73, 68, 69, 79, 71, 82, 65, 80, 72, 73, 67, 48, 12, 75, + 65, 78, 65, 32, 82, 69, 80, 69, 65, 84, 32, 254, 1, 76, 186, 3, 77, 88, + 17, 79, 78, 69, 32, 69, 73, 71, 72, 84, 72, 32, 66, 76, 79, 67, 75, 45, + 62, 82, 158, 1, 84, 218, 1, 90, 237, 73, 3, 83, 73, 88, 8, 108, 6, 66, + 69, 83, 73, 68, 69, 64, 8, 68, 79, 85, 66, 76, 69, 32, 76, 20, 4, 84, 82, + 73, 80, 143, 1, 87, 2, 17, 2, 32, 82, 2, 21, 3, 73, 71, 72, 2, 223, 130, + 1, 84, 2, 69, 2, 69, 70, 2, 25, 4, 76, 69, 32, 82, 2, 21, 3, 73, 71, 72, + 2, 11, 84, 2, 29, 5, 32, 84, 85, 82, 78, 2, 11, 83, 2, 11, 84, 2, 139, + 130, 1, 73, 2, 21, 3, 73, 84, 72, 2, 17, 2, 32, 72, 2, 221, 247, 1, 7, + 79, 82, 73, 90, 79, 78, 84, 2, 225, 238, 1, 5, 65, 80, 65, 67, 73, 2, 25, + 4, 76, 76, 73, 80, 2, 11, 83, 2, 171, 233, 1, 73, 2, 11, 79, 2, 141, 84, + 2, 85, 82, 2, 177, 159, 1, 3, 79, 45, 75, 2, 17, 2, 32, 73, 2, 217, 188, + 1, 2, 84, 69, 10, 120, 4, 77, 65, 82, 75, 45, 22, 87, 73, 84, 72, 32, 86, + 79, 73, 67, 69, 68, 32, 83, 79, 85, 78, 68, 32, 77, 65, 82, 75, 7, 11, + 32, 4, 50, 85, 21, 3, 76, 79, 87, 5, 17, 2, 32, 85, 2, 17, 2, 80, 80, 2, + 17, 2, 69, 82, 2, 133, 30, 2, 32, 72, 16, 30, 65, 33, 3, 73, 78, 69, 2, + 11, 68, 2, 235, 229, 1, 68, 15, 11, 32, 12, 38, 69, 49, 5, 87, 73, 84, + 72, 32, 2, 25, 4, 88, 84, 69, 78, 2, 175, 210, 1, 83, 10, 60, 5, 67, 73, + 82, 67, 76, 86, 70, 26, 84, 215, 141, 1, 77, 4, 11, 69, 4, 11, 32, 4, 26, + 66, 131, 165, 1, 65, 2, 11, 69, 2, 183, 133, 1, 76, 2, 57, 3, 79, 85, 82, + 2, 11, 72, 2, 21, 3, 82, 69, 69, 2, 45, 9, 32, 84, 73, 67, 75, 32, 77, + 65, 82, 2, 131, 227, 1, 75, 2, 65, 14, 65, 76, 69, 32, 87, 73, 84, 72, + 32, 83, 84, 82, 79, 75, 2, 135, 153, 1, 69, 12, 242, 159, 2, 50, 2, 51, + 2, 52, 2, 53, 2, 54, 3, 55, 4, 42, 65, 57, 6, 69, 83, 73, 83, 84, 79, 2, + 25, 4, 67, 73, 78, 71, 2, 11, 32, 2, 167, 123, 67, 2, 21, 3, 82, 32, 83, + 2, 11, 69, 2, 251, 218, 1, 71, 10, 32, 2, 65, 66, 106, 73, 19, 82, 6, 18, + 32, 35, 85, 2, 11, 75, 2, 143, 140, 2, 69, 4, 33, 6, 76, 65, 84, 73, 79, + 78, 5, 239, 46, 32, 2, 155, 10, 76, 2, 29, 5, 65, 70, 70, 73, 67, 2, 141, + 242, 1, 2, 32, 76, 2, 177, 108, 4, 73, 71, 90, 65, 26, 80, 6, 72, 69, 65, + 86, 89, 32, 176, 5, 3, 77, 85, 67, 229, 10, 3, 66, 79, 76, 20, 62, 69, + 190, 1, 70, 38, 82, 82, 83, 246, 1, 87, 203, 11, 71, 4, 25, 4, 73, 71, + 72, 84, 4, 11, 32, 4, 22, 80, 223, 2, 83, 2, 25, 4, 79, 73, 78, 84, 2, + 17, 2, 69, 68, 2, 17, 2, 32, 66, 2, 25, 4, 76, 65, 67, 75, 2, 11, 32, 2, + 151, 81, 83, 2, 11, 73, 2, 185, 1, 2, 86, 69, 2, 11, 69, 2, 29, 5, 86, + 69, 82, 83, 69, 2, 17, 2, 32, 83, 2, 231, 1, 79, 6, 30, 65, 42, 73, 147, + 1, 79, 2, 11, 76, 2, 11, 84, 2, 235, 117, 73, 2, 11, 88, 2, 11, 32, 2, + 11, 83, 2, 21, 3, 80, 79, 75, 2, 17, 2, 69, 68, 2, 11, 32, 2, 11, 65, 2, + 11, 83, 2, 149, 80, 3, 84, 69, 82, 2, 161, 14, 3, 76, 73, 68, 4, 21, 3, + 72, 73, 84, 4, 11, 69, 4, 11, 32, 4, 162, 66, 67, 187, 49, 83, 4, 11, 72, + 4, 11, 32, 4, 18, 71, 39, 76, 2, 69, 6, 82, 69, 65, 84, 69, 82, 2, 11, + 69, 2, 11, 83, 2, 11, 83, 2, 17, 2, 45, 84, 2, 251, 72, 72, 4, 11, 65, 5, + 11, 32, 2, 11, 70, 2, 21, 3, 79, 82, 77, 2, 17, 2, 32, 84, 2, 195, 245, + 1, 87, 162, 1, 156, 1, 9, 66, 82, 65, 84, 73, 79, 78, 32, 77, 32, 4, 67, + 84, 79, 82, 36, 3, 68, 69, 79, 126, 69, 222, 1, 79, 22, 82, 21, 7, 84, + 72, 75, 85, 81, 73, 32, 2, 11, 79, 2, 159, 252, 1, 68, 4, 170, 130, 1, + 89, 255, 141, 1, 73, 6, 30, 32, 77, 3, 67, 65, 83, 4, 18, 67, 43, 71, 2, + 17, 2, 65, 77, 2, 179, 205, 1, 69, 2, 239, 119, 65, 2, 167, 72, 83, 6, 168, 1, 31, 84, 78, 65, 77, 69, 83, 69, 32, 65, 76, 84, 69, 82, 78, 65, - 84, 69, 32, 82, 69, 65, 68, 73, 78, 71, 32, 77, 65, 82, 75, 32, 189, 108, - 5, 87, 68, 65, 84, 65, 4, 26, 78, 219, 138, 2, 67, 2, 139, 129, 1, 72, 2, - 167, 141, 1, 76, 2, 243, 237, 1, 71, 140, 1, 56, 6, 67, 65, 80, 73, 84, + 84, 69, 32, 82, 69, 65, 68, 73, 78, 71, 32, 77, 65, 82, 75, 32, 161, 109, + 5, 87, 68, 65, 84, 65, 4, 26, 78, 195, 141, 2, 67, 2, 215, 129, 1, 72, 2, + 143, 144, 1, 76, 2, 219, 240, 1, 71, 140, 1, 56, 6, 67, 65, 80, 73, 84, 65, 1, 4, 83, 77, 65, 76, 70, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, 32, - 70, 230, 1, 66, 34, 69, 22, 73, 22, 76, 34, 78, 246, 136, 1, 67, 2, 68, + 70, 230, 1, 66, 34, 69, 22, 73, 22, 76, 34, 78, 222, 139, 1, 67, 2, 68, 2, 83, 2, 84, 226, 56, 72, 238, 48, 70, 2, 74, 2, 77, 2, 80, 2, 82, 2, 86, 2, 88, 2, 90, 158, 20, 71, 2, 75, 2, 81, 186, 2, 65, 2, 79, 2, 85, 3, - 89, 4, 166, 243, 1, 66, 215, 22, 69, 5, 219, 137, 2, 73, 5, 243, 242, 1, - 74, 4, 250, 134, 2, 76, 187, 2, 65, 4, 190, 242, 1, 74, 215, 22, 69, 8, - 28, 3, 73, 68, 69, 59, 76, 2, 21, 3, 68, 32, 71, 2, 141, 71, 4, 82, 69, - 69, 75, 6, 46, 67, 20, 3, 76, 69, 89, 41, 2, 85, 77, 2, 219, 222, 1, 65, - 2, 11, 66, 2, 11, 65, 2, 139, 126, 76, 2, 11, 69, 2, 17, 2, 32, 73, 2, - 193, 125, 4, 78, 84, 69, 71, 5, 239, 134, 2, 83, 40, 70, 67, 45, 13, 71, + 89, 4, 142, 246, 1, 66, 215, 22, 69, 5, 195, 140, 2, 73, 5, 219, 245, 1, + 74, 4, 226, 137, 2, 76, 187, 2, 65, 4, 166, 245, 1, 74, 215, 22, 69, 8, + 28, 3, 73, 68, 69, 59, 76, 2, 21, 3, 68, 32, 71, 2, 225, 71, 4, 82, 69, + 69, 75, 6, 46, 67, 20, 3, 76, 69, 89, 41, 2, 85, 77, 2, 195, 225, 1, 65, + 2, 11, 66, 2, 11, 65, 2, 215, 126, 76, 2, 11, 69, 2, 17, 2, 32, 73, 2, + 141, 126, 4, 78, 84, 69, 71, 5, 215, 137, 2, 83, 40, 70, 67, 45, 13, 71, 65, 82, 32, 70, 82, 65, 67, 84, 73, 79, 78, 32, 2, 11, 65, 2, 11, 78, 2, - 159, 200, 1, 85, 38, 106, 70, 96, 4, 79, 78, 69, 32, 178, 2, 84, 80, 7, + 135, 203, 1, 85, 38, 106, 70, 96, 4, 79, 78, 69, 32, 178, 2, 84, 80, 7, 83, 69, 86, 69, 78, 32, 69, 153, 33, 3, 90, 69, 82, 6, 56, 4, 73, 86, 69, 32, 253, 3, 5, 79, 85, 82, 32, 70, 4, 162, 3, 69, 113, 3, 83, 73, 88, 18, 66, 69, 28, 2, 70, 73, 18, 72, 34, 78, 14, 81, 30, 83, 55, 84, 2, 197, 1, - 3, 73, 71, 72, 2, 171, 1, 70, 2, 11, 65, 2, 251, 129, 1, 76, 2, 111, 73, - 2, 133, 75, 3, 85, 65, 82, 4, 24, 2, 69, 86, 15, 73, 2, 43, 69, 2, 43, - 88, 4, 18, 69, 35, 72, 2, 11, 78, 2, 255, 128, 2, 84, 2, 143, 107, 73, + 3, 73, 71, 72, 2, 171, 1, 70, 2, 11, 65, 2, 227, 132, 1, 76, 2, 111, 73, + 2, 217, 75, 3, 85, 65, 82, 4, 24, 2, 69, 86, 15, 73, 2, 43, 69, 2, 43, + 88, 4, 18, 69, 35, 72, 2, 11, 78, 2, 231, 131, 2, 84, 2, 243, 107, 73, 10, 48, 5, 72, 82, 69, 69, 32, 93, 3, 87, 79, 32, 6, 26, 69, 26, 81, 67, - 70, 2, 109, 3, 73, 71, 72, 2, 21, 3, 85, 65, 82, 2, 139, 114, 84, 4, 22, - 70, 219, 32, 84, 2, 11, 73, 2, 11, 70, 2, 205, 194, 1, 2, 84, 72, 164, 6, - 86, 65, 250, 23, 69, 158, 3, 72, 250, 68, 73, 234, 8, 79, 134, 6, 82, - 191, 144, 1, 74, 204, 2, 114, 70, 18, 78, 220, 5, 2, 88, 73, 158, 1, 82, - 210, 10, 84, 194, 1, 86, 221, 152, 1, 6, 83, 84, 69, 66, 65, 83, 2, 147, + 70, 2, 109, 3, 73, 71, 72, 2, 21, 3, 85, 65, 82, 2, 215, 114, 84, 4, 22, + 70, 219, 32, 84, 2, 11, 73, 2, 11, 70, 2, 181, 197, 1, 2, 84, 72, 168, 6, + 86, 65, 250, 23, 69, 158, 3, 72, 222, 69, 73, 234, 8, 79, 238, 5, 82, + 219, 146, 1, 74, 204, 2, 114, 70, 18, 78, 220, 5, 2, 88, 73, 158, 1, 82, + 210, 10, 84, 194, 1, 86, 197, 155, 1, 6, 83, 84, 69, 66, 65, 83, 2, 231, 90, 70, 122, 36, 4, 67, 72, 79, 32, 183, 5, 73, 118, 100, 7, 76, 69, 84, 84, 69, 82, 32, 252, 3, 3, 78, 71, 85, 16, 5, 84, 79, 78, 69, 32, 243, 7, 68, 88, 210, 1, 65, 38, 79, 34, 69, 22, 73, 22, 76, 50, 78, 42, 84, 50, - 85, 22, 89, 130, 178, 1, 75, 2, 80, 2, 83, 138, 69, 66, 2, 67, 2, 68, 2, + 85, 22, 89, 234, 180, 1, 75, 2, 80, 2, 83, 138, 69, 66, 2, 67, 2, 68, 2, 70, 2, 71, 2, 72, 2, 74, 2, 77, 2, 82, 2, 86, 2, 87, 3, 90, 13, 34, 65, - 210, 250, 1, 78, 87, 85, 7, 11, 78, 5, 151, 251, 1, 71, 5, 131, 251, 1, - 78, 5, 155, 250, 1, 78, 4, 26, 76, 195, 250, 1, 65, 2, 135, 248, 1, 72, - 6, 242, 247, 1, 71, 2, 89, 187, 2, 65, 8, 202, 247, 1, 72, 2, 82, 2, 83, - 187, 2, 65, 5, 243, 169, 1, 69, 4, 174, 248, 1, 73, 147, 1, 65, 2, 159, - 114, 78, 8, 40, 3, 75, 79, 73, 1, 3, 84, 85, 80, 5, 139, 229, 1, 78, 4, + 186, 253, 1, 78, 87, 85, 7, 11, 78, 5, 255, 253, 1, 71, 5, 235, 253, 1, + 78, 5, 131, 253, 1, 78, 4, 26, 76, 171, 253, 1, 65, 2, 239, 250, 1, 72, + 6, 218, 250, 1, 71, 2, 89, 187, 2, 65, 8, 178, 250, 1, 72, 2, 82, 2, 83, + 187, 2, 65, 5, 219, 172, 1, 69, 4, 150, 251, 1, 73, 147, 1, 65, 2, 135, + 117, 78, 8, 40, 3, 75, 79, 73, 1, 3, 84, 85, 80, 5, 243, 231, 1, 78, 4, 21, 3, 78, 71, 32, 4, 76, 8, 67, 82, 69, 83, 67, 69, 78, 84, 1, 7, 71, - 73, 66, 66, 79, 85, 83, 2, 21, 3, 32, 77, 79, 2, 11, 79, 2, 155, 100, 78, - 170, 1, 72, 9, 65, 78, 71, 32, 67, 73, 84, 73, 32, 229, 111, 4, 78, 73, + 73, 66, 66, 79, 85, 83, 2, 21, 3, 32, 77, 79, 2, 11, 79, 2, 231, 100, 78, + 170, 1, 72, 9, 65, 78, 71, 32, 67, 73, 84, 73, 32, 205, 114, 4, 78, 73, 78, 71, 168, 1, 128, 1, 6, 67, 65, 80, 73, 84, 65, 0, 4, 83, 77, 65, 76, - 190, 4, 68, 156, 2, 7, 78, 85, 77, 66, 69, 82, 32, 175, 222, 1, 79, 64, + 190, 4, 68, 156, 2, 7, 78, 85, 77, 66, 69, 82, 32, 151, 225, 1, 79, 64, 45, 9, 76, 32, 76, 69, 84, 84, 69, 82, 32, 64, 174, 1, 65, 38, 69, 42, - 72, 74, 78, 50, 79, 22, 83, 50, 85, 30, 89, 226, 42, 84, 180, 110, 2, 86, + 72, 74, 78, 50, 79, 22, 83, 50, 85, 30, 89, 174, 43, 84, 208, 112, 2, 86, 73, 222, 51, 66, 2, 80, 246, 5, 75, 158, 11, 73, 2, 87, 162, 17, 68, 3, - 71, 9, 166, 243, 1, 78, 86, 77, 3, 84, 7, 11, 78, 4, 202, 243, 1, 78, 3, - 89, 8, 38, 79, 198, 154, 1, 73, 235, 31, 65, 4, 170, 186, 1, 82, 235, 25, - 76, 4, 26, 71, 215, 161, 1, 85, 2, 147, 240, 1, 65, 5, 151, 172, 1, 68, - 4, 26, 83, 179, 222, 1, 73, 2, 159, 205, 1, 85, 4, 242, 241, 1, 67, 3, - 85, 8, 34, 85, 182, 241, 1, 65, 3, 79, 5, 179, 241, 1, 74, 20, 11, 73, + 71, 9, 142, 246, 1, 78, 86, 77, 3, 84, 7, 11, 78, 4, 178, 246, 1, 78, 3, + 89, 8, 38, 79, 174, 157, 1, 73, 235, 31, 65, 4, 146, 189, 1, 82, 235, 25, + 76, 4, 26, 71, 191, 164, 1, 85, 2, 251, 242, 1, 65, 5, 255, 174, 1, 68, + 4, 26, 83, 155, 225, 1, 73, 2, 135, 208, 1, 85, 4, 218, 244, 1, 67, 3, + 85, 8, 34, 85, 158, 244, 1, 65, 3, 79, 5, 155, 244, 1, 74, 20, 11, 73, 20, 11, 71, 20, 17, 2, 73, 84, 20, 11, 32, 20, 66, 70, 30, 83, 42, 84, - 62, 90, 238, 85, 78, 14, 79, 223, 110, 69, 4, 206, 115, 73, 131, 4, 79, - 4, 22, 69, 207, 99, 73, 2, 135, 28, 86, 4, 26, 72, 211, 208, 1, 87, 2, - 11, 82, 2, 227, 216, 1, 69, 2, 11, 69, 2, 163, 208, 1, 82, 18, 42, 69, + 62, 90, 210, 86, 78, 14, 79, 227, 112, 69, 4, 182, 118, 73, 131, 4, 79, + 4, 22, 69, 155, 100, 73, 2, 211, 28, 86, 4, 26, 72, 187, 211, 1, 87, 2, + 11, 82, 2, 203, 219, 1, 69, 2, 11, 69, 2, 139, 211, 1, 82, 18, 42, 69, 30, 70, 42, 78, 38, 83, 39, 84, 2, 221, 1, 3, 73, 71, 72, 4, 22, 73, 139, 1, 79, 2, 171, 1, 70, 2, 17, 2, 73, 78, 2, 135, 1, 69, 4, 92, 2, 69, 86, - 25, 2, 73, 88, 6, 34, 72, 26, 87, 179, 157, 1, 69, 2, 11, 73, 2, 35, 82, - 2, 11, 69, 2, 11, 78, 2, 175, 219, 1, 84, 12, 32, 2, 69, 82, 179, 235, 1, - 67, 10, 34, 32, 165, 156, 1, 2, 77, 69, 8, 80, 3, 67, 76, 79, 22, 87, - 228, 200, 1, 5, 66, 85, 70, 70, 65, 1, 2, 80, 79, 2, 175, 182, 1, 83, 2, - 223, 110, 65, 20, 60, 2, 69, 32, 124, 4, 73, 78, 71, 32, 161, 1, 2, 89, - 32, 6, 182, 2, 68, 161, 189, 1, 23, 65, 82, 82, 79, 87, 32, 80, 79, 73, + 25, 2, 73, 88, 6, 34, 72, 26, 87, 155, 160, 1, 69, 2, 11, 73, 2, 35, 82, + 2, 11, 69, 2, 11, 78, 2, 151, 222, 1, 84, 12, 32, 2, 69, 82, 155, 238, 1, + 67, 10, 34, 32, 141, 159, 1, 2, 77, 69, 8, 80, 3, 67, 76, 79, 22, 87, + 204, 203, 1, 5, 66, 85, 70, 70, 65, 1, 2, 80, 79, 2, 151, 185, 1, 83, 2, + 199, 113, 65, 20, 60, 2, 69, 32, 124, 4, 73, 78, 71, 32, 161, 1, 2, 89, + 32, 6, 182, 2, 68, 137, 192, 1, 23, 65, 82, 82, 79, 87, 32, 80, 79, 73, 78, 84, 73, 78, 71, 32, 68, 73, 82, 69, 67, 84, 76, 89, 6, 64, 5, 66, 76, 65, 67, 75, 0, 5, 87, 72, 73, 84, 69, 55, 72, 2, 17, 2, 32, 70, 2, 11, - 76, 2, 175, 232, 1, 65, 2, 11, 65, 2, 11, 78, 2, 215, 97, 68, 8, 26, 68, - 34, 76, 43, 79, 2, 11, 65, 2, 143, 231, 1, 83, 4, 22, 79, 203, 78, 73, 2, - 163, 78, 87, 2, 11, 86, 2, 11, 69, 2, 135, 78, 82, 14, 48, 3, 65, 82, 89, - 70, 68, 70, 73, 171, 1, 83, 4, 11, 32, 4, 32, 2, 67, 65, 211, 169, 1, 70, - 2, 183, 169, 1, 84, 4, 26, 71, 167, 149, 1, 68, 2, 129, 70, 6, 69, 45, + 76, 2, 151, 235, 1, 65, 2, 11, 65, 2, 11, 78, 2, 191, 100, 68, 8, 26, 68, + 34, 76, 43, 79, 2, 11, 65, 2, 247, 233, 1, 83, 4, 22, 79, 175, 79, 73, 2, + 135, 79, 87, 2, 11, 86, 2, 11, 69, 2, 235, 78, 82, 14, 48, 3, 65, 82, 89, + 70, 68, 70, 73, 171, 1, 83, 4, 11, 32, 4, 32, 2, 67, 65, 187, 172, 1, 70, + 2, 159, 172, 1, 84, 4, 26, 71, 143, 152, 1, 68, 2, 229, 70, 6, 69, 45, 84, 65, 73, 76, 4, 116, 17, 69, 82, 83, 84, 82, 65, 83, 83, 32, 69, 76, - 76, 73, 80, 84, 73, 67, 145, 45, 7, 71, 72, 84, 32, 76, 73, 70, 2, 17, 2, - 32, 70, 2, 149, 148, 1, 2, 85, 78, 2, 37, 7, 84, 32, 83, 89, 82, 73, 65, - 2, 131, 35, 67, 188, 2, 52, 3, 69, 69, 76, 100, 3, 73, 84, 69, 219, 62, - 65, 7, 60, 7, 32, 79, 70, 32, 68, 72, 65, 21, 4, 67, 72, 65, 73, 2, 147, - 194, 1, 82, 2, 231, 79, 82, 180, 2, 54, 32, 161, 66, 8, 45, 70, 69, 65, - 84, 72, 69, 82, 178, 2, 148, 2, 18, 65, 82, 82, 79, 87, 32, 83, 72, 65, - 70, 84, 32, 87, 73, 68, 84, 72, 32, 114, 66, 46, 67, 250, 15, 68, 166, 5, - 69, 50, 70, 178, 3, 72, 246, 3, 76, 210, 4, 77, 222, 1, 78, 34, 80, 146, + 76, 73, 80, 84, 73, 67, 229, 45, 7, 71, 72, 84, 32, 76, 73, 70, 2, 17, 2, + 32, 70, 2, 253, 150, 1, 2, 85, 78, 2, 37, 7, 84, 32, 83, 89, 82, 73, 65, + 2, 215, 35, 67, 192, 2, 52, 3, 69, 69, 76, 100, 3, 73, 84, 69, 175, 63, + 65, 7, 60, 7, 32, 79, 70, 32, 68, 72, 65, 21, 4, 67, 72, 65, 73, 2, 251, + 196, 1, 82, 2, 179, 80, 82, 184, 2, 54, 32, 133, 67, 8, 45, 70, 69, 65, + 84, 72, 69, 82, 182, 2, 148, 2, 18, 65, 82, 82, 79, 87, 32, 83, 72, 65, + 70, 84, 32, 87, 73, 68, 84, 72, 32, 114, 66, 46, 67, 198, 16, 68, 166, 5, + 69, 50, 70, 186, 3, 72, 246, 3, 76, 210, 4, 77, 222, 1, 78, 34, 80, 146, 1, 81, 78, 82, 142, 2, 83, 158, 12, 84, 228, 3, 2, 85, 80, 149, 4, 3, 86, - 69, 82, 4, 22, 84, 231, 70, 79, 2, 11, 87, 2, 21, 3, 79, 32, 84, 2, 17, - 2, 72, 73, 2, 11, 82, 2, 239, 161, 1, 68, 2, 11, 85, 2, 11, 76, 2, 135, - 170, 1, 76, 94, 154, 1, 72, 176, 10, 5, 73, 82, 67, 76, 69, 162, 3, 76, + 69, 82, 4, 22, 84, 203, 71, 79, 2, 11, 87, 2, 21, 3, 79, 32, 84, 2, 17, + 2, 72, 73, 2, 11, 82, 2, 215, 164, 1, 68, 2, 11, 85, 2, 11, 76, 2, 239, + 172, 1, 76, 98, 154, 1, 72, 252, 10, 5, 73, 82, 67, 76, 69, 162, 3, 76, 24, 20, 79, 78, 67, 65, 86, 69, 45, 83, 73, 68, 69, 68, 32, 68, 73, 65, - 77, 79, 78, 68, 79, 82, 66, 25, 4, 69, 83, 83, 32, 66, 66, 66, 38, 69, - 118, 75, 142, 4, 80, 22, 81, 38, 82, 131, 2, 84, 6, 241, 5, 5, 73, 83, - 72, 79, 80, 4, 45, 9, 81, 85, 73, 72, 79, 80, 80, 69, 82, 5, 17, 2, 32, - 82, 2, 129, 6, 8, 79, 84, 65, 84, 69, 68, 32, 78, 26, 38, 73, 25, 5, 78, - 73, 71, 72, 84, 6, 177, 4, 2, 78, 71, 21, 22, 32, 151, 3, 45, 12, 41, 8, - 82, 79, 84, 65, 84, 69, 68, 32, 12, 104, 2, 70, 79, 0, 15, 79, 78, 69, + 77, 79, 78, 68, 79, 82, 70, 25, 4, 69, 83, 83, 32, 70, 104, 3, 65, 76, + 70, 18, 66, 38, 69, 116, 3, 70, 69, 82, 22, 75, 142, 4, 80, 22, 81, 38, + 82, 131, 2, 84, 2, 255, 83, 73, 6, 133, 6, 5, 73, 83, 72, 79, 80, 4, 45, + 9, 81, 85, 73, 72, 79, 80, 80, 69, 82, 5, 17, 2, 32, 82, 2, 149, 6, 8, + 79, 84, 65, 84, 69, 68, 32, 78, 2, 167, 222, 1, 90, 26, 38, 73, 25, 5, + 78, 73, 71, 72, 84, 6, 177, 4, 2, 78, 71, 21, 22, 32, 151, 3, 45, 12, 41, + 8, 82, 79, 84, 65, 84, 69, 68, 32, 12, 104, 2, 70, 79, 0, 15, 79, 78, 69, 32, 72, 85, 78, 68, 82, 69, 68, 32, 84, 72, 73, 18, 84, 215, 3, 78, 2, 207, 1, 82, 6, 148, 1, 11, 87, 79, 32, 72, 85, 78, 68, 82, 69, 68, 32, 133, 3, 20, 72, 82, 69, 69, 32, 72, 85, 78, 68, 82, 69, 68, 32, 70, 73, @@ -8854,374 +8956,377 @@ static const unsigned char packed_name_dawg[] = { 87, 6, 21, 3, 85, 69, 69, 6, 35, 78, 6, 21, 3, 79, 79, 75, 7, 45, 9, 32, 82, 79, 84, 65, 84, 69, 68, 32, 4, 70, 78, 25, 13, 84, 87, 79, 32, 72, 85, 78, 68, 82, 69, 68, 32, 83, 2, 49, 3, 73, 78, 69, 2, 25, 4, 69, 86, - 69, 78, 2, 17, 2, 84, 89, 2, 225, 65, 6, 32, 68, 69, 71, 82, 69, 12, 29, + 69, 78, 2, 17, 2, 84, 89, 2, 241, 65, 6, 32, 68, 69, 71, 82, 69, 12, 29, 5, 85, 82, 78, 69, 68, 12, 11, 32, 12, 42, 66, 30, 75, 34, 80, 34, 81, - 47, 82, 2, 197, 91, 3, 73, 83, 72, 4, 198, 131, 1, 73, 171, 38, 78, 2, - 11, 65, 2, 179, 132, 1, 87, 2, 11, 85, 2, 11, 69, 2, 135, 132, 1, 69, 2, - 243, 169, 1, 79, 19, 11, 32, 16, 100, 16, 67, 79, 78, 84, 65, 73, 78, 73, + 47, 82, 2, 225, 93, 3, 73, 83, 72, 4, 226, 133, 1, 73, 171, 38, 78, 2, + 11, 65, 2, 207, 134, 1, 87, 2, 11, 85, 2, 11, 69, 2, 163, 134, 1, 69, 2, + 143, 172, 1, 79, 19, 11, 32, 16, 100, 16, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, 65, 67, 75, 121, 5, 87, 73, 84, 72, 32, 2, 17, 2, 32, 83, 2, 11, 77, 2, 21, 3, 65, 76, 76, 2, 11, 32, 2, 11, 67, 2, 11, 73, 2, - 11, 82, 2, 187, 45, 67, 14, 56, 2, 68, 79, 70, 84, 228, 31, 2, 76, 79, - 231, 1, 85, 4, 18, 84, 35, 87, 2, 11, 32, 2, 167, 166, 1, 82, 2, 143, 54, - 78, 2, 11, 87, 2, 11, 79, 2, 11, 32, 2, 247, 59, 68, 2, 209, 27, 2, 85, - 66, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 228, 30, 2, 76, 69, 49, 2, 82, - 73, 2, 17, 2, 79, 83, 2, 227, 141, 1, 83, 28, 76, 6, 73, 65, 77, 79, 78, + 11, 82, 2, 195, 45, 67, 14, 56, 2, 68, 79, 70, 84, 236, 31, 2, 76, 79, + 231, 1, 85, 4, 18, 84, 35, 87, 2, 11, 32, 2, 195, 168, 1, 82, 2, 167, 54, + 78, 2, 11, 87, 2, 11, 79, 2, 11, 32, 2, 147, 60, 68, 2, 217, 27, 2, 85, + 66, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 236, 30, 2, 76, 69, 49, 2, 82, + 73, 2, 17, 2, 79, 83, 2, 255, 143, 1, 83, 28, 76, 6, 73, 65, 77, 79, 78, 68, 216, 2, 3, 79, 87, 78, 177, 1, 2, 82, 65, 15, 11, 32, 12, 160, 1, 17, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, 65, 67, 75, 32, 128, - 1, 9, 87, 73, 84, 72, 32, 67, 69, 78, 84, 226, 23, 83, 197, 19, 2, 73, + 1, 9, 87, 73, 84, 72, 32, 67, 69, 78, 84, 234, 23, 83, 213, 19, 2, 73, 78, 6, 74, 83, 0, 6, 86, 69, 82, 89, 32, 83, 29, 6, 77, 69, 68, 73, 85, - 77, 2, 25, 4, 77, 65, 76, 76, 2, 197, 15, 2, 32, 68, 2, 11, 82, 2, 11, + 77, 2, 25, 4, 77, 65, 76, 76, 2, 205, 15, 2, 32, 68, 2, 11, 82, 2, 11, 69, 2, 231, 58, 68, 10, 96, 10, 32, 80, 79, 73, 78, 84, 73, 78, 71, 32, - 53, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 6, 170, 36, 66, 24, 5, - 76, 69, 70, 84, 32, 51, 73, 4, 194, 37, 83, 51, 84, 4, 33, 6, 85, 71, 72, - 84, 83, 32, 4, 22, 77, 255, 120, 75, 2, 159, 122, 65, 2, 29, 5, 88, 67, - 76, 65, 77, 2, 167, 15, 65, 14, 74, 76, 144, 2, 11, 79, 85, 82, 32, 80, + 53, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 6, 178, 36, 66, 24, 5, + 76, 69, 70, 84, 32, 51, 73, 4, 202, 37, 83, 51, 84, 4, 33, 6, 85, 71, 72, + 84, 83, 32, 4, 22, 77, 155, 123, 75, 2, 187, 124, 65, 2, 29, 5, 88, 67, + 76, 65, 77, 2, 175, 15, 65, 14, 74, 76, 144, 2, 11, 79, 85, 82, 32, 80, 79, 73, 78, 84, 69, 68, 71, 82, 8, 28, 2, 65, 71, 175, 1, 79, 5, 149, 1, 34, 32, 87, 73, 84, 72, 32, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 32, 77, 73, 68, 68, 76, 69, 32, 66, 76, 65, 67, 75, 32, 83, 84, 82, 73, 2, - 231, 176, 1, 80, 4, 26, 82, 163, 137, 1, 87, 2, 17, 2, 69, 84, 2, 163, - 176, 1, 84, 4, 11, 32, 4, 18, 67, 23, 83, 2, 171, 198, 1, 85, 2, 247, 36, - 84, 2, 235, 61, 79, 16, 34, 65, 150, 1, 69, 231, 1, 79, 2, 25, 4, 82, 68, - 32, 83, 2, 45, 9, 72, 69, 76, 76, 32, 70, 76, 79, 80, 2, 17, 2, 80, 89, - 2, 17, 2, 32, 68, 2, 11, 73, 2, 211, 193, 1, 83, 10, 22, 65, 151, 12, 88, - 8, 30, 82, 29, 3, 86, 89, 32, 4, 11, 84, 5, 211, 15, 32, 4, 74, 67, 53, - 14, 83, 65, 76, 84, 73, 82, 69, 32, 87, 73, 84, 72, 32, 82, 2, 17, 2, 72, - 69, 2, 11, 67, 2, 211, 129, 1, 75, 2, 167, 19, 79, 4, 60, 8, 82, 73, 90, - 79, 78, 84, 65, 76, 233, 42, 2, 85, 82, 2, 205, 31, 2, 32, 69, 22, 42, - 65, 116, 3, 69, 70, 84, 175, 1, 79, 4, 24, 2, 82, 71, 19, 84, 2, 227, 32, - 69, 2, 11, 73, 2, 11, 78, 2, 17, 2, 32, 67, 2, 11, 82, 2, 187, 42, 79, - 12, 58, 32, 77, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 6, 44, 6, 76, - 65, 78, 69, 32, 77, 247, 24, 80, 2, 11, 69, 2, 227, 10, 82, 6, 150, 2, - 80, 206, 24, 83, 51, 84, 6, 160, 1, 4, 87, 69, 82, 32, 221, 8, 30, 90, - 69, 78, 71, 69, 32, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, - 65, 67, 75, 32, 83, 77, 65, 76, 76, 32, 76, 4, 44, 3, 76, 69, 70, 1, 4, - 82, 73, 71, 72, 2, 11, 84, 2, 17, 2, 32, 80, 2, 203, 5, 79, 12, 68, 6, - 69, 68, 73, 85, 77, 32, 117, 7, 79, 79, 78, 32, 83, 69, 76, 10, 30, 68, - 54, 83, 227, 6, 76, 2, 11, 73, 2, 11, 65, 2, 11, 77, 2, 199, 46, 79, 6, - 246, 26, 84, 50, 77, 59, 81, 2, 11, 69, 2, 203, 185, 1, 78, 2, 11, 73, 2, - 227, 187, 1, 66, 6, 18, 65, 87, 69, 2, 37, 7, 82, 65, 76, 76, 69, 76, 79, - 2, 11, 71, 2, 11, 82, 2, 163, 170, 1, 65, 4, 11, 78, 4, 174, 2, 84, 211, - 46, 78, 2, 21, 3, 85, 69, 83, 2, 197, 118, 9, 84, 73, 79, 78, 32, 77, 65, - 82, 75, 14, 34, 69, 25, 4, 73, 71, 72, 84, 2, 129, 21, 2, 67, 84, 12, 60, - 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 211, 17, 32, 8, 30, 80, 202, - 19, 83, 51, 84, 4, 18, 69, 55, 79, 2, 11, 78, 2, 11, 84, 2, 11, 65, 2, - 179, 104, 71, 2, 11, 73, 2, 11, 78, 2, 139, 122, 84, 56, 118, 67, 32, 3, - 69, 83, 65, 18, 72, 58, 77, 166, 1, 80, 68, 5, 81, 85, 65, 82, 69, 180, - 6, 2, 85, 78, 183, 12, 84, 2, 153, 40, 4, 73, 83, 83, 79, 2, 175, 37, 77, - 2, 21, 3, 79, 71, 73, 2, 169, 121, 4, 32, 80, 73, 69, 8, 32, 4, 65, 76, - 76, 32, 115, 73, 6, 18, 76, 71, 83, 2, 11, 79, 2, 11, 90, 2, 11, 69, 2, - 11, 78, 2, 203, 158, 1, 71, 4, 210, 19, 84, 107, 81, 2, 211, 44, 76, 2, - 21, 3, 65, 68, 69, 2, 11, 32, 2, 11, 83, 2, 251, 151, 1, 85, 29, 11, 32, - 26, 114, 66, 36, 17, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, 66, 76, - 65, 67, 75, 32, 85, 5, 87, 73, 84, 72, 32, 2, 17, 2, 85, 84, 2, 159, 99, - 84, 6, 54, 86, 178, 17, 83, 37, 6, 77, 69, 68, 73, 85, 77, 2, 153, 17, 3, - 69, 82, 89, 18, 150, 1, 76, 50, 82, 214, 1, 85, 144, 1, 17, 86, 69, 82, - 84, 73, 67, 65, 76, 32, 66, 73, 83, 69, 67, 84, 73, 78, 233, 19, 6, 67, - 69, 78, 84, 82, 69, 6, 18, 69, 15, 79, 2, 67, 70, 4, 247, 1, 87, 4, 18, - 73, 115, 79, 2, 17, 2, 71, 72, 2, 33, 6, 84, 87, 65, 82, 68, 83, 2, 11, - 32, 2, 11, 84, 2, 11, 73, 2, 215, 172, 1, 67, 2, 29, 5, 85, 78, 68, 69, - 68, 2, 21, 3, 32, 67, 79, 2, 193, 32, 2, 82, 78, 4, 17, 2, 80, 80, 4, 21, - 3, 69, 82, 32, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, 2, 33, 6, 84, - 32, 81, 85, 65, 68, 2, 175, 36, 82, 2, 171, 20, 71, 11, 11, 32, 8, 84, - 12, 66, 69, 72, 73, 78, 68, 32, 67, 76, 79, 85, 68, 69, 5, 87, 73, 84, - 72, 32, 5, 29, 5, 32, 87, 73, 84, 72, 2, 17, 2, 32, 82, 2, 255, 44, 65, - 4, 38, 82, 29, 5, 83, 77, 65, 76, 76, 2, 11, 65, 2, 179, 110, 89, 2, 11, - 32, 2, 21, 3, 67, 76, 79, 2, 187, 101, 85, 10, 38, 79, 54, 69, 62, 82, - 203, 1, 87, 2, 49, 10, 85, 67, 72, 84, 79, 78, 69, 32, 84, 69, 2, 17, 2, - 76, 69, 2, 11, 80, 2, 11, 72, 2, 151, 17, 79, 4, 148, 1, 4, 65, 80, 69, - 90, 33, 28, 73, 65, 78, 71, 76, 69, 32, 67, 79, 78, 84, 65, 73, 78, 73, - 78, 71, 32, 83, 77, 65, 76, 76, 32, 87, 72, 73, 84, 2, 11, 73, 2, 183, - 152, 1, 85, 2, 135, 4, 69, 2, 11, 79, 2, 85, 19, 45, 87, 65, 89, 32, 76, - 69, 70, 84, 32, 87, 65, 89, 32, 84, 82, 65, 70, 70, 2, 11, 73, 2, 251, - 167, 1, 67, 12, 62, 32, 185, 1, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, - 32, 4, 11, 80, 4, 41, 8, 79, 73, 78, 84, 73, 78, 71, 32, 4, 18, 66, 75, - 73, 2, 21, 3, 65, 67, 75, 2, 25, 4, 72, 65, 78, 68, 2, 17, 2, 32, 73, 2, - 17, 2, 78, 68, 2, 219, 25, 69, 8, 54, 67, 42, 83, 125, 7, 84, 82, 73, 65, - 78, 71, 76, 2, 21, 3, 72, 69, 86, 2, 179, 85, 82, 2, 25, 4, 77, 65, 76, - 76, 2, 17, 2, 32, 84, 2, 17, 2, 82, 73, 2, 11, 65, 2, 11, 78, 2, 11, 71, - 2, 211, 141, 1, 76, 4, 11, 69, 5, 11, 32, 2, 11, 87, 2, 217, 18, 3, 73, - 84, 72, 10, 44, 6, 84, 73, 67, 65, 76, 32, 255, 1, 89, 8, 62, 69, 48, 9, - 82, 69, 67, 84, 65, 78, 71, 76, 69, 127, 66, 2, 11, 76, 2, 17, 2, 76, 73, - 2, 183, 25, 80, 5, 37, 7, 32, 87, 73, 84, 72, 32, 72, 2, 37, 7, 79, 82, - 73, 90, 79, 78, 84, 2, 17, 2, 65, 76, 2, 11, 32, 2, 11, 66, 2, 219, 104, - 65, 2, 17, 2, 32, 83, 2, 11, 77, 2, 21, 3, 65, 76, 76, 2, 17, 2, 32, 83, - 2, 11, 81, 2, 11, 85, 2, 11, 65, 2, 227, 137, 1, 82, 2, 11, 69, 2, 11, - 68, 2, 17, 2, 32, 82, 2, 21, 3, 73, 71, 72, 2, 11, 84, 2, 11, 87, 2, 241, - 4, 4, 65, 82, 68, 83, 100, 140, 1, 10, 68, 69, 45, 72, 69, 65, 68, 69, - 68, 32, 132, 4, 4, 71, 71, 76, 89, 124, 6, 76, 84, 69, 68, 32, 70, 42, - 78, 189, 1, 2, 82, 69, 80, 128, 1, 3, 76, 69, 70, 0, 4, 82, 73, 71, 72, - 12, 4, 68, 79, 87, 78, 0, 2, 85, 80, 32, 3, 78, 79, 82, 1, 3, 83, 79, 85, - 10, 11, 84, 10, 109, 5, 87, 65, 82, 68, 83, 20, 21, 3, 84, 72, 32, 20, - 32, 2, 69, 65, 1, 2, 87, 69, 10, 17, 2, 83, 84, 10, 11, 32, 10, 110, 72, - 0, 6, 86, 69, 82, 89, 32, 72, 28, 5, 76, 73, 71, 72, 84, 0, 6, 77, 69, - 68, 73, 85, 77, 23, 66, 2, 25, 4, 69, 65, 86, 89, 2, 17, 2, 32, 66, 2, - 21, 3, 65, 82, 66, 2, 11, 32, 2, 11, 65, 2, 11, 82, 2, 11, 82, 2, 131, - 28, 79, 2, 17, 2, 32, 86, 2, 11, 69, 2, 33, 6, 82, 84, 73, 67, 65, 76, 2, - 11, 32, 2, 11, 76, 2, 11, 73, 2, 215, 130, 1, 78, 2, 11, 76, 2, 11, 79, - 2, 147, 91, 87, 12, 46, 68, 106, 69, 186, 15, 75, 163, 136, 1, 71, 6, 22, - 32, 139, 26, 79, 4, 44, 2, 67, 72, 217, 15, 4, 66, 76, 79, 87, 2, 11, 73, - 2, 151, 129, 1, 77, 2, 11, 32, 2, 121, 3, 71, 76, 65, 4, 36, 5, 68, 32, - 75, 69, 89, 51, 76, 2, 17, 2, 66, 79, 2, 11, 65, 2, 203, 80, 82, 2, 11, - 69, 2, 243, 88, 83, 30, 66, 77, 158, 3, 82, 226, 11, 78, 226, 64, 79, - 129, 9, 2, 76, 70, 14, 36, 2, 65, 78, 161, 2, 2, 69, 78, 13, 72, 12, 32, - 87, 73, 84, 72, 32, 66, 85, 78, 78, 89, 32, 29, 2, 83, 32, 2, 11, 69, 2, - 167, 6, 65, 8, 48, 2, 66, 79, 28, 2, 67, 76, 54, 72, 19, 83, 2, 11, 79, - 2, 207, 86, 84, 2, 11, 79, 2, 11, 84, 2, 11, 72, 2, 155, 86, 69, 2, 187, - 119, 65, 2, 17, 2, 65, 78, 2, 131, 10, 68, 2, 11, 83, 2, 11, 32, 2, 11, - 83, 2, 11, 89, 2, 17, 2, 77, 66, 2, 187, 9, 79, 10, 72, 2, 68, 32, 156, - 1, 3, 76, 68, 32, 32, 2, 82, 73, 219, 144, 1, 77, 4, 56, 9, 83, 69, 80, - 65, 82, 65, 84, 79, 82, 203, 83, 74, 2, 17, 2, 32, 77, 2, 21, 3, 73, 68, - 68, 2, 11, 76, 2, 11, 69, 2, 11, 32, 2, 207, 64, 68, 2, 11, 77, 2, 223, - 144, 1, 65, 2, 11, 69, 2, 171, 83, 68, 10, 56, 7, 65, 80, 80, 69, 68, 32, - 80, 30, 69, 163, 1, 73, 2, 213, 76, 3, 82, 69, 83, 6, 48, 2, 65, 84, 80, - 3, 83, 84, 76, 187, 108, 78, 2, 11, 72, 2, 11, 32, 2, 11, 80, 2, 25, 4, - 82, 79, 68, 85, 2, 195, 114, 67, 2, 11, 69, 2, 247, 80, 82, 2, 11, 84, 2, - 11, 73, 2, 17, 2, 78, 71, 2, 17, 2, 32, 72, 2, 11, 65, 2, 215, 71, 78, - 34, 76, 2, 32, 73, 138, 1, 45, 28, 7, 73, 65, 78, 71, 81, 73, 32, 155, - 83, 79, 2, 53, 11, 78, 32, 65, 32, 82, 69, 67, 84, 65, 78, 71, 2, 11, 76, - 2, 11, 69, 2, 11, 32, 2, 11, 66, 2, 11, 79, 2, 163, 140, 1, 88, 2, 11, - 82, 2, 187, 122, 65, 28, 48, 5, 66, 76, 65, 67, 75, 1, 3, 82, 69, 68, 14, - 11, 32, 14, 130, 1, 67, 72, 4, 69, 76, 69, 80, 28, 4, 71, 69, 78, 69, 46, - 72, 36, 4, 83, 79, 76, 68, 169, 9, 6, 77, 65, 78, 68, 65, 82, 4, 24, 2, - 65, 78, 19, 72, 2, 167, 58, 78, 2, 201, 57, 3, 65, 82, 73, 2, 11, 72, 2, - 191, 70, 65, 2, 11, 82, 2, 11, 65, 2, 179, 137, 1, 76, 2, 17, 2, 79, 82, - 2, 183, 114, 83, 2, 143, 75, 73, 242, 19, 50, 65, 58, 69, 226, 11, 73, - 217, 35, 2, 79, 45, 2, 17, 2, 87, 78, 2, 11, 73, 2, 241, 74, 2, 78, 71, - 98, 60, 4, 76, 76, 79, 87, 62, 78, 53, 5, 90, 73, 68, 73, 32, 2, 17, 2, - 32, 72, 2, 11, 69, 2, 11, 65, 2, 227, 106, 82, 2, 11, 32, 2, 11, 83, 2, - 11, 73, 2, 251, 54, 71, 94, 112, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, - 32, 76, 5, 72, 89, 80, 72, 69, 17, 7, 76, 69, 84, 84, 69, 82, 32, 4, 44, - 3, 77, 65, 68, 13, 4, 72, 65, 77, 90, 2, 11, 68, 2, 215, 67, 65, 2, 215, - 27, 78, 88, 250, 1, 67, 50, 77, 18, 68, 42, 69, 58, 72, 30, 75, 22, 71, - 2, 81, 32, 3, 76, 65, 77, 98, 78, 18, 80, 30, 83, 66, 84, 28, 2, 86, 65, - 126, 87, 14, 79, 18, 88, 52, 3, 89, 79, 84, 154, 1, 90, 134, 53, 82, 238, - 48, 66, 254, 5, 85, 162, 14, 70, 3, 74, 6, 22, 72, 147, 114, 73, 4, 22, - 72, 251, 113, 73, 2, 247, 113, 73, 4, 11, 65, 4, 178, 130, 1, 68, 3, 76, - 8, 42, 76, 142, 50, 89, 226, 79, 84, 3, 87, 2, 71, 73, 4, 150, 112, 65, - 147, 15, 72, 4, 18, 72, 15, 65, 2, 11, 65, 2, 163, 129, 1, 70, 5, 11, 32, - 2, 11, 87, 2, 21, 3, 73, 84, 72, 2, 17, 2, 32, 68, 2, 11, 79, 2, 187, 3, - 84, 2, 207, 48, 85, 4, 202, 105, 72, 215, 22, 69, 8, 46, 72, 246, 47, 73, - 194, 9, 65, 163, 70, 69, 2, 243, 47, 73, 4, 238, 104, 72, 215, 22, 65, 5, - 37, 7, 32, 65, 76, 84, 69, 82, 78, 2, 17, 2, 65, 84, 2, 11, 69, 2, 11, - 32, 2, 11, 70, 2, 11, 79, 2, 227, 109, 82, 2, 11, 65, 2, 159, 126, 87, 4, - 22, 72, 251, 125, 65, 2, 11, 69, 2, 139, 46, 89, 5, 37, 7, 32, 87, 73, - 84, 72, 32, 67, 2, 45, 9, 73, 82, 67, 85, 77, 70, 76, 69, 88, 2, 11, 32, - 2, 11, 65, 2, 11, 66, 2, 11, 79, 2, 255, 101, 86, 6, 22, 65, 175, 124, - 69, 5, 171, 124, 76, 140, 19, 34, 32, 161, 35, 3, 78, 32, 89, 138, 19, - 88, 8, 82, 65, 68, 73, 67, 65, 76, 32, 181, 7, 9, 83, 89, 76, 76, 65, 66, - 76, 69, 32, 110, 170, 1, 66, 42, 67, 86, 68, 42, 71, 74, 72, 66, 74, 66, - 75, 30, 76, 30, 77, 26, 78, 74, 80, 26, 83, 74, 84, 30, 86, 30, 89, 30, - 90, 250, 35, 81, 198, 49, 87, 235, 30, 79, 4, 22, 66, 247, 64, 85, 2, - 163, 93, 85, 12, 42, 85, 18, 89, 178, 98, 72, 203, 22, 73, 2, 135, 121, - 79, 7, 130, 121, 80, 3, 84, 4, 22, 68, 215, 120, 85, 2, 247, 63, 85, 10, - 42, 71, 238, 91, 79, 162, 28, 69, 15, 65, 4, 162, 89, 85, 235, 30, 79, 8, - 22, 88, 243, 88, 77, 6, 238, 88, 85, 202, 2, 73, 163, 28, 79, 8, 22, 74, - 167, 119, 79, 6, 246, 90, 85, 218, 5, 73, 215, 22, 89, 4, 206, 90, 73, - 175, 28, 69, 6, 190, 54, 73, 199, 7, 89, 4, 182, 118, 79, 15, 73, 8, 30, - 89, 26, 90, 199, 90, 66, 4, 254, 117, 73, 3, 79, 2, 231, 117, 85, 4, 182, - 89, 85, 3, 89, 10, 22, 72, 223, 97, 83, 8, 214, 60, 85, 178, 28, 65, 162, - 28, 79, 15, 89, 4, 214, 88, 65, 175, 28, 85, 4, 138, 60, 85, 211, 56, 69, - 4, 158, 88, 73, 175, 28, 79, 10, 54, 85, 224, 62, 2, 90, 73, 238, 24, 79, - 175, 28, 65, 4, 246, 115, 80, 3, 82, 156, 18, 134, 2, 66, 134, 1, 67, - 162, 1, 68, 110, 70, 50, 71, 150, 1, 72, 138, 3, 73, 134, 1, 74, 98, 75, - 54, 76, 62, 77, 134, 1, 78, 234, 4, 80, 54, 81, 2, 89, 46, 82, 162, 1, - 83, 134, 1, 84, 102, 86, 82, 87, 58, 88, 50, 90, 140, 2, 2, 85, 79, 66, - 65, 2, 79, 107, 69, 132, 1, 66, 66, 238, 21, 85, 150, 1, 69, 26, 73, 42, - 65, 2, 79, 67, 89, 64, 234, 21, 85, 150, 1, 69, 26, 73, 42, 65, 2, 79, 3, - 89, 122, 66, 72, 238, 20, 85, 150, 1, 69, 26, 73, 42, 65, 2, 79, 67, 89, - 54, 46, 85, 146, 22, 65, 2, 69, 2, 79, 67, 89, 19, 142, 22, 79, 106, 82, - 230, 88, 80, 3, 88, 106, 58, 68, 138, 15, 85, 134, 5, 73, 94, 69, 66, 65, - 3, 79, 54, 210, 19, 85, 58, 73, 94, 69, 66, 65, 3, 79, 42, 182, 20, 79, - 66, 65, 2, 73, 2, 89, 67, 85, 116, 58, 71, 214, 15, 85, 146, 4, 73, 42, - 65, 2, 69, 3, 79, 56, 50, 73, 162, 15, 85, 186, 4, 65, 2, 69, 3, 79, 13, - 150, 19, 69, 142, 90, 84, 3, 88, 246, 1, 78, 73, 30, 76, 58, 77, 54, 78, - 110, 88, 50, 85, 254, 15, 69, 66, 65, 3, 79, 6, 198, 19, 69, 231, 88, 84, - 64, 238, 16, 85, 58, 73, 94, 69, 2, 79, 66, 65, 67, 89, 58, 182, 16, 85, - 58, 73, 158, 1, 65, 2, 79, 35, 89, 42, 46, 79, 34, 85, 202, 16, 69, 26, - 73, 43, 65, 6, 242, 106, 80, 2, 84, 3, 88, 6, 238, 17, 79, 231, 88, 84, - 46, 46, 85, 254, 15, 69, 26, 73, 42, 65, 3, 79, 8, 187, 16, 79, 19, 42, - 84, 130, 16, 69, 206, 89, 80, 3, 88, 5, 11, 69, 2, 11, 82, 2, 11, 65, 2, - 11, 84, 2, 11, 73, 2, 11, 79, 2, 191, 39, 78, 106, 50, 74, 190, 10, 85, - 146, 4, 73, 42, 79, 67, 89, 50, 158, 13, 85, 174, 1, 73, 42, 79, 3, 89, - 56, 242, 12, 85, 58, 73, 158, 1, 65, 2, 69, 3, 79, 70, 218, 9, 85, 250, - 3, 69, 26, 73, 42, 65, 2, 79, 67, 89, 106, 70, 71, 218, 8, 85, 158, 3, - 73, 158, 1, 65, 2, 79, 2, 89, 107, 69, 44, 186, 11, 85, 150, 1, 69, 66, - 65, 2, 79, 105, 2, 73, 69, 248, 2, 102, 66, 54, 68, 94, 71, 90, 74, 46, - 82, 50, 89, 78, 90, 134, 7, 85, 58, 73, 94, 65, 2, 69, 67, 79, 54, 202, - 10, 73, 158, 1, 65, 2, 79, 66, 85, 3, 89, 46, 46, 73, 198, 10, 69, 66, - 65, 2, 79, 67, 85, 13, 234, 11, 69, 230, 88, 80, 2, 84, 3, 88, 34, 60, 2, - 85, 79, 218, 9, 69, 0, 2, 73, 69, 66, 65, 3, 79, 7, 226, 99, 84, 3, 88, - 50, 230, 1, 85, 242, 7, 73, 42, 79, 67, 89, 46, 146, 9, 79, 66, 65, 2, - 69, 66, 85, 3, 89, 38, 30, 85, 222, 8, 73, 43, 79, 15, 194, 8, 79, 142, - 90, 80, 2, 84, 3, 88, 56, 62, 85, 206, 4, 79, 178, 2, 73, 158, 1, 65, 66, - 89, 43, 69, 15, 254, 8, 79, 2, 82, 230, 88, 80, 3, 88, 60, 150, 6, 85, - 58, 73, 158, 1, 65, 2, 79, 67, 89, 56, 254, 2, 85, 146, 4, 73, 42, 79, - 67, 89, 100, 58, 82, 254, 4, 85, 150, 1, 69, 66, 65, 2, 79, 67, 89, 48, - 46, 85, 162, 6, 69, 2, 79, 66, 89, 43, 65, 17, 134, 7, 79, 2, 82, 230, - 88, 80, 2, 84, 3, 88, 176, 1, 70, 83, 158, 3, 72, 50, 85, 58, 73, 94, 69, - 66, 65, 2, 79, 67, 89, 56, 130, 4, 73, 94, 69, 66, 65, 2, 79, 2, 85, 67, - 89, 56, 46, 85, 158, 3, 73, 94, 69, 66, 65, 3, 79, 21, 182, 4, 79, 106, - 82, 230, 88, 80, 2, 84, 3, 88, 60, 54, 69, 166, 3, 73, 42, 65, 2, 79, 66, - 85, 3, 89, 4, 150, 93, 80, 3, 88, 28, 38, 85, 206, 2, 69, 2, 79, 67, 65, - 9, 203, 2, 79, 40, 210, 2, 73, 42, 79, 66, 89, 41, 2, 85, 79, 178, 1, 66, - 72, 50, 85, 58, 73, 42, 90, 54, 69, 66, 65, 2, 79, 67, 89, 54, 46, 85, - 214, 1, 65, 2, 69, 2, 79, 67, 89, 19, 146, 1, 79, 170, 1, 82, 230, 88, - 80, 2, 84, 3, 88, 15, 90, 69, 142, 90, 80, 2, 84, 3, 88, 58, 50, 69, 2, - 79, 26, 73, 42, 65, 34, 85, 35, 89, 7, 138, 90, 80, 3, 88, 17, 38, 69, - 206, 89, 80, 2, 84, 3, 88, 9, 202, 89, 80, 2, 84, 3, 88, 11, 70, 82, 230, - 88, 80, 3, 88, 13, 38, 82, 230, 88, 80, 2, 84, 3, 88, 5, 227, 88, 88, 2, - 219, 7, 65, 2, 207, 57, 89, 180, 4, 252, 1, 10, 32, 78, 79, 84, 65, 84, - 73, 79, 78, 32, 224, 6, 16, 65, 78, 65, 66, 65, 90, 65, 82, 32, 83, 81, - 85, 65, 82, 69, 32, 210, 15, 69, 180, 2, 6, 73, 80, 80, 69, 82, 45, 96, - 8, 78, 65, 77, 69, 78, 78, 89, 32, 188, 33, 3, 79, 77, 66, 235, 26, 87, - 26, 144, 1, 9, 66, 65, 71, 32, 77, 69, 77, 66, 69, 42, 82, 104, 6, 68, - 79, 77, 65, 73, 78, 60, 3, 76, 69, 70, 154, 1, 83, 145, 2, 3, 84, 89, 80, - 2, 11, 82, 2, 11, 83, 2, 215, 83, 72, 8, 100, 4, 65, 78, 71, 69, 60, 3, - 73, 71, 72, 221, 1, 11, 69, 76, 65, 84, 73, 79, 78, 65, 76, 32, 67, 2, - 173, 3, 11, 32, 65, 78, 84, 73, 82, 69, 83, 84, 82, 73, 4, 17, 2, 84, 32, - 4, 60, 4, 73, 77, 65, 71, 13, 7, 66, 73, 78, 68, 73, 78, 71, 2, 11, 69, - 2, 25, 4, 32, 66, 82, 65, 2, 11, 67, 2, 175, 29, 75, 8, 44, 6, 67, 72, - 69, 77, 65, 32, 211, 1, 80, 6, 18, 67, 71, 80, 2, 17, 2, 79, 77, 2, 11, - 80, 2, 11, 79, 2, 11, 83, 2, 107, 73, 4, 30, 73, 41, 3, 82, 79, 74, 2, - 11, 80, 2, 11, 73, 2, 163, 80, 78, 2, 11, 69, 2, 11, 67, 2, 11, 84, 2, - 87, 73, 2, 139, 52, 79, 2, 11, 69, 2, 11, 32, 2, 11, 67, 2, 11, 79, 2, - 11, 76, 2, 11, 79, 2, 223, 79, 78, 144, 1, 240, 1, 2, 67, 76, 68, 7, 73, - 78, 73, 84, 73, 65, 76, 204, 2, 14, 70, 73, 78, 65, 76, 32, 67, 79, 78, - 83, 79, 78, 65, 78, 16, 7, 76, 69, 84, 84, 69, 82, 32, 148, 3, 5, 77, 65, - 82, 75, 32, 206, 1, 83, 181, 3, 6, 86, 79, 87, 69, 76, 32, 14, 64, 5, 79, - 83, 73, 78, 71, 137, 1, 6, 85, 83, 84, 69, 82, 45, 4, 11, 32, 4, 64, 12, - 68, 79, 85, 66, 76, 69, 45, 76, 73, 78, 69, 68, 23, 72, 2, 17, 2, 32, 72, - 2, 17, 2, 69, 65, 2, 215, 10, 68, 10, 96, 13, 70, 73, 78, 65, 76, 32, 76, - 69, 84, 84, 69, 82, 32, 41, 7, 73, 78, 73, 84, 73, 65, 76, 8, 238, 72, - 76, 2, 82, 2, 86, 3, 89, 2, 37, 7, 32, 76, 69, 84, 84, 69, 82, 2, 151, 6, - 32, 2, 131, 9, 84, 82, 166, 1, 68, 50, 75, 38, 78, 46, 83, 38, 84, 46, - 66, 2, 67, 2, 71, 2, 80, 2, 90, 138, 69, 45, 2, 72, 2, 74, 2, 76, 2, 77, - 2, 82, 2, 86, 2, 89, 187, 2, 65, 12, 206, 1, 68, 2, 90, 138, 69, 72, 187, - 2, 65, 6, 154, 70, 83, 14, 72, 187, 2, 65, 8, 130, 70, 71, 2, 78, 2, 89, - 187, 2, 65, 6, 214, 69, 72, 2, 83, 187, 2, 65, 12, 42, 83, 2, 84, 138, - 69, 72, 187, 2, 65, 4, 134, 69, 72, 187, 2, 65, 8, 50, 68, 58, 83, 40, 4, - 76, 79, 78, 71, 23, 84, 2, 29, 5, 79, 85, 66, 76, 69, 2, 11, 32, 2, 11, - 83, 2, 11, 72, 2, 11, 65, 2, 159, 70, 68, 2, 17, 2, 32, 84, 2, 17, 2, 83, - 72, 2, 147, 69, 69, 14, 36, 4, 73, 71, 78, 32, 255, 2, 85, 12, 54, 65, - 72, 6, 67, 65, 78, 68, 82, 65, 167, 1, 86, 2, 11, 78, 2, 11, 85, 2, 17, - 2, 83, 86, 2, 11, 65, 2, 135, 66, 82, 6, 36, 5, 66, 73, 78, 68, 85, 15, - 32, 5, 11, 32, 2, 25, 4, 87, 73, 84, 72, 2, 17, 2, 32, 79, 2, 21, 3, 82, - 78, 65, 2, 11, 77, 2, 11, 69, 2, 239, 38, 78, 4, 11, 73, 4, 18, 82, 19, - 83, 2, 219, 33, 65, 2, 11, 65, 2, 11, 82, 2, 139, 64, 71, 2, 151, 4, 66, - 20, 38, 76, 109, 5, 83, 73, 71, 78, 32, 2, 17, 2, 69, 78, 2, 11, 71, 2, - 11, 84, 2, 11, 72, 2, 11, 32, 2, 11, 77, 2, 11, 65, 2, 135, 62, 82, 18, - 86, 65, 26, 79, 2, 85, 16, 8, 82, 69, 86, 69, 82, 83, 69, 68, 146, 64, - 69, 3, 73, 4, 182, 64, 73, 3, 85, 5, 159, 64, 69, 2, 183, 44, 32, 12, 72, - 2, 66, 82, 16, 9, 82, 79, 32, 87, 73, 68, 84, 72, 32, 203, 1, 85, 2, 147, - 2, 65, 8, 32, 2, 78, 79, 86, 83, 31, 74, 4, 26, 45, 73, 2, 78, 45, 2, 29, - 5, 66, 82, 69, 65, 75, 2, 11, 32, 2, 11, 83, 2, 163, 1, 80, 2, 11, 74, 2, - 11, 79, 2, 11, 73, 2, 11, 78, 2, 143, 5, 69, 2, 219, 61, 83, 2, 21, 3, - 77, 79, 85, 2, 17, 2, 84, 72, 2, 11, 32, 2, 11, 70, 2, 11, 65, 2, 167, - 38, 67, 242, 2, 168, 1, 10, 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 224, - 18, 6, 78, 69, 85, 77, 69, 32, 181, 38, 17, 80, 82, 73, 90, 78, 65, 75, - 32, 77, 79, 68, 73, 70, 73, 69, 82, 32, 128, 1, 144, 2, 17, 76, 79, 87, - 69, 82, 32, 84, 79, 78, 65, 76, 32, 82, 65, 78, 71, 69, 88, 5, 77, 65, - 82, 75, 32, 148, 3, 18, 65, 84, 84, 65, 67, 72, 73, 78, 71, 32, 86, 69, - 82, 84, 73, 67, 65, 76, 233, 11, 17, 84, 79, 78, 65, 76, 32, 82, 65, 78, - 71, 69, 32, 77, 65, 82, 75, 32, 2, 33, 6, 32, 73, 78, 68, 73, 67, 2, 11, - 65, 2, 11, 84, 2, 11, 79, 2, 219, 56, 82, 118, 182, 2, 67, 142, 1, 68, - 104, 8, 71, 79, 82, 65, 90, 68, 79, 32, 34, 78, 106, 75, 114, 79, 72, 2, - 80, 79, 152, 2, 8, 77, 65, 76, 79, 32, 80, 79, 86, 100, 2, 82, 65, 50, - 83, 186, 1, 84, 108, 7, 86, 89, 83, 79, 75, 79, 32, 234, 1, 90, 224, 10, - 2, 76, 79, 224, 22, 4, 85, 68, 65, 82, 129, 6, 4, 66, 79, 82, 90, 6, 60, - 6, 72, 65, 83, 72, 75, 65, 29, 5, 85, 82, 86, 69, 68, 5, 197, 47, 3, 32, - 80, 79, 2, 17, 2, 32, 79, 2, 11, 77, 2, 235, 24, 69, 4, 240, 10, 13, 69, - 77, 69, 83, 84, 86, 69, 78, 78, 89, 32, 90, 65, 217, 14, 6, 86, 79, 69, - 84, 79, 67, 10, 30, 78, 89, 3, 86, 89, 83, 8, 29, 5, 73, 90, 75, 79, 32, - 8, 164, 8, 8, 83, 32, 75, 82, 89, 90, 72, 69, 35, 79, 2, 167, 20, 79, 8, - 56, 4, 82, 89, 90, 72, 150, 6, 65, 233, 39, 2, 85, 80, 5, 21, 3, 32, 79, - 78, 2, 11, 32, 2, 203, 7, 76, 6, 220, 5, 3, 84, 83, 69, 200, 13, 5, 66, - 76, 65, 67, 72, 131, 31, 78, 18, 22, 68, 131, 2, 86, 6, 60, 7, 67, 72, - 65, 83, 72, 73, 69, 201, 22, 3, 86, 69, 82, 5, 17, 2, 32, 87, 2, 21, 3, - 73, 84, 72, 2, 17, 2, 32, 86, 2, 29, 5, 69, 82, 84, 73, 67, 2, 17, 2, 65, - 76, 2, 11, 32, 2, 11, 83, 2, 11, 84, 2, 11, 82, 2, 11, 79, 2, 131, 25, - 75, 12, 29, 5, 89, 83, 72, 69, 32, 12, 22, 83, 251, 3, 79, 8, 154, 3, 32, - 229, 2, 4, 84, 82, 65, 78, 4, 28, 2, 90, 83, 183, 5, 86, 2, 219, 37, 69, - 10, 136, 1, 2, 75, 79, 16, 16, 84, 82, 65, 78, 78, 79, 32, 77, 65, 76, - 79, 32, 80, 79, 86, 89, 236, 1, 5, 82, 69, 68, 78, 69, 231, 26, 79, 2, - 239, 42, 66, 2, 11, 83, 2, 183, 22, 72, 10, 50, 79, 16, 5, 83, 65, 84, - 65, 32, 139, 36, 73, 2, 187, 28, 67, 6, 158, 1, 79, 201, 24, 3, 83, 32, - 75, 10, 24, 2, 83, 32, 95, 79, 6, 11, 75, 6, 44, 6, 72, 79, 75, 72, 76, - 79, 247, 24, 82, 4, 11, 77, 4, 17, 2, 32, 79, 4, 11, 78, 4, 11, 32, 4, - 18, 76, 31, 82, 2, 11, 69, 2, 179, 14, 70, 2, 11, 73, 2, 11, 71, 2, 139, - 14, 72, 6, 18, 65, 31, 69, 2, 249, 25, 3, 68, 69, 82, 4, 22, 86, 239, 10, - 76, 2, 199, 38, 79, 6, 60, 5, 77, 82, 65, 67, 72, 18, 83, 1, 4, 84, 82, - 69, 83, 2, 155, 10, 78, 2, 17, 2, 86, 69, 2, 155, 6, 84, 232, 1, 128, 2, - 2, 67, 72, 38, 68, 218, 1, 70, 28, 10, 71, 79, 76, 85, 66, 67, 72, 73, - 75, 32, 158, 1, 75, 160, 2, 6, 77, 69, 67, 72, 73, 75, 184, 1, 2, 78, 69, - 18, 79, 138, 2, 80, 146, 2, 82, 114, 83, 180, 20, 9, 86, 82, 65, 75, 72, - 73, 89, 65, 32, 151, 2, 90, 4, 246, 11, 69, 209, 10, 2, 65, 83, 10, 74, - 69, 98, 85, 16, 9, 86, 65, 32, 86, 32, 67, 72, 69, 76, 187, 27, 79, 4, - 76, 2, 82, 66, 213, 2, 12, 77, 69, 83, 84, 86, 69, 78, 78, 89, 32, 75, - 76, 2, 195, 34, 73, 2, 203, 34, 68, 2, 11, 78, 2, 231, 36, 85, 2, 11, 73, - 2, 147, 34, 84, 10, 78, 84, 38, 83, 240, 3, 5, 77, 82, 65, 67, 72, 145, - 14, 4, 66, 79, 82, 90, 4, 32, 3, 82, 69, 83, 251, 1, 73, 2, 21, 3, 86, - 69, 84, 2, 231, 17, 76, 14, 76, 4, 72, 65, 77, 73, 18, 76, 40, 3, 79, 66, - 89, 16, 2, 82, 89, 87, 85, 2, 219, 3, 76, 2, 11, 89, 2, 11, 85, 2, 151, - 33, 67, 2, 223, 31, 76, 6, 28, 2, 85, 75, 219, 32, 90, 5, 21, 3, 32, 84, - 73, 2, 11, 75, 2, 251, 15, 72, 2, 11, 70, 2, 11, 73, 2, 11, 83, 2, 215, - 30, 77, 11, 11, 32, 8, 44, 7, 75, 76, 89, 85, 67, 72, 69, 83, 80, 6, 64, - 9, 78, 69, 80, 79, 83, 84, 79, 89, 65, 14, 80, 163, 14, 86, 2, 39, 78, 2, - 25, 4, 79, 86, 79, 68, 2, 143, 14, 78, 2, 223, 22, 77, 14, 40, 2, 66, 76, - 41, 4, 83, 79, 75, 65, 2, 11, 65, 2, 11, 75, 2, 243, 30, 79, 13, 11, 32, - 10, 30, 75, 142, 26, 84, 39, 83, 6, 104, 11, 76, 89, 85, 67, 72, 69, 86, - 65, 89, 65, 32, 185, 25, 10, 82, 89, 85, 75, 79, 86, 65, 89, 65, 32, 4, - 202, 16, 78, 251, 8, 83, 14, 58, 65, 88, 8, 69, 82, 69, 86, 79, 68, 75, - 65, 27, 79, 6, 44, 3, 82, 65, 75, 222, 19, 76, 211, 5, 85, 2, 11, 76, 2, - 11, 73, 2, 171, 28, 84, 5, 153, 15, 2, 32, 78, 4, 68, 5, 68, 67, 72, 65, - 83, 245, 9, 7, 76, 75, 85, 76, 73, 90, 77, 2, 11, 72, 2, 219, 4, 73, 4, - 64, 11, 69, 86, 69, 82, 83, 69, 68, 32, 67, 72, 69, 139, 26, 79, 2, 25, - 4, 76, 89, 85, 83, 2, 215, 17, 84, 126, 96, 9, 75, 65, 77, 69, 89, 84, - 83, 65, 32, 148, 2, 8, 76, 79, 90, 72, 73, 84, 73, 69, 119, 84, 22, 128, - 1, 13, 68, 86, 79, 69, 67, 72, 69, 76, 78, 65, 89, 65, 32, 44, 7, 75, 76, - 89, 85, 67, 72, 69, 74, 84, 218, 18, 77, 119, 83, 8, 218, 10, 75, 110, - 78, 178, 8, 80, 75, 83, 6, 40, 5, 86, 65, 89, 65, 32, 243, 10, 78, 4, - 178, 15, 84, 183, 4, 83, 4, 162, 15, 73, 147, 4, 82, 9, 11, 32, 6, 48, 2, - 83, 32, 25, 6, 90, 65, 75, 82, 89, 84, 4, 166, 4, 75, 95, 90, 2, 11, 79, - 2, 211, 22, 69, 96, 92, 4, 65, 84, 89, 65, 172, 4, 6, 79, 80, 73, 84, 83, - 65, 189, 1, 5, 82, 69, 76, 65, 32, 23, 11, 32, 20, 76, 2, 83, 32, 236, 2, - 9, 90, 65, 75, 82, 89, 84, 65, 89, 65, 159, 5, 78, 14, 160, 1, 14, 68, - 86, 85, 77, 89, 65, 32, 90, 65, 80, 89, 65, 84, 89, 28, 7, 75, 82, 89, - 90, 72, 69, 77, 24, 2, 82, 79, 17, 8, 90, 65, 80, 89, 65, 84, 79, 89, 2, - 11, 77, 2, 215, 19, 73, 5, 189, 1, 2, 32, 73, 2, 203, 2, 71, 7, 21, 3, - 32, 73, 32, 4, 54, 75, 37, 9, 80, 79, 68, 67, 72, 65, 83, 72, 73, 2, 11, - 82, 2, 21, 3, 89, 90, 72, 2, 211, 1, 69, 5, 17, 2, 32, 83, 2, 17, 2, 32, - 90, 2, 29, 5, 65, 80, 89, 65, 84, 2, 11, 79, 2, 199, 17, 89, 7, 11, 32, - 4, 68, 6, 83, 32, 79, 67, 72, 75, 29, 7, 87, 73, 84, 72, 32, 83, 79, 2, - 11, 79, 2, 215, 16, 77, 2, 45, 9, 82, 79, 67, 72, 89, 65, 32, 78, 79, 2, - 11, 90, 2, 163, 7, 72, 68, 140, 1, 9, 68, 86, 79, 69, 67, 72, 69, 76, 78, - 162, 1, 75, 78, 78, 174, 1, 71, 152, 3, 8, 77, 82, 65, 67, 72, 78, 79, - 84, 42, 80, 75, 84, 10, 18, 79, 71, 65, 6, 64, 7, 80, 79, 86, 79, 68, 78, - 65, 189, 5, 4, 75, 82, 89, 90, 4, 17, 2, 89, 65, 5, 17, 2, 32, 75, 2, - 145, 5, 4, 76, 89, 85, 67, 26, 48, 6, 76, 89, 85, 67, 72, 69, 77, 2, 82, - 89, 4, 22, 78, 203, 6, 80, 2, 157, 8, 9, 69, 80, 79, 83, 84, 79, 89, 65, - 78, 22, 48, 7, 85, 75, 79, 86, 65, 89, 65, 195, 3, 90, 21, 11, 32, 18, - 54, 71, 236, 2, 5, 84, 82, 89, 65, 83, 179, 2, 80, 14, 21, 3, 82, 79, 77, - 14, 32, 4, 78, 65, 89, 65, 47, 79, 5, 237, 1, 7, 32, 87, 73, 84, 72, 32, - 83, 10, 92, 10, 75, 82, 89, 90, 72, 69, 86, 65, 89, 65, 17, 9, 80, 79, - 86, 79, 68, 78, 65, 89, 65, 5, 175, 2, 32, 7, 33, 6, 32, 87, 73, 84, 72, - 32, 4, 24, 2, 68, 79, 23, 83, 2, 41, 2, 85, 66, 2, 21, 3, 73, 78, 71, 2, - 133, 6, 6, 76, 69, 32, 90, 65, 80, 2, 175, 6, 75, 2, 237, 5, 3, 72, 69, - 86, 2, 11, 73, 2, 11, 75, 2, 187, 5, 72, 6, 22, 79, 187, 3, 82, 4, 28, 2, - 76, 85, 187, 1, 86, 2, 163, 1, 80, 8, 80, 5, 82, 89, 65, 83, 79, 153, 2, - 10, 73, 75, 72, 65, 89, 65, 32, 80, 85, 84, 6, 62, 80, 44, 4, 83, 84, 82, - 69, 173, 1, 4, 71, 76, 65, 83, 2, 17, 2, 79, 86, 2, 193, 1, 2, 79, 68, 2, - 171, 1, 76, 16, 88, 12, 75, 76, 89, 85, 67, 72, 69, 86, 65, 89, 65, 32, - 38, 77, 46, 80, 38, 84, 39, 83, 8, 34, 77, 46, 80, 38, 84, 39, 83, 2, 25, - 4, 82, 65, 67, 72, 2, 247, 1, 78, 2, 11, 82, 2, 205, 1, 2, 79, 83, 2, 11, - 82, 2, 11, 69, 2, 11, 83, 2, 157, 1, 4, 86, 69, 84, 76, 6, 30, 65, 121, - 3, 77, 69, 89, 4, 32, 4, 78, 79, 90, 72, 31, 80, 2, 11, 69, 2, 151, 3, - 75, 2, 17, 2, 89, 65, 2, 11, 84, 2, 11, 65, 2, 35, 89, 2, 11, 84, 2, 11, - 83, 2, 183, 2, 65, 10, 108, 11, 68, 73, 82, 69, 67, 84, 73, 79, 78, 32, - 70, 28, 3, 75, 82, 89, 28, 5, 76, 69, 86, 69, 76, 35, 82, 2, 11, 76, 2, - 159, 1, 73, 2, 11, 90, 2, 143, 1, 72, 4, 11, 45, 4, 114, 50, 3, 51, 2, - 11, 79, 2, 83, 71, 8, 26, 78, 34, 83, 15, 74, 4, 18, 66, 27, 74, 2, 11, - 83, 2, 11, 80, 3, 0, + 131, 179, 1, 80, 4, 26, 82, 191, 139, 1, 87, 2, 17, 2, 69, 84, 2, 191, + 178, 1, 84, 4, 11, 32, 4, 18, 67, 23, 83, 2, 199, 200, 1, 85, 2, 143, 37, + 84, 2, 141, 64, 2, 79, 87, 16, 34, 65, 150, 1, 69, 231, 1, 79, 2, 25, 4, + 82, 68, 32, 83, 2, 45, 9, 72, 69, 76, 76, 32, 70, 76, 79, 80, 2, 17, 2, + 80, 89, 2, 17, 2, 32, 68, 2, 11, 73, 2, 231, 195, 1, 83, 10, 22, 65, 151, + 12, 88, 8, 30, 82, 29, 3, 86, 89, 32, 4, 11, 84, 5, 211, 15, 32, 4, 74, + 67, 53, 14, 83, 65, 76, 84, 73, 82, 69, 32, 87, 73, 84, 72, 32, 82, 2, + 17, 2, 72, 69, 2, 11, 67, 2, 231, 131, 1, 75, 2, 167, 19, 79, 4, 60, 8, + 82, 73, 90, 79, 78, 84, 65, 76, 249, 42, 2, 85, 82, 2, 201, 31, 2, 32, + 69, 22, 42, 65, 116, 3, 69, 70, 84, 175, 1, 79, 4, 24, 2, 82, 71, 19, 84, + 2, 243, 32, 69, 2, 11, 73, 2, 11, 78, 2, 17, 2, 32, 67, 2, 11, 82, 2, + 203, 42, 79, 12, 58, 32, 77, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, + 6, 44, 6, 76, 65, 78, 69, 32, 77, 247, 24, 80, 2, 11, 69, 2, 227, 10, 82, + 6, 150, 2, 80, 206, 24, 83, 51, 84, 6, 160, 1, 4, 87, 69, 82, 32, 221, 8, + 30, 90, 69, 78, 71, 69, 32, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, + 66, 76, 65, 67, 75, 32, 83, 77, 65, 76, 76, 32, 76, 4, 44, 3, 76, 69, 70, + 1, 4, 82, 73, 71, 72, 2, 11, 84, 2, 17, 2, 32, 80, 2, 203, 5, 79, 12, 68, + 6, 69, 68, 73, 85, 77, 32, 117, 7, 79, 79, 78, 32, 83, 69, 76, 10, 30, + 68, 54, 83, 227, 6, 76, 2, 11, 73, 2, 11, 65, 2, 11, 77, 2, 191, 46, 79, + 6, 134, 27, 84, 50, 77, 59, 81, 2, 11, 69, 2, 223, 187, 1, 78, 2, 11, 73, + 2, 247, 189, 1, 66, 6, 18, 65, 87, 69, 2, 37, 7, 82, 65, 76, 76, 69, 76, + 79, 2, 11, 71, 2, 11, 82, 2, 183, 172, 1, 65, 4, 11, 78, 4, 174, 2, 84, + 203, 46, 78, 2, 21, 3, 85, 69, 83, 2, 217, 120, 9, 84, 73, 79, 78, 32, + 77, 65, 82, 75, 14, 34, 69, 25, 4, 73, 71, 72, 84, 2, 129, 21, 2, 67, 84, + 12, 60, 10, 45, 80, 79, 73, 78, 84, 73, 78, 71, 32, 211, 17, 32, 8, 30, + 80, 202, 19, 83, 51, 84, 4, 18, 69, 55, 79, 2, 11, 78, 2, 11, 84, 2, 11, + 65, 2, 199, 106, 71, 2, 11, 73, 2, 11, 78, 2, 159, 124, 84, 56, 118, 67, + 32, 3, 69, 83, 65, 18, 72, 58, 77, 166, 1, 80, 68, 5, 81, 85, 65, 82, 69, + 180, 6, 2, 85, 78, 199, 12, 84, 2, 145, 40, 4, 73, 83, 83, 79, 2, 167, + 37, 77, 2, 21, 3, 79, 71, 73, 2, 189, 123, 4, 32, 80, 73, 69, 8, 32, 4, + 65, 76, 76, 32, 115, 73, 6, 18, 76, 71, 83, 2, 11, 79, 2, 11, 90, 2, 11, + 69, 2, 11, 78, 2, 223, 160, 1, 71, 4, 226, 19, 84, 107, 81, 2, 231, 46, + 76, 2, 21, 3, 65, 68, 69, 2, 11, 32, 2, 11, 83, 2, 143, 154, 1, 85, 29, + 11, 32, 26, 114, 66, 36, 17, 67, 79, 78, 84, 65, 73, 78, 73, 78, 71, 32, + 66, 76, 65, 67, 75, 32, 85, 5, 87, 73, 84, 72, 32, 2, 17, 2, 85, 84, 2, + 179, 101, 84, 6, 54, 86, 194, 17, 83, 37, 6, 77, 69, 68, 73, 85, 77, 2, + 169, 17, 3, 69, 82, 89, 18, 150, 1, 76, 50, 82, 214, 1, 85, 144, 1, 17, + 86, 69, 82, 84, 73, 67, 65, 76, 32, 66, 73, 83, 69, 67, 84, 73, 78, 249, + 19, 6, 67, 69, 78, 84, 82, 69, 6, 18, 69, 15, 79, 2, 67, 70, 4, 247, 1, + 87, 4, 18, 73, 115, 79, 2, 17, 2, 71, 72, 2, 33, 6, 84, 87, 65, 82, 68, + 83, 2, 11, 32, 2, 11, 84, 2, 11, 73, 2, 235, 174, 1, 67, 2, 29, 5, 85, + 78, 68, 69, 68, 2, 21, 3, 32, 67, 79, 2, 185, 32, 2, 82, 78, 4, 17, 2, + 80, 80, 4, 21, 3, 69, 82, 32, 4, 44, 3, 76, 69, 70, 1, 4, 82, 73, 71, 72, + 2, 33, 6, 84, 32, 81, 85, 65, 68, 2, 167, 36, 82, 2, 187, 20, 71, 11, 11, + 32, 8, 84, 12, 66, 69, 72, 73, 78, 68, 32, 67, 76, 79, 85, 68, 69, 5, 87, + 73, 84, 72, 32, 5, 29, 5, 32, 87, 73, 84, 72, 2, 17, 2, 32, 82, 2, 147, + 47, 65, 4, 38, 82, 29, 5, 83, 77, 65, 76, 76, 2, 11, 65, 2, 199, 112, 89, + 2, 11, 32, 2, 21, 3, 67, 76, 79, 2, 207, 103, 85, 10, 38, 79, 54, 69, 62, + 82, 203, 1, 87, 2, 49, 10, 85, 67, 72, 84, 79, 78, 69, 32, 84, 69, 2, 17, + 2, 76, 69, 2, 11, 80, 2, 11, 72, 2, 167, 17, 79, 4, 148, 1, 4, 65, 80, + 69, 90, 33, 28, 73, 65, 78, 71, 76, 69, 32, 67, 79, 78, 84, 65, 73, 78, + 73, 78, 71, 32, 83, 77, 65, 76, 76, 32, 87, 72, 73, 84, 2, 11, 73, 2, + 203, 154, 1, 85, 2, 135, 4, 69, 2, 11, 79, 2, 85, 19, 45, 87, 65, 89, 32, + 76, 69, 70, 84, 32, 87, 65, 89, 32, 84, 82, 65, 70, 70, 2, 11, 73, 2, + 143, 170, 1, 67, 12, 62, 32, 185, 1, 10, 45, 80, 79, 73, 78, 84, 73, 78, + 71, 32, 4, 11, 80, 4, 41, 8, 79, 73, 78, 84, 73, 78, 71, 32, 4, 18, 66, + 75, 73, 2, 21, 3, 65, 67, 75, 2, 25, 4, 72, 65, 78, 68, 2, 17, 2, 32, 73, + 2, 17, 2, 78, 68, 2, 211, 25, 69, 8, 54, 67, 42, 83, 125, 7, 84, 82, 73, + 65, 78, 71, 76, 2, 21, 3, 72, 69, 86, 2, 199, 87, 82, 2, 25, 4, 77, 65, + 76, 76, 2, 17, 2, 32, 84, 2, 17, 2, 82, 73, 2, 11, 65, 2, 11, 78, 2, 11, + 71, 2, 231, 143, 1, 76, 4, 11, 69, 5, 11, 32, 2, 11, 87, 2, 209, 18, 3, + 73, 84, 72, 10, 44, 6, 84, 73, 67, 65, 76, 32, 143, 2, 89, 8, 58, 69, 48, + 7, 82, 69, 67, 84, 65, 78, 71, 147, 1, 66, 2, 11, 76, 2, 17, 2, 76, 73, + 2, 183, 25, 80, 4, 17, 2, 76, 69, 5, 37, 7, 32, 87, 73, 84, 72, 32, 72, + 2, 37, 7, 79, 82, 73, 90, 79, 78, 84, 2, 17, 2, 65, 76, 2, 11, 32, 2, 11, + 66, 2, 223, 106, 65, 2, 17, 2, 32, 83, 2, 11, 77, 2, 21, 3, 65, 76, 76, + 2, 17, 2, 32, 83, 2, 11, 81, 2, 11, 85, 2, 11, 65, 2, 231, 139, 1, 82, 2, + 11, 69, 2, 11, 68, 2, 17, 2, 32, 82, 2, 21, 3, 73, 71, 72, 2, 11, 84, 2, + 11, 87, 2, 241, 4, 4, 65, 82, 68, 83, 100, 140, 1, 10, 68, 69, 45, 72, + 69, 65, 68, 69, 68, 32, 132, 4, 4, 71, 71, 76, 89, 124, 6, 76, 84, 69, + 68, 32, 70, 42, 78, 189, 1, 2, 82, 69, 80, 128, 1, 3, 76, 69, 70, 0, 4, + 82, 73, 71, 72, 12, 4, 68, 79, 87, 78, 0, 2, 85, 80, 32, 3, 78, 79, 82, + 1, 3, 83, 79, 85, 10, 11, 84, 10, 109, 5, 87, 65, 82, 68, 83, 20, 21, 3, + 84, 72, 32, 20, 32, 2, 69, 65, 1, 2, 87, 69, 10, 17, 2, 83, 84, 10, 11, + 32, 10, 110, 72, 0, 6, 86, 69, 82, 89, 32, 72, 28, 5, 76, 73, 71, 72, 84, + 0, 6, 77, 69, 68, 73, 85, 77, 23, 66, 2, 25, 4, 69, 65, 86, 89, 2, 17, 2, + 32, 66, 2, 21, 3, 65, 82, 66, 2, 11, 32, 2, 11, 65, 2, 11, 82, 2, 11, 82, + 2, 135, 30, 79, 2, 17, 2, 32, 86, 2, 11, 69, 2, 33, 6, 82, 84, 73, 67, + 65, 76, 2, 11, 32, 2, 11, 76, 2, 11, 73, 2, 219, 132, 1, 78, 2, 11, 76, + 2, 11, 79, 2, 151, 93, 87, 12, 46, 68, 106, 69, 190, 17, 75, 163, 136, 1, + 71, 6, 22, 32, 143, 28, 79, 4, 44, 2, 67, 72, 221, 17, 4, 66, 76, 79, 87, + 2, 11, 73, 2, 155, 131, 1, 77, 2, 11, 32, 2, 121, 3, 71, 76, 65, 4, 36, + 5, 68, 32, 75, 69, 89, 51, 76, 2, 17, 2, 66, 79, 2, 11, 65, 2, 207, 82, + 82, 2, 11, 69, 2, 247, 90, 83, 30, 66, 77, 134, 3, 82, 254, 13, 78, 226, + 64, 79, 129, 9, 2, 76, 70, 14, 36, 2, 65, 78, 137, 2, 2, 69, 78, 13, 72, + 12, 32, 87, 73, 84, 72, 32, 66, 85, 78, 78, 89, 32, 29, 2, 83, 32, 2, 11, + 69, 2, 143, 6, 65, 8, 52, 2, 66, 79, 16, 2, 67, 76, 54, 83, 199, 12, 72, + 2, 251, 13, 79, 2, 11, 79, 2, 11, 84, 2, 11, 72, 2, 167, 88, 69, 2, 17, + 2, 65, 78, 2, 131, 10, 68, 2, 11, 83, 2, 11, 32, 2, 11, 83, 2, 11, 89, 2, + 17, 2, 77, 66, 2, 187, 9, 79, 10, 72, 2, 68, 32, 156, 1, 3, 76, 68, 32, + 32, 2, 82, 73, 247, 146, 1, 77, 4, 56, 9, 83, 69, 80, 65, 82, 65, 84, 79, + 82, 231, 85, 74, 2, 17, 2, 32, 77, 2, 21, 3, 73, 68, 68, 2, 11, 76, 2, + 11, 69, 2, 11, 32, 2, 235, 66, 68, 2, 11, 77, 2, 251, 146, 1, 65, 2, 11, + 69, 2, 199, 85, 68, 10, 56, 7, 65, 80, 80, 69, 68, 32, 80, 30, 69, 163, + 1, 73, 2, 241, 78, 3, 82, 69, 83, 6, 48, 2, 65, 84, 80, 3, 83, 84, 76, + 215, 110, 78, 2, 11, 72, 2, 11, 32, 2, 11, 80, 2, 25, 4, 82, 79, 68, 85, + 2, 223, 116, 67, 2, 11, 69, 2, 147, 83, 82, 2, 11, 84, 2, 11, 73, 2, 17, + 2, 78, 71, 2, 17, 2, 32, 72, 2, 11, 65, 2, 243, 73, 78, 34, 76, 2, 32, + 73, 138, 1, 45, 28, 7, 73, 65, 78, 71, 81, 73, 32, 183, 85, 79, 2, 53, + 11, 78, 32, 65, 32, 82, 69, 67, 84, 65, 78, 71, 2, 11, 76, 2, 11, 69, 2, + 11, 32, 2, 11, 66, 2, 11, 79, 2, 191, 142, 1, 88, 2, 11, 82, 2, 215, 124, + 65, 28, 48, 5, 66, 76, 65, 67, 75, 1, 3, 82, 69, 68, 14, 11, 32, 14, 130, + 1, 67, 72, 4, 69, 76, 69, 80, 28, 4, 71, 69, 78, 69, 46, 72, 40, 4, 83, + 79, 76, 68, 193, 11, 6, 77, 65, 78, 68, 65, 82, 4, 24, 2, 65, 78, 19, 72, + 2, 195, 60, 78, 2, 229, 59, 3, 65, 82, 73, 2, 11, 72, 2, 219, 72, 65, 2, + 11, 82, 2, 11, 65, 2, 207, 139, 1, 76, 2, 11, 79, 2, 11, 82, 2, 207, 116, + 83, 2, 167, 77, 73, 248, 19, 54, 65, 206, 2, 69, 226, 11, 73, 217, 35, 2, + 79, 45, 8, 84, 16, 78, 71, 81, 73, 78, 32, 83, 73, 71, 78, 32, 83, 76, + 79, 87, 32, 199, 1, 87, 6, 28, 3, 79, 78, 69, 51, 84, 2, 17, 2, 32, 66, + 2, 11, 69, 2, 131, 109, 65, 4, 60, 9, 72, 82, 69, 69, 32, 72, 65, 76, 70, + 1, 2, 87, 79, 2, 21, 3, 32, 66, 69, 2, 11, 65, 2, 223, 74, 84, 2, 11, 78, + 2, 11, 73, 2, 241, 74, 2, 78, 71, 98, 60, 4, 76, 76, 79, 87, 62, 78, 53, + 5, 90, 73, 68, 73, 32, 2, 17, 2, 32, 72, 2, 11, 69, 2, 11, 65, 2, 227, + 106, 82, 2, 11, 32, 2, 11, 83, 2, 11, 73, 2, 251, 54, 71, 94, 112, 10, + 67, 79, 77, 66, 73, 78, 73, 78, 71, 32, 76, 5, 72, 89, 80, 72, 69, 17, 7, + 76, 69, 84, 84, 69, 82, 32, 4, 44, 3, 77, 65, 68, 13, 4, 72, 65, 77, 90, + 2, 11, 68, 2, 215, 67, 65, 2, 215, 27, 78, 88, 250, 1, 67, 50, 77, 18, + 68, 42, 69, 58, 72, 30, 75, 22, 71, 2, 81, 32, 3, 76, 65, 77, 98, 78, 18, + 80, 30, 83, 66, 84, 28, 2, 86, 65, 126, 87, 14, 79, 18, 88, 52, 3, 89, + 79, 84, 154, 1, 90, 134, 53, 82, 238, 48, 66, 254, 5, 85, 162, 14, 70, 3, + 74, 6, 22, 72, 147, 114, 73, 4, 22, 72, 251, 113, 73, 2, 247, 113, 73, 4, + 11, 65, 4, 178, 130, 1, 68, 3, 76, 8, 42, 76, 142, 50, 89, 226, 79, 84, + 3, 87, 2, 71, 73, 4, 150, 112, 65, 147, 15, 72, 4, 18, 72, 15, 65, 2, 11, + 65, 2, 163, 129, 1, 70, 5, 11, 32, 2, 11, 87, 2, 21, 3, 73, 84, 72, 2, + 17, 2, 32, 68, 2, 11, 79, 2, 187, 3, 84, 2, 207, 48, 85, 4, 202, 105, 72, + 215, 22, 69, 8, 46, 72, 246, 47, 73, 194, 9, 65, 163, 70, 69, 2, 243, 47, + 73, 4, 238, 104, 72, 215, 22, 65, 5, 37, 7, 32, 65, 76, 84, 69, 82, 78, + 2, 17, 2, 65, 84, 2, 11, 69, 2, 11, 32, 2, 11, 70, 2, 11, 79, 2, 227, + 109, 82, 2, 11, 65, 2, 159, 126, 87, 4, 22, 72, 251, 125, 65, 2, 11, 69, + 2, 139, 46, 89, 5, 41, 8, 32, 87, 73, 84, 72, 32, 67, 73, 2, 41, 8, 82, + 67, 85, 77, 70, 76, 69, 88, 2, 11, 32, 2, 11, 65, 2, 11, 66, 2, 11, 79, + 2, 255, 101, 86, 6, 22, 65, 175, 124, 69, 5, 171, 124, 76, 140, 19, 34, + 32, 161, 35, 3, 78, 32, 89, 138, 19, 88, 8, 82, 65, 68, 73, 67, 65, 76, + 32, 181, 7, 9, 83, 89, 76, 76, 65, 66, 76, 69, 32, 110, 170, 1, 66, 42, + 67, 86, 68, 42, 71, 74, 72, 66, 74, 66, 75, 30, 76, 30, 77, 26, 78, 74, + 80, 26, 83, 74, 84, 30, 86, 30, 89, 30, 90, 250, 35, 81, 198, 49, 87, + 235, 30, 79, 4, 22, 66, 247, 64, 85, 2, 163, 93, 85, 12, 42, 85, 18, 89, + 178, 98, 72, 203, 22, 73, 2, 135, 121, 79, 7, 130, 121, 80, 3, 84, 4, 22, + 68, 215, 120, 85, 2, 247, 63, 85, 10, 42, 71, 238, 91, 79, 162, 28, 69, + 15, 65, 4, 162, 89, 85, 235, 30, 79, 8, 22, 88, 243, 88, 77, 6, 238, 88, + 85, 202, 2, 73, 163, 28, 79, 8, 22, 74, 167, 119, 79, 6, 246, 90, 85, + 218, 5, 73, 215, 22, 89, 4, 206, 90, 73, 175, 28, 69, 6, 190, 54, 73, + 199, 7, 89, 4, 182, 118, 79, 15, 73, 8, 30, 89, 26, 90, 199, 90, 66, 4, + 254, 117, 73, 3, 79, 2, 231, 117, 85, 4, 182, 89, 85, 3, 89, 10, 22, 72, + 223, 97, 83, 8, 214, 60, 85, 178, 28, 65, 162, 28, 79, 15, 89, 4, 214, + 88, 65, 175, 28, 85, 4, 138, 60, 85, 211, 56, 69, 4, 158, 88, 73, 175, + 28, 79, 10, 54, 85, 224, 62, 2, 90, 73, 238, 24, 79, 175, 28, 65, 4, 246, + 115, 80, 3, 82, 156, 18, 134, 2, 66, 134, 1, 67, 162, 1, 68, 110, 70, 50, + 71, 150, 1, 72, 138, 3, 73, 134, 1, 74, 98, 75, 54, 76, 62, 77, 134, 1, + 78, 234, 4, 80, 54, 81, 2, 89, 46, 82, 162, 1, 83, 134, 1, 84, 102, 86, + 82, 87, 58, 88, 50, 90, 140, 2, 2, 85, 79, 66, 65, 2, 79, 107, 69, 132, + 1, 66, 66, 238, 21, 85, 150, 1, 69, 26, 73, 42, 65, 2, 79, 67, 89, 64, + 234, 21, 85, 150, 1, 69, 26, 73, 42, 65, 2, 79, 3, 89, 122, 66, 72, 238, + 20, 85, 150, 1, 69, 26, 73, 42, 65, 2, 79, 67, 89, 54, 46, 85, 146, 22, + 65, 2, 69, 2, 79, 67, 89, 19, 142, 22, 79, 106, 82, 230, 88, 80, 3, 88, + 106, 58, 68, 138, 15, 85, 134, 5, 73, 94, 69, 66, 65, 3, 79, 54, 210, 19, + 85, 58, 73, 94, 69, 66, 65, 3, 79, 42, 182, 20, 79, 66, 65, 2, 73, 2, 89, + 67, 85, 116, 58, 71, 214, 15, 85, 146, 4, 73, 42, 65, 2, 69, 3, 79, 56, + 50, 73, 162, 15, 85, 186, 4, 65, 2, 69, 3, 79, 13, 150, 19, 69, 142, 90, + 84, 3, 88, 246, 1, 78, 73, 30, 76, 58, 77, 54, 78, 110, 88, 50, 85, 254, + 15, 69, 66, 65, 3, 79, 6, 198, 19, 69, 231, 88, 84, 64, 238, 16, 85, 58, + 73, 94, 69, 2, 79, 66, 65, 67, 89, 58, 182, 16, 85, 58, 73, 158, 1, 65, + 2, 79, 35, 89, 42, 46, 79, 34, 85, 202, 16, 69, 26, 73, 43, 65, 6, 242, + 106, 80, 2, 84, 3, 88, 6, 238, 17, 79, 231, 88, 84, 46, 46, 85, 254, 15, + 69, 26, 73, 42, 65, 3, 79, 8, 187, 16, 79, 19, 42, 84, 130, 16, 69, 206, + 89, 80, 3, 88, 5, 11, 69, 2, 11, 82, 2, 11, 65, 2, 11, 84, 2, 11, 73, 2, + 11, 79, 2, 191, 39, 78, 106, 50, 74, 190, 10, 85, 146, 4, 73, 42, 79, 67, + 89, 50, 158, 13, 85, 174, 1, 73, 42, 79, 3, 89, 56, 242, 12, 85, 58, 73, + 158, 1, 65, 2, 69, 3, 79, 70, 218, 9, 85, 250, 3, 69, 26, 73, 42, 65, 2, + 79, 67, 89, 106, 70, 71, 218, 8, 85, 158, 3, 73, 158, 1, 65, 2, 79, 2, + 89, 107, 69, 44, 186, 11, 85, 150, 1, 69, 66, 65, 2, 79, 105, 2, 73, 69, + 248, 2, 102, 66, 54, 68, 94, 71, 90, 74, 46, 82, 50, 89, 78, 90, 134, 7, + 85, 58, 73, 94, 65, 2, 69, 67, 79, 54, 202, 10, 73, 158, 1, 65, 2, 79, + 66, 85, 3, 89, 46, 46, 73, 198, 10, 69, 66, 65, 2, 79, 67, 85, 13, 234, + 11, 69, 230, 88, 80, 2, 84, 3, 88, 34, 60, 2, 85, 79, 218, 9, 69, 0, 2, + 73, 69, 66, 65, 3, 79, 7, 226, 99, 84, 3, 88, 50, 230, 1, 85, 242, 7, 73, + 42, 79, 67, 89, 46, 146, 9, 79, 66, 65, 2, 69, 66, 85, 3, 89, 38, 30, 85, + 222, 8, 73, 43, 79, 15, 194, 8, 79, 142, 90, 80, 2, 84, 3, 88, 56, 62, + 85, 206, 4, 79, 178, 2, 73, 158, 1, 65, 66, 89, 43, 69, 15, 254, 8, 79, + 2, 82, 230, 88, 80, 3, 88, 60, 150, 6, 85, 58, 73, 158, 1, 65, 2, 79, 67, + 89, 56, 254, 2, 85, 146, 4, 73, 42, 79, 67, 89, 100, 58, 82, 254, 4, 85, + 150, 1, 69, 66, 65, 2, 79, 67, 89, 48, 46, 85, 162, 6, 69, 2, 79, 66, 89, + 43, 65, 17, 134, 7, 79, 2, 82, 230, 88, 80, 2, 84, 3, 88, 176, 1, 70, 83, + 158, 3, 72, 50, 85, 58, 73, 94, 69, 66, 65, 2, 79, 67, 89, 56, 130, 4, + 73, 94, 69, 66, 65, 2, 79, 2, 85, 67, 89, 56, 46, 85, 158, 3, 73, 94, 69, + 66, 65, 3, 79, 21, 182, 4, 79, 106, 82, 230, 88, 80, 2, 84, 3, 88, 60, + 54, 69, 166, 3, 73, 42, 65, 2, 79, 66, 85, 3, 89, 4, 150, 93, 80, 3, 88, + 28, 38, 85, 206, 2, 69, 2, 79, 67, 65, 9, 203, 2, 79, 40, 210, 2, 73, 42, + 79, 66, 89, 41, 2, 85, 79, 178, 1, 66, 72, 50, 85, 58, 73, 42, 90, 54, + 69, 66, 65, 2, 79, 67, 89, 54, 46, 85, 214, 1, 65, 2, 69, 2, 79, 67, 89, + 19, 146, 1, 79, 170, 1, 82, 230, 88, 80, 2, 84, 3, 88, 15, 90, 69, 142, + 90, 80, 2, 84, 3, 88, 58, 50, 69, 2, 79, 26, 73, 42, 65, 34, 85, 35, 89, + 7, 138, 90, 80, 3, 88, 17, 38, 69, 206, 89, 80, 2, 84, 3, 88, 9, 202, 89, + 80, 2, 84, 3, 88, 11, 70, 82, 230, 88, 80, 3, 88, 13, 38, 82, 230, 88, + 80, 2, 84, 3, 88, 5, 227, 88, 88, 2, 219, 7, 65, 2, 207, 57, 89, 180, 4, + 252, 1, 10, 32, 78, 79, 84, 65, 84, 73, 79, 78, 32, 224, 6, 16, 65, 78, + 65, 66, 65, 90, 65, 82, 32, 83, 81, 85, 65, 82, 69, 32, 210, 15, 69, 180, + 2, 6, 73, 80, 80, 69, 82, 45, 96, 8, 78, 65, 77, 69, 78, 78, 89, 32, 188, + 33, 3, 79, 77, 66, 235, 26, 87, 26, 144, 1, 9, 66, 65, 71, 32, 77, 69, + 77, 66, 69, 42, 82, 104, 6, 68, 79, 77, 65, 73, 78, 60, 3, 76, 69, 70, + 154, 1, 83, 145, 2, 3, 84, 89, 80, 2, 11, 82, 2, 11, 83, 2, 215, 83, 72, + 8, 100, 4, 65, 78, 71, 69, 60, 3, 73, 71, 72, 221, 1, 11, 69, 76, 65, 84, + 73, 79, 78, 65, 76, 32, 67, 2, 173, 3, 11, 32, 65, 78, 84, 73, 82, 69, + 83, 84, 82, 73, 4, 17, 2, 84, 32, 4, 60, 4, 73, 77, 65, 71, 13, 7, 66, + 73, 78, 68, 73, 78, 71, 2, 11, 69, 2, 25, 4, 32, 66, 82, 65, 2, 11, 67, + 2, 175, 29, 75, 8, 44, 6, 67, 72, 69, 77, 65, 32, 211, 1, 80, 6, 18, 67, + 71, 80, 2, 17, 2, 79, 77, 2, 11, 80, 2, 11, 79, 2, 11, 83, 2, 107, 73, 4, + 30, 73, 41, 3, 82, 79, 74, 2, 11, 80, 2, 11, 73, 2, 163, 80, 78, 2, 11, + 69, 2, 11, 67, 2, 11, 84, 2, 87, 73, 2, 139, 52, 79, 2, 11, 69, 2, 11, + 32, 2, 11, 67, 2, 11, 79, 2, 11, 76, 2, 11, 79, 2, 223, 79, 78, 144, 1, + 240, 1, 2, 67, 76, 68, 7, 73, 78, 73, 84, 73, 65, 76, 204, 2, 14, 70, 73, + 78, 65, 76, 32, 67, 79, 78, 83, 79, 78, 65, 78, 16, 7, 76, 69, 84, 84, + 69, 82, 32, 148, 3, 5, 77, 65, 82, 75, 32, 206, 1, 83, 181, 3, 6, 86, 79, + 87, 69, 76, 32, 14, 64, 5, 79, 83, 73, 78, 71, 137, 1, 6, 85, 83, 84, 69, + 82, 45, 4, 11, 32, 4, 64, 12, 68, 79, 85, 66, 76, 69, 45, 76, 73, 78, 69, + 68, 23, 72, 2, 17, 2, 32, 72, 2, 17, 2, 69, 65, 2, 215, 10, 68, 10, 96, + 13, 70, 73, 78, 65, 76, 32, 76, 69, 84, 84, 69, 82, 32, 41, 7, 73, 78, + 73, 84, 73, 65, 76, 8, 238, 72, 76, 2, 82, 2, 86, 3, 89, 2, 37, 7, 32, + 76, 69, 84, 84, 69, 82, 2, 151, 6, 32, 2, 131, 9, 84, 82, 166, 1, 68, 50, + 75, 38, 78, 46, 83, 38, 84, 46, 66, 2, 67, 2, 71, 2, 80, 2, 90, 138, 69, + 45, 2, 72, 2, 74, 2, 76, 2, 77, 2, 82, 2, 86, 2, 89, 187, 2, 65, 12, 206, + 1, 68, 2, 90, 138, 69, 72, 187, 2, 65, 6, 154, 70, 83, 14, 72, 187, 2, + 65, 8, 130, 70, 71, 2, 78, 2, 89, 187, 2, 65, 6, 214, 69, 72, 2, 83, 187, + 2, 65, 12, 42, 83, 2, 84, 138, 69, 72, 187, 2, 65, 4, 134, 69, 72, 187, + 2, 65, 8, 50, 68, 58, 83, 40, 4, 76, 79, 78, 71, 23, 84, 2, 29, 5, 79, + 85, 66, 76, 69, 2, 11, 32, 2, 11, 83, 2, 11, 72, 2, 11, 65, 2, 159, 70, + 68, 2, 17, 2, 32, 84, 2, 17, 2, 83, 72, 2, 147, 69, 69, 14, 36, 4, 73, + 71, 78, 32, 255, 2, 85, 12, 54, 65, 72, 6, 67, 65, 78, 68, 82, 65, 167, + 1, 86, 2, 11, 78, 2, 11, 85, 2, 17, 2, 83, 86, 2, 11, 65, 2, 135, 66, 82, + 6, 36, 5, 66, 73, 78, 68, 85, 15, 32, 5, 11, 32, 2, 25, 4, 87, 73, 84, + 72, 2, 17, 2, 32, 79, 2, 21, 3, 82, 78, 65, 2, 11, 77, 2, 11, 69, 2, 239, + 38, 78, 4, 11, 73, 4, 18, 82, 19, 83, 2, 219, 33, 65, 2, 11, 65, 2, 11, + 82, 2, 139, 64, 71, 2, 151, 4, 66, 20, 38, 76, 109, 5, 83, 73, 71, 78, + 32, 2, 17, 2, 69, 78, 2, 11, 71, 2, 11, 84, 2, 11, 72, 2, 11, 32, 2, 11, + 77, 2, 11, 65, 2, 135, 62, 82, 18, 86, 65, 26, 79, 2, 85, 16, 8, 82, 69, + 86, 69, 82, 83, 69, 68, 146, 64, 69, 3, 73, 4, 182, 64, 73, 3, 85, 5, + 159, 64, 69, 2, 183, 44, 32, 12, 72, 2, 66, 82, 16, 9, 82, 79, 32, 87, + 73, 68, 84, 72, 32, 203, 1, 85, 2, 147, 2, 65, 8, 32, 2, 78, 79, 86, 83, + 31, 74, 4, 26, 45, 73, 2, 78, 45, 2, 29, 5, 66, 82, 69, 65, 75, 2, 11, + 32, 2, 11, 83, 2, 163, 1, 80, 2, 11, 74, 2, 11, 79, 2, 11, 73, 2, 11, 78, + 2, 143, 5, 69, 2, 219, 61, 83, 2, 21, 3, 77, 79, 85, 2, 17, 2, 84, 72, 2, + 11, 32, 2, 11, 70, 2, 11, 65, 2, 167, 38, 67, 242, 2, 168, 1, 10, 67, 79, + 77, 66, 73, 78, 73, 78, 71, 32, 224, 18, 6, 78, 69, 85, 77, 69, 32, 181, + 38, 17, 80, 82, 73, 90, 78, 65, 75, 32, 77, 79, 68, 73, 70, 73, 69, 82, + 32, 128, 1, 144, 2, 17, 76, 79, 87, 69, 82, 32, 84, 79, 78, 65, 76, 32, + 82, 65, 78, 71, 69, 88, 5, 77, 65, 82, 75, 32, 148, 3, 18, 65, 84, 84, + 65, 67, 72, 73, 78, 71, 32, 86, 69, 82, 84, 73, 67, 65, 76, 233, 11, 17, + 84, 79, 78, 65, 76, 32, 82, 65, 78, 71, 69, 32, 77, 65, 82, 75, 32, 2, + 33, 6, 32, 73, 78, 68, 73, 67, 2, 11, 65, 2, 11, 84, 2, 11, 79, 2, 219, + 56, 82, 118, 182, 2, 67, 142, 1, 68, 104, 8, 71, 79, 82, 65, 90, 68, 79, + 32, 34, 78, 106, 75, 114, 79, 72, 2, 80, 79, 152, 2, 8, 77, 65, 76, 79, + 32, 80, 79, 86, 100, 2, 82, 65, 50, 83, 186, 1, 84, 108, 7, 86, 89, 83, + 79, 75, 79, 32, 234, 1, 90, 224, 10, 2, 76, 79, 224, 22, 4, 85, 68, 65, + 82, 129, 6, 4, 66, 79, 82, 90, 6, 60, 6, 72, 65, 83, 72, 75, 65, 29, 5, + 85, 82, 86, 69, 68, 5, 197, 47, 3, 32, 80, 79, 2, 17, 2, 32, 79, 2, 11, + 77, 2, 235, 24, 69, 4, 240, 10, 13, 69, 77, 69, 83, 84, 86, 69, 78, 78, + 89, 32, 90, 65, 217, 14, 6, 86, 79, 69, 84, 79, 67, 10, 30, 78, 89, 3, + 86, 89, 83, 8, 29, 5, 73, 90, 75, 79, 32, 8, 164, 8, 8, 83, 32, 75, 82, + 89, 90, 72, 69, 35, 79, 2, 167, 20, 79, 8, 56, 4, 82, 89, 90, 72, 150, 6, + 65, 233, 39, 2, 85, 80, 5, 21, 3, 32, 79, 78, 2, 11, 32, 2, 203, 7, 76, + 6, 220, 5, 3, 84, 83, 69, 200, 13, 5, 66, 76, 65, 67, 72, 131, 31, 78, + 18, 22, 68, 131, 2, 86, 6, 60, 7, 67, 72, 65, 83, 72, 73, 69, 201, 22, 3, + 86, 69, 82, 5, 17, 2, 32, 87, 2, 21, 3, 73, 84, 72, 2, 17, 2, 32, 86, 2, + 29, 5, 69, 82, 84, 73, 67, 2, 17, 2, 65, 76, 2, 11, 32, 2, 11, 83, 2, 11, + 84, 2, 11, 82, 2, 11, 79, 2, 131, 25, 75, 12, 29, 5, 89, 83, 72, 69, 32, + 12, 22, 83, 251, 3, 79, 8, 154, 3, 32, 229, 2, 4, 84, 82, 65, 78, 4, 28, + 2, 90, 83, 183, 5, 86, 2, 219, 37, 69, 10, 136, 1, 2, 75, 79, 16, 16, 84, + 82, 65, 78, 78, 79, 32, 77, 65, 76, 79, 32, 80, 79, 86, 89, 236, 1, 5, + 82, 69, 68, 78, 69, 231, 26, 79, 2, 239, 42, 66, 2, 11, 83, 2, 183, 22, + 72, 10, 50, 79, 16, 5, 83, 65, 84, 65, 32, 139, 36, 73, 2, 187, 28, 67, + 6, 158, 1, 79, 201, 24, 3, 83, 32, 75, 10, 24, 2, 83, 32, 95, 79, 6, 11, + 75, 6, 44, 6, 72, 79, 75, 72, 76, 79, 247, 24, 82, 4, 11, 77, 4, 17, 2, + 32, 79, 4, 11, 78, 4, 11, 32, 4, 18, 76, 31, 82, 2, 11, 69, 2, 179, 14, + 70, 2, 11, 73, 2, 11, 71, 2, 139, 14, 72, 6, 18, 65, 31, 69, 2, 249, 25, + 3, 68, 69, 82, 4, 22, 86, 239, 10, 76, 2, 199, 38, 79, 6, 60, 5, 77, 82, + 65, 67, 72, 18, 83, 1, 4, 84, 82, 69, 83, 2, 155, 10, 78, 2, 17, 2, 86, + 69, 2, 155, 6, 84, 232, 1, 128, 2, 2, 67, 72, 38, 68, 218, 1, 70, 28, 10, + 71, 79, 76, 85, 66, 67, 72, 73, 75, 32, 158, 1, 75, 160, 2, 6, 77, 69, + 67, 72, 73, 75, 184, 1, 2, 78, 69, 18, 79, 138, 2, 80, 146, 2, 82, 114, + 83, 180, 20, 9, 86, 82, 65, 75, 72, 73, 89, 65, 32, 151, 2, 90, 4, 246, + 11, 69, 209, 10, 2, 65, 83, 10, 74, 69, 98, 85, 16, 9, 86, 65, 32, 86, + 32, 67, 72, 69, 76, 187, 27, 79, 4, 76, 2, 82, 66, 213, 2, 12, 77, 69, + 83, 84, 86, 69, 78, 78, 89, 32, 75, 76, 2, 195, 34, 73, 2, 203, 34, 68, + 2, 11, 78, 2, 231, 36, 85, 2, 11, 73, 2, 147, 34, 84, 10, 78, 84, 38, 83, + 240, 3, 5, 77, 82, 65, 67, 72, 145, 14, 4, 66, 79, 82, 90, 4, 32, 3, 82, + 69, 83, 251, 1, 73, 2, 21, 3, 86, 69, 84, 2, 231, 17, 76, 14, 76, 4, 72, + 65, 77, 73, 18, 76, 40, 3, 79, 66, 89, 16, 2, 82, 89, 87, 85, 2, 219, 3, + 76, 2, 11, 89, 2, 11, 85, 2, 151, 33, 67, 2, 223, 31, 76, 6, 28, 2, 85, + 75, 219, 32, 90, 5, 21, 3, 32, 84, 73, 2, 11, 75, 2, 251, 15, 72, 2, 11, + 70, 2, 11, 73, 2, 11, 83, 2, 215, 30, 77, 11, 11, 32, 8, 44, 7, 75, 76, + 89, 85, 67, 72, 69, 83, 80, 6, 64, 9, 78, 69, 80, 79, 83, 84, 79, 89, 65, + 14, 80, 163, 14, 86, 2, 39, 78, 2, 25, 4, 79, 86, 79, 68, 2, 143, 14, 78, + 2, 223, 22, 77, 14, 40, 2, 66, 76, 41, 4, 83, 79, 75, 65, 2, 11, 65, 2, + 11, 75, 2, 243, 30, 79, 13, 11, 32, 10, 30, 75, 142, 26, 84, 39, 83, 6, + 104, 11, 76, 89, 85, 67, 72, 69, 86, 65, 89, 65, 32, 185, 25, 10, 82, 89, + 85, 75, 79, 86, 65, 89, 65, 32, 4, 202, 16, 78, 251, 8, 83, 14, 58, 65, + 88, 8, 69, 82, 69, 86, 79, 68, 75, 65, 27, 79, 6, 44, 3, 82, 65, 75, 222, + 19, 76, 211, 5, 85, 2, 11, 76, 2, 11, 73, 2, 171, 28, 84, 5, 153, 15, 2, + 32, 78, 4, 68, 5, 68, 67, 72, 65, 83, 245, 9, 7, 76, 75, 85, 76, 73, 90, + 77, 2, 11, 72, 2, 219, 4, 73, 4, 64, 11, 69, 86, 69, 82, 83, 69, 68, 32, + 67, 72, 69, 139, 26, 79, 2, 25, 4, 76, 89, 85, 83, 2, 215, 17, 84, 126, + 96, 9, 75, 65, 77, 69, 89, 84, 83, 65, 32, 148, 2, 8, 76, 79, 90, 72, 73, + 84, 73, 69, 119, 84, 22, 128, 1, 13, 68, 86, 79, 69, 67, 72, 69, 76, 78, + 65, 89, 65, 32, 44, 7, 75, 76, 89, 85, 67, 72, 69, 74, 84, 218, 18, 77, + 119, 83, 8, 218, 10, 75, 110, 78, 178, 8, 80, 75, 83, 6, 40, 5, 86, 65, + 89, 65, 32, 243, 10, 78, 4, 178, 15, 84, 183, 4, 83, 4, 162, 15, 73, 147, + 4, 82, 9, 11, 32, 6, 48, 2, 83, 32, 25, 6, 90, 65, 75, 82, 89, 84, 4, + 166, 4, 75, 95, 90, 2, 11, 79, 2, 211, 22, 69, 96, 92, 4, 65, 84, 89, 65, + 172, 4, 6, 79, 80, 73, 84, 83, 65, 189, 1, 5, 82, 69, 76, 65, 32, 23, 11, + 32, 20, 76, 2, 83, 32, 236, 2, 9, 90, 65, 75, 82, 89, 84, 65, 89, 65, + 159, 5, 78, 14, 160, 1, 14, 68, 86, 85, 77, 89, 65, 32, 90, 65, 80, 89, + 65, 84, 89, 28, 7, 75, 82, 89, 90, 72, 69, 77, 24, 2, 82, 79, 17, 8, 90, + 65, 80, 89, 65, 84, 79, 89, 2, 11, 77, 2, 215, 19, 73, 5, 189, 1, 2, 32, + 73, 2, 203, 2, 71, 7, 21, 3, 32, 73, 32, 4, 54, 75, 37, 9, 80, 79, 68, + 67, 72, 65, 83, 72, 73, 2, 11, 82, 2, 21, 3, 89, 90, 72, 2, 211, 1, 69, + 5, 17, 2, 32, 83, 2, 17, 2, 32, 90, 2, 29, 5, 65, 80, 89, 65, 84, 2, 11, + 79, 2, 199, 17, 89, 7, 11, 32, 4, 68, 6, 83, 32, 79, 67, 72, 75, 29, 7, + 87, 73, 84, 72, 32, 83, 79, 2, 11, 79, 2, 215, 16, 77, 2, 45, 9, 82, 79, + 67, 72, 89, 65, 32, 78, 79, 2, 11, 90, 2, 163, 7, 72, 68, 140, 1, 9, 68, + 86, 79, 69, 67, 72, 69, 76, 78, 162, 1, 75, 78, 78, 174, 1, 71, 152, 3, + 8, 77, 82, 65, 67, 72, 78, 79, 84, 42, 80, 75, 84, 10, 18, 79, 71, 65, 6, + 64, 7, 80, 79, 86, 79, 68, 78, 65, 189, 5, 4, 75, 82, 89, 90, 4, 17, 2, + 89, 65, 5, 17, 2, 32, 75, 2, 145, 5, 4, 76, 89, 85, 67, 26, 48, 6, 76, + 89, 85, 67, 72, 69, 77, 2, 82, 89, 4, 22, 78, 203, 6, 80, 2, 157, 8, 9, + 69, 80, 79, 83, 84, 79, 89, 65, 78, 22, 48, 7, 85, 75, 79, 86, 65, 89, + 65, 195, 3, 90, 21, 11, 32, 18, 54, 71, 236, 2, 5, 84, 82, 89, 65, 83, + 179, 2, 80, 14, 21, 3, 82, 79, 77, 14, 32, 4, 78, 65, 89, 65, 47, 79, 5, + 237, 1, 7, 32, 87, 73, 84, 72, 32, 83, 10, 92, 10, 75, 82, 89, 90, 72, + 69, 86, 65, 89, 65, 17, 9, 80, 79, 86, 79, 68, 78, 65, 89, 65, 5, 175, 2, + 32, 7, 33, 6, 32, 87, 73, 84, 72, 32, 4, 24, 2, 68, 79, 23, 83, 2, 41, 2, + 85, 66, 2, 21, 3, 73, 78, 71, 2, 133, 6, 6, 76, 69, 32, 90, 65, 80, 2, + 175, 6, 75, 2, 237, 5, 3, 72, 69, 86, 2, 11, 73, 2, 11, 75, 2, 187, 5, + 72, 6, 22, 79, 187, 3, 82, 4, 28, 2, 76, 85, 187, 1, 86, 2, 163, 1, 80, + 8, 80, 5, 82, 89, 65, 83, 79, 153, 2, 10, 73, 75, 72, 65, 89, 65, 32, 80, + 85, 84, 6, 62, 80, 44, 4, 83, 84, 82, 69, 173, 1, 4, 71, 76, 65, 83, 2, + 17, 2, 79, 86, 2, 193, 1, 2, 79, 68, 2, 171, 1, 76, 16, 88, 12, 75, 76, + 89, 85, 67, 72, 69, 86, 65, 89, 65, 32, 38, 77, 46, 80, 38, 84, 39, 83, + 8, 34, 77, 46, 80, 38, 84, 39, 83, 2, 25, 4, 82, 65, 67, 72, 2, 247, 1, + 78, 2, 11, 82, 2, 205, 1, 2, 79, 83, 2, 11, 82, 2, 11, 69, 2, 11, 83, 2, + 157, 1, 4, 86, 69, 84, 76, 6, 30, 65, 121, 3, 77, 69, 89, 4, 32, 4, 78, + 79, 90, 72, 31, 80, 2, 11, 69, 2, 151, 3, 75, 2, 17, 2, 89, 65, 2, 11, + 84, 2, 11, 65, 2, 35, 89, 2, 11, 84, 2, 11, 83, 2, 183, 2, 65, 10, 108, + 11, 68, 73, 82, 69, 67, 84, 73, 79, 78, 32, 70, 28, 3, 75, 82, 89, 28, 5, + 76, 69, 86, 69, 76, 35, 82, 2, 11, 76, 2, 159, 1, 73, 2, 11, 90, 2, 143, + 1, 72, 4, 11, 45, 4, 114, 50, 3, 51, 2, 11, 79, 2, 83, 71, 8, 26, 78, 34, + 83, 15, 74, 4, 18, 66, 27, 74, 2, 11, 83, 2, 11, 80, 3, 0, }; static const unsigned int dawg_pos_to_codepoint[] = { @@ -9248,809 +9353,821 @@ static const unsigned int dawg_pos_to_codepoint[] = { 71425, 71424, 71431, 71430, 71441, 71433, 71437, 71439, 71484, 71485, 71467, 71486, 71487, 71456, 71457, 71465, 71466, 71463, 71460, 71461, 71458, 71459, 71462, 71464, 71483, 71482, 71477, 71476, 71479, 71478, - 71475, 71474, 71472, 71481, 71473, 71480, 9992, 128747, 128748, 128874, - 128822, 128823, 128837, 128776, 128777, 128774, 128775, 128773, 128811, - 128859, 128826, 128829, 128855, 128769, 128875, 128876, 128830, 128834, - 128835, 128836, 128783, 128857, 128848, 128846, 128844, 128805, 128800, - 128803, 128804, 128798, 128869, 128870, 128871, 128872, 128873, 128787, - 128865, 128866, 128864, 128880, 128794, 128841, 128883, 128882, 128854, - 128878, 128796, 128797, 128801, 128810, 128851, 128784, 128785, 128786, - 128824, 128881, 128789, 128879, 128782, 128843, 128858, 128856, 128868, - 128867, 128863, 128768, 128833, 128818, 128816, 128817, 128799, 128819, - 128820, 128821, 128827, 128828, 128877, 128792, 128793, 128788, 128806, - 128813, 128825, 128850, 128860, 128861, 128814, 128807, 128812, 128802, - 128862, 128781, 128839, 128795, 128852, 128847, 128831, 128832, 128840, - 128809, 128849, 128845, 128778, 128815, 128779, 128780, 128790, 128791, - 128808, 128772, 128842, 128853, 128771, 128838, 128770, 9879, 8501, - 983054, 128126, 117837, 117836, 117844, 117845, 117842, 117843, 117839, - 117838, 117841, 117840, 8780, 9006, 983203, 8776, 10863, 8778, 9095, - 9941, 9200, 38, 127994, 127944, 128657, 10815, 82970, 82971, 82964, - 82965, 82966, 82967, 82968, 82969, 82972, 82973, 82974, 82994, 82995, - 82996, 82987, 82988, 82992, 82993, 82986, 82989, 82990, 82991, 82997, - 82998, 82999, 83016, 83017, 83018, 83019, 83010, 83011, 83012, 83013, - 83014, 83015, 83020, 83021, 83022, 83050, 83051, 83052, 83053, 83043, - 83044, 83045, 83046, 83047, 83048, 83049, 83054, 82984, 82985, 82975, - 82976, 82977, 82978, 82979, 82980, 82981, 82982, 82983, 82953, 82954, - 82955, 82956, 82957, 82958, 82959, 82960, 82961, 82962, 82963, 82944, - 82945, 82946, 82947, 82948, 82949, 82950, 82951, 82952, 83000, 83001, - 83002, 83003, 83004, 83005, 83006, 83007, 83008, 83009, 83023, 83024, - 83025, 83026, 83027, 83028, 83029, 83030, 83031, 83032, 83033, 83034, - 83035, 83036, 83037, 83038, 83039, 83040, 83041, 83042, 83062, 83063, - 83064, 83065, 83070, 83071, 83072, 83073, 83066, 83067, 83068, 83055, - 83056, 83057, 83058, 83059, 83060, 83061, 83069, 83074, 83075, 83076, - 83077, 83078, 83083, 83084, 83079, 83080, 83081, 83082, 83085, 83086, - 83087, 83088, 83094, 83095, 83089, 83090, 83091, 83092, 83093, 83096, - 83097, 83098, 83099, 83105, 83106, 83100, 83101, 83102, 83103, 83104, - 83107, 83108, 83109, 83110, 83111, 83112, 83113, 83114, 83115, 83116, - 83117, 83118, 83119, 83120, 83121, 83122, 83123, 83124, 83125, 83126, - 83127, 83128, 83129, 83130, 83131, 83132, 83133, 83134, 83135, 83136, - 83137, 83138, 83139, 83140, 83141, 83142, 83143, 83144, 83145, 83146, - 83147, 83148, 83149, 83150, 83151, 83152, 83153, 83154, 83155, 83156, - 83157, 83158, 83159, 83160, 83161, 83162, 83163, 83164, 83165, 83166, - 83167, 83168, 83169, 83170, 83173, 83174, 83175, 83180, 83181, 83183, - 83184, 83171, 83172, 83176, 83177, 83178, 83179, 83182, 83190, 83191, - 83192, 83193, 83185, 83186, 83187, 83188, 83189, 83194, 83195, 83196, - 83274, 83275, 83280, 83281, 83270, 83271, 83272, 83273, 83276, 83277, - 83278, 83279, 83268, 83269, 83259, 83260, 83261, 83262, 83263, 83264, - 83265, 83266, 83267, 83204, 83205, 83197, 83198, 83199, 83200, 83201, - 83202, 83203, 83206, 83207, 83245, 83246, 83238, 83239, 83240, 83241, - 83242, 83243, 83244, 83247, 83248, 83208, 83209, 83210, 83211, 83212, - 83213, 83214, 83215, 83216, 83217, 83218, 83219, 83220, 83221, 83222, - 83223, 83224, 83225, 83226, 83227, 83228, 83229, 83230, 83231, 83232, - 83233, 83234, 83235, 83236, 83237, 83249, 83250, 83251, 83252, 83253, - 83254, 83255, 83256, 83257, 83258, 83291, 83292, 83282, 83283, 83284, - 83285, 83286, 83287, 83288, 83289, 83290, 83312, 83313, 83303, 83304, - 83305, 83306, 83307, 83308, 83309, 83310, 83311, 83348, 83349, 83339, - 83340, 83341, 83342, 83343, 83344, 83345, 83346, 83347, 83322, 83323, - 83324, 83325, 83316, 83317, 83318, 83314, 83315, 83319, 83320, 83321, - 83326, 83327, 83328, 83354, 83355, 83359, 83360, 83350, 83351, 83352, - 83353, 83356, 83357, 83358, 83361, 83377, 83378, 83374, 83375, 83381, - 83382, 83373, 83376, 83379, 83380, 83383, 83384, 83385, 83389, 83386, - 83387, 83388, 83390, 83391, 83392, 83393, 83394, 83395, 83363, 83364, - 83362, 83365, 83366, 83367, 83368, 83369, 83370, 83371, 83372, 83293, - 83294, 83295, 83296, 83297, 83298, 83299, 83300, 83301, 83302, 83329, - 83330, 83331, 83332, 83333, 83334, 83335, 83336, 83337, 83338, 83406, - 83407, 83408, 83409, 83410, 83411, 83412, 83413, 83414, 83415, 83416, - 83447, 83448, 83455, 83456, 83449, 83450, 83451, 83452, 83453, 83454, - 83457, 83458, 83489, 83490, 83491, 83492, 83493, 83494, 83495, 83496, - 83396, 83397, 83398, 83399, 83400, 83401, 83402, 83403, 83404, 83405, - 83417, 83418, 83419, 83420, 83421, 83422, 83423, 83424, 83425, 83426, - 83427, 83428, 83429, 83430, 83431, 83432, 83433, 83434, 83435, 83436, - 83437, 83438, 83439, 83440, 83441, 83442, 83443, 83444, 83445, 83446, - 83459, 83460, 83461, 83462, 83463, 83464, 83465, 83466, 83467, 83468, - 83469, 83470, 83471, 83472, 83473, 83474, 83475, 83476, 83477, 83478, - 83479, 83480, 83481, 83482, 83483, 83484, 83485, 83486, 83487, 83488, - 83526, 83497, 83498, 83499, 83500, 83501, 83502, 83503, 83504, 83505, - 83506, 83507, 83508, 83509, 83510, 83511, 83512, 83513, 83514, 83515, - 83516, 83517, 83518, 83519, 83520, 83521, 83522, 83523, 83524, 83525, - 129728, 8736, 10654, 10660, 128551, 8491, 128162, 128544, 128028, 117768, - 128246, 11150, 11148, 11149, 11151, 11119, 8630, 10560, 8755, 128260, - 10226, 8634, 10769, 9875, 10193, 9765, 9021, 9055, 9061, 9033, 9052, - 9022, 9066, 9058, 9067, 9042, 9049, 9035, 9034, 9038, 9062, 9073, 9046, - 9050, 9075, 9080, 9014, 9082, 9078, 9077, 9081, 9060, 9051, 9063, 9029, - 9109, 9020, 9056, 9017, 9018, 9036, 9047, 9044, 9037, 9043, 9040, 9027, - 9031, 9072, 9071, 9016, 9026, 9025, 9028, 9032, 9019, 9054, 9048, 9030, - 9076, 9070, 9023, 9059, 9069, 9015, 9079, 9024, 9074, 9057, 9041, 9045, - 9053, 9039, 9065, 9064, 9068, 39, 11236, 8773, 8786, 10864, 8774, 8784, - 983195, 983196, 69372, 1548, 2277, 2280, 2276, 2279, 2278, 2281, 1615, - 65144, 65145, 2302, 1612, 65138, 1549, 2206, 2299, 2300, 1643, 2274, - 1771, 1770, 1565, 1757, 1614, 1630, 2293, 2292, 65142, 65143, 1611, - 65136, 1538, 1645, 1748, 2207, 1621, 1620, 1616, 2294, 65146, 65147, - 1613, 65140, 2258, 2255, 2254, 2257, 2236, 2244, 2235, 2237, 1593, 1886, - 2227, 1696, 1887, 1885, 65226, 65227, 65225, 65228, 1575, 2165, 2176, - 2173, 2161, 2174, 2171, 2167, 2177, 2169, 2166, 2168, 2178, 2164, 2160, - 2162, 2175, 2172, 1571, 65156, 65155, 1573, 65160, 65159, 1651, 1650, - 1908, 1907, 1570, 65154, 65153, 2163, 2170, 1649, 64337, 64336, 1609, - 65264, 65263, 65166, 65165, 1749, 1576, 2230, 1878, 2208, 1874, 1875, - 1872, 1876, 1877, 1873, 2209, 65168, 65169, 65167, 65170, 1664, 64347, - 64348, 64346, 64349, 1659, 64339, 64340, 64338, 64341, 1583, 1882, 1774, - 1679, 2222, 69314, 1881, 1674, 1675, 1680, 1673, 65194, 65193, 1676, - 64389, 64388, 1590, 1787, 65214, 65215, 65213, 65216, 1677, 64387, 64386, - 1672, 64393, 64392, 1646, 1697, 1647, 1668, 64371, 64372, 64370, 64373, - 1678, 64391, 64390, 1740, 1911, 1910, 1909, 1599, 1598, 1597, 64509, - 64510, 64508, 64511, 1601, 1699, 2212, 1698, 1889, 1701, 1888, 65234, - 65235, 65233, 65236, 1711, 1716, 1714, 1712, 2224, 64403, 64404, 64402, - 64405, 1594, 2243, 1788, 65230, 65231, 65229, 65232, 1715, 64407, 64408, - 64406, 64409, 2248, 1581, 1916, 2186, 1903, 1906, 1902, 1880, 1669, 1666, - 1879, 1665, 65186, 65187, 65185, 65188, 1569, 65152, 1607, 1729, 1730, - 64423, 64424, 64422, 64425, 1791, 1728, 64421, 64420, 1726, 64427, 64428, - 64426, 64429, 65258, 65259, 65257, 65260, 1652, 1653, 1656, 1654, 1580, - 2210, 2246, 2245, 65182, 65183, 65181, 65184, 1688, 64395, 64394, 1603, - 69316, 1919, 1710, 2228, 1708, 1707, 65242, 65243, 65241, 65244, 1568, - 1705, 1892, 1596, 1891, 2189, 1595, 2242, 1890, 64399, 64400, 64398, - 64401, 1733, 64481, 64480, 1737, 64483, 64482, 1582, 65190, 65191, 65189, - 65192, 1604, 2214, 1718, 2247, 1717, 1720, 1719, 1898, 65246, 65247, - 65245, 65248, 2221, 1605, 2215, 1894, 1893, 65250, 65251, 65249, 65252, - 1564, 1709, 1713, 64411, 64412, 64410, 64413, 64468, 64469, 64467, 64470, - 1667, 64375, 64376, 64374, 64377, 1606, 1722, 64415, 64414, 1896, 1897, - 1725, 1895, 2185, 1721, 1724, 65254, 65255, 65253, 65256, 1662, 2231, - 2238, 64343, 64344, 64342, 64345, 1702, 64367, 64368, 64366, 64369, 1602, - 2213, 2229, 1703, 1704, 65238, 65239, 65237, 65240, 1585, 1905, 2233, - 1682, 1685, 1883, 1899, 1687, 1775, 1900, 1689, 1684, 1686, 2218, 1683, - 65198, 65197, 1681, 64397, 64396, 1723, 64417, 64418, 64416, 64419, 2220, - 1589, 2223, 1694, 1693, 65210, 65211, 65209, 65212, 1587, 1690, 1918, - 1904, 1691, 1692, 1901, 1884, 1917, 65202, 65203, 65201, 65204, 1588, - 1786, 65206, 65207, 65205, 65208, 1648, 2225, 1706, 1591, 69315, 2211, - 2188, 1695, 2187, 65218, 65219, 65217, 65220, 1670, 2241, 1727, 64379, - 64380, 64378, 64381, 1671, 64383, 64384, 64382, 64385, 1578, 1577, 65172, - 65171, 1731, 65176, 2232, 2239, 1661, 1660, 65174, 65175, 65173, 1663, - 64355, 64356, 64354, 64357, 1584, 65196, 65195, 1579, 65178, 65179, - 65177, 65180, 2182, 1657, 2240, 64359, 64360, 64358, 64361, 1658, 64351, - 64352, 64350, 64353, 1735, 1655, 64477, 64472, 64471, 64488, 64489, 1739, - 1700, 64363, 64364, 64362, 64365, 64479, 64478, 1608, 2219, 1743, 1913, - 1912, 1572, 65158, 65157, 1738, 1732, 65262, 65261, 1610, 1746, 1915, - 1914, 1747, 64433, 64432, 64431, 64430, 1574, 65162, 65163, 65161, 65164, - 1742, 2216, 2234, 2217, 1741, 1745, 65266, 65267, 65265, 65268, 1736, - 64476, 64475, 1734, 64474, 64473, 1592, 65222, 65223, 65221, 65224, 1586, - 65200, 65199, 2226, 1744, 64485, 64486, 64484, 64487, 2297, 2295, 64888, - 64887, 64886, 64950, 64699, 64554, 64964, 64885, 64698, 64553, 64787, - 64759, 64788, 64760, 64842, 64839, 64841, 64840, 64845, 65015, 64656, - 64605, 64828, 64829, 65010, 65011, 65023, 64962, 64669, 64518, 64672, - 64738, 64926, 64670, 64519, 64622, 64521, 64668, 64517, 64620, 64671, - 64520, 64737, 64621, 64619, 64618, 64623, 64522, 65021, 64878, 64939, - 64693, 64547, 64880, 64879, 64694, 64548, 64803, 64775, 64692, 64546, - 64695, 64549, 64812, 64784, 64804, 64776, 64893, 64892, 64704, 64559, - 64636, 64561, 64702, 64557, 64961, 64705, 64560, 64703, 64558, 64637, - 64562, 64889, 64891, 64890, 64701, 64556, 64789, 64761, 64700, 64555, - 64790, 64762, 64859, 64858, 64682, 64536, 64795, 64767, 64959, 64681, + 71475, 71474, 71472, 71481, 71473, 71480, 9992, 128747, 128748, 130042, + 9200, 128874, 128822, 128823, 128837, 128776, 128777, 128774, 128775, + 128773, 128811, 128859, 128826, 128829, 128855, 128769, 128875, 128876, + 128830, 128834, 128835, 128836, 128783, 128857, 128848, 128846, 128844, + 128805, 128800, 128803, 128804, 128798, 128869, 128870, 128871, 128872, + 128873, 128787, 128865, 128866, 128864, 128880, 128794, 128841, 128883, + 128882, 128854, 128878, 128796, 128797, 128801, 128810, 128851, 128784, + 128785, 128786, 128824, 128881, 128789, 128879, 128782, 128843, 128858, + 128856, 128868, 128867, 128863, 128768, 128833, 128818, 128816, 128817, + 128799, 128819, 128820, 128821, 128827, 128828, 128877, 128792, 128793, + 128788, 128806, 128813, 128825, 128850, 128860, 128861, 128814, 128807, + 128812, 128802, 128862, 128781, 128839, 128795, 128852, 128847, 128831, + 128832, 128840, 128809, 128849, 128845, 128778, 128815, 128779, 128780, + 128790, 128791, 128808, 128772, 128842, 128853, 128771, 128770, 128838, + 9879, 8501, 983054, 128126, 117837, 117836, 117844, 117845, 117842, + 117843, 117839, 117838, 117841, 117840, 8780, 9006, 983203, 8776, 10863, + 8778, 9095, 9941, 118479, 127994, 38, 127944, 128657, 10815, 82970, + 82971, 82964, 82965, 82966, 82967, 82968, 82969, 82972, 82973, 82974, + 82994, 82995, 82996, 82987, 82988, 82992, 82993, 82986, 82989, 82990, + 82991, 82997, 82998, 82999, 83016, 83017, 83018, 83019, 83010, 83011, + 83012, 83013, 83014, 83015, 83020, 83021, 83022, 83050, 83051, 83052, + 83053, 83043, 83044, 83045, 83046, 83047, 83048, 83049, 83054, 82984, + 82985, 82975, 82976, 82977, 82978, 82979, 82980, 82981, 82982, 82983, + 82953, 82954, 82955, 82956, 82957, 82958, 82959, 82960, 82961, 82962, + 82963, 82944, 82945, 82946, 82947, 82948, 82949, 82950, 82951, 82952, + 83000, 83001, 83002, 83003, 83004, 83005, 83006, 83007, 83008, 83009, + 83023, 83024, 83025, 83026, 83027, 83028, 83029, 83030, 83031, 83032, + 83033, 83034, 83035, 83036, 83037, 83038, 83039, 83040, 83041, 83042, + 83062, 83063, 83064, 83065, 83070, 83071, 83072, 83073, 83066, 83067, + 83068, 83055, 83056, 83057, 83058, 83059, 83060, 83061, 83069, 83074, + 83075, 83076, 83077, 83078, 83083, 83084, 83079, 83080, 83081, 83082, + 83085, 83086, 83087, 83088, 83094, 83095, 83089, 83090, 83091, 83092, + 83093, 83096, 83097, 83098, 83099, 83105, 83106, 83100, 83101, 83102, + 83103, 83104, 83107, 83108, 83109, 83110, 83111, 83112, 83113, 83114, + 83115, 83116, 83117, 83118, 83119, 83120, 83121, 83122, 83123, 83124, + 83125, 83126, 83127, 83128, 83129, 83130, 83131, 83132, 83133, 83134, + 83135, 83136, 83137, 83138, 83139, 83140, 83141, 83142, 83143, 83144, + 83145, 83146, 83147, 83148, 83149, 83150, 83151, 83152, 83153, 83154, + 83155, 83156, 83157, 83158, 83159, 83160, 83161, 83162, 83163, 83164, + 83165, 83166, 83167, 83168, 83169, 83170, 83173, 83174, 83175, 83180, + 83181, 83183, 83184, 83171, 83172, 83176, 83177, 83178, 83179, 83182, + 83190, 83191, 83192, 83193, 83185, 83186, 83187, 83188, 83189, 83194, + 83195, 83196, 83274, 83275, 83280, 83281, 83270, 83271, 83272, 83273, + 83276, 83277, 83278, 83279, 83268, 83269, 83259, 83260, 83261, 83262, + 83263, 83264, 83265, 83266, 83267, 83204, 83205, 83197, 83198, 83199, + 83200, 83201, 83202, 83203, 83206, 83207, 83245, 83246, 83238, 83239, + 83240, 83241, 83242, 83243, 83244, 83247, 83248, 83208, 83209, 83210, + 83211, 83212, 83213, 83214, 83215, 83216, 83217, 83218, 83219, 83220, + 83221, 83222, 83223, 83224, 83225, 83226, 83227, 83228, 83229, 83230, + 83231, 83232, 83233, 83234, 83235, 83236, 83237, 83249, 83250, 83251, + 83252, 83253, 83254, 83255, 83256, 83257, 83258, 83291, 83292, 83282, + 83283, 83284, 83285, 83286, 83287, 83288, 83289, 83290, 83312, 83313, + 83303, 83304, 83305, 83306, 83307, 83308, 83309, 83310, 83311, 83348, + 83349, 83339, 83340, 83341, 83342, 83343, 83344, 83345, 83346, 83347, + 83322, 83323, 83324, 83325, 83316, 83317, 83318, 83314, 83315, 83319, + 83320, 83321, 83326, 83327, 83328, 83354, 83355, 83359, 83360, 83350, + 83351, 83352, 83353, 83356, 83357, 83358, 83361, 83377, 83378, 83374, + 83375, 83381, 83382, 83373, 83376, 83379, 83380, 83383, 83384, 83385, + 83389, 83386, 83387, 83388, 83390, 83391, 83392, 83393, 83394, 83395, + 83363, 83364, 83362, 83365, 83366, 83367, 83368, 83369, 83370, 83371, + 83372, 83293, 83294, 83295, 83296, 83297, 83298, 83299, 83300, 83301, + 83302, 83329, 83330, 83331, 83332, 83333, 83334, 83335, 83336, 83337, + 83338, 83406, 83407, 83408, 83409, 83410, 83411, 83412, 83413, 83414, + 83415, 83416, 83447, 83448, 83455, 83456, 83449, 83450, 83451, 83452, + 83453, 83454, 83457, 83458, 83489, 83490, 83491, 83492, 83493, 83494, + 83495, 83496, 83396, 83397, 83398, 83399, 83400, 83401, 83402, 83403, + 83404, 83405, 83417, 83418, 83419, 83420, 83421, 83422, 83423, 83424, + 83425, 83426, 83427, 83428, 83429, 83430, 83431, 83432, 83433, 83434, + 83435, 83436, 83437, 83438, 83439, 83440, 83441, 83442, 83443, 83444, + 83445, 83446, 83459, 83460, 83461, 83462, 83463, 83464, 83465, 83466, + 83467, 83468, 83469, 83470, 83471, 83472, 83473, 83474, 83475, 83476, + 83477, 83478, 83479, 83480, 83481, 83482, 83483, 83484, 83485, 83486, + 83487, 83488, 83526, 83497, 83498, 83499, 83500, 83501, 83502, 83503, + 83504, 83505, 83506, 83507, 83508, 83509, 83510, 83511, 83512, 83513, + 83514, 83515, 83516, 83517, 83518, 83519, 83520, 83521, 83522, 83523, + 83524, 83525, 129728, 8736, 10654, 10660, 128551, 8491, 128162, 128544, + 128028, 117768, 128246, 11150, 11148, 11149, 11151, 11119, 8630, 10560, + 8755, 128260, 10226, 8634, 10769, 9875, 10193, 9765, 9021, 9055, 9061, + 9033, 9052, 9022, 9066, 9058, 9067, 9042, 9049, 9035, 9034, 9038, 9062, + 9073, 9046, 9050, 9075, 9080, 9014, 9082, 9078, 9077, 9081, 9060, 9051, + 9063, 9029, 9109, 9020, 9056, 9017, 9018, 9036, 9047, 9044, 9037, 9043, + 9040, 9027, 9031, 9072, 9071, 9016, 9026, 9025, 9028, 9032, 9019, 9054, + 9048, 9030, 9076, 9070, 9023, 9059, 9069, 9015, 9079, 9024, 9074, 9057, + 9041, 9045, 9053, 9039, 9065, 9064, 9068, 39, 11236, 983195, 118461, + 8773, 8786, 10864, 8774, 8784, 983196, 2183, 69328, 69372, 1548, 2277, + 2280, 2276, 2279, 2278, 2281, 1615, 65144, 65145, 2302, 1612, 65138, + 1549, 2299, 2300, 69370, 2206, 1643, 2274, 1771, 1770, 1565, 1757, 1614, + 1630, 2293, 2292, 65142, 65143, 1611, 65136, 1538, 1645, 1748, 2207, + 1621, 1620, 1616, 2294, 65146, 65147, 1613, 65140, 2258, 2255, 2254, + 2257, 2236, 2244, 2235, 2237, 1593, 1886, 2227, 1696, 1887, 1885, 65226, + 65227, 65225, 65228, 1575, 2165, 2176, 2173, 2161, 2174, 2171, 2167, + 2177, 2169, 2166, 2168, 2178, 2164, 2160, 2162, 2175, 2172, 1571, 65156, + 65155, 1573, 65160, 65159, 1651, 1650, 1908, 1907, 1570, 65154, 65153, + 2163, 2170, 1649, 64337, 64336, 1609, 65264, 65263, 65166, 65165, 1749, + 1576, 2230, 1878, 2208, 1874, 1875, 1872, 1876, 1877, 1873, 2209, 65168, + 65169, 65167, 65170, 1664, 64347, 64348, 64346, 64349, 1659, 64339, + 64340, 64338, 64341, 1583, 1882, 1774, 1679, 2222, 69314, 1881, 1674, + 1675, 1680, 1673, 65194, 65193, 1676, 64389, 64388, 1590, 1787, 65214, + 65215, 65213, 65216, 1677, 64387, 64386, 1672, 64393, 64392, 1646, 1697, + 1647, 1668, 64371, 64372, 64370, 64373, 1678, 64391, 64390, 1740, 1911, + 1910, 1909, 1599, 1598, 1597, 64509, 64510, 64508, 64511, 1601, 1699, + 2212, 1698, 1889, 1701, 1888, 65234, 65235, 65233, 65236, 1711, 1716, + 1714, 1712, 2224, 64403, 64404, 64402, 64405, 1594, 2243, 1788, 65230, + 65231, 65229, 65232, 1715, 64407, 64408, 64406, 64409, 2248, 1581, 1916, + 2186, 1903, 1906, 1902, 1880, 1669, 1666, 1879, 1665, 65186, 65187, + 65185, 65188, 1569, 65152, 1607, 1729, 1730, 64423, 64424, 64422, 64425, + 1791, 1728, 64421, 64420, 1726, 64427, 64428, 64426, 64429, 65258, 65259, + 65257, 65260, 1652, 1653, 1656, 1654, 1580, 2210, 2246, 2245, 65182, + 65183, 65181, 65184, 1688, 64395, 64394, 1603, 69316, 1919, 1710, 2228, + 1708, 1707, 65242, 65243, 65241, 65244, 1568, 1705, 1892, 1596, 1891, + 2189, 1595, 2242, 1890, 64399, 64400, 64398, 64401, 1733, 64481, 64480, + 1737, 64483, 64482, 1582, 65190, 65191, 65189, 65192, 1604, 2214, 1718, + 2247, 1717, 1720, 1719, 1898, 65246, 65247, 65245, 65248, 2221, 1605, + 2215, 1894, 1893, 65250, 65251, 65249, 65252, 1564, 1709, 1713, 64411, + 64412, 64410, 64413, 64468, 64469, 64467, 64470, 1667, 64375, 64376, + 64374, 64377, 1606, 1722, 64415, 64414, 1896, 1897, 1725, 1895, 2185, + 1724, 2191, 1721, 65254, 65255, 65253, 65256, 1662, 2231, 2238, 64343, + 64344, 64342, 64345, 1702, 64367, 64368, 64366, 64369, 1602, 2213, 2229, + 1703, 1704, 65238, 65239, 65237, 65240, 1585, 1905, 2233, 1682, 1685, + 1883, 1899, 1687, 1775, 1900, 1689, 1684, 1686, 2218, 1683, 65198, 65197, + 1681, 64397, 64396, 1723, 64417, 64418, 64416, 64419, 2220, 1589, 2223, + 1694, 1693, 65210, 65211, 65209, 65212, 1587, 1690, 1918, 1904, 1691, + 1692, 1901, 1884, 1917, 65202, 65203, 65201, 65204, 1588, 1786, 65206, + 65207, 65205, 65208, 1648, 2225, 1706, 1591, 69315, 2211, 2188, 1695, + 2187, 65218, 65219, 65217, 65220, 1670, 2241, 1727, 64379, 64380, 64378, + 64381, 1671, 64383, 64384, 64382, 64385, 1578, 1577, 65172, 65171, 1731, + 65176, 2232, 2239, 1661, 1660, 65174, 65175, 65173, 1663, 64355, 64356, + 64354, 64357, 1584, 65196, 65195, 2182, 69318, 1579, 65178, 65179, 65177, + 65180, 1657, 2240, 64359, 64360, 64358, 64361, 1658, 64351, 64352, 64350, + 64353, 1735, 1655, 64477, 64472, 64471, 64488, 64489, 1739, 1700, 64363, + 64364, 64362, 64365, 64479, 64478, 1608, 2219, 1743, 1913, 1912, 1572, + 65158, 65157, 1738, 1732, 65262, 65261, 1610, 1746, 1915, 1914, 1747, + 64433, 64432, 64431, 64430, 1574, 65162, 65163, 65161, 65164, 1742, 2216, + 2234, 2217, 1745, 1741, 69319, 65266, 65267, 65265, 65268, 1736, 64476, + 64475, 1734, 64474, 64473, 1592, 65222, 65223, 65221, 65224, 1586, 65200, + 65199, 2226, 1744, 64485, 64486, 64484, 64487, 2297, 2295, 64888, 64887, + 64886, 64950, 64699, 64554, 64964, 64885, 64698, 64553, 64787, 64759, + 64788, 64760, 64465, 64973, 64842, 64839, 64466, 69331, 64841, 69330, + 64840, 69329, 64845, 65015, 64656, 64605, 64828, 64829, 65010, 65011, + 65023, 64962, 64669, 64518, 64672, 64738, 64926, 64670, 64519, 64622, + 64521, 64668, 64517, 64620, 64671, 64520, 64737, 64621, 64619, 64618, + 64623, 64522, 65021, 64878, 64939, 64693, 64547, 64880, 64879, 64694, + 64548, 64803, 64775, 64692, 64546, 64695, 64549, 64812, 64784, 64804, + 64776, 64452, 64893, 64892, 64704, 64559, 64636, 64561, 64702, 64557, + 64961, 64705, 64560, 64703, 64558, 64637, 64562, 64889, 64891, 64890, + 64701, 64556, 64789, 64761, 64700, 64555, 64790, 64762, 64462, 64463, + 64460, 64461, 64859, 64858, 64682, 64536, 64795, 64767, 64959, 64681, 64535, 64796, 64768, 64915, 64916, 64728, 64594, 64595, 64596, 64727, - 64593, 64729, 64934, 64958, 64679, 64533, 64857, 64856, 64935, 64933, - 64680, 64534, 64797, 64769, 64798, 64770, 65019, 64643, 64573, 64640, - 64567, 64708, 64568, 64641, 64711, 64571, 64747, 64710, 64570, 64709, - 64569, 64963, 64955, 64951, 64642, 64712, 64572, 64748, 64644, 64574, - 64538, 64799, 64771, 64683, 64537, 64684, 64539, 64800, 64772, 65272, - 65271, 65274, 65273, 65270, 65269, 64646, 64579, 65276, 65275, 64898, - 64949, 64896, 64897, 64714, 64576, 64717, 64899, 64900, 64954, 64956, - 64940, 64713, 64575, 64902, 64901, 64715, 64577, 64904, 64903, 64941, - 64645, 64716, 64578, 64749, 64647, 64580, 64585, 64648, 64905, 64906, - 64907, 64719, 64582, 64910, 64911, 64953, 64720, 64583, 64909, 64914, - 64908, 64960, 64718, 64581, 64945, 64649, 64721, 64584, 64586, 65012, - 64918, 64917, 64947, 64723, 64588, 64726, 64751, 64952, 64957, 64921, - 64920, 64919, 64967, 64722, 64587, 64923, 64922, 64652, 64725, 64590, - 64750, 64654, 64591, 64653, 64651, 64724, 64589, 64650, 64655, 64592, - 64895, 64948, 64894, 64946, 64707, 64564, 64638, 64565, 64706, 64563, - 64639, 64566, 65009, 64843, 64833, 64835, 64836, 64837, 64834, 64832, - 64847, 65014, 64604, 64869, 64868, 64937, 64689, 64544, 64965, 64870, + 64593, 64729, 65019, 64451, 64934, 64958, 64679, 64533, 64857, 64856, + 64935, 64933, 64680, 64534, 64797, 64769, 64798, 64770, 64643, 64573, + 64640, 64567, 64708, 64568, 64641, 64711, 64571, 64747, 64710, 64570, + 64709, 64569, 64963, 64955, 64951, 64642, 64712, 64572, 64748, 64644, + 64574, 64974, 64538, 64799, 64771, 64683, 64537, 64684, 64539, 64800, + 64772, 65272, 65271, 65274, 65273, 65270, 65269, 64646, 64579, 65276, + 65275, 64898, 64949, 64896, 64897, 64714, 64576, 64717, 64899, 64900, + 64954, 64956, 64940, 64713, 64575, 64902, 64901, 64715, 64577, 64904, + 64903, 64941, 64645, 64716, 64578, 64749, 64647, 64580, 64585, 64648, + 64905, 64906, 64907, 64719, 64582, 64910, 64911, 64953, 64720, 64583, + 64909, 64914, 64908, 64960, 64718, 64581, 64945, 64649, 64721, 64584, + 64586, 65012, 64918, 64917, 64947, 64723, 64588, 64726, 64751, 64952, + 64957, 64921, 64920, 64919, 64967, 64722, 64587, 64923, 64922, 64652, + 64725, 64590, 64750, 64654, 64591, 64653, 64651, 64724, 64589, 64650, + 64655, 64592, 69336, 64895, 64948, 64894, 64946, 64707, 64564, 64638, + 64565, 64706, 64563, 64639, 64566, 65009, 69332, 69333, 69334, 64843, + 69335, 64833, 64835, 64836, 64837, 64834, 64969, 64459, 64971, 64970, + 64832, 64968, 64847, 64456, 64457, 64458, 64912, 64454, 64455, 64913, + 64453, 65014, 64604, 64869, 64868, 64937, 64689, 64544, 64965, 64870, 64691, 64545, 64801, 64773, 64690, 64811, 64783, 64802, 64774, 65013, - 64975, 65008, 65017, 65018, 64844, 64838, 64860, 64686, 64541, 64821, - 64817, 64744, 64862, 64861, 64685, 64540, 64820, 64936, 64966, 64687, - 64542, 64822, 64864, 64863, 64865, 64867, 64866, 64688, 64543, 64743, - 64791, 64763, 64810, 64782, 64792, 64764, 64606, 64609, 64755, 64607, - 64610, 64756, 64611, 64608, 64754, 64818, 64746, 64872, 64871, 64938, - 64806, 64814, 64778, 64824, 64873, 64805, 64813, 64777, 64823, 64875, - 64874, 64877, 64876, 64808, 64816, 64780, 64745, 64793, 64765, 64807, - 64815, 64779, 64825, 64809, 64781, 64794, 64766, 65022, 64846, 64882, - 64881, 64883, 64884, 64819, 64551, 64826, 64785, 64757, 64696, 64550, - 64786, 64758, 64851, 64850, 64849, 64674, 64524, 64677, 64740, 64930, - 64852, 64929, 64675, 64525, 64928, 64848, 64927, 64673, 64523, 64932, - 64853, 64855, 64854, 64931, 64626, 64676, 64526, 64739, 64628, 64527, - 64627, 64625, 64624, 64629, 64528, 64603, 64529, 64634, 64531, 64632, - 64678, 64530, 64741, 64633, 64631, 64630, 64635, 64532, 64742, 65016, - 64661, 64601, 64616, 64515, 64491, 64490, 64493, 64492, 64503, 64504, - 64502, 64667, 64736, 64664, 64513, 64663, 64512, 64665, 64614, 64666, - 64514, 64735, 64615, 64499, 64498, 64495, 64494, 64617, 64516, 64501, - 64500, 64613, 64612, 64497, 64496, 64942, 64731, 64598, 64734, 64753, - 64660, 64658, 64943, 64730, 64597, 64732, 64599, 64925, 64924, 64944, - 64659, 64733, 64600, 64752, 64657, 64662, 64602, 64506, 64507, 64505, - 64697, 64552, 64827, 2204, 1619, 1624, 2303, 126492, 126494, 126493, - 126495, 126644, 126638, 126641, 126647, 126648, 126646, 126632, 126645, - 126630, 126650, 126626, 126636, 126625, 126640, 126643, 126633, 126631, - 126651, 126637, 126635, 126649, 126627, 126642, 126639, 126629, 126489, - 126467, 126518, 126517, 126516, 126510, 126513, 126503, 126500, 126519, - 126506, 126498, 126508, 126497, 126512, 126505, 126523, 126509, 126507, - 126514, 126511, 126521, 126612, 126606, 126609, 126615, 126592, 126607, - 126599, 126596, 126616, 126614, 126600, 126613, 126598, 126618, 126594, - 126604, 126593, 126608, 126611, 126601, 126619, 126605, 126603, 126617, - 126595, 126610, 126597, 126475, 126704, 126705, 126588, 126590, 126585, - 126582, 126568, 126581, 126580, 126574, 126577, 126567, 126564, 126583, - 126570, 126562, 126572, 126561, 126576, 126569, 126586, 126587, 126573, - 126578, 126575, 126484, 126478, 126481, 126557, 126559, 126553, 126548, - 126542, 126545, 126551, 126530, 126537, 126535, 126555, 126541, 126539, - 126546, 126543, 126472, 126488, 126486, 126485, 126464, 126479, 126487, - 126474, 126470, 126490, 126466, 126476, 126465, 126480, 126483, 126473, - 126471, 126491, 126477, 126482, 126469, 1541, 1536, 2290, 2289, 2288, - 1642, 2199, 1550, 2192, 1769, 2193, 2184, 1544, 1629, 2296, 2301, 2298, - 1772, 2183, 1623, 983633, 983635, 983640, 983634, 983638, 983636, 983639, - 983637, 983641, 1563, 1617, 65148, 65149, 1554, 1555, 1552, 1537, 1539, - 1540, 1790, 1789, 1553, 1551, 1556, 2249, 1560, 1761, 2250, 2272, 1558, - 983202, 1751, 1750, 1753, 1752, 1762, 1764, 1768, 2264, 2273, 1756, 2261, - 1755, 1557, 2200, 2260, 2266, 2268, 2267, 2269, 2252, 2271, 2270, 2291, - 1767, 2251, 1760, 1759, 1559, 2253, 1754, 2263, 2262, 2265, 2202, 2201, - 69375, 2203, 69373, 69374, 2259, 1773, 1763, 1562, 1561, 1766, 1765, - 1622, 1618, 65150, 65151, 2256, 2205, 64444, 64435, 64434, 64441, 64440, - 64439, 64438, 64446, 64445, 64437, 64436, 64449, 64448, 64443, 64442, - 64450, 64447, 1758, 1600, 2179, 2180, 65137, 2181, 65139, 2285, 2282, - 2286, 2283, 2287, 2284, 1566, 2275, 1644, 1627, 1626, 1628, 2190, 1631, - 1567, 1625, 1545, 1546, 1542, 1543, 1637, 1636, 1639, 1638, 1635, 1634, - 1632, 1641, 1633, 1640, 1375, 1370, 1359, 1337, 1349, 1362, 1347, 1353, - 1342, 1361, 1360, 1356, 1333, 1335, 1336, 1346, 1331, 1355, 1345, 1364, - 1343, 1363, 1354, 1351, 1357, 1329, 1358, 1352, 1340, 1366, 1341, 1339, - 1330, 1348, 1350, 1338, 1334, 1344, 1332, 1365, 1373, 1372, 1371, 1395, - 1401, 1390, 1409, 1408, 1404, 1381, 1383, 1384, 1394, 1379, 1403, 1393, - 1412, 1391, 1411, 1402, 1399, 1405, 1376, 1407, 1385, 1377, 1406, 1400, - 1397, 1416, 1410, 1388, 1414, 1389, 1387, 1378, 1396, 1398, 1386, 1382, - 1392, 1380, 1413, 1415, 64279, 64277, 64275, 64276, 64278, 1369, 1418, - 1423, 1417, 1374, 129201, 10549, 10548, 129200, 10550, 10551, 129968, - 128667, 127912, 9800, 8978, 9738, 65948, 42, 8727, 8258, 128562, 11225, - 9954, 8771, 8870, 128095, 9883, 128663, 127975, 128762, 8371, 127814, - 68352, 68353, 68357, 68355, 68358, 68359, 68356, 68354, 68373, 68374, - 68372, 68393, 68405, 68388, 68387, 68386, 68391, 68390, 68389, 68371, - 68370, 68369, 68403, 68401, 68404, 68399, 68394, 68395, 68378, 68381, - 68377, 68366, 68367, 68362, 68363, 68364, 68365, 68385, 68384, 68380, - 68379, 68402, 68400, 68360, 68361, 68375, 68383, 68376, 68368, 68398, - 68392, 68382, 68397, 68396, 68409, 129361, 1547, 129518, 8525, 9810, - 129683, 128118, 128036, 127868, 128124, 128700, 128281, 128386, 11101, - 11099, 983056, 10155, 128043, 129363, 127992, 129441, 129366, 129391, - 128708, 7007, 7005, 7006, 6991, 6990, 6917, 6918, 6987, 6988, 6928, 6953, - 6954, 6936, 6937, 6948, 6944, 6943, 6949, 6984, 6927, 6933, 6934, 6919, - 6920, 6929, 6930, 6921, 6922, 6938, 6939, 6931, 6981, 6932, 6982, 6958, - 6925, 6926, 6950, 6945, 6935, 6940, 6951, 6952, 6957, 6923, 6924, 6962, - 6960, 6961, 6946, 6942, 6941, 6947, 6983, 6985, 6986, 6963, 6955, 6959, - 6956, 7022, 7025, 7021, 7024, 7023, 7026, 7020, 7019, 7027, 7012, 7013, - 7018, 7015, 7017, 7016, 7010, 7014, 7009, 7011, 7032, 7036, 7033, 7034, - 7035, 7031, 7030, 7029, 7028, 7003, 7038, 7008, 7002, 7037, 7039, 6915, - 6913, 6912, 6914, 6916, 6964, 6972, 6973, 6970, 6971, 6968, 6969, 6974, - 6975, 6977, 6976, 6965, 6978, 6979, 6966, 6967, 6980, 7004, 6997, 6996, - 6999, 6998, 6995, 6994, 6992, 7001, 6993, 7000, 127880, 10057, 9744, - 128503, 128505, 128499, 128501, 11197, 9745, 9746, 128502, 128500, 10007, - 129526, 129648, 42737, 42736, 42741, 42740, 42733, 42699, 42713, 42712, - 42692, 42706, 42683, 42719, 42734, 42735, 42682, 42729, 42657, 42725, - 42659, 42670, 42718, 42666, 42716, 42701, 42675, 42671, 42722, 42720, - 42727, 42723, 42702, 42726, 42677, 42707, 42708, 42709, 42686, 42694, - 42674, 42731, 42695, 42685, 42684, 42691, 42673, 42664, 42715, 42703, - 92193, 92188, 92161, 92199, 92240, 92179, 92211, 92219, 92213, 92243, - 92207, 92216, 92183, 92184, 92238, 92171, 983268, 92174, 92203, 92186, - 92210, 92230, 92175, 92221, 92232, 92246, 92198, 92214, 92190, 92176, - 92197, 92196, 92164, 92245, 92212, 92201, 92160, 92182, 92173, 92229, - 92227, 92180, 92237, 92241, 92223, 92185, 92194, 92178, 92239, 92225, - 92233, 92167, 92191, 92231, 92244, 92204, 92226, 92236, 92200, 92189, - 92187, 92162, 92163, 92169, 92170, 92202, 92205, 92222, 92168, 92165, - 92215, 92224, 92208, 92220, 92235, 92177, 92181, 92195, 92234, 92209, - 92166, 92172, 92206, 92192, 92228, 92217, 92242, 92218, 92262, 92271, - 92272, 92270, 92294, 92253, 92301, 92256, 92273, 92259, 92251, 92297, - 92300, 92296, 92295, 92255, 92252, 92292, 92286, 92268, 92290, 92281, - 92267, 92284, 92287, 92282, 92283, 92277, 92298, 92276, 92302, 92247, - 92299, 92288, 92269, 92260, 92261, 92257, 92274, 92289, 92263, 92279, - 92265, 92266, 92250, 92249, 92285, 92248, 92264, 92280, 92258, 92254, - 92278, 92291, 92293, 92275, 92310, 92320, 92312, 92394, 92393, 92319, - 92384, 92321, 92386, 92361, 92373, 92366, 92328, 92329, 92357, 92342, - 92397, 92365, 92376, 92339, 92382, 92363, 92318, 92387, 92383, 92315, - 92385, 92354, 92311, 92381, 92343, 92326, 92364, 92324, 92391, 92344, - 92390, 92338, 92396, 92308, 92349, 92375, 92378, 92317, 92331, 92362, - 92336, 92341, 92370, 92347, 92307, 92303, 92309, 92395, 92368, 92356, - 92367, 92360, 92389, 92333, 92359, 92374, 92351, 92325, 92371, 92350, - 92345, 92372, 92314, 92340, 92323, 92304, 92313, 92316, 92398, 92399, - 92380, 92330, 92379, 92392, 92335, 92332, 92346, 92400, 92358, 92334, - 92353, 92337, 92306, 92369, 92388, 92322, 92305, 92327, 92377, 92352, - 92348, 92355, 92436, 92517, 92488, 92434, 92415, 92431, 92454, 92460, - 92420, 92489, 92422, 92474, 92479, 92449, 92502, 92439, 92484, 92495, - 92464, 92511, 92406, 92446, 92497, 92426, 92482, 92448, 92515, 92401, - 92478, 92427, 92496, 92458, 92424, 92445, 92404, 92466, 92444, 92438, - 92442, 92441, 92510, 92499, 92425, 92437, 92440, 92471, 92465, 92409, - 92483, 92475, 92467, 92485, 92457, 92432, 92476, 92435, 92412, 92414, - 92430, 92407, 92403, 92405, 92487, 92418, 92486, 92408, 92447, 92459, - 92480, 92472, 92505, 92514, 92450, 92463, 92410, 92493, 92507, 92503, - 92462, 92506, 92443, 92509, 92469, 92461, 92490, 92512, 92494, 92455, - 92417, 92501, 92413, 92508, 92500, 92504, 92473, 92419, 92498, 92423, - 92516, 92428, 92452, 92451, 92481, 92416, 92456, 92433, 92477, 92492, - 92491, 92513, 92411, 92402, 92421, 92453, 92468, 92470, 92429, 92661, - 92626, 92616, 92596, 92612, 92603, 92673, 92651, 92627, 92597, 92585, - 92578, 92615, 92565, 92552, 92602, 92674, 92570, 92646, 92599, 92532, - 92587, 92538, 92620, 92670, 92665, 92575, 92521, 92633, 92595, 92523, - 92556, 92539, 92664, 92653, 92667, 92600, 92542, 92555, 92668, 92520, - 92582, 92591, 92581, 92551, 92654, 92611, 92614, 92666, 92671, 92617, - 92637, 92562, 92518, 92592, 92558, 92528, 92607, 92535, 92557, 92563, - 92550, 92624, 92640, 92657, 92531, 92601, 92553, 92543, 92619, 92598, - 92541, 92544, 92579, 92658, 92554, 92628, 92648, 92547, 92527, 92545, - 92540, 92604, 92622, 92589, 92608, 92583, 92609, 92662, 92613, 92584, - 92625, 92634, 92524, 92536, 92605, 92647, 92548, 92663, 92593, 92621, - 92568, 92610, 92576, 92529, 92618, 92649, 92561, 92656, 92526, 92655, - 92546, 92534, 92560, 92580, 92659, 92660, 92638, 92571, 92525, 92549, - 92559, 92635, 92577, 92530, 92636, 92669, 92572, 92672, 92537, 92519, - 92630, 92586, 92569, 92566, 92573, 92652, 92522, 92574, 92650, 92533, - 92567, 92623, 92606, 92639, 92564, 92590, 92642, 92643, 92594, 92641, - 92645, 92644, 92588, 92629, 92632, 92631, 92710, 92695, 92694, 92726, - 92675, 92719, 92677, 92718, 92682, 92717, 92689, 92720, 92724, 92685, - 92722, 92723, 92711, 92712, 92698, 92688, 92697, 92696, 92702, 92687, - 92704, 92681, 92708, 92703, 92706, 92714, 92709, 92679, 92721, 92684, - 92683, 92707, 92691, 92713, 92700, 92693, 92727, 92690, 92692, 92686, - 92680, 92725, 92699, 92701, 92705, 92716, 92728, 92678, 92715, 92676, - 42693, 42698, 42711, 42696, 42667, 42717, 42704, 42661, 42721, 42669, - 42668, 42705, 42700, 42680, 42678, 42710, 42688, 42681, 42732, 42676, - 42679, 42730, 42728, 42672, 42662, 42724, 42687, 42689, 42690, 42697, - 42714, 42660, 42656, 42665, 42663, 42658, 42738, 42742, 42739, 42743, - 127974, 128183, 128180, 128182, 128181, 127820, 129685, 128202, 129532, - 128136, 129530, 127936, 92916, 92912, 92915, 92913, 92914, 92887, 92894, - 92908, 92880, 92907, 92893, 92886, 92888, 92881, 92906, 92896, 92891, - 92902, 92900, 92885, 92890, 92884, 92904, 92905, 92899, 92889, 92897, - 92892, 92895, 92882, 92898, 92883, 92901, 92903, 92909, 92917, 9918, - 129415, 7152, 7153, 7124, 7108, 7114, 7130, 7139, 7127, 7138, 7133, 7136, - 7113, 7111, 7117, 7119, 7107, 7135, 7125, 7112, 7123, 7129, 7116, 7132, - 7105, 7126, 7128, 7110, 7109, 7137, 7121, 7118, 7106, 7120, 7134, 7122, - 7115, 7131, 7104, 7140, 7141, 7154, 7155, 7167, 7165, 7166, 7164, 7142, - 7150, 7151, 7144, 7147, 7149, 7143, 7145, 7146, 7148, 128704, 128705, - 128267, 127900, 127901, 9835, 9836, 129492, 128059, 127958, 128147, - 129451, 129752, 127866, 129714, 983055, 128276, 129745, 128277, 9086, - 128718, 2557, 2432, 2519, 2548, 2552, 2551, 2550, 2549, 2553, 2454, 2510, - 983661, 2453, 2480, 2545, 2544, 2525, 2524, 2556, 2443, 2528, 2444, 2529, - 2527, 2479, 2437, 2438, 2448, 2452, 2466, 2465, 2471, 2470, 2464, 2463, - 2469, 2468, 2441, 2442, 2439, 2440, 2457, 2467, 2462, 2472, 2486, 2487, - 2488, 2477, 2476, 2459, 2458, 2456, 2455, 2461, 2460, 2475, 2474, 2489, - 2482, 2478, 2447, 2451, 2547, 2546, 983651, 983650, 983652, 2558, 2433, - 2492, 2493, 2434, 2509, 2435, 2554, 2494, 2504, 2508, 2497, 2498, 2499, - 2500, 2530, 2531, 2495, 2496, 2503, 2507, 2539, 2538, 2541, 2540, 2537, - 2536, 2534, 2543, 2535, 2542, 2555, 11102, 127857, 9004, 9187, 8812, - 8502, 8757, 129475, 128719, 72710, 72711, 72712, 72746, 72704, 72705, - 72715, 72717, 72731, 72730, 72736, 72735, 72729, 72728, 72734, 72733, - 72708, 72709, 72706, 72707, 72722, 72732, 72727, 72737, 72747, 72748, - 72749, 72741, 72740, 72724, 72723, 72721, 72720, 72726, 72725, 72719, - 72718, 72739, 72738, 72750, 72745, 72742, 72744, 72743, 72714, 72716, - 72801, 72810, 72806, 72797, 72807, 72798, 72802, 72811, 72800, 72809, - 72799, 72808, 72796, 72805, 72804, 72795, 72803, 72794, 72764, 72768, - 72765, 72767, 72766, 72756, 72757, 72758, 72751, 72761, 72763, 72754, - 72755, 72752, 72753, 72760, 72762, 72770, 72769, 72789, 72788, 72791, - 72790, 72787, 72786, 72784, 72793, 72785, 72792, 72771, 72772, 72773, - 72812, 128692, 128690, 10745, 10744, 129506, 127921, 127874, 128038, - 8383, 129766, 9763, 128089, 129452, 9679, 9864, 10733, 9865, 9210, 11176, - 11177, 11178, 11179, 11180, 11182, 11181, 11183, 9960, 10028, 9821, - 129554, 129596, 129609, 129612, 9818, 129551, 129593, 9822, 129543, - 129564, 129585, 129597, 129606, 129555, 129619, 129617, 129618, 9823, - 129556, 129598, 9819, 129552, 129594, 9820, 129553, 129595, 129575, - 129572, 129576, 129577, 129573, 129574, 9827, 9670, 11201, 10070, 10730, - 11230, 9830, 128419, 128899, 9196, 9662, 9660, 11167, 127778, 9922, 9923, - 10047, 9873, 10022, 128447, 128420, 9829, 11042, 128426, 11052, 10711, - 11044, 117867, 117870, 117869, 117868, 11035, 9194, 9198, 128896, 9668, - 9666, 9664, 11164, 8268, 9944, 128412, 9754, 9699, 9698, 10731, 9207, - 11206, 11045, 9204, 11207, 11047, 9205, 11208, 9206, 11205, 128921, - 128927, 9726, 9724, 9912, 117871, 10002, 128392, 9648, 11039, 127986, - 118451, 128413, 9755, 9193, 9197, 9654, 9199, 128898, 11091, 9658, 9656, - 10145, 10148, 11166, 8269, 127990, 9644, 11049, 11050, 11089, 9642, - 129997, 9787, 9632, 11200, 9209, 128306, 9728, 128369, 9927, 9984, - 128900, 128909, 9986, 9751, 9824, 9733, 128919, 128925, 128908, 9951, - 128383, 9742, 9942, 128418, 128897, 9195, 9652, 9650, 9700, 9701, 11165, - 9851, 9646, 11054, 128920, 128926, 11037, 11204, 10707, 10067, 8493, - 8460, 8465, 8476, 8488, 10164, 10166, 10165, 9250, 118018, 118039, - 118128, 118187, 118218, 118159, 118054, 118112, 118234, 118084, 118202, - 118143, 118031, 118062, 118120, 118240, 118179, 118090, 118210, 118151, - 118047, 118104, 118226, 118165, 118076, 118194, 118135, 118021, 118035, - 118066, 118124, 118243, 118183, 118093, 118214, 118155, 118050, 118108, - 118230, 118168, 118080, 118198, 118139, 118028, 118058, 118116, 118237, - 118175, 118087, 118206, 118147, 118043, 118100, 118222, 118162, 118072, - 118190, 118131, 118029, 118060, 118118, 118177, 118208, 118149, 118045, - 118102, 118224, 118023, 118037, 118068, 118126, 118244, 118185, 118095, - 118216, 118157, 118052, 118110, 118232, 118170, 118082, 118200, 118141, - 118074, 118192, 118133, 118020, 118033, 118064, 118122, 118242, 118181, - 118092, 118212, 118153, 118048, 118106, 118228, 118167, 118078, 118196, - 118137, 118026, 118056, 118114, 118235, 118173, 118085, 118204, 118145, - 118041, 118098, 118220, 118160, 118070, 118188, 118129, 118034, 118065, - 118123, 118182, 118213, 118154, 118049, 118107, 118229, 118079, 118197, - 118138, 118017, 118024, 118038, 118069, 118127, 118245, 118186, 118096, - 118217, 118158, 118053, 118111, 118233, 118171, 118083, 118201, 118142, - 118030, 118061, 118119, 118239, 118178, 118089, 118209, 118150, 118046, - 118103, 118225, 118164, 118075, 118193, 118134, 118027, 118057, 118115, - 118236, 118174, 118086, 118205, 118146, 118042, 118099, 118221, 118161, - 118071, 118189, 118130, 118025, 118055, 118113, 118172, 118203, 118144, - 118040, 118097, 118219, 118016, 118022, 118036, 118067, 118125, 118184, - 118094, 118215, 118156, 118051, 118109, 118231, 118169, 118081, 118199, - 118140, 118059, 118117, 118238, 118176, 118088, 118207, 118148, 118044, - 118101, 118223, 118163, 118073, 118191, 118132, 118019, 118105, 118227, - 118166, 118032, 118063, 118121, 118241, 118180, 118091, 118211, 118152, - 118077, 118195, 118136, 129792, 129794, 129798, 129806, 129821, 129836, - 129813, 129844, 129829, 129802, 129817, 129848, 129832, 129810, 129840, - 129825, 129796, 129804, 129819, 129850, 129834, 129842, 129827, 129800, - 129815, 129846, 129831, 129808, 129838, 129823, 129793, 129801, 129816, - 129847, 129797, 129805, 129820, 129851, 129835, 129812, 129843, 129828, - 129809, 129839, 129824, 129795, 129803, 129818, 129849, 129833, 129811, - 129841, 129826, 129799, 129814, 129845, 129830, 129807, 129837, 129822, - 127804, 128033, 128216, 128153, 129744, 128939, 128951, 128957, 128945, - 128902, 128912, 128932, 128366, 128278, 128209, 128218, 129667, 12731, - 12727, 12726, 12724, 12725, 12570, 12574, 12718, 12576, 12719, 12578, - 12580, 12713, 12735, 12720, 12584, 12715, 12572, 12579, 12581, 12709, - 12708, 12573, 12575, 12582, 12557, 12728, 12588, 12707, 12732, 12583, - 12714, 12723, 12589, 12716, 12712, 12585, 12555, 12587, 12717, 12591, - 12571, 12722, 12711, 12590, 12734, 12721, 12710, 12577, 12567, 12563, - 12705, 12730, 12558, 12733, 12568, 12564, 12556, 12729, 12569, 12565, - 12549, 12704, 12560, 12706, 12553, 12552, 12559, 12551, 12550, 12561, - 12566, 12554, 12586, 12562, 118257, 118258, 118259, 118260, 117854, - 11867, 117853, 118253, 118255, 11868, 117855, 118249, 118251, 118247, - 11211, 8993, 130029, 8990, 8973, 11812, 8991, 8972, 11813, 130030, 9141, - 9142, 10555, 9183, 9181, 130026, 130018, 9185, 127870, 128144, 127893, - 128335, 129379, 127923, 8904, 10705, 10706, 127993, 118282, 117792, - 117791, 118281, 9574, 9559, 9556, 9577, 9565, 9562, 9553, 9580, 9571, - 9568, 9552, 9511, 9490, 9503, 9486, 9537, 9520, 9513, 9489, 9505, 9485, - 9543, 9519, 9558, 9555, 9573, 9557, 9554, 9572, 9592, 9598, 9593, 9599, - 9499, 9531, 9495, 9475, 9547, 9515, 9507, 9595, 9523, 9491, 9487, 9551, - 9549, 9483, 9481, 9479, 9477, 9473, 9594, 9541, 9525, 9517, 9533, 9530, - 9522, 9546, 9539, 9582, 9581, 9583, 9584, 130010, 130014, 129954, 129958, - 130003, 129959, 129964, 129965, 129955, 130000, 129952, 129956, 129963, - 129960, 129953, 129961, 129957, 129962, 130007, 130005, 130004, 130012, - 9586, 130008, 130011, 130002, 130015, 130006, 9585, 130009, 130001, - 130013, 9587, 129966, 9591, 9516, 9488, 9484, 9550, 9548, 9472, 117787, - 117788, 129967, 9588, 9596, 9482, 9480, 9478, 9476, 117789, 9589, 9597, - 9524, 9496, 9492, 9474, 118297, 118295, 118296, 118294, 9532, 9508, 9500, - 117790, 9590, 9542, 9526, 9518, 9534, 9529, 9521, 9545, 9540, 9536, 9510, - 9498, 9502, 9494, 9528, 9544, 9514, 9497, 9506, 9493, 9527, 9564, 9561, - 9576, 9563, 9560, 9575, 9570, 9567, 9579, 9538, 9512, 9504, 9535, 9509, - 9501, 9569, 9566, 9578, 129354, 983263, 128163, 128102, 128713, 128023, - 129460, 69649, 69685, 69749, 69745, 69746, 69687, 69686, 69637, 69638, - 69648, 69650, 69664, 69663, 69669, 69668, 69662, 69661, 69667, 69666, - 69643, 69644, 69645, 69646, 69679, 69641, 69642, 69639, 69640, 69684, - 69678, 69655, 69665, 69660, 69670, 69680, 69681, 69682, 69674, 69673, - 69657, 69656, 69654, 69653, 69659, 69658, 69652, 69651, 69672, 69671, - 69683, 69675, 69677, 69676, 69647, 69721, 69730, 69726, 69717, 69727, - 69718, 69722, 69731, 69720, 69729, 69719, 69728, 69716, 69725, 69724, - 69715, 69723, 69714, 69732, 69733, 69759, 69709, 69707, 69706, 69705, - 69708, 69632, 69744, 69635, 69634, 69636, 69633, 69700, 69747, 69748, - 69689, 69688, 69699, 69701, 69692, 69693, 69694, 69695, 69696, 69697, - 69690, 69691, 69698, 69702, 69704, 69703, 69739, 69738, 69741, 69740, - 69737, 69736, 69734, 69743, 69735, 69742, 10241, 10243, 10247, 10255, - 10271, 10303, 10367, 10495, 10431, 10335, 10463, 10399, 10287, 10351, - 10479, 10415, 10319, 10447, 10383, 10263, 10295, 10359, 10487, 10423, - 10327, 10455, 10391, 10279, 10343, 10471, 10407, 10311, 10439, 10375, - 10251, 10267, 10299, 10363, 10491, 10427, 10331, 10459, 10395, 10283, - 10347, 10475, 10411, 10315, 10443, 10379, 10259, 10291, 10355, 10483, - 10419, 10323, 10451, 10387, 10275, 10339, 10467, 10403, 10307, 10435, - 10371, 10245, 10253, 10269, 10301, 10365, 10493, 10429, 10333, 10461, - 10397, 10285, 10349, 10477, 10413, 10317, 10445, 10381, 10261, 10293, - 10357, 10485, 10421, 10325, 10453, 10389, 10277, 10341, 10469, 10405, - 10309, 10437, 10373, 10249, 10265, 10297, 10361, 10489, 10425, 10329, - 10457, 10393, 10281, 10345, 10473, 10409, 10313, 10441, 10377, 10257, - 10289, 10353, 10481, 10417, 10321, 10449, 10385, 10273, 10337, 10465, - 10401, 10305, 10433, 10369, 10242, 10246, 10254, 10270, 10302, 10366, - 10494, 10430, 10334, 10462, 10398, 10286, 10350, 10478, 10414, 10318, - 10446, 10382, 10262, 10294, 10358, 10486, 10422, 10326, 10454, 10390, - 10278, 10342, 10470, 10406, 10310, 10438, 10374, 10250, 10266, 10298, - 10362, 10490, 10426, 10330, 10458, 10394, 10282, 10346, 10474, 10410, - 10314, 10442, 10378, 10258, 10290, 10354, 10482, 10418, 10322, 10450, - 10386, 10274, 10338, 10466, 10402, 10306, 10434, 10370, 10244, 10252, - 10268, 10300, 10364, 10492, 10428, 10332, 10460, 10396, 10284, 10348, - 10476, 10412, 10316, 10444, 10380, 10260, 10292, 10356, 10484, 10420, - 10324, 10452, 10388, 10276, 10340, 10468, 10404, 10308, 10436, 10372, - 10248, 10264, 10296, 10360, 10488, 10424, 10328, 10456, 10392, 10280, - 10344, 10472, 10408, 10312, 10440, 10376, 10256, 10288, 10352, 10480, - 10416, 10320, 10448, 10384, 10272, 10336, 10464, 10400, 10304, 10432, - 10368, 10240, 129504, 983125, 129329, 127838, 728, 127753, 128112, - 128188, 129650, 129521, 9099, 166, 128148, 129382, 129294, 129529, - 129483, 129767, 128027, 6663, 6662, 6659, 6658, 6671, 6670, 6667, 6666, - 6661, 6668, 6665, 6657, 6678, 6669, 6656, 6674, 6660, 6673, 6676, 6664, - 6675, 6672, 6677, 6683, 6681, 6679, 6682, 6680, 6687, 6686, 5957, 5960, - 5962, 5959, 5956, 5969, 5955, 5966, 5963, 5961, 5965, 5968, 5958, 5967, - 5964, 5952, 5953, 5954, 5970, 5971, 8226, 8729, 128363, 128364, 9678, - 128652, 128101, 128100, 128655, 129480, 129419, 127959, 127791, 129699, - 118939, 118940, 118944, 118943, 118941, 118942, 118938, 118945, 118882, - 118876, 118824, 118835, 118797, 118866, 118957, 118801, 118802, 118865, - 118818, 118916, 118819, 118917, 118899, 118935, 119018, 119022, 119021, - 119020, 119023, 119019, 119017, 118986, 118984, 118985, 118843, 118887, - 118808, 118870, 119003, 119002, 119004, 119005, 118937, 118991, 118995, - 118990, 118992, 118994, 118993, 118930, 118933, 118931, 118932, 119014, - 118918, 118912, 119015, 118785, 118831, 118907, 118966, 118900, 118880, - 118798, 118888, 118884, 118869, 118960, 118959, 118958, 118836, 118969, - 118977, 118978, 118971, 118976, 118975, 118973, 118970, 118987, 118979, - 118980, 118972, 118983, 983274, 118982, 118974, 118988, 118981, 119000, - 119001, 118929, 118928, 118806, 119029, 118927, 118898, 118964, 118965, - 118853, 118968, 118837, 118967, 118936, 118956, 118810, 118854, 118847, - 118839, 118906, 118791, 118800, 119024, 119026, 118862, 118812, 119025, - 119027, 118863, 118811, 118820, 119028, 118911, 118842, 118850, 118921, - 118858, 118913, 118914, 118915, 118834, 118860, 118868, 118796, 118881, - 118922, 118926, 118925, 118924, 118923, 118830, 118877, 118949, 118947, - 118948, 118963, 118955, 118962, 118946, 118961, 118953, 118952, 118951, - 118950, 118954, 118871, 118805, 118855, 118828, 118901, 118787, 118788, - 118856, 118816, 118875, 118845, 118879, 118793, 118846, 118878, 118814, - 118822, 118873, 118859, 118857, 118849, 118840, 118861, 118786, 118895, - 118841, 118874, 118892, 118897, 118807, 118784, 118821, 118844, 118825, - 118889, 119010, 119012, 119013, 119011, 119006, 119008, 119009, 119007, - 118910, 118815, 118852, 119016, 118826, 118885, 118827, 118803, 118886, - 118792, 118813, 118920, 118799, 118833, 118829, 118904, 118902, 118903, - 118905, 118804, 118934, 118919, 118832, 118893, 118838, 118851, 118883, - 118894, 118891, 118896, 118823, 118789, 118790, 118872, 118817, 118809, - 118908, 118909, 118996, 118998, 118997, 118999, 118989, 118794, 118795, - 118867, 118864, 118848, 118890, 983262, 983126, 983057, 9764, 8454, - 129305, 128197, 128247, 128248, 127957, 983098, 5130, 5131, 5122, 6322, - 5148, 5551, 5310, 5382, 5166, 6321, 5759, 5559, 5556, 5557, 5558, 5567, - 5564, 5565, 5566, 5563, 5560, 5561, 5562, 5555, 5552, 5553, 5554, 5384, - 5439, 6387, 6388, 5281, 5264, 6382, 6389, 5203, 5674, 5675, 5677, 5676, - 5673, 5672, 5706, 5707, 5709, 5708, 5705, 5704, 5204, 5574, 5575, 5577, - 5576, 5573, 5572, 6384, 6381, 5620, 6383, 5617, 5618, 5619, 5616, 5615, - 5195, 5592, 5593, 5595, 5594, 5591, 5590, 5174, 5175, 5129, 5703, 5662, - 5663, 5665, 5664, 5661, 5660, 5655, 5656, 6386, 5659, 5657, 5654, 5652, - 5633, 5629, 5630, 5632, 5631, 5628, 5627, 5623, 5624, 5626, 5625, 5622, - 5621, 5636, 5637, 5639, 5329, 5638, 5635, 5634, 5722, 5718, 5719, 5721, - 5720, 5717, 5716, 5712, 5713, 5715, 5714, 5711, 5710, 5614, 5610, 5611, - 5613, 5612, 5609, 5608, 5702, 5698, 5699, 5701, 5700, 5697, 5696, 5686, - 5687, 5689, 5688, 5685, 5684, 5692, 5693, 5695, 5694, 5691, 5690, 5737, - 5738, 5740, 5739, 5736, 5735, 5604, 5605, 5607, 5606, 5603, 5602, 5598, - 5599, 5601, 5600, 5597, 5596, 5725, 5726, 5728, 5727, 5724, 5723, 5680, - 5681, 5683, 5682, 5679, 5678, 5668, 5669, 5671, 5670, 5667, 5666, 5731, - 5732, 5734, 5733, 5730, 5729, 5642, 5643, 5645, 5644, 5641, 5640, 5580, - 5581, 5583, 5582, 5579, 5578, 5586, 5587, 5589, 5588, 5585, 5584, 5648, - 5649, 5651, 5650, 5647, 5646, 5128, 5265, 5258, 5276, 5278, 5272, 5274, - 5268, 5270, 5266, 5741, 5261, 5262, 5259, 5260, 5257, 5121, 6364, 5163, - 5469, 5465, 5466, 5460, 5461, 5158, 5157, 5162, 5155, 5156, 6367, 6366, - 5160, 5152, 5151, 5153, 5154, 5161, 5159, 5462, 5742, 5463, 5464, 5467, - 5459, 5120, 5501, 5123, 5124, 5164, 5251, 5252, 5246, 5248, 6329, 5242, - 5244, 5238, 5240, 5236, 5234, 5235, 5228, 6328, 5231, 5232, 5229, 5230, - 5227, 5354, 5542, 5540, 5541, 5538, 5539, 5536, 5537, 5338, 5339, 5332, - 6333, 5350, 5352, 5346, 5348, 5342, 5344, 5340, 5335, 5336, 5333, 5334, - 5331, 5307, 5283, 5356, 5458, 5287, 5288, 5385, 5290, 5291, 5284, 6330, - 5302, 5304, 5298, 5300, 5294, 5296, 5292, 5285, 5286, 5309, 5328, 5473, - 5475, 5471, 5319, 5386, 5390, 5391, 5388, 5389, 5380, 5387, 5142, 5147, - 5280, 5250, 5306, 5327, 5221, 5437, 72372, 72373, 72370, 72371, 72368, - 72369, 72378, 72379, 72376, 72377, 72374, 72375, 5320, 5313, 6332, 5525, - 5523, 5524, 5518, 5744, 5521, 5522, 5519, 5520, 5526, 5749, 5750, 5747, - 5748, 5745, 5746, 5499, 5497, 5498, 5495, 5496, 5493, 5494, 5492, 5500, - 5316, 5317, 6331, 5323, 5325, 6346, 6348, 6342, 6344, 5321, 5314, 5315, - 5312, 5330, 5509, 5507, 5508, 5502, 5743, 5505, 5506, 5503, 5504, 5125, - 6361, 6347, 6349, 6343, 6345, 6362, 6363, 6359, 6358, 6360, 6356, 6357, - 5165, 5126, 6320, 5193, 5184, 5186, 6326, 5188, 5190, 5180, 5182, 5178, - 5176, 5177, 5168, 6325, 5171, 5172, 6324, 5169, 5170, 5167, 5456, 6368, - 5443, 6355, 5454, 6353, 6354, 6351, 6352, 6350, 5451, 5452, 5445, 6341, - 5448, 5449, 5446, 5447, 5442, 5381, 5364, 6335, 5570, 6380, 5571, 5568, - 5569, 5653, 6385, 5658, 5529, 6379, 6378, 5530, 5527, 5528, 5441, 5282, - 5311, 5365, 5358, 5413, 5405, 5407, 6338, 5409, 5411, 5401, 5403, 5399, - 5395, 5396, 6336, 5397, 5398, 6337, 5393, 5394, 5392, 5361, 5256, 5253, - 5254, 5255, 5362, 6334, 5383, 5376, 5378, 5372, 5374, 5368, 5370, 5366, - 72383, 72380, 72381, 72382, 5359, 5360, 5357, 5222, 5482, 5550, 5548, - 5549, 5546, 5547, 5544, 5545, 5543, 6372, 5480, 6371, 5478, 5479, 5476, - 5477, 5472, 5474, 5470, 5512, 6377, 6376, 5513, 5510, 5511, 5487, 5486, - 6375, 5485, 6374, 6373, 5483, 5484, 5226, 5223, 5224, 5225, 5205, 5206, - 5197, 6327, 5217, 5219, 5213, 5215, 5209, 5211, 5207, 5491, 5488, 5489, - 5490, 5200, 5201, 5198, 5199, 5196, 5132, 5355, 5351, 5353, 5347, 5349, - 5343, 5345, 5341, 5453, 6370, 5450, 6369, 5444, 5308, 5303, 5305, 5299, - 5301, 5295, 5297, 5293, 5194, 5189, 5191, 5185, 5187, 5181, 5183, 5179, - 5440, 5434, 5436, 5430, 5432, 5426, 5428, 5424, 5324, 5326, 5322, 5457, - 5455, 5517, 5514, 5515, 5516, 5410, 5412, 5406, 5408, 5402, 5404, 5400, - 5377, 5379, 5373, 5375, 5369, 5371, 5367, 5277, 5279, 5273, 5275, 5269, - 5271, 5267, 5247, 5249, 5243, 5245, 5239, 5241, 5237, 5481, 5218, 5220, - 5214, 5216, 5210, 5212, 5208, 5468, 5144, 5146, 5139, 5141, 5135, 5137, - 5133, 6365, 5138, 5140, 5535, 5756, 5757, 5754, 5755, 5752, 5753, 5751, - 5534, 5531, 5532, 5533, 5758, 5143, 5145, 6323, 5134, 5136, 5438, 5192, - 5173, 5263, 5233, 5337, 5289, 5318, 5363, 5202, 5420, 5127, 5149, 5421, - 5422, 5415, 6340, 5418, 5419, 6339, 5433, 5435, 5429, 5431, 5425, 5427, - 5423, 5416, 5417, 5414, 5150, 983097, 983171, 917631, 128473, 9803, - 128367, 127852, 129387, 128758, 11839, 9809, 128199, 128450, 128451, - 8248, 8257, 8453, 66225, 66246, 66211, 66214, 66254, 66218, 66250, 66251, - 66252, 66253, 66229, 66238, 66244, 66227, 66224, 66222, 66223, 66242, - 66243, 66232, 66221, 66247, 66230, 66226, 66239, 66212, 66248, 66256, - 66235, 66208, 66215, 66210, 66220, 66234, 66255, 66240, 66241, 66236, - 66237, 66231, 66209, 66213, 66249, 66233, 66245, 66217, 66219, 66216, - 66228, 127904, 711, 127887, 129690, 983073, 129365, 9936, 128008, 128049, - 128569, 128572, 66888, 66864, 66912, 66882, 66873, 66902, 66889, 66890, - 66911, 66891, 66895, 66901, 66881, 66867, 66870, 66868, 66904, 66866, - 66876, 66910, 66879, 66883, 66897, 66915, 66884, 66878, 66885, 66914, - 66903, 66877, 66896, 66909, 66906, 66908, 66899, 66872, 66913, 66874, - 66871, 66875, 66869, 66893, 66887, 66892, 66907, 66900, 66894, 66905, - 66880, 66898, 66865, 66886, 66927, 9761, 127797, 9963, 8373, 184, 65102, - 65098, 8452, 162, 128328, 9907, 9939, 129681, 69908, 69907, 69913, 69912, - 69899, 69909, 69904, 69914, 69906, 69905, 69911, 69910, 69920, 69921, - 69918, 69917, 69901, 69900, 69898, 69897, 69903, 69902, 69896, 69895, - 69956, 69923, 69916, 69915, 69926, 69919, 69922, 69925, 69959, 69924, - 69891, 69894, 69892, 69893, 69888, 69890, 69889, 69952, 69927, 69957, - 69933, 69935, 69930, 69931, 69932, 69958, 69928, 69929, 69934, 69936, - 69939, 69954, 69953, 69947, 69946, 69949, 69948, 69945, 69944, 69942, - 69951, 69943, 69950, 69955, 69940, 69938, 69937, 43587, 43597, 43596, - 43573, 43572, 43574, 43571, 43590, 43586, 43595, 43588, 43585, 43584, - 43594, 43591, 43593, 43589, 43592, 43530, 43531, 43536, 43538, 43537, - 43543, 43544, 43551, 43552, 43548, 43547, 43546, 43553, 43550, 43549, - 43545, 43542, 43541, 43558, 43559, 43520, 43524, 43533, 43532, 43529, - 43528, 43535, 43534, 43527, 43526, 43540, 43539, 43560, 43556, 43555, - 43557, 43554, 43523, 43521, 43525, 43522, 43612, 43614, 43613, 43615, - 43561, 43568, 43569, 43562, 43563, 43567, 43566, 43565, 43570, 43564, - 43605, 43604, 43607, 43606, 43603, 43602, 43600, 43609, 43601, 43608, - 983058, 983140, 983137, 8256, 128200, 128185, 128201, 128638, 129941, - 10003, 129472, 128227, 5084, 5075, 5077, 5079, 5081, 5082, 5083, 5055, - 5037, 5038, 5039, 5040, 5041, 5042, 5054, 5056, 5057, 5058, 5059, 5060, - 5061, 5069, 5068, 5070, 5071, 5072, 5073, 5074, 5085, 5086, 5087, 5088, - 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5076, 5078, 5080, 5030, - 5032, 5033, 5034, 5035, 5036, 5043, 5044, 5045, 5046, 5047, 5048, 5049, - 5050, 5051, 5052, 5053, 5109, 5062, 5063, 5064, 5065, 5066, 5067, 5097, - 5098, 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5031, - 5024, 5025, 5026, 5027, 5028, 5029, 43948, 43939, 43941, 43943, 43945, - 43946, 43947, 43919, 43901, 43902, 43903, 43904, 43905, 43906, 43918, - 43920, 43921, 43922, 43923, 43924, 43925, 43933, 43932, 43934, 43935, - 43936, 43937, 43938, 43949, 43950, 43951, 43952, 43953, 43954, 43955, - 43956, 43957, 43958, 43959, 43960, 43940, 43942, 43944, 43894, 43896, - 43897, 43898, 43899, 43900, 43907, 43908, 43909, 43910, 43911, 43912, - 43913, 43914, 43915, 43916, 43917, 5117, 43926, 43927, 43928, 43929, - 43930, 43931, 43961, 43962, 43963, 43964, 43965, 43966, 43967, 5112, - 5113, 5114, 5115, 5116, 43895, 43888, 43889, 43890, 43891, 43892, 43893, - 127800, 127826, 127792, 127937, 129490, 128696, 9767, 128063, 128020, - 9911, 69559, 69553, 69567, 69571, 69556, 69564, 69570, 69552, 69568, - 69555, 69560, 69562, 69557, 69561, 69563, 69554, 69566, 69572, 69558, - 69569, 69565, 69578, 69574, 69575, 69577, 69573, 69579, 69576, 129378, - 127851, 127876, 9962, 127910, 9680, 9682, 10690, 10683, 10691, 9684, - 9683, 9685, 9677, 9681, 10677, 10682, 10684, 127246, 8859, 11199, 10687, - 129282, 129280, 129281, 128320, 9938, 127342, 127341, 127277, 8856, - 10808, 9316, 9315, 9318, 9317, 9314, 9313, 9450, 9320, 9312, 9319, - 127247, 8857, 8861, 12905, 12919, 12904, 12918, 12903, 12917, 12926, - 12909, 12923, 12906, 12920, 12896, 12910, 12900, 12914, 12897, 12911, - 12908, 12922, 12901, 12915, 12899, 12913, 12902, 12916, 12907, 12921, - 12898, 12912, 9097, 127343, 10162, 12975, 127569, 12959, 127568, 12963, - 12951, 12962, 12965, 12973, 12943, 12957, 12935, 12950, 12939, 12932, - 12955, 12931, 12964, 12946, 12869, 12871, 12952, 12966, 12967, 12969, - 12942, 12954, 12938, 12976, 12936, 12948, 12868, 12974, 12961, 12970, - 12968, 12953, 12934, 12972, 12956, 12944, 12870, 12947, 12949, 12971, - 12945, 12933, 12958, 12930, 12937, 12929, 12941, 12940, 12960, 12928, - 127275, 127276, 128712, 13033, 13036, 13034, 13037, 13035, 13013, 13016, - 13014, 13017, 13015, 13038, 13041, 13039, 13042, 13040, 13028, 13031, - 13029, 13032, 13030, 13046, 13049, 13047, 13050, 13048, 13018, 13021, - 13019, 13022, 13020, 13023, 13026, 13024, 13027, 13025, 13051, 13053, - 13052, 13054, 13043, 13045, 13044, 13008, 13011, 13009, 13012, 13010, - 12925, 12924, 9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, - 9408, 9409, 9410, 9411, 9412, 9413, 9414, 9415, 9416, 9417, 9418, 9419, - 9420, 9421, 9422, 9423, 9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, - 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441, 9442, 9443, - 9444, 9445, 9446, 9447, 9448, 9449, 10688, 10806, 8854, 12879, 9329, - 9322, 12991, 12876, 9326, 12981, 12875, 12982, 12986, 12985, 12988, - 12987, 12984, 12983, 12990, 12989, 9325, 12878, 9328, 12877, 9327, 9321, - 12872, 12890, 12874, 12891, 12895, 12894, 12978, 12977, 12893, 12892, - 12980, 12979, 9324, 9331, 12873, 12881, 12885, 12884, 12887, 12886, - 12883, 12882, 12889, 12888, 9323, 9330, 10050, 12342, 10679, 10681, 8853, - 8858, 10680, 128981, 9098, 8855, 10686, 10026, 127278, 127245, 8860, - 10678, 10689, 128983, 11198, 94, 10768, 127914, 127961, 127750, 195088, - 195089, 195090, 195091, 195092, 195093, 195094, 195095, 195096, 195097, - 195098, 195099, 195100, 195101, 195072, 195073, 195074, 195075, 195076, - 195077, 195078, 195079, 195080, 195081, 195082, 195083, 195084, 195085, - 195086, 195087, 194560, 194561, 194562, 194563, 194564, 194565, 194566, - 194567, 194568, 194569, 194570, 194571, 194572, 194573, 194574, 194575, - 194576, 194577, 194578, 194579, 194580, 194581, 194582, 194583, 194584, - 194585, 194586, 194587, 194588, 194589, 194590, 194591, 194592, 194593, - 194594, 194595, 194596, 194597, 194598, 194599, 194600, 194601, 194602, - 194603, 194604, 194605, 194606, 194607, 194608, 194609, 194610, 194611, - 194612, 194613, 194614, 194615, 194616, 194617, 194618, 194619, 194620, - 194621, 194622, 194623, 194624, 194625, 194626, 194627, 194628, 194629, - 194630, 194631, 194632, 194633, 194634, 194635, 194636, 194637, 194638, - 194639, 194640, 194641, 194642, 194643, 194644, 194645, 194646, 194647, - 194648, 194649, 194650, 194651, 194652, 194653, 194654, 194655, 194656, - 194657, 194658, 194659, 194660, 194661, 194662, 194663, 194664, 194665, - 194666, 194667, 194668, 194669, 194670, 194671, 194672, 194673, 194674, - 194675, 194676, 194677, 194678, 194679, 194680, 194681, 194682, 194683, - 194684, 194685, 194686, 194687, 194688, 194689, 194690, 194691, 194692, - 194693, 194694, 194695, 194696, 194697, 194698, 194699, 194700, 194701, - 194702, 194703, 194704, 194705, 194706, 194707, 194708, 194709, 194710, - 194711, 194712, 194713, 194714, 194715, 194716, 194717, 194718, 194719, - 194720, 194721, 194722, 194723, 194724, 194725, 194726, 194727, 194728, - 194729, 194730, 194731, 194732, 194733, 194734, 194735, 194736, 194737, - 194738, 194739, 194740, 194741, 194742, 194743, 194744, 194745, 194746, - 194747, 194748, 194749, 194750, 194751, 194752, 194753, 194754, 194755, - 194756, 194757, 194758, 194759, 194760, 194761, 194762, 194763, 194764, - 194765, 194766, 194767, 194768, 194769, 194770, 194771, 194772, 194773, - 194774, 194775, 194776, 194777, 194778, 194779, 194780, 194781, 194782, - 194783, 194784, 194785, 194786, 194787, 194788, 194789, 194790, 194791, - 194792, 194793, 194794, 194795, 194796, 194797, 194798, 194799, 194800, - 194801, 194802, 194803, 194804, 194805, 194806, 194807, 194808, 194809, - 194810, 194811, 194812, 194813, 194814, 194815, 194816, 194817, 194818, - 194819, 194820, 194821, 194822, 194823, 194824, 194825, 194826, 194827, - 194828, 194829, 194830, 194831, 194832, 194833, 194834, 194835, 194836, - 194837, 194838, 194839, 194840, 194841, 194842, 194843, 194844, 194845, - 194846, 194847, 194848, 194849, 194850, 194851, 194852, 194853, 194854, - 194855, 194856, 194857, 194858, 194859, 194860, 194861, 194862, 194863, - 194864, 194865, 194866, 194867, 194868, 194869, 194870, 194871, 194872, - 194873, 194874, 194875, 194876, 194877, 194878, 194879, 194880, 194881, - 194882, 194883, 194884, 194885, 194886, 194887, 194888, 194889, 194890, - 194891, 194892, 194893, 194894, 194895, 194896, 194897, 194898, 194899, - 194900, 194901, 194902, 194903, 194904, 194905, 194906, 194907, 194908, - 194909, 194910, 194911, 194912, 194913, 194914, 194915, 194916, 194917, - 194918, 194919, 194920, 194921, 194922, 194923, 194924, 194925, 194926, - 194927, 194928, 194929, 194930, 194931, 194932, 194933, 194934, 194935, - 194936, 194937, 194938, 194939, 194940, 194941, 194942, 194943, 194944, - 194945, 194946, 194947, 194948, 194949, 194950, 194951, 194952, 194953, - 194954, 194955, 194956, 194957, 194958, 194959, 194960, 194961, 194962, - 194963, 194964, 194965, 194966, 194967, 194968, 194969, 194970, 194971, - 194972, 194973, 194974, 194975, 194976, 194977, 194978, 194979, 194980, - 194981, 194982, 194983, 194984, 194985, 194986, 194987, 194988, 194989, - 194990, 194991, 194992, 194993, 194994, 194995, 194996, 194997, 194998, - 194999, 195000, 195001, 195002, 195003, 195004, 195005, 195006, 195007, - 195008, 195009, 195010, 195011, 195012, 195013, 195014, 195015, 195016, - 195017, 195018, 195019, 195020, 195021, 195022, 195023, 195024, 195025, - 195026, 195027, 195028, 195029, 195030, 195031, 195032, 195033, 195034, - 195035, 195036, 195037, 195038, 195039, 195040, 195041, 195042, 195043, - 195044, 195045, 195046, 195047, 195048, 195049, 195050, 195051, 195052, - 195053, 195054, 195055, 195056, 195057, 195058, 195059, 195060, 195061, - 195062, 195063, 195064, 195065, 195066, 195067, 195068, 195069, 195070, - 195071, 64096, 64097, 64098, 64099, 64100, 64101, 64102, 64103, 64104, - 64105, 64106, 64107, 64108, 64109, 64000, 64001, 64002, 64003, 64004, - 64005, 64006, 64007, 64008, 64009, 64010, 64011, 64012, 64013, 64014, - 64015, 64016, 64017, 64018, 64019, 64020, 64021, 64022, 64023, 64024, - 64025, 64026, 64027, 64028, 64029, 64030, 64031, 64032, 64033, 64034, - 64035, 64036, 64037, 64038, 64039, 64040, 64041, 64042, 64043, 64044, - 64045, 64046, 64047, 64048, 64049, 64050, 64051, 64052, 64053, 64054, - 64055, 64056, 64057, 64058, 64059, 64060, 64061, 64062, 64063, 64064, - 64065, 64066, 64067, 64068, 64069, 64070, 64071, 64072, 64073, 64074, - 64075, 64076, 64077, 64078, 64079, 64080, 64081, 64082, 64083, 64084, - 64085, 64086, 64087, 64088, 64089, 64090, 64091, 64092, 64093, 64094, - 64095, 64112, 64113, 64114, 64115, 64116, 64117, 64118, 64119, 64120, - 64121, 64122, 64123, 64124, 64125, 64126, 64127, 64128, 64129, 64130, - 64131, 64132, 64133, 64134, 64135, 64136, 64137, 64138, 64139, 64140, - 64141, 64142, 64143, 64144, 64145, 64146, 64147, 64148, 64149, 64150, - 64151, 64152, 64153, 64154, 64155, 64156, 64157, 64158, 64159, 64160, - 64161, 64162, 64163, 64164, 64165, 64166, 64167, 64168, 64169, 64170, - 64171, 64172, 64173, 64174, 64175, 64176, 64177, 64178, 64179, 64180, - 64181, 64182, 64183, 64184, 64185, 64186, 64187, 64188, 64189, 64190, - 64191, 64192, 64193, 64194, 64195, 64196, 64197, 64198, 64199, 64200, - 64201, 64202, 64203, 64204, 64205, 64206, 64207, 64208, 64209, 64210, - 64211, 64212, 64213, 64214, 64215, 64216, 64217, 63744, 63745, 63746, - 63747, 63748, 63749, 63750, 63751, 63752, 63753, 63754, 63755, 63756, - 63757, 63758, 63759, 63760, 63761, 63762, 63763, 63764, 63765, 63766, - 63767, 63768, 63769, 63770, 63771, 63772, 63773, 63774, 63775, 63776, - 63777, 63778, 63779, 63780, 63781, 63782, 63783, 63784, 63785, 63786, - 63787, 63788, 63789, 63790, 63791, 63792, 63793, 63794, 63795, 63796, - 63797, 63798, 63799, 63800, 63801, 63802, 63803, 63804, 63805, 63806, - 63807, 63808, 63809, 63810, 63811, 63812, 63813, 63814, 63815, 63816, - 63817, 63818, 63819, 63820, 63821, 63822, 63823, 63824, 63825, 63826, - 63827, 63828, 63829, 63830, 63831, 63832, 63833, 63834, 63835, 63836, - 63837, 63838, 63839, 63840, 63841, 63842, 63843, 63844, 63845, 63846, - 63847, 63848, 63849, 63850, 63851, 63852, 63853, 63854, 63855, 63856, - 63857, 63858, 63859, 63860, 63861, 63862, 63863, 63864, 63865, 63866, - 63867, 63868, 63869, 63870, 63871, 63872, 63873, 63874, 63875, 63876, - 63877, 63878, 63879, 63880, 63881, 63882, 63883, 63884, 63885, 63886, - 63887, 63888, 63889, 63890, 63891, 63892, 63893, 63894, 63895, 63896, - 63897, 63898, 63899, 63900, 63901, 63902, 63903, 63904, 63905, 63906, - 63907, 63908, 63909, 63910, 63911, 63912, 63913, 63914, 63915, 63916, - 63917, 63918, 63919, 63920, 63921, 63922, 63923, 63924, 63925, 63926, - 63927, 63928, 63929, 63930, 63931, 63932, 63933, 63934, 63935, 63936, - 63937, 63938, 63939, 63940, 63941, 63942, 63943, 63944, 63945, 63946, - 63947, 63948, 63949, 63950, 63951, 63952, 63953, 63954, 63955, 63956, - 63957, 63958, 63959, 63960, 63961, 63962, 63963, 63964, 63965, 63966, - 63967, 63968, 63969, 63970, 63971, 63972, 63973, 63974, 63975, 63976, - 63977, 63978, 63979, 63980, 63981, 63982, 63983, 63984, 63985, 63986, - 63987, 63988, 63989, 63990, 63991, 63992, 63993, 63994, 63995, 63996, - 63997, 63998, 63999, 11946, 12003, 11910, 11963, 11962, 11950, 11992, - 12012, 12000, 12005, 11996, 12010, 11984, 11988, 11994, 11987, 11952, - 12007, 11977, 11976, 11973, 12019, 11993, 12014, 11995, 12016, 12006, - 12002, 11979, 11936, 11983, 11905, 11970, 11943, 11931, 11914, 11934, - 11944, 11999, 11998, 11997, 11960, 11947, 11939, 11978, 11968, 11967, - 11966, 12004, 11927, 11926, 12001, 11975, 11928, 12018, 12013, 12015, - 12011, 11945, 11986, 11985, 11921, 11920, 11919, 11918, 11964, 11957, - 11990, 11989, 11935, 11965, 11933, 11941, 11940, 11909, 11991, 11959, - 11929, 11904, 11908, 11907, 11906, 11915, 11942, 11974, 11980, 12008, - 12009, 11951, 11925, 11924, 11922, 11949, 11948, 11917, 11916, 11958, - 11932, 12017, 11911, 11923, 11969, 11982, 11981, 11938, 11937, 11972, - 11971, 11956, 11955, 11954, 11953, 11913, 11912, 11961, 12752, 12743, - 12748, 12768, 12772, 12757, 12741, 12750, 12769, 12747, 12749, 12744, - 12742, 12746, 12758, 12754, 12763, 12770, 12764, 12753, 12740, 12767, - 12760, 12759, 12745, 12773, 12766, 12762, 12755, 12761, 12736, 12765, - 12739, 12737, 12738, 12756, 12751, 12771, 128079, 127916, 127963, 128385, - 129346, 127867, 128203, 128346, 128358, 128343, 128355, 128340, 128352, - 128339, 128351, 128344, 128356, 128336, 128348, 128342, 128354, 128341, - 128353, 128345, 128357, 128347, 128359, 128337, 128349, 128338, 128350, - 10561, 8754, 128259, 10227, 128472, 128257, 128258, 8631, 11118, 8635, - 8753, 10959, 10961, 10960, 10962, 127746, 10828, 10832, 128234, 128235, - 128272, 128213, 10829, 8272, 9729, 127786, 127785, 127784, 127783, - 129313, 9114, 129715, 127864, 129381, 58, 8788, 8353, 128165, 7625, 7623, - 769, 791, 833, 8410, 8404, 8423, 857, 8432, 7677, 844, 774, 7627, 814, - 810, 838, 70459, 780, 812, 784, 8409, 8405, 787, 789, 806, 65062, 65069, - 42609, 1160, 11774, 11744, 11768, 11747, 11757, 11765, 42654, 11751, - 11752, 11753, 11756, 42613, 11775, 11772, 42655, 11767, 11754, 42619, - 11763, 11762, 42618, 42615, 42612, 42617, 11770, 42614, 11771, 11773, - 11769, 11759, 42616, 11760, 11758, 11748, 11749, 11761, 11746, 11764, - 11755, 11745, 11750, 11766, 42621, 1156, 1158, 1159, 1157, 42608, 42610, - 1155, 65070, 65071, 1161, 42620, 123023, 42607, 770, 813, 807, 43248, - 43244, 43245, 43246, 43247, 43242, 43243, 43249, 43237, 43236, 43239, - 43238, 43235, 43234, 43232, 43241, 43233, 43240, 7675, 776, 6833, 804, - 775, 7672, 856, 803, 7674, 7617, 7616, 861, 860, 865, 7676, 862, 863, - 6840, 831, 6858, 6857, 6844, 866, 858, 864, 65058, 65059, 8422, 840, 782, - 779, 783, 819, 7629, 6832, 798, 6835, 8413, 8416, 8418, 8414, 8419, 8420, - 8415, 839, 850, 8412, 122892, 122884, 122891, 122890, 122921, 122919, - 122889, 122916, 122900, 122907, 122910, 122901, 122908, 122880, 122920, - 122881, 122909, 122903, 122922, 122883, 122895, 122894, 122896, 122898, - 122899, 122882, 122885, 122912, 122911, 122913, 122918, 122915, 122888, - 122886, 122904, 122902, 122897, 122893, 70508, 70507, 70506, 70505, - 70504, 70502, 70503, 70515, 70513, 70514, 70516, 70512, 768, 790, 832, - 7624, 7621, 847, 119363, 119362, 119364, 835, 834, 837, 836, 777, 843, - 795, 785, 815, 826, 811, 6855, 6834, 7632, 12442, 12441, 7671, 7670, - 7643, 7646, 7647, 7649, 7650, 867, 7666, 7655, 7636, 7637, 7638, 872, - 7639, 868, 7663, 7641, 7659, 7635, 869, 7640, 6860, 6861, 6862, 7645, - 7660, 7653, 870, 7667, 7661, 871, 7668, 7664, 876, 7651, 7626, 877, 6848, - 7652, 7658, 7656, 7657, 7665, 6847, 873, 7642, 874, 7644, 875, 7648, - 7662, 878, 879, 7654, 852, 7678, 8430, 8406, 841, 794, 6849, 6851, 796, - 849, 8400, 792, 845, 8417, 8429, 8426, 65056, 65063, 65057, 65064, 6841, - 8427, 824, 822, 8402, 818, 772, 65060, 65067, 65061, 65068, 817, 7622, - 7620, 7628, 800, 6854, 842, 66424, 66425, 66423, 66426, 66422, 6839, 808, - 7630, 773, 6846, 6845, 6843, 801, 799, 6856, 8421, 788, 802, 7679, 854, - 848, 853, 8431, 8407, 825, 855, 8401, 6850, 6852, 793, 8428, 8408, 805, - 778, 7631, 859, 823, 821, 8403, 6853, 827, 6842, 7619, 7618, 828, 8411, - 771, 65065, 65066, 820, 816, 6859, 8424, 6836, 786, 846, 797, 7669, 7633, - 7634, 809, 781, 830, 7673, 8425, 6838, 6837, 851, 829, 8274, 64, 44, + 64975, 65008, 65017, 64464, 64838, 64972, 64844, 65018, 64860, 64686, + 64541, 64821, 64817, 64744, 64862, 64861, 64685, 64540, 64820, 64936, + 64966, 64687, 64542, 64822, 64864, 64863, 64865, 64867, 64866, 64688, + 64543, 64743, 64791, 64763, 64810, 64782, 64792, 64764, 64606, 64609, + 64755, 64607, 64610, 64756, 64611, 64608, 64754, 64818, 64746, 64872, + 64871, 64938, 64806, 64814, 64778, 64824, 64873, 64805, 64813, 64777, + 64823, 64875, 64874, 64877, 64876, 64808, 64816, 64780, 64745, 64793, + 64765, 64807, 64815, 64779, 64825, 64809, 64781, 64794, 64766, 65022, + 64846, 64882, 64881, 64883, 64884, 64819, 64551, 64826, 64785, 64757, + 64696, 64550, 64786, 64758, 64851, 64850, 64849, 64674, 64524, 64677, + 64740, 64930, 64852, 64929, 64675, 64525, 64928, 64848, 64927, 64673, + 64523, 64932, 64853, 64855, 64854, 64931, 64626, 64676, 64526, 64739, + 64628, 64527, 64627, 64625, 64624, 64629, 64528, 64603, 64529, 64634, + 64531, 64632, 64678, 64530, 64741, 64633, 64631, 64630, 64635, 64532, + 64742, 65016, 64661, 64601, 64616, 64515, 64491, 64490, 64493, 64492, + 64503, 64504, 64502, 64667, 64736, 64664, 64513, 64663, 64512, 64665, + 64614, 64666, 64514, 64735, 64615, 64499, 64498, 64495, 64494, 64617, + 64516, 64501, 64500, 64613, 64612, 64497, 64496, 64942, 64731, 64598, + 64734, 64753, 64660, 64658, 64943, 64730, 64597, 64732, 64599, 64925, + 64924, 64944, 64659, 64733, 64600, 64752, 64657, 64662, 64602, 64506, + 64507, 64505, 64697, 64552, 64827, 2204, 1619, 1624, 2303, 126492, + 126494, 126493, 126495, 126644, 126638, 126641, 126647, 126648, 126646, + 126632, 126645, 126630, 126650, 126626, 126636, 126625, 126640, 126643, + 126633, 126631, 126651, 126637, 126635, 126649, 126627, 126642, 126639, + 126629, 126489, 126467, 126518, 126517, 126516, 126510, 126513, 126503, + 126500, 126519, 126506, 126498, 126508, 126497, 126512, 126505, 126523, + 126509, 126507, 126514, 126511, 126521, 126612, 126606, 126609, 126615, + 126592, 126607, 126599, 126596, 126616, 126614, 126600, 126613, 126598, + 126618, 126594, 126604, 126593, 126608, 126611, 126601, 126619, 126605, + 126603, 126617, 126595, 126610, 126597, 126475, 126704, 126705, 126588, + 126590, 126585, 126582, 126568, 126581, 126580, 126574, 126577, 126567, + 126564, 126583, 126570, 126562, 126572, 126561, 126576, 126569, 126586, + 126587, 126573, 126578, 126575, 126484, 126478, 126481, 126557, 126559, + 126553, 126548, 126542, 126545, 126551, 126530, 126537, 126535, 126555, + 126541, 126539, 126546, 126543, 126472, 126488, 126486, 126485, 126464, + 126479, 126487, 126474, 126470, 126490, 126466, 126476, 126465, 126480, + 126483, 126473, 126471, 126491, 126477, 126482, 126469, 1541, 1536, 2290, + 2289, 2288, 1642, 2199, 1550, 2192, 1769, 2193, 2184, 1544, 1629, 2296, + 2301, 2298, 1772, 1623, 983633, 983635, 983640, 983634, 983638, 983636, + 983639, 983637, 983641, 1563, 1617, 65148, 65149, 1554, 1555, 1552, 1537, + 1539, 1540, 1790, 1789, 1553, 1551, 1556, 2249, 1560, 1761, 2250, 2272, + 1558, 983202, 1751, 1750, 1753, 1752, 1762, 1764, 2273, 1756, 2261, 1755, + 1557, 2200, 2260, 2266, 2268, 2267, 2269, 2252, 2271, 2270, 2291, 1767, + 2251, 1768, 2264, 1760, 1759, 1559, 2253, 1754, 2263, 2262, 1766, 69317, + 69371, 2265, 2202, 2201, 69375, 2203, 69373, 69374, 2259, 1773, 1763, + 1562, 1561, 1765, 1622, 1618, 65150, 65151, 2256, 2205, 64444, 64435, + 64434, 64441, 64440, 64439, 64438, 64446, 64445, 64437, 64436, 64449, + 64448, 64443, 64442, 64450, 64447, 1758, 1600, 2179, 2180, 65137, 2181, + 65139, 2285, 2282, 2286, 2283, 2287, 2284, 1566, 2275, 1644, 1627, 1626, + 1628, 2190, 1631, 1567, 1625, 1545, 1546, 1542, 1543, 1637, 1636, 1639, + 1638, 1635, 1634, 1632, 1641, 1633, 1640, 1375, 1370, 1359, 1337, 1349, + 1362, 1347, 1353, 1342, 1361, 1360, 1356, 1333, 1335, 1336, 1346, 1331, + 1355, 1345, 1364, 1343, 1363, 1354, 1351, 1357, 1329, 1358, 1352, 1340, + 1366, 1341, 1339, 1330, 1348, 1350, 1338, 1334, 1344, 1332, 1365, 1373, + 1372, 1371, 1395, 1401, 1390, 1409, 1408, 1404, 1381, 1383, 1384, 1394, + 1379, 1403, 1393, 1412, 1391, 1411, 1402, 1399, 1405, 1376, 1407, 1385, + 1377, 1406, 1400, 1397, 1416, 1410, 1388, 1414, 1389, 1387, 1378, 1396, + 1398, 1386, 1382, 1392, 1380, 1413, 1415, 64279, 64277, 64275, 64276, + 64278, 1369, 1418, 1423, 1417, 1374, 129201, 10549, 10548, 129200, 10550, + 10551, 129968, 128667, 127912, 9800, 8978, 9738, 65948, 42, 8727, 8258, + 128562, 118477, 9954, 11225, 128888, 8771, 8870, 128095, 9883, 128663, + 127975, 128762, 8371, 127814, 68352, 68353, 68357, 68355, 68358, 68359, + 68356, 68354, 68373, 68374, 68372, 68393, 68405, 68388, 68387, 68386, + 68391, 68390, 68389, 68371, 68370, 68369, 68403, 68401, 68404, 68399, + 68394, 68395, 68378, 68381, 68377, 68366, 68367, 68362, 68363, 68364, + 68365, 68385, 68384, 68380, 68379, 68402, 68400, 68360, 68361, 68375, + 68383, 68376, 68368, 68398, 68392, 68382, 68397, 68396, 68409, 129361, + 8525, 1547, 129518, 9810, 129683, 128118, 128036, 127868, 128124, 128700, + 128281, 128386, 11101, 11099, 983056, 10155, 128043, 129363, 127992, + 129441, 129366, 129391, 128708, 7007, 7005, 7006, 6991, 6990, 6917, 6918, + 6987, 6988, 6928, 6953, 6954, 6936, 6937, 6948, 6944, 6943, 6949, 6984, + 6927, 6933, 6934, 6919, 6920, 6929, 6930, 6921, 6922, 6938, 6939, 6931, + 6981, 6932, 6982, 6958, 6925, 6926, 6950, 6945, 6935, 6940, 6951, 6952, + 6957, 6923, 6924, 6962, 6960, 6961, 6946, 6942, 6941, 6947, 6983, 6985, + 6986, 6963, 6955, 6959, 6956, 7022, 7025, 7021, 7024, 7023, 7026, 7020, + 7019, 7027, 7012, 7013, 7018, 7015, 7017, 7016, 7010, 7014, 7009, 7011, + 7032, 7036, 7033, 7034, 7035, 7031, 7030, 7029, 7028, 7003, 7038, 7008, + 7002, 7037, 7039, 6915, 6913, 6912, 6914, 6916, 6964, 6972, 6973, 6970, + 6971, 6968, 6969, 6974, 6975, 6977, 6976, 6965, 6978, 6979, 6966, 6967, + 6980, 7004, 6997, 6996, 6999, 6998, 6995, 6994, 6992, 7001, 6993, 7000, + 127880, 10057, 9744, 128503, 128505, 128499, 128501, 11197, 9745, 9746, + 128502, 128500, 10007, 129526, 129648, 42737, 42736, 42741, 42740, 42733, + 42699, 42713, 42712, 42692, 42706, 42683, 42719, 42734, 42735, 42682, + 42729, 42657, 42725, 42659, 42670, 42718, 42666, 42716, 42701, 42675, + 42671, 42722, 42720, 42727, 42723, 42702, 42726, 42677, 42707, 42708, + 42709, 42686, 42694, 42674, 42731, 42695, 42685, 42684, 42691, 42673, + 42664, 42715, 42703, 92193, 92188, 92161, 92199, 92240, 92179, 92211, + 92219, 92213, 92243, 92207, 92216, 92183, 92184, 92238, 92171, 983268, + 92174, 92203, 92186, 92210, 92230, 92175, 92221, 92232, 92246, 92198, + 92214, 92190, 92176, 92197, 92196, 92164, 92245, 92212, 92201, 92160, + 92182, 92173, 92229, 92227, 92180, 92237, 92241, 92223, 92185, 92194, + 92178, 92239, 92225, 92233, 92167, 92191, 92231, 92244, 92204, 92226, + 92236, 92200, 92189, 92187, 92162, 92163, 92169, 92170, 92202, 92205, + 92222, 92168, 92165, 92215, 92224, 92208, 92220, 92235, 92177, 92181, + 92195, 92234, 92209, 92166, 92172, 92206, 92192, 92228, 92217, 92242, + 92218, 92262, 92271, 92272, 92270, 92294, 92253, 92301, 92256, 92273, + 92259, 92251, 92297, 92300, 92296, 92295, 92255, 92252, 92292, 92286, + 92268, 92290, 92281, 92267, 92284, 92287, 92282, 92283, 92277, 92298, + 983270, 92276, 92302, 92247, 92299, 92288, 92269, 92260, 92261, 983269, + 92289, 92257, 92274, 92263, 92279, 92265, 92266, 92250, 92249, 92285, + 92248, 92264, 92280, 92258, 92254, 92278, 92291, 92293, 92275, 92310, + 92320, 92312, 92394, 92393, 92319, 92384, 92321, 92386, 92361, 92373, + 92366, 92328, 92329, 92357, 92342, 92397, 92365, 92376, 92339, 92382, + 92363, 92318, 92387, 92383, 92315, 92385, 92354, 92311, 92381, 92343, + 92326, 92364, 92324, 92391, 92344, 92390, 92338, 92396, 92308, 92349, + 92375, 92378, 92317, 92331, 92362, 92336, 92341, 92370, 92347, 92307, + 92303, 92309, 92395, 92368, 92356, 92367, 92360, 92389, 92333, 92359, + 92374, 92351, 92325, 92371, 92350, 92345, 92372, 92314, 92340, 92323, + 92304, 92313, 92316, 92398, 92399, 92380, 92330, 983271, 92379, 92392, + 92335, 92332, 92346, 92400, 92358, 92334, 92353, 92337, 92306, 92369, + 92388, 92322, 92305, 92327, 92377, 92352, 92348, 92355, 92436, 92517, + 92488, 92434, 92415, 92431, 92454, 92460, 92420, 92489, 92422, 92474, + 92479, 92449, 92502, 92439, 92484, 92495, 92464, 92511, 92406, 92446, + 92497, 92426, 92482, 92448, 92515, 92401, 92478, 92427, 92496, 92458, + 92424, 92445, 92404, 92466, 92444, 92438, 92442, 92441, 92510, 92499, + 92425, 92437, 92440, 92471, 92465, 92409, 92483, 92475, 92467, 92485, + 92457, 92432, 92476, 92435, 92412, 92414, 92430, 92407, 92403, 92405, + 92487, 92418, 92486, 92408, 92447, 92459, 92480, 92472, 92505, 92514, + 92450, 92463, 92410, 92493, 92507, 92503, 92462, 92506, 92443, 92509, + 92469, 92461, 92490, 92512, 92494, 92455, 92417, 92501, 92413, 92508, + 92500, 92504, 92473, 92419, 92498, 92423, 92516, 92428, 92452, 92451, + 92481, 92416, 92456, 92433, 92477, 92492, 92491, 92513, 92411, 92402, + 92421, 92453, 92468, 92470, 92429, 92661, 92626, 92616, 92596, 92612, + 92603, 92673, 92651, 92627, 92597, 92585, 92578, 92615, 92565, 92552, + 92602, 92674, 92570, 92646, 92599, 92532, 92587, 92538, 92620, 92670, + 92665, 92575, 92521, 92633, 92595, 92523, 92556, 92539, 92664, 92653, + 92667, 92600, 92542, 92555, 92668, 92520, 92582, 92591, 92581, 92551, + 92654, 92611, 92614, 92666, 92671, 92617, 92637, 92562, 92518, 92592, + 92558, 92528, 92607, 92535, 92557, 92563, 92550, 92624, 983272, 92640, + 92657, 92531, 92601, 92553, 92543, 92619, 92598, 92541, 92544, 92579, + 92658, 92554, 92628, 92648, 92547, 92527, 92545, 92540, 92604, 92622, + 92589, 92608, 92583, 92609, 92662, 92613, 92584, 92625, 92634, 92524, + 92536, 92605, 92647, 92548, 92663, 92593, 92621, 92568, 92610, 92576, + 92529, 92618, 92649, 92561, 92656, 92526, 92655, 92546, 92534, 92560, + 92580, 92659, 92660, 92638, 92571, 92525, 92549, 92559, 92635, 92577, + 92530, 92636, 92669, 92572, 92672, 92537, 92519, 92630, 92586, 92569, + 92566, 92573, 92652, 92522, 92574, 92650, 92533, 92567, 92623, 92606, + 92639, 92564, 92590, 92642, 92643, 92594, 92641, 92645, 92644, 92588, + 92629, 92632, 92631, 92710, 92695, 92694, 92726, 92675, 92719, 92677, + 92718, 92682, 92717, 92689, 92720, 92724, 92685, 92722, 92723, 92711, + 92712, 92698, 92688, 92697, 92696, 92702, 92687, 92704, 92681, 92708, + 92703, 92706, 92714, 92709, 92679, 92721, 92684, 92683, 92707, 92691, + 92713, 92700, 92693, 92727, 92690, 92692, 92686, 92680, 92725, 92699, + 92701, 92705, 92716, 92728, 92678, 92715, 92676, 42693, 42698, 42711, + 42696, 42667, 42717, 42704, 42661, 42721, 42669, 42668, 42705, 42700, + 42680, 42678, 42710, 42688, 42681, 42732, 42676, 42679, 42730, 42728, + 42672, 42662, 42724, 42687, 42689, 42690, 42697, 42714, 42660, 42656, + 42665, 42663, 42658, 42738, 42742, 42739, 42743, 127974, 128183, 128180, + 128182, 128181, 127820, 129685, 128202, 129532, 128136, 129530, 127936, + 92916, 92912, 92915, 92913, 92914, 92887, 92894, 92908, 92880, 92907, + 92893, 92886, 92888, 92881, 92906, 92896, 92891, 92902, 92900, 92885, + 92890, 92884, 92904, 92905, 92899, 92889, 92897, 92892, 92895, 92882, + 92898, 92883, 92901, 92903, 92909, 92917, 9918, 129415, 7152, 7153, 7124, + 7108, 7114, 7130, 7139, 7127, 7138, 7133, 7136, 7113, 7111, 7117, 7119, + 7107, 7135, 7125, 7112, 7123, 7129, 7116, 7132, 7105, 7126, 7128, 7110, + 7109, 7137, 7121, 7118, 7106, 7120, 7134, 7122, 7115, 7131, 7104, 7140, + 7141, 7154, 7155, 7167, 7165, 7166, 7164, 7142, 7150, 7151, 7144, 7147, + 7149, 7143, 7145, 7146, 7148, 128704, 128705, 128267, 127900, 127901, + 9835, 9836, 129492, 128059, 127958, 128147, 129451, 129752, 127866, + 129714, 983055, 128276, 129745, 128277, 9086, 128718, 118478, 2557, 2432, + 2519, 2548, 2552, 2551, 2550, 2549, 2553, 2454, 2510, 983661, 2453, 2480, + 2545, 2544, 2525, 2524, 2556, 2443, 2528, 2444, 2529, 2527, 2479, 2437, + 2438, 2448, 2452, 2466, 2465, 2471, 2470, 2464, 2463, 2469, 2468, 2441, + 2442, 2439, 2440, 2457, 2467, 2462, 2472, 2486, 2487, 2488, 2477, 2476, + 2459, 2458, 2456, 2455, 2461, 2460, 2475, 2474, 2489, 2482, 2478, 2447, + 2451, 2547, 2546, 983651, 983650, 983652, 2558, 2433, 2492, 2493, 2434, + 2509, 2435, 2554, 2494, 2504, 2508, 2497, 2498, 2499, 2500, 2530, 2531, + 2495, 2496, 2503, 2507, 2539, 2538, 2541, 2540, 2537, 2536, 2534, 2543, + 2535, 2542, 2555, 11102, 127857, 9004, 9187, 93856, 93880, 93858, 93864, + 93873, 93874, 93859, 93861, 93869, 93868, 93870, 93876, 93875, 93867, + 93862, 93865, 93877, 93857, 93879, 93860, 93866, 93871, 93872, 93878, + 93863, 93883, 93907, 93885, 93891, 93900, 93901, 93886, 93888, 93896, + 93895, 93897, 93903, 93902, 93894, 93889, 93892, 93904, 93884, 93906, + 93887, 93893, 93898, 93899, 93905, 93890, 8812, 8502, 8757, 129475, + 128719, 72710, 72711, 72712, 72746, 72704, 72705, 72715, 72717, 72731, + 72730, 72736, 72735, 72729, 72728, 72734, 72733, 72708, 72709, 72706, + 72707, 72722, 72732, 72727, 72737, 72747, 72748, 72749, 72741, 72740, + 72724, 72723, 72721, 72720, 72726, 72725, 72719, 72718, 72739, 72738, + 72750, 72745, 72742, 72744, 72743, 72714, 72716, 72801, 72810, 72806, + 72797, 72807, 72798, 72802, 72811, 72800, 72809, 72799, 72808, 72796, + 72805, 72804, 72795, 72803, 72794, 72764, 72768, 72765, 72767, 72766, + 72756, 72757, 72758, 72751, 72761, 72763, 72754, 72755, 72752, 72753, + 72760, 72762, 72770, 72769, 72789, 72788, 72791, 72790, 72787, 72786, + 72784, 72793, 72785, 72792, 72771, 72772, 72773, 72812, 128692, 128690, + 10745, 10744, 129506, 127921, 127874, 128038, 8383, 129766, 9763, 128089, + 129452, 9679, 9864, 10733, 9865, 9210, 11176, 11177, 11178, 11179, 11180, + 11182, 11181, 11183, 9960, 10028, 129623, 9821, 129554, 129596, 129609, + 129612, 129622, 9818, 129551, 129593, 9822, 129543, 129564, 129585, + 129597, 129606, 129555, 129619, 129617, 129618, 9823, 129556, 129598, + 9819, 129552, 129594, 9820, 129553, 129595, 129575, 129572, 129576, + 129577, 129573, 129574, 9827, 9670, 11201, 10070, 10730, 11230, 9830, + 128419, 128899, 9196, 9662, 9660, 11167, 127778, 9922, 9923, 10047, 9873, + 10022, 128447, 128420, 9829, 11042, 128426, 11052, 10711, 11044, 117867, + 117870, 117869, 117868, 11035, 9194, 9198, 128896, 9668, 9666, 9664, + 11164, 8268, 9944, 128412, 9754, 9699, 9698, 10731, 9207, 11206, 11045, + 9204, 11207, 11047, 9205, 11208, 9206, 11205, 128921, 128927, 9726, 9724, + 9912, 117871, 10002, 128392, 9648, 11039, 127986, 118451, 128413, 9755, + 9193, 9197, 9654, 9199, 128898, 11091, 9658, 9656, 10145, 10148, 11166, + 8269, 127990, 9644, 11049, 11050, 11089, 9642, 129997, 9787, 9632, 11200, + 9209, 128306, 9728, 128369, 9927, 9984, 128900, 128909, 9986, 9751, 9824, + 9733, 128919, 128925, 128908, 9951, 128383, 9742, 9942, 128418, 128897, + 9195, 9652, 9650, 9700, 9701, 11165, 9851, 9646, 11054, 128920, 128926, + 11037, 11204, 10707, 10067, 8493, 8460, 8465, 8476, 8488, 10164, 10166, + 10165, 9250, 118018, 118039, 118128, 118187, 118218, 118159, 118054, + 118112, 118234, 118084, 118202, 118143, 118031, 118062, 118120, 118240, + 118179, 118090, 118210, 118151, 118047, 118104, 118226, 118165, 118076, + 118194, 118135, 118021, 118035, 118066, 118124, 118243, 118183, 118093, + 118214, 118155, 118050, 118108, 118230, 118168, 118080, 118198, 118139, + 118028, 118058, 118116, 118237, 118175, 118087, 118206, 118147, 118043, + 118100, 118222, 118162, 118072, 118190, 118131, 118029, 118060, 118118, + 118177, 118208, 118149, 118045, 118102, 118224, 118023, 118037, 118068, + 118126, 118244, 118185, 118095, 118216, 118157, 118052, 118110, 118232, + 118170, 118082, 118200, 118141, 118074, 118192, 118133, 118020, 118033, + 118064, 118122, 118242, 118181, 118092, 118212, 118153, 118048, 118106, + 118228, 118167, 118078, 118196, 118137, 118026, 118056, 118114, 118235, + 118173, 118085, 118204, 118145, 118041, 118098, 118220, 118160, 118070, + 118188, 118129, 118034, 118065, 118123, 118182, 118213, 118154, 118049, + 118107, 118229, 118079, 118197, 118138, 118017, 118024, 118038, 118069, + 118127, 118245, 118186, 118096, 118217, 118158, 118053, 118111, 118233, + 118171, 118083, 118201, 118142, 118030, 118061, 118119, 118239, 118178, + 118089, 118209, 118150, 118046, 118103, 118225, 118164, 118075, 118193, + 118134, 118027, 118057, 118115, 118236, 118174, 118086, 118205, 118146, + 118042, 118099, 118221, 118161, 118071, 118189, 118130, 118025, 118055, + 118113, 118172, 118203, 118144, 118040, 118097, 118219, 118016, 118022, + 118036, 118067, 118125, 118184, 118094, 118215, 118156, 118051, 118109, + 118231, 118169, 118081, 118199, 118140, 118059, 118117, 118238, 118176, + 118088, 118207, 118148, 118044, 118101, 118223, 118163, 118073, 118191, + 118132, 118019, 118105, 118227, 118166, 118032, 118063, 118121, 118241, + 118180, 118091, 118211, 118152, 118077, 118195, 118136, 129792, 129794, + 129798, 129806, 129821, 129836, 129813, 129844, 129829, 129802, 129817, + 129848, 129832, 129810, 129840, 129825, 129796, 129804, 129819, 129850, + 129834, 129842, 129827, 129800, 129815, 129846, 129831, 129808, 129838, + 129823, 129793, 129801, 129816, 129847, 129797, 129805, 129820, 129851, + 129835, 129812, 129843, 129828, 129809, 129839, 129824, 129795, 129803, + 129818, 129849, 129833, 129811, 129841, 129826, 129799, 129814, 129845, + 129830, 129807, 129837, 129822, 127804, 128033, 128216, 128153, 129744, + 128939, 128951, 128957, 128945, 128902, 128912, 128932, 128366, 128278, + 128209, 128218, 129667, 12731, 12727, 12726, 12724, 12725, 12570, 12574, + 12718, 12576, 12719, 12578, 12580, 12713, 12735, 12720, 12584, 12715, + 12572, 12579, 12581, 12709, 12708, 12573, 12575, 12582, 12557, 12728, + 12588, 12707, 12732, 12583, 12714, 12723, 12589, 12716, 12712, 12585, + 12555, 12587, 12717, 12591, 12571, 12722, 12711, 12590, 12734, 12721, + 12710, 12577, 12567, 12563, 12705, 12730, 12558, 12733, 12568, 12564, + 12556, 12729, 12569, 12565, 12549, 12704, 12560, 12706, 12553, 12552, + 12559, 12551, 12550, 12561, 12566, 12554, 12586, 12562, 118257, 118258, + 118259, 118260, 117854, 11867, 117853, 118253, 118255, 11868, 117855, + 118249, 118251, 118247, 11211, 8993, 130029, 8990, 8973, 11812, 8991, + 8972, 11813, 130030, 9141, 9142, 10555, 9183, 9181, 130026, 130018, 9185, + 127870, 128144, 127893, 128335, 129379, 127923, 8904, 10705, 10706, + 127993, 118282, 117792, 117791, 118281, 9574, 9559, 9556, 9577, 9565, + 9562, 9553, 9580, 9571, 9568, 9552, 9511, 9490, 9503, 9486, 9537, 9520, + 9513, 9489, 9505, 9485, 9543, 9519, 9558, 9555, 9573, 9557, 9554, 9572, + 9592, 9598, 9593, 9599, 9499, 9531, 9495, 9475, 9547, 9515, 9507, 9595, + 9523, 9491, 9487, 9551, 9549, 9483, 9481, 9479, 9477, 9473, 9594, 9541, + 9525, 9517, 9533, 9530, 9522, 9546, 9539, 9582, 9581, 9583, 9584, 130010, + 130014, 129954, 129958, 130003, 129959, 129964, 129965, 129955, 130000, + 129952, 129956, 129963, 129960, 129953, 129961, 129957, 129962, 130007, + 130005, 130004, 130012, 9586, 130008, 130011, 130002, 130015, 130006, + 9585, 130009, 130001, 130013, 9587, 129966, 9591, 9516, 9488, 9484, 9550, + 9548, 9472, 117787, 117788, 129967, 9588, 9596, 9482, 9480, 9478, 9476, + 117789, 9589, 9597, 9524, 9496, 9492, 9474, 118297, 118295, 118296, + 118294, 9532, 9508, 9500, 117790, 9590, 9542, 9526, 9518, 9534, 9529, + 9521, 9545, 9540, 9536, 9510, 9498, 9502, 9494, 9528, 9544, 9514, 9497, + 9506, 9493, 9527, 9564, 9561, 9576, 9563, 9560, 9575, 9570, 9567, 9579, + 9538, 9512, 9504, 9535, 9509, 9501, 9569, 9566, 9578, 129354, 983263, + 128163, 128102, 128713, 128023, 129460, 69649, 69685, 69749, 69745, + 69746, 69687, 69686, 69637, 69638, 69648, 69650, 69664, 69663, 69669, + 69668, 69662, 69661, 69667, 69666, 69643, 69644, 69645, 69646, 69679, + 69641, 69642, 69639, 69640, 69684, 69678, 69655, 69665, 69660, 69670, + 69680, 69681, 69682, 69674, 69673, 69657, 69656, 69654, 69653, 69659, + 69658, 69652, 69651, 69672, 69671, 69683, 69675, 69677, 69676, 69647, + 69721, 69730, 69726, 69717, 69727, 69718, 69722, 69731, 69720, 69729, + 69719, 69728, 69716, 69725, 69724, 69715, 69723, 69714, 69732, 69733, + 69759, 69709, 69707, 69706, 69705, 69708, 69632, 69744, 69635, 69634, + 69636, 69633, 69700, 69747, 69748, 69689, 69688, 69699, 69701, 69692, + 69693, 69694, 69695, 69696, 69697, 69690, 69691, 69698, 69702, 69704, + 69703, 69739, 69738, 69741, 69740, 69737, 69736, 69734, 69743, 69735, + 69742, 10241, 10243, 10247, 10255, 10271, 10303, 10367, 10495, 10431, + 10335, 10463, 10399, 10287, 10351, 10479, 10415, 10319, 10447, 10383, + 10263, 10295, 10359, 10487, 10423, 10327, 10455, 10391, 10279, 10343, + 10471, 10407, 10311, 10439, 10375, 10251, 10267, 10299, 10363, 10491, + 10427, 10331, 10459, 10395, 10283, 10347, 10475, 10411, 10315, 10443, + 10379, 10259, 10291, 10355, 10483, 10419, 10323, 10451, 10387, 10275, + 10339, 10467, 10403, 10307, 10435, 10371, 10245, 10253, 10269, 10301, + 10365, 10493, 10429, 10333, 10461, 10397, 10285, 10349, 10477, 10413, + 10317, 10445, 10381, 10261, 10293, 10357, 10485, 10421, 10325, 10453, + 10389, 10277, 10341, 10469, 10405, 10309, 10437, 10373, 10249, 10265, + 10297, 10361, 10489, 10425, 10329, 10457, 10393, 10281, 10345, 10473, + 10409, 10313, 10441, 10377, 10257, 10289, 10353, 10481, 10417, 10321, + 10449, 10385, 10273, 10337, 10465, 10401, 10305, 10433, 10369, 10242, + 10246, 10254, 10270, 10302, 10366, 10494, 10430, 10334, 10462, 10398, + 10286, 10350, 10478, 10414, 10318, 10446, 10382, 10262, 10294, 10358, + 10486, 10422, 10326, 10454, 10390, 10278, 10342, 10470, 10406, 10310, + 10438, 10374, 10250, 10266, 10298, 10362, 10490, 10426, 10330, 10458, + 10394, 10282, 10346, 10474, 10410, 10314, 10442, 10378, 10258, 10290, + 10354, 10482, 10418, 10322, 10450, 10386, 10274, 10338, 10466, 10402, + 10306, 10434, 10370, 10244, 10252, 10268, 10300, 10364, 10492, 10428, + 10332, 10460, 10396, 10284, 10348, 10476, 10412, 10316, 10444, 10380, + 10260, 10292, 10356, 10484, 10420, 10324, 10452, 10388, 10276, 10340, + 10468, 10404, 10308, 10436, 10372, 10248, 10264, 10296, 10360, 10488, + 10424, 10328, 10456, 10392, 10280, 10344, 10472, 10408, 10312, 10440, + 10376, 10256, 10288, 10352, 10480, 10416, 10320, 10448, 10384, 10272, + 10336, 10464, 10400, 10304, 10432, 10368, 10240, 129504, 983125, 129329, + 127838, 728, 127753, 128112, 128188, 129650, 129521, 9099, 166, 128148, + 129382, 129294, 129529, 129483, 129767, 128027, 6663, 6662, 6659, 6658, + 6671, 6670, 6667, 6666, 6661, 6668, 6665, 6657, 6678, 6669, 6656, 6674, + 6660, 6673, 6676, 6664, 6675, 6672, 6677, 6683, 6681, 6679, 6682, 6680, + 6687, 6686, 5957, 5960, 5962, 5959, 5956, 5969, 5955, 5966, 5963, 5961, + 5965, 5968, 5958, 5967, 5964, 5952, 5953, 5954, 5970, 5971, 8226, 8729, + 128363, 128364, 9678, 128652, 128101, 128100, 128655, 129480, 129419, + 127959, 127791, 129699, 118939, 118940, 118944, 118943, 118941, 118942, + 118938, 118945, 118882, 118876, 118824, 118835, 118797, 118866, 118957, + 118801, 118802, 118865, 118818, 118916, 118819, 118917, 118899, 118935, + 119018, 119022, 119021, 119020, 119023, 119019, 119017, 118986, 118984, + 118985, 118843, 118887, 118808, 118870, 119003, 119002, 119004, 119005, + 118937, 118991, 118995, 118990, 118992, 118994, 118993, 118930, 118933, + 118931, 118932, 119014, 118918, 118912, 119015, 118785, 118831, 118907, + 118966, 118900, 118880, 118798, 118888, 118884, 118869, 118960, 118959, + 118958, 118836, 118969, 118977, 118978, 118971, 118976, 118975, 118973, + 118970, 118987, 118979, 118980, 118972, 118983, 983278, 118982, 118974, + 118988, 118981, 119000, 119001, 118929, 118928, 118806, 119029, 118927, + 118898, 118964, 118965, 118853, 118968, 118837, 118967, 118936, 118956, + 118810, 118854, 118847, 118839, 118906, 118791, 118800, 119024, 119026, + 118862, 118812, 119025, 119027, 118863, 118811, 118820, 119028, 118911, + 118842, 118850, 118921, 118858, 118913, 118914, 118915, 118834, 118860, + 118868, 118796, 118881, 118922, 118926, 118925, 118924, 118923, 118830, + 118877, 118949, 118947, 118948, 118963, 118955, 118962, 118946, 118961, + 118953, 118952, 118951, 118950, 118954, 118871, 118805, 118855, 118828, + 118901, 118787, 118788, 118856, 118816, 118875, 118845, 118879, 118793, + 118846, 118878, 118814, 118822, 118873, 118859, 118857, 118849, 118840, + 118861, 118786, 118895, 118841, 118874, 118892, 118897, 118807, 118784, + 118821, 118844, 118825, 118889, 119010, 119012, 119013, 119011, 119006, + 119008, 119009, 119007, 118910, 118815, 118852, 119016, 118826, 118885, + 118827, 118803, 118886, 118792, 118813, 118920, 118799, 118833, 118829, + 118904, 118902, 118903, 118905, 118804, 118934, 118919, 118832, 118893, + 118838, 118851, 118883, 118894, 118891, 118896, 118823, 118789, 118790, + 118872, 118817, 118809, 118908, 118909, 118996, 118998, 118997, 118999, + 118989, 118794, 118795, 118867, 118864, 118848, 118890, 983262, 983126, + 983057, 9764, 8454, 129305, 128197, 128247, 128248, 127957, 983098, 5130, + 5131, 5122, 6322, 5148, 5551, 5310, 5382, 5166, 6321, 5759, 5559, 5556, + 5557, 5558, 5567, 5564, 5565, 5566, 5563, 5560, 5561, 5562, 5555, 5552, + 5553, 5554, 5384, 5439, 6387, 6388, 5281, 5264, 6382, 6389, 5203, 5674, + 5675, 5677, 5676, 5673, 5672, 5706, 5707, 5709, 5708, 5705, 5704, 5204, + 5574, 5575, 5577, 5576, 5573, 5572, 6384, 6381, 5620, 6383, 5617, 5618, + 5619, 5616, 5615, 5195, 5592, 5593, 5595, 5594, 5591, 5590, 5174, 5175, + 5129, 5703, 5662, 5663, 5665, 5664, 5661, 5660, 5655, 5656, 6386, 5659, + 5657, 5654, 5652, 5633, 5629, 5630, 5632, 5631, 5628, 5627, 5623, 5624, + 5626, 5625, 5622, 5621, 5636, 5637, 5639, 5329, 5638, 5635, 5634, 5722, + 5718, 5719, 5721, 5720, 5717, 5716, 5712, 5713, 5715, 5714, 5711, 5710, + 5614, 5610, 5611, 5613, 5612, 5609, 5608, 5702, 5698, 5699, 5701, 5700, + 5697, 5696, 5686, 5687, 5689, 5688, 5685, 5684, 5692, 5693, 5695, 5694, + 5691, 5690, 5737, 5738, 5740, 5739, 5736, 5735, 5604, 5605, 5607, 5606, + 5603, 5602, 5598, 5599, 5601, 5600, 5597, 5596, 5725, 5726, 5728, 5727, + 5724, 5723, 5680, 5681, 5683, 5682, 5679, 5678, 5668, 5669, 5671, 5670, + 5667, 5666, 5731, 5732, 5734, 5733, 5730, 5729, 5642, 5643, 5645, 5644, + 5641, 5640, 5580, 5581, 5583, 5582, 5579, 5578, 5586, 5587, 5589, 5588, + 5585, 5584, 5648, 5649, 5651, 5650, 5647, 5646, 5128, 5265, 5258, 5276, + 5278, 5272, 5274, 5268, 5270, 5266, 5741, 5261, 5262, 5259, 5260, 5257, + 5121, 6364, 5163, 5469, 5465, 5466, 5460, 5461, 5158, 5157, 5162, 5155, + 5156, 6367, 6366, 5160, 5152, 5151, 5153, 5154, 5161, 5159, 5462, 5742, + 5463, 5464, 5467, 5459, 5120, 5501, 5123, 5124, 5164, 5251, 5252, 5246, + 5248, 6329, 5242, 5244, 5238, 5240, 5236, 5234, 5235, 5228, 6328, 5231, + 5232, 5229, 5230, 5227, 5354, 5542, 5540, 5541, 5538, 5539, 5536, 5537, + 5338, 5339, 5332, 6333, 5350, 5352, 5346, 5348, 5342, 5344, 5340, 5335, + 5336, 5333, 5334, 5331, 5307, 5283, 5356, 5458, 5287, 5288, 5385, 5290, + 5291, 5284, 6330, 5302, 5304, 5298, 5300, 5294, 5296, 5292, 5285, 5286, + 5309, 5328, 5473, 5475, 5471, 5319, 5391, 5388, 5389, 5386, 5390, 5380, + 5387, 5142, 5147, 5280, 5250, 5306, 5327, 5221, 5437, 72372, 72373, + 72370, 72371, 72368, 72369, 72378, 72379, 72376, 72377, 72374, 72375, + 5320, 5313, 6332, 5525, 5523, 5524, 5518, 5744, 5521, 5522, 5519, 5520, + 5526, 5749, 5750, 5747, 5748, 5745, 5746, 5499, 5497, 5498, 5495, 5496, + 5493, 5494, 5492, 5500, 5316, 5317, 6331, 5323, 5325, 6346, 6348, 6342, + 6344, 5321, 5314, 5315, 5312, 5330, 5509, 5507, 5508, 5502, 5743, 5505, + 5506, 5503, 5504, 5125, 6361, 6347, 6349, 6343, 6345, 6362, 6363, 6359, + 6358, 6360, 6356, 6357, 5165, 5126, 6320, 5193, 5184, 5186, 6326, 5188, + 5190, 5180, 5182, 5178, 5176, 5177, 5168, 6325, 5171, 5172, 6324, 5169, + 5170, 5167, 5456, 6368, 5443, 6355, 5454, 6353, 6354, 6351, 6352, 6350, + 5451, 5452, 5445, 6341, 5448, 5449, 5446, 5447, 5442, 5381, 5364, 6335, + 5570, 6380, 5571, 5568, 5569, 5653, 6385, 5658, 5529, 6379, 6378, 5530, + 5527, 5528, 5441, 5282, 5311, 5365, 5358, 5413, 5405, 5407, 6338, 5409, + 5411, 5401, 5403, 5399, 5395, 5396, 6336, 5397, 5398, 6337, 5393, 5394, + 5392, 5361, 5256, 5253, 5254, 5255, 5362, 6334, 5383, 5376, 5378, 5372, + 5374, 5368, 5370, 5366, 72383, 72380, 72381, 72382, 5359, 5360, 5357, + 5222, 5482, 5550, 5548, 5549, 5546, 5547, 5544, 5545, 5543, 6372, 5480, + 6371, 5478, 5479, 5476, 5477, 5472, 5474, 5470, 5512, 6377, 6376, 5513, + 5510, 5511, 5487, 5486, 6375, 5485, 6374, 6373, 5483, 5484, 5226, 5223, + 5224, 5225, 5205, 5206, 5197, 6327, 5217, 5219, 5213, 5215, 5209, 5211, + 5207, 5491, 5488, 5489, 5490, 5200, 5201, 5198, 5199, 5196, 5132, 5355, + 5351, 5353, 5347, 5349, 5343, 5345, 5341, 5453, 6370, 5450, 6369, 5444, + 5308, 5303, 5305, 5299, 5301, 5295, 5297, 5293, 5194, 5189, 5191, 5185, + 5187, 5181, 5183, 5179, 5440, 5434, 5436, 5430, 5432, 5426, 5428, 5424, + 5324, 5326, 5322, 5457, 5455, 5517, 5514, 5515, 5516, 5410, 5412, 5406, + 5408, 5402, 5404, 5400, 5377, 5379, 5373, 5375, 5369, 5371, 5367, 5277, + 5279, 5273, 5275, 5269, 5271, 5267, 5247, 5249, 5243, 5245, 5239, 5241, + 5237, 5481, 5218, 5220, 5214, 5216, 5210, 5212, 5208, 5468, 5144, 5146, + 5139, 5141, 5135, 5137, 5133, 6365, 5138, 5140, 5535, 5756, 5757, 5754, + 5755, 5752, 5753, 5751, 5534, 5531, 5532, 5533, 5758, 5143, 5145, 6323, + 5134, 5136, 5438, 5192, 5173, 5263, 5233, 5337, 5289, 5318, 5363, 5202, + 5420, 5127, 5149, 5421, 5422, 5415, 6340, 5418, 5419, 6339, 5433, 5435, + 5429, 5431, 5425, 5427, 5423, 5416, 5417, 5414, 5150, 983097, 983171, + 917631, 128473, 9803, 128367, 127852, 129387, 128758, 11839, 9809, + 128199, 128450, 128451, 8248, 8257, 8453, 66225, 66246, 66211, 66214, + 66254, 66218, 66250, 66251, 66252, 66253, 66229, 66238, 66244, 66227, + 66224, 66222, 66223, 66242, 66243, 66232, 66221, 66247, 66230, 66226, + 66239, 66212, 66248, 66256, 66235, 66208, 66215, 66210, 66220, 66234, + 66255, 66240, 66241, 66236, 66237, 66231, 66209, 66213, 66249, 66233, + 66245, 66217, 66219, 66216, 66228, 127904, 711, 127887, 129690, 983073, + 129365, 9936, 128008, 128049, 128569, 128572, 66888, 66864, 66912, 66882, + 66873, 66902, 66889, 66890, 66911, 66891, 66895, 66901, 66881, 66867, + 66870, 66868, 66904, 66866, 66876, 66910, 66879, 66883, 66897, 66915, + 66884, 66878, 66885, 66914, 66903, 66877, 66896, 66909, 66906, 66908, + 66899, 66872, 66913, 66874, 66871, 66875, 66869, 66893, 66887, 66892, + 66907, 66900, 66894, 66905, 66880, 66898, 66865, 66886, 66927, 9761, + 127797, 9963, 8373, 184, 65102, 65098, 8452, 162, 128328, 9907, 9939, + 129681, 69908, 69907, 69913, 69912, 69899, 69909, 69904, 69914, 69906, + 69905, 69911, 69910, 69920, 69921, 69918, 69917, 69901, 69900, 69898, + 69897, 69903, 69902, 69896, 69895, 69956, 69923, 69916, 69915, 69926, + 69919, 69922, 69925, 69959, 69924, 69891, 69894, 69892, 69893, 69888, + 69890, 69889, 69952, 69927, 69957, 69933, 69935, 69930, 69931, 69932, + 69958, 69928, 69929, 69934, 69936, 69939, 69954, 69953, 69947, 69946, + 69949, 69948, 69945, 69944, 69942, 69951, 69943, 69950, 69955, 69940, + 69938, 69937, 43587, 43597, 43596, 43573, 43572, 43574, 43571, 43590, + 43586, 43595, 43588, 43585, 43584, 43594, 43591, 43593, 43589, 43592, + 43530, 43531, 43536, 43538, 43537, 43543, 43544, 43551, 43552, 43548, + 43547, 43546, 43553, 43550, 43549, 43545, 43542, 43541, 43558, 43559, + 43520, 43524, 43533, 43532, 43529, 43528, 43535, 43534, 43527, 43526, + 43540, 43539, 43560, 43556, 43555, 43557, 43554, 43523, 43521, 43525, + 43522, 43612, 43614, 43613, 43615, 43561, 43568, 43569, 43562, 43563, + 43567, 43566, 43565, 43570, 43564, 43605, 43604, 43607, 43606, 43603, + 43602, 43600, 43609, 43601, 43608, 983058, 983140, 983137, 8256, 128200, + 128185, 128201, 128638, 129941, 10003, 129472, 128227, 5084, 5075, 5077, + 5079, 5081, 5082, 5083, 5055, 5037, 5038, 5039, 5040, 5041, 5042, 5054, + 5056, 5057, 5058, 5059, 5060, 5061, 5069, 5068, 5070, 5071, 5072, 5073, + 5074, 5085, 5086, 5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, + 5096, 5076, 5078, 5080, 5030, 5032, 5033, 5034, 5035, 5036, 5043, 5044, + 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5109, 5062, 5063, + 5064, 5065, 5066, 5067, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, + 5105, 5106, 5107, 5108, 5031, 5024, 5025, 5026, 5027, 5028, 5029, 43948, + 43939, 43941, 43943, 43945, 43946, 43947, 43919, 43901, 43902, 43903, + 43904, 43905, 43906, 43918, 43920, 43921, 43922, 43923, 43924, 43925, + 43933, 43932, 43934, 43935, 43936, 43937, 43938, 43949, 43950, 43951, + 43952, 43953, 43954, 43955, 43956, 43957, 43958, 43959, 43960, 43940, + 43942, 43944, 43894, 43896, 43897, 43898, 43899, 43900, 43907, 43908, + 43909, 43910, 43911, 43912, 43913, 43914, 43915, 43916, 43917, 5117, + 43926, 43927, 43928, 43929, 43930, 43931, 43961, 43962, 43963, 43964, + 43965, 43966, 43967, 5112, 5113, 5114, 5115, 5116, 43895, 43888, 43889, + 43890, 43891, 43892, 43893, 127800, 118462, 127826, 127792, 127937, + 129490, 128696, 94194, 94195, 9767, 128063, 128020, 9911, 69559, 69553, + 69567, 69571, 69556, 69564, 69570, 69552, 69568, 69555, 69560, 69562, + 69557, 69561, 69563, 69554, 69566, 69572, 69558, 69569, 69565, 69578, + 69574, 69575, 69577, 69573, 69579, 69576, 129378, 127851, 127876, 9962, + 127910, 9680, 9682, 10690, 10683, 10691, 9684, 9683, 9685, 9677, 9681, + 10677, 10682, 10684, 127246, 8859, 11199, 10687, 129282, 129280, 129281, + 128320, 9938, 127342, 127341, 127277, 8856, 10808, 9316, 9315, 9318, + 9317, 9314, 9313, 9450, 9320, 9312, 9319, 127247, 8857, 8861, 12905, + 12919, 12904, 12918, 12903, 12917, 12926, 12909, 12923, 12906, 12920, + 12896, 12910, 12900, 12914, 12897, 12911, 12908, 12922, 12901, 12915, + 12899, 12913, 12902, 12916, 12907, 12921, 12898, 12912, 9097, 127343, + 10162, 12975, 127569, 12959, 127568, 12963, 12951, 12962, 12965, 12973, + 12943, 12957, 12935, 12950, 12939, 12932, 12955, 12931, 12964, 12946, + 12869, 12871, 12952, 12966, 12967, 12969, 12942, 12954, 12938, 12976, + 12936, 12948, 12868, 12974, 12961, 12970, 12968, 12953, 12934, 12972, + 12956, 12944, 12870, 12947, 12949, 12971, 12945, 12933, 12958, 12930, + 12937, 12929, 12941, 12940, 12960, 12928, 127275, 127276, 128712, 13033, + 13036, 13034, 13037, 13035, 13013, 13016, 13014, 13017, 13015, 13038, + 13041, 13039, 13042, 13040, 13028, 13031, 13029, 13032, 13030, 13046, + 13049, 13047, 13050, 13048, 13018, 13021, 13019, 13022, 13020, 13023, + 13026, 13024, 13027, 13025, 13051, 13053, 13052, 13054, 13043, 13045, + 13044, 13008, 13011, 13009, 13012, 13010, 12925, 12924, 9398, 9399, 9400, + 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, 9411, 9412, + 9413, 9414, 9415, 9416, 9417, 9418, 9419, 9420, 9421, 9422, 9423, 9424, + 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, + 9437, 9438, 9439, 9440, 9441, 9442, 9443, 9444, 9445, 9446, 9447, 9448, + 9449, 10688, 10806, 8854, 12879, 9329, 9322, 12991, 12876, 9326, 12981, + 12875, 12982, 12986, 12985, 12988, 12987, 12984, 12983, 12990, 12989, + 9325, 12878, 9328, 12877, 9327, 9321, 12872, 12890, 12874, 12891, 12895, + 12894, 12978, 12977, 12893, 12892, 12980, 12979, 9324, 9331, 12873, + 12881, 12885, 12884, 12887, 12886, 12883, 12882, 12889, 12888, 9323, + 9330, 10050, 12342, 10679, 10681, 8853, 8858, 10680, 128981, 9098, 8855, + 10686, 10026, 127278, 127245, 8860, 10678, 10689, 128983, 11198, 94, + 10768, 127914, 127961, 127750, 195088, 195089, 195090, 195091, 195092, + 195093, 195094, 195095, 195096, 195097, 195098, 195099, 195100, 195101, + 195072, 195073, 195074, 195075, 195076, 195077, 195078, 195079, 195080, + 195081, 195082, 195083, 195084, 195085, 195086, 195087, 194560, 194561, + 194562, 194563, 194564, 194565, 194566, 194567, 194568, 194569, 194570, + 194571, 194572, 194573, 194574, 194575, 194576, 194577, 194578, 194579, + 194580, 194581, 194582, 194583, 194584, 194585, 194586, 194587, 194588, + 194589, 194590, 194591, 194592, 194593, 194594, 194595, 194596, 194597, + 194598, 194599, 194600, 194601, 194602, 194603, 194604, 194605, 194606, + 194607, 194608, 194609, 194610, 194611, 194612, 194613, 194614, 194615, + 194616, 194617, 194618, 194619, 194620, 194621, 194622, 194623, 194624, + 194625, 194626, 194627, 194628, 194629, 194630, 194631, 194632, 194633, + 194634, 194635, 194636, 194637, 194638, 194639, 194640, 194641, 194642, + 194643, 194644, 194645, 194646, 194647, 194648, 194649, 194650, 194651, + 194652, 194653, 194654, 194655, 194656, 194657, 194658, 194659, 194660, + 194661, 194662, 194663, 194664, 194665, 194666, 194667, 194668, 194669, + 194670, 194671, 194672, 194673, 194674, 194675, 194676, 194677, 194678, + 194679, 194680, 194681, 194682, 194683, 194684, 194685, 194686, 194687, + 194688, 194689, 194690, 194691, 194692, 194693, 194694, 194695, 194696, + 194697, 194698, 194699, 194700, 194701, 194702, 194703, 194704, 194705, + 194706, 194707, 194708, 194709, 194710, 194711, 194712, 194713, 194714, + 194715, 194716, 194717, 194718, 194719, 194720, 194721, 194722, 194723, + 194724, 194725, 194726, 194727, 194728, 194729, 194730, 194731, 194732, + 194733, 194734, 194735, 194736, 194737, 194738, 194739, 194740, 194741, + 194742, 194743, 194744, 194745, 194746, 194747, 194748, 194749, 194750, + 194751, 194752, 194753, 194754, 194755, 194756, 194757, 194758, 194759, + 194760, 194761, 194762, 194763, 194764, 194765, 194766, 194767, 194768, + 194769, 194770, 194771, 194772, 194773, 194774, 194775, 194776, 194777, + 194778, 194779, 194780, 194781, 194782, 194783, 194784, 194785, 194786, + 194787, 194788, 194789, 194790, 194791, 194792, 194793, 194794, 194795, + 194796, 194797, 194798, 194799, 194800, 194801, 194802, 194803, 194804, + 194805, 194806, 194807, 194808, 194809, 194810, 194811, 194812, 194813, + 194814, 194815, 194816, 194817, 194818, 194819, 194820, 194821, 194822, + 194823, 194824, 194825, 194826, 194827, 194828, 194829, 194830, 194831, + 194832, 194833, 194834, 194835, 194836, 194837, 194838, 194839, 194840, + 194841, 194842, 194843, 194844, 194845, 194846, 194847, 194848, 194849, + 194850, 194851, 194852, 194853, 194854, 194855, 194856, 194857, 194858, + 194859, 194860, 194861, 194862, 194863, 194864, 194865, 194866, 194867, + 194868, 194869, 194870, 194871, 194872, 194873, 194874, 194875, 194876, + 194877, 194878, 194879, 194880, 194881, 194882, 194883, 194884, 194885, + 194886, 194887, 194888, 194889, 194890, 194891, 194892, 194893, 194894, + 194895, 194896, 194897, 194898, 194899, 194900, 194901, 194902, 194903, + 194904, 194905, 194906, 194907, 194908, 194909, 194910, 194911, 194912, + 194913, 194914, 194915, 194916, 194917, 194918, 194919, 194920, 194921, + 194922, 194923, 194924, 194925, 194926, 194927, 194928, 194929, 194930, + 194931, 194932, 194933, 194934, 194935, 194936, 194937, 194938, 194939, + 194940, 194941, 194942, 194943, 194944, 194945, 194946, 194947, 194948, + 194949, 194950, 194951, 194952, 194953, 194954, 194955, 194956, 194957, + 194958, 194959, 194960, 194961, 194962, 194963, 194964, 194965, 194966, + 194967, 194968, 194969, 194970, 194971, 194972, 194973, 194974, 194975, + 194976, 194977, 194978, 194979, 194980, 194981, 194982, 194983, 194984, + 194985, 194986, 194987, 194988, 194989, 194990, 194991, 194992, 194993, + 194994, 194995, 194996, 194997, 194998, 194999, 195000, 195001, 195002, + 195003, 195004, 195005, 195006, 195007, 195008, 195009, 195010, 195011, + 195012, 195013, 195014, 195015, 195016, 195017, 195018, 195019, 195020, + 195021, 195022, 195023, 195024, 195025, 195026, 195027, 195028, 195029, + 195030, 195031, 195032, 195033, 195034, 195035, 195036, 195037, 195038, + 195039, 195040, 195041, 195042, 195043, 195044, 195045, 195046, 195047, + 195048, 195049, 195050, 195051, 195052, 195053, 195054, 195055, 195056, + 195057, 195058, 195059, 195060, 195061, 195062, 195063, 195064, 195065, + 195066, 195067, 195068, 195069, 195070, 195071, 64096, 64097, 64098, + 64099, 64100, 64101, 64102, 64103, 64104, 64105, 64106, 64107, 64108, + 64109, 64000, 64001, 64002, 64003, 64004, 64005, 64006, 64007, 64008, + 64009, 64010, 64011, 64012, 64013, 64014, 64015, 64016, 64017, 64018, + 64019, 64020, 64021, 64022, 64023, 64024, 64025, 64026, 64027, 64028, + 64029, 64030, 64031, 64032, 64033, 64034, 64035, 64036, 64037, 64038, + 64039, 64040, 64041, 64042, 64043, 64044, 64045, 64046, 64047, 64048, + 64049, 64050, 64051, 64052, 64053, 64054, 64055, 64056, 64057, 64058, + 64059, 64060, 64061, 64062, 64063, 64064, 64065, 64066, 64067, 64068, + 64069, 64070, 64071, 64072, 64073, 64074, 64075, 64076, 64077, 64078, + 64079, 64080, 64081, 64082, 64083, 64084, 64085, 64086, 64087, 64088, + 64089, 64090, 64091, 64092, 64093, 64094, 64095, 64112, 64113, 64114, + 64115, 64116, 64117, 64118, 64119, 64120, 64121, 64122, 64123, 64124, + 64125, 64126, 64127, 64128, 64129, 64130, 64131, 64132, 64133, 64134, + 64135, 64136, 64137, 64138, 64139, 64140, 64141, 64142, 64143, 64144, + 64145, 64146, 64147, 64148, 64149, 64150, 64151, 64152, 64153, 64154, + 64155, 64156, 64157, 64158, 64159, 64160, 64161, 64162, 64163, 64164, + 64165, 64166, 64167, 64168, 64169, 64170, 64171, 64172, 64173, 64174, + 64175, 64176, 64177, 64178, 64179, 64180, 64181, 64182, 64183, 64184, + 64185, 64186, 64187, 64188, 64189, 64190, 64191, 64192, 64193, 64194, + 64195, 64196, 64197, 64198, 64199, 64200, 64201, 64202, 64203, 64204, + 64205, 64206, 64207, 64208, 64209, 64210, 64211, 64212, 64213, 64214, + 64215, 64216, 64217, 63744, 63745, 63746, 63747, 63748, 63749, 63750, + 63751, 63752, 63753, 63754, 63755, 63756, 63757, 63758, 63759, 63760, + 63761, 63762, 63763, 63764, 63765, 63766, 63767, 63768, 63769, 63770, + 63771, 63772, 63773, 63774, 63775, 63776, 63777, 63778, 63779, 63780, + 63781, 63782, 63783, 63784, 63785, 63786, 63787, 63788, 63789, 63790, + 63791, 63792, 63793, 63794, 63795, 63796, 63797, 63798, 63799, 63800, + 63801, 63802, 63803, 63804, 63805, 63806, 63807, 63808, 63809, 63810, + 63811, 63812, 63813, 63814, 63815, 63816, 63817, 63818, 63819, 63820, + 63821, 63822, 63823, 63824, 63825, 63826, 63827, 63828, 63829, 63830, + 63831, 63832, 63833, 63834, 63835, 63836, 63837, 63838, 63839, 63840, + 63841, 63842, 63843, 63844, 63845, 63846, 63847, 63848, 63849, 63850, + 63851, 63852, 63853, 63854, 63855, 63856, 63857, 63858, 63859, 63860, + 63861, 63862, 63863, 63864, 63865, 63866, 63867, 63868, 63869, 63870, + 63871, 63872, 63873, 63874, 63875, 63876, 63877, 63878, 63879, 63880, + 63881, 63882, 63883, 63884, 63885, 63886, 63887, 63888, 63889, 63890, + 63891, 63892, 63893, 63894, 63895, 63896, 63897, 63898, 63899, 63900, + 63901, 63902, 63903, 63904, 63905, 63906, 63907, 63908, 63909, 63910, + 63911, 63912, 63913, 63914, 63915, 63916, 63917, 63918, 63919, 63920, + 63921, 63922, 63923, 63924, 63925, 63926, 63927, 63928, 63929, 63930, + 63931, 63932, 63933, 63934, 63935, 63936, 63937, 63938, 63939, 63940, + 63941, 63942, 63943, 63944, 63945, 63946, 63947, 63948, 63949, 63950, + 63951, 63952, 63953, 63954, 63955, 63956, 63957, 63958, 63959, 63960, + 63961, 63962, 63963, 63964, 63965, 63966, 63967, 63968, 63969, 63970, + 63971, 63972, 63973, 63974, 63975, 63976, 63977, 63978, 63979, 63980, + 63981, 63982, 63983, 63984, 63985, 63986, 63987, 63988, 63989, 63990, + 63991, 63992, 63993, 63994, 63995, 63996, 63997, 63998, 63999, 11946, + 12003, 11910, 11963, 11962, 11950, 11992, 12012, 12000, 12005, 11996, + 12010, 11984, 11988, 11994, 11987, 11952, 12007, 11977, 11976, 11973, + 12019, 11993, 12014, 11995, 12016, 12006, 12002, 11979, 11936, 11983, + 11905, 11970, 11943, 11931, 11914, 11934, 11944, 11999, 11998, 11997, + 11960, 11947, 11939, 11978, 11968, 11967, 11966, 12004, 11927, 11926, + 12001, 11975, 11928, 12018, 12013, 12015, 12011, 11945, 11986, 11985, + 11921, 11920, 11919, 11918, 11964, 11957, 11990, 11989, 11935, 11965, + 11933, 11941, 11940, 11909, 11991, 11959, 11929, 11904, 11908, 11907, + 11906, 11915, 11942, 11974, 11980, 12008, 12009, 11951, 11925, 11924, + 11922, 11949, 11948, 11917, 11916, 11958, 11932, 12017, 11911, 11923, + 11969, 11982, 11981, 11938, 11937, 11972, 11971, 11956, 11955, 11954, + 11953, 11913, 11912, 11961, 12752, 12743, 12748, 12768, 12772, 12757, + 12741, 12750, 12769, 12747, 12749, 12744, 12742, 12746, 12758, 12754, + 12763, 12770, 12764, 12753, 12740, 12767, 12760, 12759, 12745, 12773, + 12766, 12762, 12755, 12761, 12736, 12765, 12739, 12737, 12738, 12756, + 12751, 12771, 128079, 127916, 127963, 128385, 129346, 127867, 128203, + 128346, 128358, 128343, 128355, 128340, 128352, 128339, 128351, 128344, + 128356, 128336, 128348, 128342, 128354, 128341, 128353, 128345, 128357, + 128347, 128359, 128337, 128349, 128338, 128350, 10561, 8754, 128259, + 10227, 128472, 128257, 128258, 8631, 11118, 8635, 8753, 10959, 10961, + 10960, 10962, 127746, 10828, 10832, 128234, 128235, 128272, 128213, + 10829, 8272, 9729, 127786, 127785, 127784, 127783, 129313, 9114, 129715, + 127864, 129381, 58, 8788, 8353, 128165, 6867, 7625, 7623, 769, 791, 833, + 8410, 8404, 8423, 857, 8432, 7677, 844, 774, 7627, 814, 810, 838, 70459, + 780, 812, 784, 8409, 8405, 787, 789, 806, 65062, 65069, 42609, 1160, + 11774, 11744, 11768, 11747, 11757, 11765, 42654, 11751, 11752, 11753, + 11756, 42613, 11775, 11772, 42655, 11767, 11754, 42619, 11763, 11762, + 42618, 42615, 42612, 42617, 11770, 42614, 11771, 11773, 11769, 11759, + 42616, 11760, 11758, 11748, 11749, 11761, 11746, 11764, 11755, 11745, + 11750, 11766, 42621, 1156, 1158, 1159, 1157, 42608, 42610, 1155, 65070, + 65071, 1161, 42620, 123023, 42607, 770, 813, 807, 43248, 43244, 43245, + 43246, 43247, 43242, 43243, 43249, 43237, 43236, 43239, 43238, 43235, + 43234, 43232, 43241, 43233, 43240, 7675, 776, 804, 6876, 6833, 775, 7672, + 856, 803, 7674, 6877, 7617, 7616, 6886, 6887, 779, 861, 860, 865, 7676, + 6863, 7629, 862, 863, 6840, 831, 6858, 6857, 6844, 866, 6891, 858, 864, + 65058, 65059, 8422, 840, 782, 783, 819, 6832, 798, 6875, 6835, 8413, + 8416, 8418, 8414, 8419, 8420, 8415, 839, 6888, 850, 8412, 6874, 122892, + 122884, 122891, 122890, 122921, 122919, 122889, 122916, 122900, 122907, + 122910, 122901, 122908, 122880, 122920, 122881, 122909, 122903, 122922, + 122883, 122895, 122894, 122896, 122898, 122899, 122882, 122885, 122912, + 122911, 122913, 122918, 122915, 122888, 122886, 122904, 122902, 122897, + 122893, 70508, 70507, 70506, 70505, 70504, 70502, 70503, 70515, 70513, + 70514, 70516, 70512, 768, 790, 832, 6865, 7624, 7621, 847, 119363, + 119362, 119364, 835, 834, 837, 836, 777, 843, 795, 785, 815, 826, 6883, + 811, 6855, 6834, 7632, 12442, 12441, 7671, 7670, 7643, 7646, 7647, 7649, + 7650, 867, 7666, 7655, 7636, 7637, 7638, 872, 7639, 868, 7663, 7641, + 7659, 7635, 869, 7640, 6860, 6861, 6862, 7645, 7660, 7653, 870, 7667, + 7661, 871, 7668, 7664, 876, 7651, 7626, 877, 6848, 7652, 7658, 7656, + 7657, 7665, 6847, 873, 7642, 874, 7644, 875, 7648, 7662, 878, 879, 7654, + 6889, 841, 794, 852, 7678, 8430, 8406, 6849, 6851, 796, 849, 8400, 792, + 6880, 845, 8417, 8429, 8426, 65056, 65063, 65057, 65064, 6841, 8427, 824, + 822, 8402, 818, 772, 65060, 65067, 65061, 65068, 817, 6869, 7620, 6872, + 7622, 7628, 800, 6882, 6854, 842, 66424, 66425, 66423, 66426, 66422, + 6839, 808, 7630, 773, 6846, 6845, 6843, 801, 799, 6856, 8421, 788, 802, + 7679, 854, 848, 853, 8431, 8407, 825, 855, 8401, 6850, 6852, 793, 6881, + 8428, 8408, 805, 778, 7631, 859, 823, 821, 8403, 6873, 6853, 827, 6884, + 6842, 7619, 7618, 828, 6885, 8411, 771, 65065, 65066, 820, 816, 6859, + 8424, 6836, 786, 797, 7669, 846, 6890, 7633, 7634, 809, 781, 830, 6864, + 6870, 6866, 6871, 6868, 7673, 8425, 6838, 6837, 851, 829, 8274, 64, 44, 128476, 9092, 8705, 129517, 9732, 127882, 128533, 128534, 128119, 128679, 8715, 8883, 8885, 8954, 8955, 8957, 8750, 127899, 983187, 9089, 127978, 9010, 9740, 10861, 127859, 127850, 127834, 11505, 11504, 11503, 11464, @@ -10258,30 +10375,30 @@ static const unsigned int dawg_pos_to_codepoint[] = { 983084, 983086, 983088, 983090, 983162, 9110, 9192, 127795, 128475, 8451, 176, 8457, 983120, 128666, 8796, 983119, 9161, 9159, 9153, 9156, 9162, 9160, 9154, 9157, 9164, 9151, 9163, 9150, 9158, 9152, 9155, 117829, - 117828, 127980, 9739, 66589, 66591, 66596, 66597, 66587, 66585, 66594, - 66595, 66593, 66599, 66562, 66563, 66564, 66565, 66561, 66560, 66568, - 66569, 66570, 66571, 66567, 66566, 66598, 66573, 66588, 66579, 66592, - 66590, 66581, 66578, 66580, 66582, 66577, 66586, 66575, 66584, 66583, - 66574, 66572, 66576, 66629, 66631, 66636, 66637, 66627, 66625, 66634, - 66635, 66633, 66639, 66602, 66603, 66604, 66605, 66601, 66600, 66608, - 66609, 66610, 66611, 66607, 66606, 66638, 66613, 66628, 66619, 66632, - 66630, 66621, 66618, 66620, 66622, 66617, 66626, 66615, 66624, 66623, - 66614, 66612, 66616, 127964, 127965, 128421, 128468, 2388, 2416, 43258, - 2387, 43257, 72448, 72449, 43259, 2309, 2310, 2320, 2324, 2421, 43262, - 2330, 2418, 2317, 2321, 2331, 2396, 2430, 2338, 2337, 2343, 2342, 2429, - 2394, 2328, 2427, 2327, 2426, 2361, 2350, 2424, 2308, 2318, 2322, 2358, - 2359, 2360, 2323, 2420, 2419, 2431, 2349, 2348, 2393, 2326, 2325, 2397, - 2353, 2352, 2399, 2351, 2313, 2314, 2423, 2422, 2345, 2339, 2329, 2334, - 2344, 2333, 2428, 2332, 2356, 2355, 2354, 2336, 2335, 2341, 2340, 2315, - 2400, 2316, 2401, 2357, 2311, 2312, 2347, 2346, 2425, 2395, 2398, 2392, - 2319, 983644, 983643, 983646, 983647, 983649, 983648, 983642, 983645, - 72450, 72451, 72452, 72453, 2305, 43255, 43251, 43254, 43253, 72455, - 72454, 72456, 43250, 43260, 2304, 72457, 2364, 2365, 2306, 43252, 43256, - 2417, 2381, 2307, 2386, 2385, 2366, 2376, 2380, 2383, 43263, 2389, 2373, - 2377, 2379, 2363, 2362, 2382, 2369, 2370, 2391, 2390, 2374, 2378, 2371, - 2372, 2402, 2403, 2367, 2368, 2375, 2405, 2404, 2411, 2410, 2413, 2412, - 2409, 2408, 2406, 2415, 2407, 2414, 43261, 2384, 983089, 983161, 983087, - 983085, 983083, 127962, 129487, 129420, 11033, 11032, 11030, 11031, + 117828, 127980, 127962, 9739, 66589, 66591, 66596, 66597, 66587, 66585, + 66594, 66595, 66593, 66599, 66562, 66563, 66564, 66565, 66561, 66560, + 66568, 66569, 66570, 66571, 66567, 66566, 66598, 66573, 66588, 66579, + 66592, 66590, 66581, 66578, 66580, 66582, 66577, 66586, 66575, 66584, + 66583, 66574, 66572, 66576, 66629, 66631, 66636, 66637, 66627, 66625, + 66634, 66635, 66633, 66639, 66602, 66603, 66604, 66605, 66601, 66600, + 66608, 66609, 66610, 66611, 66607, 66606, 66638, 66613, 66628, 66619, + 66632, 66630, 66621, 66618, 66620, 66622, 66617, 66626, 66615, 66624, + 66623, 66614, 66612, 66616, 127964, 127965, 128421, 128468, 2388, 2416, + 43258, 2387, 43257, 72448, 72449, 43259, 2309, 2310, 2320, 2324, 2421, + 43262, 2330, 2418, 2317, 2321, 2331, 2396, 2430, 2338, 2337, 2343, 2342, + 2429, 2394, 2328, 2427, 2327, 2426, 2361, 2350, 2424, 2308, 2318, 2322, + 2358, 2359, 2360, 2431, 2349, 2348, 2393, 2326, 2325, 2397, 2353, 2352, + 2323, 2420, 2419, 2399, 2351, 2313, 2314, 2423, 2422, 2345, 2339, 2329, + 2334, 2344, 2333, 2428, 2332, 2356, 2355, 2354, 2336, 2335, 2341, 2340, + 2315, 2400, 2316, 2401, 2357, 2311, 2312, 2347, 2346, 2425, 2395, 2398, + 2392, 2319, 983644, 983643, 983646, 983647, 983649, 983648, 983642, + 983645, 72450, 72451, 72452, 72453, 2305, 43255, 43251, 43254, 43253, + 72455, 72454, 72456, 43250, 43260, 2304, 72457, 2364, 2365, 2306, 43252, + 43256, 2417, 2381, 2307, 2386, 2385, 2366, 2376, 2380, 2383, 43263, 2389, + 2373, 2377, 2379, 2363, 2362, 2382, 2369, 2370, 2391, 2390, 2374, 2378, + 2371, 2372, 2402, 2403, 2367, 2368, 2375, 2405, 2404, 2411, 2410, 2413, + 2412, 2409, 2408, 2406, 2415, 2407, 2414, 43261, 2384, 983089, 983161, + 983087, 983085, 983083, 129487, 129420, 11033, 11032, 11030, 11031, 128924, 128160, 8900, 8960, 168, 117827, 9856, 9857, 9858, 9859, 9860, 9861, 128754, 53, 127238, 9356, 52, 127237, 9355, 57, 127242, 9360, 49, 127234, 9352, 55, 127240, 9358, 54, 127239, 9357, 51, 127236, 9354, 50, @@ -10290,645 +10407,646 @@ static const unsigned int dawg_pos_to_codepoint[] = { 10128, 10127, 10124, 10123, 127244, 10130, 10122, 10129, 10111, 10106, 10105, 10108, 10107, 10104, 10103, 10110, 10102, 10109, 10121, 10116, 10115, 10118, 10117, 10114, 10113, 127243, 10120, 10112, 10119, 9107, - 127919, 128549, 128542, 9933, 9090, 129400, 72004, 72021, 72020, 72023, - 72022, 72019, 72018, 72016, 72025, 72017, 72024, 71964, 71958, 71963, - 71974, 71973, 71936, 71937, 71961, 71960, 71966, 71965, 71940, 71941, - 71938, 71939, 71982, 71976, 71952, 71962, 71957, 71967, 71978, 71979, - 71980, 71971, 71970, 71954, 71953, 71951, 71950, 71949, 71948, 71969, - 71968, 71981, 71955, 71972, 71975, 71977, 71983, 71942, 71945, 71997, - 71996, 72003, 71995, 71984, 71991, 71987, 71988, 71985, 71986, 71989, - 71992, 71998, 72002, 72000, 72005, 72006, 71999, 72001, 8725, 247, 8903, - 129343, 8739, 9902, 129684, 128171, 128565, 12291, 8783, 9009, 128462, - 128441, 128442, 128443, 8939, 8941, 8716, 8740, 10990, 8832, 8928, 8876, - 8833, 8929, 8878, 128021, 71680, 71681, 71687, 71689, 71703, 71702, - 71708, 71707, 71723, 71716, 71701, 71700, 71706, 71705, 71684, 71685, - 71682, 71683, 71694, 71704, 71699, 71709, 71719, 71720, 71721, 71713, - 71712, 71696, 71695, 71693, 71692, 71698, 71697, 71691, 71690, 71711, - 71710, 71722, 71717, 71714, 71718, 71715, 71686, 71688, 71729, 71730, - 71724, 71732, 71734, 71727, 71728, 71725, 71726, 71731, 71733, 71739, - 71738, 71735, 71737, 71736, 128054, 128044, 36, 127025, 127026, 127027, - 127028, 127029, 127030, 127031, 127032, 127033, 127034, 127035, 127036, - 127037, 127038, 127039, 127040, 127041, 127042, 127043, 127044, 127045, - 127046, 127047, 127048, 127049, 127050, 127051, 127052, 127053, 127054, - 127055, 127056, 127057, 127058, 127059, 127060, 127061, 127062, 127063, - 127064, 127065, 127066, 127067, 127068, 127069, 127070, 127071, 127072, - 127073, 127024, 127075, 127076, 127077, 127078, 127079, 127080, 127081, - 127082, 127083, 127084, 127085, 127086, 127087, 127088, 127089, 127090, - 127091, 127092, 127093, 127094, 127095, 127096, 127097, 127098, 127099, - 127100, 127101, 127102, 127103, 127104, 127105, 127106, 127107, 127108, - 127109, 127110, 127111, 127112, 127113, 127114, 127115, 127116, 127117, - 127118, 127119, 127120, 127121, 127122, 127123, 127074, 129743, 8363, - 8724, 8760, 8901, 729, 9676, 8284, 11850, 11034, 129765, 11795, 11784, - 10649, 11798, 9470, 9465, 9464, 9467, 9466, 9463, 9462, 9469, 9461, 9468, - 10175, 10868, 10986, 8225, 8223, 11840, 8914, 8748, 11842, 8222, 8215, - 10835, 10836, 10645, 10913, 10915, 10914, 10939, 8243, 12318, 10746, - 10830, 10831, 11849, 10988, 11844, 10940, 8913, 8912, 11005, 10987, 8915, - 9208, 10981, 8875, 10979, 8214, 11799, 10646, 733, 8252, 8263, 65100, - 10908, 10907, 11002, 11001, 10906, 10905, 8510, 8473, 8511, 8450, 8461, - 8469, 8474, 8477, 8484, 8518, 8519, 8520, 8521, 8517, 8509, 8508, 8512, - 10719, 9890, 9891, 11260, 127849, 8868, 10993, 10623, 8945, 8964, 117764, - 128317, 117859, 118264, 117883, 118268, 117849, 128315, 117914, 117864, - 10728, 10729, 117875, 117879, 129288, 129290, 129289, 129291, 8595, 8629, - 8671, 129035, 129031, 129179, 129043, 129027, 129047, 8626, 8627, 10504, - 8693, 129975, 8615, 10515, 11796, 11015, 129203, 11147, 11107, 11139, - 11123, 129067, 11168, 11169, 129063, 129059, 129075, 129071, 11133, - 11085, 11117, 11143, 129171, 10507, 8609, 11247, 8681, 129175, 8623, - 8659, 8675, 129079, 10597, 10607, 10593, 10585, 8643, 10589, 10581, 8642, - 129091, 129095, 129087, 10225, 128623, 129107, 129083, 8650, 128687, - 128330, 128682, 129444, 8367, 10139, 128009, 128050, 128042, 129656, - 128167, 129316, 129345, 9946, 128087, 113784, 113788, 113785, 113783, - 113782, 113786, 113787, 113795, 113798, 113793, 113800, 113781, 113794, - 113792, 113799, 113797, 113796, 113776, 113808, 113817, 113811, 113814, - 113809, 113816, 113779, 113810, 113815, 113813, 113812, 113778, 113777, - 113780, 113729, 113733, 113672, 113677, 113683, 113735, 113739, 113746, - 113668, 113678, 113674, 113726, 113691, 113699, 113700, 113695, 113709, - 113712, 113713, 113705, 113711, 113669, 113725, 113679, 113684, 113670, - 113743, 113749, 113687, 113689, 113693, 113707, 113697, 113703, 113690, - 113694, 113708, 113698, 113704, 113764, 113763, 113762, 113761, 113732, - 113753, 113731, 113755, 113754, 113666, 113766, 113765, 113676, 113675, - 113741, 113750, 113680, 113688, 113692, 113696, 113710, 113727, 113728, - 113716, 113717, 113714, 113715, 113701, 113702, 113724, 113723, 113706, - 113742, 113740, 113767, 113769, 113730, 113768, 113682, 113685, 113752, - 113737, 113667, 113719, 113718, 113681, 113745, 113748, 113751, 113738, - 113673, 113770, 113720, 113757, 113760, 113722, 113759, 113756, 113721, - 113758, 113665, 113747, 113664, 113686, 113734, 113736, 113744, 113671, - 113821, 113822, 113823, 113820, 129375, 129414, 129516, 128192, 983082, - 128066, 127805, 127806, 129467, 9793, 127758, 127759, 127757, 9178, 9841, - 129413, 11790, 77830, 77831, 77832, 77828, 77829, 77824, 77825, 77826, - 77827, 77833, 77834, 77835, 77840, 77841, 77844, 77845, 77836, 77837, - 77838, 77839, 77842, 77843, 77846, 77847, 77869, 77870, 77872, 77873, - 77874, 77875, 77877, 77878, 77871, 77876, 77879, 77880, 77881, 77882, - 77860, 77861, 77858, 77859, 77862, 77863, 77864, 77865, 77866, 77867, - 77868, 77903, 77848, 77849, 77850, 77851, 77852, 77853, 77854, 77855, - 77856, 77857, 77883, 77884, 77885, 77886, 77887, 77888, 77889, 77890, - 77891, 77892, 77893, 77894, 77895, 77896, 77897, 77898, 77899, 77900, - 77901, 77902, 78867, 78868, 78869, 78861, 78862, 78863, 78864, 78865, - 78866, 78870, 78871, 78892, 78893, 78894, 78872, 78873, 78874, 78875, - 78876, 78877, 78878, 78879, 78880, 78881, 78882, 78883, 78884, 78885, - 78886, 78887, 78888, 78889, 78890, 78891, 78910, 78908, 78903, 77908, - 77909, 77904, 77905, 77906, 77907, 77910, 77911, 77912, 77913, 77915, - 77916, 77917, 77918, 77914, 77919, 77920, 77921, 77922, 77923, 77924, - 77925, 77926, 77927, 77928, 77929, 77930, 77931, 77932, 77933, 77934, - 77935, 77936, 77937, 77938, 77939, 77940, 77941, 77949, 77950, 77942, - 77943, 77944, 77945, 77946, 77947, 77948, 77951, 77974, 77975, 77978, - 77979, 77973, 77976, 77977, 77980, 77981, 77982, 77983, 77984, 77991, - 77992, 77994, 77995, 77985, 77986, 77987, 77988, 77989, 77990, 77993, - 77996, 77997, 77998, 77999, 78000, 78001, 78002, 78003, 78004, 78005, - 78006, 78008, 78009, 78011, 78012, 78007, 78010, 78013, 78014, 78015, - 78016, 78017, 78025, 78026, 78027, 78028, 78029, 78030, 78031, 78032, - 78033, 78018, 78019, 78020, 78021, 78022, 78023, 78024, 77969, 77970, - 77962, 77963, 77964, 77965, 77966, 77967, 77968, 77971, 77972, 77952, - 77953, 77954, 77955, 77956, 77957, 77958, 77959, 77960, 77961, 78041, - 78042, 78043, 78044, 78034, 78035, 78036, 78037, 78038, 78039, 78040, - 78057, 78058, 78066, 78067, 78059, 78060, 78061, 78062, 78063, 78064, - 78065, 78068, 78073, 78074, 78069, 78070, 78071, 78072, 78075, 78076, - 78077, 78051, 78052, 78053, 78054, 78045, 78046, 78047, 78048, 78049, - 78050, 78055, 78056, 78911, 78909, 78904, 78078, 78079, 78080, 78081, - 78082, 78083, 78084, 78085, 78086, 78087, 78091, 78092, 78088, 78089, - 78090, 78093, 78094, 78095, 78096, 78097, 78098, 78111, 78112, 78118, - 78119, 78120, 78121, 78110, 78113, 78114, 78115, 78116, 78117, 78122, - 78128, 78129, 78130, 78131, 78132, 78133, 78123, 78124, 78125, 78126, - 78127, 78134, 78135, 78137, 78138, 78139, 78140, 78136, 78141, 78142, - 78100, 78101, 78099, 78102, 78103, 78104, 78105, 78106, 78107, 78108, - 78109, 78913, 78150, 78151, 78152, 78148, 78149, 78143, 78144, 78145, - 78146, 78147, 78153, 78154, 78156, 78157, 78155, 78158, 78159, 78160, - 78161, 78162, 78163, 78164, 78165, 78184, 78185, 78186, 78187, 78178, - 78179, 78180, 78181, 78182, 78183, 78188, 78189, 78193, 78194, 78196, - 78197, 78190, 78191, 78192, 78195, 78198, 78199, 78200, 78201, 78166, - 78167, 78173, 78174, 78168, 78169, 78170, 78171, 78172, 78175, 78176, - 78177, 78202, 78203, 78204, 78205, 78206, 78212, 78213, 78207, 78208, - 78209, 78210, 78211, 78214, 78215, 78914, 78916, 78897, 78220, 78221, - 78225, 78226, 78216, 78217, 78218, 78219, 78222, 78223, 78224, 78227, - 78228, 78229, 78230, 78231, 78232, 78233, 78234, 78907, 78901, 78899, - 78906, 78900, 78898, 78905, 78244, 78245, 78249, 78250, 78243, 78246, - 78247, 78248, 78251, 78252, 78915, 78253, 78254, 78255, 78257, 78258, - 78256, 78259, 78260, 78261, 78262, 78263, 78264, 78268, 78269, 78270, - 78271, 78272, 78273, 78274, 78275, 78276, 78265, 78266, 78279, 78280, - 78281, 78282, 78283, 78284, 78267, 78277, 78278, 78285, 78286, 78289, - 78290, 78292, 78293, 78297, 78298, 78287, 78288, 78291, 78294, 78295, - 78296, 78299, 78304, 78305, 78306, 78301, 78302, 78300, 78303, 78307, - 78308, 78309, 78310, 78311, 78312, 78313, 78314, 78315, 78316, 78317, - 78318, 78933, 78928, 78920, 78924, 78932, 78926, 78921, 78929, 78925, - 78923, 78931, 78919, 78927, 78922, 78930, 78912, 78336, 78337, 78338, - 78328, 78329, 78330, 78331, 78332, 78333, 78334, 78335, 78339, 78354, - 78355, 78356, 78357, 78358, 78359, 78361, 78362, 78351, 78352, 78353, - 78360, 78363, 78364, 78345, 78346, 78340, 78341, 78342, 78343, 78344, - 78347, 78348, 78349, 78350, 78365, 78366, 78367, 78319, 78320, 78321, - 78322, 78323, 78324, 78325, 78326, 78327, 78372, 78373, 78368, 78369, - 78370, 78371, 78374, 78375, 78376, 78377, 78385, 78386, 78378, 78379, - 78380, 78381, 78382, 78383, 78384, 78387, 78388, 78389, 78399, 78400, - 78401, 78402, 78409, 78410, 78403, 78404, 78405, 78406, 78407, 78408, - 78411, 78414, 78415, 78412, 78413, 78390, 78391, 78392, 78393, 78394, - 78395, 78396, 78397, 78398, 78423, 78424, 78425, 78426, 78427, 78428, - 78429, 78416, 78417, 78421, 78422, 78418, 78419, 78420, 78430, 78431, - 78432, 78433, 78434, 78435, 78436, 78445, 78446, 78437, 78438, 78439, - 78440, 78441, 78442, 78443, 78444, 78447, 78448, 78452, 78453, 78454, - 78455, 78459, 78460, 78449, 78450, 78451, 78456, 78457, 78458, 78469, - 78470, 78471, 78472, 78473, 78461, 78462, 78465, 78466, 78463, 78464, - 78467, 78468, 78474, 78475, 78476, 78487, 78488, 78489, 78490, 78477, - 78478, 78479, 78480, 78481, 78482, 78483, 78484, 78485, 78486, 78902, - 78491, 78492, 78494, 78495, 78493, 78496, 78497, 78498, 78499, 78500, - 78501, 78502, 78503, 78514, 78515, 78516, 78512, 78513, 78511, 78517, - 78518, 78519, 78520, 78521, 78522, 78523, 78524, 78530, 78531, 78525, - 78526, 78527, 78528, 78529, 78532, 78533, 78534, 78535, 78536, 78537, - 78538, 78539, 78540, 78541, 78542, 78543, 78544, 78546, 78547, 78551, - 78552, 78545, 78548, 78549, 78550, 78553, 78554, 78555, 78560, 78561, - 78562, 78565, 78566, 78556, 78557, 78558, 78559, 78563, 78564, 78567, - 78568, 78575, 78576, 78577, 78569, 78570, 78571, 78572, 78573, 78574, - 78578, 78579, 78580, 78586, 78587, 78581, 78582, 78583, 78584, 78585, - 78588, 78589, 78590, 78591, 78592, 78593, 78594, 78595, 78596, 78597, - 78598, 78601, 78602, 78606, 78607, 78608, 78609, 78610, 78611, 78599, - 78600, 78603, 78604, 78605, 78613, 78614, 78619, 78620, 78612, 78615, - 78616, 78617, 78618, 78621, 78622, 78623, 78636, 78637, 78638, 78639, - 78634, 78635, 78640, 78641, 78642, 78624, 78625, 78626, 78627, 78628, - 78629, 78630, 78631, 78632, 78633, 78917, 78648, 78649, 78650, 78643, - 78644, 78645, 78646, 78647, 78651, 78652, 78653, 78667, 78668, 78674, - 78675, 78664, 78665, 78666, 78669, 78670, 78671, 78672, 78673, 78678, - 78679, 78676, 78677, 78680, 78681, 78682, 78683, 78684, 78685, 78686, - 78687, 78688, 78689, 78654, 78655, 78656, 78657, 78658, 78659, 78660, - 78661, 78662, 78663, 78706, 78707, 78708, 78690, 78691, 78692, 78693, - 78694, 78695, 78696, 78697, 78698, 78699, 78700, 78701, 78702, 78703, - 78704, 78705, 78709, 78710, 78712, 78713, 78714, 78715, 78895, 78716, - 78717, 78718, 78711, 78719, 78720, 78721, 78722, 78723, 78724, 78725, - 78726, 78727, 78728, 78729, 78730, 78731, 78732, 78733, 78734, 78735, - 78736, 78737, 78738, 78741, 78742, 78747, 78748, 78749, 78750, 78739, - 78740, 78743, 78744, 78745, 78746, 78751, 78752, 78753, 78754, 78756, - 78757, 78761, 78762, 78755, 78758, 78759, 78760, 78763, 78764, 78765, - 78766, 78896, 78769, 78770, 78776, 78777, 78767, 78768, 78771, 78772, - 78773, 78774, 78775, 78778, 78779, 78783, 78784, 78787, 78788, 78789, - 78790, 78780, 78781, 78782, 78785, 78786, 78791, 78796, 78797, 78792, - 78793, 78794, 78795, 78798, 78918, 78802, 78803, 78804, 78806, 78807, - 78809, 78810, 78799, 78800, 78801, 78805, 78808, 78811, 78812, 78813, - 78814, 78815, 78816, 78817, 78818, 78819, 78821, 78822, 78823, 78824, - 78825, 78826, 78827, 78828, 78829, 78830, 78831, 78832, 78820, 78833, - 78834, 78835, 78836, 78842, 78843, 78844, 78845, 78846, 78847, 78848, - 78849, 78850, 78851, 78852, 78853, 78854, 78855, 78856, 78857, 78858, - 78859, 78860, 78837, 78838, 78839, 78840, 78841, 78235, 78236, 78237, - 78238, 78239, 78240, 78241, 78242, 78504, 78505, 78506, 78507, 78508, - 78509, 78510, 78944, 78945, 78946, 78947, 78948, 78949, 78950, 78951, - 78952, 78953, 78954, 78955, 78956, 78957, 78958, 78959, 78960, 78961, - 78962, 78963, 78964, 78965, 78966, 78967, 78968, 78969, 78970, 78971, - 78972, 78973, 78974, 78975, 78976, 78977, 78978, 78979, 78980, 78981, - 78982, 78983, 78984, 78985, 78986, 78987, 78988, 78989, 78990, 78991, - 78992, 78993, 78994, 78995, 78996, 78997, 78998, 78999, 79000, 79001, - 79002, 79003, 79004, 79005, 79006, 79007, 79008, 79009, 79010, 79011, - 79012, 79013, 79014, 79015, 79016, 79017, 79018, 79019, 79020, 79021, - 79022, 79023, 79024, 79025, 79026, 79027, 79028, 79029, 79030, 79031, - 79032, 79033, 79034, 79035, 79036, 79037, 79038, 79039, 79040, 79041, - 79042, 79043, 79044, 79045, 79046, 79047, 79048, 79049, 79050, 79051, - 79052, 79053, 79054, 79055, 79056, 79057, 79058, 79059, 79060, 79061, - 79062, 79063, 79064, 79065, 79066, 79067, 79068, 79069, 79070, 79071, - 79072, 79073, 79074, 79075, 79076, 79077, 79078, 79079, 79080, 79081, - 79082, 79083, 79084, 79085, 79086, 79087, 79088, 79089, 79090, 79091, - 79092, 79093, 79094, 79095, 79096, 79097, 79098, 79099, 79100, 79101, - 79102, 79103, 79104, 79105, 79106, 79107, 79108, 79109, 79110, 79111, - 79112, 79113, 79114, 79115, 79116, 79117, 79118, 79119, 79120, 79121, - 79122, 79123, 79124, 79125, 79126, 79127, 79128, 79129, 79130, 79131, - 79132, 79133, 79134, 79135, 79136, 79137, 79138, 79139, 79140, 79141, - 79142, 79143, 79144, 79145, 79146, 79147, 79148, 79149, 79150, 79151, - 79152, 79153, 79154, 79155, 79156, 79157, 79158, 79159, 79160, 79161, - 79162, 79163, 79164, 79165, 79166, 79167, 79168, 79169, 79170, 79171, - 79172, 79173, 79174, 79175, 79176, 79177, 79178, 79179, 79180, 79181, - 79182, 79183, 79184, 79185, 79186, 79187, 79188, 79189, 79190, 79191, - 79192, 79193, 79194, 79195, 79196, 79197, 79198, 79199, 79200, 79201, - 79202, 79203, 79204, 79205, 79206, 79207, 79208, 79209, 79210, 79211, - 79212, 79213, 79214, 79215, 79216, 79217, 79218, 79219, 79220, 79221, - 79222, 79223, 79224, 79225, 79226, 79227, 79228, 79229, 79230, 79231, - 79232, 79233, 79234, 79235, 79236, 79237, 79238, 79239, 79240, 79241, - 79242, 79243, 79244, 79245, 79246, 79247, 79248, 79249, 79250, 79251, - 79252, 79253, 79254, 79255, 79256, 79257, 79258, 79259, 79260, 79261, - 79262, 79263, 79264, 79265, 79266, 79267, 79268, 79269, 79270, 79271, - 79272, 79273, 79274, 79275, 79276, 79277, 79278, 79279, 79280, 79281, - 79282, 79283, 79284, 79285, 79286, 79287, 79288, 79289, 79290, 79291, - 79292, 79293, 79294, 79295, 79296, 79297, 79298, 79299, 79300, 79301, - 79302, 79303, 79304, 79305, 79306, 79307, 79308, 79309, 79310, 79311, - 79312, 79313, 79314, 79315, 79316, 79317, 79318, 79319, 79320, 79321, - 79322, 79323, 79324, 79325, 79326, 79327, 79328, 79329, 79330, 79331, - 79332, 79333, 79334, 79335, 79336, 79337, 79338, 79339, 79340, 79341, - 79342, 79343, 79344, 79345, 79346, 79347, 79348, 79349, 79350, 79351, - 79352, 79353, 79354, 79355, 79356, 79357, 79358, 79359, 79360, 79361, - 79362, 79363, 79364, 79365, 79366, 79367, 79368, 79369, 79370, 79371, - 79372, 79373, 79374, 79375, 79376, 79377, 79378, 79379, 79380, 79381, - 79382, 79383, 79384, 79385, 79386, 79387, 79388, 79389, 79390, 79391, - 79392, 79393, 79394, 79395, 79396, 79397, 79398, 79399, 79400, 79401, - 79402, 79403, 79404, 79405, 79406, 79407, 79408, 79409, 79410, 79411, - 79412, 79413, 79414, 79415, 79416, 79417, 79418, 79419, 79420, 79421, - 79422, 79423, 79424, 79425, 79426, 79427, 79428, 79429, 79430, 79431, - 79432, 79433, 79434, 79435, 79436, 79437, 79438, 79439, 79440, 79441, - 79442, 79443, 79444, 79445, 79446, 79447, 79448, 79449, 79450, 79451, - 79452, 79453, 79454, 79455, 79456, 79457, 79458, 79459, 79460, 79461, - 79462, 79463, 79464, 79465, 79466, 79467, 79468, 79469, 79470, 79471, - 79472, 79473, 79474, 79475, 79476, 79477, 79478, 79479, 79480, 79481, - 79482, 79483, 79484, 79485, 79486, 79487, 79488, 79489, 79490, 79491, - 79492, 79493, 79494, 79495, 79496, 79497, 79498, 79499, 79500, 79501, - 79502, 79503, 79504, 79505, 79506, 79507, 79508, 79509, 79510, 79511, - 79512, 79513, 79514, 79515, 79516, 79517, 79518, 79519, 79520, 79521, - 79522, 79523, 79524, 79525, 79526, 79527, 79528, 79529, 79530, 79531, - 79532, 79533, 79534, 79535, 79536, 79537, 79538, 79539, 79540, 79541, - 79542, 79543, 79544, 79545, 79546, 79547, 79548, 79549, 79550, 79551, - 79552, 79553, 79554, 79555, 79556, 79557, 79558, 79559, 79560, 79561, - 79562, 79563, 79564, 79565, 79566, 79567, 79568, 79569, 79570, 79571, - 79572, 79573, 79574, 79575, 79576, 79577, 79578, 79579, 79580, 79581, - 79582, 79583, 79584, 79585, 79586, 79587, 79588, 79589, 79590, 79591, - 79592, 79593, 79594, 79595, 79596, 79597, 79598, 79599, 79600, 79601, - 79602, 79603, 79604, 79605, 79606, 79607, 79608, 79609, 79610, 79611, - 79612, 79613, 79614, 79615, 79616, 79617, 79618, 79619, 79620, 79621, - 79622, 79623, 79624, 79625, 79626, 79627, 79628, 79629, 79630, 79631, - 79632, 79633, 79634, 79635, 79636, 79637, 79638, 79639, 79640, 79641, - 79642, 79643, 79644, 79645, 79646, 79647, 79648, 79649, 79650, 79651, - 79652, 79653, 79654, 79655, 79656, 79657, 79658, 79659, 79660, 79661, - 79662, 79663, 79664, 79665, 79666, 79667, 79668, 79669, 79670, 79671, - 79672, 79673, 79674, 79675, 79676, 79677, 79678, 79679, 79680, 79681, - 79682, 79683, 79684, 79685, 79686, 79687, 79688, 79689, 79690, 79691, - 79692, 79693, 79694, 79695, 79696, 79697, 79698, 79699, 79700, 79701, - 79702, 79703, 79704, 79705, 79706, 79707, 79708, 79709, 79710, 79711, - 79712, 79713, 79714, 79715, 79716, 79717, 79718, 79719, 79720, 79721, - 79722, 79723, 79724, 79725, 79726, 79727, 79728, 79729, 79730, 79731, - 79732, 79733, 79734, 79735, 79736, 79737, 79738, 79739, 79740, 79741, - 79742, 79743, 79744, 79745, 79746, 79747, 79748, 79749, 79750, 79751, - 79752, 79753, 79754, 79755, 79756, 79757, 79758, 79759, 79760, 79761, - 79762, 79763, 79764, 79765, 79766, 79767, 79768, 79769, 79770, 79771, - 79772, 79773, 79774, 79775, 79776, 79777, 79778, 79779, 79780, 79781, - 79782, 79783, 79784, 79785, 79786, 79787, 79788, 79789, 79790, 79791, - 79792, 79793, 79794, 79795, 79796, 79797, 79798, 79799, 79800, 79801, - 79802, 79803, 79804, 79805, 79806, 79807, 79808, 79809, 79810, 79811, - 79812, 79813, 79814, 79815, 79816, 79817, 79818, 79819, 79820, 79821, - 79822, 79823, 79824, 79825, 79826, 79827, 79828, 79829, 79830, 79831, - 79832, 79833, 79834, 79835, 79836, 79837, 79838, 79839, 79840, 79841, - 79842, 79843, 79844, 79845, 79846, 79847, 79848, 79849, 79850, 79851, - 79852, 79853, 79854, 79855, 79856, 79857, 79858, 79859, 79860, 79861, - 79862, 79863, 79864, 79865, 79866, 79867, 79868, 79869, 79870, 79871, - 79872, 79873, 79874, 79875, 79876, 79877, 79878, 79879, 79880, 79881, - 79882, 79883, 79884, 79885, 79886, 79887, 79888, 79889, 79890, 79891, - 79892, 79893, 79894, 79895, 79896, 79897, 79898, 79899, 79900, 79901, - 79902, 79903, 79904, 79905, 79906, 79907, 79908, 79909, 79910, 79911, - 79912, 79913, 79914, 79915, 79916, 79917, 79918, 79919, 79920, 79921, - 79922, 79923, 79924, 79925, 79926, 79927, 79928, 79929, 79930, 79931, - 79932, 79933, 79934, 79935, 79936, 79937, 79938, 79939, 79940, 79941, - 79942, 79943, 79944, 79945, 79946, 79947, 79948, 79949, 79950, 79951, - 79952, 79953, 79954, 79955, 79956, 79957, 79958, 79959, 79960, 79961, - 79962, 79963, 79964, 79965, 79966, 79967, 79968, 79969, 79970, 79971, - 79972, 79973, 79974, 79975, 79976, 79977, 79978, 79979, 79980, 79981, - 79982, 79983, 79984, 79985, 79986, 79987, 79988, 79989, 79990, 79991, - 79992, 79993, 79994, 79995, 79996, 79997, 79998, 79999, 80000, 80001, - 80002, 80003, 80004, 80005, 80006, 80007, 80008, 80009, 80010, 80011, - 80012, 80013, 80014, 80015, 80016, 80017, 80018, 80019, 80020, 80021, - 80022, 80023, 80024, 80025, 80026, 80027, 80028, 80029, 80030, 80031, - 80032, 80033, 80034, 80035, 80036, 80037, 80038, 80039, 80040, 80041, - 80042, 80043, 80044, 80045, 80046, 80047, 80048, 80049, 80050, 80051, - 80052, 80053, 80054, 80055, 80056, 80057, 80058, 80059, 80060, 80061, - 80062, 80063, 80064, 80065, 80066, 80067, 80068, 80069, 80070, 80071, - 80072, 80073, 80074, 80075, 80076, 80077, 80078, 80079, 80080, 80081, - 80082, 80083, 80084, 80085, 80086, 80087, 80088, 80089, 80090, 80091, - 80092, 80093, 80094, 80095, 80096, 80097, 80098, 80099, 80100, 80101, - 80102, 80103, 80104, 80105, 80106, 80107, 80108, 80109, 80110, 80111, - 80112, 80113, 80114, 80115, 80116, 80117, 80118, 80119, 80120, 80121, - 80122, 80123, 80124, 80125, 80126, 80127, 80128, 80129, 80130, 80131, - 80132, 80133, 80134, 80135, 80136, 80137, 80138, 80139, 80140, 80141, - 80142, 80143, 80144, 80145, 80146, 80147, 80148, 80149, 80150, 80151, - 80152, 80153, 80154, 80155, 80156, 80157, 80158, 80159, 80160, 80161, - 80162, 80163, 80164, 80165, 80166, 80167, 80168, 80169, 80170, 80171, - 80172, 80173, 80174, 80175, 80176, 80177, 80178, 80179, 80180, 80181, - 80182, 80183, 80184, 80185, 80186, 80187, 80188, 80189, 80190, 80191, - 80192, 80193, 80194, 80195, 80196, 80197, 80198, 80199, 80200, 80201, - 80202, 80203, 80204, 80205, 80206, 80207, 80208, 80209, 80210, 80211, - 80212, 80213, 80214, 80215, 80216, 80217, 80218, 80219, 80220, 80221, - 80222, 80223, 80224, 80225, 80226, 80227, 80228, 80229, 80230, 80231, - 80232, 80233, 80234, 80235, 80236, 80237, 80238, 80239, 80240, 80241, - 80242, 80243, 80244, 80245, 80246, 80247, 80248, 80249, 80250, 80251, - 80252, 80253, 80254, 80255, 80256, 80257, 80258, 80259, 80260, 80261, - 80262, 80263, 80264, 80265, 80266, 80267, 80268, 80269, 80270, 80271, - 80272, 80273, 80274, 80275, 80276, 80277, 80278, 80279, 80280, 80281, - 80282, 80283, 80284, 80285, 80286, 80287, 80288, 80289, 80290, 80291, - 80292, 80293, 80294, 80295, 80296, 80297, 80298, 80299, 80300, 80301, - 80302, 80303, 80304, 80305, 80306, 80307, 80308, 80309, 80310, 80311, - 80312, 80313, 80314, 80315, 80316, 80317, 80318, 80319, 80320, 80321, - 80322, 80323, 80324, 80325, 80326, 80327, 80328, 80329, 80330, 80331, - 80332, 80333, 80334, 80335, 80336, 80337, 80338, 80339, 80340, 80341, - 80342, 80343, 80344, 80345, 80346, 80347, 80348, 80349, 80350, 80351, - 80352, 80353, 80354, 80355, 80356, 80357, 80358, 80359, 80360, 80361, - 80362, 80363, 80364, 80365, 80366, 80367, 80368, 80369, 80370, 80371, - 80372, 80373, 80374, 80375, 80376, 80377, 80378, 80379, 80380, 80381, - 80382, 80383, 80384, 80385, 80386, 80387, 80388, 80389, 80390, 80391, - 80392, 80393, 80394, 80395, 80396, 80397, 80398, 80399, 80400, 80401, - 80402, 80403, 80404, 80405, 80406, 80407, 80408, 80409, 80410, 80411, - 80412, 80413, 80414, 80415, 80416, 80417, 80418, 80419, 80420, 80421, - 80422, 80423, 80424, 80425, 80426, 80427, 80428, 80429, 80430, 80431, - 80432, 80433, 80434, 80435, 80436, 80437, 80438, 80439, 80440, 80441, - 80442, 80443, 80444, 80445, 80446, 80447, 80448, 80449, 80450, 80451, - 80452, 80453, 80454, 80455, 80456, 80457, 80458, 80459, 80460, 80461, - 80462, 80463, 80464, 80465, 80466, 80467, 80468, 80469, 80470, 80471, - 80472, 80473, 80474, 80475, 80476, 80477, 80478, 80479, 80480, 80481, - 80482, 80483, 80484, 80485, 80486, 80487, 80488, 80489, 80490, 80491, - 80492, 80493, 80494, 80495, 80496, 80497, 80498, 80499, 80500, 80501, - 80502, 80503, 80504, 80505, 80506, 80507, 80508, 80509, 80510, 80511, - 80512, 80513, 80514, 80515, 80516, 80517, 80518, 80519, 80520, 80521, - 80522, 80523, 80524, 80525, 80526, 80527, 80528, 80529, 80530, 80531, - 80532, 80533, 80534, 80535, 80536, 80537, 80538, 80539, 80540, 80541, - 80542, 80543, 80544, 80545, 80546, 80547, 80548, 80549, 80550, 80551, - 80552, 80553, 80554, 80555, 80556, 80557, 80558, 80559, 80560, 80561, - 80562, 80563, 80564, 80565, 80566, 80567, 80568, 80569, 80570, 80571, - 80572, 80573, 80574, 80575, 80576, 80577, 80578, 80579, 80580, 80581, - 80582, 80583, 80584, 80585, 80586, 80587, 80588, 80589, 80590, 80591, - 80592, 80593, 80594, 80595, 80596, 80597, 80598, 80599, 80600, 80601, - 80602, 80603, 80604, 80605, 80606, 80607, 80608, 80609, 80610, 80611, - 80612, 80613, 80614, 80615, 80616, 80617, 80618, 80619, 80620, 80621, - 80622, 80623, 80624, 80625, 80626, 80627, 80628, 80629, 80630, 80631, - 80632, 80633, 80634, 80635, 80636, 80637, 80638, 80639, 80640, 80641, - 80642, 80643, 80644, 80645, 80646, 80647, 80648, 80649, 80650, 80651, - 80652, 80653, 80654, 80655, 80656, 80657, 80658, 80659, 80660, 80661, - 80662, 80663, 80664, 80665, 80666, 80667, 80668, 80669, 80670, 80671, - 80672, 80673, 80674, 80675, 80676, 80677, 80678, 80679, 80680, 80681, - 80682, 80683, 80684, 80685, 80686, 80687, 80688, 80689, 80690, 80691, - 80692, 80693, 80694, 80695, 80696, 80697, 80698, 80699, 80700, 80701, - 80702, 80703, 80704, 80705, 80706, 80707, 80708, 80709, 80710, 80711, - 80712, 80713, 80714, 80715, 80716, 80717, 80718, 80719, 80720, 80721, - 80722, 80723, 80724, 80725, 80726, 80727, 80728, 80729, 80730, 80731, - 80732, 80733, 80734, 80735, 80736, 80737, 80738, 80739, 80740, 80741, - 80742, 80743, 80744, 80745, 80746, 80747, 80748, 80749, 80750, 80751, - 80752, 80753, 80754, 80755, 80756, 80757, 80758, 80759, 80760, 80761, - 80762, 80763, 80764, 80765, 80766, 80767, 80768, 80769, 80770, 80771, - 80772, 80773, 80774, 80775, 80776, 80777, 80778, 80779, 80780, 80781, - 80782, 80783, 80784, 80785, 80786, 80787, 80788, 80789, 80790, 80791, - 80792, 80793, 80794, 80795, 80796, 80797, 80798, 80799, 80800, 80801, - 80802, 80803, 80804, 80805, 80806, 80807, 80808, 80809, 80810, 80811, - 80812, 80813, 80814, 80815, 80816, 80817, 80818, 80819, 80820, 80821, - 80822, 80823, 80824, 80825, 80826, 80827, 80828, 80829, 80830, 80831, - 80832, 80833, 80834, 80835, 80836, 80837, 80838, 80839, 80840, 80841, - 80842, 80843, 80844, 80845, 80846, 80847, 80848, 80849, 80850, 80851, - 80852, 80853, 80854, 80855, 80856, 80857, 80858, 80859, 80860, 80861, - 80862, 80863, 80864, 80865, 80866, 80867, 80868, 80869, 80870, 80871, - 80872, 80873, 80874, 80875, 80876, 80877, 80878, 80879, 80880, 80881, - 80882, 80883, 80884, 80885, 80886, 80887, 80888, 80889, 80890, 80891, - 80892, 80893, 80894, 80895, 80896, 80897, 80898, 80899, 80900, 80901, - 80902, 80903, 80904, 80905, 80906, 80907, 80908, 80909, 80910, 80911, - 80912, 80913, 80914, 80915, 80916, 80917, 80918, 80919, 80920, 80921, - 80922, 80923, 80924, 80925, 80926, 80927, 80928, 80929, 80930, 80931, - 80932, 80933, 80934, 80935, 80936, 80937, 80938, 80939, 80940, 80941, - 80942, 80943, 80944, 80945, 80946, 80947, 80948, 80949, 80950, 80951, - 80952, 80953, 80954, 80955, 80956, 80957, 80958, 80959, 80960, 80961, - 80962, 80963, 80964, 80965, 80966, 80967, 80968, 80969, 80970, 80971, - 80972, 80973, 80974, 80975, 80976, 80977, 80978, 80979, 80980, 80981, - 80982, 80983, 80984, 80985, 80986, 80987, 80988, 80989, 80990, 80991, - 80992, 80993, 80994, 80995, 80996, 80997, 80998, 80999, 81000, 81001, - 81002, 81003, 81004, 81005, 81006, 81007, 81008, 81009, 81010, 81011, - 81012, 81013, 81014, 81015, 81016, 81017, 81018, 81019, 81020, 81021, - 81022, 81023, 81024, 81025, 81026, 81027, 81028, 81029, 81030, 81031, - 81032, 81033, 81034, 81035, 81036, 81037, 81038, 81039, 81040, 81041, - 81042, 81043, 81044, 81045, 81046, 81047, 81048, 81049, 81050, 81051, - 81052, 81053, 81054, 81055, 81056, 81057, 81058, 81059, 81060, 81061, - 81062, 81063, 81064, 81065, 81066, 81067, 81068, 81069, 81070, 81071, - 81072, 81073, 81074, 81075, 81076, 81077, 81078, 81079, 81080, 81081, - 81082, 81083, 81084, 81085, 81086, 81087, 81088, 81089, 81090, 81091, - 81092, 81093, 81094, 81095, 81096, 81097, 81098, 81099, 81100, 81101, - 81102, 81103, 81104, 81105, 81106, 81107, 81108, 81109, 81110, 81111, - 81112, 81113, 81114, 81115, 81116, 81117, 81118, 81119, 81120, 81121, - 81122, 81123, 81124, 81125, 81126, 81127, 81128, 81129, 81130, 81131, - 81132, 81133, 81134, 81135, 81136, 81137, 81138, 81139, 81140, 81141, - 81142, 81143, 81144, 81145, 81146, 81147, 81148, 81149, 81150, 81151, - 81152, 81153, 81154, 81155, 81156, 81157, 81158, 81159, 81160, 81161, - 81162, 81163, 81164, 81165, 81166, 81167, 81168, 81169, 81170, 81171, - 81172, 81173, 81174, 81175, 81176, 81177, 81178, 81179, 81180, 81181, - 81182, 81183, 81184, 81185, 81186, 81187, 81188, 81189, 81190, 81191, - 81192, 81193, 81194, 81195, 81196, 81197, 81198, 81199, 81200, 81201, - 81202, 81203, 81204, 81205, 81206, 81207, 81208, 81209, 81210, 81211, - 81212, 81213, 81214, 81215, 81216, 81217, 81218, 81219, 81220, 81221, - 81222, 81223, 81224, 81225, 81226, 81227, 81228, 81229, 81230, 81231, - 81232, 81233, 81234, 81235, 81236, 81237, 81238, 81239, 81240, 81241, - 81242, 81243, 81244, 81245, 81246, 81247, 81248, 81249, 81250, 81251, - 81252, 81253, 81254, 81255, 81256, 81257, 81258, 81259, 81260, 81261, - 81262, 81263, 81264, 81265, 81266, 81267, 81268, 81269, 81270, 81271, - 81272, 81273, 81274, 81275, 81276, 81277, 81278, 81279, 81280, 81281, - 81282, 81283, 81284, 81285, 81286, 81287, 81288, 81289, 81290, 81291, - 81292, 81293, 81294, 81295, 81296, 81297, 81298, 81299, 81300, 81301, - 81302, 81303, 81304, 81305, 81306, 81307, 81308, 81309, 81310, 81311, - 81312, 81313, 81314, 81315, 81316, 81317, 81318, 81319, 81320, 81321, - 81322, 81323, 81324, 81325, 81326, 81327, 81328, 81329, 81330, 81331, - 81332, 81333, 81334, 81335, 81336, 81337, 81338, 81339, 81340, 81341, - 81342, 81343, 81344, 81345, 81346, 81347, 81348, 81349, 81350, 81351, - 81352, 81353, 81354, 81355, 81356, 81357, 81358, 81359, 81360, 81361, - 81362, 81363, 81364, 81365, 81366, 81367, 81368, 81369, 81370, 81371, - 81372, 81373, 81374, 81375, 81376, 81377, 81378, 81379, 81380, 81381, - 81382, 81383, 81384, 81385, 81386, 81387, 81388, 81389, 81390, 81391, - 81392, 81393, 81394, 81395, 81396, 81397, 81398, 81399, 81400, 81401, - 81402, 81403, 81404, 81405, 81406, 81407, 81408, 81409, 81410, 81411, - 81412, 81413, 81414, 81415, 81416, 81417, 81418, 81419, 81420, 81421, - 81422, 81423, 81424, 81425, 81426, 81427, 81428, 81429, 81430, 81431, - 81432, 81433, 81434, 81435, 81436, 81437, 81438, 81439, 81440, 81441, - 81442, 81443, 81444, 81445, 81446, 81447, 81448, 81449, 81450, 81451, - 81452, 81453, 81454, 81455, 81456, 81457, 81458, 81459, 81460, 81461, - 81462, 81463, 81464, 81465, 81466, 81467, 81468, 81469, 81470, 81471, - 81472, 81473, 81474, 81475, 81476, 81477, 81478, 81479, 81480, 81481, - 81482, 81483, 81484, 81485, 81486, 81487, 81488, 81489, 81490, 81491, - 81492, 81493, 81494, 81495, 81496, 81497, 81498, 81499, 81500, 81501, - 81502, 81503, 81504, 81505, 81506, 81507, 81508, 81509, 81510, 81511, - 81512, 81513, 81514, 81515, 81516, 81517, 81518, 81519, 81520, 81521, - 81522, 81523, 81524, 81525, 81526, 81527, 81528, 81529, 81530, 81531, - 81532, 81533, 81534, 81535, 81536, 81537, 81538, 81539, 81540, 81541, - 81542, 81543, 81544, 81545, 81546, 81547, 81548, 81549, 81550, 81551, - 81552, 81553, 81554, 81555, 81556, 81557, 81558, 81559, 81560, 81561, - 81562, 81563, 81564, 81565, 81566, 81567, 81568, 81569, 81570, 81571, - 81572, 81573, 81574, 81575, 81576, 81577, 81578, 81579, 81580, 81581, - 81582, 81583, 81584, 81585, 81586, 81587, 81588, 81589, 81590, 81591, - 81592, 81593, 81594, 81595, 81596, 81597, 81598, 81599, 81600, 81601, - 81602, 81603, 81604, 81605, 81606, 81607, 81608, 81609, 81610, 81611, - 81612, 81613, 81614, 81615, 81616, 81617, 81618, 81619, 81620, 81621, - 81622, 81623, 81624, 81625, 81626, 81627, 81628, 81629, 81630, 81631, - 81632, 81633, 81634, 81635, 81636, 81637, 81638, 81639, 81640, 81641, - 81642, 81643, 81644, 81645, 81646, 81647, 81648, 81649, 81650, 81651, - 81652, 81653, 81654, 81655, 81656, 81657, 81658, 81659, 81660, 81661, - 81662, 81663, 81664, 81665, 81666, 81667, 81668, 81669, 81670, 81671, - 81672, 81673, 81674, 81675, 81676, 81677, 81678, 81679, 81680, 81681, - 81682, 81683, 81684, 81685, 81686, 81687, 81688, 81689, 81690, 81691, - 81692, 81693, 81694, 81695, 81696, 81697, 81698, 81699, 81700, 81701, - 81702, 81703, 81704, 81705, 81706, 81707, 81708, 81709, 81710, 81711, - 81712, 81713, 81714, 81715, 81716, 81717, 81718, 81719, 81720, 81721, - 81722, 81723, 81724, 81725, 81726, 81727, 81728, 81729, 81730, 81731, - 81732, 81733, 81734, 81735, 81736, 81737, 81738, 81739, 81740, 81741, - 81742, 81743, 81744, 81745, 81746, 81747, 81748, 81749, 81750, 81751, - 81752, 81753, 81754, 81755, 81756, 81757, 81758, 81759, 81760, 81761, - 81762, 81763, 81764, 81765, 81766, 81767, 81768, 81769, 81770, 81771, - 81772, 81773, 81774, 81775, 81776, 81777, 81778, 81779, 81780, 81781, - 81782, 81783, 81784, 81785, 81786, 81787, 81788, 81789, 81790, 81791, - 81792, 81793, 81794, 81795, 81796, 81797, 81798, 81799, 81800, 81801, - 81802, 81803, 81804, 81805, 81806, 81807, 81808, 81809, 81810, 81811, - 81812, 81813, 81814, 81815, 81816, 81817, 81818, 81819, 81820, 81821, - 81822, 81823, 81824, 81825, 81826, 81827, 81828, 81829, 81830, 81831, - 81832, 81833, 81834, 81835, 81836, 81837, 81838, 81839, 81840, 81841, - 81842, 81843, 81844, 81845, 81846, 81847, 81848, 81849, 81850, 81851, - 81852, 81853, 81854, 81855, 81856, 81857, 81858, 81859, 81860, 81861, - 81862, 81863, 81864, 81865, 81866, 81867, 81868, 81869, 81870, 81871, - 81872, 81873, 81874, 81875, 81876, 81877, 81878, 81879, 81880, 81881, - 81882, 81883, 81884, 81885, 81886, 81887, 81888, 81889, 81890, 81891, - 81892, 81893, 81894, 81895, 81896, 81897, 81898, 81899, 81900, 81901, - 81902, 81903, 81904, 81905, 81906, 81907, 81908, 81909, 81910, 81911, - 81912, 81913, 81914, 81915, 81916, 81917, 81918, 81919, 82928, 82929, - 82930, 82931, 82932, 82933, 82934, 82935, 82936, 82937, 82938, 82688, - 82689, 82690, 82691, 82692, 82693, 82694, 82695, 82696, 82697, 82698, - 82699, 82700, 82701, 82702, 82703, 82704, 82705, 82706, 82707, 82708, - 82709, 82710, 82711, 82712, 82713, 82714, 82715, 82716, 82717, 82718, - 82719, 82720, 82721, 82722, 82723, 82724, 82725, 82726, 82727, 82728, - 82729, 82730, 82731, 82732, 82733, 82734, 82735, 82736, 82737, 82738, - 82739, 82740, 82741, 82742, 82743, 82744, 82745, 82746, 82747, 82748, - 82749, 82750, 82751, 82752, 82753, 82754, 82755, 82756, 82757, 82758, - 82759, 82760, 82761, 82762, 82763, 82764, 82765, 82766, 82767, 82768, - 82769, 82770, 82771, 82772, 82773, 82774, 82775, 82776, 82777, 82778, - 82779, 82780, 82781, 82782, 82783, 82784, 82785, 82786, 82787, 82788, - 82789, 82790, 82791, 82792, 82793, 82794, 82795, 82796, 82797, 82798, - 82799, 82800, 82801, 82802, 82803, 82804, 82805, 82806, 82807, 82808, - 82809, 82810, 82811, 82812, 82813, 82814, 82815, 82816, 82817, 82818, - 82819, 82820, 82821, 82822, 82823, 82824, 82825, 82826, 82827, 82828, - 82829, 82830, 82831, 82832, 82833, 82834, 82835, 82836, 82837, 82838, - 82839, 82840, 82841, 82842, 82843, 82844, 82845, 82846, 82847, 82848, - 82849, 82850, 82851, 82852, 82853, 82854, 82855, 82856, 82857, 82858, - 82859, 82860, 82861, 82862, 82863, 82864, 82865, 82866, 82867, 82868, - 82869, 82870, 82871, 82872, 82873, 82874, 82875, 82876, 82877, 82878, - 82879, 82880, 82881, 82882, 82883, 82884, 82885, 82886, 82887, 82888, - 82889, 82890, 82891, 82892, 82893, 82894, 82895, 82896, 82897, 82898, - 82899, 82900, 82901, 82902, 82903, 82904, 82905, 82906, 82907, 82908, - 82909, 82910, 82911, 82912, 82913, 82914, 82915, 82916, 82917, 82918, - 82919, 82920, 82921, 82922, 82923, 82924, 82925, 82926, 82927, 81920, - 81921, 81922, 81923, 81924, 81925, 81926, 81927, 81928, 81929, 81930, - 81931, 81932, 81933, 81934, 81935, 81936, 81937, 81938, 81939, 81940, - 81941, 81942, 81943, 81944, 81945, 81946, 81947, 81948, 81949, 81950, - 81951, 81952, 81953, 81954, 81955, 81956, 81957, 81958, 81959, 81960, - 81961, 81962, 81963, 81964, 81965, 81966, 81967, 81968, 81969, 81970, - 81971, 81972, 81973, 81974, 81975, 81976, 81977, 81978, 81979, 81980, - 81981, 81982, 81983, 81984, 81985, 81986, 81987, 81988, 81989, 81990, - 81991, 81992, 81993, 81994, 81995, 81996, 81997, 81998, 81999, 82000, - 82001, 82002, 82003, 82004, 82005, 82006, 82007, 82008, 82009, 82010, - 82011, 82012, 82013, 82014, 82015, 82016, 82017, 82018, 82019, 82020, - 82021, 82022, 82023, 82024, 82025, 82026, 82027, 82028, 82029, 82030, - 82031, 82032, 82033, 82034, 82035, 82036, 82037, 82038, 82039, 82040, - 82041, 82042, 82043, 82044, 82045, 82046, 82047, 82048, 82049, 82050, - 82051, 82052, 82053, 82054, 82055, 82056, 82057, 82058, 82059, 82060, - 82061, 82062, 82063, 82064, 82065, 82066, 82067, 82068, 82069, 82070, - 82071, 82072, 82073, 82074, 82075, 82076, 82077, 82078, 82079, 82080, - 82081, 82082, 82083, 82084, 82085, 82086, 82087, 82088, 82089, 82090, - 82091, 82092, 82093, 82094, 82095, 82096, 82097, 82098, 82099, 82100, - 82101, 82102, 82103, 82104, 82105, 82106, 82107, 82108, 82109, 82110, - 82111, 82112, 82113, 82114, 82115, 82116, 82117, 82118, 82119, 82120, - 82121, 82122, 82123, 82124, 82125, 82126, 82127, 82128, 82129, 82130, - 82131, 82132, 82133, 82134, 82135, 82136, 82137, 82138, 82139, 82140, - 82141, 82142, 82143, 82144, 82145, 82146, 82147, 82148, 82149, 82150, - 82151, 82152, 82153, 82154, 82155, 82156, 82157, 82158, 82159, 82160, - 82161, 82162, 82163, 82164, 82165, 82166, 82167, 82168, 82169, 82170, - 82171, 82172, 82173, 82174, 82175, 82176, 82177, 82178, 82179, 82180, - 82181, 82182, 82183, 82184, 82185, 82186, 82187, 82188, 82189, 82190, - 82191, 82192, 82193, 82194, 82195, 82196, 82197, 82198, 82199, 82200, - 82201, 82202, 82203, 82204, 82205, 82206, 82207, 82208, 82209, 82210, - 82211, 82212, 82213, 82214, 82215, 82216, 82217, 82218, 82219, 82220, - 82221, 82222, 82223, 82224, 82225, 82226, 82227, 82228, 82229, 82230, - 82231, 82232, 82233, 82234, 82235, 82236, 82237, 82238, 82239, 82240, - 82241, 82242, 82243, 82244, 82245, 82246, 82247, 82248, 82249, 82250, - 82251, 82252, 82253, 82254, 82255, 82256, 82257, 82258, 82259, 82260, - 82261, 82262, 82263, 82264, 82265, 82266, 82267, 82268, 82269, 82270, - 82271, 82272, 82273, 82274, 82275, 82276, 82277, 82278, 82279, 82280, - 82281, 82282, 82283, 82284, 82285, 82286, 82287, 82288, 82289, 82290, - 82291, 82292, 82293, 82294, 82295, 82296, 82297, 82298, 82299, 82300, - 82301, 82302, 82303, 82304, 82305, 82306, 82307, 82308, 82309, 82310, - 82311, 82312, 82313, 82314, 82315, 82316, 82317, 82318, 82319, 82320, - 82321, 82322, 82323, 82324, 82325, 82326, 82327, 82328, 82329, 82330, - 82331, 82332, 82333, 82334, 82335, 82336, 82337, 82338, 82339, 82340, - 82341, 82342, 82343, 82344, 82345, 82346, 82347, 82348, 82349, 82350, - 82351, 82352, 82353, 82354, 82355, 82356, 82357, 82358, 82359, 82360, - 82361, 82362, 82363, 82364, 82365, 82366, 82367, 82368, 82369, 82370, - 82371, 82372, 82373, 82374, 82375, 82376, 82377, 82378, 82379, 82380, - 82381, 82382, 82383, 82384, 82385, 82386, 82387, 82388, 82389, 82390, - 82391, 82392, 82393, 82394, 82395, 82396, 82397, 82398, 82399, 82400, - 82401, 82402, 82403, 82404, 82405, 82406, 82407, 82408, 82409, 82410, - 82411, 82412, 82413, 82414, 82415, 82416, 82417, 82418, 82419, 82420, - 82421, 82422, 82423, 82424, 82425, 82426, 82427, 82428, 82429, 82430, - 82431, 82432, 82433, 82434, 82435, 82436, 82437, 82438, 82439, 82440, - 82441, 82442, 82443, 82444, 82445, 82446, 82447, 82448, 82449, 82450, - 82451, 82452, 82453, 82454, 82455, 82456, 82457, 82458, 82459, 82460, - 82461, 82462, 82463, 82464, 82465, 82466, 82467, 82468, 82469, 82470, - 82471, 82472, 82473, 82474, 82475, 82476, 82477, 82478, 82479, 82480, - 82481, 82482, 82483, 82484, 82485, 82486, 82487, 82488, 82489, 82490, - 82491, 82492, 82493, 82494, 82495, 82496, 82497, 82498, 82499, 82500, - 82501, 82502, 82503, 82504, 82505, 82506, 82507, 82508, 82509, 82510, - 82511, 82512, 82513, 82514, 82515, 82516, 82517, 82518, 82519, 82520, - 82521, 82522, 82523, 82524, 82525, 82526, 82527, 82528, 82529, 82530, - 82531, 82532, 82533, 82534, 82535, 82536, 82537, 82538, 82539, 82540, - 82541, 82542, 82543, 82544, 82545, 82546, 82547, 82548, 82549, 82550, - 82551, 82552, 82553, 82554, 82555, 82556, 82557, 82558, 82559, 82560, - 82561, 82562, 82563, 82564, 82565, 82566, 82567, 82568, 82569, 82570, - 82571, 82572, 82573, 82574, 82575, 82576, 82577, 82578, 82579, 82580, - 82581, 82582, 82583, 82584, 82585, 82586, 82587, 82588, 82589, 82590, - 82591, 82592, 82593, 82594, 82595, 82596, 82597, 82598, 82599, 82600, - 82601, 82602, 82603, 82604, 82605, 82606, 82607, 82608, 82609, 82610, - 82611, 82612, 82613, 82614, 82615, 82616, 82617, 82618, 82619, 82620, - 82621, 82622, 82623, 82624, 82625, 82626, 82627, 82628, 82629, 82630, - 82631, 82632, 82633, 82634, 82635, 82636, 82637, 82638, 82639, 82640, - 82641, 82642, 82643, 82644, 82645, 82646, 82647, 82648, 82649, 82650, - 82651, 82652, 82653, 82654, 82655, 82656, 82657, 82658, 82659, 82660, - 82661, 82662, 82663, 82664, 82665, 82666, 82667, 82668, 82669, 82670, - 82671, 82672, 82673, 82674, 82675, 82676, 82677, 82678, 82679, 82680, - 82681, 82682, 82683, 82684, 82685, 82686, 82687, 129370, 10037, 10039, - 10036, 10049, 117865, 117866, 10058, 10035, 9834, 66854, 66853, 66827, - 66826, 66833, 66832, 66821, 66837, 66836, 66835, 66842, 66841, 66824, - 66823, 66819, 66818, 66822, 66820, 66855, 66831, 66844, 66843, 66846, - 66845, 66852, 66851, 66817, 66825, 66828, 66830, 66834, 66839, 66840, - 66848, 66849, 66816, 66829, 66838, 66847, 66850, 128268, 128294, 128161, - 8961, 9191, 8712, 8946, 8953, 8947, 8952, 8950, 8949, 10969, 10194, - 128024, 128727, 69608, 69621, 69603, 69611, 69618, 69619, 69600, 69615, - 69602, 69606, 69614, 69617, 69620, 69609, 69604, 69607, 69610, 69601, - 69613, 69605, 69616, 69612, 69622, 129501, 983101, 129456, 129457, - 129459, 129458, 127995, 127996, 127997, 127998, 127999, 128453, 128454, - 128455, 129721, 128460, 128461, 8709, 10675, 10676, 10674, 10673, 128459, - 9091, 8193, 8212, 8195, 8192, 8211, 8194, 983179, 8718, 983178, 983135, - 983099, 983048, 983095, 983046, 983064, 128282, 983051, 983050, 9993, - 128388, 128233, 9094, 983067, 983100, 983049, 8926, 8927, 8925, 8924, - 8797, 8917, 61, 10865, 10867, 11072, 10609, 10723, 10724, 10926, 11257, - 10871, 10854, 10862, 8789, 10872, 8781, 8794, 10738, 10736, 10734, 10739, - 10737, 10735, 11249, 11248, 9003, 8998, 983105, 983104, 8494, 8793, - 983136, 4957, 4959, 4958, 4963, 4965, 4978, 4988, 4980, 4979, 4987, 4985, - 4982, 4981, 4986, 4984, 4983, 4968, 4966, 4964, 4960, 4999, 4998, 4711, - 4997, 43816, 43819, 43821, 43820, 43818, 43822, 43817, 4704, 4707, 4710, - 11653, 4709, 4708, 4706, 4705, 43808, 43811, 43813, 43812, 43810, 43814, - 43809, 11704, 11707, 11709, 11708, 11706, 11710, 11705, 11688, 11691, - 11693, 11692, 11690, 11694, 11689, 4904, 4907, 4910, 11664, 4909, 4908, - 4911, 4906, 4905, 4728, 4731, 4734, 11655, 4733, 4732, 4735, 4730, 4729, - 43789, 43788, 43787, 43786, 43790, 43785, 4856, 4859, 4862, 11661, 4861, - 4860, 4863, 4858, 4857, 43797, 43796, 43795, 43794, 43798, 43793, 4848, - 4851, 4854, 11660, 4853, 4852, 4855, 4850, 4849, 5003, 5002, 4943, 5001, - 4936, 4939, 4941, 4940, 4954, 4938, 4942, 4937, 4873, 124916, 124915, - 124924, 124923, 124910, 124909, 124926, 124925, 124922, 124921, 124920, - 124919, 124918, 124917, 124914, 124913, 124912, 124904, 11667, 4895, - 11670, 11669, 11668, 4888, 4891, 4893, 4892, 4890, 4894, 4889, 4768, - 4771, 4774, 11658, 4773, 4772, 4775, 4770, 4769, 4880, 4883, 4885, 4884, - 4882, 11736, 11739, 11741, 11740, 11738, 11742, 11737, 4872, 4875, 4878, - 4879, 4877, 4876, 4874, 124907, 124906, 4631, 124905, 124896, 124899, - 124901, 124900, 124898, 124902, 124897, 4624, 4627, 4629, 4628, 4626, - 4630, 4625, 4608, 4611, 4614, 4615, 4613, 4612, 4610, 4609, 4800, 4803, - 4805, 4804, 4802, 4792, 4795, 4797, 4796, 4794, 4798, 4793, 4784, 4787, - 4789, 4788, 4786, 11720, 11723, 11725, 11724, 11722, 11726, 11721, 4776, - 4779, 4782, 4783, 4781, 4780, 4778, 4777, 4995, 4994, 4639, 4993, 4632, - 4635, 4638, 11649, 4637, 4636, 4953, 4634, 4633, 4760, 4763, 4766, 11657, - 4765, 4764, 4767, 4762, 4761, 4752, 4755, 4758, 11656, 4757, 4756, 4759, - 4754, 4753, 4912, 4816, 4819, 4821, 4820, 4818, 4822, 4817, 4915, 4918, - 11665, 4917, 4916, 4919, 4914, 4913, 5007, 5006, 4951, 5005, 4944, 4947, - 4950, 11666, 4949, 4948, 4946, 4945, 4696, 4699, 4701, 4700, 4698, 4688, - 4691, 4693, 4692, 4690, 4694, 4689, 4680, 4683, 4685, 4684, 4682, 11712, - 11715, 11717, 11716, 11714, 11718, 11713, 4672, 4675, 4678, 4679, 4677, - 4676, 4674, 4673, 4648, 4651, 4654, 11650, 4653, 4652, 4655, 4952, 4650, - 4649, 4661, 4996, 5000, 4992, 5004, 4660, 4664, 4667, 4670, 11652, 4669, - 4668, 4671, 4666, 4665, 4640, 4643, 4645, 4644, 4647, 4642, 4646, 4641, - 11680, 11683, 11685, 11684, 11682, 11686, 11681, 4656, 4659, 4662, 11651, - 4663, 4658, 4657, 4896, 4899, 4902, 11663, 4901, 4900, 4903, 4898, 4897, - 43781, 43780, 43779, 43778, 43782, 43777, 4928, 4931, 4934, 4935, 4933, - 4932, 4930, 4929, 4920, 4923, 4925, 4924, 4927, 4922, 4926, 4921, 4720, - 4723, 4726, 11654, 4725, 4724, 4727, 4722, 4721, 4864, 4867, 4870, 11662, - 4869, 4868, 4871, 4866, 4865, 4616, 4619, 4622, 11648, 4621, 4620, 4623, - 4618, 4617, 4808, 4811, 4814, 4815, 4813, 4812, 4810, 4809, 4840, 4843, - 4846, 4847, 4845, 4844, 4842, 4841, 4744, 4747, 4749, 4748, 4746, 11728, - 11731, 11733, 11732, 11730, 11734, 11729, 4736, 4739, 4742, 4743, 4741, - 4740, 4738, 4737, 4832, 4835, 4837, 4836, 4839, 4834, 4838, 4833, 11696, - 11699, 11701, 11700, 11698, 11702, 11697, 4824, 4827, 4830, 11659, 4829, - 4828, 4831, 4826, 4825, 4712, 4715, 4717, 4716, 4719, 4714, 4718, 4713, - 5009, 5016, 5012, 5015, 5013, 5017, 5010, 5011, 5014, 5008, 4973, 4972, - 4975, 4974, 4971, 4970, 4977, 4969, 4976, 4962, 4967, 4961, 983096, - 983047, 127984, 127972, 8352, 8364, 8455, 8265, 33, 8761, 118269, 118270, + 127919, 128549, 128542, 9933, 9090, 129770, 129400, 72004, 72021, 72020, + 72023, 72022, 72019, 72018, 72016, 72025, 72017, 72024, 71964, 71958, + 71963, 71974, 71973, 71936, 71937, 71961, 71960, 71966, 71965, 71940, + 71941, 71938, 71939, 71982, 71976, 71952, 71962, 71957, 71967, 71978, + 71979, 71980, 71971, 71970, 71954, 71953, 71951, 71950, 71949, 71948, + 71969, 71968, 71981, 71955, 71972, 71975, 71977, 71983, 71942, 71945, + 71997, 71996, 72003, 71995, 71984, 71991, 71987, 71988, 71985, 71986, + 71989, 71992, 71998, 72002, 72000, 72005, 72006, 71999, 72001, 8725, 247, + 8903, 129343, 8739, 9902, 129684, 128171, 128565, 12291, 8783, 9009, + 128462, 128441, 128442, 128443, 8939, 8941, 8716, 8740, 10990, 8832, + 8928, 8876, 8833, 8929, 8878, 128021, 71680, 71681, 71687, 71689, 71703, + 71702, 71708, 71707, 71723, 71716, 71701, 71700, 71706, 71705, 71684, + 71685, 71682, 71683, 71694, 71704, 71699, 71709, 71719, 71720, 71721, + 71713, 71712, 71696, 71695, 71693, 71692, 71698, 71697, 71691, 71690, + 71711, 71710, 71722, 71717, 71714, 71718, 71715, 71686, 71688, 71729, + 71730, 71724, 71732, 71734, 71727, 71728, 71725, 71726, 71731, 71733, + 71739, 71738, 71735, 71737, 71736, 128054, 128044, 36, 127025, 127026, + 127027, 127028, 127029, 127030, 127031, 127032, 127033, 127034, 127035, + 127036, 127037, 127038, 127039, 127040, 127041, 127042, 127043, 127044, + 127045, 127046, 127047, 127048, 127049, 127050, 127051, 127052, 127053, + 127054, 127055, 127056, 127057, 127058, 127059, 127060, 127061, 127062, + 127063, 127064, 127065, 127066, 127067, 127068, 127069, 127070, 127071, + 127072, 127073, 127024, 127075, 127076, 127077, 127078, 127079, 127080, + 127081, 127082, 127083, 127084, 127085, 127086, 127087, 127088, 127089, + 127090, 127091, 127092, 127093, 127094, 127095, 127096, 127097, 127098, + 127099, 127100, 127101, 127102, 127103, 127104, 127105, 127106, 127107, + 127108, 127109, 127110, 127111, 127112, 127113, 127114, 127115, 127116, + 127117, 127118, 127119, 127120, 127121, 127122, 127123, 127074, 129743, + 8363, 8724, 8760, 8901, 729, 9676, 8284, 11850, 11034, 129765, 11795, + 11784, 10649, 11798, 9470, 9465, 9464, 9467, 9466, 9463, 9462, 9469, + 9461, 9468, 10175, 10868, 10986, 8225, 8223, 11840, 8914, 8748, 11842, + 8222, 8215, 10835, 10836, 10645, 10913, 10915, 10914, 10939, 8243, 12318, + 10746, 10830, 10831, 11849, 10988, 11844, 10940, 8913, 8912, 11005, + 10987, 8915, 9208, 10981, 8875, 10979, 8214, 11799, 10646, 733, 8252, + 8263, 65100, 10908, 10907, 11002, 11001, 10906, 10905, 8510, 8473, 8511, + 8450, 8461, 8469, 8474, 8477, 8484, 8518, 8519, 8520, 8521, 8517, 8509, + 8508, 8512, 10719, 9890, 9891, 11260, 127849, 8868, 10993, 10623, 8945, + 8964, 117764, 128317, 117859, 118264, 117883, 118268, 117849, 128315, + 117914, 117864, 10728, 10729, 117875, 117879, 129288, 129290, 129289, + 129291, 8595, 8629, 8671, 129035, 129031, 129179, 129043, 129027, 129047, + 8626, 8627, 10504, 8693, 129975, 8615, 10515, 11796, 11015, 129203, + 11147, 11107, 11139, 11123, 129067, 11168, 11169, 129063, 129059, 129075, + 129071, 11133, 11085, 11117, 11143, 129171, 10507, 8609, 11247, 8681, + 129175, 8623, 8659, 8675, 129079, 10597, 10607, 10593, 10585, 8643, + 10589, 10581, 8642, 129091, 129095, 129087, 10225, 128623, 129107, + 129083, 8650, 128687, 128330, 128682, 129444, 8367, 10139, 128009, + 128050, 128042, 129656, 128167, 129316, 129345, 9946, 128087, 113784, + 113788, 113785, 113783, 113782, 113786, 113787, 113795, 113798, 113793, + 113800, 113781, 113794, 113792, 113799, 113797, 113796, 113776, 113808, + 113817, 113811, 113814, 113809, 113816, 113779, 113810, 113815, 113813, + 113812, 113778, 113777, 113780, 113729, 113733, 113672, 113677, 113683, + 113735, 113739, 113746, 113668, 113678, 113674, 113726, 113691, 113699, + 113700, 113695, 113709, 113712, 113713, 113705, 113711, 113669, 113725, + 113679, 113684, 113670, 113743, 113749, 113687, 113689, 113693, 113707, + 113697, 113703, 113690, 113694, 113708, 113698, 113704, 113764, 113763, + 113762, 113761, 113732, 113753, 113731, 113755, 113754, 113666, 113766, + 113765, 113676, 113675, 113741, 113750, 113680, 113688, 113692, 113696, + 113710, 113727, 113728, 113716, 113717, 113714, 113715, 113701, 113702, + 113724, 113723, 113706, 113742, 113740, 113767, 113769, 113730, 113768, + 113682, 113685, 113752, 113737, 113667, 113719, 113718, 113681, 113745, + 113748, 113751, 113738, 113673, 113770, 113720, 113757, 113760, 113722, + 113759, 113756, 113721, 113758, 113665, 113747, 113664, 113686, 113734, + 113736, 113744, 113671, 113821, 113822, 113823, 113820, 129375, 129414, + 129516, 128192, 983082, 128066, 127805, 127806, 129467, 9793, 127758, + 127759, 127757, 9178, 9841, 129413, 11790, 77830, 77831, 77832, 77828, + 77829, 77824, 77825, 77826, 77827, 77833, 77834, 77835, 77840, 77841, + 77844, 77845, 77836, 77837, 77838, 77839, 77842, 77843, 77846, 77847, + 77869, 77870, 77872, 77873, 77874, 77875, 77877, 77878, 77871, 77876, + 77879, 77880, 77881, 77882, 77860, 77861, 77858, 77859, 77862, 77863, + 77864, 77865, 77866, 77867, 77868, 77903, 77848, 77849, 77850, 77851, + 77852, 77853, 77854, 77855, 77856, 77857, 77883, 77884, 77885, 77886, + 77887, 77888, 77889, 77890, 77891, 77892, 77893, 77894, 77895, 77896, + 77897, 77898, 77899, 77900, 77901, 77902, 78867, 78868, 78869, 78861, + 78862, 78863, 78864, 78865, 78866, 78870, 78871, 78892, 78893, 78894, + 78872, 78873, 78874, 78875, 78876, 78877, 78878, 78879, 78880, 78881, + 78882, 78883, 78884, 78885, 78886, 78887, 78888, 78889, 78890, 78891, + 78910, 78908, 78903, 77908, 77909, 77904, 77905, 77906, 77907, 77910, + 77911, 77912, 77913, 77915, 77916, 77917, 77918, 77914, 77919, 77920, + 77921, 77922, 77923, 77924, 77925, 77926, 77927, 77928, 77929, 77930, + 77931, 77932, 77933, 77934, 77935, 77936, 77937, 77938, 77939, 77940, + 77941, 77949, 77950, 77942, 77943, 77944, 77945, 77946, 77947, 77948, + 77951, 77974, 77975, 77978, 77979, 77973, 77976, 77977, 77980, 77981, + 77982, 77983, 77984, 77991, 77992, 77994, 77995, 77985, 77986, 77987, + 77988, 77989, 77990, 77993, 77996, 77997, 77998, 77999, 78000, 78001, + 78002, 78003, 78004, 78005, 78006, 78008, 78009, 78011, 78012, 78007, + 78010, 78013, 78014, 78015, 78016, 78017, 78025, 78026, 78027, 78028, + 78029, 78030, 78031, 78032, 78033, 78018, 78019, 78020, 78021, 78022, + 78023, 78024, 77969, 77970, 77962, 77963, 77964, 77965, 77966, 77967, + 77968, 77971, 77972, 77952, 77953, 77954, 77955, 77956, 77957, 77958, + 77959, 77960, 77961, 78041, 78042, 78043, 78044, 78034, 78035, 78036, + 78037, 78038, 78039, 78040, 78057, 78058, 78066, 78067, 78059, 78060, + 78061, 78062, 78063, 78064, 78065, 78068, 78073, 78074, 78069, 78070, + 78071, 78072, 78075, 78076, 78077, 78051, 78052, 78053, 78054, 78045, + 78046, 78047, 78048, 78049, 78050, 78055, 78056, 78911, 78909, 78904, + 78078, 78079, 78080, 78081, 78082, 78083, 78084, 78085, 78086, 78087, + 78091, 78092, 78088, 78089, 78090, 78093, 78094, 78095, 78096, 78097, + 78098, 78111, 78112, 78118, 78119, 78120, 78121, 78110, 78113, 78114, + 78115, 78116, 78117, 78122, 78128, 78129, 78130, 78131, 78132, 78133, + 78123, 78124, 78125, 78126, 78127, 78134, 78135, 78137, 78138, 78139, + 78140, 78136, 78141, 78142, 78100, 78101, 78099, 78102, 78103, 78104, + 78105, 78106, 78107, 78108, 78109, 78913, 78150, 78151, 78152, 78148, + 78149, 78143, 78144, 78145, 78146, 78147, 78153, 78154, 78156, 78157, + 78155, 78158, 78159, 78160, 78161, 78162, 78163, 78164, 78165, 78184, + 78185, 78186, 78187, 78178, 78179, 78180, 78181, 78182, 78183, 78188, + 78189, 78193, 78194, 78196, 78197, 78190, 78191, 78192, 78195, 78198, + 78199, 78200, 78201, 78166, 78167, 78173, 78174, 78168, 78169, 78170, + 78171, 78172, 78175, 78176, 78177, 78202, 78203, 78204, 78205, 78206, + 78212, 78213, 78207, 78208, 78209, 78210, 78211, 78214, 78215, 78914, + 78916, 78897, 78220, 78221, 78225, 78226, 78216, 78217, 78218, 78219, + 78222, 78223, 78224, 78227, 78228, 78229, 78230, 78231, 78232, 78233, + 78234, 78907, 78901, 78899, 78906, 78900, 78898, 78905, 78244, 78245, + 78249, 78250, 78243, 78246, 78247, 78248, 78251, 78252, 78915, 78253, + 78254, 78255, 78257, 78258, 78256, 78259, 78260, 78261, 78262, 78263, + 78264, 78268, 78269, 78270, 78271, 78272, 78273, 78274, 78275, 78276, + 78265, 78266, 78279, 78280, 78281, 78282, 78283, 78284, 78267, 78277, + 78278, 78285, 78286, 78289, 78290, 78292, 78293, 78297, 78298, 78287, + 78288, 78291, 78294, 78295, 78296, 78299, 78304, 78305, 78306, 78301, + 78302, 78300, 78303, 78307, 78308, 78309, 78310, 78311, 78312, 78313, + 78314, 78315, 78316, 78317, 78318, 78933, 78928, 78920, 78924, 78932, + 78926, 78921, 78929, 78925, 78923, 78931, 78919, 78927, 78922, 78930, + 78912, 78336, 78337, 78338, 78328, 78329, 78330, 78331, 78332, 78333, + 78334, 78335, 78339, 78354, 78355, 78356, 78357, 78358, 78359, 78361, + 78362, 78351, 78352, 78353, 78360, 78363, 78364, 78345, 78346, 78340, + 78341, 78342, 78343, 78344, 78347, 78348, 78349, 78350, 78365, 78366, + 78367, 78319, 78320, 78321, 78322, 78323, 78324, 78325, 78326, 78327, + 78372, 78373, 78368, 78369, 78370, 78371, 78374, 78375, 78376, 78377, + 78385, 78386, 78378, 78379, 78380, 78381, 78382, 78383, 78384, 78387, + 78388, 78389, 78399, 78400, 78401, 78402, 78409, 78410, 78403, 78404, + 78405, 78406, 78407, 78408, 78411, 78414, 78415, 78412, 78413, 78390, + 78391, 78392, 78393, 78394, 78395, 78396, 78397, 78398, 78423, 78424, + 78425, 78426, 78427, 78428, 78429, 78416, 78417, 78421, 78422, 78418, + 78419, 78420, 78430, 78431, 78432, 78433, 78434, 78435, 78436, 78445, + 78446, 78437, 78438, 78439, 78440, 78441, 78442, 78443, 78444, 78447, + 78448, 78452, 78453, 78454, 78455, 78459, 78460, 78449, 78450, 78451, + 78456, 78457, 78458, 78469, 78470, 78471, 78472, 78473, 78461, 78462, + 78465, 78466, 78463, 78464, 78467, 78468, 78474, 78475, 78476, 78487, + 78488, 78489, 78490, 78477, 78478, 78479, 78480, 78481, 78482, 78483, + 78484, 78485, 78486, 78902, 78491, 78492, 78494, 78495, 78493, 78496, + 78497, 78498, 78499, 78500, 78501, 78502, 78503, 78514, 78515, 78516, + 78512, 78513, 78511, 78517, 78518, 78519, 78520, 78521, 78522, 78523, + 78524, 78530, 78531, 78525, 78526, 78527, 78528, 78529, 78532, 78533, + 78534, 78535, 78536, 78537, 78538, 78539, 78540, 78541, 78542, 78543, + 78544, 78546, 78547, 78551, 78552, 78545, 78548, 78549, 78550, 78553, + 78554, 78555, 78560, 78561, 78562, 78565, 78566, 78556, 78557, 78558, + 78559, 78563, 78564, 78567, 78568, 78575, 78576, 78577, 78569, 78570, + 78571, 78572, 78573, 78574, 78578, 78579, 78580, 78586, 78587, 78581, + 78582, 78583, 78584, 78585, 78588, 78589, 78590, 78591, 78592, 78593, + 78594, 78595, 78596, 78597, 78598, 78601, 78602, 78606, 78607, 78608, + 78609, 78610, 78611, 78599, 78600, 78603, 78604, 78605, 78613, 78614, + 78619, 78620, 78612, 78615, 78616, 78617, 78618, 78621, 78622, 78623, + 78636, 78637, 78638, 78639, 78634, 78635, 78640, 78641, 78642, 78624, + 78625, 78626, 78627, 78628, 78629, 78630, 78631, 78632, 78633, 78917, + 78648, 78649, 78650, 78643, 78644, 78645, 78646, 78647, 78651, 78652, + 78653, 78667, 78668, 78674, 78675, 78664, 78665, 78666, 78669, 78670, + 78671, 78672, 78673, 78678, 78679, 78676, 78677, 78680, 78681, 78682, + 78683, 78684, 78685, 78686, 78687, 78688, 78689, 78654, 78655, 78656, + 78657, 78658, 78659, 78660, 78661, 78662, 78663, 78706, 78707, 78708, + 78690, 78691, 78692, 78693, 78694, 78695, 78696, 78697, 78698, 78699, + 78700, 78701, 78702, 78703, 78704, 78705, 78709, 78710, 78712, 78713, + 78714, 78715, 78895, 78716, 78717, 78718, 78711, 78719, 78720, 78721, + 78722, 78723, 78724, 78725, 78726, 78727, 78728, 78729, 78730, 78731, + 78732, 78733, 78734, 78735, 78736, 78737, 78738, 78741, 78742, 78747, + 78748, 78749, 78750, 78739, 78740, 78743, 78744, 78745, 78746, 78751, + 78752, 78753, 78754, 78756, 78757, 78761, 78762, 78755, 78758, 78759, + 78760, 78763, 78764, 78765, 78766, 78896, 78769, 78770, 78776, 78777, + 78767, 78768, 78771, 78772, 78773, 78774, 78775, 78778, 78779, 78783, + 78784, 78787, 78788, 78789, 78790, 78780, 78781, 78782, 78785, 78786, + 78791, 78796, 78797, 78792, 78793, 78794, 78795, 78798, 78918, 78802, + 78803, 78804, 78806, 78807, 78809, 78810, 78799, 78800, 78801, 78805, + 78808, 78811, 78812, 78813, 78814, 78815, 78816, 78817, 78818, 78819, + 78821, 78822, 78823, 78824, 78825, 78826, 78827, 78828, 78829, 78830, + 78831, 78832, 78820, 78833, 78834, 78835, 78836, 78842, 78843, 78844, + 78845, 78846, 78847, 78848, 78849, 78850, 78851, 78852, 78853, 78854, + 78855, 78856, 78857, 78858, 78859, 78860, 78837, 78838, 78839, 78840, + 78841, 78235, 78236, 78237, 78238, 78239, 78240, 78241, 78242, 78504, + 78505, 78506, 78507, 78508, 78509, 78510, 78944, 78945, 78946, 78947, + 78948, 78949, 78950, 78951, 78952, 78953, 78954, 78955, 78956, 78957, + 78958, 78959, 78960, 78961, 78962, 78963, 78964, 78965, 78966, 78967, + 78968, 78969, 78970, 78971, 78972, 78973, 78974, 78975, 78976, 78977, + 78978, 78979, 78980, 78981, 78982, 78983, 78984, 78985, 78986, 78987, + 78988, 78989, 78990, 78991, 78992, 78993, 78994, 78995, 78996, 78997, + 78998, 78999, 79000, 79001, 79002, 79003, 79004, 79005, 79006, 79007, + 79008, 79009, 79010, 79011, 79012, 79013, 79014, 79015, 79016, 79017, + 79018, 79019, 79020, 79021, 79022, 79023, 79024, 79025, 79026, 79027, + 79028, 79029, 79030, 79031, 79032, 79033, 79034, 79035, 79036, 79037, + 79038, 79039, 79040, 79041, 79042, 79043, 79044, 79045, 79046, 79047, + 79048, 79049, 79050, 79051, 79052, 79053, 79054, 79055, 79056, 79057, + 79058, 79059, 79060, 79061, 79062, 79063, 79064, 79065, 79066, 79067, + 79068, 79069, 79070, 79071, 79072, 79073, 79074, 79075, 79076, 79077, + 79078, 79079, 79080, 79081, 79082, 79083, 79084, 79085, 79086, 79087, + 79088, 79089, 79090, 79091, 79092, 79093, 79094, 79095, 79096, 79097, + 79098, 79099, 79100, 79101, 79102, 79103, 79104, 79105, 79106, 79107, + 79108, 79109, 79110, 79111, 79112, 79113, 79114, 79115, 79116, 79117, + 79118, 79119, 79120, 79121, 79122, 79123, 79124, 79125, 79126, 79127, + 79128, 79129, 79130, 79131, 79132, 79133, 79134, 79135, 79136, 79137, + 79138, 79139, 79140, 79141, 79142, 79143, 79144, 79145, 79146, 79147, + 79148, 79149, 79150, 79151, 79152, 79153, 79154, 79155, 79156, 79157, + 79158, 79159, 79160, 79161, 79162, 79163, 79164, 79165, 79166, 79167, + 79168, 79169, 79170, 79171, 79172, 79173, 79174, 79175, 79176, 79177, + 79178, 79179, 79180, 79181, 79182, 79183, 79184, 79185, 79186, 79187, + 79188, 79189, 79190, 79191, 79192, 79193, 79194, 79195, 79196, 79197, + 79198, 79199, 79200, 79201, 79202, 79203, 79204, 79205, 79206, 79207, + 79208, 79209, 79210, 79211, 79212, 79213, 79214, 79215, 79216, 79217, + 79218, 79219, 79220, 79221, 79222, 79223, 79224, 79225, 79226, 79227, + 79228, 79229, 79230, 79231, 79232, 79233, 79234, 79235, 79236, 79237, + 79238, 79239, 79240, 79241, 79242, 79243, 79244, 79245, 79246, 79247, + 79248, 79249, 79250, 79251, 79252, 79253, 79254, 79255, 79256, 79257, + 79258, 79259, 79260, 79261, 79262, 79263, 79264, 79265, 79266, 79267, + 79268, 79269, 79270, 79271, 79272, 79273, 79274, 79275, 79276, 79277, + 79278, 79279, 79280, 79281, 79282, 79283, 79284, 79285, 79286, 79287, + 79288, 79289, 79290, 79291, 79292, 79293, 79294, 79295, 79296, 79297, + 79298, 79299, 79300, 79301, 79302, 79303, 79304, 79305, 79306, 79307, + 79308, 79309, 79310, 79311, 79312, 79313, 79314, 79315, 79316, 79317, + 79318, 79319, 79320, 79321, 79322, 79323, 79324, 79325, 79326, 79327, + 79328, 79329, 79330, 79331, 79332, 79333, 79334, 79335, 79336, 79337, + 79338, 79339, 79340, 79341, 79342, 79343, 79344, 79345, 79346, 79347, + 79348, 79349, 79350, 79351, 79352, 79353, 79354, 79355, 79356, 79357, + 79358, 79359, 79360, 79361, 79362, 79363, 79364, 79365, 79366, 79367, + 79368, 79369, 79370, 79371, 79372, 79373, 79374, 79375, 79376, 79377, + 79378, 79379, 79380, 79381, 79382, 79383, 79384, 79385, 79386, 79387, + 79388, 79389, 79390, 79391, 79392, 79393, 79394, 79395, 79396, 79397, + 79398, 79399, 79400, 79401, 79402, 79403, 79404, 79405, 79406, 79407, + 79408, 79409, 79410, 79411, 79412, 79413, 79414, 79415, 79416, 79417, + 79418, 79419, 79420, 79421, 79422, 79423, 79424, 79425, 79426, 79427, + 79428, 79429, 79430, 79431, 79432, 79433, 79434, 79435, 79436, 79437, + 79438, 79439, 79440, 79441, 79442, 79443, 79444, 79445, 79446, 79447, + 79448, 79449, 79450, 79451, 79452, 79453, 79454, 79455, 79456, 79457, + 79458, 79459, 79460, 79461, 79462, 79463, 79464, 79465, 79466, 79467, + 79468, 79469, 79470, 79471, 79472, 79473, 79474, 79475, 79476, 79477, + 79478, 79479, 79480, 79481, 79482, 79483, 79484, 79485, 79486, 79487, + 79488, 79489, 79490, 79491, 79492, 79493, 79494, 79495, 79496, 79497, + 79498, 79499, 79500, 79501, 79502, 79503, 79504, 79505, 79506, 79507, + 79508, 79509, 79510, 79511, 79512, 79513, 79514, 79515, 79516, 79517, + 79518, 79519, 79520, 79521, 79522, 79523, 79524, 79525, 79526, 79527, + 79528, 79529, 79530, 79531, 79532, 79533, 79534, 79535, 79536, 79537, + 79538, 79539, 79540, 79541, 79542, 79543, 79544, 79545, 79546, 79547, + 79548, 79549, 79550, 79551, 79552, 79553, 79554, 79555, 79556, 79557, + 79558, 79559, 79560, 79561, 79562, 79563, 79564, 79565, 79566, 79567, + 79568, 79569, 79570, 79571, 79572, 79573, 79574, 79575, 79576, 79577, + 79578, 79579, 79580, 79581, 79582, 79583, 79584, 79585, 79586, 79587, + 79588, 79589, 79590, 79591, 79592, 79593, 79594, 79595, 79596, 79597, + 79598, 79599, 79600, 79601, 79602, 79603, 79604, 79605, 79606, 79607, + 79608, 79609, 79610, 79611, 79612, 79613, 79614, 79615, 79616, 79617, + 79618, 79619, 79620, 79621, 79622, 79623, 79624, 79625, 79626, 79627, + 79628, 79629, 79630, 79631, 79632, 79633, 79634, 79635, 79636, 79637, + 79638, 79639, 79640, 79641, 79642, 79643, 79644, 79645, 79646, 79647, + 79648, 79649, 79650, 79651, 79652, 79653, 79654, 79655, 79656, 79657, + 79658, 79659, 79660, 79661, 79662, 79663, 79664, 79665, 79666, 79667, + 79668, 79669, 79670, 79671, 79672, 79673, 79674, 79675, 79676, 79677, + 79678, 79679, 79680, 79681, 79682, 79683, 79684, 79685, 79686, 79687, + 79688, 79689, 79690, 79691, 79692, 79693, 79694, 79695, 79696, 79697, + 79698, 79699, 79700, 79701, 79702, 79703, 79704, 79705, 79706, 79707, + 79708, 79709, 79710, 79711, 79712, 79713, 79714, 79715, 79716, 79717, + 79718, 79719, 79720, 79721, 79722, 79723, 79724, 79725, 79726, 79727, + 79728, 79729, 79730, 79731, 79732, 79733, 79734, 79735, 79736, 79737, + 79738, 79739, 79740, 79741, 79742, 79743, 79744, 79745, 79746, 79747, + 79748, 79749, 79750, 79751, 79752, 79753, 79754, 79755, 79756, 79757, + 79758, 79759, 79760, 79761, 79762, 79763, 79764, 79765, 79766, 79767, + 79768, 79769, 79770, 79771, 79772, 79773, 79774, 79775, 79776, 79777, + 79778, 79779, 79780, 79781, 79782, 79783, 79784, 79785, 79786, 79787, + 79788, 79789, 79790, 79791, 79792, 79793, 79794, 79795, 79796, 79797, + 79798, 79799, 79800, 79801, 79802, 79803, 79804, 79805, 79806, 79807, + 79808, 79809, 79810, 79811, 79812, 79813, 79814, 79815, 79816, 79817, + 79818, 79819, 79820, 79821, 79822, 79823, 79824, 79825, 79826, 79827, + 79828, 79829, 79830, 79831, 79832, 79833, 79834, 79835, 79836, 79837, + 79838, 79839, 79840, 79841, 79842, 79843, 79844, 79845, 79846, 79847, + 79848, 79849, 79850, 79851, 79852, 79853, 79854, 79855, 79856, 79857, + 79858, 79859, 79860, 79861, 79862, 79863, 79864, 79865, 79866, 79867, + 79868, 79869, 79870, 79871, 79872, 79873, 79874, 79875, 79876, 79877, + 79878, 79879, 79880, 79881, 79882, 79883, 79884, 79885, 79886, 79887, + 79888, 79889, 79890, 79891, 79892, 79893, 79894, 79895, 79896, 79897, + 79898, 79899, 79900, 79901, 79902, 79903, 79904, 79905, 79906, 79907, + 79908, 79909, 79910, 79911, 79912, 79913, 79914, 79915, 79916, 79917, + 79918, 79919, 79920, 79921, 79922, 79923, 79924, 79925, 79926, 79927, + 79928, 79929, 79930, 79931, 79932, 79933, 79934, 79935, 79936, 79937, + 79938, 79939, 79940, 79941, 79942, 79943, 79944, 79945, 79946, 79947, + 79948, 79949, 79950, 79951, 79952, 79953, 79954, 79955, 79956, 79957, + 79958, 79959, 79960, 79961, 79962, 79963, 79964, 79965, 79966, 79967, + 79968, 79969, 79970, 79971, 79972, 79973, 79974, 79975, 79976, 79977, + 79978, 79979, 79980, 79981, 79982, 79983, 79984, 79985, 79986, 79987, + 79988, 79989, 79990, 79991, 79992, 79993, 79994, 79995, 79996, 79997, + 79998, 79999, 80000, 80001, 80002, 80003, 80004, 80005, 80006, 80007, + 80008, 80009, 80010, 80011, 80012, 80013, 80014, 80015, 80016, 80017, + 80018, 80019, 80020, 80021, 80022, 80023, 80024, 80025, 80026, 80027, + 80028, 80029, 80030, 80031, 80032, 80033, 80034, 80035, 80036, 80037, + 80038, 80039, 80040, 80041, 80042, 80043, 80044, 80045, 80046, 80047, + 80048, 80049, 80050, 80051, 80052, 80053, 80054, 80055, 80056, 80057, + 80058, 80059, 80060, 80061, 80062, 80063, 80064, 80065, 80066, 80067, + 80068, 80069, 80070, 80071, 80072, 80073, 80074, 80075, 80076, 80077, + 80078, 80079, 80080, 80081, 80082, 80083, 80084, 80085, 80086, 80087, + 80088, 80089, 80090, 80091, 80092, 80093, 80094, 80095, 80096, 80097, + 80098, 80099, 80100, 80101, 80102, 80103, 80104, 80105, 80106, 80107, + 80108, 80109, 80110, 80111, 80112, 80113, 80114, 80115, 80116, 80117, + 80118, 80119, 80120, 80121, 80122, 80123, 80124, 80125, 80126, 80127, + 80128, 80129, 80130, 80131, 80132, 80133, 80134, 80135, 80136, 80137, + 80138, 80139, 80140, 80141, 80142, 80143, 80144, 80145, 80146, 80147, + 80148, 80149, 80150, 80151, 80152, 80153, 80154, 80155, 80156, 80157, + 80158, 80159, 80160, 80161, 80162, 80163, 80164, 80165, 80166, 80167, + 80168, 80169, 80170, 80171, 80172, 80173, 80174, 80175, 80176, 80177, + 80178, 80179, 80180, 80181, 80182, 80183, 80184, 80185, 80186, 80187, + 80188, 80189, 80190, 80191, 80192, 80193, 80194, 80195, 80196, 80197, + 80198, 80199, 80200, 80201, 80202, 80203, 80204, 80205, 80206, 80207, + 80208, 80209, 80210, 80211, 80212, 80213, 80214, 80215, 80216, 80217, + 80218, 80219, 80220, 80221, 80222, 80223, 80224, 80225, 80226, 80227, + 80228, 80229, 80230, 80231, 80232, 80233, 80234, 80235, 80236, 80237, + 80238, 80239, 80240, 80241, 80242, 80243, 80244, 80245, 80246, 80247, + 80248, 80249, 80250, 80251, 80252, 80253, 80254, 80255, 80256, 80257, + 80258, 80259, 80260, 80261, 80262, 80263, 80264, 80265, 80266, 80267, + 80268, 80269, 80270, 80271, 80272, 80273, 80274, 80275, 80276, 80277, + 80278, 80279, 80280, 80281, 80282, 80283, 80284, 80285, 80286, 80287, + 80288, 80289, 80290, 80291, 80292, 80293, 80294, 80295, 80296, 80297, + 80298, 80299, 80300, 80301, 80302, 80303, 80304, 80305, 80306, 80307, + 80308, 80309, 80310, 80311, 80312, 80313, 80314, 80315, 80316, 80317, + 80318, 80319, 80320, 80321, 80322, 80323, 80324, 80325, 80326, 80327, + 80328, 80329, 80330, 80331, 80332, 80333, 80334, 80335, 80336, 80337, + 80338, 80339, 80340, 80341, 80342, 80343, 80344, 80345, 80346, 80347, + 80348, 80349, 80350, 80351, 80352, 80353, 80354, 80355, 80356, 80357, + 80358, 80359, 80360, 80361, 80362, 80363, 80364, 80365, 80366, 80367, + 80368, 80369, 80370, 80371, 80372, 80373, 80374, 80375, 80376, 80377, + 80378, 80379, 80380, 80381, 80382, 80383, 80384, 80385, 80386, 80387, + 80388, 80389, 80390, 80391, 80392, 80393, 80394, 80395, 80396, 80397, + 80398, 80399, 80400, 80401, 80402, 80403, 80404, 80405, 80406, 80407, + 80408, 80409, 80410, 80411, 80412, 80413, 80414, 80415, 80416, 80417, + 80418, 80419, 80420, 80421, 80422, 80423, 80424, 80425, 80426, 80427, + 80428, 80429, 80430, 80431, 80432, 80433, 80434, 80435, 80436, 80437, + 80438, 80439, 80440, 80441, 80442, 80443, 80444, 80445, 80446, 80447, + 80448, 80449, 80450, 80451, 80452, 80453, 80454, 80455, 80456, 80457, + 80458, 80459, 80460, 80461, 80462, 80463, 80464, 80465, 80466, 80467, + 80468, 80469, 80470, 80471, 80472, 80473, 80474, 80475, 80476, 80477, + 80478, 80479, 80480, 80481, 80482, 80483, 80484, 80485, 80486, 80487, + 80488, 80489, 80490, 80491, 80492, 80493, 80494, 80495, 80496, 80497, + 80498, 80499, 80500, 80501, 80502, 80503, 80504, 80505, 80506, 80507, + 80508, 80509, 80510, 80511, 80512, 80513, 80514, 80515, 80516, 80517, + 80518, 80519, 80520, 80521, 80522, 80523, 80524, 80525, 80526, 80527, + 80528, 80529, 80530, 80531, 80532, 80533, 80534, 80535, 80536, 80537, + 80538, 80539, 80540, 80541, 80542, 80543, 80544, 80545, 80546, 80547, + 80548, 80549, 80550, 80551, 80552, 80553, 80554, 80555, 80556, 80557, + 80558, 80559, 80560, 80561, 80562, 80563, 80564, 80565, 80566, 80567, + 80568, 80569, 80570, 80571, 80572, 80573, 80574, 80575, 80576, 80577, + 80578, 80579, 80580, 80581, 80582, 80583, 80584, 80585, 80586, 80587, + 80588, 80589, 80590, 80591, 80592, 80593, 80594, 80595, 80596, 80597, + 80598, 80599, 80600, 80601, 80602, 80603, 80604, 80605, 80606, 80607, + 80608, 80609, 80610, 80611, 80612, 80613, 80614, 80615, 80616, 80617, + 80618, 80619, 80620, 80621, 80622, 80623, 80624, 80625, 80626, 80627, + 80628, 80629, 80630, 80631, 80632, 80633, 80634, 80635, 80636, 80637, + 80638, 80639, 80640, 80641, 80642, 80643, 80644, 80645, 80646, 80647, + 80648, 80649, 80650, 80651, 80652, 80653, 80654, 80655, 80656, 80657, + 80658, 80659, 80660, 80661, 80662, 80663, 80664, 80665, 80666, 80667, + 80668, 80669, 80670, 80671, 80672, 80673, 80674, 80675, 80676, 80677, + 80678, 80679, 80680, 80681, 80682, 80683, 80684, 80685, 80686, 80687, + 80688, 80689, 80690, 80691, 80692, 80693, 80694, 80695, 80696, 80697, + 80698, 80699, 80700, 80701, 80702, 80703, 80704, 80705, 80706, 80707, + 80708, 80709, 80710, 80711, 80712, 80713, 80714, 80715, 80716, 80717, + 80718, 80719, 80720, 80721, 80722, 80723, 80724, 80725, 80726, 80727, + 80728, 80729, 80730, 80731, 80732, 80733, 80734, 80735, 80736, 80737, + 80738, 80739, 80740, 80741, 80742, 80743, 80744, 80745, 80746, 80747, + 80748, 80749, 80750, 80751, 80752, 80753, 80754, 80755, 80756, 80757, + 80758, 80759, 80760, 80761, 80762, 80763, 80764, 80765, 80766, 80767, + 80768, 80769, 80770, 80771, 80772, 80773, 80774, 80775, 80776, 80777, + 80778, 80779, 80780, 80781, 80782, 80783, 80784, 80785, 80786, 80787, + 80788, 80789, 80790, 80791, 80792, 80793, 80794, 80795, 80796, 80797, + 80798, 80799, 80800, 80801, 80802, 80803, 80804, 80805, 80806, 80807, + 80808, 80809, 80810, 80811, 80812, 80813, 80814, 80815, 80816, 80817, + 80818, 80819, 80820, 80821, 80822, 80823, 80824, 80825, 80826, 80827, + 80828, 80829, 80830, 80831, 80832, 80833, 80834, 80835, 80836, 80837, + 80838, 80839, 80840, 80841, 80842, 80843, 80844, 80845, 80846, 80847, + 80848, 80849, 80850, 80851, 80852, 80853, 80854, 80855, 80856, 80857, + 80858, 80859, 80860, 80861, 80862, 80863, 80864, 80865, 80866, 80867, + 80868, 80869, 80870, 80871, 80872, 80873, 80874, 80875, 80876, 80877, + 80878, 80879, 80880, 80881, 80882, 80883, 80884, 80885, 80886, 80887, + 80888, 80889, 80890, 80891, 80892, 80893, 80894, 80895, 80896, 80897, + 80898, 80899, 80900, 80901, 80902, 80903, 80904, 80905, 80906, 80907, + 80908, 80909, 80910, 80911, 80912, 80913, 80914, 80915, 80916, 80917, + 80918, 80919, 80920, 80921, 80922, 80923, 80924, 80925, 80926, 80927, + 80928, 80929, 80930, 80931, 80932, 80933, 80934, 80935, 80936, 80937, + 80938, 80939, 80940, 80941, 80942, 80943, 80944, 80945, 80946, 80947, + 80948, 80949, 80950, 80951, 80952, 80953, 80954, 80955, 80956, 80957, + 80958, 80959, 80960, 80961, 80962, 80963, 80964, 80965, 80966, 80967, + 80968, 80969, 80970, 80971, 80972, 80973, 80974, 80975, 80976, 80977, + 80978, 80979, 80980, 80981, 80982, 80983, 80984, 80985, 80986, 80987, + 80988, 80989, 80990, 80991, 80992, 80993, 80994, 80995, 80996, 80997, + 80998, 80999, 81000, 81001, 81002, 81003, 81004, 81005, 81006, 81007, + 81008, 81009, 81010, 81011, 81012, 81013, 81014, 81015, 81016, 81017, + 81018, 81019, 81020, 81021, 81022, 81023, 81024, 81025, 81026, 81027, + 81028, 81029, 81030, 81031, 81032, 81033, 81034, 81035, 81036, 81037, + 81038, 81039, 81040, 81041, 81042, 81043, 81044, 81045, 81046, 81047, + 81048, 81049, 81050, 81051, 81052, 81053, 81054, 81055, 81056, 81057, + 81058, 81059, 81060, 81061, 81062, 81063, 81064, 81065, 81066, 81067, + 81068, 81069, 81070, 81071, 81072, 81073, 81074, 81075, 81076, 81077, + 81078, 81079, 81080, 81081, 81082, 81083, 81084, 81085, 81086, 81087, + 81088, 81089, 81090, 81091, 81092, 81093, 81094, 81095, 81096, 81097, + 81098, 81099, 81100, 81101, 81102, 81103, 81104, 81105, 81106, 81107, + 81108, 81109, 81110, 81111, 81112, 81113, 81114, 81115, 81116, 81117, + 81118, 81119, 81120, 81121, 81122, 81123, 81124, 81125, 81126, 81127, + 81128, 81129, 81130, 81131, 81132, 81133, 81134, 81135, 81136, 81137, + 81138, 81139, 81140, 81141, 81142, 81143, 81144, 81145, 81146, 81147, + 81148, 81149, 81150, 81151, 81152, 81153, 81154, 81155, 81156, 81157, + 81158, 81159, 81160, 81161, 81162, 81163, 81164, 81165, 81166, 81167, + 81168, 81169, 81170, 81171, 81172, 81173, 81174, 81175, 81176, 81177, + 81178, 81179, 81180, 81181, 81182, 81183, 81184, 81185, 81186, 81187, + 81188, 81189, 81190, 81191, 81192, 81193, 81194, 81195, 81196, 81197, + 81198, 81199, 81200, 81201, 81202, 81203, 81204, 81205, 81206, 81207, + 81208, 81209, 81210, 81211, 81212, 81213, 81214, 81215, 81216, 81217, + 81218, 81219, 81220, 81221, 81222, 81223, 81224, 81225, 81226, 81227, + 81228, 81229, 81230, 81231, 81232, 81233, 81234, 81235, 81236, 81237, + 81238, 81239, 81240, 81241, 81242, 81243, 81244, 81245, 81246, 81247, + 81248, 81249, 81250, 81251, 81252, 81253, 81254, 81255, 81256, 81257, + 81258, 81259, 81260, 81261, 81262, 81263, 81264, 81265, 81266, 81267, + 81268, 81269, 81270, 81271, 81272, 81273, 81274, 81275, 81276, 81277, + 81278, 81279, 81280, 81281, 81282, 81283, 81284, 81285, 81286, 81287, + 81288, 81289, 81290, 81291, 81292, 81293, 81294, 81295, 81296, 81297, + 81298, 81299, 81300, 81301, 81302, 81303, 81304, 81305, 81306, 81307, + 81308, 81309, 81310, 81311, 81312, 81313, 81314, 81315, 81316, 81317, + 81318, 81319, 81320, 81321, 81322, 81323, 81324, 81325, 81326, 81327, + 81328, 81329, 81330, 81331, 81332, 81333, 81334, 81335, 81336, 81337, + 81338, 81339, 81340, 81341, 81342, 81343, 81344, 81345, 81346, 81347, + 81348, 81349, 81350, 81351, 81352, 81353, 81354, 81355, 81356, 81357, + 81358, 81359, 81360, 81361, 81362, 81363, 81364, 81365, 81366, 81367, + 81368, 81369, 81370, 81371, 81372, 81373, 81374, 81375, 81376, 81377, + 81378, 81379, 81380, 81381, 81382, 81383, 81384, 81385, 81386, 81387, + 81388, 81389, 81390, 81391, 81392, 81393, 81394, 81395, 81396, 81397, + 81398, 81399, 81400, 81401, 81402, 81403, 81404, 81405, 81406, 81407, + 81408, 81409, 81410, 81411, 81412, 81413, 81414, 81415, 81416, 81417, + 81418, 81419, 81420, 81421, 81422, 81423, 81424, 81425, 81426, 81427, + 81428, 81429, 81430, 81431, 81432, 81433, 81434, 81435, 81436, 81437, + 81438, 81439, 81440, 81441, 81442, 81443, 81444, 81445, 81446, 81447, + 81448, 81449, 81450, 81451, 81452, 81453, 81454, 81455, 81456, 81457, + 81458, 81459, 81460, 81461, 81462, 81463, 81464, 81465, 81466, 81467, + 81468, 81469, 81470, 81471, 81472, 81473, 81474, 81475, 81476, 81477, + 81478, 81479, 81480, 81481, 81482, 81483, 81484, 81485, 81486, 81487, + 81488, 81489, 81490, 81491, 81492, 81493, 81494, 81495, 81496, 81497, + 81498, 81499, 81500, 81501, 81502, 81503, 81504, 81505, 81506, 81507, + 81508, 81509, 81510, 81511, 81512, 81513, 81514, 81515, 81516, 81517, + 81518, 81519, 81520, 81521, 81522, 81523, 81524, 81525, 81526, 81527, + 81528, 81529, 81530, 81531, 81532, 81533, 81534, 81535, 81536, 81537, + 81538, 81539, 81540, 81541, 81542, 81543, 81544, 81545, 81546, 81547, + 81548, 81549, 81550, 81551, 81552, 81553, 81554, 81555, 81556, 81557, + 81558, 81559, 81560, 81561, 81562, 81563, 81564, 81565, 81566, 81567, + 81568, 81569, 81570, 81571, 81572, 81573, 81574, 81575, 81576, 81577, + 81578, 81579, 81580, 81581, 81582, 81583, 81584, 81585, 81586, 81587, + 81588, 81589, 81590, 81591, 81592, 81593, 81594, 81595, 81596, 81597, + 81598, 81599, 81600, 81601, 81602, 81603, 81604, 81605, 81606, 81607, + 81608, 81609, 81610, 81611, 81612, 81613, 81614, 81615, 81616, 81617, + 81618, 81619, 81620, 81621, 81622, 81623, 81624, 81625, 81626, 81627, + 81628, 81629, 81630, 81631, 81632, 81633, 81634, 81635, 81636, 81637, + 81638, 81639, 81640, 81641, 81642, 81643, 81644, 81645, 81646, 81647, + 81648, 81649, 81650, 81651, 81652, 81653, 81654, 81655, 81656, 81657, + 81658, 81659, 81660, 81661, 81662, 81663, 81664, 81665, 81666, 81667, + 81668, 81669, 81670, 81671, 81672, 81673, 81674, 81675, 81676, 81677, + 81678, 81679, 81680, 81681, 81682, 81683, 81684, 81685, 81686, 81687, + 81688, 81689, 81690, 81691, 81692, 81693, 81694, 81695, 81696, 81697, + 81698, 81699, 81700, 81701, 81702, 81703, 81704, 81705, 81706, 81707, + 81708, 81709, 81710, 81711, 81712, 81713, 81714, 81715, 81716, 81717, + 81718, 81719, 81720, 81721, 81722, 81723, 81724, 81725, 81726, 81727, + 81728, 81729, 81730, 81731, 81732, 81733, 81734, 81735, 81736, 81737, + 81738, 81739, 81740, 81741, 81742, 81743, 81744, 81745, 81746, 81747, + 81748, 81749, 81750, 81751, 81752, 81753, 81754, 81755, 81756, 81757, + 81758, 81759, 81760, 81761, 81762, 81763, 81764, 81765, 81766, 81767, + 81768, 81769, 81770, 81771, 81772, 81773, 81774, 81775, 81776, 81777, + 81778, 81779, 81780, 81781, 81782, 81783, 81784, 81785, 81786, 81787, + 81788, 81789, 81790, 81791, 81792, 81793, 81794, 81795, 81796, 81797, + 81798, 81799, 81800, 81801, 81802, 81803, 81804, 81805, 81806, 81807, + 81808, 81809, 81810, 81811, 81812, 81813, 81814, 81815, 81816, 81817, + 81818, 81819, 81820, 81821, 81822, 81823, 81824, 81825, 81826, 81827, + 81828, 81829, 81830, 81831, 81832, 81833, 81834, 81835, 81836, 81837, + 81838, 81839, 81840, 81841, 81842, 81843, 81844, 81845, 81846, 81847, + 81848, 81849, 81850, 81851, 81852, 81853, 81854, 81855, 81856, 81857, + 81858, 81859, 81860, 81861, 81862, 81863, 81864, 81865, 81866, 81867, + 81868, 81869, 81870, 81871, 81872, 81873, 81874, 81875, 81876, 81877, + 81878, 81879, 81880, 81881, 81882, 81883, 81884, 81885, 81886, 81887, + 81888, 81889, 81890, 81891, 81892, 81893, 81894, 81895, 81896, 81897, + 81898, 81899, 81900, 81901, 81902, 81903, 81904, 81905, 81906, 81907, + 81908, 81909, 81910, 81911, 81912, 81913, 81914, 81915, 81916, 81917, + 81918, 81919, 82928, 82929, 82930, 82931, 82932, 82933, 82934, 82935, + 82936, 82937, 82938, 82688, 82689, 82690, 82691, 82692, 82693, 82694, + 82695, 82696, 82697, 82698, 82699, 82700, 82701, 82702, 82703, 82704, + 82705, 82706, 82707, 82708, 82709, 82710, 82711, 82712, 82713, 82714, + 82715, 82716, 82717, 82718, 82719, 82720, 82721, 82722, 82723, 82724, + 82725, 82726, 82727, 82728, 82729, 82730, 82731, 82732, 82733, 82734, + 82735, 82736, 82737, 82738, 82739, 82740, 82741, 82742, 82743, 82744, + 82745, 82746, 82747, 82748, 82749, 82750, 82751, 82752, 82753, 82754, + 82755, 82756, 82757, 82758, 82759, 82760, 82761, 82762, 82763, 82764, + 82765, 82766, 82767, 82768, 82769, 82770, 82771, 82772, 82773, 82774, + 82775, 82776, 82777, 82778, 82779, 82780, 82781, 82782, 82783, 82784, + 82785, 82786, 82787, 82788, 82789, 82790, 82791, 82792, 82793, 82794, + 82795, 82796, 82797, 82798, 82799, 82800, 82801, 82802, 82803, 82804, + 82805, 82806, 82807, 82808, 82809, 82810, 82811, 82812, 82813, 82814, + 82815, 82816, 82817, 82818, 82819, 82820, 82821, 82822, 82823, 82824, + 82825, 82826, 82827, 82828, 82829, 82830, 82831, 82832, 82833, 82834, + 82835, 82836, 82837, 82838, 82839, 82840, 82841, 82842, 82843, 82844, + 82845, 82846, 82847, 82848, 82849, 82850, 82851, 82852, 82853, 82854, + 82855, 82856, 82857, 82858, 82859, 82860, 82861, 82862, 82863, 82864, + 82865, 82866, 82867, 82868, 82869, 82870, 82871, 82872, 82873, 82874, + 82875, 82876, 82877, 82878, 82879, 82880, 82881, 82882, 82883, 82884, + 82885, 82886, 82887, 82888, 82889, 82890, 82891, 82892, 82893, 82894, + 82895, 82896, 82897, 82898, 82899, 82900, 82901, 82902, 82903, 82904, + 82905, 82906, 82907, 82908, 82909, 82910, 82911, 82912, 82913, 82914, + 82915, 82916, 82917, 82918, 82919, 82920, 82921, 82922, 82923, 82924, + 82925, 82926, 82927, 81920, 81921, 81922, 81923, 81924, 81925, 81926, + 81927, 81928, 81929, 81930, 81931, 81932, 81933, 81934, 81935, 81936, + 81937, 81938, 81939, 81940, 81941, 81942, 81943, 81944, 81945, 81946, + 81947, 81948, 81949, 81950, 81951, 81952, 81953, 81954, 81955, 81956, + 81957, 81958, 81959, 81960, 81961, 81962, 81963, 81964, 81965, 81966, + 81967, 81968, 81969, 81970, 81971, 81972, 81973, 81974, 81975, 81976, + 81977, 81978, 81979, 81980, 81981, 81982, 81983, 81984, 81985, 81986, + 81987, 81988, 81989, 81990, 81991, 81992, 81993, 81994, 81995, 81996, + 81997, 81998, 81999, 82000, 82001, 82002, 82003, 82004, 82005, 82006, + 82007, 82008, 82009, 82010, 82011, 82012, 82013, 82014, 82015, 82016, + 82017, 82018, 82019, 82020, 82021, 82022, 82023, 82024, 82025, 82026, + 82027, 82028, 82029, 82030, 82031, 82032, 82033, 82034, 82035, 82036, + 82037, 82038, 82039, 82040, 82041, 82042, 82043, 82044, 82045, 82046, + 82047, 82048, 82049, 82050, 82051, 82052, 82053, 82054, 82055, 82056, + 82057, 82058, 82059, 82060, 82061, 82062, 82063, 82064, 82065, 82066, + 82067, 82068, 82069, 82070, 82071, 82072, 82073, 82074, 82075, 82076, + 82077, 82078, 82079, 82080, 82081, 82082, 82083, 82084, 82085, 82086, + 82087, 82088, 82089, 82090, 82091, 82092, 82093, 82094, 82095, 82096, + 82097, 82098, 82099, 82100, 82101, 82102, 82103, 82104, 82105, 82106, + 82107, 82108, 82109, 82110, 82111, 82112, 82113, 82114, 82115, 82116, + 82117, 82118, 82119, 82120, 82121, 82122, 82123, 82124, 82125, 82126, + 82127, 82128, 82129, 82130, 82131, 82132, 82133, 82134, 82135, 82136, + 82137, 82138, 82139, 82140, 82141, 82142, 82143, 82144, 82145, 82146, + 82147, 82148, 82149, 82150, 82151, 82152, 82153, 82154, 82155, 82156, + 82157, 82158, 82159, 82160, 82161, 82162, 82163, 82164, 82165, 82166, + 82167, 82168, 82169, 82170, 82171, 82172, 82173, 82174, 82175, 82176, + 82177, 82178, 82179, 82180, 82181, 82182, 82183, 82184, 82185, 82186, + 82187, 82188, 82189, 82190, 82191, 82192, 82193, 82194, 82195, 82196, + 82197, 82198, 82199, 82200, 82201, 82202, 82203, 82204, 82205, 82206, + 82207, 82208, 82209, 82210, 82211, 82212, 82213, 82214, 82215, 82216, + 82217, 82218, 82219, 82220, 82221, 82222, 82223, 82224, 82225, 82226, + 82227, 82228, 82229, 82230, 82231, 82232, 82233, 82234, 82235, 82236, + 82237, 82238, 82239, 82240, 82241, 82242, 82243, 82244, 82245, 82246, + 82247, 82248, 82249, 82250, 82251, 82252, 82253, 82254, 82255, 82256, + 82257, 82258, 82259, 82260, 82261, 82262, 82263, 82264, 82265, 82266, + 82267, 82268, 82269, 82270, 82271, 82272, 82273, 82274, 82275, 82276, + 82277, 82278, 82279, 82280, 82281, 82282, 82283, 82284, 82285, 82286, + 82287, 82288, 82289, 82290, 82291, 82292, 82293, 82294, 82295, 82296, + 82297, 82298, 82299, 82300, 82301, 82302, 82303, 82304, 82305, 82306, + 82307, 82308, 82309, 82310, 82311, 82312, 82313, 82314, 82315, 82316, + 82317, 82318, 82319, 82320, 82321, 82322, 82323, 82324, 82325, 82326, + 82327, 82328, 82329, 82330, 82331, 82332, 82333, 82334, 82335, 82336, + 82337, 82338, 82339, 82340, 82341, 82342, 82343, 82344, 82345, 82346, + 82347, 82348, 82349, 82350, 82351, 82352, 82353, 82354, 82355, 82356, + 82357, 82358, 82359, 82360, 82361, 82362, 82363, 82364, 82365, 82366, + 82367, 82368, 82369, 82370, 82371, 82372, 82373, 82374, 82375, 82376, + 82377, 82378, 82379, 82380, 82381, 82382, 82383, 82384, 82385, 82386, + 82387, 82388, 82389, 82390, 82391, 82392, 82393, 82394, 82395, 82396, + 82397, 82398, 82399, 82400, 82401, 82402, 82403, 82404, 82405, 82406, + 82407, 82408, 82409, 82410, 82411, 82412, 82413, 82414, 82415, 82416, + 82417, 82418, 82419, 82420, 82421, 82422, 82423, 82424, 82425, 82426, + 82427, 82428, 82429, 82430, 82431, 82432, 82433, 82434, 82435, 82436, + 82437, 82438, 82439, 82440, 82441, 82442, 82443, 82444, 82445, 82446, + 82447, 82448, 82449, 82450, 82451, 82452, 82453, 82454, 82455, 82456, + 82457, 82458, 82459, 82460, 82461, 82462, 82463, 82464, 82465, 82466, + 82467, 82468, 82469, 82470, 82471, 82472, 82473, 82474, 82475, 82476, + 82477, 82478, 82479, 82480, 82481, 82482, 82483, 82484, 82485, 82486, + 82487, 82488, 82489, 82490, 82491, 82492, 82493, 82494, 82495, 82496, + 82497, 82498, 82499, 82500, 82501, 82502, 82503, 82504, 82505, 82506, + 82507, 82508, 82509, 82510, 82511, 82512, 82513, 82514, 82515, 82516, + 82517, 82518, 82519, 82520, 82521, 82522, 82523, 82524, 82525, 82526, + 82527, 82528, 82529, 82530, 82531, 82532, 82533, 82534, 82535, 82536, + 82537, 82538, 82539, 82540, 82541, 82542, 82543, 82544, 82545, 82546, + 82547, 82548, 82549, 82550, 82551, 82552, 82553, 82554, 82555, 82556, + 82557, 82558, 82559, 82560, 82561, 82562, 82563, 82564, 82565, 82566, + 82567, 82568, 82569, 82570, 82571, 82572, 82573, 82574, 82575, 82576, + 82577, 82578, 82579, 82580, 82581, 82582, 82583, 82584, 82585, 82586, + 82587, 82588, 82589, 82590, 82591, 82592, 82593, 82594, 82595, 82596, + 82597, 82598, 82599, 82600, 82601, 82602, 82603, 82604, 82605, 82606, + 82607, 82608, 82609, 82610, 82611, 82612, 82613, 82614, 82615, 82616, + 82617, 82618, 82619, 82620, 82621, 82622, 82623, 82624, 82625, 82626, + 82627, 82628, 82629, 82630, 82631, 82632, 82633, 82634, 82635, 82636, + 82637, 82638, 82639, 82640, 82641, 82642, 82643, 82644, 82645, 82646, + 82647, 82648, 82649, 82650, 82651, 82652, 82653, 82654, 82655, 82656, + 82657, 82658, 82659, 82660, 82661, 82662, 82663, 82664, 82665, 82666, + 82667, 82668, 82669, 82670, 82671, 82672, 82673, 82674, 82675, 82676, + 82677, 82678, 82679, 82680, 82681, 82682, 82683, 82684, 82685, 82686, + 82687, 118470, 129370, 10037, 10039, 10036, 10049, 117865, 117866, 10058, + 10035, 9834, 66854, 66853, 66827, 66826, 66833, 66832, 66821, 66837, + 66836, 66835, 66842, 66841, 66824, 66823, 66819, 66818, 66822, 66820, + 66855, 66831, 66844, 66843, 66846, 66845, 66852, 66851, 66817, 66825, + 66828, 66830, 66834, 66839, 66840, 66848, 66849, 66816, 66829, 66838, + 66847, 66850, 128268, 128294, 128161, 8961, 9191, 8712, 8946, 8953, 8947, + 8952, 8950, 8949, 10969, 10194, 128024, 128727, 69608, 69621, 69603, + 69611, 69618, 69619, 69600, 69615, 69602, 69606, 69614, 69617, 69620, + 69609, 69604, 69607, 69610, 69601, 69613, 69605, 69616, 69612, 69622, + 129501, 983101, 129456, 129457, 129459, 129458, 127995, 127996, 127997, + 127998, 127999, 128453, 128454, 128455, 129721, 128460, 128461, 8709, + 10675, 10676, 10674, 10673, 128459, 9091, 8193, 8212, 8195, 8192, 8211, + 8194, 983179, 8718, 983178, 983135, 983099, 983048, 983095, 983046, + 983064, 128282, 983051, 983050, 9993, 128388, 128233, 9094, 983067, + 983100, 983049, 8926, 8927, 8925, 8924, 8797, 8917, 61, 10865, 10867, + 11072, 10609, 10723, 10724, 10926, 11257, 11158, 10871, 10854, 10862, + 8789, 10872, 8781, 8794, 10738, 10736, 10734, 10739, 10737, 10735, 11249, + 11248, 9003, 8998, 983105, 983104, 8494, 8793, 983136, 4957, 4959, 4958, + 4963, 4965, 4978, 4988, 4980, 4979, 4987, 4985, 4982, 4981, 4986, 4984, + 4983, 4968, 4966, 4964, 4960, 4999, 4998, 4711, 4997, 43816, 43819, + 43821, 43820, 43818, 43822, 43817, 4704, 4707, 4710, 11653, 4709, 4708, + 4706, 4705, 43808, 43811, 43813, 43812, 43810, 43814, 43809, 11704, + 11707, 11709, 11708, 11706, 11710, 11705, 11688, 11691, 11693, 11692, + 11690, 11694, 11689, 4904, 4907, 4910, 11664, 4909, 4908, 4911, 4906, + 4905, 4728, 4731, 4734, 11655, 4733, 4732, 4735, 4730, 4729, 43789, + 43788, 43787, 43786, 43790, 43785, 4856, 4859, 4862, 11661, 4861, 4860, + 4863, 4858, 4857, 43797, 43796, 43795, 43794, 43798, 43793, 4848, 4851, + 4854, 11660, 4853, 4852, 4855, 4850, 4849, 5003, 5002, 4943, 5001, 4936, + 4939, 4941, 4940, 4954, 4938, 4942, 4937, 4873, 124916, 124915, 124924, + 124923, 124910, 124909, 124926, 124925, 124922, 124921, 124920, 124919, + 124918, 124917, 124914, 124913, 124912, 124904, 11667, 4895, 11670, + 11669, 11668, 4888, 4891, 4893, 4892, 4890, 4894, 4889, 4768, 4771, 4774, + 11658, 4773, 4772, 4775, 4770, 4769, 4880, 4883, 4885, 4884, 4882, 11736, + 11739, 11741, 11740, 11738, 11742, 11737, 4872, 4875, 4878, 4879, 4877, + 4876, 4874, 124907, 124906, 4631, 124905, 124896, 124899, 124901, 124900, + 124898, 124902, 124897, 4624, 4627, 4629, 4628, 4626, 4630, 4625, 4608, + 4611, 4614, 4615, 4613, 4612, 4610, 4609, 4800, 4803, 4805, 4804, 4802, + 4792, 4795, 4797, 4796, 4794, 4798, 4793, 4784, 4787, 4789, 4788, 4786, + 11720, 11723, 11725, 11724, 11722, 11726, 11721, 4776, 4779, 4782, 4783, + 4781, 4780, 4778, 4777, 4995, 4994, 4639, 4993, 4632, 4635, 4638, 11649, + 4637, 4636, 4953, 4634, 4633, 4760, 4763, 4766, 11657, 4765, 4764, 4767, + 4762, 4761, 4752, 4755, 4758, 11656, 4757, 4756, 4759, 4754, 4753, 4912, + 4816, 4819, 4821, 4820, 4818, 4822, 4817, 4915, 4918, 11665, 4917, 4916, + 4919, 4914, 4913, 5007, 5006, 4951, 5005, 4944, 4947, 4950, 11666, 4949, + 4948, 4946, 4945, 4696, 4699, 4701, 4700, 4698, 4688, 4691, 4693, 4692, + 4690, 4694, 4689, 4680, 4683, 4685, 4684, 4682, 11712, 11715, 11717, + 11716, 11714, 11718, 11713, 4672, 4675, 4678, 4679, 4677, 4676, 4674, + 4673, 4648, 4651, 4654, 11650, 4653, 4652, 4655, 4952, 4650, 4649, 4661, + 4996, 5000, 4992, 5004, 4660, 4664, 4667, 4670, 11652, 4669, 4668, 4671, + 4666, 4665, 4640, 4643, 4645, 4644, 4647, 4642, 4646, 4641, 11680, 11683, + 11685, 11684, 11682, 11686, 11681, 4656, 4659, 4662, 11651, 4663, 4658, + 4657, 4896, 4899, 4902, 11663, 4901, 4900, 4903, 4898, 4897, 43781, + 43780, 43779, 43778, 43782, 43777, 4928, 4931, 4934, 4935, 4933, 4932, + 4930, 4929, 4920, 4923, 4925, 4924, 4927, 4922, 4926, 4921, 4720, 4723, + 4726, 11654, 4725, 4724, 4727, 4722, 4721, 4864, 4867, 4870, 11662, 4869, + 4868, 4871, 4866, 4865, 4616, 4619, 4622, 11648, 4621, 4620, 4623, 4618, + 4617, 4808, 4811, 4814, 4815, 4813, 4812, 4810, 4809, 4840, 4843, 4846, + 4847, 4845, 4844, 4842, 4841, 4744, 4747, 4749, 4748, 4746, 11728, 11731, + 11733, 11732, 11730, 11734, 11729, 4736, 4739, 4742, 4743, 4741, 4740, + 4738, 4737, 4832, 4835, 4837, 4836, 4839, 4834, 4838, 4833, 11696, 11699, + 11701, 11700, 11698, 11702, 11697, 4824, 4827, 4830, 11659, 4829, 4828, + 4831, 4826, 4825, 4712, 4715, 4717, 4716, 4719, 4714, 4718, 4713, 5009, + 5016, 5012, 5015, 5013, 5017, 5010, 5011, 5014, 5008, 4973, 4972, 4975, + 4974, 4971, 4970, 4977, 4969, 4976, 4962, 4967, 4961, 983096, 983047, + 127984, 127972, 8352, 8364, 118472, 8455, 8265, 33, 8761, 118269, 118270, 118271, 118274, 128529, 128942, 128954, 128948, 128905, 128915, 128935, 128125, 1781, 1780, 1783, 1782, 1779, 1778, 1776, 1785, 1777, 1784, 128065, 128083, 128064, 128231, 9167, 127794, 983180, 128523, 128561, @@ -10937,150 +11055,153 @@ static const unsigned int dawg_pos_to_codepoint[] = { 128514, 129298, 129769, 129323, 128580, 128548, 129764, 129396, 128566, 129318, 128134, 128536, 129401, 8507, 127981, 10540, 10543, 9950, 127810, 129478, 128439, 128224, 128106, 9771, 127877, 129498, 128552, 129718, - 170, 9792, 127905, 9972, 129338, 8210, 8199, 128193, 128452, 983107, - 128253, 127902, 129734, 10765, 128293, 128658, 129519, 127879, 127878, - 129512, 9789, 127771, 127763, 8296, 129351, 128031, 127907, 9673, 127845, - 128074, 8281, 11821, 127953, 129407, 129747, 9189, 117910, 9971, 129449, - 128170, 9884, 10086, 9880, 8277, 127924, 128190, 128563, 129672, 129712, - 128760, 117834, 117835, 129359, 128389, 127787, 127745, 129709, 128448, - 129462, 128099, 127860, 127869, 11792, 10972, 983071, 8704, 8873, 129376, - 10021, 11156, 8280, 8283, 10019, 127808, 10018, 128966, 8732, 8197, 9970, - 129749, 129418, 8260, 8543, 128444, 128446, 128445, 127839, 8355, 129398, - 10156, 128037, 8994, 128550, 128056, 127844, 127773, 127765, 10199, 9608, - 46, 65342, 65312, 65292, 65306, 65504, 65375, 65371, 65288, 65339, 65308, - 65313, 65314, 65315, 65316, 65317, 65318, 65319, 65320, 65321, 65322, - 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, - 65333, 65334, 65335, 65336, 65337, 65338, 65345, 65346, 65347, 65348, - 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, - 65359, 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, - 65369, 65370, 65343, 65506, 65283, 65505, 65285, 65291, 65376, 65373, - 65289, 65341, 65340, 65307, 65295, 65509, 65507, 65287, 65286, 65290, - 65284, 65301, 65300, 65303, 65302, 65299, 65298, 65296, 65305, 65297, - 65304, 65309, 65281, 65344, 65310, 65293, 65282, 65311, 65510, 65374, - 65294, 65508, 65372, 8289, 9905, 118280, 9981, 9179, 983215, 983216, - 983217, 983219, 983108, 983236, 983072, 68972, 68971, 68973, 68970, - 68964, 68965, 68959, 68961, 68948, 68945, 68954, 68960, 68953, 68963, - 68949, 68947, 68952, 68946, 68962, 68958, 68950, 68957, 68951, 68955, - 68956, 68944, 68996, 68997, 68991, 68993, 68980, 68977, 68986, 68992, - 68985, 68995, 68981, 68979, 68984, 68978, 68994, 68990, 68982, 68989, - 68983, 68987, 68988, 68976, 68943, 68969, 68941, 68938, 68939, 68940, - 68942, 68975, 68974, 69006, 69007, 68933, 68932, 68935, 68934, 68931, - 68930, 68928, 68937, 68929, 68936, 129476, 127922, 9881, 9965, 9966, - 128142, 9802, 8782, 8785, 8762, 4301, 4256, 4288, 4292, 4290, 4293, 4289, - 4281, 4285, 4284, 4282, 4278, 4258, 4287, 4283, 4277, 4265, 4276, 4270, - 4280, 4273, 4271, 4262, 4263, 4274, 4266, 4272, 4257, 4267, 4286, 4268, - 4279, 4261, 4259, 4260, 4264, 4269, 4275, 4295, 4291, 11565, 11520, - 11552, 11556, 11554, 11557, 11553, 11545, 11549, 11548, 11546, 11542, - 11522, 11551, 11547, 11541, 11529, 11540, 11534, 11544, 11537, 11535, - 11526, 11527, 11538, 11530, 11536, 11521, 11531, 11550, 11532, 11543, - 11525, 11523, 11524, 11528, 11533, 11539, 11559, 11555, 983955, 4323, - 4349, 4346, 4304, 4329, 4333, 4332, 4330, 4344, 4308, 4326, 4306, 4340, - 4350, 4336, 4338, 4341, 4337, 4335, 4331, 4325, 4313, 4351, 4314, 4324, - 4318, 4328, 4321, 4345, 4311, 4322, 4319, 4310, 4320, 4305, 4315, 4334, - 4316, 4327, 4309, 4307, 4312, 4317, 4343, 4339, 4342, 7357, 7354, 7312, - 7337, 7341, 7340, 7338, 7352, 7316, 7334, 7314, 7348, 7358, 7344, 7346, - 7349, 7345, 7343, 7339, 7333, 7321, 7359, 7322, 7332, 7326, 7336, 7329, - 7353, 7319, 7330, 7327, 7318, 7328, 7313, 7323, 7342, 7324, 7335, 7317, - 7315, 7320, 7325, 7331, 7351, 7347, 7350, 4347, 8368, 12307, 129502, - 8503, 129754, 128103, 128714, 129426, 11264, 11304, 11265, 11311, 11293, - 11276, 11268, 11271, 11287, 11306, 11267, 11275, 11274, 11305, 11303, - 11307, 11273, 11310, 11278, 11279, 11280, 11281, 11289, 11282, 11290, - 11283, 11291, 11308, 11294, 11284, 11298, 11300, 11301, 11285, 11309, - 11292, 11266, 11269, 11296, 11295, 11297, 11302, 11299, 11272, 11270, - 11288, 11286, 11277, 11312, 11352, 11313, 11359, 11341, 11324, 11316, - 11319, 11335, 11354, 11315, 11323, 11322, 11353, 11351, 11355, 11321, - 11358, 11326, 11327, 11328, 11329, 11337, 11330, 11338, 11331, 11339, - 11356, 11342, 11332, 11346, 11348, 11349, 11333, 11357, 11340, 11314, - 11317, 11344, 11343, 11345, 11350, 11347, 11320, 11318, 11336, 11334, - 11325, 129371, 127760, 127775, 129508, 10726, 129349, 128016, 66356, - 66352, 66376, 66359, 66358, 66375, 66378, 66369, 66365, 66368, 66357, - 66370, 66360, 66372, 66373, 66367, 66374, 66353, 66377, 66355, 66364, - 66371, 66361, 66363, 66366, 66354, 66362, 129421, 129405, 128893, 129727, - 127948, 127891, 70495, 70494, 70411, 70496, 70412, 70497, 70453, 70405, - 70406, 70416, 70420, 70434, 70433, 70439, 70438, 70432, 70431, 70437, - 70436, 70409, 70410, 70407, 70408, 70451, 70450, 70425, 70435, 70430, - 70440, 70454, 70455, 70456, 70445, 70444, 70427, 70426, 70424, 70423, - 70429, 70428, 70422, 70421, 70443, 70442, 70419, 70415, 70457, 70446, - 70448, 70447, 70400, 70401, 70460, 70461, 70402, 70493, 70477, 70403, - 70487, 70462, 70472, 70476, 70465, 70466, 70467, 70468, 70498, 70499, - 70463, 70464, 70475, 70471, 70480, 96, 127815, 10896, 10894, 10900, - 10892, 10898, 10616, 10890, 10888, 10917, 8935, 8809, 10878, 10882, - 10884, 10880, 10886, 8819, 8805, 8823, 10916, 8807, 8923, 10919, 10921, - 10874, 10876, 8919, 62, 65860, 65863, 65878, 65866, 65873, 65859, 65861, - 65868, 65875, 65862, 65870, 65864, 65871, 65867, 65874, 65857, 65869, - 65876, 65856, 65858, 65865, 65877, 65872, 65879, 65903, 65885, 65904, - 65907, 65908, 65900, 65883, 65886, 65896, 65890, 65882, 65880, 65891, - 65902, 65906, 65897, 65899, 65893, 65892, 65884, 65881, 65898, 65905, - 65887, 65901, 65894, 65895, 65888, 65889, 903, 65927, 65926, 913, 7945, - 7949, 8077, 7947, 8075, 7951, 8079, 8073, 7944, 7948, 8076, 7946, 8074, - 7950, 8078, 8072, 8124, 8120, 8122, 8123, 902, 8121, 882, 919, 7977, - 7981, 8093, 7979, 8091, 7983, 8095, 8089, 7976, 7980, 8092, 7978, 8090, - 7982, 8094, 8088, 8140, 8139, 8138, 905, 917, 7961, 7965, 7963, 7960, - 7964, 7962, 8137, 8136, 904, 921, 7993, 7999, 7997, 7995, 938, 7992, - 7998, 7996, 7994, 8152, 8154, 8155, 906, 8153, 937, 8041, 8045, 8109, - 8043, 8107, 8047, 8111, 8105, 8040, 8044, 8108, 8042, 8106, 8046, 8110, - 8104, 8188, 8187, 8186, 911, 927, 8009, 8013, 8011, 8008, 8012, 8010, - 8185, 8184, 908, 929, 8172, 931, 1018, 1015, 933, 8025, 8031, 8029, 8027, - 939, 8168, 8170, 8171, 910, 8169, 886, 934, 936, 928, 920, 932, 916, 922, - 915, 935, 914, 880, 918, 923, 895, 924, 925, 926, 1017, 1023, 1021, 1022, - 975, 1012, 8129, 8174, 8173, 901, 65915, 8190, 8159, 8158, 8157, 65920, - 65919, 119325, 119331, 119332, 119333, 119334, 119335, 119336, 119337, - 119326, 119338, 119339, 119340, 119341, 119342, 119343, 119344, 119345, - 119346, 119347, 119348, 119349, 119327, 119350, 119351, 119352, 119353, - 119354, 119355, 119356, 119328, 119357, 119358, 119359, 119360, 119361, - 119329, 119330, 65933, 1008, 983, 8125, 65922, 7466, 7464, 7462, 43877, - 7465, 7463, 992, 986, 984, 990, 988, 1011, 885, 1010, 1013, 65923, 884, - 65921, 119365, 65925, 65909, 65910, 65931, 8189, 65924, 65916, 8126, - 8127, 8143, 8142, 8141, 8128, 981, 982, 1020, 1009, 1014, 945, 8112, - 8048, 8114, 7937, 7941, 8069, 7943, 8071, 7939, 8067, 8065, 7936, 7940, - 8068, 7942, 8070, 7938, 8066, 8064, 8118, 8119, 8049, 8116, 8115, 940, - 8113, 985, 883, 989, 948, 949, 7953, 7957, 7955, 7952, 7956, 7954, 8051, - 8050, 941, 951, 7969, 7973, 8085, 7975, 8087, 7971, 8083, 8081, 7968, - 7972, 8084, 7974, 8086, 7970, 8082, 8080, 8134, 8135, 8053, 8132, 8052, - 8130, 8131, 942, 953, 7985, 7991, 7989, 7987, 970, 8151, 8147, 8146, 912, - 7984, 7990, 7988, 7986, 8150, 8144, 8054, 8055, 943, 8145, 965, 8017, - 8023, 8021, 8019, 971, 8167, 8163, 8162, 944, 8016, 8022, 8020, 8018, - 8166, 8160, 8058, 8059, 973, 8161, 954, 991, 969, 8033, 8037, 8101, 8039, - 8103, 8035, 8099, 8097, 8032, 8036, 8100, 8038, 8102, 8034, 8098, 8096, - 8182, 8183, 8061, 8180, 8060, 8178, 8179, 974, 959, 8001, 8005, 8003, - 8000, 8004, 8002, 8057, 8056, 972, 887, 966, 968, 960, 961, 8165, 8164, - 993, 1019, 987, 963, 1016, 952, 964, 962, 947, 967, 946, 881, 950, 955, - 956, 957, 958, 893, 891, 892, 7527, 7530, 7529, 7528, 7526, 65952, 65932, - 65918, 65912, 977, 65929, 65917, 65911, 900, 65914, 979, 980, 978, 8175, - 119297, 119315, 119316, 119317, 119318, 119319, 119300, 119320, 119321, - 119322, 119323, 119324, 119296, 119305, 119306, 119307, 119308, 119309, - 119310, 119311, 119312, 119313, 119314, 119298, 119299, 119301, 119302, - 119303, 119304, 890, 65913, 976, 65928, 65930, 894, 127823, 128215, - 128154, 129367, 129654, 128512, 129322, 129321, 128513, 128568, 128556, - 983110, 11218, 128151, 8370, 128130, 127928, 129454, 2693, 2694, 2704, - 2708, 2722, 2721, 2727, 2726, 2720, 2719, 2725, 2724, 2699, 2784, 2700, - 2785, 2741, 2697, 2698, 2695, 2696, 2739, 2738, 2809, 2713, 2723, 2718, - 2728, 2742, 2743, 2744, 2733, 2732, 2715, 2714, 2712, 2711, 2717, 2716, - 2710, 2709, 2731, 2730, 2745, 2734, 2736, 2735, 2703, 2707, 2814, 2689, - 2812, 2815, 2813, 2811, 2810, 2748, 2749, 2690, 2765, 2691, 2757, 2761, - 2750, 2760, 2764, 2753, 2754, 2755, 2756, 2786, 2787, 2751, 2752, 2759, - 2763, 2701, 2705, 2800, 2801, 2795, 2794, 2797, 2796, 2793, 2792, 2790, - 2799, 2791, 2798, 2768, 73092, 73082, 73056, 73057, 73064, 73067, 73091, - 73090, 73081, 73080, 73086, 73085, 73076, 73075, 73060, 73061, 73058, - 73059, 73087, 73077, 73071, 73070, 73084, 73083, 73079, 73078, 73089, - 73088, 73074, 73073, 73094, 73093, 73066, 73063, 73095, 73072, 73096, - 73097, 73069, 73068, 73110, 73109, 73098, 73105, 73108, 73101, 73102, - 73099, 73100, 73107, 73104, 73111, 73125, 73124, 73127, 73126, 73123, - 73122, 73120, 73129, 73121, 73128, 73112, 2678, 2673, 2650, 2584, 2583, - 2649, 2582, 2581, 2565, 2566, 2576, 2580, 2594, 2593, 2599, 2598, 2652, - 2608, 2592, 2591, 2597, 2596, 2569, 2570, 2567, 2568, 2611, 2610, 2585, - 2595, 2590, 2600, 2605, 2604, 2587, 2586, 2589, 2588, 2603, 2602, 2614, - 2616, 2579, 2575, 2654, 2617, 2606, 2613, 2607, 2651, 983656, 983655, - 983654, 983653, 983658, 983657, 2561, 2562, 2641, 2620, 2677, 2637, 2563, - 2622, 2632, 2636, 2625, 2626, 2623, 2624, 2635, 2631, 2672, 2674, 2676, - 2667, 2666, 2669, 2668, 2665, 2664, 2662, 2671, 2663, 2670, 2675, 90412, - 90414, 90411, 90410, 90373, 90388, 90382, 90381, 90387, 90386, 90380, - 90379, 90385, 90384, 90392, 90391, 90375, 90374, 90372, 90371, 90377, - 90376, 90370, 90369, 90390, 90389, 90378, 90396, 90393, 90395, 90397, - 90383, 90394, 90368, 90413, 90415, 90398, 90405, 90408, 90401, 90402, - 90406, 90407, 90399, 90400, 90403, 90404, 90409, 90421, 90420, 90423, - 90422, 90419, 90418, 90416, 90425, 90417, 90424, 128123, 983111, 129710, - 8202, 128135, 65467, 65441, 65443, 65444, 65445, 65446, 65469, 65458, + 170, 9792, 127905, 9972, 129338, 8210, 8199, 129775, 128193, 128452, + 983107, 128253, 127902, 129734, 10765, 128293, 128658, 129519, 127879, + 127878, 129512, 9789, 127771, 127763, 8296, 129351, 128031, 127907, 9673, + 127845, 128074, 8281, 11821, 127953, 129407, 129747, 9189, 117910, 9971, + 129449, 128170, 9884, 118466, 10086, 9880, 8277, 127924, 128190, 128563, + 129672, 129712, 128760, 117834, 117835, 118011, 129359, 128389, 127787, + 127745, 129709, 128448, 129462, 128099, 127860, 127869, 11792, 10972, + 129376, 118476, 983071, 8704, 8873, 10021, 11156, 8280, 8283, 10019, + 127808, 10018, 128966, 8732, 8197, 9970, 129749, 129418, 8260, 8543, + 128444, 128446, 128445, 118458, 127839, 8355, 129398, 10156, 128037, + 8994, 128550, 128056, 127844, 127773, 127765, 10199, 9608, 46, 65342, + 65312, 65292, 65306, 65504, 65375, 65371, 65288, 65339, 65308, 65313, + 65314, 65315, 65316, 65317, 65318, 65319, 65320, 65321, 65322, 65323, + 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, 65333, + 65334, 65335, 65336, 65337, 65338, 65345, 65346, 65347, 65348, 65349, + 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, + 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, + 65370, 65343, 65506, 65283, 65505, 65285, 65291, 65376, 65373, 65289, + 65341, 65340, 65307, 65295, 65509, 65507, 65287, 65286, 65290, 65284, + 65301, 65300, 65303, 65302, 65299, 65298, 65296, 65305, 65297, 65304, + 65309, 65281, 65344, 65310, 65293, 65282, 65311, 65510, 65374, 65294, + 65508, 65372, 8289, 9905, 118280, 9981, 9179, 983215, 983216, 983217, + 983219, 983108, 983236, 983072, 68972, 68971, 68973, 68970, 68964, 68965, + 68959, 68961, 68948, 68945, 68954, 68960, 68953, 68963, 68949, 68947, + 68952, 68946, 68962, 68958, 68950, 68957, 68951, 68955, 68956, 68944, + 68996, 68997, 68991, 68993, 68980, 68977, 68986, 68992, 68985, 68995, + 68981, 68979, 68984, 68978, 68994, 68990, 68982, 68989, 68983, 68987, + 68988, 68976, 68943, 68969, 68941, 68938, 68939, 68940, 68942, 68975, + 68974, 69006, 69007, 68933, 68932, 68935, 68934, 68931, 68930, 68928, + 68937, 68929, 68936, 129476, 127922, 9881, 9965, 9966, 128142, 9802, + 118501, 118506, 118498, 118503, 118510, 118505, 118502, 118508, 118499, + 118504, 118497, 118507, 118509, 118496, 118500, 118511, 8782, 8785, 8762, + 4301, 4256, 4288, 4292, 4290, 4293, 4289, 4281, 4285, 4284, 4282, 4278, + 4258, 4287, 4283, 4277, 4265, 4276, 4270, 4280, 4273, 4271, 4262, 4263, + 4274, 4266, 4272, 4257, 4267, 4286, 4268, 4279, 4261, 4259, 4260, 4264, + 4269, 4275, 4295, 4291, 11565, 11520, 11552, 11556, 11554, 11557, 11553, + 11545, 11549, 11548, 11546, 11542, 11522, 11551, 11547, 11541, 11529, + 11540, 11534, 11544, 11537, 11535, 11526, 11527, 11538, 11530, 11536, + 11521, 11531, 11550, 11532, 11543, 11525, 11523, 11524, 11528, 11533, + 11539, 11559, 11555, 983955, 4323, 4349, 4346, 4304, 4329, 4333, 4332, + 4330, 4344, 4308, 4326, 4306, 4340, 4350, 4336, 4338, 4341, 4337, 4335, + 4331, 4325, 4313, 4351, 4314, 4324, 4318, 4328, 4321, 4345, 4311, 4322, + 4319, 4310, 4320, 4305, 4315, 4334, 4316, 4327, 4309, 4307, 4312, 4317, + 4343, 4339, 4342, 7357, 7354, 7312, 7337, 7341, 7340, 7338, 7352, 7316, + 7334, 7314, 7348, 7358, 7344, 7346, 7349, 7345, 7343, 7339, 7333, 7321, + 7359, 7322, 7332, 7326, 7336, 7329, 7353, 7319, 7330, 7327, 7318, 7328, + 7313, 7323, 7342, 7324, 7335, 7317, 7315, 7320, 7325, 7331, 7351, 7347, + 7350, 4347, 8368, 12307, 129502, 8503, 129754, 128103, 128714, 129426, + 11264, 11304, 11265, 11311, 11293, 11276, 11268, 11271, 11287, 11306, + 11267, 11275, 11274, 11305, 11303, 11307, 11273, 11310, 11278, 11279, + 11280, 11281, 11289, 11282, 11290, 11283, 11291, 11308, 11294, 11284, + 11298, 11300, 11301, 11285, 11309, 11292, 11266, 11269, 11296, 11295, + 11297, 11302, 11299, 11272, 11270, 11288, 11286, 11277, 11312, 11352, + 11313, 11359, 11341, 11324, 11316, 11319, 11335, 11354, 11315, 11323, + 11322, 11353, 11351, 11355, 11321, 11358, 11326, 11327, 11328, 11329, + 11337, 11330, 11338, 11331, 11339, 11356, 11342, 11332, 11346, 11348, + 11349, 11333, 11357, 11340, 11314, 11317, 11344, 11343, 11345, 11350, + 11347, 11320, 11318, 11336, 11334, 11325, 129371, 127760, 127775, 129508, + 10726, 129349, 128016, 66356, 66352, 66376, 66359, 66358, 66375, 66378, + 66369, 66365, 66368, 66357, 66370, 66360, 66372, 66373, 66367, 66374, + 66353, 66377, 66355, 66364, 66361, 66363, 66371, 66366, 66354, 66362, + 129421, 129405, 128893, 129727, 127948, 127891, 70495, 70494, 70411, + 70496, 70412, 70497, 70453, 70405, 70406, 70416, 70420, 70434, 70433, + 70439, 70438, 70432, 70431, 70437, 70436, 70409, 70410, 70407, 70408, + 70451, 70450, 70425, 70435, 70430, 70440, 70454, 70455, 70456, 70445, + 70444, 70427, 70426, 70424, 70423, 70429, 70428, 70422, 70421, 70443, + 70442, 70419, 70415, 70457, 70446, 70448, 70447, 70400, 70401, 70460, + 70461, 70402, 70493, 70477, 70403, 70487, 70462, 70472, 70476, 70465, + 70466, 70467, 70468, 70498, 70499, 70463, 70464, 70475, 70471, 70480, 96, + 127815, 10896, 10894, 10900, 10892, 10898, 10616, 10890, 10888, 10917, + 8935, 8809, 10878, 10882, 10884, 10880, 10886, 8819, 8805, 8823, 10916, + 8807, 8923, 10919, 10921, 10874, 10876, 8919, 62, 65860, 65863, 65878, + 65866, 65873, 65859, 65861, 65868, 65875, 65862, 65870, 65864, 65871, + 65867, 65874, 65857, 65869, 65876, 65856, 65858, 65865, 65877, 65872, + 65879, 65903, 65885, 65904, 65907, 65908, 65900, 65883, 65886, 65896, + 65890, 65882, 65880, 65891, 65902, 65906, 65897, 65899, 65893, 65892, + 65884, 65881, 65898, 65905, 65887, 65901, 65894, 65895, 65888, 65889, + 903, 65927, 65926, 913, 7945, 7949, 8077, 7947, 8075, 7951, 8079, 8073, + 7944, 7948, 8076, 7946, 8074, 7950, 8078, 8072, 8124, 8120, 8122, 8123, + 902, 8121, 882, 919, 7977, 7981, 8093, 7979, 8091, 7983, 8095, 8089, + 7976, 7980, 8092, 7978, 8090, 7982, 8094, 8088, 8140, 8139, 8138, 905, + 917, 7961, 7965, 7963, 7960, 7964, 7962, 8137, 8136, 904, 921, 7993, + 7999, 7997, 7995, 938, 7992, 7998, 7996, 7994, 8152, 8154, 8155, 906, + 8153, 937, 8041, 8045, 8109, 8043, 8107, 8047, 8111, 8105, 8040, 8044, + 8108, 8042, 8106, 8046, 8110, 8104, 8188, 8187, 8186, 911, 927, 8009, + 8013, 8011, 8008, 8012, 8010, 8185, 8184, 908, 929, 8172, 931, 1018, + 1015, 933, 8025, 8031, 8029, 8027, 939, 8168, 8170, 8171, 910, 8169, 886, + 934, 936, 928, 920, 932, 916, 922, 915, 935, 914, 880, 918, 923, 895, + 924, 925, 926, 1017, 1023, 1021, 1022, 975, 1012, 8129, 8174, 8173, 901, + 65915, 8190, 8159, 8158, 8157, 65920, 65919, 119325, 119331, 119332, + 119333, 119334, 119335, 119336, 119337, 119326, 119338, 119339, 119340, + 119341, 119342, 119343, 119344, 119345, 119346, 119347, 119348, 119349, + 119327, 119350, 119351, 119352, 119353, 119354, 119355, 119356, 119328, + 119357, 119358, 119359, 119360, 119361, 119329, 119330, 65933, 1008, 983, + 8125, 65922, 7466, 7464, 7462, 43877, 7465, 7463, 992, 986, 984, 990, + 988, 1011, 885, 1010, 1013, 65923, 884, 65921, 119365, 65925, 65909, + 65910, 65931, 8189, 65924, 65916, 8126, 8127, 8143, 8142, 8141, 8128, + 981, 982, 1020, 1009, 1014, 945, 8112, 8048, 8114, 7937, 7941, 8069, + 7943, 8071, 7939, 8067, 8065, 7936, 7940, 8068, 7942, 8070, 7938, 8066, + 8064, 8118, 8119, 8049, 8116, 8115, 940, 8113, 985, 883, 989, 948, 949, + 7953, 7957, 7955, 7952, 7956, 7954, 8051, 8050, 941, 951, 7969, 7973, + 8085, 7975, 8087, 7971, 8083, 8081, 7968, 7972, 8084, 7974, 8086, 7970, + 8082, 8080, 8134, 8135, 8053, 8132, 8052, 8130, 8131, 942, 953, 7985, + 7991, 7989, 7987, 970, 8151, 8147, 8146, 912, 7984, 7990, 7988, 7986, + 8150, 8144, 8054, 8055, 943, 8145, 965, 8017, 8023, 8021, 8019, 971, + 8167, 8163, 8162, 944, 8016, 8022, 8020, 8018, 8166, 8160, 8058, 8059, + 973, 8161, 954, 991, 969, 8033, 8037, 8101, 8039, 8103, 8035, 8099, 8097, + 8032, 8036, 8100, 8038, 8102, 8034, 8098, 8096, 8182, 8183, 8061, 8180, + 8060, 8178, 8179, 974, 959, 8001, 8005, 8003, 8000, 8004, 8002, 8057, + 8056, 972, 887, 966, 968, 960, 961, 8165, 8164, 993, 1019, 987, 963, + 1016, 952, 964, 962, 947, 967, 946, 881, 950, 955, 956, 957, 958, 893, + 891, 892, 7527, 7530, 7529, 7528, 7526, 65952, 65932, 65918, 65912, 977, + 65929, 65917, 65911, 900, 65914, 979, 980, 978, 8175, 119297, 119315, + 119316, 119317, 119318, 119319, 119300, 119320, 119321, 119322, 119323, + 119324, 119296, 119305, 119306, 119307, 119308, 119309, 119310, 119311, + 119312, 119313, 119314, 119298, 119299, 119301, 119302, 119303, 119304, + 890, 65913, 976, 65928, 65930, 894, 127823, 128215, 128154, 129367, + 129654, 128512, 129322, 129321, 128513, 128568, 128556, 983110, 11218, + 128151, 8370, 128130, 127928, 129454, 2693, 2694, 2704, 2708, 2722, 2721, + 2727, 2726, 2720, 2719, 2725, 2724, 2699, 2784, 2700, 2785, 2741, 2697, + 2698, 2695, 2696, 2739, 2738, 2809, 2713, 2723, 2718, 2728, 2742, 2743, + 2744, 2733, 2732, 2715, 2714, 2712, 2711, 2717, 2716, 2710, 2709, 2731, + 2730, 2745, 2734, 2736, 2735, 2703, 2707, 2814, 2689, 2812, 2815, 2813, + 2811, 2810, 2748, 2749, 2690, 2765, 2691, 2757, 2761, 2750, 2760, 2764, + 2753, 2754, 2755, 2756, 2786, 2787, 2751, 2752, 2759, 2763, 2701, 2705, + 2800, 2801, 2795, 2794, 2797, 2796, 2793, 2792, 2790, 2799, 2791, 2798, + 2768, 73092, 73082, 73056, 73057, 73064, 73067, 73091, 73090, 73081, + 73080, 73086, 73085, 73076, 73075, 73060, 73061, 73058, 73059, 73087, + 73077, 73071, 73070, 73084, 73083, 73079, 73078, 73089, 73088, 73074, + 73073, 73094, 73093, 73066, 73063, 73095, 73072, 73096, 73097, 73069, + 73068, 73110, 73109, 73098, 73105, 73108, 73101, 73102, 73099, 73100, + 73107, 73104, 73111, 73125, 73124, 73127, 73126, 73123, 73122, 73120, + 73129, 73121, 73128, 73112, 2678, 2673, 2650, 2584, 2583, 2649, 2582, + 2581, 2565, 2566, 2576, 2580, 2594, 2593, 2599, 2598, 2652, 2608, 2592, + 2591, 2597, 2596, 2569, 2570, 2567, 2568, 2611, 2610, 2585, 2595, 2590, + 2600, 2605, 2604, 2587, 2586, 2589, 2588, 2603, 2602, 2614, 2616, 2579, + 2575, 2654, 2617, 2606, 2613, 2607, 2651, 983656, 983655, 983654, 983653, + 983658, 983657, 2561, 2562, 2641, 2620, 2677, 2637, 2563, 2622, 2632, + 2636, 2625, 2626, 2623, 2624, 2635, 2631, 2672, 2674, 2676, 2667, 2666, + 2669, 2668, 2665, 2664, 2662, 2671, 2663, 2670, 2675, 90412, 90414, + 90411, 90410, 90373, 90388, 90382, 90381, 90387, 90386, 90380, 90379, + 90385, 90384, 90392, 90391, 90375, 90374, 90372, 90371, 90377, 90376, + 90370, 90369, 90390, 90389, 90378, 90396, 90393, 90395, 90397, 90383, + 90394, 90368, 90413, 90415, 90398, 90405, 90408, 90401, 90402, 90406, + 90407, 90399, 90400, 90403, 90404, 90409, 90421, 90420, 90423, 90422, + 90419, 90418, 90416, 90425, 90417, 90424, 128123, 983111, 129710, 8202, + 129736, 128135, 65467, 65441, 65443, 65444, 65445, 65446, 65469, 65458, 65460, 65449, 65454, 65455, 65452, 65451, 65450, 65456, 65453, 65465, 65442, 65459, 65448, 65462, 65461, 65483, 65482, 65476, 65477, 65499, 65490, 65495, 65466, 65464, 65479, 65478, 65498, 65500, 65463, 65457, @@ -11169,81 +11290,81 @@ static const unsigned int dawg_pos_to_codepoint[] = { 64292, 64291, 64294, 1497, 64285, 64313, 64335, 1520, 1522, 64287, 1521, 1477, 1476, 1455, 1468, 1458, 1459, 1457, 1460, 1465, 1466, 1463, 1464, 1479, 1467, 1471, 1462, 1473, 1456, 1474, 1461, 64286, 1469, 1524, 1523, - 1472, 1475, 1478, 1470, 1519, 9937, 9096, 11263, 128641, 110597, 110594, - 110595, 110596, 110778, 110779, 110780, 110781, 110782, 110783, 110784, - 110785, 110750, 110759, 110760, 110751, 110752, 110753, 110754, 110755, - 110756, 110757, 110758, 110768, 110769, 110770, 110771, 110772, 110773, - 110774, 110775, 110776, 110777, 110761, 110762, 110763, 110764, 110765, - 110766, 110767, 110615, 110624, 110625, 110626, 110616, 110617, 110618, - 110619, 110620, 110621, 110622, 110623, 110651, 110648, 110649, 110650, - 110627, 110628, 110629, 110630, 110631, 110632, 110633, 110634, 110642, - 110643, 110644, 110645, 110646, 110647, 110635, 110636, 110637, 110638, - 110639, 110640, 110641, 110806, 110804, 110805, 110807, 110808, 110809, - 110810, 110811, 110812, 110786, 110787, 110788, 110789, 110790, 110791, - 110792, 110793, 110794, 110795, 110796, 110797, 110798, 110799, 110800, - 110801, 110802, 110803, 110744, 110738, 110739, 110740, 110741, 110742, - 110743, 110734, 110727, 110728, 110729, 110730, 110731, 110732, 110733, - 110718, 110719, 110720, 110721, 110722, 110723, 110724, 110725, 110726, - 110745, 110746, 110747, 110748, 110749, 110735, 110736, 110737, 110877, - 110878, 110850, 110851, 110852, 110853, 110854, 110855, 110840, 110841, - 110842, 110843, 110844, 110845, 110833, 110834, 110835, 110836, 110837, - 110838, 110839, 110829, 110830, 110831, 110832, 110846, 110847, 110848, - 110849, 110652, 110653, 110654, 110655, 110656, 110657, 110658, 110659, - 110666, 110667, 110668, 110669, 110670, 110671, 110672, 110673, 110660, - 110661, 110662, 110663, 110664, 110665, 110674, 110675, 110676, 110677, - 110678, 110679, 110680, 110681, 110682, 110683, 110684, 110685, 110702, - 110703, 110704, 110705, 110706, 110707, 110708, 110709, 110710, 110717, - 110711, 110712, 110713, 110714, 110715, 110716, 110701, 110697, 110698, - 110699, 110700, 110690, 110691, 110692, 110693, 110694, 110695, 110696, - 110686, 110687, 110688, 110689, 110856, 110857, 110858, 110859, 110860, - 110861, 110862, 110863, 110864, 110865, 110870, 110871, 110872, 110873, - 110874, 110875, 110876, 110866, 110867, 110868, 110869, 110818, 110813, - 110814, 110815, 110816, 110817, 110823, 110824, 110825, 110826, 110827, - 110828, 110819, 110820, 110821, 110822, 983273, 110607, 110608, 110609, - 110610, 110611, 110602, 110603, 110604, 110605, 110606, 110612, 110613, - 110614, 110598, 110599, 110600, 110601, 8889, 127807, 19922, 19966, - 19958, 19967, 19924, 19946, 19923, 19909, 19947, 19944, 19943, 19956, - 19906, 19962, 19935, 19939, 19920, 19916, 19948, 19917, 19937, 19931, - 19929, 19925, 19911, 19928, 19964, 19945, 19934, 19918, 19930, 19942, - 19950, 19941, 19949, 19938, 19914, 19927, 19936, 19952, 19965, 19912, - 19915, 19926, 19954, 19910, 19932, 19953, 19904, 19933, 19940, 19905, - 19951, 19959, 19957, 19960, 19955, 19961, 19913, 19908, 19921, 19963, - 19907, 19919, 129428, 128262, 9889, 983123, 128644, 128645, 128096, - 12447, 12354, 110879, 110593, 12430, 110929, 110928, 110930, 12419, - 12423, 12421, 12437, 12438, 110898, 12387, 12353, 12359, 12355, 12361, - 12357, 12373, 12379, 12375, 12381, 12377, 12403, 983997, 984000, 983998, - 984001, 983999, 12400, 12409, 12412, 12406, 12435, 12394, 12397, 12395, - 12398, 12396, 12384, 12391, 12386, 12393, 12389, 12364, 12370, 12366, - 12372, 12368, 12399, 12408, 12402, 12411, 12405, 12363, 12369, 12365, - 12371, 12367, 12414, 12417, 12415, 12418, 12416, 12401, 12410, 12404, - 12413, 12407, 12425, 12428, 12426, 12429, 12427, 12383, 12390, 12385, - 12392, 12388, 12374, 12380, 12376, 12382, 12378, 12431, 12433, 12432, - 12434, 12420, 12424, 12422, 12436, 12360, 12356, 12362, 12358, 12446, - 12445, 9964, 128725, 129406, 127802, 129435, 128616, 128617, 128371, - 128029, 127855, 11203, 11043, 8213, 118290, 118287, 117905, 9135, 117893, - 129921, 129910, 129911, 129912, 129913, 129914, 129915, 9146, 9147, 9148, - 9149, 983059, 983141, 983138, 11134, 128677, 117779, 8230, 9897, 117915, - 117769, 118448, 128014, 127943, 128052, 127798, 9749, 9832, 127789, - 127976, 8987, 9203, 8962, 127969, 127968, 127960, 127973, 128298, 8763, - 129693, 983124, 983060, 983142, 983139, 128559, 128175, 129303, 128726, - 8208, 11802, 8259, 8231, 45, 11794, 9102, 11226, 129723, 8372, 127848, - 129482, 127954, 9976, 8801, 10725, 10855, 129706, 12696, 12700, 12693, - 12697, 12695, 12703, 12692, 12699, 12691, 12694, 12688, 12698, 12690, - 12689, 12701, 12702, 12294, 12289, 12275, 12273, 12274, 12272, 12283, - 12282, 12285, 12279, 12280, 12281, 12278, 12277, 12284, 12783, 12287, - 12276, 12286, 12332, 12295, 119670, 119669, 119668, 119667, 119666, - 12999, 12995, 13309, 13310, 13292, 13282, 13299, 13304, 13303, 13306, - 13305, 13302, 13301, 13308, 13300, 13307, 13291, 13281, 13289, 13287, - 13297, 13290, 13294, 13284, 13283, 13293, 13288, 13298, 13286, 13296, - 13285, 13295, 13280, 13003, 13164, 13168, 13167, 13166, 13165, 13156, - 13146, 13157, 13147, 13154, 13152, 13162, 13155, 13159, 13149, 13148, - 13158, 13153, 13163, 13151, 13161, 13150, 13160, 13144, 13145, 12992, - 12997, 12998, 12993, 12994, 12996, 13002, 13000, 13001, 12343, 12351, - 12333, 12331, 12330, 12350, 12290, 12293, 12288, 8887, 8787, 128127, - 67676, 67673, 67675, 67679, 67674, 67672, 67677, 67678, 67656, 67669, - 67651, 67659, 67666, 67667, 67648, 67663, 67650, 67654, 67662, 67665, - 67668, 67657, 67652, 67655, 67658, 67649, 67661, 67653, 67664, 67660, - 67671, 128232, 10716, 128474, 10721, 8710, 983130, 983129, 129781, + 1472, 1475, 1478, 1470, 1519, 118464, 9937, 9096, 11263, 128641, 110597, + 110594, 110595, 110596, 110778, 110779, 110780, 110781, 110782, 110783, + 110784, 110785, 110750, 110759, 110760, 110751, 110752, 110753, 110754, + 110755, 110756, 110757, 110758, 110768, 110769, 110770, 110771, 110772, + 110773, 110774, 110775, 110776, 110777, 110761, 110762, 110763, 110764, + 110765, 110766, 110767, 110615, 110624, 110625, 110626, 110616, 110617, + 110618, 110619, 110620, 110621, 110622, 110623, 110651, 110648, 110649, + 110650, 110627, 110628, 110629, 110630, 110631, 110632, 110633, 110634, + 110642, 110643, 110644, 110645, 110646, 110647, 110635, 110636, 110637, + 110638, 110639, 110640, 110641, 110806, 110804, 110805, 110807, 110808, + 110809, 110810, 110811, 110812, 110786, 110787, 110788, 110789, 110790, + 110791, 110792, 110793, 110794, 110795, 110796, 110797, 110798, 110799, + 110800, 110801, 110802, 110803, 110744, 110738, 110739, 110740, 110741, + 110742, 110743, 110734, 110727, 110728, 110729, 110730, 110731, 110732, + 110733, 110718, 110719, 110720, 110721, 110722, 110723, 110724, 110725, + 110726, 110745, 110746, 110747, 110748, 110749, 110735, 110736, 110737, + 110877, 110878, 110850, 110851, 110852, 110853, 110854, 110855, 110840, + 110841, 110842, 110843, 110844, 110845, 110833, 110834, 110835, 110836, + 110837, 110838, 110839, 110829, 110830, 110831, 110832, 110846, 110847, + 110848, 110849, 110652, 110653, 110654, 110655, 110656, 110657, 110658, + 110659, 110666, 110667, 110668, 110669, 110670, 110671, 110672, 110673, + 110660, 110661, 110662, 110663, 110664, 110665, 110674, 110675, 110676, + 110677, 110678, 110679, 110680, 110681, 110682, 110683, 110684, 110685, + 110702, 110703, 110704, 110705, 110706, 110707, 110708, 110709, 110710, + 110717, 110711, 110712, 110713, 110714, 110715, 110716, 110701, 110697, + 110698, 110699, 110700, 110690, 110691, 110692, 110693, 110694, 110695, + 110696, 110686, 110687, 110688, 110689, 110856, 110857, 110858, 110859, + 110860, 110861, 110862, 110863, 110864, 110865, 110870, 110871, 110872, + 110873, 110874, 110875, 110876, 110866, 110867, 110868, 110869, 110818, + 110813, 110814, 110815, 110816, 110817, 110823, 110824, 110825, 110826, + 110827, 110828, 110819, 110820, 110821, 110822, 983277, 110607, 110608, + 110609, 110610, 110611, 110602, 110603, 110604, 110605, 110606, 110612, + 110613, 110614, 110598, 110599, 110600, 110601, 8889, 127807, 19922, + 19966, 19958, 19967, 19924, 19946, 19923, 19909, 19947, 19944, 19943, + 19956, 19906, 19962, 19935, 19939, 19920, 19916, 19948, 19917, 19937, + 19931, 19929, 19925, 19911, 19928, 19964, 19945, 19934, 19918, 19930, + 19942, 19950, 19941, 19949, 19938, 19914, 19927, 19936, 19952, 19965, + 19912, 19915, 19926, 19954, 19910, 19932, 19953, 19904, 19933, 19940, + 19905, 19951, 19959, 19957, 19960, 19955, 19961, 19913, 19908, 19921, + 19963, 19907, 19919, 129428, 128262, 9889, 983123, 128644, 128645, + 128096, 12447, 12354, 110879, 110593, 12430, 110929, 110928, 110930, + 12419, 12423, 12421, 12437, 12438, 110898, 12387, 12353, 12359, 12355, + 12361, 12357, 12373, 12379, 12375, 12381, 12377, 12403, 983997, 984000, + 983998, 984001, 983999, 12400, 12409, 12412, 12406, 12435, 12394, 12397, + 12395, 12398, 12396, 12384, 12391, 12386, 12393, 12389, 12364, 12370, + 12366, 12372, 12368, 12399, 12408, 12402, 12411, 12405, 12363, 12369, + 12365, 12371, 12367, 12414, 12417, 12415, 12418, 12416, 12401, 12410, + 12404, 12413, 12407, 12425, 12428, 12426, 12429, 12427, 12383, 12390, + 12385, 12392, 12388, 12374, 12380, 12376, 12382, 12378, 12431, 12433, + 12432, 12434, 12420, 12424, 12422, 12436, 12360, 12356, 12362, 12358, + 12446, 12445, 9964, 128725, 129406, 127802, 129435, 128616, 128617, + 128371, 128029, 127855, 11203, 11043, 8213, 118290, 118287, 117905, 9135, + 117893, 129921, 129910, 129911, 129912, 129913, 129914, 129915, 9146, + 9147, 9148, 9149, 983059, 983141, 983138, 11134, 128677, 117779, 8230, + 9897, 117915, 117769, 118448, 128014, 127943, 128052, 127798, 9749, 9832, + 127789, 127976, 8987, 9203, 8962, 127969, 127968, 127960, 127973, 128298, + 8763, 129693, 983124, 983060, 983142, 983139, 128559, 128175, 129303, + 128726, 11226, 128889, 8208, 11802, 8259, 8231, 45, 11794, 9102, 129723, + 8372, 127848, 129482, 127954, 9976, 8801, 10725, 10855, 129706, 12696, + 12700, 12693, 12697, 12695, 12703, 12692, 12699, 12691, 12694, 12688, + 12698, 12690, 12689, 12701, 12702, 12294, 12289, 12275, 12273, 12274, + 12272, 12283, 12282, 12285, 12279, 12280, 12281, 12278, 12277, 12284, + 12783, 12287, 12276, 12286, 12332, 12295, 119670, 119669, 119668, 119667, + 119666, 12999, 12995, 13309, 13310, 13292, 13282, 13299, 13304, 13303, + 13306, 13305, 13302, 13301, 13308, 13300, 13307, 13291, 13281, 13289, + 13287, 13297, 13290, 13294, 13284, 13283, 13293, 13288, 13298, 13286, + 13296, 13285, 13295, 13280, 13003, 13164, 13168, 13167, 13166, 13165, + 13156, 13146, 13157, 13147, 13154, 13152, 13162, 13155, 13159, 13149, + 13148, 13158, 13153, 13163, 13151, 13161, 13150, 13160, 13144, 13145, + 12992, 12997, 12998, 12993, 12994, 12996, 13002, 13000, 13001, 12343, + 12351, 12333, 12331, 12330, 12350, 12290, 12293, 12288, 8887, 8787, + 128127, 67676, 67673, 67675, 67679, 67674, 67672, 67677, 67678, 67656, + 67669, 67651, 67659, 67666, 67667, 67648, 67663, 67650, 67654, 67662, + 67665, 67668, 67657, 67652, 67655, 67658, 67649, 67661, 67653, 67664, + 67660, 67671, 128232, 10716, 128474, 10721, 8710, 983130, 983129, 129781, 126132, 126112, 126126, 126125, 126127, 126131, 126130, 126129, 126113, 126114, 126110, 126111, 126072, 126081, 126108, 126090, 126099, 126078, 126105, 126069, 126087, 126096, 126077, 126104, 126068, 126086, 126095, @@ -11263,254 +11384,255 @@ static const unsigned int dawg_pos_to_codepoint[] = { 9134, 65529, 65531, 65530, 9892, 8745, 10825, 10823, 10820, 10819, 10816, 10827, 8253, 8890, 10812, 117901, 117903, 9688, 129942, 129969, 129972, 9689, 129936, 11800, 11845, 11846, 8766, 9959, 161, 8487, 8276, 191, - 8290, 8292, 8291, 128229, 127982, 129311, 127875, 127983, 127971, 12292, - 9979, 127886, 128304, 128122, 128121, 43453, 43454, 43455, 43457, 43421, - 43422, 43426, 43427, 43398, 43397, 43399, 43407, 43408, 43409, 43412, - 43402, 43403, 43418, 43416, 43428, 43423, 43431, 43432, 43413, 43414, - 43410, 43411, 43429, 43430, 43401, 43435, 43436, 43441, 43439, 43440, - 43424, 43425, 43419, 43420, 43415, 43417, 43396, 43405, 43442, 43437, - 43433, 43438, 43434, 43404, 43406, 43400, 43458, 43466, 43467, 43459, - 43465, 43461, 43464, 43468, 43463, 43486, 43462, 43487, 43460, 43471, - 43456, 43469, 43393, 43443, 43392, 43395, 43394, 43448, 43449, 43444, - 43450, 43445, 43446, 43447, 43452, 43451, 43477, 43476, 43479, 43478, - 43475, 43474, 43472, 43481, 43473, 43480, 129753, 129724, 128086, 128377, - 10781, 129337, 9795, 9909, 129513, 69786, 69787, 69785, 69793, 69792, - 69763, 69764, 69770, 69772, 69784, 69783, 69791, 69790, 69767, 69768, - 69765, 69766, 69777, 69789, 69782, 69794, 69804, 69805, 69806, 69798, - 69797, 69779, 69778, 69776, 69775, 69781, 69780, 69774, 69773, 69796, - 69795, 69788, 69801, 69807, 69802, 69799, 69803, 69800, 69769, 69771, - 69760, 69818, 69761, 69817, 69762, 69822, 69823, 69825, 69824, 69826, - 69808, 69814, 69816, 69811, 69812, 69809, 69810, 69813, 69815, 69821, - 69837, 69819, 69820, 12142, 12164, 12060, 12157, 12100, 12149, 12184, - 12191, 12227, 12068, 12174, 12234, 12205, 12134, 12168, 12219, 12189, - 12088, 12090, 12096, 12160, 12182, 12224, 12190, 12147, 12114, 12118, - 12058, 12176, 12075, 12112, 12045, 12170, 12124, 12070, 12194, 12109, - 12229, 12196, 12139, 12056, 12099, 12034, 12084, 12136, 12120, 12044, - 12111, 12094, 12125, 12243, 12238, 12082, 12159, 12063, 12215, 12062, - 12042, 12241, 12067, 12235, 12043, 12140, 12119, 12207, 12123, 12133, - 12222, 12117, 12226, 12245, 12214, 12217, 12236, 12155, 12188, 12113, - 12065, 12198, 12066, 12146, 12171, 12225, 12200, 12121, 12093, 12095, - 12221, 12092, 12216, 12231, 12054, 12218, 12179, 12037, 12173, 12072, - 12046, 12127, 12152, 12049, 12074, 12107, 12208, 12212, 12041, 12210, - 12131, 12033, 12039, 12199, 12085, 12128, 12161, 12162, 12233, 12165, - 12192, 12077, 12201, 12061, 12105, 12040, 12240, 12102, 12153, 12032, - 12080, 12167, 12048, 12156, 12059, 12126, 12158, 12050, 12183, 12204, - 12097, 12239, 12053, 12078, 12150, 12071, 12187, 12186, 12223, 12228, - 12104, 12098, 12064, 12036, 12057, 12163, 12178, 12185, 12154, 12203, - 12083, 12087, 12135, 12151, 12202, 12035, 12122, 12141, 12180, 12144, - 12076, 12052, 12115, 12091, 12108, 12169, 12143, 12148, 12130, 12089, - 12211, 12073, 12101, 12138, 12103, 12209, 12047, 12220, 12172, 12129, - 12166, 12242, 12237, 12145, 12106, 12081, 12244, 12038, 12086, 12055, - 12181, 12197, 12193, 12175, 12116, 12110, 12177, 12137, 12230, 12213, - 12195, 12069, 12079, 12206, 12051, 12232, 12132, 129432, 3240, 3293, - 3225, 3235, 3230, 3205, 3206, 3216, 3220, 3234, 3233, 3239, 3238, 983205, - 3251, 3250, 3249, 3248, 3232, 3231, 3237, 3236, 3211, 3296, 3212, 3297, - 3253, 3209, 3210, 3218, 3219, 3207, 3208, 3254, 3255, 3256, 3245, 3244, - 3227, 3226, 3224, 3223, 3229, 3228, 3222, 3221, 3243, 3242, 3214, 3215, - 3294, 3257, 3246, 3247, 3285, 3315, 3201, 3200, 3204, 3260, 3261, 3202, - 3313, 3314, 3277, 3203, 3286, 3262, 3272, 3276, 3265, 3266, 3267, 3268, - 3298, 3299, 3274, 3275, 3263, 3264, 3270, 3271, 3307, 3306, 3309, 3308, - 3305, 3304, 3302, 3311, 3303, 3310, 12450, 984009, 984008, 984007, - 984010, 110881, 110880, 110882, 110592, 12499, 984002, 984005, 984003, - 984006, 984004, 12496, 12505, 12508, 12502, 12511, 110583, 110584, - 110585, 110586, 110587, 110589, 110590, 110576, 110577, 110578, 110579, - 110581, 110582, 12510, 12513, 12514, 12512, 12531, 12490, 12493, 12491, - 12494, 12492, 12789, 12792, 12790, 12793, 12791, 12795, 12798, 12796, - 12799, 12797, 12533, 12534, 110933, 12784, 12787, 12483, 12526, 110949, - 110948, 110950, 12515, 12519, 12517, 110951, 12788, 12785, 12786, 12794, - 12449, 12455, 12451, 12457, 12453, 12469, 12475, 12471, 12477, 12473, - 12480, 12487, 12482, 12489, 12485, 12460, 12466, 12462, 12468, 12464, - 12495, 12504, 12498, 12507, 12501, 12459, 12465, 12461, 12467, 12463, - 12497, 12506, 12500, 12509, 12503, 12521, 12524, 12522, 12525, 12523, - 12479, 12486, 12481, 12488, 12484, 12535, 12537, 12536, 12538, 12532, - 12470, 12476, 12472, 12478, 12474, 12527, 12529, 12528, 12530, 12516, - 12520, 12518, 12456, 12452, 12458, 12454, 12542, 12543, 12541, 12539, - 12448, 12540, 12444, 12443, 73476, 73477, 73487, 73523, 73498, 73497, - 73503, 73502, 73508, 73507, 73501, 73500, 73506, 73505, 73480, 73481, - 73482, 73483, 73484, 73485, 73478, 73479, 73494, 73504, 73499, 73509, - 73519, 73520, 73521, 73513, 73512, 73496, 73495, 73493, 73492, 73491, - 73490, 73511, 73510, 73522, 73517, 73514, 73516, 73518, 73515, 73486, - 73488, 73551, 73548, 73546, 73545, 73549, 73543, 73541, 73544, 73550, - 73542, 73547, 73537, 73472, 73562, 73474, 73475, 73473, 73525, 73524, - 73535, 73530, 73534, 73536, 73528, 73529, 73526, 73527, 73540, 73539, - 73557, 73556, 73559, 73558, 73555, 73554, 73552, 73561, 73553, 73560, - 73538, 43299, 43301, 43283, 43295, 43277, 43281, 43284, 43275, 43274, - 43286, 43285, 43279, 43278, 43294, 43282, 43289, 43297, 43288, 43276, - 43292, 43287, 43290, 43296, 43293, 43291, 43280, 43298, 43300, 43310, - 43311, 43308, 43309, 43307, 43303, 43305, 43304, 43302, 43306, 43269, - 43268, 43271, 43270, 43267, 43266, 43264, 43273, 43265, 43272, 119496, - 119506, 119499, 119503, 119493, 119492, 119502, 119497, 119507, 119495, - 119505, 119494, 119504, 119501, 119491, 119500, 119490, 119498, 119488, - 119489, 128331, 8490, 128273, 9000, 128422, 983552, 983553, 983559, - 983558, 983561, 983560, 983557, 983556, 983554, 983563, 983555, 983562, - 128287, 118449, 68163, 68162, 68161, 68160, 68113, 68146, 68112, 68147, - 68148, 68123, 68122, 68128, 68127, 68126, 68121, 68131, 68125, 68124, - 68130, 68129, 68141, 68142, 68143, 68135, 68134, 68118, 68117, 68115, - 68114, 68133, 68132, 68149, 68140, 68145, 68119, 68139, 68136, 68138, - 68137, 68144, 68096, 68165, 68164, 68166, 68167, 68179, 68178, 68183, - 68176, 68182, 68181, 68184, 68180, 68177, 68152, 68153, 68109, 68154, - 68111, 68110, 68099, 68101, 68097, 68102, 68098, 68108, 68159, 68168, - 129711, 101120, 101121, 101122, 101123, 101124, 101125, 101126, 101127, - 101128, 101129, 101130, 101131, 101132, 101133, 101134, 101135, 101136, - 101137, 101138, 101139, 101140, 101141, 101142, 101143, 101144, 101145, - 101146, 101147, 101148, 101149, 101150, 101151, 101152, 101153, 101154, - 101155, 101156, 101157, 101158, 101159, 101160, 101161, 101162, 101163, - 101164, 101165, 101166, 101167, 101168, 101169, 101170, 101171, 101172, - 101173, 101174, 101175, 101176, 101177, 101178, 101179, 101180, 101181, - 101182, 101183, 101184, 101185, 101186, 101187, 101188, 101189, 101190, - 101191, 101192, 101193, 101194, 101195, 101196, 101197, 101198, 101199, - 101200, 101201, 101202, 101203, 101204, 101205, 101206, 101207, 101208, - 101209, 101210, 101211, 101212, 101213, 101214, 101215, 101216, 101217, - 101218, 101219, 101220, 101221, 101222, 101223, 101224, 101225, 101226, - 101227, 101228, 101229, 101230, 101231, 101232, 101233, 101234, 101235, - 101236, 101237, 101238, 101239, 101240, 101241, 101242, 101243, 101244, - 101245, 101246, 101247, 101248, 101249, 101250, 101251, 101252, 101253, - 101254, 101255, 101256, 101257, 101258, 101259, 101260, 101261, 101262, - 101263, 101264, 101265, 101266, 101267, 101268, 101269, 101270, 101271, - 101272, 101273, 101274, 101275, 101276, 101277, 101278, 101279, 101280, - 101281, 101282, 101283, 101284, 101285, 101286, 101287, 101288, 101289, - 101290, 101291, 101292, 101293, 101294, 101295, 101296, 101297, 101298, - 101299, 101300, 101301, 101302, 101303, 101304, 101305, 101306, 101307, - 101308, 101309, 101310, 101311, 101312, 101313, 101314, 101315, 101316, - 101317, 101318, 101319, 101320, 101321, 101322, 101323, 101324, 101325, - 101326, 101327, 101328, 101329, 101330, 101331, 101332, 101333, 101334, - 101335, 101336, 101337, 101338, 101339, 101340, 101341, 101342, 101343, - 101344, 101345, 101346, 101347, 101348, 101349, 101350, 101351, 101352, - 101353, 101354, 101355, 101356, 101357, 101358, 101359, 101360, 101361, - 101362, 101363, 101364, 101365, 101366, 101367, 101368, 101369, 101370, - 101371, 101372, 101373, 101374, 101375, 101584, 101585, 101586, 101587, - 101588, 101589, 101376, 101377, 101378, 101379, 101380, 101381, 101382, - 101383, 101384, 101385, 101386, 101387, 101388, 101389, 101390, 101391, - 101392, 101393, 101394, 101395, 101396, 101397, 101398, 101399, 101400, - 101401, 101402, 101403, 101404, 101405, 101406, 101407, 101408, 101409, - 101410, 101411, 101412, 101413, 101414, 101415, 101416, 101417, 101418, - 101419, 101420, 101421, 101422, 101423, 101424, 101425, 101426, 101427, - 101428, 101429, 101430, 101431, 101432, 101433, 101434, 101435, 101436, - 101437, 101438, 101439, 101440, 101441, 101442, 101443, 101444, 101445, - 101446, 101447, 101448, 101449, 101450, 101451, 101452, 101453, 101454, - 101455, 101456, 101457, 101458, 101459, 101460, 101461, 101462, 101463, - 101464, 101465, 101466, 101467, 101468, 101469, 101470, 101471, 101472, - 101473, 101474, 101475, 101476, 101477, 101478, 101479, 101480, 101481, - 101482, 101483, 101484, 101485, 101486, 101487, 101488, 101489, 101490, - 101491, 101492, 101493, 101494, 101495, 101496, 101497, 101498, 101499, - 101500, 101501, 101502, 101503, 101504, 101505, 101506, 101507, 101508, - 101509, 101510, 101511, 101512, 101513, 101514, 101515, 101516, 101517, - 101518, 101519, 101520, 101521, 101522, 101523, 101524, 101525, 101526, - 101527, 101528, 101529, 101530, 101531, 101532, 101533, 101534, 101535, - 101536, 101537, 101538, 101539, 101540, 101541, 101542, 101543, 101544, - 101545, 101546, 101547, 101548, 101549, 101550, 101551, 101552, 101553, - 101554, 101555, 101556, 101557, 101558, 101559, 101560, 101561, 101562, - 101563, 101564, 101565, 101566, 101567, 101568, 101569, 101570, 101571, - 101572, 101573, 101574, 101575, 101576, 101577, 101578, 101579, 101580, - 101581, 101582, 101583, 101631, 94180, 983960, 983965, 983970, 983975, - 983962, 983964, 983961, 983963, 983957, 983959, 983956, 983958, 983977, - 983979, 983978, 983972, 983974, 983967, 983969, 983971, 983973, 983966, - 983968, 983989, 983983, 983985, 983986, 983987, 983980, 983982, 983984, - 983981, 983976, 983988, 6107, 6052, 6064, 6051, 6067, 6066, 6065, 6055, - 6057, 6058, 6056, 6053, 6054, 6063, 983994, 983991, 983992, 983993, 6061, - 6062, 6059, 6060, 6022, 6024, 6021, 6023, 6017, 6019, 6016, 6018, 6020, - 6030, 6025, 6035, 6037, 6039, 6038, 6046, 6045, 6047, 6032, 6034, 6027, - 6029, 6031, 6033, 6026, 6028, 6049, 6043, 6040, 6042, 6044, 6041, 6036, - 6048, 6050, 6108, 6109, 6095, 6096, 6099, 6091, 6101, 6104, 6102, 6098, - 6094, 6100, 6106, 6092, 6087, 6093, 6090, 6103, 6105, 6088, 6086, 6089, - 6097, 6652, 6636, 6655, 6639, 6653, 6637, 6654, 6638, 6651, 6635, 6650, - 6634, 6133, 6137, 6136, 6134, 6135, 6130, 6132, 6131, 6129, 6128, 6624, - 6648, 6632, 6649, 6633, 6647, 6631, 6646, 6630, 6645, 6629, 6642, 6626, - 6640, 6643, 6627, 6644, 6628, 6641, 6625, 6069, 6068, 6070, 983996, 6082, - 6083, 6085, 6071, 6080, 6072, 6078, 983995, 6084, 6073, 6079, 6074, - 983990, 6075, 6077, 6076, 6081, 6117, 6116, 6119, 6118, 6115, 6114, 6112, - 6121, 6113, 6120, 70204, 70201, 70200, 70208, 70185, 70178, 70179, 70177, - 70155, 70156, 70154, 70172, 70167, 70166, 70173, 70171, 70161, 70160, - 70144, 70145, 70149, 70151, 70165, 70164, 70170, 70169, 70187, 70183, - 70157, 70168, 70163, 70174, 70159, 70158, 70153, 70152, 70176, 70175, - 70186, 70180, 70207, 70182, 70184, 70181, 70148, 70146, 70150, 70147, - 70199, 70206, 70198, 70197, 70196, 70203, 70209, 70188, 70193, 70195, - 70189, 70190, 70192, 70194, 70191, 70202, 70205, 70357, 70358, 70356, - 70333, 70334, 70332, 70345, 70347, 70344, 70352, 70351, 70340, 70339, - 70338, 70320, 70321, 70327, 70329, 70346, 70361, 70343, 70342, 70350, - 70349, 70324, 70325, 70322, 70323, 70335, 70348, 70341, 70353, 70337, - 70336, 70331, 70330, 70355, 70354, 70364, 70365, 70366, 70362, 70359, - 70363, 70360, 70326, 70328, 70377, 70378, 70367, 70368, 70374, 70376, - 70371, 70372, 70369, 70370, 70373, 70375, 70389, 70388, 70391, 70390, - 70387, 70386, 70384, 70393, 70385, 70392, 93521, 93520, 93525, 93524, - 93519, 93518, 93523, 93522, 93512, 93517, 93526, 93530, 93529, 93514, - 93513, 93511, 93510, 93516, 93515, 93509, 93508, 93528, 93527, 93537, - 93536, 93538, 93534, 93531, 93533, 93535, 93532, 93507, 93505, 93549, - 93548, 93504, 93547, 93506, 93539, 93544, 93546, 93541, 93542, 93543, - 93540, 93545, 93551, 93550, 93557, 93556, 93559, 93558, 93555, 93554, - 93552, 93561, 93553, 93560, 128143, 128535, 128537, 128538, 128573, - 128139, 129373, 8365, 128088, 129665, 129486, 129698, 12927, 128040, - 11235, 129404, 127991, 129357, 128030, 129692, 3805, 3804, 983206, - 983207, 3743, 3741, 3807, 3806, 3714, 3716, 3713, 983209, 3747, 3749, - 3730, 3729, 3736, 3728, 3727, 3731, 3726, 3744, 3721, 3718, 3724, 3756, - 3740, 3742, 3739, 3752, 3753, 3754, 3722, 3734, 3735, 3733, 3755, 3758, - 3719, 3725, 3737, 3738, 3720, 3732, 3745, 983208, 3751, 3746, 3757, 3773, - 3772, 3770, 3785, 3786, 3787, 3784, 3760, 3762, 3780, 3763, 3779, 3761, - 3771, 3766, 3767, 3768, 3769, 3776, 3777, 3764, 3765, 3778, 3782, 3790, - 3759, 3797, 3796, 3799, 3798, 3795, 3794, 3792, 3801, 3793, 3800, 3788, - 3789, 128996, 129003, 128309, 128311, 128998, 128994, 129001, 68413, - 68415, 128992, 128310, 128999, 68412, 68414, 118324, 118319, 118322, - 118323, 118303, 118304, 118336, 118331, 118328, 118315, 118314, 118306, - 118316, 118318, 118334, 118335, 118333, 118327, 118339, 118341, 118342, - 118340, 118320, 118338, 118332, 118302, 118325, 118309, 118317, 118307, - 118313, 118326, 118329, 118312, 118330, 118352, 118348, 118351, 118350, - 118347, 118344, 118345, 118343, 118349, 118346, 118305, 118321, 118301, - 118299, 118298, 118310, 118311, 118308, 118300, 118337, 11004, 10201, - 10200, 10782, 128995, 129002, 128308, 128997, 128993, 129000, 9711, - 10923, 10925, 8382, 9790, 127772, 127767, 65, 258, 7858, 7856, 7854, - 7862, 7860, 550, 480, 7840, 512, 196, 478, 197, 506, 7680, 256, 983564, - 194, 7848, 7846, 7844, 7852, 7850, 461, 7842, 260, 983590, 983592, 192, - 193, 514, 195, 570, 198, 508, 482, 42946, 393, 11373, 42808, 42810, - 42802, 42804, 42806, 42812, 66, 386, 42902, 7686, 7684, 7682, 385, 579, - 42822, 42932, 67, 199, 7688, 264, 268, 262, 42948, 391, 42898, 266, 571, - 42960, 42796, 42798, 42862, 42931, 68, 498, 453, 42951, 272, 7696, 7698, - 270, 395, 7694, 7692, 7690, 394, 497, 452, 69, 552, 7708, 202, 983586, - 7874, 7872, 7870, 983584, 7878, 7876, 7704, 282, 278, 983598, 983600, - 7864, 516, 203, 7868, 7706, 274, 7700, 7702, 983570, 983572, 983574, - 7866, 280, 983594, 983596, 200, 201, 518, 276, 582, 439, 494, 440, 42786, - 42788, 42858, 208, 425, 330, 70, 401, 7710, 42904, 71, 290, 284, 486, - 500, 286, 7712, 42912, 403, 288, 484, 577, 42938, 42940, 42942, 404, - 983199, 72, 7722, 7720, 292, 542, 7718, 11367, 7716, 7714, 42922, 294, - 11381, 502, 42790, 73, 520, 7882, 304, 207, 7726, 206, 463, 298, 983566, - 296, 7724, 7880, 302, 983604, 983606, 204, 205, 522, 300, 407, 42873, - 42875, 42877, 42882, 42884, 42886, 406, 42860, 74, 308, 42930, 983608, - 584, 75, 310, 488, 42818, 11369, 7730, 42816, 42820, 7728, 7732, 42914, - 408, 76, 42925, 573, 11360, 7734, 7736, 11362, 319, 456, 321, 315, 7740, - 317, 42824, 313, 7738, 983610, 42970, 42972, 455, 77, 7742, 7746, 7744, - 983612, 11374, 7930, 7932, 42966, 78, 325, 7754, 327, 459, 544, 7752, - 413, 504, 323, 42896, 7750, 7748, 42916, 209, 458, 79, 42826, 42828, 332, - 7760, 7762, 415, 212, 7892, 7890, 7888, 7896, 7894, 465, 214, 554, 558, - 560, 7884, 524, 336, 490, 492, 216, 510, 213, 7758, 7756, 556, 983576, - 983578, 983580, 416, 7902, 7900, 7898, 7906, 7904, 7886, 210, 211, 526, - 334, 42944, 400, 390, 42934, 418, 42830, 546, 80, 42834, 11363, 42832, - 42836, 7764, 420, 7766, 81, 42840, 42838, 82, 342, 344, 7770, 7772, 7768, - 528, 11364, 983614, 340, 7774, 530, 42918, 588, 42842, 42997, 42923, - 42814, 398, 42844, 42955, 83, 352, 7782, 350, 536, 348, 346, 7780, 7778, - 7784, 7776, 42956, 42953, 11390, 983582, 42920, 42949, 586, 42926, 42891, - 7838, 42968, 42924, 399, 84, 354, 7792, 538, 356, 574, 7788, 7786, 7790, - 430, 428, 358, 42878, 11375, 11376, 42893, 42928, 42880, 412, 42929, 581, - 222, 42852, 42854, 388, 423, 444, 42794, 42792, 85, 219, 7798, 467, 220, - 473, 475, 471, 469, 7794, 532, 368, 7908, 431, 7916, 7914, 7912, 7920, - 7918, 7910, 362, 7802, 983568, 983620, 983622, 370, 983616, 983618, 360, - 7800, 7796, 217, 218, 534, 364, 366, 42936, 580, 433, 86, 42846, 7806, - 7804, 434, 42850, 42906, 42908, 42910, 42856, 42848, 87, 372, 7812, 7816, - 7814, 7808, 7810, 11378, 503, 88, 7820, 7818, 89, 374, 376, 7924, 7822, - 7922, 435, 7926, 7934, 221, 562, 7928, 590, 540, 90, 7824, 381, 377, - 11371, 7826, 379, 7828, 11391, 437, 42950, 548, 306, 338, 10013, 43007, - 43005, 43006, 43003, 43004, 42999, 450, 7461, 684, 664, 685, 662, 122638, - 446, 426, 674, 451, 122634, 7431, 7430, 7459, 618, 641, 671, 122628, + 8290, 8292, 8291, 128229, 118471, 118465, 127982, 129311, 127875, 127983, + 127971, 12292, 9979, 127886, 128304, 128122, 128121, 43453, 43454, 43455, + 43457, 43421, 43422, 43426, 43427, 43398, 43397, 43399, 43407, 43408, + 43409, 43412, 43402, 43403, 43418, 43416, 43428, 43423, 43431, 43432, + 43413, 43414, 43410, 43411, 43429, 43430, 43401, 43435, 43436, 43441, + 43439, 43440, 43424, 43425, 43419, 43420, 43415, 43417, 43396, 43405, + 43442, 43437, 43433, 43438, 43434, 43404, 43406, 43400, 43458, 43466, + 43467, 43459, 43465, 43461, 43464, 43468, 43463, 43486, 43462, 43487, + 43460, 43471, 43456, 43469, 43393, 43443, 43395, 43394, 43392, 43448, + 43449, 43444, 43450, 43445, 43446, 43447, 43452, 43451, 43477, 43476, + 43479, 43478, 43475, 43474, 43472, 43481, 43473, 43480, 129753, 129724, + 128086, 128377, 10781, 129337, 9795, 9909, 129513, 69786, 69787, 69785, + 69793, 69792, 69763, 69764, 69770, 69772, 69784, 69783, 69791, 69790, + 69767, 69768, 69765, 69766, 69777, 69789, 69782, 69794, 69804, 69805, + 69806, 69798, 69797, 69779, 69778, 69776, 69775, 69781, 69780, 69774, + 69773, 69796, 69795, 69788, 69801, 69807, 69802, 69799, 69803, 69800, + 69769, 69771, 69760, 69818, 69761, 69817, 69762, 69822, 69823, 69825, + 69824, 69826, 69808, 69814, 69816, 69811, 69812, 69809, 69810, 69813, + 69815, 69821, 69837, 69819, 69820, 12142, 12164, 12060, 12157, 12100, + 12149, 12184, 12191, 12227, 12068, 12174, 12234, 12205, 12134, 12168, + 12219, 12189, 12088, 12090, 12096, 12160, 12182, 12224, 12190, 12147, + 12114, 12118, 12058, 12176, 12075, 12112, 12045, 12170, 12124, 12070, + 12194, 12109, 12229, 12196, 12139, 12056, 12099, 12034, 12084, 12136, + 12120, 12044, 12111, 12094, 12125, 12243, 12238, 12082, 12159, 12063, + 12215, 12062, 12042, 12241, 12067, 12235, 12043, 12140, 12119, 12207, + 12123, 12133, 12222, 12117, 12226, 12245, 12214, 12217, 12236, 12155, + 12188, 12113, 12065, 12198, 12066, 12146, 12171, 12225, 12200, 12121, + 12093, 12095, 12221, 12092, 12216, 12231, 12054, 12218, 12179, 12037, + 12173, 12072, 12046, 12127, 12152, 12049, 12074, 12107, 12208, 12212, + 12041, 12210, 12131, 12033, 12039, 12199, 12085, 12128, 12161, 12162, + 12233, 12165, 12192, 12077, 12201, 12061, 12105, 12040, 12240, 12102, + 12153, 12032, 12080, 12167, 12048, 12156, 12059, 12126, 12158, 12050, + 12183, 12204, 12097, 12239, 12053, 12078, 12150, 12071, 12187, 12186, + 12223, 12228, 12104, 12098, 12064, 12036, 12057, 12163, 12178, 12185, + 12154, 12203, 12083, 12087, 12135, 12151, 12202, 12035, 12122, 12141, + 12180, 12144, 12076, 12052, 12115, 12091, 12108, 12169, 12143, 12148, + 12130, 12089, 12211, 12073, 12101, 12138, 12103, 12209, 12047, 12220, + 12172, 12129, 12166, 12242, 12237, 12145, 12106, 12081, 12244, 12038, + 12086, 12055, 12181, 12197, 12193, 12175, 12116, 12110, 12177, 12137, + 12230, 12213, 12195, 12069, 12079, 12206, 12051, 12232, 12132, 129432, + 3240, 3293, 3225, 3235, 3230, 3205, 3206, 3216, 3220, 3234, 3233, 3239, + 3238, 983205, 3251, 3250, 3249, 3248, 3232, 3231, 3237, 3236, 3211, 3296, + 3212, 3297, 3253, 3209, 3210, 3218, 3219, 3207, 3208, 3254, 3255, 3256, + 3245, 3244, 3227, 3226, 3224, 3223, 3229, 3228, 3222, 3221, 3243, 3242, + 3214, 3215, 3294, 3257, 3246, 3247, 3285, 3315, 3201, 3200, 3204, 3260, + 3261, 3202, 3313, 3314, 3277, 3203, 3292, 3286, 3262, 3272, 3276, 3265, + 3266, 3267, 3268, 3298, 3299, 3274, 3275, 3263, 3264, 3270, 3271, 3307, + 3306, 3309, 3308, 3305, 3304, 3302, 3311, 3303, 3310, 12450, 984009, + 984008, 984007, 984010, 110881, 110880, 110882, 110592, 12499, 984002, + 984005, 984003, 984006, 984004, 12496, 12505, 12508, 12502, 12511, + 110583, 110584, 110585, 110586, 110587, 110589, 110590, 110576, 110577, + 110578, 110579, 110581, 110582, 12510, 12513, 12514, 12512, 12531, 12490, + 12493, 12491, 12494, 12492, 12789, 12792, 12790, 12793, 12791, 12795, + 12798, 12796, 12799, 12797, 12533, 12534, 110933, 12784, 12787, 12483, + 12526, 110949, 110948, 110950, 12515, 12519, 12517, 110951, 12788, 12785, + 12786, 12794, 12449, 12455, 12451, 12457, 12453, 12469, 12475, 12471, + 12477, 12473, 12480, 12487, 12482, 12489, 12485, 12460, 12466, 12462, + 12468, 12464, 12495, 12504, 12498, 12507, 12501, 12459, 12465, 12461, + 12467, 12463, 12497, 12506, 12500, 12509, 12503, 12521, 12524, 12522, + 12525, 12523, 12479, 12486, 12481, 12488, 12484, 12535, 12537, 12536, + 12538, 12532, 12470, 12476, 12472, 12478, 12474, 12527, 12529, 12528, + 12530, 12516, 12520, 12518, 12456, 12452, 12458, 12454, 12542, 12543, + 12541, 12539, 12448, 12540, 12444, 12443, 73476, 73477, 73487, 73523, + 73498, 73497, 73503, 73502, 73508, 73507, 73501, 73500, 73506, 73505, + 73480, 73481, 73482, 73483, 73484, 73485, 73478, 73479, 73494, 73504, + 73499, 73509, 73519, 73520, 73521, 73513, 73512, 73496, 73495, 73493, + 73492, 73491, 73490, 73511, 73510, 73522, 73517, 73514, 73516, 73518, + 73515, 73486, 73488, 73551, 73548, 73546, 73545, 73549, 73543, 73541, + 73544, 73550, 73542, 73547, 73537, 73472, 73562, 73474, 73475, 73473, + 73525, 73524, 73535, 73530, 73534, 73536, 73528, 73529, 73526, 73527, + 73540, 73539, 73557, 73556, 73559, 73558, 73555, 73554, 73552, 73561, + 73553, 73560, 73538, 43299, 43301, 43283, 43295, 43277, 43281, 43284, + 43275, 43274, 43286, 43285, 43279, 43278, 43294, 43282, 43289, 43297, + 43288, 43276, 43292, 43287, 43290, 43296, 43293, 43291, 43280, 43298, + 43300, 43310, 43311, 43308, 43309, 43307, 43303, 43305, 43304, 43302, + 43306, 43269, 43268, 43271, 43270, 43267, 43266, 43264, 43273, 43265, + 43272, 119496, 119506, 119499, 119503, 119493, 119492, 119502, 119497, + 119507, 119495, 119505, 119494, 119504, 119501, 119491, 119500, 119490, + 119498, 119488, 119489, 128331, 8490, 128273, 9000, 128422, 983552, + 983553, 983559, 983558, 983561, 983560, 983557, 983556, 983554, 983563, + 983555, 983562, 128287, 118449, 68163, 68162, 68161, 68160, 68113, 68146, + 68112, 68147, 68148, 68123, 68122, 68128, 68127, 68126, 68121, 68131, + 68125, 68124, 68130, 68129, 68141, 68142, 68143, 68135, 68134, 68118, + 68117, 68115, 68114, 68133, 68132, 68149, 68140, 68145, 68119, 68139, + 68136, 68138, 68137, 68144, 68096, 68165, 68164, 68166, 68167, 68179, + 68178, 68183, 68176, 68182, 68181, 68184, 68180, 68177, 68152, 68153, + 68109, 68154, 68111, 68110, 68099, 68101, 68097, 68102, 68098, 68108, + 68159, 68168, 129711, 101120, 101121, 101122, 101123, 101124, 101125, + 101126, 101127, 101128, 101129, 101130, 101131, 101132, 101133, 101134, + 101135, 101136, 101137, 101138, 101139, 101140, 101141, 101142, 101143, + 101144, 101145, 101146, 101147, 101148, 101149, 101150, 101151, 101152, + 101153, 101154, 101155, 101156, 101157, 101158, 101159, 101160, 101161, + 101162, 101163, 101164, 101165, 101166, 101167, 101168, 101169, 101170, + 101171, 101172, 101173, 101174, 101175, 101176, 101177, 101178, 101179, + 101180, 101181, 101182, 101183, 101184, 101185, 101186, 101187, 101188, + 101189, 101190, 101191, 101192, 101193, 101194, 101195, 101196, 101197, + 101198, 101199, 101200, 101201, 101202, 101203, 101204, 101205, 101206, + 101207, 101208, 101209, 101210, 101211, 101212, 101213, 101214, 101215, + 101216, 101217, 101218, 101219, 101220, 101221, 101222, 101223, 101224, + 101225, 101226, 101227, 101228, 101229, 101230, 101231, 101232, 101233, + 101234, 101235, 101236, 101237, 101238, 101239, 101240, 101241, 101242, + 101243, 101244, 101245, 101246, 101247, 101248, 101249, 101250, 101251, + 101252, 101253, 101254, 101255, 101256, 101257, 101258, 101259, 101260, + 101261, 101262, 101263, 101264, 101265, 101266, 101267, 101268, 101269, + 101270, 101271, 101272, 101273, 101274, 101275, 101276, 101277, 101278, + 101279, 101280, 101281, 101282, 101283, 101284, 101285, 101286, 101287, + 101288, 101289, 101290, 101291, 101292, 101293, 101294, 101295, 101296, + 101297, 101298, 101299, 101300, 101301, 101302, 101303, 101304, 101305, + 101306, 101307, 101308, 101309, 101310, 101311, 101312, 101313, 101314, + 101315, 101316, 101317, 101318, 101319, 101320, 101321, 101322, 101323, + 101324, 101325, 101326, 101327, 101328, 101329, 101330, 101331, 101332, + 101333, 101334, 101335, 101336, 101337, 101338, 101339, 101340, 101341, + 101342, 101343, 101344, 101345, 101346, 101347, 101348, 101349, 101350, + 101351, 101352, 101353, 101354, 101355, 101356, 101357, 101358, 101359, + 101360, 101361, 101362, 101363, 101364, 101365, 101366, 101367, 101368, + 101369, 101370, 101371, 101372, 101373, 101374, 101375, 101584, 101585, + 101586, 101587, 101588, 101589, 101376, 101377, 101378, 101379, 101380, + 101381, 101382, 101383, 101384, 101385, 101386, 101387, 101388, 101389, + 101390, 101391, 101392, 101393, 101394, 101395, 101396, 101397, 101398, + 101399, 101400, 101401, 101402, 101403, 101404, 101405, 101406, 101407, + 101408, 101409, 101410, 101411, 101412, 101413, 101414, 101415, 101416, + 101417, 101418, 101419, 101420, 101421, 101422, 101423, 101424, 101425, + 101426, 101427, 101428, 101429, 101430, 101431, 101432, 101433, 101434, + 101435, 101436, 101437, 101438, 101439, 101440, 101441, 101442, 101443, + 101444, 101445, 101446, 101447, 101448, 101449, 101450, 101451, 101452, + 101453, 101454, 101455, 101456, 101457, 101458, 101459, 101460, 101461, + 101462, 101463, 101464, 101465, 101466, 101467, 101468, 101469, 101470, + 101471, 101472, 101473, 101474, 101475, 101476, 101477, 101478, 101479, + 101480, 101481, 101482, 101483, 101484, 101485, 101486, 101487, 101488, + 101489, 101490, 101491, 101492, 101493, 101494, 101495, 101496, 101497, + 101498, 101499, 101500, 101501, 101502, 101503, 101504, 101505, 101506, + 101507, 101508, 101509, 101510, 101511, 101512, 101513, 101514, 101515, + 101516, 101517, 101518, 101519, 101520, 101521, 101522, 101523, 101524, + 101525, 101526, 101527, 101528, 101529, 101530, 101531, 101532, 101533, + 101534, 101535, 101536, 101537, 101538, 101539, 101540, 101541, 101542, + 101543, 101544, 101545, 101546, 101547, 101548, 101549, 101550, 101551, + 101552, 101553, 101554, 101555, 101556, 101557, 101558, 101559, 101560, + 101561, 101562, 101563, 101564, 101565, 101566, 101567, 101568, 101569, + 101570, 101571, 101572, 101573, 101574, 101575, 101576, 101577, 101578, + 101579, 101580, 101581, 101582, 101583, 101631, 94180, 983960, 983965, + 983970, 983975, 983962, 983964, 983961, 983963, 983957, 983959, 983956, + 983958, 983977, 983979, 983978, 983972, 983974, 983967, 983969, 983971, + 983973, 983966, 983968, 983989, 983983, 983985, 983986, 983987, 983980, + 983982, 983984, 983981, 983976, 983988, 6107, 6052, 6064, 6051, 6067, + 6066, 6065, 6055, 6057, 6058, 6056, 6053, 6054, 6063, 983994, 983991, + 983992, 983993, 6061, 6062, 6059, 6060, 6022, 6024, 6021, 6023, 6017, + 6019, 6016, 6018, 6020, 6030, 6025, 6035, 6037, 6039, 6038, 6046, 6045, + 6047, 6032, 6034, 6027, 6029, 6031, 6033, 6026, 6028, 6049, 6043, 6040, + 6042, 6044, 6041, 6036, 6048, 6050, 6108, 6109, 6095, 6096, 6099, 6091, + 6101, 6104, 6102, 6098, 6094, 6100, 6106, 6092, 6087, 6090, 6093, 6103, + 6105, 6088, 6086, 6089, 6097, 6652, 6636, 6655, 6639, 6653, 6637, 6654, + 6638, 6651, 6635, 6650, 6634, 6133, 6137, 6136, 6134, 6135, 6130, 6132, + 6131, 6129, 6128, 6624, 6648, 6632, 6649, 6633, 6647, 6631, 6646, 6630, + 6645, 6629, 6642, 6626, 6640, 6643, 6627, 6644, 6628, 6641, 6625, 6069, + 6068, 6070, 983996, 6082, 6083, 6085, 6071, 6080, 6072, 6078, 983995, + 6084, 6073, 6079, 6074, 983990, 6075, 6077, 6076, 6081, 6117, 6116, 6119, + 6118, 6115, 6114, 6112, 6121, 6113, 6120, 70204, 70201, 70200, 70208, + 70185, 70178, 70179, 70177, 70155, 70156, 70154, 70172, 70167, 70166, + 70173, 70171, 70161, 70160, 70144, 70145, 70149, 70151, 70165, 70164, + 70170, 70169, 70187, 70183, 70157, 70168, 70163, 70174, 70159, 70158, + 70153, 70152, 70176, 70175, 70186, 70180, 70207, 70182, 70184, 70181, + 70148, 70146, 70150, 70147, 70199, 70206, 70198, 70197, 70196, 70203, + 70209, 70188, 70193, 70195, 70189, 70190, 70192, 70194, 70191, 70202, + 70205, 70357, 70358, 70356, 70333, 70334, 70332, 70345, 70347, 70344, + 70352, 70351, 70340, 70339, 70338, 70320, 70321, 70327, 70329, 70346, + 70361, 70343, 70342, 70350, 70349, 70324, 70325, 70322, 70323, 70335, + 70348, 70341, 70353, 70337, 70336, 70331, 70330, 70355, 70354, 70364, + 70365, 70366, 70362, 70359, 70363, 70360, 70326, 70328, 70377, 70378, + 70367, 70368, 70374, 70376, 70371, 70372, 70369, 70370, 70373, 70375, + 70389, 70388, 70391, 70390, 70387, 70386, 70384, 70393, 70385, 70392, + 93521, 93520, 93525, 93524, 93519, 93518, 93523, 93522, 93512, 93517, + 93526, 93530, 93529, 93514, 93513, 93511, 93510, 93516, 93515, 93509, + 93508, 93528, 93527, 93537, 93536, 93538, 93534, 93531, 93533, 93535, + 93532, 93507, 93505, 93549, 93548, 93504, 93547, 93506, 93539, 93544, + 93546, 93541, 93542, 93543, 93540, 93545, 93551, 93550, 93557, 93556, + 93559, 93558, 93555, 93554, 93552, 93561, 93553, 93560, 128143, 128535, + 128537, 128538, 128573, 128139, 129373, 8365, 128088, 129665, 129486, + 129698, 12927, 128040, 11235, 129404, 127991, 129357, 128030, 129692, + 128728, 917505, 3805, 3804, 983206, 983207, 3743, 3741, 3807, 3806, 3714, + 3716, 3713, 983209, 3747, 3749, 3730, 3729, 3736, 3728, 3727, 3731, 3726, + 3744, 3721, 3718, 3724, 3756, 3740, 3742, 3739, 3752, 3753, 3754, 3722, + 3734, 3735, 3733, 3755, 3758, 3719, 3725, 3737, 3738, 3720, 3732, 3745, + 983208, 3751, 3746, 3757, 3773, 3772, 3770, 3785, 3786, 3787, 3784, 3760, + 3762, 3780, 3763, 3779, 3761, 3771, 3766, 3767, 3768, 3769, 3776, 3777, + 3764, 3765, 3778, 3782, 3790, 3759, 3797, 3796, 3799, 3798, 3795, 3794, + 3792, 3801, 3793, 3800, 3788, 3789, 128996, 129003, 128309, 128311, + 128998, 128994, 129001, 68413, 68415, 128992, 128310, 128999, 68412, + 68414, 118324, 118319, 118322, 118323, 118303, 118304, 118336, 118331, + 118328, 118315, 118314, 118306, 118316, 118318, 118334, 118335, 118333, + 118327, 118339, 118341, 118342, 118340, 118320, 118338, 118332, 118302, + 118325, 118309, 118317, 118307, 118313, 118326, 118329, 118312, 118330, + 118352, 118348, 118351, 118350, 118347, 118344, 118345, 118343, 118349, + 118346, 118305, 118321, 118301, 118299, 118298, 118310, 118311, 118308, + 118300, 118337, 11004, 10201, 10200, 10782, 128995, 129002, 128308, + 128997, 128993, 129000, 9711, 10923, 10925, 8382, 9790, 127772, 127767, + 65, 258, 7858, 7856, 7854, 7862, 7860, 550, 480, 7840, 512, 196, 478, + 197, 506, 7680, 256, 983564, 194, 7848, 7846, 7844, 7852, 7850, 461, + 7842, 260, 983590, 983592, 192, 193, 514, 195, 570, 198, 508, 482, 42946, + 393, 11373, 42808, 42810, 42802, 42804, 42806, 42812, 66, 386, 42902, + 7686, 7684, 7682, 385, 579, 42822, 42932, 67, 199, 7688, 264, 268, 262, + 42948, 391, 42898, 266, 571, 42960, 42796, 42798, 42862, 42931, 68, 498, + 453, 42951, 272, 7696, 7698, 270, 395, 7694, 7692, 7690, 394, 497, 452, + 42964, 42962, 69, 552, 7708, 202, 983586, 7874, 7872, 7870, 983584, 7878, + 7876, 7704, 282, 278, 983598, 983600, 7864, 516, 203, 7868, 7706, 274, + 7700, 7702, 983570, 983572, 983574, 7866, 280, 983594, 983596, 200, 201, + 518, 276, 582, 439, 494, 440, 42786, 42788, 42858, 208, 425, 330, 70, + 401, 7710, 42904, 71, 290, 284, 486, 500, 286, 7712, 42912, 403, 288, + 484, 577, 42938, 42940, 42942, 404, 983199, 72, 7722, 7720, 292, 542, + 7718, 11367, 7716, 7714, 42922, 294, 11381, 502, 42790, 73, 520, 7882, + 304, 207, 7726, 206, 463, 298, 983566, 296, 7724, 7880, 302, 983604, + 983606, 204, 205, 522, 300, 407, 42873, 42875, 42877, 42882, 42884, + 42886, 406, 42860, 74, 308, 42930, 983608, 584, 75, 310, 488, 42818, + 11369, 7730, 42816, 42820, 7728, 7732, 42914, 408, 76, 42925, 573, 11360, + 7734, 7736, 11362, 319, 456, 321, 315, 7740, 317, 42824, 313, 7738, + 983610, 42970, 42972, 455, 77, 7742, 7746, 7744, 983612, 11374, 7930, + 7932, 42966, 78, 325, 7754, 327, 459, 544, 7752, 413, 504, 323, 42896, + 7750, 7748, 42916, 209, 458, 79, 42826, 42828, 332, 7760, 7762, 415, 212, + 7892, 7890, 7888, 7896, 7894, 465, 214, 554, 558, 560, 7884, 524, 336, + 490, 492, 216, 510, 213, 7758, 7756, 556, 983576, 983578, 983580, 416, + 7902, 7900, 7898, 7906, 7904, 7886, 210, 211, 526, 334, 42944, 400, 390, + 42934, 418, 42830, 546, 80, 42834, 11363, 42832, 42836, 7764, 420, 7766, + 42958, 81, 42840, 42838, 82, 342, 344, 7770, 7772, 7768, 528, 983614, + 11364, 340, 7774, 530, 42918, 588, 42842, 42997, 42923, 42814, 398, + 42844, 42955, 83, 352, 7782, 350, 536, 348, 346, 7780, 7778, 7784, 7776, + 42956, 42953, 11390, 983582, 42920, 42949, 586, 42926, 42891, 7838, + 42968, 42924, 399, 84, 354, 7792, 538, 356, 574, 7788, 7786, 7790, 430, + 428, 358, 42878, 11375, 11376, 42893, 42928, 42880, 412, 42929, 581, 222, + 42852, 42854, 388, 444, 423, 42794, 42792, 85, 219, 7798, 467, 220, 473, + 475, 471, 469, 7794, 532, 368, 7908, 431, 7916, 7914, 7912, 7920, 7918, + 7910, 362, 7802, 983568, 983620, 983622, 370, 983616, 983618, 360, 7800, + 7796, 217, 218, 534, 364, 366, 42936, 580, 433, 86, 42846, 7806, 7804, + 434, 42850, 42906, 42908, 42910, 42856, 42848, 87, 372, 7812, 7816, 7814, + 7808, 7810, 11378, 503, 88, 7820, 7818, 89, 374, 376, 7924, 7822, 7922, + 435, 7926, 7934, 221, 562, 7928, 590, 540, 90, 7824, 381, 377, 11371, + 7826, 379, 7828, 11391, 437, 42950, 548, 306, 338, 10013, 43007, 43005, + 43006, 43003, 43004, 42999, 450, 7461, 684, 664, 685, 662, 122638, 446, + 661, 426, 674, 451, 122634, 7431, 7430, 7459, 618, 641, 671, 122628, 7436, 7439, 7440, 630, 7445, 640, 7438, 7449, 43846, 42870, 7451, 11387, 122626, 122640, 43002, 7450, 665, 7427, 610, 667, 7424, 7425, 7428, 7429, 42800, 668, 7434, 7435, 7437, 628, 7448, 42927, 42801, 7452, 7456, 7457, - 655, 7458, 663, 122639, 42895, 443, 447, 448, 449, 660, 673, 661, 7460, - 422, 7547, 7550, 97, 259, 7859, 7857, 7855, 7863, 7861, 551, 481, 7841, - 513, 228, 479, 229, 507, 7681, 7834, 7567, 257, 983565, 226, 7849, 7847, - 7845, 7853, 7851, 462, 7843, 261, 983591, 983593, 224, 225, 515, 227, - 11365, 43825, 230, 983624, 509, 483, 42947, 593, 7568, 42809, 42811, - 42803, 42805, 42807, 42813, 98, 387, 42903, 7687, 7532, 7552, 7685, 7683, - 595, 384, 43824, 43827, 629, 43853, 43837, 43838, 43826, 42823, 7447, - 42933, 99, 231, 7689, 265, 597, 269, 263, 42900, 122653, 392, 42899, 267, - 572, 43859, 43860, 43861, 42961, 666, 631, 606, 42797, 42799, 42863, 100, + 655, 7458, 663, 122639, 42895, 443, 447, 448, 449, 660, 673, 7460, 422, + 7547, 7550, 97, 259, 7859, 7857, 7855, 7863, 7861, 551, 481, 7841, 513, + 228, 479, 229, 507, 7681, 7834, 7567, 257, 983565, 226, 7849, 7847, 7845, + 7853, 7851, 462, 7843, 261, 983591, 983593, 224, 225, 515, 227, 11365, + 43825, 230, 983624, 509, 483, 42947, 593, 7568, 42809, 42811, 42803, + 42805, 42807, 42813, 98, 387, 42903, 7687, 7532, 7552, 7685, 7683, 595, + 384, 43824, 43827, 629, 43853, 43837, 43838, 43826, 42823, 7447, 42933, + 99, 231, 7689, 265, 597, 269, 263, 42900, 122653, 392, 42899, 267, 572, + 43859, 43860, 43861, 42961, 666, 631, 606, 42797, 42799, 42863, 100, 42952, 273, 396, 598, 7697, 7699, 545, 271, 122661, 7533, 7695, 599, 7569, 7553, 7693, 7691, 676, 122642, 122649, 7839, 567, 607, 644, 305, 42965, 43848, 43850, 42963, 499, 454, 675, 677, 43878, 568, 42865, 101, @@ -11539,41 +11661,41 @@ static const unsigned int dawg_pos_to_codepoint[] = { 7757, 557, 983577, 983579, 983581, 417, 7903, 7901, 7899, 7907, 7905, 7887, 242, 243, 527, 335, 122651, 42945, 596, 983625, 983626, 7575, 43839, 43874, 603, 7571, 42935, 419, 42831, 547, 112, 42835, 7549, 42833, - 42837, 7765, 7537, 7560, 421, 7767, 632, 113, 42841, 672, 587, 42839, - 569, 114, 343, 43849, 345, 7771, 7773, 7769, 529, 638, 7539, 122646, - 7775, 636, 637, 983615, 122664, 7538, 341, 531, 7561, 42919, 589, 43847, - 42843, 42998, 604, 7572, 605, 639, 122625, 600, 122631, 8580, 42815, - 122627, 42869, 42845, 612, 115, 347, 7781, 353, 7783, 351, 537, 349, - 122654, 7779, 7785, 7777, 42957, 42954, 575, 983583, 122665, 7540, 7562, - 42921, 642, 42892, 43872, 601, 983629, 983630, 7573, 602, 43851, 43852, - 609, 43830, 223, 7441, 7442, 7443, 7455, 7454, 7453, 42969, 645, 43845, - 116, 355, 7793, 539, 566, 357, 11366, 7831, 7789, 7787, 122666, 7541, - 7791, 427, 429, 122633, 648, 359, 679, 122647, 122652, 7546, 254, 42853, - 42855, 389, 424, 445, 7446, 42795, 397, 613, 686, 687, 7433, 42879, 7444, - 43842, 43841, 43843, 43844, 7432, 633, 43880, 122645, 634, 122632, 11385, - 635, 647, 122637, 652, 983627, 983628, 592, 594, 7426, 623, 624, 654, - 122630, 43857, 477, 7543, 670, 42881, 653, 42871, 680, 678, 43879, 11383, - 42793, 117, 649, 43855, 251, 7799, 468, 252, 474, 476, 472, 470, 7795, - 533, 369, 7909, 432, 7917, 7915, 7913, 7921, 7919, 7911, 363, 7803, - 983569, 983621, 983623, 371, 983617, 983619, 7577, 367, 361, 7801, 7797, - 249, 43854, 42937, 250, 535, 365, 43858, 650, 7551, 7531, 43856, 42872, - 43875, 118, 42847, 7807, 7564, 11380, 11377, 7805, 651, 42851, 42907, - 42909, 42911, 42857, 42849, 119, 373, 7813, 7817, 7815, 7809, 7811, 7832, - 11379, 120, 7821, 7819, 43863, 43864, 43865, 43862, 7565, 121, 375, 255, - 7925, 7823, 7923, 436, 7927, 7935, 43866, 591, 253, 563, 7929, 7833, 541, - 122, 378, 7825, 657, 382, 11372, 7827, 380, 7829, 576, 438, 7542, 7566, - 656, 549, 64256, 64259, 64260, 64257, 64258, 307, 64261, 64262, 339, - 8347, 8340, 8336, 8337, 8341, 7522, 11388, 8342, 8343, 8344, 8345, 8338, - 8346, 7523, 8348, 7524, 7525, 8339, 917505, 129726, 127811, 129388, - 129897, 129916, 129947, 10203, 10202, 129899, 129917, 117902, 128494, - 12296, 10641, 10643, 11058, 11056, 10576, 10571, 10570, 10574, 12304, - 10647, 123, 9128, 9129, 9127, 12300, 8968, 9948, 10714, 12298, 8220, - 11816, 11780, 129287, 129284, 129285, 129283, 129286, 9686, 11240, 9612, - 129977, 117924, 118288, 129970, 118285, 118283, 118435, 118440, 129940, - 129932, 128379, 128709, 11804, 10204, 9614, 9615, 129999, 10197, 8596, - 8700, 8697, 8622, 10568, 8660, 10500, 8654, 8621, 11012, 8703, 11020, - 129112, 11108, 11788, 10181, 8907, 9609, 8216, 11814, 128488, 91, 9123, - 9121, 10639, 10637, 8261, 10635, 11863, 11861, 9122, 11778, 10703, + 42837, 7765, 7537, 7560, 421, 7767, 42959, 632, 113, 42841, 672, 587, + 42839, 569, 114, 343, 43849, 345, 7771, 7773, 7769, 529, 638, 7539, + 122646, 7775, 636, 983615, 637, 122664, 7538, 341, 531, 7561, 42919, 589, + 43847, 42843, 42998, 604, 7572, 605, 639, 122625, 600, 122631, 8580, + 42815, 122627, 42869, 42845, 612, 115, 347, 7781, 353, 7783, 351, 537, + 349, 122654, 7779, 7785, 7777, 42957, 42954, 575, 983583, 122665, 7540, + 7562, 42921, 642, 42892, 43872, 601, 983629, 983630, 7573, 602, 43851, + 43852, 609, 43830, 223, 7441, 7442, 7443, 7455, 7454, 7453, 42969, 645, + 43845, 116, 355, 7793, 539, 566, 357, 11366, 7831, 7789, 7787, 122666, + 7541, 7791, 427, 429, 122633, 648, 359, 679, 122647, 122652, 7546, 254, + 42853, 42855, 389, 445, 424, 7446, 42795, 397, 613, 686, 687, 7433, + 42879, 7444, 43842, 43841, 43843, 43844, 7432, 633, 43880, 122645, 634, + 122632, 11385, 635, 647, 122637, 652, 983627, 983628, 592, 594, 7426, + 623, 624, 654, 122630, 43857, 477, 7543, 670, 42881, 653, 42871, 680, + 678, 43879, 11383, 42793, 117, 649, 43855, 251, 7799, 468, 252, 474, 476, + 472, 470, 7795, 533, 369, 7909, 432, 7917, 7915, 7913, 7921, 7919, 7911, + 363, 7803, 983569, 983621, 983623, 371, 983617, 983619, 7577, 367, 361, + 7801, 7797, 249, 43854, 42937, 250, 535, 365, 43858, 650, 7551, 7531, + 43856, 42872, 43875, 118, 42847, 7807, 7564, 11380, 11377, 7805, 651, + 42851, 42907, 42909, 42911, 42857, 42849, 119, 373, 7813, 7817, 7815, + 7809, 7811, 7832, 11379, 120, 7821, 7819, 43863, 43864, 43865, 43862, + 7565, 121, 375, 255, 7925, 7823, 7923, 436, 7927, 7935, 43866, 591, 253, + 563, 7929, 7833, 541, 122, 378, 7825, 657, 382, 11372, 7827, 380, 7829, + 576, 438, 7542, 7566, 656, 549, 64256, 64259, 64260, 64257, 64258, 307, + 64261, 64262, 339, 8347, 8340, 8336, 8337, 8341, 7522, 11388, 8342, 8343, + 8344, 8345, 8338, 8346, 7523, 8348, 7524, 7525, 8339, 129726, 127811, + 129388, 129897, 129916, 129947, 10203, 10202, 129899, 129917, 117902, + 128494, 12296, 10641, 10643, 11058, 11056, 10576, 10571, 10570, 10574, + 12304, 10647, 123, 9128, 9129, 9127, 12300, 8968, 9948, 10714, 12298, + 8220, 11816, 11780, 129287, 129284, 129285, 129283, 129286, 9686, 11240, + 9612, 129977, 117924, 118288, 129970, 118285, 118283, 118435, 118440, + 129940, 129932, 128379, 128709, 11804, 10204, 9614, 9615, 129999, 10197, + 8596, 8700, 8697, 8622, 10568, 8660, 10500, 8654, 8621, 11012, 8703, + 11020, 129112, 11108, 11788, 10181, 8907, 9609, 8216, 11814, 128488, 91, + 9123, 9121, 10639, 10637, 8261, 10635, 11863, 11861, 9122, 11778, 10703, 129900, 11785, 117771, 129985, 128492, 118434, 118441, 9610, 9613, 12308, 129998, 8867, 12302, 10627, 12310, 10629, 12314, 12312, 10712, 128398, 9611, 10620, 8970, 130027, 130019, 8905, 40, 9117, 9115, 9116, 11808, @@ -11599,96 +11721,97 @@ static const unsigned int dawg_pos_to_codepoint[] = { 7206, 7212, 7207, 7237, 7236, 7239, 7238, 7235, 7234, 7232, 7241, 7233, 7240, 10897, 10895, 10893, 10899, 10891, 10614, 10889, 10887, 8922, 8934, 8808, 10918, 10920, 10885, 10877, 10881, 10883, 10879, 8818, 8804, 8822, - 8806, 10873, 10875, 8918, 60, 128210, 127898, 127819, 129461, 128626, - 128955, 128969, 128943, 11212, 128964, 10099, 128648, 10098, 9617, - 128937, 128949, 128978, 128960, 129653, 128910, 10072, 128930, 128504, - 9735, 128498, 128497, 6429, 6404, 6403, 6412, 6430, 6411, 6421, 6410, - 6405, 6415, 6425, 6426, 6427, 6419, 6418, 6407, 6406, 6414, 6413, 6409, - 6408, 6402, 6401, 6417, 6416, 6428, 6423, 6420, 6422, 6424, 6458, 6457, - 6459, 6464, 6449, 6452, 6450, 6448, 6456, 6454, 6453, 6455, 6451, 6442, - 6443, 6441, 6432, 6436, 6438, 6440, 6437, 6439, 6435, 6433, 6434, 6400, - 6468, 6469, 6475, 6474, 6477, 6476, 6473, 6472, 6470, 6479, 6471, 6478, - 13007, 10770, 10771, 10772, 983062, 8232, 983068, 983143, 67143, 67146, - 67151, 67165, 67166, 67167, 67157, 67158, 67159, 67160, 67161, 67162, - 67163, 67164, 67171, 67172, 67173, 67168, 67169, 67170, 67174, 67175, - 67176, 67177, 67178, 67179, 67230, 67231, 67180, 67181, 67182, 67183, - 67184, 67185, 67186, 67187, 67188, 67189, 67190, 67191, 67192, 67193, - 67194, 67195, 67196, 67197, 67198, 67199, 67200, 67201, 67202, 67203, - 67204, 67205, 67206, 67207, 67208, 67209, 67210, 67211, 67212, 67213, - 67214, 67215, 67216, 67217, 67218, 67219, 67220, 67221, 67222, 67223, - 67224, 67225, 67226, 67227, 67228, 67229, 67232, 67233, 67234, 67235, - 67236, 67237, 67238, 67239, 67240, 67241, 67242, 67243, 67244, 67245, - 67246, 67247, 67248, 67249, 67250, 67251, 67252, 67253, 67254, 67255, - 67256, 67257, 67258, 67259, 67260, 67261, 67262, 67263, 67264, 67274, - 67275, 67276, 67277, 67278, 67279, 67280, 67281, 67282, 67283, 67284, - 67285, 67286, 67287, 67288, 67289, 67290, 67291, 67292, 67293, 67294, - 67295, 67296, 67297, 67298, 67299, 67300, 67301, 67302, 67303, 67304, - 67265, 67266, 67267, 67268, 67269, 67270, 67271, 67272, 67273, 67325, - 67326, 67327, 67328, 67329, 67330, 67305, 67306, 67307, 67308, 67309, - 67310, 67311, 67312, 67313, 67314, 67315, 67316, 67317, 67318, 67319, - 67320, 67321, 67322, 67323, 67324, 67331, 67332, 67333, 67334, 67335, - 67336, 67337, 67338, 67349, 67350, 67351, 67352, 67353, 67354, 67355, - 67356, 67357, 67358, 67359, 67360, 67361, 67362, 67363, 67364, 67365, - 67366, 67367, 67368, 67378, 67379, 67380, 67381, 67382, 67369, 67370, - 67371, 67372, 67373, 67374, 67375, 67376, 67377, 67339, 67340, 67341, - 67342, 67343, 67344, 67345, 67346, 67347, 67348, 67401, 67404, 67403, - 67402, 67400, 67398, 67393, 67397, 67395, 67394, 67399, 67392, 67396, - 67406, 67408, 67409, 67410, 67407, 67405, 67411, 67413, 67412, 67424, - 67425, 67426, 67427, 67428, 67429, 67430, 67431, 67081, 67082, 67083, - 67084, 67085, 67087, 67088, 67089, 67090, 67091, 67092, 67093, 67094, - 67086, 67095, 67096, 67097, 67098, 67100, 67101, 67102, 67103, 67104, - 67105, 67106, 67107, 67108, 67109, 67110, 67111, 67112, 67113, 67114, - 67115, 67116, 67117, 67118, 67119, 67120, 67121, 67122, 67123, 67124, - 67125, 67126, 67127, 67128, 67129, 67130, 67131, 67132, 67133, 67134, - 67135, 67136, 67137, 67138, 67139, 67140, 67141, 67142, 67072, 67073, - 67074, 67075, 67076, 67077, 67078, 67079, 67080, 67145, 67147, 67148, - 67149, 67150, 67154, 67155, 67144, 67152, 67153, 67156, 67099, 65667, - 65668, 65669, 65670, 65671, 65672, 65673, 65675, 65674, 65677, 65676, - 65665, 65664, 65666, 65681, 65679, 65680, 65682, 65678, 65686, 65685, - 65687, 65693, 65690, 65691, 65692, 65694, 65703, 65696, 65695, 65697, - 65698, 65699, 65701, 65702, 65707, 65706, 65704, 65705, 65708, 65709, - 65710, 65711, 65712, 65713, 65719, 65717, 65714, 65715, 65716, 65718, - 65720, 65721, 65722, 65723, 65724, 65725, 65726, 65727, 65728, 65729, - 65731, 65730, 65732, 65733, 65737, 65734, 65735, 65736, 65738, 65739, - 65740, 65741, 65743, 65742, 65744, 65745, 65747, 65748, 65752, 65749, - 65750, 65751, 65753, 65754, 65755, 65756, 65757, 65779, 65780, 65781, - 65782, 65783, 65784, 65785, 65759, 65760, 65761, 65762, 65763, 65764, - 65765, 65766, 65767, 65768, 65769, 65770, 65771, 65772, 65773, 65774, - 65775, 65776, 65777, 65778, 65758, 65786, 65683, 65684, 65689, 65688, - 65700, 65746, 65561, 65543, 65587, 65582, 65589, 65536, 65541, 65579, - 65566, 65571, 65596, 65569, 65584, 65544, 65559, 65540, 65557, 65560, - 65580, 65606, 65600, 65599, 65577, 65562, 65538, 65573, 65563, 65609, - 65588, 65549, 65568, 65537, 65581, 65574, 65601, 65542, 65593, 65583, - 65594, 65552, 65547, 65605, 65578, 65545, 65585, 65586, 65546, 65570, - 65591, 65564, 65565, 65607, 65610, 65611, 65553, 65590, 65550, 65539, - 65576, 65608, 65551, 65554, 65592, 65603, 65597, 65567, 65572, 65558, - 65555, 65612, 65602, 65556, 65613, 65604, 65620, 65621, 65623, 65624, - 65626, 65627, 65628, 65629, 65622, 65616, 65617, 65619, 65618, 65625, - 128391, 128279, 128482, 128132, 42237, 42235, 42232, 42234, 42236, 42233, - 42206, 42205, 42197, 42196, 42204, 42195, 42228, 42229, 42230, 42213, - 42208, 42224, 42225, 42203, 42202, 42221, 42198, 42216, 42214, 42200, - 42199, 42194, 42193, 42219, 42210, 73648, 42220, 42211, 42212, 42222, - 42223, 42227, 42231, 42192, 42217, 42201, 42209, 42207, 42218, 42215, - 42226, 42238, 42239, 8356, 8374, 129409, 129422, 9806, 128274, 983079, - 983076, 128271, 117785, 117786, 117784, 117783, 117782, 117781, 8743, - 10848, 10846, 10833, 10844, 10842, 10847, 8744, 10841, 10851, 10850, - 10834, 10845, 10843, 10982, 10188, 129688, 10234, 10231, 10206, 10229, - 10235, 10232, 10237, 11059, 10230, 10236, 10233, 10238, 10239, 10205, - 129524, 128884, 129719, 128140, 127977, 128261, 129707, 12319, 8270, - 11847, 11848, 95, 118273, 9691, 118276, 118291, 129935, 118436, 118447, - 9604, 9697, 117765, 128394, 129852, 129853, 129870, 129872, 129868, - 129856, 129871, 129869, 129854, 129873, 129855, 128395, 128396, 128393, - 10559, 117934, 117936, 117932, 117930, 117972, 9695, 117960, 117948, - 117964, 117968, 117952, 117956, 117944, 117940, 117817, 129951, 9722, - 117820, 128397, 118428, 117935, 117937, 117933, 117931, 117973, 9694, - 117961, 117949, 117965, 117969, 117953, 117957, 117945, 117941, 117818, - 10558, 128318, 10065, 129950, 9727, 117823, 117767, 129863, 129865, - 129867, 129864, 129861, 129866, 129859, 129862, 129860, 129857, 129858, - 10195, 118431, 10063, 9998, 9987, 118429, 117821, 118430, 117822, 130021, - 9605, 118425, 118426, 118424, 117816, 118427, 117819, 9602, 9601, 9607, - 9603, 118437, 118446, 9606, 129903, 9674, 10208, 129438, 128557, 127853, - 129523, 128886, 129729, 66190, 66192, 66187, 66196, 66178, 66179, 66199, - 66185, 66200, 66176, 66201, 66177, 66202, 66191, 66193, 66181, 66180, + 8806, 10873, 10875, 8918, 60, 118480, 128210, 127898, 127819, 129461, + 128626, 128955, 128969, 128943, 11212, 128964, 10099, 128648, 10098, + 9617, 128937, 128949, 128978, 128960, 129653, 128910, 10072, 128930, + 128504, 9735, 128498, 128497, 6429, 6404, 6403, 6412, 6430, 6411, 6421, + 6410, 6405, 6415, 6425, 6426, 6427, 6419, 6418, 6407, 6406, 6414, 6413, + 6409, 6408, 6402, 6401, 6417, 6416, 6428, 6423, 6420, 6422, 6424, 6458, + 6457, 6459, 6464, 6449, 6452, 6450, 6448, 6456, 6454, 6453, 6455, 6451, + 6442, 6443, 6441, 6432, 6436, 6438, 6440, 6437, 6439, 6435, 6433, 6434, + 6400, 6468, 6469, 6475, 6474, 6477, 6476, 6473, 6472, 6470, 6479, 6471, + 6478, 13007, 10770, 10771, 10772, 983062, 8232, 983068, 983143, 67143, + 67146, 67151, 67165, 67166, 67167, 67157, 67158, 67159, 67160, 67161, + 67162, 67163, 67164, 67171, 67172, 67173, 67168, 67169, 67170, 67174, + 67175, 67176, 67177, 67178, 67179, 67230, 67231, 67180, 67181, 67182, + 67183, 67184, 67185, 67186, 67187, 67188, 67189, 67190, 67191, 67192, + 67193, 67194, 67195, 67196, 67197, 67198, 67199, 67200, 67201, 67202, + 67203, 67204, 67205, 67206, 67207, 67208, 67209, 67210, 67211, 67212, + 67213, 67214, 67215, 67216, 67217, 67218, 67219, 67220, 67221, 67222, + 67223, 67224, 67225, 67226, 67227, 67228, 67229, 67232, 67233, 67234, + 67235, 67236, 67237, 67238, 67239, 67240, 67241, 67242, 67243, 67244, + 67245, 67246, 67247, 67248, 67249, 67250, 67251, 67252, 67253, 67254, + 67255, 67256, 67257, 67258, 67259, 67260, 67261, 67262, 67263, 67264, + 67274, 67275, 67276, 67277, 67278, 67279, 67280, 67281, 67282, 67283, + 67284, 67285, 67286, 67287, 67288, 67289, 67290, 67291, 67292, 67293, + 67294, 67295, 67296, 67297, 67298, 67299, 67300, 67301, 67302, 67303, + 67304, 67265, 67266, 67267, 67268, 67269, 67270, 67271, 67272, 67273, + 67325, 67326, 67327, 67328, 67329, 67330, 67305, 67306, 67307, 67308, + 67309, 67310, 67311, 67312, 67313, 67314, 67315, 67316, 67317, 67318, + 67319, 67320, 67321, 67322, 67323, 67324, 67331, 67332, 67333, 67334, + 67335, 67336, 67337, 67338, 67349, 67350, 67351, 67352, 67353, 67354, + 67355, 67356, 67357, 67358, 67359, 67360, 67361, 67362, 67363, 67364, + 67365, 67366, 67367, 67368, 67378, 67379, 67380, 67381, 67382, 67369, + 67370, 67371, 67372, 67373, 67374, 67375, 67376, 67377, 67339, 67340, + 67341, 67342, 67343, 67344, 67345, 67346, 67347, 67348, 67401, 67404, + 67403, 67402, 67400, 67398, 67393, 67397, 67395, 67394, 67399, 67392, + 67396, 67408, 67409, 67410, 67406, 67407, 67405, 67411, 67413, 67412, + 67424, 67425, 67426, 67427, 67428, 67429, 67430, 67431, 67081, 67082, + 67083, 67084, 67085, 67087, 67088, 67089, 67090, 67091, 67092, 67093, + 67094, 67086, 67095, 67096, 67097, 67098, 67100, 67101, 67102, 67103, + 67104, 67105, 67106, 67107, 67108, 67109, 67110, 67111, 67112, 67113, + 67114, 67115, 67116, 67117, 67118, 67119, 67120, 67121, 67122, 67123, + 67124, 67125, 67126, 67127, 67128, 67129, 67130, 67131, 67132, 67133, + 67134, 67135, 67136, 67137, 67138, 67139, 67140, 67141, 67142, 67072, + 67073, 67074, 67075, 67076, 67077, 67078, 67079, 67080, 67145, 67147, + 67148, 67149, 67150, 67154, 67155, 67144, 67152, 67153, 67156, 67099, + 65667, 65668, 65669, 65670, 65671, 65672, 65673, 65675, 65674, 65677, + 65676, 65665, 65664, 65666, 65681, 65679, 65680, 65682, 65678, 65686, + 65685, 65687, 65693, 65690, 65691, 65692, 65694, 65703, 65696, 65695, + 65697, 65698, 65699, 65701, 65702, 65707, 65706, 65704, 65705, 65708, + 65709, 65710, 65711, 65712, 65713, 65719, 65717, 65714, 65715, 65716, + 65718, 65720, 65721, 65722, 65723, 65724, 65725, 65726, 65727, 65728, + 65729, 65731, 65730, 65732, 65733, 65737, 65734, 65735, 65736, 65738, + 65739, 65740, 65741, 65743, 65742, 65744, 65745, 65747, 65748, 65752, + 65749, 65750, 65751, 65753, 65754, 65755, 65756, 65757, 65779, 65780, + 65781, 65782, 65783, 65784, 65785, 65759, 65760, 65761, 65762, 65763, + 65764, 65765, 65766, 65767, 65768, 65769, 65770, 65771, 65772, 65773, + 65774, 65775, 65776, 65777, 65778, 65758, 65786, 65683, 65684, 65689, + 65688, 65700, 65746, 65561, 65543, 65587, 65582, 65589, 65536, 65541, + 65579, 65566, 65571, 65596, 65569, 65584, 65544, 65559, 65540, 65557, + 65560, 65580, 65606, 65600, 65599, 65577, 65562, 65538, 65573, 65563, + 65609, 65588, 65549, 65568, 65537, 65581, 65574, 65601, 65542, 65593, + 65583, 65594, 65552, 65547, 65605, 65578, 65545, 65585, 65586, 65546, + 65570, 65591, 65564, 65565, 65607, 65610, 65611, 65553, 65590, 65550, + 65539, 65576, 65608, 65551, 65554, 65592, 65603, 65597, 65567, 65572, + 65558, 65555, 65612, 65602, 65556, 65613, 65604, 65620, 65621, 65623, + 65624, 65626, 65627, 65628, 65629, 65622, 65616, 65617, 65619, 65618, + 65625, 128391, 128279, 128482, 128132, 42237, 42235, 42232, 42234, 42236, + 42233, 42206, 42205, 42197, 42196, 42204, 42195, 42228, 42229, 42230, + 42213, 42208, 42224, 42225, 42203, 42202, 42221, 42198, 42216, 42214, + 42200, 42199, 42194, 42193, 42219, 42210, 73648, 42220, 42211, 42212, + 42222, 42223, 42227, 42231, 42192, 42217, 42201, 42209, 42207, 42218, + 42215, 42226, 42238, 42239, 8356, 8374, 129409, 129422, 9806, 128274, + 983079, 983076, 128271, 117785, 117786, 117784, 117783, 117782, 117781, + 8743, 10848, 10846, 10833, 10844, 10842, 10847, 8744, 10841, 10851, + 10850, 10834, 10845, 10843, 10982, 10188, 129688, 10231, 129240, 10234, + 10206, 10232, 10237, 10229, 10235, 11059, 129236, 10230, 129238, 129239, + 129232, 10236, 10233, 10238, 129233, 129234, 10239, 10205, 129524, + 128884, 129719, 128140, 127977, 128261, 129707, 12319, 8270, 11847, + 11848, 95, 118273, 9691, 118276, 118291, 129935, 118436, 118447, 9604, + 9697, 117765, 128394, 129852, 129853, 129870, 129872, 129868, 129856, + 129871, 129869, 129854, 129873, 129855, 128395, 128396, 128393, 10559, + 117934, 117936, 117932, 117930, 117972, 9695, 117960, 117948, 117964, + 117968, 117952, 117956, 117944, 117940, 117817, 129951, 9722, 117820, + 128397, 118428, 117935, 117937, 117933, 117931, 117973, 9694, 117961, + 117949, 117965, 117969, 117953, 117957, 117945, 117941, 117818, 10558, + 128318, 10065, 129950, 9727, 117823, 117767, 129863, 129865, 129867, + 129864, 129861, 129866, 129859, 129862, 129860, 129857, 129858, 10195, + 118431, 10063, 9998, 9987, 118429, 117821, 118430, 117822, 130021, 9605, + 118425, 118426, 118424, 117816, 118427, 117819, 9602, 9601, 9607, 9603, + 118437, 118446, 9606, 129903, 9674, 10208, 129438, 128557, 127853, + 129523, 128886, 129729, 66190, 66192, 66187, 66196, 66199, 66185, 66200, + 66178, 66179, 66176, 66201, 66177, 66202, 66191, 66193, 66181, 66180, 66203, 66182, 66186, 66189, 66195, 66188, 66197, 66198, 66194, 66183, 66204, 66184, 67887, 67892, 67881, 67895, 67891, 67886, 67872, 67893, 67876, 67894, 67883, 67896, 67873, 67897, 67875, 67889, 67874, 67878, @@ -11856,132 +11979,132 @@ static const unsigned int dawg_pos_to_codepoint[] = { 119526, 119536, 119533, 119523, 119532, 119522, 119530, 119520, 119521, 128470, 175, 8737, 10667, 10666, 10671, 10669, 10670, 10668, 10665, 10664, 10651, 10653, 8798, 127830, 129470, 129471, 93773, 93764, 93790, - 93787, 983270, 93783, 983269, 93782, 93772, 93766, 93791, 93779, 93789, + 93787, 983274, 93783, 983273, 93782, 93772, 93766, 93791, 93779, 93789, 93786, 93776, 93777, 93785, 93775, 93770, 93769, 93771, 93774, 93780, 93760, 93767, 93781, 93788, 93761, 93768, 93778, 93762, 93763, 93784, 93765, 93847, 93827, 93846, 93826, 93845, 93825, 93844, 93829, 93828, 93831, 93830, 93824, 93833, 93832, 93837, 93836, 93834, 93842, 93835, - 93838, 93839, 93843, 93840, 93841, 93805, 93796, 93822, 93819, 983272, - 93815, 983271, 93814, 93804, 93798, 93823, 93811, 93821, 93818, 93808, + 93838, 93839, 93843, 93840, 93841, 93805, 93796, 93822, 93819, 983276, + 93815, 983275, 93814, 93804, 93798, 93823, 93811, 93821, 93818, 93808, 93809, 93817, 93807, 93802, 93801, 93803, 93806, 93812, 93792, 93799, 93813, 93820, 93793, 93800, 93810, 93794, 93795, 93816, 93797, 93849, 93850, 93848, 11859, 11852, 11860, 128901, 9899, 10090, 10091, 128967, - 128965, 128944, 10100, 10088, 10092, 10101, 10089, 10093, 8287, 9900, - 9618, 128971, 128950, 128938, 128963, 128961, 10073, 128974, 128956, - 9898, 128911, 128931, 43761, 44013, 43762, 43760, 44011, 43994, 43989, - 43974, 43746, 43993, 43991, 43751, 43750, 43992, 43986, 43987, 43990, - 43968, 43995, 43976, 43973, 43999, 43977, 44001, 43752, 43747, 43972, - 43998, 43984, 43969, 43753, 43754, 43975, 44000, 43978, 43749, 43748, - 43983, 44002, 43970, 43996, 43971, 43997, 43981, 43988, 43979, 43985, - 43980, 43982, 43744, 43745, 44012, 43763, 43764, 44005, 43757, 43759, - 43758, 44009, 44003, 44007, 44006, 44004, 43755, 44008, 43756, 44010, - 43765, 43766, 44021, 44020, 44023, 44022, 44019, 44018, 44016, 44025, - 44017, 44024, 129760, 127816, 125140, 125137, 125136, 125139, 125141, - 125138, 125142, 124928, 124929, 124930, 124936, 124937, 124949, 124950, - 124948, 124938, 124956, 124990, 124992, 124974, 124955, 124964, 124963, - 124991, 124957, 124962, 124976, 124996, 124997, 124998, 124982, 124983, - 124984, 125004, 124975, 125003, 125005, 125011, 125018, 125028, 125029, - 125012, 125019, 125020, 125027, 125013, 125035, 125048, 124942, 124934, - 125090, 125046, 125078, 125033, 124946, 125037, 125070, 125000, 125095, - 125121, 124951, 125044, 125041, 125072, 124987, 125066, 125076, 125074, - 125009, 125107, 125108, 125068, 125124, 124945, 125002, 124931, 125089, - 125022, 124980, 125099, 124986, 125100, 125080, 125119, 124933, 125021, - 125015, 125071, 124985, 125117, 125056, 124993, 125039, 125049, 125043, - 125024, 124932, 125047, 125097, 124959, 125069, 125088, 124999, 125123, - 124952, 125036, 125026, 125001, 125085, 124960, 125057, 125073, 124966, - 125098, 125014, 125091, 124989, 125007, 124978, 124940, 125106, 125050, - 125030, 125092, 124941, 125060, 125077, 125102, 125094, 125053, 125040, - 125055, 125104, 125103, 124939, 125017, 124961, 125112, 125087, 124970, - 124971, 124969, 125023, 124979, 125042, 124947, 125086, 125075, 125051, - 125111, 124968, 124944, 125038, 125096, 125016, 125118, 125109, 124953, - 125059, 125052, 125006, 124958, 125093, 125115, 125054, 124988, 125008, - 125084, 125061, 125064, 125120, 125063, 124967, 124977, 124965, 125031, - 983275, 125081, 125082, 983276, 125010, 125067, 124973, 125032, 124935, - 125116, 125122, 125101, 124994, 124995, 125113, 125058, 125079, 125114, - 125065, 125034, 125083, 124954, 125062, 125105, 125110, 125045, 124943, - 124972, 124981, 125025, 125131, 125130, 125133, 125132, 125129, 125128, - 125135, 125127, 125134, 128334, 128697, 68028, 68093, 68090, 68089, - 68086, 68029, 68092, 68091, 68095, 68088, 68087, 68094, 68000, 68016, - 68020, 68021, 68022, 68009, 68010, 68015, 68017, 68014, 68013, 68018, - 68006, 68023, 68012, 68008, 68007, 68019, 68011, 68005, 68004, 68001, - 68002, 68003, 68031, 68030, 68039, 68075, 68057, 68084, 68066, 68036, - 68054, 68081, 68063, 68045, 68072, 68035, 68053, 68080, 68062, 68044, - 68071, 68040, 68076, 68058, 68085, 68067, 68038, 68056, 68083, 68065, - 68047, 68074, 68037, 68055, 68082, 68064, 68046, 68073, 68034, 68052, - 68079, 68061, 68043, 68070, 68033, 68051, 68078, 68060, 68042, 68069, - 68041, 68068, 68032, 68050, 68077, 68059, 67974, 67975, 67982, 67983, - 67978, 67979, 67980, 67981, 67987, 67988, 67989, 67992, 67993, 67994, - 67995, 67996, 67986, 67985, 67990, 67997, 67984, 67977, 67976, 67991, - 67973, 67972, 67968, 67969, 67970, 67971, 67998, 67999, 9791, 129500, - 983173, 9170, 9172, 9177, 9176, 9175, 9173, 9174, 9171, 9169, 128647, - 128221, 94015, 93989, 93971, 93958, 94019, 94021, 93953, 94023, 93999, - 93995, 94008, 93981, 93979, 93967, 93963, 93993, 93992, 93983, 93977, - 93976, 93975, 93974, 93968, 94032, 93988, 93987, 93973, 93972, 93997, - 93996, 93969, 94106, 94107, 94108, 94109, 94110, 94111, 94002, 94026, - 94022, 94003, 94004, 94010, 93980, 93978, 94099, 94100, 94101, 94102, - 94103, 94104, 94105, 93998, 93994, 94007, 94025, 93966, 93962, 94024, - 93961, 93960, 94000, 94009, 93964, 93965, 94001, 93970, 93984, 93954, - 94017, 94014, 94016, 94013, 94006, 94012, 94005, 94011, 93986, 93985, - 93955, 93952, 94020, 93990, 93957, 93956, 93959, 93982, 94018, 93991, - 94035, 94034, 94033, 94031, 94098, 94096, 94097, 94095, 94036, 94039, - 94040, 94067, 94068, 94038, 94037, 94073, 94075, 94045, 94071, 94069, - 94046, 94047, 94085, 94074, 94049, 94050, 94051, 94052, 94053, 94086, - 94057, 94054, 94084, 94055, 94056, 94041, 94082, 94048, 94081, 94042, - 94076, 94058, 94059, 94060, 94061, 94063, 94064, 94079, 94087, 94062, - 94065, 94080, 94066, 94072, 94070, 94044, 94043, 94077, 94078, 94083, - 983239, 983240, 128300, 127908, 181, 129440, 117772, 129986, 130022, - 130023, 183, 8943, 129686, 127894, 127756, 8357, 128189, 128469, 128656, - 8722, 10793, 10794, 10796, 10795, 10810, 8770, 8723, 10751, 129694, - 129705, 128241, 128242, 128244, 129339, 8871, 71232, 71229, 71236, 71231, - 71230, 71216, 71226, 71228, 71219, 71220, 71221, 71222, 71223, 71224, - 71217, 71218, 71225, 71227, 71234, 71233, 71253, 71252, 71255, 71254, - 71251, 71250, 71248, 71257, 71249, 71256, 71168, 71169, 71179, 71181, - 71195, 71194, 71200, 71199, 71193, 71192, 71198, 71197, 71174, 71175, - 71176, 71177, 71210, 71172, 71173, 71170, 71171, 71215, 71209, 71186, - 71196, 71191, 71201, 71211, 71212, 71213, 71205, 71204, 71188, 71187, - 71185, 71184, 71190, 71189, 71183, 71182, 71203, 71202, 71214, 71206, - 71208, 71207, 71178, 71180, 71235, 43867, 67512, 714, 700, 67509, 761, - 763, 7470, 7471, 7487, 7474, 7483, 7476, 43000, 7484, 7485, 7468, 7469, - 42994, 7472, 7473, 42995, 7475, 7477, 7478, 7479, 7480, 7481, 7482, 7486, - 42996, 7488, 7489, 11389, 7490, 723, 722, 42755, 42753, 42757, 42759, - 42754, 42752, 42756, 42758, 42652, 122956, 122958, 122929, 122954, - 122932, 122952, 122943, 122987, 122946, 122938, 122939, 122942, 122960, - 122941, 122959, 122989, 122955, 122950, 122948, 122944, 122951, 122988, - 122953, 122934, 122935, 122936, 122933, 122949, 122931, 122957, 122930, - 122947, 122937, 122928, 122940, 122945, 42653, 7544, 710, 735, 42889, - 67510, 42776, 42775, 42777, 750, 698, 725, 709, 984011, 42765, 42760, - 42770, 741, 984012, 42769, 42764, 42774, 745, 762, 764, 715, 704, 67507, - 4348, 42766, 42761, 42771, 742, 721, 67511, 42888, 42768, 42763, 751, - 767, 753, 42773, 717, 754, 755, 744, 759, 719, 718, 42783, 752, 716, - 42778, 703, 43882, 706, 713, 42767, 42762, 42772, 743, 758, 757, 756, - 727, 766, 726, 697, 42780, 42782, 42781, 42779, 760, 705, 67508, 701, - 67513, 702, 43883, 707, 734, 42890, 765, 7491, 7493, 7516, 67459, 7495, - 7601, 7509, 67461, 7517, 7580, 7590, 694, 7591, 67474, 67476, 7595, - 67484, 67491, 67456, 67460, 67478, 7600, 67498, 7608, 67506, 67471, - 67492, 7581, 7521, 7496, 67468, 67469, 67467, 67466, 7519, 7585, 67480, - 67463, 67465, 67464, 7611, 7613, 7612, 7497, 7604, 7582, 7614, 7505, - 7584, 67472, 7501, 7518, 7520, 67475, 736, 688, 689, 67477, 43868, 67479, - 7504, 7596, 7588, 7589, 690, 7592, 737, 43869, 43870, 7593, 67485, 7594, - 67483, 67481, 67482, 67486, 67487, 43001, 7599, 7598, 7506, 67490, 7499, - 7507, 7510, 7602, 691, 67497, 67496, 67473, 740, 7583, 67470, 738, 67514, - 7603, 7586, 7498, 7513, 7511, 7605, 67503, 67499, 67502, 7508, 67500, - 67501, 7492, 7579, 7494, 7514, 7597, 7500, 692, 67494, 67495, 693, 67488, - 67489, 7587, 7502, 7610, 43881, 7615, 7512, 43871, 7606, 7607, 7515, - 67504, 7609, 7503, 67493, 695, 739, 696, 42784, 42785, 67458, 67457, 720, - 699, 724, 708, 749, 42864, 748, 712, 747, 746, 10762, 128184, 128176, - 129297, 71266, 6165, 6164, 6167, 6166, 6163, 6162, 6160, 6169, 6161, - 6168, 6159, 6157, 6156, 6155, 6147, 6149, 71271, 71272, 6176, 6279, 6272, - 6295, 6273, 6289, 6274, 6313, 6286, 6311, 6310, 6280, 6276, 6275, 6282, - 6287, 6278, 6285, 6284, 6288, 6277, 6291, 6290, 6293, 6294, 6292, 6283, - 6281, 6185, 6196, 6264, 6210, 6190, 6303, 6305, 6307, 6300, 6302, 6304, - 6312, 6298, 6301, 6314, 6308, 6309, 6299, 6306, 6263, 6262, 6260, 6261, - 6259, 6244, 6252, 6245, 6253, 6238, 6239, 6254, 6248, 6257, 6247, 6256, - 6242, 6258, 6255, 6241, 6240, 6249, 6251, 6250, 6243, 6246, 6237, 6193, - 6192, 6297, 6296, 6218, 6236, 6225, 6234, 6227, 6235, 6211, 6222, 6232, - 6228, 6224, 6226, 6233, 6214, 6216, 6215, 6217, 6219, 6231, 6223, 6220, - 6221, 6230, 6229, 6212, 6213, 6204, 6194, 6209, 6207, 6205, 6206, 6203, - 6202, 6208, 6191, 6177, 6183, 6179, 6181, 6180, 6182, 6186, 6195, 6201, - 6189, 6197, 6184, 6187, 6188, 6199, 6200, 6198, 6178, 71273, 71275, + 128965, 128944, 10100, 10088, 10092, 10101, 10089, 10093, 8287, 9618, + 128971, 128950, 128938, 9900, 118512, 128963, 128961, 10073, 128974, + 128956, 9898, 128911, 128931, 43761, 44013, 43762, 43760, 44011, 43994, + 43989, 43974, 43746, 43993, 43991, 43751, 43750, 43992, 43986, 43987, + 43990, 43968, 43995, 43976, 43973, 43999, 43977, 44001, 43752, 43747, + 43972, 43998, 43984, 43969, 43753, 43754, 43975, 44000, 43978, 43749, + 43748, 43983, 44002, 43970, 43996, 43971, 43997, 43981, 43988, 43979, + 43985, 43980, 43982, 43744, 43745, 44012, 43763, 43764, 44005, 43757, + 43759, 43758, 44009, 44003, 44007, 44006, 44004, 43755, 44008, 43756, + 44010, 43765, 43766, 44021, 44020, 44023, 44022, 44019, 44018, 44016, + 44025, 44017, 44024, 118475, 129760, 127816, 125140, 125137, 125136, + 125139, 125141, 125138, 125142, 124928, 124929, 124930, 124936, 124937, + 124949, 124950, 124948, 124938, 124956, 124990, 124992, 124974, 124955, + 124964, 124963, 124991, 124957, 124962, 124976, 124996, 124997, 124998, + 124982, 124983, 124984, 125004, 124975, 125003, 125005, 125011, 125018, + 125028, 125029, 125012, 125019, 125020, 125027, 125013, 125035, 124942, + 124934, 125090, 125046, 125078, 125033, 124946, 125048, 125037, 125070, + 125000, 125095, 125121, 124951, 125044, 125041, 125072, 124987, 125066, + 125076, 125074, 125009, 125107, 125108, 125068, 125124, 124945, 125002, + 124931, 125089, 125022, 124980, 125099, 124986, 125100, 125080, 125119, + 124933, 125021, 125015, 125071, 124985, 125117, 125056, 124993, 125039, + 125049, 125043, 125024, 124932, 125047, 125097, 124959, 125069, 125088, + 124999, 125123, 124952, 125036, 125026, 125001, 125085, 124960, 125057, + 125073, 124966, 125098, 125014, 125091, 124989, 125007, 124978, 124940, + 125106, 125050, 125030, 125092, 124941, 125060, 125077, 125102, 125094, + 125053, 125040, 125055, 125104, 125103, 124939, 125017, 124961, 125112, + 125087, 124970, 124971, 124969, 125023, 124979, 125042, 124947, 125086, + 125075, 125051, 125111, 124968, 124944, 125038, 125096, 125016, 125118, + 125109, 124953, 125059, 125052, 125006, 124958, 125093, 125115, 125054, + 124988, 125008, 125084, 125061, 125064, 125120, 125063, 124967, 124977, + 124965, 125031, 983279, 125081, 125082, 983280, 125010, 125067, 124973, + 125032, 124935, 125116, 125122, 125101, 124994, 124995, 125113, 125058, + 125079, 125114, 125065, 125034, 125083, 124954, 125062, 125105, 125110, + 125045, 124943, 124972, 124981, 125025, 125131, 125130, 125133, 125132, + 125129, 125128, 125135, 125127, 125134, 128334, 128697, 68028, 68093, + 68090, 68089, 68086, 68029, 68092, 68091, 68095, 68088, 68087, 68094, + 68000, 68016, 68020, 68021, 68022, 68009, 68010, 68015, 68017, 68014, + 68013, 68018, 68006, 68023, 68012, 68008, 68007, 68019, 68011, 68005, + 68004, 68001, 68002, 68003, 68031, 68030, 68039, 68075, 68057, 68084, + 68066, 68036, 68054, 68081, 68063, 68045, 68072, 68035, 68053, 68080, + 68062, 68044, 68071, 68040, 68076, 68058, 68085, 68067, 68038, 68056, + 68083, 68065, 68047, 68074, 68037, 68055, 68082, 68064, 68046, 68073, + 68034, 68052, 68079, 68061, 68043, 68070, 68033, 68051, 68078, 68060, + 68042, 68069, 68041, 68068, 68032, 68050, 68077, 68059, 67974, 67975, + 67982, 67983, 67978, 67979, 67980, 67981, 67987, 67988, 67989, 67992, + 67993, 67994, 67995, 67996, 67986, 67985, 67990, 67997, 67984, 67977, + 67976, 67991, 67973, 67972, 67968, 67969, 67970, 67971, 67998, 67999, + 9791, 129500, 983173, 9170, 9172, 9177, 9176, 9175, 9173, 9174, 9171, + 9169, 128647, 118467, 128221, 94015, 93989, 93971, 93958, 94019, 94021, + 93953, 94023, 93999, 93995, 94008, 93981, 93979, 93967, 93963, 93993, + 93992, 93983, 93977, 93976, 93975, 93974, 93968, 94032, 93988, 93987, + 93973, 93972, 93997, 93996, 93969, 94106, 94107, 94108, 94109, 94110, + 94111, 94002, 94026, 94022, 94003, 94004, 94010, 93980, 93978, 94099, + 94100, 94101, 94102, 94103, 94104, 94105, 93998, 93994, 94007, 94025, + 93966, 93962, 94024, 93961, 93960, 94000, 94009, 93964, 93965, 94001, + 93970, 93984, 93954, 94017, 94014, 94016, 94013, 94006, 94012, 94005, + 94011, 93986, 93985, 93955, 93952, 94020, 93990, 93957, 93956, 93959, + 93982, 94018, 93991, 94035, 94034, 94033, 94031, 94098, 94096, 94097, + 94095, 94036, 94039, 94040, 94067, 94068, 94038, 94037, 94073, 94075, + 94045, 94071, 94069, 94046, 94047, 94085, 94074, 94049, 94050, 94051, + 94052, 94053, 94086, 94057, 94054, 94084, 94055, 94056, 94041, 94082, + 94048, 94081, 94042, 94076, 94058, 94059, 94060, 94061, 94063, 94064, + 94079, 94087, 94062, 94065, 94080, 94066, 94072, 94070, 94044, 94043, + 94077, 94078, 94083, 983239, 983240, 128300, 127908, 181, 129440, 117772, + 129986, 130022, 130023, 183, 8943, 129686, 127894, 127756, 8357, 128189, + 128469, 128656, 8722, 10793, 10794, 10796, 10795, 10810, 8770, 8723, + 10751, 129694, 129705, 128241, 128242, 128244, 129339, 8871, 71232, + 71229, 71236, 71231, 71230, 71216, 71226, 71228, 71219, 71220, 71221, + 71222, 71223, 71224, 71217, 71218, 71225, 71227, 71234, 71233, 71253, + 71252, 71255, 71254, 71251, 71250, 71248, 71257, 71249, 71256, 71168, + 71169, 71179, 71181, 71195, 71194, 71200, 71199, 71193, 71192, 71198, + 71197, 71174, 71175, 71176, 71177, 71210, 71172, 71173, 71170, 71171, + 71215, 71209, 71186, 71196, 71191, 71201, 71211, 71212, 71213, 71205, + 71204, 71188, 71187, 71185, 71184, 71190, 71189, 71183, 71182, 71203, + 71202, 71214, 71206, 71208, 71207, 71178, 71180, 71235, 43867, 67512, + 714, 700, 67509, 761, 763, 7470, 7471, 7487, 7474, 7483, 7476, 43000, + 7484, 7485, 7468, 7469, 42994, 7472, 7473, 42995, 7475, 7477, 7478, 7479, + 7480, 7481, 7482, 7486, 42996, 42993, 7488, 7489, 11389, 7490, 723, 722, + 42755, 42753, 42757, 42759, 42754, 42752, 42756, 42758, 42652, 122956, + 122958, 122929, 122954, 122932, 122952, 122943, 122987, 122946, 122938, + 122939, 122942, 122960, 122941, 122959, 122989, 122955, 122950, 122948, + 122944, 122951, 122988, 122953, 122934, 122935, 122936, 122933, 122949, + 122931, 122957, 122930, 122947, 122937, 122928, 122940, 122945, 42653, + 7544, 710, 735, 42889, 67510, 42776, 42775, 42777, 750, 698, 725, 709, + 984011, 42765, 42760, 42770, 741, 984012, 42769, 42764, 42774, 745, 762, + 764, 715, 704, 67507, 4348, 42766, 42761, 42771, 742, 721, 67511, 42888, + 42768, 42763, 751, 767, 753, 42773, 717, 754, 755, 744, 759, 719, 718, + 42783, 752, 716, 42778, 703, 43882, 706, 713, 42767, 42762, 42772, 743, + 758, 757, 756, 727, 766, 726, 697, 42780, 42782, 42781, 42779, 760, 705, + 67508, 701, 67513, 702, 43883, 707, 734, 42890, 765, 7491, 7493, 7516, + 67459, 7495, 7601, 7509, 67461, 7517, 7580, 7590, 694, 7591, 67474, + 67476, 7595, 67484, 67491, 67456, 67460, 67478, 7600, 67498, 7608, 67506, + 67471, 67492, 7581, 7521, 7496, 67468, 67469, 67467, 67466, 7519, 7585, + 67480, 67463, 67465, 67464, 7611, 7613, 7612, 7497, 7604, 7582, 7614, + 7505, 7584, 67472, 7501, 7518, 7520, 67475, 736, 688, 689, 67477, 43868, + 67479, 7504, 7596, 7588, 7589, 690, 7592, 737, 43869, 43870, 7593, 67485, + 7594, 67483, 67481, 67482, 67486, 67487, 43001, 7599, 7598, 7506, 67490, + 7499, 7507, 7510, 7602, 691, 67497, 67496, 67473, 740, 7583, 67470, 738, + 67514, 7603, 7586, 7498, 7513, 7511, 7605, 67503, 67499, 67502, 7508, + 67500, 67501, 7492, 7579, 7494, 7514, 7597, 7500, 692, 67494, 67495, 693, + 67488, 67489, 7587, 7502, 7610, 43881, 7615, 7512, 43871, 7606, 7607, + 7515, 67504, 7609, 7503, 67493, 695, 739, 696, 42784, 42785, 67458, + 67457, 720, 699, 724, 708, 749, 42864, 748, 712, 747, 746, 10762, 128184, + 128176, 129297, 71266, 6165, 6164, 6167, 6166, 6163, 6162, 6160, 6169, + 6161, 6168, 6159, 6157, 6156, 6155, 6147, 6149, 71271, 71272, 6176, 6279, + 6272, 6295, 6273, 6289, 6274, 6313, 6286, 6311, 6310, 6280, 6276, 6275, + 6282, 6287, 6278, 6285, 6284, 6288, 6277, 6291, 6290, 6293, 6294, 6292, + 6283, 6281, 6185, 6196, 6264, 6210, 6190, 6303, 6305, 6307, 6300, 6302, + 6304, 6312, 6298, 6301, 6314, 6308, 6309, 6299, 6306, 6263, 6262, 6260, + 6261, 6259, 6244, 6252, 6245, 6253, 6254, 6248, 6238, 6239, 6257, 6247, + 6256, 6242, 6258, 6255, 6241, 6240, 6249, 6251, 6250, 6243, 6246, 6237, + 6193, 6192, 6297, 6296, 6218, 6236, 6225, 6234, 6227, 6235, 6211, 6222, + 6232, 6228, 6224, 6226, 6233, 6214, 6216, 6215, 6217, 6219, 6231, 6223, + 6220, 6221, 6230, 6229, 6212, 6213, 6204, 6194, 6209, 6207, 6205, 6206, + 6203, 6202, 6208, 6191, 6177, 6183, 6179, 6181, 6180, 6182, 6186, 6195, + 6201, 6189, 6197, 6184, 6187, 6188, 6199, 6200, 6198, 6178, 71273, 71275, 71274, 6151, 71265, 71270, 71269, 6144, 71268, 71264, 71267, 71276, 6150, 6158, 6148, 6146, 6152, 6153, 6154, 6145, 9866, 9867, 119552, 9101, 128669, 128018, 128053, 127889, 129390, 118261, 128496, 129742, 129439, @@ -11989,14 +12112,14 @@ static const unsigned int dawg_pos_to_codepoint[] = { 128693, 128507, 128001, 129700, 128045, 128068, 128511, 127909, 92748, 92744, 92761, 92750, 92739, 92751, 92737, 92754, 92749, 92753, 92743, 92752, 92757, 92766, 92736, 92741, 92746, 92764, 92745, 92765, 92755, - 92760, 92758, 92756, 92763, 92762, 92747, 92738, 92740, 92759, 92742, + 92756, 92763, 92762, 92747, 92760, 92758, 92738, 92740, 92759, 92742, 92783, 92782, 92773, 92772, 92775, 92774, 92771, 92770, 92768, 92777, 92769, 92776, 70291, 70292, 70290, 70297, 70296, 70293, 70287, 70298, 70312, 70311, 70306, 70285, 70284, 70289, 70288, 70295, 70294, 70303, 70301, 70283, 70282, 70280, 70278, 70277, 70276, 70300, 70299, 70310, 70307, 70304, 70309, 70308, 70305, 70272, 70275, 70273, 70274, 70313, 127926, 215, 10804, 10805, 10807, 10811, 10801, 10800, 10005, 8844, 8845, - 8846, 8888, 127812, 117860, 9838, 9837, 9839, 127929, 127896, 119161, + 8846, 8888, 127812, 117860, 9838, 9839, 9837, 127929, 127896, 119161, 119159, 119155, 119157, 119061, 119060, 119224, 119235, 119132, 119058, 119059, 119255, 119253, 119130, 119131, 119163, 119169, 119149, 119167, 119168, 119210, 119178, 119173, 119211, 119150, 119151, 119152, 119153, @@ -12108,9 +12231,9 @@ static const unsigned int dawg_pos_to_codepoint[] = { 129208, 128600, 128592, 128608, 11110, 11126, 11017, 8662, 129108, 11009, 128746, 8882, 8884, 8379, 8836, 8837, 8713, 8772, 8777, 8938, 8940, 8742, 8930, 8931, 172, 8877, 8769, 8813, 8800, 8802, 8815, 8814, 9083, 128323, - 10159, 128324, 10161, 128456, 128457, 128458, 128211, 128212, 160, - 128067, 9369, 9362, 9365, 9366, 9367, 35, 9368, 9364, 9361, 9363, 9371, - 9370, 8470, 110960, 110961, 110962, 110963, 110964, 110965, 110966, + 10159, 128324, 10161, 128456, 128457, 128458, 128211, 128212, 128067, + 118012, 160, 9369, 9362, 9365, 9366, 9367, 35, 9368, 9364, 9361, 9363, + 9371, 9370, 8470, 110960, 110961, 110962, 110963, 110964, 110965, 110966, 110967, 110968, 110969, 110970, 110971, 110972, 110973, 110974, 110975, 110976, 110977, 110978, 110979, 110980, 110981, 110982, 110983, 110984, 110985, 110986, 110987, 110988, 110989, 110990, 110991, 110992, 110993, @@ -12164,76 +12287,76 @@ static const unsigned int dawg_pos_to_codepoint[] = { 123185, 123188, 123187, 123215, 123205, 123204, 123207, 123206, 123203, 123202, 123200, 123209, 123201, 123208, 117776, 983231, 983066, 10663, 10662, 11869, 9215, 65532, 9287, 9286, 9284, 9285, 9289, 9281, 9290, - 9288, 9282, 9283, 9280, 128721, 128025, 128885, 127970, 5787, 5788, 5776, - 5761, 5786, 5770, 5769, 5781, 5779, 5785, 5763, 5772, 5780, 5784, 5762, - 5775, 5773, 5765, 5777, 5782, 5764, 5774, 5783, 5766, 5778, 5771, 5767, - 5768, 5760, 731, 128738, 7265, 7264, 7266, 7267, 7261, 7260, 7262, 7259, - 7280, 7282, 7281, 7279, 7271, 7270, 7272, 7269, 7258, 7263, 7278, 7268, - 7283, 7273, 7284, 7285, 7287, 7286, 7276, 7274, 7275, 7277, 7290, 7288, - 7289, 7295, 7294, 7292, 7291, 7253, 7252, 7255, 7254, 7251, 7250, 7248, - 7257, 7249, 7256, 7293, 124374, 124376, 124375, 124377, 124378, 124379, - 124392, 124396, 124395, 124397, 124394, 124393, 124380, 124381, 124383, - 124384, 124385, 124382, 124368, 124371, 124370, 124369, 124372, 124373, - 124386, 124388, 124390, 124389, 124387, 124391, 124399, 124400, 124398, - 124415, 124406, 124405, 124408, 124407, 124404, 124403, 124401, 124410, - 124402, 124409, 94179, 94178, 68736, 68739, 68744, 68737, 68756, 68745, - 68760, 68769, 68761, 68775, 68785, 68741, 68762, 68772, 68773, 68740, - 68777, 68742, 68749, 68750, 68758, 68759, 68774, 68776, 68783, 68784, - 68738, 68743, 68747, 68748, 68751, 68754, 68755, 68768, 68770, 68782, - 68765, 68780, 68766, 68781, 68763, 68767, 68764, 68778, 68757, 68786, - 68779, 68746, 68752, 68753, 68771, 68800, 68803, 68808, 68801, 68820, - 68809, 68824, 68833, 68825, 68839, 68849, 68805, 68826, 68836, 68837, - 68804, 68841, 68806, 68813, 68814, 68822, 68823, 68838, 68840, 68847, - 68848, 68802, 68807, 68811, 68812, 68815, 68818, 68819, 68832, 68834, - 68846, 68829, 68844, 68830, 68845, 68827, 68831, 68828, 68842, 68821, - 68850, 68843, 68810, 68816, 68817, 68835, 68861, 68859, 68858, 68862, - 68863, 68860, 66308, 66324, 66318, 66335, 66323, 66331, 66327, 66330, - 66315, 66316, 66317, 66329, 66314, 66306, 66322, 66351, 66321, 66350, - 66326, 66334, 66313, 66333, 66328, 66320, 66312, 66325, 66332, 66305, - 66307, 66311, 66309, 66349, 66310, 66304, 66319, 66339, 66337, 66338, - 66336, 68241, 68242, 68246, 68244, 68226, 68224, 68237, 68235, 68249, - 68251, 68247, 68233, 68248, 68252, 68227, 68234, 68230, 68239, 68232, - 68240, 68231, 68250, 68236, 68225, 68243, 68245, 68228, 68229, 68238, - 68255, 68254, 68253, 66404, 66390, 66392, 66387, 66388, 66411, 66393, - 66421, 66418, 66396, 66397, 66399, 66406, 66405, 66401, 66413, 66402, - 66398, 66414, 66415, 66416, 66408, 66420, 66417, 66407, 66419, 66389, - 66391, 66395, 66400, 66386, 66409, 66410, 66385, 66384, 66394, 66412, - 66403, 66516, 66514, 66515, 66517, 66513, 66464, 66504, 66505, 66506, - 66482, 66510, 66511, 66477, 66508, 66509, 66478, 66479, 66473, 66474, - 66490, 66491, 66480, 66475, 66476, 66507, 66471, 66469, 66470, 66467, - 66468, 66484, 66485, 66492, 66493, 66486, 66487, 66488, 66497, 66498, - 66495, 66472, 66483, 66499, 66494, 66481, 66489, 66496, 66465, 66466, - 66512, 128435, 118450, 69414, 69395, 69376, 69394, 69391, 69392, 69398, - 69399, 69403, 69404, 69377, 69379, 69382, 69400, 69388, 69380, 69384, - 69393, 69397, 69401, 69386, 69381, 69385, 69387, 69378, 69390, 69402, - 69383, 69396, 69389, 69415, 69407, 69412, 69411, 69406, 69410, 69405, - 69413, 69409, 69408, 68209, 68210, 68217, 68211, 68213, 68214, 68212, - 68203, 68205, 68207, 68206, 68202, 68198, 68220, 68219, 68215, 68201, - 68216, 68193, 68196, 68199, 68218, 68192, 68194, 68200, 68204, 68197, - 68208, 68195, 68222, 68221, 68223, 68608, 68619, 68627, 68623, 68634, - 68640, 68644, 68668, 68670, 68677, 68632, 68669, 68671, 68617, 68625, - 68621, 68638, 68643, 68660, 68666, 68675, 68630, 68648, 68653, 68646, - 68650, 68641, 68673, 68658, 68642, 68655, 68628, 68611, 68657, 68662, - 68614, 68615, 68636, 68656, 68664, 68679, 68680, 68609, 68610, 68645, - 68654, 68620, 68624, 68635, 68678, 68633, 68672, 68652, 68618, 68626, - 68622, 68639, 68661, 68667, 68676, 68631, 68613, 68649, 68647, 68651, - 68674, 68659, 68629, 68612, 68663, 68616, 68637, 68665, 69509, 69508, - 69507, 69506, 69488, 69502, 69496, 69505, 69492, 69499, 69501, 69503, - 69494, 69493, 69490, 69495, 69489, 69498, 69504, 69491, 69500, 69497, - 69511, 69512, 69513, 69510, 128477, 128117, 129491, 128116, 129746, - 128283, 128664, 128753, 128662, 128660, 128653, 11819, 8228, 128431, - 129649, 129477, 128214, 9251, 10044, 10027, 10034, 10011, 128194, 128449, - 128080, 128237, 128236, 10180, 10179, 128275, 9103, 9104, 10174, 983191, - 8997, 128191, 128440, 9934, 9741, 128217, 129505, 129447, 8886, 2902, - 2903, 2933, 2934, 2931, 2930, 2935, 2932, 2928, 2909, 2908, 2864, 2911, - 2863, 2821, 2822, 2832, 2836, 2850, 2849, 2855, 2854, 2848, 2847, 2853, - 2852, 2827, 2912, 2828, 2913, 2869, 2825, 2826, 2823, 2824, 2867, 2866, - 2841, 2851, 2846, 2856, 2870, 2871, 2872, 2861, 2860, 2843, 2842, 2840, - 2839, 2845, 2844, 2838, 2837, 2859, 2858, 2873, 2862, 2929, 2831, 2835, - 983660, 983659, 2817, 2876, 2877, 2818, 2901, 2893, 2819, 2878, 2888, - 2892, 2881, 2882, 2883, 2884, 2914, 2915, 2879, 2880, 2887, 2891, 2923, - 2922, 2925, 2924, 2921, 2920, 2918, 2927, 2919, 2926, 64830, 64831, 9766, - 117826, 10183, 128895, 66736, 66737, 66738, 66739, 66743, 66763, 66761, + 9288, 9282, 9283, 9280, 128721, 128025, 128885, 5787, 5788, 5776, 5761, + 5786, 5770, 5769, 5781, 5779, 5785, 5763, 5772, 5780, 5784, 5762, 5775, + 5773, 5765, 5777, 5782, 5764, 5774, 5783, 5766, 5778, 5771, 5767, 5768, + 5760, 731, 128738, 7265, 7264, 7266, 7267, 7261, 7260, 7262, 7259, 7280, + 7282, 7281, 7279, 7271, 7270, 7272, 7269, 7258, 7263, 7278, 7268, 7283, + 7273, 7284, 7285, 7287, 7286, 7276, 7274, 7275, 7277, 7290, 7288, 7289, + 7295, 7294, 7292, 7291, 7253, 7252, 7255, 7254, 7251, 7250, 7248, 7257, + 7249, 7256, 7293, 124374, 124376, 124375, 124377, 124378, 124379, 124392, + 124396, 124395, 124397, 124394, 124393, 124380, 124381, 124383, 124384, + 124385, 124382, 124368, 124371, 124370, 124369, 124372, 124373, 124386, + 124388, 124390, 124389, 124387, 124391, 124399, 124400, 124398, 124415, + 124406, 124405, 124408, 124407, 124404, 124403, 124401, 124410, 124402, + 124409, 94179, 94178, 68736, 68739, 68744, 68737, 68756, 68745, 68760, + 68769, 68761, 68775, 68785, 68741, 68762, 68772, 68773, 68740, 68777, + 68742, 68749, 68750, 68758, 68759, 68774, 68776, 68783, 68784, 68738, + 68743, 68747, 68748, 68751, 68754, 68755, 68768, 68770, 68782, 68765, + 68780, 68766, 68781, 68763, 68767, 68764, 68771, 68778, 68757, 68786, + 68779, 68746, 68752, 68753, 68800, 68803, 68808, 68801, 68820, 68809, + 68824, 68833, 68825, 68839, 68849, 68805, 68826, 68836, 68837, 68804, + 68841, 68806, 68813, 68814, 68822, 68823, 68838, 68840, 68847, 68848, + 68802, 68807, 68811, 68812, 68815, 68818, 68819, 68832, 68834, 68846, + 68829, 68844, 68830, 68845, 68827, 68831, 68828, 68835, 68842, 68821, + 68850, 68843, 68810, 68816, 68817, 68861, 68859, 68858, 68862, 68863, + 68860, 66308, 66324, 66318, 66335, 66323, 66331, 66327, 66330, 66315, + 66316, 66317, 66329, 66314, 66306, 66322, 66351, 66321, 66350, 66326, + 66334, 66313, 66333, 66328, 66320, 66312, 66325, 66332, 66305, 66307, + 66311, 66309, 66349, 66310, 66304, 66319, 66339, 66337, 66338, 66336, + 68241, 68242, 68246, 68244, 68226, 68224, 68237, 68235, 68249, 68251, + 68247, 68233, 68248, 68252, 68227, 68234, 68230, 68239, 68232, 68240, + 68231, 68250, 68236, 68225, 68243, 68245, 68228, 68229, 68238, 68255, + 68254, 68253, 66404, 66390, 66392, 66387, 66388, 66411, 66393, 66421, + 66418, 66396, 66397, 66399, 66406, 66405, 66401, 66413, 66402, 66398, + 66414, 66415, 66416, 66408, 66420, 66417, 66407, 66419, 66389, 66391, + 66395, 66400, 66386, 66409, 66410, 66385, 66384, 66394, 66412, 66403, + 66516, 66514, 66515, 66517, 66513, 66464, 66504, 66505, 66506, 66482, + 66510, 66511, 66477, 66508, 66509, 66478, 66479, 66473, 66474, 66490, + 66491, 66480, 66475, 66476, 66507, 66471, 66469, 66470, 66467, 66468, + 66484, 66485, 66492, 66493, 66486, 66487, 66488, 66497, 66498, 66495, + 66472, 66483, 66499, 66494, 66481, 66489, 66496, 66465, 66466, 66512, + 128435, 118450, 69414, 69395, 69376, 69394, 69391, 69392, 69398, 69399, + 69403, 69404, 69377, 69379, 69382, 69400, 69388, 69380, 69384, 69393, + 69397, 69401, 69386, 69381, 69385, 69387, 69378, 69390, 69402, 69383, + 69396, 69389, 69415, 69407, 69412, 69411, 69406, 69410, 69405, 69413, + 69409, 69408, 68209, 68210, 68217, 68211, 68213, 68214, 68212, 68203, + 68205, 68207, 68206, 68202, 68198, 68220, 68219, 68215, 68201, 68216, + 68193, 68196, 68199, 68218, 68192, 68194, 68200, 68204, 68197, 68208, + 68195, 68222, 68221, 68223, 68608, 68619, 68627, 68623, 68634, 68640, + 68644, 68668, 68670, 68677, 68632, 68669, 68671, 68617, 68625, 68621, + 68638, 68643, 68660, 68666, 68675, 68630, 68648, 68653, 68646, 68650, + 68641, 68673, 68658, 68642, 68655, 68628, 68611, 68657, 68662, 68614, + 68615, 68636, 68656, 68664, 68679, 68680, 68609, 68610, 68645, 68654, + 68620, 68624, 68635, 68678, 68633, 68672, 68652, 68618, 68626, 68622, + 68639, 68661, 68667, 68676, 68631, 68613, 68649, 68647, 68651, 68674, + 68659, 68629, 68612, 68663, 68616, 68637, 68665, 69509, 69508, 69507, + 69506, 69488, 69502, 69496, 69505, 69492, 69499, 69501, 69503, 69494, + 69493, 69490, 69495, 69489, 69498, 69504, 69491, 69500, 69497, 69511, + 69512, 69513, 69510, 128477, 128117, 129491, 128116, 129746, 128283, + 128664, 128753, 128662, 128660, 128653, 11819, 8228, 128431, 129649, + 129477, 128214, 9251, 10044, 10027, 10034, 10011, 128194, 128449, 128080, + 128237, 128236, 10180, 10179, 128275, 9103, 9104, 10174, 983191, 8997, + 128191, 128440, 9934, 9741, 128217, 129505, 129447, 128895, 129741, 8886, + 2902, 2903, 2933, 2934, 2931, 2930, 2935, 2932, 2928, 2909, 2908, 2864, + 2911, 2863, 2821, 2822, 2832, 2836, 2850, 2849, 2855, 2854, 2848, 2847, + 2853, 2852, 2827, 2912, 2828, 2913, 2869, 2825, 2826, 2823, 2824, 2867, + 2866, 2841, 2851, 2846, 2856, 2870, 2871, 2872, 2861, 2860, 2843, 2842, + 2840, 2839, 2845, 2844, 2838, 2837, 2859, 2858, 2873, 2862, 2929, 2831, + 2835, 983660, 983659, 2817, 2876, 2877, 2818, 2901, 2893, 2819, 2878, + 2888, 2892, 2881, 2882, 2883, 2884, 2914, 2915, 2879, 2880, 2887, 2891, + 2923, 2922, 2925, 2924, 2921, 2920, 2918, 2927, 2919, 2926, 64830, 64831, + 9766, 117826, 10183, 66736, 66737, 66738, 66739, 66743, 66763, 66761, 66742, 66749, 66757, 66744, 66768, 66750, 66748, 66754, 66755, 66764, 66762, 66760, 66746, 66745, 66741, 66765, 66769, 66759, 66758, 66771, 66770, 66740, 66751, 66752, 66753, 66756, 66767, 66747, 66766, 66776, @@ -12256,119 +12379,120 @@ static const unsigned int dawg_pos_to_codepoint[] = { 117986, 117987, 117988, 117989, 117990, 117991, 117992, 117993, 117994, 117995, 117996, 117997, 117998, 117999, 10015, 9885, 10029, 10009, 118005, 118004, 118007, 118006, 118003, 118002, 118000, 118009, 118001, - 118008, 8485, 129397, 128471, 11195, 11194, 11196, 8254, 129450, 8486, - 128076, 127842, 128329, 129417, 128002, 983122, 983121, 128463, 128195, - 128479, 128196, 128223, 128464, 128724, 93059, 93065, 93064, 93058, - 93070, 93056, 93055, 93053, 93062, 93069, 93061, 93066, 93071, 93068, - 93054, 93057, 93063, 93067, 93060, 92967, 92975, 92965, 92969, 92959, - 92968, 92971, 92957, 92962, 92960, 92972, 92970, 92963, 92958, 92966, - 92961, 92956, 92974, 92964, 92973, 92979, 92978, 92980, 92977, 92976, - 92982, 92981, 93023, 93020, 93024, 93021, 93019, 93025, 93022, 93043, - 92985, 93047, 93044, 93045, 92997, 93046, 93042, 93032, 93029, 92995, - 93038, 92993, 93041, 93035, 93033, 93037, 93030, 93039, 92987, 92992, - 92986, 92983, 92984, 93027, 92994, 93034, 92988, 92990, 92989, 92991, - 93028, 92996, 93031, 93040, 93036, 92954, 92955, 92938, 92939, 92932, - 92933, 92942, 92943, 92950, 92951, 92928, 92929, 92936, 92937, 92948, - 92949, 92930, 92931, 92944, 92945, 92934, 92935, 92940, 92941, 92946, - 92947, 92952, 92953, 93013, 93012, 93015, 93014, 93011, 93010, 93008, - 93017, 93009, 93016, 9908, 11801, 127796, 129779, 129780, 67703, 67693, - 67688, 67702, 67683, 67691, 67699, 67700, 67680, 67696, 67682, 67686, - 67695, 67698, 67701, 67689, 67684, 67687, 67690, 67681, 67694, 67685, - 67697, 67692, 67704, 67711, 67706, 67707, 67710, 67709, 67708, 67705, - 129330, 129374, 128060, 8233, 11853, 11791, 10995, 10994, 8741, 129666, - 12809, 12823, 12808, 12822, 12828, 12813, 12827, 12810, 12824, 12800, - 12814, 12804, 12818, 12801, 12815, 12812, 12826, 12805, 12819, 12803, - 12817, 12806, 12820, 12811, 12825, 12802, 12816, 12807, 12821, 12863, - 12855, 12858, 12861, 12847, 12839, 12854, 12843, 12836, 12864, 12835, - 12856, 12846, 12842, 12840, 12852, 12862, 12865, 12857, 12867, 12838, - 12866, 12851, 12853, 12859, 12849, 12860, 12848, 12837, 12834, 12841, - 12833, 12845, 12844, 12850, 12832, 12830, 12829, 9349, 9342, 9345, 9346, - 9350, 9347, 9348, 9344, 9351, 9343, 9341, 9336, 9335, 9338, 9337, 9334, - 9333, 9340, 9332, 9339, 127248, 127249, 127250, 127251, 127252, 127253, - 127254, 127255, 127256, 127257, 127258, 127259, 127260, 127261, 127262, - 127263, 127264, 127265, 127266, 127267, 127268, 127269, 127270, 127271, - 127272, 127273, 9372, 9373, 9374, 9375, 9376, 9377, 9378, 9379, 9380, - 9381, 9382, 9383, 9384, 9385, 9386, 9387, 9388, 9389, 9390, 9391, 9392, - 9393, 9394, 9395, 9396, 9397, 8706, 983147, 983146, 983149, 983150, 9853, - 127881, 12880, 12349, 129436, 128755, 11261, 9105, 9106, 128706, 72437, - 72440, 72432, 72416, 72419, 72413, 72417, 72415, 72412, 72414, 72418, - 72420, 72403, 72407, 72411, 72409, 72410, 72391, 72400, 72404, 72397, - 72394, 72385, 72401, 72384, 72399, 72398, 72396, 72388, 72393, 72392, - 72386, 72387, 72402, 72395, 72390, 72389, 72405, 72406, 72408, 72436, - 72435, 72438, 72439, 72422, 72421, 72424, 72425, 72431, 72433, 72434, - 72428, 72427, 72429, 72430, 72423, 72426, 128062, 128230, 128206, 983228, - 983237, 129434, 9774, 127825, 129372, 129755, 127824, 128039, 128532, - 9956, 128390, 9999, 8240, 8241, 8524, 10178, 10977, 129336, 129496, - 129494, 128113, 9977, 128590, 129733, 128591, 129493, 128589, 128588, - 129495, 128583, 128187, 8966, 128547, 37, 9854, 127917, 8359, 8369, - 129515, 128694, 129730, 43101, 43117, 43120, 43076, 43123, 43077, 43115, - 43090, 43082, 43094, 43098, 43099, 43119, 43118, 43109, 43074, 43075, - 43116, 43079, 43083, 43089, 43088, 43114, 43113, 43081, 43080, 43073, - 43072, 43085, 43084, 43092, 43093, 43104, 43110, 43086, 43108, 43100, - 43078, 43097, 43087, 43106, 43096, 43091, 43107, 43095, 43102, 43105, - 43103, 43127, 43126, 43124, 43121, 43111, 43112, 43122, 43125, 66033, - 66023, 66017, 66010, 66027, 66003, 66018, 66028, 66004, 66012, 66022, - 66020, 66045, 66019, 66031, 66041, 66007, 66006, 66025, 66026, 66038, - 66016, 66013, 66014, 66000, 66001, 66034, 66036, 66037, 66029, 66011, - 66024, 66015, 66021, 66042, 66043, 66002, 66008, 66032, 66005, 66044, - 66040, 66039, 66030, 66009, 66035, 5941, 5942, 67840, 67855, 67843, - 67844, 67847, 67858, 67857, 67860, 67854, 67861, 67848, 67845, 67846, - 67849, 67859, 67842, 67850, 67853, 67851, 67841, 67856, 67852, 67864, - 67866, 67867, 67863, 67862, 67865, 67871, 11227, 9935, 128763, 128022, - 128061, 128055, 128169, 182, 128138, 129292, 129295, 127885, 127821, - 10031, 129655, 129669, 9811, 128299, 8916, 10970, 129383, 8984, 128720, - 129703, 8462, 8463, 127183, 127136, 127167, 127199, 127188, 127140, - 127156, 127172, 127200, 127189, 127141, 127157, 127173, 127196, 127148, - 127164, 127180, 127198, 127150, 127166, 127182, 127192, 127144, 127160, - 127176, 127191, 127143, 127159, 127175, 127190, 127142, 127158, 127174, - 127197, 127149, 127165, 127181, 127194, 127146, 127162, 127178, 127187, - 127139, 127155, 127171, 127186, 127138, 127154, 127170, 127202, 127220, - 127221, 127201, 127210, 127211, 127212, 127213, 127214, 127215, 127216, - 127217, 127218, 127219, 127203, 127204, 127205, 127206, 127207, 127208, - 127209, 127185, 127137, 127153, 127169, 127193, 127145, 127161, 127177, - 127195, 127147, 127163, 127179, 128733, 983151, 43, 10797, 10798, 10809, - 10789, 10786, 10791, 10790, 10788, 10792, 10787, 10866, 177, 9799, 11222, - 11221, 11220, 11219, 129696, 983148, 117777, 128659, 128680, 128110, - 8297, 8236, 127871, 128254, 11239, 128239, 12306, 12320, 128238, 8982, - 128688, 129364, 127858, 129716, 127831, 129751, 128574, 128545, 163, - 128093, 9212, 9213, 9214, 9211, 128041, 128425, 129328, 129732, 129731, - 65043, 65040, 65045, 65073, 65074, 65049, 65041, 65042, 65091, 65047, - 65083, 65085, 65089, 65079, 65087, 65077, 65095, 65081, 65075, 65084, - 65086, 65092, 983261, 65048, 65090, 65080, 65088, 65078, 65096, 65082, - 65076, 65044, 65072, 65046, 8478, 8826, 10937, 10933, 10927, 10929, - 10935, 10931, 8936, 8830, 8828, 8880, 9111, 129384, 9113, 128424, 128438, - 129332, 128120, 983193, 983166, 983163, 983164, 983167, 8242, 8965, 8759, - 8733, 8522, 128711, 129455, 11224, 128255, 68507, 68508, 68480, 68483, - 68490, 68491, 68485, 68482, 68486, 68493, 68495, 68496, 68488, 68484, - 68487, 68489, 68481, 68492, 68497, 68494, 68526, 68522, 68523, 68525, - 68521, 68527, 68524, 68505, 68506, 11854, 8200, 128156, 128091, 128686, - 128204, 128226, 983165, 983168, 983194, 9624, 9625, 9626, 9627, 9628, - 9629, 9630, 9631, 9622, 9623, 10764, 8279, 10774, 9833, 128894, 8264, 63, - 8799, 34, 9915, 127949, 127950, 129437, 128251, 9762, 128280, 9143, - 128740, 128643, 9926, 127752, 11827, 11783, 11782, 9995, 128400, 128406, - 127338, 127339, 127340, 129996, 11787, 9994, 11828, 129306, 128000, 8758, - 128007, 128048, 129682, 128015, 129534, 117778, 9852, 9843, 9844, 9845, - 9846, 9847, 9848, 9849, 9850, 983113, 128665, 127822, 129511, 174, - 127462, 127463, 127464, 127465, 127466, 127467, 127468, 127469, 127470, - 127471, 127472, 127473, 127474, 127475, 127476, 127477, 127478, 127479, - 127480, 127481, 127482, 127483, 127484, 127485, 127486, 127487, 43344, - 43343, 43346, 43345, 43333, 43323, 43331, 43314, 43332, 43317, 43330, - 43320, 43319, 43321, 43316, 43313, 43329, 43322, 43312, 43326, 43318, - 43325, 43324, 43315, 43328, 43327, 43334, 43359, 43337, 43342, 43341, - 43338, 43340, 43335, 43339, 43336, 43347, 128524, 127895, 65533, 9952, - 9953, 128699, 8479, 9166, 11152, 11153, 128639, 128968, 983152, 92, - 10184, 10741, 10743, 11073, 11079, 983153, 10659, 10661, 8246, 12317, - 10989, 8976, 11793, 8267, 8245, 128401, 9753, 11262, 8515, 8271, 8765, - 8909, 8247, 128402, 128403, 128405, 11841, 11822, 128404, 10672, 128158, - 8251, 129423, 983154, 127872, 11190, 11188, 11191, 11189, 11186, 11187, - 11184, 11185, 127832, 127833, 129919, 129918, 128495, 8735, 12297, 10642, - 11777, 11776, 9084, 8894, 10652, 10644, 10228, 8692, 12305, 10648, 125, - 9132, 9133, 9131, 12301, 8969, 11781, 12299, 10608, 10715, 8221, 11817, - 129929, 10621, 8971, 118272, 9687, 11241, 9616, 129978, 117925, 118289, - 129971, 118286, 118284, 118432, 118443, 129933, 128381, 130025, 130017, - 11805, 8906, 10198, 129927, 9621, 129980, 41, 9120, 9118, 9119, 11789, - 10182, 8908, 129931, 8217, 11815, 128360, 128361, 128362, 128489, 93, - 9126, 9124, 10638, 10640, 8262, 10636, 11864, 11862, 9125, 11779, 117773, + 118008, 8485, 129397, 128471, 11195, 11194, 11196, 8254, 129450, 127970, + 118459, 8486, 128076, 127842, 128329, 129417, 128002, 983122, 983121, + 128463, 128195, 128479, 128196, 128223, 128464, 128724, 93059, 93065, + 93064, 93058, 93070, 93056, 93055, 93053, 93062, 93069, 93061, 93066, + 93071, 93068, 93054, 93057, 93063, 93067, 93060, 92967, 92975, 92965, + 92969, 92959, 92968, 92971, 92957, 92962, 92960, 92972, 92970, 92963, + 92958, 92966, 92961, 92956, 92974, 92964, 92973, 92979, 92978, 92980, + 92977, 92976, 92982, 92981, 93023, 93020, 93024, 93021, 93019, 93025, + 93022, 93043, 92985, 93047, 93044, 93045, 92997, 93046, 93042, 93032, + 93029, 92995, 93038, 92993, 93041, 93035, 93033, 93037, 93030, 93039, + 92987, 92992, 92986, 92983, 92984, 93027, 92994, 93034, 92988, 92990, + 92989, 92991, 93028, 92996, 93031, 93040, 93036, 92954, 92955, 92938, + 92939, 92932, 92933, 92942, 92943, 92950, 92951, 92928, 92929, 92936, + 92937, 92948, 92949, 92930, 92931, 92944, 92945, 92934, 92935, 92940, + 92941, 92946, 92947, 92952, 92953, 93013, 93012, 93015, 93014, 93011, + 93010, 93008, 93017, 93009, 93016, 9908, 11801, 127796, 129779, 129780, + 67703, 67693, 67688, 67702, 67683, 67691, 67699, 67700, 67680, 67696, + 67682, 67686, 67695, 67698, 67701, 67689, 67684, 67687, 67690, 67681, + 67694, 67685, 67697, 67692, 67704, 67711, 67706, 67707, 67710, 67709, + 67708, 67705, 129330, 129374, 128060, 8233, 11853, 11791, 10995, 10994, + 8741, 129666, 12809, 12823, 12808, 12822, 12828, 12813, 12827, 12810, + 12824, 12800, 12814, 12804, 12818, 12801, 12815, 12812, 12826, 12805, + 12819, 12803, 12817, 12806, 12820, 12811, 12825, 12802, 12816, 12807, + 12821, 12863, 12855, 12858, 12861, 12847, 12839, 12854, 12843, 12836, + 12864, 12835, 12856, 12846, 12842, 12840, 12852, 12862, 12865, 12857, + 12867, 12838, 12866, 12851, 12853, 12859, 12849, 12860, 12848, 12837, + 12834, 12841, 12833, 12845, 12844, 12850, 12832, 12830, 12829, 9349, + 9342, 9345, 9346, 9350, 9347, 9348, 9344, 9351, 9343, 9341, 9336, 9335, + 9338, 9337, 9334, 9333, 9340, 9332, 9339, 127248, 127249, 127250, 127251, + 127252, 127253, 127254, 127255, 127256, 127257, 127258, 127259, 127260, + 127261, 127262, 127263, 127264, 127265, 127266, 127267, 127268, 127269, + 127270, 127271, 127272, 127273, 9372, 9373, 9374, 9375, 9376, 9377, 9378, + 9379, 9380, 9381, 9382, 9383, 9384, 9385, 9386, 9387, 9388, 9389, 9390, + 9391, 9392, 9393, 9394, 9395, 9396, 9397, 8706, 983147, 983146, 983149, + 983150, 9853, 127881, 118468, 128890, 12880, 12349, 129436, 128755, + 11261, 9105, 9106, 128706, 72437, 72440, 72432, 72416, 72419, 72413, + 72417, 72415, 72412, 72414, 72418, 72420, 72403, 72407, 72411, 72409, + 72410, 72391, 72400, 72404, 72397, 72394, 72385, 72401, 72384, 72399, + 72398, 72396, 72388, 72393, 72392, 72386, 72387, 72402, 72395, 72390, + 72389, 72405, 72406, 72408, 72436, 72435, 72438, 72439, 72422, 72421, + 72424, 72425, 72431, 72433, 72434, 72428, 72427, 72429, 72430, 72423, + 72426, 128062, 128230, 128206, 983228, 983237, 129434, 9774, 127825, + 129372, 129755, 127824, 128039, 128532, 9956, 128390, 9999, 8240, 8241, + 8524, 10178, 10977, 129336, 129496, 129494, 128113, 9977, 128590, 129733, + 128591, 129493, 128589, 128588, 129495, 128583, 128187, 8966, 128547, 37, + 9854, 127917, 8359, 8369, 129515, 128694, 129730, 43101, 43117, 43120, + 43076, 43123, 43077, 43115, 43090, 43082, 43094, 43098, 43099, 43119, + 43118, 43109, 43074, 43075, 43116, 43079, 43083, 43089, 43088, 43114, + 43113, 43081, 43080, 43073, 43072, 43085, 43084, 43092, 43093, 43104, + 43110, 43086, 43108, 43100, 43078, 43097, 43087, 43106, 43096, 43091, + 43107, 43095, 43102, 43105, 43103, 43127, 43126, 43124, 43121, 43111, + 43112, 43122, 43125, 66033, 66023, 66017, 66010, 66027, 66003, 66018, + 66028, 66004, 66012, 66022, 66020, 66045, 66019, 66031, 66041, 66007, + 66006, 66025, 66026, 66038, 66016, 66013, 66014, 66000, 66001, 66034, + 66036, 66037, 66029, 66011, 66024, 66015, 66021, 66042, 66043, 66002, + 66008, 66032, 66005, 66044, 66040, 66039, 66030, 66009, 66035, 5941, + 5942, 67840, 67855, 67843, 67844, 67847, 67858, 67857, 67860, 67854, + 67861, 67848, 67845, 67846, 67849, 67859, 67842, 67850, 67853, 67851, + 67841, 67856, 67852, 67864, 67866, 67867, 67863, 67862, 67865, 67871, + 11227, 9935, 128763, 128022, 128061, 128055, 128169, 182, 128138, 129292, + 129295, 127885, 127821, 10031, 129655, 129669, 9811, 128299, 8916, 10970, + 129383, 8984, 128720, 129703, 8462, 8463, 128733, 127183, 127136, 127167, + 127199, 127188, 127140, 127156, 127172, 127200, 127189, 127141, 127157, + 127173, 127196, 127148, 127164, 127180, 127198, 127150, 127166, 127182, + 127192, 127144, 127160, 127176, 127191, 127143, 127159, 127175, 127190, + 127142, 127158, 127174, 127197, 127149, 127165, 127181, 127194, 127146, + 127162, 127178, 127187, 127139, 127155, 127171, 127186, 127138, 127154, + 127170, 127202, 127220, 127221, 127201, 127210, 127211, 127212, 127213, + 127214, 127215, 127216, 127217, 127218, 127219, 127203, 127204, 127205, + 127206, 127207, 127208, 127209, 127185, 127137, 127153, 127169, 127193, + 127145, 127161, 127177, 127195, 127147, 127163, 127179, 983151, 43, + 10797, 10798, 10809, 10789, 10786, 10791, 10790, 10788, 10792, 10787, + 10866, 177, 9799, 11222, 11221, 11220, 11219, 129696, 983148, 117777, + 128659, 128680, 128110, 8297, 8236, 127871, 128254, 11239, 128239, 12306, + 12320, 128238, 8982, 128688, 129364, 127858, 129716, 127831, 129751, + 128574, 128545, 163, 128093, 9212, 9213, 9214, 9211, 128041, 128425, + 129328, 129732, 129731, 65043, 65040, 65045, 65073, 65074, 65049, 65041, + 65042, 65091, 65047, 65083, 65085, 65089, 65079, 65087, 65077, 65095, + 65081, 65075, 65084, 65086, 65092, 983261, 65048, 65090, 65080, 65088, + 65078, 65096, 65082, 65076, 65044, 65072, 65046, 8478, 8826, 10937, + 10933, 10927, 10929, 10935, 10931, 8936, 8830, 8828, 8880, 9111, 129384, + 9113, 128424, 128438, 129332, 128120, 983193, 983166, 983163, 983164, + 983167, 8242, 8965, 8759, 8733, 8522, 11224, 128711, 129455, 128255, + 68507, 68508, 68480, 68483, 68490, 68491, 68485, 68482, 68486, 68493, + 68495, 68496, 68488, 68484, 68487, 68489, 68481, 68492, 68497, 68494, + 68526, 68522, 68523, 68525, 68521, 68527, 68524, 68505, 68506, 118473, + 11854, 8200, 128156, 128091, 128686, 128204, 128226, 983165, 983168, + 983194, 9624, 9625, 9626, 9627, 9628, 9629, 9630, 9631, 9622, 9623, + 10764, 8279, 10774, 9833, 128894, 8264, 63, 8799, 34, 9915, 127949, + 127950, 129437, 128251, 9762, 128280, 9143, 128740, 128643, 9926, 127752, + 11827, 11783, 11782, 9995, 128400, 128406, 127338, 127339, 127340, + 129996, 11787, 9994, 11828, 129306, 128000, 8758, 128007, 128048, 129682, + 128015, 129534, 117778, 9852, 9843, 9844, 9845, 9846, 9847, 9848, 9849, + 9850, 983113, 128665, 127822, 129511, 174, 127462, 127463, 127464, + 127465, 127466, 127467, 127468, 127469, 127470, 127471, 127472, 127473, + 127474, 127475, 127476, 127477, 127478, 127479, 127480, 127481, 127482, + 127483, 127484, 127485, 127486, 127487, 43344, 43343, 43346, 43345, + 43333, 43323, 43331, 43314, 43332, 43317, 43330, 43320, 43319, 43321, + 43316, 43313, 43329, 43322, 43312, 43326, 43318, 43325, 43324, 43315, + 43328, 43327, 43334, 43359, 43337, 43342, 43341, 43338, 43340, 43335, + 43339, 43336, 43347, 128524, 127895, 65533, 9952, 9953, 128699, 8479, + 9166, 11152, 11153, 128639, 128968, 983152, 92, 10184, 10741, 10743, + 11073, 11079, 983153, 10659, 10661, 8246, 12317, 10989, 8976, 11793, + 8267, 8245, 128401, 9753, 11262, 8515, 8271, 8765, 8909, 8247, 128402, + 128403, 128405, 11841, 11822, 10672, 128404, 128158, 8251, 129423, + 983154, 127872, 11190, 11188, 11191, 11189, 11186, 11187, 11184, 11185, + 127832, 127833, 129919, 129918, 128495, 8735, 12297, 10642, 11777, 11776, + 9084, 8894, 10652, 10644, 10228, 8692, 12305, 10648, 125, 9132, 9133, + 9131, 12301, 8969, 11781, 12299, 10608, 10715, 8221, 11817, 129929, + 10621, 8971, 118272, 9687, 11241, 9616, 129978, 117925, 118289, 129971, + 118286, 118284, 118432, 118443, 129933, 128381, 130025, 130017, 11805, + 8906, 10198, 129927, 9621, 129980, 41, 9120, 9118, 9119, 11789, 10182, + 8908, 129931, 8217, 11815, 128360, 128361, 128362, 128489, 93, 9126, + 9124, 10638, 10640, 8262, 10636, 11864, 11862, 9125, 11779, 117773, 129987, 128493, 118433, 118442, 129930, 129928, 11786, 8895, 10702, 129902, 12309, 8866, 11809, 9145, 117766, 12303, 10628, 12311, 10630, 12315, 12313, 10713, 1421, 117833, 117907, 117909, 129308, 4053, 4055, @@ -12379,8 +12503,8 @@ static const unsigned int dawg_pos_to_codepoint[] = { 8628, 10513, 8699, 129202, 8620, 129034, 10565, 129042, 129026, 8603, 11022, 11023, 8611, 10517, 10516, 129030, 129178, 129046, 8618, 8696, 8644, 10522, 129193, 129185, 11146, 11157, 8658, 10499, 8655, 10503, - 10524, 10509, 8674, 129195, 129078, 8652, 10601, 10605, 10591, 10583, - 8641, 10600, 10604, 10596, 10587, 10579, 8640, 129777, 129090, 129094, + 10524, 10509, 8674, 129195, 129078, 10601, 10605, 10591, 10583, 8641, + 10600, 10604, 10596, 10587, 10579, 8640, 8652, 129777, 129090, 129094, 129191, 8702, 8649, 129784, 129189, 128622, 8669, 129082, 129106, 129187, 11106, 11138, 11132, 983242, 11175, 11173, 129066, 129062, 129058, 129074, 129070, 11122, 11116, 11142, 129170, 10511, 8667, 10518, 10520, @@ -12419,50 +12543,54 @@ static const unsigned int dawg_pos_to_codepoint[] = { 43149, 43186, 43178, 43180, 43179, 43205, 43136, 43204, 43137, 43215, 43214, 43221, 43220, 43223, 43222, 43219, 43218, 43216, 43225, 43217, 43224, 43188, 43189, 43200, 43203, 43192, 43193, 43194, 43195, 43196, - 43197, 43201, 43202, 43190, 43191, 43198, 43199, 129429, 9973, 127927, - 127862, 129403, 9878, 129507, 127979, 127890, 129410, 9807, 128756, - 129691, 128437, 8492, 8496, 8497, 8459, 8464, 8466, 8499, 8472, 8475, - 128624, 8495, 8458, 8467, 8500, 8456, 128220, 983186, 129453, 128186, - 167, 8980, 129352, 127793, 128584, 8979, 130037, 130036, 130039, 130038, - 130035, 130034, 130032, 130041, 130033, 130040, 10802, 9914, 59, 117793, - 117795, 117799, 117807, 117803, 117797, 117805, 117801, 117794, 117798, - 117806, 117802, 117796, 117804, 117800, 118353, 118355, 118359, 118367, - 118383, 118415, 118399, 118375, 118407, 118391, 118363, 118379, 118411, - 118395, 118371, 118403, 118387, 118357, 118365, 118381, 118413, 118397, - 118373, 118405, 118389, 118361, 118377, 118409, 118393, 118369, 118401, - 118385, 118354, 118358, 118366, 118382, 118414, 118398, 118374, 118406, - 118390, 118362, 118378, 118410, 118394, 118370, 118402, 118386, 118356, - 118364, 118380, 118412, 118396, 118372, 118404, 118388, 118360, 118376, - 118408, 118392, 118368, 118400, 118384, 11259, 8480, 129324, 9916, 65093, - 983169, 8726, 129697, 9913, 11250, 129331, 10061, 10032, 10014, 129368, - 70086, 70085, 70101, 70100, 70103, 70102, 70099, 70098, 70096, 70105, - 70097, 70104, 70092, 70106, 70108, 70019, 70020, 70030, 70032, 70046, - 70045, 70051, 70050, 70044, 70043, 70049, 70048, 70025, 70026, 70027, - 70028, 70062, 70023, 70024, 70021, 70022, 70061, 70060, 70037, 70047, - 70042, 70052, 70063, 70064, 70065, 70056, 70055, 70039, 70038, 70036, - 70035, 70041, 70040, 70034, 70033, 70054, 70053, 70066, 70057, 70059, - 70058, 70029, 70031, 70089, 70110, 70111, 70088, 70095, 70107, 70016, - 70090, 70081, 70017, 70082, 70083, 70080, 70018, 70093, 70091, 70094, - 70067, 70077, 70079, 70070, 70071, 70072, 70073, 70074, 70075, 70068, - 70069, 70076, 70078, 70087, 70109, 70084, 129416, 127847, 66684, 66680, + 43197, 43201, 43202, 43190, 43191, 43198, 43199, 129429, 8385, 9973, + 127927, 127862, 129403, 9878, 129507, 127979, 127890, 129410, 9807, + 128756, 129691, 128437, 8492, 8496, 8497, 8459, 8464, 8466, 8499, 8472, + 8475, 128624, 8495, 8458, 8467, 8500, 8456, 128220, 983186, 129453, + 128186, 167, 8980, 129352, 127793, 128584, 8979, 130037, 130036, 130039, + 130038, 130035, 130034, 130032, 130041, 130033, 130040, 10802, 9914, 59, + 117793, 117795, 117799, 117807, 117803, 117797, 117805, 117801, 117794, + 117798, 117806, 117802, 117796, 117804, 117800, 118353, 118355, 118359, + 118367, 118383, 118415, 118399, 118375, 118407, 118391, 118363, 118379, + 118411, 118395, 118371, 118403, 118387, 118357, 118365, 118381, 118413, + 118397, 118373, 118405, 118389, 118361, 118377, 118409, 118393, 118369, + 118401, 118385, 118354, 118358, 118366, 118382, 118414, 118398, 118374, + 118406, 118390, 118362, 118378, 118410, 118394, 118370, 118402, 118386, + 118356, 118364, 118380, 118412, 118396, 118372, 118404, 118388, 118360, + 118376, 118408, 118392, 118368, 118400, 118384, 11259, 8480, 129324, + 9916, 65093, 983169, 8726, 129697, 9913, 11250, 129331, 10061, 10032, + 10014, 129368, 70086, 70085, 70101, 70100, 70103, 70102, 70099, 70098, + 70096, 70105, 70097, 70104, 70092, 70106, 70108, 70019, 70020, 70030, + 70032, 70046, 70045, 70051, 70050, 70044, 70043, 70049, 70048, 70025, + 70026, 70027, 70028, 70062, 70023, 70024, 70021, 70022, 70061, 70060, + 70037, 70047, 70042, 70052, 70063, 70064, 70065, 70056, 70055, 70039, + 70038, 70036, 70035, 70041, 70040, 70034, 70033, 70054, 70053, 70066, + 70057, 70059, 70058, 70029, 70031, 70089, 70110, 70111, 70088, 70095, + 70107, 70016, 70090, 70081, 70017, 70082, 70083, 70080, 70018, 70093, + 70091, 72550, 72551, 70078, 72545, 72544, 70094, 70070, 70071, 72547, + 72546, 72548, 72549, 70067, 70077, 70079, 70072, 70073, 70074, 70075, + 70068, 70069, 70076, 70087, 70109, 70084, 129416, 127847, 66684, 66680, 66682, 66665, 66673, 66679, 66664, 66669, 66647, 66685, 66672, 66683, 66663, 66659, 66649, 66686, 66674, 66662, 66660, 66656, 66661, 66677, 66678, 66668, 66676, 66666, 66681, 66640, 66670, 66646, 66645, 66644, 66654, 66641, 66667, 66658, 66648, 66687, 66657, 66651, 66655, 66643, 66652, 66650, 66642, 66653, 66671, 66675, 9752, 129768, 128737, 983075, - 983078, 9961, 128674, 127776, 128722, 128717, 11087, 11103, 11086, 10564, - 10976, 10985, 10984, 10974, 10975, 10983, 113825, 113824, 113826, 113827, - 127856, 129651, 9085, 129327, 129679, 128703, 128017, 129424, 129335, - 10722, 983198, 983080, 71113, 71040, 71131, 71041, 71051, 71053, 71128, - 71070, 71129, 71130, 71065, 71064, 71069, 71067, 71066, 71072, 71071, - 71046, 71047, 71048, 71049, 71082, 71044, 71045, 71042, 71043, 71058, - 71068, 71063, 71073, 71083, 71084, 71085, 71077, 71076, 71060, 71059, - 71057, 71056, 71062, 71061, 71055, 71054, 71075, 71074, 71086, 71081, - 71078, 71080, 71079, 71050, 71052, 71110, 71111, 71112, 71119, 71120, - 71127, 71126, 71125, 71123, 71124, 71117, 71118, 71116, 71121, 71115, - 71114, 71122, 71109, 71108, 71105, 71100, 71104, 71101, 71103, 71102, - 71132, 71133, 71087, 71097, 71099, 71092, 71093, 71090, 71091, 71088, - 71089, 71096, 71098, 71107, 71106, 128411, 128410, 128417, 128416, + 983078, 9961, 128674, 127776, 128722, 128717, 11087, 11103, 11086, + 129237, 10974, 10564, 129235, 10976, 10985, 10984, 10975, 10983, 113825, + 113824, 113826, 113827, 127856, 129651, 9085, 129327, 129679, 128703, + 128017, 129424, 129335, 10722, 983198, 983080, 71113, 71040, 71131, + 71041, 71051, 71053, 71128, 71070, 71129, 71130, 71065, 71064, 71069, + 71067, 71066, 71072, 71071, 71046, 71047, 71048, 71049, 71082, 71044, + 71045, 71042, 71043, 71058, 71068, 71063, 71073, 71083, 71084, 71085, + 71077, 71076, 71060, 71059, 71057, 71056, 71062, 71061, 71055, 71054, + 71075, 71074, 71086, 71081, 71078, 71080, 71079, 71050, 71052, 71110, + 71111, 71112, 71119, 71120, 71127, 71126, 71125, 71123, 71124, 71117, + 71118, 71116, 71121, 71115, 71114, 71122, 71109, 71108, 71105, 71100, + 71104, 71101, 71103, 71102, 71132, 71133, 71087, 71097, 71099, 71092, + 71093, 71090, 71091, 71088, 71089, 71096, 71098, 71107, 71106, 67923, + 67924, 67925, 67926, 67927, 67928, 67929, 67904, 67905, 67906, 67907, + 67908, 67909, 67910, 67911, 67912, 67913, 67914, 67915, 67916, 67917, + 67918, 67919, 67920, 67921, 67922, 128411, 128410, 128417, 128416, 128409, 128408, 128415, 128414, 121399, 121397, 121400, 121398, 121402, 121401, 121104, 121103, 121102, 121388, 121387, 121386, 121482, 121479, 121358, 121359, 121357, 121360, 121341, 121335, 121339, 121340, 121336, @@ -12519,18 +12647,18 @@ static const unsigned int dawg_pos_to_codepoint[] = { 121197, 121195, 121216, 121215, 121214, 121213, 121212, 121211, 121449, 121125, 121126, 121121, 121122, 121123, 121124, 121127, 121318, 121316, 121317, 121315, 121156, 121155, 121154, 121146, 121145, 121144, 121150, - 121149, 121148, 121147, 121230, 121231, 121229, 121228, 121261, 121254, + 121149, 121148, 121147, 121230, 121231, 121229, 121228, 121254, 121261, 121247, 121233, 121232, 121226, 121227, 121225, 121224, 121249, 121248, 121153, 121152, 121151, 121139, 121135, 121137, 121138, 121136, 121330, - 121329, 121128, 121236, 121262, 121255, 121235, 121234, 121237, 121240, - 121239, 121263, 121256, 121238, 121162, 121161, 121160, 121132, 121133, + 121329, 121128, 121236, 121255, 121262, 121235, 121234, 121237, 121240, + 121239, 121256, 121263, 121238, 121162, 121161, 121160, 121132, 121133, 121131, 121130, 121134, 121253, 121142, 121143, 121141, 121140, 121243, - 121242, 121241, 121246, 121245, 121244, 121270, 121269, 121268, 121264, - 121257, 121326, 121325, 121159, 121158, 121157, 121448, 121394, 121393, + 121242, 121241, 121246, 121245, 121244, 121270, 121269, 121268, 121257, + 121264, 121326, 121325, 121159, 121158, 121157, 121448, 121394, 121393, 121395, 121396, 121450, 121513, 121514, 121515, 121516, 121517, 121518, 121519, 121505, 121506, 121507, 121508, 121509, 121510, 121511, 121512, 121312, 121284, 121299, 121311, 121283, 121298, 121313, 121285, 121300, - 121267, 121260, 121252, 121251, 121266, 121259, 121250, 121265, 121258, + 121260, 121267, 121252, 121251, 121259, 121266, 121250, 121258, 121265, 121107, 121106, 121105, 121454, 121453, 121457, 121120, 121112, 121110, 121114, 121113, 121111, 121108, 121109, 121101, 121100, 121099, 121481, 121441, 121445, 121446, 121443, 121444, 121442, 121447, 121390, 121389, @@ -12560,326 +12688,346 @@ static const unsigned int dawg_pos_to_codepoint[] = { 65128, 65108, 68411, 732, 118266, 10849, 65125, 65123, 65130, 65122, 65119, 65106, 65110, 10922, 10924, 10803, 128571, 128570, 128525, 128520, 128519, 128515, 128517, 128516, 128518, 128522, 129325, 129392, 128526, - 129394, 8995, 128527, 128684, 128012, 128013, 129319, 127956, 9731, 9924, - 127938, 10052, 983077, 9917, 129510, 173, 127846, 128428, 9108, 129358, - 69453, 69452, 69454, 69456, 69447, 69449, 69446, 69448, 69455, 69451, - 69450, 69445, 69424, 69437, 69426, 69433, 69444, 69440, 69429, 69436, - 69439, 69441, 69431, 69427, 69430, 69432, 69425, 69443, 69435, 69442, - 69428, 69438, 69434, 69457, 69460, 69459, 69458, 69463, 69465, 69461, - 69462, 69464, 128618, 128619, 47, 10742, 128284, 69859, 69863, 69864, - 69846, 69847, 69857, 69849, 69842, 69843, 69844, 69845, 69854, 69856, - 69855, 69848, 69851, 69853, 69840, 69841, 69850, 69852, 69858, 69860, - 69862, 69861, 69877, 69876, 69879, 69878, 69875, 69874, 69872, 69881, - 69873, 69880, 8600, 10537, 10541, 8690, 10533, 129210, 128603, 128595, - 128611, 11112, 11128, 11018, 8664, 129110, 11010, 8601, 10538, 10534, - 129211, 128601, 128593, 128609, 11113, 11129, 11019, 8665, 129111, 11011, - 8471, 72328, 72329, 72327, 72326, 72340, 72339, 72334, 72332, 72341, - 72335, 72333, 72330, 72331, 72338, 72336, 72337, 72352, 72351, 72350, - 72297, 72296, 72302, 72311, 72301, 72323, 72285, 72284, 72288, 72298, - 72293, 72303, 72319, 72320, 72321, 72310, 72309, 72295, 72294, 72300, - 72299, 72307, 72306, 72290, 72289, 72287, 72286, 72292, 72291, 72305, - 72304, 72312, 72313, 72314, 72322, 72317, 72308, 72316, 72318, 72315, - 72272, 72349, 72348, 72347, 72346, 72324, 72343, 72325, 72342, 72345, - 72353, 72354, 72282, 72281, 72279, 72280, 72277, 72278, 72275, 72274, - 72276, 72273, 72283, 72344, 8384, 983043, 983182, 983118, 983177, 127837, - 128150, 10055, 10024, 117824, 117825, 32, 128586, 128264, 128263, 128265, - 128266, 128483, 128676, 128172, 8375, 117830, 117831, 8738, 10656, 10657, - 128375, 128376, 128467, 128466, 128026, 128166, 129759, 129525, 129348, - 128051, 127941, 129533, 13279, 117900, 13056, 13058, 13057, 13059, 13250, - 13171, 13278, 13101, 13172, 13108, 13105, 13118, 13116, 13251, 13192, - 8851, 13255, 13183, 13213, 13220, 13216, 13254, 8852, 13252, 13253, - 13170, 13092, 13175, 13177, 13176, 13093, 13094, 13256, 127376, 13207, - 13064, 13179, 13181, 13182, 13055, 13180, 13005, 13063, 13006, 117899, - 117898, 117897, 9974, 9165, 13209, 13070, 13071, 13311, 13075, 13073, - 13072, 13080, 13081, 13203, 13228, 13191, 13257, 13258, 13098, 13110, - 13113, 13121, 13122, 13119, 13107, 13106, 13109, 13259, 13169, 127488, - 13004, 13200, 13260, 13060, 13061, 8847, 8932, 8849, 13178, 13188, 13069, - 13068, 13067, 13074, 13076, 13078, 13079, 13077, 13214, 13262, 13222, - 13218, 13086, 13085, 13082, 13083, 13084, 13201, 13193, 13248, 13226, - 13189, 13199, 13261, 13208, 13263, 13240, 13246, 8977, 13266, 10957, - 13264, 13265, 13267, 13223, 13224, 13249, 13221, 13217, 13187, 13123, - 13124, 13127, 13126, 13125, 13190, 13268, 13131, 13132, 13133, 13128, - 13129, 13130, 13269, 13212, 13219, 13215, 13186, 13196, 13197, 13205, - 13211, 13234, 13238, 13244, 13239, 13241, 13245, 13247, 13202, 13270, - 13227, 13198, 13206, 13235, 13185, 13096, 13097, 13195, 13210, 13233, - 13237, 13243, 13065, 8848, 8933, 8850, 13066, 13173, 13225, 13099, 13100, - 13184, 13115, 13112, 13114, 13111, 13103, 13104, 13102, 13117, 13120, - 11216, 13273, 13174, 13194, 13271, 13272, 13274, 13232, 13236, 13242, - 13229, 13230, 13231, 13142, 13141, 10958, 13137, 13138, 13140, 13139, - 8730, 13087, 13088, 13090, 13091, 117887, 117886, 117884, 117885, 13089, - 13275, 13276, 128918, 13204, 13095, 13143, 11027, 9641, 9638, 9636, - 11029, 9706, 9703, 11026, 9705, 9639, 11028, 9640, 9637, 9704, 10720, - 13277, 13135, 13134, 13136, 13062, 127529, 127530, 127512, 127508, - 127533, 127545, 127520, 127516, 127534, 127506, 127540, 127525, 127546, - 127532, 127511, 127509, 127524, 127505, 127517, 127518, 127527, 127537, - 127504, 127528, 127535, 127519, 127515, 127513, 127543, 127542, 127526, - 127541, 127544, 127522, 127538, 127514, 127521, 127539, 127510, 127536, - 127523, 127547, 127531, 127378, 127377, 8865, 10693, 11820, 127390, - 127392, 127379, 10692, 127400, 127399, 127398, 127306, 127489, 127507, - 127490, 9919, 127397, 127280, 127281, 127282, 127283, 127284, 127285, - 127286, 127287, 127288, 127289, 127290, 127291, 127292, 127293, 127294, - 127295, 127296, 127297, 127298, 127299, 127300, 127301, 127302, 127303, - 127304, 127305, 10190, 10191, 127401, 8863, 127307, 127381, 127382, - 127396, 127383, 127310, 8862, 127388, 127393, 127402, 127395, 9949, - 10695, 10696, 127384, 127308, 127309, 127387, 127394, 127389, 8864, - 127391, 127385, 127403, 127404, 127386, 10694, 127311, 127380, 10151, - 129425, 983157, 983160, 983134, 983190, 9877, 9882, 128387, 8795, 10017, - 8902, 9770, 11242, 11243, 983175, 983133, 983181, 983176, 983042, 983044, - 128509, 128649, 129485, 127967, 128642, 127836, 11836, 129658, 129989, - 129990, 129993, 129991, 129992, 128480, 9201, 128207, 9188, 127827, - 10025, 983189, 117891, 117888, 117890, 117889, 8803, 127897, 129369, - 128723, 983170, 983045, 983103, 8333, 8332, 8328, 8330, 8334, 8331, 8325, - 8324, 8327, 8326, 8323, 8322, 8320, 8329, 8321, 10963, 10965, 10617, - 8834, 10953, 10949, 10951, 10955, 8842, 8838, 10947, 10943, 10945, 10941, - 983102, 8827, 10938, 10934, 10928, 10930, 10936, 10932, 8937, 8831, 8829, - 8881, 9139, 10763, 9138, 9737, 127774, 9925, 7098, 7073, 7074, 7075, - 7084, 7085, 7043, 983220, 7046, 7102, 7103, 7062, 7100, 7068, 7099, 7067, - 7087, 7070, 7048, 7049, 7053, 7057, 7060, 7101, 7064, 7086, 7050, 7054, - 7059, 7052, 7072, 7055, 7065, 7061, 7051, 7058, 7063, 7069, 7071, 7066, - 7056, 7044, 7047, 7045, 7367, 7366, 7365, 7364, 7363, 7361, 7362, 7360, - 7082, 7041, 7042, 7040, 7083, 7080, 7081, 7079, 7077, 7076, 7078, 7093, - 7092, 7095, 7094, 7091, 7090, 7088, 7097, 7089, 7096, 127749, 127748, - 72648, 72662, 72661, 72669, 72652, 72640, 72663, 72651, 72655, 72672, - 72646, 72667, 72666, 72653, 72657, 72645, 72665, 72649, 72644, 72658, - 72668, 72670, 72664, 72671, 72641, 72659, 72650, 72656, 72643, 72660, - 72654, 72642, 72647, 72673, 72693, 72692, 72695, 72694, 72691, 72690, - 72688, 72697, 72689, 72696, 127751, 127803, 8316, 8312, 8305, 8319, 8317, - 8314, 8318, 8315, 8309, 8308, 8311, 8310, 179, 178, 8304, 8313, 185, - 10966, 10964, 10619, 10968, 10967, 8835, 10954, 10950, 10952, 10956, - 8843, 8839, 10948, 10944, 10946, 10942, 10185, 129464, 129465, 8751, - 127940, 128671, 127843, 128629, 129442, 127946, 8275, 43027, 43026, - 43031, 43030, 43040, 43038, 43025, 43024, 43029, 43028, 43036, 43035, - 43021, 43020, 43018, 43017, 43023, 43022, 43016, 43015, 43034, 43033, - 43042, 43039, 43037, 43032, 43041, 43008, 43012, 43009, 43013, 43011, - 43048, 43049, 43050, 43051, 43052, 43019, 43014, 43010, 43047, 43043, - 43046, 43044, 43045, 9223, 9224, 9229, 9240, 9232, 9249, 9256, 9255, - 9253, 9257, 9236, 9235, 9234, 9233, 9241, 9220, 9239, 9219, 9221, 9243, - 9244, 9228, 9225, 9227, 9226, 128325, 9237, 9252, 9216, 9222, 9246, 9245, - 9247, 8527, 9230, 9231, 9217, 9218, 9242, 9254, 9238, 9248, 11159, 9007, - 983094, 983093, 128333, 1807, 1866, 1802, 1798, 1799, 1849, 1848, 1792, - 1854, 1853, 1805, 1804, 1803, 1852, 1851, 1850, 1797, 1814, 1813, 1815, - 1818, 1824, 2153, 2152, 2149, 2148, 2144, 2146, 2150, 2147, 2154, 2145, - 2151, 1825, 1830, 1837, 1839, 1838, 1831, 1834, 1827, 1869, 1870, 1871, - 1809, 1835, 1832, 1828, 1808, 1823, 1833, 1819, 1820, 1836, 1811, 1812, - 1821, 1822, 1810, 1817, 1826, 1816, 1829, 1864, 1863, 1842, 1841, 1840, - 1845, 1844, 1843, 1847, 1846, 1855, 1858, 1796, 983204, 1801, 1794, 1795, - 1800, 1793, 1862, 1861, 1860, 1859, 1865, 1856, 1857, 128137, 983184, - 128085, 129430, 983061, 127955, 917543, 917542, 917546, 917598, 917568, - 917548, 917562, 917540, 917557, 917556, 917559, 917558, 917555, 917554, - 917552, 917561, 917553, 917560, 917565, 917537, 917600, 917566, 917549, - 917569, 917570, 917571, 917572, 917573, 917574, 917575, 917576, 917577, - 917578, 917579, 917580, 917581, 917582, 917583, 917584, 917585, 917586, - 917587, 917588, 917589, 917590, 917591, 917592, 917593, 917594, 917601, - 917602, 917603, 917604, 917605, 917606, 917607, 917608, 917609, 917610, - 917611, 917612, 917613, 917614, 917615, 917616, 917617, 917618, 917619, - 917620, 917621, 917622, 917623, 917624, 917625, 917626, 917564, 917627, - 917544, 917595, 917599, 917541, 917547, 917538, 917567, 917629, 917545, - 917597, 917596, 917563, 917551, 917536, 917539, 917630, 917550, 917628, - 5888, 5919, 5893, 5896, 5898, 5895, 5892, 5905, 5891, 5902, 5899, 5897, - 5901, 5904, 5894, 5903, 5900, 5889, 5890, 5909, 5908, 5906, 5907, 5989, - 5992, 5994, 5991, 5988, 5987, 5998, 5995, 5993, 6000, 5990, 5999, 5996, - 5984, 5985, 5986, 6002, 6003, 6499, 6508, 6509, 6507, 6501, 6502, 6512, - 6513, 6514, 6515, 6516, 6497, 6483, 6487, 6486, 6482, 6498, 6505, 6504, - 6496, 6480, 6490, 6489, 6503, 6506, 6492, 6494, 6488, 6491, 6495, 6484, - 6493, 6481, 6485, 6500, 6745, 6746, 6743, 6747, 6742, 6741, 6748, 6749, - 6750, 6783, 6789, 6788, 6791, 6790, 6787, 6786, 6784, 6793, 6785, 6792, - 6805, 6804, 6807, 6806, 6803, 6802, 6800, 6809, 6801, 6808, 6740, 6689, - 6690, 6688, 6702, 6726, 6727, 6728, 6696, 6695, 6713, 6712, 6707, 6706, - 6714, 6729, 6720, 6693, 6692, 6691, 6704, 6699, 6697, 6717, 6715, 6709, - 6708, 6716, 6732, 6698, 6719, 6723, 6739, 6724, 6730, 6721, 6705, 6701, - 6722, 6735, 6736, 6733, 6734, 6694, 6700, 6710, 6738, 6737, 6711, 6703, - 6718, 6725, 6731, 6828, 6820, 6775, 6776, 6777, 6780, 6824, 6825, 6819, - 6772, 6744, 6823, 6779, 6778, 6822, 6826, 6827, 6818, 6752, 6816, 6817, - 6821, 6773, 6774, 6829, 6753, 6755, 6767, 6769, 6754, 6763, 6764, 6771, - 6768, 6765, 6756, 6770, 6761, 6762, 6760, 6759, 6757, 6758, 6766, 43653, - 43651, 43649, 43661, 43659, 43679, 43677, 43671, 43669, 43657, 43665, - 43673, 43675, 43667, 43681, 43655, 43693, 43689, 43683, 43687, 43663, - 43691, 43685, 43695, 43652, 43650, 43648, 43660, 43658, 43678, 43676, - 43670, 43668, 43656, 43664, 43672, 43674, 43666, 43680, 43654, 43692, - 43688, 43682, 43686, 43662, 43690, 43684, 43694, 43696, 43703, 43743, - 43739, 43740, 43742, 43741, 43712, 43713, 43714, 43711, 43707, 43697, - 43710, 43709, 43708, 43700, 43699, 43705, 43706, 43698, 43704, 43701, - 43702, 71353, 71296, 71352, 71297, 71303, 71305, 71319, 71318, 71324, - 71323, 71338, 71332, 71317, 71316, 71322, 71321, 71300, 71301, 71298, - 71299, 71310, 71320, 71315, 71325, 71329, 71328, 71312, 71311, 71309, - 71308, 71314, 71313, 71307, 71306, 71327, 71326, 71335, 71336, 71337, - 71333, 71330, 71334, 71331, 71302, 71304, 71351, 71339, 71350, 71340, - 71341, 71347, 71349, 71344, 71345, 71342, 71343, 71346, 71348, 71365, - 71364, 71367, 71366, 71363, 71362, 71360, 71369, 71361, 71368, 129377, - 119672, 119671, 3064, 3031, 73707, 983662, 983685, 983674, 983677, - 983676, 983669, 983667, 983679, 983663, 983665, 983668, 983666, 983683, - 983681, 983682, 983673, 983678, 983664, 983684, 983680, 983671, 983670, - 983675, 983672, 73706, 3063, 73701, 3062, 3059, 3051, 3050, 3053, 3052, - 3049, 3048, 3046, 3055, 3047, 3054, 73700, 73666, 73676, 73668, 73679, - 73681, 73682, 73665, 73673, 73674, 73667, 73664, 73669, 73672, 73675, - 73680, 73670, 73678, 73671, 73677, 73683, 73684, 73710, 2985, 2979, 2969, - 2974, 2984, 2975, 2980, 2949, 2950, 2960, 2964, 2996, 2995, 2994, 2993, - 2992, 2953, 2954, 2962, 2963, 2951, 2952, 2998, 2999, 3000, 2958, 2959, - 2970, 3001, 2972, 2965, 2990, 2986, 2997, 2991, 73702, 3057, 3058, 3056, - 3066, 73727, 3065, 73703, 73687, 2946, 73686, 73698, 73690, 73693, 73692, - 73712, 73689, 73688, 73691, 73697, 73694, 73695, 73696, 73713, 73699, - 3021, 2947, 73685, 73708, 73711, 983939, 983940, 983947, 983950, 983943, - 983944, 983948, 983949, 983941, 983942, 983945, 983946, 983686, 983693, - 983696, 983689, 983690, 983694, 983695, 983687, 983688, 983691, 983692, - 983840, 983847, 983850, 983843, 983844, 983848, 983849, 983841, 983842, - 983845, 983846, 983851, 983858, 983861, 983854, 983855, 983859, 983860, - 983852, 983853, 983856, 983857, 983818, 983825, 983828, 983821, 983822, - 983826, 983827, 983819, 983820, 983823, 983824, 983873, 983880, 983883, - 983876, 983877, 983881, 983882, 983874, 983875, 983878, 983879, 983741, - 983748, 983751, 983744, 983745, 983749, 983750, 983742, 983743, 983746, - 983747, 983697, 983704, 983707, 983700, 983701, 983705, 983706, 983698, - 983699, 983702, 983703, 983719, 983726, 983729, 983722, 983723, 983727, - 983728, 983720, 983721, 983724, 983725, 983763, 983770, 983773, 983766, - 983767, 983771, 983772, 983764, 983765, 983768, 983769, 983862, 983869, - 983872, 983865, 983866, 983870, 983871, 983863, 983864, 983867, 983868, - 983807, 983814, 983817, 983810, 983811, 983815, 983816, 983808, 983809, - 983812, 983813, 983895, 983902, 983905, 983898, 983899, 983903, 983904, - 983951, 983896, 983897, 983900, 983901, 983906, 983913, 983916, 983909, - 983910, 983914, 983915, 983907, 983908, 983911, 983912, 983917, 983924, - 983927, 983920, 983921, 983925, 983926, 983918, 983919, 983922, 983923, - 983730, 983737, 983740, 983733, 983734, 983738, 983739, 983731, 983732, - 983735, 983736, 983752, 983759, 983762, 983755, 983756, 983760, 983761, - 983753, 983754, 983757, 983758, 983708, 983715, 983718, 983711, 983712, - 983716, 983717, 983709, 983710, 983713, 983714, 983928, 983935, 983938, - 983931, 983932, 983936, 983937, 983929, 983930, 983933, 983934, 983884, - 983891, 983894, 983887, 983888, 983892, 983893, 983885, 983886, 983889, - 983890, 983785, 983792, 983795, 983788, 983789, 983793, 983794, 983786, - 983787, 983790, 983791, 983774, 983781, 983784, 983777, 983778, 983782, - 983783, 983775, 983776, 983779, 983780, 983829, 983836, 983839, 983832, - 983833, 983837, 983838, 983830, 983831, 983834, 983835, 983796, 983803, - 983806, 983799, 983800, 983804, 983805, 983797, 983798, 983801, 983802, - 73709, 73704, 73705, 3006, 3016, 3020, 3009, 3010, 3018, 3019, 3007, - 3008, 3014, 3015, 3061, 3060, 3024, 129748, 127883, 127818, 92809, 92810, - 92811, 92808, 92789, 92790, 92791, 92788, 92816, 92859, 92856, 92847, - 92845, 92817, 92846, 92843, 92829, 92830, 92831, 92828, 92835, 92851, - 92840, 92844, 92818, 92819, 92852, 92836, 92825, 92826, 92827, 92824, - 92813, 92814, 92815, 92812, 92820, 92822, 92823, 92821, 92805, 92806, - 92807, 92804, 92797, 92798, 92799, 92796, 92801, 92802, 92803, 92800, - 92785, 92786, 92787, 92784, 92793, 92794, 92795, 92792, 92857, 92854, - 92848, 92861, 92853, 92860, 92849, 92855, 92834, 92833, 92832, 92841, - 92839, 92842, 92850, 92838, 92858, 92837, 92862, 92869, 92868, 92871, - 92870, 92867, 92866, 92864, 92873, 92865, 92872, 100352, 100353, 100354, - 100355, 100356, 100357, 100358, 100359, 100360, 100361, 100362, 100363, - 100364, 100365, 100366, 100367, 100368, 100369, 100370, 100371, 100372, - 100373, 100374, 100375, 100376, 100377, 100378, 100379, 100380, 100381, - 100382, 100383, 100384, 100385, 100386, 100387, 100388, 100389, 100390, - 100391, 100392, 100393, 100394, 100395, 100396, 100397, 100398, 100399, - 100400, 100401, 100402, 100403, 100404, 100405, 100406, 100407, 100408, - 100409, 100410, 100411, 100412, 100413, 100414, 100415, 100416, 100417, - 100418, 100419, 100420, 100421, 100422, 100423, 100424, 100425, 100426, - 100427, 100428, 100429, 100430, 100431, 100432, 100433, 100434, 100435, - 100436, 100437, 100438, 100439, 100440, 100441, 100442, 100443, 100444, - 100445, 100446, 100447, 100448, 100449, 100450, 100451, 100452, 100453, - 100454, 100455, 100456, 100457, 100458, 100459, 100460, 100461, 100462, - 100463, 100464, 100465, 100466, 100467, 100468, 100469, 100470, 100471, - 100472, 100473, 100474, 100475, 100476, 100477, 100478, 100479, 100480, - 100481, 100482, 100483, 100484, 100485, 100486, 100487, 100488, 100489, - 100490, 100491, 100492, 100493, 100494, 100495, 100496, 100497, 100498, - 100499, 100500, 100501, 100502, 100503, 100504, 100505, 100506, 100507, - 100508, 100509, 100510, 100511, 100512, 100513, 100514, 100515, 100516, - 100517, 100518, 100519, 100520, 100521, 100522, 100523, 100524, 100525, - 100526, 100527, 100528, 100529, 100530, 100531, 100532, 100533, 100534, - 100535, 100536, 100537, 100538, 100539, 100540, 100541, 100542, 100543, - 100544, 100545, 100546, 100547, 100548, 100549, 100550, 100551, 100552, - 100553, 100554, 100555, 100556, 100557, 100558, 100559, 100560, 100561, - 100562, 100563, 100564, 100565, 100566, 100567, 100568, 100569, 100570, - 100571, 100572, 100573, 100574, 100575, 100576, 100577, 100578, 100579, - 100580, 100581, 100582, 100583, 100584, 100585, 100586, 100587, 100588, - 100589, 100590, 100591, 100592, 100593, 100594, 100595, 100596, 100597, - 100598, 100599, 100600, 100601, 100602, 100603, 100604, 100605, 100606, - 100607, 100608, 100609, 100610, 100611, 100612, 100613, 100614, 100615, - 100616, 100617, 100618, 100619, 100620, 100621, 100622, 100623, 100624, - 100625, 100626, 100627, 100628, 100629, 100630, 100631, 100632, 100633, - 100634, 100635, 100636, 100637, 100638, 100639, 100640, 100641, 100642, - 100643, 100644, 100645, 100646, 100647, 100648, 100649, 100650, 100651, - 100652, 100653, 100654, 100655, 100656, 100657, 100658, 100659, 100660, - 100661, 100662, 100663, 100664, 100665, 100666, 100667, 100668, 100669, - 100670, 100671, 100672, 100673, 100674, 100675, 100676, 100677, 100678, - 100679, 100680, 100681, 100682, 100683, 100684, 100685, 100686, 100687, - 100688, 100689, 100690, 100691, 100692, 100693, 100694, 100695, 100696, - 100697, 100698, 100699, 100700, 100701, 100702, 100703, 100704, 100705, - 100706, 100707, 100708, 100709, 100710, 100711, 100712, 100713, 100714, - 100715, 100716, 100717, 100718, 100719, 100720, 100721, 100722, 100723, - 100724, 100725, 100726, 100727, 100728, 100729, 100730, 100731, 100732, - 100733, 100734, 100735, 100736, 100737, 100738, 100739, 100740, 100741, - 100742, 100743, 100744, 100745, 100746, 100747, 100748, 100749, 100750, - 100751, 100752, 100753, 100754, 100755, 100756, 100757, 100758, 100759, - 100760, 100761, 100762, 100763, 100764, 100765, 100766, 100767, 100768, - 100769, 100770, 100771, 100772, 100773, 100774, 100775, 100776, 100777, - 100778, 100779, 100780, 100781, 100782, 100783, 100784, 100785, 100786, - 100787, 100788, 100789, 100790, 100791, 100792, 100793, 100794, 100795, - 100796, 100797, 100798, 100799, 100800, 100801, 100802, 100803, 100804, - 100805, 100806, 100807, 100808, 100809, 100810, 100811, 100812, 100813, - 100814, 100815, 100816, 100817, 100818, 100819, 100820, 100821, 100822, - 100823, 100824, 100825, 100826, 100827, 100828, 100829, 100830, 100831, - 100832, 100833, 100834, 100835, 100836, 100837, 100838, 100839, 100840, - 100841, 100842, 100843, 100844, 100845, 100846, 100847, 100848, 100849, - 100850, 100851, 100852, 100853, 100854, 100855, 100856, 100857, 100858, - 100859, 100860, 100861, 100862, 100863, 100864, 100865, 100866, 100867, - 100868, 100869, 100870, 100871, 100872, 100873, 100874, 100875, 100876, - 100877, 100878, 100879, 100880, 100881, 100882, 100883, 100884, 100885, - 100886, 100887, 100888, 100889, 100890, 100891, 100892, 100893, 100894, - 100895, 100896, 100897, 100898, 100899, 100900, 100901, 100902, 100903, - 100904, 100905, 100906, 100907, 100908, 100909, 100910, 100911, 100912, - 100913, 100914, 100915, 100916, 100917, 100918, 100919, 100920, 100921, - 100922, 100923, 100924, 100925, 100926, 100927, 100928, 100929, 100930, - 100931, 100932, 100933, 100934, 100935, 100936, 100937, 100938, 100939, - 100940, 100941, 100942, 100943, 100944, 100945, 100946, 100947, 100948, - 100949, 100950, 100951, 100952, 100953, 100954, 100955, 100956, 100957, - 100958, 100959, 100960, 100961, 100962, 100963, 100964, 100965, 100966, - 100967, 100968, 100969, 100970, 100971, 100972, 100973, 100974, 100975, - 100976, 100977, 100978, 100979, 100980, 100981, 100982, 100983, 100984, - 100985, 100986, 100987, 100988, 100989, 100990, 100991, 100992, 100993, - 100994, 100995, 100996, 100997, 100998, 100999, 101000, 101001, 101002, - 101003, 101004, 101005, 101006, 101007, 101008, 101009, 101010, 101011, - 101012, 101013, 101014, 101015, 101016, 101017, 101018, 101019, 101020, - 101021, 101022, 101023, 101024, 101025, 101026, 101027, 101028, 101029, - 101030, 101031, 101032, 101033, 101034, 101035, 101036, 101037, 101038, - 101039, 101040, 101041, 101042, 101043, 101044, 101045, 101046, 101047, - 101048, 101049, 101050, 101051, 101052, 101053, 101054, 101055, 101056, - 101057, 101058, 101059, 101060, 101061, 101062, 101063, 101064, 101065, - 101066, 101067, 101068, 101069, 101070, 101071, 101072, 101073, 101074, - 101075, 101076, 101077, 101078, 101079, 101080, 101081, 101082, 101083, - 101084, 101085, 101086, 101087, 101088, 101089, 101090, 101091, 101092, - 101093, 101094, 101095, 101096, 101097, 101098, 101099, 101100, 101101, - 101102, 101103, 101104, 101105, 101106, 101107, 101108, 101109, 101110, - 101111, 101112, 101113, 101114, 101115, 101116, 101117, 101118, 101119, - 94176, 128429, 9991, 9801, 127790, 128661, 127861, 128198, 10043, 10170, - 129750, 129528, 128222, 128380, 8981, 9990, 8481, 128384, 128301, 128250, - 3158, 3195, 3198, 3194, 3197, 3193, 3196, 3192, 3106, 3105, 3111, 3161, - 3110, 3112, 3165, 3097, 3107, 3102, 3162, 3121, 3120, 3104, 3103, 3109, - 3160, 3108, 3077, 3078, 3088, 3092, 3124, 3123, 3122, 3083, 3168, 3084, - 3169, 3125, 3081, 3082, 3090, 3091, 3079, 3080, 3126, 3127, 3128, 3117, - 3116, 3099, 3098, 3096, 3095, 3101, 3100, 3094, 3093, 3115, 3114, 3086, - 3087, 3129, 3118, 3119, 3157, 3076, 3072, 3073, 3191, 3199, 3132, 3133, - 3074, 3149, 3075, 3134, 3144, 3148, 3137, 3138, 3139, 3140, 3170, 3171, - 3146, 3147, 3135, 3136, 3142, 3143, 3179, 3178, 3181, 3180, 3177, 3176, - 3174, 3183, 3175, 3182, 127934, 8376, 9978, 129514, 119617, 119564, - 119577, 119633, 119587, 119566, 119561, 119585, 119613, 119590, 119631, - 119634, 119630, 119608, 119582, 119563, 119573, 119558, 119624, 119567, - 119623, 119586, 119636, 119612, 119625, 119568, 119584, 119619, 119618, - 119583, 119603, 119600, 119626, 119610, 119580, 119576, 119638, 119559, - 119595, 119632, 119606, 119592, 119615, 119599, 119602, 119614, 119629, - 119574, 119569, 119570, 119622, 119562, 119591, 119637, 119597, 119589, - 119616, 119609, 119560, 119635, 119565, 119604, 119588, 119571, 119594, - 119578, 119596, 119579, 119598, 119572, 119605, 119627, 119621, 119628, - 119601, 119593, 119607, 119575, 119620, 119611, 119581, 1959, 1958, 1964, - 1961, 1965, 1927, 1954, 1951, 1937, 1931, 1930, 1956, 1934, 1935, 1955, - 1945, 1920, 1926, 1946, 1933, 1925, 1929, 1943, 1942, 1941, 1922, 1969, - 1950, 1949, 1921, 1936, 1939, 1932, 1947, 1944, 1952, 1928, 1957, 1938, - 1948, 1953, 1924, 1923, 1940, 1967, 1966, 1963, 1960, 1962, 1968, 3610, - 3592, 3594, 3593, 3596, 3598, 3604, 3613, 3615, 3663, 3630, 3627, 3588, - 3587, 3589, 3586, 3590, 3675, 3585, 3628, 3621, 3653, 3622, 3659, 3633, - 3657, 3658, 3656, 3655, 3654, 3617, 3674, 3591, 3661, 3603, 3609, 3631, - 3642, 3612, 3614, 3616, 3611, 3619, 3620, 3632, 3652, 3651, 3634, 3649, - 3635, 3640, 3638, 3639, 3641, 3636, 3637, 3648, 3650, 3625, 3624, 3626, - 3595, 3660, 3601, 3602, 3607, 3600, 3608, 3606, 3605, 3599, 3623, 3662, - 3597, 3618, 3629, 3647, 3669, 3668, 3671, 3670, 3667, 3666, 3664, 3673, - 3665, 3672, 8708, 8707, 8756, 127777, 10727, 128936, 8201, 128929, + 129394, 8995, 128527, 128684, 128013, 118010, 128012, 129319, 127956, + 9731, 9924, 127938, 10052, 983077, 9917, 129510, 173, 127846, 128428, + 9108, 129358, 69453, 69452, 69454, 69456, 69447, 69449, 69446, 69448, + 69455, 69451, 69450, 69445, 69424, 69437, 69426, 69433, 69444, 69440, + 69429, 69436, 69439, 69441, 69431, 69427, 69430, 69432, 69425, 69443, + 69435, 69442, 69428, 69438, 69434, 69457, 69460, 69459, 69458, 69463, + 69465, 69461, 69462, 69464, 128618, 128619, 47, 10742, 128284, 69859, + 69863, 69864, 69846, 69847, 69857, 69849, 69842, 69843, 69844, 69845, + 69854, 69856, 69855, 69848, 69851, 69853, 69840, 69841, 69850, 69852, + 69858, 69860, 69862, 69861, 69877, 69876, 69879, 69878, 69875, 69874, + 69872, 69881, 69873, 69880, 8600, 10537, 10541, 8690, 10533, 129210, + 128603, 128595, 128611, 11112, 11128, 11018, 8664, 129110, 11010, 8601, + 10538, 10534, 129211, 128601, 128593, 128609, 11113, 11129, 11019, 8665, + 129111, 11011, 8471, 72328, 72329, 72327, 72326, 72340, 72339, 72334, + 72332, 72341, 72335, 72333, 72330, 72331, 72338, 72336, 72337, 72352, + 72351, 72350, 72297, 72296, 72302, 72311, 72301, 72323, 72285, 72284, + 72288, 72298, 72293, 72303, 72319, 72320, 72321, 72310, 72309, 72295, + 72294, 72300, 72299, 72307, 72306, 72290, 72289, 72287, 72286, 72292, + 72291, 72305, 72304, 72312, 72313, 72314, 72322, 72317, 72308, 72316, + 72318, 72315, 72272, 72349, 72348, 72347, 72346, 72324, 72343, 72325, + 72342, 72345, 72353, 72354, 72282, 72281, 72279, 72280, 72277, 72278, + 72275, 72274, 72276, 72273, 72283, 72344, 8384, 983043, 983182, 983118, + 983177, 127837, 128150, 10055, 10024, 117824, 117825, 32, 128586, 128264, + 128263, 128265, 128266, 128483, 128676, 128172, 8375, 117830, 117831, + 8738, 10656, 10657, 128375, 128376, 128467, 128466, 128026, 128166, + 129759, 129525, 129348, 128051, 127941, 129533, 13279, 117900, 13056, + 13058, 13057, 13059, 13250, 13171, 13278, 13101, 13172, 13108, 13105, + 13118, 13116, 13251, 13192, 8851, 13255, 13183, 13213, 13220, 13216, + 13254, 8852, 13252, 13253, 13170, 13092, 13175, 13177, 13176, 13093, + 13094, 13256, 127376, 13207, 13064, 13179, 13181, 13182, 13055, 13180, + 13005, 13063, 13006, 117899, 117898, 117897, 9974, 9165, 13209, 13070, + 13071, 13311, 13075, 13073, 13072, 13080, 13081, 13203, 13228, 13191, + 13257, 13258, 13098, 13110, 13113, 13121, 13122, 13119, 13107, 13106, + 13109, 13259, 13169, 127488, 13004, 13200, 13260, 13060, 13061, 8847, + 8932, 8849, 13178, 13188, 13068, 13069, 13067, 13076, 13078, 13079, + 13077, 13214, 13262, 13222, 13218, 13086, 13085, 13082, 13083, 13084, + 13074, 13201, 13193, 13248, 13226, 13189, 13199, 13261, 13208, 13263, + 13240, 13246, 8977, 13266, 10957, 13264, 13265, 13267, 13223, 13224, + 13249, 13221, 13217, 13187, 13123, 13124, 13127, 13126, 13125, 13190, + 13268, 13131, 13132, 13133, 13128, 13129, 13130, 13269, 13212, 13219, + 13215, 13186, 13196, 13197, 13205, 13211, 13234, 13238, 13244, 13239, + 13241, 13245, 13247, 13202, 13270, 13227, 13198, 13206, 13235, 13185, + 13096, 13097, 13195, 13210, 13233, 13237, 13243, 13065, 8848, 8933, 8850, + 13066, 13173, 13225, 13099, 13100, 13184, 13115, 13112, 13114, 13111, + 13103, 13104, 13102, 13117, 13120, 11216, 13273, 13174, 13194, 13271, + 13272, 13274, 13232, 13236, 13242, 13229, 13230, 13231, 13142, 13141, + 10958, 13137, 13138, 13140, 13139, 8730, 13087, 13088, 13090, 13091, + 117887, 117886, 117884, 117885, 13089, 13275, 13276, 128918, 13204, + 13095, 13143, 11027, 9641, 9638, 9636, 11029, 9706, 9703, 11026, 9705, + 9639, 11028, 9640, 9637, 9704, 10720, 13277, 13135, 13134, 13136, 13062, + 127529, 127530, 127512, 127508, 127533, 127545, 127520, 127516, 127534, + 127506, 127540, 127525, 127546, 127532, 127511, 127509, 127524, 127505, + 127517, 127518, 127527, 127537, 127504, 127528, 127535, 127519, 127515, + 127513, 127543, 127542, 127526, 127541, 127544, 127522, 127538, 127514, + 127521, 127539, 127510, 127536, 127523, 127547, 127531, 127378, 127377, + 8865, 10693, 11820, 127390, 127392, 127379, 10692, 127400, 127399, + 127398, 127306, 127489, 127507, 127490, 9919, 127397, 127280, 127281, + 127282, 127283, 127284, 127285, 127286, 127287, 127288, 127289, 127290, + 127291, 127292, 127293, 127294, 127295, 127296, 127297, 127298, 127299, + 127300, 127301, 127302, 127303, 127304, 127305, 10190, 10191, 127401, + 8863, 127307, 127381, 127382, 127396, 127383, 127310, 8862, 127388, + 127393, 127402, 127395, 9949, 10695, 10696, 127384, 127308, 127309, + 127387, 127394, 127389, 8864, 127391, 127385, 127403, 127404, 127386, + 10694, 127311, 127380, 10151, 129425, 983157, 983160, 983134, 983190, + 9877, 9882, 128387, 8795, 10017, 8902, 9770, 11242, 11243, 983175, + 983133, 983181, 983176, 983042, 983044, 128509, 128649, 129485, 127967, + 128642, 127836, 11836, 129658, 129989, 129990, 129993, 129991, 129992, + 128480, 9201, 128207, 9188, 127827, 118463, 10025, 983189, 117891, + 117888, 117890, 117889, 8803, 127897, 129369, 128723, 983170, 983045, + 983103, 8333, 8332, 8328, 8330, 8334, 8331, 8325, 8324, 8327, 8326, 8323, + 8322, 8320, 8329, 8321, 10963, 10965, 10617, 8834, 10953, 10949, 10951, + 10955, 8842, 8838, 10947, 10945, 10943, 10941, 983102, 8827, 10938, + 10934, 10928, 10930, 10936, 10932, 8937, 8831, 8829, 8881, 9139, 10763, + 9138, 9737, 127774, 9925, 7098, 7073, 7074, 7075, 7084, 7085, 7043, + 983220, 7046, 7102, 7103, 7062, 7100, 7068, 7099, 7067, 7087, 7070, 7048, + 7049, 7053, 7057, 7060, 7101, 7064, 7086, 7050, 7054, 7059, 7052, 7072, + 7055, 7065, 7061, 7051, 7058, 7063, 7069, 7071, 7066, 7056, 7044, 7047, + 7045, 7367, 7366, 7365, 7364, 7363, 7361, 7362, 7360, 7082, 7041, 7042, + 7040, 7083, 7080, 7081, 7079, 7077, 7076, 7078, 7093, 7092, 7095, 7094, + 7091, 7090, 7088, 7097, 7089, 7096, 127749, 127748, 72648, 72662, 72661, + 72669, 72652, 72640, 72663, 72651, 72655, 72672, 72646, 72667, 72666, + 72653, 72657, 72645, 72665, 72649, 72644, 72658, 72668, 72670, 72664, + 72671, 72641, 72659, 72656, 72650, 72643, 72660, 72654, 72642, 72647, + 72673, 72693, 72692, 72695, 72694, 72691, 72690, 72688, 72697, 72689, + 72696, 127751, 127803, 8316, 8312, 8305, 8319, 8317, 8314, 8318, 8315, + 8309, 8308, 8311, 8310, 179, 178, 8304, 8313, 185, 10966, 10964, 10619, + 10968, 10967, 8835, 10954, 10950, 10952, 10956, 8843, 8839, 10948, 10946, + 10944, 10942, 10185, 129464, 129465, 8751, 127940, 128671, 127843, + 128629, 129442, 127946, 8275, 43027, 43026, 43031, 43030, 43040, 43038, + 43025, 43024, 43029, 43028, 43036, 43035, 43021, 43020, 43018, 43017, + 43023, 43022, 43016, 43015, 43034, 43033, 43042, 43039, 43037, 43032, + 43041, 43008, 43012, 43009, 43013, 43011, 43048, 43049, 43050, 43051, + 43052, 43019, 43014, 43010, 43047, 43043, 43046, 43044, 43045, 9223, + 9224, 9229, 9240, 9232, 9249, 9256, 9255, 9253, 9257, 9236, 9235, 9234, + 9233, 9241, 9220, 9239, 9219, 9221, 9243, 9244, 9228, 9225, 9227, 9226, + 128325, 9237, 9252, 9216, 9222, 9246, 9245, 9247, 8527, 9230, 9231, 9217, + 9218, 9242, 9254, 9238, 9248, 11159, 9007, 983094, 983093, 128333, 1807, + 1866, 1802, 1798, 1799, 1849, 1848, 1792, 1854, 1853, 1805, 1804, 1803, + 1852, 1851, 1850, 1797, 1814, 1813, 1815, 1818, 1824, 2153, 2152, 2149, + 2148, 2144, 2146, 2150, 2147, 2154, 2145, 2151, 1825, 1830, 1837, 1839, + 1838, 1831, 1834, 1827, 1869, 1870, 1871, 1809, 1835, 1832, 1828, 1808, + 1823, 1833, 1819, 1820, 1836, 1811, 1812, 1821, 1822, 1810, 1817, 1826, + 1816, 1829, 1864, 1863, 1842, 1841, 1840, 1845, 1844, 1843, 1847, 1846, + 1855, 1858, 1796, 983204, 1801, 1794, 1795, 1800, 1793, 1862, 1861, 1860, + 1859, 1865, 1856, 1857, 128137, 983184, 128085, 129430, 983061, 127955, + 917543, 917542, 917546, 917598, 917568, 917548, 917562, 917540, 917557, + 917556, 917559, 917558, 917555, 917554, 917552, 917561, 917553, 917560, + 917565, 917537, 917600, 917566, 917549, 917569, 917570, 917571, 917572, + 917573, 917574, 917575, 917576, 917577, 917578, 917579, 917580, 917581, + 917582, 917583, 917584, 917585, 917586, 917587, 917588, 917589, 917590, + 917591, 917592, 917593, 917594, 917601, 917602, 917603, 917604, 917605, + 917606, 917607, 917608, 917609, 917610, 917611, 917612, 917613, 917614, + 917615, 917616, 917617, 917618, 917619, 917620, 917621, 917622, 917623, + 917624, 917625, 917626, 917564, 917627, 917544, 917595, 917599, 917541, + 917547, 917538, 917567, 917629, 917545, 917597, 917596, 917563, 917551, + 917536, 917539, 917630, 917550, 917628, 5888, 5919, 5893, 5896, 5898, + 5895, 5892, 5905, 5891, 5902, 5899, 5897, 5901, 5904, 5894, 5903, 5900, + 5889, 5890, 5909, 5908, 5906, 5907, 5989, 5992, 5994, 5991, 5988, 5987, + 5998, 5995, 5993, 6000, 5990, 5999, 5996, 5984, 5985, 5986, 6002, 6003, + 6499, 6508, 6509, 6507, 6501, 6502, 6512, 6513, 6514, 6515, 6516, 6497, + 6483, 6487, 6486, 6482, 6498, 6505, 6504, 6496, 6480, 6490, 6489, 6503, + 6506, 6492, 6494, 6488, 6491, 6495, 6484, 6493, 6481, 6485, 6500, 6745, + 6746, 6743, 6747, 6742, 6741, 6748, 6749, 6750, 6783, 6789, 6788, 6791, + 6790, 6787, 6786, 6784, 6793, 6785, 6792, 6805, 6804, 6807, 6806, 6803, + 6802, 6800, 6809, 6801, 6808, 6740, 6689, 6690, 6688, 6702, 6726, 6727, + 6728, 6696, 6695, 6713, 6712, 6707, 6706, 6714, 6729, 6720, 6693, 6692, + 6691, 6704, 6699, 6697, 6717, 6715, 6709, 6708, 6716, 6732, 6698, 6719, + 6723, 6739, 6724, 6730, 6721, 6705, 6701, 6722, 6735, 6736, 6733, 6734, + 6694, 6700, 6710, 6738, 6737, 6711, 6703, 6718, 6725, 6731, 6828, 6820, + 6775, 6776, 6777, 6780, 6824, 6825, 6819, 6772, 6744, 6823, 6779, 6778, + 6822, 6826, 6827, 6818, 6752, 6816, 6817, 6821, 6773, 6774, 6829, 6753, + 6755, 6767, 6769, 6754, 6763, 6764, 6771, 6768, 6765, 6756, 6770, 6761, + 6762, 6760, 6759, 6757, 6758, 6766, 43653, 43651, 43649, 43661, 43659, + 43679, 43677, 43671, 43669, 43657, 43665, 43673, 43675, 43667, 43681, + 43655, 43693, 43689, 43683, 43687, 43663, 43691, 43685, 43695, 43652, + 43650, 43648, 43660, 43658, 43678, 43676, 43670, 43668, 43656, 43664, + 43672, 43674, 43666, 43680, 43654, 43692, 43688, 43682, 43686, 43662, + 43690, 43684, 43694, 43696, 43703, 43743, 43739, 43740, 43742, 43741, + 43712, 43713, 43714, 43711, 43707, 43697, 43710, 43709, 43708, 43700, + 43699, 43705, 43706, 43698, 43704, 43701, 43702, 124653, 124640, 124645, + 124658, 124657, 124656, 124660, 124659, 124632, 124610, 124637, 124608, + 124617, 124628, 124634, 124625, 124620, 124615, 124611, 124638, 124609, + 124618, 124629, 124635, 124626, 124621, 124616, 124613, 124623, 124644, + 124642, 124650, 124651, 124627, 124622, 124641, 124649, 124647, 124652, + 124624, 124614, 124619, 124612, 124630, 124636, 124633, 124631, 124648, + 124655, 124646, 124654, 124643, 124661, 124670, 124671, 71353, 71296, + 71352, 71297, 71303, 71305, 71319, 71318, 71324, 71323, 71338, 71332, + 71317, 71316, 71322, 71321, 71300, 71301, 71298, 71299, 71310, 71320, + 71315, 71325, 71329, 71328, 71312, 71311, 71309, 71308, 71314, 71313, + 71307, 71306, 71327, 71326, 71335, 71336, 71337, 71333, 71330, 71334, + 71331, 71302, 71304, 71351, 71339, 71350, 71340, 71341, 71347, 71349, + 71344, 71345, 71342, 71343, 71346, 71348, 71365, 71364, 71367, 71366, + 71363, 71362, 71360, 71369, 71361, 71368, 129377, 119672, 119671, 3064, + 3031, 73707, 983662, 983685, 983674, 983677, 983676, 983669, 983667, + 983679, 983663, 983665, 983668, 983666, 983683, 983681, 983682, 983673, + 983678, 983664, 983684, 983680, 983671, 983670, 983675, 983672, 73706, + 3063, 73701, 3062, 3059, 3051, 3050, 3053, 3052, 3049, 3048, 3046, 3055, + 3047, 3054, 73700, 73666, 73676, 73668, 73679, 73681, 73682, 73665, + 73673, 73674, 73667, 73664, 73669, 73672, 73675, 73680, 73670, 73678, + 73671, 73677, 73683, 73684, 73710, 2985, 2979, 2969, 2974, 2984, 2975, + 2980, 2949, 2950, 2960, 2964, 2996, 2995, 2994, 2993, 2992, 2953, 2954, + 2962, 2963, 2951, 2952, 2998, 2999, 3000, 2958, 2959, 2970, 3001, 2972, + 2965, 2990, 2986, 2997, 2991, 73702, 3057, 3058, 3056, 3066, 73727, 3065, + 73703, 73687, 2946, 73686, 73698, 73690, 73693, 73692, 73712, 73689, + 73688, 73691, 73697, 73694, 73695, 73696, 73713, 73699, 3021, 2947, + 73685, 73708, 73711, 983939, 983940, 983947, 983950, 983943, 983944, + 983948, 983949, 983941, 983942, 983945, 983946, 983686, 983693, 983696, + 983689, 983690, 983694, 983695, 983687, 983688, 983691, 983692, 983840, + 983847, 983850, 983843, 983844, 983848, 983849, 983841, 983842, 983845, + 983846, 983851, 983858, 983861, 983854, 983855, 983859, 983860, 983852, + 983853, 983856, 983857, 983818, 983825, 983828, 983821, 983822, 983826, + 983827, 983819, 983820, 983823, 983824, 983873, 983880, 983883, 983876, + 983877, 983881, 983882, 983874, 983875, 983878, 983879, 983741, 983748, + 983751, 983744, 983745, 983749, 983750, 983742, 983743, 983746, 983747, + 983697, 983704, 983707, 983700, 983701, 983705, 983706, 983698, 983699, + 983702, 983703, 983719, 983726, 983729, 983722, 983723, 983727, 983728, + 983720, 983721, 983724, 983725, 983763, 983770, 983773, 983766, 983767, + 983771, 983772, 983764, 983765, 983768, 983769, 983862, 983869, 983872, + 983865, 983866, 983870, 983871, 983863, 983864, 983867, 983868, 983807, + 983814, 983817, 983810, 983811, 983815, 983816, 983808, 983809, 983812, + 983813, 983895, 983902, 983905, 983898, 983899, 983903, 983904, 983951, + 983896, 983897, 983900, 983901, 983906, 983913, 983916, 983909, 983910, + 983914, 983915, 983907, 983908, 983911, 983912, 983917, 983924, 983927, + 983920, 983921, 983925, 983926, 983918, 983919, 983922, 983923, 983730, + 983737, 983740, 983733, 983734, 983738, 983739, 983731, 983732, 983735, + 983736, 983752, 983759, 983762, 983755, 983756, 983760, 983761, 983753, + 983754, 983757, 983758, 983708, 983715, 983718, 983711, 983712, 983716, + 983717, 983709, 983710, 983713, 983714, 983928, 983935, 983938, 983931, + 983932, 983936, 983937, 983929, 983930, 983933, 983934, 983884, 983891, + 983894, 983887, 983888, 983892, 983893, 983885, 983886, 983889, 983890, + 983785, 983792, 983795, 983788, 983789, 983793, 983794, 983786, 983787, + 983790, 983791, 983774, 983781, 983784, 983777, 983778, 983782, 983783, + 983775, 983776, 983779, 983780, 983829, 983836, 983839, 983832, 983833, + 983837, 983838, 983830, 983831, 983834, 983835, 983796, 983803, 983806, + 983799, 983800, 983804, 983805, 983797, 983798, 983801, 983802, 73709, + 73704, 73705, 3006, 3016, 3020, 3009, 3010, 3018, 3019, 3007, 3008, 3014, + 3015, 3061, 3060, 3024, 129748, 127883, 127818, 92809, 92810, 92811, + 92808, 92789, 92790, 92791, 92788, 92816, 92859, 92856, 92847, 92845, + 92817, 92846, 92843, 92829, 92830, 92831, 92828, 92835, 92851, 92840, + 92844, 92818, 92819, 92852, 92836, 92825, 92826, 92827, 92824, 92813, + 92814, 92815, 92812, 92820, 92822, 92823, 92821, 92805, 92806, 92807, + 92804, 92797, 92798, 92799, 92796, 92801, 92802, 92803, 92800, 92785, + 92786, 92787, 92784, 92793, 92794, 92795, 92792, 92857, 92854, 92848, + 92861, 92853, 92860, 92849, 92855, 92834, 92833, 92832, 92841, 92839, + 92842, 92850, 92838, 92858, 92837, 92862, 92869, 92868, 92871, 92870, + 92867, 92866, 92864, 92873, 92865, 92872, 100352, 100353, 100354, 100355, + 100356, 100357, 100358, 100359, 100360, 100361, 100362, 100363, 100364, + 100365, 100366, 100367, 100368, 100369, 100370, 100371, 100372, 100373, + 100374, 100375, 100376, 100377, 100378, 100379, 100380, 100381, 100382, + 100383, 100384, 100385, 100386, 100387, 100388, 100389, 100390, 100391, + 100392, 100393, 100394, 100395, 100396, 100397, 100398, 100399, 100400, + 100401, 100402, 100403, 100404, 100405, 100406, 100407, 100408, 100409, + 100410, 100411, 100412, 100413, 100414, 100415, 100416, 100417, 100418, + 100419, 100420, 100421, 100422, 100423, 100424, 100425, 100426, 100427, + 100428, 100429, 100430, 100431, 100432, 100433, 100434, 100435, 100436, + 100437, 100438, 100439, 100440, 100441, 100442, 100443, 100444, 100445, + 100446, 100447, 100448, 100449, 100450, 100451, 100452, 100453, 100454, + 100455, 100456, 100457, 100458, 100459, 100460, 100461, 100462, 100463, + 100464, 100465, 100466, 100467, 100468, 100469, 100470, 100471, 100472, + 100473, 100474, 100475, 100476, 100477, 100478, 100479, 100480, 100481, + 100482, 100483, 100484, 100485, 100486, 100487, 100488, 100489, 100490, + 100491, 100492, 100493, 100494, 100495, 100496, 100497, 100498, 100499, + 100500, 100501, 100502, 100503, 100504, 100505, 100506, 100507, 100508, + 100509, 100510, 100511, 100512, 100513, 100514, 100515, 100516, 100517, + 100518, 100519, 100520, 100521, 100522, 100523, 100524, 100525, 100526, + 100527, 100528, 100529, 100530, 100531, 100532, 100533, 100534, 100535, + 100536, 100537, 100538, 100539, 100540, 100541, 100542, 100543, 100544, + 100545, 100546, 100547, 100548, 100549, 100550, 100551, 100552, 100553, + 100554, 100555, 100556, 100557, 100558, 100559, 100560, 100561, 100562, + 100563, 100564, 100565, 100566, 100567, 100568, 100569, 100570, 100571, + 100572, 100573, 100574, 100575, 100576, 100577, 100578, 100579, 100580, + 100581, 100582, 100583, 100584, 100585, 100586, 100587, 100588, 100589, + 100590, 100591, 100592, 100593, 100594, 100595, 100596, 100597, 100598, + 100599, 100600, 100601, 100602, 100603, 100604, 100605, 100606, 100607, + 100608, 100609, 100610, 100611, 100612, 100613, 100614, 100615, 100616, + 100617, 100618, 100619, 100620, 100621, 100622, 100623, 100624, 100625, + 100626, 100627, 100628, 100629, 100630, 100631, 100632, 100633, 100634, + 100635, 100636, 100637, 100638, 100639, 100640, 100641, 100642, 100643, + 100644, 100645, 100646, 100647, 100648, 100649, 100650, 100651, 100652, + 100653, 100654, 100655, 100656, 100657, 100658, 100659, 100660, 100661, + 100662, 100663, 100664, 100665, 100666, 100667, 100668, 100669, 100670, + 100671, 100672, 100673, 100674, 100675, 100676, 100677, 100678, 100679, + 100680, 100681, 100682, 100683, 100684, 100685, 100686, 100687, 100688, + 100689, 100690, 100691, 100692, 100693, 100694, 100695, 100696, 100697, + 100698, 100699, 100700, 100701, 100702, 100703, 100704, 100705, 100706, + 100707, 100708, 100709, 100710, 100711, 100712, 100713, 100714, 100715, + 100716, 100717, 100718, 100719, 100720, 100721, 100722, 100723, 100724, + 100725, 100726, 100727, 100728, 100729, 100730, 100731, 100732, 100733, + 100734, 100735, 100736, 100737, 100738, 100739, 100740, 100741, 100742, + 100743, 100744, 100745, 100746, 100747, 100748, 100749, 100750, 100751, + 100752, 100753, 100754, 100755, 100756, 100757, 100758, 100759, 100760, + 100761, 100762, 100763, 100764, 100765, 100766, 100767, 100768, 100769, + 100770, 100771, 100772, 100773, 100774, 100775, 100776, 100777, 100778, + 100779, 100780, 100781, 100782, 100783, 100784, 100785, 100786, 100787, + 100788, 100789, 100790, 100791, 100792, 100793, 100794, 100795, 100796, + 100797, 100798, 100799, 100800, 100801, 100802, 100803, 100804, 100805, + 100806, 100807, 100808, 100809, 100810, 100811, 100812, 100813, 100814, + 100815, 100816, 100817, 100818, 100819, 100820, 100821, 100822, 100823, + 100824, 100825, 100826, 100827, 100828, 100829, 100830, 100831, 100832, + 100833, 100834, 100835, 100836, 100837, 100838, 100839, 100840, 100841, + 100842, 100843, 100844, 100845, 100846, 100847, 100848, 100849, 100850, + 100851, 100852, 100853, 100854, 100855, 100856, 100857, 100858, 100859, + 100860, 100861, 100862, 100863, 100864, 100865, 100866, 100867, 100868, + 100869, 100870, 100871, 100872, 100873, 100874, 100875, 100876, 100877, + 100878, 100879, 100880, 100881, 100882, 100883, 100884, 100885, 100886, + 100887, 100888, 100889, 100890, 100891, 100892, 100893, 100894, 100895, + 100896, 100897, 100898, 100899, 100900, 100901, 100902, 100903, 100904, + 100905, 100906, 100907, 100908, 100909, 100910, 100911, 100912, 100913, + 100914, 100915, 100916, 100917, 100918, 100919, 100920, 100921, 100922, + 100923, 100924, 100925, 100926, 100927, 100928, 100929, 100930, 100931, + 100932, 100933, 100934, 100935, 100936, 100937, 100938, 100939, 100940, + 100941, 100942, 100943, 100944, 100945, 100946, 100947, 100948, 100949, + 100950, 100951, 100952, 100953, 100954, 100955, 100956, 100957, 100958, + 100959, 100960, 100961, 100962, 100963, 100964, 100965, 100966, 100967, + 100968, 100969, 100970, 100971, 100972, 100973, 100974, 100975, 100976, + 100977, 100978, 100979, 100980, 100981, 100982, 100983, 100984, 100985, + 100986, 100987, 100988, 100989, 100990, 100991, 100992, 100993, 100994, + 100995, 100996, 100997, 100998, 100999, 101000, 101001, 101002, 101003, + 101004, 101005, 101006, 101007, 101008, 101009, 101010, 101011, 101012, + 101013, 101014, 101015, 101016, 101017, 101018, 101019, 101020, 101021, + 101022, 101023, 101024, 101025, 101026, 101027, 101028, 101029, 101030, + 101031, 101032, 101033, 101034, 101035, 101036, 101037, 101038, 101039, + 101040, 101041, 101042, 101043, 101044, 101045, 101046, 101047, 101048, + 101049, 101050, 101051, 101052, 101053, 101054, 101055, 101056, 101057, + 101058, 101059, 101060, 101061, 101062, 101063, 101064, 101065, 101066, + 101067, 101068, 101069, 101070, 101071, 101072, 101073, 101074, 101075, + 101076, 101077, 101078, 101079, 101080, 101081, 101082, 101083, 101084, + 101085, 101086, 101087, 101088, 101089, 101090, 101091, 101092, 101093, + 101094, 101095, 101096, 101097, 101098, 101099, 101100, 101101, 101102, + 101103, 101104, 101105, 101106, 101107, 101108, 101109, 101110, 101111, + 101112, 101113, 101114, 101115, 101116, 101117, 101118, 101119, 101760, + 101761, 101762, 101763, 101764, 101765, 101766, 101767, 101768, 101769, + 101770, 101771, 101772, 101773, 101774, 101775, 101776, 101777, 101778, + 101779, 101780, 101781, 101782, 101783, 101784, 101785, 101786, 101787, + 101788, 101789, 101790, 101791, 101792, 101793, 101794, 101795, 101796, + 101797, 101798, 101799, 101800, 101801, 101802, 101803, 101804, 101805, + 101806, 101807, 101808, 101809, 101810, 101811, 101812, 101813, 101814, + 101815, 101816, 101817, 101818, 101819, 101820, 101821, 101822, 101823, + 101824, 101825, 101826, 101827, 101828, 101829, 101830, 101831, 101832, + 101833, 101834, 101835, 101836, 101837, 101838, 101839, 101840, 101841, + 101842, 101843, 101844, 101845, 101846, 101847, 101848, 101849, 101850, + 101851, 101852, 101853, 101854, 101855, 101856, 101857, 101858, 101859, + 101860, 101861, 101862, 101863, 101864, 101865, 101866, 101867, 101868, + 101869, 101870, 101871, 101872, 101873, 101874, 94176, 128429, 9991, + 9801, 127790, 128661, 127861, 128198, 10043, 10170, 129750, 129528, + 128222, 128380, 8981, 9990, 8481, 128384, 128301, 128250, 3164, 3158, + 3195, 3198, 3194, 3197, 3193, 3196, 3192, 3106, 3105, 3111, 3161, 3110, + 3112, 3165, 3097, 3107, 3102, 3162, 3121, 3120, 3104, 3103, 3109, 3160, + 3108, 3077, 3078, 3088, 3092, 3124, 3123, 3122, 3083, 3168, 3084, 3169, + 3125, 3081, 3082, 3090, 3091, 3079, 3080, 3126, 3127, 3128, 3117, 3116, + 3099, 3098, 3096, 3095, 3101, 3100, 3094, 3093, 3115, 3114, 3086, 3087, + 3129, 3118, 3119, 3157, 3076, 3072, 3073, 3191, 3199, 3132, 3133, 3074, + 3149, 3075, 3134, 3144, 3148, 3137, 3138, 3139, 3140, 3170, 3171, 3146, + 3147, 3135, 3136, 3142, 3143, 3179, 3178, 3181, 3180, 3177, 3176, 3174, + 3183, 3175, 3182, 127934, 8376, 9978, 129514, 119617, 119564, 119577, + 119633, 119587, 119566, 119561, 119585, 119613, 119590, 119631, 119634, + 119630, 119608, 119582, 119563, 119573, 119558, 119624, 119567, 119623, + 119586, 119636, 119612, 119625, 119568, 119584, 119619, 119618, 119583, + 119603, 119600, 119626, 119610, 119580, 119576, 119638, 119559, 119595, + 119632, 119606, 119592, 119615, 119599, 119602, 119614, 119629, 119574, + 119569, 119570, 119622, 119562, 119591, 119637, 119597, 119589, 119616, + 119609, 119560, 119635, 119565, 119604, 119588, 119571, 119594, 119578, + 119596, 119579, 119598, 119572, 119605, 119627, 119621, 119628, 119601, + 119593, 119607, 119575, 119620, 119611, 119581, 1959, 1958, 1964, 1961, + 1965, 1927, 1954, 1951, 1937, 1931, 1930, 1956, 1934, 1935, 1955, 1945, + 1920, 1926, 1946, 1933, 1925, 1929, 1943, 1942, 1941, 1922, 1969, 1950, + 1949, 1921, 1936, 1939, 1932, 1947, 1944, 1952, 1928, 1957, 1938, 1948, + 1953, 1924, 1923, 1940, 1967, 1966, 1963, 1960, 1962, 1968, 3610, 3592, + 3594, 3593, 3596, 3598, 3604, 3613, 3615, 3663, 3630, 3627, 3588, 3587, + 3589, 3586, 3590, 3675, 3585, 3628, 3621, 3653, 3622, 3659, 3633, 3657, + 3658, 3656, 3655, 3654, 3617, 3674, 3591, 3661, 3603, 3609, 3631, 3642, + 3612, 3614, 3616, 3611, 3619, 3620, 3632, 3652, 3651, 3634, 3649, 3635, + 3640, 3638, 3639, 3641, 3636, 3637, 3648, 3650, 3625, 3624, 3626, 3595, + 3660, 3601, 3602, 3607, 3600, 3608, 3606, 3605, 3599, 3623, 3662, 3597, + 3618, 3629, 3647, 3669, 3668, 3671, 3670, 3667, 3666, 3664, 3673, 3665, + 3672, 8708, 8707, 8756, 127777, 10727, 118474, 128936, 8201, 128929, 129300, 129353, 128173, 129652, 10176, 8278, 9887, 9886, 11057, 128485, 128484, 128486, 128487, 8694, 128433, 10870, 128491, 128962, 128423, 11160, 11162, 10146, 11163, 11161, 10147, 8196, 11835, 128077, 128078, - 9928, 9736, 3865, 3863, 3864, 4032, 4033, 4035, 4034, 3886, 3885, 3888, + 9928, 9736, 3865, 3863, 3864, 4035, 4032, 4033, 4034, 3886, 3885, 3888, 3887, 3884, 3883, 3891, 3890, 3882, 3889, 3877, 3876, 3879, 3878, 3875, 3874, 3872, 3881, 3873, 3880, 4030, 4031, 3945, 3905, 3947, 3904, 3948, 3938, 3946, 3917, 3916, 3932, 3931, 3922, 3921, 3908, 3918, 3913, 3923, @@ -12898,9 +13046,9 @@ static const unsigned int dawg_pos_to_codepoint[] = { 4040, 4037, 4039, 3968, 3969, 3956, 3957, 3958, 3959, 3960, 3961, 3964, 3965, 3954, 3955, 3962, 3963, 3953, 10717, 11647, 11608, 11595, 11585, 11573, 11620, 11607, 11600, 11582, 11590, 11596, 11601, 11586, 11592, - 11568, 11575, 11577, 11578, 11576, 11571, 11606, 11572, 11581, 11589, - 11583, 11569, 11570, 11584, 11587, 11609, 11611, 11610, 11612, 11613, - 11615, 11619, 11594, 11621, 11604, 11605, 11614, 11588, 11580, 11574, + 11568, 11571, 11606, 11572, 11581, 11589, 11583, 11609, 11611, 11610, + 11612, 11613, 11615, 11619, 11594, 11621, 11575, 11577, 11578, 11576, + 11569, 11570, 11584, 11587, 11604, 11605, 11614, 11588, 11580, 11574, 11597, 11598, 11599, 11602, 11591, 11616, 11617, 11618, 11622, 11579, 11593, 11623, 11603, 11631, 11632, 128005, 128047, 10053, 126, 8764, 11081, 10610, 10859, 10858, 11807, 11806, 11803, 9202, 10708, 10709, @@ -12918,155 +13066,161 @@ static const unsigned int dawg_pos_to_codepoint[] = { 67039, 67038, 67037, 67034, 67059, 67018, 67017, 67030, 67029, 67008, 67009, 67013, 67012, 67016, 67014, 67057, 67028, 67043, 67042, 67048, 67046, 67053, 67052, 67010, 67019, 67036, 67045, 67026, 67044, 67050, - 127813, 128069, 129463, 129701, 129520, 10554, 10557, 10556, 9182, - 118256, 117851, 118262, 118263, 11865, 117850, 118252, 118254, 11866, - 117852, 118248, 118250, 11833, 118246, 11210, 8992, 127913, 9180, 130024, - 130016, 130031, 8988, 8975, 11810, 118279, 8989, 8974, 11811, 130028, - 9140, 9184, 128285, 127553, 127554, 127559, 127555, 127557, 127560, - 127552, 127556, 127558, 127274, 9008, 123554, 123556, 123559, 123561, - 123564, 123537, 123544, 123543, 123553, 123555, 123558, 123560, 123546, - 123565, 123563, 123539, 123541, 123550, 123549, 123540, 123552, 123542, - 123536, 123551, 123545, 123538, 123548, 123547, 123562, 123557, 123566, - 128701, 128508, 128434, 128668, 8482, 128650, 128651, 11223, 10971, - 128646, 10701, 10699, 128710, 10698, 10141, 128681, 128208, 8227, 128305, - 9783, 9776, 9777, 9782, 9779, 9781, 9780, 9778, 10998, 10856, 10857, - 10747, 8244, 8779, 10996, 10624, 8874, 10997, 11003, 11851, 11000, 10999, - 8749, 8285, 129484, 128654, 127865, 128032, 127942, 8872, 11231, 127930, - 8366, 70601, 70608, 70613, 70612, 70610, 70528, 70529, 70542, 70545, - 70559, 70558, 70564, 70563, 70581, 70579, 70573, 70580, 70572, 70557, - 70556, 70562, 70561, 70534, 70535, 70536, 70537, 70574, 70532, 70533, - 70530, 70531, 70550, 70560, 70555, 70565, 70575, 70576, 70577, 70569, - 70568, 70552, 70551, 70549, 70548, 70554, 70553, 70547, 70546, 70567, - 70566, 70544, 70539, 70578, 70570, 70571, 70609, 70583, 70604, 70607, - 70615, 70616, 70602, 70611, 70606, 70605, 70626, 70625, 70584, 70597, - 70600, 70587, 70588, 70589, 70590, 70591, 70592, 70585, 70586, 70599, - 70594, 127799, 8378, 129411, 8523, 10658, 11202, 9930, 9929, 8498, 11826, - 11832, 8587, 8586, 128598, 128596, 8985, 128399, 8513, 8514, 8516, 11829, - 8526, 128599, 128597, 8489, 128034, 129347, 10041, 128256, 128432, 10869, - 8229, 8282, 11818, 128149, 10837, 10838, 10697, 10760, 10759, 128108, - 128109, 117896, 8273, 128490, 11834, 66432, 66451, 66454, 66433, 66436, - 66447, 66457, 66434, 66437, 66440, 66443, 66435, 66445, 66455, 66453, - 66450, 66444, 66461, 66456, 66441, 66458, 66442, 66439, 66449, 66448, - 66452, 66438, 66446, 66459, 66460, 66463, 9730, 9969, 9748, 128530, - 11217, 8255, 9100, 8746, 10824, 10822, 10826, 10817, 10818, 10821, - 983116, 11258, 9842, 129412, 9903, 8963, 8996, 11193, 10685, 10577, - 10573, 10572, 10575, 8597, 8616, 11021, 8661, 129113, 8691, 11109, 10622, - 8944, 8869, 10207, 117873, 117877, 117857, 128743, 117881, 118267, - 128742, 117847, 128314, 117912, 117862, 128744, 128316, 9709, 9710, - 117760, 129898, 129946, 129920, 129896, 9985, 118417, 117809, 118418, - 117810, 130020, 129924, 9600, 129937, 118275, 129938, 9690, 118292, - 129934, 118439, 118444, 9696, 129885, 129887, 129889, 129886, 129883, - 129888, 129881, 129884, 129882, 129879, 129880, 10196, 118416, 9136, - 129944, 129948, 9720, 117808, 9692, 117958, 117946, 117962, 117966, - 117950, 117954, 117928, 117926, 117942, 117970, 117938, 117813, 118421, - 118422, 118420, 117812, 118423, 117815, 129922, 9620, 129874, 129875, - 129892, 129894, 129890, 129878, 129893, 129891, 129876, 129895, 129877, - 10064, 118419, 9137, 10000, 9693, 117959, 117947, 117963, 117967, 117951, - 117955, 117929, 117927, 117943, 117971, 117939, 117814, 128319, 10066, - 129945, 129949, 9721, 117811, 129926, 129923, 118438, 118445, 129925, - 129901, 128579, 11797, 8593, 129976, 8645, 8670, 129033, 129029, 129177, - 129041, 129025, 129045, 8624, 8625, 10505, 8613, 10514, 11145, 11014, - 8657, 8673, 129077, 10606, 10595, 10592, 10584, 8639, 10588, 10580, 8638, - 129089, 129093, 129085, 10224, 128621, 129105, 129081, 11105, 11137, - 11121, 129065, 11170, 11171, 129061, 129057, 129073, 129069, 11131, - 11115, 11141, 129169, 10506, 8607, 11245, 10569, 8648, 8679, 8683, 8685, - 8684, 129173, 8682, 11192, 8686, 8687, 9797, 983117, 42509, 42510, 42511, - 42446, 42370, 42486, 42257, 42333, 42294, 42407, 42445, 42369, 42485, - 42256, 42332, 42293, 42406, 42449, 42373, 42489, 42260, 42336, 42297, - 42410, 42434, 42359, 42473, 42246, 42321, 42283, 42396, 42435, 42360, - 42474, 42247, 42322, 42284, 42397, 42452, 42376, 42492, 42263, 42339, - 42300, 42413, 42451, 42375, 42491, 42262, 42338, 42299, 42412, 42444, - 42368, 42484, 42255, 42331, 42292, 42405, 42443, 42367, 42483, 42254, - 42330, 42291, 42404, 42454, 42378, 42494, 42265, 42341, 42302, 42415, - 42453, 42377, 42493, 42264, 42340, 42301, 42414, 42439, 42440, 42364, - 42479, 42251, 42480, 42327, 42288, 42401, 42502, 42272, 42503, 42461, - 42385, 42349, 42309, 42422, 42429, 42430, 42355, 42468, 42242, 42469, - 42316, 42317, 42278, 42279, 42391, 42392, 42476, 42249, 42477, 42437, - 42362, 42324, 42325, 42286, 42399, 42459, 42383, 42346, 42347, 42499, - 42270, 42307, 42420, 42487, 42508, 42258, 42447, 42371, 42334, 42295, - 42408, 42436, 42361, 42475, 42248, 42323, 42285, 42398, 42438, 42363, - 42478, 42250, 42326, 42287, 42400, 42462, 42386, 42504, 42273, 42350, - 42310, 42423, 42450, 42514, 42539, 42512, 42513, 42538, 42374, 42490, - 42261, 42337, 42298, 42411, 42507, 42500, 42271, 42501, 42460, 42384, - 42348, 42308, 42421, 42315, 42467, 42428, 42457, 42381, 42497, 42268, - 42344, 42305, 42418, 42464, 42388, 42506, 42275, 42352, 42312, 42425, - 42463, 42387, 42505, 42274, 42351, 42311, 42424, 42455, 42379, 42495, - 42266, 42342, 42303, 42416, 42441, 42365, 42481, 42252, 42328, 42289, - 42402, 42456, 42380, 42496, 42267, 42343, 42304, 42417, 42433, 42358, - 42472, 42245, 42320, 42282, 42395, 42448, 42372, 42488, 42259, 42335, - 42296, 42409, 42442, 42366, 42482, 42253, 42329, 42290, 42403, 42458, - 42382, 42498, 42269, 42345, 42306, 42419, 42470, 42243, 42244, 42471, - 42431, 42356, 42357, 42432, 42318, 42319, 42280, 42281, 42393, 42394, - 42465, 42240, 42241, 42466, 42426, 42353, 42354, 42427, 42313, 42314, - 42276, 42277, 42389, 42390, 42523, 42526, 42522, 42515, 42520, 42527, - 42516, 42524, 42518, 42517, 42525, 42521, 42519, 42533, 42532, 42535, - 42534, 42531, 42530, 42528, 42537, 42529, 42536, 65024, 65033, 917843, - 917844, 917845, 917846, 917847, 917848, 917849, 917850, 917851, 917852, - 65034, 917853, 917854, 917855, 917856, 917857, 917858, 917859, 917860, - 917861, 917862, 65035, 917863, 917864, 917865, 917866, 917867, 917868, - 917869, 917870, 917871, 917872, 65036, 917873, 917874, 917875, 917876, - 917877, 917878, 917879, 917880, 917881, 917882, 65037, 917883, 917884, - 917885, 917886, 917887, 917888, 917889, 917890, 917891, 917892, 65038, - 917893, 917894, 917895, 917896, 917897, 917898, 917899, 917900, 917901, - 917902, 65039, 917903, 917904, 917905, 917906, 917907, 917908, 917909, - 917910, 917911, 917912, 917760, 917913, 917914, 917915, 917916, 917917, - 917918, 917919, 917920, 917921, 917922, 917761, 917923, 917924, 917925, - 917926, 917927, 917928, 917929, 917930, 917931, 917932, 917762, 917933, - 917934, 917935, 917936, 917937, 917938, 917939, 917940, 917941, 917942, - 65025, 917763, 917943, 917944, 917945, 917946, 917947, 917948, 917949, - 917950, 917951, 917952, 917764, 917953, 917954, 917955, 917956, 917957, - 917958, 917959, 917960, 917961, 917962, 917765, 917963, 917964, 917965, - 917966, 917967, 917968, 917969, 917970, 917971, 917972, 917766, 917973, - 917974, 917975, 917976, 917977, 917978, 917979, 917980, 917981, 917982, - 917767, 917983, 917984, 917985, 917986, 917987, 917988, 917989, 917990, - 917991, 917992, 917768, 917993, 917994, 917995, 917996, 917997, 917998, - 917999, 917769, 917770, 917771, 917772, 65026, 917773, 917774, 917775, - 917776, 917777, 917778, 917779, 917780, 917781, 917782, 65027, 917783, - 917784, 917785, 917786, 917787, 917788, 917789, 917790, 917791, 917792, - 65028, 917793, 917794, 917795, 917796, 917797, 917798, 917799, 917800, - 917801, 917802, 65029, 917803, 917804, 917805, 917806, 917807, 917808, - 917809, 917810, 917811, 917812, 65030, 917813, 917814, 917815, 917816, - 917817, 917818, 917819, 917820, 917821, 917822, 65031, 917823, 917824, - 917825, 917826, 917827, 917828, 917829, 917830, 917831, 917832, 65032, - 917833, 917834, 917835, 917836, 917837, 917838, 917839, 917840, 917841, - 917842, 129499, 983245, 983254, 983360, 983361, 983362, 983363, 983364, - 983365, 983366, 983367, 983368, 983369, 983255, 983370, 983371, 983372, - 983373, 983374, 983375, 983376, 983377, 983378, 983379, 983256, 983380, - 983381, 983382, 983383, 983384, 983385, 983386, 983387, 983388, 983389, - 983257, 983390, 983391, 983392, 983393, 983394, 983395, 983396, 983397, - 983398, 983399, 983258, 983400, 983401, 983402, 983403, 983404, 983405, - 983406, 983407, 983408, 983409, 983259, 983410, 983411, 983412, 983413, - 983414, 983415, 983416, 983417, 983418, 983419, 983260, 983420, 983421, - 983422, 983423, 983424, 983425, 983426, 983427, 983428, 983429, 983277, - 983430, 983431, 983432, 983433, 983434, 983435, 983436, 983437, 983438, - 983439, 983278, 983440, 983441, 983442, 983443, 983444, 983445, 983446, - 983447, 983448, 983449, 983279, 983450, 983451, 983452, 983453, 983454, - 983455, 983456, 983457, 983458, 983459, 983246, 983280, 983460, 983461, - 983462, 983463, 983464, 983465, 983466, 983467, 983468, 983469, 983281, - 983470, 983471, 983472, 983473, 983474, 983475, 983476, 983477, 983478, - 983479, 983282, 983480, 983481, 983482, 983483, 983484, 983485, 983486, - 983487, 983488, 983489, 983283, 983490, 983491, 983492, 983493, 983494, - 983495, 983496, 983497, 983498, 983499, 983284, 983500, 983501, 983502, - 983503, 983504, 983505, 983506, 983507, 983508, 983509, 983285, 983510, - 983511, 983512, 983513, 983514, 983515, 983516, 983286, 983287, 983288, - 983289, 983247, 983290, 983291, 983292, 983293, 983294, 983295, 983296, - 983297, 983298, 983299, 983248, 983300, 983301, 983302, 983303, 983304, - 983305, 983306, 983307, 983308, 983309, 983249, 983310, 983311, 983312, - 983313, 983314, 983315, 983316, 983317, 983318, 983319, 983250, 983320, - 983321, 983322, 983323, 983324, 983325, 983326, 983327, 983328, 983329, - 983251, 983330, 983331, 983332, 983333, 983334, 983335, 983336, 983337, - 983338, 983339, 983252, 983340, 983341, 983342, 983343, 983344, 983345, - 983346, 983347, 983348, 983349, 983253, 983350, 983351, 983352, 983353, - 983354, 983355, 983356, 983357, 983358, 983359, 7401, 7402, 7409, 7403, - 7404, 7415, 7410, 7418, 7413, 7379, 7398, 7396, 7411, 7408, 7406, 7407, - 7405, 7414, 7397, 7400, 7395, 7399, 7394, 7380, 7384, 7412, 7417, 7386, - 7389, 7376, 7388, 7378, 7416, 7392, 7391, 7387, 7390, 7381, 7382, 7383, - 7385, 7393, 7377, 8483, 10704, 10980, 10978, 10186, 117780, 8942, 8286, - 117917, 12347, 12337, 12339, 12341, 12338, 12340, 117892, 124, 9168, - 10992, 10991, 117904, 118293, 9087, 9896, 129904, 129905, 129906, 129907, - 129908, 129909, 117916, 117770, 11135, 983069, 983144, 11823, 128678, - 10650, 11837, 128976, 128959, 128947, 128637, 128941, 128953, 128636, - 128904, 128914, 128934, 8921, 8920, 128933, 10799, 9910, 128243, 9996, + 73140, 73141, 73149, 73154, 73155, 73150, 73151, 73156, 73171, 73166, + 73161, 73168, 73175, 73176, 73147, 73152, 73153, 73148, 73144, 73145, + 73157, 73158, 73164, 73165, 73159, 73160, 73162, 73163, 73142, 73143, + 73137, 73173, 73136, 73169, 73146, 73139, 73172, 73138, 73170, 73174, + 73167, 73177, 73178, 73179, 73189, 73188, 73191, 73190, 73187, 73186, + 73184, 73193, 73185, 73192, 127813, 128069, 129463, 129701, 129520, + 10554, 10557, 10556, 9182, 118256, 117851, 118262, 118263, 11865, 117850, + 118252, 118254, 11866, 117852, 118248, 118250, 11833, 118246, 11210, + 8992, 127913, 9180, 130024, 130016, 130031, 8988, 8975, 11810, 118279, + 8989, 8974, 11811, 130028, 9140, 9184, 128285, 127553, 127554, 127559, + 127555, 127557, 127560, 127552, 127556, 127558, 127274, 9008, 123554, + 123556, 123559, 123561, 123564, 123537, 123544, 123543, 123553, 123555, + 123558, 123560, 123546, 123565, 123563, 123539, 123541, 123550, 123549, + 123540, 123552, 123542, 123536, 123551, 123545, 123538, 123548, 123547, + 123562, 123557, 123566, 128701, 128508, 128434, 128668, 8482, 128650, + 128651, 11223, 10971, 128646, 129678, 118460, 10701, 10699, 128710, + 10698, 10141, 128681, 128208, 8227, 128305, 9783, 9776, 9777, 9782, 9779, + 9781, 9780, 9778, 10998, 10856, 10857, 10747, 8244, 8779, 10996, 10624, + 8874, 10997, 11003, 11851, 11000, 10999, 8749, 8285, 129484, 128654, + 129674, 127865, 128032, 127942, 8872, 11231, 127930, 8366, 70601, 70608, + 70613, 70612, 70610, 70528, 70529, 70542, 70545, 70559, 70558, 70564, + 70563, 70581, 70579, 70573, 70580, 70572, 70557, 70556, 70562, 70561, + 70534, 70535, 70536, 70537, 70574, 70532, 70533, 70530, 70531, 70550, + 70560, 70555, 70565, 70575, 70576, 70577, 70569, 70568, 70552, 70551, + 70549, 70548, 70554, 70553, 70547, 70546, 70567, 70566, 70544, 70539, + 70578, 70570, 70571, 70609, 70583, 70604, 70607, 70615, 70616, 70602, + 70611, 70606, 70605, 70626, 70625, 70584, 70597, 70600, 70587, 70588, + 70589, 70590, 70591, 70592, 70585, 70586, 70599, 70594, 127799, 8378, + 129411, 8523, 10658, 11202, 9930, 9929, 8498, 11826, 11832, 8587, 8586, + 128598, 128596, 8985, 128399, 8513, 8514, 8516, 11829, 8526, 128599, + 128597, 8489, 128034, 129347, 10041, 128256, 128432, 10869, 8229, 8282, + 11818, 128149, 10837, 10838, 10697, 10760, 10759, 128108, 128109, 117896, + 8273, 128490, 11834, 66432, 66451, 66454, 66433, 66436, 66447, 66457, + 66434, 66437, 66440, 66443, 66435, 66445, 66455, 66453, 66450, 66444, + 66461, 66456, 66441, 66458, 66442, 66439, 66449, 66448, 66452, 66438, + 66446, 66459, 66460, 66463, 9730, 9969, 9748, 128530, 11217, 8255, 9100, + 8746, 10824, 10822, 10826, 10817, 10818, 10821, 983116, 11258, 9842, + 129412, 9903, 8963, 8996, 11193, 10685, 10577, 10573, 10572, 10575, 8597, + 8616, 11021, 8661, 129113, 8691, 11109, 10622, 8944, 8869, 10207, 117873, + 117877, 117857, 128743, 117881, 118267, 128742, 117847, 128314, 117912, + 117862, 128744, 128316, 9709, 9710, 117760, 129898, 129946, 129920, + 129896, 9985, 118417, 117809, 118418, 117810, 130020, 129924, 9600, + 129937, 118275, 129938, 9690, 118292, 129934, 118439, 118444, 9696, + 129885, 129887, 129889, 129886, 129883, 129888, 129881, 129884, 129882, + 129879, 129880, 10196, 118416, 9136, 129944, 129948, 9720, 117808, 9692, + 117958, 117946, 117962, 117966, 117950, 117954, 117928, 117926, 117942, + 117970, 117938, 117813, 118421, 118422, 118420, 117812, 118423, 117815, + 129922, 9620, 129874, 129875, 129892, 129894, 129890, 129878, 129893, + 129891, 129876, 129895, 129877, 10064, 118419, 9137, 10000, 9693, 117959, + 117947, 117963, 117967, 117951, 117955, 117929, 117927, 117943, 117971, + 117939, 117814, 128319, 10066, 129945, 129949, 9721, 117811, 129926, + 129923, 118438, 118445, 129925, 129901, 128579, 11797, 8593, 129976, + 8645, 8670, 129033, 129029, 129177, 129041, 129025, 129045, 8624, 8625, + 10505, 8613, 10514, 11145, 11014, 8657, 8673, 129077, 10606, 10595, + 10592, 10584, 8639, 10588, 10580, 8638, 129089, 129093, 129085, 10224, + 128621, 129105, 129081, 11105, 11137, 11121, 129065, 11170, 11171, + 129061, 129057, 129073, 129069, 11131, 11115, 11141, 129169, 10506, 8607, + 11245, 10569, 8648, 8679, 8683, 8685, 8684, 129173, 8682, 11192, 8686, + 8687, 9797, 983117, 42509, 42510, 42511, 42446, 42370, 42486, 42257, + 42333, 42294, 42407, 42445, 42369, 42485, 42256, 42332, 42293, 42406, + 42449, 42373, 42489, 42260, 42336, 42297, 42410, 42434, 42359, 42473, + 42246, 42321, 42283, 42396, 42435, 42360, 42474, 42247, 42322, 42284, + 42397, 42452, 42376, 42492, 42263, 42339, 42300, 42413, 42451, 42375, + 42491, 42262, 42338, 42299, 42412, 42444, 42368, 42484, 42255, 42331, + 42292, 42405, 42443, 42367, 42483, 42254, 42330, 42291, 42404, 42454, + 42378, 42494, 42265, 42341, 42302, 42415, 42453, 42377, 42493, 42264, + 42340, 42301, 42414, 42439, 42440, 42364, 42479, 42251, 42480, 42327, + 42288, 42401, 42502, 42272, 42503, 42461, 42385, 42349, 42309, 42422, + 42429, 42430, 42355, 42468, 42242, 42469, 42316, 42317, 42278, 42279, + 42391, 42392, 42476, 42249, 42477, 42437, 42362, 42324, 42325, 42286, + 42399, 42459, 42383, 42346, 42347, 42499, 42270, 42307, 42420, 42487, + 42508, 42258, 42447, 42371, 42334, 42295, 42408, 42436, 42361, 42475, + 42248, 42323, 42285, 42398, 42438, 42363, 42478, 42250, 42326, 42287, + 42400, 42462, 42386, 42504, 42273, 42350, 42310, 42423, 42450, 42514, + 42539, 42512, 42513, 42538, 42374, 42490, 42261, 42337, 42298, 42411, + 42507, 42500, 42271, 42501, 42460, 42384, 42348, 42308, 42421, 42315, + 42467, 42428, 42457, 42381, 42497, 42268, 42344, 42305, 42418, 42464, + 42388, 42506, 42275, 42352, 42312, 42425, 42463, 42387, 42505, 42274, + 42351, 42311, 42424, 42455, 42379, 42495, 42266, 42342, 42303, 42416, + 42441, 42365, 42481, 42252, 42328, 42289, 42402, 42456, 42380, 42496, + 42267, 42343, 42304, 42417, 42433, 42358, 42472, 42245, 42320, 42282, + 42395, 42448, 42372, 42488, 42259, 42335, 42296, 42409, 42442, 42366, + 42482, 42253, 42329, 42290, 42403, 42458, 42382, 42498, 42269, 42345, + 42306, 42419, 42470, 42243, 42244, 42471, 42431, 42356, 42357, 42432, + 42318, 42319, 42280, 42281, 42393, 42394, 42465, 42240, 42241, 42466, + 42426, 42353, 42354, 42427, 42313, 42314, 42276, 42277, 42389, 42390, + 42523, 42526, 42522, 42515, 42520, 42527, 42516, 42524, 42518, 42517, + 42525, 42521, 42519, 42533, 42532, 42535, 42534, 42531, 42530, 42528, + 42537, 42529, 42536, 65024, 65033, 917843, 917844, 917845, 917846, + 917847, 917848, 917849, 917850, 917851, 917852, 65034, 917853, 917854, + 917855, 917856, 917857, 917858, 917859, 917860, 917861, 917862, 65035, + 917863, 917864, 917865, 917866, 917867, 917868, 917869, 917870, 917871, + 917872, 65036, 917873, 917874, 917875, 917876, 917877, 917878, 917879, + 917880, 917881, 917882, 65037, 917883, 917884, 917885, 917886, 917887, + 917888, 917889, 917890, 917891, 917892, 65038, 917893, 917894, 917895, + 917896, 917897, 917898, 917899, 917900, 917901, 917902, 65039, 917903, + 917904, 917905, 917906, 917907, 917908, 917909, 917910, 917911, 917912, + 917760, 917913, 917914, 917915, 917916, 917917, 917918, 917919, 917920, + 917921, 917922, 917761, 917923, 917924, 917925, 917926, 917927, 917928, + 917929, 917930, 917931, 917932, 917762, 917933, 917934, 917935, 917936, + 917937, 917938, 917939, 917940, 917941, 917942, 65025, 917763, 917943, + 917944, 917945, 917946, 917947, 917948, 917949, 917950, 917951, 917952, + 917764, 917953, 917954, 917955, 917956, 917957, 917958, 917959, 917960, + 917961, 917962, 917765, 917963, 917964, 917965, 917966, 917967, 917968, + 917969, 917970, 917971, 917972, 917766, 917973, 917974, 917975, 917976, + 917977, 917978, 917979, 917980, 917981, 917982, 917767, 917983, 917984, + 917985, 917986, 917987, 917988, 917989, 917990, 917991, 917992, 917768, + 917993, 917994, 917995, 917996, 917997, 917998, 917999, 917769, 917770, + 917771, 917772, 65026, 917773, 917774, 917775, 917776, 917777, 917778, + 917779, 917780, 917781, 917782, 65027, 917783, 917784, 917785, 917786, + 917787, 917788, 917789, 917790, 917791, 917792, 65028, 917793, 917794, + 917795, 917796, 917797, 917798, 917799, 917800, 917801, 917802, 65029, + 917803, 917804, 917805, 917806, 917807, 917808, 917809, 917810, 917811, + 917812, 65030, 917813, 917814, 917815, 917816, 917817, 917818, 917819, + 917820, 917821, 917822, 65031, 917823, 917824, 917825, 917826, 917827, + 917828, 917829, 917830, 917831, 917832, 65032, 917833, 917834, 917835, + 917836, 917837, 917838, 917839, 917840, 917841, 917842, 129499, 983245, + 983254, 983364, 983365, 983366, 983367, 983368, 983369, 983370, 983371, + 983372, 983373, 983255, 983374, 983375, 983376, 983377, 983378, 983379, + 983380, 983381, 983382, 983383, 983256, 983384, 983385, 983386, 983387, + 983388, 983389, 983390, 983391, 983392, 983393, 983257, 983394, 983395, + 983396, 983397, 983398, 983399, 983400, 983401, 983402, 983403, 983258, + 983404, 983405, 983406, 983407, 983408, 983409, 983410, 983411, 983412, + 983413, 983259, 983414, 983415, 983416, 983417, 983418, 983419, 983420, + 983421, 983422, 983423, 983260, 983424, 983425, 983426, 983427, 983428, + 983429, 983430, 983431, 983432, 983433, 983281, 983434, 983435, 983436, + 983437, 983438, 983439, 983440, 983441, 983442, 983443, 983282, 983444, + 983445, 983446, 983447, 983448, 983449, 983450, 983451, 983452, 983453, + 983283, 983454, 983455, 983456, 983457, 983458, 983459, 983460, 983461, + 983462, 983463, 983246, 983284, 983464, 983465, 983466, 983467, 983468, + 983469, 983470, 983471, 983472, 983473, 983285, 983474, 983475, 983476, + 983477, 983478, 983479, 983480, 983481, 983482, 983483, 983286, 983484, + 983485, 983486, 983487, 983488, 983489, 983490, 983491, 983492, 983493, + 983287, 983494, 983495, 983496, 983497, 983498, 983499, 983500, 983501, + 983502, 983503, 983288, 983504, 983505, 983506, 983507, 983508, 983509, + 983510, 983511, 983512, 983513, 983289, 983514, 983515, 983516, 983517, + 983518, 983519, 983520, 983290, 983291, 983292, 983293, 983247, 983294, + 983295, 983296, 983297, 983298, 983299, 983300, 983301, 983302, 983303, + 983248, 983304, 983305, 983306, 983307, 983308, 983309, 983310, 983311, + 983312, 983313, 983249, 983314, 983315, 983316, 983317, 983318, 983319, + 983320, 983321, 983322, 983323, 983250, 983324, 983325, 983326, 983327, + 983328, 983329, 983330, 983331, 983332, 983333, 983251, 983334, 983335, + 983336, 983337, 983338, 983339, 983340, 983341, 983342, 983343, 983252, + 983344, 983345, 983346, 983347, 983348, 983349, 983350, 983351, 983352, + 983353, 983253, 983354, 983355, 983356, 983357, 983358, 983359, 983360, + 983361, 983362, 983363, 7401, 7402, 7409, 7403, 7404, 7415, 7410, 7418, + 7413, 7379, 7398, 7396, 7411, 7408, 7406, 7407, 7405, 7414, 7397, 7400, + 7395, 7399, 7394, 7380, 7384, 7412, 7417, 7386, 7389, 7376, 7388, 7378, + 7416, 7392, 7391, 7387, 7390, 7381, 7382, 7383, 7385, 7393, 7377, 8483, + 10704, 10980, 10978, 10186, 117780, 8942, 8286, 117917, 12347, 12337, + 12339, 12341, 12338, 12340, 117892, 124, 9168, 10992, 10991, 117904, + 118293, 9087, 9896, 129904, 129905, 129906, 129907, 129908, 129909, + 117916, 117770, 11135, 983069, 983144, 11823, 128678, 10650, 11837, + 128976, 128959, 128947, 128637, 128941, 128953, 128636, 128904, 128914, + 128934, 8921, 8920, 128933, 9910, 128887, 10799, 128243, 9996, 118469, 128249, 127918, 128252, 94193, 94192, 8983, 127931, 9805, 66929, 66930, 66936, 66935, 66942, 66943, 66947, 66946, 66950, 66949, 66932, 66931, 66934, 66933, 66957, 66956, 66959, 66958, 66941, 66940, 66937, 66944, @@ -13095,193 +13249,194 @@ static const unsigned int dawg_pos_to_codepoint[] = { 71920, 71919, 71916, 71915, 71914, 71935, 9888, 128702, 127754, 128003, 129341, 127817, 8986, 12316, 11071, 10547, 127988, 127987, 128075, 12336, 65103, 8967, 65099, 128465, 128576, 128553, 10172, 128146, 983238, - 127947, 9840, 128734, 9784, 9855, 129197, 129196, 9702, 9815, 129548, - 129590, 129608, 129611, 9812, 129545, 129587, 9816, 129542, 129563, - 129584, 129591, 129605, 129549, 129616, 129614, 129615, 9817, 129550, - 129592, 9813, 129546, 129588, 9814, 129547, 129589, 129569, 129566, - 129570, 129571, 129567, 129568, 9675, 128906, 9862, 10732, 9863, 9717, - 9718, 9716, 9719, 9831, 10209, 10210, 10211, 129995, 9671, 9672, 128922, - 128923, 10192, 9826, 9931, 128071, 128407, 9759, 9663, 9661, 9920, 9921, - 10069, 9872, 9983, 10048, 128174, 11214, 10023, 9785, 128427, 129293, - 9825, 9989, 129984, 11041, 11053, 10710, 11036, 128326, 9945, 128072, - 9756, 9669, 9667, 9665, 117894, 117895, 128928, 11046, 11088, 9725, 9723, - 11048, 11229, 10001, 9649, 11040, 127985, 10068, 9645, 11092, 9659, 9657, - 9655, 128073, 9758, 9988, 65094, 9750, 11051, 11090, 9643, 9786, 9828, - 9633, 128307, 128916, 9635, 128917, 10212, 9713, 9714, 10213, 9634, 9712, - 9715, 9707, 9093, 127779, 127781, 127782, 9788, 127780, 9734, 128382, - 9743, 9186, 10177, 9943, 128070, 9757, 129994, 9653, 9651, 9708, 11055, - 9647, 118278, 11006, 11038, 10163, 128011, 129144, 129152, 129120, + 127947, 9840, 128734, 9784, 9855, 129197, 129196, 9702, 129621, 9815, + 129548, 129590, 129608, 129611, 129620, 9812, 129545, 129587, 9816, + 129542, 129563, 129584, 129591, 129605, 129549, 129616, 129614, 129615, + 9817, 129550, 129592, 9813, 129546, 129588, 9814, 129547, 129589, 129569, + 129566, 129570, 129571, 129567, 129568, 9675, 128906, 9862, 10732, 9863, + 9717, 9718, 9716, 9719, 9831, 10209, 10210, 10211, 129995, 9671, 9672, + 128922, 128923, 10192, 9826, 9931, 128071, 128407, 9759, 9663, 9661, + 9920, 9921, 10069, 9872, 9983, 10048, 128174, 11214, 10023, 9785, 128427, + 129293, 9825, 9989, 129984, 11041, 11053, 10710, 11036, 128326, 9945, + 128072, 9756, 9669, 9667, 9665, 117894, 117895, 128928, 11046, 11088, + 9725, 9723, 11048, 11229, 10001, 9649, 11040, 127985, 10068, 9645, 11092, + 9659, 9657, 9655, 128073, 9758, 9988, 65094, 9750, 11051, 11090, 9643, + 9786, 9828, 9633, 128307, 128916, 9635, 128917, 10212, 9713, 9714, 10213, + 9634, 9712, 9715, 9707, 9093, 127779, 127781, 127782, 9788, 127780, 9734, + 128382, 9743, 9186, 10177, 9943, 128070, 9757, 129994, 9653, 9651, 9708, + 11055, 9647, 118278, 11006, 11038, 10163, 128011, 129144, 129152, 129120, 129136, 129128, 129146, 129154, 129122, 129138, 129130, 129147, 129155, 129123, 129139, 129131, 129145, 129153, 129121, 129137, 129129, 129149, 129157, 129125, 129141, 129133, 129148, 129156, 129124, 129140, 129132, 129150, 129158, 129126, 129142, 129134, 129151, 129159, 129127, 129143, 129135, 11838, 129344, 127888, 127788, 129695, 127863, 128521, 129725, - 128430, 128732, 128105, 128111, 128098, 128090, 128082, 128097, 128698, + 128430, 128732, 128105, 128111, 128098, 128090, 128097, 128082, 128698, 11825, 8288, 128506, 128543, 129713, 8361, 129717, 128058, 127873, 8768, 129340, 128295, 9997, 983233, 8999, 129659, 129644, 129643, 129641, 129639, 129642, 129645, 129640, 129637, 129636, 129634, 129632, 129635, - 129638, 129633, 8891, 129393, 128155, 165, 69292, 69291, 69293, 69256, - 69255, 69254, 69281, 69268, 69259, 69248, 69271, 69289, 69286, 69287, - 69257, 69278, 69277, 69279, 69276, 69280, 69296, 69282, 69251, 69250, - 69266, 69265, 69267, 69253, 69252, 69269, 69274, 69275, 69284, 69285, - 69272, 69258, 69288, 69297, 69263, 69260, 69270, 69262, 69261, 69249, - 69283, 69273, 69264, 42139, 42149, 42173, 42172, 42132, 42147, 42179, - 42174, 42148, 42169, 42150, 42134, 42166, 42135, 42145, 42143, 42137, - 42175, 42157, 42154, 42167, 42165, 42163, 42130, 42182, 42129, 42171, - 42138, 42140, 42136, 42131, 42151, 42164, 42181, 42142, 42156, 42170, - 42176, 42178, 42160, 42133, 42144, 42152, 42159, 42161, 42158, 42141, - 42146, 42177, 42180, 42155, 42162, 42128, 42168, 42153, 41070, 41059, - 41060, 41058, 41073, 41072, 41071, 41068, 41069, 41066, 41067, 41065, - 41048, 41052, 41053, 41050, 41051, 41049, 41046, 41047, 41056, 41057, - 41054, 41055, 41063, 41064, 41061, 41062, 41076, 41077, 41074, 41075, - 41006, 40995, 40996, 40994, 41009, 41008, 41007, 41004, 41005, 41002, - 41003, 41001, 40984, 40988, 40989, 40986, 40987, 40985, 40982, 40983, - 40992, 40993, 40990, 40991, 40999, 41000, 40997, 40998, 41012, 41015, - 41014, 41013, 41010, 41011, 41842, 41831, 41832, 41829, 41830, 41845, - 41844, 41843, 41841, 41827, 41828, 41825, 41826, 41839, 41840, 41837, - 41838, 41835, 41836, 41833, 41834, 41848, 41851, 41850, 41849, 41846, - 41847, 41670, 41659, 41660, 41658, 41673, 41672, 41671, 41668, 41669, - 41666, 41667, 41665, 41648, 41652, 41653, 41650, 41651, 41649, 41646, - 41647, 41656, 41657, 41654, 41655, 41663, 41664, 41661, 41662, 41676, - 41679, 41678, 41677, 41674, 41675, 41293, 41282, 41283, 41281, 41296, - 41295, 41294, 41291, 41292, 41272, 41275, 41276, 41274, 41273, 41270, - 41271, 41289, 41290, 41288, 41279, 41280, 41277, 41278, 41286, 41287, - 41284, 41285, 41238, 41228, 41227, 41241, 41240, 41239, 41236, 41237, - 41218, 41221, 41222, 41220, 41219, 41216, 41217, 41234, 41235, 41233, - 41225, 41226, 41223, 41224, 41231, 41232, 41229, 41230, 41174, 41175, - 41173, 41171, 41172, 41169, 41170, 41167, 41168, 41165, 41166, 41184, - 41185, 41182, 41183, 41178, 41181, 41180, 41179, 41176, 41177, 41494, - 41496, 41497, 41495, 41492, 41493, 41516, 41504, 41505, 41502, 41503, - 41519, 41518, 41517, 41514, 41515, 41500, 41501, 41498, 41499, 41512, - 41513, 41510, 41511, 41508, 41509, 41506, 41507, 41460, 41448, 41449, - 41446, 41447, 41463, 41462, 41461, 41458, 41459, 41436, 41440, 41441, - 41438, 41439, 41437, 41434, 41435, 41444, 41445, 41442, 41443, 41456, - 41457, 41454, 41455, 41452, 41453, 41450, 41451, 41584, 41583, 41582, - 41389, 41379, 41380, 41378, 41392, 41391, 41390, 41387, 41388, 41369, - 41372, 41373, 41371, 41370, 41367, 41368, 41385, 41386, 41384, 41382, - 41383, 41381, 41376, 41377, 41374, 41375, 41395, 41398, 41397, 41396, - 41393, 41394, 41125, 41117, 41118, 41116, 41128, 41127, 41126, 41123, - 41124, 41107, 41110, 41111, 41109, 41108, 41105, 41106, 41114, 41115, - 41112, 41113, 41121, 41122, 41119, 41120, 41130, 41133, 41132, 41131, - 41129, 41336, 41334, 41335, 41333, 41332, 41340, 41338, 41339, 41337, - 41322, 41326, 41327, 41324, 41325, 41323, 41320, 41321, 41330, 41331, - 41328, 41329, 41556, 41557, 41554, 41555, 41563, 41564, 41562, 41544, - 41548, 41549, 41546, 41547, 41545, 41542, 41543, 41552, 41553, 41550, - 41551, 41560, 41561, 41558, 41559, 41591, 41592, 41589, 41590, 41598, - 41599, 41597, 41587, 41588, 41585, 41586, 41595, 41596, 41593, 41594, - 40962, 40960, 983243, 40966, 40967, 40964, 40965, 40963, 40961, 42025, - 42017, 42018, 42016, 42028, 42027, 42026, 42023, 42024, 42010, 42014, - 42015, 42012, 42013, 42011, 42008, 42009, 42021, 42022, 42019, 42020, - 42031, 42032, 42029, 42030, 41970, 41962, 41963, 41960, 41961, 41973, - 41972, 41971, 41968, 41969, 41954, 41958, 41959, 41956, 41957, 41955, - 41952, 41953, 41966, 41967, 41964, 41965, 41976, 41979, 41978, 41977, - 41974, 41975, 41488, 41476, 41477, 41475, 41491, 41490, 41489, 41486, - 41487, 41466, 41469, 41470, 41468, 41467, 41464, 41465, 41473, 41474, - 41471, 41472, 41484, 41485, 41482, 41483, 41480, 41481, 41478, 41479, - 41424, 41413, 41414, 41411, 41412, 41427, 41426, 41425, 41422, 41423, - 41420, 41421, 41419, 41401, 41405, 41406, 41403, 41404, 41402, 41399, - 41400, 41409, 41410, 41407, 41408, 41417, 41418, 41415, 41416, 41430, - 41433, 41432, 41431, 41428, 41429, 41538, 41527, 41528, 41526, 41541, - 41540, 41539, 41536, 41537, 41534, 41535, 41533, 41524, 41525, 41522, - 41523, 41531, 41532, 41529, 41530, 41521, 41520, 41157, 41147, 41148, - 41145, 41146, 41160, 41159, 41158, 41155, 41156, 41136, 41139, 41140, - 41138, 41137, 41134, 41135, 41143, 41144, 41141, 41142, 41151, 41152, - 41149, 41150, 41163, 41164, 41161, 41162, 41154, 41153, 41080, 41083, - 41084, 41082, 41081, 41078, 41079, 41087, 41088, 41085, 41086, 41091, - 41092, 41089, 41090, 41095, 41098, 41097, 41096, 41093, 41094, 41101, - 41104, 41103, 41102, 41099, 41100, 41299, 41302, 41301, 41300, 41297, - 41298, 41312, 41313, 41311, 41305, 41306, 41303, 41304, 41309, 41310, - 41307, 41308, 41316, 41319, 41318, 41317, 41314, 41315, 41574, 41572, - 41573, 41580, 41581, 41579, 41566, 41567, 41565, 41570, 41571, 41568, - 41569, 41577, 41578, 41575, 41576, 42048, 42042, 42041, 42051, 42050, - 42049, 42047, 42035, 42039, 42040, 42037, 42038, 42036, 42033, 42034, - 42045, 42046, 42043, 42044, 42054, 42057, 42056, 42055, 42052, 42053, - 41881, 41882, 41880, 41878, 41879, 41876, 41877, 41885, 41886, 41883, - 41884, 41889, 41892, 41891, 41890, 41887, 41888, 41895, 41898, 41897, - 41896, 41893, 41894, 42075, 42067, 42068, 42066, 42076, 42073, 42074, - 42060, 42064, 42065, 42062, 42063, 42061, 42058, 42059, 42071, 42072, - 42069, 42070, 41727, 41721, 41720, 41730, 41729, 41728, 41726, 41723, - 41722, 41711, 41714, 41715, 41713, 41712, 41709, 41710, 41718, 41719, - 41716, 41717, 41733, 41736, 41735, 41734, 41731, 41732, 41725, 41724, - 41363, 41352, 41353, 41351, 41366, 41365, 41364, 41361, 41362, 41343, - 41346, 41347, 41345, 41344, 41341, 41342, 41349, 41350, 41348, 41359, - 41360, 41358, 41356, 41357, 41354, 41355, 41036, 41028, 41029, 41027, - 41039, 41038, 41037, 41034, 41035, 41018, 41021, 41022, 41020, 41019, - 41016, 41017, 41025, 41026, 41023, 41024, 41032, 41033, 41030, 41031, - 41042, 41045, 41044, 41043, 41040, 41041, 41998, 41990, 41991, 41988, - 41989, 42001, 42000, 41999, 41996, 41997, 41982, 41986, 41987, 41984, - 41985, 41983, 41980, 41981, 41994, 41995, 41992, 41993, 42004, 42007, - 42006, 42005, 42002, 42003, 42115, 42107, 42108, 42105, 42106, 42118, - 42117, 42116, 42113, 42114, 42099, 42103, 42104, 42101, 42102, 42100, - 42097, 42098, 42111, 42112, 42109, 42110, 42121, 42124, 42123, 42122, - 42119, 42120, 41866, 41855, 41854, 41869, 41868, 41867, 41864, 41865, - 41862, 41863, 41860, 41861, 41858, 41859, 41856, 41857, 41872, 41875, - 41874, 41873, 41870, 41871, 41853, 41852, 41942, 41931, 41932, 41930, - 41945, 41944, 41943, 41940, 41941, 41938, 41939, 41937, 41928, 41929, - 41926, 41927, 41935, 41936, 41933, 41934, 41948, 41951, 41950, 41949, - 41946, 41947, 41772, 41775, 41776, 41774, 41773, 41770, 41771, 41786, - 41787, 41785, 41779, 41780, 41777, 41778, 41783, 41784, 41781, 41782, - 41790, 41791, 41788, 41789, 41794, 41797, 41796, 41795, 41792, 41793, - 41916, 41904, 41905, 41903, 41919, 41918, 41917, 41914, 41915, 41901, - 41902, 41899, 41900, 41912, 41913, 41910, 41911, 41908, 41909, 41906, - 41907, 41922, 41925, 41924, 41923, 41920, 41921, 41760, 41749, 41750, - 41748, 41763, 41762, 41761, 41758, 41759, 41739, 41742, 41743, 41741, - 41740, 41737, 41738, 41756, 41757, 41755, 41746, 41747, 41744, 41745, - 41753, 41754, 41751, 41752, 41766, 41769, 41768, 41767, 41764, 41765, - 41266, 41255, 41256, 41253, 41254, 41269, 41268, 41267, 41264, 41265, - 41244, 41247, 41248, 41246, 41245, 41242, 41243, 41262, 41263, 41261, - 41251, 41252, 41249, 41250, 41259, 41260, 41257, 41258, 41203, 41202, - 41188, 41192, 41193, 41190, 41191, 41189, 41186, 41187, 41196, 41197, - 41194, 41195, 41200, 41201, 41198, 41199, 41206, 41209, 41208, 41207, - 41204, 41205, 41212, 41215, 41214, 41213, 41210, 41211, 40981, 41605, - 41606, 41604, 41611, 41612, 41610, 41608, 41609, 41607, 41602, 41603, - 41600, 41601, 42079, 42083, 42084, 42081, 42082, 42080, 42077, 42078, - 42089, 42090, 42087, 42088, 42093, 42096, 42095, 42094, 42091, 42092, - 42086, 42085, 41815, 41803, 41804, 41802, 41818, 41817, 41816, 41813, - 41814, 41800, 41801, 41798, 41799, 41811, 41812, 41809, 41810, 41807, - 41808, 41805, 41806, 41821, 41824, 41823, 41822, 41819, 41820, 41636, - 41625, 41626, 41624, 41639, 41638, 41637, 41634, 41635, 41615, 41618, - 41619, 41617, 41616, 41613, 41614, 41696, 41697, 41695, 41693, 41694, - 41692, 41682, 41686, 41687, 41684, 41685, 41683, 41680, 41681, 41690, - 41691, 41688, 41689, 41699, 41702, 41701, 41700, 41698, 41705, 41708, - 41707, 41706, 41703, 41704, 41632, 41633, 41631, 41622, 41623, 41620, - 41621, 41629, 41630, 41627, 41628, 41642, 41645, 41644, 41643, 41640, - 41641, 40973, 40974, 40972, 40970, 40971, 40968, 40969, 40977, 40978, - 40975, 40976, 40980, 40979, 9775, 129664, 8959, 10853, 10632, 10634, - 10814, 10852, 10631, 10633, 10783, 10784, 10785, 10625, 10626, 72262, - 72256, 72253, 72252, 72254, 72251, 72250, 72261, 72255, 72243, 72215, - 72214, 72230, 72229, 72220, 72219, 72242, 72204, 72203, 72207, 72216, - 72211, 72221, 72238, 72239, 72240, 72228, 72227, 72213, 72212, 72218, - 72217, 72225, 72224, 72209, 72208, 72206, 72205, 72223, 72222, 72231, - 72232, 72233, 72241, 72210, 72236, 72226, 72235, 72237, 72234, 72192, - 72259, 72258, 72260, 72257, 72248, 72245, 72246, 72247, 72244, 72249, - 72263, 72202, 72199, 72200, 72198, 72197, 72195, 72194, 72201, 72196, - 72193, 129427, 65279, 8204, 8203, 8205, 11234, 129296, 118593, 118584, - 118585, 118591, 118580, 118589, 118528, 118540, 118531, 118543, 118559, - 118529, 118541, 118532, 118544, 118592, 118573, 118569, 118568, 118581, - 118586, 118561, 118582, 118583, 118566, 118538, 118550, 118555, 118556, - 118535, 118547, 118537, 118549, 118553, 118558, 118534, 118546, 118572, - 118562, 118571, 118554, 118533, 118545, 118587, 118588, 118530, 118542, - 118552, 118563, 118539, 118551, 118557, 118536, 118548, 118579, 118570, - 118560, 118567, 118565, 118564, 118590, 118576, 118577, 118578, 118619, - 118639, 118637, 118645, 118721, 118611, 118635, 118659, 118626, 118623, - 118625, 118624, 118622, 118638, 118612, 118660, 118608, 118609, 118657, - 118719, 118695, 118699, 118698, 118697, 118696, 118722, 118720, 118703, - 118708, 118707, 118706, 118705, 118704, 118610, 118620, 118723, 118616, - 118617, 118640, 118672, 118636, 118658, 118652, 118651, 118649, 118650, - 118648, 118646, 118647, 118644, 118643, 118641, 118642, 118653, 118656, - 118654, 118655, 118662, 118670, 118664, 118666, 118669, 118663, 118665, - 118671, 118667, 118668, 118673, 118614, 118615, 118618, 118685, 118687, - 118684, 118683, 118686, 118681, 118680, 118709, 118713, 118711, 118716, - 118717, 118714, 118715, 118712, 118718, 118710, 118676, 118679, 118690, - 118688, 118693, 118694, 118691, 118692, 118689, 118675, 118677, 118678, - 118674, 118701, 118702, 118700, 118682, 118632, 118631, 118634, 118633, - 118628, 118627, 118630, 118629, 118613, 118621, 118661, 118596, 118597, - 118594, 118595, 118598, 129503, 983264, 983222, 983221, 983223, + 129638, 129633, 8891, 94196, 94197, 94198, 129393, 128155, 165, 69292, + 69291, 69293, 69256, 69255, 69254, 69281, 69268, 69259, 69248, 69271, + 69289, 69286, 69287, 69257, 69278, 69277, 69279, 69276, 69280, 69296, + 69282, 69251, 69250, 69266, 69265, 69267, 69253, 69252, 69269, 69274, + 69275, 69284, 69285, 69272, 69258, 69288, 69297, 69263, 69260, 69270, + 69262, 69261, 69249, 69283, 69273, 69264, 42139, 42149, 42173, 42172, + 42132, 42147, 42179, 42174, 42148, 42169, 42150, 42134, 42166, 42135, + 42145, 42143, 42137, 42175, 42157, 42154, 42167, 42165, 42163, 42130, + 42182, 42129, 42171, 42138, 42140, 42136, 42131, 42151, 42164, 42181, + 42142, 42156, 42170, 42176, 42178, 42160, 42133, 42144, 42152, 42159, + 42161, 42158, 42141, 42146, 42177, 42180, 42155, 42162, 42128, 42168, + 42153, 41070, 41059, 41060, 41058, 41073, 41072, 41071, 41068, 41069, + 41066, 41067, 41065, 41048, 41052, 41053, 41050, 41051, 41049, 41046, + 41047, 41056, 41057, 41054, 41055, 41063, 41064, 41061, 41062, 41076, + 41077, 41074, 41075, 41006, 40995, 40996, 40994, 41009, 41008, 41007, + 41004, 41005, 41002, 41003, 41001, 40984, 40988, 40989, 40986, 40987, + 40985, 40982, 40983, 40992, 40993, 40990, 40991, 40999, 41000, 40997, + 40998, 41012, 41015, 41014, 41013, 41010, 41011, 41842, 41831, 41832, + 41829, 41830, 41845, 41844, 41843, 41841, 41827, 41828, 41825, 41826, + 41839, 41840, 41837, 41838, 41835, 41836, 41833, 41834, 41848, 41851, + 41850, 41849, 41846, 41847, 41670, 41659, 41660, 41658, 41673, 41672, + 41671, 41668, 41669, 41666, 41667, 41665, 41648, 41652, 41653, 41650, + 41651, 41649, 41646, 41647, 41656, 41657, 41654, 41655, 41663, 41664, + 41661, 41662, 41676, 41679, 41678, 41677, 41674, 41675, 41293, 41282, + 41283, 41281, 41296, 41295, 41294, 41291, 41292, 41272, 41275, 41276, + 41274, 41273, 41270, 41271, 41289, 41290, 41288, 41279, 41280, 41277, + 41278, 41286, 41287, 41284, 41285, 41238, 41228, 41227, 41241, 41240, + 41239, 41236, 41237, 41218, 41221, 41222, 41220, 41219, 41216, 41217, + 41234, 41235, 41233, 41225, 41226, 41223, 41224, 41231, 41232, 41229, + 41230, 41174, 41175, 41173, 41171, 41172, 41169, 41170, 41167, 41168, + 41165, 41166, 41184, 41185, 41182, 41183, 41178, 41181, 41180, 41179, + 41176, 41177, 41494, 41496, 41497, 41495, 41492, 41493, 41516, 41504, + 41505, 41502, 41503, 41519, 41518, 41517, 41514, 41515, 41500, 41501, + 41498, 41499, 41512, 41513, 41510, 41511, 41508, 41509, 41506, 41507, + 41460, 41448, 41449, 41446, 41447, 41463, 41462, 41461, 41458, 41459, + 41436, 41440, 41441, 41438, 41439, 41437, 41434, 41435, 41444, 41445, + 41442, 41443, 41456, 41457, 41454, 41455, 41452, 41453, 41450, 41451, + 41584, 41583, 41582, 41389, 41379, 41380, 41378, 41392, 41391, 41390, + 41387, 41388, 41369, 41372, 41373, 41371, 41370, 41367, 41368, 41385, + 41386, 41384, 41382, 41383, 41381, 41376, 41377, 41374, 41375, 41395, + 41398, 41397, 41396, 41393, 41394, 41125, 41117, 41118, 41116, 41128, + 41127, 41126, 41123, 41124, 41107, 41110, 41111, 41109, 41108, 41105, + 41106, 41114, 41115, 41112, 41113, 41121, 41122, 41119, 41120, 41130, + 41133, 41132, 41131, 41129, 41336, 41334, 41335, 41333, 41332, 41340, + 41338, 41339, 41337, 41322, 41326, 41327, 41324, 41325, 41323, 41320, + 41321, 41330, 41331, 41328, 41329, 41556, 41557, 41554, 41555, 41563, + 41564, 41562, 41544, 41548, 41549, 41546, 41547, 41545, 41542, 41543, + 41552, 41553, 41550, 41551, 41560, 41561, 41558, 41559, 41591, 41592, + 41589, 41590, 41598, 41599, 41597, 41587, 41588, 41585, 41586, 41595, + 41596, 41593, 41594, 40962, 40960, 983243, 40966, 40967, 40964, 40965, + 40963, 40961, 42025, 42017, 42018, 42016, 42028, 42027, 42026, 42023, + 42024, 42010, 42014, 42015, 42012, 42013, 42011, 42008, 42009, 42021, + 42022, 42019, 42020, 42031, 42032, 42029, 42030, 41970, 41962, 41963, + 41960, 41961, 41973, 41972, 41971, 41968, 41969, 41954, 41958, 41959, + 41956, 41957, 41955, 41952, 41953, 41966, 41967, 41964, 41965, 41976, + 41979, 41978, 41977, 41974, 41975, 41488, 41476, 41477, 41475, 41491, + 41490, 41489, 41486, 41487, 41466, 41469, 41470, 41468, 41467, 41464, + 41465, 41473, 41474, 41471, 41472, 41484, 41485, 41482, 41483, 41480, + 41481, 41478, 41479, 41424, 41413, 41414, 41411, 41412, 41427, 41426, + 41425, 41422, 41423, 41420, 41421, 41419, 41401, 41405, 41406, 41403, + 41404, 41402, 41399, 41400, 41409, 41410, 41407, 41408, 41417, 41418, + 41415, 41416, 41430, 41433, 41432, 41431, 41428, 41429, 41538, 41527, + 41528, 41526, 41541, 41540, 41539, 41536, 41537, 41534, 41535, 41533, + 41524, 41525, 41522, 41523, 41531, 41532, 41529, 41530, 41521, 41520, + 41157, 41147, 41148, 41145, 41146, 41160, 41159, 41158, 41155, 41156, + 41136, 41139, 41140, 41138, 41137, 41134, 41135, 41143, 41144, 41141, + 41142, 41151, 41152, 41149, 41150, 41163, 41164, 41161, 41162, 41154, + 41153, 41080, 41083, 41084, 41082, 41081, 41078, 41079, 41087, 41088, + 41085, 41086, 41091, 41092, 41089, 41090, 41095, 41098, 41097, 41096, + 41093, 41094, 41101, 41104, 41103, 41102, 41099, 41100, 41299, 41302, + 41301, 41300, 41297, 41298, 41312, 41313, 41311, 41305, 41306, 41303, + 41304, 41309, 41310, 41307, 41308, 41316, 41319, 41318, 41317, 41314, + 41315, 41574, 41572, 41573, 41580, 41581, 41579, 41566, 41567, 41565, + 41570, 41571, 41568, 41569, 41577, 41578, 41575, 41576, 42048, 42042, + 42041, 42051, 42050, 42049, 42047, 42035, 42039, 42040, 42037, 42038, + 42036, 42033, 42034, 42045, 42046, 42043, 42044, 42054, 42057, 42056, + 42055, 42052, 42053, 41881, 41882, 41880, 41878, 41879, 41876, 41877, + 41885, 41886, 41883, 41884, 41889, 41892, 41891, 41890, 41887, 41888, + 41895, 41898, 41897, 41896, 41893, 41894, 42075, 42067, 42068, 42066, + 42076, 42073, 42074, 42060, 42064, 42065, 42062, 42063, 42061, 42058, + 42059, 42071, 42072, 42069, 42070, 41727, 41721, 41720, 41730, 41729, + 41728, 41726, 41723, 41722, 41711, 41714, 41715, 41713, 41712, 41709, + 41710, 41718, 41719, 41716, 41717, 41733, 41736, 41735, 41734, 41731, + 41732, 41725, 41724, 41363, 41352, 41353, 41351, 41366, 41365, 41364, + 41361, 41362, 41343, 41346, 41347, 41345, 41344, 41341, 41342, 41349, + 41350, 41348, 41359, 41360, 41358, 41356, 41357, 41354, 41355, 41036, + 41028, 41029, 41027, 41039, 41038, 41037, 41034, 41035, 41018, 41021, + 41022, 41020, 41019, 41016, 41017, 41025, 41026, 41023, 41024, 41032, + 41033, 41030, 41031, 41042, 41045, 41044, 41043, 41040, 41041, 41998, + 41990, 41991, 41988, 41989, 42001, 42000, 41999, 41996, 41997, 41982, + 41986, 41987, 41984, 41985, 41983, 41980, 41981, 41994, 41995, 41992, + 41993, 42004, 42007, 42006, 42005, 42002, 42003, 42115, 42107, 42108, + 42105, 42106, 42118, 42117, 42116, 42113, 42114, 42099, 42103, 42104, + 42101, 42102, 42100, 42097, 42098, 42111, 42112, 42109, 42110, 42121, + 42124, 42123, 42122, 42119, 42120, 41866, 41855, 41854, 41869, 41868, + 41867, 41864, 41865, 41862, 41863, 41860, 41861, 41858, 41859, 41856, + 41857, 41872, 41875, 41874, 41873, 41870, 41871, 41853, 41852, 41942, + 41931, 41932, 41930, 41945, 41944, 41943, 41940, 41941, 41938, 41939, + 41937, 41928, 41929, 41926, 41927, 41935, 41936, 41933, 41934, 41948, + 41951, 41950, 41949, 41946, 41947, 41772, 41775, 41776, 41774, 41773, + 41770, 41771, 41786, 41787, 41785, 41779, 41780, 41777, 41778, 41783, + 41784, 41781, 41782, 41790, 41791, 41788, 41789, 41794, 41797, 41796, + 41795, 41792, 41793, 41916, 41904, 41905, 41903, 41919, 41918, 41917, + 41914, 41915, 41901, 41902, 41899, 41900, 41912, 41913, 41910, 41911, + 41908, 41909, 41906, 41907, 41922, 41925, 41924, 41923, 41920, 41921, + 41760, 41749, 41750, 41748, 41763, 41762, 41761, 41758, 41759, 41739, + 41742, 41743, 41741, 41740, 41737, 41738, 41756, 41757, 41755, 41746, + 41747, 41744, 41745, 41753, 41754, 41751, 41752, 41766, 41769, 41768, + 41767, 41764, 41765, 41266, 41255, 41256, 41253, 41254, 41269, 41268, + 41267, 41264, 41265, 41244, 41247, 41248, 41246, 41245, 41242, 41243, + 41262, 41263, 41261, 41251, 41252, 41249, 41250, 41259, 41260, 41257, + 41258, 41203, 41202, 41188, 41192, 41193, 41190, 41191, 41189, 41186, + 41187, 41196, 41197, 41194, 41195, 41200, 41201, 41198, 41199, 41206, + 41209, 41208, 41207, 41204, 41205, 41212, 41215, 41214, 41213, 41210, + 41211, 40981, 41605, 41606, 41604, 41611, 41612, 41610, 41608, 41609, + 41607, 41602, 41603, 41600, 41601, 42079, 42083, 42084, 42081, 42082, + 42080, 42077, 42078, 42089, 42090, 42087, 42088, 42093, 42096, 42095, + 42094, 42091, 42092, 42086, 42085, 41815, 41803, 41804, 41802, 41818, + 41817, 41816, 41813, 41814, 41800, 41801, 41798, 41799, 41811, 41812, + 41809, 41810, 41807, 41808, 41805, 41806, 41821, 41824, 41823, 41822, + 41819, 41820, 41636, 41625, 41626, 41624, 41639, 41638, 41637, 41634, + 41635, 41615, 41618, 41619, 41617, 41616, 41613, 41614, 41696, 41697, + 41695, 41693, 41694, 41692, 41682, 41686, 41687, 41684, 41685, 41683, + 41680, 41681, 41690, 41691, 41688, 41689, 41699, 41702, 41701, 41700, + 41698, 41705, 41708, 41707, 41706, 41703, 41704, 41632, 41633, 41631, + 41622, 41623, 41620, 41621, 41629, 41630, 41627, 41628, 41642, 41645, + 41644, 41643, 41640, 41641, 40973, 40974, 40972, 40970, 40971, 40968, + 40969, 40977, 40978, 40975, 40976, 40980, 40979, 9775, 129664, 8959, + 10853, 10632, 10634, 10814, 10852, 10631, 10633, 10783, 10784, 10785, + 10625, 10626, 72262, 72256, 72253, 72252, 72254, 72251, 72250, 72261, + 72255, 72243, 72215, 72214, 72230, 72229, 72220, 72219, 72242, 72204, + 72203, 72207, 72216, 72211, 72221, 72238, 72239, 72240, 72228, 72227, + 72213, 72212, 72218, 72217, 72225, 72224, 72209, 72208, 72206, 72205, + 72223, 72222, 72231, 72232, 72233, 72241, 72210, 72236, 72226, 72235, + 72237, 72234, 72192, 72259, 72258, 72260, 72257, 72248, 72245, 72246, + 72247, 72244, 72249, 72263, 72202, 72199, 72200, 72198, 72197, 72195, + 72194, 72201, 72196, 72193, 129427, 65279, 8204, 8203, 8205, 11234, + 129296, 118593, 118584, 118585, 118591, 118580, 118589, 118528, 118540, + 118531, 118543, 118559, 118529, 118541, 118532, 118544, 118592, 118573, + 118569, 118568, 118581, 118586, 118561, 118582, 118583, 118566, 118538, + 118550, 118555, 118556, 118535, 118547, 118537, 118549, 118553, 118558, + 118534, 118546, 118572, 118562, 118571, 118554, 118533, 118545, 118587, + 118588, 118530, 118542, 118552, 118563, 118539, 118551, 118557, 118536, + 118548, 118579, 118570, 118560, 118567, 118565, 118564, 118590, 118576, + 118577, 118578, 118619, 118639, 118637, 118645, 118721, 118611, 118635, + 118659, 118626, 118623, 118625, 118624, 118622, 118638, 118612, 118660, + 118608, 118609, 118657, 118719, 118695, 118699, 118698, 118697, 118696, + 118722, 118720, 118703, 118708, 118707, 118706, 118705, 118704, 118610, + 118620, 118723, 118616, 118617, 118640, 118672, 118636, 118658, 118652, + 118651, 118649, 118650, 118648, 118646, 118647, 118644, 118643, 118641, + 118642, 118653, 118656, 118654, 118655, 118662, 118670, 118664, 118666, + 118669, 118663, 118665, 118671, 118667, 118668, 118673, 118614, 118615, + 118618, 118685, 118687, 118684, 118683, 118686, 118681, 118680, 118709, + 118713, 118711, 118716, 118717, 118714, 118715, 118712, 118718, 118710, + 118676, 118679, 118690, 118688, 118693, 118694, 118691, 118692, 118689, + 118675, 118677, 118678, 118674, 118701, 118702, 118700, 118682, 118632, + 118631, 118634, 118633, 118628, 118627, 118630, 118629, 118613, 118621, + 118661, 118596, 118597, 118594, 118595, 118598, 129503, 983264, 983222, + 983221, 983223, }; #define DAWG_CODEPOINT_TO_POS_SHIFT 8 -#define DAWG_CODEPOINT_TO_POS_NOTFOUND 40951 +#define DAWG_CODEPOINT_TO_POS_NOTFOUND 41412 static const unsigned char dawg_codepoint_to_pos_index1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, @@ -13305,14 +13460,14 @@ static const unsigned char dawg_codepoint_to_pos_index1[] = { 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 136, 52, 52, 52, 52, 52, 52, 137, 138, 139, 140, 52, 141, 142, 143, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 144, 145, 146, 147, 148, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 144, 145, 146, 147, 148, 149, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 149, 150, 151, 152, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 153, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 52, 52, 52, 52, 169, 170, 171, 172, 52, 173, 174, 52, 175, - 176, 177, 52, 52, 178, 179, 180, 52, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 150, 151, 152, 153, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 154, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 52, 52, 52, 52, 170, 171, 172, 173, 52, 174, 175, 176, + 177, 178, 179, 52, 52, 180, 181, 182, 52, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, @@ -13326,7 +13481,7 @@ static const unsigned char dawg_codepoint_to_pos_index1[] = { 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 193, 194, 195, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 195, 196, 197, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, @@ -13483,7 +13638,7 @@ static const unsigned char dawg_codepoint_to_pos_index1[] = { 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 196, 197, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 198, 199, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, @@ -13497,7 +13652,7 @@ static const unsigned char dawg_codepoint_to_pos_index1[] = { 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 198, 199, 200, 201, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 200, 201, 202, 203, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, @@ -13526,1694 +13681,1684 @@ static const unsigned char dawg_codepoint_to_pos_index1[] = { 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, }; static const unsigned short dawg_codepoint_to_pos_index2[] = { - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 34087, 17354, 31745, 29447, 11088, 31317, 368, 1052, 24153, - 31969, 2527, 31568, 8453, 20460, 17532, 33926, 10872, 10857, 10869, - 10866, 10851, 10848, 10863, 10860, 10875, 10854, 8056, 32578, 24396, - 16792, 18147, 31743, 8452, 22741, 22787, 22797, 22813, 22828, 22873, - 22877, 22894, 22908, 22937, 22942, 22954, 22974, 22983, 22999, 23049, - 23057, 23060, 23081, 23105, 23134, 23173, 23184, 23193, 23196, 23210, - 24115, 31870, 31983, 6819, 25161, 18118, 23302, 23352, 23372, 23395, - 23431, 23490, 23498, 23516, 23535, 23572, 23578, 23592, 23631, 23644, - 23668, 23725, 23736, 23742, 23780, 23822, 23895, 23943, 23957, 23966, - 23974, 23990, 24056, 38833, 31932, 37296, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 29440, - 20815, 6131, 31610, 9951, 39398, 4937, 32560, 10839, 8647, 17433, 24163, - 29422, 33877, 31793, 26847, 10554, 31580, 34712, 34711, 4, 27575, 31465, - 27581, 6127, 34715, 25814, 32030, 38965, 38963, 38971, 20818, 22770, - 22771, 22759, 22773, 22752, 22754, 22775, 22798, 22859, 22860, 22831, - 22846, 22924, 22925, 22914, 22912, 22870, 22997, 23038, 23039, 23006, - 23024, 23013, 28287, 23022, 23165, 23166, 23135, 23138, 23205, 23126, - 23812, 23333, 23334, 23322, 23336, 23313, 23315, 23339, 23373, 23464, - 23465, 23434, 23449, 23553, 23554, 23536, 23538, 23489, 23663, 23707, - 23708, 23669, 23693, 23676, 10999, 23691, 23930, 23933, 23898, 23901, - 23985, 23844, 23976, 22757, 23320, 22742, 23303, 22767, 23330, 22802, - 23378, 22800, 23375, 22806, 23383, 22801, 23377, 22820, 23403, 22817, - 23397, 22849, 23453, 22862, 23467, 22841, 23444, 22856, 23461, 22840, - 23443, 22879, 23500, 22882, 23503, 22886, 23508, 22878, 23499, 22897, - 23519, 22904, 23528, 22918, 23550, 22916, 23545, 22927, 23556, 22921, - 23547, 22911, 23419, 23222, 24010, 22938, 23573, 22943, 23579, 23591, - 22968, 23609, 22964, 23596, 22966, 23599, 22961, 23606, 22963, 23617, - 22992, 23656, 22984, 23645, 22986, 23649, 23664, 22872, 23472, 23002, - 23686, 23041, 23710, 23019, 23682, 23223, 24013, 23069, 23759, 23061, - 23743, 23062, 23745, 23087, 23781, 23086, 23787, 23084, 23785, 23082, - 23783, 23106, 23823, 23109, 23827, 23116, 23839, 23162, 23927, 23154, - 23917, 23168, 23935, 23169, 23926, 23145, 23908, 23159, 23922, 23185, - 23958, 23197, 23975, 23198, 23213, 23991, 23216, 23997, 23212, 23994, - 23623, 23361, 22793, 22788, 23353, 23129, 23847, 23044, 22804, 23381, - 22779, 22825, 22821, 23398, 23852, 23078, 23104, 23043, 22874, 23493, - 22885, 22892, 23534, 22935, 22928, 22953, 23590, 23595, 23619, 23123, - 22990, 23650, 23005, 23031, 23700, 23046, 23722, 23055, 23733, 23299, - 23130, 23848, 22871, 23239, 23835, 23115, 23836, 23114, 23147, 23910, - 23172, 23177, 23202, 23980, 23219, 24000, 22864, 22866, 23482, 23487, - 23291, 23131, 23849, 23238, 23292, 23293, 23294, 23231, 23241, 22827, - 22815, 23425, 22973, 22962, 23630, 22998, 22987, 23667, 22765, 23328, - 22915, 23537, 23012, 23675, 23137, 23900, 23142, 23905, 23141, 23904, - 23139, 23902, 23140, 23903, 23884, 22753, 23314, 22749, 23310, 22777, - 23342, 22887, 23509, 22880, 23501, 22944, 23580, 23020, 23689, 23021, - 23690, 22865, 23484, 23575, 22826, 22814, 23424, 22881, 23502, 22906, - 23192, 22991, 23655, 22755, 23316, 22776, 23341, 23023, 23692, 22751, - 23312, 22772, 23335, 22845, 23448, 22861, 23466, 22909, 23544, 22926, - 23555, 23018, 23681, 23040, 23709, 23066, 23749, 23071, 23760, 23144, - 23907, 23167, 23934, 23085, 23786, 23108, 23825, 23209, 23989, 22898, - 23520, 22988, 23402, 23048, 23724, 23221, 24004, 22748, 23309, 22829, - 23432, 23014, 23677, 23027, 23696, 23015, 23678, 23016, 23679, 23206, - 23986, 23598, 23648, 23826, 23416, 23429, 23741, 22774, 22807, 23384, - 22956, 23110, 23794, 23999, 22888, 23510, 22794, 23171, 23125, 22863, - 23469, 22941, 23577, 23098, 23739, 23073, 23763, 23208, 23984, 23876, - 23344, 23877, 23360, 23713, 23376, 23399, 23407, 23772, 23803, 23807, - 23719, 23767, 23769, 23391, 23417, 23507, 23810, 23268, 23514, 23779, - 23853, 23527, 23533, 23557, 23568, 23246, 23604, 23593, 23612, 23620, - 23879, 23880, 23639, 23652, 23661, 23279, 23364, 23253, 23390, 23735, - 23864, 23867, 23870, 23754, 23755, 23750, 23770, 23255, 23247, 23800, - 23475, 23418, 23820, 23479, 23871, 23838, 23896, 23937, 23950, 23873, - 23888, 23881, 23286, 24003, 23993, 23481, 23483, 23295, 23297, 23236, - 23288, 23234, 23266, 23389, 23269, 23275, 23574, 23886, 23248, 23738, - 23296, 23240, 23426, 23412, 23427, 23891, 23840, 23890, 23496, 23627, - 23628, 23233, 23235, 23854, 23855, 27905, 27906, 27914, 27936, 27963, - 27966, 27861, 27983, 27985, 27834, 27777, 27991, 27688, 27842, 27844, - 27820, 27793, 27840, 27822, 27846, 27993, 27779, 27769, 6060, 27997, - 27823, 27687, 27792, 27818, 27809, 27815, 27814, 27990, 27800, 27721, - 27720, 27992, 27778, 27833, 27831, 4930, 11194, 32162, 29978, 33836, - 11253, 27847, 27770, 27904, 27916, 27943, 27984, 27940, 27784, 27799, - 27827, 27812, 27789, 27999, 27998, 27996, 27994, 27776, 27805, 27817, - 27807, 27810, 27811, 27830, 27829, 27828, 27813, 27839, 27690, 27790, - 27691, 27791, 27849, 27832, 27806, 8264, 8062, 8146, 8428, 8370, 8390, - 8072, 8171, 8168, 8277, 8415, 8197, 8078, 8443, 8196, 8198, 8080, 8280, - 8436, 8083, 8398, 8084, 8265, 8063, 8355, 8411, 8349, 8279, 8352, 8438, - 8202, 8395, 8379, 8394, 8399, 8174, 8170, 8414, 8085, 8148, 8388, 8442, - 8075, 8283, 8079, 8147, 8074, 8281, 8432, 8375, 8369, 8199, 8431, 8419, - 8367, 8418, 8366, 8406, 8282, 8422, 8426, 8450, 8444, 8185, 8266, 8064, - 8274, 8273, 8276, 8275, 8076, 8211, 8195, 8348, 8381, 8278, 8071, 8356, - 8437, 8269, 8402, 8353, 8212, 8449, 8344, 8403, 8401, 8407, 8173, 8068, - 8190, 8417, 8179, 8178, 8182, 8183, 8191, 8180, 8189, 8296, 8304, 8309, - 8317, 8320, 8302, 8334, 8336, 8338, 8323, 8326, 8341, 8342, 18332, 18596, - 18227, 18463, 18414, 18410, 18321, 18578, 40951, 40951, 18653, 18603, - 18604, 18602, 18658, 18335, 40951, 40951, 40951, 40951, 18618, 18348, - 18225, 18201, 18258, 18248, 18272, 40951, 18304, 40951, 18319, 18294, - 18510, 18204, 18331, 18329, 18327, 18249, 18333, 18228, 18325, 18259, - 18328, 18334, 18336, 18337, 18338, 18295, 18324, 18305, 40951, 18307, - 18326, 18310, 18322, 18330, 18323, 18274, 18264, 18315, 18460, 18475, - 18500, 18519, 18530, 18435, 18595, 18593, 18465, 18466, 18597, 18476, - 18590, 18501, 18541, 18598, 18599, 18600, 18601, 18568, 18581, 18582, - 18592, 18588, 18591, 18521, 18579, 18594, 18580, 18543, 18506, 18526, - 18577, 18539, 18567, 18343, 18655, 18614, 18622, 18620, 18621, 18430, - 18431, 18395, 18406, 18462, 18405, 18587, 18408, 18464, 18407, 18542, - 18404, 18585, 8528, 8622, 8506, 8600, 8502, 8596, 8500, 8594, 8498, 8592, - 8527, 8621, 8497, 8591, 18394, 18433, 18411, 18409, 18344, 18412, 18434, - 18309, 18589, 18339, 18308, 18586, 18432, 18341, 18342, 18340, 10218, - 10220, 10167, 10206, 10142, 10171, 10158, 10277, 10290, 10113, 10116, - 10130, 10245, 10215, 10258, 10175, 10143, 10159, 10291, 10200, 10179, - 10217, 10284, 10280, 10213, 10256, 10230, 10181, 10197, 10186, 10249, - 10117, 10192, 10195, 10127, 10137, 10199, 10207, 10133, 10160, 10263, - 10261, 10211, 10274, 10266, 10180, 10279, 10271, 10302, 10318, 10492, - 10359, 10338, 10376, 10485, 10481, 10372, 10434, 10389, 10340, 10356, - 10345, 10415, 10420, 10351, 10354, 10452, 10463, 10358, 10366, 10458, - 10319, 10441, 10439, 10370, 10475, 10444, 10339, 10480, 10472, 10377, - 10379, 10326, 10365, 10468, 10330, 10317, 10478, 10491, 10408, 10414, - 10455, 10404, 10374, 10436, 10334, 10250, 10416, 10273, 10474, 10226, - 10385, 10112, 10406, 10222, 10381, 10155, 10314, 10223, 10382, 10246, - 10405, 10120, 10424, 10289, 10490, 10228, 10387, 10229, 10388, 10141, - 10467, 10121, 10429, 10251, 10417, 10253, 10419, 10243, 10402, 10523, - 8139, 8133, 8136, 8134, 8135, 8089, 8142, 10257, 10435, 10270, 10448, - 10193, 10352, 10202, 10361, 10204, 10363, 10201, 10360, 10286, 10487, - 10282, 10483, 10231, 10390, 10233, 10392, 10234, 10393, 10153, 10312, - 10188, 10347, 10296, 10496, 10118, 10421, 10149, 10308, 10196, 10355, - 10129, 10454, 10268, 10446, 10269, 10447, 10208, 10367, 10295, 10495, - 10162, 10321, 10163, 10322, 10259, 10437, 10146, 10305, 10147, 10306, - 10299, 10287, 10488, 10232, 10391, 10184, 10343, 10191, 10350, 10190, - 10349, 10244, 10403, 10198, 10357, 10423, 10145, 10304, 10144, 10303, - 10294, 10494, 10219, 10378, 10254, 10432, 10255, 10433, 10285, 10486, - 10281, 10482, 10148, 10307, 10216, 10375, 10214, 10373, 10252, 10418, - 10151, 10310, 10152, 10311, 10194, 10353, 10140, 10466, 10139, 10465, - 10138, 10464, 10161, 10320, 10203, 10362, 10275, 10476, 10205, 10364, - 10209, 10368, 10210, 10369, 10237, 10396, 10236, 10395, 10242, 10401, - 10235, 10394, 10238, 10397, 10239, 10398, 10240, 10399, 10241, 10400, - 10125, 10428, 10185, 10344, 10114, 10409, 10126, 10431, 10272, 10473, - 10293, 10493, 10292, 10471, 10150, 10309, 10182, 10341, 10187, 10346, - 10119, 10422, 10260, 10438, 10189, 10348, 10173, 10332, 10177, 10336, - 10183, 10342, 40951, 2445, 2452, 2436, 2458, 2432, 2456, 2433, 2434, - 2423, 2455, 2451, 2448, 2450, 2428, 2440, 2457, 2438, 2435, 2426, 2453, - 2424, 2454, 2443, 2447, 2427, 2442, 2437, 2431, 2444, 2446, 2422, 2430, - 2429, 2425, 2441, 2439, 2459, 2449, 40951, 40951, 2509, 2421, 2462, 2461, - 2460, 2513, 2420, 2482, 2485, 2495, 2473, 2501, 2469, 2499, 2470, 2471, - 2484, 2498, 2494, 2491, 2493, 2465, 2477, 2500, 2475, 2472, 2463, 2496, - 2488, 2497, 2480, 2487, 2464, 2479, 2474, 2468, 2481, 2486, 2483, 2467, - 2466, 2490, 2478, 2476, 2502, 2492, 2503, 2489, 2512, 2510, 40951, 40951, - 32017, 24176, 2511, 40951, 19805, 19808, 19809, 19816, 19817, 19813, - 19820, 19818, 19803, 19815, 19812, 19796, 19797, 19798, 19806, 19811, - 19804, 19793, 19801, 19802, 19799, 19800, 19795, 19807, 19810, 19814, - 19821, 19822, 19794, 19819, 19900, 19915, 19904, 19902, 19903, 19905, - 19917, 19913, 19908, 19909, 19906, 19907, 19911, 19901, 19919, 19925, - 19912, 19922, 19914, 19916, 19923, 19899, 19898, 19924, 19910, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 19823, 19830, 19873, - 19871, 19848, 19879, 19853, 19850, 19865, 19890, 19839, 19833, 19875, - 19845, 19877, 19844, 19851, 19855, 19829, 19841, 19836, 19843, 19869, - 19846, 19863, 19857, 19867, 40951, 40951, 40951, 40951, 19926, 19894, - 19897, 19895, 19921, 19920, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 2264, 2299, 1093, 2300, 2301, 2263, - 2408, 2409, 2275, 2406, 2407, 2598, 1062, 1075, 2270, 2305, 2298, 2304, - 2296, 2297, 2306, 2326, 2312, 2341, 2308, 2357, 2356, 2292, 1381, 1083, - 2396, 2404, 1336, 1288, 1151, 1141, 1569, 1144, 1585, 1123, 1165, 1512, - 1511, 1532, 1314, 1273, 1355, 1190, 1529, 1433, 1611, 1467, 1480, 1459, - 1206, 1489, 1606, 1113, 1260, 1342, 1339, 1235, 1234, 1233, 2384, 1240, - 1424, 1325, 1360, 1373, 1397, 1290, 1564, 1159, 1576, 1091, 1073, 1103, - 1085, 1069, 1099, 2293, 2361, 2117, 1098, 1097, 2360, 2282, 2118, 2405, - 2400, 2399, 2401, 2276, 1086, 2403, 2416, 2418, 2415, 2414, 2411, 2410, - 2413, 2412, 2419, 2417, 2268, 1079, 2398, 1094, 1218, 1220, 1486, 1156, - 1148, 1147, 1310, 1311, 1313, 1550, 1312, 1538, 1544, 1185, 1520, 1519, - 1412, 1524, 1180, 1283, 1281, 1392, 1221, 1280, 1499, 1506, 1215, 1200, - 1197, 1198, 1203, 1212, 1226, 1193, 1199, 1450, 1436, 1447, 1444, 1437, - 1445, 1440, 1322, 1443, 1468, 1471, 1472, 1462, 1461, 1493, 1116, 1219, - 1243, 1241, 1557, 1245, 1419, 1427, 1428, 1337, 1488, 1331, 1330, 1382, - 1328, 1251, 1254, 1383, 1253, 1267, 1252, 1364, 1362, 1366, 1365, 1406, - 1398, 1453, 1407, 1403, 1301, 1501, 1298, 1291, 1292, 1515, 1573, 1349, - 1603, 1549, 1600, 1352, 1572, 1556, 1229, 1594, 1590, 1566, 1615, 1595, - 1577, 1580, 1095, 1164, 2315, 2314, 2317, 2316, 2343, 2325, 2323, 1084, - 2383, 2340, 2339, 2309, 2318, 2355, 2319, 2359, 2358, 2337, 2320, 2272, - 1082, 1081, 2280, 2354, 1192, 1441, 17374, 17376, 17373, 17372, 17369, - 17368, 17371, 17370, 17377, 17375, 1481, 1207, 1262, 2303, 2302, 1297, - 34842, 34916, 34913, 34914, 34910, 34851, 34838, 34839, 34915, 34912, - 34837, 34847, 34846, 34845, 40951, 34835, 34883, 34879, 34893, 34889, - 34890, 34853, 34852, 34854, 34896, 34894, 34855, 34886, 34887, 34891, - 34892, 34884, 34856, 34868, 34895, 34875, 34882, 34897, 34869, 34873, - 34881, 34885, 34874, 34880, 34888, 34870, 34872, 34871, 34902, 34901, - 34900, 34905, 34904, 34903, 34907, 34906, 34841, 34840, 34850, 34849, - 34848, 34844, 34843, 34908, 34922, 34923, 34909, 34920, 34919, 34918, - 34917, 34899, 34898, 34921, 34836, 40951, 40951, 34876, 34877, 34878, - 1171, 1174, 1169, 1170, 1172, 1173, 1167, 1282, 1279, 1196, 1191, 1438, - 1474, 1118, 1114, 1117, 1246, 1244, 1344, 1340, 1338, 1376, 1375, 1404, - 1401, 1402, 1367, 1439, 1442, 1473, 1278, 1276, 1470, 1434, 1277, 1150, - 1149, 1232, 1231, 1230, 1568, 1567, 1579, 1578, 1274, 1475, 1469, 1327, - 36865, 36878, 36874, 36891, 36890, 36869, 36866, 36854, 36885, 36870, - 36859, 36858, 36881, 36868, 36861, 36862, 36879, 36857, 36887, 36880, - 36892, 36873, 36872, 36871, 36883, 36864, 36867, 36882, 36888, 36877, - 36876, 36856, 36884, 36889, 36855, 36863, 36860, 36886, 36850, 36849, - 36896, 36852, 36897, 36895, 36851, 36853, 36894, 36893, 36898, 36875, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 29306, 29308, 29305, 29304, 29301, 29300, - 29303, 29302, 29309, 29307, 29341, 29328, 29342, 29327, 29343, 29325, - 29324, 29312, 29317, 29330, 29336, 29338, 29316, 29326, 29311, 29323, - 29322, 29337, 29329, 29331, 29333, 29334, 29319, 29335, 29320, 29318, - 29332, 29339, 29340, 29321, 29314, 29313, 29315, 29294, 29295, 29296, - 29292, 29289, 29290, 29291, 29293, 29288, 29345, 29344, 29347, 29346, - 29297, 29348, 29310, 40951, 40951, 29298, 29299, 29349, 32389, 32376, - 32390, 32378, 32381, 32377, 32392, 32380, 32387, 32396, 32382, 32383, - 32393, 32395, 32384, 32379, 32397, 32388, 32394, 32391, 32385, 32386, - 32399, 32400, 32403, 32398, 32404, 32401, 32423, 32433, 32428, 32422, - 32432, 32427, 32421, 32431, 32405, 32429, 32425, 32435, 32406, 32424, - 32434, 32426, 32430, 32402, 40951, 40951, 32413, 32407, 32409, 32412, - 32410, 32414, 32436, 32419, 32417, 32420, 32416, 32418, 32411, 32415, - 32408, 40951, 25603, 25590, 25592, 25591, 25593, 25602, 25600, 25605, - 25585, 25583, 25582, 25594, 25595, 25596, 25586, 25604, 25597, 25588, - 25598, 25599, 25587, 25584, 25601, 25606, 25589, 25581, 25607, 25608, - 40951, 40951, 25609, 40951, 34861, 34866, 34862, 34864, 34860, 34859, - 34863, 34867, 34858, 34857, 34865, 40951, 40951, 40951, 40951, 40951, - 1137, 1127, 1138, 1154, 1136, 1124, 1133, 1130, 1134, 1132, 1155, 1129, - 1140, 1126, 1128, 1139, 1125, 1131, 1135, 2385, 2386, 2388, 1537, 2281, - 2274, 1405, 1275, 1494, 1492, 1341, 2402, 40951, 2271, 2273, 40951, - 40951, 40951, 40951, 40951, 2269, 2327, 2348, 2347, 2350, 2116, 2365, - 1076, 1096, 1168, 1175, 1315, 1491, 1242, 1425, 1361, 1374, 1591, 1593, - 1446, 1565, 1458, 1372, 1194, 1460, 1255, 1487, 1614, 1115, 1329, 1426, - 1166, 1413, 1517, 1435, 1592, 1111, 1109, 1112, 1414, 1518, 1539, 1500, - 1343, 1261, 1110, 1317, 1316, 1363, 1272, 2307, 2310, 2338, 2333, 2342, - 1107, 1106, 2364, 1108, 1105, 2353, 2328, 2324, 2345, 2344, 2321, 2346, - 2329, 2331, 2330, 2332, 2335, 2334, 2311, 2322, 1080, 2397, 1065, 1063, - 1067, 1066, 1064, 1068, 2391, 2393, 2395, 2390, 2392, 2394, 2267, 2266, - 2265, 2336, 1088, 1087, 1100, 1621, 2277, 1620, 2279, 1077, 1078, 2278, - 1072, 2119, 10772, 10762, 10776, 10781, 10697, 10671, 10672, 10741, - 10742, 10717, 10718, 10736, 10738, 10679, 10698, 10749, 10673, 10680, - 10699, 10703, 10674, 10711, 10710, 10692, 10690, 10723, 10677, 10681, - 10728, 10726, 10724, 10733, 10732, 10685, 10684, 10722, 10735, 10734, - 10687, 10686, 10725, 10721, 10744, 10743, 10708, 10707, 10695, 10716, - 10714, 10713, 10731, 10730, 10729, 10740, 10700, 10701, 10702, 10694, - 10794, 10793, 10774, 10775, 10784, 10806, 10807, 10796, 10797, 10802, - 10803, 10790, 10800, 10808, 10785, 10791, 10801, 10792, 10786, 10780, - 10795, 10787, 10822, 10783, 10782, 10666, 10663, 10789, 10799, 10798, - 10748, 10709, 10689, 10746, 10682, 10712, 10747, 10715, 10737, 10739, - 10804, 10805, 10810, 10809, 10817, 10819, 10816, 10815, 10812, 10811, - 10814, 10813, 10820, 10818, 10664, 10779, 10678, 10705, 10704, 10675, - 10720, 10719, 10696, 10745, 10693, 10691, 10727, 10688, 10683, 10706, - 3549, 3617, 3620, 3622, 40951, 3573, 3574, 3587, 3588, 3585, 3586, 3567, - 3569, 40951, 40951, 3609, 3575, 40951, 40951, 3610, 3576, 3560, 3557, - 3601, 3600, 3589, 3599, 3598, 3603, 3602, 3591, 3582, 3581, 3578, 3577, - 3590, 3584, 3583, 3580, 3579, 3592, 40951, 3605, 3604, 3597, 3596, 3608, - 3572, 3561, 40951, 3607, 40951, 40951, 40951, 3593, 3594, 3595, 3606, - 40951, 40951, 3618, 3619, 3624, 3633, 3634, 3627, 3628, 3629, 3630, - 40951, 40951, 3635, 3625, 40951, 40951, 3636, 3626, 3621, 3558, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 3550, 40951, 40951, - 40951, 40951, 3565, 3564, 40951, 3571, 3568, 3570, 3631, 3632, 40951, - 40951, 3643, 3645, 3642, 3641, 3638, 3637, 3640, 3639, 3646, 3644, 3563, - 3562, 3612, 3611, 3551, 3555, 3554, 3553, 3552, 3556, 3623, 3647, 3566, - 3548, 3616, 40951, 40951, 18887, 18888, 18893, 40951, 18839, 18840, - 18855, 18856, 18853, 18854, 40951, 40951, 40951, 40951, 18874, 18841, - 40951, 40951, 18873, 18842, 18838, 18837, 18835, 18834, 18859, 18866, - 18865, 18868, 18867, 18861, 18850, 18849, 18844, 18843, 18860, 18852, - 18851, 18846, 18845, 18862, 40951, 18870, 18869, 18864, 18863, 18877, - 18879, 18848, 40951, 18858, 18857, 40951, 18878, 18871, 40951, 18872, - 18876, 40951, 40951, 18890, 40951, 18894, 18899, 18900, 18897, 18898, - 40951, 40951, 40951, 40951, 18902, 18895, 40951, 40951, 18901, 18896, - 18892, 40951, 40951, 40951, 18889, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 18836, 18833, 18880, 18847, 40951, 18875, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 18912, 18914, 18911, 18910, 18907, - 18906, 18909, 18908, 18915, 18913, 18903, 18832, 18904, 18916, 18905, - 18891, 18831, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 18727, 18735, 18737, 40951, 18677, 18678, 18696, 18697, - 18694, 18695, 18689, 18691, 18753, 40951, 18724, 18679, 18754, 40951, - 18725, 18680, 18717, 18716, 18713, 18712, 18701, 18711, 18710, 18715, - 18714, 18703, 18686, 18685, 18682, 18681, 18702, 18688, 18687, 18684, - 18683, 18704, 40951, 18719, 18718, 18709, 18708, 18721, 18723, 18722, - 40951, 18699, 18698, 40951, 18693, 18705, 18706, 18707, 18720, 40951, - 40951, 18733, 18734, 18740, 18749, 18750, 18743, 18744, 18745, 18746, - 18738, 40951, 18751, 18741, 18739, 40951, 18752, 18742, 18736, 40951, - 40951, 18767, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 18690, 18692, 18747, - 18748, 40951, 40951, 18763, 18765, 18762, 18761, 18758, 18757, 18760, - 18759, 18766, 18764, 18755, 18756, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 18700, 18732, 18731, 18728, 18730, 18726, 18729, 40951, - 30620, 30623, 30626, 40951, 30571, 30572, 30590, 30591, 30588, 30589, - 30583, 30585, 40951, 40951, 30616, 30573, 40951, 40951, 30617, 30574, - 30610, 30609, 30606, 30605, 30594, 30604, 30603, 30608, 30607, 30596, - 30580, 30579, 30576, 30575, 30595, 30582, 30581, 30578, 30577, 30597, - 40951, 30612, 30611, 30602, 30601, 30614, 30570, 30568, 40951, 30593, - 30592, 40951, 30587, 30598, 30599, 30600, 30613, 40951, 40951, 30621, - 30622, 30627, 30636, 30637, 30630, 30631, 30632, 30633, 40951, 40951, - 30638, 30628, 40951, 40951, 30639, 30629, 30625, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 30624, 30557, 30558, 40951, 40951, 40951, - 40951, 30567, 30566, 40951, 30569, 30584, 30586, 30634, 30635, 40951, - 40951, 30646, 30648, 30645, 30644, 30641, 30640, 30643, 30642, 30649, - 30647, 30565, 30615, 30562, 30561, 30564, 30559, 30560, 30563, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 35480, - 35497, 40951, 35443, 35444, 35456, 35457, 35452, 35453, 40951, 40951, - 40951, 35461, 35462, 35445, 40951, 35454, 35455, 35446, 35466, 40951, - 40951, 40951, 35438, 35463, 40951, 35465, 40951, 35439, 35441, 40951, - 40951, 40951, 35437, 35442, 40951, 40951, 40951, 35440, 35436, 35468, - 40951, 40951, 40951, 35467, 35470, 35451, 35450, 35449, 35448, 35447, - 35469, 35458, 35459, 35460, 35464, 40951, 40951, 40951, 40951, 35770, - 35777, 35778, 35773, 35774, 40951, 40951, 40951, 35779, 35780, 35771, - 40951, 35775, 35776, 35772, 35496, 40951, 40951, 35783, 40951, 40951, - 40951, 40951, 40951, 40951, 35372, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 35409, - 35411, 35408, 35407, 35404, 35403, 35406, 35405, 35412, 35410, 35474, - 35472, 35473, 35402, 35782, 35781, 35401, 35399, 35371, 35477, 35475, - 40951, 40951, 40951, 40951, 40951, 36730, 36731, 36736, 36738, 36729, - 36690, 36691, 36706, 36707, 36702, 36703, 36697, 36699, 40951, 36723, - 36724, 36692, 40951, 36704, 36705, 36693, 36720, 36719, 36716, 36715, - 36679, 36714, 36713, 36718, 36717, 36681, 36686, 36685, 36673, 36672, - 36680, 36689, 36687, 36676, 36674, 36677, 40951, 36722, 36721, 36712, - 36711, 36726, 36727, 36684, 36683, 36696, 36695, 36694, 36701, 36708, - 36709, 36710, 36725, 40951, 40951, 36734, 36735, 36739, 36750, 36751, - 36742, 36743, 36744, 36745, 40951, 36752, 36753, 36740, 40951, 36748, - 36749, 36741, 36737, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 36728, 36664, 40951, 36688, 36675, 36682, 40951, 40951, 36678, 40951, - 40951, 36698, 36700, 36746, 36747, 40951, 40951, 36760, 36762, 36759, - 36758, 36755, 36754, 36757, 36756, 36763, 36761, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 36732, 36671, 36669, 36667, 36665, 36670, - 36668, 36666, 36733, 21274, 21273, 21278, 21282, 21275, 21222, 21223, - 21248, 21249, 21244, 21245, 21239, 21241, 40951, 21265, 21266, 21224, - 40951, 21246, 21247, 21225, 21262, 21261, 21258, 21257, 21219, 21256, - 21255, 21260, 21259, 21221, 21236, 21235, 21227, 21226, 21220, 21238, - 21237, 21229, 21228, 21217, 40951, 21264, 21263, 21254, 21253, 21269, - 21270, 21234, 21233, 21232, 21231, 40951, 21243, 21250, 21251, 21252, - 21268, 40951, 40951, 21276, 21277, 21284, 21295, 21296, 21287, 21288, - 21289, 21290, 40951, 21297, 21298, 21285, 40951, 21293, 21294, 21286, - 21281, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 21271, 21283, - 40951, 40951, 40951, 40951, 40951, 40951, 21218, 21267, 40951, 21240, - 21242, 21291, 21292, 40951, 40951, 21305, 21307, 21304, 21303, 21300, - 21299, 21302, 21301, 21308, 21306, 40951, 21279, 21280, 21272, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 25543, 25545, 25550, 25548, 25500, 25474, 25476, 25520, 25521, - 25516, 25517, 25501, 25503, 40951, 25535, 25536, 25477, 40951, 25518, - 25519, 25478, 25532, 25531, 25528, 25527, 25508, 25489, 25488, 25530, - 25529, 25509, 25497, 25495, 25492, 25491, 25507, 25499, 25498, 25494, - 25493, 25510, 25506, 25534, 25533, 25526, 25525, 25538, 25539, 25515, - 25514, 25513, 25512, 25511, 25505, 25522, 25523, 25524, 25537, 25496, - 25546, 25544, 25549, 25552, 25563, 25564, 25555, 25556, 25557, 25558, - 40951, 25565, 25566, 25553, 40951, 25561, 25562, 25554, 25547, 25490, - 25551, 40951, 40951, 40951, 40951, 25486, 25487, 25481, 25567, 25466, - 25464, 25471, 25461, 25462, 25472, 25465, 25475, 25502, 25504, 25559, - 25560, 40951, 40951, 25457, 25459, 25456, 25455, 25452, 25451, 25454, - 25453, 25460, 25458, 25542, 25540, 25541, 25469, 25468, 25473, 25463, - 25467, 25470, 25450, 25483, 25482, 25484, 25479, 25480, 25485, 40951, - 33736, 33735, 33737, 40951, 33681, 33678, 33666, 33665, 33689, 33688, - 33691, 33690, 33687, 33686, 33685, 33684, 33683, 33682, 33679, 33710, - 33709, 33680, 40951, 40951, 40951, 33675, 33700, 33673, 33698, 33723, - 33713, 33672, 33697, 33674, 33699, 33720, 33721, 33714, 33667, 33692, - 33669, 33694, 33704, 33711, 33668, 33693, 33670, 33695, 33707, 40951, - 33712, 33676, 33701, 33671, 33696, 33702, 33677, 33719, 33717, 40951, - 33706, 40951, 40951, 33718, 33722, 33705, 33708, 33716, 33703, 33715, - 40951, 40951, 40951, 33734, 40951, 40951, 40951, 40951, 33754, 33746, - 33741, 33747, 33742, 33748, 40951, 33743, 40951, 33744, 33749, 33740, - 33753, 33750, 33751, 33752, 33745, 40951, 40951, 40951, 40951, 40951, - 40951, 33730, 33732, 33729, 33728, 33725, 33724, 33727, 33726, 33733, - 33731, 40951, 40951, 33738, 33739, 33755, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 36917, 36914, - 36912, 36911, 36913, 36915, 36931, 36900, 36902, 36901, 36960, 36903, - 36972, 36904, 36969, 36965, 36962, 36963, 36933, 36905, 36968, 36967, - 36964, 36966, 36934, 36899, 36940, 36937, 36906, 36938, 36907, 36939, - 36929, 36973, 36941, 36942, 36919, 36921, 36970, 36958, 36957, 36959, - 36910, 36918, 36974, 36909, 36935, 36943, 36923, 36946, 36948, 36953, - 36954, 36950, 36951, 36949, 36952, 36936, 40951, 40951, 40951, 40951, - 36975, 36955, 36947, 36956, 36945, 36944, 36920, 36928, 36927, 36926, - 36924, 36925, 36922, 36961, 36932, 36971, 36908, 36982, 36984, 36981, - 36980, 36977, 36976, 36979, 36978, 36985, 36983, 36930, 36916, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 22578, 22576, 40951, 22577, - 40951, 22591, 22606, 22610, 22590, 22600, 40951, 22592, 22607, 22588, - 22586, 22585, 22583, 22582, 22587, 22611, 22603, 22601, 22602, 22584, - 22608, 22609, 22596, 22594, 22573, 22595, 22572, 22589, 22612, 22615, - 22580, 40951, 22581, 40951, 22614, 22597, 22598, 22599, 22604, 22593, - 22616, 22605, 22642, 22624, 22629, 22625, 22627, 22637, 22638, 22631, - 22632, 22633, 22634, 22619, 22630, 22618, 22617, 40951, 40951, 22635, - 22636, 22639, 22628, 22626, 40951, 22640, 40951, 22623, 22620, 22621, - 22622, 22653, 22654, 22641, 40951, 22649, 22651, 22648, 22647, 22644, - 22643, 22646, 22645, 22652, 22650, 40951, 40951, 22569, 22568, 22575, - 22574, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 37208, 37115, 37113, 37114, 37123, 37111, 37108, - 37112, 37132, 37103, 37101, 37124, 37139, 37133, 37129, 37136, 37128, - 37131, 37130, 37107, 37116, 37099, 37098, 37026, 37027, 37025, 37147, - 37148, 37149, 37151, 37152, 37150, 37048, 37050, 37047, 37046, 37043, - 37042, 37045, 37044, 37051, 37049, 37040, 37037, 37036, 37033, 37032, - 37035, 37034, 37041, 37039, 37038, 37104, 37126, 37106, 37125, 37109, - 37135, 37117, 37118, 37119, 37120, 37158, 37144, 37057, 37055, 37085, - 37084, 37067, 37083, 37082, 37092, 40951, 37069, 37077, 37076, 37062, - 37061, 37068, 37079, 37078, 37066, 37065, 37070, 37087, 37086, 37081, - 37080, 37094, 37075, 37074, 37064, 37063, 37095, 37088, 37089, 37090, - 37096, 37059, 37093, 37071, 37072, 37073, 37091, 37097, 37054, 37060, - 37056, 37058, 40951, 40951, 40951, 40951, 37232, 37228, 37229, 37220, - 37221, 37222, 37223, 37224, 37225, 37230, 37231, 37226, 37227, 37155, - 37156, 37218, 37219, 37146, 37160, 37121, 37138, 37142, 37157, 37143, - 37145, 37140, 37141, 37159, 37207, 37206, 37205, 37172, 37171, 37191, - 37190, 37173, 37189, 37188, 37198, 40951, 37175, 37183, 37182, 37165, - 37164, 37174, 37185, 37184, 37169, 37168, 37176, 37193, 37192, 37187, - 37186, 37200, 37181, 37180, 37167, 37166, 37202, 37194, 37195, 37196, - 37203, 37201, 37199, 37177, 37178, 37179, 37197, 37204, 37170, 37162, - 37163, 37161, 40951, 37052, 37053, 37028, 37029, 37031, 37030, 37209, - 37216, 37214, 37217, 37215, 37210, 37213, 37212, 37211, 40951, 37154, - 37153, 37102, 37105, 37127, 37122, 37110, 32022, 24181, 32023, 24182, - 37137, 37134, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 28582, - 28561, 28560, 28559, 28591, 28659, 28658, 28661, 28660, 28592, 28589, - 28637, 28636, 28643, 28642, 28590, 28621, 28638, 28645, 28644, 28593, - 28663, 28662, 28657, 28656, 28588, 28665, 28595, 28655, 28641, 28620, - 28664, 28654, 28551, 28615, 28652, 28653, 28646, 28647, 28554, 28587, - 28666, 28553, 28758, 28742, 28765, 28766, 28759, 28760, 28754, 28739, - 28747, 28748, 28755, 28683, 28702, 28707, 28706, 28682, 28546, 28544, - 28545, 28543, 28558, 28783, 28785, 28782, 28781, 28778, 28777, 28780, - 28779, 28786, 28784, 28705, 28694, 28712, 28716, 28711, 28715, 28596, - 28619, 28648, 28649, 28650, 28651, 28761, 28762, 28763, 28764, 28586, - 28585, 28583, 28584, 28549, 28548, 28547, 28618, 28753, 28727, 28728, - 28640, 28639, 28756, 28757, 28697, 28698, 28699, 28700, 28701, 28557, - 28556, 28555, 28743, 28745, 28746, 28744, 28610, 28609, 28608, 28606, - 28614, 28598, 28611, 28599, 28601, 28612, 28604, 28602, 28613, 28550, - 28752, 28749, 28750, 28751, 28689, 28690, 28691, 28692, 28687, 28688, - 28686, 28594, 28703, 28678, 28680, 28677, 28676, 28673, 28672, 28675, - 28674, 28681, 28679, 28684, 28685, 28740, 28741, 28714, 28713, 17728, - 17754, 17739, 17760, 17761, 17759, 17749, 17750, 17762, 17743, 17752, - 17755, 17757, 17763, 17745, 17748, 17753, 17747, 17751, 17764, 17744, - 17742, 17738, 17758, 17746, 17734, 17737, 17741, 17736, 17735, 17756, - 17740, 17729, 17733, 17731, 17766, 17730, 17732, 40951, 17765, 40951, - 40951, 40951, 40951, 40951, 17727, 40951, 40951, 17811, 17842, 17819, - 17848, 17817, 17847, 17840, 17837, 17849, 17829, 17831, 17843, 17845, - 17850, 17833, 17839, 17841, 17835, 17838, 17808, 17832, 17828, 17818, - 17846, 17834, 17812, 17815, 17827, 17814, 17813, 17844, 17826, 17822, - 17825, 17823, 17852, 17820, 17824, 17853, 17851, 17816, 17836, 17810, - 17900, 27795, 17809, 17821, 17830, 19147, 19221, 19155, 19226, 19219, - 19183, 19150, 19165, 19223, 19197, 19215, 19129, 19127, 19213, 19114, - 19149, 19233, 19162, 19236, 19157, 19222, 19159, 19158, 19230, 19193, - 19217, 19196, 19142, 19152, 19146, 19175, 19180, 19179, 19166, 19170, - 19168, 19171, 19172, 19169, 19177, 19176, 19178, 19173, 19144, 19145, - 19204, 19210, 19209, 19202, 19207, 19198, 19199, 19201, 19212, 19206, - 19205, 19203, 19208, 19200, 19211, 19119, 19118, 19124, 19123, 19182, - 19139, 19138, 19136, 19131, 19141, 19132, 19225, 19135, 19134, 19137, - 19130, 19234, 19128, 19121, 19117, 19126, 19122, 19115, 19116, 19120, - 19125, 19163, 19143, 19224, 19235, 19148, 19161, 19156, 19160, 19227, - 19238, 19476, 19382, 19392, 19440, 19444, 19394, 19393, 19446, 19445, - 19421, 19473, 19474, 19431, 19452, 19432, 19472, 19471, 19475, 19461, - 19398, 19450, 19405, 19390, 19391, 19442, 19441, 19396, 19397, 19395, - 19448, 19449, 19429, 19428, 19424, 19422, 19430, 19453, 19454, 19455, - 19460, 19459, 19437, 19438, 19436, 19433, 19439, 19466, 19465, 19464, - 19463, 19462, 19470, 19468, 19404, 19401, 19451, 19406, 19408, 19415, - 19419, 19417, 19407, 19383, 19385, 19388, 19387, 19420, 19389, 19443, - 19447, 19426, 19427, 19258, 19359, 19261, 19281, 19284, 19288, 19363, - 19309, 19310, 19315, 19319, 19328, 19331, 19324, 19336, 19268, 19298, - 19301, 19337, 19354, 19250, 19241, 19244, 19267, 19372, 19294, 19245, - 19260, 19262, 19287, 19286, 19290, 19289, 19285, 19370, 19364, 19312, - 19335, 19329, 19330, 19349, 19316, 19318, 19323, 19322, 19313, 19327, - 19325, 19314, 19332, 19278, 19275, 19269, 19274, 19273, 19271, 19276, - 19280, 19257, 19299, 19303, 19308, 19256, 19339, 19347, 19340, 19343, - 19291, 19252, 19253, 19362, 19251, 19373, 19377, 19380, 19296, 19255, - 19248, 19246, 19247, 19249, 19381, 19264, 19265, 19263, 19259, 19266, - 19360, 17020, 17027, 17026, 17021, 17025, 17024, 17022, 17023, 17247, - 17255, 17254, 17248, 17252, 17251, 17249, 17253, 17013, 17019, 17017, - 17014, 17016, 17015, 17018, 17004, 17064, 17072, 17071, 17065, 17069, - 17068, 17066, 17062, 17176, 17183, 17181, 17177, 17179, 17178, 17182, - 17180, 17151, 17160, 17159, 17152, 17156, 17155, 17153, 17157, 17191, - 17197, 17196, 17192, 17166, 17161, 17193, 17195, 17167, 17175, 17174, - 17168, 17172, 17171, 17169, 17173, 17143, 17150, 17149, 17144, 17148, - 17147, 17145, 17146, 17131, 40951, 17135, 17132, 17134, 17133, 40951, - 40951, 17124, 17130, 17128, 17125, 17127, 17126, 17129, 40951, 17119, - 40951, 17123, 17120, 17122, 17121, 40951, 40951, 16854, 16861, 16860, - 16855, 16859, 16858, 16856, 16845, 17316, 17323, 17321, 17317, 17319, - 17318, 17322, 17320, 17229, 17237, 17236, 17230, 17234, 17233, 17231, - 17235, 16892, 16900, 16899, 16893, 16897, 16896, 16894, 16898, 17284, - 17291, 17290, 17285, 17289, 17288, 17286, 17287, 17272, 40951, 17276, - 17273, 17275, 17274, 40951, 40951, 17082, 17090, 17089, 17083, 17087, - 17086, 17084, 17088, 17073, 17081, 17080, 17074, 17078, 17077, 17075, - 17079, 16974, 16982, 16981, 16975, 16979, 16978, 16976, 16980, 17052, - 17059, 17058, 17053, 17057, 17056, 17054, 17055, 17040, 40951, 17044, - 17041, 17043, 17042, 40951, 40951, 17033, 17039, 17037, 17034, 17036, - 17035, 17038, 40951, 17028, 40951, 17032, 17029, 17031, 17030, 40951, - 40951, 17256, 17263, 17262, 17257, 17261, 17260, 17258, 17259, 17092, - 17098, 17096, 17093, 17095, 17094, 17097, 40951, 17307, 17315, 17314, - 17308, 17312, 17311, 17309, 17313, 17292, 17299, 17297, 17293, 17295, - 17294, 17298, 17296, 17264, 17271, 17270, 17265, 17269, 17268, 17266, - 17267, 16922, 16930, 16929, 16923, 16927, 16926, 16924, 16928, 16907, - 16915, 16914, 16908, 16912, 16911, 16909, 16913, 17238, 17246, 17245, - 17239, 17243, 17242, 17240, 17244, 16995, 16943, 17001, 16996, 17000, - 16999, 16997, 16998, 16983, 40951, 16987, 16984, 16986, 16985, 40951, - 40951, 16967, 16973, 16971, 16968, 16970, 16969, 16972, 16963, 17198, - 17206, 17205, 17199, 17203, 17202, 17200, 17204, 16883, 16891, 16890, - 16884, 16888, 16887, 16885, 16889, 17091, 17106, 17105, 17099, 17103, - 17102, 17100, 17104, 17221, 17228, 17226, 17222, 17224, 17223, 17227, - 17225, 17213, 17220, 17219, 17214, 17218, 17217, 17215, 17216, 16935, - 16942, 16940, 16936, 16938, 16937, 16941, 16933, 17111, 17118, 17117, - 17112, 17116, 17115, 17113, 17109, 17158, 17070, 16939, 40951, 40951, - 16823, 16825, 16824, 16842, 17345, 17343, 16826, 16841, 16827, 16840, - 17344, 16839, 17341, 17339, 17338, 17335, 17334, 17337, 17336, 17342, - 17340, 16828, 16831, 16830, 16835, 16834, 16838, 16837, 16833, 16836, - 16832, 16829, 40951, 40951, 40951, 17164, 17063, 17061, 17060, 17162, - 16846, 16844, 16843, 17163, 16934, 16932, 16931, 17165, 17110, 17108, - 17107, 17333, 17324, 17330, 17331, 17326, 17328, 17332, 17327, 17325, - 17329, 40951, 40951, 40951, 40951, 40951, 40951, 6382, 6383, 6384, 6385, - 6386, 6387, 6345, 6381, 6346, 6347, 6348, 6349, 6350, 6310, 6311, 6312, - 6313, 6314, 6315, 6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, - 6360, 6361, 6316, 6309, 6317, 6318, 6319, 6320, 6321, 6322, 6363, 6364, - 6365, 6366, 6367, 6368, 6324, 6323, 6325, 6326, 6327, 6328, 6329, 6303, - 6342, 6304, 6343, 6305, 6344, 6306, 6307, 6308, 6302, 6330, 6331, 6332, - 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6340, 6341, 6369, 6370, 6371, - 6372, 6373, 6374, 6375, 6376, 6377, 6378, 6379, 6380, 6362, 40951, 40951, - 6462, 6463, 6464, 6465, 6466, 6448, 40951, 40951, 5524, 5496, 5269, 5526, - 5527, 5676, 5690, 5973, 5480, 5340, 5267, 5268, 5850, 5940, 5960, 5938, - 5961, 5939, 5942, 5936, 5943, 5937, 5605, 5957, 5934, 5958, 5935, 5606, - 5271, 5974, 5992, 5513, 5512, 5514, 5515, 5507, 5508, 5505, 5504, 5517, - 5511, 5516, 5506, 5498, 5528, 5689, 5275, 5710, 5703, 5708, 5709, 5705, - 5706, 5964, 5338, 5339, 5701, 5702, 5700, 5879, 5698, 5877, 5699, 5878, - 5693, 5875, 5694, 5876, 5696, 5873, 5697, 5874, 5963, 5692, 5872, 5331, - 5849, 5832, 5847, 5848, 5845, 5846, 5971, 5302, 5315, 5830, 5831, 5840, - 5932, 5838, 5930, 5839, 5931, 5836, 5928, 5837, 5929, 5834, 5926, 5835, - 5927, 5611, 5792, 5827, 5828, 5829, 5826, 5547, 5541, 5545, 5546, 5543, - 5544, 5966, 5539, 5540, 5538, 5924, 5536, 5922, 5537, 5923, 5534, 5920, - 5535, 5921, 5531, 5918, 5532, 5919, 5608, 5529, 5530, 5772, 5773, 5774, - 5771, 5495, 5482, 5493, 5494, 5491, 5492, 5965, 5299, 5481, 5489, 5917, - 5487, 5915, 5488, 5916, 5485, 5913, 5486, 5914, 5483, 5911, 5484, 5912, - 5607, 5298, 5748, 5573, 5581, 5590, 5591, 5576, 5577, 5968, 5579, 5580, - 5589, 5871, 5587, 5869, 5588, 5870, 5585, 5867, 5586, 5868, 5583, 5865, - 5584, 5866, 5609, 5572, 5864, 5592, 5273, 5749, 5665, 5626, 5663, 5664, - 5653, 5654, 5969, 5597, 5625, 5662, 5890, 5656, 5888, 5657, 5889, 5610, - 5593, 5371, 5666, 5571, 5558, 5569, 5570, 5567, 5568, 5967, 5556, 5557, - 5566, 5858, 5564, 5856, 5565, 5857, 5562, 5854, 5563, 5855, 5560, 5852, - 5561, 5853, 5548, 5851, 5574, 5791, 5751, 5789, 5790, 5770, 5775, 5970, - 5731, 5750, 5784, 5910, 5782, 5908, 5783, 5909, 5780, 5906, 5781, 5907, - 5778, 5904, 5779, 5905, 5603, 5730, 5274, 5777, 5294, 5578, 5598, 5604, - 5601, 5602, 5599, 5600, 5769, 5767, 5768, 5761, 5762, 5764, 5765, 5760, - 5903, 5758, 5901, 5759, 5902, 5753, 5899, 5754, 5900, 5756, 5897, 5757, - 5898, 5752, 5991, 5977, 5989, 5990, 5979, 5980, 5972, 5975, 5976, 5988, - 5887, 5986, 5885, 5987, 5886, 5984, 5883, 5985, 5884, 5982, 5881, 5983, - 5882, 5612, 5962, 5295, 5880, 5747, 5729, 5713, 5863, 5723, 5727, 5728, - 5725, 5726, 5861, 5721, 5722, 5859, 5715, 5892, 5711, 5891, 5575, 5523, - 5502, 5503, 5518, 5520, 5521, 5500, 5501, 5522, 5933, 5499, 5811, 5596, - 5809, 5594, 5810, 5595, 5807, 5808, 5805, 5806, 5803, 5925, 5793, 5824, - 5825, 5821, 5819, 5818, 5842, 5843, 5844, 5841, 5651, 5649, 5650, 5647, - 5648, 5645, 5646, 5644, 5652, 5525, 5670, 5674, 5675, 5672, 5673, 5668, - 5669, 5667, 5816, 5817, 5812, 5815, 5894, 5895, 5896, 5893, 5631, 5635, - 5636, 5633, 5634, 5629, 5630, 5628, 5637, 5745, 5746, 5741, 5744, 5953, - 5954, 5955, 5952, 5944, 5554, 5555, 5552, 5553, 5550, 5551, 5549, 5801, - 5799, 5800, 5797, 5798, 5795, 5796, 5794, 5272, 5291, 5292, 5293, 5290, - 5279, 5280, 5281, 5278, 5287, 5288, 5289, 5286, 5283, 5284, 5285, 5282, - 5736, 5737, 5733, 5735, 5321, 5320, 5316, 5317, 5319, 5318, 5467, 5466, - 5462, 5463, 5465, 5464, 5473, 5472, 5468, 5469, 5471, 5470, 5337, 5336, - 5332, 5333, 5335, 5334, 5431, 5430, 5426, 5427, 5429, 5428, 5425, 5424, - 5420, 5421, 5423, 5422, 5394, 5393, 5389, 5390, 5392, 5391, 5388, 5330, - 5329, 5326, 5327, 5328, 5324, 5367, 5366, 5362, 5363, 5365, 5364, 5361, - 5360, 5356, 5357, 5359, 5358, 5355, 5374, 5373, 5368, 5369, 5372, 5370, - 5461, 5460, 5456, 5457, 5459, 5458, 5479, 5478, 5474, 5475, 5477, 5476, - 5354, 5738, 5353, 5348, 5349, 5352, 5740, 5351, 5347, 5346, 5342, 5343, - 5345, 5344, 5449, 5448, 5444, 5445, 5447, 5446, 5308, 5307, 5303, 5304, - 5306, 5305, 5443, 5442, 5438, 5439, 5441, 5440, 5407, 5406, 5402, 5403, - 5405, 5404, 5413, 5412, 5408, 5409, 5411, 5410, 5401, 5400, 5396, 5397, - 5399, 5398, 5395, 5341, 5314, 5313, 5309, 5310, 5312, 5311, 5387, 5386, - 5382, 5383, 5385, 5384, 5381, 5380, 5376, 5377, 5379, 5378, 5375, 5437, - 5436, 5432, 5433, 5435, 5434, 5455, 5454, 5450, 5451, 5453, 5452, 5419, - 5418, 5414, 5415, 5417, 5416, 5490, 5519, 5671, 5632, 5642, 5643, 5640, - 5641, 5638, 5639, 5951, 5949, 5950, 5947, 5948, 5945, 5946, 5956, 5277, - 29977, 29952, 29963, 29959, 29969, 29966, 29972, 29975, 29976, 29955, - 29954, 29974, 29960, 29965, 29970, 29964, 29951, 29967, 29973, 29957, - 29961, 29956, 29968, 29971, 29962, 29958, 29953, 29949, 29950, 40951, - 40951, 40951, 32296, 32352, 32346, 32350, 32349, 32344, 32342, 32289, - 32274, 32320, 32273, 32272, 32317, 32332, 32319, 32323, 32324, 32326, - 32312, 32278, 32311, 32297, 32290, 32298, 32300, 32345, 32302, 32301, - 32315, 32329, 32341, 32331, 32283, 32305, 32286, 32309, 32299, 32314, - 32335, 32306, 32348, 32275, 32338, 32337, 32333, 32276, 32354, 32343, - 32334, 32281, 32340, 32328, 32284, 32322, 32287, 32347, 32316, 32330, - 32313, 32282, 32304, 32303, 32285, 32321, 32288, 32308, 32280, 32279, - 32277, 32339, 32318, 32336, 32307, 32351, 32353, 32355, 32356, 32271, - 32357, 32358, 32270, 32310, 32327, 32325, 32294, 32293, 32295, 32292, - 32291, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 35025, 35042, - 35043, 35033, 35031, 35027, 35039, 35030, 35028, 35036, 35029, 35035, - 35041, 35037, 35034, 35040, 35038, 35032, 35046, 35047, 35045, 35044, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 35026, - 19648, 19649, 19650, 19639, 19637, 19633, 19645, 19636, 19634, 19642, - 19635, 19641, 19647, 19643, 19640, 19646, 19644, 19638, 19652, 19653, - 19651, 31427, 31428, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 4990, 4991, 4992, 4981, 4979, 4975, 4987, 4978, 4976, 4984, - 4977, 4983, 4989, 4985, 4982, 4988, 4986, 4980, 4993, 4994, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 35061, 35062, 35063, 35053, 35052, 35048, 35058, 35051, 35049, 35056, - 35050, 35055, 35060, 40951, 35054, 35059, 35057, 40951, 35064, 35065, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 22231, 22229, 22232, 22230, 22233, 22227, 22225, 22228, - 22226, 22235, 22249, 22245, 22250, 22246, 22234, 22247, 22243, 22248, - 22244, 22236, 22257, 22237, 22239, 22238, 22253, 22256, 22254, 22252, - 22255, 22241, 22240, 22242, 22258, 22251, 22259, 22206, 22204, 22214, - 22215, 22210, 22213, 22211, 22212, 22223, 22224, 22221, 22222, 22216, - 22205, 22209, 22208, 22207, 22326, 22325, 22327, 22332, 22334, 22338, - 22340, 22342, 22344, 22343, 22335, 22339, 22333, 22345, 22329, 22330, - 22337, 22331, 22280, 22274, 22279, 22281, 22276, 22265, 22273, 22275, - 22270, 22262, 22263, 22282, 22269, 22264, 22271, 22266, 22268, 22277, - 22267, 22278, 22272, 22203, 22260, 22261, 40951, 40951, 22352, 22354, - 22351, 22350, 22347, 22346, 22349, 22348, 22355, 22353, 40951, 40951, - 40951, 40951, 40951, 40951, 22304, 22303, 22300, 22302, 22301, 22295, - 22298, 22299, 22297, 22296, 40951, 40951, 40951, 40951, 40951, 40951, - 28162, 28174, 28170, 28019, 28169, 28020, 28167, 28158, 28171, 28172, - 28173, 28018, 28017, 28016, 28168, 28015, 28011, 28013, 28010, 28009, - 28006, 28005, 28008, 28007, 28014, 28012, 40951, 40951, 40951, 40951, - 40951, 40951, 28023, 28137, 28154, 28139, 28141, 28140, 28142, 28138, - 28148, 28051, 28143, 28149, 28150, 28146, 28055, 28136, 28098, 28097, - 28128, 28144, 28052, 28147, 28153, 28151, 28152, 28145, 28134, 28133, - 28127, 28131, 28132, 28130, 28135, 28129, 28054, 28107, 28125, 28126, - 28114, 28116, 28115, 28117, 28101, 28118, 28121, 28122, 28108, 28120, - 28111, 28103, 28112, 28105, 28110, 28124, 28123, 28119, 28109, 28113, - 28104, 28106, 28102, 28096, 28079, 28080, 28090, 28089, 28086, 28094, - 28075, 28077, 28095, 28084, 28082, 28091, 28093, 28092, 28076, 28078, - 28081, 28088, 28085, 28083, 28087, 28074, 28072, 28073, 28071, 28070, - 28053, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 28025, 28027, - 28029, 28036, 28035, 28043, 28039, 28024, 28034, 28050, 28037, 28049, - 28041, 28040, 28031, 28038, 28042, 28028, 28045, 28044, 28048, 28046, - 28047, 28026, 28100, 28099, 28063, 28068, 28059, 28064, 28060, 28056, - 28061, 28057, 28069, 28058, 28066, 28067, 28033, 28032, 28062, 28030, - 28065, 40951, 40951, 40951, 40951, 40951, 5691, 5276, 5270, 5959, 5707, - 5704, 5695, 5833, 5542, 5533, 5582, 5655, 5627, 5559, 5776, 5732, 5763, - 5766, 5755, 5981, 5978, 5724, 5660, 5680, 5661, 5681, 5658, 5678, 5659, - 5679, 5720, 5718, 5719, 5716, 5717, 5714, 5687, 5688, 5685, 5684, 5686, - 5677, 5682, 5683, 5497, 5941, 5510, 5509, 5712, 5862, 5860, 5804, 5802, - 5823, 5822, 5820, 5814, 5813, 5743, 5742, 5734, 5323, 5300, 5325, 5322, - 5739, 5350, 5296, 5297, 5301, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 24478, 24445, 24444, 24425, 24424, 24431, - 24439, 24438, 24443, 24442, 24430, 24428, 24426, 24441, 24440, 24432, - 24447, 24446, 24437, 24436, 24450, 24429, 24451, 24449, 24452, 24433, - 24434, 24435, 24448, 24423, 24427, 40951, 24469, 24476, 24477, 24475, - 24470, 24473, 24471, 24474, 24472, 24468, 24466, 24467, 40951, 40951, - 40951, 40951, 24460, 24457, 24459, 24465, 24458, 24463, 24462, 24464, - 24461, 24454, 24453, 24455, 40951, 40951, 40951, 40951, 24456, 40951, - 40951, 40951, 24479, 24480, 24487, 24489, 24486, 24485, 24482, 24481, - 24484, 24483, 24490, 24488, 35086, 35098, 35081, 35078, 35096, 35099, - 35080, 35079, 35093, 35088, 35087, 35094, 35091, 35097, 35092, 35095, - 35085, 35077, 35082, 35066, 35100, 35070, 35071, 35089, 35084, 35083, - 35090, 35069, 35067, 35068, 40951, 40951, 35072, 35073, 35074, 35075, - 35076, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 29120, 29142, 29102, 29104, 29107, 29124, 29126, 29129, - 29110, 29106, 29122, 29132, 29128, 29144, 29111, 29109, 29108, 29133, - 29131, 29130, 29113, 29112, 29119, 29135, 29134, 29141, 29116, 29121, - 29118, 29138, 29143, 29140, 29117, 29115, 29114, 29139, 29137, 29136, - 29101, 29103, 29123, 29125, 29105, 29127, 40951, 40951, 40951, 40951, - 29165, 29150, 29154, 29160, 29163, 29166, 29152, 29156, 29157, 29161, - 29153, 29151, 29164, 29159, 29158, 29162, 29155, 29100, 29095, 29094, - 29099, 29098, 29097, 29096, 29147, 29148, 40951, 40951, 40951, 40951, - 40951, 40951, 29173, 29175, 29172, 29171, 29168, 29167, 29170, 29169, - 29176, 29174, 29149, 40951, 40951, 40951, 29145, 29146, 22305, 22324, - 22317, 22320, 22322, 22315, 22313, 22311, 22307, 22309, 22294, 22292, - 22284, 22288, 22290, 22286, 22318, 22323, 22316, 22319, 22321, 22314, - 22312, 22310, 22306, 22308, 22293, 22291, 22283, 22287, 22289, 22285, - 4959, 4956, 4948, 4947, 4961, 4953, 4946, 4945, 4964, 4955, 4952, 4951, - 4954, 4958, 4950, 4949, 4966, 4962, 4960, 4965, 4963, 4967, 4957, 4970, - 4972, 4969, 4971, 4968, 40951, 40951, 4974, 4973, 35134, 35132, 35133, - 35150, 35149, 35148, 35174, 35140, 35139, 35153, 35160, 35152, 35175, - 35168, 35135, 35180, 35151, 35167, 35144, 35143, 35157, 35156, 35176, - 35179, 35142, 35141, 35145, 35155, 35158, 35154, 35181, 35161, 35147, - 35166, 35169, 35162, 35164, 35182, 35136, 35137, 35138, 35146, 35165, - 35183, 35159, 35172, 35173, 35170, 35171, 35178, 35177, 35163, 35131, - 35106, 35105, 35103, 35194, 35101, 35102, 35104, 35107, 35108, 35109, - 40951, 35202, 35209, 35213, 35210, 35219, 35225, 35226, 35224, 35223, - 35221, 35222, 35214, 35215, 35218, 35227, 35211, 35217, 35212, 35220, - 35216, 35193, 35206, 35207, 35186, 35187, 35188, 35197, 35196, 35189, - 40951, 40951, 35110, 35117, 35119, 35116, 35115, 35112, 35111, 35114, - 35113, 35120, 35118, 40951, 40951, 40951, 40951, 40951, 40951, 35127, - 35129, 35126, 35125, 35122, 35121, 35124, 35123, 35130, 35128, 40951, - 40951, 40951, 40951, 40951, 40951, 35203, 35204, 35201, 35192, 35185, - 35205, 35198, 35195, 35190, 35191, 35199, 35200, 35184, 35208, 40951, - 40951, 8201, 8169, 8285, 8203, 8435, 8448, 8447, 8387, 8184, 8364, 8423, - 8393, 8188, 8392, 8391, 8333, 8327, 8350, 8409, 8351, 8410, 8421, 8380, - 8284, 8396, 8187, 8186, 8433, 8311, 8312, 8313, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 2717, 2716, 2718, 2715, 2719, - 2626, 2627, 2643, 2644, 2647, 2648, 2665, 2666, 2656, 2657, 2640, 2630, - 2645, 2646, 2651, 2653, 2641, 2642, 2660, 2633, 2634, 2649, 2650, 2661, - 2672, 2671, 2637, 2636, 2659, 2670, 2673, 2635, 2638, 2658, 2662, 2663, - 2631, 2632, 2678, 2680, 2664, 2655, 2679, 2668, 2669, 2667, 2677, 2720, - 2731, 2734, 2735, 2725, 2726, 2723, 2724, 2721, 2722, 2727, 2728, 2730, - 2729, 2732, 2733, 2736, 2652, 2654, 2674, 2639, 2675, 2676, 2628, 2629, - 40951, 2625, 2624, 2744, 2746, 2743, 2742, 2739, 2738, 2741, 2740, 2747, - 2745, 2712, 2709, 2737, 2622, 2623, 2621, 2711, 2698, 2696, 2699, 2690, - 2691, 2697, 2693, 2695, 2694, 2692, 2688, 2687, 2683, 2681, 2685, 2684, - 2682, 2686, 2689, 2708, 2707, 2706, 2705, 2700, 2702, 2703, 2704, 2701, - 2713, 2710, 2714, 34633, 34631, 34632, 34584, 34619, 34621, 34586, 34620, - 34596, 34597, 34604, 34612, 34607, 34598, 34605, 34609, 34618, 34599, - 34613, 34606, 34600, 34611, 34589, 34614, 34602, 34610, 34617, 34593, - 34591, 34615, 34595, 34616, 34608, 34579, 34580, 34581, 34639, 34638, - 34640, 34637, 34635, 34636, 34630, 34634, 34582, 34583, 34603, 34594, - 34647, 34649, 34646, 34645, 34642, 34641, 34644, 34643, 34650, 34648, - 34578, 34592, 34590, 34601, 34587, 34588, 3508, 3494, 3502, 3486, 3474, - 3498, 3497, 3483, 3489, 3482, 3475, 3506, 3492, 3484, 3501, 3485, 3503, - 3500, 3505, 3490, 3473, 3488, 3495, 3478, 3496, 3491, 3476, 3507, 3493, - 3480, 3504, 3487, 3481, 3499, 3479, 3477, 3509, 3510, 3517, 3523, 3520, - 3524, 3525, 3521, 3526, 3522, 3518, 3519, 3471, 3472, 3511, 3512, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 3516, 3514, 3515, 3513, - 24308, 24307, 24306, 24320, 24319, 24325, 24335, 24334, 24338, 24326, - 24333, 24332, 24314, 24327, 24311, 24310, 24309, 24318, 24317, 24316, - 24315, 24324, 24323, 24329, 24328, 24313, 24343, 24340, 24339, 24322, - 24321, 24341, 24337, 24336, 24342, 24344, 24353, 24352, 24358, 24360, - 24356, 24357, 24354, 24355, 24359, 24297, 24302, 24301, 24299, 24303, - 24304, 24305, 24300, 24298, 24351, 24350, 40951, 40951, 40951, 24345, - 24348, 24349, 24347, 24346, 24367, 24369, 24366, 24365, 24362, 24361, - 24364, 24363, 24370, 24368, 40951, 40951, 40951, 24331, 24330, 24312, - 30023, 30025, 30022, 30021, 30018, 30017, 30020, 30019, 30026, 30024, - 29996, 29987, 29985, 29984, 29986, 29997, 29981, 29980, 29982, 29983, - 29999, 29995, 29993, 29992, 29994, 30001, 30007, 30008, 30006, 30009, - 29998, 29991, 29988, 29990, 29989, 30000, 30002, 30003, 30005, 30004, - 30011, 30012, 30010, 30016, 30015, 30027, 30014, 30013, 10430, 10407, - 10413, 10470, 10451, 10459, 10449, 10450, 10469, 10135, 10461, 40951, - 40951, 40951, 40951, 40951, 17856, 17887, 17864, 17893, 17862, 17892, - 17885, 17882, 17894, 17874, 17876, 17888, 17890, 17895, 17878, 17884, - 17886, 17880, 17883, 17896, 17877, 17873, 17863, 17891, 17879, 17857, - 17860, 17872, 17859, 17858, 17889, 17871, 17867, 17870, 17868, 17898, - 17865, 17869, 17899, 17897, 17861, 17881, 17855, 40951, 40951, 17854, - 17866, 17875, 34629, 34627, 34628, 34626, 34625, 34624, 34623, 34622, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 38803, 38816, - 38805, 38783, 38797, 38811, 38812, 38813, 38798, 38814, 38801, 38809, - 38804, 38802, 38810, 38808, 38807, 38815, 38796, 38794, 38785, 38792, - 38784, 38795, 38793, 38774, 38775, 38777, 38778, 38790, 38788, 38789, - 38787, 38776, 38780, 38786, 38799, 38782, 38791, 38779, 38806, 38800, - 38781, 40951, 40951, 40951, 40951, 40951, 23270, 23271, 23878, 23267, - 23272, 23273, 23244, 23243, 23863, 23856, 23276, 23277, 23250, 23278, - 23256, 23251, 23252, 23813, 23814, 23815, 23858, 23254, 23850, 23370, - 23280, 23257, 23265, 23260, 23283, 23818, 23817, 23816, 23284, 23285, - 23287, 23245, 23298, 23232, 18400, 18403, 18399, 18402, 18398, 10300, - 27701, 27702, 27692, 27693, 27704, 27705, 27695, 27707, 27697, 27708, - 27709, 27710, 27711, 27712, 27713, 27696, 27699, 27700, 27714, 27694, - 27716, 27717, 27719, 27850, 27957, 27851, 27959, 27854, 27879, 27893, - 27947, 27932, 27962, 27900, 27970, 27981, 27910, 27897, 27930, 27933, - 27954, 27856, 27934, 27949, 27974, 27948, 27960, 27978, 27852, 27858, - 27901, 27884, 27902, 27878, 24019, 24027, 24029, 24030, 18609, 18605, - 18608, 18607, 18606, 23939, 23356, 23405, 23491, 23634, 23654, 23731, - 23758, 23751, 23797, 23833, 24001, 23885, 27768, 23562, 23843, 23300, - 23569, 23727, 23301, 23938, 23357, 23409, 23492, 23505, 23588, 23615, - 23635, 23660, 23732, 23761, 23798, 23478, 23946, 23973, 24002, 23319, - 23345, 23408, 23468, 23720, 23768, 23806, 23559, 23716, 23480, 23925, - 23486, 27958, 27859, 27877, 27895, 27941, 27898, 27885, 27946, 27969, - 27912, 27913, 27860, 27862, 27915, 27919, 27921, 27865, 27911, 27961, - 27929, 27928, 27871, 27855, 27935, 27945, 27894, 27950, 27976, 27977, - 27873, 27980, 27971, 27890, 27892, 27891, 27896, 27973, 8177, 8176, 8425, - 8424, 8377, 8268, 8376, 8061, 8267, 8060, 8325, 8073, 8378, 8200, 8389, - 8416, 8286, 8440, 8441, 8308, 8299, 8300, 8301, 8303, 8310, 8306, 8335, - 8291, 8337, 8314, 8292, 8293, 8339, 8294, 8295, 8324, 8328, 8316, 8343, - 8298, 8330, 8331, 8329, 8307, 8315, 8319, 8340, 8305, 8322, 8332, 8297, - 8318, 8321, 8439, 8290, 8289, 8172, 8445, 8175, 8167, 8181, 8070, 8345, - 8400, 22756, 23317, 22792, 23359, 22791, 23358, 22790, 23355, 22799, - 23374, 22824, 23411, 22823, 23410, 22822, 23406, 22818, 23400, 22819, - 23401, 22850, 23454, 22851, 23455, 22839, 23442, 22848, 23452, 22830, - 23433, 22875, 23494, 22883, 23504, 22902, 23524, 22901, 23523, 22899, - 23521, 22896, 23518, 22895, 23517, 22919, 23551, 22913, 23539, 22950, - 23586, 22947, 23583, 22951, 23587, 22958, 23600, 22959, 23601, 22969, - 23610, 22965, 23597, 22975, 23632, 22977, 23637, 22976, 23636, 22995, - 23659, 22994, 23658, 22989, 23651, 22985, 23646, 23026, 23695, 23025, - 23694, 23003, 23687, 23004, 23688, 23054, 23730, 23056, 23734, 23065, - 23748, 23063, 23746, 23064, 23747, 23070, 23753, 23091, 23791, 23089, - 23789, 23088, 23782, 23083, 23784, 23090, 23790, 23112, 23831, 23111, - 23830, 23113, 23834, 23107, 23824, 23143, 23906, 23164, 23929, 23136, - 23899, 23163, 23928, 23155, 23918, 23176, 23949, 23175, 23945, 23189, - 23962, 23190, 23963, 23186, 23959, 23188, 23961, 23187, 23960, 23195, - 23968, 23194, 23967, 23200, 23978, 23211, 23992, 23215, 23996, 23217, - 23998, 23525, 23829, 23964, 23988, 23318, 23625, 23624, 23626, 23101, - 23415, 22750, 23311, 22766, 23329, 22762, 23325, 22761, 23324, 22760, - 23323, 22764, 23327, 22763, 23326, 22745, 23306, 22744, 23305, 22743, - 23304, 22747, 23308, 22746, 23307, 22844, 23447, 22855, 23460, 22847, - 23451, 22835, 23438, 22834, 23437, 22833, 23436, 22838, 23441, 22837, - 23440, 22920, 23552, 22910, 23543, 23017, 23680, 23037, 23706, 23009, - 23672, 23008, 23671, 23007, 23670, 23011, 23674, 23010, 23673, 23034, - 23703, 23033, 23702, 23032, 23701, 23036, 23705, 23035, 23704, 23146, - 23909, 23153, 23916, 23150, 23913, 23149, 23912, 23148, 23911, 23152, - 23915, 23151, 23914, 23201, 23979, 23199, 23977, 23203, 23981, 23207, - 23987, 22980, 23640, 22981, 23641, 23204, 23982, 18447, 18439, 18452, - 18444, 18448, 18440, 18450, 18442, 18213, 18205, 18216, 18208, 18214, - 18206, 18218, 18210, 18470, 18467, 18472, 18469, 18471, 18468, 40951, - 40951, 18253, 18250, 18255, 18252, 18254, 18251, 40951, 40951, 18485, - 18477, 18490, 18482, 18486, 18478, 18488, 18480, 18237, 18229, 18240, - 18232, 18238, 18230, 18242, 18234, 18511, 18502, 18514, 18505, 18513, - 18504, 18512, 18503, 18265, 18260, 18268, 18263, 18267, 18262, 18266, - 18261, 18572, 18569, 18574, 18571, 18573, 18570, 40951, 40951, 18299, - 18296, 18301, 18298, 18300, 18297, 40951, 40951, 18531, 18522, 18534, - 18525, 18533, 18524, 18532, 18523, 40951, 18311, 40951, 18314, 40951, - 18313, 40951, 18312, 18552, 18544, 18557, 18549, 18553, 18545, 18555, - 18547, 18283, 18275, 18286, 18278, 18284, 18276, 18288, 18280, 18437, - 18457, 18474, 18473, 18497, 18495, 18517, 18518, 18576, 18575, 18537, - 18538, 18564, 18562, 40951, 40951, 18454, 18446, 18453, 18445, 18449, - 18441, 18451, 18443, 18220, 18212, 18217, 18209, 18215, 18207, 18219, - 18211, 18492, 18484, 18491, 18483, 18487, 18479, 18489, 18481, 18244, - 18236, 18241, 18233, 18239, 18231, 18243, 18235, 18559, 18551, 18558, - 18550, 18554, 18546, 18556, 18548, 18290, 18282, 18287, 18279, 18285, - 18277, 18289, 18281, 18436, 18461, 18438, 18459, 18458, 40951, 18455, - 18456, 18222, 18226, 18223, 18224, 18221, 18396, 18424, 18425, 18429, - 18345, 18498, 18499, 18496, 40951, 18493, 18494, 18257, 18256, 18247, - 18246, 18245, 18428, 18427, 18426, 18516, 18520, 18509, 18508, 40951, - 40951, 18515, 18507, 18269, 18273, 18270, 18271, 40951, 18353, 18352, - 18351, 18536, 18540, 18529, 18528, 18584, 18583, 18535, 18527, 18316, - 18320, 18317, 18318, 18306, 18347, 18346, 18623, 40951, 40951, 18565, - 18566, 18563, 40951, 18560, 18561, 18303, 18302, 18293, 18292, 18291, - 18421, 18350, 40951, 16764, 16761, 16766, 16763, 37019, 17510, 33761, - 17439, 31718, 36992, 18978, 40757, 40756, 40758, 24189, 32047, 20456, - 29361, 17438, 16765, 16762, 20402, 11250, 11224, 24112, 31977, 33636, - 33634, 24065, 31942, 11223, 11218, 10529, 11217, 4995, 37548, 30526, - 37694, 20425, 20459, 24496, 31062, 24188, 32046, 31593, 24187, 32045, - 28962, 31296, 31297, 31679, 11232, 37562, 31885, 31879, 31893, 6007, - 33635, 33637, 31902, 11254, 20799, 30878, 37745, 6293, 6008, 2529, 20458, - 17514, 24120, 31988, 11255, 31742, 17353, 37393, 31884, 3854, 3896, - 25158, 31890, 8045, 37706, 8451, 34742, 20817, 17476, 36999, 31738, - 17503, 17463, 37695, 17504, 11196, 37573, 38824, 26974, 39366, 17636, - 20819, 20821, 20820, 40951, 24186, 32044, 17456, 31592, 20713, 7, 20712, - 6, 28957, 29359, 34713, 34701, 40951, 40951, 34708, 34707, 34710, 34709, - 34700, 34714, 34704, 34706, 34699, 34703, 34705, 34702, 34543, 34545, - 34542, 34541, 34538, 34537, 34540, 34539, 34533, 34544, 34534, 34536, - 34532, 34531, 34535, 40951, 24016, 24017, 24025, 24031, 24015, 24018, - 24021, 24022, 24023, 24024, 24026, 24014, 24028, 40951, 40951, 40951, - 17350, 8058, 8697, 17520, 25104, 27586, 28890, 31320, 32367, 39370, - 29093, 11190, 17351, 22555, 37582, 11372, 17901, 31321, 18673, 2540, - 20465, 6126, 25105, 34096, 36765, 20703, 37664, 29411, 25663, 32236, - 22737, 3762, 34076, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 8354, 8408, 8368, - 8420, 8066, 8082, 8347, 8405, 8413, 8081, 8065, 8427, 8213, 8204, 8207, - 8210, 8205, 8357, 8206, 8208, 8209, 8397, 8194, 8067, 8434, 8446, 8359, - 8365, 8412, 8358, 8346, 8404, 8069, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 0, - 100, 11266, 10553, 6130, 6009, 5260, 17352, 32555, 10555, 32552, 32544, - 3944, 11267, 31482, 31483, 32545, 3945, 32546, 32553, 25335, 11268, - 29454, 33992, 32548, 11264, 11269, 32549, 3946, 11270, 31655, 31863, - 32658, 36660, 37535, 38817, 11271, 30872, 30880, 20816, 3947, 37687, - 21610, 961, 32541, 3943, 16820, 32551, 32542, 32543, 37671, 32547, 32554, - 346, 3653, 17904, 10542, 20710, 32224, 17418, 11278, 11277, 11263, 11265, - 11279, 37680, 37681, 31889, 37682, 11276, 11272, 11273, 11274, 11275, - 31683, 37666, 31298, 2600, 37684, 34821, 38966, 38964, 38968, 38969, - 38974, 38962, 38973, 38972, 38960, 38967, 38959, 38961, 38970, 38958, - 38975, 17515, 32192, 32203, 32204, 32191, 32188, 32197, 32199, 32207, - 32208, 32200, 32206, 32202, 32185, 32193, 32189, 32195, 33823, 33827, - 33828, 33822, 33819, 33831, 33830, 33818, 33832, 33829, 33817, 33826, - 33821, 33824, 33820, 33825, 32196, 32190, 32201, 32205, 23774, 32198, - 32187, 32186, 32194, 38976, 37675, 37674, 40951, 40951, 40951, 40951, - 24190, 37896, 32049, 11308, 24094, 37767, 29392, 29365, 33964, 33979, - 24210, 32073, 24274, 32150, 24271, 37946, 32149, 11344, 24213, 32076, - 24221, 37909, 32056, 11322, 37768, 24219, 32082, 24204, 32068, 24102, - 24097, 11348, 37906, 37907, 11317, 11318, 32064, 11309, 972, 8029, 29394, - 24201, 977, 8031, 24240, 24234, 37923, 37920, 32110, 32104, 11359, 11356, - 32084, 37898, 24224, 24286, 37949, 32116, 11367, 24241, 32099, 24277, - 24101, 32092, 24275, 37913, 32090, 11349, 24099, 37770, 29405, 29378, - 33976, 33989, 24261, 32140, 24290, 32120, 37899, 11310, 24281, 37914, - 32096, 11350, 24200, 32063, 24272, 37950, 32151, 11346, 37955, 37951, - 37953, 37952, 37957, 37958, 32152, 29393, 33967, 37772, 31929, 11320, - 37007, 24220, 32083, 24096, 24206, 32066, 24095, 24285, 32115, 24104, - 17498, 8456, 31208, 36987, 36986, 16754, 20631, 28846, 16703, 29414, - 33803, 8464, 11016, 33796, 16768, 28805, 28793, 28797, 27590, 27597, - 11191, 10998, 32663, 2528, 32161, 4996, 34323, 8703, 17509, 31682, 20704, - 31919, 957, 26848, 34099, 11002, 11017, 31067, 29419, 25119, 25126, - 20792, 37747, 20777, 11221, 37572, 8470, 34735, 38954, 8032, 8023, 974, - 36988, 3654, 31773, 31681, 11192, 17355, 17726, 20446, 37297, 31891, - 20813, 33756, 39374, 29424, 27596, 2533, 29415, 1054, 1057, 29049, 362, - 29416, 364, 37563, 359, 16806, 17724, 11008, 1058, 17725, 1055, 20594, - 8057, 16804, 32159, 32160, 8649, 16821, 16807, 34488, 10558, 16790, - 26859, 31744, 29426, 20470, 29427, 34524, 24390, 18137, 24392, 18140, - 24381, 18130, 28542, 28541, 3652, 29425, 29429, 29428, 29054, 29051, - 24389, 18136, 29053, 29050, 24391, 18138, 29055, 29052, 31656, 34561, - 31665, 34570, 31664, 34569, 11019, 11022, 34549, 34721, 29412, 29413, - 34555, 34727, 29047, 29048, 34554, 34726, 28295, 28296, 28297, 34196, - 34285, 34198, 34287, 34131, 34138, 6804, 6750, 6809, 6542, 6555, 6805, - 6531, 6814, 6556, 34456, 34449, 34470, 34404, 32006, 24138, 11285, 37776, - 2534, 27605, 37579, 17499, 37566, 11248, 11021, 29423, 11024, 29046, - 31666, 34571, 29409, 8465, 29410, 8466, 30556, 20593, 28298, 20217, - 20800, 39395, 28891, 29364, 31925, 32002, 28802, 28803, 28804, 28798, - 10837, 11193, 34490, 11000, 4372, 24152, 31964, 24110, 31975, 31892, - 9946, 9945, 11242, 11241, 11220, 11245, 31476, 16791, 24395, 18146, - 38867, 38866, 24379, 18141, 16789, 16788, 16786, 16787, 11020, 11023, - 29420, 29421, 34197, 34286, 24380, 18129, 31663, 34568, 29417, 11014, - 29418, 11015, 38823, 27582, 37775, 11288, 16704, 16706, 33804, 16709, - 16708, 33805, 16707, 16705, 8467, 8468, 33797, 8469, 33798, 40669, 10838, - 16701, 20440, 37759, 11289, 31680, 31315, 39140, 24061, 31937, 24149, - 31946, 4355, 4352, 37483, 37479, 31882, 34229, 2524, 32565, 32561, 36658, - 31601, 38878, 31479, 37678, 39131, 20438, 37478, 37482, 4351, 4354, - 37472, 4349, 17524, 33863, 37760, 30548, 16817, 39379, 21612, 24159, - 32027, 16816, 3650, 10524, 360, 34831, 37499, 11009, 8475, 33788, 8651, - 8652, 1002, 1040, 1026, 1014, 1015, 1031, 1012, 982, 987, 1037, 1042, - 1028, 1027, 1022, 1029, 1010, 1034, 1023, 1030, 985, 994, 993, 1016, - 1019, 995, 1048, 1021, 1045, 991, 1020, 1018, 1046, 998, 1017, 1033, 992, - 999, 1008, 986, 1047, 1032, 983, 1013, 1044, 989, 1038, 1007, 984, 996, - 1009, 1050, 1049, 988, 990, 1051, 1039, 1036, 1025, 1024, 997, 1043, - 1000, 1035, 1005, 1004, 1041, 1001, 1006, 1003, 29430, 31924, 32844, - 3546, 38839, 20776, 8473, 10924, 16760, 8455, 39283, 16782, 365, 19928, - 6586, 6808, 4936, 37746, 28178, 20462, 30544, 30545, 31220, 31221, 10919, - 33880, 1011, 10549, 31667, 29278, 31669, 8052, 24155, 24156, 24154, - 31971, 31972, 31970, 24117, 24124, 24116, 31985, 31992, 31984, 24059, - 24057, 24058, 9948, 31935, 31933, 31934, 20787, 20406, 37828, 37867, - 34574, 34572, 37486, 4358, 4359, 31753, 24158, 32008, 20415, 20416, - 20417, 20418, 10571, 10569, 10573, 10562, 10566, 10574, 10563, 10567, - 10572, 10561, 10565, 10560, 10564, 10570, 10568, 34164, 31864, 17382, - 38834, 27419, 27411, 27418, 27412, 27416, 27417, 27415, 27414, 27413, - 11539, 17640, 37474, 4362, 37456, 4361, 37487, 4365, 39292, 3651, 34516, - 17468, 8, 16702, 10550, 3885, 3847, 3928, 3824, 3886, 3848, 3888, 367, - 34514, 37305, 20439, 3864, 3867, 3869, 3861, 11246, 3907, 3771, 31615, - 31612, 31613, 31614, 29932, 34816, 34824, 34825, 34805, 34803, 34806, - 34817, 34788, 34789, 34810, 34812, 34811, 34809, 34790, 34822, 34823, - 34792, 34801, 34800, 34799, 34798, 34814, 34828, 34804, 34791, 34802, - 34826, 34807, 34808, 34819, 34818, 34820, 34829, 34793, 3951, 30531, - 34815, 34796, 34827, 34795, 34794, 34797, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 29944, 29939, - 29942, 29943, 29936, 29937, 29935, 29934, 29941, 29938, 29940, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 6552, 6549, 6548, 6545, 6544, 6547, 6546, 6553, 6551, 6773, 6753, 6798, - 6786, 6768, 6756, 6772, 6770, 6752, 6799, 6787, 31154, 31152, 31151, - 31148, 31147, 31150, 31149, 31155, 31153, 31146, 31137, 31145, 31143, - 31138, 31139, 31141, 31142, 31136, 31140, 31144, 10859, 10871, 10868, - 10853, 10850, 10865, 10862, 10877, 10856, 29450, 29443, 29451, 29449, - 29444, 29445, 29446, 29448, 29442, 29453, 29452, 31182, 31183, 31184, - 31185, 31186, 31187, 31188, 31189, 31190, 31191, 31192, 31193, 31194, - 31195, 31196, 31197, 31198, 31199, 31200, 31201, 31202, 31203, 31204, - 31205, 31206, 31207, 6696, 6697, 6698, 6699, 6700, 6701, 6702, 6703, - 6704, 6705, 6706, 6707, 6708, 6709, 6710, 6711, 6712, 6713, 6714, 6715, - 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724, 6725, 6726, 6727, - 6728, 6729, 6730, 6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, - 6740, 6741, 6742, 6743, 6744, 6745, 6746, 6747, 6550, 28971, 28969, - 28967, 28972, 28973, 28975, 28976, 28970, 28974, 28968, 11212, 11210, - 11209, 11206, 11205, 11208, 11207, 11213, 11211, 11204, 28966, 4484, - 4430, 4500, 4416, 4493, 4429, 4492, 4428, 4491, 4427, 4490, 4426, 4481, - 4400, 4394, 4423, 4480, 4398, 4392, 4422, 4499, 4528, 4522, 4415, 4498, - 4526, 4520, 4413, 4507, 4544, 4521, 4393, 4541, 4399, 4527, 4419, 4506, - 4543, 4519, 4391, 4540, 4397, 4525, 4418, 4479, 4434, 4512, 4402, 4396, - 4515, 4437, 4421, 4497, 4433, 4511, 4529, 4523, 4514, 4436, 4414, 4505, - 4435, 4513, 4542, 4518, 4395, 4539, 4439, 4517, 4432, 4510, 4401, 4524, - 4516, 4438, 4417, 4483, 4425, 4482, 4424, 4390, 4386, 4407, 4404, 4382, - 4406, 4403, 4381, 4534, 4531, 4385, 4533, 4530, 4384, 4546, 4537, 4389, - 4545, 4536, 4388, 4408, 4405, 4380, 4535, 4532, 4383, 4547, 4538, 4387, - 4441, 4440, 4442, 4443, 4472, 4466, 4476, 4488, 4495, 4509, 4478, 4409, - 4411, 4431, 4420, 4489, 4496, 4410, 4412, 37805, 25259, 25258, 25261, - 25169, 25251, 25264, 25260, 17531, 24111, 24134, 24147, 24075, 24135, - 24090, 24091, 31950, 24410, 26976, 10536, 37853, 31967, 31735, 31736, - 31727, 31728, 31729, 31730, 31731, 31732, 31733, 31734, 3905, 39270, - 39279, 39273, 34342, 34351, 34341, 34348, 34350, 34340, 3902, 39267, - 3898, 39255, 3935, 39302, 3879, 39251, 3930, 39299, 3929, 39298, 3887, - 39259, 3892, 39258, 3891, 39257, 3826, 39214, 3825, 39213, 3852, 39240, - 3851, 39239, 3850, 39238, 3816, 39203, 39204, 17460, 25266, 39189, 11195, - 6525, 4999, 3767, 6517, 6526, 6518, 6523, 6522, 6524, 24073, 31948, - 20804, 20808, 37809, 25163, 37833, 37869, 25213, 25193, 37814, 25170, - 3859, 3858, 3931, 3932, 39155, 34345, 34352, 34347, 34344, 39282, 39300, - 37791, 37792, 22734, 39280, 39276, 39277, 39281, 39196, 39194, 39195, - 39197, 37831, 37886, 25204, 39247, 3874, 39246, 3873, 25227, 3909, 8046, - 37740, 33870, 8458, 3918, 39289, 24420, 37024, 34575, 2525, 10578, 8476, - 30552, 3924, 39291, 2750, 2756, 2757, 32374, 37742, 20434, 39264, 3916, - 32818, 31887, 3857, 3884, 39237, 39296, 39261, 39212, 33767, 6123, 31751, - 3764, 5259, 981, 30652, 6480, 8684, 8683, 34491, 17428, 102, 19104, - 31286, 40667, 37551, 37552, 37557, 37554, 37556, 37555, 37553, 37550, - 39151, 39224, 39268, 3904, 39287, 17453, 22738, 27408, 17434, 11535, - 25571, 20931, 32444, 37959, 29280, 31581, 2523, 36647, 17723, 5997, - 24295, 38880, 25108, 32537, 32372, 6003, 2601, 31474, 39161, 39177, - 39180, 39156, 39164, 39174, 3787, 3803, 3806, 3782, 3790, 3800, 3917, - 39227, 39208, 3815, 39269, 3836, 3821, 39198, 20435, 31740, 16657, 3532, - 3533, 28302, 28301, 28303, 39149, 11540, 37756, 31781, 31782, 31783, - 31784, 31785, 31786, 31787, 31788, 3934, 31780, 31213, 31318, 39152, - 10841, 10842, 10843, 10844, 10845, 10846, 39191, 39193, 3768, 3770, - 28175, 28176, 10881, 10884, 10883, 10882, 39218, 3832, 19105, 979, 8692, - 34485, 32532, 345, 17475, 17719, 34486, 2536, 17473, 30859, 37001, 37000, - 39125, 20285, 11281, 11282, 20791, 25570, 25569, 25568, 38840, 20426, - 26985, 26962, 26975, 25737, 11003, 37758, 8675, 17637, 29090, 6133, - 31022, 20932, 38870, 6483, 3875, 32665, 32577, 31746, 32660, 33875, 3469, - 34418, 39215, 39216, 3829, 3830, 33871, 34577, 31756, 3911, 37023, 37670, - 37669, 39209, 8693, 10923, 30551, 31459, 6065, 19927, 6538, 6134, 29352, - 366, 3925, 39294, 3855, 39235, 11381, 19785, 24062, 34461, 17422, 3922, - 31860, 31861, 2532, 19711, 31293, 32026, 24185, 20814, 3780, 32823, 6515, - 6125, 20390, 17720, 17721, 25666, 28194, 37741, 17511, 17470, 17436, - 32528, 34163, 33765, 20469, 31305, 36766, 20829, 19687, 17639, 9941, - 39219, 3912, 37798, 3915, 25245, 39262, 39228, 36659, 36646, 226, 16779, - 31769, 31761, 38872, 39377, 25244, 31295, 37868, 39250, 3877, 6299, - 19709, 28294, 19745, 2760, 19701, 30861, 19792, 30535, 19747, 23224, - 32670, 30858, 25572, 34489, 17507, 17505, 19730, 17501, 3833, 39223, - 34084, 34518, 6811, 30533, 3781, 30860, 19749, 31471, 32669, 19700, - 30534, 16656, 16651, 16649, 33759, 16650, 19723, 37690, 33762, 36652, - 30532, 19775, 33757, 3831, 39220, 16652, 6800, 19774, 33873, 37295, - 19708, 34083, 19768, 2749, 16655, 19725, 8689, 32668, 29038, 25243, - 37865, 25225, 37883, 3942, 39254, 39217, 3818, 19727, 24417, 26982, - 19791, 19758, 19759, 19719, 19720, 19742, 19741, 9953, 19728, 19734, - 19704, 32221, 17474, 32220, 26969, 26972, 26963, 26964, 26970, 26973, - 19738, 19751, 19737, 19750, 24409, 24407, 26968, 26971, 10906, 10904, - 10903, 10900, 10899, 10902, 10901, 10907, 10905, 10898, 10917, 10914, - 10913, 10910, 10909, 10912, 10911, 10918, 10916, 10908, 10896, 10893, - 10892, 10889, 10888, 10891, 10890, 10897, 10895, 10887, 19787, 19790, - 19746, 19716, 19764, 19752, 19771, 11373, 19755, 37545, 19777, 10539, - 19715, 3893, 37015, 37018, 3894, 19702, 19703, 34479, 19714, 32042, - 24175, 2613, 17522, 19743, 19782, 29432, 9947, 29434, 6588, 39306, 3948, - 3950, 3949, 19705, 19707, 19706, 36653, 19776, 39145, 19788, 30546, - 11214, 36998, 39293, 31299, 30542, 30541, 24109, 31974, 30654, 31871, - 34732, 38821, 26434, 25134, 26255, 34446, 34447, 39207, 980, 16711, - 25241, 37826, 24093, 31965, 17530, 22726, 22725, 24040, 24039, 24089, - 25149, 25138, 37777, 25267, 39199, 39200, 39201, 39275, 39278, 26435, - 26429, 26438, 26432, 26437, 26431, 26436, 26430, 26439, 26433, 37927, - 11363, 976, 8025, 31928, 25139, 25144, 25137, 25141, 25146, 25136, 25140, - 25145, 25142, 25147, 25148, 4925, 4670, 4798, 4671, 4862, 4735, 4799, - 4672, 4894, 4767, 4831, 4704, 4863, 4736, 4800, 4673, 4910, 4783, 4847, - 4720, 4879, 4752, 4816, 4689, 4895, 4768, 4832, 4705, 4864, 4737, 4801, - 4674, 4918, 4791, 4855, 4728, 4887, 4760, 4824, 4697, 4903, 4776, 4840, - 4713, 4872, 4745, 4809, 4682, 4911, 4784, 4848, 4721, 4880, 4753, 4817, - 4690, 4896, 4769, 4833, 4706, 4865, 4738, 4802, 4675, 4922, 4795, 4859, - 4732, 4891, 4764, 4828, 4701, 4907, 4780, 4844, 4717, 4876, 4749, 4813, - 4686, 4915, 4788, 4852, 4725, 4884, 4757, 4821, 4694, 4900, 4773, 4837, - 4710, 4869, 4742, 4806, 4679, 4919, 4792, 4856, 4729, 4888, 4761, 4825, - 4698, 4904, 4777, 4841, 4714, 4873, 4746, 4810, 4683, 4912, 4785, 4849, - 4722, 4881, 4754, 4818, 4691, 4897, 4770, 4834, 4707, 4866, 4739, 4803, - 4676, 4924, 4797, 4861, 4734, 4893, 4766, 4830, 4703, 4909, 4782, 4846, - 4719, 4878, 4751, 4815, 4688, 4917, 4790, 4854, 4727, 4886, 4759, 4823, - 4696, 4902, 4775, 4839, 4712, 4871, 4744, 4808, 4681, 4921, 4794, 4858, - 4731, 4890, 4763, 4827, 4700, 4906, 4779, 4843, 4716, 4875, 4748, 4812, - 4685, 4914, 4787, 4851, 4724, 4883, 4756, 4820, 4693, 4899, 4772, 4836, - 4709, 4868, 4741, 4805, 4678, 4923, 4796, 4860, 4733, 4892, 4765, 4829, - 4702, 4908, 4781, 4845, 4718, 4877, 4750, 4814, 4687, 4916, 4789, 4853, - 4726, 4885, 4758, 4822, 4695, 4901, 4774, 4838, 4711, 4870, 4743, 4807, - 4680, 4920, 4793, 4857, 4730, 4889, 4762, 4826, 4699, 4905, 4778, 4842, - 4715, 4874, 4747, 4811, 4684, 4913, 4786, 4850, 4723, 4882, 4755, 4819, - 4692, 4898, 4771, 4835, 4708, 4867, 4740, 4804, 4677, 32146, 32145, - 24276, 32091, 24100, 32147, 24278, 32093, 11319, 37908, 37945, 11343, - 24280, 32095, 24260, 32139, 32148, 32065, 37910, 11323, 32078, 32077, - 32141, 32143, 32142, 24225, 32085, 24279, 32094, 24202, 32062, 24222, - 32057, 29391, 29371, 29397, 29369, 33968, 33981, 29396, 29368, 33965, - 33980, 32165, 17420, 33966, 29366, 17421, 32166, 29367, 29395, 39134, - 2516, 2515, 2518, 2519, 32043, 24174, 37453, 4360, 37455, 37454, 25223, - 25187, 973, 8022, 32052, 24191, 32831, 32070, 24207, 32061, 24098, 37948, - 24052, 24051, 37765, 37764, 24053, 37766, 24050, 37763, 24239, 32109, - 37922, 11358, 24233, 32103, 37919, 11355, 24238, 32108, 37921, 11357, - 24232, 32102, 37918, 11354, 24235, 37917, 32107, 11352, 24237, 24231, - 32105, 32100, 24236, 24230, 32106, 32101, 37916, 11353, 31940, 16796, - 37299, 24195, 32054, 32053, 24376, 24198, 18125, 34548, 24197, 34718, - 24148, 31945, 37774, 11287, 37565, 40680, 40681, 24140, 32011, 24142, - 32013, 40675, 40671, 40676, 40672, 24121, 31989, 24119, 31986, 24118, - 31987, 24046, 31921, 24047, 31927, 11227, 11252, 24055, 31931, 11202, - 38854, 26857, 31926, 26858, 958, 5, 34100, 34101, 37667, 31877, 959, - 31878, 29930, 29929, 26856, 26855, 26850, 26849, 26854, 26852, 26853, - 26851, 31900, 16758, 16757, 16755, 16756, 6527, 6815, 6802, 6806, 6803, - 6528, 6520, 6529, 37762, 6810, 6533, 6748, 6816, 6519, 6521, 34410, - 34405, 34476, 34462, 34463, 37700, 37544, 37542, 32369, 37541, 32003, - 24126, 38818, 4373, 4374, 3941, 37306, 37307, 39232, 3840, 24145, 32016, - 24063, 31941, 20628, 37233, 20705, 11280, 34353, 20630, 32851, 16797, - 16798, 20471, 18009, 36990, 11300, 11301, 3819, 3860, 39192, 3769, 16810, - 16813, 16809, 16812, 16808, 16811, 32238, 31872, 33927, 31873, 3757, - 3756, 11234, 37561, 24162, 32029, 37308, 27598, 28792, 28790, 28791, - 28800, 28799, 28795, 28796, 37702, 37701, 28794, 28000, 34573, 31737, - 17446, 20786, 20778, 6820, 978, 24492, 24493, 24494, 20779, 31739, 20783, - 20780, 20784, 20782, 20785, 20781, 20929, 22727, 40677, 40678, 40679, - 31573, 31578, 31576, 31572, 31575, 31574, 31577, 27591, 27592, 27594, - 27593, 31569, 31570, 38869, 28293, 28292, 32576, 33848, 28288, 28289, - 6749, 28290, 6543, 31571, 27595, 28291, 20801, 32048, 40673, 372, 20797, - 37751, 37752, 20796, 20795, 37753, 37749, 20794, 37748, 20793, 37750, - 20798, 8038, 8044, 11235, 11236, 8039, 25122, 25130, 11225, 11226, 37698, - 37699, 33787, 33786, 25127, 25124, 25132, 25123, 25131, 25121, 25125, - 25120, 33838, 25129, 25128, 40674, 40670, 16802, 20472, 37559, 37560, - 37301, 37300, 33631, 8477, 16803, 363, 1056, 16793, 31579, 16794, 11215, - 37693, 37009, 16801, 16805, 24393, 18144, 24394, 18145, 24385, 18131, - 24388, 18134, 24386, 18132, 24387, 18133, 24384, 18135, 24378, 18127, - 24377, 18126, 24375, 18123, 24373, 18121, 24372, 18120, 24371, 18124, - 24374, 18122, 33772, 33770, 33773, 33771, 11262, 11261, 11258, 11257, - 33630, 33629, 33628, 33627, 11228, 11230, 11229, 18139, 18128, 24382, - 18142, 24383, 18143, 33846, 22735, 33847, 22736, 16799, 31659, 34564, - 31660, 34565, 31662, 34567, 31658, 34563, 31661, 34566, 31657, 34562, - 11231, 11240, 34559, 34731, 34557, 34729, 34558, 34730, 34556, 34728, - 34551, 34723, 34552, 34724, 34550, 34722, 34553, 34725, 34231, 34318, - 8033, 8035, 8034, 8036, 34546, 34717, 34547, 34716, 34720, 34719, 16710, - 31477, 37539, 17496, 29363, 32835, 32836, 32832, 31300, 38820, 11249, - 38819, 11247, 25133, 32837, 32834, 32833, 11216, 11244, 11238, 31881, - 11018, 38836, 38835, 11286, 31066, 31065, 37564, 37567, 37558, 37571, - 37570, 11260, 11259, 37568, 22724, 11243, 39304, 28801, 29380, 29407, - 33978, 33991, 24103, 24229, 37912, 11325, 29377, 29404, 33975, 33988, - 24105, 37769, 32074, 32075, 24211, 24212, 34346, 34339, 34349, 34343, - 10833, 10834, 10832, 10831, 11198, 3846, 39233, 3939, 39305, 3880, 39252, - 39230, 3837, 20401, 3841, 3863, 39244, 3866, 39248, 3899, 3900, 39265, - 3839, 39231, 3936, 39301, 24049, 37002, 24048, 25143, 24268, 24267, - 24269, 24270, 24205, 24215, 24214, 24263, 24265, 24264, 24199, 39133, - 16795, 31874, 24192, 32060, 32059, 24294, 32155, 31875, 32050, 37298, - 24194, 24193, 32051, 11339, 32830, 32828, 39245, 3901, 39266, 3890, - 39256, 19735, 19748, 19712, 19710, 19713, 33774, 2611, 33775, 2610, 3648, - 32829, 24245, 37931, 32124, 11328, 24107, 37773, 29402, 29375, 33973, - 33986, 24257, 37942, 32136, 11340, 8030, 971, 24256, 37933, 32135, 11330, - 40951, 40951, 29403, 29376, 33974, 33987, 24247, 37941, 32126, 11338, - 20422, 38849, 24246, 37932, 32125, 11329, 24258, 37943, 32137, 11341, - 24228, 37911, 32088, 11327, 968, 969, 967, 970, 31865, 31866, 29275, - 29276, 17502, 32089, 40951, 34830, 37013, 37017, 37014, 37016, 3853, - 3933, 3895, 3827, 11332, 11333, 37935, 37936, 24250, 32129, 24249, 32128, - 3772, 3773, 3774, 3775, 3776, 3778, 3777, 3779, 31912, 31913, 31910, - 31911, 31907, 31909, 31906, 31908, 37956, 37761, 30876, 30875, 30877, - 2755, 6818, 6532, 3906, 3817, 37668, 20400, 3940, 3870, 3862, 3865, 3868, - 29281, 37471, 4348, 24405, 32222, 39222, 32223, 34303, 37744, 18671, - 31585, 31584, 31583, 31582, 37538, 31686, 2531, 20463, 31458, 29058, - 39249, 3820, 37580, 9943, 19685, 40759, 22562, 1053, 97, 38957, 31596, - 24074, 31949, 34492, 34493, 24266, 37947, 32144, 11345, 16815, 16814, - 32666, 32364, 32362, 32363, 32361, 32365, 32366, 16800, 37755, 32657, - 11283, 31219, 31888, 19929, 17909, 17911, 17945, 17919, 17915, 17946, - 17953, 17916, 17952, 17925, 17921, 17920, 17914, 17956, 17927, 17928, - 17929, 17930, 17932, 17934, 17938, 17942, 17955, 17917, 17954, 17931, - 17933, 17935, 17944, 17913, 17937, 17948, 17947, 17949, 17939, 17951, - 17940, 17941, 17950, 17923, 17910, 17922, 17918, 17924, 17936, 17943, - 17926, 17912, 17957, 17959, 17993, 17967, 17963, 17994, 18001, 17964, - 18000, 17973, 17969, 17968, 17962, 18004, 17975, 17976, 17977, 17978, - 17980, 17982, 17986, 17990, 18003, 17965, 18002, 17979, 17981, 17983, - 17992, 17961, 17985, 17996, 17995, 17997, 17987, 17999, 17988, 17989, - 17998, 17971, 17958, 17970, 17966, 17972, 17984, 17991, 17974, 17960, - 22957, 23603, 22960, 23051, 23067, 23337, 23828, 22900, 23522, 22946, - 23582, 23214, 23995, 22780, 22979, 23118, 23119, 23948, 23191, 23965, - 23947, 22905, 23529, 23893, 23450, 23869, 23684, 23261, 24020, 27718, - 23094, 23218, 8485, 8579, 8535, 8629, 8499, 8593, 8496, 8590, 8540, 8634, - 8530, 8624, 8534, 8628, 8501, 8595, 8532, 8626, 8538, 8632, 8504, 8598, - 8509, 8603, 8541, 8635, 8542, 8636, 8505, 8599, 8510, 8604, 8537, 8631, - 8539, 8633, 8531, 8625, 8533, 8627, 8543, 8637, 8507, 8601, 8503, 8597, - 8536, 8630, 8526, 8620, 8493, 8587, 8521, 8615, 8489, 8583, 8494, 8588, - 8495, 8589, 8490, 8584, 8519, 8613, 8529, 8623, 8491, 8585, 8517, 8611, - 8520, 8614, 8484, 8578, 8492, 8586, 8512, 8606, 8513, 8607, 8508, 8602, - 8515, 8609, 8514, 8608, 8511, 8605, 8518, 8612, 8516, 8610, 8524, 8618, - 8522, 8616, 8523, 8617, 8525, 8619, 8639, 8640, 8641, 8643, 8644, 8638, - 8642, 8487, 8581, 8488, 8582, 8483, 8482, 8481, 8486, 8580, 40951, 40951, - 40951, 40951, 40951, 8577, 8574, 8575, 8576, 8572, 8573, 8645, 17768, - 17794, 17779, 17800, 17801, 17799, 17789, 17790, 17802, 17783, 17792, - 17795, 17797, 17803, 17785, 17788, 17793, 17787, 17791, 17804, 17784, - 17782, 17778, 17798, 17786, 17774, 17777, 17781, 17776, 17775, 17796, - 17780, 17769, 17773, 17771, 17806, 17770, 17772, 40951, 17805, 40951, - 40951, 40951, 40951, 40951, 17767, 40951, 40951, 37248, 37259, 37260, - 37253, 37255, 37238, 37277, 37249, 37252, 37250, 37251, 37287, 37276, - 37256, 37242, 37258, 37261, 37237, 37246, 37262, 37275, 37257, 37243, - 37282, 37247, 37288, 37270, 37236, 37244, 37278, 37279, 37280, 37241, - 37245, 37281, 37290, 37272, 37273, 37254, 37240, 37235, 37263, 37265, - 37264, 37266, 37267, 37274, 37268, 37283, 37284, 37285, 37269, 37239, - 37271, 37286, 37289, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 37291, 37292, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 37234, 17250, 17067, 17154, - 17194, 17170, 16857, 17232, 16895, 17085, 17076, 16977, 17310, 16925, - 16910, 17241, 17201, 16886, 17101, 17114, 16962, 16966, 16965, 16964, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 17184, - 17190, 17188, 17185, 17187, 17186, 17189, 40951, 16876, 16882, 16880, - 16877, 16879, 16878, 16881, 40951, 17300, 17306, 17304, 17301, 17303, - 17302, 17305, 40951, 16869, 16875, 16873, 16870, 16872, 16871, 16874, - 40951, 17136, 17142, 17140, 17137, 17139, 17138, 17141, 40951, 17045, - 17051, 17049, 17046, 17048, 17047, 17050, 40951, 17277, 17283, 17281, - 17278, 17280, 17279, 17282, 40951, 16988, 16994, 16992, 16989, 16991, - 16990, 16993, 40951, 8091, 8129, 8126, 8093, 8123, 8124, 8130, 8097, - 8098, 8099, 8106, 8128, 8100, 8094, 8122, 8119, 8121, 8125, 8109, 8108, - 8127, 8095, 8131, 8105, 8092, 8118, 8114, 8116, 8103, 8117, 8090, 8102, - 31923, 31922, 24125, 31993, 24067, 31938, 31760, 31759, 11201, 24128, - 32001, 31768, 24108, 31973, 11542, 31064, 17495, 31883, 20461, 11200, - 11324, 37895, 11203, 11251, 20810, 31023, 20457, 37304, 24088, 31963, - 37303, 37302, 24157, 32007, 37480, 37484, 4353, 4356, 24113, 31978, - 24066, 31943, 37696, 30525, 34406, 17464, 31898, 38852, 32158, 39365, - 37672, 31758, 31770, 37683, 10530, 10531, 37673, 37469, 37708, 37020, - 34506, 38855, 39348, 6002, 11219, 31897, 11222, 10537, 11239, 20811, - 20812, 25159, 25160, 11237, 11197, 37569, 26959, 31063, 31717, 8648, - 8685, 8686, 37392, 26958, 26960, 24123, 31991, 24122, 31990, 37461, - 37465, 4339, 4343, 29931, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 7916, 7869, 7919, - 7918, 7917, 7912, 7840, 7937, 7951, 7950, 7873, 7920, 7933, 7932, 7902, - 7901, 7900, 7899, 7929, 7938, 7928, 7927, 7888, 7887, 7891, 7915, 40951, - 7872, 7935, 7909, 7874, 7907, 7867, 7943, 7942, 7881, 7911, 7910, 7921, - 7871, 7875, 7896, 7838, 7880, 7931, 7930, 7843, 7926, 7854, 7949, 7948, - 7947, 7946, 7904, 7934, 7914, 7879, 7952, 7842, 7841, 7903, 7908, 7885, - 7884, 7883, 7939, 7870, 7945, 7944, 7858, 7922, 7890, 7857, 7856, 7882, - 7866, 7923, 7941, 7940, 7868, 7850, 7898, 7897, 7853, 7851, 7906, 7905, - 7913, 7844, 7860, 7852, 7862, 7848, 7878, 7877, 7876, 7846, 7889, 7865, - 7839, 7886, 7847, 7864, 7855, 7924, 7925, 7849, 7895, 7845, 7893, 7861, - 7894, 7863, 7936, 7892, 7859, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 21128, 21110, 21044, 21164, - 21152, 21096, 21196, 21111, 21124, 21107, 21059, 21063, 21048, 21033, - 21099, 21185, 21131, 21102, 21136, 21213, 21170, 21141, 21093, 21198, - 21042, 21153, 21029, 21133, 21004, 21122, 21058, 21056, 21151, 21079, - 21081, 21061, 21011, 21210, 21036, 21144, 21098, 21180, 21103, 21031, - 21169, 21120, 21142, 21211, 21129, 21194, 21054, 21159, 21045, 21113, - 21197, 21160, 21019, 21178, 21020, 21172, 21090, 21087, 21050, 21088, - 21021, 21139, 21150, 21043, 21006, 21181, 21126, 21183, 21149, 21123, - 21193, 21104, 21173, 21038, 21204, 21049, 21032, 21078, 21027, 21171, - 21203, 21070, 21028, 21065, 21047, 21086, 21165, 21067, 21035, 21051, - 21134, 21100, 21114, 21188, 21177, 21109, 21215, 21068, 21015, 21161, - 21046, 21206, 21182, 21041, 21064, 21166, 21002, 21175, 21168, 21192, - 21082, 21026, 21176, 21007, 21143, 21162, 21101, 21127, 21157, 21076, - 21132, 21005, 21135, 21055, 21022, 21115, 21116, 21154, 21003, 21118, - 21189, 21130, 21016, 21174, 21034, 21083, 21187, 21097, 21012, 21202, - 21030, 21205, 21155, 21095, 21167, 21199, 21023, 21137, 21008, 21156, - 21146, 21145, 21077, 21018, 21025, 21009, 21119, 21201, 21037, 21209, - 21040, 21200, 21080, 21112, 21085, 21121, 21163, 21158, 21138, 21014, - 21212, 21066, 21105, 21184, 21108, 21179, 21106, 21208, 21073, 21057, - 21091, 21074, 21094, 21017, 21186, 21089, 21069, 21147, 21024, 21084, - 21071, 21010, 21148, 21039, 21207, 21092, 21214, 21117, 21013, 21062, - 21075, 21191, 21053, 21140, 21125, 21060, 21190, 21052, 21195, 21072, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 20495, 20493, 20494, 20492, - 20507, 20503, 20502, 20499, 20500, 20501, 20497, 20496, 20504, 20498, - 20508, 20506, 20592, 20491, 20590, 11007, 20828, 20591, 20490, 20510, - 24045, 31920, 24064, 31939, 24060, 31936, 24139, 32010, 24054, 31930, - 31598, 17902, 24136, 32005, 24141, 32012, 24144, 32015, 24143, 32014, - 39132, 31880, 11233, 25157, 31599, 19581, 19574, 19571, 19577, 19576, - 19579, 19578, 19582, 19580, 20588, 20587, 20509, 20586, 19240, 19239, - 39138, 38827, 38830, 38828, 38831, 38829, 6801, 20584, 19575, 19573, - 19572, 38826, 25816, 31216, 20589, 20585, 40951, 20305, 20291, 20307, - 20385, 20309, 20387, 20306, 20384, 20308, 20386, 20346, 20336, 20348, - 20338, 20350, 20340, 20347, 20337, 20349, 20339, 20310, 20371, 20312, - 20373, 20314, 20375, 20311, 20372, 20313, 20374, 20366, 20331, 20368, - 20333, 20304, 20370, 20335, 20367, 20332, 20369, 20334, 20326, 20328, - 20330, 20327, 20329, 20341, 20321, 20356, 20343, 20315, 20358, 20345, - 20324, 20360, 20342, 20322, 20357, 20344, 20323, 20359, 20351, 20353, - 20355, 20352, 20354, 20298, 20380, 20300, 20382, 20299, 20381, 20361, - 20363, 20365, 20362, 20364, 20294, 20376, 20378, 20377, 20379, 20325, - 20383, 20301, 20302, 40951, 40951, 8288, 8287, 21453, 21452, 20389, - 20388, 20290, 21450, 21380, 21309, 21382, 21443, 21384, 21445, 21381, - 21442, 21383, 21444, 21405, 21395, 21407, 21397, 21409, 21399, 21406, - 21396, 21408, 21398, 21385, 21430, 21387, 21432, 21389, 21434, 21386, - 21431, 21388, 21433, 21420, 21390, 21422, 21392, 21367, 21424, 21394, - 21421, 21391, 21423, 21393, 21347, 21349, 21351, 21348, 21350, 21400, - 21324, 21410, 21402, 21318, 21412, 21404, 21327, 21414, 21401, 21325, - 21411, 21403, 21326, 21413, 21342, 21328, 21345, 21343, 21344, 21372, - 21439, 21374, 21441, 21373, 21440, 21415, 21417, 21419, 21416, 21418, - 21368, 21435, 21437, 21436, 21438, 21346, 21429, 21362, 21363, 21425, - 21427, 21426, 21428, 21449, 21451, 21448, 21446, 21447, 40951, 40951, - 40951, 40951, 40951, 4320, 4328, 4327, 4325, 4324, 4331, 4296, 4316, - 4284, 4312, 4326, 4322, 4329, 4333, 4309, 4315, 4319, 4330, 4308, 4314, - 4318, 4264, 4300, 4276, 4281, 4265, 4282, 4267, 4307, 4269, 4277, 4270, - 4278, 4283, 4289, 4274, 4295, 4332, 4297, 4286, 4292, 4303, 4299, 40951, - 19493, 19537, 19494, 19499, 19500, 19502, 19529, 19540, 19515, 19516, - 19518, 19520, 19527, 19523, 19519, 19526, 19495, 19505, 19539, 19506, - 19530, 19542, 19487, 19482, 19536, 19481, 19492, 19528, 19513, 19566, - 19477, 19480, 19563, 19564, 19484, 19483, 19550, 19549, 19567, 19546, - 19547, 19568, 19555, 19569, 19545, 19544, 19548, 19559, 19485, 19565, - 19486, 19570, 19538, 19501, 19504, 19503, 19517, 19524, 19521, 19522, - 19525, 19496, 19498, 19497, 19491, 19512, 19510, 19507, 19508, 19511, - 19509, 19489, 19490, 19532, 19533, 19535, 19534, 19531, 19514, 19543, - 19552, 19554, 19553, 19488, 19541, 19551, 19556, 19557, 19558, 19561, - 19560, 19562, 19478, 19479, 40951, 20484, 20487, 20486, 20482, 20480, - 20476, 20483, 20478, 20474, 20477, 20485, 20481, 20475, 20488, 20489, - 20479, 4321, 4310, 4323, 4287, 4280, 4279, 4306, 4302, 4294, 4271, 4290, - 4275, 4293, 4298, 4266, 4268, 4273, 4305, 4301, 4291, 4262, 4263, 4261, - 4260, 4285, 4317, 4311, 4259, 4288, 4313, 4304, 4272, 7983, 7986, 7987, - 7985, 7973, 7959, 7965, 7954, 7964, 7977, 7966, 7962, 7955, 7963, 7960, - 7989, 7953, 7972, 7968, 7981, 7988, 7958, 7967, 7976, 7975, 7982, 7980, - 7969, 7971, 7984, 7979, 7974, 7956, 7961, 7970, 7990, 7957, 7978, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 20505, 21365, - 21377, 21378, 21366, 21376, 21352, 21354, 21356, 21353, 21355, 21379, - 21357, 21359, 21361, 21358, 21360, 31078, 31082, 31094, 31088, 31080, - 31086, 31090, 31096, 31071, 31069, 31076, 31092, 31084, 31074, 31079, - 31083, 31095, 31089, 31081, 31087, 31091, 31097, 31072, 31070, 31077, - 31093, 31085, 31075, 31073, 31135, 31134, 40951, 31133, 31129, 31127, - 31108, 31106, 31126, 31118, 31103, 31112, 31128, 31111, 31105, 31131, - 31130, 31110, 31102, 31125, 31123, 31132, 31120, 31113, 31121, 31104, - 31099, 31109, 31116, 31100, 31122, 31124, 31101, 31114, 31098, 31107, - 31115, 31119, 31117, 6620, 6608, 6630, 6609, 6774, 6788, 6776, 6758, - 6755, 6771, 6769, 6751, 31215, 6789, 6795, 6794, 6791, 6790, 6793, 6792, - 6797, 6796, 6775, 6777, 6783, 6782, 6779, 6778, 6568, 6572, 6584, 6578, - 6570, 6576, 6580, 6561, 6559, 6557, 6566, 6582, 6574, 6564, 6569, 6573, - 6585, 6579, 6571, 6577, 6581, 6562, 6560, 6558, 6567, 6583, 6575, 6565, - 6695, 6694, 6563, 22560, 6643, 6639, 6637, 6605, 6603, 6635, 6626, 6600, - 6618, 6638, 6616, 6602, 6641, 6640, 6614, 6598, 6629, 6634, 6607, 6631, - 6619, 6632, 6601, 6594, 6610, 6625, 6615, 6604, 6628, 6599, 6636, 6591, - 6642, 6622, 6595, 6593, 6606, 6596, 6611, 6612, 6624, 6613, 6623, 6633, - 6627, 6597, 6621, 6589, 6617, 6781, 6780, 6785, 6784, 6757, 6759, 6765, - 6764, 6761, 6760, 6763, 6762, 6767, 6766, 6754, 20575, 20578, 20579, - 20517, 20580, 20576, 20577, 20516, 20582, 20583, 20581, 20549, 34191, - 34157, 34159, 24491, 6689, 6691, 6693, 6690, 6692, 6652, 6654, 6656, - 6653, 6655, 6672, 6674, 6676, 6673, 6675, 6677, 6679, 6681, 6678, 6680, - 6662, 6664, 6666, 6663, 6665, 6647, 6649, 6651, 6648, 6650, 6657, 6659, - 6661, 6658, 6660, 6686, 6688, 6687, 6667, 6669, 6671, 6668, 6670, 6682, - 6684, 6683, 6685, 34155, 34116, 34118, 34117, 34119, 34194, 34195, 34358, - 34158, 34151, 34284, 34288, 34203, 34202, 34201, 34166, 34167, 34171, - 34170, 34204, 34169, 34205, 34208, 34206, 34207, 34172, 34173, 34215, - 34216, 34217, 34214, 34213, 34324, 34325, 34332, 34326, 34327, 34142, - 34146, 34147, 34337, 34277, 34278, 34179, 34291, 34292, 34123, 34300, - 34298, 34299, 34126, 34186, 34185, 34125, 34187, 34180, 34297, 34295, - 34181, 34296, 34294, 34128, 34301, 34127, 34184, 34302, 34182, 34183, - 34241, 34242, 34245, 34244, 34243, 34251, 34252, 34253, 34248, 34249, - 34250, 34356, 34355, 34357, 34319, 34320, 34322, 34321, 34317, 34316, - 34338, 20573, 20574, 20556, 20558, 20565, 20564, 20571, 20569, 20560, - 20567, 20559, 20562, 20555, 20557, 20566, 20563, 20572, 20570, 20561, - 20568, 20550, 20554, 20553, 20552, 20551, 34189, 34141, 34121, 34124, - 34289, 34305, 34143, 34145, 34144, 34199, 34152, 34156, 34153, 34154, - 34133, 34293, 34276, 34258, 34240, 34200, 34222, 34246, 34176, 34130, - 34219, 34306, 34279, 34259, 34260, 34273, 34223, 34192, 34218, 34270, - 34174, 34336, 34261, 34274, 34150, 34225, 34165, 34280, 34262, 34255, - 34134, 34209, 34257, 34136, 34239, 34212, 34256, 34135, 34238, 34211, - 34235, 34236, 34290, 34221, 34272, 34175, 34313, 34314, 34315, 34310, - 34281, 34263, 34275, 34311, 34282, 34264, 34266, 34227, 34267, 34312, - 34283, 34265, 34268, 34228, 34269, 34220, 34237, 34120, 34129, 34139, - 34140, 34137, 34132, 34148, 34177, 34178, 34188, 34193, 34224, 34210, - 34226, 34232, 34233, 34230, 34234, 34247, 34254, 34271, 34307, 34308, - 34304, 34309, 34333, 34334, 34354, 34122, 34114, 20548, 20533, 20521, - 20540, 20539, 20546, 20544, 20535, 20542, 20534, 20537, 20532, 20520, - 20541, 20538, 20547, 20545, 20536, 20543, 20522, 20530, 20528, 20527, - 20524, 20523, 20526, 20525, 20531, 20529, 20518, 20519, 34168, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 20267, 20270, 20231, - 20281, 20278, 20226, 20264, 20243, 20260, 20277, 20255, 20261, 20236, - 20238, 20248, 20282, 20235, 20279, 20219, 20225, 20223, 20242, 20262, - 20256, 20244, 20241, 20249, 20240, 20265, 20268, 20247, 20233, 20257, - 20239, 20254, 20234, 20269, 20252, 20250, 20229, 20228, 20246, 20224, - 20227, 20237, 20253, 20251, 20271, 20258, 20266, 20263, 20275, 20230, - 20273, 20221, 20272, 20274, 20276, 20232, 20280, 20245, 20259, 20220, - 20222, 39884, 39891, 39883, 39890, 39888, 39889, 39886, 39887, 40659, - 40660, 40657, 40658, 40656, 40654, 40655, 40663, 40664, 40661, 40662, - 40666, 40665, 40531, 39551, 39552, 39545, 39550, 39548, 39549, 39546, - 39547, 39555, 39556, 39553, 39554, 39536, 39534, 39535, 39559, 39560, - 39557, 39558, 39544, 39542, 39543, 39540, 39541, 39533, 39539, 39538, - 39537, 39565, 39566, 39561, 39564, 39563, 39562, 40263, 40264, 40258, - 40262, 40261, 40259, 40260, 40267, 40268, 40265, 40266, 40252, 40250, - 40251, 40271, 40272, 40269, 40270, 40256, 40257, 40249, 40255, 40254, - 40253, 40277, 40278, 40273, 40276, 40275, 40274, 39519, 39520, 39513, - 39518, 39516, 39517, 39514, 39515, 39523, 39524, 39521, 39522, 39504, - 39502, 39503, 39527, 39528, 39525, 39526, 39512, 39510, 39511, 39508, - 39509, 39501, 39507, 39506, 39505, 39531, 39532, 39529, 39530, 40066, - 40067, 40061, 40065, 40064, 40062, 40063, 40070, 40071, 40068, 40069, - 40074, 40075, 40072, 40073, 40080, 40081, 40076, 40079, 40078, 40077, - 40086, 40087, 40082, 40085, 40084, 40083, 39809, 39810, 39804, 39808, - 39807, 39805, 39806, 39813, 39814, 39811, 39812, 39798, 39796, 39797, - 39817, 39818, 39815, 39816, 39802, 39803, 39795, 39801, 39800, 39799, - 39823, 39819, 39822, 39821, 39820, 40045, 40046, 40040, 40044, 40043, - 40041, 40042, 40049, 40050, 40047, 40048, 40033, 40034, 40031, 40032, - 40053, 40054, 40051, 40052, 40060, 40059, 40038, 40039, 40030, 40037, - 40036, 40035, 40057, 40058, 40055, 40056, 39690, 39691, 39688, 39689, - 39686, 39687, 39684, 39685, 39683, 39681, 39682, 39700, 39701, 39696, - 39699, 39698, 39697, 39694, 39695, 39692, 39693, 40509, 40510, 40503, - 40508, 40506, 40507, 40504, 40505, 40513, 40514, 40511, 40512, 40517, - 40518, 40515, 40516, 40502, 40501, 40523, 40524, 40519, 40522, 40521, - 40520, 40529, 40530, 40525, 40528, 40527, 40526, 39668, 39669, 39663, - 39667, 39666, 39664, 39665, 39675, 39676, 39673, 39674, 39657, 39656, - 39679, 39680, 39677, 39678, 39672, 39670, 39671, 39661, 39662, 39655, - 39660, 39659, 39658, 40488, 40489, 40483, 40487, 40486, 40484, 40485, - 40495, 40496, 40493, 40494, 40476, 40477, 40474, 40475, 40499, 40500, - 40497, 40498, 40492, 40490, 40491, 40481, 40482, 40473, 40480, 40479, - 40478, 39642, 39643, 39637, 39641, 39640, 39638, 39639, 39649, 39650, - 39647, 39648, 39631, 39629, 39630, 39653, 39654, 39651, 39652, 39646, - 39644, 39645, 39635, 39636, 39628, 39634, 39633, 39632, 40092, 40093, - 40088, 40091, 40090, 40089, 40099, 40100, 40097, 40098, 40103, 40104, - 40101, 40102, 40096, 40094, 40095, 40109, 40110, 40105, 40108, 40107, - 40106, 39839, 39840, 39833, 39838, 39836, 39837, 39834, 39835, 39843, - 39844, 39841, 39842, 39828, 39827, 39825, 39826, 39824, 39832, 39830, - 39831, 39829, 40237, 40238, 40232, 40236, 40235, 40233, 40234, 40241, - 40239, 40240, 40226, 40224, 40225, 40247, 40248, 40245, 40246, 40244, - 40242, 40243, 40230, 40231, 40223, 40229, 40228, 40227, 39777, 39778, - 39772, 39776, 39775, 39773, 39774, 39787, 39788, 39785, 39786, 39766, - 39764, 39765, 39784, 39782, 39783, 39781, 39779, 39780, 39770, 39771, - 39763, 39769, 39768, 39767, 39793, 39794, 39789, 39792, 39791, 39790, - 39992, 39993, 39986, 39991, 39989, 39990, 39987, 39988, 39996, 39997, - 39994, 39995, 39976, 39977, 39974, 39975, 40000, 40001, 39998, 39999, - 39985, 39983, 39984, 39981, 39982, 39973, 39980, 39979, 39978, 40006, - 40007, 40002, 40005, 40004, 40003, 39746, 39747, 39740, 39745, 39743, - 39744, 39741, 39742, 39750, 39751, 39748, 39749, 39733, 39734, 39731, - 39732, 39758, 39759, 39756, 39757, 39754, 39755, 39752, 39753, 39738, - 39739, 39730, 39737, 39736, 39735, 39959, 39960, 39954, 39958, 39957, - 39955, 39956, 39963, 39964, 39961, 39962, 39948, 39946, 39947, 39971, - 39972, 39969, 39970, 39967, 39968, 39965, 39966, 39952, 39953, 39945, - 39951, 39950, 39949, 39706, 39707, 39702, 39705, 39703, 39704, 39720, - 39721, 39718, 39719, 39711, 39712, 39709, 39710, 39728, 39729, 39726, - 39727, 39724, 39725, 39722, 39723, 39716, 39717, 39708, 39715, 39714, - 39713, 40029, 40028, 40022, 40023, 40020, 40021, 40011, 40009, 40010, - 40026, 40027, 40024, 40025, 40019, 40017, 40018, 40015, 40016, 40008, - 40014, 40013, 40012, 39858, 39859, 39852, 39857, 39855, 39856, 39853, - 39854, 39862, 39863, 39860, 39861, 39847, 39848, 39845, 39846, 39866, - 39867, 39864, 39865, 39851, 39849, 39850, 40119, 40117, 40118, 40122, - 40123, 40120, 40121, 40112, 40113, 40111, 40126, 40127, 40124, 40125, - 40116, 40114, 40115, 39762, 39761, 39760, 39877, 39878, 39875, 39876, - 39870, 39871, 39868, 39869, 39881, 39882, 39879, 39880, 39874, 39872, - 39873, 40543, 40544, 40541, 40542, 40534, 40532, 40533, 40540, 40538, - 40539, 40537, 40535, 40536, 40606, 40607, 40601, 40605, 40604, 40602, - 40603, 40642, 40643, 40640, 40641, 40595, 40593, 40594, 40646, 40647, - 40644, 40645, 40639, 40637, 40638, 40599, 40600, 40592, 40598, 40597, - 40596, 40652, 40653, 40648, 40651, 40650, 40649, 39612, 39613, 39606, - 39611, 39609, 39610, 39607, 39608, 39616, 39617, 39614, 39615, 39597, - 39595, 39596, 39620, 39621, 39618, 39619, 39605, 39603, 39604, 39601, - 39602, 39594, 39600, 39599, 39598, 39626, 39627, 39622, 39625, 39624, - 39623, 40620, 40621, 40614, 40619, 40617, 40618, 40615, 40616, 40624, - 40625, 40622, 40623, 40613, 40611, 40612, 40610, 40608, 40609, 40630, - 40626, 40629, 40628, 40627, 40635, 40636, 40631, 40634, 40633, 40632, - 40209, 40210, 40204, 40208, 40207, 40205, 40206, 40213, 40214, 40211, - 40212, 40197, 40196, 40203, 40202, 40222, 40221, 40201, 40195, 40200, - 40199, 40198, 40219, 40220, 40215, 40218, 40217, 40216, 40454, 40455, - 40449, 40453, 40452, 40450, 40451, 40461, 40462, 40459, 40460, 40443, - 40441, 40442, 40465, 40466, 40463, 40464, 40458, 40456, 40457, 40447, - 40448, 40440, 40446, 40445, 40444, 40471, 40472, 40467, 40470, 40469, - 40468, 40390, 40391, 40385, 40389, 40388, 40386, 40387, 40397, 40398, - 40395, 40396, 40401, 40402, 40399, 40400, 40394, 40392, 40393, 40405, - 40406, 40403, 40404, 40411, 40412, 40407, 40410, 40409, 40408, 40576, - 40577, 40574, 40575, 40568, 40566, 40567, 40584, 40585, 40582, 40583, - 40580, 40581, 40578, 40579, 40572, 40573, 40565, 40571, 40570, 40569, - 40590, 40591, 40586, 40589, 40588, 40587, 39578, 39579, 39576, 39577, - 39570, 39571, 39568, 39569, 39586, 39587, 39584, 39585, 39582, 39583, - 39580, 39581, 39575, 39567, 39574, 39573, 39572, 39592, 39593, 39588, - 39591, 39590, 39589, 40358, 40357, 40337, 40336, 40349, 40350, 40347, - 40348, 40345, 40346, 40343, 40344, 40341, 40342, 40335, 40340, 40339, - 40338, 40355, 40356, 40351, 40354, 40353, 40352, 40158, 40159, 40156, - 40157, 40155, 40153, 40154, 40162, 40163, 40160, 40161, 40168, 40169, - 40164, 40167, 40166, 40165, 40174, 40175, 40170, 40173, 40172, 40171, - 40424, 40425, 40422, 40423, 40416, 40414, 40415, 40432, 40433, 40430, - 40431, 40428, 40429, 40426, 40427, 40420, 40421, 40413, 40419, 40418, - 40417, 40438, 40439, 40434, 40437, 40436, 40435, 40373, 40374, 40371, - 40372, 40362, 40360, 40361, 40377, 40378, 40375, 40376, 40370, 40368, - 40369, 40366, 40367, 40359, 40365, 40364, 40363, 40383, 40384, 40379, - 40382, 40381, 40380, 39933, 39934, 39927, 39932, 39930, 39931, 39928, - 39929, 39920, 39921, 39918, 39919, 39937, 39938, 39935, 39936, 39925, - 39926, 39917, 39924, 39923, 39922, 39943, 39944, 39939, 39942, 39941, - 39940, 40295, 40296, 40289, 40294, 40292, 40293, 40290, 40291, 40282, - 40283, 40280, 40281, 40299, 40300, 40297, 40298, 40287, 40288, 40279, - 40286, 40285, 40284, 40305, 40306, 40301, 40304, 40303, 40302, 39907, - 39908, 39901, 39906, 39904, 39905, 39902, 39903, 39895, 39893, 39894, - 39911, 39912, 39909, 39910, 39899, 39900, 39892, 39898, 39897, 39896, - 39915, 39916, 39913, 39914, 40141, 40142, 40135, 40140, 40138, 40139, - 40136, 40137, 40130, 40129, 40145, 40146, 40143, 40144, 40134, 40128, - 40133, 40132, 40131, 40151, 40152, 40147, 40150, 40149, 40148, 40189, - 40190, 40183, 40188, 40186, 40187, 40184, 40185, 40179, 40177, 40178, - 40193, 40194, 40191, 40192, 40181, 40182, 40176, 40180, 40551, 40552, - 40545, 40550, 40548, 40549, 40546, 40547, 40564, 40563, 40555, 40556, - 40553, 40554, 40561, 40562, 40557, 40560, 40559, 40558, 40323, 40324, - 40317, 40322, 40320, 40321, 40318, 40319, 40310, 40311, 40308, 40309, - 40327, 40328, 40325, 40326, 40315, 40316, 40307, 40314, 40313, 40312, - 40333, 40334, 40329, 40332, 40331, 40330, 40951, 40951, 40951, 39498, - 39471, 39469, 39476, 39450, 39486, 39457, 39459, 39475, 39462, 39473, - 39446, 39474, 39492, 39480, 39461, 39487, 39460, 39493, 39451, 39454, - 39447, 39456, 39477, 39488, 39500, 39465, 39496, 39481, 39464, 39491, - 39489, 39485, 39490, 39497, 39468, 39478, 39467, 39458, 39466, 39499, - 39455, 39482, 39472, 39449, 39448, 39453, 39463, 39483, 39494, 39484, - 39452, 39495, 39479, 39470, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 25094, 25083, 25082, 25066, 25064, 25063, 25077, - 25081, 25080, 25096, 25075, 25074, 25065, 25062, 25061, 25098, 25071, - 25097, 25085, 25088, 25089, 25070, 25079, 25100, 25078, 25095, 25099, - 25084, 25087, 25076, 25090, 25091, 25072, 25073, 25101, 25092, 25067, - 25068, 25069, 25093, 25057, 25060, 25058, 25056, 25059, 25055, 25102, - 25103, 38225, 38226, 38062, 38211, 38212, 38185, 37988, 37995, 38098, - 38071, 38105, 38045, 38171, 38199, 38023, 38016, 37974, 37967, 38089, - 38192, 37981, 38124, 38009, 38002, 38037, 38030, 38164, 38178, 38143, - 38206, 38084, 38130, 38051, 38112, 38157, 38150, 38234, 38235, 38066, - 38067, 38220, 38221, 38187, 37990, 37997, 38100, 38077, 38107, 38048, - 38173, 38201, 38025, 38018, 37976, 37969, 38093, 38194, 37983, 38126, - 38011, 38004, 38039, 38032, 38166, 38180, 38145, 38208, 38085, 38135, - 38056, 38114, 38159, 38152, 38232, 38233, 38137, 38064, 38065, 38218, - 38219, 38186, 37989, 37996, 38099, 38075, 38076, 38106, 38047, 38172, - 38200, 38024, 38017, 37975, 37968, 38092, 38193, 37982, 38125, 38010, - 38003, 38038, 38031, 38165, 38179, 38144, 38207, 38081, 38082, 38134, - 38055, 38113, 38158, 38151, 38229, 38230, 38060, 38215, 38216, 38183, - 37986, 37993, 38096, 38074, 38103, 38043, 38169, 38197, 38021, 38014, - 37972, 37965, 38091, 38190, 37979, 38122, 38007, 38000, 38035, 38028, - 38162, 38176, 38141, 38204, 38080, 38133, 38054, 38110, 38155, 38148, - 38236, 38237, 38068, 38069, 38222, 38223, 38188, 37991, 37998, 38101, - 38078, 38108, 38049, 38174, 38202, 38026, 38019, 37977, 37970, 38094, - 38195, 37984, 38127, 38012, 38005, 38040, 38033, 38167, 38181, 38146, - 38209, 38086, 38136, 38057, 38115, 38160, 38153, 38228, 38231, 38139, - 38058, 38059, 38214, 38217, 38182, 37985, 37992, 38095, 38073, 38102, - 38041, 38042, 38168, 38196, 38020, 38013, 37971, 37964, 38090, 38189, - 37978, 38116, 38006, 37999, 38034, 38027, 38161, 38175, 38140, 38203, - 38079, 38132, 38053, 38109, 38154, 38147, 38224, 38227, 38138, 38061, - 38063, 38210, 38213, 38184, 37987, 37994, 38097, 38070, 38072, 38104, - 38044, 38046, 38170, 38198, 38022, 38015, 37973, 37966, 38087, 38191, - 37980, 38123, 38008, 38001, 38036, 38029, 38163, 38177, 38142, 38205, - 38083, 38129, 38131, 38050, 38052, 38111, 38156, 38149, 38128, 38088, - 37961, 37962, 37963, 38119, 38120, 38117, 38241, 38244, 38247, 38246, - 38250, 38242, 38249, 38240, 38238, 38245, 38248, 38239, 38243, 38257, - 38259, 38256, 38255, 38252, 38251, 38254, 38253, 38260, 38258, 38121, - 38118, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 10283, 10484, 10172, 10331, 10122, 10425, 10227, 10386, 10168, - 10327, 10248, 10411, 10156, 10315, 10115, 10412, 10276, 10477, 10224, - 10383, 10124, 10427, 10225, 10384, 10164, 10323, 10157, 10316, 10221, - 10380, 10278, 10479, 10123, 10426, 10267, 10445, 10264, 10442, 10265, - 10443, 10247, 10410, 10154, 10313, 10169, 10328, 10298, 8145, 8137, 8088, - 8138, 33776, 8112, 8101, 8115, 8111, 8120, 8113, 8110, 8107, 8143, 8132, - 10297, 10301, 10178, 10337, 10176, 10335, 10288, 10489, 10166, 10325, - 10174, 10333, 10128, 10453, 10136, 10462, 10132, 10457, 10131, 10456, - 10134, 10460, 10212, 10371, 10262, 10440, 10170, 10329, 10165, 10324, - 27730, 27767, 8096, 8104, 3413, 2779, 3416, 2781, 3412, 3388, 3405, 3415, - 2808, 3414, 2784, 3385, 3391, 3390, 2782, 2788, 3404, 2807, 2801, 2787, - 3400, 2795, 3395, 3401, 3394, 3398, 2777, 2773, 2805, 2804, 2799, 3407, - 3397, 3408, 3409, 2806, 2771, 3381, 2800, 2803, 3384, 3410, 3382, 2768, - 3393, 2786, 2793, 2810, 3387, 3392, 2772, 2796, 2797, 2798, 3396, 3383, - 2770, 2769, 3411, 2809, 2785, 3386, 2783, 2774, 2790, 3389, 2789, 2792, - 3406, 2780, 2794, 2791, 3403, 2778, 3402, 2802, 3399, 2767, 2775, 2776, - 2764, 2763, 3417, 3419, 2766, 2765, 3418, 3420, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 27727, 27723, 27726, 27722, 27728, - 27724, 27729, 27725, 27782, 27797, 27825, 27804, 27787, 27781, 27796, - 27824, 27803, 27786, 27783, 27798, 27826, 27808, 27788, 27774, 27773, - 27775, 27819, 27838, 27835, 27837, 27836, 27816, 27986, 27987, 22867, - 23470, 22868, 23471, 22907, 23532, 23133, 23894, 23132, 23851, 22809, - 23392, 22810, 23393, 23274, 23282, 22783, 23348, 22784, 23349, 22785, - 23350, 22781, 23346, 22782, 23347, 22786, 23351, 23077, 23775, 22948, - 23584, 22945, 23581, 22949, 23585, 22795, 23369, 22967, 23608, 23000, - 23683, 23001, 23685, 23047, 23723, 23052, 23728, 23050, 23726, 23053, - 23729, 23059, 23740, 23058, 23737, 23074, 23765, 23079, 23778, 23174, - 23944, 23183, 23956, 23178, 23951, 23127, 23845, 23128, 23846, 23182, - 23955, 22869, 23488, 22936, 23571, 22811, 23394, 27995, 23430, 23629, - 23643, 23666, 23777, 23259, 23889, 23941, 22929, 23560, 22930, 23561, - 22931, 23117, 23857, 23122, 23887, 22932, 23563, 22933, 23564, 22934, - 23565, 27802, 27771, 27848, 23100, 23801, 23120, 23613, 23290, 22993, - 23657, 22805, 23382, 23379, 23526, 22789, 23354, 22876, 23495, 23179, - 23952, 23180, 23953, 23181, 23954, 22884, 23506, 22952, 23589, 22996, - 23662, 23072, 23762, 23096, 23799, 22903, 23076, 23103, 22955, 23099, - 23281, 23121, 23124, 22939, 22812, 22796, 23371, 23045, 23721, 23170, - 23932, 22889, 23511, 22890, 23512, 22891, 23513, 23042, 23712, 22778, - 23343, 22803, 23097, 23220, 22816, 23396, 23093, 23793, 23080, 23092, - 23792, 40951, 40951, 22808, 23388, 40951, 23423, 40951, 23420, 22982, - 23642, 23102, 23819, 22971, 23618, 22972, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 27703, 27706, 27715, - 23075, 23766, 23230, 27698, 27927, 23264, 23228, 23229, 23226, 23227, - 23225, 34770, 34772, 34782, 34774, 34771, 34773, 34781, 34762, 34761, - 34758, 34757, 34780, 34756, 34755, 34760, 34759, 34750, 34749, 34744, - 34743, 34752, 34751, 34746, 34745, 34768, 34764, 34763, 34754, 34753, - 34767, 34748, 34766, 34747, 34769, 34765, 34784, 34786, 34787, 34785, - 34783, 34775, 34776, 34777, 34778, 34779, 40951, 40951, 40951, 29388, - 29387, 29390, 29385, 29386, 29389, 29382, 29381, 29384, 29383, 40951, - 40951, 40951, 40951, 40951, 40951, 31352, 31351, 31340, 31341, 31328, - 31330, 31362, 31343, 31350, 31349, 31333, 31344, 31354, 31353, 31359, - 31364, 31346, 31345, 31332, 31367, 31355, 31356, 31334, 31369, 31366, - 31363, 31335, 31336, 31361, 31325, 31370, 31372, 31357, 31371, 31365, - 31368, 31360, 31339, 31358, 31377, 31378, 31348, 31347, 31331, 31342, - 31326, 31338, 31337, 31327, 31376, 31379, 31329, 31375, 31380, 31374, - 31373, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 32496, - 32498, 32445, 32446, 32466, 32467, 32462, 32463, 32457, 32458, 32459, - 32460, 32489, 32490, 32447, 32464, 32465, 32448, 32486, 32485, 32482, - 32481, 32470, 32480, 32479, 32484, 32483, 32472, 32454, 32453, 32450, - 32449, 32471, 32456, 32455, 32452, 32451, 32473, 32488, 32487, 32478, - 32477, 32492, 32494, 32493, 32469, 32461, 32474, 32475, 32476, 32491, - 32468, 32511, 32512, 32523, 32524, 32515, 32516, 32517, 32518, 32519, - 32520, 32525, 32526, 32513, 32521, 32522, 32514, 32497, 32495, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 32500, 32499, 32507, - 32509, 32506, 32505, 32502, 32501, 32504, 32503, 32510, 32508, 40951, - 40951, 40951, 40951, 40951, 40951, 8163, 8165, 8162, 8161, 8158, 8157, - 8160, 8159, 8166, 8164, 8154, 8155, 8150, 8151, 8152, 8153, 8149, 8156, - 10770, 10764, 10777, 10766, 10765, 10763, 10778, 10667, 10665, 10670, - 10771, 10821, 10676, 10788, 21585, 21587, 21584, 21583, 21580, 21579, - 21582, 21581, 21588, 21586, 21549, 21548, 21559, 21545, 21553, 21552, - 21566, 21546, 21555, 21543, 21547, 21551, 21550, 21561, 21558, 21556, - 21562, 21565, 21560, 21564, 21554, 21544, 21563, 21557, 21567, 21541, - 21568, 21542, 21577, 21574, 21576, 21575, 21578, 21573, 21571, 21572, - 21569, 21570, 31838, 31835, 31827, 31843, 31834, 31829, 31840, 31832, - 31831, 31833, 31837, 31825, 31842, 31841, 31839, 31845, 31844, 31836, - 31830, 31826, 31828, 31824, 31846, 31853, 31855, 31848, 31851, 31854, - 31852, 31850, 31849, 31821, 31820, 31823, 31822, 31856, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 31847, - 19228, 19231, 19232, 19229, 19186, 19187, 19195, 19189, 19191, 19194, - 19188, 19184, 19190, 19192, 19185, 19151, 19153, 19154, 19167, 19174, - 19181, 19216, 19133, 19140, 19214, 19218, 19164, 19237, 19220, 40951, - 40951, 40951, 20903, 20901, 20905, 20904, 20875, 20843, 20842, 20844, - 20884, 20863, 20849, 20850, 20882, 20876, 20883, 20845, 20846, 20847, - 20859, 20860, 20848, 20857, 20858, 20873, 20852, 20874, 20851, 20871, - 20872, 20838, 20839, 20854, 20869, 20870, 20840, 20841, 20853, 20861, - 20862, 20855, 20856, 20879, 20881, 20864, 20865, 20878, 20880, 20867, - 20868, 20866, 20877, 20902, 20908, 20910, 20911, 20912, 20906, 20907, - 20909, 20914, 20913, 20834, 20835, 20836, 20899, 20837, 20885, 20888, - 20897, 20890, 20895, 20893, 20891, 20889, 20886, 20887, 20892, 20900, - 40951, 20898, 20921, 20923, 20920, 20919, 20916, 20915, 20918, 20917, - 20924, 20922, 40951, 40951, 40951, 40951, 20894, 20896, 28607, 28605, - 28600, 28597, 28603, 28693, 28671, 28623, 28635, 28631, 28630, 28633, - 28632, 28625, 28624, 28622, 28735, 28737, 28734, 28733, 28730, 28729, - 28732, 28731, 28738, 28736, 28634, 28627, 28626, 28629, 28628, 40951, - 6245, 6263, 6265, 6262, 6246, 6264, 6254, 6253, 6250, 6249, 6225, 6226, - 6248, 6247, 6252, 6251, 6227, 6229, 6228, 6256, 6255, 6242, 6241, 6230, - 6231, 6240, 6236, 6235, 6234, 6239, 6238, 6232, 6233, 6237, 6261, 6259, - 6258, 6260, 6243, 6244, 6257, 6270, 6273, 6274, 6279, 6277, 6276, 6275, - 6271, 6272, 6278, 6213, 6211, 6210, 6212, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 6219, 6218, 6215, 6207, 6217, 6223, - 6214, 6221, 6224, 6222, 6220, 6216, 6209, 6208, 40951, 40951, 6286, 6288, - 6285, 6284, 6281, 6280, 6283, 6282, 6289, 6287, 40951, 40951, 6266, 6268, - 6267, 6269, 28577, 28570, 28569, 28574, 28573, 28567, 28566, 28565, - 28563, 28562, 28564, 28568, 28579, 28572, 28571, 28576, 28670, 28580, - 28581, 28578, 28667, 28668, 28669, 28708, 28710, 28709, 28552, 28704, - 28695, 28696, 28616, 28617, 35254, 35230, 35253, 35229, 35252, 35228, - 35267, 35243, 35261, 35237, 35256, 35232, 35255, 35231, 35272, 35248, - 35262, 35238, 35265, 35241, 35260, 35236, 35259, 35235, 35263, 35239, - 35264, 35240, 35258, 35234, 35257, 35233, 35266, 35242, 35270, 35246, - 35274, 35250, 35271, 35247, 35269, 35245, 35273, 35249, 35268, 35244, - 35275, 35251, 35276, 35288, 35296, 35293, 35292, 35298, 35299, 35277, - 35297, 35294, 35295, 35287, 35291, 35290, 35289, 35286, 35283, 35284, - 35285, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 35279, 35280, 35282, 35281, 35278, - 27037, 27038, 26996, 27013, 27024, 27023, 27000, 26999, 27012, 27018, - 27019, 27051, 27053, 27043, 27045, 27044, 26991, 26988, 26990, 27040, - 27041, 27055, 27056, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 17212, 17210, 17209, 17208, 17207, 17211, 40951, - 40951, 16906, 16904, 16903, 16902, 16901, 16905, 40951, 40951, 16921, - 16919, 16918, 16917, 16916, 16920, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 16862, 16868, 16866, 16863, 16865, 16864, - 16867, 40951, 16847, 16853, 16851, 16848, 16850, 16849, 16852, 40951, - 23362, 23338, 23368, 23363, 23459, 23622, 23811, 23611, 23602, 23605, - 23633, 23647, 23473, 23366, 23367, 23717, 23567, 23860, 23859, 23861, - 23862, 23821, 23258, 23764, 23421, 23744, 23422, 23808, 23809, 23365, - 23931, 23897, 23940, 23883, 23936, 23385, 23386, 23387, 23972, 23969, - 23970, 23971, 23983, 27685, 27908, 27917, 27918, 27975, 23802, 23570, - 23718, 23942, 23566, 18401, 23428, 23892, 23865, 27972, 27821, 27845, - 40951, 40951, 40951, 40951, 6468, 6469, 6470, 6471, 6472, 6473, 6431, - 6467, 6432, 6433, 6434, 6435, 6436, 6396, 6397, 6398, 6399, 6400, 6401, - 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6444, 6445, 6446, 6447, 6402, - 6395, 6403, 6404, 6405, 6406, 6407, 6408, 6449, 6450, 6451, 6452, 6453, - 6454, 6410, 6409, 6411, 6412, 6413, 6414, 6415, 6389, 6428, 6390, 6429, - 6391, 6430, 6392, 6393, 6394, 6388, 6416, 6417, 6418, 6419, 6420, 6421, - 6422, 6423, 6424, 6425, 6426, 6427, 6455, 6456, 6457, 6458, 6459, 6460, - 6461, 27005, 27017, 27027, 27029, 27014, 27008, 26995, 27020, 27007, - 27010, 27022, 27033, 27035, 27031, 27036, 27025, 27016, 27034, 27002, - 27003, 27032, 26994, 27004, 26998, 27001, 26997, 26993, 27006, 27028, - 27030, 27015, 27009, 27021, 27011, 27026, 27047, 27050, 27042, 27049, - 27048, 27052, 27046, 27054, 26992, 27039, 26989, 40951, 40951, 27063, - 27065, 27062, 27061, 27058, 27057, 27060, 27059, 27066, 27064, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 19425, 19423, 19456, 19457, 19458, 19434, 19435, 19467, 19469, - 19402, 19400, 19399, 19403, 19409, 19410, 19412, 19411, 19416, 19413, - 19414, 19418, 19386, 19384, 40951, 40951, 40951, 40951, 19282, 19283, - 19351, 19352, 19371, 19365, 19366, 19369, 19368, 19367, 19326, 19311, - 19350, 19317, 19321, 19320, 19334, 19333, 19254, 19279, 19272, 19357, - 19270, 19277, 19307, 19300, 19306, 19361, 19302, 19305, 19304, 19345, - 19338, 19355, 19356, 19344, 19342, 19341, 19346, 19348, 19293, 19292, - 19378, 19379, 19243, 19242, 19358, 19297, 19295, 40951, 40951, 40951, - 40951, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, - 7593, 7594, 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, - 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614, 7615, 7616, - 7617, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, - 7629, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, - 7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, - 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, - 7665, 7666, 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674, 7675, 7676, - 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 7685, 7686, 7687, 7688, - 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, - 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, - 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, 7721, 7722, 7723, 7724, - 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, 7736, - 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, - 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, - 7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, - 7773, 7774, 7775, 7776, 7777, 7778, 7779, 7780, 7781, 7782, 7783, 7784, - 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, - 7797, 7798, 7799, 7800, 7801, 7802, 7803, 7804, 7805, 7806, 7807, 7808, - 7809, 7810, 7811, 7812, 7813, 7814, 7815, 7816, 7817, 7818, 7819, 7820, - 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, 7829, 7830, 7831, 7832, - 7833, 7834, 7835, 7836, 7837, 7380, 7381, 7382, 7383, 7384, 7385, 7386, - 7387, 7388, 7389, 7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, - 7399, 7400, 7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, - 7411, 7412, 7413, 7414, 7415, 7416, 7417, 7418, 7419, 7420, 7421, 7422, - 7423, 7424, 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434, - 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, - 7447, 7448, 7449, 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, - 7459, 7460, 7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, - 7471, 7472, 7473, 7474, 7475, 7366, 7367, 7368, 7369, 7370, 7371, 7372, - 7373, 7374, 7375, 7376, 7377, 7378, 7379, 40951, 40951, 7476, 7477, 7478, - 7479, 7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 34311, 17490, 31931, 29628, 11221, 31502, 371, 1054, 24321, + 32155, 2570, 31753, 8585, 20621, 17673, 34150, 11004, 10989, 11001, + 10998, 10983, 10980, 10995, 10992, 11007, 10986, 8161, 32765, 24564, + 16926, 18304, 31929, 8584, 22906, 22952, 22962, 22978, 22995, 23040, + 23044, 23061, 23075, 23104, 23109, 23121, 23141, 23150, 23166, 23216, + 23225, 23228, 23249, 23273, 23302, 23341, 23352, 23361, 23364, 23378, + 24283, 32056, 32169, 6924, 25337, 18275, 23470, 23520, 23540, 23563, + 23599, 23658, 23666, 23684, 23703, 23740, 23746, 23760, 23799, 23812, + 23836, 23893, 23905, 23911, 23949, 23991, 24064, 24112, 24126, 24135, + 24143, 24159, 24224, 39287, 32118, 37693, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 29622, + 20975, 6233, 31795, 10083, 39859, 5039, 32747, 10971, 8779, 17569, 24331, + 29602, 34101, 31979, 27023, 10686, 31765, 34937, 34936, 4, 27754, 31650, + 27760, 6229, 34940, 25990, 32216, 39421, 39419, 39427, 20978, 22935, + 22936, 22924, 22938, 22917, 22919, 22940, 22963, 23026, 23027, 22998, + 23013, 23091, 23092, 23081, 23079, 23037, 23164, 23205, 23206, 23173, + 23191, 23180, 28467, 23189, 23333, 23334, 23303, 23306, 23373, 23294, + 23981, 23501, 23502, 23490, 23504, 23481, 23483, 23507, 23541, 23632, + 23633, 23602, 23617, 23721, 23722, 23704, 23706, 23657, 23831, 23875, + 23876, 23837, 23861, 23844, 11132, 23859, 24099, 24102, 24067, 24070, + 24154, 24013, 24145, 22922, 23488, 22907, 23471, 22932, 23498, 22967, + 23546, 22965, 23543, 22971, 23551, 22966, 23545, 22985, 23571, 22982, + 23565, 23016, 23621, 23029, 23635, 23008, 23612, 23023, 23629, 23007, + 23611, 23046, 23668, 23049, 23671, 23053, 23676, 23045, 23667, 23064, + 23687, 23071, 23696, 23085, 23718, 23083, 23713, 23094, 23724, 23088, + 23715, 23078, 23587, 23390, 24179, 23105, 23741, 23110, 23747, 23759, + 23135, 23777, 23131, 23764, 23133, 23767, 23128, 23774, 23130, 23785, + 23159, 23824, 23151, 23813, 23153, 23817, 23832, 23039, 23640, 23169, + 23854, 23208, 23878, 23186, 23850, 23391, 24182, 23237, 23928, 23229, + 23912, 23230, 23914, 23255, 23950, 23254, 23956, 23252, 23954, 23250, + 23952, 23274, 23992, 23277, 23996, 23284, 24008, 23330, 24096, 23322, + 24086, 23336, 24104, 23337, 24095, 23313, 24077, 23327, 24091, 23353, + 24127, 23365, 24144, 23366, 23381, 24160, 23384, 24166, 23380, 24163, + 23791, 23529, 22958, 22953, 23521, 23297, 24016, 23211, 22969, 23549, + 22944, 22990, 22986, 23566, 24021, 23246, 23272, 23210, 23041, 23661, + 23052, 23059, 23702, 23102, 23095, 23120, 23758, 23763, 23787, 23291, + 23157, 23818, 23172, 23198, 23868, 23213, 23890, 23222, 23901, 23467, + 23299, 24018, 23038, 23408, 24004, 23283, 24005, 23282, 23315, 24079, + 23340, 23345, 23370, 24149, 23387, 24169, 23031, 23033, 23650, 23655, + 23460, 23298, 24017, 23406, 23461, 23462, 23463, 23399, 23410, 22992, + 22980, 23593, 23140, 23129, 23798, 23165, 23154, 23835, 22930, 23496, + 23082, 23705, 23179, 23843, 23305, 24069, 23310, 24074, 23309, 24073, + 23307, 24071, 23308, 24072, 24053, 22918, 23482, 22914, 23478, 22942, + 23510, 23054, 23677, 23047, 23669, 23111, 23748, 23187, 23857, 23188, + 23858, 23032, 23652, 23743, 22991, 22979, 23592, 23048, 23670, 23073, + 23360, 23158, 23823, 22920, 23484, 22941, 23509, 23190, 23860, 22916, + 23480, 22937, 23503, 23012, 23616, 23028, 23634, 23076, 23712, 23093, + 23723, 23185, 23849, 23207, 23877, 23234, 23918, 23239, 23929, 23312, + 24076, 23335, 24103, 23253, 23955, 23276, 23994, 23377, 24158, 23065, + 23688, 23155, 23570, 23215, 23892, 23389, 24173, 22913, 23477, 22996, + 23600, 23181, 23845, 23194, 23864, 23182, 23846, 23183, 23847, 23374, + 24155, 23766, 23816, 23995, 23584, 23597, 23910, 22939, 22972, 23552, + 23123, 23278, 23963, 24168, 23055, 23678, 22959, 23339, 23293, 23030, + 23637, 23108, 23745, 23266, 23908, 23241, 23932, 23376, 24153, 24045, + 23512, 24046, 23528, 23881, 23544, 23567, 23575, 23941, 23972, 23976, + 23887, 23936, 23938, 23559, 23585, 23675, 23979, 23437, 23682, 23948, + 24022, 23695, 23701, 23725, 23736, 23415, 23772, 23761, 23780, 23788, + 24048, 24049, 23807, 23820, 23829, 23448, 23532, 23422, 23558, 23904, + 24033, 24036, 24039, 23923, 23925, 23919, 23939, 23424, 23416, 23969, + 23643, 23586, 23989, 23647, 24040, 24007, 24065, 24106, 24119, 24042, + 24057, 24050, 23455, 24172, 24162, 23649, 23651, 23464, 23407, 23404, + 23457, 23402, 23435, 23557, 23438, 23444, 23742, 24055, 23417, 23907, + 23465, 23409, 23594, 23580, 23595, 24060, 24009, 24059, 23664, 23795, + 23796, 23401, 23403, 24023, 24024, 28085, 28086, 28094, 28116, 28143, + 28146, 28041, 28163, 28165, 28014, 27957, 28171, 27867, 28022, 28024, + 28000, 27973, 28020, 28002, 28026, 28173, 27959, 27949, 6162, 28177, + 28003, 27866, 27972, 27998, 27989, 27995, 27994, 28170, 27980, 27901, + 27900, 28172, 27958, 28013, 28011, 5032, 11327, 32348, 30158, 34059, + 11386, 28027, 27950, 28084, 28096, 28123, 28164, 28120, 27964, 27979, + 28007, 27992, 27969, 28179, 28178, 28176, 28174, 27956, 27985, 27997, + 27987, 27990, 27991, 28010, 28009, 28008, 27993, 28019, 27869, 27970, + 27870, 27971, 28029, 28012, 27986, 8379, 8168, 8252, 8554, 8489, 8512, + 8178, 8278, 8274, 8393, 8538, 8288, 8184, 8570, 8310, 8311, 8186, 8396, + 8562, 8189, 8520, 8190, 8380, 8169, 8473, 8533, 8463, 8395, 8470, 8563, + 8314, 8517, 8500, 8516, 8521, 8281, 8275, 8537, 8191, 8254, 8510, 8569, + 8181, 8400, 8185, 8253, 8180, 8397, 8558, 8494, 8488, 8312, 8557, 8542, + 8486, 8541, 8485, 8528, 8398, 8546, 8551, 8582, 8571, 8298, 8381, 8170, + 8390, 8389, 8392, 8391, 8182, 8324, 8309, 8462, 8503, 8394, 8177, 8475, + 8565, 8385, 8524, 8471, 8326, 8581, 8464, 8525, 8523, 8529, 8280, 8174, + 8304, 8540, 8290, 8289, 8295, 8296, 8305, 8291, 8302, 8413, 8421, 8426, + 8434, 8437, 8419, 8451, 8453, 8455, 8440, 8443, 8458, 8459, 18489, 18753, + 18384, 18620, 18571, 18567, 18478, 18735, 41412, 41412, 18810, 18760, + 18761, 18759, 18815, 18492, 41412, 41412, 41412, 41412, 18775, 18505, + 18382, 18358, 18415, 18405, 18429, 41412, 18461, 41412, 18476, 18451, + 18667, 18361, 18488, 18486, 18484, 18406, 18490, 18385, 18482, 18416, + 18485, 18491, 18493, 18494, 18495, 18452, 18481, 18462, 41412, 18464, + 18483, 18467, 18479, 18487, 18480, 18431, 18421, 18472, 18617, 18632, + 18657, 18676, 18687, 18592, 18752, 18750, 18622, 18623, 18754, 18633, + 18747, 18658, 18698, 18755, 18756, 18757, 18758, 18725, 18738, 18739, + 18749, 18745, 18748, 18678, 18736, 18751, 18737, 18700, 18663, 18683, + 18734, 18696, 18724, 18500, 18812, 18771, 18779, 18777, 18778, 18587, + 18588, 18552, 18563, 18619, 18562, 18744, 18565, 18621, 18564, 18699, + 18561, 18742, 8660, 8754, 8638, 8732, 8634, 8728, 8632, 8726, 8630, 8724, + 8659, 8753, 8629, 8723, 18551, 18590, 18568, 18566, 18501, 18569, 18591, + 18466, 18746, 18496, 18465, 18743, 18589, 18498, 18499, 18497, 10350, + 10352, 10299, 10338, 10274, 10303, 10290, 10409, 10422, 10245, 10248, + 10262, 10377, 10347, 10390, 10307, 10275, 10291, 10423, 10332, 10311, + 10349, 10416, 10412, 10345, 10388, 10362, 10313, 10329, 10318, 10381, + 10249, 10324, 10327, 10259, 10269, 10331, 10339, 10265, 10292, 10395, + 10393, 10343, 10406, 10398, 10312, 10411, 10403, 10434, 10450, 10624, + 10491, 10470, 10508, 10617, 10613, 10504, 10566, 10521, 10472, 10488, + 10477, 10547, 10552, 10483, 10486, 10584, 10595, 10490, 10498, 10590, + 10451, 10573, 10571, 10502, 10607, 10576, 10471, 10612, 10604, 10509, + 10511, 10458, 10497, 10600, 10462, 10449, 10610, 10623, 10540, 10546, + 10587, 10536, 10506, 10568, 10466, 10382, 10548, 10405, 10606, 10358, + 10517, 10244, 10538, 10354, 10513, 10287, 10446, 10355, 10514, 10378, + 10537, 10252, 10556, 10421, 10622, 10360, 10519, 10361, 10520, 10273, + 10599, 10253, 10561, 10383, 10549, 10385, 10551, 10375, 10534, 10655, + 8245, 8239, 8242, 8240, 8241, 8195, 8248, 10389, 10567, 10402, 10580, + 10325, 10484, 10334, 10493, 10336, 10495, 10333, 10492, 10418, 10619, + 10414, 10615, 10363, 10522, 10365, 10524, 10366, 10525, 10285, 10444, + 10320, 10479, 10428, 10628, 10250, 10553, 10281, 10440, 10328, 10487, + 10261, 10586, 10400, 10578, 10401, 10579, 10340, 10499, 10427, 10627, + 10294, 10453, 10295, 10454, 10391, 10569, 10278, 10437, 10279, 10438, + 10431, 10419, 10620, 10364, 10523, 10316, 10475, 10323, 10482, 10322, + 10481, 10376, 10535, 10330, 10489, 10555, 10277, 10436, 10276, 10435, + 10426, 10626, 10351, 10510, 10386, 10564, 10387, 10565, 10417, 10618, + 10413, 10614, 10280, 10439, 10348, 10507, 10346, 10505, 10384, 10550, + 10283, 10442, 10284, 10443, 10326, 10485, 10272, 10598, 10271, 10597, + 10270, 10596, 10293, 10452, 10335, 10494, 10407, 10608, 10337, 10496, + 10341, 10500, 10342, 10501, 10369, 10528, 10368, 10527, 10374, 10533, + 10367, 10526, 10370, 10529, 10371, 10530, 10372, 10531, 10373, 10532, + 10257, 10560, 10317, 10476, 10246, 10541, 10258, 10563, 10404, 10605, + 10425, 10625, 10424, 10603, 10282, 10441, 10314, 10473, 10319, 10478, + 10251, 10554, 10392, 10570, 10321, 10480, 10305, 10464, 10309, 10468, + 10315, 10474, 41412, 2488, 2495, 2479, 2501, 2475, 2499, 2476, 2477, + 2466, 2498, 2494, 2491, 2493, 2471, 2483, 2500, 2481, 2478, 2469, 2496, + 2467, 2497, 2486, 2490, 2470, 2485, 2480, 2474, 2487, 2489, 2465, 2473, + 2472, 2468, 2484, 2482, 2502, 2492, 41412, 41412, 2552, 2464, 2505, 2504, + 2503, 2556, 2463, 2525, 2528, 2538, 2516, 2544, 2512, 2542, 2513, 2514, + 2527, 2541, 2537, 2534, 2536, 2508, 2520, 2543, 2518, 2515, 2506, 2539, + 2531, 2540, 2523, 2530, 2507, 2522, 2517, 2511, 2524, 2529, 2526, 2510, + 2509, 2533, 2521, 2519, 2545, 2535, 2546, 2532, 2555, 2553, 41412, 41412, + 32203, 24344, 2554, 41412, 19963, 19966, 19967, 19974, 19975, 19971, + 19978, 19976, 19961, 19973, 19970, 19954, 19955, 19956, 19964, 19969, + 19962, 19951, 19959, 19960, 19957, 19958, 19953, 19965, 19968, 19972, + 19979, 19980, 19952, 19977, 20058, 20073, 20062, 20060, 20061, 20063, + 20075, 20071, 20066, 20067, 20064, 20065, 20069, 20059, 20077, 20083, + 20070, 20080, 20072, 20074, 20081, 20057, 20056, 20082, 20068, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 19981, 19988, 20031, + 20029, 20006, 20037, 20011, 20008, 20023, 20048, 19997, 19991, 20033, + 20003, 20035, 20002, 20009, 20013, 19987, 19999, 19994, 20001, 20027, + 20004, 20021, 20015, 20025, 41412, 41412, 41412, 41412, 20084, 20052, + 20055, 20053, 20079, 20078, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 2306, 2340, 1099, 2341, 2342, 2305, + 2451, 2452, 2317, 2449, 2450, 2644, 1067, 1080, 2312, 2346, 2339, 2345, + 2337, 2338, 2347, 2365, 2353, 2382, 2349, 2401, 2400, 2333, 1387, 1089, + 2439, 2447, 1342, 1294, 1157, 1147, 1577, 1150, 1593, 1129, 1171, 1519, + 1518, 1541, 1320, 1279, 1361, 1196, 1536, 1440, 1620, 1474, 1487, 1466, + 1212, 1496, 1615, 1119, 1266, 1348, 1345, 1241, 1240, 1239, 2427, 1246, + 1431, 1331, 1366, 1379, 1403, 1296, 1572, 1165, 1584, 1097, 1078, 1109, + 1091, 1074, 1105, 2334, 2404, 2159, 1104, 1103, 2403, 2323, 2160, 2448, + 2443, 2442, 2444, 2318, 1092, 2446, 2459, 2461, 2458, 2457, 2454, 2453, + 2456, 2455, 2462, 2460, 2310, 1085, 2441, 1100, 1224, 1226, 1493, 1162, + 1154, 1153, 1316, 1317, 1319, 1558, 1318, 1546, 1552, 1191, 1527, 1526, + 1419, 1531, 1186, 1289, 1287, 1398, 1227, 1286, 1506, 1513, 1221, 1206, + 1203, 1204, 1209, 1218, 1232, 1199, 1205, 1457, 1443, 1454, 1451, 1444, + 1452, 1447, 1328, 1450, 1475, 1478, 1479, 1469, 1468, 1500, 1122, 1225, + 1249, 1247, 1565, 1251, 1426, 1434, 1435, 1343, 1495, 1337, 1336, 1388, + 1334, 1257, 1260, 1389, 1259, 1273, 1258, 1370, 1368, 1372, 1371, 1414, + 1404, 1460, 1412, 1409, 1307, 1508, 1304, 1297, 1298, 1522, 1581, 1355, + 1612, 1557, 1609, 1358, 1580, 1564, 1235, 1603, 1598, 1574, 1624, 1602, + 1585, 1588, 1101, 1170, 2356, 2355, 2358, 2357, 2384, 2364, 2362, 1090, + 2426, 2381, 2380, 2350, 2359, 2399, 2360, 2402, 2387, 2376, 2378, 2314, + 1088, 1087, 2322, 2398, 1198, 1448, 17510, 17512, 17509, 17508, 17505, + 17504, 17507, 17506, 17513, 17511, 1488, 1213, 1268, 2344, 2343, 1303, + 35067, 35141, 35138, 35139, 35135, 35076, 35063, 35064, 35140, 35137, + 35062, 35072, 35071, 35070, 41412, 35060, 35108, 35104, 35118, 35114, + 35115, 35078, 35077, 35079, 35121, 35119, 35080, 35111, 35112, 35116, + 35117, 35109, 35081, 35093, 35120, 35100, 35107, 35122, 35094, 35098, + 35106, 35110, 35099, 35105, 35113, 35095, 35097, 35096, 35127, 35126, + 35125, 35130, 35129, 35128, 35132, 35131, 35066, 35065, 35075, 35074, + 35073, 35069, 35068, 35133, 35147, 35148, 35134, 35145, 35144, 35143, + 35142, 35124, 35123, 35146, 35061, 41412, 41412, 35101, 35102, 35103, + 1177, 1180, 1175, 1176, 1178, 1179, 1173, 1288, 1285, 1202, 1197, 1445, + 1481, 1124, 1120, 1123, 1252, 1250, 1350, 1346, 1344, 1382, 1381, 1410, + 1407, 1408, 1373, 1446, 1449, 1480, 1284, 1282, 1477, 1441, 1283, 1156, + 1155, 1238, 1237, 1236, 1576, 1575, 1587, 1586, 1280, 1482, 1476, 1333, + 37261, 37274, 37270, 37287, 37286, 37265, 37262, 37250, 37281, 37266, + 37255, 37254, 37277, 37264, 37257, 37258, 37275, 37253, 37283, 37276, + 37288, 37269, 37268, 37267, 37279, 37260, 37263, 37278, 37284, 37273, + 37272, 37252, 37280, 37285, 37251, 37259, 37256, 37282, 37246, 37245, + 37292, 37248, 37293, 37291, 37247, 37249, 37290, 37289, 37294, 37271, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 29486, 29488, 29485, 29484, 29481, 29480, + 29483, 29482, 29489, 29487, 29521, 29508, 29522, 29507, 29523, 29505, + 29504, 29492, 29497, 29510, 29516, 29518, 29496, 29506, 29491, 29503, + 29502, 29517, 29509, 29511, 29513, 29514, 29499, 29515, 29500, 29498, + 29512, 29519, 29520, 29501, 29494, 29493, 29495, 29474, 29475, 29476, + 29472, 29469, 29470, 29471, 29473, 29468, 29525, 29524, 29527, 29526, + 29477, 29528, 29490, 41412, 41412, 29478, 29479, 29529, 32575, 32562, + 32576, 32564, 32567, 32563, 32578, 32566, 32573, 32582, 32568, 32569, + 32579, 32581, 32570, 32565, 32583, 32574, 32580, 32577, 32571, 32572, + 32585, 32586, 32589, 32584, 32590, 32587, 32609, 32619, 32614, 32608, + 32618, 32613, 32607, 32617, 32591, 32615, 32611, 32621, 32592, 32610, + 32620, 32612, 32616, 32588, 41412, 41412, 32599, 32593, 32595, 32598, + 32596, 32600, 32622, 32605, 32603, 32606, 32602, 32604, 32597, 32601, + 32594, 41412, 25779, 25766, 25768, 25767, 25769, 25778, 25776, 25781, + 25761, 25759, 25758, 25770, 25771, 25772, 25762, 25780, 25773, 25764, + 25774, 25775, 25763, 25760, 25777, 25782, 25765, 25757, 25783, 25784, + 41412, 41412, 25785, 41412, 35086, 35091, 35087, 35089, 35085, 35084, + 35088, 35092, 35083, 35082, 35090, 41412, 41412, 41412, 41412, 41412, + 1143, 1133, 1144, 1160, 1142, 1130, 1139, 1136, 1140, 1138, 1161, 1135, + 1146, 1132, 1134, 1145, 1131, 1137, 1141, 2428, 2429, 2431, 1539, 1064, + 2316, 1411, 1281, 1501, 1499, 1347, 2445, 1413, 2313, 2315, 41412, 41412, + 41412, 41412, 41412, 2311, 2366, 2392, 2391, 2394, 2158, 2408, 1084, + 1102, 1174, 1181, 1321, 1498, 1248, 1432, 1367, 1380, 1599, 1601, 1453, + 1573, 1465, 1378, 1200, 1467, 1261, 1494, 1623, 1121, 1335, 1433, 1172, + 1420, 1524, 1442, 1600, 1117, 1115, 1118, 1421, 1525, 1547, 1507, 1349, + 1267, 1116, 1323, 1322, 1369, 1278, 2348, 2351, 2377, 2372, 2383, 1113, + 1112, 2407, 1114, 1111, 2397, 2367, 2363, 2386, 2385, 2379, 2390, 2368, + 2370, 2369, 2371, 2374, 2373, 2352, 2361, 1086, 2440, 1070, 1068, 1072, + 1071, 1069, 1073, 2434, 2436, 2438, 2433, 2435, 2437, 2309, 2308, 2307, + 2375, 1094, 1093, 1106, 1630, 2319, 1629, 2321, 1081, 1082, 2320, 1077, + 2161, 10905, 10895, 10909, 10914, 10830, 10804, 10805, 10874, 10875, + 10850, 10851, 10869, 10871, 10812, 10831, 10882, 10806, 10813, 10832, + 10845, 10807, 10841, 10840, 10825, 10823, 10856, 10810, 10814, 10861, + 10859, 10857, 10866, 10865, 10818, 10817, 10855, 10868, 10867, 10820, + 10819, 10858, 10854, 10877, 10876, 10838, 10837, 10828, 10849, 10844, + 10843, 10864, 10863, 10862, 10873, 10833, 10834, 10835, 10827, 10927, + 10926, 10907, 10908, 10917, 10939, 10940, 10929, 10930, 10935, 10936, + 10923, 10933, 10941, 10918, 10924, 10934, 10925, 10919, 10913, 10928, + 10920, 10955, 10916, 10915, 10799, 10796, 10922, 10932, 10931, 10881, + 10839, 10822, 10879, 10815, 10842, 10880, 10848, 10870, 10872, 10937, + 10938, 10943, 10942, 10950, 10952, 10949, 10948, 10945, 10944, 10947, + 10946, 10953, 10951, 10797, 10912, 10811, 10847, 10846, 10808, 10853, + 10852, 10829, 10878, 10826, 10824, 10860, 10821, 10816, 10836, 3599, + 3667, 3670, 3672, 41412, 3623, 3624, 3637, 3638, 3635, 3636, 3617, 3619, + 41412, 41412, 3659, 3625, 41412, 41412, 3660, 3626, 3610, 3607, 3651, + 3650, 3639, 3649, 3648, 3653, 3652, 3641, 3632, 3631, 3628, 3627, 3640, + 3634, 3633, 3630, 3629, 3642, 41412, 3655, 3654, 3647, 3646, 3658, 3622, + 3611, 41412, 3657, 41412, 41412, 41412, 3643, 3644, 3645, 3656, 41412, + 41412, 3668, 3669, 3674, 3683, 3684, 3677, 3678, 3679, 3680, 41412, + 41412, 3685, 3675, 41412, 41412, 3686, 3676, 3671, 3608, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 3600, 41412, 41412, 41412, + 41412, 3615, 3614, 41412, 3621, 3618, 3620, 3681, 3682, 41412, 41412, + 3693, 3695, 3692, 3691, 3688, 3687, 3690, 3689, 3696, 3694, 3613, 3612, + 3662, 3661, 3601, 3605, 3604, 3603, 3602, 3606, 3673, 3697, 3616, 3598, + 3666, 41412, 41412, 19044, 19045, 19050, 41412, 18996, 18997, 19012, + 19013, 19010, 19011, 41412, 41412, 41412, 41412, 19031, 18998, 41412, + 41412, 19030, 18999, 18995, 18994, 18992, 18991, 19016, 19023, 19022, + 19025, 19024, 19018, 19007, 19006, 19001, 19000, 19017, 19009, 19008, + 19003, 19002, 19019, 41412, 19027, 19026, 19021, 19020, 19034, 19036, + 19005, 41412, 19015, 19014, 41412, 19035, 19028, 41412, 19029, 19033, + 41412, 41412, 19047, 41412, 19051, 19056, 19057, 19054, 19055, 41412, + 41412, 41412, 41412, 19059, 19052, 41412, 41412, 19058, 19053, 19049, + 41412, 41412, 41412, 19046, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 18993, 18990, 19037, 19004, 41412, 19032, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 19069, 19071, 19068, 19067, 19064, 19063, + 19066, 19065, 19072, 19070, 19060, 18989, 19061, 19073, 19062, 19048, + 18988, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 18884, 18892, 18894, 41412, 18834, 18835, 18853, 18854, 18851, + 18852, 18846, 18848, 18910, 41412, 18881, 18836, 18911, 41412, 18882, + 18837, 18874, 18873, 18870, 18869, 18858, 18868, 18867, 18872, 18871, + 18860, 18843, 18842, 18839, 18838, 18859, 18845, 18844, 18841, 18840, + 18861, 41412, 18876, 18875, 18866, 18865, 18878, 18880, 18879, 41412, + 18856, 18855, 41412, 18850, 18862, 18863, 18864, 18877, 41412, 41412, + 18890, 18891, 18897, 18906, 18907, 18900, 18901, 18902, 18903, 18895, + 41412, 18908, 18898, 18896, 41412, 18909, 18899, 18893, 41412, 41412, + 18924, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 18847, 18849, 18904, 18905, + 41412, 41412, 18920, 18922, 18919, 18918, 18915, 18914, 18917, 18916, + 18923, 18921, 18912, 18913, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 18857, 18889, 18888, 18885, 18887, 18883, 18886, 41412, 30802, + 30805, 30808, 41412, 30753, 30754, 30772, 30773, 30770, 30771, 30765, + 30767, 41412, 41412, 30798, 30755, 41412, 41412, 30799, 30756, 30792, + 30791, 30788, 30787, 30776, 30786, 30785, 30790, 30789, 30778, 30762, + 30761, 30758, 30757, 30777, 30764, 30763, 30760, 30759, 30779, 41412, + 30794, 30793, 30784, 30783, 30796, 30752, 30750, 41412, 30775, 30774, + 41412, 30769, 30780, 30781, 30782, 30795, 41412, 41412, 30803, 30804, + 30809, 30818, 30819, 30812, 30813, 30814, 30815, 41412, 41412, 30820, + 30810, 41412, 41412, 30821, 30811, 30807, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 30806, 30739, 30740, 41412, 41412, 41412, 41412, + 30749, 30748, 41412, 30751, 30766, 30768, 30816, 30817, 41412, 41412, + 30828, 30830, 30827, 30826, 30823, 30822, 30825, 30824, 30831, 30829, + 30747, 30797, 30744, 30743, 30746, 30741, 30742, 30745, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 35760, 35777, + 41412, 35723, 35724, 35736, 35737, 35732, 35733, 41412, 41412, 41412, + 35741, 35742, 35725, 41412, 35734, 35735, 35726, 35746, 41412, 41412, + 41412, 35718, 35743, 41412, 35745, 41412, 35719, 35721, 41412, 41412, + 41412, 35717, 35722, 41412, 41412, 41412, 35720, 35716, 35748, 41412, + 41412, 41412, 35747, 35750, 35731, 35730, 35729, 35728, 35727, 35749, + 35738, 35739, 35740, 35744, 41412, 41412, 41412, 41412, 36050, 36057, + 36058, 36053, 36054, 41412, 41412, 41412, 36059, 36060, 36051, 41412, + 36055, 36056, 36052, 35776, 41412, 41412, 36063, 41412, 41412, 41412, + 41412, 41412, 41412, 35652, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 35689, 35691, + 35688, 35687, 35684, 35683, 35686, 35685, 35692, 35690, 35754, 35752, + 35753, 35682, 36062, 36061, 35681, 35679, 35651, 35757, 35755, 41412, + 41412, 41412, 41412, 41412, 37126, 37127, 37132, 37134, 37125, 37086, + 37087, 37102, 37103, 37098, 37099, 37093, 37095, 41412, 37119, 37120, + 37088, 41412, 37100, 37101, 37089, 37116, 37115, 37112, 37111, 37075, + 37110, 37109, 37114, 37113, 37077, 37082, 37081, 37069, 37068, 37076, + 37085, 37083, 37072, 37070, 37073, 41412, 37118, 37117, 37108, 37107, + 37122, 37123, 37080, 37079, 37092, 37091, 37090, 37097, 37104, 37105, + 37106, 37121, 41412, 41412, 37130, 37131, 37135, 37146, 37147, 37138, + 37139, 37140, 37141, 41412, 37148, 37149, 37136, 41412, 37144, 37145, + 37137, 37133, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 37124, + 37060, 41412, 37084, 37071, 37078, 41412, 37059, 37074, 41412, 41412, + 37094, 37096, 37142, 37143, 41412, 41412, 37156, 37158, 37155, 37154, + 37151, 37150, 37153, 37152, 37159, 37157, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 37128, 37067, 37065, 37063, 37061, 37066, 37064, + 37062, 37129, 21436, 21435, 21440, 21444, 21437, 21384, 21385, 21410, + 21411, 21406, 21407, 21401, 21403, 41412, 21427, 21428, 21386, 41412, + 21408, 21409, 21387, 21424, 21423, 21420, 21419, 21381, 21418, 21417, + 21422, 21421, 21383, 21398, 21397, 21389, 21388, 21382, 21400, 21399, + 21391, 21390, 21379, 41412, 21426, 21425, 21416, 21415, 21431, 21432, + 21396, 21395, 21394, 21393, 41412, 21405, 21412, 21413, 21414, 21430, + 41412, 41412, 21438, 21439, 21447, 21458, 21459, 21450, 21451, 21452, + 21453, 41412, 21460, 21461, 21448, 41412, 21456, 21457, 21449, 21443, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 21433, 21446, 41412, + 41412, 41412, 41412, 41412, 21445, 21380, 21429, 41412, 21402, 21404, + 21454, 21455, 41412, 41412, 21468, 21470, 21467, 21466, 21463, 21462, + 21465, 21464, 21471, 21469, 41412, 21441, 21442, 21434, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 25719, 25721, 25726, 25724, 25676, 25650, 25652, 25696, 25697, 25692, + 25693, 25677, 25679, 41412, 25711, 25712, 25653, 41412, 25694, 25695, + 25654, 25708, 25707, 25704, 25703, 25684, 25665, 25664, 25706, 25705, + 25685, 25673, 25671, 25668, 25667, 25683, 25675, 25674, 25670, 25669, + 25686, 25682, 25710, 25709, 25702, 25701, 25714, 25715, 25691, 25690, + 25689, 25688, 25687, 25681, 25698, 25699, 25700, 25713, 25672, 25722, + 25720, 25725, 25728, 25739, 25740, 25731, 25732, 25733, 25734, 41412, + 25741, 25742, 25729, 41412, 25737, 25738, 25730, 25723, 25666, 25727, + 41412, 41412, 41412, 41412, 25662, 25663, 25657, 25743, 25642, 25640, + 25647, 25637, 25638, 25648, 25641, 25651, 25678, 25680, 25735, 25736, + 41412, 41412, 25633, 25635, 25632, 25631, 25628, 25627, 25630, 25629, + 25636, 25634, 25718, 25716, 25717, 25645, 25644, 25649, 25639, 25643, + 25646, 25626, 25659, 25658, 25660, 25655, 25656, 25661, 41412, 33959, + 33958, 33960, 41412, 33904, 33901, 33889, 33888, 33912, 33911, 33914, + 33913, 33910, 33909, 33908, 33907, 33906, 33905, 33902, 33933, 33932, + 33903, 41412, 41412, 41412, 33898, 33923, 33896, 33921, 33946, 33936, + 33895, 33920, 33897, 33922, 33943, 33944, 33937, 33890, 33915, 33892, + 33917, 33927, 33934, 33891, 33916, 33893, 33918, 33930, 41412, 33935, + 33899, 33924, 33894, 33919, 33925, 33900, 33942, 33940, 41412, 33929, + 41412, 41412, 33941, 33945, 33928, 33931, 33939, 33926, 33938, 41412, + 41412, 41412, 33957, 41412, 41412, 41412, 41412, 33977, 33969, 33964, + 33970, 33965, 33971, 41412, 33966, 41412, 33967, 33972, 33963, 33976, + 33973, 33974, 33975, 33968, 41412, 41412, 41412, 41412, 41412, 41412, + 33953, 33955, 33952, 33951, 33948, 33947, 33950, 33949, 33956, 33954, + 41412, 41412, 33961, 33962, 33978, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 37313, 37310, 37308, + 37307, 37309, 37311, 37327, 37296, 37298, 37297, 37356, 37299, 37368, + 37300, 37365, 37361, 37358, 37359, 37329, 37301, 37364, 37363, 37360, + 37362, 37330, 37295, 37336, 37333, 37302, 37334, 37303, 37335, 37325, + 37369, 37337, 37338, 37315, 37317, 37366, 37354, 37353, 37355, 37306, + 37314, 37370, 37305, 37331, 37339, 37319, 37342, 37344, 37349, 37350, + 37346, 37347, 37345, 37348, 37332, 41412, 41412, 41412, 41412, 37371, + 37351, 37343, 37352, 37341, 37340, 37316, 37324, 37323, 37322, 37320, + 37321, 37318, 37357, 37328, 37367, 37304, 37378, 37380, 37377, 37376, + 37373, 37372, 37375, 37374, 37381, 37379, 37326, 37312, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 22743, 22741, 41412, 22742, 41412, + 22756, 22771, 22775, 22755, 22765, 41412, 22757, 22772, 22753, 22751, + 22750, 22748, 22747, 22752, 22776, 22768, 22766, 22767, 22749, 22773, + 22774, 22761, 22759, 22738, 22760, 22737, 22754, 22777, 22780, 22745, + 41412, 22746, 41412, 22779, 22762, 22763, 22764, 22769, 22758, 22781, + 22770, 22807, 22789, 22794, 22790, 22792, 22802, 22803, 22796, 22797, + 22798, 22799, 22784, 22795, 22783, 22782, 41412, 41412, 22800, 22801, + 22804, 22793, 22791, 41412, 22805, 41412, 22788, 22785, 22786, 22787, + 22818, 22819, 22806, 41412, 22814, 22816, 22813, 22812, 22809, 22808, + 22811, 22810, 22817, 22815, 41412, 41412, 22734, 22733, 22740, 22739, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 37605, 37512, 37510, 37511, 37520, 37508, 37505, 37509, + 37529, 37500, 37498, 37521, 37536, 37530, 37526, 37533, 37525, 37528, + 37527, 37504, 37513, 37496, 37495, 37423, 37424, 37422, 37544, 37545, + 37546, 37548, 37549, 37547, 37445, 37447, 37444, 37443, 37440, 37439, + 37442, 37441, 37448, 37446, 37437, 37434, 37433, 37430, 37429, 37432, + 37431, 37438, 37436, 37435, 37501, 37523, 37503, 37522, 37506, 37532, + 37514, 37515, 37516, 37517, 37555, 37541, 37454, 37452, 37482, 37481, + 37464, 37480, 37479, 37489, 41412, 37466, 37474, 37473, 37459, 37458, + 37465, 37476, 37475, 37463, 37462, 37467, 37484, 37483, 37478, 37477, + 37491, 37472, 37471, 37461, 37460, 37492, 37485, 37486, 37487, 37493, + 37456, 37490, 37468, 37469, 37470, 37488, 37494, 37451, 37457, 37453, + 37455, 41412, 41412, 41412, 41412, 37629, 37625, 37626, 37617, 37618, + 37619, 37620, 37621, 37622, 37627, 37628, 37623, 37624, 37552, 37553, + 37615, 37616, 37543, 37557, 37518, 37535, 37539, 37554, 37540, 37542, + 37537, 37538, 37556, 37604, 37603, 37602, 37569, 37568, 37588, 37587, + 37570, 37586, 37585, 37595, 41412, 37572, 37580, 37579, 37562, 37561, + 37571, 37582, 37581, 37566, 37565, 37573, 37590, 37589, 37584, 37583, + 37597, 37578, 37577, 37564, 37563, 37599, 37591, 37592, 37593, 37600, + 37598, 37596, 37574, 37575, 37576, 37594, 37601, 37567, 37559, 37560, + 37558, 41412, 37449, 37450, 37426, 37427, 37428, 37425, 37606, 37613, + 37611, 37614, 37612, 37607, 37610, 37609, 37608, 41412, 37551, 37550, + 37499, 37502, 37524, 37519, 37507, 32208, 24349, 32209, 24350, 37534, + 37531, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 28762, 28741, + 28740, 28739, 28771, 28839, 28838, 28841, 28840, 28772, 28769, 28817, + 28816, 28823, 28822, 28770, 28801, 28818, 28825, 28824, 28773, 28843, + 28842, 28837, 28836, 28768, 28845, 28775, 28835, 28821, 28800, 28844, + 28834, 28731, 28795, 28832, 28833, 28826, 28827, 28734, 28767, 28846, + 28733, 28938, 28922, 28945, 28946, 28939, 28940, 28934, 28919, 28927, + 28928, 28935, 28863, 28882, 28887, 28886, 28862, 28726, 28724, 28725, + 28723, 28738, 28963, 28965, 28962, 28961, 28958, 28957, 28960, 28959, + 28966, 28964, 28885, 28874, 28892, 28896, 28891, 28895, 28776, 28799, + 28828, 28829, 28830, 28831, 28941, 28942, 28943, 28944, 28766, 28765, + 28763, 28764, 28729, 28728, 28727, 28798, 28933, 28907, 28908, 28820, + 28819, 28936, 28937, 28877, 28878, 28879, 28880, 28881, 28737, 28736, + 28735, 28923, 28925, 28926, 28924, 28790, 28789, 28788, 28786, 28794, + 28778, 28791, 28779, 28781, 28792, 28784, 28782, 28793, 28730, 28932, + 28929, 28930, 28931, 28869, 28870, 28871, 28872, 28867, 28868, 28866, + 28774, 28883, 28858, 28860, 28857, 28856, 28853, 28852, 28855, 28854, + 28861, 28859, 28864, 28865, 28920, 28921, 28894, 28893, 17885, 17911, + 17896, 17917, 17918, 17916, 17906, 17907, 17919, 17900, 17909, 17912, + 17914, 17920, 17902, 17905, 17910, 17904, 17908, 17921, 17901, 17899, + 17895, 17915, 17903, 17891, 17894, 17898, 17893, 17892, 17913, 17897, + 17886, 17890, 17888, 17923, 17887, 17889, 41412, 17922, 41412, 41412, + 41412, 41412, 41412, 17884, 41412, 41412, 17968, 17999, 17976, 18005, + 17974, 18004, 17997, 17994, 18006, 17986, 17988, 18000, 18002, 18007, + 17990, 17996, 17998, 17992, 17995, 17965, 17989, 17985, 17975, 18003, + 17991, 17969, 17972, 17984, 17971, 17970, 18001, 17983, 17979, 17982, + 17980, 18009, 17977, 17981, 18010, 18008, 17973, 17993, 17967, 18057, + 27975, 17966, 17978, 17987, 19305, 19379, 19313, 19384, 19377, 19341, + 19308, 19323, 19381, 19355, 19373, 19287, 19285, 19371, 19272, 19307, + 19391, 19320, 19394, 19315, 19380, 19317, 19316, 19388, 19351, 19375, + 19354, 19300, 19310, 19304, 19333, 19338, 19337, 19324, 19328, 19326, + 19329, 19330, 19327, 19335, 19334, 19336, 19331, 19302, 19303, 19362, + 19368, 19367, 19360, 19365, 19356, 19357, 19359, 19370, 19364, 19363, + 19361, 19366, 19358, 19369, 19277, 19276, 19282, 19281, 19340, 19297, + 19296, 19294, 19289, 19299, 19290, 19383, 19293, 19292, 19295, 19288, + 19392, 19286, 19279, 19275, 19284, 19280, 19273, 19274, 19278, 19283, + 19321, 19301, 19382, 19393, 19306, 19319, 19314, 19318, 19385, 19396, + 19634, 19540, 19550, 19598, 19602, 19552, 19551, 19604, 19603, 19579, + 19631, 19632, 19589, 19610, 19590, 19630, 19629, 19633, 19619, 19556, + 19608, 19563, 19548, 19549, 19600, 19599, 19554, 19555, 19553, 19606, + 19607, 19587, 19586, 19582, 19580, 19588, 19611, 19612, 19613, 19618, + 19617, 19595, 19596, 19594, 19591, 19597, 19624, 19623, 19622, 19621, + 19620, 19628, 19626, 19562, 19559, 19609, 19564, 19566, 19573, 19577, + 19575, 19565, 19541, 19543, 19546, 19545, 19578, 19547, 19601, 19605, + 19584, 19585, 19416, 19517, 19419, 19439, 19442, 19446, 19521, 19467, + 19468, 19473, 19477, 19486, 19489, 19482, 19494, 19426, 19456, 19459, + 19495, 19512, 19408, 19399, 19402, 19425, 19530, 19452, 19403, 19418, + 19420, 19445, 19444, 19448, 19447, 19443, 19528, 19522, 19470, 19493, + 19487, 19488, 19507, 19474, 19476, 19481, 19480, 19471, 19485, 19483, + 19472, 19490, 19436, 19433, 19427, 19432, 19431, 19429, 19434, 19438, + 19415, 19457, 19461, 19466, 19414, 19497, 19505, 19498, 19501, 19449, + 19410, 19411, 19520, 19409, 19531, 19535, 19538, 19454, 19413, 19406, + 19404, 19405, 19407, 19539, 19422, 19423, 19421, 19417, 19424, 19518, + 17155, 17162, 17161, 17156, 17160, 17159, 17157, 17158, 17382, 17390, + 17389, 17383, 17387, 17386, 17384, 17388, 17148, 17154, 17152, 17149, + 17151, 17150, 17153, 17139, 17199, 17207, 17206, 17200, 17204, 17203, + 17201, 17197, 17311, 17318, 17316, 17312, 17314, 17313, 17317, 17315, + 17286, 17295, 17294, 17287, 17291, 17290, 17288, 17292, 17326, 17332, + 17331, 17327, 17301, 17296, 17328, 17330, 17302, 17310, 17309, 17303, + 17307, 17306, 17304, 17308, 17278, 17285, 17284, 17279, 17283, 17282, + 17280, 17281, 17266, 41412, 17270, 17267, 17269, 17268, 41412, 41412, + 17259, 17265, 17263, 17260, 17262, 17261, 17264, 41412, 17254, 41412, + 17258, 17255, 17257, 17256, 41412, 41412, 16989, 16996, 16995, 16990, + 16994, 16993, 16991, 16980, 17451, 17458, 17456, 17452, 17454, 17453, + 17457, 17455, 17364, 17372, 17371, 17365, 17369, 17368, 17366, 17370, + 17027, 17035, 17034, 17028, 17032, 17031, 17029, 17033, 17419, 17426, + 17425, 17420, 17424, 17423, 17421, 17422, 17407, 41412, 17411, 17408, + 17410, 17409, 41412, 41412, 17217, 17225, 17224, 17218, 17222, 17221, + 17219, 17223, 17208, 17216, 17215, 17209, 17213, 17212, 17210, 17214, + 17109, 17117, 17116, 17110, 17114, 17113, 17111, 17115, 17187, 17194, + 17193, 17188, 17192, 17191, 17189, 17190, 17175, 41412, 17179, 17176, + 17178, 17177, 41412, 41412, 17168, 17174, 17172, 17169, 17171, 17170, + 17173, 41412, 17163, 41412, 17167, 17164, 17166, 17165, 41412, 41412, + 17391, 17398, 17397, 17392, 17396, 17395, 17393, 17394, 17227, 17233, + 17231, 17228, 17230, 17229, 17232, 41412, 17442, 17450, 17449, 17443, + 17447, 17446, 17444, 17448, 17427, 17434, 17432, 17428, 17430, 17429, + 17433, 17431, 17399, 17406, 17405, 17400, 17404, 17403, 17401, 17402, + 17057, 17065, 17064, 17058, 17062, 17061, 17059, 17063, 17042, 17050, + 17049, 17043, 17047, 17046, 17044, 17048, 17373, 17381, 17380, 17374, + 17378, 17377, 17375, 17379, 17130, 17078, 17136, 17131, 17135, 17134, + 17132, 17133, 17118, 41412, 17122, 17119, 17121, 17120, 41412, 41412, + 17102, 17108, 17106, 17103, 17105, 17104, 17107, 17098, 17333, 17341, + 17340, 17334, 17338, 17337, 17335, 17339, 17018, 17026, 17025, 17019, + 17023, 17022, 17020, 17024, 17226, 17241, 17240, 17234, 17238, 17237, + 17235, 17239, 17356, 17363, 17361, 17357, 17359, 17358, 17362, 17360, + 17348, 17355, 17354, 17349, 17353, 17352, 17350, 17351, 17070, 17077, + 17075, 17071, 17073, 17072, 17076, 17068, 17246, 17253, 17252, 17247, + 17251, 17250, 17248, 17244, 17293, 17205, 17074, 41412, 41412, 16958, + 16960, 16959, 16977, 17480, 17478, 16961, 16976, 16962, 16975, 17479, + 16974, 17476, 17474, 17473, 17470, 17469, 17472, 17471, 17477, 17475, + 16963, 16966, 16965, 16970, 16969, 16973, 16972, 16968, 16971, 16967, + 16964, 41412, 41412, 41412, 17299, 17198, 17196, 17195, 17297, 16981, + 16979, 16978, 17298, 17069, 17067, 17066, 17300, 17245, 17243, 17242, + 17468, 17459, 17465, 17466, 17461, 17463, 17467, 17462, 17460, 17464, + 41412, 41412, 41412, 41412, 41412, 41412, 6484, 6485, 6486, 6487, 6488, + 6489, 6447, 6483, 6448, 6449, 6450, 6451, 6452, 6412, 6413, 6414, 6415, + 6416, 6417, 6453, 6454, 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, + 6463, 6418, 6411, 6419, 6420, 6421, 6422, 6423, 6424, 6465, 6466, 6467, + 6468, 6469, 6470, 6426, 6425, 6427, 6428, 6429, 6430, 6431, 6405, 6444, + 6406, 6445, 6407, 6446, 6408, 6409, 6410, 6404, 6432, 6433, 6434, 6435, + 6436, 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6471, 6472, 6473, 6474, + 6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6464, 41412, 41412, 6564, + 6565, 6566, 6567, 6568, 6550, 41412, 41412, 5626, 5598, 5371, 5628, 5629, + 5778, 5792, 6075, 5582, 5442, 5369, 5370, 5952, 6042, 6062, 6040, 6063, + 6041, 6044, 6038, 6045, 6039, 5707, 6059, 6036, 6060, 6037, 5708, 5373, + 6076, 6094, 5615, 5614, 5616, 5617, 5609, 5610, 5607, 5606, 5619, 5613, + 5618, 5608, 5600, 5630, 5791, 5377, 5812, 5805, 5810, 5811, 5807, 5808, + 6066, 5440, 5441, 5803, 5804, 5802, 5981, 5800, 5979, 5801, 5980, 5795, + 5977, 5796, 5978, 5798, 5975, 5799, 5976, 6065, 5794, 5974, 5433, 5951, + 5934, 5949, 5950, 5947, 5948, 6073, 5404, 5417, 5932, 5933, 5942, 6034, + 5940, 6032, 5941, 6033, 5938, 6030, 5939, 6031, 5936, 6028, 5937, 6029, + 5713, 5894, 5929, 5930, 5931, 5928, 5649, 5643, 5647, 5648, 5645, 5646, + 6068, 5641, 5642, 5640, 6026, 5638, 6024, 5639, 6025, 5636, 6022, 5637, + 6023, 5633, 6020, 5634, 6021, 5710, 5631, 5632, 5874, 5875, 5876, 5873, + 5597, 5584, 5595, 5596, 5593, 5594, 6067, 5401, 5583, 5591, 6019, 5589, + 6017, 5590, 6018, 5587, 6015, 5588, 6016, 5585, 6013, 5586, 6014, 5709, + 5400, 5850, 5675, 5683, 5692, 5693, 5678, 5679, 6070, 5681, 5682, 5691, + 5973, 5689, 5971, 5690, 5972, 5687, 5969, 5688, 5970, 5685, 5967, 5686, + 5968, 5711, 5674, 5966, 5694, 5375, 5851, 5767, 5728, 5765, 5766, 5755, + 5756, 6071, 5699, 5727, 5764, 5992, 5758, 5990, 5759, 5991, 5712, 5695, + 5473, 5768, 5673, 5660, 5671, 5672, 5669, 5670, 6069, 5658, 5659, 5668, + 5960, 5666, 5958, 5667, 5959, 5664, 5956, 5665, 5957, 5662, 5954, 5663, + 5955, 5650, 5953, 5676, 5893, 5853, 5891, 5892, 5872, 5877, 6072, 5833, + 5852, 5886, 6012, 5884, 6010, 5885, 6011, 5882, 6008, 5883, 6009, 5880, + 6006, 5881, 6007, 5705, 5832, 5376, 5879, 5396, 5680, 5703, 5706, 5701, + 5702, 5704, 5700, 5871, 5869, 5870, 5863, 5864, 5866, 5867, 5862, 6005, + 5860, 6003, 5861, 6004, 5855, 6001, 5856, 6002, 5858, 5999, 5859, 6000, + 5854, 6093, 6079, 6091, 6092, 6081, 6082, 6074, 6077, 6078, 6090, 5989, + 6088, 5987, 6089, 5988, 6086, 5985, 6087, 5986, 6084, 5983, 6085, 5984, + 5714, 6064, 5397, 5982, 5849, 5831, 5815, 5965, 5825, 5829, 5830, 5827, + 5828, 5963, 5823, 5824, 5961, 5817, 5994, 5813, 5993, 5677, 5625, 5604, + 5605, 5620, 5622, 5623, 5602, 5603, 5624, 6035, 5601, 5913, 5698, 5911, + 5696, 5912, 5697, 5909, 5910, 5907, 5908, 5905, 6027, 5895, 5926, 5927, + 5923, 5921, 5920, 5944, 5945, 5946, 5943, 5753, 5751, 5752, 5749, 5750, + 5747, 5748, 5746, 5754, 5627, 5772, 5776, 5777, 5774, 5775, 5770, 5771, + 5769, 5918, 5919, 5914, 5917, 5996, 5997, 5998, 5995, 5733, 5737, 5738, + 5735, 5736, 5731, 5732, 5730, 5739, 5847, 5848, 5843, 5846, 6055, 6056, + 6057, 6054, 6046, 5656, 5657, 5654, 5655, 5652, 5653, 5651, 5903, 5901, + 5902, 5899, 5900, 5897, 5898, 5896, 5374, 5393, 5394, 5395, 5392, 5381, + 5382, 5383, 5380, 5389, 5390, 5391, 5388, 5385, 5386, 5387, 5384, 5838, + 5839, 5835, 5837, 5423, 5422, 5418, 5419, 5421, 5420, 5569, 5568, 5564, + 5565, 5567, 5566, 5575, 5574, 5570, 5571, 5573, 5572, 5439, 5438, 5434, + 5435, 5437, 5436, 5533, 5532, 5528, 5529, 5531, 5530, 5527, 5526, 5522, + 5523, 5525, 5524, 5496, 5495, 5491, 5492, 5494, 5493, 5490, 5432, 5431, + 5428, 5429, 5430, 5426, 5469, 5468, 5464, 5465, 5467, 5466, 5463, 5462, + 5458, 5459, 5461, 5460, 5457, 5476, 5475, 5470, 5471, 5474, 5472, 5563, + 5562, 5558, 5559, 5561, 5560, 5581, 5580, 5576, 5577, 5579, 5578, 5456, + 5840, 5455, 5450, 5451, 5454, 5842, 5453, 5449, 5448, 5444, 5445, 5447, + 5446, 5551, 5550, 5546, 5547, 5549, 5548, 5410, 5409, 5405, 5406, 5408, + 5407, 5545, 5544, 5540, 5541, 5543, 5542, 5509, 5508, 5504, 5505, 5507, + 5506, 5515, 5514, 5510, 5511, 5513, 5512, 5503, 5502, 5498, 5499, 5501, + 5500, 5497, 5443, 5416, 5415, 5411, 5412, 5414, 5413, 5489, 5488, 5484, + 5485, 5487, 5486, 5483, 5482, 5478, 5479, 5481, 5480, 5477, 5539, 5538, + 5534, 5535, 5537, 5536, 5557, 5556, 5552, 5553, 5555, 5554, 5521, 5520, + 5516, 5517, 5519, 5518, 5592, 5621, 5773, 5734, 5744, 5745, 5742, 5743, + 5740, 5741, 6053, 6051, 6052, 6049, 6050, 6047, 6048, 6058, 5379, 30157, + 30132, 30143, 30139, 30149, 30146, 30152, 30155, 30156, 30135, 30134, + 30154, 30140, 30145, 30150, 30144, 30131, 30147, 30153, 30137, 30141, + 30136, 30148, 30151, 30142, 30138, 30133, 30129, 30130, 41412, 41412, + 41412, 32482, 32538, 32532, 32536, 32535, 32530, 32528, 32475, 32460, + 32506, 32459, 32458, 32503, 32518, 32505, 32509, 32510, 32512, 32498, + 32464, 32497, 32483, 32476, 32484, 32486, 32531, 32488, 32487, 32501, + 32515, 32527, 32517, 32469, 32491, 32472, 32495, 32485, 32500, 32521, + 32492, 32534, 32461, 32524, 32523, 32519, 32462, 32540, 32529, 32520, + 32467, 32526, 32514, 32470, 32508, 32473, 32533, 32502, 32516, 32499, + 32468, 32490, 32489, 32471, 32507, 32474, 32494, 32466, 32465, 32463, + 32525, 32504, 32522, 32493, 32537, 32539, 32541, 32542, 32457, 32543, + 32544, 32456, 32496, 32513, 32511, 32480, 32479, 32481, 32478, 32477, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 35250, 35267, 35268, + 35258, 35256, 35252, 35264, 35255, 35253, 35261, 35254, 35260, 35266, + 35262, 35259, 35265, 35263, 35257, 35271, 35272, 35270, 35269, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 35251, 19806, + 19807, 19808, 19797, 19795, 19791, 19803, 19794, 19792, 19800, 19793, + 19799, 19805, 19801, 19798, 19804, 19802, 19796, 19810, 19811, 19809, + 31612, 31613, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 5092, 5093, 5094, 5083, 5081, 5077, 5089, 5080, 5078, 5086, 5079, + 5085, 5091, 5087, 5084, 5090, 5088, 5082, 5095, 5096, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 35286, 35287, 35288, 35278, 35277, 35273, 35283, 35276, 35274, 35281, + 35275, 35280, 35285, 41412, 35279, 35284, 35282, 41412, 35289, 35290, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 22394, 22392, 22395, 22393, 22396, 22390, 22388, 22391, + 22389, 22398, 22412, 22408, 22413, 22409, 22397, 22410, 22406, 22411, + 22407, 22399, 22420, 22400, 22402, 22401, 22416, 22419, 22417, 22415, + 22418, 22404, 22403, 22405, 22421, 22414, 22422, 22369, 22367, 22377, + 22378, 22373, 22376, 22374, 22375, 22386, 22387, 22384, 22385, 22379, + 22368, 22372, 22371, 22370, 22489, 22488, 22490, 22495, 22497, 22501, + 22503, 22505, 22507, 22506, 22498, 22502, 22496, 22508, 22492, 22493, + 22500, 22494, 22443, 22437, 22442, 22444, 22438, 22428, 22436, 22439, + 22433, 22425, 22426, 22445, 22432, 22427, 22434, 22429, 22431, 22440, + 22430, 22441, 22435, 22366, 22423, 22424, 41412, 41412, 22515, 22517, + 22514, 22513, 22510, 22509, 22512, 22511, 22518, 22516, 41412, 41412, + 41412, 41412, 41412, 41412, 22467, 22466, 22463, 22465, 22464, 22458, + 22461, 22462, 22460, 22459, 41412, 41412, 41412, 41412, 41412, 41412, + 28342, 28354, 28350, 28199, 28349, 28200, 28347, 28338, 28351, 28352, + 28353, 28198, 28197, 28196, 28348, 28195, 28191, 28193, 28190, 28189, + 28186, 28185, 28188, 28187, 28194, 28192, 41412, 41412, 41412, 41412, + 41412, 41412, 28203, 28317, 28334, 28319, 28321, 28320, 28322, 28318, + 28328, 28231, 28323, 28329, 28330, 28326, 28235, 28316, 28278, 28277, + 28308, 28324, 28232, 28327, 28333, 28331, 28332, 28325, 28314, 28313, + 28307, 28311, 28312, 28310, 28315, 28309, 28234, 28287, 28305, 28306, + 28294, 28296, 28295, 28297, 28281, 28298, 28301, 28302, 28288, 28300, + 28291, 28283, 28292, 28285, 28290, 28304, 28303, 28299, 28289, 28293, + 28284, 28286, 28282, 28276, 28261, 28262, 28270, 28269, 28266, 28274, + 28255, 28257, 28275, 28264, 28260, 28271, 28273, 28272, 28256, 28258, + 28259, 28268, 28265, 28263, 28267, 28254, 28252, 28253, 28251, 28250, + 28233, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 28205, 28207, + 28209, 28216, 28215, 28223, 28219, 28204, 28214, 28230, 28217, 28229, + 28221, 28220, 28211, 28218, 28222, 28208, 28225, 28224, 28228, 28226, + 28227, 28206, 28280, 28279, 28243, 28248, 28239, 28244, 28240, 28236, + 28241, 28237, 28249, 28238, 28246, 28247, 28213, 28212, 28242, 28210, + 28245, 41412, 41412, 41412, 41412, 41412, 5793, 5378, 5372, 6061, 5809, + 5806, 5797, 5935, 5644, 5635, 5684, 5757, 5729, 5661, 5878, 5834, 5865, + 5868, 5857, 6083, 6080, 5826, 5762, 5782, 5763, 5783, 5760, 5780, 5761, + 5781, 5822, 5820, 5821, 5818, 5819, 5816, 5789, 5790, 5787, 5786, 5788, + 5779, 5784, 5785, 5599, 6043, 5612, 5611, 5814, 5964, 5962, 5906, 5904, + 5925, 5924, 5922, 5916, 5915, 5845, 5844, 5836, 5425, 5402, 5427, 5424, + 5841, 5452, 5398, 5399, 5403, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 24647, 24614, 24613, 24594, 24593, 24600, + 24608, 24607, 24612, 24611, 24599, 24597, 24595, 24610, 24609, 24601, + 24616, 24615, 24606, 24605, 24619, 24598, 24620, 24618, 24621, 24602, + 24603, 24604, 24617, 24592, 24596, 41412, 24638, 24645, 24646, 24644, + 24639, 24642, 24640, 24643, 24641, 24637, 24635, 24636, 41412, 41412, + 41412, 41412, 24629, 24626, 24628, 24634, 24627, 24632, 24631, 24633, + 24630, 24623, 24622, 24624, 41412, 41412, 41412, 41412, 24625, 41412, + 41412, 41412, 24648, 24649, 24656, 24658, 24655, 24654, 24651, 24650, + 24653, 24652, 24659, 24657, 35311, 35323, 35306, 35303, 35321, 35324, + 35305, 35304, 35318, 35313, 35312, 35319, 35316, 35322, 35317, 35320, + 35310, 35302, 35307, 35291, 35325, 35295, 35296, 35314, 35309, 35308, + 35315, 35294, 35292, 35293, 41412, 41412, 35297, 35298, 35299, 35300, + 35301, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 29300, 29322, 29282, 29284, 29287, 29304, 29306, 29309, + 29290, 29286, 29302, 29312, 29308, 29324, 29291, 29289, 29288, 29313, + 29311, 29310, 29293, 29292, 29299, 29315, 29314, 29321, 29296, 29301, + 29298, 29318, 29323, 29320, 29297, 29295, 29294, 29319, 29317, 29316, + 29281, 29283, 29303, 29305, 29285, 29307, 41412, 41412, 41412, 41412, + 29345, 29330, 29334, 29340, 29343, 29346, 29332, 29336, 29337, 29341, + 29333, 29331, 29344, 29339, 29338, 29342, 29335, 29280, 29275, 29274, + 29279, 29278, 29277, 29276, 29327, 29328, 41412, 41412, 41412, 41412, + 41412, 41412, 29353, 29355, 29352, 29351, 29348, 29347, 29350, 29349, + 29356, 29354, 29329, 41412, 41412, 41412, 29325, 29326, 22468, 22487, + 22480, 22483, 22485, 22478, 22476, 22474, 22470, 22472, 22457, 22455, + 22447, 22451, 22453, 22449, 22481, 22486, 22479, 22482, 22484, 22477, + 22475, 22473, 22469, 22471, 22456, 22454, 22446, 22450, 22452, 22448, + 5061, 5058, 5050, 5049, 5063, 5055, 5048, 5047, 5066, 5057, 5054, 5053, + 5056, 5060, 5052, 5051, 5068, 5064, 5062, 5067, 5065, 5069, 5059, 5072, + 5074, 5071, 5073, 5070, 41412, 41412, 5076, 5075, 35359, 35357, 35358, + 35375, 35374, 35373, 35399, 35365, 35364, 35378, 35385, 35377, 35400, + 35393, 35360, 35405, 35376, 35392, 35369, 35368, 35382, 35381, 35401, + 35404, 35367, 35366, 35370, 35380, 35383, 35379, 35406, 35386, 35372, + 35391, 35394, 35387, 35389, 35407, 35361, 35362, 35363, 35371, 35390, + 35408, 35384, 35397, 35398, 35395, 35396, 35403, 35402, 35388, 35356, + 35331, 35330, 35328, 35419, 35326, 35327, 35329, 35332, 35333, 35334, + 41412, 35427, 35434, 35438, 35435, 35444, 35450, 35451, 35449, 35448, + 35446, 35447, 35439, 35440, 35443, 35452, 35436, 35442, 35437, 35445, + 35441, 35418, 35431, 35432, 35411, 35412, 35413, 35422, 35421, 35414, + 41412, 41412, 35335, 35342, 35344, 35341, 35340, 35337, 35336, 35339, + 35338, 35345, 35343, 41412, 41412, 41412, 41412, 41412, 41412, 35352, + 35354, 35351, 35350, 35347, 35346, 35349, 35348, 35355, 35353, 41412, + 41412, 41412, 41412, 41412, 41412, 35428, 35429, 35426, 35417, 35410, + 35430, 35423, 35420, 35415, 35416, 35424, 35425, 35409, 35433, 41412, + 41412, 8313, 8277, 8402, 8316, 8561, 8580, 8579, 8509, 8297, 8483, 8548, + 8515, 8301, 8514, 8513, 8450, 8444, 8468, 8531, 8469, 8532, 8545, 8502, + 8401, 8518, 8300, 8299, 8559, 8428, 8429, 8430, 8293, 8572, 8382, 8574, + 8165, 8576, 8495, 8573, 8575, 8497, 8544, 8328, 8315, 8276, 8283, 41412, + 41412, 8474, 8534, 8501, 8399, 8547, 8552, 8286, 8287, 8325, 8461, 8566, + 8303, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 2762, 2761, 2763, 2760, 2764, 2671, 2672, 2688, 2689, 2692, 2693, + 2710, 2711, 2701, 2702, 2685, 2675, 2690, 2691, 2696, 2698, 2686, 2687, + 2705, 2678, 2679, 2694, 2695, 2706, 2717, 2716, 2682, 2681, 2704, 2715, + 2718, 2680, 2683, 2703, 2707, 2708, 2676, 2677, 2723, 2725, 2709, 2700, + 2724, 2713, 2714, 2712, 2722, 2765, 2776, 2779, 2780, 2770, 2771, 2768, + 2769, 2766, 2767, 2772, 2773, 2775, 2774, 2777, 2778, 2781, 2697, 2699, + 2719, 2684, 2720, 2721, 2673, 2674, 41412, 2670, 2669, 2789, 2791, 2788, + 2787, 2784, 2783, 2786, 2785, 2792, 2790, 2757, 2754, 2782, 2667, 2668, + 2666, 2756, 2743, 2741, 2744, 2735, 2736, 2742, 2738, 2740, 2739, 2737, + 2733, 2732, 2728, 2726, 2730, 2729, 2727, 2731, 2734, 2753, 2752, 2751, + 2750, 2745, 2747, 2748, 2749, 2746, 2758, 2755, 2759, 34858, 34856, + 34857, 34809, 34844, 34846, 34811, 34845, 34821, 34822, 34829, 34837, + 34832, 34823, 34830, 34834, 34843, 34824, 34838, 34831, 34825, 34836, + 34814, 34839, 34827, 34835, 34842, 34818, 34816, 34840, 34820, 34841, + 34833, 34804, 34805, 34806, 34864, 34863, 34865, 34862, 34860, 34861, + 34855, 34859, 34807, 34808, 34828, 34819, 34872, 34874, 34871, 34870, + 34867, 34866, 34869, 34868, 34875, 34873, 34803, 34817, 34815, 34826, + 34812, 34813, 3557, 3543, 3551, 3535, 3523, 3547, 3546, 3532, 3538, 3531, + 3524, 3555, 3541, 3533, 3550, 3534, 3552, 3549, 3554, 3539, 3522, 3537, + 3544, 3527, 3545, 3540, 3525, 3556, 3542, 3529, 3553, 3536, 3530, 3548, + 3528, 3526, 3558, 3559, 3566, 3572, 3569, 3573, 3574, 3570, 3575, 3571, + 3567, 3568, 3520, 3521, 3560, 3561, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 3565, 3563, 3564, 3562, 24476, 24475, 24474, 24488, + 24487, 24493, 24503, 24502, 24506, 24494, 24501, 24500, 24482, 24495, + 24479, 24478, 24477, 24486, 24485, 24484, 24483, 24492, 24491, 24497, + 24496, 24481, 24511, 24508, 24507, 24490, 24489, 24509, 24505, 24504, + 24510, 24512, 24521, 24520, 24526, 24528, 24524, 24525, 24522, 24523, + 24527, 24465, 24470, 24469, 24467, 24471, 24472, 24473, 24468, 24466, + 24519, 24518, 41412, 41412, 41412, 24513, 24516, 24517, 24515, 24514, + 24535, 24537, 24534, 24533, 24530, 24529, 24532, 24531, 24538, 24536, + 41412, 41412, 41412, 24499, 24498, 24480, 30203, 30205, 30202, 30201, + 30198, 30197, 30200, 30199, 30206, 30204, 30176, 30167, 30165, 30164, + 30166, 30177, 30161, 30160, 30162, 30163, 30179, 30175, 30173, 30172, + 30174, 30181, 30187, 30188, 30186, 30189, 30178, 30171, 30168, 30170, + 30169, 30180, 30182, 30183, 30185, 30184, 30191, 30192, 30190, 30196, + 30195, 30207, 30194, 30193, 10562, 10539, 10545, 10602, 10583, 10591, + 10581, 10582, 10601, 10267, 10593, 41412, 41412, 41412, 41412, 41412, + 18013, 18044, 18021, 18050, 18019, 18049, 18042, 18039, 18051, 18031, + 18033, 18045, 18047, 18052, 18035, 18041, 18043, 18037, 18040, 18053, + 18034, 18030, 18020, 18048, 18036, 18014, 18017, 18029, 18016, 18015, + 18046, 18028, 18024, 18027, 18025, 18055, 18022, 18026, 18056, 18054, + 18018, 18038, 18012, 41412, 41412, 18011, 18023, 18032, 34854, 34852, + 34853, 34851, 34850, 34849, 34848, 34847, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 39257, 39270, 39259, 39237, 39251, 39265, + 39266, 39267, 39252, 39268, 39255, 39263, 39258, 39256, 39264, 39262, + 39261, 39269, 39250, 39248, 39239, 39246, 39238, 39249, 39247, 39228, + 39229, 39231, 39232, 39244, 39242, 39243, 39241, 39230, 39234, 39240, + 39253, 39236, 39245, 39233, 39260, 39254, 39235, 41412, 41412, 41412, + 41412, 41412, 23439, 23440, 24047, 23436, 23441, 23442, 23413, 23412, + 24032, 24025, 23445, 23446, 23419, 23447, 23425, 23420, 23421, 23982, + 23983, 23984, 24027, 23423, 24019, 23538, 23449, 23426, 23434, 23429, + 23452, 23987, 23986, 23985, 23453, 23454, 23456, 23414, 23466, 23400, + 18557, 18560, 18556, 18559, 18555, 10432, 27880, 27881, 27871, 27872, + 27883, 27884, 27874, 27886, 27876, 27887, 27888, 27889, 27890, 27891, + 27892, 27875, 27878, 27879, 27893, 27873, 27896, 27897, 27899, 28030, + 28137, 28031, 28139, 28034, 28059, 28073, 28127, 28112, 28142, 28080, + 28150, 28161, 28090, 28077, 28110, 28113, 28134, 28036, 28114, 28129, + 28154, 28128, 28140, 28158, 28032, 28038, 28081, 28064, 28082, 28058, + 24188, 24196, 24198, 24199, 18766, 18762, 18765, 18764, 18763, 24108, + 23524, 23573, 23659, 23802, 23822, 23899, 23927, 23920, 23966, 24002, + 24170, 24054, 27948, 23730, 24012, 23468, 23737, 23895, 23469, 24107, + 23525, 23577, 23660, 23673, 23756, 23783, 23803, 23828, 23900, 23930, + 23967, 23646, 24115, 24142, 24171, 23487, 23513, 23576, 23636, 23888, + 23937, 23975, 23727, 23884, 23648, 24094, 23654, 28138, 28039, 28057, + 28075, 28121, 28078, 28065, 28126, 28149, 28092, 28093, 28040, 28042, + 28095, 28099, 28101, 28045, 28091, 28141, 28109, 28108, 28051, 28035, + 28115, 28125, 28074, 28130, 28156, 28157, 28053, 28160, 28151, 28070, + 28072, 28071, 28076, 28153, 8285, 8284, 8550, 8549, 8496, 8384, 8498, + 8167, 8383, 8166, 8442, 8179, 8499, 8294, 8511, 8539, 8403, 8567, 8568, + 8425, 8416, 8417, 8418, 8420, 8427, 8423, 8452, 8408, 8454, 8431, 8409, + 8410, 8456, 8411, 8412, 8441, 8445, 8433, 8460, 8415, 8447, 8448, 8446, + 8424, 8432, 8436, 8457, 8422, 8439, 8449, 8414, 8435, 8438, 8564, 8407, + 8406, 8279, 8577, 8282, 8273, 8292, 8176, 8465, 8522, 22921, 23485, + 22957, 23527, 22956, 23526, 22955, 23523, 22964, 23542, 22989, 23579, + 22988, 23578, 22987, 23574, 22983, 23568, 22984, 23569, 23017, 23622, + 23018, 23623, 23006, 23610, 23015, 23620, 22997, 23601, 23042, 23662, + 23050, 23672, 23069, 23692, 23068, 23691, 23066, 23689, 23063, 23686, + 23062, 23685, 23086, 23719, 23080, 23707, 23117, 23754, 23114, 23751, + 23118, 23755, 23125, 23768, 23126, 23769, 23136, 23778, 23132, 23765, + 23142, 23800, 23144, 23805, 23143, 23804, 23162, 23827, 23161, 23826, + 23156, 23819, 23152, 23814, 23193, 23863, 23192, 23862, 23170, 23855, + 23171, 23856, 23221, 23898, 23223, 23902, 23233, 23917, 23231, 23915, + 23232, 23916, 23238, 23922, 23259, 23960, 23257, 23958, 23256, 23951, + 23251, 23953, 23258, 23959, 23280, 24000, 23279, 23999, 23281, 24003, + 23275, 23993, 23311, 24075, 23332, 24098, 23304, 24068, 23331, 24097, + 23323, 24087, 23344, 24118, 23343, 24114, 23357, 24131, 23358, 24132, + 23354, 24128, 23356, 24130, 23355, 24129, 23363, 24137, 23362, 24136, + 23368, 24147, 23379, 24161, 23383, 24165, 23385, 24167, 23693, 23998, + 24133, 24157, 23486, 23793, 23792, 23794, 23269, 23583, 22915, 23479, + 22931, 23497, 22927, 23493, 22926, 23492, 22925, 23491, 22929, 23495, + 22928, 23494, 22910, 23474, 22909, 23473, 22908, 23472, 22912, 23476, + 22911, 23475, 23011, 23615, 23022, 23628, 23014, 23619, 23002, 23606, + 23001, 23605, 23000, 23604, 23005, 23609, 23004, 23608, 23087, 23720, + 23077, 23711, 23184, 23848, 23204, 23874, 23176, 23840, 23175, 23839, + 23174, 23838, 23178, 23842, 23177, 23841, 23201, 23871, 23200, 23870, + 23199, 23869, 23203, 23873, 23202, 23872, 23314, 24078, 23321, 24085, + 23318, 24082, 23317, 24081, 23316, 24080, 23320, 24084, 23319, 24083, + 23369, 24148, 23367, 24146, 23371, 24150, 23375, 24156, 23147, 23808, + 23148, 23809, 23372, 24151, 18604, 18596, 18609, 18601, 18605, 18597, + 18607, 18599, 18370, 18362, 18373, 18365, 18371, 18363, 18375, 18367, + 18627, 18624, 18629, 18626, 18628, 18625, 41412, 41412, 18410, 18407, + 18412, 18409, 18411, 18408, 41412, 41412, 18642, 18634, 18647, 18639, + 18643, 18635, 18645, 18637, 18394, 18386, 18397, 18389, 18395, 18387, + 18399, 18391, 18668, 18659, 18671, 18662, 18670, 18661, 18669, 18660, + 18422, 18417, 18425, 18420, 18424, 18419, 18423, 18418, 18729, 18726, + 18731, 18728, 18730, 18727, 41412, 41412, 18456, 18453, 18458, 18455, + 18457, 18454, 41412, 41412, 18688, 18679, 18691, 18682, 18690, 18681, + 18689, 18680, 41412, 18468, 41412, 18471, 41412, 18470, 41412, 18469, + 18709, 18701, 18714, 18706, 18710, 18702, 18712, 18704, 18440, 18432, + 18443, 18435, 18441, 18433, 18445, 18437, 18594, 18614, 18631, 18630, + 18654, 18652, 18674, 18675, 18733, 18732, 18694, 18695, 18721, 18719, + 41412, 41412, 18611, 18603, 18610, 18602, 18606, 18598, 18608, 18600, + 18377, 18369, 18374, 18366, 18372, 18364, 18376, 18368, 18649, 18641, + 18648, 18640, 18644, 18636, 18646, 18638, 18401, 18393, 18398, 18390, + 18396, 18388, 18400, 18392, 18716, 18708, 18715, 18707, 18711, 18703, + 18713, 18705, 18447, 18439, 18444, 18436, 18442, 18434, 18446, 18438, + 18593, 18618, 18595, 18616, 18615, 41412, 18612, 18613, 18379, 18383, + 18380, 18381, 18378, 18553, 18581, 18582, 18586, 18502, 18655, 18656, + 18653, 41412, 18650, 18651, 18414, 18413, 18404, 18403, 18402, 18585, + 18584, 18583, 18673, 18677, 18666, 18665, 41412, 41412, 18672, 18664, + 18426, 18430, 18427, 18428, 41412, 18510, 18509, 18508, 18693, 18697, + 18686, 18685, 18741, 18740, 18692, 18684, 18473, 18477, 18474, 18475, + 18463, 18504, 18503, 18780, 41412, 41412, 18722, 18723, 18720, 41412, + 18717, 18718, 18460, 18459, 18450, 18449, 18448, 18578, 18507, 41412, + 16898, 16895, 16900, 16897, 37416, 17650, 33984, 17575, 31904, 37389, + 19135, 41218, 41217, 41219, 24357, 32233, 20617, 29541, 17574, 16899, + 16896, 20561, 11383, 11357, 24280, 32163, 33859, 33857, 24233, 32128, + 11356, 11351, 10661, 11350, 5097, 38001, 30706, 38148, 20584, 20620, + 24665, 31245, 24356, 32232, 31778, 24355, 32231, 29142, 31481, 31482, + 31864, 11365, 38015, 32071, 32065, 32079, 6109, 33858, 33860, 32088, + 11387, 20959, 31059, 38199, 6395, 6110, 2572, 20619, 17654, 24288, 32174, + 11388, 31928, 17489, 37790, 32070, 3956, 3998, 25334, 32076, 8150, 38160, + 8583, 34967, 20977, 17614, 37396, 31924, 17643, 17600, 38149, 17644, + 11329, 38026, 39278, 27150, 39824, 17777, 20979, 20981, 20980, 41412, + 24354, 32230, 17593, 31777, 20873, 7, 20872, 6, 29137, 29539, 34938, + 34926, 41412, 41412, 34933, 34932, 34935, 34934, 34925, 34939, 34929, + 34931, 34924, 34928, 34930, 34927, 34768, 34770, 34767, 34766, 34763, + 34762, 34765, 34764, 34758, 34769, 34759, 34761, 34757, 34756, 34760, + 41412, 24185, 24186, 24194, 24200, 24184, 24187, 24190, 24191, 24192, + 24193, 24195, 24183, 24197, 41412, 41412, 41412, 17485, 8163, 8829, + 17661, 25273, 27765, 29070, 31505, 32553, 39828, 29273, 11323, 17486, + 22718, 38036, 11505, 18058, 31506, 18830, 2585, 20625, 6228, 25274, + 34320, 37161, 20863, 38118, 29591, 25839, 32422, 22902, 3862, 34300, + 32714, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 8472, 8530, 8487, 8543, 8172, 8188, + 8467, 8527, 8536, 8187, 8171, 8553, 8327, 8317, 8320, 8323, 8318, 8476, + 8319, 8321, 8322, 8519, 8308, 8173, 8560, 8578, 8478, 8484, 8535, 8477, + 8466, 8526, 8175, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 0, 100, 11399, 10685, + 6232, 6111, 5362, 17488, 32742, 10687, 32739, 32731, 4046, 11400, 31667, + 31668, 32732, 4047, 32733, 32740, 25511, 11401, 29635, 34216, 32735, + 11397, 11402, 32736, 4048, 11403, 31840, 32049, 32845, 37055, 37986, + 39271, 11404, 31053, 31063, 20976, 4049, 38141, 21773, 963, 32728, 4045, + 16955, 32738, 32729, 32730, 38125, 32734, 32741, 348, 3753, 18061, 10674, + 20870, 32410, 17554, 11411, 11410, 11396, 11398, 11412, 38134, 38135, + 32075, 38136, 11409, 11405, 11406, 11407, 11408, 31868, 38120, 31483, + 2643, 38138, 35046, 39422, 39420, 39424, 39425, 39430, 39418, 39429, + 39428, 39416, 39423, 39415, 39417, 39426, 39414, 39431, 17655, 32378, + 32389, 32390, 32377, 32374, 32383, 32385, 32393, 32394, 32386, 32392, + 32388, 32371, 32379, 32375, 32381, 34046, 34050, 34051, 34045, 34042, + 34054, 34053, 34041, 34055, 34052, 34040, 34049, 34044, 34047, 34043, + 34048, 32382, 32376, 32387, 32391, 23943, 32384, 32373, 32372, 32380, + 39432, 38129, 38128, 41412, 41412, 41412, 41412, 24358, 38350, 32235, + 11441, 24262, 38221, 29572, 29545, 34188, 34203, 24378, 32259, 24442, + 32336, 24439, 38400, 32335, 11477, 24381, 32262, 24389, 38363, 32242, + 11455, 38222, 24387, 32268, 24372, 32254, 24270, 24265, 11481, 38360, + 38361, 11450, 11451, 32250, 11442, 974, 8134, 29574, 24369, 979, 8136, + 24408, 24402, 38377, 38374, 32295, 32289, 11492, 11489, 32270, 38352, + 24392, 24454, 38403, 32302, 11500, 24409, 32296, 24445, 24269, 32278, + 24443, 38367, 32276, 11482, 24267, 38224, 29585, 29558, 34200, 34213, + 24429, 32326, 24458, 32306, 38353, 11443, 24449, 38368, 32282, 11483, + 24368, 32249, 24440, 38404, 32337, 11479, 38409, 38405, 38407, 38406, + 38411, 38412, 32338, 29573, 34191, 38226, 32115, 11453, 37404, 24388, + 32269, 24264, 24374, 32252, 24263, 24453, 32301, 24272, 17639, 8588, + 31391, 37383, 37382, 16888, 20791, 29026, 16837, 29594, 34026, 8596, + 11149, 34019, 16902, 28985, 28973, 28977, 27769, 27776, 11324, 11131, + 32850, 2571, 32347, 5098, 34547, 8835, 17649, 31867, 20864, 32105, 959, + 27024, 34323, 11135, 11150, 31250, 29599, 25288, 25295, 20952, 38201, + 20937, 11354, 38025, 8602, 34960, 39410, 8137, 8128, 976, 37384, 3754, + 31959, 31866, 11325, 17491, 17883, 20605, 37694, 32077, 20973, 33979, + 39832, 29604, 27775, 2578, 29595, 1058, 1061, 29229, 364, 29596, 366, + 38016, 361, 16941, 17881, 11141, 1062, 17882, 1059, 20754, 8162, 16939, + 32345, 32346, 8781, 16956, 16942, 34712, 10690, 16924, 27035, 31930, + 29606, 20630, 29607, 34749, 24558, 18294, 24560, 18297, 24549, 18287, + 28722, 28721, 3752, 29605, 29609, 29608, 29234, 29231, 24557, 18293, + 29233, 29230, 24559, 18295, 29235, 29232, 31841, 34786, 31850, 34795, + 31849, 34794, 11152, 11155, 34774, 34946, 29592, 29593, 34780, 34952, + 29227, 29228, 34779, 34951, 28475, 28476, 28477, 34420, 34509, 34422, + 34511, 34355, 34362, 6909, 6855, 6914, 6647, 6660, 6910, 6636, 6919, + 6661, 34680, 34673, 34694, 34628, 32192, 24306, 11418, 38230, 2579, + 27784, 38033, 17640, 38019, 11381, 11154, 29603, 11157, 29226, 31851, + 34796, 29589, 8597, 29590, 8598, 30738, 20753, 28478, 20376, 20960, + 39853, 29071, 29544, 32111, 32188, 28982, 28983, 28984, 28978, 10969, + 11326, 34714, 11133, 4474, 24320, 32150, 24278, 32161, 32078, 10078, + 10077, 11375, 11374, 11353, 11378, 31661, 16925, 24563, 18303, 39321, + 39320, 24547, 18298, 16923, 16922, 16920, 16921, 11153, 11156, 29600, + 29601, 34421, 34510, 24548, 18286, 31848, 34793, 29597, 11147, 29598, + 11148, 39277, 27761, 38229, 11421, 16838, 16840, 34027, 16843, 16842, + 34028, 16841, 16839, 8599, 8600, 34020, 8601, 34021, 41130, 10970, 16835, + 20599, 38213, 11422, 31865, 31500, 39596, 24229, 32123, 24317, 32132, + 4457, 4454, 37934, 37930, 32068, 34453, 2567, 32752, 32748, 37053, 31786, + 39334, 31664, 38132, 39587, 20597, 37929, 37933, 4453, 4456, 37923, 4451, + 17665, 34086, 38214, 30728, 16952, 39837, 21775, 24327, 32213, 16951, + 3700, 10656, 362, 35056, 37950, 11142, 8607, 34011, 8783, 8784, 1004, + 1042, 1028, 1016, 1017, 1033, 1014, 984, 989, 1039, 1044, 1030, 1029, + 1024, 1031, 1012, 1036, 1025, 1032, 987, 996, 995, 1018, 1021, 997, 1050, + 1023, 1047, 993, 1022, 1020, 1048, 1000, 1019, 1035, 994, 1001, 1010, + 988, 1049, 1034, 985, 1015, 1046, 991, 1040, 1009, 986, 998, 1011, 1052, + 1051, 990, 992, 1053, 1041, 1038, 1027, 1026, 999, 1045, 1002, 1037, + 1007, 1006, 1043, 1003, 1008, 1005, 29610, 32110, 33041, 3595, 39293, + 20936, 8605, 11056, 16894, 8587, 39741, 16916, 367, 20087, 6691, 6913, + 5038, 38200, 28358, 20623, 30724, 30725, 31405, 31406, 11051, 34104, + 1013, 10681, 31852, 29458, 31854, 8157, 24323, 24324, 24322, 32157, + 32158, 32156, 24285, 24292, 24284, 32171, 32178, 32170, 24227, 24225, + 24226, 10080, 32121, 32119, 32120, 20947, 20565, 38282, 38321, 34799, + 34797, 37937, 4460, 4461, 31939, 24326, 32194, 20574, 20575, 20576, + 20577, 10703, 10701, 10705, 10694, 10698, 10706, 10695, 10699, 10704, + 10693, 10697, 10692, 10696, 10702, 10700, 34388, 32050, 17518, 39288, + 27597, 27589, 27596, 27590, 27594, 27595, 27593, 27592, 27591, 11672, + 17781, 37925, 4464, 37907, 4463, 37938, 4467, 39750, 3701, 34740, 17605, + 8, 16836, 10682, 3987, 3949, 4030, 3926, 3988, 3950, 3990, 230, 34738, + 37702, 20598, 3966, 3969, 3971, 3963, 11379, 4009, 3871, 31800, 31797, + 31798, 31799, 30113, 35041, 35049, 35050, 35030, 35028, 35031, 35042, + 35013, 35014, 35035, 35037, 35036, 35034, 35015, 35047, 35048, 35017, + 35026, 35025, 35024, 35023, 35039, 35053, 35029, 35016, 35027, 35051, + 35032, 35033, 35044, 35043, 35045, 35054, 35018, 4053, 30711, 35040, + 35021, 35052, 35020, 35019, 35022, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 30125, 30120, 30123, + 30124, 30117, 30118, 30116, 30115, 30122, 30119, 30121, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 6657, + 6654, 6653, 6650, 6649, 6652, 6651, 6658, 6656, 6878, 6858, 6903, 6891, + 6873, 6861, 6877, 6875, 6857, 6904, 6892, 31337, 31335, 31334, 31331, + 31330, 31333, 31332, 31338, 31336, 31329, 31320, 31328, 31326, 31321, + 31322, 31324, 31325, 31319, 31323, 31327, 10991, 11003, 11000, 10985, + 10982, 10997, 10994, 11009, 10988, 29631, 29624, 29632, 29630, 29625, + 29626, 29627, 29629, 29623, 29634, 29633, 31365, 31366, 31367, 31368, + 31369, 31370, 31371, 31372, 31373, 31374, 31375, 31376, 31377, 31378, + 31379, 31380, 31381, 31382, 31383, 31384, 31385, 31386, 31387, 31388, + 31389, 31390, 6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, + 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, + 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, 6834, + 6835, 6836, 6837, 6838, 6839, 6840, 6841, 6842, 6843, 6844, 6845, 6846, + 6847, 6848, 6849, 6850, 6851, 6852, 6655, 29151, 29149, 29147, 29152, + 29153, 29155, 29156, 29150, 29154, 29148, 11345, 11343, 11342, 11339, + 11338, 11341, 11340, 11346, 11344, 11337, 29146, 4586, 4532, 4602, 4518, + 4595, 4531, 4594, 4530, 4593, 4529, 4592, 4528, 4583, 4502, 4496, 4525, + 4582, 4500, 4494, 4524, 4601, 4630, 4624, 4517, 4600, 4628, 4622, 4515, + 4609, 4646, 4623, 4495, 4643, 4501, 4629, 4521, 4608, 4645, 4621, 4493, + 4642, 4499, 4627, 4520, 4581, 4536, 4614, 4504, 4498, 4617, 4539, 4523, + 4599, 4535, 4613, 4631, 4625, 4616, 4538, 4516, 4607, 4537, 4615, 4644, + 4620, 4497, 4641, 4541, 4619, 4534, 4612, 4503, 4626, 4618, 4540, 4519, + 4585, 4527, 4584, 4526, 4492, 4488, 4509, 4506, 4484, 4508, 4505, 4483, + 4636, 4633, 4487, 4635, 4632, 4486, 4648, 4639, 4491, 4647, 4638, 4490, + 4510, 4507, 4482, 4637, 4634, 4485, 4649, 4640, 4489, 4543, 4542, 4544, + 4545, 4574, 4568, 4578, 4590, 4597, 4611, 4580, 4511, 4513, 4533, 4522, + 4591, 4598, 4512, 4514, 38259, 25435, 25434, 25437, 25345, 25427, 25440, + 25436, 17672, 24279, 24302, 24315, 24243, 24303, 24258, 24259, 32136, + 24579, 27151, 10668, 38307, 32153, 31921, 31922, 31913, 31914, 31915, + 31916, 31917, 31918, 31919, 31920, 4007, 39728, 39737, 39731, 34566, + 34575, 34565, 34572, 34574, 34564, 4004, 39725, 4000, 39713, 4037, 39760, + 3981, 39709, 4032, 39757, 4031, 39756, 3989, 39717, 3994, 39716, 3993, + 39715, 3928, 39672, 3927, 39671, 3954, 39698, 3953, 39697, 3952, 39696, + 3918, 39661, 39662, 17597, 25442, 39647, 11328, 6630, 5101, 3867, 6622, + 6631, 6623, 6628, 6627, 6629, 24241, 32134, 20964, 20968, 38263, 25339, + 38287, 38323, 25389, 25369, 38268, 25346, 3961, 3960, 4033, 4034, 39611, + 34569, 34576, 34571, 34568, 39740, 39758, 38245, 38246, 22899, 39738, + 39734, 39735, 39739, 39654, 39652, 39653, 39655, 38285, 38340, 25380, + 39705, 3976, 39704, 3975, 25403, 4011, 8151, 38194, 34094, 8590, 4020, + 39747, 24589, 37421, 34800, 2568, 10711, 8608, 30732, 4026, 39749, 2795, + 2801, 2802, 32560, 38196, 20593, 39722, 4018, 33013, 32073, 3959, 3986, + 39695, 39754, 39719, 39670, 33990, 6225, 31937, 3864, 5361, 983, 30834, + 6585, 8816, 8815, 34715, 17564, 102, 19262, 31471, 41128, 38004, 38005, + 38010, 38007, 38009, 38008, 38006, 38003, 39607, 39682, 39726, 4006, + 39745, 17590, 22903, 27586, 17570, 11668, 25747, 21093, 32630, 38413, + 29460, 31766, 2566, 37042, 17864, 6099, 24463, 39336, 25277, 32724, + 32558, 6105, 2646, 31659, 39619, 39635, 39638, 39613, 39622, 39632, 3889, + 3905, 3908, 3883, 3892, 3902, 4019, 39685, 39666, 3917, 39727, 3938, + 3923, 39656, 20594, 31926, 16791, 3581, 3582, 28483, 28481, 28482, 39605, + 11673, 38210, 31967, 31968, 31969, 31970, 31971, 31972, 31973, 31974, + 4036, 31966, 31396, 31503, 39608, 10973, 10974, 10975, 10976, 10977, + 10978, 39649, 39651, 3868, 3870, 28355, 28356, 11013, 11016, 11015, + 11014, 39676, 3934, 19263, 981, 8824, 34709, 32719, 347, 17613, 17860, + 34710, 2581, 17610, 31040, 37398, 37397, 39581, 20444, 11414, 11415, + 20951, 25746, 25745, 25744, 39294, 20585, 27162, 27138, 27155, 25913, + 11136, 38212, 8807, 17778, 29270, 6235, 31205, 21094, 39323, 6588, 3977, + 32852, 32764, 31932, 32847, 34099, 3518, 34642, 39673, 39674, 3931, 3932, + 34095, 34802, 31942, 4013, 37420, 38124, 38123, 39667, 8825, 11055, + 30731, 31644, 6167, 20086, 6643, 6236, 29532, 368, 4027, 39752, 3957, + 39693, 11514, 19943, 24230, 34685, 17558, 4024, 32046, 32047, 2575, + 19869, 31478, 32212, 24353, 20974, 3880, 33018, 6620, 6227, 20549, 17861, + 17862, 25842, 28374, 38195, 17651, 17607, 17572, 32715, 34387, 33988, + 20629, 31490, 37162, 20991, 19845, 17780, 10073, 39677, 4014, 38252, + 4017, 25421, 39720, 39686, 37054, 37041, 226, 16913, 31955, 31947, 39327, + 39835, 25420, 31480, 38322, 39708, 3979, 6401, 19867, 28474, 19903, 2805, + 19859, 31042, 19950, 30715, 19905, 23392, 32857, 31039, 25748, 34713, + 17647, 17645, 19888, 17641, 3935, 39681, 34308, 34743, 6916, 30713, 3881, + 31041, 19907, 31656, 32856, 19858, 30714, 16790, 16785, 16783, 33982, + 16784, 19881, 38144, 33985, 37047, 30712, 19933, 33980, 3933, 39678, + 16786, 6905, 19932, 34097, 37692, 19866, 34307, 19926, 2794, 16789, + 19883, 8821, 32855, 29218, 25419, 38319, 25401, 38337, 4044, 39712, + 39675, 3920, 19885, 24586, 27159, 19949, 19916, 19917, 19877, 19878, + 19900, 19899, 10085, 19886, 19892, 19862, 32407, 17612, 32406, 27145, + 27148, 27139, 27140, 27146, 27149, 19896, 19909, 19895, 19908, 24578, + 24576, 27144, 27147, 11038, 11036, 11035, 11032, 11031, 11034, 11033, + 11039, 11037, 11030, 11049, 11046, 11045, 11042, 11041, 11044, 11043, + 11050, 11048, 11040, 11028, 11025, 11024, 11021, 11020, 11023, 11022, + 11029, 11027, 11019, 19945, 19948, 19904, 19874, 19922, 19910, 19929, + 11506, 19913, 37998, 19935, 10671, 19873, 3995, 37412, 37415, 3996, + 19860, 19861, 34703, 19872, 32228, 24343, 2658, 17663, 19901, 19940, + 29612, 10079, 29614, 6693, 39764, 4050, 4052, 4051, 19863, 19865, 19864, + 37048, 19934, 39601, 19946, 30726, 11347, 37395, 39751, 31484, 30722, + 30721, 24277, 32160, 30836, 32057, 34957, 39275, 26610, 25303, 26431, + 34670, 34671, 39665, 982, 16845, 25417, 38280, 24261, 32151, 17671, + 22891, 22890, 24208, 24207, 24257, 25325, 25308, 38231, 25443, 39657, + 39658, 39659, 39733, 39736, 26611, 26605, 26614, 26608, 26613, 26607, + 26612, 26606, 26615, 26609, 38381, 11496, 978, 8130, 32114, 25311, 25315, + 25305, 25309, 25320, 25307, 25312, 25319, 25310, 25321, 25324, 5027, + 4772, 4900, 4773, 4964, 4837, 4901, 4774, 4996, 4869, 4933, 4806, 4965, + 4838, 4902, 4775, 5012, 4885, 4949, 4822, 4981, 4854, 4918, 4791, 4997, + 4870, 4934, 4807, 4966, 4839, 4903, 4776, 5020, 4893, 4957, 4830, 4989, + 4862, 4926, 4799, 5005, 4878, 4942, 4815, 4974, 4847, 4911, 4784, 5013, + 4886, 4950, 4823, 4982, 4855, 4919, 4792, 4998, 4871, 4935, 4808, 4967, + 4840, 4904, 4777, 5024, 4897, 4961, 4834, 4993, 4866, 4930, 4803, 5009, + 4882, 4946, 4819, 4978, 4851, 4915, 4788, 5017, 4890, 4954, 4827, 4986, + 4859, 4923, 4796, 5002, 4875, 4939, 4812, 4971, 4844, 4908, 4781, 5021, + 4894, 4958, 4831, 4990, 4863, 4927, 4800, 5006, 4879, 4943, 4816, 4975, + 4848, 4912, 4785, 5014, 4887, 4951, 4824, 4983, 4856, 4920, 4793, 4999, + 4872, 4936, 4809, 4968, 4841, 4905, 4778, 5026, 4899, 4963, 4836, 4995, + 4868, 4932, 4805, 5011, 4884, 4948, 4821, 4980, 4853, 4917, 4790, 5019, + 4892, 4956, 4829, 4988, 4861, 4925, 4798, 5004, 4877, 4941, 4814, 4973, + 4846, 4910, 4783, 5023, 4896, 4960, 4833, 4992, 4865, 4929, 4802, 5008, + 4881, 4945, 4818, 4977, 4850, 4914, 4787, 5016, 4889, 4953, 4826, 4985, + 4858, 4922, 4795, 5001, 4874, 4938, 4811, 4970, 4843, 4907, 4780, 5025, + 4898, 4962, 4835, 4994, 4867, 4931, 4804, 5010, 4883, 4947, 4820, 4979, + 4852, 4916, 4789, 5018, 4891, 4955, 4828, 4987, 4860, 4924, 4797, 5003, + 4876, 4940, 4813, 4972, 4845, 4909, 4782, 5022, 4895, 4959, 4832, 4991, + 4864, 4928, 4801, 5007, 4880, 4944, 4817, 4976, 4849, 4913, 4786, 5015, + 4888, 4952, 4825, 4984, 4857, 4921, 4794, 5000, 4873, 4937, 4810, 4969, + 4842, 4906, 4779, 32332, 32331, 24444, 32277, 24268, 32333, 24446, 32279, + 11452, 38362, 38399, 11476, 24448, 32281, 24428, 32325, 32334, 32251, + 38364, 11456, 32264, 32263, 32327, 32329, 32328, 24393, 32271, 24447, + 32280, 24370, 32248, 24390, 32243, 29571, 29551, 29577, 29549, 34192, + 34205, 29576, 29548, 34189, 34204, 32351, 17556, 34190, 29546, 17557, + 32352, 29547, 29575, 39590, 2559, 2558, 2561, 2562, 32229, 24342, 37904, + 4462, 37906, 37905, 25399, 25363, 975, 8127, 32238, 24359, 33028, 32256, + 24375, 32247, 24266, 38402, 24220, 24219, 38219, 38218, 24221, 38220, + 24218, 38217, 24407, 32294, 38376, 11491, 24401, 32288, 38373, 11488, + 24406, 32293, 38375, 11490, 24400, 32287, 38372, 11487, 24403, 38371, + 32292, 11485, 24405, 24399, 32290, 32285, 24404, 24398, 32291, 32286, + 38370, 11486, 32126, 16930, 37696, 24363, 32240, 32239, 24544, 24366, + 18282, 34773, 24365, 34943, 24316, 32131, 38228, 11420, 38018, 41141, + 41142, 24308, 32197, 24310, 32199, 41136, 41132, 41137, 41133, 24289, + 32175, 24287, 32172, 24286, 32173, 24214, 32107, 24215, 32113, 11360, + 11385, 24223, 32117, 11335, 39308, 27033, 32112, 27034, 960, 5, 34324, + 34325, 38121, 32063, 961, 32064, 30111, 30110, 27032, 27031, 27026, + 27025, 27030, 27028, 27029, 27027, 32085, 16892, 16891, 16889, 16890, + 6632, 6920, 6907, 6911, 6908, 6633, 6625, 6634, 38216, 6915, 6638, 6853, + 6921, 6624, 6626, 34634, 34629, 34700, 34686, 34687, 38154, 37997, 37995, + 32555, 37994, 32189, 24294, 39272, 4475, 4476, 4043, 37703, 37704, 39690, + 3942, 24313, 32202, 24231, 32127, 20788, 37630, 20865, 11413, 34577, + 20790, 33048, 16931, 16932, 20631, 18166, 37386, 11433, 11434, 3921, + 3962, 39650, 3869, 16945, 16948, 16944, 16947, 16943, 16946, 32424, + 32058, 34151, 32059, 3857, 3856, 11367, 38014, 24330, 32215, 37705, + 27777, 28972, 28970, 28971, 28980, 28979, 28975, 28976, 38156, 38155, + 28974, 28180, 34798, 31923, 17583, 20946, 20938, 6925, 980, 24661, 24662, + 24663, 20939, 31925, 20943, 20940, 20944, 20942, 20945, 20941, 21091, + 22892, 41138, 41139, 41140, 31758, 31763, 31761, 31757, 31760, 31759, + 31762, 27770, 27771, 27773, 27772, 31754, 31755, 39325, 28473, 28472, + 32763, 34071, 28468, 28469, 6854, 28470, 6648, 31756, 27774, 28471, + 20961, 32234, 41134, 374, 20957, 38205, 38206, 20956, 20955, 38207, + 38203, 20954, 38202, 20953, 38204, 20958, 8143, 8149, 11368, 11369, 8144, + 25291, 25299, 11358, 11359, 38152, 38153, 34010, 34009, 25296, 25293, + 25301, 25292, 25300, 25290, 25294, 25289, 34061, 25298, 25297, 41135, + 41131, 16937, 20632, 38012, 38013, 37698, 37697, 33854, 8609, 16938, 365, + 1060, 16927, 31764, 16928, 11348, 38147, 37406, 16936, 16940, 24561, + 18301, 24562, 18302, 24553, 18288, 24556, 18291, 24554, 18289, 24555, + 18290, 24552, 18292, 24546, 18284, 24545, 18283, 24543, 18280, 24541, + 18278, 24540, 18277, 24539, 18281, 24542, 18279, 33995, 33993, 33996, + 33994, 11395, 11394, 11391, 11390, 33853, 33852, 33851, 33850, 11361, + 11363, 11362, 18296, 18285, 24550, 18299, 24551, 18300, 34069, 22900, + 34070, 22901, 16933, 31844, 34789, 31845, 34790, 31847, 34792, 31843, + 34788, 31846, 34791, 31842, 34787, 11364, 11373, 34784, 34956, 34783, + 34955, 34782, 34954, 34781, 34953, 34776, 34948, 34777, 34949, 34775, + 34947, 34778, 34950, 34455, 34542, 8138, 8140, 8139, 8141, 34771, 34942, + 34772, 34941, 34945, 34944, 16844, 31662, 37990, 17635, 29543, 33027, + 33033, 33030, 31485, 39274, 11382, 39273, 11380, 25302, 33034, 33032, + 33031, 11349, 11377, 11371, 32067, 11151, 39290, 39289, 11419, 31249, + 31248, 38017, 38020, 38011, 38024, 38023, 11393, 11392, 38021, 22889, + 11376, 39762, 28981, 29560, 29587, 34202, 34215, 24271, 24397, 38366, + 11458, 29557, 29584, 34199, 34212, 24273, 38223, 32260, 32261, 24379, + 24380, 34570, 34563, 34573, 34567, 10965, 10966, 10964, 10963, 11331, + 3948, 39691, 4041, 39763, 3982, 39710, 39688, 3939, 20560, 3943, 3965, + 39702, 3968, 39706, 4001, 4002, 39723, 3941, 39689, 4038, 39759, 24217, + 37399, 24216, 25313, 24436, 24435, 24437, 24438, 24373, 24383, 24382, + 24431, 24433, 24432, 24367, 39589, 16929, 32060, 24360, 32246, 32245, + 24462, 32341, 32061, 32236, 37695, 24362, 24361, 32237, 11472, 33025, + 33023, 39703, 4003, 39724, 3992, 39714, 19893, 19906, 19870, 19868, + 19871, 33997, 2656, 33998, 2655, 3698, 33024, 24413, 38385, 32310, 11461, + 24275, 38227, 29582, 29555, 34197, 34210, 24425, 38396, 32322, 11473, + 8135, 973, 24424, 38387, 32321, 11463, 41412, 41412, 29583, 29556, 34198, + 34211, 24415, 38395, 32312, 11471, 20581, 39303, 24414, 38386, 32311, + 11462, 24426, 38397, 32323, 11474, 24396, 38365, 32274, 11460, 970, 971, + 969, 972, 32051, 32052, 29455, 29456, 17642, 32275, 16935, 35055, 37410, + 37414, 37411, 37413, 3955, 4035, 3997, 3929, 11465, 11466, 38389, 38390, + 24418, 32315, 24417, 32314, 3872, 3873, 3874, 3875, 3876, 3878, 3877, + 3879, 32098, 32099, 32096, 32097, 32093, 32095, 32092, 32094, 38410, + 38215, 31057, 31056, 31058, 2800, 6923, 6637, 4008, 3919, 38122, 20559, + 4042, 3972, 3964, 3967, 3970, 29461, 37922, 4450, 24574, 32408, 39680, + 32409, 34527, 38198, 18828, 31770, 31769, 31768, 31767, 37989, 31869, + 2576, 20615, 31643, 29238, 39707, 3922, 38034, 10075, 19843, 41220, + 22725, 1055, 97, 39413, 31781, 24242, 32135, 34716, 34717, 24434, 38401, + 32330, 11478, 16950, 16949, 32853, 32550, 32548, 32549, 32547, 32551, + 32552, 16934, 38209, 32844, 11416, 31404, 32074, 20088, 18066, 18068, + 18102, 18076, 18072, 18103, 18110, 18073, 18109, 18082, 18078, 18077, + 18071, 18113, 18084, 18085, 18086, 18087, 18089, 18091, 18095, 18099, + 18112, 18074, 18111, 18088, 18090, 18092, 18101, 18070, 18094, 18105, + 18104, 18106, 18096, 18108, 18097, 18098, 18107, 18080, 18067, 18079, + 18075, 18081, 18093, 18100, 18083, 18069, 18114, 18116, 18150, 18124, + 18120, 18151, 18158, 18121, 18157, 18130, 18126, 18125, 18119, 18161, + 18132, 18133, 18134, 18135, 18137, 18139, 18143, 18147, 18160, 18122, + 18159, 18136, 18138, 18140, 18149, 18118, 18142, 18153, 18152, 18154, + 18144, 18156, 18145, 18146, 18155, 18128, 18115, 18127, 18123, 18129, + 18141, 18148, 18131, 18117, 23124, 23771, 23127, 23218, 23236, 23505, + 23997, 23067, 23690, 23113, 23750, 23382, 24164, 22945, 23146, 23286, + 23287, 24117, 23359, 24134, 24116, 23072, 23697, 24062, 23618, 24038, + 23852, 23430, 24189, 27898, 23262, 23386, 8617, 8711, 8667, 8761, 8631, + 8725, 8628, 8722, 8672, 8766, 8662, 8756, 8666, 8760, 8633, 8727, 8664, + 8758, 8670, 8764, 8636, 8730, 8641, 8735, 8673, 8767, 8674, 8768, 8637, + 8731, 8642, 8736, 8669, 8763, 8671, 8765, 8663, 8757, 8665, 8759, 8675, + 8769, 8639, 8733, 8635, 8729, 8668, 8762, 8658, 8752, 8625, 8719, 8653, + 8747, 8621, 8715, 8626, 8720, 8627, 8721, 8622, 8716, 8651, 8745, 8661, + 8755, 8623, 8717, 8649, 8743, 8652, 8746, 8616, 8710, 8624, 8718, 8644, + 8738, 8645, 8739, 8640, 8734, 8647, 8741, 8646, 8740, 8643, 8737, 8650, + 8744, 8648, 8742, 8656, 8750, 8654, 8748, 8655, 8749, 8657, 8751, 8771, + 8772, 8773, 8775, 8776, 8770, 8774, 8619, 8713, 8620, 8714, 8615, 8614, + 8613, 8618, 8712, 41412, 41412, 41412, 41412, 41412, 8709, 8706, 8707, + 8708, 8704, 8705, 8777, 17925, 17951, 17936, 17957, 17958, 17956, 17946, + 17947, 17959, 17940, 17949, 17952, 17954, 17960, 17942, 17945, 17950, + 17944, 17948, 17961, 17941, 17939, 17935, 17955, 17943, 17931, 17934, + 17938, 17933, 17932, 17953, 17937, 17926, 17930, 17928, 17963, 17927, + 17929, 41412, 17962, 41412, 41412, 41412, 41412, 41412, 17924, 41412, + 41412, 37645, 37665, 37666, 37646, 37648, 37635, 37674, 37661, 37664, + 37662, 37663, 37684, 37673, 37649, 37639, 37651, 37667, 37634, 37643, + 37668, 37672, 37650, 37640, 37679, 37644, 37685, 37659, 37633, 37641, + 37675, 37676, 37677, 37638, 37642, 37678, 37687, 37669, 37670, 37647, + 37637, 37632, 37652, 37654, 37653, 37655, 37656, 37671, 37657, 37680, + 37681, 37682, 37658, 37636, 37660, 37683, 37686, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 37688, 37689, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 37631, 17385, 17202, 17289, 17329, 17305, 16992, 17367, 17030, 17220, + 17211, 17112, 17445, 17060, 17045, 17376, 17336, 17021, 17236, 17249, + 17097, 17101, 17100, 17099, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 17319, 17325, 17323, 17320, 17322, 17321, 17324, + 41412, 17011, 17017, 17015, 17012, 17014, 17013, 17016, 41412, 17435, + 17441, 17439, 17436, 17438, 17437, 17440, 41412, 17004, 17010, 17008, + 17005, 17007, 17006, 17009, 41412, 17271, 17277, 17275, 17272, 17274, + 17273, 17276, 41412, 17180, 17186, 17184, 17181, 17183, 17182, 17185, + 41412, 17412, 17418, 17416, 17413, 17415, 17414, 17417, 41412, 17123, + 17129, 17127, 17124, 17126, 17125, 17128, 41412, 8197, 8235, 8232, 8199, + 8229, 8230, 8236, 8203, 8204, 8205, 8212, 8234, 8206, 8200, 8228, 8225, + 8227, 8231, 8215, 8214, 8233, 8201, 8237, 8211, 8198, 8224, 8220, 8222, + 8209, 8223, 8196, 8208, 32109, 32108, 24293, 32179, 24235, 32124, 31946, + 31945, 11334, 24296, 32187, 31954, 24276, 32159, 11675, 31247, 17634, + 32069, 20622, 11333, 11457, 38349, 11336, 11384, 20970, 31206, 20618, + 37701, 24256, 32149, 37700, 37699, 24325, 32193, 37931, 37935, 4455, + 4458, 24281, 32164, 24234, 32129, 38150, 30705, 34630, 17601, 32084, + 39306, 32344, 39823, 38126, 31944, 31956, 38137, 10662, 10663, 38127, + 37920, 38162, 37417, 34730, 39309, 39806, 6104, 11352, 32083, 11355, + 10669, 11372, 20971, 20972, 25335, 25336, 11370, 11330, 38022, 27135, + 31246, 31903, 8780, 8817, 8818, 37789, 27134, 27136, 24291, 32177, 24290, + 32176, 37912, 37916, 4441, 4445, 30112, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 8021, 7974, 8024, 8023, 8022, 8017, 7945, 8042, 8056, 8055, 7978, 8025, + 8038, 8037, 8007, 8006, 8005, 8004, 8034, 8043, 8033, 8032, 7993, 7992, + 7996, 8020, 41412, 7977, 8040, 8014, 7979, 8012, 7972, 8048, 8047, 7986, + 8016, 8015, 8026, 7976, 7980, 8001, 7943, 7985, 8036, 8035, 7948, 8031, + 7959, 8054, 8053, 8052, 8051, 8009, 8039, 8019, 7984, 8057, 7947, 7946, + 8008, 8013, 7990, 7989, 7988, 8044, 7975, 8050, 8049, 7963, 8027, 7995, + 7962, 7961, 7987, 7971, 8028, 8046, 8045, 7973, 7955, 8003, 8002, 7958, + 7956, 8011, 8010, 8018, 7949, 7965, 7957, 7967, 7953, 7983, 7982, 7981, + 7951, 7994, 7970, 7944, 7991, 7952, 7969, 7960, 8029, 8030, 7954, 8000, + 7950, 7998, 7966, 7999, 7968, 8041, 7997, 7964, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 21290, + 21272, 21206, 21326, 21314, 21258, 21358, 21273, 21286, 21269, 21221, + 21225, 21210, 21195, 21261, 21347, 21293, 21264, 21298, 21375, 21332, + 21303, 21255, 21360, 21204, 21315, 21191, 21295, 21166, 21284, 21220, + 21218, 21313, 21241, 21243, 21223, 21173, 21372, 21198, 21306, 21260, + 21342, 21265, 21193, 21331, 21282, 21304, 21373, 21291, 21356, 21216, + 21321, 21207, 21275, 21359, 21322, 21181, 21340, 21182, 21334, 21252, + 21249, 21212, 21250, 21183, 21301, 21312, 21205, 21168, 21343, 21288, + 21345, 21311, 21285, 21355, 21266, 21335, 21200, 21366, 21211, 21194, + 21240, 21189, 21333, 21365, 21232, 21190, 21227, 21209, 21248, 21327, + 21229, 21197, 21213, 21296, 21262, 21276, 21350, 21339, 21271, 21377, + 21230, 21177, 21323, 21208, 21368, 21344, 21203, 21226, 21328, 21164, + 21337, 21330, 21354, 21244, 21188, 21338, 21169, 21305, 21324, 21263, + 21289, 21319, 21238, 21294, 21167, 21297, 21217, 21184, 21277, 21278, + 21316, 21165, 21280, 21351, 21292, 21178, 21336, 21196, 21245, 21349, + 21259, 21174, 21364, 21192, 21367, 21317, 21257, 21329, 21361, 21185, + 21299, 21170, 21318, 21308, 21307, 21239, 21180, 21187, 21171, 21281, + 21363, 21199, 21371, 21202, 21362, 21242, 21274, 21247, 21283, 21325, + 21320, 21300, 21176, 21374, 21228, 21267, 21346, 21270, 21341, 21268, + 21370, 21235, 21219, 21253, 21236, 21256, 21179, 21348, 21251, 21231, + 21309, 21186, 21246, 21233, 21172, 21310, 21201, 21369, 21254, 21376, + 21279, 21175, 21224, 21237, 21353, 21215, 21302, 21287, 21222, 21352, + 21214, 21357, 21234, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 20655, + 20653, 20654, 20652, 20667, 20663, 20662, 20659, 20660, 20661, 20657, + 20656, 20664, 20658, 20668, 20666, 20752, 20651, 20750, 11140, 20990, + 20751, 20650, 20670, 24213, 32106, 24232, 32125, 24228, 32122, 24307, + 32196, 24222, 32116, 31783, 18059, 24304, 32191, 24309, 32198, 24312, + 32201, 24311, 32200, 39588, 32066, 11366, 25333, 31784, 19739, 19732, + 19729, 19735, 19734, 19737, 19736, 19740, 19738, 20748, 20747, 20669, + 20746, 19398, 19397, 39594, 39281, 39284, 39282, 39285, 39283, 6906, + 20744, 19733, 19731, 19730, 39280, 25992, 31401, 20749, 20745, 41412, + 20464, 20450, 20466, 20544, 20468, 20546, 20465, 20543, 20467, 20545, + 20505, 20495, 20507, 20497, 20509, 20499, 20506, 20496, 20508, 20498, + 20469, 20530, 20471, 20532, 20473, 20534, 20470, 20531, 20472, 20533, + 20525, 20490, 20527, 20492, 20463, 20529, 20494, 20526, 20491, 20528, + 20493, 20485, 20487, 20489, 20486, 20488, 20500, 20480, 20515, 20502, + 20474, 20517, 20504, 20483, 20519, 20501, 20481, 20516, 20503, 20482, + 20518, 20510, 20512, 20514, 20511, 20513, 20457, 20539, 20459, 20541, + 20458, 20540, 20520, 20522, 20524, 20521, 20523, 20453, 20535, 20537, + 20536, 20538, 20484, 20542, 20460, 20461, 41412, 41412, 8405, 8404, + 21616, 21615, 20548, 20547, 20449, 21613, 21543, 21472, 21545, 21606, + 21547, 21608, 21544, 21605, 21546, 21607, 21568, 21558, 21570, 21560, + 21572, 21562, 21569, 21559, 21571, 21561, 21548, 21593, 21550, 21595, + 21552, 21597, 21549, 21594, 21551, 21596, 21583, 21553, 21585, 21555, + 21530, 21587, 21557, 21584, 21554, 21586, 21556, 21510, 21512, 21514, + 21511, 21513, 21563, 21487, 21573, 21565, 21481, 21575, 21567, 21490, + 21577, 21564, 21488, 21574, 21566, 21489, 21576, 21505, 21491, 21508, + 21506, 21507, 21535, 21602, 21537, 21604, 21536, 21603, 21578, 21580, + 21582, 21579, 21581, 21531, 21598, 21600, 21599, 21601, 21509, 21592, + 21525, 21526, 21588, 21590, 21589, 21591, 21612, 21614, 21611, 21609, + 21610, 41412, 41412, 41412, 41412, 41412, 4422, 4430, 4429, 4427, 4426, + 4433, 4398, 4418, 4386, 4414, 4428, 4424, 4431, 4435, 4411, 4417, 4421, + 4432, 4410, 4416, 4420, 4366, 4402, 4378, 4383, 4367, 4384, 4369, 4409, + 4371, 4379, 4372, 4380, 4385, 4391, 4376, 4397, 4434, 4399, 4388, 4394, + 4405, 4401, 41412, 19651, 19695, 19652, 19657, 19658, 19660, 19687, + 19698, 19673, 19674, 19676, 19678, 19685, 19681, 19677, 19684, 19653, + 19663, 19697, 19664, 19688, 19700, 19645, 19640, 19694, 19639, 19650, + 19686, 19671, 19724, 19635, 19638, 19721, 19722, 19642, 19641, 19708, + 19707, 19725, 19704, 19705, 19726, 19713, 19727, 19703, 19702, 19706, + 19717, 19643, 19723, 19644, 19728, 19696, 19659, 19662, 19661, 19675, + 19682, 19679, 19680, 19683, 19654, 19656, 19655, 19649, 19670, 19668, + 19665, 19666, 19669, 19667, 19647, 19648, 19690, 19691, 19693, 19692, + 19689, 19672, 19701, 19710, 19712, 19711, 19646, 19699, 19709, 19714, + 19715, 19716, 19719, 19718, 19720, 19636, 19637, 41412, 20644, 20647, + 20646, 20642, 20640, 20636, 20643, 20638, 20634, 20637, 20645, 20641, + 20635, 20648, 20649, 20639, 4423, 4412, 4425, 4389, 4382, 4381, 4408, + 4404, 4396, 4373, 4392, 4377, 4395, 4400, 4368, 4370, 4375, 4407, 4403, + 4393, 4364, 4365, 4363, 4362, 4387, 4419, 4413, 4361, 4390, 4415, 4406, + 4374, 8088, 8091, 8092, 8090, 8078, 8064, 8070, 8059, 8069, 8082, 8071, + 8067, 8060, 8068, 8065, 8094, 8058, 8077, 8073, 8086, 8093, 8063, 8072, + 8081, 8080, 8087, 8085, 8074, 8076, 8089, 8084, 8079, 8061, 8066, 8075, + 8095, 8062, 8083, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 20665, 21528, 21540, 21541, 21529, 21539, 21515, 21517, 21519, + 21516, 21518, 21542, 21520, 21522, 21524, 21521, 21523, 31261, 31265, + 31277, 31271, 31263, 31269, 31273, 31279, 31254, 31252, 31259, 31275, + 31267, 31257, 31262, 31266, 31278, 31272, 31264, 31270, 31274, 31280, + 31255, 31253, 31260, 31276, 31268, 31258, 31256, 31318, 31317, 41412, + 31316, 31312, 31310, 31291, 31289, 31309, 31301, 31286, 31295, 31311, + 31294, 31288, 31314, 31313, 31293, 31285, 31308, 31306, 31315, 31303, + 31296, 31304, 31287, 31282, 31292, 31299, 31283, 31305, 31307, 31284, + 31297, 31281, 31290, 31298, 31302, 31300, 6725, 6713, 6735, 6714, 6879, + 6893, 6881, 6863, 6860, 6876, 6874, 6856, 31400, 6894, 6900, 6899, 6896, + 6895, 6898, 6897, 6902, 6901, 6880, 6882, 6888, 6887, 6884, 6883, 6673, + 6677, 6689, 6683, 6675, 6681, 6685, 6666, 6664, 6662, 6671, 6687, 6679, + 6669, 6674, 6678, 6690, 6684, 6676, 6682, 6686, 6667, 6665, 6663, 6672, + 6688, 6680, 6670, 6800, 6799, 6668, 22723, 6748, 6744, 6742, 6710, 6708, + 6740, 6731, 6705, 6723, 6743, 6721, 6707, 6746, 6745, 6719, 6703, 6734, + 6739, 6712, 6736, 6724, 6737, 6706, 6699, 6715, 6730, 6720, 6709, 6733, + 6704, 6741, 6696, 6747, 6727, 6700, 6698, 6711, 6701, 6716, 6717, 6729, + 6718, 6728, 6738, 6732, 6702, 6726, 6694, 6722, 6886, 6885, 6890, 6889, + 6862, 6864, 6870, 6869, 6866, 6865, 6868, 6867, 6872, 6871, 6859, 20735, + 20738, 20739, 20677, 20740, 20736, 20737, 20676, 20742, 20743, 20741, + 20709, 34415, 34381, 34383, 24660, 6794, 6796, 6798, 6795, 6797, 6757, + 6759, 6761, 6758, 6760, 6777, 6779, 6781, 6778, 6780, 6782, 6784, 6786, + 6783, 6785, 6767, 6769, 6771, 6768, 6770, 6752, 6754, 6756, 6753, 6755, + 6762, 6764, 6766, 6763, 6765, 6791, 6793, 6792, 6772, 6774, 6776, 6773, + 6775, 6787, 6789, 6788, 6790, 34379, 34340, 34342, 34341, 34343, 34418, + 34419, 34582, 34382, 34375, 34508, 34512, 34427, 34425, 34426, 34390, + 34391, 34395, 34394, 34441, 34393, 34428, 34431, 34429, 34430, 34396, + 34397, 34438, 34439, 34440, 34437, 34436, 34548, 34549, 34556, 34550, + 34551, 34366, 34370, 34371, 34561, 34501, 34502, 34403, 34515, 34516, + 34347, 34524, 34522, 34523, 34350, 34410, 34409, 34349, 34411, 34404, + 34521, 34519, 34405, 34520, 34518, 34352, 34525, 34351, 34408, 34526, + 34406, 34407, 34465, 34466, 34469, 34468, 34467, 34475, 34476, 34477, + 34472, 34473, 34474, 34580, 34579, 34581, 34543, 34544, 34546, 34545, + 34541, 34540, 34562, 20733, 20734, 20716, 20718, 20725, 20724, 20731, + 20729, 20720, 20727, 20719, 20722, 20715, 20717, 20726, 20723, 20732, + 20730, 20721, 20728, 20710, 20714, 20713, 20712, 20711, 34413, 34365, + 34345, 34348, 34513, 34529, 34367, 34369, 34368, 34423, 34376, 34380, + 34377, 34378, 34357, 34517, 34500, 34482, 34464, 34424, 34446, 34470, + 34400, 34354, 34443, 34530, 34503, 34483, 34484, 34497, 34447, 34416, + 34442, 34494, 34398, 34560, 34485, 34498, 34374, 34449, 34389, 34504, + 34486, 34479, 34358, 34432, 34481, 34360, 34463, 34435, 34480, 34359, + 34462, 34434, 34459, 34460, 34514, 34445, 34496, 34399, 34537, 34538, + 34539, 34534, 34505, 34487, 34499, 34535, 34506, 34488, 34490, 34451, + 34491, 34536, 34507, 34489, 34492, 34452, 34493, 34444, 34461, 34344, + 34353, 34363, 34364, 34361, 34356, 34372, 34401, 34402, 34412, 34417, + 34448, 34433, 34450, 34456, 34457, 34454, 34458, 34471, 34478, 34495, + 34531, 34532, 34528, 34533, 34557, 34558, 34578, 34346, 34338, 20708, + 20693, 20681, 20700, 20699, 20706, 20704, 20695, 20702, 20694, 20697, + 20692, 20680, 20701, 20698, 20707, 20705, 20696, 20703, 20682, 20690, + 20688, 20687, 20684, 20683, 20686, 20685, 20691, 20689, 20678, 20679, + 34392, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 20426, + 20429, 20390, 20440, 20437, 20385, 20423, 20402, 20419, 20436, 20414, + 20420, 20395, 20397, 20407, 20441, 20394, 20438, 20378, 20384, 20382, + 20401, 20421, 20415, 20403, 20400, 20408, 20399, 20424, 20427, 20406, + 20392, 20416, 20398, 20413, 20393, 20428, 20411, 20409, 20388, 20387, + 20405, 20383, 20386, 20396, 20412, 20410, 20430, 20417, 20425, 20422, + 20434, 20389, 20432, 20380, 20431, 20433, 20435, 20391, 20439, 20404, + 20418, 20379, 20381, 40345, 40352, 40344, 40351, 40349, 40350, 40347, + 40348, 41120, 41121, 41118, 41119, 41117, 41115, 41116, 41124, 41125, + 41122, 41123, 41127, 41126, 40992, 40012, 40013, 40006, 40011, 40009, + 40010, 40007, 40008, 40016, 40017, 40014, 40015, 39997, 39995, 39996, + 40020, 40021, 40018, 40019, 40005, 40003, 40004, 40001, 40002, 39994, + 40000, 39999, 39998, 40026, 40027, 40022, 40025, 40024, 40023, 40724, + 40725, 40719, 40723, 40722, 40720, 40721, 40728, 40729, 40726, 40727, + 40713, 40711, 40712, 40732, 40733, 40730, 40731, 40717, 40718, 40710, + 40716, 40715, 40714, 40738, 40739, 40734, 40737, 40736, 40735, 39980, + 39981, 39974, 39979, 39977, 39978, 39975, 39976, 39984, 39985, 39982, + 39983, 39965, 39963, 39964, 39988, 39989, 39986, 39987, 39973, 39971, + 39972, 39969, 39970, 39962, 39968, 39967, 39966, 39992, 39993, 39990, + 39991, 40527, 40528, 40522, 40526, 40525, 40523, 40524, 40531, 40532, + 40529, 40530, 40535, 40536, 40533, 40534, 40541, 40542, 40537, 40540, + 40539, 40538, 40547, 40548, 40543, 40546, 40545, 40544, 40270, 40271, + 40265, 40269, 40268, 40266, 40267, 40274, 40275, 40272, 40273, 40259, + 40257, 40258, 40278, 40279, 40276, 40277, 40263, 40264, 40256, 40262, + 40261, 40260, 40284, 40280, 40283, 40282, 40281, 40506, 40507, 40501, + 40505, 40504, 40502, 40503, 40510, 40511, 40508, 40509, 40494, 40495, + 40492, 40493, 40514, 40515, 40512, 40513, 40521, 40520, 40499, 40500, + 40491, 40498, 40497, 40496, 40518, 40519, 40516, 40517, 40151, 40152, + 40149, 40150, 40147, 40148, 40145, 40146, 40144, 40142, 40143, 40161, + 40162, 40157, 40160, 40159, 40158, 40155, 40156, 40153, 40154, 40970, + 40971, 40964, 40969, 40967, 40968, 40965, 40966, 40974, 40975, 40972, + 40973, 40978, 40979, 40976, 40977, 40963, 40962, 40984, 40985, 40980, + 40983, 40982, 40981, 40990, 40991, 40986, 40989, 40988, 40987, 40129, + 40130, 40124, 40128, 40127, 40125, 40126, 40136, 40137, 40134, 40135, + 40118, 40117, 40140, 40141, 40138, 40139, 40133, 40131, 40132, 40122, + 40123, 40116, 40121, 40120, 40119, 40949, 40950, 40944, 40948, 40947, + 40945, 40946, 40956, 40957, 40954, 40955, 40937, 40938, 40935, 40936, + 40960, 40961, 40958, 40959, 40953, 40951, 40952, 40942, 40943, 40934, + 40941, 40940, 40939, 40103, 40104, 40098, 40102, 40101, 40099, 40100, + 40110, 40111, 40108, 40109, 40092, 40090, 40091, 40114, 40115, 40112, + 40113, 40107, 40105, 40106, 40096, 40097, 40089, 40095, 40094, 40093, + 40553, 40554, 40549, 40552, 40551, 40550, 40560, 40561, 40558, 40559, + 40564, 40565, 40562, 40563, 40557, 40555, 40556, 40570, 40571, 40566, + 40569, 40568, 40567, 40300, 40301, 40294, 40299, 40297, 40298, 40295, + 40296, 40304, 40305, 40302, 40303, 40289, 40288, 40286, 40287, 40285, + 40293, 40291, 40292, 40290, 40698, 40699, 40693, 40697, 40696, 40694, + 40695, 40702, 40700, 40701, 40687, 40685, 40686, 40708, 40709, 40706, + 40707, 40705, 40703, 40704, 40691, 40692, 40684, 40690, 40689, 40688, + 40238, 40239, 40233, 40237, 40236, 40234, 40235, 40248, 40249, 40246, + 40247, 40227, 40225, 40226, 40245, 40243, 40244, 40242, 40240, 40241, + 40231, 40232, 40224, 40230, 40229, 40228, 40254, 40255, 40250, 40253, + 40252, 40251, 40453, 40454, 40447, 40452, 40450, 40451, 40448, 40449, + 40457, 40458, 40455, 40456, 40437, 40438, 40435, 40436, 40461, 40462, + 40459, 40460, 40446, 40444, 40445, 40442, 40443, 40434, 40441, 40440, + 40439, 40467, 40468, 40463, 40466, 40465, 40464, 40207, 40208, 40201, + 40206, 40204, 40205, 40202, 40203, 40211, 40212, 40209, 40210, 40194, + 40195, 40192, 40193, 40219, 40220, 40217, 40218, 40215, 40216, 40213, + 40214, 40199, 40200, 40191, 40198, 40197, 40196, 40420, 40421, 40415, + 40419, 40418, 40416, 40417, 40424, 40425, 40422, 40423, 40409, 40407, + 40408, 40432, 40433, 40430, 40431, 40428, 40429, 40426, 40427, 40413, + 40414, 40406, 40412, 40411, 40410, 40167, 40168, 40163, 40166, 40164, + 40165, 40181, 40182, 40179, 40180, 40172, 40173, 40170, 40171, 40189, + 40190, 40187, 40188, 40185, 40186, 40183, 40184, 40177, 40178, 40169, + 40176, 40175, 40174, 40490, 40489, 40483, 40484, 40481, 40482, 40472, + 40470, 40471, 40487, 40488, 40485, 40486, 40480, 40478, 40479, 40476, + 40477, 40469, 40475, 40474, 40473, 40319, 40320, 40313, 40318, 40316, + 40317, 40314, 40315, 40323, 40324, 40321, 40322, 40308, 40309, 40306, + 40307, 40327, 40328, 40325, 40326, 40312, 40310, 40311, 40580, 40578, + 40579, 40583, 40584, 40581, 40582, 40573, 40574, 40572, 40587, 40588, + 40585, 40586, 40577, 40575, 40576, 40223, 40222, 40221, 40338, 40339, + 40336, 40337, 40331, 40332, 40329, 40330, 40342, 40343, 40340, 40341, + 40335, 40333, 40334, 41004, 41005, 41002, 41003, 40995, 40993, 40994, + 41001, 40999, 41000, 40998, 40996, 40997, 41067, 41068, 41062, 41066, + 41065, 41063, 41064, 41103, 41104, 41101, 41102, 41056, 41054, 41055, + 41107, 41108, 41105, 41106, 41100, 41098, 41099, 41060, 41061, 41053, + 41059, 41058, 41057, 41113, 41114, 41109, 41112, 41111, 41110, 40073, + 40074, 40067, 40072, 40070, 40071, 40068, 40069, 40077, 40078, 40075, + 40076, 40058, 40056, 40057, 40081, 40082, 40079, 40080, 40066, 40064, + 40065, 40062, 40063, 40055, 40061, 40060, 40059, 40087, 40088, 40083, + 40086, 40085, 40084, 41081, 41082, 41075, 41080, 41078, 41079, 41076, + 41077, 41085, 41086, 41083, 41084, 41074, 41072, 41073, 41071, 41069, + 41070, 41091, 41087, 41090, 41089, 41088, 41096, 41097, 41092, 41095, + 41094, 41093, 40670, 40671, 40665, 40669, 40668, 40666, 40667, 40674, + 40675, 40672, 40673, 40658, 40657, 40664, 40663, 40683, 40682, 40662, + 40656, 40661, 40660, 40659, 40680, 40681, 40676, 40679, 40678, 40677, + 40915, 40916, 40910, 40914, 40913, 40911, 40912, 40922, 40923, 40920, + 40921, 40904, 40902, 40903, 40926, 40927, 40924, 40925, 40919, 40917, + 40918, 40908, 40909, 40901, 40907, 40906, 40905, 40932, 40933, 40928, + 40931, 40930, 40929, 40851, 40852, 40846, 40850, 40849, 40847, 40848, + 40858, 40859, 40856, 40857, 40862, 40863, 40860, 40861, 40855, 40853, + 40854, 40866, 40867, 40864, 40865, 40872, 40873, 40868, 40871, 40870, + 40869, 41037, 41038, 41035, 41036, 41029, 41027, 41028, 41045, 41046, + 41043, 41044, 41041, 41042, 41039, 41040, 41033, 41034, 41026, 41032, + 41031, 41030, 41051, 41052, 41047, 41050, 41049, 41048, 40039, 40040, + 40037, 40038, 40031, 40032, 40029, 40030, 40047, 40048, 40045, 40046, + 40043, 40044, 40041, 40042, 40036, 40028, 40035, 40034, 40033, 40053, + 40054, 40049, 40052, 40051, 40050, 40819, 40818, 40798, 40797, 40810, + 40811, 40808, 40809, 40806, 40807, 40804, 40805, 40802, 40803, 40796, + 40801, 40800, 40799, 40816, 40817, 40812, 40815, 40814, 40813, 40619, + 40620, 40617, 40618, 40616, 40614, 40615, 40623, 40624, 40621, 40622, + 40629, 40630, 40625, 40628, 40627, 40626, 40635, 40636, 40631, 40634, + 40633, 40632, 40885, 40886, 40883, 40884, 40877, 40875, 40876, 40893, + 40894, 40891, 40892, 40889, 40890, 40887, 40888, 40881, 40882, 40874, + 40880, 40879, 40878, 40899, 40900, 40895, 40898, 40897, 40896, 40834, + 40835, 40832, 40833, 40823, 40821, 40822, 40838, 40839, 40836, 40837, + 40831, 40829, 40830, 40827, 40828, 40820, 40826, 40825, 40824, 40844, + 40845, 40840, 40843, 40842, 40841, 40394, 40395, 40388, 40393, 40391, + 40392, 40389, 40390, 40381, 40382, 40379, 40380, 40398, 40399, 40396, + 40397, 40386, 40387, 40378, 40385, 40384, 40383, 40404, 40405, 40400, + 40403, 40402, 40401, 40756, 40757, 40750, 40755, 40753, 40754, 40751, + 40752, 40743, 40744, 40741, 40742, 40760, 40761, 40758, 40759, 40748, + 40749, 40740, 40747, 40746, 40745, 40766, 40767, 40762, 40765, 40764, + 40763, 40368, 40369, 40362, 40367, 40365, 40366, 40363, 40364, 40356, + 40354, 40355, 40372, 40373, 40370, 40371, 40360, 40361, 40353, 40359, + 40358, 40357, 40376, 40377, 40374, 40375, 40602, 40603, 40596, 40601, + 40599, 40600, 40597, 40598, 40591, 40590, 40606, 40607, 40604, 40605, + 40595, 40589, 40594, 40593, 40592, 40612, 40613, 40608, 40611, 40610, + 40609, 40650, 40651, 40644, 40649, 40647, 40648, 40645, 40646, 40640, + 40638, 40639, 40654, 40655, 40652, 40653, 40642, 40643, 40637, 40641, + 41012, 41013, 41006, 41011, 41009, 41010, 41007, 41008, 41025, 41024, + 41016, 41017, 41014, 41015, 41022, 41023, 41018, 41021, 41020, 41019, + 40784, 40785, 40778, 40783, 40781, 40782, 40779, 40780, 40771, 40772, + 40769, 40770, 40788, 40789, 40786, 40787, 40776, 40777, 40768, 40775, + 40774, 40773, 40794, 40795, 40790, 40793, 40792, 40791, 41412, 41412, + 41412, 39959, 39932, 39930, 39937, 39911, 39947, 39918, 39920, 39936, + 39923, 39934, 39907, 39935, 39953, 39941, 39922, 39948, 39921, 39954, + 39912, 39915, 39908, 39917, 39938, 39949, 39961, 39926, 39957, 39942, + 39925, 39952, 39950, 39946, 39951, 39958, 39929, 39939, 39928, 39919, + 39927, 39960, 39916, 39943, 39933, 39910, 39909, 39914, 39924, 39944, + 39955, 39945, 39913, 39956, 39940, 39931, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 25263, 25252, 25251, 25235, 25233, + 25232, 25246, 25250, 25249, 25265, 25244, 25243, 25234, 25231, 25230, + 25267, 25240, 25266, 25254, 25257, 25258, 25239, 25248, 25269, 25247, + 25264, 25268, 25253, 25256, 25245, 25259, 25260, 25241, 25242, 25270, + 25261, 25236, 25237, 25238, 25262, 25226, 25229, 25227, 25225, 25228, + 25224, 25271, 25272, 38679, 38680, 38516, 38665, 38666, 38639, 38442, + 38449, 38552, 38525, 38559, 38499, 38625, 38653, 38477, 38470, 38428, + 38421, 38543, 38646, 38435, 38578, 38463, 38456, 38491, 38484, 38618, + 38632, 38597, 38660, 38538, 38584, 38505, 38566, 38611, 38604, 38688, + 38689, 38520, 38521, 38674, 38675, 38641, 38444, 38451, 38554, 38531, + 38561, 38502, 38627, 38655, 38479, 38472, 38430, 38423, 38547, 38648, + 38437, 38580, 38465, 38458, 38493, 38486, 38620, 38634, 38599, 38662, + 38539, 38589, 38510, 38568, 38613, 38606, 38686, 38687, 38591, 38518, + 38519, 38672, 38673, 38640, 38443, 38450, 38553, 38529, 38530, 38560, + 38501, 38626, 38654, 38478, 38471, 38429, 38422, 38546, 38647, 38436, + 38579, 38464, 38457, 38492, 38485, 38619, 38633, 38598, 38661, 38535, + 38536, 38588, 38509, 38567, 38612, 38605, 38683, 38684, 38514, 38669, + 38670, 38637, 38440, 38447, 38550, 38528, 38557, 38497, 38623, 38651, + 38475, 38468, 38426, 38419, 38545, 38644, 38433, 38576, 38461, 38454, + 38489, 38482, 38616, 38630, 38595, 38658, 38534, 38587, 38508, 38564, + 38609, 38602, 38690, 38691, 38522, 38523, 38676, 38677, 38642, 38445, + 38452, 38555, 38532, 38562, 38503, 38628, 38656, 38480, 38473, 38431, + 38424, 38548, 38649, 38438, 38581, 38466, 38459, 38494, 38487, 38621, + 38635, 38600, 38663, 38540, 38590, 38511, 38569, 38614, 38607, 38682, + 38685, 38593, 38512, 38513, 38668, 38671, 38636, 38439, 38446, 38549, + 38527, 38556, 38495, 38496, 38622, 38650, 38474, 38467, 38425, 38418, + 38544, 38643, 38432, 38570, 38460, 38453, 38488, 38481, 38615, 38629, + 38594, 38657, 38533, 38586, 38507, 38563, 38608, 38601, 38678, 38681, + 38592, 38515, 38517, 38664, 38667, 38638, 38441, 38448, 38551, 38524, + 38526, 38558, 38498, 38500, 38624, 38652, 38476, 38469, 38427, 38420, + 38541, 38645, 38434, 38577, 38462, 38455, 38490, 38483, 38617, 38631, + 38596, 38659, 38537, 38583, 38585, 38504, 38506, 38565, 38610, 38603, + 38582, 38542, 38415, 38416, 38417, 38573, 38574, 38571, 38695, 38698, + 38701, 38700, 38704, 38696, 38703, 38694, 38692, 38699, 38702, 38693, + 38697, 38711, 38713, 38710, 38709, 38706, 38705, 38708, 38707, 38714, + 38712, 38575, 38572, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 10415, 10616, 10304, 10463, 10254, 10557, 10359, + 10518, 10300, 10459, 10380, 10543, 10288, 10447, 10247, 10544, 10408, + 10609, 10356, 10515, 10256, 10559, 10357, 10516, 10296, 10455, 10289, + 10448, 10353, 10512, 10410, 10611, 10255, 10558, 10399, 10577, 10396, + 10574, 10397, 10575, 10379, 10542, 10286, 10445, 10301, 10460, 10430, + 8251, 8243, 8194, 8244, 33999, 8218, 8207, 8221, 8217, 8226, 8219, 8216, + 8213, 8249, 8238, 10429, 10433, 10310, 10469, 10308, 10467, 10420, 10621, + 10298, 10457, 10306, 10465, 10260, 10585, 10268, 10594, 10264, 10589, + 10263, 10588, 10266, 10592, 10344, 10503, 10394, 10572, 10302, 10461, + 10297, 10456, 27910, 27947, 8202, 8210, 3462, 2824, 3465, 2826, 3461, + 3437, 3454, 3464, 2853, 3463, 2829, 3434, 3440, 3439, 2827, 2833, 3453, + 2852, 2846, 2832, 3449, 2840, 3444, 3450, 3443, 3447, 2822, 2818, 2850, + 2849, 2844, 3456, 3446, 3457, 3458, 2851, 2816, 3430, 2845, 2848, 3433, + 3459, 3431, 2813, 3442, 2831, 2838, 2855, 3436, 3441, 2817, 2841, 2842, + 2843, 3445, 3432, 2815, 2814, 3460, 2854, 2830, 3435, 2828, 2819, 2835, + 3438, 2834, 2837, 3455, 2825, 2839, 2836, 3452, 2823, 3451, 2847, 3448, + 2812, 2820, 2821, 2809, 2808, 3466, 3468, 2811, 2810, 3467, 3469, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 27907, 27903, 27906, + 27902, 27908, 27904, 27909, 27905, 27962, 27977, 28005, 27984, 27967, + 27961, 27976, 28004, 27983, 27966, 27963, 27978, 28006, 27988, 27968, + 27954, 27953, 27955, 27999, 28018, 28015, 28017, 28016, 27996, 28166, + 28167, 23034, 23638, 23035, 23639, 23074, 23700, 23301, 24063, 23300, + 24020, 22974, 23560, 22975, 23561, 23443, 23451, 22948, 23516, 22949, + 23517, 22950, 23518, 22946, 23514, 22947, 23515, 22951, 23519, 23245, + 23944, 23115, 23752, 23112, 23749, 23116, 23753, 22960, 23537, 23134, + 23776, 23167, 23851, 23168, 23853, 23214, 23891, 23219, 23896, 23217, + 23894, 23220, 23897, 23227, 23909, 23226, 23906, 23242, 23934, 23247, + 23947, 23342, 24113, 23351, 24125, 23346, 24120, 23295, 24014, 23296, + 24015, 23350, 24124, 23036, 23656, 23103, 23739, 22976, 23562, 28175, + 23598, 23797, 23811, 23834, 23946, 23428, 24058, 24110, 23096, 23728, + 23097, 23729, 23098, 23285, 24026, 23290, 24056, 23099, 23731, 23100, + 23732, 23101, 23733, 27982, 27951, 28028, 23268, 23970, 23288, 23781, + 23459, 23160, 23825, 22970, 23550, 23547, 23694, 22954, 23522, 23043, + 23663, 23347, 24121, 23348, 24122, 23349, 24123, 23051, 23674, 23119, + 23757, 23163, 23830, 23240, 23931, 23264, 23968, 23070, 23244, 23271, + 23122, 23267, 23450, 23289, 23292, 23106, 22977, 22961, 23539, 23212, + 23889, 23338, 24101, 23056, 23679, 23057, 23680, 23058, 23681, 23209, + 23880, 22943, 23511, 22968, 23265, 23388, 22981, 23564, 23261, 23962, + 23248, 23260, 23961, 23224, 23903, 22973, 23556, 22994, 23591, 22993, + 23588, 23149, 23810, 23270, 23988, 23138, 23786, 23139, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 27895, 27882, + 27885, 27894, 23243, 23935, 23398, 27877, 28107, 23433, 23396, 23397, + 23394, 23395, 23393, 34995, 34997, 35007, 34999, 34996, 34998, 35006, + 34987, 34986, 34983, 34982, 35005, 34981, 34980, 34985, 34984, 34975, + 34974, 34969, 34968, 34977, 34976, 34971, 34970, 34993, 34989, 34988, + 34979, 34978, 34992, 34973, 34991, 34972, 34994, 34990, 35009, 35011, + 35012, 35010, 35008, 35000, 35001, 35002, 35003, 35004, 41412, 41412, + 41412, 29568, 29567, 29570, 29565, 29566, 29569, 29562, 29561, 29564, + 29563, 41412, 41412, 41412, 41412, 41412, 41412, 31537, 31536, 31525, + 31526, 31513, 31515, 31547, 31528, 31535, 31534, 31518, 31529, 31539, + 31538, 31544, 31549, 31531, 31530, 31517, 31552, 31540, 31541, 31519, + 31554, 31551, 31548, 31520, 31521, 31546, 31510, 31555, 31557, 31542, + 31556, 31550, 31553, 31545, 31524, 31543, 31562, 31563, 31533, 31532, + 31516, 31527, 31511, 31523, 31522, 31512, 31561, 31564, 31514, 31560, + 31565, 31559, 31558, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 32682, 32684, 32631, 32632, 32652, 32653, 32648, 32649, 32643, + 32644, 32645, 32646, 32675, 32676, 32633, 32650, 32651, 32634, 32672, + 32671, 32668, 32667, 32656, 32666, 32665, 32670, 32669, 32658, 32640, + 32639, 32636, 32635, 32657, 32642, 32641, 32638, 32637, 32659, 32674, + 32673, 32664, 32663, 32678, 32680, 32679, 32655, 32647, 32660, 32661, + 32662, 32677, 32654, 32697, 32698, 32709, 32710, 32701, 32702, 32703, + 32704, 32705, 32706, 32711, 32712, 32699, 32707, 32708, 32700, 32683, + 32681, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 32686, + 32685, 32693, 32695, 32692, 32691, 32688, 32687, 32690, 32689, 32696, + 32694, 41412, 41412, 41412, 41412, 41412, 41412, 8269, 8271, 8268, 8267, + 8264, 8263, 8266, 8265, 8272, 8270, 8260, 8261, 8256, 8257, 8258, 8259, + 8255, 8262, 10903, 10897, 10910, 10899, 10898, 10896, 10911, 10800, + 10798, 10803, 10904, 10954, 10809, 10921, 21748, 21750, 21747, 21746, + 21743, 21742, 21745, 21744, 21751, 21749, 21712, 21711, 21722, 21708, + 21716, 21715, 21729, 21709, 21718, 21706, 21710, 21714, 21713, 21724, + 21721, 21719, 21725, 21728, 21723, 21727, 21717, 21707, 21726, 21720, + 21730, 21704, 21731, 21705, 21740, 21737, 21739, 21738, 21741, 21736, + 21734, 21735, 21732, 21733, 32024, 32021, 32013, 32029, 32020, 32015, + 32026, 32018, 32017, 32019, 32023, 32011, 32028, 32027, 32025, 32031, + 32030, 32022, 32016, 32012, 32014, 32010, 32032, 32039, 32041, 32034, + 32037, 32040, 32038, 32036, 32035, 32007, 32006, 32009, 32008, 32042, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 32033, 19386, 19389, 19390, 19387, 19344, 19345, 19353, 19347, + 19349, 19352, 19346, 19342, 19348, 19350, 19343, 19309, 19311, 19312, + 19325, 19332, 19339, 19374, 19291, 19298, 19372, 19376, 19322, 19395, + 19378, 41412, 41412, 41412, 21067, 21063, 21066, 21065, 21037, 21005, + 21004, 21006, 21046, 21025, 21011, 21012, 21044, 21038, 21045, 21007, + 21008, 21009, 21021, 21022, 21010, 21019, 21020, 21035, 21014, 21036, + 21013, 21033, 21034, 21000, 21001, 21016, 21031, 21032, 21002, 21003, + 21015, 21023, 21024, 21017, 21018, 21041, 21043, 21026, 21027, 21040, + 21042, 21029, 21030, 21028, 21039, 21064, 21070, 21072, 21073, 21074, + 21068, 21069, 21071, 21076, 21075, 20996, 20997, 20998, 21061, 20999, + 21047, 21050, 21059, 21052, 21057, 21055, 21053, 21051, 21048, 21049, + 21054, 21062, 41412, 21060, 21083, 21085, 21082, 21081, 21078, 21077, + 21080, 21079, 21086, 21084, 41412, 41412, 41412, 41412, 21056, 21058, + 28787, 28785, 28780, 28777, 28783, 28873, 28851, 28803, 28815, 28811, + 28810, 28813, 28812, 28805, 28804, 28802, 28915, 28917, 28914, 28913, + 28910, 28909, 28912, 28911, 28918, 28916, 28814, 28807, 28806, 28809, + 28808, 41412, 6347, 6365, 6367, 6364, 6348, 6366, 6356, 6355, 6352, 6351, + 6327, 6328, 6350, 6349, 6354, 6353, 6329, 6331, 6330, 6358, 6357, 6344, + 6343, 6332, 6333, 6342, 6338, 6337, 6336, 6341, 6340, 6334, 6335, 6339, + 6363, 6361, 6360, 6362, 6345, 6346, 6359, 6372, 6375, 6376, 6381, 6379, + 6378, 6377, 6373, 6374, 6380, 6315, 6313, 6312, 6314, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 6321, 6320, 6317, 6309, + 6319, 6325, 6316, 6323, 6326, 6324, 6322, 6318, 6311, 6310, 41412, 41412, + 6388, 6390, 6387, 6386, 6383, 6382, 6385, 6384, 6391, 6389, 41412, 41412, + 6368, 6370, 6369, 6371, 28757, 28750, 28749, 28754, 28753, 28747, 28746, + 28745, 28743, 28742, 28744, 28748, 28759, 28752, 28751, 28756, 28850, + 28760, 28761, 28758, 28847, 28848, 28849, 28888, 28890, 28889, 28732, + 28884, 28875, 28876, 28796, 28797, 35479, 35455, 35478, 35454, 35477, + 35453, 35492, 35468, 35486, 35462, 35481, 35457, 35480, 35456, 35497, + 35473, 35487, 35463, 35490, 35466, 35485, 35461, 35484, 35460, 35488, + 35464, 35489, 35465, 35483, 35459, 35482, 35458, 35491, 35467, 35495, + 35471, 35499, 35475, 35496, 35472, 35494, 35470, 35498, 35474, 35493, + 35469, 35500, 35476, 35501, 35513, 35521, 35518, 35517, 35523, 35524, + 35502, 35522, 35519, 35520, 35512, 35516, 35515, 35514, 35511, 35508, + 35509, 35510, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 35504, 35505, 35507, 35506, + 35503, 27214, 27215, 27173, 27190, 27201, 27200, 27177, 27176, 27189, + 27195, 27196, 27228, 27230, 27220, 27222, 27221, 27168, 27165, 27167, + 27217, 27218, 27232, 27233, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 17347, 17345, 17344, 17343, 17342, 17346, + 41412, 41412, 17041, 17039, 17038, 17037, 17036, 17040, 41412, 41412, + 17056, 17054, 17053, 17052, 17051, 17055, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 16997, 17003, 17001, 16998, 17000, + 16999, 17002, 41412, 16982, 16988, 16986, 16983, 16985, 16984, 16987, + 41412, 23530, 23506, 23536, 23531, 23627, 23790, 23980, 23779, 23770, + 23773, 23801, 23815, 23641, 23534, 23535, 23885, 23735, 24029, 24028, + 24030, 24031, 23990, 23427, 23933, 23589, 23913, 23590, 23977, 23978, + 23533, 24100, 24066, 24109, 24052, 24105, 23553, 23554, 23555, 24141, + 24138, 24139, 24140, 24152, 27864, 28088, 28097, 28098, 28155, 23971, + 23738, 23886, 24111, 23734, 18558, 23596, 24061, 24034, 28152, 28001, + 28025, 41412, 41412, 41412, 41412, 6570, 6571, 6572, 6573, 6574, 6575, + 6533, 6569, 6534, 6535, 6536, 6537, 6538, 6498, 6499, 6500, 6501, 6502, + 6503, 6539, 6540, 6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549, + 6504, 6497, 6505, 6506, 6507, 6508, 6509, 6510, 6551, 6552, 6553, 6554, + 6555, 6556, 6512, 6511, 6513, 6514, 6515, 6516, 6517, 6491, 6530, 6492, + 6531, 6493, 6532, 6494, 6495, 6496, 6490, 6518, 6519, 6520, 6521, 6522, + 6523, 6524, 6525, 6526, 6527, 6528, 6529, 6557, 6558, 6559, 6560, 6561, + 6562, 6563, 27182, 27194, 27204, 27206, 27191, 27185, 27172, 27197, + 27184, 27187, 27199, 27210, 27212, 27208, 27213, 27202, 27193, 27211, + 27179, 27180, 27209, 27171, 27181, 27175, 27178, 27174, 27170, 27183, + 27205, 27207, 27192, 27186, 27198, 27188, 27203, 27224, 27227, 27219, + 27226, 27225, 27229, 27223, 27231, 27169, 27216, 27166, 41412, 41412, + 27240, 27242, 27239, 27238, 27235, 27234, 27237, 27236, 27243, 27241, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 19583, 19581, 19614, 19615, 19616, 19592, 19593, 19625, + 19627, 19560, 19558, 19557, 19561, 19567, 19568, 19570, 19569, 19574, + 19571, 19572, 19576, 19544, 19542, 41412, 41412, 41412, 41412, 19440, + 19441, 19509, 19510, 19529, 19523, 19524, 19527, 19526, 19525, 19484, + 19469, 19508, 19475, 19479, 19478, 19492, 19491, 19412, 19437, 19430, + 19515, 19428, 19435, 19465, 19458, 19464, 19519, 19460, 19463, 19462, + 19503, 19496, 19513, 19514, 19502, 19500, 19499, 19504, 19506, 19451, + 19450, 19536, 19537, 19401, 19400, 19516, 19455, 19453, 41412, 41412, + 41412, 41412, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, + 7697, 7698, 7699, 7700, 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, + 7709, 7710, 7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, + 7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, + 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, + 7745, 7746, 7747, 7748, 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, + 7757, 7758, 7759, 7760, 7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, + 7769, 7770, 7771, 7772, 7773, 7774, 7775, 7776, 7777, 7778, 7779, 7780, + 7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, + 7793, 7794, 7795, 7796, 7797, 7798, 7799, 7800, 7801, 7802, 7803, 7804, + 7805, 7806, 7807, 7808, 7809, 7810, 7811, 7812, 7813, 7814, 7815, 7816, + 7817, 7818, 7819, 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, + 7829, 7830, 7831, 7832, 7833, 7834, 7835, 7836, 7837, 7838, 7839, 7840, + 7841, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849, 7850, 7851, 7852, + 7853, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, + 7865, 7866, 7867, 7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 7876, + 7877, 7878, 7879, 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, + 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899, 7900, + 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, 7912, + 7913, 7914, 7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, 7923, 7924, + 7925, 7926, 7927, 7928, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, + 7937, 7938, 7939, 7940, 7941, 7942, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524, 7525, 7526, @@ -15221,3308 +15366,3370 @@ static const unsigned short dawg_codepoint_to_pos_index2[] = { 7539, 7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, 7550, 7551, 7552, 7553, 7554, 7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574, - 7575, 7576, 7577, 7578, 7579, 7580, 7581, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 24005, 24008, 24009, 24006, 24007, 24011, - 24012, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 2506, 2507, 2505, 2508, 2504, 40951, 40951, 40951, - 40951, 40951, 19891, 19918, 19896, 19827, 19883, 19886, 19888, 19887, - 19882, 19889, 19885, 19884, 19828, 19861, 19862, 19859, 19860, 19825, - 19826, 19824, 19832, 19874, 19872, 19849, 19881, 19854, 40951, 19866, - 19892, 19840, 19835, 19876, 40951, 19878, 40951, 19852, 19856, 40951, - 19842, 19838, 40951, 19870, 19847, 19864, 19858, 19868, 19880, 19831, - 19834, 19837, 19893, 1158, 1157, 1188, 1186, 1187, 1189, 1417, 1415, - 1416, 1418, 1183, 1181, 1182, 1184, 1547, 1545, 1546, 1548, 1527, 1525, - 1526, 1528, 1542, 1540, 1541, 1543, 1560, 1558, 1559, 1561, 1422, 1420, - 1421, 1423, 1224, 1222, 1223, 1225, 1395, 1393, 1394, 1396, 1504, 1502, - 1503, 1505, 1509, 1507, 1508, 1510, 1214, 1213, 1205, 1204, 1228, 1227, - 1217, 1216, 1324, 1323, 1452, 1451, 1347, 1345, 1346, 1348, 1258, 1256, - 1257, 1259, 1270, 1268, 1269, 1271, 1386, 1384, 1385, 1387, 1400, 1399, - 1456, 1454, 1455, 1457, 1300, 1299, 1295, 1293, 1294, 1296, 1304, 1302, - 1303, 1305, 1584, 1583, 1582, 1581, 2368, 2367, 2376, 2375, 2372, 2371, - 2370, 2369, 2380, 2379, 2366, 2374, 2373, 2382, 2378, 2377, 2381, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 1390, 1388, 1389, 1391, 1553, 1552, - 1605, 1604, 1602, 1601, 1551, 1563, 1562, 1351, 1350, 1354, 1353, 1618, - 1616, 1617, 1619, 1554, 1555, 2058, 2057, 2060, 2059, 2079, 2078, 2087, - 2086, 2077, 2076, 2083, 2082, 2063, 2061, 2062, 2112, 2110, 2111, 1238, - 1236, 1237, 1239, 2069, 2067, 2073, 2056, 2081, 1660, 1651, 1656, 1663, - 1658, 1669, 2021, 2009, 2016, 2029, 2032, 2037, 2039, 2044, 2041, 2050, - 1738, 1744, 1723, 1718, 1777, 1773, 1779, 1928, 1921, 1933, 1941, 1900, - 1904, 1682, 1674, 1678, 1684, 2002, 1997, 2114, 1631, 1627, 1712, 1708, - 1696, 1701, 1692, 1699, 1694, 1703, 1882, 1878, 1880, 1884, 1753, 1755, - 1763, 1761, 1758, 1769, 1751, 1772, 1805, 1797, 1809, 1815, 1789, 1818, - 1836, 1825, 1830, 1840, 1819, 1841, 1857, 1847, 1869, 1862, 1865, 1872, - 1733, 1729, 1730, 1731, 2097, 2090, 2099, 2105, 2054, 2109, 2038, 1895, - 1643, 1949, 1952, 1956, 1950, 1953, 1955, 2085, 2084, 2071, 2075, 2055, - 2080, 1667, 1666, 1661, 1665, 1657, 1668, 2035, 2034, 2027, 2033, 2031, - 2036, 2048, 2047, 2042, 2046, 2040, 2049, 1693, 1702, 1879, 1883, 1752, - 1756, 1767, 1750, 1771, 1813, 1788, 1817, 1820, 1838, 1870, 1867, 1860, - 1866, 1864, 1871, 1642, 2107, 2094, 2103, 2093, 2053, 2108, 2068, 2066, - 2070, 2072, 2064, 1659, 1650, 1655, 1662, 1652, 2020, 2008, 2015, 2028, - 2010, 2043, 1737, 1743, 1722, 1717, 1776, 1778, 1927, 1920, 1932, 1940, - 1899, 1907, 1903, 1681, 1673, 1677, 1683, 2001, 2113, 1630, 1626, 1711, - 1707, 1695, 1700, 1691, 1698, 1881, 1877, 1754, 1762, 1760, 1757, 1768, - 1804, 1796, 1808, 1814, 1798, 1835, 1824, 1829, 1839, 1856, 1846, 1868, - 1861, 1848, 1732, 1728, 1734, 2096, 2089, 2098, 2104, 2091, 2074, 2065, - 1664, 1653, 2030, 2011, 2045, 2051, 1942, 1924, 1979, 1959, 1759, 1770, - 1816, 1863, 1849, 2106, 2092, 1957, 1951, 1954, 2000, 2004, 1633, 1635, - 1710, 1714, 1944, 1948, 1981, 1989, 1720, 1725, 1746, 1748, 1775, 1781, - 1906, 1911, 1680, 1688, 1970, 1965, 1984, 1978, 1987, 1946, 1909, 1686, - 1999, 2003, 1632, 1634, 1709, 1713, 1943, 1947, 1980, 1988, 1719, 1724, - 1745, 1747, 1774, 1780, 1905, 1910, 1679, 1687, 1968, 1963, 1982, 1976, - 1986, 1945, 1908, 1685, 1969, 1964, 1983, 1977, 1923, 1958, 1996, 1929, - 1922, 1934, 1971, 1966, 1985, 1998, 2115, 1644, 1645, 30650, 30651, 1892, - 1887, 1891, 1888, 1889, 1890, 1918, 1637, 1639, 1638, 1636, 1886, 1917, - 1640, 1991, 1893, 2018, 2007, 2006, 2005, 2013, 2023, 2025, 2024, 1740, - 1739, 1716, 1715, 1919, 1926, 1925, 1936, 1935, 1937, 1939, 1938, 1897, - 1896, 1902, 1961, 1960, 1967, 1973, 1972, 1975, 1974, 1671, 1676, 1675, - 1993, 1992, 1994, 1995, 1629, 1624, 1623, 1622, 1704, 1706, 1705, 1690, - 1689, 1875, 1873, 1794, 1795, 1792, 1799, 1800, 1807, 1806, 1811, 1810, - 1821, 1822, 1823, 1833, 1831, 1826, 1827, 40951, 40951, 1832, 1726, 1727, - 1844, 1843, 1854, 1853, 1852, 1859, 1858, 2101, 2100, 1654, 2019, 2017, - 2014, 2012, 2026, 2022, 1742, 1735, 1741, 1930, 1898, 1962, 1672, 1803, - 1812, 2088, 2095, 2102, 1837, 1876, 1845, 1874, 1793, 1625, 1766, 1850, - 1828, 1801, 1765, 1802, 1851, 1736, 1721, 1834, 1697, 1649, 1764, 1628, - 1901, 1931, 1855, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 1913, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 1914, 1885, 1646, 1647, 1842, 1912, 1894, 1641, 2052, 1915, - 1916, 1749, 32167, 1670, 1990, 1648, 38261, 38372, 38440, 38451, 38462, - 38473, 38484, 38495, 38506, 38262, 38273, 38284, 38295, 38306, 38317, - 38328, 31622, 31627, 31628, 31621, 31652, 31623, 31654, 31630, 31644, - 31626, 40951, 40951, 40951, 40951, 40951, 40951, 8360, 8362, 8192, 8193, - 8371, 8373, 8086, 8361, 8363, 8429, 8430, 8372, 8374, 8087, 8140, 8141, - 31653, 31624, 31625, 31639, 31651, 31636, 31648, 31634, 31646, 31638, - 31650, 31631, 31640, 31632, 31641, 31635, 31647, 31633, 31645, 31629, - 31642, 32661, 39263, 31637, 31649, 10541, 6129, 39141, 11256, 10540, - 6128, 39139, 33800, 33809, 33844, 40951, 33834, 33801, 33845, 33807, - 33808, 33811, 33815, 33810, 33814, 33812, 33816, 33843, 33791, 33793, - 33842, 33840, 33813, 33839, 33806, 40951, 33833, 33802, 33841, 33799, - 40951, 40951, 40951, 40951, 1092, 2387, 1074, 2389, 1104, 40951, 1089, - 1090, 1070, 1071, 1101, 1102, 2294, 2295, 2362, 2363, 1289, 1153, 1152, - 1143, 1142, 1571, 1570, 1146, 1145, 1588, 1586, 1587, 1589, 1163, 1162, - 1178, 1176, 1177, 1179, 1514, 1513, 1523, 1521, 1522, 1516, 1535, 1533, - 1534, 1536, 1320, 1318, 1319, 1321, 1286, 1284, 1285, 1287, 1358, 1356, - 1357, 1359, 1202, 1201, 1531, 1530, 1449, 1448, 1613, 1612, 1478, 1476, - 1477, 1479, 1484, 1482, 1483, 1485, 1465, 1463, 1464, 1466, 1210, 1208, - 1209, 1211, 1497, 1495, 1496, 1498, 1609, 1607, 1608, 1610, 1121, 1119, - 1120, 1122, 1265, 1263, 1264, 1266, 1249, 1247, 1248, 1250, 1431, 1429, - 1430, 1432, 1334, 1332, 1333, 1335, 1370, 1368, 1369, 1371, 1379, 1377, - 1378, 1380, 1410, 1408, 1409, 1411, 1308, 1306, 1307, 1309, 1575, 1574, - 1161, 1160, 1598, 1596, 1597, 1599, 1787, 1786, 1783, 1782, 1785, 1784, - 1791, 1790, 40951, 40951, 40755, 40951, 17625, 17629, 17597, 17613, - 17599, 17611, 17610, 17540, 17603, 17612, 17600, 17535, 17628, 17633, - 17607, 17620, 17622, 17619, 17618, 17615, 17614, 17617, 17616, 17623, - 17621, 17536, 17606, 17542, 17624, 17627, 17630, 17534, 17543, 17544, - 17545, 17546, 17547, 17548, 17549, 17550, 17551, 17552, 17553, 17554, - 17555, 17556, 17557, 17558, 17559, 17560, 17561, 17562, 17563, 17564, - 17565, 17566, 17567, 17568, 17541, 17605, 17604, 17533, 17595, 17626, - 17569, 17570, 17571, 17572, 17573, 17574, 17575, 17576, 17577, 17578, - 17579, 17580, 17581, 17582, 17583, 17584, 17585, 17586, 17587, 17588, - 17589, 17590, 17591, 17592, 17593, 17594, 17539, 17635, 17602, 17632, - 17538, 17601, 19098, 19091, 19093, 19097, 19089, 19081, 19036, 19038, - 19040, 19037, 19039, 19032, 19034, 19033, 19035, 19090, 19082, 19084, - 19086, 19083, 19085, 19057, 19059, 19061, 19058, 19060, 19041, 19043, - 19045, 19042, 19044, 19072, 19074, 19076, 19073, 19075, 19047, 19049, - 19051, 19048, 19050, 19052, 19054, 19056, 19053, 19055, 19062, 19064, - 19066, 19063, 19065, 19077, 19079, 19078, 19067, 19069, 19071, 19068, - 19070, 19080, 19046, 19088, 19087, 19031, 18981, 18998, 18982, 18983, - 18984, 18985, 19019, 19000, 18989, 18994, 18993, 18992, 18996, 18990, - 18991, 18995, 19017, 18987, 18999, 18988, 19002, 19001, 19016, 19011, - 18997, 19010, 18980, 19018, 18986, 19025, 40951, 40951, 40951, 19026, - 19027, 19005, 19006, 19013, 19012, 40951, 40951, 19004, 19003, 19028, - 19022, 19023, 19029, 40951, 40951, 19008, 19030, 19021, 19020, 19024, - 19009, 40951, 40951, 19014, 19007, 19015, 40951, 40951, 40951, 17537, - 17598, 17596, 17609, 17634, 17608, 17631, 40951, 19095, 19092, 19096, - 19094, 19101, 19099, 19100, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 20788, 20790, 20789, 29933, 31859, 40951, - 40951, 24968, 24994, 24987, 25020, 24978, 24969, 24998, 24964, 24976, - 25006, 25009, 25003, 40951, 24992, 25019, 25023, 25002, 25017, 25024, - 25031, 25034, 24979, 25030, 24977, 24980, 24963, 24986, 24989, 25012, - 25013, 24971, 25028, 24993, 24974, 25010, 24972, 25029, 24988, 24996, - 40951, 25021, 24985, 25005, 24970, 24981, 24995, 24966, 25000, 24975, - 25007, 25008, 24965, 24991, 24967, 25018, 25011, 25025, 24999, 25001, - 40951, 24973, 25027, 40951, 24984, 24983, 24997, 25033, 25026, 25036, - 25004, 24982, 25014, 25022, 24990, 25015, 25016, 25032, 25035, 40951, - 40951, 25046, 25047, 25049, 25048, 25037, 25038, 25045, 25039, 25040, - 25050, 25041, 25042, 25043, 25044, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 24852, - 24851, 24853, 24840, 24841, 24842, 24843, 24844, 24845, 24846, 24848, - 24847, 24850, 24849, 24858, 24855, 24856, 24854, 24857, 24957, 24958, - 24860, 24859, 24861, 24960, 24959, 24863, 24864, 24865, 24862, 24866, - 24869, 24868, 24870, 24871, 24872, 24961, 24873, 24874, 24867, 24877, - 24878, 24876, 24875, 24879, 24880, 24881, 24882, 24883, 24884, 24887, - 24888, 24889, 24886, 24890, 24885, 24891, 24892, 24893, 24894, 24895, - 24896, 24897, 24898, 24899, 24900, 24902, 24901, 24903, 24904, 24906, - 24907, 24908, 24905, 24909, 24910, 24911, 24912, 24914, 24913, 24915, - 24916, 24962, 24917, 24918, 24920, 24921, 24922, 24919, 24923, 24924, - 24925, 24926, 24927, 24955, 24935, 24936, 24937, 24938, 24939, 24940, - 24941, 24942, 24943, 24944, 24945, 24946, 24947, 24948, 24949, 24950, - 24951, 24952, 24953, 24954, 24928, 24929, 24930, 24931, 24932, 24933, - 24934, 24956, 40951, 40951, 40951, 40951, 40951, 112, 113, 159, 40951, - 40951, 40951, 40951, 156, 151, 146, 126, 121, 139, 134, 114, 129, 154, - 149, 144, 124, 119, 140, 135, 115, 130, 157, 152, 147, 127, 122, 142, - 137, 117, 132, 158, 153, 148, 128, 123, 143, 138, 118, 133, 155, 150, - 145, 125, 120, 141, 136, 116, 131, 40951, 40951, 40951, 111, 107, 109, - 110, 108, 103, 104, 105, 106, 18166, 18163, 18167, 18153, 18148, 18154, - 18157, 18149, 18159, 18168, 18151, 18161, 18155, 18164, 18158, 18160, - 18170, 18152, 18162, 18156, 18165, 18169, 18150, 18171, 18183, 18192, - 18182, 18178, 18191, 18173, 18179, 18195, 18199, 18200, 18181, 18184, - 18190, 18189, 18197, 18198, 18180, 18187, 18193, 18188, 18177, 18196, - 18185, 18172, 18174, 18194, 18186, 18175, 18176, 18418, 18419, 18617, - 18613, 18654, 18619, 18349, 18423, 18616, 18612, 18355, 18354, 18415, - 18397, 18413, 18422, 18417, 18203, 18202, 18656, 18615, 18657, 18420, - 18611, 18393, 29360, 40951, 32211, 32214, 32209, 32212, 32183, 32213, - 32181, 32184, 32210, 32182, 32215, 32180, 2526, 40951, 40951, 40951, - 18610, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 31405, 31406, - 31417, 31386, 31389, 31420, 31398, 31397, 31418, 31425, 31384, 31411, - 31390, 31403, 31404, 31413, 31402, 31383, 31387, 31394, 31392, 31414, - 31391, 31382, 31412, 31399, 31400, 31385, 31388, 31410, 31424, 31395, - 31419, 31381, 31407, 31426, 31408, 31409, 31401, 31423, 31422, 31396, - 31415, 31416, 31421, 31393, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 25283, 25285, 25278, 25279, 25290, 25289, - 25292, 25300, 25302, 25281, 25293, 25276, 25296, 25294, 25274, 25287, - 25275, 25288, 25299, 25295, 25277, 25297, 25298, 25280, 25282, 25284, - 25286, 25291, 25301, 40951, 40951, 40951, 6039, 6050, 6041, 6012, 6035, - 6051, 6013, 6040, 6057, 6055, 6015, 6056, 6042, 6030, 6025, 6026, 6024, - 6010, 6033, 6023, 6058, 6020, 6032, 6049, 6029, 6053, 6043, 6038, 6047, - 6048, 6021, 6034, 6045, 6046, 6027, 6028, 6022, 6054, 6011, 6031, 6036, - 6052, 6016, 6017, 6018, 6019, 6014, 6044, 6037, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 8571, 8569, 8567, 8566, 8563, 8562, 8565, 8564, 8570, 8568, - 8561, 8560, 8558, 8549, 8547, 8556, 8554, 8545, 8551, 8552, 8559, 8557, - 8548, 8546, 8555, 8553, 8544, 8550, 40951, 40951, 40951, 40951, 30215, - 30209, 30195, 30210, 30182, 30212, 30214, 30211, 30206, 30202, 30194, - 30190, 30191, 30192, 30184, 30216, 30205, 30198, 30196, 30186, 30183, - 30207, 30200, 30188, 30204, 30193, 30189, 30187, 30208, 30203, 30201, - 30185, 30220, 30218, 30219, 30217, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 30213, 30199, 30197, 18013, 18029, 18037, - 18031, 18012, 18022, 18016, 18015, 18024, 18034, 18038, 18035, 18032, - 18020, 18036, 18027, 18021, 18019, 18023, 18033, 18025, 18026, 18028, - 18017, 18014, 18030, 18018, 40951, 40951, 40951, 40951, 40951, 30287, - 30286, 30283, 30256, 30257, 30279, 30254, 30280, 30255, 30259, 30288, - 30281, 30262, 30263, 30270, 30264, 30282, 30267, 30269, 30290, 30253, - 30266, 30265, 30277, 30274, 30284, 30285, 30258, 30289, 30268, 30271, - 30272, 30273, 30276, 30261, 30278, 30275, 30260, 8386, 8384, 8382, 8383, - 8385, 40951, 40951, 40951, 40951, 40951, 37709, 37712, 37716, 37720, - 37713, 37717, 37735, 37731, 37718, 37728, 37730, 37719, 37725, 37721, - 37736, 37714, 37733, 37732, 37724, 37710, 37734, 37723, 37711, 37722, - 37727, 37715, 37729, 37737, 37738, 37726, 40951, 37739, 30296, 30338, - 30339, 30319, 30320, 30317, 30318, 30316, 30331, 30308, 30309, 30313, - 30314, 30303, 30306, 30307, 30312, 30335, 30300, 30332, 30321, 30322, - 30325, 30326, 30327, 30336, 30310, 30311, 30323, 30324, 30334, 30330, - 30337, 30328, 30329, 30333, 40951, 40951, 40951, 40951, 30297, 30298, - 30299, 30315, 30304, 30305, 30301, 30302, 30340, 30295, 30292, 30293, - 30291, 30294, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 10594, 10593, 10589, 10590, 10591, 10592, - 10600, 10599, 10595, 10596, 10597, 10598, 10617, 10602, 10616, 10613, - 10618, 10611, 10608, 10604, 10609, 10607, 10610, 10615, 10614, 10584, - 10612, 10583, 10603, 10579, 10606, 10580, 10605, 10587, 10585, 10586, - 10581, 10582, 10601, 10588, 10634, 10633, 10629, 10630, 10631, 10632, - 10640, 10639, 10635, 10636, 10637, 10638, 10657, 10642, 10656, 10653, - 10658, 10651, 10648, 10644, 10649, 10647, 10650, 10655, 10654, 10624, - 10652, 10623, 10643, 10619, 10646, 10620, 10645, 10627, 10625, 10626, - 10621, 10622, 10641, 10628, 32797, 32803, 32814, 32811, 32801, 32800, - 32799, 32778, 32806, 32784, 32813, 32809, 32812, 32815, 32802, 32810, - 32789, 32808, 32805, 32783, 32788, 32790, 32787, 32782, 32776, 32773, - 32795, 32804, 32793, 32777, 32798, 32816, 32780, 32774, 32786, 32817, - 32794, 32791, 32792, 32775, 32771, 32796, 32772, 32781, 32770, 32779, - 32785, 32807, 30729, 30747, 30753, 30751, 30754, 30735, 30732, 30752, - 30737, 30736, 30733, 30731, 30749, 30748, 30739, 30734, 30742, 30738, - 30743, 30744, 30750, 30755, 30728, 30745, 30756, 30740, 30757, 30730, - 30746, 30741, 40951, 40951, 30764, 30766, 30763, 30762, 30759, 30758, - 30761, 30760, 30767, 30765, 40951, 40951, 40951, 40951, 40951, 40951, - 30656, 30657, 30658, 30659, 30684, 30677, 30663, 30660, 30666, 30676, - 30675, 30690, 30669, 30664, 30668, 30685, 30686, 30687, 30670, 30671, - 30688, 30665, 30681, 30680, 30674, 30662, 30673, 30661, 30672, 30678, - 30691, 30689, 30667, 30679, 30683, 30682, 40951, 40951, 40951, 40951, - 30692, 30693, 30694, 30695, 30720, 30713, 30699, 30696, 30702, 30712, - 30711, 30726, 30705, 30700, 30704, 30721, 30722, 30723, 30706, 30707, - 30724, 30701, 30717, 30716, 30710, 30698, 30709, 30697, 30708, 30714, - 30727, 30725, 30703, 30715, 30719, 30718, 40951, 40951, 40951, 40951, - 16693, 16684, 16673, 16672, 16675, 16664, 16674, 16671, 16670, 16685, - 16661, 16660, 16686, 16694, 16687, 16677, 16663, 16662, 16688, 16667, - 16666, 16665, 16695, 16689, 16690, 16669, 16668, 16679, 16678, 16681, - 16680, 16696, 16691, 16692, 16697, 16683, 16682, 16659, 16658, 16676, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 6071, 6120, 6087, - 6083, 6085, 6110, 6084, 6108, 6105, 6074, 6107, 6109, 6088, 6099, 6095, - 6090, 6118, 6082, 6073, 6091, 6094, 6096, 6121, 6112, 6070, 6076, 6077, - 6079, 6113, 6111, 6116, 6080, 6100, 6092, 6119, 6104, 6115, 6081, 6075, - 6098, 6086, 6117, 6102, 6114, 6103, 6101, 6089, 6078, 6072, 6106, 6097, - 6093, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 6122, 38912, 38881, 38882, 38892, 38891, 38894, 38893, - 38884, 38883, 38901, 38909, 40951, 38900, 38899, 38885, 38886, 38902, - 38910, 38888, 38887, 38903, 38890, 38889, 38913, 38904, 38911, 38905, - 40951, 38896, 38895, 38898, 38897, 38914, 38906, 38907, 40951, 38915, - 38908, 40951, 38947, 38916, 38917, 38927, 38926, 38929, 38928, 38919, - 38918, 38936, 38944, 40951, 38935, 38934, 38920, 38921, 38937, 38945, - 38923, 38922, 38938, 38925, 38924, 38948, 38939, 38946, 38940, 40951, - 38931, 38930, 38933, 38932, 38949, 38941, 38942, 40951, 38950, 38943, - 40951, 40951, 40951, 37427, 37428, 37441, 37401, 37430, 37429, 37432, - 37408, 37431, 37424, 37423, 37442, 37398, 37404, 37397, 37403, 37411, - 37410, 37445, 37399, 37434, 37426, 37425, 37402, 37409, 37405, 37421, - 37413, 37443, 37420, 37419, 37418, 37415, 37414, 37436, 37435, 37446, - 37444, 37438, 37407, 37437, 37406, 37447, 37400, 37440, 37439, 37396, - 37417, 37416, 37433, 37412, 37422, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 24819, 24820, 24821, - 24822, 24823, 24824, 24825, 24826, 24827, 24758, 24759, 24760, 24761, - 24762, 24771, 24763, 24764, 24765, 24766, 24767, 24768, 24769, 24770, - 24772, 24773, 24774, 24775, 24839, 24776, 24777, 24778, 24779, 24780, - 24781, 24782, 24783, 24784, 24785, 24786, 24787, 24788, 24789, 24790, - 24791, 24792, 24793, 24794, 24795, 24796, 24797, 24798, 24799, 24800, - 24801, 24802, 24803, 24804, 24805, 24806, 24807, 24808, 24809, 24810, - 24811, 24812, 24813, 24814, 24815, 24816, 24817, 24818, 24499, 24835, - 24828, 24500, 24829, 24830, 24831, 24832, 24501, 24836, 24837, 24833, - 24834, 24838, 24505, 24506, 24507, 24508, 24509, 24510, 24511, 24512, - 24502, 24503, 24504, 24516, 24517, 24518, 24513, 24514, 24515, 24519, - 24520, 24521, 24522, 24523, 24524, 24527, 24528, 24529, 24530, 24531, - 24532, 24533, 24534, 24535, 24536, 24537, 24538, 24539, 24540, 24541, - 24542, 24543, 24544, 24545, 24546, 24547, 24548, 24549, 24550, 24551, - 24552, 24553, 24554, 24555, 24556, 24557, 24558, 24559, 24560, 24561, - 24562, 24563, 24564, 24565, 24566, 24567, 24568, 24569, 24570, 24571, - 24572, 24573, 24574, 24575, 24576, 24525, 24526, 24577, 24578, 24579, - 24580, 24581, 24582, 24583, 24584, 24585, 24586, 24587, 24588, 24589, - 24590, 24591, 24592, 24593, 24594, 24595, 24596, 24597, 24598, 24599, - 24600, 24601, 24602, 24603, 24604, 24605, 24606, 24607, 24608, 24609, - 24641, 24642, 24643, 24644, 24645, 24646, 24647, 24648, 24649, 24610, - 24611, 24612, 24613, 24614, 24615, 24616, 24617, 24618, 24619, 24620, - 24621, 24622, 24623, 24624, 24625, 24626, 24627, 24628, 24629, 24630, - 24631, 24632, 24633, 24634, 24635, 24636, 24637, 24638, 24639, 24640, - 24656, 24657, 24658, 24659, 24660, 24661, 24662, 24663, 24664, 24665, - 24666, 24667, 24668, 24669, 24670, 24671, 24672, 24673, 24674, 24675, - 24650, 24651, 24652, 24653, 24654, 24655, 24676, 24677, 24678, 24679, - 24680, 24681, 24682, 24683, 24718, 24719, 24720, 24721, 24722, 24723, - 24724, 24725, 24726, 24727, 24684, 24685, 24686, 24687, 24688, 24689, - 24690, 24691, 24692, 24693, 24694, 24695, 24696, 24697, 24698, 24699, - 24700, 24701, 24702, 24703, 24709, 24710, 24711, 24712, 24713, 24714, - 24715, 24716, 24717, 24704, 24705, 24706, 24707, 24708, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 24739, 24734, 24737, - 24736, 24740, 24735, 24733, 24738, 24732, 24728, 24731, 24730, 24729, - 24746, 24741, 24745, 24742, 24743, 24744, 24747, 24749, 24748, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 24750, - 24751, 24752, 24753, 24754, 24755, 24756, 24757, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 27868, 27989, 27988, 27853, 27869, 27857, 40951, 27887, 27889, - 27888, 27883, 27882, 27880, 27881, 27942, 27875, 27899, 27939, 27863, - 27903, 27864, 27907, 27870, 27909, 27886, 27923, 27924, 27922, 27866, - 27920, 27925, 27926, 27967, 27968, 27931, 27867, 27876, 27982, 27964, - 27965, 27938, 27937, 27872, 27952, 27955, 27956, 27953, 27951, 27979, - 40951, 27874, 27794, 27841, 27689, 27772, 27801, 27686, 27843, 27944, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 10008, - 10009, 10010, 10011, 10012, 10002, 40951, 40951, 10003, 40951, 9958, - 9959, 9960, 9961, 9962, 9963, 9964, 9965, 9966, 9967, 9968, 9969, 9970, - 9971, 9972, 9973, 9974, 9975, 9976, 9977, 9978, 9979, 9980, 9981, 9982, - 9983, 9984, 9985, 9986, 9987, 9988, 9989, 9990, 9991, 9992, 9993, 9994, - 9995, 9996, 9997, 9998, 9999, 10000, 10001, 40951, 10006, 10007, 40951, - 40951, 40951, 10004, 40951, 40951, 10005, 20610, 20621, 20612, 20606, - 20618, 20623, 20613, 20619, 20604, 20617, 20620, 20607, 20625, 20622, - 20614, 20611, 20624, 20615, 20608, 20609, 20616, 20605, 40951, 20626, - 20601, 20597, 20600, 20598, 20596, 20602, 20603, 20599, 31035, 31046, - 31037, 31031, 31043, 31048, 31038, 31044, 31029, 31042, 31045, 31032, - 31050, 31028, 31047, 31039, 31036, 31049, 31040, 31033, 31034, 31041, - 31030, 31027, 31051, 31058, 31053, 31054, 31057, 31056, 31055, 31052, - 28806, 28821, 28811, 28832, 28823, 28817, 28813, 28829, 28834, 28824, - 28830, 28815, 28809, 28828, 28810, 28831, 28807, 28818, 28814, 28836, - 28812, 28833, 28825, 28822, 28835, 28826, 28819, 28820, 28808, 28827, - 28816, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 28841, - 28838, 28839, 28844, 28845, 28843, 28840, 28837, 28842, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 19658, 19674, 19666, 19665, - 19671, 19676, 19660, 19672, 19661, 19670, 19673, 19663, 19678, 19675, - 19667, 19659, 19677, 19668, 19664, 40951, 19669, 19662, 40951, 40951, - 40951, 40951, 40951, 19679, 19683, 19682, 19681, 19680, 31429, 31448, - 31444, 31431, 31432, 31440, 31441, 31433, 31439, 31442, 31445, 31447, - 31450, 31446, 31437, 31430, 31449, 31435, 31434, 31443, 31436, 31438, - 31455, 31454, 31451, 31456, 31452, 31453, 40951, 40951, 40951, 31457, - 25309, 25315, 25319, 25317, 25311, 25327, 25320, 25328, 25321, 25305, - 25322, 25313, 25323, 25325, 25308, 25303, 25326, 25318, 25324, 25307, - 25304, 25310, 25312, 25306, 25314, 25316, 40951, 40951, 40951, 40951, - 40951, 25329, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 27402, 27403, 27404, 27405, - 27401, 27400, 27376, 27377, 27398, 27397, 27380, 27381, 27382, 27383, - 27378, 27379, 27396, 27393, 27392, 27384, 27385, 27386, 27394, 27399, - 27387, 27388, 27389, 27390, 27391, 27395, 27406, 27407, 27298, 27319, - 27320, 27321, 27318, 27317, 27310, 27314, 27313, 27303, 27304, 27316, - 27312, 27308, 27307, 27305, 27299, 27306, 27309, 27315, 27300, 27301, - 27302, 27311, 40951, 40951, 40951, 40951, 27286, 27291, 27323, 27322, - 27372, 27364, 27358, 27335, 27329, 27352, 27346, 27324, 27341, 27370, - 27368, 27362, 27339, 27333, 27356, 27350, 40951, 40951, 27373, 27365, - 27359, 27336, 27330, 27353, 27347, 27326, 27343, 27375, 27367, 27361, - 27338, 27332, 27355, 27349, 27328, 27345, 27371, 27369, 27363, 27340, - 27334, 27357, 27351, 27325, 27342, 27374, 27366, 27360, 27337, 27331, - 27354, 27348, 27327, 27344, 27290, 27296, 27295, 27289, 27288, 27293, - 27292, 27287, 27297, 27294, 21668, 21690, 21692, 21688, 40951, 21689, - 21691, 40951, 40951, 40951, 40951, 40951, 21693, 21684, 21687, 21686, - 21634, 21632, 21656, 21655, 40951, 21654, 21653, 21662, 40951, 21642, - 21638, 21637, 21645, 21644, 21641, 21640, 21639, 21647, 21646, 21643, - 21658, 21657, 21652, 21651, 21664, 21666, 21665, 21663, 21660, 21648, - 21649, 21650, 21667, 21661, 21633, 21635, 21636, 21659, 40951, 40951, - 21682, 21683, 21685, 40951, 40951, 40951, 40951, 21694, 21631, 21630, - 21629, 21628, 21670, 21669, 21671, 21672, 21695, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 21676, 21681, 21674, 21673, 21680, 21678, - 21677, 21675, 21679, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 30405, 30401, 30406, 30411, 30402, 30409, 30395, 30403, 30407, 30399, - 30394, 30390, 30408, 30391, 30393, 30392, 30410, 30383, 30384, 30386, - 30389, 30387, 30388, 30398, 30400, 30385, 30404, 30397, 30396, 30413, - 30412, 30414, 30226, 30244, 30225, 30235, 30247, 30248, 30237, 30241, - 30239, 30232, 30236, 30228, 30243, 30227, 30249, 30238, 30240, 30221, - 30222, 30245, 30224, 30246, 30223, 30231, 30233, 30229, 30242, 30230, - 30234, 30252, 30251, 30250, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 25610, 25614, 25613, 25618, - 25617, 25615, 25639, 25642, 25658, 25622, 25621, 25620, 25619, 25640, - 25632, 25638, 25624, 25634, 25623, 25636, 25616, 25631, 25645, 25641, - 25628, 25612, 25611, 25644, 25643, 25629, 25626, 25635, 25625, 25637, - 25630, 25627, 25633, 25660, 25659, 40951, 40951, 40951, 40951, 25646, - 25650, 25649, 25648, 25647, 25657, 25655, 25653, 25652, 25651, 25656, - 25654, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 2542, 2543, 2549, 2545, 2548, 2544, 2546, 2547, 2585, 2586, 2575, 2576, - 2577, 2578, 2573, 2574, 2590, 2563, 2562, 2561, 2552, 2550, 2551, 2587, - 2589, 2572, 2570, 2582, 2581, 2571, 2593, 2588, 2580, 2579, 2557, 2556, - 2555, 2560, 2559, 2558, 2592, 2553, 2568, 2569, 2595, 2594, 2591, 2567, - 2584, 2565, 2583, 2564, 2566, 2554, 40951, 40951, 40951, 2596, 37309, - 33835, 22667, 22662, 22668, 22663, 20752, 20763, 20754, 20748, 20760, - 20765, 20755, 20761, 20746, 20759, 20762, 20749, 20767, 20764, 20756, - 20753, 20766, 20757, 20750, 20751, 20758, 20747, 40951, 40951, 20772, - 20769, 20770, 20775, 20771, 20768, 20773, 20774, 20721, 20735, 20726, - 20722, 20732, 20725, 20727, 20733, 20719, 20731, 20734, 20723, 20724, - 20736, 20728, 20737, 20729, 20730, 20720, 40951, 40951, 40951, 40951, - 40951, 20742, 20739, 20740, 20745, 20741, 20738, 20743, 20744, 31690, - 31704, 31695, 31691, 31701, 31694, 31696, 31702, 31700, 31703, 31692, - 31693, 31705, 31697, 31707, 31698, 31699, 31706, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 31715, 31716, 31688, 31689, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 31712, 31709, 31710, 31714, 31711, 31708, 31713, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 30415, 30457, 30458, - 30447, 30483, 30476, 30450, 30451, 30485, 30428, 30468, 30416, 30461, - 30430, 30470, 30418, 30462, 30429, 30469, 30417, 30446, 30482, 30436, - 30475, 30425, 30465, 30419, 30463, 30452, 30486, 30431, 30471, 30420, - 30441, 30444, 30432, 30421, 30459, 30439, 30478, 30437, 30477, 30440, - 30479, 30467, 30438, 30460, 30445, 30453, 30448, 30443, 30481, 30433, - 30472, 30449, 30484, 30454, 30487, 30434, 30473, 30422, 30426, 30423, - 30427, 30466, 30442, 30480, 30435, 30474, 30424, 30464, 30455, 30456, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 30074, 30077, 30100, 30075, 30089, - 30085, 30091, 30101, 30076, 30079, 30121, 30102, 30103, 30092, 30093, - 30104, 30122, 30123, 30105, 30106, 30078, 30118, 30094, 30095, 30080, - 30082, 30086, 30114, 30116, 30110, 30112, 30115, 30107, 30081, 30108, - 30124, 30087, 30088, 30096, 30083, 30097, 30090, 30117, 30120, 30111, - 30113, 30109, 30098, 30099, 30084, 30119, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 30125, - 30128, 30151, 30126, 30140, 30136, 30142, 30152, 30127, 30130, 30172, - 30153, 30154, 30143, 30144, 30155, 30173, 30174, 30156, 30157, 30129, - 30169, 30145, 30146, 30131, 30133, 30137, 30165, 30167, 30161, 30163, - 30166, 30158, 30132, 30159, 30175, 30138, 30139, 30147, 30134, 30148, - 30141, 30168, 30171, 30162, 30164, 30160, 30149, 30150, 30135, 30170, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 30178, 30177, 30181, - 30176, 30179, 30180, 19611, 19598, 19606, 19590, 19589, 19603, 19599, - 19602, 19587, 19600, 19584, 19583, 19592, 19591, 19610, 19597, 19596, - 19588, 19601, 19604, 19605, 19595, 19608, 19585, 19609, 19586, 19593, - 19594, 19607, 19618, 19620, 19622, 19619, 19621, 19613, 19612, 19617, - 19614, 19616, 19615, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 19629, 19631, 19628, 19627, 19624, 19623, 19626, 19625, 19632, - 19630, 40951, 40951, 40951, 40951, 40951, 40951, 17713, 17715, 17712, - 17711, 17708, 17707, 17710, 17709, 17716, 17714, 17699, 17700, 17701, - 17698, 17702, 17696, 17673, 17657, 17665, 17663, 17656, 17662, 17668, - 17670, 17664, 17660, 17658, 17671, 17672, 17669, 17667, 17654, 17659, - 17655, 17666, 17661, 17652, 17653, 40951, 40951, 40951, 17697, 17651, - 17649, 17648, 17650, 17704, 17703, 17695, 17679, 17687, 17685, 17678, - 17684, 17690, 17692, 17686, 17682, 17680, 17693, 17694, 17691, 17689, - 17676, 17681, 17677, 17688, 17683, 17674, 17675, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 17705, 17706, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 32268, 32266, 32265, 32262, 32261, - 32264, 32263, 32269, 32267, 32260, 32259, 32257, 32248, 32246, 32255, - 32253, 32244, 32250, 32251, 32258, 32256, 32247, 32245, 32254, 32252, - 32243, 32249, 32240, 32241, 32239, 32242, 40951, 39408, 39442, 39422, - 39421, 39427, 39426, 39404, 39403, 39402, 39413, 39434, 39407, 39438, - 39441, 39440, 39437, 39445, 39424, 39423, 39425, 39406, 39428, 39439, - 39409, 39433, 39444, 39429, 39430, 39417, 39415, 39414, 39416, 39418, - 39405, 39420, 39443, 39431, 39432, 39411, 39412, 39435, 39410, 40951, - 39400, 39399, 39401, 40951, 40951, 39419, 39436, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 1195, 1490, 1326, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 1061, 2351, 2352, 2349, 30345, 30353, 30367, 30354, 30358, 30364, 30355, - 30370, 30359, 30365, 30363, 30366, 30357, 30372, 30368, 30347, 30348, - 30360, 30346, 30344, 30371, 30361, 30349, 30350, 30356, 30362, 30369, - 30351, 30352, 30379, 30377, 30374, 30382, 30381, 30378, 30376, 30375, - 30380, 30343, 30373, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 33894, 33908, 33896, 33905, 33912, 33900, 33906, 33904, 33907, - 33897, 33914, 33910, 33901, 33895, 33913, 33902, 33899, 33903, 33911, - 33909, 33898, 33893, 33888, 33886, 33889, 33887, 33892, 33891, 33883, - 33882, 33884, 33890, 33885, 33915, 33918, 33917, 33916, 33921, 33922, - 33919, 33923, 33920, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 30492, 30504, 30502, 30507, 30496, - 30501, 30500, 30503, 30494, 30509, 30505, 30497, 30508, 30498, 30493, - 30499, 30506, 30495, 30491, 30490, 30489, 30488, 30513, 30510, 30511, - 30512, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 6491, - 6485, 6499, 6493, 6488, 6496, 6502, 6484, 6494, 6497, 6495, 6498, 6489, - 6504, 6500, 6486, 6492, 6503, 6490, 6487, 6501, 6509, 6506, 6507, 6511, - 6508, 6505, 6510, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 16720, 16731, 16722, 16716, 16728, 16733, 16723, 16729, - 16714, 16727, 16730, 16717, 16735, 16732, 16724, 16721, 16734, 16725, - 16718, 16719, 16726, 16715, 16736, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 4635, 4640, 4638, 4637, 4639, 4562, 4563, - 4581, 4582, 4579, 4580, 4574, 4575, 4576, 4577, 4608, 4564, 4555, 4565, - 4601, 4600, 4597, 4596, 4585, 4595, 4594, 4599, 4598, 4587, 4571, 4570, - 4567, 4566, 4586, 4573, 4572, 4569, 4568, 4588, 4603, 4602, 4593, 4592, - 4605, 4607, 4606, 4584, 4578, 4589, 4590, 4591, 4604, 4583, 4556, 4561, - 4560, 4645, 4644, 4654, 4655, 4648, 4649, 4650, 4651, 4652, 4653, 4656, - 4646, 4641, 4647, 4657, 4659, 4658, 4633, 4632, 4631, 4634, 4630, 40951, - 40951, 40951, 40951, 4626, 4624, 4621, 4612, 4614, 4619, 4617, 4609, - 4615, 4625, 4623, 4622, 4611, 4613, 4620, 4618, 4610, 4616, 4627, 4628, - 4666, 4668, 4665, 4664, 4661, 4660, 4663, 4662, 4669, 4667, 4636, 4558, - 4559, 4642, 4643, 4557, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 4629, 20979, 20981, 20983, 20939, 20940, 20949, 20950, - 20947, 20948, 20977, 20941, 20978, 20942, 20967, 20966, 20963, 20962, - 20951, 20961, 20960, 20965, 20964, 20953, 20944, 20943, 20936, 20934, - 20935, 20970, 20952, 20946, 20945, 20938, 20937, 20954, 20969, 20968, - 20959, 20958, 20974, 20976, 20971, 20973, 20975, 20955, 20956, 20957, - 20972, 20989, 20994, 20995, 20992, 20993, 20996, 20990, 20997, 20991, - 20982, 20980, 21000, 21001, 20998, 20984, 20985, 20987, 20986, 20988, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 20999, 40951, 40951, 33946, 33947, 33936, 33937, 33938, 33939, 33932, - 33933, 33943, 33935, 33948, 33944, 33949, 33945, 33940, 33942, 33941, - 33934, 33950, 33929, 33951, 33953, 33952, 33930, 33931, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 33960, 33962, 33959, 33958, 33955, - 33954, 33957, 33956, 33963, 33961, 40951, 40951, 40951, 40951, 40951, - 40951, 6174, 6176, 6175, 6170, 6172, 6173, 6171, 6159, 6158, 6155, 6154, - 6140, 6153, 6152, 6157, 6156, 6142, 6145, 6144, 6137, 6136, 6141, 6147, - 6146, 6139, 6138, 6143, 6163, 6162, 6151, 6150, 6165, 6148, 6149, 6166, - 6161, 6169, 6167, 6164, 6178, 6186, 6187, 6182, 6183, 6184, 6180, 6188, - 6181, 6189, 6206, 6205, 6190, 6204, 40951, 6199, 6201, 6198, 6197, 6194, - 6193, 6196, 6195, 6202, 6200, 6177, 6192, 6191, 6203, 6160, 6179, 6185, - 6168, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 25371, - 25373, 25375, 25372, 25374, 25363, 25362, 25359, 25358, 25357, 25356, - 25361, 25360, 25342, 25351, 25350, 25345, 25344, 25341, 25353, 25352, - 25347, 25346, 25343, 25365, 25364, 25355, 25354, 25368, 25349, 25367, - 25370, 25369, 25366, 25348, 25378, 25379, 25377, 25376, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 32741, 32744, 32748, - 32687, 32688, 32706, 32707, 32704, 32705, 32699, 32700, 32701, 32702, - 32733, 32689, 32734, 32690, 32726, 32725, 32722, 32721, 32710, 32720, - 32719, 32724, 32723, 32712, 32696, 32695, 32692, 32691, 32711, 32698, - 32697, 32694, 32693, 32713, 32728, 32727, 32718, 32717, 32730, 32732, - 32731, 32709, 32708, 32703, 32714, 32715, 32716, 32729, 32752, 32761, - 32762, 32755, 32756, 32757, 32758, 32759, 32760, 32763, 32753, 32764, - 32754, 32747, 32743, 32745, 32746, 32767, 32673, 32672, 32765, 32738, - 32735, 32742, 32750, 32684, 32749, 32751, 32739, 32680, 32682, 32679, - 32678, 32675, 32674, 32677, 32676, 32683, 32681, 32685, 32740, 32686, - 32766, 32736, 32737, 40951, 33649, 33647, 33646, 33643, 33642, 33645, - 33644, 33650, 33648, 33661, 33660, 33659, 33655, 33654, 33658, 33657, - 33653, 33656, 33651, 33652, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 22374, 22375, 22401, 22403, 22400, - 22376, 22402, 22377, 22391, 22390, 22366, 22364, 22365, 22384, 22389, - 22388, 22373, 22372, 40951, 22386, 22379, 22378, 22369, 22368, 22385, - 22381, 22380, 22371, 22367, 22370, 22387, 22393, 22392, 22363, 22361, - 22362, 22395, 22399, 22397, 22383, 22398, 22360, 22394, 22382, 22411, - 22414, 22415, 22418, 22416, 22412, 22417, 22413, 22408, 22407, 22406, - 22404, 22358, 22357, 22419, 22409, 22356, 22420, 22405, 22396, 22359, - 22410, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 28281, 28283, 28284, 28282, 28272, 28271, 28270, - 40951, 28269, 40951, 28268, 28267, 28260, 28259, 40951, 28254, 28262, - 28261, 28250, 28248, 28249, 28253, 28264, 28263, 28252, 28251, 28255, - 28274, 28273, 28266, 40951, 28265, 28277, 28280, 28258, 28276, 28279, - 28278, 28275, 28257, 28256, 28285, 40951, 40951, 40951, 40951, 40951, - 40951, 22435, 22436, 22447, 22448, 22445, 22446, 22466, 22437, 22467, - 22438, 22456, 22455, 22426, 22424, 22425, 22449, 22454, 22453, 22434, - 22433, 22432, 22451, 22442, 22441, 22429, 22427, 22439, 22428, 22450, - 22444, 22443, 22431, 22430, 22452, 22458, 22457, 22423, 22421, 22422, - 22463, 22465, 22440, 22462, 22464, 22459, 22460, 22461, 22470, 22471, - 22476, 22477, 22474, 22475, 22478, 22472, 22479, 22473, 22468, 22469, - 40951, 40951, 40951, 40951, 40951, 22486, 22488, 22485, 22484, 22481, - 22480, 22483, 22482, 22489, 22487, 40951, 40951, 40951, 40951, 40951, - 40951, 18095, 18096, 18099, 18102, 40951, 18052, 18053, 18066, 18067, - 18064, 18065, 18047, 18049, 40951, 40951, 18090, 18054, 40951, 40951, - 18089, 18055, 18086, 18085, 18082, 18081, 18070, 18080, 18079, 18084, - 18083, 18072, 18061, 18060, 18057, 18056, 18071, 18063, 18062, 18059, - 18058, 18073, 40951, 18088, 18087, 18078, 18077, 18092, 18094, 18093, - 40951, 18069, 18068, 40951, 18051, 18074, 18075, 18076, 18091, 40951, - 8077, 18097, 18098, 18104, 18113, 18114, 18107, 18108, 18109, 18110, - 40951, 40951, 18116, 18105, 40951, 40951, 18115, 18106, 18101, 40951, - 40951, 18117, 40951, 40951, 40951, 40951, 40951, 40951, 18103, 40951, - 40951, 40951, 40951, 40951, 18100, 18046, 18045, 18048, 18050, 18111, - 18112, 40951, 40951, 8257, 8258, 8256, 8255, 8254, 8253, 8252, 40951, - 40951, 40951, 8263, 8260, 8261, 8259, 8262, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 37588, 37589, 37612, - 37613, 37610, 37611, 37605, 37606, 37607, 37608, 40951, 37634, 40951, - 40951, 37590, 40951, 37633, 37591, 37630, 37629, 37626, 37625, 37614, - 37624, 37623, 37628, 37627, 37616, 37602, 37601, 37593, 37592, 37615, - 37604, 37603, 37595, 37594, 37617, 37632, 37631, 37622, 37621, 37636, - 37637, 37600, 37598, 37609, 37618, 37619, 37620, 37635, 37597, 37599, - 37596, 40951, 37639, 37650, 37659, 37660, 37653, 37654, 37655, 37656, - 37657, 37658, 40951, 37662, 40951, 40951, 37651, 40951, 37661, 37652, - 37583, 37644, 40951, 37640, 37647, 37646, 37641, 37584, 37638, 37587, - 37645, 37586, 37585, 40951, 37642, 37643, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 37649, 37648, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 29204, 29205, 29218, 29219, 29216, - 29217, 29200, 29201, 29202, 29203, 29244, 29206, 29245, 29207, 29232, - 29231, 29228, 29227, 29193, 29192, 29226, 29225, 29230, 29229, 29195, - 29194, 29213, 29212, 29209, 29208, 29197, 29215, 29214, 29211, 29210, - 29198, 29196, 29238, 29237, 29224, 29223, 29236, 29235, 29243, 29240, - 29239, 29234, 29233, 29242, 29220, 29221, 29222, 29241, 29258, 29267, - 29268, 29261, 29262, 29263, 29264, 29265, 29266, 29269, 29259, 29270, - 29260, 29253, 29246, 29249, 29254, 29247, 29248, 29251, 29274, 29255, - 29180, 29178, 29273, 29191, 29271, 29187, 29189, 29186, 29185, 29182, - 29181, 29184, 29183, 29190, 29188, 29179, 29257, 40951, 29272, 29256, - 29199, 29250, 29252, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 37311, 37312, 37313, 37331, 37332, 37329, 37330, - 37324, 37325, 37326, 37327, 37357, 37314, 37358, 37315, 37349, 37348, - 37345, 37344, 37333, 37343, 37342, 37347, 37346, 37335, 37321, 37320, - 37317, 37316, 37334, 37323, 37322, 37319, 37318, 37336, 37351, 37350, - 37341, 37340, 37354, 37356, 37355, 37353, 37328, 37337, 37338, 37339, - 37352, 37367, 37376, 37377, 37370, 37371, 37372, 37373, 37374, 37375, - 37378, 37365, 37368, 37379, 37366, 37369, 37359, 37362, 37364, 37363, - 37360, 37361, 37390, 37310, 37391, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 37386, 37388, 37385, 37384, 37381, 37380, 37383, - 37382, 37389, 37387, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 32855, - 32857, 32878, 32879, 32876, 32877, 32871, 32872, 32873, 32874, 32904, - 32858, 32905, 32859, 32896, 32895, 32892, 32891, 32880, 32890, 32889, - 32894, 32893, 32882, 32865, 32864, 32868, 32867, 32881, 32866, 32861, - 32870, 32869, 32883, 32898, 32897, 32888, 32887, 32901, 32903, 32902, - 32900, 32875, 32884, 32885, 32886, 32899, 32933, 32940, 32941, 32938, - 32939, 32936, 32937, 40951, 40951, 32942, 32934, 32943, 32935, 32926, - 32928, 32930, 32929, 32927, 32925, 32945, 32944, 32924, 32923, 32906, - 32907, 32908, 32854, 32921, 32920, 32918, 32916, 32917, 32909, 32910, - 32919, 32922, 32914, 32915, 32913, 32912, 32911, 32860, 32862, 32863, - 32856, 32931, 32932, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 27636, 27637, 27655, - 27656, 27653, 27654, 27648, 27649, 27650, 27651, 27682, 27638, 27683, - 27639, 27675, 27674, 27671, 27670, 27659, 27669, 27668, 27673, 27672, - 27661, 27645, 27644, 27641, 27640, 27660, 27647, 27646, 27643, 27642, - 27662, 27677, 27676, 27667, 27666, 27679, 27681, 27680, 27658, 27652, - 27663, 27664, 27665, 27678, 27657, 27611, 27620, 27621, 27614, 27615, - 27616, 27617, 27618, 27619, 27622, 27612, 27623, 27613, 27607, 27610, - 27609, 27606, 27625, 27624, 27684, 27608, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 27632, 27634, 27631, - 27630, 27627, 27626, 27629, 27628, 27635, 27633, 40951, 40951, 40951, - 40951, 40951, 40951, 28164, 28159, 28004, 28165, 28163, 28161, 28160, - 28021, 28022, 28155, 28157, 28156, 28166, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 35301, 35303, 35318, 35319, 35316, - 35317, 35343, 35304, 35344, 35305, 35333, 35332, 35329, 35328, 35320, - 35327, 35326, 35331, 35330, 35322, 35313, 35312, 35307, 35306, 35321, - 35315, 35314, 35309, 35308, 35323, 35335, 35334, 35325, 35324, 35340, - 35342, 35311, 35339, 35341, 35336, 35337, 35338, 35310, 35346, 35348, - 35349, 35354, 35355, 35352, 35353, 35356, 35350, 35357, 35351, 35347, - 35345, 35302, 35300, 40951, 40951, 40951, 40951, 40951, 40951, 35364, - 35366, 35363, 35362, 35359, 35358, 35361, 35360, 35367, 35365, 40951, - 40951, 40951, 40951, 40951, 40951, 28773, 28775, 28772, 28771, 28768, - 28767, 28770, 28769, 28776, 28774, 28723, 28725, 28722, 28721, 28718, - 28717, 28720, 28719, 28726, 28724, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 191, 190, 178, 181, 175, 167, 193, 192, 183, 195, - 189, 184, 174, 196, 177, 197, 180, 194, 164, 171, 170, 187, 166, 186, - 182, 188, 165, 40951, 40951, 162, 163, 161, 203, 204, 210, 211, 208, 209, - 212, 207, 213, 205, 206, 200, 40951, 40951, 40951, 40951, 222, 224, 221, - 220, 217, 216, 219, 218, 225, 223, 215, 214, 198, 199, 201, 202, 185, - 173, 172, 169, 168, 179, 176, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 11026, - 11027, 11042, 11043, 11040, 11041, 11068, 11028, 11069, 11029, 11060, - 11059, 11056, 11055, 11044, 11054, 11053, 11058, 11057, 11046, 11037, - 11036, 11031, 11030, 11045, 11039, 11038, 11033, 11032, 11047, 11062, - 11061, 11052, 11051, 11065, 11067, 11035, 11064, 11066, 11048, 11049, - 11050, 11063, 11034, 11072, 11077, 11078, 11075, 11076, 11070, 11071, - 11079, 11073, 11080, 11074, 11083, 11085, 11084, 11082, 11081, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 39052, - 39041, 39070, 39060, 39062, 39063, 39069, 39059, 39045, 39054, 39042, - 39072, 39068, 39047, 39061, 39058, 39046, 39055, 39064, 39053, 39071, - 39044, 39043, 39066, 39067, 39050, 39049, 39048, 39051, 39056, 39057, - 39065, 39084, 39073, 39102, 39092, 39094, 39095, 39101, 39091, 39077, - 39086, 39074, 39104, 39100, 39079, 39093, 39090, 39078, 39087, 39096, - 39085, 39103, 39076, 39075, 39098, 39099, 39082, 39081, 39080, 39083, - 39088, 39089, 39097, 39111, 39113, 39110, 39109, 39106, 39105, 39108, - 39107, 39114, 39112, 39123, 39122, 39121, 39117, 39116, 39120, 39119, - 39115, 39118, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 39124, 10942, 10943, 10950, 10951, 10948, - 10949, 10977, 40951, 40951, 10978, 40951, 40951, 10968, 10967, 10966, - 10965, 10954, 10964, 10963, 10972, 40951, 10956, 10938, 40951, 10945, - 10944, 10955, 10939, 10937, 10947, 10946, 10957, 10970, 10969, 10962, - 10961, 10973, 10941, 10940, 10974, 10953, 10975, 10958, 10959, 10960, - 10971, 10952, 10976, 10983, 10987, 10988, 10985, 10986, 10989, 40951, - 10984, 10990, 40951, 40951, 10982, 10980, 10979, 10991, 10996, 10993, - 10997, 10992, 10981, 10926, 10994, 10995, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 10933, 10935, 10932, 10931, 10928, - 10927, 10930, 10929, 10936, 10934, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 28895, 28896, 28911, 28912, 28909, - 28910, 28892, 28893, 40951, 40951, 28937, 28897, 28938, 28898, 28931, - 28930, 28927, 28926, 28915, 28925, 28924, 28929, 28928, 28917, 28906, - 28905, 28900, 28899, 28916, 28908, 28907, 28902, 28901, 28918, 28933, - 28932, 28923, 28922, 28935, 28936, 28904, 28914, 28894, 28919, 28920, - 28921, 28934, 28913, 28903, 28947, 28952, 28953, 28950, 28951, 28945, - 28946, 40951, 40951, 28954, 28948, 28955, 28949, 28941, 28943, 28942, - 28940, 28939, 28956, 28944, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40732, 40753, 40750, 40749, 40752, 40748, 40747, 40745, 40746, - 40751, 40744, 40700, 40699, 40719, 40718, 40701, 40717, 40716, 40726, - 40703, 40711, 40710, 40693, 40692, 40702, 40713, 40712, 40697, 40696, - 40704, 40721, 40720, 40715, 40714, 40728, 40709, 40708, 40695, 40694, - 40722, 40723, 40724, 40731, 40729, 40727, 40730, 40705, 40706, 40707, - 40725, 40698, 40691, 40741, 40738, 40739, 40740, 40737, 40742, 40688, - 40687, 40685, 40684, 40686, 40690, 40683, 40736, 40734, 40733, 40735, - 40689, 40682, 40743, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 34052, 34073, 34071, 34070, 34072, 34068, 34069, 34066, 34067, - 34065, 34064, 34074, 34019, 34018, 34038, 34037, 34020, 34036, 34035, - 34040, 34039, 34022, 34030, 34029, 34013, 34012, 34021, 34032, 34031, - 34016, 34014, 34023, 34042, 34041, 34034, 34033, 34048, 34028, 34027, - 34015, 34043, 34044, 34045, 34051, 34049, 34047, 34050, 34024, 34025, - 34026, 34046, 34017, 34057, 34059, 33996, 33995, 33993, 33994, 34004, - 34005, 34000, 34003, 33999, 34002, 34007, 34008, 34006, 33998, 33997, - 34001, 34060, 34058, 34075, 34061, 34056, 34055, 34054, 34053, 34011, - 34010, 34009, 34062, 34063, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 5617, 5618, 5615, 5616, - 5613, 5614, 5623, 5624, 5621, 5622, 5619, 5620, 5786, 5787, 5788, 5785, - 31247, 31245, 31254, 31255, 31251, 31259, 31258, 31240, 31253, 31252, - 31244, 31257, 31250, 31243, 31249, 31248, 31241, 31246, 31256, 31235, - 31242, 31260, 31261, 31236, 31262, 31238, 31239, 31237, 31231, 31228, - 31232, 31230, 31226, 31229, 31233, 31227, 31234, 31268, 31267, 31278, - 31269, 31270, 31279, 31275, 31274, 31276, 31277, 31271, 31225, 31272, - 31273, 31264, 31263, 31223, 31265, 31266, 31224, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 10668, 10669, 10758, 10759, 10760, 10761, - 10768, 10767, 10769, 10773, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 34658, 34677, 34684, 34681, - 34671, 34668, 34663, 34685, 34653, 34670, 34679, 34660, 34657, 34666, - 34683, 34661, 34680, 34667, 34672, 34678, 34682, 34655, 34654, 34659, - 34675, 34669, 34665, 34664, 34673, 34656, 34674, 34676, 34662, 34686, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 34693, 34695, 34692, 34691, 34688, 34687, - 34690, 34689, 34696, 34694, 40951, 40951, 40951, 40951, 40951, 40951, - 3661, 3662, 3675, 3676, 3673, 3674, 3657, 3658, 3659, 40951, 3701, 3663, - 3702, 3664, 3693, 3692, 3689, 3688, 3677, 3687, 3686, 3691, 3690, 3679, - 3670, 3669, 3666, 3665, 3678, 3672, 3671, 3668, 3667, 3680, 3695, 3694, - 3685, 3684, 3698, 3700, 3699, 3697, 3660, 3681, 3682, 3683, 3696, 3729, - 3734, 3735, 3732, 3733, 3726, 3727, 3728, 40951, 3736, 3730, 3737, 3731, - 3721, 3723, 3725, 3724, 3722, 3739, 3738, 3750, 3751, 3752, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 3746, 3748, 3745, - 3744, 3741, 3740, 3743, 3742, 3749, 3747, 3720, 3718, 3715, 3706, 3708, - 3713, 3711, 3703, 3709, 3719, 3717, 3716, 3705, 3707, 3714, 3712, 3704, - 3710, 3753, 40951, 40951, 40951, 25735, 25736, 25681, 25680, 25690, - 25675, 25679, 25678, 25692, 25676, 25672, 25671, 25674, 25677, 25683, - 25682, 25689, 25694, 25670, 25669, 25673, 25696, 25686, 25687, 25688, - 25697, 25695, 25693, 25684, 25685, 25691, 25698, 40951, 40951, 25713, - 25712, 25721, 25707, 25711, 25710, 25723, 25708, 25704, 25703, 25706, - 25709, 25715, 25714, 25720, 25725, 25702, 25701, 25705, 25727, 25718, - 25719, 40951, 25728, 25726, 25724, 25716, 25717, 25722, 25729, 25730, - 25732, 25734, 25731, 25733, 25700, 25699, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 25747, - 25748, 25757, 25758, 25755, 25756, 25784, 40951, 25749, 25785, 40951, - 25750, 25763, 25762, 25776, 25775, 25764, 25774, 25773, 25741, 25740, - 25766, 25743, 25742, 25752, 25751, 25765, 25746, 25744, 25754, 25753, - 25767, 25778, 25777, 25772, 25771, 25780, 25783, 25781, 25760, 25782, - 25768, 25769, 25770, 25779, 25759, 25761, 25739, 25745, 25794, 25799, - 25800, 25797, 25798, 25793, 40951, 40951, 40951, 25801, 40951, 25795, - 25802, 40951, 25796, 25792, 25791, 25790, 25788, 25789, 25803, 25787, - 25786, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 25810, - 25812, 25809, 25808, 25805, 25804, 25807, 25806, 25813, 25811, 40951, - 40951, 40951, 40951, 40951, 40951, 18770, 18771, 18784, 18785, 18782, - 18783, 40951, 18801, 18772, 40951, 18800, 18773, 18807, 18806, 18789, - 18788, 18803, 18797, 18796, 18781, 18780, 18787, 18793, 18792, 18777, - 18776, 18769, 18791, 18790, 18779, 18778, 18786, 18795, 18794, 18775, - 18774, 18768, 18799, 18798, 18802, 18804, 18805, 18810, 18815, 18816, - 18813, 18814, 40951, 18818, 18811, 40951, 18817, 18812, 18809, 18808, - 18819, 18830, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 18826, - 18828, 18825, 18824, 18821, 18820, 18823, 18822, 18829, 18827, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 25433, - 25431, 25425, 25436, 25428, 25435, 25439, 25430, 25427, 25429, 25432, - 25426, 25441, 25437, 25434, 25440, 25438, 25442, 25448, 25445, 25447, - 25444, 25446, 25443, 25424, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 21513, 21517, 21515, 21516, 21454, 21455, 21474, 21475, 21468, - 21469, 21470, 21471, 21472, 21473, 21499, 21456, 21500, 40951, 21490, - 21489, 21488, 21487, 21476, 21486, 21485, 21459, 21458, 21478, 21465, - 21464, 21461, 21460, 21477, 21467, 21466, 21463, 21462, 21479, 21492, - 21491, 21484, 21483, 21495, 21498, 21496, 21494, 21497, 21480, 21481, - 21482, 21493, 21457, 21519, 21518, 21526, 21527, 21524, 21525, 21521, - 40951, 40951, 40951, 21522, 21520, 21523, 21512, 21540, 21529, 21528, - 21507, 21510, 21506, 21508, 21504, 21503, 21511, 21502, 21505, 21509, - 21501, 21536, 21538, 21535, 21534, 21531, 21530, 21533, 21532, 21539, - 21537, 21514, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 25086, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 35424, 35420, 35414, 35423, 35416, 35425, 35429, - 35431, 35426, 35421, 35422, 35427, 35415, 35432, 35430, 35417, 35428, - 35418, 35419, 35433, 35434, 35498, 35481, 35479, 35488, 35487, 35483, - 35489, 35485, 35484, 35491, 35492, 35493, 35490, 35482, 35495, 35413, - 35400, 35471, 35478, 35768, 35769, 35398, 35373, 35499, 35767, 35435, - 35500, 35486, 35494, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 35476, 8820, 8828, 8826, 8822, - 8827, 8823, 8821, 8824, 8825, 8889, 8829, 8838, 8837, 8831, 8830, 8842, - 8832, 8833, 8841, 8835, 8836, 8843, 8844, 8849, 8846, 8845, 8847, 8848, - 8851, 8853, 8855, 8854, 8856, 8862, 8859, 8860, 8864, 8857, 8858, 8863, - 8861, 8866, 8865, 8867, 8869, 8870, 8874, 8873, 8871, 8872, 8875, 8888, - 8876, 8877, 8878, 8887, 8879, 8883, 8884, 8882, 8880, 8881, 8886, 8885, - 8890, 8891, 8902, 8893, 8897, 8898, 8899, 8900, 8901, 8903, 8906, 8905, - 8904, 8907, 8909, 8910, 8911, 8912, 8913, 8914, 8915, 8916, 8917, 8918, - 8919, 8920, 8921, 8922, 8923, 8924, 8925, 8926, 8941, 8927, 8928, 8938, - 8932, 8929, 8930, 8931, 8939, 8936, 8940, 8937, 8933, 8935, 8948, 8944, - 8945, 8946, 8949, 8960, 8950, 8953, 8954, 8956, 8957, 8958, 8961, 8964, - 8962, 8963, 8965, 8966, 8968, 8969, 8998, 9005, 8999, 9000, 9001, 9002, - 9003, 9004, 9006, 9008, 9007, 9009, 9012, 9013, 9016, 9010, 9011, 9017, - 9062, 9061, 9063, 9018, 9021, 9022, 9023, 9019, 9020, 9024, 9027, 9025, - 9028, 9030, 9039, 9040, 9041, 9042, 9060, 9043, 9044, 9057, 9058, 9056, - 9045, 9046, 9047, 9048, 9049, 9050, 9051, 9054, 9055, 9064, 9154, 9065, - 9066, 9068, 9067, 9074, 9069, 9071, 9073, 9077, 9076, 9078, 9079, 9086, - 9080, 9081, 9085, 9089, 9090, 9087, 9088, 9096, 9093, 9097, 9098, 9099, - 9100, 9101, 9103, 9104, 9106, 9105, 9108, 9107, 9110, 9109, 9111, 9112, - 9114, 9115, 9119, 9121, 9125, 9126, 9139, 9131, 9132, 9127, 9128, 9129, - 9133, 9137, 9134, 9135, 9136, 9140, 9141, 9143, 9144, 9145, 9146, 9147, - 9148, 9158, 9149, 9150, 9153, 9152, 9151, 9155, 9156, 9157, 9159, 9160, - 9163, 9164, 9165, 9166, 9167, 9169, 9168, 9185, 9176, 9177, 9170, 9171, - 9173, 9174, 9172, 9175, 9184, 9178, 9183, 9181, 9180, 9182, 9187, 9206, - 9188, 9189, 9190, 9193, 9192, 9194, 9195, 9197, 9198, 9199, 9207, 9200, - 9201, 9202, 9205, 9204, 9203, 9208, 9209, 9211, 9212, 9213, 9214, 9216, - 9220, 9217, 9221, 9219, 9218, 9222, 9223, 9224, 9225, 9229, 9228, 9226, - 9227, 9230, 9231, 9233, 9252, 9254, 9234, 9236, 9235, 9237, 9238, 9241, - 9242, 9240, 9239, 9243, 9244, 9245, 9246, 9249, 9247, 9248, 9250, 9251, - 9255, 9256, 9253, 9257, 9258, 9259, 9260, 9262, 9265, 9264, 9266, 9267, - 9269, 9270, 9271, 9275, 9274, 9272, 9273, 9276, 9280, 9279, 9278, 9281, - 9282, 9284, 9285, 9289, 9286, 9287, 9292, 9290, 9293, 9294, 9296, 9295, - 9297, 9298, 9320, 9319, 9322, 9323, 9304, 9305, 9302, 9303, 9301, 9299, - 9307, 9306, 9308, 9310, 9316, 9317, 9314, 9315, 9324, 9325, 9326, 9344, - 9329, 9330, 9331, 9327, 9328, 9332, 9333, 9334, 9335, 9336, 9338, 9339, - 9340, 9341, 9342, 9367, 9345, 9348, 9346, 9347, 9353, 9354, 9351, 9352, - 9349, 9350, 9355, 9356, 9364, 9357, 9358, 9365, 9362, 9363, 9366, 9359, - 9360, 9361, 9368, 9369, 9370, 9371, 9372, 9373, 9374, 9376, 9377, 9375, - 9378, 9379, 9420, 9421, 9382, 9383, 9380, 9381, 9386, 9387, 9385, 9391, - 9388, 9390, 9389, 9395, 9396, 9394, 9392, 9393, 9397, 9398, 9399, 9400, - 9401, 9402, 9403, 9422, 9408, 9404, 9405, 9406, 9407, 9409, 9411, 9410, - 9412, 9413, 9415, 9414, 9416, 9418, 9417, 9423, 9424, 9427, 9428, 9425, - 9426, 9502, 9497, 9498, 9499, 9500, 9501, 9503, 9506, 9504, 9505, 9507, - 9549, 9508, 9538, 9539, 9515, 9517, 9534, 9518, 9540, 9522, 9520, 9521, - 9523, 9524, 9525, 9526, 9535, 9536, 9529, 9530, 9532, 9541, 9509, 9510, - 9514, 9512, 9550, 9542, 9544, 9543, 9545, 9551, 9552, 9546, 9547, 9548, - 9553, 9554, 9555, 9558, 9559, 9560, 9556, 9557, 9561, 9562, 9564, 9566, - 9567, 9585, 9583, 9584, 9587, 9586, 9568, 9575, 9573, 9574, 9569, 9570, - 9576, 9577, 9578, 9579, 9580, 9582, 9588, 9597, 9589, 9591, 9592, 9590, - 9593, 9595, 9594, 9596, 9599, 9601, 9600, 9602, 9603, 9636, 9638, 9604, - 9606, 9605, 9608, 9611, 9609, 9610, 9614, 9618, 9621, 9620, 9623, 9626, - 9624, 9625, 9629, 9631, 9637, 9639, 9640, 9644, 9651, 9649, 9647, 9648, - 9650, 9653, 9652, 9645, 9646, 9654, 9657, 9663, 9658, 9661, 9656, 9655, - 9664, 9662, 9659, 9660, 9665, 9666, 9667, 9668, 9669, 9670, 9671, 9673, - 9676, 9677, 9680, 9681, 9682, 9678, 9679, 9674, 9675, 9683, 9684, 9685, - 9686, 9687, 9688, 9690, 9691, 9692, 9693, 9694, 9698, 9695, 9719, 9712, - 9713, 9718, 9701, 9700, 9714, 9717, 9715, 9704, 9703, 9706, 9708, 9709, - 9710, 9711, 9707, 9720, 9696, 9721, 9722, 9723, 9724, 9725, 9726, 9734, - 9732, 9730, 9733, 9729, 9731, 9727, 9728, 9735, 9737, 9738, 9739, 9746, - 9741, 9742, 9750, 9751, 9747, 9749, 9748, 9752, 9754, 9753, 9755, 9766, - 9757, 9756, 9765, 9763, 9758, 9759, 9760, 9762, 9761, 9764, 9770, 9767, - 9769, 9768, 9771, 9772, 9773, 9774, 9777, 9778, 9780, 9781, 9782, 9783, - 9785, 9784, 9786, 9793, 9787, 9788, 9794, 9789, 9790, 9791, 9792, 9795, - 9799, 9796, 9797, 9798, 9800, 9801, 9802, 9803, 9809, 9807, 9805, 9806, - 9804, 9808, 9810, 9812, 9829, 9830, 9813, 9818, 9820, 9814, 9817, 9815, - 9816, 9821, 9827, 9828, 9822, 9825, 9826, 9831, 9837, 9836, 9832, 9834, - 9833, 9918, 9919, 9838, 9839, 9844, 9845, 9842, 9843, 9846, 9840, 9841, - 9847, 9850, 9851, 9853, 9854, 9855, 9859, 9856, 9857, 9858, 9848, 9849, - 9860, 9862, 9861, 9863, 9865, 9866, 9867, 9873, 9872, 9868, 9869, 9870, - 9905, 9874, 9875, 9876, 9877, 9878, 9897, 9880, 9881, 9883, 9882, 9884, - 9885, 9901, 9886, 9888, 9887, 9900, 9890, 9898, 9902, 9893, 9892, 9899, - 9894, 9896, 9895, 9903, 9904, 9906, 9910, 9908, 9909, 9907, 9913, 9912, - 9911, 9917, 9914, 9915, 9916, 9920, 9922, 9921, 9925, 9923, 9940, 9926, - 9929, 9931, 9927, 9928, 9932, 9930, 9933, 9935, 9937, 9938, 9939, 9343, - 8839, 8850, 8868, 8934, 8943, 8959, 8967, 9059, 9052, 9070, 9072, 9162, - 9186, 9232, 9261, 9263, 9277, 9283, 9318, 9291, 9321, 9300, 9309, 9313, - 9384, 9513, 9516, 9531, 9563, 9581, 9598, 9607, 9635, 9633, 9612, 9643, - 9672, 9689, 9699, 9819, 9852, 9835, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 8804, 8799, 8736, 8722, - 8783, 8779, 8711, 8756, 8803, 8744, 8728, 8789, 8778, 8710, 8755, 8742, - 8726, 8785, 8775, 8705, 8752, 8765, 8809, 8801, 8738, 8724, 8787, 8777, - 8707, 8754, 8766, 8810, 8802, 8739, 8725, 8811, 8793, 8794, 8740, 8716, - 8782, 8774, 8704, 8751, 8769, 8812, 8795, 8796, 8741, 8717, 8780, 8781, - 8764, 8807, 8790, 8791, 8731, 8721, 8797, 8798, 8732, 8735, 8733, 8734, - 8788, 8773, 8771, 8772, 8708, 8709, 8747, 8749, 8750, 8748, 8805, 8800, - 8737, 8723, 8784, 8763, 8806, 8792, 8729, 8730, 8719, 8720, 8746, 8745, - 8759, 8808, 8768, 8814, 8718, 8767, 8813, 8760, 8761, 8757, 8758, 8762, - 8770, 8712, 8715, 8714, 8713, 8743, 8727, 8786, 8776, 8706, 8753, 40951, - 8819, 8818, 8817, 8815, 8816, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 8840, 8834, 8852, 8892, 8894, 8895, - 8896, 8908, 8947, 8942, 8952, 8951, 8955, 8972, 8970, 8971, 8973, 8974, - 8992, 8978, 8975, 8976, 8977, 8994, 8995, 8993, 8982, 8981, 8979, 8980, - 8985, 8983, 8984, 8986, 8987, 8988, 8989, 8996, 8997, 8991, 8990, 9015, - 9014, 9026, 9029, 9034, 9038, 9031, 9035, 9036, 9032, 9033, 9037, 9053, - 9075, 9082, 9083, 9084, 9091, 9092, 9095, 9094, 9102, 9113, 9116, 9117, - 9118, 9120, 9122, 9123, 9124, 9130, 9138, 9142, 9161, 9179, 9191, 9196, - 9210, 9215, 9268, 9288, 9311, 9312, 9419, 9439, 9429, 9430, 9438, 9434, - 9435, 9436, 9433, 9432, 9431, 9437, 9441, 9440, 9447, 9448, 9442, 9443, - 9444, 9449, 9445, 9446, 9450, 9451, 9452, 9453, 9454, 9455, 9462, 9456, - 9461, 9460, 9458, 9457, 9459, 9463, 9464, 9469, 9470, 9465, 9466, 9467, - 9468, 9496, 9492, 9471, 9479, 9480, 9478, 9477, 9481, 9472, 9473, 9475, - 9476, 9474, 9493, 9482, 9489, 9491, 9486, 9487, 9490, 9485, 9488, 9484, - 9483, 9494, 9495, 9511, 9537, 9519, 9527, 9528, 9533, 9565, 9572, 9571, - 9632, 9613, 9615, 9634, 9616, 9617, 9619, 9622, 9627, 9628, 9630, 9697, - 9716, 9702, 9705, 9736, 9740, 9743, 9744, 9745, 9776, 9775, 9779, 9811, - 9823, 9824, 9864, 9871, 9879, 9891, 9889, 9924, 9934, 9936, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 10013, 10014, 10015, 10016, 10017, 10018, 10019, 10020, 10023, 10024, - 10021, 10022, 10025, 10026, 10027, 10028, 10029, 10030, 10031, 10032, - 10033, 10034, 10035, 10036, 10037, 10038, 10039, 10040, 10041, 10042, - 10043, 10044, 10045, 10046, 10047, 10048, 10049, 10050, 10051, 10052, - 10053, 10054, 10055, 10056, 10057, 10058, 10059, 10079, 10080, 10081, - 10082, 10083, 10084, 10085, 10086, 10087, 10062, 10063, 10064, 10065, - 10066, 10060, 10061, 10067, 10068, 10069, 10088, 10089, 10090, 10091, - 10092, 10093, 10094, 10095, 10096, 10097, 10070, 10071, 10072, 10073, - 10074, 10075, 10076, 10077, 10078, 10098, 10099, 10100, 10101, 10102, - 10103, 10104, 10105, 10106, 10107, 10108, 10109, 10110, 10111, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 11548, 11549, 11550, 11551, 11546, 11547, 11543, 11544, - 11545, 11552, 11553, 11554, 11559, 11560, 11561, 11562, 11555, 11556, - 11563, 11564, 11557, 11558, 11565, 11566, 11593, 11594, 11595, 11596, - 11597, 11598, 11599, 11600, 11601, 11602, 11583, 11584, 11581, 11582, - 11585, 11586, 11587, 11588, 11589, 11590, 11591, 11567, 11568, 11575, - 11569, 11570, 11571, 11572, 11576, 11573, 11574, 11577, 11578, 11579, - 11580, 11603, 11604, 11605, 11606, 11607, 11608, 11609, 11610, 11611, - 11612, 11613, 11614, 11615, 11616, 11617, 11618, 11619, 11620, 11621, - 11622, 11592, 11662, 11663, 11664, 11665, 11660, 11661, 11666, 11667, - 11668, 11669, 11674, 11670, 11671, 11672, 11673, 11675, 11676, 11677, - 11678, 11679, 11680, 11681, 11682, 11683, 11684, 11685, 11686, 11687, - 11688, 11689, 11690, 11691, 11692, 11693, 11694, 11695, 11696, 11697, - 11700, 11701, 11702, 11703, 11704, 11705, 11706, 11698, 11699, 11707, - 11780, 11781, 11782, 11783, 11784, 11785, 11786, 11787, 11788, 11789, - 11771, 11772, 11773, 11774, 11775, 11776, 11777, 11769, 11770, 11778, - 11779, 11712, 11708, 11709, 11713, 11714, 11710, 11711, 11715, 11716, - 11717, 11718, 11719, 11724, 11725, 11726, 11727, 11728, 11729, 11720, - 11721, 11730, 11722, 11723, 11731, 11732, 11733, 11734, 11735, 11736, - 11737, 11738, 11739, 11740, 11741, 11746, 11742, 11743, 11747, 11744, - 11745, 11748, 11749, 11750, 11751, 11752, 11762, 11763, 11764, 11765, - 11766, 11767, 11768, 11753, 11754, 11755, 11756, 11757, 11758, 11759, - 11760, 11761, 11794, 11795, 11796, 11797, 11798, 11799, 11800, 11790, - 11791, 11792, 11793, 11826, 11827, 11828, 11829, 11830, 11831, 11822, - 11823, 11824, 11825, 11832, 11833, 11801, 11802, 11805, 11806, 11807, - 11808, 11809, 11810, 11811, 11803, 11804, 11812, 11815, 11816, 11817, - 11818, 11813, 11814, 11819, 11820, 11821, 11837, 11838, 11839, 11840, - 11841, 11842, 11843, 11844, 11845, 11846, 11849, 11850, 11851, 11847, - 11848, 11852, 11853, 11854, 11855, 11856, 11857, 11893, 11891, 11892, - 11894, 11895, 11896, 11897, 11898, 11899, 11900, 11901, 11864, 11858, - 11859, 11865, 11866, 11867, 11868, 11869, 11860, 11861, 11862, 11863, - 11870, 11877, 11878, 11879, 11880, 11881, 11871, 11872, 11873, 11874, - 11875, 11876, 11882, 11883, 11888, 11884, 11885, 11886, 11887, 11889, - 11890, 11908, 11909, 11910, 11911, 11912, 11906, 11907, 11903, 11904, - 11905, 11913, 11914, 11917, 11915, 11916, 11918, 11919, 11920, 11921, - 11922, 11923, 11924, 11925, 11950, 11951, 11954, 11955, 11956, 11957, - 11958, 11952, 11953, 11959, 11960, 11961, 11930, 11931, 11932, 11933, - 11934, 11935, 11926, 11927, 11928, 11929, 11936, 11937, 11942, 11943, - 11944, 11938, 11939, 11945, 11940, 11941, 11946, 11947, 11948, 11949, - 11962, 11963, 11964, 11965, 11966, 11969, 11970, 11971, 11972, 11973, - 11967, 11968, 11974, 11975, 11983, 11984, 11985, 11986, 11979, 11980, - 11987, 11988, 11989, 11981, 11982, 11990, 11991, 11992, 11993, 11994, - 11995, 11996, 11997, 12638, 12639, 12640, 12641, 12642, 12643, 12644, - 12645, 12009, 12005, 12006, 12010, 12011, 12012, 12007, 12008, 12013, - 12014, 12016, 12017, 12018, 12021, 12019, 12020, 12022, 12023, 12024, - 12025, 12026, 12027, 12037, 12038, 12045, 12028, 12029, 12030, 12031, - 12032, 12033, 12034, 12035, 12036, 12046, 12047, 12039, 12040, 12041, - 12042, 12043, 12044, 12048, 12049, 12056, 12057, 12050, 12051, 12058, - 12052, 12053, 12059, 12060, 12061, 12054, 12055, 12062, 12068, 12066, - 12067, 12069, 12063, 12064, 12065, 12070, 12071, 12072, 12073, 12074, - 12075, 12076, 12077, 12078, 12079, 12080, 12081, 12138, 12139, 12140, - 12141, 12142, 12143, 12144, 12145, 12146, 12101, 12102, 12103, 12104, - 12105, 12106, 12107, 12108, 12098, 12099, 12100, 12109, 12126, 12127, - 12128, 12129, 12130, 12124, 12125, 12131, 12132, 12133, 12134, 12118, - 12119, 12120, 12110, 12111, 12112, 12113, 12114, 12115, 12121, 12116, - 12117, 12122, 12123, 12135, 12136, 12137, 12149, 12150, 12151, 12152, - 12147, 12148, 12153, 12154, 12155, 12156, 12159, 12160, 12161, 12162, - 12163, 12164, 12165, 12157, 12158, 12166, 12167, 12168, 12186, 12187, - 12188, 12189, 12190, 12191, 12192, 12193, 12194, 12169, 12170, 12171, - 12172, 12175, 12176, 12177, 12178, 12179, 12180, 12173, 12174, 12181, - 12184, 12185, 12182, 12183, 12202, 12203, 12206, 12207, 12208, 12204, - 12205, 12195, 12196, 12197, 12198, 12199, 12200, 12201, 12209, 12210, - 12211, 12212, 12213, 12214, 12215, 12218, 12219, 12220, 12221, 12222, - 12223, 12224, 12225, 12216, 12217, 12226, 12227, 12234, 12235, 12236, - 12228, 12229, 12230, 12231, 12237, 12238, 12239, 12232, 12233, 12245, - 12246, 12249, 12250, 12247, 12248, 12251, 12252, 12240, 12241, 12242, - 12243, 12244, 12253, 12254, 12255, 12260, 12261, 12262, 12263, 12264, - 12265, 12266, 12267, 12268, 12269, 12256, 12257, 12258, 12259, 12271, - 12272, 12275, 12273, 12274, 12276, 12277, 12278, 12279, 12280, 12281, - 12282, 12283, 12646, 12647, 12648, 12649, 12650, 12651, 12652, 12289, - 12287, 12288, 12284, 12285, 12286, 12290, 12291, 12292, 12293, 12294, - 12295, 12296, 12297, 12300, 12301, 12302, 12303, 12304, 12298, 12299, - 12305, 12306, 12307, 12308, 12309, 12310, 12311, 12312, 12313, 12314, - 12315, 12316, 12317, 12322, 12318, 12319, 12323, 12324, 12325, 12320, - 12321, 12326, 12327, 12328, 12334, 12335, 12336, 12337, 12329, 12330, - 12331, 12338, 12339, 12332, 12333, 12340, 12341, 12345, 12346, 12347, - 12348, 12349, 12350, 12342, 12343, 12344, 12351, 12352, 12353, 12356, - 12357, 12358, 12359, 12360, 12354, 12355, 12361, 12362, 12363, 12364, - 12365, 12366, 12367, 12368, 12369, 12370, 12371, 12380, 12381, 12372, - 12373, 12382, 12383, 12384, 12374, 12375, 12376, 12377, 12378, 12379, - 12389, 12385, 12386, 12390, 12391, 12392, 12393, 12387, 12388, 12394, - 12395, 12396, 12406, 12407, 12408, 12409, 12410, 12411, 12412, 12413, - 12414, 12415, 12401, 12402, 12397, 12398, 12399, 12400, 12403, 12404, - 12405, 12420, 12421, 12422, 12423, 12424, 12417, 12418, 12419, 12425, - 12426, 12427, 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, - 12462, 12463, 12432, 12433, 12434, 12428, 12429, 12435, 12436, 12437, - 12438, 12439, 12430, 12431, 12442, 12443, 12440, 12441, 12444, 12445, - 12446, 12447, 12448, 12449, 12450, 12451, 12452, 12453, 12467, 12468, - 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, - 12479, 12480, 12481, 12482, 12464, 12465, 12466, 12483, 12484, 12493, - 12485, 12486, 12487, 12488, 12490, 12491, 12492, 12494, 12495, 12496, - 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, - 12507, 12508, 12509, 12510, 12511, 12512, 12513, 12520, 12521, 12514, - 12515, 12522, 12523, 12524, 12525, 12516, 12517, 12518, 12519, 12526, - 12527, 12528, 12529, 12534, 12530, 12531, 12535, 12536, 12537, 12532, - 12533, 12538, 12539, 12540, 12541, 12547, 12548, 12543, 12544, 12549, - 12550, 12551, 12552, 12553, 12545, 12546, 12554, 12555, 12562, 12563, - 12564, 12556, 12557, 12565, 12566, 12558, 12559, 12560, 12561, 12567, - 12570, 12571, 12572, 12573, 12568, 12569, 12574, 12583, 12584, 12585, - 12576, 12577, 12578, 12586, 12579, 12580, 12587, 12581, 12582, 12588, - 12589, 12590, 12591, 12592, 12593, 12594, 12595, 12596, 12609, 12597, - 12598, 12599, 12600, 12601, 12602, 12603, 12604, 12605, 12606, 12607, - 12608, 12610, 12611, 12612, 12613, 12633, 12634, 12635, 12636, 12637, - 12614, 12615, 12616, 12617, 12618, 12619, 12620, 12621, 12622, 12623, - 12624, 12625, 12626, 12627, 12628, 12629, 12630, 12631, 12632, 11626, - 11627, 11628, 11629, 11630, 11631, 11623, 11624, 11625, 11632, 11633, - 11637, 11638, 11639, 11640, 11641, 11642, 11643, 11644, 11645, 11646, - 11647, 11648, 11649, 11650, 11651, 11652, 11653, 11654, 11655, 11656, - 11634, 11635, 11636, 12489, 12542, 11978, 12003, 12000, 12002, 11999, - 12270, 11659, 11836, 12004, 12001, 11998, 11658, 11835, 11657, 11834, - 12097, 11902, 11976, 12015, 11977, 12416, 12575, 12093, 12084, 12088, - 12095, 12091, 12085, 12090, 12087, 12094, 12083, 12089, 12096, 12092, - 12086, 12082, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 12653, 12654, 12655, 12656, 12657, 12658, 12659, 12660, - 12661, 12662, 12663, 12664, 12665, 12666, 12667, 12668, 12669, 12670, - 12671, 12672, 12673, 12674, 12675, 12676, 12677, 12678, 12679, 12680, - 12681, 12682, 12683, 12684, 12685, 12686, 12687, 12688, 12689, 12690, - 12691, 12692, 12693, 12694, 12695, 12696, 12697, 12698, 12699, 12700, - 12701, 12702, 12703, 12704, 12705, 12706, 12707, 12708, 12709, 12710, - 12711, 12712, 12713, 12714, 12715, 12716, 12717, 12718, 12719, 12720, - 12721, 12722, 12723, 12724, 12725, 12726, 12727, 12728, 12729, 12730, - 12731, 12732, 12733, 12734, 12735, 12736, 12737, 12738, 12739, 12740, - 12741, 12742, 12743, 12744, 12745, 12746, 12747, 12748, 12749, 12750, - 12751, 12752, 12753, 12754, 12755, 12756, 12757, 12758, 12759, 12760, - 12761, 12762, 12763, 12764, 12765, 12766, 12767, 12768, 12769, 12770, - 12771, 12772, 12773, 12774, 12775, 12776, 12777, 12778, 12779, 12780, - 12781, 12782, 12783, 12784, 12785, 12786, 12787, 12788, 12789, 12790, - 12791, 12792, 12793, 12794, 12795, 12796, 12797, 12798, 12799, 12800, - 12801, 12802, 12803, 12804, 12805, 12806, 12807, 12808, 12809, 12810, - 12811, 12812, 12813, 12814, 12815, 12816, 12817, 12818, 12819, 12820, - 12821, 12822, 12823, 12824, 12825, 12826, 12827, 12828, 12829, 12830, - 12831, 12832, 12833, 12834, 12835, 12836, 12837, 12838, 12839, 12840, - 12841, 12842, 12843, 12844, 12845, 12846, 12847, 12848, 12849, 12850, - 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12858, 12859, 12860, - 12861, 12862, 12863, 12864, 12865, 12866, 12867, 12868, 12869, 12870, - 12871, 12872, 12873, 12874, 12875, 12876, 12877, 12878, 12879, 12880, - 12881, 12882, 12883, 12884, 12885, 12886, 12887, 12888, 12889, 12890, - 12891, 12892, 12893, 12894, 12895, 12896, 12897, 12898, 12899, 12900, - 12901, 12902, 12903, 12904, 12905, 12906, 12907, 12908, 12909, 12910, - 12911, 12912, 12913, 12914, 12915, 12916, 12917, 12918, 12919, 12920, - 12921, 12922, 12923, 12924, 12925, 12926, 12927, 12928, 12929, 12930, - 12931, 12932, 12933, 12934, 12935, 12936, 12937, 12938, 12939, 12940, - 12941, 12942, 12943, 12944, 12945, 12946, 12947, 12948, 12949, 12950, - 12951, 12952, 12953, 12954, 12955, 12956, 12957, 12958, 12959, 12960, - 12961, 12962, 12963, 12964, 12965, 12966, 12967, 12968, 12969, 12970, - 12971, 12972, 12973, 12974, 12975, 12976, 12977, 12978, 12979, 12980, - 12981, 12982, 12983, 12984, 12985, 12986, 12987, 12988, 12989, 12990, - 12991, 12992, 12993, 12994, 12995, 12996, 12997, 12998, 12999, 13000, - 13001, 13002, 13003, 13004, 13005, 13006, 13007, 13008, 13009, 13010, - 13011, 13012, 13013, 13014, 13015, 13016, 13017, 13018, 13019, 13020, - 13021, 13022, 13023, 13024, 13025, 13026, 13027, 13028, 13029, 13030, - 13031, 13032, 13033, 13034, 13035, 13036, 13037, 13038, 13039, 13040, - 13041, 13042, 13043, 13044, 13045, 13046, 13047, 13048, 13049, 13050, - 13051, 13052, 13053, 13054, 13055, 13056, 13057, 13058, 13059, 13060, - 13061, 13062, 13063, 13064, 13065, 13066, 13067, 13068, 13069, 13070, - 13071, 13072, 13073, 13074, 13075, 13076, 13077, 13078, 13079, 13080, - 13081, 13082, 13083, 13084, 13085, 13086, 13087, 13088, 13089, 13090, - 13091, 13092, 13093, 13094, 13095, 13096, 13097, 13098, 13099, 13100, - 13101, 13102, 13103, 13104, 13105, 13106, 13107, 13108, 13109, 13110, - 13111, 13112, 13113, 13114, 13115, 13116, 13117, 13118, 13119, 13120, - 13121, 13122, 13123, 13124, 13125, 13126, 13127, 13128, 13129, 13130, - 13131, 13132, 13133, 13134, 13135, 13136, 13137, 13138, 13139, 13140, - 13141, 13142, 13143, 13144, 13145, 13146, 13147, 13148, 13149, 13150, - 13151, 13152, 13153, 13154, 13155, 13156, 13157, 13158, 13159, 13160, - 13161, 13162, 13163, 13164, 13165, 13166, 13167, 13168, 13169, 13170, - 13171, 13172, 13173, 13174, 13175, 13176, 13177, 13178, 13179, 13180, - 13181, 13182, 13183, 13184, 13185, 13186, 13187, 13188, 13189, 13190, - 13191, 13192, 13193, 13194, 13195, 13196, 13197, 13198, 13199, 13200, - 13201, 13202, 13203, 13204, 13205, 13206, 13207, 13208, 13209, 13210, - 13211, 13212, 13213, 13214, 13215, 13216, 13217, 13218, 13219, 13220, - 13221, 13222, 13223, 13224, 13225, 13226, 13227, 13228, 13229, 13230, - 13231, 13232, 13233, 13234, 13235, 13236, 13237, 13238, 13239, 13240, - 13241, 13242, 13243, 13244, 13245, 13246, 13247, 13248, 13249, 13250, - 13251, 13252, 13253, 13254, 13255, 13256, 13257, 13258, 13259, 13260, - 13261, 13262, 13263, 13264, 13265, 13266, 13267, 13268, 13269, 13270, - 13271, 13272, 13273, 13274, 13275, 13276, 13277, 13278, 13279, 13280, - 13281, 13282, 13283, 13284, 13285, 13286, 13287, 13288, 13289, 13290, - 13291, 13292, 13293, 13294, 13295, 13296, 13297, 13298, 13299, 13300, - 13301, 13302, 13303, 13304, 13305, 13306, 13307, 13308, 13309, 13310, - 13311, 13312, 13313, 13314, 13315, 13316, 13317, 13318, 13319, 13320, - 13321, 13322, 13323, 13324, 13325, 13326, 13327, 13328, 13329, 13330, - 13331, 13332, 13333, 13334, 13335, 13336, 13337, 13338, 13339, 13340, - 13341, 13342, 13343, 13344, 13345, 13346, 13347, 13348, 13349, 13350, - 13351, 13352, 13353, 13354, 13355, 13356, 13357, 13358, 13359, 13360, - 13361, 13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13370, - 13371, 13372, 13373, 13374, 13375, 13376, 13377, 13378, 13379, 13380, - 13381, 13382, 13383, 13384, 13385, 13386, 13387, 13388, 13389, 13390, - 13391, 13392, 13393, 13394, 13395, 13396, 13397, 13398, 13399, 13400, - 13401, 13402, 13403, 13404, 13405, 13406, 13407, 13408, 13409, 13410, - 13411, 13412, 13413, 13414, 13415, 13416, 13417, 13418, 13419, 13420, - 13421, 13422, 13423, 13424, 13425, 13426, 13427, 13428, 13429, 13430, - 13431, 13432, 13433, 13434, 13435, 13436, 13437, 13438, 13439, 13440, - 13441, 13442, 13443, 13444, 13445, 13446, 13447, 13448, 13449, 13450, - 13451, 13452, 13453, 13454, 13455, 13456, 13457, 13458, 13459, 13460, - 13461, 13462, 13463, 13464, 13465, 13466, 13467, 13468, 13469, 13470, - 13471, 13472, 13473, 13474, 13475, 13476, 13477, 13478, 13479, 13480, - 13481, 13482, 13483, 13484, 13485, 13486, 13487, 13488, 13489, 13490, - 13491, 13492, 13493, 13494, 13495, 13496, 13497, 13498, 13499, 13500, - 13501, 13502, 13503, 13504, 13505, 13506, 13507, 13508, 13509, 13510, - 13511, 13512, 13513, 13514, 13515, 13516, 13517, 13518, 13519, 13520, - 13521, 13522, 13523, 13524, 13525, 13526, 13527, 13528, 13529, 13530, - 13531, 13532, 13533, 13534, 13535, 13536, 13537, 13538, 13539, 13540, - 13541, 13542, 13543, 13544, 13545, 13546, 13547, 13548, 13549, 13550, - 13551, 13552, 13553, 13554, 13555, 13556, 13557, 13558, 13559, 13560, - 13561, 13562, 13563, 13564, 13565, 13566, 13567, 13568, 13569, 13570, - 13571, 13572, 13573, 13574, 13575, 13576, 13577, 13578, 13579, 13580, - 13581, 13582, 13583, 13584, 13585, 13586, 13587, 13588, 13589, 13590, - 13591, 13592, 13593, 13594, 13595, 13596, 13597, 13598, 13599, 13600, - 13601, 13602, 13603, 13604, 13605, 13606, 13607, 13608, 13609, 13610, - 13611, 13612, 13613, 13614, 13615, 13616, 13617, 13618, 13619, 13620, - 13621, 13622, 13623, 13624, 13625, 13626, 13627, 13628, 13629, 13630, - 13631, 13632, 13633, 13634, 13635, 13636, 13637, 13638, 13639, 13640, - 13641, 13642, 13643, 13644, 13645, 13646, 13647, 13648, 13649, 13650, - 13651, 13652, 13653, 13654, 13655, 13656, 13657, 13658, 13659, 13660, - 13661, 13662, 13663, 13664, 13665, 13666, 13667, 13668, 13669, 13670, - 13671, 13672, 13673, 13674, 13675, 13676, 13677, 13678, 13679, 13680, - 13681, 13682, 13683, 13684, 13685, 13686, 13687, 13688, 13689, 13690, - 13691, 13692, 13693, 13694, 13695, 13696, 13697, 13698, 13699, 13700, - 13701, 13702, 13703, 13704, 13705, 13706, 13707, 13708, 13709, 13710, - 13711, 13712, 13713, 13714, 13715, 13716, 13717, 13718, 13719, 13720, - 13721, 13722, 13723, 13724, 13725, 13726, 13727, 13728, 13729, 13730, - 13731, 13732, 13733, 13734, 13735, 13736, 13737, 13738, 13739, 13740, - 13741, 13742, 13743, 13744, 13745, 13746, 13747, 13748, 13749, 13750, - 13751, 13752, 13753, 13754, 13755, 13756, 13757, 13758, 13759, 13760, - 13761, 13762, 13763, 13764, 13765, 13766, 13767, 13768, 13769, 13770, - 13771, 13772, 13773, 13774, 13775, 13776, 13777, 13778, 13779, 13780, - 13781, 13782, 13783, 13784, 13785, 13786, 13787, 13788, 13789, 13790, - 13791, 13792, 13793, 13794, 13795, 13796, 13797, 13798, 13799, 13800, - 13801, 13802, 13803, 13804, 13805, 13806, 13807, 13808, 13809, 13810, - 13811, 13812, 13813, 13814, 13815, 13816, 13817, 13818, 13819, 13820, - 13821, 13822, 13823, 13824, 13825, 13826, 13827, 13828, 13829, 13830, - 13831, 13832, 13833, 13834, 13835, 13836, 13837, 13838, 13839, 13840, - 13841, 13842, 13843, 13844, 13845, 13846, 13847, 13848, 13849, 13850, - 13851, 13852, 13853, 13854, 13855, 13856, 13857, 13858, 13859, 13860, - 13861, 13862, 13863, 13864, 13865, 13866, 13867, 13868, 13869, 13870, - 13871, 13872, 13873, 13874, 13875, 13876, 13877, 13878, 13879, 13880, - 13881, 13882, 13883, 13884, 13885, 13886, 13887, 13888, 13889, 13890, - 13891, 13892, 13893, 13894, 13895, 13896, 13897, 13898, 13899, 13900, - 13901, 13902, 13903, 13904, 13905, 13906, 13907, 13908, 13909, 13910, - 13911, 13912, 13913, 13914, 13915, 13916, 13917, 13918, 13919, 13920, - 13921, 13922, 13923, 13924, 13925, 13926, 13927, 13928, 13929, 13930, - 13931, 13932, 13933, 13934, 13935, 13936, 13937, 13938, 13939, 13940, - 13941, 13942, 13943, 13944, 13945, 13946, 13947, 13948, 13949, 13950, - 13951, 13952, 13953, 13954, 13955, 13956, 13957, 13958, 13959, 13960, - 13961, 13962, 13963, 13964, 13965, 13966, 13967, 13968, 13969, 13970, - 13971, 13972, 13973, 13974, 13975, 13976, 13977, 13978, 13979, 13980, - 13981, 13982, 13983, 13984, 13985, 13986, 13987, 13988, 13989, 13990, - 13991, 13992, 13993, 13994, 13995, 13996, 13997, 13998, 13999, 14000, - 14001, 14002, 14003, 14004, 14005, 14006, 14007, 14008, 14009, 14010, - 14011, 14012, 14013, 14014, 14015, 14016, 14017, 14018, 14019, 14020, - 14021, 14022, 14023, 14024, 14025, 14026, 14027, 14028, 14029, 14030, - 14031, 14032, 14033, 14034, 14035, 14036, 14037, 14038, 14039, 14040, - 14041, 14042, 14043, 14044, 14045, 14046, 14047, 14048, 14049, 14050, - 14051, 14052, 14053, 14054, 14055, 14056, 14057, 14058, 14059, 14060, - 14061, 14062, 14063, 14064, 14065, 14066, 14067, 14068, 14069, 14070, - 14071, 14072, 14073, 14074, 14075, 14076, 14077, 14078, 14079, 14080, - 14081, 14082, 14083, 14084, 14085, 14086, 14087, 14088, 14089, 14090, - 14091, 14092, 14093, 14094, 14095, 14096, 14097, 14098, 14099, 14100, - 14101, 14102, 14103, 14104, 14105, 14106, 14107, 14108, 14109, 14110, - 14111, 14112, 14113, 14114, 14115, 14116, 14117, 14118, 14119, 14120, - 14121, 14122, 14123, 14124, 14125, 14126, 14127, 14128, 14129, 14130, - 14131, 14132, 14133, 14134, 14135, 14136, 14137, 14138, 14139, 14140, - 14141, 14142, 14143, 14144, 14145, 14146, 14147, 14148, 14149, 14150, - 14151, 14152, 14153, 14154, 14155, 14156, 14157, 14158, 14159, 14160, - 14161, 14162, 14163, 14164, 14165, 14166, 14167, 14168, 14169, 14170, - 14171, 14172, 14173, 14174, 14175, 14176, 14177, 14178, 14179, 14180, - 14181, 14182, 14183, 14184, 14185, 14186, 14187, 14188, 14189, 14190, - 14191, 14192, 14193, 14194, 14195, 14196, 14197, 14198, 14199, 14200, - 14201, 14202, 14203, 14204, 14205, 14206, 14207, 14208, 14209, 14210, - 14211, 14212, 14213, 14214, 14215, 14216, 14217, 14218, 14219, 14220, - 14221, 14222, 14223, 14224, 14225, 14226, 14227, 14228, 14229, 14230, - 14231, 14232, 14233, 14234, 14235, 14236, 14237, 14238, 14239, 14240, - 14241, 14242, 14243, 14244, 14245, 14246, 14247, 14248, 14249, 14250, - 14251, 14252, 14253, 14254, 14255, 14256, 14257, 14258, 14259, 14260, - 14261, 14262, 14263, 14264, 14265, 14266, 14267, 14268, 14269, 14270, - 14271, 14272, 14273, 14274, 14275, 14276, 14277, 14278, 14279, 14280, - 14281, 14282, 14283, 14284, 14285, 14286, 14287, 14288, 14289, 14290, - 14291, 14292, 14293, 14294, 14295, 14296, 14297, 14298, 14299, 14300, - 14301, 14302, 14303, 14304, 14305, 14306, 14307, 14308, 14309, 14310, - 14311, 14312, 14313, 14314, 14315, 14316, 14317, 14318, 14319, 14320, - 14321, 14322, 14323, 14324, 14325, 14326, 14327, 14328, 14329, 14330, - 14331, 14332, 14333, 14334, 14335, 14336, 14337, 14338, 14339, 14340, - 14341, 14342, 14343, 14344, 14345, 14346, 14347, 14348, 14349, 14350, - 14351, 14352, 14353, 14354, 14355, 14356, 14357, 14358, 14359, 14360, - 14361, 14362, 14363, 14364, 14365, 14366, 14367, 14368, 14369, 14370, - 14371, 14372, 14373, 14374, 14375, 14376, 14377, 14378, 14379, 14380, - 14381, 14382, 14383, 14384, 14385, 14386, 14387, 14388, 14389, 14390, - 14391, 14392, 14393, 14394, 14395, 14396, 14397, 14398, 14399, 14400, - 14401, 14402, 14403, 14404, 14405, 14406, 14407, 14408, 14409, 14410, - 14411, 14412, 14413, 14414, 14415, 14416, 14417, 14418, 14419, 14420, - 14421, 14422, 14423, 14424, 14425, 14426, 14427, 14428, 14429, 14430, - 14431, 14432, 14433, 14434, 14435, 14436, 14437, 14438, 14439, 14440, - 14441, 14442, 14443, 14444, 14445, 14446, 14447, 14448, 14449, 14450, - 14451, 14452, 14453, 14454, 14455, 14456, 14457, 14458, 14459, 14460, - 14461, 14462, 14463, 14464, 14465, 14466, 14467, 14468, 14469, 14470, - 14471, 14472, 14473, 14474, 14475, 14476, 14477, 14478, 14479, 14480, - 14481, 14482, 14483, 14484, 14485, 14486, 14487, 14488, 14489, 14490, - 14491, 14492, 14493, 14494, 14495, 14496, 14497, 14498, 14499, 14500, - 14501, 14502, 14503, 14504, 14505, 14506, 14507, 14508, 14509, 14510, - 14511, 14512, 14513, 14514, 14515, 14516, 14517, 14518, 14519, 14520, - 14521, 14522, 14523, 14524, 14525, 14526, 14527, 14528, 14529, 14530, - 14531, 14532, 14533, 14534, 14535, 14536, 14537, 14538, 14539, 14540, - 14541, 14542, 14543, 14544, 14545, 14546, 14547, 14548, 14549, 14550, - 14551, 14552, 14553, 14554, 14555, 14556, 14557, 14558, 14559, 14560, - 14561, 14562, 14563, 14564, 14565, 14566, 14567, 14568, 14569, 14570, - 14571, 14572, 14573, 14574, 14575, 14576, 14577, 14578, 14579, 14580, - 14581, 14582, 14583, 14584, 14585, 14586, 14587, 14588, 14589, 14590, - 14591, 14592, 14593, 14594, 14595, 14596, 14597, 14598, 14599, 14600, - 14601, 14602, 14603, 14604, 14605, 14606, 14607, 14608, 14609, 14610, - 14611, 14612, 14613, 14614, 14615, 14616, 14617, 14618, 14619, 14620, - 14621, 14622, 14623, 14624, 14625, 14626, 14627, 14628, 14629, 14630, - 14631, 14632, 14633, 14634, 14635, 14636, 14637, 14638, 14639, 14640, - 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649, 14650, - 14651, 14652, 14653, 14654, 14655, 14656, 14657, 14658, 14659, 14660, - 14661, 14662, 14663, 14664, 14665, 14666, 14667, 14668, 14669, 14670, - 14671, 14672, 14673, 14674, 14675, 14676, 14677, 14678, 14679, 14680, - 14681, 14682, 14683, 14684, 14685, 14686, 14687, 14688, 14689, 14690, - 14691, 14692, 14693, 14694, 14695, 14696, 14697, 14698, 14699, 14700, - 14701, 14702, 14703, 14704, 14705, 14706, 14707, 14708, 14709, 14710, - 14711, 14712, 14713, 14714, 14715, 14716, 14717, 14718, 14719, 14720, - 14721, 14722, 14723, 14724, 14725, 14726, 14727, 14728, 14729, 14730, - 14731, 14732, 14733, 14734, 14735, 14736, 14737, 14738, 14739, 14740, - 14741, 14742, 14743, 14744, 14745, 14746, 14747, 14748, 14749, 14750, - 14751, 14752, 14753, 14754, 14755, 14756, 14757, 14758, 14759, 14760, - 14761, 14762, 14763, 14764, 14765, 14766, 14767, 14768, 14769, 14770, - 14771, 14772, 14773, 14774, 14775, 14776, 14777, 14778, 14779, 14780, - 14781, 14782, 14783, 14784, 14785, 14786, 14787, 14788, 14789, 14790, - 14791, 14792, 14793, 14794, 14795, 14796, 14797, 14798, 14799, 14800, - 14801, 14802, 14803, 14804, 14805, 14806, 14807, 14808, 14809, 14810, - 14811, 14812, 14813, 14814, 14815, 14816, 14817, 14818, 14819, 14820, - 14821, 14822, 14823, 14824, 14825, 14826, 14827, 14828, 14829, 14830, - 14831, 14832, 14833, 14834, 14835, 14836, 14837, 14838, 14839, 14840, - 14841, 14842, 14843, 14844, 14845, 14846, 14847, 14848, 14849, 14850, - 14851, 14852, 14853, 14854, 14855, 14856, 14857, 14858, 14859, 14860, - 14861, 14862, 14863, 14864, 14865, 14866, 14867, 14868, 14869, 14870, - 14871, 14872, 14873, 14874, 14875, 14876, 14877, 14878, 14879, 14880, - 14881, 14882, 14883, 14884, 14885, 14886, 14887, 14888, 14889, 14890, - 14891, 14892, 14893, 14894, 14895, 14896, 14897, 14898, 14899, 14900, - 14901, 14902, 14903, 14904, 14905, 14906, 14907, 14908, 14909, 14910, - 14911, 14912, 14913, 14914, 14915, 14916, 14917, 14918, 14919, 14920, - 14921, 14922, 14923, 14924, 14925, 14926, 14927, 14928, 14929, 14930, - 14931, 14932, 14933, 14934, 14935, 14936, 14937, 14938, 14939, 14940, - 14941, 14942, 14943, 14944, 14945, 14946, 14947, 14948, 14949, 14950, - 14951, 14952, 14953, 14954, 14955, 14956, 14957, 14958, 14959, 14960, - 14961, 14962, 14963, 14964, 14965, 14966, 14967, 14968, 14969, 14970, - 14971, 14972, 14973, 14974, 14975, 14976, 14977, 14978, 14979, 14980, - 14981, 14982, 14983, 14984, 14985, 14986, 14987, 14988, 14989, 14990, - 14991, 14992, 14993, 14994, 14995, 14996, 14997, 14998, 14999, 15000, - 15001, 15002, 15003, 15004, 15005, 15006, 15007, 15008, 15009, 15010, - 15011, 15012, 15013, 15014, 15015, 15016, 15017, 15018, 15019, 15020, - 15021, 15022, 15023, 15024, 15025, 15026, 15027, 15028, 15029, 15030, - 15031, 15032, 15033, 15034, 15035, 15036, 15037, 15038, 15039, 15040, - 15041, 15042, 15043, 15044, 15045, 15046, 15047, 15048, 15049, 15050, - 15051, 15052, 15053, 15054, 15055, 15056, 15057, 15058, 15059, 15060, - 15061, 15062, 15063, 15064, 15065, 15066, 15067, 15068, 15069, 15070, - 15071, 15072, 15073, 15074, 15075, 15076, 15077, 15078, 15079, 15080, - 15081, 15082, 15083, 15084, 15085, 15086, 15087, 15088, 15089, 15090, - 15091, 15092, 15093, 15094, 15095, 15096, 15097, 15098, 15099, 15100, - 15101, 15102, 15103, 15104, 15105, 15106, 15107, 15108, 15109, 15110, - 15111, 15112, 15113, 15114, 15115, 15116, 15117, 15118, 15119, 15120, - 15121, 15122, 15123, 15124, 15125, 15126, 15127, 15128, 15129, 15130, - 15131, 15132, 15133, 15134, 15135, 15136, 15137, 15138, 15139, 15140, - 15141, 15142, 15143, 15144, 15145, 15146, 15147, 15148, 15149, 15150, - 15151, 15152, 15153, 15154, 15155, 15156, 15157, 15158, 15159, 15160, - 15161, 15162, 15163, 15164, 15165, 15166, 15167, 15168, 15169, 15170, - 15171, 15172, 15173, 15174, 15175, 15176, 15177, 15178, 15179, 15180, - 15181, 15182, 15183, 15184, 15185, 15186, 15187, 15188, 15189, 15190, - 15191, 15192, 15193, 15194, 15195, 15196, 15197, 15198, 15199, 15200, - 15201, 15202, 15203, 15204, 15205, 15206, 15207, 15208, 15209, 15210, - 15211, 15212, 15213, 15214, 15215, 15216, 15217, 15218, 15219, 15220, - 15221, 15222, 15223, 15224, 15225, 15226, 15227, 15228, 15229, 15230, - 15231, 15232, 15233, 15234, 15235, 15236, 15237, 15238, 15239, 15240, - 15241, 15242, 15243, 15244, 15245, 15246, 15247, 15248, 15249, 15250, - 15251, 15252, 15253, 15254, 15255, 15256, 15257, 15258, 15259, 15260, - 15261, 15262, 15263, 15264, 15265, 15266, 15267, 15268, 15269, 15270, - 15271, 15272, 15273, 15274, 15275, 15276, 15277, 15278, 15279, 15280, - 15281, 15282, 15283, 15284, 15285, 15286, 15287, 15288, 15289, 15290, - 15291, 15292, 15293, 15294, 15295, 15296, 15297, 15298, 15299, 15300, - 15301, 15302, 15303, 15304, 15305, 15306, 15307, 15308, 15309, 15310, - 15311, 15312, 15313, 15314, 15315, 15316, 15317, 15318, 15319, 15320, - 15321, 15322, 15323, 15324, 15325, 15326, 15327, 15328, 15329, 15330, - 15331, 15332, 15333, 15334, 15335, 15336, 15337, 15338, 15339, 15340, - 15341, 15342, 15343, 15344, 15345, 15346, 15347, 15348, 15349, 15350, - 15351, 15352, 15353, 15354, 15355, 15356, 15357, 15358, 15359, 15360, - 15361, 15362, 15363, 15364, 15365, 15366, 15367, 15368, 15369, 15370, - 15371, 15372, 15373, 15374, 15375, 15376, 15377, 15378, 15379, 15380, - 15381, 15382, 15383, 15384, 15385, 15386, 15387, 15388, 15389, 15390, - 15391, 15392, 15393, 15394, 15395, 15396, 15397, 15398, 15399, 15400, - 15401, 15402, 15403, 15404, 15405, 15406, 15407, 15408, 15409, 15410, - 15411, 15412, 15413, 15414, 15415, 15416, 15417, 15418, 15419, 15420, - 15421, 15422, 15423, 15424, 15425, 15426, 15427, 15428, 15429, 15430, - 15431, 15432, 15433, 15434, 15435, 15436, 15437, 15438, 15439, 15440, - 15441, 15442, 15443, 15444, 15445, 15446, 15447, 15448, 15449, 15450, - 15451, 15452, 15453, 15454, 15455, 15456, 15457, 15458, 15459, 15460, - 15461, 15462, 15463, 15464, 15465, 15466, 15467, 15468, 15469, 15470, - 15471, 15472, 15473, 15474, 15475, 15476, 15477, 15478, 15479, 15480, - 15481, 15482, 15483, 15484, 15485, 15486, 15487, 15488, 15489, 15490, - 15491, 15492, 15493, 15494, 15495, 15496, 15497, 15498, 15499, 15500, - 15501, 15502, 15503, 15504, 15505, 15506, 15507, 15508, 15509, 15510, - 15511, 15512, 15513, 15514, 15515, 15516, 15517, 15518, 15519, 15520, - 15521, 15522, 15523, 15524, 15525, 15526, 15527, 15528, 15529, 15530, - 15531, 15532, 15533, 15534, 15535, 15536, 15537, 15538, 15539, 15540, - 15541, 15542, 15543, 15544, 15545, 15546, 15547, 15548, 15549, 15550, - 15551, 15552, 15553, 15554, 15555, 15556, 15557, 15558, 15559, 15560, - 15561, 15562, 15563, 15564, 15565, 15566, 15567, 15568, 15569, 15570, - 15571, 15572, 15573, 15574, 15575, 15576, 15577, 15578, 15579, 15580, - 15581, 15582, 15583, 15584, 15585, 15586, 15587, 15588, 15589, 15590, - 15591, 15592, 15593, 15594, 15595, 15596, 15597, 15598, 15599, 15600, - 15601, 15602, 15603, 15604, 15605, 15606, 15607, 15608, 15609, 15610, - 15611, 15612, 15613, 15614, 15615, 15616, 15617, 15618, 15619, 15620, - 15621, 15622, 15623, 15624, 15625, 15626, 15627, 15628, 15880, 15881, - 15882, 15883, 15884, 15885, 15886, 15887, 15888, 15889, 15890, 15891, - 15892, 15893, 15894, 15895, 15896, 15897, 15898, 15899, 15900, 15901, - 15902, 15903, 15904, 15905, 15906, 15907, 15908, 15909, 15910, 15911, - 15912, 15913, 15914, 15915, 15916, 15917, 15918, 15919, 15920, 15921, - 15922, 15923, 15924, 15925, 15926, 15927, 15928, 15929, 15930, 15931, - 15932, 15933, 15934, 15935, 15936, 15937, 15938, 15939, 15940, 15941, - 15942, 15943, 15944, 15945, 15946, 15947, 15948, 15949, 15950, 15951, - 15952, 15953, 15954, 15955, 15956, 15957, 15958, 15959, 15960, 15961, - 15962, 15963, 15964, 15965, 15966, 15967, 15968, 15969, 15970, 15971, - 15972, 15973, 15974, 15975, 15976, 15977, 15978, 15979, 15980, 15981, - 15982, 15983, 15984, 15985, 15986, 15987, 15988, 15989, 15990, 15991, - 15992, 15993, 15994, 15995, 15996, 15997, 15998, 15999, 16000, 16001, - 16002, 16003, 16004, 16005, 16006, 16007, 16008, 16009, 16010, 16011, - 16012, 16013, 16014, 16015, 16016, 16017, 16018, 16019, 16020, 16021, - 16022, 16023, 16024, 16025, 16026, 16027, 16028, 16029, 16030, 16031, - 16032, 16033, 16034, 16035, 16036, 16037, 16038, 16039, 16040, 16041, - 16042, 16043, 16044, 16045, 16046, 16047, 16048, 16049, 16050, 16051, - 16052, 16053, 16054, 16055, 16056, 16057, 16058, 16059, 16060, 16061, - 16062, 16063, 16064, 16065, 16066, 16067, 16068, 16069, 16070, 16071, - 16072, 16073, 16074, 16075, 16076, 16077, 16078, 16079, 16080, 16081, - 16082, 16083, 16084, 16085, 16086, 16087, 16088, 16089, 16090, 16091, - 16092, 16093, 16094, 16095, 16096, 16097, 16098, 16099, 16100, 16101, - 16102, 16103, 16104, 16105, 16106, 16107, 16108, 16109, 16110, 16111, - 16112, 16113, 16114, 16115, 16116, 16117, 16118, 16119, 16120, 16121, - 16122, 16123, 16124, 16125, 16126, 16127, 16128, 16129, 16130, 16131, - 16132, 16133, 16134, 16135, 16136, 16137, 16138, 16139, 16140, 16141, - 16142, 16143, 16144, 16145, 16146, 16147, 16148, 16149, 16150, 16151, - 16152, 16153, 16154, 16155, 16156, 16157, 16158, 16159, 16160, 16161, - 16162, 16163, 16164, 16165, 16166, 16167, 16168, 16169, 16170, 16171, - 16172, 16173, 16174, 16175, 16176, 16177, 16178, 16179, 16180, 16181, - 16182, 16183, 16184, 16185, 16186, 16187, 16188, 16189, 16190, 16191, - 16192, 16193, 16194, 16195, 16196, 16197, 16198, 16199, 16200, 16201, - 16202, 16203, 16204, 16205, 16206, 16207, 16208, 16209, 16210, 16211, - 16212, 16213, 16214, 16215, 16216, 16217, 16218, 16219, 16220, 16221, - 16222, 16223, 16224, 16225, 16226, 16227, 16228, 16229, 16230, 16231, - 16232, 16233, 16234, 16235, 16236, 16237, 16238, 16239, 16240, 16241, - 16242, 16243, 16244, 16245, 16246, 16247, 16248, 16249, 16250, 16251, - 16252, 16253, 16254, 16255, 16256, 16257, 16258, 16259, 16260, 16261, - 16262, 16263, 16264, 16265, 16266, 16267, 16268, 16269, 16270, 16271, - 16272, 16273, 16274, 16275, 16276, 16277, 16278, 16279, 16280, 16281, - 16282, 16283, 16284, 16285, 16286, 16287, 16288, 16289, 16290, 16291, - 16292, 16293, 16294, 16295, 16296, 16297, 16298, 16299, 16300, 16301, - 16302, 16303, 16304, 16305, 16306, 16307, 16308, 16309, 16310, 16311, - 16312, 16313, 16314, 16315, 16316, 16317, 16318, 16319, 16320, 16321, - 16322, 16323, 16324, 16325, 16326, 16327, 16328, 16329, 16330, 16331, - 16332, 16333, 16334, 16335, 16336, 16337, 16338, 16339, 16340, 16341, - 16342, 16343, 16344, 16345, 16346, 16347, 16348, 16349, 16350, 16351, - 16352, 16353, 16354, 16355, 16356, 16357, 16358, 16359, 16360, 16361, - 16362, 16363, 16364, 16365, 16366, 16367, 16368, 16369, 16370, 16371, - 16372, 16373, 16374, 16375, 16376, 16377, 16378, 16379, 16380, 16381, - 16382, 16383, 16384, 16385, 16386, 16387, 16388, 16389, 16390, 16391, - 16392, 16393, 16394, 16395, 16396, 16397, 16398, 16399, 16400, 16401, - 16402, 16403, 16404, 16405, 16406, 16407, 16408, 16409, 16410, 16411, - 16412, 16413, 16414, 16415, 16416, 16417, 16418, 16419, 16420, 16421, - 16422, 16423, 16424, 16425, 16426, 16427, 16428, 16429, 16430, 16431, - 16432, 16433, 16434, 16435, 16436, 16437, 16438, 16439, 16440, 16441, - 16442, 16443, 16444, 16445, 16446, 16447, 16448, 16449, 16450, 16451, - 16452, 16453, 16454, 16455, 16456, 16457, 16458, 16459, 16460, 16461, - 16462, 16463, 16464, 16465, 16466, 16467, 16468, 16469, 16470, 16471, - 16472, 16473, 16474, 16475, 16476, 16477, 16478, 16479, 16480, 16481, - 16482, 16483, 16484, 16485, 16486, 16487, 16488, 16489, 16490, 16491, - 16492, 16493, 16494, 16495, 16496, 16497, 16498, 16499, 16500, 16501, - 16502, 16503, 16504, 16505, 16506, 16507, 16508, 16509, 16510, 16511, - 16512, 16513, 16514, 16515, 16516, 16517, 16518, 16519, 16520, 16521, - 16522, 16523, 16524, 16525, 16526, 16527, 16528, 16529, 16530, 16531, - 16532, 16533, 16534, 16535, 16536, 16537, 16538, 16539, 16540, 16541, - 16542, 16543, 16544, 16545, 16546, 16547, 16548, 16549, 16550, 16551, - 16552, 16553, 16554, 16555, 16556, 16557, 16558, 16559, 16560, 16561, - 16562, 16563, 16564, 16565, 16566, 16567, 16568, 16569, 16570, 16571, - 16572, 16573, 16574, 16575, 16576, 16577, 16578, 16579, 16580, 16581, - 16582, 16583, 16584, 16585, 16586, 16587, 16588, 16589, 16590, 16591, - 16592, 16593, 16594, 16595, 16596, 16597, 16598, 16599, 16600, 16601, - 16602, 16603, 16604, 16605, 16606, 16607, 16608, 16609, 16610, 16611, - 16612, 16613, 16614, 16615, 16616, 16617, 16618, 16619, 16620, 16621, - 16622, 16623, 16624, 16625, 16626, 16627, 16628, 16629, 16630, 16631, - 16632, 16633, 16634, 16635, 16636, 16637, 16638, 16639, 16640, 16641, - 16642, 16643, 16644, 16645, 16646, 16647, 15640, 15641, 15642, 15643, - 15644, 15645, 15646, 15647, 15648, 15649, 15650, 15651, 15652, 15653, - 15654, 15655, 15656, 15657, 15658, 15659, 15660, 15661, 15662, 15663, - 15664, 15665, 15666, 15667, 15668, 15669, 15670, 15671, 15672, 15673, - 15674, 15675, 15676, 15677, 15678, 15679, 15680, 15681, 15682, 15683, - 15684, 15685, 15686, 15687, 15688, 15689, 15690, 15691, 15692, 15693, - 15694, 15695, 15696, 15697, 15698, 15699, 15700, 15701, 15702, 15703, - 15704, 15705, 15706, 15707, 15708, 15709, 15710, 15711, 15712, 15713, - 15714, 15715, 15716, 15717, 15718, 15719, 15720, 15721, 15722, 15723, - 15724, 15725, 15726, 15727, 15728, 15729, 15730, 15731, 15732, 15733, - 15734, 15735, 15736, 15737, 15738, 15739, 15740, 15741, 15742, 15743, - 15744, 15745, 15746, 15747, 15748, 15749, 15750, 15751, 15752, 15753, - 15754, 15755, 15756, 15757, 15758, 15759, 15760, 15761, 15762, 15763, - 15764, 15765, 15766, 15767, 15768, 15769, 15770, 15771, 15772, 15773, - 15774, 15775, 15776, 15777, 15778, 15779, 15780, 15781, 15782, 15783, - 15784, 15785, 15786, 15787, 15788, 15789, 15790, 15791, 15792, 15793, - 15794, 15795, 15796, 15797, 15798, 15799, 15800, 15801, 15802, 15803, - 15804, 15805, 15806, 15807, 15808, 15809, 15810, 15811, 15812, 15813, - 15814, 15815, 15816, 15817, 15818, 15819, 15820, 15821, 15822, 15823, - 15824, 15825, 15826, 15827, 15828, 15829, 15830, 15831, 15832, 15833, - 15834, 15835, 15836, 15837, 15838, 15839, 15840, 15841, 15842, 15843, - 15844, 15845, 15846, 15847, 15848, 15849, 15850, 15851, 15852, 15853, - 15854, 15855, 15856, 15857, 15858, 15859, 15860, 15861, 15862, 15863, - 15864, 15865, 15866, 15867, 15868, 15869, 15870, 15871, 15872, 15873, - 15874, 15875, 15876, 15877, 15878, 15879, 15629, 15630, 15631, 15632, - 15633, 15634, 15635, 15636, 15637, 15638, 15639, 40951, 40951, 40951, - 40951, 40951, 445, 446, 447, 448, 449, 450, 451, 452, 453, 434, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 375, 376, 377, 378, 379, 380, - 373, 374, 381, 382, 383, 425, 426, 427, 428, 429, 430, 431, 432, 433, - 423, 424, 391, 387, 388, 392, 393, 394, 389, 390, 384, 385, 386, 395, - 396, 397, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 402, 403, - 404, 405, 406, 407, 398, 399, 400, 401, 408, 409, 410, 464, 465, 466, - 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, - 481, 482, 483, 415, 416, 417, 418, 419, 420, 421, 411, 412, 413, 414, - 422, 495, 496, 497, 498, 499, 500, 501, 484, 485, 486, 487, 492, 493, - 494, 502, 488, 489, 490, 491, 503, 504, 505, 506, 507, 510, 511, 512, - 513, 508, 509, 514, 515, 516, 517, 520, 521, 522, 523, 524, 518, 519, - 525, 526, 527, 528, 531, 532, 533, 534, 535, 529, 530, 536, 537, 538, - 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, - 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, - 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, - 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, - 595, 596, 597, 598, 599, 607, 608, 600, 601, 602, 609, 610, 611, 612, - 603, 604, 613, 605, 606, 618, 619, 620, 621, 622, 614, 615, 616, 617, - 623, 624, 625, 651, 652, 653, 654, 655, 656, 657, 649, 650, 658, 659, - 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, - 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, - 699, 700, 662, 663, 664, 665, 666, 667, 668, 660, 661, 669, 670, 701, - 702, 703, 704, 705, 706, 707, 708, 709, 710, 640, 641, 642, 643, 644, - 645, 646, 647, 648, 638, 639, 630, 631, 632, 633, 626, 627, 634, 635, - 636, 637, 628, 629, 713, 714, 715, 716, 717, 718, 719, 720, 721, 711, - 712, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 724, 725, 726, - 727, 728, 729, 730, 731, 732, 722, 723, 751, 752, 748, 749, 750, 753, - 754, 755, 744, 745, 746, 747, 756, 757, 758, 815, 816, 817, 818, 819, - 820, 821, 822, 823, 824, 735, 736, 737, 738, 739, 740, 741, 742, 743, - 733, 734, 763, 764, 765, 766, 759, 760, 767, 768, 769, 761, 762, 770, - 796, 794, 795, 797, 798, 799, 800, 801, 802, 803, 804, 777, 773, 774, - 778, 771, 772, 779, 780, 775, 776, 781, 782, 783, 785, 786, 787, 784, - 788, 789, 790, 791, 792, 793, 856, 857, 858, 859, 860, 861, 862, 863, - 864, 865, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 866, - 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, - 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, - 895, 836, 837, 840, 841, 842, 843, 844, 845, 838, 839, 846, 847, 896, - 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, - 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, - 925, 848, 849, 850, 851, 852, 853, 854, 855, 927, 928, 929, 930, 931, - 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, - 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 926, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 18950, 18940, 18939, 18936, 18935, 18921, 18934, - 18933, 18938, 18937, 18943, 18928, 18927, 18924, 18923, 18948, 18930, - 18929, 18926, 18925, 18922, 18942, 18941, 18932, 18931, 18945, 18949, - 18946, 18944, 18947, 18953, 18960, 18961, 18956, 18957, 18962, 18963, - 18954, 18958, 18959, 18955, 18964, 18920, 18919, 18917, 18951, 18918, - 18952, 18971, 18973, 18970, 18969, 18966, 18965, 18968, 18967, 18974, - 18972, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 2847, - 2813, 2872, 2873, 2843, 2880, 2891, 2862, 2879, 2874, 2875, 2826, 2892, - 2849, 2828, 2833, 2840, 2886, 2858, 2816, 2852, 2887, 2848, 2823, 2824, - 2856, 2830, 2871, 2812, 2870, 2839, 2863, 2894, 2811, 2857, 2888, 2842, - 2841, 2837, 2814, 2869, 2846, 2876, 2829, 2866, 2877, 2893, 2821, 2883, - 2890, 2831, 2817, 2845, 2819, 2838, 2881, 2822, 2896, 2898, 2818, 2884, - 2834, 2878, 2855, 2882, 2860, 2867, 2851, 2895, 2850, 2832, 2864, 2835, - 2861, 2889, 2885, 2868, 2853, 2825, 2859, 2815, 2854, 2897, 2820, 2865, - 2844, 2836, 2930, 2946, 2944, 2943, 2909, 2915, 2904, 2950, 2914, 2906, - 2936, 2949, 2908, 2934, 2935, 2899, 2939, 2947, 2941, 2942, 2921, 2918, - 2933, 2902, 2900, 2901, 2907, 2937, 2954, 2928, 2926, 2951, 2940, 2948, - 2920, 2924, 2925, 2922, 2945, 2917, 2923, 2932, 2938, 2919, 2952, 2916, - 2953, 2903, 2913, 2912, 2910, 2927, 2931, 2911, 2905, 2929, 3006, 3026, - 3047, 3043, 3005, 2994, 3007, 2955, 2983, 2957, 3027, 3023, 2980, 3028, - 2998, 2977, 2960, 2956, 2962, 3046, 3025, 2988, 3018, 2986, 3048, 2967, - 2968, 3032, 2999, 3036, 3014, 3040, 3035, 3001, 3042, 2992, 2974, 3024, - 3002, 2970, 2985, 2990, 3021, 3037, 3004, 3051, 2995, 3020, 3017, 3050, - 3041, 2982, 3052, 3010, 2969, 3039, 3015, 3012, 2964, 3000, 2976, 2987, - 2972, 2966, 3011, 3009, 3044, 3003, 3019, 3022, 2965, 3016, 2996, 2973, - 3049, 2997, 3033, 3031, 2984, 2975, 2979, 2961, 2981, 2963, 2978, 3045, - 3013, 2991, 2989, 3034, 2959, 2958, 3008, 2993, 2971, 3029, 3030, 3038, - 3080, 3164, 3113, 3087, 3114, 3073, 3112, 3118, 3100, 3127, 3163, 3109, - 3143, 3110, 3057, 3156, 3141, 3116, 3148, 3061, 3165, 3063, 3150, 3085, - 3095, 3076, 3082, 3152, 3169, 3111, 3058, 3106, 3158, 3056, 3108, 3053, - 3096, 3090, 3068, 3097, 3092, 3091, 3133, 3089, 3086, 3074, 3119, 3078, - 3066, 3125, 3154, 3153, 3166, 3059, 3140, 3157, 3105, 3084, 3120, 3060, - 3136, 3131, 3126, 3071, 3099, 3088, 3103, 3167, 3135, 3168, 3098, 3122, - 3147, 3064, 3102, 3107, 3159, 3081, 3065, 3121, 3155, 3077, 3101, 3069, - 3104, 3117, 3115, 3055, 3062, 3137, 3161, 3160, 3128, 3139, 3070, 3083, - 3075, 3149, 3094, 3145, 3142, 3067, 3130, 3146, 3123, 3132, 3129, 3144, - 3134, 3093, 3072, 3138, 3162, 3124, 3079, 3151, 3054, 3223, 3300, 3210, - 3197, 3307, 3200, 3263, 3289, 3279, 3249, 3226, 3274, 3294, 3235, 3190, - 3310, 3282, 3228, 3264, 3299, 3192, 3202, 3251, 3241, 3207, 3238, 3242, - 3250, 3281, 3248, 3267, 3290, 3231, 3214, 3184, 3237, 3245, 3208, 3201, - 3229, 3225, 3291, 3283, 3277, 3222, 3230, 3315, 3183, 3304, 3311, 3271, - 3303, 3187, 3288, 3297, 3305, 3308, 3196, 3273, 3293, 3181, 3243, 3284, - 3213, 3211, 3256, 3260, 3180, 3302, 3191, 3323, 3254, 3316, 3212, 3224, - 3269, 3319, 3199, 3173, 3179, 3240, 3189, 3206, 3236, 3185, 3175, 3252, - 3265, 3313, 3227, 3255, 3257, 3272, 3216, 3174, 3259, 3217, 3182, 3172, - 3220, 3275, 3239, 3193, 3270, 3253, 3312, 3232, 3261, 3171, 3178, 3246, - 3324, 3301, 3326, 3325, 3198, 3262, 3292, 3295, 3221, 3287, 3314, 3233, - 3320, 3317, 3318, 3322, 3321, 3188, 3266, 3247, 3276, 3309, 3177, 3306, - 3204, 3215, 3280, 3278, 3234, 3244, 3285, 3286, 3170, 3258, 3268, 3203, - 3195, 3218, 3205, 3209, 3296, 3194, 3219, 3298, 3176, 3186, 3331, 3380, - 3333, 3378, 3358, 3371, 3352, 3335, 3361, 3360, 3340, 3370, 3350, 3346, - 3337, 3368, 3363, 3369, 3366, 3329, 3328, 3348, 3347, 3345, 3373, 3365, - 3374, 3349, 3354, 3351, 3375, 3355, 3362, 3353, 3357, 3327, 3343, 3344, - 3364, 3356, 3379, 3376, 3336, 3334, 3332, 3338, 3359, 3341, 3342, 3339, - 3372, 3330, 3367, 3377, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 28219, 28211, 28232, 28209, 28233, 28220, 28235, 28215, 28206, 28223, - 28221, 28231, 28205, 28213, 28208, 28210, 28216, 28214, 28212, 28225, - 28228, 28217, 28227, 28234, 28226, 28207, 28230, 28229, 28222, 28224, - 28218, 40951, 28244, 28246, 28243, 28242, 28239, 28238, 28241, 28240, - 28247, 28245, 40951, 40951, 40951, 40951, 28237, 28236, 35842, 35839, - 35840, 35841, 35794, 35791, 35792, 35793, 35846, 35843, 35844, 35845, - 35834, 35831, 35832, 35833, 35838, 35835, 35836, 35837, 35830, 35827, - 35828, 35829, 35790, 35787, 35788, 35789, 35822, 35819, 35820, 35821, - 35795, 35800, 35811, 35812, 35823, 35826, 35824, 35825, 35818, 35815, - 35816, 35817, 35806, 35803, 35804, 35805, 35857, 35856, 35855, 35807, - 35814, 35864, 35862, 35859, 35809, 35858, 35860, 35802, 35810, 35799, - 35801, 35798, 35849, 35853, 35861, 35808, 35813, 35851, 35848, 35854, - 35797, 35847, 35863, 35796, 35852, 35850, 35865, 40951, 35872, 35874, - 35871, 35870, 35867, 35866, 35869, 35868, 35875, 35873, 40951, 40951, - 40951, 40951, 40951, 40951, 3441, 3446, 3462, 3464, 3454, 3452, 3444, - 3438, 3445, 3458, 3453, 3449, 3460, 3443, 3439, 3461, 3448, 3459, 3463, - 3457, 3451, 3465, 3450, 3466, 3455, 3456, 3447, 3442, 3440, 3467, 40951, - 40951, 3434, 3436, 3437, 3435, 3433, 3468, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 30994, 30995, 31000, 31001, - 30988, 30989, 31004, 31005, 30996, 30997, 30986, 30987, 31006, 31007, - 30990, 30991, 31002, 31003, 31008, 31009, 30998, 30999, 30992, 30993, - 31010, 31011, 30984, 30985, 30930, 30921, 30927, 30918, 30923, 30929, - 30922, 30926, 30932, 30916, 30928, 30914, 30919, 30917, 30925, 30920, - 30924, 30933, 30931, 30915, 30938, 30937, 30935, 30934, 30936, 30940, - 30939, 30970, 30971, 30949, 30969, 30967, 30975, 30977, 30976, 30978, - 30968, 30960, 30973, 30958, 30980, 30953, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 31018, 31020, 31017, 31016, - 31013, 31012, 31015, 31014, 31021, 31019, 40951, 30945, 30942, 30944, - 30947, 30941, 30943, 30946, 40951, 30972, 30979, 30957, 30965, 30981, - 30956, 30963, 30974, 30962, 30983, 30964, 30959, 30966, 30982, 30961, - 30955, 30948, 30951, 30952, 30954, 30950, 40951, 40951, 40951, 40951, - 40951, 30902, 30909, 30901, 30900, 30910, 30898, 30895, 30913, 30905, - 30903, 30911, 30897, 30896, 30906, 30912, 30908, 30904, 30899, 30907, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 22525, 22522, 22527, 22521, - 22510, 22509, 22506, 22505, 22498, 22504, 22503, 22508, 22507, 22499, - 22495, 22494, 22491, 22490, 22497, 22496, 22493, 22492, 22500, 22512, - 22511, 22502, 22501, 22517, 22520, 22518, 22516, 22519, 22514, 22513, - 22515, 22528, 22534, 22531, 22532, 22533, 22529, 22535, 22530, 22526, - 22524, 22523, 22537, 22536, 22544, 22546, 22543, 22542, 22539, 22538, - 22541, 22540, 22547, 22545, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 26886, 26890, 26893, 26894, 26864, 26896, 26872, 26887, - 26891, 26882, 26881, 26883, 26871, 26863, 26884, 26880, 26877, 26878, - 26892, 26874, 26885, 26888, 26870, 26868, 26895, 26879, 26876, 26866, - 26889, 26875, 26865, 26873, 26944, 26948, 26951, 26952, 26922, 26954, - 26930, 26945, 26949, 26940, 26939, 26941, 26929, 26921, 26942, 26938, - 26935, 26936, 26950, 26932, 26943, 26946, 26928, 26926, 26953, 26937, - 26934, 26924, 26947, 26933, 26923, 26931, 26908, 26902, 26900, 26898, - 26905, 26904, 26907, 26906, 26910, 26909, 26913, 26915, 26912, 26911, - 26916, 26917, 26919, 26920, 26914, 26918, 26903, 26901, 26899, 26897, - 26957, 26955, 26956, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 27502, 27428, 27490, 27501, 27506, 27505, - 27425, 27507, 27482, 27481, 27479, 27436, 27485, 27486, 27478, 27435, - 27444, 27452, 27488, 27424, 27449, 27448, 27443, 27442, 27441, 27440, - 27466, 27434, 27465, 27433, 27508, 27439, 27489, 27500, 27499, 27447, - 27446, 27423, 27504, 27510, 27438, 27437, 27475, 27431, 27451, 27450, - 27474, 27430, 27483, 27487, 27459, 27462, 27463, 27497, 27495, 27476, - 27432, 27484, 27464, 27498, 27496, 27494, 27492, 27422, 27493, 27491, - 27509, 27426, 27503, 27427, 27461, 27429, 27480, 27477, 27460, 40951, - 40951, 40951, 40951, 27514, 27445, 27513, 27512, 27511, 27519, 27525, - 27524, 27520, 27521, 27546, 27550, 27567, 27566, 27528, 27531, 27532, - 27548, 27535, 27536, 27537, 27538, 27539, 27542, 27544, 27545, 27541, - 27552, 27553, 27554, 27555, 27560, 27556, 27557, 27561, 27563, 27522, - 27523, 27530, 27565, 27529, 27564, 27526, 27534, 27527, 27551, 27568, - 27569, 27558, 27562, 27549, 27547, 27570, 27543, 27533, 27540, 27559, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 27518, 27516, 27517, - 27515, 27467, 27468, 27469, 27470, 27471, 27472, 27473, 27453, 27454, - 27455, 27456, 27457, 27458, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 36644, 29851, - 30073, 30072, 22168, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 38877, 38876, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 35876, 35877, 35878, 35879, 35880, 35881, 35882, 35883, 35884, 35885, - 35886, 35887, 35888, 35889, 35890, 35891, 35892, 35893, 35894, 35895, - 35896, 35897, 35898, 35899, 35900, 35901, 35902, 35903, 35904, 35905, - 35906, 35907, 35908, 35909, 35910, 35911, 35912, 35913, 35914, 35915, - 35916, 35917, 35918, 35919, 35920, 35921, 35922, 35923, 35924, 35925, - 35926, 35927, 35928, 35929, 35930, 35931, 35932, 35933, 35934, 35935, - 35936, 35937, 35938, 35939, 35940, 35941, 35942, 35943, 35944, 35945, - 35946, 35947, 35948, 35949, 35950, 35951, 35952, 35953, 35954, 35955, - 35956, 35957, 35958, 35959, 35960, 35961, 35962, 35963, 35964, 35965, - 35966, 35967, 35968, 35969, 35970, 35971, 35972, 35973, 35974, 35975, - 35976, 35977, 35978, 35979, 35980, 35981, 35982, 35983, 35984, 35985, - 35986, 35987, 35988, 35989, 35990, 35991, 35992, 35993, 35994, 35995, - 35996, 35997, 35998, 35999, 36000, 36001, 36002, 36003, 36004, 36005, - 36006, 36007, 36008, 36009, 36010, 36011, 36012, 36013, 36014, 36015, - 36016, 36017, 36018, 36019, 36020, 36021, 36022, 36023, 36024, 36025, - 36026, 36027, 36028, 36029, 36030, 36031, 36032, 36033, 36034, 36035, - 36036, 36037, 36038, 36039, 36040, 36041, 36042, 36043, 36044, 36045, - 36046, 36047, 36048, 36049, 36050, 36051, 36052, 36053, 36054, 36055, - 36056, 36057, 36058, 36059, 36060, 36061, 36062, 36063, 36064, 36065, - 36066, 36067, 36068, 36069, 36070, 36071, 36072, 36073, 36074, 36075, - 36076, 36077, 36078, 36079, 36080, 36081, 36082, 36083, 36084, 36085, - 36086, 36087, 36088, 36089, 36090, 36091, 36092, 36093, 36094, 36095, - 36096, 36097, 36098, 36099, 36100, 36101, 36102, 36103, 36104, 36105, - 36106, 36107, 36108, 36109, 36110, 36111, 36112, 36113, 36114, 36115, - 36116, 36117, 36118, 36119, 36120, 36121, 36122, 36123, 36124, 36125, - 36126, 36127, 36128, 36129, 36130, 36131, 36132, 36133, 36134, 36135, - 36136, 36137, 36138, 36139, 36140, 36141, 36142, 36143, 36144, 36145, - 36146, 36147, 36148, 36149, 36150, 36151, 36152, 36153, 36154, 36155, - 36156, 36157, 36158, 36159, 36160, 36161, 36162, 36163, 36164, 36165, - 36166, 36167, 36168, 36169, 36170, 36171, 36172, 36173, 36174, 36175, - 36176, 36177, 36178, 36179, 36180, 36181, 36182, 36183, 36184, 36185, - 36186, 36187, 36188, 36189, 36190, 36191, 36192, 36193, 36194, 36195, - 36196, 36197, 36198, 36199, 36200, 36201, 36202, 36203, 36204, 36205, - 36206, 36207, 36208, 36209, 36210, 36211, 36212, 36213, 36214, 36215, - 36216, 36217, 36218, 36219, 36220, 36221, 36222, 36223, 36224, 36225, - 36226, 36227, 36228, 36229, 36230, 36231, 36232, 36233, 36234, 36235, - 36236, 36237, 36238, 36239, 36240, 36241, 36242, 36243, 36244, 36245, - 36246, 36247, 36248, 36249, 36250, 36251, 36252, 36253, 36254, 36255, - 36256, 36257, 36258, 36259, 36260, 36261, 36262, 36263, 36264, 36265, - 36266, 36267, 36268, 36269, 36270, 36271, 36272, 36273, 36274, 36275, - 36276, 36277, 36278, 36279, 36280, 36281, 36282, 36283, 36284, 36285, - 36286, 36287, 36288, 36289, 36290, 36291, 36292, 36293, 36294, 36295, - 36296, 36297, 36298, 36299, 36300, 36301, 36302, 36303, 36304, 36305, - 36306, 36307, 36308, 36309, 36310, 36311, 36312, 36313, 36314, 36315, - 36316, 36317, 36318, 36319, 36320, 36321, 36322, 36323, 36324, 36325, - 36326, 36327, 36328, 36329, 36330, 36331, 36332, 36333, 36334, 36335, - 36336, 36337, 36338, 36339, 36340, 36341, 36342, 36343, 36344, 36345, - 36346, 36347, 36348, 36349, 36350, 36351, 36352, 36353, 36354, 36355, - 36356, 36357, 36358, 36359, 36360, 36361, 36362, 36363, 36364, 36365, - 36366, 36367, 36368, 36369, 36370, 36371, 36372, 36373, 36374, 36375, - 36376, 36377, 36378, 36379, 36380, 36381, 36382, 36383, 36384, 36385, - 36386, 36387, 36388, 36389, 36390, 36391, 36392, 36393, 36394, 36395, - 36396, 36397, 36398, 36399, 36400, 36401, 36402, 36403, 36404, 36405, - 36406, 36407, 36408, 36409, 36410, 36411, 36412, 36413, 36414, 36415, - 36416, 36417, 36418, 36419, 36420, 36421, 36422, 36423, 36424, 36425, - 36426, 36427, 36428, 36429, 36430, 36431, 36432, 36433, 36434, 36435, - 36436, 36437, 36438, 36439, 36440, 36441, 36442, 36443, 36444, 36445, - 36446, 36447, 36448, 36449, 36450, 36451, 36452, 36453, 36454, 36455, - 36456, 36457, 36458, 36459, 36460, 36461, 36462, 36463, 36464, 36465, - 36466, 36467, 36468, 36469, 36470, 36471, 36472, 36473, 36474, 36475, - 36476, 36477, 36478, 36479, 36480, 36481, 36482, 36483, 36484, 36485, - 36486, 36487, 36488, 36489, 36490, 36491, 36492, 36493, 36494, 36495, - 36496, 36497, 36498, 36499, 36500, 36501, 36502, 36503, 36504, 36505, - 36506, 36507, 36508, 36509, 36510, 36511, 36512, 36513, 36514, 36515, - 36516, 36517, 36518, 36519, 36520, 36521, 36522, 36523, 36524, 36525, - 36526, 36527, 36528, 36529, 36530, 36531, 36532, 36533, 36534, 36535, - 36536, 36537, 36538, 36539, 36540, 36541, 36542, 36543, 36544, 36545, - 36546, 36547, 36548, 36549, 36550, 36551, 36552, 36553, 36554, 36555, - 36556, 36557, 36558, 36559, 36560, 36561, 36562, 36563, 36564, 36565, - 36566, 36567, 36568, 36569, 36570, 36571, 36572, 36573, 36574, 36575, - 36576, 36577, 36578, 36579, 36580, 36581, 36582, 36583, 36584, 36585, - 36586, 36587, 36588, 36589, 36590, 36591, 36592, 36593, 36594, 36595, - 36596, 36597, 36598, 36599, 36600, 36601, 36602, 36603, 36604, 36605, - 36606, 36607, 36608, 36609, 36610, 36611, 36612, 36613, 36614, 36615, - 36616, 36617, 36618, 36619, 36620, 36621, 36622, 36623, 36624, 36625, - 36626, 36627, 36628, 36629, 36630, 36631, 36632, 36633, 36634, 36635, - 36636, 36637, 36638, 36639, 36640, 36641, 36642, 36643, 21697, 21698, - 21699, 21700, 21701, 21702, 21703, 21704, 21705, 21706, 21707, 21708, - 21709, 21710, 21711, 21712, 21713, 21714, 21715, 21716, 21717, 21718, - 21719, 21720, 21721, 21722, 21723, 21724, 21725, 21726, 21727, 21728, - 21729, 21730, 21731, 21732, 21733, 21734, 21735, 21736, 21737, 21738, - 21739, 21740, 21741, 21742, 21743, 21744, 21745, 21746, 21747, 21748, - 21749, 21750, 21751, 21752, 21753, 21754, 21755, 21756, 21757, 21758, - 21759, 21760, 21761, 21762, 21763, 21764, 21765, 21766, 21767, 21768, - 21769, 21770, 21771, 21772, 21773, 21774, 21775, 21776, 21777, 21778, - 21779, 21780, 21781, 21782, 21783, 21784, 21785, 21786, 21787, 21788, - 21789, 21790, 21791, 21792, 21793, 21794, 21795, 21796, 21797, 21798, - 21799, 21800, 21801, 21802, 21803, 21804, 21805, 21806, 21807, 21808, - 21809, 21810, 21811, 21812, 21813, 21814, 21815, 21816, 21817, 21818, - 21819, 21820, 21821, 21822, 21823, 21824, 21825, 21826, 21827, 21828, - 21829, 21830, 21831, 21832, 21833, 21834, 21835, 21836, 21837, 21838, - 21839, 21840, 21841, 21842, 21843, 21844, 21845, 21846, 21847, 21848, - 21849, 21850, 21851, 21852, 21853, 21854, 21855, 21856, 21857, 21858, - 21859, 21860, 21861, 21862, 21863, 21864, 21865, 21866, 21867, 21868, - 21869, 21870, 21871, 21872, 21873, 21874, 21875, 21876, 21877, 21878, - 21879, 21880, 21881, 21882, 21883, 21884, 21885, 21886, 21887, 21888, - 21889, 21890, 21891, 21892, 21893, 21894, 21895, 21896, 21897, 21898, - 21899, 21900, 21901, 21902, 21903, 21904, 21905, 21906, 21907, 21908, - 21909, 21910, 21911, 21912, 21913, 21914, 21915, 21916, 21917, 21918, - 21919, 21920, 21921, 21922, 21923, 21924, 21925, 21926, 21927, 21928, - 21929, 21930, 21931, 21932, 21933, 21934, 21935, 21936, 21937, 21938, - 21939, 21940, 21941, 21942, 21943, 21944, 21945, 21946, 21947, 21948, - 21949, 21950, 21951, 21952, 21959, 21960, 21961, 21962, 21963, 21964, - 21965, 21966, 21967, 21968, 21969, 21970, 21971, 21972, 21973, 21974, - 21975, 21976, 21977, 21978, 21979, 21980, 21981, 21982, 21983, 21984, - 21985, 21986, 21987, 21988, 21989, 21990, 21991, 21992, 21993, 21994, - 21995, 21996, 21997, 21998, 21999, 22000, 22001, 22002, 22003, 22004, - 22005, 22006, 22007, 22008, 22009, 22010, 22011, 22012, 22013, 22014, - 22015, 22016, 22017, 22018, 22019, 22020, 22021, 22022, 22023, 22024, - 22025, 22026, 22027, 22028, 22029, 22030, 22031, 22032, 22033, 22034, - 22035, 22036, 22037, 22038, 22039, 22040, 22041, 22042, 22043, 22044, - 22045, 22046, 22047, 22048, 22049, 22050, 22051, 22052, 22053, 22054, - 22055, 22056, 22057, 22058, 22059, 22060, 22061, 22062, 22063, 22064, - 22065, 22066, 22067, 22068, 22069, 22070, 22071, 22072, 22073, 22074, - 22075, 22076, 22077, 22078, 22079, 22080, 22081, 22082, 22083, 22084, - 22085, 22086, 22087, 22088, 22089, 22090, 22091, 22092, 22093, 22094, - 22095, 22096, 22097, 22098, 22099, 22100, 22101, 22102, 22103, 22104, - 22105, 22106, 22107, 22108, 22109, 22110, 22111, 22112, 22113, 22114, - 22115, 22116, 22117, 22118, 22119, 22120, 22121, 22122, 22123, 22124, - 22125, 22126, 22127, 22128, 22129, 22130, 22131, 22132, 22133, 22134, - 22135, 22136, 22137, 22138, 22139, 22140, 22141, 22142, 22143, 22144, - 22145, 22146, 22147, 22148, 22149, 22150, 22151, 22152, 22153, 22154, - 22155, 22156, 22157, 22158, 22159, 22160, 22161, 22162, 22163, 22164, - 22165, 22166, 21953, 21954, 21955, 21956, 21957, 21958, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 22167, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 21336, 21337, 21338, 21339, 40951, 21340, 21341, 21329, 21330, 21331, - 21332, 21333, 40951, 21334, 21335, 40951, 21317, 20293, 19932, 19933, - 19934, 19931, 20213, 20214, 20215, 20216, 20205, 20206, 20207, 20208, - 20209, 20200, 20201, 20202, 20203, 20204, 20210, 20211, 20212, 19971, - 19975, 19976, 19977, 19978, 19979, 19980, 19981, 19982, 19972, 19973, - 19974, 19987, 19988, 19989, 19990, 19991, 19992, 19993, 19994, 20001, - 20002, 20003, 20004, 20005, 20006, 20007, 19995, 19996, 19997, 19998, - 19999, 20000, 19984, 19985, 19986, 19983, 20096, 20097, 20098, 20099, - 20100, 20101, 20102, 20103, 20112, 20113, 20114, 20115, 20116, 20117, - 20104, 20105, 20106, 20107, 20108, 20109, 20110, 20111, 20118, 20119, - 20120, 20121, 20122, 20123, 20124, 20125, 20126, 20127, 20128, 20129, - 20158, 20159, 20160, 20161, 20151, 20152, 20153, 20154, 20155, 20156, - 20157, 20147, 20148, 20149, 20150, 20146, 20130, 20131, 20132, 20133, - 20134, 20135, 20136, 20137, 20138, 20140, 20141, 20142, 20143, 20144, - 20145, 20139, 20050, 20051, 20052, 20053, 20054, 20055, 20056, 20057, - 20058, 20043, 20044, 20045, 20046, 20047, 20048, 20049, 20042, 20064, - 20065, 20066, 20036, 20037, 20038, 20039, 20040, 20041, 20035, 20059, - 20060, 20061, 20062, 20063, 19943, 19946, 19947, 19948, 19949, 19950, - 19951, 19952, 19953, 19944, 19945, 19964, 19965, 19966, 19967, 19968, - 19969, 19970, 19954, 19955, 19956, 19957, 19958, 19959, 19960, 19961, - 19962, 19963, 19935, 19936, 19937, 19938, 19939, 19940, 19941, 19942, - 20017, 20018, 20019, 20020, 20021, 20022, 20023, 20024, 20025, 20026, - 20027, 20028, 20029, 20030, 20031, 20032, 20033, 20034, 20009, 20010, - 20008, 20011, 20012, 20013, 20014, 20015, 20016, 20184, 20185, 20186, - 20187, 20188, 20183, 20195, 20196, 20197, 20198, 20189, 20190, 20191, - 20192, 20193, 20194, 20088, 20089, 20090, 20091, 20081, 20082, 20083, - 20084, 20085, 20086, 20087, 20075, 20076, 20077, 20078, 20079, 20080, - 20092, 20093, 20094, 20095, 20069, 20070, 20071, 20072, 20073, 20074, - 20162, 20163, 20164, 20165, 20166, 20167, 20168, 20169, 20170, 20171, - 20179, 20180, 20181, 20182, 20172, 20173, 20174, 20175, 20176, 20177, - 20178, 20067, 20068, 20292, 21315, 21314, 21316, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 20303, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 20296, 20295, 20297, 40951, 40951, 21364, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 21370, 21369, 21371, 21375, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 29455, 29456, 29457, 29458, 29459, 29460, - 29461, 29462, 29463, 29464, 29465, 29466, 29467, 29468, 29469, 29470, - 29471, 29472, 29473, 29474, 29475, 29476, 29477, 29478, 29479, 29480, - 29481, 29482, 29483, 29484, 29485, 29486, 29487, 29488, 29489, 29490, - 29491, 29492, 29493, 29494, 29495, 29496, 29497, 29498, 29499, 29500, - 29501, 29502, 29503, 29504, 29505, 29506, 29507, 29508, 29509, 29510, - 29511, 29512, 29513, 29514, 29515, 29516, 29517, 29518, 29519, 29520, - 29521, 29522, 29523, 29524, 29525, 29526, 29527, 29528, 29529, 29530, - 29531, 29532, 29533, 29534, 29535, 29536, 29537, 29538, 29539, 29540, - 29541, 29542, 29543, 29544, 29545, 29546, 29547, 29548, 29549, 29550, - 29551, 29552, 29553, 29554, 29555, 29556, 29557, 29558, 29559, 29560, - 29561, 29562, 29563, 29564, 29565, 29566, 29567, 29568, 29569, 29570, - 29571, 29572, 29573, 29574, 29575, 29576, 29577, 29578, 29579, 29580, - 29581, 29582, 29583, 29584, 29585, 29586, 29587, 29588, 29589, 29590, - 29591, 29592, 29593, 29594, 29595, 29596, 29597, 29598, 29599, 29600, - 29601, 29602, 29603, 29604, 29605, 29606, 29607, 29608, 29609, 29610, - 29611, 29612, 29613, 29614, 29615, 29616, 29617, 29618, 29619, 29620, - 29621, 29622, 29623, 29624, 29625, 29626, 29627, 29628, 29629, 29630, - 29631, 29632, 29633, 29634, 29635, 29636, 29637, 29638, 29639, 29640, - 29641, 29642, 29643, 29644, 29645, 29646, 29647, 29648, 29649, 29650, - 29651, 29652, 29653, 29654, 29655, 29656, 29657, 29658, 29659, 29660, - 29661, 29662, 29663, 29664, 29665, 29666, 29667, 29668, 29669, 29670, - 29671, 29672, 29673, 29674, 29675, 29676, 29677, 29678, 29679, 29680, - 29681, 29682, 29683, 29684, 29685, 29686, 29687, 29688, 29689, 29690, - 29691, 29692, 29693, 29694, 29695, 29696, 29697, 29698, 29699, 29700, - 29701, 29702, 29703, 29704, 29705, 29706, 29707, 29708, 29709, 29710, - 29711, 29712, 29713, 29714, 29715, 29716, 29717, 29718, 29719, 29720, - 29721, 29722, 29723, 29724, 29725, 29726, 29727, 29728, 29729, 29730, - 29731, 29732, 29733, 29734, 29735, 29736, 29737, 29738, 29739, 29740, - 29741, 29742, 29743, 29744, 29745, 29746, 29747, 29748, 29749, 29750, - 29751, 29752, 29753, 29754, 29755, 29756, 29757, 29758, 29759, 29760, - 29761, 29762, 29763, 29764, 29765, 29766, 29767, 29768, 29769, 29770, - 29771, 29772, 29773, 29774, 29775, 29776, 29777, 29778, 29779, 29780, - 29781, 29782, 29783, 29784, 29785, 29786, 29787, 29788, 29789, 29790, - 29791, 29792, 29793, 29794, 29795, 29796, 29797, 29798, 29799, 29800, - 29801, 29802, 29803, 29804, 29805, 29806, 29807, 29808, 29809, 29810, - 29811, 29812, 29813, 29814, 29815, 29816, 29817, 29818, 29819, 29820, - 29821, 29822, 29823, 29824, 29825, 29826, 29827, 29828, 29829, 29830, - 29831, 29832, 29833, 29834, 29835, 29836, 29837, 29838, 29839, 29840, - 29841, 29842, 29843, 29844, 29845, 29846, 29847, 29848, 29849, 29850, - 40951, 40951, 40951, 40951, 11516, 11514, 11463, 11496, 11423, 11436, - 11440, 11521, 11417, 11504, 11425, 11467, 11466, 11418, 11424, 11438, - 11470, 11499, 11492, 11419, 11439, 11493, 11517, 11443, 11471, 11444, - 11449, 11427, 11472, 11445, 11450, 11430, 11473, 11447, 11452, 11428, - 11429, 11481, 11482, 11448, 11453, 11434, 11485, 11446, 11451, 11431, - 11474, 11435, 11432, 11433, 11479, 11480, 11477, 11478, 11498, 11497, - 11506, 11512, 11509, 11484, 11483, 11437, 11426, 11475, 11476, 11415, - 11490, 11460, 11458, 11416, 11518, 11420, 11519, 11495, 11503, 11421, - 11487, 11468, 11486, 11441, 11520, 11500, 11422, 11515, 11501, 11442, - 11469, 11502, 11494, 11459, 11462, 11461, 11511, 11507, 11513, 11510, - 11508, 11457, 11456, 11455, 11454, 11465, 11464, 11488, 11491, 11489, - 11505, 40951, 40951, 40951, 40951, 40951, 11400, 11413, 11412, 11407, - 11414, 11394, 11387, 11386, 11383, 11385, 11388, 11389, 11384, 40951, - 40951, 40951, 11396, 11392, 11395, 11390, 11399, 11398, 11391, 11397, - 11393, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 11401, 11405, - 11408, 11403, 11411, 11410, 11404, 11409, 11406, 11402, 40951, 40951, - 11525, 11522, 11523, 11524, 32839, 32838, 32840, 32841, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 37793, 32041, 24171, 32038, 11290, 25171, 32009, 25229, 965, 20428, - 38848, 24129, 27577, 31994, 24164, 32031, 29926, 31588, 31779, 20424, - 38822, 25118, 25117, 25116, 25115, 25113, 25114, 4485, 4486, 4494, 4508, - 4378, 4377, 32579, 32587, 32580, 32591, 32584, 32588, 32581, 32593, - 32586, 32590, 32583, 32592, 32585, 32589, 32582, 37832, 37800, 37802, - 37887, 37849, 37845, 37881, 37851, 25255, 25202, 25222, 25257, 25205, - 25247, 25249, 25228, 34085, 34086, 30653, 10840, 10576, 10575, 34097, - 34098, 24177, 32018, 17483, 17484, 350, 349, 356, 355, 358, 357, 353, - 354, 351, 352, 24167, 37785, 32034, 11296, 37462, 37458, 37466, 4340, - 4338, 4344, 24160, 37780, 32028, 11292, 28300, 24170, 37788, 32037, - 11299, 16653, 16654, 3842, 3845, 3844, 3843, 3876, 24183, 37778, 32024, - 11302, 24184, 37779, 32025, 11303, 24173, 37782, 32040, 11294, 34330, - 34331, 34329, 34328, 34521, 34523, 34522, 34520, 38832, 20407, 39241, - 39242, 37705, 34162, 34161, 34160, 34115, 20802, 24043, 20803, 38837, - 20405, 24178, 32019, 24179, 32020, 17469, 24169, 37787, 32036, 11298, - 20427, 38847, 38825, 24172, 32039, 24166, 32033, 24168, 32035, 24077, - 31952, 37841, 37877, 37840, 37876, 25191, 25211, 25190, 25210, 25188, - 25208, 25189, 25209, 37844, 37880, 25201, 25221, 37842, 37878, 25200, - 25220, 37835, 37871, 25195, 25215, 37838, 37874, 25198, 25218, 37839, - 37875, 25199, 25219, 37834, 37870, 25194, 25214, 37836, 37872, 25196, - 25216, 37837, 37873, 25197, 25217, 37843, 37879, 25192, 25212, 30832, - 30833, 30834, 30835, 30836, 30837, 30838, 30839, 30840, 30841, 30842, - 30843, 30844, 30845, 30846, 30847, 30848, 30849, 30850, 30851, 30852, - 30853, 30854, 30855, 30856, 30857, 30868, 30870, 30867, 30866, 30863, - 30862, 30865, 30864, 30871, 30869, 40951, 40951, 40951, 40951, 40951, - 40951, 4137, 4081, 3952, 4167, 4038, 3979, 4138, 4019, 4082, 4128, 4054, - 4113, 3995, 4010, 4098, 3964, 4171, 4039, 4069, 3980, 4139, 4020, 4083, - 3953, 4134, 4062, 4121, 4003, 4160, 4016, 4106, 3972, 4047, 4075, 3988, - 4146, 4028, 4091, 3958, 4129, 4055, 4114, 3996, 4153, 4011, 4099, 3965, - 4172, 4040, 4070, 3981, 4140, 4021, 4084, 4066, 4125, 4007, 4164, 4035, - 4110, 3976, 4179, 4051, 4078, 3992, 4150, 4032, 4095, 3961, 4059, 4118, - 4000, 4157, 4103, 3969, 4176, 4044, 3985, 4143, 4025, 4088, 4135, 4063, - 4122, 4004, 4161, 4017, 4107, 3973, 4168, 4048, 4076, 3989, 4147, 4029, - 4092, 3959, 4130, 4056, 4115, 3997, 4154, 4012, 4100, 3966, 4173, 4041, - 4071, 3982, 4141, 4022, 4085, 3954, 4068, 4127, 4009, 4166, 4037, 4112, - 3978, 4181, 4053, 4080, 3994, 4152, 4034, 4097, 3963, 4133, 4061, 4120, - 4002, 4159, 4015, 4105, 3971, 4178, 4046, 4074, 3987, 4145, 4027, 4090, - 3957, 4065, 4124, 4006, 4163, 4109, 3975, 4170, 4050, 3991, 4149, 4031, - 4094, 4131, 4058, 4117, 3999, 4156, 4013, 4102, 3968, 4175, 4043, 4072, - 3984, 4142, 4024, 4087, 3955, 4067, 4126, 4008, 4165, 4036, 4111, 3977, - 4180, 4052, 4079, 3993, 4151, 4033, 4096, 3962, 4132, 4060, 4119, 4001, - 4158, 4014, 4104, 3970, 4177, 4045, 4073, 3986, 4144, 4026, 4089, 3956, - 4136, 4064, 4123, 4005, 4162, 4018, 4108, 3974, 4169, 4049, 4077, 3990, - 4148, 4030, 4093, 3960, 4057, 4116, 3998, 4155, 4101, 3967, 4174, 4042, - 3983, 4023, 4086, 37470, 4347, 37467, 4345, 37468, 4346, 37463, 4341, - 37464, 4342, 37457, 4334, 4335, 4336, 4337, 28184, 37459, 37460, 11293, - 24161, 33837, 37783, 11295, 17356, 17357, 17358, 31947, 25162, 17359, - 37807, 25164, 19784, 39303, 37481, 17638, 4379, 4376, 24081, 31956, - 24080, 31955, 20404, 24078, 31953, 20403, 25165, 37810, 38838, 4504, - 4502, 4503, 4501, 22718, 22717, 22722, 22716, 22694, 22673, 22674, 22714, - 22680, 22698, 22721, 22696, 22719, 22720, 22702, 22699, 22679, 22678, - 22681, 22697, 22682, 22670, 22691, 22715, 22671, 22672, 22669, 22695, - 22700, 22686, 22677, 22701, 22703, 22676, 22693, 22685, 22683, 22684, - 22675, 22723, 22692, 22687, 22690, 22688, 22689, 22711, 22709, 22710, - 22713, 22708, 22705, 22712, 22707, 22706, 22704, 32594, 32626, 32595, - 32642, 32611, 32627, 32596, 32650, 32619, 32635, 32604, 32643, 32612, - 32628, 32597, 32654, 32623, 32639, 32608, 32647, 32616, 32632, 32601, - 32651, 32620, 32636, 32605, 32644, 32613, 32629, 32598, 32656, 32625, - 32641, 32610, 32649, 32618, 32634, 32603, 32653, 32622, 32638, 32607, - 32646, 32615, 32631, 32600, 32655, 32624, 32640, 32609, 32648, 32617, - 32633, 32602, 32652, 32621, 32637, 32606, 32645, 32614, 32630, 32599, - 37827, 37799, 37801, 37866, 37848, 37846, 37847, 37850, 25254, 25252, - 25253, 25256, 25207, 25246, 25248, 25242, 31957, 31997, 24132, 24082, - 25167, 25262, 37890, 37812, 24083, 24133, 31998, 31958, 37813, 37891, - 25263, 25168, 20429, 21627, 30342, 3882, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40767, 40772, 40806, 40769, 40774, 40802, 40796, 40790, - 40813, 40792, 40786, 40810, 40768, 40773, 40807, 40770, 40775, 40803, - 40797, 40791, 40814, 40793, 40787, 40811, 40808, 40794, 40801, 40788, - 40789, 40812, 40795, 40771, 40817, 40782, 40799, 40809, 40820, 40819, - 40785, 40818, 40779, 40778, 40816, 40800, 40798, 40777, 40951, 40951, - 40822, 40823, 40824, 40815, 40765, 40780, 40783, 40784, 40762, 40763, - 40781, 40804, 40805, 40766, 40821, 40764, 40776, 40761, 40943, 40944, - 40941, 40942, 40945, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40841, 40842, 40858, 40830, 40839, 40938, 40893, 40894, - 40861, 40862, 40895, 40825, 40859, 40939, 40837, 40834, 40836, 40835, - 40833, 40935, 40934, 40937, 40936, 40931, 40930, 40933, 40932, 40831, - 40865, 40827, 40838, 40826, 40863, 40876, 40877, 40875, 40874, 40828, - 40872, 40873, 40871, 40869, 40870, 40868, 40867, 40878, 40880, 40881, - 40879, 40843, 40866, 40832, 40840, 40940, 40882, 40887, 40884, 40888, - 40885, 40890, 40891, 40886, 40883, 40889, 40864, 40892, 40925, 40922, - 40913, 40923, 40924, 40914, 40902, 40901, 40929, 40899, 40898, 40896, - 40900, 40897, 40916, 40921, 40915, 40919, 40920, 40917, 40918, 40845, - 40849, 40848, 40847, 40846, 40928, 40926, 40927, 40852, 40857, 40856, - 40855, 40854, 40853, 40903, 40912, 40905, 40910, 40904, 40908, 40909, - 40906, 40907, 40911, 40844, 40851, 40829, 40850, 40860, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 5194, 5066, 5187, - 5169, 5170, 5238, 5239, 5119, 5216, 5176, 5250, 5251, 5142, 5021, 5072, - 5219, 5120, 5024, 5025, 5214, 5226, 5165, 5102, 5193, 5045, 5242, 5114, - 5128, 5124, 5217, 5179, 5208, 5172, 5241, 5027, 5029, 5129, 5195, 5180, - 5237, 5019, 5197, 5211, 5213, 5167, 5221, 5149, 5067, 5229, 5220, 5139, - 5020, 5079, 5110, 5231, 5117, 5185, 5189, 5132, 5043, 5196, 5174, 5177, - 5116, 5254, 5184, 5133, 5232, 5209, 5108, 5115, 5166, 5171, 5183, 5135, - 5182, 5140, 5186, 5123, 5127, 5253, 5026, 5022, 5252, 5141, 5075, 5046, - 5164, 5240, 5181, 5190, 5173, 5018, 5150, 5178, 5175, 5071, 5143, 5017, - 5233, 5074, 5212, 5215, 5044, 5073, 5198, 5255, 5235, 5191, 5230, 5234, - 5188, 5236, 5192, 5105, 5031, 5070, 5168, 5223, 5224, 5222, 5225, 5118, - 5068, 5243, 5244, 5207, 5131, 5064, 5136, 5137, 5138, 5028, 5030, 5063, - 5228, 5218, 5134, 5144, 5148, 5147, 5146, 5145, 5104, 5101, 5100, 5058, - 5060, 5061, 5059, 5227, 5032, 5112, 5051, 5015, 5009, 5010, 5013, 5014, - 5012, 5011, 5016, 5157, 5152, 5153, 5151, 5162, 5161, 5160, 5159, 5163, - 5155, 5113, 5023, 5078, 5077, 5076, 5158, 5156, 5154, 5106, 5107, 5069, - 5111, 5109, 5080, 5087, 5083, 5091, 5086, 5095, 5085, 5084, 5081, 5082, - 5089, 5090, 5097, 5094, 5092, 5041, 5042, 5040, 5088, 5096, 5249, 5054, - 5052, 5055, 5057, 5056, 5053, 5245, 5247, 5246, 5248, 5098, 5099, 5048, - 5047, 5049, 5050, 5203, 5206, 5204, 5205, 5199, 5202, 5200, 5201, 5062, - 5065, 5210, 5039, 5033, 5038, 5036, 5035, 5034, 5037, 5121, 5125, 5122, - 5126, 5130, 5103, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 28489, 28366, 28382, 28474, 28361, 28486, 28424, 28475, - 28473, 28362, 28358, 28485, 28352, 28470, 28471, 28472, 28377, 28378, - 28315, 28316, 28311, 28310, 28441, 28512, 28509, 28384, 28383, 28490, - 28491, 28385, 28394, 28395, 28396, 28355, 28387, 28388, 28389, 28368, - 28369, 40951, 40951, 28432, 28365, 28367, 28393, 28392, 28437, 28436, - 28488, 28487, 28464, 28465, 28351, 28357, 28453, 28454, 28468, 28469, - 28433, 28535, 28407, 28467, 28376, 28493, 28511, 28495, 28440, 28533, - 28456, 28356, 28496, 28497, 28520, 28521, 28524, 28525, 28522, 28523, - 28516, 28517, 28518, 28519, 28430, 28431, 28526, 28527, 28455, 28531, - 28438, 28435, 28319, 28320, 28314, 28534, 28406, 28466, 28375, 28492, - 28510, 28494, 28439, 28340, 28341, 28344, 28345, 28346, 28379, 28380, - 28381, 28323, 28330, 28331, 28332, 28333, 28334, 28308, 28373, 28309, - 28374, 28307, 28371, 28306, 28370, 28321, 28339, 28347, 28338, 28324, - 28325, 28322, 28349, 28404, 28403, 28328, 28350, 28335, 28342, 28348, - 28327, 28343, 28476, 28499, 28538, 28463, 28426, 28386, 28354, 28363, - 28400, 28399, 28515, 28528, 28537, 28529, 28530, 28442, 28445, 28446, - 28447, 28448, 28449, 28450, 28451, 28452, 28443, 28444, 28408, 28434, - 28372, 28364, 28326, 28329, 28336, 28337, 28458, 28457, 28405, 28398, - 28397, 28536, 28359, 28360, 28425, 28421, 28312, 28479, 28481, 28427, - 28429, 28482, 28484, 28390, 28391, 28423, 28422, 28313, 28480, 28428, - 28483, 28507, 28506, 28508, 28505, 28501, 28502, 28503, 28504, 28353, - 28401, 28402, 28498, 28532, 28460, 28318, 28477, 28317, 28513, 28461, - 28462, 28478, 28514, 28459, 28409, 28412, 28416, 28419, 28418, 28417, - 28413, 28414, 28410, 28411, 28415, 28500, 28420, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 18636, 18624, - 18647, 18648, 18630, 18649, 18650, 18651, 18652, 18637, 18638, 18639, - 18640, 18641, 18642, 18643, 18644, 18645, 18646, 18625, 18626, 18627, - 18628, 18629, 18631, 18632, 18633, 18634, 18635, 18356, 18364, 18377, - 18385, 18391, 18392, 18357, 18358, 18359, 18360, 18361, 18362, 18363, - 18365, 18366, 18367, 18368, 18369, 18370, 18371, 18372, 18373, 18374, - 18375, 18376, 18378, 18379, 18380, 18381, 18382, 18383, 18384, 18386, - 18387, 18388, 18389, 18390, 8271, 8270, 8272, 18416, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 21607, - 21608, 21605, 21603, 21594, 21593, 21600, 21598, 21589, 21596, 21606, - 21591, 21604, 21602, 21595, 21592, 21601, 21599, 21590, 21597, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 26844, 26845, 26842, 26840, 26831, 26830, 26837, 26835, 26826, - 26833, 26843, 26828, 26841, 26839, 26832, 26829, 26838, 26836, 26827, - 26834, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 28177, 10885, 10886, 10880, 10879, 10878, 36785, - 36805, 36826, 36774, 36819, 36783, 36769, 36828, 36773, 36787, 36793, - 36816, 36817, 36831, 36837, 36784, 36815, 36845, 36803, 36770, 36833, - 36835, 36802, 36848, 36782, 36797, 36794, 36775, 36789, 36772, 36830, - 36823, 36777, 36820, 36809, 36843, 36832, 36806, 36834, 36822, 36836, - 36811, 36799, 36842, 36812, 36798, 36829, 36838, 36808, 36844, 36781, - 36825, 36801, 36847, 36791, 36776, 36813, 36810, 36824, 36768, 36796, - 36795, 36846, 36840, 36818, 36788, 36786, 36792, 36800, 36839, 36841, - 36814, 36780, 36778, 36807, 36771, 36779, 36827, 36790, 36821, 36804, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 8669, - 8667, 8666, 8663, 8662, 8665, 8664, 8670, 8668, 8660, 8658, 8657, 8654, - 8653, 8656, 8655, 8661, 8659, 20515, 20514, 20513, 20512, 20511, 35370, - 35369, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 25824, 25826, 25854, 25817, - 25830, 25862, 25833, 25863, 25835, 25864, 25837, 25839, 25856, 25858, - 25841, 25844, 25865, 25848, 25850, 25820, 25852, 25866, 25867, 25860, - 25868, 25828, 25872, 25874, 25907, 25869, 25878, 25881, 25883, 25915, - 25885, 25916, 25887, 25889, 25909, 25911, 25891, 25894, 25917, 25898, - 25900, 25902, 25905, 25918, 25919, 25913, 25920, 25876, 26312, 26314, - 26344, 26318, 26320, 26352, 26323, 26353, 26325, 26354, 26327, 26329, - 26346, 26348, 26331, 26334, 26355, 26338, 26340, 26308, 26342, 26356, - 26357, 26350, 26358, 26316, 26260, 26262, 26295, 26256, 26266, 26269, - 26271, 40951, 26273, 26303, 26275, 26277, 26297, 26299, 26279, 26282, - 26304, 26286, 26288, 26290, 26293, 26305, 26306, 26301, 26307, 26264, - 25977, 25979, 26009, 25983, 25985, 26017, 25988, 26018, 25990, 26019, - 25992, 25994, 26011, 26013, 25996, 25999, 26020, 26003, 26005, 25973, - 26007, 26021, 26022, 26015, 26023, 25981, 26031, 26033, 26068, 26037, - 26039, 26042, 26044, 26076, 26046, 26077, 26048, 26050, 26070, 26072, - 26052, 26055, 26078, 26059, 26061, 26063, 26066, 26079, 26080, 26074, - 26081, 26035, 26784, 40951, 26785, 26786, 40951, 40951, 26787, 40951, - 40951, 26788, 26789, 40951, 40951, 26790, 26791, 26792, 26793, 40951, - 26794, 26795, 26796, 26797, 26798, 26799, 26800, 26801, 26802, 26803, - 26804, 26805, 40951, 26806, 40951, 26807, 26808, 26809, 26810, 26811, - 26812, 26813, 40951, 26814, 26815, 26816, 26817, 26818, 26819, 26820, - 26821, 26822, 26823, 26824, 25921, 25922, 25923, 25924, 25925, 25926, - 25927, 25928, 25929, 25930, 25931, 25932, 25933, 25934, 25935, 25936, - 25937, 25938, 25939, 25940, 25941, 25942, 25943, 25944, 25945, 25946, - 25947, 25948, 25949, 25950, 25951, 25952, 25953, 25954, 25955, 25956, - 25957, 25958, 25959, 25960, 25961, 25962, 25963, 25964, 25965, 25966, - 25967, 25968, 25969, 25970, 25971, 25972, 26208, 26209, 40951, 26210, - 26211, 26212, 26213, 40951, 40951, 26214, 26215, 26216, 26217, 26218, - 26219, 26220, 26221, 40951, 26222, 26223, 26224, 26225, 26226, 26227, - 26228, 40951, 26229, 26230, 26231, 26232, 26233, 26234, 26235, 26236, - 26237, 26238, 26239, 26240, 26241, 26242, 26243, 26244, 26245, 26246, - 26247, 26248, 26249, 26250, 26251, 26252, 26253, 26254, 26153, 26154, - 40951, 26155, 26156, 26157, 26158, 40951, 26159, 26160, 26161, 26162, - 26163, 40951, 26164, 40951, 40951, 40951, 26165, 26166, 26167, 26168, - 26169, 26170, 26171, 40951, 26172, 26173, 26174, 26175, 26176, 26177, - 26178, 26179, 26180, 26181, 26182, 26183, 26184, 26185, 26186, 26187, - 26188, 26189, 26190, 26191, 26192, 26193, 26194, 26195, 26196, 26197, - 26091, 26092, 26093, 26094, 26095, 26096, 26097, 26098, 26099, 26100, - 26101, 26102, 26103, 26104, 26105, 26106, 26107, 26108, 26109, 26110, - 26111, 26112, 26113, 26114, 26115, 26116, 26117, 26118, 26119, 26120, - 26121, 26122, 26123, 26124, 26125, 26126, 26127, 26128, 26129, 26130, - 26131, 26132, 26133, 26134, 26135, 26136, 26137, 26138, 26139, 26140, - 26141, 26142, 26722, 26723, 26724, 26725, 26726, 26727, 26728, 26729, - 26730, 26731, 26732, 26733, 26734, 26735, 26736, 26737, 26738, 26739, - 26740, 26741, 26742, 26743, 26744, 26745, 26746, 26747, 26748, 26749, - 26750, 26751, 26752, 26753, 26754, 26755, 26756, 26757, 26758, 26759, - 26760, 26761, 26762, 26763, 26764, 26765, 26766, 26767, 26768, 26769, - 26770, 26771, 26772, 26773, 26554, 26556, 26586, 26560, 26562, 26594, - 26565, 26595, 26567, 26596, 26569, 26571, 26588, 26590, 26573, 26576, - 26597, 26580, 26582, 26550, 26584, 26598, 26599, 26592, 26600, 26558, - 26608, 26610, 26645, 26614, 26616, 26619, 26621, 26653, 26623, 26654, - 26625, 26627, 26647, 26649, 26629, 26632, 26655, 26636, 26638, 26640, - 26643, 26656, 26657, 26651, 26658, 26612, 26670, 26671, 26672, 26673, - 26674, 26675, 26676, 26677, 26678, 26679, 26680, 26681, 26682, 26683, - 26684, 26685, 26686, 26687, 26688, 26689, 26690, 26691, 26692, 26693, - 26694, 26695, 26696, 26697, 26698, 26699, 26700, 26701, 26702, 26703, - 26704, 26705, 26706, 26707, 26708, 26709, 26710, 26711, 26712, 26713, - 26714, 26715, 26716, 26717, 26718, 26719, 26720, 26721, 26444, 26446, - 26476, 26450, 26452, 26484, 26455, 26485, 26457, 26486, 26459, 26461, - 26478, 26480, 26463, 26466, 26487, 26470, 26472, 26440, 26474, 26488, - 26489, 26482, 26490, 26448, 26498, 26500, 26535, 26504, 26506, 26509, - 26511, 26543, 26513, 26544, 26515, 26517, 26537, 26539, 26519, 26522, - 26545, 26526, 26528, 26530, 26533, 26546, 26547, 26541, 26548, 26502, - 26367, 26368, 26369, 26370, 26371, 26372, 26373, 26374, 26375, 26376, - 26377, 26378, 26379, 26380, 26381, 26382, 26383, 26384, 26385, 26386, - 26387, 26388, 26389, 26390, 26391, 26392, 26393, 26394, 26395, 26396, - 26397, 26398, 26399, 26400, 26401, 26402, 26403, 26404, 26405, 26406, - 26407, 26408, 26409, 26410, 26411, 26412, 26413, 26414, 26415, 26416, - 26417, 26418, 26257, 26258, 40951, 40951, 25825, 25827, 25834, 25819, - 25831, 25829, 25832, 25821, 25836, 25838, 25840, 25857, 25859, 25861, - 25842, 25847, 25849, 25822, 25851, 25823, 25853, 25845, 25855, 25846, - 25843, 26085, 25873, 25875, 25884, 25871, 25879, 25877, 25880, 25903, - 25886, 25888, 25890, 25910, 25912, 25914, 25892, 25897, 25899, 25882, - 25901, 25904, 25906, 25895, 25908, 25896, 25893, 26087, 26083, 26090, - 26084, 26086, 26089, 26088, 26313, 26315, 26324, 26319, 26321, 26317, - 26322, 26309, 26326, 26328, 26330, 26347, 26349, 26351, 26332, 26337, - 26339, 26310, 26341, 26311, 26343, 26335, 26345, 26336, 26333, 26361, - 26261, 26263, 26272, 26259, 26267, 26265, 26268, 26291, 26274, 26276, - 26278, 26298, 26300, 26302, 26280, 26285, 26287, 26270, 26289, 26292, - 26294, 26283, 26296, 26284, 26281, 26363, 26359, 26366, 26360, 26362, - 26365, 26364, 25978, 25980, 25989, 25984, 25986, 25982, 25987, 25974, - 25991, 25993, 25995, 26012, 26014, 26016, 25997, 26002, 26004, 25975, - 26006, 25976, 26008, 26000, 26010, 26001, 25998, 26026, 26032, 26034, - 26045, 26038, 26040, 26036, 26041, 26064, 26047, 26049, 26051, 26071, - 26073, 26075, 26053, 26058, 26060, 26043, 26062, 26065, 26067, 26056, - 26069, 26057, 26054, 26028, 26024, 26082, 26025, 26027, 26030, 26029, - 26555, 26557, 26566, 26561, 26563, 26559, 26564, 26551, 26568, 26570, - 26572, 26589, 26591, 26593, 26574, 26579, 26581, 26552, 26583, 26553, - 26585, 26577, 26587, 26578, 26575, 26603, 26609, 26611, 26622, 26615, - 26617, 26613, 26618, 26641, 26624, 26626, 26628, 26648, 26650, 26652, - 26630, 26635, 26637, 26620, 26639, 26642, 26644, 26633, 26646, 26634, - 26631, 26605, 26601, 26659, 26602, 26604, 26607, 26606, 26445, 26447, - 26456, 26451, 26453, 26449, 26454, 26441, 26458, 26460, 26462, 26479, - 26481, 26483, 26464, 26469, 26471, 26442, 26473, 26443, 26475, 26467, - 26477, 26468, 26465, 26493, 26499, 26501, 26512, 26505, 26507, 26503, - 26508, 26531, 26514, 26516, 26518, 26538, 26540, 26542, 26520, 26525, - 26527, 26510, 26529, 26532, 26534, 26523, 26536, 26524, 26521, 26495, - 26491, 26549, 26492, 26494, 26497, 26496, 25818, 25870, 40951, 40951, - 26149, 26151, 26148, 26147, 26144, 26143, 26146, 26145, 26152, 26150, - 26204, 26206, 26203, 26202, 26199, 26198, 26201, 26200, 26207, 26205, - 26780, 26782, 26779, 26778, 26775, 26774, 26777, 26776, 26783, 26781, - 26666, 26668, 26665, 26664, 26661, 26660, 26663, 26662, 26669, 26667, - 26425, 26427, 26424, 26423, 26420, 26419, 26422, 26421, 26428, 26426, - 33092, 33048, 33073, 33289, 33244, 33030, 33093, 33057, 33206, 33158, - 33134, 33095, 33098, 33055, 33099, 33049, 33100, 33122, 33117, 33155, - 33096, 33102, 33111, 33112, 33103, 33109, 33113, 33051, 33185, 33094, - 33123, 33052, 33132, 33101, 33131, 33118, 33157, 33156, 33097, 33116, - 33126, 33127, 33130, 33129, 33197, 33105, 33106, 33107, 33179, 33147, - 33110, 33114, 33108, 33104, 33178, 33139, 33177, 33176, 33136, 33135, - 33138, 33128, 33125, 33124, 33174, 33173, 33175, 33146, 33222, 33226, - 33225, 33223, 33224, 33067, 33213, 33243, 33215, 33228, 33220, 33229, - 33221, 33230, 33219, 33077, 33078, 33242, 33283, 33216, 33217, 33218, - 33214, 33240, 33227, 33238, 33231, 33239, 33237, 33235, 33232, 33233, - 33234, 33236, 33064, 33070, 33068, 33069, 33273, 33272, 33080, 33072, - 33083, 33086, 33081, 33084, 33082, 33085, 33090, 33087, 33047, 33282, - 33288, 33285, 33287, 33261, 33263, 33241, 33271, 33264, 33268, 33262, - 33270, 33269, 33267, 33029, 33119, 33054, 33246, 33032, 33255, 33121, - 33120, 33247, 33160, 33163, 33162, 33161, 33170, 33210, 33059, 33284, - 33041, 33166, 33169, 33164, 33165, 33258, 33168, 33257, 33040, 33039, - 33167, 33058, 33256, 33038, 33133, 33053, 33248, 33265, 33031, 33115, - 33050, 33186, 33266, 33042, 33194, 33190, 33192, 33063, 33286, 33043, - 33187, 33189, 33188, 33193, 33191, 33281, 33159, 33056, 33088, 33275, - 33276, 33274, 33076, 33254, 33034, 33033, 33183, 33259, 33181, 33062, - 33171, 33182, 33280, 33180, 33184, 33172, 33060, 33089, 33079, 33260, - 33045, 33046, 33044, 33061, 33065, 33066, 33278, 33279, 33277, 33245, - 33148, 33250, 33151, 33152, 33153, 33150, 33154, 33149, 33143, 33144, - 33145, 33142, 33140, 33071, 33141, 33137, 33074, 33075, 33252, 33253, - 33249, 33251, 33036, 33037, 33035, 33195, 33200, 33203, 33204, 33205, - 33211, 33196, 33198, 33199, 33207, 33202, 33208, 33209, 33201, 33091, - 33212, 33603, 33602, 33601, 33623, 33622, 33621, 33578, 33577, 33576, - 32962, 32961, 32960, 33564, 33563, 33562, 33574, 33575, 33570, 33573, - 33569, 33572, 33571, 33019, 33022, 33018, 33021, 33020, 33568, 33438, - 33439, 33440, 33441, 33436, 33437, 33442, 33482, 33387, 33500, 33499, - 33497, 33498, 33501, 33476, 33479, 33477, 33478, 33475, 33506, 33505, - 33503, 33504, 33452, 33451, 33450, 33456, 33455, 33454, 33453, 33474, - 33473, 33472, 33449, 33448, 33447, 33522, 33521, 33520, 33496, 33495, - 33494, 33619, 33618, 33617, 33616, 33615, 33614, 33620, 33613, 33612, - 33611, 33356, 33355, 33353, 33354, 33360, 33359, 33357, 33358, 33348, - 33347, 33345, 33346, 33352, 33351, 33349, 33350, 33410, 33409, 33407, - 33408, 33411, 33425, 33428, 33426, 33427, 33384, 33415, 33414, 33413, - 33412, 33370, 33383, 33382, 33381, 33371, 33369, 33368, 33367, 33434, - 33433, 33432, 33431, 33430, 33429, 33606, 33605, 33604, 33609, 33608, - 33607, 33610, 33469, 33468, 33466, 33467, 33460, 33459, 33457, 33458, - 33465, 33464, 33487, 33486, 33483, 33488, 33493, 33490, 33489, 33509, - 33508, 33507, 33512, 33511, 33510, 33463, 33471, 33470, 33559, 33556, - 33555, 33502, 33462, 33485, 33492, 33517, 33561, 33558, 33554, 33461, - 33484, 33491, 33516, 33560, 33557, 33553, 33515, 33514, 33513, 33374, - 33373, 33391, 33389, 33390, 33388, 33400, 33398, 33399, 33397, 33417, - 33416, 33548, 33545, 33551, 33376, 33375, 33392, 33393, 33395, 33394, - 33404, 33402, 33403, 33401, 33419, 33418, 33549, 33546, 33552, 33380, - 33379, 33377, 33378, 33372, 33396, 33405, 33420, 33421, 33422, 33547, - 33544, 33550, 33406, 33446, 33444, 33445, 33443, 33366, 33364, 33362, - 33365, 33363, 33361, 33519, 33518, 33424, 33423, 33481, 33480, 33386, - 33385, 32978, 32977, 32973, 32976, 32980, 32979, 32974, 32975, 32972, - 32981, 33291, 33298, 33296, 33295, 33293, 33294, 33292, 33297, 33011, - 33009, 33010, 32987, 32986, 32985, 32970, 32968, 32969, 32971, 33026, - 33025, 33024, 33005, 33006, 33002, 32983, 32982, 33001, 33003, 33000, - 33004, 32984, 32999, 32997, 32998, 32994, 32996, 32995, 32988, 32990, - 32989, 32992, 32991, 32993, 32965, 32964, 32963, 33588, 33587, 33589, - 33008, 33525, 33524, 33526, 33527, 32955, 32957, 32954, 32956, 32959, - 32958, 33320, 33318, 33319, 33325, 33327, 33326, 33322, 33324, 33323, - 33339, 33338, 33337, 33331, 33332, 33333, 33334, 33335, 33336, 33328, - 33330, 33329, 33340, 33341, 33342, 33309, 33307, 33308, 33321, 33344, - 33343, 33596, 33595, 33593, 33594, 33592, 33597, 33591, 33590, 33580, - 33585, 33583, 33584, 33581, 33582, 33586, 33523, 33435, 33528, 33290, - 33007, 33566, 33565, 33028, 33023, 33567, 33599, 33598, 33600, 33624, - 33299, 33300, 33301, 33302, 33303, 33304, 33305, 33306, 33017, 33317, - 33316, 33311, 33314, 33313, 33310, 33312, 33315, 32967, 33027, 33579, - 32966, 33625, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 33012, 33013, 33014, - 33015, 33016, 40951, 33536, 33537, 33538, 33539, 33540, 33541, 33542, - 33543, 33529, 33530, 33531, 33532, 33533, 33534, 33535, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 23497, 23771, - 23262, 23776, 23249, 23621, 23882, 23773, 23868, 23837, 23242, 23476, - 23477, 23872, 23237, 23289, 23263, 23614, 23413, 23594, 23474, 23866, - 23752, 23841, 23485, 23414, 23558, 23711, 23842, 23380, 23788, 40951, - 40951, 40951, 40951, 40951, 40951, 23404, 23607, 23653, 23757, 23796, - 23832, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 8227, 8229, 8239, 8233, 8215, 8240, 8247, - 40951, 8246, 8220, 8217, 8216, 8214, 8251, 8235, 8234, 8236, 8250, 8237, - 8238, 8222, 8225, 8249, 8231, 8248, 40951, 40951, 8223, 8226, 8230, 8224, - 8242, 8241, 8243, 40951, 8245, 8221, 40951, 8244, 8219, 8228, 8218, 8232, - 40951, 40951, 40951, 40951, 40951, 27764, 27733, 27761, 27759, 27735, - 27757, 27754, 27755, 27756, 27763, 27740, 27741, 27765, 27744, 27742, - 27737, 27750, 27766, 27739, 27762, 27749, 27758, 27748, 27751, 27736, - 27753, 27734, 27747, 27731, 27760, 27732, 27745, 27743, 10520, 10498, - 10518, 10505, 10501, 10515, 10512, 10513, 10514, 10519, 10503, 10521, - 10517, 10504, 10522, 10502, 10507, 10511, 10516, 10510, 10508, 10509, - 10506, 10497, 10500, 10499, 27738, 27752, 27746, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 8144, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 29882, 29866, 29857, 29868, 29873, 29865, 29870, - 29861, 29887, 29891, 29893, 29896, 29860, 29855, 29890, 29880, 29864, - 29863, 29894, 29856, 29867, 29888, 29876, 29892, 29895, 29862, 29884, - 29869, 29859, 29879, 29858, 29874, 29881, 29883, 29889, 29875, 29871, - 29872, 29897, 29898, 29877, 29878, 29885, 29886, 29899, 40951, 40951, - 40951, 29908, 29912, 29911, 29914, 29913, 29910, 29909, 29905, 29902, - 29901, 29904, 29903, 29906, 29907, 40951, 40951, 29922, 29924, 29921, - 29920, 29917, 29916, 29919, 29918, 29925, 29923, 40951, 40951, 40951, - 40951, 29900, 29915, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 37522, 37505, 37525, 37515, 37519, 37516, 37521, - 37507, 37506, 37524, 37512, 37527, 37526, 37518, 37517, 37523, 37520, - 37508, 37500, 37509, 37501, 37529, 37510, 37502, 37511, 37503, 37528, - 37514, 37504, 37513, 37530, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 38979, 38978, 39010, 39011, 39012, 39014, 39003, 39006, 38992, - 38995, 39007, 38999, 38996, 39013, 39009, 39008, 39016, 39021, 39020, - 39019, 39005, 38984, 38983, 39018, 39017, 39004, 39015, 38987, 38989, - 38993, 39000, 38991, 38998, 38997, 38986, 38981, 38982, 38990, 38985, - 38988, 38980, 38994, 39001, 39002, 39025, 39026, 39023, 39024, 39033, - 39035, 39032, 39031, 39028, 39027, 39030, 39029, 39036, 39034, 40951, - 40951, 40951, 40951, 40951, 39022, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 28864, 28867, 28866, 28868, 28865, 28847, 28851, - 28849, 28848, 28850, 28859, 28862, 28860, 28863, 28861, 28869, 28870, - 28871, 28872, 28873, 28852, 28854, 28857, 28858, 28853, 28856, 28855, - 28877, 28874, 28878, 28876, 28875, 28885, 28887, 28884, 28883, 28880, - 28879, 28882, 28881, 28888, 28886, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 30046, - 30049, 30048, 30047, 30050, 30051, 30028, 30030, 30029, 30031, 30032, - 30033, 30040, 30041, 30045, 30042, 30043, 30044, 30052, 30056, 30053, - 30055, 30054, 30057, 30034, 30039, 30038, 30036, 30035, 30037, 30060, - 30058, 30059, 30068, 30070, 30067, 30066, 30063, 30062, 30065, 30064, - 30071, 30069, 40951, 40951, 40951, 40951, 30061, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 17006, 17012, 17010, 17007, 17009, 17008, 17011, 40951, 16961, - 17005, 17003, 17002, 40951, 16949, 16948, 40951, 16960, 16959, 16958, - 16945, 16944, 16957, 16956, 16955, 16954, 16953, 16952, 16947, 16946, - 16951, 16950, 40951, 27076, 27077, 27078, 27144, 27165, 27153, 27118, - 27253, 27079, 27080, 27084, 27203, 27188, 27193, 27117, 27271, 27220, - 27142, 27123, 27214, 27083, 27081, 27082, 27129, 27173, 27226, 27266, - 27089, 27085, 27093, 27230, 27168, 27178, 27205, 27094, 27091, 27090, - 27243, 27181, 27241, 27219, 27210, 27208, 27209, 27272, 27251, 27088, - 27103, 27095, 27242, 27187, 27212, 27147, 27273, 27099, 27100, 27101, - 27157, 27149, 27133, 27234, 27185, 27086, 27092, 27087, 27160, 27257, - 27258, 27096, 27097, 27098, 27171, 27126, 27176, 27143, 27104, 27102, - 27105, 27229, 27186, 27235, 27137, 27249, 27106, 27110, 27114, 27183, - 27155, 27223, 27204, 27107, 27111, 27112, 27154, 27146, 27211, 27164, - 27274, 27175, 27113, 27108, 27109, 27191, 27244, 27252, 27122, 27264, - 27115, 27174, 27124, 27221, 27161, 27199, 27131, 27213, 27163, 27130, - 27270, 27120, 27166, 27116, 27162, 27190, 27217, 27228, 27198, 27233, - 27200, 27159, 27179, 27260, 27227, 27194, 27237, 27267, 27240, 27238, - 27263, 27134, 27250, 27140, 27169, 27125, 27156, 27132, 27180, 27136, - 27216, 27135, 27195, 27121, 27261, 27151, 27246, 27247, 27265, 27236, - 27177, 27215, 27207, 27170, 27145, 27119, 27184, 27192, 27231, 27197, - 27127, 27222, 27167, 27182, 27148, 27150, 27256, 27196, 27202, 27201, - 27268, 27189, 27138, 27139, 27225, 27269, 27218, 27206, 27259, 27262, - 27232, 27254, 27158, 27224, 27152, 27239, 27128, 27255, 27172, 27141, - 40951, 40951, 27282, 27280, 27279, 27276, 27275, 27278, 27277, 27283, - 27281, 27071, 27070, 27074, 27072, 27069, 27073, 27075, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 27, 9, 24, - 14, 29, 21, 34, 28, 37, 39, 35, 40, 41, 10, 30, 32, 18, 15, 31, 42, 13, - 25, 36, 23, 12, 20, 33, 19, 38, 17, 11, 26, 16, 22, 62, 44, 59, 49, 64, - 56, 69, 63, 72, 74, 70, 75, 76, 45, 65, 67, 53, 50, 66, 77, 48, 60, 71, - 58, 47, 55, 68, 54, 73, 52, 46, 61, 51, 57, 85, 86, 79, 84, 43, 78, 83, - 82, 40951, 40951, 40951, 40951, 93, 95, 92, 91, 88, 87, 90, 89, 96, 94, - 40951, 40951, 40951, 40951, 80, 81, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 20698, 20684, - 20679, 20659, 20654, 20672, 20667, 20647, 20662, 20687, 20682, 20677, - 20657, 20652, 20673, 20668, 20648, 20663, 20699, 20685, 20680, 20660, - 20655, 20675, 20670, 20650, 20665, 20700, 20686, 20681, 20661, 20656, - 20676, 20671, 20651, 20666, 20688, 20683, 20678, 20658, 20653, 20674, - 20669, 20649, 20664, 20645, 20646, 20636, 20643, 20644, 20696, 20694, - 20693, 20690, 20689, 20692, 20691, 20697, 20695, 20702, 20638, 20637, - 20639, 20701, 20642, 20641, 20640, 20635, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 30827, 30822, 30817, 30797, 30792, 30810, 30805, 30785, - 30800, 30825, 30820, 30815, 30795, 30790, 30811, 30806, 30786, 30801, - 30828, 30823, 30818, 30798, 30793, 30813, 30808, 30788, 30803, 30829, - 30824, 30819, 30799, 30794, 30814, 30809, 30789, 30804, 30826, 30821, - 30816, 30796, 30791, 30812, 30807, 30787, 30802, 30784, 30777, 30779, - 30769, 30771, 30772, 30774, 30781, 30780, 30775, 30770, 30773, 30778, - 30776, 30783, 30782, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 2246, 2254, 2252, 2150, - 40951, 2262, 2250, 2258, 2242, 2257, 2249, 2198, 2253, 2260, 2225, 2247, - 2255, 2226, 2261, 2256, 2224, 2245, 2244, 2248, 2243, 2149, 2251, 2259, - 2120, 2122, 2121, 2123, 40951, 2162, 2160, 40951, 2157, 40951, 40951, - 2156, 40951, 2164, 2159, 2167, 2161, 2166, 2154, 2169, 2163, 2155, 2168, - 40951, 2153, 2152, 2151, 2158, 40951, 2170, 40951, 2165, 40951, 40951, - 40951, 40951, 40951, 40951, 2234, 40951, 40951, 40951, 40951, 2236, - 40951, 2235, 40951, 2239, 40951, 2238, 2231, 2241, 40951, 2232, 2240, - 40951, 2230, 40951, 40951, 2233, 40951, 2229, 40951, 2237, 40951, 2227, - 40951, 2228, 40951, 2216, 2214, 40951, 2211, 40951, 40951, 2210, 2205, - 2218, 2213, 40951, 2215, 2221, 2208, 2223, 2217, 2209, 2222, 40951, 2207, - 2206, 2204, 2212, 40951, 2203, 2219, 2220, 2201, 40951, 2202, 40951, - 2175, 2187, 2185, 2195, 2178, 2197, 2183, 2177, 2181, 2190, 40951, 2193, - 2186, 2192, 2172, 2176, 2188, 2173, 2196, 2189, 2171, 2182, 2180, 2174, - 2179, 2194, 2184, 2191, 40951, 40951, 40951, 40951, 40951, 2136, 2134, - 2145, 40951, 2148, 2132, 2140, 2130, 2139, 40951, 2143, 2135, 2142, 2125, - 2147, 2137, 2126, 2146, 2138, 2124, 2131, 2129, 2127, 2128, 2144, 2133, - 2141, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 2199, 2200, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 25385, - 25401, 25416, 25392, 25420, 25419, 25417, 25397, 25414, 25411, 25390, - 25387, 25406, 25403, 25383, 25394, 25398, 25415, 25412, 25391, 25388, - 25407, 25404, 25384, 25395, 25396, 25413, 25410, 25389, 25386, 25405, - 25402, 25382, 25393, 25400, 25399, 25380, 25423, 25409, 25408, 25421, - 25418, 25422, 25381, 40951, 40951, 40951, 40951, 11138, 11089, 11090, - 11091, 11092, 11093, 11094, 11095, 11096, 11097, 11098, 11099, 11100, - 11101, 11102, 11103, 11104, 11105, 11106, 11107, 11108, 11109, 11110, - 11111, 11112, 11113, 11114, 11115, 11116, 11117, 11118, 11119, 11120, - 11121, 11122, 11123, 11124, 11125, 11126, 11127, 11128, 11129, 11130, - 11131, 11132, 11133, 11134, 11135, 11136, 11137, 11188, 11139, 11140, - 11141, 11142, 11143, 11144, 11145, 11146, 11147, 11148, 11149, 11150, - 11151, 11152, 11153, 11154, 11155, 11156, 11157, 11158, 11159, 11160, - 11161, 11162, 11163, 11164, 11165, 11166, 11167, 11168, 11169, 11170, - 11171, 11172, 11173, 11174, 11175, 11176, 11177, 11178, 11179, 11180, - 11181, 11182, 11183, 11184, 11185, 11186, 11187, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 31485, - 31555, 31530, 31526, 31489, 31494, 31514, 31510, 31506, 31559, 31522, - 31563, 31498, 31518, 31502, 40951, 40951, 31556, 31531, 31527, 31490, - 31495, 31515, 31511, 31507, 31560, 31523, 31564, 31499, 31519, 31503, - 31486, 40951, 31557, 31532, 31528, 31491, 31496, 31516, 31512, 31508, - 31561, 31524, 31565, 31500, 31520, 31504, 31484, 40951, 31554, 31529, - 31525, 31488, 31493, 31513, 31509, 31505, 31558, 31521, 31562, 31497, - 31517, 31501, 31487, 31492, 31536, 31533, 31547, 31548, 31549, 31550, - 31551, 31552, 31553, 31537, 31538, 31539, 31540, 31541, 31542, 31543, - 31544, 31545, 31546, 31534, 31535, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 10874, 10873, 10858, 10870, 10867, - 10852, 10849, 10864, 10861, 10876, 10855, 10915, 10894, 6813, 6530, 6554, - 31156, 31157, 31158, 31159, 31160, 31161, 31162, 31163, 31164, 31165, - 31166, 31167, 31168, 31169, 31170, 31171, 31172, 31173, 31174, 31175, - 31176, 31177, 31178, 31179, 31180, 31181, 37498, 6644, 6645, 6541, 6812, - 8646, 34420, 34421, 34422, 34423, 34424, 34425, 34426, 34427, 34428, - 34429, 34430, 34431, 34432, 34433, 34434, 34435, 34436, 34437, 34438, - 34439, 34440, 34441, 34442, 34443, 34444, 34445, 34414, 34450, 34465, - 34466, 34455, 34477, 28977, 28978, 28979, 28980, 28981, 28982, 28983, - 28984, 28985, 28986, 28987, 28988, 28989, 28990, 28991, 28992, 28993, - 28994, 28995, 28996, 28997, 28998, 28999, 29000, 29001, 29002, 31764, - 31765, 31766, 6540, 6539, 6587, 29008, 29009, 29010, 29011, 29012, 29013, - 29014, 29015, 29016, 29017, 29018, 29019, 29020, 29021, 29022, 29023, - 29024, 29025, 29026, 29027, 29028, 29029, 29030, 29031, 29032, 29033, - 8690, 29040, 29043, 29044, 29039, 29041, 34149, 34403, 34402, 34409, - 34478, 34451, 34452, 34454, 34464, 34472, 34475, 34467, 34457, 34469, - 34407, 34471, 34408, 34458, 34468, 34460, 34453, 34419, 34413, 34412, - 34411, 34448, 34459, 34473, 34474, 25815, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 31794, 31795, 31796, 31797, 31798, 31799, 31800, 31801, - 31802, 31803, 31804, 31805, 31806, 31807, 31808, 31809, 31810, 31811, - 31812, 31813, 31814, 31815, 31816, 31817, 31818, 31819, 34190, 34415, - 34417, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 34381, 34376, 34368, 34416, 34362, 34374, - 34397, 34373, 34361, 34386, 34394, 34385, 34366, 34377, 34378, 34384, - 34365, 34395, 34392, 34399, 34375, 34370, 34389, 34379, 34382, 34359, - 34360, 34401, 34372, 34363, 34367, 34383, 34398, 34380, 34393, 34396, - 34369, 34390, 34388, 34387, 34391, 34364, 34371, 34400, 40951, 40951, - 40951, 40951, 37495, 37489, 37490, 37492, 37496, 37493, 37497, 37491, - 37494, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 6592, 6590, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 32230, 32231, 32228, 32232, 32227, 32229, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 10525, 17488, 8037, 29287, 34652, 34651, - 6823, 34697, 31757, 4931, 39127, 38952, 27585, 11538, 11536, 11537, - 18006, 29092, 39039, 17455, 39040, 17529, 39038, 22740, 39037, 8680, - 29091, 17454, 22739, 17528, 34576, 18007, 32825, 36989, 3828, 39284, - 39288, 39285, 39286, 8050, 8049, 8048, 8047, 17487, 39351, 20436, 36648, - 5007, 6476, 32563, 17383, 10551, 31024, 6124, 20433, 37663, 6474, 32218, - 20393, 34698, 4242, 11532, 11533, 20218, 17506, 25667, 17423, 24034, - 28299, 37448, 2541, 18119, 27068, 39130, 35786, 24399, 3426, 31470, - 31791, 18659, 31290, 31287, 6475, 34517, 19108, 33783, 26860, 31606, - 31914, 31915, 8480, 9952, 34505, 34081, 4929, 17519, 32234, 10534, 30882, - 34738, 17527, 17461, 33878, 32769, 20466, 11284, 8479, 6513, 5999, 25270, - 9955, 20399, 32842, 3649, 31604, 8478, 17493, 36650, 32530, 39353, 8054, - 37576, 3540, 7996, 2605, 17494, 4366, 31594, 31905, 39373, 3760, 20825, - 6514, 17429, 17451, 17450, 2748, 31214, 8459, 35785, 8691, 31469, 20830, - 6061, 39350, 28182, 32535, 18044, 19689, 4368, 27584, 31858, 28305, - 34525, 24398, 8471, 3530, 3531, 17444, 98, 6059, 17435, 32176, 17459, - 27574, 28204, 6516, 19688, 2522, 37473, 6821, 37395, 7992, 31319, 38874, - 10920, 33789, 3759, 17718, 4371, 17477, 28540, 28286, 32529, 18675, - 28304, 37581, 38879, 28539, 32359, 36764, 33764, 3432, 6477, 33872, - 32360, 34736, 34112, 37578, 20431, 370, 32237, 34741, 39148, 18043, - 31747, 31748, 8682, 38953, 17465, 20468, 34929, 33869, 5265, 3536, 5006, - 20443, 6822, 10828, 7993, 10659, 10660, 28958, 34503, 20442, 20441, - 29948, 20827, 17349, 20444, 3421, 2538, 20437, 25154, 8474, 32534, 10577, - 17419, 20823, 20826, 17348, 39253, 3881, 39136, 39135, 32219, 3897, - 22564, 2616, 4375, 369, 16743, 16744, 16745, 16746, 16747, 31772, 28199, - 30885, 39128, 8673, 37293, 24296, 31774, 6066, 11374, 8694, 39307, 33866, - 33867, 20430, 31777, 18011, 32848, 28180, 32217, 6482, 11025, 31461, - 4553, 16712, 29946, 34106, 4944, 964, 20398, 22566, 17458, 37577, 4243, - 37688, 19657, 2604, 17523, 3761, 31291, 22561, 31616, 11376, 2614, 11087, - 28201, 8674, 37294, 31775, 6067, 11375, 34111, 20432, 28181, 11086, - 31463, 17526, 19106, 39372, 3535, 31061, 31462, 31280, 6481, 17380, - 17378, 11531, 29441, 28202, 37449, 39295, 39210, 39236, 39260, 17462, - 39137, 30881, 37021, 37022, 7991, 30538, 8696, 39362, 17379, 29282, - 34926, 20927, 11382, 22556, 3765, 39361, 31720, 19112, 31611, 25661, - 2535, 20289, 39363, 39360, 17492, 5002, 5001, 4551, 17906, 25574, 39358, - 17427, 25580, 37703, 37704, 31591, 39359, 4932, 31304, 25577, 25578, - 30517, 30515, 2603, 8462, 31673, 20833, 20832, 18975, 2606, 17367, 348, - 20595, 33766, 20711, 18674, 10533, 25054, 28889, 17415, 18979, 3430, - 34924, 31466, 22553, 25153, 32156, 17722, 22548, 4367, 8672, 39146, 3537, - 4938, 37697, 34082, 18672, 19691, 4245, 18661, 39397, 31719, 19690, - 31901, 19692, 10836, 16700, 962, 4550, 33778, 8059, 34107, 11378, 10538, - 31464, 17472, 11005, 34095, 36996, 39221, 20453, 28002, 9950, 19721, - 8679, 3423, 3425, 3424, 3422, 28001, 6295, 32559, 31314, 4933, 27587, - 17478, 30549, 11529, 17440, 30536, 30889, 30891, 5262, 36651, 6004, 6294, - 6296, 3428, 7997, 31722, 32225, 31282, 34515, 37547, 4256, 24397, 29438, - 29439, 8043, 30530, 18660, 4244, 30553, 4257, 28960, 32556, 27421, 36656, - 30892, 17426, 32443, 31723, 6301, 30831, 20822, 31281, 17381, 20627, - 16781, 8040, 8041, 30540, 30539, 31600, 31597, 29277, 27601, 27602, - 38871, 27603, 29357, 966, 5263, 5264, 38873, 36663, 31750, 38875, 17443, - 31595, 31687, 37691, 8027, 8028, 8024, 975, 25155, 20284, 34090, 34089, - 34091, 34092, 3529, 16698, 24165, 32032, 25112, 8042, 21611, 25109, - 30543, 3543, 3545, 4255, 25052, 31752, 2608, 16776, 30519, 33928, 37488, - 29356, 21626, 20714, 20715, 20718, 20717, 20716, 17447, 16699, 39376, - 19102, 29852, 20445, 31475, 27573, 36662, 8701, 33760, 20831, 37549, - 3908, 39271, 22730, 22657, 22665, 22658, 33795, 33794, 37786, 11297, - 37790, 11291, 25224, 37882, 6537, 8688, 8687, 29431, 29433, 34813, 39234, - 19736, 6132, 30883, 11369, 21609, 28188, 34834, 27284, 4369, 8008, 8018, - 8020, 8004, 8002, 8012, 8010, 8000, 8006, 8014, 7998, 8016, 8009, 8019, - 8021, 8005, 8003, 8013, 8011, 8001, 8007, 8015, 7999, 8017, 31979, 31980, - 31981, 4997, 4998, 32164, 4254, 5998, 25664, 3910, 29355, 20397, 25575, - 33781, 10535, 34102, 34103, 20928, 25579, 24086, 36657, 31960, 39290, - 3923, 36661, 7994, 2609, 34487, 16780, 17486, 31294, 25051, 3878, 25186, - 25172, 25184, 25185, 25206, 24146, 37679, 31762, 31886, 31894, 31895, - 31899, 31896, 31763, 39211, 32951, 32950, 32947, 32946, 3856, 3883, - 32953, 32952, 32949, 32948, 3926, 3822, 3835, 10661, 21613, 37012, 31670, - 31617, 3838, 39225, 33879, 36645, 39356, 30527, 37692, 37008, 37533, - 30341, 19655, 32540, 31671, 17425, 30550, 11011, 11012, 11013, 17516, - 17518, 17517, 3834, 17490, 30537, 6005, 6006, 17441, 16748, 16749, 16750, - 29435, 29436, 29437, 16759, 16752, 16753, 11010, 30888, 30893, 39142, - 34105, 34104, 10662, 27588, 26846, 30874, 8026, 5996, 20629, 10552, 8454, - 30514, 32175, 30890, 34513, 10532, 25053, 34093, 37004, 37003, 37005, - 37006, 24114, 31982, 37707, 37010, 24131, 31996, 24044, 31918, 28185, - 24422, 24421, 2753, 2759, 2754, 2758, 2751, 24419, 2752, 39367, 28198, - 37532, 34500, 33763, 28203, 18664, 18667, 17405, 33854, 33856, 33855, - 33857, 33853, 33852, 39354, 33858, 17385, 31857, 33851, 33861, 33864, - 29089, 17360, 37743, 17388, 31292, 8460, 8461, 22549, 17416, 22550, - 22551, 17402, 17403, 17404, 10922, 39368, 963, 31609, 8700, 31316, 17410, - 10921, 17525, 960, 17431, 39144, 33780, 37394, 18669, 25269, 17393, - 20452, 17395, 17386, 2530, 17479, 33779, 11006, 17413, 17390, 18668, - 6068, 33850, 33849, 6069, 22552, 31608, 8699, 39143, 33785, 33784, 37894, - 17409, 17398, 17392, 31313, 32564, 19694, 34088, 19654, 31311, 31310, - 31306, 31308, 29400, 33984, 29373, 33971, 37677, 37686, 37676, 37685, - 29399, 33983, 29372, 33970, 19772, 19765, 19769, 19762, 29401, 33985, - 29374, 33972, 19773, 19766, 19770, 19763, 20395, 20396, 33924, 33925, - 24289, 37928, 32119, 11364, 32550, 19767, 24401, 19744, 19699, 34739, - 32437, 32438, 32439, 19789, 32440, 19756, 38862, 38859, 6297, 31867, - 32174, 19930, 34504, 31755, 20287, 20288, 37540, 27420, 24408, 34501, - 37536, 37537, 5000, 30524, 37575, 5003, 27589, 371, 17448, 31589, 30523, - 36649, 30522, 2537, 30520, 31790, 10557, 2521, 37534, 28179, 28195, - 34737, 28196, 160, 32824, 32233, 34094, 20423, 38853, 8463, 31590, 37546, - 11370, 29353, 33865, 29358, 31721, 11368, 31602, 29362, 3755, 29351, - 3754, 28197, 31323, 29354, 6479, 27285, 39364, 31862, 2607, 37531, 39126, - 32847, 3527, 3528, 31222, 9954, 2620, 24087, 37543, 31684, 6646, 4552, - 17907, 8671, 33777, 32827, 3547, 3656, 31480, 29945, 32826, 34527, 30894, - 20391, 20455, 16713, 40951, 40951, 40951, 40951, 39357, 31566, 39150, - 32157, 19103, 32820, 29979, 28193, 31754, 28190, 37784, 37781, 37789, - 33792, 29408, 227, 228, 40951, 40951, 40951, 32442, 30521, 10847, 31218, - 32538, 28191, 6001, 33782, 17482, 33769, 2539, 31460, 32177, 40951, - 40951, 40951, 295, 243, 344, 342, 339, 237, 235, 236, 233, 234, 332, 334, - 335, 321, 288, 250, 281, 282, 283, 265, 309, 286, 336, 337, 307, 308, - 270, 323, 276, 277, 259, 300, 256, 278, 319, 257, 258, 255, 310, 317, - 338, 329, 279, 238, 318, 311, 316, 333, 298, 299, 297, 301, 302, 303, - 230, 231, 284, 312, 240, 304, 305, 241, 246, 326, 327, 296, 247, 248, - 249, 232, 343, 322, 328, 271, 340, 289, 254, 331, 253, 325, 252, 330, - 313, 280, 324, 341, 274, 242, 291, 251, 290, 239, 314, 315, 320, 294, - 268, 266, 267, 293, 292, 260, 261, 262, 263, 264, 229, 244, 245, 306, - 275, 287, 269, 285, 273, 272, 25151, 29947, 25272, 40951, 40951, 40951, - 40951, 19684, 25449, 18041, 31741, 30655, 3849, 3927, 3889, 3823, 3913, - 26961, 4251, 19786, 38863, 17364, 39190, 32226, 3921, 3914, 24416, 26986, - 4252, 19783, 38864, 17365, 39272, 39274, 34335, 3919, 3937, 3871, 39205, - 39206, 10835, 3920, 3938, 3872, 39243, 36993, 24418, 26987, 4253, 38868, - 38865, 17366, 36991, 24411, 26979, 4247, 19757, 38860, 17361, 24404, - 26967, 4250, 19732, 38858, 17363, 24412, 26978, 4248, 19761, 38861, - 17362, 24402, 26984, 4249, 19726, 38857, 24414, 26981, 37011, 26980, - 24406, 26966, 17508, 26965, 31868, 24403, 19731, 26977, 19760, 33758, - 26983, 19724, 38856, 19722, 24413, 19779, 19778, 6807, 29003, 6817, - 29004, 29285, 40951, 40951, 40951, 40951, 40951, 40951, 22664, 22732, - 22660, 22728, 22655, 22731, 22659, 22666, 22733, 22661, 22729, 22656, - 40951, 40951, 40951, 40951, 19729, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 24209, 37904, 32072, 11315, 24216, 37901, 32079, 11312, 24203, 37900, - 32069, 11311, 40951, 40951, 40951, 40951, 24208, 37903, 32071, 11314, - 24218, 37905, 32081, 11316, 19740, 19781, 19754, 19718, 19739, 19780, - 19753, 19717, 24253, 37938, 32132, 11335, 24252, 37937, 32131, 11334, - 24251, 37934, 32130, 11331, 24255, 37940, 32134, 11337, 24254, 37939, - 32133, 11336, 24283, 37915, 32098, 11351, 24291, 37930, 32121, 11366, - 24293, 37926, 32154, 11362, 24243, 37924, 32112, 11360, 24244, 37925, - 32113, 11361, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 24292, 37929, 32122, 11365, 29406, 29379, 33977, 33990, 24106, 37771, - 40951, 40951, 40951, 40951, 40951, 40951, 39310, 39325, 39315, 39320, - 39335, 39330, 39340, 39345, 39312, 39327, 39317, 39322, 39337, 39332, - 39342, 39347, 39311, 39326, 39316, 39321, 39336, 39331, 39341, 39346, - 39308, 39323, 39313, 39318, 39333, 39328, 39338, 39343, 39309, 39324, - 39314, 39319, 39334, 39329, 39339, 39344, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 24259, 37944, 32138, 11342, 24273, 37954, - 32153, 11347, 24217, 37902, 32080, 11313, 19695, 19698, 19697, 19696, - 24227, 32087, 24262, 32123, 24284, 32118, 24288, 32114, 24226, 32086, - 24282, 32097, 39154, 39153, 40951, 40951, 2517, 2514, 32067, 11326, - 29034, 29035, 29042, 29036, 29398, 29370, 33969, 33982, 40951, 40951, - 40951, 40951, 24223, 32058, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 6535, 6536, 6534, 24071, 24069, - 24070, 24072, 24068, 11304, 11306, 11305, 11307, 31467, 39226, 4940, - 31468, 40760, 28003, 17406, 29283, 36994, 17389, 32235, 20454, 33626, - 5261, 31771, 24180, 32021, 19113, 19109, 20824, 17387, 8051, 28959, - 32179, 11379, 25330, 17414, 33868, 17397, 18666, 18665, 17408, 32659, - 33859, 17394, 32845, 31618, 4928, 31059, 32667, 31672, 25576, 28189, - 32850, 31301, 20930, 17437, 27604, 39375, 39129, 19111, 11001, 39349, - 11380, 7995, 37689, 34110, 18010, 32168, 17457, 32562, 36995, 4548, - 25738, 9949, 22565, 33881, 17485, 8695, 2597, 9956, 2615, 31603, 6064, - 2618, 18662, 32671, 34526, 16648, 18005, 31288, 22554, 31060, 11526, - 17500, 35368, 6512, 4370, 9942, 8055, 4939, 31478, 31668, 9957, 32441, - 6000, 24035, 25665, 28183, 2619, 33860, 39396, 33862, 17399, 17412, - 30873, 17521, 29286, 10925, 17417, 17401, 32531, 22563, 18040, 20392, - 17466, 8702, 25106, 32536, 37665, 37757, 11541, 11527, 3470, 32768, - 30884, 17513, 5005, 10830, 18039, 25107, 31903, 32849, 34480, 17908, - 40754, 20283, 32527, 34927, 8681, 21216, 25336, 31285, 20394, 31217, - 31749, 25268, 28187, 27576, 2617, 34740, 25573, 11371, 33790, 30830, - 30555, 33768, 17471, 30879, 3538, 3766, 32558, 18676, 31685, 16739, - 16740, 16742, 16741, 4554, 24400, 17491, 37450, 34733, 34734, 32370, - 11534, 28192, 25662, 26861, 26862, 6300, 9944, 32373, 3655, 17717, 30529, - 17424, 38977, 5004, 26825, 20467, 4942, 37574, 34502, 22558, 10829, - 17391, 101, 6478, 30516, 3534, 31309, 31303, 31312, 31302, 25340, 17430, - 38517, 27409, 16737, 17903, 40946, 4926, 30554, 3758, 32533, 18008, 8677, - 33876, 31792, 17452, 20933, 36767, 31322, 11528, 8457, 2599, 17449, - 37452, 4935, 25339, 25271, 25150, 34109, 2761, 32371, 36655, 4941, 3431, - 32178, 3429, 34113, 31778, 28961, 29066, 29077, 29080, 29069, 29059, - 29074, 39165, 3791, 29060, 39162, 39178, 39181, 39157, 39170, 39175, - 3788, 3804, 3807, 3783, 3796, 3801, 29067, 29078, 29081, 29070, 29065, - 29075, 39166, 3792, 29061, 39184, 39187, 39188, 39183, 39185, 39186, - 3810, 3813, 3814, 3809, 3811, 3812, 29084, 29087, 29088, 29083, 29085, - 29086, 39167, 3793, 29062, 39163, 39179, 39182, 39158, 39168, 39176, - 3789, 3805, 3808, 3784, 3794, 3802, 29068, 29079, 29082, 29071, 29063, - 29076, 39169, 3795, 29064, 39159, 3785, 29072, 39160, 3786, 29073, 39172, - 39173, 39171, 3798, 3799, 3797, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 39391, 39394, 39390, 39392, - 39389, 39388, 39393, 39384, 39387, 39383, 39385, 39382, 39381, 39386, - 40951, 40951, 2762, 30528, 4934, 32843, 36997, 24415, 18663, 31472, - 11377, 99, 34507, 39380, 8698, 40951, 40951, 40951, 40668, 22557, 31068, - 4258, 25338, 31473, 29056, 25668, 17480, 19656, 40951, 40951, 40951, - 40951, 40951, 32846, 32163, 6135, 31776, 2602, 11004, 3427, 27583, 1, - 25135, 8676, 6062, 32539, 22567, 20447, 27599, 39352, 31586, 32664, - 22559, 5008, 28200, 37451, 19686, 31481, 32173, 27600, 20473, 25156, - 19107, 17489, 18977, 21696, 17481, 39369, 3541, 8053, 31605, 39371, - 17432, 25152, 8650, 16751, 29057, 20464, 20926, 39355, 24033, 18042, 956, - 25273, 31324, 31620, 31619, 31307, 17445, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 28186, 11189, 4246, 3544, 30518, 17467, 35784, - 17512, 36654, 31607, 3539, 20925, 17905, 31289, 32216, 40951, 40951, - 34108, 27067, 32375, 17396, 17400, 17411, 11199, 3763, 4943, 32819, - 17407, 40951, 40951, 40951, 40951, 40951, 40951, 19110, 32111, 24242, - 31025, 31026, 20634, 19693, 24287, 32117, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 4182, 4212, 4183, 4227, 4198, 4216, 4184, 4235, - 4205, 4213, 4191, 4228, 4199, 4217, 4185, 4239, 4209, 4224, 4195, 4232, - 4221, 4188, 4236, 4206, 4214, 4192, 4229, 4200, 4218, 4186, 4241, 4211, - 4226, 4197, 4234, 4204, 4223, 4190, 4238, 4208, 4194, 4231, 4202, 4220, - 4187, 4240, 4210, 4225, 4196, 4233, 4203, 4222, 4189, 4237, 4207, 4215, - 4193, 4230, 4201, 4219, 25173, 25174, 25181, 25183, 25178, 25239, 25240, - 25236, 25238, 25234, 25237, 25230, 25233, 25231, 25235, 25232, 25177, - 25180, 25175, 25179, 25176, 25182, 37854, 37855, 37862, 37864, 37859, - 37824, 37825, 37821, 37823, 37819, 37822, 37815, 37818, 37816, 37820, - 37817, 37858, 37861, 37856, 37860, 37857, 37863, 37797, 24036, 37794, - 24041, 24127, 37893, 32004, 25265, 38841, 38842, 38843, 38844, 38845, - 38846, 20409, 20410, 20411, 20412, 20413, 20414, 24037, 24042, 31917, - 31916, 37796, 20408, 37852, 37889, 37804, 37892, 37888, 31966, 32000, - 31944, 31999, 31976, 24085, 31959, 37811, 25166, 20809, 37806, 37808, - 40951, 24084, 6298, 20805, 19733, 37829, 37884, 37795, 24038, 37830, - 37885, 25226, 25203, 4454, 4458, 4446, 4452, 4455, 4460, 4447, 4449, - 4457, 4459, 4461, 4456, 4450, 4451, 4477, 4487, 2520, 20806, 24079, - 31954, 20807, 24196, 32055, 11321, 37897, 24076, 31951, 38951, 31968, - 29006, 29005, 29007, 39229, 24130, 27578, 31995, 29037, 34508, 34509, - 34511, 34512, 34510, 39297, 39202, 31767, 3903, 24137, 24092, 4453, 4474, - 4469, 4448, 4464, 4463, 4471, 4462, 4467, 4473, 4444, 4468, 4465, 4475, - 4445, 4470, 37476, 31962, 4364, 24151, 37803, 25250, 27579, 27580, 37475, - 31961, 4363, 24150, 37485, 4350, 4357, 37477, 32572, 32574, 32571, 32570, - 32567, 32566, 32569, 32568, 32575, 32573, 40951, 40951, 40951, 40951, - 40951, 40951, 6854, 6855, 6856, 6857, 6858, 6859, 6860, 6861, 6862, 6863, - 6864, 6865, 6866, 6867, 6868, 6869, 6870, 6871, 6872, 6873, 6874, 6875, - 6876, 6877, 6878, 6879, 6880, 6881, 6882, 6883, 6884, 6885, 6886, 6887, - 6888, 6889, 6890, 6891, 6892, 6893, 6894, 6895, 6896, 6897, 6898, 6899, - 6900, 6901, 6902, 6903, 6904, 6905, 6906, 6907, 6908, 6909, 6910, 6911, - 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, 6920, 6921, 6922, 6923, - 6924, 6925, 6926, 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, 6935, - 6936, 6937, 6938, 6939, 6940, 6941, 6942, 6943, 6944, 6945, 6946, 6947, - 6948, 6949, 6950, 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, - 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969, 6970, 6971, - 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, 6981, 6982, 6983, - 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, - 6996, 6997, 6998, 6999, 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, - 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, - 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, 7031, - 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, - 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, 7055, - 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, - 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, - 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, 7091, - 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, 7101, 7102, 7103, - 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, - 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, 7125, 7126, 7127, - 7128, 7129, 7130, 7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, - 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149, 7150, 7151, - 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, 7161, 7162, 7163, - 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174, 7175, - 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, - 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7199, - 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, 7211, - 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, 7221, 7222, 7223, - 7224, 7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, 7233, 7234, 7235, - 7236, 7237, 7238, 7239, 7240, 7241, 7242, 7243, 7244, 7245, 7246, 7247, - 7248, 7249, 7250, 7251, 7252, 7253, 7254, 7255, 7256, 7257, 7258, 7259, - 7260, 7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, 7269, 7270, 7271, - 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, 7281, 7282, 7283, - 7284, 7285, 7286, 7287, 7288, 7289, 7290, 7291, 7292, 7293, 7294, 7295, - 7296, 7297, 7298, 7299, 7300, 7301, 7302, 7303, 7304, 7305, 7306, 7307, - 7308, 7309, 7310, 7311, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, - 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, 7331, - 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, - 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 7355, - 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, 6838, 6839, - 6840, 6841, 6842, 6843, 6844, 6845, 6846, 6847, 6848, 6849, 6850, 6851, - 6852, 6853, 6824, 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, - 6834, 6835, 6836, 6837, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 24032, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 35020, 34949, 35012, 35021, 34937, 35010, 34931, 34930, 35007, - 35015, 34932, 35011, 34935, 34952, 35023, 35019, 34944, 34946, 34943, - 34942, 34939, 34938, 34941, 34940, 34947, 34945, 34936, 35018, 35005, - 34948, 34951, 35013, 34934, 34953, 34954, 34955, 34956, 34957, 34958, - 34959, 34960, 34961, 34962, 34963, 34964, 34965, 34966, 34967, 34968, - 34969, 34970, 34971, 34972, 34973, 34974, 34975, 34976, 34977, 34978, - 35008, 35017, 35016, 34933, 35009, 34950, 34979, 34980, 34981, 34982, - 34983, 34984, 34985, 34986, 34987, 34988, 34989, 34990, 34991, 34992, - 34993, 34994, 34995, 34996, 34997, 34998, 34999, 35000, 35001, 35002, - 35003, 35004, 35006, 35024, 35014, 35022, 5995, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 38339, 38350, 38361, 38373, 38384, - 38395, 38406, 38417, 38428, 38436, 38437, 38438, 38439, 38441, 38442, - 38443, 38444, 38445, 38446, 38447, 38448, 38449, 38450, 38452, 38453, - 38454, 38455, 38456, 38457, 38458, 38459, 38460, 38461, 38463, 38464, - 38465, 38466, 38467, 38468, 38469, 38470, 38471, 38472, 38474, 38475, - 38476, 38477, 38478, 38479, 38480, 38481, 38482, 38483, 38485, 38486, - 38487, 38488, 38489, 38490, 38491, 38492, 38493, 38494, 38496, 38497, - 38498, 38499, 38500, 38501, 38502, 38503, 38504, 38505, 38507, 38508, - 38509, 38510, 38511, 38512, 38513, 38514, 38515, 38516, 38263, 38264, - 38265, 38266, 38267, 38268, 38269, 38270, 38271, 38272, 38274, 38275, - 38276, 38277, 38278, 38279, 38280, 38281, 38282, 38283, 38285, 38286, - 38287, 38288, 38289, 38290, 38291, 38292, 38293, 38294, 38296, 38297, - 38298, 38299, 38300, 38301, 38302, 38303, 38304, 38305, 38307, 38308, - 38309, 38310, 38311, 38312, 38313, 38314, 38315, 38316, 38318, 38319, - 38320, 38321, 38322, 38323, 38324, 38325, 38326, 38327, 38329, 38330, - 38331, 38332, 38333, 38334, 38335, 38336, 38337, 38338, 38340, 38341, - 38342, 38343, 38344, 38345, 38346, 38347, 38348, 38349, 38351, 38352, - 38353, 38354, 38355, 38356, 38357, 38358, 38359, 38360, 38362, 38363, - 38364, 38365, 38366, 38367, 38368, 38369, 38370, 38371, 38374, 38375, - 38376, 38377, 38378, 38379, 38380, 38381, 38382, 38383, 38385, 38386, - 38387, 38388, 38389, 38390, 38391, 38392, 38393, 38394, 38396, 38397, - 38398, 38399, 38400, 38401, 38402, 38403, 38404, 38405, 38407, 38408, - 38409, 38410, 38411, 38412, 38413, 38414, 38415, 38416, 38418, 38419, - 38420, 38421, 38422, 38423, 38424, 38425, 38426, 38427, 38429, 38430, - 38431, 38432, 38433, 38434, 38435, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 29854, 29853, 34498, 34077, 34499, 34529, 16774, 17347, 16772, - 16785, 16778, 16777, 3, 2, 347, 3542, 2612, 5258, 6290, 20419, 20449, - 34928, 24495, 29177, 16775, 25337, 29928, 16783, 24497, 38850, 38955, - 17497, 17647, 6063, 8678, 32821, 25111, 33874, 32822, 25110, 32853, - 10543, 11530, 10827, 10544, 10826, 10545, 10825, 10546, 10823, 10547, - 29045, 28963, 34833, 34832, 16773, 17346, 5993, 5266, 16771, 16784, - 16738, 34560, 34530, 16819, 16818, 20706, 17442, 17645, 20707, 18670, - 18976, 20708, 31789, 32368, 20709, 37754, 37960, 34079, 10559, 10556, - 30887, 30886, 20286, 20448, 4927, 5257, 29350, 28965, 20633, 20632, - 29279, 29284, 34495, 34483, 16770, 16822, 6292, 20421, 20451, 6291, - 20420, 20450, 24498, 38851, 38956, 31210, 31209, 31587, 31211, 31212, - 31567, 31869, 31876, 31904, 33639, 33640, 34481, 33638, 33641, 34482, - 10824, 10548, 31676, 31677, 31724, 31675, 31678, 31725, 32662, 34528, - 5994, 10528, 27410, 28789, 34494, 34497, 34080, 16769, 16767, 17384, - 34496, 34078, 33633, 34925, 33632, 32557, 8472, 10527, 34519, 34484, - 30547, 30768, 31674, 31726, 1059, 1060, 28964, 32852, 22893, 23515, - 10526, 2313, 361, 34911, 21230, 22570, 22571, 22613, 22579, 37100, 19375, - 19376, 19353, 19374, 17641, 17642, 17643, 28787, 17644, 34585, 40949, - 40948, 40950, 25333, 32171, 25331, 32169, 31283, 25334, 32172, 29927, - 28788, 39378, 25332, 32170, 17646, 31284, 39147, 27571, 27572, 24248, - 32127, 39885, 28575, 38518, 38629, 38697, 38708, 38719, 38730, 38741, - 38752, 38763, 38519, 38530, 38541, 38552, 38563, 38574, 38585, 31643, - 5256, 4549, 40947, 9642, 9641, 9337, 2827, 26869, 26867, 26927, 26925, - 20199, 5093, 27245, 27248, 38596, 38607, 38618, 38630, 38641, 38652, - 38663, 38674, 38685, 38693, 38694, 38695, 38696, 38698, 38699, 38700, - 38701, 38702, 38703, 38704, 38705, 38706, 38707, 38709, 38710, 38711, - 38712, 38713, 38714, 38715, 38716, 38717, 38718, 38720, 38721, 38722, - 38723, 38724, 38725, 38726, 38727, 38728, 38729, 38731, 38732, 38733, - 38734, 38735, 38736, 38737, 38738, 38739, 38740, 38742, 38743, 38744, - 38745, 38746, 38747, 38748, 38749, 38750, 38751, 38753, 38754, 38755, - 38756, 38757, 38758, 38759, 38760, 38761, 38762, 38764, 38765, 38766, - 38767, 38768, 38769, 38770, 38771, 38772, 38773, 38520, 38521, 38522, - 38523, 38524, 38525, 38526, 38527, 38528, 38529, 38531, 38532, 38533, - 38534, 38535, 38536, 38537, 38538, 38539, 38540, 38542, 38543, 38544, - 38545, 38546, 38547, 38548, 38549, 38550, 38551, 38553, 38554, 38555, - 38556, 38557, 38558, 38559, 38560, 38561, 38562, 38564, 38565, 38566, - 38567, 38568, 38569, 38570, 38571, 38572, 38573, 38575, 38576, 38577, - 38578, 38579, 38580, 38581, 38582, 38583, 38584, 38586, 38587, 38588, - 38589, 38590, 38591, 38592, 38593, 38594, 38595, 38597, 38598, 38599, - 38600, 38601, 38602, 38603, 38604, 38605, 38606, 38608, 38609, 38610, - 38611, 38612, 38613, 38614, 38615, 38616, 38617, 38619, 38620, 38621, - 38622, 38623, 38624, 38625, 38626, 38627, 38628, 38631, 38632, 38633, - 38634, 38635, 38636, 38637, 38638, 38639, 38640, 38642, 38643, 38644, - 38645, 38646, 38647, 38648, 38649, 38650, 38651, 38653, 38654, 38655, - 38656, 38657, 38658, 38659, 38660, 38661, 38662, 38664, 38665, 38666, - 38667, 38668, 38669, 38670, 38671, 38672, 38673, 38675, 38676, 38677, - 38678, 38679, 38680, 38681, 38682, 38683, 38684, 38686, 38687, 38688, - 38689, 38690, 38691, 38692, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 21614, - 21615, 21622, 21624, 21621, 21620, 21617, 21616, 21619, 21618, 21625, - 21623, 22758, 23321, 22917, 23546, 23156, 23919, 22852, 23456, 22853, - 23457, 22854, 23458, 23028, 23697, 23029, 23698, 23030, 23699, 23095, - 23795, 22836, 23439, 22832, 23435, 23541, 23665, 22768, 23331, 22769, - 23332, 22857, 23462, 22858, 23463, 22842, 23445, 22843, 23446, 23540, - 23542, 22922, 23548, 22923, 23549, 22940, 23576, 22970, 23616, 22978, - 23638, 23068, 23756, 23160, 23923, 23161, 23924, 23157, 23920, 23158, - 23921, 23340, 23714, 23715, 23874, 23875, 23804, 23805, 23530, 23531, - 2283, 2286, 2284, 2288, 2290, 2287, 2289, 2285, 2291, 10756, 10751, - 10750, 10757, 10752, 10753, 10755, 10754, 3614, 3613, 3615, 18884, 18883, - 18882, 18881, 18886, 18885, 30619, 30618, 3559, 35374, 35382, 35391, - 35383, 35385, 35380, 35384, 35379, 35395, 35394, 35397, 35389, 35376, - 35396, 35378, 35377, 35390, 35381, 35393, 35387, 35388, 35386, 35392, - 35375, 35513, 35520, 35521, 35516, 35517, 35522, 35523, 35514, 35518, - 35519, 35515, 35579, 35586, 35587, 35582, 35583, 35588, 35589, 35580, - 35584, 35585, 35581, 35690, 35697, 35698, 35693, 35694, 35699, 35700, - 35691, 35695, 35696, 35692, 35590, 35597, 35598, 35593, 35594, 35599, - 35600, 35591, 35595, 35596, 35592, 35668, 35675, 35676, 35671, 35672, - 35677, 35678, 35669, 35673, 35674, 35670, 35568, 35575, 35576, 35571, - 35572, 35577, 35578, 35569, 35573, 35574, 35570, 35679, 35686, 35687, - 35682, 35683, 35688, 35689, 35680, 35684, 35685, 35681, 35601, 35608, - 35609, 35604, 35605, 35610, 35611, 35602, 35606, 35607, 35603, 35734, - 35741, 35742, 35737, 35738, 35743, 35744, 35735, 35739, 35740, 35736, - 35723, 35730, 35731, 35726, 35727, 35732, 35733, 35724, 35728, 35729, - 35725, 35756, 35763, 35764, 35759, 35760, 35765, 35766, 35757, 35761, - 35762, 35758, 35623, 35630, 35631, 35626, 35627, 35632, 35633, 35624, - 35628, 35629, 35625, 35546, 35553, 35554, 35549, 35550, 35555, 35556, - 35547, 35551, 35552, 35548, 35745, 35752, 35753, 35748, 35749, 35754, - 35755, 35746, 35750, 35751, 35747, 35524, 35531, 35532, 35527, 35528, - 35533, 35534, 35525, 35529, 35530, 35526, 35535, 35542, 35543, 35538, - 35539, 35544, 35545, 35536, 35540, 35541, 35537, 35612, 35619, 35620, - 35615, 35616, 35621, 35622, 35613, 35617, 35618, 35614, 35557, 35564, - 35565, 35560, 35561, 35566, 35567, 35558, 35562, 35563, 35559, 35712, - 35719, 35720, 35715, 35716, 35721, 35722, 35713, 35717, 35718, 35714, - 35634, 35642, 35643, 35637, 35638, 35644, 35645, 35635, 35639, 35640, - 35636, 35646, 35653, 35654, 35649, 35650, 35655, 35656, 35647, 35651, - 35652, 35648, 35657, 35664, 35665, 35660, 35661, 35666, 35667, 35658, - 35662, 35663, 35659, 35701, 35708, 35709, 35704, 35705, 35710, 35711, - 35702, 35706, 35707, 35703, 35501, 35502, 35509, 35510, 35505, 35506, - 35511, 35512, 35503, 35507, 35508, 35504, 35641, 33664, 33662, 33663, - 17807, 22179, 22177, 22180, 22178, 22169, 22175, 22173, 22176, 22174, - 22170, 22190, 22186, 22191, 22187, 22171, 22188, 22184, 22189, 22185, - 22172, 22201, 22181, 22183, 22182, 22197, 22200, 22198, 22193, 22199, - 22194, 22195, 22196, 22202, 22192, 22341, 22218, 22219, 22220, 22217, - 22336, 22328, 20316, 20318, 20320, 20317, 20319, 21319, 21321, 21323, - 21320, 21322, 21312, 21311, 21310, 21313, 27780, 27785, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, - 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, 40951, + 7575, 7576, 7577, 7578, 7579, 7580, 7471, 7472, 7473, 7474, 7475, 7476, + 7477, 7478, 7479, 7480, 7481, 7482, 7483, 7484, 41412, 41412, 7581, 7582, + 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, + 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, 7606, + 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614, 7615, 7616, 7617, 7618, + 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 7629, 7630, + 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7641, 7642, + 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7654, + 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, + 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674, 7675, 7676, 7677, 7678, + 7679, 7680, 7681, 7682, 7683, 7684, 7685, 7686, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 24174, 24177, 24178, 24175, 24176, + 24180, 24181, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 2549, 2550, 2548, 2551, 2547, 41412, 41412, + 41412, 41412, 41412, 20049, 20076, 20054, 19985, 20041, 20044, 20046, + 20045, 20040, 20047, 20043, 20042, 19986, 20019, 20020, 20017, 20018, + 19983, 19984, 19982, 19990, 20032, 20030, 20007, 20039, 20012, 41412, + 20024, 20050, 19998, 19993, 20034, 41412, 20036, 41412, 20010, 20014, + 41412, 20000, 19996, 41412, 20028, 20005, 20022, 20016, 20026, 20038, + 19989, 19992, 19995, 20051, 1164, 1163, 1194, 1192, 1193, 1195, 1424, + 1422, 1423, 1425, 1189, 1187, 1188, 1190, 1555, 1553, 1554, 1556, 1534, + 1532, 1533, 1535, 1550, 1548, 1549, 1551, 1568, 1566, 1567, 1569, 1429, + 1427, 1428, 1430, 1230, 1228, 1229, 1231, 1401, 1399, 1400, 1402, 1511, + 1509, 1510, 1512, 1516, 1514, 1515, 1517, 1220, 1219, 1211, 1210, 1234, + 1233, 1223, 1222, 1330, 1329, 1459, 1458, 1353, 1351, 1352, 1354, 1264, + 1262, 1263, 1265, 1276, 1274, 1275, 1277, 1392, 1390, 1391, 1393, 1406, + 1405, 1463, 1461, 1462, 1464, 1306, 1305, 1301, 1299, 1300, 1302, 1310, + 1308, 1309, 1311, 1592, 1591, 1590, 1589, 2411, 2410, 2419, 2418, 2415, + 2414, 2413, 2412, 2423, 2422, 2409, 2417, 2416, 2425, 2421, 2420, 2424, + 1756, 1704, 1933, 1930, 1931, 1926, 1927, 1928, 1920, 1733, 1734, 1731, + 1732, 1956, 1645, 1649, 1396, 1394, 1395, 1397, 1561, 1560, 1614, 1613, + 1611, 1610, 1559, 1571, 1570, 1357, 1356, 1360, 1359, 1627, 1625, 1626, + 1628, 1562, 1563, 2100, 2099, 2102, 2101, 2121, 2120, 2129, 2128, 2119, + 2118, 2125, 2124, 2105, 2103, 2104, 2154, 2152, 2153, 1244, 1242, 1243, + 1245, 2111, 2109, 2115, 2098, 2123, 1675, 1666, 1671, 1678, 1673, 1684, + 2063, 2051, 2058, 2071, 2074, 2079, 2081, 2086, 2083, 2092, 1760, 1766, + 1743, 1738, 1799, 1795, 1801, 1970, 1963, 1975, 1983, 1940, 1944, 1697, + 1689, 1693, 1699, 2044, 2039, 2156, 1640, 1636, 1728, 1724, 1712, 1717, + 1708, 1715, 1710, 1719, 1905, 1901, 1903, 1907, 1774, 1776, 1784, 1782, + 1779, 1790, 1772, 1793, 1827, 1819, 1831, 1837, 1811, 1840, 1858, 1847, + 1852, 1862, 1841, 1863, 1879, 1869, 1891, 1884, 1887, 1894, 1753, 1749, + 1750, 1751, 2139, 2132, 2141, 2147, 2096, 2151, 2080, 1935, 1658, 1991, + 1994, 1998, 1992, 1995, 1997, 2127, 2126, 2113, 2117, 2097, 2122, 1682, + 1681, 1676, 1680, 1672, 1683, 2077, 2076, 2069, 2075, 2073, 2078, 2090, + 2089, 2084, 2088, 2082, 2091, 1709, 1718, 1902, 1906, 1773, 1777, 1788, + 1771, 1792, 1835, 1810, 1839, 1842, 1860, 1892, 1889, 1882, 1888, 1886, + 1893, 1657, 2149, 2136, 2145, 2135, 2095, 2150, 2110, 2108, 2112, 2114, + 2106, 1674, 1665, 1670, 1677, 1667, 2062, 2050, 2057, 2070, 2052, 2085, + 1759, 1765, 1742, 1737, 1798, 1800, 1969, 1962, 1974, 1982, 1939, 1947, + 1943, 1696, 1688, 1692, 1698, 2043, 2155, 1639, 1635, 1727, 1723, 1711, + 1716, 1707, 1714, 1904, 1900, 1775, 1783, 1781, 1778, 1789, 1826, 1818, + 1830, 1836, 1820, 1857, 1846, 1851, 1861, 1878, 1868, 1890, 1883, 1870, + 1752, 1748, 1754, 2138, 2131, 2140, 2146, 2133, 2116, 2107, 1679, 1668, + 2072, 2053, 2087, 2093, 1984, 1966, 2021, 2001, 1780, 1791, 1838, 1885, + 1871, 2148, 2134, 1999, 1993, 1996, 2042, 2046, 1642, 1644, 1726, 1730, + 1986, 1990, 2023, 2031, 1740, 1745, 1768, 1770, 1797, 1803, 1946, 1951, + 1695, 1703, 2012, 2007, 2026, 2020, 2029, 1988, 1949, 1701, 2041, 2045, + 1641, 1643, 1725, 1729, 1985, 1989, 2022, 2030, 1739, 1744, 1767, 1769, + 1796, 1802, 1945, 1950, 1694, 1702, 2010, 2005, 2024, 2018, 2028, 1987, + 1948, 1700, 2011, 2006, 2025, 2019, 1965, 2000, 2038, 1971, 1964, 1976, + 2013, 2008, 2027, 2040, 2157, 1659, 1660, 30832, 30833, 1923, 1914, 1918, + 1915, 1916, 1917, 1957, 1648, 1653, 1651, 1647, 1912, 1959, 1655, 2033, + 1925, 2060, 2049, 2048, 2047, 2055, 2065, 2067, 2066, 1762, 1761, 1736, + 1735, 1961, 1968, 1967, 1978, 1977, 1979, 1981, 1980, 1937, 1936, 1942, + 2003, 2002, 2009, 2015, 2014, 2017, 2016, 1686, 1691, 1690, 2035, 2034, + 2036, 2037, 1638, 1633, 1632, 1631, 1720, 1722, 1721, 1706, 1705, 1898, + 1896, 1816, 1817, 1814, 1821, 1822, 1829, 1828, 1833, 1832, 1843, 1844, + 1845, 1855, 1853, 1848, 1849, 1929, 1932, 1854, 1746, 1747, 1866, 1865, + 1876, 1875, 1874, 1881, 1880, 2143, 2142, 1669, 2061, 2059, 2056, 2054, + 2068, 2064, 1764, 1757, 1763, 1972, 1938, 2004, 1687, 1825, 1834, 2130, + 2137, 2144, 1859, 1899, 1867, 1897, 1815, 1634, 1787, 1872, 1850, 1823, + 1786, 1824, 1873, 1758, 1741, 1856, 1713, 1664, 1785, 1637, 1941, 1973, + 1877, 1924, 1919, 1922, 1921, 1958, 1646, 1794, 1953, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 1954, 1908, 1661, 1662, 1864, 1952, 1934, 1656, 2094, 1955, 1960, 1755, + 32353, 1685, 2032, 1663, 38715, 38826, 38894, 38905, 38916, 38927, 38938, + 38949, 38960, 38716, 38727, 38738, 38749, 38760, 38771, 38782, 31807, + 31812, 31813, 31806, 31837, 31808, 31839, 31815, 31829, 31811, 41412, + 41412, 41412, 41412, 41412, 41412, 8479, 8481, 8306, 8307, 8490, 8492, + 8192, 8480, 8482, 8555, 8556, 8491, 8493, 8193, 8246, 8247, 31838, 31809, + 31810, 31824, 31836, 31821, 31833, 31819, 31831, 31823, 31835, 31816, + 31825, 31817, 31826, 31820, 31832, 31818, 31830, 31814, 31827, 32848, + 39721, 31822, 31834, 10673, 6231, 39597, 11389, 10672, 6230, 39595, + 34023, 34032, 34067, 41412, 34057, 34024, 34068, 34030, 34031, 34034, + 34038, 34033, 34037, 34035, 34039, 34066, 34014, 34016, 34065, 34063, + 34036, 34062, 34029, 41412, 34056, 34025, 34064, 34022, 41412, 41412, + 41412, 41412, 1098, 2430, 1079, 2432, 1110, 41412, 1095, 1096, 1075, + 1076, 1107, 1108, 2335, 2336, 2405, 2406, 1295, 1159, 1158, 1149, 1148, + 1579, 1578, 1152, 1151, 1596, 1594, 1595, 1597, 1169, 1168, 1184, 1182, + 1183, 1185, 1521, 1520, 1530, 1528, 1529, 1523, 1544, 1542, 1543, 1545, + 1326, 1324, 1325, 1327, 1292, 1290, 1291, 1293, 1364, 1362, 1363, 1365, + 1208, 1207, 1538, 1537, 1456, 1455, 1622, 1621, 1485, 1483, 1484, 1486, + 1491, 1489, 1490, 1492, 1472, 1470, 1471, 1473, 1216, 1214, 1215, 1217, + 1504, 1502, 1503, 1505, 1618, 1616, 1617, 1619, 1127, 1125, 1126, 1128, + 1271, 1269, 1270, 1272, 1255, 1253, 1254, 1256, 1438, 1436, 1437, 1439, + 1340, 1338, 1339, 1341, 1376, 1374, 1375, 1377, 1385, 1383, 1384, 1386, + 1417, 1415, 1416, 1418, 1314, 1312, 1313, 1315, 1583, 1582, 1167, 1166, + 1607, 1605, 1606, 1608, 1809, 1808, 1805, 1804, 1807, 1806, 1813, 1812, + 41412, 41412, 41216, 41412, 17766, 17770, 17738, 17754, 17740, 17752, + 17751, 17681, 17744, 17753, 17741, 17676, 17769, 17774, 17748, 17761, + 17763, 17760, 17759, 17756, 17755, 17758, 17757, 17764, 17762, 17677, + 17747, 17683, 17765, 17768, 17771, 17675, 17684, 17685, 17686, 17687, + 17688, 17689, 17690, 17691, 17692, 17693, 17694, 17695, 17696, 17697, + 17698, 17699, 17700, 17701, 17702, 17703, 17704, 17705, 17706, 17707, + 17708, 17709, 17682, 17746, 17745, 17674, 17736, 17767, 17710, 17711, + 17712, 17713, 17714, 17715, 17716, 17717, 17718, 17719, 17720, 17721, + 17722, 17723, 17724, 17725, 17726, 17727, 17728, 17729, 17730, 17731, + 17732, 17733, 17734, 17735, 17680, 17776, 17743, 17773, 17679, 17742, + 19256, 19249, 19251, 19255, 19247, 19239, 19194, 19196, 19198, 19195, + 19197, 19190, 19192, 19191, 19193, 19248, 19240, 19242, 19244, 19241, + 19243, 19215, 19217, 19219, 19216, 19218, 19199, 19201, 19203, 19200, + 19202, 19230, 19232, 19234, 19231, 19233, 19205, 19207, 19209, 19206, + 19208, 19210, 19212, 19214, 19211, 19213, 19220, 19222, 19224, 19221, + 19223, 19235, 19237, 19236, 19225, 19227, 19229, 19226, 19228, 19238, + 19204, 19246, 19245, 19189, 19139, 19156, 19140, 19141, 19142, 19143, + 19177, 19158, 19147, 19152, 19151, 19150, 19154, 19148, 19149, 19153, + 19175, 19145, 19157, 19146, 19160, 19159, 19174, 19169, 19155, 19168, + 19138, 19176, 19144, 19183, 41412, 41412, 41412, 19184, 19185, 19163, + 19164, 19171, 19170, 41412, 41412, 19162, 19161, 19186, 19180, 19181, + 19187, 41412, 41412, 19166, 19188, 19179, 19178, 19182, 19167, 41412, + 41412, 19172, 19165, 19173, 41412, 41412, 41412, 17678, 17739, 17737, + 17750, 17775, 17749, 17772, 41412, 19253, 19250, 19254, 19252, 19259, + 19257, 19258, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 20948, 20950, 20949, 30114, 32045, 41412, 41412, 25137, + 25163, 25156, 25189, 25147, 25138, 25167, 25133, 25145, 25175, 25178, + 25172, 41412, 25161, 25188, 25192, 25171, 25186, 25193, 25200, 25203, + 25148, 25199, 25146, 25149, 25132, 25155, 25158, 25181, 25182, 25140, + 25197, 25162, 25143, 25179, 25141, 25198, 25157, 25165, 41412, 25190, + 25154, 25174, 25139, 25150, 25164, 25135, 25169, 25144, 25176, 25177, + 25134, 25160, 25136, 25187, 25180, 25194, 25168, 25170, 41412, 25142, + 25196, 41412, 25153, 25152, 25166, 25202, 25195, 25205, 25173, 25151, + 25183, 25191, 25159, 25184, 25185, 25201, 25204, 41412, 41412, 25215, + 25216, 25218, 25217, 25206, 25207, 25214, 25208, 25209, 25219, 25210, + 25211, 25212, 25213, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 25021, 25020, 25022, + 25009, 25010, 25011, 25012, 25013, 25014, 25015, 25017, 25016, 25019, + 25018, 25027, 25024, 25025, 25023, 25026, 25126, 25127, 25029, 25028, + 25030, 25129, 25128, 25032, 25033, 25034, 25031, 25035, 25038, 25037, + 25039, 25040, 25041, 25130, 25042, 25043, 25036, 25046, 25047, 25045, + 25044, 25048, 25049, 25050, 25051, 25052, 25053, 25056, 25057, 25058, + 25055, 25059, 25054, 25060, 25061, 25062, 25063, 25064, 25065, 25066, + 25067, 25068, 25069, 25071, 25070, 25072, 25073, 25075, 25076, 25077, + 25074, 25078, 25079, 25080, 25081, 25083, 25082, 25084, 25085, 25131, + 25086, 25087, 25089, 25090, 25091, 25088, 25092, 25093, 25094, 25095, + 25096, 25124, 25104, 25105, 25106, 25107, 25108, 25109, 25110, 25111, + 25112, 25113, 25114, 25115, 25116, 25117, 25118, 25119, 25120, 25121, + 25122, 25123, 25097, 25098, 25099, 25100, 25101, 25102, 25103, 25125, + 41412, 41412, 41412, 41412, 41412, 112, 113, 159, 41412, 41412, 41412, + 41412, 156, 151, 146, 126, 121, 139, 134, 114, 129, 154, 149, 144, 124, + 119, 140, 135, 115, 130, 157, 152, 147, 127, 122, 142, 137, 117, 132, + 158, 153, 148, 128, 123, 143, 138, 118, 133, 155, 150, 145, 125, 120, + 141, 136, 116, 131, 41412, 41412, 41412, 111, 107, 109, 110, 108, 103, + 104, 105, 106, 18323, 18320, 18324, 18310, 18305, 18311, 18314, 18306, + 18316, 18325, 18308, 18318, 18312, 18321, 18315, 18317, 18327, 18309, + 18319, 18313, 18322, 18326, 18307, 18328, 18340, 18349, 18339, 18335, + 18348, 18330, 18336, 18352, 18356, 18357, 18338, 18341, 18347, 18346, + 18354, 18355, 18337, 18344, 18350, 18345, 18334, 18353, 18342, 18329, + 18331, 18351, 18343, 18332, 18333, 18575, 18576, 18774, 18770, 18811, + 18776, 18506, 18580, 18773, 18769, 18512, 18511, 18572, 18554, 18570, + 18579, 18574, 18360, 18359, 18813, 18772, 18814, 18577, 18768, 18550, + 29540, 41412, 32397, 32400, 32395, 32398, 32369, 32399, 32367, 32370, + 32396, 32368, 32401, 32366, 2569, 41412, 41412, 41412, 18767, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 31590, 31591, 31602, 31571, + 31574, 31605, 31583, 31582, 31603, 31610, 31569, 31596, 31575, 31588, + 31589, 31598, 31587, 31568, 31572, 31579, 31577, 31599, 31576, 31567, + 31597, 31584, 31585, 31570, 31573, 31595, 31609, 31580, 31604, 31566, + 31592, 31611, 31593, 31594, 31586, 31608, 31607, 31581, 31600, 31601, + 31606, 31578, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 25459, 25461, 25457, 25458, 25466, 25465, 25468, 25476, + 25478, 25455, 25469, 25452, 25472, 25470, 25450, 25463, 25451, 25464, + 25475, 25471, 25453, 25473, 25474, 25454, 25456, 25460, 25462, 25467, + 25477, 41412, 41412, 41412, 6141, 6152, 6143, 6114, 6137, 6153, 6115, + 6142, 6159, 6157, 6117, 6158, 6144, 6132, 6127, 6128, 6126, 6112, 6135, + 6125, 6160, 6122, 6134, 6151, 6131, 6155, 6145, 6140, 6149, 6150, 6123, + 6136, 6147, 6148, 6129, 6130, 6124, 6156, 6113, 6133, 6138, 6154, 6118, + 6119, 6120, 6121, 6116, 6146, 6139, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 8703, 8701, 8699, 8698, 8695, 8694, 8697, 8696, 8702, 8700, 8693, 8692, + 8690, 8681, 8679, 8688, 8686, 8677, 8683, 8684, 8691, 8689, 8680, 8678, + 8687, 8685, 8676, 8682, 41412, 41412, 41412, 41412, 30395, 30389, 30375, + 30390, 30362, 30392, 30394, 30391, 30386, 30382, 30374, 30370, 30371, + 30372, 30364, 30396, 30385, 30378, 30376, 30366, 30363, 30387, 30380, + 30368, 30384, 30373, 30369, 30367, 30388, 30383, 30381, 30365, 30400, + 30398, 30399, 30397, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 30393, 30379, 30377, 18170, 18186, 18194, 18188, 18169, + 18179, 18173, 18172, 18181, 18190, 18195, 18191, 18189, 18177, 18193, + 18184, 18178, 18176, 18180, 18192, 18182, 18183, 18185, 18174, 18171, + 18187, 18175, 41412, 41412, 41412, 41412, 41412, 30467, 30466, 30463, + 30436, 30437, 30459, 30434, 30460, 30435, 30439, 30468, 30461, 30442, + 30443, 30450, 30444, 30462, 30447, 30449, 30470, 30433, 30446, 30445, + 30457, 30454, 30464, 30465, 30438, 30469, 30448, 30451, 30452, 30453, + 30456, 30441, 30458, 30455, 30440, 8508, 8506, 8504, 8505, 8507, 41412, + 41412, 41412, 41412, 41412, 38163, 38166, 38170, 38174, 38167, 38171, + 38189, 38185, 38172, 38182, 38184, 38173, 38179, 38175, 38190, 38168, + 38187, 38186, 38178, 38164, 38188, 38177, 38165, 38176, 38181, 38169, + 38183, 38191, 38192, 38180, 41412, 38193, 30476, 30518, 30519, 30499, + 30500, 30497, 30498, 30496, 30511, 30488, 30489, 30493, 30494, 30483, + 30486, 30487, 30492, 30515, 30480, 30512, 30501, 30502, 30505, 30506, + 30507, 30516, 30490, 30491, 30503, 30504, 30514, 30510, 30517, 30508, + 30509, 30513, 41412, 41412, 41412, 41412, 30477, 30478, 30479, 30495, + 30484, 30485, 30481, 30482, 30520, 30475, 30472, 30473, 30471, 30474, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 10727, 10726, 10722, 10723, 10724, 10725, 10733, 10732, + 10728, 10729, 10730, 10731, 10750, 10735, 10749, 10746, 10751, 10744, + 10741, 10737, 10742, 10740, 10743, 10748, 10747, 10717, 10745, 10716, + 10736, 10712, 10739, 10713, 10738, 10720, 10718, 10719, 10714, 10715, + 10734, 10721, 10767, 10766, 10762, 10763, 10764, 10765, 10773, 10772, + 10768, 10769, 10770, 10771, 10790, 10775, 10789, 10786, 10791, 10784, + 10781, 10777, 10782, 10780, 10783, 10788, 10787, 10757, 10785, 10756, + 10776, 10752, 10779, 10753, 10778, 10760, 10758, 10759, 10754, 10755, + 10774, 10761, 32992, 32998, 33009, 33006, 32996, 32995, 32994, 32973, + 33001, 32979, 33008, 33004, 33007, 33010, 32997, 33005, 32984, 33003, + 33000, 32978, 32983, 32985, 32982, 32977, 32971, 32968, 32990, 32999, + 32988, 32972, 32993, 33011, 32975, 32969, 32981, 33012, 32989, 32986, + 32987, 32970, 32966, 32991, 32967, 32976, 32965, 32974, 32980, 33002, + 30910, 30928, 30934, 30932, 30935, 30916, 30913, 30933, 30918, 30917, + 30914, 30912, 30930, 30929, 30920, 30915, 30923, 30919, 30924, 30925, + 30931, 30936, 30909, 30926, 30937, 30921, 30938, 30911, 30927, 30922, + 41412, 41412, 30945, 30947, 30944, 30943, 30940, 30939, 30942, 30941, + 30948, 30946, 41412, 41412, 41412, 41412, 41412, 41412, 30837, 30838, + 30839, 30840, 30865, 30858, 30844, 30841, 30847, 30857, 30856, 30871, + 30850, 30845, 30849, 30866, 30867, 30868, 30851, 30852, 30869, 30846, + 30862, 30861, 30855, 30843, 30854, 30842, 30853, 30859, 30872, 30870, + 30848, 30860, 30864, 30863, 41412, 41412, 41412, 41412, 30873, 30874, + 30875, 30876, 30901, 30894, 30880, 30877, 30883, 30893, 30892, 30907, + 30886, 30881, 30885, 30902, 30903, 30904, 30887, 30888, 30905, 30882, + 30898, 30897, 30891, 30879, 30890, 30878, 30889, 30895, 30908, 30906, + 30884, 30896, 30900, 30899, 41412, 41412, 41412, 41412, 16827, 16818, + 16807, 16806, 16809, 16798, 16808, 16805, 16804, 16819, 16795, 16794, + 16820, 16828, 16821, 16811, 16797, 16796, 16822, 16801, 16800, 16799, + 16829, 16823, 16824, 16803, 16802, 16813, 16812, 16815, 16814, 16830, + 16825, 16826, 16831, 16817, 16816, 16793, 16792, 16810, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 6173, 6222, 6189, 6185, 6187, + 6212, 6186, 6210, 6207, 6176, 6209, 6211, 6190, 6201, 6197, 6192, 6220, + 6184, 6175, 6193, 6196, 6198, 6223, 6214, 6172, 6178, 6179, 6181, 6215, + 6213, 6218, 6182, 6202, 6194, 6221, 6206, 6217, 6183, 6177, 6200, 6188, + 6219, 6204, 6216, 6205, 6203, 6191, 6180, 6174, 6208, 6199, 6195, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 6224, 39368, 39337, 39338, 39348, 39347, 39350, 39349, 39340, 39339, + 39357, 39365, 41412, 39356, 39355, 39341, 39342, 39358, 39366, 39344, + 39343, 39359, 39346, 39345, 39369, 39360, 39367, 39361, 41412, 39352, + 39351, 39354, 39353, 39370, 39362, 39363, 41412, 39371, 39364, 41412, + 39403, 39372, 39373, 39383, 39382, 39385, 39384, 39375, 39374, 39392, + 39400, 41412, 39391, 39390, 39376, 39377, 39393, 39401, 39379, 39378, + 39394, 39381, 39380, 39404, 39395, 39402, 39396, 41412, 39387, 39386, + 39389, 39388, 39405, 39397, 39398, 41412, 39406, 39399, 41412, 41412, + 41412, 37824, 37825, 37838, 37798, 37827, 37826, 37829, 37805, 37828, + 37821, 37820, 37839, 37795, 37801, 37794, 37800, 37808, 37807, 37842, + 37796, 37831, 37823, 37822, 37799, 37806, 37802, 37818, 37810, 37840, + 37817, 37816, 37815, 37812, 37811, 37833, 37832, 37843, 37841, 37835, + 37804, 37834, 37803, 37844, 37797, 37837, 37836, 37793, 37814, 37813, + 37830, 37809, 37819, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 24988, 24989, 24990, 24991, 24992, + 24993, 24994, 24995, 24996, 24927, 24928, 24929, 24930, 24931, 24940, + 24932, 24933, 24934, 24935, 24936, 24937, 24938, 24939, 24941, 24942, + 24943, 24944, 25008, 24945, 24946, 24947, 24948, 24949, 24950, 24951, + 24952, 24953, 24954, 24955, 24956, 24957, 24958, 24959, 24960, 24961, + 24962, 24963, 24964, 24965, 24966, 24967, 24968, 24969, 24970, 24971, + 24972, 24973, 24974, 24975, 24976, 24977, 24978, 24979, 24980, 24981, + 24982, 24983, 24984, 24985, 24986, 24987, 24668, 25004, 24997, 24669, + 24998, 24999, 25000, 25001, 24670, 25005, 25006, 25002, 25003, 25007, + 24674, 24675, 24676, 24677, 24678, 24679, 24680, 24681, 24671, 24672, + 24673, 24685, 24686, 24687, 24682, 24683, 24684, 24688, 24689, 24690, + 24691, 24692, 24693, 24696, 24697, 24698, 24699, 24700, 24701, 24702, + 24703, 24704, 24705, 24706, 24707, 24708, 24709, 24710, 24711, 24712, + 24713, 24714, 24715, 24716, 24717, 24718, 24719, 24720, 24721, 24722, + 24723, 24724, 24725, 24726, 24727, 24728, 24729, 24730, 24731, 24732, + 24733, 24734, 24735, 24736, 24737, 24738, 24739, 24740, 24741, 24742, + 24743, 24744, 24745, 24694, 24695, 24746, 24747, 24748, 24749, 24750, + 24751, 24752, 24753, 24754, 24755, 24756, 24757, 24758, 24759, 24760, + 24761, 24762, 24763, 24764, 24765, 24766, 24767, 24768, 24769, 24770, + 24771, 24772, 24773, 24774, 24775, 24776, 24777, 24778, 24810, 24811, + 24812, 24813, 24814, 24815, 24816, 24817, 24818, 24779, 24780, 24781, + 24782, 24783, 24784, 24785, 24786, 24787, 24788, 24789, 24790, 24791, + 24792, 24793, 24794, 24795, 24796, 24797, 24798, 24799, 24800, 24801, + 24802, 24803, 24804, 24805, 24806, 24807, 24808, 24809, 24825, 24826, + 24827, 24828, 24829, 24830, 24831, 24832, 24833, 24834, 24835, 24836, + 24837, 24838, 24839, 24840, 24841, 24842, 24843, 24844, 24819, 24820, + 24821, 24822, 24823, 24824, 24845, 24846, 24847, 24848, 24849, 24850, + 24851, 24852, 24887, 24888, 24889, 24890, 24891, 24892, 24893, 24894, + 24895, 24896, 24853, 24854, 24855, 24856, 24857, 24858, 24859, 24860, + 24861, 24862, 24863, 24864, 24865, 24866, 24867, 24868, 24869, 24870, + 24871, 24872, 24878, 24879, 24880, 24881, 24882, 24883, 24884, 24885, + 24886, 24873, 24874, 24875, 24876, 24877, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 24908, 24903, 24906, 24905, 24909, + 24904, 24902, 24907, 24901, 24897, 24900, 24899, 24898, 24915, 24913, + 24914, 24910, 24911, 24912, 24916, 24918, 24917, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 24919, 24920, 24921, + 24922, 24923, 24924, 24925, 24926, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 28048, + 28169, 28168, 28033, 28049, 28037, 41412, 28067, 28069, 28068, 28063, + 28062, 28060, 28061, 28122, 28055, 28079, 28119, 28043, 28083, 28044, + 28087, 28050, 28089, 28066, 28103, 28104, 28102, 28046, 28100, 28105, + 28106, 28147, 28148, 28111, 28047, 28056, 28162, 28144, 28145, 28118, + 28117, 28052, 28132, 28135, 28136, 28133, 28131, 28159, 41412, 28054, + 27974, 28021, 27868, 27952, 27981, 27865, 28023, 28124, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 10140, 10141, 10142, + 10143, 10144, 10134, 41412, 41412, 10135, 41412, 10090, 10091, 10092, + 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, 10102, + 10103, 10104, 10105, 10106, 10107, 10108, 10109, 10110, 10111, 10112, + 10113, 10114, 10115, 10116, 10117, 10118, 10119, 10120, 10121, 10122, + 10123, 10124, 10125, 10126, 10127, 10128, 10129, 10130, 10131, 10132, + 10133, 41412, 10138, 10139, 41412, 41412, 41412, 10136, 41412, 41412, + 10137, 20770, 20781, 20772, 20766, 20778, 20783, 20773, 20779, 20764, + 20777, 20780, 20767, 20785, 20782, 20774, 20771, 20784, 20775, 20768, + 20769, 20776, 20765, 41412, 20786, 20761, 20757, 20760, 20758, 20756, + 20762, 20763, 20759, 31218, 31229, 31220, 31214, 31226, 31231, 31221, + 31227, 31212, 31225, 31228, 31215, 31233, 31211, 31230, 31222, 31219, + 31232, 31223, 31216, 31217, 31224, 31213, 31210, 31234, 31241, 31236, + 31237, 31240, 31239, 31238, 31235, 28986, 29001, 28991, 29012, 29003, + 28997, 28993, 29009, 29014, 29004, 29010, 28995, 28989, 29008, 28990, + 29011, 28987, 28998, 28994, 29016, 28992, 29013, 29005, 29002, 29015, + 29006, 28999, 29000, 28988, 29007, 28996, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 29021, 29018, 29019, 29024, 29025, 29023, + 29020, 29017, 29022, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 19816, 19832, 19824, 19823, 19829, 19834, 19818, 19830, 19819, + 19828, 19831, 19821, 19836, 19833, 19825, 19817, 19835, 19826, 19822, + 41412, 19827, 19820, 41412, 41412, 41412, 41412, 41412, 19837, 19841, + 19840, 19839, 19838, 31614, 31633, 31629, 31616, 31617, 31625, 31626, + 31618, 31624, 31627, 31630, 31632, 31635, 31631, 31622, 31615, 31634, + 31620, 31619, 31628, 31621, 31623, 31640, 31639, 31636, 31641, 31637, + 31638, 41412, 41412, 41412, 31642, 25485, 25491, 25495, 25493, 25487, + 25503, 25496, 25504, 25497, 25481, 25498, 25489, 25499, 25501, 25484, + 25479, 25502, 25494, 25500, 25483, 25480, 25486, 25488, 25482, 25490, + 25492, 41412, 41412, 41412, 41412, 41412, 25505, 33150, 33151, 33152, + 33153, 33154, 33155, 33156, 33157, 33158, 33159, 33160, 33161, 33162, + 33163, 33164, 33165, 33166, 33167, 33168, 33143, 33144, 33145, 33146, + 33147, 33148, 33149, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 27580, 27581, 27582, 27583, 27579, 27578, 27554, 27555, 27576, + 27575, 27558, 27559, 27560, 27561, 27556, 27557, 27574, 27571, 27570, + 27562, 27563, 27564, 27572, 27577, 27565, 27566, 27567, 27568, 27569, + 27573, 27584, 27585, 27476, 27497, 27498, 27499, 27496, 27495, 27488, + 27492, 27491, 27481, 27482, 27494, 27490, 27486, 27485, 27483, 27477, + 27484, 27487, 27493, 27478, 27479, 27480, 27489, 41412, 41412, 41412, + 41412, 27464, 27469, 27501, 27500, 27550, 27542, 27536, 27513, 27507, + 27530, 27524, 27502, 27519, 27548, 27546, 27540, 27517, 27511, 27534, + 27528, 41412, 41412, 27551, 27543, 27537, 27514, 27508, 27531, 27525, + 27504, 27521, 27553, 27545, 27539, 27516, 27510, 27533, 27527, 27506, + 27523, 27549, 27547, 27541, 27518, 27512, 27535, 27529, 27503, 27520, + 27552, 27544, 27538, 27515, 27509, 27532, 27526, 27505, 27522, 27468, + 27474, 27473, 27467, 27466, 27471, 27470, 27465, 27475, 27472, 21831, + 21853, 21855, 21851, 41412, 21852, 21854, 41412, 41412, 41412, 41412, + 41412, 21856, 21847, 21850, 21849, 21797, 21795, 21819, 21818, 41412, + 21817, 21816, 21825, 41412, 21805, 21801, 21800, 21808, 21807, 21804, + 21803, 21802, 21810, 21809, 21806, 21821, 21820, 21815, 21814, 21827, + 21829, 21828, 21826, 21823, 21811, 21812, 21813, 21830, 21824, 21796, + 21798, 21799, 21822, 41412, 41412, 21845, 21846, 21848, 41412, 41412, + 41412, 41412, 21857, 21794, 21793, 21792, 21791, 21833, 21832, 21834, + 21835, 21858, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 21839, + 21844, 21837, 21836, 21843, 21841, 21840, 21838, 21842, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 30585, 30581, 30586, 30591, 30582, + 30589, 30575, 30583, 30587, 30579, 30574, 30570, 30588, 30571, 30573, + 30572, 30590, 30563, 30564, 30566, 30569, 30567, 30568, 30578, 30580, + 30565, 30584, 30577, 30576, 30593, 30592, 30594, 30406, 30424, 30405, + 30415, 30427, 30428, 30417, 30421, 30419, 30412, 30416, 30408, 30423, + 30407, 30429, 30418, 30420, 30401, 30402, 30425, 30404, 30426, 30403, + 30411, 30413, 30409, 30422, 30410, 30414, 30432, 30431, 30430, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 25786, 25790, 25789, 25794, 25793, 25791, 25815, 25818, 25834, + 25798, 25797, 25796, 25795, 25816, 25808, 25814, 25800, 25810, 25799, + 25812, 25792, 25807, 25821, 25817, 25804, 25788, 25787, 25820, 25819, + 25805, 25802, 25811, 25801, 25813, 25806, 25803, 25809, 25836, 25835, + 41412, 41412, 41412, 41412, 25822, 25826, 25825, 25824, 25823, 25833, + 25831, 25829, 25828, 25827, 25832, 25830, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 2587, 2588, 2594, 2590, 2593, 2589, + 2591, 2592, 2630, 2631, 2620, 2621, 2622, 2623, 2618, 2619, 2635, 2608, + 2607, 2606, 2597, 2595, 2596, 2632, 2634, 2617, 2615, 2627, 2626, 2616, + 2638, 2633, 2625, 2624, 2602, 2601, 2600, 2605, 2604, 2603, 2637, 2598, + 2613, 2614, 2640, 2639, 2636, 2612, 2629, 2610, 2628, 2609, 2611, 2599, + 41412, 41412, 41412, 2641, 37706, 34058, 22832, 22827, 22833, 22828, + 20912, 20923, 20914, 20908, 20920, 20925, 20915, 20921, 20906, 20919, + 20922, 20909, 20927, 20924, 20916, 20913, 20926, 20917, 20910, 20911, + 20918, 20907, 41412, 41412, 20932, 20929, 20930, 20935, 20931, 20928, + 20933, 20934, 20881, 20895, 20886, 20882, 20892, 20885, 20887, 20893, + 20879, 20891, 20894, 20883, 20884, 20896, 20888, 20897, 20889, 20890, + 20880, 41412, 41412, 41412, 41412, 41412, 20902, 20899, 20900, 20905, + 20901, 20898, 20903, 20904, 31875, 31889, 31880, 31876, 31886, 31879, + 31881, 31887, 31885, 31888, 31877, 31878, 31890, 31882, 31892, 31883, + 31884, 31891, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 31900, + 31901, 31873, 31874, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 31897, 31894, 31895, 31899, 31896, + 31893, 31898, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 30595, 30637, 30638, 30627, 30663, 30656, 30630, 30631, + 30665, 30608, 30648, 30596, 30641, 30610, 30650, 30598, 30642, 30609, + 30649, 30597, 30626, 30662, 30616, 30655, 30605, 30645, 30599, 30643, + 30632, 30666, 30611, 30651, 30600, 30621, 30624, 30612, 30601, 30639, + 30619, 30658, 30617, 30657, 30620, 30659, 30647, 30618, 30640, 30625, + 30633, 30628, 30623, 30661, 30613, 30652, 30629, 30664, 30634, 30667, + 30614, 30653, 30602, 30606, 30603, 30607, 30646, 30622, 30660, 30615, + 30654, 30604, 30644, 30635, 30636, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 30254, 30257, 30280, 30255, 30269, 30265, 30271, 30281, 30256, 30259, + 30302, 30282, 30283, 30272, 30273, 30284, 30303, 30304, 30285, 30286, + 30258, 30299, 30274, 30275, 30260, 30262, 30266, 30294, 30296, 30290, + 30292, 30295, 30287, 30261, 30288, 30297, 30267, 30268, 30276, 30263, + 30277, 30270, 30298, 30301, 30291, 30293, 30289, 30278, 30279, 30264, + 30300, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 30305, 30308, 30331, 30306, 30320, 30316, + 30322, 30332, 30307, 30310, 30353, 30333, 30334, 30323, 30324, 30335, + 30354, 30355, 30336, 30337, 30309, 30350, 30325, 30326, 30311, 30313, + 30317, 30345, 30347, 30341, 30343, 30346, 30338, 30312, 30339, 30348, + 30318, 30319, 30327, 30314, 30328, 30321, 30349, 30352, 30342, 30344, + 30340, 30329, 30330, 30315, 30351, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 30358, 30357, 30361, 30356, 30359, 30360, 19769, 19756, + 19764, 19748, 19747, 19761, 19757, 19760, 19745, 19758, 19742, 19741, + 19750, 19749, 19768, 19755, 19754, 19746, 19759, 19762, 19763, 19753, + 19766, 19743, 19767, 19744, 19751, 19752, 19765, 19776, 19778, 19780, + 19777, 19779, 19771, 19770, 19775, 19772, 19774, 19773, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 19787, 19789, 19786, 19785, + 19782, 19781, 19784, 19783, 19790, 19788, 41412, 41412, 41412, 41412, + 41412, 41412, 17854, 17856, 17853, 17852, 17849, 17848, 17851, 17850, + 17857, 17855, 17840, 17841, 17842, 17839, 17843, 17837, 17814, 17798, + 17806, 17804, 17797, 17803, 17809, 17811, 17805, 17801, 17799, 17812, + 17813, 17810, 17808, 17795, 17800, 17796, 17807, 17802, 17793, 17794, + 41412, 41412, 41412, 17838, 17792, 17790, 17789, 17791, 17845, 17844, + 17836, 17820, 17828, 17826, 17819, 17825, 17831, 17833, 17827, 17823, + 17821, 17834, 17835, 17832, 17830, 17817, 17822, 17818, 17829, 17824, + 17815, 17816, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 17846, 17847, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 32454, 32452, 32451, 32448, 32447, 32450, 32449, 32455, 32453, 32446, + 32445, 32443, 32434, 32432, 32441, 32439, 32430, 32436, 32437, 32444, + 32442, 32433, 32431, 32440, 32438, 32429, 32435, 32426, 32427, 32425, + 32428, 41412, 39869, 39903, 39883, 39882, 39888, 39887, 39865, 39864, + 39863, 39874, 39895, 39868, 39899, 39902, 39901, 39898, 39906, 39885, + 39884, 39886, 39867, 39889, 39900, 39870, 39894, 39905, 39890, 39891, + 39878, 39876, 39875, 39877, 39879, 39866, 39881, 39904, 39892, 39893, + 39872, 39873, 39896, 39871, 41412, 39861, 39860, 39862, 41412, 41412, + 39880, 39897, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 1201, 1497, 1332, + 2388, 1540, 1604, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 1065, 1654, 1652, 1650, 1909, 1910, 1911, 1913, 1895, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 1083, 2389, 1066, 2395, 2396, 2393, 30525, 30533, 30547, 30534, + 30538, 30544, 30535, 30550, 30539, 30545, 30543, 30546, 30537, 30552, + 30548, 30527, 30528, 30540, 30526, 30524, 30551, 30541, 30529, 30530, + 30536, 30542, 30549, 30531, 30532, 30559, 30557, 30554, 30562, 30561, + 30558, 30556, 30555, 30560, 30523, 30553, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 34118, 34132, 34120, 34129, 34136, 34124, + 34130, 34128, 34131, 34121, 34138, 34134, 34125, 34119, 34137, 34126, + 34123, 34127, 34135, 34133, 34122, 34117, 34112, 34110, 34113, 34111, + 34116, 34115, 34107, 34106, 34108, 34114, 34109, 34139, 34142, 34141, + 34140, 34145, 34146, 34143, 34147, 34144, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 30672, 30684, + 30682, 30687, 30676, 30681, 30680, 30683, 30674, 30689, 30685, 30677, + 30688, 30678, 30673, 30679, 30686, 30675, 30671, 30670, 30669, 30668, + 30693, 30690, 30691, 30692, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 6596, 6590, 6604, 6598, 6593, 6601, 6607, 6589, 6599, 6602, + 6600, 6603, 6594, 6609, 6605, 6591, 6597, 6608, 6595, 6592, 6606, 6614, + 6611, 6612, 6616, 6613, 6610, 6615, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 16854, 16865, 16856, 16850, 16862, + 16867, 16857, 16863, 16848, 16861, 16864, 16851, 16869, 16866, 16858, + 16855, 16868, 16859, 16852, 16853, 16860, 16849, 16870, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 4737, 4742, 4740, 4739, + 4741, 4664, 4665, 4683, 4684, 4681, 4682, 4676, 4677, 4678, 4679, 4710, + 4666, 4657, 4667, 4703, 4702, 4699, 4698, 4687, 4697, 4696, 4701, 4700, + 4689, 4673, 4672, 4669, 4668, 4688, 4675, 4674, 4671, 4670, 4690, 4705, + 4704, 4695, 4694, 4707, 4709, 4708, 4686, 4680, 4691, 4692, 4693, 4706, + 4685, 4658, 4663, 4662, 4747, 4746, 4756, 4757, 4750, 4751, 4752, 4753, + 4754, 4755, 4758, 4748, 4743, 4749, 4759, 4761, 4760, 4735, 4734, 4733, + 4736, 4732, 41412, 41412, 41412, 41412, 4728, 4726, 4723, 4714, 4716, + 4721, 4719, 4711, 4717, 4727, 4725, 4724, 4713, 4715, 4722, 4720, 4712, + 4718, 4729, 4730, 4768, 4770, 4767, 4766, 4763, 4762, 4765, 4764, 4771, + 4769, 4738, 4660, 4661, 4744, 4745, 4659, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 4731, 21141, 21143, 21145, 21101, + 21102, 21111, 21112, 21109, 21110, 21139, 21103, 21140, 21104, 21129, + 21128, 21125, 21124, 21113, 21123, 21122, 21127, 21126, 21115, 21106, + 21105, 21098, 21096, 21097, 21132, 21114, 21108, 21107, 21100, 21099, + 21116, 21131, 21130, 21121, 21120, 21136, 21138, 21133, 21135, 21137, + 21117, 21118, 21119, 21134, 21151, 21156, 21157, 21154, 21155, 21158, + 21152, 21159, 21153, 21144, 21142, 21162, 21163, 21160, 21146, 21147, + 21149, 21148, 21150, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 21161, 41412, 41412, 34170, 34171, 34160, 34161, + 34162, 34163, 34156, 34157, 34167, 34159, 34172, 34168, 34173, 34169, + 34164, 34166, 34165, 34158, 34174, 34153, 34175, 34177, 34176, 34154, + 34155, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 34184, 34186, + 34183, 34182, 34179, 34178, 34181, 34180, 34187, 34185, 41412, 41412, + 41412, 41412, 41412, 41412, 6276, 6278, 6277, 6272, 6274, 6275, 6273, + 6261, 6260, 6257, 6256, 6242, 6255, 6254, 6259, 6258, 6244, 6247, 6246, + 6239, 6238, 6243, 6249, 6248, 6241, 6240, 6245, 6265, 6264, 6253, 6252, + 6267, 6250, 6251, 6268, 6263, 6271, 6269, 6266, 6280, 6288, 6289, 6284, + 6285, 6286, 6282, 6290, 6283, 6291, 6308, 6307, 6292, 6306, 41412, 6301, + 6303, 6300, 6299, 6296, 6295, 6298, 6297, 6304, 6302, 6279, 6294, 6293, + 6305, 6262, 6281, 6287, 6270, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 25547, 25549, 25551, 25548, 25550, 25539, 25538, 25535, + 25534, 25533, 25532, 25537, 25536, 25518, 25527, 25526, 25521, 25520, + 25517, 25529, 25528, 25523, 25522, 25519, 25541, 25540, 25531, 25530, + 25544, 25525, 25543, 25546, 25545, 25542, 25524, 25554, 25555, 25553, + 25552, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 32928, 32931, 32935, 32874, 32875, 32893, 32894, 32891, 32892, 32886, + 32887, 32888, 32889, 32920, 32876, 32921, 32877, 32913, 32912, 32909, + 32908, 32897, 32907, 32906, 32911, 32910, 32899, 32883, 32882, 32879, + 32878, 32898, 32885, 32884, 32881, 32880, 32900, 32915, 32914, 32905, + 32904, 32917, 32919, 32918, 32896, 32895, 32890, 32901, 32902, 32903, + 32916, 32950, 32957, 32958, 32944, 32945, 32953, 32954, 32955, 32956, + 32959, 32951, 32940, 32952, 32934, 32930, 32932, 32933, 32962, 32860, + 32859, 32960, 32925, 32922, 32929, 32937, 32871, 32936, 32943, 32926, + 32867, 32869, 32866, 32865, 32862, 32861, 32864, 32863, 32870, 32868, + 32872, 32927, 32873, 32961, 32923, 32924, 41412, 33872, 33870, 33869, + 33866, 33865, 33868, 33867, 33873, 33871, 33884, 33883, 33882, 33878, + 33877, 33881, 33880, 33876, 33879, 33874, 33875, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 22537, 22538, + 22564, 22566, 22563, 22539, 22565, 22540, 22554, 22553, 22529, 22527, + 22528, 22547, 22552, 22551, 22536, 22535, 41412, 22549, 22542, 22541, + 22532, 22531, 22548, 22544, 22543, 22534, 22530, 22533, 22550, 22556, + 22555, 22526, 22524, 22525, 22558, 22562, 22560, 22546, 22561, 22523, + 22557, 22545, 22574, 22577, 22578, 22581, 22579, 22575, 22580, 22576, + 22571, 22570, 22569, 22567, 22521, 22520, 22582, 22572, 22519, 22583, + 22568, 22559, 22522, 22573, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 28461, 28463, 28464, 28462, + 28452, 28451, 28450, 41412, 28449, 41412, 28448, 28447, 28440, 28439, + 41412, 28434, 28442, 28441, 28430, 28428, 28429, 28433, 28444, 28443, + 28432, 28431, 28435, 28454, 28453, 28446, 41412, 28445, 28457, 28460, + 28438, 28456, 28459, 28458, 28455, 28437, 28436, 28465, 41412, 41412, + 41412, 41412, 41412, 41412, 22598, 22599, 22610, 22611, 22608, 22609, + 22629, 22600, 22630, 22601, 22619, 22618, 22589, 22587, 22588, 22612, + 22617, 22616, 22597, 22596, 22595, 22614, 22605, 22604, 22592, 22590, + 22602, 22591, 22613, 22607, 22606, 22594, 22593, 22615, 22621, 22620, + 22586, 22584, 22585, 22626, 22628, 22603, 22625, 22627, 22622, 22623, + 22624, 22633, 22634, 22639, 22640, 22637, 22638, 22641, 22635, 22642, + 22636, 22631, 22632, 41412, 41412, 41412, 41412, 41412, 22649, 22651, + 22648, 22647, 22644, 22643, 22646, 22645, 22652, 22650, 41412, 41412, + 41412, 41412, 41412, 41412, 18252, 18253, 18256, 18259, 41412, 18209, + 18210, 18223, 18224, 18221, 18222, 18204, 18206, 41412, 41412, 18247, + 18211, 41412, 41412, 18246, 18212, 18243, 18242, 18239, 18238, 18227, + 18237, 18236, 18241, 18240, 18229, 18218, 18217, 18214, 18213, 18228, + 18220, 18219, 18216, 18215, 18230, 41412, 18245, 18244, 18235, 18234, + 18249, 18251, 18250, 41412, 18226, 18225, 41412, 18208, 18231, 18232, + 18233, 18248, 41412, 8183, 18254, 18255, 18261, 18270, 18271, 18264, + 18265, 18266, 18267, 41412, 41412, 18273, 18262, 41412, 41412, 18272, + 18263, 18258, 41412, 41412, 18274, 41412, 41412, 41412, 41412, 41412, + 41412, 18260, 41412, 41412, 41412, 41412, 41412, 18257, 18203, 18202, + 18205, 18207, 18268, 18269, 41412, 41412, 8372, 8373, 8371, 8370, 8369, + 8368, 8367, 41412, 41412, 41412, 8378, 8375, 8376, 8374, 8377, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 38042, 38043, 38066, 38067, 38064, 38065, 38059, 38060, 38061, 38062, + 41412, 38088, 41412, 41412, 38044, 41412, 38087, 38045, 38084, 38083, + 38080, 38079, 38068, 38078, 38077, 38082, 38081, 38070, 38056, 38055, + 38047, 38046, 38069, 38058, 38057, 38049, 38048, 38071, 38086, 38085, + 38076, 38075, 38090, 38091, 38054, 38052, 38063, 38072, 38073, 38074, + 38089, 38051, 38053, 38050, 41412, 38093, 38104, 38113, 38114, 38107, + 38108, 38109, 38110, 38111, 38112, 41412, 38116, 41412, 41412, 38105, + 41412, 38115, 38106, 38037, 38098, 41412, 38094, 38101, 38100, 38095, + 38038, 38092, 38041, 38099, 38040, 38039, 41412, 38096, 38097, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 38103, 38102, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 29384, 29385, + 29398, 29399, 29396, 29397, 29380, 29381, 29382, 29383, 29424, 29386, + 29425, 29387, 29412, 29411, 29408, 29407, 29373, 29372, 29406, 29405, + 29410, 29409, 29375, 29374, 29393, 29392, 29389, 29388, 29377, 29395, + 29394, 29391, 29390, 29378, 29376, 29418, 29417, 29404, 29403, 29416, + 29415, 29423, 29420, 29419, 29414, 29413, 29422, 29400, 29401, 29402, + 29421, 29438, 29447, 29448, 29441, 29442, 29443, 29444, 29445, 29446, + 29449, 29439, 29450, 29440, 29433, 29426, 29429, 29434, 29427, 29428, + 29431, 29454, 29435, 29360, 29358, 29453, 29371, 29451, 29367, 29369, + 29366, 29365, 29362, 29361, 29364, 29363, 29370, 29368, 29359, 29437, + 41412, 29452, 29436, 29379, 29430, 29432, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 37708, 37709, 37710, 37728, + 37729, 37726, 37727, 37721, 37722, 37723, 37724, 37754, 37711, 37755, + 37712, 37746, 37745, 37742, 37741, 37730, 37740, 37739, 37744, 37743, + 37732, 37718, 37717, 37714, 37713, 37731, 37720, 37719, 37716, 37715, + 37733, 37748, 37747, 37738, 37737, 37751, 37753, 37752, 37750, 37725, + 37734, 37735, 37736, 37749, 37764, 37773, 37774, 37767, 37768, 37769, + 37770, 37771, 37772, 37775, 37762, 37765, 37776, 37763, 37766, 37756, + 37759, 37761, 37760, 37757, 37758, 37787, 37707, 37788, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 37783, 37785, 37782, 37781, + 37778, 37777, 37780, 37779, 37786, 37784, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 33052, 33054, 33075, 33076, 33073, 33074, 33068, 33069, + 33070, 33071, 33101, 33055, 33102, 33056, 33093, 33092, 33089, 33088, + 33077, 33087, 33086, 33091, 33090, 33079, 33062, 33061, 33065, 33064, + 33078, 33063, 33058, 33067, 33066, 33080, 33095, 33094, 33085, 33084, + 33098, 33100, 33099, 33097, 33072, 33081, 33082, 33083, 33096, 33130, + 33137, 33138, 33135, 33136, 33133, 33134, 41412, 41412, 33139, 33131, + 33140, 33132, 33123, 33125, 33127, 33126, 33124, 33122, 33142, 33141, + 33121, 33120, 33103, 33104, 33105, 33051, 33118, 33117, 33115, 33113, + 33114, 33106, 33107, 33116, 33119, 33111, 33112, 33110, 33109, 33108, + 33057, 33059, 33060, 33053, 33128, 33129, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 27815, 27816, 27834, 27835, 27832, 27833, 27827, 27828, 27829, 27830, + 27861, 27817, 27862, 27818, 27854, 27853, 27850, 27849, 27838, 27848, + 27847, 27852, 27851, 27840, 27824, 27823, 27820, 27819, 27839, 27826, + 27825, 27822, 27821, 27841, 27856, 27855, 27846, 27845, 27858, 27860, + 27859, 27837, 27831, 27842, 27843, 27844, 27857, 27836, 27790, 27799, + 27800, 27793, 27794, 27795, 27796, 27797, 27798, 27801, 27791, 27802, + 27792, 27786, 27789, 27788, 27785, 27804, 27803, 27863, 27787, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 27811, 27813, 27810, 27809, 27806, 27805, 27808, 27807, 27814, 27812, + 41412, 41412, 41412, 41412, 41412, 41412, 28344, 28339, 28184, 28345, + 28343, 28341, 28340, 28201, 28202, 28335, 28337, 28336, 28346, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 35581, 35583, + 35598, 35599, 35596, 35597, 35623, 35584, 35624, 35585, 35613, 35612, + 35609, 35608, 35600, 35607, 35606, 35611, 35610, 35602, 35593, 35592, + 35587, 35586, 35601, 35595, 35594, 35589, 35588, 35603, 35615, 35614, + 35605, 35604, 35620, 35622, 35591, 35619, 35621, 35616, 35617, 35618, + 35590, 35626, 35628, 35629, 35634, 35635, 35632, 35633, 35636, 35630, + 35637, 35631, 35627, 35625, 35582, 35580, 41412, 41412, 41412, 41412, + 41412, 41412, 35644, 35646, 35643, 35642, 35639, 35638, 35641, 35640, + 35647, 35645, 41412, 41412, 41412, 41412, 41412, 41412, 28953, 28955, + 28952, 28951, 28948, 28947, 28950, 28949, 28956, 28954, 28903, 28905, + 28902, 28901, 28898, 28897, 28900, 28899, 28906, 28904, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 191, 190, 178, 181, 175, 167, + 193, 192, 183, 195, 189, 184, 174, 196, 177, 197, 180, 194, 164, 171, + 170, 187, 166, 186, 182, 188, 165, 41412, 41412, 162, 163, 161, 203, 204, + 210, 211, 208, 209, 212, 207, 213, 205, 206, 200, 41412, 41412, 41412, + 41412, 222, 224, 221, 220, 217, 216, 219, 218, 225, 223, 215, 214, 198, + 199, 201, 202, 185, 173, 172, 169, 168, 179, 176, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 11159, 11160, 11175, 11176, 11173, 11174, 11201, 11161, + 11202, 11162, 11193, 11192, 11189, 11188, 11177, 11187, 11186, 11191, + 11190, 11179, 11170, 11169, 11164, 11163, 11178, 11172, 11171, 11166, + 11165, 11180, 11195, 11194, 11185, 11184, 11198, 11200, 11168, 11197, + 11199, 11181, 11182, 11183, 11196, 11167, 11205, 11210, 11211, 11208, + 11209, 11203, 11204, 11212, 11206, 11213, 11207, 11216, 11218, 11217, + 11215, 11214, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 39508, 39497, 39526, 39516, 39518, 39519, 39525, 39515, + 39501, 39510, 39498, 39528, 39524, 39503, 39517, 39514, 39502, 39511, + 39520, 39509, 39527, 39500, 39499, 39522, 39523, 39506, 39505, 39504, + 39507, 39512, 39513, 39521, 39540, 39529, 39558, 39548, 39550, 39551, + 39557, 39547, 39533, 39542, 39530, 39560, 39556, 39535, 39549, 39546, + 39534, 39543, 39552, 39541, 39559, 39532, 39531, 39554, 39555, 39538, + 39537, 39536, 39539, 39544, 39545, 39553, 39567, 39569, 39566, 39565, + 39562, 39561, 39564, 39563, 39570, 39568, 39579, 39578, 39577, 39573, + 39572, 39576, 39575, 39571, 39574, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 39580, 11075, 11076, + 11083, 11084, 11081, 11082, 11110, 41412, 41412, 11111, 41412, 41412, + 11101, 11100, 11099, 11098, 11087, 11097, 11096, 11105, 41412, 11089, + 11071, 41412, 11078, 11077, 11088, 11072, 11070, 11080, 11079, 11090, + 11103, 11102, 11095, 11094, 11106, 11074, 11073, 11107, 11086, 11108, + 11091, 11092, 11093, 11104, 11085, 11109, 11116, 11120, 11121, 11118, + 11119, 11122, 41412, 11117, 11123, 41412, 41412, 11115, 11113, 11112, + 11124, 11129, 11126, 11130, 11125, 11114, 11059, 11127, 11128, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 11066, 11068, + 11065, 11064, 11061, 11060, 11063, 11062, 11069, 11067, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 29075, 29076, + 29091, 29092, 29089, 29090, 29072, 29073, 41412, 41412, 29117, 29077, + 29118, 29078, 29111, 29110, 29107, 29106, 29095, 29105, 29104, 29109, + 29108, 29097, 29086, 29085, 29080, 29079, 29096, 29088, 29087, 29082, + 29081, 29098, 29113, 29112, 29103, 29102, 29115, 29116, 29084, 29094, + 29074, 29099, 29100, 29101, 29114, 29093, 29083, 29127, 29132, 29133, + 29130, 29131, 29125, 29126, 41412, 41412, 29134, 29128, 29135, 29129, + 29121, 29123, 29122, 29120, 29119, 29136, 29124, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41193, 41214, 41211, 41210, 41213, 41209, + 41208, 41206, 41207, 41212, 41205, 41161, 41160, 41180, 41179, 41162, + 41178, 41177, 41187, 41164, 41172, 41171, 41154, 41153, 41163, 41174, + 41173, 41158, 41157, 41165, 41182, 41181, 41176, 41175, 41189, 41170, + 41169, 41156, 41155, 41183, 41184, 41185, 41192, 41190, 41188, 41191, + 41166, 41167, 41168, 41186, 41159, 41152, 41202, 41199, 41200, 41201, + 41198, 41203, 41149, 41148, 41146, 41145, 41147, 41151, 41144, 41197, + 41195, 41194, 41196, 41150, 41143, 41204, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 34276, 34297, 34295, 34294, 34296, 34292, + 34293, 34290, 34291, 34289, 34288, 34298, 34243, 34242, 34262, 34261, + 34244, 34260, 34259, 34264, 34263, 34246, 34254, 34253, 34237, 34236, + 34245, 34256, 34255, 34240, 34238, 34247, 34266, 34265, 34258, 34257, + 34272, 34252, 34251, 34239, 34267, 34268, 34269, 34275, 34273, 34271, + 34274, 34248, 34249, 34250, 34270, 34241, 34281, 34283, 34220, 34219, + 34217, 34218, 34228, 34229, 34224, 34227, 34223, 34226, 34231, 34232, + 34230, 34222, 34221, 34225, 34284, 34282, 34299, 34285, 34280, 34279, + 34278, 34277, 34235, 34234, 34233, 34286, 34287, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 5719, 5720, 5717, 5718, 5715, 5716, 5725, 5726, 5723, 5724, 5721, 5722, + 5888, 5889, 5890, 5887, 31432, 31430, 31439, 31440, 31436, 31444, 31443, + 31425, 31438, 31437, 31429, 31442, 31435, 31428, 31434, 31433, 31426, + 31431, 31441, 31420, 31427, 31445, 31446, 31421, 31447, 31423, 31424, + 31422, 31416, 31413, 31417, 31415, 31411, 31414, 31418, 31412, 31419, + 31453, 31452, 31463, 31454, 31455, 31464, 31460, 31459, 31461, 31462, + 31456, 31410, 31457, 31458, 31449, 31448, 31408, 31450, 31451, 31409, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 10801, 10802, 10891, + 10892, 10893, 10894, 10901, 10900, 10902, 10906, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 32942, 32941, 32947, 32946, 32948, 32949, 32938, + 32939, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 34883, + 34902, 34909, 34906, 34896, 34893, 34888, 34910, 34878, 34895, 34905, + 34885, 34882, 34891, 34908, 34886, 34904, 34892, 34897, 34903, 34907, + 34880, 34879, 34884, 34900, 34894, 34890, 34889, 34898, 34881, 34899, + 34901, 34887, 34911, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 34918, 34920, 34917, + 34916, 34913, 34912, 34915, 34914, 34921, 34919, 41412, 41412, 41412, + 41412, 41412, 41412, 3761, 3762, 3775, 3776, 3773, 3774, 3757, 3758, + 3759, 41412, 3801, 3763, 3802, 3764, 3793, 3792, 3789, 3788, 3777, 3787, + 3786, 3791, 3790, 3779, 3770, 3769, 3766, 3765, 3778, 3772, 3771, 3768, + 3767, 3780, 3795, 3794, 3785, 3784, 3798, 3800, 3799, 3797, 3760, 3781, + 3782, 3783, 3796, 3829, 3834, 3835, 3832, 3833, 3826, 3827, 3828, 41412, + 3836, 3830, 3837, 3831, 3821, 3823, 3825, 3824, 3822, 3839, 3838, 3850, + 3851, 3852, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 3846, 3848, 3845, 3844, 3841, 3840, 3843, 3842, 3849, 3847, + 3820, 3818, 3815, 3806, 3808, 3813, 3811, 3803, 3809, 3819, 3817, 3816, + 3805, 3807, 3814, 3812, 3804, 3810, 3853, 41412, 41412, 41412, 25911, + 25912, 25857, 25856, 25866, 25851, 25855, 25854, 25868, 25852, 25848, + 25847, 25850, 25853, 25859, 25858, 25865, 25870, 25846, 25845, 25849, + 25872, 25862, 25863, 25864, 25873, 25871, 25869, 25860, 25861, 25867, + 25874, 41412, 41412, 25889, 25888, 25897, 25883, 25887, 25886, 25899, + 25884, 25880, 25879, 25882, 25885, 25891, 25890, 25896, 25901, 25878, + 25877, 25881, 25903, 25894, 25895, 41412, 25904, 25902, 25900, 25892, + 25893, 25898, 25905, 25906, 25908, 25910, 25907, 25909, 25876, 25875, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 25923, 25924, 25933, 25934, 25931, 25932, 25960, + 41412, 25925, 25961, 41412, 25926, 25939, 25938, 25952, 25951, 25940, + 25950, 25949, 25917, 25916, 25942, 25919, 25918, 25928, 25927, 25941, + 25922, 25920, 25930, 25929, 25943, 25954, 25953, 25948, 25947, 25956, + 25959, 25957, 25936, 25958, 25944, 25945, 25946, 25955, 25935, 25937, + 25915, 25921, 25970, 25975, 25976, 25973, 25974, 25969, 41412, 41412, + 41412, 25977, 41412, 25971, 25978, 41412, 25972, 25968, 25967, 25966, + 25964, 25965, 25979, 25963, 25962, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 25986, 25988, 25985, 25984, 25981, 25980, 25983, + 25982, 25989, 25987, 41412, 41412, 41412, 41412, 41412, 41412, 18927, + 18928, 18941, 18942, 18939, 18940, 41412, 18958, 18929, 41412, 18957, + 18930, 18964, 18963, 18946, 18945, 18960, 18954, 18953, 18938, 18937, + 18944, 18950, 18949, 18934, 18933, 18926, 18948, 18947, 18936, 18935, + 18943, 18952, 18951, 18932, 18931, 18925, 18956, 18955, 18959, 18961, + 18962, 18967, 18972, 18973, 18970, 18971, 41412, 18975, 18968, 41412, + 18974, 18969, 18966, 18965, 18976, 18987, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 18983, 18985, 18982, 18981, 18978, 18977, 18980, + 18979, 18986, 18984, 41412, 41412, 41412, 41412, 41412, 41412, 37877, + 37875, 37882, 37880, 37845, 37846, 37873, 37874, 37863, 37864, 37879, + 37859, 37862, 37847, 37850, 37851, 37860, 37861, 37848, 37849, 37852, + 37865, 37866, 37869, 37870, 37855, 37871, 37872, 37867, 37868, 37854, + 37885, 37856, 37878, 37883, 37853, 37881, 37876, 37884, 37857, 37858, + 37886, 37887, 37888, 41412, 41412, 41412, 41412, 37895, 37897, 37894, + 37893, 37890, 37889, 37892, 37891, 37898, 37896, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 25609, 25607, 25601, 25612, 25604, 25611, 25615, + 25606, 25603, 25605, 25608, 25602, 25617, 25613, 25610, 25616, 25614, + 25618, 25624, 25621, 25623, 25620, 25622, 25619, 25600, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 21676, 21680, 21678, 21679, 21617, + 21618, 21637, 21638, 21631, 21632, 21633, 21634, 21635, 21636, 21662, + 21619, 21663, 41412, 21653, 21652, 21651, 21650, 21639, 21649, 21648, + 21622, 21621, 21641, 21628, 21627, 21624, 21623, 21640, 21630, 21629, + 21626, 21625, 21642, 21655, 21654, 21647, 21646, 21658, 21661, 21659, + 21657, 21660, 21643, 21644, 21645, 21656, 21620, 21682, 21681, 21689, + 21690, 21687, 21688, 21684, 41412, 41412, 41412, 21685, 21683, 21686, + 21675, 21703, 21692, 21691, 21670, 21673, 21669, 21671, 21667, 21666, + 21674, 21665, 21668, 21672, 21664, 21699, 21701, 21698, 21697, 21694, + 21693, 21696, 21695, 21702, 21700, 21677, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 25255, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 35704, 35700, 35694, + 35703, 35696, 35705, 35709, 35711, 35706, 35701, 35702, 35707, 35695, + 35712, 35710, 35697, 35708, 35698, 35699, 35713, 35714, 35778, 35761, + 35759, 35768, 35767, 35763, 35769, 35765, 35764, 35771, 35772, 35773, + 35770, 35762, 35775, 35693, 35680, 35751, 35758, 36048, 36049, 35678, + 35653, 35779, 36047, 35715, 35780, 35766, 35774, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 35756, 8952, 8960, 8958, 8954, 8959, 8955, 8953, 8956, 8957, 9021, 8961, + 8970, 8969, 8963, 8962, 8974, 8964, 8965, 8973, 8967, 8968, 8975, 8976, + 8981, 8978, 8977, 8979, 8980, 8983, 8985, 8987, 8986, 8988, 8994, 8991, + 8992, 8996, 8989, 8990, 8995, 8993, 8998, 8997, 8999, 9001, 9002, 9006, + 9005, 9003, 9004, 9007, 9020, 9008, 9009, 9010, 9019, 9011, 9015, 9016, + 9014, 9012, 9013, 9018, 9017, 9022, 9023, 9034, 9025, 9029, 9030, 9031, + 9032, 9033, 9035, 9038, 9037, 9036, 9039, 9041, 9042, 9043, 9044, 9045, + 9046, 9047, 9048, 9049, 9050, 9051, 9052, 9053, 9054, 9055, 9056, 9057, + 9058, 9073, 9059, 9060, 9070, 9064, 9061, 9062, 9063, 9071, 9068, 9072, + 9069, 9065, 9067, 9080, 9076, 9077, 9078, 9081, 9092, 9082, 9085, 9086, + 9088, 9089, 9090, 9093, 9096, 9094, 9095, 9097, 9098, 9100, 9101, 9130, + 9137, 9131, 9132, 9133, 9134, 9135, 9136, 9138, 9140, 9139, 9141, 9144, + 9145, 9148, 9142, 9143, 9149, 9194, 9193, 9195, 9150, 9153, 9154, 9155, + 9151, 9152, 9156, 9159, 9157, 9160, 9162, 9171, 9172, 9173, 9174, 9192, + 9175, 9176, 9189, 9190, 9188, 9177, 9178, 9179, 9180, 9181, 9182, 9183, + 9186, 9187, 9196, 9286, 9197, 9198, 9200, 9199, 9206, 9201, 9203, 9205, + 9209, 9208, 9210, 9211, 9218, 9212, 9213, 9217, 9221, 9222, 9219, 9220, + 9228, 9225, 9229, 9230, 9231, 9232, 9233, 9235, 9236, 9238, 9237, 9240, + 9239, 9242, 9241, 9243, 9244, 9246, 9247, 9251, 9253, 9257, 9258, 9271, + 9263, 9264, 9259, 9260, 9261, 9265, 9269, 9266, 9267, 9268, 9272, 9273, + 9275, 9276, 9277, 9278, 9279, 9280, 9290, 9281, 9282, 9285, 9284, 9283, + 9287, 9288, 9289, 9291, 9292, 9295, 9296, 9297, 9298, 9299, 9301, 9300, + 9317, 9308, 9309, 9302, 9303, 9305, 9306, 9304, 9307, 9316, 9310, 9315, + 9313, 9312, 9314, 9319, 9338, 9320, 9321, 9322, 9325, 9324, 9326, 9327, + 9329, 9330, 9331, 9339, 9332, 9333, 9334, 9337, 9336, 9335, 9340, 9341, + 9343, 9344, 9345, 9346, 9348, 9352, 9349, 9353, 9351, 9350, 9354, 9355, + 9356, 9357, 9361, 9360, 9358, 9359, 9362, 9363, 9365, 9384, 9386, 9366, + 9368, 9367, 9369, 9370, 9373, 9374, 9372, 9371, 9375, 9376, 9377, 9378, + 9381, 9379, 9380, 9382, 9383, 9387, 9388, 9385, 9389, 9390, 9391, 9392, + 9394, 9397, 9396, 9398, 9399, 9401, 9402, 9403, 9407, 9406, 9404, 9405, + 9408, 9412, 9411, 9410, 9413, 9414, 9416, 9417, 9421, 9418, 9419, 9424, + 9422, 9425, 9426, 9428, 9427, 9429, 9430, 9452, 9451, 9454, 9455, 9436, + 9437, 9434, 9435, 9433, 9431, 9439, 9438, 9440, 9442, 9448, 9449, 9446, + 9447, 9456, 9457, 9458, 9476, 9461, 9462, 9463, 9459, 9460, 9464, 9465, + 9466, 9467, 9468, 9470, 9471, 9472, 9473, 9474, 9499, 9477, 9480, 9478, + 9479, 9485, 9486, 9483, 9484, 9481, 9482, 9487, 9488, 9496, 9489, 9490, + 9497, 9494, 9495, 9498, 9491, 9492, 9493, 9500, 9501, 9502, 9503, 9504, + 9505, 9506, 9508, 9509, 9507, 9510, 9511, 9552, 9553, 9514, 9515, 9512, + 9513, 9518, 9519, 9517, 9523, 9520, 9522, 9521, 9527, 9528, 9526, 9524, + 9525, 9529, 9530, 9531, 9532, 9533, 9534, 9535, 9554, 9540, 9536, 9537, + 9538, 9539, 9541, 9543, 9542, 9544, 9545, 9547, 9546, 9548, 9550, 9549, + 9555, 9556, 9559, 9560, 9557, 9558, 9634, 9629, 9630, 9631, 9632, 9633, + 9635, 9638, 9636, 9637, 9639, 9681, 9640, 9670, 9671, 9647, 9649, 9666, + 9650, 9672, 9654, 9652, 9653, 9655, 9656, 9657, 9658, 9667, 9668, 9661, + 9662, 9664, 9673, 9641, 9642, 9646, 9644, 9682, 9674, 9676, 9675, 9677, + 9683, 9684, 9678, 9679, 9680, 9685, 9686, 9687, 9690, 9691, 9692, 9688, + 9689, 9693, 9694, 9696, 9698, 9699, 9717, 9715, 9716, 9719, 9718, 9700, + 9707, 9705, 9706, 9701, 9702, 9708, 9709, 9710, 9711, 9712, 9714, 9720, + 9729, 9721, 9723, 9724, 9722, 9725, 9727, 9726, 9728, 9731, 9733, 9732, + 9734, 9735, 9768, 9770, 9736, 9738, 9737, 9740, 9743, 9741, 9742, 9746, + 9750, 9753, 9752, 9755, 9758, 9756, 9757, 9761, 9763, 9769, 9771, 9772, + 9776, 9783, 9781, 9779, 9780, 9782, 9785, 9784, 9777, 9778, 9786, 9789, + 9795, 9790, 9793, 9788, 9787, 9796, 9794, 9791, 9792, 9797, 9798, 9799, + 9800, 9801, 9802, 9803, 9805, 9808, 9809, 9812, 9813, 9814, 9810, 9811, + 9806, 9807, 9815, 9816, 9817, 9818, 9819, 9820, 9822, 9823, 9824, 9825, + 9826, 9830, 9827, 9851, 9844, 9845, 9850, 9833, 9832, 9846, 9849, 9847, + 9836, 9835, 9838, 9840, 9841, 9842, 9843, 9839, 9852, 9828, 9853, 9854, + 9855, 9856, 9857, 9858, 9866, 9864, 9862, 9865, 9861, 9863, 9859, 9860, + 9867, 9869, 9870, 9871, 9878, 9873, 9874, 9882, 9883, 9879, 9881, 9880, + 9884, 9886, 9885, 9887, 9898, 9889, 9888, 9897, 9895, 9890, 9891, 9892, + 9894, 9893, 9896, 9902, 9899, 9901, 9900, 9903, 9904, 9905, 9906, 9909, + 9910, 9912, 9913, 9914, 9915, 9917, 9916, 9918, 9925, 9919, 9920, 9926, + 9921, 9922, 9923, 9924, 9927, 9931, 9928, 9929, 9930, 9932, 9933, 9934, + 9935, 9941, 9939, 9937, 9938, 9936, 9940, 9942, 9944, 9961, 9962, 9945, + 9950, 9952, 9946, 9949, 9947, 9948, 9953, 9959, 9960, 9954, 9957, 9958, + 9963, 9969, 9968, 9964, 9966, 9965, 10050, 10051, 9970, 9971, 9976, 9977, + 9974, 9975, 9978, 9972, 9973, 9979, 9982, 9983, 9985, 9986, 9987, 9991, + 9988, 9989, 9990, 9980, 9981, 9992, 9994, 9993, 9995, 9997, 9998, 9999, + 10005, 10004, 10000, 10001, 10002, 10037, 10006, 10007, 10008, 10009, + 10010, 10029, 10012, 10013, 10015, 10014, 10016, 10017, 10033, 10018, + 10020, 10019, 10032, 10022, 10030, 10034, 10025, 10024, 10031, 10026, + 10028, 10027, 10035, 10036, 10038, 10042, 10040, 10041, 10039, 10045, + 10044, 10043, 10049, 10046, 10047, 10048, 10052, 10054, 10053, 10057, + 10055, 10072, 10058, 10061, 10063, 10059, 10060, 10064, 10062, 10065, + 10067, 10069, 10070, 10071, 9475, 8971, 8982, 9000, 9066, 9075, 9091, + 9099, 9191, 9184, 9202, 9204, 9294, 9318, 9364, 9393, 9395, 9409, 9415, + 9450, 9423, 9453, 9432, 9441, 9445, 9516, 9645, 9648, 9663, 9695, 9713, + 9730, 9739, 9767, 9765, 9744, 9775, 9804, 9821, 9831, 9951, 9984, 9967, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 8936, 8931, 8868, 8854, 8915, 8911, 8843, 8888, 8935, 8876, + 8860, 8921, 8910, 8842, 8887, 8874, 8858, 8917, 8907, 8837, 8884, 8897, + 8941, 8933, 8870, 8856, 8919, 8909, 8839, 8886, 8898, 8942, 8934, 8871, + 8857, 8943, 8925, 8926, 8872, 8848, 8914, 8906, 8836, 8883, 8901, 8944, + 8927, 8928, 8873, 8849, 8912, 8913, 8896, 8939, 8922, 8923, 8863, 8853, + 8929, 8930, 8864, 8867, 8865, 8866, 8920, 8905, 8903, 8904, 8840, 8841, + 8879, 8881, 8882, 8880, 8937, 8932, 8869, 8855, 8916, 8895, 8938, 8924, + 8861, 8862, 8851, 8852, 8878, 8877, 8891, 8940, 8900, 8946, 8850, 8899, + 8945, 8892, 8893, 8889, 8890, 8894, 8902, 8844, 8847, 8846, 8845, 8875, + 8859, 8918, 8908, 8838, 8885, 41412, 8951, 8950, 8949, 8947, 8948, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 8972, 8966, 8984, 9024, 9026, 9027, 9028, 9040, 9079, 9074, 9084, 9083, + 9087, 9104, 9102, 9103, 9105, 9106, 9124, 9110, 9107, 9108, 9109, 9126, + 9127, 9125, 9114, 9113, 9111, 9112, 9117, 9115, 9116, 9118, 9119, 9120, + 9121, 9128, 9129, 9123, 9122, 9147, 9146, 9158, 9161, 9166, 9170, 9163, + 9167, 9168, 9164, 9165, 9169, 9185, 9207, 9214, 9215, 9216, 9223, 9224, + 9227, 9226, 9234, 9245, 9248, 9249, 9250, 9252, 9254, 9255, 9256, 9262, + 9270, 9274, 9293, 9311, 9323, 9328, 9342, 9347, 9400, 9420, 9443, 9444, + 9551, 9571, 9561, 9562, 9570, 9566, 9567, 9568, 9565, 9564, 9563, 9569, + 9573, 9572, 9579, 9580, 9574, 9575, 9576, 9581, 9577, 9578, 9582, 9583, + 9584, 9585, 9586, 9587, 9594, 9588, 9593, 9592, 9590, 9589, 9591, 9595, + 9596, 9601, 9602, 9597, 9598, 9599, 9600, 9628, 9624, 9603, 9611, 9612, + 9610, 9609, 9613, 9604, 9605, 9607, 9608, 9606, 9625, 9614, 9621, 9623, + 9618, 9619, 9622, 9617, 9620, 9616, 9615, 9626, 9627, 9643, 9669, 9651, + 9659, 9660, 9665, 9697, 9704, 9703, 9764, 9745, 9747, 9766, 9748, 9749, + 9751, 9754, 9759, 9760, 9762, 9829, 9848, 9834, 9837, 9868, 9872, 9875, + 9876, 9877, 9908, 9907, 9911, 9943, 9955, 9956, 9996, 10003, 10011, + 10023, 10021, 10056, 10066, 10068, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 10145, 10146, 10147, + 10148, 10149, 10150, 10151, 10152, 10155, 10156, 10153, 10154, 10157, + 10158, 10159, 10160, 10161, 10162, 10163, 10164, 10165, 10166, 10167, + 10168, 10169, 10170, 10171, 10172, 10173, 10174, 10175, 10176, 10177, + 10178, 10179, 10180, 10181, 10182, 10183, 10184, 10185, 10186, 10187, + 10188, 10189, 10190, 10191, 10211, 10212, 10213, 10214, 10215, 10216, + 10217, 10218, 10219, 10194, 10195, 10196, 10197, 10198, 10192, 10193, + 10199, 10200, 10201, 10220, 10221, 10222, 10223, 10224, 10225, 10226, + 10227, 10228, 10229, 10202, 10203, 10204, 10205, 10206, 10207, 10208, + 10209, 10210, 10230, 10231, 10232, 10233, 10234, 10235, 10236, 10237, + 10238, 10239, 10240, 10241, 10242, 10243, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 11681, + 11682, 11683, 11684, 11679, 11680, 11676, 11677, 11678, 11685, 11686, + 11687, 11692, 11693, 11694, 11695, 11688, 11689, 11696, 11697, 11690, + 11691, 11698, 11699, 11726, 11727, 11728, 11729, 11730, 11731, 11732, + 11733, 11734, 11735, 11716, 11717, 11714, 11715, 11718, 11719, 11720, + 11721, 11722, 11723, 11724, 11700, 11701, 11708, 11702, 11703, 11704, + 11705, 11709, 11706, 11707, 11710, 11711, 11712, 11713, 11736, 11737, + 11738, 11739, 11740, 11741, 11742, 11743, 11744, 11745, 11746, 11747, + 11748, 11749, 11750, 11751, 11752, 11753, 11754, 11755, 11725, 11795, + 11796, 11797, 11798, 11793, 11794, 11799, 11800, 11801, 11802, 11807, + 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812, 11813, + 11814, 11815, 11816, 11817, 11818, 11819, 11820, 11821, 11822, 11823, + 11824, 11825, 11826, 11827, 11828, 11829, 11830, 11833, 11834, 11835, + 11836, 11837, 11838, 11839, 11831, 11832, 11840, 11913, 11914, 11915, + 11916, 11917, 11918, 11919, 11920, 11921, 11922, 11904, 11905, 11906, + 11907, 11908, 11909, 11910, 11902, 11903, 11911, 11912, 11845, 11841, + 11842, 11846, 11847, 11843, 11844, 11848, 11849, 11850, 11851, 11852, + 11857, 11858, 11859, 11860, 11861, 11862, 11853, 11854, 11863, 11855, + 11856, 11864, 11865, 11866, 11867, 11868, 11869, 11870, 11871, 11872, + 11873, 11874, 11879, 11875, 11876, 11880, 11877, 11878, 11881, 11882, + 11883, 11884, 11885, 11895, 11896, 11897, 11898, 11899, 11900, 11901, + 11886, 11887, 11888, 11889, 11890, 11891, 11892, 11893, 11894, 11927, + 11928, 11929, 11930, 11931, 11932, 11933, 11923, 11924, 11925, 11926, + 11959, 11960, 11961, 11962, 11963, 11964, 11955, 11956, 11957, 11958, + 11965, 11966, 11934, 11935, 11938, 11939, 11940, 11941, 11942, 11943, + 11944, 11936, 11937, 11945, 11948, 11949, 11950, 11951, 11946, 11947, + 11952, 11953, 11954, 11970, 11971, 11972, 11973, 11974, 11975, 11976, + 11977, 11978, 11979, 11982, 11983, 11984, 11980, 11981, 11985, 11986, + 11987, 11988, 11989, 11990, 12026, 12024, 12025, 12027, 12028, 12029, + 12030, 12031, 12032, 12033, 12034, 11997, 11991, 11992, 11998, 11999, + 12000, 12001, 12002, 11993, 11994, 11995, 11996, 12003, 12010, 12011, + 12012, 12013, 12014, 12004, 12005, 12006, 12007, 12008, 12009, 12015, + 12016, 12021, 12017, 12018, 12019, 12020, 12022, 12023, 12041, 12042, + 12043, 12044, 12045, 12039, 12040, 12036, 12037, 12038, 12046, 12047, + 12050, 12048, 12049, 12051, 12052, 12053, 12054, 12055, 12056, 12057, + 12058, 12083, 12084, 12087, 12088, 12089, 12090, 12091, 12085, 12086, + 12092, 12093, 12094, 12063, 12064, 12065, 12066, 12067, 12068, 12059, + 12060, 12061, 12062, 12069, 12070, 12075, 12076, 12077, 12071, 12072, + 12078, 12073, 12074, 12079, 12080, 12081, 12082, 12095, 12096, 12097, + 12098, 12099, 12102, 12103, 12104, 12105, 12106, 12100, 12101, 12107, + 12108, 12116, 12117, 12118, 12119, 12112, 12113, 12120, 12121, 12122, + 12114, 12115, 12123, 12124, 12125, 12126, 12127, 12128, 12129, 12130, + 12771, 12772, 12773, 12774, 12775, 12776, 12777, 12778, 12142, 12138, + 12139, 12143, 12144, 12145, 12140, 12141, 12146, 12147, 12149, 12150, + 12151, 12154, 12152, 12153, 12155, 12156, 12157, 12158, 12159, 12160, + 12170, 12171, 12178, 12161, 12162, 12163, 12164, 12165, 12166, 12167, + 12168, 12169, 12179, 12180, 12172, 12173, 12174, 12175, 12176, 12177, + 12181, 12182, 12189, 12190, 12183, 12184, 12191, 12185, 12186, 12192, + 12193, 12194, 12187, 12188, 12195, 12201, 12199, 12200, 12202, 12196, + 12197, 12198, 12203, 12204, 12205, 12206, 12207, 12208, 12209, 12210, + 12211, 12212, 12213, 12214, 12271, 12272, 12273, 12274, 12275, 12276, + 12277, 12278, 12279, 12234, 12235, 12236, 12237, 12238, 12239, 12240, + 12241, 12231, 12232, 12233, 12242, 12259, 12260, 12261, 12262, 12263, + 12257, 12258, 12264, 12265, 12266, 12267, 12251, 12252, 12253, 12243, + 12244, 12245, 12246, 12247, 12248, 12254, 12249, 12250, 12255, 12256, + 12268, 12269, 12270, 12282, 12283, 12284, 12285, 12280, 12281, 12286, + 12287, 12288, 12289, 12292, 12293, 12294, 12295, 12296, 12297, 12298, + 12290, 12291, 12299, 12300, 12301, 12319, 12320, 12321, 12322, 12323, + 12324, 12325, 12326, 12327, 12302, 12303, 12304, 12305, 12308, 12309, + 12310, 12311, 12312, 12313, 12306, 12307, 12314, 12317, 12318, 12315, + 12316, 12335, 12336, 12339, 12340, 12341, 12337, 12338, 12328, 12329, + 12330, 12331, 12332, 12333, 12334, 12342, 12343, 12344, 12345, 12346, + 12347, 12348, 12351, 12352, 12353, 12354, 12355, 12356, 12357, 12358, + 12349, 12350, 12359, 12360, 12367, 12368, 12369, 12361, 12362, 12363, + 12364, 12370, 12371, 12372, 12365, 12366, 12378, 12379, 12382, 12383, + 12380, 12381, 12384, 12385, 12373, 12374, 12375, 12376, 12377, 12386, + 12387, 12388, 12393, 12394, 12395, 12396, 12397, 12398, 12399, 12400, + 12401, 12402, 12389, 12390, 12391, 12392, 12404, 12405, 12408, 12406, + 12407, 12409, 12410, 12411, 12412, 12413, 12414, 12415, 12416, 12779, + 12780, 12781, 12782, 12783, 12784, 12785, 12422, 12420, 12421, 12417, + 12418, 12419, 12423, 12424, 12425, 12426, 12427, 12428, 12429, 12430, + 12433, 12434, 12435, 12436, 12437, 12431, 12432, 12438, 12439, 12440, + 12441, 12442, 12443, 12444, 12445, 12446, 12447, 12448, 12449, 12450, + 12455, 12451, 12452, 12456, 12457, 12458, 12453, 12454, 12459, 12460, + 12461, 12467, 12468, 12469, 12470, 12462, 12463, 12464, 12471, 12472, + 12465, 12466, 12473, 12474, 12478, 12479, 12480, 12481, 12482, 12483, + 12475, 12476, 12477, 12484, 12485, 12486, 12489, 12490, 12491, 12492, + 12493, 12487, 12488, 12494, 12495, 12496, 12497, 12498, 12499, 12500, + 12501, 12502, 12503, 12504, 12513, 12514, 12505, 12506, 12515, 12516, + 12517, 12507, 12508, 12509, 12510, 12511, 12512, 12522, 12518, 12519, + 12523, 12524, 12525, 12526, 12520, 12521, 12527, 12528, 12529, 12539, + 12540, 12541, 12542, 12543, 12544, 12545, 12546, 12547, 12548, 12534, + 12535, 12530, 12531, 12532, 12533, 12536, 12537, 12538, 12553, 12554, + 12555, 12556, 12557, 12550, 12551, 12552, 12558, 12559, 12560, 12587, + 12588, 12589, 12590, 12591, 12592, 12593, 12594, 12595, 12596, 12565, + 12566, 12567, 12561, 12562, 12568, 12569, 12570, 12571, 12572, 12563, + 12564, 12575, 12576, 12573, 12574, 12577, 12578, 12579, 12580, 12581, + 12582, 12583, 12584, 12585, 12586, 12600, 12601, 12602, 12603, 12604, + 12605, 12606, 12607, 12608, 12609, 12610, 12611, 12612, 12613, 12614, + 12615, 12597, 12598, 12599, 12616, 12617, 12626, 12618, 12619, 12620, + 12621, 12623, 12624, 12625, 12627, 12628, 12629, 12630, 12631, 12632, + 12633, 12634, 12635, 12636, 12637, 12638, 12639, 12640, 12641, 12642, + 12643, 12644, 12645, 12646, 12653, 12654, 12647, 12648, 12655, 12656, + 12657, 12658, 12649, 12650, 12651, 12652, 12659, 12660, 12661, 12662, + 12667, 12663, 12664, 12668, 12669, 12670, 12665, 12666, 12671, 12672, + 12673, 12674, 12680, 12681, 12676, 12677, 12682, 12683, 12684, 12685, + 12686, 12678, 12679, 12687, 12688, 12695, 12696, 12697, 12689, 12690, + 12698, 12699, 12691, 12692, 12693, 12694, 12700, 12703, 12704, 12705, + 12706, 12701, 12702, 12707, 12716, 12717, 12718, 12709, 12710, 12711, + 12719, 12712, 12713, 12720, 12714, 12715, 12721, 12722, 12723, 12724, + 12725, 12726, 12727, 12728, 12729, 12742, 12730, 12731, 12732, 12733, + 12734, 12735, 12736, 12737, 12738, 12739, 12740, 12741, 12743, 12744, + 12745, 12746, 12766, 12767, 12768, 12769, 12770, 12747, 12748, 12749, + 12750, 12751, 12752, 12753, 12754, 12755, 12756, 12757, 12758, 12759, + 12760, 12761, 12762, 12763, 12764, 12765, 11759, 11760, 11761, 11762, + 11763, 11764, 11756, 11757, 11758, 11765, 11766, 11770, 11771, 11772, + 11773, 11774, 11775, 11776, 11777, 11778, 11779, 11780, 11781, 11782, + 11783, 11784, 11785, 11786, 11787, 11788, 11789, 11767, 11768, 11769, + 12622, 12675, 12111, 12136, 12133, 12135, 12132, 12403, 11792, 11969, + 12137, 12134, 12131, 11791, 11968, 11790, 11967, 12230, 12035, 12109, + 12148, 12110, 12549, 12708, 12226, 12217, 12221, 12228, 12224, 12218, + 12223, 12220, 12227, 12216, 12222, 12229, 12225, 12219, 12215, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 12786, + 12787, 12788, 12789, 12790, 12791, 12792, 12793, 12794, 12795, 12796, + 12797, 12798, 12799, 12800, 12801, 12802, 12803, 12804, 12805, 12806, + 12807, 12808, 12809, 12810, 12811, 12812, 12813, 12814, 12815, 12816, + 12817, 12818, 12819, 12820, 12821, 12822, 12823, 12824, 12825, 12826, + 12827, 12828, 12829, 12830, 12831, 12832, 12833, 12834, 12835, 12836, + 12837, 12838, 12839, 12840, 12841, 12842, 12843, 12844, 12845, 12846, + 12847, 12848, 12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, + 12857, 12858, 12859, 12860, 12861, 12862, 12863, 12864, 12865, 12866, + 12867, 12868, 12869, 12870, 12871, 12872, 12873, 12874, 12875, 12876, + 12877, 12878, 12879, 12880, 12881, 12882, 12883, 12884, 12885, 12886, + 12887, 12888, 12889, 12890, 12891, 12892, 12893, 12894, 12895, 12896, + 12897, 12898, 12899, 12900, 12901, 12902, 12903, 12904, 12905, 12906, + 12907, 12908, 12909, 12910, 12911, 12912, 12913, 12914, 12915, 12916, + 12917, 12918, 12919, 12920, 12921, 12922, 12923, 12924, 12925, 12926, + 12927, 12928, 12929, 12930, 12931, 12932, 12933, 12934, 12935, 12936, + 12937, 12938, 12939, 12940, 12941, 12942, 12943, 12944, 12945, 12946, + 12947, 12948, 12949, 12950, 12951, 12952, 12953, 12954, 12955, 12956, + 12957, 12958, 12959, 12960, 12961, 12962, 12963, 12964, 12965, 12966, + 12967, 12968, 12969, 12970, 12971, 12972, 12973, 12974, 12975, 12976, + 12977, 12978, 12979, 12980, 12981, 12982, 12983, 12984, 12985, 12986, + 12987, 12988, 12989, 12990, 12991, 12992, 12993, 12994, 12995, 12996, + 12997, 12998, 12999, 13000, 13001, 13002, 13003, 13004, 13005, 13006, + 13007, 13008, 13009, 13010, 13011, 13012, 13013, 13014, 13015, 13016, + 13017, 13018, 13019, 13020, 13021, 13022, 13023, 13024, 13025, 13026, + 13027, 13028, 13029, 13030, 13031, 13032, 13033, 13034, 13035, 13036, + 13037, 13038, 13039, 13040, 13041, 13042, 13043, 13044, 13045, 13046, + 13047, 13048, 13049, 13050, 13051, 13052, 13053, 13054, 13055, 13056, + 13057, 13058, 13059, 13060, 13061, 13062, 13063, 13064, 13065, 13066, + 13067, 13068, 13069, 13070, 13071, 13072, 13073, 13074, 13075, 13076, + 13077, 13078, 13079, 13080, 13081, 13082, 13083, 13084, 13085, 13086, + 13087, 13088, 13089, 13090, 13091, 13092, 13093, 13094, 13095, 13096, + 13097, 13098, 13099, 13100, 13101, 13102, 13103, 13104, 13105, 13106, + 13107, 13108, 13109, 13110, 13111, 13112, 13113, 13114, 13115, 13116, + 13117, 13118, 13119, 13120, 13121, 13122, 13123, 13124, 13125, 13126, + 13127, 13128, 13129, 13130, 13131, 13132, 13133, 13134, 13135, 13136, + 13137, 13138, 13139, 13140, 13141, 13142, 13143, 13144, 13145, 13146, + 13147, 13148, 13149, 13150, 13151, 13152, 13153, 13154, 13155, 13156, + 13157, 13158, 13159, 13160, 13161, 13162, 13163, 13164, 13165, 13166, + 13167, 13168, 13169, 13170, 13171, 13172, 13173, 13174, 13175, 13176, + 13177, 13178, 13179, 13180, 13181, 13182, 13183, 13184, 13185, 13186, + 13187, 13188, 13189, 13190, 13191, 13192, 13193, 13194, 13195, 13196, + 13197, 13198, 13199, 13200, 13201, 13202, 13203, 13204, 13205, 13206, + 13207, 13208, 13209, 13210, 13211, 13212, 13213, 13214, 13215, 13216, + 13217, 13218, 13219, 13220, 13221, 13222, 13223, 13224, 13225, 13226, + 13227, 13228, 13229, 13230, 13231, 13232, 13233, 13234, 13235, 13236, + 13237, 13238, 13239, 13240, 13241, 13242, 13243, 13244, 13245, 13246, + 13247, 13248, 13249, 13250, 13251, 13252, 13253, 13254, 13255, 13256, + 13257, 13258, 13259, 13260, 13261, 13262, 13263, 13264, 13265, 13266, + 13267, 13268, 13269, 13270, 13271, 13272, 13273, 13274, 13275, 13276, + 13277, 13278, 13279, 13280, 13281, 13282, 13283, 13284, 13285, 13286, + 13287, 13288, 13289, 13290, 13291, 13292, 13293, 13294, 13295, 13296, + 13297, 13298, 13299, 13300, 13301, 13302, 13303, 13304, 13305, 13306, + 13307, 13308, 13309, 13310, 13311, 13312, 13313, 13314, 13315, 13316, + 13317, 13318, 13319, 13320, 13321, 13322, 13323, 13324, 13325, 13326, + 13327, 13328, 13329, 13330, 13331, 13332, 13333, 13334, 13335, 13336, + 13337, 13338, 13339, 13340, 13341, 13342, 13343, 13344, 13345, 13346, + 13347, 13348, 13349, 13350, 13351, 13352, 13353, 13354, 13355, 13356, + 13357, 13358, 13359, 13360, 13361, 13362, 13363, 13364, 13365, 13366, + 13367, 13368, 13369, 13370, 13371, 13372, 13373, 13374, 13375, 13376, + 13377, 13378, 13379, 13380, 13381, 13382, 13383, 13384, 13385, 13386, + 13387, 13388, 13389, 13390, 13391, 13392, 13393, 13394, 13395, 13396, + 13397, 13398, 13399, 13400, 13401, 13402, 13403, 13404, 13405, 13406, + 13407, 13408, 13409, 13410, 13411, 13412, 13413, 13414, 13415, 13416, + 13417, 13418, 13419, 13420, 13421, 13422, 13423, 13424, 13425, 13426, + 13427, 13428, 13429, 13430, 13431, 13432, 13433, 13434, 13435, 13436, + 13437, 13438, 13439, 13440, 13441, 13442, 13443, 13444, 13445, 13446, + 13447, 13448, 13449, 13450, 13451, 13452, 13453, 13454, 13455, 13456, + 13457, 13458, 13459, 13460, 13461, 13462, 13463, 13464, 13465, 13466, + 13467, 13468, 13469, 13470, 13471, 13472, 13473, 13474, 13475, 13476, + 13477, 13478, 13479, 13480, 13481, 13482, 13483, 13484, 13485, 13486, + 13487, 13488, 13489, 13490, 13491, 13492, 13493, 13494, 13495, 13496, + 13497, 13498, 13499, 13500, 13501, 13502, 13503, 13504, 13505, 13506, + 13507, 13508, 13509, 13510, 13511, 13512, 13513, 13514, 13515, 13516, + 13517, 13518, 13519, 13520, 13521, 13522, 13523, 13524, 13525, 13526, + 13527, 13528, 13529, 13530, 13531, 13532, 13533, 13534, 13535, 13536, + 13537, 13538, 13539, 13540, 13541, 13542, 13543, 13544, 13545, 13546, + 13547, 13548, 13549, 13550, 13551, 13552, 13553, 13554, 13555, 13556, + 13557, 13558, 13559, 13560, 13561, 13562, 13563, 13564, 13565, 13566, + 13567, 13568, 13569, 13570, 13571, 13572, 13573, 13574, 13575, 13576, + 13577, 13578, 13579, 13580, 13581, 13582, 13583, 13584, 13585, 13586, + 13587, 13588, 13589, 13590, 13591, 13592, 13593, 13594, 13595, 13596, + 13597, 13598, 13599, 13600, 13601, 13602, 13603, 13604, 13605, 13606, + 13607, 13608, 13609, 13610, 13611, 13612, 13613, 13614, 13615, 13616, + 13617, 13618, 13619, 13620, 13621, 13622, 13623, 13624, 13625, 13626, + 13627, 13628, 13629, 13630, 13631, 13632, 13633, 13634, 13635, 13636, + 13637, 13638, 13639, 13640, 13641, 13642, 13643, 13644, 13645, 13646, + 13647, 13648, 13649, 13650, 13651, 13652, 13653, 13654, 13655, 13656, + 13657, 13658, 13659, 13660, 13661, 13662, 13663, 13664, 13665, 13666, + 13667, 13668, 13669, 13670, 13671, 13672, 13673, 13674, 13675, 13676, + 13677, 13678, 13679, 13680, 13681, 13682, 13683, 13684, 13685, 13686, + 13687, 13688, 13689, 13690, 13691, 13692, 13693, 13694, 13695, 13696, + 13697, 13698, 13699, 13700, 13701, 13702, 13703, 13704, 13705, 13706, + 13707, 13708, 13709, 13710, 13711, 13712, 13713, 13714, 13715, 13716, + 13717, 13718, 13719, 13720, 13721, 13722, 13723, 13724, 13725, 13726, + 13727, 13728, 13729, 13730, 13731, 13732, 13733, 13734, 13735, 13736, + 13737, 13738, 13739, 13740, 13741, 13742, 13743, 13744, 13745, 13746, + 13747, 13748, 13749, 13750, 13751, 13752, 13753, 13754, 13755, 13756, + 13757, 13758, 13759, 13760, 13761, 13762, 13763, 13764, 13765, 13766, + 13767, 13768, 13769, 13770, 13771, 13772, 13773, 13774, 13775, 13776, + 13777, 13778, 13779, 13780, 13781, 13782, 13783, 13784, 13785, 13786, + 13787, 13788, 13789, 13790, 13791, 13792, 13793, 13794, 13795, 13796, + 13797, 13798, 13799, 13800, 13801, 13802, 13803, 13804, 13805, 13806, + 13807, 13808, 13809, 13810, 13811, 13812, 13813, 13814, 13815, 13816, + 13817, 13818, 13819, 13820, 13821, 13822, 13823, 13824, 13825, 13826, + 13827, 13828, 13829, 13830, 13831, 13832, 13833, 13834, 13835, 13836, + 13837, 13838, 13839, 13840, 13841, 13842, 13843, 13844, 13845, 13846, + 13847, 13848, 13849, 13850, 13851, 13852, 13853, 13854, 13855, 13856, + 13857, 13858, 13859, 13860, 13861, 13862, 13863, 13864, 13865, 13866, + 13867, 13868, 13869, 13870, 13871, 13872, 13873, 13874, 13875, 13876, + 13877, 13878, 13879, 13880, 13881, 13882, 13883, 13884, 13885, 13886, + 13887, 13888, 13889, 13890, 13891, 13892, 13893, 13894, 13895, 13896, + 13897, 13898, 13899, 13900, 13901, 13902, 13903, 13904, 13905, 13906, + 13907, 13908, 13909, 13910, 13911, 13912, 13913, 13914, 13915, 13916, + 13917, 13918, 13919, 13920, 13921, 13922, 13923, 13924, 13925, 13926, + 13927, 13928, 13929, 13930, 13931, 13932, 13933, 13934, 13935, 13936, + 13937, 13938, 13939, 13940, 13941, 13942, 13943, 13944, 13945, 13946, + 13947, 13948, 13949, 13950, 13951, 13952, 13953, 13954, 13955, 13956, + 13957, 13958, 13959, 13960, 13961, 13962, 13963, 13964, 13965, 13966, + 13967, 13968, 13969, 13970, 13971, 13972, 13973, 13974, 13975, 13976, + 13977, 13978, 13979, 13980, 13981, 13982, 13983, 13984, 13985, 13986, + 13987, 13988, 13989, 13990, 13991, 13992, 13993, 13994, 13995, 13996, + 13997, 13998, 13999, 14000, 14001, 14002, 14003, 14004, 14005, 14006, + 14007, 14008, 14009, 14010, 14011, 14012, 14013, 14014, 14015, 14016, + 14017, 14018, 14019, 14020, 14021, 14022, 14023, 14024, 14025, 14026, + 14027, 14028, 14029, 14030, 14031, 14032, 14033, 14034, 14035, 14036, + 14037, 14038, 14039, 14040, 14041, 14042, 14043, 14044, 14045, 14046, + 14047, 14048, 14049, 14050, 14051, 14052, 14053, 14054, 14055, 14056, + 14057, 14058, 14059, 14060, 14061, 14062, 14063, 14064, 14065, 14066, + 14067, 14068, 14069, 14070, 14071, 14072, 14073, 14074, 14075, 14076, + 14077, 14078, 14079, 14080, 14081, 14082, 14083, 14084, 14085, 14086, + 14087, 14088, 14089, 14090, 14091, 14092, 14093, 14094, 14095, 14096, + 14097, 14098, 14099, 14100, 14101, 14102, 14103, 14104, 14105, 14106, + 14107, 14108, 14109, 14110, 14111, 14112, 14113, 14114, 14115, 14116, + 14117, 14118, 14119, 14120, 14121, 14122, 14123, 14124, 14125, 14126, + 14127, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, 14136, + 14137, 14138, 14139, 14140, 14141, 14142, 14143, 14144, 14145, 14146, + 14147, 14148, 14149, 14150, 14151, 14152, 14153, 14154, 14155, 14156, + 14157, 14158, 14159, 14160, 14161, 14162, 14163, 14164, 14165, 14166, + 14167, 14168, 14169, 14170, 14171, 14172, 14173, 14174, 14175, 14176, + 14177, 14178, 14179, 14180, 14181, 14182, 14183, 14184, 14185, 14186, + 14187, 14188, 14189, 14190, 14191, 14192, 14193, 14194, 14195, 14196, + 14197, 14198, 14199, 14200, 14201, 14202, 14203, 14204, 14205, 14206, + 14207, 14208, 14209, 14210, 14211, 14212, 14213, 14214, 14215, 14216, + 14217, 14218, 14219, 14220, 14221, 14222, 14223, 14224, 14225, 14226, + 14227, 14228, 14229, 14230, 14231, 14232, 14233, 14234, 14235, 14236, + 14237, 14238, 14239, 14240, 14241, 14242, 14243, 14244, 14245, 14246, + 14247, 14248, 14249, 14250, 14251, 14252, 14253, 14254, 14255, 14256, + 14257, 14258, 14259, 14260, 14261, 14262, 14263, 14264, 14265, 14266, + 14267, 14268, 14269, 14270, 14271, 14272, 14273, 14274, 14275, 14276, + 14277, 14278, 14279, 14280, 14281, 14282, 14283, 14284, 14285, 14286, + 14287, 14288, 14289, 14290, 14291, 14292, 14293, 14294, 14295, 14296, + 14297, 14298, 14299, 14300, 14301, 14302, 14303, 14304, 14305, 14306, + 14307, 14308, 14309, 14310, 14311, 14312, 14313, 14314, 14315, 14316, + 14317, 14318, 14319, 14320, 14321, 14322, 14323, 14324, 14325, 14326, + 14327, 14328, 14329, 14330, 14331, 14332, 14333, 14334, 14335, 14336, + 14337, 14338, 14339, 14340, 14341, 14342, 14343, 14344, 14345, 14346, + 14347, 14348, 14349, 14350, 14351, 14352, 14353, 14354, 14355, 14356, + 14357, 14358, 14359, 14360, 14361, 14362, 14363, 14364, 14365, 14366, + 14367, 14368, 14369, 14370, 14371, 14372, 14373, 14374, 14375, 14376, + 14377, 14378, 14379, 14380, 14381, 14382, 14383, 14384, 14385, 14386, + 14387, 14388, 14389, 14390, 14391, 14392, 14393, 14394, 14395, 14396, + 14397, 14398, 14399, 14400, 14401, 14402, 14403, 14404, 14405, 14406, + 14407, 14408, 14409, 14410, 14411, 14412, 14413, 14414, 14415, 14416, + 14417, 14418, 14419, 14420, 14421, 14422, 14423, 14424, 14425, 14426, + 14427, 14428, 14429, 14430, 14431, 14432, 14433, 14434, 14435, 14436, + 14437, 14438, 14439, 14440, 14441, 14442, 14443, 14444, 14445, 14446, + 14447, 14448, 14449, 14450, 14451, 14452, 14453, 14454, 14455, 14456, + 14457, 14458, 14459, 14460, 14461, 14462, 14463, 14464, 14465, 14466, + 14467, 14468, 14469, 14470, 14471, 14472, 14473, 14474, 14475, 14476, + 14477, 14478, 14479, 14480, 14481, 14482, 14483, 14484, 14485, 14486, + 14487, 14488, 14489, 14490, 14491, 14492, 14493, 14494, 14495, 14496, + 14497, 14498, 14499, 14500, 14501, 14502, 14503, 14504, 14505, 14506, + 14507, 14508, 14509, 14510, 14511, 14512, 14513, 14514, 14515, 14516, + 14517, 14518, 14519, 14520, 14521, 14522, 14523, 14524, 14525, 14526, + 14527, 14528, 14529, 14530, 14531, 14532, 14533, 14534, 14535, 14536, + 14537, 14538, 14539, 14540, 14541, 14542, 14543, 14544, 14545, 14546, + 14547, 14548, 14549, 14550, 14551, 14552, 14553, 14554, 14555, 14556, + 14557, 14558, 14559, 14560, 14561, 14562, 14563, 14564, 14565, 14566, + 14567, 14568, 14569, 14570, 14571, 14572, 14573, 14574, 14575, 14576, + 14577, 14578, 14579, 14580, 14581, 14582, 14583, 14584, 14585, 14586, + 14587, 14588, 14589, 14590, 14591, 14592, 14593, 14594, 14595, 14596, + 14597, 14598, 14599, 14600, 14601, 14602, 14603, 14604, 14605, 14606, + 14607, 14608, 14609, 14610, 14611, 14612, 14613, 14614, 14615, 14616, + 14617, 14618, 14619, 14620, 14621, 14622, 14623, 14624, 14625, 14626, + 14627, 14628, 14629, 14630, 14631, 14632, 14633, 14634, 14635, 14636, + 14637, 14638, 14639, 14640, 14641, 14642, 14643, 14644, 14645, 14646, + 14647, 14648, 14649, 14650, 14651, 14652, 14653, 14654, 14655, 14656, + 14657, 14658, 14659, 14660, 14661, 14662, 14663, 14664, 14665, 14666, + 14667, 14668, 14669, 14670, 14671, 14672, 14673, 14674, 14675, 14676, + 14677, 14678, 14679, 14680, 14681, 14682, 14683, 14684, 14685, 14686, + 14687, 14688, 14689, 14690, 14691, 14692, 14693, 14694, 14695, 14696, + 14697, 14698, 14699, 14700, 14701, 14702, 14703, 14704, 14705, 14706, + 14707, 14708, 14709, 14710, 14711, 14712, 14713, 14714, 14715, 14716, + 14717, 14718, 14719, 14720, 14721, 14722, 14723, 14724, 14725, 14726, + 14727, 14728, 14729, 14730, 14731, 14732, 14733, 14734, 14735, 14736, + 14737, 14738, 14739, 14740, 14741, 14742, 14743, 14744, 14745, 14746, + 14747, 14748, 14749, 14750, 14751, 14752, 14753, 14754, 14755, 14756, + 14757, 14758, 14759, 14760, 14761, 14762, 14763, 14764, 14765, 14766, + 14767, 14768, 14769, 14770, 14771, 14772, 14773, 14774, 14775, 14776, + 14777, 14778, 14779, 14780, 14781, 14782, 14783, 14784, 14785, 14786, + 14787, 14788, 14789, 14790, 14791, 14792, 14793, 14794, 14795, 14796, + 14797, 14798, 14799, 14800, 14801, 14802, 14803, 14804, 14805, 14806, + 14807, 14808, 14809, 14810, 14811, 14812, 14813, 14814, 14815, 14816, + 14817, 14818, 14819, 14820, 14821, 14822, 14823, 14824, 14825, 14826, + 14827, 14828, 14829, 14830, 14831, 14832, 14833, 14834, 14835, 14836, + 14837, 14838, 14839, 14840, 14841, 14842, 14843, 14844, 14845, 14846, + 14847, 14848, 14849, 14850, 14851, 14852, 14853, 14854, 14855, 14856, + 14857, 14858, 14859, 14860, 14861, 14862, 14863, 14864, 14865, 14866, + 14867, 14868, 14869, 14870, 14871, 14872, 14873, 14874, 14875, 14876, + 14877, 14878, 14879, 14880, 14881, 14882, 14883, 14884, 14885, 14886, + 14887, 14888, 14889, 14890, 14891, 14892, 14893, 14894, 14895, 14896, + 14897, 14898, 14899, 14900, 14901, 14902, 14903, 14904, 14905, 14906, + 14907, 14908, 14909, 14910, 14911, 14912, 14913, 14914, 14915, 14916, + 14917, 14918, 14919, 14920, 14921, 14922, 14923, 14924, 14925, 14926, + 14927, 14928, 14929, 14930, 14931, 14932, 14933, 14934, 14935, 14936, + 14937, 14938, 14939, 14940, 14941, 14942, 14943, 14944, 14945, 14946, + 14947, 14948, 14949, 14950, 14951, 14952, 14953, 14954, 14955, 14956, + 14957, 14958, 14959, 14960, 14961, 14962, 14963, 14964, 14965, 14966, + 14967, 14968, 14969, 14970, 14971, 14972, 14973, 14974, 14975, 14976, + 14977, 14978, 14979, 14980, 14981, 14982, 14983, 14984, 14985, 14986, + 14987, 14988, 14989, 14990, 14991, 14992, 14993, 14994, 14995, 14996, + 14997, 14998, 14999, 15000, 15001, 15002, 15003, 15004, 15005, 15006, + 15007, 15008, 15009, 15010, 15011, 15012, 15013, 15014, 15015, 15016, + 15017, 15018, 15019, 15020, 15021, 15022, 15023, 15024, 15025, 15026, + 15027, 15028, 15029, 15030, 15031, 15032, 15033, 15034, 15035, 15036, + 15037, 15038, 15039, 15040, 15041, 15042, 15043, 15044, 15045, 15046, + 15047, 15048, 15049, 15050, 15051, 15052, 15053, 15054, 15055, 15056, + 15057, 15058, 15059, 15060, 15061, 15062, 15063, 15064, 15065, 15066, + 15067, 15068, 15069, 15070, 15071, 15072, 15073, 15074, 15075, 15076, + 15077, 15078, 15079, 15080, 15081, 15082, 15083, 15084, 15085, 15086, + 15087, 15088, 15089, 15090, 15091, 15092, 15093, 15094, 15095, 15096, + 15097, 15098, 15099, 15100, 15101, 15102, 15103, 15104, 15105, 15106, + 15107, 15108, 15109, 15110, 15111, 15112, 15113, 15114, 15115, 15116, + 15117, 15118, 15119, 15120, 15121, 15122, 15123, 15124, 15125, 15126, + 15127, 15128, 15129, 15130, 15131, 15132, 15133, 15134, 15135, 15136, + 15137, 15138, 15139, 15140, 15141, 15142, 15143, 15144, 15145, 15146, + 15147, 15148, 15149, 15150, 15151, 15152, 15153, 15154, 15155, 15156, + 15157, 15158, 15159, 15160, 15161, 15162, 15163, 15164, 15165, 15166, + 15167, 15168, 15169, 15170, 15171, 15172, 15173, 15174, 15175, 15176, + 15177, 15178, 15179, 15180, 15181, 15182, 15183, 15184, 15185, 15186, + 15187, 15188, 15189, 15190, 15191, 15192, 15193, 15194, 15195, 15196, + 15197, 15198, 15199, 15200, 15201, 15202, 15203, 15204, 15205, 15206, + 15207, 15208, 15209, 15210, 15211, 15212, 15213, 15214, 15215, 15216, + 15217, 15218, 15219, 15220, 15221, 15222, 15223, 15224, 15225, 15226, + 15227, 15228, 15229, 15230, 15231, 15232, 15233, 15234, 15235, 15236, + 15237, 15238, 15239, 15240, 15241, 15242, 15243, 15244, 15245, 15246, + 15247, 15248, 15249, 15250, 15251, 15252, 15253, 15254, 15255, 15256, + 15257, 15258, 15259, 15260, 15261, 15262, 15263, 15264, 15265, 15266, + 15267, 15268, 15269, 15270, 15271, 15272, 15273, 15274, 15275, 15276, + 15277, 15278, 15279, 15280, 15281, 15282, 15283, 15284, 15285, 15286, + 15287, 15288, 15289, 15290, 15291, 15292, 15293, 15294, 15295, 15296, + 15297, 15298, 15299, 15300, 15301, 15302, 15303, 15304, 15305, 15306, + 15307, 15308, 15309, 15310, 15311, 15312, 15313, 15314, 15315, 15316, + 15317, 15318, 15319, 15320, 15321, 15322, 15323, 15324, 15325, 15326, + 15327, 15328, 15329, 15330, 15331, 15332, 15333, 15334, 15335, 15336, + 15337, 15338, 15339, 15340, 15341, 15342, 15343, 15344, 15345, 15346, + 15347, 15348, 15349, 15350, 15351, 15352, 15353, 15354, 15355, 15356, + 15357, 15358, 15359, 15360, 15361, 15362, 15363, 15364, 15365, 15366, + 15367, 15368, 15369, 15370, 15371, 15372, 15373, 15374, 15375, 15376, + 15377, 15378, 15379, 15380, 15381, 15382, 15383, 15384, 15385, 15386, + 15387, 15388, 15389, 15390, 15391, 15392, 15393, 15394, 15395, 15396, + 15397, 15398, 15399, 15400, 15401, 15402, 15403, 15404, 15405, 15406, + 15407, 15408, 15409, 15410, 15411, 15412, 15413, 15414, 15415, 15416, + 15417, 15418, 15419, 15420, 15421, 15422, 15423, 15424, 15425, 15426, + 15427, 15428, 15429, 15430, 15431, 15432, 15433, 15434, 15435, 15436, + 15437, 15438, 15439, 15440, 15441, 15442, 15443, 15444, 15445, 15446, + 15447, 15448, 15449, 15450, 15451, 15452, 15453, 15454, 15455, 15456, + 15457, 15458, 15459, 15460, 15461, 15462, 15463, 15464, 15465, 15466, + 15467, 15468, 15469, 15470, 15471, 15472, 15473, 15474, 15475, 15476, + 15477, 15478, 15479, 15480, 15481, 15482, 15483, 15484, 15485, 15486, + 15487, 15488, 15489, 15490, 15491, 15492, 15493, 15494, 15495, 15496, + 15497, 15498, 15499, 15500, 15501, 15502, 15503, 15504, 15505, 15506, + 15507, 15508, 15509, 15510, 15511, 15512, 15513, 15514, 15515, 15516, + 15517, 15518, 15519, 15520, 15521, 15522, 15523, 15524, 15525, 15526, + 15527, 15528, 15529, 15530, 15531, 15532, 15533, 15534, 15535, 15536, + 15537, 15538, 15539, 15540, 15541, 15542, 15543, 15544, 15545, 15546, + 15547, 15548, 15549, 15550, 15551, 15552, 15553, 15554, 15555, 15556, + 15557, 15558, 15559, 15560, 15561, 15562, 15563, 15564, 15565, 15566, + 15567, 15568, 15569, 15570, 15571, 15572, 15573, 15574, 15575, 15576, + 15577, 15578, 15579, 15580, 15581, 15582, 15583, 15584, 15585, 15586, + 15587, 15588, 15589, 15590, 15591, 15592, 15593, 15594, 15595, 15596, + 15597, 15598, 15599, 15600, 15601, 15602, 15603, 15604, 15605, 15606, + 15607, 15608, 15609, 15610, 15611, 15612, 15613, 15614, 15615, 15616, + 15617, 15618, 15619, 15620, 15621, 15622, 15623, 15624, 15625, 15626, + 15627, 15628, 15629, 15630, 15631, 15632, 15633, 15634, 15635, 15636, + 15637, 15638, 15639, 15640, 15641, 15642, 15643, 15644, 15645, 15646, + 15647, 15648, 15649, 15650, 15651, 15652, 15653, 15654, 15655, 15656, + 15657, 15658, 15659, 15660, 15661, 15662, 15663, 15664, 15665, 15666, + 15667, 15668, 15669, 15670, 15671, 15672, 15673, 15674, 15675, 15676, + 15677, 15678, 15679, 15680, 15681, 15682, 15683, 15684, 15685, 15686, + 15687, 15688, 15689, 15690, 15691, 15692, 15693, 15694, 15695, 15696, + 15697, 15698, 15699, 15700, 15701, 15702, 15703, 15704, 15705, 15706, + 15707, 15708, 15709, 15710, 15711, 15712, 15713, 15714, 15715, 15716, + 15717, 15718, 15719, 15720, 15721, 15722, 15723, 15724, 15725, 15726, + 15727, 15728, 15729, 15730, 15731, 15732, 15733, 15734, 15735, 15736, + 15737, 15738, 15739, 15740, 15741, 15742, 15743, 15744, 15745, 15746, + 15747, 15748, 15749, 15750, 15751, 15752, 15753, 15754, 15755, 15756, + 15757, 15758, 15759, 15760, 15761, 16013, 16014, 16015, 16016, 16017, + 16018, 16019, 16020, 16021, 16022, 16023, 16024, 16025, 16026, 16027, + 16028, 16029, 16030, 16031, 16032, 16033, 16034, 16035, 16036, 16037, + 16038, 16039, 16040, 16041, 16042, 16043, 16044, 16045, 16046, 16047, + 16048, 16049, 16050, 16051, 16052, 16053, 16054, 16055, 16056, 16057, + 16058, 16059, 16060, 16061, 16062, 16063, 16064, 16065, 16066, 16067, + 16068, 16069, 16070, 16071, 16072, 16073, 16074, 16075, 16076, 16077, + 16078, 16079, 16080, 16081, 16082, 16083, 16084, 16085, 16086, 16087, + 16088, 16089, 16090, 16091, 16092, 16093, 16094, 16095, 16096, 16097, + 16098, 16099, 16100, 16101, 16102, 16103, 16104, 16105, 16106, 16107, + 16108, 16109, 16110, 16111, 16112, 16113, 16114, 16115, 16116, 16117, + 16118, 16119, 16120, 16121, 16122, 16123, 16124, 16125, 16126, 16127, + 16128, 16129, 16130, 16131, 16132, 16133, 16134, 16135, 16136, 16137, + 16138, 16139, 16140, 16141, 16142, 16143, 16144, 16145, 16146, 16147, + 16148, 16149, 16150, 16151, 16152, 16153, 16154, 16155, 16156, 16157, + 16158, 16159, 16160, 16161, 16162, 16163, 16164, 16165, 16166, 16167, + 16168, 16169, 16170, 16171, 16172, 16173, 16174, 16175, 16176, 16177, + 16178, 16179, 16180, 16181, 16182, 16183, 16184, 16185, 16186, 16187, + 16188, 16189, 16190, 16191, 16192, 16193, 16194, 16195, 16196, 16197, + 16198, 16199, 16200, 16201, 16202, 16203, 16204, 16205, 16206, 16207, + 16208, 16209, 16210, 16211, 16212, 16213, 16214, 16215, 16216, 16217, + 16218, 16219, 16220, 16221, 16222, 16223, 16224, 16225, 16226, 16227, + 16228, 16229, 16230, 16231, 16232, 16233, 16234, 16235, 16236, 16237, + 16238, 16239, 16240, 16241, 16242, 16243, 16244, 16245, 16246, 16247, + 16248, 16249, 16250, 16251, 16252, 16253, 16254, 16255, 16256, 16257, + 16258, 16259, 16260, 16261, 16262, 16263, 16264, 16265, 16266, 16267, + 16268, 16269, 16270, 16271, 16272, 16273, 16274, 16275, 16276, 16277, + 16278, 16279, 16280, 16281, 16282, 16283, 16284, 16285, 16286, 16287, + 16288, 16289, 16290, 16291, 16292, 16293, 16294, 16295, 16296, 16297, + 16298, 16299, 16300, 16301, 16302, 16303, 16304, 16305, 16306, 16307, + 16308, 16309, 16310, 16311, 16312, 16313, 16314, 16315, 16316, 16317, + 16318, 16319, 16320, 16321, 16322, 16323, 16324, 16325, 16326, 16327, + 16328, 16329, 16330, 16331, 16332, 16333, 16334, 16335, 16336, 16337, + 16338, 16339, 16340, 16341, 16342, 16343, 16344, 16345, 16346, 16347, + 16348, 16349, 16350, 16351, 16352, 16353, 16354, 16355, 16356, 16357, + 16358, 16359, 16360, 16361, 16362, 16363, 16364, 16365, 16366, 16367, + 16368, 16369, 16370, 16371, 16372, 16373, 16374, 16375, 16376, 16377, + 16378, 16379, 16380, 16381, 16382, 16383, 16384, 16385, 16386, 16387, + 16388, 16389, 16390, 16391, 16392, 16393, 16394, 16395, 16396, 16397, + 16398, 16399, 16400, 16401, 16402, 16403, 16404, 16405, 16406, 16407, + 16408, 16409, 16410, 16411, 16412, 16413, 16414, 16415, 16416, 16417, + 16418, 16419, 16420, 16421, 16422, 16423, 16424, 16425, 16426, 16427, + 16428, 16429, 16430, 16431, 16432, 16433, 16434, 16435, 16436, 16437, + 16438, 16439, 16440, 16441, 16442, 16443, 16444, 16445, 16446, 16447, + 16448, 16449, 16450, 16451, 16452, 16453, 16454, 16455, 16456, 16457, + 16458, 16459, 16460, 16461, 16462, 16463, 16464, 16465, 16466, 16467, + 16468, 16469, 16470, 16471, 16472, 16473, 16474, 16475, 16476, 16477, + 16478, 16479, 16480, 16481, 16482, 16483, 16484, 16485, 16486, 16487, + 16488, 16489, 16490, 16491, 16492, 16493, 16494, 16495, 16496, 16497, + 16498, 16499, 16500, 16501, 16502, 16503, 16504, 16505, 16506, 16507, + 16508, 16509, 16510, 16511, 16512, 16513, 16514, 16515, 16516, 16517, + 16518, 16519, 16520, 16521, 16522, 16523, 16524, 16525, 16526, 16527, + 16528, 16529, 16530, 16531, 16532, 16533, 16534, 16535, 16536, 16537, + 16538, 16539, 16540, 16541, 16542, 16543, 16544, 16545, 16546, 16547, + 16548, 16549, 16550, 16551, 16552, 16553, 16554, 16555, 16556, 16557, + 16558, 16559, 16560, 16561, 16562, 16563, 16564, 16565, 16566, 16567, + 16568, 16569, 16570, 16571, 16572, 16573, 16574, 16575, 16576, 16577, + 16578, 16579, 16580, 16581, 16582, 16583, 16584, 16585, 16586, 16587, + 16588, 16589, 16590, 16591, 16592, 16593, 16594, 16595, 16596, 16597, + 16598, 16599, 16600, 16601, 16602, 16603, 16604, 16605, 16606, 16607, + 16608, 16609, 16610, 16611, 16612, 16613, 16614, 16615, 16616, 16617, + 16618, 16619, 16620, 16621, 16622, 16623, 16624, 16625, 16626, 16627, + 16628, 16629, 16630, 16631, 16632, 16633, 16634, 16635, 16636, 16637, + 16638, 16639, 16640, 16641, 16642, 16643, 16644, 16645, 16646, 16647, + 16648, 16649, 16650, 16651, 16652, 16653, 16654, 16655, 16656, 16657, + 16658, 16659, 16660, 16661, 16662, 16663, 16664, 16665, 16666, 16667, + 16668, 16669, 16670, 16671, 16672, 16673, 16674, 16675, 16676, 16677, + 16678, 16679, 16680, 16681, 16682, 16683, 16684, 16685, 16686, 16687, + 16688, 16689, 16690, 16691, 16692, 16693, 16694, 16695, 16696, 16697, + 16698, 16699, 16700, 16701, 16702, 16703, 16704, 16705, 16706, 16707, + 16708, 16709, 16710, 16711, 16712, 16713, 16714, 16715, 16716, 16717, + 16718, 16719, 16720, 16721, 16722, 16723, 16724, 16725, 16726, 16727, + 16728, 16729, 16730, 16731, 16732, 16733, 16734, 16735, 16736, 16737, + 16738, 16739, 16740, 16741, 16742, 16743, 16744, 16745, 16746, 16747, + 16748, 16749, 16750, 16751, 16752, 16753, 16754, 16755, 16756, 16757, + 16758, 16759, 16760, 16761, 16762, 16763, 16764, 16765, 16766, 16767, + 16768, 16769, 16770, 16771, 16772, 16773, 16774, 16775, 16776, 16777, + 16778, 16779, 16780, 15773, 15774, 15775, 15776, 15777, 15778, 15779, + 15780, 15781, 15782, 15783, 15784, 15785, 15786, 15787, 15788, 15789, + 15790, 15791, 15792, 15793, 15794, 15795, 15796, 15797, 15798, 15799, + 15800, 15801, 15802, 15803, 15804, 15805, 15806, 15807, 15808, 15809, + 15810, 15811, 15812, 15813, 15814, 15815, 15816, 15817, 15818, 15819, + 15820, 15821, 15822, 15823, 15824, 15825, 15826, 15827, 15828, 15829, + 15830, 15831, 15832, 15833, 15834, 15835, 15836, 15837, 15838, 15839, + 15840, 15841, 15842, 15843, 15844, 15845, 15846, 15847, 15848, 15849, + 15850, 15851, 15852, 15853, 15854, 15855, 15856, 15857, 15858, 15859, + 15860, 15861, 15862, 15863, 15864, 15865, 15866, 15867, 15868, 15869, + 15870, 15871, 15872, 15873, 15874, 15875, 15876, 15877, 15878, 15879, + 15880, 15881, 15882, 15883, 15884, 15885, 15886, 15887, 15888, 15889, + 15890, 15891, 15892, 15893, 15894, 15895, 15896, 15897, 15898, 15899, + 15900, 15901, 15902, 15903, 15904, 15905, 15906, 15907, 15908, 15909, + 15910, 15911, 15912, 15913, 15914, 15915, 15916, 15917, 15918, 15919, + 15920, 15921, 15922, 15923, 15924, 15925, 15926, 15927, 15928, 15929, + 15930, 15931, 15932, 15933, 15934, 15935, 15936, 15937, 15938, 15939, + 15940, 15941, 15942, 15943, 15944, 15945, 15946, 15947, 15948, 15949, + 15950, 15951, 15952, 15953, 15954, 15955, 15956, 15957, 15958, 15959, + 15960, 15961, 15962, 15963, 15964, 15965, 15966, 15967, 15968, 15969, + 15970, 15971, 15972, 15973, 15974, 15975, 15976, 15977, 15978, 15979, + 15980, 15981, 15982, 15983, 15984, 15985, 15986, 15987, 15988, 15989, + 15990, 15991, 15992, 15993, 15994, 15995, 15996, 15997, 15998, 15999, + 16000, 16001, 16002, 16003, 16004, 16005, 16006, 16007, 16008, 16009, + 16010, 16011, 16012, 15762, 15763, 15764, 15765, 15766, 15767, 15768, + 15769, 15770, 15771, 15772, 41412, 41412, 41412, 41412, 41412, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 377, 378, 379, 380, 381, 382, 375, 376, 383, 384, + 385, 427, 428, 429, 430, 431, 432, 433, 434, 435, 425, 426, 393, 389, + 390, 394, 395, 396, 391, 392, 386, 387, 388, 397, 398, 399, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 465, 404, 405, 406, 407, 408, 409, + 400, 401, 402, 403, 410, 411, 412, 466, 467, 468, 469, 470, 471, 472, + 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 417, + 418, 419, 420, 421, 422, 423, 413, 414, 415, 416, 424, 497, 498, 499, + 500, 501, 502, 503, 486, 487, 488, 489, 494, 495, 496, 504, 490, 491, + 492, 493, 505, 506, 507, 508, 509, 512, 513, 514, 515, 510, 511, 516, + 517, 518, 519, 522, 523, 524, 525, 526, 520, 521, 527, 528, 529, 530, + 533, 534, 535, 536, 537, 531, 532, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, + 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, + 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, + 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, + 601, 609, 610, 602, 603, 604, 611, 612, 613, 614, 605, 606, 615, 607, + 608, 620, 621, 622, 623, 624, 616, 617, 618, 619, 625, 626, 627, 653, + 654, 655, 656, 657, 658, 659, 651, 652, 660, 661, 673, 674, 675, 676, + 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, + 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 664, 665, + 666, 667, 668, 669, 670, 662, 663, 671, 672, 703, 704, 705, 706, 707, + 708, 709, 710, 711, 712, 642, 643, 644, 645, 646, 647, 648, 649, 650, + 640, 641, 632, 633, 634, 635, 628, 629, 636, 637, 638, 639, 630, 631, + 715, 716, 717, 718, 719, 720, 721, 722, 723, 713, 714, 807, 808, 809, + 810, 811, 812, 813, 814, 815, 816, 726, 727, 728, 729, 730, 731, 732, + 733, 734, 724, 725, 753, 754, 750, 751, 752, 755, 756, 757, 746, 747, + 748, 749, 758, 759, 760, 817, 818, 819, 820, 821, 822, 823, 824, 825, + 826, 737, 738, 739, 740, 741, 742, 743, 744, 745, 735, 736, 765, 766, + 767, 768, 761, 762, 769, 770, 771, 763, 764, 772, 798, 796, 797, 799, + 800, 801, 802, 803, 804, 805, 806, 779, 775, 776, 780, 773, 774, 781, + 782, 777, 778, 783, 784, 785, 787, 788, 789, 786, 790, 791, 792, 793, + 794, 795, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 827, 828, + 829, 830, 831, 832, 833, 834, 835, 836, 837, 868, 869, 870, 871, 872, + 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, + 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 838, 839, 842, + 843, 844, 845, 846, 847, 840, 841, 848, 849, 898, 899, 900, 901, 902, + 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, + 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 850, 851, 852, + 853, 854, 855, 856, 857, 929, 930, 931, 932, 933, 934, 935, 936, 937, + 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, + 952, 953, 954, 955, 956, 957, 928, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 19107, 19097, 19096, 19093, 19092, 19078, 19091, 19090, 19095, 19094, + 19100, 19085, 19084, 19081, 19080, 19105, 19087, 19086, 19083, 19082, + 19079, 19099, 19098, 19089, 19088, 19102, 19106, 19103, 19101, 19104, + 19110, 19117, 19118, 19113, 19114, 19119, 19120, 19111, 19115, 19116, + 19112, 19121, 19077, 19076, 19074, 19108, 19075, 19109, 19128, 19130, + 19127, 19126, 19123, 19122, 19125, 19124, 19131, 19129, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 2892, 2858, 2917, 2918, 2888, + 2925, 2936, 2907, 2924, 2919, 2920, 2871, 2937, 2894, 2873, 2878, 2885, + 2931, 2903, 2861, 2897, 2932, 2893, 2868, 2869, 2901, 2875, 2916, 2857, + 2915, 2884, 2908, 2939, 2856, 2902, 2933, 2887, 2886, 2882, 2859, 2914, + 2891, 2921, 2874, 2911, 2922, 2938, 2866, 2928, 2935, 2876, 2862, 2890, + 2864, 2883, 2926, 2867, 2941, 2943, 2863, 2929, 2879, 2923, 2900, 2927, + 2905, 2912, 2896, 2940, 2895, 2877, 2909, 2880, 2906, 2934, 2930, 2913, + 2898, 2870, 2904, 2860, 2899, 2942, 2865, 2910, 2889, 2881, 2976, 2993, + 2991, 2990, 2954, 2960, 2949, 2997, 2959, 2951, 2984, 2996, 2953, 2980, + 2981, 2944, 2986, 2994, 2988, 2989, 2966, 2963, 2979, 2947, 2945, 2946, + 2952, 2985, 3001, 2974, 2971, 2998, 2987, 2995, 2965, 2969, 2970, 2967, + 2992, 2962, 2968, 2978, 2983, 2964, 2999, 2961, 3000, 2948, 2958, 2957, + 2955, 2972, 2977, 2956, 2950, 2975, 3053, 3073, 3095, 3091, 3052, 3041, + 3054, 3002, 3030, 3004, 3074, 3070, 3027, 3075, 3045, 3024, 3007, 3003, + 3009, 3094, 3072, 3035, 3065, 3033, 3096, 3014, 3015, 3079, 3046, 3084, + 3061, 3088, 3083, 3048, 3090, 3039, 3021, 3071, 3049, 3017, 3032, 3037, + 3068, 3085, 3051, 3099, 3042, 3067, 3064, 3098, 3089, 3029, 3100, 3057, + 3016, 3087, 3062, 3059, 3011, 3047, 3023, 3034, 3019, 3013, 3058, 3056, + 3092, 3050, 3066, 3069, 3012, 3063, 3043, 3020, 3097, 3044, 3081, 3078, + 3031, 3022, 3026, 3008, 3028, 3010, 3025, 3093, 3060, 3038, 3036, 3082, + 3006, 3005, 3055, 3040, 3018, 3076, 3077, 3086, 3128, 3212, 3161, 3135, + 3162, 3121, 3160, 3166, 3148, 3175, 3211, 3157, 3191, 3158, 3105, 3204, + 3189, 3164, 3196, 3109, 3213, 3111, 3198, 3133, 3143, 3124, 3130, 3200, + 3217, 3159, 3106, 3154, 3206, 3104, 3156, 3101, 3144, 3138, 3116, 3145, + 3140, 3139, 3181, 3137, 3134, 3122, 3167, 3126, 3114, 3173, 3202, 3201, + 3214, 3107, 3188, 3205, 3153, 3132, 3168, 3108, 3184, 3179, 3174, 3119, + 3147, 3136, 3151, 3215, 3183, 3216, 3146, 3170, 3195, 3112, 3150, 3155, + 3207, 3129, 3113, 3169, 3203, 3125, 3149, 3117, 3152, 3165, 3163, 3103, + 3110, 3185, 3209, 3208, 3176, 3187, 3118, 3131, 3123, 3197, 3142, 3193, + 3190, 3115, 3178, 3194, 3171, 3180, 3177, 3192, 3182, 3141, 3120, 3186, + 3210, 3172, 3127, 3199, 3102, 3271, 3349, 3258, 3245, 3356, 3248, 3312, + 3338, 3328, 3298, 3274, 3323, 3343, 3284, 3238, 3359, 3331, 3276, 3313, + 3348, 3240, 3250, 3300, 3290, 3255, 3287, 3291, 3299, 3330, 3297, 3316, + 3339, 3279, 3262, 3232, 3286, 3294, 3256, 3249, 3277, 3273, 3340, 3332, + 3326, 3270, 3278, 3364, 3231, 3353, 3360, 3320, 3352, 3235, 3337, 3346, + 3354, 3357, 3244, 3322, 3342, 3229, 3292, 3333, 3261, 3259, 3305, 3309, + 3228, 3351, 3239, 3372, 3303, 3365, 3260, 3272, 3318, 3368, 3247, 3221, + 3227, 3289, 3237, 3254, 3285, 3233, 3223, 3301, 3314, 3362, 3275, 3304, + 3306, 3321, 3264, 3222, 3308, 3265, 3230, 3220, 3268, 3324, 3288, 3241, + 3319, 3302, 3361, 3280, 3310, 3219, 3226, 3295, 3373, 3350, 3375, 3374, + 3246, 3311, 3341, 3344, 3269, 3336, 3363, 3282, 3369, 3366, 3367, 3371, + 3370, 3236, 3315, 3296, 3325, 3358, 3225, 3355, 3252, 3263, 3329, 3327, + 3283, 3293, 3334, 3335, 3218, 3307, 3317, 3251, 3243, 3266, 3253, 3257, + 3345, 3242, 3267, 3347, 3224, 3234, 3380, 3429, 3382, 3427, 3407, 3420, + 3401, 3384, 3410, 3409, 3389, 3419, 3399, 3395, 3386, 3417, 3412, 3418, + 3415, 3378, 3377, 3397, 3396, 3394, 3422, 3414, 3423, 3398, 3403, 3400, + 3424, 3404, 3411, 3402, 3406, 3376, 3392, 3393, 3413, 3405, 3428, 3425, + 3385, 3383, 3381, 3387, 3408, 3390, 3391, 3388, 3421, 3379, 3416, 3426, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 28399, 28391, 28412, + 28389, 28413, 28400, 28415, 28395, 28386, 28403, 28401, 28409, 28385, + 28393, 28388, 28390, 28396, 28394, 28392, 28405, 28406, 28397, 28411, + 28414, 28410, 28387, 28408, 28407, 28402, 28404, 28398, 41412, 28424, + 28426, 28423, 28422, 28419, 28418, 28421, 28420, 28427, 28425, 41412, + 41412, 41412, 41412, 28417, 28416, 36122, 36119, 36120, 36121, 36074, + 36071, 36072, 36073, 36126, 36123, 36124, 36125, 36114, 36111, 36112, + 36113, 36118, 36115, 36116, 36117, 36110, 36107, 36108, 36109, 36070, + 36067, 36068, 36069, 36102, 36099, 36100, 36101, 36075, 36080, 36091, + 36092, 36103, 36106, 36104, 36105, 36098, 36095, 36096, 36097, 36086, + 36083, 36084, 36085, 36137, 36136, 36135, 36087, 36094, 36144, 36142, + 36139, 36089, 36138, 36140, 36082, 36090, 36079, 36081, 36078, 36129, + 36133, 36141, 36088, 36093, 36131, 36128, 36134, 36077, 36127, 36143, + 36076, 36132, 36130, 36145, 41412, 36152, 36154, 36151, 36150, 36147, + 36146, 36149, 36148, 36155, 36153, 41412, 41412, 41412, 41412, 41412, + 41412, 3490, 3495, 3511, 3513, 3503, 3501, 3493, 3487, 3494, 3507, 3502, + 3498, 3509, 3492, 3488, 3510, 3497, 3508, 3512, 3506, 3500, 3514, 3499, + 3515, 3504, 3505, 3496, 3491, 3489, 3516, 41412, 41412, 3483, 3485, 3486, + 3484, 3482, 3517, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 31177, 31178, 31183, 31184, 31171, 31172, 31187, 31188, + 31179, 31180, 31169, 31170, 31189, 31190, 31173, 31174, 31185, 31186, + 31191, 31192, 31181, 31182, 31175, 31176, 31193, 31194, 31167, 31168, + 31113, 31104, 31110, 31101, 31106, 31112, 31105, 31109, 31115, 31099, + 31111, 31097, 31102, 31100, 31108, 31103, 31107, 31116, 31114, 31098, + 31121, 31120, 31118, 31117, 31119, 31123, 31122, 31153, 31154, 31132, + 31152, 31150, 31158, 31160, 31159, 31161, 31151, 31143, 31156, 31141, + 31163, 31136, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 31201, 31203, 31200, 31199, 31196, 31195, 31198, 31197, + 31204, 31202, 41412, 31128, 31125, 31127, 31130, 31124, 31126, 31129, + 41412, 31155, 31162, 31140, 31148, 31164, 31139, 31146, 31157, 31145, + 31166, 31147, 31142, 31149, 31165, 31144, 31138, 31131, 31134, 31135, + 31137, 31133, 41412, 41412, 41412, 41412, 41412, 31085, 31092, 31084, + 31083, 31093, 31081, 31078, 31096, 31088, 31086, 31094, 31080, 31079, + 31089, 31095, 31091, 31087, 31082, 31090, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 22688, 22685, 22690, 22684, 22673, 22672, 22669, 22668, + 22661, 22667, 22666, 22671, 22670, 22662, 22658, 22657, 22654, 22653, + 22660, 22659, 22656, 22655, 22663, 22675, 22674, 22665, 22664, 22680, + 22683, 22681, 22679, 22682, 22677, 22676, 22678, 22691, 22697, 22694, + 22695, 22696, 22692, 22698, 22693, 22689, 22687, 22686, 22700, 22699, + 22707, 22709, 22706, 22705, 22702, 22701, 22704, 22703, 22710, 22708, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 27062, 27066, + 27069, 27070, 27040, 27072, 27048, 27063, 27067, 27058, 27057, 27059, + 27047, 27039, 27060, 27056, 27053, 27054, 27068, 27050, 27061, 27064, + 27046, 27044, 27071, 27055, 27052, 27042, 27065, 27051, 27041, 27049, + 27120, 27124, 27127, 27128, 27098, 27130, 27106, 27121, 27125, 27116, + 27115, 27117, 27105, 27097, 27118, 27114, 27111, 27112, 27126, 27108, + 27119, 27122, 27104, 27102, 27129, 27113, 27110, 27100, 27123, 27109, + 27099, 27107, 27084, 27078, 27076, 27074, 27081, 27080, 27083, 27082, + 27086, 27085, 27089, 27091, 27088, 27087, 27092, 27093, 27095, 27096, + 27090, 27094, 27079, 27077, 27075, 27073, 27133, 27131, 27132, 41412, + 41412, 41412, 41412, 41412, 3702, 3719, 3704, 3708, 3721, 3709, 3716, + 3726, 3705, 3717, 3722, 3715, 3711, 3710, 3712, 3723, 3724, 3706, 3707, + 3714, 3713, 3718, 3725, 3720, 3703, 41412, 41412, 3727, 3744, 3729, 3733, + 3746, 3734, 3741, 3751, 3730, 3742, 3747, 3740, 3736, 3735, 3737, 3748, + 3749, 3731, 3732, 3739, 3738, 3743, 3750, 3745, 3728, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 27681, 27607, 27669, 27680, 27685, 27684, 27604, 27686, + 27661, 27660, 27658, 27615, 27664, 27665, 27657, 27614, 27623, 27631, + 27667, 27603, 27628, 27627, 27622, 27621, 27620, 27619, 27645, 27613, + 27644, 27612, 27687, 27618, 27668, 27679, 27678, 27626, 27625, 27602, + 27683, 27689, 27617, 27616, 27654, 27610, 27630, 27629, 27653, 27609, + 27662, 27666, 27638, 27641, 27642, 27676, 27674, 27655, 27611, 27663, + 27643, 27677, 27675, 27673, 27671, 27601, 27672, 27670, 27688, 27605, + 27682, 27606, 27640, 27608, 27659, 27656, 27639, 41412, 41412, 41412, + 41412, 27693, 27624, 27692, 27691, 27690, 27698, 27704, 27703, 27699, + 27700, 27725, 27729, 27746, 27745, 27707, 27710, 27711, 27727, 27714, + 27715, 27716, 27717, 27718, 27721, 27723, 27724, 27720, 27731, 27732, + 27733, 27734, 27739, 27735, 27736, 27740, 27742, 27701, 27702, 27709, + 27744, 27708, 27743, 27705, 27713, 27706, 27730, 27747, 27748, 27737, + 27741, 27728, 27726, 27749, 27722, 27712, 27719, 27738, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 27697, 27695, 27696, 27694, 27646, + 27647, 27648, 27649, 27650, 27651, 27652, 27632, 27633, 27634, 27635, + 27636, 27637, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 37039, 30032, 30253, 30252, + 22331, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 39333, 39332, 6583, 6584, 39854, 39855, 39856, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 36156, 36157, + 36158, 36159, 36160, 36161, 36162, 36163, 36164, 36165, 36166, 36167, + 36168, 36169, 36170, 36171, 36172, 36173, 36174, 36175, 36176, 36177, + 36178, 36179, 36180, 36181, 36182, 36183, 36184, 36185, 36186, 36187, + 36188, 36189, 36190, 36191, 36192, 36193, 36194, 36195, 36196, 36197, + 36198, 36199, 36200, 36201, 36202, 36203, 36204, 36205, 36206, 36207, + 36208, 36209, 36210, 36211, 36212, 36213, 36214, 36215, 36216, 36217, + 36218, 36219, 36220, 36221, 36222, 36223, 36224, 36225, 36226, 36227, + 36228, 36229, 36230, 36231, 36232, 36233, 36234, 36235, 36236, 36237, + 36238, 36239, 36240, 36241, 36242, 36243, 36244, 36245, 36246, 36247, + 36248, 36249, 36250, 36251, 36252, 36253, 36254, 36255, 36256, 36257, + 36258, 36259, 36260, 36261, 36262, 36263, 36264, 36265, 36266, 36267, + 36268, 36269, 36270, 36271, 36272, 36273, 36274, 36275, 36276, 36277, + 36278, 36279, 36280, 36281, 36282, 36283, 36284, 36285, 36286, 36287, + 36288, 36289, 36290, 36291, 36292, 36293, 36294, 36295, 36296, 36297, + 36298, 36299, 36300, 36301, 36302, 36303, 36304, 36305, 36306, 36307, + 36308, 36309, 36310, 36311, 36312, 36313, 36314, 36315, 36316, 36317, + 36318, 36319, 36320, 36321, 36322, 36323, 36324, 36325, 36326, 36327, + 36328, 36329, 36330, 36331, 36332, 36333, 36334, 36335, 36336, 36337, + 36338, 36339, 36340, 36341, 36342, 36343, 36344, 36345, 36346, 36347, + 36348, 36349, 36350, 36351, 36352, 36353, 36354, 36355, 36356, 36357, + 36358, 36359, 36360, 36361, 36362, 36363, 36364, 36365, 36366, 36367, + 36368, 36369, 36370, 36371, 36372, 36373, 36374, 36375, 36376, 36377, + 36378, 36379, 36380, 36381, 36382, 36383, 36384, 36385, 36386, 36387, + 36388, 36389, 36390, 36391, 36392, 36393, 36394, 36395, 36396, 36397, + 36398, 36399, 36400, 36401, 36402, 36403, 36404, 36405, 36406, 36407, + 36408, 36409, 36410, 36411, 36412, 36413, 36414, 36415, 36416, 36417, + 36418, 36419, 36420, 36421, 36422, 36423, 36424, 36425, 36426, 36427, + 36428, 36429, 36430, 36431, 36432, 36433, 36434, 36435, 36436, 36437, + 36438, 36439, 36440, 36441, 36442, 36443, 36444, 36445, 36446, 36447, + 36448, 36449, 36450, 36451, 36452, 36453, 36454, 36455, 36456, 36457, + 36458, 36459, 36460, 36461, 36462, 36463, 36464, 36465, 36466, 36467, + 36468, 36469, 36470, 36471, 36472, 36473, 36474, 36475, 36476, 36477, + 36478, 36479, 36480, 36481, 36482, 36483, 36484, 36485, 36486, 36487, + 36488, 36489, 36490, 36491, 36492, 36493, 36494, 36495, 36496, 36497, + 36498, 36499, 36500, 36501, 36502, 36503, 36504, 36505, 36506, 36507, + 36508, 36509, 36510, 36511, 36512, 36513, 36514, 36515, 36516, 36517, + 36518, 36519, 36520, 36521, 36522, 36523, 36524, 36525, 36526, 36527, + 36528, 36529, 36530, 36531, 36532, 36533, 36534, 36535, 36536, 36537, + 36538, 36539, 36540, 36541, 36542, 36543, 36544, 36545, 36546, 36547, + 36548, 36549, 36550, 36551, 36552, 36553, 36554, 36555, 36556, 36557, + 36558, 36559, 36560, 36561, 36562, 36563, 36564, 36565, 36566, 36567, + 36568, 36569, 36570, 36571, 36572, 36573, 36574, 36575, 36576, 36577, + 36578, 36579, 36580, 36581, 36582, 36583, 36584, 36585, 36586, 36587, + 36588, 36589, 36590, 36591, 36592, 36593, 36594, 36595, 36596, 36597, + 36598, 36599, 36600, 36601, 36602, 36603, 36604, 36605, 36606, 36607, + 36608, 36609, 36610, 36611, 36612, 36613, 36614, 36615, 36616, 36617, + 36618, 36619, 36620, 36621, 36622, 36623, 36624, 36625, 36626, 36627, + 36628, 36629, 36630, 36631, 36632, 36633, 36634, 36635, 36636, 36637, + 36638, 36639, 36640, 36641, 36642, 36643, 36644, 36645, 36646, 36647, + 36648, 36649, 36650, 36651, 36652, 36653, 36654, 36655, 36656, 36657, + 36658, 36659, 36660, 36661, 36662, 36663, 36664, 36665, 36666, 36667, + 36668, 36669, 36670, 36671, 36672, 36673, 36674, 36675, 36676, 36677, + 36678, 36679, 36680, 36681, 36682, 36683, 36684, 36685, 36686, 36687, + 36688, 36689, 36690, 36691, 36692, 36693, 36694, 36695, 36696, 36697, + 36698, 36699, 36700, 36701, 36702, 36703, 36704, 36705, 36706, 36707, + 36708, 36709, 36710, 36711, 36712, 36713, 36714, 36715, 36716, 36717, + 36718, 36719, 36720, 36721, 36722, 36723, 36724, 36725, 36726, 36727, + 36728, 36729, 36730, 36731, 36732, 36733, 36734, 36735, 36736, 36737, + 36738, 36739, 36740, 36741, 36742, 36743, 36744, 36745, 36746, 36747, + 36748, 36749, 36750, 36751, 36752, 36753, 36754, 36755, 36756, 36757, + 36758, 36759, 36760, 36761, 36762, 36763, 36764, 36765, 36766, 36767, + 36768, 36769, 36770, 36771, 36772, 36773, 36774, 36775, 36776, 36777, + 36778, 36779, 36780, 36781, 36782, 36783, 36784, 36785, 36786, 36787, + 36788, 36789, 36790, 36791, 36792, 36793, 36794, 36795, 36796, 36797, + 36798, 36799, 36800, 36801, 36802, 36803, 36804, 36805, 36806, 36807, + 36808, 36809, 36810, 36811, 36812, 36813, 36814, 36815, 36816, 36817, + 36818, 36819, 36820, 36821, 36822, 36823, 36824, 36825, 36826, 36827, + 36828, 36829, 36830, 36831, 36832, 36833, 36834, 36835, 36836, 36837, + 36838, 36839, 36840, 36841, 36842, 36843, 36844, 36845, 36846, 36847, + 36848, 36849, 36850, 36851, 36852, 36853, 36854, 36855, 36856, 36857, + 36858, 36859, 36860, 36861, 36862, 36863, 36864, 36865, 36866, 36867, + 36868, 36869, 36870, 36871, 36872, 36873, 36874, 36875, 36876, 36877, + 36878, 36879, 36880, 36881, 36882, 36883, 36884, 36885, 36886, 36887, + 36888, 36889, 36890, 36891, 36892, 36893, 36894, 36895, 36896, 36897, + 36898, 36899, 36900, 36901, 36902, 36903, 36904, 36905, 36906, 36907, + 36908, 36909, 36910, 36911, 36912, 36913, 36914, 36915, 36916, 36917, + 36918, 36919, 36920, 36921, 36922, 36923, 21860, 21861, 21862, 21863, + 21864, 21865, 21866, 21867, 21868, 21869, 21870, 21871, 21872, 21873, + 21874, 21875, 21876, 21877, 21878, 21879, 21880, 21881, 21882, 21883, + 21884, 21885, 21886, 21887, 21888, 21889, 21890, 21891, 21892, 21893, + 21894, 21895, 21896, 21897, 21898, 21899, 21900, 21901, 21902, 21903, + 21904, 21905, 21906, 21907, 21908, 21909, 21910, 21911, 21912, 21913, + 21914, 21915, 21916, 21917, 21918, 21919, 21920, 21921, 21922, 21923, + 21924, 21925, 21926, 21927, 21928, 21929, 21930, 21931, 21932, 21933, + 21934, 21935, 21936, 21937, 21938, 21939, 21940, 21941, 21942, 21943, + 21944, 21945, 21946, 21947, 21948, 21949, 21950, 21951, 21952, 21953, + 21954, 21955, 21956, 21957, 21958, 21959, 21960, 21961, 21962, 21963, + 21964, 21965, 21966, 21967, 21968, 21969, 21970, 21971, 21972, 21973, + 21974, 21975, 21976, 21977, 21978, 21979, 21980, 21981, 21982, 21983, + 21984, 21985, 21986, 21987, 21988, 21989, 21990, 21991, 21992, 21993, + 21994, 21995, 21996, 21997, 21998, 21999, 22000, 22001, 22002, 22003, + 22004, 22005, 22006, 22007, 22008, 22009, 22010, 22011, 22012, 22013, + 22014, 22015, 22016, 22017, 22018, 22019, 22020, 22021, 22022, 22023, + 22024, 22025, 22026, 22027, 22028, 22029, 22030, 22031, 22032, 22033, + 22034, 22035, 22036, 22037, 22038, 22039, 22040, 22041, 22042, 22043, + 22044, 22045, 22046, 22047, 22048, 22049, 22050, 22051, 22052, 22053, + 22054, 22055, 22056, 22057, 22058, 22059, 22060, 22061, 22062, 22063, + 22064, 22065, 22066, 22067, 22068, 22069, 22070, 22071, 22072, 22073, + 22074, 22075, 22076, 22077, 22078, 22079, 22080, 22081, 22082, 22083, + 22084, 22085, 22086, 22087, 22088, 22089, 22090, 22091, 22092, 22093, + 22094, 22095, 22096, 22097, 22098, 22099, 22100, 22101, 22102, 22103, + 22104, 22105, 22106, 22107, 22108, 22109, 22110, 22111, 22112, 22113, + 22114, 22115, 22122, 22123, 22124, 22125, 22126, 22127, 22128, 22129, + 22130, 22131, 22132, 22133, 22134, 22135, 22136, 22137, 22138, 22139, + 22140, 22141, 22142, 22143, 22144, 22145, 22146, 22147, 22148, 22149, + 22150, 22151, 22152, 22153, 22154, 22155, 22156, 22157, 22158, 22159, + 22160, 22161, 22162, 22163, 22164, 22165, 22166, 22167, 22168, 22169, + 22170, 22171, 22172, 22173, 22174, 22175, 22176, 22177, 22178, 22179, + 22180, 22181, 22182, 22183, 22184, 22185, 22186, 22187, 22188, 22189, + 22190, 22191, 22192, 22193, 22194, 22195, 22196, 22197, 22198, 22199, + 22200, 22201, 22202, 22203, 22204, 22205, 22206, 22207, 22208, 22209, + 22210, 22211, 22212, 22213, 22214, 22215, 22216, 22217, 22218, 22219, + 22220, 22221, 22222, 22223, 22224, 22225, 22226, 22227, 22228, 22229, + 22230, 22231, 22232, 22233, 22234, 22235, 22236, 22237, 22238, 22239, + 22240, 22241, 22242, 22243, 22244, 22245, 22246, 22247, 22248, 22249, + 22250, 22251, 22252, 22253, 22254, 22255, 22256, 22257, 22258, 22259, + 22260, 22261, 22262, 22263, 22264, 22265, 22266, 22267, 22268, 22269, + 22270, 22271, 22272, 22273, 22274, 22275, 22276, 22277, 22278, 22279, + 22280, 22281, 22282, 22283, 22284, 22285, 22286, 22287, 22288, 22289, + 22290, 22291, 22292, 22293, 22294, 22295, 22296, 22297, 22298, 22299, + 22300, 22301, 22302, 22303, 22304, 22305, 22306, 22307, 22308, 22309, + 22310, 22311, 22312, 22313, 22314, 22315, 22316, 22317, 22318, 22319, + 22320, 22321, 22322, 22323, 22324, 22325, 22326, 22327, 22328, 22329, + 22116, 22117, 22118, 22119, 22120, 22121, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 22330, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 36924, 36925, 36926, 36927, + 36928, 36929, 36930, 36931, 36932, 36933, 36934, 36935, 36936, 36937, + 36938, 36939, 36940, 36941, 36942, 36943, 36944, 36945, 36946, 36947, + 36948, 36949, 36950, 36951, 36952, 36953, 36954, 36955, 36956, 36957, + 36958, 36959, 36960, 36961, 36962, 36963, 36964, 36965, 36966, 36967, + 36968, 36969, 36970, 36971, 36972, 36973, 36974, 36975, 36976, 36977, + 36978, 36979, 36980, 36981, 36982, 36983, 36984, 36985, 36986, 36987, + 36988, 36989, 36990, 36991, 36992, 36993, 36994, 36995, 36996, 36997, + 36998, 36999, 37000, 37001, 37002, 37003, 37004, 37005, 37006, 37007, + 37008, 37009, 37010, 37011, 37012, 37013, 37014, 37015, 37016, 37017, + 37018, 37019, 37020, 37021, 37022, 37023, 37024, 37025, 37026, 37027, + 37028, 37029, 37030, 37031, 37032, 37033, 37034, 37035, 37036, 37037, + 37038, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 21499, 21500, 21501, 21502, 41412, 21503, + 21504, 21492, 21493, 21494, 21495, 21496, 41412, 21497, 21498, 41412, + 21480, 20452, 20091, 20092, 20093, 20090, 20372, 20373, 20374, 20375, + 20364, 20365, 20366, 20367, 20368, 20359, 20360, 20361, 20362, 20363, + 20369, 20370, 20371, 20130, 20134, 20135, 20136, 20137, 20138, 20139, + 20140, 20141, 20131, 20132, 20133, 20146, 20147, 20148, 20149, 20150, + 20151, 20152, 20153, 20160, 20161, 20162, 20163, 20164, 20165, 20166, + 20154, 20155, 20156, 20157, 20158, 20159, 20143, 20144, 20145, 20142, + 20255, 20256, 20257, 20258, 20259, 20260, 20261, 20262, 20271, 20272, + 20273, 20274, 20275, 20276, 20263, 20264, 20265, 20266, 20267, 20268, + 20269, 20270, 20277, 20278, 20279, 20280, 20281, 20282, 20283, 20284, + 20285, 20286, 20287, 20288, 20317, 20318, 20319, 20320, 20310, 20311, + 20312, 20313, 20314, 20315, 20316, 20306, 20307, 20308, 20309, 20305, + 20289, 20290, 20291, 20292, 20293, 20294, 20295, 20296, 20297, 20299, + 20300, 20301, 20302, 20303, 20304, 20298, 20209, 20210, 20211, 20212, + 20213, 20214, 20215, 20216, 20217, 20202, 20203, 20204, 20205, 20206, + 20207, 20208, 20201, 20223, 20224, 20225, 20195, 20196, 20197, 20198, + 20199, 20200, 20194, 20218, 20219, 20220, 20221, 20222, 20102, 20105, + 20106, 20107, 20108, 20109, 20110, 20111, 20112, 20103, 20104, 20123, + 20124, 20125, 20126, 20127, 20128, 20129, 20113, 20114, 20115, 20116, + 20117, 20118, 20119, 20120, 20121, 20122, 20094, 20095, 20096, 20097, + 20098, 20099, 20100, 20101, 20176, 20177, 20178, 20179, 20180, 20181, + 20182, 20183, 20184, 20185, 20186, 20187, 20188, 20189, 20190, 20191, + 20192, 20193, 20168, 20169, 20167, 20170, 20171, 20172, 20173, 20174, + 20175, 20343, 20344, 20345, 20346, 20347, 20342, 20354, 20355, 20356, + 20357, 20348, 20349, 20350, 20351, 20352, 20353, 20247, 20248, 20249, + 20250, 20240, 20241, 20242, 20243, 20244, 20245, 20246, 20234, 20235, + 20236, 20237, 20238, 20239, 20251, 20252, 20253, 20254, 20228, 20229, + 20230, 20231, 20232, 20233, 20321, 20322, 20323, 20324, 20325, 20326, + 20327, 20328, 20329, 20330, 20338, 20339, 20340, 20341, 20331, 20332, + 20333, 20334, 20335, 20336, 20337, 20226, 20227, 20451, 21478, 21477, + 21479, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 20462, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 20455, 20454, 20456, 41412, + 41412, 21527, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 21533, 21532, 21534, 21538, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 29636, 29637, + 29638, 29639, 29640, 29641, 29642, 29643, 29644, 29645, 29646, 29647, + 29648, 29649, 29650, 29651, 29652, 29653, 29654, 29655, 29656, 29657, + 29658, 29659, 29660, 29661, 29662, 29663, 29664, 29665, 29666, 29667, + 29668, 29669, 29670, 29671, 29672, 29673, 29674, 29675, 29676, 29677, + 29678, 29679, 29680, 29681, 29682, 29683, 29684, 29685, 29686, 29687, + 29688, 29689, 29690, 29691, 29692, 29693, 29694, 29695, 29696, 29697, + 29698, 29699, 29700, 29701, 29702, 29703, 29704, 29705, 29706, 29707, + 29708, 29709, 29710, 29711, 29712, 29713, 29714, 29715, 29716, 29717, + 29718, 29719, 29720, 29721, 29722, 29723, 29724, 29725, 29726, 29727, + 29728, 29729, 29730, 29731, 29732, 29733, 29734, 29735, 29736, 29737, + 29738, 29739, 29740, 29741, 29742, 29743, 29744, 29745, 29746, 29747, + 29748, 29749, 29750, 29751, 29752, 29753, 29754, 29755, 29756, 29757, + 29758, 29759, 29760, 29761, 29762, 29763, 29764, 29765, 29766, 29767, + 29768, 29769, 29770, 29771, 29772, 29773, 29774, 29775, 29776, 29777, + 29778, 29779, 29780, 29781, 29782, 29783, 29784, 29785, 29786, 29787, + 29788, 29789, 29790, 29791, 29792, 29793, 29794, 29795, 29796, 29797, + 29798, 29799, 29800, 29801, 29802, 29803, 29804, 29805, 29806, 29807, + 29808, 29809, 29810, 29811, 29812, 29813, 29814, 29815, 29816, 29817, + 29818, 29819, 29820, 29821, 29822, 29823, 29824, 29825, 29826, 29827, + 29828, 29829, 29830, 29831, 29832, 29833, 29834, 29835, 29836, 29837, + 29838, 29839, 29840, 29841, 29842, 29843, 29844, 29845, 29846, 29847, + 29848, 29849, 29850, 29851, 29852, 29853, 29854, 29855, 29856, 29857, + 29858, 29859, 29860, 29861, 29862, 29863, 29864, 29865, 29866, 29867, + 29868, 29869, 29870, 29871, 29872, 29873, 29874, 29875, 29876, 29877, + 29878, 29879, 29880, 29881, 29882, 29883, 29884, 29885, 29886, 29887, + 29888, 29889, 29890, 29891, 29892, 29893, 29894, 29895, 29896, 29897, + 29898, 29899, 29900, 29901, 29902, 29903, 29904, 29905, 29906, 29907, + 29908, 29909, 29910, 29911, 29912, 29913, 29914, 29915, 29916, 29917, + 29918, 29919, 29920, 29921, 29922, 29923, 29924, 29925, 29926, 29927, + 29928, 29929, 29930, 29931, 29932, 29933, 29934, 29935, 29936, 29937, + 29938, 29939, 29940, 29941, 29942, 29943, 29944, 29945, 29946, 29947, + 29948, 29949, 29950, 29951, 29952, 29953, 29954, 29955, 29956, 29957, + 29958, 29959, 29960, 29961, 29962, 29963, 29964, 29965, 29966, 29967, + 29968, 29969, 29970, 29971, 29972, 29973, 29974, 29975, 29976, 29977, + 29978, 29979, 29980, 29981, 29982, 29983, 29984, 29985, 29986, 29987, + 29988, 29989, 29990, 29991, 29992, 29993, 29994, 29995, 29996, 29997, + 29998, 29999, 30000, 30001, 30002, 30003, 30004, 30005, 30006, 30007, + 30008, 30009, 30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017, + 30018, 30019, 30020, 30021, 30022, 30023, 30024, 30025, 30026, 30027, + 30028, 30029, 30030, 30031, 41412, 41412, 41412, 41412, 11649, 11647, + 11596, 11629, 11556, 11569, 11573, 11654, 11550, 11637, 11558, 11600, + 11599, 11551, 11557, 11571, 11603, 11632, 11625, 11552, 11572, 11626, + 11650, 11576, 11604, 11577, 11582, 11560, 11605, 11578, 11583, 11563, + 11606, 11580, 11585, 11561, 11562, 11614, 11615, 11581, 11586, 11567, + 11618, 11579, 11584, 11564, 11607, 11568, 11565, 11566, 11612, 11613, + 11610, 11611, 11631, 11630, 11639, 11645, 11642, 11617, 11616, 11570, + 11559, 11608, 11609, 11548, 11623, 11593, 11591, 11549, 11651, 11553, + 11652, 11628, 11636, 11554, 11620, 11601, 11619, 11574, 11653, 11633, + 11555, 11648, 11634, 11575, 11602, 11635, 11627, 11592, 11595, 11594, + 11644, 11640, 11646, 11643, 11641, 11590, 11589, 11588, 11587, 11598, + 11597, 11621, 11624, 11622, 11638, 41412, 41412, 41412, 41412, 41412, + 11533, 11546, 11545, 11540, 11547, 11527, 11520, 11519, 11516, 11518, + 11521, 11522, 11517, 41412, 41412, 41412, 11529, 11525, 11528, 11523, + 11532, 11531, 11524, 11530, 11526, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 11534, 11538, 11541, 11536, 11544, 11543, 11537, 11542, + 11539, 11535, 41412, 41412, 11658, 11655, 11656, 11657, 33036, 33035, + 33037, 33038, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 38247, 32227, 24339, 32224, 11423, 25347, + 32195, 25405, 967, 20587, 39302, 24297, 27756, 32180, 24332, 32217, + 30107, 31773, 31965, 20583, 39276, 25287, 25286, 25285, 25284, 25282, + 25283, 4587, 4588, 4596, 4610, 4480, 4479, 32766, 32774, 32767, 32778, + 32771, 32775, 32768, 32780, 32773, 32777, 32770, 32779, 32772, 32776, + 32769, 38286, 38254, 38256, 38341, 38303, 38299, 38335, 38305, 25431, + 25378, 25398, 25433, 25381, 25423, 25425, 25404, 34309, 34310, 30835, + 10972, 10708, 10707, 34321, 34322, 24345, 32204, 17621, 17622, 352, 351, + 358, 357, 360, 359, 355, 356, 353, 354, 24335, 38239, 32220, 11429, + 37913, 37909, 37917, 4442, 4440, 4446, 24328, 38234, 32214, 11425, 28480, + 24338, 38242, 32223, 11432, 16787, 16788, 3944, 3947, 3946, 3945, 3978, + 24351, 38232, 32210, 11435, 24352, 38233, 32211, 11436, 24341, 38236, + 32226, 11427, 34554, 34555, 34553, 34552, 34746, 34748, 34747, 34745, + 39286, 20566, 39699, 39700, 38159, 34386, 34385, 34384, 34339, 20962, + 24211, 20963, 39291, 20564, 24346, 32205, 24347, 32206, 17606, 24337, + 38241, 32222, 11431, 20586, 39301, 39279, 24340, 32225, 24334, 32219, + 24336, 32221, 24245, 32138, 38295, 38331, 38294, 38330, 25367, 25387, + 25366, 25386, 25364, 25384, 25365, 25385, 38298, 38334, 25377, 25397, + 38296, 38332, 25376, 25396, 38289, 38325, 25371, 25391, 38292, 38328, + 25374, 25394, 38293, 38329, 25375, 25395, 38288, 38324, 25370, 25390, + 38290, 38326, 25372, 25392, 38291, 38327, 25373, 25393, 38297, 38333, + 25368, 25388, 31013, 31014, 31015, 31016, 31017, 31018, 31019, 31020, + 31021, 31022, 31023, 31024, 31025, 31026, 31027, 31028, 31029, 31030, + 31031, 31032, 31033, 31034, 31035, 31036, 31037, 31038, 31049, 31051, + 31048, 31047, 31044, 31043, 31046, 31045, 31052, 31050, 34090, 17623, + 29621, 41412, 41412, 41412, 4239, 4183, 4054, 4269, 4140, 4081, 4240, + 4121, 4184, 4230, 4156, 4215, 4097, 4112, 4200, 4066, 4273, 4141, 4171, + 4082, 4241, 4122, 4185, 4055, 4236, 4164, 4223, 4105, 4262, 4118, 4208, + 4074, 4149, 4177, 4090, 4248, 4130, 4193, 4060, 4231, 4157, 4216, 4098, + 4255, 4113, 4201, 4067, 4274, 4142, 4172, 4083, 4242, 4123, 4186, 4168, + 4227, 4109, 4266, 4137, 4212, 4078, 4281, 4153, 4180, 4094, 4252, 4134, + 4197, 4063, 4161, 4220, 4102, 4259, 4205, 4071, 4278, 4146, 4087, 4245, + 4127, 4190, 4237, 4165, 4224, 4106, 4263, 4119, 4209, 4075, 4270, 4150, + 4178, 4091, 4249, 4131, 4194, 4061, 4232, 4158, 4217, 4099, 4256, 4114, + 4202, 4068, 4275, 4143, 4173, 4084, 4243, 4124, 4187, 4056, 4170, 4229, + 4111, 4268, 4139, 4214, 4080, 4283, 4155, 4182, 4096, 4254, 4136, 4199, + 4065, 4235, 4163, 4222, 4104, 4261, 4117, 4207, 4073, 4280, 4148, 4176, + 4089, 4247, 4129, 4192, 4059, 4167, 4226, 4108, 4265, 4211, 4077, 4272, + 4152, 4093, 4251, 4133, 4196, 4233, 4160, 4219, 4101, 4258, 4115, 4204, + 4070, 4277, 4145, 4174, 4086, 4244, 4126, 4189, 4057, 4169, 4228, 4110, + 4267, 4138, 4213, 4079, 4282, 4154, 4181, 4095, 4253, 4135, 4198, 4064, + 4234, 4162, 4221, 4103, 4260, 4116, 4206, 4072, 4279, 4147, 4175, 4088, + 4246, 4128, 4191, 4058, 4238, 4166, 4225, 4107, 4264, 4120, 4210, 4076, + 4271, 4151, 4179, 4092, 4250, 4132, 4195, 4062, 4159, 4218, 4100, 4257, + 4203, 4069, 4276, 4144, 4085, 4125, 4188, 37921, 4449, 37918, 4447, + 37919, 4448, 37914, 4443, 37915, 4444, 37908, 4436, 4437, 4438, 4439, + 28364, 37910, 37911, 11426, 24329, 34060, 38237, 11428, 17492, 17493, + 17494, 32133, 25338, 17495, 38261, 25340, 19942, 39761, 37932, 17779, + 4481, 4478, 24249, 32142, 24248, 32141, 20563, 24246, 32139, 20562, + 25341, 38264, 39292, 4606, 4604, 4605, 4603, 22883, 22882, 22887, 22881, + 22859, 22838, 22839, 22879, 22845, 22863, 22886, 22861, 22884, 22885, + 22867, 22864, 22844, 22843, 22846, 22862, 22847, 22835, 22856, 22880, + 22836, 22837, 22834, 22860, 22865, 22851, 22842, 22866, 22868, 22841, + 22858, 22850, 22848, 22849, 22840, 22888, 22857, 22852, 22855, 22853, + 22854, 22876, 22874, 22875, 22878, 22873, 22870, 22877, 22872, 22871, + 22869, 32781, 32813, 32782, 32829, 32798, 32814, 32783, 32837, 32806, + 32822, 32791, 32830, 32799, 32815, 32784, 32841, 32810, 32826, 32795, + 32834, 32803, 32819, 32788, 32838, 32807, 32823, 32792, 32831, 32800, + 32816, 32785, 32843, 32812, 32828, 32797, 32836, 32805, 32821, 32790, + 32840, 32809, 32825, 32794, 32833, 32802, 32818, 32787, 32842, 32811, + 32827, 32796, 32835, 32804, 32820, 32789, 32839, 32808, 32824, 32793, + 32832, 32801, 32817, 32786, 38281, 38253, 38255, 38320, 38302, 38300, + 38301, 38304, 25430, 25428, 25429, 25432, 25383, 25422, 25424, 25418, + 32143, 32183, 24300, 24250, 25343, 25438, 38344, 38266, 24251, 24301, + 32184, 32144, 38267, 38345, 25439, 25344, 20588, 21790, 30522, 3984, + 41412, 41412, 41412, 41412, 41412, 41412, 17659, 31062, 37993, 1057, + 6577, 34742, 20085, 20984, 17611, 27599, 31398, 39328, 16781, 20983, + 17487, 31902, 37387, 27244, 17637, 2574, 3597, 369, 24565, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 17878, 17875, 17867, 17873, 17879, 17865, 17871, + 17868, 17874, 17870, 17866, 17876, 17872, 17877, 17869, 17880, 27156, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41228, 41233, 41267, 41230, 41235, + 41263, 41257, 41251, 41274, 41253, 41247, 41271, 41229, 41234, 41268, + 41231, 41236, 41264, 41258, 41252, 41275, 41254, 41248, 41272, 41269, + 41255, 41262, 41249, 41250, 41273, 41256, 41232, 41278, 41243, 41260, + 41270, 41281, 41280, 41246, 41279, 41240, 41239, 41277, 41261, 41259, + 41238, 41412, 41412, 41283, 41284, 41285, 41276, 41226, 41241, 41244, + 41245, 41223, 41224, 41242, 41265, 41266, 41227, 41282, 41225, 41237, + 41222, 41404, 41405, 41402, 41403, 41406, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41302, 41303, 41319, 41291, 41300, + 41399, 41354, 41355, 41322, 41323, 41356, 41286, 41320, 41400, 41298, + 41295, 41297, 41296, 41294, 41396, 41395, 41398, 41397, 41392, 41391, + 41394, 41393, 41292, 41326, 41288, 41299, 41287, 41324, 41337, 41338, + 41336, 41335, 41289, 41333, 41334, 41332, 41330, 41331, 41329, 41328, + 41339, 41341, 41342, 41340, 41304, 41327, 41293, 41301, 41401, 41343, + 41348, 41345, 41349, 41346, 41351, 41352, 41347, 41344, 41350, 41325, + 41353, 41386, 41383, 41374, 41384, 41385, 41375, 41363, 41362, 41390, + 41360, 41359, 41357, 41361, 41358, 41377, 41382, 41376, 41380, 41381, + 41378, 41379, 41306, 41310, 41309, 41308, 41307, 41389, 41387, 41388, + 41313, 41318, 41317, 41316, 41315, 41314, 41364, 41373, 41366, 41371, + 41365, 41369, 41370, 41367, 41368, 41372, 41305, 41312, 41290, 41311, + 41321, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 5296, 5168, 5289, 5271, 5272, 5340, 5341, 5221, 5318, 5278, 5352, + 5353, 5244, 5123, 5174, 5321, 5222, 5126, 5127, 5316, 5328, 5267, 5204, + 5295, 5147, 5344, 5216, 5230, 5226, 5319, 5281, 5310, 5274, 5343, 5129, + 5131, 5231, 5297, 5282, 5339, 5121, 5299, 5313, 5315, 5269, 5323, 5251, + 5169, 5331, 5322, 5241, 5122, 5181, 5212, 5333, 5219, 5287, 5291, 5234, + 5145, 5298, 5276, 5279, 5218, 5356, 5286, 5235, 5334, 5311, 5210, 5217, + 5268, 5273, 5285, 5237, 5284, 5242, 5288, 5225, 5229, 5355, 5128, 5124, + 5354, 5243, 5177, 5148, 5266, 5342, 5283, 5292, 5275, 5120, 5252, 5280, + 5277, 5173, 5245, 5119, 5335, 5176, 5314, 5317, 5146, 5175, 5300, 5357, + 5337, 5293, 5332, 5336, 5290, 5338, 5294, 5207, 5133, 5172, 5270, 5325, + 5326, 5324, 5327, 5220, 5170, 5345, 5346, 5309, 5233, 5166, 5238, 5239, + 5240, 5130, 5132, 5165, 5330, 5320, 5236, 5246, 5250, 5249, 5248, 5247, + 5206, 5203, 5202, 5160, 5162, 5163, 5161, 5329, 5134, 5214, 5153, 5117, + 5111, 5112, 5115, 5116, 5114, 5113, 5118, 5259, 5254, 5255, 5253, 5264, + 5263, 5262, 5261, 5265, 5257, 5215, 5125, 5180, 5179, 5178, 5260, 5258, + 5256, 5208, 5209, 5171, 5213, 5211, 5182, 5189, 5185, 5193, 5188, 5197, + 5187, 5186, 5183, 5184, 5191, 5192, 5199, 5196, 5194, 5143, 5144, 5142, + 5190, 5198, 5351, 5156, 5154, 5157, 5159, 5158, 5155, 5347, 5349, 5348, + 5350, 5200, 5201, 5150, 5149, 5151, 5152, 5305, 5308, 5306, 5307, 5301, + 5304, 5302, 5303, 5164, 5167, 5312, 5141, 5135, 5140, 5138, 5137, 5136, + 5139, 5223, 5227, 5224, 5228, 5232, 5205, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 28669, 28546, 28562, 28654, + 28541, 28666, 28604, 28655, 28653, 28542, 28538, 28665, 28532, 28650, + 28651, 28652, 28557, 28558, 28495, 28496, 28491, 28490, 28621, 28692, + 28689, 28564, 28563, 28670, 28671, 28565, 28574, 28575, 28576, 28535, + 28567, 28568, 28569, 28548, 28549, 41412, 41412, 28612, 28545, 28547, + 28573, 28572, 28617, 28616, 28668, 28667, 28644, 28645, 28531, 28537, + 28633, 28634, 28648, 28649, 28613, 28715, 28587, 28647, 28556, 28673, + 28691, 28675, 28620, 28713, 28636, 28536, 28676, 28677, 28700, 28701, + 28704, 28705, 28702, 28703, 28696, 28697, 28698, 28699, 28610, 28611, + 28706, 28707, 28635, 28711, 28618, 28615, 28499, 28500, 28494, 28714, + 28586, 28646, 28555, 28672, 28690, 28674, 28619, 28520, 28521, 28524, + 28525, 28526, 28559, 28560, 28561, 28503, 28510, 28511, 28512, 28513, + 28514, 28488, 28553, 28489, 28554, 28487, 28551, 28486, 28550, 28501, + 28519, 28527, 28518, 28504, 28505, 28502, 28529, 28584, 28583, 28508, + 28530, 28515, 28522, 28528, 28507, 28523, 28656, 28679, 28718, 28643, + 28606, 28566, 28534, 28543, 28580, 28579, 28695, 28708, 28717, 28709, + 28710, 28622, 28625, 28626, 28627, 28628, 28629, 28630, 28631, 28632, + 28623, 28624, 28588, 28614, 28552, 28544, 28506, 28509, 28516, 28517, + 28638, 28637, 28585, 28578, 28577, 28716, 28539, 28540, 28605, 28601, + 28492, 28659, 28661, 28607, 28609, 28662, 28664, 28570, 28571, 28603, + 28602, 28493, 28660, 28608, 28663, 28687, 28686, 28688, 28685, 28681, + 28682, 28683, 28684, 28533, 28581, 28582, 28678, 28712, 28640, 28498, + 28657, 28497, 28693, 28641, 28642, 28658, 28694, 28639, 28589, 28592, + 28596, 28599, 28598, 28597, 28593, 28594, 28590, 28591, 28595, 28680, + 28600, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 18793, 18781, 18804, 18805, 18787, 18806, 18807, 18808, + 18809, 18794, 18795, 18796, 18797, 18798, 18799, 18800, 18801, 18802, + 18803, 18782, 18783, 18784, 18785, 18786, 18788, 18789, 18790, 18791, + 18792, 18513, 18521, 18534, 18542, 18548, 18549, 18514, 18515, 18516, + 18517, 18518, 18519, 18520, 18522, 18523, 18524, 18525, 18526, 18527, + 18528, 18529, 18530, 18531, 18532, 18533, 18535, 18536, 18537, 18538, + 18539, 18540, 18541, 18543, 18544, 18545, 18546, 18547, 8387, 8386, 8388, + 18573, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 21770, 21771, 21768, 21766, 21757, 21756, 21763, + 21761, 21752, 21759, 21769, 21754, 21767, 21765, 21758, 21755, 21764, + 21762, 21753, 21760, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 27020, 27021, 27018, 27016, 27007, + 27006, 27013, 27011, 27002, 27009, 27019, 27004, 27017, 27015, 27008, + 27005, 27014, 27012, 27003, 27010, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 28357, 11017, 11018, + 11012, 11011, 11010, 37181, 37201, 37222, 37170, 37215, 37179, 37165, + 37224, 37169, 37183, 37189, 37212, 37213, 37227, 37233, 37180, 37211, + 37241, 37199, 37166, 37229, 37231, 37198, 37244, 37178, 37193, 37190, + 37171, 37185, 37168, 37226, 37219, 37173, 37216, 37205, 37239, 37228, + 37202, 37230, 37218, 37232, 37207, 37195, 37238, 37208, 37194, 37225, + 37234, 37204, 37240, 37177, 37221, 37197, 37243, 37187, 37172, 37209, + 37206, 37220, 37164, 37192, 37191, 37242, 37236, 37214, 37184, 37182, + 37188, 37196, 37235, 37237, 37210, 37176, 37174, 37203, 37167, 37175, + 37223, 37186, 37217, 37200, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 8801, 8799, 8798, 8795, 8794, 8797, 8796, 8802, + 8800, 8792, 8790, 8789, 8786, 8785, 8788, 8787, 8793, 8791, 20675, 20674, + 20673, 20672, 20671, 35650, 35649, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 26000, 26002, 26030, 25993, 26006, 26038, 26009, 26039, 26011, 26040, + 26013, 26015, 26032, 26034, 26017, 26020, 26041, 26024, 26026, 25996, + 26028, 26042, 26043, 26036, 26044, 26004, 26048, 26050, 26083, 26045, + 26054, 26057, 26059, 26091, 26061, 26092, 26063, 26065, 26085, 26087, + 26067, 26070, 26093, 26074, 26076, 26078, 26081, 26094, 26095, 26089, + 26096, 26052, 26488, 26490, 26520, 26494, 26496, 26528, 26499, 26529, + 26501, 26530, 26503, 26505, 26522, 26524, 26507, 26510, 26531, 26514, + 26516, 26484, 26518, 26532, 26533, 26526, 26534, 26492, 26436, 26438, + 26471, 26432, 26442, 26445, 26447, 41412, 26449, 26479, 26451, 26453, + 26473, 26475, 26455, 26458, 26480, 26462, 26464, 26466, 26469, 26481, + 26482, 26477, 26483, 26440, 26153, 26155, 26185, 26159, 26161, 26193, + 26164, 26194, 26166, 26195, 26168, 26170, 26187, 26189, 26172, 26175, + 26196, 26179, 26181, 26149, 26183, 26197, 26198, 26191, 26199, 26157, + 26207, 26209, 26244, 26213, 26215, 26218, 26220, 26252, 26222, 26253, + 26224, 26226, 26246, 26248, 26228, 26231, 26254, 26235, 26237, 26239, + 26242, 26255, 26256, 26250, 26257, 26211, 26960, 41412, 26961, 26962, + 41412, 41412, 26963, 41412, 41412, 26964, 26965, 41412, 41412, 26966, + 26967, 26968, 26969, 41412, 26970, 26971, 26972, 26973, 26974, 26975, + 26976, 26977, 26978, 26979, 26980, 26981, 41412, 26982, 41412, 26983, + 26984, 26985, 26986, 26987, 26988, 26989, 41412, 26990, 26991, 26992, + 26993, 26994, 26995, 26996, 26997, 26998, 26999, 27000, 26097, 26098, + 26099, 26100, 26101, 26102, 26103, 26104, 26105, 26106, 26107, 26108, + 26109, 26110, 26111, 26112, 26113, 26114, 26115, 26116, 26117, 26118, + 26119, 26120, 26121, 26122, 26123, 26124, 26125, 26126, 26127, 26128, + 26129, 26130, 26131, 26132, 26133, 26134, 26135, 26136, 26137, 26138, + 26139, 26140, 26141, 26142, 26143, 26144, 26145, 26146, 26147, 26148, + 26384, 26385, 41412, 26386, 26387, 26388, 26389, 41412, 41412, 26390, + 26391, 26392, 26393, 26394, 26395, 26396, 26397, 41412, 26398, 26399, + 26400, 26401, 26402, 26403, 26404, 41412, 26405, 26406, 26407, 26408, + 26409, 26410, 26411, 26412, 26413, 26414, 26415, 26416, 26417, 26418, + 26419, 26420, 26421, 26422, 26423, 26424, 26425, 26426, 26427, 26428, + 26429, 26430, 26329, 26330, 41412, 26331, 26332, 26333, 26334, 41412, + 26335, 26336, 26337, 26338, 26339, 41412, 26340, 41412, 41412, 41412, + 26341, 26342, 26343, 26344, 26345, 26346, 26347, 41412, 26348, 26349, + 26350, 26351, 26352, 26353, 26354, 26355, 26356, 26357, 26358, 26359, + 26360, 26361, 26362, 26363, 26364, 26365, 26366, 26367, 26368, 26369, + 26370, 26371, 26372, 26373, 26267, 26268, 26269, 26270, 26271, 26272, + 26273, 26274, 26275, 26276, 26277, 26278, 26279, 26280, 26281, 26282, + 26283, 26284, 26285, 26286, 26287, 26288, 26289, 26290, 26291, 26292, + 26293, 26294, 26295, 26296, 26297, 26298, 26299, 26300, 26301, 26302, + 26303, 26304, 26305, 26306, 26307, 26308, 26309, 26310, 26311, 26312, + 26313, 26314, 26315, 26316, 26317, 26318, 26898, 26899, 26900, 26901, + 26902, 26903, 26904, 26905, 26906, 26907, 26908, 26909, 26910, 26911, + 26912, 26913, 26914, 26915, 26916, 26917, 26918, 26919, 26920, 26921, + 26922, 26923, 26924, 26925, 26926, 26927, 26928, 26929, 26930, 26931, + 26932, 26933, 26934, 26935, 26936, 26937, 26938, 26939, 26940, 26941, + 26942, 26943, 26944, 26945, 26946, 26947, 26948, 26949, 26730, 26732, + 26762, 26736, 26738, 26770, 26741, 26771, 26743, 26772, 26745, 26747, + 26764, 26766, 26749, 26752, 26773, 26756, 26758, 26726, 26760, 26774, + 26775, 26768, 26776, 26734, 26784, 26786, 26821, 26790, 26792, 26795, + 26797, 26829, 26799, 26830, 26801, 26803, 26823, 26825, 26805, 26808, + 26831, 26812, 26814, 26816, 26819, 26832, 26833, 26827, 26834, 26788, + 26846, 26847, 26848, 26849, 26850, 26851, 26852, 26853, 26854, 26855, + 26856, 26857, 26858, 26859, 26860, 26861, 26862, 26863, 26864, 26865, + 26866, 26867, 26868, 26869, 26870, 26871, 26872, 26873, 26874, 26875, + 26876, 26877, 26878, 26879, 26880, 26881, 26882, 26883, 26884, 26885, + 26886, 26887, 26888, 26889, 26890, 26891, 26892, 26893, 26894, 26895, + 26896, 26897, 26620, 26622, 26652, 26626, 26628, 26660, 26631, 26661, + 26633, 26662, 26635, 26637, 26654, 26656, 26639, 26642, 26663, 26646, + 26648, 26616, 26650, 26664, 26665, 26658, 26666, 26624, 26674, 26676, + 26711, 26680, 26682, 26685, 26687, 26719, 26689, 26720, 26691, 26693, + 26713, 26715, 26695, 26698, 26721, 26702, 26704, 26706, 26709, 26722, + 26723, 26717, 26724, 26678, 26543, 26544, 26545, 26546, 26547, 26548, + 26549, 26550, 26551, 26552, 26553, 26554, 26555, 26556, 26557, 26558, + 26559, 26560, 26561, 26562, 26563, 26564, 26565, 26566, 26567, 26568, + 26569, 26570, 26571, 26572, 26573, 26574, 26575, 26576, 26577, 26578, + 26579, 26580, 26581, 26582, 26583, 26584, 26585, 26586, 26587, 26588, + 26589, 26590, 26591, 26592, 26593, 26594, 26433, 26434, 41412, 41412, + 26001, 26003, 26010, 25995, 26007, 26005, 26008, 25997, 26012, 26014, + 26016, 26033, 26035, 26037, 26018, 26023, 26025, 25998, 26027, 25999, + 26029, 26021, 26031, 26022, 26019, 26261, 26049, 26051, 26060, 26047, + 26055, 26053, 26056, 26079, 26062, 26064, 26066, 26086, 26088, 26090, + 26068, 26073, 26075, 26058, 26077, 26080, 26082, 26071, 26084, 26072, + 26069, 26263, 26259, 26266, 26260, 26262, 26265, 26264, 26489, 26491, + 26500, 26495, 26497, 26493, 26498, 26485, 26502, 26504, 26506, 26523, + 26525, 26527, 26508, 26513, 26515, 26486, 26517, 26487, 26519, 26511, + 26521, 26512, 26509, 26537, 26437, 26439, 26448, 26435, 26443, 26441, + 26444, 26467, 26450, 26452, 26454, 26474, 26476, 26478, 26456, 26461, + 26463, 26446, 26465, 26468, 26470, 26459, 26472, 26460, 26457, 26539, + 26535, 26542, 26536, 26538, 26541, 26540, 26154, 26156, 26165, 26160, + 26162, 26158, 26163, 26150, 26167, 26169, 26171, 26188, 26190, 26192, + 26173, 26178, 26180, 26151, 26182, 26152, 26184, 26176, 26186, 26177, + 26174, 26202, 26208, 26210, 26221, 26214, 26216, 26212, 26217, 26240, + 26223, 26225, 26227, 26247, 26249, 26251, 26229, 26234, 26236, 26219, + 26238, 26241, 26243, 26232, 26245, 26233, 26230, 26204, 26200, 26258, + 26201, 26203, 26206, 26205, 26731, 26733, 26742, 26737, 26739, 26735, + 26740, 26727, 26744, 26746, 26748, 26765, 26767, 26769, 26750, 26755, + 26757, 26728, 26759, 26729, 26761, 26753, 26763, 26754, 26751, 26779, + 26785, 26787, 26798, 26791, 26793, 26789, 26794, 26817, 26800, 26802, + 26804, 26824, 26826, 26828, 26806, 26811, 26813, 26796, 26815, 26818, + 26820, 26809, 26822, 26810, 26807, 26781, 26777, 26835, 26778, 26780, + 26783, 26782, 26621, 26623, 26632, 26627, 26629, 26625, 26630, 26617, + 26634, 26636, 26638, 26655, 26657, 26659, 26640, 26645, 26647, 26618, + 26649, 26619, 26651, 26643, 26653, 26644, 26641, 26669, 26675, 26677, + 26688, 26681, 26683, 26679, 26684, 26707, 26690, 26692, 26694, 26714, + 26716, 26718, 26696, 26701, 26703, 26686, 26705, 26708, 26710, 26699, + 26712, 26700, 26697, 26671, 26667, 26725, 26668, 26670, 26673, 26672, + 25994, 26046, 41412, 41412, 26325, 26327, 26324, 26323, 26320, 26319, + 26322, 26321, 26328, 26326, 26380, 26382, 26379, 26378, 26375, 26374, + 26377, 26376, 26383, 26381, 26956, 26958, 26955, 26954, 26951, 26950, + 26953, 26952, 26959, 26957, 26842, 26844, 26841, 26840, 26837, 26836, + 26839, 26838, 26845, 26843, 26601, 26603, 26600, 26599, 26596, 26595, + 26598, 26597, 26604, 26602, 33315, 33271, 33296, 33512, 33467, 33253, + 33316, 33280, 33429, 33381, 33357, 33318, 33321, 33278, 33322, 33272, + 33323, 33345, 33340, 33378, 33319, 33325, 33334, 33335, 33326, 33332, + 33336, 33274, 33408, 33317, 33346, 33275, 33355, 33324, 33354, 33341, + 33380, 33379, 33320, 33339, 33349, 33350, 33353, 33352, 33420, 33328, + 33329, 33330, 33402, 33370, 33333, 33337, 33331, 33327, 33401, 33362, + 33400, 33399, 33359, 33358, 33361, 33351, 33348, 33347, 33397, 33396, + 33398, 33369, 33445, 33449, 33448, 33446, 33447, 33290, 33436, 33466, + 33438, 33451, 33443, 33452, 33444, 33453, 33442, 33300, 33301, 33465, + 33506, 33439, 33440, 33441, 33437, 33463, 33450, 33461, 33454, 33462, + 33460, 33458, 33455, 33456, 33457, 33459, 33287, 33293, 33291, 33292, + 33496, 33495, 33303, 33295, 33306, 33309, 33304, 33307, 33305, 33308, + 33313, 33310, 33270, 33505, 33511, 33508, 33510, 33484, 33486, 33464, + 33494, 33487, 33491, 33485, 33493, 33492, 33490, 33252, 33342, 33277, + 33469, 33255, 33478, 33344, 33343, 33470, 33383, 33386, 33385, 33384, + 33393, 33433, 33282, 33507, 33264, 33389, 33392, 33387, 33388, 33481, + 33391, 33480, 33263, 33262, 33390, 33281, 33479, 33261, 33356, 33276, + 33471, 33488, 33254, 33338, 33273, 33409, 33489, 33265, 33417, 33413, + 33415, 33286, 33509, 33266, 33410, 33412, 33411, 33416, 33414, 33504, + 33382, 33279, 33311, 33498, 33499, 33497, 33299, 33477, 33257, 33256, + 33406, 33482, 33404, 33285, 33394, 33405, 33503, 33403, 33407, 33395, + 33283, 33312, 33302, 33483, 33268, 33269, 33267, 33284, 33288, 33289, + 33501, 33502, 33500, 33468, 33371, 33473, 33374, 33375, 33376, 33373, + 33377, 33372, 33366, 33367, 33368, 33365, 33363, 33294, 33364, 33360, + 33297, 33298, 33475, 33476, 33472, 33474, 33259, 33260, 33258, 33418, + 33423, 33426, 33427, 33428, 33434, 33419, 33421, 33422, 33430, 33425, + 33431, 33432, 33424, 33314, 33435, 33826, 33825, 33824, 33846, 33845, + 33844, 33801, 33800, 33799, 33185, 33184, 33183, 33787, 33786, 33785, + 33797, 33798, 33793, 33796, 33792, 33795, 33794, 33242, 33245, 33241, + 33244, 33243, 33791, 33661, 33662, 33663, 33664, 33659, 33660, 33665, + 33705, 33610, 33723, 33722, 33720, 33721, 33724, 33699, 33702, 33700, + 33701, 33698, 33729, 33728, 33726, 33727, 33675, 33674, 33673, 33679, + 33678, 33677, 33676, 33697, 33696, 33695, 33672, 33671, 33670, 33745, + 33744, 33743, 33719, 33718, 33717, 33842, 33841, 33840, 33839, 33838, + 33837, 33843, 33836, 33835, 33834, 33579, 33578, 33576, 33577, 33583, + 33582, 33580, 33581, 33571, 33570, 33568, 33569, 33575, 33574, 33572, + 33573, 33633, 33632, 33630, 33631, 33634, 33648, 33651, 33649, 33650, + 33607, 33638, 33637, 33636, 33635, 33593, 33606, 33605, 33604, 33594, + 33592, 33591, 33590, 33657, 33656, 33655, 33654, 33653, 33652, 33829, + 33828, 33827, 33832, 33831, 33830, 33833, 33692, 33691, 33689, 33690, + 33683, 33682, 33680, 33681, 33688, 33687, 33710, 33709, 33706, 33711, + 33716, 33713, 33712, 33732, 33731, 33730, 33735, 33734, 33733, 33686, + 33694, 33693, 33782, 33779, 33778, 33725, 33684, 33707, 33714, 33739, + 33783, 33780, 33776, 33685, 33708, 33715, 33740, 33784, 33781, 33777, + 33738, 33737, 33736, 33597, 33596, 33614, 33612, 33613, 33611, 33623, + 33621, 33622, 33620, 33640, 33639, 33771, 33768, 33774, 33599, 33598, + 33615, 33616, 33618, 33617, 33627, 33625, 33626, 33624, 33642, 33641, + 33772, 33769, 33775, 33603, 33602, 33600, 33601, 33595, 33619, 33628, + 33643, 33644, 33645, 33770, 33767, 33773, 33629, 33669, 33667, 33668, + 33666, 33589, 33587, 33585, 33588, 33586, 33584, 33742, 33741, 33647, + 33646, 33704, 33703, 33609, 33608, 33201, 33200, 33196, 33199, 33203, + 33202, 33197, 33198, 33195, 33204, 33514, 33521, 33519, 33518, 33516, + 33517, 33515, 33520, 33234, 33232, 33233, 33210, 33209, 33208, 33193, + 33191, 33192, 33194, 33249, 33248, 33247, 33228, 33229, 33225, 33206, + 33205, 33224, 33226, 33223, 33227, 33207, 33222, 33220, 33221, 33217, + 33219, 33218, 33211, 33213, 33212, 33215, 33214, 33216, 33188, 33187, + 33186, 33811, 33810, 33812, 33231, 33748, 33747, 33749, 33750, 33178, + 33180, 33177, 33179, 33182, 33181, 33543, 33541, 33542, 33548, 33550, + 33549, 33545, 33547, 33546, 33562, 33561, 33560, 33554, 33555, 33556, + 33557, 33558, 33559, 33551, 33553, 33552, 33563, 33564, 33565, 33532, + 33530, 33531, 33544, 33567, 33566, 33819, 33818, 33816, 33817, 33815, + 33820, 33814, 33813, 33803, 33808, 33806, 33807, 33804, 33805, 33809, + 33746, 33658, 33751, 33513, 33230, 33789, 33788, 33251, 33246, 33790, + 33822, 33821, 33823, 33847, 33522, 33523, 33524, 33525, 33526, 33527, + 33528, 33529, 33240, 33540, 33539, 33534, 33537, 33536, 33533, 33535, + 33538, 33190, 33250, 33802, 33189, 33848, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 33235, 33236, 33237, 33238, 33239, 41412, 33759, 33760, 33761, + 33762, 33763, 33764, 33765, 33766, 33752, 33753, 33754, 33755, 33756, + 33757, 33758, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 23665, 23940, 23431, 23945, 23418, 23789, 24051, 23942, + 24037, 24006, 23411, 23644, 23645, 24041, 23405, 23458, 23432, 23782, + 23581, 23762, 23642, 24035, 23921, 24010, 23653, 23582, 23726, 23879, + 24011, 23548, 23957, 41412, 41412, 41412, 41412, 41412, 41412, 23572, + 23775, 23821, 23926, 23965, 24001, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 8342, 8344, 8354, + 8348, 8330, 8355, 8362, 41412, 8361, 8335, 8332, 8331, 8329, 8366, 8350, + 8349, 8351, 8365, 8352, 8353, 8337, 8340, 8364, 8346, 8363, 41412, 41412, + 8338, 8341, 8345, 8339, 8357, 8356, 8358, 41412, 8360, 8336, 41412, 8359, + 8334, 8343, 8333, 8347, 41412, 41412, 41412, 41412, 41412, 27944, 27913, + 27941, 27939, 27915, 27937, 27934, 27935, 27936, 27943, 27920, 27921, + 27945, 27924, 27922, 27917, 27930, 27946, 27919, 27942, 27929, 27938, + 27928, 27931, 27916, 27933, 27914, 27927, 27911, 27940, 27912, 27925, + 27923, 10652, 10630, 10650, 10637, 10633, 10647, 10644, 10645, 10646, + 10651, 10635, 10653, 10649, 10636, 10654, 10634, 10639, 10643, 10648, + 10642, 10640, 10641, 10638, 10629, 10632, 10631, 27918, 27932, 27926, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 8250, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 30063, 30047, 30038, 30049, + 30054, 30046, 30051, 30042, 30068, 30072, 30074, 30077, 30041, 30036, + 30071, 30061, 30045, 30044, 30075, 30037, 30048, 30069, 30057, 30073, + 30076, 30043, 30065, 30050, 30040, 30060, 30039, 30055, 30062, 30064, + 30070, 30056, 30052, 30053, 30078, 30079, 30058, 30059, 30066, 30067, + 30080, 41412, 41412, 41412, 30089, 30093, 30092, 30095, 30094, 30091, + 30090, 30086, 30083, 30082, 30085, 30084, 30087, 30088, 41412, 41412, + 30103, 30105, 30102, 30101, 30098, 30097, 30100, 30099, 30106, 30104, + 41412, 41412, 41412, 41412, 30081, 30096, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 37973, 37956, 37976, 37966, + 37970, 37967, 37972, 37958, 37957, 37975, 37963, 37978, 37977, 37969, + 37968, 37974, 37971, 37959, 37951, 37960, 37952, 37980, 37961, 37953, + 37962, 37954, 37979, 37965, 37955, 37964, 37981, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 39435, 39434, 39466, 39467, 39468, 39470, + 39459, 39462, 39448, 39451, 39463, 39455, 39452, 39469, 39465, 39464, + 39472, 39477, 39476, 39475, 39461, 39440, 39439, 39474, 39473, 39460, + 39471, 39443, 39445, 39449, 39456, 39447, 39454, 39453, 39442, 39437, + 39438, 39446, 39441, 39444, 39436, 39450, 39457, 39458, 39481, 39482, + 39479, 39480, 39489, 39491, 39488, 39487, 39484, 39483, 39486, 39485, + 39492, 39490, 41412, 41412, 41412, 41412, 41412, 39478, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 29044, 29047, 29046, 29048, + 29045, 29027, 29031, 29029, 29028, 29030, 29039, 29042, 29040, 29043, + 29041, 29049, 29050, 29051, 29052, 29053, 29032, 29034, 29037, 29038, + 29033, 29036, 29035, 29057, 29054, 29058, 29056, 29055, 29065, 29067, + 29064, 29063, 29060, 29059, 29062, 29061, 29068, 29066, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 30226, 30229, 30228, 30227, 30230, 30231, 30208, 30210, + 30209, 30211, 30212, 30213, 30220, 30221, 30225, 30222, 30223, 30224, + 30232, 30236, 30233, 30235, 30234, 30237, 30214, 30219, 30218, 30216, + 30215, 30217, 30240, 30238, 30239, 30248, 30250, 30247, 30246, 30243, + 30242, 30245, 30244, 30251, 30249, 41412, 41412, 41412, 41412, 30241, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 35536, 35545, 35534, 35543, 35567, 35552, 35565, 35542, + 35551, 35537, 35546, 35566, 35541, 35550, 35559, 35553, 35564, 35540, + 35549, 35558, 35538, 35547, 35568, 35571, 35533, 35570, 35539, 35548, + 35569, 35535, 35544, 41412, 35526, 35560, 35555, 35576, 35554, 35527, + 35574, 35562, 35572, 35561, 35556, 35557, 35563, 35525, 35575, 35573, + 35530, 35529, 35528, 35532, 35531, 35577, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 35578, 35579, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 17141, 17147, 17145, 17142, 17144, 17143, 17146, 41412, 17096, 17140, + 17138, 17137, 41412, 17084, 17083, 41412, 17095, 17094, 17093, 17080, + 17079, 17092, 17091, 17090, 17089, 17088, 17087, 17082, 17081, 17086, + 17085, 41412, 27254, 27255, 27256, 27322, 27343, 27331, 27295, 27431, + 27257, 27258, 27262, 27381, 27366, 27371, 27294, 27449, 27398, 27320, + 27300, 27392, 27261, 27259, 27260, 27307, 27351, 27404, 27444, 27267, + 27263, 27271, 27408, 27346, 27356, 27383, 27272, 27269, 27268, 27421, + 27359, 27419, 27397, 27388, 27386, 27387, 27450, 27429, 27266, 27281, + 27273, 27420, 27365, 27390, 27325, 27451, 27277, 27278, 27279, 27335, + 27327, 27311, 27412, 27363, 27264, 27270, 27265, 27338, 27435, 27436, + 27274, 27275, 27276, 27349, 27304, 27354, 27321, 27282, 27280, 27283, + 27407, 27364, 27413, 27315, 27427, 27284, 27288, 27292, 27361, 27333, + 27401, 27382, 27285, 27289, 27290, 27332, 27324, 27389, 27342, 27452, + 27353, 27291, 27286, 27287, 27369, 27422, 27430, 27299, 27442, 27293, + 27352, 27302, 27399, 27339, 27377, 27309, 27391, 27341, 27308, 27448, + 27297, 27344, 27301, 27340, 27368, 27395, 27406, 27376, 27411, 27378, + 27337, 27357, 27438, 27405, 27372, 27415, 27445, 27418, 27416, 27441, + 27312, 27428, 27318, 27347, 27303, 27334, 27310, 27358, 27314, 27394, + 27313, 27373, 27298, 27439, 27329, 27424, 27425, 27443, 27414, 27355, + 27393, 27385, 27348, 27323, 27296, 27362, 27370, 27409, 27375, 27305, + 27400, 27345, 27360, 27326, 27328, 27434, 27374, 27380, 27379, 27446, + 27367, 27316, 27317, 27403, 27447, 27396, 27384, 27437, 27440, 27410, + 27432, 27336, 27402, 27330, 27417, 27306, 27433, 27350, 27319, 41412, + 41412, 27460, 27458, 27457, 27454, 27453, 27456, 27455, 27461, 27459, + 27249, 27248, 27252, 27250, 27247, 27251, 27253, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 27, 9, 24, 14, + 29, 21, 34, 28, 37, 39, 35, 40, 41, 10, 30, 32, 18, 15, 31, 42, 13, 25, + 36, 23, 12, 20, 33, 19, 38, 17, 11, 26, 16, 22, 62, 44, 59, 49, 64, 56, + 69, 63, 72, 74, 70, 75, 76, 45, 65, 67, 53, 50, 66, 77, 48, 60, 71, 58, + 47, 55, 68, 54, 73, 52, 46, 61, 51, 57, 85, 86, 79, 84, 43, 78, 83, 82, + 41412, 41412, 41412, 41412, 93, 95, 92, 91, 88, 87, 90, 89, 96, 94, + 41412, 41412, 41412, 41412, 80, 81, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 20858, 20844, + 20839, 20819, 20814, 20832, 20827, 20807, 20822, 20847, 20842, 20837, + 20817, 20812, 20833, 20828, 20808, 20823, 20859, 20845, 20840, 20820, + 20815, 20835, 20830, 20810, 20825, 20860, 20846, 20841, 20821, 20816, + 20836, 20831, 20811, 20826, 20848, 20843, 20838, 20818, 20813, 20834, + 20829, 20809, 20824, 20805, 20806, 20796, 20803, 20804, 20856, 20854, + 20853, 20850, 20849, 20852, 20851, 20857, 20855, 20862, 20798, 20797, + 20799, 20861, 20802, 20801, 20800, 20795, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 31008, 31003, 30998, 30978, 30973, 30991, 30986, 30966, + 30981, 31006, 31001, 30996, 30976, 30971, 30992, 30987, 30967, 30982, + 31009, 31004, 30999, 30979, 30974, 30994, 30989, 30969, 30984, 31010, + 31005, 31000, 30980, 30975, 30995, 30990, 30970, 30985, 31007, 31002, + 30997, 30977, 30972, 30993, 30988, 30968, 30983, 30965, 30958, 30960, + 30950, 30952, 30953, 30955, 30962, 30961, 30956, 30951, 30954, 30959, + 30957, 30964, 30963, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 2288, 2296, 2294, 2192, + 41412, 2304, 2292, 2300, 2284, 2299, 2291, 2240, 2295, 2302, 2267, 2289, + 2297, 2268, 2303, 2298, 2266, 2287, 2286, 2290, 2285, 2191, 2293, 2301, + 2162, 2164, 2163, 2165, 41412, 2204, 2202, 41412, 2199, 41412, 41412, + 2198, 41412, 2206, 2201, 2209, 2203, 2208, 2196, 2211, 2205, 2197, 2210, + 41412, 2195, 2194, 2193, 2200, 41412, 2212, 41412, 2207, 41412, 41412, + 41412, 41412, 41412, 41412, 2276, 41412, 41412, 41412, 41412, 2278, + 41412, 2277, 41412, 2281, 41412, 2280, 2273, 2283, 41412, 2274, 2282, + 41412, 2272, 41412, 41412, 2275, 41412, 2271, 41412, 2279, 41412, 2269, + 41412, 2270, 41412, 2258, 2256, 41412, 2253, 41412, 41412, 2252, 2247, + 2260, 2255, 41412, 2257, 2263, 2250, 2265, 2259, 2251, 2264, 41412, 2249, + 2248, 2246, 2254, 41412, 2245, 2261, 2262, 2243, 41412, 2244, 41412, + 2217, 2229, 2227, 2237, 2220, 2239, 2225, 2219, 2223, 2232, 41412, 2235, + 2228, 2234, 2214, 2218, 2230, 2215, 2238, 2231, 2213, 2224, 2222, 2216, + 2221, 2236, 2226, 2233, 41412, 41412, 41412, 41412, 41412, 2178, 2176, + 2187, 41412, 2190, 2174, 2182, 2172, 2181, 41412, 2185, 2177, 2184, 2167, + 2189, 2179, 2168, 2188, 2180, 2166, 2173, 2171, 2169, 2170, 2186, 2175, + 2183, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 2241, 2242, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 25561, + 25577, 25592, 25568, 25596, 25595, 25593, 25573, 25590, 25587, 25566, + 25563, 25582, 25579, 25559, 25570, 25574, 25591, 25588, 25567, 25564, + 25583, 25580, 25560, 25571, 25572, 25589, 25586, 25565, 25562, 25581, + 25578, 25558, 25569, 25576, 25575, 25556, 25599, 25585, 25584, 25597, + 25594, 25598, 25557, 41412, 41412, 41412, 41412, 11271, 11222, 11223, + 11224, 11225, 11226, 11227, 11228, 11229, 11230, 11231, 11232, 11233, + 11234, 11235, 11236, 11237, 11238, 11239, 11240, 11241, 11242, 11243, + 11244, 11245, 11246, 11247, 11248, 11249, 11250, 11251, 11252, 11253, + 11254, 11255, 11256, 11257, 11258, 11259, 11260, 11261, 11262, 11263, + 11264, 11265, 11266, 11267, 11268, 11269, 11270, 11321, 11272, 11273, + 11274, 11275, 11276, 11277, 11278, 11279, 11280, 11281, 11282, 11283, + 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, + 11294, 11295, 11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, + 11304, 11305, 11306, 11307, 11308, 11309, 11310, 11311, 11312, 11313, + 11314, 11315, 11316, 11317, 11318, 11319, 11320, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 31671, + 31741, 31716, 31712, 31675, 31680, 31700, 31696, 31692, 31745, 31708, + 31749, 31684, 31704, 31688, 41412, 41412, 31742, 31717, 31713, 31676, + 31681, 31701, 31697, 31693, 31746, 31709, 31750, 31685, 31705, 31689, + 31672, 41412, 31743, 31718, 31714, 31677, 31682, 31702, 31698, 31694, + 31747, 31710, 31751, 31686, 31706, 31690, 31670, 41412, 31740, 31715, + 31711, 31674, 31679, 31699, 31695, 31691, 31744, 31707, 31748, 31683, + 31703, 31687, 31673, 31678, 31722, 31719, 31733, 31734, 31735, 31736, + 31737, 31738, 31739, 31723, 31724, 31725, 31726, 31727, 31728, 31729, + 31730, 31731, 31732, 31720, 31721, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 11006, 11005, 10990, 11002, 10999, + 10984, 10981, 10996, 10993, 11008, 10987, 11047, 11026, 6918, 6635, 6659, + 31339, 31340, 31341, 31342, 31343, 31344, 31345, 31346, 31347, 31348, + 31349, 31350, 31351, 31352, 31353, 31354, 31355, 31356, 31357, 31358, + 31359, 31360, 31361, 31362, 31363, 31364, 37949, 6749, 6750, 6646, 6917, + 8778, 34644, 34645, 34646, 34647, 34648, 34649, 34650, 34651, 34652, + 34653, 34654, 34655, 34656, 34657, 34658, 34659, 34660, 34661, 34662, + 34663, 34664, 34665, 34666, 34667, 34668, 34669, 34638, 34674, 34689, + 34690, 34679, 34701, 29157, 29158, 29159, 29160, 29161, 29162, 29163, + 29164, 29165, 29166, 29167, 29168, 29169, 29170, 29171, 29172, 29173, + 29174, 29175, 29176, 29177, 29178, 29179, 29180, 29181, 29182, 31950, + 31951, 31952, 6645, 6644, 6692, 29188, 29189, 29190, 29191, 29192, 29193, + 29194, 29195, 29196, 29197, 29198, 29199, 29200, 29201, 29202, 29203, + 29204, 29205, 29206, 29207, 29208, 29209, 29210, 29211, 29212, 29213, + 8822, 29220, 29223, 29224, 29219, 29221, 34373, 34627, 34626, 34633, + 34702, 34675, 34676, 34678, 34688, 34696, 34699, 34691, 34681, 34693, + 34631, 34695, 34632, 34682, 34692, 34684, 34677, 34643, 34637, 34636, + 34635, 34672, 34683, 34697, 34698, 25991, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 31980, 31981, 31982, 31983, 31984, 31985, 31986, 31987, + 31988, 31989, 31990, 31991, 31992, 31993, 31994, 31995, 31996, 31997, + 31998, 31999, 32000, 32001, 32002, 32003, 32004, 32005, 34414, 34639, + 34641, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 34605, 34600, 34592, 34640, 34586, 34598, + 34621, 34597, 34585, 34610, 34618, 34609, 34590, 34601, 34602, 34608, + 34589, 34619, 34616, 34623, 34599, 34594, 34613, 34603, 34606, 34583, + 34584, 34625, 34596, 34587, 34591, 34607, 34622, 34604, 34617, 34620, + 34593, 34614, 34612, 34611, 34615, 34588, 34595, 34624, 41412, 41412, + 41412, 41412, 37946, 37940, 37941, 37943, 37947, 37944, 37948, 37942, + 37945, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 6697, 6695, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 32416, 32417, 32414, 32418, 32413, 32415, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 10657, 17627, 8142, 29467, 34877, 34876, + 6928, 34922, 31943, 5033, 39583, 39408, 27764, 11671, 11669, 11670, + 18163, 29272, 39495, 17592, 39496, 17670, 39494, 22905, 39493, 8812, + 29271, 17591, 22904, 17669, 34801, 18164, 33020, 37385, 3930, 39742, + 39746, 39743, 39744, 8155, 8154, 8153, 8152, 17626, 39809, 20595, 37043, + 5109, 6579, 32750, 17519, 10683, 31207, 6226, 20592, 38117, 6576, 32404, + 20552, 34923, 4344, 11665, 11666, 20377, 17646, 25843, 17559, 24202, + 28479, 37899, 2586, 18276, 27246, 39586, 36066, 24568, 3475, 31655, + 31977, 18816, 31475, 31472, 6578, 34741, 19266, 34006, 27036, 31791, + 32100, 32101, 8612, 10084, 34729, 34305, 5031, 17660, 32420, 10666, + 31065, 34963, 17668, 17598, 34102, 32964, 20626, 11417, 8611, 6618, 6101, + 25446, 10087, 20558, 33039, 3699, 31789, 8610, 17632, 37045, 32717, + 39811, 8159, 38030, 3589, 8101, 2650, 17633, 4468, 31779, 32091, 39831, + 3860, 20987, 6619, 17565, 17588, 17587, 2793, 31397, 8591, 36065, 8823, + 31654, 20992, 6163, 39808, 28362, 32722, 18201, 19847, 4470, 27763, + 32044, 28485, 34750, 24567, 8603, 3579, 3580, 17581, 98, 6161, 17571, + 32362, 17596, 27753, 28384, 6621, 19846, 2565, 37924, 6926, 37792, 8097, + 31504, 39330, 11052, 34012, 3859, 17859, 4473, 17615, 28720, 28466, + 32716, 18832, 28484, 38035, 39335, 28719, 32545, 37160, 33987, 3481, + 6580, 34096, 32546, 34961, 34336, 38032, 20590, 372, 32423, 34966, 39604, + 18200, 31933, 31934, 8814, 39409, 17602, 20628, 35154, 34093, 5367, 3585, + 5108, 20602, 6927, 10710, 8098, 10792, 10793, 29138, 34727, 20601, 20600, + 31061, 20989, 17484, 20603, 3470, 2583, 20596, 25330, 8606, 32721, 10709, + 17555, 20985, 20988, 17483, 39711, 3983, 39592, 39591, 32405, 3999, + 22727, 2661, 4477, 370, 16877, 16878, 16879, 16880, 16881, 31958, 28379, + 31068, 39584, 8805, 37690, 24464, 31960, 6168, 11507, 8826, 39765, 34091, + 34089, 20589, 31963, 18168, 33045, 28360, 32403, 6587, 11158, 31646, + 4655, 16846, 30127, 34330, 5046, 966, 20557, 22729, 17595, 38031, 4345, + 38142, 19815, 2649, 17664, 3861, 31476, 22724, 31801, 11509, 2659, 11220, + 28381, 8806, 37691, 31961, 6169, 11508, 34335, 20591, 28361, 11219, + 31648, 17667, 19264, 39830, 3584, 31244, 31647, 31465, 6586, 17516, + 17514, 11664, 29620, 28382, 37900, 39753, 39668, 39694, 39718, 17599, + 39593, 31064, 37418, 37419, 8096, 30718, 8828, 39821, 17515, 29462, + 35151, 21089, 11515, 22719, 3865, 39819, 31906, 19270, 31796, 25837, + 2580, 20448, 39820, 39818, 17631, 5104, 5103, 4653, 18063, 25750, 39816, + 17563, 25756, 38157, 38158, 31776, 39817, 5034, 31489, 25753, 25754, + 30697, 30695, 2648, 8594, 31858, 20995, 20994, 19132, 2651, 17503, 350, + 20755, 33989, 20871, 18831, 10665, 25223, 29069, 17551, 19137, 3479, + 35149, 31651, 22716, 25329, 32342, 17863, 22711, 4469, 8804, 39602, 3586, + 5040, 38151, 34306, 18829, 19849, 4347, 18818, 39858, 31905, 19848, + 32087, 19850, 10968, 16834, 964, 4652, 34001, 8164, 34331, 11511, 10670, + 31649, 17609, 11138, 34319, 37393, 39679, 20612, 28182, 10082, 19879, + 8811, 3472, 3474, 3473, 3471, 28181, 6397, 32746, 31499, 5035, 27766, + 17616, 30729, 11662, 17577, 30716, 31072, 31074, 5364, 37046, 6106, 6396, + 6398, 3477, 8102, 31908, 32411, 31467, 34739, 38000, 4358, 24566, 29618, + 29619, 8148, 30710, 18817, 4346, 30733, 4359, 29140, 32743, 27600, 37051, + 31075, 17562, 32629, 31909, 6403, 31012, 20982, 31466, 17517, 20787, + 16915, 8145, 8146, 30720, 30719, 31785, 31782, 29457, 27780, 27781, + 39326, 27782, 29537, 968, 5365, 5366, 39329, 37058, 31936, 39331, 17580, + 31780, 31872, 38145, 8132, 8133, 8129, 977, 25331, 20443, 34314, 34313, + 34315, 34316, 3578, 16832, 24333, 32218, 25281, 8147, 21774, 25278, + 30723, 3592, 3594, 4357, 25221, 31938, 2653, 16910, 30699, 34152, 37939, + 29536, 21789, 20874, 20875, 20878, 20877, 20876, 17584, 16833, 39834, + 19260, 30033, 20604, 31660, 27752, 37057, 8833, 33983, 20993, 38002, + 4010, 39729, 22895, 22822, 22830, 22823, 34018, 34017, 38240, 11430, + 38244, 11424, 25400, 38336, 6642, 8820, 8819, 29611, 29613, 35038, 39692, + 19894, 6234, 31066, 11502, 21772, 28368, 35059, 27462, 4471, 8113, 8123, + 8125, 8109, 8107, 8117, 8115, 8105, 8111, 8119, 8103, 8121, 8114, 8124, + 8126, 8110, 8108, 8118, 8116, 8106, 8112, 8120, 8104, 8122, 32165, 32166, + 32167, 5099, 5100, 32350, 4356, 6100, 25840, 4012, 29535, 20556, 25751, + 34004, 10667, 34326, 34327, 21090, 25755, 24254, 37052, 32146, 39748, + 4025, 37056, 8099, 2654, 34711, 16914, 17625, 31479, 25220, 3980, 25362, + 25348, 25360, 25361, 25382, 24314, 38133, 31948, 32072, 32080, 32081, + 32086, 32082, 31949, 39669, 33174, 33173, 33170, 33169, 3958, 3985, + 33176, 33175, 33172, 33171, 4028, 3924, 3937, 10794, 21776, 37409, 31855, + 31802, 3940, 39683, 34103, 37040, 39814, 30707, 38146, 37405, 37984, + 30521, 19813, 32727, 31856, 17561, 30730, 11144, 11145, 11146, 17656, + 17658, 17657, 3936, 17629, 30717, 6107, 6108, 17578, 16882, 16883, 16884, + 29615, 29616, 29617, 16893, 16886, 16887, 11143, 31071, 31076, 39598, + 34329, 34328, 10795, 27767, 27022, 31055, 8131, 6098, 20789, 10684, 8586, + 30694, 32361, 31073, 34737, 10664, 25222, 34317, 37401, 37400, 37402, + 37403, 24282, 32168, 38161, 37407, 24299, 32182, 24212, 32104, 28365, + 24591, 24590, 2798, 2804, 2799, 2803, 2796, 24588, 2797, 39825, 28378, + 37983, 34724, 33986, 28383, 18821, 18824, 17541, 34077, 34079, 34078, + 34080, 34076, 34075, 39812, 34081, 17521, 32043, 34074, 34084, 34087, + 29269, 17496, 38197, 17524, 31477, 8592, 8593, 22712, 17552, 22713, + 22714, 17538, 17539, 17540, 11054, 39826, 965, 31794, 8832, 31501, 17546, + 11053, 17666, 962, 17567, 39600, 34003, 37791, 18826, 25445, 17529, + 20611, 17531, 17522, 2573, 17617, 34002, 11139, 17549, 17526, 18825, + 6170, 34073, 34072, 6171, 22715, 31793, 8831, 39599, 34008, 34007, 38348, + 17545, 17534, 17528, 31498, 32751, 19852, 34312, 19812, 31496, 31495, + 31491, 31493, 29580, 34208, 29553, 34195, 38131, 38140, 38130, 38139, + 29579, 34207, 29552, 34194, 19930, 19923, 19927, 19920, 29581, 34209, + 29554, 34196, 19931, 19924, 19928, 19921, 20554, 20555, 34148, 34149, + 24457, 38382, 32305, 11497, 32737, 19925, 24570, 19902, 19857, 34964, + 32623, 32624, 32625, 19947, 32626, 19914, 39316, 39313, 6399, 32053, + 32360, 20089, 34728, 31941, 20446, 20447, 37991, 27598, 24577, 34725, + 37987, 37988, 5102, 30704, 38028, 5105, 27768, 373, 17585, 31774, 30703, + 37044, 30702, 2582, 30700, 31976, 10689, 2564, 37985, 28359, 28375, + 34962, 28376, 160, 33019, 32419, 34318, 20582, 39307, 8595, 31775, 37999, + 11503, 29533, 34088, 29538, 31907, 11501, 31787, 29542, 3855, 29531, + 3854, 28377, 31508, 29534, 6582, 27463, 39822, 32048, 2652, 37982, 39582, + 33044, 3576, 3577, 31407, 10086, 2665, 24255, 37996, 31870, 6751, 4654, + 18064, 8803, 34000, 33022, 3596, 3756, 31665, 30126, 33021, 34752, 31077, + 20550, 20614, 16847, 22731, 41412, 41412, 41412, 39815, 31669, 39606, + 32343, 19261, 33015, 30159, 28373, 31940, 28370, 38238, 38235, 38243, + 34015, 29588, 227, 228, 41412, 41412, 41412, 32628, 30701, 10979, 31403, + 32725, 28371, 6103, 34005, 17620, 33992, 2584, 31645, 32363, 41412, + 41412, 41412, 297, 245, 345, 344, 341, 239, 237, 238, 235, 236, 334, 336, + 337, 323, 290, 252, 283, 284, 285, 267, 311, 288, 338, 339, 309, 310, + 272, 325, 278, 279, 261, 302, 258, 280, 321, 259, 260, 257, 312, 319, + 340, 331, 281, 240, 320, 313, 318, 335, 300, 301, 299, 303, 304, 305, + 232, 233, 286, 314, 242, 306, 307, 243, 248, 328, 329, 298, 249, 250, + 251, 234, 346, 324, 330, 273, 342, 291, 256, 333, 255, 327, 254, 332, + 315, 282, 326, 343, 276, 244, 293, 253, 292, 241, 316, 317, 322, 296, + 270, 268, 269, 295, 294, 262, 263, 264, 265, 266, 231, 246, 247, 308, + 277, 289, 271, 287, 275, 274, 25327, 30128, 25448, 39324, 2577, 20616, + 31399, 19842, 25625, 18198, 31927, 30736, 3951, 4029, 3991, 3925, 4015, + 27137, 4353, 19944, 39317, 17500, 39648, 32412, 4023, 4016, 24585, 27163, + 4354, 19941, 39318, 17501, 39730, 39732, 34559, 4021, 4039, 3973, 39663, + 39664, 10967, 4022, 4040, 3974, 39701, 37390, 24587, 27164, 4355, 39322, + 39319, 17502, 37388, 24580, 27154, 4349, 19915, 39314, 17497, 24573, + 27143, 4352, 19890, 39312, 17499, 24581, 27153, 4350, 19919, 39315, + 17498, 24571, 27161, 4351, 19884, 39311, 24583, 27158, 37408, 27157, + 24575, 27142, 17648, 27141, 32054, 24572, 19889, 27152, 19918, 33981, + 27160, 19882, 39310, 19880, 24582, 19937, 19936, 6912, 29183, 6922, + 29184, 29465, 41412, 41412, 41412, 41412, 41412, 41412, 22829, 22897, + 22825, 22893, 22820, 22896, 22824, 22831, 22898, 22826, 22894, 22821, + 41412, 41412, 41412, 41412, 19887, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 24377, 38358, 32258, 11448, 24384, 38355, 32265, 11445, 24371, 38354, + 32255, 11444, 41412, 41412, 41412, 41412, 24376, 38357, 32257, 11447, + 24386, 38359, 32267, 11449, 19898, 19939, 19912, 19876, 19897, 19938, + 19911, 19875, 24421, 38392, 32318, 11468, 24420, 38391, 32317, 11467, + 24419, 38388, 32316, 11464, 24423, 38394, 32320, 11470, 24422, 38393, + 32319, 11469, 24451, 38369, 32284, 11484, 24459, 38384, 32307, 11499, + 24461, 38380, 32340, 11495, 24411, 38378, 32298, 11493, 24412, 38379, + 32299, 11494, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 24460, 38383, 32308, 11498, 29586, 29559, 34201, 34214, 24274, 38225, + 41412, 41412, 41412, 41412, 41412, 41412, 39768, 39783, 39773, 39778, + 39793, 39788, 39798, 39803, 39770, 39785, 39775, 39780, 39795, 39790, + 39800, 39805, 39769, 39784, 39774, 39779, 39794, 39789, 39799, 39804, + 39766, 39781, 39771, 39776, 39791, 39786, 39796, 39801, 39767, 39782, + 39772, 39777, 39792, 39787, 39797, 39802, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 24427, 38398, 32324, 11475, 24441, 38408, + 32339, 11480, 24385, 38356, 32266, 11446, 19853, 19856, 19855, 19854, + 24395, 32273, 24430, 32309, 24452, 32304, 24456, 32300, 24394, 32272, + 24450, 32283, 39610, 39609, 41412, 41412, 2560, 2557, 32253, 11459, + 29214, 29215, 29222, 29216, 29578, 29550, 34193, 34206, 41412, 41412, + 41412, 41412, 24391, 32244, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 25318, 25322, + 25323, 33029, 25314, 33026, 25316, 25317, 25306, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 6640, 6641, 6639, 24239, 24237, + 24238, 24240, 24236, 11437, 11439, 11438, 11440, 31652, 39684, 5042, + 31653, 41221, 28183, 17542, 29463, 37391, 17525, 32421, 20613, 33849, + 5363, 31957, 24348, 32207, 19271, 19267, 20986, 17523, 8156, 29139, + 32365, 11512, 25506, 17550, 34092, 17533, 18823, 18822, 17544, 32846, + 34082, 17530, 33042, 31803, 5030, 31242, 32854, 31857, 25752, 28369, + 33047, 31486, 21092, 17573, 27783, 39833, 39585, 19269, 11134, 39807, + 11513, 8100, 38143, 34334, 18167, 32354, 17594, 32749, 37392, 4650, + 25914, 10081, 22728, 34105, 17624, 8827, 2642, 10088, 2660, 31788, 6166, + 2663, 18819, 32858, 34751, 16782, 18162, 31473, 22717, 31243, 11659, + 17636, 35648, 6617, 4472, 10074, 8160, 5041, 31663, 31853, 10089, 32627, + 6102, 24203, 25841, 28363, 2664, 34083, 39857, 34085, 17535, 17548, + 31054, 17662, 29466, 11058, 17553, 17537, 32718, 22726, 18197, 20551, + 17603, 8834, 25275, 32723, 38119, 38211, 11674, 11660, 3519, 32963, + 31067, 17653, 5107, 10962, 18196, 25276, 32089, 33046, 34704, 18065, + 41215, 20442, 32713, 35152, 8813, 21378, 25512, 31470, 20553, 31402, + 31935, 25444, 28367, 27755, 2662, 34965, 25749, 11504, 34013, 31011, + 30735, 33991, 17608, 31060, 3587, 3866, 32745, 18833, 31871, 16873, + 16874, 16876, 16875, 4656, 24569, 17630, 37901, 34958, 34959, 32556, + 11667, 28372, 25838, 27037, 27038, 6402, 10076, 32559, 3755, 17858, + 30709, 17560, 39433, 5106, 27001, 20627, 5044, 38027, 34726, 22721, + 10961, 17527, 101, 6581, 30696, 3583, 31494, 31488, 31497, 31487, 25516, + 17566, 38971, 27587, 16871, 18060, 41407, 5028, 30734, 3858, 32720, + 18165, 8809, 34100, 31978, 17589, 21095, 37163, 31507, 11661, 8589, 2645, + 17586, 37903, 5037, 25515, 25447, 25326, 34333, 2806, 32557, 37050, 5043, + 3480, 32364, 3478, 34337, 31964, 29141, 29246, 29257, 29260, 29249, + 29239, 29254, 39623, 3893, 29240, 39620, 39636, 39639, 39614, 39628, + 39633, 3890, 3906, 3909, 3884, 3898, 3903, 29247, 29258, 29261, 29250, + 29245, 29255, 39624, 3894, 29241, 39642, 39645, 39646, 39641, 39643, + 39644, 3912, 3915, 3916, 3911, 3913, 3914, 29264, 29267, 29268, 29263, + 29265, 29266, 39625, 3895, 29242, 39621, 39637, 39640, 39615, 39626, + 39634, 3891, 3907, 3910, 3885, 3896, 3904, 29248, 29259, 29262, 29251, + 29243, 29256, 39627, 3897, 29244, 39616, 3886, 29252, 39617, 3887, 29253, + 39630, 39631, 39629, 3900, 3901, 3899, 39618, 39612, 3888, 3882, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 39849, 39852, 39848, + 39850, 39847, 39846, 39851, 39842, 39845, 39841, 39843, 39840, 39839, + 39844, 41412, 41412, 2807, 30708, 5036, 33040, 37394, 24584, 18820, + 31657, 11510, 99, 34731, 39838, 8830, 41412, 41412, 41412, 41129, 22720, + 31251, 4360, 25514, 31658, 29236, 25844, 17618, 19814, 38029, 41412, + 41412, 41412, 37992, 33043, 32349, 6237, 31962, 2647, 11137, 3476, 27762, + 1, 25304, 8808, 6164, 32726, 22730, 20606, 27778, 39810, 31771, 32851, + 22722, 5110, 28380, 37902, 19844, 31666, 32359, 27779, 20633, 25332, + 19265, 17628, 19134, 21859, 17619, 39827, 3590, 8158, 31790, 39829, + 17568, 25328, 8782, 16885, 29237, 20624, 21088, 39813, 24201, 18199, 958, + 25449, 31509, 31805, 31804, 31492, 17582, 41412, 19136, 41412, 41412, + 41412, 41412, 30737, 28366, 11322, 4348, 3593, 30698, 17604, 36064, + 17652, 37049, 31792, 3588, 21087, 18062, 31474, 32402, 41412, 41412, + 34332, 27245, 32561, 17532, 17536, 17547, 11332, 3863, 5045, 33014, + 17543, 11057, 41412, 41412, 41412, 41412, 17576, 19268, 32297, 24410, + 31208, 31209, 20794, 19851, 24455, 32303, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 4284, 4314, 4285, 4329, 4300, 4318, 4286, 4337, + 4307, 4315, 4293, 4330, 4301, 4319, 4287, 4341, 4311, 4326, 4297, 4334, + 4323, 4290, 4338, 4308, 4316, 4294, 4331, 4302, 4320, 4288, 4343, 4313, + 4328, 4299, 4336, 4306, 4325, 4292, 4340, 4310, 4296, 4333, 4304, 4322, + 4289, 4342, 4312, 4327, 4298, 4335, 4305, 4324, 4291, 4339, 4309, 4317, + 4295, 4332, 4303, 4321, 25349, 25350, 25357, 25359, 25354, 25415, 25416, + 25412, 25414, 25410, 25413, 25406, 25409, 25407, 25411, 25408, 25353, + 25356, 25351, 25355, 25352, 25358, 38308, 38309, 38316, 38318, 38313, + 38278, 38279, 38275, 38277, 38273, 38276, 38269, 38272, 38270, 38274, + 38271, 38312, 38315, 38310, 38314, 38311, 38317, 38251, 24204, 38248, + 24209, 24295, 38347, 32190, 25441, 39295, 39296, 39297, 39298, 39299, + 39300, 20568, 20569, 20570, 20571, 20572, 20573, 24205, 24210, 32103, + 32102, 38250, 20567, 38306, 38343, 38258, 38346, 38342, 32152, 32186, + 32130, 32185, 32162, 24253, 32145, 38265, 25342, 20969, 38260, 38262, + 41412, 24252, 6400, 20965, 19891, 38283, 38338, 38249, 24206, 38284, + 38339, 25402, 25379, 4556, 4560, 4548, 4554, 4557, 4562, 4549, 4551, + 4559, 4561, 4563, 4558, 4552, 4553, 4579, 4589, 2563, 20966, 24247, + 32140, 20967, 24364, 32241, 11454, 38351, 24244, 32137, 39407, 32154, + 29186, 29185, 29187, 39687, 24298, 27757, 32181, 29217, 34732, 34733, + 34735, 34736, 34734, 39755, 39660, 31953, 4005, 24305, 24260, 4555, 4576, + 4571, 4550, 4566, 4565, 4573, 4564, 4569, 4575, 4546, 4570, 4567, 4577, + 4547, 4572, 37927, 32148, 4466, 24319, 38257, 25426, 27758, 27759, 37926, + 32147, 4465, 24318, 37936, 4452, 4459, 37928, 32759, 32761, 32758, 32757, + 32754, 32753, 32756, 32755, 32762, 32760, 229, 41412, 41412, 41412, + 41412, 41412, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, + 6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, + 6981, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, + 6993, 6994, 6995, 6996, 6997, 6998, 6999, 7000, 7001, 7002, 7003, 7004, + 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, + 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, + 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, + 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, + 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, + 7065, 7066, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, + 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, + 7089, 7090, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, + 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, + 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, + 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, 7133, 7134, 7135, 7136, + 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, + 7149, 7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, + 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, + 7173, 7174, 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, + 7185, 7186, 7187, 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, 7196, + 7197, 7198, 7199, 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, + 7209, 7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, + 7221, 7222, 7223, 7224, 7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, + 7233, 7234, 7235, 7236, 7237, 7238, 7239, 7240, 7241, 7242, 7243, 7244, + 7245, 7246, 7247, 7248, 7249, 7250, 7251, 7252, 7253, 7254, 7255, 7256, + 7257, 7258, 7259, 7260, 7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, + 7269, 7270, 7271, 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, + 7281, 7282, 7283, 7284, 7285, 7286, 7287, 7288, 7289, 7290, 7291, 7292, + 7293, 7294, 7295, 7296, 7297, 7298, 7299, 7300, 7301, 7302, 7303, 7304, + 7305, 7306, 7307, 7308, 7309, 7310, 7311, 7312, 7313, 7314, 7315, 7316, + 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, + 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, + 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, + 7353, 7354, 7355, 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, + 7365, 7366, 7367, 7368, 7369, 7370, 7371, 7372, 7373, 7374, 7375, 7376, + 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, 7387, 7388, + 7389, 7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399, 7400, + 7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, + 7413, 7414, 7415, 7416, 7417, 7418, 7419, 7420, 7421, 7422, 7423, 7424, + 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434, 7435, 7436, + 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, 7447, 7448, + 7449, 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, + 7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, 6943, 6944, + 6945, 6946, 6947, 6948, 6949, 6950, 6951, 6952, 6953, 6954, 6955, 6956, + 6957, 6958, 6929, 6930, 6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, + 6939, 6940, 6941, 6942, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 22732, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 35245, 35174, 35237, 35246, 35162, 35235, 35156, 35155, 35232, + 35240, 35157, 35236, 35160, 35177, 35248, 35244, 35169, 35171, 35168, + 35167, 35164, 35163, 35166, 35165, 35172, 35170, 35161, 35243, 35230, + 35173, 35176, 35238, 35159, 35178, 35179, 35180, 35181, 35182, 35183, + 35184, 35185, 35186, 35187, 35188, 35189, 35190, 35191, 35192, 35193, + 35194, 35195, 35196, 35197, 35198, 35199, 35200, 35201, 35202, 35203, + 35233, 35242, 35241, 35158, 35234, 35175, 35204, 35205, 35206, 35207, + 35208, 35209, 35210, 35211, 35212, 35213, 35214, 35215, 35216, 35217, + 35218, 35219, 35220, 35221, 35222, 35223, 35224, 35225, 35226, 35227, + 35228, 35229, 35231, 35249, 35239, 35247, 6097, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 38793, 38804, 38815, 38827, 38838, + 38849, 38860, 38871, 38882, 38890, 38891, 38892, 38893, 38895, 38896, + 38897, 38898, 38899, 38900, 38901, 38902, 38903, 38904, 38906, 38907, + 38908, 38909, 38910, 38911, 38912, 38913, 38914, 38915, 38917, 38918, + 38919, 38920, 38921, 38922, 38923, 38924, 38925, 38926, 38928, 38929, + 38930, 38931, 38932, 38933, 38934, 38935, 38936, 38937, 38939, 38940, + 38941, 38942, 38943, 38944, 38945, 38946, 38947, 38948, 38950, 38951, + 38952, 38953, 38954, 38955, 38956, 38957, 38958, 38959, 38961, 38962, + 38963, 38964, 38965, 38966, 38967, 38968, 38969, 38970, 38717, 38718, + 38719, 38720, 38721, 38722, 38723, 38724, 38725, 38726, 38728, 38729, + 38730, 38731, 38732, 38733, 38734, 38735, 38736, 38737, 38739, 38740, + 38741, 38742, 38743, 38744, 38745, 38746, 38747, 38748, 38750, 38751, + 38752, 38753, 38754, 38755, 38756, 38757, 38758, 38759, 38761, 38762, + 38763, 38764, 38765, 38766, 38767, 38768, 38769, 38770, 38772, 38773, + 38774, 38775, 38776, 38777, 38778, 38779, 38780, 38781, 38783, 38784, + 38785, 38786, 38787, 38788, 38789, 38790, 38791, 38792, 38794, 38795, + 38796, 38797, 38798, 38799, 38800, 38801, 38802, 38803, 38805, 38806, + 38807, 38808, 38809, 38810, 38811, 38812, 38813, 38814, 38816, 38817, + 38818, 38819, 38820, 38821, 38822, 38823, 38824, 38825, 38828, 38829, + 38830, 38831, 38832, 38833, 38834, 38835, 38836, 38837, 38839, 38840, + 38841, 38842, 38843, 38844, 38845, 38846, 38847, 38848, 38850, 38851, + 38852, 38853, 38854, 38855, 38856, 38857, 38858, 38859, 38861, 38862, + 38863, 38864, 38865, 38866, 38867, 38868, 38869, 38870, 38872, 38873, + 38874, 38875, 38876, 38877, 38878, 38879, 38880, 38881, 38883, 38884, + 38885, 38886, 38887, 38888, 38889, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 30035, 30034, 34722, 34301, 34723, 34754, 16908, 17482, 16906, + 16919, 16912, 16911, 3, 2, 349, 3591, 2657, 5360, 6392, 20578, 20608, + 35153, 24664, 29357, 16909, 25513, 30109, 16917, 24666, 39304, 39411, + 17638, 17788, 6165, 8810, 33016, 25280, 34098, 33017, 25279, 33050, + 10675, 11663, 10960, 10676, 10959, 10677, 10958, 10678, 10956, 10679, + 29225, 29143, 35058, 35057, 16907, 17481, 6095, 5368, 16905, 16918, + 16872, 34785, 34755, 16954, 16953, 20866, 17579, 17786, 20867, 18827, + 19133, 20868, 31975, 32554, 20869, 38208, 38414, 34303, 10691, 10688, + 31070, 31069, 20445, 20607, 5029, 5359, 29530, 29145, 20793, 20792, + 29459, 29464, 34719, 34707, 16904, 16957, 6394, 20580, 20610, 6393, + 20579, 20609, 24667, 39305, 39412, 31393, 31392, 31772, 31394, 31395, + 31752, 32055, 32062, 32090, 33862, 33863, 34705, 33861, 33864, 34706, + 10957, 10680, 31861, 31862, 31910, 31860, 31863, 31911, 32849, 34753, + 6096, 10660, 27588, 28969, 34718, 34721, 34304, 16903, 16901, 17520, + 34720, 34302, 33856, 35150, 33855, 32744, 8604, 10659, 34744, 34708, + 30727, 30949, 31859, 31912, 1056, 1063, 29144, 33049, 23060, 23683, + 10658, 2354, 363, 35136, 21392, 22735, 22736, 22778, 22744, 37497, 19533, + 19534, 19511, 19532, 17782, 17783, 17784, 28967, 17785, 34810, 41410, + 41409, 41411, 25509, 32357, 25507, 32355, 31468, 25510, 32358, 30108, + 28968, 39836, 25508, 32356, 17787, 31469, 39603, 27750, 27751, 24416, + 32313, 40346, 28755, 38972, 39083, 39151, 39162, 39173, 39184, 39195, + 39206, 39217, 38973, 38984, 38995, 39006, 39017, 39028, 39039, 31828, + 5358, 4651, 41408, 9774, 9773, 9469, 2872, 2982, 2973, 3080, 3281, 27045, + 27043, 27103, 27101, 20358, 5195, 27423, 27426, 39050, 39061, 39072, + 39084, 39095, 39106, 39117, 39128, 39139, 39147, 39148, 39149, 39150, + 39152, 39153, 39154, 39155, 39156, 39157, 39158, 39159, 39160, 39161, + 39163, 39164, 39165, 39166, 39167, 39168, 39169, 39170, 39171, 39172, + 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183, + 39185, 39186, 39187, 39188, 39189, 39190, 39191, 39192, 39193, 39194, + 39196, 39197, 39198, 39199, 39200, 39201, 39202, 39203, 39204, 39205, + 39207, 39208, 39209, 39210, 39211, 39212, 39213, 39214, 39215, 39216, + 39218, 39219, 39220, 39221, 39222, 39223, 39224, 39225, 39226, 39227, + 38974, 38975, 38976, 38977, 38978, 38979, 38980, 38981, 38982, 38983, + 38985, 38986, 38987, 38988, 38989, 38990, 38991, 38992, 38993, 38994, + 38996, 38997, 38998, 38999, 39000, 39001, 39002, 39003, 39004, 39005, + 39007, 39008, 39009, 39010, 39011, 39012, 39013, 39014, 39015, 39016, + 39018, 39019, 39020, 39021, 39022, 39023, 39024, 39025, 39026, 39027, + 39029, 39030, 39031, 39032, 39033, 39034, 39035, 39036, 39037, 39038, + 39040, 39041, 39042, 39043, 39044, 39045, 39046, 39047, 39048, 39049, + 39051, 39052, 39053, 39054, 39055, 39056, 39057, 39058, 39059, 39060, + 39062, 39063, 39064, 39065, 39066, 39067, 39068, 39069, 39070, 39071, + 39073, 39074, 39075, 39076, 39077, 39078, 39079, 39080, 39081, 39082, + 39085, 39086, 39087, 39088, 39089, 39090, 39091, 39092, 39093, 39094, + 39096, 39097, 39098, 39099, 39100, 39101, 39102, 39103, 39104, 39105, + 39107, 39108, 39109, 39110, 39111, 39112, 39113, 39114, 39115, 39116, + 39118, 39119, 39120, 39121, 39122, 39123, 39124, 39125, 39126, 39127, + 39129, 39130, 39131, 39132, 39133, 39134, 39135, 39136, 39137, 39138, + 39140, 39141, 39142, 39143, 39144, 39145, 39146, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 21777, 21778, + 21785, 21787, 21784, 21783, 21780, 21779, 21782, 21781, 21788, 21786, + 22923, 23489, 23084, 23714, 23324, 24088, 23019, 23624, 23020, 23625, + 23021, 23626, 23195, 23865, 23196, 23866, 23197, 23867, 23263, 23964, + 23003, 23607, 22999, 23603, 23709, 23833, 22933, 23499, 22934, 23500, + 23024, 23630, 23025, 23631, 23009, 23613, 23010, 23614, 23708, 23710, + 23089, 23716, 23090, 23717, 23107, 23744, 23137, 23784, 23145, 23806, + 23235, 23924, 23328, 24092, 23329, 24093, 23325, 24089, 23326, 24090, + 23508, 23882, 23883, 24043, 24044, 23973, 23974, 23698, 23699, 2324, + 2327, 2325, 2329, 2331, 2328, 2330, 2326, 2332, 10889, 10884, 10883, + 10890, 10885, 10886, 10888, 10887, 3664, 3663, 3665, 19041, 19040, 19039, + 19038, 19043, 19042, 30801, 30800, 3609, 35654, 35662, 35671, 35663, + 35665, 35660, 35664, 35659, 35675, 35674, 35677, 35669, 35656, 35676, + 35658, 35657, 35670, 35661, 35673, 35667, 35668, 35666, 35672, 35655, + 35793, 35800, 35801, 35796, 35797, 35802, 35803, 35794, 35798, 35799, + 35795, 35859, 35866, 35867, 35862, 35863, 35868, 35869, 35860, 35864, + 35865, 35861, 35970, 35977, 35978, 35973, 35974, 35979, 35980, 35971, + 35975, 35976, 35972, 35870, 35877, 35878, 35873, 35874, 35879, 35880, + 35871, 35875, 35876, 35872, 35948, 35955, 35956, 35951, 35952, 35957, + 35958, 35949, 35953, 35954, 35950, 35848, 35855, 35856, 35851, 35852, + 35857, 35858, 35849, 35853, 35854, 35850, 35959, 35966, 35967, 35962, + 35963, 35968, 35969, 35960, 35964, 35965, 35961, 35881, 35888, 35889, + 35884, 35885, 35890, 35891, 35882, 35886, 35887, 35883, 36014, 36021, + 36022, 36017, 36018, 36023, 36024, 36015, 36019, 36020, 36016, 36003, + 36010, 36011, 36006, 36007, 36012, 36013, 36004, 36008, 36009, 36005, + 36036, 36043, 36044, 36039, 36040, 36045, 36046, 36037, 36041, 36042, + 36038, 35903, 35910, 35911, 35906, 35907, 35912, 35913, 35904, 35908, + 35909, 35905, 35826, 35833, 35834, 35829, 35830, 35835, 35836, 35827, + 35831, 35832, 35828, 36025, 36032, 36033, 36028, 36029, 36034, 36035, + 36026, 36030, 36031, 36027, 35804, 35811, 35812, 35807, 35808, 35813, + 35814, 35805, 35809, 35810, 35806, 35815, 35822, 35823, 35818, 35819, + 35824, 35825, 35816, 35820, 35821, 35817, 35892, 35899, 35900, 35895, + 35896, 35901, 35902, 35893, 35897, 35898, 35894, 35837, 35844, 35845, + 35840, 35841, 35846, 35847, 35838, 35842, 35843, 35839, 35992, 35999, + 36000, 35995, 35996, 36001, 36002, 35993, 35997, 35998, 35994, 35914, + 35922, 35923, 35917, 35918, 35924, 35925, 35915, 35919, 35920, 35916, + 35926, 35933, 35934, 35929, 35930, 35935, 35936, 35927, 35931, 35932, + 35928, 35937, 35944, 35945, 35940, 35941, 35946, 35947, 35938, 35942, + 35943, 35939, 35981, 35988, 35989, 35984, 35985, 35990, 35991, 35982, + 35986, 35987, 35983, 35781, 35782, 35789, 35790, 35785, 35786, 35791, + 35792, 35783, 35787, 35788, 35784, 35921, 33887, 33885, 33886, 17964, + 22342, 22340, 22343, 22341, 22332, 22338, 22336, 22339, 22337, 22333, + 22353, 22349, 22354, 22350, 22334, 22351, 22347, 22352, 22348, 22335, + 22364, 22344, 22346, 22345, 22360, 22363, 22361, 22356, 22362, 22357, + 22358, 22359, 22365, 22355, 22504, 22381, 22382, 22383, 22380, 22499, + 22491, 20475, 20477, 20479, 20476, 20478, 21482, 21484, 21486, 21483, + 21485, 21475, 21474, 21473, 21476, 27960, 27965, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, + 41412, 41412, 41412, 41412, 41412, 41412, 41412, 41412, }; static const unsigned int aliases_start = 0xf0000; -static const unsigned int aliases_end = 0xf01dd; +static const unsigned int aliases_end = 0xf01e1; static const unsigned int name_aliases[] = { 0x0000, 0x0000, @@ -18753,6 +18960,10 @@ static const unsigned int name_aliases[] = { 0x122D5, 0x12327, 0x1680B, + 0x16881, + 0x1688E, + 0x168DC, + 0x1697D, 0x16E56, 0x16E57, 0x16E76, diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c index 0480fb08498..09c8d9487f5 100644 --- a/Modules/xxlimited.c +++ b/Modules/xxlimited.c @@ -14,7 +14,9 @@ This module roughly corresponds to:: class Xxo: - """A class that explicitly stores attributes in an internal dict""" + """A class that explicitly stores attributes in an internal dict + (to simulate custom attribute handling). + """ def __init__(self): # In the C class, "_x_attr" is not accessible from Python code @@ -85,13 +87,16 @@ typedef struct { // Instance state typedef struct { PyObject_HEAD - PyObject *x_attr; /* Attributes dictionary */ + PyObject *x_attr; /* Attributes dictionary. + * May be NULL, which acts as an + * empty dict. + */ char x_buffer[BUFSIZE]; /* buffer for Py_buffer */ Py_ssize_t x_exports; /* how many buffer are exported */ } XxoObject; #define XxoObject_CAST(op) ((XxoObject *)(op)) -// XXX: no good way to do this yet +// TODO: full support for type-checking was added in 3.14 (Py_tp_token) // #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type) static XxoObject * @@ -112,8 +117,13 @@ newXxoObject(PyObject *module) return self; } -/* Xxo finalization */ +/* Xxo finalization. + * + * Types that store references to other PyObjects generally need to implement + * the GC slots: traverse, clear, dealloc, and (optionally) finalize. + */ +// traverse: Visit all references from an object, including its type static int Xxo_traverse(PyObject *op, visitproc visit, void *arg) { @@ -126,6 +136,7 @@ Xxo_traverse(PyObject *op, visitproc visit, void *arg) return 0; } +// clear: drop references in order to break all reference cycles static int Xxo_clear(PyObject *op) { @@ -134,6 +145,8 @@ Xxo_clear(PyObject *op) return 0; } +// finalize: like clear, but should leave the object in a consistent state. +// Equivalent to `__del__` in Python. static void Xxo_finalize(PyObject *op) { @@ -141,6 +154,7 @@ Xxo_finalize(PyObject *op) Py_CLEAR(self->x_attr); } +// dealloc: drop all remaining references and free memory static void Xxo_dealloc(PyObject *self) { @@ -155,6 +169,7 @@ Xxo_dealloc(PyObject *self) /* Xxo attribute handling */ +// Get an attribute. static PyObject * Xxo_getattro(PyObject *op, PyObject *name) { @@ -168,9 +183,12 @@ Xxo_getattro(PyObject *op, PyObject *name) return NULL; } } + // Fall back to generic implementation (this handles special attributes, + // raising AttributeError, etc.) return PyObject_GenericGetAttr(op, name); } +// Set or delete an attribute. static int Xxo_setattro(PyObject *op, PyObject *name, PyObject *v) { @@ -198,7 +216,9 @@ Xxo_setattro(PyObject *op, PyObject *name, PyObject *v) } } -/* Xxo methods */ +/* Xxo methods: C functions plus a PyMethodDef array that lists them and + * specifies metadata. + */ static PyObject * Xxo_demo(PyObject *op, PyTypeObject *defining_class, @@ -234,7 +254,10 @@ static PyMethodDef Xxo_methods[] = { {NULL, NULL} /* sentinel */ }; -/* Xxo buffer interface */ +/* Xxo buffer interface: C functions later referenced from PyType_Slot array. + * Other interfaces (e.g. for sequence-like or number-like types) are defined + * similarly. + */ static int Xxo_getbuffer(PyObject *op, Py_buffer *view, int flags) @@ -300,6 +323,7 @@ static PyType_Spec Xxo_Type_spec = { /* Str type definition*/ static PyType_Slot Str_Type_slots[] = { + // slots array intentionally kept empty {0, 0}, /* sentinel */ }; @@ -400,12 +424,32 @@ xx_modexec(PyObject *m) } static PyModuleDef_Slot xx_slots[] = { + + /* exec function to initialize the module (called as part of import + * after the object was added to sys.modules) + */ {Py_mod_exec, xx_modexec}, + + /* Signal that this module supports being loaded in multiple interpreters + * with separate GILs (global interpreter locks). + * See "Isolating Extension Modules" on how to prepare a module for this: + * https://docs.python.org/3/howto/isolating-extensions.html + */ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + + /* Signal that this module does not rely on the GIL for its own needs. + * Without this slot, free-threaded builds of CPython will enable + * the GIL when this module is loaded. + */ {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL} }; +// Module finalization: modules that hold references in their module state +// need to implement the fullowing GC hooks. They're similar to the ones for +// types (see "Xxo finalization"). + static int xx_traverse(PyObject *module, visitproc visit, void *arg) { @@ -444,7 +488,9 @@ static struct PyModuleDef xxmodule = { }; -/* Export function for the module (*must* be called PyInit_xx) */ +/* Export function for the module. *Must* be called PyInit_xx; usually it is + * the only non-`static` object in a module definition. + */ PyMODINIT_FUNC PyInit_xxlimited(void) diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index e88c9de93ba..f546f3ff1cb 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -8,6 +8,7 @@ #endif #include "Python.h" +#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_CHAR_RELAXED #include "zlib.h" #include "stdbool.h" @@ -181,15 +182,6 @@ OutputBuffer_WindowOnError(_BlocksOutputBuffer *buffer, _Uint32Window *window) } -#define ENTER_ZLIB(obj) do { \ - if (!PyThread_acquire_lock((obj)->lock, 0)) { \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock((obj)->lock, 1); \ - Py_END_ALLOW_THREADS \ - } } while (0) -#define LEAVE_ZLIB(obj) PyThread_release_lock((obj)->lock); - - /* The following parameters are copied from zutil.h, version 0.95 */ #define DEFLATED 8 #if MAX_MEM_LEVEL >= 8 @@ -228,7 +220,7 @@ typedef struct char eof; bool is_initialised; PyObject *zdict; - PyThread_type_lock lock; + PyMutex mutex; } compobject; #define _compobject_CAST(op) ((compobject *)op) @@ -273,7 +265,9 @@ static compobject * newcompobject(PyTypeObject *type) { compobject *self; - self = PyObject_New(compobject, type); + assert(type != NULL); + assert(type->tp_alloc != NULL); + self = _compobject_CAST(type->tp_alloc(type, 0)); if (self == NULL) return NULL; self->eof = 0; @@ -289,12 +283,7 @@ newcompobject(PyTypeObject *type) Py_DECREF(self); return NULL; } - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - Py_DECREF(self); - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return NULL; - } + self->mutex = (PyMutex){0}; return self; } @@ -342,7 +331,7 @@ zlib_compress_impl(PyObject *module, Py_buffer *data, int level, int wbits) PyObject *return_value; int flush; z_stream zst; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; zlibstate *state = get_zlib_state(module); @@ -427,7 +416,7 @@ zlib.decompress / wbits: int(c_default="MAX_WBITS") = MAX_WBITS The window buffer size and container format. - bufsize: Py_ssize_t(c_default="DEF_BUF_SIZE") = DEF_BUF_SIZE + bufsize: Py_ssize_t(c_default="DEF_BUF_SIZE", allow_negative=False) = DEF_BUF_SIZE The initial output buffer size. Returns a bytes object containing the uncompressed data. @@ -436,22 +425,19 @@ Returns a bytes object containing the uncompressed data. static PyObject * zlib_decompress_impl(PyObject *module, Py_buffer *data, int wbits, Py_ssize_t bufsize) -/*[clinic end generated code: output=77c7e35111dc8c42 input=a9ac17beff1f893f]*/ +/*[clinic end generated code: output=77c7e35111dc8c42 input=530077065b3a2233]*/ { PyObject *return_value; Byte *ibuf; Py_ssize_t ibuflen; int err, flush; z_stream zst; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; _Uint32Window window; // output buffer's UINT32_MAX sliding window zlibstate *state = get_zlib_state(module); - if (bufsize < 0) { - PyErr_SetString(PyExc_ValueError, "bufsize must be non-negative"); - return NULL; - } else if (bufsize == 0) { + if (bufsize == 0) { bufsize = 1; } @@ -716,33 +702,41 @@ zlib_decompressobj_impl(PyObject *module, int wbits, PyObject *zdict) } static void -Dealloc(compobject *self) +compobject_dealloc_impl(PyObject *op, int (*dealloc)(z_streamp)) { - PyTypeObject *type = Py_TYPE(self); - PyThread_free_lock(self->lock); + PyTypeObject *type = Py_TYPE(op); + PyObject_GC_UnTrack(op); + compobject *self = _compobject_CAST(op); + assert(!PyMutex_IsLocked(&self->mutex)); + if (self->is_initialised) { + (void)dealloc(&self->zst); + } Py_XDECREF(self->unused_data); Py_XDECREF(self->unconsumed_tail); Py_XDECREF(self->zdict); - PyObject_Free(self); + type->tp_free(self); Py_DECREF(type); } +static int +compobject_traverse(PyObject *op, visitproc visit, void *arg) +{ + compobject *self = _compobject_CAST(op); + Py_VISIT(Py_TYPE(op)); + Py_VISIT(self->zdict); + return 0; +} + static void Comp_dealloc(PyObject *op) { - compobject *self = _compobject_CAST(op); - if (self->is_initialised) - (void)deflateEnd(&self->zst); - Dealloc(self); + compobject_dealloc_impl(op, &deflateEnd); } static void Decomp_dealloc(PyObject *op) { - compobject *self = _compobject_CAST(op); - if (self->is_initialised) - (void)inflateEnd(&self->zst); - Dealloc(self); + compobject_dealloc_impl(op, &inflateEnd); } /*[clinic input] @@ -767,10 +761,10 @@ zlib_Compress_compress_impl(compobject *self, PyTypeObject *cls, { PyObject *return_value; int err; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; zlibstate *state = PyType_GetModuleState(cls); - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); self->zst.next_in = data->buf; Py_ssize_t ibuflen = data->len; @@ -812,7 +806,7 @@ zlib_Compress_compress_impl(compobject *self, PyTypeObject *cls, OutputBuffer_OnError(&buffer); return_value = NULL; success: - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return return_value; } @@ -826,22 +820,24 @@ save_unconsumed_input(compobject *self, Py_buffer *data, int err) input data in self->unused_data. */ if (self->zst.avail_in > 0) { Py_ssize_t old_size = PyBytes_GET_SIZE(self->unused_data); - Py_ssize_t new_size, left_size; - PyObject *new_data; + Py_ssize_t left_size; left_size = (Byte *)data->buf + data->len - self->zst.next_in; if (left_size > (PY_SSIZE_T_MAX - old_size)) { PyErr_NoMemory(); return -1; } - new_size = old_size + left_size; - new_data = PyBytes_FromStringAndSize(NULL, new_size); - if (new_data == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(old_size + left_size); + if (writer == NULL) { return -1; - memcpy(PyBytes_AS_STRING(new_data), - PyBytes_AS_STRING(self->unused_data), old_size); - memcpy(PyBytes_AS_STRING(new_data) + old_size, - self->zst.next_in, left_size); - Py_SETREF(self->unused_data, new_data); + } + char *new_data = PyBytesWriter_GetData(writer); + memcpy(new_data, PyBytes_AS_STRING(self->unused_data), old_size); + memcpy(new_data + old_size, self->zst.next_in, left_size); + PyObject *new_unused_data = PyBytesWriter_Finish(writer); + if (new_unused_data == NULL) { + return -1; + } + Py_SETREF(self->unused_data, new_unused_data); self->zst.avail_in = 0; } } @@ -869,7 +865,7 @@ zlib.Decompress.decompress data: Py_buffer The binary data to decompress. / - max_length: Py_ssize_t = 0 + max_length: Py_ssize_t(allow_negative=False) = 0 The maximum allowable length of the decompressed data. Unconsumed input data will be stored in the unconsumed_tail attribute. @@ -884,26 +880,23 @@ Call the flush() method to clear these buffers. static PyObject * zlib_Decompress_decompress_impl(compobject *self, PyTypeObject *cls, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=b024a93c2c922d57 input=205667f8c387fce4]*/ +/*[clinic end generated code: output=b024a93c2c922d57 input=77de124bd2a2ecc0]*/ { int err = Z_OK; Py_ssize_t ibuflen; PyObject *return_value; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; PyObject *module = PyType_GetModule(cls); if (module == NULL) return NULL; zlibstate *state = get_zlib_state(module); - if (max_length < 0) { - PyErr_SetString(PyExc_ValueError, "max_length must be non-negative"); - return NULL; - } else if (max_length == 0) { + if (max_length == 0) { max_length = -1; } - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); self->zst.next_in = data->buf; ibuflen = data->len; @@ -956,7 +949,7 @@ zlib_Decompress_decompress_impl(compobject *self, PyTypeObject *cls, if (err == Z_STREAM_END) { /* This is the logical place to call inflateEnd, but the old behaviour of only calling it on flush() is preserved. */ - self->eof = 1; + FT_ATOMIC_STORE_CHAR_RELAXED(self->eof, 1); } else if (err != Z_OK && err != Z_BUF_ERROR) { /* We will only get Z_BUF_ERROR if the output buffer was full but there wasn't more output when we tried again, so it is @@ -975,7 +968,7 @@ zlib_Decompress_decompress_impl(compobject *self, PyTypeObject *cls, OutputBuffer_OnError(&buffer); return_value = NULL; success: - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return return_value; } @@ -999,16 +992,16 @@ zlib_Compress_flush_impl(compobject *self, PyTypeObject *cls, int mode) { int err; PyObject *return_value; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; zlibstate *state = PyType_GetModuleState(cls); /* Flushing with Z_NO_FLUSH is a no-op, so there's no point in doing any work at all; just return an empty string. */ if (mode == Z_NO_FLUSH) { - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); self->zst.avail_in = 0; @@ -1064,7 +1057,7 @@ error: OutputBuffer_OnError(&buffer); return_value = NULL; success: - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return return_value; } @@ -1088,9 +1081,9 @@ zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls) if (!return_value) return NULL; /* Copy the zstream state - * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe + * We use mutex to make this thread-safe */ - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); int err = deflateCopy(&return_value->zst, &self->zst); switch (err) { case Z_OK: @@ -1114,11 +1107,11 @@ zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls) /* Mark it as being initialized */ return_value->is_initialised = 1; - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return (PyObject *)return_value; error: - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); Py_XDECREF(return_value); return NULL; } @@ -1172,9 +1165,9 @@ zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls) if (!return_value) return NULL; /* Copy the zstream state - * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe + * We use mutex to make this thread-safe */ - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); int err = inflateCopy(&return_value->zst, &self->zst); switch (err) { case Z_OK: @@ -1199,11 +1192,11 @@ zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls) /* Mark it as being initialized */ return_value->is_initialised = 1; - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return (PyObject *)return_value; error: - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); Py_XDECREF(return_value); return NULL; } @@ -1261,7 +1254,7 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, Py_buffer data; PyObject *return_value; Py_ssize_t ibuflen; - _BlocksOutputBuffer buffer = {.list = NULL}; + _BlocksOutputBuffer buffer = {.writer = NULL}; _Uint32Window window; // output buffer's UINT32_MAX sliding window PyObject *module = PyType_GetModule(cls); @@ -1276,10 +1269,10 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, return NULL; } - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); if (PyObject_GetBuffer(self->unconsumed_tail, &data, PyBUF_SIMPLE) == -1) { - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return NULL; } @@ -1327,7 +1320,7 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, /* If at end of stream, clean up any memory allocated by zlib. */ if (err == Z_STREAM_END) { - self->eof = 1; + FT_ATOMIC_STORE_CHAR_RELAXED(self->eof, 1); self->is_initialised = 0; err = inflateEnd(&self->zst); if (err != Z_OK) { @@ -1346,7 +1339,7 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls, return_value = NULL; success: PyBuffer_Release(&data); - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return return_value; } @@ -1355,7 +1348,7 @@ typedef struct { PyObject_HEAD z_stream zst; PyObject *zdict; - PyThread_type_lock lock; + PyMutex mutex; PyObject *unused_data; uint8_t *input_buffer; Py_ssize_t input_buffer_size; @@ -1368,6 +1361,8 @@ typedef struct { char needs_input; } ZlibDecompressor; +#define ZlibDecompressor_CAST(op) ((ZlibDecompressor *)(op)) + /*[clinic input] class zlib._ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType" [clinic start generated code]*/ @@ -1376,19 +1371,29 @@ class zlib._ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType" static void ZlibDecompressor_dealloc(PyObject *op) { - ZlibDecompressor *self = (ZlibDecompressor*)op; - PyObject *type = (PyObject *)Py_TYPE(self); - PyThread_free_lock(self->lock); + PyTypeObject *type = Py_TYPE(op); + PyObject_GC_UnTrack(op); + ZlibDecompressor *self = ZlibDecompressor_CAST(op); + assert(!PyMutex_IsLocked(&self->mutex)); if (self->is_initialised) { inflateEnd(&self->zst); } PyMem_Free(self->input_buffer); Py_CLEAR(self->unused_data); Py_CLEAR(self->zdict); - PyObject_Free(self); + type->tp_free(self); Py_DECREF(type); } +static int +ZlibDecompressor_traverse(PyObject *op, visitproc visit, void *arg) +{ + ZlibDecompressor *self = ZlibDecompressor_CAST(op); + Py_VISIT(Py_TYPE(op)); + Py_VISIT(self->zdict); + return 0; +} + static int set_inflate_zdict_ZlibDecompressor(zlibstate *state, ZlibDecompressor *self) { @@ -1527,7 +1532,7 @@ decompress_buf(ZlibDecompressor *self, Py_ssize_t max_length) } while(err != Z_STREAM_END && self->avail_in_real != 0); if (err == Z_STREAM_END) { - self->eof = 1; + FT_ATOMIC_STORE_CHAR_RELAXED(self->eof, 1); self->is_initialised = 0; /* Unlike the Decompress object we call inflateEnd here as there are no backwards compatibility issues */ @@ -1615,7 +1620,7 @@ decompress(ZlibDecompressor *self, uint8_t *data, } if (self->eof) { - self->needs_input = 0; + FT_ATOMIC_STORE_CHAR_RELAXED(self->needs_input, 0); if (self->avail_in_real > 0) { PyObject *unused_data = PyBytes_FromStringAndSize( @@ -1628,10 +1633,10 @@ decompress(ZlibDecompressor *self, uint8_t *data, } else if (self->avail_in_real == 0) { self->zst.next_in = NULL; - self->needs_input = 1; + FT_ATOMIC_STORE_CHAR_RELAXED(self->needs_input, 1); } else { - self->needs_input = 0; + FT_ATOMIC_STORE_CHAR_RELAXED(self->needs_input, 0); /* If we did not use the input buffer, we now have to copy the tail from the caller's buffer into the @@ -1700,14 +1705,14 @@ zlib__ZlibDecompressor_decompress_impl(ZlibDecompressor *self, { PyObject *result = NULL; - ENTER_ZLIB(self); + PyMutex_Lock(&self->mutex); if (self->eof) { PyErr_SetString(PyExc_EOFError, "End of stream already reached"); } else { result = decompress(self, data->buf, data->len, max_length); } - LEAVE_ZLIB(self); + PyMutex_Unlock(&self->mutex); return result; } @@ -1731,8 +1736,9 @@ static PyObject * zlib__ZlibDecompressor_impl(PyTypeObject *type, int wbits, PyObject *zdict) /*[clinic end generated code: output=1065607df0d33baa input=9ebad0be6de226e2]*/ { + assert(type != NULL && type->tp_alloc != NULL); zlibstate *state = PyType_GetModuleState(type); - ZlibDecompressor *self = PyObject_New(ZlibDecompressor, type); + ZlibDecompressor *self = ZlibDecompressor_CAST(type->tp_alloc(type, 0)); if (self == NULL) { return NULL; } @@ -1747,17 +1753,8 @@ zlib__ZlibDecompressor_impl(PyTypeObject *type, int wbits, PyObject *zdict) self->zst.zfree = PyZlib_Free; self->zst.next_in = NULL; self->zst.avail_in = 0; - self->unused_data = PyBytes_FromStringAndSize(NULL, 0); - if (self->unused_data == NULL) { - Py_CLEAR(self); - return NULL; - } - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - Py_DECREF(self); - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return NULL; - } + self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + self->mutex = (PyMutex){0}; int err = inflateInit2(&(self->zst), wbits); switch (err) { case Z_OK: @@ -1812,10 +1809,36 @@ static PyMethodDef ZlibDecompressor_methods[] = { {NULL} }; +static PyObject * +Decomp_unused_data_get(PyObject *op, void *Py_UNUSED(ignored)) +{ + compobject *self = _compobject_CAST(op); + PyMutex_Lock(&self->mutex); + assert(self->unused_data != NULL); + PyObject *result = Py_NewRef(self->unused_data); + PyMutex_Unlock(&self->mutex); + return result; +} + +static PyObject * +Decomp_unconsumed_tail_get(PyObject *op, void *Py_UNUSED(ignored)) +{ + compobject *self = _compobject_CAST(op); + PyMutex_Lock(&self->mutex); + assert(self->unconsumed_tail != NULL); + PyObject *result = Py_NewRef(self->unconsumed_tail); + PyMutex_Unlock(&self->mutex); + return result; +} + +static PyGetSetDef Decomp_getset[] = { + {"unused_data", Decomp_unused_data_get, NULL, NULL}, + {"unconsumed_tail", Decomp_unconsumed_tail_get, NULL, NULL}, + {NULL}, +}; + #define COMP_OFF(x) offsetof(compobject, x) static PyMemberDef Decomp_members[] = { - {"unused_data", _Py_T_OBJECT, COMP_OFF(unused_data), Py_READONLY}, - {"unconsumed_tail", _Py_T_OBJECT, COMP_OFF(unconsumed_tail), Py_READONLY}, {"eof", Py_T_BOOL, COMP_OFF(eof), Py_READONLY}, {NULL}, }; @@ -1829,11 +1852,26 @@ PyDoc_STRVAR(ZlibDecompressor_unused_data__doc__, PyDoc_STRVAR(ZlibDecompressor_needs_input_doc, "True if more input is needed before more decompressed data can be produced."); +static PyObject * +ZlibDecompressor_unused_data_get(PyObject *op, void *Py_UNUSED(ignored)) +{ + ZlibDecompressor *self = ZlibDecompressor_CAST(op); + PyMutex_Lock(&self->mutex); + assert(self->unused_data != NULL); + PyObject *result = Py_NewRef(self->unused_data); + PyMutex_Unlock(&self->mutex); + return result; +} + +static PyGetSetDef ZlibDecompressor_getset[] = { + {"unused_data", ZlibDecompressor_unused_data_get, NULL, + ZlibDecompressor_unused_data__doc__}, + {NULL}, +}; + static PyMemberDef ZlibDecompressor_members[] = { {"eof", Py_T_BOOL, offsetof(ZlibDecompressor, eof), Py_READONLY, ZlibDecompressor_eof__doc__}, - {"unused_data", Py_T_OBJECT_EX, offsetof(ZlibDecompressor, unused_data), - Py_READONLY, ZlibDecompressor_unused_data__doc__}, {"needs_input", Py_T_BOOL, offsetof(ZlibDecompressor, needs_input), Py_READONLY, ZlibDecompressor_needs_input_doc}, {NULL}, @@ -2000,6 +2038,27 @@ zlib_crc32_combine_impl(PyObject *module, unsigned int crc1, return crc32_combine(crc1, crc2, len); } +static PyObject * +zlib_getattr(PyObject *self, PyObject *args) +{ + PyObject *name; + if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)) { + return NULL; + } + + if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "'__version__' is deprecated and slated for removal in Python 3.20", + 1) < 0) { + return NULL; + } + return PyUnicode_FromString("1.0"); + } + + PyErr_Format(PyExc_AttributeError, "module 'zlib' has no attribute %R", name); + return NULL; +} + static PyMethodDef zlib_methods[] = { ZLIB_ADLER32_METHODDEF @@ -2010,11 +2069,13 @@ static PyMethodDef zlib_methods[] = ZLIB_CRC32_COMBINE_METHODDEF ZLIB_DECOMPRESS_METHODDEF ZLIB_DECOMPRESSOBJ_METHODDEF + {"__getattr__", zlib_getattr, METH_VARARGS, "Module __getattr__"}, {NULL, NULL} }; static PyType_Slot Comptype_slots[] = { {Py_tp_dealloc, Comp_dealloc}, + {Py_tp_traverse, compobject_traverse}, {Py_tp_methods, comp_methods}, {0, 0}, }; @@ -2022,27 +2083,41 @@ static PyType_Slot Comptype_slots[] = { static PyType_Spec Comptype_spec = { .name = "zlib.Compress", .basicsize = sizeof(compobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HAVE_GC + ), .slots= Comptype_slots, }; static PyType_Slot Decomptype_slots[] = { {Py_tp_dealloc, Decomp_dealloc}, + {Py_tp_traverse, compobject_traverse}, {Py_tp_methods, Decomp_methods}, {Py_tp_members, Decomp_members}, + {Py_tp_getset, Decomp_getset}, {0, 0}, }; static PyType_Spec Decomptype_spec = { .name = "zlib.Decompress", .basicsize = sizeof(compobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HAVE_GC + ), .slots = Decomptype_slots, }; static PyType_Slot ZlibDecompressor_type_slots[] = { {Py_tp_dealloc, ZlibDecompressor_dealloc}, + {Py_tp_traverse, ZlibDecompressor_traverse}, {Py_tp_members, ZlibDecompressor_members}, + {Py_tp_getset, ZlibDecompressor_getset}, {Py_tp_new, zlib__ZlibDecompressor}, {Py_tp_doc, (char *)zlib__ZlibDecompressor__doc__}, {Py_tp_methods, ZlibDecompressor_methods}, @@ -2056,7 +2131,11 @@ static PyType_Spec ZlibDecompressor_type_spec = { // ZlibDecompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. - .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HAVE_GC + ), .slots = ZlibDecompressor_type_slots, }; @@ -2189,9 +2268,6 @@ zlib_exec(PyObject *mod) return -1; } #endif - if (PyModule_AddStringConstant(mod, "__version__", "1.0") < 0) { - return -1; - } return 0; } diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 3cb2d411a30..25cc0bfcbab 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -17,8 +17,8 @@ class bytearray "PyByteArrayObject *" "&PyByteArray_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=5535b77c37a119e0]*/ -/* For PyByteArray_AS_STRING(). */ -char _PyByteArray_empty_string[] = ""; +/* Max number of bytes a bytearray can contain */ +#define PyByteArray_SIZE_MAX ((Py_ssize_t)(PY_SSIZE_T_MAX - _PyBytesObject_SIZE)) /* Helpers */ @@ -43,6 +43,14 @@ _getbytevalue(PyObject* arg, int *value) return 1; } +static void +bytearray_reinit_from_bytes(PyByteArrayObject *self, Py_ssize_t size, + Py_ssize_t alloc) { + self->ob_bytes = self->ob_start = PyBytes_AS_STRING(self->ob_bytes_object); + Py_SET_SIZE(self, size); + FT_ATOMIC_STORE_SSIZE_RELAXED(self->ob_alloc, alloc); +} + static int bytearray_getbuffer_lock_held(PyObject *self, Py_buffer *view, int flags) { @@ -127,7 +135,6 @@ PyObject * PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size) { PyByteArrayObject *new; - Py_ssize_t alloc; if (size < 0) { PyErr_SetString(PyExc_SystemError, @@ -135,35 +142,32 @@ PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size) return NULL; } - /* Prevent buffer overflow when setting alloc to size+1. */ - if (size == PY_SSIZE_T_MAX) { - return PyErr_NoMemory(); - } - new = PyObject_New(PyByteArrayObject, &PyByteArray_Type); - if (new == NULL) + if (new == NULL) { return NULL; + } - if (size == 0) { - new->ob_bytes = NULL; - alloc = 0; - } - else { - alloc = size + 1; - new->ob_bytes = PyMem_Malloc(alloc); - if (new->ob_bytes == NULL) { - Py_DECREF(new); - return PyErr_NoMemory(); - } - if (bytes != NULL && size > 0) - memcpy(new->ob_bytes, bytes, size); - new->ob_bytes[size] = '\0'; /* Trailing null byte */ - } - Py_SET_SIZE(new, size); - new->ob_alloc = alloc; - new->ob_start = new->ob_bytes; + /* Fill values used in bytearray_dealloc. + + In an optimized build the memory isn't zeroed and ob_exports would be + uninitialized when when PyBytes_FromStringAndSize errored leading to + intermittent test failures. */ new->ob_exports = 0; + /* Optimization: size=0 bytearray should not allocate space + + PyBytes_FromStringAndSize returns the empty bytes global when size=0 so + no allocation occurs. */ + new->ob_bytes_object = PyBytes_FromStringAndSize(NULL, size); + if (new->ob_bytes_object == NULL) { + Py_DECREF(new); + return NULL; + } + bytearray_reinit_from_bytes(new, size, size); + if (bytes != NULL && size > 0) { + memcpy(new->ob_bytes, bytes, size); + } + return (PyObject *)new; } @@ -189,7 +193,6 @@ static int bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size) { _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); - void *sval; PyByteArrayObject *obj = ((PyByteArrayObject *)self); /* All computations are done unsigned to avoid integer overflows (see issue #22335). */ @@ -214,16 +217,17 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size) return -1; } - if (size + logical_offset + 1 <= alloc) { + if (size + logical_offset <= alloc) { /* Current buffer is large enough to host the requested size, decide on a strategy. */ if (size < alloc / 2) { /* Major downsize; resize down to exact size */ - alloc = size + 1; + alloc = size; } else { /* Minor downsize; quick exit */ Py_SET_SIZE(self, size); + /* Add mid-buffer null; end provided by bytes. */ PyByteArray_AS_STRING(self)[size] = '\0'; /* Trailing null */ return 0; } @@ -236,38 +240,36 @@ bytearray_resize_lock_held(PyObject *self, Py_ssize_t requested_size) } else { /* Major upsize; resize up to exact size */ - alloc = size + 1; + alloc = size; } } - if (alloc > PY_SSIZE_T_MAX) { + if (alloc > PyByteArray_SIZE_MAX) { PyErr_NoMemory(); return -1; } + /* Re-align data to the start of the allocation. */ if (logical_offset > 0) { - sval = PyMem_Malloc(alloc); - if (sval == NULL) { - PyErr_NoMemory(); - return -1; - } - memcpy(sval, PyByteArray_AS_STRING(self), - Py_MIN((size_t)requested_size, (size_t)Py_SIZE(self))); - PyMem_Free(obj->ob_bytes); - } - else { - sval = PyMem_Realloc(obj->ob_bytes, alloc); - if (sval == NULL) { - PyErr_NoMemory(); - return -1; - } + /* optimization tradeoff: This is faster than a new allocation when + the number of bytes being removed in a resize is small; for large + size changes it may be better to just make a new bytes object as + _PyBytes_Resize will do a malloc + memcpy internally. */ + memmove(obj->ob_bytes, obj->ob_start, + Py_MIN(requested_size, Py_SIZE(self))); } - obj->ob_bytes = obj->ob_start = sval; - Py_SET_SIZE(self, size); - FT_ATOMIC_STORE_SSIZE_RELAXED(obj->ob_alloc, alloc); - obj->ob_bytes[size] = '\0'; /* Trailing null byte */ + int ret = _PyBytes_Resize(&obj->ob_bytes_object, alloc); + if (ret == -1) { + obj->ob_bytes_object = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + size = alloc = 0; + } + bytearray_reinit_from_bytes(obj, size, alloc); + if (alloc != size) { + /* Add mid-buffer null; end provided by bytes. */ + obj->ob_bytes[size] = '\0'; + } - return 0; + return ret; } int @@ -295,7 +297,7 @@ PyByteArray_Concat(PyObject *a, PyObject *b) goto done; } - if (va.len > PY_SSIZE_T_MAX - vb.len) { + if (va.len > PyByteArray_SIZE_MAX - vb.len) { PyErr_NoMemory(); goto done; } @@ -339,7 +341,7 @@ bytearray_iconcat_lock_held(PyObject *op, PyObject *other) } Py_ssize_t size = Py_SIZE(self); - if (size > PY_SSIZE_T_MAX - vo.len) { + if (size > PyByteArray_SIZE_MAX - vo.len) { PyBuffer_Release(&vo); return PyErr_NoMemory(); } @@ -373,7 +375,7 @@ bytearray_repeat_lock_held(PyObject *op, Py_ssize_t count) count = 0; } const Py_ssize_t mysize = Py_SIZE(self); - if (count > 0 && mysize > PY_SSIZE_T_MAX / count) { + if (count > 0 && mysize > PyByteArray_SIZE_MAX / count) { return PyErr_NoMemory(); } Py_ssize_t size = mysize * count; @@ -409,7 +411,7 @@ bytearray_irepeat_lock_held(PyObject *op, Py_ssize_t count) } const Py_ssize_t mysize = Py_SIZE(self); - if (count > 0 && mysize > PY_SSIZE_T_MAX / count) { + if (count > 0 && mysize > PyByteArray_SIZE_MAX / count) { return PyErr_NoMemory(); } const Py_ssize_t size = mysize * count; @@ -585,7 +587,7 @@ bytearray_setslice_linear(PyByteArrayObject *self, buf = PyByteArray_AS_STRING(self); } else if (growth > 0) { - if (Py_SIZE(self) > (Py_ssize_t)PY_SSIZE_T_MAX - growth) { + if (Py_SIZE(self) > PyByteArray_SIZE_MAX - growth) { PyErr_NoMemory(); return -1; } @@ -899,12 +901,23 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, PyObject *it; PyObject *(*iternext)(PyObject *); + /* First __init__; set ob_bytes_object so ob_bytes is always non-null. */ + if (self->ob_bytes_object == NULL) { + self->ob_bytes_object = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + bytearray_reinit_from_bytes(self, 0, 0); + self->ob_exports = 0; + } + if (Py_SIZE(self) != 0) { /* Empty previous contents (yes, do this first of all!) */ if (PyByteArray_Resize((PyObject *)self, 0) < 0) return -1; } + /* Should be caused by first init or the resize to 0. */ + assert(self->ob_bytes_object == Py_GetConstantBorrowed(Py_CONSTANT_EMPTY_BYTES)); + assert(self->ob_exports == 0); + /* Make a quick exit if no first argument */ if (arg == NULL) { if (encoding != NULL || errors != NULL) { @@ -926,9 +939,20 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, return -1; } encoded = PyUnicode_AsEncodedString(arg, encoding, errors); - if (encoded == NULL) + if (encoded == NULL) { return -1; + } assert(PyBytes_Check(encoded)); + + /* Most encodes return a new unique bytes, just use it as buffer. */ + if (_PyObject_IsUniquelyReferenced(encoded) + && PyBytes_CheckExact(encoded)) + { + Py_ssize_t size = Py_SIZE(encoded); + self->ob_bytes_object = encoded; + bytearray_reinit_from_bytes(self, size, size); + return 0; + } new = bytearray_iconcat((PyObject*)self, encoded); Py_DECREF(encoded); if (new == NULL) @@ -1067,95 +1091,20 @@ slowpath: return -1; } -/* Mostly copied from string_repr, but without the - "smart quote" functionality. */ static PyObject * bytearray_repr_lock_held(PyObject *op) { _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); - PyByteArrayObject *self = _PyByteArray_CAST(op); - const char *className = _PyType_Name(Py_TYPE(self)); - const char *quote_prefix = "(b"; - const char *quote_postfix = ")"; - Py_ssize_t length = Py_SIZE(self); - /* 6 == strlen(quote_prefix) + 2 + strlen(quote_postfix) + 1 */ - Py_ssize_t newsize; - PyObject *v; - Py_ssize_t i; - char *bytes; - char c; - char *p; - int quote; - char *test, *start; - char *buffer; - - newsize = strlen(className); - if (length > (PY_SSIZE_T_MAX - 6 - newsize) / 4) { - PyErr_SetString(PyExc_OverflowError, - "bytearray object is too large to make repr"); + const char *className = _PyType_Name(Py_TYPE(op)); + PyObject *bytes_repr = _Py_bytes_repr(PyByteArray_AS_STRING(op), + PyByteArray_GET_SIZE(op), 1, + "bytearray"); + if (bytes_repr == NULL) { return NULL; } - - newsize += 6 + length * 4; - buffer = PyMem_Malloc(newsize); - if (buffer == NULL) { - PyErr_NoMemory(); - return NULL; - } - - /* Figure out which quote to use; single is preferred */ - quote = '\''; - start = PyByteArray_AS_STRING(self); - for (test = start; test < start+length; ++test) { - if (*test == '"') { - quote = '\''; /* back to single */ - break; - } - else if (*test == '\'') - quote = '"'; - } - - p = buffer; - while (*className) - *p++ = *className++; - while (*quote_prefix) - *p++ = *quote_prefix++; - *p++ = quote; - - bytes = PyByteArray_AS_STRING(self); - for (i = 0; i < length; i++) { - /* There's at least enough room for a hex escape - and a closing quote. */ - assert(newsize - (p - buffer) >= 5); - c = bytes[i]; - if (c == '\'' || c == '\\') - *p++ = '\\', *p++ = c; - else if (c == '\t') - *p++ = '\\', *p++ = 't'; - else if (c == '\n') - *p++ = '\\', *p++ = 'n'; - else if (c == '\r') - *p++ = '\\', *p++ = 'r'; - else if (c == 0) - *p++ = '\\', *p++ = 'x', *p++ = '0', *p++ = '0'; - else if (c < ' ' || c >= 0x7f) { - *p++ = '\\'; - *p++ = 'x'; - *p++ = Py_hexdigits[(c & 0xf0) >> 4]; - *p++ = Py_hexdigits[c & 0xf]; - } - else - *p++ = c; - } - assert(newsize - (p - buffer) >= 1); - *p++ = quote; - while (*quote_postfix) { - *p++ = *quote_postfix++; - } - - v = PyUnicode_FromStringAndSize(buffer, p - buffer); - PyMem_Free(buffer); - return v; + PyObject *res = PyUnicode_FromFormat("%s(%U)", className, bytes_repr); + Py_DECREF(bytes_repr); + return res; } static PyObject * @@ -1244,9 +1193,7 @@ bytearray_dealloc(PyObject *op) "deallocated bytearray object has exported buffers"); PyErr_Print(); } - if (self->ob_bytes != 0) { - PyMem_Free(self->ob_bytes); - } + Py_XDECREF(self->ob_bytes_object); Py_TYPE(self)->tp_free((PyObject *)self); } @@ -1544,14 +1491,14 @@ bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix) /*[clinic input] bytearray.resize size: Py_ssize_t - New size to resize to.. + New size to resize to. / Resize the internal buffer of bytearray to len. [clinic start generated code]*/ static PyObject * bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size) -/*[clinic end generated code: output=f73524922990b2d9 input=75fd4d17c4aa47d3]*/ +/*[clinic end generated code: output=f73524922990b2d9 input=6c9a260ca7f72071]*/ { Py_ssize_t start_size = PyByteArray_GET_SIZE(self); int result = PyByteArray_Resize((PyObject *)self, size); @@ -1566,6 +1513,94 @@ bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size) } +/*[clinic input] +@critical_section +bytearray.take_bytes + n: object = None + Bytes to take, negative indexes from end. None indicates all bytes. + / +Take *n* bytes from the bytearray and return them as a bytes object. +[clinic start generated code]*/ + +static PyObject * +bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n) +/*[clinic end generated code: output=3147fbc0bbbe8d94 input=b15b5172cdc6deda]*/ +{ + Py_ssize_t to_take; + Py_ssize_t size = Py_SIZE(self); + if (Py_IsNone(n)) { + to_take = size; + } + // Integer index, from start (zero, positive) or end (negative). + else if (_PyIndex_Check(n)) { + to_take = PyNumber_AsSsize_t(n, PyExc_IndexError); + if (to_take == -1 && PyErr_Occurred()) { + return NULL; + } + if (to_take < 0) { + to_take += size; + } + } + else { + PyErr_SetString(PyExc_TypeError, "n must be an integer or None"); + return NULL; + } + + if (to_take < 0 || to_take > size) { + PyErr_Format(PyExc_IndexError, + "can't take %zd bytes outside size %zd", + to_take, size); + return NULL; + } + + // Exports may change the contents. No mutable bytes allowed. + if (!_canresize(self)) { + return NULL; + } + + if (to_take == 0 || size == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } + + Py_ssize_t remaining_length = size - to_take; + // optimization: If taking less than leaving, just copy the small to_take + // portion out and move ob_start. + if (to_take < remaining_length) { + PyObject *ret = PyBytes_FromStringAndSize(self->ob_start, to_take); + if (ret == NULL) { + return NULL; + } + self->ob_start += to_take; + Py_SET_SIZE(self, remaining_length); + return ret; + } + + // Copy remaining bytes to a new bytes. + PyObject *remaining = PyBytes_FromStringAndSize(self->ob_start + to_take, + remaining_length); + if (remaining == NULL) { + return NULL; + } + + // If the bytes are offset inside the buffer must first align. + if (self->ob_start != self->ob_bytes) { + memmove(self->ob_bytes, self->ob_start, to_take); + self->ob_start = self->ob_bytes; + } + + if (_PyBytes_Resize(&self->ob_bytes_object, to_take) == -1) { + Py_DECREF(remaining); + return NULL; + } + + // Point the bytearray towards the buffer with the remaining data. + PyObject *result = self->ob_bytes_object; + self->ob_bytes_object = remaining; + bytearray_reinit_from_bytes(self, remaining_length, remaining_length); + return result; +} + + /*[clinic input] @critical_section bytearray.translate @@ -1943,11 +1978,6 @@ bytearray_insert_impl(PyByteArrayObject *self, Py_ssize_t index, int item) Py_ssize_t n = Py_SIZE(self); char *buf; - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to bytearray"); - return NULL; - } if (bytearray_resize_lock_held((PyObject *)self, n + 1) < 0) return NULL; buf = PyByteArray_AS_STRING(self); @@ -2062,11 +2092,6 @@ bytearray_append_impl(PyByteArrayObject *self, int item) { Py_ssize_t n = Py_SIZE(self); - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to bytearray"); - return NULL; - } if (bytearray_resize_lock_held((PyObject *)self, n + 1) < 0) return NULL; @@ -2174,16 +2199,16 @@ bytearray_extend_impl(PyByteArrayObject *self, PyObject *iterable_of_ints) if (len >= buf_size) { Py_ssize_t addition; - if (len == PY_SSIZE_T_MAX) { + if (len == PyByteArray_SIZE_MAX) { Py_DECREF(it); Py_DECREF(bytearray_obj); return PyErr_NoMemory(); } addition = len >> 1; - if (addition > PY_SSIZE_T_MAX - len - 1) - buf_size = PY_SSIZE_T_MAX; + if (addition > PyByteArray_SIZE_MAX - len) + buf_size = PyByteArray_SIZE_MAX; else - buf_size = len + addition + 1; + buf_size = len + addition; if (bytearray_resize_lock_held((PyObject *)bytearray_obj, buf_size) < 0) { Py_DECREF(it); Py_DECREF(bytearray_obj); @@ -2480,7 +2505,11 @@ static PyObject * bytearray_alloc(PyObject *op, PyObject *Py_UNUSED(ignored)) { PyByteArrayObject *self = _PyByteArray_CAST(op); - return PyLong_FromSsize_t(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->ob_alloc)); + Py_ssize_t alloc = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->ob_alloc); + if (alloc > 0) { + alloc += _PyBytesObject_SIZE; + } + return PyLong_FromSsize_t(alloc); } /*[clinic input] @@ -2676,9 +2705,13 @@ static PyObject * bytearray_sizeof_impl(PyByteArrayObject *self) /*[clinic end generated code: output=738abdd17951c427 input=e27320fd98a4bc5a]*/ { - size_t res = _PyObject_SIZE(Py_TYPE(self)); - res += (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(self->ob_alloc) * sizeof(char); - return PyLong_FromSize_t(res); + Py_ssize_t res = _PyObject_SIZE(Py_TYPE(self)); + Py_ssize_t alloc = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->ob_alloc); + if (alloc > 0) { + res += _PyBytesObject_SIZE + alloc; + } + + return PyLong_FromSsize_t(res); } static PySequenceMethods bytearray_as_sequence = { @@ -2761,6 +2794,7 @@ static PyMethodDef bytearray_methods[] = { BYTEARRAY_STARTSWITH_METHODDEF BYTEARRAY_STRIP_METHODDEF {"swapcase", bytearray_swapcase, METH_NOARGS, _Py_swapcase__doc__}, + BYTEARRAY_TAKE_BYTES_METHODDEF {"title", bytearray_title, METH_NOARGS, _Py_title__doc__}, BYTEARRAY_TRANSLATE_METHODDEF {"upper", bytearray_upper, METH_NOARGS, _Py_upper__doc__}, diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index c239ae18a59..56a461d0dd0 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -356,26 +356,24 @@ The bytes objects frm and to must be of the same length."); PyObject * _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to) { - PyObject *res = NULL; - Py_ssize_t i; - char *p; - if (frm->len != to->len) { PyErr_Format(PyExc_ValueError, "maketrans arguments must have same length"); return NULL; } - res = PyBytes_FromStringAndSize(NULL, 256); - if (!res) + PyBytesWriter *writer = PyBytesWriter_Create(256); + if (!writer) { return NULL; - p = PyBytes_AS_STRING(res); + } + char *p = PyBytesWriter_GetData(writer); + Py_ssize_t i; for (i = 0; i < 256; i++) p[i] = (char) i; for (i = 0; i < frm->len; i++) { p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i]; } - return res; + return PyBytesWriter_Finish(writer); } #define FASTSEARCH fastsearch diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index db82f7eb684..2b0925017f2 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -7,6 +7,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_GetBuiltin() #include "pycore_format.h" // F_LJUST +#include "pycore_freelist.h" // _Py_FREELIST_FREE() #include "pycore_global_objects.h"// _Py_GET_GLOBAL_OBJECT() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _PyLong_DigitValue @@ -24,17 +25,12 @@ class bytes "PyBytesObject *" "&PyBytes_Type" #include "clinic/bytesobject.c.h" -/* PyBytesObject_SIZE gives the basic size of a bytes object; any memory allocation - for a bytes object of length n should request PyBytesObject_SIZE + n bytes. - - Using PyBytesObject_SIZE instead of sizeof(PyBytesObject) saves - 3 or 7 bytes per bytes object allocation on a typical system. -*/ -#define PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1) +#define PyBytesObject_SIZE _PyBytesObject_SIZE /* Forward declaration */ -Py_LOCAL_INLINE(Py_ssize_t) _PyBytesWriter_GetSize(_PyBytesWriter *writer, - char *str); +static void* _PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, + Py_ssize_t size, void *data); +static Py_ssize_t _PyBytesWriter_GetAllocated(PyBytesWriter *writer); #define CHARACTERS _Py_SINGLETON(bytes_characters) @@ -195,10 +191,11 @@ PyBytes_FromString(const char *str) return (PyObject *) op; } -PyObject * -PyBytes_FromFormatV(const char *format, va_list vargs) + +static char* +bytes_fromformat(PyBytesWriter *writer, Py_ssize_t writer_pos, + const char *format, va_list vargs) { - char *s; const char *f; const char *p; Py_ssize_t prec; @@ -212,21 +209,20 @@ PyBytes_FromFormatV(const char *format, va_list vargs) Longest 64-bit pointer representation: "0xffffffffffffffff\0" (19 bytes). */ char buffer[21]; - _PyBytesWriter writer; - _PyBytesWriter_Init(&writer); + char *s = (char*)PyBytesWriter_GetData(writer) + writer_pos; - s = _PyBytesWriter_Alloc(&writer, strlen(format)); - if (s == NULL) - return NULL; - writer.overallocate = 1; - -#define WRITE_BYTES(str) \ +#define WRITE_BYTES_LEN(str, len_expr) \ do { \ - s = _PyBytesWriter_WriteBytes(&writer, s, (str), strlen(str)); \ - if (s == NULL) \ + size_t len = (len_expr); \ + s = PyBytesWriter_GrowAndUpdatePointer(writer, len, s); \ + if (s == NULL) { \ goto error; \ + } \ + memcpy(s, (str), len); \ + s += len; \ } while (0) +#define WRITE_BYTES(str) WRITE_BYTES_LEN(str, strlen(str)) for (f = format; *f; f++) { if (*f != '%') { @@ -267,10 +263,6 @@ PyBytes_FromFormatV(const char *format, va_list vargs) ++f; } - /* subtract bytes preallocated for the format string - (ex: 2 for "%s") */ - writer.min_size -= (f - p + 1); - switch (*f) { case 'c': { @@ -281,7 +273,6 @@ PyBytes_FromFormatV(const char *format, va_list vargs) "expects an integer in range [0; 255]"); goto error; } - writer.min_size++; *s++ = (unsigned char)c; break; } @@ -340,9 +331,7 @@ PyBytes_FromFormatV(const char *format, va_list vargs) i++; } } - s = _PyBytesWriter_WriteBytes(&writer, s, p, i); - if (s == NULL) - goto error; + WRITE_BYTES_LEN(p, i); break; } @@ -361,31 +350,45 @@ PyBytes_FromFormatV(const char *format, va_list vargs) break; case '%': - writer.min_size++; *s++ = '%'; break; default: - if (*f == 0) { - /* fix min_size if we reached the end of the format string */ - writer.min_size++; - } - /* invalid format string: copy unformatted string and exit */ WRITE_BYTES(p); - return _PyBytesWriter_Finish(&writer, s); + return s; } } #undef WRITE_BYTES +#undef WRITE_BYTES_LEN - return _PyBytesWriter_Finish(&writer, s); + return s; error: - _PyBytesWriter_Dealloc(&writer); return NULL; } + +PyObject * +PyBytes_FromFormatV(const char *format, va_list vargs) +{ + Py_ssize_t alloc = strlen(format); + PyBytesWriter *writer = PyBytesWriter_Create(alloc); + if (writer == NULL) { + return NULL; + } + + char *s = bytes_fromformat(writer, 0, format, vargs); + if (s == NULL) { + PyBytesWriter_Discard(writer); + return NULL; + } + + return PyBytesWriter_FinishWithPointer(writer, s); +} + + PyObject * PyBytes_FromFormat(const char *format, ...) { @@ -398,6 +401,7 @@ PyBytes_FromFormat(const char *format, ...) return ret; } + /* Helpers for formatstring */ Py_LOCAL_INLINE(PyObject *) @@ -420,7 +424,7 @@ getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) static char* formatfloat(PyObject *v, int flags, int prec, int type, - PyObject **p_result, _PyBytesWriter *writer, char *str) + PyObject **p_result, PyBytesWriter *writer, char *str) { char *p; PyObject *result; @@ -448,7 +452,7 @@ formatfloat(PyObject *v, int flags, int prec, int type, len = strlen(p); if (writer != NULL) { - str = _PyBytesWriter_Prepare(writer, str, len); + str = PyBytesWriter_GrowAndUpdatePointer(writer, len, str); if (str == NULL) { PyMem_Free(p); return NULL; @@ -599,12 +603,10 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, PyObject *args, int use_bytearray) { const char *fmt; - char *res; Py_ssize_t arglen, argidx; Py_ssize_t fmtcnt; int args_owned = 0; PyObject *dict = NULL; - _PyBytesWriter writer; if (args == NULL) { PyErr_BadInternalCall(); @@ -613,14 +615,17 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, fmt = format; fmtcnt = format_len; - _PyBytesWriter_Init(&writer); - writer.use_bytearray = use_bytearray; - - res = _PyBytesWriter_Alloc(&writer, fmtcnt); - if (res == NULL) + PyBytesWriter *writer; + if (use_bytearray) { + writer = _PyBytesWriter_CreateByteArray(fmtcnt); + } + else { + writer = PyBytesWriter_Create(fmtcnt); + } + if (writer == NULL) { return NULL; - if (!use_bytearray) - writer.overallocate = 1; + } + char *res = PyBytesWriter_GetData(writer); if (PyTuple_Check(args)) { arglen = PyTuple_GET_SIZE(args); @@ -825,7 +830,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, if (fmtcnt == 0) { /* last write: disable writer overallocation */ - writer.overallocate = 0; + writer->overallocate = 0; } sign = 0; @@ -888,8 +893,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, } /* Fast path */ - writer.min_size -= 2; /* size preallocated for "%d" */ - res = _PyLong_FormatBytesWriter(&writer, res, + res = _PyLong_FormatBytesWriter(writer, res, v, base, alternate); if (res == NULL) goto error; @@ -917,8 +921,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, && !(flags & (F_SIGN | F_BLANK))) { /* Fast path */ - writer.min_size -= 2; /* size preallocated for "%f" */ - res = formatfloat(v, flags, prec, c, NULL, &writer, res); + res = formatfloat(v, flags, prec, c, NULL, writer, res); if (res == NULL) goto error; continue; @@ -974,9 +977,11 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, alloc++; /* 2: size preallocated for %s */ if (alloc > 2) { - res = _PyBytesWriter_Prepare(&writer, res, alloc - 2); - if (res == NULL) + res = PyBytesWriter_GrowAndUpdatePointer(writer, alloc - 2, res); + if (res == NULL) { + Py_XDECREF(temp); goto error; + } } #ifndef NDEBUG char *before = res; @@ -1052,7 +1057,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, /* If overallocation was disabled, ensure that it was the last write. Otherwise, we missed an optimization */ - assert(writer.overallocate || fmtcnt == 0 || use_bytearray); + assert(writer->overallocate || fmtcnt == 0 || use_bytearray); } /* until end */ if (argidx < arglen && !dict) { @@ -1064,10 +1069,10 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, if (args_owned) { Py_DECREF(args); } - return _PyBytesWriter_Finish(&writer, res); + return PyBytesWriter_FinishWithPointer(writer, res); error: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); if (args_owned) { Py_DECREF(args); } @@ -1081,22 +1086,16 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, int *first_invalid_escape_char, const char **first_invalid_escape_ptr) { - int c; - char *p; - const char *end; - _PyBytesWriter writer; - - _PyBytesWriter_Init(&writer); - - p = _PyBytesWriter_Alloc(&writer, len); - if (p == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(len); + if (writer == NULL) { return NULL; - writer.overallocate = 1; + } + char *p = PyBytesWriter_GetData(writer); *first_invalid_escape_char = -1; *first_invalid_escape_ptr = NULL; - end = s + len; + const char *end = s + len; while (s < end) { if (*s != '\\') { *p++ = *s++; @@ -1125,7 +1124,8 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, case 'a': *p++ = '\007'; break; /* BEL, not classic C */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - c = s[-1] - '0'; + { + int c = s[-1] - '0'; if (s < end && '0' <= *s && *s <= '7') { c = (c<<3) + *s++ - '0'; if (s < end && '0' <= *s && *s <= '7') @@ -1140,6 +1140,7 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, } *p++ = c; break; + } case 'x': if (s+1 < end) { int digit1, digit2; @@ -1186,10 +1187,10 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, } } - return _PyBytesWriter_Finish(&writer, p); + return PyBytesWriter_FinishWithPointer(writer, p); failed: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } @@ -1340,27 +1341,33 @@ _PyBytes_ReverseFind(const char *haystack, Py_ssize_t len_haystack, PyObject * PyBytes_Repr(PyObject *obj, int smartquotes) { - PyBytesObject* op = (PyBytesObject*) obj; - Py_ssize_t i, length = Py_SIZE(op); + return _Py_bytes_repr(PyBytes_AS_STRING(obj), PyBytes_GET_SIZE(obj), + smartquotes, "bytes"); +} + +PyObject * +_Py_bytes_repr(const char *data, Py_ssize_t length, int smartquotes, + const char *classname) +{ + Py_ssize_t i; Py_ssize_t newsize, squotes, dquotes; PyObject *v; unsigned char quote; - const unsigned char *s; Py_UCS1 *p; /* Compute size of output string */ squotes = dquotes = 0; newsize = 3; /* b'' */ - s = (const unsigned char*)op->ob_sval; for (i = 0; i < length; i++) { + unsigned char c = data[i]; Py_ssize_t incr = 1; - switch(s[i]) { + switch(c) { case '\'': squotes++; break; case '"': dquotes++; break; case '\\': case '\t': case '\n': case '\r': incr = 2; break; /* \C */ default: - if (s[i] < ' ' || s[i] >= 0x7f) + if (c < ' ' || c >= 0x7f) incr = 4; /* \xHH */ } if (newsize > PY_SSIZE_T_MAX - incr) @@ -1384,7 +1391,7 @@ PyBytes_Repr(PyObject *obj, int smartquotes) *p++ = 'b', *p++ = quote; for (i = 0; i < length; i++) { - unsigned char c = op->ob_sval[i]; + unsigned char c = data[i]; if (c == quote || c == '\\') *p++ = '\\', *p++ = c; else if (c == '\t') @@ -1407,8 +1414,8 @@ PyBytes_Repr(PyObject *obj, int smartquotes) return v; overflow: - PyErr_SetString(PyExc_OverflowError, - "bytes object is too large to make repr"); + PyErr_Format(PyExc_OverflowError, + "%s object is too large to make repr", classname); return NULL; } @@ -2526,17 +2533,13 @@ bytes_fromhex_impl(PyTypeObject *type, PyObject *string) PyObject* _PyBytes_FromHex(PyObject *string, int use_bytearray) { - char *buf; Py_ssize_t hexlen, invalid_char; unsigned int top, bot; const Py_UCS1 *str, *start, *end; - _PyBytesWriter writer; + PyBytesWriter *writer = NULL; Py_buffer view; view.obj = NULL; - _PyBytesWriter_Init(&writer); - writer.use_bytearray = use_bytearray; - if (PyUnicode_Check(string)) { hexlen = PyUnicode_GET_LENGTH(string); @@ -2572,10 +2575,16 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } /* This overestimates if there are spaces */ - buf = _PyBytesWriter_Alloc(&writer, hexlen / 2); - if (buf == NULL) { + if (use_bytearray) { + writer = _PyBytesWriter_CreateByteArray(hexlen / 2); + } + else { + writer = PyBytesWriter_Create(hexlen / 2); + } + if (writer == NULL) { goto release_buffer; } + char *buf = PyBytesWriter_GetData(writer); start = str; end = str + hexlen; @@ -2614,7 +2623,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) if (view.obj != NULL) { PyBuffer_Release(&view); } - return _PyBytesWriter_Finish(&writer, buf); + return PyBytesWriter_FinishWithPointer(writer, buf); error: if (invalid_char == -1) { @@ -2625,7 +2634,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) "non-hexadecimal number found in " "fromhex() arg at position %zd", invalid_char); } - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); release_buffer: if (view.obj != NULL) { @@ -2780,7 +2789,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, "errors without a string argument"); return NULL; } - bytes = PyBytes_FromStringAndSize(NULL, 0); + bytes = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } else if (encoding != NULL) { /* Encode via the codec registry */ @@ -2852,23 +2861,25 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, static PyObject* _PyBytes_FromBuffer(PyObject *x) { - PyObject *new; Py_buffer view; - if (PyObject_GetBuffer(x, &view, PyBUF_FULL_RO) < 0) return NULL; - new = PyBytes_FromStringAndSize(NULL, view.len); - if (!new) + PyBytesWriter *writer = PyBytesWriter_Create(view.len); + if (writer == NULL) { goto fail; - if (PyBuffer_ToContiguous(((PyBytesObject *)new)->ob_sval, - &view, view.len, 'C') < 0) + } + + if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer), + &view, view.len, 'C') < 0) { goto fail; + } + PyBuffer_Release(&view); - return new; + return PyBytesWriter_Finish(writer); fail: - Py_XDECREF(new); + PyBytesWriter_Discard(writer); PyBuffer_Release(&view); return NULL; } @@ -2876,23 +2887,18 @@ fail: static PyObject* _PyBytes_FromList(PyObject *x) { - Py_ssize_t i, size = PyList_GET_SIZE(x); - Py_ssize_t value; - char *str; - PyObject *item; - _PyBytesWriter writer; - - _PyBytesWriter_Init(&writer); - str = _PyBytesWriter_Alloc(&writer, size); - if (str == NULL) + Py_ssize_t size = PyList_GET_SIZE(x); + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - writer.overallocate = 1; - size = writer.allocated; + } + char *str = PyBytesWriter_GetData(writer); + size = _PyBytesWriter_GetAllocated(writer); - for (i = 0; i < PyList_GET_SIZE(x); i++) { - item = PyList_GET_ITEM(x, i); + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(x); i++) { + PyObject *item = PyList_GET_ITEM(x, i); Py_INCREF(item); - value = PyNumber_AsSsize_t(item, NULL); + Py_ssize_t value = PyNumber_AsSsize_t(item, NULL); Py_DECREF(item); if (value == -1 && PyErr_Occurred()) goto error; @@ -2904,33 +2910,33 @@ _PyBytes_FromList(PyObject *x) } if (i >= size) { - str = _PyBytesWriter_Resize(&writer, str, size+1); - if (str == NULL) - return NULL; - size = writer.allocated; + str = _PyBytesWriter_ResizeAndUpdatePointer(writer, size + 1, str); + if (str == NULL) { + goto error; + } + size = _PyBytesWriter_GetAllocated(writer); } *str++ = (char) value; } - return _PyBytesWriter_Finish(&writer, str); + return PyBytesWriter_FinishWithPointer(writer, str); - error: - _PyBytesWriter_Dealloc(&writer); +error: + PyBytesWriter_Discard(writer); return NULL; } static PyObject* _PyBytes_FromTuple(PyObject *x) { - PyObject *bytes; Py_ssize_t i, size = PyTuple_GET_SIZE(x); Py_ssize_t value; - char *str; PyObject *item; - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - str = ((PyBytesObject *)bytes)->ob_sval; + } + char *str = PyBytesWriter_GetData(writer); for (i = 0; i < size; i++) { item = PyTuple_GET_ITEM(x, i); @@ -2945,31 +2951,29 @@ _PyBytes_FromTuple(PyObject *x) } *str++ = (char) value; } - return bytes; + return PyBytesWriter_Finish(writer); error: - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); return NULL; } static PyObject * _PyBytes_FromIterator(PyObject *it, PyObject *x) { - char *str; Py_ssize_t i, size; - _PyBytesWriter writer; /* For iterator version, create a bytes object and resize as needed */ size = PyObject_LengthHint(x, 64); if (size == -1 && PyErr_Occurred()) return NULL; - _PyBytesWriter_Init(&writer); - str = _PyBytesWriter_Alloc(&writer, size); - if (str == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - writer.overallocate = 1; - size = writer.allocated; + } + char *str = PyBytesWriter_GetData(writer); + size = _PyBytesWriter_GetAllocated(writer); /* Run the iterator to exhaustion */ for (i = 0; ; i++) { @@ -2999,18 +3003,18 @@ _PyBytes_FromIterator(PyObject *it, PyObject *x) /* Append the byte */ if (i >= size) { - str = _PyBytesWriter_Resize(&writer, str, size+1); - if (str == NULL) - return NULL; - size = writer.allocated; + str = _PyBytesWriter_ResizeAndUpdatePointer(writer, size + 1, str); + if (str == NULL) { + goto error; + } + size = _PyBytesWriter_GetAllocated(writer); } *str++ = (char) value; } - - return _PyBytesWriter_Finish(&writer, str); + return PyBytesWriter_FinishWithPointer(writer, str); error: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } @@ -3162,7 +3166,7 @@ PyBytes_Concat(PyObject **pv, PyObject *w) return; } - if (Py_REFCNT(*pv) == 1 && PyBytes_CheckExact(*pv)) { + if (_PyObject_IsUniquelyReferenced(*pv) && PyBytes_CheckExact(*pv)) { /* Only one reference, so we can resize in place */ Py_ssize_t oldsize; Py_buffer wb; @@ -3247,7 +3251,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) Py_DECREF(v); return 0; } - if (Py_REFCNT(v) != 1) { + if (!_PyObject_IsUniquelyReferenced(v)) { if (oldsize < newsize) { *pv = _PyBytes_FromSize(newsize, 0); if (*pv) { @@ -3442,288 +3446,6 @@ bytes_iter(PyObject *seq) } -/* _PyBytesWriter API */ - -#ifdef MS_WINDOWS - /* On Windows, overallocate by 50% is the best factor */ -# define OVERALLOCATE_FACTOR 2 -#else - /* On Linux, overallocate by 25% is the best factor */ -# define OVERALLOCATE_FACTOR 4 -#endif - -void -_PyBytesWriter_Init(_PyBytesWriter *writer) -{ - /* Set all attributes before small_buffer to 0 */ - memset(writer, 0, offsetof(_PyBytesWriter, small_buffer)); -#ifndef NDEBUG - memset(writer->small_buffer, PYMEM_CLEANBYTE, - sizeof(writer->small_buffer)); -#endif -} - -void -_PyBytesWriter_Dealloc(_PyBytesWriter *writer) -{ - Py_CLEAR(writer->buffer); -} - -Py_LOCAL_INLINE(char*) -_PyBytesWriter_AsString(_PyBytesWriter *writer) -{ - if (writer->use_small_buffer) { - assert(writer->buffer == NULL); - return writer->small_buffer; - } - else if (writer->use_bytearray) { - assert(writer->buffer != NULL); - return PyByteArray_AS_STRING(writer->buffer); - } - else { - assert(writer->buffer != NULL); - return PyBytes_AS_STRING(writer->buffer); - } -} - -Py_LOCAL_INLINE(Py_ssize_t) -_PyBytesWriter_GetSize(_PyBytesWriter *writer, char *str) -{ - const char *start = _PyBytesWriter_AsString(writer); - assert(str != NULL); - assert(str >= start); - assert(str - start <= writer->allocated); - return str - start; -} - -#ifndef NDEBUG -Py_LOCAL_INLINE(int) -_PyBytesWriter_CheckConsistency(_PyBytesWriter *writer, char *str) -{ - const char *start, *end; - - if (writer->use_small_buffer) { - assert(writer->buffer == NULL); - } - else { - assert(writer->buffer != NULL); - if (writer->use_bytearray) - assert(PyByteArray_CheckExact(writer->buffer)); - else - assert(PyBytes_CheckExact(writer->buffer)); - assert(Py_REFCNT(writer->buffer) == 1); - } - - if (writer->use_bytearray) { - /* bytearray has its own overallocation algorithm, - writer overallocation must be disabled */ - assert(!writer->overallocate); - } - - assert(0 <= writer->allocated); - assert(0 <= writer->min_size && writer->min_size <= writer->allocated); - /* the last byte must always be null */ - start = _PyBytesWriter_AsString(writer); - assert(start[writer->allocated] == 0); - - end = start + writer->allocated; - assert(str != NULL); - assert(start <= str && str <= end); - return 1; -} -#endif - -void* -_PyBytesWriter_Resize(_PyBytesWriter *writer, void *str, Py_ssize_t size) -{ - Py_ssize_t allocated, pos; - - assert(_PyBytesWriter_CheckConsistency(writer, str)); - assert(writer->allocated < size); - - allocated = size; - if (writer->overallocate - && allocated <= (PY_SSIZE_T_MAX - allocated / OVERALLOCATE_FACTOR)) { - /* overallocate to limit the number of realloc() */ - allocated += allocated / OVERALLOCATE_FACTOR; - } - - pos = _PyBytesWriter_GetSize(writer, str); - if (!writer->use_small_buffer) { - if (writer->use_bytearray) { - if (PyByteArray_Resize(writer->buffer, allocated)) - goto error; - /* writer->allocated can be smaller than writer->buffer->ob_alloc, - but we cannot use ob_alloc because bytes may need to be moved - to use the whole buffer. bytearray uses an internal optimization - to avoid moving or copying bytes when bytes are removed at the - beginning (ex: del bytearray[:1]). */ - } - else { - if (_PyBytes_Resize(&writer->buffer, allocated)) - goto error; - } - } - else { - /* convert from stack buffer to bytes object buffer */ - assert(writer->buffer == NULL); - - if (writer->use_bytearray) - writer->buffer = PyByteArray_FromStringAndSize(NULL, allocated); - else - writer->buffer = PyBytes_FromStringAndSize(NULL, allocated); - if (writer->buffer == NULL) - goto error; - - if (pos != 0) { - char *dest; - if (writer->use_bytearray) - dest = PyByteArray_AS_STRING(writer->buffer); - else - dest = PyBytes_AS_STRING(writer->buffer); - memcpy(dest, - writer->small_buffer, - pos); - } - - writer->use_small_buffer = 0; -#ifndef NDEBUG - memset(writer->small_buffer, PYMEM_CLEANBYTE, - sizeof(writer->small_buffer)); -#endif - } - writer->allocated = allocated; - - str = _PyBytesWriter_AsString(writer) + pos; - assert(_PyBytesWriter_CheckConsistency(writer, str)); - return str; - -error: - _PyBytesWriter_Dealloc(writer); - return NULL; -} - -void* -_PyBytesWriter_Prepare(_PyBytesWriter *writer, void *str, Py_ssize_t size) -{ - Py_ssize_t new_min_size; - - assert(_PyBytesWriter_CheckConsistency(writer, str)); - assert(size >= 0); - - if (size == 0) { - /* nothing to do */ - return str; - } - - if (writer->min_size > PY_SSIZE_T_MAX - size) { - PyErr_NoMemory(); - _PyBytesWriter_Dealloc(writer); - return NULL; - } - new_min_size = writer->min_size + size; - - if (new_min_size > writer->allocated) - str = _PyBytesWriter_Resize(writer, str, new_min_size); - - writer->min_size = new_min_size; - return str; -} - -/* Allocate the buffer to write size bytes. - Return the pointer to the beginning of buffer data. - Raise an exception and return NULL on error. */ -void* -_PyBytesWriter_Alloc(_PyBytesWriter *writer, Py_ssize_t size) -{ - /* ensure that _PyBytesWriter_Alloc() is only called once */ - assert(writer->min_size == 0 && writer->buffer == NULL); - assert(size >= 0); - - writer->use_small_buffer = 1; -#ifndef NDEBUG - writer->allocated = sizeof(writer->small_buffer) - 1; - /* In debug mode, don't use the full small buffer because it is less - efficient than bytes and bytearray objects to detect buffer underflow - and buffer overflow. Use 10 bytes of the small buffer to test also - code using the smaller buffer in debug mode. - - Don't modify the _PyBytesWriter structure (use a shorter small buffer) - in debug mode to also be able to detect stack overflow when running - tests in debug mode. The _PyBytesWriter is large (more than 512 bytes), - if _Py_EnterRecursiveCall() is not used in deep C callback, we may hit a - stack overflow. */ - writer->allocated = Py_MIN(writer->allocated, 10); - /* _PyBytesWriter_CheckConsistency() requires the last byte to be 0, - to detect buffer overflow */ - writer->small_buffer[writer->allocated] = 0; -#else - writer->allocated = sizeof(writer->small_buffer); -#endif - return _PyBytesWriter_Prepare(writer, writer->small_buffer, size); -} - -PyObject * -_PyBytesWriter_Finish(_PyBytesWriter *writer, void *str) -{ - Py_ssize_t size; - PyObject *result; - - assert(_PyBytesWriter_CheckConsistency(writer, str)); - - size = _PyBytesWriter_GetSize(writer, str); - if (size == 0 && !writer->use_bytearray) { - Py_CLEAR(writer->buffer); - /* Get the empty byte string singleton */ - result = PyBytes_FromStringAndSize(NULL, 0); - } - else if (writer->use_small_buffer) { - if (writer->use_bytearray) { - result = PyByteArray_FromStringAndSize(writer->small_buffer, size); - } - else { - result = PyBytes_FromStringAndSize(writer->small_buffer, size); - } - } - else { - result = writer->buffer; - writer->buffer = NULL; - - if (size != writer->allocated) { - if (writer->use_bytearray) { - if (PyByteArray_Resize(result, size)) { - Py_DECREF(result); - return NULL; - } - } - else { - if (_PyBytes_Resize(&result, size)) { - assert(result == NULL); - return NULL; - } - } - } - } - return result; -} - -void* -_PyBytesWriter_WriteBytes(_PyBytesWriter *writer, void *ptr, - const void *bytes, Py_ssize_t size) -{ - char *str = (char *)ptr; - - str = _PyBytesWriter_Prepare(writer, str, size); - if (str == NULL) - return NULL; - - memcpy(str, bytes, size); - str += size; - - return str; -} - - void _PyBytes_Repeat(char* dest, Py_ssize_t len_dest, const char* src, Py_ssize_t len_src) @@ -3747,3 +3469,341 @@ _PyBytes_Repeat(char* dest, Py_ssize_t len_dest, } } + +// --- PyBytesWriter API ----------------------------------------------------- + +static inline char* +byteswriter_data(PyBytesWriter *writer) +{ + return _PyBytesWriter_GetData(writer); +} + + +static inline Py_ssize_t +byteswriter_allocated(PyBytesWriter *writer) +{ + if (writer->obj == NULL) { + return sizeof(writer->small_buffer); + } + else if (writer->use_bytearray) { + return PyByteArray_GET_SIZE(writer->obj); + } + else { + return PyBytes_GET_SIZE(writer->obj); + } +} + + +#ifdef MS_WINDOWS + /* On Windows, overallocate by 50% is the best factor */ +# define OVERALLOCATE_FACTOR 2 +#else + /* On Linux, overallocate by 25% is the best factor */ +# define OVERALLOCATE_FACTOR 4 +#endif + +static inline int +byteswriter_resize(PyBytesWriter *writer, Py_ssize_t size, int resize) +{ + assert(size >= 0); + + Py_ssize_t old_allocated = byteswriter_allocated(writer); + if (size <= old_allocated) { + return 0; + } + + if (resize & writer->overallocate) { + if (size <= (PY_SSIZE_T_MAX - size / OVERALLOCATE_FACTOR)) { + size += size / OVERALLOCATE_FACTOR; + } + } + + if (writer->obj != NULL) { + if (writer->use_bytearray) { + if (PyByteArray_Resize(writer->obj, size)) { + return -1; + } + } + else { + if (_PyBytes_Resize(&writer->obj, size)) { + return -1; + } + } + assert(writer->obj != NULL); + } + else if (writer->use_bytearray) { + writer->obj = PyByteArray_FromStringAndSize(NULL, size); + if (writer->obj == NULL) { + return -1; + } + if (resize) { + assert((size_t)size > sizeof(writer->small_buffer)); + memcpy(PyByteArray_AS_STRING(writer->obj), + writer->small_buffer, + sizeof(writer->small_buffer)); + } + } + else { + writer->obj = PyBytes_FromStringAndSize(NULL, size); + if (writer->obj == NULL) { + return -1; + } + if (resize) { + assert((size_t)size > sizeof(writer->small_buffer)); + memcpy(PyBytes_AS_STRING(writer->obj), + writer->small_buffer, + sizeof(writer->small_buffer)); + } + } + +#ifdef Py_DEBUG + Py_ssize_t allocated = byteswriter_allocated(writer); + if (resize && allocated > old_allocated) { + memset(byteswriter_data(writer) + old_allocated, 0xff, + allocated - old_allocated); + } +#endif + + return 0; +} + + +static PyBytesWriter* +byteswriter_create(Py_ssize_t size, int use_bytearray) +{ + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "size must be >= 0"); + return NULL; + } + + PyBytesWriter *writer = _Py_FREELIST_POP_MEM(bytes_writers); + if (writer == NULL) { + writer = (PyBytesWriter *)PyMem_Malloc(sizeof(PyBytesWriter)); + if (writer == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + writer->obj = NULL; + writer->size = 0; + writer->use_bytearray = use_bytearray; + writer->overallocate = !use_bytearray; + + if (size >= 1) { + if (byteswriter_resize(writer, size, 0) < 0) { + PyBytesWriter_Discard(writer); + return NULL; + } + writer->size = size; + } +#ifdef Py_DEBUG + memset(byteswriter_data(writer), 0xff, byteswriter_allocated(writer)); +#endif + return writer; +} + +PyBytesWriter* +PyBytesWriter_Create(Py_ssize_t size) +{ + return byteswriter_create(size, 0); +} + +PyBytesWriter* +_PyBytesWriter_CreateByteArray(Py_ssize_t size) +{ + return byteswriter_create(size, 1); +} + + +void +PyBytesWriter_Discard(PyBytesWriter *writer) +{ + if (writer == NULL) { + return; + } + + Py_XDECREF(writer->obj); + _Py_FREELIST_FREE(bytes_writers, writer, PyMem_Free); +} + + +PyObject* +PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size) +{ + PyObject *result; + if (size == 0) { + result = bytes_get_empty(); + } + else if (writer->obj != NULL) { + if (writer->use_bytearray) { + if (size != PyByteArray_GET_SIZE(writer->obj)) { + if (PyByteArray_Resize(writer->obj, size)) { + goto error; + } + } + } + else { + if (size != PyBytes_GET_SIZE(writer->obj)) { + if (_PyBytes_Resize(&writer->obj, size)) { + goto error; + } + } + } + result = writer->obj; + writer->obj = NULL; + } + else if (writer->use_bytearray) { + result = PyByteArray_FromStringAndSize(writer->small_buffer, size); + } + else { + result = PyBytes_FromStringAndSize(writer->small_buffer, size); + } + PyBytesWriter_Discard(writer); + return result; + +error: + PyBytesWriter_Discard(writer); + return NULL; +} + +PyObject* +PyBytesWriter_Finish(PyBytesWriter *writer) +{ + return PyBytesWriter_FinishWithSize(writer, writer->size); +} + + +PyObject* +PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf) +{ + Py_ssize_t size = (char*)buf - byteswriter_data(writer); + if (size < 0 || size > byteswriter_allocated(writer)) { + PyBytesWriter_Discard(writer); + PyErr_SetString(PyExc_ValueError, "invalid end pointer"); + return NULL; + } + + return PyBytesWriter_FinishWithSize(writer, size); +} + + +void* +PyBytesWriter_GetData(PyBytesWriter *writer) +{ + return byteswriter_data(writer); +} + + +Py_ssize_t +PyBytesWriter_GetSize(PyBytesWriter *writer) +{ + return _PyBytesWriter_GetSize(writer); +} + + +static Py_ssize_t +_PyBytesWriter_GetAllocated(PyBytesWriter *writer) +{ + return byteswriter_allocated(writer); +} + + +int +PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) +{ + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "size must be >= 0"); + return -1; + } + if (byteswriter_resize(writer, size, 1) < 0) { + return -1; + } + writer->size = size; + return 0; +} + + +static void* +_PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, + void *data) +{ + Py_ssize_t pos = (char*)data - byteswriter_data(writer); + if (PyBytesWriter_Resize(writer, size) < 0) { + return NULL; + } + return byteswriter_data(writer) + pos; +} + + +int +PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t size) +{ + if (size < 0 && writer->size + size < 0) { + PyErr_SetString(PyExc_ValueError, "invalid size"); + return -1; + } + if (size > PY_SSIZE_T_MAX - writer->size) { + PyErr_NoMemory(); + return -1; + } + size = writer->size + size; + + if (byteswriter_resize(writer, size, 1) < 0) { + return -1; + } + writer->size = size; + return 0; +} + + +void* +PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, + void *buf) +{ + Py_ssize_t pos = (char*)buf - byteswriter_data(writer); + if (PyBytesWriter_Grow(writer, size) < 0) { + return NULL; + } + return byteswriter_data(writer) + pos; +} + + +int +PyBytesWriter_WriteBytes(PyBytesWriter *writer, + const void *bytes, Py_ssize_t size) +{ + if (size < 0) { + size_t len = strlen(bytes); + if (len > (size_t)PY_SSIZE_T_MAX) { + PyErr_NoMemory(); + return -1; + } + size = (Py_ssize_t)len; + } + + Py_ssize_t pos = writer->size; + if (PyBytesWriter_Grow(writer, size) < 0) { + return -1; + } + char *buf = byteswriter_data(writer); + memcpy(buf + pos, bytes, size); + return 0; +} + + +int +PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) +{ + Py_ssize_t pos = writer->size; + if (PyBytesWriter_Grow(writer, strlen(format)) < 0) { + return -1; + } + + va_list vargs; + va_start(vargs, format); + char *buf = bytes_fromformat(writer, pos, format, vargs); + va_end(vargs); + + Py_ssize_t size = buf - byteswriter_data(writer); + return PyBytesWriter_Resize(writer, size); +} diff --git a/Objects/call.c b/Objects/call.c index c9a18bcc3da..af42fc8f7f2 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -213,7 +213,7 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, return NULL; } - PyObject *argstuple = _PyTuple_FromArray(args, nargs); + PyObject *argstuple = PyTuple_FromArray(args, nargs); if (argstuple == NULL) { return NULL; } @@ -708,7 +708,10 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, return null_error(tstate); } +_Py_COMP_DIAG_PUSH +_Py_COMP_DIAG_IGNORE_DEPR_DECLS PyObject *callable = _PyObject_GetAttrId(obj, name); +_Py_COMP_DIAG_POP if (callable == NULL) { return NULL; } @@ -726,6 +729,7 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, PyObject * _PyObject_CallMethodFormat(PyThreadState *tstate, PyObject *callable, const char *format, ...) { + assert(callable != NULL); va_list va; va_start(va, format); PyObject *retval = callmethod(tstate, callable, format, va); @@ -891,39 +895,6 @@ PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...) } -PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *obj, _Py_Identifier *name, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - return NULL; - } - _PyCStackRef method; - _PyThreadState_PushCStackRef(tstate, &method); - int is_method = _PyObject_GetMethodStackRef(tstate, obj, oname, &method.ref); - if (PyStackRef_IsNull(method.ref)) { - _PyThreadState_PopCStackRef(tstate, &method); - return NULL; - } - PyObject *callable = PyStackRef_AsPyObjectBorrow(method.ref); - - obj = is_method ? obj : NULL; - - va_list vargs; - va_start(vargs, name); - PyObject *result = object_vacall(tstate, obj, callable, vargs); - va_end(vargs); - - _PyThreadState_PopCStackRef(tstate, &method); - return result; -} - - PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h index ffb45ade11f..be704ccf68f 100644 --- a/Objects/clinic/bytearrayobject.c.h +++ b/Objects/clinic/bytearrayobject.c.h @@ -599,7 +599,7 @@ PyDoc_STRVAR(bytearray_resize__doc__, "Resize the internal buffer of bytearray to len.\n" "\n" " size\n" -" New size to resize to.."); +" New size to resize to."); #define BYTEARRAY_RESIZE_METHODDEF \ {"resize", (PyCFunction)bytearray_resize, METH_O, bytearray_resize__doc__}, @@ -631,6 +631,43 @@ exit: return return_value; } +PyDoc_STRVAR(bytearray_take_bytes__doc__, +"take_bytes($self, n=None, /)\n" +"--\n" +"\n" +"Take *n* bytes from the bytearray and return them as a bytes object.\n" +"\n" +" n\n" +" Bytes to take, negative indexes from end. None indicates all bytes."); + +#define BYTEARRAY_TAKE_BYTES_METHODDEF \ + {"take_bytes", _PyCFunction_CAST(bytearray_take_bytes), METH_FASTCALL, bytearray_take_bytes__doc__}, + +static PyObject * +bytearray_take_bytes_impl(PyByteArrayObject *self, PyObject *n); + +static PyObject * +bytearray_take_bytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *n = Py_None; + + if (!_PyArg_CheckPositional("take_bytes", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + n = args[0]; +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = bytearray_take_bytes_impl((PyByteArrayObject *)self, n); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + PyDoc_STRVAR(bytearray_translate__doc__, "translate($self, table, /, delete=b\'\')\n" "--\n" @@ -1796,4 +1833,4 @@ bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return bytearray_sizeof_impl((PyByteArrayObject *)self); } -/*[clinic end generated code: output=be6d28193bc96a2c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5eddefde2a001ceb input=a9049054013a1b77]*/ diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h index a236a32c091..c88772030ec 100644 --- a/Objects/clinic/longobject.c.h +++ b/Objects/clinic/longobject.c.h @@ -340,6 +340,11 @@ int_to_bytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject * goto exit; } length = ival; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length cannot be negative"); + goto exit; + } } if (!--noptargs) { goto skip_optional_pos; @@ -485,4 +490,4 @@ int_is_integer(PyObject *self, PyObject *Py_UNUSED(ignored)) { return int_is_integer_impl(self); } -/*[clinic end generated code: output=d23f8ce5bdf08a30 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e68f4e23ead3f649 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h index e71c29a1b26..894e9be91bb 100644 --- a/Objects/clinic/odictobject.c.h +++ b/Objects/clinic/odictobject.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(OrderedDict_fromkeys__doc__, @@ -73,6 +74,53 @@ exit: return return_value; } +PyDoc_STRVAR(OrderedDict___sizeof____doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n"); + +#define ORDEREDDICT___SIZEOF___METHODDEF \ + {"__sizeof__", (PyCFunction)OrderedDict___sizeof__, METH_NOARGS, OrderedDict___sizeof____doc__}, + +static Py_ssize_t +OrderedDict___sizeof___impl(PyODictObject *self); + +static PyObject * +OrderedDict___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + Py_ssize_t _return_value; + + Py_BEGIN_CRITICAL_SECTION(self); + _return_value = OrderedDict___sizeof___impl((PyODictObject *)self); + Py_END_CRITICAL_SECTION(); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromSsize_t(_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(OrderedDict___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n" +"Return state information for pickling"); + +#define ORDEREDDICT___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)OrderedDict___reduce__, METH_NOARGS, OrderedDict___reduce____doc__}, + +static PyObject * +OrderedDict___reduce___impl(PyODictObject *od); + +static PyObject * +OrderedDict___reduce__(PyObject *od, PyObject *Py_UNUSED(ignored)) +{ + return OrderedDict___reduce___impl((PyODictObject *)od); +} + PyDoc_STRVAR(OrderedDict_setdefault__doc__, "setdefault($self, /, key, default=None)\n" "--\n" @@ -135,7 +183,9 @@ OrderedDict_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } default_value = args[1]; skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = OrderedDict_setdefault_impl((PyODictObject *)self, key, default_value); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -204,7 +254,9 @@ OrderedDict_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObjec } default_value = args[1]; skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = OrderedDict_pop_impl((PyODictObject *)self, key, default_value); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -272,12 +324,62 @@ OrderedDict_popitem(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyO goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = OrderedDict_popitem_impl((PyODictObject *)self, last); + Py_END_CRITICAL_SECTION(); exit: return return_value; } +PyDoc_STRVAR(OrderedDict_clear__doc__, +"clear($self, /)\n" +"--\n" +"\n" +"Remove all items from ordered dict."); + +#define ORDEREDDICT_CLEAR_METHODDEF \ + {"clear", (PyCFunction)OrderedDict_clear, METH_NOARGS, OrderedDict_clear__doc__}, + +static PyObject * +OrderedDict_clear_impl(PyODictObject *self); + +static PyObject * +OrderedDict_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = OrderedDict_clear_impl((PyODictObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(OrderedDict_copy__doc__, +"copy($self, /)\n" +"--\n" +"\n" +"A shallow copy of ordered dict."); + +#define ORDEREDDICT_COPY_METHODDEF \ + {"copy", (PyCFunction)OrderedDict_copy, METH_NOARGS, OrderedDict_copy__doc__}, + +static PyObject * +OrderedDict_copy_impl(PyObject *od); + +static PyObject * +OrderedDict_copy(PyObject *od, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(od); + return_value = OrderedDict_copy_impl(od); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(OrderedDict_move_to_end__doc__, "move_to_end($self, /, key, last=True)\n" "--\n" @@ -342,9 +444,11 @@ OrderedDict_move_to_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs, goto exit; } skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = OrderedDict_move_to_end_impl((PyODictObject *)self, key, last); + Py_END_CRITICAL_SECTION(); exit: return return_value; } -/*[clinic end generated code: output=7d8206823bb1f419 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7bc997ca7900f06f input=a9049054013a1b77]*/ diff --git a/Objects/clinic/setobject.c.h b/Objects/clinic/setobject.c.h index 488be4435f8..098c4bcb53d 100644 --- a/Objects/clinic/setobject.c.h +++ b/Objects/clinic/setobject.c.h @@ -425,9 +425,7 @@ set___contains__(PyObject *so, PyObject *key) { PyObject *return_value = NULL; - Py_BEGIN_CRITICAL_SECTION(so); return_value = set___contains___impl((PySetObject *)so, key); - Py_END_CRITICAL_SECTION(); return return_value; } @@ -554,4 +552,4 @@ set___sizeof__(PyObject *so, PyObject *Py_UNUSED(ignored)) return return_value; } -/*[clinic end generated code: output=7f7fe845ca165078 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5800c0bf136a5a0a input=a9049054013a1b77]*/ diff --git a/Objects/clinic/typevarobject.c.h b/Objects/clinic/typevarobject.c.h index 9ae2f51f758..bd4c7a0e64f 100644 --- a/Objects/clinic/typevarobject.c.h +++ b/Objects/clinic/typevarobject.c.h @@ -688,14 +688,14 @@ typealias_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(typealias_new__doc__, -"typealias(name, value, *, type_params=<unrepresentable>)\n" +"typealias(name, value, *, type_params=<unrepresentable>, qualname=None)\n" "--\n" "\n" "Create a TypeAliasType."); static PyObject * typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, - PyObject *type_params); + PyObject *type_params, PyObject *qualname); static PyObject * typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) @@ -703,7 +703,7 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 3 + #define NUM_KEYWORDS 4 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -712,7 +712,7 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), }, + .ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), &_Py_ID(qualname), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -721,20 +721,21 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"name", "value", "type_params", NULL}; + static const char * const _keywords[] = {"name", "value", "type_params", "qualname", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "typealias", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[4]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; PyObject *name; PyObject *value; PyObject *type_params = NULL; + PyObject *qualname = NULL; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); @@ -750,11 +751,17 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) if (!noptargs) { goto skip_optional_kwonly; } - type_params = fastargs[2]; + if (fastargs[2]) { + type_params = fastargs[2]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + qualname = fastargs[3]; skip_optional_kwonly: - return_value = typealias_new_impl(type, name, value, type_params); + return_value = typealias_new_impl(type, name, value, type_params, qualname); exit: return return_value; } -/*[clinic end generated code: output=9dad71445e079303 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=67ab9a5d1869f2c9 input=a9049054013a1b77]*/ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 55ba6ae372b..3aea2038fd1 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1005,8 +1005,8 @@ failed: * source location tracking (co_lines/co_positions) ******************/ -int -PyCode_Addr2Line(PyCodeObject *co, int addrq) +static int +_PyCode_Addr2Line(PyCodeObject *co, int addrq) { if (addrq < 0) { return co->co_firstlineno; @@ -1020,6 +1020,33 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq) return _PyCode_CheckLineNumber(addrq, &bounds); } +int +_PyCode_SafeAddr2Line(PyCodeObject *co, int addrq) +{ + if (addrq < 0) { + return co->co_firstlineno; + } + if (co->_co_monitoring && co->_co_monitoring->lines) { + return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT)); + } + if (!(addrq >= 0 && addrq < _PyCode_NBYTES(co))) { + return -1; + } + PyCodeAddressRange bounds; + _PyCode_InitAddressRange(co, &bounds); + return _PyCode_CheckLineNumber(addrq, &bounds); +} + +int +PyCode_Addr2Line(PyCodeObject *co, int addrq) +{ + int lineno; + Py_BEGIN_CRITICAL_SECTION(co); + lineno = _PyCode_Addr2Line(co, addrq); + Py_END_CRITICAL_SECTION(); + return lineno; +} + void _PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range) { @@ -2405,6 +2432,7 @@ code_dealloc(PyObject *self) PyMem_Free(co_extra); } #ifdef _Py_TIER2 + _PyJit_Tracer_InvalidateDependency(tstate, self); if (co->co_executors != NULL) { clear_executors(co); } diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 03fc137c345..3612c2699a5 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -139,8 +139,8 @@ _Py_c_prod(Py_complex z, Py_complex w) recalc = 1; } if (recalc) { - r.real = Py_INFINITY*(a*c - b*d); - r.imag = Py_INFINITY*(a*d + b*c); + r.real = INFINITY*(a*c - b*d); + r.imag = INFINITY*(a*d + b*c); } } @@ -229,8 +229,8 @@ _Py_c_quot(Py_complex a, Py_complex b) { const double x = copysign(isinf(a.real) ? 1.0 : 0.0, a.real); const double y = copysign(isinf(a.imag) ? 1.0 : 0.0, a.imag); - r.real = Py_INFINITY * (x*b.real + y*b.imag); - r.imag = Py_INFINITY * (y*b.real - x*b.imag); + r.real = INFINITY * (x*b.real + y*b.imag); + r.imag = INFINITY * (y*b.real - x*b.imag); } else if ((isinf(abs_breal) || isinf(abs_bimag)) && isfinite(a.real) && isfinite(a.imag)) @@ -644,7 +644,7 @@ complex_hash(PyObject *op) * compare equal must have the same hash value, so that * hash(x + 0*j) must equal hash(x). */ - combined = hashreal + _PyHASH_IMAG * hashimag; + combined = hashreal + PyHASH_IMAG * hashimag; if (combined == (Py_uhash_t)-1) combined = (Py_uhash_t)-2; return (Py_hash_t)combined; diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 06a81a4fdbd..5ac4fbd8129 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -313,7 +313,7 @@ method_vectorcall_VARARGS( if (method_check_args(func, args, nargs, kwnames)) { return NULL; } - PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1); + PyObject *argstuple = PyTuple_FromArray(args+1, nargs-1); if (argstuple == NULL) { return NULL; } @@ -338,7 +338,7 @@ method_vectorcall_VARARGS_KEYWORDS( if (method_check_args(func, args, nargs, NULL)) { return NULL; } - PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1); + PyObject *argstuple = PyTuple_FromArray(args+1, nargs-1); if (argstuple == NULL) { return NULL; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 24188ffe713..49a42a35acb 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -400,8 +400,7 @@ static int _PyObject_InlineValuesConsistencyCheck(PyObject *obj); static inline Py_hash_t unicode_get_hash(PyObject *o) { - assert(PyUnicode_CheckExact(o)); - return FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyASCIIObject_CAST(o)->hash); + return PyUnstable_Unicode_GET_CACHED_HASH(o); } /* Print summary info about the state of the optimized allocator */ @@ -1079,7 +1078,7 @@ compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk, void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash) { PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix]; - PyObject *ep_key = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key); + PyObject *ep_key = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_key); assert(ep_key != NULL); assert(PyUnicode_CheckExact(ep_key)); if (ep_key == key || @@ -1372,7 +1371,7 @@ compare_unicode_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk, void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash) { PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix]; - PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key); + PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key); assert(startkey == NULL || PyUnicode_CheckExact(ep->me_key)); assert(!PyUnicode_CheckExact(key)); @@ -1415,7 +1414,7 @@ compare_unicode_unicode_threadsafe(PyDictObject *mp, PyDictKeysObject *dk, void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash) { PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix]; - PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key); + PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key); if (startkey == key) { assert(PyUnicode_CheckExact(startkey)); return 1; @@ -1451,7 +1450,7 @@ compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk, void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash) { PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix]; - PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key); + PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key); if (startkey == key) { return 1; } @@ -1600,7 +1599,7 @@ lookup_threadsafe_unicode(PyDictKeysObject *dk, PyObject *key, Py_hash_t hash, _ return DKIX_EMPTY; } if (_PyObject_HasDeferredRefcount(value)) { - *value_addr = (_PyStackRef){ .bits = (uintptr_t)value | Py_TAG_DEFERRED }; + *value_addr = (_PyStackRef){ .bits = (uintptr_t)value | Py_TAG_REFCNT }; return ix; } if (_Py_TryIncrefCompare(addr_of_value, value)) { @@ -1775,6 +1774,14 @@ static inline int insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp, Py_hash_t hash, PyObject *key, PyObject *value) { + // gh-140551: If dict was cleared in _Py_dict_lookup, + // we have to resize one more time to force general key kind. + if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) { + if (insertion_resize(mp, 0) < 0) + return -1; + assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL); + } + if (mp->ma_keys->dk_usable <= 0) { /* Need to resize. */ if (insertion_resize(mp, 1) < 0) { @@ -1871,38 +1878,31 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) { PyObject *old_value; + Py_ssize_t ix; ASSERT_DICT_LOCKED(mp); - if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) { - if (insertion_resize(mp, 0) < 0) - goto Fail; - assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL); - } - - if (_PyDict_HasSplitTable(mp)) { - Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash); + if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) { + ix = insert_split_key(mp->ma_keys, key, hash); if (ix != DKIX_EMPTY) { insert_split_value(interp, mp, key, value, ix); Py_DECREF(key); Py_DECREF(value); return 0; } - - /* No space in shared keys. Resize and continue below. */ - if (insertion_resize(mp, 1) < 0) { + // No space in shared keys. Go to insert_combined_dict() below. + } + else { + ix = _Py_dict_lookup(mp, key, hash, &old_value); + if (ix == DKIX_ERROR) goto Fail; - } } - Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value); - if (ix == DKIX_ERROR) - goto Fail; - if (ix == DKIX_EMPTY) { - assert(!_PyDict_HasSplitTable(mp)); - /* Insert into new slot. */ - assert(old_value == NULL); + // insert_combined_dict() will convert from non DICT_KEYS_GENERAL table + // into DICT_KEYS_GENERAL table if key is not Unicode. + // We don't convert it before _Py_dict_lookup because non-Unicode key + // may change generic table into Unicode table. if (insert_combined_dict(interp, mp, hash, key, value) < 0) { goto Fail; } @@ -1914,10 +1914,14 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, if (old_value != value) { _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value); assert(old_value != NULL); - assert(!_PyDict_HasSplitTable(mp)); if (DK_IS_UNICODE(mp->ma_keys)) { - PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix]; - STORE_VALUE(ep, value); + if (_PyDict_HasSplitTable(mp)) { + STORE_SPLIT_VALUE(mp, ix, value); + } + else { + PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix]; + STORE_VALUE(ep, value); + } } else { PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix]; @@ -2527,18 +2531,6 @@ _PyDict_GetItemWithError(PyObject *dp, PyObject *kv) return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference } -PyObject * -_PyDict_GetItemIdWithError(PyObject *dp, _Py_Identifier *key) -{ - PyObject *kv; - kv = _PyUnicode_FromId(key); /* borrowed */ - if (kv == NULL) - return NULL; - Py_hash_t hash = unicode_get_hash(kv); - assert (hash != -1); /* interned strings have their hash value initialised */ - return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference -} - PyObject * _PyDict_GetItemStringWithError(PyObject *v, const char *key) { @@ -2819,8 +2811,8 @@ PyDict_DelItem(PyObject *op, PyObject *key) return _PyDict_DelItem_KnownHash(op, key, hash); } -static int -delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash) +int +_PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash) { Py_ssize_t ix; PyDictObject *mp; @@ -2855,7 +2847,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) { int res; Py_BEGIN_CRITICAL_SECTION(op); - res = delitem_knownhash_lock_held(op, key, hash); + res = _PyDict_DelItem_KnownHash_LockHeld(op, key, hash); Py_END_CRITICAL_SECTION(); return res; } @@ -4374,6 +4366,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu PyDictObject *mp = (PyDictObject *)d; PyObject *value; Py_hash_t hash; + Py_ssize_t ix; PyInterpreterState *interp = _PyInterpreterState_GET(); ASSERT_DICT_LOCKED(d); @@ -4409,17 +4402,8 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu return 0; } - if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) { - if (insertion_resize(mp, 0) < 0) { - if (result) { - *result = NULL; - } - return -1; - } - } - - if (_PyDict_HasSplitTable(mp)) { - Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash); + if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) { + ix = insert_split_key(mp->ma_keys, key, hash); if (ix != DKIX_EMPTY) { PyObject *value = mp->ma_values->values[ix]; int already_present = value != NULL; @@ -4432,27 +4416,22 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu } return already_present; } - - /* No space in shared keys. Resize and continue below. */ - if (insertion_resize(mp, 1) < 0) { - goto error; - } + // No space in shared keys. Go to insert_combined_dict() below. } - - assert(!_PyDict_HasSplitTable(mp)); - - Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value); - if (ix == DKIX_ERROR) { - if (result) { - *result = NULL; + else { + ix = _Py_dict_lookup(mp, key, hash, &value); + if (ix == DKIX_ERROR) { + if (result) { + *result = NULL; + } + return -1; } - return -1; } if (ix == DKIX_EMPTY) { - assert(!_PyDict_HasSplitTable(mp)); value = default_value; + // See comment to this function in insertdict. if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) { Py_DECREF(key); Py_DECREF(value); @@ -4477,12 +4456,6 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu *result = incref_result ? Py_NewRef(value) : value; } return 1; - -error: - if (result) { - *result = NULL; - } - return -1; } int @@ -4703,9 +4676,11 @@ dict_tp_clear(PyObject *op) static PyObject *dictiter_new(PyDictObject *, PyTypeObject *); -static Py_ssize_t -sizeof_lock_held(PyDictObject *mp) +Py_ssize_t +_PyDict_SizeOf_LockHeld(PyDictObject *mp) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp); + size_t res = _PyObject_SIZE(Py_TYPE(mp)); if (_PyDict_HasSplitTable(mp)) { res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*); @@ -4724,7 +4699,7 @@ _PyDict_SizeOf(PyDictObject *mp) { Py_ssize_t res; Py_BEGIN_CRITICAL_SECTION(mp); - res = sizeof_lock_held(mp); + res = _PyDict_SizeOf_LockHeld(mp); Py_END_CRITICAL_SECTION(); return res; @@ -4862,16 +4837,6 @@ _PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) return 0; } -int -_PyDict_ContainsId(PyObject *op, _Py_Identifier *key) -{ - PyObject *kv = _PyUnicode_FromId(key); /* borrowed */ - if (kv == NULL) { - return -1; - } - return PyDict_Contains(op, kv); -} - /* Hack to implement "key in dict" */ static PySequenceMethods dict_as_sequence = { 0, /* sq_length */ @@ -5052,16 +5017,6 @@ PyDict_GetItemStringRef(PyObject *v, const char *key, PyObject **result) return res; } -int -_PyDict_SetItemId(PyObject *v, _Py_Identifier *key, PyObject *item) -{ - PyObject *kv; - kv = _PyUnicode_FromId(key); /* borrowed */ - if (kv == NULL) - return -1; - return PyDict_SetItem(v, kv, item); -} - int PyDict_SetItemString(PyObject *v, const char *key, PyObject *item) { @@ -5077,15 +5032,6 @@ PyDict_SetItemString(PyObject *v, const char *key, PyObject *item) return err; } -int -_PyDict_DelItemId(PyObject *v, _Py_Identifier *key) -{ - PyObject *kv = _PyUnicode_FromId(key); /* borrowed */ - if (kv == NULL) - return -1; - return PyDict_DelItem(v, kv); -} - int PyDict_DelItemString(PyObject *v, const char *key) { @@ -5580,7 +5526,7 @@ dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self, k = _Py_atomic_load_ptr_acquire(&d->ma_keys); assert(i >= 0); if (_PyDict_HasSplitTable(d)) { - PyDictValues *values = _Py_atomic_load_ptr_relaxed(&d->ma_values); + PyDictValues *values = _Py_atomic_load_ptr_consume(&d->ma_values); if (values == NULL) { goto concurrent_modification; } @@ -5665,22 +5611,10 @@ try_locked: #endif -static bool -has_unique_reference(PyObject *op) -{ -#ifdef Py_GIL_DISABLED - return (_Py_IsOwnedByCurrentThread(op) && - op->ob_ref_local == 1 && - _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0); -#else - return Py_REFCNT(op) == 1; -#endif -} - static bool acquire_iter_result(PyObject *result) { - if (has_unique_reference(result)) { + if (_PyObject_IsUniquelyReferenced(result)) { Py_INCREF(result); return true; } @@ -5717,8 +5651,11 @@ dictiter_iternextitem(PyObject *self) } else { result = PyTuple_New(2); - if (result == NULL) + if (result == NULL) { + Py_DECREF(key); + Py_DECREF(value); return NULL; + } PyTuple_SET_ITEM(result, 0, key); PyTuple_SET_ITEM(result, 1, value); } @@ -5826,7 +5763,7 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject *self) } else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) { result = di->di_result; - if (Py_REFCNT(result) == 1) { + if (_PyObject_IsUniquelyReferenced(result)) { PyObject *oldkey = PyTuple_GET_ITEM(result, 0); PyObject *oldvalue = PyTuple_GET_ITEM(result, 1); PyTuple_SET_ITEM(result, 0, Py_NewRef(key)); @@ -6909,7 +6846,7 @@ _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value) dict_unhashable_type(name); return -1; } - return delitem_knownhash_lock_held((PyObject *)dict, name, hash); + return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash); } else { return setitem_lock_held(dict, name, value); } @@ -7177,7 +7114,7 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr Py_BEGIN_CRITICAL_SECTION(dict); if (dict->ma_values == values && FT_ATOMIC_LOAD_UINT8(values->valid)) { - value = _Py_atomic_load_ptr_relaxed(&values->values[ix]); + value = _Py_atomic_load_ptr_consume(&values->values[ix]); *attr = _Py_XNewRefWithLock(value); success = true; } else { diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 531ee48eaf8..9a43057b383 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -13,7 +13,6 @@ #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_object.h" #include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException -#include "pycore_tuple.h" // _PyTuple_FromArray() #include "osdefs.h" // SEP #include "clinic/exceptions.c.h" @@ -119,7 +118,7 @@ BaseException_vectorcall(PyObject *type_obj, PyObject * const*args, self->context = NULL; self->suppress_context = 0; - self->args = _PyTuple_FromArray(args, PyVectorcall_NARGS(nargsf)); + self->args = PyTuple_FromArray(args, PyVectorcall_NARGS(nargsf)); if (!self->args) { Py_DECREF(self); return NULL; @@ -695,12 +694,12 @@ PyTypeObject _PyExc_ ## EXCNAME = { \ #define ComplexExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCNEW, \ EXCMETHODS, EXCMEMBERS, EXCGETSET, \ - EXCSTR, EXCDOC) \ + EXCSTR, EXCREPR, EXCDOC) \ static PyTypeObject _PyExc_ ## EXCNAME = { \ PyVarObject_HEAD_INIT(NULL, 0) \ # EXCNAME, \ sizeof(Py ## EXCSTORE ## Object), 0, \ - EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + EXCSTORE ## _dealloc, 0, 0, 0, 0, EXCREPR, 0, 0, 0, 0, 0, \ EXCSTR, 0, 0, 0, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ PyDoc_STR(EXCDOC), EXCSTORE ## _traverse, \ @@ -793,7 +792,7 @@ StopIteration_traverse(PyObject *op, visitproc visit, void *arg) } ComplexExtendsException(PyExc_Exception, StopIteration, StopIteration, - 0, 0, StopIteration_members, 0, 0, + 0, 0, StopIteration_members, 0, 0, 0, "Signal the end from iterator.__next__()."); @@ -866,7 +865,7 @@ static PyMemberDef SystemExit_members[] = { }; ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit, - 0, 0, SystemExit_members, 0, 0, + 0, 0, SystemExit_members, 0, 0, 0, "Request to exit from the interpreter."); /* @@ -891,6 +890,7 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyObject *message = NULL; PyObject *exceptions = NULL; + PyObject *exceptions_str = NULL; if (!PyArg_ParseTuple(args, "UO:BaseExceptionGroup.__new__", @@ -906,6 +906,18 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } + /* Save initial exceptions sequence as a string in case sequence is mutated */ + if (!PyList_Check(exceptions) && !PyTuple_Check(exceptions)) { + exceptions_str = PyObject_Repr(exceptions); + if (exceptions_str == NULL) { + /* We don't hold a reference to exceptions, so clear it before + * attempting a decref in the cleanup. + */ + exceptions = NULL; + goto error; + } + } + exceptions = PySequence_Tuple(exceptions); if (!exceptions) { return NULL; @@ -989,9 +1001,11 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds) self->msg = Py_NewRef(message); self->excs = exceptions; + self->excs_str = exceptions_str; return (PyObject*)self; error: - Py_DECREF(exceptions); + Py_XDECREF(exceptions); + Py_XDECREF(exceptions_str); return NULL; } @@ -1030,6 +1044,7 @@ BaseExceptionGroup_clear(PyObject *op) PyBaseExceptionGroupObject *self = PyBaseExceptionGroupObject_CAST(op); Py_CLEAR(self->msg); Py_CLEAR(self->excs); + Py_CLEAR(self->excs_str); return BaseException_clear(op); } @@ -1047,6 +1062,7 @@ BaseExceptionGroup_traverse(PyObject *op, visitproc visit, void *arg) PyBaseExceptionGroupObject *self = PyBaseExceptionGroupObject_CAST(op); Py_VISIT(self->msg); Py_VISIT(self->excs); + Py_VISIT(self->excs_str); return BaseException_traverse(op, visit, arg); } @@ -1064,6 +1080,54 @@ BaseExceptionGroup_str(PyObject *op) self->msg, num_excs, num_excs > 1 ? "s" : ""); } +static PyObject * +BaseExceptionGroup_repr(PyObject *op) +{ + PyBaseExceptionGroupObject *self = PyBaseExceptionGroupObject_CAST(op); + assert(self->msg); + + PyObject *exceptions_str = NULL; + + /* Use the saved exceptions string for custom sequences. */ + if (self->excs_str) { + exceptions_str = Py_NewRef(self->excs_str); + } + else { + assert(self->excs); + + /* Older versions delegated to BaseException, inserting the current + * value of self.args[1]; but this can be mutable and go out-of-sync + * with self.exceptions. Instead, use self.exceptions for accuracy, + * making it look like self.args[1] for backwards compatibility. */ + if (PyList_Check(PyTuple_GET_ITEM(self->args, 1))) { + PyObject *exceptions_list = PySequence_List(self->excs); + if (!exceptions_list) { + return NULL; + } + + exceptions_str = PyObject_Repr(exceptions_list); + Py_DECREF(exceptions_list); + } + else { + exceptions_str = PyObject_Repr(self->excs); + } + + if (!exceptions_str) { + return NULL; + } + } + + assert(exceptions_str != NULL); + + const char *name = _PyType_Name(Py_TYPE(self)); + PyObject *repr = PyUnicode_FromFormat( + "%s(%R, %U)", name, + self->msg, exceptions_str); + + Py_DECREF(exceptions_str); + return repr; +} + /*[clinic input] @critical_section BaseExceptionGroup.derive @@ -1698,7 +1762,7 @@ static PyMethodDef BaseExceptionGroup_methods[] = { ComplexExtendsException(PyExc_BaseException, BaseExceptionGroup, BaseExceptionGroup, BaseExceptionGroup_new /* new */, BaseExceptionGroup_methods, BaseExceptionGroup_members, - 0 /* getset */, BaseExceptionGroup_str, + 0 /* getset */, BaseExceptionGroup_str, BaseExceptionGroup_repr, "A combination of multiple unrelated exceptions."); /* @@ -2426,7 +2490,7 @@ static PyGetSetDef OSError_getset[] = { ComplexExtendsException(PyExc_Exception, OSError, OSError, OSError_new, OSError_methods, OSError_members, OSError_getset, - OSError_str, + OSError_str, 0, "Base class for I/O related errors."); @@ -2567,7 +2631,7 @@ static PyMethodDef NameError_methods[] = { ComplexExtendsException(PyExc_Exception, NameError, NameError, 0, NameError_methods, NameError_members, - 0, BaseException_str, "Name not found globally."); + 0, BaseException_str, 0, "Name not found globally."); /* * UnboundLocalError extends NameError @@ -2701,7 +2765,7 @@ static PyMethodDef AttributeError_methods[] = { ComplexExtendsException(PyExc_Exception, AttributeError, AttributeError, 0, AttributeError_methods, AttributeError_members, - 0, BaseException_str, "Attribute not found."); + 0, BaseException_str, 0, "Attribute not found."); /* * SyntaxError extends Exception @@ -2900,7 +2964,7 @@ static PyMemberDef SyntaxError_members[] = { ComplexExtendsException(PyExc_Exception, SyntaxError, SyntaxError, 0, 0, SyntaxError_members, 0, - SyntaxError_str, "Invalid syntax."); + SyntaxError_str, 0, "Invalid syntax."); /* @@ -2960,7 +3024,7 @@ KeyError_str(PyObject *op) } ComplexExtendsException(PyExc_LookupError, KeyError, BaseException, - 0, 0, 0, 0, KeyError_str, "Mapping key not found."); + 0, 0, 0, 0, KeyError_str, 0, "Mapping key not found."); /* diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 1fefb12803e..2cb690748d9 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -135,13 +135,6 @@ PyFloat_FromDouble(double fval) return (PyObject *) op; } -_PyStackRef _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value) -{ - PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); - return PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(value)); -} - static PyObject * float_from_string_inner(const char *s, Py_ssize_t len, void *obj) { @@ -2030,6 +2023,10 @@ PyFloat_Pack2(double x, char *data, int le) memcpy(&v, &x, sizeof(v)); v &= 0xffc0000000000ULL; bits = (unsigned short)(v >> 42); /* NaN's type & payload */ + /* set qNaN if no payload */ + if (!bits) { + bits |= (1<<9); + } } else { sign = (x < 0.0); @@ -2202,16 +2199,16 @@ PyFloat_Pack4(double x, char *data, int le) if ((v & (1ULL << 51)) == 0) { uint32_t u32; memcpy(&u32, &y, 4); - u32 &= ~(1 << 22); /* make sNaN */ + /* if have payload, make sNaN */ + if (u32 & 0x3fffff) { + u32 &= ~(1 << 22); + } memcpy(&y, &u32, 4); } #else uint32_t u32; memcpy(&u32, &y, 4); - if ((v & (1ULL << 51)) == 0) { - u32 &= ~(1 << 22); - } /* Workaround RISC-V: "If a NaN value is converted to a * different floating-point type, the result is the * canonical NaN of the new type". The canonical NaN here @@ -2222,6 +2219,10 @@ PyFloat_Pack4(double x, char *data, int le) /* add payload */ u32 -= (u32 & 0x3fffff); u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29); + /* if have payload, make sNaN */ + if ((v & (1ULL << 51)) == 0 && (u32 & 0x3fffff)) { + u32 &= ~(1 << 22); + } memcpy(&y, &u32, 4); #endif @@ -2407,7 +2408,7 @@ PyFloat_Unpack2(const char *data, int le) if (e == 0x1f) { if (f == 0) { /* Infinity */ - return sign ? -Py_INFINITY : Py_INFINITY; + return sign ? -INFINITY : INFINITY; } else { /* NaN */ diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 0cae3703d1d..b652973600c 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -17,6 +17,7 @@ #include "frameobject.h" // PyFrameLocalsProxyObject #include "opcode.h" // EXTENDED_ARG +#include "pycore_optimizer.h" #include "clinic/frameobject.c.h" @@ -260,7 +261,10 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value) return -1; } - _Py_Executors_InvalidateDependency(PyInterpreterState_Get(), co, 1); +#if _Py_TIER2 + _Py_Executors_InvalidateDependency(_PyInterpreterState_GET(), co, 1); + _PyJit_Tracer_InvalidateDependency(_PyThreadState_GET(), co); +#endif _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); _PyStackRef oldvalue = fast[i]; diff --git a/Objects/funcobject.c b/Objects/funcobject.c index d8a10075578..b659ac80233 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -11,7 +11,7 @@ #include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_stats.h" #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() - +#include "pycore_optimizer.h" // _PyJit_Tracer_InvalidateDependency static const char * func_event_name(PyFunction_WatchEvent event) { @@ -62,6 +62,7 @@ handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func, case PyFunction_EVENT_MODIFY_CODE: case PyFunction_EVENT_MODIFY_DEFAULTS: case PyFunction_EVENT_MODIFY_KWDEFAULTS: + case PyFunction_EVENT_MODIFY_QUALNAME: RARE_EVENT_INTERP_INC(interp, func_modification); break; default: @@ -747,6 +748,7 @@ func_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) "__qualname__ must be set to a string object"); return -1; } + handle_func_event(PyFunction_EVENT_MODIFY_QUALNAME, (PyFunctionObject *) op, value); Py_XSETREF(op->func_qualname, Py_NewRef(value)); return 0; } @@ -1149,6 +1151,10 @@ func_dealloc(PyObject *self) if (_PyObject_ResurrectEnd(self)) { return; } +#if _Py_TIER2 + _Py_Executors_InvalidateDependency(_PyInterpreterState_GET(), self, 1); + _PyJit_Tracer_InvalidateDependency(_PyThreadState_GET(), self); +#endif _PyObject_GC_UNTRACK(op); FT_CLEAR_WEAKREFS(self, op->func_weakreflist); (void)func_clear((PyObject*)op); diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 3bb961aa2b6..8b526f43f1e 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -525,12 +525,24 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje return NULL; } if (unpack) { + if (!PyTuple_Check(arg)) { + Py_DECREF(newargs); + Py_DECREF(item); + Py_XDECREF(tuple_args); + PyObject *original = PyTuple_GET_ITEM(args, iarg); + PyErr_Format(PyExc_TypeError, + "expected __typing_subst__ of %T objects to return a tuple, not %T", + original, arg); + Py_DECREF(arg); + return NULL; + } jarg = tuple_extend(&newargs, jarg, &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg)); Py_DECREF(arg); if (jarg < 0) { Py_DECREF(item); Py_XDECREF(tuple_args); + assert(newargs == NULL); return NULL; } } @@ -636,7 +648,6 @@ ga_vectorcall(PyObject *self, PyObject *const *args, static const char* const attr_exceptions[] = { "__class__", - "__bases__", "__origin__", "__args__", "__unpacked__", @@ -645,6 +656,11 @@ static const char* const attr_exceptions[] = { "__mro_entries__", "__reduce_ex__", // needed so we don't look up object.__reduce_ex__ "__reduce__", + NULL, +}; + +static const char* const attr_blocked[] = { + "__bases__", "__copy__", "__deepcopy__", NULL, @@ -655,15 +671,29 @@ ga_getattro(PyObject *self, PyObject *name) { gaobject *alias = (gaobject *)self; if (PyUnicode_Check(name)) { + // When we check blocked attrs, we don't allow to proxy them to `__origin__`. + // Otherwise, we can break existing code. + for (const char * const *p = attr_blocked; ; p++) { + if (*p == NULL) { + break; + } + if (_PyUnicode_EqualToASCIIString(name, *p)) { + goto generic_getattr; + } + } + + // When we see own attrs, it has a priority over `__origin__`'s attr. for (const char * const *p = attr_exceptions; ; p++) { if (*p == NULL) { return PyObject_GetAttr(alias->origin, name); } if (_PyUnicode_EqualToASCIIString(name, *p)) { - break; + goto generic_getattr; } } } + +generic_getattr: return PyObject_GenericGetAttr(self, name); } diff --git a/Objects/genobject.c b/Objects/genobject.c index bcde9e1a7be..3694198289d 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -315,7 +315,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) } PyDoc_STRVAR(send_doc, -"send(arg) -> send 'arg' into generator,\n\ +"send(value) -> send 'value' into generator,\n\ return next yielded value or raise StopIteration."); static PyObject * @@ -390,6 +390,7 @@ gen_close(PyObject *self, PyObject *args) if (gen->gi_frame_state == FRAME_CREATED) { gen->gi_frame_state = FRAME_COMPLETED; + gen_clear_frame(gen); Py_RETURN_NONE; } if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { @@ -407,11 +408,12 @@ gen_close(PyObject *self, PyObject *args) } _PyInterpreterFrame *frame = &gen->gi_iframe; if (is_resume(frame->instr_ptr)) { + bool no_unwind_tools = _PyEval_NoToolsForUnwind(_PyThreadState_GET()); /* We can safely ignore the outermost try block * as it is automatically generated to handle * StopIteration. */ int oparg = frame->instr_ptr->op.arg; - if (oparg & RESUME_OPARG_DEPTH1_MASK) { + if (oparg & RESUME_OPARG_DEPTH1_MASK && no_unwind_tools) { // RESUME after YIELD_VALUE and exception depth is 1 assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); gen->gi_frame_state = FRAME_COMPLETED; @@ -932,6 +934,7 @@ make_gen(PyTypeObject *type, PyFunctionObject *func) gen->gi_weakreflist = NULL; gen->gi_exc_state.exc_value = NULL; gen->gi_exc_state.previous_item = NULL; + gen->gi_iframe.f_executable = PyStackRef_None; assert(func->func_name != NULL); gen->gi_name = Py_NewRef(func->func_name); assert(func->func_qualname != NULL); diff --git a/Objects/listobject.c b/Objects/listobject.c index 5905a6d335b..1722ea60cdc 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -6,16 +6,16 @@ #include "pycore_critical_section.h" // _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED() #include "pycore_dict.h" // _PyDictViewObject #include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() -#include "pycore_pyatomic_ft_wrappers.h" #include "pycore_interp.h" // PyInterpreterState.list #include "pycore_list.h" // struct _Py_list_freelist, _PyListIterObject #include "pycore_long.h" // _PyLong_DigitCount #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats() -#include "pycore_stackref.h" // _Py_TryIncrefCompareStackRef() -#include "pycore_tuple.h" // _PyTuple_FromArray() -#include "pycore_typeobject.h" // _Py_TYPE_VERSION_LIST +#include "pycore_pyatomic_ft_wrappers.h" #include "pycore_setobject.h" // _PySet_NextEntry() +#include "pycore_stackref.h" // _Py_TryIncrefCompareStackRef() +#include "pycore_tuple.h" // _PyTuple_FromArraySteal() +#include "pycore_typeobject.h" // _Py_TYPE_VERSION_LIST #include <stddef.h> /*[clinic input] @@ -1382,9 +1382,9 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) PyObject **dest = self->ob_item + m; Py_ssize_t pos = 0; Py_ssize_t i = 0; - PyObject *key, *value; - while (_PyDict_Next((PyObject *)dict, &pos, &key, &value, NULL)) { - PyObject *item = PyTuple_Pack(2, key, value); + PyObject *key_value[2]; + while (_PyDict_Next((PyObject *)dict, &pos, &key_value[0], &key_value[1], NULL)) { + PyObject *item = PyTuple_FromArray(key_value, 2); if (item == NULL) { Py_SET_SIZE(self, m + i); return -1; @@ -3221,7 +3221,7 @@ PyList_AsTuple(PyObject *v) PyObject *ret; PyListObject *self = (PyListObject *)v; Py_BEGIN_CRITICAL_SECTION(self); - ret = _PyTuple_FromArray(self->ob_item, Py_SIZE(v)); + ret = PyTuple_FromArray(self->ob_item, Py_SIZE(v)); Py_END_CRITICAL_SECTION(); return ret; } diff --git a/Objects/longobject.c b/Objects/longobject.c index 286afae4d7d..8ba1fd65078 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -352,7 +352,7 @@ _PyLong_Negate(PyLongObject **x_p) PyLongObject *x; x = (PyLongObject *)*x_p; - if (Py_REFCNT(x) == 1) { + if (_PyObject_IsUniquelyReferenced((PyObject *)x)) { _PyLong_FlipSign(x); return; } @@ -1209,13 +1209,19 @@ _PyLong_AsByteArray(PyLongObject* v, *p = (unsigned char)(accum & 0xff); p += pincr; } - else if (j == n && n > 0 && is_signed) { + else if (j == n && is_signed) { /* The main loop filled the byte array exactly, so the code just above didn't get to ensure there's a sign bit, and the loop below wouldn't add one either. Make sure a sign bit exists. */ - unsigned char msb = *(p - pincr); - int sign_bit_set = msb >= 0x80; + int sign_bit_set; + if (n > 0) { + unsigned char msb = *(p - pincr); + sign_bit_set = msb >= 0x80; + } + else { + sign_bit_set = 0; + } assert(accumbits == 0); if (sign_bit_set == do_twos_comp) return 0; @@ -2014,7 +2020,7 @@ static int pylong_int_to_decimal_string(PyObject *aa, PyObject **p_output, _PyUnicodeWriter *writer, - _PyBytesWriter *bytes_writer, + PyBytesWriter *bytes_writer, char **bytes_str) { PyObject *s = NULL; @@ -2045,7 +2051,8 @@ pylong_int_to_decimal_string(PyObject *aa, Py_ssize_t size = PyUnicode_GET_LENGTH(s); const void *data = PyUnicode_DATA(s); int kind = PyUnicode_KIND(s); - *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, size); + *bytes_str = PyBytesWriter_GrowAndUpdatePointer(bytes_writer, size, + *bytes_str); if (*bytes_str == NULL) { goto error; } @@ -2082,7 +2089,7 @@ static int long_to_decimal_string_internal(PyObject *aa, PyObject **p_output, _PyUnicodeWriter *writer, - _PyBytesWriter *bytes_writer, + PyBytesWriter *bytes_writer, char **bytes_str) { PyLongObject *scratch, *a; @@ -2208,7 +2215,8 @@ long_to_decimal_string_internal(PyObject *aa, } } else if (bytes_writer) { - *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, strlen); + *bytes_str = PyBytesWriter_GrowAndUpdatePointer(bytes_writer, strlen, + *bytes_str); if (*bytes_str == NULL) { Py_DECREF(scratch); return -1; @@ -2318,7 +2326,7 @@ long_to_decimal_string(PyObject *aa) static int long_format_binary(PyObject *aa, int base, int alternate, PyObject **p_output, _PyUnicodeWriter *writer, - _PyBytesWriter *bytes_writer, char **bytes_str) + PyBytesWriter *bytes_writer, char **bytes_str) { PyLongObject *a = (PyLongObject *)aa; PyObject *v = NULL; @@ -2379,7 +2387,8 @@ long_format_binary(PyObject *aa, int base, int alternate, return -1; } else if (bytes_writer) { - *bytes_str = _PyBytesWriter_Prepare(bytes_writer, *bytes_str, sz); + *bytes_str = PyBytesWriter_GrowAndUpdatePointer(bytes_writer, sz, + *bytes_str); if (*bytes_str == NULL) return -1; } @@ -2508,7 +2517,7 @@ _PyLong_FormatWriter(_PyUnicodeWriter *writer, } char* -_PyLong_FormatBytesWriter(_PyBytesWriter *writer, char *str, +_PyLong_FormatBytesWriter(PyBytesWriter *writer, char *str, PyObject *obj, int base, int alternate) { @@ -3676,38 +3685,54 @@ long_hash(PyObject *obj) } i = _PyLong_DigitCount(v); sign = _PyLong_NonCompactSign(v); - x = 0; - while (--i >= 0) { - /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we - want to compute x * 2**PyLong_SHIFT + v->long_value.ob_digit[i] modulo - _PyHASH_MODULUS. - The computation of x * 2**PyLong_SHIFT % _PyHASH_MODULUS + // unroll first digit + Py_BUILD_ASSERT(PyHASH_BITS > PyLong_SHIFT); + assert(i >= 1); + --i; + x = v->long_value.ob_digit[i]; + assert(x < PyHASH_MODULUS); + +#if PyHASH_BITS >= 2 * PyLong_SHIFT + // unroll second digit + assert(i >= 1); + --i; + x <<= PyLong_SHIFT; + x += v->long_value.ob_digit[i]; + assert(x < PyHASH_MODULUS); +#endif + + while (--i >= 0) { + /* Here x is a quantity in the range [0, PyHASH_MODULUS); we + want to compute x * 2**PyLong_SHIFT + v->long_value.ob_digit[i] modulo + PyHASH_MODULUS. + + The computation of x * 2**PyLong_SHIFT % PyHASH_MODULUS amounts to a rotation of the bits of x. To see this, write - x * 2**PyLong_SHIFT = y * 2**_PyHASH_BITS + z + x * 2**PyLong_SHIFT = y * 2**PyHASH_BITS + z - where y = x >> (_PyHASH_BITS - PyLong_SHIFT) gives the top + where y = x >> (PyHASH_BITS - PyLong_SHIFT) gives the top PyLong_SHIFT bits of x (those that are shifted out of the - original _PyHASH_BITS bits, and z = (x << PyLong_SHIFT) & - _PyHASH_MODULUS gives the bottom _PyHASH_BITS - PyLong_SHIFT - bits of x, shifted up. Then since 2**_PyHASH_BITS is - congruent to 1 modulo _PyHASH_MODULUS, y*2**_PyHASH_BITS is - congruent to y modulo _PyHASH_MODULUS. So + original PyHASH_BITS bits, and z = (x << PyLong_SHIFT) & + PyHASH_MODULUS gives the bottom PyHASH_BITS - PyLong_SHIFT + bits of x, shifted up. Then since 2**PyHASH_BITS is + congruent to 1 modulo PyHASH_MODULUS, y*2**PyHASH_BITS is + congruent to y modulo PyHASH_MODULUS. So - x * 2**PyLong_SHIFT = y + z (mod _PyHASH_MODULUS). + x * 2**PyLong_SHIFT = y + z (mod PyHASH_MODULUS). The right-hand side is just the result of rotating the - _PyHASH_BITS bits of x left by PyLong_SHIFT places; since - not all _PyHASH_BITS bits of x are 1s, the same is true - after rotation, so 0 <= y+z < _PyHASH_MODULUS and y + z is + PyHASH_BITS bits of x left by PyLong_SHIFT places; since + not all PyHASH_BITS bits of x are 1s, the same is true + after rotation, so 0 <= y+z < PyHASH_MODULUS and y + z is the reduction of x*2**PyLong_SHIFT modulo - _PyHASH_MODULUS. */ - x = ((x << PyLong_SHIFT) & _PyHASH_MODULUS) | - (x >> (_PyHASH_BITS - PyLong_SHIFT)); + PyHASH_MODULUS. */ + x = ((x << PyLong_SHIFT) & PyHASH_MODULUS) | + (x >> (PyHASH_BITS - PyLong_SHIFT)); x += v->long_value.ob_digit[i]; - if (x >= _PyHASH_MODULUS) - x -= _PyHASH_MODULUS; + if (x >= PyHASH_MODULUS) + x -= PyHASH_MODULUS; } x = x * sign; if (x == (Py_uhash_t)-1) @@ -4409,10 +4434,10 @@ pylong_int_divmod(PyLongObject *v, PyLongObject *w, if (result == NULL) { return -1; } - if (!PyTuple_Check(result)) { + if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 2) { Py_DECREF(result); PyErr_SetString(PyExc_ValueError, - "tuple is required from int_divmod()"); + "tuple of length 2 is required from int_divmod()"); return -1; } PyObject *q = PyTuple_GET_ITEM(result, 0); @@ -5824,7 +5849,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) assert(size_a >= 0); _PyLong_SetSignAndDigitCount(c, 1, size_a); } - else if (Py_REFCNT(a) == 1) { + else if (_PyObject_IsUniquelyReferenced((PyObject *)a)) { c = (PyLongObject*)Py_NewRef(a); } else { @@ -5838,7 +5863,8 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) assert(size_a >= 0); _PyLong_SetSignAndDigitCount(d, 1, size_a); } - else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) { + else if (_PyObject_IsUniquelyReferenced((PyObject *)b) + && size_a <= alloc_b) { d = (PyLongObject*)Py_NewRef(b); assert(size_a >= 0); _PyLong_SetSignAndDigitCount(d, 1, size_a); @@ -6356,7 +6382,7 @@ int_as_integer_ratio_impl(PyObject *self) /*[clinic input] int.to_bytes - length: Py_ssize_t = 1 + length: Py_ssize_t(allow_negative=False) = 1 Length of bytes object to use. An OverflowError is raised if the integer is not representable with the given number of bytes. Default is length 1. @@ -6378,11 +6404,9 @@ Return an array of bytes representing an integer. static PyObject * int_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder, int is_signed) -/*[clinic end generated code: output=89c801df114050a3 input=a0103d0e9ad85c2b]*/ +/*[clinic end generated code: output=89c801df114050a3 input=66f9d0c20529b44f]*/ { int little_endian; - PyObject *bytes; - if (byteorder == NULL) little_endian = 0; else if (_PyUnicode_Equal(byteorder, &_Py_ID(little))) @@ -6395,24 +6419,19 @@ int_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder, return NULL; } - if (length < 0) { - PyErr_SetString(PyExc_ValueError, - "length argument must be non-negative"); + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; } - bytes = PyBytes_FromStringAndSize(NULL, length); - if (bytes == NULL) - return NULL; - if (_PyLong_AsByteArray((PyLongObject *)self, - (unsigned char *)PyBytes_AS_STRING(bytes), + PyBytesWriter_GetData(writer), length, little_endian, is_signed, 1) < 0) { - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); return NULL; } - return bytes; + return PyBytesWriter_Finish(writer); } /*[clinic input] diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 94ff0fe624e..f1232f38921 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -2285,7 +2285,6 @@ memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order) { Py_buffer *src = VIEW_ADDR(self); char ord = 'C'; - PyObject *bytes; CHECK_RELEASED(self); @@ -2303,16 +2302,18 @@ memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order) } } - bytes = PyBytes_FromStringAndSize(NULL, src->len); - if (bytes == NULL) - return NULL; - - if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, ord) < 0) { - Py_DECREF(bytes); + PyBytesWriter *writer = PyBytesWriter_Create(src->len); + if (writer == NULL) { return NULL; } - return bytes; + if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer), + src, src->len, ord) < 0) { + PyBytesWriter_Discard(writer); + return NULL; + } + + return PyBytesWriter_Finish(writer); } /*[clinic input] @@ -2344,8 +2345,6 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, /*[clinic end generated code: output=430ca760f94f3ca7 input=539f6a3a5fb56946]*/ { Py_buffer *src = VIEW_ADDR(self); - PyObject *bytes; - PyObject *ret; CHECK_RELEASED(self); @@ -2353,19 +2352,22 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, return _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep); } - bytes = PyBytes_FromStringAndSize(NULL, src->len); - if (bytes == NULL) - return NULL; - - if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, 'C') < 0) { - Py_DECREF(bytes); + PyBytesWriter *writer = PyBytesWriter_Create(src->len); + if (writer == NULL) { return NULL; } - ret = _Py_strhex_with_sep( - PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes), - sep, bytes_per_sep); - Py_DECREF(bytes); + if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer), + src, src->len, 'C') < 0) { + PyBytesWriter_Discard(writer); + return NULL; + } + + PyObject *ret = _Py_strhex_with_sep( + PyBytesWriter_GetData(writer), + PyBytesWriter_GetSize(writer), + sep, bytes_per_sep); + PyBytesWriter_Discard(writer); return ret; } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 47681e42518..5a0b16ba572 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -2,13 +2,14 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_ceval.h" // _PyEval_EnableGILTransient() #include "pycore_dict.h" // _PyDict_EnablePerThreadRefcounting() #include "pycore_fileutils.h" // _Py_wgetcwd #include "pycore_import.h" // _PyImport_GetNextModuleIndex() #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_modsupport.h" // _PyModule_CreateInitialized() -#include "pycore_moduleobject.h" // _PyModule_GetDef() +#include "pycore_moduleobject.h" // _PyModule_GetDefOrNull() #include "pycore_object.h" // _PyType_AllocNoTrack #include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" // _PyInterpreterState_GET() @@ -27,6 +28,27 @@ static PyMemberDef module_members[] = { {0} }; +static void +assert_def_missing_or_redundant(PyModuleObject *m) +{ + /* We copy all relevant info into the module object. + * Modules created using a def keep a reference to that (statically + * allocated) def; the info there should match what we have in the module. + */ +#ifndef NDEBUG + if (m->md_token_is_def) { + PyModuleDef *def = (PyModuleDef *)m->md_token; + assert(def); +#define DO_ASSERT(F) assert (def->m_ ## F == m->md_state_ ## F); + DO_ASSERT(size); + DO_ASSERT(traverse); + DO_ASSERT(clear); + DO_ASSERT(free); +#undef DO_ASSERT + } +#endif // NDEBUG +} + PyTypeObject PyModuleDef_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) @@ -44,14 +66,73 @@ _PyModule_IsExtension(PyObject *obj) } PyModuleObject *module = (PyModuleObject*)obj; - PyModuleDef *def = module->md_def; - return (def != NULL && def->m_methods != NULL); + if (module->md_exec) { + return 1; + } + if (module->md_token_is_def) { + PyModuleDef *def = (PyModuleDef *)module->md_token; + return (module->md_token_is_def && def->m_methods != NULL); + } + return 0; } PyObject* PyModuleDef_Init(PyModuleDef* def) { +#ifdef Py_GIL_DISABLED + // Check that this def does not come from a non-free-threading ABI. + // + // This is meant as a "sanity check"; users should never rely on it. + // In particular, if we run out of ob_flags bits, or otherwise need to + // change some of the internals, this check can go away. Still, it + // would be nice to keep it for the free-threading transition. + // + // A PyModuleDef must be initialized with PyModuleDef_HEAD_INIT, + // which (via PyObject_HEAD_INIT) sets _Py_STATICALLY_ALLOCATED_FLAG + // and not _Py_LEGACY_ABI_CHECK_FLAG. For PyModuleDef, these flags never + // change. + // This means that the lower nibble of a valid PyModuleDef's ob_flags is + // always `_10_` (in binary; `_` is don't care). + // + // So, a check for these bits won't reject valid PyModuleDef. + // Rejecting incompatible extensions is slightly less important; here's + // how that works: + // + // In the pre-free-threading stable ABI, PyModuleDef_HEAD_INIT is big + // enough to overlap with free-threading ABI's ob_flags, is all zeros + // except for the refcount field. + // The refcount field can be: + // - 1 (3.11 and below) + // - UINT_MAX >> 2 (32-bit 3.12 & 3.13) + // - UINT_MAX (64-bit 3.12 & 3.13) + // - 7L << 28 (3.14) + // + // This means that the lower nibble of *any byte* in PyModuleDef_HEAD_INIT + // is not `_10_` -- it can be: + // - 0b0000 + // - 0b0001 + // - 0b0011 (from UINT_MAX >> 2) + // - 0b0111 (from 7L << 28) + // - 0b1111 (e.g. from UINT_MAX) + // (The values may change at runtime as the PyModuleDef is used, but + // PyModuleDef_Init is required before using the def as a Python object, + // so we check at least once with the initial values. + uint16_t flags = ((PyObject*)def)->ob_flags; + uint16_t bits = _Py_STATICALLY_ALLOCATED_FLAG | _Py_LEGACY_ABI_CHECK_FLAG; + if ((flags & bits) != _Py_STATICALLY_ALLOCATED_FLAG) { + const char *message = "invalid PyModuleDef, extension possibly " + "compiled for non-free-threaded Python"; + // Write the error as unraisable: if the extension tries calling + // any API, it's likely to segfault and lose the exception. + PyErr_SetString(PyExc_SystemError, message); + PyErr_WriteUnraisable(NULL); + // But also raise the exception normally -- this is technically + // a recoverable state. + PyErr_SetString(PyExc_SystemError, message); + return NULL; + } +#endif assert(PyModuleDef_Type.tp_flags & Py_TPFLAGS_READY); if (def->m_base.m_index == 0) { Py_SET_REFCNT(def, 1); @@ -93,10 +174,19 @@ new_module_notrack(PyTypeObject *mt) m = (PyModuleObject *)_PyType_AllocNoTrack(mt, 0); if (m == NULL) return NULL; - m->md_def = NULL; m->md_state = NULL; m->md_weaklist = NULL; m->md_name = NULL; + m->md_token_is_def = false; +#ifdef Py_GIL_DISABLED + m->md_requires_gil = true; +#endif + m->md_state_size = 0; + m->md_state_traverse = NULL; + m->md_state_clear = NULL; + m->md_state_free = NULL; + m->md_exec = NULL; + m->md_token = NULL; m->md_dict = PyDict_New(); if (m->md_dict == NULL) { Py_DECREF(m); @@ -211,6 +301,17 @@ PyModule_Create2(PyModuleDef* module, int module_api_version) return _PyModule_CreateInitialized(module, module_api_version); } +static void +module_copy_members_from_deflike( + PyModuleObject *md, + PyModuleDef *def_like /* not necessarily a valid Python object */) +{ + md->md_state_size = def_like->m_size; + md->md_state_traverse = def_like->m_traverse; + md->md_state_clear = def_like->m_clear; + md->md_state_free = def_like->m_free; +} + PyObject * _PyModule_CreateInitialized(PyModuleDef* module, int module_api_version) { @@ -257,15 +358,21 @@ _PyModule_CreateInitialized(PyModuleDef* module, int module_api_version) return NULL; } } - m->md_def = module; + m->md_token = module; + m->md_token_is_def = true; + module_copy_members_from_deflike(m, module); #ifdef Py_GIL_DISABLED - m->md_gil = Py_MOD_GIL_USED; + m->md_requires_gil = true; #endif return (PyObject*)m; } -PyObject * -PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_version) +static PyObject * +module_from_def_and_spec( + PyModuleDef* def_like, /* not necessarily a valid Python object */ + PyObject *spec, + int module_api_version, + PyModuleDef* original_def /* NULL if not defined by a def */) { PyModuleDef_Slot* cur_slot; PyObject *(*create)(PyObject *, PyModuleDef*) = NULL; @@ -274,14 +381,14 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio int has_multiple_interpreters_slot = 0; void *multiple_interpreters = (void *)0; int has_gil_slot = 0; - void *gil_slot = Py_MOD_GIL_USED; + bool requires_gil = true; int has_execution_slots = 0; const char *name; int ret; + void *token = NULL; + _Py_modexecfunc m_exec = NULL; PyInterpreterState *interp = _PyInterpreterState_GET(); - PyModuleDef_Init(def); - nameobj = PyObject_GetAttrString(spec, "name"); if (nameobj == NULL) { return NULL; @@ -295,7 +402,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio goto error; } - if (def->m_size < 0) { + if (def_like->m_size < 0) { PyErr_Format( PyExc_SystemError, "module %s: m_size may not be negative for multi-phase initialization", @@ -303,7 +410,35 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio goto error; } - for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) { + for (cur_slot = def_like->m_slots; cur_slot && cur_slot->slot; cur_slot++) { + // Macro to copy a non-NULL, non-repeatable slot that's unusable with + // PyModuleDef. The destination must be initially NULL. +#define COPY_COMMON_SLOT(SLOT, TYPE, DEST) \ + do { \ + if (!(TYPE)(cur_slot->value)) { \ + PyErr_Format( \ + PyExc_SystemError, \ + "module %s: " #SLOT " must not be NULL", \ + name); \ + goto error; \ + } \ + if (original_def) { \ + PyErr_Format( \ + PyExc_SystemError, \ + "module %s: " #SLOT " used with PyModuleDef", \ + name); \ + goto error; \ + } \ + if (DEST) { \ + PyErr_Format( \ + PyExc_SystemError, \ + "module %s has more than one " #SLOT " slot", \ + name); \ + goto error; \ + } \ + DEST = (TYPE)(cur_slot->value); \ + } while (0); \ + ///////////////////////////////////////////////////////////////// switch (cur_slot->slot) { case Py_mod_create: if (create) { @@ -317,6 +452,9 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio break; case Py_mod_exec: has_execution_slots = 1; + if (!original_def) { + COPY_COMMON_SLOT(Py_mod_exec, _Py_modexecfunc, m_exec); + } break; case Py_mod_multiple_interpreters: if (has_multiple_interpreters_slot) { @@ -337,9 +475,43 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio name); goto error; } - gil_slot = cur_slot->value; + requires_gil = (cur_slot->value != Py_MOD_GIL_NOT_USED); has_gil_slot = 1; break; + case Py_mod_abi: + if (PyABIInfo_Check((PyABIInfo *)cur_slot->value, name) < 0) { + goto error; + } + break; + case Py_mod_name: + COPY_COMMON_SLOT(Py_mod_name, char*, def_like->m_name); + break; + case Py_mod_doc: + COPY_COMMON_SLOT(Py_mod_doc, char*, def_like->m_doc); + break; + case Py_mod_state_size: + COPY_COMMON_SLOT(Py_mod_state_size, Py_ssize_t, + def_like->m_size); + break; + case Py_mod_methods: + COPY_COMMON_SLOT(Py_mod_methods, PyMethodDef*, + def_like->m_methods); + break; + case Py_mod_state_traverse: + COPY_COMMON_SLOT(Py_mod_state_traverse, traverseproc, + def_like->m_traverse); + break; + case Py_mod_state_clear: + COPY_COMMON_SLOT(Py_mod_state_clear, inquiry, + def_like->m_clear); + break; + case Py_mod_state_free: + COPY_COMMON_SLOT(Py_mod_state_free, freefunc, + def_like->m_free); + break; + case Py_mod_token: + COPY_COMMON_SLOT(Py_mod_token, void*, token); + break; default: assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT); PyErr_Format( @@ -348,8 +520,25 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio name, cur_slot->slot); goto error; } +#undef COPY_COMMON_SLOT } +#ifdef Py_GIL_DISABLED + // For modules created directly from slots (not from a def), we enable + // the GIL here (pairing `_PyEval_EnableGILTransient` with + // an immediate `_PyImport_EnableGILAndWarn`). + // For modules created from a def, the caller is responsible for this. + if (!original_def && requires_gil) { + PyThreadState *tstate = _PyThreadState_GET(); + if (_PyEval_EnableGILTransient(tstate) < 0) { + goto error; + } + if (_PyImport_EnableGILAndWarn(tstate, nameobj) < 0) { + goto error; + } + } +#endif + /* By default, multi-phase init modules are expected to work under multiple interpreters. */ if (!has_multiple_interpreters_slot) { @@ -371,7 +560,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio } if (create) { - m = create(spec, def); + m = create(spec, original_def); if (m == NULL) { if (!PyErr_Occurred()) { PyErr_Format( @@ -397,15 +586,27 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio } if (PyModule_Check(m)) { - ((PyModuleObject*)m)->md_state = NULL; - ((PyModuleObject*)m)->md_def = def; + PyModuleObject *mod = (PyModuleObject*)m; + mod->md_state = NULL; + module_copy_members_from_deflike(mod, def_like); + if (original_def) { + assert (!token); + mod->md_token = original_def; + mod->md_token_is_def = 1; + } + else { + mod->md_token = token; + } #ifdef Py_GIL_DISABLED - ((PyModuleObject*)m)->md_gil = gil_slot; + mod->md_requires_gil = requires_gil; #else - (void)gil_slot; + (void)requires_gil; #endif + mod->md_exec = m_exec; } else { - if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) { + if (def_like->m_size > 0 || def_like->m_traverse || def_like->m_clear + || def_like->m_free) + { PyErr_Format( PyExc_SystemError, "module %s is not a module object, but requests module state", @@ -420,17 +621,25 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio name); goto error; } + if (token) { + PyErr_Format( + PyExc_SystemError, + "module %s specifies a token, but did not create " + "a ModuleType instance", + name); + goto error; + } } - if (def->m_methods != NULL) { - ret = _add_methods_to_object(m, nameobj, def->m_methods); + if (def_like->m_methods != NULL) { + ret = _add_methods_to_object(m, nameobj, def_like->m_methods); if (ret != 0) { goto error; } } - if (def->m_doc != NULL) { - ret = PyModule_SetDocString(m, def->m_doc); + if (def_like->m_doc != NULL) { + ret = PyModule_SetDocString(m, def_like->m_doc); if (ret != 0) { goto error; } @@ -445,83 +654,131 @@ error: return NULL; } +PyObject * +PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_version) +{ + PyModuleDef_Init(def); + return module_from_def_and_spec(def, spec, module_api_version, def); +} + +PyObject * +PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots, PyObject *spec) +{ + if (!slots) { + PyErr_SetString( + PyExc_SystemError, + "PyModule_FromSlotsAndSpec called with NULL slots"); + return NULL; + } + // Fill in enough of a PyModuleDef to pass to common machinery + PyModuleDef def_like = {.m_slots = (PyModuleDef_Slot *)slots}; + + return module_from_def_and_spec(&def_like, spec, PYTHON_API_VERSION, + NULL); +} + #ifdef Py_GIL_DISABLED int PyUnstable_Module_SetGIL(PyObject *module, void *gil) { + bool requires_gil = (gil != Py_MOD_GIL_NOT_USED); if (!PyModule_Check(module)) { PyErr_BadInternalCall(); return -1; } - ((PyModuleObject *)module)->md_gil = gil; + ((PyModuleObject *)module)->md_requires_gil = requires_gil; return 0; } #endif +static int +run_exec_func(PyObject *module, int (*exec)(PyObject *)) +{ + int ret = exec(module); + if (ret != 0) { + if (!PyErr_Occurred()) { + PyErr_Format( + PyExc_SystemError, + "execution of %R failed without setting an exception", + module); + } + return -1; + } + if (PyErr_Occurred()) { + _PyErr_FormatFromCause( + PyExc_SystemError, + "execution of module %R raised unreported exception", + module); + return -1; + } + return 0; +} + +static int +alloc_state(PyObject *module) +{ + if (!PyModule_Check(module)) { + PyErr_Format(PyExc_TypeError, "expected module, got %T", module); + return -1; + } + PyModuleObject *md = (PyModuleObject*)module; + + if (md->md_state_size >= 0) { + if (md->md_state == NULL) { + /* Always set a state pointer; this serves as a marker to skip + * multiple initialization (importlib.reload() is no-op) */ + md->md_state = PyMem_Malloc(md->md_state_size); + if (!md->md_state) { + PyErr_NoMemory(); + return -1; + } + memset(md->md_state, 0, md->md_state_size); + } + } + return 0; +} + +int +PyModule_Exec(PyObject *module) +{ + if (alloc_state(module) < 0) { + return -1; + } + PyModuleObject *md = (PyModuleObject*)module; + if (md->md_exec) { + assert(!md->md_token_is_def); + return run_exec_func(module, md->md_exec); + } + + PyModuleDef *def = _PyModule_GetDefOrNull(module); + if (def) { + return PyModule_ExecDef(module, def); + } + return 0; +} + int PyModule_ExecDef(PyObject *module, PyModuleDef *def) { PyModuleDef_Slot *cur_slot; - const char *name; - int ret; - name = PyModule_GetName(module); - if (name == NULL) { + if (alloc_state(module) < 0) { return -1; } - if (def->m_size >= 0) { - PyModuleObject *md = (PyModuleObject*)module; - if (md->md_state == NULL) { - /* Always set a state pointer; this serves as a marker to skip - * multiple initialization (importlib.reload() is no-op) */ - md->md_state = PyMem_Malloc(def->m_size); - if (!md->md_state) { - PyErr_NoMemory(); - return -1; - } - memset(md->md_state, 0, def->m_size); - } - } + assert(PyModule_Check(module)); if (def->m_slots == NULL) { return 0; } for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) { - switch (cur_slot->slot) { - case Py_mod_create: - /* handled in PyModule_FromDefAndSpec2 */ - break; - case Py_mod_exec: - ret = ((int (*)(PyObject *))cur_slot->value)(module); - if (ret != 0) { - if (!PyErr_Occurred()) { - PyErr_Format( - PyExc_SystemError, - "execution of module %s failed without setting an exception", - name); - } - return -1; - } - if (PyErr_Occurred()) { - _PyErr_FormatFromCause( - PyExc_SystemError, - "execution of module %s raised unreported exception", - name); - return -1; - } - break; - case Py_mod_multiple_interpreters: - case Py_mod_gil: - /* handled in PyModule_FromDefAndSpec2 */ - break; - default: - PyErr_Format( - PyExc_SystemError, - "module %s initialized with unknown slot %i", - name, cur_slot->slot); + if (cur_slot->slot == Py_mod_exec) { + int (*func)(PyObject *) = cur_slot->value; + if (run_exec_func(module, func) < 0) { return -1; + } + continue; } } return 0; @@ -565,6 +822,31 @@ PyModule_GetDict(PyObject *m) return _PyModule_GetDict(m); // borrowed reference } +int +PyModule_GetStateSize(PyObject *m, Py_ssize_t *size_p) +{ + *size_p = -1; + if (!PyModule_Check(m)) { + PyErr_Format(PyExc_TypeError, "expected module, got %T", m); + return -1; + } + PyModuleObject *mod = (PyModuleObject *)m; + *size_p = mod->md_state_size; + return 0; +} + +int +PyModule_GetToken(PyObject *m, void **token_p) +{ + *token_p = NULL; + if (!PyModule_Check(m)) { + PyErr_Format(PyExc_TypeError, "expected module, got %T", m); + return -1; + } + *token_p = _PyModule_GetToken(m); + return 0; +} + PyObject* PyModule_GetNameObject(PyObject *mod) { @@ -705,7 +987,7 @@ PyModule_GetDef(PyObject* m) PyErr_BadArgument(); return NULL; } - return _PyModule_GetDef(m); + return _PyModule_GetDefOrNull(m); } void* @@ -829,17 +1111,18 @@ module_dealloc(PyObject *self) } FT_CLEAR_WEAKREFS(self, m->md_weaklist); + assert_def_missing_or_redundant(m); /* bpo-39824: Don't call m_free() if m_size > 0 and md_state=NULL */ - if (m->md_def && m->md_def->m_free - && (m->md_def->m_size <= 0 || m->md_state != NULL)) + if (m->md_state_free && (m->md_state_size <= 0 || m->md_state != NULL)) { - m->md_def->m_free(m); + m->md_state_free(m); } Py_XDECREF(m->md_dict); Py_XDECREF(m->md_name); - if (m->md_state != NULL) + if (m->md_state != NULL) { PyMem_Free(m->md_state); + } Py_TYPE(m)->tp_free((PyObject *)m); } @@ -1147,11 +1430,11 @@ module_traverse(PyObject *self, visitproc visit, void *arg) { PyModuleObject *m = _PyModule_CAST(self); + assert_def_missing_or_redundant(m); /* bpo-39824: Don't call m_traverse() if m_size > 0 and md_state=NULL */ - if (m->md_def && m->md_def->m_traverse - && (m->md_def->m_size <= 0 || m->md_state != NULL)) + if (m->md_state_traverse && (m->md_state_size <= 0 || m->md_state != NULL)) { - int res = m->md_def->m_traverse((PyObject*)m, visit, arg); + int res = m->md_state_traverse((PyObject*)m, visit, arg); if (res) return res; } @@ -1165,18 +1448,19 @@ module_clear(PyObject *self) { PyModuleObject *m = _PyModule_CAST(self); + assert_def_missing_or_redundant(m); /* bpo-39824: Don't call m_clear() if m_size > 0 and md_state=NULL */ - if (m->md_def && m->md_def->m_clear - && (m->md_def->m_size <= 0 || m->md_state != NULL)) + if (m->md_state_clear && (m->md_state_size <= 0 || m->md_state != NULL)) { - int res = m->md_def->m_clear((PyObject*)m); + int res = m->md_state_clear((PyObject*)m); if (PyErr_Occurred()) { PyErr_FormatUnraisable("Exception ignored in m_clear of module%s%V", m->md_name ? " " : "", m->md_name, ""); } - if (res) + if (res) { return res; + } } Py_CLEAR(m->md_dict); return 0; diff --git a/Objects/object.c b/Objects/object.c index fba86e63cd4..4fc692bb029 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -713,7 +713,7 @@ _PyObject_IsFreed(PyObject *op) /* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ void -_PyObject_Dump(PyObject* op) +PyUnstable_Object_Dump(PyObject* op) { if (_PyObject_IsFreed(op)) { /* It seems like the object memory has been freed: @@ -945,6 +945,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) clear_freelist(&freelists->object_stack_chunks, 1, PyMem_RawFree); } clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); + clear_freelist(&freelists->bytes_writers, is_finalization, PyMem_Free); clear_freelist(&freelists->ints, is_finalization, free_object); clear_freelist(&freelists->pycfunctionobject, is_finalization, PyObject_GC_Del); clear_freelist(&freelists->pycmethodobject, is_finalization, PyObject_GC_Del); @@ -1262,7 +1263,10 @@ PyObject * _PyObject_GetAttrId(PyObject *v, _Py_Identifier *name) { PyObject *result; +_Py_COMP_DIAG_PUSH +_Py_COMP_DIAG_IGNORE_DEPR_DECLS PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ +_Py_COMP_DIAG_POP if (!oname) return NULL; result = PyObject_GetAttr(v, oname); @@ -2758,8 +2762,12 @@ PyUnstable_Object_IsUniqueReferencedTemporary(PyObject *op) _PyStackRef *stackpointer = frame->stackpointer; while (stackpointer > base) { stackpointer--; - if (op == PyStackRef_AsPyObjectBorrow(*stackpointer)) { - return PyStackRef_IsHeapSafe(*stackpointer); + _PyStackRef ref = *stackpointer; + if (PyStackRef_IsTaggedInt(ref)) { + continue; + } + if (op == PyStackRef_AsPyObjectBorrow(ref)) { + return PyStackRef_IsHeapSafe(ref); } } return 0; @@ -3050,7 +3058,7 @@ finally: /* Trashcan support. */ -/* Add op to the gcstate->trash_delete_later list. Called when the current +/* Add op to the tstate->delete_later list. Called when the current * call-stack depth gets large. op must be a gc'ed object, with refcount 0. * Py_DECREF must already have been called on it. */ @@ -3076,7 +3084,7 @@ _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op) tstate->delete_later = op; } -/* Deallocate all the objects in the gcstate->trash_delete_later list. +/* Deallocate all the objects in the tstate->delete_later list. * Called when the call-stack unwinds again. */ void _PyTrash_thread_destroy_chain(PyThreadState *tstate) @@ -3149,7 +3157,7 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg, /* This might succeed or fail, but we're about to abort, so at least try to provide any extra info we can: */ - _PyObject_Dump(obj); + PyUnstable_Object_Dump(obj); fprintf(stderr, "\n"); fflush(stderr); @@ -3286,8 +3294,18 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt) int PyRefTracer_SetTracer(PyRefTracer tracer, void *data) { _Py_AssertHoldsTstate(); + + _PyEval_StopTheWorldAll(&_PyRuntime); + if (_PyRuntime.ref_tracer.tracer_func != NULL) { + _PyReftracerTrack(NULL, PyRefTracer_TRACKER_REMOVED); + if (PyErr_Occurred()) { + _PyEval_StartTheWorldAll(&_PyRuntime); + return -1; + } + } _PyRuntime.ref_tracer.tracer_func = tracer; _PyRuntime.ref_tracer.tracer_data = data; + _PyEval_StartTheWorldAll(&_PyRuntime); return 0; } @@ -3350,24 +3368,6 @@ Py_GetConstantBorrowed(unsigned int constant_id) return Py_GetConstant(constant_id); } - -// Py_TYPE() implementation for the stable ABI -#undef Py_TYPE -PyTypeObject* -Py_TYPE(PyObject *ob) -{ - return _Py_TYPE(ob); -} - - -// Py_REFCNT() implementation for the stable ABI -#undef Py_REFCNT -Py_ssize_t -Py_REFCNT(PyObject *ob) -{ - return _Py_REFCNT(ob); -} - int PyUnstable_IsImmortal(PyObject *op) { @@ -3384,3 +3384,26 @@ PyUnstable_Object_IsUniquelyReferenced(PyObject *op) assert(op != NULL); return _PyObject_IsUniquelyReferenced(op); } + +int +_PyObject_VisitType(PyObject *op, visitproc visit, void *arg) +{ + assert(op != NULL); + PyTypeObject *tp = Py_TYPE(op); + _PyObject_ASSERT((PyObject *)tp, PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); + Py_VISIT(tp); + return 0; +} + +// Implementations for the stable ABI +// Keep these at the end. +#undef Py_TYPE +#undef Py_REFCNT +#undef Py_SIZE +#undef Py_IS_TYPE +#undef Py_SET_SIZE +PyTypeObject* Py_TYPE(PyObject *ob) { return _Py_TYPE_impl(ob); } +Py_ssize_t Py_REFCNT(PyObject *ob) { return _Py_REFCNT(ob); } +Py_ssize_t Py_SIZE(PyObject *o) { return _Py_SIZE_impl(o); } +int Py_IS_TYPE(PyObject *o, PyTypeObject *t) { return _Py_IS_TYPE_impl(o, t); } +void Py_SET_SIZE(PyVarObject *o, Py_ssize_t s) { _Py_SET_SIZE_impl(o, s); } diff --git a/Objects/object_layout_312.png b/Objects/object_layout_312.png index a63d095ea0b..9ccb99f9db1 100644 Binary files a/Objects/object_layout_312.png and b/Objects/object_layout_312.png differ diff --git a/Objects/object_layout_313.png b/Objects/object_layout_313.png index f7059c286c8..f3df59253da 100644 Binary files a/Objects/object_layout_313.png and b/Objects/object_layout_313.png differ diff --git a/Objects/object_layout_full_312.png b/Objects/object_layout_full_312.png index 4f46ca86091..8c0aca4e06a 100644 Binary files a/Objects/object_layout_full_312.png and b/Objects/object_layout_full_312.png differ diff --git a/Objects/object_layout_full_313.png b/Objects/object_layout_full_313.png index 7352ec69e5d..2d5c8569f62 100644 Binary files a/Objects/object_layout_full_313.png and b/Objects/object_layout_full_313.png differ diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 2b95ebbf8e5..b1f9fa2e692 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_interp.h" // _PyInterpreterState_HasFeature +#include "pycore_mmap.h" // _PyAnnotateMemoryMap() #include "pycore_object.h" // _PyDebugAllocatorStats() definition #include "pycore_obmalloc.h" #include "pycore_obmalloc_init.h" @@ -467,6 +468,7 @@ _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size) if (ptr == MAP_FAILED) return NULL; assert(ptr != NULL); + _PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc"); return ptr; #else return malloc(size); diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 59a956c6adf..25928028919 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -223,7 +223,6 @@ PyDict_DelItem PyMapping_DelItem PyDict_DelItemString PyMapping_DelItemString PyDict_GetItem - PyDict_GetItemWithError PyObject_GetItem -_PyDict_GetItemIdWithError - PyDict_GetItemString PyMapping_GetItemString PyDict_Items PyMapping_Items PyDict_Keys PyMapping_Keys @@ -536,6 +535,7 @@ struct _odictnode { static Py_ssize_t _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); PyObject *value = NULL; PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys; Py_ssize_t ix; @@ -560,6 +560,7 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash) static int _odict_resize(PyODictObject *od) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); Py_ssize_t size, i; _ODictNode **fast_nodes, *node; @@ -596,6 +597,7 @@ _odict_resize(PyODictObject *od) static Py_ssize_t _odict_get_index(PyODictObject *od, PyObject *key, Py_hash_t hash) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); PyDictKeysObject *keys; assert(key != NULL); @@ -616,6 +618,7 @@ _odict_get_index(PyODictObject *od, PyObject *key, Py_hash_t hash) static _ODictNode * _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); Py_ssize_t index; if (_odict_EMPTY(od)) @@ -630,6 +633,7 @@ _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash) static _ODictNode * _odict_find_node(PyODictObject *od, PyObject *key) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); Py_ssize_t index; Py_hash_t hash; @@ -648,6 +652,7 @@ _odict_find_node(PyODictObject *od, PyObject *key) static void _odict_add_head(PyODictObject *od, _ODictNode *node) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); _odictnode_PREV(node) = NULL; _odictnode_NEXT(node) = _odict_FIRST(od); if (_odict_FIRST(od) == NULL) @@ -661,6 +666,7 @@ _odict_add_head(PyODictObject *od, _ODictNode *node) static void _odict_add_tail(PyODictObject *od, _ODictNode *node) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); _odictnode_PREV(node) = _odict_LAST(od); _odictnode_NEXT(node) = NULL; if (_odict_LAST(od) == NULL) @@ -675,6 +681,7 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node) static int _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); Py_ssize_t i; _ODictNode *node; @@ -719,6 +726,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash) static void _odict_remove_node(PyODictObject *od, _ODictNode *node) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); if (_odict_FIRST(od) == node) _odict_FIRST(od) = _odictnode_NEXT(node); else if (_odictnode_PREV(node) != NULL) @@ -754,6 +762,7 @@ static int _odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key, Py_hash_t hash) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); Py_ssize_t i; assert(key != NULL); @@ -952,31 +961,34 @@ OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value) return _PyDict_FromKeys((PyObject *)type, seq, value); } -/* __sizeof__() */ +/*[clinic input] +@critical_section +OrderedDict.__sizeof__ -> Py_ssize_t +[clinic start generated code]*/ -/* OrderedDict.__sizeof__() does not have a docstring. */ -PyDoc_STRVAR(odict_sizeof__doc__, ""); - -static PyObject * -odict_sizeof(PyObject *op, PyObject *Py_UNUSED(ignored)) +static Py_ssize_t +OrderedDict___sizeof___impl(PyODictObject *self) +/*[clinic end generated code: output=1a8560db8cf83ac5 input=655e989ae24daa6a]*/ { - PyODictObject *od = _PyODictObject_CAST(op); - Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od); - res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */ - if (!_odict_EMPTY(od)) { - res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */ + Py_ssize_t res = _PyDict_SizeOf_LockHeld((PyDictObject *)self); + res += sizeof(_ODictNode *) * self->od_fast_nodes_size; /* od_fast_nodes */ + if (!_odict_EMPTY(self)) { + res += sizeof(_ODictNode) * PyODict_SIZE(self); /* linked-list */ } - return PyLong_FromSsize_t(res); + return res; } -/* __reduce__() */ +/*[clinic input] +OrderedDict.__reduce__ + self as od: self(type="PyODictObject *") -PyDoc_STRVAR(odict_reduce__doc__, "Return state information for pickling"); +Return state information for pickling +[clinic start generated code]*/ static PyObject * -odict_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) +OrderedDict___reduce___impl(PyODictObject *od) +/*[clinic end generated code: output=71eeb81f760a6a8e input=b0467c7ec400fe5e]*/ { - register PyODictObject *od = _PyODictObject_CAST(op); PyObject *state, *result = NULL; PyObject *items_iter, *items, *args = NULL; @@ -1011,8 +1023,10 @@ Done: /* setdefault(): Skips __missing__() calls. */ +static int PyODict_SetItem_LockHeld(PyObject *self, PyObject *key, PyObject *value); /*[clinic input] +@critical_section OrderedDict.setdefault key: object @@ -1026,7 +1040,7 @@ Return the value for key if key is in the dictionary, else default. static PyObject * OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=97537cb7c28464b6 input=38e098381c1efbc6]*/ +/*[clinic end generated code: output=97537cb7c28464b6 input=d7b93e92734f99b5]*/ { PyObject *result = NULL; @@ -1036,7 +1050,7 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, if (PyErr_Occurred()) return NULL; assert(_odict_find_node(self, key) == NULL); - if (PyODict_SetItem((PyObject *)self, key, default_value) >= 0) { + if (PyODict_SetItem_LockHeld((PyObject *)self, key, default_value) >= 0) { result = Py_NewRef(default_value); } } @@ -1066,10 +1080,9 @@ static PyObject * _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj, Py_hash_t hash) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); + PyObject *value = NULL; - - Py_BEGIN_CRITICAL_SECTION(od); - _ODictNode *node = _odict_find_node_hash(_PyODictObject_CAST(od), key, hash); if (node != NULL) { /* Pop the node first to avoid a possible dict resize (due to @@ -1094,7 +1107,6 @@ _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj, PyErr_SetObject(PyExc_KeyError, key); } } - Py_END_CRITICAL_SECTION(); done: return value; @@ -1102,6 +1114,7 @@ done: /* Skips __missing__() calls. */ /*[clinic input] +@critical_section @permit_long_summary OrderedDict.pop @@ -1117,7 +1130,7 @@ raise a KeyError. static PyObject * OrderedDict_pop_impl(PyODictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=7a6447d104e7494b input=eebd40ac51666d33]*/ +/*[clinic end generated code: output=7a6447d104e7494b input=0742e3c9bf076a72]*/ { Py_hash_t hash = PyObject_Hash(key); if (hash == -1) @@ -1129,6 +1142,7 @@ OrderedDict_pop_impl(PyODictObject *self, PyObject *key, /* popitem() */ /*[clinic input] +@critical_section OrderedDict.popitem last: bool = True @@ -1140,7 +1154,7 @@ Pairs are returned in LIFO order if last is true or FIFO order if false. static PyObject * OrderedDict_popitem_impl(PyODictObject *self, int last) -/*[clinic end generated code: output=98e7d986690d49eb input=d992ac5ee8305e1a]*/ +/*[clinic end generated code: output=98e7d986690d49eb input=8aafc7433e0a40e7]*/ { PyObject *key, *value, *item = NULL; _ODictNode *node; @@ -1169,6 +1183,9 @@ OrderedDict_popitem_impl(PyODictObject *self, int last) PyDoc_STRVAR(odict_keys__doc__, ""); static PyObject * odictkeys_new(PyObject *od, PyObject *Py_UNUSED(ignored)); /* forward */ +static int +_PyODict_SetItem_KnownHash_LockHeld(PyObject *od, PyObject *key, PyObject *value, + Py_hash_t hash); /* forward */ /* values() */ @@ -1194,32 +1211,36 @@ static PyObject * mutablemapping_update(PyObject *, PyObject *, PyObject *); #define odict_update mutablemapping_update -/* clear() */ +/*[clinic input] +@critical_section +OrderedDict.clear -PyDoc_STRVAR(odict_clear__doc__, - "od.clear() -> None. Remove all items from od."); +Remove all items from ordered dict. +[clinic start generated code]*/ static PyObject * -odict_clear(PyObject *op, PyObject *Py_UNUSED(ignored)) +OrderedDict_clear_impl(PyODictObject *self) +/*[clinic end generated code: output=a1a76d1322f556c5 input=08b12322e74c535c]*/ { - register PyODictObject *od = _PyODictObject_CAST(op); - PyDict_Clear(op); - _odict_clear_nodes(od); + _PyDict_Clear_LockHeld((PyObject *)self); + _odict_clear_nodes(self); Py_RETURN_NONE; } /* copy() */ -/* forward */ -static int _PyODict_SetItem_KnownHash(PyObject *, PyObject *, PyObject *, - Py_hash_t); +/*[clinic input] +@critical_section +OrderedDict.copy + self as od: self -PyDoc_STRVAR(odict_copy__doc__, "od.copy() -> a shallow copy of od"); +A shallow copy of ordered dict. +[clinic start generated code]*/ static PyObject * -odict_copy(PyObject *op, PyObject *Py_UNUSED(ignored)) +OrderedDict_copy_impl(PyObject *od) +/*[clinic end generated code: output=9cdbe7394aecc576 input=e329951ae617ed48]*/ { - register PyODictObject *od = _PyODictObject_CAST(op); _ODictNode *node; PyObject *od_copy; @@ -1239,8 +1260,8 @@ odict_copy(PyObject *op, PyObject *Py_UNUSED(ignored)) PyErr_SetObject(PyExc_KeyError, key); goto fail; } - if (_PyODict_SetItem_KnownHash((PyObject *)od_copy, key, value, - _odictnode_HASH(node)) != 0) + if (_PyODict_SetItem_KnownHash_LockHeld((PyObject *)od_copy, key, value, + _odictnode_HASH(node)) != 0) goto fail; } } @@ -1288,6 +1309,7 @@ odict_reversed(PyObject *op, PyObject *Py_UNUSED(ignored)) /* move_to_end() */ /*[clinic input] +@critical_section OrderedDict.move_to_end key: object @@ -1300,7 +1322,7 @@ Raise KeyError if the element does not exist. static PyObject * OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last) -/*[clinic end generated code: output=fafa4c5cc9b92f20 input=d6ceff7132a2fcd7]*/ +/*[clinic end generated code: output=fafa4c5cc9b92f20 input=09f8bc7053c0f6d4]*/ { _ODictNode *node; @@ -1341,10 +1363,8 @@ static PyMethodDef odict_methods[] = { /* overridden dict methods */ ORDEREDDICT_FROMKEYS_METHODDEF - {"__sizeof__", odict_sizeof, METH_NOARGS, - odict_sizeof__doc__}, - {"__reduce__", odict_reduce, METH_NOARGS, - odict_reduce__doc__}, + ORDEREDDICT___SIZEOF___METHODDEF + ORDEREDDICT___REDUCE___METHODDEF ORDEREDDICT_SETDEFAULT_METHODDEF ORDEREDDICT_POP_METHODDEF ORDEREDDICT_POPITEM_METHODDEF @@ -1356,11 +1376,8 @@ static PyMethodDef odict_methods[] = { odict_items__doc__}, {"update", _PyCFunction_CAST(odict_update), METH_VARARGS | METH_KEYWORDS, odict_update__doc__}, - {"clear", odict_clear, METH_NOARGS, - odict_clear__doc__}, - {"copy", odict_copy, METH_NOARGS, - odict_copy__doc__}, - + ORDEREDDICT_CLEAR_METHODDEF + ORDEREDDICT_COPY_METHODDEF /* new methods */ {"__reversed__", odict_reversed, METH_NOARGS, odict_reversed__doc__}, @@ -1459,7 +1476,8 @@ odict_tp_clear(PyObject *op) { PyODictObject *od = _PyODictObject_CAST(op); Py_CLEAR(od->od_inst_dict); - PyDict_Clear((PyObject *)od); + // cannot use lock held variant as critical section is not held here + PyDict_Clear(op); _odict_clear_nodes(od); return 0; } @@ -1467,7 +1485,7 @@ odict_tp_clear(PyObject *op) /* tp_richcompare */ static PyObject * -odict_richcompare(PyObject *v, PyObject *w, int op) +odict_richcompare_lock_held(PyObject *v, PyObject *w, int op) { if (!PyODict_Check(v) || !PyDict_Check(w)) { Py_RETURN_NOTIMPLEMENTED; @@ -1500,6 +1518,16 @@ odict_richcompare(PyObject *v, PyObject *w, int op) } } +static PyObject * +odict_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + Py_BEGIN_CRITICAL_SECTION2(v, w); + res = odict_richcompare_lock_held(v, w, op); + Py_END_CRITICAL_SECTION2(); + return res; +} + /* tp_iter */ static PyObject * @@ -1519,7 +1547,7 @@ odict_init(PyObject *self, PyObject *args, PyObject *kwds) if (len == -1) return -1; if (len > 1) { - const char *msg = "expected at most 1 arguments, got %zd"; + const char *msg = "expected at most 1 argument, got %zd"; PyErr_Format(PyExc_TypeError, msg, len); return -1; } @@ -1590,10 +1618,11 @@ PyODict_New(void) } static int -_PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value, - Py_hash_t hash) +_PyODict_SetItem_KnownHash_LockHeld(PyObject *od, PyObject *key, PyObject *value, + Py_hash_t hash) { - int res = _PyDict_SetItem_KnownHash(od, key, value, hash); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); + int res = _PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)od, key, value, hash); if (res == 0) { res = _odict_add_new_node(_PyODictObject_CAST(od), key, hash); if (res < 0) { @@ -1606,18 +1635,32 @@ _PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value, return res; } -int -PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value) + +static int +PyODict_SetItem_LockHeld(PyObject *od, PyObject *key, PyObject *value) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); Py_hash_t hash = PyObject_Hash(key); - if (hash == -1) + if (hash == -1) { return -1; - return _PyODict_SetItem_KnownHash(od, key, value, hash); + } + return _PyODict_SetItem_KnownHash_LockHeld(od, key, value, hash); } int -PyODict_DelItem(PyObject *od, PyObject *key) +PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value) { + int res; + Py_BEGIN_CRITICAL_SECTION(od); + res = PyODict_SetItem_LockHeld(od, key, value); + Py_END_CRITICAL_SECTION(); + return res; +} + +int +PyODict_DelItem_LockHeld(PyObject *od, PyObject *key) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od); int res; Py_hash_t hash = PyObject_Hash(key); if (hash == -1) @@ -1625,9 +1668,18 @@ PyODict_DelItem(PyObject *od, PyObject *key) res = _odict_clear_node(_PyODictObject_CAST(od), NULL, key, hash); if (res < 0) return -1; - return _PyDict_DelItem_KnownHash(od, key, hash); + return _PyDict_DelItem_KnownHash_LockHeld(od, key, hash); } +int +PyODict_DelItem(PyObject *od, PyObject *key) +{ + int res; + Py_BEGIN_CRITICAL_SECTION(od); + res = PyODict_DelItem_LockHeld(od, key); + Py_END_CRITICAL_SECTION(); + return res; +} /* ------------------------------------------- * The OrderedDict views (keys/values/items) @@ -1669,14 +1721,14 @@ odictiter_traverse(PyObject *op, visitproc visit, void *arg) /* In order to protect against modifications during iteration, we track * the current key instead of the current node. */ static PyObject * -odictiter_nextkey(odictiterobject *di) +odictiter_nextkey_lock_held(odictiterobject *di) { + assert(di->di_odict != NULL); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(di->di_odict); PyObject *key = NULL; _ODictNode *node; int reversed = di->kind & _odict_ITER_REVERSED; - if (di->di_odict == NULL) - return NULL; if (di->di_current == NULL) goto done; /* We're already done. */ @@ -1721,8 +1773,23 @@ done: return key; } + static PyObject * -odictiter_iternext(PyObject *op) +odictiter_nextkey(odictiterobject *di) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(di); + if (di->di_odict == NULL) { + return NULL; + } + PyObject *res; + Py_BEGIN_CRITICAL_SECTION(di->di_odict); + res = odictiter_nextkey_lock_held(di); + Py_END_CRITICAL_SECTION(); + return res; +} + +static PyObject * +odictiter_iternext_lock_held(PyObject *op) { odictiterobject *di = (odictiterobject*)op; PyObject *result, *value; @@ -1736,14 +1803,12 @@ odictiter_iternext(PyObject *op) return key; } - value = PyODict_GetItem((PyObject *)di->di_odict, key); /* borrowed */ - if (value == NULL) { + if (PyDict_GetItemRef((PyObject *)di->di_odict, key, &value) != 1) { if (!PyErr_Occurred()) PyErr_SetObject(PyExc_KeyError, key); Py_DECREF(key); goto done; } - Py_INCREF(value); /* Handle the values case. */ if (!(di->kind & _odict_ITER_KEYS)) { @@ -1754,7 +1819,7 @@ odictiter_iternext(PyObject *op) /* Handle the items case. */ result = di->di_result; - if (Py_REFCNT(result) == 1) { + if (_PyObject_IsUniquelyReferenced(result)) { /* not in use so we can reuse it * (the common case during iteration) */ Py_INCREF(result); @@ -1783,6 +1848,17 @@ done: return NULL; } +static PyObject * +odictiter_iternext(PyObject *op) +{ + PyObject *res; + Py_BEGIN_CRITICAL_SECTION(op); + res = odictiter_iternext_lock_held(op); + Py_END_CRITICAL_SECTION(); + return res; +} + + /* No need for tp_clear because odictiterobject is not mutable. */ PyDoc_STRVAR(reduce_doc, "Return state information for pickling"); diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index f8cdfe68a64..e93346fb277 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -1042,6 +1042,11 @@ longrangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) static PyObject * longrangeiter_setstate(PyObject *op, PyObject *state) { + if (!PyLong_CheckExact(state)) { + PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state); + return NULL; + } + longrangeiterobject *r = (longrangeiterobject*)op; PyObject *zero = _PyLong_GetZero(); // borrowed reference int cmp; diff --git a/Objects/setobject.c b/Objects/setobject.c index 63ce55e2365..5f868c85827 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -63,6 +63,148 @@ static PyObject _dummy_struct; #define dummy (&_dummy_struct) +#define SET_LOOKKEY_FOUND 1 +#define SET_LOOKKEY_NO_MATCH 0 +#define SET_LOOKKEY_ERROR (-1) +#define SET_LOOKKEY_CHANGED (-2) +#define SET_LOOKKEY_EMPTY (-3) + +typedef int (*compare_func)(PySetObject *so, setentry *table, setentry *ep, + PyObject *key, Py_hash_t hash); + +#ifdef Py_GIL_DISABLED + +#define SET_IS_SHARED(so) _PyObject_GC_IS_SHARED(so) +#define SET_MARK_SHARED(so) _PyObject_GC_SET_SHARED(so) + +static void +ensure_shared_on_read(PySetObject *so) +{ + if (!_Py_IsOwnedByCurrentThread((PyObject *)so) && !SET_IS_SHARED(so)) { + // The first time we access a set from a non-owning thread we mark it + // as shared. This ensures that a concurrent resize operation will + // delay freeing the old entries using QSBR, which is necessary + // to safely allow concurrent reads without locking... + Py_BEGIN_CRITICAL_SECTION(so); + if (!SET_IS_SHARED(so)) { + SET_MARK_SHARED(so); + } + Py_END_CRITICAL_SECTION(); + } +} + +static inline Py_ALWAYS_INLINE int +set_compare_threadsafe(PySetObject *so, setentry *table, setentry *ep, + PyObject *key, Py_hash_t hash) +{ + PyObject *startkey = FT_ATOMIC_LOAD_PTR_ACQUIRE(ep->key); + if (startkey == NULL) { + return SET_LOOKKEY_EMPTY; + } + if (startkey == key) { + return SET_LOOKKEY_FOUND; + } + Py_ssize_t ep_hash = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(ep->hash); + if (ep_hash == hash) { + if (!_Py_TryIncrefCompare(&ep->key, startkey)) { + return SET_LOOKKEY_CHANGED; + } + int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + Py_DECREF(startkey); + if (cmp < 0) { + return SET_LOOKKEY_ERROR; + } + if (table == FT_ATOMIC_LOAD_PTR_ACQUIRE(so->table) && + startkey == FT_ATOMIC_LOAD_PTR_ACQUIRE(ep->key)) { + assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH); + return cmp; + } + else { + /* The set was mutated, restart */ + return SET_LOOKKEY_CHANGED; + } + } + return SET_LOOKKEY_NO_MATCH; +} + +#else + +#define SET_IS_SHARED(so) 0 +#define SET_MARK_SHARED(so) + +#endif + +static inline Py_ALWAYS_INLINE int +set_compare_entry_lock_held(PySetObject *so, setentry *table, setentry *entry, + PyObject *key, Py_hash_t hash) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so); + if (entry->hash == 0 && entry->key == NULL) + return SET_LOOKKEY_EMPTY; + if (entry->hash == hash) { + PyObject *startkey = entry->key; + assert(startkey != dummy); + if (startkey == key) + return SET_LOOKKEY_FOUND; + if (PyUnicode_CheckExact(startkey) + && PyUnicode_CheckExact(key) + && unicode_eq(startkey, key)) + return SET_LOOKKEY_FOUND; + table = so->table; + Py_INCREF(startkey); + int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + Py_DECREF(startkey); + if (cmp < 0) + return SET_LOOKKEY_ERROR; + if (table != so->table || entry->key != startkey) + return SET_LOOKKEY_CHANGED; + if (cmp > 0) + return SET_LOOKKEY_FOUND; + } + return SET_LOOKKEY_NO_MATCH; +} + +// This is similar to set_compare_entry_lock_held() but we don't need to +// incref startkey before comparing and we don't need to check if the set has +// changed. This also omits the PyUnicode_CheckExact() special case since it +// doesn't help much for frozensets. +static inline Py_ALWAYS_INLINE int +set_compare_frozenset(PySetObject *so, setentry *table, setentry *ep, + PyObject *key, Py_hash_t hash) +{ + assert(PyFrozenSet_Check(so)); + PyObject *startkey = ep->key; + if (startkey == NULL) { + return SET_LOOKKEY_EMPTY; + } + if (startkey == key) { + return SET_LOOKKEY_FOUND; + } + Py_ssize_t ep_hash = ep->hash; + if (ep_hash == hash) { + int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + if (cmp < 0) { + return SET_LOOKKEY_ERROR; + } + assert(cmp == SET_LOOKKEY_FOUND || cmp == SET_LOOKKEY_NO_MATCH); + return cmp; + } + return SET_LOOKKEY_NO_MATCH; +} + +static void +set_zero_table(setentry *table, size_t size) +{ +#ifdef Py_GIL_DISABLED + for (size_t i = 0; i < size; i++) { + setentry *entry = &table[i]; + FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, 0); + FT_ATOMIC_STORE_PTR_RELEASE(entry->key, NULL); + } +#else + memset(table, 0, sizeof(setentry)*size); +#endif +} /* ======================================================================== */ /* ======= Begin logic for probing the hash table ========================= */ @@ -75,49 +217,34 @@ static PyObject _dummy_struct; /* This must be >= 1 */ #define PERTURB_SHIFT 5 -static setentry * -set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) +static int +set_do_lookup(PySetObject *so, setentry *table, size_t mask, PyObject *key, + Py_hash_t hash, setentry **epp, compare_func compare_entry) { - setentry *table; setentry *entry; size_t perturb = hash; - size_t mask = so->mask; size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */ int probes; - int cmp; + int status; while (1) { - entry = &so->table[i]; + entry = &table[i]; probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0; do { - if (entry->hash == 0 && entry->key == NULL) - return entry; - if (entry->hash == hash) { - PyObject *startkey = entry->key; - assert(startkey != dummy); - if (startkey == key) - return entry; - if (PyUnicode_CheckExact(startkey) - && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) - return entry; - table = so->table; - Py_INCREF(startkey); - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - Py_DECREF(startkey); - if (cmp < 0) - return NULL; - if (table != so->table || entry->key != startkey) - return set_lookkey(so, key, hash); - if (cmp > 0) - return entry; - mask = so->mask; + status = compare_entry(so, table, entry, key, hash); + if (status != SET_LOOKKEY_NO_MATCH) { + if (status == SET_LOOKKEY_EMPTY) { + return SET_LOOKKEY_NO_MATCH; + } + *epp = entry; + return status; } entry++; } while (probes--); perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; } + Py_UNREACHABLE(); } static int set_table_resize(PySetObject *, Py_ssize_t); @@ -182,15 +309,15 @@ set_add_entry_takeref(PySetObject *so, PyObject *key, Py_hash_t hash) if (freeslot == NULL) goto found_unused; FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1); - freeslot->key = key; - freeslot->hash = hash; + FT_ATOMIC_STORE_SSIZE_RELAXED(freeslot->hash, hash); + FT_ATOMIC_STORE_PTR_RELEASE(freeslot->key, key); return 0; found_unused: so->fill++; FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1); - entry->key = key; - entry->hash = hash; + FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash); + FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key); if ((size_t)so->fill*5 < mask*3) return 0; return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); @@ -273,13 +400,78 @@ set_insert_clean(setentry *table, size_t mask, PyObject *key, Py_hash_t hash) i = (i * 5 + 1 + perturb) & mask; } found_null: - entry->key = key; - entry->hash = hash; + FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, hash); + FT_ATOMIC_STORE_PTR_RELEASE(entry->key, key); } /* ======== End logic for probing the hash table ========================== */ /* ======================================================================== */ +static int +set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash, setentry **epp) +{ + int status; + if (PyFrozenSet_CheckExact(so)) { + status = set_do_lookup(so, so->table, so->mask, key, hash, epp, + set_compare_frozenset); + } + else { + Py_BEGIN_CRITICAL_SECTION(so); + do { + status = set_do_lookup(so, so->table, so->mask, key, hash, epp, + set_compare_entry_lock_held); + } while (status == SET_LOOKKEY_CHANGED); + Py_END_CRITICAL_SECTION(); + } + assert(status == SET_LOOKKEY_FOUND || + status == SET_LOOKKEY_NO_MATCH || + status == SET_LOOKKEY_ERROR); + return status; +} + +#ifdef Py_GIL_DISABLED +static int +set_lookkey_threadsafe(PySetObject *so, PyObject *key, Py_hash_t hash) +{ + int status; + setentry *entry; + if (PyFrozenSet_CheckExact(so)) { + status = set_do_lookup(so, so->table, so->mask, key, hash, &entry, + set_compare_frozenset); + assert(status == SET_LOOKKEY_FOUND || + status == SET_LOOKKEY_NO_MATCH || + status == SET_LOOKKEY_ERROR); + return status; + } + ensure_shared_on_read(so); + setentry *table = FT_ATOMIC_LOAD_PTR_ACQUIRE(so->table); + size_t mask = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->mask); + if (table == NULL || table != FT_ATOMIC_LOAD_PTR_ACQUIRE(so->table)) { + return set_lookkey(so, key, hash, &entry); + } + status = set_do_lookup(so, table, mask, key, hash, &entry, + set_compare_threadsafe); + if (status == SET_LOOKKEY_CHANGED) { + return set_lookkey(so, key, hash, &entry); + } + assert(status == SET_LOOKKEY_FOUND || + status == SET_LOOKKEY_NO_MATCH || + status == SET_LOOKKEY_ERROR); + return status; +} +#endif + +static void free_entries(setentry *entries, size_t size, bool use_qsbr) +{ +#ifdef Py_GIL_DISABLED + if (use_qsbr) { + _PyMem_FreeDelayed(entries, size * sizeof(setentry)); + return; + } +#endif + PyMem_Free(entries); +} + /* Restructure the table by allocating a new table and reinserting all keys again. When entries have been deleted, the new table may @@ -290,6 +482,7 @@ set_table_resize(PySetObject *so, Py_ssize_t minused) { setentry *oldtable, *newtable, *entry; Py_ssize_t oldmask = so->mask; + Py_ssize_t oldsize = (size_t)oldmask + 1; size_t newmask; int is_oldtable_malloced; setentry small_copy[PySet_MINSIZE]; @@ -337,9 +530,9 @@ set_table_resize(PySetObject *so, Py_ssize_t minused) /* Make the set empty, using the new table. */ assert(newtable != oldtable); - memset(newtable, 0, sizeof(setentry) * newsize); - so->mask = newsize - 1; - so->table = newtable; + set_zero_table(newtable, newsize); + FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL); + FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, newsize - 1); /* Copy the data over; this is refcount-neutral for active entries; dummy entries aren't copied over, of course */ @@ -359,20 +552,22 @@ set_table_resize(PySetObject *so, Py_ssize_t minused) } } + FT_ATOMIC_STORE_PTR_RELEASE(so->table, newtable); + if (is_oldtable_malloced) - PyMem_Free(oldtable); + free_entries(oldtable, oldsize, SET_IS_SHARED(so)); return 0; } static int set_contains_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { - setentry *entry; - - entry = set_lookkey(so, key, hash); - if (entry != NULL) - return entry->key != NULL; - return -1; +#ifdef Py_GIL_DISABLED + return set_lookkey_threadsafe(so, key, hash); +#else + setentry *entry; // unused + return set_lookkey(so, key, hash, &entry); +#endif } #define DISCARD_NOTFOUND 0 @@ -383,16 +578,18 @@ set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *entry; PyObject *old_key; - - entry = set_lookkey(so, key, hash); - if (entry == NULL) + int status = set_lookkey(so, key, hash, &entry); + if (status < 0) { return -1; - if (entry->key == NULL) + } + if (status == SET_LOOKKEY_NO_MATCH) { return DISCARD_NOTFOUND; + } + assert(status == SET_LOOKKEY_FOUND); old_key = entry->key; - entry->key = dummy; - entry->hash = -1; + FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1); FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1); + FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy); Py_DECREF(old_key); return DISCARD_FOUND; } @@ -433,12 +630,13 @@ set_discard_key(PySetObject *so, PyObject *key) static void set_empty_to_minsize(PySetObject *so) { - memset(so->smalltable, 0, sizeof(so->smalltable)); + FT_ATOMIC_STORE_PTR_RELEASE(so->table, NULL); + set_zero_table(so->smalltable, PySet_MINSIZE); so->fill = 0; FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, 0); - so->mask = PySet_MINSIZE - 1; - so->table = so->smalltable; + FT_ATOMIC_STORE_SSIZE_RELEASE(so->mask, PySet_MINSIZE - 1); FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, -1); + FT_ATOMIC_STORE_PTR_RELEASE(so->table, so->smalltable); } static int @@ -449,6 +647,7 @@ set_clear_internal(PyObject *self) setentry *table = so->table; Py_ssize_t fill = so->fill; Py_ssize_t used = so->used; + Py_ssize_t oldsize = (size_t)so->mask + 1; int table_is_malloced = table != so->smalltable; setentry small_copy[PySet_MINSIZE]; @@ -487,7 +686,7 @@ set_clear_internal(PyObject *self) } if (table_is_malloced) - PyMem_Free(table); + free_entries(table, oldsize, SET_IS_SHARED(so)); return 0; } @@ -534,6 +733,7 @@ set_dealloc(PyObject *self) PySetObject *so = _PySet_CAST(self); setentry *entry; Py_ssize_t used = so->used; + Py_ssize_t oldsize = (size_t)so->mask + 1; /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(so); @@ -546,7 +746,7 @@ set_dealloc(PyObject *self) } } if (so->table != so->smalltable) - PyMem_Free(so->table); + free_entries(so->table, oldsize, SET_IS_SHARED(so)); Py_TYPE(so)->tp_free(so); } @@ -657,8 +857,8 @@ set_merge_lock_held(PySetObject *so, PyObject *otherset) key = other_entry->key; if (key != NULL) { assert(so_entry->key == NULL); - so_entry->key = Py_NewRef(key); - so_entry->hash = other_entry->hash; + FT_ATOMIC_STORE_SSIZE_RELAXED(so_entry->hash, other_entry->hash); + FT_ATOMIC_STORE_PTR_RELEASE(so_entry->key, Py_NewRef(key)); } } so->fill = other->fill; @@ -722,10 +922,10 @@ set_pop_impl(PySetObject *so) if (entry > limit) entry = so->table; } - key = entry->key; - entry->key = dummy; - entry->hash = -1; + FT_ATOMIC_STORE_SSIZE_RELAXED(entry->hash, -1); FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used - 1); + key = entry->key; + FT_ATOMIC_STORE_PTR_RELEASE(entry->key, dummy); so->finger = entry - so->table + 1; /* next place to start */ return key; } @@ -812,11 +1012,11 @@ frozenset_hash(PyObject *self) Py_uhash_t hash; if (FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash) != -1) { - return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash); + return FT_ATOMIC_LOAD_SSIZE_ACQUIRE(so->hash); } hash = frozenset_hash_impl(self); - FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, hash); + FT_ATOMIC_STORE_SSIZE_RELEASE(so->hash, hash); return hash; } @@ -898,8 +1098,8 @@ static PyObject *setiter_iternext(PyObject *self) return NULL; assert (PyAnySet_Check(so)); - Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE(so->used); - Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE(si->si_used); + Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used); + Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_used); if (si_used != so_used) { PyErr_SetString(PyExc_RuntimeError, "Set changed size during iteration"); @@ -1239,21 +1439,28 @@ set_swap_bodies(PySetObject *a, PySetObject *b) setentry tab[PySet_MINSIZE]; Py_hash_t h; + setentry *a_table = a->table; + setentry *b_table = b->table; + FT_ATOMIC_STORE_PTR_RELEASE(a->table, NULL); + FT_ATOMIC_STORE_PTR_RELEASE(b->table, NULL); + t = a->fill; a->fill = b->fill; b->fill = t; t = a->used; FT_ATOMIC_STORE_SSIZE_RELAXED(a->used, b->used); FT_ATOMIC_STORE_SSIZE_RELAXED(b->used, t); - t = a->mask; a->mask = b->mask; b->mask = t; + t = a->mask; + FT_ATOMIC_STORE_SSIZE_RELEASE(a->mask, b->mask); + FT_ATOMIC_STORE_SSIZE_RELEASE(b->mask, t); - u = a->table; - if (a->table == a->smalltable) + u = a_table; + if (a_table == a->smalltable) u = b->smalltable; - a->table = b->table; - if (b->table == b->smalltable) - a->table = a->smalltable; - b->table = u; + a_table = b_table; + if (b_table == b->smalltable) + a_table = a->smalltable; + b_table = u; - if (a->table == a->smalltable || b->table == b->smalltable) { + if (a_table == a->smalltable || b_table == b->smalltable) { memcpy(tab, a->smalltable, sizeof(tab)); memcpy(a->smalltable, b->smalltable, sizeof(tab)); memcpy(b->smalltable, tab, sizeof(tab)); @@ -1268,6 +1475,14 @@ set_swap_bodies(PySetObject *a, PySetObject *b) FT_ATOMIC_STORE_SSIZE_RELAXED(a->hash, -1); FT_ATOMIC_STORE_SSIZE_RELAXED(b->hash, -1); } + if (!SET_IS_SHARED(b) && SET_IS_SHARED(a)) { + SET_MARK_SHARED(b); + } + if (!SET_IS_SHARED(a) && SET_IS_SHARED(b)) { + SET_MARK_SHARED(a); + } + FT_ATOMIC_STORE_PTR_RELEASE(a->table, a_table); + FT_ATOMIC_STORE_PTR_RELEASE(b->table, b_table); } /*[clinic input] @@ -2213,33 +2428,26 @@ set_add_impl(PySetObject *so, PyObject *key) Py_RETURN_NONE; } -static int -set_contains_lock_held(PySetObject *so, PyObject *key) -{ - int rv; - - rv = set_contains_key(so, key); - if (rv < 0) { - if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) - return -1; - PyErr_Clear(); - Py_hash_t hash; - Py_BEGIN_CRITICAL_SECTION(key); - hash = frozenset_hash_impl(key); - Py_END_CRITICAL_SECTION(); - rv = set_contains_entry(so, key, hash); - } - return rv; -} - int _PySet_Contains(PySetObject *so, PyObject *key) { - int rv; - Py_BEGIN_CRITICAL_SECTION(so); - rv = set_contains_lock_held(so, key); - Py_END_CRITICAL_SECTION(); - return rv; + assert(so); + + Py_hash_t hash = _PyObject_HashFast(key); + if (hash == -1) { + if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) { + set_unhashable_type(key); + return -1; + } + PyErr_Clear(); + // Note that 'key' could be a set() or frozenset() object. Unlike most + // container types, set allows membership testing with a set key, even + // though it is not hashable. + Py_BEGIN_CRITICAL_SECTION(key); + hash = frozenset_hash_impl(key); + Py_END_CRITICAL_SECTION(); + } + return set_contains_entry(so, key, hash); } static int @@ -2250,7 +2458,6 @@ set_contains(PyObject *self, PyObject *key) } /*[clinic input] -@critical_section @coexist set.__contains__ so: setobject @@ -2262,11 +2469,11 @@ x.__contains__(y) <==> y in x. static PyObject * set___contains___impl(PySetObject *so, PyObject *key) -/*[clinic end generated code: output=b44863d034b3c70e input=4a7d568459617f24]*/ +/*[clinic end generated code: output=b44863d034b3c70e input=cf4c72db704e4cf0]*/ { long result; - result = set_contains_lock_held(so, key); + result = _PySet_Contains(so, key); if (result < 0) return NULL; return PyBool_FromLong(result); @@ -2286,12 +2493,23 @@ static PyObject * frozenset___contains___impl(PySetObject *so, PyObject *key) /*[clinic end generated code: output=2301ed91bc3a6dd5 input=2f04922a98d8bab7]*/ { - long result; - - result = set_contains_lock_held(so, key); - if (result < 0) + Py_hash_t hash = _PyObject_HashFast(key); + if (hash == -1) { + if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) { + set_unhashable_type(key); + return NULL; + } + PyErr_Clear(); + Py_BEGIN_CRITICAL_SECTION(key); + hash = frozenset_hash_impl(key); + Py_END_CRITICAL_SECTION(); + } + setentry *entry; // unused + int status = set_do_lookup(so, so->table, so->mask, key, hash, &entry, + set_compare_frozenset); + if (status < 0) return NULL; - return PyBool_FromLong(result); + return PyBool_FromLong(status); } /*[clinic input] @@ -2429,7 +2647,7 @@ set_init(PyObject *so, PyObject *args, PyObject *kwds) if (!PyArg_UnpackTuple(args, Py_TYPE(self)->tp_name, 0, 1, &iterable)) return -1; - if (Py_REFCNT(self) == 1 && self->fill == 0) { + if (_PyObject_IsUniquelyReferenced((PyObject *)self) && self->fill == 0) { self->hash = -1; if (iterable == NULL) { return 0; @@ -2732,7 +2950,9 @@ PySet_Contains(PyObject *anyset, PyObject *key) PyErr_BadInternalCall(); return -1; } - + if (PyFrozenSet_CheckExact(anyset)) { + return set_contains_key((PySetObject *)anyset, key); + } int rv; Py_BEGIN_CRITICAL_SECTION(anyset); rv = set_contains_key((PySetObject *)anyset, key); @@ -2758,17 +2978,24 @@ PySet_Discard(PyObject *set, PyObject *key) int PySet_Add(PyObject *anyset, PyObject *key) { - if (!PySet_Check(anyset) && - (!PyFrozenSet_Check(anyset) || Py_REFCNT(anyset) != 1)) { - PyErr_BadInternalCall(); - return -1; + if (PySet_Check(anyset)) { + int rv; + Py_BEGIN_CRITICAL_SECTION(anyset); + rv = set_add_key((PySetObject *)anyset, key); + Py_END_CRITICAL_SECTION(); + return rv; } - int rv; - Py_BEGIN_CRITICAL_SECTION(anyset); - rv = set_add_key((PySetObject *)anyset, key); - Py_END_CRITICAL_SECTION(); - return rv; + if (PyFrozenSet_Check(anyset) && _PyObject_IsUniquelyReferenced(anyset)) { + // We can only change frozensets if they are uniquely referenced. The + // API limits the usage of `PySet_Add` to "fill in the values of brand + // new frozensets before they are exposed to other code". In this case, + // this can be done without a lock. + return set_add_key((PySetObject *)anyset, key); + } + + PyErr_BadInternalCall(); + return -1; } int diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h index 440410d0aef..9e53fab8429 100644 --- a/Objects/stringlib/codecs.h +++ b/Objects/stringlib/codecs.h @@ -257,16 +257,14 @@ InvalidContinuation3: /* UTF-8 encoder specialized for a Unicode kind to avoid the slow PyUnicode_READ() macro. Delete some parts of the code depending on the kind: UCS-1 strings don't need to handle surrogates for example. */ -Py_LOCAL_INLINE(char *) -STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, - PyObject *unicode, +Py_LOCAL_INLINE(PyBytesWriter*) +STRINGLIB(utf8_encoder)(PyObject *unicode, const STRINGLIB_CHAR *data, Py_ssize_t size, _Py_error_handler error_handler, - const char *errors) + const char *errors, + char **end) { - Py_ssize_t i; /* index into data of next input character */ - char *p; /* next free byte in output buffer */ #if STRINGLIB_SIZEOF_CHAR > 1 PyObject *error_handler_obj = NULL; PyObject *exc = NULL; @@ -284,14 +282,19 @@ STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, if (size > PY_SSIZE_T_MAX / max_char_size) { /* integer overflow */ PyErr_NoMemory(); + *end = NULL; return NULL; } - _PyBytesWriter_Init(writer); - p = _PyBytesWriter_Alloc(writer, size * max_char_size); - if (p == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size * max_char_size); + if (writer == NULL) { + *end = NULL; return NULL; + } + /* next free byte in output buffer */ + char *p = PyBytesWriter_GetData(writer); + Py_ssize_t i; /* index into data of next input character */ for (i = 0; i < size;) { Py_UCS4 ch = data[i++]; @@ -348,7 +351,7 @@ STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, case _Py_ERROR_BACKSLASHREPLACE: /* subtract preallocated bytes */ - writer->min_size -= max_char_size * (endpos - startpos); + writer->size -= max_char_size * (endpos - startpos); p = backslashreplace(writer, p, unicode, startpos, endpos); if (p == NULL) @@ -358,7 +361,7 @@ STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, case _Py_ERROR_XMLCHARREFREPLACE: /* subtract preallocated bytes */ - writer->min_size -= max_char_size * (endpos - startpos); + writer->size -= max_char_size * (endpos - startpos); p = xmlcharrefreplace(writer, p, unicode, startpos, endpos); if (p == NULL) @@ -389,22 +392,25 @@ STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, if (newpos < startpos) { writer->overallocate = 1; - p = _PyBytesWriter_Prepare(writer, p, - max_char_size * (startpos - newpos)); - if (p == NULL) + p = PyBytesWriter_GrowAndUpdatePointer(writer, + max_char_size * (startpos - newpos), + p); + if (p == NULL) { goto error; + } } else { /* subtract preallocated bytes */ - writer->min_size -= max_char_size * (newpos - startpos); + writer->size -= max_char_size * (newpos - startpos); /* Only overallocate the buffer if it's not the last write */ writer->overallocate = (newpos < size); } + char *rep_str; + Py_ssize_t rep_len; if (PyBytes_Check(rep)) { - p = _PyBytesWriter_WriteBytes(writer, p, - PyBytes_AS_STRING(rep), - PyBytes_GET_SIZE(rep)); + rep_str = PyBytes_AS_STRING(rep); + rep_len = PyBytes_GET_SIZE(rep); } else { /* rep is unicode */ @@ -415,13 +421,16 @@ STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, goto error; } - p = _PyBytesWriter_WriteBytes(writer, p, - PyUnicode_DATA(rep), - PyUnicode_GET_LENGTH(rep)); + rep_str = PyUnicode_DATA(rep); + rep_len = PyUnicode_GET_LENGTH(rep); } - if (p == NULL) + p = PyBytesWriter_GrowAndUpdatePointer(writer, rep_len, p); + if (p == NULL) { goto error; + } + memcpy(p, rep_str, rep_len); + p += rep_len; Py_CLEAR(rep); i = newpos; @@ -458,13 +467,16 @@ STRINGLIB(utf8_encoder)(_PyBytesWriter *writer, Py_XDECREF(error_handler_obj); Py_XDECREF(exc); #endif - return p; + *end = p; + return writer; #if STRINGLIB_SIZEOF_CHAR > 1 error: + PyBytesWriter_Discard(writer); Py_XDECREF(rep); Py_XDECREF(error_handler_obj); Py_XDECREF(exc); + *end = NULL; return NULL; #endif } diff --git a/Objects/stringlib/localeutil.h b/Objects/stringlib/localeutil.h deleted file mode 100644 index a4ab701de00..00000000000 --- a/Objects/stringlib/localeutil.h +++ /dev/null @@ -1,97 +0,0 @@ -/* _PyUnicode_InsertThousandsGrouping() helper functions */ - -typedef struct { - const char *grouping; - char previous; - Py_ssize_t i; /* Where we're currently pointing in grouping. */ -} GroupGenerator; - - -static void -GroupGenerator_init(GroupGenerator *self, const char *grouping) -{ - self->grouping = grouping; - self->i = 0; - self->previous = 0; -} - - -/* Returns the next grouping, or 0 to signify end. */ -static Py_ssize_t -GroupGenerator_next(GroupGenerator *self) -{ - /* Note that we don't really do much error checking here. If a - grouping string contains just CHAR_MAX, for example, then just - terminate the generator. That shouldn't happen, but at least we - fail gracefully. */ - switch (self->grouping[self->i]) { - case 0: - return self->previous; - case CHAR_MAX: - /* Stop the generator. */ - return 0; - default: { - char ch = self->grouping[self->i]; - self->previous = ch; - self->i++; - return (Py_ssize_t)ch; - } - } -} - - -/* Fill in some digits, leading zeros, and thousands separator. All - are optional, depending on when we're called. */ -static void -InsertThousandsGrouping_fill(_PyUnicodeWriter *writer, Py_ssize_t *buffer_pos, - PyObject *digits, Py_ssize_t *digits_pos, - Py_ssize_t n_chars, Py_ssize_t n_zeros, - PyObject *thousands_sep, Py_ssize_t thousands_sep_len, - Py_UCS4 *maxchar, int forward) -{ - if (!writer) { - /* if maxchar > 127, maxchar is already set */ - if (*maxchar == 127 && thousands_sep) { - Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE(thousands_sep); - *maxchar = Py_MAX(*maxchar, maxchar2); - } - return; - } - - if (thousands_sep) { - if (!forward) { - *buffer_pos -= thousands_sep_len; - } - /* Copy the thousands_sep chars into the buffer. */ - _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos, - thousands_sep, 0, - thousands_sep_len); - if (forward) { - *buffer_pos += thousands_sep_len; - } - } - - if (!forward) { - *buffer_pos -= n_chars; - *digits_pos -= n_chars; - } - _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos, - digits, *digits_pos, - n_chars); - if (forward) { - *buffer_pos += n_chars; - *digits_pos += n_chars; - } - - if (n_zeros) { - if (!forward) { - *buffer_pos -= n_zeros; - } - int kind = PyUnicode_KIND(writer->buffer); - void *data = PyUnicode_DATA(writer->buffer); - unicode_fill(kind, data, '0', *buffer_pos, n_zeros); - if (forward) { - *buffer_pos += n_zeros; - } - } -} diff --git a/Objects/structseq.c b/Objects/structseq.c index c05bcde24c4..7a159338b9b 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -12,7 +12,7 @@ #include "pycore_modsupport.h" // _PyArg_NoPositional() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_structseq.h" // PyStructSequence_InitType() -#include "pycore_tuple.h" // _PyTuple_FromArray() +#include "pycore_tuple.h" // _PyTuple_RESET_HASH_CACHE() #include "pycore_typeobject.h" // _PyStaticType_FiniBuiltin() static const char visible_length_key[] = "n_sequence_fields"; @@ -353,7 +353,7 @@ structseq_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) if (n_unnamed_fields < 0) { return NULL; } - tup = _PyTuple_FromArray(self->ob_item, n_visible_fields); + tup = PyTuple_FromArray(self->ob_item, n_visible_fields); if (!tup) goto error; diff --git a/Objects/templateobject.c b/Objects/templateobject.c index ac38e4de435..a05208e4c8f 100644 --- a/Objects/templateobject.c +++ b/Objects/templateobject.c @@ -148,13 +148,14 @@ template_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (last_was_str) { PyObject *laststring = PyTuple_GET_ITEM(strings, stringsidx - 1); PyObject *concat = PyUnicode_Concat(laststring, item); - Py_DECREF(laststring); if (!concat) { Py_DECREF(strings); Py_DECREF(interpolations); return NULL; } + /* Replace laststring with concat */ PyTuple_SET_ITEM(strings, stringsidx - 1, concat); + Py_DECREF(laststring); } else { PyTuple_SET_ITEM(strings, stringsidx++, Py_NewRef(item)); diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 9b31758485c..169ac69701d 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -118,7 +118,7 @@ int PyTuple_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem) { PyObject **p; - if (!PyTuple_Check(op) || Py_REFCNT(op) != 1) { + if (!PyTuple_Check(op) || !_PyObject_IsUniquelyReferenced(op)) { Py_XDECREF(newitem); PyErr_BadInternalCall(); return -1; @@ -156,6 +156,18 @@ _PyTuple_MaybeUntrack(PyObject *op) _PyObject_GC_UNTRACK(op); } +/* Fast, but conservative check if an object maybe tracked + May return true for an object that is not tracked, + Will always return true for an object that is tracked. + This is a temporary workaround until _PyObject_GC_IS_TRACKED + becomes fast and safe to call on non-GC objects. +*/ +static bool +maybe_tracked(PyObject *ob) +{ + return _PyType_IS_GC(Py_TYPE(ob)); +} + PyObject * PyTuple_Pack(Py_ssize_t n, ...) { @@ -163,6 +175,7 @@ PyTuple_Pack(Py_ssize_t n, ...) PyObject *o; PyObject **items; va_list vargs; + bool track = false; if (n == 0) { return tuple_get_empty(); @@ -177,10 +190,15 @@ PyTuple_Pack(Py_ssize_t n, ...) items = result->ob_item; for (i = 0; i < n; i++) { o = va_arg(vargs, PyObject *); + if (!track && maybe_tracked(o)) { + track = true; + } items[i] = Py_NewRef(o); } va_end(vargs); - _PyObject_GC_TRACK(result); + if (track) { + _PyObject_GC_TRACK(result); + } return (PyObject *)result; } @@ -366,7 +384,7 @@ tuple_item(PyObject *op, Py_ssize_t i) } PyObject * -_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) { if (n == 0) { return tuple_get_empty(); @@ -377,11 +395,17 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) return NULL; } PyObject **dst = tuple->ob_item; + bool track = false; for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = src[i]; + if (!track && maybe_tracked(item)) { + track = true; + } dst[i] = Py_NewRef(item); } - _PyObject_GC_TRACK(tuple); + if (track) { + _PyObject_GC_TRACK(tuple); + } return (PyObject *)tuple; } @@ -396,10 +420,17 @@ _PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n) return NULL; } PyObject **dst = tuple->ob_item; + bool track = false; for (Py_ssize_t i = 0; i < n; i++) { - dst[i] = PyStackRef_AsPyObjectSteal(src[i]); + PyObject *item = PyStackRef_AsPyObjectSteal(src[i]); + if (!track && maybe_tracked(item)) { + track = true; + } + dst[i] = item; + } + if (track) { + _PyObject_GC_TRACK(tuple); } - _PyObject_GC_TRACK(tuple); return (PyObject *)tuple; } @@ -438,7 +469,7 @@ tuple_slice(PyTupleObject *a, Py_ssize_t ilow, if (ilow == 0 && ihigh == Py_SIZE(a) && PyTuple_CheckExact(a)) { return Py_NewRef(a); } - return _PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow); + return PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow); } PyObject * @@ -923,7 +954,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) v = (PyTupleObject *) *pv; if (v == NULL || !Py_IS_TYPE(v, &PyTuple_Type) || - (Py_SIZE(v) != 0 && Py_REFCNT(v) != 1)) { + (Py_SIZE(v) != 0 && !_PyObject_IsUniquelyReferenced(*pv))) { *pv = 0; Py_XDECREF(v); PyErr_BadInternalCall(); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9cead729b6f..7f5149aeece 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -72,7 +72,7 @@ class object "PyObject *" "&PyBaseObject_Type" // the type has been revealed to other threads or we only do those updates // while the stop-the-world mechanism is active. The slots and flags are read // in many places without holding a lock and without atomics. -#define TYPE_LOCK &PyInterpreterState_Get()->types.mutex +#define TYPE_LOCK &_PyInterpreterState_GET()->types.mutex #define BEGIN_TYPE_LOCK() Py_BEGIN_CRITICAL_SECTION_MUTEX(TYPE_LOCK) #define END_TYPE_LOCK() Py_END_CRITICAL_SECTION() @@ -81,7 +81,7 @@ class object "PyObject *" "&PyBaseObject_Type" #define END_TYPE_DICT_LOCK() Py_END_CRITICAL_SECTION2() -#ifdef Py_DEBUG +#if !defined(NDEBUG) || defined(Py_DEBUG) // Return true if the world is currently stopped. static bool types_world_is_stopped(void) @@ -189,6 +189,8 @@ type_lock_allow_release(void) #define types_world_is_stopped() 1 #define types_stop_world() #define types_start_world() +#define type_lock_prevent_release() +#define type_lock_allow_release() #endif @@ -752,6 +754,22 @@ lookup_tp_subclasses(PyTypeObject *self) return (PyObject *)self->tp_subclasses; } +PyObject * +_PyType_LookupSubclasses(PyTypeObject *self) +{ + return lookup_tp_subclasses(self); +} + +PyObject * +_PyType_InitSubclasses(PyTypeObject *self) +{ + PyObject *existing = lookup_tp_subclasses(self); + if (existing != NULL) { + return existing; + } + return init_tp_subclasses(self); +} + int _PyType_HasSubclasses(PyTypeObject *self) { @@ -1449,15 +1467,15 @@ static PyMemberDef type_members[] = { static int check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name) { - if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { + if (!value) { PyErr_Format(PyExc_TypeError, - "cannot set '%s' attribute of immutable type '%s'", + "cannot delete '%s' attribute of type '%s'", name, type->tp_name); return 0; } - if (!value) { + if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { PyErr_Format(PyExc_TypeError, - "cannot delete '%s' attribute of immutable type '%s'", + "cannot set '%s' attribute of immutable type '%s'", name, type->tp_name); return 0; } @@ -1748,7 +1766,7 @@ type_get_mro(PyObject *tp, void *Py_UNUSED(closure)) static PyTypeObject *find_best_base(PyObject *); static int mro_internal(PyTypeObject *, int, PyObject **); static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); -static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, const char *); +static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, const char *, int); static int add_subclass(PyTypeObject*, PyTypeObject*); static int add_all_subclasses(PyTypeObject *type, PyObject *bases); static void remove_subclass(PyTypeObject *, PyTypeObject *); @@ -1764,7 +1782,7 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name, // Compute tp_mro for this type and all of its subclasses. This // is called after __bases__ is assigned to an existing type. static int -mro_hierarchy(PyTypeObject *type, PyObject *temp) +mro_hierarchy_for_complete_type(PyTypeObject *type, PyObject *temp) { ASSERT_TYPE_LOCK_HELD(); @@ -1775,6 +1793,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp) return res; } PyObject *new_mro = lookup_tp_mro(type); + assert(new_mro != NULL); PyObject *tuple; if (old_mro != NULL) { @@ -1819,7 +1838,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp) Py_ssize_t n = PyList_GET_SIZE(subclasses); for (Py_ssize_t i = 0; i < n; i++) { PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i)); - res = mro_hierarchy(subclass, temp); + res = mro_hierarchy_for_complete_type(subclass, temp); if (res < 0) { break; } @@ -1886,7 +1905,7 @@ type_check_new_bases(PyTypeObject *type, PyObject *new_bases, PyTypeObject **bes if (*best_base == NULL) return -1; - if (!compatible_for_assignment(type->tp_base, *best_base, "__bases__")) { + if (!compatible_for_assignment(type, *best_base, "__bases__", 0)) { return -1; } @@ -1903,14 +1922,18 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b assert(old_bases != NULL); PyTypeObject *old_base = type->tp_base; + type_lock_prevent_release(); + types_stop_world(); set_tp_bases(type, Py_NewRef(new_bases), 0); type->tp_base = (PyTypeObject *)Py_NewRef(best_base); + types_start_world(); + type_lock_allow_release(); PyObject *temp = PyList_New(0); if (temp == NULL) { goto bail; } - if (mro_hierarchy(type, temp) < 0) { + if (mro_hierarchy_for_complete_type(type, temp) < 0) { goto undo; } Py_DECREF(temp); @@ -1965,8 +1988,12 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b if (lookup_tp_bases(type) == new_bases) { assert(type->tp_base == best_base); + type_lock_prevent_release(); + types_stop_world(); set_tp_bases(type, old_bases, 0); type->tp_base = old_base; + types_start_world(); + type_lock_allow_release(); Py_DECREF(new_bases); Py_DECREF(best_base); @@ -3416,6 +3443,7 @@ mro_implementation_unlocked(PyTypeObject *type) */ PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, 0)); PyObject *base_mro = lookup_tp_mro(base); + assert(base_mro != NULL); Py_ssize_t k = PyTuple_GET_SIZE(base_mro); PyObject *result = PyTuple_New(k + 1); if (result == NULL) { @@ -3450,9 +3478,12 @@ mro_implementation_unlocked(PyTypeObject *type) return NULL; } + PyObject *mro_to_merge; for (Py_ssize_t i = 0; i < n; i++) { PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i)); - to_merge[i] = lookup_tp_mro(base); + mro_to_merge = lookup_tp_mro(base); + assert(mro_to_merge != NULL); + to_merge[i] = mro_to_merge; } to_merge[n] = bases; @@ -4312,14 +4343,6 @@ type_new_slots_bases(type_new_ctx *ctx) static int type_new_slots_impl(type_new_ctx *ctx, PyObject *dict) { - /* Are slots allowed? */ - if (ctx->nslot > 0 && ctx->base->tp_itemsize != 0) { - PyErr_Format(PyExc_TypeError, - "nonempty __slots__ not supported for subtype of '%s'", - ctx->base->tp_name); - return -1; - } - if (type_new_visit_slots(ctx) < 0) { return -1; } @@ -4346,14 +4369,13 @@ type_new_slots(type_new_ctx *ctx, PyObject *dict) ctx->add_dict = 0; ctx->add_weak = 0; ctx->may_add_dict = (ctx->base->tp_dictoffset == 0); - ctx->may_add_weak = (ctx->base->tp_weaklistoffset == 0 - && ctx->base->tp_itemsize == 0); + ctx->may_add_weak = (ctx->base->tp_weaklistoffset == 0); if (ctx->slots == NULL) { if (ctx->may_add_dict) { ctx->add_dict++; } - if (ctx->may_add_weak) { + if (ctx->may_add_weak && ctx->base->tp_itemsize == 0) { ctx->add_weak++; } } @@ -4619,6 +4641,12 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type, PyObject *dict if (et->ht_slots != NULL) { PyMemberDef *mp = _PyHeapType_GET_MEMBERS(et); Py_ssize_t nslot = PyTuple_GET_SIZE(et->ht_slots); + if (ctx->base->tp_itemsize != 0) { + PyErr_Format(PyExc_TypeError, + "arbitrary __slots__ not supported for subtype of '%s'", + ctx->base->tp_name); + return -1; + } for (Py_ssize_t i = 0; i < nslot; i++, mp++) { mp->name = PyUnicode_AsUTF8( PyTuple_GET_ITEM(et->ht_slots, i)); @@ -4858,8 +4886,14 @@ type_new_init(type_new_ctx *ctx) set_tp_dict(type, dict); PyHeapTypeObject *et = (PyHeapTypeObject*)type; - et->ht_slots = ctx->slots; - ctx->slots = NULL; + if (ctx->slots && PyTuple_GET_SIZE(ctx->slots)) { + et->ht_slots = ctx->slots; + ctx->slots = NULL; + } + else { + et->ht_slots = NULL; + Py_CLEAR(ctx->slots); + } return type; @@ -5743,11 +5777,11 @@ PyType_GetModuleState(PyTypeObject *type) } -/* Get the module of the first superclass where the module has the - * given PyModuleDef. +/* Return borrowed ref to the module of the first superclass where the module + * has the given token. */ -PyObject * -PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) +static PyObject * +borrow_module_by_token(PyTypeObject *type, const void *token) { assert(PyType_Check(type)); @@ -5759,7 +5793,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) else { PyHeapTypeObject *ht = (PyHeapTypeObject*)type; PyObject *module = ht->ht_module; - if (module && _PyModule_GetDef(module) == def) { + if (module && _PyModule_GetToken(module) == token) { return module; } } @@ -5787,7 +5821,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) PyHeapTypeObject *ht = (PyHeapTypeObject*)super; PyObject *module = ht->ht_module; - if (module && _PyModule_GetDef(module) == def) { + if (module && _PyModule_GetToken(module) == token) { res = module; break; } @@ -5805,6 +5839,18 @@ error: return NULL; } +PyObject * +PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) +{ + return borrow_module_by_token(type, def); +} + +PyObject * +PyType_GetModuleByToken(PyTypeObject *type, const void *token) +{ + return Py_XNewRef(borrow_module_by_token(type, token)); +} + static PyTypeObject * get_base_by_token_recursive(PyObject *bases, void *token) @@ -5831,23 +5877,15 @@ get_base_by_token_recursive(PyObject *bases, void *token) } int -PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result) +_PyType_GetBaseByToken_Borrow(PyTypeObject *type, void *token, PyTypeObject **result) { + assert(token != NULL); + assert(PyType_Check(type)); + if (result != NULL) { *result = NULL; } - if (token == NULL) { - PyErr_Format(PyExc_SystemError, - "PyType_GetBaseByToken called with token=NULL"); - return -1; - } - if (!PyType_Check(type)) { - PyErr_Format(PyExc_TypeError, - "expected a type, got a '%T' object", type); - return -1; - } - if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { // No static type has a heaptype superclass, // which is ensured by type_ready_mro(). @@ -5856,7 +5894,7 @@ PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result) if (((PyHeapTypeObject*)type)->ht_token == token) { found: if (result != NULL) { - *result = (PyTypeObject *)Py_NewRef(type); + *result = type; } return 1; } @@ -5890,6 +5928,30 @@ found: return 0; } +int +PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result) +{ + if (result != NULL) { + *result = NULL; + } + if (token == NULL) { + PyErr_Format(PyExc_SystemError, + "PyType_GetBaseByToken called with token=NULL"); + return -1; + } + if (!PyType_Check(type)) { + PyErr_Format(PyExc_TypeError, + "expected a type, got a '%T' object", type); + return -1; + } + + int res = _PyType_GetBaseByToken_Borrow(type, token, result); + if (res > 0 && result) { + Py_INCREF(*result); + } + return res; +} + void * PyObject_GetTypeData(PyObject *obj, PyTypeObject *cls) @@ -5993,7 +6055,7 @@ static PyObject * update_cache(struct type_cache_entry *entry, PyObject *name, unsigned int version_tag, PyObject *value) { _Py_atomic_store_ptr_relaxed(&entry->value, value); /* borrowed */ - assert(_PyASCIIObject_CAST(name)->hash != -1); + assert(PyUnstable_Unicode_GET_CACHED_HASH(name) != -1); OBJECT_STAT_INC_COND(type_cache_collisions, entry->name != Py_None && entry->name != name); // We're releasing this under the lock for simplicity sake because it's always a // exact unicode object or Py_None so it's safe to do so. @@ -6503,6 +6565,18 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value) assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_INLINE_VALUES)); assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_MANAGED_DICT)); +#ifdef Py_GIL_DISABLED + // gh-139103: Enable deferred refcounting for functions assigned + // to type objects. This is important for `dataclass.__init__`, + // which is generated dynamically. + if (value != NULL && + PyFunction_Check(value) && + !_PyObject_HasDeferredRefcount(value)) + { + PyUnstable_Object_EnableDeferredRefcount(value); + } +#endif + PyObject *old_value = NULL; PyObject *descr = _PyType_LookupRef(metatype, name); if (descr != NULL) { @@ -7263,10 +7337,6 @@ compatible_with_tp_base(PyTypeObject *child) return (parent != NULL && child->tp_basicsize == parent->tp_basicsize && child->tp_itemsize == parent->tp_itemsize && - child->tp_dictoffset == parent->tp_dictoffset && - child->tp_weaklistoffset == parent->tp_weaklistoffset && - ((child->tp_flags & Py_TPFLAGS_HAVE_GC) == - (parent->tp_flags & Py_TPFLAGS_HAVE_GC)) && (child->tp_dealloc == subtype_dealloc || child->tp_dealloc == parent->tp_dealloc)); } @@ -7301,11 +7371,24 @@ same_slots_added(PyTypeObject *a, PyTypeObject *b) } static int -compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* attr) +compatible_flags(int setclass, PyTypeObject *origto, PyTypeObject *newto, unsigned long flags) +{ + /* For __class__ assignment, the flags should be the same. + For __bases__ assignment, the new base flags can only be set + if the original class flags are set. + */ + return setclass ? (origto->tp_flags & flags) == (newto->tp_flags & flags) + : !(~(origto->tp_flags & flags) & (newto->tp_flags & flags)); +} + +static int +compatible_for_assignment(PyTypeObject *origto, PyTypeObject *newto, + const char *attr, int setclass) { PyTypeObject *newbase, *oldbase; + PyTypeObject *oldto = setclass ? origto : origto->tp_base; - if (newto->tp_free != oldto->tp_free) { + if (setclass && newto->tp_free != oldto->tp_free) { PyErr_Format(PyExc_TypeError, "%s assignment: " "'%s' deallocator differs from '%s'", @@ -7314,6 +7397,28 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* oldto->tp_name); return 0; } + if (!compatible_flags(setclass, origto, newto, + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_INLINE_VALUES | + Py_TPFLAGS_PREHEADER)) + { + goto differs; + } + /* For __class__ assignment, tp_dictoffset and tp_weaklistoffset should + be the same for old and new types. + For __bases__ assignment, they can only be set in the new base + if they are set in the original class with the same value. + */ + if ((setclass || newto->tp_dictoffset) + && origto->tp_dictoffset != newto->tp_dictoffset) + { + goto differs; + } + if ((setclass || newto->tp_weaklistoffset) + && origto->tp_weaklistoffset != newto->tp_weaklistoffset) + { + goto differs; + } /* It's tricky to tell if two arbitrary types are sufficiently compatible as to be interchangeable; e.g., even if they have the same tp_basicsize, they @@ -7335,17 +7440,7 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* !same_slots_added(newbase, oldbase))) { goto differs; } - if ((oldto->tp_flags & Py_TPFLAGS_INLINE_VALUES) != - ((newto->tp_flags & Py_TPFLAGS_INLINE_VALUES))) - { - goto differs; - } - /* The above does not check for the preheader */ - if ((oldto->tp_flags & Py_TPFLAGS_PREHEADER) == - ((newto->tp_flags & Py_TPFLAGS_PREHEADER))) - { - return 1; - } + return 1; differs: PyErr_Format(PyExc_TypeError, "%s assignment: " @@ -7422,7 +7517,7 @@ object_set_class_world_stopped(PyObject *self, PyTypeObject *newto) return -1; } - if (compatible_for_assignment(oldto, newto, "__class__")) { + if (compatible_for_assignment(oldto, newto, "__class__", 1)) { /* Changing the class will change the implicit dict keys, * so we must materialize the dictionary first. */ if (oldto->tp_flags & Py_TPFLAGS_INLINE_VALUES) { @@ -8856,6 +8951,13 @@ type_ready_preheader(PyTypeObject *type) type->tp_name); return -1; } + if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) { + PyErr_Format(PyExc_SystemError, + "type %s has the Py_TPFLAGS_MANAGED_DICT flag " + "but not Py_TPFLAGS_HAVE_GC flag", + type->tp_name); + return -1; + } type->tp_dictoffset = -1; } if (type->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF) { @@ -8868,6 +8970,13 @@ type_ready_preheader(PyTypeObject *type) type->tp_name); return -1; } + if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) { + PyErr_Format(PyExc_SystemError, + "type %s has the Py_TPFLAGS_MANAGED_WEAKREF flag " + "but not Py_TPFLAGS_HAVE_GC flag", + type->tp_name); + return -1; + } type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET; } return 0; @@ -8961,6 +9070,7 @@ type_ready_inherit(PyTypeObject *type) // Inherit slots PyObject *mro = lookup_tp_mro(type); + assert(mro != NULL); Py_ssize_t n = PyTuple_GET_SIZE(mro); for (Py_ssize_t i = 1; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(mro, i); @@ -10532,6 +10642,7 @@ slot_tp_hash(PyObject *self) return PyObject_HashNotImplemented(self); } if (!PyLong_Check(res)) { + Py_DECREF(res); PyErr_SetString(PyExc_TypeError, "__hash__ method should return an integer"); return -1; @@ -11385,6 +11496,11 @@ static pytype_slotdef slotdefs[] = { {NULL} }; +/* Stores the number of times where slotdefs has elements with same name. + This counter precalculated by _PyType_InitSlotDefs() when the main + interpreter starts. */ +static uint8_t slotdefs_name_counts[Py_ARRAY_LENGTH(slotdefs)]; + /* Given a type pointer and an offset gotten from a slotdef entry, return a pointer to the actual slot. This is not quite the same as simply adding the offset to the type pointer, since it takes care to indirect through the @@ -11427,61 +11543,6 @@ slotptr(PyTypeObject *type, int ioffset) return (void **)ptr; } -/* Return a slot pointer for a given name, but ONLY if the attribute has - exactly one slot function. The name must be an interned string. */ -static void ** -resolve_slotdups(PyTypeObject *type, PyObject *name) -{ - /* XXX Maybe this could be optimized more -- but is it worth it? */ - -#ifdef Py_GIL_DISABLED - pytype_slotdef *ptrs[MAX_EQUIV]; - pytype_slotdef **pp = ptrs; - /* Collect all slotdefs that match name into ptrs. */ - for (pytype_slotdef *p = slotdefs; p->name_strobj; p++) { - if (p->name_strobj == name) - *pp++ = p; - } - *pp = NULL; -#else - /* pname and ptrs act as a little cache */ - PyInterpreterState *interp = _PyInterpreterState_GET(); -#define pname _Py_INTERP_CACHED_OBJECT(interp, type_slots_pname) -#define ptrs _Py_INTERP_CACHED_OBJECT(interp, type_slots_ptrs) - pytype_slotdef *p, **pp; - - if (pname != name) { - /* Collect all slotdefs that match name into ptrs. */ - pname = name; - pp = ptrs; - for (p = slotdefs; p->name_strobj; p++) { - if (p->name_strobj == name) - *pp++ = p; - } - *pp = NULL; - } -#endif - - /* Look in all slots of the type matching the name. If exactly one of these - has a filled-in slot, return a pointer to that slot. - Otherwise, return NULL. */ - void **res, **ptr; - res = NULL; - for (pp = ptrs; *pp; pp++) { - ptr = slotptr(type, (*pp)->offset); - if (ptr == NULL || *ptr == NULL) - continue; - if (res != NULL) - return NULL; - res = ptr; - } -#ifndef Py_GIL_DISABLED -#undef pname -#undef ptrs -#endif - return res; -} - // Return true if "name" corresponds to at least one slot definition. This is // a more accurate but more expensive test compared to is_dunder_name(). static bool @@ -11608,7 +11669,15 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p, } if (Py_IS_TYPE(descr, &PyWrapperDescr_Type) && ((PyWrapperDescrObject *)descr)->d_base->name_strobj == p->name_strobj) { - void **tptr = resolve_slotdups(type, p->name_strobj); + void **tptr; + size_t index = (p - slotdefs) / sizeof(slotdefs[0]); + if (slotdefs_name_counts[index] == 1) { + tptr = slotptr(type, p->offset); + } + else { + tptr = NULL; + } + if (tptr == NULL || tptr == ptr) generic = p->function; d = (PyWrapperDescrObject *)descr; @@ -11821,6 +11890,76 @@ update_all_slots(PyTypeObject* type) #endif +int +_PyType_InitSlotDefs(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return 0; + } + PyObject *bytearray = NULL; + PyObject *cache = PyDict_New(); + if (!cache) { + return -1; + } + + pytype_slotdef *p; + Py_ssize_t idx = 0; + for (p = slotdefs; p->name_strobj; p++, idx++) { + assert(idx < 255); + + if (PyDict_GetItemRef(cache, p->name_strobj, &bytearray) < 0) { + goto error; + } + + if (!bytearray) { + Py_ssize_t size = sizeof(uint8_t) * (1 + MAX_EQUIV); + bytearray = PyByteArray_FromStringAndSize(NULL, size); + if (!bytearray) { + goto error; + } + + uint8_t *data = (uint8_t *)PyByteArray_AS_STRING(bytearray); + data[0] = 0; + + if (PyDict_SetItem(cache, p->name_strobj, bytearray) < 0) { + goto error; + } + } + + assert(PyByteArray_CheckExact(bytearray)); + uint8_t *data = (uint8_t *)PyByteArray_AS_STRING(bytearray); + + data[0] += 1; + assert(data[0] < MAX_EQUIV); + + data[data[0]] = (uint8_t)idx; + + Py_CLEAR(bytearray); + } + + memset(slotdefs_name_counts, 0, sizeof(slotdefs_name_counts)); + + Py_ssize_t pos = 0; + PyObject *key = NULL; + PyObject *value = NULL; + while (PyDict_Next(cache, &pos, &key, &value)) { + uint8_t *data = (uint8_t *)PyByteArray_AS_STRING(value); + uint8_t n = data[0]; + for (uint8_t i = 0; i < n; i++) { + uint8_t idx = data[i + 1]; + slotdefs_name_counts[idx] = n; + } + } + + Py_DECREF(cache); + return 0; + +error: + Py_XDECREF(bytearray); + Py_DECREF(cache); + return -1; +} + PyObject * _PyType_GetSlotWrapperNames(void) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index cead6e69af5..8e43962c7e3 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -53,6 +53,7 @@ typedef struct { typedef struct { PyObject_HEAD PyObject *name; + PyObject *qualname; PyObject *type_params; PyObject *compute_value; PyObject *value; @@ -250,7 +251,7 @@ static PyType_Slot constevaluator_slots[] = { {0, NULL}, }; -PyType_Spec constevaluator_spec = { +static PyType_Spec constevaluator_spec = { .name = "_typing._ConstEvaluator", .basicsize = sizeof(constevaluatorobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE @@ -472,7 +473,7 @@ typevar_dealloc(PyObject *self) _PyObject_GC_UNTRACK(self); - Py_DECREF(tv->name); + Py_XDECREF(tv->name); Py_XDECREF(tv->bound); Py_XDECREF(tv->evaluate_bound); Py_XDECREF(tv->constraints); @@ -491,6 +492,7 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); typevarobject *tv = typevarobject_CAST(self); + Py_VISIT(tv->name); Py_VISIT(tv->bound); Py_VISIT(tv->evaluate_bound); Py_VISIT(tv->constraints); @@ -505,6 +507,7 @@ static int typevar_clear(PyObject *op) { typevarobject *self = typevarobject_CAST(op); + Py_CLEAR(self->name); Py_CLEAR(self->bound); Py_CLEAR(self->evaluate_bound); Py_CLEAR(self->constraints); @@ -927,7 +930,7 @@ static PyType_Slot typevar_slots[] = { {0, NULL}, }; -PyType_Spec typevar_spec = { +static PyType_Spec typevar_spec = { .name = "typing.TypeVar", .basicsize = sizeof(typevarobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE @@ -1075,7 +1078,7 @@ static PyType_Slot paramspecargs_slots[] = { {0, NULL}, }; -PyType_Spec paramspecargs_spec = { +static PyType_Spec paramspecargs_spec = { .name = "typing.ParamSpecArgs", .basicsize = sizeof(paramspecattrobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE @@ -1155,7 +1158,7 @@ static PyType_Slot paramspeckwargs_slots[] = { {0, NULL}, }; -PyType_Spec paramspeckwargs_spec = { +static PyType_Spec paramspeckwargs_spec = { .name = "typing.ParamSpecKwargs", .basicsize = sizeof(paramspecattrobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE @@ -1171,7 +1174,7 @@ paramspec_dealloc(PyObject *self) _PyObject_GC_UNTRACK(self); - Py_DECREF(ps->name); + Py_XDECREF(ps->name); Py_XDECREF(ps->bound); Py_XDECREF(ps->default_value); Py_XDECREF(ps->evaluate_default); @@ -1187,6 +1190,7 @@ paramspec_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); paramspecobject *ps = paramspecobject_CAST(self); + Py_VISIT(ps->name); Py_VISIT(ps->bound); Py_VISIT(ps->default_value); Py_VISIT(ps->evaluate_default); @@ -1198,6 +1202,7 @@ static int paramspec_clear(PyObject *op) { paramspecobject *self = paramspecobject_CAST(op); + Py_CLEAR(self->name); Py_CLEAR(self->bound); Py_CLEAR(self->default_value); Py_CLEAR(self->evaluate_default); @@ -1504,7 +1509,7 @@ static PyType_Slot paramspec_slots[] = { {0, 0}, }; -PyType_Spec paramspec_spec = { +static PyType_Spec paramspec_spec = { .name = "typing.ParamSpec", .basicsize = sizeof(paramspecobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE @@ -1519,7 +1524,7 @@ typevartuple_dealloc(PyObject *self) _PyObject_GC_UNTRACK(self); typevartupleobject *tvt = typevartupleobject_CAST(self); - Py_DECREF(tvt->name); + Py_XDECREF(tvt->name); Py_XDECREF(tvt->default_value); Py_XDECREF(tvt->evaluate_default); PyObject_ClearManagedDict(self); @@ -1683,6 +1688,7 @@ typevartuple_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); typevartupleobject *tvt = typevartupleobject_CAST(self); + Py_VISIT(tvt->name); Py_VISIT(tvt->default_value); Py_VISIT(tvt->evaluate_default); PyObject_VisitManagedDict(self, visit, arg); @@ -1693,6 +1699,7 @@ static int typevartuple_clear(PyObject *self) { typevartupleobject *tvt = typevartupleobject_CAST(self); + Py_CLEAR(tvt->name); Py_CLEAR(tvt->default_value); Py_CLEAR(tvt->evaluate_default); PyObject_ClearManagedDict(self); @@ -1782,7 +1789,7 @@ Note that only TypeVarTuples defined in the global scope can be\n\ pickled.\n\ "); -PyType_Slot typevartuple_slots[] = { +static PyType_Slot typevartuple_slots[] = { {Py_tp_doc, (void *)typevartuple_doc}, {Py_tp_members, typevartuple_members}, {Py_tp_methods, typevartuple_methods}, @@ -1798,7 +1805,7 @@ PyType_Slot typevartuple_slots[] = { {0, 0}, }; -PyType_Spec typevartuple_spec = { +static PyType_Spec typevartuple_spec = { .name = "typing.TypeVarTuple", .basicsize = sizeof(typevartupleobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT @@ -1851,7 +1858,8 @@ typealias_dealloc(PyObject *self) PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); typealiasobject *ta = typealiasobject_CAST(self); - Py_DECREF(ta->name); + Py_XDECREF(ta->name); + Py_XDECREF(ta->qualname); Py_XDECREF(ta->type_params); Py_XDECREF(ta->compute_value); Py_XDECREF(ta->value); @@ -1878,11 +1886,12 @@ static PyObject * typealias_repr(PyObject *self) { typealiasobject *ta = (typealiasobject *)self; - return Py_NewRef(ta->name); + return Py_NewRef(ta->qualname); } static PyMemberDef typealias_members[] = { {"__name__", _Py_T_OBJECT, offsetof(typealiasobject, name), Py_READONLY}, + {"__qualname__", _Py_T_OBJECT, offsetof(typealiasobject, qualname), Py_READONLY}, {0} }; @@ -1997,7 +2006,7 @@ typealias_check_type_params(PyObject *type_params, int *err) { } static PyObject * -typelias_convert_type_params(PyObject *type_params) +typealias_convert_type_params(PyObject *type_params) { if ( type_params == NULL @@ -2012,14 +2021,15 @@ typelias_convert_type_params(PyObject *type_params) } static typealiasobject * -typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, - PyObject *value, PyObject *module) +typealias_alloc(PyObject *name, PyObject *qualname, PyObject *type_params, + PyObject *compute_value, PyObject *value, PyObject *module) { typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type); if (ta == NULL) { return NULL; } ta->name = Py_NewRef(name); + ta->qualname = Py_NewRef(qualname); ta->type_params = Py_XNewRef(type_params); ta->compute_value = Py_XNewRef(compute_value); ta->value = Py_XNewRef(value); @@ -2032,6 +2042,8 @@ static int typealias_traverse(PyObject *op, visitproc visit, void *arg) { typealiasobject *self = typealiasobject_CAST(op); + Py_VISIT(self->name); + Py_VISIT(self->qualname); Py_VISIT(self->type_params); Py_VISIT(self->compute_value); Py_VISIT(self->value); @@ -2043,6 +2055,8 @@ static int typealias_clear(PyObject *op) { typealiasobject *self = typealiasobject_CAST(op); + Py_CLEAR(self->name); + Py_CLEAR(self->qualname); Py_CLEAR(self->type_params); Py_CLEAR(self->compute_value); Py_CLEAR(self->value); @@ -2088,14 +2102,15 @@ typealias.__new__ as typealias_new value: object * type_params: object = NULL + qualname: object(c_default="NULL") = None Create a TypeAliasType. [clinic start generated code]*/ static PyObject * typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, - PyObject *type_params) -/*[clinic end generated code: output=8920ce6bdff86f00 input=df163c34e17e1a35]*/ + PyObject *type_params, PyObject *qualname) +/*[clinic end generated code: output=b7f6d9f1c577cd9c input=cbec290f8c4886ef]*/ { if (type_params != NULL && !PyTuple_Check(type_params)) { PyErr_SetString(PyExc_TypeError, "type_params must be a tuple"); @@ -2108,12 +2123,23 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, return NULL; } + if (qualname == NULL || qualname == Py_None) { + // If qualname was not set directly, we use name instead. + qualname = name; + } else { + if (!PyUnicode_Check(qualname)) { + PyErr_SetString(PyExc_TypeError, "qualname must be a string"); + return NULL; + } + } + PyObject *module = caller(); if (module == NULL) { return NULL; } - PyObject *ta = (PyObject *)typealias_alloc(name, checked_params, NULL, value, - module); + + PyObject *ta = (PyObject *)typealias_alloc( + name, qualname, checked_params, NULL, value, module); Py_DECREF(module); return ta; } @@ -2179,10 +2205,17 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args) assert(PyTuple_GET_SIZE(args) == 3); PyObject *name = PyTuple_GET_ITEM(args, 0); assert(PyUnicode_Check(name)); - PyObject *type_params = typelias_convert_type_params(PyTuple_GET_ITEM(args, 1)); + PyObject *type_params = typealias_convert_type_params(PyTuple_GET_ITEM(args, 1)); PyObject *compute_value = PyTuple_GET_ITEM(args, 2); assert(PyFunction_Check(compute_value)); - return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL); + + PyFunctionObject *compute_func = (PyFunctionObject *)compute_value; + PyCodeObject *code_obj = (PyCodeObject *)compute_func->func_code; + PyObject *qualname = code_obj->co_qualname; + assert(qualname != NULL); + + return (PyObject *)typealias_alloc( + name, qualname, type_params, compute_value, NULL, NULL); } PyDoc_STRVAR(generic_doc, @@ -2304,24 +2337,17 @@ generic_dealloc(PyObject *self) Py_DECREF(tp); } -static int -generic_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyType_Slot generic_slots[] = { {Py_tp_doc, (void *)generic_doc}, {Py_tp_methods, generic_methods}, {Py_tp_dealloc, generic_dealloc}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_free, PyObject_GC_Del}, - {Py_tp_traverse, generic_traverse}, + {Py_tp_traverse, _PyObject_VisitType}, {0, NULL}, }; -PyType_Spec generic_spec = { +static PyType_Spec generic_spec = { .name = "typing.Generic", .basicsize = sizeof(PyObject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, diff --git a/Objects/unicode_format.c b/Objects/unicode_format.c new file mode 100644 index 00000000000..26bdae55d8b --- /dev/null +++ b/Objects/unicode_format.c @@ -0,0 +1,1002 @@ +/* + +Unicode implementation based on original code by Fredrik Lundh, +modified by Marc-Andre Lemburg <mal@lemburg.com>. + +Major speed upgrades to the method implementations at the Reykjavik +NeedForSpeed sprint, by Fredrik Lundh and Andrew Dalke. + +Copyright (c) Corporation for National Research Initiatives. + +-------------------------------------------------------------------- +The original string type implementation is: + + Copyright (c) 1999 by Secret Labs AB + Copyright (c) 1999 by Fredrik Lundh + +By obtaining, using, and/or copying this software and/or its +associated documentation, you agree that you have read, understood, +and will comply with the following terms and conditions: + +Permission to use, copy, modify, and distribute this software and its +associated documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies, and that both that copyright notice and this permission notice +appear in supporting documentation, and that the name of Secret Labs +AB or the author not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-------------------------------------------------------------------- + +*/ + +// PyUnicode_Format() implementation + +#include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_format.h" // F_ALT +#include "pycore_long.h" // _PyLong_FormatWriter() +#include "pycore_object.h" // _PyObject_IsUniquelyReferenced() +#include "pycore_unicodeobject.h" // _Py_MAX_UNICODE + + +#define MAX_UNICODE _Py_MAX_UNICODE +#define ensure_unicode _PyUnicode_EnsureUnicode + +struct unicode_formatter_t { + PyObject *args; + int args_owned; + Py_ssize_t arglen, argidx; + PyObject *dict; + + int fmtkind; + Py_ssize_t fmtcnt, fmtpos; + const void *fmtdata; + PyObject *fmtstr; + + _PyUnicodeWriter writer; +}; + + +struct unicode_format_arg_t { + Py_UCS4 ch; + int flags; + Py_ssize_t width; + int prec; + int sign; +}; + + +static PyObject * +unicode_format_getnextarg(struct unicode_formatter_t *ctx) +{ + Py_ssize_t argidx = ctx->argidx; + + if (argidx < ctx->arglen) { + ctx->argidx++; + if (ctx->arglen < 0) + return ctx->args; + else + return PyTuple_GetItem(ctx->args, argidx); + } + PyErr_SetString(PyExc_TypeError, + "not enough arguments for format string"); + return NULL; +} + + +/* Returns a new reference to a PyUnicode object, or NULL on failure. */ + +/* Format a float into the writer if the writer is not NULL, or into *p_output + otherwise. + + Return 0 on success, raise an exception and return -1 on error. */ +static int +formatfloat(PyObject *v, struct unicode_format_arg_t *arg, + PyObject **p_output, + _PyUnicodeWriter *writer) +{ + char *p; + double x; + Py_ssize_t len; + int prec; + int dtoa_flags = 0; + + x = PyFloat_AsDouble(v); + if (x == -1.0 && PyErr_Occurred()) + return -1; + + prec = arg->prec; + if (prec < 0) + prec = 6; + + if (arg->flags & F_ALT) + dtoa_flags |= Py_DTSF_ALT; + p = PyOS_double_to_string(x, arg->ch, prec, dtoa_flags, NULL); + if (p == NULL) + return -1; + len = strlen(p); + if (writer) { + if (_PyUnicodeWriter_WriteASCIIString(writer, p, len) < 0) { + PyMem_Free(p); + return -1; + } + } + else + *p_output = _PyUnicode_FromASCII(p, len); + PyMem_Free(p); + return 0; +} + + +/* formatlong() emulates the format codes d, u, o, x and X, and + * the F_ALT flag, for Python's long (unbounded) ints. It's not used for + * Python's regular ints. + * Return value: a new PyUnicodeObject*, or NULL if error. + * The output string is of the form + * "-"? ("0x" | "0X")? digit+ + * "0x"/"0X" are present only for x and X conversions, with F_ALT + * set in flags. The case of hex digits will be correct, + * There will be at least prec digits, zero-filled on the left if + * necessary to get that many. + * val object to be converted + * flags bitmask of format flags; only F_ALT is looked at + * prec minimum number of digits; 0-fill on left if needed + * type a character in [duoxX]; u acts the same as d + * + * CAUTION: o, x and X conversions on regular ints can never + * produce a '-' sign, but can for Python's unbounded ints. + */ +PyObject * +_PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type) +{ + PyObject *result = NULL; + char *buf; + Py_ssize_t i; + int sign; /* 1 if '-', else 0 */ + int len; /* number of characters */ + Py_ssize_t llen; + int numdigits; /* len == numnondigits + numdigits */ + int numnondigits = 0; + + /* Avoid exceeding SSIZE_T_MAX */ + if (prec > INT_MAX-3) { + PyErr_SetString(PyExc_OverflowError, + "precision too large"); + return NULL; + } + + assert(PyLong_Check(val)); + + switch (type) { + default: + Py_UNREACHABLE(); + case 'd': + case 'i': + case 'u': + /* int and int subclasses should print numerically when a numeric */ + /* format code is used (see issue18780) */ + result = PyNumber_ToBase(val, 10); + break; + case 'o': + numnondigits = 2; + result = PyNumber_ToBase(val, 8); + break; + case 'x': + case 'X': + numnondigits = 2; + result = PyNumber_ToBase(val, 16); + break; + } + if (!result) + return NULL; + + assert(_PyUnicode_IsModifiable(result)); + assert(PyUnicode_IS_ASCII(result)); + + /* To modify the string in-place, there can only be one reference. */ + if (!_PyObject_IsUniquelyReferenced(result)) { + Py_DECREF(result); + PyErr_BadInternalCall(); + return NULL; + } + buf = PyUnicode_DATA(result); + llen = PyUnicode_GET_LENGTH(result); + if (llen > INT_MAX) { + Py_DECREF(result); + PyErr_SetString(PyExc_ValueError, + "string too large in _PyUnicode_FormatLong"); + return NULL; + } + len = (int)llen; + sign = buf[0] == '-'; + numnondigits += sign; + numdigits = len - numnondigits; + assert(numdigits > 0); + + /* Get rid of base marker unless F_ALT */ + if (((alt) == 0 && + (type == 'o' || type == 'x' || type == 'X'))) { + assert(buf[sign] == '0'); + assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' || + buf[sign+1] == 'o'); + numnondigits -= 2; + buf += 2; + len -= 2; + if (sign) + buf[0] = '-'; + assert(len == numnondigits + numdigits); + assert(numdigits > 0); + } + + /* Fill with leading zeroes to meet minimum width. */ + if (prec > numdigits) { + PyObject *r1 = PyBytes_FromStringAndSize(NULL, + numnondigits + prec); + char *b1; + if (!r1) { + Py_DECREF(result); + return NULL; + } + b1 = PyBytes_AS_STRING(r1); + for (i = 0; i < numnondigits; ++i) + *b1++ = *buf++; + for (i = 0; i < prec - numdigits; i++) + *b1++ = '0'; + for (i = 0; i < numdigits; i++) + *b1++ = *buf++; + *b1 = '\0'; + Py_SETREF(result, r1); + buf = PyBytes_AS_STRING(result); + len = numnondigits + prec; + } + + /* Fix up case for hex conversions. */ + if (type == 'X') { + /* Need to convert all lower case letters to upper case. + and need to convert 0x to 0X (and -0x to -0X). */ + for (i = 0; i < len; i++) + if (buf[i] >= 'a' && buf[i] <= 'x') + buf[i] -= 'a'-'A'; + } + if (!PyUnicode_Check(result) + || buf != PyUnicode_DATA(result)) { + PyObject *unicode; + unicode = _PyUnicode_FromASCII(buf, len); + Py_SETREF(result, unicode); + } + else if (len != PyUnicode_GET_LENGTH(result)) { + if (PyUnicode_Resize(&result, len) < 0) + Py_CLEAR(result); + } + return result; +} + + +/* Format an integer or a float as an integer. + * Return 1 if the number has been formatted into the writer, + * 0 if the number has been formatted into *p_output + * -1 and raise an exception on error */ +static int +mainformatlong(PyObject *v, + struct unicode_format_arg_t *arg, + PyObject **p_output, + _PyUnicodeWriter *writer) +{ + PyObject *iobj, *res; + char type = (char)arg->ch; + + if (!PyNumber_Check(v)) + goto wrongtype; + + /* make sure number is a type of integer for o, x, and X */ + if (!PyLong_Check(v)) { + if (type == 'o' || type == 'x' || type == 'X') { + iobj = _PyNumber_Index(v); + } + else { + iobj = PyNumber_Long(v); + } + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; + } + assert(PyLong_Check(iobj)); + } + else { + iobj = Py_NewRef(v); + } + + if (PyLong_CheckExact(v) + && arg->width == -1 && arg->prec == -1 + && !(arg->flags & (F_SIGN | F_BLANK)) + && type != 'X') + { + /* Fast path */ + int alternate = arg->flags & F_ALT; + int base; + + switch(type) + { + default: + Py_UNREACHABLE(); + case 'd': + case 'i': + case 'u': + base = 10; + break; + case 'o': + base = 8; + break; + case 'x': + case 'X': + base = 16; + break; + } + + if (_PyLong_FormatWriter(writer, v, base, alternate) == -1) { + Py_DECREF(iobj); + return -1; + } + Py_DECREF(iobj); + return 1; + } + + res = _PyUnicode_FormatLong(iobj, arg->flags & F_ALT, arg->prec, type); + Py_DECREF(iobj); + if (res == NULL) + return -1; + *p_output = res; + return 0; + +wrongtype: + switch(type) + { + case 'o': + case 'x': + case 'X': + PyErr_Format(PyExc_TypeError, + "%%%c format: an integer is required, " + "not %.200s", + type, Py_TYPE(v)->tp_name); + break; + default: + PyErr_Format(PyExc_TypeError, + "%%%c format: a real number is required, " + "not %.200s", + type, Py_TYPE(v)->tp_name); + break; + } + return -1; +} + + +static Py_UCS4 +formatchar(PyObject *v) +{ + /* presume that the buffer is at least 3 characters long */ + if (PyUnicode_Check(v)) { + if (PyUnicode_GET_LENGTH(v) == 1) { + return PyUnicode_READ_CHAR(v, 0); + } + PyErr_Format(PyExc_TypeError, + "%%c requires an int or a unicode character, " + "not a string of length %zd", + PyUnicode_GET_LENGTH(v)); + return (Py_UCS4) -1; + } + else { + int overflow; + long x = PyLong_AsLongAndOverflow(v, &overflow); + if (x == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Format(PyExc_TypeError, + "%%c requires an int or a unicode character, not %T", + v); + return (Py_UCS4) -1; + } + return (Py_UCS4) -1; + } + + if (x < 0 || x > MAX_UNICODE) { + /* this includes an overflow in converting to C long */ + PyErr_SetString(PyExc_OverflowError, + "%c arg not in range(0x110000)"); + return (Py_UCS4) -1; + } + + return (Py_UCS4) x; + } +} + + +/* Parse options of an argument: flags, width, precision. + Handle also "%(name)" syntax. + + Return 0 if the argument has been formatted into arg->str. + Return 1 if the argument has been written into ctx->writer, + Raise an exception and return -1 on error. */ +static int +unicode_format_arg_parse(struct unicode_formatter_t *ctx, + struct unicode_format_arg_t *arg) +{ +#define FORMAT_READ(ctx) \ + PyUnicode_READ((ctx)->fmtkind, (ctx)->fmtdata, (ctx)->fmtpos) + + PyObject *v; + + if (arg->ch == '(') { + /* Get argument value from a dictionary. Example: "%(name)s". */ + Py_ssize_t keystart; + Py_ssize_t keylen; + PyObject *key; + int pcount = 1; + + if (ctx->dict == NULL) { + PyErr_SetString(PyExc_TypeError, + "format requires a mapping"); + return -1; + } + ++ctx->fmtpos; + --ctx->fmtcnt; + keystart = ctx->fmtpos; + /* Skip over balanced parentheses */ + while (pcount > 0 && --ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + if (arg->ch == ')') + --pcount; + else if (arg->ch == '(') + ++pcount; + ctx->fmtpos++; + } + keylen = ctx->fmtpos - keystart - 1; + if (ctx->fmtcnt < 0 || pcount > 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format key"); + return -1; + } + key = PyUnicode_Substring(ctx->fmtstr, + keystart, keystart + keylen); + if (key == NULL) + return -1; + if (ctx->args_owned) { + ctx->args_owned = 0; + Py_DECREF(ctx->args); + } + ctx->args = PyObject_GetItem(ctx->dict, key); + Py_DECREF(key); + if (ctx->args == NULL) + return -1; + ctx->args_owned = 1; + ctx->arglen = -1; + ctx->argidx = -2; + } + + /* Parse flags. Example: "%+i" => flags=F_SIGN. */ + while (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + switch (arg->ch) { + case '-': arg->flags |= F_LJUST; continue; + case '+': arg->flags |= F_SIGN; continue; + case ' ': arg->flags |= F_BLANK; continue; + case '#': arg->flags |= F_ALT; continue; + case '0': arg->flags |= F_ZERO; continue; + } + break; + } + + /* Parse width. Example: "%10s" => width=10 */ + if (arg->ch == '*') { + v = unicode_format_getnextarg(ctx); + if (v == NULL) + return -1; + if (!PyLong_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "* wants int"); + return -1; + } + arg->width = PyLong_AsSsize_t(v); + if (arg->width == -1 && PyErr_Occurred()) + return -1; + if (arg->width < 0) { + arg->flags |= F_LJUST; + arg->width = -arg->width; + } + if (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + } + } + else if (arg->ch >= '0' && arg->ch <= '9') { + arg->width = arg->ch - '0'; + while (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + if (arg->ch < '0' || arg->ch > '9') + break; + /* Since arg->ch is unsigned, the RHS would end up as unsigned, + mixing signed and unsigned comparison. Since arg->ch is between + '0' and '9', casting to int is safe. */ + if (arg->width > (PY_SSIZE_T_MAX - ((int)arg->ch - '0')) / 10) { + PyErr_SetString(PyExc_ValueError, + "width too big"); + return -1; + } + arg->width = arg->width*10 + (arg->ch - '0'); + } + } + + /* Parse precision. Example: "%.3f" => prec=3 */ + if (arg->ch == '.') { + arg->prec = 0; + if (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + } + if (arg->ch == '*') { + v = unicode_format_getnextarg(ctx); + if (v == NULL) + return -1; + if (!PyLong_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "* wants int"); + return -1; + } + arg->prec = PyLong_AsInt(v); + if (arg->prec == -1 && PyErr_Occurred()) + return -1; + if (arg->prec < 0) + arg->prec = 0; + if (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + } + } + else if (arg->ch >= '0' && arg->ch <= '9') { + arg->prec = arg->ch - '0'; + while (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + if (arg->ch < '0' || arg->ch > '9') + break; + if (arg->prec > (INT_MAX - ((int)arg->ch - '0')) / 10) { + PyErr_SetString(PyExc_ValueError, + "precision too big"); + return -1; + } + arg->prec = arg->prec*10 + (arg->ch - '0'); + } + } + } + + /* Ignore "h", "l" and "L" format prefix (ex: "%hi" or "%ls") */ + if (ctx->fmtcnt >= 0) { + if (arg->ch == 'h' || arg->ch == 'l' || arg->ch == 'L') { + if (--ctx->fmtcnt >= 0) { + arg->ch = FORMAT_READ(ctx); + ctx->fmtpos++; + } + } + } + if (ctx->fmtcnt < 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format"); + return -1; + } + return 0; + +#undef FORMAT_READ +} + + +/* Format one argument. Supported conversion specifiers: + + - "s", "r", "a": any type + - "i", "d", "u": int or float + - "o", "x", "X": int + - "e", "E", "f", "F", "g", "G": float + - "c": int or str (1 character) + + When possible, the output is written directly into the Unicode writer + (ctx->writer). A string is created when padding is required. + + Return 0 if the argument has been formatted into *p_str, + 1 if the argument has been written into ctx->writer, + -1 on error. */ +static int +unicode_format_arg_format(struct unicode_formatter_t *ctx, + struct unicode_format_arg_t *arg, + PyObject **p_str) +{ + PyObject *v; + _PyUnicodeWriter *writer = &ctx->writer; + + if (ctx->fmtcnt == 0) + ctx->writer.overallocate = 0; + + v = unicode_format_getnextarg(ctx); + if (v == NULL) + return -1; + + + switch (arg->ch) { + case 's': + case 'r': + case 'a': + if (PyLong_CheckExact(v) && arg->width == -1 && arg->prec == -1) { + /* Fast path */ + if (_PyLong_FormatWriter(writer, v, 10, arg->flags & F_ALT) == -1) + return -1; + return 1; + } + + if (PyUnicode_CheckExact(v) && arg->ch == 's') { + *p_str = Py_NewRef(v); + } + else { + if (arg->ch == 's') + *p_str = PyObject_Str(v); + else if (arg->ch == 'r') + *p_str = PyObject_Repr(v); + else + *p_str = PyObject_ASCII(v); + } + break; + + case 'i': + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + { + int ret = mainformatlong(v, arg, p_str, writer); + if (ret != 0) + return ret; + arg->sign = 1; + break; + } + + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + if (arg->width == -1 && arg->prec == -1 + && !(arg->flags & (F_SIGN | F_BLANK))) + { + /* Fast path */ + if (formatfloat(v, arg, NULL, writer) == -1) + return -1; + return 1; + } + + arg->sign = 1; + if (formatfloat(v, arg, p_str, NULL) == -1) + return -1; + break; + + case 'c': + { + Py_UCS4 ch = formatchar(v); + if (ch == (Py_UCS4) -1) + return -1; + if (arg->width == -1 && arg->prec == -1) { + /* Fast path */ + if (_PyUnicodeWriter_WriteCharInline(writer, ch) < 0) + return -1; + return 1; + } + *p_str = PyUnicode_FromOrdinal(ch); + break; + } + + default: + PyErr_Format(PyExc_ValueError, + "unsupported format character '%c' (0x%x) " + "at index %zd", + (31<=arg->ch && arg->ch<=126) ? (char)arg->ch : '?', + (int)arg->ch, + ctx->fmtpos - 1); + return -1; + } + if (*p_str == NULL) + return -1; + assert (PyUnicode_Check(*p_str)); + return 0; +} + + +static int +unicode_format_arg_output(struct unicode_formatter_t *ctx, + struct unicode_format_arg_t *arg, + PyObject *str) +{ + Py_ssize_t len; + int kind; + const void *pbuf; + Py_ssize_t pindex; + Py_UCS4 signchar; + Py_ssize_t buflen; + Py_UCS4 maxchar; + Py_ssize_t sublen; + _PyUnicodeWriter *writer = &ctx->writer; + Py_UCS4 fill; + + fill = ' '; + if (arg->sign && arg->flags & F_ZERO) + fill = '0'; + + len = PyUnicode_GET_LENGTH(str); + if ((arg->width == -1 || arg->width <= len) + && (arg->prec == -1 || arg->prec >= len) + && !(arg->flags & (F_SIGN | F_BLANK))) + { + /* Fast path */ + if (_PyUnicodeWriter_WriteStr(writer, str) == -1) + return -1; + return 0; + } + + /* Truncate the string for "s", "r" and "a" formats + if the precision is set */ + if (arg->ch == 's' || arg->ch == 'r' || arg->ch == 'a') { + if (arg->prec >= 0 && len > arg->prec) + len = arg->prec; + } + + /* Adjust sign and width */ + kind = PyUnicode_KIND(str); + pbuf = PyUnicode_DATA(str); + pindex = 0; + signchar = '\0'; + if (arg->sign) { + Py_UCS4 ch = PyUnicode_READ(kind, pbuf, pindex); + if (ch == '-' || ch == '+') { + signchar = ch; + len--; + pindex++; + } + else if (arg->flags & F_SIGN) + signchar = '+'; + else if (arg->flags & F_BLANK) + signchar = ' '; + else + arg->sign = 0; + } + if (arg->width < len) + arg->width = len; + + /* Prepare the writer */ + maxchar = writer->maxchar; + if (!(arg->flags & F_LJUST)) { + if (arg->sign) { + if ((arg->width-1) > len) + maxchar = Py_MAX(maxchar, fill); + } + else { + if (arg->width > len) + maxchar = Py_MAX(maxchar, fill); + } + } + if (PyUnicode_MAX_CHAR_VALUE(str) > maxchar) { + Py_UCS4 strmaxchar = _PyUnicode_FindMaxChar(str, 0, pindex+len); + maxchar = Py_MAX(maxchar, strmaxchar); + } + + buflen = arg->width; + if (arg->sign && len == arg->width) + buflen++; + if (_PyUnicodeWriter_Prepare(writer, buflen, maxchar) == -1) + return -1; + + /* Write the sign if needed */ + if (arg->sign) { + if (fill != ' ') { + PyUnicode_WRITE(writer->kind, writer->data, writer->pos, signchar); + writer->pos += 1; + } + if (arg->width > len) + arg->width--; + } + + /* Write the numeric prefix for "x", "X" and "o" formats + if the alternate form is used. + For example, write "0x" for the "%#x" format. */ + if ((arg->flags & F_ALT) && (arg->ch == 'x' || arg->ch == 'X' || arg->ch == 'o')) { + assert(PyUnicode_READ(kind, pbuf, pindex) == '0'); + assert(PyUnicode_READ(kind, pbuf, pindex + 1) == arg->ch); + if (fill != ' ') { + PyUnicode_WRITE(writer->kind, writer->data, writer->pos, '0'); + PyUnicode_WRITE(writer->kind, writer->data, writer->pos+1, arg->ch); + writer->pos += 2; + pindex += 2; + } + arg->width -= 2; + if (arg->width < 0) + arg->width = 0; + len -= 2; + } + + /* Pad left with the fill character if needed */ + if (arg->width > len && !(arg->flags & F_LJUST)) { + sublen = arg->width - len; + _PyUnicode_Fill(writer->kind, writer->data, fill, writer->pos, sublen); + writer->pos += sublen; + arg->width = len; + } + + /* If padding with spaces: write sign if needed and/or numeric prefix if + the alternate form is used */ + if (fill == ' ') { + if (arg->sign) { + PyUnicode_WRITE(writer->kind, writer->data, writer->pos, signchar); + writer->pos += 1; + } + if ((arg->flags & F_ALT) && (arg->ch == 'x' || arg->ch == 'X' || arg->ch == 'o')) { + assert(PyUnicode_READ(kind, pbuf, pindex) == '0'); + assert(PyUnicode_READ(kind, pbuf, pindex+1) == arg->ch); + PyUnicode_WRITE(writer->kind, writer->data, writer->pos, '0'); + PyUnicode_WRITE(writer->kind, writer->data, writer->pos+1, arg->ch); + writer->pos += 2; + pindex += 2; + } + } + + /* Write characters */ + if (len) { + _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, + str, pindex, len); + writer->pos += len; + } + + /* Pad right with the fill character if needed */ + if (arg->width > len) { + sublen = arg->width - len; + _PyUnicode_Fill(writer->kind, writer->data, ' ', writer->pos, sublen); + writer->pos += sublen; + } + return 0; +} + + +/* Helper of PyUnicode_Format(): format one arg. + Return 0 on success, raise an exception and return -1 on error. */ +static int +unicode_format_arg(struct unicode_formatter_t *ctx) +{ + struct unicode_format_arg_t arg; + PyObject *str; + int ret; + + arg.ch = PyUnicode_READ(ctx->fmtkind, ctx->fmtdata, ctx->fmtpos); + if (arg.ch == '%') { + ctx->fmtpos++; + ctx->fmtcnt--; + if (_PyUnicodeWriter_WriteCharInline(&ctx->writer, '%') < 0) + return -1; + return 0; + } + arg.flags = 0; + arg.width = -1; + arg.prec = -1; + arg.sign = 0; + str = NULL; + + ret = unicode_format_arg_parse(ctx, &arg); + if (ret == -1) + return -1; + + ret = unicode_format_arg_format(ctx, &arg, &str); + if (ret == -1) + return -1; + + if (ret != 1) { + ret = unicode_format_arg_output(ctx, &arg, str); + Py_DECREF(str); + if (ret == -1) + return -1; + } + + if (ctx->dict && (ctx->argidx < ctx->arglen)) { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + return -1; + } + return 0; +} + + +PyObject * +PyUnicode_Format(PyObject *format, PyObject *args) +{ + struct unicode_formatter_t ctx; + + if (format == NULL || args == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + if (ensure_unicode(format) < 0) + return NULL; + + ctx.fmtstr = format; + ctx.fmtdata = PyUnicode_DATA(ctx.fmtstr); + ctx.fmtkind = PyUnicode_KIND(ctx.fmtstr); + ctx.fmtcnt = PyUnicode_GET_LENGTH(ctx.fmtstr); + ctx.fmtpos = 0; + + _PyUnicodeWriter_Init(&ctx.writer); + ctx.writer.min_length = ctx.fmtcnt + 100; + ctx.writer.overallocate = 1; + + if (PyTuple_Check(args)) { + ctx.arglen = PyTuple_Size(args); + ctx.argidx = 0; + } + else { + ctx.arglen = -1; + ctx.argidx = -2; + } + ctx.args_owned = 0; + if (PyMapping_Check(args) && !PyTuple_Check(args) && !PyUnicode_Check(args)) + ctx.dict = args; + else + ctx.dict = NULL; + ctx.args = args; + + while (--ctx.fmtcnt >= 0) { + if (PyUnicode_READ(ctx.fmtkind, ctx.fmtdata, ctx.fmtpos) != '%') { + Py_ssize_t nonfmtpos; + + nonfmtpos = ctx.fmtpos++; + while (ctx.fmtcnt >= 0 && + PyUnicode_READ(ctx.fmtkind, ctx.fmtdata, ctx.fmtpos) != '%') { + ctx.fmtpos++; + ctx.fmtcnt--; + } + if (ctx.fmtcnt < 0) { + ctx.fmtpos--; + ctx.writer.overallocate = 0; + } + + if (_PyUnicodeWriter_WriteSubstring(&ctx.writer, ctx.fmtstr, + nonfmtpos, ctx.fmtpos) < 0) + goto onError; + } + else { + ctx.fmtpos++; + if (unicode_format_arg(&ctx) == -1) + goto onError; + } + } + + if (ctx.argidx < ctx.arglen && !ctx.dict) { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + goto onError; + } + + if (ctx.args_owned) { + Py_DECREF(ctx.args); + } + return _PyUnicodeWriter_Finish(&ctx.writer); + + onError: + _PyUnicodeWriter_Dealloc(&ctx.writer); + if (ctx.args_owned) { + Py_DECREF(ctx.args); + } + return NULL; +} diff --git a/Python/formatter_unicode.c b/Objects/unicode_formatter.c similarity index 88% rename from Python/formatter_unicode.c rename to Objects/unicode_formatter.c index 30807f428c7..b8604d13559 100644 --- a/Python/formatter_unicode.c +++ b/Objects/unicode_formatter.c @@ -8,6 +8,241 @@ #include "pycore_unicodeobject.h" // PyUnicode_MAX_CHAR_VALUE() #include <locale.h> + +/* _PyUnicode_InsertThousandsGrouping() helper functions */ + +typedef struct { + const char *grouping; + char previous; + Py_ssize_t i; /* Where we're currently pointing in grouping. */ +} GroupGenerator; + + +static void +GroupGenerator_init(GroupGenerator *self, const char *grouping) +{ + self->grouping = grouping; + self->i = 0; + self->previous = 0; +} + + +/* Returns the next grouping, or 0 to signify end. */ +static Py_ssize_t +GroupGenerator_next(GroupGenerator *self) +{ + /* Note that we don't really do much error checking here. If a + grouping string contains just CHAR_MAX, for example, then just + terminate the generator. That shouldn't happen, but at least we + fail gracefully. */ + switch (self->grouping[self->i]) { + case 0: + return self->previous; + case CHAR_MAX: + /* Stop the generator. */ + return 0; + default: { + char ch = self->grouping[self->i]; + self->previous = ch; + self->i++; + return (Py_ssize_t)ch; + } + } +} + + +/* Fill in some digits, leading zeros, and thousands separator. All + are optional, depending on when we're called. */ +static void +InsertThousandsGrouping_fill(_PyUnicodeWriter *writer, Py_ssize_t *buffer_pos, + PyObject *digits, Py_ssize_t *digits_pos, + Py_ssize_t n_chars, Py_ssize_t n_zeros, + PyObject *thousands_sep, Py_ssize_t thousands_sep_len, + Py_UCS4 *maxchar, int forward) +{ + if (!writer) { + /* if maxchar > 127, maxchar is already set */ + if (*maxchar == 127 && thousands_sep) { + Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE(thousands_sep); + *maxchar = Py_MAX(*maxchar, maxchar2); + } + return; + } + + if (thousands_sep) { + if (!forward) { + *buffer_pos -= thousands_sep_len; + } + /* Copy the thousands_sep chars into the buffer. */ + _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos, + thousands_sep, 0, + thousands_sep_len); + if (forward) { + *buffer_pos += thousands_sep_len; + } + } + + if (!forward) { + *buffer_pos -= n_chars; + *digits_pos -= n_chars; + } + _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos, + digits, *digits_pos, + n_chars); + if (forward) { + *buffer_pos += n_chars; + *digits_pos += n_chars; + } + + if (n_zeros) { + if (!forward) { + *buffer_pos -= n_zeros; + } + int kind = PyUnicode_KIND(writer->buffer); + void *data = PyUnicode_DATA(writer->buffer); + _PyUnicode_Fill(kind, data, '0', *buffer_pos, n_zeros); + if (forward) { + *buffer_pos += n_zeros; + } + } +} + + +/** + * InsertThousandsGrouping: + * @writer: Unicode writer. + * @n_buffer: Number of characters in @buffer. + * @digits: Digits we're reading from. If count is non-NULL, this is unused. + * @d_pos: Start of digits string. + * @n_digits: The number of digits in the string, in which we want + * to put the grouping chars. + * @min_width: The minimum width of the digits in the output string. + * Output will be zero-padded on the left to fill. + * @grouping: see definition in localeconv(). + * @thousands_sep: see definition in localeconv(). + * + * There are 2 modes: counting and filling. If @writer is NULL, + * we are in counting mode, else filling mode. + * If counting, the required buffer size is returned. + * If filling, we know the buffer will be large enough, so we don't + * need to pass in the buffer size. + * Inserts thousand grouping characters (as defined by grouping and + * thousands_sep) into @writer. + * + * Return value: -1 on error, number of characters otherwise. + **/ +static Py_ssize_t +_PyUnicode_InsertThousandsGrouping( + _PyUnicodeWriter *writer, + Py_ssize_t n_buffer, + PyObject *digits, + Py_ssize_t d_pos, + Py_ssize_t n_digits, + Py_ssize_t min_width, + const char *grouping, + PyObject *thousands_sep, + Py_UCS4 *maxchar, + int forward) +{ + min_width = Py_MAX(0, min_width); + if (writer) { + assert(digits != NULL); + assert(maxchar == NULL); + } + else { + assert(digits == NULL); + assert(maxchar != NULL); + } + assert(0 <= d_pos); + assert(0 <= n_digits); + assert(grouping != NULL); + + Py_ssize_t count = 0; + Py_ssize_t n_zeros; + int loop_broken = 0; + int use_separator = 0; /* First time through, don't append the + separator. They only go between + groups. */ + Py_ssize_t buffer_pos; + Py_ssize_t digits_pos; + Py_ssize_t len; + Py_ssize_t n_chars; + Py_ssize_t remaining = n_digits; /* Number of chars remaining to + be looked at */ + /* A generator that returns all of the grouping widths, until it + returns 0. */ + GroupGenerator groupgen; + GroupGenerator_init(&groupgen, grouping); + const Py_ssize_t thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep); + + /* if digits are not grouped, thousands separator + should be an empty string */ + assert(!(grouping[0] == CHAR_MAX && thousands_sep_len != 0)); + + digits_pos = d_pos + (forward ? 0 : n_digits); + if (writer) { + buffer_pos = writer->pos + (forward ? 0 : n_buffer); + assert(buffer_pos <= PyUnicode_GET_LENGTH(writer->buffer)); + assert(digits_pos <= PyUnicode_GET_LENGTH(digits)); + } + else { + buffer_pos = forward ? 0 : n_buffer; + } + + if (!writer) { + *maxchar = 127; + } + + while ((len = GroupGenerator_next(&groupgen)) > 0) { + len = Py_MIN(len, Py_MAX(Py_MAX(remaining, min_width), 1)); + n_zeros = Py_MAX(0, len - remaining); + n_chars = Py_MAX(0, Py_MIN(remaining, len)); + + /* Use n_zero zero's and n_chars chars */ + + /* Count only, don't do anything. */ + count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars; + + /* Copy into the writer. */ + InsertThousandsGrouping_fill(writer, &buffer_pos, + digits, &digits_pos, + n_chars, n_zeros, + use_separator ? thousands_sep : NULL, + thousands_sep_len, maxchar, forward); + + /* Use a separator next time. */ + use_separator = 1; + + remaining -= n_chars; + min_width -= len; + + if (remaining <= 0 && min_width <= 0) { + loop_broken = 1; + break; + } + min_width -= thousands_sep_len; + } + if (!loop_broken) { + /* We left the loop without using a break statement. */ + + len = Py_MAX(Py_MAX(remaining, min_width), 1); + n_zeros = Py_MAX(0, len - remaining); + n_chars = Py_MAX(0, Py_MIN(remaining, len)); + + /* Use n_zero zero's and n_chars chars */ + count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars; + + /* Copy into the writer. */ + InsertThousandsGrouping_fill(writer, &buffer_pos, + digits, &digits_pos, + n_chars, n_zeros, + use_separator ? thousands_sep : NULL, + thousands_sep_len, maxchar, forward); + } + return count; +} + + /* Raises an exception about an unknown presentation type for this * type. */ diff --git a/Objects/unicode_writer.c b/Objects/unicode_writer.c new file mode 100644 index 00000000000..2b944bf1ea8 --- /dev/null +++ b/Objects/unicode_writer.c @@ -0,0 +1,639 @@ +/* + +Unicode implementation based on original code by Fredrik Lundh, +modified by Marc-Andre Lemburg <mal@lemburg.com>. + +Major speed upgrades to the method implementations at the Reykjavik +NeedForSpeed sprint, by Fredrik Lundh and Andrew Dalke. + +Copyright (c) Corporation for National Research Initiatives. + +-------------------------------------------------------------------- +The original string type implementation is: + + Copyright (c) 1999 by Secret Labs AB + Copyright (c) 1999 by Fredrik Lundh + +By obtaining, using, and/or copying this software and/or its +associated documentation, you agree that you have read, understood, +and will comply with the following terms and conditions: + +Permission to use, copy, modify, and distribute this software and its +associated documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies, and that both that copyright notice and this permission notice +appear in supporting documentation, and that the name of Secret Labs +AB or the author not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-------------------------------------------------------------------- + +*/ + +#include "Python.h" +#include "pycore_freelist.h" // _Py_FREELIST_FREE() +#include "pycore_long.h" // _PyLong_FormatWriter() +#include "pycore_unicodeobject.h" // _PyUnicode_Result() + + +#ifdef MS_WINDOWS + /* On Windows, overallocate by 50% is the best factor */ +# define OVERALLOCATE_FACTOR 2 +#else + /* On Linux, overallocate by 25% is the best factor */ +# define OVERALLOCATE_FACTOR 4 +#endif + + +/* Compilation of templated routines */ + +#define STRINGLIB_GET_EMPTY() _PyUnicode_GetEmpty() + +#include "stringlib/ucs1lib.h" +#include "stringlib/find_max_char.h" +#include "stringlib/undef.h" + + +/* Copy an ASCII or latin1 char* string into a Python Unicode string. + + WARNING: The function doesn't copy the terminating null character and + doesn't check the maximum character (may write a latin1 character in an + ASCII string). */ +static void +unicode_write_cstr(PyObject *unicode, Py_ssize_t index, + const char *str, Py_ssize_t len) +{ + int kind = PyUnicode_KIND(unicode); + const void *data = PyUnicode_DATA(unicode); + const char *end = str + len; + + assert(index + len <= PyUnicode_GET_LENGTH(unicode)); + switch (kind) { + case PyUnicode_1BYTE_KIND: { +#ifdef Py_DEBUG + if (PyUnicode_IS_ASCII(unicode)) { + Py_UCS4 maxchar = ucs1lib_find_max_char( + (const Py_UCS1*)str, + (const Py_UCS1*)str + len); + assert(maxchar < 128); + } +#endif + memcpy((char *) data + index, str, len); + break; + } + case PyUnicode_2BYTE_KIND: { + Py_UCS2 *start = (Py_UCS2 *)data + index; + Py_UCS2 *ucs2 = start; + + for (; str < end; ++ucs2, ++str) + *ucs2 = (Py_UCS2)*str; + + assert((ucs2 - start) <= PyUnicode_GET_LENGTH(unicode)); + break; + } + case PyUnicode_4BYTE_KIND: { + Py_UCS4 *start = (Py_UCS4 *)data + index; + Py_UCS4 *ucs4 = start; + + for (; str < end; ++ucs4, ++str) + *ucs4 = (Py_UCS4)*str; + + assert((ucs4 - start) <= PyUnicode_GET_LENGTH(unicode)); + break; + } + default: + Py_UNREACHABLE(); + } +} + + +static inline void +_PyUnicodeWriter_Update(_PyUnicodeWriter *writer) +{ + writer->maxchar = PyUnicode_MAX_CHAR_VALUE(writer->buffer); + writer->data = PyUnicode_DATA(writer->buffer); + + if (!writer->readonly) { + writer->kind = PyUnicode_KIND(writer->buffer); + writer->size = PyUnicode_GET_LENGTH(writer->buffer); + } + else { + /* use a value smaller than PyUnicode_1BYTE_KIND() so + _PyUnicodeWriter_PrepareKind() will copy the buffer. */ + writer->kind = 0; + assert(writer->kind <= PyUnicode_1BYTE_KIND); + + /* Copy-on-write mode: set buffer size to 0 so + * _PyUnicodeWriter_Prepare() will copy (and enlarge) the buffer on + * next write. */ + writer->size = 0; + } +} + + +void +_PyUnicodeWriter_Init(_PyUnicodeWriter *writer) +{ + memset(writer, 0, sizeof(*writer)); + + /* ASCII is the bare minimum */ + writer->min_char = 127; + + /* use a kind value smaller than PyUnicode_1BYTE_KIND so + _PyUnicodeWriter_PrepareKind() will copy the buffer. */ + assert(writer->kind == 0); + assert(writer->kind < PyUnicode_1BYTE_KIND); +} + + +PyUnicodeWriter* +PyUnicodeWriter_Create(Py_ssize_t length) +{ + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length must be positive"); + return NULL; + } + + const size_t size = sizeof(_PyUnicodeWriter); + PyUnicodeWriter *pub_writer; + pub_writer = _Py_FREELIST_POP_MEM(unicode_writers); + if (pub_writer == NULL) { + pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size); + if (pub_writer == NULL) { + return (PyUnicodeWriter *)PyErr_NoMemory(); + } + } + _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer; + + _PyUnicodeWriter_Init(writer); + if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) { + PyUnicodeWriter_Discard(pub_writer); + return NULL; + } + writer->overallocate = 1; + + return pub_writer; +} + + +void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) +{ + if (writer == NULL) { + return; + } + _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer); + _Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free); +} + + +// Initialize _PyUnicodeWriter with initial buffer +void +_PyUnicodeWriter_InitWithBuffer(_PyUnicodeWriter *writer, PyObject *buffer) +{ + memset(writer, 0, sizeof(*writer)); + writer->buffer = buffer; + _PyUnicodeWriter_Update(writer); + writer->min_length = writer->size; +} + + +int +_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, + Py_ssize_t length, Py_UCS4 maxchar) +{ + Py_ssize_t newlen; + PyObject *newbuffer; + + assert(length >= 0); + assert(maxchar <= _Py_MAX_UNICODE); + + /* ensure that the _PyUnicodeWriter_Prepare macro was used */ + assert((maxchar > writer->maxchar && length >= 0) + || length > 0); + + if (length > PY_SSIZE_T_MAX - writer->pos) { + PyErr_NoMemory(); + return -1; + } + newlen = writer->pos + length; + + maxchar = Py_MAX(maxchar, writer->min_char); + + if (writer->buffer == NULL) { + assert(!writer->readonly); + if (writer->overallocate + && newlen <= (PY_SSIZE_T_MAX - newlen / OVERALLOCATE_FACTOR)) { + /* overallocate to limit the number of realloc() */ + newlen += newlen / OVERALLOCATE_FACTOR; + } + if (newlen < writer->min_length) + newlen = writer->min_length; + + writer->buffer = PyUnicode_New(newlen, maxchar); + if (writer->buffer == NULL) + return -1; + } + else if (newlen > writer->size) { + if (writer->overallocate + && newlen <= (PY_SSIZE_T_MAX - newlen / OVERALLOCATE_FACTOR)) { + /* overallocate to limit the number of realloc() */ + newlen += newlen / OVERALLOCATE_FACTOR; + } + if (newlen < writer->min_length) + newlen = writer->min_length; + + if (maxchar > writer->maxchar || writer->readonly) { + /* resize + widen */ + maxchar = Py_MAX(maxchar, writer->maxchar); + newbuffer = PyUnicode_New(newlen, maxchar); + if (newbuffer == NULL) + return -1; + _PyUnicode_FastCopyCharacters(newbuffer, 0, + writer->buffer, 0, writer->pos); + Py_DECREF(writer->buffer); + writer->readonly = 0; + } + else { + newbuffer = _PyUnicode_ResizeCompact(writer->buffer, newlen); + if (newbuffer == NULL) + return -1; + } + writer->buffer = newbuffer; + } + else if (maxchar > writer->maxchar) { + assert(!writer->readonly); + newbuffer = PyUnicode_New(writer->size, maxchar); + if (newbuffer == NULL) + return -1; + _PyUnicode_FastCopyCharacters(newbuffer, 0, + writer->buffer, 0, writer->pos); + Py_SETREF(writer->buffer, newbuffer); + } + _PyUnicodeWriter_Update(writer); + return 0; + +#undef OVERALLOCATE_FACTOR +} + +int +_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer, + int kind) +{ + Py_UCS4 maxchar; + + /* ensure that the _PyUnicodeWriter_PrepareKind macro was used */ + assert(writer->kind < kind); + + switch (kind) + { + case PyUnicode_1BYTE_KIND: maxchar = 0xff; break; + case PyUnicode_2BYTE_KIND: maxchar = 0xffff; break; + case PyUnicode_4BYTE_KIND: maxchar = _Py_MAX_UNICODE; break; + default: + Py_UNREACHABLE(); + } + + return _PyUnicodeWriter_PrepareInternal(writer, 0, maxchar); +} + + +int +_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, Py_UCS4 ch) +{ + return _PyUnicodeWriter_WriteCharInline(writer, ch); +} + + +int +PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch) +{ + if (ch > _Py_MAX_UNICODE) { + PyErr_SetString(PyExc_ValueError, + "character must be in range(0x110000)"); + return -1; + } + + return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch); +} + + +int +_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str) +{ + assert(PyUnicode_Check(str)); + + Py_UCS4 maxchar; + Py_ssize_t len; + + len = PyUnicode_GET_LENGTH(str); + if (len == 0) + return 0; + maxchar = PyUnicode_MAX_CHAR_VALUE(str); + if (maxchar > writer->maxchar || len > writer->size - writer->pos) { + if (writer->buffer == NULL && !writer->overallocate) { + assert(_PyUnicode_CheckConsistency(str, 1)); + writer->readonly = 1; + writer->buffer = Py_NewRef(str); + _PyUnicodeWriter_Update(writer); + writer->pos += len; + return 0; + } + if (_PyUnicodeWriter_PrepareInternal(writer, len, maxchar) == -1) + return -1; + } + _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, + str, 0, len); + writer->pos += len; + return 0; +} + + +int +PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj) +{ + PyTypeObject *type = Py_TYPE(obj); + if (type == &PyUnicode_Type) { + return _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, obj); + } + + if (type == &PyLong_Type) { + return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0); + } + + PyObject *str = PyObject_Str(obj); + if (str == NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); + Py_DECREF(str); + return res; +} + + +int +PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj) +{ + if (Py_TYPE(obj) == &PyLong_Type) { + return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0); + } + + PyObject *repr = PyObject_Repr(obj); + if (repr == NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, repr); + Py_DECREF(repr); + return res; +} + + +int +_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, PyObject *str, + Py_ssize_t start, Py_ssize_t end) +{ + assert(0 <= start); + assert(end <= PyUnicode_GET_LENGTH(str)); + assert(start <= end); + + if (start == 0 && end == PyUnicode_GET_LENGTH(str)) + return _PyUnicodeWriter_WriteStr(writer, str); + + Py_ssize_t len = end - start; + if (len == 0) { + return 0; + } + + Py_UCS4 maxchar; + if (PyUnicode_MAX_CHAR_VALUE(str) > writer->maxchar) { + maxchar = _PyUnicode_FindMaxChar(str, start, end); + } + else { + maxchar = writer->maxchar; + } + if (_PyUnicodeWriter_Prepare(writer, len, maxchar) < 0) { + return -1; + } + + _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, + str, start, len); + writer->pos += len; + return 0; +} + + +int +PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, + Py_ssize_t start, Py_ssize_t end) +{ + if (!PyUnicode_Check(str)) { + PyErr_Format(PyExc_TypeError, "expect str, not %T", str); + return -1; + } + if (start < 0 || start > end) { + PyErr_Format(PyExc_ValueError, "invalid start argument"); + return -1; + } + if (end > PyUnicode_GET_LENGTH(str)) { + PyErr_Format(PyExc_ValueError, "invalid end argument"); + return -1; + } + + return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str, + start, end); +} + + +int +_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, + const char *ascii, Py_ssize_t len) +{ + if (len == -1) + len = strlen(ascii); + + assert(ucs1lib_find_max_char((const Py_UCS1*)ascii, (const Py_UCS1*)ascii + len) < 128); + + if (writer->buffer == NULL && !writer->overallocate) { + PyObject *str; + + str = _PyUnicode_FromASCII(ascii, len); + if (str == NULL) + return -1; + + writer->readonly = 1; + writer->buffer = str; + _PyUnicodeWriter_Update(writer); + writer->pos += len; + return 0; + } + + if (_PyUnicodeWriter_Prepare(writer, len, 127) == -1) + return -1; + + switch (writer->kind) + { + case PyUnicode_1BYTE_KIND: + { + const Py_UCS1 *str = (const Py_UCS1 *)ascii; + Py_UCS1 *data = writer->data; + + memcpy(data + writer->pos, str, len); + break; + } + case PyUnicode_2BYTE_KIND: + { + _PyUnicode_CONVERT_BYTES( + Py_UCS1, Py_UCS2, + ascii, ascii + len, + (Py_UCS2 *)writer->data + writer->pos); + break; + } + case PyUnicode_4BYTE_KIND: + { + _PyUnicode_CONVERT_BYTES( + Py_UCS1, Py_UCS4, + ascii, ascii + len, + (Py_UCS4 *)writer->data + writer->pos); + break; + } + default: + Py_UNREACHABLE(); + } + + writer->pos += len; + return 0; +} + + +int +PyUnicodeWriter_WriteASCII(PyUnicodeWriter *writer, + const char *str, + Py_ssize_t size) +{ + assert(writer != NULL); + _Py_AssertHoldsTstate(); + + _PyUnicodeWriter *priv_writer = (_PyUnicodeWriter*)writer; + return _PyUnicodeWriter_WriteASCIIString(priv_writer, str, size); +} + + +int +PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, + const char *str, + Py_ssize_t size) +{ + if (size < 0) { + size = strlen(str); + } + + _PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer; + Py_ssize_t old_pos = _writer->pos; + int res = _PyUnicode_DecodeUTF8Writer(_writer, str, size, + _Py_ERROR_STRICT, NULL, NULL); + if (res < 0) { + _writer->pos = old_pos; + } + return res; +} + + +int +PyUnicodeWriter_DecodeUTF8Stateful(PyUnicodeWriter *writer, + const char *string, + Py_ssize_t length, + const char *errors, + Py_ssize_t *consumed) +{ + if (length < 0) { + length = strlen(string); + } + + _PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer; + Py_ssize_t old_pos = _writer->pos; + int res = _PyUnicode_DecodeUTF8Writer(_writer, string, length, + _Py_ERROR_UNKNOWN, errors, + consumed); + if (res < 0) { + _writer->pos = old_pos; + if (consumed) { + *consumed = 0; + } + } + return res; +} + + +int +_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, + const char *str, Py_ssize_t len) +{ + Py_UCS4 maxchar; + + maxchar = ucs1lib_find_max_char((const Py_UCS1*)str, (const Py_UCS1*)str + len); + if (_PyUnicodeWriter_Prepare(writer, len, maxchar) == -1) + return -1; + unicode_write_cstr(writer->buffer, writer->pos, str, len); + writer->pos += len; + return 0; +} + + +PyObject * +_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer) +{ + PyObject *str; + + if (writer->pos == 0) { + Py_CLEAR(writer->buffer); + return _PyUnicode_GetEmpty(); + } + + str = writer->buffer; + writer->buffer = NULL; + + if (writer->readonly) { + assert(PyUnicode_GET_LENGTH(str) == writer->pos); + return str; + } + + if (PyUnicode_GET_LENGTH(str) != writer->pos) { + PyObject *str2; + str2 = _PyUnicode_ResizeCompact(str, writer->pos); + if (str2 == NULL) { + Py_DECREF(str); + return NULL; + } + str = str2; + } + + assert(_PyUnicode_CheckConsistency(str, 1)); + return _PyUnicode_Result(str); +} + + +PyObject* +PyUnicodeWriter_Finish(PyUnicodeWriter *writer) +{ + PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer); + assert(((_PyUnicodeWriter*)writer)->buffer == NULL); + _Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free); + return str; +} + + +void +_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer) +{ + Py_CLEAR(writer->buffer); +} diff --git a/Objects/unicodectype.c b/Objects/unicodectype.c index 7cd0dca3d13..fdd380190ac 100644 --- a/Objects/unicodectype.c +++ b/Objects/unicodectype.c @@ -9,6 +9,7 @@ */ #include "Python.h" +#include "pycore_unicodectype.h" // export _PyUnicode_IsXidStart(), _PyUnicode_IsXidContinue() #define ALPHA_MASK 0x01 #define DECIMAL_MASK 0x02 diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 9300a99a721..f737a885f19 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -46,7 +46,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_codecs.h" // _PyCodec_Lookup() #include "pycore_critical_section.h" // Py_*_CRITICAL_SECTION_SEQUENCE_FAST #include "pycore_format.h" // F_LJUST -#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // PyInterpreterState.fs_codec #include "pycore_long.h" // _PyLong_FormatWriter() @@ -56,8 +55,8 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_pyhash.h" // _Py_HashSecret_t #include "pycore_pylifecycle.h" // _Py_SetFileSystemEncoding() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI +#include "pycore_unicodectype.h" // _PyUnicode_IsXidStart #include "pycore_unicodeobject.h" // struct _Py_unicode_state #include "pycore_unicodeobject_generated.h" // _PyUnicode_InitStaticStrings() @@ -104,9 +103,8 @@ NOTE: In the interpreter's initialization phase, some globals are currently */ -// Maximum code point of Unicode 6.0: 0x10ffff (1,114,111). -// The value must be the same in fileutils.c. -#define MAX_UNICODE 0x10ffff +#define MAX_UNICODE _Py_MAX_UNICODE +#define ensure_unicode _PyUnicode_EnsureUnicode #ifdef Py_DEBUG # define _PyUnicode_CHECK(op) _PyUnicode_CheckConsistency(op, 0) @@ -185,45 +183,9 @@ static inline int _PyUnicode_HAS_UTF8_MEMORY(PyObject *op) } -/* Generic helper macro to convert characters of different types. - from_type and to_type have to be valid type names, begin and end - are pointers to the source characters which should be of type - "from_type *". to is a pointer of type "to_type *" and points to the - buffer where the result characters are written to. */ -#define _PyUnicode_CONVERT_BYTES(from_type, to_type, begin, end, to) \ - do { \ - to_type *_to = (to_type *)(to); \ - const from_type *_iter = (const from_type *)(begin);\ - const from_type *_end = (const from_type *)(end);\ - Py_ssize_t n = (_end) - (_iter); \ - const from_type *_unrolled_end = \ - _iter + _Py_SIZE_ROUND_DOWN(n, 4); \ - while (_iter < (_unrolled_end)) { \ - _to[0] = (to_type) _iter[0]; \ - _to[1] = (to_type) _iter[1]; \ - _to[2] = (to_type) _iter[2]; \ - _to[3] = (to_type) _iter[3]; \ - _iter += 4; _to += 4; \ - } \ - while (_iter < (_end)) \ - *_to++ = (to_type) *_iter++; \ - } while (0) - #define LATIN1 _Py_LATIN1_CHR -#ifdef MS_WINDOWS - /* On Windows, overallocate by 50% is the best factor */ -# define OVERALLOCATE_FACTOR 2 -#else - /* On Linux, overallocate by 25% is the best factor */ -# define OVERALLOCATE_FACTOR 4 -#endif - /* Forward declaration */ -static inline int -_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch); -static inline void -_PyUnicodeWriter_InitWithBuffer(_PyUnicodeWriter *writer, PyObject *buffer); static PyObject * unicode_encode_utf8(PyObject *unicode, _Py_error_handler error_handler, const char *errors); @@ -231,11 +193,6 @@ static PyObject * unicode_decode_utf8(const char *s, Py_ssize_t size, _Py_error_handler error_handler, const char *errors, Py_ssize_t *consumed); -static int -unicode_decode_utf8_writer(_PyUnicodeWriter *writer, - const char *s, Py_ssize_t size, - _Py_error_handler error_handler, const char *errors, - Py_ssize_t *consumed); #ifdef Py_DEBUG static inline int unicode_is_finalizing(void); static int unicode_is_singleton(PyObject *unicode); @@ -243,7 +200,8 @@ static int unicode_is_singleton(PyObject *unicode); // Return a reference to the immortal empty string singleton. -static inline PyObject* unicode_get_empty(void) +PyObject* +_PyUnicode_GetEmpty(void) { _Py_DECLARE_STR(empty, ""); return &_Py_STR(empty); @@ -417,42 +375,9 @@ static void clear_global_interned_strings(void) #define _Py_RETURN_UNICODE_EMPTY() \ do { \ - return unicode_get_empty(); \ + return _PyUnicode_GetEmpty();\ } while (0) -static inline void -unicode_fill(int kind, void *data, Py_UCS4 value, - Py_ssize_t start, Py_ssize_t length) -{ - assert(0 <= start); - switch (kind) { - case PyUnicode_1BYTE_KIND: { - assert(value <= 0xff); - Py_UCS1 ch = (unsigned char)value; - Py_UCS1 *to = (Py_UCS1 *)data + start; - memset(to, ch, length); - break; - } - case PyUnicode_2BYTE_KIND: { - assert(value <= 0xffff); - Py_UCS2 ch = (Py_UCS2)value; - Py_UCS2 *to = (Py_UCS2 *)data + start; - const Py_UCS2 *end = to + length; - for (; to < end; ++to) *to = ch; - break; - } - case PyUnicode_4BYTE_KIND: { - assert(value <= MAX_UNICODE); - Py_UCS4 ch = value; - Py_UCS4 * to = (Py_UCS4 *)data + start; - const Py_UCS4 *end = to + length; - for (; to < end; ++to) *to = ch; - break; - } - default: Py_UNREACHABLE(); - } -} - /* Fast detection of the most frequent whitespace characters */ const unsigned char _Py_ascii_whitespace[] = { @@ -487,7 +412,6 @@ const unsigned char _Py_ascii_whitespace[] = { /* forward */ static PyObject* get_latin1_char(unsigned char ch); -static int unicode_modifiable(PyObject *unicode); static PyObject * @@ -623,7 +547,8 @@ unicode_check_encoding_errors(const char *encoding, const char *errors) } /* Disable checks during Python finalization. For example, it allows to - call _PyObject_Dump() during finalization for debugging purpose. */ + * call PyUnstable_Object_Dump() during finalization for debugging purpose. + */ if (_PyInterpreterState_GetFinalizing(interp) != NULL) { return 0; } @@ -783,14 +708,14 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content) #undef CHECK } -static PyObject* -unicode_result(PyObject *unicode) +PyObject* +_PyUnicode_Result(PyObject *unicode) { assert(_PyUnicode_CHECK(unicode)); Py_ssize_t length = PyUnicode_GET_LENGTH(unicode); if (length == 0) { - PyObject *empty = unicode_get_empty(); + PyObject *empty = _PyUnicode_GetEmpty(); if (unicode != empty) { Py_DECREF(unicode); } @@ -813,6 +738,7 @@ unicode_result(PyObject *unicode) assert(_PyUnicode_CheckConsistency(unicode, 1)); return unicode; } +#define unicode_result _PyUnicode_Result static PyObject* unicode_result_unchanged(PyObject *unicode) @@ -828,7 +754,7 @@ unicode_result_unchanged(PyObject *unicode) /* Implementation of the "backslashreplace" error handler for 8-bit encodings: ASCII, Latin1, UTF-8, etc. */ static char* -backslashreplace(_PyBytesWriter *writer, char *str, +backslashreplace(PyBytesWriter *writer, char *str, PyObject *unicode, Py_ssize_t collstart, Py_ssize_t collend) { Py_ssize_t size, i; @@ -861,9 +787,10 @@ backslashreplace(_PyBytesWriter *writer, char *str, size += incr; } - str = _PyBytesWriter_Prepare(writer, str, size); - if (str == NULL) + str = PyBytesWriter_GrowAndUpdatePointer(writer, size, str); + if (str == NULL) { return NULL; + } /* generate replacement */ for (i = collstart; i < collend; ++i) { @@ -894,7 +821,7 @@ backslashreplace(_PyBytesWriter *writer, char *str, /* Implementation of the "xmlcharrefreplace" error handler for 8-bit encodings: ASCII, Latin1, UTF-8, etc. */ static char* -xmlcharrefreplace(_PyBytesWriter *writer, char *str, +xmlcharrefreplace(PyBytesWriter *writer, char *str, PyObject *unicode, Py_ssize_t collstart, Py_ssize_t collend) { Py_ssize_t size, i; @@ -935,9 +862,10 @@ xmlcharrefreplace(_PyBytesWriter *writer, char *str, size += incr; } - str = _PyBytesWriter_Prepare(writer, str, size); - if (str == NULL) + str = PyBytesWriter_GrowAndUpdatePointer(writer, size, str); + if (str == NULL) { return NULL; + } /* generate replacement */ for (i = collstart; i < collend; ++i) { @@ -1016,21 +944,9 @@ make_bloom_mask(int kind, const void* ptr, Py_ssize_t len) #undef BLOOM_UPDATE } -static int -ensure_unicode(PyObject *obj) -{ - if (!PyUnicode_Check(obj)) { - PyErr_Format(PyExc_TypeError, - "must be str, not %.100s", - Py_TYPE(obj)->tp_name); - return -1; - } - return 0; -} - /* Compilation of templated routines */ -#define STRINGLIB_GET_EMPTY() unicode_get_empty() +#define STRINGLIB_GET_EMPTY() _PyUnicode_GetEmpty() #include "stringlib/asciilib.h" #include "stringlib/fastsearch.h" @@ -1142,8 +1058,8 @@ resize_copy(PyObject *unicode, Py_ssize_t length) return copy; } -static PyObject* -resize_compact(PyObject *unicode, Py_ssize_t length) +PyObject* +_PyUnicode_ResizeCompact(PyObject *unicode, Py_ssize_t length) { Py_ssize_t char_size; Py_ssize_t struct_size; @@ -1153,7 +1069,7 @@ resize_compact(PyObject *unicode, Py_ssize_t length) Py_ssize_t old_length = _PyUnicode_LENGTH(unicode); #endif - if (!unicode_modifiable(unicode)) { + if (!_PyUnicode_IsModifiable(unicode)) { PyObject *copy = resize_copy(unicode, length); if (copy == NULL) { return NULL; @@ -1351,7 +1267,7 @@ PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) { /* Optimization for empty strings */ if (size == 0) { - return unicode_get_empty(); + return _PyUnicode_GetEmpty(); } PyObject *obj; @@ -1445,7 +1361,7 @@ PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) static int unicode_check_modifiable(PyObject *unicode) { - if (!unicode_modifiable(unicode)) { + if (!_PyUnicode_IsModifiable(unicode)) { PyErr_SetString(PyExc_SystemError, "Cannot modify a string currently used"); return -1; @@ -1807,8 +1723,8 @@ unicode_is_singleton(PyObject *unicode) } #endif -static int -unicode_modifiable(PyObject *unicode) +int +_PyUnicode_IsModifiable(PyObject *unicode) { assert(_PyUnicode_CHECK(unicode)); if (!_PyObject_IsUniquelyReferenced(unicode)) @@ -1844,12 +1760,12 @@ unicode_resize(PyObject **p_unicode, Py_ssize_t length) return 0; if (length == 0) { - PyObject *empty = unicode_get_empty(); + PyObject *empty = _PyUnicode_GetEmpty(); Py_SETREF(*p_unicode, empty); return 0; } - if (!unicode_modifiable(unicode)) { + if (!_PyUnicode_IsModifiable(unicode)) { PyObject *copy = resize_copy(unicode, length); if (copy == NULL) return -1; @@ -1858,7 +1774,7 @@ unicode_resize(PyObject **p_unicode, Py_ssize_t length) } if (PyUnicode_IS_COMPACT(unicode)) { - PyObject *new_unicode = resize_compact(unicode, length); + PyObject *new_unicode = _PyUnicode_ResizeCompact(unicode, length); if (new_unicode == NULL) return -1; *p_unicode = new_unicode; @@ -1884,58 +1800,6 @@ PyUnicode_Resize(PyObject **p_unicode, Py_ssize_t length) return unicode_resize(p_unicode, length); } -/* Copy an ASCII or latin1 char* string into a Python Unicode string. - - WARNING: The function doesn't copy the terminating null character and - doesn't check the maximum character (may write a latin1 character in an - ASCII string). */ -static void -unicode_write_cstr(PyObject *unicode, Py_ssize_t index, - const char *str, Py_ssize_t len) -{ - int kind = PyUnicode_KIND(unicode); - const void *data = PyUnicode_DATA(unicode); - const char *end = str + len; - - assert(index + len <= PyUnicode_GET_LENGTH(unicode)); - switch (kind) { - case PyUnicode_1BYTE_KIND: { -#ifdef Py_DEBUG - if (PyUnicode_IS_ASCII(unicode)) { - Py_UCS4 maxchar = ucs1lib_find_max_char( - (const Py_UCS1*)str, - (const Py_UCS1*)str + len); - assert(maxchar < 128); - } -#endif - memcpy((char *) data + index, str, len); - break; - } - case PyUnicode_2BYTE_KIND: { - Py_UCS2 *start = (Py_UCS2 *)data + index; - Py_UCS2 *ucs2 = start; - - for (; str < end; ++ucs2, ++str) - *ucs2 = (Py_UCS2)*str; - - assert((ucs2 - start) <= PyUnicode_GET_LENGTH(unicode)); - break; - } - case PyUnicode_4BYTE_KIND: { - Py_UCS4 *start = (Py_UCS4 *)data + index; - Py_UCS4 *ucs4 = start; - - for (; str < end; ++ucs4, ++str) - *ucs4 = (Py_UCS4)*str; - - assert((ucs4 - start) <= PyUnicode_GET_LENGTH(unicode)); - break; - } - default: - Py_UNREACHABLE(); - } -} - static PyObject* get_latin1_char(Py_UCS1 ch) { @@ -2150,7 +2014,7 @@ PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size) "NULL string with positive size with NULL passed to PyUnicode_FromStringAndSize"); return NULL; } - return unicode_get_empty(); + return _PyUnicode_GetEmpty(); } PyObject * @@ -2717,8 +2581,8 @@ unicode_fromformat_write_utf8(_PyUnicodeWriter *writer, const char *str, } if (width < 0) { - return unicode_decode_utf8_writer(writer, str, length, - _Py_ERROR_REPLACE, "replace", pconsumed); + return _PyUnicode_DecodeUTF8Writer(writer, str, length, + _Py_ERROR_REPLACE, "replace", pconsumed); } PyObject *unicode = PyUnicode_DecodeUTF8Stateful(str, length, @@ -3263,14 +3127,22 @@ PyUnicode_FromFormat(const char *format, ...) int PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...) +{ + va_list vargs; + va_start(vargs, format); + int res = _PyUnicodeWriter_FormatV(writer, format, vargs); + va_end(vargs); + return res; +} + +int +_PyUnicodeWriter_FormatV(PyUnicodeWriter *writer, const char *format, + va_list vargs) { _PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer; Py_ssize_t old_pos = _writer->pos; - va_list vargs; - va_start(vargs, format); int res = unicode_from_format(_writer, format, vargs); - va_end(vargs); if (res < 0) { _writer->pos = old_pos; @@ -3578,13 +3450,14 @@ PyUnicode_FromEncodedObject(PyObject *obj, return v; } -/* Normalize an encoding name: similar to encodings.normalize_encoding(), but - also convert to lowercase. Return 1 on success, or 0 on error (encoding is - longer than lower_len-1). */ +/* Normalize an encoding name like encodings.normalize_encoding() + but allow to convert to lowercase if *to_lower* is true. + Return 1 on success, or 0 on error (encoding is longer than lower_len-1). */ int _Py_normalize_encoding(const char *encoding, char *lower, - size_t lower_len) + size_t lower_len, + int to_lower) { const char *e; char *l; @@ -3615,7 +3488,7 @@ _Py_normalize_encoding(const char *encoding, if (l == l_end) { return 0; } - *l++ = Py_TOLOWER(c); + *l++ = to_lower ? Py_TOLOWER(c) : c; } else { punct = 1; @@ -3650,7 +3523,7 @@ PyUnicode_Decode(const char *s, } /* Shortcuts for common default encodings */ - if (_Py_normalize_encoding(encoding, buflower, sizeof(buflower))) { + if (_Py_normalize_encoding(encoding, buflower, sizeof(buflower), 1)) { char *lower = buflower; /* Fast paths */ @@ -3907,7 +3780,7 @@ PyUnicode_AsEncodedString(PyObject *unicode, } /* Shortcuts for common default encodings */ - if (_Py_normalize_encoding(encoding, buflower, sizeof(buflower))) { + if (_Py_normalize_encoding(encoding, buflower, sizeof(buflower), 1)) { char *lower = buflower; /* Fast paths */ @@ -4660,15 +4533,12 @@ char utf7_category[128] = { /* ENCODE_DIRECT: this character should be encoded as itself. The * answer depends on whether we are encoding set O as itself, and also - * on whether we are encoding whitespace as itself. RFC2152 makes it + * on whether we are encoding whitespace as itself. RFC 2152 makes it * clear that the answers to these questions vary between * applications, so this code needs to be flexible. */ -#define ENCODE_DIRECT(c, directO, directWS) \ - ((c) < 128 && (c) > 0 && \ - ((utf7_category[(c)] == 0) || \ - (directWS && (utf7_category[(c)] == 2)) || \ - (directO && (utf7_category[(c)] == 1)))) +#define ENCODE_DIRECT(c) \ + ((c) < 128 && (c) > 0 && ((utf7_category[(c)] != 3))) PyObject * PyUnicode_DecodeUTF7(const char *s, @@ -4885,41 +4755,33 @@ utf7Error: PyObject * _PyUnicode_EncodeUTF7(PyObject *str, - int base64SetO, - int base64WhiteSpace, const char *errors) { - int kind; - const void *data; - Py_ssize_t len; - PyObject *v; - int inShift = 0; - Py_ssize_t i; - unsigned int base64bits = 0; - unsigned long base64buffer = 0; - char * out; - const char * start; - - kind = PyUnicode_KIND(str); - data = PyUnicode_DATA(str); - len = PyUnicode_GET_LENGTH(str); - - if (len == 0) - return PyBytes_FromStringAndSize(NULL, 0); + Py_ssize_t len = PyUnicode_GET_LENGTH(str); + if (len == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } + int kind = PyUnicode_KIND(str); + const void *data = PyUnicode_DATA(str); /* It might be possible to tighten this worst case */ - if (len > PY_SSIZE_T_MAX / 8) + if (len > PY_SSIZE_T_MAX / 8) { return PyErr_NoMemory(); - v = PyBytes_FromStringAndSize(NULL, len * 8); - if (v == NULL) + } + PyBytesWriter *writer = PyBytesWriter_Create(len * 8); + if (writer == NULL) { return NULL; + } - start = out = PyBytes_AS_STRING(v); - for (i = 0; i < len; ++i) { + int inShift = 0; + unsigned int base64bits = 0; + unsigned long base64buffer = 0; + char *out = PyBytesWriter_GetData(writer); + for (Py_ssize_t i = 0; i < len; ++i) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); if (inShift) { - if (ENCODE_DIRECT(ch, !base64SetO, !base64WhiteSpace)) { + if (ENCODE_DIRECT(ch)) { /* shifting out */ if (base64bits) { /* output remaining bits */ *out++ = TO_BASE64(base64buffer << (6-base64bits)); @@ -4943,7 +4805,7 @@ _PyUnicode_EncodeUTF7(PyObject *str, *out++ = '+'; *out++ = '-'; } - else if (ENCODE_DIRECT(ch, !base64SetO, !base64WhiteSpace)) { + else if (ENCODE_DIRECT(ch)) { *out++ = (char) ch; } else { @@ -4978,9 +4840,7 @@ encode_char: *out++= TO_BASE64(base64buffer << (6-base64bits) ); if (inShift) *out++ = '-'; - if (_PyBytes_Resize(&v, out - start) < 0) - return NULL; - return v; + return PyBytesWriter_FinishWithPointer(writer, out); } #undef IS_BASE64 @@ -5460,7 +5320,6 @@ unicode_decode_utf8(const char *s, Py_ssize_t size, if (maxchr <= 255) { memcpy(PyUnicode_1BYTE_DATA(u), s, pos); s += pos; - size -= pos; writer.pos = pos; } @@ -5475,11 +5334,11 @@ unicode_decode_utf8(const char *s, Py_ssize_t size, // Used by PyUnicodeWriter_WriteUTF8() implementation -static int -unicode_decode_utf8_writer(_PyUnicodeWriter *writer, - const char *s, Py_ssize_t size, - _Py_error_handler error_handler, const char *errors, - Py_ssize_t *consumed) +int +_PyUnicode_DecodeUTF8Writer(_PyUnicodeWriter *writer, + const char *s, Py_ssize_t size, + _Py_error_handler error_handler, const char *errors, + Py_ssize_t *consumed) { if (size == 0) { if (consumed) { @@ -5508,7 +5367,6 @@ unicode_decode_utf8_writer(_PyUnicodeWriter *writer, return 0; } s += decoded; - size -= decoded; } return unicode_decode_utf8_impl(writer, starts, s, end, @@ -5828,7 +5686,7 @@ unicode_encode_utf8(PyObject *unicode, _Py_error_handler error_handler, const void *data = PyUnicode_DATA(unicode); Py_ssize_t size = PyUnicode_GET_LENGTH(unicode); - _PyBytesWriter writer; + PyBytesWriter *writer; char *end; switch (kind) { @@ -5837,21 +5695,24 @@ unicode_encode_utf8(PyObject *unicode, _Py_error_handler error_handler, case PyUnicode_1BYTE_KIND: /* the string cannot be ASCII, or PyUnicode_UTF8() would be set */ assert(!PyUnicode_IS_ASCII(unicode)); - end = ucs1lib_utf8_encoder(&writer, unicode, data, size, error_handler, errors); + writer = ucs1lib_utf8_encoder(unicode, data, size, + error_handler, errors, &end); break; case PyUnicode_2BYTE_KIND: - end = ucs2lib_utf8_encoder(&writer, unicode, data, size, error_handler, errors); + writer = ucs2lib_utf8_encoder(unicode, data, size, + error_handler, errors, &end); break; case PyUnicode_4BYTE_KIND: - end = ucs4lib_utf8_encoder(&writer, unicode, data, size, error_handler, errors); + writer = ucs4lib_utf8_encoder(unicode, data, size, + error_handler, errors, &end); break; } - if (end == NULL) { - _PyBytesWriter_Dealloc(&writer); + if (writer == NULL) { + PyBytesWriter_Discard(writer); return NULL; } - return _PyBytesWriter_Finish(&writer, end); + return PyBytesWriter_FinishWithPointer(writer, end); } static int @@ -5865,37 +5726,35 @@ unicode_fill_utf8(PyObject *unicode) const void *data = PyUnicode_DATA(unicode); Py_ssize_t size = PyUnicode_GET_LENGTH(unicode); - _PyBytesWriter writer; + PyBytesWriter *writer; char *end; switch (kind) { default: Py_UNREACHABLE(); case PyUnicode_1BYTE_KIND: - end = ucs1lib_utf8_encoder(&writer, unicode, data, size, - _Py_ERROR_STRICT, NULL); + writer = ucs1lib_utf8_encoder(unicode, data, size, + _Py_ERROR_STRICT, NULL, &end); break; case PyUnicode_2BYTE_KIND: - end = ucs2lib_utf8_encoder(&writer, unicode, data, size, - _Py_ERROR_STRICT, NULL); + writer = ucs2lib_utf8_encoder(unicode, data, size, + _Py_ERROR_STRICT, NULL, &end); break; case PyUnicode_4BYTE_KIND: - end = ucs4lib_utf8_encoder(&writer, unicode, data, size, - _Py_ERROR_STRICT, NULL); + writer = ucs4lib_utf8_encoder(unicode, data, size, + _Py_ERROR_STRICT, NULL, &end); break; } - if (end == NULL) { - _PyBytesWriter_Dealloc(&writer); + if (writer == NULL) { return -1; } - const char *start = writer.use_small_buffer ? writer.small_buffer : - PyBytes_AS_STRING(writer.buffer); + const char *start = PyBytesWriter_GetData(writer); Py_ssize_t len = end - start; char *cache = PyMem_Malloc(len + 1); if (cache == NULL) { - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); PyErr_NoMemory(); return -1; } @@ -5903,7 +5762,7 @@ unicode_fill_utf8(PyObject *unicode) cache[len] = '\0'; PyUnicode_SET_UTF8_LENGTH(unicode, len); PyUnicode_SET_UTF8(unicode, cache); - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return 0; } @@ -6081,45 +5940,61 @@ _PyUnicode_EncodeUTF32(PyObject *str, const char *errors, int byteorder) { - int kind; - const void *data; - Py_ssize_t len; - PyObject *v; - uint32_t *out; + if (!PyUnicode_Check(str)) { + PyErr_BadArgument(); + return NULL; + } + int kind = PyUnicode_KIND(str); + const void *data = PyUnicode_DATA(str); + Py_ssize_t len = PyUnicode_GET_LENGTH(str); + + if (len > PY_SSIZE_T_MAX / 4 - (byteorder == 0)) + return PyErr_NoMemory(); + Py_ssize_t nsize = len + (byteorder == 0); + #if PY_LITTLE_ENDIAN int native_ordering = byteorder <= 0; #else int native_ordering = byteorder >= 0; #endif - const char *encoding; - Py_ssize_t nsize, pos; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - PyObject *rep = NULL; - if (!PyUnicode_Check(str)) { - PyErr_BadArgument(); + if (kind == PyUnicode_1BYTE_KIND) { + // gh-139156: Don't use PyBytesWriter API here since it has an overhead + // on short strings + PyObject *v = PyBytes_FromStringAndSize(NULL, nsize * 4); + if (v == NULL) { + return NULL; + } + + /* output buffer is 4-bytes aligned */ + assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 4)); + uint32_t *out = (uint32_t *)PyBytes_AS_STRING(v); + if (byteorder == 0) { + *out++ = 0xFEFF; + } + if (len > 0) { + ucs1lib_utf32_encode((const Py_UCS1 *)data, len, + &out, native_ordering); + } + return v; + } + + PyBytesWriter *writer = PyBytesWriter_Create(nsize * 4); + if (writer == NULL) { return NULL; } - kind = PyUnicode_KIND(str); - data = PyUnicode_DATA(str); - len = PyUnicode_GET_LENGTH(str); - - if (len > PY_SSIZE_T_MAX / 4 - (byteorder == 0)) - return PyErr_NoMemory(); - nsize = len + (byteorder == 0); - v = PyBytes_FromStringAndSize(NULL, nsize * 4); - if (v == NULL) - return NULL; /* output buffer is 4-bytes aligned */ - assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 4)); - out = (uint32_t *)PyBytes_AS_STRING(v); - if (byteorder == 0) + assert(_Py_IS_ALIGNED(PyBytesWriter_GetData(writer), 4)); + uint32_t *out = (uint32_t *)PyBytesWriter_GetData(writer); + if (byteorder == 0) { *out++ = 0xFEFF; - if (len == 0) - goto done; + } + if (len == 0) { + return PyBytesWriter_Finish(writer); + } + const char *encoding; if (byteorder == -1) encoding = "utf-32-le"; else if (byteorder == 1) @@ -6127,15 +6002,11 @@ _PyUnicode_EncodeUTF32(PyObject *str, else encoding = "utf-32"; - if (kind == PyUnicode_1BYTE_KIND) { - ucs1lib_utf32_encode((const Py_UCS1 *)data, len, &out, native_ordering); - goto done; - } - - pos = 0; - while (pos < len) { - Py_ssize_t newpos, repsize, moreunits; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + PyObject *rep = NULL; + for (Py_ssize_t pos = 0; pos < len; ) { if (kind == PyUnicode_2BYTE_KIND) { pos += ucs2lib_utf32_encode((const Py_UCS2 *)data + pos, len - pos, &out, native_ordering); @@ -6148,6 +6019,7 @@ _PyUnicode_EncodeUTF32(PyObject *str, if (pos == len) break; + Py_ssize_t newpos; rep = unicode_encode_call_errorhandler( errors, &errorHandler, encoding, "surrogates not allowed", @@ -6155,6 +6027,7 @@ _PyUnicode_EncodeUTF32(PyObject *str, if (!rep) goto error; + Py_ssize_t repsize, moreunits; if (PyBytes_Check(rep)) { repsize = PyBytes_GET_SIZE(rep); if (repsize & 3) { @@ -6180,21 +6053,18 @@ _PyUnicode_EncodeUTF32(PyObject *str, /* four bytes are reserved for each surrogate */ if (moreunits > 0) { - Py_ssize_t outpos = out - (uint32_t*) PyBytes_AS_STRING(v); - if (moreunits >= (PY_SSIZE_T_MAX - PyBytes_GET_SIZE(v)) / 4) { - /* integer overflow */ - PyErr_NoMemory(); + out = PyBytesWriter_GrowAndUpdatePointer(writer, 4 * moreunits, out); + if (out == NULL) { goto error; } - if (_PyBytes_Resize(&v, PyBytes_GET_SIZE(v) + 4 * moreunits) < 0) - goto error; - out = (uint32_t*) PyBytes_AS_STRING(v) + outpos; } if (PyBytes_Check(rep)) { memcpy(out, PyBytes_AS_STRING(rep), repsize); out += repsize / 4; - } else /* rep is unicode */ { + } + else { + /* rep is unicode */ assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); ucs1lib_utf32_encode(PyUnicode_1BYTE_DATA(rep), repsize, &out, native_ordering); @@ -6203,21 +6073,19 @@ _PyUnicode_EncodeUTF32(PyObject *str, Py_CLEAR(rep); } + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + /* Cut back to size actually needed. This is necessary for, for example, encoding of a string containing isolated surrogates and the 'ignore' handler is used. */ - nsize = (unsigned char*) out - (unsigned char*) PyBytes_AS_STRING(v); - if (nsize != PyBytes_GET_SIZE(v)) - _PyBytes_Resize(&v, nsize); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - done: - return v; + return PyBytesWriter_FinishWithPointer(writer, out); + error: Py_XDECREF(rep); Py_XDECREF(errorHandler); Py_XDECREF(exc); - Py_XDECREF(v); + PyBytesWriter_Discard(writer); return NULL; } @@ -6398,32 +6266,15 @@ _PyUnicode_EncodeUTF16(PyObject *str, const char *errors, int byteorder) { - int kind; - const void *data; - Py_ssize_t len; - PyObject *v; - unsigned short *out; - Py_ssize_t pairs; -#if PY_BIG_ENDIAN - int native_ordering = byteorder >= 0; -#else - int native_ordering = byteorder <= 0; -#endif - const char *encoding; - Py_ssize_t nsize, pos; - PyObject *errorHandler = NULL; - PyObject *exc = NULL; - PyObject *rep = NULL; - if (!PyUnicode_Check(str)) { PyErr_BadArgument(); return NULL; } - kind = PyUnicode_KIND(str); - data = PyUnicode_DATA(str); - len = PyUnicode_GET_LENGTH(str); + int kind = PyUnicode_KIND(str); + const void *data = PyUnicode_DATA(str); + Py_ssize_t len = PyUnicode_GET_LENGTH(str); - pairs = 0; + Py_ssize_t pairs = 0; if (kind == PyUnicode_4BYTE_KIND) { const Py_UCS4 *in = (const Py_UCS4 *)data; const Py_UCS4 *end = in + len; @@ -6436,27 +6287,50 @@ _PyUnicode_EncodeUTF16(PyObject *str, if (len > PY_SSIZE_T_MAX / 2 - pairs - (byteorder == 0)) { return PyErr_NoMemory(); } - nsize = len + pairs + (byteorder == 0); - v = PyBytes_FromStringAndSize(NULL, nsize * 2); - if (v == NULL) { + Py_ssize_t nsize = len + pairs + (byteorder == 0); + +#if PY_BIG_ENDIAN + int native_ordering = byteorder >= 0; +#else + int native_ordering = byteorder <= 0; +#endif + + if (kind == PyUnicode_1BYTE_KIND) { + // gh-139156: Don't use PyBytesWriter API here since it has an overhead + // on short strings + PyObject *v = PyBytes_FromStringAndSize(NULL, nsize * 2); + if (v == NULL) { + return NULL; + } + + /* output buffer is 2-bytes aligned */ + assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 2)); + unsigned short *out = (unsigned short *)PyBytes_AS_STRING(v); + if (byteorder == 0) { + *out++ = 0xFEFF; + } + if (len > 0) { + ucs1lib_utf16_encode((const Py_UCS1 *)data, len, &out, native_ordering); + } + return v; + } + + PyBytesWriter *writer = PyBytesWriter_Create(nsize * 2); + if (writer == NULL) { return NULL; } /* output buffer is 2-bytes aligned */ - assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 2)); - out = (unsigned short *)PyBytes_AS_STRING(v); + assert(_Py_IS_ALIGNED(PyBytesWriter_GetData(writer), 2)); + unsigned short *out = PyBytesWriter_GetData(writer); if (byteorder == 0) { *out++ = 0xFEFF; } if (len == 0) { - goto done; - } - - if (kind == PyUnicode_1BYTE_KIND) { - ucs1lib_utf16_encode((const Py_UCS1 *)data, len, &out, native_ordering); - goto done; + return PyBytesWriter_Finish(writer); } + const char *encoding; if (byteorder < 0) { encoding = "utf-16-le"; } @@ -6467,10 +6341,11 @@ _PyUnicode_EncodeUTF16(PyObject *str, encoding = "utf-16"; } - pos = 0; - while (pos < len) { - Py_ssize_t newpos, repsize, moreunits; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + PyObject *rep = NULL; + for (Py_ssize_t pos = 0; pos < len; ) { if (kind == PyUnicode_2BYTE_KIND) { pos += ucs2lib_utf16_encode((const Py_UCS2 *)data + pos, len - pos, &out, native_ordering); @@ -6483,6 +6358,7 @@ _PyUnicode_EncodeUTF16(PyObject *str, if (pos == len) break; + Py_ssize_t newpos; rep = unicode_encode_call_errorhandler( errors, &errorHandler, encoding, "surrogates not allowed", @@ -6490,6 +6366,7 @@ _PyUnicode_EncodeUTF16(PyObject *str, if (!rep) goto error; + Py_ssize_t repsize, moreunits; if (PyBytes_Check(rep)) { repsize = PyBytes_GET_SIZE(rep); if (repsize & 1) { @@ -6515,21 +6392,17 @@ _PyUnicode_EncodeUTF16(PyObject *str, /* two bytes are reserved for each surrogate */ if (moreunits > 0) { - Py_ssize_t outpos = out - (unsigned short*) PyBytes_AS_STRING(v); - if (moreunits >= (PY_SSIZE_T_MAX - PyBytes_GET_SIZE(v)) / 2) { - /* integer overflow */ - PyErr_NoMemory(); + out = PyBytesWriter_GrowAndUpdatePointer(writer, 2 * moreunits, out); + if (out == NULL) { goto error; } - if (_PyBytes_Resize(&v, PyBytes_GET_SIZE(v) + 2 * moreunits) < 0) - goto error; - out = (unsigned short*) PyBytes_AS_STRING(v) + outpos; } if (PyBytes_Check(rep)) { memcpy(out, PyBytes_AS_STRING(rep), repsize); out += repsize / 2; - } else /* rep is unicode */ { + } else { + /* rep is unicode */ assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); ucs1lib_utf16_encode(PyUnicode_1BYTE_DATA(rep), repsize, &out, native_ordering); @@ -6538,23 +6411,20 @@ _PyUnicode_EncodeUTF16(PyObject *str, Py_CLEAR(rep); } + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + /* Cut back to size actually needed. This is necessary for, for example, encoding of a string containing isolated surrogates and the 'ignore' handler is used. */ - nsize = (unsigned char*) out - (unsigned char*) PyBytes_AS_STRING(v); - if (nsize != PyBytes_GET_SIZE(v)) - _PyBytes_Resize(&v, nsize); - Py_XDECREF(errorHandler); - Py_XDECREF(exc); - done: - return v; + return PyBytesWriter_FinishWithPointer(writer, out); + error: Py_XDECREF(rep); Py_XDECREF(errorHandler); Py_XDECREF(exc); - Py_XDECREF(v); + PyBytesWriter_Discard(writer); return NULL; -#undef STORECHAR } PyObject * @@ -6884,46 +6754,36 @@ PyUnicode_DecodeUnicodeEscape(const char *s, PyObject * PyUnicode_AsUnicodeEscapeString(PyObject *unicode) { - Py_ssize_t i, len; - PyObject *repr; - char *p; - int kind; - const void *data; - Py_ssize_t expandsize; - - /* Initial allocation is based on the longest-possible character - escape. - - For UCS1 strings it's '\xxx', 4 bytes per source character. - For UCS2 strings it's '\uxxxx', 6 bytes per source character. - For UCS4 strings it's '\U00xxxxxx', 10 bytes per source character. - */ - if (!PyUnicode_Check(unicode)) { PyErr_BadArgument(); return NULL; } - len = PyUnicode_GET_LENGTH(unicode); + Py_ssize_t len = PyUnicode_GET_LENGTH(unicode); if (len == 0) { - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } + int kind = PyUnicode_KIND(unicode); + const void *data = PyUnicode_DATA(unicode); - kind = PyUnicode_KIND(unicode); - data = PyUnicode_DATA(unicode); - /* 4 byte characters can take up 10 bytes, 2 byte characters can take up 6 - bytes, and 1 byte characters 4. */ - expandsize = kind * 2 + 2; + /* Initial allocation is based on the longest-possible character + * escape. + * + * For UCS1 strings it's '\xxx', 4 bytes per source character. + * For UCS2 strings it's '\uxxxx', 6 bytes per source character. + * For UCS4 strings it's '\U00xxxxxx', 10 bytes per source character. */ + Py_ssize_t expandsize = kind * 2 + 2; if (len > PY_SSIZE_T_MAX / expandsize) { return PyErr_NoMemory(); } - repr = PyBytes_FromStringAndSize(NULL, expandsize * len); - if (repr == NULL) { + + PyBytesWriter *writer = PyBytesWriter_Create(expandsize * len); + if (writer == NULL) { return NULL; } + char *p = PyBytesWriter_GetData(writer); - p = PyBytes_AS_STRING(repr); - for (i = 0; i < len; i++) { + for (Py_ssize_t i = 0; i < len; i++) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); /* U+0000-U+00ff range */ @@ -6989,11 +6849,7 @@ PyUnicode_AsUnicodeEscapeString(PyObject *unicode) } } - assert(p - PyBytes_AS_STRING(repr) > 0); - if (_PyBytes_Resize(&repr, p - PyBytes_AS_STRING(repr)) < 0) { - return NULL; - } - return repr; + return PyBytesWriter_FinishWithPointer(writer, p); } /* --- Raw Unicode Escape Codec ------------------------------------------- */ @@ -7146,41 +7002,34 @@ PyUnicode_DecodeRawUnicodeEscape(const char *s, PyObject * PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode) { - PyObject *repr; - char *p; - Py_ssize_t expandsize, pos; - int kind; - const void *data; - Py_ssize_t len; - if (!PyUnicode_Check(unicode)) { PyErr_BadArgument(); return NULL; } - kind = PyUnicode_KIND(unicode); - data = PyUnicode_DATA(unicode); - len = PyUnicode_GET_LENGTH(unicode); + int kind = PyUnicode_KIND(unicode); + const void *data = PyUnicode_DATA(unicode); + Py_ssize_t len = PyUnicode_GET_LENGTH(unicode); + if (len == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } if (kind == PyUnicode_1BYTE_KIND) { return PyBytes_FromStringAndSize(data, len); } /* 4 byte characters can take up 10 bytes, 2 byte characters can take up 6 bytes, and 1 byte characters 4. */ - expandsize = kind * 2 + 2; - + Py_ssize_t expandsize = kind * 2 + 2; if (len > PY_SSIZE_T_MAX / expandsize) { return PyErr_NoMemory(); } - repr = PyBytes_FromStringAndSize(NULL, expandsize * len); - if (repr == NULL) { + + PyBytesWriter *writer = PyBytesWriter_Create(expandsize * len); + if (writer == NULL) { return NULL; } - if (len == 0) { - return repr; - } + char *p = PyBytesWriter_GetData(writer); - p = PyBytes_AS_STRING(repr); - for (pos = 0; pos < len; pos++) { + for (Py_ssize_t pos = 0; pos < len; pos++) { Py_UCS4 ch = PyUnicode_READ(kind, data, pos); /* U+0000-U+00ff range: Copy 8-bit characters as-is */ @@ -7212,11 +7061,7 @@ PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode) } } - assert(p > PyBytes_AS_STRING(repr)); - if (_PyBytes_Resize(&repr, p - PyBytes_AS_STRING(repr)) < 0) { - return NULL; - } - return repr; + return PyBytesWriter_FinishWithPointer(writer, p); } /* --- Latin-1 Codec ------------------------------------------------------ */ @@ -7339,16 +7184,12 @@ unicode_encode_ucs1(PyObject *unicode, Py_ssize_t pos=0, size; int kind; const void *data; - /* pointer into the output */ - char *str; const char *encoding = (limit == 256) ? "latin-1" : "ascii"; const char *reason = (limit == 256) ? "ordinal not in range(256)" : "ordinal not in range(128)"; PyObject *error_handler_obj = NULL; PyObject *exc = NULL; _Py_error_handler error_handler = _Py_ERROR_UNKNOWN; PyObject *rep = NULL; - /* output object */ - _PyBytesWriter writer; size = PyUnicode_GET_LENGTH(unicode); kind = PyUnicode_KIND(unicode); @@ -7356,12 +7197,15 @@ unicode_encode_ucs1(PyObject *unicode, /* allocate enough for a simple encoding without replacements, if we need more, we'll resize */ if (size == 0) - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); - _PyBytesWriter_Init(&writer); - str = _PyBytesWriter_Alloc(&writer, size); - if (str == NULL) + /* output object */ + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; + } + /* pointer into the output */ + char *str = PyBytesWriter_GetData(writer); while (pos < size) { Py_UCS4 ch = PyUnicode_READ(kind, data, pos); @@ -7383,7 +7227,7 @@ unicode_encode_ucs1(PyObject *unicode, ++collend; /* Only overallocate the buffer if it's not the last write */ - writer.overallocate = (collend < size); + writer->overallocate = (collend < size); /* cache callback name lookup (if not done yet, i.e. it's the first error) */ if (error_handler == _Py_ERROR_UNKNOWN) @@ -7404,8 +7248,8 @@ unicode_encode_ucs1(PyObject *unicode, case _Py_ERROR_BACKSLASHREPLACE: /* subtract preallocated bytes */ - writer.min_size -= (collend - collstart); - str = backslashreplace(&writer, str, + writer->size -= (collend - collstart); + str = backslashreplace(writer, str, unicode, collstart, collend); if (str == NULL) goto onError; @@ -7414,8 +7258,8 @@ unicode_encode_ucs1(PyObject *unicode, case _Py_ERROR_XMLCHARREFREPLACE: /* subtract preallocated bytes */ - writer.min_size -= (collend - collstart); - str = xmlcharrefreplace(&writer, str, + writer->size -= (collend - collstart); + str = xmlcharrefreplace(writer, str, unicode, collstart, collend); if (str == NULL) goto onError; @@ -7446,24 +7290,27 @@ unicode_encode_ucs1(PyObject *unicode, goto onError; if (newpos < collstart) { - writer.overallocate = 1; - str = _PyBytesWriter_Prepare(&writer, str, - collstart - newpos); - if (str == NULL) + writer->overallocate = 1; + str = PyBytesWriter_GrowAndUpdatePointer(writer, + collstart - newpos, + str); + if (str == NULL) { goto onError; + } } else { /* subtract preallocated bytes */ - writer.min_size -= newpos - collstart; + writer->size -= newpos - collstart; /* Only overallocate the buffer if it's not the last write */ - writer.overallocate = (newpos < size); + writer->overallocate = (newpos < size); } + char *rep_str; + Py_ssize_t rep_len; if (PyBytes_Check(rep)) { /* Directly copy bytes result to output. */ - str = _PyBytesWriter_WriteBytes(&writer, str, - PyBytes_AS_STRING(rep), - PyBytes_GET_SIZE(rep)); + rep_str = PyBytes_AS_STRING(rep); + rep_len = PyBytes_GET_SIZE(rep); } else { assert(PyUnicode_Check(rep)); @@ -7478,12 +7325,16 @@ unicode_encode_ucs1(PyObject *unicode, goto onError; } assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); - str = _PyBytesWriter_WriteBytes(&writer, str, - PyUnicode_DATA(rep), - PyUnicode_GET_LENGTH(rep)); + rep_str = PyUnicode_DATA(rep); + rep_len = PyUnicode_GET_LENGTH(rep); } - if (str == NULL) + + str = PyBytesWriter_GrowAndUpdatePointer(writer, rep_len, str); + if (str == NULL) { goto onError; + } + memcpy(str, rep_str, rep_len); + str += rep_len; pos = newpos; Py_CLEAR(rep); @@ -7491,17 +7342,17 @@ unicode_encode_ucs1(PyObject *unicode, /* If overallocation was disabled, ensure that it was the last write. Otherwise, we missed an optimization */ - assert(writer.overallocate || pos == size); + assert(writer->overallocate || pos == size); } } Py_XDECREF(error_handler_obj); Py_XDECREF(exc); - return _PyBytesWriter_Finish(&writer, str); + return PyBytesWriter_FinishWithPointer(writer, str); onError: Py_XDECREF(rep); - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); Py_XDECREF(error_handler_obj); Py_XDECREF(exc); return NULL; @@ -7995,7 +7846,7 @@ encode_code_page_flags(UINT code_page, const char *errors) * an OSError and returns -1 on other error. */ static int -encode_code_page_strict(UINT code_page, PyObject **outbytes, +encode_code_page_strict(UINT code_page, PyBytesWriter **writer, PyObject *unicode, Py_ssize_t offset, int len, const char* errors) { @@ -8041,25 +7892,21 @@ encode_code_page_strict(UINT code_page, PyObject **outbytes, goto done; } - if (*outbytes == NULL) { + if (*writer == NULL) { /* Create string object */ - *outbytes = PyBytes_FromStringAndSize(NULL, outsize); - if (*outbytes == NULL) { + *writer = PyBytesWriter_Create(outsize); + if (*writer == NULL) { goto done; } - out = PyBytes_AS_STRING(*outbytes); + out = PyBytesWriter_GetData(*writer); } else { /* Extend string object */ - const Py_ssize_t n = PyBytes_Size(*outbytes); - if (outsize > PY_SSIZE_T_MAX - n) { - PyErr_NoMemory(); + Py_ssize_t n = PyBytesWriter_GetSize(*writer); + if (PyBytesWriter_Grow(*writer, outsize) < 0) { goto done; } - if (_PyBytes_Resize(outbytes, n + outsize) < 0) { - goto done; - } - out = PyBytes_AS_STRING(*outbytes) + n; + out = (char*)PyBytesWriter_GetData(*writer) + n; } /* Do the conversion */ @@ -8096,7 +7943,7 @@ error: * -1 on other error. */ static int -encode_code_page_errors(UINT code_page, PyObject **outbytes, +encode_code_page_errors(UINT code_page, PyBytesWriter **writer, PyObject *unicode, Py_ssize_t unicode_offset, Py_ssize_t insize, const char* errors) { @@ -8115,7 +7962,7 @@ encode_code_page_errors(UINT code_page, PyObject **outbytes, PyObject *exc = NULL; PyObject *encoding_obj = NULL; const char *encoding; - Py_ssize_t newpos, newoutsize; + Py_ssize_t newpos; PyObject *rep; int ret = -1; @@ -8148,23 +7995,21 @@ encode_code_page_errors(UINT code_page, PyObject **outbytes, } outsize = insize * Py_ARRAY_LENGTH(buffer); - if (*outbytes == NULL) { + if (*writer == NULL) { /* Create string object */ - *outbytes = PyBytes_FromStringAndSize(NULL, outsize); - if (*outbytes == NULL) + *writer = PyBytesWriter_Create(outsize); + if (*writer == NULL) { goto error; - out = PyBytes_AS_STRING(*outbytes); + } + out = PyBytesWriter_GetData(*writer); } else { /* Extend string object */ - Py_ssize_t n = PyBytes_Size(*outbytes); - if (n > PY_SSIZE_T_MAX - outsize) { - PyErr_NoMemory(); + Py_ssize_t n = PyBytesWriter_GetSize(*writer); + if (PyBytesWriter_Grow(*writer, outsize) < 0) { goto error; } - if (_PyBytes_Resize(outbytes, n + outsize) < 0) - goto error; - out = PyBytes_AS_STRING(*outbytes) + n; + out = (char*)PyBytesWriter_GetData(*writer) + n; } /* Encode the string character per character */ @@ -8213,13 +8058,11 @@ encode_code_page_errors(UINT code_page, PyObject **outbytes, outsize = PyBytes_GET_SIZE(rep); morebytes += outsize; if (morebytes > 0) { - Py_ssize_t offset = out - PyBytes_AS_STRING(*outbytes); - newoutsize = PyBytes_GET_SIZE(*outbytes) + morebytes; - if (_PyBytes_Resize(outbytes, newoutsize) < 0) { + out = PyBytesWriter_GrowAndUpdatePointer(*writer, morebytes, out); + if (out == NULL) { Py_DECREF(rep); goto error; } - out = PyBytes_AS_STRING(*outbytes) + offset; } memcpy(out, PyBytes_AS_STRING(rep), outsize); out += outsize; @@ -8232,13 +8075,11 @@ encode_code_page_errors(UINT code_page, PyObject **outbytes, outsize = PyUnicode_GET_LENGTH(rep); morebytes += outsize; if (morebytes > 0) { - Py_ssize_t offset = out - PyBytes_AS_STRING(*outbytes); - newoutsize = PyBytes_GET_SIZE(*outbytes) + morebytes; - if (_PyBytes_Resize(outbytes, newoutsize) < 0) { + out = PyBytesWriter_GrowAndUpdatePointer(*writer, morebytes, out); + if (out == NULL) { Py_DECREF(rep); goto error; } - out = PyBytes_AS_STRING(*outbytes) + offset; } kind = PyUnicode_KIND(rep); data = PyUnicode_DATA(rep); @@ -8261,10 +8102,11 @@ encode_code_page_errors(UINT code_page, PyObject **outbytes, } /* write a NUL byte */ *out = 0; - outsize = out - PyBytes_AS_STRING(*outbytes); - assert(outsize <= PyBytes_GET_SIZE(*outbytes)); - if (_PyBytes_Resize(outbytes, outsize) < 0) + outsize = out - (char*)PyBytesWriter_GetData(*writer); + assert(outsize <= PyBytesWriter_GetSize(*writer)); + if (PyBytesWriter_Resize(*writer, outsize) < 0) { goto error; + } ret = 0; error: @@ -8274,13 +8116,14 @@ error: return ret; } -static PyObject * -encode_code_page(int code_page, - PyObject *unicode, - const char *errors) + +PyObject * +PyUnicode_EncodeCodePage(int code_page, + PyObject *unicode, + const char *errors) { Py_ssize_t len; - PyObject *outbytes = NULL; + PyBytesWriter *writer = NULL; Py_ssize_t offset; int chunk_len, ret, done; @@ -8297,7 +8140,7 @@ encode_code_page(int code_page, } if (len == 0) - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); offset = 0; do @@ -8314,15 +8157,15 @@ encode_code_page(int code_page, done = 1; } - ret = encode_code_page_strict(code_page, &outbytes, + ret = encode_code_page_strict(code_page, &writer, unicode, offset, chunk_len, errors); if (ret == -2) - ret = encode_code_page_errors(code_page, &outbytes, + ret = encode_code_page_errors(code_page, &writer, unicode, offset, chunk_len, errors); if (ret < 0) { - Py_XDECREF(outbytes); + PyBytesWriter_Discard(writer); return NULL; } @@ -8330,16 +8173,9 @@ encode_code_page(int code_page, len -= chunk_len; } while (!done); - return outbytes; + return PyBytesWriter_Finish(writer); } -PyObject * -PyUnicode_EncodeCodePage(int code_page, - PyObject *unicode, - const char *errors) -{ - return encode_code_page(code_page, unicode, errors); -} PyObject * PyUnicode_AsMBCSString(PyObject *unicode) @@ -8849,15 +8685,13 @@ charmapencode_lookup(Py_UCS4 c, PyObject *mapping, unsigned char *replace) } static int -charmapencode_resize(PyObject **outobj, Py_ssize_t *outpos, Py_ssize_t requiredsize) +charmapencode_resize(PyBytesWriter *writer, Py_ssize_t *outpos, Py_ssize_t requiredsize) { - Py_ssize_t outsize = PyBytes_GET_SIZE(*outobj); + Py_ssize_t outsize = PyBytesWriter_GetSize(writer); /* exponentially overallocate to minimize reallocations */ - if (requiredsize < 2*outsize) - requiredsize = 2*outsize; - if (_PyBytes_Resize(outobj, requiredsize)) - return -1; - return 0; + if (requiredsize < 2 * outsize) + requiredsize = 2 * outsize; + return PyBytesWriter_Resize(writer, requiredsize); } typedef enum charmapencode_result { @@ -8871,22 +8705,26 @@ typedef enum charmapencode_result { reallocation error occurred. The caller must decref the result */ static charmapencode_result charmapencode_output(Py_UCS4 c, PyObject *mapping, - PyObject **outobj, Py_ssize_t *outpos) + PyBytesWriter *writer, Py_ssize_t *outpos) { PyObject *rep; unsigned char replace; char *outstart; - Py_ssize_t outsize = PyBytes_GET_SIZE(*outobj); + Py_ssize_t outsize = _PyBytesWriter_GetSize(writer); if (Py_IS_TYPE(mapping, &EncodingMapType)) { int res = encoding_map_lookup(c, mapping); Py_ssize_t requiredsize = *outpos+1; - if (res == -1) + if (res == -1) { return enc_FAILED; - if (outsize<requiredsize) - if (charmapencode_resize(outobj, outpos, requiredsize)) + } + + if (outsize<requiredsize) { + if (charmapencode_resize(writer, outpos, requiredsize)) { return enc_EXCEPTION; - outstart = PyBytes_AS_STRING(*outobj); + } + } + outstart = _PyBytesWriter_GetData(writer); outstart[(*outpos)++] = (char)res; return enc_SUCCESS; } @@ -8901,11 +8739,11 @@ charmapencode_output(Py_UCS4 c, PyObject *mapping, if (PyLong_Check(rep)) { Py_ssize_t requiredsize = *outpos+1; if (outsize<requiredsize) - if (charmapencode_resize(outobj, outpos, requiredsize)) { + if (charmapencode_resize(writer, outpos, requiredsize)) { Py_DECREF(rep); return enc_EXCEPTION; } - outstart = PyBytes_AS_STRING(*outobj); + outstart = _PyBytesWriter_GetData(writer); outstart[(*outpos)++] = (char)replace; } else { @@ -8913,11 +8751,11 @@ charmapencode_output(Py_UCS4 c, PyObject *mapping, Py_ssize_t repsize = PyBytes_GET_SIZE(rep); Py_ssize_t requiredsize = *outpos+repsize; if (outsize<requiredsize) - if (charmapencode_resize(outobj, outpos, requiredsize)) { + if (charmapencode_resize(writer, outpos, requiredsize)) { Py_DECREF(rep); return enc_EXCEPTION; } - outstart = PyBytes_AS_STRING(*outobj); + outstart = _PyBytesWriter_GetData(writer); memcpy(outstart + *outpos, repchars, repsize); *outpos += repsize; } @@ -8926,14 +8764,14 @@ charmapencode_output(Py_UCS4 c, PyObject *mapping, return enc_SUCCESS; } -/* handle an error in PyUnicode_EncodeCharmap +/* handle an error in _PyUnicode_EncodeCharmap() Return 0 on success, -1 on error */ static int charmap_encoding_error( PyObject *unicode, Py_ssize_t *inpos, PyObject *mapping, PyObject **exceptionObject, _Py_error_handler *error_handler, PyObject **error_handler_obj, const char *errors, - PyObject **res, Py_ssize_t *respos) + PyBytesWriter *writer, Py_ssize_t *respos) { PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ Py_ssize_t size, repsize; @@ -8988,7 +8826,7 @@ charmap_encoding_error( case _Py_ERROR_REPLACE: for (collpos = collstartpos; collpos<collendpos; ++collpos) { - x = charmapencode_output('?', mapping, res, respos); + x = charmapencode_output('?', mapping, writer, respos); if (x==enc_EXCEPTION) { return -1; } @@ -9009,7 +8847,7 @@ charmap_encoding_error( char *cp; sprintf(buffer, "&#%d;", (int)PyUnicode_READ_CHAR(unicode, collpos)); for (cp = buffer; *cp; ++cp) { - x = charmapencode_output(*cp, mapping, res, respos); + x = charmapencode_output(*cp, mapping, writer, respos); if (x==enc_EXCEPTION) return -1; else if (x==enc_FAILED) { @@ -9029,17 +8867,17 @@ charmap_encoding_error( return -1; if (PyBytes_Check(repunicode)) { /* Directly copy bytes result to output. */ - Py_ssize_t outsize = PyBytes_Size(*res); + Py_ssize_t outsize = PyBytesWriter_GetSize(writer); Py_ssize_t requiredsize; repsize = PyBytes_Size(repunicode); requiredsize = *respos + repsize; if (requiredsize > outsize) /* Make room for all additional bytes. */ - if (charmapencode_resize(res, respos, requiredsize)) { + if (charmapencode_resize(writer, respos, requiredsize)) { Py_DECREF(repunicode); return -1; } - memcpy(PyBytes_AsString(*res) + *respos, + memcpy((char*)PyBytesWriter_GetData(writer) + *respos, PyBytes_AsString(repunicode), repsize); *respos += repsize; *inpos = newpos; @@ -9052,7 +8890,7 @@ charmap_encoding_error( kind = PyUnicode_KIND(repunicode); for (index = 0; index < repsize; index++) { Py_UCS4 repch = PyUnicode_READ(kind, data, index); - x = charmapencode_output(repch, mapping, res, respos); + x = charmapencode_output(repch, mapping, writer, respos); if (x==enc_EXCEPTION) { Py_DECREF(repunicode); return -1; @@ -9074,65 +8912,105 @@ _PyUnicode_EncodeCharmap(PyObject *unicode, PyObject *mapping, const char *errors) { - /* output object */ - PyObject *res = NULL; - /* current input position */ - Py_ssize_t inpos = 0; - Py_ssize_t size; - /* current output position */ - Py_ssize_t respos = 0; + /* Default to Latin-1 */ + if (mapping == NULL) { + return unicode_encode_ucs1(unicode, errors, 256); + } + + Py_ssize_t size = PyUnicode_GET_LENGTH(unicode); + if (size == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } + const void *data = PyUnicode_DATA(unicode); + int kind = PyUnicode_KIND(unicode); + PyObject *error_handler_obj = NULL; PyObject *exc = NULL; - _Py_error_handler error_handler = _Py_ERROR_UNKNOWN; - const void *data; - int kind; - - size = PyUnicode_GET_LENGTH(unicode); - data = PyUnicode_DATA(unicode); - kind = PyUnicode_KIND(unicode); - - /* Default to Latin-1 */ - if (mapping == NULL) - return unicode_encode_ucs1(unicode, errors, 256); + /* output object */ + PyBytesWriter *writer; /* allocate enough for a simple encoding without replacements, if we need more, we'll resize */ - res = PyBytes_FromStringAndSize(NULL, size); - if (res == NULL) + writer = PyBytesWriter_Create(size); + if (writer == NULL) { goto onError; - if (size == 0) - return res; + } - while (inpos<size) { - Py_UCS4 ch = PyUnicode_READ(kind, data, inpos); - /* try to encode it */ - charmapencode_result x = charmapencode_output(ch, mapping, &res, &respos); - if (x==enc_EXCEPTION) /* error */ - goto onError; - if (x==enc_FAILED) { /* unencodable character */ + /* current input position */ + Py_ssize_t inpos = 0; + /* current output position */ + Py_ssize_t respos = 0; + _Py_error_handler error_handler = _Py_ERROR_UNKNOWN; + + if (Py_IS_TYPE(mapping, &EncodingMapType)) { + char *outstart = _PyBytesWriter_GetData(writer); + Py_ssize_t outsize = _PyBytesWriter_GetSize(writer); + + while (inpos<size) { + Py_UCS4 ch = PyUnicode_READ(kind, data, inpos); + + /* try to encode it */ + int res = encoding_map_lookup(ch, mapping); + Py_ssize_t requiredsize = respos+1; + if (res == -1) { + goto enc_FAILED; + } + + if (outsize<requiredsize) { + if (charmapencode_resize(writer, &respos, requiredsize)) { + goto onError; + } + outstart = _PyBytesWriter_GetData(writer); + outsize = _PyBytesWriter_GetSize(writer); + } + outstart[respos++] = (char)res; + + /* done with this character => adjust input position */ + ++inpos; + continue; + +enc_FAILED: if (charmap_encoding_error(unicode, &inpos, mapping, &exc, &error_handler, &error_handler_obj, errors, - &res, &respos)) { + writer, &respos)) { goto onError; } + outstart = _PyBytesWriter_GetData(writer); + outsize = _PyBytesWriter_GetSize(writer); + } + } + else { + while (inpos<size) { + Py_UCS4 ch = PyUnicode_READ(kind, data, inpos); + /* try to encode it */ + charmapencode_result x = charmapencode_output(ch, mapping, writer, &respos); + if (x==enc_EXCEPTION) { /* error */ + goto onError; + } + if (x==enc_FAILED) { /* unencodable character */ + if (charmap_encoding_error(unicode, &inpos, mapping, + &exc, + &error_handler, &error_handler_obj, errors, + writer, &respos)) { + goto onError; + } + } + else { + /* done with this character => adjust input position */ + ++inpos; + } } - else - /* done with this character => adjust input position */ - ++inpos; } - - /* Resize if we allocated to much */ - if (respos<PyBytes_GET_SIZE(res)) - if (_PyBytes_Resize(&res, respos) < 0) - goto onError; Py_XDECREF(exc); Py_XDECREF(error_handler_obj); - return res; + + /* Resize if we allocated too much */ + return PyBytesWriter_FinishWithSize(writer, respos); onError: - Py_XDECREF(res); + PyBytesWriter_Discard(writer); Py_XDECREF(exc); Py_XDECREF(error_handler_obj); return NULL; @@ -9718,142 +9596,6 @@ any_find_slice(PyObject* s1, PyObject* s2, return result; } -/* _PyUnicode_InsertThousandsGrouping() helper functions */ -#include "stringlib/localeutil.h" - -/** - * InsertThousandsGrouping: - * @writer: Unicode writer. - * @n_buffer: Number of characters in @buffer. - * @digits: Digits we're reading from. If count is non-NULL, this is unused. - * @d_pos: Start of digits string. - * @n_digits: The number of digits in the string, in which we want - * to put the grouping chars. - * @min_width: The minimum width of the digits in the output string. - * Output will be zero-padded on the left to fill. - * @grouping: see definition in localeconv(). - * @thousands_sep: see definition in localeconv(). - * - * There are 2 modes: counting and filling. If @writer is NULL, - * we are in counting mode, else filling mode. - * If counting, the required buffer size is returned. - * If filling, we know the buffer will be large enough, so we don't - * need to pass in the buffer size. - * Inserts thousand grouping characters (as defined by grouping and - * thousands_sep) into @writer. - * - * Return value: -1 on error, number of characters otherwise. - **/ -Py_ssize_t -_PyUnicode_InsertThousandsGrouping( - _PyUnicodeWriter *writer, - Py_ssize_t n_buffer, - PyObject *digits, - Py_ssize_t d_pos, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - PyObject *thousands_sep, - Py_UCS4 *maxchar, - int forward) -{ - min_width = Py_MAX(0, min_width); - if (writer) { - assert(digits != NULL); - assert(maxchar == NULL); - } - else { - assert(digits == NULL); - assert(maxchar != NULL); - } - assert(0 <= d_pos); - assert(0 <= n_digits); - assert(grouping != NULL); - - Py_ssize_t count = 0; - Py_ssize_t n_zeros; - int loop_broken = 0; - int use_separator = 0; /* First time through, don't append the - separator. They only go between - groups. */ - Py_ssize_t buffer_pos; - Py_ssize_t digits_pos; - Py_ssize_t len; - Py_ssize_t n_chars; - Py_ssize_t remaining = n_digits; /* Number of chars remaining to - be looked at */ - /* A generator that returns all of the grouping widths, until it - returns 0. */ - GroupGenerator groupgen; - GroupGenerator_init(&groupgen, grouping); - const Py_ssize_t thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep); - - /* if digits are not grouped, thousands separator - should be an empty string */ - assert(!(grouping[0] == CHAR_MAX && thousands_sep_len != 0)); - - digits_pos = d_pos + (forward ? 0 : n_digits); - if (writer) { - buffer_pos = writer->pos + (forward ? 0 : n_buffer); - assert(buffer_pos <= PyUnicode_GET_LENGTH(writer->buffer)); - assert(digits_pos <= PyUnicode_GET_LENGTH(digits)); - } - else { - buffer_pos = forward ? 0 : n_buffer; - } - - if (!writer) { - *maxchar = 127; - } - - while ((len = GroupGenerator_next(&groupgen)) > 0) { - len = Py_MIN(len, Py_MAX(Py_MAX(remaining, min_width), 1)); - n_zeros = Py_MAX(0, len - remaining); - n_chars = Py_MAX(0, Py_MIN(remaining, len)); - - /* Use n_zero zero's and n_chars chars */ - - /* Count only, don't do anything. */ - count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars; - - /* Copy into the writer. */ - InsertThousandsGrouping_fill(writer, &buffer_pos, - digits, &digits_pos, - n_chars, n_zeros, - use_separator ? thousands_sep : NULL, - thousands_sep_len, maxchar, forward); - - /* Use a separator next time. */ - use_separator = 1; - - remaining -= n_chars; - min_width -= len; - - if (remaining <= 0 && min_width <= 0) { - loop_broken = 1; - break; - } - min_width -= thousands_sep_len; - } - if (!loop_broken) { - /* We left the loop without using a break statement. */ - - len = Py_MAX(Py_MAX(remaining, min_width), 1); - n_zeros = Py_MAX(0, len - remaining); - n_chars = Py_MAX(0, Py_MIN(remaining, len)); - - /* Use n_zero zero's and n_chars chars */ - count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars; - - /* Copy into the writer. */ - InsertThousandsGrouping_fill(writer, &buffer_pos, - digits, &digits_pos, - n_chars, n_zeros, - use_separator ? thousands_sep : NULL, - thousands_sep_len, maxchar, forward); - } - return count; -} Py_ssize_t PyUnicode_Count(PyObject *str, @@ -10406,11 +10148,11 @@ _PyUnicode_FastFill(PyObject *unicode, Py_ssize_t start, Py_ssize_t length, { const int kind = PyUnicode_KIND(unicode); void *data = PyUnicode_DATA(unicode); - assert(unicode_modifiable(unicode)); + assert(_PyUnicode_IsModifiable(unicode)); assert(fill_char <= PyUnicode_MAX_CHAR_VALUE(unicode)); assert(start >= 0); assert(start + length <= PyUnicode_GET_LENGTH(unicode)); - unicode_fill(kind, data, fill_char, start, length); + _PyUnicode_Fill(kind, data, fill_char, start, length); } Py_ssize_t @@ -10479,9 +10221,10 @@ pad(PyObject *self, kind = PyUnicode_KIND(u); data = PyUnicode_DATA(u); if (left) - unicode_fill(kind, data, fill, 0, left); + _PyUnicode_Fill(kind, data, fill, 0, left); if (right) - unicode_fill(kind, data, fill, left + _PyUnicode_LENGTH(self), right); + _PyUnicode_Fill(kind, data, fill, + left + _PyUnicode_LENGTH(self), right); _PyUnicode_FastCopyCharacters(u, left, self, 0, _PyUnicode_LENGTH(self)); assert(_PyUnicode_CheckConsistency(u, 1)); return u; @@ -10933,7 +10676,7 @@ replace(PyObject *self, PyObject *str1, } new_size = slen + n * (len2 - len1); if (new_size == 0) { - u = unicode_get_empty(); + u = _PyUnicode_GetEmpty(); goto done; } if (new_size > (PY_SSIZE_T_MAX / rkind)) { @@ -11451,47 +11194,6 @@ _PyUnicode_EqualToASCIIString(PyObject *unicode, const char *str) memcmp(PyUnicode_1BYTE_DATA(unicode), str, len) == 0; } -int -_PyUnicode_EqualToASCIIId(PyObject *left, _Py_Identifier *right) -{ - PyObject *right_uni; - - assert(_PyUnicode_CHECK(left)); - assert(right->string); -#ifndef NDEBUG - for (const char *p = right->string; *p; p++) { - assert((unsigned char)*p < 128); - } -#endif - - if (!PyUnicode_IS_ASCII(left)) - return 0; - - right_uni = _PyUnicode_FromId(right); /* borrowed */ - if (right_uni == NULL) { - /* memory error or bad data */ - PyErr_Clear(); - return _PyUnicode_EqualToASCIIString(left, right->string); - } - - if (left == right_uni) - return 1; - - assert(PyUnicode_CHECK_INTERNED(right_uni)); - if (PyUnicode_CHECK_INTERNED(left)) { - return 0; - } - - Py_hash_t right_hash = PyUnicode_HASH(right_uni); - assert(right_hash != -1); - Py_hash_t hash = PyUnicode_HASH(left); - if (hash != -1 && hash != right_hash) { - return 0; - } - - return unicode_eq(left, right_uni); -} - PyObject * PyUnicode_RichCompare(PyObject *left, PyObject *right, int op) { @@ -11606,7 +11308,7 @@ PyUnicode_Concat(PyObject *left, PyObject *right) } /* Shortcuts */ - PyObject *empty = unicode_get_empty(); // Borrowed reference + PyObject *empty = _PyUnicode_GetEmpty(); // Borrowed reference if (left == empty) { return PyUnicode_FromObject(right); } @@ -11658,7 +11360,7 @@ PyUnicode_Append(PyObject **p_left, PyObject *right) } /* Shortcuts */ - PyObject *empty = unicode_get_empty(); // Borrowed reference + PyObject *empty = _PyUnicode_GetEmpty(); // Borrowed reference if (left == empty) { Py_DECREF(left); *p_left = Py_NewRef(right); @@ -11677,7 +11379,7 @@ PyUnicode_Append(PyObject **p_left, PyObject *right) } new_len = left_len + right_len; - if (unicode_modifiable(left) + if (_PyUnicode_IsModifiable(left) && PyUnicode_CheckExact(right) && PyUnicode_KIND(right) <= PyUnicode_KIND(left) /* Don't resize for ascii += latin1. Convert ascii to latin1 requires @@ -11893,7 +11595,7 @@ unicode_expandtabs_impl(PyObject *self, int tabsize) if (tabsize > 0) { incr = tabsize - (line_pos % tabsize); line_pos += incr; - unicode_fill(kind, dest_data, ' ', j, incr); + _PyUnicode_Fill(kind, dest_data, ' ', j, incr); j += incr; } } @@ -13154,7 +12856,7 @@ PyUnicode_Partition(PyObject *str_obj, PyObject *sep_obj) len1 = PyUnicode_GET_LENGTH(str_obj); len2 = PyUnicode_GET_LENGTH(sep_obj); if (kind1 < kind2 || len1 < len2) { - PyObject *empty = unicode_get_empty(); // Borrowed reference + PyObject *empty = _PyUnicode_GetEmpty(); // Borrowed reference return PyTuple_Pack(3, str_obj, empty, empty); } buf1 = PyUnicode_DATA(str_obj); @@ -13206,7 +12908,7 @@ PyUnicode_RPartition(PyObject *str_obj, PyObject *sep_obj) len1 = PyUnicode_GET_LENGTH(str_obj); len2 = PyUnicode_GET_LENGTH(sep_obj); if (kind1 < kind2 || len1 < len2) { - PyObject *empty = unicode_get_empty(); // Borrowed reference + PyObject *empty = _PyUnicode_GetEmpty(); // Borrowed reference return PyTuple_Pack(3, empty, empty, str_obj); } buf1 = PyUnicode_DATA(str_obj); @@ -13685,534 +13387,6 @@ unicode_endswith_impl(PyObject *self, PyObject *subobj, Py_ssize_t start, } -static inline void -_PyUnicodeWriter_Update(_PyUnicodeWriter *writer) -{ - writer->maxchar = PyUnicode_MAX_CHAR_VALUE(writer->buffer); - writer->data = PyUnicode_DATA(writer->buffer); - - if (!writer->readonly) { - writer->kind = PyUnicode_KIND(writer->buffer); - writer->size = PyUnicode_GET_LENGTH(writer->buffer); - } - else { - /* use a value smaller than PyUnicode_1BYTE_KIND() so - _PyUnicodeWriter_PrepareKind() will copy the buffer. */ - writer->kind = 0; - assert(writer->kind <= PyUnicode_1BYTE_KIND); - - /* Copy-on-write mode: set buffer size to 0 so - * _PyUnicodeWriter_Prepare() will copy (and enlarge) the buffer on - * next write. */ - writer->size = 0; - } -} - - -void -_PyUnicodeWriter_Init(_PyUnicodeWriter *writer) -{ - memset(writer, 0, sizeof(*writer)); - - /* ASCII is the bare minimum */ - writer->min_char = 127; - - /* use a kind value smaller than PyUnicode_1BYTE_KIND so - _PyUnicodeWriter_PrepareKind() will copy the buffer. */ - assert(writer->kind == 0); - assert(writer->kind < PyUnicode_1BYTE_KIND); -} - - -PyUnicodeWriter* -PyUnicodeWriter_Create(Py_ssize_t length) -{ - if (length < 0) { - PyErr_SetString(PyExc_ValueError, - "length must be positive"); - return NULL; - } - - const size_t size = sizeof(_PyUnicodeWriter); - PyUnicodeWriter *pub_writer; - pub_writer = _Py_FREELIST_POP_MEM(unicode_writers); - if (pub_writer == NULL) { - pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size); - if (pub_writer == NULL) { - return (PyUnicodeWriter *)PyErr_NoMemory(); - } - } - _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer; - - _PyUnicodeWriter_Init(writer); - if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) { - PyUnicodeWriter_Discard(pub_writer); - return NULL; - } - writer->overallocate = 1; - - return pub_writer; -} - - -void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) -{ - if (writer == NULL) { - return; - } - _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer); - _Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free); -} - - -// Initialize _PyUnicodeWriter with initial buffer -static inline void -_PyUnicodeWriter_InitWithBuffer(_PyUnicodeWriter *writer, PyObject *buffer) -{ - memset(writer, 0, sizeof(*writer)); - writer->buffer = buffer; - _PyUnicodeWriter_Update(writer); - writer->min_length = writer->size; -} - - -int -_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, - Py_ssize_t length, Py_UCS4 maxchar) -{ - Py_ssize_t newlen; - PyObject *newbuffer; - - assert(length >= 0); - assert(maxchar <= MAX_UNICODE); - - /* ensure that the _PyUnicodeWriter_Prepare macro was used */ - assert((maxchar > writer->maxchar && length >= 0) - || length > 0); - - if (length > PY_SSIZE_T_MAX - writer->pos) { - PyErr_NoMemory(); - return -1; - } - newlen = writer->pos + length; - - maxchar = Py_MAX(maxchar, writer->min_char); - - if (writer->buffer == NULL) { - assert(!writer->readonly); - if (writer->overallocate - && newlen <= (PY_SSIZE_T_MAX - newlen / OVERALLOCATE_FACTOR)) { - /* overallocate to limit the number of realloc() */ - newlen += newlen / OVERALLOCATE_FACTOR; - } - if (newlen < writer->min_length) - newlen = writer->min_length; - - writer->buffer = PyUnicode_New(newlen, maxchar); - if (writer->buffer == NULL) - return -1; - } - else if (newlen > writer->size) { - if (writer->overallocate - && newlen <= (PY_SSIZE_T_MAX - newlen / OVERALLOCATE_FACTOR)) { - /* overallocate to limit the number of realloc() */ - newlen += newlen / OVERALLOCATE_FACTOR; - } - if (newlen < writer->min_length) - newlen = writer->min_length; - - if (maxchar > writer->maxchar || writer->readonly) { - /* resize + widen */ - maxchar = Py_MAX(maxchar, writer->maxchar); - newbuffer = PyUnicode_New(newlen, maxchar); - if (newbuffer == NULL) - return -1; - _PyUnicode_FastCopyCharacters(newbuffer, 0, - writer->buffer, 0, writer->pos); - Py_DECREF(writer->buffer); - writer->readonly = 0; - } - else { - newbuffer = resize_compact(writer->buffer, newlen); - if (newbuffer == NULL) - return -1; - } - writer->buffer = newbuffer; - } - else if (maxchar > writer->maxchar) { - assert(!writer->readonly); - newbuffer = PyUnicode_New(writer->size, maxchar); - if (newbuffer == NULL) - return -1; - _PyUnicode_FastCopyCharacters(newbuffer, 0, - writer->buffer, 0, writer->pos); - Py_SETREF(writer->buffer, newbuffer); - } - _PyUnicodeWriter_Update(writer); - return 0; - -#undef OVERALLOCATE_FACTOR -} - -int -_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer, - int kind) -{ - Py_UCS4 maxchar; - - /* ensure that the _PyUnicodeWriter_PrepareKind macro was used */ - assert(writer->kind < kind); - - switch (kind) - { - case PyUnicode_1BYTE_KIND: maxchar = 0xff; break; - case PyUnicode_2BYTE_KIND: maxchar = 0xffff; break; - case PyUnicode_4BYTE_KIND: maxchar = MAX_UNICODE; break; - default: - Py_UNREACHABLE(); - } - - return _PyUnicodeWriter_PrepareInternal(writer, 0, maxchar); -} - -static inline int -_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch) -{ - assert(ch <= MAX_UNICODE); - if (_PyUnicodeWriter_Prepare(writer, 1, ch) < 0) - return -1; - PyUnicode_WRITE(writer->kind, writer->data, writer->pos, ch); - writer->pos++; - return 0; -} - -int -_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, Py_UCS4 ch) -{ - return _PyUnicodeWriter_WriteCharInline(writer, ch); -} - -int -PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch) -{ - if (ch > MAX_UNICODE) { - PyErr_SetString(PyExc_ValueError, - "character must be in range(0x110000)"); - return -1; - } - - return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch); -} - -int -_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str) -{ - assert(PyUnicode_Check(str)); - - Py_UCS4 maxchar; - Py_ssize_t len; - - len = PyUnicode_GET_LENGTH(str); - if (len == 0) - return 0; - maxchar = PyUnicode_MAX_CHAR_VALUE(str); - if (maxchar > writer->maxchar || len > writer->size - writer->pos) { - if (writer->buffer == NULL && !writer->overallocate) { - assert(_PyUnicode_CheckConsistency(str, 1)); - writer->readonly = 1; - writer->buffer = Py_NewRef(str); - _PyUnicodeWriter_Update(writer); - writer->pos += len; - return 0; - } - if (_PyUnicodeWriter_PrepareInternal(writer, len, maxchar) == -1) - return -1; - } - _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, - str, 0, len); - writer->pos += len; - return 0; -} - -int -PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj) -{ - PyTypeObject *type = Py_TYPE(obj); - if (type == &PyUnicode_Type) { - return _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, obj); - } - - if (type == &PyLong_Type) { - return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0); - } - - PyObject *str = PyObject_Str(obj); - if (str == NULL) { - return -1; - } - - int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); - Py_DECREF(str); - return res; -} - - -int -PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj) -{ - if (Py_TYPE(obj) == &PyLong_Type) { - return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0); - } - - PyObject *repr = PyObject_Repr(obj); - if (repr == NULL) { - return -1; - } - - int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, repr); - Py_DECREF(repr); - return res; -} - - -int -_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, PyObject *str, - Py_ssize_t start, Py_ssize_t end) -{ - assert(0 <= start); - assert(end <= PyUnicode_GET_LENGTH(str)); - assert(start <= end); - - if (start == 0 && end == PyUnicode_GET_LENGTH(str)) - return _PyUnicodeWriter_WriteStr(writer, str); - - Py_ssize_t len = end - start; - if (len == 0) { - return 0; - } - - Py_UCS4 maxchar; - if (PyUnicode_MAX_CHAR_VALUE(str) > writer->maxchar) { - maxchar = _PyUnicode_FindMaxChar(str, start, end); - } - else { - maxchar = writer->maxchar; - } - if (_PyUnicodeWriter_Prepare(writer, len, maxchar) < 0) { - return -1; - } - - _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, - str, start, len); - writer->pos += len; - return 0; -} - - -int -PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, - Py_ssize_t start, Py_ssize_t end) -{ - if (!PyUnicode_Check(str)) { - PyErr_Format(PyExc_TypeError, "expect str, not %T", str); - return -1; - } - if (start < 0 || start > end) { - PyErr_Format(PyExc_ValueError, "invalid start argument"); - return -1; - } - if (end > PyUnicode_GET_LENGTH(str)) { - PyErr_Format(PyExc_ValueError, "invalid end argument"); - return -1; - } - - return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str, - start, end); -} - - -int -_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, - const char *ascii, Py_ssize_t len) -{ - if (len == -1) - len = strlen(ascii); - - assert(ucs1lib_find_max_char((const Py_UCS1*)ascii, (const Py_UCS1*)ascii + len) < 128); - - if (writer->buffer == NULL && !writer->overallocate) { - PyObject *str; - - str = _PyUnicode_FromASCII(ascii, len); - if (str == NULL) - return -1; - - writer->readonly = 1; - writer->buffer = str; - _PyUnicodeWriter_Update(writer); - writer->pos += len; - return 0; - } - - if (_PyUnicodeWriter_Prepare(writer, len, 127) == -1) - return -1; - - switch (writer->kind) - { - case PyUnicode_1BYTE_KIND: - { - const Py_UCS1 *str = (const Py_UCS1 *)ascii; - Py_UCS1 *data = writer->data; - - memcpy(data + writer->pos, str, len); - break; - } - case PyUnicode_2BYTE_KIND: - { - _PyUnicode_CONVERT_BYTES( - Py_UCS1, Py_UCS2, - ascii, ascii + len, - (Py_UCS2 *)writer->data + writer->pos); - break; - } - case PyUnicode_4BYTE_KIND: - { - _PyUnicode_CONVERT_BYTES( - Py_UCS1, Py_UCS4, - ascii, ascii + len, - (Py_UCS4 *)writer->data + writer->pos); - break; - } - default: - Py_UNREACHABLE(); - } - - writer->pos += len; - return 0; -} - - -int -PyUnicodeWriter_WriteASCII(PyUnicodeWriter *writer, - const char *str, - Py_ssize_t size) -{ - assert(writer != NULL); - _Py_AssertHoldsTstate(); - - _PyUnicodeWriter *priv_writer = (_PyUnicodeWriter*)writer; - return _PyUnicodeWriter_WriteASCIIString(priv_writer, str, size); -} - - -int -PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, - const char *str, - Py_ssize_t size) -{ - if (size < 0) { - size = strlen(str); - } - - _PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer; - Py_ssize_t old_pos = _writer->pos; - int res = unicode_decode_utf8_writer(_writer, str, size, - _Py_ERROR_STRICT, NULL, NULL); - if (res < 0) { - _writer->pos = old_pos; - } - return res; -} - - -int -PyUnicodeWriter_DecodeUTF8Stateful(PyUnicodeWriter *writer, - const char *string, - Py_ssize_t length, - const char *errors, - Py_ssize_t *consumed) -{ - if (length < 0) { - length = strlen(string); - } - - _PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer; - Py_ssize_t old_pos = _writer->pos; - int res = unicode_decode_utf8_writer(_writer, string, length, - _Py_ERROR_UNKNOWN, errors, consumed); - if (res < 0) { - _writer->pos = old_pos; - if (consumed) { - *consumed = 0; - } - } - return res; -} - - -int -_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, - const char *str, Py_ssize_t len) -{ - Py_UCS4 maxchar; - - maxchar = ucs1lib_find_max_char((const Py_UCS1*)str, (const Py_UCS1*)str + len); - if (_PyUnicodeWriter_Prepare(writer, len, maxchar) == -1) - return -1; - unicode_write_cstr(writer->buffer, writer->pos, str, len); - writer->pos += len; - return 0; -} - -PyObject * -_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer) -{ - PyObject *str; - - if (writer->pos == 0) { - Py_CLEAR(writer->buffer); - _Py_RETURN_UNICODE_EMPTY(); - } - - str = writer->buffer; - writer->buffer = NULL; - - if (writer->readonly) { - assert(PyUnicode_GET_LENGTH(str) == writer->pos); - return str; - } - - if (PyUnicode_GET_LENGTH(str) != writer->pos) { - PyObject *str2; - str2 = resize_compact(str, writer->pos); - if (str2 == NULL) { - Py_DECREF(str); - return NULL; - } - str = str2; - } - - assert(_PyUnicode_CheckConsistency(str, 1)); - return unicode_result(str); -} - - -PyObject* -PyUnicodeWriter_Finish(PyUnicodeWriter *writer) -{ - PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer); - assert(((_PyUnicodeWriter*)writer)->buffer == NULL); - _Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free); - return str; -} - - -void -_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer) -{ - Py_CLEAR(writer->buffer); -} - #include "stringlib/unicode_format.h" PyDoc_STRVAR(format__doc__, @@ -14614,947 +13788,6 @@ static PyMappingMethods unicode_as_mapping = { }; -/* Helpers for PyUnicode_Format() */ - -struct unicode_formatter_t { - PyObject *args; - int args_owned; - Py_ssize_t arglen, argidx; - PyObject *dict; - - int fmtkind; - Py_ssize_t fmtcnt, fmtpos; - const void *fmtdata; - PyObject *fmtstr; - - _PyUnicodeWriter writer; -}; - -struct unicode_format_arg_t { - Py_UCS4 ch; - int flags; - Py_ssize_t width; - int prec; - int sign; -}; - -static PyObject * -unicode_format_getnextarg(struct unicode_formatter_t *ctx) -{ - Py_ssize_t argidx = ctx->argidx; - - if (argidx < ctx->arglen) { - ctx->argidx++; - if (ctx->arglen < 0) - return ctx->args; - else - return PyTuple_GetItem(ctx->args, argidx); - } - PyErr_SetString(PyExc_TypeError, - "not enough arguments for format string"); - return NULL; -} - -/* Returns a new reference to a PyUnicode object, or NULL on failure. */ - -/* Format a float into the writer if the writer is not NULL, or into *p_output - otherwise. - - Return 0 on success, raise an exception and return -1 on error. */ -static int -formatfloat(PyObject *v, struct unicode_format_arg_t *arg, - PyObject **p_output, - _PyUnicodeWriter *writer) -{ - char *p; - double x; - Py_ssize_t len; - int prec; - int dtoa_flags = 0; - - x = PyFloat_AsDouble(v); - if (x == -1.0 && PyErr_Occurred()) - return -1; - - prec = arg->prec; - if (prec < 0) - prec = 6; - - if (arg->flags & F_ALT) - dtoa_flags |= Py_DTSF_ALT; - p = PyOS_double_to_string(x, arg->ch, prec, dtoa_flags, NULL); - if (p == NULL) - return -1; - len = strlen(p); - if (writer) { - if (_PyUnicodeWriter_WriteASCIIString(writer, p, len) < 0) { - PyMem_Free(p); - return -1; - } - } - else - *p_output = _PyUnicode_FromASCII(p, len); - PyMem_Free(p); - return 0; -} - -/* formatlong() emulates the format codes d, u, o, x and X, and - * the F_ALT flag, for Python's long (unbounded) ints. It's not used for - * Python's regular ints. - * Return value: a new PyUnicodeObject*, or NULL if error. - * The output string is of the form - * "-"? ("0x" | "0X")? digit+ - * "0x"/"0X" are present only for x and X conversions, with F_ALT - * set in flags. The case of hex digits will be correct, - * There will be at least prec digits, zero-filled on the left if - * necessary to get that many. - * val object to be converted - * flags bitmask of format flags; only F_ALT is looked at - * prec minimum number of digits; 0-fill on left if needed - * type a character in [duoxX]; u acts the same as d - * - * CAUTION: o, x and X conversions on regular ints can never - * produce a '-' sign, but can for Python's unbounded ints. - */ -PyObject * -_PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type) -{ - PyObject *result = NULL; - char *buf; - Py_ssize_t i; - int sign; /* 1 if '-', else 0 */ - int len; /* number of characters */ - Py_ssize_t llen; - int numdigits; /* len == numnondigits + numdigits */ - int numnondigits = 0; - - /* Avoid exceeding SSIZE_T_MAX */ - if (prec > INT_MAX-3) { - PyErr_SetString(PyExc_OverflowError, - "precision too large"); - return NULL; - } - - assert(PyLong_Check(val)); - - switch (type) { - default: - Py_UNREACHABLE(); - case 'd': - case 'i': - case 'u': - /* int and int subclasses should print numerically when a numeric */ - /* format code is used (see issue18780) */ - result = PyNumber_ToBase(val, 10); - break; - case 'o': - numnondigits = 2; - result = PyNumber_ToBase(val, 8); - break; - case 'x': - case 'X': - numnondigits = 2; - result = PyNumber_ToBase(val, 16); - break; - } - if (!result) - return NULL; - - assert(unicode_modifiable(result)); - assert(PyUnicode_IS_ASCII(result)); - - /* To modify the string in-place, there can only be one reference. */ - if (!_PyObject_IsUniquelyReferenced(result)) { - Py_DECREF(result); - PyErr_BadInternalCall(); - return NULL; - } - buf = PyUnicode_DATA(result); - llen = PyUnicode_GET_LENGTH(result); - if (llen > INT_MAX) { - Py_DECREF(result); - PyErr_SetString(PyExc_ValueError, - "string too large in _PyUnicode_FormatLong"); - return NULL; - } - len = (int)llen; - sign = buf[0] == '-'; - numnondigits += sign; - numdigits = len - numnondigits; - assert(numdigits > 0); - - /* Get rid of base marker unless F_ALT */ - if (((alt) == 0 && - (type == 'o' || type == 'x' || type == 'X'))) { - assert(buf[sign] == '0'); - assert(buf[sign+1] == 'x' || buf[sign+1] == 'X' || - buf[sign+1] == 'o'); - numnondigits -= 2; - buf += 2; - len -= 2; - if (sign) - buf[0] = '-'; - assert(len == numnondigits + numdigits); - assert(numdigits > 0); - } - - /* Fill with leading zeroes to meet minimum width. */ - if (prec > numdigits) { - PyObject *r1 = PyBytes_FromStringAndSize(NULL, - numnondigits + prec); - char *b1; - if (!r1) { - Py_DECREF(result); - return NULL; - } - b1 = PyBytes_AS_STRING(r1); - for (i = 0; i < numnondigits; ++i) - *b1++ = *buf++; - for (i = 0; i < prec - numdigits; i++) - *b1++ = '0'; - for (i = 0; i < numdigits; i++) - *b1++ = *buf++; - *b1 = '\0'; - Py_SETREF(result, r1); - buf = PyBytes_AS_STRING(result); - len = numnondigits + prec; - } - - /* Fix up case for hex conversions. */ - if (type == 'X') { - /* Need to convert all lower case letters to upper case. - and need to convert 0x to 0X (and -0x to -0X). */ - for (i = 0; i < len; i++) - if (buf[i] >= 'a' && buf[i] <= 'x') - buf[i] -= 'a'-'A'; - } - if (!PyUnicode_Check(result) - || buf != PyUnicode_DATA(result)) { - PyObject *unicode; - unicode = _PyUnicode_FromASCII(buf, len); - Py_SETREF(result, unicode); - } - else if (len != PyUnicode_GET_LENGTH(result)) { - if (PyUnicode_Resize(&result, len) < 0) - Py_CLEAR(result); - } - return result; -} - -/* Format an integer or a float as an integer. - * Return 1 if the number has been formatted into the writer, - * 0 if the number has been formatted into *p_output - * -1 and raise an exception on error */ -static int -mainformatlong(PyObject *v, - struct unicode_format_arg_t *arg, - PyObject **p_output, - _PyUnicodeWriter *writer) -{ - PyObject *iobj, *res; - char type = (char)arg->ch; - - if (!PyNumber_Check(v)) - goto wrongtype; - - /* make sure number is a type of integer for o, x, and X */ - if (!PyLong_Check(v)) { - if (type == 'o' || type == 'x' || type == 'X') { - iobj = _PyNumber_Index(v); - } - else { - iobj = PyNumber_Long(v); - } - if (iobj == NULL ) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - goto wrongtype; - return -1; - } - assert(PyLong_Check(iobj)); - } - else { - iobj = Py_NewRef(v); - } - - if (PyLong_CheckExact(v) - && arg->width == -1 && arg->prec == -1 - && !(arg->flags & (F_SIGN | F_BLANK)) - && type != 'X') - { - /* Fast path */ - int alternate = arg->flags & F_ALT; - int base; - - switch(type) - { - default: - Py_UNREACHABLE(); - case 'd': - case 'i': - case 'u': - base = 10; - break; - case 'o': - base = 8; - break; - case 'x': - case 'X': - base = 16; - break; - } - - if (_PyLong_FormatWriter(writer, v, base, alternate) == -1) { - Py_DECREF(iobj); - return -1; - } - Py_DECREF(iobj); - return 1; - } - - res = _PyUnicode_FormatLong(iobj, arg->flags & F_ALT, arg->prec, type); - Py_DECREF(iobj); - if (res == NULL) - return -1; - *p_output = res; - return 0; - -wrongtype: - switch(type) - { - case 'o': - case 'x': - case 'X': - PyErr_Format(PyExc_TypeError, - "%%%c format: an integer is required, " - "not %.200s", - type, Py_TYPE(v)->tp_name); - break; - default: - PyErr_Format(PyExc_TypeError, - "%%%c format: a real number is required, " - "not %.200s", - type, Py_TYPE(v)->tp_name); - break; - } - return -1; -} - -static Py_UCS4 -formatchar(PyObject *v) -{ - /* presume that the buffer is at least 3 characters long */ - if (PyUnicode_Check(v)) { - if (PyUnicode_GET_LENGTH(v) == 1) { - return PyUnicode_READ_CHAR(v, 0); - } - PyErr_Format(PyExc_TypeError, - "%%c requires an int or a unicode character, " - "not a string of length %zd", - PyUnicode_GET_LENGTH(v)); - return (Py_UCS4) -1; - } - else { - int overflow; - long x = PyLong_AsLongAndOverflow(v, &overflow); - if (x == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Format(PyExc_TypeError, - "%%c requires an int or a unicode character, not %T", - v); - return (Py_UCS4) -1; - } - return (Py_UCS4) -1; - } - - if (x < 0 || x > MAX_UNICODE) { - /* this includes an overflow in converting to C long */ - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x110000)"); - return (Py_UCS4) -1; - } - - return (Py_UCS4) x; - } -} - -/* Parse options of an argument: flags, width, precision. - Handle also "%(name)" syntax. - - Return 0 if the argument has been formatted into arg->str. - Return 1 if the argument has been written into ctx->writer, - Raise an exception and return -1 on error. */ -static int -unicode_format_arg_parse(struct unicode_formatter_t *ctx, - struct unicode_format_arg_t *arg) -{ -#define FORMAT_READ(ctx) \ - PyUnicode_READ((ctx)->fmtkind, (ctx)->fmtdata, (ctx)->fmtpos) - - PyObject *v; - - if (arg->ch == '(') { - /* Get argument value from a dictionary. Example: "%(name)s". */ - Py_ssize_t keystart; - Py_ssize_t keylen; - PyObject *key; - int pcount = 1; - - if (ctx->dict == NULL) { - PyErr_SetString(PyExc_TypeError, - "format requires a mapping"); - return -1; - } - ++ctx->fmtpos; - --ctx->fmtcnt; - keystart = ctx->fmtpos; - /* Skip over balanced parentheses */ - while (pcount > 0 && --ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - if (arg->ch == ')') - --pcount; - else if (arg->ch == '(') - ++pcount; - ctx->fmtpos++; - } - keylen = ctx->fmtpos - keystart - 1; - if (ctx->fmtcnt < 0 || pcount > 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format key"); - return -1; - } - key = PyUnicode_Substring(ctx->fmtstr, - keystart, keystart + keylen); - if (key == NULL) - return -1; - if (ctx->args_owned) { - ctx->args_owned = 0; - Py_DECREF(ctx->args); - } - ctx->args = PyObject_GetItem(ctx->dict, key); - Py_DECREF(key); - if (ctx->args == NULL) - return -1; - ctx->args_owned = 1; - ctx->arglen = -1; - ctx->argidx = -2; - } - - /* Parse flags. Example: "%+i" => flags=F_SIGN. */ - while (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - switch (arg->ch) { - case '-': arg->flags |= F_LJUST; continue; - case '+': arg->flags |= F_SIGN; continue; - case ' ': arg->flags |= F_BLANK; continue; - case '#': arg->flags |= F_ALT; continue; - case '0': arg->flags |= F_ZERO; continue; - } - break; - } - - /* Parse width. Example: "%10s" => width=10 */ - if (arg->ch == '*') { - v = unicode_format_getnextarg(ctx); - if (v == NULL) - return -1; - if (!PyLong_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); - return -1; - } - arg->width = PyLong_AsSsize_t(v); - if (arg->width == -1 && PyErr_Occurred()) - return -1; - if (arg->width < 0) { - arg->flags |= F_LJUST; - arg->width = -arg->width; - } - if (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - } - } - else if (arg->ch >= '0' && arg->ch <= '9') { - arg->width = arg->ch - '0'; - while (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - if (arg->ch < '0' || arg->ch > '9') - break; - /* Since arg->ch is unsigned, the RHS would end up as unsigned, - mixing signed and unsigned comparison. Since arg->ch is between - '0' and '9', casting to int is safe. */ - if (arg->width > (PY_SSIZE_T_MAX - ((int)arg->ch - '0')) / 10) { - PyErr_SetString(PyExc_ValueError, - "width too big"); - return -1; - } - arg->width = arg->width*10 + (arg->ch - '0'); - } - } - - /* Parse precision. Example: "%.3f" => prec=3 */ - if (arg->ch == '.') { - arg->prec = 0; - if (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - } - if (arg->ch == '*') { - v = unicode_format_getnextarg(ctx); - if (v == NULL) - return -1; - if (!PyLong_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); - return -1; - } - arg->prec = PyLong_AsInt(v); - if (arg->prec == -1 && PyErr_Occurred()) - return -1; - if (arg->prec < 0) - arg->prec = 0; - if (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - } - } - else if (arg->ch >= '0' && arg->ch <= '9') { - arg->prec = arg->ch - '0'; - while (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - if (arg->ch < '0' || arg->ch > '9') - break; - if (arg->prec > (INT_MAX - ((int)arg->ch - '0')) / 10) { - PyErr_SetString(PyExc_ValueError, - "precision too big"); - return -1; - } - arg->prec = arg->prec*10 + (arg->ch - '0'); - } - } - } - - /* Ignore "h", "l" and "L" format prefix (ex: "%hi" or "%ls") */ - if (ctx->fmtcnt >= 0) { - if (arg->ch == 'h' || arg->ch == 'l' || arg->ch == 'L') { - if (--ctx->fmtcnt >= 0) { - arg->ch = FORMAT_READ(ctx); - ctx->fmtpos++; - } - } - } - if (ctx->fmtcnt < 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format"); - return -1; - } - return 0; - -#undef FORMAT_READ -} - -/* Format one argument. Supported conversion specifiers: - - - "s", "r", "a": any type - - "i", "d", "u": int or float - - "o", "x", "X": int - - "e", "E", "f", "F", "g", "G": float - - "c": int or str (1 character) - - When possible, the output is written directly into the Unicode writer - (ctx->writer). A string is created when padding is required. - - Return 0 if the argument has been formatted into *p_str, - 1 if the argument has been written into ctx->writer, - -1 on error. */ -static int -unicode_format_arg_format(struct unicode_formatter_t *ctx, - struct unicode_format_arg_t *arg, - PyObject **p_str) -{ - PyObject *v; - _PyUnicodeWriter *writer = &ctx->writer; - - if (ctx->fmtcnt == 0) - ctx->writer.overallocate = 0; - - v = unicode_format_getnextarg(ctx); - if (v == NULL) - return -1; - - - switch (arg->ch) { - case 's': - case 'r': - case 'a': - if (PyLong_CheckExact(v) && arg->width == -1 && arg->prec == -1) { - /* Fast path */ - if (_PyLong_FormatWriter(writer, v, 10, arg->flags & F_ALT) == -1) - return -1; - return 1; - } - - if (PyUnicode_CheckExact(v) && arg->ch == 's') { - *p_str = Py_NewRef(v); - } - else { - if (arg->ch == 's') - *p_str = PyObject_Str(v); - else if (arg->ch == 'r') - *p_str = PyObject_Repr(v); - else - *p_str = PyObject_ASCII(v); - } - break; - - case 'i': - case 'd': - case 'u': - case 'o': - case 'x': - case 'X': - { - int ret = mainformatlong(v, arg, p_str, writer); - if (ret != 0) - return ret; - arg->sign = 1; - break; - } - - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - if (arg->width == -1 && arg->prec == -1 - && !(arg->flags & (F_SIGN | F_BLANK))) - { - /* Fast path */ - if (formatfloat(v, arg, NULL, writer) == -1) - return -1; - return 1; - } - - arg->sign = 1; - if (formatfloat(v, arg, p_str, NULL) == -1) - return -1; - break; - - case 'c': - { - Py_UCS4 ch = formatchar(v); - if (ch == (Py_UCS4) -1) - return -1; - if (arg->width == -1 && arg->prec == -1) { - /* Fast path */ - if (_PyUnicodeWriter_WriteCharInline(writer, ch) < 0) - return -1; - return 1; - } - *p_str = PyUnicode_FromOrdinal(ch); - break; - } - - default: - PyErr_Format(PyExc_ValueError, - "unsupported format character '%c' (0x%x) " - "at index %zd", - (31<=arg->ch && arg->ch<=126) ? (char)arg->ch : '?', - (int)arg->ch, - ctx->fmtpos - 1); - return -1; - } - if (*p_str == NULL) - return -1; - assert (PyUnicode_Check(*p_str)); - return 0; -} - -static int -unicode_format_arg_output(struct unicode_formatter_t *ctx, - struct unicode_format_arg_t *arg, - PyObject *str) -{ - Py_ssize_t len; - int kind; - const void *pbuf; - Py_ssize_t pindex; - Py_UCS4 signchar; - Py_ssize_t buflen; - Py_UCS4 maxchar; - Py_ssize_t sublen; - _PyUnicodeWriter *writer = &ctx->writer; - Py_UCS4 fill; - - fill = ' '; - if (arg->sign && arg->flags & F_ZERO) - fill = '0'; - - len = PyUnicode_GET_LENGTH(str); - if ((arg->width == -1 || arg->width <= len) - && (arg->prec == -1 || arg->prec >= len) - && !(arg->flags & (F_SIGN | F_BLANK))) - { - /* Fast path */ - if (_PyUnicodeWriter_WriteStr(writer, str) == -1) - return -1; - return 0; - } - - /* Truncate the string for "s", "r" and "a" formats - if the precision is set */ - if (arg->ch == 's' || arg->ch == 'r' || arg->ch == 'a') { - if (arg->prec >= 0 && len > arg->prec) - len = arg->prec; - } - - /* Adjust sign and width */ - kind = PyUnicode_KIND(str); - pbuf = PyUnicode_DATA(str); - pindex = 0; - signchar = '\0'; - if (arg->sign) { - Py_UCS4 ch = PyUnicode_READ(kind, pbuf, pindex); - if (ch == '-' || ch == '+') { - signchar = ch; - len--; - pindex++; - } - else if (arg->flags & F_SIGN) - signchar = '+'; - else if (arg->flags & F_BLANK) - signchar = ' '; - else - arg->sign = 0; - } - if (arg->width < len) - arg->width = len; - - /* Prepare the writer */ - maxchar = writer->maxchar; - if (!(arg->flags & F_LJUST)) { - if (arg->sign) { - if ((arg->width-1) > len) - maxchar = Py_MAX(maxchar, fill); - } - else { - if (arg->width > len) - maxchar = Py_MAX(maxchar, fill); - } - } - if (PyUnicode_MAX_CHAR_VALUE(str) > maxchar) { - Py_UCS4 strmaxchar = _PyUnicode_FindMaxChar(str, 0, pindex+len); - maxchar = Py_MAX(maxchar, strmaxchar); - } - - buflen = arg->width; - if (arg->sign && len == arg->width) - buflen++; - if (_PyUnicodeWriter_Prepare(writer, buflen, maxchar) == -1) - return -1; - - /* Write the sign if needed */ - if (arg->sign) { - if (fill != ' ') { - PyUnicode_WRITE(writer->kind, writer->data, writer->pos, signchar); - writer->pos += 1; - } - if (arg->width > len) - arg->width--; - } - - /* Write the numeric prefix for "x", "X" and "o" formats - if the alternate form is used. - For example, write "0x" for the "%#x" format. */ - if ((arg->flags & F_ALT) && (arg->ch == 'x' || arg->ch == 'X' || arg->ch == 'o')) { - assert(PyUnicode_READ(kind, pbuf, pindex) == '0'); - assert(PyUnicode_READ(kind, pbuf, pindex + 1) == arg->ch); - if (fill != ' ') { - PyUnicode_WRITE(writer->kind, writer->data, writer->pos, '0'); - PyUnicode_WRITE(writer->kind, writer->data, writer->pos+1, arg->ch); - writer->pos += 2; - pindex += 2; - } - arg->width -= 2; - if (arg->width < 0) - arg->width = 0; - len -= 2; - } - - /* Pad left with the fill character if needed */ - if (arg->width > len && !(arg->flags & F_LJUST)) { - sublen = arg->width - len; - unicode_fill(writer->kind, writer->data, fill, writer->pos, sublen); - writer->pos += sublen; - arg->width = len; - } - - /* If padding with spaces: write sign if needed and/or numeric prefix if - the alternate form is used */ - if (fill == ' ') { - if (arg->sign) { - PyUnicode_WRITE(writer->kind, writer->data, writer->pos, signchar); - writer->pos += 1; - } - if ((arg->flags & F_ALT) && (arg->ch == 'x' || arg->ch == 'X' || arg->ch == 'o')) { - assert(PyUnicode_READ(kind, pbuf, pindex) == '0'); - assert(PyUnicode_READ(kind, pbuf, pindex+1) == arg->ch); - PyUnicode_WRITE(writer->kind, writer->data, writer->pos, '0'); - PyUnicode_WRITE(writer->kind, writer->data, writer->pos+1, arg->ch); - writer->pos += 2; - pindex += 2; - } - } - - /* Write characters */ - if (len) { - _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, - str, pindex, len); - writer->pos += len; - } - - /* Pad right with the fill character if needed */ - if (arg->width > len) { - sublen = arg->width - len; - unicode_fill(writer->kind, writer->data, ' ', writer->pos, sublen); - writer->pos += sublen; - } - return 0; -} - -/* Helper of PyUnicode_Format(): format one arg. - Return 0 on success, raise an exception and return -1 on error. */ -static int -unicode_format_arg(struct unicode_formatter_t *ctx) -{ - struct unicode_format_arg_t arg; - PyObject *str; - int ret; - - arg.ch = PyUnicode_READ(ctx->fmtkind, ctx->fmtdata, ctx->fmtpos); - if (arg.ch == '%') { - ctx->fmtpos++; - ctx->fmtcnt--; - if (_PyUnicodeWriter_WriteCharInline(&ctx->writer, '%') < 0) - return -1; - return 0; - } - arg.flags = 0; - arg.width = -1; - arg.prec = -1; - arg.sign = 0; - str = NULL; - - ret = unicode_format_arg_parse(ctx, &arg); - if (ret == -1) - return -1; - - ret = unicode_format_arg_format(ctx, &arg, &str); - if (ret == -1) - return -1; - - if (ret != 1) { - ret = unicode_format_arg_output(ctx, &arg, str); - Py_DECREF(str); - if (ret == -1) - return -1; - } - - if (ctx->dict && (ctx->argidx < ctx->arglen)) { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); - return -1; - } - return 0; -} - -PyObject * -PyUnicode_Format(PyObject *format, PyObject *args) -{ - struct unicode_formatter_t ctx; - - if (format == NULL || args == NULL) { - PyErr_BadInternalCall(); - return NULL; - } - - if (ensure_unicode(format) < 0) - return NULL; - - ctx.fmtstr = format; - ctx.fmtdata = PyUnicode_DATA(ctx.fmtstr); - ctx.fmtkind = PyUnicode_KIND(ctx.fmtstr); - ctx.fmtcnt = PyUnicode_GET_LENGTH(ctx.fmtstr); - ctx.fmtpos = 0; - - _PyUnicodeWriter_Init(&ctx.writer); - ctx.writer.min_length = ctx.fmtcnt + 100; - ctx.writer.overallocate = 1; - - if (PyTuple_Check(args)) { - ctx.arglen = PyTuple_Size(args); - ctx.argidx = 0; - } - else { - ctx.arglen = -1; - ctx.argidx = -2; - } - ctx.args_owned = 0; - if (PyMapping_Check(args) && !PyTuple_Check(args) && !PyUnicode_Check(args)) - ctx.dict = args; - else - ctx.dict = NULL; - ctx.args = args; - - while (--ctx.fmtcnt >= 0) { - if (PyUnicode_READ(ctx.fmtkind, ctx.fmtdata, ctx.fmtpos) != '%') { - Py_ssize_t nonfmtpos; - - nonfmtpos = ctx.fmtpos++; - while (ctx.fmtcnt >= 0 && - PyUnicode_READ(ctx.fmtkind, ctx.fmtdata, ctx.fmtpos) != '%') { - ctx.fmtpos++; - ctx.fmtcnt--; - } - if (ctx.fmtcnt < 0) { - ctx.fmtpos--; - ctx.writer.overallocate = 0; - } - - if (_PyUnicodeWriter_WriteSubstring(&ctx.writer, ctx.fmtstr, - nonfmtpos, ctx.fmtpos) < 0) - goto onError; - } - else { - ctx.fmtpos++; - if (unicode_format_arg(&ctx) == -1) - goto onError; - } - } - - if (ctx.argidx < ctx.arglen && !ctx.dict) { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); - goto onError; - } - - if (ctx.args_owned) { - Py_DECREF(ctx.args); - } - return _PyUnicodeWriter_Finish(&ctx.writer); - - onError: - _PyUnicodeWriter_Dealloc(&ctx.writer); - if (ctx.args_owned) { - Py_DECREF(ctx.args); - } - return NULL; -} - static PyObject * unicode_subtype_new(PyTypeObject *type, PyObject *unicode); @@ -15575,7 +13808,7 @@ unicode_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, { PyObject *unicode; if (x == NULL) { - unicode = unicode_get_empty(); + unicode = _PyUnicode_GetEmpty(); } else if (encoding == NULL && errors == NULL) { unicode = PyObject_Str(x); @@ -15611,7 +13844,7 @@ unicode_vectorcall(PyObject *type, PyObject *const *args, Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) != 0) { // Fallback to unicode_new() - PyObject *tuple = _PyTuple_FromArray(args, nargs); + PyObject *tuple = PyTuple_FromArray(args, nargs); if (tuple == NULL) { return NULL; } @@ -15629,7 +13862,7 @@ unicode_vectorcall(PyObject *type, PyObject *const *args, return NULL; } if (nargs == 0) { - return unicode_get_empty(); + return _PyUnicode_GetEmpty(); } PyObject *object = args[0]; if (nargs == 1) { @@ -16305,7 +14538,7 @@ unicodeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) if (it->it_seq != NULL) { return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); } else { - PyObject *u = unicode_get_empty(); + PyObject *u = _PyUnicode_GetEmpty(); if (u == NULL) { Py_XDECREF(iter); return NULL; diff --git a/Objects/unicodetype_db.h b/Objects/unicodetype_db.h index 5be810dd674..536f51324ae 100644 --- a/Objects/unicodetype_db.h +++ b/Objects/unicodetype_db.h @@ -508,6 +508,8 @@ const _PyUnicode_TypeRecord _PyUnicode_TypeRecords[] = { {-40, 0, -40, 0, 0, 9993}, {0, 39, 0, 0, 0, 10113}, {-39, 0, -39, 0, 0, 9993}, + {0, 27, 0, 0, 0, 10113}, + {-27, 0, -27, 0, 0, 9993}, {0, 34, 0, 0, 0, 10113}, {-34, 0, -34, 0, 0, 9993}, {0, 0, 0, 0, 0, 9344}, @@ -1755,1218 +1757,612 @@ const Py_UCS4 _PyUnicode_ExtendedCase[] = { }; /* type indexes */ -#define SHIFT 6 +#define SHIFT 7 static const unsigned short index1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 26, 26, 26, 26, 26, 68, 69, - 70, 71, 72, 73, 74, 75, 26, 26, 26, 26, 26, 26, 26, 26, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 12, 106, 106, 107, 106, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 120, 121, 122, 123, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 124, 125, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 126, 127, 119, 128, 129, 106, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 119, 119, 119, 139, 140, 141, 142, 143, - 144, 26, 145, 146, 147, 148, 149, 119, 119, 119, 119, 119, 150, 26, 151, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 152, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 153, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 119, 154, 155, 156, 157, 153, - 158, 26, 159, 160, 26, 26, 26, 161, 162, 26, 26, 26, 26, 26, 26, 26, 163, - 26, 164, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 165, 26, 26, 26, 26, - 26, 26, 26, 166, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 167, 26, 168, 169, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 170, 26, 171, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 172, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 173, 26, 26, 26, 26, - 26, 26, 26, 160, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 174, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 175, 176, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 177, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 160, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 178, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 179, 26, 158, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 180, 26, 26, 26, 26, 26, 26, 26, 26, 26, 159, 26, 26, 26, 26, 26, 181, - 182, 26, 183, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 184, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 185, 186, 26, 26, 26, 26, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 211, 212, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 26, 214, 215, 216, 26, 217, 26, 218, 219, - 220, 221, 222, 26, 223, 26, 26, 224, 225, 226, 227, 228, 229, 26, 230, - 231, 232, 233, 234, 235, 236, 26, 237, 238, 239, 240, 241, 213, 213, 242, - 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 26, 26, - 26, 26, 256, 257, 258, 213, 259, 260, 261, 262, 263, 213, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 213, 26, 273, 274, 275, 276, 277, 278, 213, - 213, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 213, 213, 306, 307, 308, 309, 310, 311, 312, 313, 213, 213, 314, 213, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 213, 213, 326, - 327, 328, 329, 213, 330, 331, 332, 213, 213, 213, 213, 333, 334, 335, - 336, 337, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 218, - 213, 338, 339, 26, 26, 26, 340, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 341, 342, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 343, 344, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 237, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 313, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 345, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 26, 26, - 26, 26, 26, 26, 26, 26, 324, 346, 347, 348, 349, 350, 351, 213, 213, 213, - 213, 213, 213, 352, 213, 213, 213, 353, 354, 213, 26, 355, 356, 357, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 358, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 359, 273, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 360, 26, 26, 26, 26, 361, 362, 26, 26, 26, 26, 26, - 363, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 26, 364, 365, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 119, 119, 119, 366, 119, 119, 119, 119, 119, 119, 138, 213, - 367, 368, 119, 369, 119, 119, 119, 370, 371, 372, 373, 374, 119, 375, - 213, 376, 119, 377, 213, 213, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, 119, 119, 119, 119, 119, 119, - 119, 119, 394, 395, 396, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 397, 213, 213, 213, 398, 399, - 400, 213, 401, 402, 213, 213, 213, 213, 403, 404, 213, 213, 213, 213, - 213, 213, 213, 405, 213, 213, 213, 406, 213, 213, 213, 213, 213, 213, - 213, 407, 26, 26, 26, 408, 409, 410, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 411, 412, 213, 413, 213, 213, 213, 414, 415, 416, - 417, 213, 213, 213, 213, 418, 119, 419, 420, 421, 422, 423, 424, 425, - 426, 213, 213, 119, 119, 119, 427, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 428, 119, 429, 119, 430, 431, 432, 433, 434, 119, - 119, 119, 119, 119, 435, 436, 437, 119, 119, 438, 366, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 439, - 440, 26, 441, 181, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 152, 26, 442, 26, 26, 26, 26, 443, 444, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 445, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 446, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 165, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 177, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 447, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 448, 26, 26, 26, 449, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 450, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 451, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 452, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 26, 26, 445, 26, - 26, 26, 26, 26, 452, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 453, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 454, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 455, 456, 213, 213, 12, 12, 12, 457, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, + 38, 39, 34, 34, 34, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 65, 66, 64, + 64, 64, 64, 67, 68, 64, 64, 64, 64, 64, 64, 69, 64, 70, 71, 72, 73, 74, + 75, 64, 76, 77, 78, 79, 80, 81, 82, 64, 64, 83, 84, 34, 34, 34, 34, 34, + 34, 85, 34, 34, 34, 34, 34, 86, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 87, 88, 89, 90, 91, 92, 34, 93, 34, 34, + 34, 94, 95, 34, 34, 34, 34, 34, 96, 34, 34, 34, 97, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 98, 99, 100, 34, 34, 34, 34, 34, 34, 101, 102, 34, + 34, 34, 34, 34, 34, 34, 34, 103, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 104, 34, 34, 34, 92, 34, 34, 34, 34, 34, 34, 34, 34, 105, 34, 34, 34, 34, + 106, 107, 34, 34, 34, 34, 34, 108, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 92, 34, 34, 34, 34, 34, 34, 109, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 110, 111, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 112, 34, 34, 34, 34, 113, 34, 34, 114, 115, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 116, 34, 34, 34, + 34, 34, 34, 34, 34, 117, 34, 34, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 130, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 132, 133, + 134, 135, 136, 137, 138, 34, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 131, 149, 150, 151, 152, 153, 154, 155, 34, 34, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 131, 184, 185, 186, + 187, 131, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 131, 200, 201, 202, 203, 34, 34, 34, 204, 34, 205, 206, 207, 34, 208, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 209, 34, 34, 34, 34, 34, 34, 34, 34, 210, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 146, 34, 34, 34, 34, 211, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 212, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 34, 34, 34, 34, + 213, 214, 215, 216, 131, 131, 217, 131, 218, 219, 220, 221, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 222, 223, 224, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 225, 34, 34, 226, 34, 34, 227, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 228, 229, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 64, + 230, 64, 64, 64, 231, 232, 233, 64, 234, 235, 236, 237, 238, 239, 131, + 240, 241, 242, 243, 244, 245, 246, 247, 64, 64, 64, 64, 248, 249, 131, + 131, 131, 131, 131, 131, 131, 131, 250, 131, 251, 252, 253, 131, 131, + 254, 131, 131, 131, 255, 131, 256, 131, 257, 131, 258, 34, 259, 260, 131, + 131, 131, 131, 131, 261, 262, 263, 131, 264, 265, 131, 131, 266, 267, + 268, 269, 270, 131, 64, 271, 64, 64, 64, 64, 64, 272, 64, 273, 274, 275, + 64, 64, 276, 277, 64, 278, 131, 131, 131, 131, 131, 131, 131, 131, 279, + 280, 281, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 85, + 282, 34, 283, 284, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 285, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 286, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 287, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 108, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 288, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 289, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 290, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 291, 34, 34, 34, 34, 292, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 34, 285, 34, + 34, 293, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 294, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 295, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 296, 131, 297, 298, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, }; static const unsigned short index2[] = { @@ -3005,7 +2401,7 @@ static const unsigned short index2[] = { 19, 77, 81, 19, 82, 83, 84, 85, 19, 86, 87, 85, 88, 89, 19, 19, 87, 19, 90, 91, 19, 19, 92, 19, 19, 19, 19, 19, 19, 19, 93, 19, 19, 94, 19, 95, 94, 19, 19, 19, 96, 94, 97, 98, 98, 99, 19, 19, 19, 19, 19, 100, 19, 55, - 19, 19, 19, 19, 19, 19, 19, 19, 101, 102, 19, 19, 19, 19, 19, 19, 19, 19, + 55, 19, 19, 19, 19, 19, 19, 19, 101, 102, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 103, 103, 103, 103, 103, 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 103, 103, 5, 5, 5, 5, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 5, 5, 5, 5, 5, 5, @@ -3089,7 +2485,7 @@ static const unsigned short index2[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 0, 0, 4, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 5, 55, 55, 55, 55, 55, 55, 0, 20, 20, 0, 0, 0, 0, 0, 24, + 55, 55, 55, 55, 5, 55, 55, 55, 55, 55, 55, 55, 20, 20, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 24, 24, 24, 24, @@ -3139,14 +2535,14 @@ static const unsigned short index2[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 55, 24, 24, 24, 17, 17, 17, 17, 0, 24, 24, 24, 0, 24, 24, 24, 24, 0, 0, 0, 0, - 0, 0, 0, 24, 24, 0, 55, 55, 55, 0, 0, 55, 0, 0, 55, 55, 24, 24, 0, 0, 6, + 0, 0, 0, 24, 24, 0, 55, 55, 55, 0, 55, 55, 0, 0, 55, 55, 24, 24, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 4, 26, 26, 26, 26, 26, 26, 26, 4, 55, 24, 17, 17, 4, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 0, 0, 24, 55, 17, 24, 17, 17, 17, 17, 17, 0, 24, 17, 17, 0, 17, 17, 24, 24, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, 0, 0, 0, - 0, 0, 55, 55, 0, 55, 55, 24, 24, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 55, 55, 55, 0, 55, 55, 24, 24, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 55, 55, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 17, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, @@ -3202,112 +2598,130 @@ static const unsigned short index2[] = { 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 4, 103, 142, 142, 142, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 0, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 0, - 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 0, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 0, 55, 55, 55, 55, 0, 0, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, - 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 0, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, + 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 0, 55, 55, 55, 55, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 0, 55, 0, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 24, 24, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 143, 144, 145, 146, 147, 148, 149, 150, 151, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, + 0, 0, 0, 0, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 234, 235, 236, 237, 0, 0, 238, 239, 240, 241, 242, 243, 0, 0, 4, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 1, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 0, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 0, 0, 238, 239, 240, 241, - 242, 243, 0, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 1, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 0, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 4, 4, 4, 244, 244, 244, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, + 244, 244, 244, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, + 24, 24, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 17, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 24, 24, 24, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, - 17, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, - 0, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 0, 24, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 17, 24, 24, 24, 24, 24, - 24, 24, 17, 17, 17, 17, 17, 17, 17, 17, 24, 17, 17, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 4, 4, 4, 104, 4, 4, 4, 4, 55, 24, 0, 0, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, - 24, 20, 24, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, + 55, 55, 55, 55, 55, 24, 24, 17, 24, 24, 24, 24, 24, 24, 24, 17, 17, 17, + 17, 17, 17, 17, 17, 24, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 4, 4, 4, 104, 4, 4, 4, 4, 55, 24, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, 24, 20, 24, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, + 55, 55, 245, 245, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 24, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 0, 24, 24, 24, 17, 17, 17, 17, 24, 24, + 17, 17, 17, 0, 0, 0, 0, 17, 17, 24, 17, 17, 17, 17, 17, 17, 24, 24, 24, + 0, 0, 0, 0, 4, 0, 0, 0, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, - 0, 0, 0, 55, 55, 55, 55, 55, 245, 245, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 24, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 143, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 24, 24, 17, 17, 24, 0, 0, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 17, 24, 17, 24, 24, 24, 24, 24, 24, 24, 0, + 24, 17, 24, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 17, 17, 17, 17, 17, + 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 24, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, + 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 104, 4, 4, 4, 4, 4, 4, 0, 0, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 5, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 24, 24, 24, - 17, 17, 17, 17, 24, 24, 17, 17, 17, 0, 0, 0, 0, 17, 17, 24, 17, 17, 17, - 17, 17, 17, 24, 24, 24, 0, 0, 0, 0, 4, 0, 0, 0, 4, 4, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, - 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 17, + 24, 24, 24, 24, 24, 17, 24, 17, 17, 17, 17, 17, 24, 17, 17, 55, 55, 55, + 55, 55, 55, 55, 55, 0, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, 17, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 17, 24, 24, 24, 24, 17, 17, 24, 24, 17, 24, + 24, 24, 55, 55, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 143, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 24, 24, 17, 17, 24, 0, 0, 4, 4, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 24, 17, 24, 24, - 24, 24, 24, 24, 24, 0, 24, 17, 24, 17, 17, 24, 24, 24, 24, 24, 24, 24, - 24, 17, 17, 17, 17, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, - 24, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 104, 4, 4, 4, - 4, 4, 4, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 5, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, - 24, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 17, 24, 24, - 24, 24, 24, 17, 24, 17, 17, 17, 17, 17, 24, 17, 17, 55, 55, 55, 55, 55, - 55, 55, 55, 0, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, 17, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 17, 24, 24, 24, 24, 17, 17, 24, 24, 17, 24, 24, - 24, 55, 55, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 24, 17, 24, 24, 17, 17, 17, 24, 17, 24, 24, 24, 17, 17, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 24, 17, 24, 24, 17, 17, 17, 24, 17, 24, 24, 24, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 17, 17, 17, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 17, 17, 24, 24, 0, 0, 0, 4, 4, 4, 4, 4, 6, 7, 8, 9, @@ -3333,44 +2747,55 @@ static const unsigned short index2[] = { 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 258, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 29, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 259, 260, 261, 262, - 263, 264, 19, 19, 265, 19, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 266, 266, 266, 266, 266, 266, 266, 266, 267, 267, 267, 267, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 259, 260, + 261, 262, 263, 264, 19, 19, 265, 19, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 266, 266, + 266, 266, 266, 266, 266, 266, 267, 267, 267, 267, 267, 267, 267, 267, + 266, 266, 266, 266, 266, 266, 0, 0, 267, 267, 267, 267, 267, 267, 0, 0, + 266, 266, 266, 266, 266, 266, 266, 266, 267, 267, 267, 267, 267, 267, + 267, 267, 266, 266, 266, 266, 266, 266, 266, 266, 267, 267, 267, 267, 267, 267, 267, 267, 266, 266, 266, 266, 266, 266, 0, 0, 267, 267, 267, - 267, 267, 267, 0, 0, 266, 266, 266, 266, 266, 266, 266, 266, 267, 267, - 267, 267, 267, 267, 267, 267, 266, 266, 266, 266, 266, 266, 266, 266, - 267, 267, 267, 267, 267, 267, 267, 267, 266, 266, 266, 266, 266, 266, 0, - 0, 267, 267, 267, 267, 267, 267, 0, 0, 268, 266, 269, 266, 270, 266, 271, - 266, 0, 267, 0, 267, 0, 267, 0, 267, 266, 266, 266, 266, 266, 266, 266, - 266, 267, 267, 267, 267, 267, 267, 267, 267, 272, 272, 273, 273, 273, - 273, 274, 274, 275, 275, 276, 276, 277, 277, 0, 0, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 266, 266, 326, 327, 328, 0, 329, 330, 267, 267, 331, 331, 332, - 5, 333, 5, 5, 5, 334, 335, 336, 0, 337, 338, 339, 339, 339, 339, 340, 5, - 5, 5, 266, 266, 341, 342, 0, 0, 343, 344, 267, 267, 345, 345, 0, 5, 5, 5, - 266, 266, 346, 347, 348, 128, 349, 350, 267, 267, 351, 351, 132, 5, 5, 5, - 0, 0, 352, 353, 354, 0, 355, 356, 357, 357, 358, 358, 359, 5, 5, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 360, 360, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 5, 2, 2, 20, 20, 20, 20, 20, - 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 20, 20, 20, 20, 20, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 361, - 103, 0, 0, 362, 363, 364, 365, 366, 367, 4, 4, 4, 4, 4, 103, 361, 25, 21, - 22, 362, 363, 364, 365, 366, 367, 4, 4, 4, 4, 4, 0, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 0, 0, 0, 4, 4, 4, 4, 4, 4, + 267, 267, 267, 0, 0, 268, 266, 269, 266, 270, 266, 271, 266, 0, 267, 0, + 267, 0, 267, 0, 267, 266, 266, 266, 266, 266, 266, 266, 266, 267, 267, + 267, 267, 267, 267, 267, 267, 272, 272, 273, 273, 273, 273, 274, 274, + 275, 275, 276, 276, 277, 277, 0, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 266, + 266, 326, 327, 328, 0, 329, 330, 267, 267, 331, 331, 332, 5, 333, 5, 5, + 5, 334, 335, 336, 0, 337, 338, 339, 339, 339, 339, 340, 5, 5, 5, 266, + 266, 341, 342, 0, 0, 343, 344, 267, 267, 345, 345, 0, 5, 5, 5, 266, 266, + 346, 347, 348, 128, 349, 350, 267, 267, 351, 351, 132, 5, 5, 5, 0, 0, + 352, 353, 354, 0, 355, 356, 357, 357, 358, 358, 359, 5, 5, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 20, 360, 360, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 5, 2, 2, 20, 20, 20, 20, 20, 1, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 20, + 20, 20, 20, 20, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 361, 103, 0, + 0, 362, 363, 364, 365, 366, 367, 4, 4, 4, 4, 4, 103, 361, 25, 21, 22, + 362, 363, 364, 365, 366, 367, 4, 4, 4, 4, 4, 0, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 5, 5, 5, 5, 24, 5, 5, 5, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 122, 4, 4, 4, 4, 122, 4, 4, 19, 122, 122, 122, 19, 19, 122, 122, + 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 5, 5, 5, 5, 24, 5, 5, 5, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 122, 4, 4, 4, 4, 122, 4, 4, 19, 122, 122, 122, 19, 19, 122, 122, 122, 19, 4, 122, 4, 4, 368, 122, 122, 122, 122, 122, 4, 4, 4, 4, 4, 4, 122, 4, 369, 4, 122, 4, 370, 371, 122, 122, 368, 19, 122, 122, 372, 122, 19, 55, 55, 55, 55, 19, 4, 4, 19, 19, 122, 122, 4, 4, 4, 4, 4, 122, 19, @@ -3384,178 +2809,328 @@ static const unsigned short index2[] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 25, 21, 22, 362, 363, 364, 365, 366, 367, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 376, 376, 376, 376, 376, - 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, - 376, 376, 376, 376, 376, 376, 376, 377, 377, 377, 377, 377, 377, 377, - 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, - 377, 377, 377, 377, 377, 361, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, - 21, 22, 362, 363, 364, 365, 366, 367, 26, 361, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 25, 21, - 22, 362, 363, 364, 365, 366, 367, 26, 25, 21, 22, 362, 363, 364, 365, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 21, 22, 362, 363, 364, 365, 366, 367, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 21, 22, 362, 363, 364, + 365, 366, 367, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 21, 22, + 362, 363, 364, 365, 366, 367, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, + 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 377, + 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, + 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 361, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, + 361, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 25, + 21, 22, 362, 363, 364, 365, 366, 367, 26, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, - 137, 137, 137, 137, 137, 137, 138, 138, 138, 138, 138, 138, 138, 138, + 137, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, - 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 29, 30, 378, - 379, 380, 381, 382, 29, 30, 29, 30, 29, 30, 383, 384, 385, 386, 19, 29, - 30, 19, 29, 30, 19, 19, 19, 19, 19, 103, 103, 387, 387, 29, 30, 29, 30, + 138, 138, 138, 138, 138, 138, 138, 29, 30, 378, 379, 380, 381, 382, 29, + 30, 29, 30, 29, 30, 383, 384, 385, 386, 19, 29, 30, 19, 29, 30, 19, 19, + 19, 19, 19, 103, 103, 387, 387, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, - 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 19, 4, 4, 4, 4, - 4, 4, 29, 30, 29, 30, 24, 24, 24, 29, 30, 0, 0, 0, 0, 0, 4, 4, 4, 4, 26, - 4, 4, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, + 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, + 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, + 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, + 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, + 19, 4, 4, 4, 4, 4, 4, 29, 30, 29, 30, 24, 24, 24, 29, 30, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 26, 4, 4, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, - 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 0, 388, 0, 0, 0, - 0, 0, 388, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 0, + 388, 0, 0, 0, 0, 0, 388, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 104, 4, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, - 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 104, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, - 55, 55, 55, 55, 55, 55, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, + 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 24, 24, 24, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 389, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 389, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 104, 55, 244, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 24, 24, 24, 24, 17, 17, 4, 104, - 104, 104, 104, 104, 4, 4, 244, 244, 244, 104, 55, 4, 4, 4, 0, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 24, 5, 5, 104, 104, - 55, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 17, 104, 104, 104, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 4, 4, 26, 26, 26, - 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 26, 26, 26, 26, 26, 26, 26, 26, 4, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 55, 55, 55, - 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 104, 55, 244, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 24, 24, 24, 24, 17, 17, 4, 104, 104, 104, + 104, 104, 4, 4, 244, 244, 244, 104, 55, 4, 4, 4, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 24, 5, 5, 104, 104, 55, 4, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 17, 104, 104, 104, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 4, 4, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 26, 26, 26, 26, 26, 26, + 26, 26, 4, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 55, 55, + 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 390, 55, 55, 390, 55, 55, 55, 390, + 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 390, 55, 390, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 390, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 390, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 390, 55, 55, 390, 55, 55, 55, 390, 55, 390, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, - 55, 55, 55, 55, 55, 55, 390, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 390, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, - 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 390, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 390, 55, 390, 390, 390, 55, 55, 55, 55, 55, 55, 390, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 390, 55, 390, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, + 55, 390, 390, 390, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 390, 390, 390, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 390, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 390, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 390, 390, + 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 390, 390, - 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, - 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 390, 390, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 390, 390, 390, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, + 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, @@ -3563,41 +3138,27 @@ static const unsigned short index2[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, - 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 390, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, @@ -3605,373 +3166,418 @@ static const unsigned short index2[] = { 55, 55, 104, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 104, 104, + 104, 104, 104, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, + 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 55, + 24, 5, 5, 5, 4, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 4, 104, 29, 30, + 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, + 29, 30, 29, 30, 29, 30, 29, 30, 103, 103, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 104, 104, 104, 104, 104, 104, 4, 4, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 104, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, - 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, - 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, - 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, - 29, 30, 29, 30, 29, 30, 29, 30, 55, 24, 5, 5, 5, 4, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 4, 104, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 24, 24, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 104, + 104, 104, 104, 104, 104, 104, 104, 104, 5, 5, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 19, 19, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 103, - 103, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 19, 19, 19, 19, 19, 19, 19, 19, 29, 30, 29, 30, 391, 29, 30, 29, 30, 29, + 30, 29, 30, 29, 30, 104, 5, 5, 29, 30, 392, 19, 55, 29, 30, 29, 30, 393, + 19, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, + 30, 29, 30, 394, 395, 396, 397, 394, 19, 398, 399, 400, 401, 29, 30, 29, + 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 402, 403, 404, 29, + 30, 29, 30, 405, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, + 29, 30, 406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 103, 103, 103, 29, 30, 55, 103, 103, 19, 55, 55, 55, 55, 55, 55, 55, + 24, 55, 55, 55, 24, 55, 55, 55, 55, 24, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 24, + 24, 17, 4, 4, 4, 4, 24, 0, 0, 0, 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 0, + 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 24, 24, 4, 4, 4, 4, - 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 104, 104, 104, 104, 104, 104, 104, 104, 104, - 5, 5, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 19, 19, 29, - 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 29, 30, 29, 30, 103, 19, 19, 19, 19, 19, 19, 19, 19, 29, 30, - 29, 30, 391, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 104, 5, 5, 29, 30, - 392, 19, 55, 29, 30, 29, 30, 393, 19, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 394, 395, 396, 397, 394, 19, - 398, 399, 400, 401, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, - 30, 29, 30, 402, 403, 404, 29, 30, 29, 30, 405, 29, 30, 0, 0, 29, 30, 0, - 19, 0, 19, 29, 30, 29, 30, 29, 30, 406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 103, 29, 30, 55, 103, 103, 19, - 55, 55, 55, 55, 55, 55, 55, 24, 55, 55, 55, 24, 55, 55, 55, 55, 24, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 17, 17, 24, 24, 17, 4, 4, 4, 4, 24, 0, 0, 0, 26, 26, 26, - 26, 26, 26, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 17, - 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 55, 55, 55, 55, 55, 55, + 4, 4, 4, 55, 4, 55, 55, 24, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 24, 24, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 55, 55, 55, 55, 55, 55, 4, 4, 4, 55, 4, 55, 55, 24, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, - 24, 24, 24, 24, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 24, 24, 24, 17, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 24, 24, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, + 17, 17, 24, 24, 24, 24, 17, 17, 24, 24, 17, 17, 17, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 0, 104, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, + 4, 4, 55, 55, 55, 55, 55, 24, 104, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 24, 17, 17, 24, 24, 24, 24, 17, 17, 24, 24, 17, - 17, 17, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 104, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 0, 0, 0, 0, 4, 4, 55, 55, 55, 55, 55, 24, 104, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, - 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 17, 17, - 24, 24, 17, 17, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 24, 55, - 55, 55, 55, 55, 55, 55, 55, 24, 17, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 0, 0, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 104, 55, 55, 55, 55, 55, 55, 4, 4, 4, 55, 17, 24, 17, 55, 55, + 55, 24, 24, 24, 24, 24, 24, 17, 17, 24, 24, 17, 17, 24, 24, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 55, 55, 24, 55, 55, 55, 55, 55, 55, 55, 55, 24, 17, 0, + 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 4, 4, 4, 4, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 55, 55, 55, 55, 55, + 55, 4, 4, 4, 55, 17, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 55, 24, 24, 24, 55, - 55, 24, 24, 55, 55, 55, 55, 55, 24, 24, 55, 24, 55, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 104, 4, 4, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 24, 24, 17, 17, 4, 4, 55, - 104, 104, 17, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, - 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, - 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 55, 55, 55, 24, 55, 24, 24, 24, 55, 55, 24, 24, 55, 55, 55, 55, 55, 24, + 24, 55, 24, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 55, 104, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 17, 24, 24, 17, 17, 4, 4, 55, 104, 104, 17, 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, + 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 407, 19, 19, 19, 19, 19, 19, 19, 5, 103, 103, 103, 103, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 103, 5, 5, 0, 0, 0, 0, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, - 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, - 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, - 484, 485, 486, 487, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 19, 19, 19, 19, 19, 19, 19, 19, 407, 19, 19, 19, 19, 19, 19, 19, 5, 103, + 103, 103, 103, 19, 19, 19, 19, 19, 19, 19, 19, 19, 103, 5, 5, 0, 0, 0, 0, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, + 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, + 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, + 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 17, 17, 24, 17, 17, 24, 17, 17, 4, 17, 24, 0, 0, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 24, 17, 17, 24, 17, + 17, 4, 17, 24, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 390, 55, + 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 390, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, + 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 390, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 488, 489, 490, 491, 492, 493, 494, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 495, 496, 497, 498, 499, 0, 0, 0, 0, 0, 55, 24, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 0, 55, 0, 55, 55, 0, 55, 55, 0, + 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 500, 500, 500, 500, 500, 500, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 500, 500, 4, 4, 4, 4, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, - 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 4, 4, 4, 17, 17, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 17, 4, 4, 5, 0, 4, 5, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 0, 0, 0, 0, 500, 55, 500, - 55, 500, 0, 500, 55, 500, 55, 500, 55, 500, 55, 500, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 0, 0, 20, 0, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 5, 4, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 5, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 4, 4, 4, 5, 17, 5, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 501, 501, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, - 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 0, 0, 0, 4, - 4, 4, 5, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 20, 20, 20, 4, 4, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 488, 489, 490, 491, 492, 493, 494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 495, 496, 497, 498, 499, 0, 0, 0, 0, 0, 55, 24, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 0, 55, 55, 55, 55, 55, 0, 55, 0, 55, 55, 0, 55, 55, 0, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 500, + 500, 500, 500, 500, 500, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 500, 500, + 4, 4, 4, 4, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 4, 4, 4, 17, 17, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 17, + 4, 4, 5, 0, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, + 4, 4, 4, 4, 0, 0, 0, 0, 500, 55, 500, 55, 500, 0, 500, 55, 500, 55, 500, + 55, 500, 55, 500, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 0, 0, 20, 0, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 5, 4, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 5, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 4, 4, 4, 5, 17, 5, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 501, 501, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 0, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, + 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 0, 0, 0, + 4, 4, 4, 5, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 20, 20, 20, 4, 4, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 4, 4, + 4, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 26, + 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 26, 26, 4, + 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 0, 0, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 244, 55, 55, 55, 55, 55, 55, 55, 55, 244, 0, 0, 0, 0, 0, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, + 24, 24, 24, 24, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 4, 244, 244, 244, + 244, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 502, 502, + 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, + 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, + 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 503, 503, 503, 503, + 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, + 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, + 503, 503, 503, 503, 503, 503, 503, 503, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 502, 502, 502, 502, + 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, + 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, + 502, 502, 502, 502, 0, 0, 0, 0, 503, 503, 503, 503, 503, 503, 503, 503, + 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, + 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 0, + 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 0, 504, 504, + 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 0, 504, + 504, 504, 504, 504, 504, 504, 0, 504, 504, 0, 505, 505, 505, 505, 505, + 505, 505, 505, 505, 505, 505, 0, 505, 505, 505, 505, 505, 505, 505, 505, + 505, 505, 505, 505, 505, 505, 505, 0, 505, 505, 505, 505, 505, 505, 505, + 0, 505, 505, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 103, 104, 104, 103, 103, 103, 0, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 0, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 0, 0, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, + 55, 55, 0, 0, 0, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 4, 26, 26, 26, 26, 26, + 26, 26, 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 26, 26, 26, 26, 26, 26, 26, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 0, 0, 0, 0, 26, 26, 26, 26, + 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 26, 26, 26, 26, 26, 26, 0, 0, 0, 4, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 0, 0, 0, 0, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 26, 26, 55, 55, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 55, 24, 24, 24, 0, 24, 24, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 55, 55, 55, 55, 0, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 0, 0, 24, 24, 24, 0, 0, 0, 0, 24, 25, 21, 22, 362, + 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, + 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 26, 26, 4, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 26, 26, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 4, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 24, 24, 0, 0, 0, 0, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, + 26, 26, 26, 26, 26, 26, 26, 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 26, 26, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 24, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 55, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 0, 0, 0, + 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, + 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 55, 55, 55, 55, 104, 55, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 24, + 24, 24, 24, 24, 4, 104, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 21, 22, 362, 363, 364, + 365, 366, 367, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 24, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 24, 24, 4, + 0, 0, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, + 104, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 26, 26, 26, 26, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 244, 55, 55, 55, 55, 55, 55, 55, 55, 244, 0, + 55, 55, 55, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 26, 26, + 26, 26, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 24, 24, 24, 24, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, - 55, 55, 4, 244, 244, 244, 244, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, - 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, - 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, - 502, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, - 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, - 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, - 0, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, - 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, - 502, 502, 502, 502, 502, 502, 502, 502, 0, 0, 0, 0, 503, 503, 503, 503, - 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, - 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, - 503, 503, 503, 503, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 4, 504, 504, 504, 504, 504, 504, 504, 504, 504, - 504, 504, 0, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, - 504, 504, 504, 0, 504, 504, 504, 504, 504, 504, 504, 0, 504, 504, 0, 505, - 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 0, 505, 505, 505, 505, - 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 0, 505, 505, 505, - 505, 505, 505, 505, 0, 505, 505, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 104, 104, 103, 103, 103, 0, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 0, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, - 0, 0, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 0, 0, 55, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 4, 26, 26, 26, 26, 26, 26, 26, 26, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 4, 4, 26, 26, 26, 26, 26, 26, 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 0, 55, 55, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 26, - 26, 26, 26, 26, 26, 0, 0, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, - 0, 0, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 0, 0, 26, 26, 55, 55, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 55, 24, 24, 24, 0, 24, 24, 0, 0, 0, 0, 0, 24, 24, 24, 24, 55, 55, - 55, 55, 0, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, - 24, 24, 24, 0, 0, 0, 0, 24, 25, 21, 22, 362, 26, 26, 26, 26, 26, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 26, 26, 4, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, - 55, 55, 55, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 0, 0, 0, - 0, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 26, 26, 26, 26, 26, 26, - 26, 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, - 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, - 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 110, 110, 110, 110, - 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, - 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, - 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, - 110, 110, 110, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, - 26, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 55, 55, 55, - 55, 104, 55, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 24, 24, 24, 24, 24, 4, 104, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 21, 22, - 362, 363, 364, 365, 366, 367, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 0, 0, 17, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 24, 24, 4, 0, 0, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 25, 21, 22, 362, 363, 364, + 365, 366, 367, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 24, 55, 55, 24, 24, 55, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 24, 24, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 55, 0, 0, - 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 26, 26, 26, 26, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 24, + 24, 24, 24, 17, 17, 24, 24, 4, 4, 20, 4, 4, 4, 4, 24, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 24, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, + 24, 24, 24, 17, 24, 24, 24, 24, 24, 24, 24, 24, 0, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 4, 4, 4, 4, 55, 17, 17, 55, 0, 0, 0, 0, 0, 0, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 4, 4, + 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 25, 21, 22, 362, - 363, 364, 365, 366, 367, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 55, 55, 24, 24, 55, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 24, 24, 24, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, - 17, 24, 24, 24, 24, 17, 17, 24, 24, 4, 4, 20, 4, 4, 4, 4, 24, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 20, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, - 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 24, 24, 24, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, - 24, 24, 24, 24, 17, 24, 24, 24, 24, 24, 24, 24, 24, 0, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 4, 4, 4, 4, 55, 17, 17, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, - 4, 4, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 17, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 17, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 17, 17, 55, 55, 55, 55, 4, 4, 4, 4, 24, 24, 24, 24, 4, 17, 24, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 55, 4, 55, 4, 4, 4, 0, 26, 26, 26, 26, 26, 26, + 55, 55, 55, 55, 55, 17, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, 17, + 17, 55, 55, 55, 55, 4, 4, 4, 4, 24, 24, 24, 24, 4, 17, 24, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 55, 4, 55, 4, 4, 4, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, @@ -4041,38 +3647,46 @@ static const unsigned short index2[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, 17, 24, 24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, - 55, 0, 0, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 17, 17, 17, 17, 17, 17, 0, 17, 17, 0, 0, 24, 24, 17, 24, - 55, 17, 55, 17, 24, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 0, 0, 55, 55, + 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, - 24, 24, 24, 24, 0, 0, 24, 24, 17, 17, 17, 17, 24, 55, 4, 55, 17, 0, 0, 0, + 17, 17, 17, 0, 17, 17, 0, 0, 24, 24, 17, 24, 55, 17, 55, 17, 24, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, + 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, - 24, 24, 24, 17, 55, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 24, 0, 0, 0, - 0, 0, 0, 0, 0, 55, 24, 24, 24, 24, 24, 24, 17, 17, 24, 24, 24, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 24, 24, 24, 24, 0, 0, 24, 24, + 17, 17, 17, 17, 24, 55, 4, 55, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 17, 55, 24, 24, 24, + 24, 4, 4, 4, 4, 4, 4, 4, 4, 24, 0, 0, 0, 0, 0, 0, 0, 0, 55, 24, 24, 24, + 24, 24, 24, 17, 17, 24, 24, 24, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 17, 24, 24, 4, 4, 4, 55, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 17, 24, 24, 4, 4, 4, + 55, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, + 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 24, 17, 24, 24, 24, 17, 24, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, @@ -4088,105 +3702,188 @@ static const unsigned short index2[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 17, 24, 24, 24, 24, 24, 24, 24, 17, 24, 24, 17, - 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 24, 24, 24, 24, 24, 24, 0, 0, 0, 24, 0, 24, 24, 0, 24, 24, - 24, 24, 24, 24, 24, 55, 24, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 17, - 17, 0, 24, 24, 0, 17, 17, 24, 17, 24, 55, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 17, 17, 4, 4, 0, - 0, 0, 0, 0, 0, 0, 24, 24, 55, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 17, 17, 24, 24, 24, 24, 24, 0, 0, 0, 17, 17, 24, 17, 24, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 0, + 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 0, - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, + 24, 24, 24, 0, 0, 0, 24, 0, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 55, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, + 0, 0, 0, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 24, 55, 55, 55, 55, 55, 55, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 17, 17, 17, 0, 24, 24, 0, 17, 17, + 24, 17, 24, 55, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 17, 17, 17, 24, 24, 24, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 4, 4, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 24, 24, 24, - 24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 104, - 104, 104, 104, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 0, 26, 26, 26, 26, 26, 26, 26, 0, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 104, 104, 104, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 104, 4, 4, 4, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 24, 55, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 104, 104, 104, 104, 104, 104, 104, - 104, 104, 104, 104, 104, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 55, 55, 0, 0, 0, 0, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 104, 104, 4, 104, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 24, 24, 17, 17, 4, 4, 0, 0, 0, 0, 0, 0, 0, 24, 24, + 55, 17, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 17, 17, 24, 24, + 24, 24, 24, 0, 0, 0, 17, 17, 24, 17, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 390, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 390, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 390, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 0, 4, 4, 4, 4, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 4, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 24, 55, + 55, 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 17, 17, + 17, 24, 24, 24, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, + 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 4, 4, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 0, 0, 24, 24, 24, 24, 24, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, + 24, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 104, 104, 104, 104, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 26, + 26, 26, 26, 26, 26, 26, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 104, 104, 104, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 104, 4, 4, 4, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 4, 4, 4, 4, 0, 0, 0, 0, 0, 506, 506, 506, 506, 506, 506, 506, + 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, + 506, 506, 506, 506, 0, 0, 507, 507, 507, 507, 507, 507, 507, 507, 507, + 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, + 507, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 0, 0, 0, 0, 24, 55, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 104, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 104, 4, 104, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 17, 104, 104, 244, 244, 244, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 104, 104, 104, 0, 104, 104, 104, 104, 104, 104, 104, 0, 104, 104, 0, 55, @@ -4199,58 +3896,89 @@ static const unsigned short index2[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, - 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 0, 4, 24, 24, 4, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, + 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 0, 0, 4, 24, 24, 4, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 24, 24, 24, 4, 4, 4, 17, 17, 17, - 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 24, 24, 24, 24, 24, 24, 24, - 24, 4, 4, 24, 24, 24, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 4, 4, + 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 24, 24, 24, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, - 0, 0, 0, 0, 0, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 24, 24, 24, 4, 4, 4, + 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 24, 24, 24, 24, + 24, 24, 24, 24, 4, 4, 24, 24, 24, 24, 24, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 24, + 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 24, 24, 24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, - 122, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, - 122, 122, 122, 122, 122, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, - 122, 122, 122, 122, 122, 122, 122, 122, 122, 19, 19, 19, 19, 19, 19, 19, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 122, 0, 122, 122, 0, 0, 122, 0, 0, 122, 122, 0, 0, 122, 122, 122, + 19, 19, 122, 0, 122, 122, 0, 0, 122, 0, 0, 122, 122, 0, 0, 122, 122, 122, 122, 0, 122, 122, 122, 122, 122, 122, 122, 122, 19, 19, 19, 19, 0, 19, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, @@ -4312,199 +4040,320 @@ static const unsigned short index2[] = { 4, 4, 4, 4, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 24, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 55, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, - 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 0, 0, 24, 24, 24, 24, 24, 24, 24, 0, 24, 24, 0, 24, 24, 24, 24, - 24, 0, 0, 0, 0, 0, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 55, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, + 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 24, 24, 24, 24, 24, 24, 24, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 0, 0, 24, 24, 24, 24, 24, 24, 24, 0, 24, 24, + 0, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 24, 24, 24, 24, 24, 24, - 24, 104, 104, 104, 104, 104, 104, 104, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 0, 0, 0, 0, 55, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 104, + 104, 104, 104, 104, 104, 104, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 55, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 24, 24, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 104, 24, 24, 24, 24, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, 55, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 24, 24, - 24, 24, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 104, 24, 24, 24, 24, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 24, 24, 55, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, - 55, 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 0, 0, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, - 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, - 506, 506, 506, 506, 506, 506, 506, 506, 506, 507, 507, 507, 507, 507, - 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, - 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, - 507, 24, 24, 24, 24, 24, 24, 24, 104, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, + 24, 55, 55, 24, 55, 55, 55, 55, 55, 55, 55, 24, 24, 55, 55, 55, 55, 55, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 55, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 4, 26, 26, 26, 4, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 4, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 0, 0, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 55, 55, 0, 55, 0, 0, 55, 0, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 55, 0, 55, 0, 0, 0, 0, 0, 0, 55, 0, - 0, 0, 0, 55, 0, 55, 0, 55, 0, 55, 55, 55, 0, 55, 55, 0, 55, 0, 0, 55, 0, - 55, 0, 55, 0, 55, 0, 55, 0, 55, 55, 0, 55, 0, 0, 55, 55, 55, 55, 0, 55, - 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, 55, 0, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 55, 55, 55, 0, 55, - 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, - 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 361, 361, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, 26, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, + 55, 55, 55, 0, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24, 24, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 508, 4, 4, 4, 4, 4, 4, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 508, 508, 4, 4, 4, 4, 4, 4, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 508, 508, 508, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, + 508, 508, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, + 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, + 509, 509, 509, 509, 509, 509, 509, 509, 24, 24, 24, 24, 24, 24, 24, 104, + 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, - 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 4, 26, 26, 26, 4, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 4, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, + 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 0, 55, 0, + 0, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 0, + 55, 0, 55, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 55, 0, 55, 0, 55, 0, 55, 55, + 55, 0, 55, 55, 0, 55, 0, 0, 55, 0, 55, 0, 55, 0, 55, 0, 55, 0, 55, 55, 0, + 55, 0, 0, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, 55, 0, 55, 55, 55, + 55, 0, 55, 55, 55, 55, 0, 55, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, + 0, 0, 0, 0, 55, 55, 55, 0, 55, 55, 55, 55, 55, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, - 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 361, 361, 25, 21, 22, 362, 363, 364, 365, 366, 367, 26, 26, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, - 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 55, 390, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 510, 510, 510, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 4, 4, 4, 4, 4, 4, 510, 510, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 510, 4, 4, 4, 4, 4, 4, 510, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 510, 510, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 4, 0, 0, 0, 0, 0, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, + 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 390, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 20, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, }; /* Returns the numeric value as double for Unicode characters @@ -4586,6 +4435,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C50: case 0x11D50: case 0x11DA0: + case 0x11DE0: case 0x11F50: case 0x16130: case 0x16A60: @@ -4726,7 +4576,12 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C5A: case 0x11D51: case 0x11DA1: + case 0x11DE1: case 0x11F51: + case 0x12038: + case 0x12039: + case 0x12079: + case 0x1230B: case 0x12415: case 0x1241E: case 0x1242C: @@ -4740,6 +4595,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x16D71: case 0x16E81: case 0x16E94: + case 0x16FF4: case 0x1CCF1: case 0x1D2C1: case 0x1D2E1: @@ -4796,6 +4652,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x10F26: case 0x11FD1: case 0x11FD2: + case 0x12226: case 0x12464: case 0x1ECAE: case 0x1ED3C: @@ -5000,7 +4857,6 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x1ECA0: case 0x1ECB4: return (double) 100000.0; - case 0x5146: case 0x16B5E: return (double) 1000000.0; case 0x1ECA1: @@ -5013,6 +4869,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) return (double) 1000000000.0; case 0x16B60: return (double) 10000000000.0; + case 0x5146: case 0x16B61: return (double) 1000000000000.0; case 0x4EAC: @@ -5219,7 +5076,10 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C5B: case 0x11D52: case 0x11DA2: + case 0x11DE2: case 0x11F52: + case 0x1222B: + case 0x12399: case 0x12400: case 0x12416: case 0x1241F: @@ -5237,6 +5097,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x16D72: case 0x16E82: case 0x16E95: + case 0x16FF6: case 0x1CCF2: case 0x1D2C2: case 0x1D2E2: @@ -5457,7 +5318,9 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C5C: case 0x11D53: case 0x11DA3: + case 0x11DE3: case 0x11F53: + case 0x1230D: case 0x12401: case 0x12408: case 0x12417: @@ -5516,6 +5379,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11FCE: return (double) 3.0/16.0; case 0x0F2B: + case 0x16FF5: return (double) 3.0/2.0; case 0x0D5D: case 0x11FCD: @@ -5691,6 +5555,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C5D: case 0x11D54: case 0x11DA4: + case 0x11DE4: case 0x11F54: case 0x12402: case 0x12409: @@ -5901,6 +5766,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C5E: case 0x11D55: case 0x11DA5: + case 0x11DE5: case 0x11F55: case 0x12403: case 0x1240A: @@ -6108,6 +5974,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C5F: case 0x11D56: case 0x11DA6: + case 0x11DE6: case 0x11F56: case 0x12404: case 0x1240B: @@ -6269,6 +6136,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C60: case 0x11D57: case 0x11DA7: + case 0x11DE7: case 0x11F57: case 0x12405: case 0x1240C: @@ -6431,6 +6299,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C61: case 0x11D58: case 0x11DA8: + case 0x11DE8: case 0x11F58: case 0x12406: case 0x1240D: @@ -6589,6 +6458,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 ch) case 0x11C62: case 0x11D59: case 0x11DA9: + case 0x11DE9: case 0x11F59: case 0x12407: case 0x1240E: diff --git a/Objects/unionobject.c b/Objects/unionobject.c index 2206ed80ef0..a47d6193d70 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -393,8 +393,23 @@ static PyGetSetDef union_properties[] = { {0} }; +static PyObject * +union_nb_or(PyObject *a, PyObject *b) +{ + unionbuilder ub; + if (!unionbuilder_init(&ub, true)) { + return NULL; + } + if (!unionbuilder_add_single(&ub, a) || + !unionbuilder_add_single(&ub, b)) { + unionbuilder_finalize(&ub); + return NULL; + } + return make_union(&ub); +} + static PyNumberMethods union_as_number = { - .nb_or = _Py_union_type_or, // Add __or__ function + .nb_or = union_nb_or, // Add __or__ function }; static const char* const cls_attrs[] = { @@ -474,11 +489,13 @@ _Py_union_from_tuple(PyObject *args) } if (PyTuple_CheckExact(args)) { if (!unionbuilder_add_tuple(&ub, args)) { + unionbuilder_finalize(&ub); return NULL; } } else { if (!unionbuilder_add_single(&ub, args)) { + unionbuilder_finalize(&ub); return NULL; } } diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index bd4c4ac9b34..61fa3ddad0b 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -964,7 +964,8 @@ PyWeakref_GetRef(PyObject *ref, PyObject **pobj) } -PyObject * +/* removed in 3.15, but kept for stable ABI compatibility */ +PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref) { if (ref == NULL || !PyWeakref_Check(ref)) { diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 45d54e3c902..92cf6e8a9be 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -73,19 +73,13 @@ PyDoc_STRVAR(winreg_HKEYType___enter____doc__, #define WINREG_HKEYTYPE___ENTER___METHODDEF \ {"__enter__", (PyCFunction)winreg_HKEYType___enter__, METH_NOARGS, winreg_HKEYType___enter____doc__}, -static PyHKEYObject * +static PyObject * winreg_HKEYType___enter___impl(PyHKEYObject *self); static PyObject * winreg_HKEYType___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - PyHKEYObject *_return_value; - - _return_value = winreg_HKEYType___enter___impl((PyHKEYObject *)self); - return_value = (PyObject *)_return_value; - - return return_value; + return winreg_HKEYType___enter___impl((PyHKEYObject *)self); } #endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ @@ -1633,6 +1627,70 @@ exit: #if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) +PyDoc_STRVAR(winreg_DeleteTree__doc__, +"DeleteTree($module, key, sub_key=None, /)\n" +"--\n" +"\n" +"Deletes the specified key and all its subkeys and values recursively.\n" +"\n" +" key\n" +" An already open key, or any one of the predefined HKEY_* constants.\n" +" sub_key\n" +" A string that names the subkey to delete. If None, deletes all subkeys\n" +" and values of the specified key.\n" +"\n" +"This function deletes a key and all its descendants. If sub_key is None,\n" +"all subkeys and values of the specified key are deleted."); + +#define WINREG_DELETETREE_METHODDEF \ + {"DeleteTree", _PyCFunction_CAST(winreg_DeleteTree), METH_FASTCALL, winreg_DeleteTree__doc__}, + +static PyObject * +winreg_DeleteTree_impl(PyObject *module, HKEY key, const wchar_t *sub_key); + +static PyObject * +winreg_DeleteTree(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + HKEY key; + const wchar_t *sub_key = NULL; + + if (!_PyArg_CheckPositional("DeleteTree", nargs, 1, 2)) { + goto exit; + } + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + if (args[1] == Py_None) { + sub_key = NULL; + } + else if (PyUnicode_Check(args[1])) { + sub_key = PyUnicode_AsWideCharString(args[1], NULL); + if (sub_key == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("DeleteTree", "argument 2", "str or None", args[1]); + goto exit; + } +skip_optional: + return_value = winreg_DeleteTree_impl(module, key, sub_key); + +exit: + /* Cleanup for sub_key */ + PyMem_Free((void *)sub_key); + + return return_value; +} + +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_QueryReflectionKey__doc__, "QueryReflectionKey($module, key, /)\n" "--\n" @@ -1771,7 +1829,11 @@ exit: #define WINREG_ENABLEREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_ENABLEREFLECTIONKEY_METHODDEF) */ +#ifndef WINREG_DELETETREE_METHODDEF + #define WINREG_DELETETREE_METHODDEF +#endif /* !defined(WINREG_DELETETREE_METHODDEF) */ + #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=be4b6857b95558b5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=97295995db2c24e9 input=a9049054013a1b77]*/ diff --git a/PC/config.c b/PC/config.c index 6ce2131c7b8..51b46c64d99 100644 --- a/PC/config.c +++ b/PC/config.c @@ -13,6 +13,7 @@ extern PyObject* PyInit_errno(void); extern PyObject* PyInit_faulthandler(void); extern PyObject* PyInit__tracemalloc(void); extern PyObject* PyInit_gc(void); +extern PyObject* PyInit__math_integer(void); extern PyObject* PyInit_math(void); extern PyObject* PyInit_nt(void); extern PyObject* PyInit__operator(void); @@ -100,6 +101,7 @@ struct _inittab _PyImport_Inittab[] = { {"errno", PyInit_errno}, {"faulthandler", PyInit_faulthandler}, {"gc", PyInit_gc}, + {"_math_integer", PyInit__math_integer}, {"math", PyInit_math}, {"nt", PyInit_nt}, /* Use the NT os functions, not posix */ {"_operator", PyInit__operator}, diff --git a/PC/icons/idlex150.png b/PC/icons/idlex150.png index 806cb0c8aa2..dbdca5b00f8 100644 Binary files a/PC/icons/idlex150.png and b/PC/icons/idlex150.png differ diff --git a/PC/layout/support/pymanager.py b/PC/layout/support/pymanager.py index 667c89cdd2c..831d49ea3f9 100644 --- a/PC/layout/support/pymanager.py +++ b/PC/layout/support/pymanager.py @@ -80,7 +80,9 @@ def calculate_install_json(ns, *, for_embed=False, for_test=False): # Tag used in runtime ID (for side-by-side install/updates) ID_TAG = XY_ARCH_TAG - # Tag shown in 'py list' output + # Tag shown in 'py list' output. + # gh-139810: We only include '-dev' here for prereleases, even though it + # works for final releases too. DISPLAY_TAG = f"{XY_TAG}-dev{TAG_ARCH}" if VER_SUFFIX else XY_ARCH_TAG # Tag used for PEP 514 registration SYS_WINVER = XY_TAG + (TAG_ARCH if TAG_ARCH != '-64' else '') @@ -102,9 +104,10 @@ def calculate_install_json(ns, *, for_embed=False, for_test=False): FULL_ARCH_TAG, XY_ARCH_TAG, X_ARCH_TAG, - # X_TAG and XY_TAG doesn't include VER_SUFFIX, so create -dev versions - f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG and VER_SUFFIX else "", - f"{X_TAG}-dev{TAG_ARCH}" if X_TAG and VER_SUFFIX else "", + # gh-139810: The -dev tags are always included so that the latest + # release is chosen, no matter whether it's prerelease or final. + f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG else "", + f"{X_TAG}-dev{TAG_ARCH}" if X_TAG else "", ] # Generate run-for entries for each target. @@ -115,16 +118,15 @@ def calculate_install_json(ns, *, for_embed=False, for_test=False): ]: if not base["target"]: continue - STD_RUN_FOR.append({**base, "tag": FULL_ARCH_TAG}) + STD_RUN_FOR.extend([ + {**base, "tag": FULL_ARCH_TAG}, + {**base, "tag": f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG else ""}, + {**base, "tag": f"{X_TAG}-dev{TAG_ARCH}" if X_TAG else ""}, + ]) if XY_TAG: STD_RUN_FOR.append({**base, "tag": XY_ARCH_TAG}) if X_TAG: STD_RUN_FOR.append({**base, "tag": X_ARCH_TAG}) - if VER_SUFFIX: - STD_RUN_FOR.extend([ - {**base, "tag": f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG else ""}, - {**base, "tag": f"{X_TAG}-dev{TAG_ARCH}" if X_TAG else ""}, - ]) # Generate alias entries for each target. We need both arch and non-arch # versions as well as windowed/non-windowed versions to make sure that all diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 0e8379387cd..a126fca6f5a 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -118,7 +118,7 @@ WIN32 is still required for the locale module. /* Microsoft C defines _MSC_VER, as does clang-cl.exe */ #ifdef _MSC_VER -/* We want COMPILER to expand to a string containing _MSC_VER's *value*. +/* We want _Py_COMPILER to expand to a string containing _MSC_VER's *value*. * This is horridly tricky, because the stringization operator only works * on macro arguments, and doesn't evaluate macros passed *as* arguments. */ @@ -148,7 +148,7 @@ WIN32 is still required for the locale module. #define MS_WIN64 #endif -/* set the COMPILER and support tier +/* set the _Py_COMPILER and support tier * * win_amd64 MSVC (x86_64-pc-windows-msvc): 1 * win32 MSVC (i686-pc-windows-msvc): 1 @@ -158,22 +158,22 @@ WIN32 is still required for the locale module. #ifdef MS_WIN64 #if defined(_M_X64) || defined(_M_AMD64) #if defined(__clang__) -#define COMPILER ("[Clang " __clang_version__ "] 64 bit (AMD64) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") +#define _Py_COMPILER ("[Clang " __clang_version__ "] 64 bit (AMD64) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") #define PY_SUPPORT_TIER 0 #elif defined(__INTEL_COMPILER) -#define COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 64 bit (amd64) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") +#define _Py_COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 64 bit (amd64) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") #define PY_SUPPORT_TIER 0 #else -#define COMPILER _Py_PASTE_VERSION("64 bit (AMD64)") +#define _Py_COMPILER _Py_PASTE_VERSION("64 bit (AMD64)") #define PY_SUPPORT_TIER 1 #endif /* __clang__ */ #define PYD_PLATFORM_TAG "win_amd64" #elif defined(_M_ARM64) -#define COMPILER _Py_PASTE_VERSION("64 bit (ARM64)") +#define _Py_COMPILER _Py_PASTE_VERSION("64 bit (ARM64)") #define PY_SUPPORT_TIER 3 #define PYD_PLATFORM_TAG "win_arm64" #else -#define COMPILER _Py_PASTE_VERSION("64 bit (Unknown)") +#define _Py_COMPILER _Py_PASTE_VERSION("64 bit (Unknown)") #define PY_SUPPORT_TIER 0 #endif #endif /* MS_WIN64 */ @@ -220,22 +220,22 @@ typedef _W64 int Py_ssize_t; #if defined(MS_WIN32) && !defined(MS_WIN64) #if defined(_M_IX86) #if defined(__clang__) -#define COMPILER ("[Clang " __clang_version__ "] 32 bit (Intel) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") +#define _Py_COMPILER ("[Clang " __clang_version__ "] 32 bit (Intel) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") #define PY_SUPPORT_TIER 0 #elif defined(__INTEL_COMPILER) -#define COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 32 bit (Intel) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") +#define _Py_COMPILER ("[ICC v." _Py_STRINGIZE(__INTEL_COMPILER) " 32 bit (Intel) with MSC v." _Py_STRINGIZE(_MSC_VER) " CRT]") #define PY_SUPPORT_TIER 0 #else -#define COMPILER _Py_PASTE_VERSION("32 bit (Intel)") +#define _Py_COMPILER _Py_PASTE_VERSION("32 bit (Intel)") #define PY_SUPPORT_TIER 1 #endif /* __clang__ */ #define PYD_PLATFORM_TAG "win32" #elif defined(_M_ARM) -#define COMPILER _Py_PASTE_VERSION("32 bit (ARM)") +#define _Py_COMPILER _Py_PASTE_VERSION("32 bit (ARM)") #define PYD_PLATFORM_TAG "win_arm32" #define PY_SUPPORT_TIER 0 #else -#define COMPILER _Py_PASTE_VERSION("32 bit (Unknown)") +#define _Py_COMPILER _Py_PASTE_VERSION("32 bit (Unknown)") #define PY_SUPPORT_TIER 0 #endif #endif /* MS_WIN32 && !MS_WIN64 */ @@ -273,7 +273,7 @@ typedef int pid_t; #warning "Please use an up-to-date version of gcc! (>2.91 recommended)" #endif -#define COMPILER "[gcc]" +#define _Py_COMPILER "[gcc]" #define PY_LONG_LONG long long #define PY_LLONG_MIN LLONG_MIN #define PY_LLONG_MAX LLONG_MAX @@ -286,7 +286,7 @@ typedef int pid_t; /* XXX These defines are likely incomplete, but should be easy to fix. They should be complete enough to build extension modules. */ -#define COMPILER "[lcc-win32]" +#define _Py_COMPILER "[lcc-win32]" typedef int pid_t; /* __declspec() is supported here too - do nothing to get the defaults */ diff --git a/PC/python3dll.c b/PC/python3dll.c index 8ec791f8280..0d9e7e9a1ba 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -71,6 +71,7 @@ EXPORT_FUNC(Py_IncRef) EXPORT_FUNC(Py_Initialize) EXPORT_FUNC(Py_InitializeEx) EXPORT_FUNC(Py_Is) +EXPORT_FUNC(Py_IS_TYPE) EXPORT_FUNC(Py_IsFalse) EXPORT_FUNC(Py_IsFinalizing) EXPORT_FUNC(Py_IsInitialized) @@ -86,13 +87,16 @@ EXPORT_FUNC(Py_PACK_VERSION) EXPORT_FUNC(Py_REFCNT) EXPORT_FUNC(Py_ReprEnter) EXPORT_FUNC(Py_ReprLeave) +EXPORT_FUNC(Py_SET_SIZE) EXPORT_FUNC(Py_SetPath) EXPORT_FUNC(Py_SetProgramName) EXPORT_FUNC(Py_SetPythonHome) EXPORT_FUNC(Py_SetRecursionLimit) +EXPORT_FUNC(Py_SIZE) EXPORT_FUNC(Py_TYPE) EXPORT_FUNC(Py_VaBuildValue) EXPORT_FUNC(Py_XNewRef) +EXPORT_FUNC(PyABIInfo_Check) EXPORT_FUNC(PyAIter_Check) EXPORT_FUNC(PyArg_Parse) EXPORT_FUNC(PyArg_ParseTuple) @@ -190,6 +194,7 @@ EXPORT_FUNC(PyDict_Merge) EXPORT_FUNC(PyDict_MergeFromSeq2) EXPORT_FUNC(PyDict_New) EXPORT_FUNC(PyDict_Next) +EXPORT_FUNC(PyDict_SetDefaultRef) EXPORT_FUNC(PyDict_SetItem) EXPORT_FUNC(PyDict_SetItemString) EXPORT_FUNC(PyDict_Size) @@ -415,8 +420,10 @@ EXPORT_FUNC(PyModule_AddObjectRef) EXPORT_FUNC(PyModule_AddStringConstant) EXPORT_FUNC(PyModule_AddType) EXPORT_FUNC(PyModule_Create2) +EXPORT_FUNC(PyModule_Exec) EXPORT_FUNC(PyModule_ExecDef) EXPORT_FUNC(PyModule_FromDefAndSpec2) +EXPORT_FUNC(PyModule_FromSlotsAndSpec) EXPORT_FUNC(PyModule_GetDef) EXPORT_FUNC(PyModule_GetDict) EXPORT_FUNC(PyModule_GetFilename) @@ -424,6 +431,8 @@ EXPORT_FUNC(PyModule_GetFilenameObject) EXPORT_FUNC(PyModule_GetName) EXPORT_FUNC(PyModule_GetNameObject) EXPORT_FUNC(PyModule_GetState) +EXPORT_FUNC(PyModule_GetStateSize) +EXPORT_FUNC(PyModule_GetToken) EXPORT_FUNC(PyModule_New) EXPORT_FUNC(PyModule_NewObject) EXPORT_FUNC(PyModule_SetDocString) @@ -667,6 +676,7 @@ EXPORT_FUNC(PyType_GetFlags) EXPORT_FUNC(PyType_GetFullyQualifiedName) EXPORT_FUNC(PyType_GetModule) EXPORT_FUNC(PyType_GetModuleByDef) +EXPORT_FUNC(PyType_GetModuleByToken) EXPORT_FUNC(PyType_GetModuleName) EXPORT_FUNC(PyType_GetModuleState) EXPORT_FUNC(PyType_GetName) diff --git a/PC/python_ver_rc.h b/PC/python_ver_rc.h index bb98144cd03..70c805d3da8 100644 --- a/PC/python_ver_rc.h +++ b/PC/python_ver_rc.h @@ -8,7 +8,6 @@ #define PYTHON_COPYRIGHT "Copyright \xA9 2001 Python Software Foundation. Copyright \xA9 2000 BeOpen.com. Copyright \xA9 1995-2001 CNRI. Copyright \xA9 1991-1995 SMC." #define MS_WINDOWS -#include "modsupport.h" #include "patchlevel.h" #ifdef Py_DEBUG # define PYTHON_DEBUG_EXT "_d" diff --git a/PC/winreg.c b/PC/winreg.c index 05a33006c32..26bcd259efd 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -53,6 +53,7 @@ PyDoc_STRVAR(module_doc, "DeleteKey() - Deletes the specified key.\n" "DeleteKeyEx() - Deletes the specified key.\n" "DeleteValue() - Removes a named value from the specified registry key.\n" +"DeleteTree() - Deletes the specified key and all its subkeys and values recursively.\n" "EnumKey() - Enumerates subkeys of the specified open registry key.\n" "EnumValue() - Enumerates values of the specified open registry key.\n" "ExpandEnvironmentStrings() - Expand the env strings in a REG_EXPAND_SZ\n" @@ -107,7 +108,9 @@ PyDoc_STRVAR(PyHKEY_doc, "Operations:\n" "__bool__ - Handles with an open object return true, otherwise false.\n" "__int__ - Converting a handle to an integer returns the Win32 handle.\n" -"rich comparison - Handle objects are compared using the handle value."); +"__enter__, __exit__ - Context manager support for 'with' statement,\n" +"automatically closes handle.\n" +"__eq__, __ne__ - Equality comparison based on Windows handle value."); @@ -161,13 +164,6 @@ PyHKEY_deallocFunc(PyObject *ob) Py_DECREF(tp); } -static int -PyHKEY_traverseFunc(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static int PyHKEY_boolFunc(PyObject *ob) { @@ -188,13 +184,38 @@ PyHKEY_strFunc(PyObject *ob) return PyUnicode_FromFormat("<PyHKEY:%p>", pyhkey->hkey); } -static int -PyHKEY_compareFunc(PyObject *ob1, PyObject *ob2) +static PyObject * +PyHKEY_richcompare(PyObject *ob1, PyObject *ob2, int op) { + /* Both objects must be PyHKEY objects from the same module */ + if (Py_TYPE(ob1) != Py_TYPE(ob2)) { + Py_RETURN_NOTIMPLEMENTED; + } + PyHKEYObject *pyhkey1 = (PyHKEYObject *)ob1; PyHKEYObject *pyhkey2 = (PyHKEYObject *)ob2; - return pyhkey1 == pyhkey2 ? 0 : - (pyhkey1 < pyhkey2 ? -1 : 1); + HKEY hkey1 = pyhkey1->hkey; + HKEY hkey2 = pyhkey2->hkey; + int result; + + switch (op) { + case Py_EQ: + result = (hkey1 == hkey2); + break; + case Py_NE: + result = (hkey1 != hkey2); + break; + default: + /* Only support equality comparisons, not ordering */ + Py_RETURN_NOTIMPLEMENTED; + } + + if (result) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } } static Py_hash_t @@ -243,19 +264,8 @@ class HKEY_return_converter(CReturnConverter): self.err_occurred_if_null_pointer("_return_value", data) data.return_conversion.append( 'return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);\n') - -# HACK: this only works for PyHKEYObjects, nothing else. -# Should this be generalized and enshrined in clinic.py, -# destroy this converter with prejudice. -class self_return_converter(CReturnConverter): - type = 'PyHKEYObject *' - - def render(self, function, data): - self.declare(data) - data.return_conversion.append( - 'return_value = (PyObject *)_return_value;\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=4979f33998ffb6f8]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=b34c8217647f5fef]*/ #include "clinic/winreg.c.h" @@ -312,14 +322,14 @@ winreg_HKEYType_Detach_impl(PyHKEYObject *self) } /*[clinic input] -winreg.HKEYType.__enter__ -> self +winreg.HKEYType.__enter__ [clinic start generated code]*/ -static PyHKEYObject * +static PyObject * winreg_HKEYType___enter___impl(PyHKEYObject *self) -/*[clinic end generated code: output=52c34986dab28990 input=c40fab1f0690a8e2]*/ +/*[clinic end generated code: output=70ec10933068a08c input=85f6abf60774c88c]*/ { - return (PyHKEYObject*)Py_XNewRef(self); + return Py_XNewRef(self); } @@ -369,9 +379,10 @@ static PyType_Slot pyhkey_type_slots[] = { {Py_tp_members, PyHKEY_memberlist}, {Py_tp_methods, PyHKEY_methods}, {Py_tp_doc, (char *)PyHKEY_doc}, - {Py_tp_traverse, PyHKEY_traverseFunc}, + {Py_tp_traverse, _PyObject_VisitType}, {Py_tp_hash, PyHKEY_hashFunc}, {Py_tp_str, PyHKEY_strFunc}, + {Py_tp_richcompare, PyHKEY_richcompare}, // Number protocol {Py_nb_add, PyHKEY_binaryFailureFunc}, @@ -406,19 +417,6 @@ static PyType_Spec pyhkey_type_spec = { /************************************************************************ The public PyHKEY API (well, not public yet :-) ************************************************************************/ -PyObject * -PyHKEY_New(PyObject *m, HKEY hInit) -{ - winreg_state *st = _PyModule_GetState(m); - PyHKEYObject *key = PyObject_GC_New(PyHKEYObject, st->PyHKEY_Type); - if (key == NULL) { - return NULL; - } - key->hkey = hInit; - PyObject_GC_Track(key); - return (PyObject *)key; -} - BOOL PyHKEY_Close(winreg_state *st, PyObject *ob_handle) { @@ -494,48 +492,6 @@ PyHKEY_FromHKEY(winreg_state *st, HKEY h) } -/************************************************************************ - The module methods -************************************************************************/ -BOOL -PyWinObject_CloseHKEY(winreg_state *st, PyObject *obHandle) -{ - BOOL ok; - if (PyHKEY_Check(st, obHandle)) { - ok = PyHKEY_Close(st, obHandle); - } -#if SIZEOF_LONG >= SIZEOF_HKEY - else if (PyLong_Check(obHandle)) { - long rc; - Py_BEGIN_ALLOW_THREADS - rc = RegCloseKey((HKEY)PyLong_AsLong(obHandle)); - Py_END_ALLOW_THREADS - ok = (rc == ERROR_SUCCESS); - if (!ok) - PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); - } -#else - else if (PyLong_Check(obHandle)) { - long rc; - HKEY hkey = (HKEY)PyLong_AsVoidPtr(obHandle); - Py_BEGIN_ALLOW_THREADS - rc = RegCloseKey(hkey); - Py_END_ALLOW_THREADS - ok = (rc == ERROR_SUCCESS); - if (!ok) - PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); - } -#endif - else { - PyErr_SetString( - PyExc_TypeError, - "A handle must be a HKEY object or an integer"); - return FALSE; - } - return ok; -} - - /* Private Helper functions for the registry interfaces @@ -1684,7 +1640,7 @@ winreg_QueryValueEx_impl(PyObject *module, HKEY key, const wchar_t *name) return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValueEx"); } - obData = Reg2Py(retBuf, bufSize, typ); + obData = Reg2Py(retBuf, retSize, typ); PyMem_Free(retBuf); if (obData == NULL) return NULL; @@ -2026,6 +1982,45 @@ winreg_EnableReflectionKey_impl(PyObject *module, HKEY key) Py_RETURN_NONE; } +/*[clinic input] +winreg.DeleteTree + + key: HKEY + An already open key, or any one of the predefined HKEY_* constants. + sub_key: Py_UNICODE(accept={str, NoneType}) = None + A string that names the subkey to delete. If None, deletes all subkeys + and values of the specified key. + / + +Deletes the specified key and all its subkeys and values recursively. + +This function deletes a key and all its descendants. If sub_key is None, +all subkeys and values of the specified key are deleted. +[clinic start generated code]*/ + +static PyObject * +winreg_DeleteTree_impl(PyObject *module, HKEY key, const wchar_t *sub_key) +/*[clinic end generated code: output=c34395ee59290501 input=419ef9bb8b06e4bf]*/ +{ + LONG rc; + + if (PySys_Audit("winreg.DeleteTree", "nu", + (Py_ssize_t)key, sub_key) < 0) { + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + rc = RegDeleteTreeW(key, sub_key); + Py_END_ALLOW_THREADS + + if (rc != ERROR_SUCCESS) { + PyErr_SetFromWindowsErrWithFunction(rc, "RegDeleteTreeW"); + return NULL; + } + + Py_RETURN_NONE; +} + /*[clinic input] winreg.QueryReflectionKey @@ -2084,6 +2079,7 @@ static struct PyMethodDef winreg_methods[] = { WINREG_DELETEKEY_METHODDEF WINREG_DELETEKEYEX_METHODDEF WINREG_DELETEVALUE_METHODDEF + WINREG_DELETETREE_METHODDEF WINREG_DISABLEREFLECTIONKEY_METHODDEF WINREG_ENABLEREFLECTIONKEY_METHODDEF WINREG_ENUMKEY_METHODDEF diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 5ceddf759b8..605861ad3fd 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -164,7 +164,10 @@ <ClCompile Include="..\Objects\tupleobject.c" /> <ClCompile Include="..\Objects\typeobject.c" /> <ClCompile Include="..\Objects\typevarobject.c" /> + <ClCompile Include="..\Objects\unicode_format.c" /> <ClCompile Include="..\Objects\unicodectype.c" /> + <ClCompile Include="..\Objects\unicode_formatter.c" /> + <ClCompile Include="..\Objects\unicode_writer.c" /> <ClCompile Include="..\Objects\unicodeobject.c" /> <ClCompile Include="..\Objects\unionobject.c" /> <ClCompile Include="..\Objects\weakrefobject.c" /> @@ -209,7 +212,6 @@ <ClCompile Include="..\Python\errors.c" /> <ClCompile Include="..\Python\fileutils.c" /> <ClCompile Include="..\Python\flowgraph.c" /> - <ClCompile Include="..\Python\formatter_unicode.c" /> <ClCompile Include="..\Python\frame.c" /> <ClCompile Include="..\Python\future.c" /> <ClCompile Include="..\Python\gc.c" /> @@ -255,6 +257,7 @@ <ClCompile Include="..\Python\pylifecycle.c" /> <ClCompile Include="..\Python\pymath.c" /> <ClCompile Include="..\Python\pystate.c" /> + <ClCompile Include="..\Python\pystats.c" /> <ClCompile Include="..\Python\pystrcmp.c" /> <ClCompile Include="..\Python\pystrhex.c" /> <ClCompile Include="..\Python\pystrtod.c" /> diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 332d466b1f7..c67fe53363e 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -160,9 +160,6 @@ <ClCompile Include="..\Python\flowgraph.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\Python\formatter_unicode.c"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="..\Python\frame.c"> <Filter>Source Files</Filter> </ClCompile> @@ -370,6 +367,9 @@ <ClCompile Include="..\Python\pystate.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Python\pystats.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Python\pystrcmp.c"> <Filter>Source Files</Filter> </ClCompile> @@ -484,9 +484,18 @@ <ClCompile Include="..\Objects\typeobject.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Objects\unicode_format.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Objects\unicodectype.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Objects\unicode_formatter.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Objects\unicode_writer.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Objects\unicodeobject.c"> <Filter>Source Files</Filter> </ClCompile> diff --git a/PCbuild/_remote_debugging.vcxproj b/PCbuild/_remote_debugging.vcxproj index c55f2908e03..830b7b87448 100644 --- a/PCbuild/_remote_debugging.vcxproj +++ b/PCbuild/_remote_debugging.vcxproj @@ -92,8 +92,23 @@ <PropertyGroup> <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> </PropertyGroup> + <ItemDefinitionGroup> + <Link> + <AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> +</ItemDefinitionGroup> <ItemGroup> - <ClCompile Include="..\Modules\_remote_debugging_module.c" /> + <ClCompile Include="..\Modules\_remote_debugging\module.c" /> + <ClCompile Include="..\Modules\_remote_debugging\object_reading.c" /> + <ClCompile Include="..\Modules\_remote_debugging\code_objects.c" /> + <ClCompile Include="..\Modules\_remote_debugging\frames.c" /> + <ClCompile Include="..\Modules\_remote_debugging\frame_cache.c" /> + <ClCompile Include="..\Modules\_remote_debugging\threads.c" /> + <ClCompile Include="..\Modules\_remote_debugging\asyncio.c" /> + <ClCompile Include="..\Modules\_remote_debugging\subprocess.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Modules\_remote_debugging\_remote_debugging.h" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc" /> diff --git a/PCbuild/_remote_debugging.vcxproj.filters b/PCbuild/_remote_debugging.vcxproj.filters index ce4437f74e0..793a3256c52 100644 --- a/PCbuild/_remote_debugging.vcxproj.filters +++ b/PCbuild/_remote_debugging.vcxproj.filters @@ -4,12 +4,43 @@ <Filter Include="Source Files"> <UniqueIdentifier>{6d101329-41df-49a0-8639-f35408ad7c6d}</UniqueIdentifier> </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + </Filter> <Filter Include="Resource Files"> <UniqueIdentifier>{711941d1-269c-49cb-a733-759b2b91fc61}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> - <ClCompile Include="..\Modules\_remote_debugging_module.c" /> + <ClCompile Include="..\Modules\_remote_debugging\module.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\object_reading.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\code_objects.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\frames.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\frame_cache.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\threads.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\asyncio.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_remote_debugging\subprocess.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\Modules\_remote_debugging\_remote_debugging.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc"> diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index a68f15d25aa..68707a54ff6 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -125,6 +125,8 @@ <ClCompile Include="..\Modules\_testcapi\immortal.c" /> <ClCompile Include="..\Modules\_testcapi\gc.c" /> <ClCompile Include="..\Modules\_testcapi\run.c" /> + <ClCompile Include="..\Modules\_testcapi\modsupport.c" /> + <ClCompile Include="..\Modules\_testcapi\module.c" /> <ClCompile Include="..\Modules\_testcapi\monitoring.c" /> <ClCompile Include="..\Modules\_testcapi\config.c" /> <ClCompile Include="..\Modules\_testcapi\import.c" /> diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 21091e9dc1a..b0e75ce433a 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -108,6 +108,12 @@ <ClCompile Include="..\Modules\_testcapi\run.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Modules\_testcapi\modsupport.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_testcapi\module.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Modules\_testcapi\monitoring.c"> <Filter>Source Files</Filter> </ClCompile> diff --git a/PCbuild/build.bat b/PCbuild/build.bat index 60235704886..e4de9a80d76 100644 --- a/PCbuild/build.bat +++ b/PCbuild/build.bat @@ -41,6 +41,7 @@ echo. --experimental-jit-off Ditto but off by default (PYTHON_JIT=1 enable echo. --experimental-jit-interpreter Enable the experimental Tier 2 interpreter. echo. --pystats Enable PyStats collection. echo. --tail-call-interp Enable tail-calling interpreter (requires LLVM 19 or higher). +echo. --enable-stackref-debug Enable stackref debugging mode. echo. echo.Available flags to avoid building certain modules. echo.These flags have no effect if '-e' is not given: @@ -98,6 +99,7 @@ if "%~1"=="--experimental-jit-interpreter-off" (set UseTIER2=6) & shift & goto C if "%~1"=="--without-remote-debug" (set DisableRemoteDebug=true) & shift & goto CheckOpts if "%~1"=="--pystats" (set PyStats=1) & shift & goto CheckOpts if "%~1"=="--tail-call-interp" (set UseTailCallInterp=true) & shift & goto CheckOpts +if "%~1"=="--enable-stackref-debug" (set StackRefDebug=true) & shift & goto CheckOpts rem These use the actual property names used by MSBuild. We could just let rem them in through the environment, but we specify them on the command line rem anyway for visibility so set defaults after this @@ -202,6 +204,7 @@ echo on /p:PyStats=%PyStats%^ /p:UseTailCallInterp=%UseTailCallInterp%^ /p:DisableRemoteDebug=%DisableRemoteDebug%^ + /p:StackRefDebug=%StackRefDebug%^ %1 %2 %3 %4 %5 %6 %7 %8 %9 @echo off diff --git a/PCbuild/field3.py b/PCbuild/field3.py deleted file mode 100644 index edcbe36ae08..00000000000 --- a/PCbuild/field3.py +++ /dev/null @@ -1,35 +0,0 @@ -# An absurd workaround for the lack of arithmetic in MS's resource compiler. -# After building Python, run this, then paste the output into the appropriate -# part of PC\python_nt.rc. -# Example output: -# -# * For 2.3a0, -# * PY_MICRO_VERSION = 0 -# * PY_RELEASE_LEVEL = 'alpha' = 0xA -# * PY_RELEASE_SERIAL = 1 -# * -# * and 0*1000 + 10*10 + 1 = 101. -# */ -# #define FIELD3 101 - -import sys - -major, minor, micro, level, serial = sys.version_info -levelnum = {'alpha': 0xA, - 'beta': 0xB, - 'candidate': 0xC, - 'final': 0xF, - }[level] -string = sys.version.split()[0] # like '2.3a0' - -print(" * For %s," % string) -print(" * PY_MICRO_VERSION = %d" % micro) -print(" * PY_RELEASE_LEVEL = %r = %s" % (level, hex(levelnum))) -print(" * PY_RELEASE_SERIAL = %d" % serial) -print(" *") - -field3 = micro * 1000 + levelnum * 10 + serial - -print(" * and %d*1000 + %d*10 + %d = %d" % (micro, levelnum, serial, field3)) -print(" */") -print("#define FIELD3", field3) diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index d65d080ca71..841d83968c6 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -47,7 +47,7 @@ @rem If py.exe finds a recent enough version, use that one @rem It is fine to add new versions to this list when they have released, @rem but we do not use prerelease builds here. -@for %%p in (3.13 3.12 3.11 3.10) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found +@for %%p in (3.14 3.13 3.12 3.11 3.10) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found @if NOT exist "%_Py_EXTERNALS_DIR%" mkdir "%_Py_EXTERNALS_DIR%" @set _Py_NUGET=%NUGET% diff --git a/PCbuild/get_external.py b/PCbuild/get_external.py index a78aa6a2304..27fbc311bbc 100755 --- a/PCbuild/get_external.py +++ b/PCbuild/get_external.py @@ -3,7 +3,9 @@ import argparse import os import pathlib +import platform import sys +import tarfile import time import urllib.error import urllib.request @@ -22,15 +24,13 @@ def retrieve_with_retries(download_location, output_path, reporthook, ) except (urllib.error.URLError, ConnectionError) as ex: if attempt == max_retries: - msg = f"Download from {download_location} failed." - raise OSError(msg) from ex + raise OSError(f'Download from {download_location} failed.') from ex time.sleep(2.25**attempt) else: return resp - def fetch_zip(commit_hash, zip_dir, *, org='python', binary=False, verbose): - repo = f'cpython-{"bin" if binary else "source"}-deps' + repo = 'cpython-bin-deps' if binary else 'cpython-source-deps' url = f'https://github.com/{org}/{repo}/archive/{commit_hash}.zip' reporthook = None if verbose: @@ -44,6 +44,42 @@ def fetch_zip(commit_hash, zip_dir, *, org='python', binary=False, verbose): return filename +def fetch_release(tag, tarball_dir, *, org='python', verbose=False): + arch = os.environ.get('PreferredToolArchitecture') + if not arch: + machine = platform.machine() + arch = 'ARM64' if machine == 'ARM64' else 'AMD64' + elif arch.lower() in ('x86', 'x64'): + arch = 'AMD64' + reporthook = None + if verbose: + reporthook = print + tarball_dir.mkdir(parents=True, exist_ok=True) + + arch_filename = f'{tag}-{arch}.tar.xz' + arch_url = f'https://github.com/{org}/cpython-bin-deps/releases/download/{tag}/{arch_filename}' + try: + output_path = tarball_dir / arch_filename + retrieve_with_retries(arch_url, output_path, reporthook) + return output_path + except OSError: + if verbose: + print(f'{arch_filename} not found, trying generic binary...') + + generic_filename = f'{tag}.tar.xz' + generic_url = f'https://github.com/{org}/cpython-bin-deps/releases/download/{tag}/{generic_filename}' + output_path = tarball_dir / generic_filename + retrieve_with_retries(generic_url, output_path, reporthook) + return output_path + + +def extract_tarball(externals_dir, tarball_path, tag): + output_path = externals_dir / tag + with tarfile.open(tarball_path) as tf: + tf.extractall(os.fspath(externals_dir), filter='data') + return output_path + + def extract_zip(externals_dir, zip_path): with zipfile.ZipFile(os.fspath(zip_path)) as zf: zf.extractall(os.fspath(externals_dir)) @@ -55,6 +91,8 @@ def parse_args(): p.add_argument('-v', '--verbose', action='store_true') p.add_argument('-b', '--binary', action='store_true', help='Is the dependency in the binary repo?') + p.add_argument('-r', '--release', action='store_true', + help='Download from GitHub release assets instead of branch') p.add_argument('-O', '--organization', help='Organization owning the deps repos', default='python') p.add_argument('-e', '--externals-dir', type=pathlib.Path, @@ -67,30 +105,53 @@ def parse_args(): def main(): args = parse_args() - zip_path = fetch_zip( - args.tag, - args.externals_dir / 'zips', - org=args.organization, - binary=args.binary, - verbose=args.verbose, - ) final_name = args.externals_dir / args.tag - extracted = extract_zip(args.externals_dir, zip_path) - for wait in [1, 2, 3, 5, 8, 0]: - try: - extracted.replace(final_name) - break - except PermissionError as ex: - retry = f" Retrying in {wait}s..." if wait else "" - print(f"Encountered permission error '{ex}'.{retry}", file=sys.stderr) - time.sleep(wait) - else: - print( - f"ERROR: Failed to extract {final_name}.", - "You may need to restart your build", - file=sys.stderr, + + # Check if the dependency already exists in externals/ directory + # (either already downloaded/extracted, or checked into the git tree) + if final_name.exists(): + if args.verbose: + print(f'{args.tag} already exists at {final_name}, skipping download.') + return + + # Determine download method: release artifacts for large deps (like LLVM), + # otherwise zip download from GitHub branches + if args.release: + tarball_path = fetch_release( + args.tag, + args.externals_dir / 'tarballs', + org=args.organization, + verbose=args.verbose, ) - sys.exit(1) + extracted = extract_tarball(args.externals_dir, tarball_path, args.tag) + else: + # Use zip download from GitHub branches + # (cpython-bin-deps if --binary, cpython-source-deps otherwise) + zip_path = fetch_zip( + args.tag, + args.externals_dir / 'zips', + org=args.organization, + binary=args.binary, + verbose=args.verbose, + ) + extracted = extract_zip(args.externals_dir, zip_path) + + if extracted != final_name: + for wait in [1, 2, 3, 5, 8, 0]: + try: + extracted.replace(final_name) + break + except PermissionError as ex: + retry = f" Retrying in {wait}s..." if wait else "" + print(f"Encountered permission error '{ex}'.{retry}", file=sys.stderr) + time.sleep(wait) + else: + print( + f"ERROR: Failed to rename {extracted} to {final_name}.", + "You may need to restart your build", + file=sys.stderr, + ) + sys.exit(1) if __name__ == '__main__': diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index eff8d1ccd7f..9d02e2121cc 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,12 +54,12 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.16 +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.18 set libraries=%libraries% mpdecimal-4.0.0 set libraries=%libraries% sqlite-3.50.4.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.15.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.15.0 -set libraries=%libraries% xz-5.2.5 +set libraries=%libraries% xz-5.8.1.1 set libraries=%libraries% zlib-ng-2.2.4 set libraries=%libraries% zstd-1.5.7 @@ -79,10 +79,10 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.16.2 +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.18 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.15.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 -if NOT "%IncludeLLVM%"=="false" set binaries=%binaries% llvm-19.1.7.0 +if NOT "%IncludeLLVM%"=="false" set binaries=%binaries% llvm-21.1.4.0 for %%b in (%binaries%) do ( if exist "%EXTERNALS_DIR%\%%b" ( @@ -92,7 +92,11 @@ for %%b in (%binaries%) do ( git clone --depth 1 https://github.com/%ORG%/cpython-bin-deps --branch %%b "%EXTERNALS_DIR%\%%b" ) else ( echo.Fetching %%b... - %PYTHON% -E "%PCBUILD%\get_external.py" -b -O %ORG% -e "%EXTERNALS_DIR%" %%b + if "%%b"=="llvm-21.1.4.0" ( + %PYTHON% -E "%PCBUILD%\get_external.py" --release --organization %ORG% --externals-dir "%EXTERNALS_DIR%" %%b + ) else ( + %PYTHON% -E "%PCBUILD%\get_external.py" --binary --organization %ORG% --externals-dir "%EXTERNALS_DIR%" %%b + ) ) ) diff --git a/PCbuild/liblzma.vcxproj b/PCbuild/liblzma.vcxproj index 97938692328..75d4e162346 100644 --- a/PCbuild/liblzma.vcxproj +++ b/PCbuild/liblzma.vcxproj @@ -92,7 +92,7 @@ <ItemDefinitionGroup> <ClCompile> <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(lzmaDir)windows/vs2019;$(lzmaDir)src/liblzma/common;$(lzmaDir)src/common;$(lzmaDir)src/liblzma/api;$(lzmaDir)src/liblzma/check;$(lzmaDir)src/liblzma/delta;$(lzmaDir)src/liblzma/lz;$(lzmaDir)src/liblzma/lzma;$(lzmaDir)src/liblzma/rangecoder;$(lzmaDir)src/liblzma/simple;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(lzmaDir)windows;$(lzmaDir)src/liblzma/common;$(lzmaDir)src/common;$(lzmaDir)src/liblzma/api;$(lzmaDir)src/liblzma/check;$(lzmaDir)src/liblzma/delta;$(lzmaDir)src/liblzma/lz;$(lzmaDir)src/liblzma/lzma;$(lzmaDir)src/liblzma/rangecoder;$(lzmaDir)src/liblzma/simple;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <DisableSpecificWarnings>4244;4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <AdditionalOptions Condition="$(PlatformToolset) == 'ClangCL'">%(AdditionalOptions) -Wno-deprecated-declarations</AdditionalOptions> </ClCompile> @@ -102,9 +102,7 @@ <ClCompile Include="$(lzmaDir)src\common\tuklib_physmem.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\check\check.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\check\crc32_fast.c" /> - <ClCompile Include="$(lzmaDir)src\liblzma\check\crc32_table.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\check\crc64_fast.c" /> - <ClCompile Include="$(lzmaDir)src\liblzma\check\crc64_table.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\check\sha256.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\common\alone_decoder.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\common\alone_encoder.c" /> @@ -163,6 +161,7 @@ <ClCompile Include="$(lzmaDir)src\liblzma\lz\lz_encoder_mf.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\rangecoder\price_table.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\simple\arm.c" /> + <ClCompile Include="$(lzmaDir)src\liblzma\simple\arm64.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\simple\armthumb.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\simple\ia64.c" /> <ClCompile Include="$(lzmaDir)src\liblzma\simple\powerpc.c" /> @@ -239,7 +238,7 @@ <ClInclude Include="$(lzmaDir)src\liblzma\simple\simple_decoder.h" /> <ClInclude Include="$(lzmaDir)src\liblzma\simple\simple_encoder.h" /> <ClInclude Include="$(lzmaDir)src\liblzma\simple\simple_private.h" /> - <ClInclude Include="$(lzmaDir)windows\vs2019\config.h" /> + <ClInclude Include="$(lzmaDir)windows\config.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/PCbuild/liblzma.vcxproj.filters b/PCbuild/liblzma.vcxproj.filters index ebe2a7d5fa9..42feca5a341 100644 --- a/PCbuild/liblzma.vcxproj.filters +++ b/PCbuild/liblzma.vcxproj.filters @@ -18,6 +18,9 @@ <ClCompile Include="$(lzmaDir)src\liblzma\simple\arm.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="$(lzmaDir)src\liblzma\simple\arm64.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="$(lzmaDir)src\liblzma\simple\armthumb.c"> <Filter>Source Files</Filter> </ClCompile> @@ -54,15 +57,9 @@ <ClCompile Include="$(lzmaDir)src\liblzma\check\crc32_fast.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="$(lzmaDir)src\liblzma\check\crc32_table.c"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="$(lzmaDir)src\liblzma\check\crc64_fast.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="$(lzmaDir)src\liblzma\check\crc64_table.c"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="$(lzmaDir)src\liblzma\delta\delta_common.c"> <Filter>Source Files</Filter> </ClCompile> @@ -428,7 +425,7 @@ <ClInclude Include="$(lzmaDir)src\liblzma\simple\simple_private.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="$(lzmaDir)windows\vs2019\config.h"> + <ClInclude Include="$(lzmaDir)windows\config.h"> <Filter>Header Files</Filter> </ClInclude> </ItemGroup> diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index cf35e705f35..53bfe5e3ea9 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -13,6 +13,7 @@ <GeneratedFrozenModulesDir>$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)_frozen\</GeneratedFrozenModulesDir> <GeneratedZlibNgDir>$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)_$(Configuration)\zlib-ng\</GeneratedZlibNgDir> <GeneratedJitStencilsDir>$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)_$(Configuration)</GeneratedJitStencilsDir> + <GeneratedJitStencilsDir Condition="$(Configuration) == 'PGUpdate'">$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)_PGInstrument</GeneratedJitStencilsDir> <TargetName Condition="'$(TargetName)' == ''">$(ProjectName)</TargetName> <TargetName>$(TargetName)$(PyDebugExt)</TargetName> <GenerateManifest>false</GenerateManifest> diff --git a/PCbuild/python.props b/PCbuild/python.props index e1c2ff3fe3c..7840e2a1cfc 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -11,6 +11,7 @@ We set BasePlatformToolset for ICC's benefit, it's otherwise ignored. --> + <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and '$(VisualStudioVersion)' == '18.0'">v143</BasePlatformToolset> <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and '$(VisualStudioVersion)' == '17.0'">v143</BasePlatformToolset> <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and '$(VisualStudioVersion)' == '16.0'">v142</BasePlatformToolset> <BasePlatformToolset Condition="'$(BasePlatformToolset)' == '' and ('$(MSBuildToolsVersion)' == '15.0' or '$(VisualStudioVersion)' == '15.0')">v141</BasePlatformToolset> @@ -76,13 +77,13 @@ <PropertyGroup> <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.50.4.0\</sqlite3Dir> <bz2Dir Condition="$(bz2Dir) == ''">$(ExternalsDir)bzip2-1.0.8\</bz2Dir> - <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.2.5\</lzmaDir> + <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.8.1.1\</lzmaDir> <libffiDir Condition="$(libffiDir) == ''">$(ExternalsDir)libffi-3.4.4\</libffiDir> <libffiOutDir Condition="$(libffiOutDir) == ''">$(libffiDir)$(ArchName)\</libffiOutDir> <libffiIncludeDir Condition="$(libffiIncludeDir) == ''">$(libffiOutDir)include</libffiIncludeDir> <mpdecimalDir Condition="$(mpdecimalDir) == ''">$(ExternalsDir)\mpdecimal-4.0.0\</mpdecimalDir> - <opensslDir Condition="$(opensslDir) == ''">$(ExternalsDir)openssl-3.0.16\</opensslDir> - <opensslOutDir Condition="$(opensslOutDir) == ''">$(ExternalsDir)openssl-bin-3.0.16.2\$(ArchName)\</opensslOutDir> + <opensslDir Condition="$(opensslDir) == ''">$(ExternalsDir)openssl-3.0.18\</opensslDir> + <opensslOutDir Condition="$(opensslOutDir) == ''">$(ExternalsDir)openssl-bin-3.0.18\$(ArchName)\</opensslOutDir> <opensslIncludeDir Condition="$(opensslIncludeDir) == ''">$(opensslOutDir)include</opensslIncludeDir> <nasmDir Condition="$(nasmDir) == ''">$(ExternalsDir)\nasm-2.11.06\</nasmDir> <zlibDir Condition="$(zlibDir) == ''">$(ExternalsDir)\zlib-1.3.1\</zlibDir> diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 517103acea8..dcfb75ce162 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -107,9 +107,10 @@ <PreprocessorDefinitions Condition="$(IncludeExternals)">_Py_HAVE_ZLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(UseJIT)' == 'true'">_Py_JIT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(UseTIER2)' != '' and '$(UseTIER2)' != '0'">_Py_TIER2=$(UseTIER2);%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessorDefinitions Condition="'$(UseTailCallInterp)' == 'true'">Py_TAIL_CALL_INTERP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(UseTailCallInterp)' == 'true'">_Py_TAIL_CALL_INTERP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(WITH_COMPUTED_GOTOS)' != ''">HAVE_COMPUTED_GOTOS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(DisableRemoteDebug)' != 'true'">Py_REMOTE_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(StackRefDebug)' == 'true'">Py_STACKREF_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <AdditionalDependencies>version.lib;ws2_32.lib;pathcch.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -168,9 +169,11 @@ <ClInclude Include="..\Include\cpython\pylock.h" /> <ClInclude Include="..\Include\cpython\longintrepr.h" /> <ClInclude Include="..\Include\cpython\longobject.h" /> + <ClInclude Include="..\Include\cpython\marshal.h" /> <ClInclude Include="..\Include\cpython\memoryobject.h" /> <ClInclude Include="..\Include\cpython\methodobject.h" /> <ClInclude Include="..\Include\cpython\modsupport.h" /> + <ClInclude Include="..\Include\cpython\monitoring.h" /> <ClInclude Include="..\Include\cpython\object.h" /> <ClInclude Include="..\Include\cpython\objimpl.h" /> <ClInclude Include="..\Include\cpython\odictobject.h" /> @@ -190,6 +193,8 @@ <ClInclude Include="..\Include\cpython\pythonrun.h" /> <ClInclude Include="..\Include\cpython\pythread.h" /> <ClInclude Include="..\Include\cpython\setobject.h" /> + <ClInclude Include="..\Include\cpython\sliceobject.h" /> + <ClInclude Include="..\Include\cpython\structseq.h" /> <ClInclude Include="..\Include\cpython\traceback.h" /> <ClInclude Include="..\Include\cpython\tracemalloc.h" /> <ClInclude Include="..\Include\cpython\tupleobject.h" /> @@ -272,6 +277,7 @@ <ClInclude Include="..\Include\internal\pycore_llist.h" /> <ClInclude Include="..\Include\internal\pycore_lock.h" /> <ClInclude Include="..\Include\internal\pycore_long.h" /> + <ClInclude Include="..\Include\internal\pycore_mmap.h" /> <ClInclude Include="..\Include\internal\pycore_modsupport.h" /> <ClInclude Include="..\Include\internal\pycore_moduleobject.h" /> <ClInclude Include="..\Include\internal\pycore_namespace.h" /> @@ -324,6 +330,7 @@ <ClInclude Include="..\Include\internal\pycore_typevarobject.h" /> <ClInclude Include="..\Include\internal\pycore_ucnhash.h" /> <ClInclude Include="..\Include\internal\pycore_unionobject.h" /> + <ClInclude Include="..\Include\internal\pycore_unicodectype.h" /> <ClInclude Include="..\Include\internal\pycore_unicodeobject.h" /> <ClInclude Include="..\Include\internal\pycore_unicodeobject_generated.h" /> <ClInclude Include="..\Include\internal\pycore_uniqueid.h" /> @@ -332,7 +339,6 @@ <ClInclude Include="..\Include\intrcheck.h" /> <ClInclude Include="..\Include\iterobject.h" /> <ClInclude Include="..\Include\listobject.h" /> - <ClInclude Include="..\Include\pylock.h" /> <ClInclude Include="..\Include\longobject.h" /> <ClInclude Include="..\Include\marshal.h" /> <ClInclude Include="..\Include\memoryobject.h" /> @@ -475,6 +481,7 @@ <ClCompile Include="..\Modules\hmacmodule.c" /> <ClCompile Include="..\Modules\itertoolsmodule.c" /> <ClCompile Include="..\Modules\main.c" /> + <ClCompile Include="..\Modules\mathintegermodule.c" /> <ClCompile Include="..\Modules\mathmodule.c" /> <ClCompile Include="..\Modules\md5module.c" /> <ClCompile Include="..\Modules\mmapmodule.c" /> @@ -555,7 +562,10 @@ <ClCompile Include="..\Objects\tupleobject.c" /> <ClCompile Include="..\Objects\typeobject.c" /> <ClCompile Include="..\Objects\typevarobject.c" /> + <ClCompile Include="..\Objects\unicode_format.c" /> <ClCompile Include="..\Objects\unicodectype.c" /> + <ClCompile Include="..\Objects\unicode_formatter.c" /> + <ClCompile Include="..\Objects\unicode_writer.c" /> <ClCompile Include="..\Objects\unicodeobject.c" /> <ClCompile Include="..\Objects\unionobject.c" /> <ClCompile Include="..\Objects\weakrefobject.c" /> @@ -602,7 +612,6 @@ <ClCompile Include="..\Python\errors.c" /> <ClCompile Include="..\Python\fileutils.c" /> <ClCompile Include="..\Python\flowgraph.c" /> - <ClCompile Include="..\Python\formatter_unicode.c" /> <ClCompile Include="..\Python\frame.c" /> <ClCompile Include="..\Python\frozen.c"> <AdditionalIncludeDirectories>$(GeneratedFrozenModulesDir)Python;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> @@ -651,6 +660,7 @@ <ClCompile Include="..\Python\pymath.c" /> <ClCompile Include="..\Python\pytime.c" /> <ClCompile Include="..\Python\pystate.c" /> + <ClCompile Include="..\Python\pystats.c" /> <ClCompile Include="..\Python\pystrcmp.c" /> <ClCompile Include="..\Python\pystrhex.c" /> <ClCompile Include="..\Python\pystrtod.c" /> diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index e9eedfd1312..247f4b5a784 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -120,9 +120,6 @@ <ClInclude Include="..\Include\listobject.h"> <Filter>Include</Filter> </ClInclude> - <ClInclude Include="..\Include\pylock.h"> - <Filter>Include</Filter> - </ClInclude> <ClInclude Include="..\Include\longobject.h"> <Filter>Include</Filter> </ClInclude> @@ -489,9 +486,15 @@ <ClInclude Include="..\Include\cpython\pylifecycle.h"> <Filter>Include\cpython</Filter> </ClInclude> + <ClInclude Include="..\Include\cpython\structseq.h"> + <Filter>Include\cpython</Filter> + </ClInclude> <ClInclude Include="..\Include\cpython\tupleobject.h"> <Filter>Include\cpython</Filter> </ClInclude> + <ClInclude Include="..\Include\cpython\sliceobject.h"> + <Filter>Include\cpython</Filter> + </ClInclude> <ClInclude Include="..\Include\cpython\traceback.h"> <Filter>Include\cpython</Filter> </ClInclude> @@ -525,6 +528,9 @@ <ClInclude Include="..\Include\cpython\initconfig.h"> <Filter>Include\cpython</Filter> </ClInclude> + <ClInclude Include="..\Include\internal\pycore_unicodectype.h"> + <Filter>Include\internal</Filter> + </ClInclude> <ClInclude Include="..\Include\internal\pycore_unicodeobject.h"> <Filter>Include\internal</Filter> </ClInclude> @@ -729,6 +735,9 @@ <ClInclude Include="..\Include\internal\pycore_long.h"> <Filter>Include\internal</Filter> </ClInclude> + <ClInclude Include="..\Include\internal\pycore_mmap.h"> + <Filter>Include\internal</Filter> + </ClInclude> <ClInclude Include="..\Include\internal\pycore_modsupport.h"> <Filter>Include\internal</Filter> </ClInclude> @@ -882,6 +891,15 @@ <ClInclude Include="..\Include\internal\pycore_uniqueid.h"> <Filter>Include\internal</Filter> </ClInclude> + <ClInclude Include="..\Include\internal\pycore_uop.h"> + <Filter>Include\internal</Filter> + </ClInclude> + <ClInclude Include="..\Include\internal\pycore_uop_ids.h"> + <Filter>Include\internal</Filter> + </ClInclude> + <ClInclude Include="..\Include\internal\pycore_uop_metadata.h"> + <Filter>Include\internal</Filter> + </ClInclude> <ClInclude Include="..\Include\internal\mimalloc\mimalloc.h"> <Filter>Include\internal\mimalloc</Filter> </ClInclude> @@ -1055,6 +1073,9 @@ <ClCompile Include="..\Modules\main.c"> <Filter>Modules</Filter> </ClCompile> + <ClCompile Include="..\Modules\mathintegermodule.c"> + <Filter>Modules</Filter> + </ClCompile> <ClCompile Include="..\Modules\mathmodule.c"> <Filter>Modules</Filter> </ClCompile> @@ -1259,9 +1280,18 @@ <ClCompile Include="..\Objects\typeobject.c"> <Filter>Objects</Filter> </ClCompile> + <ClCompile Include="..\Objects\unicode_format.c"> + <Filter>Objects</Filter> + </ClCompile> <ClCompile Include="..\Objects\unicodectype.c"> <Filter>Objects</Filter> </ClCompile> + <ClCompile Include="..\Objects\unicode_formatter.c"> + <Filter>Objects</Filter> + </ClCompile> + <ClCompile Include="..\Objects\unicode_writer.c"> + <Filter>Objects</Filter> + </ClCompile> <ClCompile Include="..\Objects\unicodeobject.c"> <Filter>Objects</Filter> </ClCompile> @@ -1370,9 +1400,6 @@ <ClCompile Include="..\Python\flowgraph.c"> <Filter>Python</Filter> </ClCompile> - <ClCompile Include="..\Python\formatter_unicode.c"> - <Filter>Python</Filter> - </ClCompile> <ClCompile Include="..\Python\frozen.c"> <Filter>Python</Filter> </ClCompile> diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 27c0d382281..313982ed28a 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -6,7 +6,7 @@ Quick Start Guide 1a. Optionally install Python 3.10 or later. If not installed, get_externals.bat (via build.bat) will download and use Python via NuGet. -2. Run "build.bat" to build Python in 32-bit Release configuration. +2. Run "build.bat" to build Python in 64-bit Release configuration. 3. (Optional, but recommended) Run the test suite with "rt.bat -q". diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 57e46b4399c..50856686335 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -947,6 +947,35 @@ _PyPegen_check_legacy_stmt(Parser *p, expr_ty name) { return 0; } +void * +_PyPegen_raise_error_for_missing_comma(Parser *p, expr_ty a, expr_ty b) +{ + // Don't raise for legacy statements like "print x" or "exec x" + if (_PyPegen_check_legacy_stmt(p, a)) { + return NULL; + } + // Only raise inside parentheses/brackets (level > 0) + if (p->tokens[p->mark - 1]->level == 0) { + return NULL; + } + // For multi-line expressions (like string concatenations), point to the + // last line instead of the first for a more helpful error message. + // Use a->col_offset as the starting column since all strings in the + // concatenation typically share the same indentation. + if (a->end_lineno > a->lineno) { + return RAISE_ERROR_KNOWN_LOCATION( + p, PyExc_SyntaxError, a->end_lineno, a->col_offset, + a->end_lineno, a->end_col_offset, + "invalid syntax. Perhaps you forgot a comma?" + ); + } + return RAISE_ERROR_KNOWN_LOCATION( + p, PyExc_SyntaxError, a->lineno, a->col_offset, + b->end_lineno, b->end_col_offset, + "invalid syntax. Perhaps you forgot a comma?" + ); +} + static ResultTokenWithMetadata * result_token_with_metadata(Parser *p, void *result, PyObject *metadata) { @@ -1612,19 +1641,46 @@ _build_concatenated_bytes(Parser *p, asdl_expr_seq *strings, int lineno, Py_ssize_t len = asdl_seq_LEN(strings); assert(len > 0); - PyObject* res = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); - /* Bytes literals never get a kind, but just for consistency since they are represented as Constant nodes, we'll mirror the same behavior as unicode strings for determining the kind. */ - PyObject* kind = asdl_seq_GET(strings, 0)->v.Constant.kind; + PyObject *kind = asdl_seq_GET(strings, 0)->v.Constant.kind; + + Py_ssize_t total = 0; for (Py_ssize_t i = 0; i < len; i++) { expr_ty elem = asdl_seq_GET(strings, i); - PyBytes_Concat(&res, elem->v.Constant.value); + PyObject *bytes = elem->v.Constant.value; + Py_ssize_t part = PyBytes_GET_SIZE(bytes); + if (part > PY_SSIZE_T_MAX - total) { + PyErr_NoMemory(); + return NULL; + } + total += part; } - if (!res || _PyArena_AddPyObject(arena, res) < 0) { - Py_XDECREF(res); + + PyBytesWriter *writer = PyBytesWriter_Create(total); + if (writer == NULL) { + return NULL; + } + char *out = PyBytesWriter_GetData(writer); + + for (Py_ssize_t i = 0; i < len; i++) { + expr_ty elem = asdl_seq_GET(strings, i); + PyObject *bytes = elem->v.Constant.value; + Py_ssize_t part = PyBytes_GET_SIZE(bytes); + if (part > 0) { + memcpy(out, PyBytes_AS_STRING(bytes), part); + out += part; + } + } + + PyObject *res = PyBytesWriter_Finish(writer); + if (res == NULL) { + return NULL; + } + if (_PyArena_AddPyObject(arena, res) < 0) { + Py_DECREF(res); return NULL; } return _PyAST_Constant(res, kind, lineno, col_offset, end_lineno, end_col_offset, p->arena); diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index dba20226c32..3e252cbc488 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1009,7 +1009,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) else { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "Field '%U' is missing from %.400s._field_types. " + "Field %R is missing from %.400s._field_types. " "This will become an error in Python 3.15.", name, Py_TYPE(self)->tp_name ) < 0) { @@ -1044,7 +1044,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) // simple field (e.g., identifier) if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "%.400s.__init__ missing 1 required positional argument: '%U'. " + "%.400s.__init__ missing 1 required positional argument: %R. " "This will become an error in Python 3.15.", Py_TYPE(self)->tp_name, name ) < 0) { diff --git a/Parser/lexer/lexer.c b/Parser/lexer/lexer.c index 81363cf8e81..7f25afec302 100644 --- a/Parser/lexer/lexer.c +++ b/Parser/lexer/lexer.c @@ -539,6 +539,9 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t return MAKE_TOKEN(ERRORTOKEN); } } + else if (c == EOF && PyErr_Occurred()) { + return MAKE_TOKEN(ERRORTOKEN); + } else { break; } @@ -1376,7 +1379,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t return MAKE_TOKEN(_PyTokenizer_syntaxerror(tok, "invalid non-printable character U+%04X", c)); } - if( c == '=' && INSIDE_FSTRING_EXPR(current_tok)) { + if( c == '=' && INSIDE_FSTRING_EXPR_AT_TOP(current_tok)) { current_tok->in_debug = 1; } diff --git a/Parser/lexer/state.c b/Parser/lexer/state.c index 2de9004fe08..3663dc3eb7f 100644 --- a/Parser/lexer/state.c +++ b/Parser/lexer/state.c @@ -43,6 +43,7 @@ _PyTokenizer_tok_new(void) tok->encoding = NULL; tok->cont_line = 0; tok->filename = NULL; + tok->module = NULL; tok->decoding_readline = NULL; tok->decoding_buffer = NULL; tok->readline = NULL; @@ -91,6 +92,7 @@ _PyTokenizer_Free(struct tok_state *tok) Py_XDECREF(tok->decoding_buffer); Py_XDECREF(tok->readline); Py_XDECREF(tok->filename); + Py_XDECREF(tok->module); if ((tok->readline != NULL || tok->fp != NULL ) && tok->buf != NULL) { PyMem_Free(tok->buf); } diff --git a/Parser/lexer/state.h b/Parser/lexer/state.h index 5e8cac7249b..9cd196a114c 100644 --- a/Parser/lexer/state.h +++ b/Parser/lexer/state.h @@ -9,6 +9,8 @@ #define INSIDE_FSTRING(tok) (tok->tok_mode_stack_index > 0) #define INSIDE_FSTRING_EXPR(tok) (tok->curly_bracket_expr_start_depth >= 0) +#define INSIDE_FSTRING_EXPR_AT_TOP(tok) \ + (tok->curly_bracket_depth - tok->curly_bracket_expr_start_depth == 1) enum decoding_state { STATE_INIT, @@ -100,6 +102,7 @@ struct tok_state { int parenlinenostack[MAXLEVEL]; int parencolstack[MAXLEVEL]; PyObject *filename; + PyObject *module; /* Stuff for checking on different tab sizes */ int altindstack[MAXINDENT]; /* Stack of alternate indents */ /* Stuff for PEP 0263 */ diff --git a/Parser/parser.c b/Parser/parser.c index c20c368a089..09bfb5725a2 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -1,5 +1,6 @@ // @generated by pegen from python.gram #include "pegen.h" +#include "pycore_ceval.h" #if defined(Py_DEBUG) && defined(Py_BUILD_CORE) # define D(x) if (p->debug) { x; } @@ -21,28 +22,28 @@ static KeywordToken *reserved_keywords[] = { (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) { - {"if", 687}, - {"as", 685}, - {"in", 700}, + {"if", 691}, + {"as", 689}, + {"in", 704}, {"or", 589}, {"is", 597}, {NULL, -1}, }, (KeywordToken[]) { {"del", 630}, - {"def", 704}, - {"for", 699}, - {"try", 661}, + {"def", 708}, + {"for", 703}, + {"try", 665}, {"and", 590}, - {"not", 708}, + {"not", 712}, {NULL, -1}, }, (KeywordToken[]) { - {"from", 638}, + {"from", 642}, {"pass", 527}, - {"with", 652}, - {"elif", 692}, - {"else", 691}, + {"with", 656}, + {"elif", 696}, + {"else", 695}, {"None", 624}, {"True", 623}, {NULL, -1}, @@ -51,24 +52,24 @@ static KeywordToken *reserved_keywords[] = { {"raise", 628}, {"yield", 588}, {"break", 528}, - {"async", 703}, - {"class", 706}, - {"while", 694}, + {"async", 707}, + {"class", 710}, + {"while", 698}, {"False", 625}, {"await", 598}, {NULL, -1}, }, (KeywordToken[]) { {"return", 522}, - {"import", 639}, - {"assert", 533}, + {"import", 643}, + {"assert", 634}, {"global", 530}, - {"except", 682}, + {"except", 686}, {"lambda", 622}, {NULL, -1}, }, (KeywordToken[]) { - {"finally", 678}, + {"finally", 682}, {NULL, -1}, }, (KeywordToken[]) { @@ -300,235 +301,238 @@ static char *soft_keywords[] = { #define invalid_ann_assign_target_type 1213 #define invalid_raise_stmt_type 1214 #define invalid_del_stmt_type 1215 -#define invalid_block_type 1216 -#define invalid_comprehension_type 1217 -#define invalid_dict_comprehension_type 1218 -#define invalid_parameters_type 1219 -#define invalid_default_type 1220 -#define invalid_star_etc_type 1221 -#define invalid_kwds_type 1222 -#define invalid_parameters_helper_type 1223 -#define invalid_lambda_parameters_type 1224 -#define invalid_lambda_parameters_helper_type 1225 -#define invalid_lambda_star_etc_type 1226 -#define invalid_lambda_kwds_type 1227 -#define invalid_double_type_comments_type 1228 -#define invalid_with_item_type 1229 -#define invalid_for_if_clause_type 1230 -#define invalid_for_target_type 1231 -#define invalid_group_type 1232 -#define invalid_import_type 1233 -#define invalid_dotted_as_name_type 1234 -#define invalid_import_from_as_name_type 1235 -#define invalid_import_from_targets_type 1236 -#define invalid_with_stmt_type 1237 -#define invalid_with_stmt_indent_type 1238 -#define invalid_try_stmt_type 1239 -#define invalid_except_stmt_type 1240 -#define invalid_except_star_stmt_type 1241 -#define invalid_finally_stmt_type 1242 -#define invalid_except_stmt_indent_type 1243 -#define invalid_except_star_stmt_indent_type 1244 -#define invalid_match_stmt_type 1245 -#define invalid_case_block_type 1246 -#define invalid_as_pattern_type 1247 -#define invalid_class_pattern_type 1248 -#define invalid_class_argument_pattern_type 1249 -#define invalid_if_stmt_type 1250 -#define invalid_elif_stmt_type 1251 -#define invalid_else_stmt_type 1252 -#define invalid_while_stmt_type 1253 -#define invalid_for_stmt_type 1254 -#define invalid_def_raw_type 1255 -#define invalid_class_def_raw_type 1256 -#define invalid_double_starred_kvpairs_type 1257 -#define invalid_kvpair_type 1258 -#define invalid_starred_expression_unpacking_type 1259 -#define invalid_starred_expression_type 1260 -#define invalid_fstring_replacement_field_type 1261 -#define invalid_fstring_conversion_character_type 1262 -#define invalid_tstring_replacement_field_type 1263 -#define invalid_tstring_conversion_character_type 1264 -#define invalid_string_tstring_concat_type 1265 -#define invalid_arithmetic_type 1266 -#define invalid_factor_type 1267 -#define invalid_type_params_type 1268 -#define _loop0_1_type 1269 -#define _loop1_2_type 1270 -#define _loop0_3_type 1271 -#define _gather_4_type 1272 -#define _tmp_5_type 1273 -#define _tmp_6_type 1274 -#define _tmp_7_type 1275 -#define _tmp_8_type 1276 -#define _tmp_9_type 1277 -#define _tmp_10_type 1278 -#define _tmp_11_type 1279 -#define _loop1_12_type 1280 -#define _loop0_13_type 1281 -#define _gather_14_type 1282 -#define _tmp_15_type 1283 -#define _tmp_16_type 1284 -#define _loop0_17_type 1285 -#define _loop1_18_type 1286 -#define _loop0_19_type 1287 -#define _gather_20_type 1288 -#define _tmp_21_type 1289 -#define _loop0_22_type 1290 -#define _gather_23_type 1291 -#define _loop1_24_type 1292 -#define _tmp_25_type 1293 -#define _tmp_26_type 1294 -#define _loop0_27_type 1295 -#define _loop0_28_type 1296 -#define _loop1_29_type 1297 -#define _loop1_30_type 1298 -#define _loop0_31_type 1299 -#define _loop1_32_type 1300 -#define _loop0_33_type 1301 -#define _gather_34_type 1302 -#define _tmp_35_type 1303 -#define _loop1_36_type 1304 -#define _loop1_37_type 1305 -#define _loop1_38_type 1306 -#define _loop0_39_type 1307 -#define _gather_40_type 1308 -#define _tmp_41_type 1309 -#define _tmp_42_type 1310 -#define _tmp_43_type 1311 -#define _loop0_44_type 1312 -#define _gather_45_type 1313 -#define _loop0_46_type 1314 -#define _gather_47_type 1315 -#define _tmp_48_type 1316 -#define _loop0_49_type 1317 -#define _gather_50_type 1318 -#define _loop0_51_type 1319 -#define _gather_52_type 1320 -#define _loop0_53_type 1321 -#define _gather_54_type 1322 -#define _loop1_55_type 1323 -#define _loop1_56_type 1324 -#define _loop0_57_type 1325 -#define _gather_58_type 1326 -#define _loop1_59_type 1327 -#define _loop1_60_type 1328 -#define _loop1_61_type 1329 -#define _tmp_62_type 1330 -#define _loop0_63_type 1331 -#define _gather_64_type 1332 -#define _tmp_65_type 1333 -#define _tmp_66_type 1334 -#define _tmp_67_type 1335 -#define _tmp_68_type 1336 -#define _tmp_69_type 1337 -#define _loop0_70_type 1338 -#define _loop0_71_type 1339 -#define _loop1_72_type 1340 -#define _loop1_73_type 1341 -#define _loop0_74_type 1342 -#define _loop1_75_type 1343 -#define _loop0_76_type 1344 -#define _loop0_77_type 1345 -#define _loop0_78_type 1346 -#define _loop0_79_type 1347 -#define _loop1_80_type 1348 -#define _loop1_81_type 1349 -#define _tmp_82_type 1350 -#define _loop0_83_type 1351 -#define _gather_84_type 1352 -#define _loop1_85_type 1353 -#define _loop0_86_type 1354 -#define _tmp_87_type 1355 -#define _loop0_88_type 1356 -#define _gather_89_type 1357 -#define _tmp_90_type 1358 -#define _loop0_91_type 1359 -#define _gather_92_type 1360 -#define _loop0_93_type 1361 -#define _gather_94_type 1362 -#define _loop0_95_type 1363 -#define _loop0_96_type 1364 -#define _gather_97_type 1365 -#define _loop1_98_type 1366 -#define _tmp_99_type 1367 -#define _loop0_100_type 1368 -#define _gather_101_type 1369 -#define _loop0_102_type 1370 -#define _gather_103_type 1371 -#define _tmp_104_type 1372 -#define _tmp_105_type 1373 -#define _loop0_106_type 1374 -#define _gather_107_type 1375 -#define _tmp_108_type 1376 -#define _tmp_109_type 1377 -#define _tmp_110_type 1378 -#define _tmp_111_type 1379 -#define _tmp_112_type 1380 -#define _loop1_113_type 1381 -#define _tmp_114_type 1382 -#define _tmp_115_type 1383 -#define _tmp_116_type 1384 -#define _tmp_117_type 1385 -#define _tmp_118_type 1386 -#define _loop0_119_type 1387 -#define _loop0_120_type 1388 -#define _tmp_121_type 1389 -#define _tmp_122_type 1390 -#define _tmp_123_type 1391 -#define _tmp_124_type 1392 -#define _tmp_125_type 1393 -#define _tmp_126_type 1394 -#define _tmp_127_type 1395 -#define _tmp_128_type 1396 -#define _tmp_129_type 1397 -#define _loop0_130_type 1398 -#define _gather_131_type 1399 -#define _tmp_132_type 1400 -#define _tmp_133_type 1401 -#define _tmp_134_type 1402 -#define _tmp_135_type 1403 -#define _loop0_136_type 1404 -#define _gather_137_type 1405 -#define _tmp_138_type 1406 -#define _loop0_139_type 1407 -#define _gather_140_type 1408 -#define _loop0_141_type 1409 -#define _gather_142_type 1410 -#define _tmp_143_type 1411 -#define _loop0_144_type 1412 -#define _tmp_145_type 1413 -#define _tmp_146_type 1414 -#define _tmp_147_type 1415 -#define _tmp_148_type 1416 -#define _tmp_149_type 1417 -#define _tmp_150_type 1418 -#define _tmp_151_type 1419 -#define _tmp_152_type 1420 -#define _tmp_153_type 1421 -#define _tmp_154_type 1422 -#define _tmp_155_type 1423 -#define _tmp_156_type 1424 -#define _tmp_157_type 1425 -#define _tmp_158_type 1426 -#define _tmp_159_type 1427 -#define _tmp_160_type 1428 -#define _tmp_161_type 1429 -#define _tmp_162_type 1430 -#define _tmp_163_type 1431 -#define _tmp_164_type 1432 -#define _tmp_165_type 1433 -#define _tmp_166_type 1434 -#define _tmp_167_type 1435 -#define _tmp_168_type 1436 -#define _tmp_169_type 1437 -#define _tmp_170_type 1438 -#define _loop0_171_type 1439 -#define _tmp_172_type 1440 -#define _tmp_173_type 1441 -#define _tmp_174_type 1442 -#define _tmp_175_type 1443 -#define _tmp_176_type 1444 +#define invalid_assert_stmt_type 1216 +#define invalid_block_type 1217 +#define invalid_comprehension_type 1218 +#define invalid_dict_comprehension_type 1219 +#define invalid_parameters_type 1220 +#define invalid_default_type 1221 +#define invalid_star_etc_type 1222 +#define invalid_kwds_type 1223 +#define invalid_parameters_helper_type 1224 +#define invalid_lambda_parameters_type 1225 +#define invalid_lambda_parameters_helper_type 1226 +#define invalid_lambda_star_etc_type 1227 +#define invalid_lambda_kwds_type 1228 +#define invalid_double_type_comments_type 1229 +#define invalid_with_item_type 1230 +#define invalid_for_if_clause_type 1231 +#define invalid_for_target_type 1232 +#define invalid_group_type 1233 +#define invalid_import_type 1234 +#define invalid_dotted_as_name_type 1235 +#define invalid_import_from_as_name_type 1236 +#define invalid_import_from_targets_type 1237 +#define invalid_with_stmt_type 1238 +#define invalid_with_stmt_indent_type 1239 +#define invalid_try_stmt_type 1240 +#define invalid_except_stmt_type 1241 +#define invalid_except_star_stmt_type 1242 +#define invalid_finally_stmt_type 1243 +#define invalid_except_stmt_indent_type 1244 +#define invalid_except_star_stmt_indent_type 1245 +#define invalid_match_stmt_type 1246 +#define invalid_case_block_type 1247 +#define invalid_as_pattern_type 1248 +#define invalid_class_pattern_type 1249 +#define invalid_mapping_pattern_type 1250 +#define invalid_class_argument_pattern_type 1251 +#define invalid_if_stmt_type 1252 +#define invalid_elif_stmt_type 1253 +#define invalid_else_stmt_type 1254 +#define invalid_while_stmt_type 1255 +#define invalid_for_stmt_type 1256 +#define invalid_def_raw_type 1257 +#define invalid_class_def_raw_type 1258 +#define invalid_double_starred_kvpairs_type 1259 +#define invalid_kvpair_type 1260 +#define invalid_starred_expression_unpacking_type 1261 +#define invalid_starred_expression_type 1262 +#define invalid_fstring_replacement_field_type 1263 +#define invalid_fstring_conversion_character_type 1264 +#define invalid_tstring_replacement_field_type 1265 +#define invalid_tstring_conversion_character_type 1266 +#define invalid_string_tstring_concat_type 1267 +#define invalid_arithmetic_type 1268 +#define invalid_factor_type 1269 +#define invalid_type_params_type 1270 +#define _loop0_1_type 1271 +#define _loop1_2_type 1272 +#define _loop0_3_type 1273 +#define _gather_4_type 1274 +#define _tmp_5_type 1275 +#define _tmp_6_type 1276 +#define _tmp_7_type 1277 +#define _tmp_8_type 1278 +#define _tmp_9_type 1279 +#define _tmp_10_type 1280 +#define _tmp_11_type 1281 +#define _loop1_12_type 1282 +#define _loop0_13_type 1283 +#define _gather_14_type 1284 +#define _tmp_15_type 1285 +#define _tmp_16_type 1286 +#define _loop0_17_type 1287 +#define _loop1_18_type 1288 +#define _loop0_19_type 1289 +#define _gather_20_type 1290 +#define _tmp_21_type 1291 +#define _loop0_22_type 1292 +#define _gather_23_type 1293 +#define _loop1_24_type 1294 +#define _tmp_25_type 1295 +#define _tmp_26_type 1296 +#define _loop0_27_type 1297 +#define _loop0_28_type 1298 +#define _loop1_29_type 1299 +#define _loop1_30_type 1300 +#define _loop0_31_type 1301 +#define _loop1_32_type 1302 +#define _loop0_33_type 1303 +#define _gather_34_type 1304 +#define _tmp_35_type 1305 +#define _loop1_36_type 1306 +#define _loop1_37_type 1307 +#define _loop1_38_type 1308 +#define _loop0_39_type 1309 +#define _gather_40_type 1310 +#define _tmp_41_type 1311 +#define _tmp_42_type 1312 +#define _tmp_43_type 1313 +#define _loop0_44_type 1314 +#define _gather_45_type 1315 +#define _loop0_46_type 1316 +#define _gather_47_type 1317 +#define _tmp_48_type 1318 +#define _loop0_49_type 1319 +#define _gather_50_type 1320 +#define _loop0_51_type 1321 +#define _gather_52_type 1322 +#define _loop0_53_type 1323 +#define _gather_54_type 1324 +#define _loop1_55_type 1325 +#define _loop1_56_type 1326 +#define _loop0_57_type 1327 +#define _gather_58_type 1328 +#define _loop1_59_type 1329 +#define _loop1_60_type 1330 +#define _loop1_61_type 1331 +#define _tmp_62_type 1332 +#define _loop0_63_type 1333 +#define _gather_64_type 1334 +#define _tmp_65_type 1335 +#define _tmp_66_type 1336 +#define _tmp_67_type 1337 +#define _tmp_68_type 1338 +#define _tmp_69_type 1339 +#define _loop0_70_type 1340 +#define _loop0_71_type 1341 +#define _loop1_72_type 1342 +#define _loop1_73_type 1343 +#define _loop0_74_type 1344 +#define _loop1_75_type 1345 +#define _loop0_76_type 1346 +#define _loop0_77_type 1347 +#define _loop0_78_type 1348 +#define _loop0_79_type 1349 +#define _loop1_80_type 1350 +#define _loop1_81_type 1351 +#define _tmp_82_type 1352 +#define _loop0_83_type 1353 +#define _gather_84_type 1354 +#define _loop1_85_type 1355 +#define _loop0_86_type 1356 +#define _tmp_87_type 1357 +#define _loop0_88_type 1358 +#define _gather_89_type 1359 +#define _tmp_90_type 1360 +#define _loop0_91_type 1361 +#define _gather_92_type 1362 +#define _loop0_93_type 1363 +#define _gather_94_type 1364 +#define _loop0_95_type 1365 +#define _loop0_96_type 1366 +#define _gather_97_type 1367 +#define _loop1_98_type 1368 +#define _tmp_99_type 1369 +#define _loop0_100_type 1370 +#define _gather_101_type 1371 +#define _loop0_102_type 1372 +#define _gather_103_type 1373 +#define _tmp_104_type 1374 +#define _tmp_105_type 1375 +#define _loop0_106_type 1376 +#define _gather_107_type 1377 +#define _tmp_108_type 1378 +#define _tmp_109_type 1379 +#define _tmp_110_type 1380 +#define _tmp_111_type 1381 +#define _tmp_112_type 1382 +#define _loop1_113_type 1383 +#define _tmp_114_type 1384 +#define _tmp_115_type 1385 +#define _tmp_116_type 1386 +#define _tmp_117_type 1387 +#define _tmp_118_type 1388 +#define _loop0_119_type 1389 +#define _loop0_120_type 1390 +#define _tmp_121_type 1391 +#define _tmp_122_type 1392 +#define _tmp_123_type 1393 +#define _tmp_124_type 1394 +#define _tmp_125_type 1395 +#define _tmp_126_type 1396 +#define _tmp_127_type 1397 +#define _tmp_128_type 1398 +#define _tmp_129_type 1399 +#define _loop0_130_type 1400 +#define _gather_131_type 1401 +#define _tmp_132_type 1402 +#define _tmp_133_type 1403 +#define _tmp_134_type 1404 +#define _tmp_135_type 1405 +#define _loop0_136_type 1406 +#define _gather_137_type 1407 +#define _tmp_138_type 1408 +#define _loop0_139_type 1409 +#define _gather_140_type 1410 +#define _loop0_141_type 1411 +#define _gather_142_type 1412 +#define _tmp_143_type 1413 +#define _loop0_144_type 1414 +#define _tmp_145_type 1415 +#define _tmp_146_type 1416 +#define _tmp_147_type 1417 +#define _tmp_148_type 1418 +#define _tmp_149_type 1419 +#define _tmp_150_type 1420 +#define _tmp_151_type 1421 +#define _tmp_152_type 1422 +#define _tmp_153_type 1423 +#define _tmp_154_type 1424 +#define _tmp_155_type 1425 +#define _tmp_156_type 1426 +#define _tmp_157_type 1427 +#define _tmp_158_type 1428 +#define _tmp_159_type 1429 +#define _tmp_160_type 1430 +#define _tmp_161_type 1431 +#define _tmp_162_type 1432 +#define _tmp_163_type 1433 +#define _tmp_164_type 1434 +#define _tmp_165_type 1435 +#define _tmp_166_type 1436 +#define _tmp_167_type 1437 +#define _tmp_168_type 1438 +#define _tmp_169_type 1439 +#define _tmp_170_type 1440 +#define _tmp_171_type 1441 +#define _loop0_172_type 1442 +#define _tmp_173_type 1443 +#define _tmp_174_type 1444 +#define _tmp_175_type 1445 +#define _tmp_176_type 1446 +#define _tmp_177_type 1447 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -746,6 +750,7 @@ static void *invalid_assignment_rule(Parser *p); static expr_ty invalid_ann_assign_target_rule(Parser *p); static void *invalid_raise_stmt_rule(Parser *p); static void *invalid_del_stmt_rule(Parser *p); +static void *invalid_assert_stmt_rule(Parser *p); static void *invalid_block_rule(Parser *p); static void *invalid_comprehension_rule(Parser *p); static void *invalid_dict_comprehension_rule(Parser *p); @@ -779,6 +784,7 @@ static void *invalid_match_stmt_rule(Parser *p); static void *invalid_case_block_rule(Parser *p); static void *invalid_as_pattern_rule(Parser *p); static void *invalid_class_pattern_rule(Parser *p); +static void *invalid_mapping_pattern_rule(Parser *p); static asdl_pattern_seq* invalid_class_argument_pattern_rule(Parser *p); static void *invalid_if_stmt_rule(Parser *p); static void *invalid_elif_stmt_rule(Parser *p); @@ -969,12 +975,13 @@ static void *_tmp_167_rule(Parser *p); static void *_tmp_168_rule(Parser *p); static void *_tmp_169_rule(Parser *p); static void *_tmp_170_rule(Parser *p); -static asdl_seq *_loop0_171_rule(Parser *p); -static void *_tmp_172_rule(Parser *p); +static void *_tmp_171_rule(Parser *p); +static asdl_seq *_loop0_172_rule(Parser *p); static void *_tmp_173_rule(Parser *p); static void *_tmp_174_rule(Parser *p); static void *_tmp_175_rule(Parser *p); static void *_tmp_176_rule(Parser *p); +static void *_tmp_177_rule(Parser *p); // file: statements? $ @@ -1786,7 +1793,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'assert' assert_stmt")); stmt_ty assert_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 533) // token='assert' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 634) // token='assert' && (assert_stmt_var = assert_stmt_rule(p)) // assert_stmt ) @@ -1940,7 +1947,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'if' if_stmt")); stmt_ty if_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 687) // token='if' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 691) // token='if' && (if_stmt_var = if_stmt_rule(p)) // if_stmt ) @@ -2024,7 +2031,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'try' try_stmt")); stmt_ty try_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 661) // token='try' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 665) // token='try' && (try_stmt_var = try_stmt_rule(p)) // try_stmt ) @@ -2045,7 +2052,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'while' while_stmt")); stmt_ty while_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 694) // token='while' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 698) // token='while' && (while_stmt_var = while_stmt_rule(p)) // while_stmt ) @@ -2812,7 +2819,7 @@ raise_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 638)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 642)) // token='from' && (b = expression_rule(p)) // expression ) @@ -3390,7 +3397,7 @@ yield_stmt_rule(Parser *p) return _res; } -// assert_stmt: 'assert' expression [',' expression] +// assert_stmt: invalid_assert_stmt | 'assert' expression [',' expression] static stmt_ty assert_stmt_rule(Parser *p) { @@ -3412,6 +3419,25 @@ assert_stmt_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro + if (p->call_invalid_rules) { // invalid_assert_stmt + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> assert_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_assert_stmt")); + void *invalid_assert_stmt_var; + if ( + (invalid_assert_stmt_var = invalid_assert_stmt_rule(p)) // invalid_assert_stmt + ) + { + D(fprintf(stderr, "%*c+ assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_assert_stmt")); + _res = invalid_assert_stmt_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s assert_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_assert_stmt")); + } { // 'assert' expression [',' expression] if (p->error_indicator) { p->level--; @@ -3422,7 +3448,7 @@ assert_stmt_rule(Parser *p) expr_ty a; void *b; if ( - (_keyword = _PyPegen_expect_token(p, 533)) // token='assert' + (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' && (a = expression_rule(p)) // expression && @@ -3564,7 +3590,7 @@ import_name_rule(Parser *p) Token * _keyword; asdl_alias_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='import' + (_keyword = _PyPegen_expect_token(p, 643)) // token='import' && (a = dotted_as_names_rule(p)) // dotted_as_names ) @@ -3633,13 +3659,13 @@ import_from_rule(Parser *p) expr_ty b; asdl_alias_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 638)) // token='from' + (_keyword = _PyPegen_expect_token(p, 642)) // token='from' && (a = _loop0_17_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && - (_keyword_1 = _PyPegen_expect_token(p, 639)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 643)) // token='import' && (c = import_from_targets_rule(p)) // import_from_targets ) @@ -3677,11 +3703,11 @@ import_from_rule(Parser *p) asdl_seq * a; asdl_alias_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 638)) // token='from' + (_keyword = _PyPegen_expect_token(p, 642)) // token='from' && (a = _loop1_18_rule(p)) // (('.' | '...'))+ && - (_keyword_1 = _PyPegen_expect_token(p, 639)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 643)) // token='import' && (b = import_from_targets_rule(p)) // import_from_targets ) @@ -4468,7 +4494,7 @@ class_def_raw_rule(Parser *p) asdl_stmt_seq* c; void *t; if ( - (_keyword = _PyPegen_expect_token(p, 706)) // token='class' + (_keyword = _PyPegen_expect_token(p, 710)) // token='class' && (a = _PyPegen_name_token(p)) // NAME && @@ -4635,7 +4661,7 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 704)) // token='def' + (_keyword = _PyPegen_expect_token(p, 708)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -4696,9 +4722,9 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='def' + (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -6036,7 +6062,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6081,7 +6107,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6176,7 +6202,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 692)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 696)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6221,7 +6247,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 692)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 696)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6302,7 +6328,7 @@ else_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword = _PyPegen_expect_token(p, 695)) // token='else' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -6381,7 +6407,7 @@ while_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 694)) // token='while' + (_keyword = _PyPegen_expect_token(p, 698)) // token='while' && (a = named_expression_rule(p)) // named_expression && @@ -6481,11 +6507,11 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword = _PyPegen_expect_token(p, 703)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' && (_cut_var = 1) && @@ -6543,13 +6569,13 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 703)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 704)) // token='in' && (_cut_var = 1) && @@ -6678,7 +6704,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword = _PyPegen_expect_token(p, 656)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6729,7 +6755,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword = _PyPegen_expect_token(p, 656)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6778,9 +6804,9 @@ with_stmt_rule(Parser *p) asdl_withitem_seq* a; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 656)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6830,9 +6856,9 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 656)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6918,7 +6944,7 @@ with_item_rule(Parser *p) if ( (e = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (t = star_target_rule(p)) // star_target && @@ -7043,7 +7069,7 @@ try_stmt_rule(Parser *p) asdl_stmt_seq* b; asdl_stmt_seq* f; if ( - (_keyword = _PyPegen_expect_token(p, 661)) // token='try' + (_keyword = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7087,7 +7113,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 661)) // token='try' + (_keyword = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7135,7 +7161,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 661)) // token='try' + (_keyword = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7234,7 +7260,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (e = expression_rule(p)) // expression && @@ -7278,11 +7304,11 @@ except_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7324,7 +7350,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (e = expressions_rule(p)) // expressions && @@ -7365,7 +7391,7 @@ except_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7477,7 +7503,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7524,13 +7550,13 @@ except_star_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7573,7 +7599,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7673,7 +7699,7 @@ finally_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 678)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 682)) // token='finally' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7981,7 +8007,7 @@ guard_rule(Parser *p) Token * _keyword; expr_ty guard; if ( - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (guard = named_expression_rule(p)) // named_expression ) @@ -8176,7 +8202,7 @@ as_pattern_rule(Parser *p) if ( (pattern = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (target = pattern_capture_target_rule(p)) // pattern_capture_target ) @@ -10072,6 +10098,7 @@ star_pattern_rule(Parser *p) // | '{' double_star_pattern ','? '}' // | '{' items_pattern ',' double_star_pattern ','? '}' // | '{' items_pattern ','? '}' +// | invalid_mapping_pattern static pattern_ty mapping_pattern_rule(Parser *p) { @@ -10264,6 +10291,25 @@ mapping_pattern_rule(Parser *p) D(fprintf(stderr, "%*c%s mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' items_pattern ','? '}'")); } + if (p->call_invalid_rules) { // invalid_mapping_pattern + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_mapping_pattern")); + void *invalid_mapping_pattern_var; + if ( + (invalid_mapping_pattern_var = invalid_mapping_pattern_rule(p)) // invalid_mapping_pattern + ) + { + D(fprintf(stderr, "%*c+ mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_mapping_pattern")); + _res = invalid_mapping_pattern_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_mapping_pattern")); + } _res = NULL; done: p->level--; @@ -11473,11 +11519,11 @@ expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' && (c = expression_rule(p)) // expression ) @@ -11583,7 +11629,7 @@ yield_expr_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 588)) // token='yield' && - (_keyword_1 = _PyPegen_expect_token(p, 638)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 642)) // token='from' && (a = expression_rule(p)) // expression ) @@ -12359,7 +12405,7 @@ inversion_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 708)) // token='not' + (_keyword = _PyPegen_expect_token(p, 712)) // token='not' && (a = inversion_rule(p)) // inversion ) @@ -13013,9 +13059,9 @@ notin_bitwise_or_rule(Parser *p) Token * _keyword_1; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 708)) // token='not' + (_keyword = _PyPegen_expect_token(p, 712)) // token='not' && - (_keyword_1 = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13061,7 +13107,7 @@ in_bitwise_or_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword = _PyPegen_expect_token(p, 704)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13110,7 +13156,7 @@ isnot_bitwise_or_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 597)) // token='is' && - (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='not' + (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='not' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -17769,13 +17815,13 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 703)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 704)) // token='in' && (_cut_var = 1) && @@ -17814,11 +17860,11 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword = _PyPegen_expect_token(p, 703)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' && (_cut_var = 1) && @@ -21119,11 +21165,11 @@ expression_without_invalid_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' && (c = expression_rule(p)) // expression ) @@ -21399,7 +21445,7 @@ invalid_expression_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(NAME STRING | SOFT_KEYWORD) disjunction expression_without_invalid")); - _res = _PyPegen_check_legacy_stmt ( p , a ) ? NULL : p -> tokens [p -> mark - 1] -> level == 0 ? NULL : RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "invalid syntax. Perhaps you forgot a comma?" ); + _res = _PyPegen_raise_error_for_missing_comma ( p , a , b ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -21423,7 +21469,7 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (b = disjunction_rule(p)) // disjunction && @@ -21456,11 +21502,11 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' && _PyPegen_lookahead_for_expr(0, expression_rule, p) ) @@ -21492,11 +21538,11 @@ invalid_expression_rule(Parser *p) if ( (a = (stmt_ty)_tmp_116_rule(p)) // pass_stmt | break_stmt | continue_stmt && - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' && (c = simple_stmt_rule(p)) // simple_stmt ) @@ -22031,7 +22077,7 @@ invalid_raise_stmt_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 628)) // token='raise' && - (b = _PyPegen_expect_token(p, 638)) // token='from' + (b = _PyPegen_expect_token(p, 642)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' 'from'")); @@ -22061,7 +22107,7 @@ invalid_raise_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (a = _PyPegen_expect_token(p, 638)) // token='from' + (a = _PyPegen_expect_token(p, 642)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression 'from'")); @@ -22129,6 +22175,173 @@ invalid_del_stmt_rule(Parser *p) return _res; } +// invalid_assert_stmt: +// | 'assert' expression '=' expression +// | 'assert' expression ',' expression '=' expression +// | 'assert' expression ':=' expression +// | 'assert' expression ',' expression ':=' expression +static void * +invalid_assert_stmt_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // 'assert' expression '=' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_assert_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'assert' expression '=' expression")); + Token * _keyword; + Token * _literal; + expr_ty a; + expr_ty b; + if ( + (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + && + (a = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + && + (b = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ invalid_assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression '=' expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot assign to %s here. Maybe you meant '==' instead of '='?" , _PyPegen_get_expr_name ( a ) ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_assert_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'assert' expression '=' expression")); + } + { // 'assert' expression ',' expression '=' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_assert_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'assert' expression ',' expression '=' expression")); + Token * _keyword; + Token * _literal; + Token * _literal_1; + expr_ty a; + expr_ty b; + expr_ty expression_var; + if ( + (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + && + (expression_var = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (a = expression_rule(p)) // expression + && + (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' + && + (b = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ invalid_assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression ',' expression '=' expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot assign to %s here. Maybe you meant '==' instead of '='?" , _PyPegen_get_expr_name ( a ) ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_assert_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'assert' expression ',' expression '=' expression")); + } + { // 'assert' expression ':=' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_assert_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'assert' expression ':=' expression")); + Token * _keyword; + Token * _literal; + expr_ty a; + expr_ty b; + if ( + (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + && + (a = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 53)) // token=':=' + && + (b = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ invalid_assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression ':=' expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use named expression without parentheses here" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_assert_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'assert' expression ':=' expression")); + } + { // 'assert' expression ',' expression ':=' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_assert_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'assert' expression ',' expression ':=' expression")); + Token * _keyword; + Token * _literal; + Token * _literal_1; + expr_ty a; + expr_ty b; + expr_ty expression_var; + if ( + (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + && + (expression_var = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (a = expression_rule(p)) // expression + && + (_literal_1 = _PyPegen_expect_token(p, 53)) // token=':=' + && + (b = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ invalid_assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression ',' expression ':=' expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use named expression without parentheses here" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_assert_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'assert' expression ',' expression ':=' expression")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_block: NEWLINE !INDENT static void * invalid_block_rule(Parser *p) @@ -23541,7 +23754,7 @@ invalid_with_item_rule(Parser *p) if ( (expression_var = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (a = expression_rule(p)) // expression && @@ -23591,13 +23804,13 @@ invalid_for_if_clause_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_tmp_135_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword = _PyPegen_expect_token(p, 703)) // token='for' && (_tmp_135_var = _tmp_135_rule(p)) // bitwise_or ((',' bitwise_or))* ','? && - _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 700) // token='in' + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 704) // token='in' ) { D(fprintf(stderr, "%*c+ invalid_for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'? 'for' (bitwise_or ((',' bitwise_or))* ','?) !'in'")); @@ -23643,9 +23856,9 @@ invalid_for_target_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings expr_ty a; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword = _PyPegen_expect_token(p, 703)) // token='for' && (a = star_expressions_rule(p)) // star_expressions ) @@ -23775,11 +23988,11 @@ invalid_import_rule(Parser *p) Token * a; expr_ty dotted_name_var; if ( - (a = _PyPegen_expect_token(p, 639)) // token='import' + (a = _PyPegen_expect_token(p, 643)) // token='import' && (_gather_137_var = _gather_137_rule(p)) // ','.dotted_name+ && - (_keyword = _PyPegen_expect_token(p, 638)) // token='from' + (_keyword = _PyPegen_expect_token(p, 642)) // token='from' && (dotted_name_var = dotted_name_rule(p)) // dotted_name ) @@ -23806,7 +24019,7 @@ invalid_import_rule(Parser *p) Token * _keyword; Token * token; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='import' + (_keyword = _PyPegen_expect_token(p, 643)) // token='import' && (token = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23830,7 +24043,7 @@ invalid_import_rule(Parser *p) return _res; } -// invalid_dotted_as_name: dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression +// invalid_dotted_as_name: dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression static void * invalid_dotted_as_name_rule(Parser *p) { @@ -23843,26 +24056,26 @@ invalid_dotted_as_name_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression + { // dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_dotted_as_name[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression")); + D(fprintf(stderr, "%*c> invalid_dotted_as_name[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression")); Token * _keyword; expr_ty a; expr_ty dotted_name_var; if ( (dotted_name_var = dotted_name_rule(p)) // dotted_name && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && _PyPegen_lookahead(0, _tmp_138_rule, p) && (a = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ invalid_dotted_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression")); + D(fprintf(stderr, "%*c+ invalid_dotted_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression")); _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use %s as import target" , _PyPegen_get_expr_name ( a ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -23873,7 +24086,7 @@ invalid_dotted_as_name_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_dotted_as_name[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | NEWLINE)) expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression")); } _res = NULL; done: @@ -23881,7 +24094,7 @@ invalid_dotted_as_name_rule(Parser *p) return _res; } -// invalid_import_from_as_name: NAME 'as' !(NAME (',' | ')' | NEWLINE)) expression +// invalid_import_from_as_name: NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression static void * invalid_import_from_as_name_rule(Parser *p) { @@ -23894,26 +24107,26 @@ invalid_import_from_as_name_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // NAME 'as' !(NAME (',' | ')' | NEWLINE)) expression + { // NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_import_from_as_name[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | NEWLINE)) expression")); + D(fprintf(stderr, "%*c> invalid_import_from_as_name[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression")); Token * _keyword; expr_ty a; expr_ty name_var; if ( (name_var = _PyPegen_name_token(p)) // NAME && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && _PyPegen_lookahead(0, _tmp_138_rule, p) && (a = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ invalid_import_from_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | NEWLINE)) expression")); + D(fprintf(stderr, "%*c+ invalid_import_from_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression")); _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use %s as import target" , _PyPegen_get_expr_name ( a ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -23924,7 +24137,7 @@ invalid_import_from_as_name_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_import_from_as_name[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | NEWLINE)) expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME 'as' !(NAME (',' | ')' | ';' | NEWLINE)) expression")); } _res = NULL; done: @@ -24032,9 +24245,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword = _PyPegen_expect_token(p, 656)) // token='with' && (_gather_140_var = _gather_140_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24070,9 +24283,9 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var_1); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword = _PyPegen_expect_token(p, 656)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -24132,9 +24345,9 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 652)) // token='with' + (a = _PyPegen_expect_token(p, 656)) // token='with' && (_gather_140_var = _gather_140_rule(p)) // ','.(expression ['as' star_target])+ && @@ -24175,9 +24388,9 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 652)) // token='with' + (a = _PyPegen_expect_token(p, 656)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -24240,7 +24453,7 @@ invalid_try_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 661)) // token='try' + (a = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24272,7 +24485,7 @@ invalid_try_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 661)) // token='try' + (_keyword = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24311,7 +24524,7 @@ invalid_try_stmt_rule(Parser *p) Token * b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 661)) // token='try' + (_keyword = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24319,7 +24532,7 @@ invalid_try_stmt_rule(Parser *p) && (_loop1_36_var = _loop1_36_rule(p)) // except_block+ && - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (b = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24358,7 +24571,7 @@ invalid_try_stmt_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings Token * a; if ( - (_keyword = _PyPegen_expect_token(p, 661)) // token='try' + (_keyword = _PyPegen_expect_token(p, 665)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24366,7 +24579,7 @@ invalid_try_stmt_rule(Parser *p) && (_loop1_37_var = _loop1_37_rule(p)) // except_star_block+ && - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (_opt_var = _tmp_145_rule(p), !p->error_indicator) // [expression ['as' NAME]] && @@ -24423,7 +24636,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (a = expression_rule(p)) // expression && @@ -24431,7 +24644,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -24463,7 +24676,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -24494,7 +24707,7 @@ invalid_except_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24525,11 +24738,11 @@ invalid_except_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' && (a = expression_rule(p)) // expression && @@ -24589,7 +24802,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24599,7 +24812,7 @@ invalid_except_star_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -24632,7 +24845,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24666,7 +24879,7 @@ invalid_except_star_stmt_rule(Parser *p) void *_tmp_146_var; Token * a; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24700,13 +24913,13 @@ invalid_except_star_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' && (a = expression_rule(p)) // expression && @@ -24757,7 +24970,7 @@ invalid_finally_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 678)) // token='finally' + (a = _PyPegen_expect_token(p, 682)) // token='finally' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24813,7 +25026,7 @@ invalid_except_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -24849,7 +25062,7 @@ invalid_except_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24905,7 +25118,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='except' + (a = _PyPegen_expect_token(p, 686)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24942,6 +25155,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) // invalid_match_stmt: // | "match" subject_expr NEWLINE // | "match" subject_expr ':' NEWLINE !INDENT +// | "case" patterns guard? ':' block static void * invalid_match_stmt_rule(Parser *p) { @@ -25019,6 +25233,43 @@ invalid_match_stmt_rule(Parser *p) D(fprintf(stderr, "%*c%s invalid_match_stmt[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\"match\" subject_expr ':' NEWLINE !INDENT")); } + { // "case" patterns guard? ':' block + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_match_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "\"case\" patterns guard? ':' block")); + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + expr_ty a; + Token * b; + asdl_stmt_seq* block_var; + pattern_ty patterns_var; + if ( + (a = _PyPegen_expect_soft_keyword(p, "case")) // soft_keyword='"case"' + && + (patterns_var = patterns_rule(p)) // patterns + && + (_opt_var = guard_rule(p), !p->error_indicator) // guard? + && + (b = _PyPegen_expect_token(p, 11)) // token=':' + && + (block_var = block_rule(p)) // block + ) + { + D(fprintf(stderr, "%*c+ invalid_match_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "\"case\" patterns guard? ':' block")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "case statement must be inside match statement" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_match_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\"case\" patterns guard? ':' block")); + } _res = NULL; done: p->level--; @@ -25144,7 +25395,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (a = _PyPegen_expect_soft_keyword(p, "_")) // soft_keyword='"_"' ) @@ -25174,7 +25425,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (a = expression_rule(p)) // expression ) @@ -25247,6 +25498,70 @@ invalid_class_pattern_rule(Parser *p) return _res; } +// invalid_mapping_pattern: +// | '{' [(items_pattern ',')] double_star_pattern ',' items_pattern ','? '}' +static void * +invalid_mapping_pattern_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '{' [(items_pattern ',')] double_star_pattern ',' items_pattern ','? '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_mapping_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' [(items_pattern ',')] double_star_pattern ',' items_pattern ','? '}'")); + Token * _literal; + Token * _literal_1; + Token * _literal_2; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + void *_opt_var_1; + UNUSED(_opt_var_1); // Silence compiler warnings + asdl_seq* items_pattern_var; + expr_ty rest; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_opt_var = _tmp_147_rule(p), !p->error_indicator) // [(items_pattern ',')] + && + (rest = double_star_pattern_rule(p)) // double_star_pattern + && + (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' + && + (items_pattern_var = items_pattern_rule(p)) // items_pattern + && + (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? + && + (_literal_2 = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ invalid_mapping_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' [(items_pattern ',')] double_star_pattern ',' items_pattern ','? '}'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( rest , "double star pattern must be the last (right-most) subpattern in the mapping pattern" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_mapping_pattern[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' [(items_pattern ',')] double_star_pattern ',' items_pattern ','? '}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_class_argument_pattern: // | [positional_patterns ','] keyword_patterns ',' positional_patterns static asdl_pattern_seq* @@ -25273,7 +25588,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_147_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_148_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -25326,7 +25641,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25357,7 +25672,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty a_1; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 687)) // token='if' + (a = _PyPegen_expect_token(p, 691)) // token='if' && (a_1 = named_expression_rule(p)) // named_expression && @@ -25412,7 +25727,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 692)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 696)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25443,7 +25758,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 692)) // token='elif' + (a = _PyPegen_expect_token(p, 696)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25496,7 +25811,7 @@ invalid_else_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 691)) // token='else' + (a = _PyPegen_expect_token(p, 695)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25529,13 +25844,13 @@ invalid_else_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword = _PyPegen_expect_token(p, 695)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (block_var = block_rule(p)) // block && - (_keyword_1 = _PyPegen_expect_token(p, 692)) // token='elif' + (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='elif' ) { D(fprintf(stderr, "%*c+ invalid_else_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else' ':' block 'elif'")); @@ -25582,7 +25897,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 694)) // token='while' + (_keyword = _PyPegen_expect_token(p, 698)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25613,7 +25928,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 694)) // token='while' + (a = _PyPegen_expect_token(p, 698)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25672,13 +25987,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword = _PyPegen_expect_token(p, 703)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -25713,13 +26028,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 699)) // token='for' + (a = _PyPegen_expect_token(p, 703)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword = _PyPegen_expect_token(p, 700)) // token='in' + (_keyword = _PyPegen_expect_token(p, 704)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -25785,9 +26100,9 @@ invalid_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 704)) // token='def' + (a = _PyPegen_expect_token(p, 708)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25844,9 +26159,9 @@ invalid_def_raw_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty name_var; if ( - (_opt_var = _PyPegen_expect_token(p, 703), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 704)) // token='def' + (_keyword = _PyPegen_expect_token(p, 708)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25910,7 +26225,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 706)) // token='class' + (_keyword = _PyPegen_expect_token(p, 710)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -25949,7 +26264,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 706)) // token='class' + (a = _PyPegen_expect_token(p, 710)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26070,7 +26385,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_148_rule, p) + _PyPegen_lookahead(1, _tmp_149_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -26180,7 +26495,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_148_rule, p) + _PyPegen_lookahead(1, _tmp_149_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -26468,7 +26783,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (annotated_rhs_var = annotated_rhs_rule(p)) // annotated_rhs && - _PyPegen_lookahead(0, _tmp_149_rule, p) + _PyPegen_lookahead(0, _tmp_150_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs !('=' | '!' | ':' | '}')")); @@ -26500,7 +26815,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_150_rule, p) + _PyPegen_lookahead(0, _tmp_151_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '=' !('!' | ':' | '}')")); @@ -26564,9 +26879,9 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_151_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_152_rule, p) + _PyPegen_lookahead(0, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] !(':' | '}')")); @@ -26603,7 +26918,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_151_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -26644,7 +26959,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_151_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -26691,7 +27006,7 @@ invalid_fstring_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_152_rule, p) + _PyPegen_lookahead(1, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -26910,7 +27225,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (annotated_rhs_var = annotated_rhs_rule(p)) // annotated_rhs && - _PyPegen_lookahead(0, _tmp_149_rule, p) + _PyPegen_lookahead(0, _tmp_150_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs !('=' | '!' | ':' | '}')")); @@ -26942,7 +27257,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_150_rule, p) + _PyPegen_lookahead(0, _tmp_151_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '=' !('!' | ':' | '}')")); @@ -27006,9 +27321,9 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_151_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_152_rule, p) + _PyPegen_lookahead(0, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] !(':' | '}')")); @@ -27045,7 +27360,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_151_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -27086,7 +27401,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_151_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -27133,7 +27448,7 @@ invalid_tstring_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_152_rule, p) + _PyPegen_lookahead(1, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -27234,7 +27549,7 @@ invalid_string_tstring_concat_rule(Parser *p) if ( (a = _loop1_81_rule(p)) // tstring+ && - (b = (expr_ty)_tmp_153_rule(p)) // fstring | string + (b = (expr_ty)_tmp_154_rule(p)) // fstring | string ) { D(fprintf(stderr, "%*c+ invalid_string_tstring_concat[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tstring+ (fstring | string)")); @@ -27275,16 +27590,16 @@ invalid_arithmetic_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_arithmetic[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "sum ('+' | '-' | '*' | '/' | '%' | '//' | '@') 'not' inversion")); - void *_tmp_154_var; + void *_tmp_155_var; Token * a; expr_ty b; expr_ty sum_var; if ( (sum_var = sum_rule(p)) // sum && - (_tmp_154_var = _tmp_154_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' + (_tmp_155_var = _tmp_155_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' && - (a = _PyPegen_expect_token(p, 708)) // token='not' + (a = _PyPegen_expect_token(p, 712)) // token='not' && (b = inversion_rule(p)) // inversion ) @@ -27327,13 +27642,13 @@ invalid_factor_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_factor[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('+' | '-' | '~') 'not' factor")); - void *_tmp_155_var; + void *_tmp_156_var; Token * a; expr_ty b; if ( - (_tmp_155_var = _tmp_155_rule(p)) // '+' | '-' | '~' + (_tmp_156_var = _tmp_156_rule(p)) // '+' | '-' | '~' && - (a = _PyPegen_expect_token(p, 708)) // token='not' + (a = _PyPegen_expect_token(p, 712)) // token='not' && (b = factor_rule(p)) // factor ) @@ -27680,7 +27995,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='import' + (_keyword = _PyPegen_expect_token(p, 643)) // token='import' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); @@ -27699,7 +28014,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 638)) // token='from' + (_keyword = _PyPegen_expect_token(p, 642)) // token='from' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); @@ -27737,7 +28052,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 704)) // token='def' + (_keyword = _PyPegen_expect_token(p, 708)) // token='def' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); @@ -27775,7 +28090,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -27813,7 +28128,7 @@ _tmp_7_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 706)) // token='class' + (_keyword = _PyPegen_expect_token(p, 710)) // token='class' ) { D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); @@ -27870,7 +28185,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 652)) // token='with' + (_keyword = _PyPegen_expect_token(p, 656)) // token='with' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); @@ -27889,7 +28204,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -27927,7 +28242,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 699)) // token='for' + (_keyword = _PyPegen_expect_token(p, 703)) // token='for' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); @@ -27946,7 +28261,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='async' + (_keyword = _PyPegen_expect_token(p, 707)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -28105,12 +28420,12 @@ _loop1_12_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_156_var; + void *_tmp_157_var; while ( - (_tmp_156_var = _tmp_156_rule(p)) // star_targets '=' + (_tmp_157_var = _tmp_157_rule(p)) // star_targets '=' ) { - _res = _tmp_156_var; + _res = _tmp_157_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28397,12 +28712,12 @@ _loop0_17_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_157_var; + void *_tmp_158_var; while ( - (_tmp_157_var = _tmp_157_rule(p)) // '.' | '...' + (_tmp_158_var = _tmp_158_rule(p)) // '.' | '...' ) { - _res = _tmp_157_var; + _res = _tmp_158_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28464,12 +28779,12 @@ _loop1_18_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_157_var; + void *_tmp_158_var; while ( - (_tmp_157_var = _tmp_157_rule(p)) // '.' | '...' + (_tmp_158_var = _tmp_158_rule(p)) // '.' | '...' ) { - _res = _tmp_157_var; + _res = _tmp_158_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28647,7 +28962,7 @@ _tmp_21_rule(Parser *p) Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) @@ -28816,12 +29131,12 @@ _loop1_24_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_158_var; + void *_tmp_159_var; while ( - (_tmp_158_var = _tmp_158_rule(p)) // '@' named_expression NEWLINE + (_tmp_159_var = _tmp_159_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_158_var; + _res = _tmp_159_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30849,12 +31164,12 @@ _loop1_56_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_159_var; + void *_tmp_160_var; while ( - (_tmp_159_var = _tmp_159_rule(p)) // ',' star_expression + (_tmp_160_var = _tmp_160_rule(p)) // ',' star_expression ) { - _res = _tmp_159_var; + _res = _tmp_160_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31038,12 +31353,12 @@ _loop1_59_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_160_var; + void *_tmp_161_var; while ( - (_tmp_160_var = _tmp_160_rule(p)) // 'or' conjunction + (_tmp_161_var = _tmp_161_rule(p)) // 'or' conjunction ) { - _res = _tmp_160_var; + _res = _tmp_161_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31110,12 +31425,12 @@ _loop1_60_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_161_var; + void *_tmp_162_var; while ( - (_tmp_161_var = _tmp_161_rule(p)) // 'and' inversion + (_tmp_162_var = _tmp_162_rule(p)) // 'and' inversion ) { - _res = _tmp_161_var; + _res = _tmp_162_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31302,7 +31617,7 @@ _loop0_63_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_162_rule(p)) // slice | starred_expression + (elem = _tmp_163_rule(p)) // slice | starred_expression ) { _res = elem; @@ -31367,7 +31682,7 @@ _gather_64_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_162_rule(p)) // slice | starred_expression + (elem = _tmp_163_rule(p)) // slice | starred_expression && (seq = _loop0_63_rule(p)) // _loop0_63 ) @@ -32430,12 +32745,12 @@ _loop1_80_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_153_var; + void *_tmp_154_var; while ( - (_tmp_153_var = _tmp_153_rule(p)) // fstring | string + (_tmp_154_var = _tmp_154_rule(p)) // fstring | string ) { - _res = _tmp_153_var; + _res = _tmp_154_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32812,12 +33127,12 @@ _loop0_86_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_163_var; + void *_tmp_164_var; while ( - (_tmp_163_var = _tmp_163_rule(p)) // 'if' disjunction + (_tmp_164_var = _tmp_164_rule(p)) // 'if' disjunction ) { - _res = _tmp_163_var; + _res = _tmp_164_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32943,7 +33258,7 @@ _loop0_88_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_164_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_165_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -33009,7 +33324,7 @@ _gather_89_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_164_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_165_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && (seq = _loop0_88_rule(p)) // _loop0_88 ) @@ -33336,12 +33651,12 @@ _loop0_95_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_165_var; + void *_tmp_166_var; while ( - (_tmp_165_var = _tmp_165_rule(p)) // ',' star_target + (_tmp_166_var = _tmp_166_rule(p)) // ',' star_target ) { - _res = _tmp_165_var; + _res = _tmp_166_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33520,12 +33835,12 @@ _loop1_98_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_165_var; + void *_tmp_166_var; while ( - (_tmp_165_var = _tmp_165_rule(p)) // ',' star_target + (_tmp_166_var = _tmp_166_rule(p)) // ',' star_target ) { - _res = _tmp_165_var; + _res = _tmp_166_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33900,13 +34215,13 @@ _tmp_105_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _tmp_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - void *_tmp_166_var; + void *_tmp_167_var; if ( - (_tmp_166_var = _tmp_166_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs + (_tmp_167_var = _tmp_167_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs ) { D(fprintf(stderr, "%*c+ _tmp_105[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - _res = _tmp_166_var; + _res = _tmp_167_var; goto done; } p->mark = _mark; @@ -33971,7 +34286,7 @@ _loop0_106_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_167_rule(p)) // starred_expression !'=' + (elem = _tmp_168_rule(p)) // starred_expression !'=' ) { _res = elem; @@ -34036,7 +34351,7 @@ _gather_107_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_167_rule(p)) // starred_expression !'=' + (elem = _tmp_168_rule(p)) // starred_expression !'=' && (seq = _loop0_106_rule(p)) // _loop0_106 ) @@ -34358,12 +34673,12 @@ _loop1_113_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(!STRING expression_without_invalid)")); - void *_tmp_168_var; + void *_tmp_169_var; while ( - (_tmp_168_var = _tmp_168_rule(p)) // !STRING expression_without_invalid + (_tmp_169_var = _tmp_169_rule(p)) // !STRING expression_without_invalid ) { - _res = _tmp_168_var; + _res = _tmp_169_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34483,7 +34798,7 @@ _tmp_115_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='else' + (_keyword = _PyPegen_expect_token(p, 695)) // token='else' ) { D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); @@ -34880,12 +35195,12 @@ _loop0_120_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_156_var; + void *_tmp_157_var; while ( - (_tmp_156_var = _tmp_156_rule(p)) // star_targets '=' + (_tmp_157_var = _tmp_157_rule(p)) // star_targets '=' ) { - _res = _tmp_156_var; + _res = _tmp_157_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35262,15 +35577,15 @@ _tmp_126_rule(Parser *p) } D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_169_var; + void *_tmp_170_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_169_var = _tmp_169_rule(p)) // ')' | '**' + (_tmp_170_var = _tmp_170_rule(p)) // ')' | '**' ) { D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_169_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_170_var); goto done; } p->mark = _mark; @@ -35686,15 +36001,15 @@ _tmp_133_rule(Parser *p) } D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_170_var; + void *_tmp_171_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_170_var = _tmp_170_rule(p)) // ':' | '**' + (_tmp_171_var = _tmp_171_rule(p)) // ':' | '**' ) { D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_170_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_171_var); goto done; } p->mark = _mark; @@ -35783,20 +36098,20 @@ _tmp_135_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); - asdl_seq * _loop0_171_var; + asdl_seq * _loop0_172_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty bitwise_or_var; if ( (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - (_loop0_171_var = _loop0_171_rule(p)) // ((',' bitwise_or))* + (_loop0_172_var = _loop0_172_rule(p)) // ((',' bitwise_or))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) { D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); - _res = _PyPegen_dummy_name(p, bitwise_or_var, _loop0_171_var, _opt_var); + _res = _PyPegen_dummy_name(p, bitwise_or_var, _loop0_172_var, _opt_var); goto done; } p->mark = _mark; @@ -35926,7 +36241,7 @@ _gather_137_rule(Parser *p) return _res; } -// _tmp_138: NAME (',' | ')' | NEWLINE) +// _tmp_138: NAME (',' | ')' | ';' | NEWLINE) static void * _tmp_138_rule(Parser *p) { @@ -35939,27 +36254,27 @@ _tmp_138_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // NAME (',' | ')' | NEWLINE) + { // NAME (',' | ')' | ';' | NEWLINE) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | NEWLINE)")); - void *_tmp_172_var; + D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); + void *_tmp_173_var; expr_ty name_var; if ( (name_var = _PyPegen_name_token(p)) // NAME && - (_tmp_172_var = _tmp_172_rule(p)) // ',' | ')' | NEWLINE + (_tmp_173_var = _tmp_173_rule(p)) // ',' | ')' | ';' | NEWLINE ) { - D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | NEWLINE)")); - _res = _PyPegen_dummy_name(p, name_var, _tmp_172_var); + D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); + _res = _PyPegen_dummy_name(p, name_var, _tmp_173_var); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME (',' | ')' | NEWLINE)")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); } _res = NULL; done: @@ -36000,7 +36315,7 @@ _loop0_139_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_173_rule(p)) // expression ['as' star_target] + (elem = _tmp_174_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -36065,7 +36380,7 @@ _gather_140_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_173_rule(p)) // expression ['as' star_target] + (elem = _tmp_174_rule(p)) // expression ['as' star_target] && (seq = _loop0_139_rule(p)) // _loop0_139 ) @@ -36117,7 +36432,7 @@ _loop0_141_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_174_rule(p)) // expressions ['as' star_target] + (elem = _tmp_175_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -36182,7 +36497,7 @@ _gather_142_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_174_rule(p)) // expressions ['as' star_target] + (elem = _tmp_175_rule(p)) // expressions ['as' star_target] && (seq = _loop0_141_rule(p)) // _loop0_141 ) @@ -36222,7 +36537,7 @@ _tmp_143_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='except' + (_keyword = _PyPegen_expect_token(p, 686)) // token='except' ) { D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); @@ -36241,7 +36556,7 @@ _tmp_143_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 678)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 682)) // token='finally' ) { D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); @@ -36424,9 +36739,50 @@ _tmp_146_rule(Parser *p) return _res; } -// _tmp_147: positional_patterns ',' +// _tmp_147: items_pattern ',' static void * _tmp_147_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // items_pattern ',' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "items_pattern ','")); + Token * _literal; + asdl_seq* items_pattern_var; + if ( + (items_pattern_var = items_pattern_rule(p)) // items_pattern + && + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + ) + { + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "items_pattern ','")); + _res = _PyPegen_dummy_name(p, items_pattern_var, _literal); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "items_pattern ','")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_148: positional_patterns ',' +static void * +_tmp_148_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36442,7 +36798,7 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -36451,12 +36807,12 @@ _tmp_147_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -36465,64 +36821,7 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: '}' | ',' -static void * -_tmp_148_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '}' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 26)) // token='}' - ) - { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); - } - { // ',' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - ) - { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_149: '=' | '!' | ':' | '}' +// _tmp_149: '}' | ',' static void * _tmp_149_rule(Parser *p) { @@ -36535,63 +36834,6 @@ _tmp_149_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '=' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 22)) // token='=' - ) - { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); - } - { // '!' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 54)) // token='!' - ) - { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); - } - { // ':' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 11)) // token=':' - ) - { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); - } { // '}' if (p->error_indicator) { p->level--; @@ -36611,13 +36853,32 @@ _tmp_149_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } + { // ',' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + ) + { + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); + } _res = NULL; done: p->level--; return _res; } -// _tmp_150: '!' | ':' | '}' +// _tmp_150: '=' | '!' | ':' | '}' static void * _tmp_150_rule(Parser *p) { @@ -36630,6 +36891,25 @@ _tmp_150_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; + { // '=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + } { // '!' if (p->error_indicator) { p->level--; @@ -36693,9 +36973,85 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: '!' NAME +// _tmp_151: '!' | ':' | '}' static void * _tmp_151_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + ) + { + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); + } + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_152: '!' NAME +static void * +_tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36711,7 +37067,7 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -36720,12 +37076,12 @@ _tmp_151_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -36734,9 +37090,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: ':' | '}' +// _tmp_153: ':' | '}' static void * -_tmp_152_rule(Parser *p) +_tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36752,18 +37108,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -36771,18 +37127,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -36791,9 +37147,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: fstring | string +// _tmp_154: fstring | string static void * -_tmp_153_rule(Parser *p) +_tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36809,18 +37165,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -36828,18 +37184,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -36848,159 +37204,7 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: '+' | '-' | '*' | '/' | '%' | '//' | '@' -static void * -_tmp_154_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '+' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 14)) // token='+' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); - } - { // '-' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 15)) // token='-' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); - } - { // '*' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 16)) // token='*' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); - } - { // '/' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 17)) // token='/' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); - } - { // '%' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'%'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 24)) // token='%' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'%'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'%'")); - } - { // '//' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'//'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 47)) // token='//' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'//'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'//'")); - } - { // '@' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 49)) // token='@' - ) - { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_155: '+' | '-' | '~' +// _tmp_155: '+' | '-' | '*' | '/' | '%' | '//' | '@' static void * _tmp_155_rule(Parser *p) { @@ -37051,23 +37255,175 @@ _tmp_155_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } - { // '~' + { // '*' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'~'")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( - (_literal = _PyPegen_expect_token(p, 31)) // token='~' + (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'~'")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); + } + { // '/' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 17)) // token='/' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); + } + { // '%' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'%'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 24)) // token='%' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'%'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'%'")); + } + { // '//' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'//'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 47)) // token='//' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'//'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'//'")); + } + { // '@' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 49)) // token='@' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_156: '+' | '-' | '~' +static void * +_tmp_156_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '+' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 14)) // token='+' + ) + { + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); + } + { // '-' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 15)) // token='-' + ) + { + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); + } + { // '~' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'~'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 31)) // token='~' + ) + { + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'~'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'~'")); } _res = NULL; @@ -37076,9 +37432,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: star_targets '=' +// _tmp_157: star_targets '=' static void * -_tmp_156_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37094,7 +37450,7 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -37103,7 +37459,7 @@ _tmp_156_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37113,7 +37469,7 @@ _tmp_156_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -37122,9 +37478,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: '.' | '...' +// _tmp_158: '.' | '...' static void * -_tmp_157_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37140,18 +37496,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -37159,18 +37515,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -37179,9 +37535,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: '@' named_expression NEWLINE +// _tmp_159: '@' named_expression NEWLINE static void * -_tmp_158_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37197,7 +37553,7 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -37209,7 +37565,7 @@ _tmp_158_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37219,7 +37575,7 @@ _tmp_158_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -37228,9 +37584,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _tmp_159: ',' star_expression +// _tmp_160: ',' star_expression static void * -_tmp_159_rule(Parser *p) +_tmp_160_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37246,7 +37602,7 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -37255,7 +37611,7 @@ _tmp_159_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37265,7 +37621,7 @@ _tmp_159_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -37274,9 +37630,9 @@ _tmp_159_rule(Parser *p) return _res; } -// _tmp_160: 'or' conjunction +// _tmp_161: 'or' conjunction static void * -_tmp_160_rule(Parser *p) +_tmp_161_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37292,7 +37648,7 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -37301,7 +37657,7 @@ _tmp_160_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37311,7 +37667,7 @@ _tmp_160_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -37320,9 +37676,9 @@ _tmp_160_rule(Parser *p) return _res; } -// _tmp_161: 'and' inversion +// _tmp_162: 'and' inversion static void * -_tmp_161_rule(Parser *p) +_tmp_162_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37338,7 +37694,7 @@ _tmp_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -37347,7 +37703,7 @@ _tmp_161_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37357,7 +37713,7 @@ _tmp_161_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -37366,9 +37722,9 @@ _tmp_161_rule(Parser *p) return _res; } -// _tmp_162: slice | starred_expression +// _tmp_163: slice | starred_expression static void * -_tmp_162_rule(Parser *p) +_tmp_163_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37384,18 +37740,18 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -37403,18 +37759,18 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -37423,9 +37779,9 @@ _tmp_162_rule(Parser *p) return _res; } -// _tmp_163: 'if' disjunction +// _tmp_164: 'if' disjunction static void * -_tmp_163_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37441,16 +37797,16 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 687)) // token='if' + (_keyword = _PyPegen_expect_token(p, 691)) // token='if' && (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37460,7 +37816,7 @@ _tmp_163_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -37469,9 +37825,9 @@ _tmp_163_rule(Parser *p) return _res; } -// _tmp_164: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_165: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_164_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37487,18 +37843,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -37506,7 +37862,7 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); void *_tmp_87_var; if ( (_tmp_87_var = _tmp_87_rule(p)) // assignment_expression | expression !':=' @@ -37514,12 +37870,12 @@ _tmp_164_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); _res = _tmp_87_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -37528,9 +37884,9 @@ _tmp_164_rule(Parser *p) return _res; } -// _tmp_165: ',' star_target +// _tmp_166: ',' star_target static void * -_tmp_165_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37546,7 +37902,7 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -37555,7 +37911,7 @@ _tmp_165_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37565,7 +37921,7 @@ _tmp_165_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -37574,10 +37930,10 @@ _tmp_165_rule(Parser *p) return _res; } -// _tmp_166: +// _tmp_167: // | ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs static void * -_tmp_166_rule(Parser *p) +_tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37593,7 +37949,7 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); asdl_seq * _gather_89_var; Token * _literal; asdl_seq* kwargs_var; @@ -37605,12 +37961,12 @@ _tmp_166_rule(Parser *p) (kwargs_var = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); _res = _PyPegen_dummy_name(p, _gather_89_var, _literal, kwargs_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); } _res = NULL; @@ -37619,9 +37975,9 @@ _tmp_166_rule(Parser *p) return _res; } -// _tmp_167: starred_expression !'=' +// _tmp_168: starred_expression !'=' static void * -_tmp_167_rule(Parser *p) +_tmp_168_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37637,7 +37993,7 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); + D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression @@ -37645,12 +38001,12 @@ _tmp_167_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); + D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression !'='")); } _res = NULL; @@ -37659,9 +38015,9 @@ _tmp_167_rule(Parser *p) return _res; } -// _tmp_168: !STRING expression_without_invalid +// _tmp_169: !STRING expression_without_invalid static void * -_tmp_168_rule(Parser *p) +_tmp_169_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37677,7 +38033,7 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); + D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); expr_ty expression_without_invalid_var; if ( _PyPegen_lookahead(0, _PyPegen_string_token, p) @@ -37685,12 +38041,12 @@ _tmp_168_rule(Parser *p) (expression_without_invalid_var = expression_without_invalid_rule(p)) // expression_without_invalid ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); + D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); _res = expression_without_invalid_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!STRING expression_without_invalid")); } _res = NULL; @@ -37699,9 +38055,9 @@ _tmp_168_rule(Parser *p) return _res; } -// _tmp_169: ')' | '**' +// _tmp_170: ')' | '**' static void * -_tmp_169_rule(Parser *p) +_tmp_170_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37717,76 +38073,19 @@ _tmp_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); - } - { // '**' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 35)) // token='**' - ) - { - D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_170: ':' | '**' -static void * -_tmp_170_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // ':' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 11)) // token=':' - ) - { - D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' if (p->error_indicator) { @@ -37813,9 +38112,66 @@ _tmp_170_rule(Parser *p) return _res; } -// _loop0_171: (',' bitwise_or) +// _tmp_171: ':' | '**' +static void * +_tmp_171_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '**' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 35)) // token='**' + ) + { + D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_172: (',' bitwise_or) static asdl_seq * -_loop0_171_rule(Parser *p) +_loop0_172_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37840,13 +38196,13 @@ _loop0_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' bitwise_or)")); - void *_tmp_175_var; + D(fprintf(stderr, "%*c> _loop0_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' bitwise_or)")); + void *_tmp_176_var; while ( - (_tmp_175_var = _tmp_175_rule(p)) // ',' bitwise_or + (_tmp_176_var = _tmp_176_rule(p)) // ',' bitwise_or ) { - _res = _tmp_175_var; + _res = _tmp_176_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -37863,7 +38219,7 @@ _loop0_171_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' bitwise_or)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37880,9 +38236,9 @@ _loop0_171_rule(Parser *p) return _seq; } -// _tmp_172: ',' | ')' | NEWLINE +// _tmp_173: ',' | ')' | ';' | NEWLINE static void * -_tmp_172_rule(Parser *p) +_tmp_173_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37898,18 +38254,18 @@ _tmp_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -37917,37 +38273,56 @@ _tmp_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } + { // ';' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 13)) // token=';' + ) + { + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'")); + } { // NEWLINE if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } _res = NULL; @@ -37956,9 +38331,9 @@ _tmp_172_rule(Parser *p) return _res; } -// _tmp_173: expression ['as' star_target] +// _tmp_174: expression ['as' star_target] static void * -_tmp_173_rule(Parser *p) +_tmp_174_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37974,22 +38349,22 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_176_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_177_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -37998,9 +38373,9 @@ _tmp_173_rule(Parser *p) return _res; } -// _tmp_174: expressions ['as' star_target] +// _tmp_175: expressions ['as' star_target] static void * -_tmp_174_rule(Parser *p) +_tmp_175_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38016,22 +38391,22 @@ _tmp_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_176_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_177_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -38040,9 +38415,9 @@ _tmp_174_rule(Parser *p) return _res; } -// _tmp_175: ',' bitwise_or +// _tmp_176: ',' bitwise_or static void * -_tmp_175_rule(Parser *p) +_tmp_176_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38058,7 +38433,7 @@ _tmp_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); + D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); Token * _literal; expr_ty bitwise_or_var; if ( @@ -38067,12 +38442,12 @@ _tmp_175_rule(Parser *p) (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or ) { - D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); + D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); _res = _PyPegen_dummy_name(p, _literal, bitwise_or_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' bitwise_or")); } _res = NULL; @@ -38081,9 +38456,9 @@ _tmp_175_rule(Parser *p) return _res; } -// _tmp_176: 'as' star_target +// _tmp_177: 'as' star_target static void * -_tmp_176_rule(Parser *p) +_tmp_177_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38099,21 +38474,21 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 685)) // token='as' + (_keyword = _PyPegen_expect_token(p, 689)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; diff --git a/Parser/peg_api.c b/Parser/peg_api.c index d4acc3e4935..e30ca0453bd 100644 --- a/Parser/peg_api.c +++ b/Parser/peg_api.c @@ -4,13 +4,15 @@ mod_ty _PyParser_ASTFromString(const char *str, PyObject* filename, int mode, - PyCompilerFlags *flags, PyArena *arena) + PyCompilerFlags *flags, PyArena *arena, + PyObject *module) { if (PySys_Audit("compile", "yO", str, filename) < 0) { return NULL; } - mod_ty result = _PyPegen_run_parser_from_string(str, mode, filename, flags, arena); + mod_ty result = _PyPegen_run_parser_from_string(str, mode, filename, flags, + arena, module); return result; } diff --git a/Parser/pegen.c b/Parser/pegen.c index 70493031656..a38e973b3f6 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -1010,6 +1010,11 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena // From here on we need to clean up even if there's an error mod_ty result = NULL; + tok->module = PyUnicode_FromString("__main__"); + if (tok->module == NULL) { + goto error; + } + int parser_flags = compute_parser_flags(flags); Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, PY_MINOR_VERSION, errcode, NULL, arena); @@ -1036,7 +1041,7 @@ error: mod_ty _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filename_ob, - PyCompilerFlags *flags, PyArena *arena) + PyCompilerFlags *flags, PyArena *arena, PyObject *module) { int exec_input = start_rule == Py_file_input; @@ -1054,6 +1059,7 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen } // This transfers the ownership to the tokenizer tok->filename = Py_NewRef(filename_ob); + tok->module = Py_XNewRef(module); // We need to clear up from here on mod_ty result = NULL; diff --git a/Parser/pegen.h b/Parser/pegen.h index dfa2b0b4fe7..be5333eb268 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -162,7 +162,6 @@ int _PyPegen_fill_token(Parser *p); expr_ty _PyPegen_name_token(Parser *p); expr_ty _PyPegen_number_token(Parser *p); void *_PyPegen_string_token(Parser *p); -PyObject *_PyPegen_set_source_in_metadata(Parser *p, Token *t); Py_ssize_t _PyPegen_byte_offset_to_character_offset_line(PyObject *line, Py_ssize_t col_offset, Py_ssize_t end_col_offset); Py_ssize_t _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset); Py_ssize_t _PyPegen_byte_offset_to_character_offset_raw(const char*, Py_ssize_t col_offset); @@ -359,6 +358,7 @@ expr_ty _PyPegen_ensure_real(Parser *p, expr_ty); asdl_seq *_PyPegen_join_sequences(Parser *, asdl_seq *, asdl_seq *); int _PyPegen_check_barry_as_flufl(Parser *, Token *); int _PyPegen_check_legacy_stmt(Parser *p, expr_ty t); +void *_PyPegen_raise_error_for_missing_comma(Parser *p, expr_ty a, expr_ty b); ResultTokenWithMetadata *_PyPegen_check_fstring_conversion(Parser *p, Token *, expr_ty t); ResultTokenWithMetadata *_PyPegen_setup_full_format_spec(Parser *, Token *, asdl_expr_seq *, int, int, int, int, PyArena *); @@ -379,7 +379,7 @@ mod_ty _PyPegen_run_parser_from_file_pointer(FILE *, int, PyObject *, const char const char *, const char *, PyCompilerFlags *, int *, PyObject **, PyArena *); void *_PyPegen_run_parser(Parser *); -mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *); +mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *, PyObject *); asdl_stmt_seq *_PyPegen_interactive_exit(Parser *); // Generated function in parse.c - function definition in python.gram diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index f62b8695995..1c61524d60a 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -2,6 +2,7 @@ #include <errcode.h> #include "pycore_pyerrors.h" // _PyErr_ProgramDecodedTextObject() +#include "pycore_runtime.h" // _Py_ID() #include "lexer/state.h" #include "lexer/lexer.h" #include "pegen.h" @@ -23,6 +24,13 @@ _PyPegen_raise_tokenizer_init_error(PyObject *filename) PyObject *value; PyObject *tback; PyErr_Fetch(&type, &value, &tback); + if (PyErr_GivenExceptionMatches(value, PyExc_SyntaxError)) { + if (PyObject_SetAttr(value, &_Py_ID(filename), filename)) { + goto error; + } + PyErr_Restore(type, value, tback); + return; + } errstr = PyObject_Str(value); if (!errstr) { goto error; @@ -35,7 +43,7 @@ _PyPegen_raise_tokenizer_init_error(PyObject *filename) tuple = PyTuple_Pack(2, errstr, tmp); Py_DECREF(tmp); - if (!value) { + if (!tuple) { goto error; } PyErr_SetObject(PyExc_SyntaxError, tuple); diff --git a/Parser/string_parser.c b/Parser/string_parser.c index ebe68989d1a..b164dfbc81a 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -88,7 +88,7 @@ warn_invalid_escape_sequence(Parser *p, const char* buffer, const char *first_in } if (PyErr_WarnExplicitObject(category, msg, p->tok->filename, - lineno, NULL, NULL) < 0) { + lineno, p->tok->module, NULL) < 0) { if (PyErr_ExceptionMatches(category)) { /* Replace the Syntax/DeprecationWarning exception with a SyntaxError to get a more accurate error report */ diff --git a/Parser/tokenizer/file_tokenizer.c b/Parser/tokenizer/file_tokenizer.c index 01e473f58a0..8c836a3f725 100644 --- a/Parser/tokenizer/file_tokenizer.c +++ b/Parser/tokenizer/file_tokenizer.c @@ -282,10 +282,8 @@ tok_underflow_interactive(struct tok_state *tok) { } static int -tok_underflow_file(struct tok_state *tok) { - if (tok->start == NULL && !INSIDE_FSTRING(tok)) { - tok->cur = tok->inp = tok->buf; - } +tok_underflow_file(struct tok_state *tok) +{ if (tok->decoding_state == STATE_INIT) { /* We have not yet determined the encoding. If an encoding is found, use the file-pointer @@ -296,8 +294,16 @@ tok_underflow_file(struct tok_state *tok) { } assert(tok->decoding_state != STATE_INIT); } + int raw = tok->decoding_readline == NULL; + if (raw && tok->decoding_state != STATE_NORMAL) { + /* Keep the first line in the buffer to validate it later if + * the encoding has not yet been determined. */ + } + else if (tok->start == NULL && !INSIDE_FSTRING(tok)) { + tok->cur = tok->inp = tok->buf; + } /* Read until '\n' or EOF */ - if (tok->decoding_readline != NULL) { + if (!raw) { /* We already have a codec associated with this input. */ if (!tok_readline_recode(tok)) { return 0; @@ -328,20 +334,35 @@ tok_underflow_file(struct tok_state *tok) { ADVANCE_LINENO(); if (tok->decoding_state != STATE_NORMAL) { - if (tok->lineno > 2) { - tok->decoding_state = STATE_NORMAL; - } - else if (!_PyTokenizer_check_coding_spec(tok->cur, strlen(tok->cur), + if (!_PyTokenizer_check_coding_spec(tok->cur, strlen(tok->cur), tok, fp_setreadl)) { return 0; } + if (tok->lineno >= 2) { + tok->decoding_state = STATE_NORMAL; + } } - /* The default encoding is UTF-8, so make sure we don't have any - non-UTF-8 sequences in it. */ - if (!tok->encoding && !_PyTokenizer_ensure_utf8(tok->cur, tok)) { - _PyTokenizer_error_ret(tok); - return 0; + if (raw && tok->decoding_state == STATE_NORMAL) { + const char *line = tok->lineno <= 2 ? tok->buf : tok->cur; + int lineno = tok->lineno <= 2 ? 1 : tok->lineno; + if (!tok->encoding) { + /* The default encoding is UTF-8, so make sure we don't have any + non-UTF-8 sequences in it. */ + if (!_PyTokenizer_ensure_utf8(line, tok, lineno)) { + _PyTokenizer_error_ret(tok); + return 0; + } + } + else { + PyObject *tmp = PyUnicode_Decode(line, strlen(line), + tok->encoding, NULL); + if (tmp == NULL) { + _PyTokenizer_error_ret(tok); + return 0; + } + Py_DECREF(tmp); + } } assert(tok->done == E_OK); return tok->done == E_OK; diff --git a/Parser/tokenizer/helpers.c b/Parser/tokenizer/helpers.c index 5a416adb875..a03531a7441 100644 --- a/Parser/tokenizer/helpers.c +++ b/Parser/tokenizer/helpers.c @@ -47,8 +47,10 @@ _syntaxerror_range(struct tok_state *tok, const char *format, goto error; } - args = Py_BuildValue("(O(OiiNii))", errmsg, tok->filename, tok->lineno, - col_offset, errtext, tok->lineno, end_col_offset); + args = Py_BuildValue("(O(OiiNii))", errmsg, + tok->filename ? tok->filename : Py_None, + tok->lineno, col_offset, errtext, + tok->lineno, end_col_offset); if (args) { PyErr_SetObject(PyExc_SyntaxError, args); Py_DECREF(args); @@ -125,7 +127,7 @@ _PyTokenizer_warn_invalid_escape_sequence(struct tok_state *tok, int first_inval } if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename, - tok->lineno, NULL, NULL) < 0) { + tok->lineno, tok->module, NULL) < 0) { Py_DECREF(msg); if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { @@ -164,7 +166,7 @@ _PyTokenizer_parser_warn(struct tok_state *tok, PyObject *category, const char * } if (PyErr_WarnExplicitObject(category, errmsg, tok->filename, - tok->lineno, NULL, NULL) < 0) { + tok->lineno, tok->module, NULL) < 0) { if (PyErr_ExceptionMatches(category)) { /* Replace the DeprecationWarning exception with a SyntaxError to get a more accurate error report */ @@ -422,10 +424,13 @@ _PyTokenizer_check_coding_spec(const char* line, Py_ssize_t size, struct tok_sta tok->encoding = cs; } else { /* then, compare cs with BOM */ if (strcmp(tok->encoding, cs) != 0) { - _PyTokenizer_error_ret(tok); - PyErr_Format(PyExc_SyntaxError, - "encoding problem: %s with BOM", cs); + tok->line_start = line; + tok->cur = (char *)line; + assert(size <= INT_MAX); + _PyTokenizer_syntaxerror_known_range(tok, 0, (int)size, + "encoding problem: %s with BOM", cs); PyMem_Free(cs); + _PyTokenizer_error_ret(tok); return 0; } PyMem_Free(cs); @@ -496,24 +501,38 @@ valid_utf8(const unsigned char* s) } int -_PyTokenizer_ensure_utf8(char *line, struct tok_state *tok) +_PyTokenizer_ensure_utf8(const char *line, struct tok_state *tok, int lineno) { - int badchar = 0; - unsigned char *c; + const char *badchar = NULL; + const char *c; int length; - for (c = (unsigned char *)line; *c; c += length) { - if (!(length = valid_utf8(c))) { - badchar = *c; + int col_offset = 0; + const char *line_start = line; + for (c = line; *c; c += length) { + if (!(length = valid_utf8((const unsigned char *)c))) { + badchar = c; break; } + col_offset++; + if (*c == '\n') { + lineno++; + col_offset = 0; + line_start = c + 1; + } } if (badchar) { - PyErr_Format(PyExc_SyntaxError, - "Non-UTF-8 code starting with '\\x%.2x' " - "in file %U on line %i, " - "but no encoding declared; " - "see https://peps.python.org/pep-0263/ for details", - badchar, tok->filename, tok->lineno); + tok->lineno = lineno; + tok->line_start = line_start; + tok->cur = (char *)badchar; + _PyTokenizer_syntaxerror_known_range(tok, + col_offset + 1, col_offset + 1, + "Non-UTF-8 code starting with '\\x%.2x'" + "%s%V on line %i, " + "but no encoding declared; " + "see https://peps.python.org/pep-0263/ for details", + (unsigned char)*badchar, + tok->filename ? " in file " : "", tok->filename, "", + lineno); return 0; } return 1; diff --git a/Parser/tokenizer/helpers.h b/Parser/tokenizer/helpers.h index 42ea13cd1f8..98f6445d5a3 100644 --- a/Parser/tokenizer/helpers.h +++ b/Parser/tokenizer/helpers.h @@ -26,7 +26,7 @@ int _PyTokenizer_check_bom(int get_char(struct tok_state *), struct tok_state *tok); int _PyTokenizer_check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok, int set_readline(struct tok_state *, const char *)); -int _PyTokenizer_ensure_utf8(char *line, struct tok_state *tok); +int _PyTokenizer_ensure_utf8(const char *line, struct tok_state *tok, int lineno); #ifdef Py_DEBUG void _PyTokenizer_print_escape(FILE *f, const char *s, Py_ssize_t size); diff --git a/Parser/tokenizer/readline_tokenizer.c b/Parser/tokenizer/readline_tokenizer.c index 22f84c77a12..0f7769aeb8f 100644 --- a/Parser/tokenizer/readline_tokenizer.c +++ b/Parser/tokenizer/readline_tokenizer.c @@ -97,7 +97,7 @@ tok_underflow_readline(struct tok_state* tok) { ADVANCE_LINENO(); /* The default encoding is UTF-8, so make sure we don't have any non-UTF-8 sequences in it. */ - if (!tok->encoding && !_PyTokenizer_ensure_utf8(tok->cur, tok)) { + if (!tok->encoding && !_PyTokenizer_ensure_utf8(tok->cur, tok, tok->lineno)) { _PyTokenizer_error_ret(tok); return 0; } diff --git a/Parser/tokenizer/string_tokenizer.c b/Parser/tokenizer/string_tokenizer.c index 0c26d5df8d4..7299ecf483c 100644 --- a/Parser/tokenizer/string_tokenizer.c +++ b/Parser/tokenizer/string_tokenizer.c @@ -86,15 +86,18 @@ decode_str(const char *input, int single, struct tok_state *tok, int preserve_cr /* need to check line 1 and 2 separately since check_coding_spec assumes a single line as input */ if (newl[0]) { + tok->lineno = 1; if (!_PyTokenizer_check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) { return NULL; } if (tok->enc == NULL && tok->decoding_state != STATE_NORMAL && newl[1]) { + tok->lineno = 2; if (!_PyTokenizer_check_coding_spec(newl[0]+1, newl[1] - newl[0], tok, buf_setreadl)) return NULL; } } + tok->lineno = 0; if (tok->enc != NULL) { assert(utf8 == NULL); utf8 = _PyTokenizer_translate_into_utf8(str, tok->enc); @@ -102,6 +105,9 @@ decode_str(const char *input, int single, struct tok_state *tok, int preserve_cr return _PyTokenizer_error_ret(tok); str = PyBytes_AS_STRING(utf8); } + else if (!_PyTokenizer_ensure_utf8(str, tok, 1)) { + return _PyTokenizer_error_ret(tok); + } assert(tok->decoding_buffer == NULL); tok->decoding_buffer = utf8; /* CAUTION */ return str; diff --git a/Programs/_freeze_module.py b/Programs/_freeze_module.py index ba638eef6c4..62274e4aa9c 100644 --- a/Programs/_freeze_module.py +++ b/Programs/_freeze_module.py @@ -23,7 +23,7 @@ def read_text(inpath: str) -> bytes: def compile_and_marshal(name: str, text: bytes) -> bytes: filename = f"<frozen {name}>" # exec == Py_file_input - code = compile(text, filename, "exec", optimize=0, dont_inherit=True) + code = compile(text, filename, "exec", optimize=0, dont_inherit=True, module=name) return marshal.dumps(code) diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 28c004c3c5a..c5e764e426b 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -22,6 +22,10 @@ extern void PySys_AddWarnOption(const wchar_t *s); extern void PySys_AddXOption(const wchar_t *s); extern void Py_SetPath(const wchar_t *path); +// These functions were removed from Python 3.15 API but are still exported +// for the stable ABI. We want to test them in this program. +extern void PySys_ResetWarnOptions(void); + int main_argc; char **main_argv; @@ -162,6 +166,8 @@ static PyModuleDef embedded_ext = { static PyObject* PyInit_embedded_ext(void) { + // keep this as a single-phase initialization module; + // see test_create_module_from_initfunc return PyModule_Create(&embedded_ext); } @@ -336,8 +342,18 @@ static int test_pre_initialization_sys_options(void) size_t xoption_len = wcslen(static_xoption); wchar_t *dynamic_once_warnoption = \ (wchar_t *) calloc(warnoption_len+1, sizeof(wchar_t)); + if (dynamic_once_warnoption == NULL) { + error("out of memory allocating warnoption"); + return 1; + } wchar_t *dynamic_xoption = \ (wchar_t *) calloc(xoption_len+1, sizeof(wchar_t)); + if (dynamic_xoption == NULL) { + free(dynamic_once_warnoption); + error("out of memory allocating xoption"); + return 1; + } + wcsncpy(dynamic_once_warnoption, static_warnoption, warnoption_len+1); wcsncpy(dynamic_xoption, static_xoption, xoption_len+1); @@ -1384,9 +1400,12 @@ static int test_audit_subinterpreter(void) PySys_AddAuditHook(_audit_subinterpreter_hook, NULL); _testembed_initialize(); - Py_NewInterpreter(); - Py_NewInterpreter(); - Py_NewInterpreter(); + PyThreadState *tstate = PyThreadState_Get(); + for (int i = 0; i < 3; ++i) + { + Py_EndInterpreter(Py_NewInterpreter()); + PyThreadState_Swap(tstate); + } Py_Finalize(); @@ -1489,44 +1508,6 @@ static int test_audit_run_stdin(void) return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test); } -static int test_init_read_set(void) -{ - PyStatus status; - PyConfig config; - PyConfig_InitPythonConfig(&config); - - config_set_string(&config, &config.program_name, L"./init_read_set"); - - status = PyConfig_Read(&config); - if (PyStatus_Exception(status)) { - goto fail; - } - - status = PyWideStringList_Insert(&config.module_search_paths, - 1, L"test_path_insert1"); - if (PyStatus_Exception(status)) { - goto fail; - } - - status = PyWideStringList_Append(&config.module_search_paths, - L"test_path_append"); - if (PyStatus_Exception(status)) { - goto fail; - } - - /* override executable computed by PyConfig_Read() */ - config_set_string(&config, &config.executable, L"my_executable"); - init_from_config_clear(&config); - - dump_config(); - Py_Finalize(); - return 0; - -fail: - PyConfig_Clear(&config); - Py_ExitStatusException(status); -} - static int test_init_sys_add(void) { @@ -1915,8 +1896,16 @@ static int test_initconfig_exit(void) } +int +extension_module_exec(PyObject *mod) +{ + return PyModule_AddStringConstant(mod, "exec_slot_ran", "yes"); +} + + static PyModuleDef_Slot extension_slots[] = { {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {Py_mod_exec, extension_module_exec}, {0, NULL} }; @@ -2074,15 +2063,20 @@ static int check_use_frozen_modules(const char *rawval) if (rawval == NULL) { wcscpy(optval, L"frozen_modules"); } - else if (swprintf(optval, 100, -#if defined(_MSC_VER) - L"frozen_modules=%S", -#else - L"frozen_modules=%s", -#endif - rawval) < 0) { - error("rawval is too long"); - return -1; + else { + wchar_t *val = Py_DecodeLocale(rawval, NULL); + if (val == NULL) { + error("unable to decode TESTFROZEN"); + return -1; + } + wcscpy(optval, L"frozen_modules="); + if ((wcslen(optval) + wcslen(val)) >= Py_ARRAY_LENGTH(optval)) { + error("TESTFROZEN is too long"); + PyMem_RawFree(val); + return -1; + } + wcscat(optval, val); + PyMem_RawFree(val); } PyConfig config; @@ -2234,6 +2228,277 @@ static int test_repeated_init_and_inittab(void) return 0; } +static PyObject* +create_module(PyObject* self, PyObject* spec) +{ + PyObject *name = PyObject_GetAttrString(spec, "name"); + if (!name) { + return NULL; + } + if (PyUnicode_EqualToUTF8(name, "my_test_extension")) { + Py_DECREF(name); + return PyImport_CreateModuleFromInitfunc(spec, init_my_test_extension); + } + if (PyUnicode_EqualToUTF8(name, "embedded_ext")) { + Py_DECREF(name); + return PyImport_CreateModuleFromInitfunc(spec, PyInit_embedded_ext); + } + PyErr_Format(PyExc_LookupError, "static module %R not found", name); + Py_DECREF(name); + return NULL; +} + +static PyObject* +exec_module(PyObject* self, PyObject* mod) +{ + if (PyModule_Exec(mod) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyMethodDef create_static_module_methods[] = { + {"create_module", create_module, METH_O, NULL}, + {"exec_module", exec_module, METH_O, NULL}, + {NULL} +}; + +static struct PyModuleDef create_static_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "create_static_module", + .m_size = 0, + .m_methods = create_static_module_methods, + .m_slots = extension_slots, +}; + +PyMODINIT_FUNC PyInit_create_static_module(void) { + return PyModuleDef_Init(&create_static_module_def); +} + +static int +test_create_module_from_initfunc(void) +{ + wchar_t* argv[] = { + PROGRAM_NAME, + L"-c", + // Multi-phase initialization + L"import my_test_extension;" + L"print(my_test_extension);" + L"print(f'{my_test_extension.executed=}');" + L"print(f'{my_test_extension.exec_slot_ran=}');" + // Single-phase initialization + L"import embedded_ext;" + L"print(embedded_ext);" + L"print(f'{embedded_ext.executed=}');" + }; + PyConfig config; + if (PyImport_AppendInittab("create_static_module", + &PyInit_create_static_module) != 0) { + fprintf(stderr, "PyImport_AppendInittab() failed\n"); + return 1; + } + PyConfig_InitPythonConfig(&config); + config.isolated = 1; + config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv); + init_from_config_clear(&config); + int result = PyRun_SimpleString( + "import sys\n" + "from importlib.util import spec_from_loader\n" + "import create_static_module\n" + "class StaticExtensionImporter:\n" + " _ORIGIN = \"static-extension\"\n" + " @classmethod\n" + " def find_spec(cls, fullname, path, target=None):\n" + " if fullname in {'my_test_extension', 'embedded_ext'}:\n" + " return spec_from_loader(fullname, cls, origin=cls._ORIGIN)\n" + " return None\n" + " @staticmethod\n" + " def create_module(spec):\n" + " return create_static_module.create_module(spec)\n" + " @staticmethod\n" + " def exec_module(module):\n" + " create_static_module.exec_module(module)\n" + " module.executed = 'yes'\n" + "sys.meta_path.append(StaticExtensionImporter)\n" + ); + if (result < 0) { + fprintf(stderr, "PyRun_SimpleString() failed\n"); + return 1; + } + return Py_RunMain(); +} + +/// Multi-phase initialization package & submodule /// + +int +mp_pkg_exec(PyObject *mod) +{ + // make this a namespace package + // empty list = namespace package + if (PyModule_Add(mod, "__path__", PyList_New(0)) < 0) { + return -1; + } + if (PyModule_AddStringConstant(mod, "mp_pkg_exec_slot_ran", "yes") < 0) { + return -1; + } + return 0; +} + +static PyModuleDef_Slot mp_pkg_slots[] = { + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {Py_mod_exec, mp_pkg_exec}, + {0, NULL} +}; + +static struct PyModuleDef mp_pkg_def = { + PyModuleDef_HEAD_INIT, + .m_name = "mp_pkg", + .m_size = 0, + .m_slots = mp_pkg_slots, +}; + +PyMODINIT_FUNC +PyInit_mp_pkg(void) +{ + return PyModuleDef_Init(&mp_pkg_def); +} + +static PyObject * +submod_greet(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromString("Hello from sub-module"); +} + +static PyMethodDef submod_methods[] = { + {"greet", submod_greet, METH_NOARGS, NULL}, + {NULL}, +}; + +int +mp_submod_exec(PyObject *mod) +{ + return PyModule_AddStringConstant(mod, "mp_submod_exec_slot_ran", "yes"); +} + +static PyModuleDef_Slot mp_submod_slots[] = { + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {Py_mod_exec, mp_submod_exec}, + {0, NULL} +}; + +static struct PyModuleDef mp_submod_def = { + PyModuleDef_HEAD_INIT, + .m_name = "mp_pkg.mp_submod", + .m_size = 0, + .m_methods = submod_methods, + .m_slots = mp_submod_slots, +}; + +PyMODINIT_FUNC +PyInit_mp_submod(void) +{ + return PyModuleDef_Init(&mp_submod_def); +} + +static int +test_inittab_submodule_multiphase(void) +{ + wchar_t* argv[] = { + PROGRAM_NAME, + L"-c", + L"import sys;" + L"import mp_pkg.mp_submod;" + L"print(mp_pkg.mp_submod);" + L"print(sys.modules['mp_pkg.mp_submod']);" + L"print(mp_pkg.mp_submod.greet());" + L"print(f'{mp_pkg.mp_submod.mp_submod_exec_slot_ran=}');" + L"print(f'{mp_pkg.mp_pkg_exec_slot_ran=}');" + }; + PyConfig config; + if (PyImport_AppendInittab("mp_pkg", + &PyInit_mp_pkg) != 0) { + fprintf(stderr, "PyImport_AppendInittab() failed\n"); + return 1; + } + if (PyImport_AppendInittab("mp_pkg.mp_submod", + &PyInit_mp_submod) != 0) { + fprintf(stderr, "PyImport_AppendInittab() failed\n"); + return 1; + } + PyConfig_InitPythonConfig(&config); + config.isolated = 1; + config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv); + init_from_config_clear(&config); + return Py_RunMain(); +} + +/// Single-phase initialization package & submodule /// + +static struct PyModuleDef sp_pkg_def = { + PyModuleDef_HEAD_INIT, + .m_name = "sp_pkg", + .m_size = 0, +}; + +PyMODINIT_FUNC +PyInit_sp_pkg(void) +{ + PyObject *mod = PyModule_Create(&sp_pkg_def); + if (mod == NULL) { + return NULL; + } + // make this a namespace package + // empty list = namespace package + if (PyModule_Add(mod, "__path__", PyList_New(0)) < 0) { + Py_DECREF(mod); + return NULL; + } + return mod; +} + +static struct PyModuleDef sp_submod_def = { + PyModuleDef_HEAD_INIT, + .m_name = "sp_pkg.sp_submod", + .m_size = 0, + .m_methods = submod_methods, +}; + +PyMODINIT_FUNC +PyInit_sp_submod(void) +{ + return PyModule_Create(&sp_submod_def); +} + +static int +test_inittab_submodule_singlephase(void) +{ + wchar_t* argv[] = { + PROGRAM_NAME, + L"-c", + L"import sys;" + L"import sp_pkg.sp_submod;" + L"print(sp_pkg.sp_submod);" + L"print(sys.modules['sp_pkg.sp_submod']);" + L"print(sp_pkg.sp_submod.greet());" + }; + PyConfig config; + if (PyImport_AppendInittab("sp_pkg", + &PyInit_sp_pkg) != 0) { + fprintf(stderr, "PyImport_AppendInittab() failed\n"); + return 1; + } + if (PyImport_AppendInittab("sp_pkg.sp_submod", + &PyInit_sp_submod) != 0) { + fprintf(stderr, "PyImport_AppendInittab() failed\n"); + return 1; + } + PyConfig_InitPythonConfig(&config); + config.isolated = 1; + config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv); + init_from_config_clear(&config); + return Py_RunMain(); +} + static void wrap_allocator(PyMemAllocatorEx *allocator); static void unwrap_allocator(PyMemAllocatorEx *allocator); @@ -2381,7 +2646,6 @@ static struct TestCase TestCases[] = { {"test_preinit_isolated2", test_preinit_isolated2}, {"test_preinit_parse_argv", test_preinit_parse_argv}, {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv}, - {"test_init_read_set", test_init_read_set}, {"test_init_run_main", test_init_run_main}, {"test_init_sys_add", test_init_sys_add}, {"test_init_setpath", test_init_setpath}, @@ -2418,6 +2682,9 @@ static struct TestCase TestCases[] = { #endif {"test_get_incomplete_frame", test_get_incomplete_frame}, {"test_gilstate_after_finalization", test_gilstate_after_finalization}, + {"test_create_module_from_initfunc", test_create_module_from_initfunc}, + {"test_inittab_submodule_multiphase", test_inittab_submodule_multiphase}, + {"test_inittab_submodule_singlephase", test_inittab_submodule_singlephase}, {NULL, NULL} }; diff --git a/Programs/freeze_test_frozenmain.py b/Programs/freeze_test_frozenmain.py index 848fc31b3d6..1a986bbac2a 100644 --- a/Programs/freeze_test_frozenmain.py +++ b/Programs/freeze_test_frozenmain.py @@ -24,7 +24,7 @@ def dump(fp, filename, name): with tokenize.open(filename) as source_fp: source = source_fp.read() - code = compile(source, code_filename, 'exec') + code = compile(source, code_filename, 'exec', module=name) data = marshal.dumps(code) writecode(fp, name, data) diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 660bc598a48..aac24ed7d3c 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5293,7 +5293,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) else { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "Field '%U' is missing from %.400s._field_types. " + "Field %R is missing from %.400s._field_types. " "This will become an error in Python 3.15.", name, Py_TYPE(self)->tp_name ) < 0) { @@ -5328,7 +5328,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) // simple field (e.g., identifier) if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "%.400s.__init__ missing 1 required positional argument: '%U'. " + "%.400s.__init__ missing 1 required positional argument: %R. " "This will become an error in Python 3.15.", Py_TYPE(self)->tp_name, name ) < 0) { diff --git a/Python/_warnings.c b/Python/_warnings.c index 243a5e88e9d..d44d414bc93 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -171,7 +171,7 @@ _PyWarnings_InitState(PyInterpreterState *interp) /*************************************************************************/ static int -check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg) +check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg, PyObject *arg2) { PyObject *result; int rc; @@ -182,6 +182,9 @@ check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg) /* An internal plain text default filter must match exactly */ if (PyUnicode_CheckExact(obj)) { + if (arg == NULL) { + return 0; + } int cmp_result = PyUnicode_Compare(obj, arg); if (cmp_result == -1 && PyErr_Occurred()) { return -1; @@ -190,10 +193,19 @@ check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg) } /* Otherwise assume a regex filter and call its match() method */ - result = PyObject_CallMethodOneArg(obj, &_Py_ID(match), arg); + if (arg != NULL) { + result = PyObject_CallMethodOneArg(obj, &_Py_ID(match), arg); + } + else { + PyObject *match = PyImport_ImportModuleAttrString("_py_warnings", "_match_filename"); + if (match == NULL) { + return -1; + } + result = PyObject_CallFunctionObjArgs(match, obj, arg2, NULL); + Py_DECREF(match); + } if (result == NULL) return -1; - rc = PyObject_IsTrue(result); Py_DECREF(result); return rc; @@ -423,7 +435,7 @@ get_default_action(PyInterpreterState *interp) static bool filter_search(PyInterpreterState *interp, PyObject *category, PyObject *text, Py_ssize_t lineno, - PyObject *module, char *list_name, PyObject *filters, + PyObject *module, PyObject *filename, char *list_name, PyObject *filters, PyObject **item, PyObject **matched_action) { bool result = true; *matched_action = NULL; @@ -459,14 +471,14 @@ filter_search(PyInterpreterState *interp, PyObject *category, break; } - good_msg = check_matched(interp, msg, text); + good_msg = check_matched(interp, msg, text, NULL); if (good_msg == -1) { Py_DECREF(tmp_item); result = false; break; } - good_mod = check_matched(interp, mod, module); + good_mod = check_matched(interp, mod, module, filename); if (good_mod == -1) { Py_DECREF(tmp_item); result = false; @@ -504,7 +516,7 @@ filter_search(PyInterpreterState *interp, PyObject *category, static PyObject* get_filter(PyInterpreterState *interp, PyObject *category, PyObject *text, Py_ssize_t lineno, - PyObject *module, PyObject **item) + PyObject *module, PyObject *filename, PyObject **item) { #ifdef Py_DEBUG WarningsState *st = warnings_get_state(interp); @@ -522,7 +534,7 @@ get_filter(PyInterpreterState *interp, PyObject *category, use_global_filters = true; } else { PyObject *context_action = NULL; - if (!filter_search(interp, category, text, lineno, module, "_warnings_context _filters", + if (!filter_search(interp, category, text, lineno, module, filename, "_warnings_context _filters", context_filters, item, &context_action)) { Py_DECREF(context_filters); return NULL; @@ -541,7 +553,7 @@ get_filter(PyInterpreterState *interp, PyObject *category, if (filters == NULL) { return NULL; } - if (!filter_search(interp, category, text, lineno, module, "filters", + if (!filter_search(interp, category, text, lineno, module, filename, "filters", filters, item, &action)) { return NULL; } @@ -612,39 +624,6 @@ already_warned(PyInterpreterState *interp, PyObject *registry, PyObject *key, return 0; } -/* New reference. */ -static PyObject * -normalize_module(PyObject *filename) -{ - PyObject *module; - int kind; - const void *data; - Py_ssize_t len; - - len = PyUnicode_GetLength(filename); - if (len < 0) - return NULL; - - if (len == 0) - return PyUnicode_FromString("<unknown>"); - - kind = PyUnicode_KIND(filename); - data = PyUnicode_DATA(filename); - - /* if filename.endswith(".py"): */ - if (len >= 3 && - PyUnicode_READ(kind, data, len-3) == '.' && - PyUnicode_READ(kind, data, len-2) == 'p' && - PyUnicode_READ(kind, data, len-1) == 'y') - { - module = PyUnicode_Substring(filename, 0, len-3); - } - else { - module = Py_NewRef(filename); - } - return module; -} - static int update_registry(PyInterpreterState *interp, PyObject *registry, PyObject *text, PyObject *category, int add_zero) @@ -812,15 +791,6 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message, return NULL; } - /* Normalize module. */ - if (module == NULL) { - module = normalize_module(filename); - if (module == NULL) - return NULL; - } - else - Py_INCREF(module); - /* Normalize message. */ Py_INCREF(message); /* DECREF'ed in cleanup. */ if (PyObject_TypeCheck(message, (PyTypeObject *)PyExc_Warning)) { @@ -858,7 +828,7 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message, /* Else this warning hasn't been generated before. */ } - action = get_filter(interp, category, text, lineno, module, &item); + action = get_filter(interp, category, text, lineno, module, filename, &item); if (action == NULL) goto cleanup; @@ -921,7 +891,6 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message, Py_XDECREF(key); Py_XDECREF(text); Py_XDECREF(lineno_obj); - Py_DECREF(module); Py_XDECREF(message); return result; /* Py_None or NULL. */ } @@ -1473,28 +1442,6 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message, return 0; } -/* Like PyErr_WarnExplicitObject, but automatically sets up context */ -int -_PyErr_WarnExplicitObjectWithContext(PyObject *category, PyObject *message, - PyObject *filename, int lineno) -{ - PyObject *unused_filename, *module, *registry; - int unused_lineno; - int stack_level = 1; - - if (!setup_context(stack_level, NULL, &unused_filename, &unused_lineno, - &module, &registry)) { - return -1; - } - - int rc = PyErr_WarnExplicitObject(category, message, filename, lineno, - module, registry); - Py_DECREF(unused_filename); - Py_DECREF(registry); - Py_DECREF(module); - return rc; -} - int PyErr_WarnExplicit(PyObject *category, const char *text, const char *filename_str, int lineno, diff --git a/Python/ast_preprocess.c b/Python/ast_preprocess.c index 44d3075098b..d45435257cc 100644 --- a/Python/ast_preprocess.c +++ b/Python/ast_preprocess.c @@ -16,9 +16,11 @@ typedef struct { typedef struct { PyObject *filename; + PyObject *module; int optimize; int ff_features; int syntax_check_only; + int enable_warnings; _Py_c_array_t cf_finally; /* context for PEP 765 check */ int cf_finally_used; @@ -70,7 +72,8 @@ control_flow_in_finally_warning(const char *kw, stmt_ty n, _PyASTPreprocessState } int ret = _PyErr_EmitSyntaxWarning(msg, state->filename, n->lineno, n->col_offset + 1, n->end_lineno, - n->end_col_offset + 1); + n->end_col_offset + 1, + state->module); Py_DECREF(msg); return ret < 0 ? 0 : 1; } @@ -78,7 +81,7 @@ control_flow_in_finally_warning(const char *kw, stmt_ty n, _PyASTPreprocessState static int before_return(_PyASTPreprocessState *state, stmt_ty node_) { - if (state->cf_finally_used > 0) { + if (state->enable_warnings && state->cf_finally_used > 0) { ControlFlowInFinallyContext *ctx = get_cf_finally_top(state); if (ctx->in_finally && ! ctx->in_funcdef) { if (!control_flow_in_finally_warning("return", node_, state)) { @@ -92,7 +95,7 @@ before_return(_PyASTPreprocessState *state, stmt_ty node_) static int before_loop_exit(_PyASTPreprocessState *state, stmt_ty node_, const char *kw) { - if (state->cf_finally_used > 0) { + if (state->enable_warnings && state->cf_finally_used > 0) { ControlFlowInFinallyContext *ctx = get_cf_finally_top(state); if (ctx->in_finally && ! ctx->in_loop) { if (!control_flow_in_finally_warning(kw, node_, state)) { @@ -968,14 +971,17 @@ astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTPreprocessState *st int _PyAST_Preprocess(mod_ty mod, PyArena *arena, PyObject *filename, int optimize, - int ff_features, int syntax_check_only) + int ff_features, int syntax_check_only, int enable_warnings, + PyObject *module) { _PyASTPreprocessState state; memset(&state, 0, sizeof(_PyASTPreprocessState)); state.filename = filename; + state.module = module; state.optimize = optimize; state.ff_features = ff_features; state.syntax_check_only = syntax_check_only; + state.enable_warnings = enable_warnings; if (_Py_CArray_Init(&state.cf_finally, sizeof(ControlFlowInFinallyContext), 20) < 0) { return -1; } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index b7e08ae54da..c2d780ac9b9 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_cell.h" // PyCell_GetRef() #include "pycore_ceval.h" // _PyEval_Vector() #include "pycore_compile.h" // _PyAST_Compile() #include "pycore_fileutils.h" // _PyFile_Flush @@ -14,8 +15,7 @@ #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pythonrun.h" // _Py_SourceAsString() -#include "pycore_tuple.h" // _PyTuple_FromArray() -#include "pycore_cell.h" // PyCell_GetRef() +#include "pycore_tuple.h" // _PyTuple_Recycle() #include "clinic/bltinmodule.c.h" @@ -123,7 +123,7 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs, "__build_class__: name is not a string"); return NULL; } - orig_bases = _PyTuple_FromArray(args + 2, nargs - 2); + orig_bases = PyTuple_FromArray(args + 2, nargs - 2); if (orig_bases == NULL) return NULL; @@ -745,12 +745,13 @@ builtin_chr(PyObject *module, PyObject *i) compile as builtin_compile source: object - filename: object(converter="PyUnicode_FSDecoder") + filename: unicode_fs_decoded mode: str flags: int = 0 dont_inherit: bool = False optimize: int = -1 * + module as modname: object = None _feature_version as feature_version: int = -1 Compile source into a code object that can be executed by exec() or eval(). @@ -770,8 +771,8 @@ in addition to any features explicitly specified. static PyObject * builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, - int optimize, int feature_version) -/*[clinic end generated code: output=b0c09c84f116d3d7 input=cc78e20e7c7682ba]*/ + int optimize, PyObject *modname, int feature_version) +/*[clinic end generated code: output=9a0dce1945917a86 input=ddeae1e0253459dc]*/ { PyObject *source_copy; const char *str; @@ -800,6 +801,15 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, "compile(): invalid optimize value"); goto error; } + if (modname == Py_None) { + modname = NULL; + } + else if (!PyUnicode_Check(modname)) { + PyErr_Format(PyExc_TypeError, + "compile() argument 'module' must be str or None, not %T", + modname); + goto error; + } if (!dont_inherit) { PyEval_MergeCompilerFlags(&cf); @@ -845,8 +855,9 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, goto error; } int syntax_check_only = ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST); /* unoptiomized AST */ - if (_PyCompile_AstPreprocess(mod, filename, &cf, optimize, - arena, syntax_check_only) < 0) { + if (_PyCompile_AstPreprocess(mod, filename, &cf, optimize, arena, + syntax_check_only, modname) < 0) + { _PyArena_Free(arena); goto error; } @@ -859,7 +870,7 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, goto error; } result = (PyObject*)_PyAST_Compile(mod, filename, - &cf, optimize, arena); + &cf, optimize, arena, modname); } _PyArena_Free(arena); goto finally; @@ -877,7 +888,9 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, tstate->suppress_co_const_immortalization++; #endif - result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize); + result = _Py_CompileStringObjectWithModule(str, filename, + start[compile_mode], &cf, + optimize, modname); #ifdef Py_GIL_DISABLED tstate->suppress_co_const_immortalization--; @@ -889,7 +902,6 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, error: result = NULL; finally: - Py_DECREF(filename); return result; } @@ -1502,34 +1514,27 @@ map_next(PyObject *self) } Py_ssize_t nargs = 0; - for (i=0; i < niters; i++) { + for (i = 0; i < niters; i++) { PyObject *it = PyTuple_GET_ITEM(lz->iters, i); PyObject *val = Py_TYPE(it)->tp_iternext(it); if (val == NULL) { if (lz->strict) { goto check; } - goto exit; + goto exit_no_result; } stack[i] = val; nargs++; } result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL); + goto exit; -exit: - for (i=0; i < nargs; i++) { - Py_DECREF(stack[i]); - } - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; check: if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_StopIteration)) { // next() on argument i raised an exception (not StopIteration) - return NULL; + goto exit_no_result; } PyErr_Clear(); } @@ -1537,9 +1542,10 @@ check: // ValueError: map() argument 2 is shorter than argument 1 // ValueError: map() argument 3 is shorter than arguments 1-2 const char* plural = i == 1 ? " " : "s 1-"; - return PyErr_Format(PyExc_ValueError, - "map() argument %d is shorter than argument%s%d", - i + 1, plural, i); + PyErr_Format(PyExc_ValueError, + "map() argument %d is shorter than argument%s%d", + i + 1, plural, i); + goto exit_no_result; } for (i = 1; i < niters; i++) { PyObject *it = PyTuple_GET_ITEM(lz->iters, i); @@ -1547,21 +1553,33 @@ check: if (val) { Py_DECREF(val); const char* plural = i == 1 ? " " : "s 1-"; - return PyErr_Format(PyExc_ValueError, - "map() argument %d is longer than argument%s%d", - i + 1, plural, i); + PyErr_Format(PyExc_ValueError, + "map() argument %d is longer than argument%s%d", + i + 1, plural, i); + goto exit_no_result; } if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_StopIteration)) { // next() on argument i raised an exception (not StopIteration) - return NULL; + goto exit_no_result; } PyErr_Clear(); } // Argument i is exhausted. So far so good... } // All arguments are exhausted. Success! - goto exit; + +exit_no_result: + assert(result == NULL); + +exit: + for (i = 0; i < nargs; i++) { + Py_DECREF(stack[i]); + } + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; } static PyObject * diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7f89c312b9a..07944f624ed 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -11,7 +11,6 @@ #include "pycore_audit.h" // _PySys_Audit() #include "pycore_backoff.h" #include "pycore_cell.h" // PyCell_GetRef() -#include "pycore_ceval.h" #include "pycore_code.h" #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS #include "pycore_function.h" @@ -241,7 +240,7 @@ dummy_func( op(_MONITOR_RESUME, (--)) { int err = _Py_call_instrumentation( - tstate, oparg > 0, frame, this_instr); + tstate, oparg == 0 ? PY_MONITORING_EVENT_PY_START : PY_MONITORING_EVENT_PY_RESUME, frame, this_instr); ERROR_IF(err); if (frame->instr_ptr != this_instr) { /* Instrumentation has jumped */ @@ -615,7 +614,7 @@ dummy_func( EXIT_IF(!_PyLong_IsCompact((PyLongObject *)value_o)); } - pure op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { + pure op(_BINARY_OP_MULTIPLY_INT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyLong_CheckExact(left_o)); @@ -625,12 +624,12 @@ dummy_func( STAT_INC(BINARY_OP, hit); res = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); EXIT_IF(PyStackRef_IsNull(res)); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; INPUTS_DEAD(); } - pure op(_BINARY_OP_ADD_INT, (left, right -- res)) { + pure op(_BINARY_OP_ADD_INT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyLong_CheckExact(left_o)); @@ -640,12 +639,12 @@ dummy_func( STAT_INC(BINARY_OP, hit); res = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); EXIT_IF(PyStackRef_IsNull(res)); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; INPUTS_DEAD(); } - pure op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { + pure op(_BINARY_OP_SUBTRACT_INT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyLong_CheckExact(left_o)); @@ -655,19 +654,19 @@ dummy_func( STAT_INC(BINARY_OP, hit); res = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); EXIT_IF(PyStackRef_IsNull(res)); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; INPUTS_DEAD(); } macro(BINARY_OP_MULTIPLY_INT) = - _GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_MULTIPLY_INT; + _GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_MULTIPLY_INT + _POP_TOP_INT + _POP_TOP_INT; macro(BINARY_OP_ADD_INT) = - _GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_ADD_INT; + _GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_ADD_INT + _POP_TOP_INT + _POP_TOP_INT; macro(BINARY_OP_SUBTRACT_INT) = - _GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_SUBTRACT_INT; + _GUARD_TOS_INT + _GUARD_NOS_INT + unused/5 + _BINARY_OP_SUBTRACT_INT + _POP_TOP_INT + _POP_TOP_INT; op(_GUARD_NOS_FLOAT, (left, unused -- left, unused)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -679,53 +678,7 @@ dummy_func( EXIT_IF(!PyFloat_CheckExact(value_o)); } - pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval * - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - INPUTS_DEAD(); - ERROR_IF(PyStackRef_IsNull(res)); - } - - pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval + - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - INPUTS_DEAD(); - ERROR_IF(PyStackRef_IsNull(res)); - } - - pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval - - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - INPUTS_DEAD(); - ERROR_IF(PyStackRef_IsNull(res)); - } - - - pure op(_BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS, (left, right -- res)) { + pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyFloat_CheckExact(left_o)); @@ -736,11 +689,15 @@ dummy_func( ((PyFloatObject *)left_o)->ob_fval * ((PyFloatObject *)right_o)->ob_fval; res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + ERROR_NO_POP(); + } + l = left; + r = right; INPUTS_DEAD(); - ERROR_IF(PyStackRef_IsNull(res)); } - pure op(_BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS, (left, right -- res)) { + pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyFloat_CheckExact(left_o)); @@ -751,11 +708,15 @@ dummy_func( ((PyFloatObject *)left_o)->ob_fval + ((PyFloatObject *)right_o)->ob_fval; res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + ERROR_NO_POP(); + } + l = left; + r = right; INPUTS_DEAD(); - ERROR_IF(PyStackRef_IsNull(res)); } - pure op(_BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS, (left, right -- res)) { + pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyFloat_CheckExact(left_o)); @@ -766,18 +727,22 @@ dummy_func( ((PyFloatObject *)left_o)->ob_fval - ((PyFloatObject *)right_o)->ob_fval; res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + ERROR_NO_POP(); + } + l = left; + r = right; INPUTS_DEAD(); - ERROR_IF(PyStackRef_IsNull(res)); } macro(BINARY_OP_MULTIPLY_FLOAT) = - _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_MULTIPLY_FLOAT; + _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_MULTIPLY_FLOAT + _POP_TOP_FLOAT + _POP_TOP_FLOAT; macro(BINARY_OP_ADD_FLOAT) = - _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_ADD_FLOAT; + _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_ADD_FLOAT + _POP_TOP_FLOAT + _POP_TOP_FLOAT; macro(BINARY_OP_SUBTRACT_FLOAT) = - _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_SUBTRACT_FLOAT; + _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_SUBTRACT_FLOAT + _POP_TOP_FLOAT + _POP_TOP_FLOAT; - pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { + pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyUnicode_CheckExact(left_o)); @@ -785,15 +750,17 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - INPUTS_DEAD(); - ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + ERROR_NO_POP(); + } + l = left; + r = right; + INPUTS_DEAD(); } macro(BINARY_OP_ADD_UNICODE) = - _GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_ADD_UNICODE; + _GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_ADD_UNICODE + _POP_TOP_UNICODE + _POP_TOP_UNICODE; // This is a subtle one. It's a super-instruction for // BINARY_OP_ADD_UNICODE followed by STORE_FAST @@ -811,7 +778,7 @@ dummy_func( assert(next_instr->op.code == STORE_FAST); next_oparg = next_instr->op.arg; #else - next_oparg = CURRENT_OPERAND0(); + next_oparg = (int)CURRENT_OPERAND0_16(); #endif _PyStackRef *target_local = &GETLOCAL(next_oparg); assert(PyUnicode_CheckExact(left_o)); @@ -983,9 +950,10 @@ dummy_func( DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(PyUnicode_GET_LENGTH(str) <= index); - // Specialize for reading an ASCII character from any string: - Py_UCS4 c = PyUnicode_READ_CHAR(str, index); - DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c); + // Specialize for reading an ASCII character from an ASCII string: + DEOPT_IF(!PyUnicode_IS_COMPACT_ASCII(str)); + uint8_t c = PyUnicode_1BYTE_DATA(str)[index]; + assert(c < 128); STAT_INC(BINARY_OP, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); @@ -1126,9 +1094,9 @@ dummy_func( macro(STORE_SUBSCR) = _SPECIALIZE_STORE_SUBSCR + _STORE_SUBSCR; macro(STORE_SUBSCR_LIST_INT) = - _GUARD_TOS_INT + _GUARD_NOS_LIST + unused/1 + _STORE_SUBSCR_LIST_INT; + _GUARD_TOS_INT + _GUARD_NOS_LIST + unused/1 + _STORE_SUBSCR_LIST_INT + _POP_TOP_INT + POP_TOP; - op(_STORE_SUBSCR_LIST_INT, (value, list_st, sub_st -- )) { + op(_STORE_SUBSCR_LIST_INT, (value, list_st, sub_st -- ls, ss)) { PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); @@ -1151,16 +1119,16 @@ dummy_func( PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); UNLOCK_OBJECT(list); // unlock before decrefs! - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - DEAD(sub_st); - PyStackRef_CLOSE(list_st); + INPUTS_DEAD(); + ls = list_st; + ss = sub_st; Py_DECREF(old_value); } macro(STORE_SUBSCR_DICT) = - _GUARD_NOS_DICT + unused/1 + _STORE_SUBSCR_DICT; + _GUARD_NOS_DICT + unused/1 + _STORE_SUBSCR_DICT + POP_TOP; - op(_STORE_SUBSCR_DICT, (value, dict_st, sub -- )) { + op(_STORE_SUBSCR_DICT, (value, dict_st, sub -- st)) { PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); assert(PyDict_CheckExact(dict)); @@ -1168,8 +1136,12 @@ dummy_func( int err = _PyDict_SetItem_Take2((PyDictObject *)dict, PyStackRef_AsPyObjectSteal(sub), PyStackRef_AsPyObjectSteal(value)); - PyStackRef_CLOSE(dict_st); - ERROR_IF(err); + if (err) { + PyStackRef_CLOSE(dict_st); + ERROR_IF(1); + } + DEAD(dict_st); + st = dict_st; } inst(DELETE_SUBSCR, (container, sub --)) { @@ -1219,7 +1191,7 @@ dummy_func( tstate->current_frame = frame->previous; assert(!_PyErr_Occurred(tstate)); PyObject *result = PyStackRef_AsPyObjectSteal(retval); -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP assert(frame == &entry.frame); #endif #ifdef _Py_TIER2 @@ -1509,7 +1481,7 @@ dummy_func( tier1 inst(CLEANUP_THROW, (sub_iter, last_sent_val, exc_value_st -- none, value)) { PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); - #if !Py_TAIL_CALL_INTERP + #if !_Py_TAIL_CALL_INTERP assert(throwflag); #endif assert(exc_value && PyExceptionInstance_Check(exc_value)); @@ -1977,14 +1949,8 @@ dummy_func( } inst(BUILD_STRING, (pieces[oparg] -- str)) { - STACKREFS_TO_PYOBJECTS(pieces, oparg, pieces_o); - if (CONVERSION_FAILED(pieces_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); - STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); - DECREF_INPUTS(); + PyObject *str_o = _Py_BuildString_StackRefSteal(pieces, oparg); + DEAD(pieces); ERROR_IF(str_o == NULL); str = PyStackRef_FromPyObjectSteal(str_o); } @@ -2099,17 +2065,9 @@ dummy_func( } inst(BUILD_MAP, (values[oparg*2] -- map)) { - STACKREFS_TO_PYOBJECTS(values, oparg*2, values_o); - if (CONVERSION_FAILED(values_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *map_o = _PyDict_FromItems( - values_o, 2, - values_o+1, 2, - oparg); - STACKREFS_TO_PYOBJECTS_CLEANUP(values_o); - DECREF_INPUTS(); + + PyObject *map_o = _Py_BuildMap_StackRefSteal(values, oparg); + DEAD(values); ERROR_IF(map_o == NULL); map = PyStackRef_FromPyObjectStealMortal(map_o); } @@ -2332,20 +2290,22 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION_FT */ } - op(_LOAD_ATTR, (owner -- attr[1], self_or_null[oparg&1])) { + op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ - *attr = PyStackRef_NULL; - int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, attr); + _PyCStackRef method; + _PyThreadState_PushCStackRef(tstate, &method); + int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref); if (is_meth) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. meth | self | arg1 | ... | argN */ - assert(!PyStackRef_IsNull(*attr)); // No errors on this branch + assert(!PyStackRef_IsNull(method.ref)); // No errors on this branch self_or_null[0] = owner; // Transfer ownership DEAD(owner); + attr = _PyThreadState_PopCStackRefSteal(tstate, &method); } else { /* meth is not an unbound method (but a regular attr, or @@ -2355,8 +2315,9 @@ dummy_func( meth | NULL | arg1 | ... | argN */ PyStackRef_CLOSE(owner); - ERROR_IF(PyStackRef_IsNull(*attr)); self_or_null[0] = PyStackRef_NULL; + attr = _PyThreadState_PopCStackRefSteal(tstate, &method); + ERROR_IF(PyStackRef_IsNull(attr)); } } else { @@ -2364,7 +2325,7 @@ dummy_func( PyObject *attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); PyStackRef_CLOSE(owner); ERROR_IF(attr_o == NULL); - *attr = PyStackRef_FromPyObjectSteal(attr_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); } } @@ -2397,7 +2358,7 @@ dummy_func( DEOPT_IF(!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)); } - op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr)) { + op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, o)) { PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); @@ -2411,7 +2372,8 @@ dummy_func( attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); - PyStackRef_CLOSE(owner); + o = owner; + DEAD(owner); } macro(LOAD_ATTR_INSTANCE_VALUE) = @@ -2419,6 +2381,7 @@ dummy_func( _GUARD_TYPE_VERSION + _CHECK_MANAGED_OBJECT_HAS_VALUES + _LOAD_ATTR_INSTANCE_VALUE + + POP_TOP + unused/5 + _PUSH_NULL_CONDITIONAL; @@ -2616,7 +2579,7 @@ dummy_func( } } - op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner --)) { + op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner -- o)) { PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); STAT_INC(STORE_ATTR, hit); @@ -2630,7 +2593,8 @@ dummy_func( _PyDictValues_AddToInsertionOrder(values, index); } UNLOCK_OBJECT(owner_o); - PyStackRef_CLOSE(owner); + o = owner; + DEAD(owner); Py_XDECREF(old_value); } @@ -2638,9 +2602,10 @@ dummy_func( unused/1 + _GUARD_TYPE_VERSION_AND_LOCK + _GUARD_DORV_NO_DICT + - _STORE_ATTR_INSTANCE_VALUE; + _STORE_ATTR_INSTANCE_VALUE + + POP_TOP; - op(_STORE_ATTR_WITH_HINT, (hint/1, value, owner --)) { + op(_STORE_ATTR_WITH_HINT, (hint/1, value, owner -- o)) { PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictObject *dict = _PyObject_GetManagedDict(owner_o); @@ -2670,16 +2635,18 @@ dummy_func( // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, // when dict only holds the strong reference to value in ep->me_value. STAT_INC(STORE_ATTR, hit); - PyStackRef_CLOSE(owner); + o = owner; + DEAD(owner); Py_XDECREF(old_value); } macro(STORE_ATTR_WITH_HINT) = unused/1 + _GUARD_TYPE_VERSION + - _STORE_ATTR_WITH_HINT; + _STORE_ATTR_WITH_HINT + + POP_TOP; - op(_STORE_ATTR_SLOT, (index/1, value, owner --)) { + op(_STORE_ATTR_SLOT, (index/1, value, owner -- o)) { PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); DEOPT_IF(!LOCK_OBJECT(owner_o)); @@ -2688,14 +2655,16 @@ dummy_func( PyObject *old_value = *(PyObject **)addr; FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(owner_o); - PyStackRef_CLOSE(owner); + INPUTS_DEAD(); + o = owner; Py_XDECREF(old_value); } macro(STORE_ATTR_SLOT) = unused/1 + _GUARD_TYPE_VERSION + - _STORE_ATTR_SLOT; + _STORE_ATTR_SLOT + + POP_TOP; family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = { COMPARE_OP_FLOAT, @@ -2740,7 +2709,7 @@ dummy_func( _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/1 + _COMPARE_OP_FLOAT; macro(COMPARE_OP_INT) = - _GUARD_TOS_INT + _GUARD_NOS_INT + unused/1 + _COMPARE_OP_INT; + _GUARD_TOS_INT + _GUARD_NOS_INT + unused/1 + _COMPARE_OP_INT + _POP_TOP_INT + _POP_TOP_INT; macro(COMPARE_OP_STR) = _GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/1 + _COMPARE_OP_STR; @@ -2763,7 +2732,7 @@ dummy_func( } // Similar to COMPARE_OP_FLOAT - op(_COMPARE_OP_INT, (left, right -- res)) { + op(_COMPARE_OP_INT, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); @@ -2776,9 +2745,9 @@ dummy_func( Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; DEAD(left); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); DEAD(right); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; // It's always a bool, so we don't care about oparg & 16. @@ -2939,10 +2908,11 @@ dummy_func( JUMP_BACKWARD_JIT, }; - tier1 op(_SPECIALIZE_JUMP_BACKWARD, (--)) { + specializing tier1 op(_SPECIALIZE_JUMP_BACKWARD, (--)) { #if ENABLE_SPECIALIZATION if (this_instr->op.code == JUMP_BACKWARD) { - this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; + uint8_t desired = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; + FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, desired); // Need to re-dispatch so the warmup counter isn't off by one: next_instr = this_instr; DISPATCH_SAME_OPARG(); @@ -2953,25 +2923,21 @@ dummy_func( tier1 op(_JIT, (--)) { #ifdef _Py_TIER2 _Py_BackoffCounter counter = this_instr[1].counter; - if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) { - _Py_CODEUNIT *start = this_instr; - /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ + if (!IS_JIT_TRACING() && backoff_counter_triggers(counter) && + this_instr->op.code == JUMP_BACKWARD_JIT && + next_instr->op.code != ENTER_EXECUTOR) { + /* Back up over EXTENDED_ARGs so executor is inserted at the correct place */ + _Py_CODEUNIT *insert_exec_at = this_instr; while (oparg > 255) { oparg >>= 8; - start--; + insert_exec_at--; } - _PyExecutorObject *executor; - int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0); - if (optimized <= 0) { - this_instr[1].counter = restart_backoff_counter(counter); - ERROR_IF(optimized < 0); + int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg); + if (succ) { + ENTER_TRACING(); } else { - this_instr[1].counter = initial_jump_backoff_counter(); - assert(tstate->current_executor == NULL); - assert(executor != tstate->interp->cold_executor); - tstate->jit_exit = NULL; - TIER1_TO_TIER2(executor); + this_instr[1].counter = restart_backoff_counter(counter); } } else { @@ -3017,6 +2983,10 @@ dummy_func( tier1 inst(ENTER_EXECUTOR, (--)) { #ifdef _Py_TIER2 + if (IS_JIT_TRACING()) { + next_instr = this_instr; + goto stop_tracing; + } PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; assert(executor->vm_data.index == INSTR_OFFSET() - 1); @@ -3078,7 +3048,7 @@ dummy_func( macro(POP_JUMP_IF_NOT_NONE) = unused/1 + _IS_NONE + _POP_JUMP_IF_FALSE; - tier1 inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { + replaced inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -3689,7 +3659,7 @@ dummy_func( #if ENABLE_SPECIALIZATION_FT if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; - _Py_Specialize_Call(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null)); + _Py_Specialize_Call(callable, self_or_null, next_instr, oparg + !PyStackRef_IsNull(self_or_null)); DISPATCH_SAME_OPARG(); } OPCODE_DEFERRED_INC(CALL); @@ -3891,27 +3861,20 @@ dummy_func( #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } - /* Callable is not a normal Python function */ - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *res_o = PyObject_Vectorcall( - callable_o, args_o, - total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); + PyObject *res_o = _Py_VectorCall_StackRefSteal( + callable, + arguments, + total_args, + PyStackRef_NULL); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4057,18 +4020,17 @@ dummy_func( DEOPT_IF(callable_o != (PyObject *)&PyUnicode_Type); } - op(_CALL_STR_1, (callable, null, arg -- res)) { + op(_CALL_STR_1, (callable, null, arg -- res, a)) { PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); STAT_INC(CALL, hit); PyObject *res_o = PyObject_Str(arg_o); - DEAD(null); - DEAD(callable); - (void)callable; // Silence compiler warnings about unused variables - (void)null; - PyStackRef_CLOSE(arg); - ERROR_IF(res_o == NULL); + if (res_o == NULL) { + ERROR_NO_POP(); + } + a = arg; + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4078,6 +4040,7 @@ dummy_func( _GUARD_NOS_NULL + _GUARD_CALLABLE_STR_1 + _CALL_STR_1 + + POP_TOP + _CHECK_PERIODIC_AT_END; op(_GUARD_CALLABLE_TUPLE_1, (callable, unused, unused -- callable, unused, unused)) { @@ -4085,18 +4048,17 @@ dummy_func( DEOPT_IF(callable_o != (PyObject *)&PyTuple_Type); } - op(_CALL_TUPLE_1, (callable, null, arg -- res)) { + op(_CALL_TUPLE_1, (callable, null, arg -- res, a)) { PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); STAT_INC(CALL, hit); PyObject *res_o = PySequence_Tuple(arg_o); - DEAD(null); - DEAD(callable); - (void)callable; // Silence compiler warnings about unused variables - (void)null; - PyStackRef_CLOSE(arg); - ERROR_IF(res_o == NULL); + if (res_o == NULL) { + ERROR_NO_POP(); + } + a = arg; + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4106,6 +4068,7 @@ dummy_func( _GUARD_NOS_NULL + _GUARD_CALLABLE_TUPLE_1 + _CALL_TUPLE_1 + + POP_TOP + _CHECK_PERIODIC_AT_END; op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { @@ -4186,14 +4149,13 @@ dummy_func( } DEOPT_IF(tp->tp_vectorcall == NULL); STAT_INC(CALL, hit); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - DECREF_INPUTS(); + PyObject *res_o = _Py_CallBuiltinClass_StackRefSteal( + callable, + arguments, + total_args); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4204,7 +4166,7 @@ dummy_func( _CALL_BUILTIN_CLASS + _CHECK_PERIODIC_AT_END; - op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res)) { + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, a, c)) { /* Builtin METH_O functions */ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4224,12 +4186,12 @@ dummy_func( PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable_o), PyStackRef_AsPyObjectBorrow(arg)); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - - PyStackRef_CLOSE(arg); - DEAD(args); - DEAD(self_or_null); - PyStackRef_CLOSE(callable); - ERROR_IF(res_o == NULL); + if (res_o == NULL) { + ERROR_NO_POP(); + } + a = arg; + c = callable; + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4237,35 +4199,30 @@ dummy_func( unused/1 + unused/2 + _CALL_BUILTIN_O + + POP_TOP + + POP_TOP + _CHECK_PERIODIC_AT_END; op(_CALL_BUILTIN_FAST, (callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); DEOPT_IF(!PyCFunction_CheckExact(callable_o)); DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL); STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - /* res = func(self, args, nargs) */ - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *res_o = _PyCFunctionFast_CAST(cfunc)( - PyCFunction_GET_SELF(callable_o), - args_o, - total_args); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); + PyObject *res_o = _Py_BuiltinCallFast_StackRefSteal( + callable, + arguments, + total_args + ); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4278,30 +4235,20 @@ dummy_func( op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); DEOPT_IF(!PyCFunction_CheckExact(callable_o)); DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)); STAT_INC(CALL, hit); - /* res = func(self, arguments, nargs, kwnames) */ - PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o)); - - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); + PyObject *res_o = _Py_BuiltinCallFastWithKeywords_StackRefSteal(callable, arguments, total_args); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4317,7 +4264,9 @@ dummy_func( unused/2 + _GUARD_NOS_NULL + _GUARD_CALLABLE_LEN + - _CALL_LEN; + _CALL_LEN + + POP_TOP + + POP_TOP; op(_GUARD_CALLABLE_LEN, (callable, unused, unused -- callable, unused, unused)){ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4325,9 +4274,8 @@ dummy_func( DEOPT_IF(callable_o != interp->callable_cache.len); } - op(_CALL_LEN, (callable, null, arg -- res)) { + op(_CALL_LEN, (callable, null, arg -- res, a, c)) { /* len(o) */ - (void)null; STAT_INC(CALL, hit); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); Py_ssize_t len_i = PyObject_Length(arg_o); @@ -4339,9 +4287,9 @@ dummy_func( if (res_o == NULL) { ERROR_NO_POP(); } - PyStackRef_CLOSE(arg); - DEAD(null); - PyStackRef_CLOSE(callable); + a = arg; + c = callable; + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4382,7 +4330,9 @@ dummy_func( _GUARD_CALLABLE_LIST_APPEND + _GUARD_NOS_NOT_NULL + _GUARD_NOS_LIST + - _CALL_LIST_APPEND; + _CALL_LIST_APPEND + + POP_TOP + + POP_TOP; op(_GUARD_CALLABLE_LIST_APPEND, (callable, unused, unused -- callable, unused, unused)){ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4391,18 +4341,20 @@ dummy_func( } // This is secretly a super-instruction - op(_CALL_LIST_APPEND, (callable, self, arg -- )) { + op(_CALL_LIST_APPEND, (callable, self, arg -- c, s)) { assert(oparg == 1); PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); - DEOPT_IF(!PyList_CheckExact(self_o)); DEOPT_IF(!LOCK_OBJECT(self_o)); STAT_INC(CALL, hit); int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); UNLOCK_OBJECT(self_o); - PyStackRef_CLOSE(self); - PyStackRef_CLOSE(callable); - ERROR_IF(err); + if (err) { + ERROR_NO_POP(); + } + c = callable; + s = self; + INPUTS_DEAD(); #if TIER_ONE // Skip the following POP_TOP. This is done here in tier one, and // during trace projection in tier two: @@ -4469,19 +4421,16 @@ dummy_func( assert(self != NULL); EXIT_IF(!Py_IS_TYPE(self, d_type)); STAT_INC(CALL, hit); - int nargs = total_args - 1; - - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(meth->ml_meth); - PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); + PyObject *res_o = _PyCallMethodDescriptorFastWithKeywords_StackRefSteal( + callable, + meth, + self, + arguments, + total_args + ); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4549,18 +4498,16 @@ dummy_func( assert(self != NULL); EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); STAT_INC(CALL, hit); - int nargs = total_args - 1; - - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth); - PyObject *res_o = cfunc(self, (args_o + 1), nargs); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); + PyObject *res_o = _PyCallMethodDescriptorFast_StackRefSteal( + callable, + meth, + self, + arguments, + total_args + ); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4793,30 +4740,21 @@ dummy_func( #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } - /* Callable is not a normal Python function */ - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true); - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); - PyObject *res_o = PyObject_Vectorcall( - callable_o, args_o, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames_o); - PyStackRef_CLOSE(kwnames); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); + PyObject *res_o = _Py_VectorCall_StackRefSteal( + callable, + arguments, + total_args, + kwnames); + DEAD(kwnames); + DEAD(args); + DEAD(self_or_null); + DEAD(callable); ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -5245,21 +5183,42 @@ dummy_func( tier2 op(_EXIT_TRACE, (exit_p/4 --)) { _PyExitData *exit = (_PyExitData *)exit_p; #if defined(Py_DEBUG) && !defined(_Py_JIT) - _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; + const _Py_CODEUNIT *target = ((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame)) + + exit->target; OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); - if (frame->lltrace >= 2) { + if (frame->lltrace >= 3) { printf("SIDE EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); - printf(", exit %lu, temp %d, target %d -> %s]\n", + printf(", exit %tu, temp %d, target %d -> %s, is_control_flow %d]\n", exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyFrame_GetBytecode(frame)), - _PyOpcode_OpName[target->op.code]); + _PyOpcode_OpName[target->op.code], exit->is_control_flow); } #endif tstate->jit_exit = exit; TIER2_TO_TIER2(exit->executor); } + tier2 op(_DYNAMIC_EXIT, (exit_p/4 --)) { + #if defined(Py_DEBUG) && !defined(_Py_JIT) + _PyExitData *exit = (_PyExitData *)exit_p; + _Py_CODEUNIT *target = frame->instr_ptr; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + printf("DYNAMIC EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code]); + } + #endif + // Disabled for now (gh-139109) as it slows down dynamic code tremendously. + // Compile and jump to the cold dynamic executors in the future. + GOTO_TIER_ONE(frame->instr_ptr); + } + tier2 op(_CHECK_VALIDITY, (--)) { DEOPT_IF(!current_executor->vm_data.valid); } @@ -5345,12 +5304,6 @@ dummy_func( value = PyStackRef_FromPyObjectBorrow(ptr); } - tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) { - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - DEOPT_IF(func->func_version != func_version); - } - tier2 op(_START_EXECUTOR, (executor/4 --)) { #ifndef _Py_JIT assert(current_executor == (_PyExecutorObject*)executor); @@ -5367,10 +5320,6 @@ dummy_func( tier2 op(_MAKE_WARM, (--)) { current_executor->vm_data.warm = true; - // It's okay if this ends up going negative. - if (--tstate->interp->trace_run_counter == 0) { - _Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT); - } } tier2 op(_FATAL_ERROR, (--)) { @@ -5379,12 +5328,17 @@ dummy_func( } tier2 op(_DEOPT, (--)) { - GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + SYNC_SP(); + GOTO_TIER_ONE((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + Py_UNREACHABLE(); } tier2 op(_HANDLE_PENDING_AND_DEOPT, (--)) { + SYNC_SP(); int err = _Py_HandlePending(tstate); GOTO_TIER_ONE(err ? NULL : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + Py_UNREACHABLE(); } tier2 op(_ERROR_POP_N, (target/2 --)) { @@ -5392,6 +5346,10 @@ dummy_func( frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; SYNC_SP(); GOTO_TIER_ONE(NULL); + Py_UNREACHABLE(); + } + + tier2 op(_SPILL_OR_RELOAD, (--)) { } /* Progress is guaranteed if we DEOPT on the eval breaker, because @@ -5409,32 +5367,80 @@ dummy_func( tier2 op(_COLD_EXIT, ( -- )) { _PyExitData *exit = tstate->jit_exit; assert(exit != NULL); + assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; _Py_BackoffCounter temperature = exit->temperature; - if (!backoff_counter_triggers(temperature)) { - exit->temperature = advance_backoff_counter(temperature); - GOTO_TIER_ONE(target); - } _PyExecutorObject *executor; if (target->op.code == ENTER_EXECUTOR) { PyCodeObject *code = _PyFrame_GetCode(frame); executor = code->co_executors->executors[target->op.arg]; Py_INCREF(executor); + assert(tstate->jit_exit == exit); + exit->executor = executor; + TIER2_TO_TIER2(exit->executor); } else { + SYNC_SP(); + if (!backoff_counter_triggers(temperature)) { + exit->temperature = advance_backoff_counter(temperature); + GOTO_TIER_ONE(target); + } _PyExecutorObject *previous_executor = _PyExecutor_FromExit(exit); assert(tstate->current_executor == (PyObject *)previous_executor); - int chain_depth = previous_executor->vm_data.chain_depth + 1; - int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth); - if (optimized <= 0) { - exit->temperature = restart_backoff_counter(temperature); - GOTO_TIER_ONE(optimized < 0 ? NULL : target); + // For control-flow guards, we don't want to increase the chain depth, as those don't actually + // represent deopts but rather just normal programs! + int chain_depth = previous_executor->vm_data.chain_depth + !exit->is_control_flow; + // Note: it's safe to use target->op.arg here instead of the oparg given by EXTENDED_ARG. + // The invariant in the optimizer is the deopt target always points back to the first EXTENDED_ARG. + // So setting it to anything else is wrong. + int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg); + exit->temperature = restart_backoff_counter(exit->temperature); + if (succ) { + GOTO_TIER_ONE_CONTINUE_TRACING(target); } - exit->temperature = initial_temperature_backoff_counter(); + GOTO_TIER_ONE(target); + Py_UNREACHABLE(); + } + } + + tier2 op(_COLD_DYNAMIC_EXIT, ( -- )) { + SYNC_SP(); + // TODO (gh-139109): This should be similar to _COLD_EXIT in the future. + _Py_CODEUNIT *target = frame->instr_ptr; + GOTO_TIER_ONE(target); + Py_UNREACHABLE(); + } + + tier2 op(_GUARD_IP__PUSH_FRAME, (ip/4 --)) { + _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(_PUSH_FRAME); + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += IP_OFFSET_OF(_PUSH_FRAME); + EXIT_IF(true); + } + } + + tier2 op(_GUARD_IP_YIELD_VALUE, (ip/4 --)) { + _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(YIELD_VALUE); + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += IP_OFFSET_OF(YIELD_VALUE); + EXIT_IF(true); + } + } + + tier2 op(_GUARD_IP_RETURN_VALUE, (ip/4 --)) { + _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(RETURN_VALUE); + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += IP_OFFSET_OF(RETURN_VALUE); + EXIT_IF(true); + } + } + + tier2 op(_GUARD_IP_RETURN_GENERATOR, (ip/4 --)) { + _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(RETURN_GENERATOR); + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += IP_OFFSET_OF(RETURN_GENERATOR); + EXIT_IF(true); } - assert(tstate->jit_exit == exit); - exit->executor = executor; - TIER2_TO_TIER2(exit->executor); } label(pop_2_error) { @@ -5521,7 +5527,7 @@ dummy_func( } #endif RELOAD_STACK(); -#if Py_TAIL_CALL_INTERP +#if _Py_TAIL_CALL_INTERP int opcode; #endif DISPATCH(); @@ -5539,7 +5545,7 @@ dummy_func( if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { /* Restore previous frame and exit */ tstate->current_frame = frame->previous; -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP assert(frame == &entry.frame); #endif #ifdef _Py_TIER2 @@ -5575,12 +5581,71 @@ dummy_func( assert(!_PyErr_Occurred(tstate)); #endif RELOAD_STACK(); -#if Py_TAIL_CALL_INTERP +#if _Py_TAIL_CALL_INTERP int opcode; #endif DISPATCH(); } + inst(TRACE_RECORD, (--)) { +#if _Py_TIER2 + assert(IS_JIT_TRACING()); + next_instr = this_instr; + frame->instr_ptr = prev_instr; + opcode = next_instr->op.code; + bool stop_tracing = (opcode == WITH_EXCEPT_START || + opcode == RERAISE || opcode == CLEANUP_THROW || + opcode == PUSH_EXC_INFO || opcode == INTERPRETER_EXIT); + int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing ? _DEOPT : 0); + if (full) { + LEAVE_TRACING(); + int err = stop_tracing_and_jit(tstate, frame); + ERROR_IF(err < 0); + DISPATCH(); + } + // Super instructions. Instruction deopted. There's a mismatch in what the stack expects + // in the optimizer. So we have to reflect in the trace correctly. + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + if ((_tstate->jit_tracer_state.prev_state.instr->op.code == CALL_LIST_APPEND && + opcode == POP_TOP) || + (_tstate->jit_tracer_state.prev_state.instr->op.code == BINARY_OP_INPLACE_ADD_UNICODE && + opcode == STORE_FAST)) { + _tstate->jit_tracer_state.prev_state.instr_is_super = true; + } + else { + _tstate->jit_tracer_state.prev_state.instr = next_instr; + } + PyObject *prev_code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + if (_tstate->jit_tracer_state.prev_state.instr_code != (PyCodeObject *)prev_code) { + Py_SETREF(_tstate->jit_tracer_state.prev_state.instr_code, (PyCodeObject*)Py_NewRef((prev_code))); + } + + _tstate->jit_tracer_state.prev_state.instr_frame = frame; + _tstate->jit_tracer_state.prev_state.instr_oparg = oparg; + _tstate->jit_tracer_state.prev_state.instr_stacklevel = PyStackRef_IsNone(frame->f_executable) ? 2 : STACK_LEVEL(); + if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { + (&next_instr[1])->counter = trigger_backoff_counter(); + } + DISPATCH_GOTO_NON_TRACING(); +#else + (void)prev_instr; + Py_FatalError("JIT instruction executed in non-jit build."); +#endif + } + + label(stop_tracing) { +#if _Py_TIER2 + assert(IS_JIT_TRACING()); + int opcode = next_instr->op.code; + _PyJit_translate_single_bytecode_to_trace(tstate, frame, NULL, _EXIT_TRACE); + LEAVE_TRACING(); + int err = stop_tracing_and_jit(tstate, frame); + ERROR_IF(err < 0); + DISPATCH_GOTO_NON_TRACING(); +#else + Py_FatalError("JIT label executed in non-jit build."); +#endif + } // END BYTECODES // diff --git a/Python/ceval.c b/Python/ceval.c index 578c5d2a8b1..90ae0b022e3 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -160,6 +160,10 @@ dump_item(_PyStackRef item) printf("<NULL>"); return; } + if (PyStackRef_IsMalformed(item)) { + printf("<INVALID>"); + return; + } if (PyStackRef_IsTaggedInt(item)) { printf("%" PRId64, (int64_t)PyStackRef_UntagInt(item)); return; @@ -206,6 +210,19 @@ dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) _PyFrame_GetStackPointer(frame); } +#if defined(_Py_TIER2) && !defined(_Py_JIT) && defined(Py_DEBUG) +static void +dump_cache_item(_PyStackRef cache, int position, int depth) +{ + if (position < depth) { + dump_item(cache); + } + else { + printf("---"); + } +} +#endif + static void lltrace_instruction(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, @@ -347,13 +364,23 @@ _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count) { uintptr_t here_addr = _Py_get_machine_stack_pointer(); _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; +#if _Py_STACK_GROWS_DOWN if (here_addr > _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES) { +#else + if (here_addr <= _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES) { +#endif return 0; } if (_tstate->c_stack_hard_limit == 0) { _Py_InitializeRecursionLimits(tstate); } - return here_addr <= _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES; +#if _Py_STACK_GROWS_DOWN + return here_addr <= _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES && + here_addr >= _tstate->c_stack_soft_limit - 2 * _PyOS_STACK_MARGIN_BYTES; +#else + return here_addr > _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES && + here_addr <= _tstate->c_stack_soft_limit + 2 * _PyOS_STACK_MARGIN_BYTES; +#endif } void @@ -361,7 +388,11 @@ _Py_EnterRecursiveCallUnchecked(PyThreadState *tstate) { uintptr_t here_addr = _Py_get_machine_stack_pointer(); _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; +#if _Py_STACK_GROWS_DOWN if (here_addr < _tstate->c_stack_hard_limit) { +#else + if (here_addr > _tstate->c_stack_hard_limit) { +#endif Py_FatalError("Unchecked stack overflow."); } } @@ -438,24 +469,26 @@ int pthread_attr_destroy(pthread_attr_t *a) #endif - -void -_Py_InitializeRecursionLimits(PyThreadState *tstate) +static void +hardware_stack_limits(uintptr_t *base, uintptr_t *top, uintptr_t sp) { - _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; #ifdef WIN32 ULONG_PTR low, high; GetCurrentThreadStackLimits(&low, &high); - _tstate->c_stack_top = (uintptr_t)high; + *top = (uintptr_t)high; ULONG guarantee = 0; SetThreadStackGuarantee(&guarantee); - _tstate->c_stack_hard_limit = ((uintptr_t)low) + guarantee + _PyOS_STACK_MARGIN_BYTES; - _tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES; + *base = (uintptr_t)low + guarantee; +#elif defined(__APPLE__) + pthread_t this_thread = pthread_self(); + void *stack_addr = pthread_get_stackaddr_np(this_thread); // top of the stack + size_t stack_size = pthread_get_stacksize_np(this_thread); + *top = (uintptr_t)stack_addr; + *base = ((uintptr_t)stack_addr) - stack_size; #else - uintptr_t here_addr = _Py_get_machine_stack_pointer(); -/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size -/// (on alpine at least) is much smaller than expected and imposes undue limits -/// compared to the old stack size estimation. (We assume musl is not glibc.) + /// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size + /// (on alpine at least) is much smaller than expected and imposes undue limits + /// compared to the old stack size estimation. (We assume musl is not glibc.) # if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \ !defined(__NetBSD__) && (defined(__GLIBC__) || !defined(__linux__)) size_t stack_size, guard_size; @@ -468,28 +501,118 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate) err |= pthread_attr_destroy(&attr); } if (err == 0) { - uintptr_t base = ((uintptr_t)stack_addr) + guard_size; - _tstate->c_stack_top = base + stack_size; -#ifdef _Py_THREAD_SANITIZER - // Thread sanitizer crashes if we use a bit more than half the stack. - _tstate->c_stack_soft_limit = base + (stack_size / 2); -#else - _tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2; -#endif - _tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES; - assert(_tstate->c_stack_soft_limit < here_addr); - assert(here_addr < _tstate->c_stack_top); + *base = ((uintptr_t)stack_addr) + guard_size; + *top = (uintptr_t)stack_addr + stack_size; return; } # endif - _tstate->c_stack_top = _Py_SIZE_ROUND_UP(here_addr, 4096); - _tstate->c_stack_soft_limit = _tstate->c_stack_top - Py_C_STACK_SIZE; - _tstate->c_stack_hard_limit = _tstate->c_stack_top - (Py_C_STACK_SIZE + _PyOS_STACK_MARGIN_BYTES); + // Add some space for caller function then round to minimum page size + // This is a guess at the top of the stack, but should be a reasonably + // good guess if called from _PyThreadState_Attach when creating a thread. + // If the thread is attached deep in a call stack, then the guess will be poor. +#if _Py_STACK_GROWS_DOWN + uintptr_t top_addr = _Py_SIZE_ROUND_UP(sp + 8*sizeof(void*), SYSTEM_PAGE_SIZE); + *top = top_addr; + *base = top_addr - Py_C_STACK_SIZE; +# else + uintptr_t base_addr = _Py_SIZE_ROUND_DOWN(sp - 8*sizeof(void*), SYSTEM_PAGE_SIZE); + *base = base_addr; + *top = base_addr + Py_C_STACK_SIZE; +#endif #endif } +static void +tstate_set_stack(PyThreadState *tstate, + uintptr_t base, uintptr_t top) +{ + assert(base < top); + assert((top - base) >= _PyOS_MIN_STACK_SIZE); + +#ifdef _Py_THREAD_SANITIZER + // Thread sanitizer crashes if we use more than half the stack. + uintptr_t stacksize = top - base; +# if _Py_STACK_GROWS_DOWN + base += stacksize/2; +# else + top -= stacksize/2; +# endif +#endif + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; +#if _Py_STACK_GROWS_DOWN + _tstate->c_stack_top = top; + _tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES; + _tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2; +# ifndef NDEBUG + // Sanity checks + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; + assert(ts->c_stack_hard_limit <= ts->c_stack_soft_limit); + assert(ts->c_stack_soft_limit < ts->c_stack_top); +# endif +#else + _tstate->c_stack_top = base; + _tstate->c_stack_hard_limit = top - _PyOS_STACK_MARGIN_BYTES; + _tstate->c_stack_soft_limit = top - _PyOS_STACK_MARGIN_BYTES * 2; +# ifndef NDEBUG + // Sanity checks + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; + assert(ts->c_stack_hard_limit >= ts->c_stack_soft_limit); + assert(ts->c_stack_soft_limit > ts->c_stack_top); +# endif +#endif +} + + +void +_Py_InitializeRecursionLimits(PyThreadState *tstate) +{ + uintptr_t base, top; + uintptr_t here_addr = _Py_get_machine_stack_pointer(); + hardware_stack_limits(&base, &top, here_addr); + assert(top != 0); + + tstate_set_stack(tstate, base, top); + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; + ts->c_stack_init_base = base; + ts->c_stack_init_top = top; +} + + +int +PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, + void *stack_start_addr, size_t stack_size) +{ + if (stack_size < _PyOS_MIN_STACK_SIZE) { + PyErr_Format(PyExc_ValueError, + "stack_size must be at least %zu bytes", + _PyOS_MIN_STACK_SIZE); + return -1; + } + + uintptr_t base = (uintptr_t)stack_start_addr; + uintptr_t top = base + stack_size; + tstate_set_stack(tstate, base, top); + return 0; +} + + +void +PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate) +{ + _PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; + if (ts->c_stack_init_top != 0) { + tstate_set_stack(tstate, + ts->c_stack_init_base, + ts->c_stack_init_top); + return; + } + + _Py_InitializeRecursionLimits(tstate); +} + + /* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall() - if the recursion_depth reaches recursion_limit. */ + if the stack pointer is between the stack base and c_stack_hard_limit. */ int _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { @@ -497,9 +620,17 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) uintptr_t here_addr = _Py_get_machine_stack_pointer(); assert(_tstate->c_stack_soft_limit != 0); assert(_tstate->c_stack_hard_limit != 0); +#if _Py_STACK_GROWS_DOWN + assert(here_addr >= _tstate->c_stack_hard_limit - _PyOS_STACK_MARGIN_BYTES); if (here_addr < _tstate->c_stack_hard_limit) { /* Overflowing while handling an overflow. Give up. */ int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024; +#else + assert(here_addr <= _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES); + if (here_addr > _tstate->c_stack_hard_limit) { + /* Overflowing while handling an overflow. Give up. */ + int kbytes_used = (int)(here_addr - _tstate->c_stack_top)/1024; +#endif char buffer[80]; snprintf(buffer, 80, "Unrecoverable stack overflow (used %d kB)%s", kbytes_used, where); Py_FatalError(buffer); @@ -508,7 +639,11 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) return 0; } else { +#if _Py_STACK_GROWS_DOWN int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024; +#else + int kbytes_used = (int)(here_addr - _tstate->c_stack_top)/1024; +#endif tstate->recursion_headroom++; _PyErr_Format(tstate, PyExc_RecursionError, "Stack overflow (used %d kB)%s", @@ -895,6 +1030,283 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #include "ceval_macros.h" + +/* Helper functions to keep the size of the largest uops down */ + +PyObject * +_Py_VectorCall_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args, + _PyStackRef kwnames) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); + int positional_args = total_args; + if (kwnames_o != NULL) { + positional_args -= (int)PyTuple_GET_SIZE(kwnames_o); + } + res = PyObject_Vectorcall( + callable_o, args_o, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames_o); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + PyStackRef_XCLOSE(kwnames); + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + PyStackRef_CLOSE(callable); + return res; +} + +PyObject * +_Py_BuiltinCallFast_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); + res = _PyCFunctionFast_CAST(cfunc)( + PyCFunction_GET_SELF(callable_o), + args_o, + total_args + ); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + PyStackRef_CLOSE(callable); + return res; +} + +PyObject * +_Py_BuiltinCallFastWithKeywords_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyCFunctionFastWithKeywords cfunc = + _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o)); + res = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + PyStackRef_CLOSE(callable); + return res; +} + +PyObject * +_PyCallMethodDescriptorFast_StackRefSteal( + _PyStackRef callable, + PyMethodDef *meth, + PyObject *self, + _PyStackRef *arguments, + int total_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + assert(((PyMethodDescrObject *)PyStackRef_AsPyObjectBorrow(callable))->d_method == meth); + assert(self == PyStackRef_AsPyObjectBorrow(arguments[0])); + + PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth); + res = cfunc(self, (args_o + 1), total_args - 1); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + PyStackRef_CLOSE(callable); + return res; +} + +PyObject * +_PyCallMethodDescriptorFastWithKeywords_StackRefSteal( + _PyStackRef callable, + PyMethodDef *meth, + PyObject *self, + _PyStackRef *arguments, + int total_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + assert(((PyMethodDescrObject *)PyStackRef_AsPyObjectBorrow(callable))->d_method == meth); + assert(self == PyStackRef_AsPyObjectBorrow(arguments[0])); + + PyCFunctionFastWithKeywords cfunc = + _PyCFunctionFastWithKeywords_CAST(meth->ml_meth); + res = cfunc(self, (args_o + 1), total_args-1, NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + PyStackRef_CLOSE(callable); + return res; +} + +PyObject * +_Py_CallBuiltinClass_StackRefSteal( + _PyStackRef callable, + _PyStackRef *arguments, + int total_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + PyTypeObject *tp = (PyTypeObject *)PyStackRef_AsPyObjectBorrow(callable); + res = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + PyStackRef_CLOSE(callable); + return res; +} + +PyObject * +_Py_BuildString_StackRefSteal( + _PyStackRef *arguments, + int total_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + res = _PyUnicode_JoinArray(&_Py_STR(empty), args_o, total_args); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = total_args-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + return res; +} + +PyObject * +_Py_BuildMap_StackRefSteal( + _PyStackRef *arguments, + int half_args) +{ + PyObject *res; + STACKREFS_TO_PYOBJECTS(arguments, half_args*2, args_o); + if (CONVERSION_FAILED(args_o)) { + res = NULL; + goto cleanup; + } + res = _PyDict_FromItems( + args_o, 2, + args_o+1, 2, + half_args + ); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res != NULL) ^ (PyErr_Occurred() != NULL)); +cleanup: + // arguments is a pointer into the GC visible stack, + // so we must NULL out values as we clear them. + for (int i = half_args*2-1; i >= 0; i--) { + _PyStackRef tmp = arguments[i]; + arguments[i] = PyStackRef_NULL; + PyStackRef_CLOSE(tmp); + } + return res; +} + +#ifdef Py_DEBUG +void +_Py_assert_within_stack_bounds( + _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, + const char *filename, int lineno +) { + if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { + return; + } + int level = (int)(stack_pointer - _PyFrame_Stackbase(frame)); + if (level < 0) { + printf("Stack underflow (depth = %d) at %s:%d\n", level, filename, lineno); + fflush(stdout); + abort(); + } + int size = _PyFrame_GetCode(frame)->co_stacksize; + if (level > size) { + printf("Stack overflow (depth = %d) at %s:%d\n", level, filename, lineno); + fflush(stdout); + abort(); + } +} +#endif + int _Py_CheckRecursiveCallPy( PyThreadState *tstate) { @@ -926,6 +1338,8 @@ static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { { .op.code = RESUME, .op.arg = RESUME_OPARG_DEPTH1_MASK | RESUME_AT_FUNC_START } }; +const _Py_CODEUNIT *_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR = (_Py_CODEUNIT*)&_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS; + #ifdef Py_DEBUG extern void _PyUOpPrint(const _PyUOpInstruction *uop); #endif @@ -954,11 +1368,12 @@ _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject if (result == NULL) { return NULL; } - result++; } else { result = scratch; } + result++; + result[0] = NULL; /* Keep GCC happy */ for (int i = 0; i < nargs; i++) { result[i] = PyStackRef_AsPyObjectBorrow(input[i]); } @@ -973,6 +1388,49 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) } } +#ifdef Py_DEBUG +#define ASSERT_WITHIN_STACK_BOUNDS(F, L) _Py_assert_within_stack_bounds(frame, stack_pointer, (F), (L)) +#else +#define ASSERT_WITHIN_STACK_BOUNDS(F, L) (void)0 +#endif + +#if _Py_TIER2 +// 0 for success, -1 for error. +static int +stop_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame) +{ + int _is_sys_tracing = (tstate->c_tracefunc != NULL) || (tstate->c_profilefunc != NULL); + int err = 0; + if (!_PyErr_Occurred(tstate) && !_is_sys_tracing) { + err = _PyOptimizer_Optimize(frame, tstate); + } + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + // Deal with backoffs + _PyExitData *exit = _tstate->jit_tracer_state.initial_state.exit; + if (exit == NULL) { + // We hold a strong reference to the code object, so the instruction won't be freed. + if (err <= 0) { + _Py_BackoffCounter counter = _tstate->jit_tracer_state.initial_state.jump_backward_instr[1].counter; + _tstate->jit_tracer_state.initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter); + } + else { + _tstate->jit_tracer_state.initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(); + } + } + else { + // Likewise, we hold a strong reference to the executor containing this exit, so the exit is guaranteed + // to be valid to access. + if (err <= 0) { + exit->temperature = restart_backoff_counter(exit->temperature); + } + else { + exit->temperature = initial_temperature_backoff_counter(); + } + } + _PyJit_FinalizeTracing(tstate); + return err; +} +#endif /* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC. */ @@ -987,7 +1445,7 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch) /* This setting is reversed below following _PyEval_EvalFrameDefault */ #endif -#if Py_TAIL_CALL_INTERP +#if _Py_TAIL_CALL_INTERP #include "opcode_targets.h" #include "generated_cases.c.h" #endif @@ -1019,18 +1477,23 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int check_invalid_reentrancy(); CALL_STAT_INC(pyeval_calls); -#if USE_COMPUTED_GOTOS && !Py_TAIL_CALL_INTERP +#if USE_COMPUTED_GOTOS && !_Py_TAIL_CALL_INTERP /* Import the static jump table */ #include "opcode_targets.h" + void **opcode_targets = opcode_targets_table; #endif #ifdef Py_STATS int lastopcode = 0; #endif -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP uint8_t opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL); +#if !USE_COMPUTED_GOTOS + uint8_t tracing_mode = 0; + uint8_t dispatch_code; +#endif #endif _PyEntryFrame entry; @@ -1099,22 +1562,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int next_instr = frame->instr_ptr; monitor_throw(tstate, frame, next_instr); stack_pointer = _PyFrame_GetStackPointer(frame); -#if Py_TAIL_CALL_INTERP +#if _Py_TAIL_CALL_INTERP # if Py_STATS - return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0, lastopcode); + return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, instruction_funcptr_handler_table, 0, lastopcode); # else - return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); + return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, instruction_funcptr_handler_table, 0); # endif #else goto error; #endif } -#if Py_TAIL_CALL_INTERP +#if _Py_TAIL_CALL_INTERP # if Py_STATS - return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0, lastopcode); + return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, instruction_funcptr_handler_table, 0, lastopcode); # else - return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0); + return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, instruction_funcptr_handler_table, 0); # endif #else goto start_frame; @@ -1153,10 +1616,20 @@ _PyTier2Interpreter( ) { const _PyUOpInstruction *next_uop; int oparg; + /* Set up "jit" state after entry from tier 1. + * This mimics what the jit trampoline function does. */ + tstate->jit_exit = NULL; + _PyStackRef _tos_cache0 = PyStackRef_ZERO_BITS; + _PyStackRef _tos_cache1 = PyStackRef_ZERO_BITS; + _PyStackRef _tos_cache2 = PyStackRef_ZERO_BITS; + int current_cached_values = 0; + tier2_start: next_uop = current_executor->trace; - assert(next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT); + assert(next_uop->opcode == _START_EXECUTOR_r00 + current_cached_values || + next_uop->opcode == _COLD_EXIT_r00 + current_cached_values || + next_uop->opcode == _COLD_DYNAMIC_EXIT_r00 + current_cached_values); #undef LOAD_IP #define LOAD_IP(UNUSED) (void)0 @@ -1180,14 +1653,23 @@ tier2_start: uint64_t trace_uop_execution_counter = 0; #endif - assert(next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT); + assert(next_uop->opcode == _START_EXECUTOR_r00 || + next_uop->opcode == _COLD_EXIT_r00 || + next_uop->opcode == _COLD_DYNAMIC_EXIT_r00); tier2_dispatch: for (;;) { uopcode = next_uop->opcode; #ifdef Py_DEBUG if (frame->lltrace >= 3) { dump_stack(frame, stack_pointer); - if (next_uop->opcode == _START_EXECUTOR) { + printf(" cache=["); + dump_cache_item(_tos_cache0, 0, current_cached_values); + printf(", "); + dump_cache_item(_tos_cache1, 1, current_cached_values); + printf(", "); + dump_cache_item(_tos_cache2, 2, current_cached_values); + printf("]\n"); + if (next_uop->opcode == _START_EXECUTOR_r00) { printf("%4d uop: ", 0); } else { @@ -1195,6 +1677,7 @@ tier2_dispatch: } _PyUOpPrint(next_uop); printf("\n"); + fflush(stdout); } #endif next_uop++; @@ -1826,14 +2309,24 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); + frame->previous = NULL; _PyFrame_ClearExceptCode(frame); _PyErr_ClearExcState(&gen->gi_exc_state); - frame->previous = NULL; } void _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) { + // Update last_profiled_frame for remote profiler frame caching. + // By this point, tstate->current_frame is already set to the parent frame. + // Only update if we're popping the exact frame that was last profiled. + // This avoids corrupting the cache when transient frames (called and returned + // between profiler samples) update last_profiled_frame to addresses the + // profiler never saw. + if (tstate->last_profiled_frame != NULL && tstate->last_profiled_frame == frame) { + tstate->last_profiled_frame = tstate->current_frame; + } + if (frame->owner == FRAME_OWNED_BY_THREAD) { clear_thread_frame(tstate, frame); } @@ -1890,7 +2383,7 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func, PyObject *kwnames = NULL; _PyStackRef *newargs; PyObject *const *object_array = NULL; - _PyStackRef stack_array[8]; + _PyStackRef stack_array[8] = {0}; if (has_dict) { object_array = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames); if (object_array == NULL) { @@ -1953,7 +2446,7 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func, if (kwnames) { total_args += PyTuple_GET_SIZE(kwnames); } - _PyStackRef stack_array[8]; + _PyStackRef stack_array[8] = {0}; _PyStackRef *arguments; if (total_args <= 8) { arguments = stack_array; @@ -1999,7 +2492,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals, { PyThreadState *tstate = _PyThreadState_GET(); PyObject *res = NULL; - PyObject *defaults = _PyTuple_FromArray(defs, defcount); + PyObject *defaults = PyTuple_FromArray(defs, defcount); if (defaults == NULL) { return NULL; } @@ -2132,6 +2625,7 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) "calling %R should have returned an instance of " "BaseException, not %R", cause, Py_TYPE(fixed_cause)); + Py_DECREF(fixed_cause); goto raise_error; } Py_DECREF(cause); @@ -2450,6 +2944,10 @@ monitor_unwind(PyThreadState *tstate, do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND); } +bool +_PyEval_NoToolsForUnwind(PyThreadState *tstate) { + return no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_UNWIND); +} static int monitor_handled(PyThreadState *tstate, @@ -2653,12 +3151,6 @@ _PyEval_GetBuiltin(PyObject *name) return attr; } -PyObject * -_PyEval_GetBuiltinId(_Py_Identifier *name) -{ - return _PyEval_GetBuiltin(_PyUnicode_FromId(name)); -} - PyObject * PyEval_GetLocals(void) { @@ -2889,6 +3381,9 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf) { PyThreadState *tstate = _PyThreadState_GET(); _PyInterpreterFrame *current_frame = tstate->current_frame; + if (current_frame == tstate->base_frame) { + current_frame = NULL; + } int result = cf->cf_flags != 0; if (current_frame != NULL) { @@ -3256,17 +3751,9 @@ int _Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args) { if (Py_TYPE(args)->tp_iter == NULL && !PySequence_Check(args)) { - /* _Py_Check_ArgsIterable() may be called with a live exception: - * clear it to prevent calling _PyObject_FunctionStr() with an - * exception set. */ - _PyErr_Clear(tstate); - PyObject *funcstr = _PyObject_FunctionStr(func); - if (funcstr != NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "%U argument after * must be an iterable, not %.200s", - funcstr, Py_TYPE(args)->tp_name); - Py_DECREF(funcstr); - } + _PyErr_Format(tstate, PyExc_TypeError, + "Value after * must be an iterable, not %.200s", + Py_TYPE(args)->tp_name); return -1; } return 0; @@ -3282,15 +3769,10 @@ _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwarg * is not a mapping. */ if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { - _PyErr_Clear(tstate); - PyObject *funcstr = _PyObject_FunctionStr(func); - if (funcstr != NULL) { - _PyErr_Format( - tstate, PyExc_TypeError, - "%U argument after ** must be a mapping, not %.200s", - funcstr, Py_TYPE(kwargs)->tp_name); - Py_DECREF(funcstr); - } + _PyErr_Format( + tstate, PyExc_TypeError, + "Value after ** must be a mapping, not %.200s", + Py_TYPE(kwargs)->tp_name); } else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { PyObject *exc = _PyErr_GetRaisedException(tstate); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 6bf64868cbb..f6ada3892f8 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -207,6 +207,7 @@ drop_gil_impl(PyThreadState *tstate, struct _gil_runtime_state *gil) _Py_atomic_store_int_relaxed(&gil->locked, 0); if (tstate != NULL) { tstate->holds_gil = 0; + tstate->gil_requested = 0; } COND_SIGNAL(gil->cond); MUTEX_UNLOCK(gil->mutex); @@ -320,6 +321,8 @@ take_gil(PyThreadState *tstate) MUTEX_LOCK(gil->mutex); + tstate->gil_requested = 1; + int drop_requested = 0; while (_Py_atomic_load_int_relaxed(&gil->locked)) { unsigned long saved_switchnum = gil->switch_number; @@ -407,6 +410,7 @@ take_gil(PyThreadState *tstate) } assert(_PyThreadState_CheckConsistency(tstate)); + tstate->gil_requested = 0; tstate->holds_gil = 1; _Py_unset_eval_breaker_bit(tstate, _PY_GIL_DROP_REQUEST_BIT); update_eval_breaker_for_thread(interp, tstate); @@ -1398,7 +1402,7 @@ _Py_HandlePending(PyThreadState *tstate) if ((breaker & _PY_EVAL_JIT_INVALIDATE_COLD_BIT) != 0) { _Py_unset_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT); _Py_Executors_InvalidateCold(tstate->interp); - tstate->interp->trace_run_counter = JIT_CLEANUP_THRESHOLD; + tstate->interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD; } /* GIL drop request */ diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 64ca7716fdb..a526a453dd9 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -62,8 +62,9 @@ #ifdef Py_STATS #define INSTRUCTION_STATS(op) \ do { \ + PyStats *s = _PyStats_GET(); \ OPCODE_EXE_INC(op); \ - if (_Py_stats) _Py_stats->opcode_stats[lastopcode].pair_count[op]++; \ + if (s) s->opcode_stats[lastopcode].pair_count[op]++; \ lastopcode = op; \ } while (0) #else @@ -71,23 +72,39 @@ #endif #ifdef Py_STATS -# define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg, int lastopcode -# define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg, lastopcode +# define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, const void *instruction_funcptr_table, int oparg, int lastopcode +# define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, instruction_funcptr_table, oparg, lastopcode #else -# define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg -# define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg +# define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, const void *instruction_funcptr_table, int oparg +# define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, instruction_funcptr_table, oparg #endif -#if Py_TAIL_CALL_INTERP +#if _Py_TAIL_CALL_INTERP +# if defined(__clang__) || defined(__GNUC__) +# if !_Py__has_attribute(preserve_none) || !_Py__has_attribute(musttail) +# error "This compiler does not have support for efficient tail calling." +# endif +# elif defined(_MSC_VER) && (_MSC_VER < 1950) +# error "You need at least VS 2026 / PlatformToolset v145 for tail calling." +# endif + // Note: [[clang::musttail]] works for GCC 15, but not __attribute__((musttail)) at the moment. # define Py_MUSTTAIL [[clang::musttail]] # define Py_PRESERVE_NONE_CC __attribute__((preserve_none)) Py_PRESERVE_NONE_CC typedef PyObject* (*py_tail_call_funcptr)(TAIL_CALL_PARAMS); +# define DISPATCH_TABLE_VAR instruction_funcptr_table +# define DISPATCH_TABLE instruction_funcptr_handler_table +# define TRACING_DISPATCH_TABLE instruction_funcptr_tracing_table # define TARGET(op) Py_PRESERVE_NONE_CC PyObject *_TAIL_CALL_##op(TAIL_CALL_PARAMS) + # define DISPATCH_GOTO() \ do { \ - Py_MUSTTAIL return (INSTRUCTION_TABLE[opcode])(TAIL_CALL_ARGS); \ + Py_MUSTTAIL return (((py_tail_call_funcptr *)instruction_funcptr_table)[opcode])(TAIL_CALL_ARGS); \ + } while (0) +# define DISPATCH_GOTO_NON_TRACING() \ + do { \ + Py_MUSTTAIL return (((py_tail_call_funcptr *)DISPATCH_TABLE)[opcode])(TAIL_CALL_ARGS); \ } while (0) # define JUMP_TO_LABEL(name) \ do { \ @@ -96,29 +113,46 @@ # ifdef Py_STATS # define JUMP_TO_PREDICTED(name) \ do { \ - Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg, lastopcode); \ + Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, instruction_funcptr_table, oparg, lastopcode); \ } while (0) # else # define JUMP_TO_PREDICTED(name) \ do { \ - Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \ + Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, instruction_funcptr_table, oparg); \ } while (0) # endif # define LABEL(name) TARGET(name) #elif USE_COMPUTED_GOTOS +# define DISPATCH_TABLE_VAR opcode_targets +# define DISPATCH_TABLE opcode_targets_table +# define TRACING_DISPATCH_TABLE opcode_tracing_targets_table # define TARGET(op) TARGET_##op: # define DISPATCH_GOTO() goto *opcode_targets[opcode] +# define DISPATCH_GOTO_NON_TRACING() goto *DISPATCH_TABLE[opcode]; # define JUMP_TO_LABEL(name) goto name; # define JUMP_TO_PREDICTED(name) goto PREDICTED_##name; # define LABEL(name) name: #else # define TARGET(op) case op: TARGET_##op: -# define DISPATCH_GOTO() goto dispatch_opcode +# define DISPATCH_GOTO() dispatch_code = opcode | tracing_mode ; goto dispatch_opcode +# define DISPATCH_GOTO_NON_TRACING() dispatch_code = opcode; goto dispatch_opcode # define JUMP_TO_LABEL(name) goto name; # define JUMP_TO_PREDICTED(name) goto PREDICTED_##name; # define LABEL(name) name: #endif +#if (_Py_TAIL_CALL_INTERP || USE_COMPUTED_GOTOS) && _Py_TIER2 +# define IS_JIT_TRACING() (DISPATCH_TABLE_VAR == TRACING_DISPATCH_TABLE) +# define ENTER_TRACING() \ + DISPATCH_TABLE_VAR = TRACING_DISPATCH_TABLE; +# define LEAVE_TRACING() \ + DISPATCH_TABLE_VAR = DISPATCH_TABLE; +#else +# define IS_JIT_TRACING() (tracing_mode != 0) +# define ENTER_TRACING() tracing_mode = 255 +# define LEAVE_TRACING() tracing_mode = 0 +#endif + /* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ #ifdef Py_DEBUG #define PRE_DISPATCH_GOTO() if (frame->lltrace >= 5) { \ @@ -155,11 +189,19 @@ do { \ DISPATCH_GOTO(); \ } +#define DISPATCH_NON_TRACING() \ + { \ + assert(frame->stackpointer == NULL); \ + NEXTOPARG(); \ + PRE_DISPATCH_GOTO(); \ + DISPATCH_GOTO_NON_TRACING(); \ + } + #define DISPATCH_SAME_OPARG() \ { \ opcode = next_instr->op.code; \ PRE_DISPATCH_GOTO(); \ - DISPATCH_GOTO(); \ + DISPATCH_GOTO_NON_TRACING(); \ } #define DISPATCH_INLINED(NEW_FRAME) \ @@ -209,6 +251,14 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define WITHIN_STACK_BOUNDS() \ (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) +#if defined(Py_DEBUG) && !defined(_Py_JIT) +// This allows temporary stack "overflows", provided it's all in the cache at any point of time. +#define WITHIN_STACK_BOUNDS_IGNORING_CACHE() \ + (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && (STACK_LEVEL()) <= STACK_SIZE())) +#else +#define WITHIN_STACK_BOUNDS_IGNORING_CACHE WITHIN_STACK_BOUNDS +#endif + /* Data access macros */ #define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts) #define FRAME_CO_NAMES (_PyFrame_GetCode(frame)->co_names) @@ -271,6 +321,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* This takes a uint16_t instead of a _Py_BackoffCounter, * because it is used directly on the cache entry in generated code, * which is always an integral type. */ +// Force re-specialization when tracing a side exit to get good side exits. #define ADAPTIVE_COUNTER_TRIGGERS(COUNTER) \ backoff_counter_triggers(forge_backoff_counter((COUNTER))) @@ -357,10 +408,19 @@ do { \ next_instr = _Py_jit_entry((EXECUTOR), frame, stack_pointer, tstate); \ frame = tstate->current_frame; \ stack_pointer = _PyFrame_GetStackPointer(frame); \ + int keep_tracing_bit = (uintptr_t)next_instr & 1; \ + next_instr = (_Py_CODEUNIT *)(((uintptr_t)next_instr) & (~1)); \ if (next_instr == NULL) { \ - next_instr = frame->instr_ptr; \ + /* gh-140104: The exception handler expects frame->instr_ptr + to after this_instr, not this_instr! */ \ + next_instr = frame->instr_ptr + 1; \ JUMP_TO_LABEL(error); \ } \ + if (keep_tracing_bit) { \ + assert(((_PyThreadStateImpl *)tstate)->jit_tracer_state.prev_state.code_curr_size == 2); \ + ENTER_TRACING(); \ + DISPATCH_NON_TRACING(); \ + } \ DISPATCH(); \ } while (0) @@ -371,18 +431,32 @@ do { \ goto tier2_start; \ } while (0) -#define GOTO_TIER_ONE(TARGET) \ - do \ - { \ - tstate->current_executor = NULL; \ - OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \ - _PyFrame_SetStackPointer(frame, stack_pointer); \ - return TARGET; \ +#define GOTO_TIER_ONE_SETUP \ + tstate->current_executor = NULL; \ + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \ + _PyFrame_SetStackPointer(frame, stack_pointer); + +#define GOTO_TIER_ONE(TARGET) \ + do \ + { \ + GOTO_TIER_ONE_SETUP \ + return (_Py_CODEUNIT *)(TARGET); \ + } while (0) + +#define GOTO_TIER_ONE_CONTINUE_TRACING(TARGET) \ + do \ + { \ + GOTO_TIER_ONE_SETUP \ + return (_Py_CODEUNIT *)(((uintptr_t)(TARGET))| 1); \ } while (0) #define CURRENT_OPARG() (next_uop[-1].oparg) -#define CURRENT_OPERAND0() (next_uop[-1].operand0) -#define CURRENT_OPERAND1() (next_uop[-1].operand1) +#define CURRENT_OPERAND0_64() (next_uop[-1].operand0) +#define CURRENT_OPERAND1_64() (next_uop[-1].operand1) +#define CURRENT_OPERAND0_32() (next_uop[-1].operand0) +#define CURRENT_OPERAND1_32() (next_uop[-1].operand1) +#define CURRENT_OPERAND0_16() (next_uop[-1].operand0) +#define CURRENT_OPERAND1_16() (next_uop[-1].operand1) #define CURRENT_TARGET() (next_uop[-1].target) #define JUMP_TO_JUMP_TARGET() goto jump_to_jump_target @@ -396,7 +470,7 @@ do { \ #define STACKREFS_TO_PYOBJECTS(ARGS, ARG_COUNT, NAME) \ /* +1 because vectorcall might use -1 to write self */ \ PyObject *NAME##_temp[MAX_STACKREF_SCRATCH+1]; \ - PyObject **NAME = _PyObjectArray_FromStackRefArray(ARGS, ARG_COUNT, NAME##_temp + 1); + PyObject **NAME = _PyObjectArray_FromStackRefArray(ARGS, ARG_COUNT, NAME##_temp); #define STACKREFS_TO_PYOBJECTS_CLEANUP(NAME) \ /* +1 because we +1 previously */ \ @@ -404,6 +478,14 @@ do { \ #define CONVERSION_FAILED(NAME) ((NAME) == NULL) +#if defined(Py_DEBUG) && !defined(_Py_JIT) +#define SET_CURRENT_CACHED_VALUES(N) current_cached_values = (N) +#define CHECK_CURRENT_CACHED_VALUES(N) assert(current_cached_values == (N)) +#else +#define SET_CURRENT_CACHED_VALUES(N) ((void)0) +#define CHECK_CURRENT_CACHED_VALUES(N) ((void)0) +#endif + static inline int check_periodics(PyThreadState *tstate) { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index 60e20a46af5..f08e5847abe 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -238,7 +238,8 @@ PyDoc_STRVAR(builtin_chr__doc__, PyDoc_STRVAR(builtin_compile__doc__, "compile($module, /, source, filename, mode, flags=0,\n" -" dont_inherit=False, optimize=-1, *, _feature_version=-1)\n" +" dont_inherit=False, optimize=-1, *, module=None,\n" +" _feature_version=-1)\n" "--\n" "\n" "Compile source into a code object that can be executed by exec() or eval().\n" @@ -260,7 +261,7 @@ PyDoc_STRVAR(builtin_compile__doc__, static PyObject * builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, - int optimize, int feature_version); + int optimize, PyObject *modname, int feature_version); static PyObject * builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -268,7 +269,7 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 7 + #define NUM_KEYWORDS 8 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -277,7 +278,7 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(source), &_Py_ID(filename), &_Py_ID(mode), &_Py_ID(flags), &_Py_ID(dont_inherit), &_Py_ID(optimize), &_Py_ID(_feature_version), }, + .ob_item = { &_Py_ID(source), &_Py_ID(filename), &_Py_ID(mode), &_Py_ID(flags), &_Py_ID(dont_inherit), &_Py_ID(optimize), &_Py_ID(module), &_Py_ID(_feature_version), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -286,21 +287,22 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"source", "filename", "mode", "flags", "dont_inherit", "optimize", "_feature_version", NULL}; + static const char * const _keywords[] = {"source", "filename", "mode", "flags", "dont_inherit", "optimize", "module", "_feature_version", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "compile", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[7]; + PyObject *argsbuf[8]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; PyObject *source; - PyObject *filename; + PyObject *filename = NULL; const char *mode; int flags = 0; int dont_inherit = 0; int optimize = -1; + PyObject *modname = Py_None; int feature_version = -1; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, @@ -359,14 +361,23 @@ skip_optional_pos: if (!noptargs) { goto skip_optional_kwonly; } - feature_version = PyLong_AsInt(args[6]); + if (args[6]) { + modname = args[6]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + feature_version = PyLong_AsInt(args[7]); if (feature_version == -1 && PyErr_Occurred()) { goto exit; } skip_optional_kwonly: - return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, feature_version); + return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, modname, feature_version); exit: + /* Cleanup for filename */ + Py_XDECREF(filename); + return return_value; } @@ -1274,4 +1285,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=c0b72519622c849e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=06500bcc9a341e68 input=a9049054013a1b77]*/ diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index a47e4d11b54..4c4a86de2f9 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -7,7 +7,6 @@ preserve # include "pycore_runtime.h" // _Py_ID() #endif #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() -#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(sys_addaudithook__doc__, "addaudithook($module, /, hook)\n" @@ -102,7 +101,7 @@ sys_audit(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - __clinic_args = _PyTuple_FromArray(args + 1, nargs - 1); + __clinic_args = PyTuple_FromArray(args + 1, nargs - 1); if (__clinic_args == NULL) { goto exit; } @@ -1948,4 +1947,4 @@ exit: #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=449d16326e69dcf6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5f7d84c5bf00d557 input=a9049054013a1b77]*/ diff --git a/Python/codecs.c b/Python/codecs.c index 8eb9f2db413..0bde56c0ac6 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -83,16 +83,15 @@ PyCodec_Unregister(PyObject *search_function) return 0; } -extern int _Py_normalize_encoding(const char *, char *, size_t); +/* Convert a string to a normalized Python string: all ASCII letters are + converted to lower case, spaces are replaced with hyphens. */ -/* Convert a string to a normalized Python string(decoded from UTF-8): all characters are - converted to lower case, spaces and hyphens are replaced with underscores. */ - -static -PyObject *normalizestring(const char *string) +static PyObject* +normalizestring(const char *string) { + size_t i; size_t len = strlen(string); - char *encoding; + char *p; PyObject *v; if (len > PY_SSIZE_T_MAX) { @@ -100,28 +99,30 @@ PyObject *normalizestring(const char *string) return NULL; } - encoding = PyMem_Malloc(len + 1); - if (encoding == NULL) + p = PyMem_Malloc(len + 1); + if (p == NULL) return PyErr_NoMemory(); - - if (!_Py_normalize_encoding(string, encoding, len + 1)) - { - PyErr_SetString(PyExc_RuntimeError, "_Py_normalize_encoding() failed"); - PyMem_Free(encoding); - return NULL; + for (i = 0; i < len; i++) { + char ch = string[i]; + if (ch == ' ') + ch = '-'; + else + ch = Py_TOLOWER(Py_CHARMASK(ch)); + p[i] = ch; } - - v = PyUnicode_FromString(encoding); - PyMem_Free(encoding); + p[i] = '\0'; + v = PyUnicode_FromString(p); + PyMem_Free(p); return v; } /* Lookup the given encoding and return a tuple providing the codec facilities. - The encoding string is looked up converted to all lower-case - characters. This makes encodings looked up through this mechanism - effectively case-insensitive. + ASCII letters in the encoding string is looked up converted to all + lower case. This makes encodings looked up through this mechanism + effectively case-insensitive. Spaces are replaced with hyphens for + names like "US ASCII" and "ISO 8859-1". If no codec is found, a LookupError is set and NULL returned. @@ -142,8 +143,8 @@ PyObject *_PyCodec_Lookup(const char *encoding) assert(interp->codecs.initialized); /* Convert the encoding to a normalized Python string: all - characters are converted to lower case, spaces and hyphens are - replaced with underscores. */ + ASCII letters are converted to lower case, spaces are + replaced with hyphens. */ PyObject *v = normalizestring(encoding); if (v == NULL) { return NULL; diff --git a/Python/codegen.c b/Python/codegen.c index 53388592330..c4109fcaa48 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -29,6 +29,7 @@ #include "pycore_symtable.h" // PySTEntryObject #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString #include "pycore_ceval.h" // SPECIAL___ENTER__ +#include "pycore_template.h" // _PyTemplate_Type #define NEED_OPCODE_METADATA #include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed @@ -3617,10 +3618,11 @@ infer_type(expr_ty e) return &PyGen_Type; case Lambda_kind: return &PyFunction_Type; - case JoinedStr_kind: case TemplateStr_kind: - case FormattedValue_kind: case Interpolation_kind: + return &_PyTemplate_Type; + case JoinedStr_kind: + case FormattedValue_kind: return &PyUnicode_Type; case Constant_kind: return Py_TYPE(e->v.Constant.value); @@ -3674,6 +3676,8 @@ check_subscripter(compiler *c, expr_ty e) case Set_kind: case SetComp_kind: case GeneratorExp_kind: + case TemplateStr_kind: + case Interpolation_kind: case Lambda_kind: { location loc = LOC(e); return _PyCompile_Warn(c, loc, "'%.200s' object is not subscriptable; " @@ -3708,9 +3712,7 @@ check_index(compiler *c, expr_ty e, expr_ty s) case List_kind: case ListComp_kind: case JoinedStr_kind: - case TemplateStr_kind: - case FormattedValue_kind: - case Interpolation_kind: { + case FormattedValue_kind: { location loc = LOC(e); return _PyCompile_Warn(c, loc, "%.200s indices must be integers " "or slices, not %.200s; " @@ -5412,23 +5414,6 @@ codegen_check_ann_expr(compiler *c, expr_ty e) return SUCCESS; } -static int -codegen_check_annotation(compiler *c, stmt_ty s) -{ - /* Annotations of complex targets does not produce anything - under annotations future */ - if (FUTURE_FEATURES(c) & CO_FUTURE_ANNOTATIONS) { - return SUCCESS; - } - - /* Annotations are only evaluated in a module or class. */ - if (SCOPE_TYPE(c) == COMPILE_SCOPE_MODULE || - SCOPE_TYPE(c) == COMPILE_SCOPE_CLASS) { - return codegen_check_ann_expr(c, s->v.AnnAssign.annotation); - } - return SUCCESS; -} - static int codegen_check_ann_subscr(compiler *c, expr_ty e) { @@ -5492,10 +5477,12 @@ codegen_annassign(compiler *c, stmt_ty s) RETURN_IF_ERROR(_PyCompile_AddDeferredAnnotation( c, s, &conditional_annotation_index)); if (conditional_annotation_index != NULL) { - ADDOP_NAME( - c, loc, - SCOPE_TYPE(c) == COMPILE_SCOPE_CLASS ? LOAD_DEREF : LOAD_NAME, - &_Py_ID(__conditional_annotations__), cellvars); + if (SCOPE_TYPE(c) == COMPILE_SCOPE_CLASS) { + ADDOP_NAME(c, loc, LOAD_DEREF, &_Py_ID(__conditional_annotations__), cellvars); + } + else { + ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__conditional_annotations__), names); + } ADDOP_LOAD_CONST_NEW(c, loc, conditional_annotation_index); ADDOP_I(c, loc, SET_ADD, 1); ADDOP(c, loc, POP_TOP); @@ -5522,10 +5509,6 @@ codegen_annassign(compiler *c, stmt_ty s) targ->kind); return ERROR; } - /* Annotation is evaluated last. */ - if (future_annotations && !s->v.AnnAssign.simple && codegen_check_annotation(c, s) < 0) { - return ERROR; - } return SUCCESS; } diff --git a/Python/compile.c b/Python/compile.c index c04391e682f..6951c98500d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -103,11 +103,14 @@ typedef struct _PyCompiler { bool c_save_nested_seqs; /* if true, construct recursive instruction sequences * (including instructions for nested code objects) */ + int c_disable_warning; + PyObject *c_module; } compiler; static int compiler_setup(compiler *c, mod_ty mod, PyObject *filename, - PyCompilerFlags *flags, int optimize, PyArena *arena) + PyCompilerFlags *flags, int optimize, PyArena *arena, + PyObject *module) { PyCompilerFlags local_flags = _PyCompilerFlags_INIT; @@ -125,6 +128,7 @@ compiler_setup(compiler *c, mod_ty mod, PyObject *filename, if (!_PyFuture_FromAST(mod, filename, &c->c_future)) { return ERROR; } + c->c_module = Py_XNewRef(module); if (!flags) { flags = &local_flags; } @@ -135,7 +139,9 @@ compiler_setup(compiler *c, mod_ty mod, PyObject *filename, c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize; c->c_save_nested_seqs = false; - if (!_PyAST_Preprocess(mod, arena, filename, c->c_optimize, merged, 0)) { + if (!_PyAST_Preprocess(mod, arena, filename, c->c_optimize, merged, + 0, 1, module)) + { return ERROR; } c->c_st = _PySymtable_Build(mod, filename, &c->c_future); @@ -155,6 +161,7 @@ compiler_free(compiler *c) _PySymtable_Free(c->c_st); } Py_XDECREF(c->c_filename); + Py_XDECREF(c->c_module); Py_XDECREF(c->c_const_cache); Py_XDECREF(c->c_stack); PyMem_Free(c); @@ -162,13 +169,13 @@ compiler_free(compiler *c) static compiler* new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, - int optimize, PyArena *arena) + int optimize, PyArena *arena, PyObject *module) { compiler *c = PyMem_Calloc(1, sizeof(compiler)); if (c == NULL) { return NULL; } - if (compiler_setup(c, mod, filename, pflags, optimize, arena) < 0) { + if (compiler_setup(c, mod, filename, pflags, optimize, arena, module) < 0) { compiler_free(c); return NULL; } @@ -765,6 +772,9 @@ _PyCompile_PushFBlock(compiler *c, location loc, f->fb_loc = loc; f->fb_exit = exit; f->fb_datum = datum; + if (t == COMPILE_FBLOCK_FINALLY_END) { + c->c_disable_warning++; + } return SUCCESS; } @@ -776,6 +786,9 @@ _PyCompile_PopFBlock(compiler *c, fblocktype t, jump_target_label block_label) u->u_nfblocks--; assert(u->u_fblock[u->u_nfblocks].fb_type == t); assert(SAME_JUMP_TARGET_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label)); + if (t == COMPILE_FBLOCK_FINALLY_END) { + c->c_disable_warning--; + } } fblockinfo * @@ -1203,6 +1216,9 @@ _PyCompile_Error(compiler *c, location loc, const char *format, ...) int _PyCompile_Warn(compiler *c, location loc, const char *format, ...) { + if (c->c_disable_warning) { + return 0; + } va_list vargs; va_start(vargs, format); PyObject *msg = PyUnicode_FromFormatV(format, vargs); @@ -1211,7 +1227,8 @@ _PyCompile_Warn(compiler *c, location loc, const char *format, ...) return ERROR; } int ret = _PyErr_EmitSyntaxWarning(msg, c->c_filename, loc.lineno, loc.col_offset + 1, - loc.end_lineno, loc.end_col_offset + 1); + loc.end_lineno, loc.end_col_offset + 1, + c->c_module); Py_DECREF(msg); return ret; } @@ -1466,10 +1483,10 @@ _PyCompile_OptimizeAndAssemble(compiler *c, int addNone) PyCodeObject * _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, - int optimize, PyArena *arena) + int optimize, PyArena *arena, PyObject *module) { assert(!PyErr_Occurred()); - compiler *c = new_compiler(mod, filename, pflags, optimize, arena); + compiler *c = new_compiler(mod, filename, pflags, optimize, arena, module); if (c == NULL) { return NULL; } @@ -1482,7 +1499,8 @@ _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, int _PyCompile_AstPreprocess(mod_ty mod, PyObject *filename, PyCompilerFlags *cf, - int optimize, PyArena *arena, int no_const_folding) + int optimize, PyArena *arena, int no_const_folding, + PyObject *module) { _PyFutureFeatures future; if (!_PyFuture_FromAST(mod, filename, &future)) { @@ -1492,7 +1510,9 @@ _PyCompile_AstPreprocess(mod_ty mod, PyObject *filename, PyCompilerFlags *cf, if (optimize == -1) { optimize = _Py_GetConfig()->optimization_level; } - if (!_PyAST_Preprocess(mod, arena, filename, optimize, flags, no_const_folding)) { + if (!_PyAST_Preprocess(mod, arena, filename, optimize, flags, + no_const_folding, 0, module)) + { return -1; } return 0; @@ -1617,7 +1637,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, return NULL; } - compiler *c = new_compiler(mod, filename, pflags, optimize, arena); + compiler *c = new_compiler(mod, filename, pflags, optimize, arena, NULL); if (c == NULL) { _PyArena_Free(arena); return NULL; diff --git a/Python/context.c b/Python/context.c index b764f5813fa..606ce4b1c8f 100644 --- a/Python/context.c +++ b/Python/context.c @@ -190,7 +190,7 @@ context_switched(PyThreadState *ts) } -static int +int _PyContext_Enter(PyThreadState *ts, PyObject *octx) { ENSURE_Context(octx, -1) @@ -220,7 +220,7 @@ PyContext_Enter(PyObject *octx) } -static int +int _PyContext_Exit(PyThreadState *ts, PyObject *octx) { ENSURE_Context(octx, -1) @@ -343,12 +343,6 @@ PyContextVar_Set(PyObject *ovar, PyObject *val) ENSURE_ContextVar(ovar, NULL) PyContextVar *var = (PyContextVar *)ovar; - if (!PyContextVar_CheckExact(var)) { - PyErr_SetString( - PyExc_TypeError, "an instance of ContextVar was expected"); - return NULL; - } - PyContext *ctx = context_get(); if (ctx == NULL) { return NULL; @@ -1025,12 +1019,6 @@ static PyObject * _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value) /*[clinic end generated code: output=0746bd0aa2ced7bf input=da66664d5d0af4ad]*/ { - if (!PyContextVar_CheckExact(self)) { - PyErr_SetString( - PyExc_TypeError, "an instance of ContextVar was expected"); - return NULL; - } - PyObject *val; if (PyContextVar_Get((PyObject *)self, default_value, &val) < 0) { return NULL; @@ -1360,11 +1348,8 @@ get_token_missing(void) PyStatus _PyContext_Init(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return _PyStatus_OK(); - } - PyObject *missing = get_token_missing(); + assert(PyUnstable_IsImmortal(missing)); if (PyDict_SetItemString( _PyType_GetDict(&PyContextToken_Type), "MISSING", missing)) { diff --git a/Python/critical_section.c b/Python/critical_section.c index e628ba2f6d1..2c2152f5de4 100644 --- a/Python/critical_section.c +++ b/Python/critical_section.c @@ -17,18 +17,30 @@ untag_critical_section(uintptr_t tag) #endif void -_PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m) +_PyCriticalSection_BeginSlow(PyThreadState *tstate, PyCriticalSection *c, PyMutex *m) { #ifdef Py_GIL_DISABLED - PyThreadState *tstate = _PyThreadState_GET(); // As an optimisation for locking the same object recursively, skip // locking if the mutex is currently locked by the top-most critical // section. - if (tstate->critical_section && - untag_critical_section(tstate->critical_section)->_cs_mutex == m) { - c->_cs_mutex = NULL; - c->_cs_prev = 0; - return; + // If the top-most critical section is a two-mutex critical section, + // then locking is skipped if either mutex is m. + if (tstate->critical_section) { + PyCriticalSection *prev = untag_critical_section(tstate->critical_section); + if (prev->_cs_mutex == m) { + c->_cs_mutex = NULL; + c->_cs_prev = 0; + return; + } + if (tstate->critical_section & _Py_CRITICAL_SECTION_TWO_MUTEXES) { + PyCriticalSection2 *prev2 = (PyCriticalSection2 *) + untag_critical_section(tstate->critical_section); + if (prev2->_cs_mutex2 == m) { + c->_cs_mutex = NULL; + c->_cs_prev = 0; + return; + } + } } c->_cs_mutex = NULL; c->_cs_prev = (uintptr_t)tstate->critical_section; @@ -40,11 +52,10 @@ _PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m) } void -_PyCriticalSection2_BeginSlow(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2, +_PyCriticalSection2_BeginSlow(PyThreadState *tstate, PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2, int is_m1_locked) { #ifdef Py_GIL_DISABLED - PyThreadState *tstate = _PyThreadState_GET(); c->_cs_base._cs_mutex = NULL; c->_cs_mutex2 = NULL; c->_cs_base._cs_prev = tstate->critical_section; @@ -126,7 +137,7 @@ void PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op) { #ifdef Py_GIL_DISABLED - _PyCriticalSection_Begin(c, op); + _PyCriticalSection_Begin(_PyThreadState_GET(), c, op); #endif } @@ -135,7 +146,7 @@ void PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m) { #ifdef Py_GIL_DISABLED - _PyCriticalSection_BeginMutex(c, m); + _PyCriticalSection_BeginMutex(_PyThreadState_GET(), c, m); #endif } @@ -144,7 +155,7 @@ void PyCriticalSection_End(PyCriticalSection *c) { #ifdef Py_GIL_DISABLED - _PyCriticalSection_End(c); + _PyCriticalSection_End(_PyThreadState_GET(), c); #endif } @@ -153,7 +164,7 @@ void PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b) { #ifdef Py_GIL_DISABLED - _PyCriticalSection2_Begin(c, a, b); + _PyCriticalSection2_Begin(_PyThreadState_GET(), c, a, b); #endif } @@ -162,7 +173,7 @@ void PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2) { #ifdef Py_GIL_DISABLED - _PyCriticalSection2_BeginMutex(c, m1, m2); + _PyCriticalSection2_BeginMutex(_PyThreadState_GET(), c, m1, m2); #endif } @@ -171,6 +182,6 @@ void PyCriticalSection2_End(PyCriticalSection2 *c) { #ifdef Py_GIL_DISABLED - _PyCriticalSection2_End(c); + _PyCriticalSection2_End(_PyThreadState_GET(), c); #endif } diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 16a23f0351c..b43f33fdf97 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -1153,8 +1153,8 @@ _release_xid_data(_PyXIData_t *xidata, int rawfree) { PyObject *exc = PyErr_GetRaisedException(); int res = rawfree - ? _PyXIData_Release(xidata) - : _PyXIData_ReleaseAndRawFree(xidata); + ? _PyXIData_ReleaseAndRawFree(xidata) + : _PyXIData_Release(xidata); if (res < 0) { /* The owning interpreter is already destroyed. */ _PyXIData_Clear(NULL, xidata); @@ -1805,6 +1805,15 @@ _PyXI_InitFailureUTF8(_PyXI_failure *failure, int _PyXI_InitFailure(_PyXI_failure *failure, _PyXI_errcode code, PyObject *obj) { + *failure = (_PyXI_failure){ + .code = code, + .msg = NULL, + .msg_owned = 0, + }; + if (obj == NULL) { + return 0; + } + PyObject *msgobj = PyObject_Str(obj); if (msgobj == NULL) { return -1; @@ -1813,7 +1822,7 @@ _PyXI_InitFailure(_PyXI_failure *failure, _PyXI_errcode code, PyObject *obj) // That happens automatically in _capture_current_exception(). const char *msg = _copy_string_obj_raw(msgobj, NULL); Py_DECREF(msgobj); - if (PyErr_Occurred()) { + if (msg == NULL) { return -1; } *failure = (_PyXI_failure){ @@ -3176,7 +3185,7 @@ _PyXI_InitTypes(PyInterpreterState *interp) "failed to initialize the cross-interpreter exception types"); } // We would initialize heap types here too but that leads to ref leaks. - // Instead, we intialize them in _PyXI_Init(). + // Instead, we initialize them in _PyXI_Init(). return _PyStatus_OK(); } diff --git a/Python/emscripten_trampoline.c b/Python/emscripten_trampoline.c index 75b98a04723..d61146504d0 100644 --- a/Python/emscripten_trampoline.c +++ b/Python/emscripten_trampoline.c @@ -2,75 +2,20 @@ #include <emscripten.h> // EM_JS, EM_JS_DEPS #include <Python.h> -#include "pycore_runtime.h" // _PyRuntime -typedef int (*CountArgsFunc)(PyCFunctionWithKeywords func); - -// Offset of emscripten_count_args_function in _PyRuntimeState. There's a couple -// of alternatives: -// 1. Just make emscripten_count_args_function a real C global variable instead -// of a field of _PyRuntimeState. This would violate our rule against mutable -// globals. -// 2. #define a preprocessor constant equal to a hard coded number and make a -// _Static_assert(offsetof(_PyRuntimeState, emscripten_count_args_function) -// == OURCONSTANT) This has the disadvantage that we have to update the hard -// coded constant when _PyRuntimeState changes -// -// So putting the mutable constant in _PyRuntime and using a immutable global to -// record the offset so we can access it from JS is probably the best way. -EMSCRIPTEN_KEEPALIVE const int _PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET = offsetof(_PyRuntimeState, emscripten_count_args_function); - -EM_JS(CountArgsFunc, _PyEM_GetCountArgsPtr, (), { - return Module._PyEM_CountArgsPtr; // initialized below +EM_JS( +PyObject*, +_PyEM_TrampolineCall_inner, (int* success, + PyCFunctionWithKeywords func, + PyObject *arg1, + PyObject *arg2, + PyObject *arg3), { + // JavaScript fallback trampoline + return wasmTable.get(func)(arg1, arg2, arg3); } -// Binary module for the checks. It has to be done in web assembly because -// clang/llvm have no support yet for the reference types yet. In fact, the wasm -// binary toolkit doesn't yet support the ref.test instruction either. To -// convert the following textual wasm to a binary, you can build wabt from this -// branch: https://github.com/WebAssembly/wabt/pull/2529 and then use that -// wat2wasm binary. -// -// (module -// (type $type0 (func (param) (result i32))) -// (type $type1 (func (param i32) (result i32))) -// (type $type2 (func (param i32 i32) (result i32))) -// (type $type3 (func (param i32 i32 i32) (result i32))) -// (type $blocktype (func (param) (result))) -// (table $funcs (import "e" "t") 0 funcref) -// (export "f" (func $f)) -// (func $f (param $fptr i32) (result i32) -// (local $fref funcref) -// local.get $fptr -// table.get $funcs -// local.tee $fref -// ref.test $type3 -// if $blocktype -// i32.const 3 -// return -// end -// local.get $fref -// ref.test $type2 -// if $blocktype -// i32.const 2 -// return -// end -// local.get $fref -// ref.test $type1 -// if $blocktype -// i32.const 1 -// return -// end -// local.get $fref -// ref.test $type0 -// if $blocktype -// i32.const 0 -// return -// end -// i32.const -1 -// ) -// ) - -function getPyEMCountArgsPtr() { +// Try to replace the JS definition of _PyEM_TrampolineCall_inner with a wasm +// version. +(function () { // Starting with iOS 18.3.1, WebKit on iOS has an issue with the garbage // collector that breaks the call trampoline. See #130418 and // https://bugs.webkit.org/show_bug.cgi?id=293113 for details. @@ -82,137 +27,33 @@ function getPyEMCountArgsPtr() { (navigator.platform === 'MacIntel' && typeof navigator.maxTouchPoints !== 'undefined' && navigator.maxTouchPoints > 1) ); if (isIOS) { - return 0; + return; } - - // Try to initialize countArgsFunc - const code = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, // \0asm magic number - 0x01, 0x00, 0x00, 0x00, // version 1 - 0x01, 0x1a, // Type section, body is 0x1a bytes - 0x05, // 6 entries - 0x60, 0x00, 0x01, 0x7f, // (type $type0 (func (param) (result i32))) - 0x60, 0x01, 0x7f, 0x01, 0x7f, // (type $type1 (func (param i32) (result i32))) - 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, // (type $type2 (func (param i32 i32) (result i32))) - 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, // (type $type3 (func (param i32 i32 i32) (result i32))) - 0x60, 0x00, 0x00, // (type $blocktype (func (param) (result))) - 0x02, 0x09, // Import section, 0x9 byte body - 0x01, // 1 import (table $funcs (import "e" "t") 0 funcref) - 0x01, 0x65, // "e" - 0x01, 0x74, // "t" - 0x01, // importing a table - 0x70, // of entry type funcref - 0x00, 0x00, // table limits: no max, min of 0 - 0x03, 0x02, // Function section - 0x01, 0x01, // We're going to define one function of type 1 (func (param i32) (result i32)) - 0x07, 0x05, // export section - 0x01, // 1 export - 0x01, 0x66, // called "f" - 0x00, // a function - 0x00, // at index 0 - - 0x0a, 56, // Code section, - 0x01, 54, // one entry of length 54 - 0x01, 0x01, 0x70, // one local of type funcref - // Body of the function - 0x20, 0x00, // local.get $fptr - 0x25, 0x00, // table.get $funcs - 0x22, 0x01, // local.tee $fref - 0xfb, 0x14, 0x03, // ref.test $type3 - 0x04, 0x04, // if (type $blocktype) - 0x41, 0x03, // i32.const 3 - 0x0f, // return - 0x0b, // end block - - 0x20, 0x01, // local.get $fref - 0xfb, 0x14, 0x02, // ref.test $type2 - 0x04, 0x04, // if (type $blocktype) - 0x41, 0x02, // i32.const 2 - 0x0f, // return - 0x0b, // end block - - 0x20, 0x01, // local.get $fref - 0xfb, 0x14, 0x01, // ref.test $type1 - 0x04, 0x04, // if (type $blocktype) - 0x41, 0x01, // i32.const 1 - 0x0f, // return - 0x0b, // end block - - 0x20, 0x01, // local.get $fref - 0xfb, 0x14, 0x00, // ref.test $type0 - 0x04, 0x04, // if (type $blocktype) - 0x41, 0x00, // i32.const 0 - 0x0f, // return - 0x0b, // end block - - 0x41, 0x7f, // i32.const -1 - 0x0b // end function - ]); try { - const mod = new WebAssembly.Module(code); - const inst = new WebAssembly.Instance(mod, { e: { t: wasmTable } }); - return addFunction(inst.exports.f); + const trampolineModule = getWasmTrampolineModule(); + const trampolineInstance = new WebAssembly.Instance(trampolineModule, { + env: { __indirect_function_table: wasmTable, memory: wasmMemory }, + }); + _PyEM_TrampolineCall_inner = trampolineInstance.exports.trampoline_call; } catch (e) { - // If something goes wrong, we'll null out _PyEM_CountFuncParams and fall - // back to the JS trampoline. - return 0; + // Compilation error due to missing wasm-gc support, fall back to JS + // trampoline } -} - -addOnPreRun(() => { - const ptr = getPyEMCountArgsPtr(); - Module._PyEM_CountArgsPtr = ptr; - const offset = HEAP32[__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET / 4]; - HEAP32[(__PyRuntime + offset) / 4] = ptr; -}); +})(); ); -void -_Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime) -{ - runtime->emscripten_count_args_function = _PyEM_GetCountArgsPtr(); -} - -// We have to be careful to work correctly with memory snapshots. Even if we are -// loading a memory snapshot, we need to perform the JS initialization work. -// That means we can't call the initialization code from C. Instead, we export -// this function pointer to JS and then fill it in a preRun function which runs -// unconditionally. -/** - * Backwards compatible trampoline works with all JS runtimes - */ -EM_JS(PyObject*, _PyEM_TrampolineCall_JS, (PyCFunctionWithKeywords func, PyObject *arg1, PyObject *arg2, PyObject *arg3), { - return wasmTable.get(func)(arg1, arg2, arg3); -}); - -typedef PyObject* (*zero_arg)(void); -typedef PyObject* (*one_arg)(PyObject*); -typedef PyObject* (*two_arg)(PyObject*, PyObject*); -typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*); - PyObject* _PyEM_TrampolineCall(PyCFunctionWithKeywords func, PyObject* self, PyObject* args, PyObject* kw) { - CountArgsFunc count_args = _PyRuntime.emscripten_count_args_function; - if (count_args == 0) { - return _PyEM_TrampolineCall_JS(func, self, args, kw); - } - switch (count_args(func)) { - case 0: - return ((zero_arg)func)(); - case 1: - return ((one_arg)func)(self); - case 2: - return ((two_arg)func)(self, args); - case 3: - return ((three_arg)func)(self, args, kw); - default: - PyErr_SetString(PyExc_SystemError, "Handler takes too many arguments"); - return NULL; + int success = 1; + PyObject *result = _PyEM_TrampolineCall_inner(&success, func, self, args, kw); + if (!success) { + PyErr_SetString(PyExc_SystemError, "Handler takes too many arguments"); } + return result; } #endif diff --git a/Python/emscripten_trampoline_inner.c b/Python/emscripten_trampoline_inner.c new file mode 100644 index 00000000000..a2bad4857ed --- /dev/null +++ b/Python/emscripten_trampoline_inner.c @@ -0,0 +1,38 @@ +// This file must be compiled with -mgc to enable the extra wasm-gc +// instructions. It has to be compiled separately because not enough JS runtimes +// support wasm-gc yet. If the JS runtime does not support wasm-gc (or has buggy +// support like iOS), we will use the JS trampoline fallback. + +// We can't import Python.h here because it is compiled/linked with -nostdlib. +// We don't need to know what's inside PyObject* anyways. We could just call it +// void* everywhere. There are two reasons to do this: +// 1. to improve readability +// 2. eventually when we are comfortable requiring wasm-gc, we can merge this +// into emscripten_trampoline.c without worrying about it. +typedef void PyObject; + +typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*); +typedef PyObject* (*two_arg)(PyObject*, PyObject*); +typedef PyObject* (*one_arg)(PyObject*); +typedef PyObject* (*zero_arg)(void); + +#define TRY_RETURN_CALL(ty, args...) \ + if (__builtin_wasm_test_function_pointer_signature((ty)func)) { \ + return ((ty)func)(args); \ + } + +__attribute__((export_name("trampoline_call"))) PyObject* +trampoline_call(int* success, + void* func, + PyObject* self, + PyObject* args, + PyObject* kw) +{ + *success = 1; + TRY_RETURN_CALL(three_arg, self, args, kw); + TRY_RETURN_CALL(two_arg, self, args); + TRY_RETURN_CALL(one_arg, self); + TRY_RETURN_CALL(zero_arg); + *success = 0; + return 0; +} diff --git a/Python/errors.c b/Python/errors.c index 2688396004e..5c6ac48371a 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1960,10 +1960,11 @@ _PyErr_RaiseSyntaxError(PyObject *msg, PyObject *filename, int lineno, int col_o */ int _PyErr_EmitSyntaxWarning(PyObject *msg, PyObject *filename, int lineno, int col_offset, - int end_lineno, int end_col_offset) + int end_lineno, int end_col_offset, + PyObject *module) { - if (_PyErr_WarnExplicitObjectWithContext(PyExc_SyntaxWarning, msg, - filename, lineno) < 0) + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, filename, lineno, + module, NULL) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { /* Replace the SyntaxWarning exception with a SyntaxError diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 3dcb2decc43..9f3a207929f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -8,32 +8,88 @@ #endif #define TIER_TWO 2 - case _NOP: { + case _NOP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_PERIODIC: { + case _NOP_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _NOP_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _NOP_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_PERIODIC_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _CHECK_PERIODIC_AT_END is not a viable micro-op for tier 2 because it is replaced */ - case _CHECK_PERIODIC_IF_NOT_YIELD_FROM: { + case _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) { _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -41,10 +97,13 @@ /* _LOAD_BYTECODE is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _RESUME_CHECK: { + case _RESUME_CHECK_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); #if defined(__EMSCRIPTEN__) if (_Py_emscripten_signal_clock == 0) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; @@ -54,21 +113,153 @@ assert((version & _PY_EVAL_EVENTS_MASK) == 0); if (eval_breaker != version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #ifdef Py_GIL_DISABLED if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #endif + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _RESUME_CHECK_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); + assert((version & _PY_EVAL_EVENTS_MASK) == 0); + if (eval_breaker != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + if (frame->tlbc_index != + ((_PyThreadStateImpl *)tstate)->tlbc_index) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _RESUME_CHECK_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); + assert((version & _PY_EVAL_EVENTS_MASK) == 0); + if (eval_breaker != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + if (frame->tlbc_index != + ((_PyThreadStateImpl *)tstate)->tlbc_index) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _RESUME_CHECK_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); + assert((version & _PY_EVAL_EVENTS_MASK) == 0); + if (eval_breaker != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + if (frame->tlbc_index != + ((_PyThreadStateImpl *)tstate)->tlbc_index) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _MONITOR_RESUME is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _LOAD_FAST_CHECK: { + case _LOAD_FAST_CHECK_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); _PyStackRef value_s = GETLOCAL(oparg); @@ -79,641 +270,2078 @@ PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } value = PyStackRef_DUP(value_s); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_0: { + case _LOAD_FAST_CHECK_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + _PyStackRef value_s = GETLOCAL(oparg); + if (PyStackRef_IsNull(value_s)) { + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + value = PyStackRef_DUP(value_s); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_CHECK_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + _PyStackRef value_s = GETLOCAL(oparg); + if (PyStackRef_IsNull(value_s)) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + value = PyStackRef_DUP(value_s); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_0_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 0; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_1: { + case _LOAD_FAST_0_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_0_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_1_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 1; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_2: { + case _LOAD_FAST_1_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_2_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 2; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_3: { + case _LOAD_FAST_2_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_2_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_3_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 3; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_4: { + case _LOAD_FAST_3_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_3_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_4_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 4; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_5: { + case _LOAD_FAST_4_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_4_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_5_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 5; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_6: { + case _LOAD_FAST_5_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_5_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_6_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 6; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_7: { + case _LOAD_FAST_6_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_6_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_7_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 7; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST: { + case _LOAD_FAST_7_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_7_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_DUP(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_0: { + case _LOAD_FAST_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_DUP(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_0_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 0; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_1: { + case _LOAD_FAST_BORROW_0_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_0_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_1_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 1; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_2: { + case _LOAD_FAST_BORROW_1_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_2_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 2; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_3: { + case _LOAD_FAST_BORROW_2_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_2_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_3_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 3; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_4: { + case _LOAD_FAST_BORROW_3_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_3_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_4_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 4; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_5: { + case _LOAD_FAST_BORROW_4_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_4_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_5_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 5; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_6: { + case _LOAD_FAST_BORROW_5_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_5_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_6_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 6; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW_7: { + case _LOAD_FAST_BORROW_6_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_6_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_7_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 7; assert(oparg == CURRENT_OPARG()); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_BORROW: { + case _LOAD_FAST_BORROW_7_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_7_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); assert(!PyStackRef_IsNull(GETLOCAL(oparg))); value = PyStackRef_Borrow(GETLOCAL(oparg)); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FAST_AND_CLEAR: { + case _LOAD_FAST_BORROW_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_BORROW_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + assert(!PyStackRef_IsNull(GETLOCAL(oparg))); + value = PyStackRef_Borrow(GETLOCAL(oparg)); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_AND_CLEAR_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); value = GETLOCAL(oparg); GETLOCAL(oparg) = PyStackRef_NULL; - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_CONST: { + case _LOAD_FAST_AND_CLEAR_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + value = GETLOCAL(oparg); + GETLOCAL(oparg) = PyStackRef_NULL; + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_FAST_AND_CLEAR_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + value = GETLOCAL(oparg); + GETLOCAL(oparg) = PyStackRef_NULL; + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); value = PyStackRef_FromPyObjectBorrow(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SMALL_INT_0: { + case _LOAD_CONST_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_0_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 0; assert(oparg == CURRENT_OPARG()); assert(oparg < _PY_NSMALLPOSINTS); PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; value = PyStackRef_FromPyObjectBorrow(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SMALL_INT_1: { + case _LOAD_SMALL_INT_0_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_0_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_1_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 1; assert(oparg == CURRENT_OPARG()); assert(oparg < _PY_NSMALLPOSINTS); PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; value = PyStackRef_FromPyObjectBorrow(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SMALL_INT_2: { + case _LOAD_SMALL_INT_1_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_2_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 2; assert(oparg == CURRENT_OPARG()); assert(oparg < _PY_NSMALLPOSINTS); PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; value = PyStackRef_FromPyObjectBorrow(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SMALL_INT_3: { + case _LOAD_SMALL_INT_2_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_2_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_3_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = 3; assert(oparg == CURRENT_OPARG()); assert(oparg < _PY_NSMALLPOSINTS); PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; value = PyStackRef_FromPyObjectBorrow(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SMALL_INT: { + case _LOAD_SMALL_INT_3_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_3_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); assert(oparg < _PY_NSMALLPOSINTS); PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; value = PyStackRef_FromPyObjectBorrow(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_0: { + case _LOAD_SMALL_INT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_SMALL_INT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + assert(oparg < _PY_NSMALLPOSINTS); + PyObject *obj = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + oparg]; + value = PyStackRef_FromPyObjectBorrow(obj); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_FAST_0_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 0; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_1: { + case _STORE_FAST_1_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 1; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_2: { + case _STORE_FAST_2_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 2; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_3: { + case _STORE_FAST_3_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 3; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_4: { + case _STORE_FAST_4_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 4; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_5: { + case _STORE_FAST_5_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 5; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_6: { + case _STORE_FAST_6_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 6; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST_7: { + case _STORE_FAST_7_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = 7; assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_FAST: { + case _STORE_FAST_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - value = stack_pointer[-1]; + value = _stack_item_0; _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_TOP: { + case _POP_TOP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; - value = stack_pointer[-1]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_TOP_NOP: { + case _POP_TOP_NOP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; assert(PyStackRef_IsNull(value) || (!PyStackRef_RefcountOnObject(value)) || _Py_IsImmortal((PyStackRef_AsPyObjectBorrow(value)))); + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_TOP_INT: { + case _POP_TOP_NOP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + assert(PyStackRef_IsNull(value) || (!PyStackRef_RefcountOnObject(value)) || + _Py_IsImmortal((PyStackRef_AsPyObjectBorrow(value)))); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_NOP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + assert(PyStackRef_IsNull(value) || (!PyStackRef_RefcountOnObject(value)) || + _Py_IsImmortal((PyStackRef_AsPyObjectBorrow(value)))); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_NOP_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + assert(PyStackRef_IsNull(value) || (!PyStackRef_RefcountOnObject(value)) || + _Py_IsImmortal((PyStackRef_AsPyObjectBorrow(value)))); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_INT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_TOP_FLOAT: { + case _POP_TOP_INT_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_INT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_INT_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_FLOAT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_TOP_UNICODE: { + case _POP_TOP_FLOAT_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_FLOAT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_FLOAT_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_UNICODE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_TWO: { + case _POP_TOP_UNICODE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_UNICODE_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_UNICODE_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TWO_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef tos; _PyStackRef nos; - tos = stack_pointer[-1]; - nos = stack_pointer[-2]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + tos = _stack_item_1; + nos = _stack_item_0; + stack_pointer[0] = nos; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(tos); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(nos); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _PUSH_NULL: { + case _PUSH_NULL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef res; res = PyStackRef_NULL; - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _END_FOR: { + case _PUSH_NULL_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + res = PyStackRef_NULL; + _tos_cache1 = res; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _PUSH_NULL_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + res = PyStackRef_NULL; + _tos_cache2 = res; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _END_FOR_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; - value = stack_pointer[-1]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_ITER: { + case _POP_ITER_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef index_or_null; _PyStackRef iter; - index_or_null = stack_pointer[-1]; - iter = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + index_or_null = _stack_item_1; + iter = _stack_item_0; (void)index_or_null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iter); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _END_SEND: { + case _END_SEND_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef receiver; _PyStackRef val; - value = stack_pointer[-1]; - receiver = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + receiver = _stack_item_0; val = value; - stack_pointer[-2] = val; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[0] = val; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(receiver); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = val; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNARY_NEGATIVE: { + case _UNARY_NEGATIVE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNARY_NOT: { + case _UNARY_NOT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; assert(PyStackRef_BoolCheck(value)); res = PyStackRef_IsFalse(value) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-1] = res; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TO_BOOL: { + case _UNARY_NOT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + assert(PyStackRef_BoolCheck(value)); + res = PyStackRef_IsFalse(value) + ? PyStackRef_True : PyStackRef_False; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _UNARY_NOT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + assert(PyStackRef_BoolCheck(value)); + res = PyStackRef_IsFalse(value) + ? PyStackRef_True : PyStackRef_False; + _tos_cache1 = res; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _UNARY_NOT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + assert(PyStackRef_BoolCheck(value)); + res = PyStackRef_IsFalse(value) + ? PyStackRef_True : PyStackRef_False; + _tos_cache2 = res; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = err ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TO_BOOL_BOOL: { + case _TO_BOOL_BOOL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; if (!PyStackRef_BoolCheck(value)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(TO_BOOL, hit); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TO_BOOL_INT: { + case _TO_BOOL_BOOL_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + if (!PyStackRef_BoolCheck(value)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(TO_BOOL, hit); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_BOOL_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + if (!PyStackRef_BoolCheck(value)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(TO_BOOL, hit); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_BOOL_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + if (!PyStackRef_BoolCheck(value)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(TO_BOOL, hit); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_INT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); if (!PyLong_CheckExact(value_o)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } STAT_INC(TO_BOOL, hit); @@ -722,108 +2350,582 @@ res = PyStackRef_False; } else { - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); res = PyStackRef_True; - stack_pointer += 1; } - stack_pointer[-1] = res; + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_LIST: { + case _GUARD_NOS_LIST_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef nos; nos = stack_pointer[-2]; PyObject *o = PyStackRef_AsPyObjectBorrow(nos); if (!PyList_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_LIST: { + case _GUARD_NOS_LIST_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + nos = stack_pointer[-1]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_LIST_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + nos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_LIST_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + nos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_LIST_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef tos; tos = stack_pointer[-1]; PyObject *o = PyStackRef_AsPyObjectBorrow(tos); if (!PyList_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_SLICE: { + case _GUARD_TOS_LIST_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + tos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyList_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_LIST_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + tos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyList_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_LIST_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + tos = _stack_item_2; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyList_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_SLICE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef tos; tos = stack_pointer[-1]; PyObject *o = PyStackRef_AsPyObjectBorrow(tos); if (!PySlice_Check(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TO_BOOL_LIST: { + case _GUARD_TOS_SLICE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + tos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PySlice_Check(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_SLICE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + tos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PySlice_Check(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_SLICE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + tos = _stack_item_2; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PySlice_Check(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_LIST_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); assert(PyList_CheckExact(value_o)); STAT_INC(TO_BOOL, hit); res = PyList_GET_SIZE(value_o) ? PyStackRef_True : PyStackRef_False; + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = value; value = res; stack_pointer[-1] = value; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TO_BOOL_NONE: { + case _TO_BOOL_NONE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; value = stack_pointer[-1]; if (!PyStackRef_IsNone(value)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(TO_BOOL, hit); res = PyStackRef_False; - stack_pointer[-1] = res; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_UNICODE: { + case _TO_BOOL_NONE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + if (!PyStackRef_IsNone(value)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(TO_BOOL, hit); + res = PyStackRef_False; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_NONE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + if (!PyStackRef_IsNone(value)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(TO_BOOL, hit); + res = PyStackRef_False; + _tos_cache1 = res; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_NONE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + if (!PyStackRef_IsNone(value)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(TO_BOOL, hit); + res = PyStackRef_False; + _tos_cache2 = res; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_UNICODE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef nos; nos = stack_pointer[-2]; PyObject *o = PyStackRef_AsPyObjectBorrow(nos); if (!PyUnicode_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_UNICODE: { + case _GUARD_NOS_UNICODE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + nos = stack_pointer[-1]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyUnicode_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_UNICODE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + nos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyUnicode_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_UNICODE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + nos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyUnicode_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_UNICODE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); if (!PyUnicode_CheckExact(value_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TO_BOOL_STR: { + case _GUARD_TOS_UNICODE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!PyUnicode_CheckExact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_UNICODE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!PyUnicode_CheckExact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_UNICODE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!PyUnicode_CheckExact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TO_BOOL_STR_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; STAT_INC(TO_BOOL, hit); PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); if (value_o == &_Py_STR(empty)) { @@ -832,106 +2934,433 @@ } else { assert(Py_SIZE(value_o)); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); res = PyStackRef_True; - stack_pointer += 1; } - stack_pointer[-1] = res; + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _REPLACE_WITH_TRUE: { + case _REPLACE_WITH_TRUE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); res = PyStackRef_True; - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNARY_INVERT: { + case _UNARY_INVERT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_INT: { + case _GUARD_NOS_INT_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef left; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); if (!_PyLong_CheckExactAndCompact(left_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_INT: { + case _GUARD_NOS_INT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + if (!_PyLong_CheckExactAndCompact(left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_INT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + if (!_PyLong_CheckExactAndCompact(left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_INT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + left = _stack_item_1; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + if (!_PyLong_CheckExactAndCompact(left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = left; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = left; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_INT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); if (!_PyLong_CheckExactAndCompact(value_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_OVERFLOWED: { + case _GUARD_TOS_INT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!_PyLong_CheckExactAndCompact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_INT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!_PyLong_CheckExactAndCompact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_INT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!_PyLong_CheckExactAndCompact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_OVERFLOWED_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef left; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); assert(Py_TYPE(left_o) == &PyLong_Type); if (!_PyLong_IsCompact((PyLongObject *)left_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_OVERFLOWED: { + case _GUARD_NOS_OVERFLOWED_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + assert(Py_TYPE(left_o) == &PyLong_Type); + if (!_PyLong_IsCompact((PyLongObject *)left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_OVERFLOWED_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + assert(Py_TYPE(left_o) == &PyLong_Type); + if (!_PyLong_IsCompact((PyLongObject *)left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_OVERFLOWED_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + left = _stack_item_1; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + assert(Py_TYPE(left_o) == &PyLong_Type); + if (!_PyLong_IsCompact((PyLongObject *)left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = left; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = left; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_OVERFLOWED_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); assert(Py_TYPE(value_o) == &PyLong_Type); if (!_PyLong_IsCompact((PyLongObject *)value_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_MULTIPLY_INT: { + case _GUARD_TOS_OVERFLOWED_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + assert(Py_TYPE(value_o) == &PyLong_Type); + if (!_PyLong_IsCompact((PyLongObject *)value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_OVERFLOWED_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + assert(Py_TYPE(value_o) == &PyLong_Type); + if (!_PyLong_IsCompact((PyLongObject *)value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_OVERFLOWED_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + assert(Py_TYPE(value_o) == &PyLong_Type); + if (!_PyLong_IsCompact((PyLongObject *)value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_MULTIPLY_INT_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -943,20 +3372,101 @@ res = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); if (PyStackRef_IsNull(res)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_ADD_INT: { + case _BINARY_OP_MULTIPLY_INT_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyLong_CheckExact(left_o)); + assert(PyLong_CheckExact(right_o)); + assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); + STAT_INC(BINARY_OP, hit); + res = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); + if (PyStackRef_IsNull(res)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = right; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_MULTIPLY_INT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyLong_CheckExact(left_o)); + assert(PyLong_CheckExact(right_o)); + assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); + STAT_INC(BINARY_OP, hit); + res = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); + if (PyStackRef_IsNull(res)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = right; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_ADD_INT_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -968,20 +3478,101 @@ res = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); if (PyStackRef_IsNull(res)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBTRACT_INT: { + case _BINARY_OP_ADD_INT_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyLong_CheckExact(left_o)); + assert(PyLong_CheckExact(right_o)); + assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); + STAT_INC(BINARY_OP, hit); + res = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); + if (PyStackRef_IsNull(res)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = right; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_ADD_INT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyLong_CheckExact(left_o)); + assert(PyLong_CheckExact(right_o)); + assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); + STAT_INC(BINARY_OP, hit); + res = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); + if (PyStackRef_IsNull(res)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = right; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBTRACT_INT_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -993,123 +3584,275 @@ res = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); if (PyStackRef_IsNull(res)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_FLOAT: { + case _BINARY_OP_SUBTRACT_INT_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyLong_CheckExact(left_o)); + assert(PyLong_CheckExact(right_o)); + assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); + STAT_INC(BINARY_OP, hit); + res = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); + if (PyStackRef_IsNull(res)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = right; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBTRACT_INT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyLong_CheckExact(left_o)); + assert(PyLong_CheckExact(right_o)); + assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); + STAT_INC(BINARY_OP, hit); + res = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); + if (PyStackRef_IsNull(res)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = right; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_FLOAT_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef left; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); if (!PyFloat_CheckExact(left_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_FLOAT: { + case _GUARD_NOS_FLOAT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + if (!PyFloat_CheckExact(left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_FLOAT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + if (!PyFloat_CheckExact(left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_FLOAT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + left = _stack_item_1; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + if (!PyFloat_CheckExact(left_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = left; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = left; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_FLOAT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; value = stack_pointer[-1]; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); if (!PyFloat_CheckExact(value_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } - break; - } - - case _BINARY_OP_MULTIPLY_FLOAT: { - _PyStackRef right; - _PyStackRef left; - _PyStackRef res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval * - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - if (PyStackRef_IsNull(res)) { - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } - stack_pointer[-2] = res; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_ADD_FLOAT: { - _PyStackRef right; - _PyStackRef left; - _PyStackRef res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval + - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - if (PyStackRef_IsNull(res)) { - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); + case _GUARD_TOS_FLOAT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!PyFloat_CheckExact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBTRACT_FLOAT: { - _PyStackRef right; - _PyStackRef left; - _PyStackRef res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval - - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - if (PyStackRef_IsNull(res)) { - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); + case _GUARD_TOS_FLOAT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + value = _stack_item_1; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!PyFloat_CheckExact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS: { + case _GUARD_TOS_FLOAT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + value = _stack_item_2; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); + if (!PyFloat_CheckExact(value_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_MULTIPLY_FLOAT_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -1122,21 +3865,107 @@ ((PyFloatObject *)right_o)->ob_fval; res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); if (PyStackRef_IsNull(res)) { - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS: { + case _BINARY_OP_MULTIPLY_FLOAT_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyFloat_CheckExact(left_o)); + assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval * + ((PyFloatObject *)right_o)->ob_fval; + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = right; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_MULTIPLY_FLOAT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyFloat_CheckExact(left_o)); + assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval * + ((PyFloatObject *)right_o)->ob_fval; + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_ADD_FLOAT_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -1149,21 +3978,107 @@ ((PyFloatObject *)right_o)->ob_fval; res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); if (PyStackRef_IsNull(res)) { - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS: { + case _BINARY_OP_ADD_FLOAT_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyFloat_CheckExact(left_o)); + assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval + + ((PyFloatObject *)right_o)->ob_fval; + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = right; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_ADD_FLOAT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyFloat_CheckExact(left_o)); + assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval + + ((PyFloatObject *)right_o)->ob_fval; + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBTRACT_FLOAT_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -1176,21 +4091,107 @@ ((PyFloatObject *)right_o)->ob_fval; res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); if (PyStackRef_IsNull(res)) { - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_ADD_UNICODE: { + case _BINARY_OP_SUBTRACT_FLOAT_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyFloat_CheckExact(left_o)); + assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval - + ((PyFloatObject *)right_o)->ob_fval; + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = right; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBTRACT_FLOAT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyFloat_CheckExact(left_o)); + assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval - + ((PyFloatObject *)right_o)->ob_fval; + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_ADD_UNICODE_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -1199,25 +4200,106 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_INPLACE_ADD_UNICODE: { + case _BINARY_OP_ADD_UNICODE_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyUnicode_CheckExact(left_o)); + assert(PyUnicode_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyUnicode_Concat(left_o, right_o); + res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = right; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_ADD_UNICODE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert(PyUnicode_CheckExact(left_o)); + assert(PyUnicode_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyUnicode_Concat(left_o, right_o); + res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_INPLACE_ADD_UNICODE_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); assert(PyUnicode_CheckExact(left_o)); assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(right))); @@ -1226,12 +4308,15 @@ assert(next_instr->op.code == STORE_FAST); next_oparg = next_instr->op.arg; #else - next_oparg = CURRENT_OPERAND0(); + next_oparg = (int)CURRENT_OPERAND0_16(); #endif _PyStackRef *target_local = &GETLOCAL(next_oparg); assert(PyUnicode_CheckExact(left_o)); if (PyStackRef_AsPyObjectBorrow(*target_local) != left_o) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = right; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } STAT_INC(BINARY_OP, hit); @@ -1239,8 +4324,6 @@ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); PyObject *right_o = PyStackRef_AsPyObjectSteal(right); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyUnicode_Append(&temp, right_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1249,6 +4332,7 @@ Py_DECREF(right_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(*target_local)) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } #if TIER_ONE @@ -1256,42 +4340,75 @@ assert(next_instr->op.code == STORE_FAST); SKIP_OVER(1); #endif + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_BINARY_OP_EXTEND: { + case _GUARD_BINARY_OP_EXTEND_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); assert(d && d->guard); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = d->guard(left_o, right_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (!res) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = right; + _tos_cache0 = left; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = right; + _tos_cache0 = left; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_EXTEND: { + case _BINARY_OP_EXTEND_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; STAT_INC(BINARY_OP, hit); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = d->action(left_o, right_o); _PyStackRef tmp = right; @@ -1304,22 +4421,34 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_SLICE: { + case _BINARY_SLICE_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef stop; _PyStackRef start; _PyStackRef container; _PyStackRef res; - stop = stack_pointer[-1]; - start = stack_pointer[-2]; - container = stack_pointer[-3]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + stop = _stack_item_2; + start = _stack_item_1; + container = _stack_item_0; + stack_pointer[0] = container; + stack_pointer[1] = start; + stack_pointer[2] = stop; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), PyStackRef_AsPyObjectSteal(stop)); @@ -1330,7 +4459,7 @@ } else { stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); Py_DECREF(slice); @@ -1338,29 +4467,42 @@ stack_pointer += 2; } stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(container); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_SLICE: { + case _STORE_SLICE_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef stop; _PyStackRef start; _PyStackRef container; _PyStackRef v; - stop = stack_pointer[-1]; - start = stack_pointer[-2]; - container = stack_pointer[-3]; - v = stack_pointer[-4]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + stop = _stack_item_2; + start = _stack_item_1; + container = _stack_item_0; + v = stack_pointer[-1]; + stack_pointer[0] = container; + stack_pointer[1] = start; + stack_pointer[2] = stop; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), PyStackRef_AsPyObjectSteal(stop)); @@ -1371,7 +4513,7 @@ } else { stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); Py_DECREF(slice); @@ -1389,34 +4531,56 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -4; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_LIST_INT: { + case _BINARY_OP_SUBSCR_LIST_INT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef list_st; _PyStackRef res; - sub_st = stack_pointer[-1]; - list_st = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + sub_st = _stack_item_1; + list_st = _stack_item_0; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); assert(PyLong_CheckExact(sub)); assert(PyList_CheckExact(list)); if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = list_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; #ifdef Py_GIL_DISABLED + stack_pointer[0] = list_st; + stack_pointer[1] = sub_st; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyList_GetItemRef((PyListObject*)list, index); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = list_st; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_JUMP_TARGET(); } STAT_INC(BINARY_OP, hit); @@ -1424,12 +4588,16 @@ #else if (index >= PyList_GET_SIZE(list)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = list_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } STAT_INC(BINARY_OP, hit); PyObject *res_o = PyList_GET_ITEM(list, index); assert(res_o != NULL); res = PyStackRef_FromPyObjectNew(res_o); + stack_pointer += 2; #endif STAT_INC(BINARY_OP, hit); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1443,20 +4611,35 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_LIST_SLICE: { + case _BINARY_OP_SUBSCR_LIST_SLICE_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef list_st; _PyStackRef res; - sub_st = stack_pointer[-1]; - list_st = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + sub_st = _stack_item_1; + list_st = _stack_item_0; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); assert(PySlice_Check(sub)); assert(PyList_CheckExact(list)); + stack_pointer[0] = list_st; + stack_pointer[1] = sub_st; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyList_SliceSubscript(list, sub); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1472,95 +4655,274 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_STR_INT: { + case _BINARY_OP_SUBSCR_STR_INT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef str_st; _PyStackRef res; - sub_st = stack_pointer[-1]; - str_st = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + sub_st = _stack_item_1; + str_st = _stack_item_0; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *str = PyStackRef_AsPyObjectBorrow(str_st); assert(PyLong_CheckExact(sub)); assert(PyUnicode_CheckExact(str)); if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = str_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; if (PyUnicode_GET_LENGTH(str) <= index) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = str_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } - Py_UCS4 c = PyUnicode_READ_CHAR(str, index); - if (Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c) { + if (!PyUnicode_IS_COMPACT_ASCII(str)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = str_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } + uint8_t c = PyUnicode_1BYTE_DATA(str)[index]; + assert(c < 128); STAT_INC(BINARY_OP, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(str_st); stack_pointer = _PyFrame_GetStackPointer(frame); res = PyStackRef_FromPyObjectBorrow(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_TUPLE: { + case _GUARD_NOS_TUPLE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef nos; nos = stack_pointer[-2]; PyObject *o = PyStackRef_AsPyObjectBorrow(nos); if (!PyTuple_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_TUPLE: { + case _GUARD_NOS_TUPLE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + nos = stack_pointer[-1]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyTuple_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_TUPLE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + nos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyTuple_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_TUPLE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + nos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyTuple_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_TUPLE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef tos; tos = stack_pointer[-1]; PyObject *o = PyStackRef_AsPyObjectBorrow(tos); if (!PyTuple_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_TUPLE_INT: { + case _GUARD_TOS_TUPLE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + tos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyTuple_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_TUPLE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + tos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyTuple_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_TUPLE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + tos = _stack_item_2; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyTuple_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBSCR_TUPLE_INT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef tuple_st; _PyStackRef res; - sub_st = stack_pointer[-1]; - tuple_st = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + sub_st = _stack_item_1; + tuple_st = _stack_item_0; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *tuple = PyStackRef_AsPyObjectBorrow(tuple_st); assert(PyLong_CheckExact(sub)); assert(PyTuple_CheckExact(tuple)); if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = tuple_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; if (index >= PyTuple_GET_SIZE(tuple)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = sub_st; + _tos_cache0 = tuple_st; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } STAT_INC(BINARY_OP, hit); @@ -1568,50 +4930,218 @@ assert(res_o != NULL); PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); res = PyStackRef_FromPyObjectNew(res_o); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[0] = tuple_st; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = tuple_st; tuple_st = res; stack_pointer[-1] = tuple_st; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_DICT: { + case _GUARD_NOS_DICT_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef nos; nos = stack_pointer[-2]; PyObject *o = PyStackRef_AsPyObjectBorrow(nos); if (!PyDict_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_DICT: { + case _GUARD_NOS_DICT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + nos = stack_pointer[-1]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyDict_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_DICT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + nos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyDict_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_DICT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + nos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyDict_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_DICT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef tos; tos = stack_pointer[-1]; PyObject *o = PyStackRef_AsPyObjectBorrow(tos); if (!PyDict_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_DICT: { + case _GUARD_TOS_DICT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + tos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyDict_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_DICT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + tos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyDict_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_DICT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + tos = _stack_item_2; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyDict_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBSCR_DICT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef dict_st; _PyStackRef res; - sub_st = stack_pointer[-1]; - dict_st = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + sub_st = _stack_item_1; + dict_st = _stack_item_0; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); assert(PyDict_CheckExact(dict)); STAT_INC(BINARY_OP, hit); PyObject *res_o; + stack_pointer[0] = dict_st; + stack_pointer[1] = sub_st; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int rc = PyDict_GetItemRef(dict, sub, &res_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1631,53 +5161,76 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (rc <= 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_CHECK_FUNC: { + case _BINARY_OP_SUBSCR_CHECK_FUNC_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef container; _PyStackRef getitem; - container = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + container = _stack_item_0; PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = container; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); if (getitem_o == NULL) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = container; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } assert(PyFunction_Check(getitem_o)); uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); if (((PyFunctionObject *)getitem_o)->func_version != cached_version) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = container; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); assert(code->co_argcount == 2); if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = container; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } getitem = PyStackRef_FromPyObjectNew(getitem_o); STAT_INC(BINARY_OP, hit); - stack_pointer[0] = getitem; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = getitem; + _tos_cache1 = _stack_item_1; + _tos_cache0 = container; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_SUBSCR_INIT_CALL: { + case _BINARY_OP_SUBSCR_INIT_CALL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef getitem; _PyStackRef sub; _PyStackRef container; @@ -1688,59 +5241,158 @@ _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; - frame->return_offset = 6 ; + frame->return_offset = 6u ; new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-3] = new_frame; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LIST_APPEND: { + case _BINARY_OP_SUBSCR_INIT_CALL_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef getitem; + _PyStackRef sub; + _PyStackRef container; + _PyStackRef new_frame; + _PyStackRef _stack_item_0 = _tos_cache0; + getitem = _stack_item_0; + sub = stack_pointer[-1]; + container = stack_pointer[-2]; + _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); + pushed_frame->localsplus[0] = container; + pushed_frame->localsplus[1] = sub; + frame->return_offset = 6u ; + new_frame = PyStackRef_Wrap(pushed_frame); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBSCR_INIT_CALL_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef getitem; + _PyStackRef sub; + _PyStackRef container; + _PyStackRef new_frame; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + getitem = _stack_item_1; + sub = _stack_item_0; + container = stack_pointer[-1]; + _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); + pushed_frame->localsplus[0] = container; + pushed_frame->localsplus[1] = sub; + frame->return_offset = 6u ; + new_frame = PyStackRef_Wrap(pushed_frame); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BINARY_OP_SUBSCR_INIT_CALL_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef getitem; + _PyStackRef sub; + _PyStackRef container; + _PyStackRef new_frame; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + getitem = _stack_item_2; + sub = _stack_item_1; + container = _stack_item_0; + _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); + pushed_frame->localsplus[0] = container; + pushed_frame->localsplus[1] = sub; + frame->return_offset = 6u ; + new_frame = PyStackRef_Wrap(pushed_frame); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LIST_APPEND_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; _PyStackRef list; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - v = stack_pointer[-1]; - list = stack_pointer[-2 - (oparg-1)]; + v = _stack_item_0; + list = stack_pointer[-1 - (oparg-1)]; int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), PyStackRef_AsPyObjectSteal(v)); if (err < 0) { - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SET_ADD: { + case _SET_ADD_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; _PyStackRef set; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - v = stack_pointer[-1]; - set = stack_pointer[-2 - (oparg-1)]; + v = _stack_item_0; + set = stack_pointer[-1 - (oparg-1)]; + stack_pointer[0] = v; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PySet_AddTakeRef((PySetObject *)PyStackRef_AsPyObjectBorrow(set), PyStackRef_AsPyObjectSteal(v)); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_SUBSCR: { + case _STORE_SUBSCR_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub; _PyStackRef container; _PyStackRef v; - sub = stack_pointer[-1]; - container = stack_pointer[-2]; - v = stack_pointer[-3]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + sub = _stack_item_2; + container = _stack_item_1; + v = _stack_item_0; + stack_pointer[0] = v; + stack_pointer[1] = container; + stack_pointer[2] = sub; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub), PyStackRef_AsPyObjectBorrow(v)); _PyStackRef tmp = sub; @@ -1757,37 +5409,62 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_SUBSCR_LIST_INT: { + case _STORE_SUBSCR_LIST_INT_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef list_st; _PyStackRef value; - sub_st = stack_pointer[-1]; - list_st = stack_pointer[-2]; - value = stack_pointer[-3]; + _PyStackRef ls; + _PyStackRef ss; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + sub_st = _stack_item_2; + list_st = _stack_item_1; + value = _stack_item_0; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); assert(PyLong_CheckExact(sub)); assert(PyList_CheckExact(list)); if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = sub_st; + _tos_cache1 = list_st; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; if (!LOCK_OBJECT(list)) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = sub_st; + _tos_cache1 = list_st; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } if (index >= PyList_GET_SIZE(list)) { UNLOCK_OBJECT(list); if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = sub_st; + _tos_cache1 = list_st; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } } @@ -1797,47 +5474,84 @@ PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); UNLOCK_OBJECT(list); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ls = list_st; + ss = sub_st; + stack_pointer[0] = ls; + stack_pointer[1] = ss; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(list_st); Py_DECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache1 = ss; + _tos_cache0 = ls; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_SUBSCR_DICT: { + case _STORE_SUBSCR_DICT_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub; _PyStackRef dict_st; _PyStackRef value; - sub = stack_pointer[-1]; - dict_st = stack_pointer[-2]; - value = stack_pointer[-3]; + _PyStackRef st; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + sub = _stack_item_2; + dict_st = _stack_item_1; + value = _stack_item_0; PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); assert(PyDict_CheckExact(dict)); STAT_INC(STORE_SUBSCR, hit); + stack_pointer[0] = value; + stack_pointer[1] = dict_st; + stack_pointer[2] = sub; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, PyStackRef_AsPyObjectSteal(sub), PyStackRef_AsPyObjectSteal(value)); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(dict_st); - stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(dict_st); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + st = dict_st; + _tos_cache0 = st; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DELETE_SUBSCR: { + case _DELETE_SUBSCR_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub; _PyStackRef container; - sub = stack_pointer[-1]; - container = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + sub = _stack_item_1; + container = _stack_item_0; + stack_pointer[0] = container; + stack_pointer[1] = sub; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_DelItem(PyStackRef_AsPyObjectBorrow(container), PyStackRef_AsPyObjectBorrow(sub)); @@ -1851,47 +5565,70 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_INTRINSIC_1: { + case _CALL_INTRINSIC_1_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - value = stack_pointer[-1]; + value = _stack_item_0; assert(oparg <= MAX_INTRINSIC_1); + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_INTRINSIC_2: { + case _CALL_INTRINSIC_2_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value1_st; _PyStackRef value2_st; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - value1_st = stack_pointer[-1]; - value2_st = stack_pointer[-2]; + value1_st = _stack_item_1; + value2_st = _stack_item_0; assert(oparg <= MAX_INTRINSIC_2); PyObject *value1 = PyStackRef_AsPyObjectBorrow(value1_st); PyObject *value2 = PyStackRef_AsPyObjectBorrow(value2_st); + stack_pointer[0] = value2_st; + stack_pointer[1] = value1_st; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyIntrinsics_BinaryFunctions[oparg].func(tstate, value2, value1); _PyStackRef tmp = value1_st; @@ -1904,25 +5641,29 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _RETURN_VALUE: { + case _RETURN_VALUE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef retval; _PyStackRef res; - retval = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + retval = _stack_item_0; assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(STACK_LEVEL() == 0); _Py_LeaveRecursiveCallPy(tstate); @@ -1933,16 +5674,21 @@ LOAD_IP(frame->return_offset); res = temp; LLTRACE_RESUME_FRAME(); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GET_AITER: { + case _GET_AITER_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef obj; _PyStackRef iter; - obj = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + obj = _stack_item_0; unaryfunc getter = NULL; PyObject *obj_o = PyStackRef_AsPyObjectBorrow(obj); PyObject *iter_o; @@ -1951,6 +5697,9 @@ getter = type->tp_as_async->am_aiter; } if (getter == NULL) { + stack_pointer[0] = obj; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an object with " @@ -1958,21 +5707,26 @@ type->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(obj); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + stack_pointer[0] = obj; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); iter_o = (*getter)(obj_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(obj); stack_pointer = _PyFrame_GetStackPointer(frame); if (iter_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (Py_TYPE(iter_o)->tp_as_async == NULL || @@ -1984,71 +5738,104 @@ Py_TYPE(iter_o)->tp_name); Py_DECREF(iter_o); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[0] = iter; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = iter; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GET_ANEXT: { + case _GET_ANEXT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef aiter; _PyStackRef awaitable; - aiter = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + aiter = _stack_item_0; + stack_pointer[0] = aiter; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *awaitable_o = _PyEval_GetANext(PyStackRef_AsPyObjectBorrow(aiter)); stack_pointer = _PyFrame_GetStackPointer(frame); if (awaitable_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } awaitable = PyStackRef_FromPyObjectSteal(awaitable_o); - stack_pointer[0] = awaitable; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = awaitable; + _tos_cache0 = aiter; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GET_AWAITABLE: { + case _GET_AWAITABLE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iterable; _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - iterable = stack_pointer[-1]; + iterable = _stack_item_0; + stack_pointer[0] = iterable; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); if (iter_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[0] = iter; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = iter; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _SEND is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _SEND_GEN_FRAME: { + case _SEND_GEN_FRAME_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; _PyStackRef receiver; _PyStackRef gen_frame; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - v = stack_pointer[-1]; - receiver = stack_pointer[-2]; + v = _stack_item_1; + receiver = _stack_item_0; PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver); if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = v; + _tos_cache0 = receiver; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } if (gen->gi_frame_state >= FRAME_EXECUTING) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = v; + _tos_cache0 = receiver; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } STAT_INC(SEND, hit); @@ -2057,19 +5844,26 @@ gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - assert( 2 + oparg <= UINT16_MAX); - frame->return_offset = (uint16_t)( 2 + oparg); + assert( 2u + oparg <= UINT16_MAX); + frame->return_offset = (uint16_t)( 2u + oparg); pushed_frame->previous = frame; gen_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-1] = gen_frame; + _tos_cache1 = gen_frame; + _tos_cache0 = receiver; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _YIELD_VALUE: { + case _YIELD_VALUE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef retval; _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - retval = stack_pointer[-1]; + retval = _stack_item_0; assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); frame->instr_ptr++; PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); @@ -2077,8 +5871,6 @@ assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; @@ -2099,44 +5891,94 @@ LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); value = PyStackRef_MakeHeapSafe(temp); LLTRACE_RESUME_FRAME(); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _POP_EXCEPT: { + case _POP_EXCEPT_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef exc_value; - exc_value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + exc_value = _stack_item_0; _PyErr_StackItem *exc_info = tstate->exc_info; + stack_pointer[0] = exc_value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); Py_XSETREF(exc_info->exc_value, PyStackRef_IsNone(exc_value) ? NULL : PyStackRef_AsPyObjectSteal(exc_value)); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_COMMON_CONSTANT: { + case _LOAD_COMMON_CONSTANT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); assert(oparg < NUM_COMMON_CONSTANTS); value = PyStackRef_FromPyObjectNew(tstate->interp->common_consts[oparg]); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_BUILD_CLASS: { + case _LOAD_COMMON_CONSTANT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + assert(oparg < NUM_COMMON_CONSTANTS); + value = PyStackRef_FromPyObjectNew(tstate->interp->common_consts[oparg]); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_COMMON_CONSTANT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + assert(oparg < NUM_COMMON_CONSTANTS); + value = PyStackRef_FromPyObjectNew(tstate->interp->common_consts[oparg]); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_BUILD_CLASS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef bc; PyObject *bc_o; _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (bc_o == NULL) { @@ -2144,56 +5986,80 @@ _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } bc = PyStackRef_FromPyObjectSteal(bc_o); - stack_pointer[0] = bc; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = bc; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_NAME: { + case _STORE_NAME_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - v = stack_pointer[-1]; + v = _stack_item_0; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { + stack_pointer[0] = v; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (PyDict_CheckExact(ns)) { + stack_pointer[0] = v; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); err = PyDict_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); stack_pointer = _PyFrame_GetStackPointer(frame); } else { + stack_pointer[0] = v; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DELETE_NAME: { + case _DELETE_NAME_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); @@ -2203,6 +6069,7 @@ _PyErr_Format(tstate, PyExc_SystemError, "no locals when deleting %R", name); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFrame_SetStackPointer(frame, stack_pointer); @@ -2214,68 +6081,98 @@ NAME_ERROR_MSG, name); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE: { + case _UNPACK_SEQUENCE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *top; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - seq = stack_pointer[-1]; - top = &stack_pointer[-1 + oparg]; + seq = _stack_item_0; + top = &stack_pointer[oparg]; PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top); Py_DECREF(seq_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (res == 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE_TWO_TUPLE: { + case _UNPACK_SEQUENCE_TWO_TUPLE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef val1; _PyStackRef val0; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - seq = stack_pointer[-1]; + seq = _stack_item_0; assert(oparg == 2); PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); assert(PyTuple_CheckExact(seq_o)); if (PyTuple_GET_SIZE(seq_o) != 2) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = seq; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } STAT_INC(UNPACK_SEQUENCE, hit); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); - stack_pointer[-1] = val1; - stack_pointer[0] = val0; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[0] = val1; + stack_pointer[1] = val0; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(seq); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache1 = val0; + _tos_cache0 = val1; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE_TUPLE: { + case _UNPACK_SEQUENCE_TUPLE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *values; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; + seq = _stack_item_0; + values = &stack_pointer[0]; PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); assert(PyTuple_CheckExact(seq_o)); if (PyTuple_GET_SIZE(seq_o) != oparg) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = seq; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } STAT_INC(UNPACK_SEQUENCE, hit); @@ -2283,30 +6180,42 @@ for (int i = oparg; --i >= 0; ) { *values++ = PyStackRef_FromPyObjectNew(items[i]); } - stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer += oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(seq); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE_LIST: { + case _UNPACK_SEQUENCE_LIST_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *values; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; + seq = _stack_item_0; + values = &stack_pointer[0]; PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); assert(PyList_CheckExact(seq_o)); if (!LOCK_OBJECT(seq_o)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = seq; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (PyList_GET_SIZE(seq_o) != oparg) { UNLOCK_OBJECT(seq_o); if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = seq; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } @@ -2316,42 +6225,62 @@ *values++ = PyStackRef_FromPyObjectNew(items[i]); } UNLOCK_OBJECT(seq_o); - stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer += oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(seq); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_EX: { + case _UNPACK_EX_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *top; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - seq = stack_pointer[-1]; - top = &stack_pointer[(oparg & 0xFF) + (oparg >> 8)]; + seq = _stack_item_0; + top = &stack_pointer[1 + (oparg & 0xFF) + (oparg >> 8)]; PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg & 0xFF, oparg >> 8, top); Py_DECREF(seq_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (res == 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += 1 + (oparg & 0xFF) + (oparg >> 8); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_ATTR: { + case _STORE_ATTR_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef v; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - v = stack_pointer[-2]; + owner = _stack_item_1; + v = _stack_item_0; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + stack_pointer[0] = v; + stack_pointer[1] = owner; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_SetAttr(PyStackRef_AsPyObjectBorrow(owner), name, PyStackRef_AsPyObjectBorrow(v)); @@ -2365,58 +6294,91 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DELETE_ATTR: { + case _DELETE_ATTR_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; + owner = _stack_item_0; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + stack_pointer[0] = owner; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_GLOBAL: { + case _STORE_GLOBAL_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - v = stack_pointer[-1]; + v = _stack_item_0; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + stack_pointer[0] = v; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DELETE_GLOBAL: { + case _DELETE_GLOBAL_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_Pop(GLOBALS(), name, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (err == 0) { @@ -2424,12 +6386,20 @@ _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_LOCALS: { + case _LOAD_LOCALS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef locals; PyObject *l = LOCALS(); if (l == NULL) { @@ -2437,18 +6407,74 @@ _PyErr_SetString(tstate, PyExc_SystemError, "no locals found"); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } locals = PyStackRef_FromPyObjectNew(l); - stack_pointer[0] = locals; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = locals; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_LOCALS_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef locals; + _PyStackRef _stack_item_0 = _tos_cache0; + PyObject *l = LOCALS(); + if (l == NULL) { + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + locals = PyStackRef_FromPyObjectNew(l); + _tos_cache1 = locals; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_LOCALS_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef locals; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + PyObject *l = LOCALS(); + if (l == NULL) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + locals = PyStackRef_FromPyObjectNew(l); + _tos_cache2 = locals; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 because it has both popping and not-popping errors */ - case _LOAD_NAME: { + case _LOAD_NAME_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; oparg = CURRENT_OPARG(); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -2456,16 +6482,21 @@ PyObject *v_o = _PyEval_LoadName(tstate, frame, name); stack_pointer = _PyFrame_GetStackPointer(frame); if (v_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } v = PyStackRef_FromPyObjectSteal(v_o); - stack_pointer[0] = v; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = v; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_GLOBAL: { + case _LOAD_GLOBAL_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *res; oparg = CURRENT_OPARG(); res = &stack_pointer[0]; @@ -2474,53 +6505,163 @@ _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); stack_pointer = _PyFrame_GetStackPointer(frame); if (PyStackRef_IsNull(*res)) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _PUSH_NULL_CONDITIONAL: { + case _PUSH_NULL_CONDITIONAL_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *null; oparg = CURRENT_OPARG(); null = &stack_pointer[0]; if (oparg & 1) { null[0] = PyStackRef_NULL; } + SET_CURRENT_CACHED_VALUES(0); stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_GLOBALS_VERSION: { - uint16_t version = (uint16_t)CURRENT_OPERAND0(); + case _GUARD_GLOBALS_VERSION_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + uint16_t version = (uint16_t)CURRENT_OPERAND0_16(); PyDictObject *dict = (PyDictObject *)GLOBALS(); if (!PyDict_CheckExact(dict)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(DK_IS_UNICODE(keys)); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_GLOBAL_MODULE: { - _PyStackRef res; - uint16_t version = (uint16_t)CURRENT_OPERAND0(); - uint16_t index = (uint16_t)CURRENT_OPERAND1(); + case _GUARD_GLOBALS_VERSION_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + uint16_t version = (uint16_t)CURRENT_OPERAND0_16(); PyDictObject *dict = (PyDictObject *)GLOBALS(); if (!PyDict_CheckExact(dict)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + assert(DK_IS_UNICODE(keys)); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_GLOBALS_VERSION_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + uint16_t version = (uint16_t)CURRENT_OPERAND0_16(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + if (!PyDict_CheckExact(dict)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); + if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + assert(DK_IS_UNICODE(keys)); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_GLOBALS_VERSION_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + uint16_t version = (uint16_t)CURRENT_OPERAND0_16(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + if (!PyDict_CheckExact(dict)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); + if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + assert(DK_IS_UNICODE(keys)); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_GLOBAL_MODULE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef res; + uint16_t version = (uint16_t)CURRENT_OPERAND0_16(); + uint16_t index = (uint16_t)CURRENT_OPERAND1_16(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + if (!PyDict_CheckExact(dict)) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); + if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(DK_IS_UNICODE(keys)); @@ -2529,36 +6670,44 @@ PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #if Py_GIL_DISABLED int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); if (!increfed) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #else res = PyStackRef_FromPyObjectNew(res_o); #endif STAT_INC(LOAD_GLOBAL, hit); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_GLOBAL_BUILTINS: { + case _LOAD_GLOBAL_BUILTINS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef res; - uint16_t version = (uint16_t)CURRENT_OPERAND0(); - uint16_t index = (uint16_t)CURRENT_OPERAND1(); + uint16_t version = (uint16_t)CURRENT_OPERAND0_16(); + uint16_t index = (uint16_t)CURRENT_OPERAND1_16(); PyDictObject *dict = (PyDictObject *)BUILTINS(); if (!PyDict_CheckExact(dict)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(DK_IS_UNICODE(keys)); @@ -2566,25 +6715,31 @@ PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); if (res_o == NULL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #if Py_GIL_DISABLED int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); if (!increfed) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #else res = PyStackRef_FromPyObjectNew(res_o); #endif STAT_INC(LOAD_GLOBAL, hit); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DELETE_FAST: { + case _DELETE_FAST_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); _PyStackRef v = GETLOCAL(oparg); if (PyStackRef_IsNull(v)) { @@ -2594,6 +6749,7 @@ PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyStackRef tmp = GETLOCAL(oparg); @@ -2601,14 +6757,22 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MAKE_CELL: { + case _MAKE_CELL_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); PyObject *initial = PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); PyObject *cell = PyCell_New(initial); if (cell == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyStackRef tmp = GETLOCAL(oparg); @@ -2616,10 +6780,17 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DELETE_DEREF: { + case _DELETE_DEREF_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); PyObject *cell = PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL); @@ -2627,29 +6798,42 @@ _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFrame_SetStackPointer(frame, stack_pointer); Py_DECREF(oldobj); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_FROM_DICT_OR_DEREF: { + case _LOAD_FROM_DICT_OR_DEREF_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef class_dict_st; _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - class_dict_st = stack_pointer[-1]; + class_dict_st = _stack_item_0; PyObject *value_o; PyObject *name; PyObject *class_dict = PyStackRef_AsPyObjectBorrow(class_dict_st); assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); + stack_pointer[0] = class_dict_st; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyMapping_GetOptionalItem(class_dict, name, &value_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (!value_o) { @@ -2659,22 +6843,27 @@ _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(class_dict_st); stack_pointer = _PyFrame_GetStackPointer(frame); value = PyStackRef_FromPyObjectSteal(value_o); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_DEREF: { + case _LOAD_DEREF_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; oparg = CURRENT_OPARG(); PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); @@ -2684,32 +6873,48 @@ if (PyStackRef_IsNull(value)) { stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_DEREF: { + case _STORE_DEREF_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef v; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - v = stack_pointer[-1]; + v = _stack_item_0; PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); + stack_pointer[0] = v; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyCell_SetTakeRef(cell, PyStackRef_AsPyObjectSteal(v)); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COPY_FREE_VARS: { + case _COPY_FREE_VARS_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyStackRef_FunctionCheck(frame->f_funcobj)); @@ -2721,51 +6926,110 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = PyStackRef_FromPyObjectNew(o); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_STRING: { + case _COPY_FREE_VARS_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + PyCodeObject *co = _PyFrame_GetCode(frame); + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + PyObject *closure = func->func_closure; + assert(oparg == co->co_nfreevars); + int offset = co->co_nlocalsplus - oparg; + for (int i = 0; i < oparg; ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + frame->localsplus[offset + i] = PyStackRef_FromPyObjectNew(o); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_FREE_VARS_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + PyCodeObject *co = _PyFrame_GetCode(frame); + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + PyObject *closure = func->func_closure; + assert(oparg == co->co_nfreevars); + int offset = co->co_nlocalsplus - oparg; + for (int i = 0; i < oparg; ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + frame->localsplus[offset + i] = PyStackRef_FromPyObjectNew(o); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_FREE_VARS_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + PyCodeObject *co = _PyFrame_GetCode(frame); + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + PyObject *closure = func->func_closure; + assert(oparg == co->co_nfreevars); + int offset = co->co_nlocalsplus - oparg; + for (int i = 0; i < oparg; ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + frame->localsplus[offset + i] = PyStackRef_FromPyObjectNew(o); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _BUILD_STRING_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *pieces; _PyStackRef str; oparg = CURRENT_OPARG(); pieces = &stack_pointer[-oparg]; - STACKREFS_TO_PYOBJECTS(pieces, oparg, pieces_o); - if (CONVERSION_FAILED(pieces_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = pieces[_i]; - pieces[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } - PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); - STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = pieces[_i]; - pieces[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } + PyObject *str_o = _Py_BuildString_StackRefSteal(pieces, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); if (str_o == NULL) { + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } str = PyStackRef_FromPyObjectSteal(str_o); - stack_pointer[0] = str; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = str; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_INTERPOLATION: { + case _BUILD_INTERPOLATION_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *format; _PyStackRef str; _PyStackRef value; @@ -2789,7 +7053,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); if (oparg & 1) { stack_pointer += -(oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(format[0]); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2798,73 +7062,94 @@ stack_pointer += -(oparg & 1); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(str); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (interpolation_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } interpolation = PyStackRef_FromPyObjectSteal(interpolation_o); - stack_pointer[0] = interpolation; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = interpolation; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_TEMPLATE: { + case _BUILD_TEMPLATE_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef interpolations; _PyStackRef strings; _PyStackRef template; - interpolations = stack_pointer[-1]; - strings = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + interpolations = _stack_item_1; + strings = _stack_item_0; PyObject *strings_o = PyStackRef_AsPyObjectBorrow(strings); PyObject *interpolations_o = PyStackRef_AsPyObjectBorrow(interpolations); + stack_pointer[0] = strings; + stack_pointer[1] = interpolations; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *template_o = _PyTemplate_Build(strings_o, interpolations_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(interpolations); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(strings); stack_pointer = _PyFrame_GetStackPointer(frame); if (template_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } template = PyStackRef_FromPyObjectSteal(template_o); - stack_pointer[0] = template; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = template; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_TUPLE: { + case _BUILD_TUPLE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *values; _PyStackRef tup; oparg = CURRENT_OPARG(); values = &stack_pointer[-oparg]; PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); if (tup_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } tup = PyStackRef_FromPyObjectStealMortal(tup_o); - stack_pointer[-oparg] = tup; - stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = tup; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_LIST: { + case _BUILD_LIST_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *values; _PyStackRef list; oparg = CURRENT_OPARG(); @@ -2873,23 +7158,34 @@ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); if (list_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } list = PyStackRef_FromPyObjectStealMortal(list_o); - stack_pointer[-oparg] = list; - stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = list; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LIST_EXTEND: { + case _LIST_EXTEND_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iterable_st; _PyStackRef list_st; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - iterable_st = stack_pointer[-1]; - list_st = stack_pointer[-2 - (oparg-1)]; + iterable_st = _stack_item_0; + list_st = stack_pointer[-1 - (oparg-1)]; PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); PyObject *iterable = PyStackRef_AsPyObjectBorrow(iterable_st); + stack_pointer[0] = iterable_st; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2908,43 +7204,63 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable_st); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } assert(Py_IsNone(none_val)); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable_st); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SET_UPDATE: { + case _SET_UPDATE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iterable; _PyStackRef set; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - iterable = stack_pointer[-1]; - set = stack_pointer[-2 - (oparg-1)]; + iterable = _stack_item_0; + set = stack_pointer[-1 - (oparg-1)]; + stack_pointer[0] = iterable; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PySet_Update(PyStackRef_AsPyObjectBorrow(set), PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_SET: { + case _BUILD_SET_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *values; _PyStackRef set; oparg = CURRENT_OPARG(); @@ -2962,7 +7278,8 @@ } stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } int err = 0; @@ -2982,78 +7299,68 @@ } if (err) { stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); Py_DECREF(set_o); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } set = PyStackRef_FromPyObjectStealMortal(set_o); - stack_pointer[-oparg] = set; - stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = set; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_MAP: { + case _BUILD_MAP_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *values; _PyStackRef map; oparg = CURRENT_OPARG(); values = &stack_pointer[-oparg*2]; - STACKREFS_TO_PYOBJECTS(values, oparg*2, values_o); - if (CONVERSION_FAILED(values_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg*2; --_i >= 0;) { - tmp = values[_i]; - values[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg*2; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *map_o = _PyDict_FromItems( - values_o, 2, - values_o+1, 2, - oparg); + PyObject *map_o = _Py_BuildMap_StackRefSteal(values, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(values_o); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg*2; --_i >= 0;) { - tmp = values[_i]; - values[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg*2; - assert(WITHIN_STACK_BOUNDS()); if (map_o == NULL) { + stack_pointer += -oparg*2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } map = PyStackRef_FromPyObjectStealMortal(map_o); - stack_pointer[0] = map; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = map; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -oparg*2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SETUP_ANNOTATIONS: { + case _SETUP_ANNOTATIONS_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); PyObject *ann_dict; if (LOCALS() == NULL) { _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_Format(tstate, PyExc_SystemError, "no locals found when setting up annotations"); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (ann_dict == NULL) { @@ -3061,6 +7368,7 @@ ann_dict = PyDict_New(); stack_pointer = _PyFrame_GetStackPointer(frame); if (ann_dict == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3069,6 +7377,7 @@ Py_DECREF(ann_dict); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } } @@ -3077,17 +7386,28 @@ Py_DECREF(ann_dict); stack_pointer = _PyFrame_GetStackPointer(frame); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DICT_UPDATE: { + case _DICT_UPDATE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef update; _PyStackRef dict; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - update = stack_pointer[-1]; - dict = stack_pointer[-2 - (oparg - 1)]; + update = _stack_item_0; + dict = stack_pointer[-1 - (oparg - 1)]; PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict); PyObject *update_o = PyStackRef_AsPyObjectBorrow(update); + stack_pointer[0] = update; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = PyDict_Update(dict_o, update_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3103,31 +7423,43 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DICT_MERGE: { + case _DICT_MERGE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef update; _PyStackRef dict; _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - update = stack_pointer[-1]; - dict = stack_pointer[-2 - (oparg - 1)]; - callable = stack_pointer[-5 - (oparg - 1)]; + update = _stack_item_0; + dict = stack_pointer[-1 - (oparg - 1)]; + callable = stack_pointer[-4 - (oparg - 1)]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict); PyObject *update_o = PyStackRef_AsPyObjectBorrow(update); + stack_pointer[0] = update; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_MergeEx(dict_o, update_o, 2); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3136,30 +7468,44 @@ _PyEval_FormatKwargsError(tstate, callable_o, update_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MAP_ADD: { + case _MAP_ADD_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef key; _PyStackRef dict_st; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - value = stack_pointer[-1]; - key = stack_pointer[-2]; - dict_st = stack_pointer[-3 - (oparg - 1)]; + value = _stack_item_1; + key = _stack_item_0; + dict_st = stack_pointer[-1 - (oparg - 1)]; PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); assert(PyDict_CheckExact(dict)); + stack_pointer[0] = key; + stack_pointer[1] = value; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyDict_SetItem_Take2( (PyDictObject *)dict, @@ -3169,37 +7515,61 @@ stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) { stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SUPER_ATTR_ATTR: { + case _LOAD_SUPER_ATTR_ATTR_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_st; _PyStackRef class_st; _PyStackRef global_super_st; _PyStackRef attr_st; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; oparg = CURRENT_OPARG(); - self_st = stack_pointer[-1]; - class_st = stack_pointer[-2]; - global_super_st = stack_pointer[-3]; + self_st = _stack_item_2; + class_st = _stack_item_1; + global_super_st = _stack_item_0; PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); assert(!(oparg & 1)); if (global_super != (PyObject *)&PySuper_Type) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = self_st; + _tos_cache1 = class_st; + _tos_cache0 = global_super_st; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } if (!PyType_Check(class)) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = self_st; + _tos_cache1 = class_st; + _tos_cache0 = global_super_st; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + stack_pointer[0] = global_super_st; + stack_pointer[1] = class_st; + stack_pointer[2] = self_st; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); _PyStackRef tmp = self_st; @@ -3216,55 +7586,77 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (attr == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } attr_st = PyStackRef_FromPyObjectSteal(attr); - stack_pointer[0] = attr_st; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = attr_st; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SUPER_ATTR_METHOD: { + case _LOAD_SUPER_ATTR_METHOD_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_st; _PyStackRef class_st; _PyStackRef global_super_st; _PyStackRef attr; _PyStackRef self_or_null; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; oparg = CURRENT_OPARG(); - self_st = stack_pointer[-1]; - class_st = stack_pointer[-2]; - global_super_st = stack_pointer[-3]; + self_st = _stack_item_2; + class_st = _stack_item_1; + global_super_st = _stack_item_0; PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); assert(oparg & 1); if (global_super != (PyObject *)&PySuper_Type) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = self_st; + _tos_cache1 = class_st; + _tos_cache0 = global_super_st; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } if (!PyType_Check(class)) { UOP_STAT_INC(uopcode, miss); + _tos_cache2 = self_st; + _tos_cache1 = class_st; + _tos_cache0 = global_super_st; + SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; + stack_pointer[0] = global_super_st; + stack_pointer[1] = class_st; + stack_pointer[2] = self_st; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr_o = _PySuper_Lookup(cls, self, name, Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); stack_pointer = _PyFrame_GetStackPointer(frame); if (attr_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (method_found) { self_or_null = self_st; } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(self_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3272,7 +7664,7 @@ stack_pointer += 1; } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = global_super_st; global_super_st = self_or_null; @@ -3284,87 +7676,190 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); attr = PyStackRef_FromPyObjectSteal(attr_o); - stack_pointer[0] = attr; - stack_pointer[1] = self_or_null; - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = self_or_null; + _tos_cache0 = attr; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR: { + case _LOAD_ATTR_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; - _PyStackRef *attr; + _PyStackRef attr; _PyStackRef *self_or_null; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - attr = &stack_pointer[-1]; - self_or_null = &stack_pointer[0]; + owner = _stack_item_0; + self_or_null = &stack_pointer[1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { - *attr = PyStackRef_NULL; + _PyCStackRef method; + stack_pointer[0] = owner; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, attr); + _PyThreadState_PushCStackRef(tstate, &method); + int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref); stack_pointer = _PyFrame_GetStackPointer(frame); if (is_meth) { - assert(!PyStackRef_IsNull(*attr)); + assert(!PyStackRef_IsNull(method.ref)); self_or_null[0] = owner; + attr = _PyThreadState_PopCStackRefSteal(tstate, &method); } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(*attr)) { + self_or_null[0] = PyStackRef_NULL; + attr = _PyThreadState_PopCStackRefSteal(tstate, &method); + if (PyStackRef_IsNull(attr)) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - self_or_null[0] = PyStackRef_NULL; stack_pointer += 1; } } else { + stack_pointer[0] = owner; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); if (attr_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - *attr = PyStackRef_FromPyObjectSteal(attr_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); stack_pointer += 1; } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[-1] = attr; stack_pointer += (oparg&1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TYPE_VERSION: { + case _GUARD_TYPE_VERSION_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; - uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); assert(type_version != 0); if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TYPE_VERSION_AND_LOCK: { + case _GUARD_TYPE_VERSION_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_VERSION_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_VERSION_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_VERSION_AND_LOCK_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; - uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); assert(type_version != 0); if (!LOCK_OBJECT(owner_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyTypeObject *tp = Py_TYPE(owner_o); @@ -3372,13 +7867,126 @@ UNLOCK_OBJECT(owner_o); if (true) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_MANAGED_OBJECT_HAS_VALUES: { + case _GUARD_TYPE_VERSION_AND_LOCK_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(type_version != 0); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + PyTypeObject *tp = Py_TYPE(owner_o); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UNLOCK_OBJECT(owner_o); + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_VERSION_AND_LOCK_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(type_version != 0); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + PyTypeObject *tp = Py_TYPE(owner_o); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UNLOCK_OBJECT(owner_o); + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_VERSION_AND_LOCK_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(type_version != 0); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + PyTypeObject *tp = Py_TYPE(owner_o); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UNLOCK_OBJECT(owner_o); + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_MANAGED_OBJECT_HAS_VALUES_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); @@ -3386,21 +7994,103 @@ assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_INSTANCE_VALUE: { + case _CHECK_MANAGED_OBJECT_HAS_VALUES_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_MANAGED_OBJECT_HAS_VALUES_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_MANAGED_OBJECT_HAS_VALUES_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_INSTANCE_VALUE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; + _PyStackRef o; owner = stack_pointer[-1]; - uint16_t offset = (uint16_t)CURRENT_OPERAND0(); + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); if (attr_o == NULL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #ifdef Py_GIL_DISABLED @@ -3408,6 +8098,7 @@ if (!increfed) { if (true) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } } @@ -3415,22 +8106,114 @@ attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); - stack_pointer[-1] = attr; - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); - stack_pointer = _PyFrame_GetStackPointer(frame); + o = owner; + _tos_cache1 = o; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_MODULE: { + case _LOAD_ATTR_INSTANCE_VALUE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; - owner = stack_pointer[-1]; - uint32_t dict_version = (uint32_t)CURRENT_OPERAND0(); - uint16_t index = (uint16_t)CURRENT_OPERAND1(); + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); + if (attr_o == NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + int increfed = _Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr); + if (!increfed) { + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + #else + attr = PyStackRef_FromPyObjectNew(attr_o); + #endif + STAT_INC(LOAD_ATTR, hit); + o = owner; + _tos_cache1 = o; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_INSTANCE_VALUE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); + if (attr_o == NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + int increfed = _Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr); + if (!increfed) { + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + #else + attr = PyStackRef_FromPyObjectNew(attr_o); + #endif + STAT_INC(LOAD_ATTR, hit); + o = owner; + _tos_cache2 = o; + _tos_cache1 = attr; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_MODULE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint32_t dict_version = (uint32_t)CURRENT_OPERAND0_32(); + uint16_t index = (uint16_t)CURRENT_OPERAND1_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); if (Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; @@ -3438,6 +8221,8 @@ PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } assert(keys->dk_kind == DICT_KEYS_UNICODE); @@ -3446,6 +8231,8 @@ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); if (attr_o == NULL) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } #ifdef Py_GIL_DISABLED @@ -3453,6 +8240,8 @@ if (!increfed) { if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } @@ -3460,24 +8249,38 @@ attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); - stack_pointer[-1] = attr; + stack_pointer[0] = attr; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = attr; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_WITH_HINT: { + case _LOAD_ATTR_WITH_HINT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t hint = (uint16_t)CURRENT_OPERAND0(); + owner = _stack_item_0; + uint16_t hint = (uint16_t)CURRENT_OPERAND0_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictObject *dict = _PyObject_GetManagedDict(owner_o); if (dict == NULL) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys); @@ -3485,6 +8288,8 @@ #ifdef Py_GIL_DISABLED if (!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } #endif @@ -3492,6 +8297,8 @@ if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) { if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } @@ -3499,6 +8306,8 @@ if (dk->dk_kind != DICT_KEYS_UNICODE) { if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } @@ -3506,6 +8315,8 @@ if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) { if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } @@ -3513,6 +8324,8 @@ if (attr_o == NULL) { if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } @@ -3522,121 +8335,281 @@ if (!increfed) { if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } } #else attr = PyStackRef_FromPyObjectNew(attr_o); #endif - stack_pointer[-1] = attr; + stack_pointer[0] = attr; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = attr; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_SLOT: { + case _LOAD_ATTR_SLOT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); PyObject **addr = (PyObject **)((char *)owner_o + index); PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); if (attr_o == NULL) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } #ifdef Py_GIL_DISABLED int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); if (!increfed) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } #else attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); + stack_pointer[0] = owner; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = owner; owner = attr; stack_pointer[-1] = owner; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = attr; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_ATTR_CLASS: { + case _CHECK_ATTR_CLASS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; - uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); if (!PyType_Check(owner_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(type_version != 0); if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_CLASS: { + case _CHECK_ATTR_CLASS_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!PyType_Check(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_ATTR_CLASS_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!PyType_Check(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_ATTR_CLASS_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!PyType_Check(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_CLASS_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = PyStackRef_FromPyObjectNew(descr); + stack_pointer[0] = owner; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = owner; owner = attr; stack_pointer[-1] = owner; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = attr; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_PROPERTY_FRAME: { + case _LOAD_ATTR_PROPERTY_FRAME_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef new_frame; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *fget = (PyObject *)CURRENT_OPERAND0(); + owner = _stack_item_0; + PyObject *fget = (PyObject *)CURRENT_OPERAND0_64(); assert((oparg & 1) == 0); assert(Py_IS_TYPE(fget, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)fget; PyCodeObject *code = (PyCodeObject *)f->func_code; if ((code->co_flags & (CO_VARKEYWORDS | CO_VARARGS | CO_OPTIMIZED)) != CO_OPTIMIZED) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (code->co_kwonlyargcount) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (code->co_argcount != 1) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } STAT_INC(LOAD_ATTR, hit); _PyInterpreterFrame *pushed_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame); pushed_frame->localsplus[0] = owner; new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-1] = new_frame; + _tos_cache0 = new_frame; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN is not a viable micro-op for tier 2 because it has too many cache entries */ - case _GUARD_DORV_NO_DICT: { + case _GUARD_DORV_NO_DICT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); @@ -3647,18 +8620,113 @@ UNLOCK_OBJECT(owner_o); if (true) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_ATTR_INSTANCE_VALUE: { + case _GUARD_DORV_NO_DICT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + if (_PyObject_GetManagedDict(owner_o) || + !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UNLOCK_OBJECT(owner_o); + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_DORV_NO_DICT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + if (_PyObject_GetManagedDict(owner_o) || + !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UNLOCK_OBJECT(owner_o); + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_DORV_NO_DICT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + if (_PyObject_GetManagedDict(owner_o) || + !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UNLOCK_OBJECT(owner_o); + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_INSTANCE_VALUE_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef value; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t offset = (uint16_t)CURRENT_OPERAND0(); + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + value = _stack_item_0; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); STAT_INC(STORE_ATTR, hit); assert(_PyObject_GetManagedDict(owner_o) == NULL); @@ -3671,31 +8739,50 @@ _PyDictValues_AddToInsertionOrder(values, index); } UNLOCK_OBJECT(owner_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + o = owner; + stack_pointer[0] = o; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); Py_XDECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = o; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_ATTR_WITH_HINT: { + case _STORE_ATTR_WITH_HINT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t hint = (uint16_t)CURRENT_OPERAND0(); + owner = _stack_item_1; + value = _stack_item_0; + uint16_t hint = (uint16_t)CURRENT_OPERAND0_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictObject *dict = _PyObject_GetManagedDict(owner_o); if (dict == NULL) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } if (!LOCK_OBJECT(dict)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } assert(PyDict_CheckExact((PyObject *)dict)); @@ -3705,6 +8792,9 @@ UNLOCK_OBJECT(dict); if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } } @@ -3713,6 +8803,9 @@ UNLOCK_OBJECT(dict); if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } } @@ -3721,33 +8814,56 @@ UNLOCK_OBJECT(dict); if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } } + stack_pointer[0] = value; + stack_pointer[1] = owner; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(dict); STAT_INC(STORE_ATTR, hit); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + o = owner; + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); Py_XDECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = o; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _STORE_ATTR_SLOT: { + case _STORE_ATTR_SLOT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef value; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + value = _stack_item_0; + uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); if (!LOCK_OBJECT(owner_o)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } char *addr = (char *)owner_o + index; @@ -3755,25 +8871,41 @@ PyObject *old_value = *(PyObject **)addr; FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(owner_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + o = owner; + stack_pointer[0] = o; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); Py_XDECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = o; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COMPARE_OP: { + case _COMPARE_OP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert((oparg >> 5) <= Py_GE); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_RichCompare(left_o, right_o, oparg >> 5); _PyStackRef tmp = right; @@ -3786,8 +8918,9 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (oparg & 16) { @@ -3796,6 +8929,7 @@ Py_DECREF(res_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_bool < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = res_bool ? PyStackRef_True : PyStackRef_False; @@ -3803,13 +8937,17 @@ else { res = PyStackRef_FromPyObjectSteal(res_o); } - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COMPARE_OP_FLOAT: { + case _COMPARE_OP_FLOAT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; @@ -3825,19 +8963,108 @@ PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COMPARE_OP_INT: { + case _COMPARE_OP_FLOAT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_0; + left = stack_pointer[-1]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + STAT_INC(COMPARE_OP, hit); + double dleft = PyFloat_AS_DOUBLE(left_o); + double dright = PyFloat_AS_DOUBLE(right_o); + int sign_ish = COMPARISON_BIT(dleft, dright); + PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); + res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COMPARE_OP_FLOAT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + right = _stack_item_1; + left = _stack_item_0; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + STAT_INC(COMPARE_OP, hit); + double dleft = PyFloat_AS_DOUBLE(left_o); + double dright = PyFloat_AS_DOUBLE(right_o); + int sign_ish = COMPARISON_BIT(dleft, dright); + PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); + res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COMPARE_OP_FLOAT_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + right = _stack_item_2; + left = _stack_item_1; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + STAT_INC(COMPARE_OP, hit); + double dleft = PyFloat_AS_DOUBLE(left_o); + double dright = PyFloat_AS_DOUBLE(right_o); + int sign_ish = COMPARISON_BIT(dleft, dright); + PyStackRef_CLOSE_SPECIALIZED(left, _PyFloat_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyFloat_ExactDealloc); + res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; + _tos_cache1 = res; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COMPARE_OP_INT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef right; + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(_PyLong_IsCompact((PyLongObject *)left_o)); @@ -3848,22 +9075,28 @@ Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left_o); Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); int sign_ish = COMPARISON_BIT(ileft, iright); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + l = left; + r = right; res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COMPARE_OP_STR: { + case _COMPARE_OP_STR_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); STAT_INC(COMPARE_OP, hit); @@ -3875,48 +9108,63 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _IS_OP: { + case _IS_OP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef b; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_1; + left = _stack_item_0; int res = Py_Is(PyStackRef_AsPyObjectBorrow(left), PyStackRef_AsPyObjectBorrow(right)) ^ oparg; _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = right; right = PyStackRef_NULL; - stack_pointer[-1] = right; + stack_pointer[0] = left; + stack_pointer[1] = right; PyStackRef_CLOSE(tmp); tmp = left; left = PyStackRef_NULL; - stack_pointer[-2] = left; + stack_pointer[0] = left; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); b = res ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = b; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = b; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CONTAINS_OP: { + case _CONTAINS_OP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef b; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = PySequence_Contains(right_o, left_o); _PyStackRef tmp = right; @@ -3929,39 +9177,124 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = b; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = b; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_TOS_ANY_SET: { + case _GUARD_TOS_ANY_SET_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef tos; tos = stack_pointer[-1]; PyObject *o = PyStackRef_AsPyObjectBorrow(tos); if (!PyAnySet_CheckExact(o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CONTAINS_OP_SET: { + case _GUARD_TOS_ANY_SET_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + tos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyAnySet_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = tos; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_ANY_SET_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + tos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyAnySet_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = tos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TOS_ANY_SET_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef tos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + tos = _stack_item_2; + PyObject *o = PyStackRef_AsPyObjectBorrow(tos); + if (!PyAnySet_CheckExact(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = tos; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CONTAINS_OP_SET_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef b; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyAnySet_CheckExact(right_o)); STAT_INC(CONTAINS_OP, hit); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PySet_Contains((PySetObject *)right_o, left_o); _PyStackRef tmp = right; @@ -3974,28 +9307,39 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = b; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = b; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CONTAINS_OP_DICT: { + case _CONTAINS_OP_DICT_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef b; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - right = stack_pointer[-1]; - left = stack_pointer[-2]; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyDict_CheckExact(right_o)); STAT_INC(CONTAINS_OP, hit); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = PyDict_Contains(right_o, left_o); _PyStackRef tmp = right; @@ -4008,26 +9352,37 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = b; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = b; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_EG_MATCH: { + case _CHECK_EG_MATCH_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef match_type_st; _PyStackRef exc_value_st; _PyStackRef rest; _PyStackRef match; - match_type_st = stack_pointer[-1]; - exc_value_st = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + match_type_st = _stack_item_1; + exc_value_st = _stack_item_0; PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); PyObject *match_type = PyStackRef_AsPyObjectBorrow(match_type_st); + stack_pointer[0] = exc_value_st; + stack_pointer[1] = match_type_st; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyEval_CheckExceptStarTypeValid(tstate, match_type); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -4043,7 +9398,8 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } PyObject *match_o = NULL; @@ -4061,12 +9417,14 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } assert((match_o == NULL) == (rest_o == NULL)); if (match_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (!Py_IsNone(match_o)) { @@ -4076,51 +9434,73 @@ } rest = PyStackRef_FromPyObjectSteal(rest_o); match = PyStackRef_FromPyObjectSteal(match_o); - stack_pointer[0] = rest; - stack_pointer[1] = match; - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = match; + _tos_cache0 = rest; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_EXC_MATCH: { + case _CHECK_EXC_MATCH_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef b; - right = stack_pointer[-1]; - left = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + right = _stack_item_1; + left = _stack_item_0; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyExceptionInstance_Check(left_o)); + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyEval_CheckExceptTypeValid(tstate, right_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFrame_SetStackPointer(frame, stack_pointer); int res = PyErr_GivenExceptionMatches(left_o, right_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(right); stack_pointer = _PyFrame_GetStackPointer(frame); b = res ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = b; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = b; + _tos_cache0 = left; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _IMPORT_NAME: { + case _IMPORT_NAME_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef fromlist; _PyStackRef level; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - fromlist = stack_pointer[-1]; - level = stack_pointer[-2]; + fromlist = _stack_item_1; + level = _stack_item_0; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + stack_pointer[0] = level; + stack_pointer[1] = fromlist; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_ImportName(tstate, frame, name, PyStackRef_AsPyObjectBorrow(fromlist), @@ -4135,33 +9515,47 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _IMPORT_FROM: { + case _IMPORT_FROM_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef from; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - from = stack_pointer[-1]; + from = _stack_item_0; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + stack_pointer[0] = from; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = res; + _tos_cache0 = from; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -4169,57 +9563,92 @@ /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 because it is replaced */ - case _IS_NONE: { + case _IS_NONE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef b; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; if (PyStackRef_IsNone(value)) { b = PyStackRef_True; } else { b = PyStackRef_False; + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = value; value = b; stack_pointer[-1] = value; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; } - stack_pointer[-1] = b; + _tos_cache0 = b; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GET_LEN: { + /* _JUMP_BACKWARD_NO_INTERRUPT is not a viable micro-op for tier 2 because it is replaced */ + + case _GET_LEN_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef obj; _PyStackRef len; - obj = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + obj = _stack_item_0; + stack_pointer[0] = obj; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); stack_pointer = _PyFrame_GetStackPointer(frame); if (len_i < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } PyObject *len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } len = PyStackRef_FromPyObjectSteal(len_o); - stack_pointer[0] = len; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = len; + _tos_cache0 = obj; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MATCH_CLASS: { + case _MATCH_CLASS_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef names; _PyStackRef type; _PyStackRef subject; _PyStackRef attrs; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; oparg = CURRENT_OPARG(); - names = stack_pointer[-1]; - type = stack_pointer[-2]; - subject = stack_pointer[-3]; + names = _stack_item_2; + type = _stack_item_1; + subject = _stack_item_0; assert(PyTuple_CheckExact(PyStackRef_AsPyObjectBorrow(names))); + stack_pointer[0] = subject; + stack_pointer[1] = type; + stack_pointer[2] = names; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *attrs_o = _PyEval_MatchClass(tstate, PyStackRef_AsPyObjectBorrow(subject), @@ -4239,76 +9668,177 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (attrs_o) { assert(PyTuple_CheckExact(attrs_o)); attrs = PyStackRef_FromPyObjectSteal(attrs_o); } else { if (_PyErr_Occurred(tstate)) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } attrs = PyStackRef_None; } - stack_pointer[0] = attrs; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = attrs; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MATCH_MAPPING: { + case _MATCH_MAPPING_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef subject; _PyStackRef res; subject = stack_pointer[-1]; int match = PyStackRef_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = res; + _tos_cache0 = subject; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MATCH_SEQUENCE: { + case _MATCH_MAPPING_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef subject; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + subject = _stack_item_0; + int match = PyStackRef_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; + res = match ? PyStackRef_True : PyStackRef_False; + _tos_cache1 = res; + _tos_cache0 = subject; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MATCH_MAPPING_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef subject; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + subject = _stack_item_1; + int match = PyStackRef_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; + res = match ? PyStackRef_True : PyStackRef_False; + _tos_cache2 = res; + _tos_cache1 = subject; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MATCH_SEQUENCE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef subject; _PyStackRef res; subject = stack_pointer[-1]; int match = PyStackRef_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? PyStackRef_True : PyStackRef_False; - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = res; + _tos_cache0 = subject; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MATCH_KEYS: { + case _MATCH_SEQUENCE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef subject; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + subject = _stack_item_0; + int match = PyStackRef_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; + res = match ? PyStackRef_True : PyStackRef_False; + _tos_cache1 = res; + _tos_cache0 = subject; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MATCH_SEQUENCE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef subject; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + subject = _stack_item_1; + int match = PyStackRef_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; + res = match ? PyStackRef_True : PyStackRef_False; + _tos_cache2 = res; + _tos_cache1 = subject; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MATCH_KEYS_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef keys; _PyStackRef subject; _PyStackRef values_or_none; - keys = stack_pointer[-1]; - subject = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + keys = _stack_item_1; + subject = _stack_item_0; + stack_pointer[0] = subject; + stack_pointer[1] = keys; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); stack_pointer = _PyFrame_GetStackPointer(frame); if (values_or_none_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); - stack_pointer[0] = values_or_none; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = values_or_none; + _tos_cache1 = keys; + _tos_cache0 = subject; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GET_ITER: { + case _GET_ITER_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iterable; _PyStackRef iter; _PyStackRef index_or_null; - iterable = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + iterable = _stack_item_0; #ifdef Py_STATS + stack_pointer[0] = iterable; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_GatherStats_GetIter(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; #endif PyTypeObject *tp = PyStackRef_TYPE(iterable); @@ -4317,40 +9847,51 @@ index_or_null = PyStackRef_TagInt(0); } else { + stack_pointer[0] = iterable; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); if (iter_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } iter = PyStackRef_FromPyObjectSteal(iter_o); index_or_null = PyStackRef_NULL; - stack_pointer += 1; } - stack_pointer[-1] = iter; - stack_pointer[0] = index_or_null; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = index_or_null; + _tos_cache0 = iter; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GET_YIELD_FROM_ITER: { + case _GET_YIELD_FROM_ITER_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iterable; _PyStackRef iter; - iterable = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + iterable = _stack_item_0; PyObject *iterable_o = PyStackRef_AsPyObjectBorrow(iterable); if (PyCoro_CheckExact(iterable_o)) { if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { + stack_pointer[0] = iterable; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetString(tstate, PyExc_TypeError, "cannot 'yield from' a coroutine object " "in a non-coroutine generator"); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } iter = iterable; @@ -4359,10 +9900,14 @@ iter = iterable; } else { + stack_pointer[0] = iterable; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = PyObject_GetIter(iterable_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (iter_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } iter = PyStackRef_FromPyObjectSteal(iter_o); @@ -4372,42 +9917,67 @@ stack_pointer[-1] = iterable; PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; } - stack_pointer[-1] = iter; + _tos_cache0 = iter; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _FOR_ITER is not a viable micro-op for tier 2 because it is replaced */ - case _FOR_ITER_TIER_TWO: { + case _FOR_ITER_TIER_TWO_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; _PyStackRef next; - null_or_index = stack_pointer[-1]; - iter = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; + stack_pointer[0] = iter; + stack_pointer[1] = null_or_index; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index); stack_pointer = _PyFrame_GetStackPointer(frame); if (!PyStackRef_IsValid(item)) { if (PyStackRef_IsError(item)) { + stack_pointer[-1] = null_or_index; + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } if (true) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_JUMP_TARGET(); } } next = item; - stack_pointer[-1] = null_or_index; - stack_pointer[0] = next; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = next; + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _INSTRUMENTED_FOR_ITER is not a viable micro-op for tier 2 because it is instrumented */ - case _ITER_CHECK_LIST: { + case _ITER_CHECK_LIST_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; null_or_index = stack_pointer[-1]; @@ -4415,21 +9985,136 @@ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (Py_TYPE(iter_o) != &PyList_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(PyStackRef_IsTaggedInt(null_or_index)); #ifdef Py_GIL_DISABLED if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #endif + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_LIST_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + null_or_index = _stack_item_0; + iter = stack_pointer[-1]; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != &PyList_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = null_or_index; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + assert(PyStackRef_IsTaggedInt(null_or_index)); + #ifdef Py_GIL_DISABLED + if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = null_or_index; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_LIST_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != &PyList_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + assert(PyStackRef_IsTaggedInt(null_or_index)); + #ifdef Py_GIL_DISABLED + if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_LIST_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + null_or_index = _stack_item_2; + iter = _stack_item_1; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != &PyList_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + assert(PyStackRef_IsTaggedInt(null_or_index)); + #ifdef Py_GIL_DISABLED + if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _ITER_JUMP_LIST is not a viable micro-op for tier 2 because it is replaced */ - case _GUARD_NOT_EXHAUSTED_LIST: { + case _GUARD_NOT_EXHAUSTED_LIST_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; null_or_index = stack_pointer[-1]; @@ -4439,46 +10124,156 @@ assert(Py_TYPE(list_o) == &PyList_Type); if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyList_GET_SIZE(list_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #endif + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_LIST_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + null_or_index = _stack_item_0; + iter = stack_pointer[-1]; + #ifndef Py_GIL_DISABLED + PyObject *list_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(list_o) == &PyList_Type); + if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyList_GET_SIZE(list_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = null_or_index; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_LIST_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; + #ifndef Py_GIL_DISABLED + PyObject *list_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(list_o) == &PyList_Type); + if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyList_GET_SIZE(list_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_LIST_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + null_or_index = _stack_item_2; + iter = _stack_item_1; + #ifndef Py_GIL_DISABLED + PyObject *list_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(list_o) == &PyList_Type); + if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyList_GET_SIZE(list_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _ITER_NEXT_LIST is not a viable micro-op for tier 2 because it is replaced */ - case _ITER_NEXT_LIST_TIER_TWO: { + case _ITER_NEXT_LIST_TIER_TWO_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; _PyStackRef next; - null_or_index = stack_pointer[-1]; - iter = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; PyObject *list_o = PyStackRef_AsPyObjectBorrow(iter); assert(PyList_CheckExact(list_o)); #ifdef Py_GIL_DISABLED assert(_Py_IsOwnedByCurrentThread((PyObject *)list_o) || _PyObject_GC_IS_SHARED(list_o)); STAT_INC(FOR_ITER, hit); + stack_pointer[0] = iter; + stack_pointer[1] = null_or_index; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int result = _PyList_GetItemRefNoLock((PyListObject *)list_o, PyStackRef_UntagInt(null_or_index), &next); stack_pointer = _PyFrame_GetStackPointer(frame); if (result <= 0) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_JUMP_TARGET(); } #else assert(PyStackRef_UntagInt(null_or_index) < PyList_GET_SIZE(list_o)); next = PyStackRef_FromPyObjectNew(PyList_GET_ITEM(list_o, PyStackRef_UntagInt(null_or_index))); + stack_pointer += 2; #endif null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); - stack_pointer[-1] = null_or_index; - stack_pointer[0] = next; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = next; + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _ITER_CHECK_TUPLE: { + case _ITER_CHECK_TUPLE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; null_or_index = stack_pointer[-1]; @@ -4486,15 +10281,102 @@ PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (Py_TYPE(iter_o) != &PyTuple_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(PyStackRef_IsTaggedInt(null_or_index)); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_TUPLE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + null_or_index = _stack_item_0; + iter = stack_pointer[-1]; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != &PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = null_or_index; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + assert(PyStackRef_IsTaggedInt(null_or_index)); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_TUPLE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != &PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + assert(PyStackRef_IsTaggedInt(null_or_index)); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_TUPLE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + null_or_index = _stack_item_2; + iter = _stack_item_1; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != &PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + assert(PyStackRef_IsTaggedInt(null_or_index)); + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _ITER_JUMP_TUPLE is not a viable micro-op for tier 2 because it is replaced */ - case _GUARD_NOT_EXHAUSTED_TUPLE: { + case _GUARD_NOT_EXHAUSTED_TUPLE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; null_or_index = stack_pointer[-1]; @@ -4503,12 +10385,99 @@ assert(Py_TYPE(tuple_o) == &PyTuple_Type); if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyTuple_GET_SIZE(tuple_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _ITER_NEXT_TUPLE: { + case _GUARD_NOT_EXHAUSTED_TUPLE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + null_or_index = _stack_item_0; + iter = stack_pointer[-1]; + PyObject *tuple_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(tuple_o) == &PyTuple_Type); + if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyTuple_GET_SIZE(tuple_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = null_or_index; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_TUPLE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; + PyObject *tuple_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(tuple_o) == &PyTuple_Type); + if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyTuple_GET_SIZE(tuple_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_TUPLE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + null_or_index = _stack_item_2; + iter = _stack_item_1; + PyObject *tuple_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(tuple_o) == &PyTuple_Type); + if ((size_t)PyStackRef_UntagInt(null_or_index) >= (size_t)PyTuple_GET_SIZE(tuple_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = null_or_index; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_NEXT_TUPLE_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null_or_index; _PyStackRef iter; _PyStackRef next; @@ -4520,45 +10489,286 @@ assert((size_t)i < (size_t)PyTuple_GET_SIZE(tuple_o)); next = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(tuple_o, i)); null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); - stack_pointer[-1] = null_or_index; - stack_pointer[0] = next; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = next; + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _ITER_CHECK_RANGE: { + case _ITER_NEXT_TUPLE_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef next; + _PyStackRef _stack_item_0 = _tos_cache0; + null_or_index = _stack_item_0; + iter = stack_pointer[-1]; + PyObject *tuple_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(tuple_o) == &PyTuple_Type); + uintptr_t i = PyStackRef_UntagInt(null_or_index); + assert((size_t)i < (size_t)PyTuple_GET_SIZE(tuple_o)); + next = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(tuple_o, i)); + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + _tos_cache2 = next; + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_NEXT_TUPLE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null_or_index; + _PyStackRef iter; + _PyStackRef next; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null_or_index = _stack_item_1; + iter = _stack_item_0; + PyObject *tuple_o = PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(tuple_o) == &PyTuple_Type); + uintptr_t i = PyStackRef_UntagInt(null_or_index); + assert((size_t)i < (size_t)PyTuple_GET_SIZE(tuple_o)); + next = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(tuple_o, i)); + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + _tos_cache2 = next; + _tos_cache1 = null_or_index; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_RANGE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iter; iter = stack_pointer[-2]; _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); if (Py_TYPE(r) != &PyRangeIter_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #ifdef Py_GIL_DISABLED if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } #endif + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_RANGE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + iter = stack_pointer[-1]; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(r) != &PyRangeIter_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = _stack_item_0; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_RANGE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + iter = _stack_item_0; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(r) != &PyRangeIter_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_CHECK_RANGE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + iter = _stack_item_1; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(r) != &PyRangeIter_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + #ifdef Py_GIL_DISABLED + if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + #endif + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _ITER_JUMP_RANGE is not a viable micro-op for tier 2 because it is replaced */ - case _GUARD_NOT_EXHAUSTED_RANGE: { + case _GUARD_NOT_EXHAUSTED_RANGE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iter; iter = stack_pointer[-2]; _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); assert(Py_TYPE(r) == &PyRangeIter_Type); if (r->len <= 0) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _ITER_NEXT_RANGE: { + case _GUARD_NOT_EXHAUSTED_RANGE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + iter = stack_pointer[-1]; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(r) == &PyRangeIter_Type); + if (r->len <= 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_RANGE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + iter = _stack_item_0; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(r) == &PyRangeIter_Type); + if (r->len <= 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOT_EXHAUSTED_RANGE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + iter = _stack_item_1; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(r) == &PyRangeIter_Type); + if (r->len <= 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_NEXT_RANGE_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iter; _PyStackRef next; iter = stack_pointer[-2]; @@ -4573,34 +10783,122 @@ r->len--; PyObject *res = PyLong_FromLong(value); if (res == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } next = PyStackRef_FromPyObjectSteal(res); - stack_pointer[0] = next; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = next; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _FOR_ITER_GEN_FRAME: { + case _ITER_NEXT_RANGE_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef next; + _PyStackRef _stack_item_0 = _tos_cache0; + iter = stack_pointer[-1]; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(r) == &PyRangeIter_Type); + #ifdef Py_GIL_DISABLED + assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); + #endif + assert(r->len > 0); + long value = r->start; + r->start = value + r->step; + r->len--; + PyObject *res = PyLong_FromLong(value); + if (res == NULL) { + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + next = PyStackRef_FromPyObjectSteal(res); + _tos_cache2 = next; + _tos_cache1 = _stack_item_0; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_NEXT_RANGE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef next; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + iter = _stack_item_0; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); + assert(Py_TYPE(r) == &PyRangeIter_Type); + #ifdef Py_GIL_DISABLED + assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); + #endif + assert(r->len > 0); + long value = r->start; + r->start = value + r->step; + r->len--; + PyObject *res = PyLong_FromLong(value); + if (res == NULL) { + stack_pointer[0] = iter; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + next = PyStackRef_FromPyObjectSteal(res); + _tos_cache2 = next; + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _FOR_ITER_GEN_FRAME_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iter; _PyStackRef gen_frame; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - iter = stack_pointer[-2]; + iter = _stack_item_0; PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); if (Py_TYPE(gen) != &PyGen_Type) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } #ifdef Py_GIL_DISABLED if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } #endif if (gen->gi_frame_state >= FRAME_EXECUTING) { UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } STAT_INC(FOR_ITER, hit); @@ -4610,27 +10908,36 @@ gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; pushed_frame->previous = frame; - frame->return_offset = (uint16_t)( 2 + oparg); + frame->return_offset = (uint16_t)( 2u + oparg); gen_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[0] = gen_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = gen_frame; + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INSERT_NULL: { + case _INSERT_NULL_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self; _PyStackRef *method_and_self; - self = stack_pointer[-1]; - method_and_self = &stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + self = _stack_item_0; + method_and_self = &stack_pointer[0]; method_and_self[1] = self; method_and_self[0] = PyStackRef_NULL; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_SPECIAL: { + case _LOAD_SPECIAL_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *method_and_self; oparg = CURRENT_OPARG(); method_and_self = &stack_pointer[-2]; @@ -4652,21 +10959,32 @@ _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner); stack_pointer = _PyFrame_GetStackPointer(frame); } + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _WITH_EXCEPT_START: { + case _WITH_EXCEPT_START_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef val; _PyStackRef lasti; _PyStackRef exit_self; _PyStackRef exit_func; _PyStackRef res; - val = stack_pointer[-1]; - lasti = stack_pointer[-3]; - exit_self = stack_pointer[-4]; - exit_func = stack_pointer[-5]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + val = _stack_item_2; + lasti = _stack_item_0; + exit_self = stack_pointer[-1]; + exit_func = stack_pointer[-2]; PyObject *exc, *tb; PyObject *val_o = PyStackRef_AsPyObjectBorrow(val); PyObject *exit_func_o = PyStackRef_AsPyObjectBorrow(exit_func); @@ -4680,22 +10998,34 @@ (void)lasti; PyObject *stack[5] = {NULL, PyStackRef_AsPyObjectBorrow(exit_self), exc, val_o, tb}; int has_self = !PyStackRef_IsNull(exit_self); + stack_pointer[0] = lasti; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = val; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); Py_XDECREF(original_tb); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = res; + _tos_cache1 = val; + _tos_cache0 = _stack_item_1; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _PUSH_EXC_INFO: { + case _PUSH_EXC_INFO_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef exc; _PyStackRef prev_exc; _PyStackRef new_exc; @@ -4710,14 +11040,70 @@ assert(PyStackRef_ExceptionInstanceCheck(exc)); exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); new_exc = exc; - stack_pointer[-1] = prev_exc; - stack_pointer[0] = new_exc; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = new_exc; + _tos_cache0 = prev_exc; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { + case _PUSH_EXC_INFO_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef exc; + _PyStackRef prev_exc; + _PyStackRef new_exc; + _PyStackRef _stack_item_0 = _tos_cache0; + exc = _stack_item_0; + _PyErr_StackItem *exc_info = tstate->exc_info; + if (exc_info->exc_value != NULL) { + prev_exc = PyStackRef_FromPyObjectSteal(exc_info->exc_value); + } + else { + prev_exc = PyStackRef_None; + } + assert(PyStackRef_ExceptionInstanceCheck(exc)); + exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); + new_exc = exc; + _tos_cache1 = new_exc; + _tos_cache0 = prev_exc; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _PUSH_EXC_INFO_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef exc; + _PyStackRef prev_exc; + _PyStackRef new_exc; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + exc = _stack_item_1; + _PyErr_StackItem *exc_info = tstate->exc_info; + if (exc_info->exc_value != NULL) { + prev_exc = PyStackRef_FromPyObjectSteal(exc_info->exc_value); + } + else { + prev_exc = PyStackRef_None; + } + assert(PyStackRef_ExceptionInstanceCheck(exc)); + exc_info->exc_value = PyStackRef_AsPyObjectNew(exc); + new_exc = exc; + _tos_cache2 = new_exc; + _tos_cache1 = prev_exc; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); @@ -4725,52 +11111,267 @@ PyDictValues *ivs = _PyObject_InlineValues(owner_o); if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_KEYS_VERSION: { + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + PyDictValues *ivs = _PyObject_InlineValues(owner_o); + if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + PyDictValues *ivs = _PyObject_InlineValues(owner_o); + if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); + PyDictValues *ivs = _PyObject_InlineValues(owner_o); + if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_KEYS_VERSION_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; - uint32_t keys_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_METHOD_WITH_VALUES: { + case _GUARD_KEYS_VERSION_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; + if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_KEYS_VERSION_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; + if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_KEYS_VERSION_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32(); + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; + if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_METHOD_WITH_VALUES_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; _PyStackRef self; oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); assert(oparg & 1); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; - stack_pointer[-1] = attr; - stack_pointer[0] = self; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = self; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_METHOD_NO_DICT: { + case _LOAD_ATTR_METHOD_WITH_VALUES_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef self; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + owner = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); + assert(oparg & 1); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = PyStackRef_FromPyObjectNew(descr); + self = owner; + _tos_cache1 = self; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_METHOD_WITH_VALUES_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef self; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + owner = _stack_item_1; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); + assert(oparg & 1); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = PyStackRef_FromPyObjectNew(descr); + self = owner; + _tos_cache2 = self; + _tos_cache1 = attr; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_METHOD_NO_DICT_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; _PyStackRef self; oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); assert(oparg & 1); assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); @@ -4778,90 +11379,282 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; - stack_pointer[-1] = attr; - stack_pointer[0] = self; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = self; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { + case _LOAD_ATTR_METHOD_NO_DICT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; + _PyStackRef self; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + owner = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); + assert(oparg & 1); + assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = PyStackRef_FromPyObjectNew(descr); + self = owner; + _tos_cache1 = self; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_METHOD_NO_DICT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef self; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + owner = _stack_item_1; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); + assert(oparg & 1); + assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = PyStackRef_FromPyObjectNew(descr); + self = owner; + _tos_cache2 = self; + _tos_cache1 = attr; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + owner = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); assert((oparg & 1) == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[0] = attr; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = attr; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { + case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + owner = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); assert((oparg & 1) == 0); assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); attr = PyStackRef_FromPyObjectNew(descr); - stack_pointer[0] = attr; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = attr; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_ATTR_METHOD_LAZY_DICT: { + case _CHECK_ATTR_METHOD_LAZY_DICT_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; owner = stack_pointer[-1]; - uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0(); + uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0_16(); char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); if (dict != NULL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_ATTR_METHOD_LAZY_DICT: { + case _CHECK_ATTR_METHOD_LAZY_DICT_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0_16(); + char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; + PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); + if (dict != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_ATTR_METHOD_LAZY_DICT_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0_16(); + char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; + PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); + if (dict != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = owner; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_ATTR_METHOD_LAZY_DICT_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0_16(); + char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; + PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); + if (dict != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = owner; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_METHOD_LAZY_DICT_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; _PyStackRef self; oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); assert(oparg & 1); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); attr = PyStackRef_FromPyObjectNew(descr); self = owner; - stack_pointer[-1] = attr; - stack_pointer[0] = self; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = self; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MAYBE_EXPAND_METHOD: { + case _LOAD_ATTR_METHOD_LAZY_DICT_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef self; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + owner = _stack_item_0; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); + assert(oparg & 1); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = PyStackRef_FromPyObjectNew(descr); + self = owner; + _tos_cache1 = self; + _tos_cache0 = attr; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_ATTR_METHOD_LAZY_DICT_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef attr; + _PyStackRef self; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + owner = _stack_item_1; + PyObject *descr = (PyObject *)CURRENT_OPERAND0_64(); + assert(oparg & 1); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + attr = PyStackRef_FromPyObjectNew(descr); + self = owner; + _tos_cache2 = self; + _tos_cache1 = attr; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MAYBE_EXPAND_METHOD_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; oparg = CURRENT_OPARG(); @@ -4880,8 +11673,13 @@ PyStackRef_CLOSE(temp); stack_pointer = _PyFrame_GetStackPointer(frame); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); stack_pointer[-2 - oparg] = callable; stack_pointer[-1 - oparg] = self_or_null; + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -4889,7 +11687,9 @@ /* _MONITOR_CALL is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _PY_FRAME_GENERAL: { + case _PY_FRAME_GENERAL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -4914,76 +11714,169 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } new_frame = PyStackRef_Wrap(temp); - stack_pointer[0] = new_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_FUNCTION_VERSION: { + case _CHECK_FUNCTION_VERSION_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; oparg = CURRENT_OPARG(); callable = stack_pointer[-2 - oparg]; - uint32_t func_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyFunctionObject *func = (PyFunctionObject *)callable_o; if (func->func_version != func_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_FUNCTION_VERSION_INLINE: { - uint32_t func_version = (uint32_t)CURRENT_OPERAND0(); - PyObject *callable_o = (PyObject *)CURRENT_OPERAND1(); + case _CHECK_FUNCTION_VERSION_INLINE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *callable_o = (PyObject *)CURRENT_OPERAND1_64(); assert(PyFunction_Check(callable_o)); PyFunctionObject *func = (PyFunctionObject *)callable_o; if (func->func_version != func_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_METHOD_VERSION: { + case _CHECK_FUNCTION_VERSION_INLINE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *callable_o = (PyObject *)CURRENT_OPERAND1_64(); + assert(PyFunction_Check(callable_o)); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + if (func->func_version != func_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_FUNCTION_VERSION_INLINE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *callable_o = (PyObject *)CURRENT_OPERAND1_64(); + assert(PyFunction_Check(callable_o)); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + if (func->func_version != func_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_FUNCTION_VERSION_INLINE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *callable_o = (PyObject *)CURRENT_OPERAND1_64(); + assert(PyFunction_Check(callable_o)); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + if (func->func_version != func_version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_METHOD_VERSION_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null; _PyStackRef callable; oparg = CURRENT_OPARG(); null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - uint32_t func_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (Py_TYPE(callable_o) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyObject *func = ((PyMethodObject *)callable_o)->im_func; if (!PyFunction_Check(func)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (((PyFunctionObject *)func)->func_version != func_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (!PyStackRef_IsNull(null)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _EXPAND_METHOD: { + case _EXPAND_METHOD_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; oparg = CURRENT_OPARG(); @@ -5001,26 +11894,39 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(temp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_IS_NOT_PY_CALLABLE: { + case _CHECK_IS_NOT_PY_CALLABLE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; oparg = CURRENT_OPARG(); callable = stack_pointer[-2 - oparg]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (Py_TYPE(callable_o) == &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_NON_PY_GENERAL: { + case _CALL_NON_PY_GENERAL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5032,72 +11938,39 @@ #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( - callable_o, args_o, - total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - NULL); + PyObject *res_o = _Py_VectorCall_StackRefSteal( + callable, + arguments, + total_args, + PyStackRef_NULL); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null; _PyStackRef callable; oparg = CURRENT_OPARG(); @@ -5105,16 +11978,22 @@ callable = stack_pointer[-2 - oparg]; if (!PyStackRef_IsNull(null)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (Py_TYPE(PyStackRef_AsPyObjectBorrow(callable)) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { + case _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; oparg = CURRENT_OPARG(); @@ -5131,18 +12010,87 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(temp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_PEP_523: { + case _CHECK_PEP_523_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); if (tstate->interp->eval_frame) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_FUNCTION_EXACT_ARGS: { + case _CHECK_PEP_523_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + if (tstate->interp->eval_frame) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_PEP_523_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + if (tstate->interp->eval_frame) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_PEP_523_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + if (tstate->interp->eval_frame) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_FUNCTION_EXACT_ARGS_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; oparg = CURRENT_OPARG(); @@ -5154,12 +12102,17 @@ PyCodeObject *code = (PyCodeObject *)func->func_code; if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null))) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_STACK_SPACE: { + case _CHECK_STACK_SPACE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; oparg = CURRENT_OPARG(); callable = stack_pointer[-2 - oparg]; @@ -5168,20 +12121,87 @@ PyCodeObject *code = (PyCodeObject *)func->func_code; if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_RECURSION_REMAINING: { + case _CHECK_RECURSION_REMAINING_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); if (tstate->py_recursion_remaining <= 1) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_PY_EXACT_ARGS_0: { + case _CHECK_RECURSION_REMAINING_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + if (tstate->py_recursion_remaining <= 1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_RECURSION_REMAINING_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + if (tstate->py_recursion_remaining <= 1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_RECURSION_REMAINING_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + if (tstate->py_recursion_remaining <= 1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _INIT_CALL_PY_EXACT_ARGS_0_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5200,13 +12220,17 @@ first_non_self_local[i] = args[i]; } new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-2 - oparg] = new_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_PY_EXACT_ARGS_1: { + case _INIT_CALL_PY_EXACT_ARGS_1_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5225,13 +12249,17 @@ first_non_self_local[i] = args[i]; } new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-2 - oparg] = new_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_PY_EXACT_ARGS_2: { + case _INIT_CALL_PY_EXACT_ARGS_2_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5250,13 +12278,17 @@ first_non_self_local[i] = args[i]; } new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-2 - oparg] = new_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_PY_EXACT_ARGS_3: { + case _INIT_CALL_PY_EXACT_ARGS_3_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5275,13 +12307,17 @@ first_non_self_local[i] = args[i]; } new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-2 - oparg] = new_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_PY_EXACT_ARGS_4: { + case _INIT_CALL_PY_EXACT_ARGS_4_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5300,13 +12336,17 @@ first_non_self_local[i] = args[i]; } new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-2 - oparg] = new_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _INIT_CALL_PY_EXACT_ARGS: { + case _INIT_CALL_PY_EXACT_ARGS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5324,19 +12364,22 @@ first_non_self_local[i] = args[i]; } new_frame = PyStackRef_Wrap(pushed_frame); - stack_pointer[-2 - oparg] = new_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _PUSH_FRAME: { + case _PUSH_FRAME_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef new_frame; - new_frame = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + new_frame = _stack_item_0; assert(tstate->interp->eval_frame == NULL); _PyInterpreterFrame *temp = PyStackRef_Unwrap(new_frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); assert(temp->previous == frame || temp->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); @@ -5345,180 +12388,693 @@ LOAD_SP(); LOAD_IP(0); LLTRACE_RESUME_FRAME(); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_NULL: { + case _GUARD_NOS_NULL_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null; null = stack_pointer[-2]; if (!PyStackRef_IsNull(null)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_NOS_NOT_NULL: { + case _GUARD_NOS_NULL_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef _stack_item_0 = _tos_cache0; + null = stack_pointer[-1]; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_NULL_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null = _stack_item_0; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_NULL_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + null = _stack_item_1; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = null; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = null; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_NOT_NULL_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef nos; nos = stack_pointer[-2]; PyObject *o = PyStackRef_AsPyObjectBorrow(nos); if (o == NULL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_THIRD_NULL: { + case _GUARD_NOS_NOT_NULL_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + nos = stack_pointer[-1]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (o == NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_NOT_NULL_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + nos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (o == NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_NOS_NOT_NULL_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + nos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (o == NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_THIRD_NULL_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null; null = stack_pointer[-3]; if (!PyStackRef_IsNull(null)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_CALLABLE_TYPE_1: { + case _GUARD_THIRD_NULL_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef _stack_item_0 = _tos_cache0; + null = stack_pointer[-2]; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_THIRD_NULL_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null = stack_pointer[-1]; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_THIRD_NULL_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + null = _stack_item_0; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = null; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_TYPE_1_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (callable_o != (PyObject *)&PyType_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_TYPE_1: { + case _GUARD_CALLABLE_TYPE_1_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + callable = stack_pointer[-2]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyType_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_TYPE_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + callable = stack_pointer[-1]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyType_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_TYPE_1_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callable = _stack_item_0; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyType_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_TYPE_1_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef arg; _PyStackRef null; _PyStackRef callable; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; oparg = CURRENT_OPARG(); - arg = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; + arg = _stack_item_2; + null = _stack_item_1; + callable = _stack_item_0; PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); (void)callable; (void)null; STAT_INC(CALL, hit); res = PyStackRef_FromPyObjectNew(Py_TYPE(arg_o)); - stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[0] = res; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(arg); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_CALLABLE_STR_1: { + case _GUARD_CALLABLE_STR_1_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (callable_o != (PyObject *)&PyUnicode_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_STR_1: { - _PyStackRef arg; - _PyStackRef null; + case _GUARD_CALLABLE_STR_1_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + callable = stack_pointer[-2]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyUnicode_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_STR_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + callable = stack_pointer[-1]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyUnicode_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_STR_1_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callable = _stack_item_0; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyUnicode_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_STR_1_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; _PyStackRef res; + _PyStackRef a; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; oparg = CURRENT_OPARG(); - arg = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; + arg = _stack_item_2; PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); STAT_INC(CALL, hit); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = arg; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Str(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); - (void)callable; - (void)null; - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + a = arg; res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = a; + _tos_cache0 = res; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_CALLABLE_TUPLE_1: { + case _GUARD_CALLABLE_TUPLE_1_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (callable_o != (PyObject *)&PyTuple_Type) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_TUPLE_1: { - _PyStackRef arg; - _PyStackRef null; + case _GUARD_CALLABLE_TUPLE_1_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + callable = stack_pointer[-2]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_TUPLE_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + callable = stack_pointer[-1]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_TUPLE_1_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callable = _stack_item_0; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (callable_o != (PyObject *)&PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_TUPLE_1_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; _PyStackRef res; + _PyStackRef a; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; oparg = CURRENT_OPARG(); - arg = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; + arg = _stack_item_2; PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); assert(oparg == 1); STAT_INC(CALL, hit); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = arg; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PySequence_Tuple(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); - (void)callable; - (void)null; - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + a = arg; res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = a; + _tos_cache0 = res; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_AND_ALLOCATE_OBJECT: { + case _CHECK_AND_ALLOCATE_OBJECT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; oparg = CURRENT_OPARG(); self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); + uint32_t type_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyStackRef_IsNull(self_or_null)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (!PyType_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyTypeObject *tp = (PyTypeObject *)callable_o; if (FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(tp->tp_new == PyBaseObject_Type.tp_new); @@ -5529,6 +13085,7 @@ PyCodeObject *code = (PyCodeObject *)init_func->func_code; if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); @@ -5536,6 +13093,7 @@ PyObject *self_o = PyType_GenericAlloc(tp, 0); stack_pointer = _PyFrame_GetStackPointer(frame); if (self_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } self_or_null = PyStackRef_FromPyObjectSteal(self_o); @@ -5546,10 +13104,17 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(temp); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CREATE_INIT_FRAME: { + case _CREATE_INIT_FRAME_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self; _PyStackRef init; @@ -5570,39 +13135,54 @@ tstate, init, NULL, args-1, oparg+1, NULL, shim); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FrameClearAndPop(tstate, shim); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL; tstate->py_recursion_remaining--; init_frame = PyStackRef_Wrap(temp); - stack_pointer[0] = init_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = init_frame; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _EXIT_INIT_CHECK: { + case _EXIT_INIT_CHECK_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef should_be_none; - should_be_none = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + should_be_none = _stack_item_0; if (!PyStackRef_IsNone(should_be_none)) { + stack_pointer[0] = should_be_none; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyErr_Format(PyExc_TypeError, "__init__() should return None, not '%.200s'", Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_BUILTIN_CLASS: { + case _CALL_BUILTIN_CLASS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5614,6 +13194,7 @@ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyType_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyTypeObject *tp = (PyTypeObject *)callable_o; @@ -5625,68 +13206,42 @@ } if (tp->tp_vectorcall == NULL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + PyObject *res_o = _Py_CallBuiltinClass_StackRefSteal( + callable, + arguments, + total_args); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_BUILTIN_O: { + case _CALL_BUILTIN_O_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; @@ -5699,18 +13254,22 @@ } if (total_args != 1) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (!PyCFunction_CheckExact(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (PyCFunction_GET_FLAGS(callable_o) != METH_O) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (_Py_ReachedRecursionLimit(tstate)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); @@ -5721,25 +13280,26 @@ stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + a = arg; + c = callable; res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = c; + _tos_cache1 = a; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_BUILTIN_FAST: { + case _CALL_BUILTIN_FAST_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5748,82 +13308,51 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyCFunction_CheckExact(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = _PyCFunctionFast_CAST(cfunc)( - PyCFunction_GET_SELF(callable_o), - args_o, - total_args); + PyObject *res_o = _Py_BuiltinCallFast_StackRefSteal( + callable, + arguments, + total_args + ); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { + case _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -5832,242 +13361,630 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyCFunction_CheckExact(callable_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o)); + PyObject *res_o = _Py_BuiltinCallFastWithKeywords_StackRefSteal(callable, arguments, total_args); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_CALLABLE_LEN: { + case _GUARD_CALLABLE_LEN_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyInterpreterState *interp = tstate->interp; if (callable_o != interp->callable_cache.len) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_LEN: { + case _GUARD_CALLABLE_LEN_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + callable = stack_pointer[-2]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.len) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_LEN_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + callable = stack_pointer[-1]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.len) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_LEN_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callable = _stack_item_0; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.len) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_LEN_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef arg; - _PyStackRef null; _PyStackRef callable; _PyStackRef res; - arg = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; - (void)null; + _PyStackRef a; + _PyStackRef c; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + arg = _stack_item_2; + callable = _stack_item_0; STAT_INC(CALL, hit); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); + stack_pointer[0] = callable; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = arg; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (len_i < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } PyObject *res_o = PyLong_FromSsize_t(len_i); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); + a = arg; + c = callable; res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = c; + _tos_cache1 = a; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_CALLABLE_ISINSTANCE: { + case _GUARD_CALLABLE_ISINSTANCE_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; callable = stack_pointer[-4]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyInterpreterState *interp = tstate->interp; if (callable_o != interp->callable_cache.isinstance) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = stack_pointer[-3]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_ISINSTANCE: { + case _GUARD_CALLABLE_ISINSTANCE_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + callable = stack_pointer[-3]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.isinstance) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = stack_pointer[-2]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_ISINSTANCE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + callable = stack_pointer[-2]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.isinstance) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = stack_pointer[-1]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_ISINSTANCE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callable = stack_pointer[-1]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.isinstance) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_ISINSTANCE_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef cls; _PyStackRef instance; _PyStackRef null; _PyStackRef callable; _PyStackRef res; - cls = stack_pointer[-1]; - instance = stack_pointer[-2]; - null = stack_pointer[-3]; - callable = stack_pointer[-4]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + cls = _stack_item_2; + instance = _stack_item_1; + null = _stack_item_0; + callable = stack_pointer[-1]; STAT_INC(CALL, hit); PyObject *inst_o = PyStackRef_AsPyObjectBorrow(instance); PyObject *cls_o = PyStackRef_AsPyObjectBorrow(cls); + stack_pointer[0] = null; + stack_pointer[1] = instance; + stack_pointer[2] = cls; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int retval = PyObject_IsInstance(inst_o, cls_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (retval < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } (void)null; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(cls); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(instance); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callable); stack_pointer = _PyFrame_GetStackPointer(frame); res = retval ? PyStackRef_True : PyStackRef_False; assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_CALLABLE_LIST_APPEND: { + case _GUARD_CALLABLE_LIST_APPEND_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; callable = stack_pointer[-3]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyInterpreterState *interp = tstate->interp; if (callable_o != interp->callable_cache.list_append) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_LIST_APPEND: { + case _GUARD_CALLABLE_LIST_APPEND_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + callable = stack_pointer[-2]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.list_append) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_LIST_APPEND_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + callable = stack_pointer[-1]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.list_append) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CALLABLE_LIST_APPEND_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callable = _stack_item_0; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.list_append) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_LIST_APPEND_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef arg; _PyStackRef self; _PyStackRef callable; + _PyStackRef c; + _PyStackRef s; oparg = CURRENT_OPARG(); arg = stack_pointer[-1]; self = stack_pointer[-2]; callable = stack_pointer[-3]; assert(oparg == 1); PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); - if (!PyList_CheckExact(self_o)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } if (!LOCK_OBJECT(self_o)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); UNLOCK_OBJECT(self_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + c = callable; + s = self; #if TIER_ONE assert(next_instr->op.code == POP_TOP); SKIP_OVER(1); #endif + _tos_cache1 = s; + _tos_cache0 = c; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_METHOD_DESCRIPTOR_O: { + case _CALL_LIST_APPEND_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef self; + _PyStackRef callable; + _PyStackRef c; + _PyStackRef s; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + arg = _stack_item_0; + self = stack_pointer[-1]; + callable = stack_pointer[-2]; + assert(oparg == 1); + PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); + if (!LOCK_OBJECT(self_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = arg; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); + if (err) { + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + c = callable; + s = self; + #if TIER_ONE + + assert(next_instr->op.code == POP_TOP); + SKIP_OVER(1); + #endif + _tos_cache1 = s; + _tos_cache0 = c; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_LIST_APPEND_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef self; + _PyStackRef callable; + _PyStackRef c; + _PyStackRef s; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + arg = _stack_item_1; + self = _stack_item_0; + callable = stack_pointer[-1]; + assert(oparg == 1); + PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); + if (!LOCK_OBJECT(self_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = arg; + _tos_cache0 = self; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); + if (err) { + stack_pointer[0] = self; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + c = callable; + s = self; + #if TIER_ONE + + assert(next_instr->op.code == POP_TOP); + SKIP_OVER(1); + #endif + _tos_cache1 = s; + _tos_cache0 = c; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_LIST_APPEND_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef self; + _PyStackRef callable; + _PyStackRef c; + _PyStackRef s; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + arg = _stack_item_2; + self = _stack_item_1; + callable = _stack_item_0; + assert(oparg == 1); + PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); + if (!LOCK_OBJECT(self_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = arg; + _tos_cache1 = self; + _tos_cache0 = callable; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); + if (err) { + stack_pointer[0] = callable; + stack_pointer[1] = self; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + c = callable; + s = self; + #if TIER_ONE + + assert(next_instr->op.code == POP_TOP); + SKIP_OVER(1); + #endif + _tos_cache1 = s; + _tos_cache0 = c; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CALL_METHOD_DESCRIPTOR_O_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -6086,19 +14003,23 @@ PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (total_args != 2) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDef *meth = method->d_method; if (meth->ml_flags != METH_O) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (_Py_ReachedRecursionLimit(tstate)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } _PyStackRef arg_stackref = arguments[1]; @@ -6106,6 +14027,7 @@ if (!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), method->d_common.d_type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); @@ -6134,18 +14056,23 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { + case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -6163,16 +14090,19 @@ } if (total_args == 0) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDef *meth = method->d_method; if (meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyTypeObject *d_type = method->d_common.d_type; @@ -6180,68 +14110,39 @@ assert(self != NULL); if (!Py_IS_TYPE(self, d_type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); - int nargs = total_args - 1; - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(meth->ml_meth); - PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); + PyObject *res_o = _PyCallMethodDescriptorFastWithKeywords_StackRefSteal( + callable, + meth, + self, + arguments, + total_args + ); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_METHOD_DESCRIPTOR_NOARGS: { + case _CALL_METHOD_DESCRIPTOR_NOARGS_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -6259,11 +14160,13 @@ } if (total_args != 1) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDef *meth = method->d_method; @@ -6271,14 +14174,17 @@ PyObject *self = PyStackRef_AsPyObjectBorrow(self_stackref); if (!Py_IS_TYPE(self, method->d_common.d_type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (meth->ml_flags != METH_NOARGS) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (_Py_ReachedRecursionLimit(tstate)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); @@ -6292,21 +14198,26 @@ PyStackRef_CLOSE(self_stackref); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callable); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_METHOD_DESCRIPTOR_FAST: { + case _CALL_METHOD_DESCRIPTOR_FAST_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; @@ -6324,90 +14235,66 @@ } if (total_args == 0) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyMethodDef *meth = method->d_method; if (meth->ml_flags != METH_FASTCALL) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); assert(self != NULL); if (!Py_IS_TYPE(self, method->d_common.d_type)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } STAT_INC(CALL, hit); - int nargs = total_args - 1; - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth); - PyObject *res_o = cfunc(self, (args_o + 1), nargs); + PyObject *res_o = _PyCallMethodDescriptorFast_StackRefSteal( + callable, + meth, + self, + arguments, + total_args + ); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _MAYBE_EXPAND_METHOD_KW: { + case _MAYBE_EXPAND_METHOD_KW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - self_or_null = stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; if (PyStackRef_TYPE(callable) == &PyMethod_Type && PyStackRef_IsNull(self_or_null)) { PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyObject *self = ((PyMethodObject *)callable_o)->im_self; @@ -6415,30 +14302,42 @@ PyObject *method = ((PyMethodObject *)callable_o)->im_func; _PyStackRef temp = callable; callable = PyStackRef_FromPyObjectNew(method); - stack_pointer[-3 - oparg] = callable; - stack_pointer[-2 - oparg] = self_or_null; + stack_pointer[-2 - oparg] = callable; + stack_pointer[-1 - oparg] = self_or_null; + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(temp); stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; } - stack_pointer[-3 - oparg] = callable; - stack_pointer[-2 - oparg] = self_or_null; + _tos_cache0 = _stack_item_0; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer[-2 - oparg] = callable; + stack_pointer[-1 - oparg] = self_or_null; + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _DO_CALL_KW is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _PY_FRAME_KW: { + case _PY_FRAME_KW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef kwnames; _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef new_frame; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; - self_or_null = stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + kwnames = _stack_item_0; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; @@ -6451,6 +14350,9 @@ assert(Py_TYPE(callable_o) == &PyFunction_Type); int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + stack_pointer[0] = kwnames; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( tstate, callable, locals, @@ -6458,74 +14360,104 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } new_frame = PyStackRef_Wrap(temp); - stack_pointer[0] = new_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = new_frame; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_FUNCTION_VERSION_KW: { + case _CHECK_FUNCTION_VERSION_KW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - callable = stack_pointer[-3 - oparg]; - uint32_t func_version = (uint32_t)CURRENT_OPERAND0(); + callable = stack_pointer[-2 - oparg]; + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } PyFunctionObject *func = (PyFunctionObject *)callable_o; if (func->func_version != func_version) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_METHOD_VERSION_KW: { + case _CHECK_METHOD_VERSION_KW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef null; _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - null = stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; - uint32_t func_version = (uint32_t)CURRENT_OPERAND0(); + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + uint32_t func_version = (uint32_t)CURRENT_OPERAND0_32(); PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (Py_TYPE(callable_o) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } PyObject *func = ((PyMethodObject *)callable_o)->im_func; if (!PyFunction_Check(func)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (((PyFunctionObject *)func)->func_version != func_version) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (!PyStackRef_IsNull(null)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _EXPAND_METHOD_KW: { + case _EXPAND_METHOD_KW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef self_or_null; _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - self_or_null = stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; assert(PyStackRef_IsNull(self_or_null)); _PyStackRef callable_s = callable; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -6533,136 +14465,129 @@ self_or_null = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); callable = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); assert(PyStackRef_FunctionCheck(callable)); - stack_pointer[-3 - oparg] = callable; - stack_pointer[-2 - oparg] = self_or_null; + stack_pointer[-2 - oparg] = callable; + stack_pointer[-1 - oparg] = self_or_null; + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callable_s); stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = _stack_item_0; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_IS_NOT_PY_CALLABLE_KW: { + case _CHECK_IS_NOT_PY_CALLABLE_KW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - callable = stack_pointer[-3 - oparg]; + callable = stack_pointer[-2 - oparg]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (PyFunction_Check(callable_o)) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } if (Py_TYPE(callable_o) == &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CALL_KW_NON_PY: { + case _CALL_KW_NON_PY_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef kwnames; _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; - self_or_null = stack_pointer[-2 - oparg]; - callable = stack_pointer[-3 - oparg]; + kwnames = _stack_item_0; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = kwnames; - kwnames = PyStackRef_NULL; - stack_pointer[-1] = kwnames; - PyStackRef_CLOSE(tmp); - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-2 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-3 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_ERROR(); - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); + stack_pointer[0] = kwnames; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( - callable_o, args_o, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames_o); + PyObject *res_o = _Py_VectorCall_StackRefSteal( + callable, + arguments, + total_args, + kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -3 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -3 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MAKE_CALLARGS_A_TUPLE: { + case _MAKE_CALLARGS_A_TUPLE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef callargs; _PyStackRef func; - callargs = stack_pointer[-2]; - func = stack_pointer[-4]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + callargs = _stack_item_1; + func = stack_pointer[-1]; PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); if (!PyTuple_CheckExact(callargs_o)) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = callargs; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (err < 0) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *tuple_o = PySequence_Tuple(callargs_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (tuple_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyStackRef temp = callargs; @@ -6671,40 +14596,56 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(temp); stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -3; } - stack_pointer[-2] = callargs; + _tos_cache2 = _stack_item_2; + _tos_cache1 = callargs; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } /* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _MAKE_FUNCTION: { + case _MAKE_FUNCTION_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef codeobj_st; _PyStackRef func; - codeobj_st = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + codeobj_st = _stack_item_0; PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st); + stack_pointer[0] = codeobj_st; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(codeobj_st); stack_pointer = _PyFrame_GetStackPointer(frame); if (func_obj == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } _PyFunction_SetVersion( func_obj, ((PyCodeObject *)codeobj)->co_version); func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); - stack_pointer[0] = func; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = func; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SET_FUNCTION_ATTRIBUTE: { + case _SET_FUNCTION_ATTRIBUTE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef func_in; _PyStackRef attr_st; _PyStackRef func_out; @@ -6720,13 +14661,98 @@ PyObject **ptr = (PyObject **)(((char *)func) + offset); assert(*ptr == NULL); *ptr = attr; - stack_pointer[-2] = func_out; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = func_out; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _RETURN_GENERATOR: { + case _SET_FUNCTION_ATTRIBUTE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef func_in; + _PyStackRef attr_st; + _PyStackRef func_out; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + func_in = _stack_item_0; + attr_st = stack_pointer[-1]; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; + assert(PyFunction_Check(func)); + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; + _tos_cache0 = func_out; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SET_FUNCTION_ATTRIBUTE_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef func_in; + _PyStackRef attr_st; + _PyStackRef func_out; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + func_in = _stack_item_1; + attr_st = _stack_item_0; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; + assert(PyFunction_Check(func)); + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; + _tos_cache0 = func_out; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SET_FUNCTION_ATTRIBUTE_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef func_in; + _PyStackRef attr_st; + _PyStackRef func_out; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + func_in = _stack_item_2; + attr_st = _stack_item_1; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_in); + PyObject *attr = PyStackRef_AsPyObjectSteal(attr_st); + func_out = func_in; + assert(PyFunction_Check(func)); + size_t offset = _Py_FunctionAttributeOffsets[oparg]; + assert(offset != 0); + PyObject **ptr = (PyObject **)(((char *)func) + offset); + assert(*ptr == NULL); + *ptr = attr; + _tos_cache1 = func_out; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _RETURN_GENERATOR_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef res; assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); @@ -6734,6 +14760,7 @@ PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); stack_pointer = _PyFrame_GetStackPointer(frame); if (gen == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } assert(STACK_LEVEL() == 0); @@ -6752,13 +14779,17 @@ stack_pointer = _PyFrame_GetStackPointer(frame); res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); LLTRACE_RESUME_FRAME(); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BUILD_SLICE: { + case _BUILD_SLICE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef slice; oparg = CURRENT_OPARG(); @@ -6776,78 +14807,106 @@ } stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (slice_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } slice = PyStackRef_FromPyObjectStealMortal(slice_o); - stack_pointer[0] = slice; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = slice; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CONVERT_VALUE: { + case _CONVERT_VALUE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef result; + _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); - value = stack_pointer[-1]; + value = _stack_item_0; conversion_func conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = _PyEval_ConversionFuncs[oparg]; + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (result_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } result = PyStackRef_FromPyObjectSteal(result_o); - stack_pointer[0] = result; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = result; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _FORMAT_SIMPLE: { + case _FORMAT_SIMPLE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef value; _PyStackRef res; - value = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + value = _stack_item_0; PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); if (!PyUnicode_CheckExact(value_o)) { + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Format(value_o, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); } else { res = value; - stack_pointer += -1; } - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _FORMAT_WITH_SPEC: { + case _FORMAT_WITH_SPEC_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef fmt_spec; _PyStackRef value; _PyStackRef res; - fmt_spec = stack_pointer[-1]; - value = stack_pointer[-2]; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + fmt_spec = _stack_item_1; + value = _stack_item_0; + stack_pointer[0] = value; + stack_pointer[1] = fmt_spec; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Format(PyStackRef_AsPyObjectBorrow(value), PyStackRef_AsPyObjectBorrow(fmt_spec)); _PyStackRef tmp = fmt_spec; @@ -6860,76 +14919,230 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COPY_1: { + case _COPY_1_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef bottom; _PyStackRef top; bottom = stack_pointer[-1]; top = PyStackRef_DUP(bottom); - stack_pointer[0] = top; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache1 = top; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COPY_2: { + case _COPY_1_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + bottom = _stack_item_0; + top = PyStackRef_DUP(bottom); + _tos_cache1 = top; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_1_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + bottom = _stack_item_1; + top = PyStackRef_DUP(bottom); + _tos_cache2 = top; + _tos_cache1 = bottom; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_2_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef bottom; _PyStackRef top; bottom = stack_pointer[-2]; top = PyStackRef_DUP(bottom); - stack_pointer[0] = top; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = top; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COPY_3: { + case _COPY_2_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + bottom = stack_pointer[-1]; + top = PyStackRef_DUP(bottom); + _tos_cache2 = top; + _tos_cache1 = _stack_item_0; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_2_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + bottom = _stack_item_0; + top = PyStackRef_DUP(bottom); + _tos_cache2 = top; + _tos_cache1 = _stack_item_1; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_3_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef bottom; _PyStackRef top; bottom = stack_pointer[-3]; top = PyStackRef_DUP(bottom); - stack_pointer[0] = top; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache2 = top; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = stack_pointer[-2]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COPY: { + case _COPY_3_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + bottom = stack_pointer[-2]; + top = PyStackRef_DUP(bottom); + _tos_cache2 = top; + _tos_cache1 = _stack_item_0; + _tos_cache0 = stack_pointer[-1]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_3_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + bottom = stack_pointer[-1]; + top = PyStackRef_DUP(bottom); + _tos_cache2 = top; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_3_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef bottom; + _PyStackRef top; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + bottom = _stack_item_0; + top = PyStackRef_DUP(bottom); + _tos_cache2 = top; + _tos_cache1 = _stack_item_2; + _tos_cache0 = _stack_item_1; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer[0] = bottom; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COPY_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef bottom; _PyStackRef top; oparg = CURRENT_OPARG(); bottom = stack_pointer[-1 - (oparg-1)]; top = PyStackRef_DUP(bottom); - stack_pointer[0] = top; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + _tos_cache0 = top; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP: { + case _BINARY_OP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef rhs; _PyStackRef lhs; _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - rhs = stack_pointer[-1]; - lhs = stack_pointer[-2]; + rhs = _stack_item_1; + lhs = _stack_item_0; PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); PyObject *rhs_o = PyStackRef_AsPyObjectBorrow(rhs); assert(_PyEval_BinaryOps[oparg]); + stack_pointer[0] = lhs; + stack_pointer[1] = rhs; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); @@ -6944,11 +15157,20 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _tos_cache0 = res; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SWAP_2: { + case _SWAP_2_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef top; _PyStackRef bottom; top = stack_pointer[-1]; @@ -6956,12 +15178,78 @@ _PyStackRef temp = bottom; bottom = top; top = temp; - stack_pointer[-2] = bottom; - stack_pointer[-1] = top; + _tos_cache1 = top; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SWAP_3: { + case _SWAP_2_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef top; + _PyStackRef bottom; + _PyStackRef _stack_item_0 = _tos_cache0; + top = _stack_item_0; + bottom = stack_pointer[-1]; + _PyStackRef temp = bottom; + bottom = top; + top = temp; + _tos_cache1 = top; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SWAP_2_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef top; + _PyStackRef bottom; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + top = _stack_item_1; + bottom = _stack_item_0; + _PyStackRef temp = bottom; + bottom = top; + top = temp; + _tos_cache1 = top; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SWAP_2_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef top; + _PyStackRef bottom; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + top = _stack_item_2; + bottom = _stack_item_1; + _PyStackRef temp = bottom; + bottom = top; + top = temp; + _tos_cache2 = top; + _tos_cache1 = bottom; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SWAP_3_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef top; _PyStackRef bottom; top = stack_pointer[-1]; @@ -6969,22 +15257,96 @@ _PyStackRef temp = bottom; bottom = top; top = temp; - stack_pointer[-3] = bottom; - stack_pointer[-1] = top; + _tos_cache2 = top; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SWAP: { + case _SWAP_3_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef top; _PyStackRef bottom; - oparg = CURRENT_OPARG(); - top = stack_pointer[-1]; - bottom = stack_pointer[-2 - (oparg-2)]; + _PyStackRef _stack_item_0 = _tos_cache0; + top = _stack_item_0; + bottom = stack_pointer[-2]; _PyStackRef temp = bottom; bottom = top; top = temp; - stack_pointer[-2 - (oparg-2)] = bottom; - stack_pointer[-1] = top; + _tos_cache2 = top; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SWAP_3_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef top; + _PyStackRef bottom; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + top = _stack_item_1; + bottom = stack_pointer[-1]; + _PyStackRef temp = bottom; + bottom = top; + top = temp; + _tos_cache2 = top; + _tos_cache1 = _stack_item_0; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SWAP_3_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef top; + _PyStackRef bottom; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + top = _stack_item_2; + bottom = _stack_item_0; + _PyStackRef temp = bottom; + bottom = top; + top = temp; + _tos_cache2 = top; + _tos_cache1 = _stack_item_1; + _tos_cache0 = bottom; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SWAP_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef top; + _PyStackRef bottom; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + top = _stack_item_0; + bottom = stack_pointer[-1 - (oparg-2)]; + _PyStackRef temp = bottom; + bottom = top; + top = temp; + _tos_cache0 = top; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer[-1 - (oparg-2)] = bottom; + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -7006,94 +15368,468 @@ /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 because it is instrumented */ - case _GUARD_IS_TRUE_POP: { + case _GUARD_IS_TRUE_POP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef flag; flag = stack_pointer[-1]; int is_true = PyStackRef_IsTrue(flag); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); if (!is_true) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_IS_FALSE_POP: { + case _GUARD_IS_TRUE_POP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + flag = _stack_item_0; + int is_true = PyStackRef_IsTrue(flag); + if (!is_true) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_TRUE_POP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + flag = _stack_item_1; + int is_true = PyStackRef_IsTrue(flag); + if (!is_true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_TRUE_POP_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + flag = _stack_item_2; + int is_true = PyStackRef_IsTrue(flag); + if (!is_true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_FALSE_POP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef flag; flag = stack_pointer[-1]; int is_false = PyStackRef_IsFalse(flag); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); if (!is_false) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_IS_NONE_POP: { + case _GUARD_IS_FALSE_POP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + flag = _stack_item_0; + int is_false = PyStackRef_IsFalse(flag); + if (!is_false) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_FALSE_POP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + flag = _stack_item_1; + int is_false = PyStackRef_IsFalse(flag); + if (!is_false) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_FALSE_POP_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + flag = _stack_item_2; + int is_false = PyStackRef_IsFalse(flag); + if (!is_false) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_NONE_POP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef val; val = stack_pointer[-1]; int is_none = PyStackRef_IsNone(val); if (!is_none) { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(val); stack_pointer = _PyFrame_GetStackPointer(frame); if (1) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } } + SET_CURRENT_CACHED_VALUES(0); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _GUARD_IS_NOT_NONE_POP: { + case _GUARD_IS_NONE_POP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef val; - val = stack_pointer[-1]; + _PyStackRef _stack_item_0 = _tos_cache0; + val = _stack_item_0; + int is_none = PyStackRef_IsNone(val); + if (!is_none) { + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(val); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (1) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_NONE_POP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef val; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + val = _stack_item_1; + int is_none = PyStackRef_IsNone(val); + if (!is_none) { + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(val); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_NONE_POP_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef val; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + val = _stack_item_2; + int is_none = PyStackRef_IsNone(val); + if (!is_none) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(val); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IS_NOT_NONE_POP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef val; + _PyStackRef _stack_item_0 = _tos_cache0; + val = _stack_item_0; int is_none = PyStackRef_IsNone(val); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(val); stack_pointer = _PyFrame_GetStackPointer(frame); if (is_none) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _JUMP_TO_TOP: { + case _JUMP_TO_TOP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); JUMP_TO_JUMP_TARGET(); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SET_IP: { - PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND0(); + case _SET_IP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND0_64(); frame->instr_ptr = (_Py_CODEUNIT *)instr_ptr; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _CHECK_STACK_SPACE_OPERAND: { - uint32_t framesize = (uint32_t)CURRENT_OPERAND0(); + case _SET_IP_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND0_64(); + frame->instr_ptr = (_Py_CODEUNIT *)instr_ptr; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SET_IP_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND0_64(); + frame->instr_ptr = (_Py_CODEUNIT *)instr_ptr; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SET_IP_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + PyObject *instr_ptr = (PyObject *)CURRENT_OPERAND0_64(); + frame->instr_ptr = (_Py_CODEUNIT *)instr_ptr; + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_STACK_SPACE_OPERAND_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + uint32_t framesize = (uint32_t)CURRENT_OPERAND0_32(); assert(framesize <= INT_MAX); if (!_PyThreadState_HasStackSpace(tstate, framesize)) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } if (tstate->py_recursion_remaining <= 1) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _SAVE_RETURN_OFFSET: { + case _CHECK_STACK_SPACE_OPERAND_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + uint32_t framesize = (uint32_t)CURRENT_OPERAND0_32(); + assert(framesize <= INT_MAX); + if (!_PyThreadState_HasStackSpace(tstate, framesize)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + if (tstate->py_recursion_remaining <= 1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_STACK_SPACE_OPERAND_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + uint32_t framesize = (uint32_t)CURRENT_OPERAND0_32(); + assert(framesize <= INT_MAX); + if (!_PyThreadState_HasStackSpace(tstate, framesize)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + if (tstate->py_recursion_remaining <= 1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_STACK_SPACE_OPERAND_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + uint32_t framesize = (uint32_t)CURRENT_OPERAND0_32(); + assert(framesize <= INT_MAX); + if (!_PyThreadState_HasStackSpace(tstate, framesize)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + if (tstate->py_recursion_remaining <= 1) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SAVE_RETURN_OFFSET_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); #if TIER_ONE frame->return_offset = (uint16_t)(next_instr - this_instr); @@ -7101,304 +15837,870 @@ #if TIER_TWO frame->return_offset = oparg; #endif + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _EXIT_TRACE: { - PyObject *exit_p = (PyObject *)CURRENT_OPERAND0(); + case _SAVE_RETURN_OFFSET_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + #if TIER_ONE + frame->return_offset = (uint16_t)(next_instr - this_instr); + #endif + #if TIER_TWO + frame->return_offset = oparg; + #endif + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SAVE_RETURN_OFFSET_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + #if TIER_ONE + frame->return_offset = (uint16_t)(next_instr - this_instr); + #endif + #if TIER_TWO + frame->return_offset = oparg; + #endif + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SAVE_RETURN_OFFSET_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + #if TIER_ONE + frame->return_offset = (uint16_t)(next_instr - this_instr); + #endif + #if TIER_TWO + frame->return_offset = oparg; + #endif + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _EXIT_TRACE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); _PyExitData *exit = (_PyExitData *)exit_p; #if defined(Py_DEBUG) && !defined(_Py_JIT) - _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; + const _Py_CODEUNIT *target = ((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame)) + + exit->target; OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); - if (frame->lltrace >= 2) { + if (frame->lltrace >= 3) { _PyFrame_SetStackPointer(frame, stack_pointer); printf("SIDE EXIT: [UOp "); _PyUOpPrint(&next_uop[-1]); - printf(", exit %lu, temp %d, target %d -> %s]\n", + printf(", exit %tu, temp %d, target %d -> %s, is_control_flow %d]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code], exit->is_control_flow); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + #endif + tstate->jit_exit = exit; + SET_CURRENT_CACHED_VALUES(0); + TIER2_TO_TIER2(exit->executor); + } + + case _EXIT_TRACE_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + _PyExitData *exit = (_PyExitData *)exit_p; + #if defined(Py_DEBUG) && !defined(_Py_JIT) + const _Py_CODEUNIT *target = ((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame)) + + exit->target; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("SIDE EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s, is_control_flow %d]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code], exit->is_control_flow); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + } + #endif + tstate->jit_exit = exit; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + TIER2_TO_TIER2(exit->executor); + } + + case _EXIT_TRACE_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + _PyExitData *exit = (_PyExitData *)exit_p; + #if defined(Py_DEBUG) && !defined(_Py_JIT) + const _Py_CODEUNIT *target = ((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame)) + + exit->target; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("SIDE EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s, is_control_flow %d]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code], exit->is_control_flow); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -2; + } + #endif + tstate->jit_exit = exit; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + TIER2_TO_TIER2(exit->executor); + } + + case _EXIT_TRACE_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + _PyExitData *exit = (_PyExitData *)exit_p; + #if defined(Py_DEBUG) && !defined(_Py_JIT) + const _Py_CODEUNIT *target = ((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame)) + + exit->target; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("SIDE EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s, is_control_flow %d]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code], exit->is_control_flow); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -3; + } + #endif + tstate->jit_exit = exit; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + TIER2_TO_TIER2(exit->executor); + } + + case _DYNAMIC_EXIT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + #if defined(Py_DEBUG) && !defined(_Py_JIT) + _PyExitData *exit = (_PyExitData *)exit_p; + _Py_CODEUNIT *target = frame->instr_ptr; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("DYNAMIC EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s]\n", exit - current_executor->exits, exit->temperature.value_and_backoff, (int)(target - _PyFrame_GetBytecode(frame)), _PyOpcode_OpName[target->op.code]); stack_pointer = _PyFrame_GetStackPointer(frame); } #endif - tstate->jit_exit = exit; - TIER2_TO_TIER2(exit->executor); - break; + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(frame->instr_ptr); } - case _CHECK_VALIDITY: { + case _DYNAMIC_EXIT_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + #if defined(Py_DEBUG) && !defined(_Py_JIT) + _PyExitData *exit = (_PyExitData *)exit_p; + _Py_CODEUNIT *target = frame->instr_ptr; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("DYNAMIC EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code]); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + } + #endif + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + GOTO_TIER_ONE(frame->instr_ptr); + } + + case _DYNAMIC_EXIT_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + #if defined(Py_DEBUG) && !defined(_Py_JIT) + _PyExitData *exit = (_PyExitData *)exit_p; + _Py_CODEUNIT *target = frame->instr_ptr; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("DYNAMIC EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code]); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -2; + } + #endif + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + GOTO_TIER_ONE(frame->instr_ptr); + } + + case _DYNAMIC_EXIT_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0_64(); + #if defined(Py_DEBUG) && !defined(_Py_JIT) + _PyExitData *exit = (_PyExitData *)exit_p; + _Py_CODEUNIT *target = frame->instr_ptr; + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + if (frame->lltrace >= 3) { + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("DYNAMIC EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(", exit %tu, temp %d, target %d -> %s]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code]); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -3; + } + #endif + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + GOTO_TIER_ONE(frame->instr_ptr); + } + + case _CHECK_VALIDITY_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); if (!current_executor->vm_data.valid) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _LOAD_CONST_INLINE: { - _PyStackRef value; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - value = PyStackRef_FromPyObjectNew(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _POP_TOP_LOAD_CONST_INLINE: { - _PyStackRef pop; - _PyStackRef value; - pop = stack_pointer[-1]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop); - stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectNew(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_CONST_INLINE_BORROW: { - _PyStackRef value; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _POP_CALL: { - _PyStackRef null; - _PyStackRef callable; - null = stack_pointer[-1]; - callable = stack_pointer[-2]; - (void)null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - - case _POP_CALL_ONE: { - _PyStackRef pop; - _PyStackRef null; - _PyStackRef callable; - pop = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop); - stack_pointer = _PyFrame_GetStackPointer(frame); - (void)null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - - case _POP_CALL_TWO: { - _PyStackRef pop2; - _PyStackRef pop1; - _PyStackRef null; - _PyStackRef callable; - pop2 = stack_pointer[-1]; - pop1 = stack_pointer[-2]; - null = stack_pointer[-3]; - callable = stack_pointer[-4]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop2); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop1); - stack_pointer = _PyFrame_GetStackPointer(frame); - (void)null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - - case _POP_TOP_LOAD_CONST_INLINE_BORROW: { - _PyStackRef pop; - _PyStackRef value; - pop = stack_pointer[-1]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop); - stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _POP_TWO_LOAD_CONST_INLINE_BORROW: { - _PyStackRef pop2; - _PyStackRef pop1; - _PyStackRef value; - pop2 = stack_pointer[-1]; - pop1 = stack_pointer[-2]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop2); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop1); - stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _POP_CALL_LOAD_CONST_INLINE_BORROW: { - _PyStackRef null; - _PyStackRef callable; - _PyStackRef value; - null = stack_pointer[-1]; - callable = stack_pointer[-2]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - (void)null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW: { - _PyStackRef pop; - _PyStackRef null; - _PyStackRef callable; - _PyStackRef value; - pop = stack_pointer[-1]; - null = stack_pointer[-2]; - callable = stack_pointer[-3]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop); - stack_pointer = _PyFrame_GetStackPointer(frame); - (void)null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW: { - _PyStackRef pop2; - _PyStackRef pop1; - _PyStackRef null; - _PyStackRef callable; - _PyStackRef value; - pop2 = stack_pointer[-1]; - pop1 = stack_pointer[-2]; - null = stack_pointer[-3]; - callable = stack_pointer[-4]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop2); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(pop1); - stack_pointer = _PyFrame_GetStackPointer(frame); - (void)null; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_CONST_UNDER_INLINE: { - _PyStackRef old; - _PyStackRef value; - _PyStackRef new; - old = stack_pointer[-1]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - new = old; - value = PyStackRef_FromPyObjectNew(ptr); - stack_pointer[-1] = value; - stack_pointer[0] = new; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_CONST_UNDER_INLINE_BORROW: { - _PyStackRef old; - _PyStackRef value; - _PyStackRef new; - old = stack_pointer[-1]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); - new = old; - value = PyStackRef_FromPyObjectBorrow(ptr); - stack_pointer[-1] = value; - stack_pointer[0] = new; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _CHECK_FUNCTION: { - uint32_t func_version = (uint32_t)CURRENT_OPERAND0(); - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - if (func->func_version != func_version) { + case _CHECK_VALIDITY_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + if (!current_executor->vm_data.valid) { UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _START_EXECUTOR: { - PyObject *executor = (PyObject *)CURRENT_OPERAND0(); + case _CHECK_VALIDITY_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + if (!current_executor->vm_data.valid) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _CHECK_VALIDITY_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + if (!current_executor->vm_data.valid) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_INLINE_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_INLINE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_INLINE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_LOAD_CONST_INLINE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop; + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + pop = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop); + stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_INLINE_BORROW_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_INLINE_BORROW_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_INLINE_BORROW_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache2 = value; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_CALL_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null = _stack_item_1; + callable = _stack_item_0; + (void)null; + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_CALL_ONE_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop; + _PyStackRef null; + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + pop = _stack_item_2; + null = _stack_item_1; + callable = _stack_item_0; + stack_pointer[0] = callable; + stack_pointer[1] = null; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop); + stack_pointer = _PyFrame_GetStackPointer(frame); + (void)null; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_CALL_TWO_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop2; + _PyStackRef pop1; + _PyStackRef null; + _PyStackRef callable; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + pop2 = _stack_item_2; + pop1 = _stack_item_1; + null = _stack_item_0; + callable = stack_pointer[-1]; + stack_pointer[0] = null; + stack_pointer[1] = pop1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop2); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop1); + stack_pointer = _PyFrame_GetStackPointer(frame); + (void)null; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + _tos_cache0 = PyStackRef_ZERO_BITS; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TOP_LOAD_CONST_INLINE_BORROW_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop; + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + pop = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop); + stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_TWO_LOAD_CONST_INLINE_BORROW_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop2; + _PyStackRef pop1; + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + pop2 = _stack_item_1; + pop1 = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + stack_pointer[0] = pop1; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop2); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop1); + stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_CALL_LOAD_CONST_INLINE_BORROW_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef null; + _PyStackRef callable; + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + null = _stack_item_1; + callable = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + (void)null; + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop; + _PyStackRef null; + _PyStackRef callable; + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + pop = _stack_item_2; + null = _stack_item_1; + callable = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + stack_pointer[0] = callable; + stack_pointer[1] = null; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop); + stack_pointer = _PyFrame_GetStackPointer(frame); + (void)null; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef pop2; + _PyStackRef pop1; + _PyStackRef null; + _PyStackRef callable; + _PyStackRef value; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + pop2 = _stack_item_2; + pop1 = _stack_item_1; + null = _stack_item_0; + callable = stack_pointer[-1]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + stack_pointer[0] = null; + stack_pointer[1] = pop1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop2); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(pop1); + stack_pointer = _PyFrame_GetStackPointer(frame); + (void)null; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache0 = value; + _tos_cache1 = PyStackRef_ZERO_BITS; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_UNDER_INLINE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef old; + _PyStackRef value; + _PyStackRef new; + old = stack_pointer[-1]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + new = old; + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache1 = new; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_UNDER_INLINE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef old; + _PyStackRef value; + _PyStackRef new; + _PyStackRef _stack_item_0 = _tos_cache0; + old = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + new = old; + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache1 = new; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_UNDER_INLINE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef old; + _PyStackRef value; + _PyStackRef new; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + old = _stack_item_1; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + new = old; + value = PyStackRef_FromPyObjectNew(ptr); + _tos_cache2 = new; + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_UNDER_INLINE_BORROW_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef old; + _PyStackRef value; + _PyStackRef new; + old = stack_pointer[-1]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + new = old; + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache1 = new; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_UNDER_INLINE_BORROW_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef old; + _PyStackRef value; + _PyStackRef new; + _PyStackRef _stack_item_0 = _tos_cache0; + old = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + new = old; + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache1 = new; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _LOAD_CONST_UNDER_INLINE_BORROW_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef old; + _PyStackRef value; + _PyStackRef new; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + old = _stack_item_1; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + new = old; + value = PyStackRef_FromPyObjectBorrow(ptr); + _tos_cache2 = new; + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _START_EXECUTOR_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + PyObject *executor = (PyObject *)CURRENT_OPERAND0_64(); #ifndef _Py_JIT assert(current_executor == (_PyExecutorObject*)executor); #endif @@ -7412,52 +16714,407 @@ stack_pointer = _PyFrame_GetStackPointer(frame); if (true) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _MAKE_WARM: { + case _MAKE_WARM_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); current_executor->vm_data.warm = true; - if (--tstate->interp->trace_run_counter == 0) { - _Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT); - } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _FATAL_ERROR: { + case _MAKE_WARM_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + current_executor->vm_data.warm = true; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MAKE_WARM_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + current_executor->vm_data.warm = true; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MAKE_WARM_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + current_executor->vm_data.warm = true; + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _FATAL_ERROR_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); assert(0); Py_FatalError("Fatal error uop executed."); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _DEOPT: { - GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + case _FATAL_ERROR_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + assert(0); + Py_FatalError("Fatal error uop executed."); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _HANDLE_PENDING_AND_DEOPT: { + case _FATAL_ERROR_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + assert(0); + Py_FatalError("Fatal error uop executed."); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _FATAL_ERROR_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + assert(0); + Py_FatalError("Fatal error uop executed."); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _DEOPT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _DEOPT_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _DEOPT_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _DEOPT_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE((frame->owner == FRAME_OWNED_BY_INTERPRETER) + ? _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _HANDLE_PENDING_AND_DEOPT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); GOTO_TIER_ONE(err ? NULL : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); - break; } - case _ERROR_POP_N: { + case _HANDLE_PENDING_AND_DEOPT_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(err ? NULL : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _HANDLE_PENDING_AND_DEOPT_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(err ? NULL : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _HANDLE_PENDING_AND_DEOPT_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(err ? NULL : _PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + + case _ERROR_POP_N_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); oparg = CURRENT_OPARG(); - uint32_t target = (uint32_t)CURRENT_OPERAND0(); + uint32_t target = (uint32_t)CURRENT_OPERAND0_32(); assert(oparg == 0); frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; + SET_CURRENT_CACHED_VALUES(0); GOTO_TIER_ONE(NULL); + } + + case _SPILL_OR_RELOAD_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _tos_cache0 = stack_pointer[-1]; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _TIER2_RESUME_CHECK: { + case _SPILL_OR_RELOAD_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = stack_pointer[-2]; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _tos_cache2 = stack_pointer[-1]; + _tos_cache1 = stack_pointer[-2]; + _tos_cache0 = stack_pointer[-3]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _tos_cache1 = _stack_item_0; + _tos_cache0 = stack_pointer[-1]; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _tos_cache2 = _stack_item_0; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = stack_pointer[-2]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r20: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _tos_cache0 = _stack_item_1; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _tos_cache2 = _stack_item_1; + _tos_cache1 = _stack_item_0; + _tos_cache0 = stack_pointer[-1]; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r30: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + SET_CURRENT_CACHED_VALUES(0); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer[2] = _stack_item_2; + stack_pointer += 3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r31: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + _tos_cache0 = _stack_item_2; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer[0] = _stack_item_0; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SPILL_OR_RELOAD_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + _tos_cache1 = _stack_item_2; + _tos_cache0 = _stack_item_1; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer[0] = _stack_item_0; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TIER2_RESUME_CHECK_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); #if defined(__EMSCRIPTEN__) if (_Py_emscripten_signal_clock == 0) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; @@ -7465,46 +17122,546 @@ uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); if (eval_breaker & _PY_EVAL_EVENTS_MASK) { UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _COLD_EXIT: { + case _TIER2_RESUME_CHECK_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + if (eval_breaker & _PY_EVAL_EVENTS_MASK) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TIER2_RESUME_CHECK_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + if (eval_breaker & _PY_EVAL_EVENTS_MASK) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _TIER2_RESUME_CHECK_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + if (eval_breaker & _PY_EVAL_EVENTS_MASK) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _COLD_EXIT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyExitData *exit = tstate->jit_exit; assert(exit != NULL); + assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; _Py_BackoffCounter temperature = exit->temperature; - if (!backoff_counter_triggers(temperature)) { - exit->temperature = advance_backoff_counter(temperature); - GOTO_TIER_ONE(target); - } _PyExecutorObject *executor; if (target->op.code == ENTER_EXECUTOR) { PyCodeObject *code = _PyFrame_GetCode(frame); executor = code->co_executors->executors[target->op.arg]; Py_INCREF(executor); + assert(tstate->jit_exit == exit); + exit->executor = executor; + SET_CURRENT_CACHED_VALUES(0); + TIER2_TO_TIER2(exit->executor); } else { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyExecutorObject *previous_executor = _PyExecutor_FromExit(exit); - stack_pointer = _PyFrame_GetStackPointer(frame); - assert(tstate->current_executor == (PyObject *)previous_executor); - int chain_depth = previous_executor->vm_data.chain_depth + 1; - _PyFrame_SetStackPointer(frame, stack_pointer); - int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (optimized <= 0) { - exit->temperature = restart_backoff_counter(temperature); - GOTO_TIER_ONE(optimized < 0 ? NULL : target); + if (!backoff_counter_triggers(temperature)) { + exit->temperature = advance_backoff_counter(temperature); + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(target); } - exit->temperature = initial_temperature_backoff_counter(); + _PyExecutorObject *previous_executor = _PyExecutor_FromExit(exit); + assert(tstate->current_executor == (PyObject *)previous_executor); + int chain_depth = previous_executor->vm_data.chain_depth + !exit->is_control_flow; + int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg); + exit->temperature = restart_backoff_counter(exit->temperature); + if (succ) { + GOTO_TIER_ONE_CONTINUE_TRACING(target); + } + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(target); } - assert(tstate->jit_exit == exit); - exit->executor = executor; - TIER2_TO_TIER2(exit->executor); + } + + case _COLD_DYNAMIC_EXIT_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _Py_CODEUNIT *target = frame->instr_ptr; + SET_CURRENT_CACHED_VALUES(0); + GOTO_TIER_ONE(target); + } + + case _GUARD_IP__PUSH_FRAME_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + #define OFFSET_OF__PUSH_FRAME ((0)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF__PUSH_FRAME; + if (true) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + } + SET_CURRENT_CACHED_VALUES(0); + #undef OFFSET_OF__PUSH_FRAME + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } + case _GUARD_IP__PUSH_FRAME_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + #define OFFSET_OF__PUSH_FRAME ((0)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF__PUSH_FRAME; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + #undef OFFSET_OF__PUSH_FRAME + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP__PUSH_FRAME_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + #define OFFSET_OF__PUSH_FRAME ((0)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF__PUSH_FRAME; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + #undef OFFSET_OF__PUSH_FRAME + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP__PUSH_FRAME_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + #define OFFSET_OF__PUSH_FRAME ((0)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF__PUSH_FRAME; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + #undef OFFSET_OF__PUSH_FRAME + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_YIELD_VALUE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + } + SET_CURRENT_CACHED_VALUES(0); + #undef OFFSET_OF_YIELD_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_YIELD_VALUE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + #undef OFFSET_OF_YIELD_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_YIELD_VALUE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + #undef OFFSET_OF_YIELD_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_YIELD_VALUE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + #undef OFFSET_OF_YIELD_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_VALUE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + } + SET_CURRENT_CACHED_VALUES(0); + #undef OFFSET_OF_RETURN_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_VALUE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + #undef OFFSET_OF_RETURN_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_VALUE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + #undef OFFSET_OF_RETURN_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_VALUE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + #undef OFFSET_OF_RETURN_VALUE + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_GENERATOR_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + if (true) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + } + SET_CURRENT_CACHED_VALUES(0); + #undef OFFSET_OF_RETURN_GENERATOR + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_GENERATOR_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + #undef OFFSET_OF_RETURN_GENERATOR + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_GENERATOR_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + #undef OFFSET_OF_RETURN_GENERATOR + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_IP_RETURN_GENERATOR_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) + PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); + _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + if (target != (_Py_CODEUNIT *)ip) { + frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + #undef OFFSET_OF_RETURN_GENERATOR + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + /* _TRACE_RECORD is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ + + #undef TIER_TWO diff --git a/Python/fileutils.c b/Python/fileutils.c index 2a3f12d4e87..0c1766b8804 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -2,6 +2,7 @@ #include "pycore_fileutils.h" // fileutils definitions #include "pycore_runtime.h" // _PyRuntime #include "pycore_pystate.h" // _Py_AssertHoldsTstate() +#include "pycore_unicodeobject.h" // _Py_MAX_UNICODE #include "osdefs.h" // SEP #include <stdlib.h> // mbstowcs() @@ -50,9 +51,6 @@ extern int winerror_to_errno(int); int _Py_open_cloexec_works = -1; #endif -// The value must be the same in unicodeobject.c. -#define MAX_UNICODE 0x10ffff - // mbstowcs() and mbrtowc() errors static const size_t DECODE_ERROR = ((size_t)-1); #ifdef HAVE_MBRTOWC @@ -123,7 +121,7 @@ is_valid_wide_char(wchar_t ch) { #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION /* Oracle Solaris doesn't use Unicode code points as wchar_t encoding - for non-Unicode locales, which makes values higher than MAX_UNICODE + for non-Unicode locales, which makes values higher than _Py_MAX_UNICODE possibly valid. */ return 1; #endif @@ -132,7 +130,7 @@ is_valid_wide_char(wchar_t ch) return 0; } #if SIZEOF_WCHAR_T > 2 - if (ch > MAX_UNICODE) { + if (ch > _Py_MAX_UNICODE) { // bpo-35883: Reject characters outside [U+0000; U+10ffff] range. // The glibc mbstowcs() UTF-8 decoder does not respect the RFC 3629, // it creates characters outside the [U+0000; U+10ffff] range: @@ -180,7 +178,7 @@ _Py_mbrtowc(wchar_t *pwc, const char *str, size_t len, mbstate_t *pmbs) #define USE_FORCE_ASCII -extern int _Py_normalize_encoding(const char *, char *, size_t); +extern int _Py_normalize_encoding(const char *, char *, size_t, int); /* Workaround FreeBSD and OpenIndiana locale encoding issue with the C locale and POSIX locale. nl_langinfo(CODESET) announces an alias of the @@ -231,7 +229,7 @@ check_force_ascii(void) } char encoding[20]; /* longest name: "iso_646.irv_1991\0" */ - if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding))) { + if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding), 1)) { goto error; } @@ -2120,7 +2118,6 @@ _Py_wrealpath(const wchar_t *path, wchar_t *resolved_path, size_t resolved_path_len) { char *cpath; - char cresolved_path[MAXPATHLEN]; wchar_t *wresolved_path; char *res; size_t r; @@ -2129,12 +2126,14 @@ _Py_wrealpath(const wchar_t *path, errno = EINVAL; return NULL; } - res = realpath(cpath, cresolved_path); + res = realpath(cpath, NULL); PyMem_RawFree(cpath); if (res == NULL) return NULL; - wresolved_path = Py_DecodeLocale(cresolved_path, &r); + wresolved_path = Py_DecodeLocale(res, &r); + free(res); + if (wresolved_path == NULL) { errno = EINVAL; return NULL; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index f8a4fa60f22..a43f8b45b87 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -2891,7 +2891,7 @@ optimize_load_fast(cfg_builder *g) int num_pushed = _PyOpcode_num_pushed(opcode, oparg); int net_pushed = num_pushed - num_popped; assert(net_pushed >= 0); - for (int i = 0; i < net_pushed; i++) { + for (int j = 0; j < net_pushed; j++) { PUSH_REF(i, NOT_LOCAL); } break; @@ -2993,11 +2993,8 @@ optimize_load_fast(cfg_builder *g) } // Push fallthrough block - cfg_instr *term = basicblock_last_instr(block); - if (term != NULL && block->b_next != NULL && - !(IS_UNCONDITIONAL_JUMP_OPCODE(term->i_opcode) || - IS_SCOPE_EXIT_OPCODE(term->i_opcode))) { - assert(BB_HAS_FALLTHROUGH(block)); + if (BB_HAS_FALLTHROUGH(block)) { + assert(block->b_next != NULL); load_fast_push_block(&sp, block->b_next, refs.size); } @@ -3594,8 +3591,19 @@ duplicate_exits_without_lineno(cfg_builder *g) * Also reduces the size of the line number table, * but has no impact on the generated line number events. */ + +static inline void +maybe_propagate_location(basicblock *b, int i, location loc) +{ + assert(b->b_iused > i); + if (b->b_instr[i].i_loc.lineno == NO_LOCATION.lineno) { + b->b_instr[i].i_loc = loc; + } +} + static void -propagate_line_numbers(basicblock *entryblock) { +propagate_line_numbers(basicblock *entryblock) +{ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { cfg_instr *last = basicblock_last_instr(b); if (last == NULL) { @@ -3604,26 +3612,21 @@ propagate_line_numbers(basicblock *entryblock) { location prev_location = NO_LOCATION; for (int i = 0; i < b->b_iused; i++) { - if (b->b_instr[i].i_loc.lineno == NO_LOCATION.lineno) { - b->b_instr[i].i_loc = prev_location; - } - else { - prev_location = b->b_instr[i].i_loc; - } + maybe_propagate_location(b, i, prev_location); + prev_location = b->b_instr[i].i_loc; } if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) { if (b->b_next->b_iused > 0) { - if (b->b_next->b_instr[0].i_loc.lineno == NO_LOCATION.lineno) { - b->b_next->b_instr[0].i_loc = prev_location; - } + maybe_propagate_location(b->b_next, 0, prev_location); } } if (is_jump(last)) { basicblock *target = last->i_target; + while (target->b_iused == 0 && target->b_predecessors == 1) { + target = target->b_next; + } if (target->b_predecessors == 1) { - if (target->b_instr[0].i_loc.lineno == NO_LOCATION.lineno) { - target->b_instr[0].i_loc = prev_location; - } + maybe_propagate_location(target, 0, prev_location); } } } diff --git a/Python/gc.c b/Python/gc.c index 79c7476f4a9..d067a6144b0 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -483,11 +483,12 @@ validate_consistent_old_space(PyGC_Head *head) /* Set all gc_refs = ob_refcnt. After this, gc_refs is > 0 and * PREV_MASK_COLLECTING bit is set for all objects in containers. */ -static void +static Py_ssize_t update_refs(PyGC_Head *containers) { PyGC_Head *next; PyGC_Head *gc = GC_NEXT(containers); + Py_ssize_t candidates = 0; while (gc != containers) { next = GC_NEXT(gc); @@ -519,7 +520,9 @@ update_refs(PyGC_Head *containers) */ _PyObject_ASSERT(op, gc_get_refs(gc) != 0); gc = next; + candidates++; } + return candidates; } /* A traversal callback for subtract_refs. */ @@ -1240,7 +1243,7 @@ flag set but it does not clear it to skip unnecessary iteration. Before the flag is cleared (for example, by using 'clear_unreachable_mask' function or by a call to 'move_legacy_finalizers'), the 'unreachable' list is not a normal list and we can not use most gc_list_* functions for it. */ -static inline void +static inline Py_ssize_t deduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) { validate_list(base, collecting_clear_unreachable_clear); /* Using ob_refcnt and gc_refs, calculate which objects in the @@ -1248,7 +1251,7 @@ deduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) { * refcount greater than 0 when all the references within the * set are taken into account). */ - update_refs(base); // gc_prev is used for gc_refs + Py_ssize_t candidates = update_refs(base); // gc_prev is used for gc_refs subtract_refs(base); /* Leave everything reachable from outside base in base, and move @@ -1289,6 +1292,7 @@ deduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) { move_unreachable(base, unreachable); // gc_prev is pointer again validate_list(base, collecting_clear_unreachable_clear); validate_list(unreachable, collecting_set_unreachable_set); + return candidates; } /* Handle objects that may have resurrected after a call to 'finalize_garbage', moving @@ -1363,8 +1367,10 @@ gc_list_set_space(PyGC_Head *list, int space) static void add_stats(GCState *gcstate, int gen, struct gc_collection_stats *stats) { + gcstate->generation_stats[gen].duration += stats->duration; gcstate->generation_stats[gen].collected += stats->collected; gcstate->generation_stats[gen].uncollectable += stats->uncollectable; + gcstate->generation_stats[gen].candidates += stats->candidates; gcstate->generation_stats[gen].collections += 1; } @@ -1387,7 +1393,6 @@ gc_collect_young(PyThreadState *tstate, validate_spaces(gcstate); gcstate->young.count = 0; gcstate->old[gcstate->visited_space].count++; - add_stats(gcstate, 0, stats); validate_spaces(gcstate); } @@ -1639,7 +1644,7 @@ assess_work_to_do(GCState *gcstate) scale_factor = 2; } intptr_t new_objects = gcstate->young.count; - intptr_t max_heap_fraction = new_objects*3/2; + intptr_t max_heap_fraction = new_objects*2; intptr_t heap_fraction = gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor; if (heap_fraction > max_heap_fraction) { heap_fraction = max_heap_fraction; @@ -1654,11 +1659,15 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats) GC_STAT_ADD(1, collections, 1); GCState *gcstate = &tstate->interp->gc; gcstate->work_to_do += assess_work_to_do(gcstate); + if (gcstate->work_to_do < 0) { + return; + } untrack_tuples(&gcstate->young.head); if (gcstate->phase == GC_PHASE_MARK) { Py_ssize_t objects_marked = mark_at_start(tstate); GC_STAT_ADD(1, objects_transitively_reachable, objects_marked); gcstate->work_to_do -= objects_marked; + stats->candidates += objects_marked; validate_spaces(gcstate); return; } @@ -1696,10 +1705,8 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats) gc_collect_region(tstate, &increment, &survivors, stats); gc_list_merge(&survivors, visited); assert(gc_list_is_empty(&increment)); - gcstate->work_to_do += gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor; gcstate->work_to_do -= increment_size; - add_stats(gcstate, 1, stats); if (gc_list_is_empty(not_visited)) { completed_scavenge(gcstate); } @@ -1734,7 +1741,6 @@ gc_collect_full(PyThreadState *tstate, completed_scavenge(gcstate); _PyGC_ClearAllFreeLists(tstate->interp); validate_spaces(gcstate); - add_stats(gcstate, 2, stats); } /* This is the main function. Read this to understand how the @@ -1754,7 +1760,7 @@ gc_collect_region(PyThreadState *tstate, assert(!_PyErr_Occurred(tstate)); gc_list_init(&unreachable); - deduce_unreachable(from, &unreachable); + stats->candidates = deduce_unreachable(from, &unreachable); validate_consistent_old_space(from); untrack_tuples(from); @@ -1844,10 +1850,12 @@ do_gc_callback(GCState *gcstate, const char *phase, assert(PyList_CheckExact(gcstate->callbacks)); PyObject *info = NULL; if (PyList_GET_SIZE(gcstate->callbacks) != 0) { - info = Py_BuildValue("{sisnsn}", + info = Py_BuildValue("{sisnsnsnsd}", "generation", generation, "collected", stats->collected, - "uncollectable", stats->uncollectable); + "uncollectable", stats->uncollectable, + "candidates", stats->candidates, + "duration", stats->duration); if (info == NULL) { PyErr_FormatUnraisable("Exception ignored while invoking gc callbacks"); return; @@ -2072,6 +2080,7 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason) // Don't start a garbage collection if one is already in progress. return 0; } + gcstate->frame = tstate->current_frame; struct gc_collection_stats stats = { 0 }; if (reason != _Py_GC_REASON_SHUTDOWN) { @@ -2084,6 +2093,8 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason) if (PyDTrace_GC_START_ENABLED()) { PyDTrace_GC_START(generation); } + PyTime_t start, stop; + (void)PyTime_PerfCounterRaw(&start); PyObject *exc = _PyErr_GetRaisedException(tstate); switch(generation) { case 0: @@ -2098,6 +2109,9 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason) default: Py_UNREACHABLE(); } + (void)PyTime_PerfCounterRaw(&stop); + stats.duration = PyTime_AsSecondsDouble(stop - start); + add_stats(gcstate, generation, &stats); if (PyDTrace_GC_DONE_ENABLED()) { PyDTrace_GC_DONE(stats.uncollectable + stats.collected); } @@ -2107,14 +2121,24 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason) _PyErr_SetRaisedException(tstate, exc); GC_STAT_ADD(generation, objects_collected, stats.collected); #ifdef Py_STATS - if (_Py_stats) { + PyStats *s = _PyStats_GET(); + if (s) { GC_STAT_ADD(generation, object_visits, - _Py_stats->object_stats.object_visits); - _Py_stats->object_stats.object_visits = 0; + s->object_stats.object_visits); + s->object_stats.object_visits = 0; } #endif validate_spaces(gcstate); + gcstate->frame = NULL; _Py_atomic_store_int(&gcstate->collecting, 0); + + if (gcstate->debug & _PyGC_DEBUG_STATS) { + PySys_WriteStderr( + "gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n", + stats.collected + stats.uncollectable, stats.uncollectable, stats.duration + ); + } + return stats.uncollectable + stats.collected; } @@ -2219,7 +2243,7 @@ _PyGC_Fini(PyInterpreterState *interp) void _PyGC_Dump(PyGC_Head *g) { - _PyObject_Dump(FROM_GC(g)); + PyUnstable_Object_Dump(FROM_GC(g)); } @@ -2286,21 +2310,11 @@ _Py_ScheduleGC(PyThreadState *tstate) } void -_PyObject_GC_Link(PyObject *op) +_Py_TriggerGC(struct _gc_runtime_state *gcstate) { - PyGC_Head *gc = AS_GC(op); - // gc must be correctly aligned - _PyObject_ASSERT(op, ((uintptr_t)gc & (sizeof(uintptr_t)-1)) == 0); - PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->gc; - gc->_gc_next = 0; - gc->_gc_prev = 0; - gcstate->young.count++; /* number of allocated GC objects */ - gcstate->heap_size++; - if (gcstate->young.count > gcstate->young.threshold && - gcstate->enabled && - gcstate->young.threshold && + if (gcstate->enabled && + gcstate->young.threshold != 0 && !_Py_atomic_load_int_relaxed(&gcstate->collecting) && !_PyErr_Occurred(tstate)) { @@ -2308,6 +2322,17 @@ _PyObject_GC_Link(PyObject *op) } } +void +_PyObject_GC_Link(PyObject *op) +{ + PyGC_Head *gc = AS_GC(op); + // gc must be correctly aligned + _PyObject_ASSERT(op, ((uintptr_t)gc & (sizeof(uintptr_t)-1)) == 0); + gc->_gc_next = 0; + gc->_gc_prev = 0; + +} + void _Py_RunGC(PyThreadState *tstate) { @@ -2414,6 +2439,11 @@ PyObject_GC_Del(void *op) PyGC_Head *g = AS_GC(op); if (_PyObject_GC_IS_TRACKED(op)) { gc_list_remove(g); + GCState *gcstate = get_gc_state(); + if (gcstate->young.count > 0) { + gcstate->young.count--; + } + gcstate->heap_size--; #ifdef Py_DEBUG PyObject *exc = PyErr_GetRaisedException(); if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, @@ -2427,11 +2457,6 @@ PyObject_GC_Del(void *op) PyErr_SetRaisedException(exc); #endif } - GCState *gcstate = get_gc_state(); - if (gcstate->young.count > 0) { - gcstate->young.count--; - } - gcstate->heap_size--; PyObject_Free(((char *)op)-presize); } diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 842aa340154..04b9b8f3f85 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -100,6 +100,7 @@ struct collection_state { int skip_deferred_objects; Py_ssize_t collected; Py_ssize_t uncollectable; + Py_ssize_t candidates; Py_ssize_t long_lived_total; struct worklist unreachable; struct worklist legacy_finalizers; @@ -289,7 +290,7 @@ frame_disable_deferred_refcounting(_PyInterpreterFrame *frame) frame->f_funcobj = PyStackRef_AsStrongReference(frame->f_funcobj); for (_PyStackRef *ref = frame->localsplus; ref < frame->stackpointer; ref++) { - if (!PyStackRef_IsNullOrInt(*ref) && PyStackRef_IsDeferred(*ref)) { + if (!PyStackRef_IsNullOrInt(*ref) && !PyStackRef_RefcountOnObject(*ref)) { *ref = PyStackRef_AsStrongReference(*ref); } } @@ -374,6 +375,19 @@ op_from_block(void *block, void *arg, bool include_frozen) return op; } +// As above but returns untracked and frozen objects as well. +static PyObject * +op_from_block_all_gc(void *block, void *arg) +{ + struct visitor_args *a = arg; + if (block == NULL) { + return NULL; + } + PyObject *op = (PyObject *)((char*)block + a->offset); + assert(PyObject_IS_GC(op)); + return op; +} + static int gc_visit_heaps_lock_held(PyInterpreterState *interp, mi_block_visit_fun *visitor, struct visitor_args *arg) @@ -444,7 +458,7 @@ gc_visit_heaps(PyInterpreterState *interp, mi_block_visit_fun *visitor, static inline void gc_visit_stackref(_PyStackRef stackref) { - if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNullOrInt(stackref)) { + if (!PyStackRef_IsNullOrInt(stackref) && !PyStackRef_RefcountOnObject(stackref)) { PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); if (_PyObject_GC_IS_TRACKED(obj) && !gc_is_frozen(obj)) { gc_add_refs(obj, 1); @@ -675,10 +689,11 @@ gc_mark_span_push(gc_span_stack_t *ss, PyObject **start, PyObject **end) else { ss->capacity *= 2; } - ss->stack = (gc_span_t *)PyMem_Realloc(ss->stack, ss->capacity * sizeof(gc_span_t)); - if (ss->stack == NULL) { + gc_span_t *new_stack = (gc_span_t *)PyMem_Realloc(ss->stack, ss->capacity * sizeof(gc_span_t)); + if (new_stack == NULL) { return -1; } + ss->stack = new_stack; } assert(end > start); ss->stack[ss->size].start = start; @@ -974,15 +989,12 @@ static bool update_refs(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *args) { + struct collection_state *state = (struct collection_state *)args; PyObject *op = op_from_block(block, args, false); if (op == NULL) { return true; } - if (gc_is_alive(op)) { - return true; - } - // Exclude immortal objects from garbage collection if (_Py_IsImmortal(op)) { op->ob_tid = 0; @@ -990,6 +1002,11 @@ update_refs(const mi_heap_t *heap, const mi_heap_area_t *area, gc_clear_unreachable(op); return true; } + // Marked objects count as candidates, immortals don't: + state->candidates++; + if (gc_is_alive(op)) { + return true; + } Py_ssize_t refcount = Py_REFCNT(op); if (_PyObject_HasDeferredRefcount(op)) { @@ -1182,12 +1199,20 @@ static bool scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *args) { - PyObject *op = op_from_block(block, args, false); + PyObject *op = op_from_block_all_gc(block, args); if (op == NULL) { return true; } - struct collection_state *state = (struct collection_state *)args; + // The free-threaded GC cost is proportional to the number of objects in + // the mimalloc GC heap and so we should include the counts for untracked + // and frozen objects as well. This is especially important if many + // tuples have been untracked. + state->long_lived_total++; + if (!_PyObject_GC_IS_TRACKED(op) || gc_is_frozen(op)) { + return true; + } + if (gc_is_unreachable(op)) { // Disable deferred refcounting for unreachable objects so that they // are collected immediately after finalization. @@ -1205,6 +1230,9 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, else { worklist_push(&state->unreachable, op); } + // It is possible this object will be resurrected but + // for now we assume it will be deallocated. + state->long_lived_total--; return true; } @@ -1218,7 +1246,6 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, // object is reachable, restore `ob_tid`; we're done with these objects gc_restore_tid(op); gc_clear_alive(op); - state->long_lived_total++; return true; } @@ -1801,7 +1828,7 @@ _PyGC_VisitStackRef(_PyStackRef *ref, visitproc visit, void *arg) // computing the incoming references, but otherwise treat them like // regular references. assert(!PyStackRef_IsTaggedInt(*ref)); - if (!PyStackRef_IsDeferred(*ref) || + if (PyStackRef_RefcountOnObject(*ref) || (visit != visit_decref && visit != visit_decref_unreachable)) { Py_VISIT(PyStackRef_AsPyObjectBorrow(*ref)); @@ -1887,6 +1914,7 @@ handle_resurrected_objects(struct collection_state *state) _PyObject_ASSERT(op, Py_REFCNT(op) > 1); worklist_remove(&iter); merge_refcount(op, -1); // remove worklist reference + state->long_lived_total++; } } } @@ -1910,7 +1938,8 @@ handle_resurrected_objects(struct collection_state *state) static void invoke_gc_callback(PyThreadState *tstate, const char *phase, int generation, Py_ssize_t collected, - Py_ssize_t uncollectable) + Py_ssize_t uncollectable, Py_ssize_t candidates, + double duration) { assert(!_PyErr_Occurred(tstate)); @@ -1924,10 +1953,12 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, assert(PyList_CheckExact(gcstate->callbacks)); PyObject *info = NULL; if (PyList_GET_SIZE(gcstate->callbacks) != 0) { - info = Py_BuildValue("{sisnsn}", + info = Py_BuildValue("{sisnsnsnsd}", "generation", generation, "collected", collected, - "uncollectable", uncollectable); + "uncollectable", uncollectable, + "candidates", candidates, + "duration", duration); if (info == NULL) { PyErr_FormatUnraisable("Exception ignored while " "invoking gc callbacks"); @@ -2203,7 +2234,19 @@ record_deallocation(PyThreadState *tstate) gc->alloc_count--; if (gc->alloc_count <= -LOCAL_ALLOC_COUNT_THRESHOLD) { GCState *gcstate = &tstate->interp->gc; - _Py_atomic_add_int(&gcstate->young.count, (int)gc->alloc_count); + int count = _Py_atomic_load_int_relaxed(&gcstate->young.count); + int new_count; + do { + if (count == 0) { + break; + } + new_count = count + (int)gc->alloc_count; + if (new_count < 0) { + new_count = 0; + } + } while (!_Py_atomic_compare_exchange_int(&gcstate->young.count, + &count, + new_count)); gc->alloc_count = 0; } } @@ -2284,9 +2327,6 @@ gc_collect_internal(PyInterpreterState *interp, struct collection_state *state, } } - // Record the number of live GC objects - interp->gc.long_lived_total = state->long_lived_total; - // Find weakref callbacks we will honor (but do not call them). find_weakref_callbacks(state); _PyEval_StartTheWorld(interp); @@ -2307,8 +2347,11 @@ gc_collect_internal(PyInterpreterState *interp, struct collection_state *state, if (err == 0) { clear_weakrefs(state); } + // Record the number of live GC objects + interp->gc.long_lived_total = state->long_lived_total; _PyEval_StartTheWorld(interp); + if (err < 0) { cleanup_worklist(&state->unreachable); cleanup_worklist(&state->legacy_finalizers); @@ -2339,7 +2382,6 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) { Py_ssize_t m = 0; /* # objects collected */ Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */ - PyTime_t t1 = 0; /* initialize to prevent a compiler warning */ GCState *gcstate = &tstate->interp->gc; // gc_collect_main() must not be called before _PyGC_Init @@ -2358,30 +2400,32 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) _Py_atomic_store_int(&gcstate->collecting, 0); return 0; } + gcstate->frame = tstate->current_frame; assert(generation >= 0 && generation < NUM_GENERATIONS); #ifdef Py_STATS - if (_Py_stats) { - _Py_stats->object_stats.object_visits = 0; + PyStats *s = _PyStats_GET(); + if (s) { + s->object_stats.object_visits = 0; } #endif GC_STAT_ADD(generation, collections, 1); if (reason != _Py_GC_REASON_SHUTDOWN) { - invoke_gc_callback(tstate, "start", generation, 0, 0); + invoke_gc_callback(tstate, "start", generation, 0, 0, 0, 0.0); } if (gcstate->debug & _PyGC_DEBUG_STATS) { PySys_WriteStderr("gc: collecting generation %d...\n", generation); show_stats_each_generations(gcstate); - // ignore error: don't interrupt the GC if reading the clock fails - (void)PyTime_PerfCounterRaw(&t1); } if (PyDTrace_GC_START_ENABLED()) { PyDTrace_GC_START(generation); } + PyTime_t start, stop; + (void)PyTime_PerfCounterRaw(&start); PyInterpreterState *interp = tstate->interp; @@ -2396,13 +2440,13 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) m = state.collected; n = state.uncollectable; + (void)PyTime_PerfCounterRaw(&stop); + double duration = PyTime_AsSecondsDouble(stop - start); + if (gcstate->debug & _PyGC_DEBUG_STATS) { - PyTime_t t2; - (void)PyTime_PerfCounterRaw(&t2); - double d = PyTime_AsSecondsDouble(t2 - t1); PySys_WriteStderr( "gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n", - n+m, n, d); + n+m, n, duration); } // Clear the current thread's free-list again. @@ -2423,13 +2467,18 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) stats->collections++; stats->collected += m; stats->uncollectable += n; + stats->duration += duration; + stats->candidates += state.candidates; GC_STAT_ADD(generation, objects_collected, m); #ifdef Py_STATS - if (_Py_stats) { - GC_STAT_ADD(generation, object_visits, - _Py_stats->object_stats.object_visits); - _Py_stats->object_stats.object_visits = 0; + { + PyStats *s = _PyStats_GET(); + if (s) { + GC_STAT_ADD(generation, object_visits, + s->object_stats.object_visits); + s->object_stats.object_visits = 0; + } } #endif @@ -2438,10 +2487,11 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) } if (reason != _Py_GC_REASON_SHUTDOWN) { - invoke_gc_callback(tstate, "stop", generation, m, n); + invoke_gc_callback(tstate, "stop", generation, m, n, state.candidates, duration); } assert(!_PyErr_Occurred(tstate)); + gcstate->frame = NULL; _Py_atomic_store_int(&gcstate->collecting, 0); return n + m; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7547eaad125..8d3119e9169 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,18 +8,18 @@ #endif #define TIER_ONE 1 -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP #if !USE_COMPUTED_GOTOS dispatch_opcode: - switch (opcode) + switch (dispatch_code) #endif { -#endif /* Py_TAIL_CALL_INTERP */ +#endif /* _Py_TAIL_CALL_INTERP */ /* BEGIN INSTRUCTIONS */ TARGET(BINARY_OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP; (void)(opcode); #endif @@ -76,13 +76,13 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); } DISPATCH(); } TARGET(BINARY_OP_ADD_FLOAT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_ADD_FLOAT; (void)(opcode); #endif @@ -96,6 +96,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_FLOAT { value = stack_pointer[-1]; @@ -128,19 +130,33 @@ double dres = ((PyFloatObject *)left_o)->ob_fval + ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); if (PyStackRef_IsNull(res)) { - JUMP_TO_LABEL(pop_2_error); + JUMP_TO_LABEL(error); } + l = left; + r = right; + } + // _POP_TOP_FLOAT + { + value = r; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + } + // _POP_TOP_FLOAT + { + value = l; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_ADD_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_ADD_INT; (void)(opcode); #endif @@ -154,6 +170,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -190,17 +208,29 @@ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); JUMP_TO_PREDICTED(BINARY_OP); } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; + } + // _POP_TOP_INT + { + value = r; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP_INT + { + value = l; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_ADD_UNICODE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_ADD_UNICODE; (void)(opcode); #endif @@ -215,6 +245,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_UNICODE { value = stack_pointer[-1]; @@ -246,21 +278,33 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - JUMP_TO_LABEL(pop_2_error); - } res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + JUMP_TO_LABEL(error); + } + l = left; + r = right; + } + // _POP_TOP_UNICODE + { + value = r; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); + } + // _POP_TOP_UNICODE + { + value = l; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_EXTEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_EXTEND; (void)(opcode); #endif @@ -314,17 +358,17 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); res = PyStackRef_FromPyObjectSteal(res_o); } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_INPLACE_ADD_UNICODE; (void)(opcode); #endif @@ -371,7 +415,7 @@ assert(next_instr->op.code == STORE_FAST); next_oparg = next_instr->op.arg; #else - next_oparg = CURRENT_OPERAND0(); + next_oparg = (int)CURRENT_OPERAND0_16(); #endif _PyStackRef *target_local = &GETLOCAL(next_oparg); assert(PyUnicode_CheckExact(left_o)); @@ -386,7 +430,7 @@ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); PyObject *right_o = PyStackRef_AsPyObjectSteal(right); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyUnicode_Append(&temp, right_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -407,7 +451,7 @@ } TARGET(BINARY_OP_MULTIPLY_FLOAT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_MULTIPLY_FLOAT; (void)(opcode); #endif @@ -421,6 +465,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_FLOAT { value = stack_pointer[-1]; @@ -453,19 +499,33 @@ double dres = ((PyFloatObject *)left_o)->ob_fval * ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); if (PyStackRef_IsNull(res)) { - JUMP_TO_LABEL(pop_2_error); + JUMP_TO_LABEL(error); } + l = left; + r = right; + } + // _POP_TOP_FLOAT + { + value = r; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + } + // _POP_TOP_FLOAT + { + value = l; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_MULTIPLY_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_MULTIPLY_INT; (void)(opcode); #endif @@ -479,6 +539,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -515,17 +577,29 @@ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); JUMP_TO_PREDICTED(BINARY_OP); } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; + } + // _POP_TOP_INT + { + value = r; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP_INT + { + value = l; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_SUBSCR_DICT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBSCR_DICT; (void)(opcode); #endif @@ -578,7 +652,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (rc <= 0) { JUMP_TO_LABEL(error); } @@ -586,12 +660,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_SUBSCR_GETITEM) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBSCR_GETITEM; (void)(opcode); #endif @@ -653,7 +727,7 @@ _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; - frame->return_offset = 6 ; + frame->return_offset = 6u ; new_frame = PyStackRef_Wrap(pushed_frame); } // _PUSH_FRAME @@ -661,7 +735,7 @@ assert(tstate->interp->eval_frame == NULL); _PyInterpreterFrame *temp = PyStackRef_Unwrap(new_frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(temp->previous == frame || temp->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); @@ -675,7 +749,7 @@ } TARGET(BINARY_OP_SUBSCR_LIST_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBSCR_LIST_INT; (void)(opcode); #endif @@ -759,13 +833,13 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); } DISPATCH(); } TARGET(BINARY_OP_SUBSCR_LIST_SLICE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBSCR_LIST_SLICE; (void)(opcode); #endif @@ -824,7 +898,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -832,12 +906,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_SUBSCR_STR_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBSCR_STR_INT; (void)(opcode); #endif @@ -892,17 +966,18 @@ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); JUMP_TO_PREDICTED(BINARY_OP); } - Py_UCS4 c = PyUnicode_READ_CHAR(str, index); - if (Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c) { + if (!PyUnicode_IS_COMPACT_ASCII(str)) { UPDATE_MISS_STATS(BINARY_OP); assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); JUMP_TO_PREDICTED(BINARY_OP); } + uint8_t c = PyUnicode_1BYTE_DATA(str)[index]; + assert(c < 128); STAT_INC(BINARY_OP, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(str_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -910,12 +985,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_SUBSCR_TUPLE_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBSCR_TUPLE_INT; (void)(opcode); #endif @@ -976,7 +1051,7 @@ PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); res = PyStackRef_FromPyObjectNew(res_o); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = tuple_st; tuple_st = res; @@ -988,7 +1063,7 @@ } TARGET(BINARY_OP_SUBTRACT_FLOAT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBTRACT_FLOAT; (void)(opcode); #endif @@ -1002,6 +1077,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_FLOAT { value = stack_pointer[-1]; @@ -1034,19 +1111,33 @@ double dres = ((PyFloatObject *)left_o)->ob_fval - ((PyFloatObject *)right_o)->ob_fval; - res = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); + res = PyStackRef_FromPyObjectSteal(PyFloat_FromDouble(dres)); if (PyStackRef_IsNull(res)) { - JUMP_TO_LABEL(pop_2_error); + JUMP_TO_LABEL(error); } + l = left; + r = right; + } + // _POP_TOP_FLOAT + { + value = r; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); + } + // _POP_TOP_FLOAT + { + value = l; + assert(PyFloat_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyFloat_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_OP_SUBTRACT_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_OP_SUBTRACT_INT; (void)(opcode); #endif @@ -1060,6 +1151,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -1096,17 +1189,29 @@ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); JUMP_TO_PREDICTED(BINARY_OP); } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); + l = left; + r = right; + } + // _POP_TOP_INT + { + value = r; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP_INT + { + value = l; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BINARY_SLICE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BINARY_SLICE; (void)(opcode); #endif @@ -1138,7 +1243,7 @@ } else { stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); Py_DECREF(slice); @@ -1146,7 +1251,7 @@ stack_pointer += 2; } stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(container); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1157,12 +1262,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_INTERPOLATION) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_INTERPOLATION; (void)(opcode); #endif @@ -1191,7 +1296,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); if (oparg & 1) { stack_pointer += -(oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(format[0]); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1200,12 +1305,12 @@ stack_pointer += -(oparg & 1); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(str); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1215,12 +1320,12 @@ interpolation = PyStackRef_FromPyObjectSteal(interpolation_o); stack_pointer[0] = interpolation; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_LIST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_LIST; (void)(opcode); #endif @@ -1239,12 +1344,12 @@ list = PyStackRef_FromPyObjectStealMortal(list_o); stack_pointer[-oparg] = list; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_MAP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_MAP; (void)(opcode); #endif @@ -1254,49 +1359,23 @@ _PyStackRef *values; _PyStackRef map; values = &stack_pointer[-oparg*2]; - STACKREFS_TO_PYOBJECTS(values, oparg*2, values_o); - if (CONVERSION_FAILED(values_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg*2; --_i >= 0;) { - tmp = values[_i]; - values[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg*2; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *map_o = _PyDict_FromItems( - values_o, 2, - values_o+1, 2, - oparg); + PyObject *map_o = _Py_BuildMap_StackRefSteal(values, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(values_o); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg*2; --_i >= 0;) { - tmp = values[_i]; - values[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg*2; - assert(WITHIN_STACK_BOUNDS()); if (map_o == NULL) { + stack_pointer += -oparg*2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } map = PyStackRef_FromPyObjectStealMortal(map_o); - stack_pointer[0] = map; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-oparg*2] = map; + stack_pointer += 1 - oparg*2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_SET) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_SET; (void)(opcode); #endif @@ -1319,7 +1398,7 @@ } stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } int err = 0; @@ -1339,7 +1418,7 @@ } if (err) { stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); Py_DECREF(set_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1348,12 +1427,12 @@ set = PyStackRef_FromPyObjectStealMortal(set_o); stack_pointer[-oparg] = set; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_SLICE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_SLICE; (void)(opcode); #endif @@ -1376,19 +1455,19 @@ } stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (slice_o == NULL) { JUMP_TO_LABEL(error); } slice = PyStackRef_FromPyObjectStealMortal(slice_o); stack_pointer[0] = slice; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_STRING) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_STRING; (void)(opcode); #endif @@ -1398,44 +1477,23 @@ _PyStackRef *pieces; _PyStackRef str; pieces = &stack_pointer[-oparg]; - STACKREFS_TO_PYOBJECTS(pieces, oparg, pieces_o); - if (CONVERSION_FAILED(pieces_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = pieces[_i]; - pieces[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } - PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); - STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = pieces[_i]; - pieces[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } + PyObject *str_o = _Py_BuildString_StackRefSteal(pieces, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); if (str_o == NULL) { + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } str = PyStackRef_FromPyObjectSteal(str_o); - stack_pointer[0] = str; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-oparg] = str; + stack_pointer += 1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_TEMPLATE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_TEMPLATE; (void)(opcode); #endif @@ -1453,12 +1511,12 @@ PyObject *template_o = _PyTemplate_Build(strings_o, interpolations_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(interpolations); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(strings); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1468,12 +1526,12 @@ template = PyStackRef_FromPyObjectSteal(template_o); stack_pointer[0] = template; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(BUILD_TUPLE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = BUILD_TUPLE; (void)(opcode); #endif @@ -1490,12 +1548,12 @@ tup = PyStackRef_FromPyObjectStealMortal(tup_o); stack_pointer[-oparg] = tup; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CACHE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CACHE; (void)(opcode); #endif @@ -1508,7 +1566,7 @@ } TARGET(CALL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL; (void)(opcode); #endif @@ -1533,7 +1591,7 @@ if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); - _Py_Specialize_Call(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null)); + _Py_Specialize_Call(callable, self_or_null, next_instr, oparg + !PyStackRef_IsNull(self_or_null)); stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } @@ -1583,11 +1641,11 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (new_frame == NULL) { JUMP_TO_LABEL(error); } - frame->return_offset = 4 ; + frame->return_offset = 4u ; DISPATCH_INLINED(new_frame); } STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); @@ -1611,7 +1669,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } stack_pointer[-2 - oparg] = callable; @@ -1664,7 +1722,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -1674,7 +1732,7 @@ { stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -1686,7 +1744,7 @@ } TARGET(CALL_ALLOC_AND_ENTER_INIT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_ALLOC_AND_ENTER_INIT; (void)(opcode); #endif @@ -1778,7 +1836,7 @@ tstate, init, NULL, args-1, oparg+1, NULL, shim); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FrameClearAndPop(tstate, shim); @@ -1807,7 +1865,7 @@ } TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_BOUND_METHOD_EXACT_ARGS; (void)(opcode); #endif @@ -1936,7 +1994,7 @@ assert(tstate->interp->eval_frame == NULL); _PyInterpreterFrame *temp = PyStackRef_Unwrap(new_frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(temp->previous == frame || temp->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); @@ -1950,7 +2008,7 @@ } TARGET(CALL_BOUND_METHOD_GENERAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_BOUND_METHOD_GENERAL; (void)(opcode); #endif @@ -2046,7 +2104,7 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { JUMP_TO_LABEL(error); } @@ -2078,7 +2136,7 @@ } TARGET(CALL_BUILTIN_CLASS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_BUILTIN_CLASS; (void)(opcode); #endif @@ -2118,60 +2176,24 @@ JUMP_TO_PREDICTED(CALL); } STAT_INC(CALL, hit); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + PyObject *res_o = _Py_CallBuiltinClass_StackRefSteal( + callable, + arguments, + total_args); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2183,7 +2205,7 @@ } TARGET(CALL_BUILTIN_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_BUILTIN_FAST; (void)(opcode); #endif @@ -2204,13 +2226,13 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyCFunction_CheckExact(callable_o)) { UPDATE_MISS_STATS(CALL); assert(_PyOpcode_Deopt[opcode] == (CALL)); @@ -2222,65 +2244,25 @@ JUMP_TO_PREDICTED(CALL); } STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = _PyCFunctionFast_CAST(cfunc)( - PyCFunction_GET_SELF(callable_o), - args_o, - total_args); + PyObject *res_o = _Py_BuiltinCallFast_StackRefSteal( + callable, + arguments, + total_args + ); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2292,7 +2274,7 @@ } TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_BUILTIN_FAST_WITH_KEYWORDS; (void)(opcode); #endif @@ -2313,13 +2295,13 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); if (!PyCFunction_CheckExact(callable_o)) { UPDATE_MISS_STATS(CALL); assert(_PyOpcode_Deopt[opcode] == (CALL)); @@ -2332,64 +2314,20 @@ } STAT_INC(CALL, hit); _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o)); + PyObject *res_o = _Py_BuiltinCallFastWithKeywords_StackRefSteal(callable, arguments, total_args); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2401,7 +2339,7 @@ } TARGET(CALL_BUILTIN_O) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_BUILTIN_O; (void)(opcode); #endif @@ -2415,6 +2353,9 @@ _PyStackRef self_or_null; _PyStackRef *args; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_BUILTIN_O @@ -2456,24 +2397,35 @@ stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { JUMP_TO_LABEL(error); } + a = arg; + c = callable; res = PyStackRef_FromPyObjectSteal(res_o); } + // _POP_TOP + { + value = c; + stack_pointer[-2 - oparg] = res; + stack_pointer[-1 - oparg] = a; + stack_pointer += -oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = a; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2485,7 +2437,7 @@ } TARGET(CALL_FUNCTION_EX) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_FUNCTION_EX; (void)(opcode); #endif @@ -2592,18 +2544,18 @@ int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( tstate, func_st, locals, nargs, callargs, kwargs, frame); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (new_frame == NULL) { JUMP_TO_LABEL(error); } - assert( 1 == 1); + assert( 1u == 1); frame->return_offset = 1; DISPATCH_INLINED(new_frame); } @@ -2617,17 +2569,17 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(kwargs_st); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callargs_st); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(func_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2640,7 +2592,7 @@ { stack_pointer[0] = result; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2652,7 +2604,7 @@ } TARGET(CALL_INTRINSIC_1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_INTRINSIC_1; (void)(opcode); #endif @@ -2667,7 +2619,7 @@ PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2677,12 +2629,12 @@ res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CALL_INTRINSIC_2) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_INTRINSIC_2; (void)(opcode); #endif @@ -2709,19 +2661,19 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CALL_ISINSTANCE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_ISINSTANCE; (void)(opcode); #endif @@ -2773,17 +2725,17 @@ } (void)null; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(cls); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(instance); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callable); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -2792,12 +2744,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CALL_KW) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_KW; (void)(opcode); #endif @@ -2876,15 +2828,15 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); if (new_frame == NULL) { JUMP_TO_LABEL(error); } - assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); - frame->return_offset = 4 ; + assert( 4u == 1 + INLINE_CACHE_ENTRIES_CALL_KW); + frame->return_offset = 4u ; DISPATCH_INLINED(new_frame); } STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); @@ -2911,7 +2863,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } stack_pointer[-3 - oparg] = callable; @@ -2966,7 +2918,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -2974,12 +2926,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CALL_KW_BOUND_METHOD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_KW_BOUND_METHOD; (void)(opcode); #endif @@ -3072,12 +3024,12 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { JUMP_TO_LABEL(error); } @@ -3109,7 +3061,7 @@ } TARGET(CALL_KW_NON_PY) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_KW_NON_PY; (void)(opcode); #endif @@ -3150,81 +3102,31 @@ #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = kwnames; - kwnames = PyStackRef_NULL; - stack_pointer[-1] = kwnames; - PyStackRef_CLOSE(tmp); - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-2 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-3 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( - callable_o, args_o, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames_o); + PyObject *res_o = _Py_VectorCall_StackRefSteal( + callable, + arguments, + total_args, + kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -3 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-3 - oparg] = res; + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3236,7 +3138,7 @@ } TARGET(CALL_KW_PY) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_KW_PY; (void)(opcode); #endif @@ -3309,12 +3211,12 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { JUMP_TO_LABEL(error); } @@ -3346,7 +3248,7 @@ } TARGET(CALL_LEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_LEN; (void)(opcode); #endif @@ -3360,6 +3262,9 @@ _PyStackRef callable; _PyStackRef arg; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _GUARD_NOS_NULL @@ -3385,7 +3290,6 @@ // _CALL_LEN { arg = stack_pointer[-1]; - (void)null; STAT_INC(CALL, hit); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3399,26 +3303,35 @@ if (res_o == NULL) { JUMP_TO_LABEL(error); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); + a = arg; + c = callable; res = PyStackRef_FromPyObjectSteal(res_o); } - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + // _POP_TOP + { + value = c; + stack_pointer[-3] = res; + stack_pointer[-2] = a; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = a; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } DISPATCH(); } TARGET(CALL_LIST_APPEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_LIST_APPEND; (void)(opcode); #endif @@ -3432,6 +3345,9 @@ _PyStackRef nos; _PyStackRef self; _PyStackRef arg; + _PyStackRef c; + _PyStackRef s; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _GUARD_CALLABLE_LIST_APPEND @@ -3470,11 +3386,6 @@ self = nos; assert(oparg == 1); PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); - if (!PyList_CheckExact(self_o)) { - UPDATE_MISS_STATS(CALL); - assert(_PyOpcode_Deopt[opcode] == (CALL)); - JUMP_TO_PREDICTED(CALL); - } if (!LOCK_OBJECT(self_o)) { UPDATE_MISS_STATS(CALL); assert(_PyOpcode_Deopt[opcode] == (CALL)); @@ -3483,30 +3394,41 @@ STAT_INC(CALL, hit); int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); UNLOCK_OBJECT(self_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { JUMP_TO_LABEL(error); } + c = callable; + s = self; #if TIER_ONE assert(next_instr->op.code == POP_TOP); SKIP_OVER(1); #endif } + // _POP_TOP + { + value = s; + stack_pointer[-3] = c; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = c; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } DISPATCH(); } TARGET(CALL_METHOD_DESCRIPTOR_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_METHOD_DESCRIPTOR_FAST; (void)(opcode); #endif @@ -3559,63 +3481,27 @@ JUMP_TO_PREDICTED(CALL); } STAT_INC(CALL, hit); - int nargs = total_args - 1; - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth); - PyObject *res_o = cfunc(self, (args_o + 1), nargs); + PyObject *res_o = _PyCallMethodDescriptorFast_StackRefSteal( + callable, + meth, + self, + arguments, + total_args + ); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3627,7 +3513,7 @@ } TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS; (void)(opcode); #endif @@ -3681,64 +3567,27 @@ JUMP_TO_PREDICTED(CALL); } STAT_INC(CALL, hit); - int nargs = total_args - 1; - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(meth->ml_meth); - PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); + PyObject *res_o = _PyCallMethodDescriptorFastWithKeywords_StackRefSteal( + callable, + meth, + self, + arguments, + total_args + ); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3750,7 +3599,7 @@ } TARGET(CALL_METHOD_DESCRIPTOR_NOARGS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_METHOD_DESCRIPTOR_NOARGS; (void)(opcode); #endif @@ -3818,7 +3667,7 @@ PyStackRef_CLOSE(self_stackref); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callable); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3831,7 +3680,7 @@ { stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3843,7 +3692,7 @@ } TARGET(CALL_METHOD_DESCRIPTOR_O) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_METHOD_DESCRIPTOR_O; (void)(opcode); #endif @@ -3927,7 +3776,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -3937,7 +3786,7 @@ { stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3949,7 +3798,7 @@ } TARGET(CALL_NON_PY_GENERAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_NON_PY_GENERAL; (void)(opcode); #endif @@ -3988,71 +3837,31 @@ #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; _PyStackRef *arguments = args; if (!PyStackRef_IsNull(self_or_null)) { arguments--; total_args++; } - STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - JUMP_TO_LABEL(error); - } _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( - callable_o, args_o, - total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - NULL); + PyObject *res_o = _Py_VectorCall_StackRefSteal( + callable, + arguments, + total_args, + PyStackRef_NULL); stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); if (res_o == NULL) { + stack_pointer += -2 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -4064,7 +3873,7 @@ } TARGET(CALL_PY_EXACT_ARGS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_PY_EXACT_ARGS; (void)(opcode); #endif @@ -4163,7 +3972,7 @@ assert(tstate->interp->eval_frame == NULL); _PyInterpreterFrame *temp = PyStackRef_Unwrap(new_frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(temp->previous == frame || temp->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); @@ -4177,7 +3986,7 @@ } TARGET(CALL_PY_GENERAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_PY_GENERAL; (void)(opcode); #endif @@ -4245,7 +4054,7 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (temp == NULL) { JUMP_TO_LABEL(error); } @@ -4277,7 +4086,7 @@ } TARGET(CALL_STR_1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_STR_1; (void)(opcode); #endif @@ -4291,6 +4100,8 @@ _PyStackRef callable; _PyStackRef arg; _PyStackRef res; + _PyStackRef a; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _GUARD_NOS_NULL @@ -4321,23 +4132,24 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Str(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); - (void)callable; - (void)null; - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { JUMP_TO_LABEL(error); } + a = arg; res = PyStackRef_FromPyObjectSteal(res_o); } + // _POP_TOP + { + value = a; + stack_pointer[-3] = res; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -4349,7 +4161,7 @@ } TARGET(CALL_TUPLE_1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_TUPLE_1; (void)(opcode); #endif @@ -4363,6 +4175,8 @@ _PyStackRef callable; _PyStackRef arg; _PyStackRef res; + _PyStackRef a; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _GUARD_NOS_NULL @@ -4393,23 +4207,24 @@ _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PySequence_Tuple(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); - (void)callable; - (void)null; - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); if (res_o == NULL) { JUMP_TO_LABEL(error); } + a = arg; res = PyStackRef_FromPyObjectSteal(res_o); } + // _POP_TOP + { + value = a; + stack_pointer[-3] = res; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } // _CHECK_PERIODIC_AT_END { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -4421,7 +4236,7 @@ } TARGET(CALL_TYPE_1) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CALL_TYPE_1; (void)(opcode); #endif @@ -4467,7 +4282,7 @@ res = PyStackRef_FromPyObjectNew(Py_TYPE(arg_o)); stack_pointer[-3] = res; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(arg); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -4476,7 +4291,7 @@ } TARGET(CHECK_EG_MATCH) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CHECK_EG_MATCH; (void)(opcode); #endif @@ -4506,7 +4321,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } PyObject *match_o = NULL; @@ -4524,7 +4339,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { JUMP_TO_LABEL(error); } @@ -4542,12 +4357,12 @@ stack_pointer[0] = rest; stack_pointer[1] = match; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CHECK_EXC_MATCH) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CHECK_EXC_MATCH; (void)(opcode); #endif @@ -4572,19 +4387,19 @@ int res = PyErr_GivenExceptionMatches(left_o, right_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(right); stack_pointer = _PyFrame_GetStackPointer(frame); b = res ? PyStackRef_True : PyStackRef_False; stack_pointer[0] = b; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CLEANUP_THROW) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CLEANUP_THROW; (void)(opcode); #endif @@ -4602,7 +4417,7 @@ last_sent_val = stack_pointer[-2]; sub_iter = stack_pointer[-3]; PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); - #if !Py_TAIL_CALL_INTERP + #if !_Py_TAIL_CALL_INTERP assert(throwflag); #endif assert(exc_value && PyExceptionInstance_Check(exc_value)); @@ -4626,7 +4441,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); none = PyStackRef_None; } else { @@ -4638,12 +4453,12 @@ stack_pointer[0] = none; stack_pointer[1] = value; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(COMPARE_OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = COMPARE_OP; (void)(opcode); #endif @@ -4691,7 +4506,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -4711,12 +4526,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(COMPARE_OP_FLOAT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = COMPARE_OP_FLOAT; (void)(opcode); #endif @@ -4766,12 +4581,12 @@ } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(COMPARE_OP_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = COMPARE_OP_INT; (void)(opcode); #endif @@ -4785,6 +4600,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -4819,18 +4636,30 @@ Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left_o); Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); int sign_ish = COMPARISON_BIT(ileft, iright); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + l = left; + r = right; res = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; } + // _POP_TOP_INT + { + value = r; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP_INT + { + value = l; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(COMPARE_OP_STR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = COMPARE_OP_STR; (void)(opcode); #endif @@ -4884,12 +4713,12 @@ } stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CONTAINS_OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CONTAINS_OP; (void)(opcode); #endif @@ -4936,7 +4765,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { JUMP_TO_LABEL(error); } @@ -4944,12 +4773,12 @@ } stack_pointer[0] = b; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CONTAINS_OP_DICT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CONTAINS_OP_DICT; (void)(opcode); #endif @@ -4994,7 +4823,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { JUMP_TO_LABEL(error); } @@ -5002,12 +4831,12 @@ } stack_pointer[0] = b; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CONTAINS_OP_SET) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CONTAINS_OP_SET; (void)(opcode); #endif @@ -5052,7 +4881,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res < 0) { JUMP_TO_LABEL(error); } @@ -5060,12 +4889,12 @@ } stack_pointer[0] = b; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(CONVERT_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = CONVERT_VALUE; (void)(opcode); #endif @@ -5082,7 +4911,7 @@ PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5092,12 +4921,12 @@ result = PyStackRef_FromPyObjectSteal(result_o); stack_pointer[0] = result; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(COPY) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = COPY; (void)(opcode); #endif @@ -5110,12 +4939,12 @@ top = PyStackRef_DUP(bottom); stack_pointer[0] = top; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = COPY_FREE_VARS; (void)(opcode); #endif @@ -5136,7 +4965,7 @@ } TARGET(DELETE_ATTR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DELETE_ATTR; (void)(opcode); #endif @@ -5150,7 +4979,7 @@ int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5161,7 +4990,7 @@ } TARGET(DELETE_DEREF) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DELETE_DEREF; (void)(opcode); #endif @@ -5183,7 +5012,7 @@ } TARGET(DELETE_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DELETE_FAST; (void)(opcode); #endif @@ -5209,7 +5038,7 @@ } TARGET(DELETE_GLOBAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DELETE_GLOBAL; (void)(opcode); #endif @@ -5234,7 +5063,7 @@ } TARGET(DELETE_NAME) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DELETE_NAME; (void)(opcode); #endif @@ -5266,7 +5095,7 @@ } TARGET(DELETE_SUBSCR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DELETE_SUBSCR; (void)(opcode); #endif @@ -5290,7 +5119,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { JUMP_TO_LABEL(error); } @@ -5298,7 +5127,7 @@ } TARGET(DICT_MERGE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DICT_MERGE; (void)(opcode); #endif @@ -5322,14 +5151,14 @@ _PyEval_FormatKwargsError(tstate, callable_o, update_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_LABEL(error); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5337,7 +5166,7 @@ } TARGET(DICT_UPDATE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = DICT_UPDATE; (void)(opcode); #endif @@ -5365,14 +5194,14 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_LABEL(error); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(update); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5380,7 +5209,7 @@ } TARGET(END_ASYNC_FOR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = END_ASYNC_FOR; (void)(opcode); #endif @@ -5412,7 +5241,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); } else { Py_INCREF(exc); @@ -5425,7 +5254,7 @@ } TARGET(END_FOR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = END_FOR; (void)(opcode); #endif @@ -5434,7 +5263,7 @@ _PyStackRef value; value = stack_pointer[-1]; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5442,7 +5271,7 @@ } TARGET(END_SEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = END_SEND; (void)(opcode); #endif @@ -5457,7 +5286,7 @@ val = value; stack_pointer[-2] = val; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(receiver); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5465,7 +5294,7 @@ } TARGET(ENTER_EXECUTOR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = ENTER_EXECUTOR; (void)(opcode); #endif @@ -5476,6 +5305,10 @@ INSTRUCTION_STATS(ENTER_EXECUTOR); opcode = ENTER_EXECUTOR; #ifdef _Py_TIER2 + if (IS_JIT_TRACING()) { + next_instr = this_instr; + JUMP_TO_LABEL(stop_tracing); + } PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; assert(executor->vm_data.index == INSTR_OFFSET() - 1); @@ -5497,11 +5330,10 @@ #else Py_FatalError("ENTER_EXECUTOR is not supported in this build"); #endif /* _Py_TIER2 */ - DISPATCH(); } TARGET(EXIT_INIT_CHECK) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = EXIT_INIT_CHECK; (void)(opcode); #endif @@ -5519,12 +5351,12 @@ JUMP_TO_LABEL(error); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(EXTENDED_ARG) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = EXTENDED_ARG; (void)(opcode); #endif @@ -5540,7 +5372,7 @@ } TARGET(FORMAT_SIMPLE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FORMAT_SIMPLE; (void)(opcode); #endif @@ -5556,7 +5388,7 @@ PyObject *res_o = PyObject_Format(value_o, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5571,12 +5403,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(FORMAT_WITH_SPEC) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FORMAT_WITH_SPEC; (void)(opcode); #endif @@ -5600,19 +5432,19 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(FOR_ITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FOR_ITER; (void)(opcode); #endif @@ -5661,12 +5493,12 @@ stack_pointer[-1] = null_or_index; stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(FOR_ITER_GEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FOR_ITER_GEN; (void)(opcode); #endif @@ -5716,7 +5548,7 @@ gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; pushed_frame->previous = frame; - frame->return_offset = (uint16_t)( 2 + oparg); + frame->return_offset = (uint16_t)( 2u + oparg); gen_frame = PyStackRef_Wrap(pushed_frame); } // _PUSH_FRAME @@ -5737,7 +5569,7 @@ } TARGET(FOR_ITER_LIST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FOR_ITER_LIST; (void)(opcode); #endif @@ -5816,12 +5648,12 @@ stack_pointer[-1] = null_or_index; stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(FOR_ITER_RANGE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FOR_ITER_RANGE; (void)(opcode); #endif @@ -5883,12 +5715,12 @@ } stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(FOR_ITER_TUPLE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = FOR_ITER_TUPLE; (void)(opcode); #endif @@ -5939,12 +5771,12 @@ stack_pointer[-1] = null_or_index; stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(GET_AITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = GET_AITER; (void)(opcode); #endif @@ -5969,7 +5801,7 @@ type->tp_name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(obj); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5979,7 +5811,7 @@ iter_o = (*getter)(obj_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(obj); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6000,12 +5832,12 @@ iter = PyStackRef_FromPyObjectSteal(iter_o); stack_pointer[0] = iter; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(GET_ANEXT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = GET_ANEXT; (void)(opcode); #endif @@ -6024,12 +5856,12 @@ awaitable = PyStackRef_FromPyObjectSteal(awaitable_o); stack_pointer[0] = awaitable; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(GET_AWAITABLE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = GET_AWAITABLE; (void)(opcode); #endif @@ -6043,7 +5875,7 @@ PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6053,12 +5885,12 @@ iter = PyStackRef_FromPyObjectSteal(iter_o); stack_pointer[0] = iter; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(GET_ITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = GET_ITER; (void)(opcode); #endif @@ -6085,7 +5917,7 @@ PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6099,12 +5931,12 @@ stack_pointer[-1] = iter; stack_pointer[0] = index_or_null; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(GET_LEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = GET_LEN; (void)(opcode); #endif @@ -6127,12 +5959,12 @@ len = PyStackRef_FromPyObjectSteal(len_o); stack_pointer[0] = len; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(GET_YIELD_FROM_ITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = GET_YIELD_FROM_ITER; (void)(opcode); #endif @@ -6177,7 +6009,7 @@ } TARGET(IMPORT_FROM) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = IMPORT_FROM; (void)(opcode); #endif @@ -6197,12 +6029,12 @@ res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(IMPORT_NAME) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = IMPORT_NAME; (void)(opcode); #endif @@ -6229,19 +6061,19 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_CALL; (void)(opcode); #endif @@ -6330,11 +6162,11 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (new_frame == NULL) { JUMP_TO_LABEL(error); } - frame->return_offset = 4 ; + frame->return_offset = 4u ; DISPATCH_INLINED(new_frame); } STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); @@ -6356,7 +6188,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } _PyFrame_SetStackPointer(frame, stack_pointer); @@ -6407,7 +6239,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -6417,7 +6249,7 @@ { stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6429,7 +6261,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_CALL_FUNCTION_EX; (void)(opcode); #endif @@ -6536,18 +6368,18 @@ int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( tstate, func_st, locals, nargs, callargs, kwargs, frame); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (new_frame == NULL) { JUMP_TO_LABEL(error); } - assert( 1 == 1); + assert( 1u == 1); frame->return_offset = 1; DISPATCH_INLINED(new_frame); } @@ -6561,17 +6393,17 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(kwargs_st); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(callargs_st); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(func_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6584,7 +6416,7 @@ { stack_pointer[0] = result; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6596,7 +6428,7 @@ } TARGET(INSTRUMENTED_CALL_KW) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_CALL_KW; (void)(opcode); #endif @@ -6683,15 +6515,15 @@ ); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(kwnames); stack_pointer = _PyFrame_GetStackPointer(frame); if (new_frame == NULL) { JUMP_TO_LABEL(error); } - assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); - frame->return_offset = 4 ; + assert( 4u == 1 + INLINE_CACHE_ENTRIES_CALL_KW); + frame->return_offset = 4u ; DISPATCH_INLINED(new_frame); } STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); @@ -6716,7 +6548,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } _PyFrame_SetStackPointer(frame, stack_pointer); @@ -6769,7 +6601,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } @@ -6777,12 +6609,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_END_ASYNC_FOR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_END_ASYNC_FOR; (void)(opcode); #endif @@ -6821,7 +6653,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); } else { Py_INCREF(exc); @@ -6835,7 +6667,7 @@ } TARGET(INSTRUMENTED_END_FOR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_END_FOR; (void)(opcode); #endif @@ -6856,7 +6688,7 @@ } } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6864,7 +6696,7 @@ } TARGET(INSTRUMENTED_END_SEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_END_SEND; (void)(opcode); #endif @@ -6890,7 +6722,7 @@ val = value; stack_pointer[-2] = val; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(receiver); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -6898,7 +6730,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_FOR_ITER; (void)(opcode); #endif @@ -6929,12 +6761,12 @@ stack_pointer[-1] = null_or_index; stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_INSTRUCTION; (void)(opcode); #endif @@ -6961,7 +6793,7 @@ } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_JUMP_BACKWARD; (void)(opcode); #endif @@ -6988,7 +6820,7 @@ } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_JUMP_FORWARD; (void)(opcode); #endif @@ -7002,7 +6834,7 @@ } TARGET(INSTRUMENTED_LINE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_LINE; (void)(opcode); #endif @@ -7042,7 +6874,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_LOAD_SUPER_ATTR; (void)(opcode); #endif @@ -7089,7 +6921,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } } @@ -7134,7 +6966,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (super == NULL) { JUMP_TO_LABEL(error); } @@ -7157,12 +6989,12 @@ } stack_pointer[0] = attr; stack_pointer += 1 + (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_NOT_TAKEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_NOT_TAKEN; (void)(opcode); #endif @@ -7178,7 +7010,7 @@ } TARGET(INSTRUMENTED_POP_ITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_POP_ITER; (void)(opcode); #endif @@ -7195,7 +7027,7 @@ (void)index_or_null; INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iter); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -7203,7 +7035,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_POP_JUMP_IF_FALSE; (void)(opcode); #endif @@ -7222,12 +7054,12 @@ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_POP_JUMP_IF_NONE; (void)(opcode); #endif @@ -7246,19 +7078,19 @@ } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += 1; } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_POP_JUMP_IF_NOT_NONE; (void)(opcode); #endif @@ -7274,7 +7106,7 @@ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); if (jump) { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -7287,7 +7119,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_POP_JUMP_IF_TRUE; (void)(opcode); #endif @@ -7306,12 +7138,12 @@ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_RESUME) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_RESUME; (void)(opcode); #endif @@ -7378,7 +7210,7 @@ { _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( - tstate, oparg > 0, frame, this_instr); + tstate, oparg == 0 ? PY_MONITORING_EVENT_PY_START : PY_MONITORING_EVENT_PY_RESUME, frame, this_instr); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { JUMP_TO_LABEL(error); @@ -7391,7 +7223,7 @@ } TARGET(INSTRUMENTED_RETURN_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_RETURN_VALUE; (void)(opcode); #endif @@ -7421,7 +7253,7 @@ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(STACK_LEVEL() == 0); _Py_LeaveRecursiveCallPy(tstate); @@ -7435,12 +7267,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INSTRUMENTED_YIELD_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INSTRUMENTED_YIELD_VALUE; (void)(opcode); #endif @@ -7479,7 +7311,7 @@ gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; @@ -7503,12 +7335,12 @@ } stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(INTERPRETER_EXIT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = INTERPRETER_EXIT; (void)(opcode); #endif @@ -7522,7 +7354,7 @@ tstate->current_frame = frame->previous; assert(!_PyErr_Occurred(tstate)); PyObject *result = PyStackRef_AsPyObjectSteal(retval); - #if !Py_TAIL_CALL_INTERP + #if !_Py_TAIL_CALL_INTERP assert(frame == &entry.frame); #endif #ifdef _Py_TIER2 @@ -7531,7 +7363,7 @@ if (!PyStackRef_IsNull(executor)) { tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(executor); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -7543,7 +7375,7 @@ } TARGET(IS_OP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = IS_OP; (void)(opcode); #endif @@ -7567,16 +7399,16 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); b = res ? PyStackRef_True : PyStackRef_False; stack_pointer[0] = b; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(JUMP_BACKWARD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = JUMP_BACKWARD; (void)(opcode); #endif @@ -7591,7 +7423,8 @@ { #if ENABLE_SPECIALIZATION if (this_instr->op.code == JUMP_BACKWARD) { - this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; + uint8_t desired = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; + FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, desired); next_instr = this_instr; DISPATCH_SAME_OPARG(); } @@ -7615,7 +7448,7 @@ } TARGET(JUMP_BACKWARD_JIT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = JUMP_BACKWARD_JIT; (void)(opcode); #endif @@ -7644,30 +7477,20 @@ { #ifdef _Py_TIER2 _Py_BackoffCounter counter = this_instr[1].counter; - if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) { - _Py_CODEUNIT *start = this_instr; + if (!IS_JIT_TRACING() && backoff_counter_triggers(counter) && + this_instr->op.code == JUMP_BACKWARD_JIT && + next_instr->op.code != ENTER_EXECUTOR) { + _Py_CODEUNIT *insert_exec_at = this_instr; while (oparg > 255) { oparg >>= 8; - start--; + insert_exec_at--; } - _PyExecutorObject *executor; - _PyFrame_SetStackPointer(frame, stack_pointer); - int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (optimized <= 0) { - this_instr[1].counter = restart_backoff_counter(counter); - if (optimized < 0) { - JUMP_TO_LABEL(error); - } + int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg); + if (succ) { + ENTER_TRACING(); } else { - _PyFrame_SetStackPointer(frame, stack_pointer); - this_instr[1].counter = initial_jump_backoff_counter(); - stack_pointer = _PyFrame_GetStackPointer(frame); - assert(tstate->current_executor == NULL); - assert(executor != tstate->interp->cold_executor); - tstate->jit_exit = NULL; - TIER1_TO_TIER2(executor); + this_instr[1].counter = restart_backoff_counter(counter); } } else { @@ -7679,7 +7502,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = JUMP_BACKWARD_NO_INTERRUPT; (void)(opcode); #endif @@ -7692,7 +7515,7 @@ } TARGET(JUMP_BACKWARD_NO_JIT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = JUMP_BACKWARD_NO_JIT; (void)(opcode); #endif @@ -7719,7 +7542,7 @@ } TARGET(JUMP_FORWARD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = JUMP_FORWARD; (void)(opcode); #endif @@ -7731,7 +7554,7 @@ } TARGET(LIST_APPEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LIST_APPEND; (void)(opcode); #endif @@ -7748,12 +7571,12 @@ JUMP_TO_LABEL(pop_1_error); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LIST_EXTEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LIST_EXTEND; (void)(opcode); #endif @@ -7784,7 +7607,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -7792,7 +7615,7 @@ } assert(Py_IsNone(none_val)); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -7800,7 +7623,7 @@ } TARGET(LOAD_ATTR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR; (void)(opcode); #endif @@ -7811,7 +7634,7 @@ _Py_CODEUNIT* const this_instr = next_instr - 10; (void)this_instr; _PyStackRef owner; - _PyStackRef *attr; + _PyStackRef attr; _PyStackRef *self_or_null; // _SPECIALIZE_LOAD_ATTR { @@ -7834,28 +7657,30 @@ /* Skip 8 cache entries */ // _LOAD_ATTR { - attr = &stack_pointer[-1]; self_or_null = &stack_pointer[0]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { - *attr = PyStackRef_NULL; + _PyCStackRef method; _PyFrame_SetStackPointer(frame, stack_pointer); - int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, attr); + _PyThreadState_PushCStackRef(tstate, &method); + int is_meth = _PyObject_GetMethodStackRef(tstate, PyStackRef_AsPyObjectBorrow(owner), name, &method.ref); stack_pointer = _PyFrame_GetStackPointer(frame); if (is_meth) { - assert(!PyStackRef_IsNull(*attr)); + assert(!PyStackRef_IsNull(method.ref)); self_or_null[0] = owner; + attr = _PyThreadState_PopCStackRefSteal(tstate, &method); } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(*attr)) { + self_or_null[0] = PyStackRef_NULL; + attr = _PyThreadState_PopCStackRefSteal(tstate, &method); + if (PyStackRef_IsNull(attr)) { JUMP_TO_LABEL(error); } - self_or_null[0] = PyStackRef_NULL; stack_pointer += 1; } } @@ -7864,24 +7689,25 @@ PyObject *attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); if (attr_o == NULL) { JUMP_TO_LABEL(error); } - *attr = PyStackRef_FromPyObjectSteal(attr_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); stack_pointer += 1; } } + stack_pointer[-1] = attr; stack_pointer += (oparg&1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_CLASS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_CLASS; (void)(opcode); #endif @@ -7934,12 +7760,12 @@ } } stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_CLASS_WITH_METACLASS_CHECK; (void)(opcode); #endif @@ -8002,12 +7828,12 @@ } } stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN; (void)(opcode); #endif @@ -8058,14 +7884,14 @@ tstate, PyStackRef_FromPyObjectNew(f), 2, frame); new_frame->localsplus[0] = owner; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); new_frame->localsplus[1] = PyStackRef_FromPyObjectNew(name); - frame->return_offset = 10 ; + frame->return_offset = 10u ; DISPATCH_INLINED(new_frame); } TARGET(LOAD_ATTR_INSTANCE_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_INSTANCE_VALUE; (void)(opcode); #endif @@ -8077,6 +7903,8 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); _PyStackRef owner; _PyStackRef attr; + _PyStackRef o; + _PyStackRef value; _PyStackRef *null; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION @@ -8126,9 +7954,14 @@ attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); + o = owner; + } + // _POP_TOP + { + value = o; stack_pointer[-1] = attr; _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); } /* Skip 5 cache entries */ @@ -8140,12 +7973,12 @@ } } stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_METHOD_LAZY_DICT; (void)(opcode); #endif @@ -8196,12 +8029,12 @@ stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_METHOD_NO_DICT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_METHOD_NO_DICT; (void)(opcode); #endif @@ -8242,12 +8075,12 @@ stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_METHOD_WITH_VALUES; (void)(opcode); #endif @@ -8309,12 +8142,12 @@ stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_MODULE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_MODULE; (void)(opcode); #endif @@ -8383,12 +8216,12 @@ } } stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_NONDESCRIPTOR_NO_DICT; (void)(opcode); #endif @@ -8422,7 +8255,7 @@ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -8430,12 +8263,12 @@ } stack_pointer[0] = attr; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; (void)(opcode); #endif @@ -8490,7 +8323,7 @@ STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(owner); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -8498,12 +8331,12 @@ } stack_pointer[0] = attr; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_PROPERTY) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_PROPERTY; (void)(opcode); #endif @@ -8583,7 +8416,7 @@ assert(tstate->interp->eval_frame == NULL); _PyInterpreterFrame *temp = PyStackRef_Unwrap(new_frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(temp->previous == frame || temp->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); @@ -8597,7 +8430,7 @@ } TARGET(LOAD_ATTR_SLOT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_SLOT; (void)(opcode); #endif @@ -8661,12 +8494,12 @@ } } stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_ATTR_WITH_HINT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_ATTR_WITH_HINT; (void)(opcode); #endif @@ -8771,12 +8604,12 @@ } } stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_BUILD_CLASS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_BUILD_CLASS; (void)(opcode); #endif @@ -8801,12 +8634,12 @@ bc = PyStackRef_FromPyObjectSteal(bc_o); stack_pointer[0] = bc; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_COMMON_CONSTANT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_COMMON_CONSTANT; (void)(opcode); #endif @@ -8818,12 +8651,12 @@ value = PyStackRef_FromPyObjectNew(tstate->interp->common_consts[oparg]); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_CONST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_CONST; (void)(opcode); #endif @@ -8835,12 +8668,12 @@ value = PyStackRef_FromPyObjectBorrow(obj); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_DEREF) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_DEREF; (void)(opcode); #endif @@ -8855,7 +8688,7 @@ if (PyStackRef_IsNull(value)) { stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -8863,12 +8696,12 @@ } stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FAST; (void)(opcode); #endif @@ -8880,12 +8713,12 @@ value = PyStackRef_DUP(GETLOCAL(oparg)); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FAST_AND_CLEAR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FAST_AND_CLEAR; (void)(opcode); #endif @@ -8897,12 +8730,12 @@ GETLOCAL(oparg) = PyStackRef_NULL; stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FAST_BORROW) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FAST_BORROW; (void)(opcode); #endif @@ -8914,12 +8747,12 @@ value = PyStackRef_Borrow(GETLOCAL(oparg)); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FAST_BORROW_LOAD_FAST_BORROW) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FAST_BORROW_LOAD_FAST_BORROW; (void)(opcode); #endif @@ -8935,12 +8768,12 @@ stack_pointer[0] = value1; stack_pointer[1] = value2; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FAST_CHECK) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FAST_CHECK; (void)(opcode); #endif @@ -8961,12 +8794,12 @@ value = PyStackRef_DUP(value_s); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FAST_LOAD_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FAST_LOAD_FAST; (void)(opcode); #endif @@ -8982,12 +8815,12 @@ stack_pointer[0] = value1; stack_pointer[1] = value2; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FROM_DICT_OR_DEREF; (void)(opcode); #endif @@ -9020,19 +8853,19 @@ } } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(class_dict_st); stack_pointer = _PyFrame_GetStackPointer(frame); value = PyStackRef_FromPyObjectSteal(value_o); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_GLOBALS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_FROM_DICT_OR_GLOBALS; (void)(opcode); #endif @@ -9048,7 +8881,7 @@ int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(mod_or_class_dict); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -9102,12 +8935,12 @@ v = PyStackRef_FromPyObjectSteal(v_o); stack_pointer[0] = v; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_GLOBAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_GLOBAL; (void)(opcode); #endif @@ -9158,12 +8991,12 @@ } } stack_pointer += 1 + (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_GLOBAL_BUILTIN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_GLOBAL_BUILTIN; (void)(opcode); #endif @@ -9238,12 +9071,12 @@ } stack_pointer[0] = res; stack_pointer += 1 + (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_GLOBAL_MODULE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_GLOBAL_MODULE; (void)(opcode); #endif @@ -9305,12 +9138,12 @@ } stack_pointer[0] = res; stack_pointer += 1 + (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_LOCALS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_LOCALS; (void)(opcode); #endif @@ -9329,12 +9162,12 @@ locals = PyStackRef_FromPyObjectNew(l); stack_pointer[0] = locals; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_NAME) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_NAME; (void)(opcode); #endif @@ -9352,12 +9185,12 @@ v = PyStackRef_FromPyObjectSteal(v_o); stack_pointer[0] = v; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_SMALL_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_SMALL_INT; (void)(opcode); #endif @@ -9370,12 +9203,12 @@ value = PyStackRef_FromPyObjectBorrow(obj); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_SPECIAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_SPECIAL; (void)(opcode); #endif @@ -9396,7 +9229,7 @@ method_and_self = &stack_pointer[-1]; PyObject *name = _Py_SpecialMethods[oparg].name; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _PyObject_LookupSpecialMethod(name, method_and_self); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -9421,7 +9254,7 @@ } TARGET(LOAD_SUPER_ATTR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_SUPER_ATTR; (void)(opcode); #endif @@ -9485,7 +9318,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); JUMP_TO_LABEL(error); } } @@ -9530,7 +9363,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (super == NULL) { JUMP_TO_LABEL(error); } @@ -9553,12 +9386,12 @@ } stack_pointer[0] = attr; stack_pointer += 1 + (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_SUPER_ATTR_ATTR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_SUPER_ATTR_ATTR; (void)(opcode); #endif @@ -9608,19 +9441,19 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (attr == NULL) { JUMP_TO_LABEL(error); } attr_st = PyStackRef_FromPyObjectSteal(attr); stack_pointer[0] = attr_st; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(LOAD_SUPER_ATTR_METHOD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = LOAD_SUPER_ATTR_METHOD; (void)(opcode); #endif @@ -9668,7 +9501,7 @@ self_or_null = self_st; } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(self_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -9676,7 +9509,7 @@ stack_pointer += 1; } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = global_super_st; global_super_st = self_or_null; @@ -9688,17 +9521,17 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); attr = PyStackRef_FromPyObjectSteal(attr_o); stack_pointer[0] = attr; stack_pointer[1] = self_or_null; stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(MAKE_CELL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MAKE_CELL; (void)(opcode); #endif @@ -9719,7 +9552,7 @@ } TARGET(MAKE_FUNCTION) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MAKE_FUNCTION; (void)(opcode); #endif @@ -9735,7 +9568,7 @@ PyFunction_New(codeobj, GLOBALS()); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(codeobj_st); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -9747,12 +9580,12 @@ func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); stack_pointer[0] = func; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(MAP_ADD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MAP_ADD; (void)(opcode); #endif @@ -9778,12 +9611,12 @@ JUMP_TO_LABEL(pop_2_error); } stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(MATCH_CLASS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MATCH_CLASS; (void)(opcode); #endif @@ -9817,7 +9650,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (attrs_o) { assert(PyTuple_CheckExact(attrs_o)); attrs = PyStackRef_FromPyObjectSteal(attrs_o); @@ -9830,12 +9663,12 @@ } stack_pointer[0] = attrs; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(MATCH_KEYS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MATCH_KEYS; (void)(opcode); #endif @@ -9857,12 +9690,12 @@ values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); stack_pointer[0] = values_or_none; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(MATCH_MAPPING) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MATCH_MAPPING; (void)(opcode); #endif @@ -9876,12 +9709,12 @@ res = match ? PyStackRef_True : PyStackRef_False; stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(MATCH_SEQUENCE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = MATCH_SEQUENCE; (void)(opcode); #endif @@ -9895,12 +9728,12 @@ res = match ? PyStackRef_True : PyStackRef_False; stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(NOP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = NOP; (void)(opcode); #endif @@ -9911,7 +9744,7 @@ } TARGET(NOT_TAKEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = NOT_TAKEN; (void)(opcode); #endif @@ -9922,7 +9755,7 @@ } TARGET(POP_EXCEPT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_EXCEPT; (void)(opcode); #endif @@ -9938,12 +9771,12 @@ ? NULL : PyStackRef_AsPyObjectSteal(exc_value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(POP_ITER) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_ITER; (void)(opcode); #endif @@ -9956,7 +9789,7 @@ iter = stack_pointer[-2]; (void)index_or_null; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iter); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -9964,7 +9797,7 @@ } TARGET(POP_JUMP_IF_FALSE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_JUMP_IF_FALSE; (void)(opcode); #endif @@ -9981,12 +9814,12 @@ RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_JUMP_IF_NONE; (void)(opcode); #endif @@ -10024,12 +9857,12 @@ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_JUMP_IF_NOT_NONE; (void)(opcode); #endif @@ -10067,12 +9900,12 @@ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_JUMP_IF_TRUE; (void)(opcode); #endif @@ -10089,12 +9922,12 @@ RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(POP_TOP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = POP_TOP; (void)(opcode); #endif @@ -10104,7 +9937,7 @@ _PyStackRef value; value = stack_pointer[-1]; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -10112,7 +9945,7 @@ } TARGET(PUSH_EXC_INFO) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = PUSH_EXC_INFO; (void)(opcode); #endif @@ -10136,12 +9969,12 @@ stack_pointer[-1] = prev_exc; stack_pointer[0] = new_exc; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(PUSH_NULL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = PUSH_NULL; (void)(opcode); #endif @@ -10152,12 +9985,12 @@ res = PyStackRef_NULL; stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(RAISE_VARARGS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RAISE_VARARGS; (void)(opcode); #endif @@ -10172,7 +10005,7 @@ PyObject *cause = oparg == 2 ? PyStackRef_AsPyObjectSteal(args[1]) : NULL; PyObject *exc = oparg > 0 ? PyStackRef_AsPyObjectSteal(args[0]) : NULL; stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int err = do_raise(tstate, exc, cause); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -10186,7 +10019,7 @@ } TARGET(RERAISE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RERAISE; (void)(opcode); #endif @@ -10206,7 +10039,7 @@ } assert(exc && PyExceptionInstance_Check(exc)); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); _PyErr_SetRaisedException(tstate, exc); monitor_reraise(tstate, frame, this_instr); @@ -10214,7 +10047,7 @@ } TARGET(RESERVED) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RESERVED; (void)(opcode); #endif @@ -10227,7 +10060,7 @@ } TARGET(RESUME) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RESUME; (void)(opcode); #endif @@ -10303,7 +10136,7 @@ } TARGET(RESUME_CHECK) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RESUME_CHECK; (void)(opcode); #endif @@ -10341,7 +10174,7 @@ } TARGET(RETURN_GENERATOR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RETURN_GENERATOR; (void)(opcode); #endif @@ -10375,12 +10208,12 @@ LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(RETURN_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = RETURN_VALUE; (void)(opcode); #endif @@ -10393,7 +10226,7 @@ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(STACK_LEVEL() == 0); _Py_LeaveRecursiveCallPy(tstate); @@ -10406,12 +10239,12 @@ LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(SEND) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SEND; (void)(opcode); #endif @@ -10455,12 +10288,12 @@ _PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v)); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - assert( 2 + oparg <= UINT16_MAX); - frame->return_offset = (uint16_t)( 2 + oparg); + assert( 2u + oparg <= UINT16_MAX); + frame->return_offset = (uint16_t)( 2u + oparg); assert(gen_frame->previous == NULL); gen_frame->previous = frame; DISPATCH_INLINED(gen_frame); @@ -10495,7 +10328,7 @@ } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -10503,7 +10336,7 @@ } } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -10511,12 +10344,12 @@ } stack_pointer[0] = retval; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(SEND_GEN) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SEND_GEN; (void)(opcode); #endif @@ -10560,8 +10393,8 @@ gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - assert( 2 + oparg <= UINT16_MAX); - frame->return_offset = (uint16_t)( 2 + oparg); + assert( 2u + oparg <= UINT16_MAX); + frame->return_offset = (uint16_t)( 2u + oparg); pushed_frame->previous = frame; gen_frame = PyStackRef_Wrap(pushed_frame); } @@ -10571,7 +10404,7 @@ assert(tstate->interp->eval_frame == NULL); _PyInterpreterFrame *temp = PyStackRef_Unwrap(new_frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); assert(temp->previous == frame || temp->previous->previous == frame); CALL_STAT_INC(inlined_py_calls); @@ -10585,7 +10418,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SETUP_ANNOTATIONS; (void)(opcode); #endif @@ -10631,7 +10464,7 @@ } TARGET(SET_ADD) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SET_ADD; (void)(opcode); #endif @@ -10650,12 +10483,12 @@ JUMP_TO_LABEL(pop_1_error); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(SET_FUNCTION_ATTRIBUTE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SET_FUNCTION_ATTRIBUTE; (void)(opcode); #endif @@ -10678,12 +10511,12 @@ *ptr = attr; stack_pointer[-2] = func_out; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(SET_UPDATE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SET_UPDATE; (void)(opcode); #endif @@ -10699,7 +10532,7 @@ PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -10710,7 +10543,7 @@ } TARGET(STORE_ATTR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_ATTR; (void)(opcode); #endif @@ -10758,7 +10591,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { JUMP_TO_LABEL(error); } @@ -10767,7 +10600,7 @@ } TARGET(STORE_ATTR_INSTANCE_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_ATTR_INSTANCE_VALUE; (void)(opcode); #endif @@ -10779,6 +10612,7 @@ static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); _PyStackRef owner; _PyStackRef value; + _PyStackRef o; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION_AND_LOCK { @@ -10832,18 +10666,28 @@ _PyDictValues_AddToInsertionOrder(values, index); } UNLOCK_OBJECT(owner_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + o = owner; + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); Py_XDECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); } + // _POP_TOP + { + value = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } DISPATCH(); } TARGET(STORE_ATTR_SLOT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_ATTR_SLOT; (void)(opcode); #endif @@ -10855,6 +10699,7 @@ static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); _PyStackRef owner; _PyStackRef value; + _PyStackRef o; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION { @@ -10883,18 +10728,28 @@ PyObject *old_value = *(PyObject **)addr; FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(owner_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + o = owner; + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); Py_XDECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); } + // _POP_TOP + { + value = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } DISPATCH(); } TARGET(STORE_ATTR_WITH_HINT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_ATTR_WITH_HINT; (void)(opcode); #endif @@ -10906,6 +10761,7 @@ static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); _PyStackRef owner; _PyStackRef value; + _PyStackRef o; /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION { @@ -10971,18 +10827,28 @@ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(dict); STAT_INC(STORE_ATTR, hit); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + o = owner; + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); Py_XDECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); } + // _POP_TOP + { + value = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } DISPATCH(); } TARGET(STORE_DEREF) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_DEREF; (void)(opcode); #endif @@ -10996,12 +10862,12 @@ PyCell_SetTakeRef(cell, PyStackRef_AsPyObjectSteal(v)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(STORE_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_FAST; (void)(opcode); #endif @@ -11013,7 +10879,7 @@ _PyStackRef tmp = GETLOCAL(oparg); GETLOCAL(oparg) = value; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11021,7 +10887,7 @@ } TARGET(STORE_FAST_LOAD_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_FAST_LOAD_FAST; (void)(opcode); #endif @@ -11044,7 +10910,7 @@ } TARGET(STORE_FAST_STORE_FAST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_FAST_STORE_FAST; (void)(opcode); #endif @@ -11060,14 +10926,14 @@ _PyStackRef tmp = GETLOCAL(oparg1); GETLOCAL(oparg1) = value1; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); tmp = GETLOCAL(oparg2); GETLOCAL(oparg2) = value2; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11075,7 +10941,7 @@ } TARGET(STORE_GLOBAL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_GLOBAL; (void)(opcode); #endif @@ -11089,7 +10955,7 @@ int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11100,7 +10966,7 @@ } TARGET(STORE_NAME) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_NAME; (void)(opcode); #endif @@ -11118,7 +10984,7 @@ "no locals found when storing %R", name); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11135,7 +11001,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); } stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(v); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11146,7 +11012,7 @@ } TARGET(STORE_SLICE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_SLICE; (void)(opcode); #endif @@ -11179,7 +11045,7 @@ } else { stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); Py_DECREF(slice); @@ -11197,7 +11063,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -4; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { JUMP_TO_LABEL(error); } @@ -11206,7 +11072,7 @@ } TARGET(STORE_SUBSCR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_SUBSCR; (void)(opcode); #endif @@ -11256,7 +11122,7 @@ PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (err) { JUMP_TO_LABEL(error); } @@ -11265,7 +11131,7 @@ } TARGET(STORE_SUBSCR_DICT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_SUBSCR_DICT; (void)(opcode); #endif @@ -11279,6 +11145,7 @@ _PyStackRef value; _PyStackRef dict_st; _PyStackRef sub; + _PyStackRef st; // _GUARD_NOS_DICT { nos = stack_pointer[-2]; @@ -11303,20 +11170,30 @@ PyStackRef_AsPyObjectSteal(sub), PyStackRef_AsPyObjectSteal(value)); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(dict_st); - stack_pointer = _PyFrame_GetStackPointer(frame); if (err) { + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(dict_st); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_LABEL(error); } + st = dict_st; + } + // _POP_TOP + { + value = st; + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); } DISPATCH(); } TARGET(STORE_SUBSCR_LIST_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = STORE_SUBSCR_LIST_INT; (void)(opcode); #endif @@ -11330,6 +11207,8 @@ _PyStackRef nos; _PyStackRef list_st; _PyStackRef sub_st; + _PyStackRef ls; + _PyStackRef ss; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -11385,19 +11264,36 @@ PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); UNLOCK_OBJECT(list); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ls = list_st; + ss = sub_st; + stack_pointer[-3] = ls; + stack_pointer[-2] = ss; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(list_st); Py_DECREF(old_value); stack_pointer = _PyFrame_GetStackPointer(frame); } + // _POP_TOP_INT + { + value = ss; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP + { + value = ls; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } DISPATCH(); } TARGET(SWAP) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = SWAP; (void)(opcode); #endif @@ -11417,7 +11313,7 @@ } TARGET(TO_BOOL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL; (void)(opcode); #endif @@ -11453,7 +11349,7 @@ int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11464,12 +11360,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(TO_BOOL_ALWAYS_TRUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL_ALWAYS_TRUE; (void)(opcode); #endif @@ -11499,7 +11395,7 @@ { value = owner; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11507,12 +11403,12 @@ } stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(TO_BOOL_BOOL) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL_BOOL; (void)(opcode); #endif @@ -11536,7 +11432,7 @@ } TARGET(TO_BOOL_INT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL_INT; (void)(opcode); #endif @@ -11564,7 +11460,7 @@ } else { stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11576,7 +11472,7 @@ } TARGET(TO_BOOL_LIST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL_LIST; (void)(opcode); #endif @@ -11619,7 +11515,7 @@ } TARGET(TO_BOOL_NONE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL_NONE; (void)(opcode); #endif @@ -11646,7 +11542,7 @@ } TARGET(TO_BOOL_STR) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = TO_BOOL_STR; (void)(opcode); #endif @@ -11681,7 +11577,7 @@ else { assert(Py_SIZE(value_o)); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11693,8 +11589,70 @@ DISPATCH(); } + TARGET(TRACE_RECORD) { + #if _Py_TAIL_CALL_INTERP + int opcode = TRACE_RECORD; + (void)(opcode); + #endif + _Py_CODEUNIT* const prev_instr = frame->instr_ptr; + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(TRACE_RECORD); + opcode = TRACE_RECORD; + #if _Py_TIER2 + assert(IS_JIT_TRACING()); + next_instr = this_instr; + frame->instr_ptr = prev_instr; + opcode = next_instr->op.code; + bool stop_tracing = (opcode == WITH_EXCEPT_START || + opcode == RERAISE || opcode == CLEANUP_THROW || + opcode == PUSH_EXC_INFO || opcode == INTERPRETER_EXIT); + _PyFrame_SetStackPointer(frame, stack_pointer); + int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing ? _DEOPT : 0); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (full) { + LEAVE_TRACING(); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = stop_tracing_and_jit(tstate, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + JUMP_TO_LABEL(error); + } + DISPATCH(); + } + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + if ((_tstate->jit_tracer_state.prev_state.instr->op.code == CALL_LIST_APPEND && + opcode == POP_TOP) || + (_tstate->jit_tracer_state.prev_state.instr->op.code == BINARY_OP_INPLACE_ADD_UNICODE && + opcode == STORE_FAST)) { + _tstate->jit_tracer_state.prev_state.instr_is_super = true; + } + else { + _tstate->jit_tracer_state.prev_state.instr = next_instr; + } + PyObject *prev_code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + if (_tstate->jit_tracer_state.prev_state.instr_code != (PyCodeObject *)prev_code) { + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_SETREF(_tstate->jit_tracer_state.prev_state.instr_code, (PyCodeObject*)Py_NewRef((prev_code))); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + _tstate->jit_tracer_state.prev_state.instr_frame = frame; + _tstate->jit_tracer_state.prev_state.instr_oparg = oparg; + _tstate->jit_tracer_state.prev_state.instr_stacklevel = PyStackRef_IsNone(frame->f_executable) ? 2 : STACK_LEVEL(); + if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { + (&next_instr[1])->counter = trigger_backoff_counter(); + } + DISPATCH_GOTO_NON_TRACING(); + #else + (void)prev_instr; + Py_FatalError("JIT instruction executed in non-jit build."); + #endif + } + TARGET(UNARY_INVERT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNARY_INVERT; (void)(opcode); #endif @@ -11708,7 +11666,7 @@ PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11718,12 +11676,12 @@ res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(UNARY_NEGATIVE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNARY_NEGATIVE; (void)(opcode); #endif @@ -11737,7 +11695,7 @@ PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11747,12 +11705,12 @@ res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(UNARY_NOT) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNARY_NOT; (void)(opcode); #endif @@ -11770,7 +11728,7 @@ } TARGET(UNPACK_EX) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNPACK_EX; (void)(opcode); #endif @@ -11783,7 +11741,7 @@ top = &stack_pointer[(oparg & 0xFF) + (oparg >> 8)]; PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg & 0xFF, oparg >> 8, top); Py_DECREF(seq_o); @@ -11792,12 +11750,12 @@ JUMP_TO_LABEL(error); } stack_pointer += 1 + (oparg & 0xFF) + (oparg >> 8); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(UNPACK_SEQUENCE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNPACK_SEQUENCE; (void)(opcode); #endif @@ -11833,7 +11791,7 @@ top = &stack_pointer[-1 + oparg]; PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top); Py_DECREF(seq_o); @@ -11843,12 +11801,12 @@ } } stack_pointer += oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(UNPACK_SEQUENCE_LIST) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNPACK_SEQUENCE_LIST; (void)(opcode); #endif @@ -11898,7 +11856,7 @@ } UNLOCK_OBJECT(seq_o); stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(seq); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11907,7 +11865,7 @@ } TARGET(UNPACK_SEQUENCE_TUPLE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNPACK_SEQUENCE_TUPLE; (void)(opcode); #endif @@ -11948,7 +11906,7 @@ *values++ = PyStackRef_FromPyObjectNew(items[i]); } stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(seq); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11957,7 +11915,7 @@ } TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = UNPACK_SEQUENCE_TWO_TUPLE; (void)(opcode); #endif @@ -11999,7 +11957,7 @@ stack_pointer[-1] = val1; stack_pointer[0] = val0; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_CLOSE(seq); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -12008,7 +11966,7 @@ } TARGET(WITH_EXCEPT_START) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = WITH_EXCEPT_START; (void)(opcode); #endif @@ -12048,12 +12006,12 @@ res = PyStackRef_FromPyObjectSteal(res_o); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } TARGET(YIELD_VALUE) { - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode = YIELD_VALUE; (void)(opcode); #endif @@ -12071,7 +12029,7 @@ gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; @@ -12094,12 +12052,12 @@ LLTRACE_RESUME_FRAME(); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } /* END INSTRUCTIONS */ -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP #if USE_COMPUTED_GOTOS _unknown_opcode: #else @@ -12121,7 +12079,7 @@ JUMP_TO_LABEL(error); /* This should never be reached. Every opcode should end with DISPATCH() or goto error. */ Py_UNREACHABLE(); -#endif /* Py_TAIL_CALL_INTERP */ +#endif /* _Py_TAIL_CALL_INTERP */ /* BEGIN LABELS */ LABEL(pop_2_error) @@ -12207,7 +12165,7 @@ JUMP_TO_LABEL(error); } #endif stack_pointer = _PyFrame_GetStackPointer(frame); - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode; #endif DISPATCH(); @@ -12224,7 +12182,7 @@ JUMP_TO_LABEL(error); frame->return_offset = 0; if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { tstate->current_frame = frame->previous; - #if !Py_TAIL_CALL_INTERP + #if !_Py_TAIL_CALL_INTERP assert(frame == &entry.frame); #endif #ifdef _Py_TIER2 @@ -12258,11 +12216,32 @@ JUMP_TO_LABEL(error); assert(!_PyErr_Occurred(tstate)); #endif stack_pointer = _PyFrame_GetStackPointer(frame); - #if Py_TAIL_CALL_INTERP + #if _Py_TAIL_CALL_INTERP int opcode; #endif DISPATCH(); } + LABEL(stop_tracing) + { + #if _Py_TIER2 + assert(IS_JIT_TRACING()); + int opcode = next_instr->op.code; + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyJit_translate_single_bytecode_to_trace(tstate, frame, NULL, _EXIT_TRACE); + stack_pointer = _PyFrame_GetStackPointer(frame); + LEAVE_TRACING(); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = stop_tracing_and_jit(tstate, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + JUMP_TO_LABEL(error); + } + DISPATCH_GOTO_NON_TRACING(); + #else + Py_FatalError("JIT label executed in non-jit build."); + #endif + } + /* END LABELS */ #undef TIER_ONE diff --git a/Python/getcompiler.c b/Python/getcompiler.c index a5d26239e87..cc56ad8c895 100644 --- a/Python/getcompiler.c +++ b/Python/getcompiler.c @@ -3,6 +3,10 @@ #include "Python.h" +#ifdef _Py_COMPILER +# define COMPILER _Py_COMPILER +#endif + #ifndef COMPILER // Note the __clang__ conditional has to come before the __GNUC__ one because diff --git a/Python/import.c b/Python/import.c index 9dee20ecb63..db433dbc971 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_audit.h" // _PySys_Audit() #include "pycore_ceval.h" +#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION() #include "pycore_hashtable.h" // _Py_hashtable_new_full() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() @@ -309,13 +310,8 @@ PyImport_GetModule(PyObject *name) if not, create a new one and insert it in the modules dictionary. */ static PyObject * -import_add_module(PyThreadState *tstate, PyObject *name) +import_add_module_lock_held(PyObject *modules, PyObject *name) { - PyObject *modules = get_modules_dict(tstate, false); - if (modules == NULL) { - return NULL; - } - PyObject *m; if (PyMapping_GetOptionalItem(modules, name, &m) < 0) { return NULL; @@ -335,6 +331,21 @@ import_add_module(PyThreadState *tstate, PyObject *name) return m; } +static PyObject * +import_add_module(PyThreadState *tstate, PyObject *name) +{ + PyObject *modules = get_modules_dict(tstate, false); + if (modules == NULL) { + return NULL; + } + + PyObject *m; + Py_BEGIN_CRITICAL_SECTION(modules); + m = import_add_module_lock_held(modules, name); + Py_END_CRITICAL_SECTION(); + return m; +} + PyObject * PyImport_AddModuleRef(const char *name) { @@ -672,8 +683,8 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) (6). first time (not found in _PyRuntime.imports.extensions): A. _imp_create_dynamic_impl() -> import_find_extension() - B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc() - C. _PyImport_GetModInitFunc(): load <module init func> + B. _imp_create_dynamic_impl() -> _PyImport_GetModuleExportHooks() + C. _PyImport_GetModuleExportHooks(): load <module init func> D. _imp_create_dynamic_impl() -> import_run_extension() E. import_run_extension() -> _PyImport_RunModInitFunc() F. _PyImport_RunModInitFunc(): call <module init func> @@ -743,16 +754,19 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) A. noop - ...for multi-phase init modules: + ...for multi-phase init modules from PyModInit_* (PyModuleDef): (6). every time: A. _imp_create_dynamic_impl() -> import_find_extension() (not found) - B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc() - C. _PyImport_GetModInitFunc(): load <module init func> + B. _imp_create_dynamic_impl() -> _PyImport_GetModuleExportHooks() + C. _PyImport_GetModuleExportHooks(): load <module init func> D. _imp_create_dynamic_impl() -> import_run_extension() E. import_run_extension() -> _PyImport_RunModInitFunc() F. _PyImport_RunModInitFunc(): call <module init func> G. import_run_extension() -> PyModule_FromDefAndSpec() + + PyModule_FromDefAndSpec(): + H. PyModule_FromDefAndSpec(): gather/check moduledef slots I. if there's a Py_mod_create slot: 1. PyModule_FromDefAndSpec(): call its function @@ -765,10 +779,29 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) (10). every time: A. _imp_exec_dynamic_impl() -> exec_builtin_or_dynamic() B. if mod->md_state == NULL (including if m_size == 0): - 1. exec_builtin_or_dynamic() -> PyModule_ExecDef() - 2. PyModule_ExecDef(): allocate mod->md_state + 1. exec_builtin_or_dynamic() -> PyModule_Exec() + 2. PyModule_Exec(): allocate mod->md_state 3. if there's a Py_mod_exec slot: - 1. PyModule_ExecDef(): call its function + 1. PyModule_Exec(): call its function + + + ...for multi-phase init modules from PyModExport_* (slots array): + + (6). every time: + + A. _imp_create_dynamic_impl() -> import_find_extension() (not found) + B. _imp_create_dynamic_impl() -> _PyImport_GetModuleExportHooks() + C. _PyImport_GetModuleExportHooks(): load <module export func> + D. _imp_create_dynamic_impl() -> import_run_modexport() + E. import_run_modexport(): call <module init func> + F. import_run_modexport() -> PyModule_FromSlotsAndSpec() + G. PyModule_FromSlotsAndSpec(): create temporary PyModuleDef-like + H. PyModule_FromSlotsAndSpec() -> PyModule_FromDefAndSpec() + + (PyModule_FromDefAndSpec behaves as for PyModInit_*, above) + + (10). every time: as for PyModInit_*, above + */ @@ -782,18 +815,13 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) substitute this (if the name actually matches). */ -#ifdef HAVE_THREAD_LOCAL -_Py_thread_local const char *pkgcontext = NULL; +static _Py_thread_local const char *pkgcontext = NULL; # undef PKGCONTEXT # define PKGCONTEXT pkgcontext -#endif const char * _PyImport_ResolveNameWithPackageContext(const char *name) { -#ifndef HAVE_THREAD_LOCAL - PyMutex_Lock(&EXTENSIONS.mutex); -#endif if (PKGCONTEXT != NULL) { const char *p = strrchr(PKGCONTEXT, '.'); if (p != NULL && strcmp(name, p+1) == 0) { @@ -801,23 +829,14 @@ _PyImport_ResolveNameWithPackageContext(const char *name) PKGCONTEXT = NULL; } } -#ifndef HAVE_THREAD_LOCAL - PyMutex_Unlock(&EXTENSIONS.mutex); -#endif return name; } const char * _PyImport_SwapPackageContext(const char *newcontext) { -#ifndef HAVE_THREAD_LOCAL - PyMutex_Lock(&EXTENSIONS.mutex); -#endif const char *oldcontext = PKGCONTEXT; PKGCONTEXT = newcontext; -#ifndef HAVE_THREAD_LOCAL - PyMutex_Unlock(&EXTENSIONS.mutex); -#endif return oldcontext; } @@ -839,25 +858,19 @@ _PyImport_SetDLOpenFlags(PyInterpreterState *interp, int new_val) /* Common implementation for _imp.exec_dynamic and _imp.exec_builtin */ static int exec_builtin_or_dynamic(PyObject *mod) { - PyModuleDef *def; void *state; if (!PyModule_Check(mod)) { return 0; } - def = PyModule_GetDef(mod); - if (def == NULL) { - return 0; - } - state = PyModule_GetState(mod); if (state) { /* Already initialized; skip reload */ return 0; } - return PyModule_ExecDef(mod, def); + return PyModule_Exec(mod); } @@ -1015,9 +1028,10 @@ struct extensions_cache_value { _Py_ext_module_origin origin; #ifdef Py_GIL_DISABLED - /* The module's md_gil slot, for legacy modules that are reinitialized from - m_dict rather than calling their initialization function again. */ - void *md_gil; + /* The module's md_requires_gil member, for legacy modules that are + * reinitialized from m_dict rather than calling their initialization + * function again. */ + bool md_requires_gil; #endif }; @@ -1348,7 +1362,7 @@ static struct extensions_cache_value * _extensions_cache_set(PyObject *path, PyObject *name, PyModuleDef *def, PyModInitFunction m_init, Py_ssize_t m_index, PyObject *m_dict, - _Py_ext_module_origin origin, void *md_gil) + _Py_ext_module_origin origin, bool requires_gil) { struct extensions_cache_value *value = NULL; void *key = NULL; @@ -1403,11 +1417,11 @@ _extensions_cache_set(PyObject *path, PyObject *name, /* m_dict is set by set_cached_m_dict(). */ .origin=origin, #ifdef Py_GIL_DISABLED - .md_gil=md_gil, + .md_requires_gil=requires_gil, #endif }; #ifndef Py_GIL_DISABLED - (void)md_gil; + (void)requires_gil; #endif if (init_cached_m_dict(newvalue, m_dict) < 0) { goto finally; @@ -1545,26 +1559,13 @@ _PyImport_CheckGILForModule(PyObject* module, PyObject *module_name) } if (!PyModule_Check(module) || - ((PyModuleObject *)module)->md_gil == Py_MOD_GIL_USED) { - if (_PyEval_EnableGILPermanent(tstate)) { - int warn_result = PyErr_WarnFormat( - PyExc_RuntimeWarning, - 1, - "The global interpreter lock (GIL) has been enabled to load " - "module '%U', which has not declared that it can run safely " - "without the GIL. To override this behavior and keep the GIL " - "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", - module_name - ); - if (warn_result < 0) { - return warn_result; - } + ((PyModuleObject *)module)->md_requires_gil) + { + if (PyModule_Check(module)) { + assert(((PyModuleObject *)module)->md_token_is_def); } - - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); - if (config->enable_gil == _PyConfig_GIL_DEFAULT && config->verbose) { - PySys_FormatStderr("# loading module '%U', which requires the GIL\n", - module_name); + if (_PyImport_EnableGILAndWarn(tstate, module_name) < 0) { + return -1; } } else { @@ -1573,6 +1574,28 @@ _PyImport_CheckGILForModule(PyObject* module, PyObject *module_name) return 0; } + +int +_PyImport_EnableGILAndWarn(PyThreadState *tstate, PyObject *module_name) +{ + if (_PyEval_EnableGILPermanent(tstate)) { + return PyErr_WarnFormat( + PyExc_RuntimeWarning, + 1, + "The global interpreter lock (GIL) has been enabled to load " + "module '%U', which has not declared that it can run safely " + "without the GIL. To override this behavior and keep the GIL " + "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", + module_name + ); + } + const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); + if (config->enable_gil == _PyConfig_GIL_DEFAULT && config->verbose) { + PySys_FormatStderr("# loading module '%U', which requires the GIL\n", + module_name); + } + return 0; +} #endif static PyThreadState * @@ -1723,7 +1746,7 @@ struct singlephase_global_update { Py_ssize_t m_index; PyObject *m_dict; _Py_ext_module_origin origin; - void *md_gil; + bool md_requires_gil; }; static struct extensions_cache_value * @@ -1782,7 +1805,7 @@ update_global_state_for_extension(PyThreadState *tstate, #endif cached = _extensions_cache_set( path, name, def, m_init, singlephase->m_index, m_dict, - singlephase->origin, singlephase->md_gil); + singlephase->origin, singlephase->md_requires_gil); if (cached == NULL) { // XXX Ignore this error? Doing so would effectively // mark the module as not loadable. @@ -1801,7 +1824,7 @@ finish_singlephase_extension(PyThreadState *tstate, PyObject *mod, PyObject *name, PyObject *modules) { assert(mod != NULL && PyModule_Check(mod)); - assert(cached->def == _PyModule_GetDef(mod)); + assert(cached->def == _PyModule_GetDefOrNull(mod)); Py_ssize_t index = _get_cached_module_index(cached); if (_modules_by_index_set(tstate->interp, index, mod) < 0) { @@ -1871,7 +1894,7 @@ reload_singlephase_extension(PyThreadState *tstate, if (def->m_base.m_copy != NULL) { // For non-core modules, fetch the GIL slot that was stored by // import_run_extension(). - ((PyModuleObject *)mod)->md_gil = cached->md_gil; + ((PyModuleObject *)mod)->md_requires_gil = cached->md_requires_gil; } #endif /* We can't set mod->md_def if it's missing, @@ -1879,8 +1902,8 @@ reload_singlephase_extension(PyThreadState *tstate, * due to violating interpreter isolation. * See the note in set_cached_m_dict(). * Until that is solved, we leave md_def set to NULL. */ - assert(_PyModule_GetDef(mod) == NULL - || _PyModule_GetDef(mod) == def); + assert(_PyModule_GetDefOrNull(mod) == NULL + || _PyModule_GetDefOrNull(mod) == def); } else { assert(cached->m_dict == NULL); @@ -1967,6 +1990,43 @@ import_find_extension(PyThreadState *tstate, return mod; } +static PyObject * +import_run_modexport(PyThreadState *tstate, PyModExportFunction ex0, + struct _Py_ext_module_loader_info *info, + PyObject *spec) +{ + /* This is like import_run_extension, but avoids interpreter switching + * and code for for single-phase modules. + */ + PyModuleDef_Slot *slots = ex0(); + if (!slots) { + if (!PyErr_Occurred()) { + PyErr_Format( + PyExc_SystemError, + "module export hook for module %R failed without setting an exception", + info->name); + } + return NULL; + } + if (PyErr_Occurred()) { + PyErr_Format( + PyExc_SystemError, + "module export hook for module %R raised unreported exception", + info->name); + } + PyObject *result = PyModule_FromSlotsAndSpec(slots, spec); + if (!result) { + return NULL; + } + if (PyModule_Check(result)) { + PyModuleObject *mod = (PyModuleObject *)result; + if (mod && !mod->md_token) { + mod->md_token = slots; + } + } + return result; +} + static PyObject * import_run_extension(PyThreadState *tstate, PyModInitFunction p0, struct _Py_ext_module_loader_info *info, @@ -2089,7 +2149,7 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0, .m_index=def->m_base.m_index, .origin=info->origin, #ifdef Py_GIL_DISABLED - .md_gil=((PyModuleObject *)mod)->md_gil, + .md_requires_gil=((PyModuleObject *)mod)->md_requires_gil, #endif }; // gh-88216: Extensions and def->m_base.m_copy can be updated @@ -2139,7 +2199,7 @@ main_finally: assert_multiphase_def(def); assert(mod == NULL); /* Note that we cheat a little by not repeating the calls - * to _PyImport_GetModInitFunc() and _PyImport_RunModInitFunc(). */ + * to _PyImport_GetModuleExportHooks() and _PyImport_RunModInitFunc(). */ mod = PyModule_FromDefAndSpec(def, spec); if (mod == NULL) { goto error; @@ -2253,8 +2313,9 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name, return -1; } - PyModuleDef *def = PyModule_GetDef(mod); + PyModuleDef *def = _PyModule_GetDefOrNull(mod); if (def == NULL) { + assert(!PyErr_Occurred()); PyErr_BadInternalCall(); goto finally; } @@ -2283,7 +2344,7 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name, .origin=_Py_ext_module_origin_CORE, #ifdef Py_GIL_DISABLED /* Unused when m_dict == NULL. */ - .md_gil=NULL, + .md_requires_gil=false, #endif }; cached = update_global_state_for_extension( @@ -2322,8 +2383,23 @@ is_builtin(PyObject *name) return 0; } +static struct _inittab* +lookup_inittab_entry(const struct _Py_ext_module_loader_info* info) +{ + for (struct _inittab *p = INITTAB; p->name != NULL; p++) { + if (_PyUnicode_EqualToASCIIString(info->name, p->name)) { + return p; + } + } + // not found + return NULL; +} + static PyObject* -create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) +create_builtin( + PyThreadState *tstate, PyObject *name, + PyObject *spec, + PyModInitFunction initfunc) { struct _Py_ext_module_loader_info info; if (_Py_ext_module_loader_info_init_for_builtin(&info, name) < 0) { @@ -2336,8 +2412,8 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) assert(!_PyErr_Occurred(tstate)); assert(cached != NULL); /* The module might not have md_def set in certain reload cases. */ - assert(_PyModule_GetDef(mod) == NULL - || cached->def == _PyModule_GetDef(mod)); + assert(_PyModule_GetDefOrNull(mod) == NULL + || cached->def == _PyModule_GetDefOrNull(mod)); assert_singlephase(cached); goto finally; } @@ -2354,19 +2430,21 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) _extensions_cache_delete(info.path, info.name); } - struct _inittab *found = NULL; - for (struct _inittab *p = INITTAB; p->name != NULL; p++) { - if (_PyUnicode_EqualToASCIIString(info.name, p->name)) { - found = p; + PyModInitFunction p0 = NULL; + if (initfunc == NULL) { + struct _inittab *entry = lookup_inittab_entry(&info); + if (entry == NULL) { + mod = NULL; + _PyErr_SetModuleNotFoundError(name); + goto finally; } + + p0 = (PyModInitFunction)entry->initfunc; } - if (found == NULL) { - // not found - mod = Py_NewRef(Py_None); - goto finally; + else { + p0 = initfunc; } - PyModInitFunction p0 = (PyModInitFunction)found->initfunc; if (p0 == NULL) { /* Cannot re-init internal module ("sys" or "builtins") */ assert(is_core_module(tstate->interp, info.name, info.path)); @@ -2374,6 +2452,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) goto finally; } + #ifdef Py_GIL_DISABLED // This call (and the corresponding call to _PyImport_CheckGILForModule()) // would ideally be inside import_run_extension(). They are kept in the @@ -2397,6 +2476,33 @@ finally: return mod; } +PyObject* +PyImport_CreateModuleFromInitfunc( + PyObject *spec, PyObject *(*initfunc)(void)) +{ + if (initfunc == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + PyThreadState *tstate = _PyThreadState_GET(); + + PyObject *name = PyObject_GetAttr(spec, &_Py_ID(name)); + if (name == NULL) { + return NULL; + } + + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "spec name must be string, not %T", name); + Py_DECREF(name); + return NULL; + } + + PyObject *mod = create_builtin(tstate, name, spec, initfunc); + Py_DECREF(name); + return mod; +} /*****************************/ /* the builtin modules table */ @@ -3166,7 +3272,7 @@ bootstrap_imp(PyThreadState *tstate) } // Create the _imp module from its definition. - PyObject *mod = create_builtin(tstate, name, spec); + PyObject *mod = create_builtin(tstate, name, spec, NULL); Py_CLEAR(name); Py_DECREF(spec); if (mod == NULL) { @@ -3681,33 +3787,6 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) PyTime_t t1 = 0, accumulated_copy = accumulated; - PyObject *sys_path, *sys_meta_path, *sys_path_hooks; - if (PySys_GetOptionalAttrString("path", &sys_path) < 0) { - return NULL; - } - if (PySys_GetOptionalAttrString("meta_path", &sys_meta_path) < 0) { - Py_XDECREF(sys_path); - return NULL; - } - if (PySys_GetOptionalAttrString("path_hooks", &sys_path_hooks) < 0) { - Py_XDECREF(sys_meta_path); - Py_XDECREF(sys_path); - return NULL; - } - if (_PySys_Audit(tstate, "import", "OOOOO", - abs_name, Py_None, sys_path ? sys_path : Py_None, - sys_meta_path ? sys_meta_path : Py_None, - sys_path_hooks ? sys_path_hooks : Py_None) < 0) { - Py_XDECREF(sys_path_hooks); - Py_XDECREF(sys_meta_path); - Py_XDECREF(sys_path); - return NULL; - } - Py_XDECREF(sys_path_hooks); - Py_XDECREF(sys_meta_path); - Py_XDECREF(sys_path); - - /* XOptions is initialized after first some imports. * So we can't have negative cache before completed initialization. * Anyway, importlib._find_and_load is much slower than @@ -3760,7 +3839,6 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, PyObject *abs_name = NULL; PyObject *final_mod = NULL; PyObject *mod = NULL; - PyObject *package = NULL; PyInterpreterState *interp = tstate->interp; int has_from; @@ -3889,7 +3967,6 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, error: Py_XDECREF(abs_name); Py_XDECREF(mod); - Py_XDECREF(package); if (final_mod == NULL) { remove_importlib_frames(tstate); } @@ -4353,7 +4430,13 @@ _imp_create_builtin(PyObject *module, PyObject *spec) return NULL; } - PyObject *mod = create_builtin(tstate, name, spec); + if (PyUnicode_GetLength(name) == 0) { + PyErr_Format(PyExc_ValueError, "name must not be empty"); + Py_DECREF(name); + return NULL; + } + + PyObject *mod = create_builtin(tstate, name, spec, NULL); Py_DECREF(name); return mod; } @@ -4693,8 +4776,8 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) assert(!_PyErr_Occurred(tstate)); assert(cached != NULL); /* The module might not have md_def set in certain reload cases. */ - assert(_PyModule_GetDef(mod) == NULL - || cached->def == _PyModule_GetDef(mod)); + assert(_PyModule_GetDefOrNull(mod) == NULL + || cached->def == _PyModule_GetDefOrNull(mod)); assert_singlephase(cached); goto finally; } @@ -4719,7 +4802,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) } /* We would move this (and the fclose() below) into - * _PyImport_GetModInitFunc(), but it isn't clear if the intervening + * _PyImport_GetModuleExportHooks(), but it isn't clear if the intervening * code relies on fp still being open. */ FILE *fp; if (file != NULL) { @@ -4732,7 +4815,15 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) fp = NULL; } - PyModInitFunction p0 = _PyImport_GetModInitFunc(&info, fp); + PyModInitFunction p0 = NULL; + PyModExportFunction ex0 = NULL; + _PyImport_GetModuleExportHooks(&info, fp, &p0, &ex0); + if (ex0) { + mod = import_run_modexport(tstate, ex0, &info, spec); + // Modules created from slots handle GIL enablement (Py_mod_gil slot) + // when they're created. + goto cleanup; + } if (p0 == NULL) { goto finally; } @@ -4754,6 +4845,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) } #endif +cleanup: // XXX Shouldn't this happen in the error cases too (i.e. in "finally")? if (fp) { fclose(fp); diff --git a/Python/importdl.c b/Python/importdl.c index 802843fe7b9..537e8d869dc 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -5,38 +5,19 @@ #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_import.h" // _PyImport_SwapPackageContext() #include "pycore_importdl.h" -#include "pycore_moduleobject.h" // _PyModule_GetDef() +#include "pycore_moduleobject.h" // _PyModule_GetDefOrNull() #include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_runtime.h" // _Py_ID() -/* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is - supported on this platform. configure will then compile and link in one - of the dynload_*.c files, as appropriate. We will call a function in - those modules to get a function pointer to the module's init function. -*/ -#ifdef HAVE_DYNAMIC_LOADING - -#ifdef MS_WINDOWS -extern dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, - const char *shortname, - PyObject *pathname, - FILE *fp); -#else -extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, - const char *shortname, - const char *pathname, FILE *fp); -#endif - -#endif /* HAVE_DYNAMIC_LOADING */ - - /***********************************/ /* module info to use when loading */ /***********************************/ -static const char * const ascii_only_prefix = "PyInit"; -static const char * const nonascii_prefix = "PyInitU"; +static const struct hook_prefixes ascii_only_prefixes = { + "PyInit", "PyModExport"}; +static const struct hook_prefixes nonascii_prefixes = { + "PyInitU", "PyModExportU"}; /* Get the variable part of a module's export symbol name. * Returns a bytes instance. For non-ASCII-named modules, the name is @@ -45,7 +26,7 @@ static const char * const nonascii_prefix = "PyInitU"; * nonascii_prefix, as appropriate. */ static PyObject * -get_encoded_name(PyObject *name, const char **hook_prefix) { +get_encoded_name(PyObject *name, const struct hook_prefixes **hook_prefixes) { PyObject *tmp; PyObject *encoded = NULL; PyObject *modname = NULL; @@ -72,7 +53,7 @@ get_encoded_name(PyObject *name, const char **hook_prefix) { /* Encode to ASCII or Punycode, as needed */ encoded = PyUnicode_AsEncodedString(name, "ascii", NULL); if (encoded != NULL) { - *hook_prefix = ascii_only_prefix; + *hook_prefixes = &ascii_only_prefixes; } else { if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) { PyErr_Clear(); @@ -80,7 +61,7 @@ get_encoded_name(PyObject *name, const char **hook_prefix) { if (encoded == NULL) { goto error; } - *hook_prefix = nonascii_prefix; + *hook_prefixes = &nonascii_prefixes; } else { goto error; } @@ -130,7 +111,7 @@ _Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info, assert(PyUnicode_GetLength(name) > 0); info.name = Py_NewRef(name); - info.name_encoded = get_encoded_name(info.name, &info.hook_prefix); + info.name_encoded = get_encoded_name(info.name, &info.hook_prefixes); if (info.name_encoded == NULL) { _Py_ext_module_loader_info_clear(&info); return -1; @@ -175,7 +156,6 @@ _Py_ext_module_loader_info_init_for_builtin( PyObject *name) { assert(PyUnicode_Check(name)); - assert(PyUnicode_FindChar(name, '.', 0, PyUnicode_GetLength(name), -1) == -1); assert(PyUnicode_GetLength(name) > 0); PyObject *name_encoded = PyUnicode_AsEncodedString(name, "ascii", NULL); @@ -189,7 +169,7 @@ _Py_ext_module_loader_info_init_for_builtin( /* We won't need filename. */ .path=name, .origin=_Py_ext_module_origin_BUILTIN, - .hook_prefix=ascii_only_prefix, + .hook_prefixes=&ascii_only_prefixes, .newcontext=NULL, }; return 0; @@ -377,39 +357,66 @@ _Py_ext_module_loader_result_apply_error( /********************************************/ #ifdef HAVE_DYNAMIC_LOADING -PyModInitFunction -_PyImport_GetModInitFunc(struct _Py_ext_module_loader_info *info, - FILE *fp) +static dl_funcptr +findfuncptr(const char *prefix, const char *name_buf, + struct _Py_ext_module_loader_info *info, + FILE *fp) { +#ifdef MS_WINDOWS + return _PyImport_FindSharedFuncptrWindows( + prefix, name_buf, info->filename, fp); +#else + const char *path_buf = PyBytes_AS_STRING(info->filename_encoded); + return _PyImport_FindSharedFuncptr( + prefix, name_buf, path_buf, fp); +#endif +} + +int +_PyImport_GetModuleExportHooks( + struct _Py_ext_module_loader_info *info, + FILE *fp, + PyModInitFunction *modinit, + PyModExportFunction *modexport) +{ + *modinit = NULL; + *modexport = NULL; + const char *name_buf = PyBytes_AS_STRING(info->name_encoded); dl_funcptr exportfunc; -#ifdef MS_WINDOWS - exportfunc = _PyImport_FindSharedFuncptrWindows( - info->hook_prefix, name_buf, info->filename, fp); -#else - { - const char *path_buf = PyBytes_AS_STRING(info->filename_encoded); - exportfunc = _PyImport_FindSharedFuncptr( - info->hook_prefix, name_buf, path_buf, fp); - } -#endif - if (exportfunc == NULL) { - if (!PyErr_Occurred()) { - PyObject *msg; - msg = PyUnicode_FromFormat( - "dynamic module does not define " - "module export function (%s_%s)", - info->hook_prefix, name_buf); - if (msg != NULL) { - PyErr_SetImportError(msg, info->name, info->filename); - Py_DECREF(msg); - } + exportfunc = findfuncptr( + info->hook_prefixes->export_prefix, + name_buf, info, fp); + if (exportfunc) { + *modexport = (PyModExportFunction)exportfunc; + return 2; + } + if (PyErr_Occurred()) { + return -1; + } + + exportfunc = findfuncptr( + info->hook_prefixes->init_prefix, + name_buf, info, fp); + if (exportfunc) { + *modinit = (PyModInitFunction)exportfunc; + return 1; + } + + if (!PyErr_Occurred()) { + PyObject *msg; + msg = PyUnicode_FromFormat( + "dynamic module does not define " + "module export function (%s_%s or %s_%s)", + info->hook_prefixes->export_prefix, name_buf, + info->hook_prefixes->init_prefix, name_buf); + if (msg != NULL) { + PyErr_SetImportError(msg, info->name, info->filename); + Py_DECREF(msg); } - return NULL; } - - return (PyModInitFunction)exportfunc; + return -1; } #endif /* HAVE_DYNAMIC_LOADING */ @@ -477,7 +484,7 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, res.def = (PyModuleDef *)m; /* Run PyModule_FromDefAndSpec() to finish loading the module. */ } - else if (info->hook_prefix == nonascii_prefix) { + else if (info->hook_prefixes == &nonascii_prefixes) { /* Non-ASCII is only supported for multi-phase init. */ res.kind = _Py_ext_module_kind_MULTIPHASE; /* Don't allow legacy init for non-ASCII module names. */ @@ -496,7 +503,7 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, goto error; } - res.def = _PyModule_GetDef(m); + res.def = _PyModule_GetDefOrNull(m); if (res.def == NULL) { PyErr_Clear(); _Py_ext_module_loader_result_set_error( diff --git a/Python/initconfig.c b/Python/initconfig.c index cc0db19d416..7176670c110 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -239,9 +239,11 @@ static const PyConfigSpec PYPRECONFIG_SPEC[] = { // Forward declarations -static PyObject* -config_get(const PyConfig *config, const PyConfigSpec *spec, - int use_sys); +static PyObject* config_get(const PyConfig *config, const PyConfigSpec *spec, + int use_sys); +static void initconfig_free_wstr(wchar_t *member); +static void initconfig_free_wstr_list(PyWideStringList *list); +static void initconfig_free_config(const PyConfig *config); /* --- Command line options --------------------------------------- */ @@ -256,6 +258,7 @@ static const char usage_help[] = "\ Options (and corresponding environment variables):\n\ -b : issue warnings about converting bytes/bytearray to str and comparing\n\ bytes/bytearray with str or bytes with int. (-bb: issue errors)\n\ + deprecated since 3.15 and will become no-op in 3.17.\n\ -B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\ -c cmd : program passed in as string (terminates option list)\n\ -d : turn on parser debugging output (for experts only, only works on\n\ @@ -2807,12 +2810,6 @@ _PyConfig_Write(const PyConfig *config, _PyRuntimeState *runtime) return _PyStatus_NO_MEMORY(); } -#ifdef Py_STATS - if (config->_pystats) { - _Py_StatsOn(); - } -#endif - return _PyStatus_OK(); } @@ -3725,6 +3722,9 @@ PyInitConfig_Free(PyInitConfig *config) if (config == NULL) { return; } + + initconfig_free_config(&config->config); + PyMem_RawFree(config->inittab); free(config->err_msg); free(config); } @@ -4093,13 +4093,51 @@ PyInitConfig_SetStr(PyInitConfig *config, const char *name, const char* value) } +static void +initconfig_free_wstr(wchar_t *member) +{ + if (member) { + free(member); + } +} + + +static void +initconfig_free_wstr_list(PyWideStringList *list) +{ + for (Py_ssize_t i = 0; i < list->length; i++) { + free(list->items[i]); + } + free(list->items); +} + + +static void +initconfig_free_config(const PyConfig *config) +{ + const PyConfigSpec *spec = PYCONFIG_SPEC; + for (; spec->name != NULL; spec++) { + void *member = config_get_spec_member(config, spec); + if (spec->type == PyConfig_MEMBER_WSTR + || spec->type == PyConfig_MEMBER_WSTR_OPT) + { + wchar_t *wstr = *(wchar_t **)member; + initconfig_free_wstr(wstr); + } + else if (spec->type == PyConfig_MEMBER_WSTR_LIST) { + initconfig_free_wstr_list(member); + } + } +} + + static int -_PyWideStringList_FromUTF8(PyInitConfig *config, PyWideStringList *list, - Py_ssize_t length, char * const *items) +initconfig_set_str_list(PyInitConfig *config, PyWideStringList *list, + Py_ssize_t length, char * const *items) { PyWideStringList wlist = _PyWideStringList_INIT; size_t size = sizeof(wchar_t*) * length; - wlist.items = (wchar_t **)PyMem_RawMalloc(size); + wlist.items = (wchar_t **)malloc(size); if (wlist.items == NULL) { config->status = _PyStatus_NO_MEMORY(); return -1; @@ -4108,14 +4146,14 @@ _PyWideStringList_FromUTF8(PyInitConfig *config, PyWideStringList *list, for (Py_ssize_t i = 0; i < length; i++) { wchar_t *arg = utf8_to_wstr(config, items[i]); if (arg == NULL) { - _PyWideStringList_Clear(&wlist); + initconfig_free_wstr_list(&wlist); return -1; } wlist.items[i] = arg; wlist.length++; } - _PyWideStringList_Clear(list); + initconfig_free_wstr_list(list); *list = wlist; return 0; } @@ -4136,7 +4174,7 @@ PyInitConfig_SetStrList(PyInitConfig *config, const char *name, return -1; } PyWideStringList *list = raw_member; - if (_PyWideStringList_FromUTF8(config, list, length, items) < 0) { + if (initconfig_set_str_list(config, list, length, items) < 0) { return -1; } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index b4b2bc5dc69..9e750433cff 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -18,6 +18,7 @@ #include "pycore_tuple.h" // _PyTuple_FromArraySteal() #include "opcode_ids.h" +#include "pycore_optimizer.h" /* Uncomment this to dump debugging output when assertions fail */ @@ -190,7 +191,7 @@ is_instrumented(int opcode) { assert(opcode != 0); assert(opcode != RESERVED); - return opcode != ENTER_EXECUTOR && opcode >= MIN_INSTRUMENTED_OPCODE; + return opcode < ENTER_EXECUTOR && opcode >= MIN_INSTRUMENTED_OPCODE; } #ifndef NDEBUG @@ -525,7 +526,7 @@ valid_opcode(int opcode) if (IS_VALID_OPCODE(opcode) && opcode != CACHE && opcode != RESERVED && - opcode < 255) + opcode < 254) { return true; } @@ -1785,6 +1786,7 @@ force_instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp) _PyCode_Clear_Executors(code); } _Py_Executors_InvalidateDependency(interp, code, 1); + _PyJit_Tracer_InvalidateDependency(PyThreadState_GET(), code); #endif int code_len = (int)Py_SIZE(code); /* Exit early to avoid creating instrumentation @@ -2019,12 +2021,12 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) if (existing_events == events) { return 0; } - set_events(&interp->monitors, tool_id, events); uint32_t new_version = global_version(interp) + MONITORING_VERSION_INCREMENT; if (new_version == 0) { PyErr_Format(PyExc_OverflowError, "events set too many times"); return -1; } + set_events(&interp->monitors, tool_id, events); set_global_version(tstate, new_version); #ifdef _Py_TIER2 _Py_Executors_InvalidateAll(interp, 1); diff --git a/Python/intrinsics.c b/Python/intrinsics.c index 8ea920e690c..9cfc285c6a5 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -9,7 +9,6 @@ #include "pycore_intrinsics.h" // INTRINSIC_PRINT #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_runtime.h" // _Py_ID() -#include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_typevarobject.h" // _Py_make_typevar() #include "pycore_unicodeobject.h" // _PyUnicode_FromASCII() @@ -192,7 +191,7 @@ static PyObject * list_to_tuple(PyThreadState* unused, PyObject *v) { assert(PyList_Check(v)); - return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v)); + return PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v)); } static PyObject * diff --git a/Python/jit.c b/Python/jit.c index 01ec9c1fa6e..ccafe0ce497 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -16,6 +16,7 @@ #include "pycore_intrinsics.h" #include "pycore_list.h" #include "pycore_long.h" +#include "pycore_mmap.h" #include "pycore_opcode_metadata.h" #include "pycore_opcode_utils.h" #include "pycore_optimizer.h" @@ -60,6 +61,10 @@ jit_error(const char *message) static unsigned char * jit_alloc(size_t size) { + if (size > PY_MAX_JIT_CODE_SIZE) { + jit_error("code too big; refactor bytecodes.c to keep uop size down, or reduce maximum trace length."); + return NULL; + } assert(size); assert(size % get_page_size() == 0); #ifdef MS_WINDOWS @@ -71,6 +76,9 @@ jit_alloc(size_t size) int prot = PROT_READ | PROT_WRITE; unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0); int failed = memory == MAP_FAILED; + if (!failed) { + _PyAnnotateMemoryMap(memory, size, "cpython:jit"); + } #endif if (failed) { jit_error("unable to allocate memory"); @@ -126,7 +134,8 @@ mark_executable(unsigned char *memory, size_t size) // JIT compiler stuff: ///////////////////////////////////////////////////////// -#define SYMBOL_MASK_WORDS 4 +#define GOT_SLOT_SIZE sizeof(uintptr_t) +#define SYMBOL_MASK_WORDS 8 typedef uint32_t symbol_mask[SYMBOL_MASK_WORDS]; @@ -134,10 +143,11 @@ typedef struct { unsigned char *mem; symbol_mask mask; size_t size; -} trampoline_state; +} symbol_state; typedef struct { - trampoline_state trampolines; + symbol_state trampolines; + symbol_state got_symbols; uintptr_t instruction_starts[UOP_MAX_TRACE_LENGTH]; } jit_state; @@ -157,21 +167,30 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start, uint8_t width) { assert(loc_start + width <= 32); + uint32_t temp_val; + // Use memcpy to safely read the value, avoiding potential alignment + // issues and strict aliasing violations. + memcpy(&temp_val, loc, sizeof(temp_val)); // Clear the bits we're about to patch: - *loc &= ~(((1ULL << width) - 1) << loc_start); - assert(get_bits(*loc, loc_start, width) == 0); + temp_val &= ~(((1ULL << width) - 1) << loc_start); + assert(get_bits(temp_val, loc_start, width) == 0); // Patch the bits: - *loc |= get_bits(value, value_start, width) << loc_start; - assert(get_bits(*loc, loc_start, width) == get_bits(value, value_start, width)); + temp_val |= get_bits(value, value_start, width) << loc_start; + assert(get_bits(temp_val, loc_start, width) == get_bits(value, value_start, width)); + // Safely write the modified value back to memory. + memcpy(loc, &temp_val, sizeof(temp_val)); } // See https://developer.arm.com/documentation/ddi0602/2023-09/Base-Instructions // for instruction encodings: -#define IS_AARCH64_ADD_OR_SUB(I) (((I) & 0x11C00000) == 0x11000000) -#define IS_AARCH64_ADRP(I) (((I) & 0x9F000000) == 0x90000000) -#define IS_AARCH64_BRANCH(I) (((I) & 0x7C000000) == 0x14000000) -#define IS_AARCH64_LDR_OR_STR(I) (((I) & 0x3B000000) == 0x39000000) -#define IS_AARCH64_MOV(I) (((I) & 0x9F800000) == 0x92800000) +#define IS_AARCH64_ADD_OR_SUB(I) (((I) & 0x11C00000) == 0x11000000) +#define IS_AARCH64_ADRP(I) (((I) & 0x9F000000) == 0x90000000) +#define IS_AARCH64_BRANCH(I) (((I) & 0x7C000000) == 0x14000000) +#define IS_AARCH64_BRANCH_COND(I) (((I) & 0x7C000000) == 0x54000000) +#define IS_AARCH64_BRANCH_ZERO(I) (((I) & 0x7E000000) == 0x34000000) +#define IS_AARCH64_TEST_AND_BRANCH(I) (((I) & 0x7E000000) == 0x36000000) +#define IS_AARCH64_LDR_OR_STR(I) (((I) & 0x3B000000) == 0x39000000) +#define IS_AARCH64_MOV(I) (((I) & 0x9F800000) == 0x92800000) // LLD is a great reference for performing relocations... just keep in // mind that Tools/jit/build.py does filtering and preprocessing for us! @@ -193,6 +212,33 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start, // - x86_64-unknown-linux-gnu: // - https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/X86_64.cpp + +// Get the symbol slot memory location for a given symbol ordinal. +static unsigned char * +get_symbol_slot(int ordinal, symbol_state *state, int size) +{ + const uint32_t symbol_mask = 1U << (ordinal % 32); + const uint32_t state_mask = state->mask[ordinal / 32]; + assert(symbol_mask & state_mask); + + // Count the number of set bits in the symbol mask lower than ordinal + size_t index = _Py_popcount32(state_mask & (symbol_mask - 1)); + for (int i = 0; i < ordinal / 32; i++) { + index += _Py_popcount32(state->mask[i]); + } + + unsigned char *slot = state->mem + index * size; + assert((size_t)(index + 1) * size <= state->size); + return slot; +} + +// Return the address of the GOT slot for the requested symbol ordinal. +static uintptr_t +got_symbol_address(int ordinal, jit_state *state) +{ + return (uintptr_t)get_symbol_slot(ordinal, &state->got_symbols, GOT_SLOT_SIZE); +} + // Many of these patches are "relaxing", meaning that they can rewrite the // code they're patching to be more efficient (like turning a 64-bit memory // load into a 32-bit immediate load). These patches have an "x" in their name. @@ -202,30 +248,29 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start, void patch_32(unsigned char *location, uint64_t value) { - uint32_t *loc32 = (uint32_t *)location; // Check that we're not out of range of 32 unsigned bits: assert(value < (1ULL << 32)); - *loc32 = (uint32_t)value; + uint32_t final_value = (uint32_t)value; + memcpy(location, &final_value, sizeof(final_value)); } // 32-bit relative address. void patch_32r(unsigned char *location, uint64_t value) { - uint32_t *loc32 = (uint32_t *)location; value -= (uintptr_t)location; // Check that we're not out of range of 32 signed bits: assert((int64_t)value >= -(1LL << 31)); assert((int64_t)value < (1LL << 31)); - *loc32 = (uint32_t)value; + uint32_t final_value = (uint32_t)value; + memcpy(location, &final_value, sizeof(final_value)); } // 64-bit absolute address. void patch_64(unsigned char *location, uint64_t value) { - uint64_t *loc64 = (uint64_t *)location; - *loc64 = value; + memcpy(location, &value, sizeof(value)); } // 12-bit low part of an absolute address. Pairs nicely with patch_aarch64_21r @@ -332,6 +377,21 @@ patch_aarch64_21rx(unsigned char *location, uint64_t value) patch_aarch64_21r(location, value); } +// 21-bit relative branch. +void +patch_aarch64_19r(unsigned char *location, uint64_t value) +{ + uint32_t *loc32 = (uint32_t *)location; + assert(IS_AARCH64_BRANCH_COND(*loc32) || IS_AARCH64_BRANCH_ZERO(*loc32)); + value -= (uintptr_t)location; + // Check that we're not out of range of 21 signed bits: + assert((int64_t)value >= -(1 << 20)); + assert((int64_t)value < (1 << 20)); + // Since instructions are 4-byte aligned, only use 19 bits: + assert(get_bits(value, 0, 2) == 0); + set_bits(loc32, 5, value, 2, 19); +} + // 28-bit relative branch. void patch_aarch64_26r(unsigned char *location, uint64_t value) @@ -372,6 +432,15 @@ patch_aarch64_33rx(unsigned char *location, uint64_t value) loc32[1] = 0xF2A00000 | (get_bits(relaxed, 16, 16) << 5) | reg; return; } + int64_t page_delta = (relaxed >> 12) - ((uintptr_t)location >> 12); + if (page_delta >= -(1L << 20) && + page_delta < (1L << 20)) + { + // adrp reg, AAA; ldr reg, [reg + BBB] -> adrp reg, AAA; add reg, reg, BBB + patch_aarch64_21rx(location, relaxed); + loc32[1] = 0x91000000 | get_bits(relaxed, 0, 12) << 10 | reg << 5 | reg; + return; + } relaxed = value - (uintptr_t)location; if ((relaxed & 0x3) == 0 && (int64_t)relaxed >= -(1L << 19) && @@ -393,7 +462,10 @@ patch_x86_64_32rx(unsigned char *location, uint64_t value) { uint8_t *loc8 = (uint8_t *)location; // Try to relax the GOT load into an immediate value: - uint64_t relaxed = *(uint64_t *)(value + 4) - 4; + uint64_t relaxed; + memcpy(&relaxed, (void *)(value + 4), sizeof(relaxed)); + relaxed -= 4; + if ((int64_t)relaxed - (int64_t)location >= -(1LL << 31) && (int64_t)relaxed - (int64_t)location + 1 < (1LL << 31)) { @@ -418,18 +490,34 @@ patch_x86_64_32rx(unsigned char *location, uint64_t value) patch_32r(location, value); } +void patch_got_symbol(jit_state *state, int ordinal); void patch_aarch64_trampoline(unsigned char *location, int ordinal, jit_state *state); +void patch_x86_64_trampoline(unsigned char *location, int ordinal, jit_state *state); #include "jit_stencils.h" #if defined(__aarch64__) || defined(_M_ARM64) #define TRAMPOLINE_SIZE 16 #define DATA_ALIGN 8 +#elif defined(__x86_64__) && defined(__APPLE__) + // LLVM 20 on macOS x86_64 debug builds: GOT entries may exceed ±2GB PC-relative + // range. + #define TRAMPOLINE_SIZE 16 // 14 bytes + 2 bytes padding for alignment + #define DATA_ALIGN 8 #else #define TRAMPOLINE_SIZE 0 #define DATA_ALIGN 1 #endif +// Populate the GOT entry for the given symbol ordinal with its resolved address. +void +patch_got_symbol(jit_state *state, int ordinal) +{ + uint64_t value = (uintptr_t)symbols_map[ordinal]; + unsigned char *location = (unsigned char *)get_symbol_slot(ordinal, &state->got_symbols, GOT_SLOT_SIZE); + patch_64(location, value); +} + // Generate and patch AArch64 trampolines. The symbols to jump to are stored // in the jit_stencils.h in the symbols_map. void @@ -446,21 +534,8 @@ patch_aarch64_trampoline(unsigned char *location, int ordinal, jit_state *state) return; } - // Masking is done modulo 32 as the mask is stored as an array of uint32_t - const uint32_t symbol_mask = 1 << (ordinal % 32); - const uint32_t trampoline_mask = state->trampolines.mask[ordinal / 32]; - assert(symbol_mask & trampoline_mask); - - // Count the number of set bits in the trampoline mask lower than ordinal, - // this gives the index into the array of trampolines. - int index = _Py_popcount32(trampoline_mask & (symbol_mask - 1)); - for (int i = 0; i < ordinal / 32; i++) { - index += _Py_popcount32(state->trampolines.mask[i]); - } - - uint32_t *p = (uint32_t*)(state->trampolines.mem + index * TRAMPOLINE_SIZE); - assert((size_t)(index + 1) * TRAMPOLINE_SIZE <= state->trampolines.size); - + // Out of range - need a trampoline + uint32_t *p = (uint32_t *)get_symbol_slot(ordinal, &state->trampolines, TRAMPOLINE_SIZE); /* Generate the trampoline 0: 58000048 ldr x8, 8 @@ -476,6 +551,37 @@ patch_aarch64_trampoline(unsigned char *location, int ordinal, jit_state *state) patch_aarch64_26r(location, (uintptr_t)p); } +// Generate and patch x86_64 trampolines. +void +patch_x86_64_trampoline(unsigned char *location, int ordinal, jit_state *state) +{ + uint64_t value = (uintptr_t)symbols_map[ordinal]; + int64_t range = (int64_t)value - 4 - (int64_t)location; + + // If we are in range of 32 signed bits, we can patch directly + if (range >= -(1LL << 31) && range < (1LL << 31)) { + patch_32r(location, value - 4); + return; + } + + // Out of range - need a trampoline + unsigned char *trampoline = get_symbol_slot(ordinal, &state->trampolines, TRAMPOLINE_SIZE); + + /* Generate the trampoline (14 bytes, padded to 16): + 0: ff 25 00 00 00 00 jmp *(%rip) + 6: XX XX XX XX XX XX XX XX (64-bit target address) + + Reference: https://wiki.osdev.org/X86-64_Instruction_Encoding#FF (JMP r/m64) + */ + trampoline[0] = 0xFF; + trampoline[1] = 0x25; + memset(trampoline + 2, 0, 4); + memcpy(trampoline + 6, &value, 8); + + // Patch the call site to call the trampoline instead + patch_32r(location, (uintptr_t)trampoline - 4); +} + static void combine_symbol_mask(const symbol_mask src, symbol_mask dest) { @@ -501,21 +607,26 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz code_size += group->code_size; data_size += group->data_size; combine_symbol_mask(group->trampoline_mask, state.trampolines.mask); + combine_symbol_mask(group->got_mask, state.got_symbols.mask); } - group = &stencil_groups[_FATAL_ERROR]; + group = &stencil_groups[_FATAL_ERROR_r00]; code_size += group->code_size; data_size += group->data_size; combine_symbol_mask(group->trampoline_mask, state.trampolines.mask); + combine_symbol_mask(group->got_mask, state.got_symbols.mask); // Calculate the size of the trampolines required by the whole trace for (size_t i = 0; i < Py_ARRAY_LENGTH(state.trampolines.mask); i++) { state.trampolines.size += _Py_popcount32(state.trampolines.mask[i]) * TRAMPOLINE_SIZE; } + for (size_t i = 0; i < Py_ARRAY_LENGTH(state.got_symbols.mask); i++) { + state.got_symbols.size += _Py_popcount32(state.got_symbols.mask[i]) * GOT_SLOT_SIZE; + } // Round up to the nearest page: size_t page_size = get_page_size(); assert((page_size & (page_size - 1)) == 0); size_t code_padding = DATA_ALIGN - ((code_size + state.trampolines.size) & (DATA_ALIGN - 1)); - size_t padding = page_size - ((code_size + state.trampolines.size + code_padding + data_size) & (page_size - 1)); - size_t total_size = code_size + state.trampolines.size + code_padding + data_size + padding; + size_t padding = page_size - ((code_size + state.trampolines.size + code_padding + data_size + state.got_symbols.size) & (page_size - 1)); + size_t total_size = code_size + state.trampolines.size + code_padding + data_size + state.got_symbols.size + padding; unsigned char *memory = jit_alloc(total_size); if (memory == NULL) { return -1; @@ -525,6 +636,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz OPT_STAT_ADD(jit_code_size, code_size); OPT_STAT_ADD(jit_trampoline_size, state.trampolines.size); OPT_STAT_ADD(jit_data_size, data_size); + OPT_STAT_ADD(jit_got_size, state.got_symbols.size); OPT_STAT_ADD(jit_padding_size, padding); OPT_HIST(total_size, trace_total_memory_hist); // Update the offsets of each instruction: @@ -535,7 +647,8 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz unsigned char *code = memory; state.trampolines.mem = memory + code_size; unsigned char *data = memory + code_size + state.trampolines.size + code_padding; - assert(trace[0].opcode == _START_EXECUTOR || trace[0].opcode == _COLD_EXIT); + assert(trace[0].opcode == _START_EXECUTOR_r00 || trace[0].opcode == _COLD_EXIT_r00 || trace[0].opcode == _COLD_DYNAMIC_EXIT_r00); + state.got_symbols.mem = data + data_size; for (size_t i = 0; i < length; i++) { const _PyUOpInstruction *instruction = &trace[i]; group = &stencil_groups[instruction->opcode]; @@ -544,7 +657,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz data += group->data_size; } // Protect against accidental buffer overrun into data: - group = &stencil_groups[_FATAL_ERROR]; + group = &stencil_groups[_FATAL_ERROR_r00]; group->emit(code, data, executor, NULL, &state); code += group->code_size; data += group->data_size; @@ -576,12 +689,13 @@ compile_trampoline(void) code_size += group->code_size; data_size += group->data_size; combine_symbol_mask(group->trampoline_mask, state.trampolines.mask); + combine_symbol_mask(group->got_mask, state.got_symbols.mask); // Round up to the nearest page: size_t page_size = get_page_size(); assert((page_size & (page_size - 1)) == 0); size_t code_padding = DATA_ALIGN - ((code_size + state.trampolines.size) & (DATA_ALIGN - 1)); - size_t padding = page_size - ((code_size + state.trampolines.size + code_padding + data_size) & (page_size - 1)); - size_t total_size = code_size + state.trampolines.size + code_padding + data_size + padding; + size_t padding = page_size - ((code_size + state.trampolines.size + code_padding + data_size + state.got_symbols.size) & (page_size - 1)); + size_t total_size = code_size + state.trampolines.size + code_padding + data_size + state.got_symbols.size + padding; unsigned char *memory = jit_alloc(total_size); if (memory == NULL) { return NULL; @@ -589,6 +703,7 @@ compile_trampoline(void) unsigned char *code = memory; state.trampolines.mem = memory + code_size; unsigned char *data = memory + code_size + state.trampolines.size + code_padding; + state.got_symbols.mem = data + data_size; // Compile the shim, which handles converting between the native // calling convention and the calling convention used by jitted code // (which may be different for efficiency reasons). diff --git a/Python/lock.c b/Python/lock.c index a49d587a168..789065d8162 100644 --- a/Python/lock.c +++ b/Python/lock.c @@ -6,6 +6,7 @@ #include "pycore_parking_lot.h" #include "pycore_semaphore.h" #include "pycore_time.h" // _PyTime_Add() +#include "pycore_stats.h" // FT_STAT_MUTEX_SLEEP_INC() #ifdef MS_WINDOWS # ifndef WIN32_LEAN_AND_MEAN @@ -62,6 +63,8 @@ _PyMutex_LockTimed(PyMutex *m, PyTime_t timeout, _PyLockFlags flags) return PY_LOCK_FAILURE; } + FT_STAT_MUTEX_SLEEP_INC(); + PyTime_t now; // silently ignore error: cannot report error to the caller (void)PyTime_MonotonicRaw(&now); @@ -227,7 +230,7 @@ _PyRawMutex_LockSlow(_PyRawMutex *m) // Wait for us to be woken up. Note that we still have to lock the // mutex ourselves: it is NOT handed off to us. - _PySemaphore_Wait(&waiter.sema, -1, /*detach=*/0); + _PySemaphore_Wait(&waiter.sema, -1); } _PySemaphore_Destroy(&waiter.sema); diff --git a/Python/marshal.c b/Python/marshal.c index 4f444d4671c..69d6dd7cf0f 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -11,6 +11,7 @@ #include "pycore_code.h" // _PyCode_New() #include "pycore_hashtable.h" // _Py_hashtable_t #include "pycore_long.h" // _PyLong_IsZero() +#include "pycore_object.h" // _PyObject_IsUniquelyReferenced #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_setobject.h" // _PySet_NextEntryRef() #include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal() @@ -309,7 +310,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) } if (!long_export.digits) { int8_t sign = long_export.value < 0 ? -1 : 1; - uint64_t abs_value = Py_ABS(long_export.value); + uint64_t abs_value = _Py_ABS_CAST(uint64_t, long_export.value); uint64_t d = abs_value; long l = 0; @@ -388,7 +389,7 @@ w_ref(PyObject *v, char *flag, WFILE *p) * But we use TYPE_REF always for interned string, to PYC file stable * as possible. */ - if (Py_REFCNT(v) == 1 && + if (_PyObject_IsUniquelyReferenced(v) && !(PyUnicode_CheckExact(v) && PyUnicode_CHECK_INTERNED(v))) { return 0; } diff --git a/Python/modsupport.c b/Python/modsupport.c index 437ad412027..239c6c6a1b3 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_object.h" // _PyType_IsReady() +#include "pycore_unicodeobject.h" // _PyUnicodeWriter_FormatV() typedef double va_double; @@ -33,6 +34,19 @@ _Py_convert_optional_to_ssize_t(PyObject *obj, void *result) return 1; } +int +_Py_convert_optional_to_non_negative_ssize_t(PyObject *obj, void *result) +{ + if (!_Py_convert_optional_to_ssize_t(obj, result)) { + return 0; + } + if (obj != Py_None && *((Py_ssize_t *)result) < 0) { + PyErr_SetString(PyExc_ValueError, "argument cannot be negative"); + return 0; + } + return 1; +} + /* Helper for mkvalue() to scan the length of a format */ @@ -655,6 +669,116 @@ PyModule_AddType(PyObject *module, PyTypeObject *type) return PyModule_AddObjectRef(module, name, (PyObject *)type); } +static int _abiinfo_raise(const char *module_name, const char *format, ...) +{ + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (!writer) { + return -1; + } + if (module_name) { + if (PyUnicodeWriter_WriteUTF8(writer, module_name, -1) < 0) { + PyUnicodeWriter_Discard(writer); + return -1; + } + if (PyUnicodeWriter_WriteASCII(writer, ": ", 2) < 0) { + PyUnicodeWriter_Discard(writer); + return -1; + } + } + va_list vargs; + va_start(vargs, format); + if (_PyUnicodeWriter_FormatV(writer, format, vargs) < 0) { + PyUnicodeWriter_Discard(writer); + return -1; + } + PyObject *message = PyUnicodeWriter_Finish(writer); + if (!message) { + return -1; + } + PyErr_SetObject(PyExc_ImportError, message); + Py_DECREF(message); + return -1; +} + +int PyABIInfo_Check(PyABIInfo *info, const char *module_name) +{ + if (!info) { + return _abiinfo_raise(module_name, "NULL PyABIInfo"); + } + + /* abiinfo_major_version */ + if (info->abiinfo_major_version == 0) { + return 0; + } + if (info->abiinfo_major_version > 1) { + return _abiinfo_raise(module_name, "PyABIInfo version too high"); + } + + /* Internal ABI */ + if (info->flags & PyABIInfo_INTERNAL) { + if (info->abi_version && (info->abi_version != PY_VERSION_HEX)) { + return _abiinfo_raise( + module_name, + "incompatible internal ABI (0x%x != 0x%x)", + info->abi_version, PY_VERSION_HEX); + } + } + +#define XY_MASK 0xffff0000 + if (info->flags & PyABIInfo_STABLE) { + /* Greater-than major.minor version check */ + if (info->abi_version) { + if ((info->abi_version & XY_MASK) > (PY_VERSION_HEX & XY_MASK)) { + return _abiinfo_raise( + module_name, + "incompatible future stable ABI version (%d.%d)", + ((info->abi_version) >> 24) % 0xff, + ((info->abi_version) >> 16) % 0xff); + } + if (info->abi_version < Py_PACK_VERSION(3, 2)) { + return _abiinfo_raise( + module_name, + "invalid stable ABI version (%d.%d)", + ((info->abi_version) >> 24) % 0xff, + ((info->abi_version) >> 16) % 0xff); + } + } + if (info->flags & PyABIInfo_INTERNAL) { + return _abiinfo_raise(module_name, + "cannot use both internal and stable ABI"); + } + } + else { + /* Exact major.minor version check */ + if (info->abi_version) { + if ((info->abi_version & XY_MASK) != (PY_VERSION_HEX & XY_MASK)) { + return _abiinfo_raise( + module_name, + "incompatible ABI version (%d.%d)", + ((info->abi_version) >> 24) % 0xff, + ((info->abi_version) >> 16) % 0xff); + } + } + } +#undef XY_MASK + + /* Free-threading/GIL */ + uint16_t gilflags = info->flags & (PyABIInfo_GIL | PyABIInfo_FREETHREADED); +#if Py_GIL_DISABLED + if (gilflags == PyABIInfo_GIL) { + return _abiinfo_raise(module_name, + "incompatible with free-threaded CPython"); + } +#else + if (gilflags == PyABIInfo_FREETHREADED) { + return _abiinfo_raise(module_name, + "only compatible with free-threaded CPython"); + } +#endif + + return 0; +} + /* Exported functions for version helper macros */ diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 1d6dcddab4b..b2fa7d01e8f 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -1,5 +1,5 @@ -#if !Py_TAIL_CALL_INTERP -static void *opcode_targets[256] = { +#if !_Py_TAIL_CALL_INTERP +static void *opcode_targets_table[256] = { &&TARGET_CACHE, &&TARGET_BINARY_SLICE, &&TARGET_BUILD_TEMPLATE, @@ -233,7 +233,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_END_SEND, @@ -256,9 +255,272 @@ static void *opcode_targets[256] = { &&TARGET_INSTRUMENTED_JUMP_BACKWARD, &&TARGET_INSTRUMENTED_LINE, &&TARGET_ENTER_EXECUTOR, + &&TARGET_TRACE_RECORD, }; -#else /* Py_TAIL_CALL_INTERP */ -static py_tail_call_funcptr INSTRUCTION_TABLE[256]; +#if _Py_TIER2 +static void *opcode_tracing_targets_table[256] = { + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, +}; +#endif +#else /* _Py_TAIL_CALL_INTERP */ +static py_tail_call_funcptr instruction_funcptr_handler_table[256]; + +static py_tail_call_funcptr instruction_funcptr_tracing_table[256]; Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_2_error(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_1_error(TAIL_CALL_PARAMS); @@ -266,6 +528,7 @@ Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_error(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exception_unwind(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exit_unwind(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_start_frame(TAIL_CALL_PARAMS); +Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_stop_tracing(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_FLOAT(TAIL_CALL_PARAMS); @@ -482,6 +745,7 @@ Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_INT(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_LIST(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_NONE(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_STR(TAIL_CALL_PARAMS); +Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TRACE_RECORD(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_INVERT(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NEGATIVE(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NOT(TAIL_CALL_PARAMS); @@ -503,7 +767,7 @@ Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNKNOWN_OPCODE(TAIL_CALL_PARAMS) JUMP_TO_LABEL(error); } -static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { +static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [BINARY_OP] = _TAIL_CALL_BINARY_OP, [BINARY_OP_ADD_FLOAT] = _TAIL_CALL_BINARY_OP_ADD_FLOAT, [BINARY_OP_ADD_INT] = _TAIL_CALL_BINARY_OP_ADD_INT, @@ -719,6 +983,7 @@ static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { [TO_BOOL_LIST] = _TAIL_CALL_TO_BOOL_LIST, [TO_BOOL_NONE] = _TAIL_CALL_TO_BOOL_NONE, [TO_BOOL_STR] = _TAIL_CALL_TO_BOOL_STR, + [TRACE_RECORD] = _TAIL_CALL_TRACE_RECORD, [UNARY_INVERT] = _TAIL_CALL_UNARY_INVERT, [UNARY_NEGATIVE] = _TAIL_CALL_UNARY_NEGATIVE, [UNARY_NOT] = _TAIL_CALL_UNARY_NOT, @@ -759,6 +1024,263 @@ static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { [230] = _TAIL_CALL_UNKNOWN_OPCODE, [231] = _TAIL_CALL_UNKNOWN_OPCODE, [232] = _TAIL_CALL_UNKNOWN_OPCODE, - [233] = _TAIL_CALL_UNKNOWN_OPCODE, }; -#endif /* Py_TAIL_CALL_INTERP */ +static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { + [BINARY_OP] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_ADD_FLOAT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_ADD_INT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_ADD_UNICODE] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_EXTEND] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_INPLACE_ADD_UNICODE] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_MULTIPLY_FLOAT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_MULTIPLY_INT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBSCR_DICT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBSCR_GETITEM] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBSCR_LIST_INT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBSCR_LIST_SLICE] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBSCR_STR_INT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBSCR_TUPLE_INT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBTRACT_FLOAT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_OP_SUBTRACT_INT] = _TAIL_CALL_TRACE_RECORD, + [BINARY_SLICE] = _TAIL_CALL_TRACE_RECORD, + [BUILD_INTERPOLATION] = _TAIL_CALL_TRACE_RECORD, + [BUILD_LIST] = _TAIL_CALL_TRACE_RECORD, + [BUILD_MAP] = _TAIL_CALL_TRACE_RECORD, + [BUILD_SET] = _TAIL_CALL_TRACE_RECORD, + [BUILD_SLICE] = _TAIL_CALL_TRACE_RECORD, + [BUILD_STRING] = _TAIL_CALL_TRACE_RECORD, + [BUILD_TEMPLATE] = _TAIL_CALL_TRACE_RECORD, + [BUILD_TUPLE] = _TAIL_CALL_TRACE_RECORD, + [CACHE] = _TAIL_CALL_TRACE_RECORD, + [CALL] = _TAIL_CALL_TRACE_RECORD, + [CALL_ALLOC_AND_ENTER_INIT] = _TAIL_CALL_TRACE_RECORD, + [CALL_BOUND_METHOD_EXACT_ARGS] = _TAIL_CALL_TRACE_RECORD, + [CALL_BOUND_METHOD_GENERAL] = _TAIL_CALL_TRACE_RECORD, + [CALL_BUILTIN_CLASS] = _TAIL_CALL_TRACE_RECORD, + [CALL_BUILTIN_FAST] = _TAIL_CALL_TRACE_RECORD, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = _TAIL_CALL_TRACE_RECORD, + [CALL_BUILTIN_O] = _TAIL_CALL_TRACE_RECORD, + [CALL_FUNCTION_EX] = _TAIL_CALL_TRACE_RECORD, + [CALL_INTRINSIC_1] = _TAIL_CALL_TRACE_RECORD, + [CALL_INTRINSIC_2] = _TAIL_CALL_TRACE_RECORD, + [CALL_ISINSTANCE] = _TAIL_CALL_TRACE_RECORD, + [CALL_KW] = _TAIL_CALL_TRACE_RECORD, + [CALL_KW_BOUND_METHOD] = _TAIL_CALL_TRACE_RECORD, + [CALL_KW_NON_PY] = _TAIL_CALL_TRACE_RECORD, + [CALL_KW_PY] = _TAIL_CALL_TRACE_RECORD, + [CALL_LEN] = _TAIL_CALL_TRACE_RECORD, + [CALL_LIST_APPEND] = _TAIL_CALL_TRACE_RECORD, + [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_TRACE_RECORD, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_TRACE_RECORD, + [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_TRACE_RECORD, + [CALL_METHOD_DESCRIPTOR_O] = _TAIL_CALL_TRACE_RECORD, + [CALL_NON_PY_GENERAL] = _TAIL_CALL_TRACE_RECORD, + [CALL_PY_EXACT_ARGS] = _TAIL_CALL_TRACE_RECORD, + [CALL_PY_GENERAL] = _TAIL_CALL_TRACE_RECORD, + [CALL_STR_1] = _TAIL_CALL_TRACE_RECORD, + [CALL_TUPLE_1] = _TAIL_CALL_TRACE_RECORD, + [CALL_TYPE_1] = _TAIL_CALL_TRACE_RECORD, + [CHECK_EG_MATCH] = _TAIL_CALL_TRACE_RECORD, + [CHECK_EXC_MATCH] = _TAIL_CALL_TRACE_RECORD, + [CLEANUP_THROW] = _TAIL_CALL_TRACE_RECORD, + [COMPARE_OP] = _TAIL_CALL_TRACE_RECORD, + [COMPARE_OP_FLOAT] = _TAIL_CALL_TRACE_RECORD, + [COMPARE_OP_INT] = _TAIL_CALL_TRACE_RECORD, + [COMPARE_OP_STR] = _TAIL_CALL_TRACE_RECORD, + [CONTAINS_OP] = _TAIL_CALL_TRACE_RECORD, + [CONTAINS_OP_DICT] = _TAIL_CALL_TRACE_RECORD, + [CONTAINS_OP_SET] = _TAIL_CALL_TRACE_RECORD, + [CONVERT_VALUE] = _TAIL_CALL_TRACE_RECORD, + [COPY] = _TAIL_CALL_TRACE_RECORD, + [COPY_FREE_VARS] = _TAIL_CALL_TRACE_RECORD, + [DELETE_ATTR] = _TAIL_CALL_TRACE_RECORD, + [DELETE_DEREF] = _TAIL_CALL_TRACE_RECORD, + [DELETE_FAST] = _TAIL_CALL_TRACE_RECORD, + [DELETE_GLOBAL] = _TAIL_CALL_TRACE_RECORD, + [DELETE_NAME] = _TAIL_CALL_TRACE_RECORD, + [DELETE_SUBSCR] = _TAIL_CALL_TRACE_RECORD, + [DICT_MERGE] = _TAIL_CALL_TRACE_RECORD, + [DICT_UPDATE] = _TAIL_CALL_TRACE_RECORD, + [END_ASYNC_FOR] = _TAIL_CALL_TRACE_RECORD, + [END_FOR] = _TAIL_CALL_TRACE_RECORD, + [END_SEND] = _TAIL_CALL_TRACE_RECORD, + [ENTER_EXECUTOR] = _TAIL_CALL_TRACE_RECORD, + [EXIT_INIT_CHECK] = _TAIL_CALL_TRACE_RECORD, + [EXTENDED_ARG] = _TAIL_CALL_TRACE_RECORD, + [FORMAT_SIMPLE] = _TAIL_CALL_TRACE_RECORD, + [FORMAT_WITH_SPEC] = _TAIL_CALL_TRACE_RECORD, + [FOR_ITER] = _TAIL_CALL_TRACE_RECORD, + [FOR_ITER_GEN] = _TAIL_CALL_TRACE_RECORD, + [FOR_ITER_LIST] = _TAIL_CALL_TRACE_RECORD, + [FOR_ITER_RANGE] = _TAIL_CALL_TRACE_RECORD, + [FOR_ITER_TUPLE] = _TAIL_CALL_TRACE_RECORD, + [GET_AITER] = _TAIL_CALL_TRACE_RECORD, + [GET_ANEXT] = _TAIL_CALL_TRACE_RECORD, + [GET_AWAITABLE] = _TAIL_CALL_TRACE_RECORD, + [GET_ITER] = _TAIL_CALL_TRACE_RECORD, + [GET_LEN] = _TAIL_CALL_TRACE_RECORD, + [GET_YIELD_FROM_ITER] = _TAIL_CALL_TRACE_RECORD, + [IMPORT_FROM] = _TAIL_CALL_TRACE_RECORD, + [IMPORT_NAME] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_CALL] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_CALL_FUNCTION_EX] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_CALL_KW] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_END_ASYNC_FOR] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_END_FOR] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_END_SEND] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_FOR_ITER] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_INSTRUCTION] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_JUMP_BACKWARD] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_JUMP_FORWARD] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_LINE] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_LOAD_SUPER_ATTR] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_NOT_TAKEN] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_POP_ITER] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_POP_JUMP_IF_NONE] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_RESUME] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD, + [INSTRUMENTED_YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD, + [INTERPRETER_EXIT] = _TAIL_CALL_TRACE_RECORD, + [IS_OP] = _TAIL_CALL_TRACE_RECORD, + [JUMP_BACKWARD] = _TAIL_CALL_TRACE_RECORD, + [JUMP_BACKWARD_JIT] = _TAIL_CALL_TRACE_RECORD, + [JUMP_BACKWARD_NO_INTERRUPT] = _TAIL_CALL_TRACE_RECORD, + [JUMP_BACKWARD_NO_JIT] = _TAIL_CALL_TRACE_RECORD, + [JUMP_FORWARD] = _TAIL_CALL_TRACE_RECORD, + [LIST_APPEND] = _TAIL_CALL_TRACE_RECORD, + [LIST_EXTEND] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_CLASS] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_INSTANCE_VALUE] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_METHOD_LAZY_DICT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_METHOD_NO_DICT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_METHOD_WITH_VALUES] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_MODULE] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_PROPERTY] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_SLOT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_ATTR_WITH_HINT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_BUILD_CLASS] = _TAIL_CALL_TRACE_RECORD, + [LOAD_COMMON_CONSTANT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_CONST] = _TAIL_CALL_TRACE_RECORD, + [LOAD_DEREF] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FAST] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FAST_AND_CLEAR] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FAST_BORROW] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FAST_BORROW_LOAD_FAST_BORROW] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FAST_CHECK] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FAST_LOAD_FAST] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FROM_DICT_OR_DEREF] = _TAIL_CALL_TRACE_RECORD, + [LOAD_FROM_DICT_OR_GLOBALS] = _TAIL_CALL_TRACE_RECORD, + [LOAD_GLOBAL] = _TAIL_CALL_TRACE_RECORD, + [LOAD_GLOBAL_BUILTIN] = _TAIL_CALL_TRACE_RECORD, + [LOAD_GLOBAL_MODULE] = _TAIL_CALL_TRACE_RECORD, + [LOAD_LOCALS] = _TAIL_CALL_TRACE_RECORD, + [LOAD_NAME] = _TAIL_CALL_TRACE_RECORD, + [LOAD_SMALL_INT] = _TAIL_CALL_TRACE_RECORD, + [LOAD_SPECIAL] = _TAIL_CALL_TRACE_RECORD, + [LOAD_SUPER_ATTR] = _TAIL_CALL_TRACE_RECORD, + [LOAD_SUPER_ATTR_ATTR] = _TAIL_CALL_TRACE_RECORD, + [LOAD_SUPER_ATTR_METHOD] = _TAIL_CALL_TRACE_RECORD, + [MAKE_CELL] = _TAIL_CALL_TRACE_RECORD, + [MAKE_FUNCTION] = _TAIL_CALL_TRACE_RECORD, + [MAP_ADD] = _TAIL_CALL_TRACE_RECORD, + [MATCH_CLASS] = _TAIL_CALL_TRACE_RECORD, + [MATCH_KEYS] = _TAIL_CALL_TRACE_RECORD, + [MATCH_MAPPING] = _TAIL_CALL_TRACE_RECORD, + [MATCH_SEQUENCE] = _TAIL_CALL_TRACE_RECORD, + [NOP] = _TAIL_CALL_TRACE_RECORD, + [NOT_TAKEN] = _TAIL_CALL_TRACE_RECORD, + [POP_EXCEPT] = _TAIL_CALL_TRACE_RECORD, + [POP_ITER] = _TAIL_CALL_TRACE_RECORD, + [POP_JUMP_IF_FALSE] = _TAIL_CALL_TRACE_RECORD, + [POP_JUMP_IF_NONE] = _TAIL_CALL_TRACE_RECORD, + [POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_TRACE_RECORD, + [POP_JUMP_IF_TRUE] = _TAIL_CALL_TRACE_RECORD, + [POP_TOP] = _TAIL_CALL_TRACE_RECORD, + [PUSH_EXC_INFO] = _TAIL_CALL_TRACE_RECORD, + [PUSH_NULL] = _TAIL_CALL_TRACE_RECORD, + [RAISE_VARARGS] = _TAIL_CALL_TRACE_RECORD, + [RERAISE] = _TAIL_CALL_TRACE_RECORD, + [RESERVED] = _TAIL_CALL_TRACE_RECORD, + [RESUME] = _TAIL_CALL_TRACE_RECORD, + [RESUME_CHECK] = _TAIL_CALL_TRACE_RECORD, + [RETURN_GENERATOR] = _TAIL_CALL_TRACE_RECORD, + [RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD, + [SEND] = _TAIL_CALL_TRACE_RECORD, + [SEND_GEN] = _TAIL_CALL_TRACE_RECORD, + [SETUP_ANNOTATIONS] = _TAIL_CALL_TRACE_RECORD, + [SET_ADD] = _TAIL_CALL_TRACE_RECORD, + [SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_TRACE_RECORD, + [SET_UPDATE] = _TAIL_CALL_TRACE_RECORD, + [STORE_ATTR] = _TAIL_CALL_TRACE_RECORD, + [STORE_ATTR_INSTANCE_VALUE] = _TAIL_CALL_TRACE_RECORD, + [STORE_ATTR_SLOT] = _TAIL_CALL_TRACE_RECORD, + [STORE_ATTR_WITH_HINT] = _TAIL_CALL_TRACE_RECORD, + [STORE_DEREF] = _TAIL_CALL_TRACE_RECORD, + [STORE_FAST] = _TAIL_CALL_TRACE_RECORD, + [STORE_FAST_LOAD_FAST] = _TAIL_CALL_TRACE_RECORD, + [STORE_FAST_STORE_FAST] = _TAIL_CALL_TRACE_RECORD, + [STORE_GLOBAL] = _TAIL_CALL_TRACE_RECORD, + [STORE_NAME] = _TAIL_CALL_TRACE_RECORD, + [STORE_SLICE] = _TAIL_CALL_TRACE_RECORD, + [STORE_SUBSCR] = _TAIL_CALL_TRACE_RECORD, + [STORE_SUBSCR_DICT] = _TAIL_CALL_TRACE_RECORD, + [STORE_SUBSCR_LIST_INT] = _TAIL_CALL_TRACE_RECORD, + [SWAP] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL_ALWAYS_TRUE] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL_BOOL] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL_INT] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL_LIST] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL_NONE] = _TAIL_CALL_TRACE_RECORD, + [TO_BOOL_STR] = _TAIL_CALL_TRACE_RECORD, + [TRACE_RECORD] = _TAIL_CALL_TRACE_RECORD, + [UNARY_INVERT] = _TAIL_CALL_TRACE_RECORD, + [UNARY_NEGATIVE] = _TAIL_CALL_TRACE_RECORD, + [UNARY_NOT] = _TAIL_CALL_TRACE_RECORD, + [UNPACK_EX] = _TAIL_CALL_TRACE_RECORD, + [UNPACK_SEQUENCE] = _TAIL_CALL_TRACE_RECORD, + [UNPACK_SEQUENCE_LIST] = _TAIL_CALL_TRACE_RECORD, + [UNPACK_SEQUENCE_TUPLE] = _TAIL_CALL_TRACE_RECORD, + [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD, + [WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD, + [YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD, + [121] = _TAIL_CALL_UNKNOWN_OPCODE, + [122] = _TAIL_CALL_UNKNOWN_OPCODE, + [123] = _TAIL_CALL_UNKNOWN_OPCODE, + [124] = _TAIL_CALL_UNKNOWN_OPCODE, + [125] = _TAIL_CALL_UNKNOWN_OPCODE, + [126] = _TAIL_CALL_UNKNOWN_OPCODE, + [127] = _TAIL_CALL_UNKNOWN_OPCODE, + [210] = _TAIL_CALL_UNKNOWN_OPCODE, + [211] = _TAIL_CALL_UNKNOWN_OPCODE, + [212] = _TAIL_CALL_UNKNOWN_OPCODE, + [213] = _TAIL_CALL_UNKNOWN_OPCODE, + [214] = _TAIL_CALL_UNKNOWN_OPCODE, + [215] = _TAIL_CALL_UNKNOWN_OPCODE, + [216] = _TAIL_CALL_UNKNOWN_OPCODE, + [217] = _TAIL_CALL_UNKNOWN_OPCODE, + [218] = _TAIL_CALL_UNKNOWN_OPCODE, + [219] = _TAIL_CALL_UNKNOWN_OPCODE, + [220] = _TAIL_CALL_UNKNOWN_OPCODE, + [221] = _TAIL_CALL_UNKNOWN_OPCODE, + [222] = _TAIL_CALL_UNKNOWN_OPCODE, + [223] = _TAIL_CALL_UNKNOWN_OPCODE, + [224] = _TAIL_CALL_UNKNOWN_OPCODE, + [225] = _TAIL_CALL_UNKNOWN_OPCODE, + [226] = _TAIL_CALL_UNKNOWN_OPCODE, + [227] = _TAIL_CALL_UNKNOWN_OPCODE, + [228] = _TAIL_CALL_UNKNOWN_OPCODE, + [229] = _TAIL_CALL_UNKNOWN_OPCODE, + [230] = _TAIL_CALL_UNKNOWN_OPCODE, + [231] = _TAIL_CALL_UNKNOWN_OPCODE, + [232] = _TAIL_CALL_UNKNOWN_OPCODE, +}; +#endif /* _Py_TAIL_CALL_INTERP */ diff --git a/Python/optimizer.c b/Python/optimizer.c index bae5cfa50ea..fc984a5374a 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -6,6 +6,7 @@ #include "pycore_interp.h" #include "pycore_backoff.h" #include "pycore_bitutils.h" // _Py_popcount32() +#include "pycore_ceval.h" // _Py_set_eval_breaker_bit #include "pycore_code.h" // _Py_GetBaseCodeUnit #include "pycore_function.h" // _PyFunction_LookupByVersion() #include "pycore_interpframe.h" @@ -14,7 +15,7 @@ #include "pycore_opcode_utils.h" // MAX_REAL_OPCODE #include "pycore_optimizer.h" // _Py_uop_analyze_and_optimize() #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_tuple.h" // _PyTuple_FromArraySteal +#include "pycore_tuple.h" // _PyTuple_FromArraySteal #include "pycore_unicodeobject.h" // _PyUnicode_FromASCII #include "pycore_uop_ids.h" #include "pycore_jit.h" @@ -28,11 +29,24 @@ #define MAX_EXECUTORS_SIZE 256 +// Trace too short, no progress: +// _START_EXECUTOR +// _MAKE_WARM +// _CHECK_VALIDITY +// _SET_IP +// is 4-5 instructions. +#define CODE_SIZE_NO_PROGRESS 5 +// We start with _START_EXECUTOR, _MAKE_WARM +#define CODE_SIZE_EMPTY 2 + #define _PyExecutorObject_CAST(op) ((_PyExecutorObject *)(op)) static bool has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) { + if (code == (PyCodeObject *)&_Py_InitCleanup) { + return false; + } if (instr->op.code == ENTER_EXECUTOR) { return true; } @@ -99,11 +113,11 @@ insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorO } static _PyExecutorObject * -make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies); +make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies, int chain_depth); static int -uop_optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, - _PyExecutorObject **exec_ptr, int curr_stackentries, +uop_optimize(_PyInterpreterFrame *frame, PyThreadState *tstate, + _PyExecutorObject **exec_ptr, bool progress_needed); /* Returns 1 if optimized, 0 if not optimized, and -1 for an error. @@ -112,27 +126,47 @@ uop_optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, // gh-137573: inlining this function causes stack overflows Py_NO_INLINE int _PyOptimizer_Optimize( - _PyInterpreterFrame *frame, _Py_CODEUNIT *start, - _PyExecutorObject **executor_ptr, int chain_depth) + _PyInterpreterFrame *frame, PyThreadState *tstate) { - _PyStackRef *stack_pointer = frame->stackpointer; - assert(_PyInterpreterState_GET()->jit); + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + int chain_depth = _tstate->jit_tracer_state.initial_state.chain_depth; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!interp->jit) { + // gh-140936: It is possible that interp->jit will become false during + // interpreter finalization. However, the specialized JUMP_BACKWARD_JIT + // instruction may still be present. In this case, we should + // return immediately without optimization. + return 0; + } + assert(!interp->compiling); + assert(_tstate->jit_tracer_state.initial_state.stack_depth >= 0); +#ifndef Py_GIL_DISABLED + assert(_tstate->jit_tracer_state.initial_state.func != NULL); + interp->compiling = true; // The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must* // make progress in order to avoid infinite loops or excessively-long // side-exit chains. We can only insert the executor into the bytecode if // this is true, since a deopt won't infinitely re-enter the executor: chain_depth %= MAX_CHAIN_DEPTH; bool progress_needed = chain_depth == 0; - PyCodeObject *code = _PyFrame_GetCode(frame); - assert(PyCode_Check(code)); + PyCodeObject *code = (PyCodeObject *)_tstate->jit_tracer_state.initial_state.code; + _Py_CODEUNIT *start = _tstate->jit_tracer_state.initial_state.start_instr; if (progress_needed && !has_space_for_executor(code, start)) { + interp->compiling = false; return 0; } - int err = uop_optimize(frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed); + // One of our dependencies while tracing was invalidated. Not worth compiling. + if (!_tstate->jit_tracer_state.prev_state.dependencies_still_valid) { + interp->compiling = false; + return 0; + } + _PyExecutorObject *executor; + int err = uop_optimize(frame, tstate, &executor, progress_needed); if (err <= 0) { + interp->compiling = false; return err; } - assert(*executor_ptr != NULL); + assert(executor != NULL); if (progress_needed) { int index = get_index_for_executor(code, start); if (index < 0) { @@ -142,17 +176,26 @@ _PyOptimizer_Optimize( * If an optimizer has already produced an executor, * it might get confused by the executor disappearing, * but there is not much we can do about that here. */ - Py_DECREF(*executor_ptr); + Py_DECREF(executor); + interp->compiling = false; return 0; } - insert_executor(code, start, index, *executor_ptr); + insert_executor(code, start, index, executor); } else { - (*executor_ptr)->vm_data.code = NULL; + executor->vm_data.code = NULL; } - (*executor_ptr)->vm_data.chain_depth = chain_depth; - assert((*executor_ptr)->vm_data.valid); + _PyExitData *exit = _tstate->jit_tracer_state.initial_state.exit; + if (exit != NULL) { + exit->executor = executor; + } + executor->vm_data.chain_depth = chain_depth; + assert(executor->vm_data.valid); + interp->compiling = false; return 1; +#else + return 0; +#endif } static _PyExecutorObject * @@ -278,7 +321,7 @@ uop_dealloc(PyObject *op) { const char * _PyUOpName(int index) { - if (index < 0 || index > MAX_UOP_ID) { + if (index < 0 || index > MAX_UOP_REGS_ID) { return NULL; } return _PyOpcode_uop_name[index]; @@ -313,7 +356,7 @@ _PyUOpPrint(const _PyUOpInstruction *uop) default: printf(" (%d, Unknown format)", uop->oparg); } - if (_PyUop_Flags[uop->opcode] & HAS_ERROR_FLAG) { + if (_PyUop_Flags[_PyUop_Uncached[uop->opcode]] & HAS_ERROR_FLAG) { printf(", error_target=%d", uop->error_target); } @@ -337,7 +380,9 @@ uop_item(PyObject *op, Py_ssize_t index) PyErr_SetNone(PyExc_IndexError); return NULL; } - const char *name = _PyUOpName(self->trace[index].opcode); + int opcode = self->trace[index].opcode; + int base_opcode = _PyUop_Uncached[opcode]; + const char *name = _PyUOpName(base_opcode); if (name == NULL) { name = "<nil>"; } @@ -351,7 +396,7 @@ uop_item(PyObject *op, Py_ssize_t index) return NULL; } PyObject *target = PyLong_FromUnsignedLong(self->trace[index].target); - if (oparg == NULL) { + if (target == NULL) { Py_DECREF(oparg); Py_DECREF(oname); return NULL; @@ -456,6 +501,14 @@ BRANCH_TO_GUARD[4][2] = { [POP_JUMP_IF_NOT_NONE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_NOT_NONE_POP, }; +static const uint16_t +guard_ip_uop[MAX_UOP_ID + 1] = { + [_PUSH_FRAME] = _GUARD_IP__PUSH_FRAME, + [_RETURN_GENERATOR] = _GUARD_IP_RETURN_GENERATOR, + [_RETURN_VALUE] = _GUARD_IP_RETURN_VALUE, + [_YIELD_VALUE] = _GUARD_IP_YIELD_VALUE, +}; + #define CONFIDENCE_RANGE 1000 #define CONFIDENCE_CUTOFF 333 @@ -512,64 +565,31 @@ add_to_trace( DPRINTF(2, "No room for %s (need %d, got %d)\n", \ (opname), (n), max_length - trace_length); \ OPT_STAT_INC(trace_too_long); \ - goto done; \ + goto full; \ } -// Reserve space for N uops, plus 3 for _SET_IP, _CHECK_VALIDITY and _EXIT_TRACE -#define RESERVE(needed) RESERVE_RAW((needed) + 3, _PyUOpName(opcode)) - -// Trace stack operations (used by _PUSH_FRAME, _RETURN_VALUE) -#define TRACE_STACK_PUSH() \ - if (trace_stack_depth >= TRACE_STACK_SIZE) { \ - DPRINTF(2, "Trace stack overflow\n"); \ - OPT_STAT_INC(trace_stack_overflow); \ - return 0; \ - } \ - assert(func == NULL || func->func_code == (PyObject *)code); \ - trace_stack[trace_stack_depth].func = func; \ - trace_stack[trace_stack_depth].code = code; \ - trace_stack[trace_stack_depth].instr = instr; \ - trace_stack_depth++; -#define TRACE_STACK_POP() \ - if (trace_stack_depth <= 0) { \ - Py_FatalError("Trace stack underflow\n"); \ - } \ - trace_stack_depth--; \ - func = trace_stack[trace_stack_depth].func; \ - code = trace_stack[trace_stack_depth].code; \ - assert(func == NULL || func->func_code == (PyObject *)code); \ - instr = trace_stack[trace_stack_depth].instr; - -/* Returns the length of the trace on success, - * 0 if it failed to produce a worthwhile trace, - * and -1 on an error. - */ static int -translate_bytecode_to_trace( - _PyInterpreterFrame *frame, - _Py_CODEUNIT *instr, - _PyUOpInstruction *trace, - int buffer_size, - _PyBloomFilter *dependencies, bool progress_needed) +is_terminator(const _PyUOpInstruction *uop) +{ + int opcode = _PyUop_Uncached[uop->opcode]; + return ( + opcode == _EXIT_TRACE || + opcode == _DEOPT || + opcode == _JUMP_TO_TOP || + opcode == _DYNAMIC_EXIT + ); +} + +/* Returns 1 on success (added to trace), 0 on trace end. + */ +// gh-142543: inlining this function causes stack overflows +Py_NO_INLINE int +_PyJit_translate_single_bytecode_to_trace( + PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *next_instr, + int stop_tracing_opcode) { - bool first = true; - PyCodeObject *code = _PyFrame_GetCode(frame); - PyFunctionObject *func = _PyFrame_GetFunction(frame); - assert(PyFunction_Check(func)); - PyCodeObject *initial_code = code; - _Py_BloomFilter_Add(dependencies, initial_code); - _Py_CODEUNIT *initial_instr = instr; - int trace_length = 0; - // Leave space for possible trailing _EXIT_TRACE - int max_length = buffer_size-2; - struct { - PyFunctionObject *func; - PyCodeObject *code; - _Py_CODEUNIT *instr; - } trace_stack[TRACE_STACK_SIZE]; - int trace_stack_depth = 0; - int confidence = CONFIDENCE_RANGE; // Adjusted by branch instructions - bool jump_seen = false; #ifdef Py_DEBUG char *python_lltrace = Py_GETENV("PYTHON_LLTRACE"); @@ -578,411 +598,488 @@ translate_bytecode_to_trace( lltrace = *python_lltrace - '0'; // TODO: Parse an int and all that } #endif + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + PyCodeObject *old_code = _tstate->jit_tracer_state.prev_state.instr_code; + bool progress_needed = (_tstate->jit_tracer_state.initial_state.chain_depth % MAX_CHAIN_DEPTH) == 0; + _PyBloomFilter *dependencies = &_tstate->jit_tracer_state.prev_state.dependencies; + int trace_length = _tstate->jit_tracer_state.prev_state.code_curr_size; + _PyUOpInstruction *trace = _tstate->jit_tracer_state.code_buffer; + int max_length = _tstate->jit_tracer_state.prev_state.code_max_size; - DPRINTF(2, - "Optimizing %s (%s:%d) at byte offset %d\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - 2 * INSTR_IP(initial_instr, code)); - ADD_TO_TRACE(_START_EXECUTOR, 0, (uintptr_t)instr, INSTR_IP(instr, code)); - ADD_TO_TRACE(_MAKE_WARM, 0, 0, 0); + _Py_CODEUNIT *this_instr = _tstate->jit_tracer_state.prev_state.instr; + _Py_CODEUNIT *target_instr = this_instr; uint32_t target = 0; - for (;;) { - target = INSTR_IP(instr, code); - // Need space for _DEOPT - max_length--; + target = Py_IsNone((PyObject *)old_code) + ? (int)(target_instr - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR) + : INSTR_IP(target_instr, old_code); - uint32_t opcode = instr->op.code; - uint32_t oparg = instr->op.arg; + // Rewind EXTENDED_ARG so that we see the whole thing. + // We must point to the first EXTENDED_ARG when deopting. + int oparg = _tstate->jit_tracer_state.prev_state.instr_oparg; + int opcode = this_instr->op.code; + int rewind_oparg = oparg; + while (rewind_oparg > 255) { + rewind_oparg >>= 8; + target--; + } - if (!first && instr == initial_instr) { - // We have looped around to the start: - RESERVE(1); - ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0); + if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]] > 0) { + uint16_t backoff = (this_instr + 1)->counter.value_and_backoff; + // adaptive_counter_cooldown is a fresh specialization. + // trigger_backoff_counter is what we set during tracing. + // All tracing backoffs should be freshly specialized or untouched. + // If not, that indicates a deopt during tracing, and + // thus the "actual" instruction executed is not the one that is + // in the instruction stream, but rather the deopt. + // It's important we check for this, as some specializations might make + // no progress (they can immediately deopt after specializing). + // We do this to improve performance, as otherwise a compiled trace + // will just deopt immediately. + if (backoff != adaptive_counter_cooldown().value_and_backoff && + backoff != trigger_backoff_counter().value_and_backoff) { + OPT_STAT_INC(trace_immediately_deopts); + opcode = _PyOpcode_Deopt[opcode]; + } + } + + int old_stack_level = _tstate->jit_tracer_state.prev_state.instr_stacklevel; + + // Strange control-flow + bool has_dynamic_jump_taken = OPCODE_HAS_UNPREDICTABLE_JUMP(opcode) && + (next_instr != this_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]); + + /* Special case the first instruction, + * so that we can guarantee forward progress */ + if (progress_needed && _tstate->jit_tracer_state.prev_state.code_curr_size < CODE_SIZE_NO_PROGRESS) { + if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) { + opcode = _PyOpcode_Deopt[opcode]; + } + assert(!OPCODE_HAS_EXIT(opcode)); + assert(!OPCODE_HAS_DEOPT(opcode)); + } + + bool needs_guard_ip = OPCODE_HAS_NEEDS_GUARD_IP(opcode); + if (has_dynamic_jump_taken && !needs_guard_ip) { + DPRINTF(2, "Unsupported: dynamic jump taken %s\n", _PyOpcode_OpName[opcode]); + goto unsupported; + } + + int is_sys_tracing = (tstate->c_tracefunc != NULL) || (tstate->c_profilefunc != NULL); + if (is_sys_tracing) { + goto full; + } + + if (stop_tracing_opcode != 0) { + ADD_TO_TRACE(stop_tracing_opcode, 0, 0, target); + goto done; + } + + DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level); + +#ifdef Py_DEBUG + if (oparg > 255) { + assert(_Py_GetBaseCodeUnit(old_code, target).op.code == EXTENDED_ARG); + } +#endif + + // Skip over super instructions. + if (_tstate->jit_tracer_state.prev_state.instr_is_super) { + _tstate->jit_tracer_state.prev_state.instr_is_super = false; + return 1; + } + + if (opcode == ENTER_EXECUTOR) { + goto full; + } + + if (!_tstate->jit_tracer_state.prev_state.dependencies_still_valid) { + goto done; + } + + // This happens when a recursive call happens that we can't trace. Such as Python -> C -> Python calls + // If we haven't guarded the IP, then it's untraceable. + if (frame != _tstate->jit_tracer_state.prev_state.instr_frame && !needs_guard_ip) { + DPRINTF(2, "Unsupported: unguardable jump taken\n"); + goto unsupported; + } + + if (oparg > 0xFFFF) { + DPRINTF(2, "Unsupported: oparg too large\n"); + goto unsupported; + } + + // TODO (gh-140277): The constituent use one extra stack slot. So we need to check for headroom. + if (opcode == BINARY_OP_SUBSCR_GETITEM && old_stack_level + 1 > old_code->co_stacksize) { + unsupported: + { + // Rewind to previous instruction and replace with _EXIT_TRACE. + _PyUOpInstruction *curr = &trace[trace_length-1]; + while (curr->opcode != _SET_IP && trace_length > 2) { + trace_length--; + curr = &trace[trace_length-1]; + } + assert(curr->opcode == _SET_IP || trace_length == 2); + if (curr->opcode == _SET_IP) { + int32_t old_target = (int32_t)uop_get_target(curr); + curr++; + trace_length++; + curr->opcode = _EXIT_TRACE; + curr->format = UOP_FORMAT_TARGET; + curr->target = old_target; + } goto done; } + } - DPRINTF(2, "%d: %s(%d)\n", target, _PyOpcode_OpName[opcode], oparg); + if (opcode == NOP) { + return 1; + } - if (opcode == EXTENDED_ARG) { - instr++; - opcode = instr->op.code; - oparg = (oparg << 8) | instr->op.arg; - if (opcode == EXTENDED_ARG) { - instr--; + if (opcode == JUMP_FORWARD) { + return 1; + } + + if (opcode == EXTENDED_ARG) { + return 1; + } + + // One for possible _DEOPT, one because _CHECK_VALIDITY itself might _DEOPT + max_length -= 2; + + const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; + + assert(opcode != ENTER_EXECUTOR && opcode != EXTENDED_ARG); + assert(!_PyErr_Occurred(tstate)); + + + if (OPCODE_HAS_EXIT(opcode)) { + // Make space for side exit and final _EXIT_TRACE: + max_length--; + } + if (OPCODE_HAS_ERROR(opcode)) { + // Make space for error stub and final _EXIT_TRACE: + max_length--; + } + + // _GUARD_IP leads to an exit. + max_length -= needs_guard_ip; + + RESERVE_RAW(expansion->nuops + needs_guard_ip + 2 + (!OPCODE_HAS_NO_SAVE_IP(opcode)), "uop and various checks"); + + ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target); + + if (!OPCODE_HAS_NO_SAVE_IP(opcode)) { + ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)target_instr, target); + } + + // Can be NULL for the entry frame. + if (old_code != NULL) { + _Py_BloomFilter_Add(dependencies, old_code); + } + + switch (opcode) { + case POP_JUMP_IF_NONE: + case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + { + _Py_CODEUNIT *computed_next_instr_without_modifiers = target_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; + _Py_CODEUNIT *computed_next_instr = computed_next_instr_without_modifiers + (computed_next_instr_without_modifiers->op.code == NOT_TAKEN); + _Py_CODEUNIT *computed_jump_instr = computed_next_instr_without_modifiers + oparg; + assert(next_instr == computed_next_instr || next_instr == computed_jump_instr); + int jump_happened = computed_jump_instr == next_instr; + assert(jump_happened == (target_instr[1].cache & 1)); + uint32_t uopcode = BRANCH_TO_GUARD[opcode - POP_JUMP_IF_FALSE][jump_happened]; + ADD_TO_TRACE(uopcode, 0, 0, INSTR_IP(jump_happened ? computed_next_instr : computed_jump_instr, old_code)); + break; + } + case JUMP_BACKWARD_JIT: + // This is possible as the JIT might have re-activated after it was disabled + case JUMP_BACKWARD_NO_JIT: + case JUMP_BACKWARD: + ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target); + _Py_FALLTHROUGH; + case JUMP_BACKWARD_NO_INTERRUPT: + { + if ((next_instr != _tstate->jit_tracer_state.initial_state.close_loop_instr) && + (next_instr != _tstate->jit_tracer_state.initial_state.start_instr) && + _tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS && + // For side exits, we don't want to terminate them early. + _tstate->jit_tracer_state.initial_state.exit == NULL && + // These are coroutines, and we want to unroll those usually. + opcode != JUMP_BACKWARD_NO_INTERRUPT) { + // We encountered a JUMP_BACKWARD but not to the top of our own loop. + // We don't want to continue tracing as we might get stuck in the + // inner loop. Instead, end the trace where the executor of the + // inner loop might start and let the traces rejoin. + OPT_STAT_INC(inner_loop); + ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target); + trace[trace_length-1].operand1 = true; // is_control_flow + DPRINTF(2, "JUMP_BACKWARD not to top ends trace %p %p %p\n", next_instr, + _tstate->jit_tracer_state.initial_state.close_loop_instr, _tstate->jit_tracer_state.initial_state.start_instr); goto done; } - } - if (opcode == ENTER_EXECUTOR) { - // We have a couple of options here. We *could* peek "underneath" - // this executor and continue tracing, which could give us a longer, - // more optimizeable trace (at the expense of lots of duplicated - // tier two code). Instead, we choose to just end here and stitch to - // the other trace, which allows a side-exit traces to rejoin the - // "main" trace periodically (and also helps protect us against - // pathological behavior where the amount of tier two code explodes - // for a medium-length, branchy code path). This seems to work - // better in practice, but in the future we could be smarter about - // what we do here: - goto done; - } - assert(opcode != ENTER_EXECUTOR && opcode != EXTENDED_ARG); - RESERVE_RAW(2, "_CHECK_VALIDITY"); - ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target); - if (!OPCODE_HAS_NO_SAVE_IP(opcode)) { - RESERVE_RAW(2, "_SET_IP"); - ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)instr, target); + break; } - /* Special case the first instruction, - * so that we can guarantee forward progress */ - if (first && progress_needed) { - assert(first); - if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) { - opcode = _PyOpcode_Deopt[opcode]; + case RESUME: + case RESUME_CHECK: + /* Use a special tier 2 version of RESUME_CHECK to allow traces to + * start with RESUME_CHECK */ + ADD_TO_TRACE(_TIER2_RESUME_CHECK, 0, 0, target); + break; + default: + { + const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; + // Reserve space for nuops (+ _SET_IP + _EXIT_TRACE) + int nuops = expansion->nuops; + if (nuops == 0) { + DPRINTF(2, "Unsupported opcode %s\n", _PyOpcode_OpName[opcode]); + goto unsupported; } - assert(!OPCODE_HAS_EXIT(opcode)); - assert(!OPCODE_HAS_DEOPT(opcode)); - } + assert(nuops > 0); + uint32_t orig_oparg = oparg; // For OPARG_TOP/BOTTOM + uint32_t orig_target = target; + for (int i = 0; i < nuops; i++) { + oparg = orig_oparg; + target = orig_target; + uint32_t uop = expansion->uops[i].uop; + uint64_t operand = 0; + // Add one to account for the actual opcode/oparg pair: + int offset = expansion->uops[i].offset + 1; + switch (expansion->uops[i].size) { + case OPARG_SIMPLE: + assert(opcode != _JUMP_BACKWARD_NO_INTERRUPT && opcode != JUMP_BACKWARD); + break; + case OPARG_CACHE_1: + operand = read_u16(&this_instr[offset].cache); + break; + case OPARG_CACHE_2: + operand = read_u32(&this_instr[offset].cache); + break; + case OPARG_CACHE_4: + operand = read_u64(&this_instr[offset].cache); + break; + case OPARG_TOP: // First half of super-instr + assert(orig_oparg <= 255); + oparg = orig_oparg >> 4; + break; + case OPARG_BOTTOM: // Second half of super-instr + assert(orig_oparg <= 255); + oparg = orig_oparg & 0xF; + break; + case OPARG_SAVE_RETURN_OFFSET: // op=_SAVE_RETURN_OFFSET; oparg=return_offset + oparg = offset; + assert(uop == _SAVE_RETURN_OFFSET); + break; + case OPARG_REPLACED: + uop = _PyUOp_Replacements[uop]; + assert(uop != 0); - if (OPCODE_HAS_EXIT(opcode)) { - // Make space for side exit and final _EXIT_TRACE: - RESERVE_RAW(2, "_EXIT_TRACE"); - max_length--; - } - if (OPCODE_HAS_ERROR(opcode)) { - // Make space for error stub and final _EXIT_TRACE: - RESERVE_RAW(2, "_ERROR_POP_N"); - max_length--; - } - switch (opcode) { - case POP_JUMP_IF_NONE: - case POP_JUMP_IF_NOT_NONE: - case POP_JUMP_IF_FALSE: - case POP_JUMP_IF_TRUE: - { - RESERVE(1); - int counter = instr[1].cache; - int bitcount = _Py_popcount32(counter); - int jump_likely = bitcount > 8; - /* If bitcount is 8 (half the jumps were taken), adjust confidence by 50%. - For values in between, adjust proportionally. */ - if (jump_likely) { - confidence = confidence * bitcount / 16; + uint32_t next_inst = target + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; + if (uop == _TIER2_RESUME_CHECK) { + target = next_inst; + } + else { + int extended_arg = orig_oparg > 255; + uint32_t jump_target = next_inst + orig_oparg + extended_arg; + assert(_Py_GetBaseCodeUnit(old_code, jump_target).op.code == END_FOR); + assert(_Py_GetBaseCodeUnit(old_code, jump_target+1).op.code == POP_ITER); + if (is_for_iter_test[uop]) { + target = jump_target + 1; + } + } + break; + case OPERAND1_1: + assert(trace[trace_length-1].opcode == uop); + operand = read_u16(&this_instr[offset].cache); + trace[trace_length-1].operand1 = operand; + continue; + case OPERAND1_2: + assert(trace[trace_length-1].opcode == uop); + operand = read_u32(&this_instr[offset].cache); + trace[trace_length-1].operand1 = operand; + continue; + case OPERAND1_4: + assert(trace[trace_length-1].opcode == uop); + operand = read_u64(&this_instr[offset].cache); + trace[trace_length-1].operand1 = operand; + continue; + default: + fprintf(stderr, + "opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n", + opcode, oparg, nuops, i, + expansion->uops[i].size, + expansion->uops[i].offset); + Py_FatalError("garbled expansion"); } - else { - confidence = confidence * (16 - bitcount) / 16; - } - uint32_t uopcode = BRANCH_TO_GUARD[opcode - POP_JUMP_IF_FALSE][jump_likely]; - DPRINTF(2, "%d: %s(%d): counter=%04x, bitcount=%d, likely=%d, confidence=%d, uopcode=%s\n", - target, _PyOpcode_OpName[opcode], oparg, - counter, bitcount, jump_likely, confidence, _PyUOpName(uopcode)); - if (confidence < CONFIDENCE_CUTOFF) { - DPRINTF(2, "Confidence too low (%d < %d)\n", confidence, CONFIDENCE_CUTOFF); - OPT_STAT_INC(low_confidence); - goto done; - } - _Py_CODEUNIT *next_instr = instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; - _Py_CODEUNIT *target_instr = next_instr + oparg; - if (jump_likely) { - DPRINTF(2, "Jump likely (%04x = %d bits), continue at byte offset %d\n", - instr[1].cache, bitcount, 2 * INSTR_IP(target_instr, code)); - instr = target_instr; - ADD_TO_TRACE(uopcode, 0, 0, INSTR_IP(next_instr, code)); - goto top; - } - ADD_TO_TRACE(uopcode, 0, 0, INSTR_IP(target_instr, code)); - break; - } + if (uop == _PUSH_FRAME || uop == _RETURN_VALUE || uop == _RETURN_GENERATOR || uop == _YIELD_VALUE) { + PyCodeObject *new_code = (PyCodeObject *)PyStackRef_AsPyObjectBorrow(frame->f_executable); + PyFunctionObject *new_func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - case JUMP_BACKWARD: - case JUMP_BACKWARD_JIT: - ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target); - _Py_FALLTHROUGH; - case JUMP_BACKWARD_NO_INTERRUPT: - { - instr += 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] - (int)oparg; - if (jump_seen) { - OPT_STAT_INC(inner_loop); - DPRINTF(2, "JUMP_BACKWARD not to top ends trace\n"); - goto done; - } - jump_seen = true; - goto top; - } - - case JUMP_FORWARD: - { - RESERVE(0); - // This will emit two _SET_IP instructions; leave it to the optimizer - instr += oparg; - break; - } - - case RESUME: - /* Use a special tier 2 version of RESUME_CHECK to allow traces to - * start with RESUME_CHECK */ - ADD_TO_TRACE(_TIER2_RESUME_CHECK, 0, 0, target); - break; - - default: - { - const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; - if (expansion->nuops > 0) { - // Reserve space for nuops (+ _SET_IP + _EXIT_TRACE) - int nuops = expansion->nuops; - RESERVE(nuops + 1); /* One extra for exit */ - int16_t last_op = expansion->uops[nuops-1].uop; - if (last_op == _RETURN_VALUE || last_op == _RETURN_GENERATOR || last_op == _YIELD_VALUE) { - // Check for trace stack underflow now: - // We can't bail e.g. in the middle of - // LOAD_CONST + _RETURN_VALUE. - if (trace_stack_depth == 0) { - DPRINTF(2, "Trace stack underflow\n"); - OPT_STAT_INC(trace_stack_underflow); - return 0; + operand = 0; + if (frame->owner < FRAME_OWNED_BY_INTERPRETER) { + // Don't add nested code objects to the dependency. + // It causes endless re-traces. + if (new_func != NULL && !Py_IsNone((PyObject*)new_func) && !(new_code->co_flags & CO_NESTED)) { + operand = (uintptr_t)new_func; + DPRINTF(2, "Adding %p func to op\n", (void *)operand); + _Py_BloomFilter_Add(dependencies, new_func); + } + else if (new_code != NULL && !Py_IsNone((PyObject*)new_code)) { + operand = (uintptr_t)new_code | 1; + DPRINTF(2, "Adding %p code to op\n", (void *)operand); + _Py_BloomFilter_Add(dependencies, new_code); } } - uint32_t orig_oparg = oparg; // For OPARG_TOP/BOTTOM - for (int i = 0; i < nuops; i++) { - oparg = orig_oparg; - uint32_t uop = expansion->uops[i].uop; - uint64_t operand = 0; - // Add one to account for the actual opcode/oparg pair: - int offset = expansion->uops[i].offset + 1; - switch (expansion->uops[i].size) { - case OPARG_SIMPLE: - assert(opcode != JUMP_BACKWARD_NO_INTERRUPT && opcode != JUMP_BACKWARD); - break; - case OPARG_CACHE_1: - operand = read_u16(&instr[offset].cache); - break; - case OPARG_CACHE_2: - operand = read_u32(&instr[offset].cache); - break; - case OPARG_CACHE_4: - operand = read_u64(&instr[offset].cache); - break; - case OPARG_TOP: // First half of super-instr - oparg = orig_oparg >> 4; - break; - case OPARG_BOTTOM: // Second half of super-instr - oparg = orig_oparg & 0xF; - break; - case OPARG_SAVE_RETURN_OFFSET: // op=_SAVE_RETURN_OFFSET; oparg=return_offset - oparg = offset; - assert(uop == _SAVE_RETURN_OFFSET); - break; - case OPARG_REPLACED: - uop = _PyUOp_Replacements[uop]; - assert(uop != 0); - uint32_t next_inst = target + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + (oparg > 255); - if (uop == _TIER2_RESUME_CHECK) { - target = next_inst; - } -#ifdef Py_DEBUG - else { - uint32_t jump_target = next_inst + oparg; - assert(_Py_GetBaseCodeUnit(code, jump_target).op.code == END_FOR); - assert(_Py_GetBaseCodeUnit(code, jump_target+1).op.code == POP_ITER); - } -#endif - break; - case OPERAND1_1: - assert(trace[trace_length-1].opcode == uop); - operand = read_u16(&instr[offset].cache); - trace[trace_length-1].operand1 = operand; - continue; - case OPERAND1_2: - assert(trace[trace_length-1].opcode == uop); - operand = read_u32(&instr[offset].cache); - trace[trace_length-1].operand1 = operand; - continue; - case OPERAND1_4: - assert(trace[trace_length-1].opcode == uop); - operand = read_u64(&instr[offset].cache); - trace[trace_length-1].operand1 = operand; - continue; - default: - fprintf(stderr, - "opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n", - opcode, oparg, nuops, i, - expansion->uops[i].size, - expansion->uops[i].offset); - Py_FatalError("garbled expansion"); - } - - if (uop == _RETURN_VALUE || uop == _RETURN_GENERATOR || uop == _YIELD_VALUE) { - TRACE_STACK_POP(); - /* Set the operand to the function or code object returned to, - * to assist optimization passes. (See _PUSH_FRAME below.) - */ - if (func != NULL) { - operand = (uintptr_t)func; - } - else if (code != NULL) { - operand = (uintptr_t)code | 1; - } - else { - operand = 0; - } - ADD_TO_TRACE(uop, oparg, operand, target); - DPRINTF(2, - "Returning to %s (%s:%d) at byte offset %d\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - 2 * INSTR_IP(instr, code)); - goto top; - } - - if (uop == _PUSH_FRAME) { - assert(i + 1 == nuops); - if (opcode == FOR_ITER_GEN || - opcode == LOAD_ATTR_PROPERTY || - opcode == BINARY_OP_SUBSCR_GETITEM || - opcode == SEND_GEN) - { - DPRINTF(2, "Bailing due to dynamic target\n"); - OPT_STAT_INC(unknown_callee); - return 0; - } - assert(_PyOpcode_Deopt[opcode] == CALL || _PyOpcode_Deopt[opcode] == CALL_KW); - int func_version_offset = - offsetof(_PyCallCache, func_version)/sizeof(_Py_CODEUNIT) - // Add one to account for the actual opcode/oparg pair: - + 1; - uint32_t func_version = read_u32(&instr[func_version_offset].cache); - PyCodeObject *new_code = NULL; - PyFunctionObject *new_func = - _PyFunction_LookupByVersion(func_version, (PyObject **) &new_code); - DPRINTF(2, "Function: version=%#x; new_func=%p, new_code=%p\n", - (int)func_version, new_func, new_code); - if (new_code != NULL) { - if (new_code == code) { - // Recursive call, bail (we could be here forever). - DPRINTF(2, "Bailing on recursive call to %s (%s:%d)\n", - PyUnicode_AsUTF8(new_code->co_qualname), - PyUnicode_AsUTF8(new_code->co_filename), - new_code->co_firstlineno); - OPT_STAT_INC(recursive_call); - ADD_TO_TRACE(uop, oparg, 0, target); - ADD_TO_TRACE(_EXIT_TRACE, 0, 0, 0); - goto done; - } - if (new_code->co_version != func_version) { - // func.__code__ was updated. - // Perhaps it may happen again, so don't bother tracing. - // TODO: Reason about this -- is it better to bail or not? - DPRINTF(2, "Bailing because co_version != func_version\n"); - ADD_TO_TRACE(uop, oparg, 0, target); - ADD_TO_TRACE(_EXIT_TRACE, 0, 0, 0); - goto done; - } - // Increment IP to the return address - instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + 1; - TRACE_STACK_PUSH(); - _Py_BloomFilter_Add(dependencies, new_code); - /* Set the operand to the callee's function or code object, - * to assist optimization passes. - * We prefer setting it to the function (for remove_globals()) - * but if that's not available but the code is available, - * use the code, setting the low bit so the optimizer knows. - */ - if (new_func != NULL) { - operand = (uintptr_t)new_func; - } - else if (new_code != NULL) { - operand = (uintptr_t)new_code | 1; - } - else { - operand = 0; - } - ADD_TO_TRACE(uop, oparg, operand, target); - code = new_code; - func = new_func; - instr = _PyCode_CODE(code); - DPRINTF(2, - "Continuing in %s (%s:%d) at byte offset %d\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - 2 * INSTR_IP(instr, code)); - goto top; - } - DPRINTF(2, "Bail, new_code == NULL\n"); - OPT_STAT_INC(unknown_callee); - return 0; - } - - if (uop == _BINARY_OP_INPLACE_ADD_UNICODE) { - assert(i + 1 == nuops); - _Py_CODEUNIT *next_instr = instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; - assert(next_instr->op.code == STORE_FAST); - operand = next_instr->op.arg; - // Skip the STORE_FAST: - instr++; - } - - // All other instructions - ADD_TO_TRACE(uop, oparg, operand, target); - } + ADD_TO_TRACE(uop, oparg, operand, target); + trace[trace_length - 1].operand1 = PyStackRef_IsNone(frame->f_executable) ? 2 : ((int)(frame->stackpointer - _PyFrame_Stackbase(frame))); break; } - DPRINTF(2, "Unsupported opcode %s\n", _PyOpcode_OpName[opcode]); - OPT_UNSUPPORTED_OPCODE(opcode); - goto done; // Break out of loop - } // End default + if (uop == _BINARY_OP_INPLACE_ADD_UNICODE) { + assert(i + 1 == nuops); + _Py_CODEUNIT *next = target_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; + assert(next->op.code == STORE_FAST); + operand = next->op.arg; + } + // All other instructions + ADD_TO_TRACE(uop, oparg, operand, target); + } + break; + } // End default - } // End switch (opcode) + } // End switch (opcode) - instr++; - // Add cache size for opcode - instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; - - if (opcode == CALL_LIST_APPEND) { - assert(instr->op.code == POP_TOP); - instr++; + if (needs_guard_ip) { + uint16_t guard_ip = guard_ip_uop[trace[trace_length-1].opcode]; + if (guard_ip == 0) { + DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[trace[trace_length-1].opcode]); + Py_UNREACHABLE(); } - top: - // Jump here after _PUSH_FRAME or likely branches. - first = false; - } // End for (;;) - -done: - while (trace_stack_depth > 0) { - TRACE_STACK_POP(); + ADD_TO_TRACE(guard_ip, 0, (uintptr_t)next_instr, 0); } - assert(code == initial_code); - // Skip short traces where we can't even translate a single instruction: - if (first) { - OPT_STAT_INC(trace_too_short); - DPRINTF(2, - "No trace for %s (%s:%d) at byte offset %d (no progress)\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - 2 * INSTR_IP(initial_instr, code)); + // Loop back to the start + int is_first_instr = _tstate->jit_tracer_state.initial_state.close_loop_instr == next_instr || + _tstate->jit_tracer_state.initial_state.start_instr == next_instr; + if (is_first_instr && _tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS) { + if (needs_guard_ip) { + ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)next_instr, 0); + } + ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0); + goto done; + } + DPRINTF(2, "Trace continuing\n"); + _tstate->jit_tracer_state.prev_state.code_curr_size = trace_length; + _tstate->jit_tracer_state.prev_state.code_max_size = max_length; + return 1; +done: + DPRINTF(2, "Trace done\n"); + _tstate->jit_tracer_state.prev_state.code_curr_size = trace_length; + _tstate->jit_tracer_state.prev_state.code_max_size = max_length; + return 0; +full: + DPRINTF(2, "Trace full\n"); + if (!is_terminator(&_tstate->jit_tracer_state.code_buffer[trace_length-1])) { + // Undo the last few instructions. + trace_length = _tstate->jit_tracer_state.prev_state.code_curr_size; + max_length = _tstate->jit_tracer_state.prev_state.code_max_size; + // We previously reversed one. + max_length += 1; + ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target); + trace[trace_length-1].operand1 = true; // is_control_flow + } + _tstate->jit_tracer_state.prev_state.code_curr_size = trace_length; + _tstate->jit_tracer_state.prev_state.code_max_size = max_length; + return 0; +} + +// Returns 0 for do not enter tracing, 1 on enter tracing. +// gh-142543: inlining this function causes stack overflows +Py_NO_INLINE int +_PyJit_TryInitializeTracing( + PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *curr_instr, + _Py_CODEUNIT *start_instr, _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, + _PyExitData *exit, int oparg) +{ + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + // A recursive trace. + // Don't trace into the inner call because it will stomp on the previous trace, causing endless retraces. + if (_tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_EMPTY) { return 0; } - if (!is_terminator(&trace[trace_length-1])) { - /* Allow space for _EXIT_TRACE */ - max_length += 2; - ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target); + if (oparg > 0xFFFF) { + return 0; } - DPRINTF(1, - "Created a proto-trace for %s (%s:%d) at byte offset %d -- length %d\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - 2 * INSTR_IP(initial_instr, code), - trace_length); - OPT_HIST(trace_length, trace_length_hist); - return trace_length; + if (_tstate->jit_tracer_state.code_buffer == NULL) { + _tstate->jit_tracer_state.code_buffer = (_PyUOpInstruction *)_PyObject_VirtualAlloc(UOP_BUFFER_SIZE); + if (_tstate->jit_tracer_state.code_buffer == NULL) { + // Don't error, just go to next instruction. + return 0; + } + } + PyObject *func = PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + if (func == NULL) { + return 0; + } + PyCodeObject *code = _PyFrame_GetCode(frame); +#ifdef Py_DEBUG + char *python_lltrace = Py_GETENV("PYTHON_LLTRACE"); + int lltrace = 0; + if (python_lltrace != NULL && *python_lltrace >= '0') { + lltrace = *python_lltrace - '0'; // TODO: Parse an int and all that + } + DPRINTF(2, + "Tracing %s (%s:%d) at byte offset %d at chain depth %d\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + 2 * INSTR_IP(close_loop_instr, code), + chain_depth); +#endif + + add_to_trace(_tstate->jit_tracer_state.code_buffer, 0, _START_EXECUTOR, 0, (uintptr_t)start_instr, INSTR_IP(start_instr, code)); + add_to_trace(_tstate->jit_tracer_state.code_buffer, 1, _MAKE_WARM, 0, 0, 0); + _tstate->jit_tracer_state.prev_state.code_curr_size = CODE_SIZE_EMPTY; + + _tstate->jit_tracer_state.prev_state.code_max_size = UOP_MAX_TRACE_LENGTH/2; + _tstate->jit_tracer_state.initial_state.start_instr = start_instr; + _tstate->jit_tracer_state.initial_state.close_loop_instr = close_loop_instr; + _tstate->jit_tracer_state.initial_state.code = (PyCodeObject *)Py_NewRef(code); + _tstate->jit_tracer_state.initial_state.func = (PyFunctionObject *)Py_NewRef(func); + _tstate->jit_tracer_state.initial_state.exit = exit; + _tstate->jit_tracer_state.initial_state.stack_depth = curr_stackdepth; + _tstate->jit_tracer_state.initial_state.chain_depth = chain_depth; + _tstate->jit_tracer_state.prev_state.instr_frame = frame; + _tstate->jit_tracer_state.prev_state.dependencies_still_valid = true; + _tstate->jit_tracer_state.prev_state.instr_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame)); + _tstate->jit_tracer_state.prev_state.instr = curr_instr; + _tstate->jit_tracer_state.prev_state.instr_frame = frame; + _tstate->jit_tracer_state.prev_state.instr_oparg = oparg; + _tstate->jit_tracer_state.prev_state.instr_stacklevel = curr_stackdepth; + _tstate->jit_tracer_state.prev_state.instr_is_super = false; + assert(curr_instr->op.code == JUMP_BACKWARD_JIT || (exit != NULL)); + _tstate->jit_tracer_state.initial_state.jump_backward_instr = curr_instr; + + if (_PyOpcode_Caches[_PyOpcode_Deopt[close_loop_instr->op.code]]) { + close_loop_instr[1].counter = trigger_backoff_counter(); + } + _Py_BloomFilter_Init(&_tstate->jit_tracer_state.prev_state.dependencies); + return 1; } +Py_NO_INLINE void +_PyJit_FinalizeTracing(PyThreadState *tstate) +{ + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + Py_CLEAR(_tstate->jit_tracer_state.initial_state.code); + Py_CLEAR(_tstate->jit_tracer_state.initial_state.func); + Py_CLEAR(_tstate->jit_tracer_state.prev_state.instr_code); + _tstate->jit_tracer_state.prev_state.code_curr_size = CODE_SIZE_EMPTY; + _tstate->jit_tracer_state.prev_state.code_max_size = UOP_MAX_TRACE_LENGTH/2 - 1; +} + + #undef RESERVE #undef RESERVE_RAW #undef INSTR_IP @@ -1000,21 +1097,42 @@ count_exits(_PyUOpInstruction *buffer, int length) { int exit_count = 0; for (int i = 0; i < length; i++) { - int opcode = buffer[i].opcode; - if (opcode == _EXIT_TRACE) { + uint16_t base_opcode = _PyUop_Uncached[buffer[i].opcode]; + if (base_opcode == _EXIT_TRACE || base_opcode == _DYNAMIC_EXIT) { exit_count++; } } return exit_count; } -static void make_exit(_PyUOpInstruction *inst, int opcode, int target) +/* The number of cached registers at any exit (`EXIT_IF` or `DEOPT_IF`) + * This is the number of cached at entries at start, unless the uop is + * marked as `exit_depth_is_output` in which case it is the number of + * cached entries at the end */ +static int +get_cached_entries_for_side_exit(_PyUOpInstruction *inst) { + // Maybe add another generated table for this? + int base_opcode = _PyUop_Uncached[inst->opcode]; + assert(base_opcode != 0); + for (int i = 0; i <= MAX_CACHED_REGISTER; i++) { + const _PyUopTOSentry *entry = &_PyUop_Caching[base_opcode].entries[i]; + if (entry->opcode == inst->opcode) { + return entry->exit; + } + } + Py_UNREACHABLE(); +} + +static void make_exit(_PyUOpInstruction *inst, int opcode, int target, bool is_control_flow) +{ + assert(opcode > MAX_UOP_ID && opcode <= MAX_UOP_REGS_ID); inst->opcode = opcode; inst->oparg = 0; inst->operand0 = 0; inst->format = UOP_FORMAT_TARGET; inst->target = target; + inst->operand1 = is_control_flow; #ifdef Py_STATS inst->execution_count = 0; #endif @@ -1046,27 +1164,33 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length) int next_spare = length; for (int i = 0; i < length; i++) { _PyUOpInstruction *inst = &buffer[i]; - int opcode = inst->opcode; + int base_opcode = _PyUop_Uncached[inst->opcode]; + assert(inst->opcode != _NOP); int32_t target = (int32_t)uop_get_target(inst); - uint16_t exit_flags = _PyUop_Flags[opcode] & (HAS_EXIT_FLAG | HAS_DEOPT_FLAG | HAS_PERIODIC_FLAG); + uint16_t exit_flags = _PyUop_Flags[base_opcode] & (HAS_EXIT_FLAG | HAS_DEOPT_FLAG | HAS_PERIODIC_FLAG); if (exit_flags) { - uint16_t exit_op = _EXIT_TRACE; + uint16_t base_exit_op = _EXIT_TRACE; if (exit_flags & HAS_DEOPT_FLAG) { - exit_op = _DEOPT; + base_exit_op = _DEOPT; } else if (exit_flags & HAS_PERIODIC_FLAG) { - exit_op = _HANDLE_PENDING_AND_DEOPT; + base_exit_op = _HANDLE_PENDING_AND_DEOPT; } int32_t jump_target = target; - if (is_for_iter_test[opcode]) { - /* Target the POP_TOP immediately after the END_FOR, - * leaving only the iterator on the stack. */ - int extended_arg = inst->oparg > 255; - int32_t next_inst = target + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + extended_arg; - jump_target = next_inst + inst->oparg + 1; + if ( + base_opcode == _GUARD_IP__PUSH_FRAME || + base_opcode == _GUARD_IP_RETURN_VALUE || + base_opcode == _GUARD_IP_YIELD_VALUE || + base_opcode == _GUARD_IP_RETURN_GENERATOR + ) { + base_exit_op = _DYNAMIC_EXIT; } + int exit_depth = get_cached_entries_for_side_exit(inst); + assert(_PyUop_Caching[base_exit_op].entries[exit_depth].opcode > 0); + int16_t exit_op = _PyUop_Caching[base_exit_op].entries[exit_depth].opcode; + bool is_control_flow = (base_opcode == _GUARD_IS_FALSE_POP || base_opcode == _GUARD_IS_TRUE_POP || is_for_iter_test[base_opcode]); if (jump_target != current_jump_target || current_exit_op != exit_op) { - make_exit(&buffer[next_spare], exit_op, jump_target); + make_exit(&buffer[next_spare], exit_op, jump_target, is_control_flow); current_exit_op = exit_op; current_jump_target = jump_target; current_jump = next_spare; @@ -1075,14 +1199,14 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length) buffer[i].jump_target = current_jump; buffer[i].format = UOP_FORMAT_JUMP; } - if (_PyUop_Flags[opcode] & HAS_ERROR_FLAG) { - int popped = (_PyUop_Flags[opcode] & HAS_ERROR_NO_POP_FLAG) ? - 0 : _PyUop_num_popped(opcode, inst->oparg); + if (_PyUop_Flags[base_opcode] & HAS_ERROR_FLAG) { + int popped = (_PyUop_Flags[base_opcode] & HAS_ERROR_NO_POP_FLAG) ? + 0 : _PyUop_num_popped(base_opcode, inst->oparg); if (target != current_error_target || popped != current_popped) { current_popped = popped; current_error = next_spare; current_error_target = target; - make_exit(&buffer[next_spare], _ERROR_POP_N, 0); + make_exit(&buffer[next_spare], _ERROR_POP_N_r00, 0, false); buffer[next_spare].operand0 = target; next_spare++; } @@ -1092,8 +1216,8 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length) buffer[i].jump_target = 0; } } - if (opcode == _JUMP_TO_TOP) { - assert(buffer[0].opcode == _START_EXECUTOR); + if (base_opcode == _JUMP_TO_TOP) { + assert(_PyUop_Uncached[buffer[0].opcode] == _START_EXECUTOR); buffer[i].format = UOP_FORMAT_JUMP; buffer[i].jump_target = 1; } @@ -1140,21 +1264,26 @@ sanity_check(_PyExecutorObject *executor) } bool ended = false; uint32_t i = 0; - CHECK(executor->trace[0].opcode == _START_EXECUTOR || executor->trace[0].opcode == _COLD_EXIT); + CHECK(_PyUop_Uncached[executor->trace[0].opcode] == _START_EXECUTOR || + _PyUop_Uncached[executor->trace[0].opcode] == _COLD_EXIT || + _PyUop_Uncached[executor->trace[0].opcode] == _COLD_DYNAMIC_EXIT); for (; i < executor->code_size; i++) { const _PyUOpInstruction *inst = &executor->trace[i]; uint16_t opcode = inst->opcode; - CHECK(opcode <= MAX_UOP_ID); - CHECK(_PyOpcode_uop_name[opcode] != NULL); + uint16_t base_opcode = _PyUop_Uncached[opcode]; + CHECK(opcode > MAX_UOP_ID); + CHECK(opcode <= MAX_UOP_REGS_ID); + CHECK(base_opcode <= MAX_UOP_ID); + CHECK(base_opcode != 0); switch(inst->format) { case UOP_FORMAT_TARGET: - CHECK(target_unused(opcode)); + CHECK(target_unused(base_opcode)); break; case UOP_FORMAT_JUMP: CHECK(inst->jump_target < executor->code_size); break; } - if (_PyUop_Flags[opcode] & HAS_ERROR_FLAG) { + if (_PyUop_Flags[base_opcode] & HAS_ERROR_FLAG) { CHECK(inst->format == UOP_FORMAT_JUMP); CHECK(inst->error_target < executor->code_size); } @@ -1167,12 +1296,13 @@ sanity_check(_PyExecutorObject *executor) CHECK(ended); for (; i < executor->code_size; i++) { const _PyUOpInstruction *inst = &executor->trace[i]; - uint16_t opcode = inst->opcode; + uint16_t base_opcode = _PyUop_Uncached[inst->opcode]; CHECK( - opcode == _DEOPT || - opcode == _HANDLE_PENDING_AND_DEOPT || - opcode == _EXIT_TRACE || - opcode == _ERROR_POP_N); + base_opcode == _DEOPT || + base_opcode == _HANDLE_PENDING_AND_DEOPT || + base_opcode == _EXIT_TRACE || + base_opcode == _ERROR_POP_N || + base_opcode == _DYNAMIC_EXIT); } } @@ -1185,7 +1315,7 @@ sanity_check(_PyExecutorObject *executor) * and not a NOP. */ static _PyExecutorObject * -make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies) +make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies, int chain_depth) { int exit_count = count_exits(buffer, length); _PyExecutorObject *executor = allocate_executor(exit_count, length); @@ -1195,30 +1325,37 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil /* Initialize exits */ _PyExecutorObject *cold = _PyExecutor_GetColdExecutor(); + _PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor(); + cold->vm_data.chain_depth = chain_depth; for (int i = 0; i < exit_count; i++) { executor->exits[i].index = i; executor->exits[i].temperature = initial_temperature_backoff_counter(); - executor->exits[i].executor = cold; } int next_exit = exit_count-1; _PyUOpInstruction *dest = (_PyUOpInstruction *)&executor->trace[length]; - assert(buffer[0].opcode == _START_EXECUTOR); + assert(_PyUop_Uncached[buffer[0].opcode] == _START_EXECUTOR); buffer[0].operand0 = (uint64_t)executor; for (int i = length-1; i >= 0; i--) { - int opcode = buffer[i].opcode; + uint16_t base_opcode = _PyUop_Uncached[buffer[i].opcode]; dest--; *dest = buffer[i]; - assert(opcode != _POP_JUMP_IF_FALSE && opcode != _POP_JUMP_IF_TRUE); - if (opcode == _EXIT_TRACE) { + if (base_opcode == _EXIT_TRACE || base_opcode == _DYNAMIC_EXIT) { _PyExitData *exit = &executor->exits[next_exit]; exit->target = buffer[i].target; dest->operand0 = (uint64_t)exit; + exit->executor = base_opcode == _EXIT_TRACE ? cold : cold_dynamic; + exit->is_dynamic = (char)(base_opcode == _DYNAMIC_EXIT); + exit->is_control_flow = (char)buffer[i].operand1; next_exit--; } } assert(next_exit == -1); assert(dest == executor->trace); - assert(dest->opcode == _START_EXECUTOR); + assert(_PyUop_Uncached[dest->opcode] == _START_EXECUTOR); + // Note: we MUST track it here before any Py_DECREF(executor) or + // linking of executor. Otherwise, the GC tries to untrack a + // still untracked object during dealloc. + _PyObject_GC_TRACK(executor); _Py_ExecutorInit(executor, dependencies); #ifdef Py_DEBUG char *python_lltrace = Py_GETENV("PYTHON_LLTRACE"); @@ -1247,7 +1384,6 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil return NULL; } #endif - _PyObject_GC_TRACK(executor); return executor; } @@ -1271,35 +1407,77 @@ int effective_trace_length(_PyUOpInstruction *buffer, int length) } #endif + +static int +stack_allocate(_PyUOpInstruction *buffer, int length) +{ + assert(buffer[0].opcode == _START_EXECUTOR); + for (int i = length-1; i >= 0; i--) { + buffer[i*2+1] = buffer[i]; + buffer[i*2].format = UOP_FORMAT_TARGET; + buffer[i*2].oparg = 0; + buffer[i*2].target = 0; + } + int depth = 0; + for (int i = 0; i < length; i++) { + _PyUOpInstruction *spill_or_reload = &buffer[i*2]; + int uop = buffer[i*2+1].opcode; + if (uop == _NOP) { + // leave _NOPs to be cleaned up later + spill_or_reload->opcode = _NOP; + continue; + } + int new_depth = _PyUop_Caching[uop].best[depth]; + if (new_depth == depth) { + spill_or_reload->opcode = _NOP; + } + else { + spill_or_reload->opcode = _PyUop_SpillsAndReloads[depth][new_depth]; + depth = new_depth; + } + uint16_t new_opcode = _PyUop_Caching[uop].entries[depth].opcode; + assert(new_opcode != 0); + assert(spill_or_reload->opcode != 0); + buffer[i*2+1].opcode = new_opcode; + depth = _PyUop_Caching[uop].entries[depth].output; + } + return length*2; +} + static int uop_optimize( _PyInterpreterFrame *frame, - _Py_CODEUNIT *instr, + PyThreadState *tstate, _PyExecutorObject **exec_ptr, - int curr_stackentries, bool progress_needed) { - _PyBloomFilter dependencies; - _Py_BloomFilter_Init(&dependencies); - _PyUOpInstruction buffer[UOP_MAX_TRACE_LENGTH]; + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + _PyBloomFilter *dependencies = &_tstate->jit_tracer_state.prev_state.dependencies; + _PyUOpInstruction *buffer = _tstate->jit_tracer_state.code_buffer; OPT_STAT_INC(attempts); - int length = translate_bytecode_to_trace(frame, instr, buffer, UOP_MAX_TRACE_LENGTH, &dependencies, progress_needed); - if (length <= 0) { - // Error or nothing translated - return length; - } - assert(length < UOP_MAX_TRACE_LENGTH); - OPT_STAT_INC(traces_created); char *env_var = Py_GETENV("PYTHON_UOPS_OPTIMIZE"); + bool is_noopt = true; if (env_var == NULL || *env_var == '\0' || *env_var > '0') { - length = _Py_uop_analyze_and_optimize(frame, buffer, - length, - curr_stackentries, &dependencies); + is_noopt = false; + } + int curr_stackentries = _tstate->jit_tracer_state.initial_state.stack_depth; + int length = _tstate->jit_tracer_state.prev_state.code_curr_size; + if (length <= CODE_SIZE_NO_PROGRESS) { + return 0; + } + assert(length > 0); + assert(length < UOP_MAX_TRACE_LENGTH/2); + OPT_STAT_INC(traces_created); + if (!is_noopt) { + length = _Py_uop_analyze_and_optimize( + _tstate->jit_tracer_state.initial_state.func, + buffer,length, + curr_stackentries, dependencies); if (length <= 0) { return length; } } - assert(length < UOP_MAX_TRACE_LENGTH); + assert(length < UOP_MAX_TRACE_LENGTH/2); assert(length >= 1); /* Fix up */ for (int pc = 0; pc < length; pc++) { @@ -1315,13 +1493,22 @@ uop_optimize( assert(_PyOpcode_uop_name[buffer[pc].opcode]); } OPT_HIST(effective_trace_length(buffer, length), optimized_trace_length_hist); + length = stack_allocate(buffer, length); length = prepare_for_execution(buffer, length); assert(length <= UOP_MAX_TRACE_LENGTH); - _PyExecutorObject *executor = make_executor_from_uops(buffer, length, &dependencies); + _PyExecutorObject *executor = make_executor_from_uops( + buffer, length, dependencies, _tstate->jit_tracer_state.initial_state.chain_depth); if (executor == NULL) { return -1; } assert(length <= UOP_MAX_TRACE_LENGTH); + + // Check executor coldness + // It's okay if this ends up going negative. + if (--tstate->interp->executor_creation_counter == 0) { + _Py_set_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT); + } + *exec_ptr = executor; return 1; } @@ -1486,7 +1673,7 @@ _PyExecutor_GetColdExecutor(void) if (cold == NULL) { Py_FatalError("Cannot allocate core JIT code"); } - ((_PyUOpInstruction *)cold->trace)->opcode = _COLD_EXIT; + ((_PyUOpInstruction *)cold->trace)->opcode = _COLD_EXIT_r00; #ifdef _Py_JIT cold->jit_code = NULL; cold->jit_size = 0; @@ -1503,6 +1690,35 @@ _PyExecutor_GetColdExecutor(void) return cold; } +_PyExecutorObject * +_PyExecutor_GetColdDynamicExecutor(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->cold_dynamic_executor != NULL) { + assert(interp->cold_dynamic_executor->trace[0].opcode == _COLD_DYNAMIC_EXIT_r00); + return interp->cold_dynamic_executor; + } + _PyExecutorObject *cold = allocate_executor(0, 1); + if (cold == NULL) { + Py_FatalError("Cannot allocate core JIT code"); + } + ((_PyUOpInstruction *)cold->trace)->opcode = _COLD_DYNAMIC_EXIT_r00; +#ifdef _Py_JIT + cold->jit_code = NULL; + cold->jit_size = 0; + // This is initialized to true so we can prevent the executor + // from being immediately detected as cold and invalidated. + cold->vm_data.warm = true; + if (_PyJIT_Compile(cold, cold->trace, 1)) { + Py_DECREF(cold); + Py_FatalError("Cannot allocate core JIT code"); + } +#endif + _Py_SetImmortal((PyObject *)cold); + interp->cold_dynamic_executor = cold; + return cold; +} + void _PyExecutor_ClearExit(_PyExitData *exit) { @@ -1510,7 +1726,12 @@ _PyExecutor_ClearExit(_PyExitData *exit) return; } _PyExecutorObject *old = exit->executor; - exit->executor = _PyExecutor_GetColdExecutor(); + if (exit->is_dynamic) { + exit->executor = _PyExecutor_GetColdDynamicExecutor(); + } + else { + exit->executor = _PyExecutor_GetColdExecutor(); + } Py_DECREF(old); } @@ -1612,6 +1833,18 @@ error: _Py_Executors_InvalidateAll(interp, is_invalidation); } +void +_PyJit_Tracer_InvalidateDependency(PyThreadState *tstate, void *obj) +{ + _PyBloomFilter obj_filter; + _Py_BloomFilter_Init(&obj_filter); + _Py_BloomFilter_Add(&obj_filter, obj); + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + if (bloom_filter_may_contain(&_tstate->jit_tracer_state.prev_state.dependencies, &obj_filter)) + { + _tstate->jit_tracer_state.prev_state.dependencies_still_valid = false; + } +} /* Invalidate all executors */ void _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation) @@ -1737,13 +1970,14 @@ executor_to_gv(_PyExecutorObject *executor, FILE *out) * https://graphviz.readthedocs.io/en/stable/manual.html#node-ports-compass */ _PyUOpInstruction const *inst = &executor->trace[i]; - const char *opname = _PyOpcode_uop_name[inst->opcode]; + uint16_t base_opcode = _PyUop_Uncached[inst->opcode]; + const char *opname = _PyOpcode_uop_name[base_opcode]; #ifdef Py_STATS fprintf(out, " <tr><td port=\"i%d\" border=\"1\" >%s -- %" PRIu64 "</td></tr>\n", i, opname, inst->execution_count); #else - fprintf(out, " <tr><td port=\"i%d\" border=\"1\" >%s</td></tr>\n", i, opname); + fprintf(out, " <tr><td port=\"i%d\" border=\"1\" >%s op0=%" PRIu64 "</td></tr>\n", i, opname, inst->operand0); #endif - if (inst->opcode == _EXIT_TRACE || inst->opcode == _JUMP_TO_TOP) { + if (base_opcode == _EXIT_TRACE || base_opcode == _JUMP_TO_TOP) { break; } } @@ -1751,23 +1985,27 @@ executor_to_gv(_PyExecutorObject *executor, FILE *out) fprintf(out, "]\n\n"); /* Write all the outgoing edges */ + _PyExecutorObject *cold = _PyExecutor_GetColdExecutor(); + _PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor(); for (uint32_t i = 0; i < executor->code_size; i++) { _PyUOpInstruction const *inst = &executor->trace[i]; - uint16_t flags = _PyUop_Flags[inst->opcode]; + uint16_t base_opcode = _PyUop_Uncached[inst->opcode]; + uint16_t flags = _PyUop_Flags[base_opcode]; _PyExitData *exit = NULL; - if (inst->opcode == _EXIT_TRACE) { + if (base_opcode == _EXIT_TRACE) { exit = (_PyExitData *)inst->operand0; } else if (flags & HAS_EXIT_FLAG) { assert(inst->format == UOP_FORMAT_JUMP); _PyUOpInstruction const *exit_inst = &executor->trace[inst->jump_target]; - assert(exit_inst->opcode == _EXIT_TRACE); + uint16_t base_exit_opcode = _PyUop_Uncached[exit_inst->opcode]; + assert(base_exit_opcode == _EXIT_TRACE || base_exit_opcode == _DYNAMIC_EXIT); exit = (_PyExitData *)exit_inst->operand0; } - if (exit != NULL && exit->executor != NULL) { + if (exit != NULL && exit->executor != cold && exit->executor != cold_dynamic) { fprintf(out, "executor_%p:i%d -> executor_%p:start\n", executor, i, exit->executor); } - if (inst->opcode == _EXIT_TRACE || inst->opcode == _JUMP_TO_TOP) { + if (base_opcode == _EXIT_TRACE || base_opcode == _JUMP_TO_TOP) { break; } } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 533d70580e4..a0210fdcbff 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -128,198 +128,28 @@ convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop) return res; } -static int -incorrect_keys(_PyUOpInstruction *inst, PyObject *obj) +static bool +incorrect_keys(PyObject *obj, uint32_t version) { if (!PyDict_CheckExact(obj)) { - return 1; + return true; } PyDictObject *dict = (PyDictObject *)obj; - if (dict->ma_keys->dk_version != inst->operand0) { - return 1; - } - return 0; + return dict->ma_keys->dk_version != version; } -/* Returns 1 if successfully optimized - * 0 if the trace is not suitable for optimization (yet) - * -1 if there was an error. */ -static int -remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, - int buffer_size, _PyBloomFilter *dependencies) -{ - PyInterpreterState *interp = _PyInterpreterState_GET(); - PyObject *builtins = frame->f_builtins; - if (builtins != interp->builtins) { - OPT_STAT_INC(remove_globals_builtins_changed); - return 1; - } - PyObject *globals = frame->f_globals; - PyFunctionObject *function = _PyFrame_GetFunction(frame); - assert(PyFunction_Check(function)); - assert(function->func_builtins == builtins); - assert(function->func_globals == globals); - uint32_t function_version = _PyFunction_GetVersionForCurrentState(function); - /* In order to treat globals as constants, we need to - * know that the globals dict is the one we expected, and - * that it hasn't changed - * In order to treat builtins as constants, we need to - * know that the builtins dict is the one we expected, and - * that it hasn't changed and that the global dictionary's - * keys have not changed */ - - /* These values represent stacks of booleans (one bool per bit). - * Pushing a frame shifts left, popping a frame shifts right. */ - uint32_t function_checked = 0; - uint32_t builtins_watched = 0; - uint32_t globals_watched = 0; - uint32_t prechecked_function_version = 0; - if (interp->dict_state.watchers[GLOBALS_WATCHER_ID] == NULL) { - interp->dict_state.watchers[GLOBALS_WATCHER_ID] = globals_watcher_callback; - } - if (interp->type_watchers[TYPE_WATCHER_ID] == NULL) { - interp->type_watchers[TYPE_WATCHER_ID] = type_watcher_callback; - } - for (int pc = 0; pc < buffer_size; pc++) { - _PyUOpInstruction *inst = &buffer[pc]; - int opcode = inst->opcode; - switch(opcode) { - case _GUARD_GLOBALS_VERSION: - if (incorrect_keys(inst, globals)) { - OPT_STAT_INC(remove_globals_incorrect_keys); - return 0; - } - if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { - continue; - } - if ((globals_watched & 1) == 0) { - PyDict_Watch(GLOBALS_WATCHER_ID, globals); - _Py_BloomFilter_Add(dependencies, globals); - globals_watched |= 1; - } - if (function_checked & 1) { - buffer[pc].opcode = NOP; - } - else { - buffer[pc].opcode = _CHECK_FUNCTION; - buffer[pc].operand0 = function_version; - function_checked |= 1; - } - break; - case _LOAD_GLOBAL_BUILTINS: - if (incorrect_keys(inst, builtins)) { - OPT_STAT_INC(remove_globals_incorrect_keys); - return 0; - } - if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { - continue; - } - if ((builtins_watched & 1) == 0) { - PyDict_Watch(BUILTINS_WATCHER_ID, builtins); - builtins_watched |= 1; - } - if (function_checked & globals_watched & 1) { - convert_global_to_const(inst, builtins, false); - } - break; - case _LOAD_GLOBAL_MODULE: - if (incorrect_keys(inst, globals)) { - OPT_STAT_INC(remove_globals_incorrect_keys); - return 0; - } - if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { - continue; - } - if ((globals_watched & 1) == 0) { - PyDict_Watch(GLOBALS_WATCHER_ID, globals); - _Py_BloomFilter_Add(dependencies, globals); - globals_watched |= 1; - } - if ((function_checked & 1) == 0 && buffer[pc-1].opcode == _NOP) { - buffer[pc-1].opcode = _CHECK_FUNCTION; - buffer[pc-1].operand0 = function_version; - function_checked |= 1; - } - if (function_checked & 1) { - convert_global_to_const(inst, globals, false); - } - break; - case _PUSH_FRAME: - { - builtins_watched <<= 1; - globals_watched <<= 1; - function_checked <<= 1; - uint64_t operand = buffer[pc].operand0; - if (operand == 0 || (operand & 1)) { - // It's either a code object or NULL, so bail - return 1; - } - PyFunctionObject *func = (PyFunctionObject *)operand; - if (func == NULL) { - return 1; - } - assert(PyFunction_Check(func)); - function_version = func->func_version; - if (prechecked_function_version == function_version) { - function_checked |= 1; - } - prechecked_function_version = 0; - globals = func->func_globals; - builtins = func->func_builtins; - if (builtins != interp->builtins) { - OPT_STAT_INC(remove_globals_builtins_changed); - return 1; - } - break; - } - case _RETURN_VALUE: - { - builtins_watched >>= 1; - globals_watched >>= 1; - function_checked >>= 1; - uint64_t operand = buffer[pc].operand0; - if (operand == 0 || (operand & 1)) { - // It's either a code object or NULL, so bail - return 1; - } - PyFunctionObject *func = (PyFunctionObject *)operand; - if (func == NULL) { - return 1; - } - assert(PyFunction_Check(func)); - function_version = func->func_version; - globals = func->func_globals; - builtins = func->func_builtins; - break; - } - case _CHECK_FUNCTION_EXACT_ARGS: - prechecked_function_version = (uint32_t)buffer[pc].operand0; - break; - default: - if (is_terminator(inst)) { - return 1; - } - break; - } - } - return 0; -} - - #define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) #define STACK_SIZE() ((int)(ctx->frame->stack_len)) -#define WITHIN_STACK_BOUNDS() \ - (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE()) - +#define CURRENT_FRAME_IS_INIT_SHIM() (ctx->frame->code == ((PyCodeObject *)&_Py_InitCleanup)) #define GETLOCAL(idx) ((ctx->frame->locals[idx])) #define REPLACE_OP(INST, OP, ARG, OPERAND) \ - INST->opcode = OP; \ - INST->oparg = ARG; \ - INST->operand0 = OPERAND; + (INST)->opcode = OP; \ + (INST)->oparg = ARG; \ + (INST)->operand0 = OPERAND; /* Shortened forms for convenience, used in optimizer_bytecodes.c */ #define sym_is_not_null _Py_uop_sym_is_not_null @@ -358,6 +188,27 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, #define JUMP_TO_LABEL(label) goto label; +static int +check_stack_bounds(JitOptContext *ctx, JitOptRef *stack_pointer, int offset, int opcode) +{ + int stack_level = (int)(stack_pointer + (offset) - ctx->frame->stack); + int should_check = !CURRENT_FRAME_IS_INIT_SHIM() || + (opcode == _RETURN_VALUE) || + (opcode == _RETURN_GENERATOR) || + (opcode == _YIELD_VALUE); + if (should_check && (stack_level < 0 || stack_level > STACK_SIZE() + MAX_CACHED_REGISTER)) { + ctx->contradiction = true; + ctx->done = true; + return 1; + } + return 0; +} + +#define CHECK_STACK_BOUNDS(offset) \ + if (check_stack_bounds(ctx, stack_pointer, offset, opcode)) { \ + break; \ + } \ + static int optimize_to_bool( _PyUOpInstruction *this_instr, @@ -391,7 +242,7 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit) } static JitOptRef -lookup_attr(JitOptContext *ctx, _PyUOpInstruction *this_instr, +lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction *this_instr, PyTypeObject *type, PyObject *name, uint16_t immortal, uint16_t mortal) { @@ -401,36 +252,14 @@ lookup_attr(JitOptContext *ctx, _PyUOpInstruction *this_instr, if (lookup) { int opcode = _Py_IsImmortal(lookup) ? immortal : mortal; REPLACE_OP(this_instr, opcode, 0, (uintptr_t)lookup); + PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); + _Py_BloomFilter_Add(dependencies, type); return sym_new_const(ctx, lookup); } } return sym_new_not_null(ctx); } -/* _PUSH_FRAME/_RETURN_VALUE's operand can be 0, a PyFunctionObject *, or a - * PyCodeObject *. Retrieve the code object if possible. - */ -static PyCodeObject * -get_code(_PyUOpInstruction *op) -{ - assert(op->opcode == _PUSH_FRAME || op->opcode == _RETURN_VALUE || op->opcode == _RETURN_GENERATOR); - PyCodeObject *co = NULL; - uint64_t operand = op->operand0; - if (operand == 0) { - return NULL; - } - if (operand & 1) { - co = (PyCodeObject *)(operand & ~1); - } - else { - PyFunctionObject *func = (PyFunctionObject *)operand; - assert(PyFunction_Check(func)); - co = (PyCodeObject *)func->func_code; - } - assert(PyCode_Check(co)); - return co; -} - static PyCodeObject * get_code_with_logging(_PyUOpInstruction *op) { @@ -455,48 +284,94 @@ get_code_with_logging(_PyUOpInstruction *op) return co; } -// TODO (gh-134584) generate most of this table automatically -const uint16_t op_without_decref_inputs[MAX_UOP_ID + 1] = { - [_BINARY_OP_MULTIPLY_FLOAT] = _BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS, - [_BINARY_OP_ADD_FLOAT] = _BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS, - [_BINARY_OP_SUBTRACT_FLOAT] = _BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS, -}; +static +PyCodeObject * +get_current_code_object(JitOptContext *ctx) +{ + return (PyCodeObject *)ctx->frame->code; +} -/* 1 for success, 0 for not ready, cannot error at the moment. */ +static PyObject * +get_co_name(JitOptContext *ctx, int index) +{ + return PyTuple_GET_ITEM(get_current_code_object(ctx)->co_names, index); +} + +#ifdef Py_DEBUG +void +_Py_opt_assert_within_stack_bounds( + _Py_UOpsAbstractFrame *frame, JitOptRef *stack_pointer, + const char *filename, int lineno +) { + if (frame->code == ((PyCodeObject *)&_Py_InitCleanup)) { + return; + } + int level = (int)(stack_pointer - frame->stack); + if (level < 0) { + printf("Stack underflow (depth = %d) at %s:%d\n", level, filename, lineno); + fflush(stdout); + abort(); + } + int size = (int)(frame->stack_len) + MAX_CACHED_REGISTER; + if (level > size) { + printf("Stack overflow (depth = %d) at %s:%d\n", level, filename, lineno); + fflush(stdout); + abort(); + } +} +#endif + +#ifdef Py_DEBUG +#define ASSERT_WITHIN_STACK_BOUNDS(F, L) _Py_opt_assert_within_stack_bounds(ctx->frame, stack_pointer, (F), (L)) +#else +#define ASSERT_WITHIN_STACK_BOUNDS(F, L) (void)0 +#endif + +/* >0 (length) for success, 0 for not ready, clears all possible errors. */ static int optimize_uops( - PyCodeObject *co, + PyFunctionObject *func, _PyUOpInstruction *trace, int trace_len, int curr_stacklen, _PyBloomFilter *dependencies ) { + assert(!PyErr_Occurred()); JitOptContext context; JitOptContext *ctx = &context; uint32_t opcode = UINT16_MAX; - int curr_space = 0; - int max_space = 0; - _PyUOpInstruction *first_valid_check_stack = NULL; - _PyUOpInstruction *corresponding_check_stack = NULL; + + // Make sure that watchers are set up + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->dict_state.watchers[GLOBALS_WATCHER_ID] == NULL) { + interp->dict_state.watchers[GLOBALS_WATCHER_ID] = globals_watcher_callback; + interp->type_watchers[TYPE_WATCHER_ID] = type_watcher_callback; + } _Py_uop_abstractcontext_init(ctx); - _Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, co, curr_stacklen, NULL, 0); + _Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, (PyCodeObject *)func->func_code, curr_stacklen, NULL, 0); if (frame == NULL) { return 0; } + frame->func = func; ctx->curr_frame_depth++; ctx->frame = frame; _PyUOpInstruction *this_instr = NULL; + JitOptRef *stack_pointer = ctx->frame->stack_pointer; + for (int i = 0; !ctx->done; i++) { assert(i < trace_len); this_instr = &trace[i]; int oparg = this_instr->oparg; opcode = this_instr->opcode; - JitOptRef *stack_pointer = ctx->frame->stack_pointer; + + if (!CURRENT_FRAME_IS_INIT_SHIM()) { + stack_pointer = ctx->frame->stack_pointer; + } #ifdef Py_DEBUG if (get_lltrace() >= 3) { @@ -515,9 +390,11 @@ optimize_uops( Py_UNREACHABLE(); } assert(ctx->frame != NULL); - DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); - ctx->frame->stack_pointer = stack_pointer; - assert(STACK_LEVEL() >= 0); + if (!CURRENT_FRAME_IS_INIT_SHIM()) { + DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); + ctx->frame->stack_pointer = stack_pointer; + assert(STACK_LEVEL() >= 0); + } } if (ctx->out_of_space) { DPRINTF(3, "\n"); @@ -525,27 +402,21 @@ optimize_uops( } if (ctx->contradiction) { // Attempted to push a "bottom" (contradiction) symbol onto the stack. - // This means that the abstract interpreter has hit unreachable code. + // This means that the abstract interpreter has optimized to trace + // to an unreachable estate. // We *could* generate an _EXIT_TRACE or _FATAL_ERROR here, but hitting - // bottom indicates type instability, so we are probably better off + // bottom usually indicates an optimizer bug, so we are probably better off // retrying later. DPRINTF(3, "\n"); DPRINTF(1, "Hit bottom in abstract interpreter\n"); _Py_uop_abstractcontext_fini(ctx); + OPT_STAT_INC(optimizer_contradiction); return 0; } /* Either reached the end or cannot optimize further, but there * would be no benefit in retrying later */ _Py_uop_abstractcontext_fini(ctx); - if (first_valid_check_stack != NULL) { - assert(first_valid_check_stack->opcode == _CHECK_STACK_SPACE); - assert(max_space > 0); - assert(max_space <= INT_MAX); - assert(max_space <= INT32_MAX); - first_valid_check_stack->opcode = _CHECK_STACK_SPACE_OPERAND; - first_valid_check_stack->operand0 = max_space; - } return trace_len; error: @@ -555,7 +426,11 @@ error: OPT_ERROR_IN_OPCODE(opcode); } _Py_uop_abstractcontext_fini(ctx); - return -1; + + assert(PyErr_Occurred()); + PyErr_Clear(); + + return 0; } @@ -626,6 +501,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) buffer[pc].opcode = _NOP; } break; + case _EXIT_TRACE: default: { // Cancel out pushes and pops, repeatedly. So: @@ -642,7 +518,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) opcode = buffer[pc].opcode = op_without_pop[opcode]; if (op_without_pop[last->opcode]) { opcode = last->opcode; - pc = last - buffer; + pc = (int)(last - buffer); } } else if (last->opcode == _PUSH_NULL) { @@ -659,7 +535,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) } /* _PUSH_FRAME doesn't escape or error, but it * does need the IP for the return address */ - bool needs_ip = opcode == _PUSH_FRAME; + bool needs_ip = (opcode == _PUSH_FRAME || opcode == _YIELD_VALUE || opcode == _DYNAMIC_EXIT || opcode == _EXIT_TRACE); if (_PyUop_Flags[opcode] & HAS_ESCAPES_FLAG) { needs_ip = true; may_have_escaped = true; @@ -669,10 +545,14 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) buffer[last_set_ip].opcode = _SET_IP; last_set_ip = -1; } + if (opcode == _EXIT_TRACE) { + return pc + 1; + } break; } case _JUMP_TO_TOP: - case _EXIT_TRACE: + case _DYNAMIC_EXIT: + case _DEOPT: return pc + 1; } } @@ -684,7 +564,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) // > 0 - length of optimized trace int _Py_uop_analyze_and_optimize( - _PyInterpreterFrame *frame, + PyFunctionObject *func, _PyUOpInstruction *buffer, int length, int curr_stacklen, @@ -693,19 +573,16 @@ _Py_uop_analyze_and_optimize( { OPT_STAT_INC(optimizer_attempts); - int err = remove_globals(frame, buffer, length, dependencies); - if (err <= 0) { - return err; - } - length = optimize_uops( - _PyFrame_GetCode(frame), buffer, - length, curr_stacklen, dependencies); + func, buffer, + length, curr_stacklen, dependencies); - if (length <= 0) { + if (length == 0) { return length; } + assert(length > 0); + length = remove_unneeded_uops(buffer, length); assert(length > 0); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 77759f67532..e3921054f7c 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -99,10 +99,37 @@ dummy_func(void) { GETLOCAL(oparg) = temp; } + op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner -- o)) { + (void)value; + o = owner; + } + + op(_STORE_ATTR_WITH_HINT, (hint/1, value, owner -- o)) { + (void)value; + o = owner; + } + op(_STORE_FAST, (value --)) { GETLOCAL(oparg) = value; } + op(_STORE_SUBSCR_LIST_INT, (value, list_st, sub_st -- ls, ss)) { + (void)value; + ls = list_st; + ss = sub_st; + } + + op(_STORE_ATTR_SLOT, (index/1, value, owner -- o)) { + (void)index; + (void)value; + o = owner; + } + + op(_STORE_SUBSCR_DICT, (value, dict_st, sub -- st)) { + (void)value; + st = dict_st; + } + op(_PUSH_NULL, (-- res)) { res = sym_new_null(ctx); } @@ -235,54 +262,50 @@ dummy_func(void) { } } - op(_BINARY_OP_ADD_INT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_BINARY_OP_ADD_INT, (left, right -- res, l, r)) { res = sym_new_compact_int(ctx); + l = left; + r = right; } - op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_BINARY_OP_SUBTRACT_INT, (left, right -- res, l, r)) { res = sym_new_compact_int(ctx); + l = left; + r = right; } - op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_BINARY_OP_MULTIPLY_INT, (left, right -- res, l, r)) { res = sym_new_compact_int(ctx); + l = left; + r = right; } - op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_BINARY_OP_ADD_FLOAT, (left, right -- res, l, r)) { res = sym_new_type(ctx, &PyFloat_Type); - // TODO (gh-134584): Refactor this to use another uop - if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) { - REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0); - } + l = left; + r = right; } - op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res, l, r)) { res = sym_new_type(ctx, &PyFloat_Type); - // TODO (gh-134584): Refactor this to use another uop - if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) { - REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0); - } + l = left; + r = right; } - op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res, l, r)) { res = sym_new_type(ctx, &PyFloat_Type); - // TODO (gh-134584): Refactor this to use another uop - if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) { - REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0); - } + l = left; + r = right; } - op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { + op(_BINARY_OP_ADD_UNICODE, (left, right -- res, l, r)) { REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); res = sym_new_type(ctx, &PyUnicode_Type); + l = left; + r = right; } - op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) { + op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { JitOptRef res; if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { assert(PyUnicode_CheckExact(sym_get_const(ctx, left))); @@ -316,7 +339,7 @@ dummy_func(void) { assert(PyLong_CheckExact(sym_get_const(ctx, sub_st))); long index = PyLong_AsLong(sym_get_const(ctx, sub_st)); assert(index >= 0); - int tuple_length = sym_tuple_length(tuple_st); + Py_ssize_t tuple_length = sym_tuple_length(tuple_st); if (tuple_length == -1) { // Unknown length res = sym_new_not_null(ctx); @@ -342,7 +365,6 @@ dummy_func(void) { int already_bool = optimize_to_bool(this_instr, ctx, value, &value); if (!already_bool) { sym_set_type(value, &PyBool_Type); - value = sym_new_truthiness(ctx, value, true); } } @@ -397,6 +419,7 @@ dummy_func(void) { } op(_UNARY_NEGATIVE, (value -- res)) { + REPLACE_OPCODE_IF_EVALUATES_PURE(value); if (sym_is_compact_int(value)) { res = sym_new_compact_int(ctx); } @@ -412,6 +435,10 @@ dummy_func(void) { } op(_UNARY_INVERT, (value -- res)) { + // Required to avoid a warning due to the deprecation of bitwise inversion of bools + if (!sym_matches_type(value, &PyBool_Type)) { + REPLACE_OPCODE_IF_EVALUATES_PURE(value); + } if (sym_matches_type(value, &PyLong_Type)) { res = sym_new_type(ctx, &PyLong_Type); } @@ -421,6 +448,9 @@ dummy_func(void) { } op(_COMPARE_OP, (left, right -- res)) { + // Comparison between bytes and str or int is not impacted by this optimization as bytes + // is not a safe type (due to its ability to raise a warning during comparisons). + REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); if (oparg & 16) { res = sym_new_type(ctx, &PyBool_Type); } @@ -429,9 +459,10 @@ dummy_func(void) { } } - op(_COMPARE_OP_INT, (left, right -- res)) { - REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); + op(_COMPARE_OP_INT, (left, right -- res, l, r)) { res = sym_new_type(ctx, &PyBool_Type); + l = left; + r = right; } op(_COMPARE_OP_FLOAT, (left, right -- res)) { @@ -449,6 +480,7 @@ dummy_func(void) { } op(_CONTAINS_OP, (left, right -- b)) { + REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); b = sym_new_type(ctx, &PyBool_Type); } @@ -461,6 +493,7 @@ dummy_func(void) { } op(_LOAD_CONST, (-- value)) { + PyCodeObject *co = get_current_code_object(ctx); PyObject *val = PyTuple_GET_ITEM(co->co_consts, oparg); REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = PyJitRef_Borrow(sym_new_const(ctx, val)); @@ -520,6 +553,24 @@ dummy_func(void) { } } + op(_POP_TOP_INT, (value --)) { + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + } + + op(_POP_TOP_FLOAT, (value --)) { + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + } + + op(_POP_TOP_UNICODE, (value --)) { + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + } + op(_COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { assert(oparg > 0); top = bottom; @@ -532,9 +583,10 @@ dummy_func(void) { assert(oparg >= 2); } - op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr)) { + op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, o)) { attr = sym_new_not_null(ctx); (void)offset; + o = owner; } op(_LOAD_ATTR_MODULE, (dict_version/2, index/1, owner -- attr)) { @@ -576,9 +628,9 @@ dummy_func(void) { } } - op(_LOAD_ATTR, (owner -- attr[1], self_or_null[oparg&1])) { + op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { (void)owner; - *attr = sym_new_not_null(ctx); + attr = sym_new_not_null(ctx); if (oparg & 1) { self_or_null[0] = sym_new_unknown(ctx); } @@ -597,8 +649,8 @@ dummy_func(void) { op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr)) { (void)descr; PyTypeObject *type = (PyTypeObject *)sym_get_const(ctx, owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _POP_TOP_LOAD_CONST_INLINE_BORROW, _POP_TOP_LOAD_CONST_INLINE); } @@ -606,8 +658,8 @@ dummy_func(void) { op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr)) { (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _POP_TOP_LOAD_CONST_INLINE_BORROW, _POP_TOP_LOAD_CONST_INLINE); } @@ -615,8 +667,8 @@ dummy_func(void) { op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr)) { (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _POP_TOP_LOAD_CONST_INLINE_BORROW, _POP_TOP_LOAD_CONST_INLINE); } @@ -624,8 +676,8 @@ dummy_func(void) { op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _LOAD_CONST_UNDER_INLINE_BORROW, _LOAD_CONST_UNDER_INLINE); self = owner; @@ -634,8 +686,8 @@ dummy_func(void) { op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) { (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _LOAD_CONST_UNDER_INLINE_BORROW, _LOAD_CONST_UNDER_INLINE); self = owner; @@ -644,8 +696,8 @@ dummy_func(void) { op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self)) { (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _LOAD_CONST_UNDER_INLINE_BORROW, _LOAD_CONST_UNDER_INLINE); self = owner; @@ -702,15 +754,13 @@ dummy_func(void) { op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame)) { int argcount = oparg; - PyCodeObject *co = NULL; assert((this_instr + 2)->opcode == _PUSH_FRAME); - co = get_code_with_logging((this_instr + 2)); + PyCodeObject *co = get_code_with_logging((this_instr + 2)); if (co == NULL) { ctx->done = true; break; } - assert(!PyJitRef_IsNull(self_or_null)); assert(args != NULL); if (sym_is_not_null(self_or_null)) { @@ -733,9 +783,8 @@ dummy_func(void) { } op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame)) { - PyCodeObject *co = NULL; assert((this_instr + 2)->opcode == _PUSH_FRAME); - co = get_code_with_logging((this_instr + 2)); + PyCodeObject *co = get_code_with_logging((this_instr + 2)); if (co == NULL) { ctx->done = true; break; @@ -745,8 +794,14 @@ dummy_func(void) { } op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame)) { - new_frame = PyJitRef_NULL; - ctx->done = true; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 2)); + if (co == NULL) { + ctx->done = true; + break; + } + + new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); } op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { @@ -757,33 +812,46 @@ dummy_func(void) { } op(_CREATE_INIT_FRAME, (init, self, args[oparg] -- init_frame)) { - init_frame = PyJitRef_NULL; - ctx->done = true; + ctx->frame->stack_pointer = stack_pointer - oparg - 2; + _Py_UOpsAbstractFrame *shim = frame_new(ctx, (PyCodeObject *)&_Py_InitCleanup, 0, NULL, 0); + if (shim == NULL) { + break; + } + /* Push self onto stack of shim */ + shim->stack[0] = self; + shim->stack_pointer++; + assert((int)(shim->stack_pointer - shim->stack) == 1); + ctx->frame = shim; + ctx->curr_frame_depth++; + assert((this_instr + 1)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 1)); + init_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, args-1, oparg+1)); } op(_RETURN_VALUE, (retval -- res)) { - // We wrap and unwrap the value to mimic PyStackRef_MakeHeapSafe - // in bytecodes.c - JitOptRef temp = PyJitRef_Wrap(PyJitRef_Unwrap(retval)); + // Mimics PyStackRef_MakeHeapSafe in the interpreter. + JitOptRef temp = PyJitRef_StripReferenceInfo(retval); DEAD(retval); SAVE_STACK(); ctx->frame->stack_pointer = stack_pointer; - frame_pop(ctx); + PyCodeObject *returning_code = get_code_with_logging(this_instr); + if (returning_code == NULL) { + ctx->done = true; + break; + } + int returning_stacklevel = this_instr->operand1; + if (ctx->curr_frame_depth >= 2) { + PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code; + if (expected_code == returning_code) { + assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE); + REPLACE_OP((this_instr + 1), _NOP, 0, 0); + } + } + if (frame_pop(ctx, returning_code, returning_stacklevel)) { + break; + } stack_pointer = ctx->frame->stack_pointer; - /* Stack space handling */ - assert(corresponding_check_stack == NULL); - assert(co != NULL); - int framesize = co->co_framesize; - assert(framesize > 0); - assert(framesize <= curr_space); - curr_space -= framesize; - - co = get_code(this_instr); - if (co == NULL) { - // might be impossible, but bailing is still safe - ctx->done = true; - } RELOAD_STACK(); res = temp; } @@ -791,27 +859,39 @@ dummy_func(void) { op(_RETURN_GENERATOR, ( -- res)) { SYNC_SP(); ctx->frame->stack_pointer = stack_pointer; - frame_pop(ctx); + PyCodeObject *returning_code = get_code_with_logging(this_instr); + if (returning_code == NULL) { + ctx->done = true; + break; + } + _Py_BloomFilter_Add(dependencies, returning_code); + int returning_stacklevel = this_instr->operand1; + if (frame_pop(ctx, returning_code, returning_stacklevel)) { + break; + } stack_pointer = ctx->frame->stack_pointer; res = sym_new_unknown(ctx); - - /* Stack space handling */ - assert(corresponding_check_stack == NULL); - assert(co != NULL); - int framesize = co->co_framesize; - assert(framesize > 0); - assert(framesize <= curr_space); - curr_space -= framesize; - - co = get_code(this_instr); - if (co == NULL) { - // might be impossible, but bailing is still safe - ctx->done = true; - } } - op(_YIELD_VALUE, (unused -- value)) { - value = sym_new_unknown(ctx); + op(_YIELD_VALUE, (retval -- value)) { + // Mimics PyStackRef_MakeHeapSafe in the interpreter. + JitOptRef temp = PyJitRef_StripReferenceInfo(retval); + DEAD(retval); + SAVE_STACK(); + ctx->frame->stack_pointer = stack_pointer; + PyCodeObject *returning_code = get_code_with_logging(this_instr); + if (returning_code == NULL) { + ctx->done = true; + break; + } + _Py_BloomFilter_Add(dependencies, returning_code); + int returning_stacklevel = this_instr->operand1; + if (frame_pop(ctx, returning_code, returning_stacklevel)) { + break; + } + stack_pointer = ctx->frame->stack_pointer; + RELOAD_STACK(); + value = temp; } op(_GET_ITER, (iterable -- iter, index_or_null)) { @@ -838,8 +918,6 @@ dummy_func(void) { } op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) { - assert(corresponding_check_stack == NULL); - corresponding_check_stack = this_instr; } op (_CHECK_STACK_SPACE_OPERAND, (framesize/2 -- )) { @@ -851,35 +929,29 @@ dummy_func(void) { op(_PUSH_FRAME, (new_frame -- )) { SYNC_SP(); - ctx->frame->stack_pointer = stack_pointer; + if (!CURRENT_FRAME_IS_INIT_SHIM()) { + ctx->frame->stack_pointer = stack_pointer; + } ctx->frame = (_Py_UOpsAbstractFrame *)PyJitRef_Unwrap(new_frame); ctx->curr_frame_depth++; stack_pointer = ctx->frame->stack_pointer; - co = get_code(this_instr); - if (co == NULL) { - // should be about to _EXIT_TRACE anyway + uint64_t operand = this_instr->operand0; + if (operand == 0) { ctx->done = true; break; } - - /* Stack space handling */ - int framesize = co->co_framesize; - assert(framesize > 0); - curr_space += framesize; - if (curr_space < 0 || curr_space > INT32_MAX) { - // won't fit in signed 32-bit int - ctx->done = true; - break; + if (!(operand & 1)) { + PyFunctionObject *func = (PyFunctionObject *)operand; + // No need to re-add to dependencies here. Already + // handled by the tracer. + ctx->frame->func = func; } - max_space = curr_space > max_space ? curr_space : max_space; - if (first_valid_check_stack == NULL) { - first_valid_check_stack = corresponding_check_stack; + // Fixed calls don't need IP guards. + if ((this_instr-1)->opcode == _SAVE_RETURN_OFFSET || + (this_instr-1)->opcode == _CREATE_INIT_FRAME) { + assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME); + REPLACE_OP(this_instr+1, _NOP, 0, 0); } - else if (corresponding_check_stack) { - // delete all but the first valid _CHECK_STACK_SPACE - corresponding_check_stack->opcode = _NOP; - } - corresponding_check_stack = NULL; } op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0])) { @@ -922,14 +994,17 @@ dummy_func(void) { } } - op(_CALL_STR_1, (unused, unused, arg -- res)) { + op(_CALL_STR_1, (unused, unused, arg -- res, a)) { if (sym_matches_type(arg, &PyUnicode_Type)) { // e.g. str('foo') or str(foo) where foo is known to be a string - res = arg; + // Note: we must strip the reference information because it goes + // through str() which strips the reference information from it. + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyUnicode_Type); } + a = arg; } op(_CALL_ISINSTANCE, (unused, unused, instance, cls -- res)) { @@ -961,6 +1036,12 @@ dummy_func(void) { sym_set_const(flag, Py_True); } + op(_CALL_LIST_APPEND, (callable, self, arg -- c, s)) { + (void)(arg); + c = callable; + s = self; + } + op(_GUARD_IS_FALSE_POP, (flag -- )) { if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); @@ -1022,6 +1103,10 @@ dummy_func(void) { ctx->done = true; } + op(_DEOPT, (--)) { + ctx->done = true; + } + op(_REPLACE_WITH_TRUE, (value -- res)) { REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)Py_True); res = sym_new_const(ctx, Py_True); @@ -1062,14 +1147,17 @@ dummy_func(void) { } } - op(_CALL_TUPLE_1, (callable, null, arg -- res)) { + op(_CALL_TUPLE_1, (callable, null, arg -- res, a)) { if (sym_matches_type(arg, &PyTuple_Type)) { // e.g. tuple((1, 2)) or tuple(foo) where foo is known to be a tuple - res = arg; + // Note: we must strip the reference information because it goes + // through tuple() which strips the reference information from it. + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyTuple_Type); } + a = arg; } op(_GUARD_TOS_LIST, (tos -- tos)) { @@ -1164,11 +1252,11 @@ dummy_func(void) { sym_set_const(callable, (PyObject *)&PyUnicode_Type); } - op(_CALL_LEN, (callable, null, arg -- res)) { + op(_CALL_LEN, (callable, null, arg -- res, a, c)) { res = sym_new_type(ctx, &PyLong_Type); - int tuple_length = sym_tuple_length(arg); + Py_ssize_t tuple_length = sym_tuple_length(arg); if (tuple_length >= 0) { - PyObject *temp = PyLong_FromLong(tuple_length); + PyObject *temp = PyLong_FromSsize_t(tuple_length); if (temp == NULL) { goto error; } @@ -1179,16 +1267,18 @@ dummy_func(void) { res = sym_new_const(ctx, temp); Py_DECREF(temp); } + a = arg; + c = callable; } op(_GET_LEN, (obj -- obj, len)) { - int tuple_length = sym_tuple_length(obj); + Py_ssize_t tuple_length = sym_tuple_length(obj); if (tuple_length == -1) { len = sym_new_type(ctx, &PyLong_Type); } else { assert(tuple_length >= 0); - PyObject *temp = PyLong_FromLong(tuple_length); + PyObject *temp = PyLong_FromSsize_t(tuple_length); if (temp == NULL) { goto error; } @@ -1238,6 +1328,96 @@ dummy_func(void) { } } + op(_GUARD_GLOBALS_VERSION, (version/1 --)) { + if (ctx->frame->func != NULL) { + PyObject *globals = ctx->frame->func->func_globals; + if (incorrect_keys(globals, version)) { + OPT_STAT_INC(remove_globals_incorrect_keys); + ctx->done = true; + } + else if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { + /* Do nothing */ + } + else { + if (!ctx->frame->globals_watched) { + PyDict_Watch(GLOBALS_WATCHER_ID, globals); + _Py_BloomFilter_Add(dependencies, globals); + ctx->frame->globals_watched = true; + } + if (ctx->frame->globals_checked_version == version) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + } + } + ctx->frame->globals_checked_version = version; + } + + op(_LOAD_GLOBAL_BUILTINS, (version/1, index/1 -- res)) { + (void)version; + (void)index; + PyObject *cnst = NULL; + PyInterpreterState *interp = _PyInterpreterState_GET(); + PyObject *builtins = interp->builtins; + if (incorrect_keys(builtins, version)) { + OPT_STAT_INC(remove_globals_incorrect_keys); + ctx->done = true; + } + else if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { + /* Do nothing */ + } + else { + if (!ctx->builtins_watched) { + PyDict_Watch(BUILTINS_WATCHER_ID, builtins); + ctx->builtins_watched = true; + } + if (ctx->frame->globals_checked_version != 0 && ctx->frame->globals_watched) { + cnst = convert_global_to_const(this_instr, builtins, false); + } + } + if (cnst == NULL) { + res = sym_new_not_null(ctx); + } + else { + res = sym_new_const(ctx, cnst); + } + } + + op(_LOAD_GLOBAL_MODULE, (version/1, unused/1, index/1 -- res)) { + (void)index; + PyObject *cnst = NULL; + if (ctx->frame->func != NULL) { + PyObject *globals = ctx->frame->func->func_globals; + if (incorrect_keys(globals, version)) { + OPT_STAT_INC(remove_globals_incorrect_keys); + ctx->done = true; + } + else if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { + /* Do nothing */ + } + else { + if (!ctx->frame->globals_watched) { + PyDict_Watch(GLOBALS_WATCHER_ID, globals); + _Py_BloomFilter_Add(dependencies, globals); + ctx->frame->globals_watched = true; + } + if (ctx->frame->globals_checked_version != version && this_instr[-1].opcode == _NOP) { + REPLACE_OP(this_instr-1, _GUARD_GLOBALS_VERSION, 0, version); + ctx->frame->globals_checked_version = version; + } + if (ctx->frame->globals_checked_version == version) { + cnst = convert_global_to_const(this_instr, globals, false); + } + } + } + if (cnst == NULL) { + res = sym_new_not_null(ctx); + } + else { + res = sym_new_const(ctx, cnst); + } + } + + // END BYTECODES // } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2477ede3e68..32d60c76a4f 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -33,27 +33,30 @@ if (sym_is_null(value)) { ctx->done = true; } + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_FAST: { JitOptRef value; value = GETLOCAL(oparg); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_FAST_BORROW: { JitOptRef value; value = PyJitRef_Borrow(GETLOCAL(oparg)); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -62,20 +65,23 @@ value = GETLOCAL(oparg); JitOptRef temp = sym_new_null(ctx); GETLOCAL(oparg) = temp; + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_CONST: { JitOptRef value; + PyCodeObject *co = get_current_code_object(ctx); PyObject *val = PyTuple_GET_ITEM(co->co_consts, oparg); REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = PyJitRef_Borrow(sym_new_const(ctx, val)); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -86,9 +92,10 @@ assert(_Py_IsImmortal(val)); REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); value = PyJitRef_Borrow(sym_new_const(ctx, val)); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -96,8 +103,9 @@ JitOptRef value; value = stack_pointer[-1]; GETLOCAL(oparg) = value; + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -119,68 +127,93 @@ else if (typ == &PyUnicode_Type) { REPLACE_OP(this_instr, _POP_TOP_UNICODE, 0, 0); } + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_TOP_NOP: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_TOP_INT: { + JitOptRef value; + value = stack_pointer[-1]; + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_TOP_FLOAT: { + JitOptRef value; + value = stack_pointer[-1]; + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_TOP_UNICODE: { + JitOptRef value; + value = stack_pointer[-1]; + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_TWO: { + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _PUSH_NULL: { JitOptRef res; res = sym_new_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _END_FOR: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_ITER: { + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _END_SEND: { JitOptRef val; val = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = val; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -188,6 +221,31 @@ JitOptRef value; JitOptRef res; value = stack_pointer[-1]; + if ( + sym_is_safe_const(ctx, value) + ) { + JitOptRef value_sym = value; + _PyStackRef value = sym_get_const_as_stackref(ctx, value_sym); + _PyStackRef res_stackref; + /* Start of uop copied from bytecodes for constant evaluation */ + PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); + PyStackRef_CLOSE(value); + if (res_o == NULL) { + goto error; + } + res_stackref = PyStackRef_FromPyObjectSteal(res_o); + /* End of uop copied from bytecodes for constant evaluation */ + res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); + if (sym_is_const(ctx, res)) { + PyObject *result = sym_get_const(ctx, res); + if (_Py_IsImmortal(result)) { + // Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result + REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); + } + } + stack_pointer[-1] = res; + break; + } if (sym_is_compact_int(value)) { res = sym_new_compact_int(ctx); } @@ -220,6 +278,13 @@ ? PyStackRef_True : PyStackRef_False; /* End of uop copied from bytecodes for constant evaluation */ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); + if (sym_is_const(ctx, res)) { + PyObject *result = sym_get_const(ctx, res); + if (_Py_IsImmortal(result)) { + // Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result + REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); + } + } stack_pointer[-1] = res; break; } @@ -247,7 +312,6 @@ int already_bool = optimize_to_bool(this_instr, ctx, value, &value); if (!already_bool) { sym_set_type(value, &PyBool_Type); - value = sym_new_truthiness(ctx, value, true); } stack_pointer[-1] = value; break; @@ -359,6 +423,33 @@ JitOptRef value; JitOptRef res; value = stack_pointer[-1]; + if (!sym_matches_type(value, &PyBool_Type)) { + if ( + sym_is_safe_const(ctx, value) + ) { + JitOptRef value_sym = value; + _PyStackRef value = sym_get_const_as_stackref(ctx, value_sym); + _PyStackRef res_stackref; + /* Start of uop copied from bytecodes for constant evaluation */ + PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); + PyStackRef_CLOSE(value); + if (res_o == NULL) { + goto error; + } + res_stackref = PyStackRef_FromPyObjectSteal(res_o); + /* End of uop copied from bytecodes for constant evaluation */ + res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); + if (sym_is_const(ctx, res)) { + PyObject *result = sym_get_const(ctx, res); + if (_Py_IsImmortal(result)) { + // Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result + REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); + } + } + stack_pointer[-1] = res; + break; + } + } if (sym_matches_type(value, &PyLong_Type)) { res = sym_new_type(ctx, &PyLong_Type); } @@ -411,50 +502,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyLong_CheckExact(left_o)); - assert(PyLong_CheckExact(right_o)); - assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); - STAT_INC(BINARY_OP, hit); - res_stackref = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); - if (PyStackRef_IsNull(res_stackref )) { - ctx->done = true; - break; - } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_compact_int(ctx); + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -462,50 +522,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyLong_CheckExact(left_o)); - assert(PyLong_CheckExact(right_o)); - assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); - STAT_INC(BINARY_OP, hit); - res_stackref = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); - if (PyStackRef_IsNull(res_stackref )) { - ctx->done = true; - break; - } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_compact_int(ctx); + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -513,50 +542,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyLong_CheckExact(left_o)); - assert(PyLong_CheckExact(right_o)); - assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o)); - STAT_INC(BINARY_OP, hit); - res_stackref = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); - if (PyStackRef_IsNull(res_stackref )) { - ctx->done = true; - break; - } - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_compact_int(ctx); + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -584,52 +582,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval * - ((PyFloatObject *)right_o)->ob_fval; - res_stackref = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - if (PyStackRef_IsNull(res_stackref )) { - goto error; - } - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_type(ctx, &PyFloat_Type); - if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) { - REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0); - } + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -637,52 +602,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval + - ((PyFloatObject *)right_o)->ob_fval; - res_stackref = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - if (PyStackRef_IsNull(res_stackref )) { - goto error; - } - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_type(ctx, &PyFloat_Type); - if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) { - REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0); - } + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -690,79 +622,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyFloat_CheckExact(left_o)); - assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval - - ((PyFloatObject *)right_o)->ob_fval; - res_stackref = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); - if (PyStackRef_IsNull(res_stackref )) { - goto error; - } - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_type(ctx, &PyFloat_Type); - if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) { - REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0); - } + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _BINARY_OP_MULTIPLY_FLOAT__NO_DECREF_INPUTS: { - JitOptRef res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _BINARY_OP_ADD_FLOAT__NO_DECREF_INPUTS: { - JitOptRef res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _BINARY_OP_SUBTRACT_FLOAT__NO_DECREF_INPUTS: { - JitOptRef res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -770,6 +642,8 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; if ( @@ -781,6 +655,8 @@ _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); _PyStackRef res_stackref; + _PyStackRef l_stackref; + _PyStackRef r_stackref; /* Start of uop copied from bytecodes for constant evaluation */ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); @@ -788,31 +664,33 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - goto error; - } res_stackref = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + JUMP_TO_LABEL(error); + } + l_stackref = left; + r_stackref = right; /* End of uop copied from bytecodes for constant evaluation */ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } + l = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(l_stackref)); + r = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(r_stackref)); + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } res = sym_new_type(ctx, &PyUnicode_Type); + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -836,8 +714,9 @@ res = sym_new_type(ctx, &PyUnicode_Type); } GETLOCAL(this_instr->operand0) = res; + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -848,9 +727,10 @@ case _BINARY_OP_EXTEND: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -868,42 +748,47 @@ else { res = sym_new_not_null(ctx); } + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = res; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_SLICE: { + CHECK_STACK_BOUNDS(-4); stack_pointer += -4; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BINARY_OP_SUBSCR_LIST_INT: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BINARY_OP_SUBSCR_LIST_SLICE: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BINARY_OP_SUBSCR_STR_INT: { JitOptRef res; res = sym_new_type(ctx, &PyUnicode_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -938,7 +823,7 @@ assert(PyLong_CheckExact(sym_get_const(ctx, sub_st))); long index = PyLong_AsLong(sym_get_const(ctx, sub_st)); assert(index >= 0); - int tuple_length = sym_tuple_length(tuple_st); + Py_ssize_t tuple_length = sym_tuple_length(tuple_st); if (tuple_length == -1) { res = sym_new_not_null(ctx); } @@ -950,9 +835,10 @@ else { res = sym_new_not_null(ctx); } + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -979,18 +865,20 @@ case _BINARY_OP_SUBSCR_DICT: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BINARY_OP_SUBSCR_CHECK_FUNC: { JitOptRef getitem; getitem = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = getitem; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -998,45 +886,73 @@ JitOptRef new_frame; new_frame = PyJitRef_NULL; ctx->done = true; + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = new_frame; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LIST_APPEND: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _SET_ADD: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_SUBSCR: { + CHECK_STACK_BOUNDS(-3); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_SUBSCR_LIST_INT: { - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + JitOptRef sub_st; + JitOptRef list_st; + JitOptRef value; + JitOptRef ls; + JitOptRef ss; + sub_st = stack_pointer[-1]; + list_st = stack_pointer[-2]; + value = stack_pointer[-3]; + (void)value; + ls = list_st; + ss = sub_st; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-3] = ls; + stack_pointer[-2] = ss; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_SUBSCR_DICT: { - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + JitOptRef dict_st; + JitOptRef value; + JitOptRef st; + dict_st = stack_pointer[-2]; + value = stack_pointer[-3]; + (void)value; + st = dict_st; + CHECK_STACK_BOUNDS(-2); + stack_pointer[-3] = st; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _DELETE_SUBSCR: { + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1050,9 +966,10 @@ case _CALL_INTRINSIC_2: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1060,26 +977,33 @@ JitOptRef retval; JitOptRef res; retval = stack_pointer[-1]; - JitOptRef temp = PyJitRef_Wrap(PyJitRef_Unwrap(retval)); + JitOptRef temp = PyJitRef_StripReferenceInfo(retval); + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); ctx->frame->stack_pointer = stack_pointer; - frame_pop(ctx); - stack_pointer = ctx->frame->stack_pointer; - assert(corresponding_check_stack == NULL); - assert(co != NULL); - int framesize = co->co_framesize; - assert(framesize > 0); - assert(framesize <= curr_space); - curr_space -= framesize; - co = get_code(this_instr); - if (co == NULL) { + PyCodeObject *returning_code = get_code_with_logging(this_instr); + if (returning_code == NULL) { ctx->done = true; + break; } + int returning_stacklevel = this_instr->operand1; + if (ctx->curr_frame_depth >= 2) { + PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code; + if (expected_code == returning_code) { + assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE); + REPLACE_OP((this_instr + 1), _NOP, 0, 0); + } + } + if (frame_pop(ctx, returning_code, returning_stacklevel)) { + break; + } + stack_pointer = ctx->frame->stack_pointer; res = temp; + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1093,9 +1017,10 @@ case _GET_ANEXT: { JitOptRef awaitable; awaitable = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = awaitable; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1117,39 +1042,64 @@ } case _YIELD_VALUE: { + JitOptRef retval; JitOptRef value; - value = sym_new_unknown(ctx); - stack_pointer[-1] = value; + retval = stack_pointer[-1]; + JitOptRef temp = PyJitRef_StripReferenceInfo(retval); + CHECK_STACK_BOUNDS(-1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + ctx->frame->stack_pointer = stack_pointer; + PyCodeObject *returning_code = get_code_with_logging(this_instr); + if (returning_code == NULL) { + ctx->done = true; + break; + } + _Py_BloomFilter_Add(dependencies, returning_code); + int returning_stacklevel = this_instr->operand1; + if (frame_pop(ctx, returning_code, returning_stacklevel)) { + break; + } + stack_pointer = ctx->frame->stack_pointer; + value = temp; + CHECK_STACK_BOUNDS(1); + stack_pointer[0] = value; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_EXCEPT: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_COMMON_CONSTANT: { JitOptRef value; value = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_BUILD_CLASS: { JitOptRef bc; bc = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = bc; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_NAME: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1166,8 +1116,9 @@ for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); } + CHECK_STACK_BOUNDS(-1 + oparg); stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1178,10 +1129,11 @@ seq = stack_pointer[-1]; val0 = sym_tuple_getitem(ctx, seq, 0); val1 = sym_tuple_getitem(ctx, seq, 1); + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = val1; stack_pointer[0] = val0; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1193,8 +1145,9 @@ for (int i = 0; i < oparg; i++) { values[i] = sym_tuple_getitem(ctx, seq, oparg - i - 1); } + CHECK_STACK_BOUNDS(-1 + oparg); stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1204,8 +1157,9 @@ for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_not_null(ctx); } + CHECK_STACK_BOUNDS(-1 + oparg); stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1219,26 +1173,30 @@ for (int i = 0; i < totalargs; i++) { values[i] = sym_new_unknown(ctx); } + CHECK_STACK_BOUNDS((oparg & 0xFF) + (oparg >> 8)); stack_pointer += (oparg & 0xFF) + (oparg >> 8); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_ATTR: { + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _DELETE_ATTR: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_GLOBAL: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1249,9 +1207,10 @@ case _LOAD_LOCALS: { JitOptRef locals; locals = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = locals; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1260,9 +1219,10 @@ case _LOAD_NAME: { JitOptRef v; v = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = v; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1270,8 +1230,9 @@ JitOptRef *res; res = &stack_pointer[0]; res[0] = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1285,30 +1246,113 @@ else { REPLACE_OP(this_instr, _NOP, 0, 0); } + CHECK_STACK_BOUNDS((oparg & 1)); stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _GUARD_GLOBALS_VERSION: { + uint16_t version = (uint16_t)this_instr->operand0; + if (ctx->frame->func != NULL) { + PyObject *globals = ctx->frame->func->func_globals; + if (incorrect_keys(globals, version)) { + OPT_STAT_INC(remove_globals_incorrect_keys); + ctx->done = true; + } + else if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { + } + else { + if (!ctx->frame->globals_watched) { + PyDict_Watch(GLOBALS_WATCHER_ID, globals); + _Py_BloomFilter_Add(dependencies, globals); + ctx->frame->globals_watched = true; + } + if (ctx->frame->globals_checked_version == version) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + } + } + ctx->frame->globals_checked_version = version; break; } case _LOAD_GLOBAL_MODULE: { JitOptRef res; - res = sym_new_not_null(ctx); + uint16_t version = (uint16_t)this_instr->operand0; + uint16_t index = (uint16_t)this_instr->operand0; + (void)index; + PyObject *cnst = NULL; + if (ctx->frame->func != NULL) { + PyObject *globals = ctx->frame->func->func_globals; + if (incorrect_keys(globals, version)) { + OPT_STAT_INC(remove_globals_incorrect_keys); + ctx->done = true; + } + else if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { + } + else { + if (!ctx->frame->globals_watched) { + PyDict_Watch(GLOBALS_WATCHER_ID, globals); + _Py_BloomFilter_Add(dependencies, globals); + ctx->frame->globals_watched = true; + } + if (ctx->frame->globals_checked_version != version && this_instr[-1].opcode == _NOP) { + REPLACE_OP(this_instr-1, _GUARD_GLOBALS_VERSION, 0, version); + ctx->frame->globals_checked_version = version; + } + if (ctx->frame->globals_checked_version == version) { + cnst = convert_global_to_const(this_instr, globals, false); + } + } + } + if (cnst == NULL) { + res = sym_new_not_null(ctx); + } + else { + res = sym_new_const(ctx, cnst); + } + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_GLOBAL_BUILTINS: { JitOptRef res; - res = sym_new_not_null(ctx); + uint16_t version = (uint16_t)this_instr->operand0; + uint16_t index = (uint16_t)this_instr->operand0; + (void)version; + (void)index; + PyObject *cnst = NULL; + PyInterpreterState *interp = _PyInterpreterState_GET(); + PyObject *builtins = interp->builtins; + if (incorrect_keys(builtins, version)) { + OPT_STAT_INC(remove_globals_incorrect_keys); + ctx->done = true; + } + else if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) { + } + else { + if (!ctx->builtins_watched) { + PyDict_Watch(BUILTINS_WATCHER_ID, builtins); + ctx->builtins_watched = true; + } + if (ctx->frame->globals_checked_version != 0 && ctx->frame->globals_watched) { + cnst = convert_global_to_const(this_instr, builtins, false); + } + } + if (cnst == NULL) { + res = sym_new_not_null(ctx); + } + else { + res = sym_new_const(ctx, cnst); + } + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1334,15 +1378,17 @@ case _LOAD_DEREF: { JitOptRef value; value = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_DEREF: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1353,27 +1399,30 @@ case _BUILD_STRING: { JitOptRef str; str = sym_new_type(ctx, &PyUnicode_Type); + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-oparg] = str; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BUILD_INTERPOLATION: { JitOptRef interpolation; interpolation = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - (oparg & 1)); stack_pointer[-2 - (oparg & 1)] = interpolation; stack_pointer += -1 - (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BUILD_TEMPLATE: { JitOptRef template; template = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = template; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1382,48 +1431,54 @@ JitOptRef tup; values = &stack_pointer[-oparg]; tup = sym_new_tuple(ctx, oparg, values); + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-oparg] = tup; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BUILD_LIST: { JitOptRef list; list = sym_new_type(ctx, &PyList_Type); + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-oparg] = list; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LIST_EXTEND: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _SET_UPDATE: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BUILD_SET: { JitOptRef set; set = sym_new_type(ctx, &PySet_Type); + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-oparg] = set; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BUILD_MAP: { JitOptRef map; map = sym_new_type(ctx, &PyDict_Type); + CHECK_STACK_BOUNDS(1 - oparg*2); stack_pointer[-oparg*2] = map; stack_pointer += 1 - oparg*2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1432,29 +1487,33 @@ } case _DICT_UPDATE: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _DICT_MERGE: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _MAP_ADD: { + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_SUPER_ATTR_ATTR: { JitOptRef attr_st; attr_st = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = attr_st; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1463,27 +1522,29 @@ JitOptRef self_or_null; attr = sym_new_not_null(ctx); self_or_null = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-3] = attr; stack_pointer[-2] = self_or_null; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _LOAD_ATTR: { JitOptRef owner; - JitOptRef *attr; + JitOptRef attr; JitOptRef *self_or_null; owner = stack_pointer[-1]; - attr = &stack_pointer[-1]; self_or_null = &stack_pointer[0]; (void)owner; - *attr = sym_new_not_null(ctx); + attr = sym_new_not_null(ctx); if (oparg & 1) { self_or_null[0] = sym_new_unknown(ctx); } + CHECK_STACK_BOUNDS((oparg&1)); + stack_pointer[-1] = attr; stack_pointer += (oparg&1); - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1515,11 +1576,19 @@ } case _LOAD_ATTR_INSTANCE_VALUE: { + JitOptRef owner; JitOptRef attr; + JitOptRef o; + owner = stack_pointer[-1]; uint16_t offset = (uint16_t)this_instr->operand0; attr = sym_new_not_null(ctx); (void)offset; + o = owner; + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; + stack_pointer[0] = o; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1599,8 +1668,8 @@ PyObject *descr = (PyObject *)this_instr->operand0; (void)descr; PyTypeObject *type = (PyTypeObject *)sym_get_const(ctx, owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _POP_TOP_LOAD_CONST_INLINE_BORROW, _POP_TOP_LOAD_CONST_INLINE); stack_pointer[-1] = attr; @@ -1624,34 +1693,113 @@ } case _STORE_ATTR_INSTANCE_VALUE: { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + JitOptRef owner; + JitOptRef value; + JitOptRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t offset = (uint16_t)this_instr->operand0; + (void)value; + o = owner; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_ATTR_WITH_HINT: { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + JitOptRef owner; + JitOptRef value; + JitOptRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t hint = (uint16_t)this_instr->operand0; + (void)value; + o = owner; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _STORE_ATTR_SLOT: { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + JitOptRef owner; + JitOptRef value; + JitOptRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t index = (uint16_t)this_instr->operand0; + (void)index; + (void)value; + o = owner; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _COMPARE_OP: { + JitOptRef right; + JitOptRef left; JitOptRef res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if ( + sym_is_safe_const(ctx, left) && + sym_is_safe_const(ctx, right) + ) { + JitOptRef left_sym = left; + JitOptRef right_sym = right; + _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); + _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); + _PyStackRef res_stackref; + /* Start of uop copied from bytecodes for constant evaluation */ + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + assert((oparg >> 5) <= Py_GE); + PyObject *res_o = PyObject_RichCompare(left_o, right_o, oparg >> 5); + if (res_o == NULL) { + goto error; + } + if (oparg & 16) { + int res_bool = PyObject_IsTrue(res_o); + Py_DECREF(res_o); + if (res_bool < 0) { + goto error; + } + res_stackref = res_bool ? PyStackRef_True : PyStackRef_False; + } + else { + res_stackref = PyStackRef_FromPyObjectSteal(res_o); + } + /* End of uop copied from bytecodes for constant evaluation */ + res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); + if (sym_is_const(ctx, res)) { + PyObject *result = sym_get_const(ctx, res); + if (_Py_IsImmortal(result)) { + // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); + } + } + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = res; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } if (oparg & 16) { res = sym_new_type(ctx, &PyBool_Type); } else { res = _Py_uop_sym_new_not_null(ctx); } + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1682,7 +1830,6 @@ res_stackref = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; /* End of uop copied from bytecodes for constant evaluation */ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - if (sym_is_const(ctx, res)) { PyObject *result = sym_get_const(ctx, res); if (_Py_IsImmortal(result)) { @@ -1690,15 +1837,17 @@ REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); } } + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } res = sym_new_type(ctx, &PyBool_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1706,50 +1855,19 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - if ( - sym_is_safe_const(ctx, left) && - sym_is_safe_const(ctx, right) - ) { - JitOptRef left_sym = left; - JitOptRef right_sym = right; - _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); - _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); - _PyStackRef res_stackref; - /* Start of uop copied from bytecodes for constant evaluation */ - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(_PyLong_IsCompact((PyLongObject *)left_o)); - assert(_PyLong_IsCompact((PyLongObject *)right_o)); - STAT_INC(COMPARE_OP, hit); - assert(_PyLong_DigitCount((PyLongObject *)left_o) <= 1 && - _PyLong_DigitCount((PyLongObject *)right_o) <= 1); - Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left_o); - Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); - int sign_ish = COMPARISON_BIT(ileft, iright); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - res_stackref = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False; - /* End of uop copied from bytecodes for constant evaluation */ - res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } res = sym_new_type(ctx, &PyBool_Type); + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1782,7 +1900,6 @@ res_stackref = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? PyStackRef_True : PyStackRef_False; /* End of uop copied from bytecodes for constant evaluation */ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - if (sym_is_const(ctx, res)) { PyObject *result = sym_get_const(ctx, res); if (_Py_IsImmortal(result)) { @@ -1790,33 +1907,73 @@ REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); } } + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } res = sym_new_type(ctx, &PyBool_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _IS_OP: { JitOptRef b; b = sym_new_type(ctx, &PyBool_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = b; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CONTAINS_OP: { + JitOptRef right; + JitOptRef left; JitOptRef b; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if ( + sym_is_safe_const(ctx, left) && + sym_is_safe_const(ctx, right) + ) { + JitOptRef left_sym = left; + JitOptRef right_sym = right; + _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); + _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); + _PyStackRef b_stackref; + /* Start of uop copied from bytecodes for constant evaluation */ + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + int res = PySequence_Contains(right_o, left_o); + if (res < 0) { + goto error; + } + b_stackref = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + /* End of uop copied from bytecodes for constant evaluation */ + b = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(b_stackref)); + if (sym_is_const(ctx, b)) { + PyObject *result = sym_get_const(ctx, b); + if (_Py_IsImmortal(result)) { + // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); + } + } + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = b; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } b = sym_new_type(ctx, &PyBool_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = b; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1834,18 +1991,20 @@ case _CONTAINS_OP_SET: { JitOptRef b; b = sym_new_type(ctx, &PyBool_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = b; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CONTAINS_OP_DICT: { JitOptRef b; b = sym_new_type(ctx, &PyBool_Type); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = b; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1869,18 +2028,20 @@ case _IMPORT_NAME: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _IMPORT_FROM: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1895,17 +2056,19 @@ break; } + /* _JUMP_BACKWARD_NO_INTERRUPT is not a viable micro-op for tier 2 */ + case _GET_LEN: { JitOptRef obj; JitOptRef len; obj = stack_pointer[-1]; - int tuple_length = sym_tuple_length(obj); + Py_ssize_t tuple_length = sym_tuple_length(obj); if (tuple_length == -1) { len = sym_new_type(ctx, &PyLong_Type); } else { assert(tuple_length >= 0); - PyObject *temp = PyLong_FromLong(tuple_length); + PyObject *temp = PyLong_FromSsize_t(tuple_length); if (temp == NULL) { goto error; } @@ -1913,51 +2076,57 @@ REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); } len = sym_new_const(ctx, temp); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = len; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); Py_DECREF(temp); stack_pointer += -1; } + CHECK_STACK_BOUNDS(1); stack_pointer[0] = len; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _MATCH_CLASS: { JitOptRef attrs; attrs = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = attrs; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _MATCH_MAPPING: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _MATCH_SEQUENCE: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _MATCH_KEYS: { JitOptRef values_or_none; values_or_none = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = values_or_none; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1974,10 +2143,11 @@ iter = sym_new_not_null(ctx); index_or_null = sym_new_unknown(ctx); } + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = iter; stack_pointer[0] = index_or_null; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1993,9 +2163,10 @@ case _FOR_ITER_TIER_TWO: { JitOptRef next; next = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2016,9 +2187,10 @@ case _ITER_NEXT_LIST_TIER_TWO: { JitOptRef next; next = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2041,9 +2213,10 @@ case _ITER_NEXT_TUPLE: { JitOptRef next; next = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2060,9 +2233,10 @@ case _ITER_NEXT_RANGE: { JitOptRef next; next = sym_new_type(ctx, &PyLong_Type); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = next; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2070,9 +2244,10 @@ JitOptRef gen_frame; gen_frame = PyJitRef_NULL; ctx->done = true; + CHECK_STACK_BOUNDS(1); stack_pointer[0] = gen_frame; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2083,8 +2258,9 @@ method_and_self = &stack_pointer[-1]; method_and_self[0] = sym_new_null(ctx); method_and_self[1] = self; + CHECK_STACK_BOUNDS(1); stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2099,9 +2275,10 @@ case _WITH_EXCEPT_START: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2110,10 +2287,11 @@ JitOptRef new_exc; prev_exc = sym_new_not_null(ctx); new_exc = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = prev_exc; stack_pointer[0] = new_exc; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2133,15 +2311,16 @@ PyObject *descr = (PyObject *)this_instr->operand0; (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _LOAD_CONST_UNDER_INLINE_BORROW, _LOAD_CONST_UNDER_INLINE); self = owner; + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2153,15 +2332,16 @@ PyObject *descr = (PyObject *)this_instr->operand0; (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _LOAD_CONST_UNDER_INLINE_BORROW, _LOAD_CONST_UNDER_INLINE); self = owner; + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2172,8 +2352,8 @@ PyObject *descr = (PyObject *)this_instr->operand0; (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _POP_TOP_LOAD_CONST_INLINE_BORROW, _POP_TOP_LOAD_CONST_INLINE); stack_pointer[-1] = attr; @@ -2187,8 +2367,8 @@ PyObject *descr = (PyObject *)this_instr->operand0; (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _POP_TOP_LOAD_CONST_INLINE_BORROW, _POP_TOP_LOAD_CONST_INLINE); stack_pointer[-1] = attr; @@ -2207,15 +2387,16 @@ PyObject *descr = (PyObject *)this_instr->operand0; (void)descr; PyTypeObject *type = sym_get_type(owner); - PyObject *name = PyTuple_GET_ITEM(co->co_names, oparg >> 1); - attr = lookup_attr(ctx, this_instr, type, name, + PyObject *name = get_co_name(ctx, oparg >> 1); + attr = lookup_attr(ctx, dependencies, this_instr, type, name, _LOAD_CONST_UNDER_INLINE_BORROW, _LOAD_CONST_UNDER_INLINE); self = owner; + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; stack_pointer[0] = self; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2240,17 +2421,17 @@ case _PY_FRAME_GENERAL: { JitOptRef new_frame; - PyCodeObject *co = NULL; assert((this_instr + 2)->opcode == _PUSH_FRAME); - co = get_code_with_logging((this_instr + 2)); + PyCodeObject *co = get_code_with_logging((this_instr + 2)); if (co == NULL) { ctx->done = true; break; } new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = new_frame; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2296,9 +2477,10 @@ case _CALL_NON_PY_GENERAL: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2350,8 +2532,6 @@ } case _CHECK_STACK_SPACE: { - assert(corresponding_check_stack == NULL); - corresponding_check_stack = this_instr; break; } @@ -2366,9 +2546,8 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; int argcount = oparg; - PyCodeObject *co = NULL; assert((this_instr + 2)->opcode == _PUSH_FRAME); - co = get_code_with_logging((this_instr + 2)); + PyCodeObject *co = get_code_with_logging((this_instr + 2)); if (co == NULL) { ctx->done = true; break; @@ -2384,41 +2563,39 @@ } else { new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); } + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = new_frame; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _PUSH_FRAME: { JitOptRef new_frame; new_frame = stack_pointer[-1]; + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - ctx->frame->stack_pointer = stack_pointer; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + if (!CURRENT_FRAME_IS_INIT_SHIM()) { + ctx->frame->stack_pointer = stack_pointer; + } ctx->frame = (_Py_UOpsAbstractFrame *)PyJitRef_Unwrap(new_frame); ctx->curr_frame_depth++; stack_pointer = ctx->frame->stack_pointer; - co = get_code(this_instr); - if (co == NULL) { + uint64_t operand = this_instr->operand0; + if (operand == 0) { ctx->done = true; break; } - int framesize = co->co_framesize; - assert(framesize > 0); - curr_space += framesize; - if (curr_space < 0 || curr_space > INT32_MAX) { - ctx->done = true; - break; + if (!(operand & 1)) { + PyFunctionObject *func = (PyFunctionObject *)operand; + ctx->frame->func = func; } - max_space = curr_space > max_space ? curr_space : max_space; - if (first_valid_check_stack == NULL) { - first_valid_check_stack = corresponding_check_stack; + if ((this_instr-1)->opcode == _SAVE_RETURN_OFFSET || + (this_instr-1)->opcode == _CREATE_INIT_FRAME) { + assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME); + REPLACE_OP(this_instr+1, _NOP, 0, 0); } - else if (corresponding_check_stack) { - corresponding_check_stack->opcode = _NOP; - } - corresponding_check_stack = NULL; break; } @@ -2475,9 +2652,10 @@ else { res = sym_new_not_null(ctx); } + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = res; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2494,16 +2672,20 @@ case _CALL_STR_1: { JitOptRef arg; JitOptRef res; + JitOptRef a; arg = stack_pointer[-1]; if (sym_matches_type(arg, &PyUnicode_Type)) { - res = arg; + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyUnicode_Type); } + a = arg; + CHECK_STACK_BOUNDS(-1); stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2] = a; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2520,16 +2702,20 @@ case _CALL_TUPLE_1: { JitOptRef arg; JitOptRef res; + JitOptRef a; arg = stack_pointer[-1]; if (sym_matches_type(arg, &PyTuple_Type)) { - res = arg; + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyTuple_Type); } + a = arg; + CHECK_STACK_BOUNDS(-1); stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2] = a; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2551,54 +2737,81 @@ } case _CREATE_INIT_FRAME: { + JitOptRef *args; + JitOptRef self; JitOptRef init_frame; - init_frame = PyJitRef_NULL; - ctx->done = true; + args = &stack_pointer[-oparg]; + self = stack_pointer[-1 - oparg]; + ctx->frame->stack_pointer = stack_pointer - oparg - 2; + _Py_UOpsAbstractFrame *shim = frame_new(ctx, (PyCodeObject *)&_Py_InitCleanup, 0, NULL, 0); + if (shim == NULL) { + break; + } + shim->stack[0] = self; + shim->stack_pointer++; + assert((int)(shim->stack_pointer - shim->stack) == 1); + ctx->frame = shim; + ctx->curr_frame_depth++; + assert((this_instr + 1)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 1)); + init_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, args-1, oparg+1)); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = init_frame; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _EXIT_INIT_CHECK: { + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_BUILTIN_CLASS: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_BUILTIN_O: { JitOptRef res; + JitOptRef a; + JitOptRef c; res = sym_new_not_null(ctx); + a = sym_new_not_null(ctx); + c = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-1 - oparg] = a; + stack_pointer[-oparg] = c; + stack_pointer += 1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_BUILTIN_FAST: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2615,12 +2828,16 @@ case _CALL_LEN: { JitOptRef arg; + JitOptRef callable; JitOptRef res; + JitOptRef a; + JitOptRef c; arg = stack_pointer[-1]; + callable = stack_pointer[-3]; res = sym_new_type(ctx, &PyLong_Type); - int tuple_length = sym_tuple_length(arg); + Py_ssize_t tuple_length = sym_tuple_length(arg); if (tuple_length >= 0) { - PyObject *temp = PyLong_FromLong(tuple_length); + PyObject *temp = PyLong_FromSsize_t(tuple_length); if (temp == NULL) { goto error; } @@ -2629,15 +2846,18 @@ 0, (uintptr_t)temp); } res = sym_new_const(ctx, temp); + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = res; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); Py_DECREF(temp); stack_pointer += 2; } + a = arg; + c = callable; stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2] = a; + stack_pointer[-1] = c; break; } @@ -2669,9 +2889,10 @@ sym_set_const(res, out); REPLACE_OP(this_instr, _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)out); } + CHECK_STACK_BOUNDS(-3); stack_pointer[-4] = res; stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2687,44 +2908,62 @@ } case _CALL_LIST_APPEND: { - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + JitOptRef arg; + JitOptRef self; + JitOptRef callable; + JitOptRef c; + JitOptRef s; + arg = stack_pointer[-1]; + self = stack_pointer[-2]; + callable = stack_pointer[-3]; + (void)(arg); + c = callable; + s = self; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-3] = c; + stack_pointer[-2] = s; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_METHOD_DESCRIPTOR_O: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_METHOD_DESCRIPTOR_NOARGS: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _CALL_METHOD_DESCRIPTOR_FAST: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2738,11 +2977,17 @@ case _PY_FRAME_KW: { JitOptRef new_frame; - new_frame = PyJitRef_NULL; - ctx->done = true; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 2)); + if (co == NULL) { + ctx->done = true; + break; + } + new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + CHECK_STACK_BOUNDS(-2 - oparg); stack_pointer[-3 - oparg] = new_frame; stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2765,9 +3010,10 @@ case _CALL_KW_NON_PY: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-2 - oparg); stack_pointer[-3 - oparg] = res; stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2787,40 +3033,42 @@ case _SET_FUNCTION_ATTRIBUTE: { JitOptRef func_out; func_out = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = func_out; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _RETURN_GENERATOR: { JitOptRef res; ctx->frame->stack_pointer = stack_pointer; - frame_pop(ctx); + PyCodeObject *returning_code = get_code_with_logging(this_instr); + if (returning_code == NULL) { + ctx->done = true; + break; + } + _Py_BloomFilter_Add(dependencies, returning_code); + int returning_stacklevel = this_instr->operand1; + if (frame_pop(ctx, returning_code, returning_stacklevel)) { + break; + } stack_pointer = ctx->frame->stack_pointer; res = sym_new_unknown(ctx); - assert(corresponding_check_stack == NULL); - assert(co != NULL); - int framesize = co->co_framesize; - assert(framesize > 0); - assert(framesize <= curr_space); - curr_space -= framesize; + CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - co = get_code(this_instr); - if (co == NULL) { - ctx->done = true; - } + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _BUILD_SLICE: { JitOptRef slice; slice = sym_new_type(ctx, &PySlice_Type); + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-oparg] = slice; stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2841,9 +3089,10 @@ case _FORMAT_WITH_SPEC: { JitOptRef res; res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2853,9 +3102,10 @@ bottom = stack_pointer[-1 - (oparg-1)]; assert(oparg > 0); top = bottom; + CHECK_STACK_BOUNDS(1); stack_pointer[0] = top; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2885,7 +3135,6 @@ res_stackref = PyStackRef_FromPyObjectSteal(res_o); /* End of uop copied from bytecodes for constant evaluation */ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - if (sym_is_const(ctx, res)) { PyObject *result = sym_get_const(ctx, res); if (_Py_IsImmortal(result)) { @@ -2893,9 +3142,10 @@ REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); } } + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } bool lhs_int = sym_matches_type(lhs, &PyLong_Type); @@ -2931,9 +3181,10 @@ else { res = sym_new_type(ctx, &PyFloat_Type); } + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = res; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2978,8 +3229,9 @@ eliminate_pop_guard(this_instr, value != Py_True); } sym_set_const(flag, Py_True); + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2992,8 +3244,9 @@ eliminate_pop_guard(this_instr, value != Py_False); } sym_set_const(flag, Py_False); + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3010,8 +3263,9 @@ eliminate_pop_guard(this_instr, true); } sym_set_const(val, Py_None); + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3027,8 +3281,9 @@ assert(!sym_matches_type(val, &_PyNone_Type)); eliminate_pop_guard(this_instr, false); } + CHECK_STACK_BOUNDS(-1); stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3059,6 +3314,10 @@ break; } + case _DYNAMIC_EXIT: { + break; + } + case _CHECK_VALIDITY: { break; } @@ -3067,9 +3326,10 @@ JitOptRef value; PyObject *ptr = (PyObject *)this_instr->operand0; value = sym_new_const(ctx, ptr); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3085,27 +3345,31 @@ JitOptRef value; PyObject *ptr = (PyObject *)this_instr->operand0; value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); + CHECK_STACK_BOUNDS(1); stack_pointer[0] = value; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_CALL: { + CHECK_STACK_BOUNDS(-2); stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_CALL_ONE: { + CHECK_STACK_BOUNDS(-3); stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _POP_CALL_TWO: { + CHECK_STACK_BOUNDS(-4); stack_pointer += -4; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3120,9 +3384,10 @@ case _POP_TWO_LOAD_CONST_INLINE_BORROW: { JitOptRef value; value = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = value; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3130,9 +3395,10 @@ JitOptRef value; PyObject *ptr = (PyObject *)this_instr->operand0; value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); + CHECK_STACK_BOUNDS(-1); stack_pointer[-2] = value; stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3140,9 +3406,10 @@ JitOptRef value; PyObject *ptr = (PyObject *)this_instr->operand0; value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); + CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = value; stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3150,9 +3417,10 @@ JitOptRef value; PyObject *ptr = (PyObject *)this_instr->operand0; value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); + CHECK_STACK_BOUNDS(-3); stack_pointer[-4] = value; stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3161,10 +3429,11 @@ JitOptRef new; value = sym_new_not_null(ctx); new = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = value; stack_pointer[0] = new; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3173,14 +3442,11 @@ JitOptRef new; value = sym_new_not_null(ctx); new = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = value; stack_pointer[0] = new; stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _CHECK_FUNCTION: { + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -3197,6 +3463,7 @@ } case _DEOPT: { + ctx->done = true; break; } @@ -3208,6 +3475,10 @@ break; } + case _SPILL_OR_RELOAD: { + break; + } + case _TIER2_RESUME_CHECK: { break; } @@ -3216,3 +3487,25 @@ break; } + case _COLD_DYNAMIC_EXIT: { + break; + } + + case _GUARD_IP__PUSH_FRAME: { + break; + } + + case _GUARD_IP_YIELD_VALUE: { + break; + } + + case _GUARD_IP_RETURN_VALUE: { + break; + } + + case _GUARD_IP_RETURN_GENERATOR: { + break; + } + + /* _TRACE_RECORD is not a viable micro-op for tier 2 */ + diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 8169ce9df5a..8a71eff465e 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -7,7 +7,6 @@ #include "pycore_long.h" #include "pycore_optimizer.h" #include "pycore_stats.h" -#include "pycore_tuple.h" // _PyTuple_FromArray() #include <stdbool.h> #include <stdint.h> @@ -667,7 +666,7 @@ _Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptRef *args) } JitOptRef -_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptRef ref, int item) +_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptRef ref, Py_ssize_t item) { JitOptSymbol *sym = PyJitRef_Unwrap(ref); assert(item >= 0); @@ -683,7 +682,7 @@ _Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptRef ref, int item) return _Py_uop_sym_new_not_null(ctx); } -int +Py_ssize_t _Py_uop_sym_tuple_length(JitOptRef ref) { JitOptSymbol *sym = PyJitRef_Unwrap(ref); @@ -818,15 +817,23 @@ _Py_uop_frame_new( JitOptRef *args, int arg_len) { - assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); + if (ctx->curr_frame_depth >= MAX_ABSTRACT_FRAME_DEPTH) { + ctx->done = true; + ctx->out_of_space = true; + OPT_STAT_INC(optimizer_frame_overflow); + return NULL; + } _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; - + frame->code = co; frame->stack_len = co->co_stacksize; frame->locals_len = co->co_nlocalsplus; frame->locals = ctx->n_consumed; frame->stack = frame->locals + co->co_nlocalsplus; frame->stack_pointer = frame->stack + curr_stackentries; + frame->globals_checked_version = 0; + frame->globals_watched = false; + frame->func = NULL; ctx->n_consumed = ctx->n_consumed + (co->co_nlocalsplus + co->co_stacksize); if (ctx->n_consumed >= ctx->limit) { ctx->done = true; @@ -895,16 +902,46 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx) ctx->done = false; ctx->out_of_space = false; ctx->contradiction = false; + ctx->builtins_watched = false; } int -_Py_uop_frame_pop(JitOptContext *ctx) +_Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries) { _Py_UOpsAbstractFrame *frame = ctx->frame; ctx->n_consumed = frame->locals; + ctx->curr_frame_depth--; - assert(ctx->curr_frame_depth >= 1); - ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1]; + + if (ctx->curr_frame_depth >= 1) { + ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1]; + + // We returned to the correct code. Nothing to do here. + if (co == ctx->frame->code) { + return 0; + } + // Else: the code we recorded doesn't match the code we *think* we're + // returning to. We could trace anything, we can't just return to the + // old frame. We have to restore what the tracer recorded + // as the traced next frame. + // Remove the current frame, and later swap it out with the right one. + else { + ctx->curr_frame_depth--; + } + } + // Else: trace stack underflow. + + // This handles swapping out frames. + assert(curr_stackentries >= 1); + // -1 to stackentries as we push to the stack our return value after this. + _Py_UOpsAbstractFrame *new_frame = _Py_uop_frame_new(ctx, co, curr_stackentries - 1, NULL, 0); + if (new_frame == NULL) { + ctx->done = true; + return 1; + } + + ctx->curr_frame_depth++; + ctx->frame = new_frame; return 0; } @@ -1040,7 +1077,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) "tuple item does not match value used to create tuple" ); PyObject *pair[2] = { val_42, val_43 }; - tuple = _PyTuple_FromArray(pair, 2); + tuple = PyTuple_FromArray(pair, 2); ref = _Py_uop_sym_new_const(ctx, tuple); TEST_PREDICATE( _Py_uop_sym_get_const(ctx, _Py_uop_sym_tuple_getitem(ctx, ref, 1)) == val_43, diff --git a/Python/parking_lot.c b/Python/parking_lot.c index e896dea0271..99c1ad848be 100644 --- a/Python/parking_lot.c +++ b/Python/parking_lot.c @@ -91,8 +91,8 @@ _PySemaphore_Destroy(_PySemaphore *sema) #endif } -static int -_PySemaphore_PlatformWait(_PySemaphore *sema, PyTime_t timeout) +int +_PySemaphore_Wait(_PySemaphore *sema, PyTime_t timeout) { int res; #if defined(MS_WINDOWS) @@ -225,27 +225,6 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, PyTime_t timeout) return res; } -int -_PySemaphore_Wait(_PySemaphore *sema, PyTime_t timeout, int detach) -{ - PyThreadState *tstate = NULL; - if (detach) { - tstate = _PyThreadState_GET(); - if (tstate && _PyThreadState_IsAttached(tstate)) { - // Only detach if we are attached - PyEval_ReleaseThread(tstate); - } - else { - tstate = NULL; - } - } - int res = _PySemaphore_PlatformWait(sema, timeout); - if (tstate) { - PyEval_AcquireThread(tstate); - } - return res; -} - void _PySemaphore_Wakeup(_PySemaphore *sema) { @@ -342,7 +321,19 @@ _PyParkingLot_Park(const void *addr, const void *expected, size_t size, enqueue(bucket, addr, &wait); _PyRawMutex_Unlock(&bucket->mutex); - int res = _PySemaphore_Wait(&wait.sema, timeout_ns, detach); + PyThreadState *tstate = NULL; + if (detach) { + tstate = _PyThreadState_GET(); + if (tstate && _PyThreadState_IsAttached(tstate)) { + // Only detach if we are attached + PyEval_ReleaseThread(tstate); + } + else { + tstate = NULL; + } + } + + int res = _PySemaphore_Wait(&wait.sema, timeout_ns); if (res == Py_PARK_OK) { goto done; } @@ -354,7 +345,7 @@ _PyParkingLot_Park(const void *addr, const void *expected, size_t size, // Another thread has started to unpark us. Wait until we process the // wakeup signal. do { - res = _PySemaphore_Wait(&wait.sema, -1, detach); + res = _PySemaphore_Wait(&wait.sema, -1); } while (res != Py_PARK_OK); goto done; } @@ -366,6 +357,9 @@ _PyParkingLot_Park(const void *addr, const void *expected, size_t size, done: _PySemaphore_Destroy(&wait.sema); + if (tstate) { + PyEval_AcquireThread(tstate); + } return res; } diff --git a/Python/perf_jit_trampoline.c b/Python/perf_jit_trampoline.c index 8732be97361..af7d8f9f1ec 100644 --- a/Python/perf_jit_trampoline.c +++ b/Python/perf_jit_trampoline.c @@ -61,6 +61,7 @@ #include "pycore_ceval.h" // _PyPerf_Callbacks #include "pycore_frame.h" #include "pycore_interp.h" +#include "pycore_mmap.h" // _PyAnnotateMemoryMap() #include "pycore_runtime.h" // _PyRuntime #ifdef PY_HAVE_PERF_TRAMPOLINE @@ -1085,6 +1086,7 @@ static void* perf_map_jit_init(void) { close(fd); return NULL; // Memory mapping failed } + _PyAnnotateMemoryMap(perf_jit_map_state.mapped_buffer, page_size, "cpython:perf_jit_trampoline"); #endif perf_jit_map_state.mapped_size = page_size; diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 987e8d2a11a..669a47ae173 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -132,6 +132,7 @@ any DWARF information available for them). #include "Python.h" #include "pycore_ceval.h" // _PyPerf_Callbacks #include "pycore_interpframe.h" // _PyFrame_GetCode() +#include "pycore_mmap.h" // _PyAnnotateMemoryMap() #include "pycore_runtime.h" // _PyRuntime @@ -290,6 +291,7 @@ new_code_arena(void) perf_status = PERF_STATUS_FAILED; return -1; } + _PyAnnotateMemoryMap(memory, mem_size, "cpython:perf_trampoline"); void *start = &_Py_trampoline_func_start; void *end = &_Py_trampoline_func_end; size_t code_size = end - start; diff --git a/Python/pyhash.c b/Python/pyhash.c index 216f437dd9a..157312a936b 100644 --- a/Python/pyhash.c +++ b/Python/pyhash.c @@ -29,7 +29,7 @@ static Py_ssize_t hashstats[Py_HASH_STATS_MAX + 1] = {0}; #endif /* For numeric types, the hash of a number x is based on the reduction - of x modulo the prime P = 2**_PyHASH_BITS - 1. It's designed so that + of x modulo the prime P = 2**PyHASH_BITS - 1. It's designed so that hash(x) == hash(y) whenever x and y are numerically equal, even if x and y have different types. @@ -52,8 +52,8 @@ static Py_ssize_t hashstats[Py_HASH_STATS_MAX + 1] = {0}; If the result of the reduction is infinity (this is impossible for integers, floats and Decimals) then use the predefined hash value - _PyHASH_INF for x >= 0, or -_PyHASH_INF for x < 0, instead. - _PyHASH_INF and -_PyHASH_INF are also used for the + PyHASH_INF for x >= 0, or -PyHASH_INF for x < 0, instead. + PyHASH_INF and -PyHASH_INF are also used for the hashes of float and Decimal infinities. NaNs hash with a pointer hash. Having distinct hash values prevents @@ -65,16 +65,16 @@ static Py_ssize_t hashstats[Py_HASH_STATS_MAX + 1] = {0}; efficiently, even if the exponent of the binary or decimal number is large. The key point is that - reduce(x * y) == reduce(x) * reduce(y) (modulo _PyHASH_MODULUS) + reduce(x * y) == reduce(x) * reduce(y) (modulo PyHASH_MODULUS) provided that {reduce(x), reduce(y)} != {0, infinity}. The reduction of a binary or decimal float is never infinity, since the denominator is a power of 2 (for binary) or a divisor of a power of 10 (for decimal). So we have, for nonnegative x, - reduce(x * 2**e) == reduce(x) * reduce(2**e) % _PyHASH_MODULUS + reduce(x * 2**e) == reduce(x) * reduce(2**e) % PyHASH_MODULUS - reduce(x * 10**e) == reduce(x) * reduce(10**e) % _PyHASH_MODULUS + reduce(x * 10**e) == reduce(x) * reduce(10**e) % PyHASH_MODULUS and reduce(10**e) can be computed efficiently by the usual modular exponentiation algorithm. For reduce(2**e) it's even better: since @@ -92,7 +92,7 @@ _Py_HashDouble(PyObject *inst, double v) if (!isfinite(v)) { if (isinf(v)) - return v > 0 ? _PyHASH_INF : -_PyHASH_INF; + return v > 0 ? PyHASH_INF : -PyHASH_INF; else return PyObject_GenericHash(inst); } @@ -109,19 +109,19 @@ _Py_HashDouble(PyObject *inst, double v) and hexadecimal floating point. */ x = 0; while (m) { - x = ((x << 28) & _PyHASH_MODULUS) | x >> (_PyHASH_BITS - 28); + x = ((x << 28) & PyHASH_MODULUS) | x >> (PyHASH_BITS - 28); m *= 268435456.0; /* 2**28 */ e -= 28; y = (Py_uhash_t)m; /* pull out integer part */ m -= y; x += y; - if (x >= _PyHASH_MODULUS) - x -= _PyHASH_MODULUS; + if (x >= PyHASH_MODULUS) + x -= PyHASH_MODULUS; } - /* adjust for the exponent; first reduce it modulo _PyHASH_BITS */ - e = e >= 0 ? e % _PyHASH_BITS : _PyHASH_BITS-1-((-1-e) % _PyHASH_BITS); - x = ((x << e) & _PyHASH_MODULUS) | x >> (_PyHASH_BITS - e); + /* adjust for the exponent; first reduce it modulo PyHASH_BITS */ + e = e >= 0 ? e % PyHASH_BITS : PyHASH_BITS-1-((-1-e) % PyHASH_BITS); + x = ((x << e) & PyHASH_MODULUS) | x >> (PyHASH_BITS - e); x = x * sign; if (x == (Py_uhash_t)-1) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index b6b1d2845ec..2527dca71d7 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -26,6 +26,7 @@ #include "pycore_runtime.h" // _Py_ID() #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_setobject.h" // _PySet_NextEntry() +#include "pycore_stats.h" // _PyStats_InterpInit() #include "pycore_sysmodule.h" // _PySys_ClearAttrString() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() #include "pycore_typeobject.h" // _PyTypes_InitTypes() @@ -209,7 +210,10 @@ _Py_LegacyLocaleDetected(int warn) * we may also want to check for that explicitly. */ const char *ctype_loc = setlocale(LC_CTYPE, NULL); - return ctype_loc != NULL && strcmp(ctype_loc, "C") == 0; + if (ctype_loc == NULL) { + return 0; + } + return (strcmp(ctype_loc, "C") == 0 || strcmp(ctype_loc, "POSIX") == 0); #else /* Windows uses code pages instead of locales, so no locale is legacy */ return 0; @@ -503,6 +507,7 @@ pycore_init_runtime(_PyRuntimeState *runtime, _PyRuntimeState_SetFinalizing(runtime, NULL); _Py_InitVersion(); + _Py_DumpTraceback_Init(); status = _Py_HashRandomization_Init(config); if (_PyStatus_EXCEPTION(status)) { @@ -652,6 +657,14 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } +#ifdef Py_STATS + // initialize pystats. This must be done after the settings are loaded. + status = _PyStats_InterpInit(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +#endif + // initialize the interp->obmalloc state. This must be done after // the settings are loaded (so that feature_flags are set) but before // any calls are made to obmalloc functions. @@ -833,6 +846,10 @@ pycore_init_builtins(PyThreadState *tstate) } interp->callable_cache.object__getattribute__ = object__getattribute__; + if (_PyType_InitSlotDefs(interp) < 0) { + return _PyStatus_ERR("failed to init slotdefs"); + } + if (_PyBuiltins_AddExceptions(bimod) < 0) { return _PyStatus_ERR("failed to add exceptions to builtins"); } @@ -1702,6 +1719,7 @@ finalize_modules(PyThreadState *tstate) // Invalidate all executors and turn off JIT: interp->jit = false; + interp->compiling = false; #ifdef _Py_TIER2 _Py_Executors_InvalidateAll(interp, 0); #endif @@ -2000,6 +2018,7 @@ resolve_final_tstate(_PyRuntimeState *runtime) } else { /* Fall back to the current tstate. It's better than nothing. */ + // XXX No it's not main_tstate = tstate; } } @@ -2011,6 +2030,133 @@ resolve_final_tstate(_PyRuntimeState *runtime) return main_tstate; } +#ifdef Py_GIL_DISABLED +#define ASSERT_WORLD_STOPPED(interp) assert(interp->runtime->stoptheworld.world_stopped) +#else +#define ASSERT_WORLD_STOPPED(interp) +#endif + +static int +interp_has_threads(PyInterpreterState *interp) +{ + /* This needs to check for non-daemon threads only, otherwise we get stuck + * in an infinite loop. */ + assert(interp != NULL); + ASSERT_WORLD_STOPPED(interp); + assert(interp->threads.head != NULL); + if (interp->threads.head->next == NULL) { + // No other threads active, easy way out. + return 0; + } + + // We don't have to worry about locking this because the + // world is stopped. + _Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) { + if (tstate->_whence == _PyThreadState_WHENCE_THREADING) { + return 1; + } + } + + return 0; +} + +static int +interp_has_pending_calls(PyInterpreterState *interp) +{ + assert(interp != NULL); + ASSERT_WORLD_STOPPED(interp); + return interp->ceval.pending.npending != 0; +} + +static int +interp_has_atexit_callbacks(PyInterpreterState *interp) +{ + assert(interp != NULL); + assert(interp->atexit.callbacks != NULL); + ASSERT_WORLD_STOPPED(interp); + assert(PyList_CheckExact(interp->atexit.callbacks)); + return PyList_GET_SIZE(interp->atexit.callbacks) != 0; +} + +static int +runtime_has_subinterpreters(_PyRuntimeState *runtime) +{ + assert(runtime != NULL); + HEAD_LOCK(runtime); + PyInterpreterState *interp = runtime->interpreters.head; + HEAD_UNLOCK(runtime); + return interp->next != NULL; +} + +static void +make_pre_finalization_calls(PyThreadState *tstate, int subinterpreters) +{ + assert(tstate != NULL); + PyInterpreterState *interp = tstate->interp; + /* Each of these functions can start one another, e.g. a pending call + * could start a thread or vice versa. To ensure that we properly clean + * call everything, we run these in a loop until none of them run anything. */ + for (;;) { + assert(!interp->runtime->stoptheworld.world_stopped); + + // Wrap up existing "threading"-module-created, non-daemon threads. + wait_for_thread_shutdown(tstate); + + // Make any remaining pending calls. + _Py_FinishPendingCalls(tstate); + + /* The interpreter is still entirely intact at this point, and the + * exit funcs may be relying on that. In particular, if some thread + * or exit func is still waiting to do an import, the import machinery + * expects Py_IsInitialized() to return true. So don't say the + * runtime is uninitialized until after the exit funcs have run. + * Note that Threading.py uses an exit func to do a join on all the + * threads created thru it, so this also protects pending imports in + * the threads created via Threading. + */ + + _PyAtExit_Call(tstate->interp); + + if (subinterpreters) { + /* Clean up any lingering subinterpreters. + + Two preconditions need to be met here: + + - This has to happen before _PyRuntimeState_SetFinalizing is + called, or else threads might get prematurely blocked. + - The world must not be stopped, as finalizers can run. + */ + finalize_subinterpreters(); + } + + + /* Stop the world to prevent other threads from creating threads or + * atexit callbacks. On the default build, this is simply locked by + * the GIL. For pending calls, we acquire the dedicated mutex, because + * Py_AddPendingCall() can be called without an attached thread state. + */ + + PyMutex_Lock(&interp->ceval.pending.mutex); + // XXX Why does _PyThreadState_DeleteList() rely on all interpreters + // being stopped? + _PyEval_StopTheWorldAll(interp->runtime); + int has_subinterpreters = subinterpreters + ? runtime_has_subinterpreters(interp->runtime) + : 0; + int should_continue = (interp_has_threads(interp) + || interp_has_atexit_callbacks(interp) + || interp_has_pending_calls(interp) + || has_subinterpreters); + if (!should_continue) { + break; + } + _PyEval_StartTheWorldAll(interp->runtime); + PyMutex_Unlock(&interp->ceval.pending.mutex); + } + assert(PyMutex_IsLocked(&interp->ceval.pending.mutex)); + ASSERT_WORLD_STOPPED(interp); +} + static int _Py_Finalize(_PyRuntimeState *runtime) { @@ -2027,23 +2173,8 @@ _Py_Finalize(_PyRuntimeState *runtime) // Block some operations. tstate->interp->finalizing = 1; - // Wrap up existing "threading"-module-created, non-daemon threads. - wait_for_thread_shutdown(tstate); - - // Make any remaining pending calls. - _Py_FinishPendingCalls(tstate); - - /* The interpreter is still entirely intact at this point, and the - * exit funcs may be relying on that. In particular, if some thread - * or exit func is still waiting to do an import, the import machinery - * expects Py_IsInitialized() to return true. So don't say the - * runtime is uninitialized until after the exit funcs have run. - * Note that Threading.py uses an exit func to do a join on all the - * threads created thru it, so this also protects pending imports in - * the threads created via Threading. - */ - - _PyAtExit_Call(tstate->interp); + // This call stops the world and takes the pending calls lock. + make_pre_finalization_calls(tstate, /*subinterpreters=*/1); assert(_PyThreadState_GET() == tstate); @@ -2061,7 +2192,7 @@ _Py_Finalize(_PyRuntimeState *runtime) #endif /* Ensure that remaining threads are detached */ - _PyEval_StopTheWorldAll(runtime); + ASSERT_WORLD_STOPPED(tstate->interp); /* Remaining daemon threads will be trapped in PyThread_hang_thread when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ @@ -2082,6 +2213,7 @@ _Py_Finalize(_PyRuntimeState *runtime) _PyThreadState_SetShuttingDown(p); } _PyEval_StartTheWorldAll(runtime); + PyMutex_Unlock(&tstate->interp->ceval.pending.mutex); /* Clear frames of other threads to call objects destructors. Destructors will be called in the current Python thread. Since @@ -2132,9 +2264,6 @@ _Py_Finalize(_PyRuntimeState *runtime) _PyImport_FiniExternal(tstate->interp); finalize_modules(tstate); - /* Clean up any lingering subinterpreters. */ - finalize_subinterpreters(); - /* Print debug stats if any */ _PyEval_Fini(); @@ -2299,17 +2428,16 @@ new_interpreter(PyThreadState **tstate_p, interpreters: disable PyGILState_Check(). */ runtime->gilstate.check_enabled = 0; - PyInterpreterState *interp = PyInterpreterState_New(); - if (interp == NULL) { - *tstate_p = NULL; - return _PyStatus_OK(); - } - _PyInterpreterState_SetWhence(interp, whence); - interp->_ready = 1; - // XXX Might new_interpreter() have been called without the GIL held? PyThreadState *save_tstate = _PyThreadState_GET(); PyThreadState *tstate = NULL; + PyInterpreterState *interp; + status = _PyInterpreterState_New(save_tstate, &interp); + if (interp == NULL) { + goto error; + } + _PyInterpreterState_SetWhence(interp, whence); + interp->_ready = 1; /* From this point until the init_interp_create_gil() call, we must not do anything that requires that the GIL be held @@ -2350,6 +2478,14 @@ new_interpreter(PyThreadState **tstate_p, return status; } +#ifdef Py_STATS + // initialize pystats. This must be done after the settings are loaded. + status = _PyStats_InterpInit(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +#endif + // initialize the interp->obmalloc state. This must be done after // the settings are loaded (so that feature_flags are set) but before // any calls are made to obmalloc functions. @@ -2386,7 +2522,7 @@ error: *tstate_p = NULL; if (tstate != NULL) { Py_EndInterpreter(tstate); - } else { + } else if (interp != NULL) { PyInterpreterState_Delete(interp); } if (save_tstate != NULL) { @@ -2416,9 +2552,8 @@ Py_NewInterpreter(void) return tstate; } -/* Delete an interpreter and its last thread. This requires that the - given thread state is current, that the thread has no remaining - frames, and that it is its interpreter's only remaining thread. +/* Delete an interpreter. This requires that the given thread state + is current, and that the thread has no remaining frames. It is a fatal error to violate these constraints. (Py_FinalizeEx() doesn't have these constraints -- it zaps @@ -2436,27 +2571,28 @@ Py_EndInterpreter(PyThreadState *tstate) if (tstate != _PyThreadState_GET()) { Py_FatalError("thread is not current"); } - if (tstate->current_frame != NULL) { + if (tstate->current_frame != tstate->base_frame) { Py_FatalError("thread still has a frame"); } interp->finalizing = 1; - // Wrap up existing "threading"-module-created, non-daemon threads. - wait_for_thread_shutdown(tstate); - - // Make any remaining pending calls. - _Py_FinishPendingCalls(tstate); - - _PyAtExit_Call(tstate->interp); - - if (tstate != interp->threads.head || tstate->next != NULL) { - Py_FatalError("not the last thread"); - } + // This call stops the world and takes the pending calls lock. + make_pre_finalization_calls(tstate, /*subinterpreters=*/0); + ASSERT_WORLD_STOPPED(interp); /* Remaining daemon threads will automatically exit when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ _PyInterpreterState_SetFinalizing(interp, tstate); + PyThreadState *list = _PyThreadState_RemoveExcept(tstate); + for (PyThreadState *p = list; p != NULL; p = p->next) { + _PyThreadState_SetShuttingDown(p); + } + + _PyEval_StartTheWorldAll(interp->runtime); + PyMutex_Unlock(&interp->ceval.pending.mutex); + _PyThreadState_DeleteList(list, /*is_after_fork=*/0); + // XXX Call something like _PyImport_Disable() here? _PyImport_FiniExternal(tstate->interp); @@ -2486,6 +2622,8 @@ finalize_subinterpreters(void) PyInterpreterState *main_interp = _PyInterpreterState_Main(); assert(final_tstate->interp == main_interp); _PyRuntimeState *runtime = main_interp->runtime; + assert(!runtime->stoptheworld.world_stopped); + assert(_PyRuntimeState_GetFinalizing(runtime) == NULL); struct pyinterpreters *interpreters = &runtime->interpreters; /* Get the first interpreter in the list. */ @@ -2505,7 +2643,7 @@ finalize_subinterpreters(void) (void)PyErr_WarnEx( PyExc_RuntimeWarning, "remaining subinterpreters; " - "destroy them with _interpreters.destroy()", + "close them with Interpreter.close()", 0); /* Swap out the current tstate, which we know must belong @@ -2514,27 +2652,17 @@ finalize_subinterpreters(void) /* Clean up all remaining subinterpreters. */ while (interp != NULL) { - assert(!_PyInterpreterState_IsRunningMain(interp)); - - /* Find the tstate to use for fini. We assume the interpreter - will have at most one tstate at this point. */ - PyThreadState *tstate = interp->threads.head; - if (tstate != NULL) { - /* Ideally we would be able to use tstate as-is, and rely - on it being in a ready state: no exception set, not - running anything (tstate->current_frame), matching the - current thread ID (tstate->thread_id). To play it safe, - we always delete it and use a fresh tstate instead. */ - assert(tstate != final_tstate); - _PyThreadState_Attach(tstate); - PyThreadState_Clear(tstate); - _PyThreadState_Detach(tstate); - PyThreadState_Delete(tstate); + /* Make a tstate for finalization. */ + PyThreadState *tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI); + if (tstate == NULL) { + // XXX Some graceful way to always get a thread state? + Py_FatalError("thread state allocation failed"); } - tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI); + + /* Enter the subinterpreter. */ + _PyThreadState_Attach(tstate); /* Destroy the subinterpreter. */ - _PyThreadState_Attach(tstate); Py_EndInterpreter(tstate); assert(_PyThreadState_GET() == NULL); @@ -3444,6 +3572,27 @@ Py_ExitStatusException(PyStatus status) } +static void +handle_thread_shutdown_exception(PyThreadState *tstate) +{ + assert(tstate != NULL); + assert(_PyErr_Occurred(tstate)); + PyInterpreterState *interp = tstate->interp; + assert(interp->threads.head != NULL); + _PyEval_StopTheWorld(interp); + + // We don't have to worry about locking this because the + // world is stopped. + _Py_FOR_EACH_TSTATE_UNLOCKED(interp, tstate) { + if (tstate->_whence == _PyThreadState_WHENCE_THREADING) { + tstate->_whence = _PyThreadState_WHENCE_THREADING_DAEMON; + } + } + + _PyEval_StartTheWorld(interp); + PyErr_FormatUnraisable("Exception ignored on threading shutdown"); +} + /* Wait until threading._shutdown completes, provided the threading module was imported in the first place. The shutdown routine will wait until all non-daemon @@ -3455,14 +3604,14 @@ wait_for_thread_shutdown(PyThreadState *tstate) PyObject *threading = PyImport_GetModule(&_Py_ID(threading)); if (threading == NULL) { if (_PyErr_Occurred(tstate)) { - PyErr_FormatUnraisable("Exception ignored on threading shutdown"); + handle_thread_shutdown_exception(tstate); } /* else: threading not imported */ return; } result = PyObject_CallMethodNoArgs(threading, &_Py_ID(_shutdown)); if (result == NULL) { - PyErr_FormatUnraisable("Exception ignored on threading shutdown"); + handle_thread_shutdown_exception(tstate); } else { Py_DECREF(result); @@ -3595,7 +3744,7 @@ PyOS_getsig(int sig) /* * All of the code in this function must only use async-signal-safe functions, - * listed at `man 7 signal` or + * listed at `man 7 signal-safety` or * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. */ PyOS_sighandler_t diff --git a/Python/pystate.c b/Python/pystate.c index 2465d866747..4bf89a23426 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -8,7 +8,6 @@ #include "pycore_codecs.h" // _PyCodec_Fini() #include "pycore_critical_section.h" // _PyCriticalSection_Resume() #include "pycore_dtoa.h" // _dtoa_state_INIT() -#include "pycore_emscripten_trampoline.h" // _Py_EmscriptenTrampoline_Init() #include "pycore_freelist.h" // _PyObject_ClearFreeLists() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interpframe.h" // _PyThreadState_HasStackSpace() @@ -22,7 +21,9 @@ #include "pycore_runtime.h" // _PyRuntime #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_stackref.h" // Py_STACKREF_DEBUG +#include "pycore_stats.h" // FT_STAT_WORLD_STOP_INC() #include "pycore_time.h" // _PyTime_Init() +#include "pycore_uop.h" // UOP_BUFFER_SIZE #include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts() @@ -68,47 +69,37 @@ to avoid the expense of doing their own locking). */ -#ifdef HAVE_THREAD_LOCAL /* The attached thread state for the current thread. */ _Py_thread_local PyThreadState *_Py_tss_tstate = NULL; /* The "bound" thread state used by PyGILState_Ensure(), also known as a "gilstate." */ _Py_thread_local PyThreadState *_Py_tss_gilstate = NULL; -#endif + +/* The interpreter of the attached thread state, + and is same as tstate->interp. */ +_Py_thread_local PyInterpreterState *_Py_tss_interp = NULL; static inline PyThreadState * current_fast_get(void) { -#ifdef HAVE_THREAD_LOCAL return _Py_tss_tstate; -#else - // XXX Fall back to the PyThread_tss_*() API. -# error "no supported thread-local variable storage classifier" -#endif } static inline void current_fast_set(_PyRuntimeState *Py_UNUSED(runtime), PyThreadState *tstate) { assert(tstate != NULL); -#ifdef HAVE_THREAD_LOCAL _Py_tss_tstate = tstate; -#else - // XXX Fall back to the PyThread_tss_*() API. -# error "no supported thread-local variable storage classifier" -#endif + assert(tstate->interp != NULL); + _Py_tss_interp = tstate->interp; } static inline void current_fast_clear(_PyRuntimeState *Py_UNUSED(runtime)) { -#ifdef HAVE_THREAD_LOCAL _Py_tss_tstate = NULL; -#else - // XXX Fall back to the PyThread_tss_*() API. -# error "no supported thread-local variable storage classifier" -#endif + _Py_tss_interp = NULL; } #define tstate_verify_not_active(tstate) \ @@ -353,11 +344,6 @@ init_runtime(_PyRuntimeState *runtime, runtime->main_thread = PyThread_get_thread_ident(); runtime->unicode_state.ids.next_index = unicode_next_index; - -#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) - _Py_EmscriptenTrampoline_Init(runtime); -#endif - runtime->_initialized = 1; } @@ -462,21 +448,30 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime) static PyInterpreterState * alloc_interpreter(void) { + // Aligned allocation for PyInterpreterState. + // the first word of the memory block is used to store + // the original pointer to be used later to free the memory. size_t alignment = _Alignof(PyInterpreterState); - size_t allocsize = sizeof(PyInterpreterState) + alignment - 1; + size_t allocsize = sizeof(PyInterpreterState) + sizeof(void *) + alignment - 1; void *mem = PyMem_RawCalloc(1, allocsize); if (mem == NULL) { return NULL; } - PyInterpreterState *interp = _Py_ALIGN_UP(mem, alignment); - assert(_Py_IS_ALIGNED(interp, alignment)); - interp->_malloced = mem; - return interp; + void *ptr = _Py_ALIGN_UP((char *)mem + sizeof(void *), alignment); + ((void **)ptr)[-1] = mem; + assert(_Py_IS_ALIGNED(ptr, alignment)); + return ptr; } static void free_interpreter(PyInterpreterState *interp) { +#ifdef Py_STATS + if (interp->pystats_struct) { + PyMem_RawFree(interp->pystats_struct); + interp->pystats_struct = NULL; + } +#endif // The main interpreter is statically allocated so // should not be freed. if (interp != &_PyRuntime._main_interpreter) { @@ -486,7 +481,7 @@ free_interpreter(PyInterpreterState *interp) interp->obmalloc = NULL; } assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState))); - PyMem_RawFree(interp->_malloced); + PyMem_RawFree(((void **)interp)[-1]); } } @@ -556,6 +551,7 @@ init_interpreter(PyInterpreterState *interp, #ifdef Py_GIL_DISABLED _Py_brc_init_state(interp); #endif + llist_init(&interp->mem_free_queue.head); llist_init(&interp->asyncio_tasks_head); interp->asyncio_tasks_lock = (PyMutex){0}; @@ -571,10 +567,11 @@ init_interpreter(PyInterpreterState *interp, } interp->_code_object_generation = 0; interp->jit = false; + interp->compiling = false; interp->executor_list_head = NULL; interp->executor_deletion_list_head = NULL; interp->executor_deletion_list_remaining_capacity = 0; - interp->trace_run_counter = JIT_CLEANUP_THRESHOLD; + interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD; if (interp != &runtime->_main_interpreter) { /* Fix the self-referential, statically initialized fields. */ interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); @@ -762,10 +759,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) Py_CLEAR(interp->audit_hooks); - // At this time, all the threads should be cleared so we don't need atomic - // operations for instrumentation_version or eval_breaker. + // gh-140257: Threads have already been cleared, but daemon threads may + // still access eval_breaker atomically via take_gil() right before they + // hang. Use an atomic store to prevent data races during finalization. interp->ceval.instrumentation_version = 0; - tstate->eval_breaker = 0; + _Py_atomic_store_uintptr(&tstate->eval_breaker, 0); for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; @@ -825,6 +823,14 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) assert(cold->vm_data.warm); _PyExecutor_Free(cold); } + + struct _PyExecutorObject *cold_dynamic = interp->cold_dynamic_executor; + if (cold_dynamic != NULL) { + interp->cold_dynamic_executor = NULL; + assert(cold_dynamic->vm_data.valid); + assert(cold_dynamic->vm_data.warm); + _PyExecutor_Free(cold_dynamic); + } /* We don't clear sysdict and builtins until the end of this function. Because clearing other attributes can execute arbitrary Python code which requires sysdict and builtins. */ @@ -954,6 +960,8 @@ PyInterpreterState_Delete(PyInterpreterState *interp) _PyObject_FiniState(interp); + PyConfig_Clear(&interp->config); + free_interpreter(interp); } @@ -1284,9 +1292,8 @@ _PyInterpreterState_RequireIDRef(PyInterpreterState *interp, int required) PyInterpreterState* PyInterpreterState_Get(void) { - PyThreadState *tstate = current_fast_get(); - _Py_EnsureTstateNotNULL(tstate); - PyInterpreterState *interp = tstate->interp; + _Py_AssertHoldsTstate(); + PyInterpreterState *interp = _Py_tss_interp; if (interp == NULL) { Py_FatalError("no current interpreter"); } @@ -1407,6 +1414,9 @@ static void free_threadstate(_PyThreadStateImpl *tstate) { PyInterpreterState *interp = tstate->base.interp; +#ifdef Py_STATS + _PyStats_ThreadFini(tstate); +#endif // The initial thread state of the interpreter is allocated // as part of the interpreter state so should not be freed. if (tstate == &interp->_initial_thread) { @@ -1456,7 +1466,7 @@ init_threadstate(_PyThreadStateImpl *_tstate, assert(tstate->prev == NULL); assert(tstate->_whence == _PyThreadState_WHENCE_NOTSET); - assert(whence >= 0 && whence <= _PyThreadState_WHENCE_EXEC); + assert(whence >= 0 && whence <= _PyThreadState_WHENCE_THREADING_DAEMON); tstate->_whence = whence; assert(id > 0); @@ -1472,7 +1482,31 @@ init_threadstate(_PyThreadStateImpl *_tstate, // This is cleared when PyGILState_Ensure() creates the thread state. tstate->gilstate_counter = 1; - tstate->current_frame = NULL; + // Initialize the embedded base frame - sentinel at the bottom of the frame stack + _tstate->base_frame.previous = NULL; + _tstate->base_frame.f_executable = PyStackRef_None; + _tstate->base_frame.f_funcobj = PyStackRef_NULL; + _tstate->base_frame.f_globals = NULL; + _tstate->base_frame.f_builtins = NULL; + _tstate->base_frame.f_locals = NULL; + _tstate->base_frame.frame_obj = NULL; + _tstate->base_frame.instr_ptr = NULL; + _tstate->base_frame.stackpointer = _tstate->base_frame.localsplus; + _tstate->base_frame.return_offset = 0; + _tstate->base_frame.owner = FRAME_OWNED_BY_INTERPRETER; + _tstate->base_frame.visited = 0; +#ifdef Py_DEBUG + _tstate->base_frame.lltrace = 0; +#endif +#ifdef Py_GIL_DISABLED + _tstate->base_frame.tlbc_index = 0; +#endif + _tstate->base_frame.localsplus[0] = PyStackRef_NULL; + + // current_frame starts pointing to the base frame + tstate->current_frame = &_tstate->base_frame; + // base_frame pointer for profilers to validate stack unwinding + tstate->base_frame = &_tstate->base_frame; tstate->datastack_chunk = NULL; tstate->datastack_top = NULL; tstate->datastack_limit = NULL; @@ -1485,9 +1519,15 @@ init_threadstate(_PyThreadStateImpl *_tstate, _tstate->c_stack_top = 0; _tstate->c_stack_hard_limit = 0; + _tstate->c_stack_init_base = 0; + _tstate->c_stack_init_top = 0; + _tstate->asyncio_running_loop = NULL; _tstate->asyncio_running_task = NULL; +#ifdef _Py_TIER2 + _tstate->jit_tracer_state.code_buffer = NULL; +#endif tstate->delete_later = NULL; llist_init(&_tstate->mem_free_queue); @@ -1535,6 +1575,13 @@ new_threadstate(PyInterpreterState *interp, int whence) return NULL; } #endif +#ifdef Py_STATS + // The PyStats structure is quite large and is allocated separated from tstate. + if (!_PyStats_ThreadInit(interp, tstate)) { + free_threadstate(tstate); + return NULL; + } +#endif /* We serialize concurrent creation to protect global state. */ HEAD_LOCK(interp->runtime); @@ -1620,7 +1667,11 @@ PyThreadState_Clear(PyThreadState *tstate) { assert(tstate->_status.initialized && !tstate->_status.cleared); assert(current_fast_get()->interp == tstate->interp); - assert(!_PyThreadState_IsRunningMain(tstate)); + // GH-126016: In the _interpreters module, KeyboardInterrupt exceptions + // during PyEval_EvalCode() are sent to finalization, which doesn't let us + // mark threads as "not running main". So, for now this assertion is + // disabled. + // XXX assert(!_PyThreadState_IsRunningMain(tstate)); // XXX assert(!tstate->_status.bound || tstate->_status.unbound); tstate->_status.finalizing = 1; // just in case @@ -1633,7 +1684,7 @@ PyThreadState_Clear(PyThreadState *tstate) int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; - if (verbose && tstate->current_frame != NULL) { + if (verbose && tstate->current_frame != tstate->base_frame) { /* bpo-20526: After the main thread calls _PyInterpreterState_SetFinalizing() in Py_FinalizeEx() (or in Py_EndInterpreter() for subinterpreters), @@ -1714,16 +1765,23 @@ PyThreadState_Clear(PyThreadState *tstate) struct _Py_freelists *freelists = _Py_freelists_GET(); _PyObject_ClearFreeLists(freelists, 1); + // Flush the thread's local GC allocation count to the global count + // before the thread state is cleared, otherwise the count is lost. + _PyThreadStateImpl *tstate_impl = (_PyThreadStateImpl *)tstate; + _Py_atomic_add_int(&tstate->interp->gc.young.count, + (int)tstate_impl->gc.alloc_count); + tstate_impl->gc.alloc_count = 0; + // Merge our thread-local refcounts into the type's own refcount and // free our local refcount array. - _PyObject_FinalizePerThreadRefcounts((_PyThreadStateImpl *)tstate); + _PyObject_FinalizePerThreadRefcounts(tstate_impl); // Remove ourself from the biased reference counting table of threads. _Py_brc_remove_thread(tstate); // Release our thread-local copies of the bytecode for reuse by another // thread - _Py_ClearTLBCIndex((_PyThreadStateImpl *)tstate); + _Py_ClearTLBCIndex(tstate_impl); #endif // Merge our queue of pointers to be freed into the interpreter queue. @@ -1783,6 +1841,14 @@ tstate_delete_common(PyThreadState *tstate, int release_gil) assert(tstate_impl->refcounts.values == NULL); #endif +#if _Py_TIER2 + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + if (_tstate->jit_tracer_state.code_buffer != NULL) { + _PyObject_VirtualFree(_tstate->jit_tracer_state.code_buffer, UOP_BUFFER_SIZE); + _tstate->jit_tracer_state.code_buffer = NULL; + } +#endif + HEAD_UNLOCK(runtime); // XXX Unbind in PyThreadState_Clear(), or earlier @@ -1842,6 +1908,9 @@ _PyThreadState_DeleteCurrent(PyThreadState *tstate) _Py_EnsureTstateNotNULL(tstate); #ifdef Py_GIL_DISABLED _Py_qsbr_detach(((_PyThreadStateImpl *)tstate)->qsbr); +#endif +#ifdef Py_STATS + _PyStats_Detach((_PyThreadStateImpl *)tstate); #endif current_fast_clear(tstate->interp->runtime); tstate_delete_common(tstate, 1); // release GIL as part of call @@ -2016,6 +2085,10 @@ tstate_deactivate(PyThreadState *tstate) assert(tstate_is_bound(tstate)); assert(tstate->_status.active); +#if Py_STATS + _PyStats_Detach((_PyThreadStateImpl *)tstate); +#endif + tstate->_status.active = 0; // We do not unbind the gilstate tstate here. @@ -2119,6 +2192,10 @@ _PyThreadState_Attach(PyThreadState *tstate) _PyCriticalSection_Resume(tstate); } +#ifdef Py_STATS + _PyStats_Attach((_PyThreadStateImpl *)tstate); +#endif + #if defined(Py_DEBUG) errno = err; #endif @@ -2253,19 +2330,22 @@ stop_the_world(struct _stoptheworld_state *stw) { _PyRuntimeState *runtime = &_PyRuntime; - PyMutex_Lock(&stw->mutex); + // gh-137433: Acquire the rwmutex first to avoid deadlocks with daemon + // threads that may hang when blocked on lock acquisition. if (stw->is_global) { _PyRWMutex_Lock(&runtime->stoptheworld_mutex); } else { _PyRWMutex_RLock(&runtime->stoptheworld_mutex); } + PyMutex_Lock(&stw->mutex); HEAD_LOCK(runtime); stw->requested = 1; stw->thread_countdown = 0; stw->stop_event = (PyEvent){0}; // zero-initialize (unset) stw->requester = _PyThreadState_GET(); // may be NULL + FT_STAT_WORLD_STOP_INC(); _Py_FOR_EACH_STW_INTERP(stw, i) { _Py_FOR_EACH_TSTATE_UNLOCKED(i, t) { @@ -2325,13 +2405,13 @@ start_the_world(struct _stoptheworld_state *stw) } stw->requester = NULL; HEAD_UNLOCK(runtime); + PyMutex_Unlock(&stw->mutex); if (stw->is_global) { _PyRWMutex_Unlock(&runtime->stoptheworld_mutex); } else { _PyRWMutex_RUnlock(&runtime->stoptheworld_mutex); } - PyMutex_Unlock(&stw->mutex); } #endif // Py_GIL_DISABLED @@ -2477,14 +2557,10 @@ _PyThreadState_Bind(PyThreadState *tstate) uintptr_t _Py_GetThreadLocal_Addr(void) { -#ifdef HAVE_THREAD_LOCAL // gh-112535: Use the address of the thread-local PyThreadState variable as // a unique identifier for the current thread. Each thread has a unique // _Py_tss_tstate variable with a unique address. return (uintptr_t)&_Py_tss_tstate; -#else -# error "no supported thread-local variable storage classifier" -#endif } #endif diff --git a/Python/pystats.c b/Python/pystats.c new file mode 100644 index 00000000000..a057ad88456 --- /dev/null +++ b/Python/pystats.c @@ -0,0 +1,819 @@ +#include "Python.h" + +#include "pycore_opcode_metadata.h" // _PyOpcode_Caches +#include "pycore_pyatomic_ft_wrappers.h" +#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() +#include "pycore_tstate.h" +#include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_uop_metadata.h" // _PyOpcode_uop_name +#include "pycore_uop_ids.h" // MAX_UOP_REGS_ID +#include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_runtime.h" // NUM_GENERATIONS + +#include <stdlib.h> // rand() + +#ifdef Py_STATS + +PyStats * +_PyStats_GetLocal(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate) { + return tstate->pystats; + } + return NULL; +} + +#ifdef Py_GIL_DISABLED +#define STATS_LOCK(interp) PyMutex_Lock(&interp->pystats_mutex) +#define STATS_UNLOCK(interp) PyMutex_Unlock(&interp->pystats_mutex) +#else +#define STATS_LOCK(interp) +#define STATS_UNLOCK(interp) +#endif + + +#if PYSTATS_MAX_UOP_ID < MAX_UOP_REGS_ID +#error "Not enough space allocated for pystats. Increase PYSTATS_MAX_UOP_ID to at least MAX_UOP_REGS_ID" +#endif + +#define ADD_STAT_TO_DICT(res, field) \ + do { \ + PyObject *val = PyLong_FromUnsignedLongLong(stats->field); \ + if (val == NULL) { \ + Py_DECREF(res); \ + return NULL; \ + } \ + if (PyDict_SetItemString(res, #field, val) == -1) { \ + Py_DECREF(res); \ + Py_DECREF(val); \ + return NULL; \ + } \ + Py_DECREF(val); \ + } while(0); + +static PyObject* +stats_to_dict(SpecializationStats *stats) +{ + PyObject *res = PyDict_New(); + if (res == NULL) { + return NULL; + } + ADD_STAT_TO_DICT(res, success); + ADD_STAT_TO_DICT(res, failure); + ADD_STAT_TO_DICT(res, hit); + ADD_STAT_TO_DICT(res, deferred); + ADD_STAT_TO_DICT(res, miss); + ADD_STAT_TO_DICT(res, deopt); + PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS); + if (failure_kinds == NULL) { + Py_DECREF(res); + return NULL; + } + for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) { + PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]); + if (stat == NULL) { + Py_DECREF(res); + Py_DECREF(failure_kinds); + return NULL; + } + PyTuple_SET_ITEM(failure_kinds, i, stat); + } + if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) { + Py_DECREF(res); + Py_DECREF(failure_kinds); + return NULL; + } + Py_DECREF(failure_kinds); + return res; +} +#undef ADD_STAT_TO_DICT + +static int +add_stat_dict( + PyStats *src, + PyObject *res, + int opcode, + const char *name) { + + SpecializationStats *stats = &src->opcode_stats[opcode].specialization; + PyObject *d = stats_to_dict(stats); + if (d == NULL) { + return -1; + } + int err = PyDict_SetItemString(res, name, d); + Py_DECREF(d); + return err; +} + +PyObject* +_Py_GetSpecializationStats(void) { + PyThreadState *tstate = _PyThreadState_GET(); + PyStats *src = FT_ATOMIC_LOAD_PTR_RELAXED(tstate->interp->pystats_struct); + if (src == NULL) { + Py_RETURN_NONE; + } + PyObject *stats = PyDict_New(); + if (stats == NULL) { + return NULL; + } + int err = 0; + err += add_stat_dict(src, stats, CONTAINS_OP, "contains_op"); + err += add_stat_dict(src, stats, LOAD_SUPER_ATTR, "load_super_attr"); + err += add_stat_dict(src, stats, LOAD_ATTR, "load_attr"); + err += add_stat_dict(src, stats, LOAD_GLOBAL, "load_global"); + err += add_stat_dict(src, stats, STORE_SUBSCR, "store_subscr"); + err += add_stat_dict(src, stats, STORE_ATTR, "store_attr"); + err += add_stat_dict(src, stats, JUMP_BACKWARD, "jump_backward"); + err += add_stat_dict(src, stats, CALL, "call"); + err += add_stat_dict(src, stats, CALL_KW, "call_kw"); + err += add_stat_dict(src, stats, BINARY_OP, "binary_op"); + err += add_stat_dict(src, stats, COMPARE_OP, "compare_op"); + err += add_stat_dict(src, stats, UNPACK_SEQUENCE, "unpack_sequence"); + err += add_stat_dict(src, stats, FOR_ITER, "for_iter"); + err += add_stat_dict(src, stats, TO_BOOL, "to_bool"); + err += add_stat_dict(src, stats, SEND, "send"); + if (err < 0) { + Py_DECREF(stats); + return NULL; + } + return stats; +} + + +#define PRINT_STAT(i, field) \ + if (stats[i].field) { \ + fprintf(out, " opcode[%s]." #field " : %" PRIu64 "\n", _PyOpcode_OpName[i], stats[i].field); \ + } + +static void +print_spec_stats(FILE *out, OpcodeStats *stats) +{ + /* Mark some opcodes as specializable for stats, + * even though we don't specialize them yet. */ + fprintf(out, "opcode[BINARY_SLICE].specializable : 1\n"); + fprintf(out, "opcode[STORE_SLICE].specializable : 1\n"); + fprintf(out, "opcode[GET_ITER].specializable : 1\n"); + for (int i = 0; i < 256; i++) { + if (_PyOpcode_Caches[i]) { + /* Ignore jumps as they cannot be specialized */ + switch (i) { + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + case POP_JUMP_IF_NONE: + case POP_JUMP_IF_NOT_NONE: + case JUMP_BACKWARD: + break; + default: + fprintf(out, "opcode[%s].specializable : 1\n", _PyOpcode_OpName[i]); + } + } + PRINT_STAT(i, specialization.success); + PRINT_STAT(i, specialization.failure); + PRINT_STAT(i, specialization.hit); + PRINT_STAT(i, specialization.deferred); + PRINT_STAT(i, specialization.miss); + PRINT_STAT(i, specialization.deopt); + PRINT_STAT(i, execution_count); + for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) { + uint64_t val = stats[i].specialization.failure_kinds[j]; + if (val) { + fprintf(out, " opcode[%s].specialization.failure_kinds[%d] : %" + PRIu64 "\n", _PyOpcode_OpName[i], j, val); + } + } + for (int j = 0; j < 256; j++) { + if (stats[i].pair_count[j]) { + fprintf(out, "opcode[%s].pair_count[%s] : %" PRIu64 "\n", + _PyOpcode_OpName[i], _PyOpcode_OpName[j], stats[i].pair_count[j]); + } + } + } +} +#undef PRINT_STAT + + +static void +print_call_stats(FILE *out, CallStats *stats) +{ + fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls); + fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls); + fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed); + fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created); + for (int i = 0; i < EVAL_CALL_KINDS; i++) { + fprintf(out, "Calls via PyEval_EvalFrame[%d] : %" PRIu64 "\n", i, stats->eval_calls[i]); + } +} + +static void +print_object_stats(FILE *out, ObjectStats *stats) +{ + fprintf(out, "Object allocations from freelist: %" PRIu64 "\n", stats->from_freelist); + fprintf(out, "Object frees to freelist: %" PRIu64 "\n", stats->to_freelist); + fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations); + fprintf(out, "Object allocations to 512 bytes: %" PRIu64 "\n", stats->allocations512); + fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k); + fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big); + fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees); + fprintf(out, "Object inline values: %" PRIu64 "\n", stats->inline_values); + fprintf(out, "Object interpreter mortal increfs: %" PRIu64 "\n", stats->interpreter_increfs); + fprintf(out, "Object interpreter mortal decrefs: %" PRIu64 "\n", stats->interpreter_decrefs); + fprintf(out, "Object mortal increfs: %" PRIu64 "\n", stats->increfs); + fprintf(out, "Object mortal decrefs: %" PRIu64 "\n", stats->decrefs); + fprintf(out, "Object interpreter immortal increfs: %" PRIu64 "\n", stats->interpreter_immortal_increfs); + fprintf(out, "Object interpreter immortal decrefs: %" PRIu64 "\n", stats->interpreter_immortal_decrefs); + fprintf(out, "Object immortal increfs: %" PRIu64 "\n", stats->immortal_increfs); + fprintf(out, "Object immortal decrefs: %" PRIu64 "\n", stats->immortal_decrefs); + fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request); + fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); + fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); + fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass); + fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits); + fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses); + fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); + fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits); + fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses); +} + +static void +print_gc_stats(FILE *out, GCStats *stats) +{ + for (int i = 0; i < NUM_GENERATIONS; i++) { + fprintf(out, "GC[%d] collections: %" PRIu64 "\n", i, stats[i].collections); + fprintf(out, "GC[%d] object visits: %" PRIu64 "\n", i, stats[i].object_visits); + fprintf(out, "GC[%d] objects collected: %" PRIu64 "\n", i, stats[i].objects_collected); + fprintf(out, "GC[%d] objects reachable from roots: %" PRIu64 "\n", i, stats[i].objects_transitively_reachable); + fprintf(out, "GC[%d] objects not reachable from roots: %" PRIu64 "\n", i, stats[i].objects_not_transitively_reachable); + } +} + +#ifdef _Py_TIER2 +static void +print_histogram(FILE *out, const char *name, uint64_t hist[_Py_UOP_HIST_SIZE]) +{ + for (int i = 0; i < _Py_UOP_HIST_SIZE; i++) { + fprintf(out, "%s[%" PRIu64"]: %" PRIu64 "\n", name, (uint64_t)1 << i, hist[i]); + } +} + +extern const char *_PyUOpName(int index); + +static void +print_optimization_stats(FILE *out, OptimizationStats *stats) +{ + fprintf(out, "Optimization attempts: %" PRIu64 "\n", stats->attempts); + fprintf(out, "Optimization traces created: %" PRIu64 "\n", stats->traces_created); + fprintf(out, "Optimization traces executed: %" PRIu64 "\n", stats->traces_executed); + fprintf(out, "Optimization uops executed: %" PRIu64 "\n", stats->uops_executed); + fprintf(out, "Optimization trace stack overflow: %" PRIu64 "\n", stats->trace_stack_overflow); + fprintf(out, "Optimization trace stack underflow: %" PRIu64 "\n", stats->trace_stack_underflow); + fprintf(out, "Optimization trace too long: %" PRIu64 "\n", stats->trace_too_long); + fprintf(out, "Optimization trace too short: %" PRIu64 "\n", stats->trace_too_short); + fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop); + fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call); + fprintf(out, "Optimization low confidence: %" PRIu64 "\n", stats->low_confidence); + fprintf(out, "Optimization unknown callee: %" PRIu64 "\n", stats->unknown_callee); + fprintf(out, "Executors invalidated: %" PRIu64 "\n", stats->executors_invalidated); + + print_histogram(out, "Trace length", stats->trace_length_hist); + print_histogram(out, "Trace run length", stats->trace_run_length_hist); + print_histogram(out, "Optimized trace length", stats->optimized_trace_length_hist); + + fprintf(out, "Optimization optimizer attempts: %" PRIu64 "\n", stats->optimizer_attempts); + fprintf(out, "Optimization optimizer successes: %" PRIu64 "\n", stats->optimizer_successes); + fprintf(out, "Optimization optimizer failure no memory: %" PRIu64 "\n", + stats->optimizer_failure_reason_no_memory); + fprintf(out, "Optimizer remove globals builtins changed: %" PRIu64 "\n", stats->remove_globals_builtins_changed); + fprintf(out, "Optimizer remove globals incorrect keys: %" PRIu64 "\n", stats->remove_globals_incorrect_keys); + for (int i = 0; i <= MAX_UOP_REGS_ID; i++) { + if (stats->opcode[i].execution_count) { + fprintf(out, "uops[%s].execution_count : %" PRIu64 "\n", _PyUOpName(i), stats->opcode[i].execution_count); + } + if (stats->opcode[i].miss) { + fprintf(out, "uops[%s].specialization.miss : %" PRIu64 "\n", _PyUOpName(i), stats->opcode[i].miss); + } + } + for (int i = 0; i < 256; i++) { + if (stats->unsupported_opcode[i]) { + fprintf( + out, + "unsupported_opcode[%s].count : %" PRIu64 "\n", + _PyOpcode_OpName[i], + stats->unsupported_opcode[i] + ); + } + } + + for (int i = 1; i <= MAX_UOP_REGS_ID; i++){ + for (int j = 1; j <= MAX_UOP_REGS_ID; j++) { + if (stats->opcode[i].pair_count[j]) { + fprintf(out, "uop[%s].pair_count[%s] : %" PRIu64 "\n", + _PyOpcode_uop_name[i], _PyOpcode_uop_name[j], stats->opcode[i].pair_count[j]); + } + } + } + for (int i = 0; i < MAX_UOP_REGS_ID; i++) { + if (stats->error_in_opcode[i]) { + fprintf( + out, + "error_in_opcode[%s].count : %" PRIu64 "\n", + _PyUOpName(i), + stats->error_in_opcode[i] + ); + } + } + fprintf(out, "JIT total memory size: %" PRIu64 "\n", stats->jit_total_memory_size); + fprintf(out, "JIT code size: %" PRIu64 "\n", stats->jit_code_size); + fprintf(out, "JIT trampoline size: %" PRIu64 "\n", stats->jit_trampoline_size); + fprintf(out, "JIT data size: %" PRIu64 "\n", stats->jit_data_size); + fprintf(out, "JIT padding size: %" PRIu64 "\n", stats->jit_padding_size); + fprintf(out, "JIT freed memory size: %" PRIu64 "\n", stats->jit_freed_memory_size); + + print_histogram(out, "Trace total memory size", stats->trace_total_memory_hist); +} +#endif + +#ifdef Py_GIL_DISABLED +static void +print_ft_stats(FILE *out, FTStats *stats) +{ + fprintf(out, "Mutex sleeps (mutex_sleeps): %" PRIu64 "\n", stats->mutex_sleeps); + fprintf(out, "QSBR polls (qsbr_polls): %" PRIu64 "\n", stats->qsbr_polls); + fprintf(out, "World stops (world_stops): %" PRIu64 "\n", stats->world_stops); +} +#endif + +static void +print_rare_event_stats(FILE *out, RareEventStats *stats) +{ + fprintf(out, "Rare event (set_class): %" PRIu64 "\n", stats->set_class); + fprintf(out, "Rare event (set_bases): %" PRIu64 "\n", stats->set_bases); + fprintf(out, "Rare event (set_eval_frame_func): %" PRIu64 "\n", stats->set_eval_frame_func); + fprintf(out, "Rare event (builtin_dict): %" PRIu64 "\n", stats->builtin_dict); + fprintf(out, "Rare event (func_modification): %" PRIu64 "\n", stats->func_modification); + fprintf(out, "Rare event (watched_dict_modification): %" PRIu64 "\n", stats->watched_dict_modification); + fprintf(out, "Rare event (watched_globals_modification): %" PRIu64 "\n", stats->watched_globals_modification); +} + +static void +print_stats(FILE *out, PyStats *stats) +{ + print_spec_stats(out, stats->opcode_stats); + print_call_stats(out, &stats->call_stats); + print_object_stats(out, &stats->object_stats); + print_gc_stats(out, stats->gc_stats); +#ifdef _Py_TIER2 + print_optimization_stats(out, &stats->optimization_stats); +#endif +#ifdef Py_GIL_DISABLED + print_ft_stats(out, &stats->ft_stats); +#endif + print_rare_event_stats(out, &stats->rare_event_stats); +} + +#ifdef Py_GIL_DISABLED + +static void +merge_specialization_stats(SpecializationStats *dest, const SpecializationStats *src) +{ + dest->success += src->success; + dest->failure += src->failure; + dest->hit += src->hit; + dest->deferred += src->deferred; + dest->miss += src->miss; + dest->deopt += src->deopt; + for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) { + dest->failure_kinds[i] += src->failure_kinds[i]; + } +} + +static void +merge_opcode_stats_array(OpcodeStats *dest, const OpcodeStats *src) +{ + for (int i = 0; i < 256; i++) { + merge_specialization_stats(&dest[i].specialization, &src[i].specialization); + dest[i].execution_count += src[i].execution_count; + for (int j = 0; j < 256; j++) { + dest[i].pair_count[j] += src[i].pair_count[j]; + } + } +} + +static void +merge_call_stats(CallStats *dest, const CallStats *src) +{ + dest->inlined_py_calls += src->inlined_py_calls; + dest->pyeval_calls += src->pyeval_calls; + dest->frames_pushed += src->frames_pushed; + dest->frame_objects_created += src->frame_objects_created; + for (int i = 0; i < EVAL_CALL_KINDS; i++) { + dest->eval_calls[i] += src->eval_calls[i]; + } +} + +static void +merge_object_stats(ObjectStats *dest, const ObjectStats *src) +{ + dest->increfs += src->increfs; + dest->decrefs += src->decrefs; + dest->interpreter_increfs += src->interpreter_increfs; + dest->interpreter_decrefs += src->interpreter_decrefs; + dest->immortal_increfs += src->immortal_increfs; + dest->immortal_decrefs += src->immortal_decrefs; + dest->interpreter_immortal_increfs += src->interpreter_immortal_increfs; + dest->interpreter_immortal_decrefs += src->interpreter_immortal_decrefs; + dest->allocations += src->allocations; + dest->allocations512 += src->allocations512; + dest->allocations4k += src->allocations4k; + dest->allocations_big += src->allocations_big; + dest->frees += src->frees; + dest->to_freelist += src->to_freelist; + dest->from_freelist += src->from_freelist; + dest->inline_values += src->inline_values; + dest->dict_materialized_on_request += src->dict_materialized_on_request; + dest->dict_materialized_new_key += src->dict_materialized_new_key; + dest->dict_materialized_too_big += src->dict_materialized_too_big; + dest->dict_materialized_str_subclass += src->dict_materialized_str_subclass; + dest->type_cache_hits += src->type_cache_hits; + dest->type_cache_misses += src->type_cache_misses; + dest->type_cache_dunder_hits += src->type_cache_dunder_hits; + dest->type_cache_dunder_misses += src->type_cache_dunder_misses; + dest->type_cache_collisions += src->type_cache_collisions; + dest->object_visits += src->object_visits; +} + +static void +merge_uop_stats_array(UOpStats *dest, const UOpStats *src) +{ + for (int i = 0; i <= PYSTATS_MAX_UOP_ID; i++) { + dest[i].execution_count += src[i].execution_count; + dest[i].miss += src[i].miss; + for (int j = 0; j <= PYSTATS_MAX_UOP_ID; j++) { + dest[i].pair_count[j] += src[i].pair_count[j]; + } + } +} + +static void +merge_optimization_stats(OptimizationStats *dest, const OptimizationStats *src) +{ + dest->attempts += src->attempts; + dest->traces_created += src->traces_created; + dest->traces_executed += src->traces_executed; + dest->uops_executed += src->uops_executed; + dest->trace_stack_overflow += src->trace_stack_overflow; + dest->trace_stack_underflow += src->trace_stack_underflow; + dest->trace_too_long += src->trace_too_long; + dest->trace_too_short += src->trace_too_short; + dest->inner_loop += src->inner_loop; + dest->recursive_call += src->recursive_call; + dest->low_confidence += src->low_confidence; + dest->unknown_callee += src->unknown_callee; + dest->executors_invalidated += src->executors_invalidated; + dest->optimizer_attempts += src->optimizer_attempts; + dest->optimizer_successes += src->optimizer_successes; + dest->optimizer_failure_reason_no_memory += src->optimizer_failure_reason_no_memory; + dest->remove_globals_builtins_changed += src->remove_globals_builtins_changed; + dest->remove_globals_incorrect_keys += src->remove_globals_incorrect_keys; + dest->jit_total_memory_size += src->jit_total_memory_size; + dest->jit_code_size += src->jit_code_size; + dest->jit_trampoline_size += src->jit_trampoline_size; + dest->jit_data_size += src->jit_data_size; + dest->jit_padding_size += src->jit_padding_size; + dest->jit_freed_memory_size += src->jit_freed_memory_size; + + merge_uop_stats_array(dest->opcode, src->opcode); + + for (int i = 0; i < 256; i++) { + dest->unsupported_opcode[i] += src->unsupported_opcode[i]; + } + for (int i = 0; i < _Py_UOP_HIST_SIZE; i++) { + dest->trace_length_hist[i] += src->trace_length_hist[i]; + dest->trace_run_length_hist[i] += src->trace_run_length_hist[i]; + dest->optimized_trace_length_hist[i] += src->optimized_trace_length_hist[i]; + dest->trace_total_memory_hist[i] += src->trace_total_memory_hist[i]; + } + for (int i = 0; i <= PYSTATS_MAX_UOP_ID; i++) { + dest->error_in_opcode[i] += src->error_in_opcode[i]; + } +} + +static void +merge_ft_stats(FTStats *dest, const FTStats *src) +{ + dest->mutex_sleeps = src->mutex_sleeps; + dest->qsbr_polls = src->qsbr_polls; + dest->world_stops = src->world_stops; +} + +static void +merge_rare_event_stats(RareEventStats *dest, const RareEventStats *src) +{ + dest->set_class += src->set_class; + dest->set_bases += src->set_bases; + dest->set_eval_frame_func += src->set_eval_frame_func; + dest->builtin_dict += src->builtin_dict; + dest->func_modification += src->func_modification; + dest->watched_dict_modification += src->watched_dict_modification; + dest->watched_globals_modification += src->watched_globals_modification; +} + +static void +merge_gc_stats_array(GCStats *dest, const GCStats *src) +{ + for (int i = 0; i < NUM_GENERATIONS; i++) { + dest[i].collections += src[i].collections; + dest[i].object_visits += src[i].object_visits; + dest[i].objects_collected += src[i].objects_collected; + dest[i].objects_transitively_reachable += src[i].objects_transitively_reachable; + dest[i].objects_not_transitively_reachable += src[i].objects_not_transitively_reachable; + } +} + +void +stats_zero_thread(_PyThreadStateImpl *tstate) +{ + // Zero the thread local stat counters + if (tstate->pystats_struct) { + memset(tstate->pystats_struct, 0, sizeof(PyStats)); + } +} + +// merge stats for a single thread into the global structure +void +stats_merge_thread(_PyThreadStateImpl *tstate) +{ + PyStats *src = tstate->pystats_struct; + PyStats *dest = ((PyThreadState *)tstate)->interp->pystats_struct; + + if (src == NULL || dest == NULL) { + return; + } + + // Merge each category of stats using the helper functions. + merge_opcode_stats_array(dest->opcode_stats, src->opcode_stats); + merge_call_stats(&dest->call_stats, &src->call_stats); + merge_object_stats(&dest->object_stats, &src->object_stats); + merge_optimization_stats(&dest->optimization_stats, &src->optimization_stats); + merge_ft_stats(&dest->ft_stats, &src->ft_stats); + merge_rare_event_stats(&dest->rare_event_stats, &src->rare_event_stats); + merge_gc_stats_array(dest->gc_stats, src->gc_stats); +} +#endif // Py_GIL_DISABLED + +// toggle stats collection on or off for all threads +static int +stats_toggle_on_off(PyThreadState *tstate, int on) +{ + bool changed = false; + PyInterpreterState *interp = tstate->interp; + STATS_LOCK(interp); + if (on && interp->pystats_struct == NULL) { + PyStats *s = PyMem_RawCalloc(1, sizeof(PyStats)); + if (s == NULL) { + STATS_UNLOCK(interp); + return -1; + } + FT_ATOMIC_STORE_PTR_RELAXED(interp->pystats_struct, s); + } + if (tstate->interp->pystats_enabled != on) { + FT_ATOMIC_STORE_INT_RELAXED(interp->pystats_enabled, on); + changed = true; + } + STATS_UNLOCK(interp); + if (!changed) { + return 0; + } + _PyEval_StopTheWorld(interp); + _Py_FOR_EACH_TSTATE_UNLOCKED(interp, ts) { + PyStats *s = NULL; + if (interp->pystats_enabled) { +#ifdef Py_GIL_DISABLED + _PyThreadStateImpl *ts_impl = (_PyThreadStateImpl *)ts; + if (ts_impl->pystats_struct == NULL) { + // first activation for this thread, allocate structure + ts_impl->pystats_struct = PyMem_RawCalloc(1, sizeof(PyStats)); + } + s = ts_impl->pystats_struct; +#else + s = ts->interp->pystats_struct; +#endif + } + ts->pystats = s; + } + _PyEval_StartTheWorld(interp); + return 0; +} + +// zero stats for all threads and for the interpreter +static void +stats_zero_all(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate == NULL) { + return; + } + if (FT_ATOMIC_LOAD_PTR_RELAXED(tstate->interp->pystats_struct) == NULL) { + return; + } + PyInterpreterState *interp = tstate->interp; + _PyEval_StopTheWorld(interp); +#ifdef Py_GIL_DISABLED + _Py_FOR_EACH_TSTATE_UNLOCKED(interp, ts) { + stats_zero_thread((_PyThreadStateImpl *)ts); + } +#endif + if (interp->pystats_struct) { + memset(interp->pystats_struct, 0, sizeof(PyStats)); + } + _PyEval_StartTheWorld(interp); +} + +// merge stats for all threads into the per-interpreter structure +static void +stats_merge_all(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate == NULL) { + return; + } + if (FT_ATOMIC_LOAD_PTR_RELAXED(tstate->interp->pystats_struct) == NULL) { + return; + } + PyInterpreterState *interp = tstate->interp; + _PyEval_StopTheWorld(interp); +#ifdef Py_GIL_DISABLED + _Py_FOR_EACH_TSTATE_UNLOCKED(interp, ts) { + stats_merge_thread((_PyThreadStateImpl *)ts); + stats_zero_thread((_PyThreadStateImpl *)ts); + } +#endif + _PyEval_StartTheWorld(interp); +} + +int +_Py_StatsOn(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + return stats_toggle_on_off(tstate, 1); +} + +void +_Py_StatsOff(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + stats_toggle_on_off(tstate, 0); +} + +void +_Py_StatsClear(void) +{ + stats_zero_all(); +} + +static int +mem_is_zero(unsigned char *ptr, size_t size) +{ + for (size_t i=0; i < size; i++) { + if (*ptr != 0) { + return 0; + } + ptr++; + } + return 1; +} + +int +_Py_PrintSpecializationStats(int to_file) +{ + assert(to_file); + stats_merge_all(); + PyThreadState *tstate = _PyThreadState_GET(); + STATS_LOCK(tstate->interp); + PyStats *stats = tstate->interp->pystats_struct; + if (stats == NULL) { + STATS_UNLOCK(tstate->interp); + return 0; + } +#define MEM_IS_ZERO(DATA) mem_is_zero((unsigned char*)DATA, sizeof(*(DATA))) + int is_zero = ( + MEM_IS_ZERO(stats->gc_stats) // is a pointer + && MEM_IS_ZERO(&stats->opcode_stats) + && MEM_IS_ZERO(&stats->call_stats) + && MEM_IS_ZERO(&stats->object_stats) + ); +#undef MEM_IS_ZERO + STATS_UNLOCK(tstate->interp); + if (is_zero) { + // gh-108753: -X pystats command line was used, but then _stats_off() + // and _stats_clear() have been called: in this case, avoid printing + // useless "all zeros" statistics. + return 0; + } + + FILE *out = stderr; + if (to_file) { + /* Write to a file instead of stderr. */ +# ifdef MS_WINDOWS + const char *dirname = "c:\\temp\\py_stats\\"; +# else + const char *dirname = "/tmp/py_stats/"; +# endif + /* Use random 160 bit number as file name, + * to avoid both accidental collisions and + * symlink attacks. */ + unsigned char rand[20]; + char hex_name[41]; + _PyOS_URandomNonblock(rand, 20); + for (int i = 0; i < 20; i++) { + hex_name[2*i] = Py_hexdigits[rand[i]&15]; + hex_name[2*i+1] = Py_hexdigits[(rand[i]>>4)&15]; + } + hex_name[40] = '\0'; + char buf[64]; + assert(strlen(dirname) + 40 + strlen(".txt") < 64); + sprintf(buf, "%s%s.txt", dirname, hex_name); + FILE *fout = fopen(buf, "w"); + if (fout) { + out = fout; + } + } + else { + fprintf(out, "Specialization stats:\n"); + } + STATS_LOCK(tstate->interp); + print_stats(out, stats); + STATS_UNLOCK(tstate->interp); + if (out != stderr) { + fclose(out); + } + return 1; +} + +PyStatus +_PyStats_InterpInit(PyInterpreterState *interp) +{ + if (interp->config._pystats) { + // start with pystats enabled, can be disabled via sys._stats_off() + // this needs to be set before the first tstate is created + interp->pystats_enabled = 1; + interp->pystats_struct = PyMem_RawCalloc(1, sizeof(PyStats)); + if (interp->pystats_struct == NULL) { + return _PyStatus_ERR("out-of-memory while initializing interpreter"); + } + } + return _PyStatus_OK(); +} + +bool +_PyStats_ThreadInit(PyInterpreterState *interp, _PyThreadStateImpl *tstate) +{ +#ifdef Py_GIL_DISABLED + if (FT_ATOMIC_LOAD_INT_RELAXED(interp->pystats_enabled)) { + assert(interp->pystats_struct != NULL); + tstate->pystats_struct = PyMem_RawCalloc(1, sizeof(PyStats)); + if (tstate->pystats_struct == NULL) { + return false; + } + } +#endif + return true; +} + +void +_PyStats_ThreadFini(_PyThreadStateImpl *tstate) +{ +#ifdef Py_GIL_DISABLED + STATS_LOCK(((PyThreadState *)tstate)->interp); + stats_merge_thread(tstate); + STATS_UNLOCK(((PyThreadState *)tstate)->interp); + PyMem_RawFree(tstate->pystats_struct); +#endif +} + +void +_PyStats_Attach(_PyThreadStateImpl *tstate_impl) +{ + PyStats *s; + PyThreadState *tstate = (PyThreadState *)tstate_impl; + PyInterpreterState *interp = tstate->interp; + if (FT_ATOMIC_LOAD_INT_RELAXED(interp->pystats_enabled)) { +#ifdef Py_GIL_DISABLED + s = ((_PyThreadStateImpl *)tstate)->pystats_struct; +#else + s = tstate->interp->pystats_struct; +#endif + } + else { + s = NULL; + } + tstate->pystats = s; +} + +void +_PyStats_Detach(_PyThreadStateImpl *tstate_impl) +{ + ((PyThreadState *)tstate_impl)->pystats = NULL; +} + +#endif // Py_STATS diff --git a/Python/pystrhex.c b/Python/pystrhex.c index 38484f5a7d4..af2f5c5dce5 100644 --- a/Python/pystrhex.c +++ b/Python/pystrhex.c @@ -42,8 +42,7 @@ static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen, else { bytes_per_sep_group = 0; } - - unsigned int abs_bytes_per_sep = Py_ABS(bytes_per_sep_group); + unsigned int abs_bytes_per_sep = _Py_ABS_CAST(unsigned int, bytes_per_sep_group); Py_ssize_t resultlen = 0; if (bytes_per_sep_group && arglen > 0) { /* How many sep characters we'll be inserting. */ diff --git a/Python/pystrtod.c b/Python/pystrtod.c index 7b74f613ed5..e8aca939d1f 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -43,7 +43,7 @@ _Py_parse_inf_or_nan(const char *p, char **endptr) s += 3; if (case_insensitive_match(s, "inity")) s += 5; - retval = negate ? -Py_INFINITY : Py_INFINITY; + retval = negate ? -INFINITY : INFINITY; } else if (case_insensitive_match(s, "nan")) { s += 3; @@ -286,7 +286,7 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) string, -1.0 is returned and again ValueError is raised. On overflow (e.g., when trying to convert '1e500' on an IEEE 754 machine), - if overflow_exception is NULL then +-Py_INFINITY is returned, and no Python + if overflow_exception is NULL then +-INFINITY is returned, and no Python exception is raised. Otherwise, overflow_exception should point to a Python exception, this exception will be raised, -1.0 will be returned, and *endptr will point just past the end of the converted value. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 45211e1b075..f2c402eb1a0 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -478,9 +478,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, if (PyDict_SetItemString(dict, "__file__", filename) < 0) { goto done; } - if (PyDict_SetItemString(dict, "__cached__", Py_None) < 0) { - goto done; - } set_file_name = 1; } @@ -535,9 +532,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, if (PyDict_PopString(dict, "__file__", NULL) < 0) { PyErr_Print(); } - if (PyDict_PopString(dict, "__cached__", NULL) < 0) { - PyErr_Print(); - } } Py_XDECREF(main_module); return ret; @@ -1181,7 +1175,7 @@ fallback: } if (print_exception_recursive(&ctx, value) < 0) { PyErr_Clear(); - _PyObject_Dump(value); + PyUnstable_Object_Dump(value); fprintf(stderr, "lost sys.stderr\n"); } Py_XDECREF(ctx.seen); @@ -1199,14 +1193,14 @@ PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) PyObject *file; if (PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) { PyObject *exc = PyErr_GetRaisedException(); - _PyObject_Dump(value); + PyUnstable_Object_Dump(value); fprintf(stderr, "lost sys.stderr\n"); - _PyObject_Dump(exc); + PyUnstable_Object_Dump(exc); Py_DECREF(exc); return; } if (file == NULL) { - _PyObject_Dump(value); + PyUnstable_Object_Dump(value); fprintf(stderr, "lost sys.stderr\n"); return; } @@ -1252,12 +1246,19 @@ _PyRun_StringFlagsWithName(const char *str, PyObject* name, int start, } else { name = &_Py_STR(anon_string); } + PyObject *module = NULL; + if (globals && PyDict_GetItemStringRef(globals, "__name__", &module) < 0) { + goto done; + } - mod = _PyParser_ASTFromString(str, name, start, flags, arena); + mod = _PyParser_ASTFromString(str, name, start, flags, arena, module); + Py_XDECREF(module); - if (mod != NULL) { + if (mod != NULL) { ret = run_mod(mod, name, globals, locals, flags, arena, source, generate_new_source); } + +done: Py_XDECREF(source); _PyArena_Free(arena); return ret; @@ -1407,8 +1408,17 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, return NULL; } } + PyObject *module = NULL; + if (globals && PyDict_GetItemStringRef(globals, "__name__", &module) < 0) { + if (interactive_src) { + Py_DECREF(interactive_filename); + } + return NULL; + } - PyCodeObject *co = _PyAST_Compile(mod, interactive_filename, flags, -1, arena); + PyCodeObject *co = _PyAST_Compile(mod, interactive_filename, flags, -1, + arena, module); + Py_XDECREF(module); if (co == NULL) { if (interactive_src) { Py_DECREF(interactive_filename); @@ -1507,6 +1517,14 @@ error: PyObject * Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize) +{ + return _Py_CompileStringObjectWithModule(str, filename, start, + flags, optimize, NULL); +} + +PyObject * +_Py_CompileStringObjectWithModule(const char *str, PyObject *filename, int start, + PyCompilerFlags *flags, int optimize, PyObject *module) { PyCodeObject *co; mod_ty mod; @@ -1514,14 +1532,16 @@ Py_CompileStringObject(const char *str, PyObject *filename, int start, if (arena == NULL) return NULL; - mod = _PyParser_ASTFromString(str, filename, start, flags, arena); + mod = _PyParser_ASTFromString(str, filename, start, flags, arena, module); if (mod == NULL) { _PyArena_Free(arena); return NULL; } if (flags && (flags->cf_flags & PyCF_ONLY_AST)) { int syntax_check_only = ((flags->cf_flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST); /* unoptiomized AST */ - if (_PyCompile_AstPreprocess(mod, filename, flags, optimize, arena, syntax_check_only) < 0) { + if (_PyCompile_AstPreprocess(mod, filename, flags, optimize, arena, + syntax_check_only, module) < 0) + { _PyArena_Free(arena); return NULL; } @@ -1529,7 +1549,7 @@ Py_CompileStringObject(const char *str, PyObject *filename, int start, _PyArena_Free(arena); return result; } - co = _PyAST_Compile(mod, filename, flags, optimize, arena); + co = _PyAST_Compile(mod, filename, flags, optimize, arena, module); _PyArena_Free(arena); return (PyObject *)co; } diff --git a/Python/pytime.c b/Python/pytime.c index 67cf6437264..2f3d854428b 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -2,7 +2,7 @@ #include "pycore_initconfig.h" // _PyStatus_ERR #include "pycore_pystate.h" // _Py_AssertHoldsTstate() #include "pycore_runtime.h" // _PyRuntime -#include "pycore_time.h" // PyTime_t +#include "pycore_time.h" // export _PyLong_FromTime_t() #include <time.h> // gmtime_r() #ifdef HAVE_SYS_TIME_H @@ -368,8 +368,20 @@ pytime_object_to_denominator(PyObject *obj, time_t *sec, long *numerator, { assert(denominator >= 1); - if (PyFloat_Check(obj)) { + if (PyIndex_Check(obj)) { + *sec = _PyLong_AsTime_t(obj); + *numerator = 0; + if (*sec == (time_t)-1 && PyErr_Occurred()) { + return -1; + } + return 0; + } + else { double d = PyFloat_AsDouble(obj); + if (d == -1 && PyErr_Occurred()) { + *numerator = 0; + return -1; + } if (isnan(d)) { *numerator = 0; PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); @@ -378,30 +390,28 @@ pytime_object_to_denominator(PyObject *obj, time_t *sec, long *numerator, return pytime_double_to_denominator(d, sec, numerator, denominator, round); } - else { - *sec = _PyLong_AsTime_t(obj); - *numerator = 0; - if (*sec == (time_t)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Format(PyExc_TypeError, - "argument must be int or float, not %T", obj); - } - return -1; - } - return 0; - } } int _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) { - if (PyFloat_Check(obj)) { + if (PyIndex_Check(obj)) { + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) { + return -1; + } + return 0; + } + else { double intpart; /* volatile avoids optimization changing how numbers are rounded */ volatile double d; d = PyFloat_AsDouble(obj); + if (d == -1 && PyErr_Occurred()) { + return -1; + } if (isnan(d)) { PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); return -1; @@ -418,13 +428,6 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) *sec = (time_t)intpart; return 0; } - else { - *sec = _PyLong_AsTime_t(obj); - if (*sec == (time_t)-1 && PyErr_Occurred()) { - return -1; - } - return 0; - } } @@ -469,31 +472,6 @@ _PyTime_FromMicrosecondsClamp(PyTime_t us) } -int -_PyTime_FromLong(PyTime_t *tp, PyObject *obj) -{ - if (!PyLong_Check(obj)) { - PyErr_Format(PyExc_TypeError, "expect int, got %s", - Py_TYPE(obj)->tp_name); - return -1; - } - - static_assert(sizeof(long long) == sizeof(PyTime_t), - "PyTime_t is not long long"); - long long nsec = PyLong_AsLongLong(obj); - if (nsec == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - pytime_overflow(); - } - return -1; - } - - PyTime_t t = (PyTime_t)nsec; - *tp = t; - return 0; -} - - #ifdef HAVE_CLOCK_GETTIME static int pytime_fromtimespec(PyTime_t *tp, const struct timespec *ts, int raise_exc) @@ -586,39 +564,38 @@ static int pytime_from_object(PyTime_t *tp, PyObject *obj, _PyTime_round_t round, long unit_to_ns) { - if (PyFloat_Check(obj)) { + if (PyIndex_Check(obj)) { + long long sec = PyLong_AsLongLong(obj); + if (sec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + pytime_overflow(); + } + return -1; + } + + static_assert(sizeof(long long) <= sizeof(PyTime_t), + "PyTime_t is smaller than long long"); + PyTime_t ns = (PyTime_t)sec; + if (pytime_mul(&ns, unit_to_ns) < 0) { + pytime_overflow(); + return -1; + } + + *tp = ns; + return 0; + } + else { double d; d = PyFloat_AsDouble(obj); + if (d == -1 && PyErr_Occurred()) { + return -1; + } if (isnan(d)) { PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); return -1; } return pytime_from_double(tp, d, round, unit_to_ns); } - - long long sec = PyLong_AsLongLong(obj); - if (sec == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - pytime_overflow(); - } - else if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Format(PyExc_TypeError, - "'%T' object cannot be interpreted as an integer or float", - obj); - } - return -1; - } - - static_assert(sizeof(long long) <= sizeof(PyTime_t), - "PyTime_t is smaller than long long"); - PyTime_t ns = (PyTime_t)sec; - if (pytime_mul(&ns, unit_to_ns) < 0) { - pytime_overflow(); - return -1; - } - - *tp = ns; - return 0; } @@ -656,14 +633,6 @@ PyTime_AsSecondsDouble(PyTime_t ns) } -PyObject * -_PyTime_AsLong(PyTime_t ns) -{ - static_assert(sizeof(long long) >= sizeof(PyTime_t), - "PyTime_t is larger than long long"); - return PyLong_FromLongLong((long long)ns); -} - int _PyTime_FromSecondsDouble(double seconds, _PyTime_round_t round, PyTime_t *result) { diff --git a/Python/qsbr.c b/Python/qsbr.c index c992c285cb1..6bf5b75f346 100644 --- a/Python/qsbr.c +++ b/Python/qsbr.c @@ -36,6 +36,7 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_qsbr.h" #include "pycore_tstate.h" // _PyThreadStateImpl +#include "pycore_stats.h" // FT_STAT_QSBR_POLL_INC() // Starting size of the array of qsbr thread states @@ -56,7 +57,7 @@ qsbr_allocate(struct _qsbr_shared *shared) return qsbr; } -// Initialize (or reintialize) the freelist of QSBR thread states +// Initialize (or reinitialize) the freelist of QSBR thread states static void initialize_new_array(struct _qsbr_shared *shared) { @@ -158,7 +159,7 @@ _Py_qsbr_poll(struct _qsbr_thread_state *qsbr, uint64_t goal) if (_Py_qbsr_goal_reached(qsbr, goal)) { return true; } - + FT_STAT_QSBR_POLL_INC(); uint64_t rd_seq = qsbr_poll_scan(qsbr->shared); return QSBR_LEQ(goal, rd_seq); } diff --git a/Python/remote_debug.h b/Python/remote_debug.h index d920d9e5b5f..d3932a3fd1e 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -158,7 +158,7 @@ static mach_port_t pid_to_task(pid_t pid); #endif // Initialize the process handle -static int +UNUSED static int _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) { handle->pid = pid; #if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX @@ -188,7 +188,7 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) { } // Clean up the process handle -static void +UNUSED static void _Py_RemoteDebug_CleanupProcHandle(proc_handle_t *handle) { #ifdef MS_WINDOWS if (handle->hProcess != NULL) { @@ -722,6 +722,11 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c } const char *path = line + path_pos; + if (path[0] == '[' && path[strlen(path)-1] == ']') { + // Skip [heap], [stack], [anon:cpython:pymalloc], etc. + continue; + } + const char *filename = strrchr(path, '/'); if (filename) { filename++; // Move past the '/' @@ -875,7 +880,7 @@ search_windows_map_for_section(proc_handle_t* handle, const char* secname, const #endif // MS_WINDOWS // Get the PyRuntime section address for any platform -static uintptr_t +UNUSED static uintptr_t _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle) { uintptr_t address; @@ -891,7 +896,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle) handle->pid); _PyErr_ChainExceptions1(exc); } -#elif defined(__linux__) +#elif defined(__linux__) && HAVE_PROCESS_VM_READV // On Linux, search for 'python' in executable or DLL address = search_linux_map_for_section(handle, "PyRuntime", "python"); if (address == 0) { @@ -1102,6 +1107,115 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address #endif } +#if defined(__linux__) && HAVE_PROCESS_VM_READV +// Fallback write using /proc/pid/mem +static int +_Py_RemoteDebug_WriteRemoteMemoryFallback(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) +{ + if (handle->memfd == -1) { + if (open_proc_mem_fd(handle) < 0) { + return -1; + } + } + + struct iovec local[1]; + Py_ssize_t result = 0; + Py_ssize_t written = 0; + + do { + local[0].iov_base = (char*)src + result; + local[0].iov_len = len - result; + off_t offset = remote_address + result; + + written = pwritev(handle->memfd, local, 1, offset); + if (written < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + result += written; + } while ((size_t)written != local[0].iov_len); + return 0; +} +#endif // __linux__ + +// Platform-independent memory write function +UNUSED static int +_Py_RemoteDebug_WriteRemoteMemory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) +{ +#ifdef MS_WINDOWS + SIZE_T written = 0; + SIZE_T result = 0; + do { + if (!WriteProcessMemory(handle->hProcess, (LPVOID)(remote_address + result), (const char*)src + result, len - result, &written)) { + PyErr_SetFromWindowsErr(0); + DWORD error = GetLastError(); + _set_debug_exception_cause(PyExc_OSError, + "WriteProcessMemory failed for PID %d at address 0x%lx " + "(size %zu, partial write %zu bytes): Windows error %lu", + handle->pid, remote_address + result, len - result, result, error); + return -1; + } + result += written; + } while (result < len); + return 0; +#elif defined(__linux__) && HAVE_PROCESS_VM_READV + if (handle->memfd != -1) { + return _Py_RemoteDebug_WriteRemoteMemoryFallback(handle, remote_address, len, src); + } + struct iovec local[1]; + struct iovec remote[1]; + Py_ssize_t result = 0; + Py_ssize_t written = 0; + + do { + local[0].iov_base = (void*)((char*)src + result); + local[0].iov_len = len - result; + remote[0].iov_base = (void*)((char*)remote_address + result); + remote[0].iov_len = len - result; + + written = process_vm_writev(handle->pid, local, 1, remote, 1, 0); + if (written < 0) { + if (errno == ENOSYS) { + return _Py_RemoteDebug_WriteRemoteMemoryFallback(handle, remote_address, len, src); + } + PyErr_SetFromErrno(PyExc_OSError); + _set_debug_exception_cause(PyExc_OSError, + "process_vm_writev failed for PID %d at address 0x%lx " + "(size %zu, partial write %zd bytes): %s", + handle->pid, remote_address + result, len - result, result, strerror(errno)); + return -1; + } + + result += written; + } while ((size_t)written != local[0].iov_len); + return 0; +#elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX + kern_return_t kr = mach_vm_write( + handle->task, + (mach_vm_address_t)remote_address, + (vm_offset_t)src, + (mach_msg_type_number_t)len); + + if (kr != KERN_SUCCESS) { + switch (kr) { + case KERN_PROTECTION_FAILURE: + PyErr_SetString(PyExc_PermissionError, "Not enough permissions to write memory"); + break; + case KERN_INVALID_ARGUMENT: + PyErr_SetString(PyExc_PermissionError, "Invalid argument to mach_vm_write"); + break; + default: + PyErr_Format(PyExc_RuntimeError, "Unknown error writing memory: %d", (int)kr); + } + return -1; + } + return 0; +#else + Py_UNREACHABLE(); +#endif +} + UNUSED static int _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle, uintptr_t addr, @@ -1158,7 +1272,7 @@ fallback: return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out); } -static int +UNUSED static int _Py_RemoteDebug_ReadDebugOffsets( proc_handle_t *handle, uintptr_t *runtime_start_address, diff --git a/Python/remote_debugging.c b/Python/remote_debugging.c index 7aee87ef05a..5b50b95db94 100644 --- a/Python/remote_debugging.c +++ b/Python/remote_debugging.c @@ -19,109 +19,16 @@ cleanup_proc_handle(proc_handle_t *handle) { } static int -read_memory(proc_handle_t *handle, uint64_t remote_address, size_t len, void* dst) +read_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, void* dst) { return _Py_RemoteDebug_ReadRemoteMemory(handle, remote_address, len, dst); } -// Why is pwritev not guarded? Except on Android API level 23 (no longer -// supported), HAVE_PROCESS_VM_READV is sufficient. -#if defined(__linux__) && HAVE_PROCESS_VM_READV -static int -write_memory_fallback(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) -{ - if (handle->memfd == -1) { - if (open_proc_mem_fd(handle) < 0) { - return -1; - } - } - - struct iovec local[1]; - Py_ssize_t result = 0; - Py_ssize_t written = 0; - - do { - local[0].iov_base = (char*)src + result; - local[0].iov_len = len - result; - off_t offset = remote_address + result; - - written = pwritev(handle->memfd, local, 1, offset); - if (written < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return -1; - } - - result += written; - } while ((size_t)written != local[0].iov_len); - return 0; -} -#endif // __linux__ - +// Use the shared write function from remote_debug.h static int write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src) { -#ifdef MS_WINDOWS - SIZE_T written = 0; - SIZE_T result = 0; - do { - if (!WriteProcessMemory(handle->hProcess, (LPVOID)(remote_address + result), (const char*)src + result, len - result, &written)) { - PyErr_SetFromWindowsErr(0); - return -1; - } - result += written; - } while (result < len); - return 0; -#elif defined(__linux__) && HAVE_PROCESS_VM_READV - if (handle->memfd != -1) { - return write_memory_fallback(handle, remote_address, len, src); - } - struct iovec local[1]; - struct iovec remote[1]; - Py_ssize_t result = 0; - Py_ssize_t written = 0; - - do { - local[0].iov_base = (void*)((char*)src + result); - local[0].iov_len = len - result; - remote[0].iov_base = (void*)((char*)remote_address + result); - remote[0].iov_len = len - result; - - written = process_vm_writev(handle->pid, local, 1, remote, 1, 0); - if (written < 0) { - if (errno == ENOSYS) { - return write_memory_fallback(handle, remote_address, len, src); - } - PyErr_SetFromErrno(PyExc_OSError); - return -1; - } - - result += written; - } while ((size_t)written != local[0].iov_len); - return 0; -#elif defined(__APPLE__) && TARGET_OS_OSX - kern_return_t kr = mach_vm_write( - pid_to_task(handle->pid), - (mach_vm_address_t)remote_address, - (vm_offset_t)src, - (mach_msg_type_number_t)len); - - if (kr != KERN_SUCCESS) { - switch (kr) { - case KERN_PROTECTION_FAILURE: - PyErr_SetString(PyExc_PermissionError, "Not enough permissions to write memory"); - break; - case KERN_INVALID_ARGUMENT: - PyErr_SetString(PyExc_PermissionError, "Invalid argument to mach_vm_write"); - break; - default: - PyErr_Format(PyExc_RuntimeError, "Unknown error writing memory: %d", (int)kr); - } - return -1; - } - return 0; -#else - Py_UNREACHABLE(); -#endif + return _Py_RemoteDebug_WriteRemoteMemory(handle, remote_address, len, src); } static int @@ -235,7 +142,7 @@ send_exec_to_proc_handle(proc_handle_t *handle, int tid, const char *debugger_sc int is_remote_debugging_enabled = 0; if (0 != read_memory( handle, - interpreter_state_addr + debug_offsets.debugger_support.remote_debugging_enabled, + interpreter_state_addr + (uintptr_t)debug_offsets.debugger_support.remote_debugging_enabled, sizeof(int), &is_remote_debugging_enabled)) { @@ -255,7 +162,7 @@ send_exec_to_proc_handle(proc_handle_t *handle, int tid, const char *debugger_sc if (tid != 0) { if (0 != read_memory( handle, - interpreter_state_addr + debug_offsets.interpreter_state.threads_head, + interpreter_state_addr + (uintptr_t)debug_offsets.interpreter_state.threads_head, sizeof(void*), &thread_state_addr)) { @@ -264,7 +171,7 @@ send_exec_to_proc_handle(proc_handle_t *handle, int tid, const char *debugger_sc while (thread_state_addr != 0) { if (0 != read_memory( handle, - thread_state_addr + debug_offsets.thread_state.native_thread_id, + thread_state_addr + (uintptr_t)debug_offsets.thread_state.native_thread_id, sizeof(this_tid), &this_tid)) { @@ -277,7 +184,7 @@ send_exec_to_proc_handle(proc_handle_t *handle, int tid, const char *debugger_sc if (0 != read_memory( handle, - thread_state_addr + debug_offsets.thread_state.next, + thread_state_addr + (uintptr_t)debug_offsets.thread_state.next, sizeof(void*), &thread_state_addr)) { @@ -294,7 +201,7 @@ send_exec_to_proc_handle(proc_handle_t *handle, int tid, const char *debugger_sc } else { if (0 != read_memory( handle, - interpreter_state_addr + debug_offsets.interpreter_state.threads_main, + interpreter_state_addr + (uintptr_t)debug_offsets.interpreter_state.threads_main, sizeof(void*), &thread_state_addr)) { @@ -346,7 +253,7 @@ send_exec_to_proc_handle(proc_handle_t *handle, int tid, const char *debugger_sc uintptr_t eval_breaker; if (0 != read_memory( handle, - thread_state_addr + debug_offsets.debugger_support.eval_breaker, + thread_state_addr + (uintptr_t)debug_offsets.debugger_support.eval_breaker, sizeof(uintptr_t), &eval_breaker)) { diff --git a/Python/specialize.c b/Python/specialize.c index 38df5741f32..19433bc7a74 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -22,437 +22,23 @@ #include <stdlib.h> // rand() -extern const char *_PyUOpName(int index); - /* For guidance on adding or extending families of instructions see * InternalDocs/interpreter.md `Specialization` section. */ -#ifdef Py_STATS -GCStats _py_gc_stats[NUM_GENERATIONS] = { 0 }; -static PyStats _Py_stats_struct = { .gc_stats = _py_gc_stats }; -PyStats *_Py_stats = NULL; - -#if PYSTATS_MAX_UOP_ID < MAX_UOP_ID -#error "Not enough space allocated for pystats. Increase PYSTATS_MAX_UOP_ID to at least MAX_UOP_ID" -#endif - -#define ADD_STAT_TO_DICT(res, field) \ - do { \ - PyObject *val = PyLong_FromUnsignedLongLong(stats->field); \ - if (val == NULL) { \ - Py_DECREF(res); \ - return NULL; \ - } \ - if (PyDict_SetItemString(res, #field, val) == -1) { \ - Py_DECREF(res); \ - Py_DECREF(val); \ - return NULL; \ - } \ - Py_DECREF(val); \ - } while(0); - -static PyObject* -stats_to_dict(SpecializationStats *stats) -{ - PyObject *res = PyDict_New(); - if (res == NULL) { - return NULL; - } - ADD_STAT_TO_DICT(res, success); - ADD_STAT_TO_DICT(res, failure); - ADD_STAT_TO_DICT(res, hit); - ADD_STAT_TO_DICT(res, deferred); - ADD_STAT_TO_DICT(res, miss); - ADD_STAT_TO_DICT(res, deopt); - PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS); - if (failure_kinds == NULL) { - Py_DECREF(res); - return NULL; - } - for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) { - PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]); - if (stat == NULL) { - Py_DECREF(res); - Py_DECREF(failure_kinds); - return NULL; - } - PyTuple_SET_ITEM(failure_kinds, i, stat); - } - if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) { - Py_DECREF(res); - Py_DECREF(failure_kinds); - return NULL; - } - Py_DECREF(failure_kinds); - return res; -} -#undef ADD_STAT_TO_DICT - -static int -add_stat_dict( - PyObject *res, - int opcode, - const char *name) { - - SpecializationStats *stats = &_Py_stats_struct.opcode_stats[opcode].specialization; - PyObject *d = stats_to_dict(stats); - if (d == NULL) { - return -1; - } - int err = PyDict_SetItemString(res, name, d); - Py_DECREF(d); - return err; -} - -PyObject* -_Py_GetSpecializationStats(void) { - PyObject *stats = PyDict_New(); - if (stats == NULL) { - return NULL; - } - int err = 0; - err += add_stat_dict(stats, CONTAINS_OP, "contains_op"); - err += add_stat_dict(stats, LOAD_SUPER_ATTR, "load_super_attr"); - err += add_stat_dict(stats, LOAD_ATTR, "load_attr"); - err += add_stat_dict(stats, LOAD_GLOBAL, "load_global"); - err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr"); - err += add_stat_dict(stats, STORE_ATTR, "store_attr"); - err += add_stat_dict(stats, JUMP_BACKWARD, "jump_backward"); - err += add_stat_dict(stats, CALL, "call"); - err += add_stat_dict(stats, CALL_KW, "call_kw"); - err += add_stat_dict(stats, BINARY_OP, "binary_op"); - err += add_stat_dict(stats, COMPARE_OP, "compare_op"); - err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence"); - err += add_stat_dict(stats, FOR_ITER, "for_iter"); - err += add_stat_dict(stats, TO_BOOL, "to_bool"); - err += add_stat_dict(stats, SEND, "send"); - if (err < 0) { - Py_DECREF(stats); - return NULL; - } - return stats; -} - - -#define PRINT_STAT(i, field) \ - if (stats[i].field) { \ - fprintf(out, " opcode[%s]." #field " : %" PRIu64 "\n", _PyOpcode_OpName[i], stats[i].field); \ - } - -static void -print_spec_stats(FILE *out, OpcodeStats *stats) -{ - /* Mark some opcodes as specializable for stats, - * even though we don't specialize them yet. */ - fprintf(out, "opcode[BINARY_SLICE].specializable : 1\n"); - fprintf(out, "opcode[STORE_SLICE].specializable : 1\n"); - fprintf(out, "opcode[GET_ITER].specializable : 1\n"); - for (int i = 0; i < 256; i++) { - if (_PyOpcode_Caches[i]) { - /* Ignore jumps as they cannot be specialized */ - switch (i) { - case POP_JUMP_IF_FALSE: - case POP_JUMP_IF_TRUE: - case POP_JUMP_IF_NONE: - case POP_JUMP_IF_NOT_NONE: - case JUMP_BACKWARD: - break; - default: - fprintf(out, "opcode[%s].specializable : 1\n", _PyOpcode_OpName[i]); - } - } - PRINT_STAT(i, specialization.success); - PRINT_STAT(i, specialization.failure); - PRINT_STAT(i, specialization.hit); - PRINT_STAT(i, specialization.deferred); - PRINT_STAT(i, specialization.miss); - PRINT_STAT(i, specialization.deopt); - PRINT_STAT(i, execution_count); - for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) { - uint64_t val = stats[i].specialization.failure_kinds[j]; - if (val) { - fprintf(out, " opcode[%s].specialization.failure_kinds[%d] : %" - PRIu64 "\n", _PyOpcode_OpName[i], j, val); - } - } - for (int j = 0; j < 256; j++) { - if (stats[i].pair_count[j]) { - fprintf(out, "opcode[%s].pair_count[%s] : %" PRIu64 "\n", - _PyOpcode_OpName[i], _PyOpcode_OpName[j], stats[i].pair_count[j]); - } - } - } -} -#undef PRINT_STAT - - -static void -print_call_stats(FILE *out, CallStats *stats) -{ - fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls); - fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls); - fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed); - fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created); - for (int i = 0; i < EVAL_CALL_KINDS; i++) { - fprintf(out, "Calls via PyEval_EvalFrame[%d] : %" PRIu64 "\n", i, stats->eval_calls[i]); - } -} - -static void -print_object_stats(FILE *out, ObjectStats *stats) -{ - fprintf(out, "Object allocations from freelist: %" PRIu64 "\n", stats->from_freelist); - fprintf(out, "Object frees to freelist: %" PRIu64 "\n", stats->to_freelist); - fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations); - fprintf(out, "Object allocations to 512 bytes: %" PRIu64 "\n", stats->allocations512); - fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k); - fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big); - fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees); - fprintf(out, "Object inline values: %" PRIu64 "\n", stats->inline_values); - fprintf(out, "Object interpreter mortal increfs: %" PRIu64 "\n", stats->interpreter_increfs); - fprintf(out, "Object interpreter mortal decrefs: %" PRIu64 "\n", stats->interpreter_decrefs); - fprintf(out, "Object mortal increfs: %" PRIu64 "\n", stats->increfs); - fprintf(out, "Object mortal decrefs: %" PRIu64 "\n", stats->decrefs); - fprintf(out, "Object interpreter immortal increfs: %" PRIu64 "\n", stats->interpreter_immortal_increfs); - fprintf(out, "Object interpreter immortal decrefs: %" PRIu64 "\n", stats->interpreter_immortal_decrefs); - fprintf(out, "Object immortal increfs: %" PRIu64 "\n", stats->immortal_increfs); - fprintf(out, "Object immortal decrefs: %" PRIu64 "\n", stats->immortal_decrefs); - fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request); - fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); - fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); - fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass); - fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits); - fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses); - fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); - fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits); - fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses); -} - -static void -print_gc_stats(FILE *out, GCStats *stats) -{ - for (int i = 0; i < NUM_GENERATIONS; i++) { - fprintf(out, "GC[%d] collections: %" PRIu64 "\n", i, stats[i].collections); - fprintf(out, "GC[%d] object visits: %" PRIu64 "\n", i, stats[i].object_visits); - fprintf(out, "GC[%d] objects collected: %" PRIu64 "\n", i, stats[i].objects_collected); - fprintf(out, "GC[%d] objects reachable from roots: %" PRIu64 "\n", i, stats[i].objects_transitively_reachable); - fprintf(out, "GC[%d] objects not reachable from roots: %" PRIu64 "\n", i, stats[i].objects_not_transitively_reachable); - } -} - -#ifdef _Py_TIER2 -static void -print_histogram(FILE *out, const char *name, uint64_t hist[_Py_UOP_HIST_SIZE]) -{ - for (int i = 0; i < _Py_UOP_HIST_SIZE; i++) { - fprintf(out, "%s[%" PRIu64"]: %" PRIu64 "\n", name, (uint64_t)1 << i, hist[i]); - } -} - -static void -print_optimization_stats(FILE *out, OptimizationStats *stats) -{ - fprintf(out, "Optimization attempts: %" PRIu64 "\n", stats->attempts); - fprintf(out, "Optimization traces created: %" PRIu64 "\n", stats->traces_created); - fprintf(out, "Optimization traces executed: %" PRIu64 "\n", stats->traces_executed); - fprintf(out, "Optimization uops executed: %" PRIu64 "\n", stats->uops_executed); - fprintf(out, "Optimization trace stack overflow: %" PRIu64 "\n", stats->trace_stack_overflow); - fprintf(out, "Optimization trace stack underflow: %" PRIu64 "\n", stats->trace_stack_underflow); - fprintf(out, "Optimization trace too long: %" PRIu64 "\n", stats->trace_too_long); - fprintf(out, "Optimization trace too short: %" PRIu64 "\n", stats->trace_too_short); - fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop); - fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call); - fprintf(out, "Optimization low confidence: %" PRIu64 "\n", stats->low_confidence); - fprintf(out, "Optimization unknown callee: %" PRIu64 "\n", stats->unknown_callee); - fprintf(out, "Executors invalidated: %" PRIu64 "\n", stats->executors_invalidated); - - print_histogram(out, "Trace length", stats->trace_length_hist); - print_histogram(out, "Trace run length", stats->trace_run_length_hist); - print_histogram(out, "Optimized trace length", stats->optimized_trace_length_hist); - - fprintf(out, "Optimization optimizer attempts: %" PRIu64 "\n", stats->optimizer_attempts); - fprintf(out, "Optimization optimizer successes: %" PRIu64 "\n", stats->optimizer_successes); - fprintf(out, "Optimization optimizer failure no memory: %" PRIu64 "\n", - stats->optimizer_failure_reason_no_memory); - fprintf(out, "Optimizer remove globals builtins changed: %" PRIu64 "\n", stats->remove_globals_builtins_changed); - fprintf(out, "Optimizer remove globals incorrect keys: %" PRIu64 "\n", stats->remove_globals_incorrect_keys); - for (int i = 0; i <= MAX_UOP_ID; i++) { - if (stats->opcode[i].execution_count) { - fprintf(out, "uops[%s].execution_count : %" PRIu64 "\n", _PyUOpName(i), stats->opcode[i].execution_count); - } - if (stats->opcode[i].miss) { - fprintf(out, "uops[%s].specialization.miss : %" PRIu64 "\n", _PyUOpName(i), stats->opcode[i].miss); - } - } - for (int i = 0; i < 256; i++) { - if (stats->unsupported_opcode[i]) { - fprintf( - out, - "unsupported_opcode[%s].count : %" PRIu64 "\n", - _PyOpcode_OpName[i], - stats->unsupported_opcode[i] - ); - } - } - - for (int i = 1; i <= MAX_UOP_ID; i++){ - for (int j = 1; j <= MAX_UOP_ID; j++) { - if (stats->opcode[i].pair_count[j]) { - fprintf(out, "uop[%s].pair_count[%s] : %" PRIu64 "\n", - _PyOpcode_uop_name[i], _PyOpcode_uop_name[j], stats->opcode[i].pair_count[j]); - } - } - } - for (int i = 0; i < MAX_UOP_ID; i++) { - if (stats->error_in_opcode[i]) { - fprintf( - out, - "error_in_opcode[%s].count : %" PRIu64 "\n", - _PyUOpName(i), - stats->error_in_opcode[i] - ); - } - } - fprintf(out, "JIT total memory size: %" PRIu64 "\n", stats->jit_total_memory_size); - fprintf(out, "JIT code size: %" PRIu64 "\n", stats->jit_code_size); - fprintf(out, "JIT trampoline size: %" PRIu64 "\n", stats->jit_trampoline_size); - fprintf(out, "JIT data size: %" PRIu64 "\n", stats->jit_data_size); - fprintf(out, "JIT padding size: %" PRIu64 "\n", stats->jit_padding_size); - fprintf(out, "JIT freed memory size: %" PRIu64 "\n", stats->jit_freed_memory_size); - - print_histogram(out, "Trace total memory size", stats->trace_total_memory_hist); -} -#endif - -static void -print_rare_event_stats(FILE *out, RareEventStats *stats) -{ - fprintf(out, "Rare event (set_class): %" PRIu64 "\n", stats->set_class); - fprintf(out, "Rare event (set_bases): %" PRIu64 "\n", stats->set_bases); - fprintf(out, "Rare event (set_eval_frame_func): %" PRIu64 "\n", stats->set_eval_frame_func); - fprintf(out, "Rare event (builtin_dict): %" PRIu64 "\n", stats->builtin_dict); - fprintf(out, "Rare event (func_modification): %" PRIu64 "\n", stats->func_modification); - fprintf(out, "Rare event (watched_dict_modification): %" PRIu64 "\n", stats->watched_dict_modification); - fprintf(out, "Rare event (watched_globals_modification): %" PRIu64 "\n", stats->watched_globals_modification); -} - -static void -print_stats(FILE *out, PyStats *stats) -{ - print_spec_stats(out, stats->opcode_stats); - print_call_stats(out, &stats->call_stats); - print_object_stats(out, &stats->object_stats); - print_gc_stats(out, stats->gc_stats); -#ifdef _Py_TIER2 - print_optimization_stats(out, &stats->optimization_stats); -#endif - print_rare_event_stats(out, &stats->rare_event_stats); -} - -void -_Py_StatsOn(void) -{ - _Py_stats = &_Py_stats_struct; -} - -void -_Py_StatsOff(void) -{ - _Py_stats = NULL; -} - -void -_Py_StatsClear(void) -{ - memset(&_py_gc_stats, 0, sizeof(_py_gc_stats)); - memset(&_Py_stats_struct, 0, sizeof(_Py_stats_struct)); - _Py_stats_struct.gc_stats = _py_gc_stats; -} - -static int -mem_is_zero(unsigned char *ptr, size_t size) -{ - for (size_t i=0; i < size; i++) { - if (*ptr != 0) { - return 0; - } - ptr++; - } - return 1; -} - -int -_Py_PrintSpecializationStats(int to_file) -{ - PyStats *stats = &_Py_stats_struct; -#define MEM_IS_ZERO(DATA) mem_is_zero((unsigned char*)DATA, sizeof(*(DATA))) - int is_zero = ( - MEM_IS_ZERO(stats->gc_stats) // is a pointer - && MEM_IS_ZERO(&stats->opcode_stats) - && MEM_IS_ZERO(&stats->call_stats) - && MEM_IS_ZERO(&stats->object_stats) - ); -#undef MEM_IS_ZERO - if (is_zero) { - // gh-108753: -X pystats command line was used, but then _stats_off() - // and _stats_clear() have been called: in this case, avoid printing - // useless "all zeros" statistics. - return 0; - } - - FILE *out = stderr; - if (to_file) { - /* Write to a file instead of stderr. */ -# ifdef MS_WINDOWS - const char *dirname = "c:\\temp\\py_stats\\"; -# else - const char *dirname = "/tmp/py_stats/"; -# endif - /* Use random 160 bit number as file name, - * to avoid both accidental collisions and - * symlink attacks. */ - unsigned char rand[20]; - char hex_name[41]; - _PyOS_URandomNonblock(rand, 20); - for (int i = 0; i < 20; i++) { - hex_name[2*i] = Py_hexdigits[rand[i]&15]; - hex_name[2*i+1] = Py_hexdigits[(rand[i]>>4)&15]; - } - hex_name[40] = '\0'; - char buf[64]; - assert(strlen(dirname) + 40 + strlen(".txt") < 64); - sprintf(buf, "%s%s.txt", dirname, hex_name); - FILE *fout = fopen(buf, "w"); - if (fout) { - out = fout; - } - } - else { - fprintf(out, "Specialization stats:\n"); - } - print_stats(out, stats); - if (out != stderr) { - fclose(out); - } - return 1; -} - +#if Py_STATS #define SPECIALIZATION_FAIL(opcode, kind) \ do { \ - if (_Py_stats) { \ + PyStats *s = _PyStats_GET(); \ + if (s) { \ int _kind = (kind); \ assert(_kind < SPECIALIZATION_FAILURE_KINDS); \ - _Py_stats->opcode_stats[opcode].specialization.failure_kinds[_kind]++; \ + s->opcode_stats[opcode].specialization.failure_kinds[_kind]++; \ } \ } while (0) - -#endif // Py_STATS - - -#ifndef SPECIALIZATION_FAIL +#else # define SPECIALIZATION_FAIL(opcode, kind) ((void)0) -#endif +#endif // Py_STATS // Initialize warmup counters and optimize instructions. This cannot fail. void @@ -630,6 +216,7 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters #define SPEC_FAIL_CALL_INIT_NOT_PYTHON 21 #define SPEC_FAIL_CALL_PEP_523 22 #define SPEC_FAIL_CALL_BOUND_METHOD 23 +#define SPEC_FAIL_CALL_VECTORCALL 24 #define SPEC_FAIL_CALL_CLASS_MUTABLE 26 #define SPEC_FAIL_CALL_METHOD_WRAPPER 28 #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 @@ -2015,8 +1602,8 @@ generic: } static int -specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, - int nargs) +specialize_method_descriptor(PyMethodDescrObject *descr, PyObject *self_or_null, + _Py_CODEUNIT *instr, int nargs) { switch (descr->d_method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | @@ -2040,8 +1627,11 @@ specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, bool pop = (next.op.code == POP_TOP); int oparg = instr->op.arg; if ((PyObject *)descr == list_append && oparg == 1 && pop) { - specialize(instr, CALL_LIST_APPEND); - return 0; + assert(self_or_null != NULL); + if (PyList_CheckExact(self_or_null)) { + specialize(instr, CALL_LIST_APPEND); + return 0; + } } specialize(instr, CALL_METHOD_DESCRIPTOR_O); return 0; @@ -2071,6 +1661,10 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523); return -1; } + if (func->vectorcall != _PyFunction_Vectorcall) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_VECTORCALL); + return -1; + } int argcount = -1; if (kind == SPEC_FAIL_CODE_NOT_OPTIMIZED) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CODE_NOT_OPTIMIZED); @@ -2110,6 +1704,10 @@ specialize_py_call_kw(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523); return -1; } + if (func->vectorcall != _PyFunction_Vectorcall) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_VECTORCALL); + return -1; + } if (kind == SPEC_FAIL_CODE_NOT_OPTIMIZED) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CODE_NOT_OPTIMIZED); return -1; @@ -2171,7 +1769,7 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) } Py_NO_INLINE void -_Py_Specialize_Call(_PyStackRef callable_st, _Py_CODEUNIT *instr, int nargs) +_Py_Specialize_Call(_PyStackRef callable_st, _PyStackRef self_or_null_st, _Py_CODEUNIT *instr, int nargs) { PyObject *callable = PyStackRef_AsPyObjectBorrow(callable_st); @@ -2189,7 +1787,9 @@ _Py_Specialize_Call(_PyStackRef callable_st, _Py_CODEUNIT *instr, int nargs) fail = specialize_class_call(callable, instr, nargs); } else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) { - fail = specialize_method_descriptor((PyMethodDescrObject *)callable, instr, nargs); + PyObject *self_or_null = PyStackRef_AsPyObjectBorrow(self_or_null_st); + fail = specialize_method_descriptor((PyMethodDescrObject *)callable, + self_or_null, instr, nargs); } else if (PyMethod_Check(callable)) { PyObject *func = ((PyMethodObject *)callable)->im_func; @@ -2595,7 +2195,7 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in specialize(instr, BINARY_OP_ADD_UNICODE); return; } - if (PyLong_CheckExact(lhs)) { + if (_PyLong_CheckExactAndCompact(lhs) && _PyLong_CheckExactAndCompact(rhs)) { specialize(instr, BINARY_OP_ADD_INT); return; } @@ -2609,7 +2209,7 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { break; } - if (PyLong_CheckExact(lhs)) { + if (_PyLong_CheckExactAndCompact(lhs) && _PyLong_CheckExactAndCompact(rhs)) { specialize(instr, BINARY_OP_MULTIPLY_INT); return; } @@ -2623,7 +2223,7 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { break; } - if (PyLong_CheckExact(lhs)) { + if (_PyLong_CheckExactAndCompact(lhs) && _PyLong_CheckExactAndCompact(rhs)) { specialize(instr, BINARY_OP_SUBTRACT_INT); return; } diff --git a/Python/stackrefs.c b/Python/stackrefs.c index ecc0012ef17..0c13cc65510 100644 --- a/Python/stackrefs.c +++ b/Python/stackrefs.c @@ -19,6 +19,8 @@ typedef struct _table_entry { int linenumber; const char *filename_borrow; int linenumber_borrow; + int borrows; + _PyStackRef borrowed_from; } TableEntry; TableEntry * @@ -34,6 +36,8 @@ make_table_entry(PyObject *obj, const char *filename, int linenumber) result->linenumber = linenumber; result->filename_borrow = NULL; result->linenumber_borrow = 0; + result->borrows = 0; + result->borrowed_from = PyStackRef_NULL; return result; } @@ -47,11 +51,13 @@ _Py_stackref_get_object(_PyStackRef ref) PyInterpreterState *interp = PyInterpreterState_Get(); assert(interp != NULL); if (ref.index >= interp->next_stackref) { - _Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index); + _Py_FatalErrorFormat(__func__, + "Garbled stack ref with ID %" PRIu64 "\n", ref.index); } TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index); if (entry == NULL) { - _Py_FatalErrorFormat(__func__, "Accessing closed stack ref with ID %" PRIu64 "\n", ref.index); + _Py_FatalErrorFormat(__func__, + "Accessing closed stack ref with ID %" PRIu64 "\n", ref.index); } return entry->obj; } @@ -68,13 +74,16 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber) assert(!PyStackRef_IsError(ref)); PyInterpreterState *interp = PyInterpreterState_Get(); if (ref.index >= interp->next_stackref) { - _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", (void *)ref.index, filename, linenumber); - + _Py_FatalErrorFormat(__func__, + "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", + ref.index, filename, linenumber); } PyObject *obj; if (ref.index < INITIAL_STACKREF_INDEX) { if (ref.index == 0) { - _Py_FatalErrorFormat(__func__, "Passing NULL to PyStackRef_CLOSE at %s:%d\n", filename, linenumber); + _Py_FatalErrorFormat(__func__, + "Passing NULL to _Py_stackref_close at %s:%d\n", + filename, linenumber); } // Pre-allocated reference to None, False or True -- Do not clear TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index); @@ -88,10 +97,27 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber) if (entry != NULL) { _Py_FatalErrorFormat(__func__, "Double close of ref ID %" PRIu64 " at %s:%d. Referred to instance of %s at %p. Closed at %s:%d\n", - (void *)ref.index, filename, linenumber, entry->classname, entry->obj, entry->filename, entry->linenumber); + ref.index, filename, linenumber, entry->classname, entry->obj, entry->filename, entry->linenumber); } #endif - _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index); + _Py_FatalErrorFormat(__func__, + "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", + ref.index, filename, linenumber); + } + if (!PyStackRef_IsNull(entry->borrowed_from)) { + _PyStackRef borrowed_from = entry->borrowed_from; + TableEntry *entry_borrowed = _Py_hashtable_get(interp->open_stackrefs_table, (void *)borrowed_from.index); + if (entry_borrowed == NULL) { + _Py_FatalErrorFormat(__func__, + "Invalid borrowed StackRef with ID %" PRIu64 " at %s:%d\n", + borrowed_from.index, filename, linenumber); + } + entry_borrowed->borrows--; + } + if (entry->borrows > 0) { + _Py_FatalErrorFormat(__func__, + "StackRef with ID %" PRIu64 " closed with %d borrowed refs at %s:%d. Opened at %s:%d\n", + ref.index, entry->borrows, filename, linenumber, entry->filename, entry->linenumber); } obj = entry->obj; free(entry); @@ -109,18 +135,19 @@ _Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber) } _PyStackRef -_Py_stackref_create(PyObject *obj, const char *filename, int linenumber) +_Py_stackref_create(PyObject *obj, uint16_t flags, const char *filename, int linenumber) { if (obj == NULL) { Py_FatalError("Cannot create a stackref for NULL"); } PyInterpreterState *interp = PyInterpreterState_Get(); uint64_t new_id = interp->next_stackref; - interp->next_stackref = new_id + 2; + interp->next_stackref = new_id + (1 << Py_TAGGED_SHIFT); TableEntry *entry = make_table_entry(obj, filename, linenumber); if (entry == NULL) { Py_FatalError("No memory left for stackref debug table"); } + new_id |= flags; if (_Py_hashtable_set(interp->open_stackrefs_table, (void *)new_id, entry) < 0) { Py_FatalError("No memory left for stackref debug table"); } @@ -142,15 +169,62 @@ _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber if (entry != NULL) { _Py_FatalErrorFormat(__func__, "Borrow of closed ref ID %" PRIu64 " at %s:%d. Referred to instance of %s at %p. Closed at %s:%d\n", - (void *)ref.index, filename, linenumber, entry->classname, entry->obj, entry->filename, entry->linenumber); + ref.index, filename, linenumber, entry->classname, entry->obj, entry->filename, entry->linenumber); } #endif - _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", (void *)ref.index, filename, linenumber); + _Py_FatalErrorFormat(__func__, + "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", + ref.index, filename, linenumber); } entry->filename_borrow = filename; entry->linenumber_borrow = linenumber; } +_PyStackRef +_Py_stackref_get_borrowed_from(_PyStackRef ref, const char *filename, int linenumber) +{ + assert(!PyStackRef_IsError(ref)); + PyInterpreterState *interp = PyInterpreterState_Get(); + + TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index); + if (entry == NULL) { + _Py_FatalErrorFormat(__func__, + "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", + ref.index, filename, linenumber); + } + + return entry->borrowed_from; +} + +// This function should be used no more than once per ref. +void +_Py_stackref_set_borrowed_from(_PyStackRef ref, _PyStackRef borrowed_from, const char *filename, int linenumber) +{ + assert(!PyStackRef_IsError(ref)); + PyInterpreterState *interp = PyInterpreterState_Get(); + + TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index); + if (entry == NULL) { + _Py_FatalErrorFormat(__func__, + "Invalid StackRef (ref) with ID %" PRIu64 " at %s:%d\n", + ref.index, filename, linenumber); + } + + assert(PyStackRef_IsNull(entry->borrowed_from)); + if (PyStackRef_IsNull(borrowed_from)) { + return; + } + + TableEntry *entry_borrowed = _Py_hashtable_get(interp->open_stackrefs_table, (void *)borrowed_from.index); + if (entry_borrowed == NULL) { + _Py_FatalErrorFormat(__func__, + "Invalid StackRef (borrowed_from) with ID %" PRIu64 " at %s:%d\n", + borrowed_from.index, filename, linenumber); + } + + entry->borrowed_from = borrowed_from; + entry_borrowed->borrows++; +} void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref) @@ -194,16 +268,10 @@ _Py_stackref_report_leaks(PyInterpreterState *interp) } } -void -_PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct, const char *filename, int linenumber) -{ - PyObject *obj = _Py_stackref_close(ref, filename, linenumber); - _Py_DECREF_SPECIALIZED(obj, destruct); -} - _PyStackRef PyStackRef_TagInt(intptr_t i) { - return (_PyStackRef){ .index = (i << 1) + 1 }; + assert(Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (i << Py_TAGGED_SHIFT), Py_TAGGED_SHIFT) == i); + return (_PyStackRef){ .index = (i << Py_TAGGED_SHIFT) | Py_INT_TAG }; } intptr_t @@ -211,7 +279,7 @@ PyStackRef_UntagInt(_PyStackRef i) { assert(PyStackRef_IsTaggedInt(i)); intptr_t val = (intptr_t)i.index; - return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 1); + return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, Py_TAGGED_SHIFT); } bool @@ -223,8 +291,9 @@ PyStackRef_IsNullOrInt(_PyStackRef ref) _PyStackRef PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref) { - assert(ref.index <= INT_MAX - 2); // No overflow - return (_PyStackRef){ .index = ref.index + 2 }; + assert(PyStackRef_IsTaggedInt(ref)); + assert((ref.index & (~Py_TAG_BITS)) != (INTPTR_MAX & (~Py_TAG_BITS))); // Isn't about to overflow + return (_PyStackRef){ .index = ref.index + (1 << Py_TAGGED_SHIFT) }; } diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 47c88839bc8..8937e666bbb 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -51,6 +51,7 @@ static const char* _Py_stdlib_module_names[] = { "_lsprof", "_lzma", "_markupbase", +"_math_integer", "_md5", "_multibytecodec", "_multiprocessing", diff --git a/Python/symtable.c b/Python/symtable.c index bcd7365f8e1..29cf9190a4e 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -3137,7 +3137,7 @@ symtable_raise_if_not_coroutine(struct symtable *st, const char *msg, _Py_Source struct symtable * _Py_SymtableStringObjectFlags(const char *str, PyObject *filename, - int start, PyCompilerFlags *flags) + int start, PyCompilerFlags *flags, PyObject *module) { struct symtable *st; mod_ty mod; @@ -3147,7 +3147,7 @@ _Py_SymtableStringObjectFlags(const char *str, PyObject *filename, if (arena == NULL) return NULL; - mod = _PyParser_ASTFromString(str, filename, start, flags, arena); + mod = _PyParser_ASTFromString(str, filename, start, flags, arena, module); if (mod == NULL) { _PyArena_Free(arena); return NULL; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cc798f6ae5c..94eb3164eca 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -610,7 +610,7 @@ sys_breakpointhook(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyOb if (last_dot == NULL) { /* The breakpoint is a built-in, e.g. PYTHONBREAKPOINT=int */ - modulepath = PyUnicode_FromString("builtins"); + modulepath = &_Py_ID(builtins); attrname = envar; } else if (last_dot != envar) { @@ -1587,10 +1587,10 @@ get_hash_info(PyThreadState *tstate) } while(0) SET_HASH_INFO_ITEM(PyLong_FromLong(8 * sizeof(Py_hash_t))); - SET_HASH_INFO_ITEM(PyLong_FromSsize_t(_PyHASH_MODULUS)); - SET_HASH_INFO_ITEM(PyLong_FromLong(_PyHASH_INF)); + SET_HASH_INFO_ITEM(PyLong_FromSsize_t(PyHASH_MODULUS)); + SET_HASH_INFO_ITEM(PyLong_FromLong(PyHASH_INF)); SET_HASH_INFO_ITEM(PyLong_FromLong(0)); // This is no longer used - SET_HASH_INFO_ITEM(PyLong_FromLong(_PyHASH_IMAG)); + SET_HASH_INFO_ITEM(PyLong_FromLong(PyHASH_IMAG)); SET_HASH_INFO_ITEM(PyUnicode_FromString(hashfunc->name)); SET_HASH_INFO_ITEM(PyLong_FromLong(hashfunc->hash_bits)); SET_HASH_INFO_ITEM(PyLong_FromLong(hashfunc->seed_bits)); @@ -2281,7 +2281,9 @@ static PyObject * sys__stats_on_impl(PyObject *module) /*[clinic end generated code: output=aca53eafcbb4d9fe input=43b5bfe145299e55]*/ { - _Py_StatsOn(); + if (_Py_StatsOn() < 0) { + return NULL; + } Py_RETURN_NONE; } @@ -2378,14 +2380,14 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) return NULL; } } - else if (strcmp(backend, "perf_jit") == 0) { - _PyPerf_Callbacks cur_cb; - _PyPerfTrampoline_GetCallbacks(&cur_cb); - if (cur_cb.write_state != _Py_perfmap_jit_callbacks.write_state) { - if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_jit_callbacks) < 0 ) { - PyErr_SetString(PyExc_ValueError, "can't activate perf jit trampoline"); - return NULL; - } + } + else if (strcmp(backend, "perf_jit") == 0) { + _PyPerf_Callbacks cur_cb; + _PyPerfTrampoline_GetCallbacks(&cur_cb); + if (cur_cb.write_state != _Py_perfmap_jit_callbacks.write_state) { + if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_jit_callbacks) < 0 ) { + PyErr_SetString(PyExc_ValueError, "can't activate perf jit trampoline"); + return NULL; } } } @@ -2751,20 +2753,31 @@ PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename) { } char buf[4096]; PyThread_acquire_lock(perf_map_state.map_lock, 1); - int fflush_result = 0, result = 0; + int result = 0; while (1) { size_t bytes_read = fread(buf, 1, sizeof(buf), from); - size_t bytes_written = fwrite(buf, 1, bytes_read, perf_map_state.perf_map); - fflush_result = fflush(perf_map_state.perf_map); - if (fflush_result != 0 || bytes_read == 0 || bytes_written < bytes_read) { - result = -1; - goto close_and_release; + if (bytes_read == 0) { + if (ferror(from)) { + result = -1; + } + break; } + + size_t bytes_written = fwrite(buf, 1, bytes_read, perf_map_state.perf_map); + if (bytes_written < bytes_read) { + result = -1; + break; + } + + if (fflush(perf_map_state.perf_map) != 0) { + result = -1; + break; + } + if (bytes_read < sizeof(buf) && feof(from)) { - goto close_and_release; + break; } } -close_and_release: fclose(from); PyThread_release_lock(perf_map_state.map_lock); return result; @@ -3045,7 +3058,7 @@ get_warnoptions(PyThreadState *tstate) return warnoptions; } -void +PyAPI_FUNC(void) PySys_ResetWarnOptions(void) { PyThreadState *tstate = _PyThreadState_GET(); @@ -3268,6 +3281,7 @@ PyDoc_STR( "\n\ Static objects:\n\ \n\ +abi_info -- Python ABI information.\n\ builtin_module_names -- tuple of module names built into this interpreter\n\ copyright -- copyright notice pertaining to this interpreter\n\ exec_prefix -- prefix used to find the machine-specific Python library\n\ @@ -3638,6 +3652,66 @@ error: return NULL; } + +static PyObject * +make_abi_info(void) +{ + // New entries should be added when needed for a supported platform, + // or by core dev consensus for enabling an unsupported one. + + PyObject *value; + PyObject *abi_info = PyDict_New(); + if (abi_info == NULL) { + return NULL; + } + + value = PyLong_FromLong(sizeof(void *) * 8); + if (value == NULL) { + goto error; + } + if (PyDict_SetItem(abi_info, &_Py_ID(pointer_bits), value) < 0) { + goto error; + } + Py_DECREF(value); + +#ifdef Py_GIL_DISABLED + value = Py_True; +#else + value = Py_False; +#endif + if (PyDict_SetItem(abi_info, &_Py_ID(free_threaded), value) < 0) { + goto error; + } + +#ifdef Py_DEBUG + value = Py_True; +#else + value = Py_False; +#endif + if (PyDict_SetItem(abi_info, &_Py_ID(debug), value) < 0) { + goto error; + } + +#if PY_BIG_ENDIAN + value = &_Py_ID(big); +#else + value = &_Py_ID(little); +#endif + if (PyDict_SetItem(abi_info, &_Py_ID(byteorder), value) < 0) { + goto error; + } + + PyObject *ns = _PyNamespace_New(abi_info); + Py_DECREF(abi_info); + return ns; + +error: + Py_DECREF(abi_info); + Py_XDECREF(value); + return NULL; +} + + #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__, @@ -3812,9 +3886,9 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("builtin_module_names", list_builtin_module_names()); SET_SYS("stdlib_module_names", list_stdlib_module_names()); #if PY_BIG_ENDIAN - SET_SYS_FROM_STRING("byteorder", "big"); + SET_SYS("byteorder", &_Py_ID(big)); #else - SET_SYS_FROM_STRING("byteorder", "little"); + SET_SYS("byteorder", &_Py_ID(little)); #endif #ifdef MS_COREDLL @@ -3856,13 +3930,15 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */ #if _PY_SHORT_FLOAT_REPR == 1 - SET_SYS_FROM_STRING("float_repr_style", "short"); + SET_SYS("float_repr_style", &_Py_ID(short)); #else - SET_SYS_FROM_STRING("float_repr_style", "legacy"); + SET_SYS("float_repr_style", &_Py_ID(legacy)); #endif SET_SYS("thread_info", PyThread_GetInfo()); + SET_SYS("abi_info", make_abi_info()); + /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) diff --git a/Python/thread.c b/Python/thread.c index 18c4af7f634..0365f977d82 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -334,14 +334,12 @@ PyThread_GetInfo(void) #ifdef HAVE_PTHREAD_STUBS value = Py_NewRef(Py_None); -#elif defined(_POSIX_THREADS) +#else value = PyUnicode_FromString("pymutex"); if (value == NULL) { Py_DECREF(threadinfo); return NULL; } -#else - value = Py_NewRef(Py_None); #endif PyStructSequence_SET_ITEM(threadinfo, pos++, value); diff --git a/Python/traceback.c b/Python/traceback.c index da7956d1ec4..264f034dea7 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -69,6 +69,13 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type" #include "clinic/traceback.c.h" + +#ifdef MS_WINDOWS +typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*); +static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL; +#endif + + static PyObject * tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti, int lineno) @@ -408,6 +415,9 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * npath = PyList_Size(syspath); open = PyObject_GetAttr(io, &_Py_ID(open)); + if (open == NULL) { + goto error; + } for (i = 0; i < npath; i++) { v = PyList_GetItem(syspath, i); if (v == NULL) { @@ -973,16 +983,72 @@ done: } } + +#ifdef MS_WINDOWS +static void +_Py_DumpWideString(int fd, wchar_t *str) +{ + Py_ssize_t size = wcslen(str); + int truncated; + if (MAX_STRING_LENGTH < size) { + size = MAX_STRING_LENGTH; + truncated = 1; + } + else { + truncated = 0; + } + + for (Py_ssize_t i=0; i < size; i++) { + Py_UCS4 ch = str[i]; + if (' ' <= ch && ch <= 126) { + /* printable ASCII character */ + dump_char(fd, (char)ch); + } + else if (ch <= 0xff) { + PUTS(fd, "\\x"); + _Py_DumpHexadecimal(fd, ch, 2); + } + else if (Py_UNICODE_IS_HIGH_SURROGATE(ch) + && Py_UNICODE_IS_LOW_SURROGATE(str[i+1])) { + ch = Py_UNICODE_JOIN_SURROGATES(ch, str[i+1]); + i++; // Skip the low surrogate character + PUTS(fd, "\\U"); + _Py_DumpHexadecimal(fd, ch, 8); + } + else { + Py_BUILD_ASSERT(sizeof(wchar_t) == 2); + PUTS(fd, "\\u"); + _Py_DumpHexadecimal(fd, ch, 4); + } + } + + if (truncated) { + PUTS(fd, "..."); + } +} +#endif + + /* Write a frame into the file fd: "File "xxx", line xxx in xxx". - This function is signal safe. */ + This function is signal safe. -static void + Return 0 on success. Return -1 if the frame is invalid. */ + +static int dump_frame(int fd, _PyInterpreterFrame *frame) { - assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); + if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { + /* Ignore trampoline frames and base frame sentinel */ + return 0; + } - PyCodeObject *code =_PyFrame_GetCode(frame); + PyCodeObject *code = _PyFrame_SafeGetCode(frame); + if (code == NULL) { + return -1; + } + + int res = 0; PUTS(fd, " File "); if (code->co_filename != NULL && PyUnicode_Check(code->co_filename)) @@ -990,29 +1056,36 @@ dump_frame(int fd, _PyInterpreterFrame *frame) PUTS(fd, "\""); _Py_DumpASCII(fd, code->co_filename); PUTS(fd, "\""); - } else { + } + else { PUTS(fd, "???"); + res = -1; } - int lineno = PyUnstable_InterpreterFrame_GetLine(frame); PUTS(fd, ", line "); + int lasti = _PyFrame_SafeGetLasti(frame); + int lineno = -1; + if (lasti >= 0) { + lineno = _PyCode_SafeAddr2Line(code, lasti); + } if (lineno >= 0) { _Py_DumpDecimal(fd, (size_t)lineno); } else { PUTS(fd, "???"); + res = -1; } - PUTS(fd, " in "); - if (code->co_name != NULL - && PyUnicode_Check(code->co_name)) { + PUTS(fd, " in "); + if (code->co_name != NULL && PyUnicode_Check(code->co_name)) { _Py_DumpASCII(fd, code->co_name); } else { PUTS(fd, "???"); + res = -1; } - PUTS(fd, "\n"); + return res; } static int @@ -1024,6 +1097,9 @@ tstate_is_freed(PyThreadState *tstate) if (_PyMem_IsPtrFreed(tstate->interp)) { return 1; } + if (_PyMem_IsULongFreed(tstate->thread_id)) { + return 1; + } return 0; } @@ -1043,7 +1119,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) } if (tstate_is_freed(tstate)) { - PUTS(fd, " <tstate is freed>\n"); + PUTS(fd, " <freed thread state>\n"); return; } @@ -1055,17 +1131,6 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) unsigned int depth = 0; while (1) { - if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { - /* Trampoline frame */ - frame = frame->previous; - if (frame == NULL) { - break; - } - - /* Can't have more than one shim frame in a row */ - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - } - if (MAX_FRAME_DEPTH <= depth) { if (MAX_FRAME_DEPTH < depth) { PUTS(fd, "plus "); @@ -1075,8 +1140,20 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) break; } - dump_frame(fd, frame); - frame = frame->previous; + if (_PyMem_IsPtrFreed(frame)) { + PUTS(fd, " <freed frame>\n"); + break; + } + // Read frame->previous early since memory can be freed during + // dump_frame() + _PyInterpreterFrame *previous = frame->previous; + + if (dump_frame(fd, frame) < 0) { + PUTS(fd, " <invalid frame>\n"); + break; + } + + frame = previous; if (frame == NULL) { break; } @@ -1107,23 +1184,12 @@ _Py_DumpTraceback(int fd, PyThreadState *tstate) # endif #endif -/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if - is_current is true, "Thread 0xHHHH:\n" otherwise. - - This function is signal safe. */ +// Write the thread name static void -write_thread_id(int fd, PyThreadState *tstate, int is_current) +write_thread_name(int fd, PyThreadState *tstate) { - if (is_current) - PUTS(fd, "Current thread 0x"); - else - PUTS(fd, "Thread 0x"); - _Py_DumpHexadecimal(fd, - tstate->thread_id, - sizeof(unsigned long) * 2); - - // Write the thread name +#ifndef MS_WINDOWS #if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP) char name[100]; pthread_t thread = (pthread_t)tstate->thread_id; @@ -1142,6 +1208,51 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current) } } #endif +#else + // Windows implementation + if (pGetThreadDescription == NULL) { + return; + } + + HANDLE thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tstate->thread_id); + if (thread == NULL) { + return; + } + + wchar_t *name; + HRESULT hr = pGetThreadDescription(thread, &name); + if (!FAILED(hr)) { + if (name[0] != 0) { + PUTS(fd, " ["); + _Py_DumpWideString(fd, name); + PUTS(fd, "]"); + } + LocalFree(name); + } + CloseHandle(thread); +#endif +} + + +/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if + is_current is true, "Thread 0xHHHH:\n" otherwise. + + This function is signal safe (except on Windows). */ + +static void +write_thread_id(int fd, PyThreadState *tstate, int is_current) +{ + if (is_current) + PUTS(fd, "Current thread 0x"); + else + PUTS(fd, "Thread 0x"); + _Py_DumpHexadecimal(fd, + tstate->thread_id, + sizeof(unsigned long) * 2); + + if (!_PyMem_IsULongFreed(tstate->thread_id)) { + write_thread_name(fd, tstate); + } PUTS(fd, " (most recent call first):\n"); } @@ -1199,7 +1310,6 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, return "unable to get the thread head state"; /* Dump the traceback of each thread */ - tstate = PyInterpreterState_ThreadHead(interp); unsigned int nthreads = 0; _Py_BEGIN_SUPPRESS_IPH do @@ -1210,11 +1320,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, PUTS(fd, "...\n"); break; } + + if (tstate_is_freed(tstate)) { + PUTS(fd, "<freed thread state>\n"); + break; + } + write_thread_id(fd, tstate, tstate == current_tstate); if (tstate == current_tstate && tstate->interp->gc.collecting) { PUTS(fd, " Garbage-collecting\n"); } dump_traceback(fd, tstate, 0); + tstate = PyThreadState_Next(tstate); nthreads++; } while (tstate != NULL); @@ -1336,3 +1453,20 @@ _Py_InitDumpStack(void) (void)backtrace(callstack, 1); #endif } + + +void +_Py_DumpTraceback_Init(void) +{ +#ifdef MS_WINDOWS + if (pGetThreadDescription != NULL) { + return; + } + + HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); + if (kernelbase != NULL) { + pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress( + kernelbase, "GetThreadDescription"); + } +#endif +} diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index 7066a214f10..20351618721 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -36,7 +36,7 @@ static int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, the GIL held from PyMem_RawFree(). It cannot acquire the lock because it would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ #define tables_lock _PyRuntime.tracemalloc.tables_lock -#define TABLES_LOCK() PyMutex_LockFlags(&tables_lock, _Py_LOCK_DONT_DETACH) +#define TABLES_LOCK() PyMutex_Lock(&tables_lock) #define TABLES_UNLOCK() PyMutex_Unlock(&tables_lock) @@ -46,7 +46,7 @@ typedef struct tracemalloc_frame frame_t; typedef struct tracemalloc_traceback traceback_t; #define TRACEBACK_SIZE(NFRAME) \ - (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) + (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME)) static const int MAX_NFRAME = UINT16_MAX; @@ -230,7 +230,7 @@ tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) } frame->lineno = (unsigned int)lineno; - PyObject *filename = filename = _PyFrame_GetCode(pyframe)->co_filename; + PyObject *filename = _PyFrame_GetCode(pyframe)->co_filename; if (filename == NULL) { #ifdef TRACE_DEBUG tracemalloc_error("failed to get the filename of the code object"); @@ -329,8 +329,9 @@ traceback_new(void) traceback->nframe = 0; traceback->total_nframe = 0; traceback_get_frames(traceback); - if (traceback->nframe == 0) - return &tracemalloc_empty_traceback; + if (traceback->nframe == 0) { + return tracemalloc_empty_traceback; + } traceback->hash = traceback_hash(traceback); /* intern the traceback */ @@ -754,12 +755,18 @@ _PyTraceMalloc_Init(void) return _PyStatus_NO_MEMORY(); } - tracemalloc_empty_traceback.nframe = 1; - tracemalloc_empty_traceback.total_nframe = 1; + assert(tracemalloc_empty_traceback == NULL); + tracemalloc_empty_traceback = raw_malloc(TRACEBACK_SIZE(1)); + if (tracemalloc_empty_traceback == NULL) { + return _PyStatus_NO_MEMORY(); + } + + tracemalloc_empty_traceback->nframe = 1; + tracemalloc_empty_traceback->total_nframe = 1; /* borrowed reference */ - tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown); - tracemalloc_empty_traceback.frames[0].lineno = 0; - tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); + tracemalloc_empty_traceback->frames[0].filename = &_Py_STR(anon_unknown); + tracemalloc_empty_traceback->frames[0].lineno = 0; + tracemalloc_empty_traceback->hash = traceback_hash(tracemalloc_empty_traceback); tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; return _PyStatus_OK(); @@ -782,6 +789,9 @@ tracemalloc_deinit(void) _Py_hashtable_destroy(tracemalloc_filenames); PyThread_tss_delete(&tracemalloc_reentrant_key); + + raw_free(tracemalloc_empty_traceback); + tracemalloc_empty_traceback = NULL; } diff --git a/README.rst b/README.rst index baea5e0978d..5f451c6876c 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.15.0 alpha 0 +This is Python version 3.15.0 alpha 3 ===================================== .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push @@ -153,7 +153,7 @@ Documentation updated daily. It can also be downloaded in many formats for faster access. The documentation -is downloadable in HTML, PDF, and reStructuredText formats; the latter version +is downloadable in HTML, EPUB, and reStructuredText formats; the latter version is primarily for documentation authors, translators, and people with special formatting requirements. @@ -232,4 +232,4 @@ This Python distribution contains *no* GNU General Public License (GPL) code, so it may be used in proprietary projects. There are interfaces to some GNU code but these are entirely optional. -All trademarks referenced herein are property of their respective holders. \ No newline at end of file +All trademarks referenced herein are property of their respective holders. diff --git a/Tools/README b/Tools/README index 09bd6fb4798..90acb261482 100644 --- a/Tools/README +++ b/Tools/README @@ -16,6 +16,8 @@ clinic A preprocessor for CPython C files in order to automate freeze Create a stand-alone executable from a Python program. +ftscalingbench Benchmarks for free-threading and finding bottlenecks. + gdb Python code to be run inside gdb, to make it easier to debug Python itself (by David Malcolm). @@ -26,6 +28,12 @@ i18n Tools for internationalization. pygettext.py importbench A set of micro-benchmarks for various import scenarios. +inspection Tooling for PEP-678 "Safe external debugger interface for CPython". + +jit Tooling for building the JIT. + +lockbench Benchmarks for PyMutex and critical sections. + msi Support for packaging Python as an MSI package on Windows. nuget Files for the NuGet package manager for .NET. @@ -35,13 +43,15 @@ patchcheck Tools for checking and applying patches to the Python source cod peg_generator PEG-based parser generator (pegen) used for new parser. +pixi-packages Pixi package definitions for downstream from-source builds. + scripts A number of useful single-file programs, e.g. run_tests.py which runs the Python test suite. ssl Scripts to generate ssl_data.h from OpenSSL sources, and run tests against multiple installations of OpenSSL and LibreSSL. -tz A script to dump timezone from /usr/share/zoneinfo. +tsan Utilities for building CPython with thread-sanitizer. unicode Tools for generating unicodedata and codecs from unicode.org and other mapping files (by Fredrik Lundh, Marc-Andre Lemburg diff --git a/Tools/build/.ruff.toml b/Tools/build/.ruff.toml index dcbf2936290..996f725fdcb 100644 --- a/Tools/build/.ruff.toml +++ b/Tools/build/.ruff.toml @@ -29,7 +29,6 @@ ignore = [ "F541", # f-string without any placeholders "PYI024", # Use `typing.NamedTuple` instead of `collections.namedtuple` "PYI025", # Use `from collections.abc import Set as AbstractSet` - "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` ] [lint.per-file-ignores] diff --git a/Tools/build/check_extension_modules.py b/Tools/build/check_extension_modules.py index 668db8df0bd..f23c1d5286f 100644 --- a/Tools/build/check_extension_modules.py +++ b/Tools/build/check_extension_modules.py @@ -23,9 +23,11 @@ from __future__ import annotations import _imp import argparse import enum +import json import logging import os import pathlib +import pprint import re import sys import sysconfig @@ -116,6 +118,18 @@ parser.add_argument( help="Print a list of module names to stdout and exit", ) +parser.add_argument( + "--generate-missing-stdlib-info", + action="store_true", + help="Generate file with stdlib module info", +) + +parser.add_argument( + "--with-missing-stdlib-config", + metavar="CONFIG_FILE", + help="Path to JSON config file with custom missing module messages", +) + @enum.unique class ModuleState(enum.Enum): @@ -281,6 +295,39 @@ class ModuleChecker: names.update(WINDOWS_MODULES) return names + def generate_missing_stdlib_info(self, config_path: str | None = None) -> None: + config_messages = {} + if config_path: + try: + with open(config_path, encoding='utf-8') as f: + config_messages = json.load(f) + except (FileNotFoundError, json.JSONDecodeError) as e: + raise RuntimeError(f"Failed to load missing stdlib config {config_path!r}") from e + + messages = {} + for name in WINDOWS_MODULES: + messages[name] = f"Unsupported platform for Windows-only standard library module {name!r}" + + for modinfo in self.modules: + if modinfo.state in (ModuleState.DISABLED, ModuleState.DISABLED_SETUP): + messages[modinfo.name] = f"Standard library module disabled during build {modinfo.name!r} was not found" + elif modinfo.state == ModuleState.NA: + messages[modinfo.name] = f"Unsupported platform for standard library module {modinfo.name!r}" + + messages.update(config_messages) + + content = f'''\ +# Standard library information used by the traceback module for more informative +# ModuleNotFound error messages. +# Generated by check_extension_modules.py + +_MISSING_STDLIB_MODULE_MESSAGES = {pprint.pformat(messages)} +''' + + output_path = self.builddir / "_missing_stdlib_info.py" + with open(output_path, "w", encoding="utf-8") as f: + f.write(content) + def get_builddir(self) -> pathlib.Path: try: with open(self.pybuilddir_txt, encoding="utf-8") as f: @@ -499,6 +546,9 @@ def main() -> None: names = checker.list_module_names(all=True) for name in sorted(names): print(name) + elif args.generate_missing_stdlib_info: + checker.check() + checker.generate_missing_stdlib_info(args.with_missing_stdlib_config) else: checker.check() checker.summary(verbose=args.verbose) diff --git a/Tools/build/compute-changes.py b/Tools/build/compute-changes.py index b5993d29b92..524d3066fbf 100644 --- a/Tools/build/compute-changes.py +++ b/Tools/build/compute-changes.py @@ -45,12 +45,22 @@ UNIX_BUILD_SYSTEM_FILE_NAMES = frozenset({ SUFFIXES_C_OR_CPP = frozenset({".c", ".h", ".cpp"}) SUFFIXES_DOCUMENTATION = frozenset({".rst", ".md"}) +ANDROID_DIRS = frozenset({"Android"}) +IOS_DIRS = frozenset({"Apple", "iOS"}) +MACOS_DIRS = frozenset({"Mac"}) +WASI_DIRS = frozenset({Path("Tools", "wasm")}) + @dataclass(kw_only=True, slots=True) class Outputs: + run_android: bool = False run_ci_fuzz: bool = False run_docs: bool = False + run_ios: bool = False + run_macos: bool = False run_tests: bool = False + run_ubuntu: bool = False + run_wasi: bool = False run_windows_msi: bool = False run_windows_tests: bool = False @@ -63,7 +73,15 @@ def compute_changes() -> None: outputs = process_changed_files(files) else: # Otherwise, just run the tests - outputs = Outputs(run_tests=True, run_windows_tests=True) + outputs = Outputs( + run_android=True, + run_ios=True, + run_macos=True, + run_tests=True, + run_ubuntu=True, + run_wasi=True, + run_windows_tests=True, + ) outputs = process_target_branch(outputs, target_branch) if outputs.run_tests: @@ -111,6 +129,21 @@ def get_changed_files( return frozenset(map(Path, filter(None, map(str.strip, changed_files)))) +def get_file_platform(file: Path) -> str | None: + if not file.parts: + return None + first_part = file.parts[0] + if first_part in MACOS_DIRS: + return "macos" + if first_part in IOS_DIRS: + return "ios" + if first_part in ANDROID_DIRS: + return "android" + if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS: # Tools/wasm/ + return "wasi" + return None + + def process_changed_files(changed_files: Set[Path]) -> Outputs: run_tests = False run_ci_fuzz = False @@ -118,6 +151,9 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs: run_windows_tests = False run_windows_msi = False + platforms_changed = set() + has_platform_specific_change = True + for file in changed_files: # Documentation files doc_or_misc = file.parts[0] in {"Doc", "Misc"} @@ -126,10 +162,15 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs: if file.parent == GITHUB_WORKFLOWS_PATH: if file.name == "build.yml": run_tests = run_ci_fuzz = True + has_platform_specific_change = False if file.name == "reusable-docs.yml": run_docs = True if file.name == "reusable-windows-msi.yml": run_windows_msi = True + if file.name == "reusable-macos.yml": + platforms_changed.add("macos") + if file.name == "reusable-wasi.yml": + platforms_changed.add("wasi") if not ( doc_file @@ -138,8 +179,13 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs: ): run_tests = True - if file not in UNIX_BUILD_SYSTEM_FILE_NAMES: - run_windows_tests = True + platform = get_file_platform(file) + if platform is not None: + platforms_changed.add(platform) + else: + has_platform_specific_change = False + if file not in UNIX_BUILD_SYSTEM_FILE_NAMES: + run_windows_tests = True # The fuzz tests are pretty slow so they are executed only for PRs # changing relevant files. @@ -159,12 +205,38 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs: if file.parts[:2] == ("Tools", "msi"): run_windows_msi = True + # Check which platform specific tests to run + if run_tests: + if not has_platform_specific_change or not platforms_changed: + run_android = True + run_ios = True + run_macos = True + run_ubuntu = True + run_wasi = True + else: + run_android = "android" in platforms_changed + run_ios = "ios" in platforms_changed + run_macos = "macos" in platforms_changed + run_ubuntu = False + run_wasi = "wasi" in platforms_changed + else: + run_android = False + run_ios = False + run_macos = False + run_ubuntu = False + run_wasi = False + return Outputs( + run_android=run_android, run_ci_fuzz=run_ci_fuzz, run_docs=run_docs, + run_ios=run_ios, + run_macos=run_macos, run_tests=run_tests, - run_windows_tests=run_windows_tests, + run_ubuntu=run_ubuntu, + run_wasi=run_wasi, run_windows_msi=run_windows_msi, + run_windows_tests=run_windows_tests, ) @@ -191,11 +263,16 @@ def write_github_output(outputs: Outputs) -> None: return with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f: + f.write(f"run-android={bool_lower(outputs.run_android)}\n") f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n") f.write(f"run-docs={bool_lower(outputs.run_docs)}\n") + f.write(f"run-ios={bool_lower(outputs.run_ios)}\n") + f.write(f"run-macos={bool_lower(outputs.run_macos)}\n") f.write(f"run-tests={bool_lower(outputs.run_tests)}\n") - f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n") + f.write(f"run-ubuntu={bool_lower(outputs.run_ubuntu)}\n") + f.write(f"run-wasi={bool_lower(outputs.run_wasi)}\n") f.write(f"run-windows-msi={bool_lower(outputs.run_windows_msi)}\n") + f.write(f"run-windows-tests={bool_lower(outputs.run_windows_tests)}\n") def bool_lower(value: bool, /) -> str: diff --git a/Tools/build/consts_getter.py b/Tools/build/consts_getter.py new file mode 100644 index 00000000000..4cd454448ba --- /dev/null +++ b/Tools/build/consts_getter.py @@ -0,0 +1,20 @@ +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +INTERNAL = ROOT / "Include" / "internal" + +def get_nsmallnegints_and_nsmallposints() -> tuple[int, int]: + nsmallposints = None + nsmallnegints = None + with open(INTERNAL / "pycore_runtime_structs.h") as infile: + for line in infile: + if line.startswith("#define _PY_NSMALLPOSINTS"): + nsmallposints = int(line.split()[-1]) + elif line.startswith("#define _PY_NSMALLNEGINTS"): + nsmallnegints = int(line.split()[-1]) + break + else: + raise NotImplementedError + assert nsmallposints + assert nsmallnegints + return nsmallnegints, nsmallposints diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 2b9f03aebb6..477c3d0f5b3 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -17,6 +17,7 @@ import re import time import types +import consts_getter import umarshal TYPE_CHECKING = False @@ -362,7 +363,9 @@ class Printer: self.write(f".ob_digit = {{ {ds} }},") def generate_int(self, name: str, i: int) -> str: - if -5 <= i <= 256: + nsmallnegints, nsmallposints = consts_getter.get_nsmallnegints_and_nsmallposints() + + if -nsmallnegints <= i <= nsmallposints: return f"(PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + {i}]" if i >= 0: name = f"const_int_{i}" diff --git a/Tools/build/generate-build-details.py b/Tools/build/generate-build-details.py index 8cd23e2f54f..8272635bc62 100644 --- a/Tools/build/generate-build-details.py +++ b/Tools/build/generate-build-details.py @@ -48,14 +48,16 @@ def generate_data(schema_version: str) -> collections.defaultdict[str, Any]: #data['base_interpreter'] = sys._base_executable data['base_interpreter'] = os.path.join( sysconfig.get_path('scripts'), - 'python' + sysconfig.get_config_var('VERSION'), + "python" + + sysconfig.get_config_var('LDVERSION') + + sysconfig.get_config_var('EXE'), ) data['platform'] = sysconfig.get_platform() data['language']['version'] = sysconfig.get_python_version() data['language']['version_info'] = version_info_to_dict(sys.version_info) - data['implementation'] = vars(sys.implementation) + data['implementation'] = vars(sys.implementation).copy() data['implementation']['version'] = version_info_to_dict(sys.implementation.version) # Fix cross-compilation if '_multiarch' in data['implementation']: @@ -104,7 +106,7 @@ def generate_data(schema_version: str) -> collections.defaultdict[str, Any]: data['abi']['extension_suffix'] = sysconfig.get_config_var('EXT_SUFFIX') # EXTENSION_SUFFIXES has been constant for a long time, and currently we - # don't have a better information source to find the stable ABI suffix. + # don't have a better information source to find the stable ABI suffix. for suffix in importlib.machinery.EXTENSION_SUFFIXES: if suffix.startswith('.abi'): data['abi']['stable_abi_suffix'] = suffix @@ -133,33 +135,51 @@ def generate_data(schema_version: str) -> collections.defaultdict[str, Any]: def make_paths_relative(data: dict[str, Any], config_path: str | None = None) -> None: # Make base_prefix relative to the config_path directory if config_path: - data['base_prefix'] = os.path.relpath(data['base_prefix'], os.path.dirname(config_path)) + data['base_prefix'] = relative_path(data['base_prefix'], + os.path.dirname(config_path)) + base_prefix = data['base_prefix'] + # Update path values to make them relative to base_prefix - PATH_KEYS = [ + PATH_KEYS = ( 'base_interpreter', 'libpython.dynamic', 'libpython.dynamic_stableabi', 'libpython.static', 'c_api.headers', 'c_api.pkgconfig_path', - ] + ) for entry in PATH_KEYS: - parent, _, child = entry.rpartition('.') + *parents, child = entry.split('.') # Get the key container object try: container = data - for part in parent.split('.'): + for part in parents: container = container[part] + if child not in container: + raise KeyError(child) current_path = container[child] except KeyError: continue # Get the relative path - new_path = os.path.relpath(current_path, data['base_prefix']) + new_path = relative_path(current_path, base_prefix) # Join '.' so that the path is formated as './path' instead of 'path' new_path = os.path.join('.', new_path) container[child] = new_path +def relative_path(path: str, base: str) -> str: + if os.name != 'nt': + return os.path.relpath(path, base) + + # There are no relative paths between drives on Windows. + path_drv, _ = os.path.splitdrive(path) + base_drv, _ = os.path.splitdrive(base) + if path_drv.lower() == base_drv.lower(): + return os.path.relpath(path, base) + + return path + + def main() -> None: parser = argparse.ArgumentParser(exit_on_error=False) parser.add_argument('location') @@ -186,8 +206,9 @@ def main() -> None: make_paths_relative(data, args.config_file_path) json_output = json.dumps(data, indent=2) - with open(args.location, 'w') as f: - print(json_output, file=f) + with open(args.location, 'w', encoding='utf-8') as f: + f.write(json_output) + f.write('\n') if __name__ == '__main__': diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index 94905b3756d..5b188e338ba 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -3,6 +3,8 @@ import io import os.path import re +import consts_getter + SCRIPT_NAME = 'Tools/build/generate_global_objects.py' __file__ = os.path.abspath(__file__) ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -274,20 +276,7 @@ def generate_global_strings(identifiers, strings): def generate_runtime_init(identifiers, strings): - # First get some info from the declarations. - nsmallposints = None - nsmallnegints = None - with open(os.path.join(INTERNAL, 'pycore_runtime_structs.h')) as infile: - for line in infile: - if line.startswith('#define _PY_NSMALLPOSINTS'): - nsmallposints = int(line.split()[-1]) - elif line.startswith('#define _PY_NSMALLNEGINTS'): - nsmallnegints = int(line.split()[-1]) - break - else: - raise NotImplementedError - assert nsmallposints - assert nsmallnegints + nsmallnegints, nsmallposints = consts_getter.get_nsmallnegints_and_nsmallposints() # Then target the runtime initializer. filename = os.path.join(INTERNAL, 'pycore_runtime_init_generated.h') diff --git a/Tools/build/generate_sbom.py b/Tools/build/generate_sbom.py index 968397728b2..f5a2f26cbb0 100644 --- a/Tools/build/generate_sbom.py +++ b/Tools/build/generate_sbom.py @@ -242,14 +242,14 @@ def check_sbom_packages(sbom_data: dict[str, typing.Any]) -> None: ) # libexpat specifies its expected rev in a refresh script. - if package["name"] == "libexpat": + if package["name"] == "expat": libexpat_refresh_sh = (CPYTHON_ROOT_DIR / "Modules/expat/refresh.sh").read_text() libexpat_expected_version_match = re.search( r"expected_libexpat_version=\"([0-9]+\.[0-9]+\.[0-9]+)\"", libexpat_refresh_sh ) libexpat_expected_sha256_match = re.search( - r"expected_libexpat_sha256=\"[a-f0-9]{40}\"", + r"expected_libexpat_sha256=\"([a-f0-9]{64})\"", libexpat_refresh_sh ) libexpat_expected_version = libexpat_expected_version_match and libexpat_expected_version_match.group(1) diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini index 331bada6f47..7d341afd1cd 100644 --- a/Tools/build/mypy.ini +++ b/Tools/build/mypy.ini @@ -6,6 +6,7 @@ files = Tools/build/check_extension_modules.py, Tools/build/check_warnings.py, Tools/build/compute-changes.py, + Tools/build/consts_getter.py, Tools/build/deepfreeze.py, Tools/build/generate-build-details.py, Tools/build/generate_sbom.py, diff --git a/Tools/build/smelly.py b/Tools/build/smelly.py index 9a360412a73..424fa6ad4a1 100755 --- a/Tools/build/smelly.py +++ b/Tools/build/smelly.py @@ -21,8 +21,6 @@ EXCEPTIONS = frozenset({ }) IGNORED_EXTENSION = "_ctypes_test" -# Ignore constructor and destructor functions -IGNORED_SYMBOLS = {'_init', '_fini'} def is_local_symbol_type(symtype): @@ -34,19 +32,12 @@ def is_local_symbol_type(symtype): if symtype.islower() and symtype not in "uvw": return True - # Ignore the initialized data section (d and D) and the BSS data - # section. For example, ignore "__bss_start (type: B)" - # and "_edata (type: D)". - if symtype in "bBdD": - return True - return False def get_exported_symbols(library, dynamic=False): print(f"Check that {library} only exports symbols starting with Py or _Py") - # Only look at dynamic symbols args = ['nm', '--no-sort'] if dynamic: args.append('--dynamic') @@ -89,8 +80,6 @@ def get_smelly_symbols(stdout, dynamic=False): if is_local_symbol_type(symtype): local_symbols.append(result) - elif symbol in IGNORED_SYMBOLS: - local_symbols.append(result) else: smelly_symbols.append(result) diff --git a/Tools/build/stable_abi.py b/Tools/build/stable_abi.py index 1ddd76cdd9b..39115b331ba 100644 --- a/Tools/build/stable_abi.py +++ b/Tools/build/stable_abi.py @@ -232,7 +232,7 @@ ITEM_KIND_TO_DOC_ROLE = { 'data': 'data', 'struct': 'type', 'macro': 'macro', - # 'const': 'const', # all undocumented + 'const': 'macro', 'typedef': 'type', } diff --git a/Tools/c-analyzer/c_parser/parser/__init__.py b/Tools/c-analyzer/c_parser/parser/__init__.py index ff4f303c4a2..f3f09107aef 100644 --- a/Tools/c-analyzer/c_parser/parser/__init__.py +++ b/Tools/c-analyzer/c_parser/parser/__init__.py @@ -116,6 +116,8 @@ TODO: * alt impl using a state machine (& tokenizer or split on delimiters) """ +import textwrap + from ..info import ParsedItem from ._info import SourceInfo @@ -208,7 +210,27 @@ def _iter_source(lines, *, maxtext=11_000, maxlines=200, showtext=False): return # At this point either the file ended prematurely # or there's "too much" text. - filename, lno, text = srcinfo.filename, srcinfo._start, srcinfo.text + filename, lno_from, lno_to = srcinfo.filename, srcinfo.start, srcinfo.end + text = srcinfo.text if len(text) > 500: text = text[:500] + '...' - raise Exception(f'unmatched text ({filename} starting at line {lno}):\n{text}') + + if srcinfo.too_much_text(maxtext): + msg = f''' + too much text, try to increase MAX_SIZES[MAXTEXT] in cpython/_parser.py + {filename} starting at line {lno_from} to {lno_to} + has code with length {len(text)} greater than {maxtext}: + {text} + ''' + raise RuntimeError(textwrap.dedent(msg)) + + if srcinfo.too_many_lines(maxlines): + msg = f''' + too many lines, try to increase MAX_SIZES[MAXLINES] in cpython/_parser.py + {filename} starting at line {lno_from} to {lno_to} + has code with number of lines {lno_to - lno_from} greater than {maxlines}: + {text} + ''' + raise RuntimeError(textwrap.dedent(msg)) + + raise RuntimeError(f'unmatched text ({filename} starting at line {lno_from}):\n{text}') diff --git a/Tools/c-analyzer/c_parser/parser/_info.py b/Tools/c-analyzer/c_parser/parser/_info.py index 340223db933..13b192e2ce9 100644 --- a/Tools/c-analyzer/c_parser/parser/_info.py +++ b/Tools/c-analyzer/c_parser/parser/_info.py @@ -123,10 +123,16 @@ class SourceInfo: def done(self): self._set_ready() + def too_much_text(self, maxtext): + return maxtext and len(self.text) > maxtext + + def too_many_lines(self, maxlines): + return maxlines and self.end - self.start > maxlines + def too_much(self, maxtext, maxlines): - if maxtext and len(self.text) > maxtext: + if self.too_much_text(maxtext): pass - elif maxlines and self.end - self.start > maxlines: + elif self.too_many_lines(maxlines): pass else: return False diff --git a/Tools/c-analyzer/c_parser/preprocessor/__init__.py b/Tools/c-analyzer/c_parser/preprocessor/__init__.py index 30a86cbd7dc..f8d2f805cb1 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/__init__.py +++ b/Tools/c-analyzer/c_parser/preprocessor/__init__.py @@ -16,6 +16,7 @@ from . import errors as _errors from . import ( pure as _pure, gcc as _gcc, + clang as _clang, ) @@ -234,7 +235,7 @@ _COMPILERS = { 'bcpp': None, # aliases/extras: 'gcc': _gcc.preprocess, - 'clang': None, + 'clang': _clang.preprocess, } diff --git a/Tools/c-analyzer/c_parser/preprocessor/clang.py b/Tools/c-analyzer/c_parser/preprocessor/clang.py new file mode 100644 index 00000000000..574a23f8f6d --- /dev/null +++ b/Tools/c-analyzer/c_parser/preprocessor/clang.py @@ -0,0 +1,104 @@ +import os.path +import re, sys + +from . import common as _common +from . import gcc as _gcc + +_normpath = _gcc._normpath + +TOOL = 'clang' + +META_FILES = { + '<built-in>', + '<command line>', +} + + +def preprocess(filename, + incldirs=None, + includes=None, + macros=None, + samefiles=None, + cwd=None, + ): + if not cwd or not os.path.isabs(cwd): + cwd = os.path.abspath(cwd or '.') + filename = _normpath(filename, cwd) + + postargs = _gcc.POST_ARGS + basename = os.path.basename(filename) + dirname = os.path.basename(os.path.dirname(filename)) + if (basename not in _gcc.FILES_WITHOUT_INTERNAL_CAPI + and dirname not in _gcc.DIRS_WITHOUT_INTERNAL_CAPI): + postargs += ('-DPy_BUILD_CORE=1',) + + text = _common.preprocess( + TOOL, + filename, + incldirs=incldirs, + includes=includes, + macros=macros, + #preargs=PRE_ARGS, + postargs=postargs, + executable=['clang'], + compiler='unix', + cwd=cwd, + ) + return _iter_lines(text, filename, samefiles, cwd) + + +EXIT_MARKERS = {'# 2 "<built-in>" 2', '# 3 "<built-in>" 2', '# 4 "<built-in>" 2'} + + +def _iter_lines(text, reqfile, samefiles, cwd, raw=False): + lines = iter(text.splitlines()) + + # The first line is special. + # The subsequent lines are consistent. + firstlines = [ + f'# 1 "{reqfile}"', + '# 1 "<built-in>" 1', + '# 1 "<built-in>" 3', + '# 370 "<built-in>" 3', + '# 1 "<command line>" 1', + '# 1 "<built-in>" 2', + ] + for expected in firstlines: + line = next(lines) + if line != expected: + raise NotImplementedError((line, expected)) + + # Do all the CLI-provided includes. + filter_reqfile = (lambda f: _gcc._filter_reqfile(f, reqfile, samefiles)) + make_info = (lambda lno: _common.FileInfo(reqfile, lno)) + last = None + for line in lines: + assert last != reqfile, (last,) + # NOTE:condition is clang specific + if not line: + continue + lno, included, flags = _gcc._parse_marker_line(line, reqfile) + if not included: + raise NotImplementedError((line,)) + if included == reqfile: + # This will be the last one. + assert 2 in flags, (line, flags) + else: + # NOTE:first condition is specific to clang + if _normpath(included, cwd) == reqfile: + assert 1 in flags or 2 in flags, (line, flags, included, reqfile) + else: + assert 1 in flags, (line, flags, included, reqfile) + yield from _gcc._iter_top_include_lines( + lines, + _normpath(included, cwd), + cwd, + filter_reqfile, + make_info, + raw, + EXIT_MARKERS + ) + last = included + # The last one is always the requested file. + # NOTE:_normpath is clang specific + assert _normpath(included, cwd) == reqfile, (line,) diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index d20cd19f6e6..4a55a1a24ee 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -65,6 +65,8 @@ POST_ARGS = ( '-E', ) +EXIT_MARKERS = {'# 0 "<command-line>" 2', '# 1 "<command-line>" 2'} + def preprocess(filename, incldirs=None, @@ -138,6 +140,7 @@ def _iter_lines(text, reqfile, samefiles, cwd, raw=False): filter_reqfile, make_info, raw, + EXIT_MARKERS ) last = included # The last one is always the requested file. @@ -146,7 +149,7 @@ def _iter_lines(text, reqfile, samefiles, cwd, raw=False): def _iter_top_include_lines(lines, topfile, cwd, filter_reqfile, make_info, - raw): + raw, exit_markers): partial = 0 # depth files = [topfile] # We start at 1 in case there are source lines (including blank ones) @@ -154,12 +157,20 @@ def _iter_top_include_lines(lines, topfile, cwd, # _parse_marker_line() that the preprocessor reported lno as 1. lno = 1 for line in lines: - if line == '# 0 "<command-line>" 2' or line == '# 1 "<command-line>" 2': + if line in exit_markers: # We're done with this top-level include. return _lno, included, flags = _parse_marker_line(line) if included: + # HACK: + # Mixes curses.h and ncurses.h marker lines + # gcc silently passes this, while clang fails + # See: /Include/py_curses.h #if-elif directives + # And compare with preprocessor output + if os.path.basename(included) == 'curses.h': + included = os.path.join(os.path.dirname(included), 'ncurses.h') + lno = _lno included = _normpath(included, cwd) # We hit a marker line. diff --git a/Tools/c-analyzer/cpython/_analyzer.py b/Tools/c-analyzer/cpython/_analyzer.py index 6f0f4648928..43ed552fcf7 100644 --- a/Tools/c-analyzer/cpython/_analyzer.py +++ b/Tools/c-analyzer/cpython/_analyzer.py @@ -76,6 +76,7 @@ _OTHER_SUPPORTED_TYPES = { 'PyBufferProcs', 'PyStructSequence_Field[]', 'PyStructSequence_Desc', + 'PyABIInfo', } # XXX We should normalize all cases to a single name, diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 1e754040eaf..6332dec3aef 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -1,5 +1,4 @@ import os.path -import re from c_parser.preprocessor import ( get_preprocessor as _get_preprocessor, @@ -18,16 +17,16 @@ def _abs(relfile): return os.path.join(REPO_ROOT, relfile) -def clean_lines(text): - """Clear out comments, blank lines, and leading/trailing whitespace.""" - lines = (line.strip() for line in text.splitlines()) - lines = (line.partition('#')[0].rstrip() - for line in lines - if line and not line.startswith('#')) - glob_all = f'{GLOB_ALL} ' - lines = (re.sub(r'^[*] ', glob_all, line) for line in lines) - lines = (_abs(line) for line in lines) - return list(lines) +def format_conf_lines(lines): + """Format conf entries for use in a TSV table.""" + return [_abs(entry) for entry in lines] + + +def format_tsv_lines(lines): + """Format entries for use in a TSV table.""" + lines = ((_abs(first), *rest) for first, *rest in lines) + lines = map('\t'.join, lines) + return list(map(str.rstrip, lines)) ''' @@ -47,255 +46,246 @@ def clean_lines(text): ''' # XXX Handle these. -# Tab separated: -EXCLUDED = clean_lines(''' -# @begin=conf@ +EXCLUDED = format_conf_lines([ + # macOS + 'Modules/_scproxy.c', # SystemConfiguration/SystemConfiguration.h -# OSX -Modules/_scproxy.c # SystemConfiguration/SystemConfiguration.h + # Windows + 'Modules/_winapi.c', # windows.h + 'Modules/expat/winconfig.h', + 'Modules/overlapped.c', # winsock.h + 'Python/dynload_win.c', # windows.h + 'Python/thread_nt.h', -# Windows -Modules/_winapi.c # windows.h -Modules/expat/winconfig.h -Modules/overlapped.c # winsock.h -Python/dynload_win.c # windows.h -Python/thread_nt.h + # other OS-dependent + 'Python/dynload_aix.c', # sys/ldr.h + 'Python/dynload_dl.c', # dl.h + 'Python/dynload_hpux.c', # dl.h + 'Python/emscripten_signal.c', + 'Python/emscripten_syscalls.c', + 'Python/emscripten_trampoline_inner.c', + 'Python/thread_pthread.h', + 'Python/thread_pthread_stubs.h', -# other OS-dependent -Python/dynload_aix.c # sys/ldr.h -Python/dynload_dl.c # dl.h -Python/dynload_hpux.c # dl.h -Python/emscripten_signal.c -Python/emscripten_syscalls.c -Python/thread_pthread.h -Python/thread_pthread_stubs.h + # only huge constants (safe but parsing is slow) + 'Modules/_ssl_data_*.h', + 'Modules/cjkcodecs/mappings_*.h', + 'Modules/unicodedata_db.h', + 'Modules/unicodename_db.h', + 'Objects/unicodetype_db.h', -# only huge constants (safe but parsing is slow) -Modules/_ssl_data_*.h -Modules/cjkcodecs/mappings_*.h -Modules/unicodedata_db.h -Modules/unicodename_db.h -Objects/unicodetype_db.h + # generated + 'Python/deepfreeze/*.c', + 'Python/frozen_modules/*.h', + 'Python/generated_cases.c.h', + 'Python/executor_cases.c.h', + 'Python/optimizer_cases.c.h', + 'Python/opcode_targets.h', + # XXX: Throws errors if PY_VERSION_HEX is not mocked out + 'Modules/clinic/_testclinic_depr.c.h', -# generated -Python/deepfreeze/*.c -Python/frozen_modules/*.h -Python/generated_cases.c.h -Python/executor_cases.c.h -Python/optimizer_cases.c.h -# XXX: Throws errors if PY_VERSION_HEX is not mocked out -Modules/clinic/_testclinic_depr.c.h + # not actually source + 'Python/bytecodes.c', + 'Python/optimizer_bytecodes.c', -# not actually source -Python/bytecodes.c -Python/optimizer_bytecodes.c - -# mimalloc -Objects/mimalloc/*.c -Include/internal/mimalloc/*.h -Include/internal/mimalloc/mimalloc/*.h - -# @end=conf@ -''') + # mimalloc + 'Objects/mimalloc/*.c', + 'Include/internal/mimalloc/*.h', + 'Include/internal/mimalloc/mimalloc/*.h', +]) # XXX Fix the parser. -EXCLUDED += clean_lines(''' -# The tool should be able to parse these... +EXCLUDED += format_conf_lines([ + # The tool should be able to parse these... -# The problem with xmlparse.c is that something -# has gone wrong where # we handle "maybe inline actual" -# in Tools/c-analyzer/c_parser/parser/_global.py. -Modules/expat/internal.h -Modules/expat/xmlparse.c -''') + # The problem with xmlparse.c is that something + # has gone wrong where # we handle "maybe inline actual" + # in Tools/c-analyzer/c_parser/parser/_global.py. + 'Modules/expat/internal.h', + 'Modules/expat/xmlparse.c', +]) -INCL_DIRS = clean_lines(''' -# @begin=tsv@ +INCL_DIRS = format_tsv_lines([ + # (glob, dirname) -glob dirname -* . -* ./Include -* ./Include/internal -* ./Include/internal/mimalloc + ('*', '.'), + ('*', './Include'), + ('*', './Include/internal'), + ('*', './Include/internal/mimalloc'), -Modules/_decimal/**/*.c Modules/_decimal/libmpdec -Modules/_elementtree.c Modules/expat -Modules/_hacl/*.c Modules/_hacl/include -Modules/_hacl/*.c Modules/_hacl/ -Modules/_hacl/*.h Modules/_hacl/include -Modules/_hacl/*.h Modules/_hacl/ -Modules/md5module.c Modules/_hacl/include -Modules/sha1module.c Modules/_hacl/include -Modules/sha2module.c Modules/_hacl/include -Modules/sha3module.c Modules/_hacl/include -Modules/blake2module.c Modules/_hacl/include -Modules/hmacmodule.c Modules/_hacl/include -Objects/stringlib/*.h Objects + ('Modules/_decimal/**/*.c', 'Modules/_decimal/libmpdec'), -# possible system-installed headers, just in case -Modules/_tkinter.c /usr/include/tcl8.6 -Modules/_uuidmodule.c /usr/include/uuid -Modules/tkappinit.c /usr/include/tcl + ('Modules/_elementtree.c', 'Modules/expat'), + ('Modules/pyexpat.c', 'Modules/expat'), -# @end=tsv@ -''')[1:] + ('Modules/_hacl/*.c', 'Modules/_hacl/include'), + ('Modules/_hacl/*.c', 'Modules/_hacl/'), + ('Modules/_hacl/*.h', 'Modules/_hacl/include'), + ('Modules/_hacl/*.h', 'Modules/_hacl/'), + ('Modules/md5module.c', 'Modules/_hacl/include'), + ('Modules/sha1module.c', 'Modules/_hacl/include'), + ('Modules/sha2module.c', 'Modules/_hacl/include'), + ('Modules/sha3module.c', 'Modules/_hacl/include'), + ('Modules/blake2module.c', 'Modules/_hacl/include'), + ('Modules/hmacmodule.c', 'Modules/_hacl/include'), -INCLUDES = clean_lines(''' -# @begin=tsv@ + ('Objects/stringlib/*.h', 'Objects'), -glob include + # possible system-installed headers, just in case + ('Modules/_tkinter.c', '/usr/include/tcl8.6'), + ('Modules/_uuidmodule.c', '/usr/include/uuid'), + ('Modules/tkappinit.c', '/usr/include/tcl'), -**/*.h Python.h -Include/**/*.h object.h +]) -# for Py_HAVE_CONDVAR -Include/internal/pycore_gil.h pycore_condvar.h -Python/thread_pthread.h pycore_condvar.h +INCLUDES = format_tsv_lines([ + # (glob, include) -# other + ('**/*.h', 'Python.h'), + ('Include/**/*.h', 'object.h'), -Objects/stringlib/join.h stringlib/stringdefs.h -Objects/stringlib/ctype.h stringlib/stringdefs.h -Objects/stringlib/transmogrify.h stringlib/stringdefs.h -#Objects/stringlib/fastsearch.h stringlib/stringdefs.h -#Objects/stringlib/count.h stringlib/stringdefs.h -#Objects/stringlib/find.h stringlib/stringdefs.h -#Objects/stringlib/partition.h stringlib/stringdefs.h -#Objects/stringlib/split.h stringlib/stringdefs.h -Objects/stringlib/fastsearch.h stringlib/ucs1lib.h -Objects/stringlib/count.h stringlib/ucs1lib.h -Objects/stringlib/find.h stringlib/ucs1lib.h -Objects/stringlib/partition.h stringlib/ucs1lib.h -Objects/stringlib/split.h stringlib/ucs1lib.h -Objects/stringlib/find_max_char.h Objects/stringlib/ucs1lib.h -Objects/stringlib/count.h Objects/stringlib/fastsearch.h -Objects/stringlib/find.h Objects/stringlib/fastsearch.h -Objects/stringlib/partition.h Objects/stringlib/fastsearch.h -Objects/stringlib/replace.h Objects/stringlib/fastsearch.h -Objects/stringlib/repr.h Objects/stringlib/fastsearch.h -Objects/stringlib/split.h Objects/stringlib/fastsearch.h + # for Py_HAVE_CONDVAR + ('Include/internal/pycore_gil.h', 'pycore_condvar.h'), + ('Python/thread_pthread.h', 'pycore_condvar.h'), -# @end=tsv@ -''')[1:] + # other -MACROS = clean_lines(''' -# @begin=tsv@ + ('Objects/stringlib/join.h', 'stringlib/stringdefs.h'), + ('Objects/stringlib/ctype.h', 'stringlib/stringdefs.h'), + ('Objects/stringlib/transmogrify.h', 'stringlib/stringdefs.h'), + # ('Objects/stringlib/fastsearch.h', 'stringlib/stringdefs.h'), + # ('Objects/stringlib/count.h', 'stringlib/stringdefs.h'), + # ('Objects/stringlib/find.h', 'stringlib/stringdefs.h'), + # ('Objects/stringlib/partition.h', 'stringlib/stringdefs.h'), + # ('Objects/stringlib/split.h', 'stringlib/stringdefs.h'), + ('Objects/stringlib/fastsearch.h', 'stringlib/ucs1lib.h'), + ('Objects/stringlib/count.h', 'stringlib/ucs1lib.h'), + ('Objects/stringlib/find.h', 'stringlib/ucs1lib.h'), + ('Objects/stringlib/partition.h', 'stringlib/ucs1lib.h'), + ('Objects/stringlib/split.h', 'stringlib/ucs1lib.h'), + ('Objects/stringlib/find_max_char.h', 'Objects/stringlib/ucs1lib.h'), + ('Objects/stringlib/count.h', 'Objects/stringlib/fastsearch.h'), + ('Objects/stringlib/find.h', 'Objects/stringlib/fastsearch.h'), + ('Objects/stringlib/partition.h', 'Objects/stringlib/fastsearch.h'), + ('Objects/stringlib/replace.h', 'Objects/stringlib/fastsearch.h'), + ('Objects/stringlib/repr.h', 'Objects/stringlib/fastsearch.h'), + ('Objects/stringlib/split.h', 'Objects/stringlib/fastsearch.h'), +]) -glob name value +MACROS = format_tsv_lines([ + # (glob, name, value) -Include/internal/*.h Py_BUILD_CORE 1 -Python/**/*.c Py_BUILD_CORE 1 -Python/**/*.h Py_BUILD_CORE 1 -Parser/**/*.c Py_BUILD_CORE 1 -Parser/**/*.h Py_BUILD_CORE 1 -Objects/**/*.c Py_BUILD_CORE 1 -Objects/**/*.h Py_BUILD_CORE 1 + ('Include/internal/*.h', 'Py_BUILD_CORE', '1'), + ('Python/**/*.c', 'Py_BUILD_CORE', '1'), + ('Python/**/*.h', 'Py_BUILD_CORE', '1'), + ('Parser/**/*.c', 'Py_BUILD_CORE', '1'), + ('Parser/**/*.h', 'Py_BUILD_CORE', '1'), + ('Objects/**/*.c', 'Py_BUILD_CORE', '1'), + ('Objects/**/*.h', 'Py_BUILD_CORE', '1'), -Modules/_asynciomodule.c Py_BUILD_CORE 1 -Modules/_codecsmodule.c Py_BUILD_CORE 1 -Modules/_collectionsmodule.c Py_BUILD_CORE 1 -Modules/_ctypes/_ctypes.c Py_BUILD_CORE 1 -Modules/_ctypes/cfield.c Py_BUILD_CORE 1 -Modules/_cursesmodule.c Py_BUILD_CORE 1 -Modules/_datetimemodule.c Py_BUILD_CORE 1 -Modules/_functoolsmodule.c Py_BUILD_CORE 1 -Modules/_heapqmodule.c Py_BUILD_CORE 1 -Modules/_io/*.c Py_BUILD_CORE 1 -Modules/_io/*.h Py_BUILD_CORE 1 -Modules/_localemodule.c Py_BUILD_CORE 1 -Modules/_operator.c Py_BUILD_CORE 1 -Modules/_posixsubprocess.c Py_BUILD_CORE 1 -Modules/_sre/sre.c Py_BUILD_CORE 1 -Modules/_threadmodule.c Py_BUILD_CORE 1 -Modules/_tracemalloc.c Py_BUILD_CORE 1 -Modules/_weakref.c Py_BUILD_CORE 1 -Modules/_zoneinfo.c Py_BUILD_CORE 1 -Modules/atexitmodule.c Py_BUILD_CORE 1 -Modules/cmathmodule.c Py_BUILD_CORE 1 -Modules/faulthandler.c Py_BUILD_CORE 1 -Modules/gcmodule.c Py_BUILD_CORE 1 -Modules/getpath.c Py_BUILD_CORE 1 -Modules/getpath_noop.c Py_BUILD_CORE 1 -Modules/itertoolsmodule.c Py_BUILD_CORE 1 -Modules/main.c Py_BUILD_CORE 1 -Modules/mathmodule.c Py_BUILD_CORE 1 -Modules/posixmodule.c Py_BUILD_CORE 1 -Modules/sha256module.c Py_BUILD_CORE 1 -Modules/sha512module.c Py_BUILD_CORE 1 -Modules/signalmodule.c Py_BUILD_CORE 1 -Modules/symtablemodule.c Py_BUILD_CORE 1 -Modules/timemodule.c Py_BUILD_CORE 1 -Modules/unicodedata.c Py_BUILD_CORE 1 + ('Modules/_asynciomodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_codecsmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_collectionsmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_ctypes/_ctypes.c', 'Py_BUILD_CORE', '1'), + ('Modules/_ctypes/cfield.c', 'Py_BUILD_CORE', '1'), + ('Modules/_cursesmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_datetimemodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_functoolsmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_heapqmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_io/*.c', 'Py_BUILD_CORE', '1'), + ('Modules/_io/*.h', 'Py_BUILD_CORE', '1'), + ('Modules/_localemodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_operator.c', 'Py_BUILD_CORE', '1'), + ('Modules/_posixsubprocess.c', 'Py_BUILD_CORE', '1'), + ('Modules/_sre/sre.c', 'Py_BUILD_CORE', '1'), + ('Modules/_threadmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/_tracemalloc.c', 'Py_BUILD_CORE', '1'), + ('Modules/_weakref.c', 'Py_BUILD_CORE', '1'), + ('Modules/_zoneinfo.c', 'Py_BUILD_CORE', '1'), + ('Modules/atexitmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/cmathmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/faulthandler.c', 'Py_BUILD_CORE', '1'), + ('Modules/gcmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/getpath.c', 'Py_BUILD_CORE', '1'), + ('Modules/getpath_noop.c', 'Py_BUILD_CORE', '1'), + ('Modules/itertoolsmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/main.c', 'Py_BUILD_CORE', '1'), + ('Modules/mathmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/posixmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/sha256module.c', 'Py_BUILD_CORE', '1'), + ('Modules/sha512module.c', 'Py_BUILD_CORE', '1'), + ('Modules/signalmodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/symtablemodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/timemodule.c', 'Py_BUILD_CORE', '1'), + ('Modules/unicodedata.c', 'Py_BUILD_CORE', '1'), -Modules/_json.c Py_BUILD_CORE_BUILTIN 1 -Modules/_pickle.c Py_BUILD_CORE_BUILTIN 1 -Modules/_testinternalcapi.c Py_BUILD_CORE_BUILTIN 1 + ('Modules/_json.c', 'Py_BUILD_CORE_BUILTIN', '1'), + ('Modules/_pickle.c', 'Py_BUILD_CORE_BUILTIN', '1'), + ('Modules/_testinternalcapi.c', 'Py_BUILD_CORE_BUILTIN', '1'), -Include/cpython/abstract.h Py_CPYTHON_ABSTRACTOBJECT_H 1 -Include/cpython/bytearrayobject.h Py_CPYTHON_BYTEARRAYOBJECT_H 1 -Include/cpython/bytesobject.h Py_CPYTHON_BYTESOBJECT_H 1 -Include/cpython/ceval.h Py_CPYTHON_CEVAL_H 1 -Include/cpython/code.h Py_CPYTHON_CODE_H 1 -Include/cpython/dictobject.h Py_CPYTHON_DICTOBJECT_H 1 -Include/cpython/fileobject.h Py_CPYTHON_FILEOBJECT_H 1 -Include/cpython/fileutils.h Py_CPYTHON_FILEUTILS_H 1 -Include/cpython/frameobject.h Py_CPYTHON_FRAMEOBJECT_H 1 -Include/cpython/import.h Py_CPYTHON_IMPORT_H 1 -Include/cpython/interpreteridobject.h Py_CPYTHON_INTERPRETERIDOBJECT_H 1 -Include/cpython/listobject.h Py_CPYTHON_LISTOBJECT_H 1 -Include/cpython/methodobject.h Py_CPYTHON_METHODOBJECT_H 1 -Include/cpython/object.h Py_CPYTHON_OBJECT_H 1 -Include/cpython/objimpl.h Py_CPYTHON_OBJIMPL_H 1 -Include/cpython/pyerrors.h Py_CPYTHON_ERRORS_H 1 -Include/cpython/pylifecycle.h Py_CPYTHON_PYLIFECYCLE_H 1 -Include/cpython/pymem.h Py_CPYTHON_PYMEM_H 1 -Include/cpython/pystate.h Py_CPYTHON_PYSTATE_H 1 -Include/cpython/sysmodule.h Py_CPYTHON_SYSMODULE_H 1 -Include/cpython/traceback.h Py_CPYTHON_TRACEBACK_H 1 -Include/cpython/tupleobject.h Py_CPYTHON_TUPLEOBJECT_H 1 -Include/cpython/unicodeobject.h Py_CPYTHON_UNICODEOBJECT_H 1 + ('Include/cpython/abstract.h', 'Py_CPYTHON_ABSTRACTOBJECT_H', '1'), + ('Include/cpython/bytearrayobject.h', 'Py_CPYTHON_BYTEARRAYOBJECT_H', '1'), + ('Include/cpython/bytesobject.h', 'Py_CPYTHON_BYTESOBJECT_H', '1'), + ('Include/cpython/ceval.h', 'Py_CPYTHON_CEVAL_H', '1'), + ('Include/cpython/code.h', 'Py_CPYTHON_CODE_H', '1'), + ('Include/cpython/dictobject.h', 'Py_CPYTHON_DICTOBJECT_H', '1'), + ('Include/cpython/fileobject.h', 'Py_CPYTHON_FILEOBJECT_H', '1'), + ('Include/cpython/fileutils.h', 'Py_CPYTHON_FILEUTILS_H', '1'), + ('Include/cpython/frameobject.h', 'Py_CPYTHON_FRAMEOBJECT_H', '1'), + ('Include/cpython/import.h', 'Py_CPYTHON_IMPORT_H', '1'), + ('Include/cpython/interpreteridobject.h', 'Py_CPYTHON_INTERPRETERIDOBJECT_H', '1'), + ('Include/cpython/listobject.h', 'Py_CPYTHON_LISTOBJECT_H', '1'), + ('Include/cpython/methodobject.h', 'Py_CPYTHON_METHODOBJECT_H', '1'), + ('Include/cpython/object.h', 'Py_CPYTHON_OBJECT_H', '1'), + ('Include/cpython/objimpl.h', 'Py_CPYTHON_OBJIMPL_H', '1'), + ('Include/cpython/pyerrors.h', 'Py_CPYTHON_ERRORS_H', '1'), + ('Include/cpython/pylifecycle.h', 'Py_CPYTHON_PYLIFECYCLE_H', '1'), + ('Include/cpython/pymem.h', 'Py_CPYTHON_PYMEM_H', '1'), + ('Include/cpython/pystate.h', 'Py_CPYTHON_PYSTATE_H', '1'), + ('Include/cpython/sysmodule.h', 'Py_CPYTHON_SYSMODULE_H', '1'), + ('Include/cpython/traceback.h', 'Py_CPYTHON_TRACEBACK_H', '1'), + ('Include/cpython/tupleobject.h', 'Py_CPYTHON_TUPLEOBJECT_H', '1'), + ('Include/cpython/unicodeobject.h', 'Py_CPYTHON_UNICODEOBJECT_H', '1'), -# implied include of <unistd.h> -Include/**/*.h _POSIX_THREADS 1 -Include/**/*.h HAVE_PTHREAD_H 1 + # implied include of <unistd.h> + ('Include/**/*.h', '_POSIX_THREADS', '1'), + ('Include/**/*.h', 'HAVE_PTHREAD_H', '1'), -# from pyconfig.h -Include/cpython/pthread_stubs.h HAVE_PTHREAD_STUBS 1 -Python/thread_pthread_stubs.h HAVE_PTHREAD_STUBS 1 + # from pyconfig.h + ('Include/cpython/pthread_stubs.h', 'HAVE_PTHREAD_STUBS', '1'), + ('Python/thread_pthread_stubs.h', 'HAVE_PTHREAD_STUBS', '1'), -# from Objects/bytesobject.c -Objects/stringlib/partition.h STRINGLIB_GET_EMPTY() bytes_get_empty() -Objects/stringlib/join.h STRINGLIB_MUTABLE 0 -Objects/stringlib/partition.h STRINGLIB_MUTABLE 0 -Objects/stringlib/split.h STRINGLIB_MUTABLE 0 -Objects/stringlib/transmogrify.h STRINGLIB_MUTABLE 0 + # from Objects/bytesobject.c + ('Objects/stringlib/partition.h', 'STRINGLIB_GET_EMPTY()', 'bytes_get_empty()'), + ('Objects/stringlib/join.h', 'STRINGLIB_MUTABLE', '0'), + ('Objects/stringlib/partition.h', 'STRINGLIB_MUTABLE', '0'), + ('Objects/stringlib/split.h', 'STRINGLIB_MUTABLE', '0'), + ('Objects/stringlib/transmogrify.h', 'STRINGLIB_MUTABLE', '0'), -# from Makefile -Modules/getpath.c PYTHONPATH 1 -Modules/getpath.c PREFIX ... -Modules/getpath.c EXEC_PREFIX ... -Modules/getpath.c VERSION ... -Modules/getpath.c VPATH ... -Modules/getpath.c PLATLIBDIR ... -#Modules/_dbmmodule.c USE_GDBM_COMPAT 1 -Modules/_dbmmodule.c USE_NDBM 1 -#Modules/_dbmmodule.c USE_BERKDB 1 + # from Makefile + ('Modules/getpath.c', 'PYTHONPATH', '1'), + ('Modules/getpath.c', 'PREFIX', '...'), + ('Modules/getpath.c', 'EXEC_PREFIX', '...'), + ('Modules/getpath.c', 'VERSION', '...'), + ('Modules/getpath.c', 'VPATH', '...'), + ('Modules/getpath.c', 'PLATLIBDIR', '...'), + # ('Modules/_dbmmodule.c', 'USE_GDBM_COMPAT', '1'), + ('Modules/_dbmmodule.c', 'USE_NDBM', '1'), + # ('Modules/_dbmmodule.c', 'USE_BERKDB', '1'), -# See: setup.py -Modules/_decimal/**/*.c CONFIG_64 1 -Modules/_decimal/**/*.c ASM 1 -Modules/expat/xmlparse.c HAVE_EXPAT_CONFIG_H 1 -Modules/expat/xmlparse.c XML_POOR_ENTROPY 1 -Modules/_dbmmodule.c HAVE_GDBM_DASH_NDBM_H 1 + # See: setup.py + ('Modules/_decimal/**/*.c', 'CONFIG_64', '1'), + ('Modules/_decimal/**/*.c', 'ASM', '1'), + ('Modules/expat/xmlparse.c', 'HAVE_EXPAT_CONFIG_H', '1'), + ('Modules/expat/xmlparse.c', 'XML_POOR_ENTROPY', '1'), + ('Modules/_dbmmodule.c', 'HAVE_GDBM_DASH_NDBM_H', '1'), -# others -Modules/_sre/sre_lib.h LOCAL(type) static inline type -Modules/_sre/sre_lib.h SRE(F) sre_ucs2_##F -Objects/stringlib/codecs.h STRINGLIB_IS_UNICODE 1 -Include/internal/pycore_crossinterp_data_registry.h Py_CORE_CROSSINTERP_DATA_REGISTRY_H 1 - -# @end=tsv@ -''')[1:] + # others + ('Modules/_sre/sre_lib.h', 'LOCAL(type)', 'static inline type'), + ('Modules/_sre/sre_lib.h', 'SRE(F)', 'sre_ucs2_##F'), + ('Objects/stringlib/codecs.h', 'STRINGLIB_IS_UNICODE', '1'), + ('Include/internal/pycore_crossinterp_data_registry.h', 'Py_CORE_CROSSINTERP_DATA_REGISTRY_H', '1'), +]) # -pthread # -Wno-unused-result @@ -326,12 +316,12 @@ MAX_SIZES = { _abs('Modules/_testcapimodule.c'): (20_000, 400), _abs('Modules/expat/expat.h'): (10_000, 400), _abs('Objects/stringlib/unicode_format.h'): (10_000, 400), - _abs('Objects/typeobject.c'): (35_000, 200), + _abs('Objects/typeobject.c'): (380_000, 13_000), _abs('Python/compile.c'): (20_000, 500), _abs('Python/optimizer.c'): (100_000, 5_000), _abs('Python/parking_lot.c'): (40_000, 1000), - _abs('Python/pylifecycle.c'): (500_000, 5000), - _abs('Python/pystate.c'): (500_000, 5000), + _abs('Python/pylifecycle.c'): (750_000, 5000), + _abs('Python/pystate.c'): (750_000, 5000), _abs('Python/initconfig.c'): (50_000, 500), # Generated files: @@ -354,6 +344,10 @@ MAX_SIZES = { # Catch-alls: _abs('Include/**/*.h'): (5_000, 500), + + # Specific to clang + _abs('Modules/selectmodule.c'): (40_000, 3000), + _abs('Modules/_testcapi/pyatomic.c'): (30_000, 1000), } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 3c3cb2f9c86..301784f773d 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -400,6 +400,7 @@ Modules/_tkinter.c - tcl_lock - Modules/_tkinter.c - excInCmd - Modules/_tkinter.c - valInCmd - Modules/_tkinter.c - trbInCmd - +Modules/socketmodule.c - netdb_lock - ################################## diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 4fdb7b3cd1a..adb183000de 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -16,6 +16,7 @@ filename funcname name reason ## indicators for resource availability/capability # (set during first init) Python/bootstrap_hash.c py_getrandom getrandom_works - +Python/bootstrap_hash.c py_getentropy getentropy_works - Python/fileutils.c - _Py_open_cloexec_works - Python/fileutils.c set_inheritable ioctl_works - # (set lazily, *after* first init) @@ -24,6 +25,7 @@ Modules/posixmodule.c os_dup2_impl dup3_works - ## guards around resource init Python/thread_pthread.h PyThread__init_thread lib_initialized - +Modules/_struct.c - endian_tables_init_once - ##----------------------- ## other values (not Python-specific) @@ -56,7 +58,7 @@ Python/pyhash.c - _Py_HashSecret - Python/parking_lot.c - buckets - ## data needed for introspecting asyncio state from debuggers and profilers -Modules/_asynciomodule.c - _AsyncioDebug - +Modules/_asynciomodule.c - _Py_AsyncioDebug - ################################## @@ -194,6 +196,7 @@ Python/pyfpe.c - PyFPE_counter - Python/import.c - pkgcontext - Python/pystate.c - _Py_tss_tstate - Python/pystate.c - _Py_tss_gilstate - +Python/pystate.c - _Py_tss_interp - ##----------------------- ## should be const @@ -344,6 +347,8 @@ Objects/obmalloc.c - obmalloc_state_main - Objects/obmalloc.c - obmalloc_state_initialized - Objects/typeobject.c - name_op - Objects/typeobject.c - slotdefs - +# It initialized only once when main interpeter starts +Objects/typeobject.c - slotdefs_name_counts - Objects/unicodeobject.c - stripfuncnames - Objects/unicodeobject.c - utf7_category - Objects/unicodeobject.c unicode_decode_call_errorhandler_wchar argparse - @@ -355,6 +360,7 @@ Parser/parser.c - soft_keywords - Parser/lexer/lexer.c - type_comment_prefix - Python/ceval.c - _PyEval_BinaryOps - Python/ceval.c - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS - +Python/ceval.c - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR - Python/codecs.c - Py_hexdigits - Python/codecs.c - codecs_builtin_error_handlers - Python/codecs.c - ucnhash_capi - diff --git a/Tools/c-analyzer/distutils/util.py b/Tools/c-analyzer/distutils/util.py index 89ca094336f..f687a28ec2f 100644 --- a/Tools/c-analyzer/distutils/util.py +++ b/Tools/c-analyzer/distutils/util.py @@ -19,8 +19,8 @@ def get_host_platform(): particularly important. Examples of returned values: - linux-i586 - linux-alpha (?) + linux-x86_64 + linux-aarch64 solaris-2.6-sun4u Windows will return one of: diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 9dd7e5dbfba..fcd0dcf12ac 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -3,10 +3,12 @@ import itertools import lexer import parser import re -from typing import Optional, Callable +from typing import Optional, Callable, Iterator from parser import Stmt, SimpleStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, MacroIfStmt +MAX_CACHED_REGISTER = 3 + @dataclass class EscapingCall: stmt: SimpleStmt @@ -26,14 +28,17 @@ class Properties: eval_breaker: bool needs_this: bool always_exits: bool - stores_sp: bool + sync_sp: bool uses_co_consts: bool uses_co_names: bool uses_locals: bool has_free: bool side_exit: bool + side_exit_at_end: bool pure: bool uses_opcode: bool + needs_guard_ip: bool + unpredictable_jump: bool tier: int | None = None const_oparg: int = -1 needs_prev: bool = False @@ -65,16 +70,19 @@ class Properties: eval_breaker=any(p.eval_breaker for p in properties), needs_this=any(p.needs_this for p in properties), always_exits=any(p.always_exits for p in properties), - stores_sp=any(p.stores_sp for p in properties), + sync_sp=any(p.sync_sp for p in properties), uses_co_consts=any(p.uses_co_consts for p in properties), uses_co_names=any(p.uses_co_names for p in properties), uses_locals=any(p.uses_locals for p in properties), uses_opcode=any(p.uses_opcode for p in properties), has_free=any(p.has_free for p in properties), side_exit=any(p.side_exit for p in properties), + side_exit_at_end=any(p.side_exit_at_end for p in properties), pure=all(p.pure for p in properties), needs_prev=any(p.needs_prev for p in properties), no_save_ip=all(p.no_save_ip for p in properties), + needs_guard_ip=any(p.needs_guard_ip for p in properties), + unpredictable_jump=any(p.unpredictable_jump for p in properties), ) @property @@ -93,15 +101,18 @@ SKIP_PROPERTIES = Properties( eval_breaker=False, needs_this=False, always_exits=False, - stores_sp=False, + sync_sp=False, uses_co_consts=False, uses_co_names=False, uses_locals=False, uses_opcode=False, has_free=False, side_exit=False, + side_exit_at_end=False, pure=True, no_save_ip=False, + needs_guard_ip=False, + unpredictable_jump=False, ) @@ -608,6 +619,8 @@ NON_ESCAPING_FUNCTIONS = ( "PyUnicode_Concat", "PyUnicode_GET_LENGTH", "PyUnicode_READ_CHAR", + "PyUnicode_IS_COMPACT_ASCII", + "PyUnicode_1BYTE_DATA", "Py_ARRAY_LENGTH", "Py_FatalError", "Py_INCREF", @@ -621,7 +634,6 @@ NON_ESCAPING_FUNCTIONS = ( "_PyCode_CODE", "_PyDictValues_AddToInsertionOrder", "_PyErr_Occurred", - "_PyFloat_FromDouble_ConsumeInputs", "_PyFrame_GetBytecode", "_PyFrame_GetCode", "_PyFrame_IsIncomplete", @@ -692,6 +704,12 @@ NON_ESCAPING_FUNCTIONS = ( "PyStackRef_Wrap", "PyStackRef_Unwrap", "_PyLong_CheckExactAndCompact", + "_PyExecutor_FromExit", + "_PyJit_TryInitializeTracing", + "_Py_unset_eval_breaker_bit", + "_Py_set_eval_breaker_bit", + "trigger_backoff_counter", + "_PyThreadState_PopCStackRefSteal", ) @@ -882,6 +900,46 @@ def stmt_escapes(stmt: Stmt) -> bool: else: assert False, "Unexpected statement type" +def stmt_has_jump_on_unpredictable_path_body(stmts: list[Stmt] | None, branches_seen: int) -> tuple[bool, int]: + if not stmts: + return False, branches_seen + predict = False + seen = 0 + for st in stmts: + predict_body, seen_body = stmt_has_jump_on_unpredictable_path(st, branches_seen) + predict = predict or predict_body + seen += seen_body + return predict, seen + +def stmt_has_jump_on_unpredictable_path(stmt: Stmt, branches_seen: int) -> tuple[bool, int]: + if isinstance(stmt, BlockStmt): + return stmt_has_jump_on_unpredictable_path_body(stmt.body, branches_seen) + elif isinstance(stmt, SimpleStmt): + for tkn in stmt.contents: + if tkn.text == "JUMPBY": + return True, branches_seen + return False, branches_seen + elif isinstance(stmt, IfStmt): + predict, seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen) + if stmt.else_body: + predict_else, seen_else = stmt_has_jump_on_unpredictable_path(stmt.else_body, branches_seen) + return predict != predict_else, seen + seen_else + 1 + return predict, seen + 1 + elif isinstance(stmt, MacroIfStmt): + predict, seen = stmt_has_jump_on_unpredictable_path_body(stmt.body, branches_seen) + if stmt.else_body: + predict_else, seen_else = stmt_has_jump_on_unpredictable_path_body(stmt.else_body, branches_seen) + return predict != predict_else, seen + seen_else + return predict, seen + elif isinstance(stmt, ForStmt): + unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen) + return unpredictable, branches_seen + 1 + elif isinstance(stmt, WhileStmt): + unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen) + return unpredictable, branches_seen + 1 + else: + assert False, f"Unexpected statement type {stmt}" + def compute_properties(op: parser.CodeDef) -> Properties: escaping_calls = find_escaping_api_calls(op) @@ -892,7 +950,8 @@ def compute_properties(op: parser.CodeDef) -> Properties: or variable_used(op, "PyCell_SwapTakeRef") ) deopts_if = variable_used(op, "DEOPT_IF") - exits_if = variable_used(op, "EXIT_IF") or variable_used(op, "AT_END_EXIT_IF") + exits_if = variable_used(op, "EXIT_IF") + exit_if_at_end = variable_used(op, "AT_END_EXIT_IF") deopts_periodic = variable_used(op, "HANDLE_PENDING_AND_DEOPT_IF") exits_and_deopts = sum((deopts_if, exits_if, deopts_periodic)) if exits_and_deopts > 1: @@ -909,6 +968,8 @@ def compute_properties(op: parser.CodeDef) -> Properties: escapes = stmt_escapes(op.block) pure = False if isinstance(op, parser.LabelDef) else "pure" in op.annotations no_save_ip = False if isinstance(op, parser.LabelDef) else "no_save_ip" in op.annotations + unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(op.block, 0) + unpredictable_jump = False if isinstance(op, parser.LabelDef) else (unpredictable and branches_seen > 0) return Properties( escaping_calls=escaping_calls, escapes=escapes, @@ -917,12 +978,13 @@ def compute_properties(op: parser.CodeDef) -> Properties: deopts=deopts_if, deopts_periodic=deopts_periodic, side_exit=exits_if, + side_exit_at_end=exit_if_at_end, oparg=oparg_used(op), jumps=variable_used(op, "JUMPBY"), eval_breaker="CHECK_PERIODIC" in op.name, needs_this=variable_used(op, "this_instr"), always_exits=always_exits(op), - stores_sp=variable_used(op, "SYNC_SP"), + sync_sp=variable_used(op, "SYNC_SP"), uses_co_consts=variable_used(op, "FRAME_CO_CONSTS"), uses_co_names=variable_used(op, "FRAME_CO_NAMES"), uses_locals=variable_used(op, "GETLOCAL") and not has_free, @@ -932,6 +994,11 @@ def compute_properties(op: parser.CodeDef) -> Properties: no_save_ip=no_save_ip, tier=tier_variable(op), needs_prev=variable_used(op, "prev_instr"), + needs_guard_ip=(isinstance(op, parser.InstDef) + and (unpredictable_jump and "replaced" not in op.annotations)) + or variable_used(op, "LOAD_IP") + or variable_used(op, "DISPATCH_INLINED"), + unpredictable_jump=unpredictable_jump, ) def expand(items: list[StackItem], oparg: int) -> list[StackItem]: @@ -1137,8 +1204,9 @@ def assign_opcodes( # This is an historical oddity. instmap["BINARY_OP_INPLACE_ADD_UNICODE"] = 3 - instmap["INSTRUMENTED_LINE"] = 254 - instmap["ENTER_EXECUTOR"] = 255 + instmap["INSTRUMENTED_LINE"] = 253 + instmap["ENTER_EXECUTOR"] = 254 + instmap["TRACE_RECORD"] = 255 instrumented = [name for name in instructions if name.startswith("INSTRUMENTED")] @@ -1163,7 +1231,7 @@ def assign_opcodes( # Specialized ops appear in their own section # Instrumented opcodes are at the end of the valid range min_internal = instmap["RESUME"] + 1 - min_instrumented = 254 - (len(instrumented) - 1) + min_instrumented = 254 - len(instrumented) assert min_internal + len(specialized) < min_instrumented next_opcode = 1 @@ -1281,6 +1349,59 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis: ) +#Simple heuristic for size to avoid too much stencil duplication +def is_large(uop: Uop) -> bool: + return len(list(uop.body.tokens())) > 120 + + +def get_uop_cache_depths(uop: Uop) -> Iterator[tuple[int, int, int]]: + if uop.name == "_SPILL_OR_RELOAD": + for inputs in range(MAX_CACHED_REGISTER+1): + for outputs in range(MAX_CACHED_REGISTER+1): + if inputs != outputs: + yield inputs, outputs, inputs + return + if uop.name in ("_DEOPT", "_HANDLE_PENDING_AND_DEOPT", "_EXIT_TRACE", "_DYNAMIC_EXIT"): + for i in range(MAX_CACHED_REGISTER+1): + yield i, 0, 0 + return + if uop.name in ("_START_EXECUTOR", "_JUMP_TO_TOP", "_COLD_EXIT"): + yield 0, 0, 0 + return + if uop.name == "_ERROR_POP_N": + yield 0, 0, 0 + return + ideal_inputs = 0 + has_array = False + for item in reversed(uop.stack.inputs): + if item.size: + has_array = True + break + ideal_inputs += 1 + ideal_outputs = 0 + for item in reversed(uop.stack.outputs): + if item.size: + has_array = True + break + ideal_outputs += 1 + if ideal_inputs > MAX_CACHED_REGISTER: + ideal_inputs = MAX_CACHED_REGISTER + if ideal_outputs > MAX_CACHED_REGISTER: + ideal_outputs = MAX_CACHED_REGISTER + at_end = uop.properties.sync_sp or uop.properties.side_exit_at_end + exit_depth = ideal_outputs if at_end else ideal_inputs + if uop.properties.escapes or uop.properties.sync_sp or has_array or is_large(uop): + yield ideal_inputs, ideal_outputs, exit_depth + return + for inputs in range(MAX_CACHED_REGISTER + 1): + outputs = ideal_outputs - ideal_inputs + inputs + if outputs < ideal_outputs: + outputs = ideal_outputs + elif outputs > MAX_CACHED_REGISTER: + continue + yield inputs, outputs, outputs if at_end else inputs + + def analyze_files(filenames: list[str]) -> Analysis: return analyze_forest(parser.parse_files(filenames)) diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index cc0edcdf600..89bd801c61a 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -7,6 +7,7 @@ from analyzer import ( analysis_error, Label, CodeSection, + Uop, ) from cwriter import CWriter from typing import Callable, TextIO, Iterator, Iterable @@ -107,8 +108,9 @@ class Emitter: labels: dict[str, Label] _replacers: dict[str, ReplacementFunctionType] cannot_escape: bool + jump_prefix: str - def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool = False): + def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool = False, jump_prefix: str = ""): self._replacers = { "EXIT_IF": self.exit_if, "AT_END_EXIT_IF": self.exit_if_after, @@ -127,10 +129,15 @@ class Emitter: "DISPATCH": self.dispatch, "INSTRUCTION_SIZE": self.instruction_size, "stack_pointer": self.stack_pointer, + "Py_UNREACHABLE": self.unreachable, + "TIER1_TO_TIER2": self.tier1_to_tier2, + "TIER2_TO_TIER2": self.tier2_to_tier2, + "GOTO_TIER_ONE": self.goto_tier_one } self.out = out self.labels = labels self.cannot_escape = cannot_escape + self.jump_prefix = jump_prefix def dispatch( self, @@ -146,6 +153,19 @@ class Emitter: self.emit(tkn) return False + def unreachable( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + self.emit(tkn) + emit_to(self.out, tkn_iter, "SEMI") + self.emit(";\n") + return False + def deopt_if( self, tkn: Token, @@ -167,7 +187,7 @@ class Emitter: family_name = inst.family.name self.emit(f"UPDATE_MISS_STATS({family_name});\n") self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n") - self.emit(f"JUMP_TO_PREDICTED({family_name});\n") + self.emit(f"JUMP_TO_PREDICTED({self.jump_prefix}{family_name});\n") self.emit("}\n") return not always_true(first_tkn) @@ -196,12 +216,22 @@ class Emitter: storage.stack.clear(self.out) return self.exit_if(tkn, tkn_iter, uop, storage, inst) + def goto_tier_one( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + raise NotImplementedError("GOTO_TIER_ONE not supported in tier 1") + def goto_error(self, offset: int, storage: Storage) -> str: if offset > 0: - return f"JUMP_TO_LABEL(pop_{offset}_error);" + return f"{self.jump_prefix}JUMP_TO_LABEL(pop_{offset}_error);" if offset < 0: storage.copy().flush(self.out) - return f"JUMP_TO_LABEL(error);" + return f"{self.jump_prefix}JUMP_TO_LABEL(error);" def error_if( self, @@ -238,6 +268,24 @@ class Emitter: self.out.emit("}\n") return not unconditional + def tier1_to_tier2( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + self.out.emit(tkn) + lparen = next(tkn_iter) + assert lparen.kind == "LPAREN" + self.emit(lparen) + emit_to(self.out, tkn_iter, "RPAREN") + self.out.emit(")") + return False + + tier2_to_tier2 = tier1_to_tier2 + def error_no_pop( self, tkn: Token, @@ -421,7 +469,7 @@ class Emitter: elif storage.spilled: raise analysis_error("Cannot jump from spilled label without reloading the stack pointer", goto) self.out.start_line() - self.out.emit("JUMP_TO_LABEL(") + self.out.emit(f"{self.jump_prefix}JUMP_TO_LABEL(") self.out.emit(label) self.out.emit(")") @@ -470,7 +518,7 @@ class Emitter: """Replace the INSTRUCTION_SIZE macro with the size of the current instruction.""" if uop.instruction_size is None: raise analysis_error("The INSTRUCTION_SIZE macro requires uop.instruction_size to be set", tkn) - self.out.emit(f" {uop.instruction_size} ") + self.out.emit(f" {uop.instruction_size}u ") return True def _print_storage(self, reason:str, storage: Storage) -> None: @@ -558,10 +606,10 @@ class Emitter: self.out.emit(stmt.condition) branch = stmt.else_ is not None reachable = True - if branch: - else_storage = storage.copy() + if_storage = storage + else_storage = storage.copy() for s in stmt.body: - r, tkn, storage = self._emit_stmt(s, uop, storage, inst) + r, tkn, if_storage = self._emit_stmt(s, uop, if_storage, inst) if tkn is not None: self.out.emit(tkn) if not r: @@ -576,7 +624,10 @@ class Emitter: self.out.emit(tkn) if not r: reachable = False - else_storage.merge(storage, self.out) # type: ignore[possibly-undefined] + else_storage.merge(if_storage, self.out) + storage = if_storage + else: + if_storage.merge(else_storage, self.out) storage = else_storage self.out.emit(stmt.endif) return reachable, None, storage @@ -719,7 +770,7 @@ def cflags(p: Properties) -> str: flags.append("HAS_DEOPT_FLAG") if p.deopts_periodic: flags.append("HAS_PERIODIC_FLAG") - if p.side_exit: + if p.side_exit or p.side_exit_at_end: flags.append("HAS_EXIT_FLAG") if not p.infallible: flags.append("HAS_ERROR_FLAG") @@ -731,6 +782,12 @@ def cflags(p: Properties) -> str: flags.append("HAS_PURE_FLAG") if p.no_save_ip: flags.append("HAS_NO_SAVE_IP_FLAG") + if p.sync_sp: + flags.append("HAS_SYNC_SP_FLAG") + if p.unpredictable_jump: + flags.append("HAS_UNPREDICTABLE_JUMP_FLAG") + if p.needs_guard_ip: + flags.append("HAS_NEEDS_GUARD_IP_FLAG") if flags: return " | ".join(flags) else: diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index b649b381233..a0664cdfde1 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -53,9 +53,12 @@ FLAGS = [ "ESCAPES", "EXIT", "PURE", + "SYNC_SP", "ERROR_NO_POP", "NO_SAVE_IP", "PERIODIC", + "UNPREDICTABLE_JUMP", + "NEEDS_GUARD_IP", ] @@ -201,7 +204,7 @@ def generate_metadata_table(analysis: Analysis, out: CWriter) -> None: out.emit("struct opcode_metadata {\n") out.emit("uint8_t valid_entry;\n") out.emit("uint8_t instr_format;\n") - out.emit("uint16_t flags;\n") + out.emit("uint32_t flags;\n") out.emit("};\n\n") out.emit( f"extern const struct opcode_metadata _PyOpcode_opcode_metadata[{table_size}];\n" diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py index b9985eaf483..ab0a90e234b 100644 --- a/Tools/cases_generator/optimizer_generator.py +++ b/Tools/cases_generator/optimizer_generator.py @@ -190,6 +190,7 @@ class OptimizerEmitter(Emitter): input_identifiers_as_str = {tkn.text for tkn in input_identifiers} used_stack_inputs = [inp for inp in uop.stack.inputs if inp.name in input_identifiers_as_str] assert len(used_stack_inputs) > 0 + self.out.start_line() emitter = OptimizerConstantEmitter(self.out, {}, self.original_uop, self.stack.copy()) emitter.emit("if (\n") for inp in used_stack_inputs[:-1]: @@ -232,18 +233,28 @@ class OptimizerEmitter(Emitter): emitter.emit(f"{outp.name} = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal({outp.name}_stackref));\n") else: emitter.emit(f"{outp.name} = sym_new_const(ctx, PyStackRef_AsPyObjectBorrow({outp.name}_stackref));\n") + if len(self.original_uop.stack.outputs) == 1: + outp = self.original_uop.stack.outputs[0] + if not outp.peek: + if self.original_uop.name.startswith('_'): + # Map input count to the appropriate constant-loading uop + input_count_to_uop = { + 1: "_POP_TOP_LOAD_CONST_INLINE_BORROW", + 2: "_POP_TWO_LOAD_CONST_INLINE_BORROW" + } - if len(used_stack_inputs) == 2 and len(self.original_uop.stack.outputs) == 1: - outp = self.original_uop.stack.outputs[0] - if not outp.peek: - emitter.emit(f""" - if (sym_is_const(ctx, {outp.name})) {{ - PyObject *result = sym_get_const(ctx, {outp.name}); - if (_Py_IsImmortal(result)) {{ - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - }} - }}""") + input_count = len(used_stack_inputs) + if input_count in input_count_to_uop: + replacement_uop = input_count_to_uop[input_count] + input_desc = "one input" if input_count == 1 else "two inputs" + + emitter.emit(f"if (sym_is_const(ctx, {outp.name})) {{\n") + emitter.emit(f"PyObject *result = sym_get_const(ctx, {outp.name});\n") + emitter.emit(f"if (_Py_IsImmortal(result)) {{\n") + emitter.emit(f"// Replace with {replacement_uop} since we have {input_desc} and an immortal result\n") + emitter.emit(f"REPLACE_OP(this_instr, {replacement_uop}, 0, (uintptr_t)result);\n") + emitter.emit("}\n") + emitter.emit("}\n") storage.flush(self.out) emitter.emit("break;\n") @@ -434,7 +445,7 @@ def generate_abstract_interpreter( declare_variables(override, out, skip_inputs=False) else: declare_variables(uop, out, skip_inputs=True) - stack = Stack() + stack = Stack(check_stack_bounds=True) write_uop(override, uop, out, stack, debug, skip_inputs=(override is None)) out.start_line() out.emit("break;\n") diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index 3a0e7e5d0d5..efc534fb607 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -216,11 +216,18 @@ def array_or_scalar(var: StackItem | Local) -> str: return "array" if var.is_array() else "scalar" class Stack: - def __init__(self) -> None: + def __init__(self, check_stack_bounds: bool = False) -> None: self.base_offset = PointerOffset.zero() self.physical_sp = PointerOffset.zero() self.logical_sp = PointerOffset.zero() self.variables: list[Local] = [] + self.check_stack_bounds = check_stack_bounds + + def push_cache(self, cached_items:list[str], out: CWriter) -> None: + for i, name in enumerate(cached_items): + out.start_line() + out.emit(f"_PyStackRef _stack_item_{i} = {name};\n") + self.push(Local.register(f"_stack_item_{i}")) def drop(self, var: StackItem, check_liveness: bool) -> None: self.logical_sp = self.logical_sp.pop(var) @@ -296,7 +303,7 @@ class Stack: diff = self.logical_sp - self.physical_sp out.start_line() out.emit(f"stack_pointer += {diff.to_c()};\n") - out.emit(f"assert(WITHIN_STACK_BOUNDS());\n") + out.emit(f"ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);\n") self.physical_sp = self.logical_sp self._print(out) @@ -316,8 +323,17 @@ class Stack: self._print(out) var_offset = var_offset.push(var.item) + def stack_bound_check(self, out: CWriter) -> None: + if not self.check_stack_bounds: + return + if self.physical_sp != self.logical_sp: + diff = self.logical_sp - self.physical_sp + out.start_line() + out.emit(f"CHECK_STACK_BOUNDS({diff});\n") + def flush(self, out: CWriter) -> None: self._print(out) + self.stack_bound_check(out) self.save_variables(out) self._save_physical_sp(out) out.start_line() @@ -347,6 +363,7 @@ class Stack: other.physical_sp = self.physical_sp other.logical_sp = self.logical_sp other.variables = [var.copy() for var in self.variables] + other.check_stack_bounds = self.check_stack_bounds return other def __eq__(self, other: object) -> bool: @@ -475,7 +492,7 @@ class Storage: def _push_defined_outputs(self) -> None: defined_output = "" for output in self.outputs: - if output.in_local and not output.memory_offset: + if output.in_local and not output.memory_offset and not output.item.peek: defined_output = output.name if not defined_output: return @@ -499,6 +516,7 @@ class Storage: return False def flush(self, out: CWriter) -> None: + self._print(out) self.clear_dead_inputs() self._push_defined_outputs() self.stack.flush(out) diff --git a/Tools/cases_generator/target_generator.py b/Tools/cases_generator/target_generator.py index ca151ff640a..f633f704485 100644 --- a/Tools/cases_generator/target_generator.py +++ b/Tools/cases_generator/target_generator.py @@ -26,19 +26,31 @@ def write_opcode_targets(analysis: Analysis, out: CWriter) -> None: for name, op in analysis.opmap.items(): if op < 256: targets[op] = f"&&TARGET_{name},\n" - out.emit("#if !Py_TAIL_CALL_INTERP\n") - out.emit("static void *opcode_targets[256] = {\n") + out.emit("#if !_Py_TAIL_CALL_INTERP\n") + out.emit("static void *opcode_targets_table[256] = {\n") for target in targets: out.emit(target) out.emit("};\n") - out.emit("#else /* Py_TAIL_CALL_INTERP */\n") + targets = ["&&_unknown_opcode,\n"] * 256 + for name, op in analysis.opmap.items(): + if op < 256: + targets[op] = f"&&TARGET_TRACE_RECORD,\n" + out.emit("#if _Py_TIER2\n") + out.emit("static void *opcode_tracing_targets_table[256] = {\n") + for target in targets: + out.emit(target) + out.emit("};\n") + out.emit(f"#endif\n") + out.emit("#else /* _Py_TAIL_CALL_INTERP */\n") def function_proto(name: str) -> str: return f"Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_{name}(TAIL_CALL_PARAMS)" def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None: - out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256];\n") + out.emit("static py_tail_call_funcptr instruction_funcptr_handler_table[256];\n") + out.emit("\n") + out.emit("static py_tail_call_funcptr instruction_funcptr_tracing_table[256];\n") out.emit("\n") # Emit function prototypes for labels. @@ -60,7 +72,7 @@ def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None: out.emit("\n") # Emit the dispatch table. - out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {\n") + out.emit("static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {\n") for name in sorted(analysis.instructions.keys()): out.emit(f"[{name}] = _TAIL_CALL_{name},\n") named_values = analysis.opmap.values() @@ -68,7 +80,17 @@ def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None: if rest not in named_values: out.emit(f"[{rest}] = _TAIL_CALL_UNKNOWN_OPCODE,\n") out.emit("};\n") - outfile.write("#endif /* Py_TAIL_CALL_INTERP */\n") + + # Emit the tracing dispatch table. + out.emit("static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {\n") + for name in sorted(analysis.instructions.keys()): + out.emit(f"[{name}] = _TAIL_CALL_TRACE_RECORD,\n") + named_values = analysis.opmap.values() + for rest in range(256): + if rest not in named_values: + out.emit(f"[{rest}] = _TAIL_CALL_UNKNOWN_OPCODE,\n") + out.emit("};\n") + outfile.write("#endif /* _Py_TAIL_CALL_INTERP */\n") arg_parser = argparse.ArgumentParser( description="Generate the file with dispatch targets.", diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index 2fc6794f6a0..c7ff5de681e 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -157,20 +157,20 @@ def generate_tier1( #define TIER_ONE 1 """) outfile.write(f""" -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP #if !USE_COMPUTED_GOTOS dispatch_opcode: - switch (opcode) + switch (dispatch_code) #endif {{ -#endif /* Py_TAIL_CALL_INTERP */ +#endif /* _Py_TAIL_CALL_INTERP */ {INSTRUCTION_START_MARKER} """ ) generate_tier1_cases(analysis, outfile, lines) outfile.write(f""" {INSTRUCTION_END_MARKER} -#if !Py_TAIL_CALL_INTERP +#if !_Py_TAIL_CALL_INTERP #if USE_COMPUTED_GOTOS _unknown_opcode: #else @@ -186,7 +186,7 @@ def generate_tier1( /* This should never be reached. Every opcode should end with DISPATCH() or goto error. */ Py_UNREACHABLE(); -#endif /* Py_TAIL_CALL_INTERP */ +#endif /* _Py_TAIL_CALL_INTERP */ {LABEL_START_MARKER} """) out = CWriter(outfile, 2, lines) @@ -226,7 +226,7 @@ def generate_tier1_cases( popped = get_popped(inst, analysis) # We need to ifdef it because this breaks platforms # without computed gotos/tail calling. - out.emit(f"#if Py_TAIL_CALL_INTERP\n") + out.emit(f"#if _Py_TAIL_CALL_INTERP\n") out.emit(f"int opcode = {name};\n") out.emit(f"(void)(opcode);\n") out.emit(f"#endif\n") diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index 1bb5f48658d..9dc529753de 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -14,7 +14,11 @@ from analyzer import ( analyze_files, StackItem, analysis_error, + get_uop_cache_depths, + is_large, + MAX_CACHED_REGISTER, ) + from generators_common import ( DEFAULT_INPUT, ROOT, @@ -60,36 +64,20 @@ def declare_variables(uop: Uop, out: CWriter) -> None: class Tier2Emitter(Emitter): - def __init__(self, out: CWriter, labels: dict[str, Label]): + def __init__(self, out: CWriter, labels: dict[str, Label], exit_cache_depth: int): super().__init__(out, labels) self._replacers["oparg"] = self.oparg + self._replacers["IP_OFFSET_OF"] = self.ip_offset_of + self.exit_cache_depth = exit_cache_depth def goto_error(self, offset: int, storage: Storage) -> str: # To do: Add jump targets for popping values. if offset != 0: storage.copy().flush(self.out) - return f"JUMP_TO_ERROR();" - - def deopt_if( - self, - tkn: Token, - tkn_iter: TokenIterator, - uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: - self.out.emit_at("if ", tkn) - lparen = next(tkn_iter) - self.emit(lparen) - assert lparen.kind == "LPAREN" - first_tkn = tkn_iter.peek() - emit_to(self.out, tkn_iter, "RPAREN") - next(tkn_iter) # Semi colon - self.emit(") {\n") - self.emit("UOP_STAT_INC(uopcode, miss);\n") - self.emit("JUMP_TO_JUMP_TARGET();\n") - self.emit("}\n") - return not always_true(first_tkn) + else: + storage.stack.copy().flush(self.out) + self.emit("SET_CURRENT_CACHED_VALUES(0);\n") + return "JUMP_TO_ERROR();" def exit_if( self, @@ -107,11 +95,14 @@ class Tier2Emitter(Emitter): next(tkn_iter) # Semi colon self.emit(") {\n") self.emit("UOP_STAT_INC(uopcode, miss);\n") + storage = storage.copy() + self.cache_items(storage.stack, self.exit_cache_depth, False) + storage.stack.flush(self.out) self.emit("JUMP_TO_JUMP_TARGET();\n") self.emit("}\n") return not always_true(first_tkn) - periodic_if = deopt_if + periodic_if = deopt_if = exit_if def oparg( self, @@ -134,10 +125,94 @@ class Tier2Emitter(Emitter): self.out.emit_at(uop.name[-1], tkn) return True + def ip_offset_of( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + assert uop.name.startswith("_GUARD_IP") + # LPAREN + next(tkn_iter) + tok = next(tkn_iter) + self.emit(f" OFFSET_OF_{tok.text};\n") + # RPAREN + next(tkn_iter) + # SEMI + next(tkn_iter) + return True -def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack: + def tier2_to_tier2( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + assert self.exit_cache_depth == 0, uop.name + self.cache_items(storage.stack, self.exit_cache_depth, False) + storage.flush(self.out) + self.out.emit(tkn) + lparen = next(tkn_iter) + assert lparen.kind == "LPAREN" + self.emit(lparen) + emit_to(self.out, tkn_iter, "RPAREN") + self.out.emit(")") + return False + + goto_tier_one = tier2_to_tier2 + + def exit_if_after( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + self.out.emit_at("if ", tkn) + lparen = next(tkn_iter) + self.emit(lparen) + first_tkn = tkn_iter.peek() + emit_to(self.out, tkn_iter, "RPAREN") + next(tkn_iter) # Semi colon + self.emit(") {\n") + self.emit("UOP_STAT_INC(uopcode, miss);\n") + storage = storage.copy() + storage.clear_inputs("in AT_END_EXIT_IF") + self.cache_items(storage.stack, self.exit_cache_depth, False) + storage.flush(self.out) + self.emit("JUMP_TO_JUMP_TARGET();\n") + self.emit("}\n") + return not always_true(first_tkn) + + def cache_items(self, stack: Stack, cached_items: int, zero_regs: bool) -> None: + self.out.start_line() + i = cached_items + while i > 0: + self.out.start_line() + item = StackItem(f"_tos_cache{i-1}", "", False, True) + stack.pop(item, self.out) + i -= 1 + if zero_regs: + # TO DO -- For compilers that support it, + # replace this with a "clobber" to tell + # the compiler that these values are unused + # without having to emit any code. + for i in range(cached_items, MAX_CACHED_REGISTER): + self.out.emit(f"_tos_cache{i} = PyStackRef_ZERO_BITS;\n") + self.emit(f"SET_CURRENT_CACHED_VALUES({cached_items});\n") + + +def write_uop(uop: Uop, emitter: Tier2Emitter, stack: Stack, offset_strs: dict[str, tuple[str, str]], cached_items: int = 0) -> tuple[bool, Stack]: locals: dict[str, Local] = {} + zero_regs = is_large(uop) or uop.properties.escapes try: + if name_offset_pair := offset_strs.get(uop.name): + emitter.emit(f"#define OFFSET_OF_{name_offset_pair[0]} ({name_offset_pair[1]})\n") emitter.out.start_line() if uop.properties.oparg: emitter.emit("oparg = CURRENT_OPARG();\n") @@ -149,21 +224,55 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack: idx = 0 for cache in uop.caches: if cache.name != "unused": + bits = cache.size*16 if cache.size == 4: type = cast = "PyObject *" else: - type = f"uint{cache.size*16}_t " - cast = f"uint{cache.size*16}_t" - emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND{idx}();\n") + type = f"uint{bits}_t " + cast = f"uint{bits}_t" + emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND{idx}_{bits}();\n") idx += 1 - _, storage = emitter.emit_tokens(uop, storage, None, False) - storage.flush(emitter.out) + reachable, storage = emitter.emit_tokens(uop, storage, None, False) + if reachable: + storage.stack._print(emitter.out) + emitter.cache_items(storage.stack, cached_items, zero_regs) + storage.flush(emitter.out) + if name_offset_pair: + emitter.emit(f"#undef OFFSET_OF_{name_offset_pair[0]}\n") + return reachable, storage.stack except StackError as ex: raise analysis_error(ex.args[0], uop.body.open) from None - return storage.stack SKIPS = ("_EXTENDED_ARG",) +def is_for_iter_test(uop: Uop) -> bool: + return uop.name in ( + "_GUARD_NOT_EXHAUSTED_RANGE", "_GUARD_NOT_EXHAUSTED_LIST", + "_GUARD_NOT_EXHAUSTED_TUPLE", "_FOR_ITER_TIER_TWO" + ) + +def populate_offset_strs(analysis: Analysis) -> dict[str, tuple[str, str]]: + offset_strs: dict[str, tuple[str, str]] = {} + for name, uop in analysis.uops.items(): + if not f"_GUARD_IP_{name}" in analysis.uops: + continue + tkn_iter = uop.body.tokens() + found = False + offset_str = "" + for token in tkn_iter: + if token.kind == "IDENTIFIER" and token.text == "LOAD_IP": + if found: + raise analysis_error("Cannot have two LOAD_IP in a guarded single uop.", uop.body.open) + offset = [] + while token.kind != "SEMI": + offset.append(token.text) + token = next(tkn_iter) + # 1: to remove the LOAD_IP text + offset_str = "".join(offset[1:]) + found = True + assert offset_str + offset_strs[f"_GUARD_IP_{name}"] = (name, offset_str) + return offset_strs def generate_tier2( filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool @@ -178,8 +287,9 @@ def generate_tier2( """ ) out = CWriter(outfile, 2, lines) - emitter = Tier2Emitter(out, analysis.labels) + offset_strs = populate_offset_strs(analysis) out.emit("\n") + for name, uop in analysis.uops.items(): if uop.properties.tier == 1: continue @@ -191,16 +301,25 @@ def generate_tier2( f"/* {uop.name} is not a viable micro-op for tier 2 because it {why_not_viable} */\n\n" ) continue - out.emit(f"case {uop.name}: {{\n") - declare_variables(uop, out) - stack = Stack() - stack = write_uop(uop, emitter, stack) - out.start_line() - if not uop.properties.always_exits: - out.emit("break;\n") - out.start_line() - out.emit("}") - out.emit("\n\n") + for inputs, outputs, exit_depth in get_uop_cache_depths(uop): + emitter = Tier2Emitter(out, analysis.labels, exit_depth) + out.emit(f"case {uop.name}_r{inputs}{outputs}: {{\n") + out.emit(f"CHECK_CURRENT_CACHED_VALUES({inputs});\n") + out.emit("assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());\n") + declare_variables(uop, out) + stack = Stack() + stack.push_cache([f"_tos_cache{i}" for i in range(inputs)], out) + stack._print(out) + reachable, stack = write_uop(uop, emitter, stack, offset_strs, outputs) + out.start_line() + if reachable: + out.emit("assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());\n") + if not uop.properties.always_exits: + out.emit("break;\n") + out.start_line() + out.emit("}") + out.emit("\n\n") + out.emit("\n") outfile.write("#undef TIER_TWO\n") diff --git a/Tools/cases_generator/uop_id_generator.py b/Tools/cases_generator/uop_id_generator.py index aae89faaa92..6992806a95b 100644 --- a/Tools/cases_generator/uop_id_generator.py +++ b/Tools/cases_generator/uop_id_generator.py @@ -8,6 +8,7 @@ import argparse from analyzer import ( Analysis, analyze_files, + get_uop_cache_depths, ) from generators_common import ( DEFAULT_INPUT, @@ -38,9 +39,7 @@ def generate_uop_ids( uops = [(uop.name, uop) for uop in analysis.uops.values()] # Sort so that _BASE comes immediately before _BASE_0, etc. for name, uop in sorted(uops): - if name in PRE_DEFINED: - continue - if uop.properties.tier == 1: + if name in PRE_DEFINED or uop.is_super() or uop.properties.tier == 1: continue if uop.implicitly_created and not distinct_namespace and not uop.replicated: out.emit(f"#define {name} {name[1:]}\n") @@ -49,6 +48,13 @@ def generate_uop_ids( next_id += 1 out.emit(f"#define MAX_UOP_ID {next_id-1}\n") + for name, uop in sorted(uops): + if uop.properties.tier == 1: + continue + for inputs, outputs, _ in sorted(get_uop_cache_depths(uop)): + out.emit(f"#define {name}_r{inputs}{outputs} {next_id}\n") + next_id += 1 + out.emit(f"#define MAX_UOP_REGS_ID {next_id-1}\n") arg_parser = argparse.ArgumentParser( diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py index 1cc23837a72..bdecb18d1d5 100644 --- a/Tools/cases_generator/uop_metadata_generator.py +++ b/Tools/cases_generator/uop_metadata_generator.py @@ -8,6 +8,9 @@ import argparse from analyzer import ( Analysis, analyze_files, + get_uop_cache_depths, + Uop, + MAX_CACHED_REGISTER, ) from generators_common import ( DEFAULT_INPUT, @@ -22,16 +25,55 @@ from typing import TextIO DEFAULT_OUTPUT = ROOT / "Include/internal/pycore_uop_metadata.h" +def uop_cache_info(uop: Uop) -> list[str] | None: + if uop.name == "_SPILL_OR_RELOAD": + return None + default = "{ -1, -1, -1 },\n" + table_size = MAX_CACHED_REGISTER + 1 + entries = [ default ] * table_size + low = MAX_CACHED_REGISTER+1 + high = -1 + defined = [ False ] * 4 + for inputs, outputs, exit_depth in get_uop_cache_depths(uop): + entries[inputs] = f"{{ {outputs}, {exit_depth}, {uop.name}_r{inputs}{outputs} }},\n" + if inputs < low: + low = inputs + if inputs > high: + high = inputs + best = [ str(low if i < low else (high if high < i else i)) for i in range(MAX_CACHED_REGISTER+1) ] + + return [ f".best = {{ {', '.join(best)} }},\n", ".entries = {\n", ] + entries + [ "},\n" ] + + +CACHING_INFO_DECL = """ +typedef struct _pyuop_tos_cache_entry { + /* input depth is implicit in position */ + int8_t output; + int8_t exit; + int16_t opcode; +} _PyUopTOSentry; +typedef struct _PyUopCachingInfo { + uint8_t best[MAX_CACHED_REGISTER + 1]; + _PyUopTOSentry entries[MAX_CACHED_REGISTER + 1]; +} _PyUopCachingInfo; +extern const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1]; +""" + + def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: - out.emit("extern const uint16_t _PyUop_Flags[MAX_UOP_ID+1];\n") + out.emit(f"#define MAX_CACHED_REGISTER {MAX_CACHED_REGISTER}\n") + out.emit("extern const uint32_t _PyUop_Flags[MAX_UOP_ID+1];\n") out.emit("typedef struct _rep_range { uint8_t start; uint8_t stop; } ReplicationRange;\n") out.emit("extern const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1];\n") - out.emit("extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1];\n\n") - out.emit("extern int _PyUop_num_popped(int opcode, int oparg);\n\n") + out.emit("extern const char * const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1];\n\n") + out.emit("extern int _PyUop_num_popped(int opcode, int oparg);\n") + out.emit(CACHING_INFO_DECL) + out.emit(f"extern const uint16_t _PyUop_SpillsAndReloads[{MAX_CACHED_REGISTER+1}][{MAX_CACHED_REGISTER+1}];\n") + out.emit("extern const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1];\n\n") out.emit("#ifdef NEED_OPCODE_METADATA\n") - out.emit("const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {\n") + out.emit("const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {\n") for uop in analysis.uops.values(): - if uop.is_viable() and uop.properties.tier != 1: + if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): out.emit(f"[{uop.name}] = {cflags(uop.properties)},\n") out.emit("};\n\n") @@ -42,16 +84,40 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit(f"[{uop.name}] = {{ {uop.replicated.start}, {uop.replicated.stop} }},\n") out.emit("};\n\n") - out.emit("const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {\n") + out.emit("const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {\n") + for uop in analysis.uops.values(): + if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): + info = uop_cache_info(uop) + if info is not None: + out.emit(f"[{uop.name}] = {{\n") + for line in info: + out.emit(line) + out.emit("},\n") + out.emit("};\n\n") + out.emit("const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {\n"); + for uop in analysis.uops.values(): + if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): + for inputs, outputs, _ in get_uop_cache_depths(uop): + out.emit(f"[{uop.name}_r{inputs}{outputs}] = {uop.name},\n") + out.emit("};\n\n") + out.emit(f"const uint16_t _PyUop_SpillsAndReloads[{MAX_CACHED_REGISTER+1}][{MAX_CACHED_REGISTER+1}] = {{\n") + for i in range(MAX_CACHED_REGISTER+1): + for j in range(MAX_CACHED_REGISTER+1): + if i != j: + out.emit(f"[{i}][{j}] = _SPILL_OR_RELOAD_r{i}{j},\n") + out.emit("};\n\n") + out.emit("const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {\n") for uop in sorted(analysis.uops.values(), key=lambda t: t.name): - if uop.is_viable() and uop.properties.tier != 1: + if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): out.emit(f'[{uop.name}] = "{uop.name}",\n') + for inputs, outputs, _ in get_uop_cache_depths(uop): + out.emit(f'[{uop.name}_r{inputs}{outputs}] = "{uop.name}_r{inputs}{outputs}",\n') out.emit("};\n") out.emit("int _PyUop_num_popped(int opcode, int oparg)\n{\n") out.emit("switch(opcode) {\n") null = CWriter.null() for uop in analysis.uops.values(): - if uop.is_viable() and uop.properties.tier != 1: + if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): stack = Stack() for var in reversed(uop.stack.inputs): if var.peek: diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt new file mode 100644 index 00000000000..e81ffd51e19 --- /dev/null +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -0,0 +1,93 @@ +# pydtrace_probes.h +PyDTrace_AUDIT +PyDTrace_FUNCTION_ENTRY +PyDTrace_FUNCTION_RETURN +PyDTrace_GC_DONE +PyDTrace_GC_START +PyDTrace_IMPORT_FIND_LOAD_DONE +PyDTrace_IMPORT_FIND_LOAD_START +PyDTrace_INSTANCE_DELETE_DONE +PyDTrace_INSTANCE_DELETE_START +PyDTrace_INSTANCE_NEW_DONE +PyDTrace_INSTANCE_NEW_START +PyDTrace_LINE +# fileobject.h +Py_FileSystemDefaultEncodeErrors +Py_FileSystemDefaultEncoding +Py_HasFileSystemDefaultEncoding +Py_UTF8Mode +# pyhash.h +Py_HASH_EXTERNAL +# exports.h +PyAPI_DATA +Py_EXPORTED_SYMBOL +Py_IMPORTED_SYMBOL +Py_LOCAL_SYMBOL +# modsupport.h +PyABIInfo_FREETHREADING_AGNOSTIC +# moduleobject.h +PyModuleDef_Type +# object.h +Py_INVALID_SIZE +Py_TPFLAGS_HAVE_VERSION_TAG +Py_TPFLAGS_INLINE_VALUES +Py_TPFLAGS_IS_ABSTRACT +# pyexpat.h +PyExpat_CAPI_MAGIC +PyExpat_CAPSULE_NAME +# pyport.h +Py_ALIGNED +Py_ARITHMETIC_RIGHT_SHIFT +Py_CAN_START_THREADS +Py_FORCE_EXPANSION +Py_GCC_ATTRIBUTE +Py_LL +Py_SAFE_DOWNCAST +Py_ULL +Py_VA_COPY +# unicodeobject.h +Py_UNICODE_SIZE +# cpython/methodobject.h +PyCFunction_GET_CLASS +# cpython/compile.h +PyCF_ALLOW_INCOMPLETE_INPUT +PyCF_COMPILE_MASK +PyCF_DONT_IMPLY_DEDENT +PyCF_IGNORE_COOKIE +PyCF_MASK +PyCF_MASK_OBSOLETE +PyCF_SOURCE_IS_UTF8 +# cpython/descrobject.h +PyDescr_COMMON +PyDescr_NAME +PyDescr_TYPE +PyWrapperFlag_KEYWORDS +# cpython/fileobject.h +PyFile_NewStdPrinter +PyStdPrinter_Type +Py_UniversalNewlineFgets +# cpython/setobject.h +PySet_MINSIZE +# cpython/ceval.h +PyUnstable_CopyPerfMapFile +PyUnstable_PerfTrampoline_CompileCode +PyUnstable_PerfTrampoline_SetPersistAfterFork +# cpython/genobject.h +PyAsyncGenASend_CheckExact +# cpython/longintrepr.h +PyLong_BASE +PyLong_MASK +PyLong_SHIFT +# cpython/pyerrors.h +PyException_HEAD +# cpython/pyframe.h +PyUnstable_EXECUTABLE_KINDS +PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION +PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR +PyUnstable_EXECUTABLE_KIND_PY_FUNCTION +PyUnstable_EXECUTABLE_KIND_SKIP +# cpython/pylifecycle.h +Py_FrozenMain +# cpython/unicodeobject.h +PyUnicode_IS_COMPACT +PyUnicode_IS_COMPACT_ASCII diff --git a/Tools/check-c-api-docs/main.py b/Tools/check-c-api-docs/main.py new file mode 100644 index 00000000000..6bdf80a9ae8 --- /dev/null +++ b/Tools/check-c-api-docs/main.py @@ -0,0 +1,193 @@ +import re +from pathlib import Path +import sys +import _colorize +import textwrap + +SIMPLE_FUNCTION_REGEX = re.compile(r"PyAPI_FUNC(.+) (\w+)\(") +SIMPLE_MACRO_REGEX = re.compile(r"# *define *(\w+)(\(.+\))? ") +SIMPLE_INLINE_REGEX = re.compile(r"static inline .+( |\n)(\w+)") +SIMPLE_DATA_REGEX = re.compile(r"PyAPI_DATA\(.+\) (\w+)") + +CPYTHON = Path(__file__).parent.parent.parent +INCLUDE = CPYTHON / "Include" +C_API_DOCS = CPYTHON / "Doc" / "c-api" +IGNORED = ( + (CPYTHON / "Tools" / "check-c-api-docs" / "ignored_c_api.txt") + .read_text() + .split("\n") +) + +for index, line in enumerate(IGNORED): + if line.startswith("#"): + IGNORED.pop(index) + +MISTAKE = """ +If this is a mistake and this script should not be failing, create an +issue and tag Peter (@ZeroIntensity) on it.\ +""" + + +def found_undocumented(singular: bool) -> str: + some = "an" if singular else "some" + s = "" if singular else "s" + these = "this" if singular else "these" + them = "it" if singular else "them" + were = "was" if singular else "were" + + return ( + textwrap.dedent( + f""" + Found {some} undocumented C API{s}! + + Python requires documentation on all public C API symbols, macros, and types. + If {these} API{s} {were} not meant to be public, prefix {them} with a + leading underscore (_PySomething_API) or move {them} to the internal C API + (pycore_*.h files). + + In exceptional cases, certain APIs can be ignored by adding them to + Tools/check-c-api-docs/ignored_c_api.txt + """ + ) + + MISTAKE + ) + + +def found_ignored_documented(singular: bool) -> str: + some = "a" if singular else "some" + s = "" if singular else "s" + them = "it" if singular else "them" + were = "was" if singular else "were" + they = "it" if singular else "they" + + return ( + textwrap.dedent( + f""" + Found {some} C API{s} listed in Tools/c-api-docs-check/ignored_c_api.txt, but + {they} {were} found in the documentation. To fix this, remove {them} from + ignored_c_api.txt. + """ + ) + + MISTAKE + ) + + +def is_documented(name: str) -> bool: + """ + Is a name present in the C API documentation? + """ + for path in C_API_DOCS.iterdir(): + if path.is_dir(): + continue + if path.suffix != ".rst": + continue + + text = path.read_text(encoding="utf-8") + if name in text: + return True + + return False + + +def scan_file_for_docs(filename: str, text: str) -> tuple[list[str], list[str]]: + """ + Scan a header file for C API functions. + """ + undocumented: list[str] = [] + documented_ignored: list[str] = [] + colors = _colorize.get_colors() + + def check_for_name(name: str) -> None: + documented = is_documented(name) + if documented and (name in IGNORED): + documented_ignored.append(name) + elif not documented and (name not in IGNORED): + undocumented.append(name) + + for function in SIMPLE_FUNCTION_REGEX.finditer(text): + name = function.group(2) + if not name.startswith("Py"): + continue + + check_for_name(name) + + for macro in SIMPLE_MACRO_REGEX.finditer(text): + name = macro.group(1) + if not name.startswith("Py"): + continue + + if "(" in name: + name = name[: name.index("(")] + + check_for_name(name) + + for inline in SIMPLE_INLINE_REGEX.finditer(text): + name = inline.group(2) + if not name.startswith("Py"): + continue + + check_for_name(name) + + for data in SIMPLE_DATA_REGEX.finditer(text): + name = data.group(1) + if not name.startswith("Py"): + continue + + check_for_name(name) + + # Remove duplicates and sort alphabetically to keep the output deterministic + undocumented = list(set(undocumented)) + undocumented.sort() + + if undocumented or documented_ignored: + print(f"{filename} {colors.RED}BAD{colors.RESET}") + for name in undocumented: + print(f"{colors.BOLD_RED}UNDOCUMENTED:{colors.RESET} {name}") + for name in documented_ignored: + print(f"{colors.BOLD_YELLOW}DOCUMENTED BUT IGNORED:{colors.RESET} {name}") + else: + print(f"{filename} {colors.GREEN}OK{colors.RESET}") + + return undocumented, documented_ignored + + +def main() -> None: + print("Scanning for undocumented C API functions...") + files = [*INCLUDE.iterdir(), *(INCLUDE / "cpython").iterdir()] + all_missing: list[str] = [] + all_found_ignored: list[str] = [] + + for file in files: + if file.is_dir(): + continue + assert file.exists() + text = file.read_text(encoding="utf-8") + missing, ignored = scan_file_for_docs(str(file.relative_to(INCLUDE)), text) + all_found_ignored += ignored + all_missing += missing + + fail = False + to_check = [ + (all_missing, "missing", found_undocumented(len(all_missing) == 1)), + ( + all_found_ignored, + "documented but ignored", + found_ignored_documented(len(all_found_ignored) == 1), + ), + ] + for name_list, what, message in to_check: + if not name_list: + continue + + s = "s" if len(name_list) != 1 else "" + print(f"-- {len(name_list)} {what} C API{s} --") + for name in name_list: + print(f" - {name}") + print(message) + fail = True + + sys.exit(1 if fail else 0) + + +if __name__ == "__main__": + main() diff --git a/Tools/check-c-api-docs/mypy.ini b/Tools/check-c-api-docs/mypy.ini new file mode 100644 index 00000000000..f42eb2836e2 --- /dev/null +++ b/Tools/check-c-api-docs/mypy.ini @@ -0,0 +1,19 @@ +[mypy] +files = Tools/check-c-api-docs/ +pretty = True + +# We need `_colorize` import: +mypy_path = $MYPY_CONFIG_FILE_DIR/../../Misc/mypy + +# Make sure Python can still be built +# using Python 3.13 for `PYTHON_FOR_REGEN`... +python_version = 3.13 + +# ...And be strict: +strict = True +extra_checks = True +enable_error_code = + ignore-without-code, + redundant-expr, + truthy-bool, + possibly-undefined, diff --git a/Tools/clinic/.ruff.toml b/Tools/clinic/.ruff.toml index 5033887df0c..944d17ee3e9 100644 --- a/Tools/clinic/.ruff.toml +++ b/Tools/clinic/.ruff.toml @@ -17,9 +17,6 @@ ignore = [ # Use f-strings instead of format specifiers. # Doesn't always make code more readable. "UP032", - # Use PEP-604 unions rather than tuples for isinstance() checks. - # Makes code slower and more verbose. https://github.com/astral-sh/ruff/issues/7871. - "UP038", ] unfixable = [ # The autofixes sometimes do the wrong things for these; diff --git a/Tools/clinic/libclinic/__init__.py b/Tools/clinic/libclinic/__init__.py index 7c5cede2396..9e9bdeadcc0 100644 --- a/Tools/clinic/libclinic/__init__.py +++ b/Tools/clinic/libclinic/__init__.py @@ -84,6 +84,7 @@ CLINIC_PREFIXED_ARGS: Final = frozenset( "argsbuf", "fastargs", "kwargs", + "kwds", "kwnames", "nargs", "noptargs", diff --git a/Tools/clinic/libclinic/app.py b/Tools/clinic/libclinic/app.py index 632bed3ce53..9e8cec5320f 100644 --- a/Tools/clinic/libclinic/app.py +++ b/Tools/clinic/libclinic/app.py @@ -255,14 +255,14 @@ impl_definition block cls: Class | None = None for idx, field in enumerate(fields): + fullname = ".".join(fields[:idx + 1]) if not isinstance(parent, Class): - if field in parent.modules: - parent = module = parent.modules[field] + if fullname in parent.modules: + parent = module = parent.modules[fullname] continue if field in parent.classes: parent = cls = parent.classes[field] else: - fullname = ".".join(fields[idx:]) fail(f"Parent class or module {fullname!r} does not exist.") return module, cls diff --git a/Tools/clinic/libclinic/converter.py b/Tools/clinic/libclinic/converter.py index 2c93dda3541..ac66e79f93b 100644 --- a/Tools/clinic/libclinic/converter.py +++ b/Tools/clinic/libclinic/converter.py @@ -274,7 +274,7 @@ class CConverter(metaclass=CConverterAutoRegister): data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip()) # keywords - if parameter.is_vararg(): + if parameter.is_variable_length(): pass elif parameter.is_positional_only(): data.keywords.append('') diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index 6e89e8de7cc..bc21ae84e1c 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -420,21 +420,39 @@ class Py_ssize_t_converter(CConverter): type = 'Py_ssize_t' c_ignored_default = "0" - def converter_init(self, *, accept: TypeSet = {int}) -> None: + def converter_init(self, *, accept: TypeSet = {int}, + allow_negative: bool = True) -> None: + self.allow_negative = allow_negative if accept == {int}: self.format_unit = 'n' self.default_type = int elif accept == {int, NoneType}: - self.converter = '_Py_convert_optional_to_ssize_t' + if self.allow_negative: + self.converter = '_Py_convert_optional_to_ssize_t' + else: + self.converter = '_Py_convert_optional_to_non_negative_ssize_t' else: fail(f"Py_ssize_t_converter: illegal 'accept' argument {accept!r}") def use_converter(self) -> None: - if self.converter == '_Py_convert_optional_to_ssize_t': - self.add_include('pycore_abstract.h', - '_Py_convert_optional_to_ssize_t()') + if self.converter in { + '_Py_convert_optional_to_ssize_t', + '_Py_convert_optional_to_non_negative_ssize_t', + }: + self.add_include('pycore_abstract.h', f'{self.converter}()') def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + if self.allow_negative: + non_negative_check = '' + else: + non_negative_check = self.format_code(""" + if ({paramname} < 0) {{{{ + PyErr_SetString(PyExc_ValueError, + "{paramname} cannot be negative"); + goto exit; + }}}}""", + argname=argname, + ) if self.format_unit == 'n': if limited_capi: PyNumber_Index = 'PyNumber_Index' @@ -452,11 +470,13 @@ class Py_ssize_t_converter(CConverter): if (ival == -1 && PyErr_Occurred()) {{{{ goto exit; }}}} - {paramname} = ival; + {paramname} = ival;{non_negative_check} }}}} """, argname=argname, - PyNumber_Index=PyNumber_Index) + PyNumber_Index=PyNumber_Index, + non_negative_check=non_negative_check, + ) if not limited_capi: return super().parse_arg(argname, displayname, limited_capi=limited_capi) return self.format_code(""" @@ -465,7 +485,7 @@ class Py_ssize_t_converter(CConverter): {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError); if ({paramname} == -1 && PyErr_Occurred()) {{{{ goto exit; - }}}} + }}}}{non_negative_check} }}}} else {{{{ {bad_argument} @@ -475,6 +495,7 @@ class Py_ssize_t_converter(CConverter): """, argname=argname, bad_argument=self.bad_argument(displayname, 'integer or None', limited_capi=limited_capi), + non_negative_check=non_negative_check, ) @@ -895,6 +916,26 @@ class unicode_converter(CConverter): return super().parse_arg(argname, displayname, limited_capi=limited_capi) +class _unicode_fs_converter_base(CConverter): + type = 'PyObject *' + + def converter_init(self) -> None: + if self.default is not unspecified: + fail(f"{self.__class__.__name__} does not support default values") + self.c_default = 'NULL' + + def cleanup(self) -> str: + return f"Py_XDECREF({self.parser_name});" + + +class unicode_fs_encoded_converter(_unicode_fs_converter_base): + converter = 'PyUnicode_FSConverter' + + +class unicode_fs_decoded_converter(_unicode_fs_converter_base): + converter = 'PyUnicode_FSDecoder' + + @add_legacy_c_converter('u') @add_legacy_c_converter('u#', zeroes=True) @add_legacy_c_converter('Z', accept={str, NoneType}) @@ -1225,13 +1266,12 @@ class varpos_tuple_converter(VarPosCConverter): }}}} """ else: - self.add_include('pycore_tuple.h', '_PyTuple_FromArray()') start = f'args + {max_pos}' if max_pos else 'args' size = f'nargs - {max_pos}' if max_pos else 'nargs' if min(pos_only, min_pos) < max_pos: return f""" {paramname} = nargs > {max_pos} - ? _PyTuple_FromArray({start}, {size}) + ? PyTuple_FromArray({start}, {size}) : PyTuple_New(0); if ({paramname} == NULL) {{{{ goto exit; @@ -1239,7 +1279,7 @@ class varpos_tuple_converter(VarPosCConverter): """ else: return f""" - {paramname} = _PyTuple_FromArray({start}, {size}); + {paramname} = PyTuple_FromArray({start}, {size}); if ({paramname} == NULL) {{{{ goto exit; }}}} @@ -1279,3 +1319,37 @@ class varpos_array_converter(VarPosCConverter): {paramname} = {start}; {self.length_name} = {size}; """ + + +# Converters for var-keyword parameters. + +class VarKeywordCConverter(CConverter): + format_unit = '' + + def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + raise AssertionError('should never be called') + + def parse_var_keyword(self) -> str: + raise NotImplementedError + + +class var_keyword_dict_converter(VarKeywordCConverter): + type = 'PyObject *' + c_default = 'NULL' + + def cleanup(self) -> str: + return f'Py_XDECREF({self.parser_name});\n' + + def parse_var_keyword(self) -> str: + param_name = self.parser_name + return f""" + if (kwargs == NULL) {{{{ + {param_name} = PyDict_New(); + if ({param_name} == NULL) {{{{ + goto exit; + }}}} + }}}} + else {{{{ + {param_name} = Py_NewRef(kwargs); + }}}} + """ diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py index f9587d20383..0d83baeba9e 100644 --- a/Tools/clinic/libclinic/dsl_parser.py +++ b/Tools/clinic/libclinic/dsl_parser.py @@ -246,6 +246,7 @@ class IndentStack: class DSLParser: function: Function | None state: StateKeeper + expecting_parameters: bool keyword_only: bool positional_only: bool deprecated_positional: VersionTuple | None @@ -285,6 +286,7 @@ class DSLParser: def reset(self) -> None: self.function = None self.state = self.state_dsl_start + self.expecting_parameters = True self.keyword_only = False self.positional_only = False self.deprecated_positional = None @@ -876,6 +878,10 @@ class DSLParser: def parse_parameter(self, line: str) -> None: assert self.function is not None + if not self.expecting_parameters: + fail('Encountered parameter line when not expecting ' + f'parameters: {line}') + match self.parameter_state: case ParamState.START | ParamState.REQUIRED: self.to_required() @@ -909,27 +915,40 @@ class DSLParser: if len(function_args.args) > 1: fail(f"Function {self.function.name!r} has an " f"invalid parameter declaration (comma?): {line!r}") - if function_args.kwarg: - fail(f"Function {self.function.name!r} has an " - f"invalid parameter declaration (**kwargs?): {line!r}") + is_vararg = is_var_keyword = False if function_args.vararg: self.check_previous_star() self.check_remaining_star() is_vararg = True parameter = function_args.vararg + elif function_args.kwarg: + # If the existing parameters are all positional only or ``*args`` + # (var-positional), then we allow ``**kwds`` (var-keyword). + # Currently, pos-or-keyword or keyword-only arguments are not + # allowed with the ``**kwds`` converter. + has_non_positional_param = any( + p.is_positional_or_keyword() or p.is_keyword_only() + for p in self.function.parameters.values() + ) + if has_non_positional_param: + fail(f"Function {self.function.name!r} has an " + f"invalid parameter declaration (**kwargs?): {line!r}") + is_var_keyword = True + parameter = function_args.kwarg else: - is_vararg = False parameter = function_args.args[0] parameter_name = parameter.arg name, legacy, kwargs = self.parse_converter(parameter.annotation) if is_vararg: - name = 'varpos_' + name + name = f'varpos_{name}' + elif is_var_keyword: + name = f'var_keyword_{name}' value: object if not function_args.defaults: - if is_vararg: + if is_vararg or is_var_keyword: value = NULL else: if self.parameter_state is ParamState.OPTIONAL: @@ -1065,6 +1084,8 @@ class DSLParser: kind: inspect._ParameterKind if is_vararg: kind = inspect.Parameter.VAR_POSITIONAL + elif is_var_keyword: + kind = inspect.Parameter.VAR_KEYWORD elif self.keyword_only: kind = inspect.Parameter.KEYWORD_ONLY else: @@ -1118,6 +1139,8 @@ class DSLParser: if is_vararg: self.keyword_only = True + if is_var_keyword: + self.expecting_parameters = False @staticmethod def parse_converter( @@ -1159,6 +1182,9 @@ class DSLParser: The 'version' parameter signifies the future version from which the marker will take effect (None means it is already in effect). """ + if not self.expecting_parameters: + fail("Encountered '*' when not expecting parameters") + if version is None: self.check_previous_star() self.check_remaining_star() @@ -1214,6 +1240,9 @@ class DSLParser: The 'version' parameter signifies the future version from which the marker will take effect (None means it is already in effect). """ + if not self.expecting_parameters: + fail("Encountered '/' when not expecting parameters") + if version is None: if self.deprecated_keyword: fail(f"Function {function.name!r}: '/' must precede '/ [from ...]'") @@ -1450,11 +1479,13 @@ class DSLParser: if p.is_vararg(): p_lines.append("*") added_star = True + if p.is_var_keyword(): + p_lines.append("**") name = p.converter.signature_name or p.name p_lines.append(name) - if not p.is_vararg() and p.converter.is_optional(): + if not p.is_variable_length() and p.converter.is_optional(): p_lines.append('=') value = p.converter.py_default if not value: @@ -1583,8 +1614,11 @@ class DSLParser: for p in reversed(self.function.parameters.values()): if self.keyword_only: - if (p.kind == inspect.Parameter.KEYWORD_ONLY or - p.kind == inspect.Parameter.VAR_POSITIONAL): + if p.kind in { + inspect.Parameter.KEYWORD_ONLY, + inspect.Parameter.VAR_POSITIONAL, + inspect.Parameter.VAR_KEYWORD + }: return elif self.deprecated_positional: if p.deprecated_positional == self.deprecated_positional: diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index 4280af0c4c9..f981f0bcaf8 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -220,9 +220,18 @@ class Parameter: def is_positional_only(self) -> bool: return self.kind == inspect.Parameter.POSITIONAL_ONLY + def is_positional_or_keyword(self) -> bool: + return self.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD + def is_vararg(self) -> bool: return self.kind == inspect.Parameter.VAR_POSITIONAL + def is_var_keyword(self) -> bool: + return self.kind == inspect.Parameter.VAR_KEYWORD + + def is_variable_length(self) -> bool: + return self.is_vararg() or self.is_var_keyword() + def is_optional(self) -> bool: return not self.is_vararg() and (self.default is not unspecified) diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index 0e15d2f163b..bca87ecd751 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -36,7 +36,7 @@ def declare_parser( num_keywords = len([ p for p in f.parameters.values() - if not p.is_positional_only() and not p.is_vararg() + if p.is_positional_or_keyword() or p.is_keyword_only() ]) condition = '#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)' @@ -220,6 +220,7 @@ class ParseArgsCodeGen: max_pos: int = 0 min_kw_only: int = 0 varpos: Parameter | None = None + var_keyword: Parameter | None = None docstring_prototype: str docstring_definition: str @@ -255,13 +256,24 @@ class ParseArgsCodeGen: del self.parameters[i] break + for i, p in enumerate(self.parameters): + if p.is_var_keyword(): + self.var_keyword = p + del self.parameters[i] + break + self.converters = [p.converter for p in self.parameters] if self.func.critical_section: self.codegen.add_include('pycore_critical_section.h', 'Py_BEGIN_CRITICAL_SECTION()') + + # Use fastcall if not disabled, except if in a __new__ or + # __init__ method, or if there is a **kwargs parameter. if self.func.disable_fastcall: self.fastcall = False + elif self.var_keyword is not None: + self.fastcall = False else: self.fastcall = not self.is_new_or_init() @@ -469,6 +481,12 @@ class ParseArgsCodeGen: fastcall=self.fastcall, limited_capi=self.limited_capi) + def _parse_kwarg(self) -> str: + assert self.var_keyword is not None + c = self.var_keyword.converter + assert isinstance(c, libclinic.converters.VarKeywordCConverter) + return c.parse_var_keyword() + def parse_pos_only(self) -> None: if self.fastcall: # positional-only, but no option groups @@ -564,6 +582,8 @@ class ParseArgsCodeGen: parser_code.append("skip_optional:") if self.varpos: parser_code.append(libclinic.normalize_snippet(self._parse_vararg(), indent=4)) + elif self.var_keyword: + parser_code.append(libclinic.normalize_snippet(self._parse_kwarg(), indent=4)) else: for parameter in self.parameters: parameter.converter.use_converter() @@ -590,6 +610,45 @@ class ParseArgsCodeGen: """, indent=4)] self.parser_body(*parser_code) + def parse_var_keyword(self) -> None: + self.flags = "METH_VARARGS|METH_KEYWORDS" + self.parser_prototype = PARSER_PROTOTYPE_KEYWORD + nargs = 'PyTuple_GET_SIZE(args)' + + parser_code = [] + max_args = NO_VARARG if self.varpos else self.max_pos + if self.varpos is None and self.min_pos == self.max_pos == 0: + self.codegen.add_include('pycore_modsupport.h', + '_PyArg_NoPositional()') + parser_code.append(libclinic.normalize_snippet(""" + if (!_PyArg_NoPositional("{name}", args)) {{ + goto exit; + }} + """, indent=4)) + elif self.min_pos or max_args != NO_VARARG: + self.codegen.add_include('pycore_modsupport.h', + '_PyArg_CheckPositional()') + parser_code.append(libclinic.normalize_snippet(f""" + if (!_PyArg_CheckPositional("{{name}}", {nargs}, {self.min_pos}, {max_args})) {{{{ + goto exit; + }}}} + """, indent=4)) + + for i, p in enumerate(self.parameters): + parse_arg = p.converter.parse_arg( + f'PyTuple_GET_ITEM(args, {i})', + p.get_displayname(i+1), + limited_capi=self.limited_capi, + ) + assert parse_arg is not None + parser_code.append(libclinic.normalize_snippet(parse_arg, indent=4)) + + if self.varpos: + parser_code.append(libclinic.normalize_snippet(self._parse_vararg(), indent=4)) + if self.var_keyword: + parser_code.append(libclinic.normalize_snippet(self._parse_kwarg(), indent=4)) + self.parser_body(*parser_code) + def parse_general(self, clang: CLanguage) -> None: parsearg: str | None deprecated_positionals: dict[int, Parameter] = {} @@ -921,12 +980,14 @@ class ParseArgsCodeGen: # previous call to parser_body. this is used for an awful hack. self.parser_body_fields: tuple[str, ...] = () - if not self.parameters and not self.varpos: + if not self.parameters and not self.varpos and not self.var_keyword: self.parse_no_args() elif self.use_meth_o(): self.parse_one_arg() elif self.has_option_groups(): self.parse_option_groups() + elif self.var_keyword is not None: + self.parse_var_keyword() elif (not self.requires_defining_class and self.pos_only == len(self.parameters)): self.parse_pos_only() diff --git a/Tools/ftscalingbench/ftscalingbench.py b/Tools/ftscalingbench/ftscalingbench.py index 1a59e25189d..097a065f368 100644 --- a/Tools/ftscalingbench/ftscalingbench.py +++ b/Tools/ftscalingbench/ftscalingbench.py @@ -27,6 +27,7 @@ import queue import sys import threading import time +from dataclasses import dataclass from operator import methodcaller # The iterations in individual benchmarks are scaled by this factor. @@ -202,6 +203,17 @@ def method_caller(): for i in range(1000 * WORK_SCALE): mc(obj) +@dataclass +class MyDataClass: + x: int + y: int + z: int + +@register_benchmark +def instantiate_dataclass(): + for _ in range(1000 * WORK_SCALE): + obj = MyDataClass(x=1, y=2, z=3) + def bench_one_thread(func): t0 = time.perf_counter_ns() func() diff --git a/Tools/i18n/.ruff.toml b/Tools/i18n/.ruff.toml new file mode 100644 index 00000000000..a8f4f2f5a96 --- /dev/null +++ b/Tools/i18n/.ruff.toml @@ -0,0 +1,10 @@ +extend = "../../.ruff.toml" # Inherit the project-wide settings + +target-version = "py313" + +[lint] +select = [ + "F", # pyflakes + "I", # isort + "UP", # pyupgrade +] diff --git a/Tools/i18n/makelocalealias.py b/Tools/i18n/makelocalealias.py index 7f001abc097..f825862ffdf 100755 --- a/Tools/i18n/makelocalealias.py +++ b/Tools/i18n/makelocalealias.py @@ -8,6 +8,7 @@ """ import locale import sys + _locale = locale # Location of the X11 alias file. @@ -100,16 +101,15 @@ def parse_glibc_supported(filename): def pprint(data): items = sorted(data.items()) for k, v in items: - print(' %-40s%a,' % ('%a:' % k, v)) + print(f" {k!a:<40}{v!a},") def print_differences(data, olddata): items = sorted(olddata.items()) for k, v in items: if k not in data: - print('# removed %a' % k) + print(f'# removed {k!a}') elif olddata[k] != data[k]: - print('# updated %a -> %a to %a' % \ - (k, olddata[k], data[k])) + print(f'# updated {k!a} -> {olddata[k]!a} to {data[k]!a}') # Additions are not mentioned def optimize(data): @@ -132,7 +132,7 @@ def check(data): errors = 0 for k, v in data.items(): if locale.normalize(k) != v: - print('ERROR: %a -> %a != %a' % (k, locale.normalize(k), v), + print(f'ERROR: {k!a} -> {locale.normalize(k)!a} != {v!a}', file=sys.stderr) errors += 1 return errors @@ -142,10 +142,10 @@ if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--locale-alias', default=LOCALE_ALIAS, help='location of the X11 alias file ' - '(default: %a)' % LOCALE_ALIAS) + f'(default: {LOCALE_ALIAS})') parser.add_argument('--glibc-supported', default=SUPPORTED, help='location of the glibc SUPPORTED locales file ' - '(default: %a)' % SUPPORTED) + f'(default: {SUPPORTED})') args = parser.parse_args() data = locale.locale_alias.copy() diff --git a/Tools/i18n/msgfmt.py b/Tools/i18n/msgfmt.py index 65254a7c375..3351511bbc8 100755 --- a/Tools/i18n/msgfmt.py +++ b/Tools/i18n/msgfmt.py @@ -24,14 +24,14 @@ Options: Display version information and exit. """ -import os -import sys -import ast -import getopt -import struct import array -from email.parser import HeaderParser +import ast import codecs +import getopt +import os +import struct +import sys +from email.parser import HeaderParser __version__ = "1.2" @@ -113,7 +113,7 @@ def make(filename, outfile): try: with open(infile, 'rb') as f: lines = f.readlines() - except IOError as msg: + except OSError as msg: print(msg, file=sys.stderr) sys.exit(1) @@ -126,6 +126,7 @@ def make(filename, outfile): sys.exit(1) section = msgctxt = None + msgid = msgstr = b'' fuzzy = 0 # Start off assuming Latin-1, so everything decodes without failure, @@ -177,7 +178,7 @@ def make(filename, outfile): # This is a message with plural forms elif l.startswith('msgid_plural'): if section != ID: - print('msgid_plural not preceded by msgid on %s:%d' % (infile, lno), + print(f'msgid_plural not preceded by msgid on {infile}:{lno}', file=sys.stderr) sys.exit(1) l = l[12:] @@ -188,7 +189,7 @@ def make(filename, outfile): section = STR if l.startswith('msgstr['): if not is_plural: - print('plural without msgid_plural on %s:%d' % (infile, lno), + print(f'plural without msgid_plural on {infile}:{lno}', file=sys.stderr) sys.exit(1) l = l.split(']', 1)[1] @@ -196,7 +197,7 @@ def make(filename, outfile): msgstr += b'\0' # Separator of the various plural forms else: if is_plural: - print('indexed msgstr required for plural on %s:%d' % (infile, lno), + print(f'indexed msgstr required for plural on {infile}:{lno}', file=sys.stderr) sys.exit(1) l = l[6:] @@ -212,8 +213,7 @@ def make(filename, outfile): elif section == STR: msgstr += l.encode(encoding) else: - print('Syntax error on %s:%d' % (infile, lno), \ - 'before:', file=sys.stderr) + print(f'Syntax error on {infile}:{lno} before:', file=sys.stderr) print(l, file=sys.stderr) sys.exit(1) # Add last entry @@ -226,7 +226,7 @@ def make(filename, outfile): try: with open(outfile,"wb") as f: f.write(output) - except IOError as msg: + except OSError as msg: print(msg, file=sys.stderr) diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index f46b05067d7..ddf4474d2bc 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -193,7 +193,7 @@ def make_escapes(pass_nonascii): escape = escape_ascii else: escape = escape_nonascii - escapes = [r"\%03o" % i for i in range(256)] + escapes = [fr"\{i:03o}" for i in range(256)] for i in range(32, 127): escapes[i] = chr(i) escapes[ord('\\')] = r'\\' @@ -796,7 +796,7 @@ def main(): try: with open(options.excludefilename) as fp: options.toexclude = fp.readlines() - except IOError: + except OSError: print(f"Can't read --exclude-file: {options.excludefilename}", file=sys.stderr) sys.exit(1) diff --git a/Tools/inspection/benchmark_external_inspection.py b/Tools/inspection/benchmark_external_inspection.py index 0ac7ac4d385..9c40c2f4492 100644 --- a/Tools/inspection/benchmark_external_inspection.py +++ b/Tools/inspection/benchmark_external_inspection.py @@ -434,7 +434,7 @@ def main(): elif args.threads == "only_active": kwargs["only_active_thread"] = True unwinder = _remote_debugging.RemoteUnwinder( - process.pid, **kwargs + process.pid, cache_frames=True, **kwargs ) results = benchmark(unwinder, duration_seconds=args.duration) finally: diff --git a/Tools/jit/README.md b/Tools/jit/README.md index 8e817574b4d..8eadb3349ba 100644 --- a/Tools/jit/README.md +++ b/Tools/jit/README.md @@ -9,32 +9,32 @@ Python 3.11 or newer is required to build the JIT. The JIT compiler does not require end users to install any third-party dependencies, but part of it must be *built* using LLVM[^why-llvm]. You are *not* required to build the rest of CPython using LLVM, or even the same version of LLVM (in fact, this is uncommon). -LLVM version 19 is required. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-19`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code. +LLVM version 21 is the officially supported version. You can modify if needed using the `LLVM_VERSION` env var during configure. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-19`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code. It's easy to install all of the required tools: ### Linux -Install LLVM 19 on Ubuntu/Debian: +Install LLVM 21 on Ubuntu/Debian: ```sh wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh -sudo ./llvm.sh 19 +sudo ./llvm.sh 21 ``` -Install LLVM 19 on Fedora Linux 40 or newer: +Install LLVM 21 on Fedora Linux 40 or newer: ```sh -sudo dnf install 'clang(major) = 19' 'llvm(major) = 19' +sudo dnf install 'clang(major) = 21' 'llvm(major) = 21' ``` ### macOS -Install LLVM 19 with [Homebrew](https://brew.sh): +Install LLVM 21 with [Homebrew](https://brew.sh): ```sh -brew install llvm@19 +brew install llvm@21 ``` Homebrew won't add any of the tools to your `$PATH`. That's okay; the build script knows how to find them. @@ -43,14 +43,27 @@ Homebrew won't add any of the tools to your `$PATH`. That's okay; the build scri LLVM is downloaded automatically (along with other external binary dependencies) by `PCbuild\build.bat`. -Otherwise, you can install LLVM 19 [by searching for it on LLVM's GitHub releases page](https://github.com/llvm/llvm-project/releases?q=19), clicking on "Assets", downloading the appropriate Windows installer for your platform (likely the file ending with `-win64.exe`), and running it. **When installing, be sure to select the option labeled "Add LLVM to the system PATH".** +By default, the architecture of the LLVM tools is auto-detected based on the host machine. To override this, set the `PreferredToolArchitecture` environment variable before building: + +```sh +set PreferredToolArchitecture=AMD64 +PCbuild\build.bat --experimental-jit +``` + +Valid values are`x64`, `x86` and `ARM64`. + +Otherwise, you can install LLVM 21 [by searching for it on LLVM's GitHub releases page](https://github.com/llvm/llvm-project/releases?q=21), clicking on "Assets", downloading the appropriate Windows installer for your platform (likely the file ending with `-win64.exe`), and running it. **When installing, be sure to select the option labeled "Add LLVM to the system PATH".** Alternatively, you can use [chocolatey](https://chocolatey.org): ```sh -choco install llvm --version=19.1.0 +choco install llvm --version=21.1.0 ``` +### Dev Containers + +If you are working on CPython in a [Codespaces instance](https://devguide.python.org/getting-started/setup-building/#using-codespaces), there's no +need to install LLVM as the Fedora 43 base image includes LLVM 21 out of the box. ## Building @@ -62,6 +75,9 @@ Otherwise, just configure and build as you normally would. Cross-compiling "just The JIT can also be enabled or disabled using the `PYTHON_JIT` environment variable, even on builds where it is enabled or disabled by default. More details about configuring CPython with the JIT and optional values for `--enable-experimental-jit` can be found [here](https://docs.python.org/dev/using/configure.html#cmdoption-enable-experimental-jit). +## Miscellaneous +If you're looking for information on how to update the JIT build dependencies, see [JIT Build Infrastructure](jit_infra.md). + [^pep-744]: [PEP 744](https://peps.python.org/pep-0744/) [^why-llvm]: Clang is specifically needed because it's the only C compiler with support for guaranteed tail calls (`musttail`), which are required by CPython's continuation-passing-style approach to JIT compilation. Since LLVM also includes other functionalities we need (namely, object file parsing and disassembly), it's convenient to only support one toolchain at this time. diff --git a/Tools/jit/_llvm.py b/Tools/jit/_llvm.py index f09a8404871..0b9cb5192f1 100644 --- a/Tools/jit/_llvm.py +++ b/Tools/jit/_llvm.py @@ -10,9 +10,9 @@ import typing import _targets -_LLVM_VERSION = 19 -_LLVM_VERSION_PATTERN = re.compile(rf"version\s+{_LLVM_VERSION}\.\d+\.\d+\S*\s+") -_EXTERNALS_LLVM_TAG = "llvm-19.1.7.0" + +_LLVM_VERSION = "21" +_EXTERNALS_LLVM_TAG = "llvm-21.1.4.0" _P = typing.ParamSpec("_P") _R = typing.TypeVar("_R") @@ -56,53 +56,71 @@ async def _run(tool: str, args: typing.Iterable[str], echo: bool = False) -> str @_async_cache -async def _check_tool_version(name: str, *, echo: bool = False) -> bool: +async def _check_tool_version( + name: str, llvm_version: str, *, echo: bool = False +) -> bool: output = await _run(name, ["--version"], echo=echo) - return bool(output and _LLVM_VERSION_PATTERN.search(output)) + _llvm_version_pattern = re.compile(rf"version\s+{llvm_version}\.\d+\.\d+\S*\s+") + return bool(output and _llvm_version_pattern.search(output)) @_async_cache -async def _get_brew_llvm_prefix(*, echo: bool = False) -> str | None: - output = await _run("brew", ["--prefix", f"llvm@{_LLVM_VERSION}"], echo=echo) +async def _get_brew_llvm_prefix(llvm_version: str, *, echo: bool = False) -> str | None: + output = await _run("brew", ["--prefix", f"llvm@{llvm_version}"], echo=echo) return output and output.removesuffix("\n") @_async_cache -async def _find_tool(tool: str, *, echo: bool = False) -> str | None: +async def _find_tool(tool: str, llvm_version: str, *, echo: bool = False) -> str | None: # Unversioned executables: path = tool - if await _check_tool_version(path, echo=echo): + if await _check_tool_version(path, llvm_version, echo=echo): return path # Versioned executables: - path = f"{tool}-{_LLVM_VERSION}" - if await _check_tool_version(path, echo=echo): + path = f"{tool}-{llvm_version}" + if await _check_tool_version(path, llvm_version, echo=echo): return path # PCbuild externals: externals = os.environ.get("EXTERNALS_DIR", _targets.EXTERNALS) path = os.path.join(externals, _EXTERNALS_LLVM_TAG, "bin", tool) - if await _check_tool_version(path, echo=echo): + # On Windows, executables need .exe extension + if os.name == "nt" and not path.endswith(".exe"): + path_with_exe = path + ".exe" + if os.path.exists(path_with_exe): + path = path_with_exe + if await _check_tool_version(path, llvm_version, echo=echo): return path # Homebrew-installed executables: - prefix = await _get_brew_llvm_prefix(echo=echo) + prefix = await _get_brew_llvm_prefix(llvm_version, echo=echo) if prefix is not None: path = os.path.join(prefix, "bin", tool) - if await _check_tool_version(path, echo=echo): + if await _check_tool_version(path, llvm_version, echo=echo): return path # Nothing found: return None async def maybe_run( - tool: str, args: typing.Iterable[str], echo: bool = False + tool: str, + args: typing.Iterable[str], + echo: bool = False, + llvm_version: str = _LLVM_VERSION, ) -> str | None: """Run an LLVM tool if it can be found. Otherwise, return None.""" - path = await _find_tool(tool, echo=echo) + + path = await _find_tool(tool, llvm_version, echo=echo) return path and await _run(path, args, echo=echo) -async def run(tool: str, args: typing.Iterable[str], echo: bool = False) -> str: +async def run( + tool: str, + args: typing.Iterable[str], + echo: bool = False, + llvm_version: str = _LLVM_VERSION, +) -> str: """Run an LLVM tool if it can be found. Otherwise, raise RuntimeError.""" - output = await maybe_run(tool, args, echo=echo) + + output = await maybe_run(tool, args, echo=echo, llvm_version=llvm_version) if output is None: - raise RuntimeError(f"Can't find {tool}-{_LLVM_VERSION}!") + raise RuntimeError(f"Can't find {tool}-{llvm_version}!") return output diff --git a/Tools/jit/_optimizers.py b/Tools/jit/_optimizers.py index 33db110b728..83c878d8fe2 100644 --- a/Tools/jit/_optimizers.py +++ b/Tools/jit/_optimizers.py @@ -1,6 +1,7 @@ """Low-level optimization of textual assembly.""" import dataclasses +import enum import pathlib import re import typing @@ -9,7 +10,7 @@ import typing _RE_NEVER_MATCH = re.compile(r"(?!)") # Dictionary mapping branch instructions to their inverted branch instructions. # If a branch cannot be inverted, the value is None: -_X86_BRANCHES = { +_X86_BRANCH_NAMES = { # https://www.felixcloutier.com/x86/jcc "ja": "jna", "jae": "jnae", @@ -37,16 +38,103 @@ _X86_BRANCHES = { "loopz": None, } # Update with all of the inverted branches, too: -_X86_BRANCHES |= {v: k for k, v in _X86_BRANCHES.items() if v} +_X86_BRANCH_NAMES |= {v: k for k, v in _X86_BRANCH_NAMES.items() if v} +# No custom relocations needed +_X86_BRANCHES: dict[str, tuple[str | None, str | None]] = { + k: (v, None) for k, v in _X86_BRANCH_NAMES.items() +} + +_AARCH64_COND_CODES = { + # https://developer.arm.com/documentation/dui0801/b/CJAJIHAD?lang=en + "eq": "ne", + "ne": "eq", + "lt": "ge", + "ge": "lt", + "gt": "le", + "le": "gt", + "vs": "vc", + "vc": "vs", + "mi": "pl", + "pl": "mi", + "cs": "cc", + "cc": "cs", + "hs": "lo", + "lo": "hs", + "hi": "ls", + "ls": "hi", +} +# MyPy doesn't understand that a invariant variable can be initialized by a covariant value +CUSTOM_AARCH64_BRANCH19: str | None = "CUSTOM_AARCH64_BRANCH19" + +_AARCH64_SHORT_BRANCHES = { + "tbz": "tbnz", + "tbnz": "tbz", +} + +# Branches are either b.{cond}, bc.{cond}, cbz, cbnz, tbz or tbnz +_AARCH64_BRANCHES: dict[str, tuple[str | None, str | None]] = ( + { + "b." + cond: (("b." + inverse if inverse else None), CUSTOM_AARCH64_BRANCH19) + for (cond, inverse) in _AARCH64_COND_CODES.items() + } + | { + "bc." + cond: (("bc." + inverse if inverse else None), CUSTOM_AARCH64_BRANCH19) + for (cond, inverse) in _AARCH64_COND_CODES.items() + } + | { + "cbz": ("cbnz", CUSTOM_AARCH64_BRANCH19), + "cbnz": ("cbz", CUSTOM_AARCH64_BRANCH19), + } + | {cond: (inverse, None) for (cond, inverse) in _AARCH64_SHORT_BRANCHES.items()} +) + + +@enum.unique +class InstructionKind(enum.Enum): + + JUMP = enum.auto() + LONG_BRANCH = enum.auto() + SHORT_BRANCH = enum.auto() + CALL = enum.auto() + RETURN = enum.auto() + SMALL_CONST_1 = enum.auto() + SMALL_CONST_2 = enum.auto() + OTHER = enum.auto() @dataclasses.dataclass +class Instruction: + kind: InstructionKind + name: str + text: str + target: str | None + + def is_branch(self) -> bool: + return self.kind in (InstructionKind.LONG_BRANCH, InstructionKind.SHORT_BRANCH) + + def update_target(self, target: str) -> "Instruction": + assert self.target is not None + return Instruction( + self.kind, self.name, self.text.replace(self.target, target), target + ) + + def update_name_and_target(self, name: str, target: str) -> "Instruction": + assert self.target is not None + return Instruction( + self.kind, + name, + self.text.replace(self.name, name).replace(self.target, target), + target, + ) + + +@dataclasses.dataclass(eq=False) class _Block: label: str | None = None # Non-instruction lines like labels, directives, and comments: noninstructions: list[str] = dataclasses.field(default_factory=list) # Instruction lines: - instructions: list[str] = dataclasses.field(default_factory=list) + instructions: list[Instruction] = dataclasses.field(default_factory=list) # If this block ends in a jump, where to? target: typing.Self | None = None # The next block in the linked list: @@ -73,6 +161,7 @@ class Optimizer: # Prefixes used to mangle local labels and symbols: label_prefix: str symbol_prefix: str + re_global: re.Pattern[str] # The first block in the linked list: _root: _Block = dataclasses.field(init=False, default_factory=_Block) _labels: dict[str, _Block] = dataclasses.field(init=False, default_factory=dict) @@ -85,28 +174,44 @@ class Optimizer: r'\s*(?P<label>[\w."$?@]+):' ) # Override everything that follows in subclasses: - _branches: typing.ClassVar[dict[str, str | None]] = {} + _supports_external_relocations = True + supports_small_constants = False + _branches: typing.ClassVar[dict[str, tuple[str | None, str | None]]] = {} + # Short branches are instructions that can branch within a micro-op, + # but might not have the reach to branch anywhere within a trace. + _short_branches: typing.ClassVar[dict[str, str]] = {} # Two groups (instruction and target): _re_branch: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH # One group (target): + _re_call: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH + # One group (target): _re_jump: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH # No groups: _re_return: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH + text: str = "" + globals: set[str] = dataclasses.field(default_factory=set) + _re_small_const_1 = _RE_NEVER_MATCH + _re_small_const_2 = _RE_NEVER_MATCH + const_reloc = "<Not supported>" def __post_init__(self) -> None: # Split the code into a linked list of basic blocks. A basic block is an # optional label, followed by zero or more non-instruction lines, # followed by zero or more instruction lines (only the last of which may # be a branch, jump, or return): - text = self._preprocess(self.path.read_text()) + self.text = self._preprocess(self.path.read_text()) block = self._root - for line in text.splitlines(): + for line in self.text.splitlines(): # See if we need to start a new block: if match := self._re_label.match(line): # Label. New block: block.link = block = self._lookup_label(match["label"]) block.noninstructions.append(line) continue + if match := self.re_global.match(line): + self.globals.add(match["label"]) + block.noninstructions.append(line) + continue if self._re_noninstructions.match(line): if block.instructions: # Non-instruction lines. New block: @@ -116,16 +221,24 @@ class Optimizer: if block.target or not block.fallthrough: # Current block ends with a branch, jump, or return. New block: block.link = block = _Block() - block.instructions.append(line) - if match := self._re_branch.match(line): + inst = self._parse_instruction(line) + block.instructions.append(inst) + if inst.is_branch(): # A block ending in a branch has a target and fallthrough: - block.target = self._lookup_label(match["target"]) + assert inst.target is not None + block.target = self._lookup_label(inst.target) assert block.fallthrough - elif match := self._re_jump.match(line): + elif inst.kind == InstructionKind.CALL: + # A block ending in a call has a target and return point after call: + assert inst.target is not None + block.target = self._lookup_label(inst.target) + assert block.fallthrough + elif inst.kind == InstructionKind.JUMP: # A block ending in a jump has a target and no fallthrough: - block.target = self._lookup_label(match["target"]) + assert inst.target is not None + block.target = self._lookup_label(inst.target) block.fallthrough = False - elif self._re_return.match(line): + elif inst.kind == InstructionKind.RETURN: # A block ending in a return has no target and fallthrough: assert not block.target block.fallthrough = False @@ -138,36 +251,59 @@ class Optimizer: continue_label = f"{self.label_prefix}_JIT_CONTINUE" return re.sub(continue_symbol, continue_label, text) - @classmethod - def _invert_branch(cls, line: str, target: str) -> str | None: - match = cls._re_branch.match(line) - assert match - inverted = cls._branches.get(match["instruction"]) + def _parse_instruction(self, line: str) -> Instruction: + target = None + if match := self._re_branch.match(line): + target = match["target"] + name = match["instruction"] + if name in self._short_branches: + kind = InstructionKind.SHORT_BRANCH + else: + kind = InstructionKind.LONG_BRANCH + elif match := self._re_jump.match(line): + target = match["target"] + name = line[: -len(target)].strip() + kind = InstructionKind.JUMP + elif match := self._re_call.match(line): + target = match["target"] + name = line[: -len(target)].strip() + kind = InstructionKind.CALL + elif match := self._re_return.match(line): + name = line + kind = InstructionKind.RETURN + elif match := self._re_small_const_1.match(line): + target = match["value"] + name = match["instruction"] + kind = InstructionKind.SMALL_CONST_1 + elif match := self._re_small_const_2.match(line): + target = match["value"] + name = match["instruction"] + kind = InstructionKind.SMALL_CONST_2 + else: + name, *_ = line.split(" ") + kind = InstructionKind.OTHER + return Instruction(kind, name, line, target) + + def _invert_branch(self, inst: Instruction, target: str) -> Instruction | None: + assert inst.is_branch() + if inst.kind == InstructionKind.SHORT_BRANCH and self._is_far_target(target): + return None + inverted_reloc = self._branches.get(inst.name) + if inverted_reloc is None: + return None + inverted = inverted_reloc[0] if not inverted: return None - (a, b), (c, d) = match.span("instruction"), match.span("target") - # Before: - # je FOO - # After: - # jne BAR - return "".join([line[:a], inverted, line[b:c], target, line[d:]]) - - @classmethod - def _update_jump(cls, line: str, target: str) -> str: - match = cls._re_jump.match(line) - assert match - a, b = match.span("target") - # Before: - # jmp FOO - # After: - # jmp BAR - return "".join([line[:a], target, line[b:]]) + return inst.update_name_and_target(inverted, target) def _lookup_label(self, label: str) -> _Block: if label not in self._labels: self._labels[label] = _Block(label) return self._labels[label] + def _is_far_target(self, label: str) -> bool: + return not label.startswith(self.label_prefix) + def _blocks(self) -> typing.Generator[_Block, None, None]: block: _Block | None = self._root while block: @@ -175,7 +311,7 @@ class Optimizer: block = block.link def _body(self) -> str: - lines = [] + lines = ["#" + line for line in self.text.splitlines()] hot = True for block in self._blocks(): if hot != block.hot: @@ -183,7 +319,8 @@ class Optimizer: # Make it easy to tell at a glance where cold code is: lines.append(f"# JIT: {'HOT' if hot else 'COLD'} ".ljust(80, "#")) lines.extend(block.noninstructions) - lines.extend(block.instructions) + for inst in block.instructions: + lines.append(inst.text) return "\n".join(lines) def _predecessors(self, block: _Block) -> typing.Generator[_Block, None, None]: @@ -250,8 +387,8 @@ class Optimizer: if inverted is None: continue branch.instructions[-1] = inverted - jump.instructions[-1] = self._update_jump( - jump.instructions[-1], branch.target.label + jump.instructions[-1] = jump.instructions[-1].update_target( + branch.target.label ) branch.target, jump.target = jump.target, branch.target jump.hot = True @@ -260,43 +397,255 @@ class Optimizer: # Zero-length jumps can be introduced by _insert_continue_label and # _invert_hot_branches: for block in self._blocks(): + target = block.target + if target is None: + continue + target = target.resolve() # Before: # jmp FOO # FOO: # After: # FOO: - if ( - block.target - and block.link - and block.target.resolve() is block.link.resolve() - ): + if block.link and target is block.link.resolve(): block.target = None block.fallthrough = True block.instructions.pop() + # Before: + # branch FOO: + # ... + # FOO: + # jump BAR + # After: + # br cond BAR + # ... + elif ( + len(target.instructions) == 1 + and target.instructions[0].kind == InstructionKind.JUMP + ): + assert target.target is not None + assert target.target.label is not None + if block.instructions[ + -1 + ].kind == InstructionKind.SHORT_BRANCH and self._is_far_target( + target.target.label + ): + continue + block.target = target.target + block.instructions[-1] = block.instructions[-1].update_target( + target.target.label + ) + + def _find_live_blocks(self) -> set[_Block]: + live: set[_Block] = set() + # Externally reachable blocks are live + todo: set[_Block] = {b for b in self._blocks() if b.label in self.globals} + while todo: + block = todo.pop() + live.add(block) + if block.fallthrough: + next = block.link + if next is not None and next not in live: + todo.add(next) + next = block.target + if next is not None and next not in live: + todo.add(next) + return live + + def _remove_unreachable(self) -> None: + live = self._find_live_blocks() + continuation = self._lookup_label(f"{self.label_prefix}_JIT_CONTINUE") + # Keep blocks after continuation as they may contain data and + # metadata that the assembler needs + prev: _Block | None = None + block = self._root + while block is not continuation: + next = block.link + assert next is not None + if not block in live and prev: + prev.link = next + else: + prev = block + block = next + assert prev.link is block + + def _fixup_external_labels(self) -> None: + if self._supports_external_relocations: + # Nothing to fix up + return + for index, block in enumerate(self._blocks()): + if block.target and block.fallthrough: + branch = block.instructions[-1] + if branch.kind == InstructionKind.CALL: + continue + assert branch.is_branch() + target = branch.target + assert target is not None + reloc = self._branches[branch.name][1] + if reloc is not None and self._is_far_target(target): + name = target[len(self.symbol_prefix) :] + label = f"{self.symbol_prefix}{reloc}_JIT_RELOCATION_{name}_JIT_RELOCATION_{index}:" + block.instructions[-1] = Instruction( + InstructionKind.OTHER, "", label, None + ) + block.instructions.append(branch.update_target("0")) + + def _make_temp_label(self, index: int) -> Instruction: + marker = f"jit_temp_{index}:" + return Instruction(InstructionKind.OTHER, "", marker, None) + + def _fixup_constants(self) -> None: + if not self.supports_small_constants: + return + index = 0 + for block in self._blocks(): + fixed: list[Instruction] = [] + small_const_index = -1 + for inst in block.instructions: + if inst.kind == InstructionKind.SMALL_CONST_1: + marker = f"jit_pending_{inst.target}{index}:" + fixed.append(self._make_temp_label(index)) + index += 1 + small_const_index = len(fixed) + fixed.append(inst) + elif inst.kind == InstructionKind.SMALL_CONST_2: + if small_const_index < 0: + fixed.append(inst) + continue + small_const_1 = fixed[small_const_index] + if not self._small_consts_match(small_const_1, inst): + small_const_index = -1 + fixed.append(inst) + continue + assert small_const_1.target is not None + if small_const_1.target.endswith("16"): + fixed[small_const_index] = self._make_temp_label(index) + index += 1 + else: + assert small_const_1.target.endswith("32") + patch_kind, replacement = self._small_const_1(small_const_1) + if replacement is not None: + label = f"{self.const_reloc}{patch_kind}_JIT_RELOCATION_CONST{small_const_1.target[:-3]}_JIT_RELOCATION_{index}:" + index += 1 + fixed[small_const_index - 1] = Instruction( + InstructionKind.OTHER, "", label, None + ) + fixed[small_const_index] = replacement + patch_kind, replacement = self._small_const_2(inst) + if replacement is not None: + assert inst.target is not None + label = f"{self.const_reloc}{patch_kind}_JIT_RELOCATION_CONST{inst.target[:-3]}_JIT_RELOCATION_{index}:" + index += 1 + fixed.append( + Instruction(InstructionKind.OTHER, "", label, None) + ) + fixed.append(replacement) + small_const_index = -1 + else: + fixed.append(inst) + block.instructions = fixed + + def _small_const_1(self, inst: Instruction) -> tuple[str, Instruction | None]: + raise NotImplementedError() + + def _small_const_2(self, inst: Instruction) -> tuple[str, Instruction | None]: + raise NotImplementedError() + + def _small_consts_match(self, inst1: Instruction, inst2: Instruction) -> bool: + raise NotImplementedError() def run(self) -> None: """Run this optimizer.""" self._insert_continue_label() self._mark_hot_blocks() - self._invert_hot_branches() - self._remove_redundant_jumps() + # Removing branches can expose opportunities for more branch removal. + # Repeat a few times. 2 would probably do, but it's fast enough with 4. + for _ in range(4): + self._invert_hot_branches() + self._remove_redundant_jumps() + self._remove_unreachable() + self._fixup_external_labels() + self._fixup_constants() self.path.write_text(self._body()) class OptimizerAArch64(Optimizer): # pylint: disable = too-few-public-methods - """aarch64-apple-darwin/aarch64-pc-windows-msvc/aarch64-unknown-linux-gnu""" + """aarch64-pc-windows-msvc/aarch64-apple-darwin/aarch64-unknown-linux-gnu""" + _branches = _AARCH64_BRANCHES + _short_branches = _AARCH64_SHORT_BRANCHES + # Mach-O does not support the 19 bit branch locations needed for branch reordering + _supports_external_relocations = False + _branch_patterns = [name.replace(".", r"\.") for name in _AARCH64_BRANCHES] + _re_branch = re.compile( + rf"\s*(?P<instruction>{'|'.join(_branch_patterns)})\s+(.+,\s+)*(?P<target>[\w.]+)" + ) + + # https://developer.arm.com/documentation/ddi0406/b/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/BL--BLX--immediate- + _re_call = re.compile(r"\s*blx?\s+(?P<target>[\w.]+)") # https://developer.arm.com/documentation/ddi0602/2025-03/Base-Instructions/B--Branch- _re_jump = re.compile(r"\s*b\s+(?P<target>[\w.]+)") + # https://developer.arm.com/documentation/ddi0602/2025-09/Base-Instructions/RET--Return-from-subroutine- + _re_return = re.compile(r"\s*ret\b") + + supports_small_constants = True + _re_small_const_1 = re.compile( + r"\s*(?P<instruction>adrp)\s+.*(?P<value>_JIT_OP(ARG|ERAND(0|1))_(16|32)).*" + ) + _re_small_const_2 = re.compile( + r"\s*(?P<instruction>ldr)\s+.*(?P<value>_JIT_OP(ARG|ERAND(0|1))_(16|32)).*" + ) + const_reloc = "CUSTOM_AARCH64_CONST" + + def _get_reg(self, inst: Instruction) -> str: + _, rest = inst.text.split(inst.name) + reg, *_ = rest.split(",") + return reg.strip() + + def _small_const_1(self, inst: Instruction) -> tuple[str, Instruction | None]: + assert inst.kind is InstructionKind.SMALL_CONST_1 + assert inst.target is not None + if "16" in inst.target: + return "", None + pre, _ = inst.text.split(inst.name) + return "16a", Instruction( + InstructionKind.OTHER, "movz", f"{pre}movz {self._get_reg(inst)}, 0", None + ) + + def _small_const_2(self, inst: Instruction) -> tuple[str, Instruction | None]: + assert inst.kind is InstructionKind.SMALL_CONST_2 + assert inst.target is not None + pre, _ = inst.text.split(inst.name) + if "16" in inst.target: + return "16a", Instruction( + InstructionKind.OTHER, + "movz", + f"{pre}movz {self._get_reg(inst)}, 0", + None, + ) + else: + return "16b", Instruction( + InstructionKind.OTHER, + "movk", + f"{pre}movk {self._get_reg(inst)}, 0, lsl #16", + None, + ) + + def _small_consts_match(self, inst1: Instruction, inst2: Instruction) -> bool: + reg1 = self._get_reg(inst1) + reg2 = self._get_reg(inst2) + return reg1 == reg2 class OptimizerX86(Optimizer): # pylint: disable = too-few-public-methods """i686-pc-windows-msvc/x86_64-apple-darwin/x86_64-unknown-linux-gnu""" _branches = _X86_BRANCHES + _short_branches = {} _re_branch = re.compile( rf"\s*(?P<instruction>{'|'.join(_X86_BRANCHES)})\s+(?P<target>[\w.]+)" ) + # https://www.felixcloutier.com/x86/call + _re_call = re.compile(r"\s*callq?\s+(?P<target>[\w.]+)") # https://www.felixcloutier.com/x86/jmp _re_jump = re.compile(r"\s*jmp\s+(?P<target>[\w.]+)") # https://www.felixcloutier.com/x86/ret diff --git a/Tools/jit/_schema.py b/Tools/jit/_schema.py index 228fc389584..964e8bdbdc1 100644 --- a/Tools/jit/_schema.py +++ b/Tools/jit/_schema.py @@ -9,7 +9,11 @@ HoleKind: typing.TypeAlias = typing.Literal[ "ARM64_RELOC_PAGE21", "ARM64_RELOC_PAGEOFF12", "ARM64_RELOC_UNSIGNED", + "CUSTOM_AARCH64_BRANCH19", + "CUSTOM_AARCH64_CONST_16", + "CUSTOM_AARCH64_CONST_32", "IMAGE_REL_AMD64_REL32", + "IMAGE_REL_ARM64_BRANCH19", "IMAGE_REL_ARM64_BRANCH26", "IMAGE_REL_ARM64_PAGEBASE_REL21", "IMAGE_REL_ARM64_PAGEOFFSET_12A", @@ -20,6 +24,7 @@ HoleKind: typing.TypeAlias = typing.Literal[ "R_AARCH64_ADR_GOT_PAGE", "R_AARCH64_ADR_PREL_PG_HI21", "R_AARCH64_CALL26", + "R_AARCH64_CONDBR19", "R_AARCH64_JUMP26", "R_AARCH64_ADD_ABS_LO12_NC", "R_AARCH64_LD64_GOT_LO12_NC", @@ -87,6 +92,7 @@ class COFFSection(typing.TypedDict): Characteristics: dict[ typing.Literal["Flags"], list[dict[typing.Literal["Name"], str]] ] + Name: dict[typing.Literal["Value"], str] Number: int RawDataSize: int Relocations: list[dict[typing.Literal["Relocation"], COFFRelocation]] diff --git a/Tools/jit/_stencils.py b/Tools/jit/_stencils.py index 1d82f5366f6..2b78d8013af 100644 --- a/Tools/jit/_stencils.py +++ b/Tools/jit/_stencils.py @@ -32,6 +32,12 @@ class HoleValue(enum.Enum): # The current uop's operand0 on 32-bit platforms (exposed as _JIT_OPERAND0_HI/LO): OPERAND0_HI = enum.auto() OPERAND0_LO = enum.auto() + # 16 and 32 bit versions of OPARG, OPERAND0 and OPERAND1 + OPARG_16 = enum.auto() + OPERAND0_16 = enum.auto() + OPERAND1_16 = enum.auto() + OPERAND0_32 = enum.auto() + OPERAND1_32 = enum.auto() # The current uop's operand1 on 64-bit platforms (exposed as _JIT_OPERAND1): OPERAND1 = enum.auto() # The current uop's operand1 on 32-bit platforms (exposed as _JIT_OPERAND1_HI/LO): @@ -58,9 +64,13 @@ _PATCH_FUNCS = { "ARM64_RELOC_PAGE21": "patch_aarch64_21r", "ARM64_RELOC_PAGEOFF12": "patch_aarch64_12", "ARM64_RELOC_UNSIGNED": "patch_64", + "CUSTOM_AARCH64_BRANCH19": "patch_aarch64_19r", + "CUSTOM_AARCH64_CONST16a": "patch_aarch64_16a", + "CUSTOM_AARCH64_CONST16b": "patch_aarch64_16b", # x86_64-pc-windows-msvc: "IMAGE_REL_AMD64_REL32": "patch_x86_64_32rx", # aarch64-pc-windows-msvc: + "IMAGE_REL_ARM64_BRANCH19": "patch_aarch64_19r", "IMAGE_REL_ARM64_BRANCH26": "patch_aarch64_26r", "IMAGE_REL_ARM64_PAGEBASE_REL21": "patch_aarch64_21rx", "IMAGE_REL_ARM64_PAGEOFFSET_12A": "patch_aarch64_12", @@ -74,6 +84,7 @@ _PATCH_FUNCS = { "R_AARCH64_ADR_GOT_PAGE": "patch_aarch64_21rx", "R_AARCH64_ADR_PREL_PG_HI21": "patch_aarch64_21r", "R_AARCH64_CALL26": "patch_aarch64_26r", + "R_AARCH64_CONDBR19": "patch_aarch64_19r", "R_AARCH64_JUMP26": "patch_aarch64_26r", "R_AARCH64_LD64_GOT_LO12_NC": "patch_aarch64_12x", "R_AARCH64_MOVW_UABS_G0_NC": "patch_aarch64_16a", @@ -92,18 +103,24 @@ _PATCH_FUNCS = { "X86_64_RELOC_SIGNED": "patch_32r", "X86_64_RELOC_UNSIGNED": "patch_64", } + # Translate HoleValues to C expressions: _HOLE_EXPRS = { HoleValue.CODE: "(uintptr_t)code", HoleValue.DATA: "(uintptr_t)data", HoleValue.EXECUTOR: "(uintptr_t)executor", + HoleValue.GOT: "", # These should all have been turned into DATA values by process_relocations: - # HoleValue.GOT: "", HoleValue.OPARG: "instruction->oparg", + HoleValue.OPARG_16: "instruction->oparg", HoleValue.OPERAND0: "instruction->operand0", + HoleValue.OPERAND0_16: "instruction->operand0", + HoleValue.OPERAND0_32: "instruction->operand0", HoleValue.OPERAND0_HI: "(instruction->operand0 >> 32)", HoleValue.OPERAND0_LO: "(instruction->operand0 & UINT32_MAX)", HoleValue.OPERAND1: "instruction->operand1", + HoleValue.OPERAND1_16: "instruction->operand1", + HoleValue.OPERAND1_32: "instruction->operand1", HoleValue.OPERAND1_HI: "(instruction->operand1 >> 32)", HoleValue.OPERAND1_LO: "(instruction->operand1 & UINT32_MAX)", HoleValue.TARGET: "instruction->target", @@ -112,6 +129,24 @@ _HOLE_EXPRS = { HoleValue.ZERO: "", } +_AARCH64_GOT_RELOCATIONS = { + "R_AARCH64_ADR_GOT_PAGE", + "R_AARCH64_LD64_GOT_LO12_NC", + "ARM64_RELOC_GOT_LOAD_PAGE21", + "ARM64_RELOC_GOT_LOAD_PAGEOFF12", + "IMAGE_REL_ARM64_PAGEBASE_REL21", + "IMAGE_REL_ARM64_PAGEOFFSET_12L", + "IMAGE_REL_ARM64_PAGEOFFSET_12A", +} + +_X86_GOT_RELOCATIONS = { + "R_X86_64_GOTPCRELX", + "R_X86_64_REX_GOTPCRELX", + "X86_64_RELOC_GOT", + "X86_64_RELOC_GOT_LOAD", + "IMAGE_REL_AMD64_REL32", +} + @dataclasses.dataclass class Hole: @@ -130,6 +165,8 @@ class Hole: # ...plus this addend: addend: int need_state: bool = False + custom_location: str = "" + custom_value: str = "" func: str = dataclasses.field(init=False) # Convenience method: replace = dataclasses.replace @@ -137,11 +174,7 @@ class Hole: def __post_init__(self) -> None: self.func = _PATCH_FUNCS[self.kind] - def fold( - self, - other: typing.Self, - body: bytes | bytearray, - ) -> typing.Self | None: + def fold(self, other: typing.Self, body: bytearray) -> typing.Self | None: """Combine two holes into a single hole, if possible.""" instruction_a = int.from_bytes( body[self.offset : self.offset + 4], byteorder=sys.byteorder @@ -171,16 +204,25 @@ class Hole: def as_c(self, where: str) -> str: """Dump this hole as a call to a patch_* function.""" - location = f"{where} + {self.offset:#x}" - value = _HOLE_EXPRS[self.value] - if self.symbol: - if value: - value += " + " - value += f"(uintptr_t)&{self.symbol}" - if _signed(self.addend) or not value: - if value: - value += " + " - value += f"{_signed(self.addend):#x}" + if self.custom_location: + location = self.custom_location + else: + location = f"{where} + {self.offset:#x}" + if self.custom_value: + value = self.custom_value + else: + value = _HOLE_EXPRS[self.value] + if self.symbol: + if value: + value += " + " + if self.symbol.startswith("CONST"): + value += f"instruction->{self.symbol[10:].lower()}" + else: + value += f"(uintptr_t)&{self.symbol}" + if _signed(self.addend) or not value: + if value: + value += " + " + value += f"{_signed(self.addend):#x}" if self.need_state: return f"{self.func}({location}, {value}, state);" return f"{self.func}({location}, {value});" @@ -220,8 +262,22 @@ class StencilGroup: symbols: dict[int | str, tuple[HoleValue, int]] = dataclasses.field( default_factory=dict, init=False ) - _got: dict[str, int] = dataclasses.field(default_factory=dict, init=False) + _jit_symbol_table: dict[str, int] = dataclasses.field( + default_factory=dict, init=False + ) _trampolines: set[int] = dataclasses.field(default_factory=set, init=False) + _got_entries: set[int] = dataclasses.field(default_factory=set, init=False) + + def convert_labels_to_relocations(self) -> None: + for name, hole_plus in self.symbols.items(): + if isinstance(name, str) and "_JIT_RELOCATION_" in name: + _, offset = hole_plus + reloc, target, _ = name.split("_JIT_RELOCATION_") + value, symbol = symbol_to_value(target) + hole = Hole( + int(offset), typing.cast(_schema.HoleKind, reloc), value, symbol, 0 + ) + self.code.holes.append(hole) def process_relocations(self, known_symbols: dict[str, int]) -> None: """Fix up all GOT and internal relocations for this stencil group.""" @@ -243,13 +299,56 @@ class StencilGroup: self._trampolines.add(ordinal) hole.addend = ordinal hole.symbol = None + # x86_64 Darwin trampolines for external symbols + elif ( + hole.kind == "X86_64_RELOC_BRANCH" + and hole.value is HoleValue.ZERO + and hole.symbol not in self.symbols + ): + hole.func = "patch_x86_64_trampoline" + hole.need_state = True + assert hole.symbol is not None + if hole.symbol in known_symbols: + ordinal = known_symbols[hole.symbol] + else: + ordinal = len(known_symbols) + known_symbols[hole.symbol] = ordinal + self._trampolines.add(ordinal) + hole.addend = ordinal + hole.symbol = None + elif ( + hole.kind in _AARCH64_GOT_RELOCATIONS | _X86_GOT_RELOCATIONS + and hole.symbol + and "_JIT_" not in hole.symbol + and hole.value is HoleValue.GOT + ): + if hole.symbol in known_symbols: + ordinal = known_symbols[hole.symbol] + else: + ordinal = len(known_symbols) + known_symbols[hole.symbol] = ordinal + self._got_entries.add(ordinal) self.data.pad(8) for stencil in [self.code, self.data]: for hole in stencil.holes: if hole.value is HoleValue.GOT: assert hole.symbol is not None - hole.value = HoleValue.DATA - hole.addend += self._global_offset_table_lookup(hole.symbol) + if "_JIT_" in hole.symbol: + # Relocations for local symbols + hole.value = HoleValue.DATA + hole.addend += self._jit_symbol_table_lookup(hole.symbol) + else: + _ordinal = known_symbols[hole.symbol] + _custom_value = f"got_symbol_address({_ordinal:#x}, state)" + if hole.kind in _X86_GOT_RELOCATIONS: + # When patching on x86, subtract the addend -4 + # that is used to compute the 32 bit RIP relative + # displacement to the GOT entry + _custom_value = ( + f"got_symbol_address({_ordinal:#x}, state) - 4" + ) + hole.addend = _ordinal + hole.custom_value = _custom_value hole.symbol = None elif hole.symbol in self.symbols: hole.value, addend = self.symbols[hole.symbol] @@ -262,16 +361,19 @@ class StencilGroup: raise ValueError( f"Add PyAPI_FUNC(...) or PyAPI_DATA(...) to declaration of {hole.symbol}!" ) + self._emit_jit_symbol_table() self._emit_global_offset_table() self.code.holes.sort(key=lambda hole: hole.offset) self.data.holes.sort(key=lambda hole: hole.offset) - def _global_offset_table_lookup(self, symbol: str) -> int: - return len(self.data.body) + self._got.setdefault(symbol, 8 * len(self._got)) + def _jit_symbol_table_lookup(self, symbol: str) -> int: + return len(self.data.body) + self._jit_symbol_table.setdefault( + symbol, 8 * len(self._jit_symbol_table) + ) - def _emit_global_offset_table(self) -> None: + def _emit_jit_symbol_table(self) -> None: got = len(self.data.body) - for s, offset in self._got.items(): + for s, offset in self._jit_symbol_table.items(): if s in self.symbols: value, addend = self.symbols[s] symbol = None @@ -295,20 +397,35 @@ class StencilGroup: ) self.data.body.extend([0] * 8) - def _get_trampoline_mask(self) -> str: + def _emit_global_offset_table(self) -> None: + for hole in self.code.holes: + if hole.value is HoleValue.GOT: + _got_hole = Hole(0, "R_X86_64_64", hole.value, None, hole.addend) + _got_hole.func = "patch_got_symbol" + _got_hole.custom_location = "state" + if _got_hole not in self.data.holes: + self.data.holes.append(_got_hole) + + def _get_symbol_mask(self, ordinals: set[int]) -> str: bitmask: int = 0 - trampoline_mask: list[str] = [] - for ordinal in self._trampolines: + symbol_mask: list[str] = [] + for ordinal in ordinals: bitmask |= 1 << ordinal while bitmask: word = bitmask & ((1 << 32) - 1) - trampoline_mask.append(f"{word:#04x}") + symbol_mask.append(f"{word:#04x}") bitmask >>= 32 - return "{" + (", ".join(trampoline_mask) or "0") + "}" + return "{" + (", ".join(symbol_mask) or "0") + "}" + + def _get_trampoline_mask(self) -> str: + return self._get_symbol_mask(self._trampolines) + + def _get_got_mask(self) -> str: + return self._get_symbol_mask(self._got_entries) def as_c(self, opname: str) -> str: """Dump this hole as a StencilGroup initializer.""" - return f"{{emit_{opname}, {len(self.code.body)}, {len(self.data.body)}, {self._get_trampoline_mask()}}}" + return f"{{emit_{opname}, {len(self.code.body)}, {len(self.data.body)}, {self._get_trampoline_mask()}, {self._get_got_mask()}}}" def symbol_to_value(symbol: str) -> tuple[HoleValue, str | None]: diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index 7e261c9f8e2..5895e91c3c4 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -46,10 +46,12 @@ class _Target(typing.Generic[_S, _R]): optimizer: type[_optimizers.Optimizer] = _optimizers.Optimizer label_prefix: typing.ClassVar[str] symbol_prefix: typing.ClassVar[str] + re_global: typing.ClassVar[re.Pattern[str]] stable: bool = False debug: bool = False verbose: bool = False cflags: str = "" + llvm_version: str = _llvm._LLVM_VERSION known_symbols: dict[str, int] = dataclasses.field(default_factory=dict) pyconfig_dir: pathlib.Path = pathlib.Path.cwd().resolve() @@ -71,14 +73,19 @@ class _Target(typing.Generic[_S, _R]): hasher.update(PYTHON_EXECUTOR_CASES_C_H.read_bytes()) hasher.update((self.pyconfig_dir / "pyconfig.h").read_bytes()) for dirpath, _, filenames in sorted(os.walk(TOOLS_JIT)): - for filename in filenames: + # Exclude cache files from digest computation to ensure reproducible builds. + if dirpath.endswith("__pycache__"): + continue + for filename in sorted(filenames): hasher.update(pathlib.Path(dirpath, filename).read_bytes()) return hasher.hexdigest() async def _parse(self, path: pathlib.Path) -> _stencils.StencilGroup: group = _stencils.StencilGroup() args = ["--disassemble", "--reloc", f"{path}"] - output = await _llvm.maybe_run("llvm-objdump", args, echo=self.verbose) + output = await _llvm.maybe_run( + "llvm-objdump", args, echo=self.verbose, llvm_version=self.llvm_version + ) if output is not None: # Make sure that full paths don't leak out (for reproducibility): long, short = str(path), str(path.name) @@ -96,7 +103,9 @@ class _Target(typing.Generic[_S, _R]): "--sections", f"{path}", ] - output = await _llvm.run("llvm-readobj", args, echo=self.verbose) + output = await _llvm.run( + "llvm-readobj", args, echo=self.verbose, llvm_version=self.llvm_version + ) # --elf-output-style=JSON is only *slightly* broken on Mach-O... output = output.replace("PrivateExtern\n", "\n") output = output.replace("Extern\n", "\n") @@ -116,7 +125,7 @@ class _Target(typing.Generic[_S, _R]): raise NotImplementedError(type(self)) def _handle_relocation( - self, base: int, relocation: _R, raw: bytes | bytearray + self, base: int, relocation: _R, raw: bytearray ) -> _stencils.Hole: raise NotImplementedError(type(self)) @@ -129,6 +138,7 @@ class _Target(typing.Generic[_S, _R]): f"--target={self.triple}", "-DPy_BUILD_CORE_MODULE", "-D_DEBUG" if self.debug else "-DNDEBUG", + f"-DSUPPORTS_SMALL_CONSTS={1 if self.optimizer.supports_small_constants else 0}", f"-D_JIT_OPCODE={opname}", "-D_PyJIT_ACTIVE", "-D_Py_JIT", @@ -158,10 +168,6 @@ class _Target(typing.Generic[_S, _R]): "-fno-asynchronous-unwind-tables", # Don't call built-in functions that we can't find or patch: "-fno-builtin", - # Emit relaxable 64-bit calls/jumps, so we don't have to worry about - # about emitting in-range trampolines for out-of-range targets. - # We can probably remove this and emit trampolines in the future: - "-fno-plt", # Don't call stack-smashing canaries that we can't find or patch: "-fno-stack-protector", "-std=c11", @@ -172,12 +178,19 @@ class _Target(typing.Generic[_S, _R]): # Allow user-provided CFLAGS to override any defaults *shlex.split(self.cflags), ] - await _llvm.run("clang", args_s, echo=self.verbose) + await _llvm.run( + "clang", args_s, echo=self.verbose, llvm_version=self.llvm_version + ) self.optimizer( - s, label_prefix=self.label_prefix, symbol_prefix=self.symbol_prefix + s, + label_prefix=self.label_prefix, + symbol_prefix=self.symbol_prefix, + re_global=self.re_global, ).run() args_o = [f"--target={self.triple}", "-c", "-o", f"{o}", f"{s}"] - await _llvm.run("clang", args_o, echo=self.verbose) + await _llvm.run( + "clang", args_o, echo=self.verbose, llvm_version=self.llvm_version + ) return await self._parse(o) async def _build_stencils(self) -> dict[str, _stencils.StencilGroup]: @@ -206,6 +219,7 @@ class _Target(typing.Generic[_S, _R]): tasks.append(group.create_task(coro, name=opname)) stencil_groups = {task.get_name(): task.result() for task in tasks} for stencil_group in stencil_groups.values(): + stencil_group.convert_labels_to_relocations() stencil_group.process_relocations(self.known_symbols) return stencil_groups @@ -221,6 +235,8 @@ class _Target(typing.Generic[_S, _R]): if not self.stable: warning = f"JIT support for {self.triple} is still experimental!" request = "Please report any issues you encounter.".center(len(warning)) + if self.llvm_version != _llvm._LLVM_VERSION: + request = f"Warning! Building with an LLVM version other than {_llvm._LLVM_VERSION} is not supported." outline = "=" * len(warning) print("\n".join(["", outline, warning, request, outline, ""])) digest = f"// {self._compute_digest()}\n" @@ -256,6 +272,10 @@ class _COFF( def _handle_section( self, section: _schema.COFFSection, group: _stencils.StencilGroup ) -> None: + name = section["Name"]["Value"] + if name == ".debug$S": + # skip debug sections + return flags = {flag["Name"] for flag in section["Characteristics"]["Flags"]} if "SectionData" in section: section_data_bytes = section["SectionData"]["Bytes"] @@ -294,10 +314,7 @@ class _COFF( return _stencils.symbol_to_value(name) def _handle_relocation( - self, - base: int, - relocation: _schema.COFFRelocation, - raw: bytes | bytearray, + self, base: int, relocation: _schema.COFFRelocation, raw: bytearray ) -> _stencils.Hole: match relocation: case { @@ -324,7 +341,8 @@ class _COFF( "Offset": offset, "Symbol": s, "Type": { - "Name": "IMAGE_REL_ARM64_BRANCH26" + "Name": "IMAGE_REL_ARM64_BRANCH19" + | "IMAGE_REL_ARM64_BRANCH26" | "IMAGE_REL_ARM64_PAGEBASE_REL21" | "IMAGE_REL_ARM64_PAGEOFFSET_12A" | "IMAGE_REL_ARM64_PAGEOFFSET_12L" as kind @@ -342,12 +360,14 @@ class _COFF32(_COFF): # These mangle like Mach-O and other "older" formats: label_prefix = "L" symbol_prefix = "_" + re_global = re.compile(r'\s*\.def\s+(?P<label>[\w."$?@]+);') class _COFF64(_COFF): # These mangle like ELF and other "newer" formats: label_prefix = ".L" symbol_prefix = "" + re_global = re.compile(r'\s*\.def\s+(?P<label>[\w."$?@]+);') class _ELF( @@ -355,6 +375,7 @@ class _ELF( ): # pylint: disable = too-few-public-methods label_prefix = ".L" symbol_prefix = "" + re_global = re.compile(r'\s*\.globl\s+(?P<label>[\w."$?@]+)(\s+.*)?') def _handle_section( self, section: _schema.ELFSection, group: _stencils.StencilGroup @@ -407,10 +428,7 @@ class _ELF( }, section_type def _handle_relocation( - self, - base: int, - relocation: _schema.ELFRelocation, - raw: bytes | bytearray, + self, base: int, relocation: _schema.ELFRelocation, raw: bytearray ) -> _stencils.Hole: symbol: str | None match relocation: @@ -448,6 +466,7 @@ class _MachO( ): # pylint: disable = too-few-public-methods label_prefix = "L" symbol_prefix = "_" + re_global = re.compile(r'\s*\.globl\s+(?P<label>[\w."$?@]+)(\s+.*)?') def _handle_section( self, section: _schema.MachOSection, group: _stencils.StencilGroup @@ -489,10 +508,7 @@ class _MachO( stencil.holes.append(hole) def _handle_relocation( - self, - base: int, - relocation: _schema.MachORelocation, - raw: bytes | bytearray, + self, base: int, relocation: _schema.MachORelocation, raw: bytearray ) -> _stencils.Hole: symbol: str | None match relocation: @@ -557,38 +573,45 @@ def get_target(host: str) -> _COFF32 | _COFF64 | _ELF | _MachO: optimizer: type[_optimizers.Optimizer] target: _COFF32 | _COFF64 | _ELF | _MachO if re.fullmatch(r"aarch64-apple-darwin.*", host): + host = "aarch64-apple-darwin" condition = "defined(__aarch64__) && defined(__APPLE__)" optimizer = _optimizers.OptimizerAArch64 target = _MachO(host, condition, optimizer=optimizer) elif re.fullmatch(r"aarch64-pc-windows-msvc", host): - args = ["-fms-runtime-lib=dll", "-fplt"] + host = "aarch64-pc-windows-msvc" condition = "defined(_M_ARM64)" + args = ["-fms-runtime-lib=dll"] optimizer = _optimizers.OptimizerAArch64 target = _COFF64(host, condition, args=args, optimizer=optimizer) elif re.fullmatch(r"aarch64-.*-linux-gnu", host): - # -mno-outline-atomics: Keep intrinsics from being emitted. - args = ["-fpic", "-mno-outline-atomics"] + host = "aarch64-unknown-linux-gnu" condition = "defined(__aarch64__) && defined(__linux__)" + # -mno-outline-atomics: Keep intrinsics from being emitted. + args = ["-fpic", "-mno-outline-atomics", "-fno-plt"] optimizer = _optimizers.OptimizerAArch64 target = _ELF(host, condition, args=args, optimizer=optimizer) elif re.fullmatch(r"i686-pc-windows-msvc", host): + host = "i686-pc-windows-msvc" + condition = "defined(_M_IX86)" # -Wno-ignored-attributes: __attribute__((preserve_none)) is not supported here. args = ["-DPy_NO_ENABLE_SHARED", "-Wno-ignored-attributes"] optimizer = _optimizers.OptimizerX86 - condition = "defined(_M_IX86)" target = _COFF32(host, condition, args=args, optimizer=optimizer) elif re.fullmatch(r"x86_64-apple-darwin.*", host): + host = "x86_64-apple-darwin" condition = "defined(__x86_64__) && defined(__APPLE__)" optimizer = _optimizers.OptimizerX86 target = _MachO(host, condition, optimizer=optimizer) elif re.fullmatch(r"x86_64-pc-windows-msvc", host): - args = ["-fms-runtime-lib=dll"] + host = "x86_64-pc-windows-msvc" condition = "defined(_M_X64)" + args = ["-fms-runtime-lib=dll"] optimizer = _optimizers.OptimizerX86 target = _COFF64(host, condition, args=args, optimizer=optimizer) elif re.fullmatch(r"x86_64-.*-linux-gnu", host): - args = ["-fno-pic", "-mcmodel=medium", "-mlarge-data-threshold=0"] + host = "x86_64-unknown-linux-gnu" condition = "defined(__x86_64__) && defined(__linux__)" + args = ["-fno-pic", "-mcmodel=medium", "-mlarge-data-threshold=0", "-fno-plt"] optimizer = _optimizers.OptimizerX86 target = _ELF(host, condition, args=args, optimizer=optimizer) else: diff --git a/Tools/jit/_writer.py b/Tools/jit/_writer.py index 4f373011ebf..3a59ffce7a2 100644 --- a/Tools/jit/_writer.py +++ b/Tools/jit/_writer.py @@ -20,11 +20,12 @@ def _dump_footer( yield " size_t code_size;" yield " size_t data_size;" yield " symbol_mask trampoline_mask;" + yield " symbol_mask got_mask;" yield "} StencilGroup;" yield "" yield f"static const StencilGroup trampoline = {groups['trampoline'].as_c('trampoline')};" yield "" - yield "static const StencilGroup stencil_groups[MAX_UOP_ID + 1] = {" + yield "static const StencilGroup stencil_groups[MAX_UOP_REGS_ID + 1] = {" for opname, group in sorted(groups.items()): if opname == "trampoline": continue diff --git a/Tools/jit/build.py b/Tools/jit/build.py index a0733005929..127d93b317f 100644 --- a/Tools/jit/build.py +++ b/Tools/jit/build.py @@ -42,6 +42,7 @@ if __name__ == "__main__": parser.add_argument( "--cflags", help="additional flags to pass to the compiler", default="" ) + parser.add_argument("--llvm-version", help="LLVM version to use") args = parser.parse_args() for target in args.target: target.debug = args.debug @@ -49,6 +50,8 @@ if __name__ == "__main__": target.verbose = args.verbose target.cflags = args.cflags target.pyconfig_dir = args.pyconfig_dir + if args.llvm_version: + target.llvm_version = args.llvm_version target.build( comment=comment, force=args.force, diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h index 10829654eab..d5cf288c660 100644 --- a/Tools/jit/jit.h +++ b/Tools/jit/jit.h @@ -9,4 +9,5 @@ typedef jit_func __attribute__((preserve_none)) jit_func_preserve_none; #define DECLARE_TARGET(NAME) \ _Py_CODEUNIT *__attribute__((preserve_none, visibility("hidden"))) \ - NAME(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate); + NAME(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, \ + _PyStackRef _tos_cache0, _PyStackRef _tos_cache1, _PyStackRef _tos_cache2); diff --git a/Tools/jit/jit_infra.md b/Tools/jit/jit_infra.md new file mode 100644 index 00000000000..0b851c67d65 --- /dev/null +++ b/Tools/jit/jit_infra.md @@ -0,0 +1,35 @@ +# JIT Build Infrastructure + +This document includes details about the intricacies of the JIT build infrastructure. + +## Updating LLVM + +When we update LLVM, we need to also update the LLVM release artifact for Windows builds. This is because Windows builds automatically pull prebuilt LLVM binaries in our pipelines (e.g. notice that `.github/workflows/jit.yml` does not explicitly download LLVM or build it from source). + +To update the LLVM release artifact for Windows builds, follow these steps: +1. Go to the [LLVM releases page](https://github.com/llvm/llvm-project/releases). +1. Download Windows artifacts for the desired LLVM version (e.g. `clang+llvm-21.1.4-x86_64-pc-windows-msvc.tar.xz` and `clang+llvm-21.1.4-aarch64-pc-windows-msvc.tar.xz`). +1. Extract and repackage each tarball with the correct directory structure. For example: + ```bash + # For x86_64 (AMD64) + tar -xf clang+llvm-21.1.4-x86_64-pc-windows-msvc.tar.xz + mv clang+llvm-21.1.4-x86_64-pc-windows-msvc llvm-21.1.4.0 + tar -cf - llvm-21.1.4.0 | pv | xz > llvm-21.1.4.0-x64.tar.xz + rm -rf llvm-21.1.4.0 + + # For ARM64 + tar -xf clang+llvm-21.1.4-aarch64-pc-windows-msvc.tar.xz + mv clang+llvm-21.1.4-aarch64-pc-windows-msvc llvm-21.1.4.0 + tar -cf - llvm-21.1.4.0 | pv | xz > llvm-21.1.4.0-ARM64.tar.xz + ``` + Each tarball must contain a top-level directory named `llvm-{version}.0/`. +1. Go to [cpython-bin-deps](https://github.com/python/cpython-bin-deps). +1. Create a new release with the LLVM artifacts. + - Create a new tag to match the LLVM version (e.g. `llvm-21.1.4.0`). + - Specify the release title (e.g. `LLVM 21.1.4`). + - Upload both platform-specific assets to the same release. + +### Other notes +- You must make sure that the name of the artifact matches exactly what is expected in `Tools/jit/_llvm.py` and `PCbuild/get_externals.py`. +- The artifact filename must include the architecture suffix (e.g. `llvm-21.1.4.0-x64.tar.xz`, `llvm-21.1.4.0-ARM64.tar.xz`). +- You must have permissions to create releases in the `cpython-bin-deps` repository. If you don't have permissions, you should contact one of the organization admins. \ No newline at end of file diff --git a/Tools/jit/template.c b/Tools/jit/template.c index 8f71010a1af..064b401bc3a 100644 --- a/Tools/jit/template.c +++ b/Tools/jit/template.c @@ -34,14 +34,38 @@ #include "jit.h" + +#undef CURRENT_OPERAND0_64 +#define CURRENT_OPERAND0_64() (_operand0_64) + +#undef CURRENT_OPERAND1_64 +#define CURRENT_OPERAND1_64() (_operand1_64) + + #undef CURRENT_OPARG +#undef CURRENT_OPERAND0_16 +#undef CURRENT_OPERAND0_32 +#undef CURRENT_OPERAND1_16 +#undef CURRENT_OPERAND1_32 + +#if SUPPORTS_SMALL_CONSTS + +#define CURRENT_OPARG() (_oparg_16) +#define CURRENT_OPERAND0_32() (_operand0_32) +#define CURRENT_OPERAND0_16() (_operand0_16) +#define CURRENT_OPERAND1_32() (_operand1_32) +#define CURRENT_OPERAND1_16() (_operand1_16) + +#else + #define CURRENT_OPARG() (_oparg) +#define CURRENT_OPERAND0_32() (_operand0_64) +#define CURRENT_OPERAND0_16() (_operand0_64) +#define CURRENT_OPERAND1_32() (_operand1_64) +#define CURRENT_OPERAND1_16() (_operand1_64) -#undef CURRENT_OPERAND0 -#define CURRENT_OPERAND0() (_operand0) +#endif -#undef CURRENT_OPERAND1 -#define CURRENT_OPERAND1() (_operand1) #undef CURRENT_TARGET #define CURRENT_TARGET() (_target) @@ -52,16 +76,14 @@ do { \ OPT_STAT_INC(traces_executed); \ _PyExecutorObject *_executor = (EXECUTOR); \ jit_func_preserve_none jitted = _executor->jit_code; \ - __attribute__((musttail)) return jitted(frame, stack_pointer, tstate); \ + __attribute__((musttail)) return jitted(frame, stack_pointer, tstate, \ + _tos_cache0, _tos_cache1, _tos_cache2); \ } while (0) -#undef GOTO_TIER_ONE -#define GOTO_TIER_ONE(TARGET) \ -do { \ - tstate->current_executor = NULL; \ - _PyFrame_SetStackPointer(frame, stack_pointer); \ - return TARGET; \ -} while (0) +#undef GOTO_TIER_ONE_SETUP +#define GOTO_TIER_ONE_SETUP \ + tstate->current_executor = NULL; \ + _PyFrame_SetStackPointer(frame, stack_pointer); #undef LOAD_IP #define LOAD_IP(UNUSED) \ @@ -69,14 +91,17 @@ do { \ } while (0) #undef LLTRACE_RESUME_FRAME -#define LLTRACE_RESUME_FRAME() \ - do { \ - } while (0) +#ifdef Py_DEBUG +#define LLTRACE_RESUME_FRAME() (frame->lltrace = 0) +#else +#define LLTRACE_RESUME_FRAME() do {} while (0) +#endif #define PATCH_JUMP(ALIAS) \ do { \ DECLARE_TARGET(ALIAS); \ - __attribute__((musttail)) return ALIAS(frame, stack_pointer, tstate); \ + __attribute__((musttail)) return ALIAS(frame, stack_pointer, tstate, \ + _tos_cache0, _tos_cache1, _tos_cache2); \ } while (0) #undef JUMP_TO_JUMP_TARGET @@ -87,27 +112,43 @@ do { \ #define TIER_TWO 2 +#ifdef Py_DEBUG +#define ASSERT_WITHIN_STACK_BOUNDS(F, L) _Py_assert_within_stack_bounds(frame, stack_pointer, (F), (L)) +#else +#define ASSERT_WITHIN_STACK_BOUNDS(F, L) (void)0 +#endif + __attribute__((preserve_none)) _Py_CODEUNIT * -_JIT_ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) -{ +_JIT_ENTRY( + _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, + _PyStackRef _tos_cache0, _PyStackRef _tos_cache1, _PyStackRef _tos_cache2 +) { // Locals that the instruction implementations expect to exist: PATCH_VALUE(_PyExecutorObject *, current_executor, _JIT_EXECUTOR) int oparg; int uopcode = _JIT_OPCODE; _Py_CODEUNIT *next_instr; // Other stuff we need handy: - PATCH_VALUE(uint16_t, _oparg, _JIT_OPARG) #if SIZEOF_VOID_P == 8 - PATCH_VALUE(uint64_t, _operand0, _JIT_OPERAND0) - PATCH_VALUE(uint64_t, _operand1, _JIT_OPERAND1) + PATCH_VALUE(uint64_t, _operand0_64, _JIT_OPERAND0) + PATCH_VALUE(uint64_t, _operand1_64, _JIT_OPERAND1) #else assert(SIZEOF_VOID_P == 4); PATCH_VALUE(uint32_t, _operand0_hi, _JIT_OPERAND0_HI) PATCH_VALUE(uint32_t, _operand0_lo, _JIT_OPERAND0_LO) - uint64_t _operand0 = ((uint64_t)_operand0_hi << 32) | _operand0_lo; + uint64_t _operand0_64 = ((uint64_t)_operand0_hi << 32) | _operand0_lo; PATCH_VALUE(uint32_t, _operand1_hi, _JIT_OPERAND1_HI) PATCH_VALUE(uint32_t, _operand1_lo, _JIT_OPERAND1_LO) - uint64_t _operand1 = ((uint64_t)_operand1_hi << 32) | _operand1_lo; + uint64_t _operand1_64 = ((uint64_t)_operand1_hi << 32) | _operand1_lo; +#endif +#if SUPPORTS_SMALL_CONSTS + PATCH_VALUE(uint32_t, _operand0_32, _JIT_OPERAND0_32) + PATCH_VALUE(uint32_t, _operand1_32, _JIT_OPERAND1_32) + PATCH_VALUE(uint16_t, _operand0_16, _JIT_OPERAND0_16) + PATCH_VALUE(uint16_t, _operand1_16, _JIT_OPERAND1_16) + PATCH_VALUE(uint16_t, _oparg_16, _JIT_OPARG_16) +#else + PATCH_VALUE(uint16_t, _oparg, _JIT_OPARG) #endif PATCH_VALUE(uint32_t, _target, _JIT_TARGET) OPT_STAT_INC(uops_executed); diff --git a/Tools/jit/trampoline.c b/Tools/jit/trampoline.c index 79d6af97961..698e491aeb3 100644 --- a/Tools/jit/trampoline.c +++ b/Tools/jit/trampoline.c @@ -10,7 +10,7 @@ _Py_CODEUNIT * _JIT_ENTRY( _PyExecutorObject *exec, _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate ) { - typedef DECLARE_TARGET((*jit_func)); - jit_func jitted = (jit_func)exec->jit_code; - return jitted(frame, stack_pointer, tstate); + // Note that this is *not* a tail call + jit_func_preserve_none jitted = (jit_func_preserve_none)exec->jit_code; + return jitted(frame, stack_pointer, tstate, PyStackRef_ZERO_BITS, PyStackRef_ZERO_BITS, PyStackRef_ZERO_BITS); } diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs index abfeb887848..3fcb00553f5 100644 --- a/Tools/msi/bundle/bundle.wxs +++ b/Tools/msi/bundle/bundle.wxs @@ -106,11 +106,11 @@ <Variable Name="SimpleInstallDescription" Value="" bal:Overridable="yes" /> <Chain ParallelCache="yes"> + <PackageGroupRef Id="core" /> + <PackageGroupRef Id="exe" /> <?if $(var.Platform)!="ARM64" ?> <PackageGroupRef Id="crt" /> <?endif ?> - <PackageGroupRef Id="core" /> - <PackageGroupRef Id="exe" /> <PackageGroupRef Id="dev" /> <PackageGroupRef Id="lib" /> <?if $(var.IncludeFreethreaded)~="true" ?> diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index afd010a5254..1a5797f7422 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -176,12 +176,6 @@ def docs_modified(file_paths): return bool(file_paths) -@status("Misc/ACKS updated", modal=True) -def credit_given(file_paths): - """Check if Misc/ACKS has been changed.""" - return os.path.join('Misc', 'ACKS') in file_paths - - @status("Misc/NEWS.d updated with `blurb`", modal=True) def reported_news(file_paths): """Check if Misc/NEWS.d has been changed.""" @@ -215,8 +209,6 @@ def main(): misc_files = {p for p in file_paths if p.startswith('Misc')} # Docs updated. docs_modified(has_doc_files) - # Misc/ACKS changed. - credit_given(misc_files) # Misc/NEWS changed. reported_news(misc_files) # Regenerated configure, if necessary. diff --git a/Tools/peg_generator/.ruff.toml b/Tools/peg_generator/.ruff.toml new file mode 100644 index 00000000000..bcf57248713 --- /dev/null +++ b/Tools/peg_generator/.ruff.toml @@ -0,0 +1,22 @@ +extend = "../../.ruff.toml" # Inherit the project-wide settings + +extend-exclude = [ + # Generated files: + "Tools/peg_generator/pegen/grammar_parser.py", +] + +[lint] +select = [ + "F", # pyflakes + "I", # isort + "UP", # pyupgrade + "RUF100", # Ban unused `# noqa` comments + "PGH004", # Ban blanket `# noqa` comments (only ignore specific error codes) +] +unfixable = [ + # The autofixes sometimes do the wrong things for these; + # it's better to have to manually look at the code and see how it needs fixing + "F841", # Detects unused variables + "F601", # Detects dictionaries that have duplicate keys + "F602", # Also detects dictionaries that have duplicate keys +] diff --git a/Tools/peg_generator/peg_extension/peg_extension.c b/Tools/peg_generator/peg_extension/peg_extension.c index 1587d53d594..2fec5b05129 100644 --- a/Tools/peg_generator/peg_extension/peg_extension.c +++ b/Tools/peg_generator/peg_extension/peg_extension.c @@ -8,7 +8,7 @@ _build_return_object(mod_ty module, int mode, PyObject *filename_ob, PyArena *ar PyObject *result = NULL; if (mode == 2) { - result = (PyObject *)_PyAST_Compile(module, filename_ob, NULL, -1, arena); + result = (PyObject *)_PyAST_Compile(module, filename_ob, NULL, -1, arena, NULL); } else if (mode == 1) { result = PyAST_mod2obj(module); } else { @@ -93,7 +93,7 @@ parse_string(PyObject *self, PyObject *args, PyObject *kwds) PyCompilerFlags flags = _PyCompilerFlags_INIT; mod_ty res = _PyPegen_run_parser_from_string(the_string, Py_file_input, filename_ob, - &flags, arena); + &flags, arena, NULL); if (res == NULL) { goto error; } diff --git a/Tools/peg_generator/pegen/__main__.py b/Tools/peg_generator/pegen/__main__.py index 0b0b4b291c2..7a82ad861b4 100755 --- a/Tools/peg_generator/pegen/__main__.py +++ b/Tools/peg_generator/pegen/__main__.py @@ -10,7 +10,6 @@ import sys import time import token import traceback -from typing import Tuple from pegen.grammar import Grammar from pegen.parser import Parser @@ -21,7 +20,7 @@ from pegen.validator import validate_grammar def generate_c_code( args: argparse.Namespace, -) -> Tuple[Grammar, Parser, Tokenizer, ParserGenerator]: +) -> tuple[Grammar, Parser, Tokenizer, ParserGenerator]: from pegen.build import build_c_parser_and_generator verbose = args.verbose @@ -50,7 +49,7 @@ def generate_c_code( def generate_python_code( args: argparse.Namespace, -) -> Tuple[Grammar, Parser, Tokenizer, ParserGenerator]: +) -> tuple[Grammar, Parser, Tokenizer, ParserGenerator]: from pegen.build import build_python_parser_and_generator verbose = args.verbose @@ -188,7 +187,7 @@ def main() -> None: if __name__ == "__main__": - if sys.version_info < (3, 8): - print("ERROR: using pegen requires at least Python 3.8!", file=sys.stderr) + if sys.version_info < (3, 10): # noqa: UP036 + print("ERROR: using pegen requires at least Python 3.10!", file=sys.stderr) sys.exit(1) main() diff --git a/Tools/peg_generator/pegen/ast_dump.py b/Tools/peg_generator/pegen/ast_dump.py index 07f8799c114..60dc1b04672 100644 --- a/Tools/peg_generator/pegen/ast_dump.py +++ b/Tools/peg_generator/pegen/ast_dump.py @@ -6,7 +6,7 @@ always fail. We rely on string comparison of the base classes instead. TODO: Remove the above-described hack. """ -from typing import Any, Optional, Tuple +from typing import Any def ast_dump( @@ -14,9 +14,9 @@ def ast_dump( annotate_fields: bool = True, include_attributes: bool = False, *, - indent: Optional[str] = None, + indent: str | None = None, ) -> str: - def _format(node: Any, level: int = 0) -> Tuple[str, bool]: + def _format(node: Any, level: int = 0) -> tuple[str, bool]: if indent is not None: level += 1 prefix = "\n" + indent * level @@ -41,7 +41,7 @@ def ast_dump( value, simple = _format(value, level) allsimple = allsimple and simple if keywords: - args.append("%s=%s" % (name, value)) + args.append(f"{name}={value}") else: args.append(value) if include_attributes and node._attributes: @@ -54,16 +54,16 @@ def ast_dump( continue value, simple = _format(value, level) allsimple = allsimple and simple - args.append("%s=%s" % (name, value)) + args.append(f"{name}={value}") if allsimple and len(args) <= 3: - return "%s(%s)" % (node.__class__.__name__, ", ".join(args)), not args - return "%s(%s%s)" % (node.__class__.__name__, prefix, sep.join(args)), False + return "{}({})".format(node.__class__.__name__, ", ".join(args)), not args + return f"{node.__class__.__name__}({prefix}{sep.join(args)})", False elif isinstance(node, list): if not node: return "[]", True - return "[%s%s]" % (prefix, sep.join(_format(x, level)[0] for x in node)), False + return f"[{prefix}{sep.join(_format(x, level)[0] for x in node)}]", False return repr(node), True if all(cls.__name__ != "AST" for cls in node.__class__.__mro__): - raise TypeError("expected AST, got %r" % node.__class__.__name__) + raise TypeError(f"expected AST, got {node.__class__.__name__!r}") return _format(node)[0] diff --git a/Tools/peg_generator/pegen/build.py b/Tools/peg_generator/pegen/build.py index be289c352de..44a58581686 100644 --- a/Tools/peg_generator/pegen/build.py +++ b/Tools/peg_generator/pegen/build.py @@ -6,7 +6,7 @@ import sys import sysconfig import tempfile import tokenize -from typing import IO, Any, Dict, List, Optional, Set, Tuple +from typing import IO, Any from pegen.c_generator import CParserGenerator from pegen.grammar import Grammar @@ -18,11 +18,11 @@ from pegen.tokenizer import Tokenizer MOD_DIR = pathlib.Path(__file__).resolve().parent -TokenDefinitions = Tuple[Dict[int, str], Dict[str, int], Set[str]] +TokenDefinitions = tuple[dict[int, str], dict[str, int], set[str]] Incomplete = Any # TODO: install `types-setuptools` and remove this alias -def get_extra_flags(compiler_flags: str, compiler_py_flags_nodist: str) -> List[str]: +def get_extra_flags(compiler_flags: str, compiler_py_flags_nodist: str) -> list[str]: flags = sysconfig.get_config_var(compiler_flags) py_flags_nodist = sysconfig.get_config_var(compiler_py_flags_nodist) if flags is None or py_flags_nodist is None: @@ -71,11 +71,11 @@ def fixup_build_ext(cmd: Incomplete) -> None: def compile_c_extension( generated_source_path: str, - build_dir: Optional[str] = None, + build_dir: str | None = None, verbose: bool = False, keep_asserts: bool = True, disable_optimization: bool = False, - library_dir: Optional[str] = None, + library_dir: str | None = None, ) -> pathlib.Path: """Compile the generated source for a parser generator into an extension module. @@ -93,11 +93,10 @@ def compile_c_extension( """ import setuptools.command.build_ext import setuptools.logging - - from setuptools import Extension, Distribution - from setuptools.modified import newer_group + from setuptools import Distribution, Extension from setuptools._distutils.ccompiler import new_compiler from setuptools._distutils.sysconfig import customize_compiler + from setuptools.modified import newer_group if verbose: setuptools.logging.set_threshold(logging.DEBUG) @@ -241,7 +240,7 @@ def compile_c_extension( def build_parser( grammar_file: str, verbose_tokenizer: bool = False, verbose_parser: bool = False -) -> Tuple[Grammar, Parser, Tokenizer]: +) -> tuple[Grammar, Parser, Tokenizer]: with open(grammar_file) as file: tokenizer = Tokenizer(tokenize.generate_tokens(file.readline), verbose=verbose_tokenizer) parser = GrammarParser(tokenizer, verbose=verbose_parser) @@ -292,7 +291,7 @@ def build_c_generator( keep_asserts_in_extension: bool = True, skip_actions: bool = False, ) -> ParserGenerator: - with open(tokens_file, "r") as tok_file: + with open(tokens_file) as tok_file: all_tokens, exact_tok, non_exact_tok = generate_token_definitions(tok_file) with open(output_file, "w") as file: gen: ParserGenerator = CParserGenerator( @@ -333,7 +332,7 @@ def build_c_parser_and_generator( verbose_c_extension: bool = False, keep_asserts_in_extension: bool = True, skip_actions: bool = False, -) -> Tuple[Grammar, Parser, Tokenizer, ParserGenerator]: +) -> tuple[Grammar, Parser, Tokenizer, ParserGenerator]: """Generate rules, C parser, tokenizer, parser generator for a given grammar Args: @@ -373,7 +372,7 @@ def build_python_parser_and_generator( verbose_tokenizer: bool = False, verbose_parser: bool = False, skip_actions: bool = False, -) -> Tuple[Grammar, Parser, Tokenizer, ParserGenerator]: +) -> tuple[Grammar, Parser, Tokenizer, ParserGenerator]: """Generate rules, python parser, tokenizer, parser generator for a given grammar Args: diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index 04f66eec1a0..a4e111972bd 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -1,9 +1,10 @@ import ast import os.path import re +from collections.abc import Callable from dataclasses import dataclass, field from enum import Enum -from typing import IO, Any, Callable, Dict, List, Optional, Set, Text, Tuple +from typing import IO, Any from pegen import grammar from pegen.grammar import ( @@ -30,6 +31,7 @@ from pegen.parser_generator import ParserGenerator EXTENSION_PREFIX = """\ #include "pegen.h" +#include "pycore_ceval.h" #if defined(Py_DEBUG) && defined(Py_BUILD_CORE) # define D(x) if (p->debug) { x; } @@ -86,13 +88,13 @@ BASE_NODETYPES = { @dataclass class FunctionCall: function: str - arguments: List[Any] = field(default_factory=list) - assigned_variable: Optional[str] = None - assigned_variable_type: Optional[str] = None - return_type: Optional[str] = None - nodetype: Optional[NodeTypes] = None + arguments: list[Any] = field(default_factory=list) + assigned_variable: str | None = None + assigned_variable_type: str | None = None + return_type: str | None = None + nodetype: NodeTypes | None = None force_true: bool = False - comment: Optional[str] = None + comment: str | None = None def __str__(self) -> str: parts = [] @@ -124,14 +126,14 @@ class CCallMakerVisitor(GrammarVisitor): def __init__( self, parser_generator: ParserGenerator, - exact_tokens: Dict[str, int], - non_exact_tokens: Set[str], + exact_tokens: dict[str, int], + non_exact_tokens: set[str], ): self.gen = parser_generator self.exact_tokens = exact_tokens self.non_exact_tokens = non_exact_tokens - self.cache: Dict[str, str] = {} - self.cleanup_statements: List[str] = [] + self.cache: dict[str, str] = {} + self.cleanup_statements: list[str] = [] def keyword_helper(self, keyword: str) -> FunctionCall: return FunctionCall( @@ -167,7 +169,7 @@ class CCallMakerVisitor(GrammarVisitor): ) return FunctionCall( assigned_variable=f"{name.lower()}_var", - function=f"_PyPegen_expect_token", + function="_PyPegen_expect_token", arguments=["p", name], nodetype=NodeTypes.GENERIC_TOKEN, return_type="Token *", @@ -199,7 +201,7 @@ class CCallMakerVisitor(GrammarVisitor): type = self.exact_tokens[val] return FunctionCall( assigned_variable="_literal", - function=f"_PyPegen_expect_token", + function="_PyPegen_expect_token", arguments=["p", type], nodetype=NodeTypes.GENERIC_TOKEN, return_type="Token *", @@ -271,7 +273,7 @@ class CCallMakerVisitor(GrammarVisitor): type = self.exact_tokens[val] return FunctionCall( assigned_variable="_literal", - function=f"_PyPegen_expect_forced_token", + function="_PyPegen_expect_forced_token", arguments=["p", type, f'"{val}"'], nodetype=NodeTypes.GENERIC_TOKEN, return_type="Token *", @@ -283,7 +285,7 @@ class CCallMakerVisitor(GrammarVisitor): call.comment = None return FunctionCall( assigned_variable="_literal", - function=f"_PyPegen_expect_forced_result", + function="_PyPegen_expect_forced_result", arguments=["p", str(call), f'"{node.node.rhs!s}"'], return_type="void *", comment=f"forced_token=({node.node.rhs!s})", @@ -306,7 +308,7 @@ class CCallMakerVisitor(GrammarVisitor): node: Any, prefix: str, rule_generation_func: Callable[[], str], - return_type: Optional[str] = None, + return_type: str | None = None, ) -> FunctionCall: node_str = f"{node}" key = f"{prefix}_{node_str}" @@ -377,10 +379,10 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): def __init__( self, grammar: grammar.Grammar, - tokens: Dict[int, str], - exact_tokens: Dict[str, int], - non_exact_tokens: Set[str], - file: Optional[IO[Text]], + tokens: dict[int, str], + exact_tokens: dict[str, int], + non_exact_tokens: set[str], + file: IO[str] | None, debug: bool = False, skip_actions: bool = False, ): @@ -391,7 +393,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self._varname_counter = 0 self.debug = debug self.skip_actions = skip_actions - self.cleanup_statements: List[str] = [] + self.cleanup_statements: list[str] = [] def add_level(self) -> None: self.print("if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) {") @@ -427,12 +429,12 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print(f"if ({error_var}) {{") with self.indent(): self.print(f"goto {goto_target};") - self.print(f"}}") + self.print("}") def out_of_memory_return( self, expr: str, - cleanup_code: Optional[str] = None, + cleanup_code: str | None = None, ) -> None: self.print(f"if ({expr}) {{") with self.indent(): @@ -441,14 +443,14 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print("p->error_indicator = 1;") self.print("PyErr_NoMemory();") self.add_return("NULL") - self.print(f"}}") + self.print("}") def out_of_memory_goto(self, expr: str, goto_target: str) -> None: self.print(f"if ({expr}) {{") with self.indent(): self.print("PyErr_NoMemory();") self.print(f"goto {goto_target};") - self.print(f"}}") + self.print("}") def generate(self, filename: str) -> None: self.collect_rules() @@ -491,8 +493,8 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): if trailer: self.print(trailer.rstrip("\n") % dict(mode=mode, modulename=modulename)) - def _group_keywords_by_length(self) -> Dict[int, List[Tuple[str, int]]]: - groups: Dict[int, List[Tuple[str, int]]] = {} + def _group_keywords_by_length(self) -> dict[int, list[tuple[str, int]]]: + groups: dict[int, list[tuple[str, int]]] = {} for keyword_str, keyword_type in self.keywords.items(): length = len(keyword_str) if length in groups: @@ -584,17 +586,17 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print("if (_raw == NULL || p->mark <= _resmark)") with self.indent(): self.print("break;") - self.print(f"_resmark = p->mark;") + self.print("_resmark = p->mark;") self.print("_res = _raw;") self.print("}") - self.print(f"p->mark = _resmark;") + self.print("p->mark = _resmark;") self.add_return("_res") self.print("}") self.print(f"static {result_type}") self.print(f"{node.name}_raw(Parser *p)") def _should_memoize(self, node: Rule) -> bool: - return node.memo and not node.left_recursive + return "memo" in node.flags and not node.left_recursive def _handle_default_rule_body(self, node: Rule, rhs: Rhs, result_type: str) -> None: memoize = self._should_memoize(node) @@ -643,7 +645,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): if memoize: self.print("int _start_mark = p->mark;") self.print("void **_children = PyMem_Malloc(sizeof(void *));") - self.out_of_memory_return(f"!_children") + self.out_of_memory_return("!_children") self.print("Py_ssize_t _children_capacity = 1;") self.print("Py_ssize_t _n = 0;") if any(alt.action and "EXTRA" in alt.action for alt in rhs.alts): @@ -661,7 +663,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.add_return("NULL") self.print("}") self.print("asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);") - self.out_of_memory_return(f"!_seq", cleanup_code="PyMem_Free(_children);") + self.out_of_memory_return("!_seq", cleanup_code="PyMem_Free(_children);") self.print("for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);") self.print("PyMem_Free(_children);") if memoize and node.name: @@ -715,7 +717,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print(call) def visit_Rhs( - self, node: Rhs, is_loop: bool, is_gather: bool, rulename: Optional[str] + self, node: Rhs, is_loop: bool, is_gather: bool, rulename: str | None ) -> None: if is_loop: assert len(node.alts) == 1 @@ -734,7 +736,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.visit(item) self.print(")") - def emit_action(self, node: Alt, cleanup_code: Optional[str] = None) -> None: + def emit_action(self, node: Alt, cleanup_code: str | None = None) -> None: self.print(f"_res = {node.action};") self.print("if (_res == NULL && PyErr_Occurred()) {") @@ -776,7 +778,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): def emit_dummy_action(self) -> None: self.print("_res = _PyPegen_dummy_name(p);") - def handle_alt_normal(self, node: Alt, is_gather: bool, rulename: Optional[str]) -> None: + def handle_alt_normal(self, node: Alt, is_gather: bool, rulename: str | None) -> None: self.join_conditions(keyword="if", node=node) self.print("{") # We have parsed successfully all the conditions for the option. @@ -796,10 +798,10 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.emit_default_action(is_gather, node) # As the current option has parsed correctly, do not continue with the rest. - self.print(f"goto done;") + self.print("goto done;") self.print("}") - def handle_alt_loop(self, node: Alt, is_gather: bool, rulename: Optional[str]) -> None: + def handle_alt_loop(self, node: Alt, is_gather: bool, rulename: str | None) -> None: # Condition of the main body of the alternative self.join_conditions(keyword="while", node=node) self.print("{") @@ -823,7 +825,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print( "void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));" ) - self.out_of_memory_return(f"!_new_children", cleanup_code="PyMem_Free(_children);") + self.out_of_memory_return("!_new_children", cleanup_code="PyMem_Free(_children);") self.print("_children = _new_children;") self.print("}") self.print("_children[_n++] = _res;") @@ -831,7 +833,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print("}") def visit_Alt( - self, node: Alt, is_loop: bool, is_gather: bool, rulename: Optional[str] + self, node: Alt, is_loop: bool, is_gather: bool, rulename: str | None ) -> None: if len(node.items) == 1 and str(node.items[0]).startswith("invalid_"): self.print(f"if (p->call_invalid_rules) {{ // {node}") @@ -875,7 +877,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): self.print("}") self.print("}") - def collect_vars(self, node: Alt) -> Dict[Optional[str], Optional[str]]: + def collect_vars(self, node: Alt) -> dict[str | None, str | None]: types = {} with self.local_variable_context(): for item in node.items: @@ -883,7 +885,7 @@ class CParserGenerator(ParserGenerator, GrammarVisitor): types[name] = type return types - def add_var(self, node: NamedItem) -> Tuple[Optional[str], Optional[str]]: + def add_var(self, node: NamedItem) -> tuple[str | None, str | None]: call = self.callmakervisitor.generate_call(node.item) name = node.name if node.name else call.assigned_variable if name is not None: diff --git a/Tools/peg_generator/pegen/first_sets.py b/Tools/peg_generator/pegen/first_sets.py index 6d794ffa4bf..f6b83c0ca31 100755 --- a/Tools/peg_generator/pegen/first_sets.py +++ b/Tools/peg_generator/pegen/first_sets.py @@ -3,7 +3,6 @@ import argparse import pprint import sys -from typing import Dict, Set from pegen.build import build_parser from pegen.grammar import ( @@ -33,20 +32,20 @@ argparser.add_argument("grammar_file", help="The grammar file") class FirstSetCalculator(GrammarVisitor): - def __init__(self, rules: Dict[str, Rule]) -> None: + def __init__(self, rules: dict[str, Rule]) -> None: self.rules = rules self.nullables = compute_nullables(rules) - self.first_sets: Dict[str, Set[str]] = dict() - self.in_process: Set[str] = set() + self.first_sets: dict[str, set[str]] = dict() + self.in_process: set[str] = set() - def calculate(self) -> Dict[str, Set[str]]: + def calculate(self) -> dict[str, set[str]]: for name, rule in self.rules.items(): self.visit(rule) return self.first_sets - def visit_Alt(self, item: Alt) -> Set[str]: - result: Set[str] = set() - to_remove: Set[str] = set() + def visit_Alt(self, item: Alt) -> set[str]: + result: set[str] = set() + to_remove: set[str] = set() for other in item.items: new_terminals = self.visit(other) if isinstance(other.item, NegativeLookahead): @@ -71,34 +70,34 @@ class FirstSetCalculator(GrammarVisitor): return result - def visit_Cut(self, item: Cut) -> Set[str]: + def visit_Cut(self, item: Cut) -> set[str]: return set() - def visit_Group(self, item: Group) -> Set[str]: + def visit_Group(self, item: Group) -> set[str]: return self.visit(item.rhs) - def visit_PositiveLookahead(self, item: Lookahead) -> Set[str]: + def visit_PositiveLookahead(self, item: Lookahead) -> set[str]: return self.visit(item.node) - def visit_NegativeLookahead(self, item: NegativeLookahead) -> Set[str]: + def visit_NegativeLookahead(self, item: NegativeLookahead) -> set[str]: return self.visit(item.node) - def visit_NamedItem(self, item: NamedItem) -> Set[str]: + def visit_NamedItem(self, item: NamedItem) -> set[str]: return self.visit(item.item) - def visit_Opt(self, item: Opt) -> Set[str]: + def visit_Opt(self, item: Opt) -> set[str]: return self.visit(item.node) - def visit_Gather(self, item: Gather) -> Set[str]: + def visit_Gather(self, item: Gather) -> set[str]: return self.visit(item.node) - def visit_Repeat0(self, item: Repeat0) -> Set[str]: + def visit_Repeat0(self, item: Repeat0) -> set[str]: return self.visit(item.node) - def visit_Repeat1(self, item: Repeat1) -> Set[str]: + def visit_Repeat1(self, item: Repeat1) -> set[str]: return self.visit(item.node) - def visit_NameLeaf(self, item: NameLeaf) -> Set[str]: + def visit_NameLeaf(self, item: NameLeaf) -> set[str]: if item.value not in self.rules: return {item.value} @@ -110,16 +109,16 @@ class FirstSetCalculator(GrammarVisitor): return self.first_sets[item.value] - def visit_StringLeaf(self, item: StringLeaf) -> Set[str]: + def visit_StringLeaf(self, item: StringLeaf) -> set[str]: return {item.value} - def visit_Rhs(self, item: Rhs) -> Set[str]: - result: Set[str] = set() + def visit_Rhs(self, item: Rhs) -> set[str]: + result: set[str] = set() for alt in item.alts: result |= self.visit(alt) return result - def visit_Rule(self, item: Rule) -> Set[str]: + def visit_Rule(self, item: Rule) -> set[str]: if item.name in self.in_process: return set() elif item.name not in self.first_sets: @@ -138,7 +137,7 @@ def main() -> None: try: grammar, parser, tokenizer = build_parser(args.grammar_file) except Exception as err: - print("ERROR: Failed to parse grammar file", file=sys.stderr) + print("ERROR: Failed to parse grammar file", err, file=sys.stderr) sys.exit(1) firs_sets = FirstSetCalculator(grammar.rules).calculate() diff --git a/Tools/peg_generator/pegen/grammar.py b/Tools/peg_generator/pegen/grammar.py index 1ee9d100b61..d3c2eca6615 100644 --- a/Tools/peg_generator/pegen/grammar.py +++ b/Tools/peg_generator/pegen/grammar.py @@ -1,15 +1,7 @@ from __future__ import annotations -from typing import ( - AbstractSet, - Any, - Iterable, - Iterator, - List, - Optional, - Tuple, - Union, -) +from collections.abc import Iterable, Iterator, Set +from typing import Any class GrammarError(Exception): @@ -34,7 +26,7 @@ class GrammarVisitor: class Grammar: - def __init__(self, rules: Iterable[Rule], metas: Iterable[Tuple[str, Optional[str]]]): + def __init__(self, rules: Iterable[Rule], metas: Iterable[tuple[str, str | None]]): # Check if there are repeated rules in "rules" all_rules = {} for rule in rules: @@ -66,11 +58,11 @@ SIMPLE_STR = True class Rule: - def __init__(self, name: str, type: Optional[str], rhs: Rhs, memo: Optional[object] = None): + def __init__(self, name: str, type: str | None, rhs: Rhs, flags: frozenset[str] | None = None): self.name = name self.type = type self.rhs = rhs - self.memo = bool(memo) + self.flags = flags or frozenset() self.left_recursive = False self.leader = False @@ -141,9 +133,8 @@ class StringLeaf(Leaf): class Rhs: - def __init__(self, alts: List[Alt]): + def __init__(self, alts: list[Alt]): self.alts = alts - self.memo: Optional[Tuple[Optional[str], str]] = None def __str__(self) -> str: return " | ".join(str(alt) for alt in self.alts) @@ -151,7 +142,7 @@ class Rhs: def __repr__(self) -> str: return f"Rhs({self.alts!r})" - def __iter__(self) -> Iterator[List[Alt]]: + def __iter__(self) -> Iterator[list[Alt]]: yield self.alts @property @@ -165,7 +156,7 @@ class Rhs: class Alt: - def __init__(self, items: List[NamedItem], *, icut: int = -1, action: Optional[str] = None): + def __init__(self, items: list[NamedItem], *, icut: int = -1, action: str | None = None): self.items = items self.icut = icut self.action = action @@ -185,12 +176,12 @@ class Alt: args.append(f"action={self.action!r}") return f"Alt({', '.join(args)})" - def __iter__(self) -> Iterator[List[NamedItem]]: + def __iter__(self) -> Iterator[list[NamedItem]]: yield self.items class NamedItem: - def __init__(self, name: Optional[str], item: Item, type: Optional[str] = None): + def __init__(self, name: str | None, item: Item, type: str | None = None): self.name = name self.item = item self.type = type @@ -271,7 +262,6 @@ class Repeat: def __init__(self, node: Plain): self.node = node - self.memo: Optional[Tuple[Optional[str], str]] = None def __iter__(self) -> Iterator[Plain]: yield self.node @@ -334,12 +324,12 @@ class Cut: pass def __repr__(self) -> str: - return f"Cut()" + return "Cut()" def __str__(self) -> str: - return f"~" + return "~" - def __iter__(self) -> Iterator[Tuple[str, str]]: + def __iter__(self) -> Iterator[tuple[str, str]]: yield from () def __eq__(self, other: object) -> bool: @@ -347,15 +337,15 @@ class Cut: return NotImplemented return True - def initial_names(self) -> AbstractSet[str]: + def initial_names(self) -> Set[str]: return set() -Plain = Union[Leaf, Group] -Item = Union[Plain, Opt, Repeat, Forced, Lookahead, Rhs, Cut] -RuleName = Tuple[str, Optional[str]] -MetaTuple = Tuple[str, Optional[str]] -MetaList = List[MetaTuple] -RuleList = List[Rule] -NamedItemList = List[NamedItem] -LookaheadOrCut = Union[Lookahead, Cut] +Plain = Leaf | Group +Item = Plain | Opt | Repeat | Forced | Lookahead | Rhs | Cut +RuleName = tuple[str, str | None] +MetaTuple = tuple[str, str | None] +MetaList = list[MetaTuple] +RuleList = list[Rule] +NamedItemList = list[NamedItem] +LookaheadOrCut = Lookahead | Cut diff --git a/Tools/peg_generator/pegen/grammar_parser.py b/Tools/peg_generator/pegen/grammar_parser.py index 2e3a607f720..4fa27392707 100644 --- a/Tools/peg_generator/pegen/grammar_parser.py +++ b/Tools/peg_generator/pegen/grammar_parser.py @@ -147,12 +147,12 @@ class GeneratedParser(Parser): @memoize def rule(self) -> Optional[Rule]: - # rule: rulename memoflag? ":" alts NEWLINE INDENT more_alts DEDENT | rulename memoflag? ":" NEWLINE INDENT more_alts DEDENT | rulename memoflag? ":" alts NEWLINE + # rule: rulename flags? ":" alts NEWLINE INDENT more_alts DEDENT | rulename flags? ":" NEWLINE INDENT more_alts DEDENT | rulename flags? ":" alts NEWLINE mark = self._mark() if ( (rulename := self.rulename()) and - (opt := self.memoflag(),) + (flags := self.flags(),) and (literal := self.expect(":")) and @@ -166,12 +166,12 @@ class GeneratedParser(Parser): and (_dedent := self.expect('DEDENT')) ): - return Rule ( rulename [0] , rulename [1] , Rhs ( alts . alts + more_alts . alts ) , memo = opt ) + return Rule ( rulename [0] , rulename [1] , Rhs ( alts . alts + more_alts . alts ) , flags = flags ) self._reset(mark) if ( (rulename := self.rulename()) and - (opt := self.memoflag(),) + (flags := self.flags(),) and (literal := self.expect(":")) and @@ -183,12 +183,12 @@ class GeneratedParser(Parser): and (_dedent := self.expect('DEDENT')) ): - return Rule ( rulename [0] , rulename [1] , more_alts , memo = opt ) + return Rule ( rulename [0] , rulename [1] , more_alts , flags = flags ) self._reset(mark) if ( (rulename := self.rulename()) and - (opt := self.memoflag(),) + (flags := self.flags(),) and (literal := self.expect(":")) and @@ -196,7 +196,7 @@ class GeneratedParser(Parser): and (_newline := self.expect('NEWLINE')) ): - return Rule ( rulename [0] , rulename [1] , alts , memo = opt ) + return Rule ( rulename [0] , rulename [1] , alts , flags = flags ) self._reset(mark) return None @@ -219,17 +219,28 @@ class GeneratedParser(Parser): return None @memoize - def memoflag(self) -> Optional[str]: - # memoflag: '(' "memo" ')' + def flags(self) -> Optional[frozenset [str]]: + # flags: '(' ','.flag+ ')' mark = self._mark() if ( (literal := self.expect('(')) and - (literal_1 := self.expect("memo")) + (a := self._gather_2()) and - (literal_2 := self.expect(')')) + (literal_1 := self.expect(')')) ): - return "memo" + return frozenset ( a ) + self._reset(mark) + return None + + @memoize + def flag(self) -> Optional[str]: + # flag: NAME + mark = self._mark() + if ( + (name := self.name()) + ): + return name . string self._reset(mark) return None @@ -661,8 +672,38 @@ class GeneratedParser(Parser): self._reset(mark) return None + @memoize + def _loop0_1(self) -> Optional[Any]: + # _loop0_1: ',' flag + mark = self._mark() + children = [] + while ( + (literal := self.expect(',')) + and + (elem := self.flag()) + ): + children.append(elem) + mark = self._mark() + self._reset(mark) + return children + + @memoize + def _gather_2(self) -> Optional[Any]: + # _gather_2: flag _loop0_1 + mark = self._mark() + if ( + (elem := self.flag()) + is not None + and + (seq := self._loop0_1()) + is not None + ): + return [elem] + seq + self._reset(mark) + return None + KEYWORDS = () - SOFT_KEYWORDS = ('memo',) + SOFT_KEYWORDS = () if __name__ == '__main__': diff --git a/Tools/peg_generator/pegen/grammar_visualizer.py b/Tools/peg_generator/pegen/grammar_visualizer.py index 11f784f45b6..eadb6987389 100644 --- a/Tools/peg_generator/pegen/grammar_visualizer.py +++ b/Tools/peg_generator/pegen/grammar_visualizer.py @@ -1,6 +1,7 @@ import argparse import sys -from typing import Any, Callable, Iterator +from collections.abc import Callable, Iterator +from typing import Any from pegen.build import build_parser from pegen.grammar import Grammar, Rule @@ -52,7 +53,7 @@ def main() -> None: try: grammar, parser, tokenizer = build_parser(args.filename) except Exception as err: - print("ERROR: Failed to parse grammar file", file=sys.stderr) + print("ERROR: Failed to parse grammar file", err, file=sys.stderr) sys.exit(1) visitor = ASTGrammarPrinter() diff --git a/Tools/peg_generator/pegen/metagrammar.gram b/Tools/peg_generator/pegen/metagrammar.gram index f484c478182..cae91ab9c41 100644 --- a/Tools/peg_generator/pegen/metagrammar.gram +++ b/Tools/peg_generator/pegen/metagrammar.gram @@ -50,19 +50,21 @@ rules[RuleList]: | rule { [rule] } rule[Rule]: - | rulename memoflag? ":" alts NEWLINE INDENT more_alts DEDENT { - Rule(rulename[0], rulename[1], Rhs(alts.alts + more_alts.alts), memo=opt) } - | rulename memoflag? ":" NEWLINE INDENT more_alts DEDENT { - Rule(rulename[0], rulename[1], more_alts, memo=opt) } - | rulename memoflag? ":" alts NEWLINE { Rule(rulename[0], rulename[1], alts, memo=opt) } + | rulename flags=flags? ":" alts NEWLINE INDENT more_alts DEDENT { + Rule(rulename[0], rulename[1], Rhs(alts.alts + more_alts.alts), flags=flags) } + | rulename flags=flags? ":" NEWLINE INDENT more_alts DEDENT { + Rule(rulename[0], rulename[1], more_alts, flags=flags) } + | rulename flags=flags? ":" alts NEWLINE { Rule(rulename[0], rulename[1], alts, flags=flags) } rulename[RuleName]: | NAME annotation { (name.string, annotation) } | NAME { (name.string, None) } -# In the future this may return something more complicated -memoflag[str]: - | '(' "memo" ')' { "memo" } +flags[frozenset[str]]: + | '(' a=','.flag+ ')' { frozenset(a) } + +flag[str]: + | NAME { name.string } alts[Rhs]: | alt "|" alts { Rhs([alt] + alts.alts)} diff --git a/Tools/peg_generator/pegen/parser.py b/Tools/peg_generator/pegen/parser.py index a987d30a9d6..806003c8350 100644 --- a/Tools/peg_generator/pegen/parser.py +++ b/Tools/peg_generator/pegen/parser.py @@ -5,7 +5,8 @@ import token import tokenize import traceback from abc import abstractmethod -from typing import Any, Callable, ClassVar, Dict, Optional, Tuple, Type, TypeVar, cast +from collections.abc import Callable +from typing import Any, ClassVar, TypeVar, cast from pegen.tokenizer import Mark, Tokenizer, exact_token_types @@ -74,12 +75,12 @@ def memoize(method: F) -> F: def memoize_left_rec( - method: Callable[["Parser"], Optional[T]] -) -> Callable[["Parser"], Optional[T]]: + method: Callable[["Parser"], T | None] +) -> Callable[["Parser"], T | None]: """Memoize a left-recursive symbol method.""" method_name = method.__name__ - def memoize_left_rec_wrapper(self: "Parser") -> Optional[T]: + def memoize_left_rec_wrapper(self: "Parser") -> T | None: mark = self._mark() key = mark, method_name, () # Fast path: cache hit, and not verbose. @@ -160,15 +161,15 @@ def memoize_left_rec( class Parser: """Parsing base class.""" - KEYWORDS: ClassVar[Tuple[str, ...]] + KEYWORDS: ClassVar[tuple[str, ...]] - SOFT_KEYWORDS: ClassVar[Tuple[str, ...]] + SOFT_KEYWORDS: ClassVar[tuple[str, ...]] def __init__(self, tokenizer: Tokenizer, *, verbose: bool = False): self._tokenizer = tokenizer self._verbose = verbose self._level = 0 - self._cache: Dict[Tuple[Mark, str, Tuple[Any, ...]], Tuple[Any, Mark]] = {} + self._cache: dict[tuple[Mark, str, tuple[Any, ...]], tuple[Any, Mark]] = {} # Integer tracking whether we are in a left recursive rule or not. Can be useful # for error reporting. self.in_recursive_rule = 0 @@ -185,28 +186,28 @@ class Parser: return f"{tok.start[0]}.{tok.start[1]}: {token.tok_name[tok.type]}:{tok.string!r}" @memoize - def name(self) -> Optional[tokenize.TokenInfo]: + def name(self) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.type == token.NAME and tok.string not in self.KEYWORDS: return self._tokenizer.getnext() return None @memoize - def number(self) -> Optional[tokenize.TokenInfo]: + def number(self) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.type == token.NUMBER: return self._tokenizer.getnext() return None @memoize - def string(self) -> Optional[tokenize.TokenInfo]: + def string(self) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.type == token.STRING: return self._tokenizer.getnext() return None @memoize - def fstring_start(self) -> Optional[tokenize.TokenInfo]: + def fstring_start(self) -> tokenize.TokenInfo | None: FSTRING_START = getattr(token, "FSTRING_START", None) if not FSTRING_START: return None @@ -216,7 +217,7 @@ class Parser: return None @memoize - def fstring_middle(self) -> Optional[tokenize.TokenInfo]: + def fstring_middle(self) -> tokenize.TokenInfo | None: FSTRING_MIDDLE = getattr(token, "FSTRING_MIDDLE", None) if not FSTRING_MIDDLE: return None @@ -226,7 +227,7 @@ class Parser: return None @memoize - def fstring_end(self) -> Optional[tokenize.TokenInfo]: + def fstring_end(self) -> tokenize.TokenInfo | None: FSTRING_END = getattr(token, "FSTRING_END", None) if not FSTRING_END: return None @@ -236,28 +237,28 @@ class Parser: return None @memoize - def op(self) -> Optional[tokenize.TokenInfo]: + def op(self) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.type == token.OP: return self._tokenizer.getnext() return None @memoize - def type_comment(self) -> Optional[tokenize.TokenInfo]: + def type_comment(self) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.type == token.TYPE_COMMENT: return self._tokenizer.getnext() return None @memoize - def soft_keyword(self) -> Optional[tokenize.TokenInfo]: + def soft_keyword(self) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.type == token.NAME and tok.string in self.SOFT_KEYWORDS: return self._tokenizer.getnext() return None @memoize - def expect(self, type: str) -> Optional[tokenize.TokenInfo]: + def expect(self, type: str) -> tokenize.TokenInfo | None: tok = self._tokenizer.peek() if tok.string == type: return self._tokenizer.getnext() @@ -271,7 +272,7 @@ class Parser: return self._tokenizer.getnext() return None - def expect_forced(self, res: Any, expectation: str) -> Optional[tokenize.TokenInfo]: + def expect_forced(self, res: Any, expectation: str) -> tokenize.TokenInfo | None: if res is None: raise self.make_syntax_error(f"expected {expectation}") return res @@ -293,7 +294,7 @@ class Parser: return SyntaxError(message, (filename, tok.start[0], 1 + tok.start[1], tok.line)) -def simple_parser_main(parser_class: Type[Parser]) -> None: +def simple_parser_main(parser_class: type[Parser]) -> None: argparser = argparse.ArgumentParser() argparser.add_argument( "-v", @@ -330,7 +331,7 @@ def simple_parser_main(parser_class: Type[Parser]) -> None: endpos = 0 else: endpos = file.tell() - except IOError: + except OSError: endpos = 0 finally: if file is not sys.stdin: diff --git a/Tools/peg_generator/pegen/parser_generator.py b/Tools/peg_generator/pegen/parser_generator.py index 7dd56f98a65..81314b0cc07 100644 --- a/Tools/peg_generator/pegen/parser_generator.py +++ b/Tools/peg_generator/pegen/parser_generator.py @@ -1,22 +1,10 @@ -import sys import ast import contextlib import re +import sys from abc import abstractmethod -from typing import ( - IO, - AbstractSet, - Any, - Dict, - Iterable, - Iterator, - List, - Optional, - Set, - Text, - Tuple, - Union, -) +from collections.abc import Iterable, Iterator, Set +from typing import IO, Any from pegen import sccutils from pegen.grammar import ( @@ -44,8 +32,7 @@ from pegen.grammar import ( class RuleCollectorVisitor(GrammarVisitor): """Visitor that invokes a provided callmaker visitor with just the NamedItem nodes""" - def __init__(self, rules: Dict[str, Rule], callmakervisitor: GrammarVisitor) -> None: - self.rulses = rules + def __init__(self, callmakervisitor: GrammarVisitor) -> None: self.callmaker = callmakervisitor def visit_Rule(self, rule: Rule) -> None: @@ -58,7 +45,7 @@ class RuleCollectorVisitor(GrammarVisitor): class KeywordCollectorVisitor(GrammarVisitor): """Visitor that collects all the keywords and soft keywords in the Grammar""" - def __init__(self, gen: "ParserGenerator", keywords: Dict[str, int], soft_keywords: Set[str]): + def __init__(self, gen: "ParserGenerator", keywords: dict[str, int], soft_keywords: set[str]): self.generator = gen self.keywords = keywords self.soft_keywords = soft_keywords @@ -73,7 +60,7 @@ class KeywordCollectorVisitor(GrammarVisitor): class RuleCheckingVisitor(GrammarVisitor): - def __init__(self, rules: Dict[str, Rule], tokens: Set[str]): + def __init__(self, rules: dict[str, Rule], tokens: set[str]): self.rules = rules self.tokens = tokens # If python < 3.12 add the virtual fstring tokens @@ -100,11 +87,11 @@ class RuleCheckingVisitor(GrammarVisitor): class ParserGenerator: callmakervisitor: GrammarVisitor - def __init__(self, grammar: Grammar, tokens: Set[str], file: Optional[IO[Text]]): + def __init__(self, grammar: Grammar, tokens: set[str], file: IO[str] | None): self.grammar = grammar self.tokens = tokens - self.keywords: Dict[str, int] = {} - self.soft_keywords: Set[str] = set() + self.keywords: dict[str, int] = {} + self.soft_keywords: set[str] = set() self.rules = grammar.rules self.validate_rule_names() if "trailer" not in grammar.metas and "start" not in self.rules: @@ -117,8 +104,8 @@ class ParserGenerator: self.first_graph, self.first_sccs = compute_left_recursives(self.rules) self.counter = 0 # For name_rule()/name_loop() self.keyword_counter = 499 # For keyword_type() - self.all_rules: Dict[str, Rule] = self.rules.copy() # Rules + temporal rules - self._local_variable_stack: List[List[str]] = [] + self.all_rules: dict[str, Rule] = self.rules.copy() # Rules + temporal rules + self._local_variable_stack: list[list[str]] = [] def validate_rule_names(self) -> None: for rule in self.rules: @@ -132,7 +119,7 @@ class ParserGenerator: self._local_variable_stack.pop() @property - def local_variable_names(self) -> List[str]: + def local_variable_names(self) -> list[str]: return self._local_variable_stack[-1] @abstractmethod @@ -163,8 +150,8 @@ class ParserGenerator: for rule in self.all_rules.values(): keyword_collector.visit(rule) - rule_collector = RuleCollectorVisitor(self.rules, self.callmakervisitor) - done: Set[str] = set() + rule_collector = RuleCollectorVisitor(self.callmakervisitor) + done: set[str] = set() while True: computed_rules = list(self.all_rules) todo = [i for i in computed_rules if i not in done] @@ -229,10 +216,10 @@ class ParserGenerator: class NullableVisitor(GrammarVisitor): - def __init__(self, rules: Dict[str, Rule]) -> None: + def __init__(self, rules: dict[str, Rule]) -> None: self.rules = rules - self.visited: Set[Any] = set() - self.nullables: Set[Union[Rule, NamedItem]] = set() + self.visited: set[Any] = set() + self.nullables: set[Rule | NamedItem] = set() def visit_Rule(self, rule: Rule) -> bool: if rule in self.visited: @@ -294,7 +281,7 @@ class NullableVisitor(GrammarVisitor): return not node.value -def compute_nullables(rules: Dict[str, Rule]) -> Set[Any]: +def compute_nullables(rules: dict[str, Rule]) -> set[Any]: """Compute which rules in a grammar are nullable. Thanks to TatSu (tatsu/leftrec.py) for inspiration. @@ -306,12 +293,12 @@ def compute_nullables(rules: Dict[str, Rule]) -> Set[Any]: class InitialNamesVisitor(GrammarVisitor): - def __init__(self, rules: Dict[str, Rule]) -> None: + def __init__(self, rules: dict[str, Rule]) -> None: self.rules = rules self.nullables = compute_nullables(rules) - def generic_visit(self, node: Iterable[Any], *args: Any, **kwargs: Any) -> Set[Any]: - names: Set[str] = set() + def generic_visit(self, node: Iterable[Any], *args: Any, **kwargs: Any) -> set[Any]: + names: set[str] = set() for value in node: if isinstance(value, list): for item in value: @@ -320,33 +307,33 @@ class InitialNamesVisitor(GrammarVisitor): names |= self.visit(value, *args, **kwargs) return names - def visit_Alt(self, alt: Alt) -> Set[Any]: - names: Set[str] = set() + def visit_Alt(self, alt: Alt) -> set[Any]: + names: set[str] = set() for item in alt.items: names |= self.visit(item) if item not in self.nullables: break return names - def visit_Forced(self, force: Forced) -> Set[Any]: + def visit_Forced(self, force: Forced) -> set[Any]: return set() - def visit_LookAhead(self, lookahead: Lookahead) -> Set[Any]: + def visit_LookAhead(self, lookahead: Lookahead) -> set[Any]: return set() - def visit_Cut(self, cut: Cut) -> Set[Any]: + def visit_Cut(self, cut: Cut) -> set[Any]: return set() - def visit_NameLeaf(self, node: NameLeaf) -> Set[Any]: + def visit_NameLeaf(self, node: NameLeaf) -> set[Any]: return {node.value} - def visit_StringLeaf(self, node: StringLeaf) -> Set[Any]: + def visit_StringLeaf(self, node: StringLeaf) -> set[Any]: return set() def compute_left_recursives( - rules: Dict[str, Rule] -) -> Tuple[Dict[str, AbstractSet[str]], List[AbstractSet[str]]]: + rules: dict[str, Rule] +) -> tuple[dict[str, Set[str]], list[Set[str]]]: graph = make_first_graph(rules) sccs = list(sccutils.strongly_connected_components(graph.keys(), graph)) for scc in sccs: @@ -374,7 +361,7 @@ def compute_left_recursives( return graph, sccs -def make_first_graph(rules: Dict[str, Rule]) -> Dict[str, AbstractSet[str]]: +def make_first_graph(rules: dict[str, Rule]) -> dict[str, Set[str]]: """Compute the graph of left-invocations. There's an edge from A to B if A may invoke B at its initial @@ -384,7 +371,7 @@ def make_first_graph(rules: Dict[str, Rule]) -> Dict[str, AbstractSet[str]]: """ initial_name_visitor = InitialNamesVisitor(rules) graph = {} - vertices: Set[str] = set() + vertices: set[str] = set() for rulename, rhs in rules.items(): graph[rulename] = names = initial_name_visitor.visit(rhs) vertices |= names diff --git a/Tools/peg_generator/pegen/python_generator.py b/Tools/peg_generator/pegen/python_generator.py index 4bb26480ebc..e69ea4b5f4e 100644 --- a/Tools/peg_generator/pegen/python_generator.py +++ b/Tools/peg_generator/pegen/python_generator.py @@ -1,6 +1,7 @@ import os.path import token -from typing import IO, Any, Callable, Dict, Optional, Sequence, Set, Text, Tuple +from collections.abc import Callable, Sequence +from typing import IO, Any from pegen import grammar from pegen.grammar import ( @@ -74,10 +75,10 @@ class InvalidNodeVisitor(GrammarVisitor): def visit_Opt(self, node: Opt) -> bool: return self.visit(node.node) - def visit_Repeat(self, node: Repeat0) -> Tuple[str, str]: + def visit_Repeat(self, node: Repeat0) -> tuple[str, str]: return self.visit(node.node) - def visit_Gather(self, node: Gather) -> Tuple[str, str]: + def visit_Gather(self, node: Gather) -> tuple[str, str]: return self.visit(node.node) def visit_Group(self, node: Group) -> bool: @@ -93,9 +94,9 @@ class InvalidNodeVisitor(GrammarVisitor): class PythonCallMakerVisitor(GrammarVisitor): def __init__(self, parser_generator: ParserGenerator): self.gen = parser_generator - self.cache: Dict[str, Tuple[str, str]] = {} + self.cache: dict[str, tuple[str, str]] = {} - def visit_NameLeaf(self, node: NameLeaf) -> Tuple[Optional[str], str]: + def visit_NameLeaf(self, node: NameLeaf) -> tuple[str | None, str]: name = node.value if name == "SOFT_KEYWORD": return "soft_keyword", "self.soft_keyword()" @@ -108,31 +109,31 @@ class PythonCallMakerVisitor(GrammarVisitor): return "_" + name.lower(), f"self.expect({name!r})" return name, f"self.{name}()" - def visit_StringLeaf(self, node: StringLeaf) -> Tuple[str, str]: + def visit_StringLeaf(self, node: StringLeaf) -> tuple[str, str]: return "literal", f"self.expect({node.value})" - def visit_NamedItem(self, node: NamedItem) -> Tuple[Optional[str], str]: + def visit_NamedItem(self, node: NamedItem) -> tuple[str | None, str]: name, call = self.visit(node.item) if node.name: name = node.name return name, call - def lookahead_call_helper(self, node: Lookahead) -> Tuple[str, str]: + def lookahead_call_helper(self, node: Lookahead) -> tuple[str, str]: name, call = self.visit(node.node) head, tail = call.split("(", 1) assert tail[-1] == ")" tail = tail[:-1] return head, tail - def visit_PositiveLookahead(self, node: PositiveLookahead) -> Tuple[None, str]: + def visit_PositiveLookahead(self, node: PositiveLookahead) -> tuple[None, str]: head, tail = self.lookahead_call_helper(node) return None, f"self.positive_lookahead({head}, {tail})" - def visit_NegativeLookahead(self, node: NegativeLookahead) -> Tuple[None, str]: + def visit_NegativeLookahead(self, node: NegativeLookahead) -> tuple[None, str]: head, tail = self.lookahead_call_helper(node) return None, f"self.negative_lookahead({head}, {tail})" - def visit_Opt(self, node: Opt) -> Tuple[str, str]: + def visit_Opt(self, node: Opt) -> tuple[str, str]: name, call = self.visit(node.node) # Note trailing comma (the call may already have one comma # at the end, for example when rules have both repeat0 and optional @@ -148,7 +149,7 @@ class PythonCallMakerVisitor(GrammarVisitor): prefix: str, call_by_name_func: Callable[[str], str], rule_generation_func: Callable[[], str], - ) -> Tuple[str, str]: + ) -> tuple[str, str]: node_str = f"{node}" key = f"{prefix}_{node_str}" if key in self.cache: @@ -159,7 +160,7 @@ class PythonCallMakerVisitor(GrammarVisitor): self.cache[key] = name, call return self.cache[key] - def visit_Rhs(self, node: Rhs) -> Tuple[str, str]: + def visit_Rhs(self, node: Rhs) -> tuple[str, str]: if len(node.alts) == 1 and len(node.alts[0].items) == 1: return self.visit(node.alts[0].items[0]) @@ -170,7 +171,7 @@ class PythonCallMakerVisitor(GrammarVisitor): lambda: self.gen.artificial_rule_from_rhs(node), ) - def visit_Repeat0(self, node: Repeat0) -> Tuple[str, str]: + def visit_Repeat0(self, node: Repeat0) -> tuple[str, str]: return self._generate_artificial_rule_call( node, "repeat0", @@ -178,7 +179,7 @@ class PythonCallMakerVisitor(GrammarVisitor): lambda: self.gen.artificial_rule_from_repeat(node.node, is_repeat1=False), ) - def visit_Repeat1(self, node: Repeat1) -> Tuple[str, str]: + def visit_Repeat1(self, node: Repeat1) -> tuple[str, str]: return self._generate_artificial_rule_call( node, "repeat1", @@ -186,7 +187,7 @@ class PythonCallMakerVisitor(GrammarVisitor): lambda: self.gen.artificial_rule_from_repeat(node.node, is_repeat1=True), ) - def visit_Gather(self, node: Gather) -> Tuple[str, str]: + def visit_Gather(self, node: Gather) -> tuple[str, str]: return self._generate_artificial_rule_call( node, "gather", @@ -194,13 +195,13 @@ class PythonCallMakerVisitor(GrammarVisitor): lambda: self.gen.artificial_rule_from_gather(node), ) - def visit_Group(self, node: Group) -> Tuple[Optional[str], str]: + def visit_Group(self, node: Group) -> tuple[str | None, str]: return self.visit(node.rhs) - def visit_Cut(self, node: Cut) -> Tuple[str, str]: + def visit_Cut(self, node: Cut) -> tuple[str, str]: return "cut", "True" - def visit_Forced(self, node: Forced) -> Tuple[str, str]: + def visit_Forced(self, node: Forced) -> tuple[str, str]: if isinstance(node.node, Group): _, val = self.visit(node.node.rhs) return "forced", f"self.expect_forced({val}, '''({node.node.rhs!s})''')" @@ -215,10 +216,10 @@ class PythonParserGenerator(ParserGenerator, GrammarVisitor): def __init__( self, grammar: grammar.Grammar, - file: Optional[IO[Text]], - tokens: Set[str] = set(token.tok_name.values()), - location_formatting: Optional[str] = None, - unreachable_formatting: Optional[str] = None, + file: IO[str] | None, + tokens: set[str] = set(token.tok_name.values()), + location_formatting: str | None = None, + unreachable_formatting: str | None = None, ): tokens.add("SOFT_KEYWORD") super().__init__(grammar, tokens, file) @@ -355,7 +356,7 @@ class PythonParserGenerator(ParserGenerator, GrammarVisitor): if is_loop: self.print(f"children.append({action})") - self.print(f"mark = self._mark()") + self.print("mark = self._mark()") else: if "UNREACHABLE" in action: action = action.replace("UNREACHABLE", self.unreachable_formatting) diff --git a/Tools/peg_generator/pegen/sccutils.py b/Tools/peg_generator/pegen/sccutils.py index da4c9331625..db30fc28346 100644 --- a/Tools/peg_generator/pegen/sccutils.py +++ b/Tools/peg_generator/pegen/sccutils.py @@ -1,11 +1,11 @@ # Adapted from mypy (mypy/build.py) under the MIT license. -from typing import * +from collections.abc import Iterable, Iterator, Set def strongly_connected_components( - vertices: AbstractSet[str], edges: Dict[str, AbstractSet[str]] -) -> Iterator[AbstractSet[str]]: + vertices: Set[str], edges: dict[str, Set[str]] +) -> Iterator[Set[str]]: """Compute Strongly Connected Components of a directed graph. Args: @@ -20,12 +20,12 @@ def strongly_connected_components( From https://code.activestate.com/recipes/578507-strongly-connected-components-of-a-directed-graph/. """ - identified: Set[str] = set() - stack: List[str] = [] - index: Dict[str, int] = {} - boundaries: List[int] = [] + identified: set[str] = set() + stack: list[str] = [] + index: dict[str, int] = {} + boundaries: list[int] = [] - def dfs(v: str) -> Iterator[Set[str]]: + def dfs(v: str) -> Iterator[set[str]]: index[v] = len(stack) stack.append(v) boundaries.append(index[v]) @@ -49,57 +49,9 @@ def strongly_connected_components( yield from dfs(v) -def topsort( - data: Dict[AbstractSet[str], Set[AbstractSet[str]]] -) -> Iterable[AbstractSet[AbstractSet[str]]]: - """Topological sort. - - Args: - data: A map from SCCs (represented as frozen sets of strings) to - sets of SCCs, its dependencies. NOTE: This data structure - is modified in place -- for normalization purposes, - self-dependencies are removed and entries representing - orphans are added. - - Returns: - An iterator yielding sets of SCCs that have an equivalent - ordering. NOTE: The algorithm doesn't care about the internal - structure of SCCs. - - Example: - Suppose the input has the following structure: - - {A: {B, C}, B: {D}, C: {D}} - - This is normalized to: - - {A: {B, C}, B: {D}, C: {D}, D: {}} - - The algorithm will yield the following values: - - {D} - {B, C} - {A} - - From https://code.activestate.com/recipes/577413-topological-sort/history/1/. - """ - # TODO: Use a faster algorithm? - for k, v in data.items(): - v.discard(k) # Ignore self dependencies. - for item in set.union(*data.values()) - set(data.keys()): - data[item] = set() - while True: - ready = {item for item, dep in data.items() if not dep} - if not ready: - break - yield ready - data = {item: (dep - ready) for item, dep in data.items() if item not in ready} - assert not data, "A cyclic dependency exists amongst %r" % data - - def find_cycles_in_scc( - graph: Dict[str, AbstractSet[str]], scc: AbstractSet[str], start: str -) -> Iterable[List[str]]: + graph: dict[str, Set[str]], scc: Set[str], start: str +) -> Iterable[list[str]]: """Find cycles in SCC emanating from start. Yields lists of the form ['A', 'B', 'C', 'A'], which means there's @@ -117,7 +69,7 @@ def find_cycles_in_scc( assert start in graph # Recursive helper that yields cycles. - def dfs(node: str, path: List[str]) -> Iterator[List[str]]: + def dfs(node: str, path: list[str]) -> Iterator[list[str]]: if node in path: yield path + [node] return diff --git a/Tools/peg_generator/pegen/testutil.py b/Tools/peg_generator/pegen/testutil.py index 0e85b844ef1..46f6c7fec1b 100644 --- a/Tools/peg_generator/pegen/testutil.py +++ b/Tools/peg_generator/pegen/testutil.py @@ -6,7 +6,7 @@ import sys import textwrap import token import tokenize -from typing import IO, Any, Dict, Final, Optional, Type, cast +from typing import IO, Any, Final, cast from pegen.build import compile_c_extension from pegen.c_generator import CParserGenerator @@ -23,19 +23,19 @@ NON_EXACT_TOKENS = { } -def generate_parser(grammar: Grammar) -> Type[Parser]: +def generate_parser(grammar: Grammar) -> type[Parser]: # Generate a parser. out = io.StringIO() genr = PythonParserGenerator(grammar, out) genr.generate("<string>") # Load the generated parser class. - ns: Dict[str, Any] = {} + ns: dict[str, Any] = {} exec(out.getvalue(), ns) return ns["GeneratedParser"] -def run_parser(file: IO[bytes], parser_class: Type[Parser], *, verbose: bool = False) -> Any: +def run_parser(file: IO[bytes], parser_class: type[Parser], *, verbose: bool = False) -> Any: # Run a parser on a file (stream). tokenizer = Tokenizer(tokenize.generate_tokens(file.readline)) # type: ignore[arg-type] # typeshed issue #3515 parser = parser_class(tokenizer, verbose=verbose) @@ -46,7 +46,7 @@ def run_parser(file: IO[bytes], parser_class: Type[Parser], *, verbose: bool = F def parse_string( - source: str, parser_class: Type[Parser], *, dedent: bool = True, verbose: bool = False + source: str, parser_class: type[Parser], *, dedent: bool = True, verbose: bool = False ) -> Any: # Run the parser on a string. if dedent: @@ -55,7 +55,7 @@ def parse_string( return run_parser(file, parser_class, verbose=verbose) # type: ignore[arg-type] # typeshed issue #3515 -def make_parser(source: str) -> Type[Parser]: +def make_parser(source: str) -> type[Parser]: # Combine parse_string() and generate_parser(). grammar = parse_string(source, GrammarParser) return generate_parser(grammar) @@ -86,7 +86,7 @@ def generate_parser_c_extension( grammar: Grammar, path: pathlib.PurePath, debug: bool = False, - library_dir: Optional[str] = None, + library_dir: str | None = None, ) -> Any: """Generate a parser c extension for the given grammar in the given path diff --git a/Tools/peg_generator/pegen/tokenizer.py b/Tools/peg_generator/pegen/tokenizer.py index 7ee49e1432b..fba5bac9517 100644 --- a/Tools/peg_generator/pegen/tokenizer.py +++ b/Tools/peg_generator/pegen/tokenizer.py @@ -1,6 +1,6 @@ import token import tokenize -from typing import Dict, Iterator, List +from collections.abc import Iterator Mark = int # NewType('Mark', int) @@ -8,7 +8,11 @@ exact_token_types = token.EXACT_TOKEN_TYPES def shorttok(tok: tokenize.TokenInfo) -> str: - return "%-25.25s" % f"{tok.start[0]}.{tok.start[1]}: {token.tok_name[tok.type]}:{tok.string!r}" + formatted = ( + f"{tok.start[0]}.{tok.start[1]}: " + f"{token.tok_name[tok.type]}:{tok.string!r}" + ) + return f"{formatted:<25.25}" class Tokenizer: @@ -17,7 +21,7 @@ class Tokenizer: This is pretty tied to Python's syntax. """ - _tokens: List[tokenize.TokenInfo] + _tokens: list[tokenize.TokenInfo] def __init__( self, tokengen: Iterator[tokenize.TokenInfo], *, path: str = "", verbose: bool = False @@ -26,7 +30,7 @@ class Tokenizer: self._tokens = [] self._index = 0 self._verbose = verbose - self._lines: Dict[int, str] = {} + self._lines: dict[int, str] = {} self._path = path if verbose: self.report(False, False) @@ -72,7 +76,7 @@ class Tokenizer: break return tok - def get_lines(self, line_numbers: List[int]) -> List[str]: + def get_lines(self, line_numbers: list[int]) -> list[str]: """Retrieve source lines corresponding to line numbers.""" if self._lines: lines = self._lines diff --git a/Tools/peg_generator/pegen/validator.py b/Tools/peg_generator/pegen/validator.py index 4699d5712d9..635eb398b41 100644 --- a/Tools/peg_generator/pegen/validator.py +++ b/Tools/peg_generator/pegen/validator.py @@ -1,5 +1,3 @@ -from typing import Optional - from pegen import grammar from pegen.grammar import Alt, GrammarVisitor, Rhs, Rule @@ -11,7 +9,7 @@ class ValidationError(Exception): class GrammarValidator(GrammarVisitor): def __init__(self, grammar: grammar.Grammar) -> None: self.grammar = grammar - self.rulename: Optional[str] = None + self.rulename: str | None = None def validate_rule(self, rulename: str, node: Rule) -> None: self.rulename = rulename diff --git a/Tools/picklebench/README.md b/Tools/picklebench/README.md new file mode 100644 index 00000000000..7d52485c386 --- /dev/null +++ b/Tools/picklebench/README.md @@ -0,0 +1,232 @@ +# Pickle Chunked Reading Benchmark + +This benchmark measures the performance impact of the chunked reading optimization in GH PR #119204 for the pickle module. + +## What This Tests + +The PR adds chunked reading (1MB chunks) to prevent memory exhaustion when unpickling large objects: +- **BINBYTES8** - Large bytes objects (protocol 4+) +- **BINUNICODE8** - Large strings (protocol 4+) +- **BYTEARRAY8** - Large bytearrays (protocol 5) +- **FRAME** - Large frames +- **LONG4** - Large integers +- An antagonistic mode that tests using memory denial of service inducing malicious pickles. + +## Quick Start + +```bash +# Run full benchmark suite (1MiB → 200MiB, takes several minutes) +build/python Tools/picklebench/memory_dos_impact.py + +# Test just a few sizes (quick test: 1, 10, 50 MiB) +build/python Tools/picklebench/memory_dos_impact.py --sizes 1 10 50 + +# Test smaller range for faster results +build/python Tools/picklebench/memory_dos_impact.py --sizes 1 5 10 + +# Output as markdown for reports +build/python Tools/picklebench/memory_dos_impact.py --format markdown > results.md + +# Test with protocol 4 instead of 5 +build/python Tools/picklebench/memory_dos_impact.py --protocol 4 +``` + +**Note:** Sizes are specified in MiB. Use `--sizes 1 2 5` for 1MiB, 2MiB, 5MiB objects. + +## Antagonistic Mode (DoS Protection Test) + +The `--antagonistic` flag tests **malicious pickles** that demonstrate the memory DoS protection: + +```bash +# Quick DoS protection test (claims 10, 50, 100 MB but provides 1KB) +build/python Tools/picklebench/memory_dos_impact.py --antagonistic --sizes 10 50 100 + +# Full DoS test (default: 10, 50, 100, 500, 1000, 5000 MB claimed) +build/python Tools/picklebench/memory_dos_impact.py --antagonistic +``` + +### What This Tests + +Unlike normal benchmarks that test **legitimate pickles**, antagonistic mode tests: +- **Truncated BINBYTES8**: Claims 100MB but provides only 1KB (will fail to unpickle) +- **Truncated BINUNICODE8**: Same for strings +- **Truncated BYTEARRAY8**: Same for bytearrays +- **Sparse memo attacks**: PUT at index 1 billion (would allocate huge array before PR) + +**Key difference:** +- **Normal mode**: Tests real data, shows ~5% time overhead +- **Antagonistic mode**: Tests malicious data, shows ~99% memory savings + +### Expected Results + +``` +100MB Claimed (actual: 1KB) + binbytes8_100MB_claim + Peak memory: 1.00 MB (claimed: 100 MB, saved: 99.00 MB, 99.0%) + Error: UnpicklingError ← Expected! + +Summary: + Average claimed: 126.2 MB + Average peak: 0.54 MB + Average saved: 125.7 MB (99.6% reduction) +Protection Status: ✓ Memory DoS attacks mitigated by chunked reading +``` + +**Before PR**: Would allocate full claimed size (100MB+), potentially crash +**After PR**: Allocates 1MB chunks, fails fast with minimal memory + +This demonstrates the **security improvement** - protection against memory exhaustion attacks. + +## Before/After Comparison + +The benchmark includes an automatic comparison feature that runs the same tests on both a baseline and current Python build. + +### Option 1: Automatic Comparison (Recommended) + +Build both versions, then use `--baseline` to automatically compare: + +```bash +# Build the baseline (main branch without PR) +git checkout main +mkdir -p build-main +cd build-main && ../configure && make -j $(nproc) && cd .. + +# Build the current version (with PR) +git checkout unpickle-overallocate +mkdir -p build +cd build && ../configure && make -j $(nproc) && cd .. + +# Run automatic comparison (quick test with a few sizes) +build/python Tools/picklebench/memory_dos_impact.py \ + --baseline build-main/python \ + --sizes 1 10 50 + +# Full comparison (all default sizes) +build/python Tools/picklebench/memory_dos_impact.py \ + --baseline build-main/python +``` + +The comparison output shows: +- Side-by-side metrics (Current vs Baseline) +- Percentage change for time and memory +- Overall summary statistics + +### Interpreting Comparison Results + +- **Time change**: Small positive % is expected (chunking adds overhead, typically 5-10%) +- **Memory change**: Negative % is good (chunking saves memory, especially for large objects) +- **Trade-off**: Slightly slower but much safer against memory exhaustion attacks + +### Option 2: Manual Comparison + +Save results separately and compare manually: + +```bash +# Baseline results +build-main/python Tools/picklebench/memory_dos_impact.py --format json > baseline.json + +# Current results +build/python Tools/picklebench/memory_dos_impact.py --format json > current.json + +# Manual comparison +diff -y <(jq '.' baseline.json) <(jq '.' current.json) +``` + +## Understanding the Results + +### Critical Sizes + +The default test suite includes: +- **< 1MiB (999,000 bytes)**: No chunking, allocates full size upfront +- **= 1MiB (1,048,576 bytes)**: Threshold, chunking just starts +- **> 1MiB (1,048,577 bytes)**: Chunked reading engaged +- **1, 2, 5, 10MiB**: Show scaling behavior with chunking +- **20, 50, 100, 200MiB**: Stress test large object handling + +**Note:** The full suite may require more than 16GiB of RAM. + +### Key Metrics + +- **Time (mean)**: Average unpickling time - should be similar before/after +- **Time (stdev)**: Consistency - lower is better +- **Peak Memory**: Maximum memory during unpickling - **expected to be LOWER after PR** +- **Pickle Size**: Size of the serialized data on disk + +### Test Types + +| Test | What It Stresses | +|------|------------------| +| `bytes_*` | BINBYTES8 opcode, raw binary data | +| `string_ascii_*` | BINUNICODE8 with simple ASCII | +| `string_utf8_*` | BINUNICODE8 with multibyte UTF-8 (€ chars) | +| `bytearray_*` | BYTEARRAY8 opcode (protocol 5) | +| `list_large_items_*` | Multiple chunked reads in sequence | +| `dict_large_values_*` | Chunking in dict deserialization | +| `nested_*` | Realistic mixed data structures | +| `tuple_*` | Immutable structures | + +## Expected Results + +### Before PR (main branch) +- Single large allocation per object +- Risk of memory exhaustion with malicious pickles + +### After PR (unpickle-overallocate branch) +- Chunked allocation (1MB at a time) +- **Slightly higher CPU time** (multiple allocations + resizing) +- **Significantly lower peak memory** (no large pre-allocation) +- Protection against DoS via memory exhaustion + +## Advanced Usage + +### Test Specific Sizes + +```bash +# Test only 5MiB and 10MiB objects +build/python Tools/picklebench/memory_dos_impact.py --sizes 5 10 + +# Test large objects: 50, 100, 200 MiB +build/python Tools/picklebench/memory_dos_impact.py --sizes 50 100 200 +``` + +### More Iterations for Stable Timing + +```bash +# Run 10 iterations per test for better statistics +build/python Tools/picklebench/memory_dos_impact.py --iterations 10 --sizes 1 10 +``` + +### JSON Output for Analysis + +```bash +# Generate JSON for programmatic analysis +build/python Tools/picklebench/memory_dos_impact.py --format json | python -m json.tool +``` + +## Interpreting Memory Results + +The **peak memory** metric shows the maximum memory allocated during unpickling: + +- **Without chunking**: Allocates full size immediately + - 10MB object → 10MB allocation upfront + +- **With chunking**: Allocates in 1MB chunks, grows geometrically + - 10MB object → starts with 1MB, grows: 2MB, 4MB, 8MB (final: ~10MB total) + - Peak is lower because allocation is incremental + +## Typical Results + +On a system with the PR applied, you should see: + +``` +1.00MiB Test Results + bytes_1.00MiB: ~0.3ms, 1.00MiB peak (just at threshold) + +2.00MiB Test Results + bytes_2.00MiB: ~0.8ms, 2.00MiB peak (chunked: 1MiB → 2MiB) + +10.00MiB Test Results + bytes_10.00MiB: ~3-5ms, 10.00MiB peak (chunked: 1→2→4→8→10 MiB) +``` + +Time overhead is minimal (~10-20% for very large objects), but memory safety is significantly improved. diff --git a/Tools/picklebench/memory_dos_impact.py b/Tools/picklebench/memory_dos_impact.py new file mode 100755 index 00000000000..3bad6586c46 --- /dev/null +++ b/Tools/picklebench/memory_dos_impact.py @@ -0,0 +1,1069 @@ +#!/usr/bin/env python3 +# +# Author: Claude Sonnet 4.5 as driven by gpshead +# +""" +Microbenchmark for pickle module chunked reading performance (GH PR #119204). + +This script generates Python data structures that act as antagonistic load +tests for the chunked reading code introduced to prevent memory exhaustion when +unpickling large objects. + +The PR adds chunked reading (1MB chunks) for: +- BINBYTES8 (large bytes) +- BINUNICODE8 (large strings) +- BYTEARRAY8 (large bytearrays) +- FRAME (large frames) +- LONG4 (large integers) + +Including an antagonistic mode that exercies memory denial of service pickles. + +Usage: + python memory_dos_impact.py --help +""" + +import argparse +import gc +import io +import json +import os +import pickle +import statistics +import struct +import subprocess +import sys +import tempfile +import tracemalloc +from pathlib import Path +from time import perf_counter +from typing import Any, Dict, List, Tuple, Optional + + +# Configuration +MIN_READ_BUF_SIZE = 1 << 20 # 1MB - matches pickle.py _MIN_READ_BUF_SIZE + +# Test sizes in MiB +DEFAULT_SIZES_MIB = [1, 2, 5, 10, 20, 50, 100, 200] + +# Convert to bytes, plus threshold boundary tests +DEFAULT_SIZES = ( + [999_000] # Below 1MiB (no chunking) + + [size * (1 << 20) for size in DEFAULT_SIZES_MIB] # MiB to bytes + + [1_048_577] # Just above 1MiB (minimal chunking overhead) +) +DEFAULT_SIZES.sort() + +# Baseline benchmark configuration +BASELINE_BENCHMARK_TIMEOUT_SECONDS = 600 # 10 minutes + +# Sparse memo attack test configuration +# Format: test_name -> (memo_index, baseline_memory_note) +SPARSE_MEMO_TESTS = { + "sparse_memo_1M": (1_000_000, "~8 MB array"), + "sparse_memo_100M": (100_000_000, "~800 MB array"), + "sparse_memo_1B": (1_000_000_000, "~8 GB array"), +} + + +# Utility functions + +def _extract_size_mb(size_key: str) -> float: + """Extract numeric MiB value from size_key like '10.00MB' or '1.00MiB'. + + Returns 0.0 for non-numeric keys (they'll be sorted last). + """ + try: + return float(size_key.replace('MB', '').replace('MiB', '')) + except ValueError: + return 999999.0 # Put non-numeric keys last + + +def _format_output(results: Dict[str, Dict[str, Any]], format_type: str, is_antagonistic: bool) -> str: + """Format benchmark results according to requested format. + + Args: + results: Benchmark results dictionary + format_type: Output format ('text', 'markdown', or 'json') + is_antagonistic: Whether these are antagonistic (DoS) test results + + Returns: + Formatted output string + """ + if format_type == 'json': + return Reporter.format_json(results) + elif is_antagonistic: + # Antagonistic mode uses specialized formatter for text/markdown + return Reporter.format_antagonistic(results) + elif format_type == 'text': + return Reporter.format_text(results) + elif format_type == 'markdown': + return Reporter.format_markdown(results) + else: + # Default to text format + return Reporter.format_text(results) + + +class AntagonisticGenerator: + """Generate malicious/truncated pickles for DoS protection testing. + + These pickles claim large sizes but provide minimal data, causing them to fail + during unpickling. They demonstrate the memory protection of chunked reading. + """ + + @staticmethod + def truncated_binbytes8(claimed_size: int, actual_size: int = 1024) -> bytes: + """BINBYTES8 claiming `claimed_size` but providing only `actual_size` bytes. + + This will fail with UnpicklingError but demonstrates peak memory usage. + Before PR: Allocates full claimed_size + After PR: Allocates in 1MB chunks, fails fast + """ + return b'\x8e' + struct.pack('<Q', claimed_size) + b'x' * actual_size + + @staticmethod + def truncated_binunicode8(claimed_size: int, actual_size: int = 1024) -> bytes: + """BINUNICODE8 claiming `claimed_size` but providing only `actual_size` bytes.""" + return b'\x8d' + struct.pack('<Q', claimed_size) + b'x' * actual_size + + @staticmethod + def truncated_bytearray8(claimed_size: int, actual_size: int = 1024) -> bytes: + """BYTEARRAY8 claiming `claimed_size` but providing only `actual_size` bytes.""" + return b'\x96' + struct.pack('<Q', claimed_size) + b'x' * actual_size + + @staticmethod + def truncated_frame(claimed_size: int) -> bytes: + """FRAME claiming `claimed_size` but providing minimal data.""" + return b'\x95' + struct.pack('<Q', claimed_size) + b'N.' + + @staticmethod + def sparse_memo_attack(index: int) -> bytes: + """LONG_BINPUT with huge sparse index. + + Before PR: Tries to allocate array with `index` slots (OOM) + After PR: Uses dict-based memo for sparse indices + """ + return (b'(]r' + struct.pack('<I', index & 0xFFFFFFFF) + + b'j' + struct.pack('<I', index & 0xFFFFFFFF) + b't.') + + @staticmethod + def multi_claim_attack(count: int, size_each: int) -> bytes: + """Multiple BINBYTES8 claims in sequence. + + Tests that multiple large claims don't accumulate memory. + """ + data = b'(' # MARK + for _ in range(count): + data += b'\x8e' + struct.pack('<Q', size_each) + b'x' * 1024 + data += b't.' # TUPLE + STOP + return data + + +class DataGenerator: + """Generate various types of large data structures for pickle testing.""" + + @staticmethod + def large_bytes(size: int) -> bytes: + """Generate random bytes of specified size.""" + return os.urandom(size) + + @staticmethod + def large_string_ascii(size: int) -> str: + """Generate ASCII string of specified size.""" + return 'x' * size + + @staticmethod + def large_string_multibyte(size: int) -> str: + """Generate multibyte UTF-8 string (3 bytes per char for €).""" + # Each € is 3 bytes in UTF-8 + return '€' * (size // 3) + + @staticmethod + def large_bytearray(size: int) -> bytearray: + """Generate bytearray of specified size.""" + return bytearray(os.urandom(size)) + + @staticmethod + def list_of_large_bytes(item_size: int, count: int) -> List[bytes]: + """Generate list containing multiple large bytes objects.""" + return [os.urandom(item_size) for _ in range(count)] + + @staticmethod + def dict_with_large_values(value_size: int, count: int) -> Dict[str, bytes]: + """Generate dict with large bytes values.""" + return { + f'key_{i}': os.urandom(value_size) + for i in range(count) + } + + @staticmethod + def nested_structure(size: int) -> Dict[str, Any]: + """Generate nested structure with various large objects.""" + chunk_size = size // 4 + return { + 'name': 'test_object', + 'data': { + 'bytes': os.urandom(chunk_size), + 'string': 's' * chunk_size, + 'bytearray': bytearray(b'b' * chunk_size), + }, + 'items': [os.urandom(chunk_size // 4) for _ in range(4)], + 'metadata': { + 'size': size, + 'type': 'nested', + }, + } + + @staticmethod + def tuple_of_large_objects(size: int) -> Tuple[bytes, str, bytearray]: + """Generate tuple with large objects (immutable, different pickle path).""" + chunk_size = size // 3 + return ( + os.urandom(chunk_size), + 'x' * chunk_size, + bytearray(b'y' * chunk_size), + ) + + +class PickleBenchmark: + """Benchmark pickle unpickling performance and memory usage.""" + + def __init__(self, obj: Any, protocol: int = 5, iterations: int = 3): + self.obj = obj + self.protocol = protocol + self.iterations = iterations + self.pickle_data = pickle.dumps(obj, protocol=protocol) + self.pickle_size = len(self.pickle_data) + + def benchmark_time(self) -> Dict[str, float]: + """Measure unpickling time over multiple iterations.""" + times = [] + + for _ in range(self.iterations): + start = perf_counter() + result = pickle.loads(self.pickle_data) + elapsed = perf_counter() - start + times.append(elapsed) + + # Verify correctness (first iteration only) + if len(times) == 1: + if result != self.obj: + raise ValueError("Unpickled object doesn't match original!") + + return { + 'mean': statistics.mean(times), + 'median': statistics.median(times), + 'stdev': statistics.stdev(times) if len(times) > 1 else 0.0, + 'min': min(times), + 'max': max(times), + } + + def benchmark_memory(self) -> int: + """Measure peak memory usage during unpickling.""" + tracemalloc.start() + + # Warmup + pickle.loads(self.pickle_data) + + # Actual measurement + gc.collect() + tracemalloc.reset_peak() + result = pickle.loads(self.pickle_data) + current, peak = tracemalloc.get_traced_memory() + + tracemalloc.stop() + + # Verify correctness + if result != self.obj: + raise ValueError("Unpickled object doesn't match original!") + + return peak + + def run_all(self) -> Dict[str, Any]: + """Run all benchmarks and return comprehensive results.""" + time_stats = self.benchmark_time() + peak_memory = self.benchmark_memory() + + return { + 'pickle_size_bytes': self.pickle_size, + 'pickle_size_mb': self.pickle_size / (1 << 20), + 'protocol': self.protocol, + 'time': time_stats, + 'memory_peak_bytes': peak_memory, + 'memory_peak_mb': peak_memory / (1 << 20), + 'iterations': self.iterations, + } + + +class AntagonisticBenchmark: + """Benchmark antagonistic/malicious pickles that demonstrate DoS protection. + + These pickles are designed to FAIL unpickling, but we measure peak memory + usage before the failure to demonstrate the memory protection. + """ + + def __init__(self, pickle_data: bytes, name: str): + self.pickle_data = pickle_data + self.name = name + + def measure_peak_memory(self, expect_success: bool = False) -> Dict[str, Any]: + """Measure peak memory when attempting to unpickle antagonistic data. + + Args: + expect_success: If True, test expects successful unpickling (e.g., sparse memo). + If False, test expects failure (e.g., truncated data). + """ + tracemalloc.start() + gc.collect() + tracemalloc.reset_peak() + + error_type = None + error_msg = None + succeeded = False + + try: + result = pickle.loads(self.pickle_data) + succeeded = True + if expect_success: + error_type = "Success (expected)" + else: + error_type = "WARNING: Expected failure but succeeded" + except (pickle.UnpicklingError, EOFError, ValueError, OverflowError) as e: + if expect_success: + error_type = f"UNEXPECTED FAILURE: {type(e).__name__}" + error_msg = str(e)[:100] + else: + # Expected failure for truncated data tests + error_type = type(e).__name__ + error_msg = str(e)[:100] + + current, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + + return { + 'test_name': self.name, + 'peak_memory_bytes': peak, + 'peak_memory_mb': peak / (1 << 20), + 'error_type': error_type, + 'error_msg': error_msg, + 'pickle_size_bytes': len(self.pickle_data), + 'expected_outcome': 'success' if expect_success else 'failure', + 'succeeded': succeeded, + } + + +class AntagonisticTestSuite: + """Manage a suite of antagonistic (DoS protection) tests.""" + + # Default sizes in MB to claim (will provide only 1KB actual data) + DEFAULT_ANTAGONISTIC_SIZES_MB = [10, 50, 100, 500, 1000, 5000] + + def __init__(self, claimed_sizes_mb: List[int]): + self.claimed_sizes_mb = claimed_sizes_mb + + def _run_truncated_test( + self, + test_type: str, + generator_func, + claimed_bytes: int, + claimed_mb: int, + size_key: str, + all_results: Dict[str, Dict[str, Any]] + ) -> None: + """Run a single truncated data test and store results. + + Args: + test_type: Type identifier (e.g., 'binbytes8', 'binunicode8') + generator_func: Function to generate malicious pickle data + claimed_bytes: Size claimed in the pickle (bytes) + claimed_mb: Size claimed in the pickle (MB) + size_key: Result key for this size (e.g., '10MB') + all_results: Dictionary to store results in + """ + test_name = f"{test_type}_{size_key}_claim" + data = generator_func(claimed_bytes) + bench = AntagonisticBenchmark(data, test_name) + result = bench.measure_peak_memory(expect_success=False) + result['claimed_mb'] = claimed_mb + all_results[size_key][test_name] = result + + def run_all_tests(self) -> Dict[str, Dict[str, Any]]: + """Run comprehensive antagonistic test suite.""" + all_results = {} + + for claimed_mb in self.claimed_sizes_mb: + claimed_bytes = claimed_mb << 20 + size_key = f"{claimed_mb}MB" + all_results[size_key] = {} + + # Run truncated data tests (expect failure) + self._run_truncated_test('binbytes8', AntagonisticGenerator.truncated_binbytes8, + claimed_bytes, claimed_mb, size_key, all_results) + self._run_truncated_test('binunicode8', AntagonisticGenerator.truncated_binunicode8, + claimed_bytes, claimed_mb, size_key, all_results) + self._run_truncated_test('bytearray8', AntagonisticGenerator.truncated_bytearray8, + claimed_bytes, claimed_mb, size_key, all_results) + self._run_truncated_test('frame', AntagonisticGenerator.truncated_frame, + claimed_bytes, claimed_mb, size_key, all_results) + + # Test 5: Sparse memo (expect success - dict-based memo works!) + all_results["Sparse Memo (Success Expected)"] = {} + for test_name, (index, baseline_note) in SPARSE_MEMO_TESTS.items(): + data = AntagonisticGenerator.sparse_memo_attack(index) + bench = AntagonisticBenchmark(data, test_name) + result = bench.measure_peak_memory(expect_success=True) + result['claimed_mb'] = "N/A" + result['baseline_note'] = f"Without PR: {baseline_note}" + all_results["Sparse Memo (Success Expected)"][test_name] = result + + # Test 6: Multi-claim attack (expect failure) + test_name = "multi_claim_10x100MB" + data = AntagonisticGenerator.multi_claim_attack(10, 100 << 20) + bench = AntagonisticBenchmark(data, test_name) + result = bench.measure_peak_memory(expect_success=False) + result['claimed_mb'] = 1000 # 10 * 100MB + all_results["Multi-Claim (Failure Expected)"] = {test_name: result} + + return all_results + + +class TestSuite: + """Manage a suite of benchmark tests.""" + + def __init__(self, sizes: List[int], protocol: int = 5, iterations: int = 3): + self.sizes = sizes + self.protocol = protocol + self.iterations = iterations + self.results = {} + + def run_test(self, name: str, obj: Any) -> Dict[str, Any]: + """Run benchmark for a single test object.""" + bench = PickleBenchmark(obj, self.protocol, self.iterations) + results = bench.run_all() + results['test_name'] = name + results['object_type'] = type(obj).__name__ + return results + + def run_all_tests(self) -> Dict[str, Dict[str, Any]]: + """Run comprehensive test suite across all sizes and types.""" + all_results = {} + + for size in self.sizes: + size_key = f"{size / (1 << 20):.2f}MB" + all_results[size_key] = {} + + # Test 1: Large bytes object (BINBYTES8) + test_name = f"bytes_{size_key}" + obj = DataGenerator.large_bytes(size) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 2: Large ASCII string (BINUNICODE8) + test_name = f"string_ascii_{size_key}" + obj = DataGenerator.large_string_ascii(size) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 3: Large multibyte UTF-8 string + if size >= 3: + test_name = f"string_utf8_{size_key}" + obj = DataGenerator.large_string_multibyte(size) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 4: Large bytearray (BYTEARRAY8, protocol 5) + if self.protocol >= 5: + test_name = f"bytearray_{size_key}" + obj = DataGenerator.large_bytearray(size) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 5: List of large objects (repeated chunking) + if size >= MIN_READ_BUF_SIZE * 2: + test_name = f"list_large_items_{size_key}" + item_size = size // 5 + obj = DataGenerator.list_of_large_bytes(item_size, 5) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 6: Dict with large values + if size >= MIN_READ_BUF_SIZE * 2: + test_name = f"dict_large_values_{size_key}" + value_size = size // 3 + obj = DataGenerator.dict_with_large_values(value_size, 3) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 7: Nested structure + if size >= MIN_READ_BUF_SIZE: + test_name = f"nested_{size_key}" + obj = DataGenerator.nested_structure(size) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + # Test 8: Tuple (immutable) + if size >= 3: + test_name = f"tuple_{size_key}" + obj = DataGenerator.tuple_of_large_objects(size) + all_results[size_key][test_name] = self.run_test(test_name, obj) + + return all_results + + +class Comparator: + """Compare benchmark results between current and baseline interpreters.""" + + @staticmethod + def _extract_json_from_output(output: str) -> Dict[str, Dict[str, Any]]: + """Extract JSON data from subprocess output. + + Skips any print statements before the JSON output and parses the JSON. + + Args: + output: Raw stdout from subprocess + + Returns: + Parsed JSON as dictionary + + Raises: + SystemExit: If JSON cannot be found or parsed + """ + output_lines = output.strip().split('\n') + json_start = -1 + for i, line in enumerate(output_lines): + if line.strip().startswith('{'): + json_start = i + break + + if json_start == -1: + print("Error: Could not find JSON output from baseline", file=sys.stderr) + sys.exit(1) + + json_output = '\n'.join(output_lines[json_start:]) + try: + return json.loads(json_output) + except json.JSONDecodeError as e: + print(f"Error: Could not parse baseline JSON output: {e}", file=sys.stderr) + sys.exit(1) + + @staticmethod + def run_baseline_benchmark(baseline_python: str, args: argparse.Namespace) -> Dict[str, Dict[str, Any]]: + """Run the benchmark using the baseline Python interpreter.""" + # Build command to run this script with baseline Python + cmd = [ + baseline_python, + __file__, + '--format', 'json', + '--protocol', str(args.protocol), + '--iterations', str(args.iterations), + ] + + if args.sizes is not None: + cmd.extend(['--sizes'] + [str(s) for s in args.sizes]) + + if args.antagonistic: + cmd.append('--antagonistic') + + print(f"\nRunning baseline benchmark with: {baseline_python}") + print(f"Command: {' '.join(cmd)}\n") + + try: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=BASELINE_BENCHMARK_TIMEOUT_SECONDS, + ) + + if result.returncode != 0: + print(f"Error running baseline benchmark:", file=sys.stderr) + print(result.stderr, file=sys.stderr) + sys.exit(1) + + # Extract and parse JSON from output + return Comparator._extract_json_from_output(result.stdout) + + except subprocess.TimeoutExpired: + print("Error: Baseline benchmark timed out", file=sys.stderr) + sys.exit(1) + + @staticmethod + def calculate_change(baseline_value: float, current_value: float) -> float: + """Calculate percentage change from baseline to current.""" + if baseline_value == 0: + return 0.0 + return ((current_value - baseline_value) / baseline_value) * 100 + + @staticmethod + def format_comparison( + current_results: Dict[str, Dict[str, Any]], + baseline_results: Dict[str, Dict[str, Any]] + ) -> str: + """Format comparison results as readable text.""" + lines = [] + lines.append("=" * 100) + lines.append("Pickle Unpickling Benchmark Comparison") + lines.append("=" * 100) + lines.append("") + lines.append("Legend: Current vs Baseline | % Change (+ is slower/more memory, - is faster/less memory)") + lines.append("") + + # Sort size keys numerically + for size_key in sorted(current_results.keys(), key=_extract_size_mb): + if size_key not in baseline_results: + continue + + lines.append(f"\n{size_key} Comparison") + lines.append("-" * 100) + + current_tests = current_results[size_key] + baseline_tests = baseline_results[size_key] + + for test_name in sorted(current_tests.keys()): + if test_name not in baseline_tests: + continue + + curr = current_tests[test_name] + base = baseline_tests[test_name] + + time_change = Comparator.calculate_change( + base['time']['mean'], curr['time']['mean'] + ) + mem_change = Comparator.calculate_change( + base['memory_peak_mb'], curr['memory_peak_mb'] + ) + + lines.append(f"\n {curr['test_name']}") + lines.append(f" Time: {curr['time']['mean']*1000:6.2f}ms vs {base['time']['mean']*1000:6.2f}ms | " + f"{time_change:+6.1f}%") + lines.append(f" Memory: {curr['memory_peak_mb']:6.2f}MB vs {base['memory_peak_mb']:6.2f}MB | " + f"{mem_change:+6.1f}%") + + lines.append("\n" + "=" * 100) + lines.append("\nSummary:") + + # Calculate overall statistics + time_changes = [] + mem_changes = [] + + for size_key in current_results.keys(): + if size_key not in baseline_results: + continue + for test_name in current_results[size_key].keys(): + if test_name not in baseline_results[size_key]: + continue + curr = current_results[size_key][test_name] + base = baseline_results[size_key][test_name] + + time_changes.append(Comparator.calculate_change( + base['time']['mean'], curr['time']['mean'] + )) + mem_changes.append(Comparator.calculate_change( + base['memory_peak_mb'], curr['memory_peak_mb'] + )) + + if time_changes: + lines.append(f" Time change: mean={statistics.mean(time_changes):+.1f}%, " + f"median={statistics.median(time_changes):+.1f}%") + if mem_changes: + lines.append(f" Memory change: mean={statistics.mean(mem_changes):+.1f}%, " + f"median={statistics.median(mem_changes):+.1f}%") + + lines.append("=" * 100) + return "\n".join(lines) + + @staticmethod + def format_antagonistic_comparison( + current_results: Dict[str, Dict[str, Any]], + baseline_results: Dict[str, Dict[str, Any]] + ) -> str: + """Format antagonistic benchmark comparison results.""" + lines = [] + lines.append("=" * 100) + lines.append("Antagonistic Pickle Benchmark Comparison (Memory DoS Protection)") + lines.append("=" * 100) + lines.append("") + lines.append("Legend: Current vs Baseline | Memory Change (- is better, shows memory saved)") + lines.append("") + lines.append("This compares TWO types of DoS protection:") + lines.append(" 1. Truncated data → Baseline allocates full claimed size, Current uses chunked reading") + lines.append(" 2. Sparse memo → Baseline uses huge arrays, Current uses dict-based memo") + lines.append("") + + # Track statistics + truncated_memory_changes = [] + sparse_memory_changes = [] + + # Sort size keys numerically + for size_key in sorted(current_results.keys(), key=_extract_size_mb): + if size_key not in baseline_results: + continue + + lines.append(f"\n{size_key} Comparison") + lines.append("-" * 100) + + current_tests = current_results[size_key] + baseline_tests = baseline_results[size_key] + + for test_name in sorted(current_tests.keys()): + if test_name not in baseline_tests: + continue + + curr = current_tests[test_name] + base = baseline_tests[test_name] + + curr_peak_mb = curr['peak_memory_mb'] + base_peak_mb = base['peak_memory_mb'] + expected_outcome = curr.get('expected_outcome', 'failure') + + mem_change = Comparator.calculate_change(base_peak_mb, curr_peak_mb) + mem_saved_mb = base_peak_mb - curr_peak_mb + + lines.append(f"\n {curr['test_name']}") + lines.append(f" Memory: {curr_peak_mb:6.2f}MB vs {base_peak_mb:6.2f}MB | " + f"{mem_change:+6.1f}% ({mem_saved_mb:+.2f}MB saved)") + + # Track based on test type + if expected_outcome == 'success': + sparse_memory_changes.append(mem_change) + if curr.get('baseline_note'): + lines.append(f" Note: {curr['baseline_note']}") + else: + truncated_memory_changes.append(mem_change) + claimed_mb = curr.get('claimed_mb', 'N/A') + if claimed_mb != 'N/A': + lines.append(f" Claimed: {claimed_mb:,}MB") + + # Show status + curr_status = curr.get('error_type', 'Unknown') + base_status = base.get('error_type', 'Unknown') + if curr_status != base_status: + lines.append(f" Status: {curr_status} (baseline: {base_status})") + else: + lines.append(f" Status: {curr_status}") + + lines.append("\n" + "=" * 100) + lines.append("\nSummary:") + lines.append("") + + if truncated_memory_changes: + lines.append(" Truncated Data Protection (chunked reading):") + lines.append(f" Mean memory change: {statistics.mean(truncated_memory_changes):+.1f}%") + lines.append(f" Median memory change: {statistics.median(truncated_memory_changes):+.1f}%") + avg_change = statistics.mean(truncated_memory_changes) + if avg_change < -50: + lines.append(f" Result: ✓ Dramatic memory reduction ({avg_change:.1f}%) - DoS protection working!") + elif avg_change < 0: + lines.append(f" Result: ✓ Memory reduced ({avg_change:.1f}%)") + else: + lines.append(f" Result: ⚠ Memory increased ({avg_change:.1f}%) - unexpected!") + lines.append("") + + if sparse_memory_changes: + lines.append(" Sparse Memo Protection (dict-based memo):") + lines.append(f" Mean memory change: {statistics.mean(sparse_memory_changes):+.1f}%") + lines.append(f" Median memory change: {statistics.median(sparse_memory_changes):+.1f}%") + avg_change = statistics.mean(sparse_memory_changes) + if avg_change < -50: + lines.append(f" Result: ✓ Dramatic memory reduction ({avg_change:.1f}%) - Dict optimization working!") + elif avg_change < 0: + lines.append(f" Result: ✓ Memory reduced ({avg_change:.1f}%)") + else: + lines.append(f" Result: ⚠ Memory increased ({avg_change:.1f}%) - unexpected!") + + lines.append("") + lines.append("=" * 100) + return "\n".join(lines) + + +class Reporter: + """Format and display benchmark results.""" + + @staticmethod + def format_text(results: Dict[str, Dict[str, Any]]) -> str: + """Format results as readable text.""" + lines = [] + lines.append("=" * 80) + lines.append("Pickle Unpickling Benchmark Results") + lines.append("=" * 80) + lines.append("") + + for size_key, tests in results.items(): + lines.append(f"\n{size_key} Test Results") + lines.append("-" * 80) + + for test_name, data in tests.items(): + lines.append(f"\n Test: {data['test_name']}") + lines.append(f" Type: {data['object_type']}") + lines.append(f" Pickle size: {data['pickle_size_mb']:.2f} MB") + lines.append(f" Time (mean): {data['time']['mean']*1000:.2f} ms") + lines.append(f" Time (stdev): {data['time']['stdev']*1000:.2f} ms") + lines.append(f" Peak memory: {data['memory_peak_mb']:.2f} MB") + lines.append(f" Protocol: {data['protocol']}") + + lines.append("\n" + "=" * 80) + return "\n".join(lines) + + @staticmethod + def format_markdown(results: Dict[str, Dict[str, Any]]) -> str: + """Format results as markdown table.""" + lines = [] + lines.append("# Pickle Unpickling Benchmark Results\n") + + for size_key, tests in results.items(): + lines.append(f"## {size_key}\n") + lines.append("| Test | Type | Pickle Size (MB) | Time (ms) | Stdev (ms) | Peak Memory (MB) |") + lines.append("|------|------|------------------|-----------|------------|------------------|") + + for test_name, data in tests.items(): + lines.append( + f"| {data['test_name']} | " + f"{data['object_type']} | " + f"{data['pickle_size_mb']:.2f} | " + f"{data['time']['mean']*1000:.2f} | " + f"{data['time']['stdev']*1000:.2f} | " + f"{data['memory_peak_mb']:.2f} |" + ) + lines.append("") + + return "\n".join(lines) + + @staticmethod + def format_json(results: Dict[str, Dict[str, Any]]) -> str: + """Format results as JSON.""" + import json + return json.dumps(results, indent=2) + + @staticmethod + def format_antagonistic(results: Dict[str, Dict[str, Any]]) -> str: + """Format antagonistic benchmark results.""" + lines = [] + lines.append("=" * 100) + lines.append("Antagonistic Pickle Benchmark (Memory DoS Protection Test)") + lines.append("=" * 100) + lines.append("") + lines.append("This benchmark tests TWO types of DoS protection:") + lines.append(" 1. Truncated data attacks → Expect FAILURE with minimal memory before failure") + lines.append(" 2. Sparse memo attacks → Expect SUCCESS with dict-based memo (vs huge array)") + lines.append("") + + # Sort size keys numerically + for size_key in sorted(results.keys(), key=_extract_size_mb): + tests = results[size_key] + + # Determine test type from first test + if tests: + first_test = next(iter(tests.values())) + expected_outcome = first_test.get('expected_outcome', 'failure') + claimed_mb = first_test.get('claimed_mb', 'N/A') + + # Header varies by test type + if "Sparse Memo" in size_key: + lines.append(f"\n{size_key}") + lines.append("-" * 100) + elif "Multi-Claim" in size_key: + lines.append(f"\n{size_key}") + lines.append("-" * 100) + elif claimed_mb != 'N/A': + lines.append(f"\n{size_key} Claimed (actual: 1KB) - Expect Failure") + lines.append("-" * 100) + else: + lines.append(f"\n{size_key}") + lines.append("-" * 100) + + for test_name, data in tests.items(): + peak_mb = data['peak_memory_mb'] + claimed = data.get('claimed_mb', 'N/A') + expected_outcome = data.get('expected_outcome', 'failure') + succeeded = data.get('succeeded', False) + baseline_note = data.get('baseline_note', '') + + lines.append(f" {data['test_name']}") + + # Format output based on test type + if expected_outcome == 'success': + # Sparse memo test - show success with dict + status_icon = "✓" if succeeded else "✗" + lines.append(f" Peak memory: {peak_mb:8.2f} MB {status_icon}") + lines.append(f" Status: {data['error_type']}") + if baseline_note: + lines.append(f" {baseline_note}") + else: + # Truncated data test - show savings before failure + if claimed != 'N/A': + saved_mb = claimed - peak_mb + savings_pct = (saved_mb / claimed * 100) if claimed > 0 else 0 + lines.append(f" Peak memory: {peak_mb:8.2f} MB (claimed: {claimed:,} MB, saved: {saved_mb:.2f} MB, {savings_pct:.1f}%)") + else: + lines.append(f" Peak memory: {peak_mb:8.2f} MB") + lines.append(f" Status: {data['error_type']}") + + lines.append("\n" + "=" * 100) + + # Calculate statistics by test type + truncated_claimed = 0 + truncated_peak = 0 + truncated_count = 0 + + sparse_peak_total = 0 + sparse_count = 0 + + for size_key, tests in results.items(): + for test_name, data in tests.items(): + expected_outcome = data.get('expected_outcome', 'failure') + + if expected_outcome == 'failure': + # Truncated data test + claimed = data.get('claimed_mb', 0) + if claimed != 'N/A' and claimed > 0: + truncated_claimed += claimed + truncated_peak += data['peak_memory_mb'] + truncated_count += 1 + else: + # Sparse memo test + sparse_peak_total += data['peak_memory_mb'] + sparse_count += 1 + + lines.append("\nSummary:") + lines.append("") + + if truncated_count > 0: + avg_claimed = truncated_claimed / truncated_count + avg_peak = truncated_peak / truncated_count + avg_saved = avg_claimed - avg_peak + avg_savings_pct = (avg_saved / avg_claimed * 100) if avg_claimed > 0 else 0 + + lines.append(" Truncated Data Protection (chunked reading):") + lines.append(f" Average claimed: {avg_claimed:,.1f} MB") + lines.append(f" Average peak: {avg_peak:,.2f} MB") + lines.append(f" Average saved: {avg_saved:,.2f} MB ({avg_savings_pct:.1f}% reduction)") + lines.append(f" Status: ✓ Fails fast with minimal memory") + lines.append("") + + if sparse_count > 0: + avg_sparse_peak = sparse_peak_total / sparse_count + lines.append(" Sparse Memo Protection (dict-based memo):") + lines.append(f" Average peak: {avg_sparse_peak:,.2f} MB") + lines.append(f" Status: ✓ Succeeds with dict (vs GB-sized arrays without PR)") + lines.append(f" Note: Compare with --baseline to see actual memory savings") + + lines.append("") + lines.append("=" * 100) + return "\n".join(lines) + + +def main(): + parser = argparse.ArgumentParser( + description="Benchmark pickle unpickling performance for large objects" + ) + parser.add_argument( + '--sizes', + type=int, + nargs='+', + default=None, + metavar='MiB', + help=f'Object sizes to test in MiB (default: {DEFAULT_SIZES_MIB})' + ) + parser.add_argument( + '--protocol', + type=int, + default=5, + choices=[0, 1, 2, 3, 4, 5], + help='Pickle protocol version (default: 5)' + ) + parser.add_argument( + '--iterations', + type=int, + default=3, + help='Number of benchmark iterations (default: 3)' + ) + parser.add_argument( + '--format', + choices=['text', 'markdown', 'json'], + default='text', + help='Output format (default: text)' + ) + parser.add_argument( + '--baseline', + type=str, + metavar='PYTHON', + help='Path to baseline Python interpreter for comparison (e.g., ../main-build/python)' + ) + parser.add_argument( + '--antagonistic', + action='store_true', + help='Run antagonistic/malicious pickle tests (DoS protection benchmark)' + ) + + args = parser.parse_args() + + # Handle antagonistic mode + if args.antagonistic: + # Antagonistic mode uses claimed sizes in MB, not actual data sizes + if args.sizes is None: + claimed_sizes_mb = AntagonisticTestSuite.DEFAULT_ANTAGONISTIC_SIZES_MB + else: + claimed_sizes_mb = args.sizes + + print(f"Running ANTAGONISTIC pickle benchmark (DoS protection test)...") + print(f"Claimed sizes: {claimed_sizes_mb} MiB (actual data: 1KB each)") + print(f"NOTE: These pickles will FAIL to unpickle (expected)") + print() + + # Run antagonistic benchmark suite + suite = AntagonisticTestSuite(claimed_sizes_mb) + results = suite.run_all_tests() + + # Format and display results + if args.baseline: + # Verify baseline Python exists + baseline_path = Path(args.baseline) + if not baseline_path.exists(): + print(f"Error: Baseline Python not found: {args.baseline}", file=sys.stderr) + return 1 + + # Run baseline benchmark + baseline_results = Comparator.run_baseline_benchmark(args.baseline, args) + + # Show comparison + comparison_output = Comparator.format_antagonistic_comparison(results, baseline_results) + print(comparison_output) + else: + # Format and display results + output = _format_output(results, args.format, is_antagonistic=True) + print(output) + + else: + # Normal mode: legitimate pickle benchmarks + # Convert sizes from MiB to bytes + if args.sizes is None: + sizes_bytes = DEFAULT_SIZES + else: + sizes_bytes = [size * (1 << 20) for size in args.sizes] + + print(f"Running pickle benchmark with protocol {args.protocol}...") + print(f"Test sizes: {[f'{s/(1<<20):.2f}MiB' for s in sizes_bytes]}") + print(f"Iterations per test: {args.iterations}") + print() + + # Run benchmark suite + suite = TestSuite(sizes_bytes, args.protocol, args.iterations) + results = suite.run_all_tests() + + # If baseline comparison requested, run baseline and compare + if args.baseline: + # Verify baseline Python exists + baseline_path = Path(args.baseline) + if not baseline_path.exists(): + print(f"Error: Baseline Python not found: {args.baseline}", file=sys.stderr) + return 1 + + # Run baseline benchmark + baseline_results = Comparator.run_baseline_benchmark(args.baseline, args) + + # Show comparison + comparison_output = Comparator.format_comparison(results, baseline_results) + print(comparison_output) + + else: + # Format and display results + output = _format_output(results, args.format, is_antagonistic=False) + print(output) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/Tools/pixi-packages/README.md b/Tools/pixi-packages/README.md new file mode 100644 index 00000000000..50c3315ac0e --- /dev/null +++ b/Tools/pixi-packages/README.md @@ -0,0 +1,36 @@ +# CPython Pixi packages + +This directory contains definitions for [Pixi packages](https://pixi.sh/latest/reference/pixi_manifest/#the-package-section) +which can be built from the CPython source code. + +Downstream developers can make use of these packages by adding them as Git dependencies in a +[Pixi workspace](https://pixi.sh/latest/first_workspace/), like: + +```toml +[dependencies] +python = { git = "https://github.com/python/cpython", subdirectory = "Tools/pixi-packages/asan" } +``` + +This is particularly useful when developers need to build CPython from source +(for example, for an ASan-instrumented build), as it does not require any manual +clone or build steps. Instead, Pixi will automatically handle both the build +and installation of the package. + +Each package definition is contained in a subdirectory, but they share the build script +`build.sh` in this directory. Currently defined package variants: + +- `default` +- `asan`: ASan-instrumented build with `PYTHON_ASAN=1` + +## Maintenance + +- Keep the `version` fields in each `recipe.yaml` up to date with the Python version +- Keep the dependency requirements up to date in each `recipe.yaml` +- Update `build.sh` for any breaking changes in the `configure` and `make` workflow + +## Opportunities for future improvement + +- More package variants (such as TSan, UBSan) +- Support for Windows +- Using a single `pixi.toml` and `recipe.yaml` for all package variants is blocked on https://github.com/prefix-dev/pixi/issues/4599 +- A workaround can be removed from the build script once https://github.com/prefix-dev/rattler-build/issues/2012 is resolved diff --git a/Tools/pixi-packages/asan/pixi.toml b/Tools/pixi-packages/asan/pixi.toml new file mode 100644 index 00000000000..001ff78fa5d --- /dev/null +++ b/Tools/pixi-packages/asan/pixi.toml @@ -0,0 +1,8 @@ +[workspace] +channels = ["https://prefix.dev/conda-forge"] +platforms = ["osx-arm64", "linux-64"] +preview = ["pixi-build"] + +[package.build.backend] +name = "pixi-build-rattler-build" +version = "*" diff --git a/Tools/pixi-packages/asan/recipe.yaml b/Tools/pixi-packages/asan/recipe.yaml new file mode 100644 index 00000000000..dea88394ad9 --- /dev/null +++ b/Tools/pixi-packages/asan/recipe.yaml @@ -0,0 +1,63 @@ +context: + # Keep up to date + version: "3.15" + +package: + name: python + version: ${{ version }} + +source: + - path: ../../.. + +build: + files: + exclude: + - "*.o" + script: + file: ../build.sh + env: + PYTHON_VARIANT: "asan" + +# derived from https://github.com/conda-forge/python-feedstock/blob/main/recipe/meta.yaml +requirements: + build: + - ${{ compiler('c') }} + - ${{ compiler('cxx') }} + - make + - pkg-config + # configure script looks for llvm-ar for lto + - if: osx + then: + - llvm-tools + - if: linux + then: + - ld_impl_${{ target_platform }} + - binutils_impl_${{ target_platform }} + - clang-19 + - llvm-tools-19 + + host: + - bzip2 + - sqlite + - liblzma-devel + - zlib + - zstd + - openssl + - readline + - tk + # These two are just to get the headers needed for tk.h, but is unused + - xorg-libx11 + - xorg-xorgproto + - ncurses + - libffi + - if: linux + then: + - ld_impl_${{ target_platform }} + - libuuid + - libmpdec-devel + - expat + +about: + homepage: https://www.python.org/ + license: Python-2.0 + license_file: LICENSE diff --git a/Tools/pixi-packages/build.sh b/Tools/pixi-packages/build.sh new file mode 100644 index 00000000000..120f1d6bb00 --- /dev/null +++ b/Tools/pixi-packages/build.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +if [[ "${PYTHON_VARIANT}" == "asan" ]]; then + echo "BUILD TYPE: ASAN" + BUILD_DIR="../build_asan" + CONFIGURE_EXTRA="--with-address-sanitizer" + export PYTHON_ASAN="1" + export ASAN_OPTIONS="strict_init_order=true" +else + echo "BUILD TYPE: DEFAULT" + BUILD_DIR="../build" + CONFIGURE_EXTRA="" +fi + +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +if [[ -f configure-done ]]; then + echo "Skipping configure step, already done." +else + "${SRC_DIR}/configure" \ + --prefix="${PREFIX}" \ + --oldincludedir="${BUILD_PREFIX}/${HOST}/sysroot/usr/include" \ + --enable-shared \ + --srcdir="${SRC_DIR}" \ + ${CONFIGURE_EXTRA} +fi + +touch configure-done + +make -j"${CPU_COUNT}" install +ln -sf "${PREFIX}/bin/python3" "${PREFIX}/bin/python" + +# https://github.com/prefix-dev/rattler-build/issues/2012 +if [[ ${OSTYPE} == "darwin"* ]]; then + cp "${BUILD_PREFIX}/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib" "${PREFIX}/lib/libclang_rt.asan_osx_dynamic.dylib" +fi diff --git a/Tools/pixi-packages/default/pixi.toml b/Tools/pixi-packages/default/pixi.toml new file mode 100644 index 00000000000..001ff78fa5d --- /dev/null +++ b/Tools/pixi-packages/default/pixi.toml @@ -0,0 +1,8 @@ +[workspace] +channels = ["https://prefix.dev/conda-forge"] +platforms = ["osx-arm64", "linux-64"] +preview = ["pixi-build"] + +[package.build.backend] +name = "pixi-build-rattler-build" +version = "*" diff --git a/Tools/pixi-packages/default/recipe.yaml b/Tools/pixi-packages/default/recipe.yaml new file mode 100644 index 00000000000..eeb4052ec38 --- /dev/null +++ b/Tools/pixi-packages/default/recipe.yaml @@ -0,0 +1,61 @@ +context: + # Keep up to date + version: "3.15" + +package: + name: python + version: ${{ version }} + +source: + - path: ../../.. + +build: + files: + exclude: + - "*.o" + script: + file: ../build.sh + +# derived from https://github.com/conda-forge/python-feedstock/blob/main/recipe/meta.yaml +requirements: + build: + - ${{ compiler('c') }} + - ${{ compiler('cxx') }} + - make + - pkg-config + # configure script looks for llvm-ar for lto + - if: osx + then: + - llvm-tools + - if: linux + then: + - ld_impl_${{ target_platform }} + - binutils_impl_${{ target_platform }} + - clang-19 + - llvm-tools-19 + + host: + - bzip2 + - sqlite + - liblzma-devel + - zlib + - zstd + - openssl + - readline + - tk + # These two are just to get the headers needed for tk.h, but is unused + - xorg-libx11 + - xorg-xorgproto + - ncurses + - libffi + - if: linux + then: + - ld_impl_${{ target_platform }} + - libuuid + - libmpdec-devel + - expat + +about: + homepage: https://www.python.org/ + license: Python-2.0 + license_file: LICENSE diff --git a/Tools/scripts/README b/Tools/scripts/README index a078bfbf662..4e52cda38e8 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -1,8 +1,6 @@ This directory contains a collection of executable Python scripts that are useful while building, extending or managing Python. -checkpip.py Checks the version of the projects bundled in ensurepip - are the latest available combinerefs.py A helper for analyzing PYTHONDUMPREFS output divmod_threshold.py Determine threshold for switching from longobject.c divmod to _pylong.int_divmod() diff --git a/Tools/scripts/checkpip.py b/Tools/scripts/checkpip.py deleted file mode 100755 index a4a9ddfa6f3..00000000000 --- a/Tools/scripts/checkpip.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3 -""" -Checks that the version of the projects bundled in ensurepip are the latest -versions available. -""" -import ensurepip -import json -import urllib.request -import sys - - -def main(): - outofdate = False - - for project, version in ensurepip._PROJECTS: - data = json.loads(urllib.request.urlopen( - "https://pypi.org/pypi/{}/json".format(project), - cadefault=True, - ).read().decode("utf8")) - upstream_version = data["info"]["version"] - - if version != upstream_version: - outofdate = True - print("The latest version of {} on PyPI is {}, but ensurepip " - "has {}".format(project, upstream_version, version)) - - if outofdate: - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index e632adafaaa..56976de4998 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -48,11 +48,11 @@ OPENSSL_OLD_VERSIONS = [ ] OPENSSL_RECENT_VERSIONS = [ - "3.0.16", - "3.2.5", - "3.3.4", - "3.4.2", - "3.5.2", + "3.0.18", + "3.2.6", + "3.3.5", + "3.4.3", + "3.5.4", # See make_ssl_data.py for notes on adding a new version. ] @@ -306,7 +306,7 @@ class AbstractBuilder(object): raise ValueError(member.name, base) member.name = member.name[len(base):].lstrip('/') log.info("Unpacking files to {}".format(self.build_dir)) - tf.extractall(self.build_dir, members) + tf.extractall(self.build_dir, members, filter='data') def _build_src(self, config_args=()): """Now build openssl""" diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 6bd31e8e6ec..46489f5cd9d 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -23,9 +23,6 @@ race_top:write_thread_id # gh-129068: race on shared range iterators (test_free_threading.test_zip.ZipThreading.test_threading) race_top:rangeiter_next -# gh-129748: test.test_free_threading.test_slots.TestSlots.test_object -race_top:mi_block_set_nextx - # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 thread:pthread_create @@ -41,7 +38,3 @@ race:list_inplace_repeat_lock_held # PyObject_Realloc internally does memcpy which isn't atomic so can race # with non-locking reads. See #132070 race:PyObject_Realloc - -# gh-133467. Some of these could be hard to trigger. -race_top:set_tp_bases -race_top:type_set_bases_unlocked diff --git a/Tools/tz/zdump.py b/Tools/tz/zdump.py deleted file mode 100644 index 39de0a416d0..00000000000 --- a/Tools/tz/zdump.py +++ /dev/null @@ -1,81 +0,0 @@ -import sys -import os -import struct -from array import array -from collections import namedtuple -from datetime import datetime - -ttinfo = namedtuple('ttinfo', ['tt_gmtoff', 'tt_isdst', 'tt_abbrind']) - -class TZInfo: - def __init__(self, transitions, type_indices, ttis, abbrs): - self.transitions = transitions - self.type_indices = type_indices - self.ttis = ttis - self.abbrs = abbrs - - @classmethod - def fromfile(cls, fileobj): - if fileobj.read(4).decode() != "TZif": - raise ValueError("not a zoneinfo file") - fileobj.seek(20) - header = fileobj.read(24) - tzh = (tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt, - tzh_timecnt, tzh_typecnt, tzh_charcnt) = struct.unpack(">6l", header) - transitions = array('i') - transitions.fromfile(fileobj, tzh_timecnt) - if sys.byteorder != 'big': - transitions.byteswap() - - type_indices = array('B') - type_indices.fromfile(fileobj, tzh_timecnt) - - ttis = [] - for i in range(tzh_typecnt): - ttis.append(ttinfo._make(struct.unpack(">lbb", fileobj.read(6)))) - - abbrs = fileobj.read(tzh_charcnt) - - self = cls(transitions, type_indices, ttis, abbrs) - self.tzh = tzh - - return self - - def dump(self, stream, start=None, end=None): - for j, (trans, i) in enumerate(zip(self.transitions, self.type_indices)): - utc = datetime.utcfromtimestamp(trans) - tti = self.ttis[i] - lmt = datetime.utcfromtimestamp(trans + tti.tt_gmtoff) - abbrind = tti.tt_abbrind - abbr = self.abbrs[abbrind:self.abbrs.find(0, abbrind)].decode() - if j > 0: - prev_tti = self.ttis[self.type_indices[j - 1]] - shift = " %+g" % ((tti.tt_gmtoff - prev_tti.tt_gmtoff) / 3600) - else: - shift = '' - print("%s UTC = %s %-5s isdst=%d" % (utc, lmt, abbr, tti[1]) + shift, file=stream) - - @classmethod - def zonelist(cls, zonedir='/usr/share/zoneinfo'): - zones = [] - for root, _, files in os.walk(zonedir): - for f in files: - p = os.path.join(root, f) - with open(p, 'rb') as o: - magic = o.read(4) - if magic == b'TZif': - zones.append(p[len(zonedir) + 1:]) - return zones - -if __name__ == '__main__': - if len(sys.argv) < 2: - zones = TZInfo.zonelist() - for z in zones: - print(z) - sys.exit() - filepath = sys.argv[1] - if not filepath.startswith('/'): - filepath = os.path.join('/usr/share/zoneinfo', filepath) - with open(filepath, 'rb') as fileobj: - tzi = TZInfo.fromfile(fileobj) - tzi.dump(sys.stdout) diff --git a/Tools/unicode/makeunicodedata.py b/Tools/unicode/makeunicodedata.py index d4cca68c3e3..ddd564deffd 100644 --- a/Tools/unicode/makeunicodedata.py +++ b/Tools/unicode/makeunicodedata.py @@ -44,7 +44,7 @@ VERSION = "3.3" # * Doc/library/stdtypes.rst, and # * Doc/library/unicodedata.rst # * Doc/reference/lexical_analysis.rst (three occurrences) -UNIDATA_VERSION = "16.0.0" +UNIDATA_VERSION = "17.0.0" UNICODE_DATA = "UnicodeData%s.txt" COMPOSITION_EXCLUSIONS = "CompositionExclusions%s.txt" EASTASIAN_WIDTH = "EastAsianWidth%s.txt" @@ -104,13 +104,14 @@ cjk_ranges = [ ('3400', '4DBF'), # CJK Ideograph Extension A CJK ('4E00', '9FFF'), # CJK Ideograph ('20000', '2A6DF'), # CJK Ideograph Extension B - ('2A700', '2B739'), # CJK Ideograph Extension C + ('2A700', '2B73F'), # CJK Ideograph Extension C ('2B740', '2B81D'), # CJK Ideograph Extension D - ('2B820', '2CEA1'), # CJK Ideograph Extension E + ('2B820', '2CEAD'), # CJK Ideograph Extension E ('2CEB0', '2EBE0'), # CJK Ideograph Extension F ('2EBF0', '2EE5D'), # CJK Ideograph Extension I ('30000', '3134A'), # CJK Ideograph Extension G ('31350', '323AF'), # CJK Ideograph Extension H + ('323B0', '33479'), # CJK Ideograph Extension J ] diff --git a/Tools/wasm/.ruff.toml b/Tools/wasm/.ruff.toml new file mode 100644 index 00000000000..3d8e59fa3f2 --- /dev/null +++ b/Tools/wasm/.ruff.toml @@ -0,0 +1,25 @@ +extend = "../../.ruff.toml" # Inherit the project-wide settings + +[format] +preview = true +docstring-code-format = true + +[lint] +select = [ + "C4", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "ISC", # flake8-implicit-str-concat + "LOG", # flake8-logging + "PGH", # pygrep-hooks + "PT", # flake8-pytest-style + "PYI", # flake8-pyi + "RUF100", # Ban unused `# noqa` comments + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 +] +ignore = [ + "E501", # Line too long +] diff --git a/Tools/wasm/README.md b/Tools/wasm/README.md index efe9a3550c3..35685db07b1 100644 --- a/Tools/wasm/README.md +++ b/Tools/wasm/README.md @@ -9,68 +9,14 @@ compilation of CPython to WebAssembly (WASM). Python supports Emscripten run in modern browsers and JavaScript runtimes like *Node.js*. WASI builds use WASM runtimes such as *wasmtime*. -Users and developers are encouraged to use the script -`Tools/wasm/wasm_build.py`. The tool automates the build process and provides -assistance with installation of SDKs, running tests, etc. +**NOTE**: If you are looking for general information about WebAssembly that is +not directly related to CPython, please see https://github.com/psf/webassembly. -**NOTE**: If you are looking for information that is not directly related to -building CPython for WebAssembly (or the resulting build), please see -https://github.com/psf/webassembly for more information. - -## wasm32-emscripten +## Emscripten (wasm32-emscripten) ### Build -To cross compile to the ``wasm32-emscripten`` platform you need -[the Emscripten compiler toolchain](https://emscripten.org/), -a Python interpreter, and an installation of Node version 18 or newer. -Emscripten version 4.0.2 is recommended; newer versions may also work, but all -official testing is performed with that version. All commands below are relative -to a checkout of the Python repository. - -#### Install [the Emscripten compiler toolchain](https://emscripten.org/docs/getting_started/downloads.html) - -You can install the Emscripten toolchain as follows: -```shell -git clone https://github.com/emscripten-core/emsdk.git --depth 1 -./emsdk/emsdk install latest -./emsdk/emsdk activate latest -``` -To add the Emscripten compiler to your path: -```shell -source ./emsdk/emsdk_env.sh -``` -This adds `emcc` and `emconfigure` to your path. - -##### Optionally: enable ccache for EMSDK - -The ``EM_COMPILER_WRAPPER`` must be set after the EMSDK environment is -sourced. Otherwise the source script removes the environment variable. - -```shell -export EM_COMPILER_WRAPPER=ccache -``` - -#### Compile and build Python interpreter - -You can use `python Tools/wasm/emscripten` to compile and build targeting -Emscripten. You can do everything at once with: -```shell -python Tools/wasm/emscripten build -``` -or you can break it out into four separate steps: -```shell -python Tools/wasm/emscripten configure-build-python -python Tools/wasm/emscripten make-build-python -python Tools/wasm/emscripten make-libffi -python Tools/wasm/emscripten configure-host -python Tools/wasm/emscripten make-host -``` -Extra arguments to the configure steps are passed along to configure. For -instance, to do a debug build, you can use: -```shell -python Tools/wasm/emscripten build --with-py-debug -``` +See [the devguide instructions for building for Emscripten](https://devguide.python.org/getting-started/setup-building/#emscripten). ### Running from node @@ -97,8 +43,8 @@ You can run the browser smoke test with: ### The Web Example -When building for Emscripten, the web example will be built automatically. It -is in the ``web_example`` directory. To run the web example, ``cd`` into the +When building for Emscripten, a small web example will be built automatically +in the ``web_example`` directory. To run the web example, ``cd`` into the ``web_example`` directory, then run ``python server.py``. This will start a web server; you can then visit ``http://localhost:8000/`` in a browser to see a simple REPL example. @@ -226,8 +172,8 @@ await createEmscriptenModule({ e.g. ``ctypes``, ``readline``, ``ssl``, and more. - Shared extension modules are not implemented yet. All extension modules are statically linked into the main binary. The experimental configure - option ``--enable-wasm-dynamic-linking`` enables dynamic extensions - supports. It's currently known to crash in combination with threading. + option ``--enable-wasm-dynamic-linking`` enables dynamic extension + support. It's currently known to crash in combination with threading. - glibc extensions for date and time formatting are not available. - ``locales`` module is affected by musl libc issues, [gh-90548](https://github.com/python/cpython/issues/90548). diff --git a/Tools/wasm/emscripten/__main__.py b/Tools/wasm/emscripten/__main__.py index 202dd298199..c88e9edba6d 100644 --- a/Tools/wasm/emscripten/__main__.py +++ b/Tools/wasm/emscripten/__main__.py @@ -3,16 +3,16 @@ import argparse import contextlib import functools +import hashlib import os import shutil import subprocess import sys import sysconfig -import hashlib import tempfile -from urllib.request import urlopen from pathlib import Path from textwrap import dedent +from urllib.request import urlopen try: from os import process_cpu_count as cpu_count @@ -33,7 +33,7 @@ HOST_DIR = HOST_BUILD_DIR / "python" PREFIX_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "prefix" LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" -LOCAL_SETUP_MARKER = "# Generated by Tools/wasm/emscripten.py\n".encode("utf-8") +LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/emscripten.py\n" def updated_env(updates={}): @@ -45,7 +45,9 @@ def updated_env(updates={}): # https://reproducible-builds.org/docs/source-date-epoch/ git_epoch_cmd = ["git", "log", "-1", "--pretty=%ct"] try: - epoch = subprocess.check_output(git_epoch_cmd, encoding="utf-8").strip() + epoch = subprocess.check_output( + git_epoch_cmd, encoding="utf-8" + ).strip() env_defaults["SOURCE_DATE_EPOCH"] = epoch except subprocess.CalledProcessError: pass # Might be building from a tarball. @@ -79,7 +81,11 @@ def subdir(working_dir, *, clean_ok=False): terminal_width = 80 print("⎯" * terminal_width) print("📁", working_dir) - if clean_ok and getattr(context, "clean", False) and working_dir.exists(): + if ( + clean_ok + and getattr(context, "clean", False) + and working_dir.exists() + ): print("🚮 Deleting directory (--clean)...") shutil.rmtree(working_dir) @@ -128,7 +134,9 @@ def build_python_path(): if not binary.is_file(): binary = binary.with_suffix(".exe") if not binary.is_file(): - raise FileNotFoundError("Unable to find `python(.exe)` in " f"{NATIVE_BUILD_DIR}") + raise FileNotFoundError( + f"Unable to find `python(.exe)` in {NATIVE_BUILD_DIR}" + ) return binary @@ -158,7 +166,8 @@ def make_build_python(context, working_dir): cmd = [ binary, "-c", - "import sys; " "print(f'{sys.version_info.major}.{sys.version_info.minor}')", + "import sys; " + "print(f'{sys.version_info.major}.{sys.version_info.minor}')", ] version = subprocess.check_output(cmd, encoding="utf-8").strip() @@ -173,7 +182,9 @@ def check_shasum(file: str, expected_shasum: str): def download_and_unpack(working_dir: Path, url: str, expected_shasum: str): - with tempfile.NamedTemporaryFile(suffix=".tar.gz", delete_on_close=False) as tmp_file: + with tempfile.NamedTemporaryFile( + suffix=".tar.gz", delete_on_close=False + ) as tmp_file: with urlopen(url) as response: shutil.copyfileobj(response, tmp_file) tmp_file.close() @@ -186,7 +197,11 @@ def make_emscripten_libffi(context, working_dir): ver = "3.4.6" libffi_dir = working_dir / f"libffi-{ver}" shutil.rmtree(libffi_dir, ignore_errors=True) - download_and_unpack(working_dir, f"https://github.com/libffi/libffi/releases/download/v{ver}/libffi-{ver}.tar.gz", "b0dea9df23c863a7a50e825440f3ebffabd65df1497108e5d437747843895a4e") + download_and_unpack( + working_dir, + f"https://github.com/libffi/libffi/releases/download/v{ver}/libffi-{ver}.tar.gz", + "b0dea9df23c863a7a50e825440f3ebffabd65df1497108e5d437747843895a4e", + ) call( [EMSCRIPTEN_DIR / "make_libffi.sh"], env=updated_env({"PREFIX": PREFIX_DIR}), @@ -200,7 +215,11 @@ def make_mpdec(context, working_dir): ver = "4.0.1" mpdec_dir = working_dir / f"mpdecimal-{ver}" shutil.rmtree(mpdec_dir, ignore_errors=True) - download_and_unpack(working_dir, f"https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-{ver}.tar.gz", "96d33abb4bb0070c7be0fed4246cd38416188325f820468214471938545b1ac8") + download_and_unpack( + working_dir, + f"https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-{ver}.tar.gz", + "96d33abb4bb0070c7be0fed4246cd38416188325f820468214471938545b1ac8", + ) call( [ "emconfigure", @@ -214,10 +233,7 @@ def make_mpdec(context, working_dir): quiet=context.quiet, ) call( - [ - "make", - "install" - ], + ["make", "install"], cwd=mpdec_dir, quiet=context.quiet, ) @@ -226,17 +242,15 @@ def make_mpdec(context, working_dir): @subdir(HOST_DIR, clean_ok=True) def configure_emscripten_python(context, working_dir): """Configure the emscripten/host build.""" - config_site = os.fsdecode( - EMSCRIPTEN_DIR / "config.site-wasm32-emscripten" - ) + config_site = os.fsdecode(EMSCRIPTEN_DIR / "config.site-wasm32-emscripten") emscripten_build_dir = working_dir.relative_to(CHECKOUT) python_build_dir = NATIVE_BUILD_DIR / "build" lib_dirs = list(python_build_dir.glob("lib.*")) - assert ( - len(lib_dirs) == 1 - ), f"Expected a single lib.* directory in {python_build_dir}" + assert len(lib_dirs) == 1, ( + f"Expected a single lib.* directory in {python_build_dir}" + ) lib_dir = os.fsdecode(lib_dirs[0]) pydebug = lib_dir.endswith("-pydebug") python_version = lib_dir.removesuffix("-pydebug").rpartition("-")[-1] @@ -290,7 +304,9 @@ def configure_emscripten_python(context, working_dir): quiet=context.quiet, ) - shutil.copy(EMSCRIPTEN_DIR / "node_entry.mjs", working_dir / "node_entry.mjs") + shutil.copy( + EMSCRIPTEN_DIR / "node_entry.mjs", working_dir / "node_entry.mjs" + ) node_entry = working_dir / "node_entry.mjs" exec_script = working_dir / "python.sh" @@ -383,13 +399,15 @@ def main(): subcommands = parser.add_subparsers(dest="subcommand") build = subcommands.add_parser("build", help="Build everything") configure_build = subcommands.add_parser( - "configure-build-python", help="Run `configure` for the " "build Python" + "configure-build-python", help="Run `configure` for the build Python" ) make_mpdec_cmd = subcommands.add_parser( - "make-mpdec", help="Clone mpdec repo, configure and build it for emscripten" + "make-mpdec", + help="Clone mpdec repo, configure and build it for emscripten", ) make_libffi_cmd = subcommands.add_parser( - "make-libffi", help="Clone libffi repo, configure and build it for emscripten" + "make-libffi", + help="Clone libffi repo, configure and build it for emscripten", ) make_build = subcommands.add_parser( "make-build-python", help="Run `make` for the build Python" @@ -412,6 +430,7 @@ def main(): make_build, configure_host, make_host, + clean, ): subcommand.add_argument( "--quiet", @@ -457,7 +476,11 @@ def main(): if not context.subcommand: # No command provided, display help and exit - print("Expected one of", ", ".join(sorted(dispatch.keys())), file=sys.stderr) + print( + "Expected one of", + ", ".join(sorted(dispatch.keys())), + file=sys.stderr, + ) parser.print_help(sys.stderr) sys.exit(1) dispatch[context.subcommand](context) diff --git a/Tools/wasm/emscripten/prepare_external_wasm.py b/Tools/wasm/emscripten/prepare_external_wasm.py new file mode 100644 index 00000000000..1b0a9de4b1f --- /dev/null +++ b/Tools/wasm/emscripten/prepare_external_wasm.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import argparse +import sys +from pathlib import Path + +JS_TEMPLATE = """ +#include "emscripten.h" + +EM_JS(void, {function_name}, (void), {{ + return new WebAssembly.Module(hexStringToUTF8Array("{hex_string}")); +}} +function hexStringToUTF8Array(hex) {{ + const bytes = []; + for (let i = 0; i < hex.length; i += 2) {{ + bytes.push(parseInt(hex.substr(i, 2), 16)); + }} + return new Uint8Array(bytes); +}}); +""" + + +def prepare_wasm(input_file, output_file, function_name): + # Read the compiled WASM as binary and convert to hex + wasm_bytes = Path(input_file).read_bytes() + + hex_string = "".join(f"{byte:02x}" for byte in wasm_bytes) + + # Generate JavaScript module + js_content = JS_TEMPLATE.format( + function_name=function_name, hex_string=hex_string + ) + Path(output_file).write_text(js_content) + + print(f"Successfully compiled {input_file} and generated {output_file}") + return 0 + + +def main(): + parser = argparse.ArgumentParser( + description="Compile WebAssembly text files using wasm-as" + ) + parser.add_argument("input_file", help="Input .wat file to compile") + parser.add_argument("output_file", help="Output file name") + parser.add_argument("function_name", help="Name of the export function") + + args = parser.parse_args() + + return prepare_wasm(args.input_file, args.output_file, args.function_name) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Tools/wasm/emscripten/wasm_assets.py b/Tools/wasm/emscripten/wasm_assets.py index b08e7ce1114..38479087235 100755 --- a/Tools/wasm/emscripten/wasm_assets.py +++ b/Tools/wasm/emscripten/wasm_assets.py @@ -15,7 +15,6 @@ import pathlib import sys import sysconfig import zipfile -from typing import Dict # source directory SRCDIR = pathlib.Path(__file__).parents[3].absolute() @@ -27,7 +26,9 @@ WASM_LIB = pathlib.PurePath("lib") WASM_STDLIB_ZIP = ( WASM_LIB / f"python{sys.version_info.major}{sys.version_info.minor}.zip" ) -WASM_STDLIB = WASM_LIB / f"python{sys.version_info.major}.{sys.version_info.minor}" +WASM_STDLIB = ( + WASM_LIB / f"python{sys.version_info.major}.{sys.version_info.minor}" +) WASM_DYNLOAD = WASM_STDLIB / "lib-dynload" @@ -58,7 +59,6 @@ OMIT_FILES = ( # socket.create_connection() raises an exception: # "BlockingIOError: [Errno 26] Operation in progress". OMIT_NETWORKING_FILES = ( - "email/", "ftplib.py", "http/", "imaplib.py", @@ -133,7 +133,7 @@ def create_stdlib_zip( pzf.writepy(entry, filterfunc=filterfunc) -def detect_extension_modules(args: argparse.Namespace) -> Dict[str, bool]: +def detect_extension_modules(args: argparse.Namespace) -> dict[str, bool]: modules = {} # disabled by Modules/Setup.local ? @@ -148,7 +148,7 @@ def detect_extension_modules(args: argparse.Namespace) -> Dict[str, bool]: # disabled by configure? with open(args.sysconfig_data) as f: data = f.read() - loc: Dict[str, Dict[str, str]] = {} + loc: dict[str, dict[str, str]] = {} exec(data, globals(), loc) for key, value in loc["build_time_vars"].items(): diff --git a/Tools/wasm/emscripten/web_example/server.py b/Tools/wasm/emscripten/web_example/server.py index 768e6f84e07..f2e6ed56c6b 100755 --- a/Tools/wasm/emscripten/web_example/server.py +++ b/Tools/wasm/emscripten/web_example/server.py @@ -6,10 +6,16 @@ parser = argparse.ArgumentParser( description="Start a local webserver with a Python terminal." ) parser.add_argument( - "--port", type=int, default=8000, help="port for the http server to listen on" + "--port", + type=int, + default=8000, + help="port for the http server to listen on", ) parser.add_argument( - "--bind", type=str, default="127.0.0.1", help="Bind address (empty for all)" + "--bind", + type=str, + default="127.0.0.1", + help="Bind address (empty for all)", ) diff --git a/Tools/wasm/wasi.py b/Tools/wasm/wasi.py index b49b27cbbbe..af55e03d10f 100644 --- a/Tools/wasm/wasi.py +++ b/Tools/wasm/wasi.py @@ -1,10 +1,12 @@ -if __name__ == "__main__": +if __name__ == "__main__": import pathlib import runpy import sys - print("⚠️ WARNING: This script is deprecated and slated for removal in Python 3.20; " - "execute the `wasi/` directory instead (i.e. `python Tools/wasm/wasi`)\n", - file=sys.stderr) + print( + "⚠️ WARNING: This script is deprecated and slated for removal in Python 3.20; " + "execute the `wasi/` directory instead (i.e. `python Tools/wasm/wasi`)\n", + file=sys.stderr, + ) runpy.run_path(pathlib.Path(__file__).parent / "wasi", run_name="__main__") diff --git a/Tools/wasm/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index 973d78caa08..3d9a2472d4d 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -4,6 +4,9 @@ import argparse import contextlib import functools import os + +import tomllib + try: from os import process_cpu_count as cpu_count except ImportError: @@ -15,24 +18,54 @@ import sys import sysconfig import tempfile +HERE = pathlib.Path(__file__).parent -CHECKOUT = pathlib.Path(__file__).parent.parent.parent.parent -assert (CHECKOUT / "configure").is_file(), "Please update the location of the file" +# Path is: cpython/Tools/wasm/wasi +CHECKOUT = HERE.parent.parent.parent +assert (CHECKOUT / "configure").is_file(), ( + "Please update the location of the file" +) CROSS_BUILD_DIR = CHECKOUT / "cross-build" # Build platform can also be found via `config.guess`. BUILD_DIR = CROSS_BUILD_DIR / sysconfig.get_config_var("BUILD_GNU_TYPE") LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" -LOCAL_SETUP_MARKER = ("# Generated by Tools/wasm/wasi .\n" - "# Required to statically build extension modules.").encode("utf-8") +LOCAL_SETUP_MARKER = ( + b"# Generated by Tools/wasm/wasi .\n" + b"# Required to statically build extension modules." +) -WASI_SDK_VERSION = 24 +WASI_SDK_VERSION = 29 WASMTIME_VAR_NAME = "WASMTIME" WASMTIME_HOST_RUNNER_VAR = f"{{{WASMTIME_VAR_NAME}}}" +def separator(): + """Print a separator line across the terminal width.""" + try: + tput_output = subprocess.check_output( + ["tput", "cols"], encoding="utf-8" + ) + except subprocess.CalledProcessError: + terminal_width = 80 + else: + terminal_width = int(tput_output.strip()) + print("⎯" * terminal_width) + + +def log(emoji, message, *, spacing=None): + """Print a notification with an emoji. + + If 'spacing' is None, calculate the spacing based on the number of code points + in the emoji as terminals "eat" a space when the emoji has multiple code points. + """ + if spacing is None: + spacing = " " if len(emoji) == 1 else " " + print("".join([emoji, spacing, message])) + + def updated_env(updates={}): """Create a new dict representing the environment to use. @@ -42,7 +75,9 @@ def updated_env(updates={}): # https://reproducible-builds.org/docs/source-date-epoch/ git_epoch_cmd = ["git", "log", "-1", "--pretty=%ct"] try: - epoch = subprocess.check_output(git_epoch_cmd, encoding="utf-8").strip() + epoch = subprocess.check_output( + git_epoch_cmd, encoding="utf-8" + ).strip() env_defaults["SOURCE_DATE_EPOCH"] = epoch except subprocess.CalledProcessError: pass # Might be building from a tarball. @@ -54,15 +89,17 @@ def updated_env(updates={}): if os.environ.get(key) != value: env_diff[key] = value - print("🌎 Environment changes:") - for key in sorted(env_diff.keys()): - print(f" {key}={env_diff[key]}") + env_vars = ( + f"\n {key}={item}" for key, item in sorted(env_diff.items()) + ) + log("🌎", f"Environment changes:{''.join(env_vars)}") return environment def subdir(working_dir, *, clean_ok=False): """Decorator to change to a working directory.""" + def decorator(func): @functools.wraps(func) def wrapper(context): @@ -70,18 +107,14 @@ def subdir(working_dir, *, clean_ok=False): if callable(working_dir): working_dir = working_dir(context) - try: - tput_output = subprocess.check_output(["tput", "cols"], - encoding="utf-8") - except subprocess.CalledProcessError: - terminal_width = 80 - else: - terminal_width = int(tput_output.strip()) - print("⎯" * terminal_width) - print("📁", working_dir) - if (clean_ok and getattr(context, "clean", False) and - working_dir.exists()): - print("🚮 Deleting directory (--clean)...") + separator() + log("📁", os.fsdecode(working_dir)) + if ( + clean_ok + and getattr(context, "clean", False) + and working_dir.exists() + ): + log("🚮", "Deleting directory (--clean)...") shutil.rmtree(working_dir) working_dir.mkdir(parents=True, exist_ok=True) @@ -105,18 +138,21 @@ def call(command, *, context=None, quiet=False, logdir=None, **kwargs): elif quiet and logdir is None: raise ValueError("When quiet is True, logdir must be specified") - print("❯", " ".join(map(str, command))) + log("❯", " ".join(map(str, command)), spacing=" ") if not quiet: stdout = None stderr = None else: - stdout = tempfile.NamedTemporaryFile("w", encoding="utf-8", - delete=False, - dir=logdir, - prefix="cpython-wasi-", - suffix=".log") + stdout = tempfile.NamedTemporaryFile( + "w", + encoding="utf-8", + delete=False, + dir=logdir, + prefix="cpython-wasi-", + suffix=".log", + ) stderr = subprocess.STDOUT - print(f"📝 Logging output to {stdout.name} (--quiet)...") + log("📝", f"Logging output to {stdout.name} (--quiet)...") subprocess.check_call(command, **kwargs, stdout=stdout, stderr=stderr) @@ -127,8 +163,9 @@ def build_python_path(): if not binary.is_file(): binary = binary.with_suffix(".exe") if not binary.is_file(): - raise FileNotFoundError("Unable to find `python(.exe)` in " - f"{BUILD_DIR}") + raise FileNotFoundError( + f"Unable to find `python(.exe)` in {BUILD_DIR}" + ) return binary @@ -136,9 +173,10 @@ def build_python_path(): def build_python_is_pydebug(): """Find out if the build Python is a pydebug build.""" test = "import sys, test.support; sys.exit(test.support.Py_DEBUG)" - result = subprocess.run([build_python_path(), "-c", test], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + result = subprocess.run( + [build_python_path(), "-c", test], + capture_output=True, + ) return bool(result.returncode) @@ -147,14 +185,14 @@ def configure_build_python(context, working_dir): """Configure the build/host Python.""" if LOCAL_SETUP.exists(): if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: - print(f"👍 {LOCAL_SETUP} exists ...") + log("👍", f"{LOCAL_SETUP} exists ...") else: - print(f"⚠️ {LOCAL_SETUP} exists, but has unexpected contents") + log("⚠️", f"{LOCAL_SETUP} exists, but has unexpected contents") else: - print(f"📝 Creating {LOCAL_SETUP} ...") + log("📝", f"Creating {LOCAL_SETUP} ...") LOCAL_SETUP.write_bytes(LOCAL_SETUP_MARKER) - configure = [os.path.relpath(CHECKOUT / 'configure', working_dir)] + configure = [os.path.relpath(CHECKOUT / "configure", working_dir)] if context.args: configure.extend(context.args) @@ -164,64 +202,99 @@ def configure_build_python(context, working_dir): @subdir(BUILD_DIR) def make_build_python(context, working_dir): """Make/build the build Python.""" - call(["make", "--jobs", str(cpu_count()), "all"], - context=context) + call(["make", "--jobs", str(cpu_count()), "all"], context=context) binary = build_python_path() - cmd = [binary, "-c", - "import sys; " - "print(f'{sys.version_info.major}.{sys.version_info.minor}')"] + cmd = [ + binary, + "-c", + "import sys; " + "print(f'{sys.version_info.major}.{sys.version_info.minor}')", + ] version = subprocess.check_output(cmd, encoding="utf-8").strip() - print(f"🎉 {binary} {version}") + log("🎉", f"{binary} {version}") -def find_wasi_sdk(): +def find_wasi_sdk(config): """Find the path to the WASI SDK.""" - if wasi_sdk_path := os.environ.get("WASI_SDK_PATH"): - return pathlib.Path(wasi_sdk_path) + wasi_sdk_path = None + wasi_sdk_version = config["targets"]["wasi-sdk"] - opt_path = pathlib.Path("/opt") - # WASI SDK versions have a ``.0`` suffix, but it's a constant; the WASI SDK team - # has said they don't plan to ever do a point release and all of their Git tags - # lack the ``.0`` suffix. - # Starting with WASI SDK 23, the tarballs went from containing a directory named - # ``wasi-sdk-{WASI_SDK_VERSION}.0`` to e.g. - # ``wasi-sdk-{WASI_SDK_VERSION}.0-x86_64-linux``. - potential_sdks = [path for path in opt_path.glob(f"wasi-sdk-{WASI_SDK_VERSION}.0*") - if path.is_dir()] - if len(potential_sdks) == 1: - return potential_sdks[0] - elif (default_path := opt_path / "wasi-sdk").is_dir(): - return default_path + if wasi_sdk_path_env_var := os.environ.get("WASI_SDK_PATH"): + wasi_sdk_path = pathlib.Path(wasi_sdk_path_env_var) + else: + opt_path = pathlib.Path("/opt") + # WASI SDK versions have a ``.0`` suffix, but it's a constant; the WASI SDK team + # has said they don't plan to ever do a point release and all of their Git tags + # lack the ``.0`` suffix. + # Starting with WASI SDK 23, the tarballs went from containing a directory named + # ``wasi-sdk-{WASI_SDK_VERSION}.0`` to e.g. + # ``wasi-sdk-{WASI_SDK_VERSION}.0-x86_64-linux``. + potential_sdks = [ + path + for path in opt_path.glob(f"wasi-sdk-{wasi_sdk_version}.0*") + if path.is_dir() + ] + if len(potential_sdks) == 1: + wasi_sdk_path = potential_sdks[0] + elif (default_path := opt_path / "wasi-sdk").is_dir(): + wasi_sdk_path = default_path + + # Starting with WASI SDK 25, a VERSION file is included in the root + # of the SDK directory that we can read to warn folks when they are using + # an unsupported version. + if wasi_sdk_path and (version_file := wasi_sdk_path / "VERSION").is_file(): + version_details = version_file.read_text(encoding="utf-8") + found_version = version_details.splitlines()[0] + # Make sure there's a trailing dot to avoid false positives if somehow the + # supported version is a prefix of the found version (e.g. `25` and `2567`). + if not found_version.startswith(f"{wasi_sdk_version}."): + major_version = found_version.partition(".")[0] + log( + "⚠️", + f" Found WASI SDK {major_version}, " + f"but WASI SDK {wasi_sdk_version} is the supported version", + ) + + return wasi_sdk_path def wasi_sdk_env(context): """Calculate environment variables for building with wasi-sdk.""" wasi_sdk_path = context.wasi_sdk_path sysroot = wasi_sdk_path / "share" / "wasi-sysroot" - env = {"CC": "clang", "CPP": "clang-cpp", "CXX": "clang++", - "AR": "llvm-ar", "RANLIB": "ranlib"} + env = { + "CC": "clang", + "CPP": "clang-cpp", + "CXX": "clang++", + "AR": "llvm-ar", + "RANLIB": "ranlib", + } for env_var, binary_name in list(env.items()): env[env_var] = os.fsdecode(wasi_sdk_path / "bin" / binary_name) - if wasi_sdk_path != pathlib.Path("/opt/wasi-sdk"): + if not wasi_sdk_path.name.startswith("wasi-sdk"): for compiler in ["CC", "CPP", "CXX"]: env[compiler] += f" --sysroot={sysroot}" env["PKG_CONFIG_PATH"] = "" env["PKG_CONFIG_LIBDIR"] = os.pathsep.join( - map(os.fsdecode, - [sysroot / "lib" / "pkgconfig", - sysroot / "share" / "pkgconfig"])) + map( + os.fsdecode, + [sysroot / "lib" / "pkgconfig", sysroot / "share" / "pkgconfig"], + ) + ) env["PKG_CONFIG_SYSROOT_DIR"] = os.fsdecode(sysroot) env["WASI_SDK_PATH"] = os.fsdecode(wasi_sdk_path) env["WASI_SYSROOT"] = os.fsdecode(sysroot) - env["PATH"] = os.pathsep.join([os.fsdecode(wasi_sdk_path / "bin"), - os.environ["PATH"]]) + env["PATH"] = os.pathsep.join([ + os.fsdecode(wasi_sdk_path / "bin"), + os.environ["PATH"], + ]) return env @@ -230,170 +303,252 @@ def wasi_sdk_env(context): def configure_wasi_python(context, working_dir): """Configure the WASI/host build.""" if not context.wasi_sdk_path or not context.wasi_sdk_path.exists(): - raise ValueError("WASI-SDK not found; " - "download from " - "https://github.com/WebAssembly/wasi-sdk and/or " - "specify via $WASI_SDK_PATH or --wasi-sdk") + raise ValueError( + "WASI-SDK not found; " + "download from " + "https://github.com/WebAssembly/wasi-sdk and/or " + "specify via $WASI_SDK_PATH or --wasi-sdk" + ) - config_site = os.fsdecode(CHECKOUT / "Tools" / "wasm" / "wasi" / "config.site-wasm32-wasi") + config_site = os.fsdecode(HERE / "config.site-wasm32-wasi") wasi_build_dir = working_dir.relative_to(CHECKOUT) python_build_dir = BUILD_DIR / "build" lib_dirs = list(python_build_dir.glob("lib.*")) - assert len(lib_dirs) == 1, f"Expected a single lib.* directory in {python_build_dir}" + assert len(lib_dirs) == 1, ( + f"Expected a single lib.* directory in {python_build_dir}" + ) lib_dir = os.fsdecode(lib_dirs[0]) python_version = lib_dir.rpartition("-")[-1] - sysconfig_data_dir = f"{wasi_build_dir}/build/lib.wasi-wasm32-{python_version}" + sysconfig_data_dir = ( + f"{wasi_build_dir}/build/lib.wasi-wasm32-{python_version}" + ) # Use PYTHONPATH to include sysconfig data which must be anchored to the # WASI guest's `/` directory. - args = {"GUEST_DIR": "/", - "HOST_DIR": CHECKOUT, - "ENV_VAR_NAME": "PYTHONPATH", - "ENV_VAR_VALUE": f"/{sysconfig_data_dir}", - "PYTHON_WASM": working_dir / "python.wasm"} + args = { + "PYTHONPATH": f"/{sysconfig_data_dir}", + "PYTHON_WASM": working_dir / "python.wasm", + } # Check dynamically for wasmtime in case it was specified manually via # `--host-runner`. if WASMTIME_HOST_RUNNER_VAR in context.host_runner: if wasmtime := shutil.which("wasmtime"): args[WASMTIME_VAR_NAME] = wasmtime else: - raise FileNotFoundError("wasmtime not found; download from " - "https://github.com/bytecodealliance/wasmtime") + raise FileNotFoundError( + "wasmtime not found; download from " + "https://github.com/bytecodealliance/wasmtime" + ) host_runner = context.host_runner.format_map(args) env_additions = {"CONFIG_SITE": config_site, "HOSTRUNNER": host_runner} build_python = os.fsdecode(build_python_path()) # The path to `configure` MUST be relative, else `python.wasm` is unable # to find the stdlib due to Python not recognizing that it's being # executed from within a checkout. - configure = [os.path.relpath(CHECKOUT / 'configure', working_dir), - f"--host={context.host_triple}", - f"--build={BUILD_DIR.name}", - f"--with-build-python={build_python}"] + configure = [ + os.path.relpath(CHECKOUT / "configure", working_dir), + f"--host={context.host_triple}", + f"--build={BUILD_DIR.name}", + f"--with-build-python={build_python}", + ] if build_python_is_pydebug(): configure.append("--with-pydebug") if context.args: configure.extend(context.args) - call(configure, - env=updated_env(env_additions | wasi_sdk_env(context)), - context=context) + call( + configure, + env=updated_env(env_additions | wasi_sdk_env(context)), + context=context, + ) python_wasm = working_dir / "python.wasm" exec_script = working_dir / "python.sh" with exec_script.open("w", encoding="utf-8") as file: file.write(f'#!/bin/sh\nexec {host_runner} {python_wasm} "$@"\n') exec_script.chmod(0o755) - print(f"🏃‍♀️ Created {exec_script} (--host-runner)... ") + log("🏃", f"Created {exec_script} (--host-runner)... ") sys.stdout.flush() @subdir(lambda context: CROSS_BUILD_DIR / context.host_triple) def make_wasi_python(context, working_dir): """Run `make` for the WASI/host build.""" - call(["make", "--jobs", str(cpu_count()), "all"], - env=updated_env(), - context=context) + call( + ["make", "--jobs", str(cpu_count()), "all"], + env=updated_env(), + context=context, + ) exec_script = working_dir / "python.sh" call([exec_script, "--version"], quiet=False) - print( - f"🎉 Use `{exec_script.relative_to(context.init_dir)}` " - "to run CPython w/ the WASI host specified by --host-runner" + log( + "🎉", + f"Use `{exec_script.relative_to(context.init_dir)}` " + "to run CPython w/ the WASI host specified by --host-runner", ) -def build_all(context): - """Build everything.""" - steps = [configure_build_python, make_build_python, configure_wasi_python, - make_wasi_python] - for step in steps: - step(context) - def clean_contents(context): """Delete all files created by this script.""" if CROSS_BUILD_DIR.exists(): - print(f"🧹 Deleting {CROSS_BUILD_DIR} ...") + log("🧹", f"Deleting {CROSS_BUILD_DIR} ...") shutil.rmtree(CROSS_BUILD_DIR) if LOCAL_SETUP.exists(): if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: - print(f"🧹 Deleting generated {LOCAL_SETUP} ...") + log("🧹", f"Deleting generated {LOCAL_SETUP} ...") + + +def build_steps(*steps): + """Construct a command from other steps.""" + + def builder(context): + for step in steps: + step(context) + + return builder def main(): - default_host_triple = "wasm32-wasip1" - default_wasi_sdk = find_wasi_sdk() - default_host_runner = (f"{WASMTIME_HOST_RUNNER_VAR} run " - # Make sure the stack size will work for a pydebug - # build. - # Use 16 MiB stack. - "--wasm max-wasm-stack=16777216 " - # Enable thread support; causes use of preview1. - #"--wasm threads=y --wasi threads=y " - # Map the checkout to / to load the stdlib from /Lib. - "--dir {HOST_DIR}::{GUEST_DIR} " - # Set PYTHONPATH to the sysconfig data. - "--env {ENV_VAR_NAME}={ENV_VAR_VALUE}") + with (HERE / "config.toml").open("rb") as file: + config = tomllib.load(file) + default_wasi_sdk = find_wasi_sdk(config) + default_host_triple = config["targets"]["host-triple"] + default_host_runner = ( + f"{WASMTIME_HOST_RUNNER_VAR} run " + # For setting PYTHONPATH to the sysconfig data directory. + "--env PYTHONPATH={PYTHONPATH} " + # Map the checkout to / to load the stdlib from /Lib. + f"--dir {os.fsdecode(CHECKOUT)}::/ " + # Flags involving --optimize, --codegen, --debug, --wasm, and --wasi can be kept + # in a config file. + # We are using such a file to act as defaults in case a user wants to override + # only some of the settings themselves, make it easy to modify settings + # post-build so that they immediately apply to the Makefile instead of having to + # regenerate it, and allow for easy copying of the settings for anyone else who + # may want to use them. + f"--config {os.fsdecode(HERE / 'wasmtime.toml')}" + ) default_logdir = pathlib.Path(tempfile.gettempdir()) parser = argparse.ArgumentParser() subcommands = parser.add_subparsers(dest="subcommand") build = subcommands.add_parser("build", help="Build everything") - configure_build = subcommands.add_parser("configure-build-python", - help="Run `configure` for the " - "build Python") - make_build = subcommands.add_parser("make-build-python", - help="Run `make` for the build Python") - configure_host = subcommands.add_parser("configure-host", - help="Run `configure` for the " - "host/WASI (pydebug builds " - "are inferred from the build " - "Python)") - make_host = subcommands.add_parser("make-host", - help="Run `make` for the host/WASI") - subcommands.add_parser("clean", help="Delete files and directories " - "created by this script") - for subcommand in build, configure_build, make_build, configure_host, make_host: - subcommand.add_argument("--quiet", action="store_true", default=False, - dest="quiet", - help="Redirect output from subprocesses to a log file") - subcommand.add_argument("--logdir", type=pathlib.Path, default=default_logdir, - help="Directory to store log files; " - f"defaults to {default_logdir}") - for subcommand in configure_build, configure_host: - subcommand.add_argument("--clean", action="store_true", default=False, - dest="clean", - help="Delete any relevant directories before building") - for subcommand in build, configure_build, configure_host: - subcommand.add_argument("args", nargs="*", - help="Extra arguments to pass to `configure`") - for subcommand in build, configure_host: - subcommand.add_argument("--wasi-sdk", type=pathlib.Path, - dest="wasi_sdk_path", - default=default_wasi_sdk, - help=f"Path to the WASI SDK; defaults to {default_wasi_sdk}") - subcommand.add_argument("--host-runner", action="store", - default=default_host_runner, dest="host_runner", - help="Command template for running the WASI host; defaults to " - f"`{default_host_runner}`") - for subcommand in build, configure_host, make_host: - subcommand.add_argument("--host-triple", action="store", - default=default_host_triple, - help="The target triple for the WASI host build; " - f"defaults to {default_host_triple}") + configure_build = subcommands.add_parser( + "configure-build-python", help="Run `configure` for the build Python" + ) + make_build = subcommands.add_parser( + "make-build-python", help="Run `make` for the build Python" + ) + build_python = subcommands.add_parser( + "build-python", help="Build the build Python" + ) + configure_host = subcommands.add_parser( + "configure-host", + help="Run `configure` for the " + "host/WASI (pydebug builds " + "are inferred from the build " + "Python)", + ) + make_host = subcommands.add_parser( + "make-host", help="Run `make` for the host/WASI" + ) + build_host = subcommands.add_parser( + "build-host", help="Build the host/WASI Python" + ) + subcommands.add_parser( + "clean", help="Delete files and directories created by this script" + ) + for subcommand in ( + build, + configure_build, + make_build, + build_python, + configure_host, + make_host, + build_host, + ): + subcommand.add_argument( + "--quiet", + action="store_true", + default=False, + dest="quiet", + help="Redirect output from subprocesses to a log file", + ) + subcommand.add_argument( + "--logdir", + type=pathlib.Path, + default=default_logdir, + help=f"Directory to store log files; defaults to {default_logdir}", + ) + for subcommand in ( + configure_build, + configure_host, + build_python, + build_host, + ): + subcommand.add_argument( + "--clean", + action="store_true", + default=False, + dest="clean", + help="Delete any relevant directories before building", + ) + for subcommand in ( + build, + configure_build, + configure_host, + build_python, + build_host, + ): + subcommand.add_argument( + "args", nargs="*", help="Extra arguments to pass to `configure`" + ) + for subcommand in build, configure_host, build_host: + subcommand.add_argument( + "--wasi-sdk", + type=pathlib.Path, + dest="wasi_sdk_path", + default=default_wasi_sdk, + help=f"Path to the WASI SDK; defaults to {default_wasi_sdk}", + ) + subcommand.add_argument( + "--host-runner", + action="store", + default=default_host_runner, + dest="host_runner", + help="Command template for running the WASI host; defaults to " + f"`{default_host_runner}`", + ) + for subcommand in build, configure_host, make_host, build_host: + subcommand.add_argument( + "--host-triple", + action="store", + default=default_host_triple, + help="The target triple for the WASI host build; " + f"defaults to {default_host_triple}", + ) context = parser.parse_args() context.init_dir = pathlib.Path().absolute() - dispatch = {"configure-build-python": configure_build_python, - "make-build-python": make_build_python, - "configure-host": configure_wasi_python, - "make-host": make_wasi_python, - "build": build_all, - "clean": clean_contents} + build_build_python = build_steps(configure_build_python, make_build_python) + build_wasi_python = build_steps(configure_wasi_python, make_wasi_python) + + dispatch = { + "configure-build-python": configure_build_python, + "make-build-python": make_build_python, + "build-python": build_build_python, + "configure-host": configure_wasi_python, + "make-host": make_wasi_python, + "build-host": build_wasi_python, + "build": build_steps(build_build_python, build_wasi_python), + "clean": clean_contents, + } dispatch[context.subcommand](context) -if __name__ == "__main__": +if __name__ == "__main__": main() diff --git a/Tools/wasm/wasi/config.toml b/Tools/wasm/wasi/config.toml new file mode 100644 index 00000000000..7ca2f76f56d --- /dev/null +++ b/Tools/wasm/wasi/config.toml @@ -0,0 +1,6 @@ +# Any data that can vary between Python versions is to be kept in this file. +# This allows for blanket copying of the WASI build code between supported +# Python versions. +[targets] +wasi-sdk = 29 +host-triple = "wasm32-wasip1" diff --git a/Tools/wasm/wasi/wasmtime.toml b/Tools/wasm/wasi/wasmtime.toml new file mode 100644 index 00000000000..5a45e8c3db9 --- /dev/null +++ b/Tools/wasm/wasi/wasmtime.toml @@ -0,0 +1,5 @@ +# https://docs.wasmtime.dev/cli-options.html#cli-options-using-toml-file + +[wasm] +# 32 MiB; big enough for the test suite to pass under a debug build. +max-wasm-stack = 33_554_432 diff --git a/configure b/configure index bdeab8a6d12..a1bc7991aa8 100755 --- a/configure +++ b/configure @@ -644,6 +644,7 @@ ac_includes_default="\ ac_header_c_list= ac_subst_vars='LTLIBOBJS MODULE_BLOCK +JIT_STENCILS_H MODULE_XXLIMITED_35_FALSE MODULE_XXLIMITED_35_TRUE MODULE_XXLIMITED_FALSE @@ -813,6 +814,8 @@ MODULE__BISECT_FALSE MODULE__BISECT_TRUE MODULE__ASYNCIO_FALSE MODULE__ASYNCIO_TRUE +MODULE__MATH_INTEGER_FALSE +MODULE__MATH_INTEGER_TRUE MODULE_ARRAY_FALSE MODULE_ARRAY_TRUE MODULE_TIME_FALSE @@ -839,8 +842,9 @@ LIBREADLINE_CFLAGS WHEEL_PKG_DIR LIBPL PY_ENABLE_SHARED -PLATLIBDIR BINLIBDEST +LIBDEST +PLATLIBDIR LIBPYTHON MODULE_DEPS_SHARED EXT_SUFFIX @@ -904,7 +908,6 @@ LDSHARED SHLIB_SUFFIX DSYMUTIL_PATH DSYMUTIL -JIT_STENCILS_H REGEN_JIT_COMMAND UNIVERSAL_ARCH_FLAGS WASM_STDLIB @@ -965,6 +968,7 @@ LDLIBRARY LIBRARY BUILDEXEEXT NO_AS_NEEDED +_Py_STACK_GROWS_DOWN MULTIARCH_CPPFLAGS PLATFORM_TRIPLET MULTIARCH @@ -1009,6 +1013,7 @@ UNIVERSALSDK host_exec_prefix host_prefix MACHDEP +MISSING_STDLIB_CONFIG PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG @@ -1080,6 +1085,7 @@ ac_user_opts=' enable_option_checking with_build_python with_pkg_config +with_missing_stdlib_config enable_universalsdk with_universal_archs with_framework_name @@ -1819,7 +1825,8 @@ Optional Features: no) --enable-wasm-dynamic-linking Enable dynamic linking support for WebAssembly - (default is no) + (default is no); WASI requires an external dynamic + loader to handle imports --enable-wasm-pthreads Enable pthread emulation for WebAssembly (default is no) --enable-shared enable building a shared Python library (default is @@ -1859,6 +1866,9 @@ Optional Packages: --with-pkg-config=[yes|no|check] use pkg-config to detect build options (default is check) + --with-missing-stdlib-config=FILE + File with custom module error messages for missing + stdlib modules --with-universal-archs=ARCH specify the kind of macOS universal binary that should be created. This option is only valid when @@ -3816,7 +3826,7 @@ fi -for ac_prog in python$PACKAGE_VERSION python3.13 python3.12 python3.11 python3.10 python3 python +for ac_prog in python$PACKAGE_VERSION python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 python3 python do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -4092,6 +4102,19 @@ if test "$with_pkg_config" = yes -a -z "$PKG_CONFIG"; then as_fn_error $? "pkg-config is required" "$LINENO" 5] fi + +# Check whether --with-missing-stdlib-config was given. +if test ${with_missing_stdlib_config+y} +then : + withval=$with_missing_stdlib_config; MISSING_STDLIB_CONFIG="$withval" +else case e in #( + e) MISSING_STDLIB_CONFIG="" + ;; +esac +fi + + + # Set name for machine-dependent library files { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 @@ -4359,7 +4382,7 @@ then : yes) case $ac_sys_system in Darwin) enableval=/Library/Frameworks ;; - iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; + iOS) enableval=Apple/iOS/Frameworks/\$\(MULTIARCH\) ;; *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 esac esac @@ -4470,9 +4493,9 @@ then : prefix=$PYTHONFRAMEWORKPREFIX PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" - RESSRCDIR=iOS/Resources + RESSRCDIR=Apple/iOS/Resources - ac_config_files="$ac_config_files iOS/Resources/Info.plist" + ac_config_files="$ac_config_files Apple/iOS/Resources/Info.plist" ;; *) @@ -7211,6 +7234,18 @@ if test x$MULTIARCH != x; then fi +# Guess C stack direction +case $host in #( + hppa*) : + _Py_STACK_GROWS_DOWN=0 ;; #( + *) : + _Py_STACK_GROWS_DOWN=1 ;; +esac + +printf "%s\n" "#define _Py_STACK_GROWS_DOWN $_Py_STACK_GROWS_DOWN" >>confdefs.h + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PEP 11 support tier" >&5 printf %s "checking for PEP 11 support tier... " >&6; } case $host/$ac_cv_cc_name in #( @@ -7382,7 +7417,7 @@ then : Emscripten) : ;; #( WASI) : - as_fn_error $? "WASI dynamic linking is not implemented yet." "$LINENO" 5 ;; #( + ;; #( *) : as_fn_error $? "--enable-wasm-dynamic-linking only applies to Emscripten and WASI" "$LINENO" 5 ;; @@ -7775,10 +7810,6 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDLIBRARY" >&5 printf "%s\n" "$LDLIBRARY" >&6; } -if test "$cross_compiling" = yes; then - RUNSHARED= -fi - # HOSTRUNNER - Program to run CPython for the host platform { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking HOSTRUNNER" >&5 printf %s "checking HOSTRUNNER... " >&6; } @@ -7903,8 +7934,10 @@ then : as_fn_append HOSTRUNNER " --experimental-wasm-memory64" fi ;; #( - WASI) : - HOSTRUNNER='wasmtime run --wasm max-wasm-stack=16777216 --wasi preview2=n --env PYTHONPATH=/$(shell realpath --relative-to $(abs_srcdir) $(abs_builddir))/$(shell cat pybuilddir.txt):/Lib --dir $(srcdir)::/' ;; #( + WASI) : + + as_fn_error $? "HOSTRUNNER must be set when cross-compiling to WASI" "$LINENO" 5 + ;; #( *) : HOSTRUNNER='' ;; @@ -9394,7 +9427,7 @@ fi printf %s "checking BOLT_COMMON_FLAGS... " >&6; } if test -z "${BOLT_COMMON_FLAGS}" then - BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1 " + BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1 " fi @@ -9611,7 +9644,7 @@ fi as_fn_append LINKFORSHARED " -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js" as_fn_append LINKFORSHARED " -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV,HEAPU32,TTY" - as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET,_PyGILState_GetThisThreadState,__Py_DumpTraceback" + as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,_PyGILState_GetThisThreadState,__Py_DumpTraceback" as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB" as_fn_append LINKFORSHARED " -sTEXTDECODER=2" @@ -10873,8 +10906,7 @@ then : else case e in #( e) as_fn_append CFLAGS_NODIST " $jit_flags" - REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\"" - JIT_STENCILS_H="jit_stencils.h" + REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\" --llvm-version=\"$LLVM_VERSION\"" if test "x$Py_DEBUG" = xtrue then : as_fn_append REGEN_JIT_COMMAND " --debug" @@ -10882,14 +10914,14 @@ fi ;; esac fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tier2_flags $jit_flags" >&5 printf "%s\n" "$tier2_flags $jit_flags" >&6; } if test "$disable_gil" = "yes" -a "$enable_experimental_jit" != "no"; then # GH-133171: This configuration builds the JIT but never actually uses it, # which is surprising (and strictly worse than not building it at all): - as_fn_error $? "--enable-experimental-jit cannot be used with --disable-gil." "$LINENO" 5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --enable-experimental-jit does not work correctly with --disable-gil." >&5 +printf "%s\n" "$as_me: WARNING: --enable-experimental-jit does not work correctly with --disable-gil." >&2;} fi case "$ac_cv_cc_name" in @@ -12002,7 +12034,7 @@ then : fi -# On Linux, can.h, can/bcm.h, can/j1939.h, can/raw.h require sys/socket.h +# On Linux, can.h, can/bcm.h, can/isotp.h, can/j1939.h, can/raw.h require sys/socket.h # On NetBSD, netcan/can.h requires sys/socket.h ac_fn_c_check_header_compile "$LINENO" "linux/can.h" "ac_cv_header_linux_can_h" " #ifdef HAVE_SYS_SOCKET_H @@ -12025,6 +12057,17 @@ if test "x$ac_cv_header_linux_can_bcm_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_CAN_BCM_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "linux/can/isotp.h" "ac_cv_header_linux_can_isotp_h" " +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +" +if test "x$ac_cv_header_linux_can_isotp_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_CAN_ISOTP_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/can/j1939.h" "ac_cv_header_linux_can_j1939_h" " #ifdef HAVE_SYS_SOCKET_H @@ -19088,7 +19131,7 @@ PLATFORM_OBJS= case $ac_sys_system in #( Emscripten) : - as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_syscalls.o' + as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o Python/emscripten_syscalls.o' as_fn_append PLATFORM_HEADERS ' $(srcdir)/Include/internal/pycore_emscripten_signal.h $(srcdir)/Include/internal/pycore_emscripten_trampoline.h' ;; #( *) : @@ -19213,6 +19256,12 @@ if test "x$ac_cv_func_chown" = xyes then : printf "%s\n" "#define HAVE_CHOWN 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "clearenv" "ac_cv_func_clearenv" +if test "x$ac_cv_func_clearenv" = xyes +then : + printf "%s\n" "#define HAVE_CLEARENV 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "clock" "ac_cv_func_clock" if test "x$ac_cv_func_clock" = xyes @@ -20374,6 +20423,22 @@ then : fi +# os.statx uses Linux's statx function. AIX also has a function named statx, +# but it's unrelated. Check only on Linux (including Android). +case $ac_sys_system in #( + Linux*) : + ac_fn_c_check_func "$LINENO" "statx" "ac_cv_func_statx" +if test "x$ac_cv_func_statx" = xyes +then : + printf "%s\n" "#define HAVE_STATX 1" >>confdefs.h + +fi + + ;; #( + *) : + ;; +esac + # Force lchmod off for Linux. Linux disallows changing the mode of symbolic # links. Some libc implementations have a stub lchmod implementation that always # returns an error. @@ -21718,19 +21783,19 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib >= 1.2.0" >&5 -printf %s "checking for zlib >= 1.2.0... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib >= 1.2.2.1" >&5 +printf %s "checking for zlib >= 1.2.2.1... " >&6; } if test -n "$ZLIB_CFLAGS"; then pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.0\""; } >&5 - ($PKG_CONFIG --exists --print-errors "zlib >= 1.2.0") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.2.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "zlib >= 1.2.2.1") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib >= 1.2.0" 2>/dev/null` + pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib >= 1.2.2.1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -21742,12 +21807,12 @@ if test -n "$ZLIB_LIBS"; then pkg_cv_ZLIB_LIBS="$ZLIB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.0\""; } >&5 - ($PKG_CONFIG --exists --print-errors "zlib >= 1.2.0") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.2.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "zlib >= 1.2.2.1") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib >= 1.2.0" 2>/dev/null` + pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib >= 1.2.2.1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -21768,9 +21833,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib >= 1.2.0" 2>&1` + ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib >= 1.2.2.1" 2>&1` else - ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib >= 1.2.0" 2>&1` + ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib >= 1.2.2.1" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ZLIB_PKG_ERRORS" >&5 @@ -23883,6 +23948,25 @@ printf "%s\n" "#define HAVE_UT_NAMESIZE 1" >>confdefs.h fi +ac_fn_check_decl "$LINENO" "PR_SET_VMA_ANON_NAME" "ac_cv_have_decl_PR_SET_VMA_ANON_NAME" "#include <linux/prctl.h> + #include <sys/prctl.h> +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_PR_SET_VMA_ANON_NAME" = xyes +then : + ac_have_decl=1 +else case e in #( + e) ac_have_decl=0 ;; +esac +fi +printf "%s\n" "#define HAVE_DECL_PR_SET_VMA_ANON_NAME $ac_have_decl" >>confdefs.h +if test $ac_have_decl = 1 +then : + +printf "%s\n" "#define HAVE_PR_SET_VMA_ANON_NAME 1" >>confdefs.h + +fi + + # check for openpty, login_tty, and forkpty @@ -25109,6 +25193,72 @@ printf "%s\n" "#define HAVE_SIGINFO_T_SI_BAND 1" >>confdefs.h fi +if test "$ac_cv_func_statx" = yes; then + # Some systems have the definitions of the mask bits without having the + # corresponding members in struct statx. Check for members added after Linux + # 4.11 (when statx itself was added). + ac_fn_c_check_member "$LINENO" "struct statx" "stx_mnt_id" "ac_cv_member_struct_statx_stx_mnt_id" "$ac_includes_default" +if test "x$ac_cv_member_struct_statx_stx_mnt_id" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX_STX_MNT_ID 1" >>confdefs.h + + +fi + + ac_fn_c_check_member "$LINENO" "struct statx" "stx_dio_mem_align" "ac_cv_member_struct_statx_stx_dio_mem_align" "$ac_includes_default" +if test "x$ac_cv_member_struct_statx_stx_dio_mem_align" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN 1" >>confdefs.h + + +fi + + # stx_dio_offset_align was added together with stx_dio_mem_align + ac_fn_c_check_member "$LINENO" "struct statx" "stx_subvol" "ac_cv_member_struct_statx_stx_subvol" "$ac_includes_default" +if test "x$ac_cv_member_struct_statx_stx_subvol" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX_STX_SUBVOL 1" >>confdefs.h + + +fi + + ac_fn_c_check_member "$LINENO" "struct statx" "stx_atomic_write_unit_min" "ac_cv_member_struct_statx_stx_atomic_write_unit_min" "$ac_includes_default" +if test "x$ac_cv_member_struct_statx_stx_atomic_write_unit_min" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MIN 1" >>confdefs.h + + +fi + + # stx_atomic_write_unit_max and stx_atomic_write_segments_max were added + # together with stx_atomic_write_unit_min + ac_fn_c_check_member "$LINENO" "struct statx" "stx_dio_read_offset_align" "ac_cv_member_struct_statx_stx_dio_read_offset_align" "$ac_includes_default" +if test "x$ac_cv_member_struct_statx_stx_dio_read_offset_align" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX_STX_DIO_READ_OFFSET_ALIGN 1" >>confdefs.h + + +fi + + # stx_atomic_write_unit_max_opt was added in Linux 6.16, but is controlled by + # the STATX_WRITE_ATOMIC mask bit added in Linux 6.11, so having the mask bit + # doesn't imply having the member. + ac_fn_c_check_member "$LINENO" "struct statx" "stx_atomic_write_unit_max_opt" "ac_cv_member_struct_statx_stx_atomic_write_unit_max_opt" "$ac_includes_default" +if test "x$ac_cv_member_struct_statx_stx_atomic_write_unit_max_opt" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT 1" >>confdefs.h + + +fi + +fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 printf %s "checking for time.h that defines altzone... " >&6; } if test ${ac_cv_header_time_altzone+y} @@ -25990,8 +26140,8 @@ main (void) { unsigned int fpcr; - __asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=g" (fpcr)); - __asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "g" (fpcr)); + __asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=dm" (fpcr)); + __asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "dm" (fpcr)); ; return 0; @@ -26793,15 +26943,10 @@ if test "$ac_sys_system" = "iOS"; then MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi - - -BINLIBDEST='$(LIBDIR)/python$(VERSION)$(ABI_THREAD)' - - # Check for --with-platlibdir # /usr/$PLATLIBDIR/python$(VERSION)$(ABI_THREAD) -PLATLIBDIR="lib" +PLATLIBDIR="lib" # XXX: We should probably calculate the defauly from libdir, if defined. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-platlibdir" >&5 printf %s "checking for --with-platlibdir... " >&6; } @@ -26818,7 +26963,6 @@ then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } PLATLIBDIR="$withval" - BINLIBDEST='${exec_prefix}/${PLATLIBDIR}/python$(VERSION)$(ABI_THREAD)' else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -26832,10 +26976,14 @@ fi +LIBDEST='${prefix}/${PLATLIBDIR}/python$(VERSION)$(ABI_THREAD)' +BINLIBDEST='${exec_prefix}/${PLATLIBDIR}/python$(VERSION)$(ABI_THREAD)' + + if test x$PLATFORM_TRIPLET = x; then - LIBPL='$(prefix)'"/${PLATLIBDIR}/python${VERSION}${ABI_THREAD}/config-${LDVERSION}" + LIBPL='$(LIBDEST)'"/config-${LDVERSION}" else - LIBPL='$(prefix)'"/${PLATLIBDIR}/python${VERSION}${ABI_THREAD}/config-${LDVERSION}-${PLATFORM_TRIPLET}" + LIBPL='$(LIBDEST)'"/config-${LDVERSION}-${PLATFORM_TRIPLET}" fi @@ -29801,7 +29949,7 @@ then : if test "$withval" = yes then -printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h +printf "%s\n" "#define _Py_TAIL_CALL_INTERP 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } @@ -29809,7 +29957,7 @@ fi if test "$withval" = no then -printf "%s\n" "#define Py_TAIL_CALL_INTERP 0" >>confdefs.h +printf "%s\n" "#define _Py_TAIL_CALL_INTERP 0" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -29872,6 +30020,7 @@ SRCDIRS="\ Modules/_hacl \ Modules/_io \ Modules/_multiprocessing \ + Modules/_remote_debugging \ Modules/_sqlite \ Modules/_sre \ Modules/_testcapi \ @@ -31234,6 +31383,28 @@ then : +fi + + + if test "$py_cv_module__math_integer" != "n/a" +then : + py_cv_module__math_integer=yes +fi + if test "$py_cv_module__math_integer" = yes; then + MODULE__MATH_INTEGER_TRUE= + MODULE__MATH_INTEGER_FALSE='#' +else + MODULE__MATH_INTEGER_TRUE='#' + MODULE__MATH_INTEGER_FALSE= +fi + + as_fn_append MODULE_BLOCK "MODULE__MATH_INTEGER_STATE=$py_cv_module__math_integer$as_nl" + if test "x$py_cv_module__math_integer" = xyes +then : + + + + fi @@ -34180,6 +34351,40 @@ fi printf "%s\n" "$py_cv_module_xxlimited_35" >&6; } +# Determine JIT stencils header files based on target platform +JIT_STENCILS_H="" +if test "x$enable_experimental_jit" = xno +then : + +else case e in #( + e) case "$host" in + aarch64-apple-darwin*) + JIT_STENCILS_H="jit_stencils-aarch64-apple-darwin.h" + ;; + x86_64-apple-darwin*) + JIT_STENCILS_H="jit_stencils-x86_64-apple-darwin.h" + ;; + aarch64-pc-windows-msvc) + JIT_STENCILS_H="jit_stencils-aarch64-pc-windows-msvc.h" + ;; + i686-pc-windows-msvc) + JIT_STENCILS_H="jit_stencils-i686-pc-windows-msvc.h" + ;; + x86_64-pc-windows-msvc) + JIT_STENCILS_H="jit_stencils-x86_64-pc-windows-msvc.h" + ;; + aarch64-*-linux-gnu) + JIT_STENCILS_H="jit_stencils-aarch64-unknown-linux-gnu.h" + ;; + x86_64-*-linux-gnu) + JIT_STENCILS_H="jit_stencils-x86_64-unknown-linux-gnu.h" + ;; + esac ;; +esac +fi + + + # substitute multiline block, must come after last PY_STDLIB_MOD() @@ -34313,6 +34518,10 @@ if test -z "${MODULE_ARRAY_TRUE}" && test -z "${MODULE_ARRAY_FALSE}"; then as_fn_error $? "conditional \"MODULE_ARRAY\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${MODULE__MATH_INTEGER_TRUE}" && test -z "${MODULE__MATH_INTEGER_FALSE}"; then + as_fn_error $? "conditional \"MODULE__MATH_INTEGER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${MODULE__ASYNCIO_TRUE}" && test -z "${MODULE__ASYNCIO_FALSE}"; then as_fn_error $? "conditional \"MODULE__ASYNCIO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -35222,7 +35431,7 @@ do "Mac/PythonLauncher/Makefile") CONFIG_FILES="$CONFIG_FILES Mac/PythonLauncher/Makefile" ;; "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; - "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; + "Apple/iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES Apple/iOS/Resources/Info.plist" ;; "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;; "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; diff --git a/configure.ac b/configure.ac index 991fa40746b..a284a118f02 100644 --- a/configure.ac +++ b/configure.ac @@ -205,7 +205,7 @@ AC_SUBST([FREEZE_MODULE_DEPS]) AC_SUBST([PYTHON_FOR_BUILD_DEPS]) AC_CHECK_PROGS([PYTHON_FOR_REGEN], - [python$PACKAGE_VERSION python3.13 python3.12 python3.11 python3.10 python3 python], + [python$PACKAGE_VERSION python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 python3 python], [python3]) AC_SUBST([PYTHON_FOR_REGEN]) @@ -307,6 +307,15 @@ if test "$with_pkg_config" = yes -a -z "$PKG_CONFIG"; then AC_MSG_ERROR([pkg-config is required])] fi +dnl Allow distributors to provide custom missing stdlib module error messages +AC_ARG_WITH([missing-stdlib-config], + [AS_HELP_STRING([--with-missing-stdlib-config=FILE], + [File with custom module error messages for missing stdlib modules])], + [MISSING_STDLIB_CONFIG="$withval"], + [MISSING_STDLIB_CONFIG=""] +) +AC_SUBST([MISSING_STDLIB_CONFIG]) + # Set name for machine-dependent library files AC_ARG_VAR([MACHDEP], [name for machine-dependent library files]) AC_MSG_CHECKING([MACHDEP]) @@ -559,7 +568,7 @@ AC_ARG_ENABLE([framework], yes) case $ac_sys_system in Darwin) enableval=/Library/Frameworks ;; - iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; + iOS) enableval=Apple/iOS/Frameworks/\$\(MULTIARCH\) ;; *) AC_MSG_ERROR([Unknown platform for framework build]) esac esac @@ -666,9 +675,9 @@ AC_ARG_ENABLE([framework], prefix=$PYTHONFRAMEWORKPREFIX PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" - RESSRCDIR=iOS/Resources + RESSRCDIR=Apple/iOS/Resources - AC_CONFIG_FILES([iOS/Resources/Info.plist]) + AC_CONFIG_FILES([Apple/iOS/Resources/Info.plist]) ;; *) AC_MSG_ERROR([Unknown platform for framework build]) @@ -1202,6 +1211,14 @@ if test x$MULTIARCH != x; then fi AC_SUBST([MULTIARCH_CPPFLAGS]) +# Guess C stack direction +AS_CASE([$host], + [hppa*], [_Py_STACK_GROWS_DOWN=0], + [_Py_STACK_GROWS_DOWN=1]) +AC_DEFINE_UNQUOTED([_Py_STACK_GROWS_DOWN], [$_Py_STACK_GROWS_DOWN], + [Define to 1 if the machine stack grows down (default); 0 if it grows up.]) +AC_SUBST([_Py_STACK_GROWS_DOWN]) + dnl Support tiers according to https://peps.python.org/pep-0011/ dnl dnl NOTE: Windows support tiers are defined in PC/pyconfig.h. @@ -1306,11 +1323,11 @@ dnl See https://emscripten.org/docs/compiling/Dynamic-Linking.html AC_MSG_CHECKING([for --enable-wasm-dynamic-linking]) AC_ARG_ENABLE([wasm-dynamic-linking], [AS_HELP_STRING([--enable-wasm-dynamic-linking], - [Enable dynamic linking support for WebAssembly (default is no)])], + [Enable dynamic linking support for WebAssembly (default is no); WASI requires an external dynamic loader to handle imports])], [ AS_CASE([$ac_sys_system], [Emscripten], [], - [WASI], [AC_MSG_ERROR([WASI dynamic linking is not implemented yet.])], + [WASI], [], [AC_MSG_ERROR([--enable-wasm-dynamic-linking only applies to Emscripten and WASI])] ) ], [ @@ -1622,10 +1639,6 @@ else # shared is disabled fi AC_MSG_RESULT([$LDLIBRARY]) -if test "$cross_compiling" = yes; then - RUNSHARED= -fi - # HOSTRUNNER - Program to run CPython for the host platform AC_MSG_CHECKING([HOSTRUNNER]) if test -z "$HOSTRUNNER" @@ -1636,10 +1649,9 @@ then HOSTRUNNER="$NODE" AS_VAR_IF([host_cpu], [wasm64], [AS_VAR_APPEND([HOSTRUNNER], [" --experimental-wasm-memory64"])]) ], - dnl TODO: support other WASI runtimes - dnl wasmtime starts the process with "/" as CWD. For OOT builds add the - dnl directory containing _sysconfigdata to PYTHONPATH. - [WASI], [HOSTRUNNER='wasmtime run --wasm max-wasm-stack=16777216 --wasi preview2=n --env PYTHONPATH=/$(shell realpath --relative-to $(abs_srcdir) $(abs_builddir))/$(shell cat pybuilddir.txt):/Lib --dir $(srcdir)::/'], + [WASI], [ + AC_MSG_ERROR([HOSTRUNNER must be set when cross-compiling to WASI]) + ], [HOSTRUNNER=''] ) fi @@ -2163,7 +2175,8 @@ then dnl At least LLVM 19.x doesn't support computed gotos in PIC compiled code. dnl Exclude functions containing computed gotos. dnl TODO this may be fixed in LLVM 20.x via https://github.com/llvm/llvm-project/pull/120267. - [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1] + dnl GCC's LTO creates .lto_priv.0 clones of these functions. + [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1] ")] ) fi @@ -2344,7 +2357,7 @@ AS_CASE([$ac_sys_system], dnl Include file system support AS_VAR_APPEND([LINKFORSHARED], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"]) AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV,HEAPU32,TTY"]) - AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET,_PyGILState_GetThisThreadState,__Py_DumpTraceback"]) + AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,_PyGILState_GetThisThreadState,__Py_DumpTraceback"]) AS_VAR_APPEND([LINKFORSHARED], [" -sSTACK_SIZE=5MB"]) dnl Avoid bugs in JS fallback string decoding path AS_VAR_APPEND([LINKFORSHARED], [" -sTEXTDECODER=2"]) @@ -2787,20 +2800,18 @@ AS_VAR_IF([jit_flags], [], [AS_VAR_APPEND([CFLAGS_NODIST], [" $jit_flags"]) AS_VAR_SET([REGEN_JIT_COMMAND], - ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\""]) - AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"]) + ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\" --llvm-version=\"$LLVM_VERSION\""]) AS_VAR_IF([Py_DEBUG], [true], [AS_VAR_APPEND([REGEN_JIT_COMMAND], [" --debug"])], [])]) AC_SUBST([REGEN_JIT_COMMAND]) -AC_SUBST([JIT_STENCILS_H]) AC_MSG_RESULT([$tier2_flags $jit_flags]) if test "$disable_gil" = "yes" -a "$enable_experimental_jit" != "no"; then # GH-133171: This configuration builds the JIT but never actually uses it, # which is surprising (and strictly worse than not building it at all): - AC_MSG_ERROR([--enable-experimental-jit cannot be used with --disable-gil.]) + AC_MSG_WARN([--enable-experimental-jit does not work correctly with --disable-gil.]) fi case "$ac_cv_cc_name" in @@ -3054,10 +3065,10 @@ AC_CHECK_HEADERS([linux/vm_sockets.h], [], [], [ #endif ]) -# On Linux, can.h, can/bcm.h, can/j1939.h, can/raw.h require sys/socket.h +# On Linux, can.h, can/bcm.h, can/isotp.h, can/j1939.h, can/raw.h require sys/socket.h # On NetBSD, netcan/can.h requires sys/socket.h AC_CHECK_HEADERS( -[linux/can.h linux/can/bcm.h linux/can/j1939.h linux/can/raw.h netcan/can.h], +[linux/can.h linux/can/bcm.h linux/can/isotp.h linux/can/j1939.h linux/can/raw.h netcan/can.h], [], [], [ #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> @@ -5147,7 +5158,7 @@ PLATFORM_OBJS= AS_CASE([$ac_sys_system], [Emscripten], [ - AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_syscalls.o']) + AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o Python/emscripten_syscalls.o']) AS_VAR_APPEND([PLATFORM_HEADERS], [' $(srcdir)/Include/internal/pycore_emscripten_signal.h $(srcdir)/Include/internal/pycore_emscripten_trampoline.h']) ], ) @@ -5229,7 +5240,8 @@ fi # checks for library functions AC_CHECK_FUNCS([ \ - accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ + accept4 alarm bind_textdomain_codeset chmod chown clearenv \ + clock closefrom close_range confstr \ copy_file_range ctermid dladdr dup dup3 execv explicit_bzero explicit_memset \ faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ @@ -5259,6 +5271,12 @@ AC_CHECK_FUNCS([ \ wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \ ]) +# os.statx uses Linux's statx function. AIX also has a function named statx, +# but it's unrelated. Check only on Linux (including Android). +AS_CASE([$ac_sys_system], + [Linux*], [AC_CHECK_FUNCS([statx])] +) + # Force lchmod off for Linux. Linux disallows changing the mode of symbolic # links. Some libc implementations have a stub lchmod implementation that always # returns an error. @@ -5426,7 +5444,7 @@ AH_TEMPLATE([HAVE_ZLIB_COPY], [Define if the zlib library has inflateCopy]) dnl detect zlib from Emscripten emport PY_CHECK_EMSCRIPTEN_PORT([ZLIB], [-sUSE_ZLIB]) -PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.0], [ +PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.2.1], [ have_zlib=yes dnl zlib 1.2.0 (2003) added inflateCopy AC_DEFINE([HAVE_ZLIB_COPY], [1]) @@ -5565,6 +5583,13 @@ AC_CHECK_DECLS([UT_NAMESIZE], [], [@%:@include <utmp.h>]) +AC_CHECK_DECLS([PR_SET_VMA_ANON_NAME], + [AC_DEFINE([HAVE_PR_SET_VMA_ANON_NAME], [1], + [Define if you have the 'PR_SET_VMA_ANON_NAME' constant.])], + [], + [@%:@include <linux/prctl.h> + @%:@include <sys/prctl.h>]) + # check for openpty, login_tty, and forkpty AC_CHECK_FUNCS([openpty], [], @@ -5821,6 +5846,24 @@ AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_passwd], [], [], [[ # Issue #21085: In Cygwin, siginfo_t does not have si_band field. AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[@%:@include <signal.h>]]) +if test "$ac_cv_func_statx" = yes; then + # Some systems have the definitions of the mask bits without having the + # corresponding members in struct statx. Check for members added after Linux + # 4.11 (when statx itself was added). + AC_CHECK_MEMBERS([struct statx.stx_mnt_id]) + AC_CHECK_MEMBERS([struct statx.stx_dio_mem_align]) + # stx_dio_offset_align was added together with stx_dio_mem_align + AC_CHECK_MEMBERS([struct statx.stx_subvol]) + AC_CHECK_MEMBERS([struct statx.stx_atomic_write_unit_min]) + # stx_atomic_write_unit_max and stx_atomic_write_segments_max were added + # together with stx_atomic_write_unit_min + AC_CHECK_MEMBERS([struct statx.stx_dio_read_offset_align]) + # stx_atomic_write_unit_max_opt was added in Linux 6.16, but is controlled by + # the STATX_WRITE_ATOMIC mask bit added in Linux 6.11, so having the mask bit + # doesn't imply having the member. + AC_CHECK_MEMBERS([struct statx.stx_atomic_write_unit_max_opt]) +fi + AC_CACHE_CHECK([for time.h that defines altzone], [ac_cv_header_time_altzone], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <time.h>]], [[return altzone;]])], [ac_cv_header_time_altzone=yes], @@ -6090,8 +6133,8 @@ AS_VAR_IF([ac_cv_gcc_asm_for_x87], [yes], [ AC_CACHE_CHECK([whether we can use gcc inline assembler to get and set mc68881 fpcr], [ac_cv_gcc_asm_for_mc68881], [ AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ unsigned int fpcr; - __asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=g" (fpcr)); - __asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "g" (fpcr)); + __asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=dm" (fpcr)); + __asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "dm" (fpcr)); ]])],[ac_cv_gcc_asm_for_mc68881=yes],[ac_cv_gcc_asm_for_mc68881=no]) ]) AS_VAR_IF([ac_cv_gcc_asm_for_mc68881], [yes], [ @@ -6377,15 +6420,10 @@ if test "$ac_sys_system" = "iOS"; then MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi - -AC_SUBST([BINLIBDEST]) -BINLIBDEST='$(LIBDIR)/python$(VERSION)$(ABI_THREAD)' - - # Check for --with-platlibdir # /usr/$PLATLIBDIR/python$(VERSION)$(ABI_THREAD) AC_SUBST([PLATLIBDIR]) -PLATLIBDIR="lib" +PLATLIBDIR="lib" # XXX: We should probably calculate the defauly from libdir, if defined. AC_MSG_CHECKING([for --with-platlibdir]) AC_ARG_WITH( [platlibdir], @@ -6402,19 +6440,22 @@ if test -n "$withval" -a "$withval" != yes -a "$withval" != no then AC_MSG_RESULT([yes]) PLATLIBDIR="$withval" - BINLIBDEST='${exec_prefix}/${PLATLIBDIR}/python$(VERSION)$(ABI_THREAD)' else AC_MSG_RESULT([no]) fi], [AC_MSG_RESULT([no])]) +AC_SUBST([LIBDEST]) +AC_SUBST([BINLIBDEST]) +LIBDEST='${prefix}/${PLATLIBDIR}/python$(VERSION)$(ABI_THREAD)' +BINLIBDEST='${exec_prefix}/${PLATLIBDIR}/python$(VERSION)$(ABI_THREAD)' dnl define LIBPL after ABIFLAGS and LDVERSION is defined. AC_SUBST([PY_ENABLE_SHARED]) if test x$PLATFORM_TRIPLET = x; then - LIBPL='$(prefix)'"/${PLATLIBDIR}/python${VERSION}${ABI_THREAD}/config-${LDVERSION}" + LIBPL='$(LIBDEST)'"/config-${LDVERSION}" else - LIBPL='$(prefix)'"/${PLATLIBDIR}/python${VERSION}${ABI_THREAD}/config-${LDVERSION}-${PLATFORM_TRIPLET}" + LIBPL='$(LIBDEST)'"/config-${LDVERSION}-${PLATFORM_TRIPLET}" fi AC_SUBST([LIBPL]) @@ -7108,13 +7149,13 @@ AC_ARG_WITH( [ if test "$withval" = yes then - AC_DEFINE([Py_TAIL_CALL_INTERP], [1], + AC_DEFINE([_Py_TAIL_CALL_INTERP], [1], [Define if you want to use tail-calling interpreters in CPython.]) AC_MSG_RESULT([yes]) fi if test "$withval" = no then - AC_DEFINE([Py_TAIL_CALL_INTERP], [0], + AC_DEFINE([_Py_TAIL_CALL_INTERP], [0], [Define if you want to use tail-calling interpreters in CPython.]) AC_MSG_RESULT([no]) fi @@ -7163,6 +7204,7 @@ SRCDIRS="\ Modules/_hacl \ Modules/_io \ Modules/_multiprocessing \ + Modules/_remote_debugging \ Modules/_sqlite \ Modules/_sre \ Modules/_testcapi \ @@ -7858,6 +7900,7 @@ PY_STDLIB_MOD_SIMPLE([time], [], [$TIMEMODULE_LIB]) dnl always enabled extension modules PY_STDLIB_MOD_SIMPLE([array]) +PY_STDLIB_MOD_SIMPLE([_math_integer]) PY_STDLIB_MOD_SIMPLE([_asyncio]) PY_STDLIB_MOD_SIMPLE([_bisect]) PY_STDLIB_MOD_SIMPLE([_csv]) @@ -8174,6 +8217,36 @@ dnl Emscripten does not support shared libraries yet. PY_STDLIB_MOD([xxlimited], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) PY_STDLIB_MOD([xxlimited_35], [test "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) +# Determine JIT stencils header files based on target platform +JIT_STENCILS_H="" +AS_VAR_IF([enable_experimental_jit], [no], + [], + [case "$host" in + aarch64-apple-darwin*) + JIT_STENCILS_H="jit_stencils-aarch64-apple-darwin.h" + ;; + x86_64-apple-darwin*) + JIT_STENCILS_H="jit_stencils-x86_64-apple-darwin.h" + ;; + aarch64-pc-windows-msvc) + JIT_STENCILS_H="jit_stencils-aarch64-pc-windows-msvc.h" + ;; + i686-pc-windows-msvc) + JIT_STENCILS_H="jit_stencils-i686-pc-windows-msvc.h" + ;; + x86_64-pc-windows-msvc) + JIT_STENCILS_H="jit_stencils-x86_64-pc-windows-msvc.h" + ;; + aarch64-*-linux-gnu) + JIT_STENCILS_H="jit_stencils-aarch64-unknown-linux-gnu.h" + ;; + x86_64-*-linux-gnu) + JIT_STENCILS_H="jit_stencils-x86_64-unknown-linux-gnu.h" + ;; + esac]) + +AC_SUBST([JIT_STENCILS_H]) + # substitute multiline block, must come after last PY_STDLIB_MOD() AC_SUBST([MODULE_BLOCK]) diff --git a/iOS/README.rst b/iOS/README.rst deleted file mode 100644 index 4d38e5d7c30..00000000000 --- a/iOS/README.rst +++ /dev/null @@ -1,352 +0,0 @@ -==================== -Python on iOS README -==================== - -:Authors: - Russell Keith-Magee (2023-11) - -This document provides a quick overview of some iOS specific features in the -Python distribution. - -These instructions are only needed if you're planning to compile Python for iOS -yourself. Most users should *not* need to do this. If you're looking to -experiment with writing an iOS app in Python, tools such as `BeeWare's Briefcase -<https://briefcase.readthedocs.io>`__ and `Kivy's Buildozer -<https://buildozer.readthedocs.io>`__ will provide a much more approachable -user experience. - -Compilers for building on iOS -============================= - -Building for iOS requires the use of Apple's Xcode tooling. It is strongly -recommended that you use the most recent stable release of Xcode. This will -require the use of the most (or second-most) recently released macOS version, -as Apple does not maintain Xcode for older macOS versions. The Xcode Command -Line Tools are not sufficient for iOS development; you need a *full* Xcode -install. - -If you want to run your code on the iOS simulator, you'll also need to install -an iOS Simulator Platform. You should be prompted to select an iOS Simulator -Platform when you first run Xcode. Alternatively, you can add an iOS Simulator -Platform by selecting an open the Platforms tab of the Xcode Settings panel. - -iOS specific arguments to configure -=================================== - -* ``--enable-framework[=DIR]`` - - This argument specifies the location where the Python.framework will be - installed. If ``DIR`` is not specified, the framework will be installed into - a subdirectory of the ``iOS/Frameworks`` folder. - - This argument *must* be provided when configuring iOS builds. iOS does not - support non-framework builds. - -* ``--with-framework-name=NAME`` - - Specify the name for the Python framework; defaults to ``Python``. - - .. admonition:: Use this option with care! - - Unless you know what you're doing, changing the name of the Python - framework on iOS is not advised. If you use this option, you won't be able - to run the ``make testios`` target without making significant manual - alterations, and you won't be able to use any binary packages unless you - compile them yourself using your own framework name. - -Building Python on iOS -====================== - -ABIs and Architectures ----------------------- - -iOS apps can be deployed on physical devices, and on the iOS simulator. Although -the API used on these devices is identical, the ABI is different - you need to -link against different libraries for an iOS device build (``iphoneos``) or an -iOS simulator build (``iphonesimulator``). - -Apple uses the ``XCframework`` format to allow specifying a single dependency -that supports multiple ABIs. An ``XCframework`` is a wrapper around multiple -ABI-specific frameworks that share a common API. - -iOS can also support different CPU architectures within each ABI. At present, -there is only a single supported architecture on physical devices - ARM64. -However, the *simulator* supports 2 architectures - ARM64 (for running on Apple -Silicon machines), and x86_64 (for running on older Intel-based machines). - -To support multiple CPU architectures on a single platform, Apple uses a "fat -binary" format - a single physical file that contains support for multiple -architectures. It is possible to compile and use a "thin" single architecture -version of a binary for testing purposes; however, the "thin" binary will not be -portable to machines using other architectures. - -Building a single-architecture framework ----------------------------------------- - -The Python build system will create a ``Python.framework`` that supports a -*single* ABI with a *single* architecture. Unlike macOS, iOS does not allow a -framework to contain non-library content, so the iOS build will produce a -``bin`` and ``lib`` folder in the same output folder as ``Python.framework``. -The ``lib`` folder will be needed at runtime to support the Python library. - -If you want to use Python in a real iOS project, you need to produce multiple -``Python.framework`` builds, one for each ABI and architecture. iOS builds of -Python *must* be constructed as framework builds. To support this, you must -provide the ``--enable-framework`` flag when configuring the build. The build -also requires the use of cross-compilation. The minimal commands for building -Python for the ARM64 iOS simulator will look something like:: - - $ export PATH="$(pwd)/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" - $ ./configure \ - --enable-framework \ - --host=arm64-apple-ios-simulator \ - --build=arm64-apple-darwin \ - --with-build-python=/path/to/python.exe - $ make - $ make install - -In this invocation: - -* ``iOS/Resources/bin`` has been added to the path, providing some shims for the - compilers and linkers needed by the build. Xcode requires the use of ``xcrun`` - to invoke compiler tooling. However, if ``xcrun`` is pre-evaluated and the - result passed to ``configure``, these results can embed user- and - version-specific paths into the sysconfig data, which limits the portability - of the compiled Python. Alternatively, if ``xcrun`` is used *as* the compiler, - it requires that compiler variables like ``CC`` include spaces, which can - cause significant problems with many C configuration systems which assume that - ``CC`` will be a single executable. - - To work around this problem, the ``iOS/Resources/bin`` folder contains some - wrapper scripts that present as simple compilers and linkers, but wrap - underlying calls to ``xcrun``. This allows configure to use a ``CC`` - definition without spaces, and without user- or version-specific paths, while - retaining the ability to adapt to the local Xcode install. These scripts are - included in the ``bin`` directory of an iOS install. - - These scripts will, by default, use the currently active Xcode installation. - If you want to use a different Xcode installation, you can use - ``xcode-select`` to set a new default Xcode globally, or you can use the - ``DEVELOPER_DIR`` environment variable to specify an Xcode install. The - scripts will use the default ``iphoneos``/``iphonesimulator`` SDK version for - the select Xcode install; if you want to use a different SDK, you can set the - ``IOS_SDK_VERSION`` environment variable. (e.g, setting - ``IOS_SDK_VERSION=17.1`` would cause the scripts to use the ``iphoneos17.1`` - and ``iphonesimulator17.1`` SDKs, regardless of the Xcode default.) - - The path has also been cleared of any user customizations. A common source of - bugs is for tools like Homebrew to accidentally leak macOS binaries into an iOS - build. Resetting the path to a known "bare bones" value is the easiest way to - avoid these problems. - -* ``--host`` is the architecture and ABI that you want to build, in GNU compiler - triple format. This will be one of: - - - ``arm64-apple-ios`` for ARM64 iOS devices. - - ``arm64-apple-ios-simulator`` for the iOS simulator running on Apple - Silicon devices. - - ``x86_64-apple-ios-simulator`` for the iOS simulator running on Intel - devices. - -* ``--build`` is the GNU compiler triple for the machine that will be running - the compiler. This is one of: - - - ``arm64-apple-darwin`` for Apple Silicon devices. - - ``x86_64-apple-darwin`` for Intel devices. - -* ``/path/to/python.exe`` is the path to a Python binary on the machine that - will be running the compiler. This is needed because the Python compilation - process involves running some Python code. On a normal desktop build of - Python, you can compile a python interpreter and then use that interpreter to - run Python code. However, the binaries produced for iOS won't run on macOS, so - you need to provide an external Python interpreter. This interpreter must be - the same version as the Python that is being compiled. To be completely safe, - this should be the *exact* same commit hash. However, the longer a Python - release has been stable, the more likely it is that this constraint can be - relaxed - the same micro version will often be sufficient. - -* The ``install`` target for iOS builds is slightly different to other - platforms. On most platforms, ``make install`` will install the build into - the final runtime location. This won't be the case for iOS, as the final - runtime location will be on a physical device. - - However, you still need to run the ``install`` target for iOS builds, as it - performs some final framework assembly steps. The location specified with - ``--enable-framework`` will be the location where ``make install`` will - assemble the complete iOS framework. This completed framework can then - be copied and relocated as required. - -For a full CPython build, you also need to specify the paths to iOS builds of -the binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL). -This can be done by defining the ``LIBLZMA_CFLAGS``, ``LIBLZMA_LIBS``, -``BZIP2_CFLAGS``, ``BZIP2_LIBS``, ``LIBFFI_CFLAGS``, and ``LIBFFI_LIBS`` -environment variables, and the ``--with-openssl`` configure option. Versions of -these libraries pre-compiled for iOS can be found in `this repository -<https://github.com/beeware/cpython-apple-source-deps/releases>`__. LibFFI is -especially important, as many parts of the standard library (including the -``platform``, ``sysconfig`` and ``webbrowser`` modules) require the use of the -``ctypes`` module at runtime. - -By default, Python will be compiled with an iOS deployment target (i.e., the -minimum supported iOS version) of 13.0. To specify a different deployment -target, provide the version number as part of the ``--host`` argument - for -example, ``--host=arm64-apple-ios15.4-simulator`` would compile an ARM64 -simulator build with a deployment target of 15.4. - -Merge thin frameworks into fat frameworks ------------------------------------------ - -Once you've built a ``Python.framework`` for each ABI and architecture, you -must produce a "fat" framework for each ABI that contains all the architectures -for that ABI. - -The ``iphoneos`` build only needs to support a single architecture, so it can be -used without modification. - -If you only want to support a single simulator architecture, (e.g., only support -ARM64 simulators), you can use a single architecture ``Python.framework`` build. -However, if you want to create ``Python.xcframework`` that supports *all* -architectures, you'll need to merge the ``iphonesimulator`` builds for ARM64 and -x86_64 into a single "fat" framework. - -The "fat" framework can be constructed by performing a directory merge of the -content of the two "thin" ``Python.framework`` directories, plus the ``bin`` and -``lib`` folders for each thin framework. When performing this merge: - -* The pure Python standard library content is identical for each architecture, - except for a handful of platform-specific files (such as the ``sysconfig`` - module). Ensure that the "fat" framework has the union of all standard library - files. - -* Any binary files in the standard library, plus the main - ``libPython3.X.dylib``, can be merged using the ``lipo`` tool, provide by - Xcode:: - - $ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib - -* The header files will be identical on both architectures, except for - ``pyconfig.h``. Copy all the headers from one platform (say, arm64), rename - ``pyconfig.h`` to ``pyconfig-arm64.h``, and copy the ``pyconfig.h`` for the - other architecture into the merged header folder as ``pyconfig-x86_64.h``. - Then copy the ``iOS/Resources/pyconfig.h`` file from the CPython sources into - the merged headers folder. This will allow the two Python architectures to - share a common ``pyconfig.h`` header file. - -At this point, you should have 2 Python.framework folders - one for ``iphoneos``, -and one for ``iphonesimulator`` that is a merge of x86+64 and ARM64 content. - -Merge frameworks into an XCframework ------------------------------------- - -Now that we have 2 (potentially fat) ABI-specific frameworks, we can merge those -frameworks into a single ``XCframework``. - -The initial skeleton of an ``XCframework`` is built using:: - - xcodebuild -create-xcframework -output Python.xcframework -framework path/to/iphoneos/Python.framework -framework path/to/iphonesimulator/Python.framework - -Then, copy the ``bin`` and ``lib`` folders into the architecture-specific slices of -the XCframework:: - - cp path/to/iphoneos/bin Python.xcframework/ios-arm64 - cp path/to/iphoneos/lib Python.xcframework/ios-arm64 - - cp path/to/iphonesimulator/bin Python.xcframework/ios-arm64_x86_64-simulator - cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64_x86_64-simulator - -Note that the name of the architecture-specific slice for the simulator will -depend on the CPU architecture(s) that you build. - -You now have a Python.xcframework that can be used in a project. - -Testing Python on iOS -===================== - -The ``iOS/testbed`` folder that contains an Xcode project that is able to run -the iOS test suite. This project converts the Python test suite into a single -test case in Xcode's XCTest framework. The single XCTest passes if the test -suite passes. - -To run the test suite, configure a Python build for an iOS simulator (i.e., -``--host=arm64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator`` -), specifying a framework build (i.e. ``--enable-framework``). Ensure that your -``PATH`` has been configured to include the ``iOS/Resources/bin`` folder and -exclude any non-iOS tools, then run:: - - $ make all - $ make install - $ make testios - -This will: - -* Build an iOS framework for your chosen architecture; -* Finalize the single-platform framework; -* Make a clean copy of the testbed project; -* Install the Python iOS framework into the copy of the testbed project; and -* Run the test suite on an "iPhone SE (3rd generation)" simulator. - -On success, the test suite will exit and report successful completion of the -test suite. On a 2022 M1 MacBook Pro, the test suite takes approximately 15 -minutes to run; a couple of extra minutes is required to compile the testbed -project, and then boot and prepare the iOS simulator. - -Debugging test failures ------------------------ - -Running ``make testios`` generates a standalone version of the ``iOS/testbed`` -project, and runs the full test suite. It does this using ``iOS/testbed`` -itself - the folder is an executable module that can be used to create and run -a clone of the testbed project. - -You can generate your own standalone testbed instance by running:: - - $ python iOS/testbed clone --framework iOS/Frameworks/arm64-iphonesimulator my-testbed - -This invocation assumes that ``iOS/Frameworks/arm64-iphonesimulator`` is the -path to the iOS simulator framework for your platform (ARM64 in this case); -``my-testbed`` is the name of the folder for the new testbed clone. - -You can then use the ``my-testbed`` folder to run the Python test suite, -passing in any command line arguments you may require. For example, if you're -trying to diagnose a failure in the ``os`` module, you might run:: - - $ python my-testbed run -- test -W test_os - -This is the equivalent of running ``python -m test -W test_os`` on a desktop -Python build. Any arguments after the ``--`` will be passed to testbed as if -they were arguments to ``python -m`` on a desktop machine. - -Testing in Xcode -^^^^^^^^^^^^^^^^ - -You can also open the testbed project in Xcode by running:: - - $ open my-testbed/iOSTestbed.xcodeproj - -This will allow you to use the full Xcode suite of tools for debugging. - -The arguments used to run the test suite are defined as part of the test plan. -To modify the test plan, select the test plan node of the project tree (it -should be the first child of the root node), and select the "Configurations" -tab. Modify the "Arguments Passed On Launch" value to change the testing -arguments. - -The test plan also disables parallel testing, and specifies the use of the -``iOSTestbed.lldbinit`` file for providing configuration of the debugger. The -default debugger configuration disables automatic breakpoints on the -``SIGINT``, ``SIGUSR1``, ``SIGUSR2``, and ``SIGXFSZ`` signals. - -Testing on an iOS device -^^^^^^^^^^^^^^^^^^^^^^^^ - -To test on an iOS device, the app needs to be signed with known developer -credentials. To obtain these credentials, you must have an iOS Developer -account, and your Xcode install will need to be logged into your account (see -the Accounts tab of the Preferences dialog). - -Once the project is open, and you're signed into your Apple Developer account, -select the root node of the project tree (labeled "iOSTestbed"), then the -"Signing & Capabilities" tab in the details page. Select a development team -(this will likely be your own name), and plug in a physical device to your -macOS machine with a USB cable. You should then be able to select your physical -device from the list of targets in the pulldown in the Xcode titlebar. diff --git a/iOS/testbed/iOSTestbed/dylib-Info-template.plist b/iOS/testbed/iOSTestbed/dylib-Info-template.plist deleted file mode 100644 index f652e272f71..00000000000 --- a/iOS/testbed/iOSTestbed/dylib-Info-template.plist +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>en</string> - <key>CFBundleExecutable</key> - <string></string> - <key>CFBundleIdentifier</key> - <string></string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleShortVersionString</key> - <string>1.0</string> - <key>CFBundleSupportedPlatforms</key> - <array> - <string>iPhoneOS</string> - </array> - <key>MinimumOSVersion</key> - <string>12.0</string> - <key>CFBundleVersion</key> - <string>1</string> -</dict> -</plist> diff --git a/pyconfig.h.in b/pyconfig.h.in index 0d6ad4465c0..aabf9f0be8d 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -141,6 +141,9 @@ /* Define if you have the 'chroot' function. */ #undef HAVE_CHROOT +/* Define to 1 if you have the 'clearenv' function. */ +#undef HAVE_CLEARENV + /* Define to 1 if you have the 'clock' function. */ #undef HAVE_CLOCK @@ -225,6 +228,10 @@ /* Define to 1 if you have the <db.h> header file. */ #undef HAVE_DB_H +/* Define to 1 if you have the declaration of 'PR_SET_VMA_ANON_NAME', and to 0 + if you don't. */ +#undef HAVE_DECL_PR_SET_VMA_ANON_NAME + /* Define to 1 if you have the declaration of 'RTLD_DEEPBIND', and to 0 if you don't. */ #undef HAVE_DECL_RTLD_DEEPBIND @@ -727,6 +734,9 @@ /* Define to 1 if you have the <linux/can.h> header file. */ #undef HAVE_LINUX_CAN_H +/* Define to 1 if you have the <linux/can/isotp.h> header file. */ +#undef HAVE_LINUX_CAN_ISOTP_H + /* Define to 1 if you have the <linux/can/j1939.h> header file. */ #undef HAVE_LINUX_CAN_J1939_H @@ -990,6 +1000,9 @@ /* Define if your compiler supports function prototype */ #undef HAVE_PROTOTYPES +/* Define if you have the 'PR_SET_VMA_ANON_NAME' constant. */ +#undef HAVE_PR_SET_VMA_ANON_NAME + /* Define to 1 if you have the 'pthread_condattr_setclock' function. */ #undef HAVE_PTHREAD_CONDATTR_SETCLOCK @@ -1279,6 +1292,9 @@ /* Define to 1 if you have the 'statvfs' function. */ #undef HAVE_STATVFS +/* Define to 1 if you have the 'statx' function. */ +#undef HAVE_STATX + /* Define if you have struct stat.st_mtim.tv_nsec */ #undef HAVE_STAT_TV_NSEC @@ -1321,6 +1337,27 @@ /* Define to 1 if 'pw_passwd' is a member of 'struct passwd'. */ #undef HAVE_STRUCT_PASSWD_PW_PASSWD +/* Define to 1 if 'stx_atomic_write_unit_max_opt' is a member of 'struct + statx'. */ +#undef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MAX_OPT + +/* Define to 1 if 'stx_atomic_write_unit_min' is a member of 'struct statx'. + */ +#undef HAVE_STRUCT_STATX_STX_ATOMIC_WRITE_UNIT_MIN + +/* Define to 1 if 'stx_dio_mem_align' is a member of 'struct statx'. */ +#undef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + +/* Define to 1 if 'stx_dio_read_offset_align' is a member of 'struct statx'. + */ +#undef HAVE_STRUCT_STATX_STX_DIO_READ_OFFSET_ALIGN + +/* Define to 1 if 'stx_mnt_id' is a member of 'struct statx'. */ +#undef HAVE_STRUCT_STATX_STX_MNT_ID + +/* Define to 1 if 'stx_subvol' is a member of 'struct statx'. */ +#undef HAVE_STRUCT_STATX_STX_SUBVOL + /* Define to 1 if 'st_birthtime' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BIRTHTIME @@ -1749,9 +1786,6 @@ /* The version of SunOS/Solaris as reported by `uname -r' without the dot. */ #undef Py_SUNOS_VERSION -/* Define if you want to use tail-calling interpreters in CPython. */ -#undef Py_TAIL_CALL_INTERP - /* Define if you want to enable tracing references for debugging purpose */ #undef Py_TRACE_REFS @@ -2023,6 +2057,12 @@ /* HACL* library can compile SIMD256 implementations */ #undef _Py_HACL_CAN_COMPILE_VEC256 +/* Define to 1 if the machine stack grows down (default); 0 if it grows up. */ +#undef _Py_STACK_GROWS_DOWN + +/* Define if you want to use tail-calling interpreters in CPython. */ +#undef _Py_TAIL_CALL_INTERP + /* Define to force use of thread-safe errno, h_errno, and other functions */ #undef _REENTRANT